From 6221bbc5a7312598a9d83bd29c9a6136d01b9323 Mon Sep 17 00:00:00 2001 From: king6cong Date: Sat, 30 Sep 2017 14:55:16 +0800 Subject: [PATCH 0001/3747] update trans_fulfill_obligation call signature --- src/librustc_mir/interpret/eval_context.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs index 3388031a30cab..b483cf1aed869 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/src/librustc_mir/interpret/eval_context.rs @@ -6,6 +6,7 @@ use rustc::hir::map::definitions::DefPathData; use rustc::middle::const_val::ConstVal; use rustc::middle::region; use rustc::mir; +use rustc::traits; use rustc::traits::Reveal; use rustc::ty::layout::{self, Layout, Size, Align, HasDataLayout}; use rustc::ty::subst::{Subst, Substs, Kind}; @@ -2411,7 +2412,7 @@ fn resolve_associated_item<'a, 'tcx>( ); let trait_ref = ty::TraitRef::from_method(tcx, trait_id, rcvr_substs); - let vtbl = tcx.trans_fulfill_obligation(DUMMY_SP, ty::Binder(trait_ref)); + let vtbl = tcx.trans_fulfill_obligation(DUMMY_SP, ty::ParamEnv::empty(traits::Reveal::All), ty::Binder(trait_ref)); // Now that we know which impl is being used, we can dispatch to // the actual function: From 3d1332d7f813fece8a0e98124aa6a7595e58d512 Mon Sep 17 00:00:00 2001 From: king6cong Date: Sat, 30 Sep 2017 15:07:07 +0800 Subject: [PATCH 0002/3747] update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 22cb5aed79b1a..7660735a7cefa 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ how to fix it, you could send a PR. :smile: ## Running tests ```sh -cargo run --bin miri tests/run-pass/vecs.rs # Or whatever test you like. +cargo run --bin miri tests/run-pass-fullmir/vecs.rs # Or whatever test you like. ``` ## Debugging From 52599adf2752feb4432422b355dac22e66a1cf09 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Thu, 5 Oct 2017 12:31:47 +0200 Subject: [PATCH 0003/3747] Miri core has moved to rustc::mir::interpret --- Cargo.lock | 96 +- Cargo.toml | 1 - miri/fn_call.rs | 16 +- miri/helpers.rs | 2 +- miri/intrinsic.rs | 4 +- miri/lib.rs | 25 +- miri/memory.rs | 6 +- miri/operator.rs | 4 +- src/librustc_mir/Cargo.toml | 19 - src/librustc_mir/interpret/cast.rs | 122 - src/librustc_mir/interpret/const_eval.rs | 259 -- src/librustc_mir/interpret/error.rs | 313 -- src/librustc_mir/interpret/eval_context.rs | 2535 ----------------- src/librustc_mir/interpret/lvalue.rs | 506 ---- src/librustc_mir/interpret/machine.rs | 82 - src/librustc_mir/interpret/memory.rs | 1700 ----------- src/librustc_mir/interpret/mod.rs | 42 - src/librustc_mir/interpret/operator.rs | 268 -- src/librustc_mir/interpret/range_map.rs | 250 -- src/librustc_mir/interpret/step.rs | 402 --- src/librustc_mir/interpret/terminator/drop.rs | 83 - src/librustc_mir/interpret/terminator/mod.rs | 411 --- src/librustc_mir/interpret/traits.rs | 137 - src/librustc_mir/interpret/validation.rs | 727 ----- src/librustc_mir/interpret/value.rs | 405 --- src/librustc_mir/lib.rs | 26 - 26 files changed, 36 insertions(+), 8405 deletions(-) delete mode 100644 src/librustc_mir/Cargo.toml delete mode 100644 src/librustc_mir/interpret/cast.rs delete mode 100644 src/librustc_mir/interpret/const_eval.rs delete mode 100644 src/librustc_mir/interpret/error.rs delete mode 100644 src/librustc_mir/interpret/eval_context.rs delete mode 100644 src/librustc_mir/interpret/lvalue.rs delete mode 100644 src/librustc_mir/interpret/machine.rs delete mode 100644 src/librustc_mir/interpret/memory.rs delete mode 100644 src/librustc_mir/interpret/mod.rs delete mode 100644 src/librustc_mir/interpret/operator.rs delete mode 100644 src/librustc_mir/interpret/range_map.rs delete mode 100644 src/librustc_mir/interpret/step.rs delete mode 100644 src/librustc_mir/interpret/terminator/drop.rs delete mode 100644 src/librustc_mir/interpret/terminator/mod.rs delete mode 100644 src/librustc_mir/interpret/traits.rs delete mode 100644 src/librustc_mir/interpret/validation.rs delete mode 100644 src/librustc_mir/interpret/value.rs delete mode 100644 src/librustc_mir/lib.rs diff --git a/Cargo.lock b/Cargo.lock index c84d79a089c3a..ecc1e85596c5f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,13 +1,13 @@ [root] -name = "rustc_miri" +name = "miri" version = "0.1.0" dependencies = [ - "backtrace 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "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)", + "cargo_metadata 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "compiletest_rs 0.3.1 (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)", - "regex 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -18,29 +18,6 @@ dependencies = [ "memchr 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "backtrace" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "backtrace-sys 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "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.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 = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "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]] name = "bitflags" version = "0.7.0" @@ -61,11 +38,6 @@ dependencies = [ "serde_json 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "cfg-if" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "compiletest_rs" version = "0.3.1" @@ -93,15 +65,6 @@ name = "custom_derive" version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -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 = "diff" version = "0.1.10" @@ -129,11 +92,6 @@ dependencies = [ "libc 0.2.30 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "gcc" -version = "0.3.53" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "getopts" version = "0.2.15" @@ -144,15 +102,6 @@ name = "itoa" version = "0.3.2" 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" @@ -201,19 +150,6 @@ dependencies = [ "libc 0.2.30 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -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)", - "compiletest_rs 0.3.1 (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)", - "rustc_miri 0.1.0", -] - [[package]] name = "num-traits" version = "0.1.40" @@ -250,11 +186,6 @@ name = "regex-syntax" 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-serialize" version = "0.3.24" @@ -353,36 +284,20 @@ 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.3 (registry+https://github.com/rust-lang/crates.io-index)" = "99f2ce94e22b8e664d95c57fff45b98a966c2252b60691d0b7aeeccd88d70983" -"checksum backtrace-sys 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "afccc5772ba333abccdf60d55200fa3406f8c59dcf54d5f7998c9107d3799c7c" "checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d" "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 cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d4c819a1287eb618df47cc647173c5c4c66ba19d888a6e50d605672aed3140de" "checksum compiletest_rs 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "86f4663adfd113e17109c35c2067194eca782a5baf9c90f4696ca13d04631adb" "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 diff 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "0a515461b6c8c08419850ced27bc29e86166dcdcde8fbe76f8b1f0589bb49472" "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 filetime 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "5363ab8e4139b8568a6237db5248646e5a8a2f89bd5ccb02092182b11fd3e922" -"checksum gcc 0.3.53 (registry+https://github.com/rust-lang/crates.io-index)" = "e8310f7e9c890398b0e80e301c4f474e9918d2b27fca8f48486ca775fa9ffc5a" "checksum getopts 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)" = "65922871abd2f101a2eb0eaebadc66668e54a87ad9c3dd82520b5f86ede5eff9" "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.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" @@ -395,7 +310,6 @@ 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.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" @@ -409,5 +323,3 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "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/Cargo.toml b/Cargo.toml index b3db572871dac..34cbfcc03a2fe 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,7 +27,6 @@ env_logger = "0.4.3" log = "0.3.6" log_settings = "0.1.1" cargo_metadata = { version = "0.2", optional = true } -rustc_miri = { path = "src/librustc_mir" } [features] cargo_miri = ["cargo_metadata"] diff --git a/miri/fn_call.rs b/miri/fn_call.rs index 79ef3f97a9e9a..77a22ac9c35f5 100644 --- a/miri/fn_call.rs +++ b/miri/fn_call.rs @@ -7,7 +7,8 @@ use syntax::codemap::Span; use std::mem; -use rustc_miri::interpret::*; +use rustc::mir::interpret::*; +use rustc::traits; use super::{TlsKey, EvalContext}; @@ -109,7 +110,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> self.write_null(dest, dest_ty)?; } else { let align = self.memory.pointer_size(); - let ptr = self.memory.allocate(size, align, MemoryKind::C.into())?; + let ptr = self.memory.allocate(size, align, Some(MemoryKind::C.into()))?; self.write_primval(dest, PrimVal::Ptr(ptr), dest_ty)?; } } @@ -305,7 +306,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> let value_copy = self.memory.allocate( (value.len() + 1) as u64, 1, - MemoryKind::Env.into(), + Some(MemoryKind::Env.into()), )?; self.memory.write_bytes(value_copy.into(), &value)?; let trailing_zero_ptr = value_copy.offset(value.len() as u64, &self)?.into(); @@ -381,9 +382,10 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> }; // compute global if not cached let val = match self.globals.get(&cid).cloned() { - Some(ptr) => self.value_to_primval(ValTy { value: Value::ByRef(ptr), ty: args[0].ty })?.to_u64()?, - None => eval_body_as_primval(self.tcx, instance)?.0.to_u64()?, + Some(ptr) => ptr, + None => eval_body(self.tcx, instance, ty::ParamEnv::empty(traits::Reveal::All))?.0, }; + let val = self.value_to_primval(ValTy { value: Value::ByRef(val), ty: args[0].ty })?.to_u64()?; if val == name { result = Some(path_value); break; @@ -558,7 +560,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> if !align.is_power_of_two() { return err!(HeapAllocNonPowerOfTwoAlignment(align)); } - let ptr = self.memory.allocate(size, align, MemoryKind::Rust.into())?; + let ptr = self.memory.allocate(size, align, Some(MemoryKind::Rust.into()))?; self.write_primval(dest, PrimVal::Ptr(ptr), dest_ty)?; } "alloc::heap::::__rust_alloc_zeroed" => { @@ -570,7 +572,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> if !align.is_power_of_two() { return err!(HeapAllocNonPowerOfTwoAlignment(align)); } - let ptr = self.memory.allocate(size, align, MemoryKind::Rust.into())?; + let ptr = self.memory.allocate(size, align, Some(MemoryKind::Rust.into()))?; self.memory.write_repeat(ptr.into(), 0, size)?; self.write_primval(dest, PrimVal::Ptr(ptr), dest_ty)?; } diff --git a/miri/helpers.rs b/miri/helpers.rs index 809e5ebfacdb0..3ee148afb2b22 100644 --- a/miri/helpers.rs +++ b/miri/helpers.rs @@ -1,4 +1,4 @@ -use rustc_miri::interpret::{Pointer, EvalResult, PrimVal, EvalContext}; +use rustc::mir::interpret::{Pointer, EvalResult, PrimVal, EvalContext}; use rustc::ty::Ty; diff --git a/miri/intrinsic.rs b/miri/intrinsic.rs index bcff3b4aa9919..b41a753519712 100644 --- a/miri/intrinsic.rs +++ b/miri/intrinsic.rs @@ -3,7 +3,7 @@ use rustc::traits::Reveal; use rustc::ty::layout::Layout; use rustc::ty::{self, Ty}; -use rustc_miri::interpret::{EvalResult, Lvalue, LvalueExtra, PrimVal, PrimValKind, Value, Pointer, +use rustc::mir::interpret::{EvalResult, Lvalue, LvalueExtra, PrimVal, PrimValKind, Value, Pointer, HasMemory, AccessKind, EvalContext, PtrAndAlign, ValTy}; use helpers::EvalContextExt as HelperEvalContextExt; @@ -654,7 +654,7 @@ fn numeric_intrinsic<'tcx>( ) -> EvalResult<'tcx, PrimVal> { macro_rules! integer_intrinsic { ($method:ident) => ({ - use rustc_miri::interpret::PrimValKind::*; + use rustc::mir::interpret::PrimValKind::*; let result_bytes = match kind { I8 => (bytes as i8).$method() as u128, U8 => (bytes as u8).$method() as u128, diff --git a/miri/lib.rs b/miri/lib.rs index f6ecd6e0b00b7..27bd3d5939f31 100644 --- a/miri/lib.rs +++ b/miri/lib.rs @@ -14,15 +14,14 @@ use rustc::ty::{self, TyCtxt}; use rustc::ty::layout::Layout; use rustc::hir::def_id::DefId; use rustc::mir; +use rustc::traits; use syntax::ast::Mutability; use syntax::codemap::Span; use std::collections::{HashMap, BTreeMap}; -#[macro_use] -extern crate rustc_miri; -pub use rustc_miri::interpret::*; +pub use rustc::mir::interpret::*; mod fn_call; mod operator; @@ -43,7 +42,7 @@ pub fn eval_main<'a, 'tcx: 'a>( limits: ResourceLimits, ) { fn run_main<'a, 'tcx: 'a>( - ecx: &mut rustc_miri::interpret::EvalContext<'a, 'tcx, Evaluator>, + ecx: &mut rustc::mir::interpret::EvalContext<'a, 'tcx, Evaluator>, main_id: DefId, start_wrapper: Option, ) -> EvalResult<'tcx> { @@ -72,7 +71,7 @@ pub fn eval_main<'a, 'tcx: 'a>( // Return value let size = ecx.tcx.data_layout.pointer_size.bytes(); let align = ecx.tcx.data_layout.pointer_align.abi(); - let ret_ptr = ecx.memory_mut().allocate(size, align, MemoryKind::Stack)?; + let ret_ptr = ecx.memory_mut().allocate(size, align, Some(MemoryKind::Stack))?; cleanup_ptr = Some(ret_ptr); // Push our stack frame @@ -108,9 +107,9 @@ pub fn eval_main<'a, 'tcx: 'a>( // Third argument (argv): &[b"foo"] let dest = ecx.eval_lvalue(&mir::Lvalue::Local(args.next().unwrap()))?; let ty = ecx.tcx.mk_imm_ptr(ecx.tcx.mk_imm_ptr(ecx.tcx.types.u8)); - let foo = ecx.memory.allocate_cached(b"foo\0")?; + let foo = ecx.memory.allocate_cached(b"foo\0"); let ptr_size = ecx.memory.pointer_size(); - let foo_ptr = ecx.memory.allocate(ptr_size * 1, ptr_size, MemoryKind::UninitializedStatic)?; + let foo_ptr = ecx.memory.allocate(ptr_size * 1, ptr_size, None)?; ecx.memory.write_primval(foo_ptr.into(), PrimVal::Ptr(foo.into()), ptr_size, false)?; ecx.memory.mark_static_initalized(foo_ptr.alloc_id, Mutability::Immutable)?; ecx.write_ptr(dest, foo_ptr.into(), ty)?; @@ -186,6 +185,12 @@ impl<'tcx> Machine<'tcx> for Evaluator { type MemoryData = MemoryData<'tcx>; type MemoryKinds = memory::MemoryKind; + fn param_env<'a>( + _: &EvalContext<'a, 'tcx, Self>, + ) -> ty::ParamEnv<'tcx> { + ty::ParamEnv::empty(traits::Reveal::All) + } + /// Returns Ok() when the function was handled, fail otherwise fn eval_fn_call<'a>( ecx: &mut EvalContext<'a, 'tcx, Self>, @@ -199,7 +204,7 @@ impl<'tcx> Machine<'tcx> for Evaluator { } fn call_intrinsic<'a>( - ecx: &mut rustc_miri::interpret::EvalContext<'a, 'tcx, Self>, + ecx: &mut rustc::mir::interpret::EvalContext<'a, 'tcx, Self>, instance: ty::Instance<'tcx>, args: &[ValTy<'tcx>], dest: Lvalue, @@ -211,7 +216,7 @@ impl<'tcx> Machine<'tcx> for Evaluator { } fn try_ptr_op<'a>( - ecx: &rustc_miri::interpret::EvalContext<'a, 'tcx, Self>, + ecx: &rustc::mir::interpret::EvalContext<'a, 'tcx, Self>, bin_op: mir::BinOp, left: PrimVal, left_ty: ty::Ty<'tcx>, @@ -292,7 +297,7 @@ impl<'tcx> Machine<'tcx> for Evaluator { let ptr = ecx.memory.allocate( ptr_size, ptr_size, - MemoryKind::UninitializedStatic, + None, )?; ecx.memory.write_ptr_sized_unsigned(ptr, PrimVal::Bytes(0))?; ecx.memory.mark_static_initalized(ptr.alloc_id, mutability)?; diff --git a/miri/memory.rs b/miri/memory.rs index 110540c0cf1d2..0daba8e280ef0 100644 --- a/miri/memory.rs +++ b/miri/memory.rs @@ -9,8 +9,8 @@ pub enum MemoryKind { Env, } -impl Into<::rustc_miri::interpret::MemoryKind> for MemoryKind { - fn into(self) -> ::rustc_miri::interpret::MemoryKind { - ::rustc_miri::interpret::MemoryKind::Machine(self) +impl Into<::rustc::mir::interpret::MemoryKind> for MemoryKind { + fn into(self) -> ::rustc::mir::interpret::MemoryKind { + ::rustc::mir::interpret::MemoryKind::Machine(self) } } diff --git a/miri/operator.rs b/miri/operator.rs index 6d68aadf96cc7..04e84d27201b3 100644 --- a/miri/operator.rs +++ b/miri/operator.rs @@ -1,7 +1,7 @@ use rustc::ty; use rustc::mir; -use rustc_miri::interpret::*; +use rustc::mir::interpret::*; use helpers::EvalContextExt as HelperEvalContextExt; @@ -33,7 +33,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> right: PrimVal, right_ty: ty::Ty<'tcx>, ) -> EvalResult<'tcx, Option<(PrimVal, bool)>> { - use rustc_miri::interpret::PrimValKind::*; + use rustc::mir::interpret::PrimValKind::*; use rustc::mir::BinOp::*; let usize = PrimValKind::from_uint_size(self.memory.pointer_size()); let isize = PrimValKind::from_int_size(self.memory.pointer_size()); diff --git a/src/librustc_mir/Cargo.toml b/src/librustc_mir/Cargo.toml deleted file mode 100644 index c72de828c8d2b..0000000000000 --- a/src/librustc_mir/Cargo.toml +++ /dev/null @@ -1,19 +0,0 @@ -[package] -authors = ["Scott Olson "] -description = "An experimental interpreter for Rust MIR." -license = "MIT/Apache-2.0" -name = "rustc_miri" -repository = "https://github.com/solson/miri" -version = "0.1.0" -workspace = "../.." - -[lib] -path = "lib.rs" - -[dependencies] -byteorder = { version = "1.1", features = ["i128"]} -log = "0.3.6" -log_settings = "0.1.1" -lazy_static = "0.2.8" -regex = "0.2.2" -backtrace = "0.3.3" diff --git a/src/librustc_mir/interpret/cast.rs b/src/librustc_mir/interpret/cast.rs deleted file mode 100644 index 5ae7c9da31c09..0000000000000 --- a/src/librustc_mir/interpret/cast.rs +++ /dev/null @@ -1,122 +0,0 @@ -use rustc::ty::{self, Ty}; -use syntax::ast::{FloatTy, IntTy, UintTy}; - -use super::{PrimVal, EvalContext, EvalResult, MemoryPointer, PointerArithmetic, Machine}; - -impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { - pub(super) fn cast_primval( - &self, - val: PrimVal, - 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 { - PrimVal::Undef => Ok(PrimVal::Undef), - PrimVal::Ptr(ptr) => self.cast_from_ptr(ptr, dest_ty), - val @ PrimVal::Bytes(_) => { - use super::PrimValKind::*; - match src_kind { - F32 => self.cast_from_float(val.to_f32()? as f64, dest_ty), - F64 => self.cast_from_float(val.to_f64()?, dest_ty), - - I8 | I16 | I32 | I64 | I128 => { - self.cast_from_signed_int(val.to_i128()?, dest_ty) - } - - Bool | Char | U8 | U16 | U32 | U64 | U128 | FnPtr | Ptr => { - self.cast_from_int(val.to_u128()?, dest_ty, false) - } - } - } - } - } - - fn cast_from_signed_int(&self, val: i128, ty: ty::Ty<'tcx>) -> EvalResult<'tcx, PrimVal> { - self.cast_from_int(val as u128, ty, val < 0) - } - - fn int_to_int(&self, v: i128, ty: IntTy) -> u128 { - match ty { - IntTy::I8 => v as i8 as u128, - IntTy::I16 => v as i16 as u128, - IntTy::I32 => v as i32 as u128, - IntTy::I64 => v as i64 as u128, - IntTy::I128 => v as u128, - IntTy::Is => { - let ty = self.tcx.sess.target.isize_ty; - self.int_to_int(v, ty) - } - } - } - fn int_to_uint(&self, v: u128, ty: UintTy) -> u128 { - match ty { - UintTy::U8 => v as u8 as u128, - UintTy::U16 => v as u16 as u128, - UintTy::U32 => v as u32 as u128, - UintTy::U64 => v as u64 as u128, - UintTy::U128 => v, - UintTy::Us => { - let ty = self.tcx.sess.target.usize_ty; - self.int_to_uint(v, ty) - } - } - } - - fn cast_from_int( - &self, - v: u128, - ty: ty::Ty<'tcx>, - negative: bool, - ) -> EvalResult<'tcx, PrimVal> { - trace!("cast_from_int: {}, {}, {}", v, ty, negative); - use rustc::ty::TypeVariants::*; - match ty.sty { - // Casts to bool are not permitted by rustc, no need to handle them here. - TyInt(ty) => Ok(PrimVal::Bytes(self.int_to_int(v as i128, ty))), - TyUint(ty) => Ok(PrimVal::Bytes(self.int_to_uint(v, ty))), - - TyFloat(FloatTy::F64) if negative => Ok(PrimVal::from_f64(v as i128 as f64)), - TyFloat(FloatTy::F64) => Ok(PrimVal::from_f64(v as f64)), - TyFloat(FloatTy::F32) if negative => Ok(PrimVal::from_f32(v as i128 as f32)), - TyFloat(FloatTy::F32) => Ok(PrimVal::from_f32(v as f32)), - - TyChar if v as u8 as u128 == v => Ok(PrimVal::Bytes(v)), - TyChar => err!(InvalidChar(v)), - - // No alignment check needed for raw pointers. But we have to truncate to target ptr size. - TyRawPtr(_) => Ok(PrimVal::Bytes(self.memory.truncate_to_ptr(v).0 as u128)), - - _ => err!(Unimplemented(format!("int to {:?} cast", ty))), - } - } - - fn cast_from_float(&self, val: f64, ty: Ty<'tcx>) -> EvalResult<'tcx, PrimVal> { - use rustc::ty::TypeVariants::*; - match ty.sty { - // Casting negative floats to unsigned integers yields zero. - TyUint(_) if val < 0.0 => self.cast_from_int(0, ty, false), - TyInt(_) if val < 0.0 => self.cast_from_int(val as i128 as u128, ty, true), - - TyInt(_) | ty::TyUint(_) => self.cast_from_int(val as u128, ty, false), - - TyFloat(FloatTy::F64) => Ok(PrimVal::from_f64(val)), - TyFloat(FloatTy::F32) => Ok(PrimVal::from_f32(val as f32)), - _ => err!(Unimplemented(format!("float to {:?} cast", ty))), - } - } - - fn cast_from_ptr(&self, ptr: MemoryPointer, ty: Ty<'tcx>) -> EvalResult<'tcx, PrimVal> { - use rustc::ty::TypeVariants::*; - match ty.sty { - // Casting to a reference or fn pointer is not permitted by rustc, no need to support it here. - TyRawPtr(_) | - TyInt(IntTy::Is) | - TyUint(UintTy::Us) => Ok(PrimVal::Ptr(ptr)), - TyInt(_) | TyUint(_) => err!(ReadPointerAsBytes), - _ => err!(Unimplemented(format!("ptr to {:?} cast", ty))), - } - } -} diff --git a/src/librustc_mir/interpret/const_eval.rs b/src/librustc_mir/interpret/const_eval.rs deleted file mode 100644 index 075880fc5bfd1..0000000000000 --- a/src/librustc_mir/interpret/const_eval.rs +++ /dev/null @@ -1,259 +0,0 @@ -use rustc::traits::Reveal; -use rustc::ty::{self, TyCtxt, Ty, Instance, layout}; -use rustc::mir; - -use syntax::ast::Mutability; -use syntax::codemap::Span; - -use super::{EvalResult, EvalError, EvalErrorKind, GlobalId, Lvalue, Value, PrimVal, EvalContext, - StackPopCleanup, PtrAndAlign, MemoryKind, ValTy}; - -use rustc_const_math::ConstInt; - -use std::fmt; -use std::error::Error; - -pub fn eval_body_as_primval<'a, 'tcx>( - tcx: TyCtxt<'a, 'tcx, 'tcx>, - instance: Instance<'tcx>, -) -> EvalResult<'tcx, (PrimVal, Ty<'tcx>)> { - let limits = super::ResourceLimits::default(); - let mut ecx = EvalContext::::new(tcx, limits, (), ()); - let cid = GlobalId { - instance, - promoted: None, - }; - if ecx.tcx.has_attr(instance.def_id(), "linkage") { - return Err(ConstEvalError::NotConst("extern global".to_string()).into()); - } - - let mir = ecx.load_mir(instance.def)?; - if !ecx.globals.contains_key(&cid) { - let size = ecx.type_size_with_substs(mir.return_ty, instance.substs)? - .expect("unsized global"); - let align = ecx.type_align_with_substs(mir.return_ty, instance.substs)?; - let ptr = ecx.memory.allocate( - size, - align, - MemoryKind::UninitializedStatic, - )?; - let aligned = !ecx.is_packed(mir.return_ty)?; - ecx.globals.insert( - cid, - PtrAndAlign { - ptr: ptr.into(), - aligned, - }, - ); - let mutable = !mir.return_ty.is_freeze( - ecx.tcx, - ty::ParamEnv::empty(Reveal::All), - mir.span, - ); - let mutability = if mutable { - Mutability::Mutable - } else { - Mutability::Immutable - }; - let cleanup = StackPopCleanup::MarkStatic(mutability); - let name = ty::tls::with(|tcx| tcx.item_path_str(instance.def_id())); - trace!("const_eval: pushing stack frame for global: {}", name); - ecx.push_stack_frame( - instance, - mir.span, - mir, - Lvalue::from_ptr(ptr), - cleanup, - )?; - - while ecx.step()? {} - } - let value = Value::ByRef(*ecx.globals.get(&cid).expect("global not cached")); - let valty = ValTy { - value, - ty: mir.return_ty, - }; - Ok((ecx.value_to_primval(valty)?, mir.return_ty)) -} - -pub fn eval_body_as_integer<'a, 'tcx>( - tcx: TyCtxt<'a, 'tcx, 'tcx>, - instance: Instance<'tcx>, -) -> EvalResult<'tcx, ConstInt> { - let (prim, ty) = eval_body_as_primval(tcx, instance)?; - let prim = prim.to_bytes()?; - use syntax::ast::{IntTy, UintTy}; - use rustc::ty::TypeVariants::*; - use rustc_const_math::{ConstIsize, ConstUsize}; - Ok(match ty.sty { - TyInt(IntTy::I8) => ConstInt::I8(prim as i128 as i8), - TyInt(IntTy::I16) => ConstInt::I16(prim as i128 as i16), - TyInt(IntTy::I32) => ConstInt::I32(prim as i128 as i32), - TyInt(IntTy::I64) => ConstInt::I64(prim as i128 as i64), - TyInt(IntTy::I128) => ConstInt::I128(prim as i128), - TyInt(IntTy::Is) => ConstInt::Isize( - ConstIsize::new(prim as i128 as i64, tcx.sess.target.isize_ty) - .expect("miri should already have errored"), - ), - TyUint(UintTy::U8) => ConstInt::U8(prim as u8), - TyUint(UintTy::U16) => ConstInt::U16(prim as u16), - TyUint(UintTy::U32) => ConstInt::U32(prim as u32), - TyUint(UintTy::U64) => ConstInt::U64(prim as u64), - TyUint(UintTy::U128) => ConstInt::U128(prim), - TyUint(UintTy::Us) => ConstInt::Usize( - ConstUsize::new(prim as u64, tcx.sess.target.usize_ty) - .expect("miri should already have errored"), - ), - _ => { - return Err( - ConstEvalError::NeedsRfc( - "evaluating anything other than isize/usize during typeck".to_string(), - ).into(), - ) - } - }) -} - -struct CompileTimeFunctionEvaluator; - -impl<'tcx> Into> for ConstEvalError { - fn into(self) -> EvalError<'tcx> { - EvalErrorKind::MachineError(Box::new(self)).into() - } -} - -#[derive(Clone, Debug)] -enum ConstEvalError { - NeedsRfc(String), - NotConst(String), -} - -impl fmt::Display for ConstEvalError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - use self::ConstEvalError::*; - match *self { - NeedsRfc(ref msg) => { - write!( - f, - "\"{}\" needs an rfc before being allowed inside constants", - msg - ) - } - NotConst(ref msg) => write!(f, "Cannot evaluate within constants: \"{}\"", msg), - } - } -} - -impl Error for ConstEvalError { - fn description(&self) -> &str { - use self::ConstEvalError::*; - match *self { - NeedsRfc(_) => "this feature needs an rfc before being allowed inside constants", - NotConst(_) => "this feature is not compatible with constant evaluation", - } - } - - fn cause(&self) -> Option<&Error> { - None - } -} - -impl<'tcx> super::Machine<'tcx> for CompileTimeFunctionEvaluator { - type Data = (); - type MemoryData = (); - type MemoryKinds = !; - fn eval_fn_call<'a>( - ecx: &mut EvalContext<'a, 'tcx, Self>, - instance: ty::Instance<'tcx>, - destination: Option<(Lvalue, mir::BasicBlock)>, - _args: &[ValTy<'tcx>], - span: Span, - _sig: ty::FnSig<'tcx>, - ) -> EvalResult<'tcx, bool> { - if !ecx.tcx.is_const_fn(instance.def_id()) { - return Err( - ConstEvalError::NotConst(format!("calling non-const fn `{}`", instance)).into(), - ); - } - let mir = match ecx.load_mir(instance.def) { - Ok(mir) => mir, - Err(EvalError { kind: EvalErrorKind::NoMirFor(path), .. }) => { - // some simple things like `malloc` might get accepted in the future - return Err( - ConstEvalError::NeedsRfc(format!("calling extern function `{}`", path)) - .into(), - ); - } - Err(other) => return Err(other), - }; - let (return_lvalue, return_to_block) = match destination { - Some((lvalue, block)) => (lvalue, StackPopCleanup::Goto(block)), - None => (Lvalue::undef(), StackPopCleanup::None), - }; - - ecx.push_stack_frame( - instance, - span, - mir, - return_lvalue, - return_to_block, - )?; - - Ok(false) - } - - fn call_intrinsic<'a>( - _ecx: &mut EvalContext<'a, 'tcx, Self>, - _instance: ty::Instance<'tcx>, - _args: &[ValTy<'tcx>], - _dest: Lvalue, - _dest_ty: Ty<'tcx>, - _dest_layout: &'tcx layout::Layout, - _target: mir::BasicBlock, - ) -> EvalResult<'tcx> { - Err( - ConstEvalError::NeedsRfc("calling intrinsics".to_string()).into(), - ) - } - - fn try_ptr_op<'a>( - _ecx: &EvalContext<'a, 'tcx, Self>, - _bin_op: mir::BinOp, - left: PrimVal, - _left_ty: Ty<'tcx>, - right: PrimVal, - _right_ty: Ty<'tcx>, - ) -> EvalResult<'tcx, Option<(PrimVal, bool)>> { - if left.is_bytes() && right.is_bytes() { - Ok(None) - } else { - Err( - ConstEvalError::NeedsRfc("Pointer arithmetic or comparison".to_string()).into(), - ) - } - } - - fn mark_static_initialized(m: !) -> EvalResult<'tcx> { - m - } - - fn box_alloc<'a>( - _ecx: &mut EvalContext<'a, 'tcx, Self>, - _ty: ty::Ty<'tcx>, - _dest: Lvalue, - ) -> EvalResult<'tcx> { - Err( - ConstEvalError::NeedsRfc("Heap allocations via `box` keyword".to_string()).into(), - ) - } - - fn global_item_with_linkage<'a>( - _ecx: &mut EvalContext<'a, 'tcx, Self>, - _instance: ty::Instance<'tcx>, - _mutability: Mutability, - ) -> EvalResult<'tcx> { - Err( - ConstEvalError::NotConst("statics with `linkage` attribute".to_string()).into(), - ) - } -} diff --git a/src/librustc_mir/interpret/error.rs b/src/librustc_mir/interpret/error.rs deleted file mode 100644 index 96911c10cca80..0000000000000 --- a/src/librustc_mir/interpret/error.rs +++ /dev/null @@ -1,313 +0,0 @@ -use std::error::Error; -use std::{fmt, env}; - -use rustc::mir; -use rustc::ty::{FnSig, Ty, layout}; - -use super::{ - MemoryPointer, Lock, AccessKind -}; - -use rustc_const_math::ConstMathErr; -use syntax::codemap::Span; -use backtrace::Backtrace; - -#[derive(Debug)] -pub struct EvalError<'tcx> { - pub kind: EvalErrorKind<'tcx>, - pub backtrace: Option, -} - -impl<'tcx> From> for EvalError<'tcx> { - fn from(kind: EvalErrorKind<'tcx>) -> Self { - let backtrace = match env::var("RUST_BACKTRACE") { - Ok(ref val) if !val.is_empty() => Some(Backtrace::new_unresolved()), - _ => None - }; - EvalError { - kind, - backtrace, - } - } -} - -#[derive(Debug)] -pub enum EvalErrorKind<'tcx> { - /// This variant is used by machines to signal their own errors that do not - /// match an existing variant - MachineError(Box), - FunctionPointerTyMismatch(FnSig<'tcx>, FnSig<'tcx>), - NoMirFor(String), - UnterminatedCString(MemoryPointer), - DanglingPointerDeref, - DoubleFree, - InvalidMemoryAccess, - InvalidFunctionPointer, - InvalidBool, - InvalidDiscriminant, - PointerOutOfBounds { - ptr: MemoryPointer, - access: bool, - allocation_size: u64, - }, - InvalidNullPointerUsage, - ReadPointerAsBytes, - ReadBytesAsPointer, - InvalidPointerMath, - ReadUndefBytes, - DeadLocal, - InvalidBoolOp(mir::BinOp), - Unimplemented(String), - DerefFunctionPointer, - ExecuteMemory, - ArrayIndexOutOfBounds(Span, u64, u64), - Math(Span, ConstMathErr), - Intrinsic(String), - OverflowingMath, - InvalidChar(u128), - OutOfMemory { - allocation_size: u64, - memory_size: u64, - memory_usage: u64, - }, - ExecutionTimeLimitReached, - StackFrameLimitReached, - OutOfTls, - TlsOutOfBounds, - AbiViolation(String), - AlignmentCheckFailed { - required: u64, - has: u64, - }, - MemoryLockViolation { - ptr: MemoryPointer, - len: u64, - frame: usize, - access: AccessKind, - lock: Lock, - }, - MemoryAcquireConflict { - ptr: MemoryPointer, - len: u64, - kind: AccessKind, - lock: Lock, - }, - InvalidMemoryLockRelease { - ptr: MemoryPointer, - len: u64, - frame: usize, - lock: Lock, - }, - DeallocatedLockedMemory { - ptr: MemoryPointer, - lock: Lock, - }, - ValidationFailure(String), - CalledClosureAsFunction, - VtableForArgumentlessMethod, - ModifiedConstantMemory, - AssumptionNotHeld, - InlineAsm, - TypeNotPrimitive(Ty<'tcx>), - ReallocatedWrongMemoryKind(String, String), - DeallocatedWrongMemoryKind(String, String), - ReallocateNonBasePtr, - DeallocateNonBasePtr, - IncorrectAllocationInformation, - Layout(layout::LayoutError<'tcx>), - HeapAllocZeroBytes, - HeapAllocNonPowerOfTwoAlignment(u64), - Unreachable, - Panic, - ReadFromReturnPointer, - PathNotFound(Vec), -} - -pub type EvalResult<'tcx, T = ()> = Result>; - -impl<'tcx> Error for EvalError<'tcx> { - fn description(&self) -> &str { - use self::EvalErrorKind::*; - match self.kind { - MachineError(ref inner) => inner.description(), - FunctionPointerTyMismatch(..) => - "tried to call a function through a function pointer of a different type", - InvalidMemoryAccess => - "tried to access memory through an invalid pointer", - DanglingPointerDeref => - "dangling pointer was dereferenced", - DoubleFree => - "tried to deallocate dangling pointer", - InvalidFunctionPointer => - "tried to use a function pointer after offsetting it", - InvalidBool => - "invalid boolean value read", - InvalidDiscriminant => - "invalid enum discriminant value read", - PointerOutOfBounds { .. } => - "pointer offset outside bounds of allocation", - InvalidNullPointerUsage => - "invalid use of NULL pointer", - MemoryLockViolation { .. } => - "memory access conflicts with lock", - MemoryAcquireConflict { .. } => - "new memory lock conflicts with existing lock", - ValidationFailure(..) => - "type validation failed", - InvalidMemoryLockRelease { .. } => - "invalid attempt to release write lock", - DeallocatedLockedMemory { .. } => - "tried to deallocate memory in conflict with a lock", - ReadPointerAsBytes => - "a raw memory access tried to access part of a pointer value as raw bytes", - ReadBytesAsPointer => - "a memory access tried to interpret some bytes as a pointer", - InvalidPointerMath => - "attempted to do invalid arithmetic on pointers that would leak base addresses, e.g. comparing pointers into different allocations", - ReadUndefBytes => - "attempted to read undefined bytes", - DeadLocal => - "tried to access a dead local variable", - InvalidBoolOp(_) => - "invalid boolean operation", - Unimplemented(ref msg) => msg, - DerefFunctionPointer => - "tried to dereference a function pointer", - ExecuteMemory => - "tried to treat a memory pointer as a function pointer", - ArrayIndexOutOfBounds(..) => - "array index out of bounds", - Math(..) => - "mathematical operation failed", - Intrinsic(..) => - "intrinsic failed", - OverflowingMath => - "attempted to do overflowing math", - NoMirFor(..) => - "mir not found", - InvalidChar(..) => - "tried to interpret an invalid 32-bit value as a char", - OutOfMemory{..} => - "could not allocate more memory", - ExecutionTimeLimitReached => - "reached the configured maximum execution time", - StackFrameLimitReached => - "reached the configured maximum number of stack frames", - OutOfTls => - "reached the maximum number of representable TLS keys", - TlsOutOfBounds => - "accessed an invalid (unallocated) TLS key", - AbiViolation(ref msg) => msg, - AlignmentCheckFailed{..} => - "tried to execute a misaligned read or write", - CalledClosureAsFunction => - "tried to call a closure through a function pointer", - VtableForArgumentlessMethod => - "tried to call a vtable function without arguments", - ModifiedConstantMemory => - "tried to modify constant memory", - AssumptionNotHeld => - "`assume` argument was false", - InlineAsm => - "miri does not support inline assembly", - TypeNotPrimitive(_) => - "expected primitive type, got nonprimitive", - ReallocatedWrongMemoryKind(_, _) => - "tried to reallocate memory from one kind to another", - DeallocatedWrongMemoryKind(_, _) => - "tried to deallocate memory of the wrong kind", - ReallocateNonBasePtr => - "tried to reallocate with a pointer not to the beginning of an existing object", - DeallocateNonBasePtr => - "tried to deallocate with a pointer not to the beginning of an existing object", - IncorrectAllocationInformation => - "tried to deallocate or reallocate using incorrect alignment or size", - Layout(_) => - "rustc layout computation failed", - UnterminatedCString(_) => - "attempted to get length of a null terminated string, but no null found before end of allocation", - HeapAllocZeroBytes => - "tried to re-, de- or allocate zero bytes on the heap", - HeapAllocNonPowerOfTwoAlignment(_) => - "tried to re-, de-, or allocate heap memory with alignment that is not a power of two", - Unreachable => - "entered unreachable code", - Panic => - "the evaluated program panicked", - ReadFromReturnPointer => - "tried to read from the return pointer", - EvalErrorKind::PathNotFound(_) => - "a path could not be resolved, maybe the crate is not loaded", - } - } - - fn cause(&self) -> Option<&Error> { - use self::EvalErrorKind::*; - match self.kind { - MachineError(ref inner) => Some(&**inner), - _ => None, - } - } -} - -impl<'tcx> fmt::Display for EvalError<'tcx> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - use self::EvalErrorKind::*; - match self.kind { - PointerOutOfBounds { ptr, access, allocation_size } => { - write!(f, "{} at offset {}, outside bounds of allocation {} which has size {}", - if access { "memory access" } else { "pointer computed" }, - ptr.offset, ptr.alloc_id, allocation_size) - }, - MemoryLockViolation { ptr, len, frame, access, ref lock } => { - write!(f, "{:?} access by frame {} at {:?}, size {}, is in conflict with lock {:?}", - access, frame, ptr, len, lock) - } - MemoryAcquireConflict { ptr, len, kind, ref lock } => { - write!(f, "new {:?} lock at {:?}, size {}, is in conflict with lock {:?}", - kind, ptr, len, lock) - } - InvalidMemoryLockRelease { ptr, len, frame, ref lock } => { - write!(f, "frame {} tried to release memory write lock at {:?}, size {}, but cannot release lock {:?}", - frame, ptr, len, lock) - } - DeallocatedLockedMemory { ptr, ref lock } => { - write!(f, "tried to deallocate memory at {:?} in conflict with lock {:?}", - ptr, lock) - } - ValidationFailure(ref err) => { - write!(f, "type validation failed: {}", err) - } - NoMirFor(ref func) => write!(f, "no mir for `{}`", func), - FunctionPointerTyMismatch(sig, got) => - write!(f, "tried to call a function with sig {} through a function pointer of type {}", sig, got), - ArrayIndexOutOfBounds(span, len, index) => - write!(f, "index out of bounds: the len is {} but the index is {} at {:?}", len, index, span), - ReallocatedWrongMemoryKind(ref old, ref new) => - write!(f, "tried to reallocate memory from {} to {}", old, new), - DeallocatedWrongMemoryKind(ref old, ref new) => - write!(f, "tried to deallocate {} memory but gave {} as the kind", old, new), - Math(span, ref err) => - write!(f, "{:?} at {:?}", err, span), - Intrinsic(ref err) => - write!(f, "{}", err), - InvalidChar(c) => - write!(f, "tried to interpret an invalid 32-bit value as a char: {}", c), - OutOfMemory { allocation_size, memory_size, memory_usage } => - write!(f, "tried to allocate {} more bytes, but only {} bytes are free of the {} byte memory", - allocation_size, memory_size - memory_usage, memory_size), - AlignmentCheckFailed { required, has } => - write!(f, "tried to access memory with alignment {}, but alignment {} is required", - has, required), - TypeNotPrimitive(ty) => - write!(f, "expected primitive type, got {}", ty), - Layout(ref err) => - write!(f, "rustc layout computation failed: {:?}", err), - PathNotFound(ref path) => - write!(f, "Cannot find path {:?}", path), - MachineError(ref inner) => - write!(f, "machine error: {}", inner), - _ => write!(f, "{}", self.description()), - } - } -} diff --git a/src/librustc_mir/interpret/eval_context.rs b/src/librustc_mir/interpret/eval_context.rs deleted file mode 100644 index b483cf1aed869..0000000000000 --- a/src/librustc_mir/interpret/eval_context.rs +++ /dev/null @@ -1,2535 +0,0 @@ -use std::collections::{HashMap, HashSet}; -use std::fmt::Write; - -use rustc::hir::def_id::DefId; -use rustc::hir::map::definitions::DefPathData; -use rustc::middle::const_val::ConstVal; -use rustc::middle::region; -use rustc::mir; -use rustc::traits; -use rustc::traits::Reveal; -use rustc::ty::layout::{self, Layout, Size, Align, HasDataLayout}; -use rustc::ty::subst::{Subst, Substs, Kind}; -use rustc::ty::{self, Ty, TyCtxt, TypeFoldable}; -use rustc_data_structures::indexed_vec::Idx; -use syntax::codemap::{self, DUMMY_SP}; -use syntax::ast::Mutability; -use syntax::abi::Abi; - -use super::{EvalError, EvalResult, EvalErrorKind, GlobalId, Lvalue, LvalueExtra, Memory, - MemoryPointer, HasMemory, MemoryKind, operator, PrimVal, PrimValKind, Value, Pointer, - ValidationQuery, Machine}; - -pub struct EvalContext<'a, 'tcx: 'a, M: Machine<'tcx>> { - /// Stores data required by the `Machine` - pub machine_data: M::Data, - - /// The results of the type checker, from rustc. - pub tcx: TyCtxt<'a, 'tcx, 'tcx>, - - /// The virtual memory system. - pub memory: Memory<'a, 'tcx, M>, - - /// Lvalues that were suspended by the validation subsystem, and will be recovered later - pub(crate) suspended: HashMap>>, - - /// Precomputed statics, constants and promoteds. - pub globals: HashMap, PtrAndAlign>, - - /// The virtual call stack. - pub(crate) stack: Vec>, - - /// The maximum number of stack frames allowed - pub(crate) stack_limit: usize, - - /// The maximum number of operations that may be executed. - /// This prevents infinite loops and huge computations from freezing up const eval. - /// Remove once halting problem is solved. - pub(crate) steps_remaining: u64, -} - -/// A stack frame. -pub struct Frame<'tcx> { - //////////////////////////////////////////////////////////////////////////////// - // Function and callsite information - //////////////////////////////////////////////////////////////////////////////// - /// The MIR for the function called on this frame. - pub mir: &'tcx mir::Mir<'tcx>, - - /// The def_id and substs of the current function - pub instance: ty::Instance<'tcx>, - - /// The span of the call site. - pub span: codemap::Span, - - //////////////////////////////////////////////////////////////////////////////// - // Return lvalue and locals - //////////////////////////////////////////////////////////////////////////////// - /// The block to return to when returning from the current stack frame - pub return_to_block: StackPopCleanup, - - /// The location where the result of the current stack frame should be written to. - pub return_lvalue: Lvalue, - - /// The list of locals for this stack frame, stored in order as - /// `[arguments..., variables..., temporaries...]`. The locals are stored as `Option`s. - /// `None` represents a local that is currently dead, while a live local - /// can either directly contain `PrimVal` or refer to some part of an `Allocation`. - /// - /// Before being initialized, arguments are `Value::ByVal(PrimVal::Undef)` and other locals are `None`. - pub locals: Vec>, - - //////////////////////////////////////////////////////////////////////////////// - // Current position within the function - //////////////////////////////////////////////////////////////////////////////// - /// The block that is currently executed (or will be executed after the above call stacks - /// return). - pub block: mir::BasicBlock, - - /// The index of the currently evaluated statment. - pub stmt: usize, -} - -#[derive(Clone, Debug, Eq, PartialEq, Hash)] -pub enum StackPopCleanup { - /// The stackframe existed to compute the initial value of a static/constant, make sure it - /// isn't modifyable afterwards in case of constants. - /// In case of `static mut`, mark the memory to ensure it's never marked as immutable through - /// references or deallocated - MarkStatic(Mutability), - /// A regular stackframe added due to a function call will need to get forwarded to the next - /// block - Goto(mir::BasicBlock), - /// The main function and diverging functions have nowhere to return to - None, -} - -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] -pub struct DynamicLifetime { - pub frame: usize, - pub region: Option, // "None" indicates "until the function ends" -} - -#[derive(Copy, Clone, Debug)] -pub struct ResourceLimits { - pub memory_size: u64, - pub step_limit: u64, - pub stack_limit: usize, -} - -impl Default for ResourceLimits { - fn default() -> Self { - ResourceLimits { - memory_size: 100 * 1024 * 1024, // 100 MB - step_limit: 1_000_000, - stack_limit: 100, - } - } -} - -#[derive(Copy, Clone, Debug)] -pub struct TyAndPacked<'tcx> { - pub ty: Ty<'tcx>, - pub packed: bool, -} - -#[derive(Copy, Clone, Debug)] -pub struct ValTy<'tcx> { - pub value: Value, - pub ty: Ty<'tcx>, -} - -impl<'tcx> ::std::ops::Deref for ValTy<'tcx> { - type Target = Value; - fn deref(&self) -> &Value { - &self.value - } -} - -#[derive(Copy, Clone, Debug)] -pub struct PtrAndAlign { - pub ptr: Pointer, - /// Remember whether this lvalue is *supposed* to be aligned. - pub aligned: bool, -} - -impl PtrAndAlign { - pub fn to_ptr<'tcx>(self) -> EvalResult<'tcx, MemoryPointer> { - self.ptr.to_ptr() - } - pub fn offset<'tcx, C: HasDataLayout>(self, i: u64, cx: C) -> EvalResult<'tcx, Self> { - Ok(PtrAndAlign { - ptr: self.ptr.offset(i, cx)?, - aligned: self.aligned, - }) - } -} - -impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { - pub fn new( - tcx: TyCtxt<'a, 'tcx, 'tcx>, - limits: ResourceLimits, - machine_data: M::Data, - memory_data: M::MemoryData, - ) -> Self { - EvalContext { - machine_data, - tcx, - memory: Memory::new(&tcx.data_layout, limits.memory_size, memory_data), - suspended: HashMap::new(), - globals: HashMap::new(), - stack: Vec::new(), - stack_limit: limits.stack_limit, - steps_remaining: limits.step_limit, - } - } - - pub fn alloc_ptr(&mut self, ty: Ty<'tcx>) -> EvalResult<'tcx, MemoryPointer> { - let substs = self.substs(); - self.alloc_ptr_with_substs(ty, substs) - } - - pub fn alloc_ptr_with_substs( - &mut self, - ty: Ty<'tcx>, - substs: &'tcx Substs<'tcx>, - ) -> EvalResult<'tcx, MemoryPointer> { - let size = self.type_size_with_substs(ty, substs)?.expect( - "cannot alloc memory for unsized type", - ); - let align = self.type_align_with_substs(ty, substs)?; - self.memory.allocate(size, align, MemoryKind::Stack) - } - - pub fn memory(&self) -> &Memory<'a, 'tcx, M> { - &self.memory - } - - pub fn memory_mut(&mut self) -> &mut Memory<'a, 'tcx, M> { - &mut self.memory - } - - pub fn stack(&self) -> &[Frame<'tcx>] { - &self.stack - } - - #[inline] - pub fn cur_frame(&self) -> usize { - assert!(self.stack.len() > 0); - self.stack.len() - 1 - } - - pub fn str_to_value(&mut self, s: &str) -> EvalResult<'tcx, Value> { - let ptr = self.memory.allocate_cached(s.as_bytes())?; - Ok(Value::ByValPair( - PrimVal::Ptr(ptr), - PrimVal::from_u128(s.len() as u128), - )) - } - - pub(super) fn const_to_value(&mut self, const_val: &ConstVal<'tcx>) -> EvalResult<'tcx, Value> { - use rustc::middle::const_val::ConstVal::*; - - let primval = match *const_val { - Integral(const_int) => PrimVal::Bytes(const_int.to_u128_unchecked()), - - Float(val) => PrimVal::Bytes(val.bits), - - Bool(b) => PrimVal::from_bool(b), - Char(c) => PrimVal::from_char(c), - - Str(ref s) => return self.str_to_value(s), - - ByteStr(ref bs) => { - let ptr = self.memory.allocate_cached(bs.data)?; - PrimVal::Ptr(ptr) - } - - Unevaluated(def_id, substs) => { - let instance = self.resolve_associated_const(def_id, substs); - let cid = GlobalId { - instance, - promoted: None, - }; - return Ok(Value::ByRef(*self.globals.get(&cid).expect("static/const not cached"))); - } - - Aggregate(..) | - Variant(_) => bug!("should not have aggregate or variant constants in MIR"), - // function items are zero sized and thus have no readable value - Function(..) => PrimVal::Undef, - }; - - Ok(Value::ByVal(primval)) - } - - pub(super) fn type_is_sized(&self, ty: Ty<'tcx>) -> bool { - // generics are weird, don't run this function on a generic - assert!(!ty.needs_subst()); - ty.is_sized(self.tcx, ty::ParamEnv::empty(Reveal::All), DUMMY_SP) - } - - pub fn load_mir( - &self, - instance: ty::InstanceDef<'tcx>, - ) -> EvalResult<'tcx, &'tcx mir::Mir<'tcx>> { - trace!("load mir {:?}", instance); - match instance { - ty::InstanceDef::Item(def_id) => { - self.tcx.maybe_optimized_mir(def_id).ok_or_else(|| { - EvalErrorKind::NoMirFor(self.tcx.item_path_str(def_id)).into() - }) - } - _ => Ok(self.tcx.instance_mir(instance)), - } - } - - pub fn monomorphize(&self, ty: Ty<'tcx>, substs: &'tcx Substs<'tcx>) -> Ty<'tcx> { - // miri doesn't care about lifetimes, and will choke on some crazy ones - // let's simply get rid of them - let without_lifetimes = self.tcx.erase_regions(&ty); - let substituted = without_lifetimes.subst(self.tcx, substs); - let substituted = self.tcx.normalize_associated_type(&substituted); - substituted - } - - /// Return the size and aligment of the value at the given type. - /// Note that the value does not matter if the type is sized. For unsized types, - /// the value has to be a fat pointer, and we only care about the "extra" data in it. - pub fn size_and_align_of_dst( - &mut self, - ty: ty::Ty<'tcx>, - value: Value, - ) -> EvalResult<'tcx, (u64, u64)> { - if let Some(size) = self.type_size(ty)? { - Ok((size as u64, self.type_align(ty)? as u64)) - } else { - match ty.sty { - ty::TyAdt(..) | ty::TyTuple(..) => { - // First get the size of all statically known fields. - // Don't use type_of::sizing_type_of because that expects t to be sized, - // and it also rounds up to alignment, which we want to avoid, - // as the unsized field's alignment could be smaller. - assert!(!ty.is_simd()); - let layout = self.type_layout(ty)?; - debug!("DST {} layout: {:?}", ty, layout); - - let (sized_size, sized_align) = match *layout { - ty::layout::Layout::Univariant { ref variant, .. } => { - ( - variant.offsets.last().map_or(0, |o| o.bytes()), - variant.align, - ) - } - _ => { - bug!( - "size_and_align_of_dst: expcted Univariant for `{}`, found {:#?}", - ty, - layout - ); - } - }; - debug!( - "DST {} statically sized prefix size: {} align: {:?}", - ty, - sized_size, - sized_align - ); - - // Recurse to get the size of the dynamically sized field (must be - // the last field). - let (unsized_size, unsized_align) = match ty.sty { - ty::TyAdt(def, substs) => { - let last_field = def.struct_variant().fields.last().unwrap(); - let field_ty = self.field_ty(substs, last_field); - self.size_and_align_of_dst(field_ty, value)? - } - ty::TyTuple(ref types, _) => { - let field_ty = types.last().unwrap(); - let field_ty = self.tcx.normalize_associated_type(field_ty); - self.size_and_align_of_dst(field_ty, value)? - } - _ => bug!("We already checked that we know this type"), - }; - - // FIXME (#26403, #27023): We should be adding padding - // to `sized_size` (to accommodate the `unsized_align` - // required of the unsized field that follows) before - // summing it with `sized_size`. (Note that since #26403 - // is unfixed, we do not yet add the necessary padding - // here. But this is where the add would go.) - - // Return the sum of sizes and max of aligns. - let size = sized_size + unsized_size; - - // Choose max of two known alignments (combined value must - // be aligned according to more restrictive of the two). - let align = - sized_align.max(Align::from_bytes(unsized_align, unsized_align).unwrap()); - - // Issue #27023: must add any necessary padding to `size` - // (to make it a multiple of `align`) before returning it. - // - // Namely, the returned size should be, in C notation: - // - // `size + ((size & (align-1)) ? align : 0)` - // - // emulated via the semi-standard fast bit trick: - // - // `(size + (align-1)) & -align` - - let size = Size::from_bytes(size).abi_align(align).bytes(); - Ok((size, align.abi())) - } - ty::TyDynamic(..) => { - let (_, vtable) = value.into_ptr_vtable_pair(&mut self.memory)?; - // the second entry in the vtable is the dynamic size of the object. - self.read_size_and_align_from_vtable(vtable) - } - - ty::TySlice(_) | ty::TyStr => { - let elem_ty = ty.sequence_element_type(self.tcx); - let elem_size = self.type_size(elem_ty)?.expect( - "slice element must be sized", - ) as u64; - let (_, len) = value.into_slice(&mut self.memory)?; - let align = self.type_align(elem_ty)?; - Ok((len * elem_size, align as u64)) - } - - _ => bug!("size_of_val::<{:?}>", ty), - } - } - } - - /// Returns the normalized type of a struct field - fn field_ty(&self, param_substs: &Substs<'tcx>, f: &ty::FieldDef) -> ty::Ty<'tcx> { - self.tcx.normalize_associated_type( - &f.ty(self.tcx, param_substs), - ) - } - - pub fn type_size(&self, ty: Ty<'tcx>) -> EvalResult<'tcx, Option> { - self.type_size_with_substs(ty, self.substs()) - } - - pub fn type_align(&self, ty: Ty<'tcx>) -> EvalResult<'tcx, u64> { - self.type_align_with_substs(ty, self.substs()) - } - - pub fn type_size_with_substs( - &self, - ty: Ty<'tcx>, - substs: &'tcx Substs<'tcx>, - ) -> EvalResult<'tcx, Option> { - let layout = self.type_layout_with_substs(ty, substs)?; - if layout.is_unsized() { - Ok(None) - } else { - Ok(Some(layout.size(&self.tcx.data_layout).bytes())) - } - } - - pub fn type_align_with_substs( - &self, - ty: Ty<'tcx>, - substs: &'tcx Substs<'tcx>, - ) -> EvalResult<'tcx, u64> { - self.type_layout_with_substs(ty, substs).map(|layout| { - layout.align(&self.tcx.data_layout).abi() - }) - } - - pub fn type_layout(&self, ty: Ty<'tcx>) -> EvalResult<'tcx, &'tcx Layout> { - self.type_layout_with_substs(ty, self.substs()) - } - - fn type_layout_with_substs( - &self, - ty: Ty<'tcx>, - substs: &'tcx Substs<'tcx>, - ) -> EvalResult<'tcx, &'tcx Layout> { - // TODO(solson): Is this inefficient? Needs investigation. - let ty = self.monomorphize(ty, substs); - - ty.layout(self.tcx, ty::ParamEnv::empty(Reveal::All)) - .map_err(|layout| EvalErrorKind::Layout(layout).into()) - } - - pub fn push_stack_frame( - &mut self, - instance: ty::Instance<'tcx>, - span: codemap::Span, - mir: &'tcx mir::Mir<'tcx>, - return_lvalue: Lvalue, - return_to_block: StackPopCleanup, - ) -> EvalResult<'tcx> { - ::log_settings::settings().indentation += 1; - - /// Return the set of locals that have a storage annotation anywhere - fn collect_storage_annotations<'tcx>(mir: &'tcx mir::Mir<'tcx>) -> HashSet { - use rustc::mir::StatementKind::*; - - let mut set = HashSet::new(); - for block in mir.basic_blocks() { - for stmt in block.statements.iter() { - match stmt.kind { - StorageLive(local) | - StorageDead(local) => { - set.insert(local); - } - _ => {} - } - } - } - set - } - - // Subtract 1 because `local_decls` includes the ReturnMemoryPointer, but we don't store a local - // `Value` for that. - let num_locals = mir.local_decls.len() - 1; - - let locals = { - let annotated_locals = collect_storage_annotations(mir); - let mut locals = vec![None; num_locals]; - for i in 0..num_locals { - let local = mir::Local::new(i + 1); - if !annotated_locals.contains(&local) { - locals[i] = Some(Value::ByVal(PrimVal::Undef)); - } - } - locals - }; - - self.stack.push(Frame { - mir, - block: mir::START_BLOCK, - return_to_block, - return_lvalue, - locals, - span, - instance, - stmt: 0, - }); - - self.memory.cur_frame = self.cur_frame(); - - if self.stack.len() > self.stack_limit { - err!(StackFrameLimitReached) - } else { - Ok(()) - } - } - - pub(super) fn pop_stack_frame(&mut self) -> EvalResult<'tcx> { - ::log_settings::settings().indentation -= 1; - self.end_region(None)?; - let frame = self.stack.pop().expect( - "tried to pop a stack frame, but there were none", - ); - if !self.stack.is_empty() { - // TODO: Is this the correct time to start considering these accesses as originating from the returned-to stack frame? - self.memory.cur_frame = self.cur_frame(); - } - match frame.return_to_block { - StackPopCleanup::MarkStatic(mutable) => { - if let Lvalue::Ptr { ptr, .. } = frame.return_lvalue { - // FIXME: to_ptr()? might be too extreme here, static zsts might reach this under certain conditions - self.memory.mark_static_initalized( - ptr.to_ptr()?.alloc_id, - mutable, - )? - } else { - bug!("StackPopCleanup::MarkStatic on: {:?}", frame.return_lvalue); - } - } - StackPopCleanup::Goto(target) => self.goto_block(target), - StackPopCleanup::None => {} - } - // deallocate all locals that are backed by an allocation - for local in frame.locals { - self.deallocate_local(local)?; - } - - Ok(()) - } - - pub fn deallocate_local(&mut self, local: Option) -> EvalResult<'tcx> { - if let Some(Value::ByRef(ptr)) = local { - trace!("deallocating local"); - let ptr = ptr.to_ptr()?; - self.memory.dump_alloc(ptr.alloc_id); - match self.memory.get(ptr.alloc_id)?.kind { - // for a constant like `const FOO: &i32 = &1;` the local containing - // the `1` is referred to by the global. We transitively marked everything - // the global refers to as static itself, so we don't free it here - MemoryKind::Static => {} - MemoryKind::Stack => self.memory.deallocate(ptr, None, MemoryKind::Stack)?, - other => bug!("local contained non-stack memory: {:?}", other), - } - }; - Ok(()) - } - - pub fn assign_discr_and_fields( - &mut self, - dest: Lvalue, - dest_ty: Ty<'tcx>, - discr_offset: u64, - operands: &[mir::Operand<'tcx>], - 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_primval(discr_dest, PrimVal::Bytes(discr_val), discr_size, discr_signed)?; - - let dest = Lvalue::Ptr { - ptr: PtrAndAlign { - ptr: dest_ptr.into(), - aligned: true, - }, - extra: LvalueExtra::DowncastVariant(variant_idx), - }; - - self.assign_fields(dest, dest_ty, operands) - } - - pub fn assign_fields( - &mut self, - dest: Lvalue, - dest_ty: Ty<'tcx>, - operands: &[mir::Operand<'tcx>], - ) -> EvalResult<'tcx> { - if self.type_size(dest_ty)? == Some(0) { - // zst assigning is a nop - return Ok(()); - } - if self.ty_to_primval_kind(dest_ty).is_ok() { - assert_eq!(operands.len(), 1); - let value = self.eval_operand(&operands[0])?; - return self.write_value(value, dest); - } - for (field_index, operand) in operands.iter().enumerate() { - let value = self.eval_operand(operand)?; - let field_dest = self.lvalue_field(dest, mir::Field::new(field_index), dest_ty, value.ty)?; - self.write_value(value, field_dest)?; - } - Ok(()) - } - - /// Evaluate an assignment statement. - /// - /// There is no separate `eval_rvalue` function. Instead, the code for handling each rvalue - /// type writes its results directly into the memory specified by the lvalue. - pub(super) fn eval_rvalue_into_lvalue( - &mut self, - rvalue: &mir::Rvalue<'tcx>, - lvalue: &mir::Lvalue<'tcx>, - ) -> EvalResult<'tcx> { - let dest = self.eval_lvalue(lvalue)?; - let dest_ty = self.lvalue_ty(lvalue); - let dest_layout = self.type_layout(dest_ty)?; - - use rustc::mir::Rvalue::*; - match *rvalue { - Use(ref operand) => { - let value = self.eval_operand(operand)?.value; - let valty = ValTy { - value, - ty: dest_ty, - }; - self.write_value(valty, dest)?; - } - - BinaryOp(bin_op, ref left, ref right) => { - let left = self.eval_operand(left)?; - let right = self.eval_operand(right)?; - if self.intrinsic_overflowing( - bin_op, - left, - right, - dest, - dest_ty, - )? - { - // There was an overflow in an unchecked binop. Right now, we consider this an error and bail out. - // The rationale is that the reason rustc emits unchecked binops in release mode (vs. the checked binops - // it emits in debug mode) is performance, but it doesn't cost us any performance in miri. - // If, however, the compiler ever starts transforming unchecked intrinsics into unchecked binops, - // we have to go back to just ignoring the overflow here. - return err!(OverflowingMath); - } - } - - CheckedBinaryOp(bin_op, ref left, ref right) => { - let left = self.eval_operand(left)?; - let right = self.eval_operand(right)?; - self.intrinsic_with_overflow( - bin_op, - left, - right, - dest, - dest_ty, - )?; - } - - UnaryOp(un_op, ref operand) => { - let val = self.eval_operand_to_primval(operand)?; - let kind = self.ty_to_primval_kind(dest_ty)?; - self.write_primval( - dest, - operator::unary_op(un_op, val, kind)?, - dest_ty, - )?; - } - - // Skip everything for zsts - Aggregate(..) if self.type_size(dest_ty)? == Some(0) => {} - - Aggregate(ref kind, ref operands) => { - self.inc_step_counter_and_check_limit(operands.len() as u64)?; - use rustc::ty::layout::Layout::*; - match *dest_layout { - Univariant { ref variant, .. } => { - self.write_maybe_aligned_mut(!variant.packed, |ecx| { - ecx.assign_fields(dest, dest_ty, operands) - })?; - } - - Array { .. } => { - self.assign_fields(dest, dest_ty, operands)?; - } - - General { - discr, - ref variants, - .. - } => { - if let mir::AggregateKind::Adt(adt_def, variant, _, _) = **kind { - let discr_val = adt_def - .discriminants(self.tcx) - .nth(variant) - .expect("broken mir: Adt variant id invalid") - .to_u128_unchecked(); - let discr_size = discr.size().bytes(); - - self.assign_discr_and_fields( - dest, - dest_ty, - variants[variant].offsets[0].bytes(), - operands, - discr_val, - variant, - discr_size, - false, - )?; - } else { - bug!("tried to assign {:?} to Layout::General", kind); - } - } - - RawNullablePointer { nndiscr, .. } => { - if let mir::AggregateKind::Adt(_, variant, _, _) = **kind { - if nndiscr == variant as u64 { - assert_eq!(operands.len(), 1); - let operand = &operands[0]; - let value = self.eval_operand(operand)?; - self.write_value(value, dest)?; - } else { - if let Some(operand) = operands.get(0) { - assert_eq!(operands.len(), 1); - let operand_ty = self.operand_ty(operand); - assert_eq!(self.type_size(operand_ty)?, Some(0)); - } - self.write_null(dest, dest_ty)?; - } - } else { - bug!("tried to assign {:?} to Layout::RawNullablePointer", kind); - } - } - - StructWrappedNullablePointer { - nndiscr, - ref discrfield_source, - ref nonnull, - .. - } => { - if let mir::AggregateKind::Adt(_, variant, _, _) = **kind { - if nndiscr == variant as u64 { - self.write_maybe_aligned_mut(!nonnull.packed, |ecx| { - ecx.assign_fields(dest, dest_ty, operands) - })?; - } else { - for operand in operands { - let operand_ty = self.operand_ty(operand); - assert_eq!(self.type_size(operand_ty)?, Some(0)); - } - self.write_struct_wrapped_null_pointer( - dest_ty, - nndiscr, - discrfield_source, - dest, - )?; - } - } else { - bug!("tried to assign {:?} to Layout::RawNullablePointer", kind); - } - } - - CEnum { .. } => { - assert_eq!(operands.len(), 0); - if let mir::AggregateKind::Adt(adt_def, variant, _, _) = **kind { - let n = adt_def - .discriminants(self.tcx) - .nth(variant) - .expect("broken mir: Adt variant index invalid") - .to_u128_unchecked(); - self.write_primval(dest, PrimVal::Bytes(n), dest_ty)?; - } else { - bug!("tried to assign {:?} to Layout::CEnum", kind); - } - } - - Vector { count, .. } => { - debug_assert_eq!(count, operands.len() as u64); - self.assign_fields(dest, dest_ty, operands)?; - } - - UntaggedUnion { ref variants } => { - assert_eq!(operands.len(), 1); - let operand = &operands[0]; - let value = self.eval_operand(operand)?; - self.write_maybe_aligned_mut(!variants.packed, |ecx| { - ecx.write_value(value, dest) - })?; - } - - _ => { - return err!(Unimplemented(format!( - "can't handle destination layout {:?} when assigning {:?}", - dest_layout, - kind - ))); - } - } - } - - Repeat(ref operand, _) => { - let (elem_ty, length) = match dest_ty.sty { - ty::TyArray(elem_ty, n) => (elem_ty, n.val.to_const_int().unwrap().to_u64().unwrap()), - _ => { - bug!( - "tried to assign array-repeat to non-array type {:?}", - dest_ty - ) - } - }; - self.inc_step_counter_and_check_limit(length)?; - let elem_size = self.type_size(elem_ty)?.expect( - "repeat element type must be sized", - ); - let value = self.eval_operand(operand)?.value; - - // FIXME(solson) - let dest = Pointer::from(self.force_allocation(dest)?.to_ptr()?); - - for i in 0..length { - let elem_dest = dest.offset(i * elem_size, &self)?; - self.write_value_to_ptr(value, elem_dest, elem_ty)?; - } - } - - Len(ref lvalue) => { - // FIXME(CTFE): don't allow computing the length of arrays in const eval - let src = self.eval_lvalue(lvalue)?; - let ty = self.lvalue_ty(lvalue); - let (_, len) = src.elem_ty_and_len(ty); - self.write_primval( - dest, - PrimVal::from_u128(len as u128), - dest_ty, - )?; - } - - Ref(_, _, ref lvalue) => { - let src = self.eval_lvalue(lvalue)?; - // We ignore the alignment of the lvalue here -- special handling for packed structs ends - // at the `&` operator. - let (ptr, extra) = self.force_allocation(src)?.to_ptr_extra_aligned(); - - let val = match extra { - LvalueExtra::None => ptr.ptr.to_value(), - LvalueExtra::Length(len) => ptr.ptr.to_value_with_len(len), - LvalueExtra::Vtable(vtable) => ptr.ptr.to_value_with_vtable(vtable), - LvalueExtra::DowncastVariant(..) => { - bug!("attempted to take a reference to an enum downcast lvalue") - } - }; - let valty = ValTy { - value: val, - ty: dest_ty, - }; - self.write_value(valty, dest)?; - } - - NullaryOp(mir::NullOp::Box, ty) => { - M::box_alloc(self, ty, dest)?; - } - - NullaryOp(mir::NullOp::SizeOf, ty) => { - let size = self.type_size(ty)?.expect( - "SizeOf nullary MIR operator called for unsized type", - ); - self.write_primval( - dest, - PrimVal::from_u128(size as u128), - dest_ty, - )?; - } - - Cast(kind, ref operand, cast_ty) => { - debug_assert_eq!(self.monomorphize(cast_ty, self.substs()), dest_ty); - use rustc::mir::CastKind::*; - match kind { - Unsize => { - let src = self.eval_operand(operand)?; - self.unsize_into(src.value, src.ty, dest, dest_ty)?; - } - - Misc => { - let src = self.eval_operand(operand)?; - if self.type_is_fat_ptr(src.ty) { - match (src.value, self.type_is_fat_ptr(dest_ty)) { - (Value::ByRef { .. }, _) | - (Value::ByValPair(..), true) => { - let valty = ValTy { - value: src.value, - ty: dest_ty, - }; - self.write_value(valty, dest)?; - } - (Value::ByValPair(data, _), false) => { - let valty = ValTy { - value: Value::ByVal(data), - ty: dest_ty, - }; - self.write_value(valty, dest)?; - } - (Value::ByVal(_), _) => bug!("expected fat ptr"), - } - } else { - let src_val = self.value_to_primval(src)?; - let dest_val = self.cast_primval(src_val, src.ty, dest_ty)?; - let valty = ValTy { - value: Value::ByVal(dest_val), - ty: dest_ty, - }; - self.write_value(valty, dest)?; - } - } - - ReifyFnPointer => { - match self.operand_ty(operand).sty { - ty::TyFnDef(def_id, substs) => { - let instance = resolve(self.tcx, def_id, substs); - let fn_ptr = self.memory.create_fn_alloc(instance); - let valty = ValTy { - value: Value::ByVal(PrimVal::Ptr(fn_ptr)), - ty: dest_ty, - }; - self.write_value(valty, dest)?; - } - ref other => bug!("reify fn pointer on {:?}", other), - } - } - - UnsafeFnPointer => { - match dest_ty.sty { - ty::TyFnPtr(_) => { - let mut src = self.eval_operand(operand)?; - src.ty = dest_ty; - self.write_value(src, dest)?; - } - ref other => bug!("fn to unsafe fn cast on {:?}", other), - } - } - - ClosureFnPointer => { - match self.operand_ty(operand).sty { - ty::TyClosure(def_id, substs) => { - let instance = resolve_closure( - self.tcx, - def_id, - substs, - ty::ClosureKind::FnOnce, - ); - let fn_ptr = self.memory.create_fn_alloc(instance); - let valty = ValTy { - value: Value::ByVal(PrimVal::Ptr(fn_ptr)), - ty: dest_ty, - }; - self.write_value(valty, dest)?; - } - ref other => bug!("closure fn pointer on {:?}", other), - } - } - } - } - - Discriminant(ref lvalue) => { - let lval = self.eval_lvalue(lvalue)?; - let ty = self.lvalue_ty(lvalue); - 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::>()); - 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"); - } - } - } - - if log_enabled!(::log::LogLevel::Trace) { - self.dump_local(dest); - } - - 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) | - ty::TyRef(_, ref tam) => !self.type_is_sized(tam.ty), - ty::TyAdt(def, _) if def.is_box() => !self.type_is_sized(ty.boxed_ty()), - _ => false, - } - } - - pub(super) fn nonnull_offset_and_ty( - &self, - ty: Ty<'tcx>, - nndiscr: u64, - discrfield: &[u32], - ) -> EvalResult<'tcx, (Size, TyAndPacked<'tcx>)> { - // Skip the constant 0 at the start meant for LLVM GEP and the outer non-null variant - let path = discrfield.iter().skip(2).map(|&i| i as usize); - - // Handle the field index for the outer non-null variant. - let (inner_offset, inner_ty) = match ty.sty { - ty::TyAdt(adt_def, substs) => { - let variant = &adt_def.variants[nndiscr as usize]; - let index = discrfield[1]; - let field = &variant.fields[index as usize]; - ( - self.get_field_offset(ty, index as usize)?, - field.ty(self.tcx, substs), - ) - } - _ => bug!("non-enum for StructWrappedNullablePointer: {}", ty), - }; - - self.field_path_offset_and_ty(inner_offset, inner_ty, path) - } - - fn field_path_offset_and_ty>( - &self, - mut offset: Size, - mut ty: Ty<'tcx>, - path: I, - ) -> EvalResult<'tcx, (Size, TyAndPacked<'tcx>)> { - // Skip the initial 0 intended for LLVM GEP. - let mut packed = false; - for field_index in path { - let field_offset = self.get_field_offset(ty, field_index)?; - trace!( - "field_path_offset_and_ty: {}, {}, {:?}, {:?}", - field_index, - ty, - field_offset, - offset - ); - let field_ty = self.get_field_ty(ty, field_index)?; - ty = field_ty.ty; - packed = packed || field_ty.packed; - offset = offset - .checked_add(field_offset, &self.tcx.data_layout) - .unwrap(); - } - - Ok((offset, TyAndPacked { ty, packed })) - } - fn get_fat_field( - &self, - pointee_ty: Ty<'tcx>, - field_index: usize, - ) -> EvalResult<'tcx, Ty<'tcx>> { - match (field_index, &self.tcx.struct_tail(pointee_ty).sty) { - (1, &ty::TyStr) | - (1, &ty::TySlice(_)) => Ok(self.tcx.types.usize), - (1, &ty::TyDynamic(..)) | - (0, _) => Ok(self.tcx.mk_imm_ptr(self.tcx.types.u8)), - _ => bug!("invalid fat pointee type: {}", pointee_ty), - } - } - - /// Returns the field type and whether the field is packed - pub fn get_field_ty( - &self, - ty: Ty<'tcx>, - field_index: usize, - ) -> EvalResult<'tcx, TyAndPacked<'tcx>> { - match ty.sty { - ty::TyAdt(adt_def, _) if adt_def.is_box() => Ok(TyAndPacked { - ty: self.get_fat_field(ty.boxed_ty(), field_index)?, - packed: false, - }), - ty::TyAdt(adt_def, substs) if adt_def.is_enum() => { - use rustc::ty::layout::Layout::*; - match *self.type_layout(ty)? { - RawNullablePointer { nndiscr, .. } => Ok(TyAndPacked { - ty: adt_def.variants[nndiscr as usize].fields[field_index].ty( - self.tcx, - substs, - ), - packed: false, - }), - StructWrappedNullablePointer { - nndiscr, - ref nonnull, - .. - } => { - let ty = adt_def.variants[nndiscr as usize].fields[field_index].ty( - self.tcx, - substs, - ); - Ok(TyAndPacked { - ty, - packed: nonnull.packed, - }) - } - // mir optimizations treat single variant enums as structs - General { .. } if adt_def.variants.len() == 1 => Ok(TyAndPacked { - ty: adt_def.variants[0].fields[field_index].ty(self.tcx, substs), - packed: false, - }), - _ => { - err!(Unimplemented(format!( - "get_field_ty can't handle enum type: {:?}, {:?}", - ty, - ty.sty - ))) - } - } - } - ty::TyAdt(adt_def, substs) => { - let variant_def = adt_def.struct_variant(); - use rustc::ty::layout::Layout::*; - match *self.type_layout(ty)? { - UntaggedUnion { ref variants } => Ok(TyAndPacked { - ty: variant_def.fields[field_index].ty(self.tcx, substs), - packed: variants.packed, - }), - Univariant { ref variant, .. } => Ok(TyAndPacked { - ty: variant_def.fields[field_index].ty(self.tcx, substs), - packed: variant.packed, - }), - _ => { - err!(Unimplemented(format!( - "get_field_ty can't handle struct type: {:?}, {:?}", - ty, - ty.sty - ))) - } - } - } - - ty::TyTuple(fields, _) => Ok(TyAndPacked { - ty: fields[field_index], - packed: false, - }), - - ty::TyRef(_, ref tam) | - ty::TyRawPtr(ref tam) => Ok(TyAndPacked { - ty: self.get_fat_field(tam.ty, field_index)?, - packed: false, - }), - - ty::TyArray(ref inner, _) => Ok(TyAndPacked { - ty: inner, - packed: false, - }), - - ty::TyClosure(def_id, ref closure_substs) => Ok(TyAndPacked { - ty: closure_substs.upvar_tys(def_id, self.tcx).nth(field_index).unwrap(), - packed: false, - }), - - _ => { - err!(Unimplemented( - format!("can't handle type: {:?}, {:?}", ty, ty.sty), - )) - } - } - } - - fn get_field_offset(&self, ty: Ty<'tcx>, field_index: usize) -> EvalResult<'tcx, Size> { - // Also see lvalue_field in lvalue.rs, which handles more cases but needs an actual value at the given type - let layout = self.type_layout(ty)?; - - use rustc::ty::layout::Layout::*; - match *layout { - Univariant { ref variant, .. } => Ok(variant.offsets[field_index]), - FatPointer { .. } => { - let bytes = field_index as u64 * self.memory.pointer_size(); - Ok(Size::from_bytes(bytes)) - } - StructWrappedNullablePointer { ref nonnull, .. } => Ok(nonnull.offsets[field_index]), - UntaggedUnion { .. } => Ok(Size::from_bytes(0)), - // mir optimizations treat single variant enums as structs - General { ref variants, .. } if variants.len() == 1 => Ok(variants[0].offsets[field_index]), - _ => { - let msg = format!( - "get_field_offset: can't handle type: {:?}, with layout: {:?}", - ty, - layout - ); - err!(Unimplemented(msg)) - } - } - } - - pub fn get_field_count(&self, ty: Ty<'tcx>) -> EvalResult<'tcx, u64> { - let layout = self.type_layout(ty)?; - - use rustc::ty::layout::Layout::*; - match *layout { - Univariant { ref variant, .. } => Ok(variant.offsets.len() as u64), - FatPointer { .. } => Ok(2), - StructWrappedNullablePointer { ref nonnull, .. } => Ok(nonnull.offsets.len() as u64), - Vector { count, .. } | - Array { count, .. } => Ok(count), - Scalar { .. } => Ok(0), - UntaggedUnion { .. } => Ok(1), - _ => { - let msg = format!( - "get_field_count: can't handle type: {:?}, with layout: {:?}", - ty, - layout - ); - err!(Unimplemented(msg)) - } - } - } - - pub(super) fn eval_operand_to_primval( - &mut self, - op: &mir::Operand<'tcx>, - ) -> EvalResult<'tcx, PrimVal> { - let valty = self.eval_operand(op)?; - self.value_to_primval(valty) - } - - pub(crate) fn operands_to_args( - &mut self, - ops: &[mir::Operand<'tcx>], - ) -> EvalResult<'tcx, Vec>> { - ops.into_iter() - .map(|op| self.eval_operand(op)) - .collect() - } - - pub fn eval_operand(&mut self, op: &mir::Operand<'tcx>) -> EvalResult<'tcx, ValTy<'tcx>> { - use rustc::mir::Operand::*; - match *op { - Consume(ref lvalue) => { - Ok(ValTy { - value: self.eval_and_read_lvalue(lvalue)?, - ty: self.operand_ty(op), - }) - }, - - Constant(ref constant) => { - use rustc::mir::Literal; - let mir::Constant { ref literal, .. } = **constant; - let value = match *literal { - Literal::Value { ref value } => self.const_to_value(&value.val)?, - - Literal::Promoted { index } => { - let cid = GlobalId { - instance: self.frame().instance, - promoted: Some(index), - }; - Value::ByRef(*self.globals.get(&cid).expect("promoted not cached")) - } - }; - - Ok(ValTy { - value, - ty: self.operand_ty(op), - }) - } - } - } - - 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")) - } - - pub fn operand_ty(&self, operand: &mir::Operand<'tcx>) -> Ty<'tcx> { - self.monomorphize(operand.ty(self.mir(), self.tcx), self.substs()) - } - - fn copy(&mut self, src: Pointer, dest: Pointer, ty: Ty<'tcx>) -> EvalResult<'tcx> { - let size = self.type_size(ty)?.expect( - "cannot copy from an unsized type", - ); - let align = self.type_align(ty)?; - self.memory.copy(src, dest, size, align, false)?; - Ok(()) - } - - pub fn is_packed(&self, ty: Ty<'tcx>) -> EvalResult<'tcx, bool> { - let layout = self.type_layout(ty)?; - use rustc::ty::layout::Layout::*; - Ok(match *layout { - Univariant { ref variant, .. } => variant.packed, - - StructWrappedNullablePointer { ref nonnull, .. } => nonnull.packed, - - UntaggedUnion { ref variants } => variants.packed, - - // can only apply #[repr(packed)] to struct and union - _ => false, - }) - } - - pub fn force_allocation(&mut self, lvalue: Lvalue) -> EvalResult<'tcx, Lvalue> { - let new_lvalue = match lvalue { - Lvalue::Local { frame, local } => { - // -1 since we don't store the return value - match self.stack[frame].locals[local.index() - 1] { - None => return err!(DeadLocal), - Some(Value::ByRef(ptr)) => { - Lvalue::Ptr { - ptr, - extra: LvalueExtra::None, - } - } - Some(val) => { - let ty = self.stack[frame].mir.local_decls[local].ty; - let ty = self.monomorphize(ty, self.stack[frame].instance.substs); - let substs = self.stack[frame].instance.substs; - let ptr = self.alloc_ptr_with_substs(ty, substs)?; - self.stack[frame].locals[local.index() - 1] = - Some(Value::by_ref(ptr.into())); // it stays live - self.write_value_to_ptr(val, ptr.into(), ty)?; - Lvalue::from_ptr(ptr) - } - } - } - Lvalue::Ptr { .. } => lvalue, - }; - Ok(new_lvalue) - } - - /// ensures this Value is not a ByRef - pub(super) fn follow_by_ref_value( - &self, - value: Value, - ty: Ty<'tcx>, - ) -> EvalResult<'tcx, Value> { - match value { - Value::ByRef(PtrAndAlign { ptr, aligned }) => { - self.read_maybe_aligned(aligned, |ectx| ectx.read_value(ptr, ty)) - } - other => Ok(other), - } - } - - pub fn value_to_primval( - &self, - ValTy { value, ty } : ValTy<'tcx>, - ) -> EvalResult<'tcx, PrimVal> { - match self.follow_by_ref_value(value, ty)? { - Value::ByRef { .. } => bug!("follow_by_ref_value can't result in `ByRef`"), - - Value::ByVal(primval) => { - // TODO: Do we really want insta-UB here? - self.ensure_valid_value(primval, ty)?; - Ok(primval) - } - - Value::ByValPair(..) => bug!("value_to_primval can't work with fat pointers"), - } - } - - pub fn write_null(&mut self, dest: Lvalue, dest_ty: Ty<'tcx>) -> EvalResult<'tcx> { - self.write_primval(dest, PrimVal::Bytes(0), dest_ty) - } - - pub fn write_ptr(&mut self, dest: Lvalue, val: Pointer, dest_ty: Ty<'tcx>) -> EvalResult<'tcx> { - let valty = ValTy { - value: val.to_value(), - ty: dest_ty, - }; - self.write_value(valty, dest) - } - - pub fn write_primval( - &mut self, - dest: Lvalue, - val: PrimVal, - dest_ty: Ty<'tcx>, - ) -> EvalResult<'tcx> { - let valty = ValTy { - value: Value::ByVal(val), - ty: dest_ty, - }; - self.write_value(valty, dest) - } - - pub fn write_value( - &mut self, - ValTy { value: src_val, ty: dest_ty } : ValTy<'tcx>, - dest: Lvalue, - ) -> EvalResult<'tcx> { - //trace!("Writing {:?} to {:?} at type {:?}", src_val, dest, dest_ty); - // Note that it is really important that the type here is the right one, and matches the type things are read at. - // In case `src_val` is a `ByValPair`, we don't do any magic here to handle padding properly, which is only - // correct if we never look at this data with the wrong type. - - match dest { - Lvalue::Ptr { - ptr: PtrAndAlign { ptr, aligned }, - extra, - } => { - assert_eq!(extra, LvalueExtra::None); - self.write_maybe_aligned_mut( - aligned, - |ectx| ectx.write_value_to_ptr(src_val, ptr, dest_ty), - ) - } - - Lvalue::Local { frame, local } => { - let dest = self.stack[frame].get_local(local)?; - self.write_value_possibly_by_val( - src_val, - |this, val| this.stack[frame].set_local(local, val), - dest, - dest_ty, - ) - } - } - } - - // The cases here can be a bit subtle. Read carefully! - fn write_value_possibly_by_val EvalResult<'tcx>>( - &mut self, - src_val: Value, - write_dest: F, - old_dest_val: Value, - dest_ty: Ty<'tcx>, - ) -> EvalResult<'tcx> { - if let Value::ByRef(PtrAndAlign { - ptr: dest_ptr, - aligned, - }) = old_dest_val - { - // If the value is already `ByRef` (that is, backed by an `Allocation`), - // then we must write the new value into this allocation, because there may be - // other pointers into the allocation. These other pointers are logically - // pointers into the local variable, and must be able to observe the change. - // - // Thus, it would be an error to replace the `ByRef` with a `ByVal`, unless we - // knew for certain that there were no outstanding pointers to this allocation. - self.write_maybe_aligned_mut(aligned, |ectx| { - ectx.write_value_to_ptr(src_val, dest_ptr, dest_ty) - })?; - - } else if let Value::ByRef(PtrAndAlign { - ptr: src_ptr, - aligned, - }) = src_val - { - // If the value is not `ByRef`, then we know there are no pointers to it - // and we can simply overwrite the `Value` in the locals array directly. - // - // In this specific case, where the source value is `ByRef`, we must duplicate - // the allocation, because this is a by-value operation. It would be incorrect - // if they referred to the same allocation, since then a change to one would - // implicitly change the other. - // - // It is a valid optimization to attempt reading a primitive value out of the - // source and write that into the destination without making an allocation, so - // we do so here. - self.read_maybe_aligned_mut(aligned, |ectx| { - if let Ok(Some(src_val)) = ectx.try_read_value(src_ptr, dest_ty) { - write_dest(ectx, src_val)?; - } else { - let dest_ptr = ectx.alloc_ptr(dest_ty)?.into(); - ectx.copy(src_ptr, dest_ptr, dest_ty)?; - write_dest(ectx, Value::by_ref(dest_ptr))?; - } - Ok(()) - })?; - - } else { - // Finally, we have the simple case where neither source nor destination are - // `ByRef`. We may simply copy the source value over the the destintion. - write_dest(self, src_val)?; - } - Ok(()) - } - - pub fn write_value_to_ptr( - &mut self, - value: Value, - dest: Pointer, - dest_ty: Ty<'tcx>, - ) -> EvalResult<'tcx> { - match value { - Value::ByRef(PtrAndAlign { ptr, aligned }) => { - self.read_maybe_aligned_mut(aligned, |ectx| ectx.copy(ptr, dest, dest_ty)) - } - Value::ByVal(primval) => { - let size = self.type_size(dest_ty)?.expect("dest type must be sized"); - 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), - } - } - - pub fn write_pair_to_ptr( - &mut self, - a: PrimVal, - b: PrimVal, - ptr: MemoryPointer, - mut ty: Ty<'tcx>, - ) -> EvalResult<'tcx> { - let mut packed = false; - while self.get_field_count(ty)? == 1 { - let field = self.get_field_ty(ty, 0)?; - ty = field.ty; - packed = packed || field.packed; - } - assert_eq!(self.get_field_count(ty)?, 2); - let field_0 = self.get_field_offset(ty, 0)?; - let field_1 = self.get_field_offset(ty, 1)?; - let field_0_ty = self.get_field_ty(ty, 0)?; - let field_1_ty = self.get_field_ty(ty, 1)?; - assert_eq!( - field_0_ty.packed, - field_1_ty.packed, - "the two fields must agree on being packed" - ); - packed = packed || field_0_ty.packed; - let field_0_size = self.type_size(field_0_ty.ty)?.expect( - "pair element type must be sized", - ); - let field_1_size = self.type_size(field_1_ty.ty)?.expect( - "pair element type must be sized", - ); - 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, false) - })?; - self.write_maybe_aligned_mut(!packed, |ectx| { - ectx.memory.write_primval(field_1_ptr, b, field_1_size, false) - })?; - Ok(()) - } - - pub fn ty_to_primval_kind(&self, ty: Ty<'tcx>) -> EvalResult<'tcx, PrimValKind> { - use syntax::ast::FloatTy; - - let kind = match ty.sty { - ty::TyBool => PrimValKind::Bool, - ty::TyChar => PrimValKind::Char, - - ty::TyInt(int_ty) => { - use syntax::ast::IntTy::*; - let size = match int_ty { - I8 => 1, - I16 => 2, - I32 => 4, - I64 => 8, - I128 => 16, - Is => self.memory.pointer_size(), - }; - PrimValKind::from_int_size(size) - } - - ty::TyUint(uint_ty) => { - use syntax::ast::UintTy::*; - let size = match uint_ty { - U8 => 1, - U16 => 2, - U32 => 4, - U64 => 8, - U128 => 16, - Us => self.memory.pointer_size(), - }; - PrimValKind::from_uint_size(size) - } - - ty::TyFloat(FloatTy::F32) => PrimValKind::F32, - ty::TyFloat(FloatTy::F64) => PrimValKind::F64, - - ty::TyFnPtr(_) => PrimValKind::FnPtr, - - ty::TyRef(_, ref tam) | - ty::TyRawPtr(ref tam) if self.type_is_sized(tam.ty) => PrimValKind::Ptr, - - ty::TyAdt(def, _) if def.is_box() => PrimValKind::Ptr, - - ty::TyAdt(def, substs) => { - use rustc::ty::layout::Layout::*; - match *self.type_layout(ty)? { - CEnum { discr, signed, .. } => { - let size = discr.size().bytes(); - if signed { - PrimValKind::from_int_size(size) - } else { - PrimValKind::from_uint_size(size) - } - } - - RawNullablePointer { value, .. } => { - use rustc::ty::layout::Primitive::*; - match value { - // TODO(solson): Does signedness matter here? What should the sign be? - Int(int) => PrimValKind::from_uint_size(int.size().bytes()), - F32 => PrimValKind::F32, - F64 => PrimValKind::F64, - Pointer => PrimValKind::Ptr, - } - } - - // represent single field structs as their single field - Univariant { .. } => { - // enums with just one variant are no different, but `.struct_variant()` doesn't work for enums - let variant = &def.variants[0]; - // FIXME: also allow structs with only a single non zst field - if variant.fields.len() == 1 { - return self.ty_to_primval_kind(variant.fields[0].ty(self.tcx, substs)); - } else { - return err!(TypeNotPrimitive(ty)); - } - } - - _ => return err!(TypeNotPrimitive(ty)), - } - } - - _ => return err!(TypeNotPrimitive(ty)), - }; - - Ok(kind) - } - - fn ensure_valid_value(&self, val: PrimVal, ty: Ty<'tcx>) -> EvalResult<'tcx> { - match ty.sty { - ty::TyBool if val.to_bytes()? > 1 => err!(InvalidBool), - - ty::TyChar if ::std::char::from_u32(val.to_bytes()? as u32).is_none() => { - err!(InvalidChar(val.to_bytes()? as u32 as u128)) - } - - _ => Ok(()), - } - } - - pub fn read_value(&self, ptr: Pointer, ty: Ty<'tcx>) -> EvalResult<'tcx, Value> { - if let Some(val) = self.try_read_value(ptr, ty)? { - Ok(val) - } else { - bug!("primitive read failed for type: {:?}", ty); - } - } - - pub(crate) fn read_ptr( - &self, - ptr: MemoryPointer, - pointee_ty: Ty<'tcx>, - ) -> EvalResult<'tcx, Value> { - 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(ptr_size, self)?; - match self.tcx.struct_tail(pointee_ty).sty { - ty::TyDynamic(..) => Ok(p.to_value_with_vtable( - self.memory.read_ptr_sized_unsigned(extra)?.to_ptr()?, - )), - ty::TySlice(..) | ty::TyStr => Ok( - p.to_value_with_len(self.memory.read_ptr_sized_unsigned(extra)?.to_bytes()? as u64), - ), - _ => bug!("unsized primval ptr read from {:?}", pointee_ty), - } - } - } - - fn try_read_value(&self, ptr: Pointer, ty: Ty<'tcx>) -> EvalResult<'tcx, Option> { - use syntax::ast::FloatTy; - - let ptr = ptr.to_ptr()?; - let val = match ty.sty { - ty::TyBool => { - let val = self.memory.read_primval(ptr, 1, false)?; - let val = match val { - PrimVal::Bytes(0) => false, - PrimVal::Bytes(1) => true, - // TODO: This seems a little overeager, should reading at bool type already be insta-UB? - _ => return err!(InvalidBool), - }; - PrimVal::from_bool(val) - } - ty::TyChar => { - 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)), - } - } - - ty::TyInt(int_ty) => { - use syntax::ast::IntTy::*; - let size = match int_ty { - I8 => 1, - I16 => 2, - I32 => 4, - I64 => 8, - I128 => 16, - Is => self.memory.pointer_size(), - }; - self.memory.read_primval(ptr, size, true)? - } - - ty::TyUint(uint_ty) => { - use syntax::ast::UintTy::*; - let size = match uint_ty { - U8 => 1, - U16 => 2, - U32 => 4, - U64 => 8, - U128 => 16, - Us => self.memory.pointer_size(), - }; - self.memory.read_primval(ptr, size, false)? - } - - 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_sized_unsigned(ptr)?, - ty::TyRef(_, ref tam) | - 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, ty.boxed_ty()).map(Some); - } - use rustc::ty::layout::Layout::*; - if let CEnum { discr, signed, .. } = *self.type_layout(ty)? { - let size = discr.size().bytes(); - self.memory.read_primval(ptr, size, signed)? - } else { - return Ok(None); - } - } - - _ => return Ok(None), - }; - - Ok(Some(Value::ByVal(val))) - } - - pub fn frame(&self) -> &Frame<'tcx> { - self.stack.last().expect("no call frames exist") - } - - pub(super) fn frame_mut(&mut self) -> &mut Frame<'tcx> { - self.stack.last_mut().expect("no call frames exist") - } - - pub(super) fn mir(&self) -> &'tcx mir::Mir<'tcx> { - self.frame().mir - } - - pub(super) fn substs(&self) -> &'tcx Substs<'tcx> { - self.frame().instance.substs - } - - fn unsize_into_ptr( - &mut self, - src: Value, - src_ty: Ty<'tcx>, - dest: Lvalue, - dest_ty: Ty<'tcx>, - sty: Ty<'tcx>, - dty: Ty<'tcx>, - ) -> EvalResult<'tcx> { - // A -> A conversion - let (src_pointee_ty, dest_pointee_ty) = self.tcx.struct_lockstep_tails(sty, dty); - - match (&src_pointee_ty.sty, &dest_pointee_ty.sty) { - (&ty::TyArray(_, length), &ty::TySlice(_)) => { - let ptr = src.into_ptr(&self.memory)?; - // u64 cast is from usize to u64, which is always good - let valty = ValTy { - value: ptr.to_value_with_len(length.val.to_const_int().unwrap().to_u64().unwrap() ), - ty: dest_ty, - }; - self.write_value(valty, dest) - } - (&ty::TyDynamic(..), &ty::TyDynamic(..)) => { - // For now, upcasts are limited to changes in marker - // traits, and hence never actually require an actual - // change to the vtable. - let valty = ValTy { - value: src, - ty: dest_ty, - }; - self.write_value(valty, dest) - } - (_, &ty::TyDynamic(ref data, _)) => { - let trait_ref = data.principal().unwrap().with_self_ty( - self.tcx, - src_pointee_ty, - ); - let trait_ref = self.tcx.erase_regions(&trait_ref); - let vtable = self.get_vtable(src_pointee_ty, trait_ref)?; - let ptr = src.into_ptr(&self.memory)?; - let valty = ValTy { - value: ptr.to_value_with_vtable(vtable), - ty: dest_ty, - }; - self.write_value(valty, dest) - } - - _ => bug!("invalid unsizing {:?} -> {:?}", src_ty, dest_ty), - } - } - - fn unsize_into( - &mut self, - src: Value, - src_ty: Ty<'tcx>, - dest: Lvalue, - dest_ty: Ty<'tcx>, - ) -> EvalResult<'tcx> { - match (&src_ty.sty, &dest_ty.sty) { - (&ty::TyRef(_, ref s), &ty::TyRef(_, ref d)) | - (&ty::TyRef(_, ref s), &ty::TyRawPtr(ref d)) | - (&ty::TyRawPtr(ref s), &ty::TyRawPtr(ref d)) => { - self.unsize_into_ptr(src, src_ty, dest, dest_ty, s.ty, d.ty) - } - (&ty::TyAdt(def_a, substs_a), &ty::TyAdt(def_b, substs_b)) => { - if def_a.is_box() || def_b.is_box() { - if !def_a.is_box() || !def_b.is_box() { - panic!("invalid unsizing between {:?} -> {:?}", src_ty, dest_ty); - } - return self.unsize_into_ptr( - src, - src_ty, - dest, - dest_ty, - src_ty.boxed_ty(), - dest_ty.boxed_ty(), - ); - } - if self.ty_to_primval_kind(src_ty).is_ok() { - // TODO: We ignore the packed flag here - let sty = self.get_field_ty(src_ty, 0)?.ty; - let dty = self.get_field_ty(dest_ty, 0)?.ty; - return self.unsize_into(src, sty, dest, dty); - } - // unsizing of generic struct with pointer fields - // Example: `Arc` -> `Arc` - // here we need to increase the size of every &T thin ptr field to a fat ptr - - assert_eq!(def_a, def_b); - - let src_fields = def_a.variants[0].fields.iter(); - let dst_fields = def_b.variants[0].fields.iter(); - - //let src = adt::MaybeSizedValue::sized(src); - //let dst = adt::MaybeSizedValue::sized(dst); - let src_ptr = match src { - Value::ByRef(PtrAndAlign { ptr, aligned: true }) => ptr, - // TODO: Is it possible for unaligned pointers to occur here? - _ => bug!("expected aligned pointer, got {:?}", src), - }; - - // FIXME(solson) - let dest = self.force_allocation(dest)?.to_ptr()?; - let iter = src_fields.zip(dst_fields).enumerate(); - for (i, (src_f, dst_f)) in iter { - let src_fty = self.field_ty(substs_a, src_f); - let dst_fty = self.field_ty(substs_b, dst_f); - if self.type_size(dst_fty)? == Some(0) { - continue; - } - let src_field_offset = self.get_field_offset(src_ty, i)?.bytes(); - let dst_field_offset = self.get_field_offset(dest_ty, i)?.bytes(); - let src_f_ptr = src_ptr.offset(src_field_offset, &self)?; - let dst_f_ptr = dest.offset(dst_field_offset, &self)?; - if src_fty == dst_fty { - self.copy(src_f_ptr, dst_f_ptr.into(), src_fty)?; - } else { - self.unsize_into( - Value::by_ref(src_f_ptr), - src_fty, - Lvalue::from_ptr(dst_f_ptr), - dst_fty, - )?; - } - } - Ok(()) - } - _ => { - bug!( - "unsize_into: invalid conversion: {:?} -> {:?}", - src_ty, - dest_ty - ) - } - } - } - - pub fn dump_local(&self, lvalue: Lvalue) { - // Debug output - match lvalue { - Lvalue::Local { frame, local } => { - let mut allocs = Vec::new(); - let mut msg = format!("{:?}", local); - if frame != self.cur_frame() { - write!(msg, " ({} frames up)", self.cur_frame() - frame).unwrap(); - } - write!(msg, ":").unwrap(); - - match self.stack[frame].get_local(local) { - Err(EvalError { kind: EvalErrorKind::DeadLocal, .. }) => { - write!(msg, " is dead").unwrap(); - } - Err(err) => { - panic!("Failed to access local: {:?}", err); - } - Ok(Value::ByRef(PtrAndAlign { ptr, aligned })) => { - match ptr.into_inner_primval() { - PrimVal::Ptr(ptr) => { - write!(msg, " by {}ref:", if aligned { "" } else { "unaligned " }) - .unwrap(); - allocs.push(ptr.alloc_id); - } - ptr => write!(msg, " integral by ref: {:?}", ptr).unwrap(), - } - } - Ok(Value::ByVal(val)) => { - write!(msg, " {:?}", val).unwrap(); - if let PrimVal::Ptr(ptr) = val { - allocs.push(ptr.alloc_id); - } - } - Ok(Value::ByValPair(val1, val2)) => { - write!(msg, " ({:?}, {:?})", val1, val2).unwrap(); - if let PrimVal::Ptr(ptr) = val1 { - allocs.push(ptr.alloc_id); - } - if let PrimVal::Ptr(ptr) = val2 { - allocs.push(ptr.alloc_id); - } - } - } - - trace!("{}", msg); - self.memory.dump_allocs(allocs); - } - Lvalue::Ptr { ptr: PtrAndAlign { ptr, aligned }, .. } => { - match ptr.into_inner_primval() { - PrimVal::Ptr(ptr) => { - trace!("by {}ref:", if aligned { "" } else { "unaligned " }); - self.memory.dump_alloc(ptr.alloc_id); - } - ptr => trace!(" integral by ref: {:?}", ptr), - } - } - } - } - - /// Convenience function to ensure correct usage of locals - pub fn modify_local(&mut self, frame: usize, local: mir::Local, f: F) -> EvalResult<'tcx> - where - F: FnOnce(&mut Self, Value) -> EvalResult<'tcx, Value>, - { - let val = self.stack[frame].get_local(local)?; - let new_val = f(self, val)?; - self.stack[frame].set_local(local, new_val)?; - // FIXME(solson): Run this when setting to Undef? (See previous version of this code.) - // if let Value::ByRef(ptr) = self.stack[frame].get_local(local) { - // self.memory.deallocate(ptr)?; - // } - Ok(()) - } - - pub fn report(&self, e: &mut EvalError) { - if let Some(ref mut backtrace) = e.backtrace { - let mut trace_text = "\n\nAn error occurred in miri:\n".to_string(); - let mut skip_init = true; - backtrace.resolve(); - 'frames: for (i, frame) in backtrace.frames().iter().enumerate() { - for symbol in frame.symbols() { - if let Some(name) = symbol.name() { - // unmangle the symbol via `to_string` - let name = name.to_string(); - if name.starts_with("miri::after_analysis") { - // don't report initialization gibberish - break 'frames; - } else if name.starts_with("backtrace::capture::Backtrace::new") - // debug mode produces funky symbol names - || name.starts_with("backtrace::capture::{{impl}}::new") - { - // don't report backtrace internals - skip_init = false; - continue 'frames; - } - } - } - if skip_init { - continue; - } - for symbol in frame.symbols() { - write!(trace_text, "{}: ", i).unwrap(); - if let Some(name) = symbol.name() { - write!(trace_text, "{}\n", name).unwrap(); - } else { - write!(trace_text, "\n").unwrap(); - } - write!(trace_text, "\tat ").unwrap(); - if let Some(file_path) = symbol.filename() { - write!(trace_text, "{}", file_path.display()).unwrap(); - } else { - write!(trace_text, "").unwrap(); - } - if let Some(line) = symbol.lineno() { - write!(trace_text, ":{}\n", line).unwrap(); - } else { - write!(trace_text, "\n").unwrap(); - } - } - } - error!("{}", trace_text); - } - if let Some(frame) = self.stack().last() { - let block = &frame.mir.basic_blocks()[frame.block]; - let span = if frame.stmt < block.statements.len() { - block.statements[frame.stmt].source_info.span - } else { - block.terminator().source_info.span - }; - let mut err = self.tcx.sess.struct_span_err(span, &e.to_string()); - for &Frame { instance, span, .. } in self.stack().iter().rev() { - if self.tcx.def_key(instance.def_id()).disambiguated_data.data == - DefPathData::ClosureExpr - { - err.span_note(span, "inside call to closure"); - continue; - } - err.span_note(span, &format!("inside call to {}", instance)); - } - err.emit(); - } else { - self.tcx.sess.err(&e.to_string()); - } - } -} - -impl<'tcx> Frame<'tcx> { - pub fn get_local(&self, local: mir::Local) -> EvalResult<'tcx, Value> { - // Subtract 1 because we don't store a value for the ReturnPointer, the local with index 0. - self.locals[local.index() - 1].ok_or(EvalErrorKind::DeadLocal.into()) - } - - fn set_local(&mut self, local: mir::Local, value: Value) -> EvalResult<'tcx> { - // Subtract 1 because we don't store a value for the ReturnPointer, the local with index 0. - match self.locals[local.index() - 1] { - None => err!(DeadLocal), - Some(ref mut local) => { - *local = value; - Ok(()) - } - } - } - - pub fn storage_live(&mut self, local: mir::Local) -> EvalResult<'tcx, Option> { - trace!("{:?} is now live", local); - - let old = self.locals[local.index() - 1]; - self.locals[local.index() - 1] = Some(Value::ByVal(PrimVal::Undef)); // StorageLive *always* kills the value that's currently stored - return Ok(old); - } - - /// Returns the old value of the local - pub fn storage_dead(&mut self, local: mir::Local) -> EvalResult<'tcx, Option> { - trace!("{:?} is now dead", local); - - let old = self.locals[local.index() - 1]; - self.locals[local.index() - 1] = None; - return Ok(old); - } -} - -// TODO(solson): Upstream these methods into rustc::ty::layout. - -pub(super) trait IntegerExt { - fn size(self) -> Size; -} - -impl IntegerExt for layout::Integer { - fn size(self) -> Size { - use rustc::ty::layout::Integer::*; - match self { - I1 | I8 => Size::from_bits(8), - I16 => Size::from_bits(16), - I32 => Size::from_bits(32), - I64 => Size::from_bits(64), - I128 => Size::from_bits(128), - } - } -} - -/// FIXME: expose trans::monomorphize::resolve_closure -pub fn resolve_closure<'a, 'tcx>( - tcx: TyCtxt<'a, 'tcx, 'tcx>, - def_id: DefId, - substs: ty::ClosureSubsts<'tcx>, - requested_kind: ty::ClosureKind, -) -> ty::Instance<'tcx> { - let actual_kind = tcx.closure_kind(def_id); - match needs_fn_once_adapter_shim(actual_kind, requested_kind) { - Ok(true) => fn_once_adapter_instance(tcx, def_id, substs), - _ => ty::Instance::new(def_id, substs.substs), - } -} - -fn fn_once_adapter_instance<'a, 'tcx>( - tcx: TyCtxt<'a, 'tcx, 'tcx>, - closure_did: DefId, - substs: ty::ClosureSubsts<'tcx>, -) -> ty::Instance<'tcx> { - debug!("fn_once_adapter_shim({:?}, {:?})", closure_did, substs); - let fn_once = tcx.lang_items().fn_once_trait().unwrap(); - let call_once = tcx.associated_items(fn_once) - .find(|it| it.kind == ty::AssociatedKind::Method) - .unwrap() - .def_id; - let def = ty::InstanceDef::ClosureOnceShim { call_once }; - - let self_ty = tcx.mk_closure_from_closure_substs(closure_did, substs); - - let sig = tcx.fn_sig(closure_did).subst(tcx, substs.substs); - let sig = tcx.erase_late_bound_regions_and_normalize(&sig); - assert_eq!(sig.inputs().len(), 1); - let substs = tcx.mk_substs( - [Kind::from(self_ty), Kind::from(sig.inputs()[0])] - .iter() - .cloned(), - ); - - debug!("fn_once_adapter_shim: self_ty={:?} sig={:?}", self_ty, sig); - ty::Instance { def, substs } -} - -fn needs_fn_once_adapter_shim( - actual_closure_kind: ty::ClosureKind, - trait_closure_kind: ty::ClosureKind, -) -> Result { - match (actual_closure_kind, trait_closure_kind) { - (ty::ClosureKind::Fn, ty::ClosureKind::Fn) | - (ty::ClosureKind::FnMut, ty::ClosureKind::FnMut) | - (ty::ClosureKind::FnOnce, ty::ClosureKind::FnOnce) => { - // No adapter needed. - Ok(false) - } - (ty::ClosureKind::Fn, ty::ClosureKind::FnMut) => { - // The closure fn `llfn` is a `fn(&self, ...)`. We want a - // `fn(&mut self, ...)`. In fact, at trans time, these are - // basically the same thing, so we can just return llfn. - Ok(false) - } - (ty::ClosureKind::Fn, ty::ClosureKind::FnOnce) | - (ty::ClosureKind::FnMut, ty::ClosureKind::FnOnce) => { - // The closure fn `llfn` is a `fn(&self, ...)` or `fn(&mut - // self, ...)`. We want a `fn(self, ...)`. We can produce - // this by doing something like: - // - // fn call_once(self, ...) { call_mut(&self, ...) } - // fn call_once(mut self, ...) { call_mut(&mut self, ...) } - // - // These are both the same at trans time. - Ok(true) - } - _ => Err(()), - } -} - -/// The point where linking happens. Resolve a (def_id, substs) -/// pair to an instance. -pub fn resolve<'a, 'tcx>( - tcx: TyCtxt<'a, 'tcx, 'tcx>, - def_id: DefId, - substs: &'tcx Substs<'tcx>, -) -> ty::Instance<'tcx> { - debug!("resolve(def_id={:?}, substs={:?})", def_id, substs); - let result = if let Some(trait_def_id) = tcx.trait_of_item(def_id) { - debug!(" => associated item, attempting to find impl"); - let item = tcx.associated_item(def_id); - resolve_associated_item(tcx, &item, trait_def_id, substs) - } else { - let item_type = def_ty(tcx, def_id, substs); - let def = match item_type.sty { - ty::TyFnDef(..) - if { - let f = item_type.fn_sig(tcx); - f.abi() == Abi::RustIntrinsic || f.abi() == Abi::PlatformIntrinsic - } => { - debug!(" => intrinsic"); - ty::InstanceDef::Intrinsic(def_id) - } - _ => { - if Some(def_id) == tcx.lang_items().drop_in_place_fn() { - let ty = substs.type_at(0); - if needs_drop_glue(tcx, ty) { - debug!(" => nontrivial drop glue"); - ty::InstanceDef::DropGlue(def_id, Some(ty)) - } else { - debug!(" => trivial drop glue"); - ty::InstanceDef::DropGlue(def_id, None) - } - } else { - debug!(" => free item"); - ty::InstanceDef::Item(def_id) - } - } - }; - ty::Instance { def, substs } - }; - debug!( - "resolve(def_id={:?}, substs={:?}) = {}", - def_id, - substs, - result - ); - result -} - -pub fn needs_drop_glue<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, t: Ty<'tcx>) -> bool { - assert!(t.is_normalized_for_trans()); - - let t = tcx.erase_regions(&t); - - // FIXME (#22815): note that type_needs_drop conservatively - // approximates in some cases and may say a type expression - // requires drop glue when it actually does not. - // - // (In this case it is not clear whether any harm is done, i.e. - // erroneously returning `true` in some cases where we could have - // returned `false` does not appear unsound. The impact on - // code quality is unknown at this time.) - - let env = ty::ParamEnv::empty(Reveal::All); - if !t.needs_drop(tcx, env) { - return false; - } - match t.sty { - ty::TyAdt(def, _) if def.is_box() => { - let typ = t.boxed_ty(); - if !typ.needs_drop(tcx, env) && type_is_sized(tcx, typ) { - let layout = t.layout(tcx, ty::ParamEnv::empty(Reveal::All)).unwrap(); - // `Box` does not allocate. - layout.size(&tcx.data_layout).bytes() != 0 - } else { - true - } - } - _ => true, - } -} - -fn resolve_associated_item<'a, 'tcx>( - tcx: TyCtxt<'a, 'tcx, 'tcx>, - trait_item: &ty::AssociatedItem, - trait_id: DefId, - rcvr_substs: &'tcx Substs<'tcx>, -) -> ty::Instance<'tcx> { - let def_id = trait_item.def_id; - debug!( - "resolve_associated_item(trait_item={:?}, \ - trait_id={:?}, \ - rcvr_substs={:?})", - def_id, - trait_id, - rcvr_substs - ); - - let trait_ref = ty::TraitRef::from_method(tcx, trait_id, rcvr_substs); - let vtbl = tcx.trans_fulfill_obligation(DUMMY_SP, ty::ParamEnv::empty(traits::Reveal::All), ty::Binder(trait_ref)); - - // Now that we know which impl is being used, we can dispatch to - // the actual function: - match vtbl { - ::rustc::traits::VtableImpl(impl_data) => { - let (def_id, substs) = - ::rustc::traits::find_associated_item(tcx, trait_item, rcvr_substs, &impl_data); - let substs = tcx.erase_regions(&substs); - ty::Instance::new(def_id, substs) - } - ::rustc::traits::VtableGenerator(closure_data) => { - ty::Instance { - def: ty::InstanceDef::Item(closure_data.closure_def_id), - substs: closure_data.substs.substs - } - } - ::rustc::traits::VtableClosure(closure_data) => { - let trait_closure_kind = tcx.lang_items().fn_trait_kind(trait_id).unwrap(); - resolve_closure( - tcx, - closure_data.closure_def_id, - closure_data.substs, - trait_closure_kind, - ) - } - ::rustc::traits::VtableFnPointer(ref data) => { - ty::Instance { - def: ty::InstanceDef::FnPtrShim(trait_item.def_id, data.fn_ty), - substs: rcvr_substs, - } - } - ::rustc::traits::VtableObject(ref data) => { - let index = tcx.get_vtable_index_of_object_method(data, def_id); - ty::Instance { - def: ty::InstanceDef::Virtual(def_id, index), - substs: rcvr_substs, - } - } - ::rustc::traits::VtableBuiltin(..) if Some(trait_id) == tcx.lang_items().clone_trait() => { - ty::Instance { - def: ty::InstanceDef::CloneShim(def_id, trait_ref.self_ty()), - substs: rcvr_substs - } - } - _ => bug!("static call to invalid vtable: {:?}", vtbl), - } -} - -pub fn def_ty<'a, 'tcx>( - tcx: TyCtxt<'a, 'tcx, 'tcx>, - def_id: DefId, - substs: &'tcx Substs<'tcx>, -) -> Ty<'tcx> { - let ty = tcx.type_of(def_id); - apply_param_substs(tcx, substs, &ty) -} - -/// Monomorphizes a type from the AST by first applying the in-scope -/// substitutions and then normalizing any associated types. -pub fn apply_param_substs<'a, 'tcx, T>( - tcx: TyCtxt<'a, 'tcx, 'tcx>, - param_substs: &Substs<'tcx>, - value: &T, -) -> T -where - T: ::rustc::infer::TransNormalize<'tcx>, -{ - debug!( - "apply_param_substs(param_substs={:?}, value={:?})", - param_substs, - value - ); - let substituted = value.subst(tcx, param_substs); - let substituted = tcx.erase_regions(&substituted); - AssociatedTypeNormalizer { tcx }.fold(&substituted) -} - - -struct AssociatedTypeNormalizer<'a, 'tcx: 'a> { - tcx: TyCtxt<'a, 'tcx, 'tcx>, -} - -impl<'a, 'tcx> AssociatedTypeNormalizer<'a, 'tcx> { - fn fold>(&mut self, value: &T) -> T { - if !value.has_projections() { - value.clone() - } else { - value.fold_with(self) - } - } -} - -impl<'a, 'tcx> ::rustc::ty::fold::TypeFolder<'tcx, 'tcx> for AssociatedTypeNormalizer<'a, 'tcx> { - fn tcx<'c>(&'c self) -> TyCtxt<'c, 'tcx, 'tcx> { - self.tcx - } - - fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { - if !ty.has_projections() { - ty - } else { - self.tcx.normalize_associated_type(&ty) - } - } -} - -fn type_is_sized<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, ty: Ty<'tcx>) -> bool { - // generics are weird, don't run this function on a generic - assert!(!ty.needs_subst()); - ty.is_sized(tcx, ty::ParamEnv::empty(Reveal::All), DUMMY_SP) -} - -pub fn resolve_drop_in_place<'a, 'tcx>( - tcx: TyCtxt<'a, 'tcx, 'tcx>, - ty: Ty<'tcx>, -) -> ty::Instance<'tcx> { - let def_id = tcx.require_lang_item(::rustc::middle::lang_items::DropInPlaceFnLangItem); - let substs = tcx.intern_substs(&[Kind::from(ty)]); - resolve(tcx, def_id, substs) -} diff --git a/src/librustc_mir/interpret/lvalue.rs b/src/librustc_mir/interpret/lvalue.rs deleted file mode 100644 index 36b396a7a2ba5..0000000000000 --- a/src/librustc_mir/interpret/lvalue.rs +++ /dev/null @@ -1,506 +0,0 @@ -use rustc::mir; -use rustc::ty::layout::{Size, Align}; -use rustc::ty::{self, Ty}; -use rustc_data_structures::indexed_vec::Idx; - -use super::{EvalResult, EvalContext, MemoryPointer, PrimVal, Value, Pointer, Machine, PtrAndAlign, ValTy}; - -#[derive(Copy, Clone, Debug)] -pub enum Lvalue { - /// An lvalue referring to a value allocated in the `Memory` system. - Ptr { - /// An lvalue may have an invalid (integral or undef) pointer, - /// since it might be turned back into a reference - /// before ever being dereferenced. - ptr: PtrAndAlign, - extra: LvalueExtra, - }, - - /// An lvalue referring to a value on the stack. Represented by a stack frame index paired with - /// a Mir local index. - Local { frame: usize, local: mir::Local }, -} - -#[derive(Copy, Clone, Debug, Eq, PartialEq)] -pub enum LvalueExtra { - None, - Length(u64), - Vtable(MemoryPointer), - DowncastVariant(usize), -} - -/// Uniquely identifies a specific constant or static. -#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] -pub struct GlobalId<'tcx> { - /// For a constant or static, the `Instance` of the item itself. - /// For a promoted global, the `Instance` of the function they belong to. - pub instance: ty::Instance<'tcx>, - - /// The index for promoted globals within their function's `Mir`. - pub promoted: Option, -} - -impl<'tcx> Lvalue { - /// Produces an Lvalue that will error if attempted to be read from - pub fn undef() -> Self { - Self::from_primval_ptr(PrimVal::Undef.into()) - } - - pub fn from_primval_ptr(ptr: Pointer) -> Self { - Lvalue::Ptr { - ptr: PtrAndAlign { ptr, aligned: true }, - extra: LvalueExtra::None, - } - } - - pub fn from_ptr(ptr: MemoryPointer) -> Self { - Self::from_primval_ptr(ptr.into()) - } - - pub(super) fn to_ptr_extra_aligned(self) -> (PtrAndAlign, LvalueExtra) { - match self { - Lvalue::Ptr { ptr, extra } => (ptr, extra), - _ => bug!("to_ptr_and_extra: expected Lvalue::Ptr, got {:?}", self), - - } - } - - pub fn to_ptr(self) -> EvalResult<'tcx, MemoryPointer> { - let (ptr, extra) = self.to_ptr_extra_aligned(); - // At this point, we forget about the alignment information -- the lvalue has been turned into a reference, - // and no matter where it came from, it now must be aligned. - assert_eq!(extra, LvalueExtra::None); - ptr.to_ptr() - } - - pub(super) fn elem_ty_and_len(self, ty: Ty<'tcx>) -> (Ty<'tcx>, u64) { - match ty.sty { - ty::TyArray(elem, n) => (elem, n.val.to_const_int().unwrap().to_u64().unwrap() as u64), - - ty::TySlice(elem) => { - match self { - Lvalue::Ptr { extra: LvalueExtra::Length(len), .. } => (elem, len), - _ => { - bug!( - "elem_ty_and_len of a TySlice given non-slice lvalue: {:?}", - self - ) - } - } - } - - _ => bug!("elem_ty_and_len expected array or slice, got {:?}", ty), - } - } -} - -impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { - /// Reads a value from the lvalue without going through the intermediate step of obtaining - /// a `miri::Lvalue` - pub fn try_read_lvalue( - &mut self, - lvalue: &mir::Lvalue<'tcx>, - ) -> EvalResult<'tcx, Option> { - use rustc::mir::Lvalue::*; - match *lvalue { - // Might allow this in the future, right now there's no way to do this from Rust code anyway - Local(mir::RETURN_POINTER) => err!(ReadFromReturnPointer), - // Directly reading a local will always succeed - Local(local) => self.frame().get_local(local).map(Some), - // Directly reading a static will always succeed - Static(ref static_) => { - let instance = ty::Instance::mono(self.tcx, static_.def_id); - let cid = GlobalId { - instance, - promoted: None, - }; - Ok(Some(Value::ByRef( - *self.globals.get(&cid).expect("global not cached"), - ))) - } - Projection(ref proj) => self.try_read_lvalue_projection(proj), - } - } - - fn try_read_lvalue_projection( - &mut self, - proj: &mir::LvalueProjection<'tcx>, - ) -> EvalResult<'tcx, Option> { - use rustc::mir::ProjectionElem::*; - let base = match self.try_read_lvalue(&proj.base)? { - Some(base) => base, - None => return Ok(None), - }; - let base_ty = self.lvalue_ty(&proj.base); - match proj.elem { - Field(field, _) => match (field.index(), base) { - // the only field of a struct - (0, Value::ByVal(val)) => Ok(Some(Value::ByVal(val))), - // split fat pointers, 2 element tuples, ... - (0...1, Value::ByValPair(a, b)) if self.get_field_count(base_ty)? == 2 => { - let val = [a, b][field.index()]; - Ok(Some(Value::ByVal(val))) - }, - // the only field of a struct is a fat pointer - (0, Value::ByValPair(..)) => Ok(Some(base)), - _ => Ok(None), - }, - // The NullablePointer cases should work fine, need to take care for normal enums - Downcast(..) | - Subslice { .. } | - // reading index 0 or index 1 from a ByVal or ByVal pair could be optimized - ConstantIndex { .. } | Index(_) | - // No way to optimize this projection any better than the normal lvalue path - Deref => Ok(None), - } - } - - /// Returns a value and (in case of a ByRef) if we are supposed to use aligned accesses. - pub(super) fn eval_and_read_lvalue( - &mut self, - lvalue: &mir::Lvalue<'tcx>, - ) -> EvalResult<'tcx, Value> { - // Shortcut for things like accessing a fat pointer's field, - // which would otherwise (in the `eval_lvalue` path) require moving a `ByValPair` to memory - // and returning an `Lvalue::Ptr` to it - if let Some(val) = self.try_read_lvalue(lvalue)? { - return Ok(val); - } - let lvalue = self.eval_lvalue(lvalue)?; - self.read_lvalue(lvalue) - } - - pub fn read_lvalue(&self, lvalue: Lvalue) -> EvalResult<'tcx, Value> { - match lvalue { - Lvalue::Ptr { ptr, extra } => { - assert_eq!(extra, LvalueExtra::None); - Ok(Value::ByRef(ptr)) - } - Lvalue::Local { frame, local } => self.stack[frame].get_local(local), - } - } - - pub fn eval_lvalue(&mut self, mir_lvalue: &mir::Lvalue<'tcx>) -> EvalResult<'tcx, Lvalue> { - use rustc::mir::Lvalue::*; - let lvalue = match *mir_lvalue { - Local(mir::RETURN_POINTER) => self.frame().return_lvalue, - Local(local) => Lvalue::Local { - frame: self.cur_frame(), - local, - }, - - Static(ref static_) => { - let instance = ty::Instance::mono(self.tcx, static_.def_id); - let gid = GlobalId { - instance, - promoted: None, - }; - Lvalue::Ptr { - ptr: *self.globals.get(&gid).expect("uncached global"), - extra: LvalueExtra::None, - } - } - - Projection(ref proj) => { - let ty = self.lvalue_ty(&proj.base); - let lvalue = self.eval_lvalue(&proj.base)?; - return self.eval_lvalue_projection(lvalue, ty, &proj.elem); - } - }; - - if log_enabled!(::log::LogLevel::Trace) { - self.dump_local(lvalue); - } - - Ok(lvalue) - } - - pub fn lvalue_field( - &mut self, - base: Lvalue, - field: mir::Field, - base_ty: Ty<'tcx>, - field_ty: Ty<'tcx>, - ) -> EvalResult<'tcx, Lvalue> { - use rustc::ty::layout::Layout::*; - - let base_layout = self.type_layout(base_ty)?; - let field_index = field.index(); - let (offset, packed) = match *base_layout { - Univariant { ref variant, .. } => (variant.offsets[field_index], variant.packed), - - // mir optimizations treat single variant enums as structs - General { ref variants, .. } if variants.len() == 1 => { - (variants[0].offsets[field_index], variants[0].packed) - } - - General { ref variants, .. } => { - let (_, base_extra) = base.to_ptr_extra_aligned(); - if let LvalueExtra::DowncastVariant(variant_idx) = base_extra { - // +1 for the discriminant, which is field 0 - assert!(!variants[variant_idx].packed); - (variants[variant_idx].offsets[field_index + 1], false) - } else { - bug!("field access on enum had no variant index"); - } - } - - RawNullablePointer { .. } => { - assert_eq!(field_index, 0); - return Ok(base); - } - - StructWrappedNullablePointer { ref nonnull, .. } => { - (nonnull.offsets[field_index], nonnull.packed) - } - - UntaggedUnion { .. } => return Ok(base), - - Vector { element, count } => { - let field = field_index as u64; - assert!(field < count); - let elem_size = element.size(&self.tcx.data_layout).bytes(); - (Size::from_bytes(field * elem_size), false) - } - - // We treat arrays + fixed sized indexing like field accesses - Array { .. } => { - let field = field_index as u64; - let elem_size = match base_ty.sty { - ty::TyArray(elem_ty, n) => { - assert!(field < n.val.to_const_int().unwrap().to_u64().unwrap() as u64); - self.type_size(elem_ty)?.expect("array elements are sized") as u64 - } - _ => { - bug!( - "lvalue_field: got Array layout but non-array type {:?}", - base_ty - ) - } - }; - (Size::from_bytes(field * elem_size), false) - } - - FatPointer { .. } => { - let bytes = field_index as u64 * self.memory.pointer_size(); - let offset = Size::from_bytes(bytes); - (offset, false) - } - - _ => bug!("field access on non-product type: {:?}", base_layout), - }; - - // Do not allocate in trivial cases - let (base_ptr, base_extra) = match base { - Lvalue::Ptr { ptr, extra } => (ptr, extra), - Lvalue::Local { frame, local } => { - match self.stack[frame].get_local(local)? { - // in case the type has a single field, just return the value - Value::ByVal(_) - if self.get_field_count(base_ty).map(|c| c == 1).unwrap_or( - false, - ) => { - assert_eq!( - offset.bytes(), - 0, - "ByVal can only have 1 non zst field with offset 0" - ); - return Ok(base); - } - Value::ByRef { .. } | - Value::ByValPair(..) | - Value::ByVal(_) => self.force_allocation(base)?.to_ptr_extra_aligned(), - } - } - }; - - let offset = match base_extra { - LvalueExtra::Vtable(tab) => { - let (_, align) = self.size_and_align_of_dst( - base_ty, - base_ptr.ptr.to_value_with_vtable(tab), - )?; - offset - .abi_align(Align::from_bytes(align, align).unwrap()) - .bytes() - } - _ => offset.bytes(), - }; - - let mut ptr = base_ptr.offset(offset, &self)?; - // if we were unaligned, stay unaligned - // no matter what we were, if we are packed, we must not be aligned anymore - ptr.aligned &= !packed; - - let field_ty = self.monomorphize(field_ty, self.substs()); - - let extra = if self.type_is_sized(field_ty) { - LvalueExtra::None - } else { - match base_extra { - LvalueExtra::None => bug!("expected fat pointer"), - LvalueExtra::DowncastVariant(..) => { - bug!("Rust doesn't support unsized fields in enum variants") - } - LvalueExtra::Vtable(_) | - LvalueExtra::Length(_) => {} - } - base_extra - }; - - Ok(Lvalue::Ptr { ptr, extra }) - } - - pub(super) fn val_to_lvalue(&self, val: Value, ty: Ty<'tcx>) -> EvalResult<'tcx, Lvalue> { - Ok(match self.tcx.struct_tail(ty).sty { - ty::TyDynamic(..) => { - let (ptr, vtable) = val.into_ptr_vtable_pair(&self.memory)?; - Lvalue::Ptr { - ptr: PtrAndAlign { ptr, aligned: true }, - extra: LvalueExtra::Vtable(vtable), - } - } - ty::TyStr | ty::TySlice(_) => { - let (ptr, len) = val.into_slice(&self.memory)?; - Lvalue::Ptr { - ptr: PtrAndAlign { ptr, aligned: true }, - extra: LvalueExtra::Length(len), - } - } - _ => Lvalue::from_primval_ptr(val.into_ptr(&self.memory)?), - }) - } - - pub(super) fn lvalue_index( - &mut self, - base: Lvalue, - outer_ty: Ty<'tcx>, - n: u64, - ) -> EvalResult<'tcx, Lvalue> { - // Taking the outer type here may seem odd; it's needed because for array types, the outer type gives away the length. - let base = self.force_allocation(base)?; - let (base_ptr, _) = base.to_ptr_extra_aligned(); - - let (elem_ty, len) = base.elem_ty_and_len(outer_ty); - let elem_size = self.type_size(elem_ty)?.expect( - "slice element must be sized", - ); - assert!( - n < len, - "Tried to access element {} of array/slice with length {}", - n, - len - ); - let ptr = base_ptr.offset(n * elem_size, self.memory.layout)?; - Ok(Lvalue::Ptr { - ptr, - extra: LvalueExtra::None, - }) - } - - pub(super) fn eval_lvalue_projection( - &mut self, - base: Lvalue, - base_ty: Ty<'tcx>, - proj_elem: &mir::ProjectionElem<'tcx, mir::Local, Ty<'tcx>>, - ) -> EvalResult<'tcx, Lvalue> { - use rustc::mir::ProjectionElem::*; - let (ptr, extra) = match *proj_elem { - Field(field, field_ty) => { - return self.lvalue_field(base, field, base_ty, field_ty); - } - - Downcast(_, variant) => { - let base_layout = self.type_layout(base_ty)?; - // FIXME(solson) - let base = self.force_allocation(base)?; - let (base_ptr, base_extra) = base.to_ptr_extra_aligned(); - - use rustc::ty::layout::Layout::*; - let extra = match *base_layout { - General { .. } => LvalueExtra::DowncastVariant(variant), - RawNullablePointer { .. } | - StructWrappedNullablePointer { .. } => base_extra, - _ => bug!("variant downcast on non-aggregate: {:?}", base_layout), - }; - (base_ptr, extra) - } - - Deref => { - let val = self.read_lvalue(base)?; - - let pointee_type = match base_ty.sty { - ty::TyRawPtr(ref tam) | - ty::TyRef(_, ref tam) => tam.ty, - ty::TyAdt(def, _) if def.is_box() => base_ty.boxed_ty(), - _ => bug!("can only deref pointer types"), - }; - - trace!("deref to {} on {:?}", pointee_type, val); - - return self.val_to_lvalue(val, pointee_type); - } - - Index(local) => { - let value = self.frame().get_local(local)?; - let ty = self.tcx.types.usize; - let n = self.value_to_primval(ValTy { value, ty })?.to_u64()?; - return self.lvalue_index(base, base_ty, n); - } - - ConstantIndex { - offset, - min_length, - from_end, - } => { - // FIXME(solson) - let base = self.force_allocation(base)?; - let (base_ptr, _) = base.to_ptr_extra_aligned(); - - let (elem_ty, n) = base.elem_ty_and_len(base_ty); - let elem_size = self.type_size(elem_ty)?.expect( - "sequence element must be sized", - ); - assert!(n >= min_length as u64); - - let index = if from_end { - n - u64::from(offset) - } else { - u64::from(offset) - }; - - let ptr = base_ptr.offset(index * elem_size, &self)?; - (ptr, LvalueExtra::None) - } - - Subslice { from, to } => { - // FIXME(solson) - let base = self.force_allocation(base)?; - let (base_ptr, _) = base.to_ptr_extra_aligned(); - - let (elem_ty, n) = base.elem_ty_and_len(base_ty); - let elem_size = self.type_size(elem_ty)?.expect( - "slice element must be sized", - ); - assert!(u64::from(from) <= n - u64::from(to)); - let ptr = base_ptr.offset(u64::from(from) * elem_size, &self)?; - // sublicing arrays produces arrays - let extra = if self.type_is_sized(base_ty) { - LvalueExtra::None - } else { - LvalueExtra::Length(n - u64::from(to) - u64::from(from)) - }; - (ptr, extra) - } - }; - - Ok(Lvalue::Ptr { ptr, extra }) - } - - pub fn lvalue_ty(&self, lvalue: &mir::Lvalue<'tcx>) -> Ty<'tcx> { - self.monomorphize( - lvalue.ty(self.mir(), self.tcx).to_ty(self.tcx), - self.substs(), - ) - } -} diff --git a/src/librustc_mir/interpret/machine.rs b/src/librustc_mir/interpret/machine.rs deleted file mode 100644 index 3df5d1b6a31be..0000000000000 --- a/src/librustc_mir/interpret/machine.rs +++ /dev/null @@ -1,82 +0,0 @@ -//! This module contains everything needed to instantiate an interpreter. -//! This separation exists to ensure that no fancy miri features like -//! interpreting common C functions leak into CTFE. - -use super::{EvalResult, EvalContext, Lvalue, PrimVal, ValTy}; - -use rustc::{mir, ty}; -use syntax::codemap::Span; -use syntax::ast::Mutability; - -/// Methods of this trait signifies a point where CTFE evaluation would fail -/// and some use case dependent behaviour can instead be applied -pub trait Machine<'tcx>: Sized { - /// Additional data that can be accessed via the EvalContext - type Data; - - /// Additional data that can be accessed via the Memory - type MemoryData; - - /// Additional memory kinds a machine wishes to distinguish from the builtin ones - type MemoryKinds: ::std::fmt::Debug + PartialEq + Copy + Clone; - - /// Entry point to all function calls. - /// - /// Returns Ok(true) when the function was handled completely - /// e.g. due to missing mir - /// - /// Returns Ok(false) if a new stack frame was pushed - fn eval_fn_call<'a>( - ecx: &mut EvalContext<'a, 'tcx, Self>, - instance: ty::Instance<'tcx>, - destination: Option<(Lvalue, mir::BasicBlock)>, - args: &[ValTy<'tcx>], - span: Span, - sig: ty::FnSig<'tcx>, - ) -> EvalResult<'tcx, bool>; - - /// directly process an intrinsic without pushing a stack frame. - fn call_intrinsic<'a>( - ecx: &mut EvalContext<'a, 'tcx, Self>, - instance: ty::Instance<'tcx>, - args: &[ValTy<'tcx>], - dest: Lvalue, - dest_ty: ty::Ty<'tcx>, - dest_layout: &'tcx ty::layout::Layout, - target: mir::BasicBlock, - ) -> EvalResult<'tcx>; - - /// Called for all binary operations except on float types. - /// - /// Returns `None` if the operation should be handled by the integer - /// op code in order to share more code between machines - /// - /// Returns a (value, overflowed) pair if the operation succeeded - fn try_ptr_op<'a>( - ecx: &EvalContext<'a, 'tcx, Self>, - bin_op: mir::BinOp, - left: PrimVal, - left_ty: ty::Ty<'tcx>, - right: PrimVal, - right_ty: ty::Ty<'tcx>, - ) -> EvalResult<'tcx, Option<(PrimVal, bool)>>; - - /// Called when trying to mark machine defined `MemoryKinds` as static - fn mark_static_initialized(m: Self::MemoryKinds) -> EvalResult<'tcx>; - - /// Heap allocations via the `box` keyword - /// - /// Returns a pointer to the allocated memory - fn box_alloc<'a>( - ecx: &mut EvalContext<'a, 'tcx, Self>, - ty: ty::Ty<'tcx>, - dest: Lvalue, - ) -> EvalResult<'tcx>; - - /// Called when trying to access a global declared with a `linkage` attribute - fn global_item_with_linkage<'a>( - ecx: &mut EvalContext<'a, 'tcx, Self>, - instance: ty::Instance<'tcx>, - mutability: Mutability, - ) -> EvalResult<'tcx>; -} diff --git a/src/librustc_mir/interpret/memory.rs b/src/librustc_mir/interpret/memory.rs deleted file mode 100644 index bde79294adda5..0000000000000 --- a/src/librustc_mir/interpret/memory.rs +++ /dev/null @@ -1,1700 +0,0 @@ -use byteorder::{ReadBytesExt, WriteBytesExt, LittleEndian, BigEndian}; -use std::collections::{btree_map, BTreeMap, HashMap, HashSet, VecDeque}; -use std::{fmt, iter, ptr, mem, io}; -use std::cell::Cell; - -use rustc::ty::Instance; -use rustc::ty::layout::{self, TargetDataLayout, HasDataLayout}; -use syntax::ast::Mutability; -use rustc::middle::region; - -use super::{EvalResult, EvalErrorKind, PrimVal, Pointer, EvalContext, DynamicLifetime, Machine, - RangeMap, AbsLvalue}; - -//////////////////////////////////////////////////////////////////////////////// -// Locks -//////////////////////////////////////////////////////////////////////////////// - -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -pub enum AccessKind { - Read, - Write, -} - -/// Information about a lock that is currently held. -#[derive(Clone, Debug)] -struct LockInfo<'tcx> { - /// Stores for which lifetimes (of the original write lock) we got - /// which suspensions. - suspended: HashMap, Vec>, - /// The current state of the lock that's actually effective. - active: Lock, -} - -/// Write locks are identified by a stack frame and an "abstract" (untyped) lvalue. -/// It may be tempting to use the lifetime as identifier, but that does not work -/// for two reasons: -/// * First of all, due to subtyping, the same lock may be referred to with different -/// lifetimes. -/// * Secondly, different write locks may actually have the same lifetime. See `test2` -/// in `run-pass/many_shr_bor.rs`. -/// The Id is "captured" when the lock is first suspended; at that point, the borrow checker -/// considers the path frozen and hence the Id remains stable. -#[derive(Clone, Debug, PartialEq, Eq, Hash)] -struct WriteLockId<'tcx> { - frame: usize, - path: AbsLvalue<'tcx>, -} - -#[derive(Clone, Debug, PartialEq)] -pub enum Lock { - NoLock, - WriteLock(DynamicLifetime), - ReadLock(Vec), // This should never be empty -- that would be a read lock held and nobody there to release it... -} -use self::Lock::*; - -impl<'tcx> Default for LockInfo<'tcx> { - fn default() -> Self { - LockInfo::new(NoLock) - } -} - -impl<'tcx> LockInfo<'tcx> { - fn new(lock: Lock) -> LockInfo<'tcx> { - LockInfo { - suspended: HashMap::new(), - active: lock, - } - } - - fn access_permitted(&self, frame: Option, access: AccessKind) -> bool { - use self::AccessKind::*; - match (&self.active, access) { - (&NoLock, _) => true, - (&ReadLock(ref lfts), Read) => { - assert!(!lfts.is_empty(), "Someone left an empty read lock behind."); - // Read access to read-locked region is okay, no matter who's holding the read lock. - true - } - (&WriteLock(ref lft), _) => { - // All access is okay if we are the ones holding it - Some(lft.frame) == frame - } - _ => false, // Nothing else is okay. - } - } -} - -//////////////////////////////////////////////////////////////////////////////// -// Allocations and pointers -//////////////////////////////////////////////////////////////////////////////// - -#[derive(Copy, Clone, Eq, Hash, Ord, PartialEq, PartialOrd)] -pub struct AllocId(u64); - -#[derive(Debug)] -pub enum AllocIdKind { - /// We can't ever have more than `usize::max_value` functions at the same time - /// since we never "deallocate" functions - Function(usize), - /// Locals and heap allocations (also statics for now, but those will get their - /// own variant soonish). - Runtime(u64), -} - -impl AllocIdKind { - pub fn into_alloc_id(self) -> AllocId { - match self { - AllocIdKind::Function(n) => AllocId(n as u64), - AllocIdKind::Runtime(n) => AllocId((1 << 63) | n), - } - } -} - -impl AllocId { - /// Currently yields the top bit to discriminate the `AllocIdKind`s - fn discriminant(self) -> u64 { - self.0 >> 63 - } - /// Yields everything but the discriminant bits - pub fn index(self) -> u64 { - self.0 & ((1 << 63) - 1) - } - pub fn into_alloc_id_kind(self) -> AllocIdKind { - match self.discriminant() { - 0 => AllocIdKind::Function(self.index() as usize), - 1 => AllocIdKind::Runtime(self.index()), - n => bug!("got discriminant {} for AllocId", n), - } - } -} - -impl fmt::Display for AllocId { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{:?}", self.into_alloc_id_kind()) - } -} - -impl fmt::Debug for AllocId { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{:?}", self.into_alloc_id_kind()) - } -} - -#[derive(Debug)] -pub struct Allocation<'tcx, M> { - /// The actual bytes of the allocation. - /// Note that the bytes of a pointer represent the offset of the pointer - pub bytes: Vec, - /// Maps from byte addresses to allocations. - /// Only the first byte of a pointer is inserted into the map. - pub relocations: BTreeMap, - /// Denotes undefined memory. Reading from undefined memory is forbidden in miri - pub undef_mask: UndefMask, - /// The alignment of the allocation to detect unaligned reads. - pub align: u64, - /// Whether the allocation may be modified. - pub mutable: Mutability, - /// Use the `mark_static_initalized` method of `Memory` to ensure that an error occurs, if the memory of this - /// allocation is modified or deallocated in the future. - /// Helps guarantee that stack allocations aren't deallocated via `rust_deallocate` - pub kind: MemoryKind, - /// Memory regions that are locked by some function - locks: RangeMap>, -} - -impl<'tcx, M> Allocation<'tcx, M> { - fn check_locks( - &self, - frame: Option, - offset: u64, - len: u64, - access: AccessKind, - ) -> Result<(), LockInfo<'tcx>> { - if len == 0 { - return Ok(()); - } - for lock in self.locks.iter(offset, len) { - // Check if the lock is in conflict with the access. - if !lock.access_permitted(frame, access) { - return Err(lock.clone()); - } - } - Ok(()) - } -} - -#[derive(Debug, PartialEq, Copy, Clone)] -pub enum MemoryKind { - /// Error if deallocated except during a stack pop - Stack, - /// Static in the process of being initialized. - /// The difference is important: An immutable static referring to a - /// mutable initialized static will freeze immutably and would not - /// be able to distinguish already initialized statics from uninitialized ones - UninitializedStatic, - /// May never be deallocated - Static, - /// Additional memory kinds a machine wishes to distinguish from the builtin ones - Machine(T), -} - -#[derive(Copy, Clone, Debug, Eq, PartialEq)] -pub struct MemoryPointer { - pub alloc_id: AllocId, - pub offset: u64, -} - -impl<'tcx> MemoryPointer { - pub fn new(alloc_id: AllocId, offset: u64) -> Self { - MemoryPointer { alloc_id, offset } - } - - pub(crate) fn wrapping_signed_offset(self, i: i64, cx: C) -> Self { - MemoryPointer::new( - self.alloc_id, - cx.data_layout().wrapping_signed_offset(self.offset, i), - ) - } - - pub fn overflowing_signed_offset(self, i: i128, cx: C) -> (Self, bool) { - let (res, over) = cx.data_layout().overflowing_signed_offset(self.offset, i); - (MemoryPointer::new(self.alloc_id, res), over) - } - - pub(crate) fn signed_offset(self, i: i64, cx: C) -> EvalResult<'tcx, Self> { - Ok(MemoryPointer::new( - self.alloc_id, - cx.data_layout().signed_offset(self.offset, i)?, - )) - } - - pub fn overflowing_offset(self, i: u64, cx: C) -> (Self, bool) { - let (res, over) = cx.data_layout().overflowing_offset(self.offset, i); - (MemoryPointer::new(self.alloc_id, res), over) - } - - pub fn offset(self, i: u64, cx: C) -> EvalResult<'tcx, Self> { - Ok(MemoryPointer::new( - self.alloc_id, - cx.data_layout().offset(self.offset, i)?, - )) - } -} - -//////////////////////////////////////////////////////////////////////////////// -// Top-level interpreter memory -//////////////////////////////////////////////////////////////////////////////// - -pub struct Memory<'a, 'tcx, M: Machine<'tcx>> { - /// Additional data required by the Machine - pub data: M::MemoryData, - - /// Actual memory allocations (arbitrary bytes, may contain pointers into other allocations). - alloc_map: HashMap>, - - /// The AllocId to assign to the next new regular allocation. Always incremented, never gets smaller. - next_alloc_id: u64, - - /// Number of virtual bytes allocated. - memory_usage: u64, - - /// Maximum number of virtual bytes that may be allocated. - memory_size: u64, - - /// Function "allocations". They exist solely so pointers have something to point to, and - /// we can figure out what they point to. - functions: Vec>, - - /// Inverse map of `functions` so we don't allocate a new pointer every time we need one - function_alloc_cache: HashMap, AllocId>, - - /// Target machine data layout to emulate. - pub layout: &'a TargetDataLayout, - - /// A cache for basic byte allocations keyed by their contents. This is used to deduplicate - /// allocations for string and bytestring literals. - literal_alloc_cache: HashMap, AllocId>, - - /// To avoid having to pass flags to every single memory access, we have some global state saying whether - /// alignment checking is currently enforced for read and/or write accesses. - reads_are_aligned: Cell, - writes_are_aligned: Cell, - - /// The current stack frame. Used to check accesses against locks. - pub(super) cur_frame: usize, -} - -impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> { - pub fn new(layout: &'a TargetDataLayout, max_memory: u64, data: M::MemoryData) -> Self { - Memory { - data, - alloc_map: HashMap::new(), - functions: Vec::new(), - function_alloc_cache: HashMap::new(), - next_alloc_id: 0, - layout, - memory_size: max_memory, - memory_usage: 0, - literal_alloc_cache: HashMap::new(), - reads_are_aligned: Cell::new(true), - writes_are_aligned: Cell::new(true), - cur_frame: usize::max_value(), - } - } - - pub fn allocations<'x>( - &'x self, - ) -> impl Iterator)> { - self.alloc_map.iter().map(|(&id, alloc)| { - (AllocIdKind::Runtime(id).into_alloc_id(), alloc) - }) - } - - 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); - } - let id = self.functions.len(); - debug!("creating fn ptr: {}", id); - self.functions.push(instance); - let alloc_id = AllocIdKind::Function(id).into_alloc_id(); - self.function_alloc_cache.insert(instance, alloc_id); - MemoryPointer::new(alloc_id, 0) - } - - pub fn allocate_cached(&mut self, bytes: &[u8]) -> EvalResult<'tcx, MemoryPointer> { - if let Some(&alloc_id) = self.literal_alloc_cache.get(bytes) { - return Ok(MemoryPointer::new(alloc_id, 0)); - } - - let ptr = self.allocate( - bytes.len() as u64, - 1, - MemoryKind::UninitializedStatic, - )?; - self.write_bytes(ptr.into(), bytes)?; - self.mark_static_initalized( - ptr.alloc_id, - Mutability::Immutable, - )?; - self.literal_alloc_cache.insert( - bytes.to_vec(), - ptr.alloc_id, - ); - Ok(ptr) - } - - pub fn allocate( - &mut self, - size: u64, - align: u64, - kind: MemoryKind, - ) -> EvalResult<'tcx, MemoryPointer> { - assert_ne!(align, 0); - assert!(align.is_power_of_two()); - - if self.memory_size - self.memory_usage < size { - return err!(OutOfMemory { - allocation_size: size, - memory_size: self.memory_size, - memory_usage: self.memory_usage, - }); - } - self.memory_usage += size; - assert_eq!(size as usize as u64, size); - let alloc = Allocation { - bytes: vec![0; size as usize], - relocations: BTreeMap::new(), - undef_mask: UndefMask::new(size), - align, - kind, - mutable: Mutability::Mutable, - locks: RangeMap::new(), - }; - let id = self.next_alloc_id; - self.next_alloc_id += 1; - self.alloc_map.insert(id, alloc); - Ok(MemoryPointer::new( - AllocIdKind::Runtime(id).into_alloc_id(), - 0, - )) - } - - pub fn reallocate( - &mut self, - ptr: MemoryPointer, - old_size: u64, - old_align: u64, - new_size: u64, - new_align: u64, - kind: MemoryKind, - ) -> EvalResult<'tcx, MemoryPointer> { - use std::cmp::min; - - if ptr.offset != 0 { - return err!(ReallocateNonBasePtr); - } - if let Ok(alloc) = self.get(ptr.alloc_id) { - if alloc.kind != kind { - return err!(ReallocatedWrongMemoryKind( - format!("{:?}", alloc.kind), - format!("{:?}", kind), - )); - } - } - - // For simplicities' sake, we implement reallocate as "alloc, copy, dealloc" - let new_ptr = self.allocate(new_size, new_align, kind)?; - self.copy( - ptr.into(), - new_ptr.into(), - min(old_size, new_size), - min(old_align, new_align), - /*nonoverlapping*/ - true, - )?; - self.deallocate(ptr, Some((old_size, old_align)), kind)?; - - Ok(new_ptr) - } - - pub fn deallocate( - &mut self, - ptr: MemoryPointer, - size_and_align: Option<(u64, u64)>, - kind: MemoryKind, - ) -> EvalResult<'tcx> { - if ptr.offset != 0 { - return err!(DeallocateNonBasePtr); - } - - let alloc_id = match ptr.alloc_id.into_alloc_id_kind() { - AllocIdKind::Function(_) => { - return err!(DeallocatedWrongMemoryKind( - "function".to_string(), - format!("{:?}", kind), - )) - } - AllocIdKind::Runtime(id) => id, - }; - - let alloc = match self.alloc_map.remove(&alloc_id) { - Some(alloc) => alloc, - None => return err!(DoubleFree), - }; - - // It is okay for us to still holds locks on deallocation -- for example, we could store data we own - // in a local, and the local could be deallocated (from StorageDead) before the function returns. - // However, we should check *something*. For now, we make sure that there is no conflicting write - // lock by another frame. We *have* to permit deallocation if we hold a read lock. - // TODO: Figure out the exact rules here. - alloc - .check_locks( - Some(self.cur_frame), - 0, - alloc.bytes.len() as u64, - AccessKind::Read, - ) - .map_err(|lock| { - EvalErrorKind::DeallocatedLockedMemory { - ptr, - lock: lock.active, - } - })?; - - if alloc.kind != kind { - return err!(DeallocatedWrongMemoryKind( - format!("{:?}", alloc.kind), - format!("{:?}", kind), - )); - } - if let Some((size, align)) = size_and_align { - if size != alloc.bytes.len() as u64 || align != alloc.align { - return err!(IncorrectAllocationInformation); - } - } - - self.memory_usage -= alloc.bytes.len() as u64; - debug!("deallocated : {}", ptr.alloc_id); - - Ok(()) - } - - pub fn pointer_size(&self) -> u64 { - self.layout.pointer_size.bytes() - } - - pub fn endianess(&self) -> layout::Endian { - self.layout.endian - } - - /// Check that the pointer is aligned AND non-NULL. - pub fn check_align(&self, ptr: Pointer, align: u64, access: Option) -> 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)?; - (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, 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 { - err!(AlignmentCheckFailed { - has: offset % align, - required: align, - }) - } - } - - pub fn check_bounds(&self, ptr: MemoryPointer, access: bool) -> EvalResult<'tcx> { - let alloc = self.get(ptr.alloc_id)?; - let allocation_size = alloc.bytes.len() as u64; - if ptr.offset > allocation_size { - return err!(PointerOutOfBounds { - ptr, - access, - allocation_size, - }); - } - Ok(()) - } -} - -/// Locking -impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> { - pub(crate) fn check_locks( - &self, - ptr: MemoryPointer, - len: u64, - access: AccessKind, - ) -> EvalResult<'tcx> { - if len == 0 { - return Ok(()); - } - let alloc = self.get(ptr.alloc_id)?; - let frame = self.cur_frame; - alloc - .check_locks(Some(frame), ptr.offset, len, access) - .map_err(|lock| { - EvalErrorKind::MemoryLockViolation { - ptr, - len, - frame, - access, - lock: lock.active, - }.into() - }) - } - - /// Acquire the lock for the given lifetime - pub(crate) fn acquire_lock( - &mut self, - ptr: MemoryPointer, - len: u64, - region: Option, - kind: AccessKind, - ) -> EvalResult<'tcx> { - let frame = self.cur_frame; - assert!(len > 0); - trace!( - "Frame {} acquiring {:?} lock at {:?}, size {} for region {:?}", - frame, - kind, - ptr, - len, - region - ); - self.check_bounds(ptr.offset(len, self.layout)?, true)?; // if ptr.offset is in bounds, then so is ptr (because offset checks for overflow) - let alloc = self.get_mut_unchecked(ptr.alloc_id)?; - - // Iterate over our range and acquire the lock. If the range is already split into pieces, - // we have to manipulate all of them. - let lifetime = DynamicLifetime { frame, region }; - for lock in alloc.locks.iter_mut(ptr.offset, len) { - if !lock.access_permitted(None, kind) { - return err!(MemoryAcquireConflict { - ptr, - len, - kind, - lock: lock.active.clone(), - }); - } - // See what we have to do - match (&mut lock.active, kind) { - (active @ &mut NoLock, AccessKind::Write) => { - *active = WriteLock(lifetime); - } - (active @ &mut NoLock, AccessKind::Read) => { - *active = ReadLock(vec![lifetime]); - } - (&mut ReadLock(ref mut lifetimes), AccessKind::Read) => { - lifetimes.push(lifetime); - } - _ => bug!("We already checked that there is no conflicting lock"), - } - } - Ok(()) - } - - /// Release or suspend a write lock of the given lifetime prematurely. - /// When releasing, if there is a read lock or someone else's write lock, that's an error. - /// If no lock is held, that's fine. This can happen when e.g. a local is initialized - /// from a constant, and then suspended. - /// When suspending, the same cases are fine; we just register an additional suspension. - pub(crate) fn suspend_write_lock( - &mut self, - ptr: MemoryPointer, - len: u64, - lock_path: &AbsLvalue<'tcx>, - suspend: Option, - ) -> EvalResult<'tcx> { - assert!(len > 0); - let cur_frame = self.cur_frame; - let alloc = self.get_mut_unchecked(ptr.alloc_id)?; - - 'locks: for lock in alloc.locks.iter_mut(ptr.offset, len) { - let is_our_lock = match lock.active { - WriteLock(lft) => - // Double-check that we are holding the lock. - // (Due to subtyping, checking the region would not make any sense.) - lft.frame == cur_frame, - ReadLock(_) | NoLock => false, - }; - if is_our_lock { - trace!("Releasing {:?}", lock.active); - // Disable the lock - lock.active = NoLock; - } else { - trace!( - "Not touching {:?} as it is not our lock", - lock.active, - ); - } - // Check if we want to register a suspension - if let Some(suspend_region) = suspend { - let lock_id = WriteLockId { - frame: cur_frame, - path: lock_path.clone(), - }; - trace!("Adding suspension to {:?}", lock_id); - let mut new_suspension = false; - lock.suspended - .entry(lock_id) - // Remember whether we added a new suspension or not - .or_insert_with(|| { new_suspension = true; Vec::new() }) - .push(suspend_region); - // If the suspension is new, we should have owned this. - // If there already was a suspension, we should NOT have owned this. - if new_suspension == is_our_lock { - // All is well - continue 'locks; - } - } else { - if !is_our_lock { - // All is well. - continue 'locks; - } - } - // If we get here, releasing this is an error except for NoLock. - if lock.active != NoLock { - return err!(InvalidMemoryLockRelease { - ptr, - len, - frame: cur_frame, - lock: lock.active.clone(), - }); - } - } - - Ok(()) - } - - /// Release a suspension from the write lock. If this is the last suspension or if there is no suspension, acquire the lock. - pub(crate) fn recover_write_lock( - &mut self, - ptr: MemoryPointer, - len: u64, - lock_path: &AbsLvalue<'tcx>, - lock_region: Option, - suspended_region: region::Scope, - ) -> EvalResult<'tcx> { - assert!(len > 0); - let cur_frame = self.cur_frame; - let lock_id = WriteLockId { - frame: cur_frame, - path: lock_path.clone(), - }; - let alloc = self.get_mut_unchecked(ptr.alloc_id)?; - - for lock in alloc.locks.iter_mut(ptr.offset, len) { - // Check if we have a suspension here - let (got_the_lock, remove_suspension) = match lock.suspended.get_mut(&lock_id) { - None => { - trace!("No suspension around, we can just acquire"); - (true, false) - } - Some(suspensions) => { - trace!("Found suspension of {:?}, removing it", lock_id); - // That's us! Remove suspension (it should be in there). The same suspension can - // occur multiple times (when there are multiple shared borrows of this that have the same - // lifetime); only remove one of them. - let idx = match suspensions.iter().enumerate().find(|&(_, re)| re == &suspended_region) { - None => // TODO: Can the user trigger this? - bug!("We have this lock suspended, but not for the given region."), - Some((idx, _)) => idx - }; - suspensions.remove(idx); - let got_lock = suspensions.is_empty(); - if got_lock { - trace!("All suspensions are gone, we can have the lock again"); - } - (got_lock, got_lock) - } - }; - if remove_suspension { - // with NLL, we could do that up in the match above... - assert!(got_the_lock); - lock.suspended.remove(&lock_id); - } - if got_the_lock { - match lock.active { - ref mut active @ NoLock => { - *active = WriteLock( - DynamicLifetime { - frame: cur_frame, - region: lock_region, - } - ); - } - _ => { - return err!(MemoryAcquireConflict { - ptr, - len, - kind: AccessKind::Write, - lock: lock.active.clone(), - }) - } - } - } - } - - Ok(()) - } - - pub(crate) fn locks_lifetime_ended(&mut self, ending_region: Option) { - let cur_frame = self.cur_frame; - trace!( - "Releasing frame {} locks that expire at {:?}", - cur_frame, - ending_region - ); - let has_ended = |lifetime: &DynamicLifetime| -> bool { - if lifetime.frame != cur_frame { - return false; - } - match ending_region { - None => true, // When a function ends, we end *all* its locks. It's okay for a function to still have lifetime-related locks - // when it returns, that can happen e.g. with NLL when a lifetime can, but does not have to, extend beyond the - // end of a function. Same for a function still having recoveries. - Some(ending_region) => lifetime.region == Some(ending_region), - } - }; - - for alloc in self.alloc_map.values_mut() { - for lock in alloc.locks.iter_mut_all() { - // Delete everything that ends now -- i.e., keep only all the other lifetimes. - let lock_ended = match lock.active { - WriteLock(ref lft) => has_ended(lft), - ReadLock(ref mut lfts) => { - lfts.retain(|lft| !has_ended(lft)); - lfts.is_empty() - } - NoLock => false, - }; - if lock_ended { - lock.active = NoLock; - } - // Also clean up suspended write locks when the function returns - if ending_region.is_none() { - lock.suspended.retain(|id, _suspensions| id.frame != cur_frame); - } - } - // Clean up the map - alloc.locks.retain(|lock| match lock.active { - NoLock => lock.suspended.len() > 0, - _ => true, - }); - } - } -} - -/// Allocation accessors -impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> { - pub fn get(&self, id: AllocId) -> EvalResult<'tcx, &Allocation<'tcx, M::MemoryKinds>> { - match id.into_alloc_id_kind() { - AllocIdKind::Function(_) => err!(DerefFunctionPointer), - AllocIdKind::Runtime(id) => { - match self.alloc_map.get(&id) { - Some(alloc) => Ok(alloc), - None => err!(DanglingPointerDeref), - } - } - } - } - - fn get_mut_unchecked( - &mut self, - id: AllocId, - ) -> EvalResult<'tcx, &mut Allocation<'tcx, M::MemoryKinds>> { - match id.into_alloc_id_kind() { - AllocIdKind::Function(_) => err!(DerefFunctionPointer), - AllocIdKind::Runtime(id) => { - match self.alloc_map.get_mut(&id) { - Some(alloc) => Ok(alloc), - None => err!(DanglingPointerDeref), - } - } - } - } - - fn get_mut(&mut self, id: AllocId) -> EvalResult<'tcx, &mut Allocation<'tcx, M::MemoryKinds>> { - let alloc = self.get_mut_unchecked(id)?; - if alloc.mutable == Mutability::Mutable { - Ok(alloc) - } else { - err!(ModifiedConstantMemory) - } - } - - pub fn get_fn(&self, ptr: MemoryPointer) -> EvalResult<'tcx, Instance<'tcx>> { - if ptr.offset != 0 { - return err!(InvalidFunctionPointer); - } - debug!("reading fn ptr: {}", ptr.alloc_id); - match ptr.alloc_id.into_alloc_id_kind() { - AllocIdKind::Function(id) => Ok(self.functions[id]), - AllocIdKind::Runtime(_) => err!(ExecuteMemory), - } - } - - /// For debugging, print an allocation and all allocations it points to, recursively. - pub fn dump_alloc(&self, id: AllocId) { - self.dump_allocs(vec![id]); - } - - /// For debugging, print a list of allocations and all allocations they point to, recursively. - pub fn dump_allocs(&self, mut allocs: Vec) { - use std::fmt::Write; - allocs.sort(); - allocs.dedup(); - let mut allocs_to_print = VecDeque::from(allocs); - let mut allocs_seen = HashSet::new(); - - while let Some(id) = allocs_to_print.pop_front() { - let mut msg = format!("Alloc {:<5} ", format!("{}:", id)); - let prefix_len = msg.len(); - let mut relocations = vec![]; - - let alloc = match id.into_alloc_id_kind() { - AllocIdKind::Function(id) => { - trace!("{} {}", msg, self.functions[id]); - continue; - } - AllocIdKind::Runtime(id) => { - match self.alloc_map.get(&id) { - Some(a) => a, - None => { - trace!("{} (deallocated)", msg); - continue; - } - } - } - }; - - for i in 0..(alloc.bytes.len() as u64) { - if let Some(&target_id) = alloc.relocations.get(&i) { - if allocs_seen.insert(target_id) { - allocs_to_print.push_back(target_id); - } - relocations.push((i, target_id)); - } - if alloc.undef_mask.is_range_defined(i, i + 1) { - // this `as usize` is fine, since `i` came from a `usize` - write!(msg, "{:02x} ", alloc.bytes[i as usize]).unwrap(); - } else { - msg.push_str("__ "); - } - } - - let immutable = match (alloc.kind, alloc.mutable) { - (MemoryKind::UninitializedStatic, _) => { - " (static in the process of initialization)".to_owned() - } - (MemoryKind::Static, Mutability::Mutable) => " (static mut)".to_owned(), - (MemoryKind::Static, Mutability::Immutable) => " (immutable)".to_owned(), - (MemoryKind::Machine(m), _) => format!(" ({:?})", m), - (MemoryKind::Stack, _) => " (stack)".to_owned(), - }; - trace!( - "{}({} bytes, alignment {}){}", - msg, - alloc.bytes.len(), - alloc.align, - immutable - ); - - if !relocations.is_empty() { - msg.clear(); - write!(msg, "{:1$}", "", prefix_len).unwrap(); // Print spaces. - let mut pos = 0; - let relocation_width = (self.pointer_size() - 1) * 3; - for (i, target_id) in relocations { - // this `as usize` is fine, since we can't print more chars than `usize::MAX` - write!(msg, "{:1$}", "", ((i - pos) * 3) as usize).unwrap(); - let target = format!("({})", target_id); - // this `as usize` is fine, since we can't print more chars than `usize::MAX` - write!(msg, "└{0:─^1$}┘ ", target, relocation_width as usize).unwrap(); - pos = i + self.pointer_size(); - } - trace!("{}", msg); - } - } - } - - pub fn leak_report(&self) -> usize { - trace!("### LEAK REPORT ###"); - let leaks: Vec<_> = self.alloc_map - .iter() - .filter_map(|(&key, val)| if val.kind != MemoryKind::Static { - Some(AllocIdKind::Runtime(key).into_alloc_id()) - } else { - None - }) - .collect(); - let n = leaks.len(); - self.dump_allocs(leaks); - n - } -} - -/// Byte accessors -impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> { - fn get_bytes_unchecked( - &self, - ptr: MemoryPointer, - size: u64, - align: u64, - ) -> EvalResult<'tcx, &[u8]> { - // Zero-sized accesses can use dangling pointers, but they still have to be aligned and non-NULL - self.check_align(ptr.into(), align, Some(AccessKind::Read))?; - if size == 0 { - return Ok(&[]); - } - self.check_locks(ptr, size, AccessKind::Read)?; - self.check_bounds(ptr.offset(size, self)?, true)?; // if ptr.offset is in bounds, then so is ptr (because offset checks for overflow) - let alloc = self.get(ptr.alloc_id)?; - assert_eq!(ptr.offset as usize as u64, ptr.offset); - assert_eq!(size as usize as u64, size); - let offset = ptr.offset as usize; - Ok(&alloc.bytes[offset..offset + size as usize]) - } - - fn get_bytes_unchecked_mut( - &mut self, - ptr: MemoryPointer, - size: u64, - align: u64, - ) -> EvalResult<'tcx, &mut [u8]> { - // Zero-sized accesses can use dangling pointers, but they still have to be aligned and non-NULL - self.check_align(ptr.into(), align, Some(AccessKind::Write))?; - if size == 0 { - return Ok(&mut []); - } - self.check_locks(ptr, size, AccessKind::Write)?; - self.check_bounds(ptr.offset(size, self.layout)?, true)?; // if ptr.offset is in bounds, then so is ptr (because offset checks for overflow) - let alloc = self.get_mut(ptr.alloc_id)?; - assert_eq!(ptr.offset as usize as u64, ptr.offset); - assert_eq!(size as usize as u64, size); - let offset = ptr.offset as usize; - Ok(&mut alloc.bytes[offset..offset + size as usize]) - } - - fn get_bytes(&self, ptr: MemoryPointer, size: u64, align: u64) -> EvalResult<'tcx, &[u8]> { - assert_ne!(size, 0); - if self.relocations(ptr, size)?.count() != 0 { - return err!(ReadPointerAsBytes); - } - self.check_defined(ptr, size)?; - self.get_bytes_unchecked(ptr, size, align) - } - - fn get_bytes_mut( - &mut self, - ptr: MemoryPointer, - size: u64, - align: u64, - ) -> EvalResult<'tcx, &mut [u8]> { - assert_ne!(size, 0); - self.clear_relocations(ptr, size)?; - self.mark_definedness(ptr.into(), size, true)?; - self.get_bytes_unchecked_mut(ptr, size, align) - } -} - -/// 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 - fn mark_inner_allocation_initialized( - &mut self, - alloc: AllocId, - mutability: Mutability, - ) -> EvalResult<'tcx> { - // relocations into other statics are not "inner allocations" - if self.get(alloc).ok().map_or(false, |alloc| { - alloc.kind != MemoryKind::UninitializedStatic - }) - { - self.mark_static_initalized(alloc, mutability)?; - } - Ok(()) - } - - /// mark an allocation as static and initialized, either mutable or not - pub fn mark_static_initalized( - &mut self, - alloc_id: AllocId, - mutability: Mutability, - ) -> EvalResult<'tcx> { - trace!( - "mark_static_initalized {:?}, mutability: {:?}", - alloc_id, - mutability - ); - // do not use `self.get_mut(alloc_id)` here, because we might have already marked a - // sub-element or have circular pointers (e.g. `Rc`-cycles) - let alloc_id = match alloc_id.into_alloc_id_kind() { - AllocIdKind::Function(_) => return Ok(()), - AllocIdKind::Runtime(id) => id, - }; - let relocations = match self.alloc_map.get_mut(&alloc_id) { - Some(&mut Allocation { - ref mut relocations, - ref mut kind, - ref mut mutable, - .. - }) => { - match *kind { - // const eval results can refer to "locals". - // E.g. `const Foo: &u32 = &1;` refers to the temp local that stores the `1` - MemoryKind::Stack | - // The entire point of this function - MemoryKind::UninitializedStatic => {}, - MemoryKind::Machine(m) => M::mark_static_initialized(m)?, - MemoryKind::Static => { - trace!("mark_static_initalized: skipping already initialized static referred to by static currently being initialized"); - return Ok(()); - }, - } - *kind = MemoryKind::Static; - *mutable = mutability; - // take out the relocations vector to free the borrow on self, so we can call - // mark recursively - mem::replace(relocations, Default::default()) - } - None => return err!(DanglingPointerDeref), - }; - // recurse into inner allocations - for &alloc in relocations.values() { - self.mark_inner_allocation_initialized(alloc, mutability)?; - } - // put back the relocations - self.alloc_map - .get_mut(&alloc_id) - .expect("checked above") - .relocations = relocations; - Ok(()) - } - - pub fn copy( - &mut self, - src: Pointer, - dest: Pointer, - size: u64, - 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 { - return Ok(()); - } - let src = src.to_ptr()?; - let dest = dest.to_ptr()?; - self.check_relocation_edges(src, size)?; - - // first copy the relocations to a temporary buffer, because - // `get_bytes_mut` will clear the relocations, which is correct, - // since we don't want to keep any relocations at the target. - - let relocations: Vec<_> = self.relocations(src, size)? - .map(|(&offset, &alloc_id)| { - // Update relocation offsets for the new positions in the destination allocation. - (offset + dest.offset - src.offset, alloc_id) - }) - .collect(); - - let src_bytes = self.get_bytes_unchecked(src, size, align)?.as_ptr(); - let dest_bytes = self.get_bytes_mut(dest, size, align)?.as_mut_ptr(); - - // SAFE: The above indexing would have panicked if there weren't at least `size` bytes - // behind `src` and `dest`. Also, we use the overlapping-safe `ptr::copy` if `src` and - // `dest` could possibly overlap. - unsafe { - assert_eq!(size as usize as u64, size); - if src.alloc_id == dest.alloc_id { - if nonoverlapping { - if (src.offset <= dest.offset && src.offset + size > dest.offset) || - (dest.offset <= src.offset && dest.offset + size > src.offset) - { - return err!(Intrinsic( - format!("copy_nonoverlapping called on overlapping ranges"), - )); - } - } - ptr::copy(src_bytes, dest_bytes, size as usize); - } else { - ptr::copy_nonoverlapping(src_bytes, dest_bytes, size as usize); - } - } - - self.copy_undef_mask(src, dest, size)?; - // copy back the relocations - self.get_mut(dest.alloc_id)?.relocations.extend(relocations); - - Ok(()) - } - - pub fn read_c_str(&self, ptr: MemoryPointer) -> EvalResult<'tcx, &[u8]> { - let alloc = self.get(ptr.alloc_id)?; - assert_eq!(ptr.offset as usize as u64, ptr.offset); - let offset = ptr.offset as usize; - match alloc.bytes[offset..].iter().position(|&c| c == 0) { - Some(size) => { - if self.relocations(ptr, (size + 1) as u64)?.count() != 0 { - return err!(ReadPointerAsBytes); - } - self.check_defined(ptr, (size + 1) as u64)?; - self.check_locks(ptr, (size + 1) as u64, AccessKind::Read)?; - Ok(&alloc.bytes[offset..offset + size]) - } - None => err!(UnterminatedCString(ptr)), - } - } - - 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 { - 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() { - return Ok(()); - } - let bytes = self.get_bytes_mut(ptr.to_ptr()?, src.len() as u64, 1)?; - bytes.clone_from_slice(src); - Ok(()) - } - - 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 { - return Ok(()); - } - let bytes = self.get_bytes_mut(ptr.to_ptr()?, count, 1)?; - for b in bytes { - *b = val; - } - Ok(()) - } - - 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, 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()); - } - // 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 read_ptr_sized_unsigned(&self, ptr: MemoryPointer) -> EvalResult<'tcx, PrimVal> { - self.read_primval(ptr, self.pointer_size(), false) - } - - 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()); - val.offset as u128 - } - - PrimVal::Bytes(bytes) => { - // We need to mask here, or the byteorder crate can die when given a u64 larger - // than fits in an integer of the requested size. - let mask = match size { - 1 => !0u8 as u128, - 2 => !0u16 as u128, - 4 => !0u32 as u128, - 8 => !0u64 as u128, - 16 => !0, - n => bug!("unexpected PrimVal::Bytes size: {}", n), - }; - bytes & mask - } - - PrimVal::Undef => { - self.mark_definedness(PrimVal::Ptr(ptr).into(), size, false)?; - return Ok(()); - } - }; - - { - 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(); - } - } - - // 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, - ); - } - _ => {} - } - - Ok(()) - } - - 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) - } - - 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), - } - } -} - -/// Relocations -impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> { - fn relocations( - &self, - ptr: MemoryPointer, - size: u64, - ) -> EvalResult<'tcx, btree_map::Range> { - let start = ptr.offset.saturating_sub(self.pointer_size() - 1); - let end = ptr.offset + size; - Ok(self.get(ptr.alloc_id)?.relocations.range(start..end)) - } - - fn clear_relocations(&mut self, ptr: MemoryPointer, size: u64) -> EvalResult<'tcx> { - // Find all relocations overlapping the given range. - let keys: Vec<_> = self.relocations(ptr, size)?.map(|(&k, _)| k).collect(); - if keys.is_empty() { - return Ok(()); - } - - // Find the start and end of the given range and its outermost relocations. - let start = ptr.offset; - let end = start + size; - let first = *keys.first().unwrap(); - let last = *keys.last().unwrap() + self.pointer_size(); - - let alloc = self.get_mut(ptr.alloc_id)?; - - // Mark parts of the outermost relocations as undefined if they partially fall outside the - // given range. - if first < start { - alloc.undef_mask.set_range(first, start, false); - } - if last > end { - alloc.undef_mask.set_range(end, last, false); - } - - // Forget all the relocations. - for k in keys { - alloc.relocations.remove(&k); - } - - Ok(()) - } - - fn check_relocation_edges(&self, ptr: MemoryPointer, size: u64) -> EvalResult<'tcx> { - let overlapping_start = self.relocations(ptr, 0)?.count(); - let overlapping_end = self.relocations(ptr.offset(size, self.layout)?, 0)?.count(); - if overlapping_start + overlapping_end != 0 { - return err!(ReadPointerAsBytes); - } - Ok(()) - } -} - -/// Undefined bytes -impl<'a, 'tcx, M: Machine<'tcx>> Memory<'a, 'tcx, M> { - // FIXME(solson): This is a very naive, slow version. - fn copy_undef_mask( - &mut self, - src: MemoryPointer, - dest: MemoryPointer, - size: u64, - ) -> EvalResult<'tcx> { - // The bits have to be saved locally before writing to dest in case src and dest overlap. - assert_eq!(size as usize as u64, size); - let mut v = Vec::with_capacity(size as usize); - for i in 0..size { - let defined = self.get(src.alloc_id)?.undef_mask.get(src.offset + i); - v.push(defined); - } - for (i, defined) in v.into_iter().enumerate() { - self.get_mut(dest.alloc_id)?.undef_mask.set( - dest.offset + - i as u64, - defined, - ); - } - Ok(()) - } - - fn check_defined(&self, ptr: MemoryPointer, size: u64) -> EvalResult<'tcx> { - let alloc = self.get(ptr.alloc_id)?; - if !alloc.undef_mask.is_range_defined( - ptr.offset, - ptr.offset + size, - ) - { - return err!(ReadUndefBytes); - } - Ok(()) - } - - pub fn mark_definedness( - &mut self, - ptr: Pointer, - size: u64, - new_state: bool, - ) -> EvalResult<'tcx> { - if size == 0 { - return Ok(()); - } - let ptr = ptr.to_ptr()?; - let alloc = self.get_mut(ptr.alloc_id)?; - alloc.undef_mask.set_range( - ptr.offset, - ptr.offset + size, - new_state, - ); - Ok(()) - } -} - -//////////////////////////////////////////////////////////////////////////////// -// Methods to access integers in the target endianess -//////////////////////////////////////////////////////////////////////////////// - -fn write_target_uint( - endianess: layout::Endian, - mut target: &mut [u8], - data: u128, -) -> Result<(), io::Error> { - let len = target.len(); - match endianess { - layout::Endian::Little => target.write_uint128::(data, len), - layout::Endian::Big => target.write_uint128::(data, len), - } -} -fn write_target_int( - endianess: layout::Endian, - mut target: &mut [u8], - data: i128, -) -> Result<(), io::Error> { - let len = target.len(); - match endianess { - layout::Endian::Little => target.write_int128::(data, len), - layout::Endian::Big => target.write_int128::(data, len), - } -} - -fn read_target_uint(endianess: layout::Endian, mut source: &[u8]) -> Result { - match endianess { - layout::Endian::Little => source.read_uint128::(source.len()), - layout::Endian::Big => source.read_uint128::(source.len()), - } -} - -fn read_target_int(endianess: layout::Endian, mut source: &[u8]) -> Result { - match endianess { - layout::Endian::Little => source.read_int128::(source.len()), - layout::Endian::Big => source.read_int128::(source.len()), - } -} - -//////////////////////////////////////////////////////////////////////////////// -// Undefined byte tracking -//////////////////////////////////////////////////////////////////////////////// - -type Block = u64; -const BLOCK_SIZE: u64 = 64; - -#[derive(Clone, Debug)] -pub struct UndefMask { - blocks: Vec, - len: u64, -} - -impl UndefMask { - fn new(size: u64) -> Self { - let mut m = UndefMask { - blocks: vec![], - len: 0, - }; - m.grow(size, false); - m - } - - /// Check whether the range `start..end` (end-exclusive) is entirely defined. - pub fn is_range_defined(&self, start: u64, end: u64) -> bool { - if end > self.len { - return false; - } - for i in start..end { - if !self.get(i) { - return false; - } - } - true - } - - fn set_range(&mut self, start: u64, end: u64, new_state: bool) { - let len = self.len; - if end > len { - self.grow(end - len, new_state); - } - self.set_range_inbounds(start, end, new_state); - } - - fn set_range_inbounds(&mut self, start: u64, end: u64, new_state: bool) { - for i in start..end { - self.set(i, new_state); - } - } - - fn get(&self, i: u64) -> bool { - let (block, bit) = bit_index(i); - (self.blocks[block] & 1 << bit) != 0 - } - - fn set(&mut self, i: u64, new_state: bool) { - let (block, bit) = bit_index(i); - if new_state { - self.blocks[block] |= 1 << bit; - } else { - self.blocks[block] &= !(1 << bit); - } - } - - fn grow(&mut self, amount: u64, new_state: bool) { - let unused_trailing_bits = self.blocks.len() as u64 * BLOCK_SIZE - self.len; - if amount > unused_trailing_bits { - let additional_blocks = amount / BLOCK_SIZE + 1; - assert_eq!(additional_blocks as usize as u64, additional_blocks); - self.blocks.extend( - iter::repeat(0).take(additional_blocks as usize), - ); - } - let start = self.len; - self.len += amount; - self.set_range_inbounds(start, start + amount, new_state); - } -} - -fn bit_index(bits: u64) -> (usize, usize) { - let a = bits / BLOCK_SIZE; - let b = bits % BLOCK_SIZE; - assert_eq!(a as usize as u64, a); - assert_eq!(b as usize as u64, b); - (a as usize, b as usize) -} - -//////////////////////////////////////////////////////////////////////////////// -// Unaligned accesses -//////////////////////////////////////////////////////////////////////////////// - -pub trait HasMemory<'a, 'tcx, M: Machine<'tcx>> { - fn memory_mut(&mut self) -> &mut Memory<'a, 'tcx, M>; - fn memory(&self) -> &Memory<'a, 'tcx, M>; - - // These are not supposed to be overriden. - fn read_maybe_aligned(&self, aligned: bool, f: F) -> EvalResult<'tcx, T> - where - F: FnOnce(&Self) -> EvalResult<'tcx, T>, - { - let old = self.memory().reads_are_aligned.get(); - // Do alignment checking if *all* nested calls say it has to be aligned. - self.memory().reads_are_aligned.set(old && aligned); - let t = f(self); - self.memory().reads_are_aligned.set(old); - t - } - - fn read_maybe_aligned_mut(&mut self, aligned: bool, f: F) -> EvalResult<'tcx, T> - where - F: FnOnce(&mut Self) -> EvalResult<'tcx, T>, - { - let old = self.memory().reads_are_aligned.get(); - // Do alignment checking if *all* nested calls say it has to be aligned. - self.memory().reads_are_aligned.set(old && aligned); - let t = f(self); - self.memory().reads_are_aligned.set(old); - t - } - - fn write_maybe_aligned_mut(&mut self, aligned: bool, f: F) -> EvalResult<'tcx, T> - where - F: FnOnce(&mut Self) -> EvalResult<'tcx, T>, - { - let old = self.memory().writes_are_aligned.get(); - // Do alignment checking if *all* nested calls say it has to be aligned. - self.memory().writes_are_aligned.set(old && aligned); - let t = f(self); - self.memory().writes_are_aligned.set(old); - t - } -} - -impl<'a, 'tcx, M: Machine<'tcx>> HasMemory<'a, 'tcx, M> for Memory<'a, 'tcx, M> { - #[inline] - fn memory_mut(&mut self) -> &mut Memory<'a, 'tcx, M> { - self - } - - #[inline] - fn memory(&self) -> &Memory<'a, 'tcx, M> { - self - } -} - -impl<'a, 'tcx, M: Machine<'tcx>> HasMemory<'a, 'tcx, M> for EvalContext<'a, 'tcx, M> { - #[inline] - fn memory_mut(&mut self) -> &mut Memory<'a, 'tcx, M> { - &mut self.memory - } - - #[inline] - fn memory(&self) -> &Memory<'a, 'tcx, M> { - &self.memory - } -} - -//////////////////////////////////////////////////////////////////////////////// -// Pointer arithmetic -//////////////////////////////////////////////////////////////////////////////// - -pub trait PointerArithmetic: layout::HasDataLayout { - // These are not supposed to be overriden. - - //// Trunace the given value to the pointer size; also return whether there was an overflow - fn truncate_to_ptr(self, val: u128) -> (u64, bool) { - let max_ptr_plus_1 = 1u128 << self.data_layout().pointer_size.bits(); - ((val % max_ptr_plus_1) as u64, val >= max_ptr_plus_1) - } - - // Overflow checking only works properly on the range from -u64 to +u64. - fn overflowing_signed_offset(self, val: u64, i: i128) -> (u64, bool) { - // FIXME: is it possible to over/underflow here? - if i < 0 { - // trickery to ensure that i64::min_value() works fine - // this formula only works for true negative values, it panics for zero! - let n = u64::max_value() - (i as u64) + 1; - val.overflowing_sub(n) - } else { - self.overflowing_offset(val, i as u64) - } - } - - fn overflowing_offset(self, val: u64, i: u64) -> (u64, bool) { - let (res, over1) = val.overflowing_add(i); - let (res, over2) = self.truncate_to_ptr(res as u128); - (res, over1 || over2) - } - - fn signed_offset<'tcx>(self, val: u64, i: i64) -> EvalResult<'tcx, u64> { - let (res, over) = self.overflowing_signed_offset(val, i as i128); - if over { err!(OverflowingMath) } else { Ok(res) } - } - - fn offset<'tcx>(self, val: u64, i: u64) -> EvalResult<'tcx, u64> { - let (res, over) = self.overflowing_offset(val, i); - if over { err!(OverflowingMath) } else { Ok(res) } - } - - fn wrapping_signed_offset(self, val: u64, i: i64) -> u64 { - self.overflowing_signed_offset(val, i as i128).0 - } -} - -impl PointerArithmetic for T {} - -impl<'a, 'tcx, M: Machine<'tcx>> layout::HasDataLayout for &'a Memory<'a, 'tcx, M> { - #[inline] - fn data_layout(&self) -> &TargetDataLayout { - self.layout - } -} -impl<'a, 'tcx, M: Machine<'tcx>> layout::HasDataLayout for &'a EvalContext<'a, 'tcx, M> { - #[inline] - fn data_layout(&self) -> &TargetDataLayout { - self.memory().layout - } -} - -impl<'c, 'b, 'a, 'tcx, M: Machine<'tcx>> layout::HasDataLayout - for &'c &'b mut EvalContext<'a, 'tcx, M> { - #[inline] - fn data_layout(&self) -> &TargetDataLayout { - self.memory().layout - } -} diff --git a/src/librustc_mir/interpret/mod.rs b/src/librustc_mir/interpret/mod.rs deleted file mode 100644 index 08837c4fb6d78..0000000000000 --- a/src/librustc_mir/interpret/mod.rs +++ /dev/null @@ -1,42 +0,0 @@ -//! An interpreter for MIR used in CTFE and by miri - -#[macro_export] -macro_rules! err { - ($($tt:tt)*) => { Err($crate::interpret::EvalErrorKind::$($tt)*.into()) }; -} - -mod cast; -mod const_eval; -mod error; -mod eval_context; -mod lvalue; -mod validation; -mod machine; -mod memory; -mod operator; -mod range_map; -mod step; -mod terminator; -mod traits; -mod value; - -pub use self::error::{EvalError, EvalResult, EvalErrorKind}; - -pub use self::eval_context::{EvalContext, Frame, ResourceLimits, StackPopCleanup, DynamicLifetime, - TyAndPacked, PtrAndAlign, ValTy}; - -pub use self::lvalue::{Lvalue, LvalueExtra, GlobalId}; - -pub use self::memory::{AllocId, Memory, MemoryPointer, MemoryKind, HasMemory, AccessKind, AllocIdKind}; - -use self::memory::{PointerArithmetic, Lock}; - -use self::range_map::RangeMap; - -pub use self::value::{PrimVal, PrimValKind, Value, Pointer}; - -pub use self::const_eval::{eval_body_as_integer, eval_body_as_primval}; - -pub use self::machine::Machine; - -pub use self::validation::{ValidationQuery, AbsLvalue}; diff --git a/src/librustc_mir/interpret/operator.rs b/src/librustc_mir/interpret/operator.rs deleted file mode 100644 index 7fe4691ffff0c..0000000000000 --- a/src/librustc_mir/interpret/operator.rs +++ /dev/null @@ -1,268 +0,0 @@ -use rustc::mir; -use rustc::ty::Ty; -use rustc_const_math::ConstFloat; -use syntax::ast::FloatTy; -use std::cmp::Ordering; - -use super::{EvalResult, EvalContext, Lvalue, Machine, ValTy}; - -use super::value::{PrimVal, PrimValKind, Value, bytes_to_f32, bytes_to_f64, f32_to_bytes, - f64_to_bytes}; - -impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { - fn binop_with_overflow( - &mut self, - op: mir::BinOp, - left: ValTy<'tcx>, - right: ValTy<'tcx>, - ) -> EvalResult<'tcx, (PrimVal, bool)> { - let left_val = self.value_to_primval(left)?; - let right_val = self.value_to_primval(right)?; - self.binary_op(op, left_val, left.ty, right_val, right.ty) - } - - /// Applies the binary operation `op` to the two operands and writes a tuple of the result - /// and a boolean signifying the potential overflow to the destination. - pub fn intrinsic_with_overflow( - &mut self, - op: mir::BinOp, - left: ValTy<'tcx>, - right: ValTy<'tcx>, - dest: Lvalue, - dest_ty: Ty<'tcx>, - ) -> EvalResult<'tcx> { - let (val, overflowed) = self.binop_with_overflow(op, left, right)?; - let val = Value::ByValPair(val, PrimVal::from_bool(overflowed)); - let valty = ValTy { - value: val, - ty: dest_ty, - }; - self.write_value(valty, dest) - } - - /// Applies the binary operation `op` to the arguments and writes the result to the - /// destination. Returns `true` if the operation overflowed. - pub fn intrinsic_overflowing( - &mut self, - op: mir::BinOp, - left: ValTy<'tcx>, - right: ValTy<'tcx>, - dest: Lvalue, - dest_ty: Ty<'tcx>, - ) -> EvalResult<'tcx, bool> { - let (val, overflowed) = self.binop_with_overflow(op, left, right)?; - self.write_primval(dest, val, dest_ty)?; - Ok(overflowed) - } -} - -macro_rules! overflow { - ($op:ident, $l:expr, $r:expr) => ({ - let (val, overflowed) = $l.$op($r); - let primval = PrimVal::Bytes(val as u128); - Ok((primval, overflowed)) - }) -} - -macro_rules! int_arithmetic { - ($kind:expr, $int_op:ident, $l:expr, $r:expr) => ({ - let l = $l; - let r = $r; - use super::PrimValKind::*; - match $kind { - I8 => overflow!($int_op, l as i8, r as i8), - I16 => overflow!($int_op, l as i16, r as i16), - I32 => overflow!($int_op, l as i32, r as i32), - I64 => overflow!($int_op, l as i64, r as i64), - I128 => overflow!($int_op, l as i128, r as i128), - U8 => overflow!($int_op, l as u8, r as u8), - U16 => overflow!($int_op, l as u16, r as u16), - U32 => overflow!($int_op, l as u32, r as u32), - U64 => overflow!($int_op, l as u64, r as u64), - U128 => overflow!($int_op, l as u128, r as u128), - _ => bug!("int_arithmetic should only be called on int primvals"), - } - }) -} - -macro_rules! int_shift { - ($kind:expr, $int_op:ident, $l:expr, $r:expr) => ({ - let l = $l; - let r = $r; - let r_wrapped = r as u32; - match $kind { - I8 => overflow!($int_op, l as i8, r_wrapped), - I16 => overflow!($int_op, l as i16, r_wrapped), - I32 => overflow!($int_op, l as i32, r_wrapped), - I64 => overflow!($int_op, l as i64, r_wrapped), - I128 => overflow!($int_op, l as i128, r_wrapped), - U8 => overflow!($int_op, l as u8, r_wrapped), - U16 => overflow!($int_op, l as u16, r_wrapped), - U32 => overflow!($int_op, l as u32, r_wrapped), - U64 => overflow!($int_op, l as u64, r_wrapped), - U128 => overflow!($int_op, l as u128, r_wrapped), - _ => bug!("int_shift should only be called on int primvals"), - }.map(|(val, over)| (val, over || r != r_wrapped as u128)) - }) -} - -impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { - /// Returns the result of the specified operation and whether it overflowed. - pub fn binary_op( - &self, - bin_op: mir::BinOp, - left: PrimVal, - left_ty: Ty<'tcx>, - right: PrimVal, - right_ty: Ty<'tcx>, - ) -> EvalResult<'tcx, (PrimVal, bool)> { - use rustc::mir::BinOp::*; - use super::PrimValKind::*; - - let left_kind = self.ty_to_primval_kind(left_ty)?; - let right_kind = self.ty_to_primval_kind(right_ty)?; - //trace!("Running binary op {:?}: {:?} ({:?}), {:?} ({:?})", bin_op, left, left_kind, right, right_kind); - - // I: Handle operations that support pointers - if !left_kind.is_float() && !right_kind.is_float() { - if let Some(handled) = M::try_ptr_op(self, bin_op, left, left_ty, right, right_ty)? { - return Ok(handled); - } - } - - // II: From now on, everything must be bytes, no pointers - let l = left.to_bytes()?; - let r = right.to_bytes()?; - - // These ops can have an RHS with a different numeric type. - if right_kind.is_int() && (bin_op == Shl || bin_op == Shr) { - return match bin_op { - Shl => int_shift!(left_kind, overflowing_shl, l, r), - Shr => int_shift!(left_kind, overflowing_shr, l, r), - _ => bug!("it has already been checked that this is a shift op"), - }; - } - - if left_kind != right_kind { - let msg = format!( - "unimplemented binary op {:?}: {:?} ({:?}), {:?} ({:?})", - bin_op, - left, - left_kind, - right, - right_kind - ); - return err!(Unimplemented(msg)); - } - - let float_op = |op, l, r, ty| { - let l = ConstFloat { - bits: l, - ty, - }; - let r = ConstFloat { - bits: r, - ty, - }; - match op { - Eq => PrimVal::from_bool(l.try_cmp(r).unwrap() == Ordering::Equal), - Ne => PrimVal::from_bool(l.try_cmp(r).unwrap() != Ordering::Equal), - Lt => PrimVal::from_bool(l.try_cmp(r).unwrap() == Ordering::Less), - Le => PrimVal::from_bool(l.try_cmp(r).unwrap() != Ordering::Greater), - Gt => PrimVal::from_bool(l.try_cmp(r).unwrap() == Ordering::Greater), - Ge => PrimVal::from_bool(l.try_cmp(r).unwrap() != Ordering::Less), - Add => PrimVal::Bytes((l + r).unwrap().bits), - Sub => PrimVal::Bytes((l - r).unwrap().bits), - Mul => PrimVal::Bytes((l * r).unwrap().bits), - Div => PrimVal::Bytes((l / r).unwrap().bits), - Rem => PrimVal::Bytes((l % r).unwrap().bits), - _ => bug!("invalid float op: `{:?}`", op), - } - }; - - let val = match (bin_op, left_kind) { - (_, F32) => float_op(bin_op, l, r, FloatTy::F32), - (_, F64) => float_op(bin_op, l, r, FloatTy::F64), - - - (Eq, _) => PrimVal::from_bool(l == r), - (Ne, _) => PrimVal::from_bool(l != r), - - (Lt, k) if k.is_signed_int() => PrimVal::from_bool((l as i128) < (r as i128)), - (Lt, _) => PrimVal::from_bool(l < r), - (Le, k) if k.is_signed_int() => PrimVal::from_bool((l as i128) <= (r as i128)), - (Le, _) => PrimVal::from_bool(l <= r), - (Gt, k) if k.is_signed_int() => PrimVal::from_bool((l as i128) > (r as i128)), - (Gt, _) => PrimVal::from_bool(l > r), - (Ge, k) if k.is_signed_int() => PrimVal::from_bool((l as i128) >= (r as i128)), - (Ge, _) => PrimVal::from_bool(l >= r), - - (BitOr, _) => PrimVal::Bytes(l | r), - (BitAnd, _) => PrimVal::Bytes(l & r), - (BitXor, _) => PrimVal::Bytes(l ^ r), - - (Add, k) if k.is_int() => return int_arithmetic!(k, overflowing_add, l, r), - (Sub, k) if k.is_int() => return int_arithmetic!(k, overflowing_sub, l, r), - (Mul, k) if k.is_int() => return int_arithmetic!(k, overflowing_mul, l, r), - (Div, k) if k.is_int() => return int_arithmetic!(k, overflowing_div, l, r), - (Rem, k) if k.is_int() => return int_arithmetic!(k, overflowing_rem, l, r), - - _ => { - let msg = format!( - "unimplemented binary op {:?}: {:?} ({:?}), {:?} ({:?})", - bin_op, - left, - left_kind, - right, - right_kind - ); - return err!(Unimplemented(msg)); - } - }; - - Ok((val, false)) - } -} - -pub fn unary_op<'tcx>( - un_op: mir::UnOp, - val: PrimVal, - val_kind: PrimValKind, -) -> EvalResult<'tcx, PrimVal> { - use rustc::mir::UnOp::*; - use super::PrimValKind::*; - - let bytes = val.to_bytes()?; - - let result_bytes = match (un_op, val_kind) { - (Not, Bool) => !val.to_bool()? as u128, - - (Not, U8) => !(bytes as u8) as u128, - (Not, U16) => !(bytes as u16) as u128, - (Not, U32) => !(bytes as u32) as u128, - (Not, U64) => !(bytes as u64) as u128, - (Not, U128) => !bytes, - - (Not, I8) => !(bytes as i8) as u128, - (Not, I16) => !(bytes as i16) as u128, - (Not, I32) => !(bytes as i32) as u128, - (Not, I64) => !(bytes as i64) as u128, - (Not, I128) => !(bytes as i128) as u128, - - (Neg, I8) => -(bytes as i8) as u128, - (Neg, I16) => -(bytes as i16) as u128, - (Neg, I32) => -(bytes as i32) as u128, - (Neg, I64) => -(bytes as i64) as u128, - (Neg, I128) => -(bytes as i128) as u128, - - (Neg, F32) => f32_to_bytes(-bytes_to_f32(bytes)), - (Neg, F64) => f64_to_bytes(-bytes_to_f64(bytes)), - - _ => { - let msg = format!("unimplemented unary op: {:?}, {:?}", un_op, val); - return err!(Unimplemented(msg)); - } - }; - - Ok(PrimVal::Bytes(result_bytes)) -} diff --git a/src/librustc_mir/interpret/range_map.rs b/src/librustc_mir/interpret/range_map.rs deleted file mode 100644 index 5cdcbe35121a5..0000000000000 --- a/src/librustc_mir/interpret/range_map.rs +++ /dev/null @@ -1,250 +0,0 @@ -//! Implements a map from integer indices to data. -//! Rather than storing data for every index, internally, this maps entire ranges to the data. -//! To this end, the APIs all work on ranges, not on individual integers. Ranges are split as -//! necessary (e.g. when [0,5) is first associated with X, and then [1,2) is mutated). -//! Users must not depend on whether a range is coalesced or not, even though this is observable -//! via the iteration APIs. -use std::collections::BTreeMap; -use std::ops; - -#[derive(Clone, Debug)] -pub struct RangeMap { - map: BTreeMap, -} - -// The derived `Ord` impl sorts first by the first field, then, if the fields are the same, -// by the second field. -// This is exactly what we need for our purposes, since a range query on a BTReeSet/BTreeMap will give us all -// `MemoryRange`s whose `start` is <= than the one we're looking for, but not > the end of the range we're checking. -// At the same time the `end` is irrelevant for the sorting and range searching, but used for the check. -// This kind of search breaks, if `end < start`, so don't do that! -#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Debug)] -struct Range { - start: u64, - end: u64, // Invariant: end > start -} - -impl Range { - fn range(offset: u64, len: u64) -> ops::Range { - assert!(len > 0); - // We select all elements that are within - // the range given by the offset into the allocation and the length. - // This is sound if all ranges that intersect with the argument range, are in the - // resulting range of ranges. - let left = Range { - // lowest range to include `offset` - start: 0, - end: offset + 1, - }; - let right = Range { - // lowest (valid) range not to include `offset+len` - start: offset + len, - end: offset + len + 1, - }; - left..right - } - - /// Tests if all of [offset, offset+len) are contained in this range. - fn overlaps(&self, offset: u64, len: u64) -> bool { - assert!(len > 0); - offset < self.end && offset + len >= self.start - } -} - -impl RangeMap { - pub fn new() -> RangeMap { - RangeMap { map: BTreeMap::new() } - } - - fn iter_with_range<'a>( - &'a self, - offset: u64, - len: u64, - ) -> impl Iterator + 'a { - assert!(len > 0); - self.map.range(Range::range(offset, len)).filter_map( - move |(range, - data)| { - if range.overlaps(offset, len) { - Some((range, data)) - } else { - None - } - }, - ) - } - - pub fn iter<'a>(&'a self, offset: u64, len: u64) -> impl Iterator + 'a { - self.iter_with_range(offset, len).map(|(_, data)| data) - } - - fn split_entry_at(&mut self, offset: u64) - where - T: Clone, - { - let range = match self.iter_with_range(offset, 1).next() { - Some((&range, _)) => range, - None => return, - }; - assert!( - range.start <= offset && range.end > offset, - "We got a range that doesn't even contain what we asked for." - ); - // There is an entry overlapping this position, see if we have to split it - if range.start < offset { - let data = self.map.remove(&range).unwrap(); - let old = self.map.insert( - Range { - start: range.start, - end: offset, - }, - data.clone(), - ); - assert!(old.is_none()); - let old = self.map.insert( - Range { - start: offset, - end: range.end, - }, - data, - ); - assert!(old.is_none()); - } - } - - pub fn iter_mut_all<'a>(&'a mut self) -> impl Iterator + 'a { - self.map.values_mut() - } - - /// Provide mutable iteration over everything in the given range. As a side-effect, - /// this will split entries in the map that are only partially hit by the given range, - /// to make sure that when they are mutated, the effect is constrained to the given range. - pub fn iter_mut_with_gaps<'a>( - &'a mut self, - offset: u64, - len: u64, - ) -> impl Iterator + 'a - where - T: Clone, - { - assert!(len > 0); - // Preparation: Split first and last entry as needed. - self.split_entry_at(offset); - self.split_entry_at(offset + len); - // Now we can provide a mutable iterator - self.map.range_mut(Range::range(offset, len)).filter_map( - move |(&range, data)| { - if range.overlaps(offset, len) { - assert!( - offset <= range.start && offset + len >= range.end, - "The splitting went wrong" - ); - Some(data) - } else { - // Skip this one - None - } - }, - ) - } - - /// Provide a mutable iterator over everything in the given range, with the same side-effects as - /// iter_mut_with_gaps. Furthermore, if there are gaps between ranges, fill them with the given default. - /// This is also how you insert. - pub fn iter_mut<'a>(&'a mut self, offset: u64, len: u64) -> impl Iterator + 'a - where - T: Clone + Default, - { - // Do a first iteration to collect the gaps - let mut gaps = Vec::new(); - let mut last_end = offset; - for (range, _) in self.iter_with_range(offset, len) { - if last_end < range.start { - gaps.push(Range { - start: last_end, - end: range.start, - }); - } - last_end = range.end; - } - if last_end < offset + len { - gaps.push(Range { - start: last_end, - end: offset + len, - }); - } - - // Add default for all gaps - for gap in gaps { - let old = self.map.insert(gap, Default::default()); - assert!(old.is_none()); - } - - // Now provide mutable iteration - self.iter_mut_with_gaps(offset, len) - } - - pub fn retain(&mut self, mut f: F) - where - F: FnMut(&T) -> bool, - { - let mut remove = Vec::new(); - for (range, data) in self.map.iter() { - if !f(data) { - remove.push(*range); - } - } - - for range in remove { - self.map.remove(&range); - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - - /// Query the map at every offset in the range and collect the results. - fn to_vec(map: &RangeMap, offset: u64, len: u64) -> Vec { - (offset..offset + len) - .into_iter() - .map(|i| *map.iter(i, 1).next().unwrap()) - .collect() - } - - #[test] - fn basic_insert() { - let mut map = RangeMap::::new(); - // Insert - for x in map.iter_mut(10, 1) { - *x = 42; - } - // Check - assert_eq!(to_vec(&map, 10, 1), vec![42]); - } - - #[test] - fn gaps() { - let mut map = RangeMap::::new(); - for x in map.iter_mut(11, 1) { - *x = 42; - } - for x in map.iter_mut(15, 1) { - *x = 42; - } - - // Now request a range that needs three gaps filled - for x in map.iter_mut(10, 10) { - if *x != 42 { - *x = 23; - } - } - - assert_eq!( - to_vec(&map, 10, 10), - vec![23, 42, 23, 23, 23, 42, 23, 23, 23, 23] - ); - assert_eq!(to_vec(&map, 13, 5), vec![23, 23, 42, 23, 23]); - } -} diff --git a/src/librustc_mir/interpret/step.rs b/src/librustc_mir/interpret/step.rs deleted file mode 100644 index c701ebfbf4c75..0000000000000 --- a/src/librustc_mir/interpret/step.rs +++ /dev/null @@ -1,402 +0,0 @@ -//! This module contains the `EvalContext` methods for executing a single step of the interpreter. -//! -//! The main entry point is the `step` method. - -use rustc::hir::def_id::DefId; -use rustc::hir; -use rustc::mir::visit::{Visitor, LvalueContext}; -use rustc::mir; -use rustc::traits::Reveal; -use rustc::ty; -use rustc::ty::layout::Layout; -use rustc::ty::subst::Substs; -use rustc::middle::const_val::ConstVal; - -use super::{EvalResult, EvalContext, StackPopCleanup, PtrAndAlign, GlobalId, Lvalue, - MemoryKind, Machine, PrimVal}; - -use syntax::codemap::Span; -use syntax::ast::Mutability; - -impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { - pub fn inc_step_counter_and_check_limit(&mut self, n: u64) -> EvalResult<'tcx> { - self.steps_remaining = self.steps_remaining.saturating_sub(n); - if self.steps_remaining > 0 { - Ok(()) - } else { - err!(ExecutionTimeLimitReached) - } - } - - /// Returns true as long as there are more things to do. - pub fn step(&mut self) -> EvalResult<'tcx, bool> { - self.inc_step_counter_and_check_limit(1)?; - if self.stack.is_empty() { - return Ok(false); - } - - let block = self.frame().block; - let stmt_id = self.frame().stmt; - let mir = self.mir(); - let basic_block = &mir.basic_blocks()[block]; - - if let Some(stmt) = basic_block.statements.get(stmt_id) { - let mut new = Ok(0); - ConstantExtractor { - span: stmt.source_info.span, - instance: self.frame().instance, - ecx: self, - mir, - new_constants: &mut new, - }.visit_statement( - block, - stmt, - mir::Location { - block, - statement_index: stmt_id, - }, - ); - // if ConstantExtractor added new frames, we don't execute anything here - // but await the next call to step - if new? == 0 { - self.statement(stmt)?; - } - return Ok(true); - } - - let terminator = basic_block.terminator(); - let mut new = Ok(0); - ConstantExtractor { - span: terminator.source_info.span, - instance: self.frame().instance, - ecx: self, - mir, - new_constants: &mut new, - }.visit_terminator( - block, - terminator, - mir::Location { - block, - statement_index: stmt_id, - }, - ); - // if ConstantExtractor added new frames, we don't execute anything here - // but await the next call to step - if new? == 0 { - self.terminator(terminator)?; - } - Ok(true) - } - - fn statement(&mut self, stmt: &mir::Statement<'tcx>) -> EvalResult<'tcx> { - trace!("{:?}", stmt); - - use rustc::mir::StatementKind::*; - - // Some statements (e.g. box) push new stack frames. We have to record the stack frame number - // *before* executing the statement. - let frame_idx = self.cur_frame(); - - match stmt.kind { - Assign(ref lvalue, ref rvalue) => self.eval_rvalue_into_lvalue(rvalue, lvalue)?, - - SetDiscriminant { - ref lvalue, - variant_index, - } => { - let dest = self.eval_lvalue(lvalue)?; - let dest_ty = self.lvalue_ty(lvalue); - let dest_layout = self.type_layout(dest_ty)?; - - match *dest_layout { - Layout::General { discr, .. } => { - let discr_size = discr.size().bytes(); - let dest_ptr = self.force_allocation(dest)?.to_ptr()?; - self.memory.write_primval( - dest_ptr, - PrimVal::Bytes(variant_index as u128), - discr_size, - false - )? - } - - Layout::RawNullablePointer { nndiscr, .. } => { - if variant_index as u64 != nndiscr { - self.write_null(dest, dest_ty)?; - } - } - - Layout::StructWrappedNullablePointer { - nndiscr, - ref discrfield_source, - .. - } => { - if variant_index as u64 != nndiscr { - self.write_struct_wrapped_null_pointer( - dest_ty, - nndiscr, - discrfield_source, - dest, - )?; - } - } - - _ => { - bug!( - "SetDiscriminant on {} represented as {:#?}", - dest_ty, - dest_layout - ) - } - } - } - - // Mark locals as alive - StorageLive(local) => { - let old_val = self.frame_mut().storage_live(local)?; - self.deallocate_local(old_val)?; - } - - // Mark locals as dead - StorageDead(local) => { - let old_val = self.frame_mut().storage_dead(local)?; - self.deallocate_local(old_val)?; - } - - // Validity checks. - Validate(op, ref lvalues) => { - for operand in lvalues { - self.validation_op(op, operand)?; - } - } - EndRegion(ce) => { - self.end_region(Some(ce))?; - } - - // Defined to do nothing. These are added by optimization passes, to avoid changing the - // size of MIR constantly. - Nop => {} - - InlineAsm { .. } => return err!(InlineAsm), - } - - self.stack[frame_idx].stmt += 1; - Ok(()) - } - - fn terminator(&mut self, terminator: &mir::Terminator<'tcx>) -> EvalResult<'tcx> { - trace!("{:?}", terminator.kind); - self.eval_terminator(terminator)?; - if !self.stack.is_empty() { - trace!("// {:?}", self.frame().block); - } - Ok(()) - } - - /// returns `true` if a stackframe was pushed - fn global_item( - &mut self, - def_id: DefId, - substs: &'tcx Substs<'tcx>, - span: Span, - mutability: Mutability, - ) -> EvalResult<'tcx, bool> { - let instance = self.resolve_associated_const(def_id, substs); - let cid = GlobalId { - instance, - promoted: None, - }; - if self.globals.contains_key(&cid) { - return Ok(false); - } - if self.tcx.has_attr(def_id, "linkage") { - M::global_item_with_linkage(self, cid.instance, mutability)?; - return Ok(false); - } - let mir = self.load_mir(instance.def)?; - let size = self.type_size_with_substs(mir.return_ty, substs)?.expect( - "unsized global", - ); - let align = self.type_align_with_substs(mir.return_ty, substs)?; - let ptr = self.memory.allocate( - size, - align, - MemoryKind::UninitializedStatic, - )?; - let aligned = !self.is_packed(mir.return_ty)?; - self.globals.insert( - cid, - PtrAndAlign { - ptr: ptr.into(), - aligned, - }, - ); - let internally_mutable = !mir.return_ty.is_freeze( - self.tcx, - ty::ParamEnv::empty(Reveal::All), - span, - ); - let mutability = if mutability == Mutability::Mutable || internally_mutable { - Mutability::Mutable - } else { - Mutability::Immutable - }; - let cleanup = StackPopCleanup::MarkStatic(mutability); - let name = ty::tls::with(|tcx| tcx.item_path_str(def_id)); - trace!("pushing stack frame for global: {}", name); - self.push_stack_frame( - instance, - span, - mir, - Lvalue::from_ptr(ptr), - cleanup, - )?; - Ok(true) - } -} - -// WARNING: This code pushes new stack frames. Make sure that any methods implemented on this -// type don't ever access ecx.stack[ecx.cur_frame()], as that will change. This includes, e.g., -// using the current stack frame's substitution. -// Basically don't call anything other than `load_mir`, `alloc_ptr`, `push_stack_frame`. -struct ConstantExtractor<'a, 'b: 'a, 'tcx: 'b, M: Machine<'tcx> + 'a> { - span: Span, - ecx: &'a mut EvalContext<'b, 'tcx, M>, - mir: &'tcx mir::Mir<'tcx>, - instance: ty::Instance<'tcx>, - new_constants: &'a mut EvalResult<'tcx, u64>, -} - -impl<'a, 'b, 'tcx, M: Machine<'tcx>> ConstantExtractor<'a, 'b, 'tcx, M> { - fn try EvalResult<'tcx, bool>>(&mut self, f: F) { - // previous constant errored - let n = match *self.new_constants { - Ok(n) => n, - Err(_) => return, - }; - match f(self) { - // everything ok + a new stackframe - Ok(true) => *self.new_constants = Ok(n + 1), - // constant correctly evaluated, but no new stackframe - Ok(false) => {} - // constant eval errored - Err(err) => *self.new_constants = Err(err), - } - } -} - -impl<'a, 'b, 'tcx, M: Machine<'tcx>> Visitor<'tcx> for ConstantExtractor<'a, 'b, 'tcx, M> { - fn visit_constant(&mut self, constant: &mir::Constant<'tcx>, location: mir::Location) { - self.super_constant(constant, location); - match constant.literal { - // already computed by rustc - mir::Literal::Value { value: &ty::Const { val: ConstVal::Unevaluated(def_id, substs), .. } } => { - self.try(|this| { - this.ecx.global_item( - def_id, - substs, - constant.span, - Mutability::Immutable, - ) - }); - } - mir::Literal::Value { .. } => {} - mir::Literal::Promoted { index } => { - let cid = GlobalId { - instance: self.instance, - promoted: Some(index), - }; - if self.ecx.globals.contains_key(&cid) { - return; - } - let mir = &self.mir.promoted[index]; - self.try(|this| { - let size = this.ecx - .type_size_with_substs(mir.return_ty, this.instance.substs)? - .expect("unsized global"); - let align = this.ecx.type_align_with_substs( - mir.return_ty, - this.instance.substs, - )?; - let ptr = this.ecx.memory.allocate( - size, - align, - MemoryKind::UninitializedStatic, - )?; - let aligned = !this.ecx.is_packed(mir.return_ty)?; - this.ecx.globals.insert( - cid, - PtrAndAlign { - ptr: ptr.into(), - aligned, - }, - ); - trace!("pushing stack frame for {:?}", index); - this.ecx.push_stack_frame( - this.instance, - constant.span, - mir, - Lvalue::from_ptr(ptr), - StackPopCleanup::MarkStatic(Mutability::Immutable), - )?; - Ok(true) - }); - } - } - } - - fn visit_lvalue( - &mut self, - lvalue: &mir::Lvalue<'tcx>, - context: LvalueContext<'tcx>, - location: mir::Location, - ) { - self.super_lvalue(lvalue, context, location); - if let mir::Lvalue::Static(ref static_) = *lvalue { - let def_id = static_.def_id; - let substs = self.ecx.tcx.intern_substs(&[]); - let span = self.span; - if let Some(node_item) = self.ecx.tcx.hir.get_if_local(def_id) { - if let hir::map::Node::NodeItem(&hir::Item { ref node, .. }) = node_item { - if let hir::ItemStatic(_, m, _) = *node { - self.try(|this| { - this.ecx.global_item( - def_id, - substs, - span, - if m == hir::MutMutable { - Mutability::Mutable - } else { - Mutability::Immutable - }, - ) - }); - return; - } else { - bug!("static def id doesn't point to static"); - } - } else { - bug!("static def id doesn't point to item"); - } - } else { - let def = self.ecx.tcx.describe_def(def_id).expect("static not found"); - if let hir::def::Def::Static(_, mutable) = def { - self.try(|this| { - this.ecx.global_item( - def_id, - substs, - span, - if mutable { - Mutability::Mutable - } else { - Mutability::Immutable - }, - ) - }); - } else { - bug!("static found but isn't a static: {:?}", def); - } - } - } - } -} diff --git a/src/librustc_mir/interpret/terminator/drop.rs b/src/librustc_mir/interpret/terminator/drop.rs deleted file mode 100644 index 6596cf951fd9e..0000000000000 --- a/src/librustc_mir/interpret/terminator/drop.rs +++ /dev/null @@ -1,83 +0,0 @@ -use rustc::mir::BasicBlock; -use rustc::ty::{self, Ty}; -use syntax::codemap::Span; - -use interpret::{EvalResult, EvalContext, Lvalue, LvalueExtra, PrimVal, Value, - Machine, ValTy}; - -impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { - pub(crate) fn drop_lvalue( - &mut self, - lval: Lvalue, - instance: ty::Instance<'tcx>, - ty: Ty<'tcx>, - span: Span, - target: BasicBlock, - ) -> EvalResult<'tcx> { - trace!("drop_lvalue: {:#?}", lval); - // We take the address of the object. This may well be unaligned, which is fine for us here. - // However, unaligned accesses will probably make the actual drop implementation fail -- a problem shared - // by rustc. - let val = match self.force_allocation(lval)? { - Lvalue::Ptr { - ptr, - extra: LvalueExtra::Vtable(vtable), - } => ptr.ptr.to_value_with_vtable(vtable), - Lvalue::Ptr { - ptr, - extra: LvalueExtra::Length(len), - } => ptr.ptr.to_value_with_len(len), - Lvalue::Ptr { - ptr, - extra: LvalueExtra::None, - } => ptr.ptr.to_value(), - _ => bug!("force_allocation broken"), - }; - self.drop(val, instance, ty, span, target) - } - - fn drop( - &mut self, - arg: Value, - instance: ty::Instance<'tcx>, - ty: Ty<'tcx>, - span: Span, - target: BasicBlock, - ) -> EvalResult<'tcx> { - trace!("drop: {:#?}, {:?}, {:?}", arg, ty.sty, instance.def); - - let instance = match ty.sty { - ty::TyDynamic(..) => { - let vtable = match arg { - Value::ByValPair(_, PrimVal::Ptr(vtable)) => vtable, - _ => bug!("expected fat ptr, got {:?}", arg), - }; - match self.read_drop_type_from_vtable(vtable)? { - Some(func) => func, - // no drop fn -> bail out - None => { - self.goto_block(target); - return Ok(()) - }, - } - } - _ => instance, - }; - - // the drop function expects a reference to the value - let valty = ValTy { - value: arg, - ty: self.tcx.mk_mut_ptr(ty), - }; - - let fn_sig = self.tcx.fn_sig(instance.def_id()).skip_binder().clone(); - - self.eval_fn_call( - instance, - Some((Lvalue::undef(), target)), - &vec![valty], - span, - fn_sig, - ) - } -} diff --git a/src/librustc_mir/interpret/terminator/mod.rs b/src/librustc_mir/interpret/terminator/mod.rs deleted file mode 100644 index e01777cdb4e76..0000000000000 --- a/src/librustc_mir/interpret/terminator/mod.rs +++ /dev/null @@ -1,411 +0,0 @@ -use rustc::mir; -use rustc::ty::{self, TypeVariants}; -use rustc::ty::layout::Layout; -use syntax::codemap::Span; -use syntax::abi::Abi; - -use super::{EvalResult, EvalContext, eval_context, - PtrAndAlign, Lvalue, PrimVal, Value, Machine, ValTy}; - -use rustc_data_structures::indexed_vec::Idx; - -mod drop; - -impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { - pub fn goto_block(&mut self, target: mir::BasicBlock) { - self.frame_mut().block = target; - self.frame_mut().stmt = 0; - } - - pub(super) fn eval_terminator( - &mut self, - terminator: &mir::Terminator<'tcx>, - ) -> EvalResult<'tcx> { - use rustc::mir::TerminatorKind::*; - match terminator.kind { - Return => { - self.dump_local(self.frame().return_lvalue); - self.pop_stack_frame()? - } - - Goto { target } => self.goto_block(target), - - SwitchInt { - ref discr, - ref values, - ref targets, - .. - } => { - // FIXME(CTFE): forbid branching - let discr_val = self.eval_operand(discr)?; - let discr_prim = self.value_to_primval(discr_val)?; - - // Branch to the `otherwise` case by default, if no match is found. - let mut target_block = targets[targets.len() - 1]; - - for (index, const_int) in values.iter().enumerate() { - let prim = PrimVal::Bytes(const_int.to_u128_unchecked()); - if discr_prim.to_bytes()? == prim.to_bytes()? { - target_block = targets[index]; - break; - } - } - - self.goto_block(target_block); - } - - Call { - ref func, - ref args, - ref destination, - .. - } => { - let destination = match *destination { - Some((ref lv, target)) => Some((self.eval_lvalue(lv)?, target)), - None => None, - }; - - let func_ty = self.operand_ty(func); - let (fn_def, sig) = match func_ty.sty { - ty::TyFnPtr(sig) => { - let fn_ptr = self.eval_operand_to_primval(func)?.to_ptr()?; - let instance = self.memory.get_fn(fn_ptr)?; - let instance_ty = instance.def.def_ty(self.tcx); - let instance_ty = self.monomorphize(instance_ty, instance.substs); - match instance_ty.sty { - ty::TyFnDef(..) => { - let real_sig = instance_ty.fn_sig(self.tcx); - let sig = self.tcx.erase_late_bound_regions_and_normalize(&sig); - let real_sig = self.tcx.erase_late_bound_regions_and_normalize(&real_sig); - if !self.check_sig_compat(sig, real_sig)? { - return err!(FunctionPointerTyMismatch(real_sig, sig)); - } - } - ref other => bug!("instance def ty: {:?}", other), - } - (instance, sig) - } - ty::TyFnDef(def_id, substs) => ( - eval_context::resolve(self.tcx, def_id, substs), - func_ty.fn_sig(self.tcx), - ), - _ => { - let msg = format!("can't handle callee of type {:?}", func_ty); - return err!(Unimplemented(msg)); - } - }; - let args = self.operands_to_args(args)?; - let sig = self.tcx.erase_late_bound_regions_and_normalize(&sig); - self.eval_fn_call( - fn_def, - destination, - &args, - terminator.source_info.span, - sig, - )?; - } - - Drop { - ref location, - target, - .. - } => { - // FIXME(CTFE): forbid drop in const eval - let lval = self.eval_lvalue(location)?; - let ty = self.lvalue_ty(location); - let ty = eval_context::apply_param_substs(self.tcx, self.substs(), &ty); - trace!("TerminatorKind::drop: {:?}, type {}", location, ty); - - let instance = eval_context::resolve_drop_in_place(self.tcx, ty); - self.drop_lvalue( - lval, - instance, - ty, - terminator.source_info.span, - target, - )?; - } - - Assert { - ref cond, - expected, - ref msg, - target, - .. - } => { - let cond_val = self.eval_operand_to_primval(cond)?.to_bool()?; - if expected == cond_val { - self.goto_block(target); - } else { - use rustc::mir::AssertMessage::*; - return match *msg { - BoundsCheck { ref len, ref index } => { - let span = terminator.source_info.span; - let len = self.eval_operand_to_primval(len) - .expect("can't eval len") - .to_u64()?; - let index = self.eval_operand_to_primval(index) - .expect("can't eval index") - .to_u64()?; - err!(ArrayIndexOutOfBounds(span, len, index)) - } - Math(ref err) => { - err!(Math(terminator.source_info.span, err.clone())) - } - GeneratorResumedAfterReturn | - GeneratorResumedAfterPanic => unimplemented!(), - }; - } - } - - Yield { .. } => unimplemented!("{:#?}", terminator.kind), - GeneratorDrop => unimplemented!(), - DropAndReplace { .. } => unimplemented!(), - Resume => unimplemented!(), - Unreachable => return err!(Unreachable), - } - - Ok(()) - } - - /// Decides whether it is okay to call the method with signature `real_sig` using signature `sig`. - /// FIXME: This should take into account the platform-dependent ABI description. - fn check_sig_compat( - &mut self, - sig: ty::FnSig<'tcx>, - real_sig: ty::FnSig<'tcx>, - ) -> EvalResult<'tcx, bool> { - fn check_ty_compat<'tcx>(ty: ty::Ty<'tcx>, real_ty: ty::Ty<'tcx>) -> bool { - if ty == real_ty { - return true; - } // This is actually a fast pointer comparison - return match (&ty.sty, &real_ty.sty) { - // Permit changing the pointer type of raw pointers and references as well as - // mutability of raw pointers. - // TODO: Should not be allowed when fat pointers are involved. - (&TypeVariants::TyRawPtr(_), &TypeVariants::TyRawPtr(_)) => true, - (&TypeVariants::TyRef(_, _), &TypeVariants::TyRef(_, _)) => { - ty.is_mutable_pointer() == real_ty.is_mutable_pointer() - } - // rule out everything else - _ => false, - }; - } - - if sig.abi == real_sig.abi && sig.variadic == real_sig.variadic && - sig.inputs_and_output.len() == real_sig.inputs_and_output.len() && - sig.inputs_and_output - .iter() - .zip(real_sig.inputs_and_output) - .all(|(ty, real_ty)| check_ty_compat(ty, real_ty)) - { - // Definitely good. - return Ok(true); - } - - if sig.variadic || real_sig.variadic { - // We're not touching this - return Ok(false); - } - - // We need to allow what comes up when a non-capturing closure is cast to a fn(). - match (sig.abi, real_sig.abi) { - (Abi::Rust, Abi::RustCall) // check the ABIs. This makes the test here non-symmetric. - if check_ty_compat(sig.output(), real_sig.output()) && real_sig.inputs_and_output.len() == 3 => { - // First argument of real_sig must be a ZST - let fst_ty = real_sig.inputs_and_output[0]; - let layout = self.type_layout(fst_ty)?; - let size = layout.size(&self.tcx.data_layout).bytes(); - if size == 0 { - // Second argument must be a tuple matching the argument list of sig - let snd_ty = real_sig.inputs_and_output[1]; - match snd_ty.sty { - TypeVariants::TyTuple(tys, _) if sig.inputs().len() == tys.len() => - if sig.inputs().iter().zip(tys).all(|(ty, real_ty)| check_ty_compat(ty, real_ty)) { - return Ok(true) - }, - _ => {} - } - } - } - _ => {} - }; - - // Nope, this doesn't work. - return Ok(false); - } - - fn eval_fn_call( - &mut self, - instance: ty::Instance<'tcx>, - destination: Option<(Lvalue, mir::BasicBlock)>, - args: &[ValTy<'tcx>], - span: Span, - sig: ty::FnSig<'tcx>, - ) -> EvalResult<'tcx> { - trace!("eval_fn_call: {:#?}", instance); - match instance.def { - ty::InstanceDef::Intrinsic(..) => { - let (ret, target) = match destination { - Some(dest) => dest, - _ => return err!(Unreachable), - }; - let ty = sig.output(); - let layout = self.type_layout(ty)?; - M::call_intrinsic(self, instance, args, ret, ty, layout, target)?; - self.dump_local(ret); - Ok(()) - } - // FIXME: figure out why we can't just go through the shim - ty::InstanceDef::ClosureOnceShim { .. } => { - if M::eval_fn_call(self, instance, destination, args, span, sig)? { - return Ok(()); - } - let mut arg_locals = self.frame().mir.args_iter(); - match sig.abi { - // closure as closure once - Abi::RustCall => { - for (arg_local, &valty) in arg_locals.zip(args) { - let dest = self.eval_lvalue(&mir::Lvalue::Local(arg_local))?; - self.write_value(valty, dest)?; - } - } - // non capture closure as fn ptr - // need to inject zst ptr for closure object (aka do nothing) - // and need to pack arguments - Abi::Rust => { - trace!( - "arg_locals: {:?}", - self.frame().mir.args_iter().collect::>() - ); - trace!("args: {:?}", args); - let local = arg_locals.nth(1).unwrap(); - for (i, &valty) in args.into_iter().enumerate() { - let dest = self.eval_lvalue(&mir::Lvalue::Local(local).field( - mir::Field::new(i), - valty.ty, - ))?; - self.write_value(valty, dest)?; - } - } - _ => bug!("bad ABI for ClosureOnceShim: {:?}", sig.abi), - } - Ok(()) - } - ty::InstanceDef::FnPtrShim(..) | - ty::InstanceDef::DropGlue(..) | - ty::InstanceDef::CloneShim(..) | - ty::InstanceDef::Item(_) => { - // Push the stack frame, and potentially be entirely done if the call got hooked - if M::eval_fn_call(self, instance, destination, args, span, sig)? { - return Ok(()); - } - - // Pass the arguments - let mut arg_locals = self.frame().mir.args_iter(); - trace!("ABI: {:?}", sig.abi); - trace!( - "arg_locals: {:?}", - self.frame().mir.args_iter().collect::>() - ); - trace!("args: {:?}", args); - match sig.abi { - Abi::RustCall => { - assert_eq!(args.len(), 2); - - { - // write first argument - let first_local = arg_locals.next().unwrap(); - let dest = self.eval_lvalue(&mir::Lvalue::Local(first_local))?; - self.write_value(args[0], dest)?; - } - - // unpack and write all other args - let layout = self.type_layout(args[1].ty)?; - if let (&ty::TyTuple(fields, _), - &Layout::Univariant { ref variant, .. }) = (&args[1].ty.sty, layout) - { - trace!("fields: {:?}", fields); - if self.frame().mir.args_iter().count() == fields.len() + 1 { - let offsets = variant.offsets.iter().map(|s| s.bytes()); - match args[1].value { - Value::ByRef(PtrAndAlign { ptr, aligned }) => { - assert!( - aligned, - "Unaligned ByRef-values cannot occur as function arguments" - ); - for ((offset, ty), arg_local) in - offsets.zip(fields).zip(arg_locals) - { - let arg = Value::by_ref(ptr.offset(offset, &self)?); - let dest = - self.eval_lvalue(&mir::Lvalue::Local(arg_local))?; - trace!( - "writing arg {:?} to {:?} (type: {})", - arg, - dest, - ty - ); - let valty = ValTy { - value: arg, - ty, - }; - self.write_value(valty, dest)?; - } - } - Value::ByVal(PrimVal::Undef) => {} - other => { - assert_eq!(fields.len(), 1); - let dest = self.eval_lvalue(&mir::Lvalue::Local( - arg_locals.next().unwrap(), - ))?; - let valty = ValTy { - value: other, - ty: fields[0], - }; - self.write_value(valty, dest)?; - } - } - } else { - trace!("manual impl of rust-call ABI"); - // called a manual impl of a rust-call function - let dest = self.eval_lvalue( - &mir::Lvalue::Local(arg_locals.next().unwrap()), - )?; - self.write_value(args[1], dest)?; - } - } else { - bug!( - "rust-call ABI tuple argument was {:#?}, {:#?}", - args[1].ty, - layout - ); - } - } - _ => { - for (arg_local, &valty) in arg_locals.zip(args) { - let dest = self.eval_lvalue(&mir::Lvalue::Local(arg_local))?; - self.write_value(valty, dest)?; - } - } - } - Ok(()) - } - // cannot use the shim here, because that will only result in infinite recursion - 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_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; - args[0].value = ptr.to_value(); - // recurse with concrete function - self.eval_fn_call(instance, destination, &args, span, sig) - } - } - } -} diff --git a/src/librustc_mir/interpret/traits.rs b/src/librustc_mir/interpret/traits.rs deleted file mode 100644 index 3f7e10a9eaff0..0000000000000 --- a/src/librustc_mir/interpret/traits.rs +++ /dev/null @@ -1,137 +0,0 @@ -use rustc::traits::{self, Reveal}; -use rustc::hir::def_id::DefId; -use rustc::ty::subst::Substs; -use rustc::ty::{self, Ty}; -use syntax::codemap::DUMMY_SP; -use syntax::ast::{self, Mutability}; - -use super::{EvalResult, EvalContext, eval_context, MemoryPointer, MemoryKind, Value, PrimVal, - Machine}; - -impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { - pub(crate) fn fulfill_obligation( - &self, - trait_ref: ty::PolyTraitRef<'tcx>, - ) -> traits::Vtable<'tcx, ()> { - // Do the initial selection for the obligation. This yields the shallow result we are - // looking for -- that is, what specific impl. - self.tcx.infer_ctxt().enter(|infcx| { - let mut selcx = traits::SelectionContext::new(&infcx); - - let obligation = traits::Obligation::new( - traits::ObligationCause::misc(DUMMY_SP, ast::DUMMY_NODE_ID), - ty::ParamEnv::empty(Reveal::All), - trait_ref.to_poly_trait_predicate(), - ); - let selection = selcx.select(&obligation).unwrap().unwrap(); - - // Currently, we use a fulfillment context to completely resolve all nested obligations. - // This is because they can inform the inference of the impl's type parameters. - let mut fulfill_cx = traits::FulfillmentContext::new(); - let vtable = selection.map(|predicate| { - fulfill_cx.register_predicate_obligation(&infcx, predicate); - }); - infcx.drain_fulfillment_cx_or_panic(DUMMY_SP, &mut fulfill_cx, &vtable) - }) - } - - /// Creates a dynamic vtable for the given type and vtable origin. This is used only for - /// objects. - /// - /// The `trait_ref` encodes the erased self type. Hence if we are - /// making an object `Foo` from a value of type `Foo`, then - /// `trait_ref` would map `T:Trait`. - pub fn get_vtable( - &mut self, - ty: Ty<'tcx>, - trait_ref: ty::PolyTraitRef<'tcx>, - ) -> EvalResult<'tcx, MemoryPointer> { - debug!("get_vtable(trait_ref={:?})", trait_ref); - - let size = self.type_size(trait_ref.self_ty())?.expect( - "can't create a vtable for an unsized type", - ); - let align = self.type_align(trait_ref.self_ty())?; - - let ptr_size = self.memory.pointer_size(); - let methods = ::rustc::traits::get_vtable_methods(self.tcx, trait_ref); - let vtable = self.memory.allocate( - ptr_size * (3 + methods.count() as u64), - ptr_size, - MemoryKind::UninitializedStatic, - )?; - - let drop = eval_context::resolve_drop_in_place(self.tcx, ty); - let drop = self.memory.create_fn_alloc(drop); - self.memory.write_ptr_sized_unsigned(vtable, PrimVal::Ptr(drop))?; - - let size_ptr = vtable.offset(ptr_size, &self)?; - 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_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_sized_unsigned(method_ptr, PrimVal::Ptr(fn_ptr))?; - } - } - - self.memory.mark_static_initalized( - vtable.alloc_id, - Mutability::Mutable, - )?; - - Ok(vtable) - } - - pub fn read_drop_type_from_vtable( - &self, - vtable: MemoryPointer, - ) -> EvalResult<'tcx, Option>> { - // we don't care about the pointee type, we just want a pointer - match self.read_ptr(vtable, self.tcx.mk_nil_ptr())? { - // some values don't need to call a drop impl, so the value is null - Value::ByVal(PrimVal::Bytes(0)) => Ok(None), - Value::ByVal(PrimVal::Ptr(drop_fn)) => self.memory.get_fn(drop_fn).map(Some), - _ => err!(ReadBytesAsPointer), - } - } - - pub fn read_size_and_align_from_vtable( - &self, - vtable: MemoryPointer, - ) -> EvalResult<'tcx, (u64, u64)> { - let pointer_size = self.memory.pointer_size(); - 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)) - } - - pub(crate) fn resolve_associated_const( - &self, - def_id: DefId, - substs: &'tcx Substs<'tcx>, - ) -> ty::Instance<'tcx> { - if let Some(trait_id) = self.tcx.trait_of_item(def_id) { - let trait_ref = ty::Binder(ty::TraitRef::new(trait_id, substs)); - let vtable = self.fulfill_obligation(trait_ref); - if let traits::VtableImpl(vtable_impl) = vtable { - let name = self.tcx.item_name(def_id); - let assoc_const_opt = self.tcx.associated_items(vtable_impl.impl_def_id).find( - |item| { - item.kind == ty::AssociatedKind::Const && item.name == name - }, - ); - if let Some(assoc_const) = assoc_const_opt { - return ty::Instance::new(assoc_const.def_id, vtable_impl.substs); - } - } - } - ty::Instance::new(def_id, substs) - } -} diff --git a/src/librustc_mir/interpret/validation.rs b/src/librustc_mir/interpret/validation.rs deleted file mode 100644 index 9be9341ee239b..0000000000000 --- a/src/librustc_mir/interpret/validation.rs +++ /dev/null @@ -1,727 +0,0 @@ -use rustc::hir::{self, Mutability}; -use rustc::hir::Mutability::*; -use rustc::mir::{self, ValidationOp, ValidationOperand}; -use rustc::ty::{self, Ty, TypeFoldable, TyCtxt}; -use rustc::ty::subst::{Substs, Subst}; -use rustc::traits; -use rustc::infer::InferCtxt; -use rustc::traits::Reveal; -use rustc::middle::region; -use rustc_data_structures::indexed_vec::Idx; - -use super::{EvalError, EvalResult, EvalErrorKind, EvalContext, DynamicLifetime, AccessKind, Value, - Lvalue, LvalueExtra, Machine, ValTy}; - -pub type ValidationQuery<'tcx> = ValidationOperand<'tcx, (AbsLvalue<'tcx>, Lvalue)>; - -#[derive(Copy, Clone, Debug, PartialEq)] -enum ValidationMode { - Acquire, - /// Recover because the given region ended - Recover(region::Scope), - ReleaseUntil(Option), -} - -impl ValidationMode { - fn acquiring(self) -> bool { - use self::ValidationMode::*; - match self { - Acquire | Recover(_) => true, - ReleaseUntil(_) => false, - } - } -} - -// Abstract lvalues -#[derive(Clone, Debug, PartialEq, Eq, Hash)] -pub enum AbsLvalue<'tcx> { - Local(mir::Local), - Static(hir::def_id::DefId), - Projection(Box>), -} - -type AbsLvalueProjection<'tcx> = mir::Projection<'tcx, AbsLvalue<'tcx>, u64, ()>; -type AbsLvalueElem<'tcx> = mir::ProjectionElem<'tcx, u64, ()>; - -impl<'tcx> AbsLvalue<'tcx> { - pub fn field(self, f: mir::Field) -> AbsLvalue<'tcx> { - self.elem(mir::ProjectionElem::Field(f, ())) - } - - pub fn deref(self) -> AbsLvalue<'tcx> { - self.elem(mir::ProjectionElem::Deref) - } - - pub fn downcast(self, adt_def: &'tcx ty::AdtDef, variant_index: usize) -> AbsLvalue<'tcx> { - self.elem(mir::ProjectionElem::Downcast(adt_def, variant_index)) - } - - pub fn index(self, index: u64) -> AbsLvalue<'tcx> { - self.elem(mir::ProjectionElem::Index(index)) - } - - fn elem(self, elem: AbsLvalueElem<'tcx>) -> AbsLvalue<'tcx> { - AbsLvalue::Projection(Box::new(AbsLvalueProjection { - base: self, - elem, - })) - } -} - -impl<'a, 'tcx, M: Machine<'tcx>> EvalContext<'a, 'tcx, M> { - fn abstract_lvalue_projection(&self, proj: &mir::LvalueProjection<'tcx>) -> EvalResult<'tcx, AbsLvalueProjection<'tcx>> { - use self::mir::ProjectionElem::*; - - let elem = match proj.elem { - Deref => Deref, - Field(f, _) => Field(f, ()), - Index(v) => { - let value = self.frame().get_local(v)?; - let ty = self.tcx.types.usize; - let n = self.value_to_primval(ValTy { value, ty })?.to_u64()?; - Index(n) - }, - ConstantIndex { offset, min_length, from_end } => - ConstantIndex { offset, min_length, from_end }, - Subslice { from, to } => - Subslice { from, to }, - Downcast(adt, sz) => Downcast(adt, sz), - }; - Ok(AbsLvalueProjection { - base: self.abstract_lvalue(&proj.base)?, - elem - }) - } - - fn abstract_lvalue(&self, lval: &mir::Lvalue<'tcx>) -> EvalResult<'tcx, AbsLvalue<'tcx>> { - Ok(match lval { - &mir::Lvalue::Local(l) => AbsLvalue::Local(l), - &mir::Lvalue::Static(ref s) => AbsLvalue::Static(s.def_id), - &mir::Lvalue::Projection(ref p) => - AbsLvalue::Projection(Box::new(self.abstract_lvalue_projection(&*p)?)), - }) - } - - // Validity checks - pub(crate) fn validation_op( - &mut self, - op: ValidationOp, - operand: &ValidationOperand<'tcx, mir::Lvalue<'tcx>>, - ) -> EvalResult<'tcx> { - // If mir-emit-validate is set to 0 (i.e., disabled), we may still see validation commands - // because other crates may have been compiled with mir-emit-validate > 0. Ignore those - // commands. This makes mir-emit-validate also a flag to control whether miri will do - // validation or not. - if self.tcx.sess.opts.debugging_opts.mir_emit_validate == 0 { - return Ok(()); - } - debug_assert!(self.memory.cur_frame == self.cur_frame()); - - // HACK: Determine if this method is whitelisted and hence we do not perform any validation. - // We currently insta-UB on anything passing around uninitialized memory, so we have to whitelist - // the places that are allowed to do that. - // The second group is stuff libstd does that is forbidden even under relaxed validation. - { - // The regexp we use for filtering - use regex::Regex; - lazy_static! { - static ref RE: Regex = Regex::new("^(\ - (std|alloc::heap::__core)::mem::(uninitialized|forget)::|\ - <(std|alloc)::heap::Heap as (std::heap|alloc::allocator)::Alloc>::|\ - <(std|alloc::heap::__core)::mem::ManuallyDrop><.*>::new$|\ - <(std|alloc::heap::__core)::mem::ManuallyDrop as std::ops::DerefMut><.*>::deref_mut$|\ - (std|alloc::heap::__core)::ptr::read::|\ - \ - ><.*>::inner$|\ - ><.*>::drop_slow$|\ - (std::heap|alloc::allocator)::Layout::for_value::|\ - (std|alloc::heap::__core)::mem::(size|align)_of_val::\ - )").unwrap(); - } - // Now test - let name = self.stack[self.cur_frame()].instance.to_string(); - if RE.is_match(&name) { - return Ok(()); - } - } - - // We need to monomorphize ty *without* erasing lifetimes - let ty = operand.ty.subst(self.tcx, self.substs()); - let lval = self.eval_lvalue(&operand.lval)?; - let abs_lval = self.abstract_lvalue(&operand.lval)?; - let query = ValidationQuery { - lval: (abs_lval, lval), - ty, - re: operand.re, - mutbl: operand.mutbl, - }; - - // Check the mode, and also perform mode-specific operations - let mode = match op { - ValidationOp::Acquire => ValidationMode::Acquire, - ValidationOp::Release => ValidationMode::ReleaseUntil(None), - ValidationOp::Suspend(scope) => { - if query.mutbl == MutMutable { - let lft = DynamicLifetime { - frame: self.cur_frame(), - region: Some(scope), // Notably, we only ever suspend things for given regions. - // Suspending for the entire function does not make any sense. - }; - trace!("Suspending {:?} until {:?}", query, scope); - self.suspended.entry(lft).or_insert_with(Vec::new).push( - query.clone(), - ); - } - ValidationMode::ReleaseUntil(Some(scope)) - } - }; - self.validate(query, mode) - } - - /// Release locks and executes suspensions of the given region (or the entire fn, in case of None). - pub(crate) fn end_region(&mut self, scope: Option) -> EvalResult<'tcx> { - debug_assert!(self.memory.cur_frame == self.cur_frame()); - self.memory.locks_lifetime_ended(scope); - match scope { - Some(scope) => { - // Recover suspended lvals - let lft = DynamicLifetime { - frame: self.cur_frame(), - region: Some(scope), - }; - if let Some(queries) = self.suspended.remove(&lft) { - for query in queries { - trace!("Recovering {:?} from suspension", query); - self.validate(query, ValidationMode::Recover(scope))?; - } - } - } - None => { - // Clean suspension table of current frame - let cur_frame = self.cur_frame(); - self.suspended.retain(|lft, _| { - lft.frame != cur_frame // keep only what is in the other (lower) frames - }); - } - } - Ok(()) - } - - fn normalize_type_unerased(&self, ty: Ty<'tcx>) -> Ty<'tcx> { - return normalize_associated_type(self.tcx, &ty); - - use syntax::codemap::{Span, DUMMY_SP}; - - // We copy a bunch of stuff from rustc/infer/mod.rs to be able to tweak its behavior - fn normalize_projections_in<'a, 'gcx, 'tcx, T>( - self_: &InferCtxt<'a, 'gcx, 'tcx>, - param_env: ty::ParamEnv<'tcx>, - value: &T, - ) -> T::Lifted - where - T: TypeFoldable<'tcx> + ty::Lift<'gcx>, - { - let mut selcx = traits::SelectionContext::new(self_); - let cause = traits::ObligationCause::dummy(); - let traits::Normalized { - value: result, - obligations, - } = traits::normalize(&mut selcx, param_env, cause, value); - - let mut fulfill_cx = traits::FulfillmentContext::new(); - - for obligation in obligations { - fulfill_cx.register_predicate_obligation(self_, obligation); - } - - drain_fulfillment_cx_or_panic(self_, DUMMY_SP, &mut fulfill_cx, &result) - } - - fn drain_fulfillment_cx_or_panic<'a, 'gcx, 'tcx, T>( - self_: &InferCtxt<'a, 'gcx, 'tcx>, - span: Span, - fulfill_cx: &mut traits::FulfillmentContext<'tcx>, - result: &T, - ) -> T::Lifted - where - T: TypeFoldable<'tcx> + ty::Lift<'gcx>, - { - // In principle, we only need to do this so long as `result` - // contains unbound type parameters. It could be a slight - // optimization to stop iterating early. - match fulfill_cx.select_all_or_error(self_) { - Ok(()) => { } - Err(errors) => { - span_bug!( - span, - "Encountered errors `{:?}` resolving bounds after type-checking", - errors - ); - } - } - - let result = self_.resolve_type_vars_if_possible(result); - let result = self_.tcx.fold_regions( - &result, - &mut false, - |r, _| match *r { - ty::ReVar(_) => self_.tcx.types.re_erased, - _ => r, - }, - ); - - match self_.tcx.lift_to_global(&result) { - Some(result) => result, - None => { - span_bug!(span, "Uninferred types/regions in `{:?}`", result); - } - } - } - - trait MyTransNormalize<'gcx>: TypeFoldable<'gcx> { - fn my_trans_normalize<'a, 'tcx>( - &self, - infcx: &InferCtxt<'a, 'gcx, 'tcx>, - param_env: ty::ParamEnv<'tcx>, - ) -> Self; - } - - macro_rules! items { ($($item:item)+) => ($($item)+) } - macro_rules! impl_trans_normalize { - ($lt_gcx:tt, $($ty:ty),+) => { - items!($(impl<$lt_gcx> MyTransNormalize<$lt_gcx> for $ty { - fn my_trans_normalize<'a, 'tcx>(&self, - infcx: &InferCtxt<'a, $lt_gcx, 'tcx>, - param_env: ty::ParamEnv<'tcx>) - -> Self { - normalize_projections_in(infcx, param_env, self) - } - })+); - } - } - - impl_trans_normalize!('gcx, - Ty<'gcx>, - &'gcx Substs<'gcx>, - ty::FnSig<'gcx>, - ty::PolyFnSig<'gcx>, - ty::ClosureSubsts<'gcx>, - ty::PolyTraitRef<'gcx>, - ty::ExistentialTraitRef<'gcx> - ); - - fn normalize_associated_type<'a, 'tcx, T>(self_: TyCtxt<'a, 'tcx, 'tcx>, value: &T) -> T - where - T: MyTransNormalize<'tcx>, - { - let param_env = ty::ParamEnv::empty(Reveal::All); - - if !value.has_projections() { - return value.clone(); - } - - self_.infer_ctxt().enter(|infcx| { - value.my_trans_normalize(&infcx, param_env) - }) - } - } - - fn validate_variant( - &mut self, - query: ValidationQuery<'tcx>, - variant: &ty::VariantDef, - subst: &ty::subst::Substs<'tcx>, - mode: ValidationMode, - ) -> EvalResult<'tcx> { - // TODO: Maybe take visibility/privacy into account. - for (idx, field_def) in variant.fields.iter().enumerate() { - let field_ty = field_def.ty(self.tcx, subst); - let field = mir::Field::new(idx); - let field_lvalue = self.lvalue_field(query.lval.1, field, query.ty, field_ty)?; - self.validate( - ValidationQuery { - lval: (query.lval.0.clone().field(field), field_lvalue), - ty: field_ty, - ..query - }, - mode, - )?; - } - Ok(()) - } - - fn validate_ptr( - &mut self, - val: Value, - abs_lval: AbsLvalue<'tcx>, - pointee_ty: Ty<'tcx>, - re: Option, - mutbl: Mutability, - mode: ValidationMode, - ) -> EvalResult<'tcx> { - // 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, None)?; - - // Recurse - let pointee_lvalue = self.val_to_lvalue(val, pointee_ty)?; - self.validate( - ValidationQuery { - lval: (abs_lval.deref(), pointee_lvalue), - ty: pointee_ty, - re, - mutbl, - }, - mode, - ) - } - - /// Validate the lvalue at the given type. If `acquire` is false, just do a release of all write locks - fn validate( - &mut self, - mut query: ValidationQuery<'tcx>, - mode: ValidationMode, - ) -> EvalResult<'tcx> { - use rustc::ty::TypeVariants::*; - use rustc::ty::RegionKind::*; - use rustc::ty::AdtKind; - - // No point releasing shared stuff. - if !mode.acquiring() && query.mutbl == MutImmutable { - return Ok(()); - } - // When we recover, we may see data whose validity *just* ended. Do not acquire it. - if let ValidationMode::Recover(ending_ce) = mode { - if query.re == Some(ending_ce) { - return Ok(()); - } - } - - query.ty = self.normalize_type_unerased(&query.ty); - trace!("{:?} on {:?}", mode, query); - - // Decide whether this type *owns* the memory it covers (like integers), or whether it - // just assembles pieces (that each own their memory) together to a larger whole. - // TODO: Currently, we don't acquire locks for padding and discriminants. We should. - let is_owning = match query.ty.sty { - TyInt(_) | TyUint(_) | TyRawPtr(_) | TyBool | TyFloat(_) | TyChar | TyStr | - TyRef(..) | TyFnPtr(..) | TyFnDef(..) | TyNever => true, - TyAdt(adt, _) if adt.is_box() => true, - TySlice(_) | TyAdt(_, _) | TyTuple(..) | TyClosure(..) | TyArray(..) | - TyDynamic(..) | TyGenerator(..) => false, - TyParam(_) | TyInfer(_) | TyProjection(_) | TyAnon(..) | TyError => { - bug!("I got an incomplete/unnormalized type for validation") - } - }; - if is_owning { - // We need to lock. So we need memory. So we have to force_acquire. - // Tracking the same state for locals not backed by memory would just duplicate too - // much machinery. - // FIXME: We ignore alignment. - let (ptr, extra) = self.force_allocation(query.lval.1)?.to_ptr_extra_aligned(); - // Determine the size - // FIXME: Can we reuse size_and_align_of_dst for Lvalues? - let len = match self.type_size(query.ty)? { - Some(size) => { - assert_eq!(extra, LvalueExtra::None, "Got a fat ptr to a sized type"); - size - } - None => { - // The only unsized typ we concider "owning" is TyStr. - assert_eq!( - query.ty.sty, - TyStr, - "Found a surprising unsized owning type" - ); - // The extra must be the length, in bytes. - match extra { - LvalueExtra::Length(len) => len, - _ => bug!("TyStr must have a length as extra"), - } - } - }; - // Handle locking - if len > 0 { - let ptr = ptr.to_ptr()?; - match query.mutbl { - MutImmutable => { - if mode.acquiring() { - self.memory.acquire_lock( - ptr, - len, - query.re, - AccessKind::Read, - )?; - } - } - // No releasing of read locks, ever. - MutMutable => { - match mode { - ValidationMode::Acquire => { - self.memory.acquire_lock( - ptr, - len, - query.re, - AccessKind::Write, - )? - } - ValidationMode::Recover(ending_ce) => { - self.memory.recover_write_lock( - ptr, - len, - &query.lval.0, - query.re, - ending_ce, - )? - } - ValidationMode::ReleaseUntil(suspended_ce) => { - self.memory.suspend_write_lock( - ptr, - len, - &query.lval.0, - suspended_ce, - )? - } - } - } - } - } - } - - let res = do catch { - match query.ty.sty { - TyInt(_) | TyUint(_) | TyRawPtr(_) => { - if mode.acquiring() { - // Make sure we can read this. - let val = self.read_lvalue(query.lval.1)?; - self.follow_by_ref_value(val, query.ty)?; - // FIXME: It would be great to rule out Undef here, but that doesn't actually work. - // Passing around undef data is a thing that e.g. Vec::extend_with does. - } - Ok(()) - } - TyBool | TyFloat(_) | TyChar => { - if mode.acquiring() { - let val = self.read_lvalue(query.lval.1)?; - let val = self.value_to_primval(ValTy { value: val, ty: query.ty })?; - val.to_bytes()?; - // TODO: Check if these are valid bool/float/codepoint/UTF-8 - } - Ok(()) - } - TyNever => err!(ValidationFailure(format!("The empty type is never valid."))), - TyRef(region, - ty::TypeAndMut { - ty: pointee_ty, - mutbl, - }) => { - let val = self.read_lvalue(query.lval.1)?; - // Sharing restricts our context - if mutbl == MutImmutable { - query.mutbl = MutImmutable; - } - // Inner lifetimes *outlive* outer ones, so only if we have no lifetime restriction yet, - // we record the region of this borrow to the context. - if query.re == None { - match *region { - ReScope(scope) => query.re = Some(scope), - // It is possible for us to encounter erased lifetimes here because the lifetimes in - // this functions' Subst will be erased. - _ => {} - } - } - self.validate_ptr(val, query.lval.0, pointee_ty, query.re, query.mutbl, mode) - } - TyAdt(adt, _) if adt.is_box() => { - let val = self.read_lvalue(query.lval.1)?; - self.validate_ptr(val, query.lval.0, query.ty.boxed_ty(), query.re, query.mutbl, mode) - } - TyFnPtr(_sig) => { - let ptr = self.read_lvalue(query.lval.1)? - .into_ptr(&self.memory)? - .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?). - Ok(()) - } - TyFnDef(..) => { - // This is a zero-sized type with all relevant data sitting in the type. - // There is nothing to validate. - Ok(()) - } - - // Compound types - TyStr => { - // TODO: Validate strings - Ok(()) - } - TySlice(elem_ty) => { - let len = match query.lval.1 { - Lvalue::Ptr { extra: LvalueExtra::Length(len), .. } => len, - _ => { - bug!( - "acquire_valid of a TySlice given non-slice lvalue: {:?}", - query.lval - ) - } - }; - for i in 0..len { - let inner_lvalue = self.lvalue_index(query.lval.1, query.ty, i)?; - self.validate( - ValidationQuery { - lval: (query.lval.0.clone().index(i), inner_lvalue), - ty: elem_ty, - ..query - }, - mode, - )?; - } - Ok(()) - } - TyArray(elem_ty, len) => { - let len = len.val.to_const_int().unwrap().to_u64().unwrap(); - for i in 0..len { - let inner_lvalue = self.lvalue_index(query.lval.1, query.ty, i as u64)?; - self.validate( - ValidationQuery { - lval: (query.lval.0.clone().index(i as u64), inner_lvalue), - ty: elem_ty, - ..query - }, - mode, - )?; - } - Ok(()) - } - TyDynamic(_data, _region) => { - // Check that this is a valid vtable - let vtable = match query.lval.1 { - Lvalue::Ptr { extra: LvalueExtra::Vtable(vtable), .. } => vtable, - _ => { - bug!( - "acquire_valid of a TyDynamic given non-trait-object lvalue: {:?}", - query.lval - ) - } - }; - self.read_size_and_align_from_vtable(vtable)?; - // TODO: Check that the vtable contains all the function pointers we expect it to have. - // Trait objects cannot have any operations performed - // on them directly. We cannot, in general, even acquire any locks as the trait object *could* - // contain an UnsafeCell. If we call functions to get access to data, we will validate - // their return values. So, it doesn't seem like there's anything else to do. - Ok(()) - } - TyAdt(adt, subst) => { - if Some(adt.did) == self.tcx.lang_items().unsafe_cell_type() && - query.mutbl == MutImmutable - { - // No locks for shared unsafe cells. Also no other validation, the only field is private anyway. - return Ok(()); - } - - match adt.adt_kind() { - AdtKind::Enum => { - // TODO: Can we get the discriminant without forcing an allocation? - let ptr = self.force_allocation(query.lval.1)?.to_ptr()?; - let discr = self.read_discriminant_value(ptr, query.ty)?; - - // Get variant index for discriminant - let variant_idx = adt.discriminants(self.tcx).position(|variant_discr| { - variant_discr.to_u128_unchecked() == discr - }); - let variant_idx = match variant_idx { - Some(val) => val, - None => return err!(InvalidDiscriminant), - }; - let variant = &adt.variants[variant_idx]; - - if variant.fields.len() > 0 { - // Downcast to this variant, if needed - let lval = if adt.variants.len() > 1 { - ( - query.lval.0.downcast(adt, variant_idx), - self.eval_lvalue_projection( - query.lval.1, - query.ty, - &mir::ProjectionElem::Downcast(adt, variant_idx), - )?, - ) - } else { - query.lval - }; - - // Recursively validate the fields - self.validate_variant( - ValidationQuery { lval, ..query }, - variant, - subst, - mode, - ) - } else { - // No fields, nothing left to check. Downcasting may fail, e.g. in case of a CEnum. - Ok(()) - } - } - AdtKind::Struct => { - self.validate_variant(query, adt.struct_variant(), subst, mode) - } - AdtKind::Union => { - // No guarantees are provided for union types. - // TODO: Make sure that all access to union fields is unsafe; otherwise, we may have some checking to do (but what exactly?) - Ok(()) - } - } - } - TyTuple(ref types, _) => { - for (idx, field_ty) in types.iter().enumerate() { - let field = mir::Field::new(idx); - let field_lvalue = self.lvalue_field(query.lval.1, field, query.ty, field_ty)?; - self.validate( - ValidationQuery { - lval: (query.lval.0.clone().field(field), field_lvalue), - ty: field_ty, - ..query - }, - mode, - )?; - } - Ok(()) - } - TyClosure(def_id, ref closure_substs) => { - for (idx, field_ty) in closure_substs.upvar_tys(def_id, self.tcx).enumerate() { - let field = mir::Field::new(idx); - let field_lvalue = self.lvalue_field(query.lval.1, field, query.ty, field_ty)?; - self.validate( - ValidationQuery { - lval: (query.lval.0.clone().field(field), field_lvalue), - ty: field_ty, - ..query - }, - mode, - )?; - } - // TODO: Check if the signature matches (should be the same check as what terminator/mod.rs already does on call?). - // Is there other things we can/should check? Like vtable pointers? - Ok(()) - } - // FIXME: generators aren't validated right now - TyGenerator(..) => Ok(()), - _ => bug!("We already established that this is a type we support. ({})", query.ty), - } - }; - match res { - // ReleaseUntil(None) of an uninitalized variable is a NOP. This is needed because - // we have to release the return value of a function; due to destination-passing-style - // the callee may directly write there. - // TODO: Ideally we would know whether the destination is already initialized, and only - // release if it is. But of course that can't even always be statically determined. - Err(EvalError { kind: EvalErrorKind::ReadUndefBytes, .. }) - if mode == ValidationMode::ReleaseUntil(None) => { - return Ok(()); - } - res => res, - } - } -} diff --git a/src/librustc_mir/interpret/value.rs b/src/librustc_mir/interpret/value.rs deleted file mode 100644 index e052ec1e391cd..0000000000000 --- a/src/librustc_mir/interpret/value.rs +++ /dev/null @@ -1,405 +0,0 @@ -#![allow(unknown_lints)] - -use rustc::ty::layout::HasDataLayout; - -use super::{EvalResult, Memory, MemoryPointer, HasMemory, PointerArithmetic, Machine, PtrAndAlign}; - -pub(super) fn bytes_to_f32(bytes: u128) -> f32 { - f32::from_bits(bytes as u32) -} - -pub(super) fn bytes_to_f64(bytes: u128) -> f64 { - f64::from_bits(bytes as u64) -} - -pub(super) fn f32_to_bytes(f: f32) -> u128 { - f.to_bits() as u128 -} - -pub(super) fn f64_to_bytes(f: f64) -> u128 { - f.to_bits() as u128 -} - -/// A `Value` represents a single self-contained Rust value. -/// -/// A `Value` can either refer to a block of memory inside an allocation (`ByRef`) or to a primitve -/// value held directly, outside of any allocation (`ByVal`). For `ByRef`-values, we remember -/// whether the pointer is supposed to be aligned or not (also see Lvalue). -/// -/// For optimization of a few very common cases, there is also a representation for a pair of -/// primitive values (`ByValPair`). It allows Miri to avoid making allocations for checked binary -/// operations and fat pointers. This idea was taken from rustc's trans. -#[derive(Clone, Copy, Debug)] -pub enum Value { - ByRef(PtrAndAlign), - ByVal(PrimVal), - ByValPair(PrimVal, PrimVal), -} - -/// A wrapper type around `PrimVal` that cannot be turned back into a `PrimVal` accidentally. -/// This type clears up a few APIs where having a `PrimVal` argument for something that is -/// potentially an integer pointer or a pointer to an allocation was unclear. -/// -/// I (@oli-obk) believe it is less easy to mix up generic primvals and primvals that are just -/// the representation of pointers. Also all the sites that convert between primvals and pointers -/// are explicit now (and rare!) -#[derive(Clone, Copy, Debug)] -pub struct Pointer { - primval: PrimVal, -} - -impl<'tcx> Pointer { - pub fn null() -> Self { - PrimVal::Bytes(0).into() - } - pub fn to_ptr(self) -> EvalResult<'tcx, MemoryPointer> { - self.primval.to_ptr() - } - pub fn into_inner_primval(self) -> PrimVal { - self.primval - } - - pub fn signed_offset(self, i: i64, cx: C) -> EvalResult<'tcx, Self> { - let layout = cx.data_layout(); - match self.primval { - PrimVal::Bytes(b) => { - assert_eq!(b as u64 as u128, b); - Ok(Pointer::from( - PrimVal::Bytes(layout.signed_offset(b as u64, i)? as u128), - )) - } - PrimVal::Ptr(ptr) => ptr.signed_offset(i, layout).map(Pointer::from), - PrimVal::Undef => err!(ReadUndefBytes), - } - } - - pub fn offset(self, i: u64, cx: C) -> EvalResult<'tcx, Self> { - let layout = cx.data_layout(); - match self.primval { - PrimVal::Bytes(b) => { - assert_eq!(b as u64 as u128, b); - Ok(Pointer::from( - PrimVal::Bytes(layout.offset(b as u64, i)? as u128), - )) - } - PrimVal::Ptr(ptr) => ptr.offset(i, layout).map(Pointer::from), - PrimVal::Undef => err!(ReadUndefBytes), - } - } - - pub fn wrapping_signed_offset(self, i: i64, cx: C) -> EvalResult<'tcx, Self> { - let layout = cx.data_layout(); - match self.primval { - PrimVal::Bytes(b) => { - assert_eq!(b as u64 as u128, b); - Ok(Pointer::from(PrimVal::Bytes( - layout.wrapping_signed_offset(b as u64, i) as u128, - ))) - } - PrimVal::Ptr(ptr) => Ok(Pointer::from(ptr.wrapping_signed_offset(i, layout))), - PrimVal::Undef => err!(ReadUndefBytes), - } - } - - pub fn is_null(self) -> EvalResult<'tcx, bool> { - match self.primval { - PrimVal::Bytes(b) => Ok(b == 0), - PrimVal::Ptr(_) => Ok(false), - PrimVal::Undef => err!(ReadUndefBytes), - } - } - - pub fn to_value_with_len(self, len: u64) -> Value { - Value::ByValPair(self.primval, PrimVal::from_u128(len as u128)) - } - - pub fn to_value_with_vtable(self, vtable: MemoryPointer) -> Value { - Value::ByValPair(self.primval, PrimVal::Ptr(vtable)) - } - - pub fn to_value(self) -> Value { - Value::ByVal(self.primval) - } -} - -impl ::std::convert::From for Pointer { - fn from(primval: PrimVal) -> Self { - Pointer { primval } - } -} - -impl ::std::convert::From for Pointer { - fn from(ptr: MemoryPointer) -> Self { - PrimVal::Ptr(ptr).into() - } -} - -/// A `PrimVal` represents an immediate, primitive value existing outside of a -/// `memory::Allocation`. It is in many ways like a small chunk of a `Allocation`, up to 8 bytes in -/// size. Like a range of bytes in an `Allocation`, a `PrimVal` can either represent the raw bytes -/// of a simple value, a pointer into another `Allocation`, or be undefined. -#[derive(Clone, Copy, Debug)] -pub enum PrimVal { - /// The raw bytes of a simple value. - Bytes(u128), - - /// A pointer into an `Allocation`. An `Allocation` in the `memory` module has a list of - /// relocations, but a `PrimVal` is only large enough to contain one, so we just represent the - /// relocation and its associated offset together as a `MemoryPointer` here. - Ptr(MemoryPointer), - - /// An undefined `PrimVal`, for representing values that aren't safe to examine, but are safe - /// to copy around, just like undefined bytes in an `Allocation`. - Undef, -} - -#[derive(Clone, Copy, Debug, PartialEq)] -pub enum PrimValKind { - I8, I16, I32, I64, I128, - U8, U16, U32, U64, U128, - F32, F64, - Ptr, FnPtr, - Bool, - Char, -} - -impl<'a, 'tcx: 'a> Value { - #[inline] - pub fn by_ref(ptr: Pointer) -> Self { - Value::ByRef(PtrAndAlign { ptr, aligned: true }) - } - - /// Convert the value into a pointer (or a pointer-sized integer). If the value is a ByRef, - /// this may have to perform a load. - pub fn into_ptr>( - &self, - mem: &Memory<'a, 'tcx, M>, - ) -> EvalResult<'tcx, Pointer> { - use self::Value::*; - Ok(match *self { - ByRef(PtrAndAlign { ptr, aligned }) => { - mem.read_maybe_aligned(aligned, |mem| mem.read_ptr_sized_unsigned(ptr.to_ptr()?))? - } - ByVal(ptr) | - ByValPair(ptr, _) => ptr, - }.into()) - } - - pub(super) fn into_ptr_vtable_pair>( - &self, - mem: &Memory<'a, 'tcx, M>, - ) -> EvalResult<'tcx, (Pointer, MemoryPointer)> { - use self::Value::*; - match *self { - ByRef(PtrAndAlign { - ptr: ref_ptr, - aligned, - }) => { - mem.read_maybe_aligned(aligned, |mem| { - 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()?, - )?.to_ptr()?; - Ok((ptr, vtable)) - }) - } - - ByValPair(ptr, vtable) => Ok((ptr.into(), vtable.to_ptr()?)), - - ByVal(PrimVal::Undef) => err!(ReadUndefBytes), - _ => bug!("expected ptr and vtable, got {:?}", self), - } - } - - pub(super) fn into_slice>( - &self, - mem: &Memory<'a, 'tcx, M>, - ) -> EvalResult<'tcx, (Pointer, u64)> { - use self::Value::*; - match *self { - ByRef(PtrAndAlign { - ptr: ref_ptr, - aligned, - }) => { - mem.read_maybe_aligned(aligned, |mem| { - 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)) - }) - } - ByValPair(ptr, val) => { - let len = val.to_u128()?; - assert_eq!(len as u64 as u128, len); - Ok((ptr.into(), len as u64)) - } - ByVal(PrimVal::Undef) => err!(ReadUndefBytes), - ByVal(_) => bug!("expected ptr and length, got {:?}", self), - } - } -} - -impl<'tcx> PrimVal { - pub fn from_u128(n: u128) -> Self { - PrimVal::Bytes(n) - } - - pub fn from_i128(n: i128) -> Self { - PrimVal::Bytes(n as u128) - } - - pub fn from_f32(f: f32) -> Self { - PrimVal::Bytes(f32_to_bytes(f)) - } - - pub fn from_f64(f: f64) -> Self { - PrimVal::Bytes(f64_to_bytes(f)) - } - - pub fn from_bool(b: bool) -> Self { - PrimVal::Bytes(b as u128) - } - - pub fn from_char(c: char) -> Self { - PrimVal::Bytes(c as u128) - } - - pub fn to_bytes(self) -> EvalResult<'tcx, u128> { - match self { - PrimVal::Bytes(b) => Ok(b), - PrimVal::Ptr(_) => err!(ReadPointerAsBytes), - PrimVal::Undef => err!(ReadUndefBytes), - } - } - - pub fn to_ptr(self) -> EvalResult<'tcx, MemoryPointer> { - match self { - PrimVal::Bytes(_) => err!(ReadBytesAsPointer), - PrimVal::Ptr(p) => Ok(p), - PrimVal::Undef => err!(ReadUndefBytes), - } - } - - pub fn is_bytes(self) -> bool { - match self { - PrimVal::Bytes(_) => true, - _ => false, - } - } - - pub fn is_ptr(self) -> bool { - match self { - PrimVal::Ptr(_) => true, - _ => false, - } - } - - pub fn is_undef(self) -> bool { - match self { - PrimVal::Undef => true, - _ => false, - } - } - - pub fn to_u128(self) -> EvalResult<'tcx, u128> { - self.to_bytes() - } - - pub fn to_u64(self) -> EvalResult<'tcx, u64> { - self.to_bytes().map(|b| { - assert_eq!(b as u64 as u128, b); - b as u64 - }) - } - - pub fn to_i32(self) -> EvalResult<'tcx, i32> { - self.to_bytes().map(|b| { - assert_eq!(b as i32 as u128, b); - b as i32 - }) - } - - pub fn to_i128(self) -> EvalResult<'tcx, i128> { - self.to_bytes().map(|b| b as i128) - } - - pub fn to_i64(self) -> EvalResult<'tcx, i64> { - self.to_bytes().map(|b| { - assert_eq!(b as i64 as u128, b); - b as i64 - }) - } - - pub fn to_f32(self) -> EvalResult<'tcx, f32> { - self.to_bytes().map(bytes_to_f32) - } - - pub fn to_f64(self) -> EvalResult<'tcx, f64> { - self.to_bytes().map(bytes_to_f64) - } - - pub fn to_bool(self) -> EvalResult<'tcx, bool> { - match self.to_bytes()? { - 0 => Ok(false), - 1 => Ok(true), - _ => err!(InvalidBool), - } - } -} - -impl PrimValKind { - pub fn is_int(self) -> bool { - use self::PrimValKind::*; - match self { - I8 | I16 | I32 | I64 | I128 | U8 | U16 | U32 | U64 | U128 => true, - _ => false, - } - } - - pub fn is_signed_int(self) -> bool { - use self::PrimValKind::*; - match self { - I8 | I16 | I32 | I64 | I128 => true, - _ => false, - } - } - - pub fn is_float(self) -> bool { - use self::PrimValKind::*; - match self { - F32 | F64 => true, - _ => false, - } - } - - pub fn from_uint_size(size: u64) -> Self { - match size { - 1 => PrimValKind::U8, - 2 => PrimValKind::U16, - 4 => PrimValKind::U32, - 8 => PrimValKind::U64, - 16 => PrimValKind::U128, - _ => bug!("can't make uint with size {}", size), - } - } - - pub fn from_int_size(size: u64) -> Self { - match size { - 1 => PrimValKind::I8, - 2 => PrimValKind::I16, - 4 => PrimValKind::I32, - 8 => PrimValKind::I64, - 16 => PrimValKind::I128, - _ => bug!("can't make int with size {}", size), - } - } - - pub fn is_ptr(self) -> bool { - use self::PrimValKind::*; - match self { - Ptr | FnPtr => true, - _ => false, - } - } -} diff --git a/src/librustc_mir/lib.rs b/src/librustc_mir/lib.rs deleted file mode 100644 index c640932e50e21..0000000000000 --- a/src/librustc_mir/lib.rs +++ /dev/null @@ -1,26 +0,0 @@ -#![feature( - i128_type, - rustc_private, - conservative_impl_trait, - never_type, - catch_expr, -)] - -// From rustc. -#[macro_use] -extern crate log; -extern crate log_settings; -#[macro_use] -extern crate rustc; -extern crate rustc_const_math; -extern crate rustc_data_structures; -extern crate syntax; - -// From crates.io. -extern crate byteorder; -#[macro_use] -extern crate lazy_static; -extern crate regex; -extern crate backtrace; - -pub mod interpret; From 8d546e8b9ae47ce7200db469cb8807f6df2dd3d3 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Fri, 6 Oct 2017 17:12:07 +0200 Subject: [PATCH 0004/3747] Use rustc's logging libraries in order to be able to log rustc::mir::interpret --- Cargo.lock | 96 ------------------------------------------------------ Cargo.toml | 3 -- 2 files changed, 99 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index ecc1e85596c5f..a66207a614f7a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5,17 +5,6 @@ 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)", "compiletest_rs 0.3.1 (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)", -] - -[[package]] -name = "aho-corasick" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "memchr 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -75,15 +64,6 @@ name = "dtoa" version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "env_logger" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "filetime" version = "0.1.10" @@ -102,11 +82,6 @@ name = "itoa" version = "0.3.2" source = "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" - [[package]] name = "libc" version = "0.2.30" @@ -117,14 +92,6 @@ name = "log" version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "log_settings" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "magenta" version = "0.1.1" @@ -142,14 +109,6 @@ dependencies = [ "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "memchr" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.30 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "num-traits" version = "0.1.40" @@ -169,23 +128,6 @@ dependencies = [ "magenta 0.1.1 (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" -dependencies = [ - "aho-corasick 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", - "memchr 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "regex-syntax 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "thread_local 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "regex-syntax" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "rustc-serialize" version = "0.3.24" @@ -252,40 +194,12 @@ dependencies = [ "rand 0.3.16 (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" -dependencies = [ - "lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[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" -dependencies = [ - "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "utf8-ranges" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "void" -version = "1.0.2" -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 bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d" "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" @@ -294,22 +208,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum custom_derive 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "ef8ae57c4978a2acd8b869ce6b9ca1dfe817bff704c220209fdef2c0b75a01b9" "checksum diff 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "0a515461b6c8c08419850ced27bc29e86166dcdcde8fbe76f8b1f0589bb49472" "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 filetime 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "5363ab8e4139b8568a6237db5248646e5a8a2f89bd5ccb02092182b11fd3e922" "checksum getopts 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)" = "65922871abd2f101a2eb0eaebadc66668e54a87ad9c3dd82520b5f86ede5eff9" "checksum itoa 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f74cf6ca1bdbc28496a2b9798ab7fccc2ca5a42cace95bb2b219577216a5fb90" -"checksum lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "3b37545ab726dd833ec6420aaba8231c5b320814b9029ad585555d2a03e94fbf" "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" "checksum magenta-sys 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "40d014c7011ac470ae28e2f76a02bfea4a8480f73e701353b49ad7a8d75f4699" -"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 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-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" @@ -318,8 +226,4 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "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 tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "87974a6f5c1dfb344d733055601650059a3363de2a6104819293baff662132d6" -"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" diff --git a/Cargo.toml b/Cargo.toml index 34cbfcc03a2fe..19ba30eb54864 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,9 +23,6 @@ path = "miri/lib.rs" [dependencies] byteorder = { version = "1.1", features = ["i128"]} -env_logger = "0.4.3" -log = "0.3.6" -log_settings = "0.1.1" cargo_metadata = { version = "0.2", optional = true } [features] From 072c02f9a3e1767a7b9121ef5217415bbbc8711f Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Fri, 6 Oct 2017 17:12:32 +0200 Subject: [PATCH 0005/3747] Use numbers instead of indentations Noone can differentiate between 8 and 9 spaces if they aren't aligned --- miri/bin/miri.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/miri/bin/miri.rs b/miri/bin/miri.rs index d38f63610a0e0..6ea1fac605e11 100644 --- a/miri/bin/miri.rs +++ b/miri/bin/miri.rs @@ -193,14 +193,13 @@ fn resource_limits_from_attributes(state: &CompileState) -> miri::ResourceLimits fn init_logger() { let format = |record: &log::LogRecord| { if record.level() == log::LogLevel::Trace { - // prepend spaces to indent the final string + // prepend frame number let indentation = log_settings::settings().indentation; format!( - "{lvl}:{module}:{indent: Date: Thu, 12 Oct 2017 11:13:34 +0200 Subject: [PATCH 0006/3747] Use host floats for the intrinsics that we don't have soft float impls for --- miri/intrinsic.rs | 58 +++++++++++++++++++++++++++++------------------ 1 file changed, 36 insertions(+), 22 deletions(-) diff --git a/miri/intrinsic.rs b/miri/intrinsic.rs index b41a753519712..aa17422159c47 100644 --- a/miri/intrinsic.rs +++ b/miri/intrinsic.rs @@ -245,7 +245,8 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> "sinf32" | "fabsf32" | "cosf32" | "sqrtf32" | "expf32" | "exp2f32" | "logf32" | "log10f32" | "log2f32" | "floorf32" | "ceilf32" | "truncf32" => { - let f = self.value_to_primval(args[0])?.to_f32()?; + let f = self.value_to_primval(args[0])?.to_bytes()?; + let f = f32::from_bits(f as u32); let f = match intrinsic_name { "sinf32" => f.sin(), "fabsf32" => f.abs(), @@ -261,12 +262,13 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> "truncf32" => f.trunc(), _ => bug!(), }; - self.write_primval(dest, PrimVal::from_f32(f), dest_ty)?; + self.write_primval(dest, PrimVal::Bytes(f.to_bits() as u128), dest_ty)?; } "sinf64" | "fabsf64" | "cosf64" | "sqrtf64" | "expf64" | "exp2f64" | "logf64" | "log10f64" | "log2f64" | "floorf64" | "ceilf64" | "truncf64" => { - let f = self.value_to_primval(args[0])?.to_f64()?; + let f = self.value_to_primval(args[0])?.to_bytes()?; + let f = f64::from_bits(f as u64); let f = match intrinsic_name { "sinf64" => f.sin(), "fabsf64" => f.abs(), @@ -282,7 +284,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> "truncf64" => f.trunc(), _ => bug!(), }; - self.write_primval(dest, PrimVal::from_f64(f), dest_ty)?; + self.write_primval(dest, PrimVal::Bytes(f.to_bits() as u128), dest_ty)?; } "fadd_fast" | "fsub_fast" | "fmul_fast" | "fdiv_fast" | "frem_fast" => { @@ -413,63 +415,75 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> } "powf32" => { - let f = self.value_to_primval(args[0])?.to_f32()?; - let f2 = self.value_to_primval(args[1])?.to_f32()?; + let f = self.value_to_primval(args[0])?.to_bytes()?; + let f = f32::from_bits(f as u32); + let f2 = self.value_to_primval(args[1])?.to_bytes()?; + let f2 = f32::from_bits(f2 as u32); self.write_primval( dest, - PrimVal::from_f32(f.powf(f2)), + PrimVal::Bytes(f.powf(f2).to_bits() as u128), dest_ty, )?; } "powf64" => { - let f = self.value_to_primval(args[0])?.to_f64()?; - let f2 = self.value_to_primval(args[1])?.to_f64()?; + let f = self.value_to_primval(args[0])?.to_bytes()?; + let f = f64::from_bits(f as u64); + let f2 = self.value_to_primval(args[1])?.to_bytes()?; + let f2 = f64::from_bits(f2 as u64); self.write_primval( dest, - PrimVal::from_f64(f.powf(f2)), + PrimVal::Bytes(f.powf(f2).to_bits() as u128), dest_ty, )?; } "fmaf32" => { - let a = self.value_to_primval(args[0])?.to_f32()?; - let b = self.value_to_primval(args[1])?.to_f32()?; - let c = self.value_to_primval(args[2])?.to_f32()?; + let a = self.value_to_primval(args[0])?.to_bytes()?; + let a = f32::from_bits(a as u32); + let b = self.value_to_primval(args[1])?.to_bytes()?; + let b = f32::from_bits(b as u32); + let c = self.value_to_primval(args[2])?.to_bytes()?; + let c = f32::from_bits(c as u32); self.write_primval( dest, - PrimVal::from_f32(a * b + c), + PrimVal::Bytes((a * b + c).to_bits() as u128), dest_ty, )?; } "fmaf64" => { - let a = self.value_to_primval(args[0])?.to_f64()?; - let b = self.value_to_primval(args[1])?.to_f64()?; - let c = self.value_to_primval(args[2])?.to_f64()?; + let a = self.value_to_primval(args[0])?.to_bytes()?; + let a = f64::from_bits(a as u64); + let b = self.value_to_primval(args[1])?.to_bytes()?; + let b = f64::from_bits(b as u64); + let c = self.value_to_primval(args[2])?.to_bytes()?; + let c = f64::from_bits(c as u64); self.write_primval( dest, - PrimVal::from_f64(a * b + c), + PrimVal::Bytes((a * b + c).to_bits() as u128), dest_ty, )?; } "powif32" => { - let f = self.value_to_primval(args[0])?.to_f32()?; + let f = self.value_to_primval(args[0])?.to_bytes()?; + let f = f32::from_bits(f as u32); let i = self.value_to_primval(args[1])?.to_i128()?; self.write_primval( dest, - PrimVal::from_f32(f.powi(i as i32)), + PrimVal::Bytes(f.powi(i as i32).to_bits() as u128), dest_ty, )?; } "powif64" => { - let f = self.value_to_primval(args[0])?.to_f64()?; + let f = self.value_to_primval(args[0])?.to_bytes()?; + let f = f64::from_bits(f as u64); let i = self.value_to_primval(args[1])?.to_i128()?; self.write_primval( dest, - PrimVal::from_f64(f.powi(i as i32)), + PrimVal::Bytes(f.powi(i as i32).to_bits() as u128), dest_ty, )?; } From 042430270f6c1561f6496359bb488d2547672f00 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Thu, 12 Oct 2017 11:13:56 +0200 Subject: [PATCH 0007/3747] repeat expressions abort due to OOM instead of execution time exhaustion --- tests/compile-fail/repeat2.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/compile-fail/repeat2.rs b/tests/compile-fail/repeat2.rs index d489342b8599c..61aa855a798f8 100644 --- a/tests/compile-fail/repeat2.rs +++ b/tests/compile-fail/repeat2.rs @@ -1,5 +1,5 @@ fn main() { let data: [u8; 1024*1024*1024] = [42; 1024*1024*1024]; - //~^ ERROR: reached the configured maximum execution time + //~^ ERROR: tried to allocate assert_eq!(data.len(), 1024*1024*1024); } From 25e0f5b5db8f7770858f3807e4873873b5773dd6 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Mon, 16 Oct 2017 16:21:49 +0200 Subject: [PATCH 0008/3747] Rustup --- miri/bin/miri.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/miri/bin/miri.rs b/miri/bin/miri.rs index 6ea1fac605e11..d74c05c0462d9 100644 --- a/miri/bin/miri.rs +++ b/miri/bin/miri.rs @@ -116,7 +116,7 @@ fn after_analysis<'a, 'tcx>(state: &mut CompileState<'a, 'tcx>) { let did = self.1.hir.body_owner_def_id(body_id); println!( "running test: {}", - self.1.hir.def_path(did).to_string(self.1) + self.1.def_path_debug_str(did), ); miri::eval_main(self.1, did, None, self.0); self.2.session.abort_if_errors(); From 6dbfe23c4d1af109c894ff9d7d5da97c025584e5 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Thu, 2 Nov 2017 11:15:50 +0100 Subject: [PATCH 0009/3747] Rustup --- Cargo.lock | 229 ------------------------------------------------ miri/fn_call.rs | 4 +- miri/lib.rs | 2 +- 3 files changed, 3 insertions(+), 232 deletions(-) delete mode 100644 Cargo.lock diff --git a/Cargo.lock b/Cargo.lock deleted file mode 100644 index a66207a614f7a..0000000000000 --- a/Cargo.lock +++ /dev/null @@ -1,229 +0,0 @@ -[root] -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)", - "compiletest_rs 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "bitflags" -version = "0.7.0" -source = "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" -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 = "compiletest_rs" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "diff 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "filetime 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "getopts 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.30 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", - "tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "conv" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "custom_derive 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "custom_derive" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "diff" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "dtoa" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "filetime" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.30 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "getopts" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "itoa" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "libc" -version = "0.2.30" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "log" -version = "0.3.8" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "magenta" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "conv 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "magenta-sys 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "magenta-sys" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[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 = "rand" -version = "0.3.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "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)", -] - -[[package]] -name = "rustc-serialize" -version = "0.3.24" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[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.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)", -] - -[[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 = "tempdir" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "rand 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "unicode-xid" -version = "0.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[metadata] -"checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d" -"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 compiletest_rs 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "86f4663adfd113e17109c35c2067194eca782a5baf9c90f4696ca13d04631adb" -"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 diff 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "0a515461b6c8c08419850ced27bc29e86166dcdcde8fbe76f8b1f0589bb49472" -"checksum dtoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "09c3753c3db574d215cba4ea76018483895d7bff25a31b49ba45db21c48e50ab" -"checksum filetime 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "5363ab8e4139b8568a6237db5248646e5a8a2f89bd5ccb02092182b11fd3e922" -"checksum getopts 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)" = "65922871abd2f101a2eb0eaebadc66668e54a87ad9c3dd82520b5f86ede5eff9" -"checksum itoa 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f74cf6ca1bdbc28496a2b9798ab7fccc2ca5a42cace95bb2b219577216a5fb90" -"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 magenta 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4bf0336886480e671965f794bc9b6fce88503563013d1bfb7a502c81fe3ac527" -"checksum magenta-sys 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "40d014c7011ac470ae28e2f76a02bfea4a8480f73e701353b49ad7a8d75f4699" -"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 rand 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)" = "eb250fd207a4729c976794d03db689c9be1d634ab5a1c9da9492a13d8fecbcdf" -"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" -"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 tempdir 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "87974a6f5c1dfb344d733055601650059a3363de2a6104819293baff662132d6" -"checksum unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f860d7d29cf02cb2f3f359fd35991af3d30bac52c57d265a3c461074cb4dc" diff --git a/miri/fn_call.rs b/miri/fn_call.rs index 77a22ac9c35f5..6c393ded638d9 100644 --- a/miri/fn_call.rs +++ b/miri/fn_call.rs @@ -381,9 +381,9 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> promoted: None, }; // compute global if not cached - let val = match self.globals.get(&cid).cloned() { + let val = match self.tcx.interpret_interner.borrow().get_cached(cid) { Some(ptr) => ptr, - None => eval_body(self.tcx, instance, ty::ParamEnv::empty(traits::Reveal::All))?.0, + None => eval_body(self.tcx, instance, ty::ParamEnv::empty(traits::Reveal::All)).0?.0, }; let val = self.value_to_primval(ValTy { value: Value::ByRef(val), ty: args[0].ty })?.to_u64()?; if val == name { diff --git a/miri/lib.rs b/miri/lib.rs index 27bd3d5939f31..6e8571556602b 100644 --- a/miri/lib.rs +++ b/miri/lib.rs @@ -301,7 +301,7 @@ impl<'tcx> Machine<'tcx> for Evaluator { )?; ecx.memory.write_ptr_sized_unsigned(ptr, PrimVal::Bytes(0))?; ecx.memory.mark_static_initalized(ptr.alloc_id, mutability)?; - ecx.globals.insert( + ecx.tcx.interpret_interner.borrow_mut().cache( GlobalId { instance, promoted: None, From a107f14ed8abee5a4e0b3776ca55fe92438cccfd Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Tue, 21 Nov 2017 13:32:40 +0100 Subject: [PATCH 0010/3747] Rustup after layout optimizations --- miri/fn_call.rs | 11 +++-- miri/intrinsic.rs | 102 +++++++++++++++++++++++----------------------- miri/lib.rs | 9 ++-- 3 files changed, 63 insertions(+), 59 deletions(-) diff --git a/miri/fn_call.rs b/miri/fn_call.rs index 6c393ded638d9..4c17b4db33079 100644 --- a/miri/fn_call.rs +++ b/miri/fn_call.rs @@ -45,6 +45,8 @@ pub trait EvalContextExt<'tcx> { span: Span, sig: ty::FnSig<'tcx>, ) -> EvalResult<'tcx, bool>; + + fn write_null(&mut self, dest: Lvalue, dest_ty: Ty<'tcx>) -> EvalResult<'tcx>; } impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> { @@ -416,10 +418,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> // 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, ty::LvaluePreference::NoPreference) .ok_or(EvalErrorKind::AbiViolation("Wrong signature used for pthread_key_create: First argument must be a raw pointer.".to_owned()))?.ty; - let key_size = { - let layout = self.type_layout(key_type)?; - layout.size(&self.tcx.data_layout) - }; + let key_size = self.type_layout(key_type)?.size; // Create key and write it into the memory where key_ptr wants it let key = self.memory.create_tls_key(dtor) as u128; @@ -655,4 +654,8 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> self.goto_block(dest_block); return Ok(()); } + + fn write_null(&mut self, dest: Lvalue, dest_ty: Ty<'tcx>) -> EvalResult<'tcx> { + self.write_primval(dest, PrimVal::Bytes(0), dest_ty) + } } diff --git a/miri/intrinsic.rs b/miri/intrinsic.rs index aa17422159c47..79dc3c7fe2abb 100644 --- a/miri/intrinsic.rs +++ b/miri/intrinsic.rs @@ -1,7 +1,7 @@ use rustc::mir; use rustc::traits::Reveal; -use rustc::ty::layout::Layout; -use rustc::ty::{self, Ty}; +use rustc::ty::layout::TyLayout; +use rustc::ty; use rustc::mir::interpret::{EvalResult, Lvalue, LvalueExtra, PrimVal, PrimValKind, Value, Pointer, HasMemory, AccessKind, EvalContext, PtrAndAlign, ValTy}; @@ -14,8 +14,7 @@ pub trait EvalContextExt<'tcx> { instance: ty::Instance<'tcx>, args: &[ValTy<'tcx>], dest: Lvalue, - dest_ty: Ty<'tcx>, - dest_layout: &'tcx Layout, + dest_layout: TyLayout<'tcx>, target: mir::BasicBlock, ) -> EvalResult<'tcx>; } @@ -26,8 +25,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> instance: ty::Instance<'tcx>, args: &[ValTy<'tcx>], dest: Lvalue, - dest_ty: Ty<'tcx>, - dest_layout: &'tcx Layout, + dest_layout: TyLayout<'tcx>, target: mir::BasicBlock, ) -> EvalResult<'tcx> { let substs = instance.substs; @@ -37,7 +35,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> "align_offset" => { // FIXME: return a real value in case the target allocation has an // alignment bigger than the one requested - self.write_primval(dest, PrimVal::Bytes(u128::max_value()), dest_ty)?; + self.write_primval(dest, PrimVal::Bytes(u128::max_value()), dest_layout.ty)?; }, "add_with_overflow" => { @@ -46,7 +44,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> args[0], args[1], dest, - dest_ty, + dest_layout.ty, )? } @@ -56,7 +54,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> args[0], args[1], dest, - dest_ty, + dest_layout.ty, )? } @@ -66,7 +64,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> args[0], args[1], dest, - dest_ty, + dest_layout.ty, )? } @@ -74,7 +72,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> let offset = self.value_to_primval(args[1])?.to_i128()? as i64; let ptr = args[0].into_ptr(&self.memory)?; let result_ptr = self.wrapping_pointer_offset(ptr, substs.type_at(0), offset)?; - self.write_ptr(dest, result_ptr, dest_ty)?; + self.write_ptr(dest, result_ptr, dest_layout.ty)?; } "assume" => { @@ -139,8 +137,11 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> Value::ByValPair(..) => bug!("atomic_cxchg doesn't work with nonprimitives"), }; let (val, _) = self.binary_op(mir::BinOp::Eq, old, ty, expect_old, ty)?; - let dest = self.force_allocation(dest)?.to_ptr()?; - self.write_pair_to_ptr(old, val, dest, dest_ty)?; + let valty = ValTy { + value: Value::ByValPair(old, val), + ty: dest_layout.ty, + }; + self.write_value(valty, dest)?; self.write_primval( Lvalue::from_primval_ptr(ptr), change, @@ -238,9 +239,10 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> "discriminant_value" => { let ty = substs.type_at(0); - let adt_ptr = args[0].into_ptr(&self.memory)?.to_ptr()?; - let discr_val = self.read_discriminant_value(adt_ptr, ty)?; - self.write_primval(dest, PrimVal::Bytes(discr_val), dest_ty)?; + let adt_ptr = args[0].into_ptr(&self.memory)?; + let lval = Lvalue::from_primval_ptr(adt_ptr); + let discr_val = self.read_discriminant_value(lval, ty)?; + self.write_primval(dest, PrimVal::Bytes(discr_val), dest_layout.ty)?; } "sinf32" | "fabsf32" | "cosf32" | "sqrtf32" | "expf32" | "exp2f32" | "logf32" | @@ -262,7 +264,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> "truncf32" => f.trunc(), _ => bug!(), }; - self.write_primval(dest, PrimVal::Bytes(f.to_bits() as u128), dest_ty)?; + self.write_primval(dest, PrimVal::Bytes(f.to_bits() as u128), dest_layout.ty)?; } "sinf64" | "fabsf64" | "cosf64" | "sqrtf64" | "expf64" | "exp2f64" | "logf64" | @@ -284,7 +286,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> "truncf64" => f.trunc(), _ => bug!(), }; - self.write_primval(dest, PrimVal::Bytes(f.to_bits() as u128), dest_ty)?; + self.write_primval(dest, PrimVal::Bytes(f.to_bits() as u128), dest_layout.ty)?; } "fadd_fast" | "fsub_fast" | "fmul_fast" | "fdiv_fast" | "frem_fast" => { @@ -300,13 +302,13 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> _ => bug!(), }; let result = self.binary_op(op, a, ty, b, ty)?; - self.write_primval(dest, result.0, dest_ty)?; + self.write_primval(dest, result.0, dest_layout.ty)?; } "likely" | "unlikely" | "forget" => {} "init" => { - let size = self.type_size(dest_ty)?.expect("cannot zero unsized value"); + let size = self.type_size(dest_layout.ty)?.expect("cannot zero unsized value"); let init = |this: &mut Self, val: Value| { let zero_val = match val { Value::ByRef(PtrAndAlign { ptr, .. }) => { @@ -316,10 +318,10 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> } // TODO(solson): Revisit this, it's fishy to check for Undef here. Value::ByVal(PrimVal::Undef) => { - match this.ty_to_primval_kind(dest_ty) { + match this.ty_to_primval_kind(dest_layout.ty) { Ok(_) => Value::ByVal(PrimVal::Bytes(0)), Err(_) => { - let ptr = this.alloc_ptr_with_substs(dest_ty, substs)?; + let ptr = this.alloc_ptr_with_substs(dest_layout.ty, substs)?; let ptr = Pointer::from(PrimVal::Ptr(ptr)); this.memory.write_repeat(ptr, 0, size)?; Value::by_ref(ptr) @@ -349,15 +351,15 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> let elem_ty = substs.type_at(0); let elem_align = self.type_align(elem_ty)?; let align_val = PrimVal::from_u128(elem_align as u128); - self.write_primval(dest, align_val, dest_ty)?; + self.write_primval(dest, align_val, dest_layout.ty)?; } "pref_align_of" => { let ty = substs.type_at(0); let layout = self.type_layout(ty)?; - let align = layout.align(&self.tcx.data_layout).pref(); + let align = layout.align.pref(); let align_val = PrimVal::from_u128(align as u128); - self.write_primval(dest, align_val, dest_ty)?; + self.write_primval(dest, align_val, dest_layout.ty)?; } "move_val_init" => { @@ -373,7 +375,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> self.write_primval( dest, PrimVal::from_bool(needs_drop), - dest_ty, + dest_layout.ty, )?; } @@ -381,7 +383,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> let offset = self.value_to_primval(args[1])?.to_i128()? as i64; let ptr = args[0].into_ptr(&self.memory)?; let result_ptr = self.pointer_offset(ptr, substs.type_at(0), offset)?; - self.write_ptr(dest, result_ptr, dest_ty)?; + self.write_ptr(dest, result_ptr, dest_layout.ty)?; } "overflowing_sub" => { @@ -390,7 +392,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> args[0], args[1], dest, - dest_ty, + dest_layout.ty, )?; } @@ -400,7 +402,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> args[0], args[1], dest, - dest_ty, + dest_layout.ty, )?; } @@ -410,7 +412,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> args[0], args[1], dest, - dest_ty, + dest_layout.ty, )?; } @@ -422,7 +424,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> self.write_primval( dest, PrimVal::Bytes(f.powf(f2).to_bits() as u128), - dest_ty, + dest_layout.ty, )?; } @@ -434,7 +436,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> self.write_primval( dest, PrimVal::Bytes(f.powf(f2).to_bits() as u128), - dest_ty, + dest_layout.ty, )?; } @@ -448,7 +450,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> self.write_primval( dest, PrimVal::Bytes((a * b + c).to_bits() as u128), - dest_ty, + dest_layout.ty, )?; } @@ -462,7 +464,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> self.write_primval( dest, PrimVal::Bytes((a * b + c).to_bits() as u128), - dest_ty, + dest_layout.ty, )?; } @@ -473,7 +475,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> self.write_primval( dest, PrimVal::Bytes(f.powi(i as i32).to_bits() as u128), - dest_ty, + dest_layout.ty, )?; } @@ -484,7 +486,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> self.write_primval( dest, PrimVal::Bytes(f.powi(i as i32).to_bits() as u128), - dest_ty, + dest_layout.ty, )?; } @@ -493,7 +495,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> let size = self.type_size(ty)?.expect( "size_of intrinsic called on unsized value", ) as u128; - self.write_primval(dest, PrimVal::from_u128(size), dest_ty)?; + self.write_primval(dest, PrimVal::from_u128(size), dest_layout.ty)?; } "size_of_val" => { @@ -501,8 +503,8 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> let (size, _) = self.size_and_align_of_dst(ty, args[0].value)?; self.write_primval( dest, - PrimVal::from_u128(size as u128), - dest_ty, + PrimVal::from_u128(size.bytes() as u128), + dest_layout.ty, )?; } @@ -512,8 +514,8 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> let (_, align) = self.size_and_align_of_dst(ty, args[0].value)?; self.write_primval( dest, - PrimVal::from_u128(align as u128), - dest_ty, + PrimVal::from_u128(align.pref() as u128), + dest_layout.ty, )?; } @@ -521,12 +523,12 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> let ty = substs.type_at(0); let ty_name = ty.to_string(); let value = self.str_to_value(&ty_name)?; - self.write_value(ValTy { value, ty: dest_ty }, dest)?; + self.write_value(ValTy { value, ty: dest_layout.ty }, dest)?; } "type_id" => { let ty = substs.type_at(0); let n = self.tcx.type_id_hash(ty); - self.write_primval(dest, PrimVal::Bytes(n as u128), dest_ty)?; + self.write_primval(dest, PrimVal::Bytes(n as u128), dest_layout.ty)?; } "transmute" => { @@ -542,7 +544,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> } "unchecked_shl" => { - let bits = self.type_size(dest_ty)?.expect( + let bits = self.type_size(dest_layout.ty)?.expect( "intrinsic can't be called on unsized type", ) as u128 * 8; let rhs = self.value_to_primval(args[1])? @@ -557,12 +559,12 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> args[0], args[1], dest, - dest_ty, + dest_layout.ty, )?; } "unchecked_shr" => { - let bits = self.type_size(dest_ty)?.expect( + let bits = self.type_size(dest_layout.ty)?.expect( "intrinsic can't be called on unsized type", ) as u128 * 8; let rhs = self.value_to_primval(args[1])? @@ -577,7 +579,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> args[0], args[1], dest, - dest_ty, + dest_layout.ty, )?; } @@ -592,7 +594,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> args[0], args[1], dest, - dest_ty, + dest_layout.ty, )?; } @@ -607,12 +609,12 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> args[0], args[1], dest, - dest_ty, + dest_layout.ty, )?; } "uninit" => { - let size = dest_layout.size(&self.tcx.data_layout).bytes(); + let size = dest_layout.size.bytes(); let uninit = |this: &mut Self, val: Value| match val { Value::ByRef(PtrAndAlign { ptr, .. }) => { this.memory.mark_definedness(ptr, size, false)?; diff --git a/miri/lib.rs b/miri/lib.rs index 6e8571556602b..e5566bfe94719 100644 --- a/miri/lib.rs +++ b/miri/lib.rs @@ -11,7 +11,7 @@ extern crate rustc; extern crate syntax; use rustc::ty::{self, TyCtxt}; -use rustc::ty::layout::Layout; +use rustc::ty::layout::TyLayout; use rustc::hir::def_id::DefId; use rustc::mir; use rustc::traits; @@ -50,7 +50,7 @@ pub fn eval_main<'a, 'tcx: 'a>( let main_mir = ecx.load_mir(main_instance.def)?; let mut cleanup_ptr = None; // Pointer to be deallocated when we are done - if !main_mir.return_ty.is_nil() || main_mir.arg_count != 0 { + if !main_mir.return_ty().is_nil() || main_mir.arg_count != 0 { return err!(Unimplemented( "miri does not support main functions without `fn()` type signatures" .to_owned(), @@ -208,11 +208,10 @@ impl<'tcx> Machine<'tcx> for Evaluator { instance: ty::Instance<'tcx>, args: &[ValTy<'tcx>], dest: Lvalue, - dest_ty: ty::Ty<'tcx>, - dest_layout: &'tcx Layout, + dest_layout: TyLayout<'tcx>, target: mir::BasicBlock, ) -> EvalResult<'tcx> { - ecx.call_intrinsic(instance, args, dest, dest_ty, dest_layout, target) + ecx.call_intrinsic(instance, args, dest, dest_layout, target) } fn try_ptr_op<'a>( From 4e8b9451ab940b976b56072f3a341c6e93cbdc29 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Mon, 27 Nov 2017 14:31:51 +0100 Subject: [PATCH 0011/3747] Update error messages --- tests/compile-fail/deallocate-bad-alignment.rs | 2 +- tests/compile-fail/deallocate-bad-size.rs | 2 +- tests/compile-fail/invalid_bool.rs | 4 ++-- tests/compile-fail/match_char.rs | 4 ++-- tests/compile-fail/reallocate-bad-alignment-2.rs | 2 +- tests/compile-fail/reallocate-bad-alignment.rs | 2 +- tests/compile-fail/reallocate-bad-size.rs | 2 +- 7 files changed, 9 insertions(+), 9 deletions(-) diff --git a/tests/compile-fail/deallocate-bad-alignment.rs b/tests/compile-fail/deallocate-bad-alignment.rs index c1ae7477c81a8..b64740de81f4d 100644 --- a/tests/compile-fail/deallocate-bad-alignment.rs +++ b/tests/compile-fail/deallocate-bad-alignment.rs @@ -5,7 +5,7 @@ extern crate alloc; use alloc::heap::Heap; use alloc::allocator::*; -// error-pattern: tried to deallocate or reallocate using incorrect alignment or size +// error-pattern: incorrect alloc info: expected size 1 and align 2, got size 1 and align 1 fn main() { unsafe { diff --git a/tests/compile-fail/deallocate-bad-size.rs b/tests/compile-fail/deallocate-bad-size.rs index 5577f10736d2e..f5b82f65d2af3 100644 --- a/tests/compile-fail/deallocate-bad-size.rs +++ b/tests/compile-fail/deallocate-bad-size.rs @@ -5,7 +5,7 @@ extern crate alloc; use alloc::heap::Heap; use alloc::allocator::*; -// error-pattern: tried to deallocate or reallocate using incorrect alignment or size +// error-pattern: incorrect alloc info: expected size 2 and align 1, got size 1 and align 1 fn main() { unsafe { diff --git a/tests/compile-fail/invalid_bool.rs b/tests/compile-fail/invalid_bool.rs index c30c9b439a46b..9de2630797ece 100644 --- a/tests/compile-fail/invalid_bool.rs +++ b/tests/compile-fail/invalid_bool.rs @@ -1,4 +1,4 @@ fn main() { - let b = unsafe { std::mem::transmute::(2) }; //~ ERROR: invalid boolean value read - if b { unreachable!() } else { unreachable!() } + let b = unsafe { std::mem::transmute::(2) }; + if b { unreachable!() } else { unreachable!() } //~ ERROR: invalid boolean value read } diff --git a/tests/compile-fail/match_char.rs b/tests/compile-fail/match_char.rs index 4fee6e692bada..a91c7fef6aa1e 100644 --- a/tests/compile-fail/match_char.rs +++ b/tests/compile-fail/match_char.rs @@ -1,7 +1,7 @@ fn main() { assert!(std::char::from_u32(-1_i32 as u32).is_none()); - match unsafe { std::mem::transmute::(-1) } { //~ERROR tried to interpret an invalid 32-bit value as a char: 4294967295 - 'a' => {}, + match unsafe { std::mem::transmute::(-1) } { + 'a' => {}, //~ERROR tried to interpret an invalid 32-bit value as a char: 4294967295 'b' => {}, _ => {}, } diff --git a/tests/compile-fail/reallocate-bad-alignment-2.rs b/tests/compile-fail/reallocate-bad-alignment-2.rs index cd6214440ff26..fae8246c5d29c 100644 --- a/tests/compile-fail/reallocate-bad-alignment-2.rs +++ b/tests/compile-fail/reallocate-bad-alignment-2.rs @@ -5,7 +5,7 @@ extern crate alloc; use alloc::heap::Heap; use alloc::allocator::*; -// error-pattern: tried to deallocate or reallocate using incorrect alignment or size +// error-pattern: incorrect alloc info: expected size 1 and align 2, got size 1 and align 1 fn main() { unsafe { diff --git a/tests/compile-fail/reallocate-bad-alignment.rs b/tests/compile-fail/reallocate-bad-alignment.rs index da5fe1d81909d..6a928de07eec3 100644 --- a/tests/compile-fail/reallocate-bad-alignment.rs +++ b/tests/compile-fail/reallocate-bad-alignment.rs @@ -5,7 +5,7 @@ extern crate alloc; use alloc::heap::Heap; use alloc::allocator::*; -// error-pattern: tried to deallocate or reallocate using incorrect alignment or size +// error-pattern: incorrect alloc info: expected size 1 and align 1, got size 1 and align 2 fn main() { unsafe { diff --git a/tests/compile-fail/reallocate-bad-size.rs b/tests/compile-fail/reallocate-bad-size.rs index 953178742c46f..d57c610d9337f 100644 --- a/tests/compile-fail/reallocate-bad-size.rs +++ b/tests/compile-fail/reallocate-bad-size.rs @@ -5,7 +5,7 @@ extern crate alloc; use alloc::heap::Heap; use alloc::allocator::*; -// error-pattern: tried to deallocate or reallocate using incorrect alignment or size +// error-pattern: incorrect alloc info: expected size 2 and align 1, got size 1 and align 1 fn main() { unsafe { From ab0a805440ccd4d254d77b6214440e5382f91307 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Mon, 27 Nov 2017 14:32:09 +0100 Subject: [PATCH 0012/3747] Use correct alignment --- miri/intrinsic.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/miri/intrinsic.rs b/miri/intrinsic.rs index 79dc3c7fe2abb..ccc2a9dd25741 100644 --- a/miri/intrinsic.rs +++ b/miri/intrinsic.rs @@ -514,7 +514,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> let (_, align) = self.size_and_align_of_dst(ty, args[0].value)?; self.write_primval( dest, - PrimVal::from_u128(align.pref() as u128), + PrimVal::from_u128(align.abi() as u128), dest_layout.ty, )?; } From fd77411a1841f4b19ee80c5f1c623b605ac22594 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Thu, 30 Nov 2017 12:49:19 +0100 Subject: [PATCH 0013/3747] Compiler bug --- tests/run-pass/{packed_struct.rs => packed_struct.rs_broken} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename tests/run-pass/{packed_struct.rs => packed_struct.rs_broken} (100%) diff --git a/tests/run-pass/packed_struct.rs b/tests/run-pass/packed_struct.rs_broken similarity index 100% rename from tests/run-pass/packed_struct.rs rename to tests/run-pass/packed_struct.rs_broken From bf26b96dc7506b2f1fac9265489a6f3cd4d99dfc Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Tue, 5 Dec 2017 17:06:03 +0100 Subject: [PATCH 0014/3747] Update to latest rustc changes --- .gitignore | 1 + Cargo.toml | 2 +- miri/fn_call.rs | 2 +- miri/lib.rs | 10 +++++----- miri/tls.rs | 2 +- tests/compile-fail/invalid_bool.rs | 4 ++-- tests/compile-fail/match_char.rs | 4 ++-- tests/compile-fail/never_say_never.rs | 2 +- tests/compile-fail/reference_to_packed.rs | 2 +- tests/run-pass/issue-36278-prefix-nesting.rs | 3 +++ 10 files changed, 18 insertions(+), 14 deletions(-) diff --git a/.gitignore b/.gitignore index d32d9eb99afd2..dcca7ec10a30d 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ tex/*/out *.dot *.mir *.rs.bk +Cargo.lock diff --git a/Cargo.toml b/Cargo.toml index 19ba30eb54864..9d1f615e8d1b1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -29,7 +29,7 @@ cargo_metadata = { version = "0.2", optional = true } cargo_miri = ["cargo_metadata"] [dev-dependencies] -compiletest_rs = { version = "0.3", features = ["tmp"] } +compiletest_rs = { version = "0.3.3", features = ["tmp"] } [workspace] exclude = ["xargo", "cargo-miri-test", "rustc_tests"] diff --git a/miri/fn_call.rs b/miri/fn_call.rs index 4c17b4db33079..adb235edb67bb 100644 --- a/miri/fn_call.rs +++ b/miri/fn_call.rs @@ -187,7 +187,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> .to_owned(), ), )?; - let arg_dest = self.eval_lvalue(&mir::Lvalue::Local(arg_local))?; + let arg_dest = self.eval_lvalue(&mir::Place::Local(arg_local))?; self.write_ptr(arg_dest, data, u8_ptr_ty)?; assert!(args.next().is_none(), "__rust_maybe_catch_panic argument has more arguments than expected"); diff --git a/miri/lib.rs b/miri/lib.rs index e5566bfe94719..b03518468b691 100644 --- a/miri/lib.rs +++ b/miri/lib.rs @@ -87,7 +87,7 @@ pub fn eval_main<'a, 'tcx: 'a>( // First argument: pointer to main() let main_ptr = ecx.memory_mut().create_fn_alloc(main_instance); - let dest = ecx.eval_lvalue(&mir::Lvalue::Local(args.next().unwrap()))?; + let dest = ecx.eval_lvalue(&mir::Place::Local(args.next().unwrap()))?; let main_ty = main_instance.def.def_ty(ecx.tcx); let main_ptr_ty = ecx.tcx.mk_fn_ptr(main_ty.fn_sig(ecx.tcx)); ecx.write_value( @@ -99,13 +99,13 @@ pub fn eval_main<'a, 'tcx: 'a>( )?; // Second argument (argc): 1 - let dest = ecx.eval_lvalue(&mir::Lvalue::Local(args.next().unwrap()))?; + let dest = ecx.eval_lvalue(&mir::Place::Local(args.next().unwrap()))?; let ty = ecx.tcx.types.isize; ecx.write_primval(dest, PrimVal::Bytes(1), ty)?; // FIXME: extract main source file path // Third argument (argv): &[b"foo"] - let dest = ecx.eval_lvalue(&mir::Lvalue::Local(args.next().unwrap()))?; + let dest = ecx.eval_lvalue(&mir::Place::Local(args.next().unwrap()))?; let ty = ecx.tcx.mk_imm_ptr(ecx.tcx.mk_imm_ptr(ecx.tcx.types.u8)); let foo = ecx.memory.allocate_cached(b"foo\0"); let ptr_size = ecx.memory.pointer_size(); @@ -261,7 +261,7 @@ impl<'tcx> Machine<'tcx> for Evaluator { let usize = ecx.tcx.types.usize; // First argument: size - let dest = ecx.eval_lvalue(&mir::Lvalue::Local(args.next().unwrap()))?; + let dest = ecx.eval_lvalue(&mir::Place::Local(args.next().unwrap()))?; ecx.write_value( ValTy { value: Value::ByVal(PrimVal::Bytes(size as u128)), @@ -271,7 +271,7 @@ impl<'tcx> Machine<'tcx> for Evaluator { )?; // Second argument: align - let dest = ecx.eval_lvalue(&mir::Lvalue::Local(args.next().unwrap()))?; + let dest = ecx.eval_lvalue(&mir::Place::Local(args.next().unwrap()))?; ecx.write_value( ValTy { value: Value::ByVal(PrimVal::Bytes(align as u128)), diff --git a/miri/tls.rs b/miri/tls.rs index e592478f6f9e6..8ec31f00e7f1c 100644 --- a/miri/tls.rs +++ b/miri/tls.rs @@ -125,7 +125,7 @@ impl<'a, 'tcx: 'a> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, Evaluator> { let arg_local = self.frame().mir.args_iter().next().ok_or( EvalErrorKind::AbiViolation("TLS dtor does not take enough arguments.".to_owned()), )?; - let dest = self.eval_lvalue(&mir::Lvalue::Local(arg_local))?; + let dest = self.eval_lvalue(&mir::Place::Local(arg_local))?; let ty = self.tcx.mk_mut_ptr(self.tcx.types.u8); self.write_ptr(dest, ptr, ty)?; diff --git a/tests/compile-fail/invalid_bool.rs b/tests/compile-fail/invalid_bool.rs index 9de2630797ece..c30c9b439a46b 100644 --- a/tests/compile-fail/invalid_bool.rs +++ b/tests/compile-fail/invalid_bool.rs @@ -1,4 +1,4 @@ fn main() { - let b = unsafe { std::mem::transmute::(2) }; - if b { unreachable!() } else { unreachable!() } //~ ERROR: invalid boolean value read + let b = unsafe { std::mem::transmute::(2) }; //~ ERROR: invalid boolean value read + if b { unreachable!() } else { unreachable!() } } diff --git a/tests/compile-fail/match_char.rs b/tests/compile-fail/match_char.rs index a91c7fef6aa1e..4fee6e692bada 100644 --- a/tests/compile-fail/match_char.rs +++ b/tests/compile-fail/match_char.rs @@ -1,7 +1,7 @@ fn main() { assert!(std::char::from_u32(-1_i32 as u32).is_none()); - match unsafe { std::mem::transmute::(-1) } { - 'a' => {}, //~ERROR tried to interpret an invalid 32-bit value as a char: 4294967295 + match unsafe { std::mem::transmute::(-1) } { //~ERROR tried to interpret an invalid 32-bit value as a char: 4294967295 + 'a' => {}, 'b' => {}, _ => {}, } diff --git a/tests/compile-fail/never_say_never.rs b/tests/compile-fail/never_say_never.rs index 6aa4e281818ca..71306cc62bf7f 100644 --- a/tests/compile-fail/never_say_never.rs +++ b/tests/compile-fail/never_say_never.rs @@ -7,7 +7,7 @@ fn main() { let y = &5; let x: ! = unsafe { - *(y as *const _ as *const !) //~ ERROR tried to access a dead local variable + *(y as *const _ as *const !) //~ ERROR entered unreachable code }; f(x) } diff --git a/tests/compile-fail/reference_to_packed.rs b/tests/compile-fail/reference_to_packed.rs index cc927f879504a..064386b3d010c 100644 --- a/tests/compile-fail/reference_to_packed.rs +++ b/tests/compile-fail/reference_to_packed.rs @@ -14,6 +14,6 @@ fn main() { x: 42, y: 99, }; - let p = &foo.x; + let p = unsafe { &foo.x }; let i = *p; //~ ERROR tried to access memory with alignment 1, but alignment 4 is required } diff --git a/tests/run-pass/issue-36278-prefix-nesting.rs b/tests/run-pass/issue-36278-prefix-nesting.rs index 95269d0569dec..dc807bfde7a34 100644 --- a/tests/run-pass/issue-36278-prefix-nesting.rs +++ b/tests/run-pass/issue-36278-prefix-nesting.rs @@ -22,7 +22,10 @@ fn main() { let size_of_sized; let size_of_unsized; let x: Box> = Box::new(P([0; SZ], P([0; SZ], [0; 0]))); size_of_sized = mem::size_of_val::>(&x); + let align_of_sized = mem::align_of_val::>(&x); let y: Box> = x; size_of_unsized = mem::size_of_val::>(&y); assert_eq!(size_of_sized, size_of_unsized); + assert_eq!(align_of_sized, 1); + assert_eq!(mem::align_of_val::>(&y), 1); } From dd630a2a263105f104b82dd53a1b9b90d4206a3d Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Wed, 6 Dec 2017 08:39:31 +0100 Subject: [PATCH 0015/3747] Rename lvalue to place --- miri/fn_call.rs | 30 +++++++++++++++--------------- miri/intrinsic.rs | 32 ++++++++++++++++---------------- miri/lib.rs | 20 ++++++++++---------- miri/tls.rs | 6 +++--- tex/report/miri-report.tex | 10 +++++----- 5 files changed, 49 insertions(+), 49 deletions(-) diff --git a/miri/fn_call.rs b/miri/fn_call.rs index adb235edb67bb..1d02c979ba74e 100644 --- a/miri/fn_call.rs +++ b/miri/fn_call.rs @@ -21,7 +21,7 @@ pub trait EvalContextExt<'tcx> { &mut self, def_id: DefId, args: &[ValTy<'tcx>], - dest: Lvalue, + dest: Place, dest_ty: Ty<'tcx>, dest_block: mir::BasicBlock, ) -> EvalResult<'tcx>; @@ -31,7 +31,7 @@ pub trait EvalContextExt<'tcx> { fn call_missing_fn( &mut self, instance: ty::Instance<'tcx>, - destination: Option<(Lvalue, mir::BasicBlock)>, + destination: Option<(Place, mir::BasicBlock)>, args: &[ValTy<'tcx>], sig: ty::FnSig<'tcx>, path: String, @@ -40,20 +40,20 @@ pub trait EvalContextExt<'tcx> { fn eval_fn_call( &mut self, instance: ty::Instance<'tcx>, - destination: Option<(Lvalue, mir::BasicBlock)>, + destination: Option<(Place, mir::BasicBlock)>, args: &[ValTy<'tcx>], span: Span, sig: ty::FnSig<'tcx>, ) -> EvalResult<'tcx, bool>; - fn write_null(&mut self, dest: Lvalue, dest_ty: Ty<'tcx>) -> EvalResult<'tcx>; + fn write_null(&mut self, dest: Place, dest_ty: Ty<'tcx>) -> EvalResult<'tcx>; } impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> { fn eval_fn_call( &mut self, instance: ty::Instance<'tcx>, - destination: Option<(Lvalue, mir::BasicBlock)>, + destination: Option<(Place, mir::BasicBlock)>, args: &[ValTy<'tcx>], span: Span, sig: ty::FnSig<'tcx>, @@ -75,16 +75,16 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> Err(other) => return Err(other), }; - let (return_lvalue, return_to_block) = match destination { - Some((lvalue, block)) => (lvalue, StackPopCleanup::Goto(block)), - None => (Lvalue::undef(), StackPopCleanup::None), + let (return_place, return_to_block) = match destination { + Some((place, block)) => (place, StackPopCleanup::Goto(block)), + None => (Place::undef(), StackPopCleanup::None), }; self.push_stack_frame( instance, span, mir, - return_lvalue, + return_place, return_to_block, )?; @@ -95,7 +95,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> &mut self, def_id: DefId, args: &[ValTy<'tcx>], - dest: Lvalue, + dest: Place, dest_ty: Ty<'tcx>, dest_block: mir::BasicBlock, ) -> EvalResult<'tcx> { @@ -176,7 +176,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> f_instance, mir.span, mir, - Lvalue::undef(), + Place::undef(), StackPopCleanup::Goto(dest_block), )?; let mut args = self.frame().mir.args_iter(); @@ -187,7 +187,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> .to_owned(), ), )?; - let arg_dest = self.eval_lvalue(&mir::Place::Local(arg_local))?; + let arg_dest = self.eval_place(&mir::Place::Local(arg_local))?; self.write_ptr(arg_dest, data, u8_ptr_ty)?; assert!(args.next().is_none(), "__rust_maybe_catch_panic argument has more arguments than expected"); @@ -416,7 +416,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> }; // 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, ty::LvaluePreference::NoPreference) + let key_type = args[0].ty.builtin_deref(true, ty::PlacePreference::NoPreference) .ok_or(EvalErrorKind::AbiViolation("Wrong signature used for pthread_key_create: First argument must be a raw pointer.".to_owned()))?.ty; let key_size = self.type_layout(key_type)?.size; @@ -516,7 +516,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> fn call_missing_fn( &mut self, instance: ty::Instance<'tcx>, - destination: Option<(Lvalue, mir::BasicBlock)>, + destination: Option<(Place, mir::BasicBlock)>, args: &[ValTy<'tcx>], sig: ty::FnSig<'tcx>, path: String, @@ -655,7 +655,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> return Ok(()); } - fn write_null(&mut self, dest: Lvalue, dest_ty: Ty<'tcx>) -> EvalResult<'tcx> { + fn write_null(&mut self, dest: Place, dest_ty: Ty<'tcx>) -> EvalResult<'tcx> { self.write_primval(dest, PrimVal::Bytes(0), dest_ty) } } diff --git a/miri/intrinsic.rs b/miri/intrinsic.rs index ccc2a9dd25741..0db3f4f2542fa 100644 --- a/miri/intrinsic.rs +++ b/miri/intrinsic.rs @@ -3,7 +3,7 @@ use rustc::traits::Reveal; use rustc::ty::layout::TyLayout; use rustc::ty; -use rustc::mir::interpret::{EvalResult, Lvalue, LvalueExtra, PrimVal, PrimValKind, Value, Pointer, +use rustc::mir::interpret::{EvalResult, Place, PlaceExtra, PrimVal, PrimValKind, Value, Pointer, HasMemory, AccessKind, EvalContext, PtrAndAlign, ValTy}; use helpers::EvalContextExt as HelperEvalContextExt; @@ -13,7 +13,7 @@ pub trait EvalContextExt<'tcx> { &mut self, instance: ty::Instance<'tcx>, args: &[ValTy<'tcx>], - dest: Lvalue, + dest: Place, dest_layout: TyLayout<'tcx>, target: mir::BasicBlock, ) -> EvalResult<'tcx>; @@ -24,7 +24,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> &mut self, instance: ty::Instance<'tcx>, args: &[ValTy<'tcx>], - dest: Lvalue, + dest: Place, dest_layout: TyLayout<'tcx>, target: mir::BasicBlock, ) -> EvalResult<'tcx> { @@ -119,7 +119,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> }; self.write_primval(dest, old, ty)?; self.write_primval( - Lvalue::from_primval_ptr(ptr), + Place::from_primval_ptr(ptr), change, ty, )?; @@ -143,7 +143,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> }; self.write_value(valty, dest)?; self.write_primval( - Lvalue::from_primval_ptr(ptr), + Place::from_primval_ptr(ptr), change, ty, )?; @@ -196,7 +196,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> }; // FIXME: what do atomics do on overflow? let (val, _) = self.binary_op(op, old, ty, change, ty)?; - self.write_primval(Lvalue::from_primval_ptr(ptr), val, ty)?; + self.write_primval(Place::from_primval_ptr(ptr), val, ty)?; } "breakpoint" => unimplemented!(), // halt miri @@ -240,8 +240,8 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> "discriminant_value" => { let ty = substs.type_at(0); let adt_ptr = args[0].into_ptr(&self.memory)?; - let lval = Lvalue::from_primval_ptr(adt_ptr); - let discr_val = self.read_discriminant_value(lval, ty)?; + let place = Place::from_primval_ptr(adt_ptr); + let discr_val = self.read_discriminant_value(place, ty)?; self.write_primval(dest, PrimVal::Bytes(discr_val), dest_layout.ty)?; } @@ -336,12 +336,12 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> Ok(zero_val) }; match dest { - Lvalue::Local { frame, local } => self.modify_local(frame, local, init)?, - Lvalue::Ptr { + Place::Local { frame, local } => self.modify_local(frame, local, init)?, + Place::Ptr { ptr: PtrAndAlign { ptr, aligned: true }, - extra: LvalueExtra::None, + extra: PlaceExtra::None, } => self.memory.write_repeat(ptr, 0, size)?, - Lvalue::Ptr { .. } => { + Place::Ptr { .. } => { bug!("init intrinsic tried to write to fat or unaligned ptr target") } } @@ -623,12 +623,12 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> _ => Ok(Value::ByVal(PrimVal::Undef)), }; match dest { - Lvalue::Local { frame, local } => self.modify_local(frame, local, uninit)?, - Lvalue::Ptr { + Place::Local { frame, local } => self.modify_local(frame, local, uninit)?, + Place::Ptr { ptr: PtrAndAlign { ptr, aligned: true }, - extra: LvalueExtra::None, + extra: PlaceExtra::None, } => self.memory.mark_definedness(ptr, size, false)?, - Lvalue::Ptr { .. } => { + Place::Ptr { .. } => { bug!("uninit intrinsic tried to write to fat or unaligned ptr target") } } diff --git a/miri/lib.rs b/miri/lib.rs index b03518468b691..399418f6734bc 100644 --- a/miri/lib.rs +++ b/miri/lib.rs @@ -79,7 +79,7 @@ pub fn eval_main<'a, 'tcx: 'a>( start_instance, start_mir.span, start_mir, - Lvalue::from_ptr(ret_ptr), + Place::from_ptr(ret_ptr), StackPopCleanup::None, )?; @@ -87,7 +87,7 @@ pub fn eval_main<'a, 'tcx: 'a>( // First argument: pointer to main() let main_ptr = ecx.memory_mut().create_fn_alloc(main_instance); - let dest = ecx.eval_lvalue(&mir::Place::Local(args.next().unwrap()))?; + let dest = ecx.eval_place(&mir::Place::Local(args.next().unwrap()))?; let main_ty = main_instance.def.def_ty(ecx.tcx); let main_ptr_ty = ecx.tcx.mk_fn_ptr(main_ty.fn_sig(ecx.tcx)); ecx.write_value( @@ -99,13 +99,13 @@ pub fn eval_main<'a, 'tcx: 'a>( )?; // Second argument (argc): 1 - let dest = ecx.eval_lvalue(&mir::Place::Local(args.next().unwrap()))?; + let dest = ecx.eval_place(&mir::Place::Local(args.next().unwrap()))?; let ty = ecx.tcx.types.isize; ecx.write_primval(dest, PrimVal::Bytes(1), ty)?; // FIXME: extract main source file path // Third argument (argv): &[b"foo"] - let dest = ecx.eval_lvalue(&mir::Place::Local(args.next().unwrap()))?; + let dest = ecx.eval_place(&mir::Place::Local(args.next().unwrap()))?; let ty = ecx.tcx.mk_imm_ptr(ecx.tcx.mk_imm_ptr(ecx.tcx.types.u8)); let foo = ecx.memory.allocate_cached(b"foo\0"); let ptr_size = ecx.memory.pointer_size(); @@ -120,7 +120,7 @@ pub fn eval_main<'a, 'tcx: 'a>( main_instance, main_mir.span, main_mir, - Lvalue::undef(), + Place::undef(), StackPopCleanup::None, )?; @@ -195,7 +195,7 @@ impl<'tcx> Machine<'tcx> for Evaluator { fn eval_fn_call<'a>( ecx: &mut EvalContext<'a, 'tcx, Self>, instance: ty::Instance<'tcx>, - destination: Option<(Lvalue, mir::BasicBlock)>, + destination: Option<(Place, mir::BasicBlock)>, args: &[ValTy<'tcx>], span: Span, sig: ty::FnSig<'tcx>, @@ -207,7 +207,7 @@ impl<'tcx> Machine<'tcx> for Evaluator { ecx: &mut rustc::mir::interpret::EvalContext<'a, 'tcx, Self>, instance: ty::Instance<'tcx>, args: &[ValTy<'tcx>], - dest: Lvalue, + dest: Place, dest_layout: TyLayout<'tcx>, target: mir::BasicBlock, ) -> EvalResult<'tcx> { @@ -237,7 +237,7 @@ impl<'tcx> Machine<'tcx> for Evaluator { fn box_alloc<'a>( ecx: &mut EvalContext<'a, 'tcx, Self>, ty: ty::Ty<'tcx>, - dest: Lvalue, + dest: Place, ) -> EvalResult<'tcx> { let size = ecx.type_size(ty)?.expect("box only works with sized types"); let align = ecx.type_align(ty)?; @@ -261,7 +261,7 @@ impl<'tcx> Machine<'tcx> for Evaluator { let usize = ecx.tcx.types.usize; // First argument: size - let dest = ecx.eval_lvalue(&mir::Place::Local(args.next().unwrap()))?; + let dest = ecx.eval_place(&mir::Place::Local(args.next().unwrap()))?; ecx.write_value( ValTy { value: Value::ByVal(PrimVal::Bytes(size as u128)), @@ -271,7 +271,7 @@ impl<'tcx> Machine<'tcx> for Evaluator { )?; // Second argument: align - let dest = ecx.eval_lvalue(&mir::Place::Local(args.next().unwrap()))?; + let dest = ecx.eval_place(&mir::Place::Local(args.next().unwrap()))?; ecx.write_value( ValTy { value: Value::ByVal(PrimVal::Bytes(align as u128)), diff --git a/miri/tls.rs b/miri/tls.rs index 8ec31f00e7f1c..0a0ba1c03b672 100644 --- a/miri/tls.rs +++ b/miri/tls.rs @@ -1,6 +1,6 @@ use rustc::{ty, mir}; -use super::{TlsKey, TlsEntry, EvalResult, EvalErrorKind, Pointer, Memory, Evaluator, Lvalue, +use super::{TlsKey, TlsEntry, EvalResult, EvalErrorKind, Pointer, Memory, Evaluator, Place, StackPopCleanup, EvalContext}; pub trait MemoryExt<'tcx> { @@ -119,13 +119,13 @@ impl<'a, 'tcx: 'a> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, Evaluator> { instance, mir.span, mir, - Lvalue::undef(), + Place::undef(), StackPopCleanup::None, )?; let arg_local = self.frame().mir.args_iter().next().ok_or( EvalErrorKind::AbiViolation("TLS dtor does not take enough arguments.".to_owned()), )?; - let dest = self.eval_lvalue(&mir::Place::Local(arg_local))?; + let dest = self.eval_place(&mir::Place::Local(arg_local))?; let ty = self.tcx.mk_mut_ptr(self.tcx.types.u8); self.write_ptr(dest, ptr, ty)?; diff --git a/tex/report/miri-report.tex b/tex/report/miri-report.tex index f8bb37b911330..27a063de0272a 100644 --- a/tex/report/miri-report.tex +++ b/tex/report/miri-report.tex @@ -52,10 +52,10 @@ \section{Background} The Rust compiler generates an instance of \rust{Mir} for each function [\autoref{fig:mir}]. Each \rust{Mir} structure represents a control-flow graph for a given function, and contains a list of ``basic blocks'' which in turn contain a list of statements followed by a single terminator. Each -statement is of the form \rust{lvalue = rvalue}. An \rust{Lvalue} is used for referencing variables +statement is of the form \rust{place = rvalue}. An \rust{Place} is used for referencing variables and calculating addresses such as when dereferencing pointers, accessing fields, or indexing arrays. An \rust{Rvalue} represents the core set of operations possible in MIR, including reading a value -from an lvalue, performing math operations, creating new pointers, structures, and arrays, and so +from an place, performing math operations, creating new pointers, structures, and arrays, and so on. Finally, a terminator decides where control will flow next, optionally based on the value of a boolean or integer. @@ -73,7 +73,7 @@ \section{Background} } struct Statement { - lvalue: Lvalue, + place: Place, rvalue: Rvalue } @@ -99,7 +99,7 @@ \subsection{Basic operation} To investigate the possibility of executing Rust at compile-time I wrote an interpreter for MIR called Miri\footnote{\url{https://github.com/solson/miri}}. The structure of the interpreter closely mirrors the structure of MIR itself. It starts executing a function by iterating the statement list -in the starting basic block, translating the lvalue into a pointer and using the rvalue to decide +in the starting basic block, translating the place into a pointer and using the rvalue to decide what to write into that pointer. Evaluating the rvalue may involve reads (such as for the two sides of a binary operation) or construction of new values. When the terminator is reached, it is used to decide which basic block to jump to next. Finally, Miri repeats this entire process, reading @@ -343,7 +343,7 @@ \subsection{Aggregates} closures. Miri supports all common usage of all of these types. The main missing piece is to handle \texttt{\#[repr(..)]} annotations which adjust the layout of a \rust{struct} or \rust{enum}. -\subsection{Lvalue projections} +\subsection{Place projections} This category includes field accesses, dereferencing, accessing data in an \rust{enum} variant, and indexing arrays. Miri supports all of these, including nested projections such as From eccf680b5d191bb39ef2fc5ae51bf3909c312bbe Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Wed, 6 Dec 2017 15:03:24 +0100 Subject: [PATCH 0016/3747] Remove type_size and type_align calls --- miri/fn_call.rs | 11 ++++++----- miri/helpers.rs | 9 +++------ miri/intrinsic.rs | 37 +++++++++++++++---------------------- miri/lib.rs | 21 ++++++--------------- 4 files changed, 30 insertions(+), 48 deletions(-) diff --git a/miri/fn_call.rs b/miri/fn_call.rs index 1d02c979ba74e..8961ae4d2029c 100644 --- a/miri/fn_call.rs +++ b/miri/fn_call.rs @@ -1,4 +1,5 @@ use rustc::ty::{self, Ty}; +use rustc::ty::layout::LayoutOf; use rustc::hir::def_id::{DefId, CRATE_DEF_INDEX}; use rustc::mir; use syntax::attr; @@ -261,7 +262,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> let result = { let name_ptr = args[0].into_ptr(&mut self.memory)?.to_ptr()?; let name = self.memory.read_c_str(name_ptr)?; - match self.machine_data.env_vars.get(name) { + match self.machine.env_vars.get(name) { Some(&var) => PrimVal::Ptr(var), None => PrimVal::Bytes(0), } @@ -276,7 +277,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> 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_data.env_vars.remove(name)); + success = Some(self.machine.env_vars.remove(name)); } } } @@ -313,7 +314,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> self.memory.write_bytes(value_copy.into(), &value)?; let trailing_zero_ptr = value_copy.offset(value.len() as u64, &self)?.into(); self.memory.write_bytes(trailing_zero_ptr, &[0])?; - if let Some(var) = self.machine_data.env_vars.insert( + if let Some(var) = self.machine.env_vars.insert( name.to_owned(), value_copy, ) @@ -416,9 +417,9 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> }; // 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, ty::PlacePreference::NoPreference) + let key_type = args[0].ty.builtin_deref(true, ty::LvaluePreference::NoPreference) .ok_or(EvalErrorKind::AbiViolation("Wrong signature used for pthread_key_create: First argument must be a raw pointer.".to_owned()))?.ty; - let key_size = self.type_layout(key_type)?.size; + let key_size = self.layout_of(key_type)?.size; // Create key and write it into the memory where key_ptr wants it let key = self.memory.create_tls_key(dtor) as u128; diff --git a/miri/helpers.rs b/miri/helpers.rs index 3ee148afb2b22..9ca85a6018e10 100644 --- a/miri/helpers.rs +++ b/miri/helpers.rs @@ -1,6 +1,7 @@ use rustc::mir::interpret::{Pointer, EvalResult, PrimVal, EvalContext}; use rustc::ty::Ty; +use rustc::ty::layout::LayoutOf; pub trait EvalContextExt<'tcx> { fn wrapping_pointer_offset( @@ -26,9 +27,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> offset: i64, ) -> EvalResult<'tcx, Pointer> { // FIXME: assuming here that type size is < i64::max_value() - let pointee_size = self.type_size(pointee_ty)?.expect( - "cannot offset a pointer to an unsized type", - ) as i64; + let pointee_size = self.layout_of(pointee_ty)?.size.bytes() as i64; let offset = offset.overflowing_mul(pointee_size).0; ptr.wrapping_signed_offset(offset, self) } @@ -53,9 +52,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> }; } // FIXME: assuming here that type size is < i64::max_value() - let pointee_size = self.type_size(pointee_ty)?.expect( - "cannot offset a pointer to an unsized type", - ) as i64; + let pointee_size = self.layout_of(pointee_ty)?.size.bytes() as i64; return if let Some(offset) = offset.checked_mul(pointee_size) { let ptr = ptr.signed_offset(offset, self)?; // Do not do bounds-checking for integers; they can never alias a normal pointer anyway. diff --git a/miri/intrinsic.rs b/miri/intrinsic.rs index 0db3f4f2542fa..a509606aaaa09 100644 --- a/miri/intrinsic.rs +++ b/miri/intrinsic.rs @@ -1,6 +1,6 @@ use rustc::mir; use rustc::traits::Reveal; -use rustc::ty::layout::TyLayout; +use rustc::ty::layout::{TyLayout, LayoutOf}; use rustc::ty; use rustc::mir::interpret::{EvalResult, Place, PlaceExtra, PrimVal, PrimValKind, Value, Pointer, @@ -204,12 +204,13 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> "copy" | "copy_nonoverlapping" => { let elem_ty = substs.type_at(0); - let elem_size = self.type_size(elem_ty)?.expect("cannot copy unsized value"); + let elem_layout = self.layout_of(elem_ty)?; + let elem_size = elem_layout.size.bytes(); let count = self.value_to_primval(args[2])?.to_u64()?; if count * elem_size != 0 { // 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 = self.type_align(elem_ty)?; + let elem_align = elem_layout.align.abi(); let src = args[0].into_ptr(&self.memory)?; let dest = args[1].into_ptr(&self.memory)?; self.memory.copy( @@ -308,7 +309,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> "likely" | "unlikely" | "forget" => {} "init" => { - let size = self.type_size(dest_layout.ty)?.expect("cannot zero unsized value"); + let size = dest_layout.size.bytes(); let init = |this: &mut Self, val: Value| { let zero_val = match val { Value::ByRef(PtrAndAlign { ptr, .. }) => { @@ -321,7 +322,8 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> match this.ty_to_primval_kind(dest_layout.ty) { Ok(_) => Value::ByVal(PrimVal::Bytes(0)), Err(_) => { - let ptr = this.alloc_ptr_with_substs(dest_layout.ty, substs)?; + // FIXME(oli-obk): pass TyLayout to alloc_ptr instead of Ty + let ptr = this.alloc_ptr(dest_layout.ty)?; let ptr = Pointer::from(PrimVal::Ptr(ptr)); this.memory.write_repeat(ptr, 0, size)?; Value::by_ref(ptr) @@ -349,14 +351,14 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> "min_align_of" => { let elem_ty = substs.type_at(0); - let elem_align = self.type_align(elem_ty)?; + let elem_align = self.layout_of(elem_ty)?.align.abi(); let align_val = PrimVal::from_u128(elem_align as u128); self.write_primval(dest, align_val, dest_layout.ty)?; } "pref_align_of" => { let ty = substs.type_at(0); - let layout = self.type_layout(ty)?; + let layout = self.layout_of(ty)?; let align = layout.align.pref(); let align_val = PrimVal::from_u128(align as u128); self.write_primval(dest, align_val, dest_layout.ty)?; @@ -492,9 +494,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> "size_of" => { let ty = substs.type_at(0); - let size = self.type_size(ty)?.expect( - "size_of intrinsic called on unsized value", - ) as u128; + let size = self.layout_of(ty)?.size.bytes().into(); self.write_primval(dest, PrimVal::from_u128(size), dest_layout.ty)?; } @@ -544,9 +544,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> } "unchecked_shl" => { - let bits = self.type_size(dest_layout.ty)?.expect( - "intrinsic can't be called on unsized type", - ) as u128 * 8; + let bits = dest_layout.size.bytes() as u128 * 8; let rhs = self.value_to_primval(args[1])? .to_bytes()?; if rhs >= bits { @@ -564,9 +562,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> } "unchecked_shr" => { - let bits = self.type_size(dest_layout.ty)?.expect( - "intrinsic can't be called on unsized type", - ) as u128 * 8; + let bits = dest_layout.size.bytes() as u128 * 8; let rhs = self.value_to_primval(args[1])? .to_bytes()?; if rhs >= bits { @@ -636,18 +632,15 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> "write_bytes" => { let ty = substs.type_at(0); - let ty_align = self.type_align(ty)?; + let ty_layout = self.layout_of(ty)?; let val_byte = self.value_to_primval(args[1])?.to_u128()? as u8; - let size = self.type_size(ty)?.expect( - "write_bytes() type must be sized", - ); let ptr = args[0].into_ptr(&self.memory)?; let count = self.value_to_primval(args[2])?.to_u64()?; 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, Some(AccessKind::Write))?; - self.memory.write_repeat(ptr, val_byte, size * count)?; + self.memory.check_align(ptr, ty_layout.align.abi(), Some(AccessKind::Write))?; + self.memory.write_repeat(ptr, val_byte, ty_layout.size.bytes() * count)?; } } diff --git a/miri/lib.rs b/miri/lib.rs index 399418f6734bc..398062b8c2245 100644 --- a/miri/lib.rs +++ b/miri/lib.rs @@ -11,7 +11,7 @@ extern crate rustc; extern crate syntax; use rustc::ty::{self, TyCtxt}; -use rustc::ty::layout::TyLayout; +use rustc::ty::layout::{TyLayout, LayoutOf}; use rustc::hir::def_id::DefId; use rustc::mir; use rustc::traits; @@ -141,7 +141,7 @@ pub fn eval_main<'a, 'tcx: 'a>( Ok(()) } - let mut ecx = EvalContext::new(tcx, limits, Default::default(), Default::default()); + let mut ecx = EvalContext::new(tcx, ty::ParamEnv::empty(traits::Reveal::All), limits, Default::default(), Default::default()); match run_main(&mut ecx, main_id, start_wrapper) { Ok(()) => { let leaks = ecx.memory().leak_report(); @@ -155,9 +155,8 @@ pub fn eval_main<'a, 'tcx: 'a>( } } -pub struct Evaluator; #[derive(Default)] -pub struct EvaluatorData { +pub struct Evaluator { /// Environment variables set by `setenv` /// Miri does not expose env vars from the host to the emulated program pub(crate) env_vars: HashMap, MemoryPointer>, @@ -181,16 +180,9 @@ pub struct MemoryData<'tcx> { } impl<'tcx> Machine<'tcx> for Evaluator { - type Data = EvaluatorData; type MemoryData = MemoryData<'tcx>; type MemoryKinds = memory::MemoryKind; - fn param_env<'a>( - _: &EvalContext<'a, 'tcx, Self>, - ) -> ty::ParamEnv<'tcx> { - ty::ParamEnv::empty(traits::Reveal::All) - } - /// Returns Ok() when the function was handled, fail otherwise fn eval_fn_call<'a>( ecx: &mut EvalContext<'a, 'tcx, Self>, @@ -239,8 +231,7 @@ impl<'tcx> Machine<'tcx> for Evaluator { ty: ty::Ty<'tcx>, dest: Place, ) -> EvalResult<'tcx> { - let size = ecx.type_size(ty)?.expect("box only works with sized types"); - let align = ecx.type_align(ty)?; + let layout = ecx.layout_of(ty)?; // Call the `exchange_malloc` lang item let malloc = ecx.tcx.lang_items().exchange_malloc_fn().unwrap(); @@ -264,7 +255,7 @@ impl<'tcx> Machine<'tcx> for Evaluator { let dest = ecx.eval_place(&mir::Place::Local(args.next().unwrap()))?; ecx.write_value( ValTy { - value: Value::ByVal(PrimVal::Bytes(size as u128)), + value: Value::ByVal(PrimVal::Bytes(layout.size.bytes().into())), ty: usize, }, dest, @@ -274,7 +265,7 @@ impl<'tcx> Machine<'tcx> for Evaluator { let dest = ecx.eval_place(&mir::Place::Local(args.next().unwrap()))?; ecx.write_value( ValTy { - value: Value::ByVal(PrimVal::Bytes(align as u128)), + value: Value::ByVal(PrimVal::Bytes(layout.align.abi().into())), ty: usize, }, dest, From bde093fa140cbf95023482a94b92b0b16af4b521 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Thu, 14 Dec 2017 11:03:55 +0100 Subject: [PATCH 0017/3747] Move validation from rustc to miri --- Cargo.toml | 2 + miri/fn_call.rs | 45 ++- miri/helpers.rs | 5 +- miri/intrinsic.rs | 30 +- miri/lib.rs | 92 ++++- miri/locks.rs | 405 ++++++++++++++++++++++ miri/memory.rs | 6 +- miri/operator.rs | 4 +- miri/range_map.rs | 250 ++++++++++++++ miri/tls.rs | 4 +- miri/validation.rs | 843 +++++++++++++++++++++++++++++++++++++++++++++ 11 files changed, 1633 insertions(+), 53 deletions(-) create mode 100644 miri/locks.rs create mode 100644 miri/range_map.rs create mode 100644 miri/validation.rs diff --git a/Cargo.toml b/Cargo.toml index 9d1f615e8d1b1..79fad037385c7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,6 +24,8 @@ path = "miri/lib.rs" [dependencies] byteorder = { version = "1.1", features = ["i128"]} cargo_metadata = { version = "0.2", optional = true } +regex = "0.2.2" +lazy_static = "1.0" [features] cargo_miri = ["cargo_metadata"] diff --git a/miri/fn_call.rs b/miri/fn_call.rs index 8961ae4d2029c..71da97b5ab9b2 100644 --- a/miri/fn_call.rs +++ b/miri/fn_call.rs @@ -8,10 +8,9 @@ use syntax::codemap::Span; use std::mem; -use rustc::mir::interpret::*; use rustc::traits; -use super::{TlsKey, EvalContext}; +use super::*; use tls::MemoryExt; @@ -50,7 +49,7 @@ pub trait EvalContextExt<'tcx> { fn write_null(&mut self, dest: Place, dest_ty: Ty<'tcx>) -> EvalResult<'tcx>; } -impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> { +impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<'tcx>> { fn eval_fn_call( &mut self, instance: ty::Instance<'tcx>, @@ -119,7 +118,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> } "free" => { - let ptr = args[0].into_ptr(&mut self.memory)?; + let ptr = self.into_ptr(args[0].value)?; if !ptr.is_null()? { self.memory.deallocate( ptr.to_ptr()?, @@ -150,8 +149,8 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> } "dlsym" => { - let _handle = args[0].into_ptr(&mut self.memory)?; - let symbol = args[1].into_ptr(&mut self.memory)?.to_ptr()?; + let _handle = self.into_ptr(args[0].value)?; + let symbol = self.into_ptr(args[1].value)?.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); @@ -165,8 +164,8 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> // 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 = args[0].into_ptr(&mut self.memory)?.to_ptr()?; - let data = args[1].into_ptr(&mut self.memory)?; + let f = self.into_ptr(args[0].value)?.to_ptr()?; + let data = self.into_ptr(args[1].value)?; let f_instance = self.memory.get_fn(f)?; self.write_null(dest, dest_ty)?; @@ -205,8 +204,8 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> } "memcmp" => { - let left = args[0].into_ptr(&mut self.memory)?; - let right = args[1].into_ptr(&mut self.memory)?; + let left = self.into_ptr(args[0].value)?; + let right = self.into_ptr(args[1].value)?; let n = self.value_to_primval(args[2])?.to_u64()?; let result = { @@ -229,7 +228,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> } "memrchr" => { - let ptr = args[0].into_ptr(&mut self.memory)?; + let ptr = self.into_ptr(args[0].value)?; let val = self.value_to_primval(args[1])?.to_u64()? as u8; let num = self.value_to_primval(args[2])?.to_u64()?; if let Some(idx) = self.memory.read_bytes(ptr, num)?.iter().rev().position( @@ -244,7 +243,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> } "memchr" => { - let ptr = args[0].into_ptr(&mut self.memory)?; + let ptr = self.into_ptr(args[0].value)?; let val = self.value_to_primval(args[1])?.to_u64()? as u8; let num = self.value_to_primval(args[2])?.to_u64()?; if let Some(idx) = self.memory.read_bytes(ptr, num)?.iter().position( @@ -260,7 +259,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> "getenv" => { let result = { - let name_ptr = args[0].into_ptr(&mut self.memory)?.to_ptr()?; + let name_ptr = self.into_ptr(args[0].value)?.to_ptr()?; let name = self.memory.read_c_str(name_ptr)?; match self.machine.env_vars.get(name) { Some(&var) => PrimVal::Ptr(var), @@ -273,7 +272,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> "unsetenv" => { let mut success = None; { - let name_ptr = args[0].into_ptr(&mut self.memory)?; + let name_ptr = self.into_ptr(args[0].value)?; if !name_ptr.is_null()? { let name = self.memory.read_c_str(name_ptr.to_ptr()?)?; if !name.is_empty() && !name.contains(&b'=') { @@ -294,8 +293,8 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> "setenv" => { let mut new = None; { - let name_ptr = args[0].into_ptr(&mut self.memory)?; - let value_ptr = args[1].into_ptr(&mut self.memory)?.to_ptr()?; + let name_ptr = self.into_ptr(args[0].value)?; + let value_ptr = self.into_ptr(args[1].value)?.to_ptr()?; let value = self.memory.read_c_str(value_ptr)?; if !name_ptr.is_null()? { let name = self.memory.read_c_str(name_ptr.to_ptr()?)?; @@ -329,7 +328,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> "write" => { let fd = self.value_to_primval(args[0])?.to_u64()?; - let buf = args[1].into_ptr(&mut self.memory)?; + let buf = self.into_ptr(args[1].value)?; let n = self.value_to_primval(args[2])?.to_u64()?; trace!("Called write({:?}, {:?}, {:?})", fd, buf, n); let result = if fd == 1 || fd == 2 { @@ -358,7 +357,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> } "strlen" => { - let ptr = args[0].into_ptr(&mut self.memory)?.to_ptr()?; + let ptr = self.into_ptr(args[0].value)?.to_ptr()?; let n = self.memory.read_c_str(ptr)?.len(); self.write_primval(dest, PrimVal::Bytes(n as u128), dest_ty)?; } @@ -406,10 +405,10 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> // Hook pthread calls that go to the thread-local storage memory subsystem "pthread_key_create" => { - let key_ptr = args[0].into_ptr(&mut self.memory)?; + let key_ptr = self.into_ptr(args[0].value)?; // Extract the function type out of the signature (that seems easier than constructing it ourselves...) - let dtor = match args[1].into_ptr(&mut self.memory)?.into_inner_primval() { + let dtor = match self.into_ptr(args[1].value)?.into_inner_primval() { PrimVal::Ptr(dtor_ptr) => Some(self.memory.get_fn(dtor_ptr)?), PrimVal::Bytes(0) => None, PrimVal::Bytes(_) => return err!(ReadBytesAsPointer), @@ -452,7 +451,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> "pthread_setspecific" => { // The conversion into TlsKey here is a little fishy, but should work as long as usize >= libc::pthread_key_t let key = self.value_to_primval(args[0])?.to_u64()? as TlsKey; - let new_ptr = args[1].into_ptr(&mut self.memory)?; + let new_ptr = self.into_ptr(args[1].value)?; self.memory.store_tls(key, new_ptr)?; // Return success (0) @@ -577,7 +576,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> self.write_primval(dest, PrimVal::Ptr(ptr), dest_ty)?; } "alloc::heap::::__rust_dealloc" => { - let ptr = args[0].into_ptr(&mut self.memory)?.to_ptr()?; + let ptr = self.into_ptr(args[0].value)?.to_ptr()?; let old_size = self.value_to_primval(args[1])?.to_u64()?; let align = self.value_to_primval(args[2])?.to_u64()?; if old_size == 0 { @@ -593,7 +592,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> )?; } "alloc::heap::::__rust_realloc" => { - let ptr = args[0].into_ptr(&mut self.memory)?.to_ptr()?; + let ptr = self.into_ptr(args[0].value)?.to_ptr()?; let old_size = self.value_to_primval(args[1])?.to_u64()?; let old_align = self.value_to_primval(args[2])?.to_u64()?; let new_size = self.value_to_primval(args[3])?.to_u64()?; diff --git a/miri/helpers.rs b/miri/helpers.rs index 9ca85a6018e10..0e541cf292086 100644 --- a/miri/helpers.rs +++ b/miri/helpers.rs @@ -1,5 +1,4 @@ -use rustc::mir::interpret::{Pointer, EvalResult, PrimVal, EvalContext}; - +use super::{Pointer, EvalResult, PrimVal, EvalContext}; use rustc::ty::Ty; use rustc::ty::layout::LayoutOf; @@ -19,7 +18,7 @@ pub trait EvalContextExt<'tcx> { ) -> EvalResult<'tcx, Pointer>; } -impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> { +impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<'tcx>> { fn wrapping_pointer_offset( &self, ptr: Pointer, diff --git a/miri/intrinsic.rs b/miri/intrinsic.rs index a509606aaaa09..705c332523397 100644 --- a/miri/intrinsic.rs +++ b/miri/intrinsic.rs @@ -3,8 +3,8 @@ use rustc::traits::Reveal; use rustc::ty::layout::{TyLayout, LayoutOf}; use rustc::ty; -use rustc::mir::interpret::{EvalResult, Place, PlaceExtra, PrimVal, PrimValKind, Value, Pointer, - HasMemory, AccessKind, EvalContext, PtrAndAlign, ValTy}; +use rustc::mir::interpret::{EvalResult, PrimVal, PrimValKind, Value, Pointer, AccessKind, PtrAndAlign}; +use rustc_mir::interpret::{Place, PlaceExtra, HasMemory, EvalContext, ValTy}; use helpers::EvalContextExt as HelperEvalContextExt; @@ -19,7 +19,7 @@ pub trait EvalContextExt<'tcx> { ) -> EvalResult<'tcx>; } -impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> { +impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<'tcx>> { fn call_intrinsic( &mut self, instance: ty::Instance<'tcx>, @@ -70,7 +70,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> "arith_offset" => { let offset = self.value_to_primval(args[1])?.to_i128()? as i64; - let ptr = args[0].into_ptr(&self.memory)?; + let ptr = self.into_ptr(args[0].value)?; let result_ptr = self.wrapping_pointer_offset(ptr, substs.type_at(0), offset)?; self.write_ptr(dest, result_ptr, dest_layout.ty)?; } @@ -86,7 +86,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> "atomic_load_relaxed" | "atomic_load_acq" | "volatile_load" => { - let ptr = args[0].into_ptr(&self.memory)?; + let ptr = self.into_ptr(args[0].value)?; let valty = ValTy { value: Value::by_ref(ptr), ty: substs.type_at(0), @@ -99,7 +99,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> "atomic_store_rel" | "volatile_store" => { let ty = substs.type_at(0); - let dest = args[0].into_ptr(&self.memory)?; + let dest = self.into_ptr(args[0].value)?; self.write_value_to_ptr(args[1].value, dest, ty)?; } @@ -109,7 +109,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> _ if intrinsic_name.starts_with("atomic_xchg") => { let ty = substs.type_at(0); - let ptr = args[0].into_ptr(&self.memory)?; + let ptr = self.into_ptr(args[0].value)?; let change = self.value_to_primval(args[1])?; let old = self.read_value(ptr, ty)?; let old = match old { @@ -127,7 +127,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> _ if intrinsic_name.starts_with("atomic_cxchg") => { let ty = substs.type_at(0); - let ptr = args[0].into_ptr(&self.memory)?; + let ptr = self.into_ptr(args[0].value)?; let expect_old = self.value_to_primval(args[1])?; let change = self.value_to_primval(args[2])?; let old = self.read_value(ptr, ty)?; @@ -175,7 +175,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> "atomic_xsub_acqrel" | "atomic_xsub_relaxed" => { let ty = substs.type_at(0); - let ptr = args[0].into_ptr(&self.memory)?; + let ptr = self.into_ptr(args[0].value)?; let change = self.value_to_primval(args[1])?; let old = self.read_value(ptr, ty)?; let old = match old { @@ -211,8 +211,8 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> // 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.abi(); - let src = args[0].into_ptr(&self.memory)?; - let dest = args[1].into_ptr(&self.memory)?; + let src = self.into_ptr(args[0].value)?; + let dest = self.into_ptr(args[1].value)?; self.memory.copy( src, dest, @@ -240,7 +240,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> "discriminant_value" => { let ty = substs.type_at(0); - let adt_ptr = args[0].into_ptr(&self.memory)?; + let adt_ptr = self.into_ptr(args[0].value)?; let place = Place::from_primval_ptr(adt_ptr); let discr_val = self.read_discriminant_value(place, ty)?; self.write_primval(dest, PrimVal::Bytes(discr_val), dest_layout.ty)?; @@ -366,7 +366,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> "move_val_init" => { let ty = substs.type_at(0); - let ptr = args[0].into_ptr(&self.memory)?; + let ptr = self.into_ptr(args[0].value)?; self.write_value_to_ptr(args[1].value, ptr, ty)?; } @@ -383,7 +383,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> "offset" => { let offset = self.value_to_primval(args[1])?.to_i128()? as i64; - let ptr = args[0].into_ptr(&self.memory)?; + let ptr = self.into_ptr(args[0].value)?; let result_ptr = self.pointer_offset(ptr, substs.type_at(0), offset)?; self.write_ptr(dest, result_ptr, dest_layout.ty)?; } @@ -634,7 +634,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> let ty = substs.type_at(0); let ty_layout = self.layout_of(ty)?; let val_byte = self.value_to_primval(args[1])?.to_u128()? as u8; - let ptr = args[0].into_ptr(&self.memory)?; + let ptr = self.into_ptr(args[0].value)?; let count = self.value_to_primval(args[2])?.to_u64()?; if count > 0 { // HashMap relies on write_bytes on a NULL ptr with count == 0 to work diff --git a/miri/lib.rs b/miri/lib.rs index 398062b8c2245..739ccfbf76712 100644 --- a/miri/lib.rs +++ b/miri/lib.rs @@ -1,6 +1,8 @@ #![feature( i128_type, rustc_private, + conservative_impl_trait, + catch_expr, )] // From rustc. @@ -8,7 +10,12 @@ extern crate log; #[macro_use] extern crate rustc; +extern crate rustc_mir; +extern crate rustc_data_structures; extern crate syntax; +extern crate regex; +#[macro_use] +extern crate lazy_static; use rustc::ty::{self, TyCtxt}; use rustc::ty::layout::{TyLayout, LayoutOf}; @@ -22,6 +29,7 @@ use syntax::codemap::Span; use std::collections::{HashMap, BTreeMap}; pub use rustc::mir::interpret::*; +pub use rustc_mir::interpret::*; mod fn_call; mod operator; @@ -29,11 +37,19 @@ mod intrinsic; mod helpers; mod memory; mod tls; +mod locks; +mod range_map; +mod validation; use fn_call::EvalContextExt as MissingFnsEvalContextExt; use operator::EvalContextExt as OperatorEvalContextExt; use intrinsic::EvalContextExt as IntrinsicEvalContextExt; use tls::EvalContextExt as TlsEvalContextExt; +use locks::LockInfo; +use locks::MemoryExt as LockMemoryExt; +use validation::EvalContextExt as ValidationEvalContextExt; +use range_map::RangeMap; +use validation::{ValidationQuery, AbsPlace}; pub fn eval_main<'a, 'tcx: 'a>( tcx: TyCtxt<'a, 'tcx, 'tcx>, @@ -42,7 +58,7 @@ pub fn eval_main<'a, 'tcx: 'a>( limits: ResourceLimits, ) { fn run_main<'a, 'tcx: 'a>( - ecx: &mut rustc::mir::interpret::EvalContext<'a, 'tcx, Evaluator>, + ecx: &mut rustc_mir::interpret::EvalContext<'a, 'tcx, Evaluator<'tcx>>, main_id: DefId, start_wrapper: Option, ) -> EvalResult<'tcx> { @@ -156,10 +172,13 @@ pub fn eval_main<'a, 'tcx: 'a>( } #[derive(Default)] -pub struct Evaluator { +pub struct Evaluator<'tcx> { /// Environment variables set by `setenv` /// Miri does not expose env vars from the host to the emulated program pub(crate) env_vars: HashMap, MemoryPointer>, + + /// Places that were suspended by the validation subsystem, and will be recovered later + pub(crate) suspended: HashMap>>, } pub type TlsKey = usize; @@ -177,9 +196,15 @@ pub struct MemoryData<'tcx> { /// pthreads-style thread-local storage. thread_local: BTreeMap>, + + /// Memory regions that are locked by some function + /// + /// Only mutable (static mut, heap, stack) allocations have an entry in this map. + /// The entry is created when allocating the memory and deleted after deallocation. + locks: HashMap>>, } -impl<'tcx> Machine<'tcx> for Evaluator { +impl<'tcx> Machine<'tcx> for Evaluator<'tcx> { type MemoryData = MemoryData<'tcx>; type MemoryKinds = memory::MemoryKind; @@ -196,7 +221,7 @@ impl<'tcx> Machine<'tcx> for Evaluator { } fn call_intrinsic<'a>( - ecx: &mut rustc::mir::interpret::EvalContext<'a, 'tcx, Self>, + ecx: &mut rustc_mir::interpret::EvalContext<'a, 'tcx, Self>, instance: ty::Instance<'tcx>, args: &[ValTy<'tcx>], dest: Place, @@ -207,7 +232,7 @@ impl<'tcx> Machine<'tcx> for Evaluator { } fn try_ptr_op<'a>( - ecx: &rustc::mir::interpret::EvalContext<'a, 'tcx, Self>, + ecx: &rustc_mir::interpret::EvalContext<'a, 'tcx, Self>, bin_op: mir::BinOp, left: PrimVal, left_ty: ty::Ty<'tcx>, @@ -303,4 +328,61 @@ impl<'tcx> Machine<'tcx> for Evaluator { ); Ok(()) } + + fn check_locks<'a>( + mem: &Memory<'a, 'tcx, Self>, + ptr: MemoryPointer, + size: u64, + access: AccessKind, + ) -> EvalResult<'tcx> { + mem.check_locks(ptr, size, access) + } + + fn add_lock<'a>( + mem: &mut Memory<'a, 'tcx, Self>, + id: u64, + ) { + mem.data.locks.insert(id, RangeMap::new()); + } + + fn free_lock<'a>( + mem: &mut Memory<'a, 'tcx, Self>, + id: u64, + len: u64, + ) -> EvalResult<'tcx> { + mem.data.locks + .remove(&id) + .expect("allocation has no corresponding locks") + .check( + Some(mem.cur_frame), + 0, + len, + AccessKind::Read, + ) + .map_err(|lock| { + EvalErrorKind::DeallocatedLockedMemory { + //ptr, FIXME + ptr: MemoryPointer { + alloc_id: AllocId(0), + offset: 0, + }, + lock: lock.active, + }.into() + }) + } + + fn end_region<'a>( + ecx: &mut EvalContext<'a, 'tcx, Self>, + reg: Option<::rustc::middle::region::Scope>, + ) -> EvalResult<'tcx> { + ecx.end_region(reg) + } + + fn validation_op<'a>( + ecx: &mut EvalContext<'a, 'tcx, Self>, + op: ::rustc::mir::ValidationOp, + operand: &::rustc::mir::ValidationOperand<'tcx, ::rustc::mir::Place<'tcx>>, + ) -> EvalResult<'tcx> { + ecx.validation_op(op, operand) + } } diff --git a/miri/locks.rs b/miri/locks.rs new file mode 100644 index 0000000000000..3a9df6a38dff1 --- /dev/null +++ b/miri/locks.rs @@ -0,0 +1,405 @@ +use super::*; +use rustc::middle::region; + +//////////////////////////////////////////////////////////////////////////////// +// Locks +//////////////////////////////////////////////////////////////////////////////// + +/// Information about a lock that is currently held. +#[derive(Clone, Debug)] +pub struct LockInfo<'tcx> { + /// Stores for which lifetimes (of the original write lock) we got + /// which suspensions. + suspended: HashMap, Vec>, + /// The current state of the lock that's actually effective. + pub active: Lock, +} + +/// Write locks are identified by a stack frame and an "abstract" (untyped) place. +/// It may be tempting to use the lifetime as identifier, but that does not work +/// for two reasons: +/// * First of all, due to subtyping, the same lock may be referred to with different +/// lifetimes. +/// * Secondly, different write locks may actually have the same lifetime. See `test2` +/// in `run-pass/many_shr_bor.rs`. +/// The Id is "captured" when the lock is first suspended; at that point, the borrow checker +/// considers the path frozen and hence the Id remains stable. +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +pub struct WriteLockId<'tcx> { + frame: usize, + path: AbsPlace<'tcx>, +} + + +use rustc::mir::interpret::Lock::*; +use rustc::mir::interpret::Lock; + +impl<'tcx> Default for LockInfo<'tcx> { + fn default() -> Self { + LockInfo::new(NoLock) + } +} + +impl<'tcx> LockInfo<'tcx> { + fn new(lock: Lock) -> LockInfo<'tcx> { + LockInfo { + suspended: HashMap::new(), + active: lock, + } + } + + fn access_permitted(&self, frame: Option, access: AccessKind) -> bool { + use super::AccessKind::*; + match (&self.active, access) { + (&NoLock, _) => true, + (&ReadLock(ref lfts), Read) => { + assert!(!lfts.is_empty(), "Someone left an empty read lock behind."); + // Read access to read-locked region is okay, no matter who's holding the read lock. + true + } + (&WriteLock(ref lft), _) => { + // All access is okay if we are the ones holding it + Some(lft.frame) == frame + } + _ => false, // Nothing else is okay. + } + } +} + +pub trait MemoryExt<'tcx> { + fn check_locks( + &self, + ptr: MemoryPointer, + len: u64, + access: AccessKind, + ) -> EvalResult<'tcx>; + fn acquire_lock( + &mut self, + ptr: MemoryPointer, + len: u64, + region: Option, + kind: AccessKind, + ) -> EvalResult<'tcx>; + fn suspend_write_lock( + &mut self, + ptr: MemoryPointer, + len: u64, + lock_path: &AbsPlace<'tcx>, + suspend: Option, + ) -> EvalResult<'tcx>; + fn recover_write_lock( + &mut self, + ptr: MemoryPointer, + len: u64, + lock_path: &AbsPlace<'tcx>, + lock_region: Option, + suspended_region: region::Scope, + ) -> EvalResult<'tcx>; + fn locks_lifetime_ended(&mut self, ending_region: Option); +} + + +impl<'a, 'tcx: 'a> MemoryExt<'tcx> for Memory<'a, 'tcx, Evaluator<'tcx>> { + fn check_locks( + &self, + ptr: MemoryPointer, + len: u64, + access: AccessKind, + ) -> EvalResult<'tcx> { + if len == 0 { + return Ok(()); + } + let locks = match self.data.locks.get(&ptr.alloc_id.0) { + Some(locks) => locks, + // immutable static or other constant memory + None => return Ok(()), + }; + let frame = self.cur_frame; + locks + .check(Some(frame), ptr.offset, len, access) + .map_err(|lock| { + EvalErrorKind::MemoryLockViolation { + ptr, + len, + frame, + access, + lock: lock.active, + }.into() + }) + } + + /// Acquire the lock for the given lifetime + fn acquire_lock( + &mut self, + ptr: MemoryPointer, + len: u64, + region: Option, + kind: AccessKind, + ) -> EvalResult<'tcx> { + let frame = self.cur_frame; + assert!(len > 0); + trace!( + "Frame {} acquiring {:?} lock at {:?}, size {} for region {:?}", + frame, + kind, + ptr, + len, + region + ); + self.check_bounds(ptr.offset(len, &*self)?, true)?; // if ptr.offset is in bounds, then so is ptr (because offset checks for overflow) + + let locks = match self.data.locks.get_mut(&ptr.alloc_id.0) { + Some(locks) => locks, + // immutable static or other constant memory + None => return Ok(()), + }; + + // Iterate over our range and acquire the lock. If the range is already split into pieces, + // we have to manipulate all of them. + let lifetime = DynamicLifetime { frame, region }; + for lock in locks.iter_mut(ptr.offset, len) { + if !lock.access_permitted(None, kind) { + return err!(MemoryAcquireConflict { + ptr, + len, + kind, + lock: lock.active.clone(), + }); + } + // See what we have to do + match (&mut lock.active, kind) { + (active @ &mut NoLock, AccessKind::Write) => { + *active = WriteLock(lifetime); + } + (active @ &mut NoLock, AccessKind::Read) => { + *active = ReadLock(vec![lifetime]); + } + (&mut ReadLock(ref mut lifetimes), AccessKind::Read) => { + lifetimes.push(lifetime); + } + _ => bug!("We already checked that there is no conflicting lock"), + } + } + Ok(()) + } + + /// Release or suspend a write lock of the given lifetime prematurely. + /// When releasing, if there is a read lock or someone else's write lock, that's an error. + /// If no lock is held, that's fine. This can happen when e.g. a local is initialized + /// from a constant, and then suspended. + /// When suspending, the same cases are fine; we just register an additional suspension. + fn suspend_write_lock( + &mut self, + ptr: MemoryPointer, + len: u64, + lock_path: &AbsPlace<'tcx>, + suspend: Option, + ) -> EvalResult<'tcx> { + assert!(len > 0); + let cur_frame = self.cur_frame; + let locks = match self.data.locks.get_mut(&ptr.alloc_id.0) { + Some(locks) => locks, + // immutable static or other constant memory + None => return Ok(()), + }; + + 'locks: for lock in locks.iter_mut(ptr.offset, len) { + let is_our_lock = match lock.active { + WriteLock(lft) => + // Double-check that we are holding the lock. + // (Due to subtyping, checking the region would not make any sense.) + lft.frame == cur_frame, + ReadLock(_) | NoLock => false, + }; + if is_our_lock { + trace!("Releasing {:?}", lock.active); + // Disable the lock + lock.active = NoLock; + } else { + trace!( + "Not touching {:?} as it is not our lock", + lock.active, + ); + } + // Check if we want to register a suspension + if let Some(suspend_region) = suspend { + let lock_id = WriteLockId { + frame: cur_frame, + path: lock_path.clone(), + }; + trace!("Adding suspension to {:?}", lock_id); + let mut new_suspension = false; + lock.suspended + .entry(lock_id) + // Remember whether we added a new suspension or not + .or_insert_with(|| { new_suspension = true; Vec::new() }) + .push(suspend_region); + // If the suspension is new, we should have owned this. + // If there already was a suspension, we should NOT have owned this. + if new_suspension == is_our_lock { + // All is well + continue 'locks; + } + } else { + if !is_our_lock { + // All is well. + continue 'locks; + } + } + // If we get here, releasing this is an error except for NoLock. + if lock.active != NoLock { + return err!(InvalidMemoryLockRelease { + ptr, + len, + frame: cur_frame, + lock: lock.active.clone(), + }); + } + } + + Ok(()) + } + + /// Release a suspension from the write lock. If this is the last suspension or if there is no suspension, acquire the lock. + fn recover_write_lock( + &mut self, + ptr: MemoryPointer, + len: u64, + lock_path: &AbsPlace<'tcx>, + lock_region: Option, + suspended_region: region::Scope, + ) -> EvalResult<'tcx> { + assert!(len > 0); + let cur_frame = self.cur_frame; + let lock_id = WriteLockId { + frame: cur_frame, + path: lock_path.clone(), + }; + let locks = match self.data.locks.get_mut(&ptr.alloc_id.0) { + Some(locks) => locks, + // immutable static or other constant memory + None => return Ok(()), + }; + + for lock in locks.iter_mut(ptr.offset, len) { + // Check if we have a suspension here + let (got_the_lock, remove_suspension) = match lock.suspended.get_mut(&lock_id) { + None => { + trace!("No suspension around, we can just acquire"); + (true, false) + } + Some(suspensions) => { + trace!("Found suspension of {:?}, removing it", lock_id); + // That's us! Remove suspension (it should be in there). The same suspension can + // occur multiple times (when there are multiple shared borrows of this that have the same + // lifetime); only remove one of them. + let idx = match suspensions.iter().enumerate().find(|&(_, re)| re == &suspended_region) { + None => // TODO: Can the user trigger this? + bug!("We have this lock suspended, but not for the given region."), + Some((idx, _)) => idx + }; + suspensions.remove(idx); + let got_lock = suspensions.is_empty(); + if got_lock { + trace!("All suspensions are gone, we can have the lock again"); + } + (got_lock, got_lock) + } + }; + if remove_suspension { + // with NLL, we could do that up in the match above... + assert!(got_the_lock); + lock.suspended.remove(&lock_id); + } + if got_the_lock { + match lock.active { + ref mut active @ NoLock => { + *active = WriteLock( + DynamicLifetime { + frame: cur_frame, + region: lock_region, + } + ); + } + _ => { + return err!(MemoryAcquireConflict { + ptr, + len, + kind: AccessKind::Write, + lock: lock.active.clone(), + }) + } + } + } + } + + Ok(()) + } + + fn locks_lifetime_ended(&mut self, ending_region: Option) { + let cur_frame = self.cur_frame; + trace!( + "Releasing frame {} locks that expire at {:?}", + cur_frame, + ending_region + ); + let has_ended = |lifetime: &DynamicLifetime| -> bool { + if lifetime.frame != cur_frame { + return false; + } + match ending_region { + None => true, // When a function ends, we end *all* its locks. It's okay for a function to still have lifetime-related locks + // when it returns, that can happen e.g. with NLL when a lifetime can, but does not have to, extend beyond the + // end of a function. Same for a function still having recoveries. + Some(ending_region) => lifetime.region == Some(ending_region), + } + }; + + for alloc_locks in self.data.locks.values_mut() { + for lock in alloc_locks.iter_mut_all() { + // Delete everything that ends now -- i.e., keep only all the other lifetimes. + let lock_ended = match lock.active { + WriteLock(ref lft) => has_ended(lft), + ReadLock(ref mut lfts) => { + lfts.retain(|lft| !has_ended(lft)); + lfts.is_empty() + } + NoLock => false, + }; + if lock_ended { + lock.active = NoLock; + } + // Also clean up suspended write locks when the function returns + if ending_region.is_none() { + lock.suspended.retain(|id, _suspensions| id.frame != cur_frame); + } + } + // Clean up the map + alloc_locks.retain(|lock| match lock.active { + NoLock => lock.suspended.len() > 0, + _ => true, + }); + } + } +} + +impl<'tcx> RangeMap> { + pub fn check( + &self, + frame: Option, + offset: u64, + len: u64, + access: AccessKind, + ) -> Result<(), LockInfo<'tcx>> { + if len == 0 { + return Ok(()); + } + for lock in self.iter(offset, len) { + // Check if the lock is in conflict with the access. + if !lock.access_permitted(frame, access) { + return Err(lock.clone()); + } + } + Ok(()) + } +} diff --git a/miri/memory.rs b/miri/memory.rs index 0daba8e280ef0..bed0eb28c25c6 100644 --- a/miri/memory.rs +++ b/miri/memory.rs @@ -9,8 +9,8 @@ pub enum MemoryKind { Env, } -impl Into<::rustc::mir::interpret::MemoryKind> for MemoryKind { - fn into(self) -> ::rustc::mir::interpret::MemoryKind { - ::rustc::mir::interpret::MemoryKind::Machine(self) +impl Into<::rustc_mir::interpret::MemoryKind> for MemoryKind { + fn into(self) -> ::rustc_mir::interpret::MemoryKind { + ::rustc_mir::interpret::MemoryKind::Machine(self) } } diff --git a/miri/operator.rs b/miri/operator.rs index 04e84d27201b3..e70f1b12628ac 100644 --- a/miri/operator.rs +++ b/miri/operator.rs @@ -1,7 +1,7 @@ use rustc::ty; use rustc::mir; -use rustc::mir::interpret::*; +use super::*; use helpers::EvalContextExt as HelperEvalContextExt; @@ -24,7 +24,7 @@ pub trait EvalContextExt<'tcx> { ) -> EvalResult<'tcx, (PrimVal, bool)>; } -impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> { +impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<'tcx>> { fn ptr_op( &self, bin_op: mir::BinOp, diff --git a/miri/range_map.rs b/miri/range_map.rs new file mode 100644 index 0000000000000..5cdcbe35121a5 --- /dev/null +++ b/miri/range_map.rs @@ -0,0 +1,250 @@ +//! Implements a map from integer indices to data. +//! Rather than storing data for every index, internally, this maps entire ranges to the data. +//! To this end, the APIs all work on ranges, not on individual integers. Ranges are split as +//! necessary (e.g. when [0,5) is first associated with X, and then [1,2) is mutated). +//! Users must not depend on whether a range is coalesced or not, even though this is observable +//! via the iteration APIs. +use std::collections::BTreeMap; +use std::ops; + +#[derive(Clone, Debug)] +pub struct RangeMap { + map: BTreeMap, +} + +// The derived `Ord` impl sorts first by the first field, then, if the fields are the same, +// by the second field. +// This is exactly what we need for our purposes, since a range query on a BTReeSet/BTreeMap will give us all +// `MemoryRange`s whose `start` is <= than the one we're looking for, but not > the end of the range we're checking. +// At the same time the `end` is irrelevant for the sorting and range searching, but used for the check. +// This kind of search breaks, if `end < start`, so don't do that! +#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Debug)] +struct Range { + start: u64, + end: u64, // Invariant: end > start +} + +impl Range { + fn range(offset: u64, len: u64) -> ops::Range { + assert!(len > 0); + // We select all elements that are within + // the range given by the offset into the allocation and the length. + // This is sound if all ranges that intersect with the argument range, are in the + // resulting range of ranges. + let left = Range { + // lowest range to include `offset` + start: 0, + end: offset + 1, + }; + let right = Range { + // lowest (valid) range not to include `offset+len` + start: offset + len, + end: offset + len + 1, + }; + left..right + } + + /// Tests if all of [offset, offset+len) are contained in this range. + fn overlaps(&self, offset: u64, len: u64) -> bool { + assert!(len > 0); + offset < self.end && offset + len >= self.start + } +} + +impl RangeMap { + pub fn new() -> RangeMap { + RangeMap { map: BTreeMap::new() } + } + + fn iter_with_range<'a>( + &'a self, + offset: u64, + len: u64, + ) -> impl Iterator + 'a { + assert!(len > 0); + self.map.range(Range::range(offset, len)).filter_map( + move |(range, + data)| { + if range.overlaps(offset, len) { + Some((range, data)) + } else { + None + } + }, + ) + } + + pub fn iter<'a>(&'a self, offset: u64, len: u64) -> impl Iterator + 'a { + self.iter_with_range(offset, len).map(|(_, data)| data) + } + + fn split_entry_at(&mut self, offset: u64) + where + T: Clone, + { + let range = match self.iter_with_range(offset, 1).next() { + Some((&range, _)) => range, + None => return, + }; + assert!( + range.start <= offset && range.end > offset, + "We got a range that doesn't even contain what we asked for." + ); + // There is an entry overlapping this position, see if we have to split it + if range.start < offset { + let data = self.map.remove(&range).unwrap(); + let old = self.map.insert( + Range { + start: range.start, + end: offset, + }, + data.clone(), + ); + assert!(old.is_none()); + let old = self.map.insert( + Range { + start: offset, + end: range.end, + }, + data, + ); + assert!(old.is_none()); + } + } + + pub fn iter_mut_all<'a>(&'a mut self) -> impl Iterator + 'a { + self.map.values_mut() + } + + /// Provide mutable iteration over everything in the given range. As a side-effect, + /// this will split entries in the map that are only partially hit by the given range, + /// to make sure that when they are mutated, the effect is constrained to the given range. + pub fn iter_mut_with_gaps<'a>( + &'a mut self, + offset: u64, + len: u64, + ) -> impl Iterator + 'a + where + T: Clone, + { + assert!(len > 0); + // Preparation: Split first and last entry as needed. + self.split_entry_at(offset); + self.split_entry_at(offset + len); + // Now we can provide a mutable iterator + self.map.range_mut(Range::range(offset, len)).filter_map( + move |(&range, data)| { + if range.overlaps(offset, len) { + assert!( + offset <= range.start && offset + len >= range.end, + "The splitting went wrong" + ); + Some(data) + } else { + // Skip this one + None + } + }, + ) + } + + /// Provide a mutable iterator over everything in the given range, with the same side-effects as + /// iter_mut_with_gaps. Furthermore, if there are gaps between ranges, fill them with the given default. + /// This is also how you insert. + pub fn iter_mut<'a>(&'a mut self, offset: u64, len: u64) -> impl Iterator + 'a + where + T: Clone + Default, + { + // Do a first iteration to collect the gaps + let mut gaps = Vec::new(); + let mut last_end = offset; + for (range, _) in self.iter_with_range(offset, len) { + if last_end < range.start { + gaps.push(Range { + start: last_end, + end: range.start, + }); + } + last_end = range.end; + } + if last_end < offset + len { + gaps.push(Range { + start: last_end, + end: offset + len, + }); + } + + // Add default for all gaps + for gap in gaps { + let old = self.map.insert(gap, Default::default()); + assert!(old.is_none()); + } + + // Now provide mutable iteration + self.iter_mut_with_gaps(offset, len) + } + + pub fn retain(&mut self, mut f: F) + where + F: FnMut(&T) -> bool, + { + let mut remove = Vec::new(); + for (range, data) in self.map.iter() { + if !f(data) { + remove.push(*range); + } + } + + for range in remove { + self.map.remove(&range); + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + /// Query the map at every offset in the range and collect the results. + fn to_vec(map: &RangeMap, offset: u64, len: u64) -> Vec { + (offset..offset + len) + .into_iter() + .map(|i| *map.iter(i, 1).next().unwrap()) + .collect() + } + + #[test] + fn basic_insert() { + let mut map = RangeMap::::new(); + // Insert + for x in map.iter_mut(10, 1) { + *x = 42; + } + // Check + assert_eq!(to_vec(&map, 10, 1), vec![42]); + } + + #[test] + fn gaps() { + let mut map = RangeMap::::new(); + for x in map.iter_mut(11, 1) { + *x = 42; + } + for x in map.iter_mut(15, 1) { + *x = 42; + } + + // Now request a range that needs three gaps filled + for x in map.iter_mut(10, 10) { + if *x != 42 { + *x = 23; + } + } + + assert_eq!( + to_vec(&map, 10, 10), + vec![23, 42, 23, 23, 23, 42, 23, 23, 23, 23] + ); + assert_eq!(to_vec(&map, 13, 5), vec![23, 23, 42, 23, 23]); + } +} diff --git a/miri/tls.rs b/miri/tls.rs index 0a0ba1c03b672..7f4f194c67f11 100644 --- a/miri/tls.rs +++ b/miri/tls.rs @@ -18,7 +18,7 @@ pub trait EvalContextExt<'tcx> { fn run_tls_dtors(&mut self) -> EvalResult<'tcx>; } -impl<'a, 'tcx: 'a> MemoryExt<'tcx> for Memory<'a, 'tcx, Evaluator> { +impl<'a, 'tcx: 'a> MemoryExt<'tcx> for Memory<'a, 'tcx, Evaluator<'tcx>> { fn create_tls_key(&mut self, dtor: Option>) -> TlsKey { let new_key = self.data.next_thread_local; self.data.next_thread_local += 1; @@ -106,7 +106,7 @@ impl<'a, 'tcx: 'a> MemoryExt<'tcx> for Memory<'a, 'tcx, Evaluator> { } } -impl<'a, 'tcx: 'a> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, Evaluator> { +impl<'a, 'tcx: 'a> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, Evaluator<'tcx>> { fn run_tls_dtors(&mut self) -> EvalResult<'tcx> { let mut dtor = self.memory.fetch_tls_dtor(None)?; // FIXME: replace loop by some structure that works with stepping diff --git a/miri/validation.rs b/miri/validation.rs new file mode 100644 index 0000000000000..52f0c24bd6d18 --- /dev/null +++ b/miri/validation.rs @@ -0,0 +1,843 @@ +use rustc::hir::{self, Mutability}; +use rustc::hir::Mutability::*; +use rustc::mir::{self, ValidationOp, ValidationOperand}; +use rustc::ty::{self, Ty, TypeFoldable, TyCtxt}; +use rustc::ty::layout::LayoutOf; +use rustc::ty::subst::{Substs, Subst}; +use rustc::traits; +use rustc::infer::InferCtxt; +use rustc::traits::Reveal; +use rustc::middle::region; +use rustc_data_structures::indexed_vec::Idx; +use rustc_mir::interpret::HasMemory; + +use super::{EvalContext, Place, PlaceExtra, ValTy}; +use rustc::mir::interpret::{DynamicLifetime, AccessKind, EvalErrorKind, Value, EvalError, EvalResult}; +use locks::MemoryExt; + +pub type ValidationQuery<'tcx> = ValidationOperand<'tcx, (AbsPlace<'tcx>, Place)>; + +#[derive(Copy, Clone, Debug, PartialEq)] +pub(crate) enum ValidationMode { + Acquire, + /// Recover because the given region ended + Recover(region::Scope), + ReleaseUntil(Option), +} + +impl ValidationMode { + fn acquiring(self) -> bool { + use self::ValidationMode::*; + match self { + Acquire | Recover(_) => true, + ReleaseUntil(_) => false, + } + } +} + +// Abstract places +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +pub enum AbsPlace<'tcx> { + Local(mir::Local), + Static(hir::def_id::DefId), + Projection(Box>), +} + +type AbsPlaceProjection<'tcx> = mir::Projection<'tcx, AbsPlace<'tcx>, u64, ()>; +type AbsPlaceElem<'tcx> = mir::ProjectionElem<'tcx, u64, ()>; + +impl<'tcx> AbsPlace<'tcx> { + pub fn field(self, f: mir::Field) -> AbsPlace<'tcx> { + self.elem(mir::ProjectionElem::Field(f, ())) + } + + pub fn deref(self) -> AbsPlace<'tcx> { + self.elem(mir::ProjectionElem::Deref) + } + + pub fn downcast(self, adt_def: &'tcx ty::AdtDef, variant_index: usize) -> AbsPlace<'tcx> { + self.elem(mir::ProjectionElem::Downcast(adt_def, variant_index)) + } + + pub fn index(self, index: u64) -> AbsPlace<'tcx> { + self.elem(mir::ProjectionElem::Index(index)) + } + + fn elem(self, elem: AbsPlaceElem<'tcx>) -> AbsPlace<'tcx> { + AbsPlace::Projection(Box::new(AbsPlaceProjection { + base: self, + elem, + })) + } +} + +pub(crate) trait EvalContextExt<'tcx> { + fn abstract_place_projection(&self, proj: &mir::PlaceProjection<'tcx>) -> EvalResult<'tcx, AbsPlaceProjection<'tcx>>; + fn abstract_place(&self, place: &mir::Place<'tcx>) -> EvalResult<'tcx, AbsPlace<'tcx>>; + fn validation_op( + &mut self, + op: ValidationOp, + operand: &ValidationOperand<'tcx, mir::Place<'tcx>>, + ) -> EvalResult<'tcx>; + fn end_region(&mut self, scope: Option) -> EvalResult<'tcx>; + fn normalize_type_unerased(&self, ty: Ty<'tcx>) -> Ty<'tcx>; + fn field_with_lifetimes( + &mut self, + base: Place, + layout: ty::layout::TyLayout<'tcx>, + i: usize, + ) -> EvalResult<'tcx, Ty<'tcx>>; + fn validate_fields( + &mut self, + query: ValidationQuery<'tcx>, + mode: ValidationMode, + ) -> EvalResult<'tcx>; + fn validate_ptr( + &mut self, + val: Value, + abs_place: AbsPlace<'tcx>, + pointee_ty: Ty<'tcx>, + re: Option, + mutbl: Mutability, + mode: ValidationMode, + ) -> EvalResult<'tcx>; + fn validate( + &mut self, + query: ValidationQuery<'tcx>, + mode: ValidationMode, + ) -> EvalResult<'tcx>; +} + +impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<'tcx>> { + fn abstract_place_projection(&self, proj: &mir::PlaceProjection<'tcx>) -> EvalResult<'tcx, AbsPlaceProjection<'tcx>> { + use self::mir::ProjectionElem::*; + + let elem = match proj.elem { + Deref => Deref, + Field(f, _) => Field(f, ()), + Index(v) => { + let value = self.frame().get_local(v)?; + let ty = self.tcx.types.usize; + let n = self.value_to_primval(ValTy { value, ty })?.to_u64()?; + Index(n) + }, + ConstantIndex { offset, min_length, from_end } => + ConstantIndex { offset, min_length, from_end }, + Subslice { from, to } => + Subslice { from, to }, + Downcast(adt, sz) => Downcast(adt, sz), + }; + Ok(AbsPlaceProjection { + base: self.abstract_place(&proj.base)?, + elem + }) + } + + fn abstract_place(&self, place: &mir::Place<'tcx>) -> EvalResult<'tcx, AbsPlace<'tcx>> { + Ok(match place { + &mir::Place::Local(l) => AbsPlace::Local(l), + &mir::Place::Static(ref s) => AbsPlace::Static(s.def_id), + &mir::Place::Projection(ref p) => + AbsPlace::Projection(Box::new(self.abstract_place_projection(&*p)?)), + }) + } + + // Validity checks + fn validation_op( + &mut self, + op: ValidationOp, + operand: &ValidationOperand<'tcx, mir::Place<'tcx>>, + ) -> EvalResult<'tcx> { + // If mir-emit-validate is set to 0 (i.e., disabled), we may still see validation commands + // because other crates may have been compiled with mir-emit-validate > 0. Ignore those + // commands. This makes mir-emit-validate also a flag to control whether miri will do + // validation or not. + if self.tcx.sess.opts.debugging_opts.mir_emit_validate == 0 { + return Ok(()); + } + debug_assert!(self.memory.cur_frame == self.cur_frame()); + + // HACK: Determine if this method is whitelisted and hence we do not perform any validation. + // We currently insta-UB on anything passing around uninitialized memory, so we have to whitelist + // the places that are allowed to do that. + // The second group is stuff libstd does that is forbidden even under relaxed validation. + { + // The regexp we use for filtering + use regex::Regex; + lazy_static! { + static ref RE: Regex = Regex::new("^(\ + (std|alloc::heap::__core)::mem::(uninitialized|forget)::|\ + <(std|alloc)::heap::Heap as (std::heap|alloc::allocator)::Alloc>::|\ + <(std|alloc::heap::__core)::mem::ManuallyDrop><.*>::new$|\ + <(std|alloc::heap::__core)::mem::ManuallyDrop as std::ops::DerefMut><.*>::deref_mut$|\ + (std|alloc::heap::__core)::ptr::read::|\ + \ + ><.*>::inner$|\ + ><.*>::drop_slow$|\ + (std::heap|alloc::allocator)::Layout::for_value::|\ + (std|alloc::heap::__core)::mem::(size|align)_of_val::\ + )").unwrap(); + } + // Now test + let name = self.frame().instance.to_string(); + if RE.is_match(&name) { + return Ok(()); + } + } + + // We need to monomorphize ty *without* erasing lifetimes + trace!("validation_op1: {:?}", operand.ty.sty); + let ty = operand.ty.subst(self.tcx, self.substs()); + trace!("validation_op2: {:?}", operand.ty.sty); + let place = self.eval_place(&operand.place)?; + let abs_place = self.abstract_place(&operand.place)?; + let query = ValidationQuery { + place: (abs_place, place), + ty, + re: operand.re, + mutbl: operand.mutbl, + }; + + // Check the mode, and also perform mode-specific operations + let mode = match op { + ValidationOp::Acquire => ValidationMode::Acquire, + ValidationOp::Release => ValidationMode::ReleaseUntil(None), + ValidationOp::Suspend(scope) => { + if query.mutbl == MutMutable { + let lft = DynamicLifetime { + frame: self.cur_frame(), + region: Some(scope), // Notably, we only ever suspend things for given regions. + // Suspending for the entire function does not make any sense. + }; + trace!("Suspending {:?} until {:?}", query, scope); + self.machine.suspended.entry(lft).or_insert_with(Vec::new).push( + query.clone(), + ); + } + ValidationMode::ReleaseUntil(Some(scope)) + } + }; + self.validate(query, mode) + } + + /// Release locks and executes suspensions of the given region (or the entire fn, in case of None). + fn end_region(&mut self, scope: Option) -> EvalResult<'tcx> { + debug_assert!(self.memory.cur_frame == self.cur_frame()); + self.memory.locks_lifetime_ended(scope); + match scope { + Some(scope) => { + // Recover suspended places + let lft = DynamicLifetime { + frame: self.cur_frame(), + region: Some(scope), + }; + if let Some(queries) = self.machine.suspended.remove(&lft) { + for query in queries { + trace!("Recovering {:?} from suspension", query); + self.validate(query, ValidationMode::Recover(scope))?; + } + } + } + None => { + // Clean suspension table of current frame + let cur_frame = self.cur_frame(); + self.machine.suspended.retain(|lft, _| { + lft.frame != cur_frame // keep only what is in the other (lower) frames + }); + } + } + Ok(()) + } + + fn normalize_type_unerased(&self, ty: Ty<'tcx>) -> Ty<'tcx> { + return normalize_associated_type(self.tcx, &ty); + + use syntax::codemap::{Span, DUMMY_SP}; + + // We copy a bunch of stuff from rustc/infer/mod.rs to be able to tweak its behavior + fn normalize_projections_in<'a, 'gcx, 'tcx, T>( + self_: &InferCtxt<'a, 'gcx, 'tcx>, + param_env: ty::ParamEnv<'tcx>, + value: &T, + ) -> T::Lifted + where + T: TypeFoldable<'tcx> + ty::Lift<'gcx>, + { + let mut selcx = traits::SelectionContext::new(self_); + let cause = traits::ObligationCause::dummy(); + let traits::Normalized { + value: result, + obligations, + } = traits::normalize(&mut selcx, param_env, cause, value); + + let mut fulfill_cx = traits::FulfillmentContext::new(); + + for obligation in obligations { + fulfill_cx.register_predicate_obligation(self_, obligation); + } + + drain_fulfillment_cx_or_panic(self_, DUMMY_SP, &mut fulfill_cx, &result) + } + + fn drain_fulfillment_cx_or_panic<'a, 'gcx, 'tcx, T>( + self_: &InferCtxt<'a, 'gcx, 'tcx>, + span: Span, + fulfill_cx: &mut traits::FulfillmentContext<'tcx>, + result: &T, + ) -> T::Lifted + where + T: TypeFoldable<'tcx> + ty::Lift<'gcx>, + { + // In principle, we only need to do this so long as `result` + // contains unbound type parameters. It could be a slight + // optimization to stop iterating early. + match fulfill_cx.select_all_or_error(self_) { + Ok(()) => { } + Err(errors) => { + span_bug!( + span, + "Encountered errors `{:?}` resolving bounds after type-checking", + errors + ); + } + } + + let result = self_.resolve_type_vars_if_possible(result); + let result = self_.tcx.fold_regions( + &result, + &mut false, + |r, _| match *r { + ty::ReVar(_) => self_.tcx.types.re_erased, + _ => r, + }, + ); + + match self_.tcx.lift_to_global(&result) { + Some(result) => result, + None => { + span_bug!(span, "Uninferred types/regions in `{:?}`", result); + } + } + } + + trait MyTransNormalize<'gcx>: TypeFoldable<'gcx> { + fn my_trans_normalize<'a, 'tcx>( + &self, + infcx: &InferCtxt<'a, 'gcx, 'tcx>, + param_env: ty::ParamEnv<'tcx>, + ) -> Self; + } + + macro_rules! items { ($($item:item)+) => ($($item)+) } + macro_rules! impl_trans_normalize { + ($lt_gcx:tt, $($ty:ty),+) => { + items!($(impl<$lt_gcx> MyTransNormalize<$lt_gcx> for $ty { + fn my_trans_normalize<'a, 'tcx>(&self, + infcx: &InferCtxt<'a, $lt_gcx, 'tcx>, + param_env: ty::ParamEnv<'tcx>) + -> Self { + normalize_projections_in(infcx, param_env, self) + } + })+); + } + } + + impl_trans_normalize!('gcx, + Ty<'gcx>, + &'gcx Substs<'gcx>, + ty::FnSig<'gcx>, + ty::PolyFnSig<'gcx>, + ty::ClosureSubsts<'gcx>, + ty::PolyTraitRef<'gcx>, + ty::ExistentialTraitRef<'gcx> + ); + + fn normalize_associated_type<'a, 'tcx, T>(self_: TyCtxt<'a, 'tcx, 'tcx>, value: &T) -> T + where + T: MyTransNormalize<'tcx>, + { + let param_env = ty::ParamEnv::empty(Reveal::All); + + if !value.has_projections() { + return value.clone(); + } + + self_.infer_ctxt().enter(|infcx| { + value.my_trans_normalize(&infcx, param_env) + }) + } + } + + // This is a copy of `Layout::field` + // + // FIXME: remove once validation does not depend on lifetimes + fn field_with_lifetimes( + &mut self, + base: Place, + mut layout: ty::layout::TyLayout<'tcx>, + i: usize, + ) -> EvalResult<'tcx, Ty<'tcx>> { + match base { + Place::Ptr { extra: PlaceExtra::DowncastVariant(variant_index), .. } => { + layout = layout.for_variant(&self, variant_index); + } + _ => {} + } + let tcx = self.tcx; + Ok(match layout.ty.sty { + ty::TyBool | + ty::TyChar | + ty::TyInt(_) | + ty::TyUint(_) | + ty::TyFloat(_) | + ty::TyFnPtr(_) | + ty::TyNever | + ty::TyFnDef(..) | + ty::TyDynamic(..) | + ty::TyForeign(..) => { + bug!("TyLayout::field_type({:?}): not applicable", layout) + } + + // Potentially-fat pointers. + ty::TyRef(_, ty::TypeAndMut { ty: pointee, .. }) | + ty::TyRawPtr(ty::TypeAndMut { ty: pointee, .. }) => { + assert!(i < 2); + + // Reuse the fat *T type as its own thin pointer data field. + // This provides information about e.g. DST struct pointees + // (which may have no non-DST form), and will work as long + // as the `Abi` or `FieldPlacement` is checked by users. + if i == 0 { + return Ok(layout.ty); + } + + match tcx.struct_tail(pointee).sty { + ty::TySlice(_) | + ty::TyStr => tcx.types.usize, + ty::TyDynamic(..) => { + // FIXME(eddyb) use an usize/fn() array with + // the correct number of vtables slots. + tcx.mk_imm_ref(tcx.types.re_static, tcx.mk_nil()) + } + _ => bug!("TyLayout::field_type({:?}): not applicable", layout) + } + } + + // Arrays and slices. + ty::TyArray(element, _) | + ty::TySlice(element) => element, + ty::TyStr => tcx.types.u8, + + // Tuples, generators and closures. + ty::TyClosure(def_id, ref substs) => { + substs.upvar_tys(def_id, tcx).nth(i).unwrap() + } + + ty::TyGenerator(def_id, ref substs, _) => { + substs.field_tys(def_id, tcx).nth(i).unwrap() + } + + ty::TyTuple(tys, _) => tys[i], + + // SIMD vector types. + ty::TyAdt(def, ..) if def.repr.simd() => { + layout.ty.simd_type(tcx) + } + + // ADTs. + ty::TyAdt(def, substs) => { + use rustc::ty::layout::Variants; + match layout.variants { + Variants::Single { index } => { + def.variants[index].fields[i].ty(tcx, substs) + } + + // Discriminant field for enums (where applicable). + Variants::Tagged { ref discr, .. } | + Variants::NicheFilling { niche: ref discr, .. } => { + assert_eq!(i, 0); + return Ok(discr.value.to_ty(tcx)) + } + } + } + + ty::TyProjection(_) | ty::TyAnon(..) | ty::TyParam(_) | + ty::TyInfer(_) | ty::TyError => { + bug!("TyLayout::field_type: unexpected type `{}`", layout.ty) + } + }) + } + + fn validate_fields( + &mut self, + query: ValidationQuery<'tcx>, + mode: ValidationMode, + ) -> EvalResult<'tcx> { + let mut layout = self.layout_of(query.ty)?; + layout.ty = query.ty; + + // TODO: Maybe take visibility/privacy into account. + for idx in 0..layout.fields.count() { + let field = mir::Field::new(idx); + let (field_place, field_layout) = + self.place_field(query.place.1, field, layout)?; + // layout stuff erases lifetimes, get the field ourselves + let field_ty = self.field_with_lifetimes(query.place.1, layout, idx)?; + trace!("assuming \n{:?}\n == \n{:?}\n except for lifetimes", field_layout.ty, field_ty); + self.validate( + ValidationQuery { + place: (query.place.0.clone().field(field), field_place), + ty: field_ty, + ..query + }, + mode, + )?; + } + + Ok(()) + } + + fn validate_ptr( + &mut self, + val: Value, + abs_place: AbsPlace<'tcx>, + pointee_ty: Ty<'tcx>, + re: Option, + mutbl: Mutability, + mode: ValidationMode, + ) -> EvalResult<'tcx> { + // Check alignment and non-NULLness + let (_, align) = self.size_and_align_of_dst(pointee_ty, val)?; + let ptr = self.into_ptr(val)?; + self.memory.check_align(ptr, align.abi(), None)?; + + // Recurse + let pointee_place = self.val_to_place(val, pointee_ty)?; + self.validate( + ValidationQuery { + place: (abs_place.deref(), pointee_place), + ty: pointee_ty, + re, + mutbl, + }, + mode, + ) + } + + /// Validate the place at the given type. If `acquire` is false, just do a release of all write locks + fn validate( + &mut self, + mut query: ValidationQuery<'tcx>, + mode: ValidationMode, + ) -> EvalResult<'tcx> { + use rustc::ty::TypeVariants::*; + use rustc::ty::RegionKind::*; + use rustc::ty::AdtKind; + + // No point releasing shared stuff. + if !mode.acquiring() && query.mutbl == MutImmutable { + return Ok(()); + } + // When we recover, we may see data whose validity *just* ended. Do not acquire it. + if let ValidationMode::Recover(ending_ce) = mode { + if query.re == Some(ending_ce) { + return Ok(()); + } + } + + query.ty = self.normalize_type_unerased(&query.ty); + trace!("{:?} on {:#?}", mode, query); + trace!("{:#?}", query.ty.sty); + + // Decide whether this type *owns* the memory it covers (like integers), or whether it + // just assembles pieces (that each own their memory) together to a larger whole. + // TODO: Currently, we don't acquire locks for padding and discriminants. We should. + let is_owning = match query.ty.sty { + TyInt(_) | TyUint(_) | TyRawPtr(_) | TyBool | TyFloat(_) | TyChar | TyStr | + TyRef(..) | TyFnPtr(..) | TyFnDef(..) | TyNever => true, + TyAdt(adt, _) if adt.is_box() => true, + TySlice(_) | TyAdt(_, _) | TyTuple(..) | TyClosure(..) | TyArray(..) | + TyDynamic(..) | TyGenerator(..) | TyForeign(_) => false, + TyParam(_) | TyInfer(_) | TyProjection(_) | TyAnon(..) | TyError => { + bug!("I got an incomplete/unnormalized type for validation") + } + }; + if is_owning { + // We need to lock. So we need memory. So we have to force_acquire. + // Tracking the same state for locals not backed by memory would just duplicate too + // much machinery. + // FIXME: We ignore alignment. + let (ptr, extra) = self.force_allocation(query.place.1)?.to_ptr_extra_aligned(); + // Determine the size + // FIXME: Can we reuse size_and_align_of_dst for Places? + let layout = self.layout_of(query.ty)?; + let len = if !layout.is_unsized() { + assert_eq!(extra, PlaceExtra::None, "Got a fat ptr to a sized type"); + layout.size.bytes() + } else { + // The only unsized typ we concider "owning" is TyStr. + assert_eq!( + query.ty.sty, + TyStr, + "Found a surprising unsized owning type" + ); + // The extra must be the length, in bytes. + match extra { + PlaceExtra::Length(len) => len, + _ => bug!("TyStr must have a length as extra"), + } + }; + // Handle locking + if len > 0 { + let ptr = ptr.to_ptr()?; + match query.mutbl { + MutImmutable => { + if mode.acquiring() { + self.memory.acquire_lock( + ptr, + len, + query.re, + AccessKind::Read, + )?; + } + } + // No releasing of read locks, ever. + MutMutable => { + match mode { + ValidationMode::Acquire => { + self.memory.acquire_lock( + ptr, + len, + query.re, + AccessKind::Write, + )? + } + ValidationMode::Recover(ending_ce) => { + self.memory.recover_write_lock( + ptr, + len, + &query.place.0, + query.re, + ending_ce, + )? + } + ValidationMode::ReleaseUntil(suspended_ce) => { + self.memory.suspend_write_lock( + ptr, + len, + &query.place.0, + suspended_ce, + )? + } + } + } + } + } + } + + let res = do catch { + match query.ty.sty { + TyInt(_) | TyUint(_) | TyRawPtr(_) => { + if mode.acquiring() { + // Make sure we can read this. + let val = self.read_place(query.place.1)?; + self.follow_by_ref_value(val, query.ty)?; + // FIXME: It would be great to rule out Undef here, but that doesn't actually work. + // Passing around undef data is a thing that e.g. Vec::extend_with does. + } + Ok(()) + } + TyBool | TyFloat(_) | TyChar => { + if mode.acquiring() { + let val = self.read_place(query.place.1)?; + let val = self.value_to_primval(ValTy { value: val, ty: query.ty })?; + val.to_bytes()?; + // TODO: Check if these are valid bool/float/codepoint/UTF-8 + } + Ok(()) + } + TyNever => err!(ValidationFailure(format!("The empty type is never valid."))), + TyRef(region, + ty::TypeAndMut { + ty: pointee_ty, + mutbl, + }) => { + let val = self.read_place(query.place.1)?; + // Sharing restricts our context + if mutbl == MutImmutable { + query.mutbl = MutImmutable; + } + // Inner lifetimes *outlive* outer ones, so only if we have no lifetime restriction yet, + // we record the region of this borrow to the context. + if query.re == None { + match *region { + ReScope(scope) => query.re = Some(scope), + // It is possible for us to encounter erased lifetimes here because the lifetimes in + // this functions' Subst will be erased. + _ => {} + } + } + self.validate_ptr(val, query.place.0, pointee_ty, query.re, query.mutbl, mode) + } + TyAdt(adt, _) if adt.is_box() => { + let val = self.read_place(query.place.1)?; + self.validate_ptr(val, query.place.0, query.ty.boxed_ty(), query.re, query.mutbl, mode) + } + TyFnPtr(_sig) => { + let ptr = self.read_place(query.place.1)?; + let ptr = self.into_ptr(ptr)?.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?). + Ok(()) + } + TyFnDef(..) => { + // This is a zero-sized type with all relevant data sitting in the type. + // There is nothing to validate. + Ok(()) + } + + // Compound types + TyStr => { + // TODO: Validate strings + Ok(()) + } + TySlice(elem_ty) => { + let len = match query.place.1 { + Place::Ptr { extra: PlaceExtra::Length(len), .. } => len, + _ => { + bug!( + "acquire_valid of a TySlice given non-slice place: {:?}", + query.place + ) + } + }; + for i in 0..len { + let inner_place = self.place_index(query.place.1, query.ty, i)?; + self.validate( + ValidationQuery { + place: (query.place.0.clone().index(i), inner_place), + ty: elem_ty, + ..query + }, + mode, + )?; + } + Ok(()) + } + TyArray(elem_ty, len) => { + let len = len.val.to_const_int().unwrap().to_u64().unwrap(); + for i in 0..len { + let inner_place = self.place_index(query.place.1, query.ty, i as u64)?; + self.validate( + ValidationQuery { + place: (query.place.0.clone().index(i as u64), inner_place), + ty: elem_ty, + ..query + }, + mode, + )?; + } + Ok(()) + } + TyDynamic(_data, _region) => { + // Check that this is a valid vtable + let vtable = match query.place.1 { + Place::Ptr { extra: PlaceExtra::Vtable(vtable), .. } => vtable, + _ => { + bug!( + "acquire_valid of a TyDynamic given non-trait-object place: {:?}", + query.place + ) + } + }; + self.read_size_and_align_from_vtable(vtable)?; + // TODO: Check that the vtable contains all the function pointers we expect it to have. + // Trait objects cannot have any operations performed + // on them directly. We cannot, in general, even acquire any locks as the trait object *could* + // contain an UnsafeCell. If we call functions to get access to data, we will validate + // their return values. So, it doesn't seem like there's anything else to do. + Ok(()) + } + TyAdt(adt, _) => { + if Some(adt.did) == self.tcx.lang_items().unsafe_cell_type() && + query.mutbl == MutImmutable + { + // No locks for shared unsafe cells. Also no other validation, the only field is private anyway. + return Ok(()); + } + + match adt.adt_kind() { + AdtKind::Enum => { + let discr = self.read_discriminant_value(query.place.1, query.ty)?; + + // Get variant index for discriminant + let variant_idx = adt.discriminants(self.tcx).position(|variant_discr| { + variant_discr.to_u128_unchecked() == discr + }); + let variant_idx = match variant_idx { + Some(val) => val, + None => return err!(InvalidDiscriminant), + }; + let variant = &adt.variants[variant_idx]; + + if variant.fields.len() > 0 { + // Downcast to this variant, if needed + let place = if adt.is_enum() { + ( + query.place.0.downcast(adt, variant_idx), + self.eval_place_projection( + query.place.1, + query.ty, + &mir::ProjectionElem::Downcast(adt, variant_idx), + )?, + ) + } else { + query.place + }; + + // Recursively validate the fields + self.validate_fields( + ValidationQuery { place, ..query }, + mode, + ) + } else { + // No fields, nothing left to check. Downcasting may fail, e.g. in case of a CEnum. + Ok(()) + } + } + AdtKind::Struct => { + self.validate_fields(query, mode) + } + AdtKind::Union => { + // No guarantees are provided for union types. + // TODO: Make sure that all access to union fields is unsafe; otherwise, we may have some checking to do (but what exactly?) + Ok(()) + } + } + } + TyTuple(..) | + TyClosure(..) => { + // TODO: Check if the signature matches for `TyClosure` + // (should be the same check as what terminator/mod.rs already does on call?). + // Is there other things we can/should check? Like vtable pointers? + self.validate_fields(query, mode) + } + // FIXME: generators aren't validated right now + TyGenerator(..) => Ok(()), + _ => bug!("We already established that this is a type we support. ({})", query.ty), + } + }; + match res { + // ReleaseUntil(None) of an uninitalized variable is a NOP. This is needed because + // we have to release the return value of a function; due to destination-passing-style + // the callee may directly write there. + // TODO: Ideally we would know whether the destination is already initialized, and only + // release if it is. But of course that can't even always be statically determined. + Err(EvalError { kind: EvalErrorKind::ReadUndefBytes, .. }) + if mode == ValidationMode::ReleaseUntil(None) => { + return Ok(()); + } + res => res, + } + } +} From fc587ac6ae2b49096f440aea37a77b39b6b03971 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Fri, 15 Dec 2017 09:32:10 +0100 Subject: [PATCH 0018/3747] Without a Cargo.lock it makes no sense to use --locked --- .travis.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.travis.yml b/.travis.yml index 86577702e96d9..97f1da545be4f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -16,9 +16,9 @@ script: xargo/build.sh - | # Test plain miri - cargo build --locked --release --all-features && - cargo test --locked --release --all-features --all && - cargo install --locked --all-features + cargo build --release --all-features && + cargo test --release --all-features --all && + cargo install --all-features - | # Test cargo miri cd cargo-miri-test && @@ -27,11 +27,11 @@ script: cd .. - | # and run all tests with full mir - MIRI_SYSROOT=~/.xargo/HOST cargo test --locked --release + MIRI_SYSROOT=~/.xargo/HOST cargo test --release - | # test that the rustc_tests binary compiles cd rustc_tests && - cargo build --locked --release && + cargo build --release && cd .. notifications: email: From aa9177fec6b080024ffaf6e287cd3dc25bbad9b5 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Fri, 15 Dec 2017 09:54:53 +0100 Subject: [PATCH 0019/3747] Also update rustc_tests to unrelated rustc changes --- rustc_tests/src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rustc_tests/src/main.rs b/rustc_tests/src/main.rs index 819721c1cd0f9..29b2dc2b7a425 100644 --- a/rustc_tests/src/main.rs +++ b/rustc_tests/src/main.rs @@ -90,7 +90,7 @@ fn after_analysis<'a, 'tcx>(state: &mut CompileState<'a, 'tcx>) { if let hir::Item_::ItemFn(_, _, _, _, _, body_id) = i.node { if i.attrs.iter().any(|attr| attr.name().map_or(false, |n| n == "test")) { let did = self.1.hir.body_owner_def_id(body_id); - println!("running test: {}", self.1.hir.def_path(did).to_string(self.1)); + println!("running test: {}", self.1.def_path_debug_str(did)); miri::eval_main(self.1, did, None, self.0); self.2.session.abort_if_errors(); } From 2671cf34a58b11f995add8402e75c1cd94ed051e Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Fri, 15 Dec 2017 10:14:02 +0100 Subject: [PATCH 0020/3747] Update to some cleanups in rustc --- miri/fn_call.rs | 2 +- miri/lib.rs | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/miri/fn_call.rs b/miri/fn_call.rs index 71da97b5ab9b2..3ca71e9b90c20 100644 --- a/miri/fn_call.rs +++ b/miri/fn_call.rs @@ -385,7 +385,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<' // compute global if not cached let val = match self.tcx.interpret_interner.borrow().get_cached(cid) { Some(ptr) => ptr, - None => eval_body(self.tcx, instance, ty::ParamEnv::empty(traits::Reveal::All)).0?.0, + None => eval_body(self.tcx, instance, ty::ParamEnv::empty(traits::Reveal::All))?.0, }; let val = self.value_to_primval(ValTy { value: Value::ByRef(val), ty: args[0].ty })?.to_u64()?; if val == name { diff --git a/miri/lib.rs b/miri/lib.rs index 739ccfbf76712..fc282104e116e 100644 --- a/miri/lib.rs +++ b/miri/lib.rs @@ -20,6 +20,7 @@ extern crate lazy_static; use rustc::ty::{self, TyCtxt}; use rustc::ty::layout::{TyLayout, LayoutOf}; use rustc::hir::def_id::DefId; +use rustc::ty::subst::Substs; use rustc::mir; use rustc::traits; @@ -157,7 +158,7 @@ pub fn eval_main<'a, 'tcx: 'a>( Ok(()) } - let mut ecx = EvalContext::new(tcx, ty::ParamEnv::empty(traits::Reveal::All), limits, Default::default(), Default::default()); + let mut ecx = EvalContext::new(tcx, ty::ParamEnv::empty(traits::Reveal::All), limits, Default::default(), Default::default(), Substs::empty()); match run_main(&mut ecx, main_id, start_wrapper) { Ok(()) => { let leaks = ecx.memory().leak_report(); From b7d382a95673e7ba0dc9edebaf9bd6f5b50e39e0 Mon Sep 17 00:00:00 2001 From: kennytm Date: Sat, 16 Dec 2017 03:58:17 +0800 Subject: [PATCH 0021/3747] Remove the [workspace] section. Miri does not need to maintain a workspace anymore. Also, keeping miri a workspace conflicts with rustc's own workspace. --- Cargo.toml | 3 --- 1 file changed, 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 79fad037385c7..bbb3958ac35f8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -32,6 +32,3 @@ cargo_miri = ["cargo_metadata"] [dev-dependencies] compiletest_rs = { version = "0.3.3", features = ["tmp"] } - -[workspace] -exclude = ["xargo", "cargo-miri-test", "rustc_tests"] From a23e587dc3a55a766ddd95454fd8368988cc7a3a Mon Sep 17 00:00:00 2001 From: Ariel Ben-Yehuda Date: Sat, 16 Dec 2017 19:48:08 -0600 Subject: [PATCH 0022/3747] stop using Instance::def_ty that function has been removed --- miri/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/miri/lib.rs b/miri/lib.rs index fc282104e116e..d4c211e1fd959 100644 --- a/miri/lib.rs +++ b/miri/lib.rs @@ -105,7 +105,7 @@ pub fn eval_main<'a, 'tcx: 'a>( // First argument: pointer to main() let main_ptr = ecx.memory_mut().create_fn_alloc(main_instance); let dest = ecx.eval_place(&mir::Place::Local(args.next().unwrap()))?; - let main_ty = main_instance.def.def_ty(ecx.tcx); + let main_ty = main_instance.ty(ecx.tcx); let main_ptr_ty = ecx.tcx.mk_fn_ptr(main_ty.fn_sig(ecx.tcx)); ecx.write_value( ValTy { From 30496f5dd27b02c5433956c2704cef41a5b119ad Mon Sep 17 00:00:00 2001 From: David Renshaw Date: Sun, 31 Dec 2017 08:35:02 -0500 Subject: [PATCH 0023/3747] update compiletest dependency --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index bbb3958ac35f8..4f0d0fe2ef1cb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -31,4 +31,4 @@ lazy_static = "1.0" cargo_miri = ["cargo_metadata"] [dev-dependencies] -compiletest_rs = { version = "0.3.3", features = ["tmp"] } +compiletest_rs = { version = "0.3.4", features = ["tmp"] } From 03aa8765b19a561e85441c6ed94ba3d646477807 Mon Sep 17 00:00:00 2001 From: David Renshaw Date: Tue, 2 Jan 2018 17:43:03 -0500 Subject: [PATCH 0024/3747] pass typecheck --- miri/fn_call.rs | 27 ++++++++++++------ miri/intrinsic.rs | 68 ++++++++++++++++++++++++---------------------- miri/lib.rs | 22 +++++++-------- miri/operator.rs | 2 +- miri/validation.rs | 4 +-- 5 files changed, 67 insertions(+), 56 deletions(-) diff --git a/miri/fn_call.rs b/miri/fn_call.rs index 3ca71e9b90c20..df101739ed919 100644 --- a/miri/fn_call.rs +++ b/miri/fn_call.rs @@ -1,5 +1,5 @@ use rustc::ty::{self, Ty}; -use rustc::ty::layout::LayoutOf; +use rustc::ty::layout::{Align, LayoutOf}; use rustc::hir::def_id::{DefId, CRATE_DEF_INDEX}; use rustc::mir; use syntax::attr; @@ -111,7 +111,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<' if size == 0 { self.write_null(dest, dest_ty)?; } else { - let align = self.memory.pointer_size(); + let align = self.tcx.data_layout.pointer_align; let ptr = self.memory.allocate(size, align, Some(MemoryKind::C.into()))?; self.write_primval(dest, PrimVal::Ptr(ptr), dest_ty)?; } @@ -307,7 +307,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<' // +1 for the null terminator let value_copy = self.memory.allocate( (value.len() + 1) as u64, - 1, + Align::from_bytes(1, 1).unwrap(), Some(MemoryKind::Env.into()), )?; self.memory.write_bytes(value_copy.into(), &value)?; @@ -369,6 +369,8 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<' "sysconf" => { let name = self.value_to_primval(args[0])?.to_u64()?; + let name_align = self.layout_of(args[0].ty)?.align; + trace!("sysconf() called with name {}", name); // cache the sysconf integers via miri's global cache let paths = &[ @@ -387,7 +389,8 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<' Some(ptr) => ptr, None => eval_body(self.tcx, instance, ty::ParamEnv::empty(traits::Reveal::All))?.0, }; - let val = self.value_to_primval(ValTy { value: Value::ByRef(val), ty: args[0].ty })?.to_u64()?; + let val = self.value_to_primval(ValTy { value: Value::ByRef(val, name_align), + ty: args[0].ty })?.to_u64()?; if val == name { result = Some(path_value); break; @@ -406,6 +409,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<' // 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; // Extract the function type out of the signature (that seems easier than constructing it ourselves...) let dtor = match self.into_ptr(args[1].value)?.into_inner_primval() { @@ -427,6 +431,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<' } self.memory.write_primval( key_ptr.to_ptr()?, + key_align, PrimVal::Bytes(key), key_size.bytes(), false, @@ -559,7 +564,9 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<' if !align.is_power_of_two() { return err!(HeapAllocNonPowerOfTwoAlignment(align)); } - let ptr = self.memory.allocate(size, align, Some(MemoryKind::Rust.into()))?; + let ptr = self.memory.allocate(size, + Align::from_bytes(align, align).unwrap(), + Some(MemoryKind::Rust.into()))?; self.write_primval(dest, PrimVal::Ptr(ptr), dest_ty)?; } "alloc::heap::::__rust_alloc_zeroed" => { @@ -571,7 +578,9 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<' if !align.is_power_of_two() { return err!(HeapAllocNonPowerOfTwoAlignment(align)); } - let ptr = self.memory.allocate(size, align, Some(MemoryKind::Rust.into()))?; + let ptr = self.memory.allocate(size, + Align::from_bytes(align, align).unwrap(), + Some(MemoryKind::Rust.into()))?; self.memory.write_repeat(ptr.into(), 0, size)?; self.write_primval(dest, PrimVal::Ptr(ptr), dest_ty)?; } @@ -587,7 +596,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<' } self.memory.deallocate( ptr, - Some((old_size, align)), + Some((old_size, Align::from_bytes(align, align).unwrap())), MemoryKind::Rust.into(), )?; } @@ -609,9 +618,9 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<' let new_ptr = self.memory.reallocate( ptr, old_size, - old_align, + Align::from_bytes(old_align, old_align).unwrap(), new_size, - new_align, + Align::from_bytes(new_align, new_align).unwrap(), MemoryKind::Rust.into(), )?; self.write_primval(dest, PrimVal::Ptr(new_ptr), dest_ty)?; diff --git a/miri/intrinsic.rs b/miri/intrinsic.rs index 705c332523397..3357f0bba3927 100644 --- a/miri/intrinsic.rs +++ b/miri/intrinsic.rs @@ -3,7 +3,7 @@ use rustc::traits::Reveal; use rustc::ty::layout::{TyLayout, LayoutOf}; use rustc::ty; -use rustc::mir::interpret::{EvalResult, PrimVal, PrimValKind, Value, Pointer, AccessKind, PtrAndAlign}; +use rustc::mir::interpret::{EvalResult, PrimVal, PrimValKind, Value, Pointer}; use rustc_mir::interpret::{Place, PlaceExtra, HasMemory, EvalContext, ValTy}; use helpers::EvalContextExt as HelperEvalContextExt; @@ -87,8 +87,10 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<' "atomic_load_acq" | "volatile_load" => { let ptr = self.into_ptr(args[0].value)?; + let align = self.layout_of(args[0].ty)?.align; + let valty = ValTy { - value: Value::by_ref(ptr), + value: Value::ByRef(ptr, align), ty: substs.type_at(0), }; self.write_value(valty, dest)?; @@ -99,8 +101,9 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<' "atomic_store_rel" | "volatile_store" => { let ty = substs.type_at(0); + let align = self.layout_of(ty)?.align; let dest = self.into_ptr(args[0].value)?; - self.write_value_to_ptr(args[1].value, dest, ty)?; + self.write_value_to_ptr(args[1].value, dest, align, ty)?; } "atomic_fence_acq" => { @@ -109,9 +112,10 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<' _ 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 change = self.value_to_primval(args[1])?; - let old = self.read_value(ptr, ty)?; + let old = self.read_value(ptr, align, ty)?; let old = match old { Value::ByVal(val) => val, Value::ByRef { .. } => bug!("just read the value, can't be byref"), @@ -119,7 +123,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<' }; self.write_primval(dest, old, ty)?; self.write_primval( - Place::from_primval_ptr(ptr), + Place::from_primval_ptr(ptr, align), change, ty, )?; @@ -127,10 +131,11 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<' _ 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 expect_old = self.value_to_primval(args[1])?; let change = self.value_to_primval(args[2])?; - let old = self.read_value(ptr, ty)?; + let old = self.read_value(ptr, align, ty)?; let old = match old { Value::ByVal(val) => val, Value::ByRef { .. } => bug!("just read the value, can't be byref"), @@ -143,7 +148,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<' }; self.write_value(valty, dest)?; self.write_primval( - Place::from_primval_ptr(ptr), + Place::from_primval_ptr(ptr, dest_layout.align), change, ty, )?; @@ -175,9 +180,10 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<' "atomic_xsub_acqrel" | "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 change = self.value_to_primval(args[1])?; - let old = self.read_value(ptr, ty)?; + let old = self.read_value(ptr, align, ty)?; let old = match old { Value::ByVal(val) => val, Value::ByRef { .. } => bug!("just read the value, can't be byref"), @@ -196,7 +202,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<' }; // FIXME: what do atomics do on overflow? let (val, _) = self.binary_op(op, old, ty, change, ty)?; - self.write_primval(Place::from_primval_ptr(ptr), val, ty)?; + self.write_primval(Place::from_primval_ptr(ptr, dest_layout.align), val, ty)?; } "breakpoint" => unimplemented!(), // halt miri @@ -210,14 +216,16 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<' if count * elem_size != 0 { // 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.abi(); + let elem_align = elem_layout.align; let src = self.into_ptr(args[0].value)?; + let src_align = self.layout_of(args[0].ty)?.align; let dest = self.into_ptr(args[1].value)?; self.memory.copy( src, + src_align, dest, - count * elem_size, elem_align, + count * elem_size, intrinsic_name.ends_with("_nonoverlapping"), )?; } @@ -241,7 +249,8 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<' "discriminant_value" => { let ty = substs.type_at(0); let adt_ptr = self.into_ptr(args[0].value)?; - let place = Place::from_primval_ptr(adt_ptr); + let adt_align = self.layout_of(args[0].ty)?.align; + let place = Place::from_primval_ptr(adt_ptr, adt_align); let discr_val = self.read_discriminant_value(place, ty)?; self.write_primval(dest, PrimVal::Bytes(discr_val), dest_layout.ty)?; } @@ -312,7 +321,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<' let size = dest_layout.size.bytes(); let init = |this: &mut Self, val: Value| { let zero_val = match val { - Value::ByRef(PtrAndAlign { ptr, .. }) => { + Value::ByRef(ptr, _) => { // These writes have no alignment restriction anyway. this.memory.write_repeat(ptr, 0, size)?; val @@ -326,7 +335,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<' let ptr = this.alloc_ptr(dest_layout.ty)?; let ptr = Pointer::from(PrimVal::Ptr(ptr)); this.memory.write_repeat(ptr, 0, size)?; - Value::by_ref(ptr) + Value::ByRef(ptr, dest_layout.align) } } } @@ -340,12 +349,11 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<' match dest { Place::Local { frame, local } => self.modify_local(frame, local, init)?, Place::Ptr { - ptr: PtrAndAlign { ptr, aligned: true }, + ptr: ptr, + align: _align, extra: PlaceExtra::None, } => self.memory.write_repeat(ptr, 0, size)?, - Place::Ptr { .. } => { - bug!("init intrinsic tried to write to fat or unaligned ptr target") - } + _ => bug!("TODO"), } } @@ -367,7 +375,8 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<' "move_val_init" => { let ty = substs.type_at(0); let ptr = self.into_ptr(args[0].value)?; - self.write_value_to_ptr(args[1].value, ptr, ty)?; + let align = self.layout_of(args[0].ty)?.align; + self.write_value_to_ptr(args[1].value, ptr, align, ty)?; } "needs_drop" => { @@ -533,14 +542,10 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<' "transmute" => { let src_ty = substs.type_at(0); + let src_align = self.layout_of(src_ty)?.align; let ptr = self.force_allocation(dest)?.to_ptr()?; - self.write_maybe_aligned_mut( - /*aligned*/ - false, - |ectx| { - ectx.write_value_to_ptr(args[0].value, ptr.into(), src_ty) - }, - )?; + let dest_align = self.layout_of(substs.type_at(1))?.align; + self.write_value_to_ptr(args[0].value, ptr.into(), dest_align, src_ty); } "unchecked_shl" => { @@ -612,7 +617,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<' "uninit" => { let size = dest_layout.size.bytes(); let uninit = |this: &mut Self, val: Value| match val { - Value::ByRef(PtrAndAlign { ptr, .. }) => { + Value::ByRef(ptr, _) => { this.memory.mark_definedness(ptr, size, false)?; Ok(val) } @@ -621,12 +626,11 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<' match dest { Place::Local { frame, local } => self.modify_local(frame, local, uninit)?, Place::Ptr { - ptr: PtrAndAlign { ptr, aligned: true }, + ptr: ptr, + align: _align, extra: PlaceExtra::None, } => self.memory.mark_definedness(ptr, size, false)?, - Place::Ptr { .. } => { - bug!("uninit intrinsic tried to write to fat or unaligned ptr target") - } + _ => bug!("todo"), } } @@ -639,7 +643,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_layout.align.abi(), Some(AccessKind::Write))?; + self.memory.check_align(ptr, ty_layout.align)?; self.memory.write_repeat(ptr, val_byte, ty_layout.size.bytes() * count)?; } } diff --git a/miri/lib.rs b/miri/lib.rs index d4c211e1fd959..d458a3c47e8c3 100644 --- a/miri/lib.rs +++ b/miri/lib.rs @@ -20,7 +20,6 @@ extern crate lazy_static; use rustc::ty::{self, TyCtxt}; use rustc::ty::layout::{TyLayout, LayoutOf}; use rustc::hir::def_id::DefId; -use rustc::ty::subst::Substs; use rustc::mir; use rustc::traits; @@ -87,7 +86,7 @@ pub fn eval_main<'a, 'tcx: 'a>( // Return value let size = ecx.tcx.data_layout.pointer_size.bytes(); - let align = ecx.tcx.data_layout.pointer_align.abi(); + let align = ecx.tcx.data_layout.pointer_align; let ret_ptr = ecx.memory_mut().allocate(size, align, Some(MemoryKind::Stack))?; cleanup_ptr = Some(ret_ptr); @@ -96,7 +95,7 @@ pub fn eval_main<'a, 'tcx: 'a>( start_instance, start_mir.span, start_mir, - Place::from_ptr(ret_ptr), + Place::from_ptr(ret_ptr, align), StackPopCleanup::None, )?; @@ -126,8 +125,9 @@ pub fn eval_main<'a, 'tcx: 'a>( let ty = ecx.tcx.mk_imm_ptr(ecx.tcx.mk_imm_ptr(ecx.tcx.types.u8)); let foo = ecx.memory.allocate_cached(b"foo\0"); let ptr_size = ecx.memory.pointer_size(); - let foo_ptr = ecx.memory.allocate(ptr_size * 1, ptr_size, None)?; - ecx.memory.write_primval(foo_ptr.into(), PrimVal::Ptr(foo.into()), ptr_size, false)?; + let ptr_align = ecx.tcx.data_layout.pointer_align; + let foo_ptr = ecx.memory.allocate(ptr_size, ptr_align, None)?; + ecx.memory.write_primval(foo_ptr, ptr_align, PrimVal::Ptr(foo.into()), ptr_size, false)?; ecx.memory.mark_static_initalized(foo_ptr.alloc_id, Mutability::Immutable)?; ecx.write_ptr(dest, foo_ptr.into(), ty)?; @@ -158,7 +158,7 @@ pub fn eval_main<'a, 'tcx: 'a>( Ok(()) } - let mut ecx = EvalContext::new(tcx, ty::ParamEnv::empty(traits::Reveal::All), limits, Default::default(), Default::default(), Substs::empty()); + let mut ecx = EvalContext::new(tcx, ty::ParamEnv::empty(traits::Reveal::All), limits, Default::default(), Default::default()); match run_main(&mut ecx, main_id, start_wrapper) { Ok(()) => { let leaks = ecx.memory().leak_report(); @@ -310,22 +310,20 @@ impl<'tcx> Machine<'tcx> for Evaluator<'tcx> { // FIXME: check that it's `#[linkage = "extern_weak"]` trace!("Initializing an extern global with NULL"); let ptr_size = ecx.memory.pointer_size(); + let ptr_align = ecx.tcx.data_layout.pointer_align; let ptr = ecx.memory.allocate( ptr_size, - ptr_size, + ptr_align, None, )?; - ecx.memory.write_ptr_sized_unsigned(ptr, PrimVal::Bytes(0))?; + ecx.memory.write_ptr_sized_unsigned(ptr, ptr_align, PrimVal::Bytes(0))?; ecx.memory.mark_static_initalized(ptr.alloc_id, mutability)?; ecx.tcx.interpret_interner.borrow_mut().cache( GlobalId { instance, promoted: None, }, - PtrAndAlign { - ptr: ptr.into(), - aligned: true, - }, + ptr.into(), ); Ok(()) } diff --git a/miri/operator.rs b/miri/operator.rs index e70f1b12628ac..919997a5217cb 100644 --- a/miri/operator.rs +++ b/miri/operator.rs @@ -153,7 +153,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<' map_to_primval(left.overflowing_offset(right as u64, self)), BitAnd if !signed => { - let base_mask : u64 = !(self.memory.get(left.alloc_id)?.align - 1); + let base_mask : u64 = !(self.memory.get(left.alloc_id)?.align.abi() - 1); let right = right as u64; if right & base_mask == base_mask { // Case 1: The base address bits are all preserved, i.e., right is all-1 there diff --git a/miri/validation.rs b/miri/validation.rs index 52f0c24bd6d18..843dcd4041d77 100644 --- a/miri/validation.rs +++ b/miri/validation.rs @@ -509,7 +509,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<' // Check alignment and non-NULLness let (_, align) = self.size_and_align_of_dst(pointee_ty, val)?; let ptr = self.into_ptr(val)?; - self.memory.check_align(ptr, align.abi(), None)?; + self.memory.check_align(ptr, align)?; // Recurse let pointee_place = self.val_to_place(val, pointee_ty)?; @@ -567,7 +567,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<' // Tracking the same state for locals not backed by memory would just duplicate too // much machinery. // FIXME: We ignore alignment. - let (ptr, extra) = self.force_allocation(query.place.1)?.to_ptr_extra_aligned(); + let (ptr, _, extra) = self.force_allocation(query.place.1)?.to_ptr_align_extra(); // Determine the size // FIXME: Can we reuse size_and_align_of_dst for Places? let layout = self.layout_of(query.ty)?; From cabdc5597c6adc2e9f492c9cb682a3b58518bd8c Mon Sep 17 00:00:00 2001 From: David Renshaw Date: Sat, 6 Jan 2018 10:21:24 -0500 Subject: [PATCH 0025/3747] update log deps --- Cargo.toml | 2 ++ miri/bin/miri.rs | 21 ++++++++++++--------- miri/lib.rs | 3 ++- 3 files changed, 16 insertions(+), 10 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 4f0d0fe2ef1cb..cc7de42ceabfb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -26,6 +26,8 @@ byteorder = { version = "1.1", features = ["i128"]} cargo_metadata = { version = "0.2", optional = true } regex = "0.2.2" lazy_static = "1.0" +env_logger = "0.5.0-rc.1" +log = "0.4" [features] cargo_miri = ["cargo_metadata"] diff --git a/miri/bin/miri.rs b/miri/bin/miri.rs index d74c05c0462d9..c3d422a6ff5df 100644 --- a/miri/bin/miri.rs +++ b/miri/bin/miri.rs @@ -191,38 +191,41 @@ fn resource_limits_from_attributes(state: &CompileState) -> miri::ResourceLimits } fn init_logger() { - let format = |record: &log::LogRecord| { - if record.level() == log::LogLevel::Trace { + let format = |formatter: &mut env_logger::fmt::Formatter, record: &log::Record| { + use std::io::Write; + if record.level() == log::Level::Trace { // prepend frame number let indentation = log_settings::settings().indentation; - format!( + writeln!( + formatter, "{indentation}:{lvl}:{module}: {text}", lvl = record.level(), - module = record.location().module_path(), + module = record.module_path().unwrap_or(""), indentation = indentation, text = record.args(), ) } else { - format!( + writeln!( + formatter, "{lvl}:{module}: {text}", lvl = record.level(), - module = record.location().module_path(), + module = record.module_path().unwrap_or(""), text = record.args(), ) } }; - let mut builder = env_logger::LogBuilder::new(); + let mut builder = env_logger::Builder::new(); builder.format(format).filter( None, - log::LogLevelFilter::Info, + log::LevelFilter::Info, ); if std::env::var("MIRI_LOG").is_ok() { builder.parse(&std::env::var("MIRI_LOG").unwrap()); } - builder.init().unwrap(); + builder.init(); } fn find_sysroot() -> String { diff --git a/miri/lib.rs b/miri/lib.rs index d458a3c47e8c3..9f6550ac072ed 100644 --- a/miri/lib.rs +++ b/miri/lib.rs @@ -5,9 +5,10 @@ catch_expr, )] -// From rustc. #[macro_use] extern crate log; + +// From rustc. #[macro_use] extern crate rustc; extern crate rustc_mir; From 33af3208fdb2180570c3ef266abc634a45158ef1 Mon Sep 17 00:00:00 2001 From: David Renshaw Date: Sun, 14 Jan 2018 22:31:59 -0500 Subject: [PATCH 0026/3747] update for rust/47205 --- miri/fn_call.rs | 2 +- miri/lib.rs | 8 ++++---- miri/locks.rs | 8 ++++---- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/miri/fn_call.rs b/miri/fn_call.rs index df101739ed919..b46f712818f29 100644 --- a/miri/fn_call.rs +++ b/miri/fn_call.rs @@ -386,7 +386,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<' }; // compute global if not cached let val = match self.tcx.interpret_interner.borrow().get_cached(cid) { - Some(ptr) => ptr, + Some(ptr) => MemoryPointer::new(ptr, 0).into(), None => eval_body(self.tcx, instance, ty::ParamEnv::empty(traits::Reveal::All))?.0, }; let val = self.value_to_primval(ValTy { value: Value::ByRef(val, name_align), diff --git a/miri/lib.rs b/miri/lib.rs index 9f6550ac072ed..92ae0ab8a8204 100644 --- a/miri/lib.rs +++ b/miri/lib.rs @@ -203,7 +203,7 @@ pub struct MemoryData<'tcx> { /// /// Only mutable (static mut, heap, stack) allocations have an entry in this map. /// The entry is created when allocating the memory and deleted after deallocation. - locks: HashMap>>, + locks: HashMap>>, } impl<'tcx> Machine<'tcx> for Evaluator<'tcx> { @@ -324,7 +324,7 @@ impl<'tcx> Machine<'tcx> for Evaluator<'tcx> { instance, promoted: None, }, - ptr.into(), + ptr.alloc_id, ); Ok(()) } @@ -340,14 +340,14 @@ impl<'tcx> Machine<'tcx> for Evaluator<'tcx> { fn add_lock<'a>( mem: &mut Memory<'a, 'tcx, Self>, - id: u64, + id: AllocId, ) { mem.data.locks.insert(id, RangeMap::new()); } fn free_lock<'a>( mem: &mut Memory<'a, 'tcx, Self>, - id: u64, + id: AllocId, len: u64, ) -> EvalResult<'tcx> { mem.data.locks diff --git a/miri/locks.rs b/miri/locks.rs index 3a9df6a38dff1..f0e8815c4fc50 100644 --- a/miri/locks.rs +++ b/miri/locks.rs @@ -109,7 +109,7 @@ impl<'a, 'tcx: 'a> MemoryExt<'tcx> for Memory<'a, 'tcx, Evaluator<'tcx>> { if len == 0 { return Ok(()); } - let locks = match self.data.locks.get(&ptr.alloc_id.0) { + let locks = match self.data.locks.get(&ptr.alloc_id) { Some(locks) => locks, // immutable static or other constant memory None => return Ok(()), @@ -148,7 +148,7 @@ impl<'a, 'tcx: 'a> MemoryExt<'tcx> for Memory<'a, 'tcx, Evaluator<'tcx>> { ); self.check_bounds(ptr.offset(len, &*self)?, true)?; // if ptr.offset is in bounds, then so is ptr (because offset checks for overflow) - let locks = match self.data.locks.get_mut(&ptr.alloc_id.0) { + let locks = match self.data.locks.get_mut(&ptr.alloc_id) { Some(locks) => locks, // immutable static or other constant memory None => return Ok(()), @@ -197,7 +197,7 @@ impl<'a, 'tcx: 'a> MemoryExt<'tcx> for Memory<'a, 'tcx, Evaluator<'tcx>> { ) -> EvalResult<'tcx> { assert!(len > 0); let cur_frame = self.cur_frame; - let locks = match self.data.locks.get_mut(&ptr.alloc_id.0) { + let locks = match self.data.locks.get_mut(&ptr.alloc_id) { Some(locks) => locks, // immutable static or other constant memory None => return Ok(()), @@ -275,7 +275,7 @@ impl<'a, 'tcx: 'a> MemoryExt<'tcx> for Memory<'a, 'tcx, Evaluator<'tcx>> { frame: cur_frame, path: lock_path.clone(), }; - let locks = match self.data.locks.get_mut(&ptr.alloc_id.0) { + let locks = match self.data.locks.get_mut(&ptr.alloc_id) { Some(locks) => locks, // immutable static or other constant memory None => return Ok(()), From d289c0f46467fc8abd7b89129116e8dd959c3e34 Mon Sep 17 00:00:00 2001 From: David Renshaw Date: Mon, 15 Jan 2018 09:47:17 -0500 Subject: [PATCH 0027/3747] partially deal with rust/46479 --- miri/lib.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/miri/lib.rs b/miri/lib.rs index 92ae0ab8a8204..091a3b7e1dfb9 100644 --- a/miri/lib.rs +++ b/miri/lib.rs @@ -75,7 +75,14 @@ pub fn eval_main<'a, 'tcx: 'a>( } if let Some(start_id) = start_wrapper { - let start_instance = ty::Instance::mono(ecx.tcx, start_id); + let main_ret_ty = ecx.tcx.fn_sig(main_id).output(); + let main_ret_ty = main_ret_ty.no_late_bound_regions().unwrap(); + let start_instance = ty::Instance::resolve( + ecx.tcx, + ty::ParamEnv::empty(traits::Reveal::All), + start_id, + ecx.tcx.mk_substs( + ::std::iter::once(ty::subst::Kind::from(main_ret_ty)))).unwrap(); let start_mir = ecx.load_mir(start_instance.def)?; if start_mir.arg_count != 3 { From 61833b9aeab8bf8f0c0c0e42b7c96b6eceb37d0d Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Tue, 30 Jan 2018 15:11:09 +0100 Subject: [PATCH 0028/3747] Update compiletest_rs dependency to match clippy's --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index bbb3958ac35f8..70457fed9077a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -31,4 +31,4 @@ lazy_static = "1.0" cargo_miri = ["cargo_metadata"] [dev-dependencies] -compiletest_rs = { version = "0.3.3", features = ["tmp"] } +compiletest_rs = { version = "0.3.6", features = ["tmp"] } From d4712ca37500f26bbcbf97edcb27820717f769f7 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Tue, 6 Mar 2018 15:36:52 +0100 Subject: [PATCH 0029/3747] Update compiletest_rs dependency --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 70457fed9077a..b32f0d0e9a72d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -31,4 +31,4 @@ lazy_static = "1.0" cargo_miri = ["cargo_metadata"] [dev-dependencies] -compiletest_rs = { version = "0.3.6", features = ["tmp"] } +compiletest_rs = { version = "0.3.7", features = ["tmp"] } From 753da676bacd058cd6ef58aa23f02b787381421e Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Sun, 14 Jan 2018 18:59:13 +0100 Subject: [PATCH 0030/3747] Rustup --- miri/bin/miri.rs | 65 +++++++------------------------------ miri/fn_call.rs | 24 +++++++------- miri/helpers.rs | 2 +- miri/intrinsic.rs | 15 ++++----- miri/lib.rs | 81 +++++++++++++++++++++++++++------------------- miri/locks.rs | 2 +- miri/operator.rs | 4 +-- miri/tls.rs | 4 +-- miri/validation.rs | 44 ++++++++++++++++--------- 9 files changed, 113 insertions(+), 128 deletions(-) diff --git a/miri/bin/miri.rs b/miri/bin/miri.rs index c3d422a6ff5df..bbc8322194fac 100644 --- a/miri/bin/miri.rs +++ b/miri/bin/miri.rs @@ -5,6 +5,7 @@ extern crate miri; extern crate rustc; extern crate rustc_driver; extern crate rustc_errors; +extern crate rustc_trans_utils; extern crate env_logger; extern crate log_settings; extern crate syntax; @@ -17,7 +18,8 @@ use rustc_driver::driver::{CompileState, CompileController}; use rustc::session::config::{self, Input, ErrorOutputType}; use rustc::hir::{self, itemlikevisit}; use rustc::ty::TyCtxt; -use syntax::ast::{self, MetaItemKind, NestedMetaItemKind}; +use rustc_trans_utils::trans_crate::TransCrate; +use syntax::ast; use std::path::PathBuf; struct MiriCompilerCalls { @@ -61,6 +63,7 @@ impl<'a> CompilerCalls<'a> for MiriCompilerCalls { } fn late_callback( &mut self, + trans: &TransCrate, matches: &getopts::Matches, sess: &Session, cstore: &CrateStore, @@ -68,7 +71,7 @@ impl<'a> CompilerCalls<'a> for MiriCompilerCalls { odir: &Option, ofile: &Option, ) -> Compilation { - self.default.late_callback(matches, sess, cstore, input, odir, ofile) + self.default.late_callback(trans, matches, sess, cstore, input, odir, ofile) } fn build_controller( &mut self, @@ -98,11 +101,9 @@ fn after_analysis<'a, 'tcx>(state: &mut CompileState<'a, 'tcx>) { state.session.abort_if_errors(); let tcx = state.tcx.unwrap(); - let limits = resource_limits_from_attributes(state); if std::env::args().any(|arg| arg == "--test") { struct Visitor<'a, 'tcx: 'a>( - miri::ResourceLimits, TyCtxt<'a, 'tcx, 'tcx>, &'a CompileState<'a, 'tcx> ); @@ -113,13 +114,13 @@ fn after_analysis<'a, 'tcx>(state: &mut CompileState<'a, 'tcx>) { attr.name().map_or(false, |n| n == "test") }) { - let did = self.1.hir.body_owner_def_id(body_id); + let did = self.0.hir.body_owner_def_id(body_id); println!( "running test: {}", - self.1.def_path_debug_str(did), + self.0.def_path_debug_str(did), ); - miri::eval_main(self.1, did, None, self.0); - self.2.session.abort_if_errors(); + miri::eval_main(self.0, did, None); + self.1.session.abort_if_errors(); } } } @@ -127,7 +128,7 @@ fn after_analysis<'a, 'tcx>(state: &mut CompileState<'a, 'tcx>) { fn visit_impl_item(&mut self, _impl_item: &'hir hir::ImplItem) {} } state.hir_crate.unwrap().visit_all_item_likes( - &mut Visitor(limits, tcx, state), + &mut Visitor(tcx, state), ); } else if let Some((entry_node_id, _)) = *state.session.entry_fn.borrow() { let entry_def_id = tcx.hir.local_def_id(entry_node_id); @@ -138,7 +139,7 @@ fn after_analysis<'a, 'tcx>(state: &mut CompileState<'a, 'tcx>) { None } }); - miri::eval_main(tcx, entry_def_id, start_wrapper, limits); + miri::eval_main(tcx, entry_def_id, start_wrapper); state.session.abort_if_errors(); } else { @@ -146,50 +147,6 @@ fn after_analysis<'a, 'tcx>(state: &mut CompileState<'a, 'tcx>) { } } -fn resource_limits_from_attributes(state: &CompileState) -> miri::ResourceLimits { - let mut limits = miri::ResourceLimits::default(); - let krate = state.hir_crate.as_ref().unwrap(); - let err_msg = "miri attributes need to be in the form `miri(key = value)`"; - let extract_int = |lit: &syntax::ast::Lit| -> u128 { - match lit.node { - syntax::ast::LitKind::Int(i, _) => i, - _ => { - state.session.span_fatal( - lit.span, - "expected an integer literal", - ) - } - } - }; - - for attr in krate.attrs.iter().filter(|a| { - a.name().map_or(false, |n| n == "miri") - }) - { - if let Some(items) = attr.meta_item_list() { - for item in items { - if let NestedMetaItemKind::MetaItem(ref inner) = item.node { - if let MetaItemKind::NameValue(ref value) = inner.node { - match &inner.name().as_str()[..] { - "memory_size" => limits.memory_size = extract_int(value) as u64, - "step_limit" => limits.step_limit = extract_int(value) as u64, - "stack_limit" => limits.stack_limit = extract_int(value) as usize, - _ => state.session.span_err(item.span, "unknown miri attribute"), - } - } else { - state.session.span_err(inner.span, err_msg); - } - } else { - state.session.span_err(item.span, err_msg); - } - } - } else { - state.session.span_err(attr.span, err_msg); - } - } - limits -} - fn init_logger() { let format = |formatter: &mut env_logger::fmt::Formatter, record: &log::Record| { use std::io::Write; diff --git a/miri/fn_call.rs b/miri/fn_call.rs index b46f712818f29..d07929e0d5608 100644 --- a/miri/fn_call.rs +++ b/miri/fn_call.rs @@ -8,8 +8,6 @@ use syntax::codemap::Span; use std::mem; -use rustc::traits; - use super::*; use tls::MemoryExt; @@ -49,7 +47,7 @@ pub trait EvalContextExt<'tcx> { fn write_null(&mut self, dest: Place, dest_ty: Ty<'tcx>) -> EvalResult<'tcx>; } -impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<'tcx>> { +impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super::Evaluator<'tcx>> { fn eval_fn_call( &mut self, instance: ty::Instance<'tcx>, @@ -385,13 +383,17 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<' promoted: None, }; // compute global if not cached - let val = match self.tcx.interpret_interner.borrow().get_cached(cid) { - Some(ptr) => MemoryPointer::new(ptr, 0).into(), - None => eval_body(self.tcx, instance, ty::ParamEnv::empty(traits::Reveal::All))?.0, + let value: Value = match self.tcx.interpret_interner.get_cached(instance.def_id()) { + Some(ptr) => { + Value::ByRef(MemoryPointer::new(ptr, 0).into(), name_align) + } + None => { + let res: Option<(Value, Pointer, Ty)> = eval_body(self.tcx.tcx, cid, ty::ParamEnv::reveal_all()); + res.ok_or_else(||EvalErrorKind::MachineError("".to_string()))?.0 + }, }; - let val = self.value_to_primval(ValTy { value: Value::ByRef(val, name_align), - ty: args[0].ty })?.to_u64()?; - if val == name { + let value = self.value_to_primval(ValTy { value, ty: args[0].ty })?.to_u64()?; + if value == name { result = Some(path_value); break; } @@ -420,7 +422,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<' }; // 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, ty::LvaluePreference::NoPreference) + let key_type = args[0].ty.builtin_deref(true) .ok_or(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; @@ -502,7 +504,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<' for item in mem::replace(&mut items, Default::default()).iter() { if item.ident.name == *segment { if path_it.peek().is_none() { - return Some(ty::Instance::mono(self.tcx, item.def.def_id())); + return Some(ty::Instance::mono(self.tcx.tcx, item.def.def_id())); } items = self.tcx.item_children(item.def.def_id()); diff --git a/miri/helpers.rs b/miri/helpers.rs index 0e541cf292086..3dd499f7a62e9 100644 --- a/miri/helpers.rs +++ b/miri/helpers.rs @@ -18,7 +18,7 @@ pub trait EvalContextExt<'tcx> { ) -> EvalResult<'tcx, Pointer>; } -impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<'tcx>> { +impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super::Evaluator<'tcx>> { fn wrapping_pointer_offset( &self, ptr: Pointer, diff --git a/miri/intrinsic.rs b/miri/intrinsic.rs index 3357f0bba3927..5047ab5b6ac21 100644 --- a/miri/intrinsic.rs +++ b/miri/intrinsic.rs @@ -1,5 +1,4 @@ use rustc::mir; -use rustc::traits::Reveal; use rustc::ty::layout::{TyLayout, LayoutOf}; use rustc::ty; @@ -19,7 +18,7 @@ pub trait EvalContextExt<'tcx> { ) -> EvalResult<'tcx>; } -impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<'tcx>> { +impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super::Evaluator<'tcx>> { fn call_intrinsic( &mut self, instance: ty::Instance<'tcx>, @@ -349,7 +348,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<' match dest { Place::Local { frame, local } => self.modify_local(frame, local, init)?, Place::Ptr { - ptr: ptr, + ptr, align: _align, extra: PlaceExtra::None, } => self.memory.write_repeat(ptr, 0, size)?, @@ -381,8 +380,8 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<' "needs_drop" => { let ty = substs.type_at(0); - let env = ty::ParamEnv::empty(Reveal::All); - let needs_drop = ty.needs_drop(self.tcx, env); + let env = ty::ParamEnv::reveal_all(); + let needs_drop = ty.needs_drop(self.tcx.tcx, env); self.write_primval( dest, PrimVal::from_bool(needs_drop), @@ -542,10 +541,10 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<' "transmute" => { let src_ty = substs.type_at(0); - let src_align = self.layout_of(src_ty)?.align; + let _src_align = self.layout_of(src_ty)?.align; let ptr = self.force_allocation(dest)?.to_ptr()?; let dest_align = self.layout_of(substs.type_at(1))?.align; - self.write_value_to_ptr(args[0].value, ptr.into(), dest_align, src_ty); + self.write_value_to_ptr(args[0].value, ptr.into(), dest_align, src_ty).unwrap(); } "unchecked_shl" => { @@ -626,7 +625,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<' match dest { Place::Local { frame, local } => self.modify_local(frame, local, uninit)?, Place::Ptr { - ptr: ptr, + ptr, align: _align, extra: PlaceExtra::None, } => self.memory.mark_definedness(ptr, size, false)?, diff --git a/miri/lib.rs b/miri/lib.rs index 091a3b7e1dfb9..99bc91a171776 100644 --- a/miri/lib.rs +++ b/miri/lib.rs @@ -22,7 +22,6 @@ use rustc::ty::{self, TyCtxt}; use rustc::ty::layout::{TyLayout, LayoutOf}; use rustc::hir::def_id::DefId; use rustc::mir; -use rustc::traits; use syntax::ast::Mutability; use syntax::codemap::Span; @@ -56,14 +55,13 @@ pub fn eval_main<'a, 'tcx: 'a>( tcx: TyCtxt<'a, 'tcx, 'tcx>, main_id: DefId, start_wrapper: Option, - limits: ResourceLimits, ) { - fn run_main<'a, 'tcx: 'a>( - ecx: &mut rustc_mir::interpret::EvalContext<'a, 'tcx, Evaluator<'tcx>>, + fn run_main<'a, 'mir: 'a, 'tcx: 'mir>( + ecx: &mut rustc_mir::interpret::EvalContext<'a, 'mir, 'tcx, Evaluator<'tcx>>, main_id: DefId, start_wrapper: Option, ) -> EvalResult<'tcx> { - let main_instance = ty::Instance::mono(ecx.tcx, main_id); + let main_instance = ty::Instance::mono(ecx.tcx.tcx, main_id); let main_mir = ecx.load_mir(main_instance.def)?; let mut cleanup_ptr = None; // Pointer to be deallocated when we are done @@ -78,8 +76,8 @@ pub fn eval_main<'a, 'tcx: 'a>( let main_ret_ty = ecx.tcx.fn_sig(main_id).output(); let main_ret_ty = main_ret_ty.no_late_bound_regions().unwrap(); let start_instance = ty::Instance::resolve( - ecx.tcx, - ty::ParamEnv::empty(traits::Reveal::All), + ecx.tcx.tcx, + ty::ParamEnv::reveal_all(), start_id, ecx.tcx.mk_substs( ::std::iter::once(ty::subst::Kind::from(main_ret_ty)))).unwrap(); @@ -112,8 +110,8 @@ pub fn eval_main<'a, 'tcx: 'a>( // First argument: pointer to main() let main_ptr = ecx.memory_mut().create_fn_alloc(main_instance); let dest = ecx.eval_place(&mir::Place::Local(args.next().unwrap()))?; - let main_ty = main_instance.ty(ecx.tcx); - let main_ptr_ty = ecx.tcx.mk_fn_ptr(main_ty.fn_sig(ecx.tcx)); + let main_ty = main_instance.ty(ecx.tcx.tcx); + let main_ptr_ty = ecx.tcx.mk_fn_ptr(main_ty.fn_sig(ecx.tcx.tcx)); ecx.write_value( ValTy { value: Value::ByVal(PrimVal::Ptr(main_ptr)), @@ -136,7 +134,7 @@ pub fn eval_main<'a, 'tcx: 'a>( let ptr_align = ecx.tcx.data_layout.pointer_align; let foo_ptr = ecx.memory.allocate(ptr_size, ptr_align, None)?; ecx.memory.write_primval(foo_ptr, ptr_align, PrimVal::Ptr(foo.into()), ptr_size, false)?; - ecx.memory.mark_static_initalized(foo_ptr.alloc_id, Mutability::Immutable)?; + ecx.memory.mark_static_initialized(foo_ptr.alloc_id, Mutability::Immutable)?; ecx.write_ptr(dest, foo_ptr.into(), ty)?; assert!(args.next().is_none(), "start lang item has more arguments than expected"); @@ -166,7 +164,7 @@ pub fn eval_main<'a, 'tcx: 'a>( Ok(()) } - let mut ecx = EvalContext::new(tcx, ty::ParamEnv::empty(traits::Reveal::All), limits, Default::default(), Default::default()); + let mut ecx = EvalContext::new(tcx.at(syntax::codemap::DUMMY_SP), ty::ParamEnv::reveal_all(), Default::default(), Default::default()); match run_main(&mut ecx, main_id, start_wrapper) { Ok(()) => { let leaks = ecx.memory().leak_report(); @@ -175,7 +173,7 @@ pub fn eval_main<'a, 'tcx: 'a>( } } Err(mut e) => { - ecx.report(&mut e); + ecx.report(&mut e, true, None); } } } @@ -213,13 +211,13 @@ pub struct MemoryData<'tcx> { locks: HashMap>>, } -impl<'tcx> Machine<'tcx> for Evaluator<'tcx> { +impl<'mir, 'tcx: 'mir> Machine<'mir, 'tcx> for Evaluator<'tcx> { type MemoryData = MemoryData<'tcx>; type MemoryKinds = memory::MemoryKind; /// Returns Ok() when the function was handled, fail otherwise fn eval_fn_call<'a>( - ecx: &mut EvalContext<'a, 'tcx, Self>, + ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, instance: ty::Instance<'tcx>, destination: Option<(Place, mir::BasicBlock)>, args: &[ValTy<'tcx>], @@ -230,7 +228,7 @@ impl<'tcx> Machine<'tcx> for Evaluator<'tcx> { } fn call_intrinsic<'a>( - ecx: &mut rustc_mir::interpret::EvalContext<'a, 'tcx, Self>, + ecx: &mut rustc_mir::interpret::EvalContext<'a, 'mir, 'tcx, Self>, instance: ty::Instance<'tcx>, args: &[ValTy<'tcx>], dest: Place, @@ -241,7 +239,7 @@ impl<'tcx> Machine<'tcx> for Evaluator<'tcx> { } fn try_ptr_op<'a>( - ecx: &rustc_mir::interpret::EvalContext<'a, 'tcx, Self>, + ecx: &rustc_mir::interpret::EvalContext<'a, 'mir, 'tcx, Self>, bin_op: mir::BinOp, left: PrimVal, left_ty: ty::Ty<'tcx>, @@ -251,17 +249,35 @@ impl<'tcx> Machine<'tcx> for Evaluator<'tcx> { ecx.ptr_op(bin_op, left, left_ty, right, right_ty) } - fn mark_static_initialized(m: memory::MemoryKind) -> EvalResult<'tcx> { - use memory::MemoryKind::*; + fn mark_static_initialized<'a>( + _mem: &mut Memory<'a, 'mir, 'tcx, Self>, + _id: AllocId, + _mutability: Mutability, + ) -> EvalResult<'tcx, bool> { + /*use memory::MemoryKind::*; match m { // FIXME: This could be allowed, but not for env vars set during miri execution Env => err!(Unimplemented("statics can't refer to env vars".to_owned())), - _ => Ok(()), - } + _ => Ok(false), // TODO: What does the bool mean? + }*/ + Ok(true) + } + + fn init_static<'a>( + ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, + cid: GlobalId<'tcx>, + ) -> EvalResult<'tcx, AllocId> { + let def_id = cid.instance.def_id(); + let ty = ecx.tcx.type_of(def_id); + let layout = ecx.tcx.layout_of(ty::ParamEnvAnd { + param_env: ty::ParamEnv::reveal_all(), + value: ty + }).expect("Couldn't compute layout for the type of a static"); + ecx.memory.allocate(layout.size.bytes(), layout.align, None).map(|mptr|mptr.alloc_id) } fn box_alloc<'a>( - ecx: &mut EvalContext<'a, 'tcx, Self>, + ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, ty: ty::Ty<'tcx>, dest: Place, ) -> EvalResult<'tcx> { @@ -269,7 +285,7 @@ impl<'tcx> Machine<'tcx> for Evaluator<'tcx> { // Call the `exchange_malloc` lang item let malloc = ecx.tcx.lang_items().exchange_malloc_fn().unwrap(); - let malloc = ty::Instance::mono(ecx.tcx, malloc); + let malloc = ty::Instance::mono(ecx.tcx.tcx, malloc); let malloc_mir = ecx.load_mir(malloc.def)?; ecx.push_stack_frame( malloc, @@ -311,7 +327,7 @@ impl<'tcx> Machine<'tcx> for Evaluator<'tcx> { } fn global_item_with_linkage<'a>( - ecx: &mut EvalContext<'a, 'tcx, Self>, + ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, instance: ty::Instance<'tcx>, mutability: Mutability, ) -> EvalResult<'tcx> { @@ -325,19 +341,16 @@ impl<'tcx> Machine<'tcx> for Evaluator<'tcx> { None, )?; ecx.memory.write_ptr_sized_unsigned(ptr, ptr_align, PrimVal::Bytes(0))?; - ecx.memory.mark_static_initalized(ptr.alloc_id, mutability)?; - ecx.tcx.interpret_interner.borrow_mut().cache( - GlobalId { - instance, - promoted: None, - }, + ecx.memory.mark_static_initialized(ptr.alloc_id, mutability)?; + ecx.tcx.interpret_interner.cache( + instance.def_id(), ptr.alloc_id, ); Ok(()) } fn check_locks<'a>( - mem: &Memory<'a, 'tcx, Self>, + mem: &Memory<'a, 'mir, 'tcx, Self>, ptr: MemoryPointer, size: u64, access: AccessKind, @@ -346,14 +359,14 @@ impl<'tcx> Machine<'tcx> for Evaluator<'tcx> { } fn add_lock<'a>( - mem: &mut Memory<'a, 'tcx, Self>, + mem: &mut Memory<'a, 'mir, 'tcx, Self>, id: AllocId, ) { mem.data.locks.insert(id, RangeMap::new()); } fn free_lock<'a>( - mem: &mut Memory<'a, 'tcx, Self>, + mem: &mut Memory<'a, 'mir, 'tcx, Self>, id: AllocId, len: u64, ) -> EvalResult<'tcx> { @@ -379,14 +392,14 @@ impl<'tcx> Machine<'tcx> for Evaluator<'tcx> { } fn end_region<'a>( - ecx: &mut EvalContext<'a, 'tcx, Self>, + ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, reg: Option<::rustc::middle::region::Scope>, ) -> EvalResult<'tcx> { ecx.end_region(reg) } fn validation_op<'a>( - ecx: &mut EvalContext<'a, 'tcx, Self>, + ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, op: ::rustc::mir::ValidationOp, operand: &::rustc::mir::ValidationOperand<'tcx, ::rustc::mir::Place<'tcx>>, ) -> EvalResult<'tcx> { diff --git a/miri/locks.rs b/miri/locks.rs index f0e8815c4fc50..677b0454a546c 100644 --- a/miri/locks.rs +++ b/miri/locks.rs @@ -99,7 +99,7 @@ pub trait MemoryExt<'tcx> { } -impl<'a, 'tcx: 'a> MemoryExt<'tcx> for Memory<'a, 'tcx, Evaluator<'tcx>> { +impl<'a, 'mir, 'tcx: 'mir + 'a> MemoryExt<'tcx> for Memory<'a, 'mir, 'tcx, Evaluator<'tcx>> { fn check_locks( &self, ptr: MemoryPointer, diff --git a/miri/operator.rs b/miri/operator.rs index 919997a5217cb..220f8f9acd541 100644 --- a/miri/operator.rs +++ b/miri/operator.rs @@ -24,7 +24,7 @@ pub trait EvalContextExt<'tcx> { ) -> EvalResult<'tcx, (PrimVal, bool)>; } -impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<'tcx>> { +impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super::Evaluator<'tcx>> { fn ptr_op( &self, bin_op: mir::BinOp, @@ -42,7 +42,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<' match bin_op { Offset if left_kind == Ptr && right_kind == usize => { let pointee_ty = left_ty - .builtin_deref(true, ty::LvaluePreference::NoPreference) + .builtin_deref(true) .expect("Offset called on non-ptr type") .ty; let ptr = self.pointer_offset( diff --git a/miri/tls.rs b/miri/tls.rs index 7f4f194c67f11..e55cbede23394 100644 --- a/miri/tls.rs +++ b/miri/tls.rs @@ -18,7 +18,7 @@ pub trait EvalContextExt<'tcx> { fn run_tls_dtors(&mut self) -> EvalResult<'tcx>; } -impl<'a, 'tcx: 'a> MemoryExt<'tcx> for Memory<'a, 'tcx, Evaluator<'tcx>> { +impl<'a, 'mir, 'tcx: 'mir + 'a> MemoryExt<'tcx> for Memory<'a, 'mir, 'tcx, Evaluator<'tcx>> { fn create_tls_key(&mut self, dtor: Option>) -> TlsKey { let new_key = self.data.next_thread_local; self.data.next_thread_local += 1; @@ -106,7 +106,7 @@ impl<'a, 'tcx: 'a> MemoryExt<'tcx> for Memory<'a, 'tcx, Evaluator<'tcx>> { } } -impl<'a, 'tcx: 'a> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, Evaluator<'tcx>> { +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)?; // FIXME: replace loop by some structure that works with stepping diff --git a/miri/validation.rs b/miri/validation.rs index 843dcd4041d77..801fd952f666d 100644 --- a/miri/validation.rs +++ b/miri/validation.rs @@ -1,15 +1,16 @@ use rustc::hir::{self, Mutability}; use rustc::hir::Mutability::*; use rustc::mir::{self, ValidationOp, ValidationOperand}; -use rustc::ty::{self, Ty, TypeFoldable, TyCtxt}; +use rustc::mir::interpret::GlobalId; +use rustc::ty::{self, Ty, TypeFoldable, TyCtxt, Instance}; use rustc::ty::layout::LayoutOf; use rustc::ty::subst::{Substs, Subst}; use rustc::traits; use rustc::infer::InferCtxt; -use rustc::traits::Reveal; use rustc::middle::region; +use rustc::middle::const_val::ConstVal; use rustc_data_structures::indexed_vec::Idx; -use rustc_mir::interpret::HasMemory; +use rustc_mir::interpret::{HasMemory, eval_body}; use super::{EvalContext, Place, PlaceExtra, ValTy}; use rustc::mir::interpret::{DynamicLifetime, AccessKind, EvalErrorKind, Value, EvalError, EvalResult}; @@ -108,7 +109,7 @@ pub(crate) trait EvalContextExt<'tcx> { ) -> EvalResult<'tcx>; } -impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<'tcx>> { +impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super::Evaluator<'tcx>> { fn abstract_place_projection(&self, proj: &mir::PlaceProjection<'tcx>) -> EvalResult<'tcx, AbsPlaceProjection<'tcx>> { use self::mir::ProjectionElem::*; @@ -117,7 +118,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<' Field(f, _) => Field(f, ()), Index(v) => { let value = self.frame().get_local(v)?; - let ty = self.tcx.types.usize; + let ty = self.tcx.tcx.types.usize; let n = self.value_to_primval(ValTy { value, ty })?.to_u64()?; Index(n) }, @@ -152,7 +153,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<' // because other crates may have been compiled with mir-emit-validate > 0. Ignore those // commands. This makes mir-emit-validate also a flag to control whether miri will do // validation or not. - if self.tcx.sess.opts.debugging_opts.mir_emit_validate == 0 { + if self.tcx.tcx.sess.opts.debugging_opts.mir_emit_validate == 0 { return Ok(()); } debug_assert!(self.memory.cur_frame == self.cur_frame()); @@ -187,7 +188,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<' // We need to monomorphize ty *without* erasing lifetimes trace!("validation_op1: {:?}", operand.ty.sty); - let ty = operand.ty.subst(self.tcx, self.substs()); + let ty = operand.ty.subst(self.tcx.tcx, self.substs()); trace!("validation_op2: {:?}", operand.ty.sty); let place = self.eval_place(&operand.place)?; let abs_place = self.abstract_place(&operand.place)?; @@ -250,7 +251,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<' } fn normalize_type_unerased(&self, ty: Ty<'tcx>) -> Ty<'tcx> { - return normalize_associated_type(self.tcx, &ty); + return normalize_associated_type(self.tcx.tcx, &ty); use syntax::codemap::{Span, DUMMY_SP}; @@ -356,7 +357,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<' where T: MyTransNormalize<'tcx>, { - let param_env = ty::ParamEnv::empty(Reveal::All); + let param_env = ty::ParamEnv::reveal_all(); if !value.has_projections() { return value.clone(); @@ -383,7 +384,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<' } _ => {} } - let tcx = self.tcx; + let tcx = self.tcx.tcx; Ok(match layout.ty.sty { ty::TyBool | ty::TyChar | @@ -393,6 +394,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<' ty::TyFnPtr(_) | ty::TyNever | ty::TyFnDef(..) | + ty::TyGeneratorWitness(..) | ty::TyDynamic(..) | ty::TyForeign(..) => { bug!("TyLayout::field_type({:?}): not applicable", layout) @@ -437,7 +439,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<' substs.field_tys(def_id, tcx).nth(i).unwrap() } - ty::TyTuple(tys, _) => tys[i], + ty::TyTuple(tys) => tys[i], // SIMD vector types. ty::TyAdt(def, ..) if def.repr.simd() => { @@ -558,6 +560,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<' TyAdt(adt, _) if adt.is_box() => true, TySlice(_) | TyAdt(_, _) | TyTuple(..) | TyClosure(..) | TyArray(..) | TyDynamic(..) | TyGenerator(..) | TyForeign(_) => false, + TyGeneratorWitness(..) => bug!("I'm not sure what to return here"), TyParam(_) | TyInfer(_) | TyProjection(_) | TyAnon(..) | TyError => { bug!("I got an incomplete/unnormalized type for validation") } @@ -725,7 +728,18 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<' Ok(()) } TyArray(elem_ty, len) => { - let len = len.val.to_const_int().unwrap().to_u64().unwrap(); + let len_val = match len.val { + ConstVal::Unevaluated(def_id, substs) => { + eval_body(self.tcx.tcx, GlobalId { + instance: Instance::new(def_id, substs), + promoted: None, + }, ty::ParamEnv::reveal_all()) + .ok_or_else(||EvalErrorKind::MachineError("".to_string()))? + .0 + } + ConstVal::Value(val) => val, + }; + let len = ConstVal::Value(len_val).unwrap_u64(); for i in 0..len { let inner_place = self.place_index(query.place.1, query.ty, i as u64)?; self.validate( @@ -759,7 +773,7 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<' Ok(()) } TyAdt(adt, _) => { - if Some(adt.did) == self.tcx.lang_items().unsafe_cell_type() && + if Some(adt.did) == self.tcx.tcx.lang_items().unsafe_cell_type() && query.mutbl == MutImmutable { // No locks for shared unsafe cells. Also no other validation, the only field is private anyway. @@ -771,8 +785,8 @@ impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator<' let discr = self.read_discriminant_value(query.place.1, query.ty)?; // Get variant index for discriminant - let variant_idx = adt.discriminants(self.tcx).position(|variant_discr| { - variant_discr.to_u128_unchecked() == discr + let variant_idx = adt.discriminants(self.tcx.tcx).position(|variant_discr| { + variant_discr.val == discr }); let variant_idx = match variant_idx { Some(val) => val, From a3a01ba5b7c955f65d576d8f51b57d9cb307f481 Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Sat, 17 Mar 2018 18:57:18 +0100 Subject: [PATCH 0031/3747] Add stack guard shim --- miri/fn_call.rs | 71 ++++++++++++++++++++++++++++++++++++++++++++++++- miri/lib.rs | 1 + 2 files changed, 71 insertions(+), 1 deletion(-) diff --git a/miri/fn_call.rs b/miri/fn_call.rs index d07929e0d5608..d5d77c5d32593 100644 --- a/miri/fn_call.rs +++ b/miri/fn_call.rs @@ -1,7 +1,8 @@ use rustc::ty::{self, Ty}; -use rustc::ty::layout::{Align, LayoutOf}; +use rustc::ty::layout::{self, Align, LayoutOf}; use rustc::hir::def_id::{DefId, CRATE_DEF_INDEX}; use rustc::mir; +use rustc_data_structures::indexed_vec::Idx; use syntax::attr; use syntax::abi::Abi; use syntax::codemap::Span; @@ -14,6 +15,50 @@ use tls::MemoryExt; use super::memory::MemoryKind; +fn write_discriminant_value<'a, 'mir, 'tcx: 'a + 'mir>( + ecx: &mut EvalContext<'a, 'mir, 'tcx, super::Evaluator<'tcx>>, + dest_ty: Ty<'tcx>, + dest: Place, + variant_index: usize, + ) -> EvalResult<'tcx> { + let layout = ecx.layout_of(dest_ty)?; + + match layout.variants { + layout::Variants::Single { index } => { + if index != variant_index { + // If the layout of an enum is `Single`, all + // other variants are necessarily uninhabited. + assert_eq!(layout.for_variant(&ecx, variant_index).abi, + layout::Abi::Uninhabited); + } + } + layout::Variants::Tagged { .. } => { + let discr_val = dest_ty.ty_adt_def().unwrap() + .discriminant_for_variant(*ecx.tcx, variant_index) + .val; + + let (discr_dest, discr) = ecx.place_field(dest, mir::Field::new(0), layout)?; + ecx.write_primval(discr_dest, PrimVal::Bytes(discr_val), discr.ty)?; + } + layout::Variants::NicheFilling { + dataful_variant, + ref niche_variants, + niche_start, + .. + } => { + if variant_index != dataful_variant { + let (niche_dest, niche) = + ecx.place_field(dest, mir::Field::new(0), layout)?; + let niche_value = ((variant_index - niche_variants.start) as u128) + .wrapping_add(niche_start); + ecx.write_primval(niche_dest, PrimVal::Bytes(niche_value), niche.ty)?; + } + } + } + + Ok(()) + } + pub trait EvalContextExt<'tcx> { fn call_c_abi( &mut self, @@ -58,6 +103,30 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' ) -> EvalResult<'tcx, bool> { trace!("eval_fn_call: {:#?}, {:#?}", instance, destination); + let def_id = instance.def_id(); + let item_path = self.tcx.absolute_item_path_str(def_id); + if item_path.starts_with("std::") { + println!("{}", item_path); + } + match &*item_path { + "std::sys::unix::thread::guard::init" | "std::sys::unix::thread::guard::current" => { + // Return None, as it doesn't make sense to return Some, because miri detects stack overflow itself. + let ret_ty = sig.output(); + match ret_ty.sty { + ty::TyAdt(ref adt_def, _) => { + assert!(adt_def.is_enum(), "Unexpected return type for {}", item_path); + let none_variant_index = adt_def.variants.iter().enumerate().find(|&(_i, ref def)| { + def.name.as_str() == "None" + }).expect("No None variant").0; + write_discriminant_value(self, ret_ty, destination.unwrap().0, none_variant_index)?; + return Ok(true); + } + _ => panic!("Unexpected return type for {}", item_path) + } + } + _ => {} + } + let mir = match self.load_mir(instance.def) { Ok(mir) => mir, Err(EvalError { kind: EvalErrorKind::NoMirFor(path), .. }) => { diff --git a/miri/lib.rs b/miri/lib.rs index 99bc91a171776..85827da5dd3c8 100644 --- a/miri/lib.rs +++ b/miri/lib.rs @@ -3,6 +3,7 @@ rustc_private, conservative_impl_trait, catch_expr, + inclusive_range_fields )] #[macro_use] From cd89e56f152798ef437377acd7d503dae2b3cb99 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Sun, 18 Mar 2018 13:18:41 +0100 Subject: [PATCH 0032/3747] Get the tests one step further --- miri/fn_call.rs | 6 ++++-- tests/compiletest.rs | 10 +++++----- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/miri/fn_call.rs b/miri/fn_call.rs index d5d77c5d32593..70b4900a4eff7 100644 --- a/miri/fn_call.rs +++ b/miri/fn_call.rs @@ -106,7 +106,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' let def_id = instance.def_id(); let item_path = self.tcx.absolute_item_path_str(def_id); if item_path.starts_with("std::") { - println!("{}", item_path); + //println!("{}", item_path); } match &*item_path { "std::sys::unix::thread::guard::init" | "std::sys::unix::thread::guard::current" => { @@ -118,7 +118,9 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' let none_variant_index = adt_def.variants.iter().enumerate().find(|&(_i, ref def)| { def.name.as_str() == "None" }).expect("No None variant").0; - write_discriminant_value(self, ret_ty, destination.unwrap().0, none_variant_index)?; + let (return_place, return_to_block) = destination.unwrap(); + write_discriminant_value(self, ret_ty, return_place, none_variant_index)?; + self.goto_block(return_to_block); return Ok(true); } _ => panic!("Unexpected return type for {}", item_path) diff --git a/tests/compiletest.rs b/tests/compiletest.rs index b1ea3fc8b0d47..e2e00d828c1af 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -53,10 +53,10 @@ fn compile_fail(sysroot: &Path, path: &str, target: &str, host: &str, fullmir: b let sysroot = std::env::home_dir().unwrap() .join(".xargo") .join("HOST"); - config.target_rustcflags = Some(format!("--sysroot {}", sysroot.to_str().unwrap())); + flags.push(format!("--sysroot {}", sysroot.to_str().unwrap())); config.src_base = PathBuf::from(path.to_string()); } else { - config.target_rustcflags = Some(format!("--sysroot {}", sysroot.to_str().unwrap())); + flags.push(format!("--sysroot {}", sysroot.to_str().unwrap())); config.src_base = PathBuf::from(path.to_string()); } flags.push("-Zmir-emit-validate=1".to_owned()); @@ -206,8 +206,8 @@ fn compile_fail_miri() { let sysroot = get_sysroot(); let host = get_host(); - for_all_targets(&sysroot, |target| { - compile_fail(&sysroot, "tests/compile-fail", &target, &host, false); - }); + // FIXME: run tests for other targets, too + compile_fail(&sysroot, "tests/compile-fail", &host, &host, true); + compile_fail(&sysroot, "tests/compile-fail-fullmir", &host, &host, true); } From d4f30aa9c1bc9e343cd47904ac8deef479fcf047 Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Sun, 18 Mar 2018 19:25:13 +0100 Subject: [PATCH 0033/3747] Fix alignment issue --- miri/intrinsic.rs | 10 +++++++++- xargo/Cargo.lock | 2 +- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/miri/intrinsic.rs b/miri/intrinsic.rs index 5047ab5b6ac21..d01d52ad1af76 100644 --- a/miri/intrinsic.rs +++ b/miri/intrinsic.rs @@ -217,8 +217,16 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: // Also see the write_bytes intrinsic. let elem_align = elem_layout.align; let src = self.into_ptr(args[0].value)?; - let src_align = self.layout_of(args[0].ty)?.align; + //let src_align = self.layout_of(args[0].ty)?.align; + let src_align = ty::layout::Align::from_bytes(1, 1).unwrap(); let dest = self.into_ptr(args[1].value)?; + /*self.tcx.sess.warn(&format!("src_ty: {:?} src_align: {} elem_align: {} src_aligned: {:?} dst_aligned: {:?}", + args[0].ty, + src_align.abi(), + elem_align.abi(), + self.memory.check_align(src, src_align), + self.memory.check_align(dest, elem_align) + ));*/ self.memory.copy( src, src_align, diff --git a/xargo/Cargo.lock b/xargo/Cargo.lock index 031ad9a879549..c85820b708b67 100644 --- a/xargo/Cargo.lock +++ b/xargo/Cargo.lock @@ -1,4 +1,4 @@ -[root] +[[package]] name = "miri-xargo" version = "0.0.0" From 4ecbcc5577ad74ded0f564af28530007bbaa31cd Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Mon, 19 Mar 2018 08:09:50 +0100 Subject: [PATCH 0034/3747] Dont claim to have marked static initialized --- miri/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/miri/lib.rs b/miri/lib.rs index 85827da5dd3c8..8af33e30a5efc 100644 --- a/miri/lib.rs +++ b/miri/lib.rs @@ -261,7 +261,7 @@ impl<'mir, 'tcx: 'mir> Machine<'mir, 'tcx> for Evaluator<'tcx> { Env => err!(Unimplemented("statics can't refer to env vars".to_owned())), _ => Ok(false), // TODO: What does the bool mean? }*/ - Ok(true) + Ok(false) } fn init_static<'a>( From 6a85104945c9b07b9ef26cf50026bee467a56aa4 Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Mon, 19 Mar 2018 08:12:53 +0100 Subject: [PATCH 0035/3747] Use elem align as src align in copy intrinsic --- miri/intrinsic.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/miri/intrinsic.rs b/miri/intrinsic.rs index d01d52ad1af76..d6807f83c18df 100644 --- a/miri/intrinsic.rs +++ b/miri/intrinsic.rs @@ -218,7 +218,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: let elem_align = elem_layout.align; let src = self.into_ptr(args[0].value)?; //let src_align = self.layout_of(args[0].ty)?.align; - let src_align = ty::layout::Align::from_bytes(1, 1).unwrap(); + //let src_align = ty::layout::Align::from_bytes(1, 1).unwrap(); let dest = self.into_ptr(args[1].value)?; /*self.tcx.sess.warn(&format!("src_ty: {:?} src_align: {} elem_align: {} src_aligned: {:?} dst_aligned: {:?}", args[0].ty, @@ -229,7 +229,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: ));*/ self.memory.copy( src, - src_align, + elem_align, dest, elem_align, count * elem_size, From 680bcf86f03632e0f1d17fdf89f5274a2f42da92 Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Mon, 19 Mar 2018 08:35:01 +0100 Subject: [PATCH 0036/3747] Hack: copy init_static from rustc CompileTimeEvaluator to try to fix uninitialized static error --- miri/lib.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/miri/lib.rs b/miri/lib.rs index 8af33e30a5efc..5305eb9d154d5 100644 --- a/miri/lib.rs +++ b/miri/lib.rs @@ -268,6 +268,12 @@ impl<'mir, 'tcx: 'mir> Machine<'mir, 'tcx> for Evaluator<'tcx> { ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, cid: GlobalId<'tcx>, ) -> EvalResult<'tcx, AllocId> { +ecx.const_eval(cid)?; + return Ok(ecx + .tcx + .interpret_interner + .get_cached(cid.instance.def_id()) + .expect("uncached static")); let def_id = cid.instance.def_id(); let ty = ecx.tcx.type_of(def_id); let layout = ecx.tcx.layout_of(ty::ParamEnvAnd { From 878d66692c2037c2d42532f1a127f2d825700658 Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Mon, 19 Mar 2018 11:46:18 +0100 Subject: [PATCH 0037/3747] Maybe prevent marking statics as immutable --- miri/lib.rs | 76 ++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 63 insertions(+), 13 deletions(-) diff --git a/miri/lib.rs b/miri/lib.rs index 5305eb9d154d5..0e3d00f1f15a3 100644 --- a/miri/lib.rs +++ b/miri/lib.rs @@ -268,19 +268,69 @@ impl<'mir, 'tcx: 'mir> Machine<'mir, 'tcx> for Evaluator<'tcx> { ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, cid: GlobalId<'tcx>, ) -> EvalResult<'tcx, AllocId> { -ecx.const_eval(cid)?; - return Ok(ecx - .tcx - .interpret_interner - .get_cached(cid.instance.def_id()) - .expect("uncached static")); - let def_id = cid.instance.def_id(); - let ty = ecx.tcx.type_of(def_id); - let layout = ecx.tcx.layout_of(ty::ParamEnvAnd { - param_env: ty::ParamEnv::reveal_all(), - value: ty - }).expect("Couldn't compute layout for the type of a static"); - ecx.memory.allocate(layout.size.bytes(), layout.align, None).map(|mptr|mptr.alloc_id) + let tcx = self.tcx.tcx; + let mir = None; + let param_env = ty::ParamEnv::reveal_all(); + // we start out with the best span we have + // and try improving it down the road when more information is available + let res = (|| { + let mut mir = match mir { + Some(mir) => mir, + None => ecx.load_mir(cid.instance.def)?, + }; + if let Some(index) = cid.promoted { + mir = &mir.promoted[index]; + } + span = mir.span; + let layout = ecx.layout_of(mir.return_ty().subst(tcx, cid.instance.substs))?; + let alloc = tcx.interpret_interner.get_cached(cid.instance.def_id()); + let is_static = tcx.is_static(cid.instance.def_id()).is_some(); + let alloc = match alloc { + Some(alloc) => { + assert!(cid.promoted.is_none()); + assert!(param_env.caller_bounds.is_empty()); + alloc + }, + None => { + assert!(!layout.is_unsized()); + let ptr = ecx.memory.allocate( + layout.size.bytes(), + layout.align, + None, + )?; + if is_static { + tcx.interpret_interner.cache(cid.instance.def_id(), ptr.alloc_id); + } + let internally_mutable = !layout.ty.is_freeze(tcx, param_env, mir.span); + let mutability = tcx.is_static(cid.instance.def_id()); + let mutability = if mutability == Some(hir::Mutability::MutMutable) || internally_mutable { + Mutability::Mutable + } else { + Mutability::Immutable + }; + let cleanup = StackPopCleanup::MarkStatic(mutability); + let name = ty::tls::with(|tcx| tcx.item_path_str(cid.instance.def_id())); + let prom = cid.promoted.map_or(String::new(), |p| format!("::promoted[{:?}]", p)); + trace!("const_eval: pushing stack frame for global: {}{}", name, prom); + assert!(mir.arg_count == 0); + ecx.push_stack_frame( + cid.instance, + mir.span, + mir, + Place::from_ptr(ptr, layout.align), + cleanup, + )?; + + while ecx.step()? {} + ptr.alloc_id + } + }; + let ptr = MemoryPointer::new(alloc, 0).into(); + // always try to read the value and report errors + Ok((ptr, layout.ty)) + })(); + let (mem_ptr, _) = res?; + Ok(mem_ptr.alloc_id) } fn box_alloc<'a>( From f55d07745f8aa17d2dd7b73180bb95ecdc97e35f Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Fri, 23 Mar 2018 12:06:32 +0100 Subject: [PATCH 0038/3747] Fix init_static --- miri/lib.rs | 85 ++++++++++++++--------------------------------------- 1 file changed, 22 insertions(+), 63 deletions(-) diff --git a/miri/lib.rs b/miri/lib.rs index 0e3d00f1f15a3..fb79780c3820a 100644 --- a/miri/lib.rs +++ b/miri/lib.rs @@ -210,6 +210,8 @@ pub struct MemoryData<'tcx> { /// Only mutable (static mut, heap, stack) allocations have an entry in this map. /// The entry is created when allocating the memory and deleted after deallocation. locks: HashMap>>, + + mut_statics: HashMap, AllocId>, } impl<'mir, 'tcx: 'mir> Machine<'mir, 'tcx> for Evaluator<'tcx> { @@ -268,69 +270,26 @@ impl<'mir, 'tcx: 'mir> Machine<'mir, 'tcx> for Evaluator<'tcx> { ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, cid: GlobalId<'tcx>, ) -> EvalResult<'tcx, AllocId> { - let tcx = self.tcx.tcx; - let mir = None; - let param_env = ty::ParamEnv::reveal_all(); - // we start out with the best span we have - // and try improving it down the road when more information is available - let res = (|| { - let mut mir = match mir { - Some(mir) => mir, - None => ecx.load_mir(cid.instance.def)?, - }; - if let Some(index) = cid.promoted { - mir = &mir.promoted[index]; - } - span = mir.span; - let layout = ecx.layout_of(mir.return_ty().subst(tcx, cid.instance.substs))?; - let alloc = tcx.interpret_interner.get_cached(cid.instance.def_id()); - let is_static = tcx.is_static(cid.instance.def_id()).is_some(); - let alloc = match alloc { - Some(alloc) => { - assert!(cid.promoted.is_none()); - assert!(param_env.caller_bounds.is_empty()); - alloc - }, - None => { - assert!(!layout.is_unsized()); - let ptr = ecx.memory.allocate( - layout.size.bytes(), - layout.align, - None, - )?; - if is_static { - tcx.interpret_interner.cache(cid.instance.def_id(), ptr.alloc_id); - } - let internally_mutable = !layout.ty.is_freeze(tcx, param_env, mir.span); - let mutability = tcx.is_static(cid.instance.def_id()); - let mutability = if mutability == Some(hir::Mutability::MutMutable) || internally_mutable { - Mutability::Mutable - } else { - Mutability::Immutable - }; - let cleanup = StackPopCleanup::MarkStatic(mutability); - let name = ty::tls::with(|tcx| tcx.item_path_str(cid.instance.def_id())); - let prom = cid.promoted.map_or(String::new(), |p| format!("::promoted[{:?}]", p)); - trace!("const_eval: pushing stack frame for global: {}{}", name, prom); - assert!(mir.arg_count == 0); - ecx.push_stack_frame( - cid.instance, - mir.span, - mir, - Place::from_ptr(ptr, layout.align), - cleanup, - )?; - - while ecx.step()? {} - ptr.alloc_id - } - }; - let ptr = MemoryPointer::new(alloc, 0).into(); - // always try to read the value and report errors - Ok((ptr, layout.ty)) - })(); - let (mem_ptr, _) = res?; - Ok(mem_ptr.alloc_id) + if let Some(alloc_id) = ecx.memory.data.get(&cid) { + return Ok(alloc_id); + } + let mir = ecx.load_mir(cid.instance.def)?; + let layout = ecx.layout_of(mir.return_ty().subst(tcx, cid.instance.substs))?; + let to_ptr = ecx.memory.allocate( + layout.size.bytes(), + layout.align, + None, + )?; + ecx.const_eval(cid)?; + let ptr = ecx + .tcx + .interpret_interner + .get_cached(cid.instance.def_id()) + .expect("uncached static"); + ecx.memory.copy(ptr, layout.align, to_ptr.into(), layout.align, layout.size.bytes(), true)?; + ecx.memory.mark_static_initialized(to_ptr.alloc_id, ::syntax::ast::Mutability::Mutable)?; + assert!(ecx.memory.data.insert(cid, to_ptr.alloc_id).is_none()); + Ok(to_ptr.alloc_id) } fn box_alloc<'a>( From ac42af3789e6a536cabd900611e703c363aec3b3 Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Fri, 23 Mar 2018 12:08:15 +0100 Subject: [PATCH 0039/3747] travis: cache build dir --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 97f1da545be4f..b02b14392daea 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,4 +1,5 @@ language: rust +cache: cargo rust: - nightly before_script: From a6cdd8a81b6dfd89a717b44cff6c4e489bd67bea Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Fri, 23 Mar 2018 12:18:33 +0100 Subject: [PATCH 0040/3747] Fix it --- miri/bin/miri.rs | 2 +- miri/fn_call.rs | 9 ++++ miri/lib.rs | 65 ++++++++++++++++++------ miri/validation.rs | 2 +- tests/run-pass-fullmir/u128.rs | 2 - tests/run-pass/generator_control_flow.rs | 2 +- tests/run-pass/subslice_array.rs | 1 - tests/run-pass/vec-matching-fold.rs | 2 - 8 files changed, 62 insertions(+), 23 deletions(-) diff --git a/miri/bin/miri.rs b/miri/bin/miri.rs index bbc8322194fac..cb90bbd704a8a 100644 --- a/miri/bin/miri.rs +++ b/miri/bin/miri.rs @@ -1,4 +1,4 @@ -#![feature(rustc_private, i128_type)] +#![feature(rustc_private)] extern crate getopts; extern crate miri; diff --git a/miri/fn_call.rs b/miri/fn_call.rs index 70b4900a4eff7..b4328ef88c00f 100644 --- a/miri/fn_call.rs +++ b/miri/fn_call.rs @@ -126,6 +126,12 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' _ => panic!("Unexpected return type for {}", item_path) } } + "std::sys_common::thread_info::set" | "std::sys_common::cleanup" => { + // TODO rustc creates invalid mir inside std::cell::BorrowRef::new which is used by this function + let (_return_place, return_to_block) = destination.unwrap(); + self.goto_block(return_to_block); + return Ok(true); + } _ => {} } @@ -535,6 +541,9 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' // Return success (0) self.write_null(dest, dest_ty)?; } + "_tlv_atexit" => { + // TODO: handle it + } // Stub out all the other pthread calls to just return 0 link_name if link_name.starts_with("pthread_") => { diff --git a/miri/lib.rs b/miri/lib.rs index fb79780c3820a..42b0cacbd053f 100644 --- a/miri/lib.rs +++ b/miri/lib.rs @@ -1,7 +1,5 @@ #![feature( - i128_type, rustc_private, - conservative_impl_trait, catch_expr, inclusive_range_fields )] @@ -21,6 +19,7 @@ extern crate lazy_static; use rustc::ty::{self, TyCtxt}; use rustc::ty::layout::{TyLayout, LayoutOf}; +use rustc::ty::subst::Subst; use rustc::hir::def_id::DefId; use rustc::mir; @@ -170,7 +169,7 @@ pub fn eval_main<'a, 'tcx: 'a>( Ok(()) => { let leaks = ecx.memory().leak_report(); if leaks != 0 { - tcx.sess.err("the evaluated program leaked memory"); + //tcx.sess.err("the evaluated program leaked memory"); } } Err(mut e) => { @@ -270,26 +269,59 @@ impl<'mir, 'tcx: 'mir> Machine<'mir, 'tcx> for Evaluator<'tcx> { ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, cid: GlobalId<'tcx>, ) -> EvalResult<'tcx, AllocId> { - if let Some(alloc_id) = ecx.memory.data.get(&cid) { - return Ok(alloc_id); + if let Some(alloc_id) = ecx.memory.data.mut_statics.get(&cid) { + return Ok(*alloc_id); } - let mir = ecx.load_mir(cid.instance.def)?; + + let tcx = ecx.tcx.tcx; + let param_env = ty::ParamEnv::reveal_all(); + + let mut mir = ecx.load_mir(cid.instance.def)?; + if let Some(index) = cid.promoted { + mir = &mir.promoted[index]; + } + assert!(mir.arg_count == 0); + + // we start out with the best span we have + // and try improving it down the road when more information is available let layout = ecx.layout_of(mir.return_ty().subst(tcx, cid.instance.substs))?; - let to_ptr = ecx.memory.allocate( + assert!(!layout.is_unsized()); + let ptr = ecx.memory.allocate( layout.size.bytes(), layout.align, None, )?; - ecx.const_eval(cid)?; - let ptr = ecx + + let internally_mutable = !layout.ty.is_freeze(tcx, param_env, mir.span); + let mutability = tcx.is_static(cid.instance.def_id()); + if mutability != Some(::rustc::hir::Mutability::MutMutable) && !internally_mutable { + ecx.const_eval(cid)?; + return Ok(ecx .tcx .interpret_interner .get_cached(cid.instance.def_id()) - .expect("uncached static"); - ecx.memory.copy(ptr, layout.align, to_ptr.into(), layout.align, layout.size.bytes(), true)?; - ecx.memory.mark_static_initialized(to_ptr.alloc_id, ::syntax::ast::Mutability::Mutable)?; - assert!(ecx.memory.data.insert(cid, to_ptr.alloc_id).is_none()); - Ok(to_ptr.alloc_id) + .expect("uncached static")); + } + + //let cleanup = StackPopCleanup::MarkStatic(Mutability::Mutable); + let cleanup = StackPopCleanup::None; + let name = ty::tls::with(|tcx| tcx.item_path_str(cid.instance.def_id())); + let prom = cid.promoted.map_or(String::new(), |p| format!("::promoted[{:?}]", p)); + trace!("const_eval: pushing stack frame for global: {}{}", name, prom); + let caller_stackframe = ecx.stack().len(); + ecx.push_stack_frame( + cid.instance, + mir.span, + mir, + Place::from_ptr(ptr, layout.align), + cleanup, + )?; + + while ecx.step()? && ecx.stack().len() > caller_stackframe {} + + assert!(ecx.memory.data.mut_statics.insert(cid, ptr.alloc_id).is_none()); + + Ok(ptr.alloc_id) } fn box_alloc<'a>( @@ -321,7 +353,10 @@ impl<'mir, 'tcx: 'mir> Machine<'mir, 'tcx> for Evaluator<'tcx> { let dest = ecx.eval_place(&mir::Place::Local(args.next().unwrap()))?; ecx.write_value( ValTy { - value: Value::ByVal(PrimVal::Bytes(layout.size.bytes().into())), + value: Value::ByVal(PrimVal::Bytes(match layout.size.bytes() { + 0 => 1, + size => size, + }.into())), ty: usize, }, dest, diff --git a/miri/validation.rs b/miri/validation.rs index 801fd952f666d..ec8901dca5d42 100644 --- a/miri/validation.rs +++ b/miri/validation.rs @@ -5,7 +5,7 @@ use rustc::mir::interpret::GlobalId; use rustc::ty::{self, Ty, TypeFoldable, TyCtxt, Instance}; use rustc::ty::layout::LayoutOf; use rustc::ty::subst::{Substs, Subst}; -use rustc::traits; +use rustc::traits::{self, TraitEngine}; use rustc::infer::InferCtxt; use rustc::middle::region; use rustc::middle::const_val::ConstVal; diff --git a/tests/run-pass-fullmir/u128.rs b/tests/run-pass-fullmir/u128.rs index 5b2efdd205170..d7764bf6201ae 100644 --- a/tests/run-pass-fullmir/u128.rs +++ b/tests/run-pass-fullmir/u128.rs @@ -10,8 +10,6 @@ //ignore-msvc -#![feature(i128_type)] - fn b(t: T) -> T { t } fn main() { diff --git a/tests/run-pass/generator_control_flow.rs b/tests/run-pass/generator_control_flow.rs index f15c7db9c2030..900ff0e34904c 100644 --- a/tests/run-pass/generator_control_flow.rs +++ b/tests/run-pass/generator_control_flow.rs @@ -16,7 +16,7 @@ fn finish(mut amt: usize, mut t: T) -> T::Return where T: Generator { loop { - match t.resume() { + match unsafe { t.resume() } { GeneratorState::Yielded(()) => amt -= 1, GeneratorState::Complete(ret) => { assert_eq!(amt, 0); diff --git a/tests/run-pass/subslice_array.rs b/tests/run-pass/subslice_array.rs index 468cc9f094169..5bbbffe4e60e1 100644 --- a/tests/run-pass/subslice_array.rs +++ b/tests/run-pass/subslice_array.rs @@ -1,4 +1,3 @@ -#![feature(advanced_slice_patterns)] #![feature(slice_patterns)] fn bar(a: &'static str, b: &'static str) -> [&'static str; 4] { diff --git a/tests/run-pass/vec-matching-fold.rs b/tests/run-pass/vec-matching-fold.rs index ac80a4211ada6..1a30f875580c2 100644 --- a/tests/run-pass/vec-matching-fold.rs +++ b/tests/run-pass/vec-matching-fold.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. - -#![feature(advanced_slice_patterns)] #![feature(slice_patterns)] use std::fmt::Debug; From e09a996b2a7aa4d0bc6f93b91dce21037d67fe6d Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Wed, 4 Apr 2018 15:54:40 +0200 Subject: [PATCH 0041/3747] Fix some more tests with some unsafe code --- miri/fn_call.rs | 6 ++++++ miri/lib.rs | 50 +++++++++++++++++++++++++------------------- tests/compiletest.rs | 1 + 3 files changed, 36 insertions(+), 21 deletions(-) diff --git a/miri/fn_call.rs b/miri/fn_call.rs index b4328ef88c00f..cce36e6bacc6a 100644 --- a/miri/fn_call.rs +++ b/miri/fn_call.rs @@ -132,6 +132,12 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' self.goto_block(return_to_block); return Ok(true); } + "std::sys::unix::fast_thread_local::register_dtor" => { + // TODO: register the dtor + let (_return_place, return_to_block) = destination.unwrap(); + self.goto_block(return_to_block); + return Ok(true); + } _ => {} } diff --git a/miri/lib.rs b/miri/lib.rs index 42b0cacbd053f..f9332ccc629da 100644 --- a/miri/lib.rs +++ b/miri/lib.rs @@ -269,21 +269,21 @@ impl<'mir, 'tcx: 'mir> Machine<'mir, 'tcx> for Evaluator<'tcx> { ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, cid: GlobalId<'tcx>, ) -> EvalResult<'tcx, AllocId> { + // Step 1: If the static has already been evaluated return the cached version if let Some(alloc_id) = ecx.memory.data.mut_statics.get(&cid) { return Ok(*alloc_id); } let tcx = ecx.tcx.tcx; - let param_env = ty::ParamEnv::reveal_all(); + // Step 2: Load mir let mut mir = ecx.load_mir(cid.instance.def)?; if let Some(index) = cid.promoted { mir = &mir.promoted[index]; } assert!(mir.arg_count == 0); - // we start out with the best span we have - // and try improving it down the road when more information is available + // Step 3: Allocate storage let layout = ecx.layout_of(mir.return_ty().subst(tcx, cid.instance.substs))?; assert!(!layout.is_unsized()); let ptr = ecx.memory.allocate( @@ -292,23 +292,11 @@ impl<'mir, 'tcx: 'mir> Machine<'mir, 'tcx> for Evaluator<'tcx> { None, )?; - let internally_mutable = !layout.ty.is_freeze(tcx, param_env, mir.span); - let mutability = tcx.is_static(cid.instance.def_id()); - if mutability != Some(::rustc::hir::Mutability::MutMutable) && !internally_mutable { - ecx.const_eval(cid)?; - return Ok(ecx - .tcx - .interpret_interner - .get_cached(cid.instance.def_id()) - .expect("uncached static")); - } + // Step 4: Cache allocation id for recursive statics + assert!(ecx.memory.data.mut_statics.insert(cid, ptr.alloc_id).is_none()); - //let cleanup = StackPopCleanup::MarkStatic(Mutability::Mutable); + // Step 5: Push stackframe to evaluate static let cleanup = StackPopCleanup::None; - let name = ty::tls::with(|tcx| tcx.item_path_str(cid.instance.def_id())); - let prom = cid.promoted.map_or(String::new(), |p| format!("::promoted[{:?}]", p)); - trace!("const_eval: pushing stack frame for global: {}{}", name, prom); - let caller_stackframe = ecx.stack().len(); ecx.push_stack_frame( cid.instance, mir.span, @@ -317,10 +305,30 @@ impl<'mir, 'tcx: 'mir> Machine<'mir, 'tcx> for Evaluator<'tcx> { cleanup, )?; - while ecx.step()? && ecx.stack().len() > caller_stackframe {} - - assert!(ecx.memory.data.mut_statics.insert(cid, ptr.alloc_id).is_none()); + // Step 6: Step until static has been initialized + let call_stackframe = ecx.stack().len(); + while ecx.step()? && ecx.stack().len() >= call_stackframe { + if ecx.stack().len() == call_stackframe { + let frame = ecx.stack().last().unwrap(); + let bb = &frame.mir.basic_blocks()[frame.block]; + if bb.statements.len() == frame.stmt && !bb.is_cleanup { + match bb.terminator().kind { + ::rustc::mir::TerminatorKind::Return => { + for (local, _local_decl) in mir.local_decls.iter_enumerated().skip(1) { + // Don't deallocate locals, because the return value might reference them + // ------------------------------------------------------------ + // ||||||||||||| TODO: remove this horrible hack |||||||||||||| + // ------------------------------------------------------------ + unsafe { &mut *(frame as *const Frame as *mut Frame) }.storage_dead(local); + } + } + _ => {} + } + } + } + } + // Step 7: Return the alloc Ok(ptr.alloc_id) } diff --git a/tests/compiletest.rs b/tests/compiletest.rs index e2e00d828c1af..a1a28d4e4a688 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -202,6 +202,7 @@ fn run_pass_rustc() { } #[test] +#[ignore] // TODO: update test errors fn compile_fail_miri() { let sysroot = get_sysroot(); let host = get_host(); From 73658c40bb02762d9e68690bc5ebf7695f9d34b7 Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Sat, 7 Apr 2018 10:44:19 +0200 Subject: [PATCH 0042/3747] Remove unsafe code --- miri/lib.rs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/miri/lib.rs b/miri/lib.rs index f9332ccc629da..cc564d1afe3f3 100644 --- a/miri/lib.rs +++ b/miri/lib.rs @@ -309,17 +309,14 @@ impl<'mir, 'tcx: 'mir> Machine<'mir, 'tcx> for Evaluator<'tcx> { let call_stackframe = ecx.stack().len(); while ecx.step()? && ecx.stack().len() >= call_stackframe { if ecx.stack().len() == call_stackframe { - let frame = ecx.stack().last().unwrap(); + let frame = ecx.frame_mut(); let bb = &frame.mir.basic_blocks()[frame.block]; if bb.statements.len() == frame.stmt && !bb.is_cleanup { match bb.terminator().kind { ::rustc::mir::TerminatorKind::Return => { for (local, _local_decl) in mir.local_decls.iter_enumerated().skip(1) { // Don't deallocate locals, because the return value might reference them - // ------------------------------------------------------------ - // ||||||||||||| TODO: remove this horrible hack |||||||||||||| - // ------------------------------------------------------------ - unsafe { &mut *(frame as *const Frame as *mut Frame) }.storage_dead(local); + frame.storage_dead(local); } } _ => {} From 7bd20f1b12bc68396acb387884902a1308a045e5 Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Sat, 7 Apr 2018 11:43:46 +0200 Subject: [PATCH 0043/3747] Some cleanups --- miri/fn_call.rs | 23 ++++------------------- miri/intrinsic.rs | 17 ++++++----------- miri/lib.rs | 21 +++++++++++---------- miri/validation.rs | 2 +- rust-toolchain | 1 + 5 files changed, 23 insertions(+), 41 deletions(-) create mode 100644 rust-toolchain diff --git a/miri/fn_call.rs b/miri/fn_call.rs index cce36e6bacc6a..26a3829e7e8df 100644 --- a/miri/fn_call.rs +++ b/miri/fn_call.rs @@ -115,9 +115,9 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' match ret_ty.sty { ty::TyAdt(ref adt_def, _) => { assert!(adt_def.is_enum(), "Unexpected return type for {}", item_path); - let none_variant_index = adt_def.variants.iter().enumerate().find(|&(_i, ref def)| { + let none_variant_index = adt_def.variants.iter().position(|def| { def.name.as_str() == "None" - }).expect("No None variant").0; + }).expect("No None variant"); let (return_place, return_to_block) = destination.unwrap(); write_discriminant_value(self, ret_ty, return_place, none_variant_index)?; self.goto_block(return_to_block); @@ -126,12 +126,6 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' _ => panic!("Unexpected return type for {}", item_path) } } - "std::sys_common::thread_info::set" | "std::sys_common::cleanup" => { - // TODO rustc creates invalid mir inside std::cell::BorrowRef::new which is used by this function - let (_return_place, return_to_block) = destination.unwrap(); - self.goto_block(return_to_block); - return Ok(true); - } "std::sys::unix::fast_thread_local::register_dtor" => { // TODO: register the dtor let (_return_place, return_to_block) = destination.unwrap(); @@ -465,17 +459,8 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' instance, promoted: None, }; - // compute global if not cached - let value: Value = match self.tcx.interpret_interner.get_cached(instance.def_id()) { - Some(ptr) => { - Value::ByRef(MemoryPointer::new(ptr, 0).into(), name_align) - } - None => { - let res: Option<(Value, Pointer, Ty)> = eval_body(self.tcx.tcx, cid, ty::ParamEnv::reveal_all()); - res.ok_or_else(||EvalErrorKind::MachineError("".to_string()))?.0 - }, - }; - let value = self.value_to_primval(ValTy { value, ty: args[0].ty })?.to_u64()?; + let const_val = self.const_eval(cid)?; + let value = const_val.val.unwrap_u64(); if value == name { result = Some(path_value); break; diff --git a/miri/intrinsic.rs b/miri/intrinsic.rs index d6807f83c18df..60f176dd95db3 100644 --- a/miri/intrinsic.rs +++ b/miri/intrinsic.rs @@ -217,16 +217,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: // Also see the write_bytes intrinsic. let elem_align = elem_layout.align; let src = self.into_ptr(args[0].value)?; - //let src_align = self.layout_of(args[0].ty)?.align; - //let src_align = ty::layout::Align::from_bytes(1, 1).unwrap(); let dest = self.into_ptr(args[1].value)?; - /*self.tcx.sess.warn(&format!("src_ty: {:?} src_align: {} elem_align: {} src_aligned: {:?} dst_aligned: {:?}", - args[0].ty, - src_align.abi(), - elem_align.abi(), - self.memory.check_align(src, src_align), - self.memory.check_align(dest, elem_align) - ));*/ self.memory.copy( src, elem_align, @@ -360,7 +351,9 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: align: _align, extra: PlaceExtra::None, } => self.memory.write_repeat(ptr, 0, size)?, - _ => bug!("TODO"), + Place::Ptr { .. } => { + bug!("init intrinsic tried to write to fat or unaligned ptr target") + } } } @@ -637,7 +630,9 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: align: _align, extra: PlaceExtra::None, } => self.memory.mark_definedness(ptr, size, false)?, - _ => bug!("todo"), + Place::Ptr { .. } => { + bug!("uninit intrinsic tried to write to fat or unaligned ptr target") + } } } diff --git a/miri/lib.rs b/miri/lib.rs index cc564d1afe3f3..d9afd0860a527 100644 --- a/miri/lib.rs +++ b/miri/lib.rs @@ -210,7 +210,7 @@ pub struct MemoryData<'tcx> { /// The entry is created when allocating the memory and deleted after deallocation. locks: HashMap>>, - mut_statics: HashMap, AllocId>, + statics: HashMap, AllocId>, } impl<'mir, 'tcx: 'mir> Machine<'mir, 'tcx> for Evaluator<'tcx> { @@ -252,17 +252,16 @@ impl<'mir, 'tcx: 'mir> Machine<'mir, 'tcx> for Evaluator<'tcx> { } fn mark_static_initialized<'a>( - _mem: &mut Memory<'a, 'mir, 'tcx, Self>, - _id: AllocId, + mem: &mut Memory<'a, 'mir, 'tcx, Self>, + id: AllocId, _mutability: Mutability, ) -> EvalResult<'tcx, bool> { - /*use memory::MemoryKind::*; - match m { + use memory::MemoryKind::*; + match mem.get_alloc_kind(id) { // FIXME: This could be allowed, but not for env vars set during miri execution - Env => err!(Unimplemented("statics can't refer to env vars".to_owned())), + Some(MemoryKind::Machine(Env)) => err!(Unimplemented("statics can't refer to env vars".to_owned())), _ => Ok(false), // TODO: What does the bool mean? - }*/ - Ok(false) + } } fn init_static<'a>( @@ -270,7 +269,7 @@ impl<'mir, 'tcx: 'mir> Machine<'mir, 'tcx> for Evaluator<'tcx> { cid: GlobalId<'tcx>, ) -> EvalResult<'tcx, AllocId> { // Step 1: If the static has already been evaluated return the cached version - if let Some(alloc_id) = ecx.memory.data.mut_statics.get(&cid) { + if let Some(alloc_id) = ecx.memory.data.statics.get(&cid) { return Ok(*alloc_id); } @@ -293,7 +292,7 @@ impl<'mir, 'tcx: 'mir> Machine<'mir, 'tcx> for Evaluator<'tcx> { )?; // Step 4: Cache allocation id for recursive statics - assert!(ecx.memory.data.mut_statics.insert(cid, ptr.alloc_id).is_none()); + assert!(ecx.memory.data.statics.insert(cid, ptr.alloc_id).is_none()); // Step 5: Push stackframe to evaluate static let cleanup = StackPopCleanup::None; @@ -325,6 +324,8 @@ impl<'mir, 'tcx: 'mir> Machine<'mir, 'tcx> for Evaluator<'tcx> { } } + // TODO: Freeze immutable statics without copying them to the global static cache + // Step 7: Return the alloc Ok(ptr.alloc_id) } diff --git a/miri/validation.rs b/miri/validation.rs index ec8901dca5d42..c83c1a515fc6b 100644 --- a/miri/validation.rs +++ b/miri/validation.rs @@ -560,7 +560,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' TyAdt(adt, _) if adt.is_box() => true, TySlice(_) | TyAdt(_, _) | TyTuple(..) | TyClosure(..) | TyArray(..) | TyDynamic(..) | TyGenerator(..) | TyForeign(_) => false, - TyGeneratorWitness(..) => bug!("I'm not sure what to return here"), + TyGeneratorWitness(..) => unreachable!("TyGeneratorWitness in validate"), TyParam(_) | TyInfer(_) | TyProjection(_) | TyAnon(..) | TyError => { bug!("I got an incomplete/unnormalized type for validation") } diff --git a/rust-toolchain b/rust-toolchain new file mode 100644 index 0000000000000..bf867e0ae5b6c --- /dev/null +++ b/rust-toolchain @@ -0,0 +1 @@ +nightly From 9d186d914e378426064f7158c4cba8149ba44eb2 Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Sat, 7 Apr 2018 14:31:39 +0200 Subject: [PATCH 0044/3747] Update Cargo.lock and some improvements --- Cargo.toml | 2 +- miri/bin/cargo-miri.rs | 4 +++- miri/fn_call.rs | 1 - miri/lib.rs | 1 + 4 files changed, 5 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index cc7de42ceabfb..444c6f60d544e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,7 +23,7 @@ path = "miri/lib.rs" [dependencies] byteorder = { version = "1.1", features = ["i128"]} -cargo_metadata = { version = "0.2", optional = true } +cargo_metadata = { version = "0.5", optional = true } regex = "0.2.2" lazy_static = "1.0" env_logger = "0.5.0-rc.1" diff --git a/miri/bin/cargo-miri.rs b/miri/bin/cargo-miri.rs index 06d5b3e9971fe..39a41583a39e0 100644 --- a/miri/bin/cargo-miri.rs +++ b/miri/bin/cargo-miri.rs @@ -121,7 +121,9 @@ fn main() { let home = option_env!("RUSTUP_HOME").or(option_env!("MULTIRUST_HOME")); let toolchain = option_env!("RUSTUP_TOOLCHAIN").or(option_env!("MULTIRUST_TOOLCHAIN")); - let sys_root = if let (Some(home), Some(toolchain)) = (home, toolchain) { + let sys_root = if let Ok(sysroot) = ::std::env::var("MIRI_SYSROOT") { + sysroot + } else if let (Some(home), Some(toolchain)) = (home, toolchain) { format!("{}/toolchains/{}", home, toolchain) } else { option_env!("RUST_SYSROOT") diff --git a/miri/fn_call.rs b/miri/fn_call.rs index 26a3829e7e8df..16a7c5ad77c1b 100644 --- a/miri/fn_call.rs +++ b/miri/fn_call.rs @@ -444,7 +444,6 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' "sysconf" => { let name = self.value_to_primval(args[0])?.to_u64()?; - let name_align = self.layout_of(args[0].ty)?.align; trace!("sysconf() called with name {}", name); // cache the sysconf integers via miri's global cache diff --git a/miri/lib.rs b/miri/lib.rs index d9afd0860a527..16510a5f17b25 100644 --- a/miri/lib.rs +++ b/miri/lib.rs @@ -173,6 +173,7 @@ pub fn eval_main<'a, 'tcx: 'a>( } } Err(mut e) => { + ecx.tcx.sess.err(&e.to_string()); ecx.report(&mut e, true, None); } } From 95a8771bf15c5231c0269a062a4c9a0562694c95 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Fri, 13 Apr 2018 16:02:55 +0200 Subject: [PATCH 0045/3747] Fixup various things needed to get miri working on rustc --- miri/bin/miri.rs | 1 + miri/fn_call.rs | 2 +- miri/intrinsic.rs | 4 +++- miri/lib.rs | 2 +- miri/validation.rs | 11 +---------- 5 files changed, 7 insertions(+), 13 deletions(-) diff --git a/miri/bin/miri.rs b/miri/bin/miri.rs index cb90bbd704a8a..506845dd76ada 100644 --- a/miri/bin/miri.rs +++ b/miri/bin/miri.rs @@ -206,6 +206,7 @@ fn find_sysroot() -> String { } fn main() { + rustc_driver::init_rustc_env_logger(); init_logger(); let mut args: Vec = std::env::args().collect(); diff --git a/miri/fn_call.rs b/miri/fn_call.rs index 16a7c5ad77c1b..a824cbab40a04 100644 --- a/miri/fn_call.rs +++ b/miri/fn_call.rs @@ -499,7 +499,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' return err!(OutOfTls); } self.memory.write_primval( - key_ptr.to_ptr()?, + key_ptr, key_align, PrimVal::Bytes(key), key_size.bytes(), diff --git a/miri/intrinsic.rs b/miri/intrinsic.rs index 60f176dd95db3..ea9f0428964a4 100644 --- a/miri/intrinsic.rs +++ b/miri/intrinsic.rs @@ -34,7 +34,9 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: "align_offset" => { // FIXME: return a real value in case the target allocation has an // alignment bigger than the one requested - self.write_primval(dest, PrimVal::Bytes(u128::max_value()), dest_layout.ty)?; + let n = u128::max_value(); + let amt = 128 - self.memory.pointer_size() * 8; + self.write_primval(dest, PrimVal::Bytes((n << amt) >> amt), dest_layout.ty)?; }, "add_with_overflow" => { diff --git a/miri/lib.rs b/miri/lib.rs index 16510a5f17b25..4d4af6e3adc24 100644 --- a/miri/lib.rs +++ b/miri/lib.rs @@ -133,7 +133,7 @@ pub fn eval_main<'a, 'tcx: 'a>( let ptr_size = ecx.memory.pointer_size(); let ptr_align = ecx.tcx.data_layout.pointer_align; let foo_ptr = ecx.memory.allocate(ptr_size, ptr_align, None)?; - ecx.memory.write_primval(foo_ptr, ptr_align, PrimVal::Ptr(foo.into()), ptr_size, false)?; + ecx.memory.write_primval(foo_ptr.into(), ptr_align, PrimVal::Ptr(foo.into()), ptr_size, false)?; ecx.memory.mark_static_initialized(foo_ptr.alloc_id, Mutability::Immutable)?; ecx.write_ptr(dest, foo_ptr.into(), ty)?; diff --git a/miri/validation.rs b/miri/validation.rs index c83c1a515fc6b..b2c6f427c51a1 100644 --- a/miri/validation.rs +++ b/miri/validation.rs @@ -782,16 +782,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' match adt.adt_kind() { AdtKind::Enum => { - let discr = self.read_discriminant_value(query.place.1, query.ty)?; - - // Get variant index for discriminant - let variant_idx = adt.discriminants(self.tcx.tcx).position(|variant_discr| { - variant_discr.val == discr - }); - let variant_idx = match variant_idx { - Some(val) => val, - None => return err!(InvalidDiscriminant), - }; + let variant_idx = self.read_discriminant_value_as_variant_index(query.place.1, query.ty)?; let variant = &adt.variants[variant_idx]; if variant.fields.len() > 0 { From 3f1b2bdd6895f9aedb22601bd28bc690d5a55a1e Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Fri, 13 Apr 2018 16:25:26 +0200 Subject: [PATCH 0046/3747] Mirror function rename in rustc --- miri/validation.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/miri/validation.rs b/miri/validation.rs index b2c6f427c51a1..85dd895776363 100644 --- a/miri/validation.rs +++ b/miri/validation.rs @@ -782,7 +782,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' match adt.adt_kind() { AdtKind::Enum => { - let variant_idx = self.read_discriminant_value_as_variant_index(query.place.1, query.ty)?; + let variant_idx = self.read_discriminant_as_variant_index(query.place.1, query.ty)?; let variant = &adt.variants[variant_idx]; if variant.fields.len() > 0 { From f48fed70d4447445b586a35c4ae88683542ffc72 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Tue, 17 Apr 2018 14:26:17 +0200 Subject: [PATCH 0047/3747] Rustup --- miri/bin/miri.rs | 2 +- miri/lib.rs | 23 ++++------------------- miri/validation.rs | 28 +++++++++------------------- 3 files changed, 14 insertions(+), 39 deletions(-) diff --git a/miri/bin/miri.rs b/miri/bin/miri.rs index 506845dd76ada..6ba86c81e0401 100644 --- a/miri/bin/miri.rs +++ b/miri/bin/miri.rs @@ -130,7 +130,7 @@ fn after_analysis<'a, 'tcx>(state: &mut CompileState<'a, 'tcx>) { state.hir_crate.unwrap().visit_all_item_likes( &mut Visitor(tcx, state), ); - } else if let Some((entry_node_id, _)) = *state.session.entry_fn.borrow() { + } else if let Some((entry_node_id, _, _)) = *state.session.entry_fn.borrow() { let entry_def_id = tcx.hir.local_def_id(entry_node_id); let start_wrapper = tcx.lang_items().start_fn().and_then(|start_fn| { if tcx.is_mir_available(start_fn) { diff --git a/miri/lib.rs b/miri/lib.rs index 4d4af6e3adc24..7c8183b50984f 100644 --- a/miri/lib.rs +++ b/miri/lib.rs @@ -385,26 +385,11 @@ impl<'mir, 'tcx: 'mir> Machine<'mir, 'tcx> for Evaluator<'tcx> { } fn global_item_with_linkage<'a>( - ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, - instance: ty::Instance<'tcx>, - mutability: Mutability, + _ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, + _instance: ty::Instance<'tcx>, + _mutability: Mutability, ) -> EvalResult<'tcx> { - // FIXME: check that it's `#[linkage = "extern_weak"]` - trace!("Initializing an extern global with NULL"); - let ptr_size = ecx.memory.pointer_size(); - let ptr_align = ecx.tcx.data_layout.pointer_align; - let ptr = ecx.memory.allocate( - ptr_size, - ptr_align, - None, - )?; - ecx.memory.write_ptr_sized_unsigned(ptr, ptr_align, PrimVal::Bytes(0))?; - ecx.memory.mark_static_initialized(ptr.alloc_id, mutability)?; - ecx.tcx.interpret_interner.cache( - instance.def_id(), - ptr.alloc_id, - ); - Ok(()) + panic!("remove this function from rustc"); } fn check_locks<'a>( diff --git a/miri/validation.rs b/miri/validation.rs index 85dd895776363..2de620510ffef 100644 --- a/miri/validation.rs +++ b/miri/validation.rs @@ -638,7 +638,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' } } - let res = do catch { + let res: EvalResult<'tcx> = do catch { match query.ty.sty { TyInt(_) | TyUint(_) | TyRawPtr(_) => { if mode.acquiring() { @@ -648,7 +648,6 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' // FIXME: It would be great to rule out Undef here, but that doesn't actually work. // Passing around undef data is a thing that e.g. Vec::extend_with does. } - Ok(()) } TyBool | TyFloat(_) | TyChar => { if mode.acquiring() { @@ -657,9 +656,8 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' val.to_bytes()?; // TODO: Check if these are valid bool/float/codepoint/UTF-8 } - Ok(()) } - TyNever => err!(ValidationFailure(format!("The empty type is never valid."))), + TyNever => return err!(ValidationFailure(format!("The empty type is never valid."))), TyRef(region, ty::TypeAndMut { ty: pointee_ty, @@ -680,29 +678,26 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' _ => {} } } - self.validate_ptr(val, query.place.0, pointee_ty, query.re, query.mutbl, mode) + self.validate_ptr(val, query.place.0, pointee_ty, query.re, query.mutbl, mode)?; } TyAdt(adt, _) if adt.is_box() => { let val = self.read_place(query.place.1)?; - self.validate_ptr(val, query.place.0, query.ty.boxed_ty(), query.re, query.mutbl, mode) + self.validate_ptr(val, query.place.0, query.ty.boxed_ty(), query.re, query.mutbl, mode)?; } TyFnPtr(_sig) => { let ptr = self.read_place(query.place.1)?; let ptr = self.into_ptr(ptr)?.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?). - Ok(()) } TyFnDef(..) => { // This is a zero-sized type with all relevant data sitting in the type. // There is nothing to validate. - Ok(()) } // Compound types TyStr => { // TODO: Validate strings - Ok(()) } TySlice(elem_ty) => { let len = match query.place.1 { @@ -725,7 +720,6 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' mode, )?; } - Ok(()) } TyArray(elem_ty, len) => { let len_val = match len.val { @@ -751,7 +745,6 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' mode, )?; } - Ok(()) } TyDynamic(_data, _region) => { // Check that this is a valid vtable @@ -770,7 +763,6 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' // on them directly. We cannot, in general, even acquire any locks as the trait object *could* // contain an UnsafeCell. If we call functions to get access to data, we will validate // their return values. So, it doesn't seem like there's anything else to do. - Ok(()) } TyAdt(adt, _) => { if Some(adt.did) == self.tcx.tcx.lang_items().unsafe_cell_type() && @@ -804,19 +796,17 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' self.validate_fields( ValidationQuery { place, ..query }, mode, - ) + )?; } else { // No fields, nothing left to check. Downcasting may fail, e.g. in case of a CEnum. - Ok(()) } } AdtKind::Struct => { - self.validate_fields(query, mode) + self.validate_fields(query, mode)?; } AdtKind::Union => { // No guarantees are provided for union types. // TODO: Make sure that all access to union fields is unsafe; otherwise, we may have some checking to do (but what exactly?) - Ok(()) } } } @@ -825,10 +815,10 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' // TODO: Check if the signature matches for `TyClosure` // (should be the same check as what terminator/mod.rs already does on call?). // Is there other things we can/should check? Like vtable pointers? - self.validate_fields(query, mode) + self.validate_fields(query, mode)?; } // FIXME: generators aren't validated right now - TyGenerator(..) => Ok(()), + TyGenerator(..) => {}, _ => bug!("We already established that this is a type we support. ({})", query.ty), } }; @@ -840,7 +830,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' // release if it is. But of course that can't even always be statically determined. Err(EvalError { kind: EvalErrorKind::ReadUndefBytes, .. }) if mode == ValidationMode::ReleaseUntil(None) => { - return Ok(()); + Ok(()) } res => res, } From ba1c88a3c15929692af82798f055885e972af417 Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Tue, 1 May 2018 11:04:01 +0200 Subject: [PATCH 0048/3747] Rustup to rustc 1.27.0-nightly (79252ff4e 2018-04-29) --- miri/fn_call.rs | 4 ++-- miri/intrinsic.rs | 2 +- miri/lib.rs | 1 + miri/validation.rs | 2 +- 4 files changed, 5 insertions(+), 4 deletions(-) diff --git a/miri/fn_call.rs b/miri/fn_call.rs index a824cbab40a04..15b67cca93976 100644 --- a/miri/fn_call.rs +++ b/miri/fn_call.rs @@ -2,9 +2,9 @@ use rustc::ty::{self, Ty}; use rustc::ty::layout::{self, Align, LayoutOf}; use rustc::hir::def_id::{DefId, CRATE_DEF_INDEX}; use rustc::mir; +use rustc_target::spec::abi::Abi; use rustc_data_structures::indexed_vec::Idx; use syntax::attr; -use syntax::abi::Abi; use syntax::codemap::Span; use std::mem; @@ -177,7 +177,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' let attrs = self.tcx.get_attrs(def_id); let link_name = match attr::first_attr_value_str_by_name(&attrs, "link_name") { Some(name) => name.as_str(), - None => self.tcx.item_name(def_id), + None => self.tcx.item_name(def_id).as_str(), }; match &link_name[..] { diff --git a/miri/intrinsic.rs b/miri/intrinsic.rs index ea9f0428964a4..9f4950e8c9fb7 100644 --- a/miri/intrinsic.rs +++ b/miri/intrinsic.rs @@ -29,7 +29,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: ) -> EvalResult<'tcx> { let substs = instance.substs; - let intrinsic_name = &self.tcx.item_name(instance.def_id())[..]; + let intrinsic_name = &self.tcx.item_name(instance.def_id()).as_str()[..]; match intrinsic_name { "align_offset" => { // FIXME: return a real value in case the target allocation has an diff --git a/miri/lib.rs b/miri/lib.rs index 7c8183b50984f..73437d713d01b 100644 --- a/miri/lib.rs +++ b/miri/lib.rs @@ -11,6 +11,7 @@ extern crate log; #[macro_use] extern crate rustc; extern crate rustc_mir; +extern crate rustc_target; extern crate rustc_data_structures; extern crate syntax; extern crate regex; diff --git a/miri/validation.rs b/miri/validation.rs index 2de620510ffef..51b4077213997 100644 --- a/miri/validation.rs +++ b/miri/validation.rs @@ -3,7 +3,7 @@ use rustc::hir::Mutability::*; use rustc::mir::{self, ValidationOp, ValidationOperand}; use rustc::mir::interpret::GlobalId; use rustc::ty::{self, Ty, TypeFoldable, TyCtxt, Instance}; -use rustc::ty::layout::LayoutOf; +use rustc::ty::layout::{LayoutOf, PrimitiveExt}; use rustc::ty::subst::{Substs, Subst}; use rustc::traits::{self, TraitEngine}; use rustc::infer::InferCtxt; From 3dba298f1419d8c3ca9766aaeacdc4c5087c0f44 Mon Sep 17 00:00:00 2001 From: Alexander Regueiro Date: Tue, 1 May 2018 17:13:22 +0100 Subject: [PATCH 0049/3747] Fixed build for latest nightly --- miri/fn_call.rs | 6 +++--- miri/helpers.rs | 6 ++++-- miri/intrinsic.rs | 2 +- miri/lib.rs | 4 +++- miri/validation.rs | 2 +- 5 files changed, 12 insertions(+), 8 deletions(-) diff --git a/miri/fn_call.rs b/miri/fn_call.rs index a824cbab40a04..c763802bec9d9 100644 --- a/miri/fn_call.rs +++ b/miri/fn_call.rs @@ -3,8 +3,8 @@ use rustc::ty::layout::{self, Align, LayoutOf}; use rustc::hir::def_id::{DefId, CRATE_DEF_INDEX}; use rustc::mir; use rustc_data_structures::indexed_vec::Idx; +use rustc_target::spec::abi::Abi; use syntax::attr; -use syntax::abi::Abi; use syntax::codemap::Span; use std::mem; @@ -49,7 +49,7 @@ fn write_discriminant_value<'a, 'mir, 'tcx: 'a + 'mir>( if variant_index != dataful_variant { let (niche_dest, niche) = ecx.place_field(dest, mir::Field::new(0), layout)?; - let niche_value = ((variant_index - niche_variants.start) as u128) + let niche_value = ((variant_index - niche_variants.start()) as u128) .wrapping_add(niche_start); ecx.write_primval(niche_dest, PrimVal::Bytes(niche_value), niche.ty)?; } @@ -177,7 +177,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' let attrs = self.tcx.get_attrs(def_id); let link_name = match attr::first_attr_value_str_by_name(&attrs, "link_name") { Some(name) => name.as_str(), - None => self.tcx.item_name(def_id), + None => self.tcx.item_name(def_id).as_str(), }; match &link_name[..] { diff --git a/miri/helpers.rs b/miri/helpers.rs index 3dd499f7a62e9..b941e65437d9b 100644 --- a/miri/helpers.rs +++ b/miri/helpers.rs @@ -1,7 +1,9 @@ -use super::{Pointer, EvalResult, PrimVal, EvalContext}; +use mir; use rustc::ty::Ty; use rustc::ty::layout::LayoutOf; +use super::{Pointer, EvalResult, PrimVal, EvalContext}; + pub trait EvalContextExt<'tcx> { fn wrapping_pointer_offset( &self, @@ -63,7 +65,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: } Ok(ptr) } else { - err!(OverflowingMath) + err!(Overflow(mir::BinOp::Mul)) }; } } diff --git a/miri/intrinsic.rs b/miri/intrinsic.rs index ea9f0428964a4..9f4950e8c9fb7 100644 --- a/miri/intrinsic.rs +++ b/miri/intrinsic.rs @@ -29,7 +29,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: ) -> EvalResult<'tcx> { let substs = instance.substs; - let intrinsic_name = &self.tcx.item_name(instance.def_id())[..]; + let intrinsic_name = &self.tcx.item_name(instance.def_id()).as_str()[..]; match intrinsic_name { "align_offset" => { // FIXME: return a real value in case the target allocation has an diff --git a/miri/lib.rs b/miri/lib.rs index 7c8183b50984f..adc19ba0a7ae2 100644 --- a/miri/lib.rs +++ b/miri/lib.rs @@ -1,7 +1,8 @@ #![feature( rustc_private, catch_expr, - inclusive_range_fields + inclusive_range_fields, + inclusive_range_methods, )] #[macro_use] @@ -12,6 +13,7 @@ extern crate log; extern crate rustc; extern crate rustc_mir; extern crate rustc_data_structures; +extern crate rustc_target; extern crate syntax; extern crate regex; #[macro_use] diff --git a/miri/validation.rs b/miri/validation.rs index 2de620510ffef..51b4077213997 100644 --- a/miri/validation.rs +++ b/miri/validation.rs @@ -3,7 +3,7 @@ use rustc::hir::Mutability::*; use rustc::mir::{self, ValidationOp, ValidationOperand}; use rustc::mir::interpret::GlobalId; use rustc::ty::{self, Ty, TypeFoldable, TyCtxt, Instance}; -use rustc::ty::layout::LayoutOf; +use rustc::ty::layout::{LayoutOf, PrimitiveExt}; use rustc::ty::subst::{Substs, Subst}; use rustc::traits::{self, TraitEngine}; use rustc::infer::InferCtxt; From 915695371ff79f7df437494790bcec378996adff Mon Sep 17 00:00:00 2001 From: Alexander Regueiro Date: Thu, 3 May 2018 21:57:50 +0100 Subject: [PATCH 0050/3747] Minor fix to get build working --- miri/bin/miri.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/miri/bin/miri.rs b/miri/bin/miri.rs index 6ba86c81e0401..5491762c33952 100644 --- a/miri/bin/miri.rs +++ b/miri/bin/miri.rs @@ -111,7 +111,7 @@ fn after_analysis<'a, 'tcx>(state: &mut CompileState<'a, 'tcx>) { fn visit_item(&mut self, i: &'hir hir::Item) { if let hir::Item_::ItemFn(_, _, _, _, _, body_id) = i.node { if i.attrs.iter().any(|attr| { - attr.name().map_or(false, |n| n == "test") + attr.name() == "test" }) { let did = self.0.hir.body_owner_def_id(body_id); From 3d8c7a8dba7cab5d2d222cc08eaac648d6529b6a Mon Sep 17 00:00:00 2001 From: Alexander Regueiro Date: Thu, 3 May 2018 23:29:13 +0100 Subject: [PATCH 0051/3747] Fixed build for latest nightly --- miri/fn_call.rs | 1 - miri/lib.rs | 3 +-- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/miri/fn_call.rs b/miri/fn_call.rs index 51e5547de4386..c763802bec9d9 100644 --- a/miri/fn_call.rs +++ b/miri/fn_call.rs @@ -2,7 +2,6 @@ use rustc::ty::{self, Ty}; use rustc::ty::layout::{self, Align, LayoutOf}; use rustc::hir::def_id::{DefId, CRATE_DEF_INDEX}; use rustc::mir; -use rustc_target::spec::abi::Abi; use rustc_data_structures::indexed_vec::Idx; use rustc_target::spec::abi::Abi; use syntax::attr; diff --git a/miri/lib.rs b/miri/lib.rs index 9b18888451644..8359f0ad7ad0d 100644 --- a/miri/lib.rs +++ b/miri/lib.rs @@ -11,9 +11,8 @@ extern crate log; // From rustc. #[macro_use] extern crate rustc; -extern crate rustc_mir; -extern crate rustc_target; extern crate rustc_data_structures; +extern crate rustc_mir; extern crate rustc_target; extern crate syntax; extern crate regex; From b0d3daed4050874bbc4cfeaaf1fb6b1ec4e29221 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Mon, 7 May 2018 10:18:45 +0200 Subject: [PATCH 0052/3747] Rustup --- miri/bin/miri.rs | 2 +- miri/fn_call.rs | 1 - miri/lib.rs | 1 - miri/validation.rs | 5 ++++- 4 files changed, 5 insertions(+), 4 deletions(-) diff --git a/miri/bin/miri.rs b/miri/bin/miri.rs index 6ba86c81e0401..5491762c33952 100644 --- a/miri/bin/miri.rs +++ b/miri/bin/miri.rs @@ -111,7 +111,7 @@ fn after_analysis<'a, 'tcx>(state: &mut CompileState<'a, 'tcx>) { fn visit_item(&mut self, i: &'hir hir::Item) { if let hir::Item_::ItemFn(_, _, _, _, _, body_id) = i.node { if i.attrs.iter().any(|attr| { - attr.name().map_or(false, |n| n == "test") + attr.name() == "test" }) { let did = self.0.hir.body_owner_def_id(body_id); diff --git a/miri/fn_call.rs b/miri/fn_call.rs index 51e5547de4386..336c9e67a1343 100644 --- a/miri/fn_call.rs +++ b/miri/fn_call.rs @@ -4,7 +4,6 @@ use rustc::hir::def_id::{DefId, CRATE_DEF_INDEX}; use rustc::mir; use rustc_target::spec::abi::Abi; use rustc_data_structures::indexed_vec::Idx; -use rustc_target::spec::abi::Abi; use syntax::attr; use syntax::codemap::Span; diff --git a/miri/lib.rs b/miri/lib.rs index 9b18888451644..b44b70faa891a 100644 --- a/miri/lib.rs +++ b/miri/lib.rs @@ -14,7 +14,6 @@ extern crate rustc; extern crate rustc_mir; extern crate rustc_target; extern crate rustc_data_structures; -extern crate rustc_target; extern crate syntax; extern crate regex; #[macro_use] diff --git a/miri/validation.rs b/miri/validation.rs index 51b4077213997..5b919a09bd91f 100644 --- a/miri/validation.rs +++ b/miri/validation.rs @@ -455,7 +455,10 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' } // Discriminant field for enums (where applicable). - Variants::Tagged { ref discr, .. } | + Variants::Tagged { ref tag, .. } => { + assert_eq!(i, 0); + return Ok(tag.value.to_ty(tcx)) + }, Variants::NicheFilling { niche: ref discr, .. } => { assert_eq!(i, 0); return Ok(discr.value.to_ty(tcx)) From 6bc35f77cec4947dd9cb38e34dc6354745645d82 Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Mon, 7 May 2018 10:38:13 +0200 Subject: [PATCH 0053/3747] Fix allocator api and temporarily disable validation_op --- miri/fn_call.rs | 22 +++++++++------------- miri/lib.rs | 4 +++- 2 files changed, 12 insertions(+), 14 deletions(-) diff --git a/miri/fn_call.rs b/miri/fn_call.rs index c763802bec9d9..c862238e889c1 100644 --- a/miri/fn_call.rs +++ b/miri/fn_call.rs @@ -627,7 +627,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' match &path[..] { // Allocators are magic. They have no MIR, even when the rest of libstd does. - "alloc::heap::::__rust_alloc" => { + "alloc::alloc::::__rust_alloc" => { let size = self.value_to_primval(args[0])?.to_u64()?; let align = self.value_to_primval(args[1])?.to_u64()?; if size == 0 { @@ -641,7 +641,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' Some(MemoryKind::Rust.into()))?; self.write_primval(dest, PrimVal::Ptr(ptr), dest_ty)?; } - "alloc::heap::::__rust_alloc_zeroed" => { + "alloc::alloc::::__rust_alloc_zeroed" => { let size = self.value_to_primval(args[0])?.to_u64()?; let align = self.value_to_primval(args[1])?.to_u64()?; if size == 0 { @@ -656,7 +656,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' self.memory.write_repeat(ptr.into(), 0, size)?; self.write_primval(dest, PrimVal::Ptr(ptr), dest_ty)?; } - "alloc::heap::::__rust_dealloc" => { + "alloc::alloc::::__rust_dealloc" => { let ptr = self.into_ptr(args[0].value)?.to_ptr()?; let old_size = self.value_to_primval(args[1])?.to_u64()?; let align = self.value_to_primval(args[2])?.to_u64()?; @@ -672,27 +672,23 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' MemoryKind::Rust.into(), )?; } - "alloc::heap::::__rust_realloc" => { + "alloc::alloc::::__rust_realloc" => { let ptr = self.into_ptr(args[0].value)?.to_ptr()?; let old_size = self.value_to_primval(args[1])?.to_u64()?; - let old_align = self.value_to_primval(args[2])?.to_u64()?; + let align = self.value_to_primval(args[2])?.to_u64()?; let new_size = self.value_to_primval(args[3])?.to_u64()?; - let new_align = self.value_to_primval(args[4])?.to_u64()?; if old_size == 0 || new_size == 0 { return err!(HeapAllocZeroBytes); } - if !old_align.is_power_of_two() { - return err!(HeapAllocNonPowerOfTwoAlignment(old_align)); - } - if !new_align.is_power_of_two() { - return err!(HeapAllocNonPowerOfTwoAlignment(new_align)); + if !align.is_power_of_two() { + return err!(HeapAllocNonPowerOfTwoAlignment(align)); } let new_ptr = self.memory.reallocate( ptr, old_size, - Align::from_bytes(old_align, old_align).unwrap(), + Align::from_bytes(align, align).unwrap(), new_size, - Align::from_bytes(new_align, new_align).unwrap(), + Align::from_bytes(align, align).unwrap(), MemoryKind::Rust.into(), )?; self.write_primval(dest, PrimVal::Ptr(new_ptr), dest_ty)?; diff --git a/miri/lib.rs b/miri/lib.rs index 8359f0ad7ad0d..ca479e765ce5a 100644 --- a/miri/lib.rs +++ b/miri/lib.rs @@ -448,6 +448,8 @@ impl<'mir, 'tcx: 'mir> Machine<'mir, 'tcx> for Evaluator<'tcx> { op: ::rustc::mir::ValidationOp, operand: &::rustc::mir::ValidationOperand<'tcx, ::rustc::mir::Place<'tcx>>, ) -> EvalResult<'tcx> { - ecx.validation_op(op, operand) + // FIXME: prevent this from ICEing + //ecx.validation_op(op, operand) + Ok(()) } } From 860e2b802f6ef77b64c1cc25219e6548a0a851cb Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Mon, 7 May 2018 10:44:18 +0200 Subject: [PATCH 0054/3747] Dedup tag reading --- miri/validation.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/miri/validation.rs b/miri/validation.rs index 5b919a09bd91f..8f444f19bd867 100644 --- a/miri/validation.rs +++ b/miri/validation.rs @@ -455,10 +455,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' } // Discriminant field for enums (where applicable). - Variants::Tagged { ref tag, .. } => { - assert_eq!(i, 0); - return Ok(tag.value.to_ty(tcx)) - }, + Variants::Tagged { tag: ref discr, .. } | Variants::NicheFilling { niche: ref discr, .. } => { assert_eq!(i, 0); return Ok(discr.value.to_ty(tcx)) From 0eb3c18565070e4af530e0ec0f707d99be7c5cef Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Mon, 7 May 2018 10:46:32 +0200 Subject: [PATCH 0055/3747] Use a deterministic method for executing the start lang item --- miri/bin/miri.rs | 22 +++++++++++++++++++--- tests/compiletest.rs | 1 + 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/miri/bin/miri.rs b/miri/bin/miri.rs index 5491762c33952..4e0be7bd32048 100644 --- a/miri/bin/miri.rs +++ b/miri/bin/miri.rs @@ -24,6 +24,10 @@ use std::path::PathBuf; struct MiriCompilerCalls { default: RustcDefaultCalls, + /// Whether to begin interpretation at the start_fn lang item or not + /// + /// If false, the interpretation begins at the `main` function + start_fn: bool, } impl<'a> CompilerCalls<'a> for MiriCompilerCalls { @@ -80,7 +84,8 @@ impl<'a> CompilerCalls<'a> for MiriCompilerCalls { ) -> CompileController<'a> { 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); + let start_fn = self.start_fn; + control.after_analysis.callback = Box::new(move |state| after_analysis(state, start_fn)); if sess.target.target != sess.host { // only fully compile targets on the host. linking will fail for cross-compilation. control.after_analysis.stop = Compilation::Stop; @@ -97,7 +102,7 @@ fn after_hir_lowering(state: &mut CompileState) { state.session.plugin_attributes.borrow_mut().push(attr); } -fn after_analysis<'a, 'tcx>(state: &mut CompileState<'a, 'tcx>) { +fn after_analysis<'a, 'tcx>(state: &mut CompileState<'a, 'tcx>, use_start_fn: bool) { state.session.abort_if_errors(); let tcx = state.tcx.unwrap(); @@ -133,7 +138,7 @@ fn after_analysis<'a, 'tcx>(state: &mut CompileState<'a, 'tcx>) { } else if let Some((entry_node_id, _, _)) = *state.session.entry_fn.borrow() { let entry_def_id = tcx.hir.local_def_id(entry_node_id); let start_wrapper = tcx.lang_items().start_fn().and_then(|start_fn| { - if tcx.is_mir_available(start_fn) { + if use_start_fn { Some(start_fn) } else { None @@ -216,10 +221,21 @@ fn main() { args.push(find_sysroot()); } + let mut start_fn = false; + args.retain(|arg| { + if arg == "-Zmiri-start-fn" { + start_fn = true; + false + } else { + true + } + }); + // Make sure we always have all the MIR (e.g. for auxilary builds in unit tests). args.push("-Zalways-encode-mir".to_owned()); rustc_driver::run_compiler(&args, &mut MiriCompilerCalls { default: RustcDefaultCalls, + start_fn, }, None, None); } diff --git a/tests/compiletest.rs b/tests/compiletest.rs index a1a28d4e4a688..3fb7f2784a6ac 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -114,6 +114,7 @@ fn miri_pass(path: &str, target: &str, host: &str, fullmir: bool, opt: bool) { .join(".xargo") .join("HOST"); + flags.push("-Zmiri-start-fn".to_owned()); flags.push(format!("--sysroot {}", sysroot.to_str().unwrap())); } if opt { From 0a88698daf8b5bc63de8297b287c82df82c07c36 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Mon, 7 May 2018 10:49:54 +0200 Subject: [PATCH 0056/3747] Hide some warnings/Fix build --- miri/fn_call.rs | 1 + miri/lib.rs | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/miri/fn_call.rs b/miri/fn_call.rs index de69c58fb4ac6..c862238e889c1 100644 --- a/miri/fn_call.rs +++ b/miri/fn_call.rs @@ -3,6 +3,7 @@ use rustc::ty::layout::{self, Align, LayoutOf}; use rustc::hir::def_id::{DefId, CRATE_DEF_INDEX}; use rustc::mir; use rustc_data_structures::indexed_vec::Idx; +use rustc_target::spec::abi::Abi; use syntax::attr; use syntax::codemap::Span; diff --git a/miri/lib.rs b/miri/lib.rs index ca479e765ce5a..5818a27085044 100644 --- a/miri/lib.rs +++ b/miri/lib.rs @@ -444,9 +444,9 @@ impl<'mir, 'tcx: 'mir> Machine<'mir, 'tcx> for Evaluator<'tcx> { } fn validation_op<'a>( - ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, - op: ::rustc::mir::ValidationOp, - operand: &::rustc::mir::ValidationOperand<'tcx, ::rustc::mir::Place<'tcx>>, + _ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, + _op: ::rustc::mir::ValidationOp, + _operand: &::rustc::mir::ValidationOperand<'tcx, ::rustc::mir::Place<'tcx>>, ) -> EvalResult<'tcx> { // FIXME: prevent this from ICEing //ecx.validation_op(op, operand) From 6653bb38d5bb95bda0937e876094ef3b8bfca92c Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Mon, 7 May 2018 18:02:57 +0200 Subject: [PATCH 0057/3747] Implement missing intrinsic --- miri/intrinsic.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/miri/intrinsic.rs b/miri/intrinsic.rs index 9f4950e8c9fb7..453e834566a6e 100644 --- a/miri/intrinsic.rs +++ b/miri/intrinsic.rs @@ -315,6 +315,20 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: self.write_primval(dest, result.0, dest_layout.ty)?; } + "exact_div" => { + // Performs an exact division, resulting in undefined behavior where + // `x % y != 0` or `y == 0` or `x == T::min_value() && y == -1` + let ty = substs.type_at(0); + let a = self.value_to_primval(args[0])?; + let b = self.value_to_primval(args[1])?; + // check x % y != 0 + if self.binary_op(mir::BinOp::Rem, a, ty, b, ty)?.0 != PrimVal::Bytes(0) { + return err!(ValidationFailure(format!("exact_div: {:?} cannot be divided by {:?}", a, b))); + } + let result = self.binary_op(mir::BinOp::Div, a, ty, b, ty)?; + self.write_primval(dest, result.0, dest_layout.ty)?; + }, + "likely" | "unlikely" | "forget" => {} "init" => { From e0e1bd7ff778e5913b566c9e03224faecc0eb486 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Mon, 7 May 2018 18:03:28 +0200 Subject: [PATCH 0058/3747] Pointers must be valid, even pointers to zsts --- miri/lib.rs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/miri/lib.rs b/miri/lib.rs index 5818a27085044..dce31c4ed3383 100644 --- a/miri/lib.rs +++ b/miri/lib.rs @@ -145,7 +145,7 @@ pub fn eval_main<'a, 'tcx: 'a>( main_instance, main_mir.span, main_mir, - Place::undef(), + Place::from_primval_ptr(PrimVal::Bytes(1).into(), ty::layout::Align::from_bytes(1, 1).unwrap()), StackPopCleanup::None, )?; @@ -177,6 +177,16 @@ pub fn eval_main<'a, 'tcx: 'a>( Err(mut e) => { ecx.tcx.sess.err(&e.to_string()); ecx.report(&mut e, true, None); + for (i, frame) in ecx.stack().iter().enumerate() { + trace!("-------------------"); + trace!("Frame {}", i); + trace!(" return: {:#?}", frame.return_place); + for (i, local) in frame.locals.iter().enumerate() { + if let Some(local) = local { + trace!(" local {}: {:?}", i, local); + } + } + } } } } From ce7605caaa46e0a218fe10f1294491ab336e4afc Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Wed, 9 May 2018 11:52:41 +0200 Subject: [PATCH 0059/3747] Fix some bad conversions on 32 bit emulation --- miri/helpers.rs | 59 ++++++++++++++++++++++++++++++++++++++++++++++- miri/intrinsic.rs | 18 +++++++-------- 2 files changed, 67 insertions(+), 10 deletions(-) diff --git a/miri/helpers.rs b/miri/helpers.rs index b941e65437d9b..a7b94a656da4a 100644 --- a/miri/helpers.rs +++ b/miri/helpers.rs @@ -2,7 +2,8 @@ use mir; use rustc::ty::Ty; use rustc::ty::layout::LayoutOf; -use super::{Pointer, EvalResult, PrimVal, EvalContext}; +use super::{Pointer, EvalResult, PrimVal, EvalContext, ValTy}; +use rustc_mir::interpret::sign_extend; pub trait EvalContextExt<'tcx> { fn wrapping_pointer_offset( @@ -18,6 +19,26 @@ pub trait EvalContextExt<'tcx> { pointee_ty: Ty<'tcx>, offset: i64, ) -> EvalResult<'tcx, Pointer>; + + fn value_to_isize( + &self, + value: ValTy<'tcx>, + ) -> EvalResult<'tcx, i64>; + + fn value_to_usize( + &self, + value: ValTy<'tcx>, + ) -> EvalResult<'tcx, u64>; + + fn value_to_i32( + &self, + value: ValTy<'tcx>, + ) -> EvalResult<'tcx, i32>; + + fn value_to_u8( + &self, + value: ValTy<'tcx>, + ) -> EvalResult<'tcx, u8>; } impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super::Evaluator<'tcx>> { @@ -68,4 +89,40 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: err!(Overflow(mir::BinOp::Mul)) }; } + + fn value_to_isize( + &self, + value: ValTy<'tcx>, + ) -> EvalResult<'tcx, i64> { + assert_eq!(value.ty, self.tcx.types.isize); + let raw = self.value_to_primval(value)?.to_bytes()?; + let raw = sign_extend(self.tcx.tcx, raw, self.tcx.types.isize)?; + Ok(raw as i64) + } + + fn value_to_usize( + &self, + value: ValTy<'tcx>, + ) -> EvalResult<'tcx, u64> { + assert_eq!(value.ty, self.tcx.types.usize); + self.value_to_primval(value)?.to_bytes().map(|v| v as u64) + } + + fn value_to_i32( + &self, + value: ValTy<'tcx>, + ) -> EvalResult<'tcx, i32> { + assert_eq!(value.ty, self.tcx.types.i32); + let raw = self.value_to_primval(value)?.to_bytes()?; + let raw = sign_extend(self.tcx.tcx, raw, self.tcx.types.i32)?; + Ok(raw as i32) + } + + fn value_to_u8( + &self, + value: ValTy<'tcx>, + ) -> EvalResult<'tcx, u8> { + assert_eq!(value.ty, self.tcx.types.u8); + self.value_to_primval(value)?.to_bytes().map(|v| v as u8) + } } diff --git a/miri/intrinsic.rs b/miri/intrinsic.rs index 453e834566a6e..234d1ee784838 100644 --- a/miri/intrinsic.rs +++ b/miri/intrinsic.rs @@ -70,7 +70,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: } "arith_offset" => { - let offset = self.value_to_primval(args[1])?.to_i128()? as i64; + let offset = self.value_to_isize(args[1])?; let ptr = self.into_ptr(args[0].value)?; let result_ptr = self.wrapping_pointer_offset(ptr, substs.type_at(0), offset)?; self.write_ptr(dest, result_ptr, dest_layout.ty)?; @@ -213,7 +213,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: let elem_ty = substs.type_at(0); let elem_layout = self.layout_of(elem_ty)?; let elem_size = elem_layout.size.bytes(); - let count = self.value_to_primval(args[2])?.to_u64()?; + let count = self.value_to_usize(args[2])?; if count * elem_size != 0 { // 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. @@ -407,7 +407,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: } "offset" => { - let offset = self.value_to_primval(args[1])?.to_i128()? as i64; + let offset = self.value_to_isize(args[1])?; let ptr = self.into_ptr(args[0].value)?; let result_ptr = self.pointer_offset(ptr, substs.type_at(0), offset)?; self.write_ptr(dest, result_ptr, dest_layout.ty)?; @@ -498,10 +498,10 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: "powif32" => { let f = self.value_to_primval(args[0])?.to_bytes()?; let f = f32::from_bits(f as u32); - let i = self.value_to_primval(args[1])?.to_i128()?; + let i = self.value_to_i32(args[1])?; self.write_primval( dest, - PrimVal::Bytes(f.powi(i as i32).to_bits() as u128), + PrimVal::Bytes(f.powi(i).to_bits() as u128), dest_layout.ty, )?; } @@ -509,10 +509,10 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: "powif64" => { let f = self.value_to_primval(args[0])?.to_bytes()?; let f = f64::from_bits(f as u64); - let i = self.value_to_primval(args[1])?.to_i128()?; + let i = self.value_to_i32(args[1])?; self.write_primval( dest, - PrimVal::Bytes(f.powi(i as i32).to_bits() as u128), + PrimVal::Bytes(f.powi(i).to_bits() as u128), dest_layout.ty, )?; } @@ -655,9 +655,9 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: "write_bytes" => { let ty = substs.type_at(0); let ty_layout = self.layout_of(ty)?; - let val_byte = self.value_to_primval(args[1])?.to_u128()? as u8; + let val_byte = self.value_to_u8(args[1])?; let ptr = self.into_ptr(args[0].value)?; - let count = self.value_to_primval(args[2])?.to_u64()?; + 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 // TODO: Should we, at least, validate the alignment? (Also see the copy intrinsic) From a4fdcd29b5c4cd5f733e7f920c4e33f21c6fd15a Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Wed, 9 May 2018 13:43:31 +0200 Subject: [PATCH 0060/3747] Disable cargo miri test for now --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index b02b14392daea..9b6bd15b1eb9d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -24,7 +24,7 @@ script: # Test cargo miri cd cargo-miri-test && cargo miri && - cargo miri test && + #cargo miri test && cd .. - | # and run all tests with full mir From c05d570d6e048db69116ebdd6af3ebb18bf08670 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Wed, 9 May 2018 14:05:51 +0200 Subject: [PATCH 0061/3747] Update the rustc_tests crate --- rustc_tests/src/main.rs | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/rustc_tests/src/main.rs b/rustc_tests/src/main.rs index 29b2dc2b7a425..77e4a3df406b7 100644 --- a/rustc_tests/src/main.rs +++ b/rustc_tests/src/main.rs @@ -1,9 +1,10 @@ -#![feature(rustc_private, i128_type)] +#![feature(rustc_private)] extern crate miri; extern crate getopts; extern crate rustc; extern crate rustc_driver; extern crate rustc_errors; +extern crate rustc_trans_utils; extern crate syntax; use std::path::{PathBuf, Path}; @@ -18,6 +19,7 @@ use rustc_driver::{Compilation, CompilerCalls, RustcDefaultCalls}; use rustc_driver::driver::{CompileState, CompileController}; use rustc::session::config::{self, Input, ErrorOutputType}; use rustc::hir::{self, itemlikevisit}; +use rustc_trans_utils::trans_crate::TransCrate; use rustc::ty::TyCtxt; use syntax::ast; @@ -51,14 +53,15 @@ impl<'a> CompilerCalls<'a> for MiriCompilerCalls { } fn late_callback( &mut self, + trans: &TransCrate, matches: &getopts::Matches, sess: &Session, cstore: &CrateStore, input: &Input, odir: &Option, - ofile: &Option + ofile: &Option, ) -> Compilation { - self.default.late_callback(matches, sess, cstore, input, odir, ofile) + self.default.late_callback(trans, matches, sess, cstore, input, odir, ofile) } fn build_controller(&mut self, sess: &Session, matches: &getopts::Matches) -> CompileController<'a> { let mut control = self.default.build_controller(sess, matches); @@ -81,30 +84,29 @@ fn after_analysis<'a, 'tcx>(state: &mut CompileState<'a, 'tcx>) { state.session.abort_if_errors(); let tcx = state.tcx.unwrap(); - let limits = Default::default(); if std::env::args().any(|arg| arg == "--test") { - struct Visitor<'a, 'tcx: 'a>(miri::ResourceLimits, TyCtxt<'a, 'tcx, 'tcx>, &'a CompileState<'a, 'tcx>); + struct Visitor<'a, 'tcx: 'a>(TyCtxt<'a, 'tcx, 'tcx>, &'a CompileState<'a, 'tcx>); impl<'a, 'tcx: 'a, 'hir> itemlikevisit::ItemLikeVisitor<'hir> for Visitor<'a, 'tcx> { fn visit_item(&mut self, i: &'hir hir::Item) { if let hir::Item_::ItemFn(_, _, _, _, _, body_id) = i.node { - if i.attrs.iter().any(|attr| attr.name().map_or(false, |n| n == "test")) { - let did = self.1.hir.body_owner_def_id(body_id); - println!("running test: {}", self.1.def_path_debug_str(did)); - miri::eval_main(self.1, did, None, self.0); - self.2.session.abort_if_errors(); + if i.attrs.iter().any(|attr| attr.name() == "test") { + let did = self.0.hir.body_owner_def_id(body_id); + println!("running test: {}", self.0.def_path_debug_str(did)); + miri::eval_main(self.0, did, None); + self.1.session.abort_if_errors(); } } } fn visit_trait_item(&mut self, _trait_item: &'hir hir::TraitItem) {} fn visit_impl_item(&mut self, _impl_item: &'hir hir::ImplItem) {} } - state.hir_crate.unwrap().visit_all_item_likes(&mut Visitor(limits, tcx, state)); - } else if let Some((entry_node_id, _)) = *state.session.entry_fn.borrow() { + state.hir_crate.unwrap().visit_all_item_likes(&mut Visitor(tcx, state)); + } else if let Some((entry_node_id, _, _)) = *state.session.entry_fn.borrow() { let entry_def_id = tcx.hir.local_def_id(entry_node_id); let start_wrapper = tcx.lang_items().start_fn().and_then(|start_fn| if tcx.is_mir_available(start_fn) { Some(start_fn) } else { None }); - miri::eval_main(tcx, entry_def_id, start_wrapper, limits); + miri::eval_main(tcx, entry_def_id, start_wrapper); state.session.abort_if_errors(); } else { From e1013e011ca698fff257704522f9a8088d594b24 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Wed, 9 May 2018 14:33:17 +0200 Subject: [PATCH 0062/3747] Appveyor update to ignore Cargo.lock --- appveyor.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index 86f9b19af87f6..40ecd9492c1a5 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -33,8 +33,8 @@ build: false test_script: - set RUST_BACKTRACE=1 - - cargo build --locked --release - - cargo test --locked --release + - cargo build --release + - cargo test --release notifications: - provider: Email From 27fe2636698f814debae621f00e1e3df8a7fca85 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Wed, 9 May 2018 14:37:00 +0200 Subject: [PATCH 0063/3747] Move back to a normal folder structure --- Cargo.toml | 7 ++----- {miri => src}/bin/cargo-miri.rs | 0 {miri => src}/bin/miri.rs | 0 {miri => src}/fn_call.rs | 0 {miri => src}/helpers.rs | 0 {miri => src}/intrinsic.rs | 0 {miri => src}/lib.rs | 0 {miri => src}/locks.rs | 0 {miri => src}/memory.rs | 0 {miri => src}/operator.rs | 0 {miri => src}/range_map.rs | 0 {miri => src}/tls.rs | 0 {miri => src}/validation.rs | 0 13 files changed, 2 insertions(+), 5 deletions(-) rename {miri => src}/bin/cargo-miri.rs (100%) rename {miri => src}/bin/miri.rs (100%) rename {miri => src}/fn_call.rs (100%) rename {miri => src}/helpers.rs (100%) rename {miri => src}/intrinsic.rs (100%) rename {miri => src}/lib.rs (100%) rename {miri => src}/locks.rs (100%) rename {miri => src}/memory.rs (100%) rename {miri => src}/operator.rs (100%) rename {miri => src}/range_map.rs (100%) rename {miri => src}/tls.rs (100%) rename {miri => src}/validation.rs (100%) diff --git a/Cargo.toml b/Cargo.toml index 444c6f60d544e..86ac2c040fd1c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,17 +10,14 @@ build = "build.rs" [[bin]] doc = false name = "miri" -path = "miri/bin/miri.rs" +path = "src/bin/miri.rs" [[bin]] doc = false name = "cargo-miri" -path = "miri/bin/cargo-miri.rs" +path = "src/bin/cargo-miri.rs" required-features = ["cargo_miri"] -[lib] -path = "miri/lib.rs" - [dependencies] byteorder = { version = "1.1", features = ["i128"]} cargo_metadata = { version = "0.5", optional = true } diff --git a/miri/bin/cargo-miri.rs b/src/bin/cargo-miri.rs similarity index 100% rename from miri/bin/cargo-miri.rs rename to src/bin/cargo-miri.rs diff --git a/miri/bin/miri.rs b/src/bin/miri.rs similarity index 100% rename from miri/bin/miri.rs rename to src/bin/miri.rs diff --git a/miri/fn_call.rs b/src/fn_call.rs similarity index 100% rename from miri/fn_call.rs rename to src/fn_call.rs diff --git a/miri/helpers.rs b/src/helpers.rs similarity index 100% rename from miri/helpers.rs rename to src/helpers.rs diff --git a/miri/intrinsic.rs b/src/intrinsic.rs similarity index 100% rename from miri/intrinsic.rs rename to src/intrinsic.rs diff --git a/miri/lib.rs b/src/lib.rs similarity index 100% rename from miri/lib.rs rename to src/lib.rs diff --git a/miri/locks.rs b/src/locks.rs similarity index 100% rename from miri/locks.rs rename to src/locks.rs diff --git a/miri/memory.rs b/src/memory.rs similarity index 100% rename from miri/memory.rs rename to src/memory.rs diff --git a/miri/operator.rs b/src/operator.rs similarity index 100% rename from miri/operator.rs rename to src/operator.rs diff --git a/miri/range_map.rs b/src/range_map.rs similarity index 100% rename from miri/range_map.rs rename to src/range_map.rs diff --git a/miri/tls.rs b/src/tls.rs similarity index 100% rename from miri/tls.rs rename to src/tls.rs diff --git a/miri/validation.rs b/src/validation.rs similarity index 100% rename from miri/validation.rs rename to src/validation.rs From 9068a2a4b36ac7f008c52b8f6d5b874ec8a37739 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Wed, 9 May 2018 15:13:36 +0200 Subject: [PATCH 0064/3747] cargo cache was messing up xargo/miri install --- .travis.yml | 4 ++-- appveyor.yml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 9b6bd15b1eb9d..360b741106e58 100644 --- a/.travis.yml +++ b/.travis.yml @@ -8,7 +8,7 @@ before_script: - rustup target add i686-pc-windows-gnu - rustup target add i686-pc-windows-msvc - rustup component add rust-src -- cargo install --git https://github.com/japaric/xargo.git +- cargo install xargo || echo "skipping xargo install" - export RUST_SYSROOT=$HOME/rust script: - set -e @@ -19,7 +19,7 @@ script: # Test plain miri cargo build --release --all-features && cargo test --release --all-features --all && - cargo install --all-features + cargo install --all-features --force - | # Test cargo miri cd cargo-miri-test && diff --git a/appveyor.yml b/appveyor.yml index 40ecd9492c1a5..46580f274bf62 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -22,7 +22,7 @@ install: - rustc -V - cargo -V - rustup component add rust-src - - cargo install --git https://github.com/japaric/xargo.git + - cargo install xargo - cd xargo - set RUSTFLAGS=-Zalways-encode-mir -Zmir-emit-validate=1 - xargo build From 8d6a893a4a47828fa0e9727545b6a0accf63a55d Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Fri, 11 May 2018 09:38:13 +0200 Subject: [PATCH 0065/3747] Rustup to 1.27.0-nightly (acd3871ba 2018-05-10) --- src/validation.rs | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/validation.rs b/src/validation.rs index 8f444f19bd867..b274b4650157d 100644 --- a/src/validation.rs +++ b/src/validation.rs @@ -401,7 +401,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' } // Potentially-fat pointers. - ty::TyRef(_, ty::TypeAndMut { ty: pointee, .. }) | + ty::TyRef(_, pointee, _) | ty::TyRawPtr(ty::TypeAndMut { ty: pointee, .. }) => { assert!(i < 2); @@ -658,11 +658,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' } } TyNever => return err!(ValidationFailure(format!("The empty type is never valid."))), - TyRef(region, - ty::TypeAndMut { - ty: pointee_ty, - mutbl, - }) => { + TyRef(region, pointee_ty, mutbl) => { let val = self.read_place(query.place.1)?; // Sharing restricts our context if mutbl == MutImmutable { From 20c2e0bede0877abe79dda162922ec8c267105fe Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Wed, 19 Jul 2017 15:06:21 +0200 Subject: [PATCH 0066/3747] Test miri on mac os --- .travis.yml | 9 +++++++++ src/fn_call.rs | 11 +++++++++-- tests/run-pass-fullmir/catch.rs | 1 + tests/run-pass-fullmir/format.rs | 1 + tests/run-pass-fullmir/hello.rs | 1 + tests/run-pass-fullmir/issue-3794.rs | 1 + 6 files changed, 22 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 360b741106e58..6a987f93748c1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,8 +1,17 @@ language: rust cache: cargo + +os: +- osx +- linux + rust: - nightly before_script: +# mac os weirdness (https://github.com/travis-ci/travis-ci/issues/6307) +- curl -sSL https://rvm.io/mpapis.asc | gpg --import - +- rvm get stable +# actual travis code - export PATH=$HOME/.local/bin:$PATH - rustup target add i686-unknown-linux-gnu - rustup target add i686-pc-windows-gnu diff --git a/src/fn_call.rs b/src/fn_call.rs index c862238e889c1..2b4e7b7366284 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -531,9 +531,10 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' // Return success (0) self.write_null(dest, dest_ty)?; } + "_tlv_atexit" => { - // TODO: handle it - } + return err!(Unimplemented("can't interpret with full mir for osx target".to_owned())); + }, // Stub out all the other pthread calls to just return 0 link_name if link_name.starts_with("pthread_") => { @@ -541,6 +542,12 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' self.write_null(dest, dest_ty)?; } + "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)?; + self.write_ptr(dest, addr, dest_ty)?; + } + _ => { return err!(Unimplemented( format!("can't call C ABI function: {}", link_name), diff --git a/tests/run-pass-fullmir/catch.rs b/tests/run-pass-fullmir/catch.rs index 490f17d4cf4f5..60c86c99e9aaf 100644 --- a/tests/run-pass-fullmir/catch.rs +++ b/tests/run-pass-fullmir/catch.rs @@ -1,4 +1,5 @@ //ignore-msvc +//ignore-macos use std::panic::{catch_unwind, AssertUnwindSafe}; fn main() { diff --git a/tests/run-pass-fullmir/format.rs b/tests/run-pass-fullmir/format.rs index a14d7054e7290..59af803b59f0f 100644 --- a/tests/run-pass-fullmir/format.rs +++ b/tests/run-pass-fullmir/format.rs @@ -1,4 +1,5 @@ //ignore-msvc +//ignore-macos fn main() { println!("Hello {}", 13); } diff --git a/tests/run-pass-fullmir/hello.rs b/tests/run-pass-fullmir/hello.rs index 986efcaf9005a..a0d73733bdfc8 100644 --- a/tests/run-pass-fullmir/hello.rs +++ b/tests/run-pass-fullmir/hello.rs @@ -1,4 +1,5 @@ //ignore-msvc +//ignore-macos fn main() { println!("Hello, world!"); } diff --git a/tests/run-pass-fullmir/issue-3794.rs b/tests/run-pass-fullmir/issue-3794.rs index 8d55af58eeca8..8b653f0f95fc9 100644 --- a/tests/run-pass-fullmir/issue-3794.rs +++ b/tests/run-pass-fullmir/issue-3794.rs @@ -9,6 +9,7 @@ // except according to those terms. //ignore-msvc +//ignore-macos #![feature(box_syntax)] trait T { From 6a4c62c1673c3dabcc9a0c99018bd08fec46fda7 Mon Sep 17 00:00:00 2001 From: David Renshaw Date: Sat, 6 Jan 2018 16:50:21 -0500 Subject: [PATCH 0067/3747] add iter_any test --- tests/run-pass/iter_any.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 tests/run-pass/iter_any.rs diff --git a/tests/run-pass/iter_any.rs b/tests/run-pass/iter_any.rs new file mode 100644 index 0000000000000..b14eb074488b2 --- /dev/null +++ b/tests/run-pass/iter_any.rs @@ -0,0 +1,12 @@ +pub fn main() { + let f = |x: &u8| { 10u8 == *x }; + f(&1u8); + + let g = |(), x: &u8| { 10u8 == *x }; + g((), &1u8); + + let h = |(), (), x: &u8| { 10u8 == *x }; + h((), (), &1u8); + + [1, 2, 3u8].into_iter().any(|elt| 10 == *elt); +} From 68378a7b9772a58c6b1035e998f7d4d6ee2a6725 Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Sun, 13 May 2018 13:14:26 +0200 Subject: [PATCH 0068/3747] Rustup to rustc 1.27.0-nightly (ff2ac35db 2018-05-12) --- src/fn_call.rs | 2 +- src/validation.rs | 15 +++++++-------- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index 2b4e7b7366284..272c27e402196 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -459,7 +459,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' promoted: None, }; let const_val = self.const_eval(cid)?; - let value = const_val.val.unwrap_u64(); + let value = const_val.unwrap_usize(self.tcx.tcx); if value == name { result = Some(path_value); break; diff --git a/src/validation.rs b/src/validation.rs index b274b4650157d..deb1c5d5bc079 100644 --- a/src/validation.rs +++ b/src/validation.rs @@ -10,7 +10,7 @@ use rustc::infer::InferCtxt; use rustc::middle::region; use rustc::middle::const_val::ConstVal; use rustc_data_structures::indexed_vec::Idx; -use rustc_mir::interpret::{HasMemory, eval_body}; +use rustc_mir::interpret::HasMemory; use super::{EvalContext, Place, PlaceExtra, ValTy}; use rustc::mir::interpret::{DynamicLifetime, AccessKind, EvalErrorKind, Value, EvalError, EvalResult}; @@ -718,18 +718,17 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' } } TyArray(elem_ty, len) => { - let len_val = match len.val { + let len = match len.val { ConstVal::Unevaluated(def_id, substs) => { - eval_body(self.tcx.tcx, GlobalId { + self.tcx.const_eval(self.tcx.param_env(def_id).and(GlobalId { instance: Instance::new(def_id, substs), promoted: None, - }, ty::ParamEnv::reveal_all()) - .ok_or_else(||EvalErrorKind::MachineError("".to_string()))? - .0 + })) + .map_err(|_err|EvalErrorKind::MachineError("".to_string()))? } - ConstVal::Value(val) => val, + ConstVal::Value(_) => len, }; - let len = ConstVal::Value(len_val).unwrap_u64(); + let len = len.unwrap_usize(self.tcx.tcx); for i in 0..len { let inner_place = self.place_index(query.place.1, query.ty, i as u64)?; self.validate( From 1bf0ffcb27ff8e38424f1e4115b52752cd0eeb70 Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Sun, 13 May 2018 15:32:35 +0200 Subject: [PATCH 0069/3747] Enable backtraces for tests --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 6a987f93748c1..9aa632da05e0e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -27,7 +27,7 @@ script: - | # Test plain miri cargo build --release --all-features && - cargo test --release --all-features --all && + RUST_BACKTRACE=1 cargo test --release --all-features --all && cargo install --all-features --force - | # Test cargo miri From d3b9085f1aec3cd60818e76fc2436145081cf7c6 Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Sat, 19 May 2018 12:14:13 +0200 Subject: [PATCH 0070/3747] Rustup to rustc 1.28.0-nightly (952f344cd 2018-05-18) --- src/bin/miri.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 4e0be7bd32048..5ae9626f01fbd 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -5,7 +5,7 @@ extern crate miri; extern crate rustc; extern crate rustc_driver; extern crate rustc_errors; -extern crate rustc_trans_utils; +extern crate rustc_codegen_utils; extern crate env_logger; extern crate log_settings; extern crate syntax; @@ -18,7 +18,7 @@ use rustc_driver::driver::{CompileState, CompileController}; use rustc::session::config::{self, Input, ErrorOutputType}; use rustc::hir::{self, itemlikevisit}; use rustc::ty::TyCtxt; -use rustc_trans_utils::trans_crate::TransCrate; +use rustc_codegen_utils::codegen_backend::CodegenBackend; use syntax::ast; use std::path::PathBuf; @@ -67,7 +67,7 @@ impl<'a> CompilerCalls<'a> for MiriCompilerCalls { } fn late_callback( &mut self, - trans: &TransCrate, + trans: &CodegenBackend, matches: &getopts::Matches, sess: &Session, cstore: &CrateStore, From 04608016ecd042308f2c55d652f67cac9025ae78 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Sat, 19 May 2018 14:09:29 +0200 Subject: [PATCH 0071/3747] trans -> codegen_backend --- src/bin/miri.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 5ae9626f01fbd..8d80135cde300 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -67,7 +67,7 @@ impl<'a> CompilerCalls<'a> for MiriCompilerCalls { } fn late_callback( &mut self, - trans: &CodegenBackend, + codegen_backend: &CodegenBackend, matches: &getopts::Matches, sess: &Session, cstore: &CrateStore, @@ -75,7 +75,7 @@ impl<'a> CompilerCalls<'a> for MiriCompilerCalls { odir: &Option, ofile: &Option, ) -> Compilation { - self.default.late_callback(trans, matches, sess, cstore, input, odir, ofile) + self.default.late_callback(codegen_backend, matches, sess, cstore, input, odir, ofile) } fn build_controller( &mut self, From 7d953a65f368fb2b60af5c0dc7ce51e3856ca4d6 Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Sun, 20 May 2018 11:26:40 +0200 Subject: [PATCH 0072/3747] Rustup to rustc 1.28.0-nightly (a3085756e 2018-05-19) --- src/fn_call.rs | 34 +++++++++++++++++----------------- src/intrinsic.rs | 12 ++++++------ src/lib.rs | 16 ++++++++-------- src/locks.rs | 11 ++++++----- src/operator.rs | 10 +++++----- 5 files changed, 42 insertions(+), 41 deletions(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index 272c27e402196..e7250eca949d1 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -1,5 +1,5 @@ use rustc::ty::{self, Ty}; -use rustc::ty::layout::{self, Align, LayoutOf}; +use rustc::ty::layout::{self, Align, LayoutOf, Size}; use rustc::hir::def_id::{DefId, CRATE_DEF_INDEX}; use rustc::mir; use rustc_data_structures::indexed_vec::Idx; @@ -187,7 +187,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' self.write_null(dest, dest_ty)?; } else { let align = self.tcx.data_layout.pointer_align; - let ptr = self.memory.allocate(size, align, Some(MemoryKind::C.into()))?; + let ptr = self.memory.allocate(Size::from_bytes(size), align, Some(MemoryKind::C.into()))?; self.write_primval(dest, PrimVal::Ptr(ptr), dest_ty)?; } } @@ -281,7 +281,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' "memcmp" => { let left = self.into_ptr(args[0].value)?; let right = self.into_ptr(args[1].value)?; - let n = self.value_to_primval(args[2])?.to_u64()?; + let n = Size::from_bytes(self.value_to_primval(args[2])?.to_u64()?); let result = { let left_bytes = self.memory.read_bytes(left, n)?; @@ -306,11 +306,11 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' let ptr = self.into_ptr(args[0].value)?; let val = self.value_to_primval(args[1])?.to_u64()? as u8; let num = self.value_to_primval(args[2])?.to_u64()?; - if let Some(idx) = self.memory.read_bytes(ptr, num)?.iter().rev().position( + if let Some(idx) = self.memory.read_bytes(ptr, Size::from_bytes(num))?.iter().rev().position( |&c| c == val, ) { - let new_ptr = ptr.offset(num - idx as u64 - 1, &self)?; + let new_ptr = ptr.offset(Size::from_bytes(num - idx as u64 - 1), &self)?; self.write_ptr(dest, new_ptr, dest_ty)?; } else { self.write_null(dest, dest_ty)?; @@ -321,11 +321,11 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' let ptr = self.into_ptr(args[0].value)?; let val = self.value_to_primval(args[1])?.to_u64()? as u8; let num = self.value_to_primval(args[2])?.to_u64()?; - if let Some(idx) = self.memory.read_bytes(ptr, num)?.iter().position( + if let Some(idx) = self.memory.read_bytes(ptr, Size::from_bytes(num))?.iter().position( |&c| c == val, ) { - let new_ptr = ptr.offset(idx as u64, &self)?; + let new_ptr = ptr.offset(Size::from_bytes(idx as u64), &self)?; self.write_ptr(dest, new_ptr, dest_ty)?; } else { self.write_null(dest, dest_ty)?; @@ -381,12 +381,12 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' if let Some((name, value)) = new { // +1 for the null terminator let value_copy = self.memory.allocate( - (value.len() + 1) as u64, + Size::from_bytes((value.len() + 1) as u64), Align::from_bytes(1, 1).unwrap(), Some(MemoryKind::Env.into()), )?; self.memory.write_bytes(value_copy.into(), &value)?; - let trailing_zero_ptr = value_copy.offset(value.len() as u64, &self)?.into(); + let trailing_zero_ptr = value_copy.offset(Size::from_bytes(value.len() as u64), &self)?.into(); self.memory.write_bytes(trailing_zero_ptr, &[0])?; if let Some(var) = self.machine.env_vars.insert( name.to_owned(), @@ -410,7 +410,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' // stdout/stderr use std::io::{self, Write}; - let buf_cont = self.memory.read_bytes(buf, n)?; + let buf_cont = self.memory.read_bytes(buf, Size::from_bytes(n))?; let res = if fd == 1 { io::stdout().write(buf_cont) } else { @@ -502,7 +502,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' key_ptr, key_align, PrimVal::Bytes(key), - key_size.bytes(), + key_size, false, )?; @@ -643,7 +643,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' if !align.is_power_of_two() { return err!(HeapAllocNonPowerOfTwoAlignment(align)); } - let ptr = self.memory.allocate(size, + let ptr = self.memory.allocate(Size::from_bytes(size), Align::from_bytes(align, align).unwrap(), Some(MemoryKind::Rust.into()))?; self.write_primval(dest, PrimVal::Ptr(ptr), dest_ty)?; @@ -657,10 +657,10 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' if !align.is_power_of_two() { return err!(HeapAllocNonPowerOfTwoAlignment(align)); } - let ptr = self.memory.allocate(size, + let ptr = self.memory.allocate(Size::from_bytes(size), Align::from_bytes(align, align).unwrap(), Some(MemoryKind::Rust.into()))?; - self.memory.write_repeat(ptr.into(), 0, size)?; + self.memory.write_repeat(ptr.into(), 0, Size::from_bytes(size))?; self.write_primval(dest, PrimVal::Ptr(ptr), dest_ty)?; } "alloc::alloc::::__rust_dealloc" => { @@ -675,7 +675,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' } self.memory.deallocate( ptr, - Some((old_size, Align::from_bytes(align, align).unwrap())), + Some((Size::from_bytes(old_size), Align::from_bytes(align, align).unwrap())), MemoryKind::Rust.into(), )?; } @@ -692,9 +692,9 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' } let new_ptr = self.memory.reallocate( ptr, - old_size, + Size::from_bytes(old_size), Align::from_bytes(align, align).unwrap(), - new_size, + Size::from_bytes(new_size), Align::from_bytes(align, align).unwrap(), MemoryKind::Rust.into(), )?; diff --git a/src/intrinsic.rs b/src/intrinsic.rs index 234d1ee784838..30de1c68ca618 100644 --- a/src/intrinsic.rs +++ b/src/intrinsic.rs @@ -1,5 +1,5 @@ use rustc::mir; -use rustc::ty::layout::{TyLayout, LayoutOf}; +use rustc::ty::layout::{TyLayout, LayoutOf, Size}; use rustc::ty; use rustc::mir::interpret::{EvalResult, PrimVal, PrimValKind, Value, Pointer}; @@ -35,7 +35,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: // FIXME: return a real value in case the target allocation has an // alignment bigger than the one requested let n = u128::max_value(); - let amt = 128 - self.memory.pointer_size() * 8; + let amt = 128 - self.memory.pointer_size().bytes() * 8; self.write_primval(dest, PrimVal::Bytes((n << amt) >> amt), dest_layout.ty)?; }, @@ -225,7 +225,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: elem_align, dest, elem_align, - count * elem_size, + Size::from_bytes(count * elem_size), intrinsic_name.ends_with("_nonoverlapping"), )?; } @@ -332,7 +332,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: "likely" | "unlikely" | "forget" => {} "init" => { - let size = dest_layout.size.bytes(); + let size = dest_layout.size; let init = |this: &mut Self, val: Value| { let zero_val = match val { Value::ByRef(ptr, _) => { @@ -631,7 +631,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: } "uninit" => { - let size = dest_layout.size.bytes(); + let size = dest_layout.size; let uninit = |this: &mut Self, val: Value| match val { Value::ByRef(ptr, _) => { this.memory.mark_definedness(ptr, size, false)?; @@ -662,7 +662,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: // HashMap relies on write_bytes on a NULL ptr with count == 0 to work // TODO: Should we, at least, validate the alignment? (Also see the copy intrinsic) self.memory.check_align(ptr, ty_layout.align)?; - self.memory.write_repeat(ptr, val_byte, ty_layout.size.bytes() * count)?; + self.memory.write_repeat(ptr, val_byte, ty_layout.size * count)?; } } diff --git a/src/lib.rs b/src/lib.rs index dce31c4ed3383..66ad6377e3279 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -20,7 +20,7 @@ extern crate regex; extern crate lazy_static; use rustc::ty::{self, TyCtxt}; -use rustc::ty::layout::{TyLayout, LayoutOf}; +use rustc::ty::layout::{TyLayout, LayoutOf, Size}; use rustc::ty::subst::Subst; use rustc::hir::def_id::DefId; use rustc::mir; @@ -93,7 +93,7 @@ pub fn eval_main<'a, 'tcx: 'a>( } // Return value - let size = ecx.tcx.data_layout.pointer_size.bytes(); + let size = ecx.tcx.data_layout.pointer_size; let align = ecx.tcx.data_layout.pointer_align; let ret_ptr = ecx.memory_mut().allocate(size, align, Some(MemoryKind::Stack))?; cleanup_ptr = Some(ret_ptr); @@ -299,7 +299,7 @@ impl<'mir, 'tcx: 'mir> Machine<'mir, 'tcx> for Evaluator<'tcx> { let layout = ecx.layout_of(mir.return_ty().subst(tcx, cid.instance.substs))?; assert!(!layout.is_unsized()); let ptr = ecx.memory.allocate( - layout.size.bytes(), + layout.size, layout.align, None, )?; @@ -373,8 +373,8 @@ impl<'mir, 'tcx: 'mir> Machine<'mir, 'tcx> for Evaluator<'tcx> { ecx.write_value( ValTy { value: Value::ByVal(PrimVal::Bytes(match layout.size.bytes() { - 0 => 1, - size => size, + 0 => 1 as u128, + size => size as u128, }.into())), ty: usize, }, @@ -407,10 +407,10 @@ impl<'mir, 'tcx: 'mir> Machine<'mir, 'tcx> for Evaluator<'tcx> { fn check_locks<'a>( mem: &Memory<'a, 'mir, 'tcx, Self>, ptr: MemoryPointer, - size: u64, + size: Size, access: AccessKind, ) -> EvalResult<'tcx> { - mem.check_locks(ptr, size, access) + mem.check_locks(ptr, size.bytes(), access) } fn add_lock<'a>( @@ -439,7 +439,7 @@ impl<'mir, 'tcx: 'mir> Machine<'mir, 'tcx> for Evaluator<'tcx> { //ptr, FIXME ptr: MemoryPointer { alloc_id: AllocId(0), - offset: 0, + offset: Size::from_bytes(0), }, lock: lock.active, }.into() diff --git a/src/locks.rs b/src/locks.rs index 677b0454a546c..9efbabc7171b3 100644 --- a/src/locks.rs +++ b/src/locks.rs @@ -1,5 +1,6 @@ use super::*; use rustc::middle::region; +use rustc::ty::layout::Size; //////////////////////////////////////////////////////////////////////////////// // Locks @@ -116,7 +117,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> MemoryExt<'tcx> for Memory<'a, 'mir, 'tcx, Evalu }; let frame = self.cur_frame; locks - .check(Some(frame), ptr.offset, len, access) + .check(Some(frame), ptr.offset.bytes(), len, access) .map_err(|lock| { EvalErrorKind::MemoryLockViolation { ptr, @@ -146,7 +147,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> MemoryExt<'tcx> for Memory<'a, 'mir, 'tcx, Evalu len, region ); - self.check_bounds(ptr.offset(len, &*self)?, true)?; // if ptr.offset is in bounds, then so is ptr (because offset checks for overflow) + self.check_bounds(ptr.offset(Size::from_bytes(len), &*self)?, true)?; // if ptr.offset is in bounds, then so is ptr (because offset checks for overflow) let locks = match self.data.locks.get_mut(&ptr.alloc_id) { Some(locks) => locks, @@ -157,7 +158,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> MemoryExt<'tcx> for Memory<'a, 'mir, 'tcx, Evalu // Iterate over our range and acquire the lock. If the range is already split into pieces, // we have to manipulate all of them. let lifetime = DynamicLifetime { frame, region }; - for lock in locks.iter_mut(ptr.offset, len) { + for lock in locks.iter_mut(ptr.offset.bytes(), len) { if !lock.access_permitted(None, kind) { return err!(MemoryAcquireConflict { ptr, @@ -203,7 +204,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> MemoryExt<'tcx> for Memory<'a, 'mir, 'tcx, Evalu None => return Ok(()), }; - 'locks: for lock in locks.iter_mut(ptr.offset, len) { + 'locks: for lock in locks.iter_mut(ptr.offset.bytes(), len) { let is_our_lock = match lock.active { WriteLock(lft) => // Double-check that we are holding the lock. @@ -281,7 +282,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> MemoryExt<'tcx> for Memory<'a, 'mir, 'tcx, Evalu None => return Ok(()), }; - for lock in locks.iter_mut(ptr.offset, len) { + for lock in locks.iter_mut(ptr.offset.bytes(), len) { // Check if we have a suspension here let (got_the_lock, remove_suspension) = match lock.suspended.get_mut(&lock_id) { None => { diff --git a/src/operator.rs b/src/operator.rs index 220f8f9acd541..557e07975d73b 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -89,9 +89,9 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: Sub => { return self.binary_op( Sub, - PrimVal::Bytes(left.offset as u128), + PrimVal::Bytes(left.offset.bytes() as u128), self.tcx.types.usize, - PrimVal::Bytes(right.offset as u128), + PrimVal::Bytes(right.offset.bytes() as u128), self.tcx.types.usize, ).map(Some) } @@ -150,17 +150,17 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: Add if signed => map_to_primval(left.overflowing_signed_offset(right, self)), Add if !signed => - map_to_primval(left.overflowing_offset(right as u64, self)), + map_to_primval(left.overflowing_offset(Size::from_bytes(right as u64), self)), BitAnd if !signed => { let base_mask : u64 = !(self.memory.get(left.alloc_id)?.align.abi() - 1); let right = right as u64; if right & base_mask == base_mask { // Case 1: The base address bits are all preserved, i.e., right is all-1 there - (PrimVal::Ptr(MemoryPointer::new(left.alloc_id, left.offset & right)), false) + (PrimVal::Ptr(MemoryPointer::new(left.alloc_id, Size::from_bytes(left.offset.bytes() & right))), false) } else if right & base_mask == 0 { // Case 2: The base address bits are all taken away, i.e., right is all-0 there - (PrimVal::from_u128((left.offset & right) as u128), false) + (PrimVal::from_u128((left.offset.bytes() & right) as u128), false) } else { return err!(ReadPointerAsBytes); } From 850841e9ed18b111f9574224d28f7643c1b037c2 Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Fri, 25 May 2018 14:37:12 +0200 Subject: [PATCH 0073/3747] s/allocate_cached/allocate_bytes --- src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 66ad6377e3279..f8119245b484c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -131,7 +131,7 @@ pub fn eval_main<'a, 'tcx: 'a>( // Third argument (argv): &[b"foo"] let dest = ecx.eval_place(&mir::Place::Local(args.next().unwrap()))?; let ty = ecx.tcx.mk_imm_ptr(ecx.tcx.mk_imm_ptr(ecx.tcx.types.u8)); - let foo = ecx.memory.allocate_cached(b"foo\0"); + let foo = ecx.memory.allocate_bytes(b"foo\0"); let ptr_size = ecx.memory.pointer_size(); let ptr_align = ecx.tcx.data_layout.pointer_align; let foo_ptr = ecx.memory.allocate(ptr_size, ptr_align, None)?; From 49ca1746482e3c8221d8e8c7161b7d92ae076c8f Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Sat, 26 May 2018 17:07:34 +0200 Subject: [PATCH 0074/3747] Partial rustup --- benches/helpers/miri_helper.rs | 9 +- src/fn_call.rs | 114 +++++++++--------- src/helpers.rs | 34 +++--- src/intrinsic.rs | 206 +++++++++++++++++---------------- src/lib.rs | 104 ++++++++++++++--- src/locks.rs | 16 +-- src/operator.rs | 101 +++++++++------- src/tls.rs | 24 ++-- src/validation.rs | 6 +- 9 files changed, 358 insertions(+), 256 deletions(-) diff --git a/benches/helpers/miri_helper.rs b/benches/helpers/miri_helper.rs index 6657ba1199765..2bf78b0a71cc1 100644 --- a/benches/helpers/miri_helper.rs +++ b/benches/helpers/miri_helper.rs @@ -55,16 +55,13 @@ impl<'a> CompilerCalls<'a> for MiriCompilerCalls<'a> { state.session.abort_if_errors(); let tcx = state.tcx.unwrap(); - let (entry_node_id, _) = state.session.entry_fn.borrow().expect( + let (entry_node_id, _, _) = state.session.entry_fn.borrow().expect( "no main or start function found", ); - let entry_def_id = tcx.map.local_def_id(entry_node_id); + let entry_def_id = tcx.hir.local_def_id(entry_node_id); - let memory_size = 100 * 1024 * 1024; // 100MB - let step_limit = 1000_000; - let stack_limit = 100; bencher.borrow_mut().iter(|| { - eval_main(tcx, entry_def_id, memory_size, step_limit, stack_limit); + eval_main(tcx, entry_def_id, None); }); state.session.abort_if_errors(); diff --git a/src/fn_call.rs b/src/fn_call.rs index e7250eca949d1..ea0c5eb8b26e9 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -38,7 +38,7 @@ fn write_discriminant_value<'a, 'mir, 'tcx: 'a + 'mir>( .val; let (discr_dest, discr) = ecx.place_field(dest, mir::Field::new(0), layout)?; - ecx.write_primval(discr_dest, PrimVal::Bytes(discr_val), discr.ty)?; + ecx.write_scalar(discr_dest, Scalar::from_u128(discr_val), discr.ty)?; } layout::Variants::NicheFilling { dataful_variant, @@ -51,7 +51,7 @@ fn write_discriminant_value<'a, 'mir, 'tcx: 'a + 'mir>( ecx.place_field(dest, mir::Field::new(0), layout)?; let niche_value = ((variant_index - niche_variants.start()) as u128) .wrapping_add(niche_start); - ecx.write_primval(niche_dest, PrimVal::Bytes(niche_value), niche.ty)?; + ecx.write_scalar(niche_dest, Scalar::from_u128(niche_value), niche.ty)?; } } } @@ -182,13 +182,13 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' match &link_name[..] { "malloc" => { - let size = self.value_to_primval(args[0])?.to_u64()?; + let size = self.value_to_scalar(args[0])?.to_u64()?; if size == 0 { self.write_null(dest, dest_ty)?; } else { let align = self.tcx.data_layout.pointer_align; let ptr = self.memory.allocate(Size::from_bytes(size), align, Some(MemoryKind::C.into()))?; - self.write_primval(dest, PrimVal::Ptr(ptr), dest_ty)?; + self.write_scalar(dest, Scalar::Ptr(ptr), dest_ty)?; } } @@ -209,7 +209,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' // // libc::syscall(NR_GETRANDOM, buf.as_mut_ptr(), buf.len(), GRND_NONBLOCK) // is called if a `HashMap` is created the regular way. - match self.value_to_primval(args[0])?.to_u64()? { + match self.value_to_scalar(args[0])?.to_u64()? { 318 | 511 => { return err!(Unimplemented( "miri does not support random number generators".to_owned(), @@ -281,7 +281,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' "memcmp" => { let left = self.into_ptr(args[0].value)?; let right = self.into_ptr(args[1].value)?; - let n = Size::from_bytes(self.value_to_primval(args[2])?.to_u64()?); + let n = Size::from_bytes(self.value_to_scalar(args[2])?.to_u64()?); let result = { let left_bytes = self.memory.read_bytes(left, n)?; @@ -295,22 +295,22 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' } }; - self.write_primval( + self.write_scalar( dest, - PrimVal::Bytes(result as u128), + Scalar::from_i8(result), dest_ty, )?; } "memrchr" => { let ptr = self.into_ptr(args[0].value)?; - let val = self.value_to_primval(args[1])?.to_u64()? as u8; - let num = self.value_to_primval(args[2])?.to_u64()?; + let val = self.value_to_scalar(args[1])?.to_u64()? as u8; + let num = self.value_to_scalar(args[2])?.to_u64()?; if let Some(idx) = self.memory.read_bytes(ptr, Size::from_bytes(num))?.iter().rev().position( |&c| c == val, ) { - let new_ptr = ptr.offset(Size::from_bytes(num - idx as u64 - 1), &self)?; + let new_ptr = ptr.ptr_offset(Size::from_bytes(num - idx as u64 - 1), &self)?; self.write_ptr(dest, new_ptr, dest_ty)?; } else { self.write_null(dest, dest_ty)?; @@ -319,13 +319,13 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' "memchr" => { let ptr = self.into_ptr(args[0].value)?; - let val = self.value_to_primval(args[1])?.to_u64()? as u8; - let num = self.value_to_primval(args[2])?.to_u64()?; + let val = self.value_to_scalar(args[1])?.to_u64()? as u8; + let num = self.value_to_scalar(args[2])?.to_u64()?; if let Some(idx) = self.memory.read_bytes(ptr, Size::from_bytes(num))?.iter().position( |&c| c == val, ) { - let new_ptr = ptr.offset(Size::from_bytes(idx as u64), &self)?; + let new_ptr = ptr.ptr_offset(Size::from_bytes(idx as u64), &self)?; self.write_ptr(dest, new_ptr, dest_ty)?; } else { self.write_null(dest, dest_ty)?; @@ -337,11 +337,11 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' let name_ptr = self.into_ptr(args[0].value)?.to_ptr()?; let name = self.memory.read_c_str(name_ptr)?; match self.machine.env_vars.get(name) { - Some(&var) => PrimVal::Ptr(var), - None => PrimVal::Bytes(0), + Some(&var) => Scalar::Ptr(var), + None => Scalar::null(), } }; - self.write_primval(dest, result, dest_ty)?; + self.write_scalar(dest, result, dest_ty)?; } "unsetenv" => { @@ -361,7 +361,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' } self.write_null(dest, dest_ty)?; } else { - self.write_primval(dest, PrimVal::from_i128(-1), dest_ty)?; + self.write_scalar(dest, Scalar::from_i128(-1), dest_ty)?; } } @@ -397,14 +397,14 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' } self.write_null(dest, dest_ty)?; } else { - self.write_primval(dest, PrimVal::from_i128(-1), dest_ty)?; + self.write_scalar(dest, Scalar::from_i128(-1), dest_ty)?; } } "write" => { - let fd = self.value_to_primval(args[0])?.to_u64()?; + let fd = self.value_to_scalar(args[0])?.to_u64()?; let buf = self.into_ptr(args[1].value)?; - let n = self.value_to_primval(args[2])?.to_u64()?; + let n = self.value_to_scalar(args[2])?.to_u64()?; trace!("Called write({:?}, {:?}, {:?})", fd, buf, n); let result = if fd == 1 || fd == 2 { // stdout/stderr @@ -417,16 +417,17 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' io::stderr().write(buf_cont) }; match res { - Ok(n) => n as isize, + Ok(n) => n as i64, Err(_) => -1, } } else { warn!("Ignored output to FD {}", fd); - n as isize // pretend it all went well + n as i64 // pretend it all went well }; // now result is the value we return back to the program - self.write_primval( + let ptr_size = self.memory.pointer_size(); + self.write_scalar( dest, - PrimVal::Bytes(result as u128), + Scalar::from_isize(result, ptr_size), dest_ty, )?; } @@ -434,22 +435,23 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' "strlen" => { let ptr = self.into_ptr(args[0].value)?.to_ptr()?; let n = self.memory.read_c_str(ptr)?.len(); - self.write_primval(dest, PrimVal::Bytes(n as u128), dest_ty)?; + let ptr_size = self.memory.pointer_size(); + self.write_scalar(dest, Scalar::from_usize(n as u64, ptr_size), dest_ty)?; } // Some things needed for sys::thread initialization to go through "signal" | "sigaction" | "sigaltstack" => { - self.write_primval(dest, PrimVal::Bytes(0), dest_ty)?; + self.write_scalar(dest, Scalar::null(), dest_ty)?; } "sysconf" => { - let name = self.value_to_primval(args[0])?.to_u64()?; + let name = self.value_to_scalar(args[0])?.to_u64()?; trace!("sysconf() called with name {}", name); // cache the sysconf integers via miri's global cache let paths = &[ - (&["libc", "_SC_PAGESIZE"], PrimVal::Bytes(4096)), - (&["libc", "_SC_GETPW_R_SIZE_MAX"], PrimVal::from_i128(-1)), + (&["libc", "_SC_PAGESIZE"], Scalar::from_i128(4096)), + (&["libc", "_SC_GETPW_R_SIZE_MAX"], Scalar::from_i128(-1)), ]; let mut result = None; for &(path, path_value) in paths { @@ -467,7 +469,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' } } if let Some(result) = result { - self.write_primval(dest, result, dest_ty)?; + self.write_scalar(dest, result, dest_ty)?; } else { return err!(Unimplemented( format!("Unimplemented sysconf name: {}", name), @@ -481,11 +483,11 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' let key_align = self.layout_of(args[0].ty)?.align; // Extract the function type out of the signature (that seems easier than constructing it ourselves...) - let dtor = match self.into_ptr(args[1].value)?.into_inner_primval() { - PrimVal::Ptr(dtor_ptr) => Some(self.memory.get_fn(dtor_ptr)?), - PrimVal::Bytes(0) => None, - PrimVal::Bytes(_) => return err!(ReadBytesAsPointer), - PrimVal::Undef => return err!(ReadUndefBytes), + let dtor = match self.into_ptr(args[1].value)? { + Scalar::Ptr(dtor_ptr) => Some(self.memory.get_fn(dtor_ptr)?), + Scalar::Bits { defined: 0, .. } => return err!(ReadUndefBytes), + Scalar::Bits { bits: 0, .. } => None, + Scalar::Bits { .. } => return err!(ReadBytesAsPointer), }; // Figure out how large a pthread TLS key actually is. This is libc::pthread_key_t. @@ -498,10 +500,10 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' if key_size.bits() < 128 && key >= (1u128 << key_size.bits() as u128) { return err!(OutOfTls); } - self.memory.write_primval( + self.memory.write_scalar( key_ptr, key_align, - PrimVal::Bytes(key), + Scalar::from_u128(key), key_size, false, )?; @@ -511,20 +513,20 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' } "pthread_key_delete" => { // The conversion into TlsKey here is a little fishy, but should work as long as usize >= libc::pthread_key_t - let key = self.value_to_primval(args[0])?.to_u64()? as TlsKey; + let key = self.value_to_scalar(args[0])?.to_u64()? as TlsKey; self.memory.delete_tls_key(key)?; // Return success (0) self.write_null(dest, dest_ty)?; } "pthread_getspecific" => { // The conversion into TlsKey here is a little fishy, but should work as long as usize >= libc::pthread_key_t - let key = self.value_to_primval(args[0])?.to_u64()? as TlsKey; + let key = self.value_to_scalar(args[0])?.to_u64()? as TlsKey; let ptr = self.memory.load_tls(key)?; self.write_ptr(dest, ptr, dest_ty)?; } "pthread_setspecific" => { // The conversion into TlsKey here is a little fishy, but should work as long as usize >= libc::pthread_key_t - let key = self.value_to_primval(args[0])?.to_u64()? as TlsKey; + let key = self.value_to_scalar(args[0])?.to_u64()? as TlsKey; let new_ptr = self.into_ptr(args[1].value)?; self.memory.store_tls(key, new_ptr)?; @@ -635,8 +637,8 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' match &path[..] { // Allocators are magic. They have no MIR, even when the rest of libstd does. "alloc::alloc::::__rust_alloc" => { - let size = self.value_to_primval(args[0])?.to_u64()?; - let align = self.value_to_primval(args[1])?.to_u64()?; + let size = self.value_to_scalar(args[0])?.to_u64()?; + let align = self.value_to_scalar(args[1])?.to_u64()?; if size == 0 { return err!(HeapAllocZeroBytes); } @@ -646,11 +648,11 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' let ptr = self.memory.allocate(Size::from_bytes(size), Align::from_bytes(align, align).unwrap(), Some(MemoryKind::Rust.into()))?; - self.write_primval(dest, PrimVal::Ptr(ptr), dest_ty)?; + self.write_scalar(dest, Scalar::Ptr(ptr), dest_ty)?; } "alloc::alloc::::__rust_alloc_zeroed" => { - let size = self.value_to_primval(args[0])?.to_u64()?; - let align = self.value_to_primval(args[1])?.to_u64()?; + let size = self.value_to_scalar(args[0])?.to_u64()?; + let align = self.value_to_scalar(args[1])?.to_u64()?; if size == 0 { return err!(HeapAllocZeroBytes); } @@ -661,12 +663,12 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' Align::from_bytes(align, align).unwrap(), Some(MemoryKind::Rust.into()))?; self.memory.write_repeat(ptr.into(), 0, Size::from_bytes(size))?; - self.write_primval(dest, PrimVal::Ptr(ptr), dest_ty)?; + self.write_scalar(dest, Scalar::Ptr(ptr), dest_ty)?; } "alloc::alloc::::__rust_dealloc" => { let ptr = self.into_ptr(args[0].value)?.to_ptr()?; - let old_size = self.value_to_primval(args[1])?.to_u64()?; - let align = self.value_to_primval(args[2])?.to_u64()?; + let old_size = self.value_to_scalar(args[1])?.to_u64()?; + let align = self.value_to_scalar(args[2])?.to_u64()?; if old_size == 0 { return err!(HeapAllocZeroBytes); } @@ -681,9 +683,9 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' } "alloc::alloc::::__rust_realloc" => { let ptr = self.into_ptr(args[0].value)?.to_ptr()?; - let old_size = self.value_to_primval(args[1])?.to_u64()?; - let align = self.value_to_primval(args[2])?.to_u64()?; - let new_size = self.value_to_primval(args[3])?.to_u64()?; + let old_size = self.value_to_scalar(args[1])?.to_u64()?; + let align = self.value_to_scalar(args[2])?.to_u64()?; + let new_size = self.value_to_scalar(args[3])?.to_u64()?; if old_size == 0 || new_size == 0 { return err!(HeapAllocZeroBytes); } @@ -698,7 +700,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' Align::from_bytes(align, align).unwrap(), MemoryKind::Rust.into(), )?; - self.write_primval(dest, PrimVal::Ptr(new_ptr), dest_ty)?; + self.write_scalar(dest, Scalar::Ptr(new_ptr), dest_ty)?; } // A Rust function is missing, which means we are running with MIR missing for libstd (or other dependencies). @@ -720,13 +722,13 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' "std::rt::panicking" => { // we abort on panic -> `std::rt::panicking` always returns false let bool = self.tcx.types.bool; - self.write_primval(dest, PrimVal::from_bool(false), bool)?; + self.write_scalar(dest, Scalar::from_bool(false), bool)?; } "std::sys::imp::c::::AddVectoredExceptionHandler" | "std::sys::imp::c::::SetThreadStackGuarantee" => { let usize = self.tcx.types.usize; // any non zero value works for the stdlib. This is just used for stackoverflows anyway - self.write_primval(dest, PrimVal::Bytes(1), usize)?; + self.write_scalar(dest, Scalar::from_u128(1), usize)?; }, _ => return err!(NoMirFor(path)), } @@ -740,6 +742,6 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' } fn write_null(&mut self, dest: Place, dest_ty: Ty<'tcx>) -> EvalResult<'tcx> { - self.write_primval(dest, PrimVal::Bytes(0), dest_ty) + self.write_scalar(dest, Scalar::null(), dest_ty) } } diff --git a/src/helpers.rs b/src/helpers.rs index a7b94a656da4a..d881d5c271104 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -1,24 +1,24 @@ use mir; use rustc::ty::Ty; -use rustc::ty::layout::LayoutOf; +use rustc::ty::layout::{LayoutOf, Size}; -use super::{Pointer, EvalResult, PrimVal, EvalContext, ValTy}; +use super::{Scalar, ScalarExt, EvalResult, EvalContext, ValTy}; use rustc_mir::interpret::sign_extend; pub trait EvalContextExt<'tcx> { fn wrapping_pointer_offset( &self, - ptr: Pointer, + ptr: Scalar, pointee_ty: Ty<'tcx>, offset: i64, - ) -> EvalResult<'tcx, Pointer>; + ) -> EvalResult<'tcx, Scalar>; fn pointer_offset( &self, - ptr: Pointer, + ptr: Scalar, pointee_ty: Ty<'tcx>, offset: i64, - ) -> EvalResult<'tcx, Pointer>; + ) -> EvalResult<'tcx, Scalar>; fn value_to_isize( &self, @@ -44,22 +44,22 @@ pub trait EvalContextExt<'tcx> { impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super::Evaluator<'tcx>> { fn wrapping_pointer_offset( &self, - ptr: Pointer, + ptr: Scalar, pointee_ty: Ty<'tcx>, offset: i64, - ) -> EvalResult<'tcx, Pointer> { + ) -> EvalResult<'tcx, Scalar> { // FIXME: assuming here that type size is < i64::max_value() let pointee_size = self.layout_of(pointee_ty)?.size.bytes() as i64; let offset = offset.overflowing_mul(pointee_size).0; - ptr.wrapping_signed_offset(offset, self) + ptr.ptr_wrapping_signed_offset(offset, self) } fn pointer_offset( &self, - ptr: Pointer, + ptr: Scalar, pointee_ty: Ty<'tcx>, offset: i64, - ) -> EvalResult<'tcx, Pointer> { + ) -> EvalResult<'tcx, Scalar> { // This function raises an error if the offset moves the pointer outside of its allocation. We consider // ZSTs their own huge allocation that doesn't overlap with anything (and nothing moves in there because the size is 0). // We also consider the NULL pointer its own separate allocation, and all the remaining integers pointers their own @@ -76,9 +76,9 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: // FIXME: assuming here that type size is < i64::max_value() let pointee_size = self.layout_of(pointee_ty)?.size.bytes() as i64; return if let Some(offset) = offset.checked_mul(pointee_size) { - let ptr = ptr.signed_offset(offset, self)?; + let ptr = ptr.ptr_signed_offset(offset, self)?; // Do not do bounds-checking for integers; they can never alias a normal pointer anyway. - if let PrimVal::Ptr(ptr) = ptr.into_inner_primval() { + if let Scalar::Ptr(ptr) = ptr { self.memory.check_bounds(ptr, false)?; } else if ptr.is_null()? { // We moved *to* a NULL pointer. That seems wrong, LLVM considers the NULL pointer its own small allocation. Reject this, for now. @@ -95,7 +95,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: value: ValTy<'tcx>, ) -> EvalResult<'tcx, i64> { assert_eq!(value.ty, self.tcx.types.isize); - let raw = self.value_to_primval(value)?.to_bytes()?; + let raw = self.value_to_scalar(value)?.to_bits(self.memory.pointer_size())?; let raw = sign_extend(self.tcx.tcx, raw, self.tcx.types.isize)?; Ok(raw as i64) } @@ -105,7 +105,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: value: ValTy<'tcx>, ) -> EvalResult<'tcx, u64> { assert_eq!(value.ty, self.tcx.types.usize); - self.value_to_primval(value)?.to_bytes().map(|v| v as u64) + self.value_to_scalar(value)?.to_bits(self.memory.pointer_size()).map(|v| v as u64) } fn value_to_i32( @@ -113,7 +113,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: value: ValTy<'tcx>, ) -> EvalResult<'tcx, i32> { assert_eq!(value.ty, self.tcx.types.i32); - let raw = self.value_to_primval(value)?.to_bytes()?; + let raw = self.value_to_scalar(value)?.to_bits(Size::from_bits(32))?; let raw = sign_extend(self.tcx.tcx, raw, self.tcx.types.i32)?; Ok(raw as i32) } @@ -123,6 +123,6 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: value: ValTy<'tcx>, ) -> EvalResult<'tcx, u8> { assert_eq!(value.ty, self.tcx.types.u8); - self.value_to_primval(value)?.to_bytes().map(|v| v as u8) + self.value_to_scalar(value)?.to_bits(Size::from_bits(8)).map(|v| v as u8) } } diff --git a/src/intrinsic.rs b/src/intrinsic.rs index 30de1c68ca618..3d537ea629c3b 100644 --- a/src/intrinsic.rs +++ b/src/intrinsic.rs @@ -1,12 +1,14 @@ use rustc::mir; -use rustc::ty::layout::{TyLayout, LayoutOf, Size}; +use rustc::ty::layout::{TyLayout, LayoutOf, Size, Primitive, Integer::*}; use rustc::ty; -use rustc::mir::interpret::{EvalResult, PrimVal, PrimValKind, Value, Pointer}; +use rustc::mir::interpret::{EvalResult, Scalar, Value}; use rustc_mir::interpret::{Place, PlaceExtra, HasMemory, EvalContext, ValTy}; use helpers::EvalContextExt as HelperEvalContextExt; +use super::ScalarExt; + pub trait EvalContextExt<'tcx> { fn call_intrinsic( &mut self, @@ -36,7 +38,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: // alignment bigger than the one requested let n = u128::max_value(); let amt = 128 - self.memory.pointer_size().bytes() * 8; - self.write_primval(dest, PrimVal::Bytes((n << amt) >> amt), dest_layout.ty)?; + self.write_scalar(dest, Scalar::from_u128((n << amt) >> amt), dest_layout.ty)?; }, "add_with_overflow" => { @@ -77,7 +79,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: } "assume" => { - let cond = self.value_to_primval(args[0])?.to_bool()?; + let cond = self.value_to_scalar(args[0])?.to_bool()?; if !cond { return err!(AssumptionNotHeld); } @@ -115,16 +117,16 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: let ty = substs.type_at(0); let align = self.layout_of(ty)?.align; let ptr = self.into_ptr(args[0].value)?; - let change = self.value_to_primval(args[1])?; + let change = self.value_to_scalar(args[1])?; let old = self.read_value(ptr, align, ty)?; let old = match old { - Value::ByVal(val) => val, + Value::Scalar(val) => val, Value::ByRef { .. } => bug!("just read the value, can't be byref"), - Value::ByValPair(..) => bug!("atomic_xchg doesn't work with nonprimitives"), + Value::ScalarPair(..) => bug!("atomic_xchg doesn't work with nonprimitives"), }; - self.write_primval(dest, old, ty)?; - self.write_primval( - Place::from_primval_ptr(ptr, align), + self.write_scalar(dest, old, ty)?; + self.write_scalar( + Place::from_scalar_ptr(ptr, align), change, ty, )?; @@ -134,22 +136,22 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: let ty = substs.type_at(0); let align = self.layout_of(ty)?.align; let ptr = self.into_ptr(args[0].value)?; - let expect_old = self.value_to_primval(args[1])?; - let change = self.value_to_primval(args[2])?; + let expect_old = self.value_to_scalar(args[1])?; + let change = self.value_to_scalar(args[2])?; let old = self.read_value(ptr, align, ty)?; let old = match old { - Value::ByVal(val) => val, + Value::Scalar(val) => val, Value::ByRef { .. } => bug!("just read the value, can't be byref"), - Value::ByValPair(..) => bug!("atomic_cxchg doesn't work with nonprimitives"), + Value::ScalarPair(..) => bug!("atomic_cxchg doesn't work with nonprimitives"), }; let (val, _) = self.binary_op(mir::BinOp::Eq, old, ty, expect_old, ty)?; let valty = ValTy { - value: Value::ByValPair(old, val), + value: Value::ScalarPair(old, val), ty: dest_layout.ty, }; self.write_value(valty, dest)?; - self.write_primval( - Place::from_primval_ptr(ptr, dest_layout.align), + self.write_scalar( + Place::from_scalar_ptr(ptr, dest_layout.align), change, ty, )?; @@ -183,16 +185,16 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: let ty = substs.type_at(0); let align = self.layout_of(ty)?.align; let ptr = self.into_ptr(args[0].value)?; - let change = self.value_to_primval(args[1])?; + let change = self.value_to_scalar(args[1])?; let old = self.read_value(ptr, align, ty)?; let old = match old { - Value::ByVal(val) => val, + Value::Scalar(val) => val, Value::ByRef { .. } => bug!("just read the value, can't be byref"), - Value::ByValPair(..) => { + Value::ScalarPair(..) => { bug!("atomic_xadd_relaxed doesn't work with nonprimitives") } }; - self.write_primval(dest, old, ty)?; + self.write_scalar(dest, old, ty)?; let op = match intrinsic_name.split('_').nth(1).unwrap() { "or" => mir::BinOp::BitOr, "xor" => mir::BinOp::BitXor, @@ -203,7 +205,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: }; // FIXME: what do atomics do on overflow? let (val, _) = self.binary_op(op, old, ty, change, ty)?; - self.write_primval(Place::from_primval_ptr(ptr, dest_layout.align), val, ty)?; + self.write_scalar(Place::from_scalar_ptr(ptr, dest_layout.align), val, ty)?; } "breakpoint" => unimplemented!(), // halt miri @@ -233,8 +235,11 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: "ctpop" | "cttz" | "cttz_nonzero" | "ctlz" | "ctlz_nonzero" | "bswap" => { let ty = substs.type_at(0); - let num = self.value_to_primval(args[0])?.to_bytes()?; - let kind = self.ty_to_primval_kind(ty)?; + let num = self.value_to_scalar(args[0])?.to_bytes()?; + let kind = match self.layout_of(ty)?.abi { + ty::layout::Abi::Scalar(ref scalar) => scalar.value, + _ => Err(::rustc::mir::interpret::EvalErrorKind::TypeNotPrimitive(ty))?, + }; let num = if intrinsic_name.ends_with("_nonzero") { if num == 0 { return err!(Intrinsic(format!("{} called on 0", intrinsic_name))); @@ -243,21 +248,21 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: } else { numeric_intrinsic(intrinsic_name, num, kind)? }; - self.write_primval(dest, num, ty)?; + self.write_scalar(dest, num, ty)?; } "discriminant_value" => { let ty = substs.type_at(0); let adt_ptr = self.into_ptr(args[0].value)?; let adt_align = self.layout_of(args[0].ty)?.align; - let place = Place::from_primval_ptr(adt_ptr, adt_align); + let place = Place::from_scalar_ptr(adt_ptr, adt_align); let discr_val = self.read_discriminant_value(place, ty)?; - self.write_primval(dest, PrimVal::Bytes(discr_val), dest_layout.ty)?; + self.write_scalar(dest, Scalar::from_u128(discr_val), dest_layout.ty)?; } "sinf32" | "fabsf32" | "cosf32" | "sqrtf32" | "expf32" | "exp2f32" | "logf32" | "log10f32" | "log2f32" | "floorf32" | "ceilf32" | "truncf32" => { - let f = self.value_to_primval(args[0])?.to_bytes()?; + let f = self.value_to_scalar(args[0])?.to_bytes()?; let f = f32::from_bits(f as u32); let f = match intrinsic_name { "sinf32" => f.sin(), @@ -274,12 +279,12 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: "truncf32" => f.trunc(), _ => bug!(), }; - self.write_primval(dest, PrimVal::Bytes(f.to_bits() as u128), dest_layout.ty)?; + self.write_scalar(dest, Scalar::from_f32(f), dest_layout.ty)?; } "sinf64" | "fabsf64" | "cosf64" | "sqrtf64" | "expf64" | "exp2f64" | "logf64" | "log10f64" | "log2f64" | "floorf64" | "ceilf64" | "truncf64" => { - let f = self.value_to_primval(args[0])?.to_bytes()?; + let f = self.value_to_scalar(args[0])?.to_bytes()?; let f = f64::from_bits(f as u64); let f = match intrinsic_name { "sinf64" => f.sin(), @@ -296,13 +301,13 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: "truncf64" => f.trunc(), _ => bug!(), }; - self.write_primval(dest, PrimVal::Bytes(f.to_bits() as u128), dest_layout.ty)?; + self.write_scalar(dest, Scalar::from_f64(f), dest_layout.ty)?; } "fadd_fast" | "fsub_fast" | "fmul_fast" | "fdiv_fast" | "frem_fast" => { let ty = substs.type_at(0); - let a = self.value_to_primval(args[0])?; - let b = self.value_to_primval(args[1])?; + let a = self.value_to_scalar(args[0])?; + let b = self.value_to_scalar(args[1])?; let op = match intrinsic_name { "fadd_fast" => mir::BinOp::Add, "fsub_fast" => mir::BinOp::Sub, @@ -312,21 +317,21 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: _ => bug!(), }; let result = self.binary_op(op, a, ty, b, ty)?; - self.write_primval(dest, result.0, dest_layout.ty)?; + self.write_scalar(dest, result.0, dest_layout.ty)?; } "exact_div" => { // Performs an exact division, resulting in undefined behavior where // `x % y != 0` or `y == 0` or `x == T::min_value() && y == -1` let ty = substs.type_at(0); - let a = self.value_to_primval(args[0])?; - let b = self.value_to_primval(args[1])?; + let a = self.value_to_scalar(args[0])?; + let b = self.value_to_scalar(args[1])?; // check x % y != 0 - if self.binary_op(mir::BinOp::Rem, a, ty, b, ty)?.0 != PrimVal::Bytes(0) { + if self.binary_op(mir::BinOp::Rem, a, ty, b, ty)?.0 != Scalar::null() { return err!(ValidationFailure(format!("exact_div: {:?} cannot be divided by {:?}", a, b))); } let result = self.binary_op(mir::BinOp::Div, a, ty, b, ty)?; - self.write_primval(dest, result.0, dest_layout.ty)?; + self.write_scalar(dest, result.0, dest_layout.ty)?; }, "likely" | "unlikely" | "forget" => {} @@ -341,21 +346,21 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: val } // TODO(solson): Revisit this, it's fishy to check for Undef here. - Value::ByVal(PrimVal::Undef) => { - match this.ty_to_primval_kind(dest_layout.ty) { - Ok(_) => Value::ByVal(PrimVal::Bytes(0)), - Err(_) => { + Value::Scalar(Scalar::Bits { defined: 0, .. }) => { + match this.layout_of(dest_layout.ty)?.abi { + ty::layout::Abi::Scalar(_) => Value::Scalar(Scalar::null()), + _ => { // FIXME(oli-obk): pass TyLayout to alloc_ptr instead of Ty let ptr = this.alloc_ptr(dest_layout.ty)?; - let ptr = Pointer::from(PrimVal::Ptr(ptr)); + let ptr = Scalar::Ptr(ptr); this.memory.write_repeat(ptr, 0, size)?; Value::ByRef(ptr, dest_layout.align) } } } - Value::ByVal(_) => Value::ByVal(PrimVal::Bytes(0)), - Value::ByValPair(..) => { - Value::ByValPair(PrimVal::Bytes(0), PrimVal::Bytes(0)) + Value::Scalar(_) => Value::Scalar(Scalar::null()), + Value::ScalarPair(..) => { + Value::ScalarPair(Scalar::null(), Scalar::null()) } }; Ok(zero_val) @@ -376,16 +381,16 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: "min_align_of" => { let elem_ty = substs.type_at(0); let elem_align = self.layout_of(elem_ty)?.align.abi(); - let align_val = PrimVal::from_u128(elem_align as u128); - self.write_primval(dest, align_val, dest_layout.ty)?; + let align_val = Scalar::from_u128(elem_align as u128); + self.write_scalar(dest, align_val, dest_layout.ty)?; } "pref_align_of" => { let ty = substs.type_at(0); let layout = self.layout_of(ty)?; let align = layout.align.pref(); - let align_val = PrimVal::from_u128(align as u128); - self.write_primval(dest, align_val, dest_layout.ty)?; + let align_val = Scalar::from_u128(align as u128); + self.write_scalar(dest, align_val, dest_layout.ty)?; } "move_val_init" => { @@ -399,9 +404,9 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: let ty = substs.type_at(0); let env = ty::ParamEnv::reveal_all(); let needs_drop = ty.needs_drop(self.tcx.tcx, env); - self.write_primval( + self.write_scalar( dest, - PrimVal::from_bool(needs_drop), + Scalar::from_bool(needs_drop), dest_layout.ty, )?; } @@ -444,75 +449,75 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: } "powf32" => { - let f = self.value_to_primval(args[0])?.to_bytes()?; + let f = self.value_to_scalar(args[0])?.to_bits(Size::from_bits(32))?; let f = f32::from_bits(f as u32); - let f2 = self.value_to_primval(args[1])?.to_bytes()?; + let f2 = self.value_to_scalar(args[1])?.to_bits(Size::from_bits(32))?; let f2 = f32::from_bits(f2 as u32); - self.write_primval( + self.write_scalar( dest, - PrimVal::Bytes(f.powf(f2).to_bits() as u128), + Scalar::from_f32(f.powf(f2)), dest_layout.ty, )?; } "powf64" => { - let f = self.value_to_primval(args[0])?.to_bytes()?; + let f = self.value_to_scalar(args[0])?.to_bits(Size::from_bits(64))?; let f = f64::from_bits(f as u64); - let f2 = self.value_to_primval(args[1])?.to_bytes()?; + let f2 = self.value_to_scalar(args[1])?.to_bits(Size::from_bits(64))?; let f2 = f64::from_bits(f2 as u64); - self.write_primval( + self.write_scalar( dest, - PrimVal::Bytes(f.powf(f2).to_bits() as u128), + Scalar::from_f64(f.powf(f2)), dest_layout.ty, )?; } "fmaf32" => { - let a = self.value_to_primval(args[0])?.to_bytes()?; + let a = self.value_to_scalar(args[0])?.to_bits(Size::from_bits(32))?; let a = f32::from_bits(a as u32); - let b = self.value_to_primval(args[1])?.to_bytes()?; + let b = self.value_to_scalar(args[1])?.to_bits(Size::from_bits(32))?; let b = f32::from_bits(b as u32); - let c = self.value_to_primval(args[2])?.to_bytes()?; + let c = self.value_to_scalar(args[2])?.to_bits(Size::from_bits(32))?; let c = f32::from_bits(c as u32); - self.write_primval( + self.write_scalar( dest, - PrimVal::Bytes((a * b + c).to_bits() as u128), + Scalar::from_f32(a * b + c), dest_layout.ty, )?; } "fmaf64" => { - let a = self.value_to_primval(args[0])?.to_bytes()?; + let a = self.value_to_scalar(args[0])?.to_bits(Size::from_bits(64))?; let a = f64::from_bits(a as u64); - let b = self.value_to_primval(args[1])?.to_bytes()?; + let b = self.value_to_scalar(args[1])?.to_bits(Size::from_bits(64))?; let b = f64::from_bits(b as u64); - let c = self.value_to_primval(args[2])?.to_bytes()?; + let c = self.value_to_scalar(args[2])?.to_bits(Size::from_bits(64))?; let c = f64::from_bits(c as u64); - self.write_primval( + self.write_scalar( dest, - PrimVal::Bytes((a * b + c).to_bits() as u128), + Scalar::from_f64(a * b + c), dest_layout.ty, )?; } "powif32" => { - let f = self.value_to_primval(args[0])?.to_bytes()?; + let f = self.value_to_scalar(args[0])?.to_bits(Size::from_bits(32))?; let f = f32::from_bits(f as u32); let i = self.value_to_i32(args[1])?; - self.write_primval( + self.write_scalar( dest, - PrimVal::Bytes(f.powi(i).to_bits() as u128), + Scalar::from_f32(f.powi(i)), dest_layout.ty, )?; } "powif64" => { - let f = self.value_to_primval(args[0])?.to_bytes()?; + let f = self.value_to_scalar(args[0])?.to_bits(Size::from_bits(64))?; let f = f64::from_bits(f as u64); let i = self.value_to_i32(args[1])?; - self.write_primval( + self.write_scalar( dest, - PrimVal::Bytes(f.powi(i).to_bits() as u128), + Scalar::from_f64(f.powi(i)), dest_layout.ty, )?; } @@ -520,15 +525,15 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: "size_of" => { let ty = substs.type_at(0); let size = self.layout_of(ty)?.size.bytes().into(); - self.write_primval(dest, PrimVal::from_u128(size), dest_layout.ty)?; + self.write_scalar(dest, Scalar::from_u128(size), dest_layout.ty)?; } "size_of_val" => { let ty = substs.type_at(0); let (size, _) = self.size_and_align_of_dst(ty, args[0].value)?; - self.write_primval( + self.write_scalar( dest, - PrimVal::from_u128(size.bytes() as u128), + Scalar::from_u128(size.bytes() as u128), dest_layout.ty, )?; } @@ -537,9 +542,9 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: "align_of_val" => { let ty = substs.type_at(0); let (_, align) = self.size_and_align_of_dst(ty, args[0].value)?; - self.write_primval( + self.write_scalar( dest, - PrimVal::from_u128(align.abi() as u128), + Scalar::from_u128(align.abi() as u128), dest_layout.ty, )?; } @@ -553,7 +558,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: "type_id" => { let ty = substs.type_at(0); let n = self.tcx.type_id_hash(ty); - self.write_primval(dest, PrimVal::Bytes(n as u128), dest_layout.ty)?; + self.write_scalar(dest, Scalar::Bits { bits: n as u128, defined: 64 }, dest_layout.ty)?; } "transmute" => { @@ -566,7 +571,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: "unchecked_shl" => { let bits = dest_layout.size.bytes() as u128 * 8; - let rhs = self.value_to_primval(args[1])? + let rhs = self.value_to_scalar(args[1])? .to_bytes()?; if rhs >= bits { return err!(Intrinsic( @@ -584,7 +589,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: "unchecked_shr" => { let bits = dest_layout.size.bytes() as u128 * 8; - let rhs = self.value_to_primval(args[1])? + let rhs = self.value_to_scalar(args[1])? .to_bytes()?; if rhs >= bits { return err!(Intrinsic( @@ -601,7 +606,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: } "unchecked_div" => { - let rhs = self.value_to_primval(args[1])? + let rhs = self.value_to_scalar(args[1])? .to_bytes()?; if rhs == 0 { return err!(Intrinsic(format!("Division by 0 in unchecked_div"))); @@ -616,7 +621,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: } "unchecked_rem" => { - let rhs = self.value_to_primval(args[1])? + let rhs = self.value_to_scalar(args[1])? .to_bytes()?; if rhs == 0 { return err!(Intrinsic(format!("Division by 0 in unchecked_rem"))); @@ -637,7 +642,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: this.memory.mark_definedness(ptr, size, false)?; Ok(val) } - _ => Ok(Value::ByVal(PrimVal::Undef)), + _ => Ok(Value::Scalar(Scalar::undef())), }; match dest { Place::Local { frame, local } => self.modify_local(frame, local, uninit)?, @@ -681,26 +686,25 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: fn numeric_intrinsic<'tcx>( name: &str, bytes: u128, - kind: PrimValKind, -) -> EvalResult<'tcx, PrimVal> { + kind: Primitive, +) -> EvalResult<'tcx, Scalar> { macro_rules! integer_intrinsic { ($method:ident) => ({ - use rustc::mir::interpret::PrimValKind::*; let result_bytes = match kind { - I8 => (bytes as i8).$method() as u128, - U8 => (bytes as u8).$method() as u128, - I16 => (bytes as i16).$method() as u128, - U16 => (bytes as u16).$method() as u128, - I32 => (bytes as i32).$method() as u128, - U32 => (bytes as u32).$method() as u128, - I64 => (bytes as i64).$method() as u128, - U64 => (bytes as u64).$method() as u128, - I128 => (bytes as i128).$method() as u128, - U128 => bytes.$method() as u128, + Primitive::Int(I8, true) => (bytes as i8).$method() as u128, + Primitive::Int(I8, false) => (bytes as u8).$method() as u128, + Primitive::Int(I16, true) => (bytes as i16).$method() as u128, + Primitive::Int(I16, false) => (bytes as u16).$method() as u128, + Primitive::Int(I32, true) => (bytes as i32).$method() as u128, + Primitive::Int(I32, false) => (bytes as u32).$method() as u128, + Primitive::Int(I64, true) => (bytes as i64).$method() as u128, + Primitive::Int(I64, false) => (bytes as u64).$method() as u128, + Primitive::Int(I128, true) => (bytes as i128).$method() as u128, + Primitive::Int(I128, false) => bytes.$method() as u128, _ => bug!("invalid `{}` argument: {:?}", name, bytes), }; - PrimVal::Bytes(result_bytes) + Scalar::from_u128(result_bytes) }); } diff --git a/src/lib.rs b/src/lib.rs index f8119245b484c..e3c83c284db99 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -53,6 +53,81 @@ use validation::EvalContextExt as ValidationEvalContextExt; use range_map::RangeMap; use validation::{ValidationQuery, AbsPlace}; +pub trait ScalarExt { + fn null() -> Self; + fn from_i8(i: i8) -> Self; + fn from_u128(i: u128) -> Self; + fn from_i128(i: i128) -> Self; + fn from_usize(i: u64, ptr_size: Size) -> Self; + fn from_isize(i: i64, ptr_size: Size) -> Self; + fn from_f32(f: f32) -> Self; + fn from_f64(f: f64) -> Self; + fn to_u64(self) -> EvalResult<'static, u64>; + fn is_null(self) -> EvalResult<'static, bool>; + fn to_bytes(self) -> EvalResult<'static, u128>; +} + +impl ScalarExt for Scalar { + fn null() -> Self { + Scalar::Bits { bits: 0, defined: 128 } + } + + fn from_i8(i: i8) -> Self { + Scalar::Bits { bits: i as i128 as u128, defined: 8 } + } + + fn from_u128(i: u128) -> Self { + Scalar::Bits { bits: i, defined: 128 } + } + + fn from_i128(i: i128) -> Self { + Scalar::Bits { bits: i as u128, defined: 128 } + } + + fn from_usize(i: u64, ptr_size: Size) -> Self { + Scalar::Bits { bits: i as u128, defined: ptr_size.bits() as u8 } + } + + fn from_isize(i: i64, ptr_size: Size) -> Self { + Scalar::Bits { bits: i as i128 as u128, defined: ptr_size.bits() as u8 } + } + + fn from_f32(f: f32) -> Self { + Scalar::Bits { bits: f.to_bits() as u128, defined: 32 } + } + + fn from_f64(f: f64) -> Self { + Scalar::Bits { bits: f.to_bits() as u128, defined: 64 } + } + + fn to_u64(self) -> EvalResult<'static, u64> { + let b = self.to_bits(Size::from_bits(64))?; + assert_eq!(b as u64 as u128, b); + Ok(b as u64) + } + + fn is_null(self) -> EvalResult<'static, bool> { + match self { + Scalar::Bits { bits, defined } => { + if defined > 0 { + Ok(bits == 0) + } else { + err!(ReadUndefBytes) + } + } + Scalar::Ptr(_) => Ok(false) + } + } + + fn to_bytes(self) -> EvalResult<'static, u128> { + match self { + Scalar::Bits { defined: 0, .. } => err!(ReadUndefBytes), + Scalar::Bits { bits, .. } => Ok(bits), + Scalar::Ptr(_) => err!(ReadPointerAsBytes), + } + } +} + pub fn eval_main<'a, 'tcx: 'a>( tcx: TyCtxt<'a, 'tcx, 'tcx>, main_id: DefId, @@ -65,7 +140,7 @@ pub fn eval_main<'a, 'tcx: 'a>( ) -> EvalResult<'tcx> { let main_instance = ty::Instance::mono(ecx.tcx.tcx, main_id); let main_mir = ecx.load_mir(main_instance.def)?; - let mut cleanup_ptr = None; // Pointer to be deallocated when we are done + let mut cleanup_ptr = None; // Scalar to be deallocated when we are done if !main_mir.return_ty().is_nil() || main_mir.arg_count != 0 { return err!(Unimplemented( @@ -116,7 +191,7 @@ pub fn eval_main<'a, 'tcx: 'a>( let main_ptr_ty = ecx.tcx.mk_fn_ptr(main_ty.fn_sig(ecx.tcx.tcx)); ecx.write_value( ValTy { - value: Value::ByVal(PrimVal::Ptr(main_ptr)), + value: Value::Scalar(Scalar::Ptr(main_ptr)), ty: main_ptr_ty, }, dest, @@ -125,7 +200,7 @@ pub fn eval_main<'a, 'tcx: 'a>( // Second argument (argc): 1 let dest = ecx.eval_place(&mir::Place::Local(args.next().unwrap()))?; let ty = ecx.tcx.types.isize; - ecx.write_primval(dest, PrimVal::Bytes(1), ty)?; + ecx.write_scalar(dest, Scalar::from_u128(1), ty)?; // FIXME: extract main source file path // Third argument (argv): &[b"foo"] @@ -135,7 +210,7 @@ pub fn eval_main<'a, 'tcx: 'a>( let ptr_size = ecx.memory.pointer_size(); let ptr_align = ecx.tcx.data_layout.pointer_align; let foo_ptr = ecx.memory.allocate(ptr_size, ptr_align, None)?; - ecx.memory.write_primval(foo_ptr.into(), ptr_align, PrimVal::Ptr(foo.into()), ptr_size, false)?; + ecx.memory.write_scalar(foo_ptr.into(), ptr_align, Scalar::Ptr(foo), ptr_size, false)?; ecx.memory.mark_static_initialized(foo_ptr.alloc_id, Mutability::Immutable)?; ecx.write_ptr(dest, foo_ptr.into(), ty)?; @@ -145,7 +220,7 @@ pub fn eval_main<'a, 'tcx: 'a>( main_instance, main_mir.span, main_mir, - Place::from_primval_ptr(PrimVal::Bytes(1).into(), ty::layout::Align::from_bytes(1, 1).unwrap()), + Place::from_scalar_ptr(Scalar::from_u128(1), ty::layout::Align::from_bytes(1, 1).unwrap()), StackPopCleanup::None, )?; @@ -187,6 +262,7 @@ pub fn eval_main<'a, 'tcx: 'a>( } } } + ::std::process::exit(1); } } } @@ -195,7 +271,7 @@ pub fn eval_main<'a, 'tcx: 'a>( pub struct Evaluator<'tcx> { /// Environment variables set by `setenv` /// Miri does not expose env vars from the host to the emulated program - pub(crate) env_vars: HashMap, MemoryPointer>, + pub(crate) env_vars: HashMap, Pointer>, /// Places that were suspended by the validation subsystem, and will be recovered later pub(crate) suspended: HashMap>>, @@ -205,7 +281,7 @@ pub type TlsKey = usize; #[derive(Copy, Clone, Debug)] pub struct TlsEntry<'tcx> { - data: Pointer, // Will eventually become a map from thread IDs to `Pointer`s, if we ever support more than one thread. + data: Scalar, // Will eventually become a map from thread IDs to `Scalar`s, if we ever support more than one thread. dtor: Option>, } @@ -256,11 +332,11 @@ impl<'mir, 'tcx: 'mir> Machine<'mir, 'tcx> for Evaluator<'tcx> { fn try_ptr_op<'a>( ecx: &rustc_mir::interpret::EvalContext<'a, 'mir, 'tcx, Self>, bin_op: mir::BinOp, - left: PrimVal, + left: Scalar, left_ty: ty::Ty<'tcx>, - right: PrimVal, + right: Scalar, right_ty: ty::Ty<'tcx>, - ) -> EvalResult<'tcx, Option<(PrimVal, bool)>> { + ) -> EvalResult<'tcx, Option<(Scalar, bool)>> { ecx.ptr_op(bin_op, left, left_ty, right, right_ty) } @@ -372,7 +448,7 @@ impl<'mir, 'tcx: 'mir> Machine<'mir, 'tcx> for Evaluator<'tcx> { let dest = ecx.eval_place(&mir::Place::Local(args.next().unwrap()))?; ecx.write_value( ValTy { - value: Value::ByVal(PrimVal::Bytes(match layout.size.bytes() { + value: Value::Scalar(Scalar::from_u128(match layout.size.bytes() { 0 => 1 as u128, size => size as u128, }.into())), @@ -385,7 +461,7 @@ impl<'mir, 'tcx: 'mir> Machine<'mir, 'tcx> for Evaluator<'tcx> { let dest = ecx.eval_place(&mir::Place::Local(args.next().unwrap()))?; ecx.write_value( ValTy { - value: Value::ByVal(PrimVal::Bytes(layout.align.abi().into())), + value: Value::Scalar(Scalar::from_u128(layout.align.abi().into())), ty: usize, }, dest, @@ -406,7 +482,7 @@ impl<'mir, 'tcx: 'mir> Machine<'mir, 'tcx> for Evaluator<'tcx> { fn check_locks<'a>( mem: &Memory<'a, 'mir, 'tcx, Self>, - ptr: MemoryPointer, + ptr: Pointer, size: Size, access: AccessKind, ) -> EvalResult<'tcx> { @@ -437,7 +513,7 @@ impl<'mir, 'tcx: 'mir> Machine<'mir, 'tcx> for Evaluator<'tcx> { .map_err(|lock| { EvalErrorKind::DeallocatedLockedMemory { //ptr, FIXME - ptr: MemoryPointer { + ptr: Pointer { alloc_id: AllocId(0), offset: Size::from_bytes(0), }, diff --git a/src/locks.rs b/src/locks.rs index 9efbabc7171b3..a463f8ba575e8 100644 --- a/src/locks.rs +++ b/src/locks.rs @@ -70,27 +70,27 @@ impl<'tcx> LockInfo<'tcx> { pub trait MemoryExt<'tcx> { fn check_locks( &self, - ptr: MemoryPointer, + ptr: Pointer, len: u64, access: AccessKind, ) -> EvalResult<'tcx>; fn acquire_lock( &mut self, - ptr: MemoryPointer, + ptr: Pointer, len: u64, region: Option, kind: AccessKind, ) -> EvalResult<'tcx>; fn suspend_write_lock( &mut self, - ptr: MemoryPointer, + ptr: Pointer, len: u64, lock_path: &AbsPlace<'tcx>, suspend: Option, ) -> EvalResult<'tcx>; fn recover_write_lock( &mut self, - ptr: MemoryPointer, + ptr: Pointer, len: u64, lock_path: &AbsPlace<'tcx>, lock_region: Option, @@ -103,7 +103,7 @@ pub trait MemoryExt<'tcx> { impl<'a, 'mir, 'tcx: 'mir + 'a> MemoryExt<'tcx> for Memory<'a, 'mir, 'tcx, Evaluator<'tcx>> { fn check_locks( &self, - ptr: MemoryPointer, + ptr: Pointer, len: u64, access: AccessKind, ) -> EvalResult<'tcx> { @@ -132,7 +132,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> MemoryExt<'tcx> for Memory<'a, 'mir, 'tcx, Evalu /// Acquire the lock for the given lifetime fn acquire_lock( &mut self, - ptr: MemoryPointer, + ptr: Pointer, len: u64, region: Option, kind: AccessKind, @@ -191,7 +191,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> MemoryExt<'tcx> for Memory<'a, 'mir, 'tcx, Evalu /// When suspending, the same cases are fine; we just register an additional suspension. fn suspend_write_lock( &mut self, - ptr: MemoryPointer, + ptr: Pointer, len: u64, lock_path: &AbsPlace<'tcx>, suspend: Option, @@ -264,7 +264,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> MemoryExt<'tcx> for Memory<'a, 'mir, 'tcx, Evalu /// Release a suspension from the write lock. If this is the last suspension or if there is no suspension, acquire the lock. fn recover_write_lock( &mut self, - ptr: MemoryPointer, + ptr: Pointer, len: u64, lock_path: &AbsPlace<'tcx>, lock_region: Option, diff --git a/src/operator.rs b/src/operator.rs index 557e07975d73b..721b4f0bfddab 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -1,4 +1,5 @@ use rustc::ty; +use rustc::ty::layout::Primitive; use rustc::mir; use super::*; @@ -9,38 +10,58 @@ pub trait EvalContextExt<'tcx> { fn ptr_op( &self, bin_op: mir::BinOp, - left: PrimVal, + left: Scalar, left_ty: ty::Ty<'tcx>, - right: PrimVal, + right: Scalar, right_ty: ty::Ty<'tcx>, - ) -> EvalResult<'tcx, Option<(PrimVal, bool)>>; + ) -> EvalResult<'tcx, Option<(Scalar, bool)>>; fn ptr_int_arithmetic( &self, bin_op: mir::BinOp, - left: MemoryPointer, + left: Pointer, right: i128, signed: bool, - ) -> EvalResult<'tcx, (PrimVal, bool)>; + ) -> EvalResult<'tcx, (Scalar, bool)>; } impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super::Evaluator<'tcx>> { fn ptr_op( &self, bin_op: mir::BinOp, - left: PrimVal, + left: Scalar, left_ty: ty::Ty<'tcx>, - right: PrimVal, + right: Scalar, right_ty: ty::Ty<'tcx>, - ) -> EvalResult<'tcx, Option<(PrimVal, bool)>> { - use rustc::mir::interpret::PrimValKind::*; + ) -> EvalResult<'tcx, Option<(Scalar, bool)>> { use rustc::mir::BinOp::*; - let usize = PrimValKind::from_uint_size(self.memory.pointer_size()); - let isize = PrimValKind::from_int_size(self.memory.pointer_size()); - let left_kind = self.ty_to_primval_kind(left_ty)?; - let right_kind = self.ty_to_primval_kind(right_ty)?; + use rustc::ty::layout::Integer::*; + let usize = Primitive::Int(match self.memory.pointer_size().bytes() { + 1 => I8, + 2 => I16, + 4 => I32, + 8 => I64, + 16 => I128, + _ => unreachable!(), + }, false); + let isize = Primitive::Int(match self.memory.pointer_size().bytes() { + 1 => I8, + 2 => I16, + 4 => I32, + 8 => I64, + 16 => I128, + _ => unreachable!(), + }, true); + let left_kind = match self.layout_of(left_ty)?.abi { + ty::layout::Abi::Scalar(ref scalar) => scalar.value, + _ => Err(EvalErrorKind::TypeNotPrimitive(left_ty))?, + }; + let right_kind = match self.layout_of(right_ty)?.abi { + ty::layout::Abi::Scalar(ref scalar) => scalar.value, + _ => Err(EvalErrorKind::TypeNotPrimitive(right_ty))?, + }; match bin_op { - Offset if left_kind == Ptr && right_kind == usize => { + Offset if left_kind == Primitive::Pointer && right_kind == usize => { let pointee_ty = left_ty .builtin_deref(true) .expect("Offset called on non-ptr type") @@ -48,35 +69,35 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: let ptr = self.pointer_offset( left.into(), pointee_ty, - right.to_bytes()? as i64, + right.to_bits(self.memory.pointer_size())? as i64, )?; - Ok(Some((ptr.into_inner_primval(), false))) + Ok(Some((ptr, false))) } // These work on anything Eq if left_kind == right_kind => { let result = match (left, right) { - (PrimVal::Bytes(left), PrimVal::Bytes(right)) => left == right, - (PrimVal::Ptr(left), PrimVal::Ptr(right)) => left == right, - (PrimVal::Undef, _) | - (_, PrimVal::Undef) => return err!(ReadUndefBytes), + (Scalar::Bits { .. }, Scalar::Bits { .. }) => { + left.to_bits(self.memory.pointer_size())? == right.to_bits(self.memory.pointer_size())? + }, + (Scalar::Ptr(left), Scalar::Ptr(right)) => left == right, _ => false, }; - Ok(Some((PrimVal::from_bool(result), false))) + Ok(Some((Scalar::from_bool(result), false))) } Ne if left_kind == right_kind => { let result = match (left, right) { - (PrimVal::Bytes(left), PrimVal::Bytes(right)) => left != right, - (PrimVal::Ptr(left), PrimVal::Ptr(right)) => left != right, - (PrimVal::Undef, _) | - (_, PrimVal::Undef) => return err!(ReadUndefBytes), + (Scalar::Bits { .. }, Scalar::Bits { .. }) => { + left.to_bits(self.memory.pointer_size())? != right.to_bits(self.memory.pointer_size())? + }, + (Scalar::Ptr(left), Scalar::Ptr(right)) => left != right, _ => true, }; - Ok(Some((PrimVal::from_bool(result), false))) + Ok(Some((Scalar::from_bool(result), false))) } // These need both pointers to be in the same allocation Lt | Le | Gt | Ge | Sub if left_kind == right_kind && - (left_kind == Ptr || left_kind == usize || left_kind == isize) && + (left_kind == Primitive::Pointer || left_kind == usize || left_kind == isize) && left.is_ptr() && right.is_ptr() => { let left = left.to_ptr()?; let right = right.to_ptr()?; @@ -89,15 +110,15 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: Sub => { return self.binary_op( Sub, - PrimVal::Bytes(left.offset.bytes() as u128), + Scalar::Bits { bits: left.offset.bytes() as u128, defined: self.memory.pointer_size().bits() as u8 }, self.tcx.types.usize, - PrimVal::Bytes(right.offset.bytes() as u128), + Scalar::Bits { bits: right.offset.bytes() as u128, defined: self.memory.pointer_size().bits() as u8 }, self.tcx.types.usize, ).map(Some) } _ => bug!("We already established it has to be one of these operators."), }; - Ok(Some((PrimVal::from_bool(res), false))) + Ok(Some((Scalar::from_bool(res), false))) } else { // Both are pointers, but from different allocations. err!(InvalidPointerMath) @@ -106,23 +127,23 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: // These work if one operand is a pointer, the other an integer Add | BitAnd | Sub if left_kind == right_kind && (left_kind == usize || left_kind == isize) && - left.is_ptr() && right.is_bytes() => { + left.is_ptr() && right.is_bits() => { // Cast to i128 is fine as we checked the kind to be ptr-sized self.ptr_int_arithmetic( bin_op, left.to_ptr()?, - right.to_bytes()? as i128, + right.to_bits(self.memory.pointer_size())? as i128, left_kind == isize, ).map(Some) } Add | BitAnd if left_kind == right_kind && (left_kind == usize || left_kind == isize) && - left.is_bytes() && right.is_ptr() => { + left.is_bits() && right.is_ptr() => { // This is a commutative operation, just swap the operands self.ptr_int_arithmetic( bin_op, right.to_ptr()?, - left.to_bytes()? as i128, + left.to_bits(self.memory.pointer_size())? as i128, left_kind == isize, ).map(Some) } @@ -133,14 +154,14 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: fn ptr_int_arithmetic( &self, bin_op: mir::BinOp, - left: MemoryPointer, + left: Pointer, right: i128, signed: bool, - ) -> EvalResult<'tcx, (PrimVal, bool)> { + ) -> EvalResult<'tcx, (Scalar, bool)> { use rustc::mir::BinOp::*; - fn map_to_primval((res, over): (MemoryPointer, bool)) -> (PrimVal, bool) { - (PrimVal::Ptr(res), over) + fn map_to_primval((res, over): (Pointer, bool)) -> (Scalar, bool) { + (Scalar::Ptr(res), over) } Ok(match bin_op { @@ -157,10 +178,10 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: let right = right as u64; if right & base_mask == base_mask { // Case 1: The base address bits are all preserved, i.e., right is all-1 there - (PrimVal::Ptr(MemoryPointer::new(left.alloc_id, Size::from_bytes(left.offset.bytes() & right))), false) + (Scalar::Ptr(Pointer::new(left.alloc_id, Size::from_bytes(left.offset.bytes() & right))), false) } else if right & base_mask == 0 { // Case 2: The base address bits are all taken away, i.e., right is all-0 there - (PrimVal::from_u128((left.offset.bytes() & right) as u128), false) + (Scalar::Bits { bits: (left.offset.bytes() & right) as u128, defined: 128 }, false) } else { return err!(ReadPointerAsBytes); } diff --git a/src/tls.rs b/src/tls.rs index e55cbede23394..7f49509ef42ea 100644 --- a/src/tls.rs +++ b/src/tls.rs @@ -1,17 +1,17 @@ use rustc::{ty, mir}; -use super::{TlsKey, TlsEntry, EvalResult, EvalErrorKind, Pointer, Memory, Evaluator, Place, - StackPopCleanup, EvalContext}; +use super::{TlsKey, TlsEntry, EvalResult, EvalErrorKind, Scalar, ScalarExt, Memory, Evaluator, + Place, StackPopCleanup, EvalContext}; pub trait MemoryExt<'tcx> { fn create_tls_key(&mut self, dtor: Option>) -> TlsKey; fn delete_tls_key(&mut self, key: TlsKey) -> EvalResult<'tcx>; - fn load_tls(&mut self, key: TlsKey) -> EvalResult<'tcx, Pointer>; - fn store_tls(&mut self, key: TlsKey, new_data: Pointer) -> EvalResult<'tcx>; + fn load_tls(&mut self, key: TlsKey) -> EvalResult<'tcx, Scalar>; + fn store_tls(&mut self, key: TlsKey, new_data: Scalar) -> EvalResult<'tcx>; fn fetch_tls_dtor( &mut self, key: Option, - ) -> EvalResult<'tcx, Option<(ty::Instance<'tcx>, Pointer, TlsKey)>>; + ) -> EvalResult<'tcx, Option<(ty::Instance<'tcx>, Scalar, TlsKey)>>; } pub trait EvalContextExt<'tcx> { @@ -25,7 +25,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> MemoryExt<'tcx> for Memory<'a, 'mir, 'tcx, Evalu self.data.thread_local.insert( new_key, TlsEntry { - data: Pointer::null(), + data: Scalar::null(), dtor, }, ); @@ -43,7 +43,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> MemoryExt<'tcx> for Memory<'a, 'mir, 'tcx, Evalu }; } - fn load_tls(&mut self, key: TlsKey) -> EvalResult<'tcx, Pointer> { + fn load_tls(&mut self, key: TlsKey) -> EvalResult<'tcx, Scalar> { return match self.data.thread_local.get(&key) { Some(&TlsEntry { data, .. }) => { trace!("TLS key {} loaded: {:?}", key, data); @@ -53,7 +53,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> MemoryExt<'tcx> for Memory<'a, 'mir, 'tcx, Evalu }; } - fn store_tls(&mut self, key: TlsKey, new_data: Pointer) -> EvalResult<'tcx> { + fn store_tls(&mut self, key: TlsKey, new_data: Scalar) -> EvalResult<'tcx> { return match self.data.thread_local.get_mut(&key) { Some(&mut TlsEntry { ref mut data, .. }) => { trace!("TLS key {} stored: {:?}", key, new_data); @@ -85,19 +85,21 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> MemoryExt<'tcx> for Memory<'a, 'mir, 'tcx, Evalu fn fetch_tls_dtor( &mut self, key: Option, - ) -> EvalResult<'tcx, Option<(ty::Instance<'tcx>, Pointer, TlsKey)>> { + ) -> EvalResult<'tcx, Option<(ty::Instance<'tcx>, Scalar, TlsKey)>> { use std::collections::Bound::*; + + let thread_local = &mut self.data.thread_local; let start = match key { Some(key) => Excluded(key), None => Unbounded, }; for (&key, &mut TlsEntry { ref mut data, dtor }) in - self.data.thread_local.range_mut((start, Unbounded)) + thread_local.range_mut((start, Unbounded)) { if !data.is_null()? { if let Some(dtor) = dtor { let ret = Some((dtor, *data, key)); - *data = Pointer::null(); + *data = Scalar::null(); return Ok(ret); } } diff --git a/src/validation.rs b/src/validation.rs index deb1c5d5bc079..24ddffee9def6 100644 --- a/src/validation.rs +++ b/src/validation.rs @@ -12,7 +12,7 @@ use rustc::middle::const_val::ConstVal; use rustc_data_structures::indexed_vec::Idx; use rustc_mir::interpret::HasMemory; -use super::{EvalContext, Place, PlaceExtra, ValTy}; +use super::{EvalContext, Place, PlaceExtra, ValTy, ScalarExt}; use rustc::mir::interpret::{DynamicLifetime, AccessKind, EvalErrorKind, Value, EvalError, EvalResult}; use locks::MemoryExt; @@ -119,7 +119,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' Index(v) => { let value = self.frame().get_local(v)?; let ty = self.tcx.tcx.types.usize; - let n = self.value_to_primval(ValTy { value, ty })?.to_u64()?; + let n = self.value_to_scalar(ValTy { value, ty })?.to_u64()?; Index(n) }, ConstantIndex { offset, min_length, from_end } => @@ -652,7 +652,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' TyBool | TyFloat(_) | TyChar => { if mode.acquiring() { let val = self.read_place(query.place.1)?; - let val = self.value_to_primval(ValTy { value: val, ty: query.ty })?; + let val = self.value_to_scalar(ValTy { value: val, ty: query.ty })?; val.to_bytes()?; // TODO: Check if these are valid bool/float/codepoint/UTF-8 } From b0ee05e86115d39e0c111e78e1d017f334b065a6 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Wed, 30 May 2018 14:29:32 +0200 Subject: [PATCH 0075/3747] `memcmp` returns `i32` --- src/fn_call.rs | 4 ++-- src/lib.rs | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index ea0c5eb8b26e9..6a2255e577724 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -289,7 +289,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' use std::cmp::Ordering::*; match left_bytes.cmp(right_bytes) { - Less => -1i8, + Less => -1i32, Equal => 0, Greater => 1, } @@ -297,7 +297,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' self.write_scalar( dest, - Scalar::from_i8(result), + Scalar::from_i32(result), dest_ty, )?; } diff --git a/src/lib.rs b/src/lib.rs index e3c83c284db99..079560c0ca955 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -55,7 +55,7 @@ use validation::{ValidationQuery, AbsPlace}; pub trait ScalarExt { fn null() -> Self; - fn from_i8(i: i8) -> 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; @@ -72,8 +72,8 @@ impl ScalarExt for Scalar { Scalar::Bits { bits: 0, defined: 128 } } - fn from_i8(i: i8) -> Self { - Scalar::Bits { bits: i as i128 as u128, defined: 8 } + fn from_i32(i: i32) -> Self { + Scalar::Bits { bits: i as u32 as u128, defined: 32 } } fn from_u128(i: u128) -> Self { From f927014c8a147208cbeb373c714d2748c33ae7b9 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Wed, 30 May 2018 14:29:54 +0200 Subject: [PATCH 0076/3747] Comparing Scalar's with differend `defined` values is false --- src/intrinsic.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/intrinsic.rs b/src/intrinsic.rs index 3d537ea629c3b..1e8090dc18976 100644 --- a/src/intrinsic.rs +++ b/src/intrinsic.rs @@ -327,7 +327,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 != Scalar::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)?; From ac667d372f4094debfb9b7e29041f9e4a874fa6c Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Wed, 30 May 2018 14:30:15 +0200 Subject: [PATCH 0077/3747] Comparing non-pointer-size types should be possible --- src/operator.rs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/operator.rs b/src/operator.rs index 721b4f0bfddab..f36e749dc9279 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -52,11 +52,13 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: 16 => I128, _ => unreachable!(), }, true); - let left_kind = match self.layout_of(left_ty)?.abi { + let left_layout = self.layout_of(left_ty)?; + let left_kind = match left_layout.abi { ty::layout::Abi::Scalar(ref scalar) => scalar.value, _ => Err(EvalErrorKind::TypeNotPrimitive(left_ty))?, }; - let right_kind = match self.layout_of(right_ty)?.abi { + let right_layout = self.layout_of(right_ty)?; + let right_kind = match right_layout.abi { ty::layout::Abi::Scalar(ref scalar) => scalar.value, _ => Err(EvalErrorKind::TypeNotPrimitive(right_ty))?, }; @@ -77,7 +79,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: Eq if left_kind == right_kind => { let result = match (left, right) { (Scalar::Bits { .. }, Scalar::Bits { .. }) => { - left.to_bits(self.memory.pointer_size())? == right.to_bits(self.memory.pointer_size())? + left.to_bits(left_layout.size)? == right.to_bits(right_layout.size)? }, (Scalar::Ptr(left), Scalar::Ptr(right)) => left == right, _ => false, @@ -87,7 +89,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: Ne if left_kind == right_kind => { let result = match (left, right) { (Scalar::Bits { .. }, Scalar::Bits { .. }) => { - left.to_bits(self.memory.pointer_size())? != right.to_bits(self.memory.pointer_size())? + left.to_bits(left_layout.size)? != right.to_bits(right_layout.size)? }, (Scalar::Ptr(left), Scalar::Ptr(right)) => left != right, _ => true, From e4f075459c5b9bb83ca695cf139581e07587bc15 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Wed, 30 May 2018 15:59:04 +0200 Subject: [PATCH 0078/3747] TlsKey is messy because it changes types between systems --- src/fn_call.rs | 9 +++------ src/lib.rs | 2 +- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index 6a2255e577724..d1a483d2e8043 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -512,21 +512,18 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' self.write_null(dest, dest_ty)?; } "pthread_key_delete" => { - // The conversion into TlsKey here is a little fishy, but should work as long as usize >= libc::pthread_key_t - let key = self.value_to_scalar(args[0])?.to_u64()? as TlsKey; + 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)?; } "pthread_getspecific" => { - // The conversion into TlsKey here is a little fishy, but should work as long as usize >= libc::pthread_key_t - let key = self.value_to_scalar(args[0])?.to_u64()? as TlsKey; + let key = self.value_to_scalar(args[0])?.to_bytes()?; let ptr = self.memory.load_tls(key)?; self.write_ptr(dest, ptr, dest_ty)?; } "pthread_setspecific" => { - // The conversion into TlsKey here is a little fishy, but should work as long as usize >= libc::pthread_key_t - let key = self.value_to_scalar(args[0])?.to_u64()? as TlsKey; + let key = self.value_to_scalar(args[0])?.to_bytes()?; let new_ptr = self.into_ptr(args[1].value)?; self.memory.store_tls(key, new_ptr)?; diff --git a/src/lib.rs b/src/lib.rs index 079560c0ca955..6d7c0b05f80f7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -277,7 +277,7 @@ pub struct Evaluator<'tcx> { pub(crate) suspended: HashMap>>, } -pub type TlsKey = usize; +pub type TlsKey = u128; #[derive(Copy, Clone, Debug)] pub struct TlsEntry<'tcx> { From ea2c8bfb041bad805578d0ec50b46b0675ca0187 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Wed, 30 May 2018 17:43:27 +0200 Subject: [PATCH 0079/3747] `align_offset` intrinsic is now a lang item --- src/fn_call.rs | 12 ++++++++++++ src/intrinsic.rs | 8 -------- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index d1a483d2e8043..fdaa819c08f7a 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -135,6 +135,18 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' _ => {} } + if self.tcx.lang_items().align_offset_fn() == Some(instance.def.def_id()) { + // FIXME: return a real value in case the target allocation has an + // alignment bigger than the one requested + let n = u128::max_value(); + let amt = 128 - self.memory.pointer_size().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)?; + self.goto_block(return_to_block); + return Ok(true); + } + let mir = match self.load_mir(instance.def) { Ok(mir) => mir, Err(EvalError { kind: EvalErrorKind::NoMirFor(path), .. }) => { diff --git a/src/intrinsic.rs b/src/intrinsic.rs index 1e8090dc18976..cee2f1ab7682f 100644 --- a/src/intrinsic.rs +++ b/src/intrinsic.rs @@ -33,14 +33,6 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: let intrinsic_name = &self.tcx.item_name(instance.def_id()).as_str()[..]; match intrinsic_name { - "align_offset" => { - // FIXME: return a real value in case the target allocation has an - // alignment bigger than the one requested - let n = u128::max_value(); - let amt = 128 - self.memory.pointer_size().bytes() * 8; - self.write_scalar(dest, Scalar::from_u128((n << amt) >> amt), dest_layout.ty)?; - }, - "add_with_overflow" => { self.intrinsic_with_overflow( mir::BinOp::Add, From 066a284557ff6e6a2aa19084f599f167a724af7b Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Wed, 30 May 2018 17:43:54 +0200 Subject: [PATCH 0080/3747] `to_u64` and `to_bytes` are horribly easy to use wrongly. --- src/fn_call.rs | 8 ++++---- src/lib.rs | 3 +++ 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index fdaa819c08f7a..72efcd6ede077 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -316,7 +316,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' "memrchr" => { let ptr = self.into_ptr(args[0].value)?; - let val = self.value_to_scalar(args[1])?.to_u64()? as u8; + let val = self.value_to_scalar(args[1])?.to_bytes()? as u8; let num = self.value_to_scalar(args[2])?.to_u64()?; if let Some(idx) = self.memory.read_bytes(ptr, Size::from_bytes(num))?.iter().rev().position( |&c| c == val, @@ -331,7 +331,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' "memchr" => { let ptr = self.into_ptr(args[0].value)?; - let val = self.value_to_scalar(args[1])?.to_u64()? as u8; + let val = self.value_to_scalar(args[1])?.to_bytes()? as u8; let num = self.value_to_scalar(args[2])?.to_u64()?; if let Some(idx) = self.memory.read_bytes(ptr, Size::from_bytes(num))?.iter().position( |&c| c == val, @@ -414,9 +414,9 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' } "write" => { - let fd = self.value_to_scalar(args[0])?.to_u64()?; + let fd = self.value_to_scalar(args[0])?.to_bytes()?; let buf = self.into_ptr(args[1].value)?; - let n = self.value_to_scalar(args[2])?.to_u64()?; + 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 { // stdout/stderr diff --git a/src/lib.rs b/src/lib.rs index 6d7c0b05f80f7..550965573cb47 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -64,6 +64,9 @@ pub trait ScalarExt { fn from_f64(f: f64) -> Self; fn to_u64(self) -> EvalResult<'static, u64>; fn is_null(self) -> EvalResult<'static, 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 fn to_bytes(self) -> EvalResult<'static, u128>; } From e29b696e8d10978914cb5c20329cb2ac0d5bdb91 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Sun, 3 Jun 2018 11:54:17 +0200 Subject: [PATCH 0081/3747] Use correct bit size when reading usize values --- src/fn_call.rs | 30 +++++++++++++++--------------- src/lib.rs | 6 +++--- src/validation.rs | 2 +- 3 files changed, 19 insertions(+), 19 deletions(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index 72efcd6ede077..36cc29a2b5b5b 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -194,7 +194,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' match &link_name[..] { "malloc" => { - let size = self.value_to_scalar(args[0])?.to_u64()?; + let size = self.value_to_scalar(args[0])?.to_usize(self)?; if size == 0 { self.write_null(dest, dest_ty)?; } else { @@ -221,7 +221,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' // // libc::syscall(NR_GETRANDOM, buf.as_mut_ptr(), buf.len(), GRND_NONBLOCK) // is called if a `HashMap` is created the regular way. - match self.value_to_scalar(args[0])?.to_u64()? { + match self.value_to_scalar(args[0])?.to_usize(self)? { 318 | 511 => { return err!(Unimplemented( "miri does not support random number generators".to_owned(), @@ -293,7 +293,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' "memcmp" => { let left = self.into_ptr(args[0].value)?; let right = self.into_ptr(args[1].value)?; - let n = Size::from_bytes(self.value_to_scalar(args[2])?.to_u64()?); + let n = Size::from_bytes(self.value_to_scalar(args[2])?.to_usize(self)?); let result = { let left_bytes = self.memory.read_bytes(left, n)?; @@ -317,7 +317,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' "memrchr" => { let ptr = self.into_ptr(args[0].value)?; let val = self.value_to_scalar(args[1])?.to_bytes()? as u8; - let num = self.value_to_scalar(args[2])?.to_u64()?; + 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( |&c| c == val, ) @@ -332,7 +332,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' "memchr" => { let ptr = self.into_ptr(args[0].value)?; let val = self.value_to_scalar(args[1])?.to_bytes()? as u8; - let num = self.value_to_scalar(args[2])?.to_u64()?; + 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( |&c| c == val, ) @@ -457,7 +457,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' } "sysconf" => { - let name = self.value_to_scalar(args[0])?.to_u64()?; + let name = self.value_to_scalar(args[0])?.to_usize(self)?; trace!("sysconf() called with name {}", name); // cache the sysconf integers via miri's global cache @@ -646,8 +646,8 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' match &path[..] { // Allocators are magic. They have no MIR, even when the rest of libstd does. "alloc::alloc::::__rust_alloc" => { - let size = self.value_to_scalar(args[0])?.to_u64()?; - let align = self.value_to_scalar(args[1])?.to_u64()?; + let size = self.value_to_scalar(args[0])?.to_usize(self)?; + let align = self.value_to_scalar(args[1])?.to_usize(self)?; if size == 0 { return err!(HeapAllocZeroBytes); } @@ -660,8 +660,8 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' self.write_scalar(dest, Scalar::Ptr(ptr), dest_ty)?; } "alloc::alloc::::__rust_alloc_zeroed" => { - let size = self.value_to_scalar(args[0])?.to_u64()?; - let align = self.value_to_scalar(args[1])?.to_u64()?; + let size = self.value_to_scalar(args[0])?.to_usize(self)?; + let align = self.value_to_scalar(args[1])?.to_usize(self)?; if size == 0 { return err!(HeapAllocZeroBytes); } @@ -676,8 +676,8 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' } "alloc::alloc::::__rust_dealloc" => { let ptr = self.into_ptr(args[0].value)?.to_ptr()?; - let old_size = self.value_to_scalar(args[1])?.to_u64()?; - let align = self.value_to_scalar(args[2])?.to_u64()?; + 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 { return err!(HeapAllocZeroBytes); } @@ -692,9 +692,9 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' } "alloc::alloc::::__rust_realloc" => { let ptr = self.into_ptr(args[0].value)?.to_ptr()?; - let old_size = self.value_to_scalar(args[1])?.to_u64()?; - let align = self.value_to_scalar(args[2])?.to_u64()?; - let new_size = self.value_to_scalar(args[3])?.to_u64()?; + 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)?; if old_size == 0 || new_size == 0 { return err!(HeapAllocZeroBytes); } diff --git a/src/lib.rs b/src/lib.rs index 550965573cb47..a29211df996bf 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -62,7 +62,7 @@ pub trait ScalarExt { fn from_isize(i: i64, ptr_size: Size) -> Self; fn from_f32(f: f32) -> Self; fn from_f64(f: f64) -> Self; - fn to_u64(self) -> EvalResult<'static, u64>; + fn 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>; /// 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 @@ -103,8 +103,8 @@ impl ScalarExt for Scalar { Scalar::Bits { bits: f.to_bits() as u128, defined: 64 } } - fn to_u64(self) -> EvalResult<'static, u64> { - let b = self.to_bits(Size::from_bits(64))?; + fn to_usize<'a, 'mir, 'tcx>(self, ecx: &rustc_mir::interpret::EvalContext<'a, 'mir, 'tcx, Evaluator<'tcx>>) -> EvalResult<'static, u64> { + let b = self.to_bits(ecx.memory.pointer_size())?; assert_eq!(b as u64 as u128, b); Ok(b as u64) } diff --git a/src/validation.rs b/src/validation.rs index 24ddffee9def6..d82a345c2512a 100644 --- a/src/validation.rs +++ b/src/validation.rs @@ -119,7 +119,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' Index(v) => { let value = self.frame().get_local(v)?; let ty = self.tcx.tcx.types.usize; - let n = self.value_to_scalar(ValTy { value, ty })?.to_u64()?; + let n = self.value_to_scalar(ValTy { value, ty })?.to_usize(self)?; Index(n) }, ConstantIndex { offset, min_length, from_end } => From dbadf1e3fbc7a26a560e570efb6c5c4468e046e4 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Sun, 3 Jun 2018 12:13:30 +0200 Subject: [PATCH 0082/3747] Update cargo-miri --- cargo-miri-test/Cargo.lock | 12 ++++++------ src/bin/cargo-miri.rs | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/cargo-miri-test/Cargo.lock b/cargo-miri-test/Cargo.lock index 8b2387fa64109..85c3c08dba019 100644 --- a/cargo-miri-test/Cargo.lock +++ b/cargo-miri-test/Cargo.lock @@ -1,14 +1,14 @@ -[root] +[[package]] +name = "byteorder" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] name = "cargo-miri-test" version = "0.1.0" dependencies = [ "byteorder 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "byteorder" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - [metadata] "checksum byteorder 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c40977b0ee6b9885c9013cd41d9feffdd22deb3bb4dc3a71d901cc7a77de18c8" diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 39a41583a39e0..010f25e8152dc 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -154,7 +154,7 @@ fn main() { // this check ensures that dependencies are built but not interpreted and the final crate is // interpreted but not built - let miri_enabled = std::env::args().any(|s| s == "-Zno-trans"); + let miri_enabled = std::env::args().any(|s| s == "--emit=dep-info,metadata"); let mut command = if miri_enabled { let mut path = std::env::current_exe().expect("current executable path invalid"); @@ -193,7 +193,7 @@ where if !found_dashes { args.push("--".to_owned()); } - args.push("-Zno-trans".to_owned()); + args.push("--emit=dep-info,metadata".to_owned()); args.push("--cfg".to_owned()); args.push(r#"feature="cargo-miri""#.to_owned()); From 10078dd6d0d056d19e4c64fc8bf4c8b1ec02a86b Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Sun, 3 Jun 2018 12:54:43 +0200 Subject: [PATCH 0083/3747] Reenable the rustc tester --- rustc_tests/Cargo.lock | 203 +++++++++++++++++++++++++--------------- rustc_tests/src/main.rs | 10 +- src/lib.rs | 1 - 3 files changed, 131 insertions(+), 83 deletions(-) diff --git a/rustc_tests/Cargo.lock b/rustc_tests/Cargo.lock index a1e273a96bdb8..9cf4fe0d1342a 100644 --- a/rustc_tests/Cargo.lock +++ b/rustc_tests/Cargo.lock @@ -1,10 +1,3 @@ -[root] -name = "rustc_tests" -version = "0.1.0" -dependencies = [ - "miri 0.1.0", -] - [[package]] name = "aho-corasick" version = "0.6.3" @@ -14,26 +7,13 @@ dependencies = [ ] [[package]] -name = "backtrace" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "backtrace-sys 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "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.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" +name = "atty" +version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "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)", + "termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -47,40 +27,33 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] -name = "dbghelp-sys" -version = "0.2.0" +name = "env_logger" +version = "0.5.10" 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)", + "atty 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", + "humantime 1.1.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)", + "termcolor 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] -name = "env_logger" -version = "0.4.3" +name = "humantime" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] -name = "gcc" -version = "0.3.53" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "kernel32-sys" -version = "0.2.2" +name = "lazy_static" +version = "0.2.8" 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" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -90,20 +63,23 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "log" -version = "0.3.8" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", +] [[package]] -name = "log_settings" -version = "0.1.1" +name = "memchr" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.30 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "memchr" -version = "1.0.1" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "libc 0.2.30 (registry+https://github.com/rust-lang/crates.io-index)", @@ -114,10 +90,28 @@ name = "miri" version = "0.1.0" dependencies = [ "byteorder 1.1.0 (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)", - "rustc_miri 0.1.0", + "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 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "quick-error" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "redox_syscall" +version = "0.1.40" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "redox_termios" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -132,26 +126,54 @@ dependencies = [ "utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "regex" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "aho-corasick 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "regex-syntax 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "thread_local 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "regex-syntax" version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] -name = "rustc-demangle" -version = "0.1.5" +name = "regex-syntax" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "ucd-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] [[package]] -name = "rustc_miri" +name = "rustc_tests" version = "0.1.0" dependencies = [ - "backtrace 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "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)", - "log_settings 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "miri 0.1.0", +] + +[[package]] +name = "termcolor" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "wincolor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "termion" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.30 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -163,6 +185,11 @@ dependencies = [ "unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "ucd-util" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "unreachable" version = "1.0.0" @@ -183,35 +210,59 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "winapi" -version = "0.2.8" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", +] [[package]] -name = "winapi-build" -version = "0.1.1" +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "wincolor" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi 0.3.4 (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.3 (registry+https://github.com/rust-lang/crates.io-index)" = "99f2ce94e22b8e664d95c57fff45b98a966c2252b60691d0b7aeeccd88d70983" -"checksum backtrace-sys 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "afccc5772ba333abccdf60d55200fa3406f8c59dcf54d5f7998c9107d3799c7c" +"checksum atty 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "2fc4a1aa4c24c0718a250f0681885c1af91419d242f29eb8f2ab28502d80dbd1" "checksum byteorder 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ff81738b726f5d099632ceaffe7fb65b90212e8dce59d518729e7e8634032d3d" "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 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 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.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 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" +"checksum memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "796fba70e76612589ed2ce7f45282f5af869e0fdd7cc6199fa1aa1f1d591ba9d" +"checksum quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9274b940887ce9addde99c4eee6b5c44cc494b182b97e73dc8ffdcb3397fd3f0" +"checksum redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "c214e91d3ecf43e9a4e41e578973adeb14b474f2bee858742d127af75a0112b1" +"checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76" "checksum regex 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1731164734096285ec2a5ec7fea5248ae2f5485b3feeb0115af4fda2183b2d1b" +"checksum regex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "75ecf88252dce580404a22444fc7d626c01815debba56a7f4f536772a5ff19d3" "checksum regex-syntax 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ad890a5eef7953f55427c50575c680c42841653abd2b028b68cd223d157f62db" -"checksum rustc-demangle 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "aee45432acc62f7b9a108cc054142dac51f979e69e71ddce7d6fc7adf29e817e" +"checksum regex-syntax 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8f1ac0f60d675cc6cf13a20ec076568254472551051ad5dd050364d70671bf6b" +"checksum termcolor 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "adc4587ead41bf016f11af03e55a624c06568b5a19db4e90fde573d805074f83" +"checksum termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "689a3bdfaab439fd92bc87df5c4c78417d3cbe537487274e9b0b2dce76e92096" "checksum thread_local 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "1697c4b57aeeb7a536b647165a2825faddffb1d3bad386d507709bd51a90bb14" +"checksum ucd-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "fd2be2d6639d0f8fe6cdda291ad456e23629558d466e2789d2c3e9892bda285d" "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" +"checksum winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "04e3bd221fcbe8a271359c04f21a76db7d0c6028862d1bb5512d85e1e2eb5bb3" +"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +"checksum wincolor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "eeb06499a3a4d44302791052df005d5232b927ed1a9658146d842165c4de7767" diff --git a/rustc_tests/src/main.rs b/rustc_tests/src/main.rs index 77e4a3df406b7..ecc5287c72771 100644 --- a/rustc_tests/src/main.rs +++ b/rustc_tests/src/main.rs @@ -4,7 +4,7 @@ extern crate getopts; extern crate rustc; extern crate rustc_driver; extern crate rustc_errors; -extern crate rustc_trans_utils; +extern crate rustc_codegen_utils; extern crate syntax; use std::path::{PathBuf, Path}; @@ -19,7 +19,7 @@ use rustc_driver::{Compilation, CompilerCalls, RustcDefaultCalls}; use rustc_driver::driver::{CompileState, CompileController}; use rustc::session::config::{self, Input, ErrorOutputType}; use rustc::hir::{self, itemlikevisit}; -use rustc_trans_utils::trans_crate::TransCrate; +use rustc_codegen_utils::codegen_backend::CodegenBackend; use rustc::ty::TyCtxt; use syntax::ast; @@ -53,7 +53,7 @@ impl<'a> CompilerCalls<'a> for MiriCompilerCalls { } fn late_callback( &mut self, - trans: &TransCrate, + trans: &CodegenBackend, matches: &getopts::Matches, sess: &Session, cstore: &CrateStore, @@ -104,9 +104,7 @@ fn after_analysis<'a, 'tcx>(state: &mut CompileState<'a, 'tcx>) { state.hir_crate.unwrap().visit_all_item_likes(&mut Visitor(tcx, state)); } else if let Some((entry_node_id, _, _)) = *state.session.entry_fn.borrow() { let entry_def_id = tcx.hir.local_def_id(entry_node_id); - let start_wrapper = tcx.lang_items().start_fn().and_then(|start_fn| - if tcx.is_mir_available(start_fn) { Some(start_fn) } else { None }); - miri::eval_main(tcx, entry_def_id, start_wrapper); + miri::eval_main(tcx, entry_def_id, None); state.session.abort_if_errors(); } else { diff --git a/src/lib.rs b/src/lib.rs index a29211df996bf..1ba763349aa7d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -265,7 +265,6 @@ pub fn eval_main<'a, 'tcx: 'a>( } } } - ::std::process::exit(1); } } } From 574aa3bc42a02348ee8b7bd61fbea480f48c01d5 Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Sun, 13 May 2018 13:14:26 +0200 Subject: [PATCH 0084/3747] Rustup to rustc 1.27.0-nightly (ff2ac35db 2018-05-12) --- src/fn_call.rs | 2 +- src/validation.rs | 15 +++++++-------- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index 2b4e7b7366284..272c27e402196 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -459,7 +459,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' promoted: None, }; let const_val = self.const_eval(cid)?; - let value = const_val.val.unwrap_u64(); + let value = const_val.unwrap_usize(self.tcx.tcx); if value == name { result = Some(path_value); break; diff --git a/src/validation.rs b/src/validation.rs index b274b4650157d..deb1c5d5bc079 100644 --- a/src/validation.rs +++ b/src/validation.rs @@ -10,7 +10,7 @@ use rustc::infer::InferCtxt; use rustc::middle::region; use rustc::middle::const_val::ConstVal; use rustc_data_structures::indexed_vec::Idx; -use rustc_mir::interpret::{HasMemory, eval_body}; +use rustc_mir::interpret::HasMemory; use super::{EvalContext, Place, PlaceExtra, ValTy}; use rustc::mir::interpret::{DynamicLifetime, AccessKind, EvalErrorKind, Value, EvalError, EvalResult}; @@ -718,18 +718,17 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' } } TyArray(elem_ty, len) => { - let len_val = match len.val { + let len = match len.val { ConstVal::Unevaluated(def_id, substs) => { - eval_body(self.tcx.tcx, GlobalId { + self.tcx.const_eval(self.tcx.param_env(def_id).and(GlobalId { instance: Instance::new(def_id, substs), promoted: None, - }, ty::ParamEnv::reveal_all()) - .ok_or_else(||EvalErrorKind::MachineError("".to_string()))? - .0 + })) + .map_err(|_err|EvalErrorKind::MachineError("".to_string()))? } - ConstVal::Value(val) => val, + ConstVal::Value(_) => len, }; - let len = ConstVal::Value(len_val).unwrap_u64(); + let len = len.unwrap_usize(self.tcx.tcx); for i in 0..len { let inner_place = self.place_index(query.place.1, query.ty, i as u64)?; self.validate( From c8ff634f828b62290a5ee9798687bca2ec300f71 Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Sun, 13 May 2018 15:32:35 +0200 Subject: [PATCH 0085/3747] Enable backtraces for tests --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 6a987f93748c1..9aa632da05e0e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -27,7 +27,7 @@ script: - | # Test plain miri cargo build --release --all-features && - cargo test --release --all-features --all && + RUST_BACKTRACE=1 cargo test --release --all-features --all && cargo install --all-features --force - | # Test cargo miri From b906ce84ec0635e2033b94415f6ad3ef938c7489 Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Sat, 19 May 2018 12:14:13 +0200 Subject: [PATCH 0086/3747] Rustup to rustc 1.28.0-nightly (952f344cd 2018-05-18) --- src/bin/miri.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 4e0be7bd32048..5ae9626f01fbd 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -5,7 +5,7 @@ extern crate miri; extern crate rustc; extern crate rustc_driver; extern crate rustc_errors; -extern crate rustc_trans_utils; +extern crate rustc_codegen_utils; extern crate env_logger; extern crate log_settings; extern crate syntax; @@ -18,7 +18,7 @@ use rustc_driver::driver::{CompileState, CompileController}; use rustc::session::config::{self, Input, ErrorOutputType}; use rustc::hir::{self, itemlikevisit}; use rustc::ty::TyCtxt; -use rustc_trans_utils::trans_crate::TransCrate; +use rustc_codegen_utils::codegen_backend::CodegenBackend; use syntax::ast; use std::path::PathBuf; @@ -67,7 +67,7 @@ impl<'a> CompilerCalls<'a> for MiriCompilerCalls { } fn late_callback( &mut self, - trans: &TransCrate, + trans: &CodegenBackend, matches: &getopts::Matches, sess: &Session, cstore: &CrateStore, From 601673d06fd2ddee44dfb437f56afeee36f0e96f Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Sat, 19 May 2018 14:09:29 +0200 Subject: [PATCH 0087/3747] trans -> codegen_backend --- src/bin/miri.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 5ae9626f01fbd..8d80135cde300 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -67,7 +67,7 @@ impl<'a> CompilerCalls<'a> for MiriCompilerCalls { } fn late_callback( &mut self, - trans: &CodegenBackend, + codegen_backend: &CodegenBackend, matches: &getopts::Matches, sess: &Session, cstore: &CrateStore, @@ -75,7 +75,7 @@ impl<'a> CompilerCalls<'a> for MiriCompilerCalls { odir: &Option, ofile: &Option, ) -> Compilation { - self.default.late_callback(trans, matches, sess, cstore, input, odir, ofile) + self.default.late_callback(codegen_backend, matches, sess, cstore, input, odir, ofile) } fn build_controller( &mut self, From 98802769a1d3df9b106ad89221679aef0e8aede1 Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Sun, 20 May 2018 11:26:40 +0200 Subject: [PATCH 0088/3747] Rustup to rustc 1.28.0-nightly (a3085756e 2018-05-19) --- src/fn_call.rs | 34 +++++++++++++++++----------------- src/intrinsic.rs | 12 ++++++------ src/lib.rs | 16 ++++++++-------- src/locks.rs | 11 ++++++----- src/operator.rs | 10 +++++----- 5 files changed, 42 insertions(+), 41 deletions(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index 272c27e402196..e7250eca949d1 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -1,5 +1,5 @@ use rustc::ty::{self, Ty}; -use rustc::ty::layout::{self, Align, LayoutOf}; +use rustc::ty::layout::{self, Align, LayoutOf, Size}; use rustc::hir::def_id::{DefId, CRATE_DEF_INDEX}; use rustc::mir; use rustc_data_structures::indexed_vec::Idx; @@ -187,7 +187,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' self.write_null(dest, dest_ty)?; } else { let align = self.tcx.data_layout.pointer_align; - let ptr = self.memory.allocate(size, align, Some(MemoryKind::C.into()))?; + let ptr = self.memory.allocate(Size::from_bytes(size), align, Some(MemoryKind::C.into()))?; self.write_primval(dest, PrimVal::Ptr(ptr), dest_ty)?; } } @@ -281,7 +281,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' "memcmp" => { let left = self.into_ptr(args[0].value)?; let right = self.into_ptr(args[1].value)?; - let n = self.value_to_primval(args[2])?.to_u64()?; + let n = Size::from_bytes(self.value_to_primval(args[2])?.to_u64()?); let result = { let left_bytes = self.memory.read_bytes(left, n)?; @@ -306,11 +306,11 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' let ptr = self.into_ptr(args[0].value)?; let val = self.value_to_primval(args[1])?.to_u64()? as u8; let num = self.value_to_primval(args[2])?.to_u64()?; - if let Some(idx) = self.memory.read_bytes(ptr, num)?.iter().rev().position( + if let Some(idx) = self.memory.read_bytes(ptr, Size::from_bytes(num))?.iter().rev().position( |&c| c == val, ) { - let new_ptr = ptr.offset(num - idx as u64 - 1, &self)?; + let new_ptr = ptr.offset(Size::from_bytes(num - idx as u64 - 1), &self)?; self.write_ptr(dest, new_ptr, dest_ty)?; } else { self.write_null(dest, dest_ty)?; @@ -321,11 +321,11 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' let ptr = self.into_ptr(args[0].value)?; let val = self.value_to_primval(args[1])?.to_u64()? as u8; let num = self.value_to_primval(args[2])?.to_u64()?; - if let Some(idx) = self.memory.read_bytes(ptr, num)?.iter().position( + if let Some(idx) = self.memory.read_bytes(ptr, Size::from_bytes(num))?.iter().position( |&c| c == val, ) { - let new_ptr = ptr.offset(idx as u64, &self)?; + let new_ptr = ptr.offset(Size::from_bytes(idx as u64), &self)?; self.write_ptr(dest, new_ptr, dest_ty)?; } else { self.write_null(dest, dest_ty)?; @@ -381,12 +381,12 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' if let Some((name, value)) = new { // +1 for the null terminator let value_copy = self.memory.allocate( - (value.len() + 1) as u64, + Size::from_bytes((value.len() + 1) as u64), Align::from_bytes(1, 1).unwrap(), Some(MemoryKind::Env.into()), )?; self.memory.write_bytes(value_copy.into(), &value)?; - let trailing_zero_ptr = value_copy.offset(value.len() as u64, &self)?.into(); + let trailing_zero_ptr = value_copy.offset(Size::from_bytes(value.len() as u64), &self)?.into(); self.memory.write_bytes(trailing_zero_ptr, &[0])?; if let Some(var) = self.machine.env_vars.insert( name.to_owned(), @@ -410,7 +410,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' // stdout/stderr use std::io::{self, Write}; - let buf_cont = self.memory.read_bytes(buf, n)?; + let buf_cont = self.memory.read_bytes(buf, Size::from_bytes(n))?; let res = if fd == 1 { io::stdout().write(buf_cont) } else { @@ -502,7 +502,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' key_ptr, key_align, PrimVal::Bytes(key), - key_size.bytes(), + key_size, false, )?; @@ -643,7 +643,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' if !align.is_power_of_two() { return err!(HeapAllocNonPowerOfTwoAlignment(align)); } - let ptr = self.memory.allocate(size, + let ptr = self.memory.allocate(Size::from_bytes(size), Align::from_bytes(align, align).unwrap(), Some(MemoryKind::Rust.into()))?; self.write_primval(dest, PrimVal::Ptr(ptr), dest_ty)?; @@ -657,10 +657,10 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' if !align.is_power_of_two() { return err!(HeapAllocNonPowerOfTwoAlignment(align)); } - let ptr = self.memory.allocate(size, + let ptr = self.memory.allocate(Size::from_bytes(size), Align::from_bytes(align, align).unwrap(), Some(MemoryKind::Rust.into()))?; - self.memory.write_repeat(ptr.into(), 0, size)?; + self.memory.write_repeat(ptr.into(), 0, Size::from_bytes(size))?; self.write_primval(dest, PrimVal::Ptr(ptr), dest_ty)?; } "alloc::alloc::::__rust_dealloc" => { @@ -675,7 +675,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' } self.memory.deallocate( ptr, - Some((old_size, Align::from_bytes(align, align).unwrap())), + Some((Size::from_bytes(old_size), Align::from_bytes(align, align).unwrap())), MemoryKind::Rust.into(), )?; } @@ -692,9 +692,9 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' } let new_ptr = self.memory.reallocate( ptr, - old_size, + Size::from_bytes(old_size), Align::from_bytes(align, align).unwrap(), - new_size, + Size::from_bytes(new_size), Align::from_bytes(align, align).unwrap(), MemoryKind::Rust.into(), )?; diff --git a/src/intrinsic.rs b/src/intrinsic.rs index 234d1ee784838..30de1c68ca618 100644 --- a/src/intrinsic.rs +++ b/src/intrinsic.rs @@ -1,5 +1,5 @@ use rustc::mir; -use rustc::ty::layout::{TyLayout, LayoutOf}; +use rustc::ty::layout::{TyLayout, LayoutOf, Size}; use rustc::ty; use rustc::mir::interpret::{EvalResult, PrimVal, PrimValKind, Value, Pointer}; @@ -35,7 +35,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: // FIXME: return a real value in case the target allocation has an // alignment bigger than the one requested let n = u128::max_value(); - let amt = 128 - self.memory.pointer_size() * 8; + let amt = 128 - self.memory.pointer_size().bytes() * 8; self.write_primval(dest, PrimVal::Bytes((n << amt) >> amt), dest_layout.ty)?; }, @@ -225,7 +225,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: elem_align, dest, elem_align, - count * elem_size, + Size::from_bytes(count * elem_size), intrinsic_name.ends_with("_nonoverlapping"), )?; } @@ -332,7 +332,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: "likely" | "unlikely" | "forget" => {} "init" => { - let size = dest_layout.size.bytes(); + let size = dest_layout.size; let init = |this: &mut Self, val: Value| { let zero_val = match val { Value::ByRef(ptr, _) => { @@ -631,7 +631,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: } "uninit" => { - let size = dest_layout.size.bytes(); + let size = dest_layout.size; let uninit = |this: &mut Self, val: Value| match val { Value::ByRef(ptr, _) => { this.memory.mark_definedness(ptr, size, false)?; @@ -662,7 +662,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: // HashMap relies on write_bytes on a NULL ptr with count == 0 to work // TODO: Should we, at least, validate the alignment? (Also see the copy intrinsic) self.memory.check_align(ptr, ty_layout.align)?; - self.memory.write_repeat(ptr, val_byte, ty_layout.size.bytes() * count)?; + self.memory.write_repeat(ptr, val_byte, ty_layout.size * count)?; } } diff --git a/src/lib.rs b/src/lib.rs index dce31c4ed3383..66ad6377e3279 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -20,7 +20,7 @@ extern crate regex; extern crate lazy_static; use rustc::ty::{self, TyCtxt}; -use rustc::ty::layout::{TyLayout, LayoutOf}; +use rustc::ty::layout::{TyLayout, LayoutOf, Size}; use rustc::ty::subst::Subst; use rustc::hir::def_id::DefId; use rustc::mir; @@ -93,7 +93,7 @@ pub fn eval_main<'a, 'tcx: 'a>( } // Return value - let size = ecx.tcx.data_layout.pointer_size.bytes(); + let size = ecx.tcx.data_layout.pointer_size; let align = ecx.tcx.data_layout.pointer_align; let ret_ptr = ecx.memory_mut().allocate(size, align, Some(MemoryKind::Stack))?; cleanup_ptr = Some(ret_ptr); @@ -299,7 +299,7 @@ impl<'mir, 'tcx: 'mir> Machine<'mir, 'tcx> for Evaluator<'tcx> { let layout = ecx.layout_of(mir.return_ty().subst(tcx, cid.instance.substs))?; assert!(!layout.is_unsized()); let ptr = ecx.memory.allocate( - layout.size.bytes(), + layout.size, layout.align, None, )?; @@ -373,8 +373,8 @@ impl<'mir, 'tcx: 'mir> Machine<'mir, 'tcx> for Evaluator<'tcx> { ecx.write_value( ValTy { value: Value::ByVal(PrimVal::Bytes(match layout.size.bytes() { - 0 => 1, - size => size, + 0 => 1 as u128, + size => size as u128, }.into())), ty: usize, }, @@ -407,10 +407,10 @@ impl<'mir, 'tcx: 'mir> Machine<'mir, 'tcx> for Evaluator<'tcx> { fn check_locks<'a>( mem: &Memory<'a, 'mir, 'tcx, Self>, ptr: MemoryPointer, - size: u64, + size: Size, access: AccessKind, ) -> EvalResult<'tcx> { - mem.check_locks(ptr, size, access) + mem.check_locks(ptr, size.bytes(), access) } fn add_lock<'a>( @@ -439,7 +439,7 @@ impl<'mir, 'tcx: 'mir> Machine<'mir, 'tcx> for Evaluator<'tcx> { //ptr, FIXME ptr: MemoryPointer { alloc_id: AllocId(0), - offset: 0, + offset: Size::from_bytes(0), }, lock: lock.active, }.into() diff --git a/src/locks.rs b/src/locks.rs index 677b0454a546c..9efbabc7171b3 100644 --- a/src/locks.rs +++ b/src/locks.rs @@ -1,5 +1,6 @@ use super::*; use rustc::middle::region; +use rustc::ty::layout::Size; //////////////////////////////////////////////////////////////////////////////// // Locks @@ -116,7 +117,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> MemoryExt<'tcx> for Memory<'a, 'mir, 'tcx, Evalu }; let frame = self.cur_frame; locks - .check(Some(frame), ptr.offset, len, access) + .check(Some(frame), ptr.offset.bytes(), len, access) .map_err(|lock| { EvalErrorKind::MemoryLockViolation { ptr, @@ -146,7 +147,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> MemoryExt<'tcx> for Memory<'a, 'mir, 'tcx, Evalu len, region ); - self.check_bounds(ptr.offset(len, &*self)?, true)?; // if ptr.offset is in bounds, then so is ptr (because offset checks for overflow) + self.check_bounds(ptr.offset(Size::from_bytes(len), &*self)?, true)?; // if ptr.offset is in bounds, then so is ptr (because offset checks for overflow) let locks = match self.data.locks.get_mut(&ptr.alloc_id) { Some(locks) => locks, @@ -157,7 +158,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> MemoryExt<'tcx> for Memory<'a, 'mir, 'tcx, Evalu // Iterate over our range and acquire the lock. If the range is already split into pieces, // we have to manipulate all of them. let lifetime = DynamicLifetime { frame, region }; - for lock in locks.iter_mut(ptr.offset, len) { + for lock in locks.iter_mut(ptr.offset.bytes(), len) { if !lock.access_permitted(None, kind) { return err!(MemoryAcquireConflict { ptr, @@ -203,7 +204,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> MemoryExt<'tcx> for Memory<'a, 'mir, 'tcx, Evalu None => return Ok(()), }; - 'locks: for lock in locks.iter_mut(ptr.offset, len) { + 'locks: for lock in locks.iter_mut(ptr.offset.bytes(), len) { let is_our_lock = match lock.active { WriteLock(lft) => // Double-check that we are holding the lock. @@ -281,7 +282,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> MemoryExt<'tcx> for Memory<'a, 'mir, 'tcx, Evalu None => return Ok(()), }; - for lock in locks.iter_mut(ptr.offset, len) { + for lock in locks.iter_mut(ptr.offset.bytes(), len) { // Check if we have a suspension here let (got_the_lock, remove_suspension) = match lock.suspended.get_mut(&lock_id) { None => { diff --git a/src/operator.rs b/src/operator.rs index 220f8f9acd541..557e07975d73b 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -89,9 +89,9 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: Sub => { return self.binary_op( Sub, - PrimVal::Bytes(left.offset as u128), + PrimVal::Bytes(left.offset.bytes() as u128), self.tcx.types.usize, - PrimVal::Bytes(right.offset as u128), + PrimVal::Bytes(right.offset.bytes() as u128), self.tcx.types.usize, ).map(Some) } @@ -150,17 +150,17 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: Add if signed => map_to_primval(left.overflowing_signed_offset(right, self)), Add if !signed => - map_to_primval(left.overflowing_offset(right as u64, self)), + map_to_primval(left.overflowing_offset(Size::from_bytes(right as u64), self)), BitAnd if !signed => { let base_mask : u64 = !(self.memory.get(left.alloc_id)?.align.abi() - 1); let right = right as u64; if right & base_mask == base_mask { // Case 1: The base address bits are all preserved, i.e., right is all-1 there - (PrimVal::Ptr(MemoryPointer::new(left.alloc_id, left.offset & right)), false) + (PrimVal::Ptr(MemoryPointer::new(left.alloc_id, Size::from_bytes(left.offset.bytes() & right))), false) } else if right & base_mask == 0 { // Case 2: The base address bits are all taken away, i.e., right is all-0 there - (PrimVal::from_u128((left.offset & right) as u128), false) + (PrimVal::from_u128((left.offset.bytes() & right) as u128), false) } else { return err!(ReadPointerAsBytes); } From 1437a975d64b0e04f807abfbca78deb4c93f928e Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Fri, 25 May 2018 14:37:12 +0200 Subject: [PATCH 0089/3747] s/allocate_cached/allocate_bytes --- src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 66ad6377e3279..f8119245b484c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -131,7 +131,7 @@ pub fn eval_main<'a, 'tcx: 'a>( // Third argument (argv): &[b"foo"] let dest = ecx.eval_place(&mir::Place::Local(args.next().unwrap()))?; let ty = ecx.tcx.mk_imm_ptr(ecx.tcx.mk_imm_ptr(ecx.tcx.types.u8)); - let foo = ecx.memory.allocate_cached(b"foo\0"); + let foo = ecx.memory.allocate_bytes(b"foo\0"); let ptr_size = ecx.memory.pointer_size(); let ptr_align = ecx.tcx.data_layout.pointer_align; let foo_ptr = ecx.memory.allocate(ptr_size, ptr_align, None)?; From 4143922d1d613154ad2c3369b3e2c6a6fd4ef35e Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Sat, 26 May 2018 17:07:34 +0200 Subject: [PATCH 0090/3747] Partial rustup --- benches/helpers/miri_helper.rs | 9 +- src/fn_call.rs | 114 +++++++++--------- src/helpers.rs | 34 +++--- src/intrinsic.rs | 206 +++++++++++++++++---------------- src/lib.rs | 104 ++++++++++++++--- src/locks.rs | 16 +-- src/operator.rs | 101 +++++++++------- src/tls.rs | 24 ++-- src/validation.rs | 6 +- 9 files changed, 358 insertions(+), 256 deletions(-) diff --git a/benches/helpers/miri_helper.rs b/benches/helpers/miri_helper.rs index 6657ba1199765..2bf78b0a71cc1 100644 --- a/benches/helpers/miri_helper.rs +++ b/benches/helpers/miri_helper.rs @@ -55,16 +55,13 @@ impl<'a> CompilerCalls<'a> for MiriCompilerCalls<'a> { state.session.abort_if_errors(); let tcx = state.tcx.unwrap(); - let (entry_node_id, _) = state.session.entry_fn.borrow().expect( + let (entry_node_id, _, _) = state.session.entry_fn.borrow().expect( "no main or start function found", ); - let entry_def_id = tcx.map.local_def_id(entry_node_id); + let entry_def_id = tcx.hir.local_def_id(entry_node_id); - let memory_size = 100 * 1024 * 1024; // 100MB - let step_limit = 1000_000; - let stack_limit = 100; bencher.borrow_mut().iter(|| { - eval_main(tcx, entry_def_id, memory_size, step_limit, stack_limit); + eval_main(tcx, entry_def_id, None); }); state.session.abort_if_errors(); diff --git a/src/fn_call.rs b/src/fn_call.rs index e7250eca949d1..ea0c5eb8b26e9 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -38,7 +38,7 @@ fn write_discriminant_value<'a, 'mir, 'tcx: 'a + 'mir>( .val; let (discr_dest, discr) = ecx.place_field(dest, mir::Field::new(0), layout)?; - ecx.write_primval(discr_dest, PrimVal::Bytes(discr_val), discr.ty)?; + ecx.write_scalar(discr_dest, Scalar::from_u128(discr_val), discr.ty)?; } layout::Variants::NicheFilling { dataful_variant, @@ -51,7 +51,7 @@ fn write_discriminant_value<'a, 'mir, 'tcx: 'a + 'mir>( ecx.place_field(dest, mir::Field::new(0), layout)?; let niche_value = ((variant_index - niche_variants.start()) as u128) .wrapping_add(niche_start); - ecx.write_primval(niche_dest, PrimVal::Bytes(niche_value), niche.ty)?; + ecx.write_scalar(niche_dest, Scalar::from_u128(niche_value), niche.ty)?; } } } @@ -182,13 +182,13 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' match &link_name[..] { "malloc" => { - let size = self.value_to_primval(args[0])?.to_u64()?; + let size = self.value_to_scalar(args[0])?.to_u64()?; if size == 0 { self.write_null(dest, dest_ty)?; } else { let align = self.tcx.data_layout.pointer_align; let ptr = self.memory.allocate(Size::from_bytes(size), align, Some(MemoryKind::C.into()))?; - self.write_primval(dest, PrimVal::Ptr(ptr), dest_ty)?; + self.write_scalar(dest, Scalar::Ptr(ptr), dest_ty)?; } } @@ -209,7 +209,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' // // libc::syscall(NR_GETRANDOM, buf.as_mut_ptr(), buf.len(), GRND_NONBLOCK) // is called if a `HashMap` is created the regular way. - match self.value_to_primval(args[0])?.to_u64()? { + match self.value_to_scalar(args[0])?.to_u64()? { 318 | 511 => { return err!(Unimplemented( "miri does not support random number generators".to_owned(), @@ -281,7 +281,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' "memcmp" => { let left = self.into_ptr(args[0].value)?; let right = self.into_ptr(args[1].value)?; - let n = Size::from_bytes(self.value_to_primval(args[2])?.to_u64()?); + let n = Size::from_bytes(self.value_to_scalar(args[2])?.to_u64()?); let result = { let left_bytes = self.memory.read_bytes(left, n)?; @@ -295,22 +295,22 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' } }; - self.write_primval( + self.write_scalar( dest, - PrimVal::Bytes(result as u128), + Scalar::from_i8(result), dest_ty, )?; } "memrchr" => { let ptr = self.into_ptr(args[0].value)?; - let val = self.value_to_primval(args[1])?.to_u64()? as u8; - let num = self.value_to_primval(args[2])?.to_u64()?; + let val = self.value_to_scalar(args[1])?.to_u64()? as u8; + let num = self.value_to_scalar(args[2])?.to_u64()?; if let Some(idx) = self.memory.read_bytes(ptr, Size::from_bytes(num))?.iter().rev().position( |&c| c == val, ) { - let new_ptr = ptr.offset(Size::from_bytes(num - idx as u64 - 1), &self)?; + let new_ptr = ptr.ptr_offset(Size::from_bytes(num - idx as u64 - 1), &self)?; self.write_ptr(dest, new_ptr, dest_ty)?; } else { self.write_null(dest, dest_ty)?; @@ -319,13 +319,13 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' "memchr" => { let ptr = self.into_ptr(args[0].value)?; - let val = self.value_to_primval(args[1])?.to_u64()? as u8; - let num = self.value_to_primval(args[2])?.to_u64()?; + let val = self.value_to_scalar(args[1])?.to_u64()? as u8; + let num = self.value_to_scalar(args[2])?.to_u64()?; if let Some(idx) = self.memory.read_bytes(ptr, Size::from_bytes(num))?.iter().position( |&c| c == val, ) { - let new_ptr = ptr.offset(Size::from_bytes(idx as u64), &self)?; + let new_ptr = ptr.ptr_offset(Size::from_bytes(idx as u64), &self)?; self.write_ptr(dest, new_ptr, dest_ty)?; } else { self.write_null(dest, dest_ty)?; @@ -337,11 +337,11 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' let name_ptr = self.into_ptr(args[0].value)?.to_ptr()?; let name = self.memory.read_c_str(name_ptr)?; match self.machine.env_vars.get(name) { - Some(&var) => PrimVal::Ptr(var), - None => PrimVal::Bytes(0), + Some(&var) => Scalar::Ptr(var), + None => Scalar::null(), } }; - self.write_primval(dest, result, dest_ty)?; + self.write_scalar(dest, result, dest_ty)?; } "unsetenv" => { @@ -361,7 +361,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' } self.write_null(dest, dest_ty)?; } else { - self.write_primval(dest, PrimVal::from_i128(-1), dest_ty)?; + self.write_scalar(dest, Scalar::from_i128(-1), dest_ty)?; } } @@ -397,14 +397,14 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' } self.write_null(dest, dest_ty)?; } else { - self.write_primval(dest, PrimVal::from_i128(-1), dest_ty)?; + self.write_scalar(dest, Scalar::from_i128(-1), dest_ty)?; } } "write" => { - let fd = self.value_to_primval(args[0])?.to_u64()?; + let fd = self.value_to_scalar(args[0])?.to_u64()?; let buf = self.into_ptr(args[1].value)?; - let n = self.value_to_primval(args[2])?.to_u64()?; + let n = self.value_to_scalar(args[2])?.to_u64()?; trace!("Called write({:?}, {:?}, {:?})", fd, buf, n); let result = if fd == 1 || fd == 2 { // stdout/stderr @@ -417,16 +417,17 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' io::stderr().write(buf_cont) }; match res { - Ok(n) => n as isize, + Ok(n) => n as i64, Err(_) => -1, } } else { warn!("Ignored output to FD {}", fd); - n as isize // pretend it all went well + n as i64 // pretend it all went well }; // now result is the value we return back to the program - self.write_primval( + let ptr_size = self.memory.pointer_size(); + self.write_scalar( dest, - PrimVal::Bytes(result as u128), + Scalar::from_isize(result, ptr_size), dest_ty, )?; } @@ -434,22 +435,23 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' "strlen" => { let ptr = self.into_ptr(args[0].value)?.to_ptr()?; let n = self.memory.read_c_str(ptr)?.len(); - self.write_primval(dest, PrimVal::Bytes(n as u128), dest_ty)?; + let ptr_size = self.memory.pointer_size(); + self.write_scalar(dest, Scalar::from_usize(n as u64, ptr_size), dest_ty)?; } // Some things needed for sys::thread initialization to go through "signal" | "sigaction" | "sigaltstack" => { - self.write_primval(dest, PrimVal::Bytes(0), dest_ty)?; + self.write_scalar(dest, Scalar::null(), dest_ty)?; } "sysconf" => { - let name = self.value_to_primval(args[0])?.to_u64()?; + let name = self.value_to_scalar(args[0])?.to_u64()?; trace!("sysconf() called with name {}", name); // cache the sysconf integers via miri's global cache let paths = &[ - (&["libc", "_SC_PAGESIZE"], PrimVal::Bytes(4096)), - (&["libc", "_SC_GETPW_R_SIZE_MAX"], PrimVal::from_i128(-1)), + (&["libc", "_SC_PAGESIZE"], Scalar::from_i128(4096)), + (&["libc", "_SC_GETPW_R_SIZE_MAX"], Scalar::from_i128(-1)), ]; let mut result = None; for &(path, path_value) in paths { @@ -467,7 +469,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' } } if let Some(result) = result { - self.write_primval(dest, result, dest_ty)?; + self.write_scalar(dest, result, dest_ty)?; } else { return err!(Unimplemented( format!("Unimplemented sysconf name: {}", name), @@ -481,11 +483,11 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' let key_align = self.layout_of(args[0].ty)?.align; // Extract the function type out of the signature (that seems easier than constructing it ourselves...) - let dtor = match self.into_ptr(args[1].value)?.into_inner_primval() { - PrimVal::Ptr(dtor_ptr) => Some(self.memory.get_fn(dtor_ptr)?), - PrimVal::Bytes(0) => None, - PrimVal::Bytes(_) => return err!(ReadBytesAsPointer), - PrimVal::Undef => return err!(ReadUndefBytes), + let dtor = match self.into_ptr(args[1].value)? { + Scalar::Ptr(dtor_ptr) => Some(self.memory.get_fn(dtor_ptr)?), + Scalar::Bits { defined: 0, .. } => return err!(ReadUndefBytes), + Scalar::Bits { bits: 0, .. } => None, + Scalar::Bits { .. } => return err!(ReadBytesAsPointer), }; // Figure out how large a pthread TLS key actually is. This is libc::pthread_key_t. @@ -498,10 +500,10 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' if key_size.bits() < 128 && key >= (1u128 << key_size.bits() as u128) { return err!(OutOfTls); } - self.memory.write_primval( + self.memory.write_scalar( key_ptr, key_align, - PrimVal::Bytes(key), + Scalar::from_u128(key), key_size, false, )?; @@ -511,20 +513,20 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' } "pthread_key_delete" => { // The conversion into TlsKey here is a little fishy, but should work as long as usize >= libc::pthread_key_t - let key = self.value_to_primval(args[0])?.to_u64()? as TlsKey; + let key = self.value_to_scalar(args[0])?.to_u64()? as TlsKey; self.memory.delete_tls_key(key)?; // Return success (0) self.write_null(dest, dest_ty)?; } "pthread_getspecific" => { // The conversion into TlsKey here is a little fishy, but should work as long as usize >= libc::pthread_key_t - let key = self.value_to_primval(args[0])?.to_u64()? as TlsKey; + let key = self.value_to_scalar(args[0])?.to_u64()? as TlsKey; let ptr = self.memory.load_tls(key)?; self.write_ptr(dest, ptr, dest_ty)?; } "pthread_setspecific" => { // The conversion into TlsKey here is a little fishy, but should work as long as usize >= libc::pthread_key_t - let key = self.value_to_primval(args[0])?.to_u64()? as TlsKey; + let key = self.value_to_scalar(args[0])?.to_u64()? as TlsKey; let new_ptr = self.into_ptr(args[1].value)?; self.memory.store_tls(key, new_ptr)?; @@ -635,8 +637,8 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' match &path[..] { // Allocators are magic. They have no MIR, even when the rest of libstd does. "alloc::alloc::::__rust_alloc" => { - let size = self.value_to_primval(args[0])?.to_u64()?; - let align = self.value_to_primval(args[1])?.to_u64()?; + let size = self.value_to_scalar(args[0])?.to_u64()?; + let align = self.value_to_scalar(args[1])?.to_u64()?; if size == 0 { return err!(HeapAllocZeroBytes); } @@ -646,11 +648,11 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' let ptr = self.memory.allocate(Size::from_bytes(size), Align::from_bytes(align, align).unwrap(), Some(MemoryKind::Rust.into()))?; - self.write_primval(dest, PrimVal::Ptr(ptr), dest_ty)?; + self.write_scalar(dest, Scalar::Ptr(ptr), dest_ty)?; } "alloc::alloc::::__rust_alloc_zeroed" => { - let size = self.value_to_primval(args[0])?.to_u64()?; - let align = self.value_to_primval(args[1])?.to_u64()?; + let size = self.value_to_scalar(args[0])?.to_u64()?; + let align = self.value_to_scalar(args[1])?.to_u64()?; if size == 0 { return err!(HeapAllocZeroBytes); } @@ -661,12 +663,12 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' Align::from_bytes(align, align).unwrap(), Some(MemoryKind::Rust.into()))?; self.memory.write_repeat(ptr.into(), 0, Size::from_bytes(size))?; - self.write_primval(dest, PrimVal::Ptr(ptr), dest_ty)?; + self.write_scalar(dest, Scalar::Ptr(ptr), dest_ty)?; } "alloc::alloc::::__rust_dealloc" => { let ptr = self.into_ptr(args[0].value)?.to_ptr()?; - let old_size = self.value_to_primval(args[1])?.to_u64()?; - let align = self.value_to_primval(args[2])?.to_u64()?; + let old_size = self.value_to_scalar(args[1])?.to_u64()?; + let align = self.value_to_scalar(args[2])?.to_u64()?; if old_size == 0 { return err!(HeapAllocZeroBytes); } @@ -681,9 +683,9 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' } "alloc::alloc::::__rust_realloc" => { let ptr = self.into_ptr(args[0].value)?.to_ptr()?; - let old_size = self.value_to_primval(args[1])?.to_u64()?; - let align = self.value_to_primval(args[2])?.to_u64()?; - let new_size = self.value_to_primval(args[3])?.to_u64()?; + let old_size = self.value_to_scalar(args[1])?.to_u64()?; + let align = self.value_to_scalar(args[2])?.to_u64()?; + let new_size = self.value_to_scalar(args[3])?.to_u64()?; if old_size == 0 || new_size == 0 { return err!(HeapAllocZeroBytes); } @@ -698,7 +700,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' Align::from_bytes(align, align).unwrap(), MemoryKind::Rust.into(), )?; - self.write_primval(dest, PrimVal::Ptr(new_ptr), dest_ty)?; + self.write_scalar(dest, Scalar::Ptr(new_ptr), dest_ty)?; } // A Rust function is missing, which means we are running with MIR missing for libstd (or other dependencies). @@ -720,13 +722,13 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' "std::rt::panicking" => { // we abort on panic -> `std::rt::panicking` always returns false let bool = self.tcx.types.bool; - self.write_primval(dest, PrimVal::from_bool(false), bool)?; + self.write_scalar(dest, Scalar::from_bool(false), bool)?; } "std::sys::imp::c::::AddVectoredExceptionHandler" | "std::sys::imp::c::::SetThreadStackGuarantee" => { let usize = self.tcx.types.usize; // any non zero value works for the stdlib. This is just used for stackoverflows anyway - self.write_primval(dest, PrimVal::Bytes(1), usize)?; + self.write_scalar(dest, Scalar::from_u128(1), usize)?; }, _ => return err!(NoMirFor(path)), } @@ -740,6 +742,6 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' } fn write_null(&mut self, dest: Place, dest_ty: Ty<'tcx>) -> EvalResult<'tcx> { - self.write_primval(dest, PrimVal::Bytes(0), dest_ty) + self.write_scalar(dest, Scalar::null(), dest_ty) } } diff --git a/src/helpers.rs b/src/helpers.rs index a7b94a656da4a..d881d5c271104 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -1,24 +1,24 @@ use mir; use rustc::ty::Ty; -use rustc::ty::layout::LayoutOf; +use rustc::ty::layout::{LayoutOf, Size}; -use super::{Pointer, EvalResult, PrimVal, EvalContext, ValTy}; +use super::{Scalar, ScalarExt, EvalResult, EvalContext, ValTy}; use rustc_mir::interpret::sign_extend; pub trait EvalContextExt<'tcx> { fn wrapping_pointer_offset( &self, - ptr: Pointer, + ptr: Scalar, pointee_ty: Ty<'tcx>, offset: i64, - ) -> EvalResult<'tcx, Pointer>; + ) -> EvalResult<'tcx, Scalar>; fn pointer_offset( &self, - ptr: Pointer, + ptr: Scalar, pointee_ty: Ty<'tcx>, offset: i64, - ) -> EvalResult<'tcx, Pointer>; + ) -> EvalResult<'tcx, Scalar>; fn value_to_isize( &self, @@ -44,22 +44,22 @@ pub trait EvalContextExt<'tcx> { impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super::Evaluator<'tcx>> { fn wrapping_pointer_offset( &self, - ptr: Pointer, + ptr: Scalar, pointee_ty: Ty<'tcx>, offset: i64, - ) -> EvalResult<'tcx, Pointer> { + ) -> EvalResult<'tcx, Scalar> { // FIXME: assuming here that type size is < i64::max_value() let pointee_size = self.layout_of(pointee_ty)?.size.bytes() as i64; let offset = offset.overflowing_mul(pointee_size).0; - ptr.wrapping_signed_offset(offset, self) + ptr.ptr_wrapping_signed_offset(offset, self) } fn pointer_offset( &self, - ptr: Pointer, + ptr: Scalar, pointee_ty: Ty<'tcx>, offset: i64, - ) -> EvalResult<'tcx, Pointer> { + ) -> EvalResult<'tcx, Scalar> { // This function raises an error if the offset moves the pointer outside of its allocation. We consider // ZSTs their own huge allocation that doesn't overlap with anything (and nothing moves in there because the size is 0). // We also consider the NULL pointer its own separate allocation, and all the remaining integers pointers their own @@ -76,9 +76,9 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: // FIXME: assuming here that type size is < i64::max_value() let pointee_size = self.layout_of(pointee_ty)?.size.bytes() as i64; return if let Some(offset) = offset.checked_mul(pointee_size) { - let ptr = ptr.signed_offset(offset, self)?; + let ptr = ptr.ptr_signed_offset(offset, self)?; // Do not do bounds-checking for integers; they can never alias a normal pointer anyway. - if let PrimVal::Ptr(ptr) = ptr.into_inner_primval() { + if let Scalar::Ptr(ptr) = ptr { self.memory.check_bounds(ptr, false)?; } else if ptr.is_null()? { // We moved *to* a NULL pointer. That seems wrong, LLVM considers the NULL pointer its own small allocation. Reject this, for now. @@ -95,7 +95,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: value: ValTy<'tcx>, ) -> EvalResult<'tcx, i64> { assert_eq!(value.ty, self.tcx.types.isize); - let raw = self.value_to_primval(value)?.to_bytes()?; + let raw = self.value_to_scalar(value)?.to_bits(self.memory.pointer_size())?; let raw = sign_extend(self.tcx.tcx, raw, self.tcx.types.isize)?; Ok(raw as i64) } @@ -105,7 +105,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: value: ValTy<'tcx>, ) -> EvalResult<'tcx, u64> { assert_eq!(value.ty, self.tcx.types.usize); - self.value_to_primval(value)?.to_bytes().map(|v| v as u64) + self.value_to_scalar(value)?.to_bits(self.memory.pointer_size()).map(|v| v as u64) } fn value_to_i32( @@ -113,7 +113,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: value: ValTy<'tcx>, ) -> EvalResult<'tcx, i32> { assert_eq!(value.ty, self.tcx.types.i32); - let raw = self.value_to_primval(value)?.to_bytes()?; + let raw = self.value_to_scalar(value)?.to_bits(Size::from_bits(32))?; let raw = sign_extend(self.tcx.tcx, raw, self.tcx.types.i32)?; Ok(raw as i32) } @@ -123,6 +123,6 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: value: ValTy<'tcx>, ) -> EvalResult<'tcx, u8> { assert_eq!(value.ty, self.tcx.types.u8); - self.value_to_primval(value)?.to_bytes().map(|v| v as u8) + self.value_to_scalar(value)?.to_bits(Size::from_bits(8)).map(|v| v as u8) } } diff --git a/src/intrinsic.rs b/src/intrinsic.rs index 30de1c68ca618..3d537ea629c3b 100644 --- a/src/intrinsic.rs +++ b/src/intrinsic.rs @@ -1,12 +1,14 @@ use rustc::mir; -use rustc::ty::layout::{TyLayout, LayoutOf, Size}; +use rustc::ty::layout::{TyLayout, LayoutOf, Size, Primitive, Integer::*}; use rustc::ty; -use rustc::mir::interpret::{EvalResult, PrimVal, PrimValKind, Value, Pointer}; +use rustc::mir::interpret::{EvalResult, Scalar, Value}; use rustc_mir::interpret::{Place, PlaceExtra, HasMemory, EvalContext, ValTy}; use helpers::EvalContextExt as HelperEvalContextExt; +use super::ScalarExt; + pub trait EvalContextExt<'tcx> { fn call_intrinsic( &mut self, @@ -36,7 +38,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: // alignment bigger than the one requested let n = u128::max_value(); let amt = 128 - self.memory.pointer_size().bytes() * 8; - self.write_primval(dest, PrimVal::Bytes((n << amt) >> amt), dest_layout.ty)?; + self.write_scalar(dest, Scalar::from_u128((n << amt) >> amt), dest_layout.ty)?; }, "add_with_overflow" => { @@ -77,7 +79,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: } "assume" => { - let cond = self.value_to_primval(args[0])?.to_bool()?; + let cond = self.value_to_scalar(args[0])?.to_bool()?; if !cond { return err!(AssumptionNotHeld); } @@ -115,16 +117,16 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: let ty = substs.type_at(0); let align = self.layout_of(ty)?.align; let ptr = self.into_ptr(args[0].value)?; - let change = self.value_to_primval(args[1])?; + let change = self.value_to_scalar(args[1])?; let old = self.read_value(ptr, align, ty)?; let old = match old { - Value::ByVal(val) => val, + Value::Scalar(val) => val, Value::ByRef { .. } => bug!("just read the value, can't be byref"), - Value::ByValPair(..) => bug!("atomic_xchg doesn't work with nonprimitives"), + Value::ScalarPair(..) => bug!("atomic_xchg doesn't work with nonprimitives"), }; - self.write_primval(dest, old, ty)?; - self.write_primval( - Place::from_primval_ptr(ptr, align), + self.write_scalar(dest, old, ty)?; + self.write_scalar( + Place::from_scalar_ptr(ptr, align), change, ty, )?; @@ -134,22 +136,22 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: let ty = substs.type_at(0); let align = self.layout_of(ty)?.align; let ptr = self.into_ptr(args[0].value)?; - let expect_old = self.value_to_primval(args[1])?; - let change = self.value_to_primval(args[2])?; + let expect_old = self.value_to_scalar(args[1])?; + let change = self.value_to_scalar(args[2])?; let old = self.read_value(ptr, align, ty)?; let old = match old { - Value::ByVal(val) => val, + Value::Scalar(val) => val, Value::ByRef { .. } => bug!("just read the value, can't be byref"), - Value::ByValPair(..) => bug!("atomic_cxchg doesn't work with nonprimitives"), + Value::ScalarPair(..) => bug!("atomic_cxchg doesn't work with nonprimitives"), }; let (val, _) = self.binary_op(mir::BinOp::Eq, old, ty, expect_old, ty)?; let valty = ValTy { - value: Value::ByValPair(old, val), + value: Value::ScalarPair(old, val), ty: dest_layout.ty, }; self.write_value(valty, dest)?; - self.write_primval( - Place::from_primval_ptr(ptr, dest_layout.align), + self.write_scalar( + Place::from_scalar_ptr(ptr, dest_layout.align), change, ty, )?; @@ -183,16 +185,16 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: let ty = substs.type_at(0); let align = self.layout_of(ty)?.align; let ptr = self.into_ptr(args[0].value)?; - let change = self.value_to_primval(args[1])?; + let change = self.value_to_scalar(args[1])?; let old = self.read_value(ptr, align, ty)?; let old = match old { - Value::ByVal(val) => val, + Value::Scalar(val) => val, Value::ByRef { .. } => bug!("just read the value, can't be byref"), - Value::ByValPair(..) => { + Value::ScalarPair(..) => { bug!("atomic_xadd_relaxed doesn't work with nonprimitives") } }; - self.write_primval(dest, old, ty)?; + self.write_scalar(dest, old, ty)?; let op = match intrinsic_name.split('_').nth(1).unwrap() { "or" => mir::BinOp::BitOr, "xor" => mir::BinOp::BitXor, @@ -203,7 +205,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: }; // FIXME: what do atomics do on overflow? let (val, _) = self.binary_op(op, old, ty, change, ty)?; - self.write_primval(Place::from_primval_ptr(ptr, dest_layout.align), val, ty)?; + self.write_scalar(Place::from_scalar_ptr(ptr, dest_layout.align), val, ty)?; } "breakpoint" => unimplemented!(), // halt miri @@ -233,8 +235,11 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: "ctpop" | "cttz" | "cttz_nonzero" | "ctlz" | "ctlz_nonzero" | "bswap" => { let ty = substs.type_at(0); - let num = self.value_to_primval(args[0])?.to_bytes()?; - let kind = self.ty_to_primval_kind(ty)?; + let num = self.value_to_scalar(args[0])?.to_bytes()?; + let kind = match self.layout_of(ty)?.abi { + ty::layout::Abi::Scalar(ref scalar) => scalar.value, + _ => Err(::rustc::mir::interpret::EvalErrorKind::TypeNotPrimitive(ty))?, + }; let num = if intrinsic_name.ends_with("_nonzero") { if num == 0 { return err!(Intrinsic(format!("{} called on 0", intrinsic_name))); @@ -243,21 +248,21 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: } else { numeric_intrinsic(intrinsic_name, num, kind)? }; - self.write_primval(dest, num, ty)?; + self.write_scalar(dest, num, ty)?; } "discriminant_value" => { let ty = substs.type_at(0); let adt_ptr = self.into_ptr(args[0].value)?; let adt_align = self.layout_of(args[0].ty)?.align; - let place = Place::from_primval_ptr(adt_ptr, adt_align); + let place = Place::from_scalar_ptr(adt_ptr, adt_align); let discr_val = self.read_discriminant_value(place, ty)?; - self.write_primval(dest, PrimVal::Bytes(discr_val), dest_layout.ty)?; + self.write_scalar(dest, Scalar::from_u128(discr_val), dest_layout.ty)?; } "sinf32" | "fabsf32" | "cosf32" | "sqrtf32" | "expf32" | "exp2f32" | "logf32" | "log10f32" | "log2f32" | "floorf32" | "ceilf32" | "truncf32" => { - let f = self.value_to_primval(args[0])?.to_bytes()?; + let f = self.value_to_scalar(args[0])?.to_bytes()?; let f = f32::from_bits(f as u32); let f = match intrinsic_name { "sinf32" => f.sin(), @@ -274,12 +279,12 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: "truncf32" => f.trunc(), _ => bug!(), }; - self.write_primval(dest, PrimVal::Bytes(f.to_bits() as u128), dest_layout.ty)?; + self.write_scalar(dest, Scalar::from_f32(f), dest_layout.ty)?; } "sinf64" | "fabsf64" | "cosf64" | "sqrtf64" | "expf64" | "exp2f64" | "logf64" | "log10f64" | "log2f64" | "floorf64" | "ceilf64" | "truncf64" => { - let f = self.value_to_primval(args[0])?.to_bytes()?; + let f = self.value_to_scalar(args[0])?.to_bytes()?; let f = f64::from_bits(f as u64); let f = match intrinsic_name { "sinf64" => f.sin(), @@ -296,13 +301,13 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: "truncf64" => f.trunc(), _ => bug!(), }; - self.write_primval(dest, PrimVal::Bytes(f.to_bits() as u128), dest_layout.ty)?; + self.write_scalar(dest, Scalar::from_f64(f), dest_layout.ty)?; } "fadd_fast" | "fsub_fast" | "fmul_fast" | "fdiv_fast" | "frem_fast" => { let ty = substs.type_at(0); - let a = self.value_to_primval(args[0])?; - let b = self.value_to_primval(args[1])?; + let a = self.value_to_scalar(args[0])?; + let b = self.value_to_scalar(args[1])?; let op = match intrinsic_name { "fadd_fast" => mir::BinOp::Add, "fsub_fast" => mir::BinOp::Sub, @@ -312,21 +317,21 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: _ => bug!(), }; let result = self.binary_op(op, a, ty, b, ty)?; - self.write_primval(dest, result.0, dest_layout.ty)?; + self.write_scalar(dest, result.0, dest_layout.ty)?; } "exact_div" => { // Performs an exact division, resulting in undefined behavior where // `x % y != 0` or `y == 0` or `x == T::min_value() && y == -1` let ty = substs.type_at(0); - let a = self.value_to_primval(args[0])?; - let b = self.value_to_primval(args[1])?; + let a = self.value_to_scalar(args[0])?; + let b = self.value_to_scalar(args[1])?; // check x % y != 0 - if self.binary_op(mir::BinOp::Rem, a, ty, b, ty)?.0 != PrimVal::Bytes(0) { + if self.binary_op(mir::BinOp::Rem, a, ty, b, ty)?.0 != Scalar::null() { return err!(ValidationFailure(format!("exact_div: {:?} cannot be divided by {:?}", a, b))); } let result = self.binary_op(mir::BinOp::Div, a, ty, b, ty)?; - self.write_primval(dest, result.0, dest_layout.ty)?; + self.write_scalar(dest, result.0, dest_layout.ty)?; }, "likely" | "unlikely" | "forget" => {} @@ -341,21 +346,21 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: val } // TODO(solson): Revisit this, it's fishy to check for Undef here. - Value::ByVal(PrimVal::Undef) => { - match this.ty_to_primval_kind(dest_layout.ty) { - Ok(_) => Value::ByVal(PrimVal::Bytes(0)), - Err(_) => { + Value::Scalar(Scalar::Bits { defined: 0, .. }) => { + match this.layout_of(dest_layout.ty)?.abi { + ty::layout::Abi::Scalar(_) => Value::Scalar(Scalar::null()), + _ => { // FIXME(oli-obk): pass TyLayout to alloc_ptr instead of Ty let ptr = this.alloc_ptr(dest_layout.ty)?; - let ptr = Pointer::from(PrimVal::Ptr(ptr)); + let ptr = Scalar::Ptr(ptr); this.memory.write_repeat(ptr, 0, size)?; Value::ByRef(ptr, dest_layout.align) } } } - Value::ByVal(_) => Value::ByVal(PrimVal::Bytes(0)), - Value::ByValPair(..) => { - Value::ByValPair(PrimVal::Bytes(0), PrimVal::Bytes(0)) + Value::Scalar(_) => Value::Scalar(Scalar::null()), + Value::ScalarPair(..) => { + Value::ScalarPair(Scalar::null(), Scalar::null()) } }; Ok(zero_val) @@ -376,16 +381,16 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: "min_align_of" => { let elem_ty = substs.type_at(0); let elem_align = self.layout_of(elem_ty)?.align.abi(); - let align_val = PrimVal::from_u128(elem_align as u128); - self.write_primval(dest, align_val, dest_layout.ty)?; + let align_val = Scalar::from_u128(elem_align as u128); + self.write_scalar(dest, align_val, dest_layout.ty)?; } "pref_align_of" => { let ty = substs.type_at(0); let layout = self.layout_of(ty)?; let align = layout.align.pref(); - let align_val = PrimVal::from_u128(align as u128); - self.write_primval(dest, align_val, dest_layout.ty)?; + let align_val = Scalar::from_u128(align as u128); + self.write_scalar(dest, align_val, dest_layout.ty)?; } "move_val_init" => { @@ -399,9 +404,9 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: let ty = substs.type_at(0); let env = ty::ParamEnv::reveal_all(); let needs_drop = ty.needs_drop(self.tcx.tcx, env); - self.write_primval( + self.write_scalar( dest, - PrimVal::from_bool(needs_drop), + Scalar::from_bool(needs_drop), dest_layout.ty, )?; } @@ -444,75 +449,75 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: } "powf32" => { - let f = self.value_to_primval(args[0])?.to_bytes()?; + let f = self.value_to_scalar(args[0])?.to_bits(Size::from_bits(32))?; let f = f32::from_bits(f as u32); - let f2 = self.value_to_primval(args[1])?.to_bytes()?; + let f2 = self.value_to_scalar(args[1])?.to_bits(Size::from_bits(32))?; let f2 = f32::from_bits(f2 as u32); - self.write_primval( + self.write_scalar( dest, - PrimVal::Bytes(f.powf(f2).to_bits() as u128), + Scalar::from_f32(f.powf(f2)), dest_layout.ty, )?; } "powf64" => { - let f = self.value_to_primval(args[0])?.to_bytes()?; + let f = self.value_to_scalar(args[0])?.to_bits(Size::from_bits(64))?; let f = f64::from_bits(f as u64); - let f2 = self.value_to_primval(args[1])?.to_bytes()?; + let f2 = self.value_to_scalar(args[1])?.to_bits(Size::from_bits(64))?; let f2 = f64::from_bits(f2 as u64); - self.write_primval( + self.write_scalar( dest, - PrimVal::Bytes(f.powf(f2).to_bits() as u128), + Scalar::from_f64(f.powf(f2)), dest_layout.ty, )?; } "fmaf32" => { - let a = self.value_to_primval(args[0])?.to_bytes()?; + let a = self.value_to_scalar(args[0])?.to_bits(Size::from_bits(32))?; let a = f32::from_bits(a as u32); - let b = self.value_to_primval(args[1])?.to_bytes()?; + let b = self.value_to_scalar(args[1])?.to_bits(Size::from_bits(32))?; let b = f32::from_bits(b as u32); - let c = self.value_to_primval(args[2])?.to_bytes()?; + let c = self.value_to_scalar(args[2])?.to_bits(Size::from_bits(32))?; let c = f32::from_bits(c as u32); - self.write_primval( + self.write_scalar( dest, - PrimVal::Bytes((a * b + c).to_bits() as u128), + Scalar::from_f32(a * b + c), dest_layout.ty, )?; } "fmaf64" => { - let a = self.value_to_primval(args[0])?.to_bytes()?; + let a = self.value_to_scalar(args[0])?.to_bits(Size::from_bits(64))?; let a = f64::from_bits(a as u64); - let b = self.value_to_primval(args[1])?.to_bytes()?; + let b = self.value_to_scalar(args[1])?.to_bits(Size::from_bits(64))?; let b = f64::from_bits(b as u64); - let c = self.value_to_primval(args[2])?.to_bytes()?; + let c = self.value_to_scalar(args[2])?.to_bits(Size::from_bits(64))?; let c = f64::from_bits(c as u64); - self.write_primval( + self.write_scalar( dest, - PrimVal::Bytes((a * b + c).to_bits() as u128), + Scalar::from_f64(a * b + c), dest_layout.ty, )?; } "powif32" => { - let f = self.value_to_primval(args[0])?.to_bytes()?; + let f = self.value_to_scalar(args[0])?.to_bits(Size::from_bits(32))?; let f = f32::from_bits(f as u32); let i = self.value_to_i32(args[1])?; - self.write_primval( + self.write_scalar( dest, - PrimVal::Bytes(f.powi(i).to_bits() as u128), + Scalar::from_f32(f.powi(i)), dest_layout.ty, )?; } "powif64" => { - let f = self.value_to_primval(args[0])?.to_bytes()?; + let f = self.value_to_scalar(args[0])?.to_bits(Size::from_bits(64))?; let f = f64::from_bits(f as u64); let i = self.value_to_i32(args[1])?; - self.write_primval( + self.write_scalar( dest, - PrimVal::Bytes(f.powi(i).to_bits() as u128), + Scalar::from_f64(f.powi(i)), dest_layout.ty, )?; } @@ -520,15 +525,15 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: "size_of" => { let ty = substs.type_at(0); let size = self.layout_of(ty)?.size.bytes().into(); - self.write_primval(dest, PrimVal::from_u128(size), dest_layout.ty)?; + self.write_scalar(dest, Scalar::from_u128(size), dest_layout.ty)?; } "size_of_val" => { let ty = substs.type_at(0); let (size, _) = self.size_and_align_of_dst(ty, args[0].value)?; - self.write_primval( + self.write_scalar( dest, - PrimVal::from_u128(size.bytes() as u128), + Scalar::from_u128(size.bytes() as u128), dest_layout.ty, )?; } @@ -537,9 +542,9 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: "align_of_val" => { let ty = substs.type_at(0); let (_, align) = self.size_and_align_of_dst(ty, args[0].value)?; - self.write_primval( + self.write_scalar( dest, - PrimVal::from_u128(align.abi() as u128), + Scalar::from_u128(align.abi() as u128), dest_layout.ty, )?; } @@ -553,7 +558,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: "type_id" => { let ty = substs.type_at(0); let n = self.tcx.type_id_hash(ty); - self.write_primval(dest, PrimVal::Bytes(n as u128), dest_layout.ty)?; + self.write_scalar(dest, Scalar::Bits { bits: n as u128, defined: 64 }, dest_layout.ty)?; } "transmute" => { @@ -566,7 +571,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: "unchecked_shl" => { let bits = dest_layout.size.bytes() as u128 * 8; - let rhs = self.value_to_primval(args[1])? + let rhs = self.value_to_scalar(args[1])? .to_bytes()?; if rhs >= bits { return err!(Intrinsic( @@ -584,7 +589,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: "unchecked_shr" => { let bits = dest_layout.size.bytes() as u128 * 8; - let rhs = self.value_to_primval(args[1])? + let rhs = self.value_to_scalar(args[1])? .to_bytes()?; if rhs >= bits { return err!(Intrinsic( @@ -601,7 +606,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: } "unchecked_div" => { - let rhs = self.value_to_primval(args[1])? + let rhs = self.value_to_scalar(args[1])? .to_bytes()?; if rhs == 0 { return err!(Intrinsic(format!("Division by 0 in unchecked_div"))); @@ -616,7 +621,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: } "unchecked_rem" => { - let rhs = self.value_to_primval(args[1])? + let rhs = self.value_to_scalar(args[1])? .to_bytes()?; if rhs == 0 { return err!(Intrinsic(format!("Division by 0 in unchecked_rem"))); @@ -637,7 +642,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: this.memory.mark_definedness(ptr, size, false)?; Ok(val) } - _ => Ok(Value::ByVal(PrimVal::Undef)), + _ => Ok(Value::Scalar(Scalar::undef())), }; match dest { Place::Local { frame, local } => self.modify_local(frame, local, uninit)?, @@ -681,26 +686,25 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: fn numeric_intrinsic<'tcx>( name: &str, bytes: u128, - kind: PrimValKind, -) -> EvalResult<'tcx, PrimVal> { + kind: Primitive, +) -> EvalResult<'tcx, Scalar> { macro_rules! integer_intrinsic { ($method:ident) => ({ - use rustc::mir::interpret::PrimValKind::*; let result_bytes = match kind { - I8 => (bytes as i8).$method() as u128, - U8 => (bytes as u8).$method() as u128, - I16 => (bytes as i16).$method() as u128, - U16 => (bytes as u16).$method() as u128, - I32 => (bytes as i32).$method() as u128, - U32 => (bytes as u32).$method() as u128, - I64 => (bytes as i64).$method() as u128, - U64 => (bytes as u64).$method() as u128, - I128 => (bytes as i128).$method() as u128, - U128 => bytes.$method() as u128, + Primitive::Int(I8, true) => (bytes as i8).$method() as u128, + Primitive::Int(I8, false) => (bytes as u8).$method() as u128, + Primitive::Int(I16, true) => (bytes as i16).$method() as u128, + Primitive::Int(I16, false) => (bytes as u16).$method() as u128, + Primitive::Int(I32, true) => (bytes as i32).$method() as u128, + Primitive::Int(I32, false) => (bytes as u32).$method() as u128, + Primitive::Int(I64, true) => (bytes as i64).$method() as u128, + Primitive::Int(I64, false) => (bytes as u64).$method() as u128, + Primitive::Int(I128, true) => (bytes as i128).$method() as u128, + Primitive::Int(I128, false) => bytes.$method() as u128, _ => bug!("invalid `{}` argument: {:?}", name, bytes), }; - PrimVal::Bytes(result_bytes) + Scalar::from_u128(result_bytes) }); } diff --git a/src/lib.rs b/src/lib.rs index f8119245b484c..e3c83c284db99 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -53,6 +53,81 @@ use validation::EvalContextExt as ValidationEvalContextExt; use range_map::RangeMap; use validation::{ValidationQuery, AbsPlace}; +pub trait ScalarExt { + fn null() -> Self; + fn from_i8(i: i8) -> Self; + fn from_u128(i: u128) -> Self; + fn from_i128(i: i128) -> Self; + fn from_usize(i: u64, ptr_size: Size) -> Self; + fn from_isize(i: i64, ptr_size: Size) -> Self; + fn from_f32(f: f32) -> Self; + fn from_f64(f: f64) -> Self; + fn to_u64(self) -> EvalResult<'static, u64>; + fn is_null(self) -> EvalResult<'static, bool>; + fn to_bytes(self) -> EvalResult<'static, u128>; +} + +impl ScalarExt for Scalar { + fn null() -> Self { + Scalar::Bits { bits: 0, defined: 128 } + } + + fn from_i8(i: i8) -> Self { + Scalar::Bits { bits: i as i128 as u128, defined: 8 } + } + + fn from_u128(i: u128) -> Self { + Scalar::Bits { bits: i, defined: 128 } + } + + fn from_i128(i: i128) -> Self { + Scalar::Bits { bits: i as u128, defined: 128 } + } + + fn from_usize(i: u64, ptr_size: Size) -> Self { + Scalar::Bits { bits: i as u128, defined: ptr_size.bits() as u8 } + } + + fn from_isize(i: i64, ptr_size: Size) -> Self { + Scalar::Bits { bits: i as i128 as u128, defined: ptr_size.bits() as u8 } + } + + fn from_f32(f: f32) -> Self { + Scalar::Bits { bits: f.to_bits() as u128, defined: 32 } + } + + fn from_f64(f: f64) -> Self { + Scalar::Bits { bits: f.to_bits() as u128, defined: 64 } + } + + fn to_u64(self) -> EvalResult<'static, u64> { + let b = self.to_bits(Size::from_bits(64))?; + assert_eq!(b as u64 as u128, b); + Ok(b as u64) + } + + fn is_null(self) -> EvalResult<'static, bool> { + match self { + Scalar::Bits { bits, defined } => { + if defined > 0 { + Ok(bits == 0) + } else { + err!(ReadUndefBytes) + } + } + Scalar::Ptr(_) => Ok(false) + } + } + + fn to_bytes(self) -> EvalResult<'static, u128> { + match self { + Scalar::Bits { defined: 0, .. } => err!(ReadUndefBytes), + Scalar::Bits { bits, .. } => Ok(bits), + Scalar::Ptr(_) => err!(ReadPointerAsBytes), + } + } +} + pub fn eval_main<'a, 'tcx: 'a>( tcx: TyCtxt<'a, 'tcx, 'tcx>, main_id: DefId, @@ -65,7 +140,7 @@ pub fn eval_main<'a, 'tcx: 'a>( ) -> EvalResult<'tcx> { let main_instance = ty::Instance::mono(ecx.tcx.tcx, main_id); let main_mir = ecx.load_mir(main_instance.def)?; - let mut cleanup_ptr = None; // Pointer to be deallocated when we are done + let mut cleanup_ptr = None; // Scalar to be deallocated when we are done if !main_mir.return_ty().is_nil() || main_mir.arg_count != 0 { return err!(Unimplemented( @@ -116,7 +191,7 @@ pub fn eval_main<'a, 'tcx: 'a>( let main_ptr_ty = ecx.tcx.mk_fn_ptr(main_ty.fn_sig(ecx.tcx.tcx)); ecx.write_value( ValTy { - value: Value::ByVal(PrimVal::Ptr(main_ptr)), + value: Value::Scalar(Scalar::Ptr(main_ptr)), ty: main_ptr_ty, }, dest, @@ -125,7 +200,7 @@ pub fn eval_main<'a, 'tcx: 'a>( // Second argument (argc): 1 let dest = ecx.eval_place(&mir::Place::Local(args.next().unwrap()))?; let ty = ecx.tcx.types.isize; - ecx.write_primval(dest, PrimVal::Bytes(1), ty)?; + ecx.write_scalar(dest, Scalar::from_u128(1), ty)?; // FIXME: extract main source file path // Third argument (argv): &[b"foo"] @@ -135,7 +210,7 @@ pub fn eval_main<'a, 'tcx: 'a>( let ptr_size = ecx.memory.pointer_size(); let ptr_align = ecx.tcx.data_layout.pointer_align; let foo_ptr = ecx.memory.allocate(ptr_size, ptr_align, None)?; - ecx.memory.write_primval(foo_ptr.into(), ptr_align, PrimVal::Ptr(foo.into()), ptr_size, false)?; + ecx.memory.write_scalar(foo_ptr.into(), ptr_align, Scalar::Ptr(foo), ptr_size, false)?; ecx.memory.mark_static_initialized(foo_ptr.alloc_id, Mutability::Immutable)?; ecx.write_ptr(dest, foo_ptr.into(), ty)?; @@ -145,7 +220,7 @@ pub fn eval_main<'a, 'tcx: 'a>( main_instance, main_mir.span, main_mir, - Place::from_primval_ptr(PrimVal::Bytes(1).into(), ty::layout::Align::from_bytes(1, 1).unwrap()), + Place::from_scalar_ptr(Scalar::from_u128(1), ty::layout::Align::from_bytes(1, 1).unwrap()), StackPopCleanup::None, )?; @@ -187,6 +262,7 @@ pub fn eval_main<'a, 'tcx: 'a>( } } } + ::std::process::exit(1); } } } @@ -195,7 +271,7 @@ pub fn eval_main<'a, 'tcx: 'a>( pub struct Evaluator<'tcx> { /// Environment variables set by `setenv` /// Miri does not expose env vars from the host to the emulated program - pub(crate) env_vars: HashMap, MemoryPointer>, + pub(crate) env_vars: HashMap, Pointer>, /// Places that were suspended by the validation subsystem, and will be recovered later pub(crate) suspended: HashMap>>, @@ -205,7 +281,7 @@ pub type TlsKey = usize; #[derive(Copy, Clone, Debug)] pub struct TlsEntry<'tcx> { - data: Pointer, // Will eventually become a map from thread IDs to `Pointer`s, if we ever support more than one thread. + data: Scalar, // Will eventually become a map from thread IDs to `Scalar`s, if we ever support more than one thread. dtor: Option>, } @@ -256,11 +332,11 @@ impl<'mir, 'tcx: 'mir> Machine<'mir, 'tcx> for Evaluator<'tcx> { fn try_ptr_op<'a>( ecx: &rustc_mir::interpret::EvalContext<'a, 'mir, 'tcx, Self>, bin_op: mir::BinOp, - left: PrimVal, + left: Scalar, left_ty: ty::Ty<'tcx>, - right: PrimVal, + right: Scalar, right_ty: ty::Ty<'tcx>, - ) -> EvalResult<'tcx, Option<(PrimVal, bool)>> { + ) -> EvalResult<'tcx, Option<(Scalar, bool)>> { ecx.ptr_op(bin_op, left, left_ty, right, right_ty) } @@ -372,7 +448,7 @@ impl<'mir, 'tcx: 'mir> Machine<'mir, 'tcx> for Evaluator<'tcx> { let dest = ecx.eval_place(&mir::Place::Local(args.next().unwrap()))?; ecx.write_value( ValTy { - value: Value::ByVal(PrimVal::Bytes(match layout.size.bytes() { + value: Value::Scalar(Scalar::from_u128(match layout.size.bytes() { 0 => 1 as u128, size => size as u128, }.into())), @@ -385,7 +461,7 @@ impl<'mir, 'tcx: 'mir> Machine<'mir, 'tcx> for Evaluator<'tcx> { let dest = ecx.eval_place(&mir::Place::Local(args.next().unwrap()))?; ecx.write_value( ValTy { - value: Value::ByVal(PrimVal::Bytes(layout.align.abi().into())), + value: Value::Scalar(Scalar::from_u128(layout.align.abi().into())), ty: usize, }, dest, @@ -406,7 +482,7 @@ impl<'mir, 'tcx: 'mir> Machine<'mir, 'tcx> for Evaluator<'tcx> { fn check_locks<'a>( mem: &Memory<'a, 'mir, 'tcx, Self>, - ptr: MemoryPointer, + ptr: Pointer, size: Size, access: AccessKind, ) -> EvalResult<'tcx> { @@ -437,7 +513,7 @@ impl<'mir, 'tcx: 'mir> Machine<'mir, 'tcx> for Evaluator<'tcx> { .map_err(|lock| { EvalErrorKind::DeallocatedLockedMemory { //ptr, FIXME - ptr: MemoryPointer { + ptr: Pointer { alloc_id: AllocId(0), offset: Size::from_bytes(0), }, diff --git a/src/locks.rs b/src/locks.rs index 9efbabc7171b3..a463f8ba575e8 100644 --- a/src/locks.rs +++ b/src/locks.rs @@ -70,27 +70,27 @@ impl<'tcx> LockInfo<'tcx> { pub trait MemoryExt<'tcx> { fn check_locks( &self, - ptr: MemoryPointer, + ptr: Pointer, len: u64, access: AccessKind, ) -> EvalResult<'tcx>; fn acquire_lock( &mut self, - ptr: MemoryPointer, + ptr: Pointer, len: u64, region: Option, kind: AccessKind, ) -> EvalResult<'tcx>; fn suspend_write_lock( &mut self, - ptr: MemoryPointer, + ptr: Pointer, len: u64, lock_path: &AbsPlace<'tcx>, suspend: Option, ) -> EvalResult<'tcx>; fn recover_write_lock( &mut self, - ptr: MemoryPointer, + ptr: Pointer, len: u64, lock_path: &AbsPlace<'tcx>, lock_region: Option, @@ -103,7 +103,7 @@ pub trait MemoryExt<'tcx> { impl<'a, 'mir, 'tcx: 'mir + 'a> MemoryExt<'tcx> for Memory<'a, 'mir, 'tcx, Evaluator<'tcx>> { fn check_locks( &self, - ptr: MemoryPointer, + ptr: Pointer, len: u64, access: AccessKind, ) -> EvalResult<'tcx> { @@ -132,7 +132,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> MemoryExt<'tcx> for Memory<'a, 'mir, 'tcx, Evalu /// Acquire the lock for the given lifetime fn acquire_lock( &mut self, - ptr: MemoryPointer, + ptr: Pointer, len: u64, region: Option, kind: AccessKind, @@ -191,7 +191,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> MemoryExt<'tcx> for Memory<'a, 'mir, 'tcx, Evalu /// When suspending, the same cases are fine; we just register an additional suspension. fn suspend_write_lock( &mut self, - ptr: MemoryPointer, + ptr: Pointer, len: u64, lock_path: &AbsPlace<'tcx>, suspend: Option, @@ -264,7 +264,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> MemoryExt<'tcx> for Memory<'a, 'mir, 'tcx, Evalu /// Release a suspension from the write lock. If this is the last suspension or if there is no suspension, acquire the lock. fn recover_write_lock( &mut self, - ptr: MemoryPointer, + ptr: Pointer, len: u64, lock_path: &AbsPlace<'tcx>, lock_region: Option, diff --git a/src/operator.rs b/src/operator.rs index 557e07975d73b..721b4f0bfddab 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -1,4 +1,5 @@ use rustc::ty; +use rustc::ty::layout::Primitive; use rustc::mir; use super::*; @@ -9,38 +10,58 @@ pub trait EvalContextExt<'tcx> { fn ptr_op( &self, bin_op: mir::BinOp, - left: PrimVal, + left: Scalar, left_ty: ty::Ty<'tcx>, - right: PrimVal, + right: Scalar, right_ty: ty::Ty<'tcx>, - ) -> EvalResult<'tcx, Option<(PrimVal, bool)>>; + ) -> EvalResult<'tcx, Option<(Scalar, bool)>>; fn ptr_int_arithmetic( &self, bin_op: mir::BinOp, - left: MemoryPointer, + left: Pointer, right: i128, signed: bool, - ) -> EvalResult<'tcx, (PrimVal, bool)>; + ) -> EvalResult<'tcx, (Scalar, bool)>; } impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super::Evaluator<'tcx>> { fn ptr_op( &self, bin_op: mir::BinOp, - left: PrimVal, + left: Scalar, left_ty: ty::Ty<'tcx>, - right: PrimVal, + right: Scalar, right_ty: ty::Ty<'tcx>, - ) -> EvalResult<'tcx, Option<(PrimVal, bool)>> { - use rustc::mir::interpret::PrimValKind::*; + ) -> EvalResult<'tcx, Option<(Scalar, bool)>> { use rustc::mir::BinOp::*; - let usize = PrimValKind::from_uint_size(self.memory.pointer_size()); - let isize = PrimValKind::from_int_size(self.memory.pointer_size()); - let left_kind = self.ty_to_primval_kind(left_ty)?; - let right_kind = self.ty_to_primval_kind(right_ty)?; + use rustc::ty::layout::Integer::*; + let usize = Primitive::Int(match self.memory.pointer_size().bytes() { + 1 => I8, + 2 => I16, + 4 => I32, + 8 => I64, + 16 => I128, + _ => unreachable!(), + }, false); + let isize = Primitive::Int(match self.memory.pointer_size().bytes() { + 1 => I8, + 2 => I16, + 4 => I32, + 8 => I64, + 16 => I128, + _ => unreachable!(), + }, true); + let left_kind = match self.layout_of(left_ty)?.abi { + ty::layout::Abi::Scalar(ref scalar) => scalar.value, + _ => Err(EvalErrorKind::TypeNotPrimitive(left_ty))?, + }; + let right_kind = match self.layout_of(right_ty)?.abi { + ty::layout::Abi::Scalar(ref scalar) => scalar.value, + _ => Err(EvalErrorKind::TypeNotPrimitive(right_ty))?, + }; match bin_op { - Offset if left_kind == Ptr && right_kind == usize => { + Offset if left_kind == Primitive::Pointer && right_kind == usize => { let pointee_ty = left_ty .builtin_deref(true) .expect("Offset called on non-ptr type") @@ -48,35 +69,35 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: let ptr = self.pointer_offset( left.into(), pointee_ty, - right.to_bytes()? as i64, + right.to_bits(self.memory.pointer_size())? as i64, )?; - Ok(Some((ptr.into_inner_primval(), false))) + Ok(Some((ptr, false))) } // These work on anything Eq if left_kind == right_kind => { let result = match (left, right) { - (PrimVal::Bytes(left), PrimVal::Bytes(right)) => left == right, - (PrimVal::Ptr(left), PrimVal::Ptr(right)) => left == right, - (PrimVal::Undef, _) | - (_, PrimVal::Undef) => return err!(ReadUndefBytes), + (Scalar::Bits { .. }, Scalar::Bits { .. }) => { + left.to_bits(self.memory.pointer_size())? == right.to_bits(self.memory.pointer_size())? + }, + (Scalar::Ptr(left), Scalar::Ptr(right)) => left == right, _ => false, }; - Ok(Some((PrimVal::from_bool(result), false))) + Ok(Some((Scalar::from_bool(result), false))) } Ne if left_kind == right_kind => { let result = match (left, right) { - (PrimVal::Bytes(left), PrimVal::Bytes(right)) => left != right, - (PrimVal::Ptr(left), PrimVal::Ptr(right)) => left != right, - (PrimVal::Undef, _) | - (_, PrimVal::Undef) => return err!(ReadUndefBytes), + (Scalar::Bits { .. }, Scalar::Bits { .. }) => { + left.to_bits(self.memory.pointer_size())? != right.to_bits(self.memory.pointer_size())? + }, + (Scalar::Ptr(left), Scalar::Ptr(right)) => left != right, _ => true, }; - Ok(Some((PrimVal::from_bool(result), false))) + Ok(Some((Scalar::from_bool(result), false))) } // These need both pointers to be in the same allocation Lt | Le | Gt | Ge | Sub if left_kind == right_kind && - (left_kind == Ptr || left_kind == usize || left_kind == isize) && + (left_kind == Primitive::Pointer || left_kind == usize || left_kind == isize) && left.is_ptr() && right.is_ptr() => { let left = left.to_ptr()?; let right = right.to_ptr()?; @@ -89,15 +110,15 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: Sub => { return self.binary_op( Sub, - PrimVal::Bytes(left.offset.bytes() as u128), + Scalar::Bits { bits: left.offset.bytes() as u128, defined: self.memory.pointer_size().bits() as u8 }, self.tcx.types.usize, - PrimVal::Bytes(right.offset.bytes() as u128), + Scalar::Bits { bits: right.offset.bytes() as u128, defined: self.memory.pointer_size().bits() as u8 }, self.tcx.types.usize, ).map(Some) } _ => bug!("We already established it has to be one of these operators."), }; - Ok(Some((PrimVal::from_bool(res), false))) + Ok(Some((Scalar::from_bool(res), false))) } else { // Both are pointers, but from different allocations. err!(InvalidPointerMath) @@ -106,23 +127,23 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: // These work if one operand is a pointer, the other an integer Add | BitAnd | Sub if left_kind == right_kind && (left_kind == usize || left_kind == isize) && - left.is_ptr() && right.is_bytes() => { + left.is_ptr() && right.is_bits() => { // Cast to i128 is fine as we checked the kind to be ptr-sized self.ptr_int_arithmetic( bin_op, left.to_ptr()?, - right.to_bytes()? as i128, + right.to_bits(self.memory.pointer_size())? as i128, left_kind == isize, ).map(Some) } Add | BitAnd if left_kind == right_kind && (left_kind == usize || left_kind == isize) && - left.is_bytes() && right.is_ptr() => { + left.is_bits() && right.is_ptr() => { // This is a commutative operation, just swap the operands self.ptr_int_arithmetic( bin_op, right.to_ptr()?, - left.to_bytes()? as i128, + left.to_bits(self.memory.pointer_size())? as i128, left_kind == isize, ).map(Some) } @@ -133,14 +154,14 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: fn ptr_int_arithmetic( &self, bin_op: mir::BinOp, - left: MemoryPointer, + left: Pointer, right: i128, signed: bool, - ) -> EvalResult<'tcx, (PrimVal, bool)> { + ) -> EvalResult<'tcx, (Scalar, bool)> { use rustc::mir::BinOp::*; - fn map_to_primval((res, over): (MemoryPointer, bool)) -> (PrimVal, bool) { - (PrimVal::Ptr(res), over) + fn map_to_primval((res, over): (Pointer, bool)) -> (Scalar, bool) { + (Scalar::Ptr(res), over) } Ok(match bin_op { @@ -157,10 +178,10 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: let right = right as u64; if right & base_mask == base_mask { // Case 1: The base address bits are all preserved, i.e., right is all-1 there - (PrimVal::Ptr(MemoryPointer::new(left.alloc_id, Size::from_bytes(left.offset.bytes() & right))), false) + (Scalar::Ptr(Pointer::new(left.alloc_id, Size::from_bytes(left.offset.bytes() & right))), false) } else if right & base_mask == 0 { // Case 2: The base address bits are all taken away, i.e., right is all-0 there - (PrimVal::from_u128((left.offset.bytes() & right) as u128), false) + (Scalar::Bits { bits: (left.offset.bytes() & right) as u128, defined: 128 }, false) } else { return err!(ReadPointerAsBytes); } diff --git a/src/tls.rs b/src/tls.rs index e55cbede23394..7f49509ef42ea 100644 --- a/src/tls.rs +++ b/src/tls.rs @@ -1,17 +1,17 @@ use rustc::{ty, mir}; -use super::{TlsKey, TlsEntry, EvalResult, EvalErrorKind, Pointer, Memory, Evaluator, Place, - StackPopCleanup, EvalContext}; +use super::{TlsKey, TlsEntry, EvalResult, EvalErrorKind, Scalar, ScalarExt, Memory, Evaluator, + Place, StackPopCleanup, EvalContext}; pub trait MemoryExt<'tcx> { fn create_tls_key(&mut self, dtor: Option>) -> TlsKey; fn delete_tls_key(&mut self, key: TlsKey) -> EvalResult<'tcx>; - fn load_tls(&mut self, key: TlsKey) -> EvalResult<'tcx, Pointer>; - fn store_tls(&mut self, key: TlsKey, new_data: Pointer) -> EvalResult<'tcx>; + fn load_tls(&mut self, key: TlsKey) -> EvalResult<'tcx, Scalar>; + fn store_tls(&mut self, key: TlsKey, new_data: Scalar) -> EvalResult<'tcx>; fn fetch_tls_dtor( &mut self, key: Option, - ) -> EvalResult<'tcx, Option<(ty::Instance<'tcx>, Pointer, TlsKey)>>; + ) -> EvalResult<'tcx, Option<(ty::Instance<'tcx>, Scalar, TlsKey)>>; } pub trait EvalContextExt<'tcx> { @@ -25,7 +25,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> MemoryExt<'tcx> for Memory<'a, 'mir, 'tcx, Evalu self.data.thread_local.insert( new_key, TlsEntry { - data: Pointer::null(), + data: Scalar::null(), dtor, }, ); @@ -43,7 +43,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> MemoryExt<'tcx> for Memory<'a, 'mir, 'tcx, Evalu }; } - fn load_tls(&mut self, key: TlsKey) -> EvalResult<'tcx, Pointer> { + fn load_tls(&mut self, key: TlsKey) -> EvalResult<'tcx, Scalar> { return match self.data.thread_local.get(&key) { Some(&TlsEntry { data, .. }) => { trace!("TLS key {} loaded: {:?}", key, data); @@ -53,7 +53,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> MemoryExt<'tcx> for Memory<'a, 'mir, 'tcx, Evalu }; } - fn store_tls(&mut self, key: TlsKey, new_data: Pointer) -> EvalResult<'tcx> { + fn store_tls(&mut self, key: TlsKey, new_data: Scalar) -> EvalResult<'tcx> { return match self.data.thread_local.get_mut(&key) { Some(&mut TlsEntry { ref mut data, .. }) => { trace!("TLS key {} stored: {:?}", key, new_data); @@ -85,19 +85,21 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> MemoryExt<'tcx> for Memory<'a, 'mir, 'tcx, Evalu fn fetch_tls_dtor( &mut self, key: Option, - ) -> EvalResult<'tcx, Option<(ty::Instance<'tcx>, Pointer, TlsKey)>> { + ) -> EvalResult<'tcx, Option<(ty::Instance<'tcx>, Scalar, TlsKey)>> { use std::collections::Bound::*; + + let thread_local = &mut self.data.thread_local; let start = match key { Some(key) => Excluded(key), None => Unbounded, }; for (&key, &mut TlsEntry { ref mut data, dtor }) in - self.data.thread_local.range_mut((start, Unbounded)) + thread_local.range_mut((start, Unbounded)) { if !data.is_null()? { if let Some(dtor) = dtor { let ret = Some((dtor, *data, key)); - *data = Pointer::null(); + *data = Scalar::null(); return Ok(ret); } } diff --git a/src/validation.rs b/src/validation.rs index deb1c5d5bc079..24ddffee9def6 100644 --- a/src/validation.rs +++ b/src/validation.rs @@ -12,7 +12,7 @@ use rustc::middle::const_val::ConstVal; use rustc_data_structures::indexed_vec::Idx; use rustc_mir::interpret::HasMemory; -use super::{EvalContext, Place, PlaceExtra, ValTy}; +use super::{EvalContext, Place, PlaceExtra, ValTy, ScalarExt}; use rustc::mir::interpret::{DynamicLifetime, AccessKind, EvalErrorKind, Value, EvalError, EvalResult}; use locks::MemoryExt; @@ -119,7 +119,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' Index(v) => { let value = self.frame().get_local(v)?; let ty = self.tcx.tcx.types.usize; - let n = self.value_to_primval(ValTy { value, ty })?.to_u64()?; + let n = self.value_to_scalar(ValTy { value, ty })?.to_u64()?; Index(n) }, ConstantIndex { offset, min_length, from_end } => @@ -652,7 +652,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' TyBool | TyFloat(_) | TyChar => { if mode.acquiring() { let val = self.read_place(query.place.1)?; - let val = self.value_to_primval(ValTy { value: val, ty: query.ty })?; + let val = self.value_to_scalar(ValTy { value: val, ty: query.ty })?; val.to_bytes()?; // TODO: Check if these are valid bool/float/codepoint/UTF-8 } From 1bd088a96c03ae38ccea15403487da6a10d978f3 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Wed, 30 May 2018 14:29:32 +0200 Subject: [PATCH 0091/3747] `memcmp` returns `i32` --- src/fn_call.rs | 4 ++-- src/lib.rs | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index ea0c5eb8b26e9..6a2255e577724 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -289,7 +289,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' use std::cmp::Ordering::*; match left_bytes.cmp(right_bytes) { - Less => -1i8, + Less => -1i32, Equal => 0, Greater => 1, } @@ -297,7 +297,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' self.write_scalar( dest, - Scalar::from_i8(result), + Scalar::from_i32(result), dest_ty, )?; } diff --git a/src/lib.rs b/src/lib.rs index e3c83c284db99..079560c0ca955 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -55,7 +55,7 @@ use validation::{ValidationQuery, AbsPlace}; pub trait ScalarExt { fn null() -> Self; - fn from_i8(i: i8) -> 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; @@ -72,8 +72,8 @@ impl ScalarExt for Scalar { Scalar::Bits { bits: 0, defined: 128 } } - fn from_i8(i: i8) -> Self { - Scalar::Bits { bits: i as i128 as u128, defined: 8 } + fn from_i32(i: i32) -> Self { + Scalar::Bits { bits: i as u32 as u128, defined: 32 } } fn from_u128(i: u128) -> Self { From 9655aaf3aa74e948935b1749fbdff2f8f774226b Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Wed, 30 May 2018 14:29:54 +0200 Subject: [PATCH 0092/3747] Comparing Scalar's with differend `defined` values is false --- src/intrinsic.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/intrinsic.rs b/src/intrinsic.rs index 3d537ea629c3b..1e8090dc18976 100644 --- a/src/intrinsic.rs +++ b/src/intrinsic.rs @@ -327,7 +327,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 != Scalar::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)?; From 062be7c047fa6c276b48c7b024725e90d3a93c25 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Wed, 30 May 2018 14:30:15 +0200 Subject: [PATCH 0093/3747] Comparing non-pointer-size types should be possible --- src/operator.rs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/operator.rs b/src/operator.rs index 721b4f0bfddab..f36e749dc9279 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -52,11 +52,13 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: 16 => I128, _ => unreachable!(), }, true); - let left_kind = match self.layout_of(left_ty)?.abi { + let left_layout = self.layout_of(left_ty)?; + let left_kind = match left_layout.abi { ty::layout::Abi::Scalar(ref scalar) => scalar.value, _ => Err(EvalErrorKind::TypeNotPrimitive(left_ty))?, }; - let right_kind = match self.layout_of(right_ty)?.abi { + let right_layout = self.layout_of(right_ty)?; + let right_kind = match right_layout.abi { ty::layout::Abi::Scalar(ref scalar) => scalar.value, _ => Err(EvalErrorKind::TypeNotPrimitive(right_ty))?, }; @@ -77,7 +79,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: Eq if left_kind == right_kind => { let result = match (left, right) { (Scalar::Bits { .. }, Scalar::Bits { .. }) => { - left.to_bits(self.memory.pointer_size())? == right.to_bits(self.memory.pointer_size())? + left.to_bits(left_layout.size)? == right.to_bits(right_layout.size)? }, (Scalar::Ptr(left), Scalar::Ptr(right)) => left == right, _ => false, @@ -87,7 +89,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: Ne if left_kind == right_kind => { let result = match (left, right) { (Scalar::Bits { .. }, Scalar::Bits { .. }) => { - left.to_bits(self.memory.pointer_size())? != right.to_bits(self.memory.pointer_size())? + left.to_bits(left_layout.size)? != right.to_bits(right_layout.size)? }, (Scalar::Ptr(left), Scalar::Ptr(right)) => left != right, _ => true, From 1d9c56ddf40fd43231c3caa167465167738ebfda Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Wed, 30 May 2018 15:59:04 +0200 Subject: [PATCH 0094/3747] TlsKey is messy because it changes types between systems --- src/fn_call.rs | 9 +++------ src/lib.rs | 2 +- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index 6a2255e577724..d1a483d2e8043 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -512,21 +512,18 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' self.write_null(dest, dest_ty)?; } "pthread_key_delete" => { - // The conversion into TlsKey here is a little fishy, but should work as long as usize >= libc::pthread_key_t - let key = self.value_to_scalar(args[0])?.to_u64()? as TlsKey; + 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)?; } "pthread_getspecific" => { - // The conversion into TlsKey here is a little fishy, but should work as long as usize >= libc::pthread_key_t - let key = self.value_to_scalar(args[0])?.to_u64()? as TlsKey; + let key = self.value_to_scalar(args[0])?.to_bytes()?; let ptr = self.memory.load_tls(key)?; self.write_ptr(dest, ptr, dest_ty)?; } "pthread_setspecific" => { - // The conversion into TlsKey here is a little fishy, but should work as long as usize >= libc::pthread_key_t - let key = self.value_to_scalar(args[0])?.to_u64()? as TlsKey; + let key = self.value_to_scalar(args[0])?.to_bytes()?; let new_ptr = self.into_ptr(args[1].value)?; self.memory.store_tls(key, new_ptr)?; diff --git a/src/lib.rs b/src/lib.rs index 079560c0ca955..6d7c0b05f80f7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -277,7 +277,7 @@ pub struct Evaluator<'tcx> { pub(crate) suspended: HashMap>>, } -pub type TlsKey = usize; +pub type TlsKey = u128; #[derive(Copy, Clone, Debug)] pub struct TlsEntry<'tcx> { From 77c8582031ca4084651d2cf365f81f19bbd50fcc Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Wed, 30 May 2018 17:43:27 +0200 Subject: [PATCH 0095/3747] `align_offset` intrinsic is now a lang item --- src/fn_call.rs | 12 ++++++++++++ src/intrinsic.rs | 8 -------- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index d1a483d2e8043..fdaa819c08f7a 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -135,6 +135,18 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' _ => {} } + if self.tcx.lang_items().align_offset_fn() == Some(instance.def.def_id()) { + // FIXME: return a real value in case the target allocation has an + // alignment bigger than the one requested + let n = u128::max_value(); + let amt = 128 - self.memory.pointer_size().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)?; + self.goto_block(return_to_block); + return Ok(true); + } + let mir = match self.load_mir(instance.def) { Ok(mir) => mir, Err(EvalError { kind: EvalErrorKind::NoMirFor(path), .. }) => { diff --git a/src/intrinsic.rs b/src/intrinsic.rs index 1e8090dc18976..cee2f1ab7682f 100644 --- a/src/intrinsic.rs +++ b/src/intrinsic.rs @@ -33,14 +33,6 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: let intrinsic_name = &self.tcx.item_name(instance.def_id()).as_str()[..]; match intrinsic_name { - "align_offset" => { - // FIXME: return a real value in case the target allocation has an - // alignment bigger than the one requested - let n = u128::max_value(); - let amt = 128 - self.memory.pointer_size().bytes() * 8; - self.write_scalar(dest, Scalar::from_u128((n << amt) >> amt), dest_layout.ty)?; - }, - "add_with_overflow" => { self.intrinsic_with_overflow( mir::BinOp::Add, From 8284b4e912baf72473c3696ce9e46cc334da18e4 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Wed, 30 May 2018 17:43:54 +0200 Subject: [PATCH 0096/3747] `to_u64` and `to_bytes` are horribly easy to use wrongly. --- src/fn_call.rs | 8 ++++---- src/lib.rs | 3 +++ 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index fdaa819c08f7a..72efcd6ede077 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -316,7 +316,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' "memrchr" => { let ptr = self.into_ptr(args[0].value)?; - let val = self.value_to_scalar(args[1])?.to_u64()? as u8; + let val = self.value_to_scalar(args[1])?.to_bytes()? as u8; let num = self.value_to_scalar(args[2])?.to_u64()?; if let Some(idx) = self.memory.read_bytes(ptr, Size::from_bytes(num))?.iter().rev().position( |&c| c == val, @@ -331,7 +331,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' "memchr" => { let ptr = self.into_ptr(args[0].value)?; - let val = self.value_to_scalar(args[1])?.to_u64()? as u8; + let val = self.value_to_scalar(args[1])?.to_bytes()? as u8; let num = self.value_to_scalar(args[2])?.to_u64()?; if let Some(idx) = self.memory.read_bytes(ptr, Size::from_bytes(num))?.iter().position( |&c| c == val, @@ -414,9 +414,9 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' } "write" => { - let fd = self.value_to_scalar(args[0])?.to_u64()?; + let fd = self.value_to_scalar(args[0])?.to_bytes()?; let buf = self.into_ptr(args[1].value)?; - let n = self.value_to_scalar(args[2])?.to_u64()?; + 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 { // stdout/stderr diff --git a/src/lib.rs b/src/lib.rs index 6d7c0b05f80f7..550965573cb47 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -64,6 +64,9 @@ pub trait ScalarExt { fn from_f64(f: f64) -> Self; fn to_u64(self) -> EvalResult<'static, u64>; fn is_null(self) -> EvalResult<'static, 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 fn to_bytes(self) -> EvalResult<'static, u128>; } From cec51f8513bc1fa6344b702a4e5036c4961fda04 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Sun, 3 Jun 2018 11:54:17 +0200 Subject: [PATCH 0097/3747] Use correct bit size when reading usize values --- src/fn_call.rs | 30 +++++++++++++++--------------- src/lib.rs | 6 +++--- src/validation.rs | 2 +- 3 files changed, 19 insertions(+), 19 deletions(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index 72efcd6ede077..36cc29a2b5b5b 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -194,7 +194,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' match &link_name[..] { "malloc" => { - let size = self.value_to_scalar(args[0])?.to_u64()?; + let size = self.value_to_scalar(args[0])?.to_usize(self)?; if size == 0 { self.write_null(dest, dest_ty)?; } else { @@ -221,7 +221,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' // // libc::syscall(NR_GETRANDOM, buf.as_mut_ptr(), buf.len(), GRND_NONBLOCK) // is called if a `HashMap` is created the regular way. - match self.value_to_scalar(args[0])?.to_u64()? { + match self.value_to_scalar(args[0])?.to_usize(self)? { 318 | 511 => { return err!(Unimplemented( "miri does not support random number generators".to_owned(), @@ -293,7 +293,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' "memcmp" => { let left = self.into_ptr(args[0].value)?; let right = self.into_ptr(args[1].value)?; - let n = Size::from_bytes(self.value_to_scalar(args[2])?.to_u64()?); + let n = Size::from_bytes(self.value_to_scalar(args[2])?.to_usize(self)?); let result = { let left_bytes = self.memory.read_bytes(left, n)?; @@ -317,7 +317,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' "memrchr" => { let ptr = self.into_ptr(args[0].value)?; let val = self.value_to_scalar(args[1])?.to_bytes()? as u8; - let num = self.value_to_scalar(args[2])?.to_u64()?; + 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( |&c| c == val, ) @@ -332,7 +332,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' "memchr" => { let ptr = self.into_ptr(args[0].value)?; let val = self.value_to_scalar(args[1])?.to_bytes()? as u8; - let num = self.value_to_scalar(args[2])?.to_u64()?; + 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( |&c| c == val, ) @@ -457,7 +457,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' } "sysconf" => { - let name = self.value_to_scalar(args[0])?.to_u64()?; + let name = self.value_to_scalar(args[0])?.to_usize(self)?; trace!("sysconf() called with name {}", name); // cache the sysconf integers via miri's global cache @@ -646,8 +646,8 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' match &path[..] { // Allocators are magic. They have no MIR, even when the rest of libstd does. "alloc::alloc::::__rust_alloc" => { - let size = self.value_to_scalar(args[0])?.to_u64()?; - let align = self.value_to_scalar(args[1])?.to_u64()?; + let size = self.value_to_scalar(args[0])?.to_usize(self)?; + let align = self.value_to_scalar(args[1])?.to_usize(self)?; if size == 0 { return err!(HeapAllocZeroBytes); } @@ -660,8 +660,8 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' self.write_scalar(dest, Scalar::Ptr(ptr), dest_ty)?; } "alloc::alloc::::__rust_alloc_zeroed" => { - let size = self.value_to_scalar(args[0])?.to_u64()?; - let align = self.value_to_scalar(args[1])?.to_u64()?; + let size = self.value_to_scalar(args[0])?.to_usize(self)?; + let align = self.value_to_scalar(args[1])?.to_usize(self)?; if size == 0 { return err!(HeapAllocZeroBytes); } @@ -676,8 +676,8 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' } "alloc::alloc::::__rust_dealloc" => { let ptr = self.into_ptr(args[0].value)?.to_ptr()?; - let old_size = self.value_to_scalar(args[1])?.to_u64()?; - let align = self.value_to_scalar(args[2])?.to_u64()?; + 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 { return err!(HeapAllocZeroBytes); } @@ -692,9 +692,9 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' } "alloc::alloc::::__rust_realloc" => { let ptr = self.into_ptr(args[0].value)?.to_ptr()?; - let old_size = self.value_to_scalar(args[1])?.to_u64()?; - let align = self.value_to_scalar(args[2])?.to_u64()?; - let new_size = self.value_to_scalar(args[3])?.to_u64()?; + 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)?; if old_size == 0 || new_size == 0 { return err!(HeapAllocZeroBytes); } diff --git a/src/lib.rs b/src/lib.rs index 550965573cb47..a29211df996bf 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -62,7 +62,7 @@ pub trait ScalarExt { fn from_isize(i: i64, ptr_size: Size) -> Self; fn from_f32(f: f32) -> Self; fn from_f64(f: f64) -> Self; - fn to_u64(self) -> EvalResult<'static, u64>; + fn 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>; /// 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 @@ -103,8 +103,8 @@ impl ScalarExt for Scalar { Scalar::Bits { bits: f.to_bits() as u128, defined: 64 } } - fn to_u64(self) -> EvalResult<'static, u64> { - let b = self.to_bits(Size::from_bits(64))?; + fn to_usize<'a, 'mir, 'tcx>(self, ecx: &rustc_mir::interpret::EvalContext<'a, 'mir, 'tcx, Evaluator<'tcx>>) -> EvalResult<'static, u64> { + let b = self.to_bits(ecx.memory.pointer_size())?; assert_eq!(b as u64 as u128, b); Ok(b as u64) } diff --git a/src/validation.rs b/src/validation.rs index 24ddffee9def6..d82a345c2512a 100644 --- a/src/validation.rs +++ b/src/validation.rs @@ -119,7 +119,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' Index(v) => { let value = self.frame().get_local(v)?; let ty = self.tcx.tcx.types.usize; - let n = self.value_to_scalar(ValTy { value, ty })?.to_u64()?; + let n = self.value_to_scalar(ValTy { value, ty })?.to_usize(self)?; Index(n) }, ConstantIndex { offset, min_length, from_end } => From 675587280f5cee0ea99ebb4c4f70043e89aa1aed Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Sun, 3 Jun 2018 12:13:30 +0200 Subject: [PATCH 0098/3747] Update cargo-miri --- cargo-miri-test/Cargo.lock | 12 ++++++------ src/bin/cargo-miri.rs | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/cargo-miri-test/Cargo.lock b/cargo-miri-test/Cargo.lock index 8b2387fa64109..85c3c08dba019 100644 --- a/cargo-miri-test/Cargo.lock +++ b/cargo-miri-test/Cargo.lock @@ -1,14 +1,14 @@ -[root] +[[package]] +name = "byteorder" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] name = "cargo-miri-test" version = "0.1.0" dependencies = [ "byteorder 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "byteorder" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - [metadata] "checksum byteorder 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c40977b0ee6b9885c9013cd41d9feffdd22deb3bb4dc3a71d901cc7a77de18c8" diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 39a41583a39e0..010f25e8152dc 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -154,7 +154,7 @@ fn main() { // this check ensures that dependencies are built but not interpreted and the final crate is // interpreted but not built - let miri_enabled = std::env::args().any(|s| s == "-Zno-trans"); + let miri_enabled = std::env::args().any(|s| s == "--emit=dep-info,metadata"); let mut command = if miri_enabled { let mut path = std::env::current_exe().expect("current executable path invalid"); @@ -193,7 +193,7 @@ where if !found_dashes { args.push("--".to_owned()); } - args.push("-Zno-trans".to_owned()); + args.push("--emit=dep-info,metadata".to_owned()); args.push("--cfg".to_owned()); args.push(r#"feature="cargo-miri""#.to_owned()); From e1734470e780e05a3366a2f74cfa25ea88a518a5 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Sun, 3 Jun 2018 12:54:43 +0200 Subject: [PATCH 0099/3747] Reenable the rustc tester --- rustc_tests/Cargo.lock | 203 +++++++++++++++++++++++++--------------- rustc_tests/src/main.rs | 10 +- src/lib.rs | 1 - 3 files changed, 131 insertions(+), 83 deletions(-) diff --git a/rustc_tests/Cargo.lock b/rustc_tests/Cargo.lock index a1e273a96bdb8..9cf4fe0d1342a 100644 --- a/rustc_tests/Cargo.lock +++ b/rustc_tests/Cargo.lock @@ -1,10 +1,3 @@ -[root] -name = "rustc_tests" -version = "0.1.0" -dependencies = [ - "miri 0.1.0", -] - [[package]] name = "aho-corasick" version = "0.6.3" @@ -14,26 +7,13 @@ dependencies = [ ] [[package]] -name = "backtrace" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "backtrace-sys 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "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.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" +name = "atty" +version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "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)", + "termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -47,40 +27,33 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] -name = "dbghelp-sys" -version = "0.2.0" +name = "env_logger" +version = "0.5.10" 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)", + "atty 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", + "humantime 1.1.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)", + "termcolor 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] -name = "env_logger" -version = "0.4.3" +name = "humantime" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] -name = "gcc" -version = "0.3.53" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "kernel32-sys" -version = "0.2.2" +name = "lazy_static" +version = "0.2.8" 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" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -90,20 +63,23 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "log" -version = "0.3.8" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", +] [[package]] -name = "log_settings" -version = "0.1.1" +name = "memchr" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.30 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "memchr" -version = "1.0.1" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "libc 0.2.30 (registry+https://github.com/rust-lang/crates.io-index)", @@ -114,10 +90,28 @@ name = "miri" version = "0.1.0" dependencies = [ "byteorder 1.1.0 (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)", - "rustc_miri 0.1.0", + "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 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "quick-error" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "redox_syscall" +version = "0.1.40" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "redox_termios" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -132,26 +126,54 @@ dependencies = [ "utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "regex" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "aho-corasick 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "regex-syntax 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "thread_local 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "regex-syntax" version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] -name = "rustc-demangle" -version = "0.1.5" +name = "regex-syntax" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "ucd-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] [[package]] -name = "rustc_miri" +name = "rustc_tests" version = "0.1.0" dependencies = [ - "backtrace 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "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)", - "log_settings 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "miri 0.1.0", +] + +[[package]] +name = "termcolor" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "wincolor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "termion" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.30 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -163,6 +185,11 @@ dependencies = [ "unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "ucd-util" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "unreachable" version = "1.0.0" @@ -183,35 +210,59 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "winapi" -version = "0.2.8" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", +] [[package]] -name = "winapi-build" -version = "0.1.1" +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "wincolor" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi 0.3.4 (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.3 (registry+https://github.com/rust-lang/crates.io-index)" = "99f2ce94e22b8e664d95c57fff45b98a966c2252b60691d0b7aeeccd88d70983" -"checksum backtrace-sys 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "afccc5772ba333abccdf60d55200fa3406f8c59dcf54d5f7998c9107d3799c7c" +"checksum atty 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "2fc4a1aa4c24c0718a250f0681885c1af91419d242f29eb8f2ab28502d80dbd1" "checksum byteorder 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ff81738b726f5d099632ceaffe7fb65b90212e8dce59d518729e7e8634032d3d" "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 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 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.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 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" +"checksum memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "796fba70e76612589ed2ce7f45282f5af869e0fdd7cc6199fa1aa1f1d591ba9d" +"checksum quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9274b940887ce9addde99c4eee6b5c44cc494b182b97e73dc8ffdcb3397fd3f0" +"checksum redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "c214e91d3ecf43e9a4e41e578973adeb14b474f2bee858742d127af75a0112b1" +"checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76" "checksum regex 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1731164734096285ec2a5ec7fea5248ae2f5485b3feeb0115af4fda2183b2d1b" +"checksum regex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "75ecf88252dce580404a22444fc7d626c01815debba56a7f4f536772a5ff19d3" "checksum regex-syntax 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ad890a5eef7953f55427c50575c680c42841653abd2b028b68cd223d157f62db" -"checksum rustc-demangle 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "aee45432acc62f7b9a108cc054142dac51f979e69e71ddce7d6fc7adf29e817e" +"checksum regex-syntax 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8f1ac0f60d675cc6cf13a20ec076568254472551051ad5dd050364d70671bf6b" +"checksum termcolor 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "adc4587ead41bf016f11af03e55a624c06568b5a19db4e90fde573d805074f83" +"checksum termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "689a3bdfaab439fd92bc87df5c4c78417d3cbe537487274e9b0b2dce76e92096" "checksum thread_local 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "1697c4b57aeeb7a536b647165a2825faddffb1d3bad386d507709bd51a90bb14" +"checksum ucd-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "fd2be2d6639d0f8fe6cdda291ad456e23629558d466e2789d2c3e9892bda285d" "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" +"checksum winapi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "04e3bd221fcbe8a271359c04f21a76db7d0c6028862d1bb5512d85e1e2eb5bb3" +"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +"checksum wincolor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "eeb06499a3a4d44302791052df005d5232b927ed1a9658146d842165c4de7767" diff --git a/rustc_tests/src/main.rs b/rustc_tests/src/main.rs index 77e4a3df406b7..ecc5287c72771 100644 --- a/rustc_tests/src/main.rs +++ b/rustc_tests/src/main.rs @@ -4,7 +4,7 @@ extern crate getopts; extern crate rustc; extern crate rustc_driver; extern crate rustc_errors; -extern crate rustc_trans_utils; +extern crate rustc_codegen_utils; extern crate syntax; use std::path::{PathBuf, Path}; @@ -19,7 +19,7 @@ use rustc_driver::{Compilation, CompilerCalls, RustcDefaultCalls}; use rustc_driver::driver::{CompileState, CompileController}; use rustc::session::config::{self, Input, ErrorOutputType}; use rustc::hir::{self, itemlikevisit}; -use rustc_trans_utils::trans_crate::TransCrate; +use rustc_codegen_utils::codegen_backend::CodegenBackend; use rustc::ty::TyCtxt; use syntax::ast; @@ -53,7 +53,7 @@ impl<'a> CompilerCalls<'a> for MiriCompilerCalls { } fn late_callback( &mut self, - trans: &TransCrate, + trans: &CodegenBackend, matches: &getopts::Matches, sess: &Session, cstore: &CrateStore, @@ -104,9 +104,7 @@ fn after_analysis<'a, 'tcx>(state: &mut CompileState<'a, 'tcx>) { state.hir_crate.unwrap().visit_all_item_likes(&mut Visitor(tcx, state)); } else if let Some((entry_node_id, _, _)) = *state.session.entry_fn.borrow() { let entry_def_id = tcx.hir.local_def_id(entry_node_id); - let start_wrapper = tcx.lang_items().start_fn().and_then(|start_fn| - if tcx.is_mir_available(start_fn) { Some(start_fn) } else { None }); - miri::eval_main(tcx, entry_def_id, start_wrapper); + miri::eval_main(tcx, entry_def_id, None); state.session.abort_if_errors(); } else { diff --git a/src/lib.rs b/src/lib.rs index a29211df996bf..1ba763349aa7d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -265,7 +265,6 @@ pub fn eval_main<'a, 'tcx: 'a>( } } } - ::std::process::exit(1); } } } From 3db0568c408e0b22088d889ad95fccd8659f1fcc Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Wed, 9 May 2018 15:54:45 +0200 Subject: [PATCH 0100/3747] Fix a couple of tests --- tests/compile-fail/copy_nonoverlapping.rs | 2 -- tests/compile-fail/deallocate-bad-alignment.rs | 8 ++++---- tests/compile-fail/deallocate-bad-size.rs | 8 ++++---- tests/compile-fail/deallocate-twice.rs | 10 +++++----- tests/compile-fail/never_transmute_humans.rs | 17 ----------------- tests/compile-fail/out_of_bounds_ptr_2.rs | 2 +- tests/compile-fail/ptr_offset_overflow.rs | 2 +- .../compile-fail/reallocate-bad-alignment-2.rs | 16 ---------------- tests/compile-fail/reallocate-bad-alignment.rs | 16 ---------------- tests/compile-fail/reallocate-bad-size.rs | 8 ++++---- tests/compile-fail/reallocate-change-alloc.rs | 10 +++++----- tests/compile-fail/reallocate-dangling.rs | 10 +++++----- tests/compile-fail/repeat.rs | 3 ++- tests/compile-fail/repeat2.rs | 2 ++ tests/compile-fail/transmute_fat.rs | 3 +-- tests/compile-fail/transmute_fat2.rs | 2 -- tests/compile-fail/validation_aliasing_mut1.rs | 2 ++ tests/compile-fail/validation_aliasing_mut2.rs | 2 ++ tests/compile-fail/validation_aliasing_mut3.rs | 2 ++ tests/compile-fail/validation_aliasing_mut4.rs | 2 ++ .../validation_buggy_as_mut_slice.rs | 2 ++ .../validation_buggy_split_at_mut.rs | 2 ++ tests/compile-fail/validation_illegal_write.rs | 2 ++ tests/compile-fail/validation_lock_confusion.rs | 2 ++ .../validation_pointer_smuggling.rs | 2 ++ tests/compile-fail/validation_recover1.rs | 2 ++ tests/compile-fail/validation_recover2.rs | 2 ++ tests/compile-fail/validation_recover3.rs | 2 ++ tests/compile-fail/validation_undef.rs | 2 ++ 29 files changed, 60 insertions(+), 85 deletions(-) delete mode 100644 tests/compile-fail/never_transmute_humans.rs delete mode 100644 tests/compile-fail/reallocate-bad-alignment-2.rs delete mode 100644 tests/compile-fail/reallocate-bad-alignment.rs diff --git a/tests/compile-fail/copy_nonoverlapping.rs b/tests/compile-fail/copy_nonoverlapping.rs index f4acbadfd549d..18fbc61b6d070 100644 --- a/tests/compile-fail/copy_nonoverlapping.rs +++ b/tests/compile-fail/copy_nonoverlapping.rs @@ -10,8 +10,6 @@ #![feature(core_intrinsics)] -use std::intrinsics::*; - //error-pattern: copy_nonoverlapping called on overlapping ranges fn main() { diff --git a/tests/compile-fail/deallocate-bad-alignment.rs b/tests/compile-fail/deallocate-bad-alignment.rs index b64740de81f4d..36e99cb11f725 100644 --- a/tests/compile-fail/deallocate-bad-alignment.rs +++ b/tests/compile-fail/deallocate-bad-alignment.rs @@ -2,14 +2,14 @@ extern crate alloc; -use alloc::heap::Heap; -use alloc::allocator::*; +use alloc::alloc::Global; +use std::alloc::*; // error-pattern: incorrect alloc info: expected size 1 and align 2, got size 1 and align 1 fn main() { unsafe { - let x = Heap.alloc(Layout::from_size_align_unchecked(1, 1)).unwrap(); - Heap.dealloc(x, Layout::from_size_align_unchecked(1, 2)); + let x = Global.alloc(Layout::from_size_align_unchecked(1, 1)); + Global.dealloc(x, Layout::from_size_align_unchecked(1, 2)); } } diff --git a/tests/compile-fail/deallocate-bad-size.rs b/tests/compile-fail/deallocate-bad-size.rs index f5b82f65d2af3..f1271cefd1ac1 100644 --- a/tests/compile-fail/deallocate-bad-size.rs +++ b/tests/compile-fail/deallocate-bad-size.rs @@ -2,14 +2,14 @@ extern crate alloc; -use alloc::heap::Heap; -use alloc::allocator::*; +use alloc::alloc::Global; +use std::alloc::*; // error-pattern: incorrect alloc info: expected size 2 and align 1, got size 1 and align 1 fn main() { unsafe { - let x = Heap.alloc(Layout::from_size_align_unchecked(1, 1)).unwrap(); - Heap.dealloc(x, Layout::from_size_align_unchecked(2, 1)); + let x = Global.alloc(Layout::from_size_align_unchecked(1, 1)); + Global.dealloc(x, Layout::from_size_align_unchecked(2, 1)); } } diff --git a/tests/compile-fail/deallocate-twice.rs b/tests/compile-fail/deallocate-twice.rs index e11df0eb4147d..58fcb7409495c 100644 --- a/tests/compile-fail/deallocate-twice.rs +++ b/tests/compile-fail/deallocate-twice.rs @@ -2,15 +2,15 @@ extern crate alloc; -use alloc::heap::Heap; -use alloc::allocator::*; +use alloc::alloc::Global; +use std::alloc::*; // error-pattern: tried to deallocate dangling pointer fn main() { unsafe { - let x = Heap.alloc(Layout::from_size_align_unchecked(1, 1)).unwrap(); - Heap.dealloc(x, Layout::from_size_align_unchecked(1, 1)); - Heap.dealloc(x, Layout::from_size_align_unchecked(1, 1)); + let x = Global.alloc(Layout::from_size_align_unchecked(1, 1)); + Global.dealloc(x, Layout::from_size_align_unchecked(1, 1)); + Global.dealloc(x, Layout::from_size_align_unchecked(1, 1)); } } diff --git a/tests/compile-fail/never_transmute_humans.rs b/tests/compile-fail/never_transmute_humans.rs deleted file mode 100644 index 7390596cf7fa6..0000000000000 --- a/tests/compile-fail/never_transmute_humans.rs +++ /dev/null @@ -1,17 +0,0 @@ -// This should fail even without validation -// compile-flags: -Zmir-emit-validate=0 - -#![feature(never_type)] -#![allow(unreachable_code)] -#![allow(unused_variables)] - -struct Human; - -fn main() { - let x: ! = unsafe { - std::mem::transmute::(Human) //~ ERROR entered unreachable code - }; - f(x) -} - -fn f(x: !) -> ! { x } diff --git a/tests/compile-fail/out_of_bounds_ptr_2.rs b/tests/compile-fail/out_of_bounds_ptr_2.rs index f7546494574b0..e19a616a19165 100644 --- a/tests/compile-fail/out_of_bounds_ptr_2.rs +++ b/tests/compile-fail/out_of_bounds_ptr_2.rs @@ -1,4 +1,4 @@ -// error-pattern: overflowing math +// error-pattern: attempt to add with overflow fn main() { let v = [0i8; 4]; let x = &v as *const i8; diff --git a/tests/compile-fail/ptr_offset_overflow.rs b/tests/compile-fail/ptr_offset_overflow.rs index 578468c3399bb..32ab2daebf0d0 100644 --- a/tests/compile-fail/ptr_offset_overflow.rs +++ b/tests/compile-fail/ptr_offset_overflow.rs @@ -1,4 +1,4 @@ -//error-pattern: overflowing math +//error-pattern: attempt to add with overflow fn main() { let v = [1i8, 2]; let x = &v[1] as *const i8; diff --git a/tests/compile-fail/reallocate-bad-alignment-2.rs b/tests/compile-fail/reallocate-bad-alignment-2.rs deleted file mode 100644 index fae8246c5d29c..0000000000000 --- a/tests/compile-fail/reallocate-bad-alignment-2.rs +++ /dev/null @@ -1,16 +0,0 @@ -#![feature(alloc, allocator_api)] - -extern crate alloc; - -use alloc::heap::Heap; -use alloc::allocator::*; - -// error-pattern: incorrect alloc info: expected size 1 and align 2, got size 1 and align 1 - -fn main() { - unsafe { - let x = Heap.alloc(Layout::from_size_align_unchecked(1, 1)).unwrap(); - // Try realloc with a too big alignment. - let _y = Heap.realloc(x, Layout::from_size_align_unchecked(1, 2), Layout::from_size_align_unchecked(1, 1)).unwrap(); - } -} diff --git a/tests/compile-fail/reallocate-bad-alignment.rs b/tests/compile-fail/reallocate-bad-alignment.rs deleted file mode 100644 index 6a928de07eec3..0000000000000 --- a/tests/compile-fail/reallocate-bad-alignment.rs +++ /dev/null @@ -1,16 +0,0 @@ -#![feature(alloc, allocator_api)] - -extern crate alloc; - -use alloc::heap::Heap; -use alloc::allocator::*; - -// error-pattern: incorrect alloc info: expected size 1 and align 1, got size 1 and align 2 - -fn main() { - unsafe { - let x = Heap.alloc(Layout::from_size_align_unchecked(1, 2)).unwrap(); - // Try realloc with a too small alignment. - let _y = Heap.realloc(x, Layout::from_size_align_unchecked(1, 1), Layout::from_size_align_unchecked(1, 2)).unwrap(); - } -} diff --git a/tests/compile-fail/reallocate-bad-size.rs b/tests/compile-fail/reallocate-bad-size.rs index d57c610d9337f..d75c195d521e0 100644 --- a/tests/compile-fail/reallocate-bad-size.rs +++ b/tests/compile-fail/reallocate-bad-size.rs @@ -2,14 +2,14 @@ extern crate alloc; -use alloc::heap::Heap; -use alloc::allocator::*; +use alloc::alloc::Global; +use std::alloc::*; // error-pattern: incorrect alloc info: expected size 2 and align 1, got size 1 and align 1 fn main() { unsafe { - let x = Heap.alloc(Layout::from_size_align_unchecked(1, 1)).unwrap(); - let _y = Heap.realloc(x, Layout::from_size_align_unchecked(2, 1), Layout::from_size_align_unchecked(1, 1)).unwrap(); + let x = Global.alloc(Layout::from_size_align_unchecked(1, 1)); + let _y = Global.realloc(x, Layout::from_size_align_unchecked(2, 1), 1); } } diff --git a/tests/compile-fail/reallocate-change-alloc.rs b/tests/compile-fail/reallocate-change-alloc.rs index 290c966a2bc8a..8a788104d8697 100644 --- a/tests/compile-fail/reallocate-change-alloc.rs +++ b/tests/compile-fail/reallocate-change-alloc.rs @@ -2,13 +2,13 @@ extern crate alloc; -use alloc::heap::Heap; -use alloc::allocator::*; +use alloc::alloc::Global; +use std::alloc::*; fn main() { unsafe { - let x = Heap.alloc(Layout::from_size_align_unchecked(1, 1)).unwrap(); - let _y = Heap.realloc(x, Layout::from_size_align_unchecked(1, 1), Layout::from_size_align_unchecked(1, 1)).unwrap(); - let _z = *x; //~ ERROR: dangling pointer was dereferenced + let x = Global.alloc(Layout::from_size_align_unchecked(1, 1)); + let _y = Global.realloc(x, Layout::from_size_align_unchecked(1, 1), 1); + let _z = *(x as *mut u8); //~ ERROR: dangling pointer was dereferenced } } diff --git a/tests/compile-fail/reallocate-dangling.rs b/tests/compile-fail/reallocate-dangling.rs index 6225879a5a2a0..39b60407160e4 100644 --- a/tests/compile-fail/reallocate-dangling.rs +++ b/tests/compile-fail/reallocate-dangling.rs @@ -2,15 +2,15 @@ extern crate alloc; -use alloc::heap::Heap; -use alloc::allocator::*; +use alloc::alloc::Global; +use std::alloc::*; // error-pattern: dangling pointer was dereferenced fn main() { unsafe { - let x = Heap.alloc(Layout::from_size_align_unchecked(1, 1)).unwrap(); - Heap.dealloc(x, Layout::from_size_align_unchecked(1, 1)); - Heap.realloc(x, Layout::from_size_align_unchecked(1, 1), Layout::from_size_align_unchecked(1, 1)); + let x = Global.alloc(Layout::from_size_align_unchecked(1, 1)); + Global.dealloc(x, Layout::from_size_align_unchecked(1, 1)); + Global.realloc(x, Layout::from_size_align_unchecked(1, 1), 1); } } diff --git a/tests/compile-fail/repeat.rs b/tests/compile-fail/repeat.rs index abe89e233e7cd..0367580f4ce9b 100644 --- a/tests/compile-fail/repeat.rs +++ b/tests/compile-fail/repeat.rs @@ -1,5 +1,6 @@ +// error-pattern the type `[u8; + fn main() { let data: [u8; std::usize::MAX] = [42; std::usize::MAX]; - //~^ ERROR: rustc layout computation failed: SizeOverflow([u8; assert_eq!(data.len(), 1024); } diff --git a/tests/compile-fail/repeat2.rs b/tests/compile-fail/repeat2.rs index 61aa855a798f8..16cd9c1df8135 100644 --- a/tests/compile-fail/repeat2.rs +++ b/tests/compile-fail/repeat2.rs @@ -1,3 +1,5 @@ +// ignore-test + fn main() { let data: [u8; 1024*1024*1024] = [42; 1024*1024*1024]; //~^ ERROR: tried to allocate diff --git a/tests/compile-fail/transmute_fat.rs b/tests/compile-fail/transmute_fat.rs index 7d5d95a1dc6da..a2ebb6b21aa24 100644 --- a/tests/compile-fail/transmute_fat.rs +++ b/tests/compile-fail/transmute_fat.rs @@ -1,6 +1,5 @@ // This should fail even without validation // compile-flags: -Zmir-emit-validate=0 -#![feature(i128_type)] fn main() { #[cfg(target_pointer_width="64")] @@ -11,5 +10,5 @@ fn main() { let bad = unsafe { std::mem::transmute::<&[u8], u64>(&[1u8]) }; - bad + 1; //~ ERROR a raw memory access tried to access part of a pointer value as raw bytes + let _ = bad + 1; //~ ERROR a raw memory access tried to access part of a pointer value as raw bytes } diff --git a/tests/compile-fail/transmute_fat2.rs b/tests/compile-fail/transmute_fat2.rs index 028ed613eee71..3121a139d9204 100644 --- a/tests/compile-fail/transmute_fat2.rs +++ b/tests/compile-fail/transmute_fat2.rs @@ -1,5 +1,3 @@ -#![feature(i128_type)] - fn main() { #[cfg(target_pointer_width="64")] let bad = unsafe { diff --git a/tests/compile-fail/validation_aliasing_mut1.rs b/tests/compile-fail/validation_aliasing_mut1.rs index 86aa57447fe60..e812e13e702ca 100644 --- a/tests/compile-fail/validation_aliasing_mut1.rs +++ b/tests/compile-fail/validation_aliasing_mut1.rs @@ -1,3 +1,5 @@ +// ignore-test validation_op is disabled + #![allow(unused_variables)] mod safe { diff --git a/tests/compile-fail/validation_aliasing_mut2.rs b/tests/compile-fail/validation_aliasing_mut2.rs index ed7497e5e5460..36ebcc2b4ac6f 100644 --- a/tests/compile-fail/validation_aliasing_mut2.rs +++ b/tests/compile-fail/validation_aliasing_mut2.rs @@ -1,3 +1,5 @@ +// ignore-test validation_op is disabled + #![allow(unused_variables)] mod safe { diff --git a/tests/compile-fail/validation_aliasing_mut3.rs b/tests/compile-fail/validation_aliasing_mut3.rs index 69fbbc167ca0f..ad50fbd61b451 100644 --- a/tests/compile-fail/validation_aliasing_mut3.rs +++ b/tests/compile-fail/validation_aliasing_mut3.rs @@ -1,3 +1,5 @@ +// ignore-test validation_op is disabled + #![allow(unused_variables)] mod safe { diff --git a/tests/compile-fail/validation_aliasing_mut4.rs b/tests/compile-fail/validation_aliasing_mut4.rs index 3dac55aeaac95..a0f0a3cf9753a 100644 --- a/tests/compile-fail/validation_aliasing_mut4.rs +++ b/tests/compile-fail/validation_aliasing_mut4.rs @@ -1,3 +1,5 @@ +// ignore-test validation_op is disabled + #![allow(unused_variables)] mod safe { diff --git a/tests/compile-fail/validation_buggy_as_mut_slice.rs b/tests/compile-fail/validation_buggy_as_mut_slice.rs index 98eca8d3607f7..282e536ce9b73 100644 --- a/tests/compile-fail/validation_buggy_as_mut_slice.rs +++ b/tests/compile-fail/validation_buggy_as_mut_slice.rs @@ -1,3 +1,5 @@ +// ignore-test validation_op is disabled + #![allow(unused_variables)] // For some reason, the error location is different when using fullmir diff --git a/tests/compile-fail/validation_buggy_split_at_mut.rs b/tests/compile-fail/validation_buggy_split_at_mut.rs index 9e67b2a4ab18c..a750f1466f51b 100644 --- a/tests/compile-fail/validation_buggy_split_at_mut.rs +++ b/tests/compile-fail/validation_buggy_split_at_mut.rs @@ -1,3 +1,5 @@ +// ignore-test validation_op is disabled + #![allow(unused_variables)] mod safe { diff --git a/tests/compile-fail/validation_illegal_write.rs b/tests/compile-fail/validation_illegal_write.rs index 1432f4cc9f172..cb3e4b3c1a204 100644 --- a/tests/compile-fail/validation_illegal_write.rs +++ b/tests/compile-fail/validation_illegal_write.rs @@ -1,3 +1,5 @@ +// ignore-test validation_op is disabled + #![allow(unused_variables)] mod safe { diff --git a/tests/compile-fail/validation_lock_confusion.rs b/tests/compile-fail/validation_lock_confusion.rs index b352346114d7f..2a0857659622f 100644 --- a/tests/compile-fail/validation_lock_confusion.rs +++ b/tests/compile-fail/validation_lock_confusion.rs @@ -1,3 +1,5 @@ +// ignore-test validation_op is disabled + // Make sure validation can handle many overlapping shared borrows for different parts of a data structure #![allow(unused_variables)] use std::cell::RefCell; diff --git a/tests/compile-fail/validation_pointer_smuggling.rs b/tests/compile-fail/validation_pointer_smuggling.rs index 3320d2a89d355..14d6242860382 100644 --- a/tests/compile-fail/validation_pointer_smuggling.rs +++ b/tests/compile-fail/validation_pointer_smuggling.rs @@ -1,3 +1,5 @@ +// ignore-test validation_op is disabled + #![allow(unused_variables)] static mut PTR: *mut u8 = 0 as *mut _; diff --git a/tests/compile-fail/validation_recover1.rs b/tests/compile-fail/validation_recover1.rs index 55c38a694c55e..9061070ef67eb 100644 --- a/tests/compile-fail/validation_recover1.rs +++ b/tests/compile-fail/validation_recover1.rs @@ -1,3 +1,5 @@ +// ignore-test validation_op is disabled + #![allow(unused_variables)] #[repr(u32)] diff --git a/tests/compile-fail/validation_recover2.rs b/tests/compile-fail/validation_recover2.rs index 756be9fde6fc5..7a4a417ab1db9 100644 --- a/tests/compile-fail/validation_recover2.rs +++ b/tests/compile-fail/validation_recover2.rs @@ -1,3 +1,5 @@ +// ignore-test validation_op is disabled + #![allow(unused_variables)] mod safe { diff --git a/tests/compile-fail/validation_recover3.rs b/tests/compile-fail/validation_recover3.rs index afe6fe7c0bb9f..5cfc8aaa66b5f 100644 --- a/tests/compile-fail/validation_recover3.rs +++ b/tests/compile-fail/validation_recover3.rs @@ -1,3 +1,5 @@ +// ignore-test validation_op is disabled + #![allow(unused_variables)] mod safe { diff --git a/tests/compile-fail/validation_undef.rs b/tests/compile-fail/validation_undef.rs index b889b1ea5317b..939e93a264e8c 100644 --- a/tests/compile-fail/validation_undef.rs +++ b/tests/compile-fail/validation_undef.rs @@ -1,3 +1,5 @@ +// ignore-test validation_op is disabled + #![allow(unused_variables)] // error-pattern: attempted to read undefined bytes From 569792acbc6fccc13a7cb7377948912f6bba0aab Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Wed, 9 May 2018 17:30:16 +0200 Subject: [PATCH 0101/3747] Address some review comments --- tests/compile-fail/never_transmute_humans.rs | 18 ++++++++++++++++++ tests/compile-fail/oom2.rs | 14 -------------- tests/compile-fail/repeat2.rs | 7 ------- tests/compile-fail/timeout.rs | 9 --------- tests/compiletest.rs | 2 +- 5 files changed, 19 insertions(+), 31 deletions(-) create mode 100644 tests/compile-fail/never_transmute_humans.rs delete mode 100644 tests/compile-fail/oom2.rs delete mode 100644 tests/compile-fail/repeat2.rs delete mode 100644 tests/compile-fail/timeout.rs diff --git a/tests/compile-fail/never_transmute_humans.rs b/tests/compile-fail/never_transmute_humans.rs new file mode 100644 index 0000000000000..d0662c917ba7e --- /dev/null +++ b/tests/compile-fail/never_transmute_humans.rs @@ -0,0 +1,18 @@ +// This should fail even without validation +// compile-fail causes rustc ICE: rust-lang/rust#50570 +// compile-flags: -Zmir-emit-validate=0 + +#![feature(never_type)] +#![allow(unreachable_code)] +#![allow(unused_variables)] + +struct Human; + +fn main() { + let x: ! = unsafe { + std::mem::transmute::(Human) //~ ERROR entered unreachable code + }; + f(x) +} + +fn f(x: !) -> ! { x } diff --git a/tests/compile-fail/oom2.rs b/tests/compile-fail/oom2.rs deleted file mode 100644 index 6c973bcf4016d..0000000000000 --- a/tests/compile-fail/oom2.rs +++ /dev/null @@ -1,14 +0,0 @@ -// Validation forces more allocation; disable it. -// compile-flags: -Zmir-emit-validate=0 -#![feature(box_syntax, custom_attribute, attr_literals)] -#![miri(memory_size=1024)] - -// On 64bit platforms, the allocator needs 32 bytes allocated to pass a return value, so that's the error we see. -// On 32bit platforms, it's just 16 bytes. -// error-pattern: tried to allocate - -fn main() { - loop { - ::std::mem::forget(box 42); - } -} diff --git a/tests/compile-fail/repeat2.rs b/tests/compile-fail/repeat2.rs deleted file mode 100644 index 16cd9c1df8135..0000000000000 --- a/tests/compile-fail/repeat2.rs +++ /dev/null @@ -1,7 +0,0 @@ -// ignore-test - -fn main() { - let data: [u8; 1024*1024*1024] = [42; 1024*1024*1024]; - //~^ ERROR: tried to allocate - assert_eq!(data.len(), 1024*1024*1024); -} diff --git a/tests/compile-fail/timeout.rs b/tests/compile-fail/timeout.rs deleted file mode 100644 index edd4c31866910..0000000000000 --- a/tests/compile-fail/timeout.rs +++ /dev/null @@ -1,9 +0,0 @@ -//error-pattern: reached the configured maximum execution time -#![feature(custom_attribute, attr_literals)] -#![miri(step_limit=1000)] - -fn main() { - for i in 0..1000000 { - assert!(i < 1000); - } -} diff --git a/tests/compiletest.rs b/tests/compiletest.rs index 3fb7f2784a6ac..e62fa4e65e630 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -203,7 +203,7 @@ fn run_pass_rustc() { } #[test] -#[ignore] // TODO: update test errors +#[should_panic] // TODO: update test errors fn compile_fail_miri() { let sysroot = get_sysroot(); let host = get_host(); From 8ae66db798ae61342442eaafca8cd4dddab47a91 Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Wed, 9 May 2018 17:45:16 +0200 Subject: [PATCH 0102/3747] Convert some of the tests to the new format --- tests/compile-fail/alignment.rs | 3 ++- tests/compile-fail/assume.rs | 3 ++- tests/compile-fail/bitop-beyond-alignment.rs | 5 +++-- tests/compile-fail/cast_box_int_to_fn_ptr.rs | 3 ++- tests/compile-fail/cast_fn_ptr.rs | 3 ++- tests/compile-fail/cast_fn_ptr2.rs | 3 ++- tests/compile-fail/cast_int_to_fn_ptr.rs | 3 ++- tests/compile-fail/ctlz_nonzero.rs | 3 ++- tests/compile-fail/cttz_nonzero.rs | 3 ++- tests/compile-fail/dangling_pointer_deref.rs | 3 ++- tests/compile-fail/deref_fn_ptr.rs | 3 ++- tests/compile-fail/div-by-zero-2.rs | 3 ++- tests/compile-fail/execute_memory.rs | 3 ++- tests/compile-fail/fn_ptr_offset.rs | 3 ++- tests/compile-fail/invalid_bool.rs | 5 +++-- tests/compile-fail/invalid_enum_discriminant.rs | 5 +++-- tests/compile-fail/modifying_constants.rs | 3 ++- tests/compile-fail/never_say_never.rs | 3 ++- tests/compile-fail/never_transmute_humans.rs | 2 +- tests/compile-fail/never_transmute_void.rs | 5 +++-- tests/compile-fail/null_pointer_deref.rs | 3 ++- tests/compile-fail/oom.rs | 7 ------- tests/compile-fail/out_of_bounds_read.rs | 3 ++- tests/compile-fail/out_of_bounds_read2.rs | 3 ++- tests/compile-fail/overflowing-lsh-neg.rs | 3 ++- tests/compile-fail/overflowing-rsh.rs | 3 ++- ...rwriting_part_of_relocation_makes_the_rest_undefined.rs | 3 ++- tests/compile-fail/pointer_byte_read_1.rs | 3 ++- tests/compile-fail/pointer_byte_read_2.rs | 3 ++- .../pointers_to_different_allocations_are_unorderable.rs | 3 ++- tests/compile-fail/ptr_bitops.rs | 3 ++- tests/compile-fail/ptr_int_cast.rs | 3 ++- tests/compile-fail/reading_half_a_pointer.rs | 3 ++- tests/compile-fail/reallocate-change-alloc.rs | 3 ++- tests/compile-fail/reference_to_packed.rs | 3 ++- tests/compile-fail/static_memory_modification2.rs | 3 ++- tests/compile-fail/static_memory_modification3.rs | 3 ++- tests/compile-fail/transmute-pair-undef.rs | 3 ++- tests/compile-fail/transmute_fat.rs | 3 ++- tests/compile-fail/transmute_fat2.rs | 3 ++- tests/compile-fail/unaligned_ptr_cast.rs | 3 ++- tests/compile-fail/unaligned_ptr_cast2.rs | 3 ++- tests/compile-fail/unaligned_ptr_cast_zst.rs | 3 ++- tests/compile-fail/wild_pointer_deref.rs | 3 ++- tests/compile-fail/zst.rs | 3 ++- 45 files changed, 91 insertions(+), 55 deletions(-) delete mode 100644 tests/compile-fail/oom.rs diff --git a/tests/compile-fail/alignment.rs b/tests/compile-fail/alignment.rs index 4faaa359df624..9730fe473aa5d 100644 --- a/tests/compile-fail/alignment.rs +++ b/tests/compile-fail/alignment.rs @@ -5,7 +5,8 @@ fn main() { let x_ptr: *mut u8 = &mut x[0]; let y_ptr = x_ptr as *mut u64; unsafe { - *y_ptr = 42; //~ ERROR tried to access memory with alignment 1, but alignment + *y_ptr = 42; //~ ERROR constant evaluation error [E0080] + //~^ NOTE tried to access memory with alignment 1, but alignment } panic!("unreachable in miri"); } diff --git a/tests/compile-fail/assume.rs b/tests/compile-fail/assume.rs index 69758a5d7fe8c..cf0632393ad6d 100644 --- a/tests/compile-fail/assume.rs +++ b/tests/compile-fail/assume.rs @@ -5,6 +5,7 @@ fn main() { unsafe { std::intrinsics::assume(x < 10); std::intrinsics::assume(x > 1); - std::intrinsics::assume(x > 42); //~ ERROR: `assume` argument was false + std::intrinsics::assume(x > 42); //~ ERROR constant evaluation error [E0080] + //~^ NOTE `assume` argument was false } } diff --git a/tests/compile-fail/bitop-beyond-alignment.rs b/tests/compile-fail/bitop-beyond-alignment.rs index a30c054ab5d04..89f5e048a36d9 100644 --- a/tests/compile-fail/bitop-beyond-alignment.rs +++ b/tests/compile-fail/bitop-beyond-alignment.rs @@ -28,10 +28,11 @@ fn mk_rec() -> Rec { fn is_u64_aligned(u: &Tag) -> bool { let p: usize = unsafe { mem::transmute(u) }; let u64_align = std::mem::align_of::(); - return (p & (u64_align + 1)) == 0; //~ ERROR a raw memory access tried to access part of a pointer value as raw bytes + return (p & (u64_align + 1)) == 0; //~ ERROR constant evaluation error [E0080] + //~^ NOTE a raw memory access tried to access part of a pointer value as raw bytes } pub fn main() { let x = mk_rec(); - assert!(is_u64_aligned(&x.t)); + assert!(is_u64_aligned(&x.t)); //~ NOTE inside call to `is_u64_aligned } diff --git a/tests/compile-fail/cast_box_int_to_fn_ptr.rs b/tests/compile-fail/cast_box_int_to_fn_ptr.rs index 912b1bd7d91f2..39b53da0b75cd 100644 --- a/tests/compile-fail/cast_box_int_to_fn_ptr.rs +++ b/tests/compile-fail/cast_box_int_to_fn_ptr.rs @@ -7,5 +7,6 @@ fn main() { std::mem::transmute::<&usize, &fn(i32)>(&b) }; - (*g)(42) //~ ERROR a memory access tried to interpret some bytes as a pointer + (*g)(42) //~ ERROR constant evaluation error [E0080] + //~^ NOTE a memory access tried to interpret some bytes as a pointer } diff --git a/tests/compile-fail/cast_fn_ptr.rs b/tests/compile-fail/cast_fn_ptr.rs index 7509ae6ed77cb..19344b13ba7c9 100644 --- a/tests/compile-fail/cast_fn_ptr.rs +++ b/tests/compile-fail/cast_fn_ptr.rs @@ -5,5 +5,6 @@ fn main() { std::mem::transmute::(f) }; - g(42) //~ ERROR tried to call a function with sig fn() through a function pointer of type fn(i32) + g(42) //~ ERROR constant evaluation error [E0080] + //~^ NOTE tried to call a function with sig fn() through a function pointer of type fn(i32) } diff --git a/tests/compile-fail/cast_fn_ptr2.rs b/tests/compile-fail/cast_fn_ptr2.rs index 5d902e1f9aaaf..23868c0e57db4 100644 --- a/tests/compile-fail/cast_fn_ptr2.rs +++ b/tests/compile-fail/cast_fn_ptr2.rs @@ -5,5 +5,6 @@ fn main() { std::mem::transmute::(f) }; - g(42) //~ ERROR tried to call a function with sig fn((i32, i32)) through a function pointer of type fn(i32) + g(42) //~ ERROR constant evaluation error [E0080] + //~^ NOTE tried to call a function with sig fn((i32, i32)) through a function pointer of type fn(i32) } diff --git a/tests/compile-fail/cast_int_to_fn_ptr.rs b/tests/compile-fail/cast_int_to_fn_ptr.rs index 23f85dbaf3ecb..c7556ae06b93e 100644 --- a/tests/compile-fail/cast_int_to_fn_ptr.rs +++ b/tests/compile-fail/cast_int_to_fn_ptr.rs @@ -6,5 +6,6 @@ fn main() { std::mem::transmute::(42) }; - g(42) //~ ERROR a memory access tried to interpret some bytes as a pointer + g(42) //~ ERROR constant evaluation error [E0080] + //~^ NOTE a memory access tried to interpret some bytes as a pointer } diff --git a/tests/compile-fail/ctlz_nonzero.rs b/tests/compile-fail/ctlz_nonzero.rs index 704c4d4b7d462..d952187eba456 100644 --- a/tests/compile-fail/ctlz_nonzero.rs +++ b/tests/compile-fail/ctlz_nonzero.rs @@ -10,6 +10,7 @@ pub fn main() { unsafe { use rusti::*; - ctlz_nonzero(0u8); //~ ERROR: ctlz_nonzero called on 0 + ctlz_nonzero(0u8); //~ ERROR constant evaluation error [E0080] + //~^ NOTE ctlz_nonzero called on 0 } } diff --git a/tests/compile-fail/cttz_nonzero.rs b/tests/compile-fail/cttz_nonzero.rs index eda25c6615214..b308484622bc4 100644 --- a/tests/compile-fail/cttz_nonzero.rs +++ b/tests/compile-fail/cttz_nonzero.rs @@ -10,6 +10,7 @@ pub fn main() { unsafe { use rusti::*; - cttz_nonzero(0u8); //~ ERROR: cttz_nonzero called on 0 + cttz_nonzero(0u8); //~ ERROR constant evaluation error [E0080] + //~^ NOTE cttz_nonzero called on 0 } } diff --git a/tests/compile-fail/dangling_pointer_deref.rs b/tests/compile-fail/dangling_pointer_deref.rs index 0ede7c96f0047..d42c1d33b530a 100644 --- a/tests/compile-fail/dangling_pointer_deref.rs +++ b/tests/compile-fail/dangling_pointer_deref.rs @@ -3,6 +3,7 @@ fn main() { let b = Box::new(42); &*b as *const i32 }; - let x = unsafe { *p }; //~ ERROR: dangling pointer was dereferenced + let x = unsafe { *p }; //~ ERROR constant evaluation error [E0080] + //~^ NOTE dangling pointer was dereferenced panic!("this should never print: {}", x); } diff --git a/tests/compile-fail/deref_fn_ptr.rs b/tests/compile-fail/deref_fn_ptr.rs index c1eaf7eaa61d2..a56df5bce408e 100644 --- a/tests/compile-fail/deref_fn_ptr.rs +++ b/tests/compile-fail/deref_fn_ptr.rs @@ -2,7 +2,8 @@ fn f() {} fn main() { let x: i32 = unsafe { - *std::mem::transmute::(f) //~ ERROR: tried to dereference a function pointer + *std::mem::transmute::(f) //~ ERROR constant evaluation error [E0080] + //~^ NOTE tried to dereference a function pointer }; panic!("this should never print: {}", x); } diff --git a/tests/compile-fail/div-by-zero-2.rs b/tests/compile-fail/div-by-zero-2.rs index 3e869ad4a5078..c90ca8d15ccea 100644 --- a/tests/compile-fail/div-by-zero-2.rs +++ b/tests/compile-fail/div-by-zero-2.rs @@ -11,5 +11,6 @@ #![allow(const_err)] fn main() { - let _n = 1 / 0; //~ ERROR: DivisionByZero + let _n = 1 / 0; //~ ERROR constant evaluation error [E0080] + //~^ NOTE attempt to divide by zero } diff --git a/tests/compile-fail/execute_memory.rs b/tests/compile-fail/execute_memory.rs index 87d975e1f9d48..014c551df0f13 100644 --- a/tests/compile-fail/execute_memory.rs +++ b/tests/compile-fail/execute_memory.rs @@ -7,6 +7,7 @@ fn main() { let x = box 42; unsafe { let f = std::mem::transmute::, fn()>(x); - f() //~ ERROR: tried to treat a memory pointer as a function pointer + f() //~ ERROR constant evaluation error [E0080] + //~^ NOTE tried to treat a memory pointer as a function pointer } } diff --git a/tests/compile-fail/fn_ptr_offset.rs b/tests/compile-fail/fn_ptr_offset.rs index 45e32142a8c44..20eb6573989c0 100644 --- a/tests/compile-fail/fn_ptr_offset.rs +++ b/tests/compile-fail/fn_ptr_offset.rs @@ -10,5 +10,6 @@ fn main() { let y : *mut u8 = unsafe { mem::transmute(x) }; let y = y.wrapping_offset(1); let x : fn() = unsafe { mem::transmute(y) }; - x(); //~ ERROR: tried to use a function pointer after offsetting it + x(); //~ ERROR constant evaluation error [E0080] + //~^ NOTE tried to use a function pointer after offsetting it } diff --git a/tests/compile-fail/invalid_bool.rs b/tests/compile-fail/invalid_bool.rs index c30c9b439a46b..07c407966a8fd 100644 --- a/tests/compile-fail/invalid_bool.rs +++ b/tests/compile-fail/invalid_bool.rs @@ -1,4 +1,5 @@ fn main() { - let b = unsafe { std::mem::transmute::(2) }; //~ ERROR: invalid boolean value read - if b { unreachable!() } else { unreachable!() } + let b = unsafe { std::mem::transmute::(2) }; + if b { unreachable!() } else { unreachable!() } //~ ERROR constant evaluation error [E0080] + //~^ NOTE invalid boolean value read } diff --git a/tests/compile-fail/invalid_enum_discriminant.rs b/tests/compile-fail/invalid_enum_discriminant.rs index 9ce6d44ca460f..69d7e3e427d4b 100644 --- a/tests/compile-fail/invalid_enum_discriminant.rs +++ b/tests/compile-fail/invalid_enum_discriminant.rs @@ -9,9 +9,10 @@ pub enum Foo { fn main() { let f = unsafe { std::mem::transmute::(42) }; match f { - Foo::A => {}, //~ ERROR invalid enum discriminant value read + Foo::A => {}, Foo::B => {}, Foo::C => {}, Foo::D => {}, } -} +} //~ ERROR constant evaluation error [E0080] +//~^ NOTE entered unreachable code diff --git a/tests/compile-fail/modifying_constants.rs b/tests/compile-fail/modifying_constants.rs index cb2e7217d5797..06920fa0acf16 100644 --- a/tests/compile-fail/modifying_constants.rs +++ b/tests/compile-fail/modifying_constants.rs @@ -1,6 +1,7 @@ fn main() { let x = &1; // the `&1` is promoted to a constant, but it used to be that only the pointer is marked static, not the pointee let y = unsafe { &mut *(x as *const i32 as *mut i32) }; - *y = 42; //~ ERROR tried to modify constant memory + *y = 42; //~ ERROR constant evaluation error [E0080] + //~^ NOTE tried to modify constant memory assert_eq!(*x, 42); } diff --git a/tests/compile-fail/never_say_never.rs b/tests/compile-fail/never_say_never.rs index 71306cc62bf7f..de8815ffd9c4e 100644 --- a/tests/compile-fail/never_say_never.rs +++ b/tests/compile-fail/never_say_never.rs @@ -7,7 +7,8 @@ fn main() { let y = &5; let x: ! = unsafe { - *(y as *const _ as *const !) //~ ERROR entered unreachable code + *(y as *const _ as *const !) //~ ERROR constant evaluation error [E0080] + //~^ NOTE entered unreachable code }; f(x) } diff --git a/tests/compile-fail/never_transmute_humans.rs b/tests/compile-fail/never_transmute_humans.rs index d0662c917ba7e..3924dc7371e7c 100644 --- a/tests/compile-fail/never_transmute_humans.rs +++ b/tests/compile-fail/never_transmute_humans.rs @@ -1,5 +1,5 @@ // This should fail even without validation -// compile-fail causes rustc ICE: rust-lang/rust#50570 +// ignore-test causes rustc ICE: rust-lang/rust#50570 // compile-flags: -Zmir-emit-validate=0 #![feature(never_type)] diff --git a/tests/compile-fail/never_transmute_void.rs b/tests/compile-fail/never_transmute_void.rs index 0b0897644409e..4f1499483eda2 100644 --- a/tests/compile-fail/never_transmute_void.rs +++ b/tests/compile-fail/never_transmute_void.rs @@ -8,12 +8,13 @@ enum Void {} fn f(v: Void) -> ! { - match v {} //~ ERROR entered unreachable code + match v {} //~ ERROR constant evaluation error [E0080] + //~^ NOTE entered unreachable code } fn main() { let v: Void = unsafe { std::mem::transmute::<(), Void>(()) }; - f(v); + f(v); //~ inside call to `f` } diff --git a/tests/compile-fail/null_pointer_deref.rs b/tests/compile-fail/null_pointer_deref.rs index 5a26856eba087..70df937c4c7c5 100644 --- a/tests/compile-fail/null_pointer_deref.rs +++ b/tests/compile-fail/null_pointer_deref.rs @@ -1,4 +1,5 @@ fn main() { - let x: i32 = unsafe { *std::ptr::null() }; //~ ERROR: invalid use of NULL pointer + let x: i32 = unsafe { *std::ptr::null() }; //~ ERROR constant evaluation error [E0080] + //~^ NOTE invalid use of NULL pointer panic!("this should never print: {}", x); } diff --git a/tests/compile-fail/oom.rs b/tests/compile-fail/oom.rs deleted file mode 100644 index d4aebb912ee17..0000000000000 --- a/tests/compile-fail/oom.rs +++ /dev/null @@ -1,7 +0,0 @@ -#![feature(custom_attribute, attr_literals)] -#![miri(memory_size=4095)] - -fn main() { - let _x = [42; 1024]; - //~^ERROR tried to allocate 4096 more bytes, but only -} diff --git a/tests/compile-fail/out_of_bounds_read.rs b/tests/compile-fail/out_of_bounds_read.rs index 8c56b14bdf221..d8811e7abcd25 100644 --- a/tests/compile-fail/out_of_bounds_read.rs +++ b/tests/compile-fail/out_of_bounds_read.rs @@ -1,5 +1,6 @@ fn main() { let v: Vec = vec![1, 2]; - let x = unsafe { *v.as_ptr().wrapping_offset(5) }; //~ ERROR: which has size 2 + let x = unsafe { *v.as_ptr().wrapping_offset(5) }; //~ ERROR constant evaluation error [E0080] + //~^ NOTE which has size 2 panic!("this should never print: {}", x); } diff --git a/tests/compile-fail/out_of_bounds_read2.rs b/tests/compile-fail/out_of_bounds_read2.rs index d29b22ffb2a6b..54738cf81fbd8 100644 --- a/tests/compile-fail/out_of_bounds_read2.rs +++ b/tests/compile-fail/out_of_bounds_read2.rs @@ -1,5 +1,6 @@ fn main() { let v: Vec = vec![1, 2]; - let x = unsafe { *v.as_ptr().wrapping_offset(5) }; //~ ERROR: memory access at offset 6, outside bounds of allocation + let x = unsafe { *v.as_ptr().wrapping_offset(5) }; //~ ERROR constant evaluation error [E0080] + //~^ NOTE memory access at offset 6, outside bounds of allocation panic!("this should never print: {}", x); } diff --git a/tests/compile-fail/overflowing-lsh-neg.rs b/tests/compile-fail/overflowing-lsh-neg.rs index 3a889be741efd..e50e425036499 100644 --- a/tests/compile-fail/overflowing-lsh-neg.rs +++ b/tests/compile-fail/overflowing-lsh-neg.rs @@ -12,5 +12,6 @@ #![allow(const_err)] fn main() { - let _n = 2i64 << -1; //~ Overflow(Shl) + let _n = 2i64 << -1; //~ ERROR constant evaluation error [E0080] + //~^ NOTE attempt to shift left with overflow } diff --git a/tests/compile-fail/overflowing-rsh.rs b/tests/compile-fail/overflowing-rsh.rs index a7ac9d1d50398..c291815e2e79a 100644 --- a/tests/compile-fail/overflowing-rsh.rs +++ b/tests/compile-fail/overflowing-rsh.rs @@ -11,5 +11,6 @@ #![allow(exceeding_bitshifts)] fn main() { - let _n = 1i64 >> 64; //~ Overflow(Shr) + let _n = 1i64 >> 64; //~ ERROR constant evaluation error [E0080] + //~^ NOTE attempt to shift right with overflow } diff --git a/tests/compile-fail/overwriting_part_of_relocation_makes_the_rest_undefined.rs b/tests/compile-fail/overwriting_part_of_relocation_makes_the_rest_undefined.rs index 50f51d0ba9cad..fabbef5004d77 100644 --- a/tests/compile-fail/overwriting_part_of_relocation_makes_the_rest_undefined.rs +++ b/tests/compile-fail/overwriting_part_of_relocation_makes_the_rest_undefined.rs @@ -6,6 +6,7 @@ fn main() { // "attempted to interpret some raw bytes as a pointer address" instead of // "attempted to read undefined bytes" } - let x = *p; //~ ERROR: attempted to read undefined bytes + let x = *p; //~ ERROR constant evaluation error [E0080] + //~^ NOTE attempted to read undefined bytes panic!("this should never print: {}", x); } diff --git a/tests/compile-fail/pointer_byte_read_1.rs b/tests/compile-fail/pointer_byte_read_1.rs index 342eb28a970fc..012af897e8370 100644 --- a/tests/compile-fail/pointer_byte_read_1.rs +++ b/tests/compile-fail/pointer_byte_read_1.rs @@ -3,5 +3,6 @@ fn main() { let y = &x; let z = &y as *const &i32 as *const usize; let ptr_bytes = unsafe { *z }; // the actual deref is fine, because we read the entire pointer at once - let _ = ptr_bytes % 432; //~ ERROR: tried to access part of a pointer value as raw bytes + let _ = ptr_bytes % 432; //~ ERROR constant evaluation error [E0080] + //~^ NOTE tried to access part of a pointer value as raw bytes } diff --git a/tests/compile-fail/pointer_byte_read_2.rs b/tests/compile-fail/pointer_byte_read_2.rs index b0f619332e00c..4d25a36a3c883 100644 --- a/tests/compile-fail/pointer_byte_read_2.rs +++ b/tests/compile-fail/pointer_byte_read_2.rs @@ -3,5 +3,6 @@ fn main() { let y = &x; let z = &y as *const &i32 as *const u8; // the deref fails, because we are reading only a part of the pointer - let _ = unsafe { *z }; //~ ERROR: tried to access part of a pointer value as raw bytes + let _ = unsafe { *z }; //~ ERROR constant evaluation error [E0080] + //~^ NOTE tried to access part of a pointer value as raw bytes } diff --git a/tests/compile-fail/pointers_to_different_allocations_are_unorderable.rs b/tests/compile-fail/pointers_to_different_allocations_are_unorderable.rs index 245b7527c55b2..72ae1b123e8a2 100644 --- a/tests/compile-fail/pointers_to_different_allocations_are_unorderable.rs +++ b/tests/compile-fail/pointers_to_different_allocations_are_unorderable.rs @@ -1,7 +1,8 @@ fn main() { let x: *const u8 = &1; let y: *const u8 = &2; - if x < y { //~ ERROR: attempted to do invalid arithmetic on pointers + if x < y { //~ ERROR constant evaluation error [E0080] + //~^ NOTE attempted to do invalid arithmetic on pointers unreachable!() } } diff --git a/tests/compile-fail/ptr_bitops.rs b/tests/compile-fail/ptr_bitops.rs index 78fd8e912b5e7..52bcf24cf6b8f 100644 --- a/tests/compile-fail/ptr_bitops.rs +++ b/tests/compile-fail/ptr_bitops.rs @@ -2,6 +2,7 @@ fn main() { let bytes = [0i8, 1, 2, 3, 4, 5, 6, 7, 8, 9]; let one = bytes.as_ptr().wrapping_offset(1); let three = bytes.as_ptr().wrapping_offset(3); - let res = (one as usize) | (three as usize); //~ ERROR a raw memory access tried to access part of a pointer value as raw bytes + let res = (one as usize) | (three as usize); //~ ERROR constant evaluation error [E0080] + //~^ NOTE a raw memory access tried to access part of a pointer value as raw bytes println!("{}", res); } diff --git a/tests/compile-fail/ptr_int_cast.rs b/tests/compile-fail/ptr_int_cast.rs index 396c71ebb03d1..56403d619ffad 100644 --- a/tests/compile-fail/ptr_int_cast.rs +++ b/tests/compile-fail/ptr_int_cast.rs @@ -2,7 +2,8 @@ fn main() { let x = &1; // Casting down to u8 and back up to a pointer loses too much precision; this must not work. let x = x as *const i32; - let x = x as u8; //~ ERROR: a raw memory access tried to access part of a pointer value as raw bytes + let x = x as u8; //~ ERROR constant evaluation error [E0080] + //~^ NOTE a raw memory access tried to access part of a pointer value as raw bytes let x = x as *const i32; let _ = unsafe { *x }; } diff --git a/tests/compile-fail/reading_half_a_pointer.rs b/tests/compile-fail/reading_half_a_pointer.rs index cc41b52f33372..e44f26c4c4cfb 100644 --- a/tests/compile-fail/reading_half_a_pointer.rs +++ b/tests/compile-fail/reading_half_a_pointer.rs @@ -24,6 +24,7 @@ fn main() { // starts 1 byte to the right, so using it would actually be wrong! let d_alias = &mut w.data as *mut _ as *mut *const u8; unsafe { - let _x = *d_alias; //~ ERROR: tried to access part of a pointer value as raw bytes + let _x = *d_alias; //~ ERROR constant evaluation error [E0080] + //~^ NOTE tried to access part of a pointer value as raw bytes } } diff --git a/tests/compile-fail/reallocate-change-alloc.rs b/tests/compile-fail/reallocate-change-alloc.rs index 8a788104d8697..d8234e933300b 100644 --- a/tests/compile-fail/reallocate-change-alloc.rs +++ b/tests/compile-fail/reallocate-change-alloc.rs @@ -9,6 +9,7 @@ fn main() { unsafe { let x = Global.alloc(Layout::from_size_align_unchecked(1, 1)); let _y = Global.realloc(x, Layout::from_size_align_unchecked(1, 1), 1); - let _z = *(x as *mut u8); //~ ERROR: dangling pointer was dereferenced + let _z = *(x as *mut u8); //~ ERROR constant evaluation error [E0080] + //~^ NOTE dangling pointer was dereferenced } } diff --git a/tests/compile-fail/reference_to_packed.rs b/tests/compile-fail/reference_to_packed.rs index 064386b3d010c..16b452ca0e3c9 100644 --- a/tests/compile-fail/reference_to_packed.rs +++ b/tests/compile-fail/reference_to_packed.rs @@ -15,5 +15,6 @@ fn main() { y: 99, }; let p = unsafe { &foo.x }; - let i = *p; //~ ERROR tried to access memory with alignment 1, but alignment 4 is required + let i = *p; //~ ERROR constant evaluation error [E0080] + //~^ NOTE tried to access memory with alignment 1, but alignment 4 is required } diff --git a/tests/compile-fail/static_memory_modification2.rs b/tests/compile-fail/static_memory_modification2.rs index f030a9c281de7..6abe6de1fcf41 100644 --- a/tests/compile-fail/static_memory_modification2.rs +++ b/tests/compile-fail/static_memory_modification2.rs @@ -7,6 +7,7 @@ use std::mem::transmute; fn main() { unsafe { let s = "this is a test"; - transmute::<&[u8], &mut [u8]>(s.as_bytes())[4] = 42; //~ ERROR: tried to modify constant memory + transmute::<&[u8], &mut [u8]>(s.as_bytes())[4] = 42; //~ ERROR constant evaluation error [E0080] + //~^ NOTE tried to modify constant memory } } diff --git a/tests/compile-fail/static_memory_modification3.rs b/tests/compile-fail/static_memory_modification3.rs index 743fbe60efff6..0891756f0ec61 100644 --- a/tests/compile-fail/static_memory_modification3.rs +++ b/tests/compile-fail/static_memory_modification3.rs @@ -4,6 +4,7 @@ use std::mem::transmute; fn main() { unsafe { let bs = b"this is a test"; - transmute::<&[u8], &mut [u8]>(bs)[4] = 42; //~ ERROR: tried to modify constant memory + transmute::<&[u8], &mut [u8]>(bs)[4] = 42; //~ ERROR constant evaluation error [E0080] + //~^ NOTE tried to modify constant memory } } diff --git a/tests/compile-fail/transmute-pair-undef.rs b/tests/compile-fail/transmute-pair-undef.rs index acc6098af7ee0..6b4fe2273a080 100644 --- a/tests/compile-fail/transmute-pair-undef.rs +++ b/tests/compile-fail/transmute-pair-undef.rs @@ -16,5 +16,6 @@ fn main() { assert_eq!(byte, 0); } let v = unsafe { *z.offset(first_undef) }; - if v == 0 {} //~ ERROR attempted to read undefined bytes + if v == 0 {} //~ ERROR constant evaluation error [E0080] + //~^ NOTE attempted to read undefined bytes } diff --git a/tests/compile-fail/transmute_fat.rs b/tests/compile-fail/transmute_fat.rs index a2ebb6b21aa24..81d783807c586 100644 --- a/tests/compile-fail/transmute_fat.rs +++ b/tests/compile-fail/transmute_fat.rs @@ -10,5 +10,6 @@ fn main() { let bad = unsafe { std::mem::transmute::<&[u8], u64>(&[1u8]) }; - let _ = bad + 1; //~ ERROR a raw memory access tried to access part of a pointer value as raw bytes + let _ = bad + 1; //~ ERROR constant evaluation error [E0080] + //~^ NOTE a raw memory access tried to access part of a pointer value as raw bytes } diff --git a/tests/compile-fail/transmute_fat2.rs b/tests/compile-fail/transmute_fat2.rs index 3121a139d9204..96a713305e6bd 100644 --- a/tests/compile-fail/transmute_fat2.rs +++ b/tests/compile-fail/transmute_fat2.rs @@ -7,5 +7,6 @@ fn main() { let bad = unsafe { std::mem::transmute::(42) }; - bad[0]; //~ ERROR index out of bounds: the len is 0 but the index is 0 + bad[0]; //~ ERROR constant evaluation error [E0080] + //~^ NOTE index out of bounds: the len is 0 but the index is 0 } diff --git a/tests/compile-fail/unaligned_ptr_cast.rs b/tests/compile-fail/unaligned_ptr_cast.rs index 8ad1b323250c9..cb9523395391f 100644 --- a/tests/compile-fail/unaligned_ptr_cast.rs +++ b/tests/compile-fail/unaligned_ptr_cast.rs @@ -2,5 +2,6 @@ fn main() { let x = &2u16; let x = x as *const _ as *const u32; // This must fail because alignment is violated - let _x = unsafe { *x }; //~ ERROR: tried to access memory with alignment 2, but alignment 4 is required + let _x = unsafe { *x }; //~ ERROR constant evaluation error [E0080] + //~^ NOTE tried to access memory with alignment 2, but alignment 4 is required } diff --git a/tests/compile-fail/unaligned_ptr_cast2.rs b/tests/compile-fail/unaligned_ptr_cast2.rs index 15fb7dd31368b..dee2bbc9972f7 100644 --- a/tests/compile-fail/unaligned_ptr_cast2.rs +++ b/tests/compile-fail/unaligned_ptr_cast2.rs @@ -3,5 +3,6 @@ fn main() { let x = x as *const _ as *const *const u8; // This must fail because alignment is violated. Test specifically for loading pointers, which have special code // in miri's memory. - let _x = unsafe { *x }; //~ ERROR: tried to access memory with alignment 2, but alignment + let _x = unsafe { *x }; //~ ERROR constant evaluation error [E0080] + //~^ NOTE tried to access memory with alignment 2, but alignment } diff --git a/tests/compile-fail/unaligned_ptr_cast_zst.rs b/tests/compile-fail/unaligned_ptr_cast_zst.rs index fc603840684e8..eba17ab6c6406 100644 --- a/tests/compile-fail/unaligned_ptr_cast_zst.rs +++ b/tests/compile-fail/unaligned_ptr_cast_zst.rs @@ -2,5 +2,6 @@ fn main() { let x = &2u16; let x = x as *const _ as *const [u32; 0]; // This must fail because alignment is violated. Test specifically for loading ZST. - let _x = unsafe { *x }; //~ ERROR: tried to access memory with alignment 2, but alignment 4 is required + let _x = unsafe { *x }; //~ ERROR constant evaluation error [E0080] + //~^ NOTE tried to access memory with alignment 2, but alignment 4 is required } diff --git a/tests/compile-fail/wild_pointer_deref.rs b/tests/compile-fail/wild_pointer_deref.rs index 57da8dfc01b27..035d979c5b07e 100644 --- a/tests/compile-fail/wild_pointer_deref.rs +++ b/tests/compile-fail/wild_pointer_deref.rs @@ -1,5 +1,6 @@ fn main() { let p = 44 as *const i32; - let x = unsafe { *p }; //~ ERROR: a memory access tried to interpret some bytes as a pointer + let x = unsafe { *p }; //~ ERROR constant evaluation error [E0080] + //~^ NOTE a memory access tried to interpret some bytes as a pointer panic!("this should never print: {}", x); } diff --git a/tests/compile-fail/zst.rs b/tests/compile-fail/zst.rs index 3439824047943..d6518a48aa828 100644 --- a/tests/compile-fail/zst.rs +++ b/tests/compile-fail/zst.rs @@ -1,4 +1,5 @@ fn main() { let x = &() as *const () as *const i32; - let _ = unsafe { *x }; //~ ERROR: tried to access memory with alignment 1, but alignment 4 is required + let _ = unsafe { *x }; //~ ERROR constant evaluation error [E0080] + //~^ NOTE tried to access memory with alignment 1, but alignment 4 is required } From 94754de60010dba845ea9c299c9616dbc2022c86 Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Wed, 9 May 2018 19:24:25 +0200 Subject: [PATCH 0103/3747] Convert legitimate failing errors to the new error format --- src/lib.rs | 1 + tests/compile-fail/match_char.rs | 3 ++- tests/compile-fail/overflowing-rsh-2.rs | 3 ++- tests/compile-fail/repeat.rs | 6 ------ tests/compile-fail/static_memory_modification.rs | 3 ++- 5 files changed, 7 insertions(+), 9 deletions(-) delete mode 100644 tests/compile-fail/repeat.rs diff --git a/src/lib.rs b/src/lib.rs index 1ba763349aa7d..e8bbe164611da 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -249,6 +249,7 @@ pub fn eval_main<'a, 'tcx: 'a>( Ok(()) => { let leaks = ecx.memory().leak_report(); if leaks != 0 { + // TODO: Prevent leaks which aren't supposed to be there //tcx.sess.err("the evaluated program leaked memory"); } } diff --git a/tests/compile-fail/match_char.rs b/tests/compile-fail/match_char.rs index 4fee6e692bada..15ce2f2f79525 100644 --- a/tests/compile-fail/match_char.rs +++ b/tests/compile-fail/match_char.rs @@ -1,6 +1,7 @@ fn main() { assert!(std::char::from_u32(-1_i32 as u32).is_none()); - match unsafe { std::mem::transmute::(-1) } { //~ERROR tried to interpret an invalid 32-bit value as a char: 4294967295 + match unsafe { std::mem::transmute::(-1) } { //~ ERROR constant evaluation error [E0080] + //~^ NOTE tried to interpret an invalid 32-bit value as a char: 4294967295 'a' => {}, 'b' => {}, _ => {}, diff --git a/tests/compile-fail/overflowing-rsh-2.rs b/tests/compile-fail/overflowing-rsh-2.rs index ac09a1740c43e..4447b9d7579a7 100644 --- a/tests/compile-fail/overflowing-rsh-2.rs +++ b/tests/compile-fail/overflowing-rsh-2.rs @@ -12,5 +12,6 @@ fn main() { // Make sure we catch overflows that would be hidden by first casting the RHS to u32 - let _n = 1i64 >> (u32::max_value() as i64 + 1); //~ Overflow(Shr) + let _n = 1i64 >> (u32::max_value() as i64 + 1); //~ ERROR constant evaluation error [E0080] + //~^ NOTE suiriuruihrihue } diff --git a/tests/compile-fail/repeat.rs b/tests/compile-fail/repeat.rs deleted file mode 100644 index 0367580f4ce9b..0000000000000 --- a/tests/compile-fail/repeat.rs +++ /dev/null @@ -1,6 +0,0 @@ -// error-pattern the type `[u8; - -fn main() { - let data: [u8; std::usize::MAX] = [42; std::usize::MAX]; - assert_eq!(data.len(), 1024); -} diff --git a/tests/compile-fail/static_memory_modification.rs b/tests/compile-fail/static_memory_modification.rs index 11961becb246a..7182f40d994dd 100644 --- a/tests/compile-fail/static_memory_modification.rs +++ b/tests/compile-fail/static_memory_modification.rs @@ -3,7 +3,8 @@ static X: usize = 5; #[allow(mutable_transmutes)] fn main() { unsafe { - *std::mem::transmute::<&usize, &mut usize>(&X) = 6; //~ ERROR: tried to modify constant memory + *std::mem::transmute::<&usize, &mut usize>(&X) = 6; //~ ERROR constant evaluation error [E0080] + //~^ NOTE tried to modify constant memory assert_eq!(X, 6); } } From ac25a513af7900a5ad2b10498d50591f28ba0db4 Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Sun, 20 May 2018 15:08:15 +0200 Subject: [PATCH 0104/3747] Re-enable never_transmute_humans.rs --- tests/compile-fail/never_transmute_humans.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/compile-fail/never_transmute_humans.rs b/tests/compile-fail/never_transmute_humans.rs index 3924dc7371e7c..3422d52f9c044 100644 --- a/tests/compile-fail/never_transmute_humans.rs +++ b/tests/compile-fail/never_transmute_humans.rs @@ -1,5 +1,4 @@ // This should fail even without validation -// ignore-test causes rustc ICE: rust-lang/rust#50570 // compile-flags: -Zmir-emit-validate=0 #![feature(never_type)] @@ -10,7 +9,8 @@ struct Human; fn main() { let x: ! = unsafe { - std::mem::transmute::(Human) //~ ERROR entered unreachable code + std::mem::transmute::(Human) //~ ERROR constant evaluation error [E0080] + //^~ NOTE entered unreachable code }; f(x) } From 60669cbdfd5d0aa4ed7528e3cddac71047e378ac Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Sun, 10 Jun 2018 11:23:56 +0200 Subject: [PATCH 0105/3747] Rustup to rustc 1.28.0-nightly (2a0062974 2018-06-09) --- benches/helpers/miri_helper.rs | 46 +++++++++++++--------------------- src/bin/miri.rs | 15 +++++------ src/lib.rs | 24 +++++++++++++++--- 3 files changed, 46 insertions(+), 39 deletions(-) diff --git a/benches/helpers/miri_helper.rs b/benches/helpers/miri_helper.rs index 2bf78b0a71cc1..0fbb46246aea8 100644 --- a/benches/helpers/miri_helper.rs +++ b/benches/helpers/miri_helper.rs @@ -5,8 +5,7 @@ extern crate rustc_driver; extern crate test; use self::miri::eval_main; -use self::rustc::session::Session; -use self::rustc_driver::{driver, CompilerCalls, Compilation}; +use self::rustc_driver::{driver, Compilation}; use std::cell::RefCell; use std::rc::Rc; use test::Bencher; @@ -36,37 +35,26 @@ pub fn run(filename: &str, bencher: &mut Bencher) { "--sysroot".to_string(), find_sysroot(), ]; - let compiler_calls = &mut MiriCompilerCalls(Rc::new(RefCell::new(bencher))); - rustc_driver::run_compiler(args, compiler_calls, None, None); -} - -impl<'a> CompilerCalls<'a> for MiriCompilerCalls<'a> { - fn build_controller( - &mut self, - _: &Session, - _: &getopts::Matches, - ) -> driver::CompileController<'a> { - let mut control: driver::CompileController<'a> = driver::CompileController::basic(); - - let bencher = self.0.clone(); + let bencher = RefCell::new(bencher); - control.after_analysis.stop = Compilation::Stop; - control.after_analysis.callback = Box::new(move |state| { - state.session.abort_if_errors(); + let mut control = driver::CompileController::basic(); - let tcx = state.tcx.unwrap(); - let (entry_node_id, _, _) = state.session.entry_fn.borrow().expect( - "no main or start function found", - ); - let entry_def_id = tcx.hir.local_def_id(entry_node_id); + control.after_analysis.stop = Compilation::Stop; + control.after_analysis.callback = Box::new(move |state| { + state.session.abort_if_errors(); - bencher.borrow_mut().iter(|| { - eval_main(tcx, entry_def_id, None); - }); + let tcx = state.tcx.unwrap(); + let (entry_node_id, _, _) = state.session.entry_fn.borrow().expect( + "no main or start function found", + ); + let entry_def_id = tcx.hir.local_def_id(entry_node_id); - state.session.abort_if_errors(); + bencher.borrow_mut().iter(|| { + eval_main(tcx, entry_def_id, None); }); - control - } + state.session.abort_if_errors(); + }); + + rustc_driver::run_compiler(args, Box::new(control), None, None); } diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 8d80135cde300..35e83d49125e0 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -23,7 +23,7 @@ use syntax::ast; use std::path::PathBuf; struct MiriCompilerCalls { - default: RustcDefaultCalls, + default: Box, /// Whether to begin interpretation at the start_fn lang item or not /// /// If false, the interpretation begins at the `main` function @@ -78,13 +78,14 @@ impl<'a> CompilerCalls<'a> for MiriCompilerCalls { self.default.late_callback(codegen_backend, matches, sess, cstore, input, odir, ofile) } fn build_controller( - &mut self, + self: Box, sess: &Session, matches: &getopts::Matches, ) -> CompileController<'a> { - let mut control = self.default.build_controller(sess, matches); + let this = *self; + let mut control = this.default.build_controller(sess, matches); control.after_hir_lowering.callback = Box::new(after_hir_lowering); - let start_fn = self.start_fn; + let start_fn = this.start_fn; control.after_analysis.callback = Box::new(move |state| after_analysis(state, start_fn)); if sess.target.target != sess.host { // only fully compile targets on the host. linking will fail for cross-compilation. @@ -234,8 +235,8 @@ fn main() { // Make sure we always have all the MIR (e.g. for auxilary builds in unit tests). args.push("-Zalways-encode-mir".to_owned()); - rustc_driver::run_compiler(&args, &mut MiriCompilerCalls { - default: RustcDefaultCalls, + rustc_driver::run_compiler(&args, Box::new(MiriCompilerCalls { + default: Box::new(RustcDefaultCalls), start_fn, - }, None, None); + }), None, None); } diff --git a/src/lib.rs b/src/lib.rs index e8bbe164611da..d2ee39dd995a4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -24,6 +24,7 @@ use rustc::ty::layout::{TyLayout, LayoutOf, Size}; use rustc::ty::subst::Subst; use rustc::hir::def_id::DefId; use rustc::mir; +use rustc::middle::const_val; use syntax::ast::Mutability; use syntax::codemap::Span; @@ -253,9 +254,26 @@ pub fn eval_main<'a, 'tcx: 'a>( //tcx.sess.err("the evaluated program leaked memory"); } } - Err(mut e) => { - ecx.tcx.sess.err(&e.to_string()); - ecx.report(&mut e, true, None); + Err(e) => { + if let Some(frame) = ecx.stack().last() { + let block = &frame.mir.basic_blocks()[frame.block]; + let span = if frame.stmt < block.statements.len() { + block.statements[frame.stmt].source_info.span + } else { + block.terminator().source_info.span + }; + + let mut err = const_val::struct_error(ecx.tcx.tcx.at(span), "constant evaluation error"); + let (frames, span) = ecx.generate_stacktrace(None); + err.span_label(span, e.to_string()); + for const_val::FrameInfo { span, location, .. } in frames { + err.span_note(span, &format!("inside call to `{}`", location)); + } + err.emit(); + } else { + ecx.tcx.sess.err(&e.to_string()); + } + for (i, frame) in ecx.stack().iter().enumerate() { trace!("-------------------"); trace!("Frame {}", i); From 25ca33d1073cfcd53c12f43df4e3a315411bef9d Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Sun, 10 Jun 2018 11:47:04 +0200 Subject: [PATCH 0106/3747] Fix rustc_tests --- rustc_tests/src/main.rs | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/rustc_tests/src/main.rs b/rustc_tests/src/main.rs index ecc5287c72771..3e2cd032a80e8 100644 --- a/rustc_tests/src/main.rs +++ b/rustc_tests/src/main.rs @@ -24,7 +24,7 @@ use rustc::ty::TyCtxt; use syntax::ast; struct MiriCompilerCalls { - default: RustcDefaultCalls, + default: Box, /// whether we are building for the host host_target: bool, } @@ -63,11 +63,12 @@ impl<'a> CompilerCalls<'a> for MiriCompilerCalls { ) -> Compilation { self.default.late_callback(trans, matches, sess, cstore, input, odir, ofile) } - fn build_controller(&mut self, sess: &Session, matches: &getopts::Matches) -> CompileController<'a> { - let mut control = self.default.build_controller(sess, matches); + fn build_controller(self: Box, sess: &Session, matches: &getopts::Matches) -> CompileController<'a> { + let this = *self; + let mut control = this.default.build_controller(sess, matches); control.after_hir_lowering.callback = Box::new(after_hir_lowering); control.after_analysis.callback = Box::new(after_analysis); - if !self.host_target { + if !this.host_target { // only fully compile targets on the host control.after_analysis.stop = Compilation::Stop; } @@ -182,10 +183,10 @@ fn main() { let buf = BufWriter::default(); let output = buf.clone(); let result = std::panic::catch_unwind(|| { - rustc_driver::run_compiler(&args, &mut MiriCompilerCalls { - default: RustcDefaultCalls, + rustc_driver::run_compiler(&args, Box::new(MiriCompilerCalls { + default: Box::new(RustcDefaultCalls), host_target, - }, None, Some(Box::new(buf))); + }), None, Some(Box::new(buf))); }); match result { From b04391c56555e518092fef78263d30d2dd3ac755 Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Mon, 11 Jun 2018 18:49:17 +0200 Subject: [PATCH 0107/3747] Split create_ecx out of eval_main --- src/lib.rs | 197 +++++++++++++++++++++++++++-------------------------- 1 file changed, 102 insertions(+), 95 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index d2ee39dd995a4..cfe79f7602d7f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -132,107 +132,116 @@ impl ScalarExt for Scalar { } } -pub fn eval_main<'a, 'tcx: 'a>( +fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( tcx: TyCtxt<'a, 'tcx, 'tcx>, main_id: DefId, start_wrapper: Option, -) { - fn run_main<'a, 'mir: 'a, 'tcx: 'mir>( - ecx: &mut rustc_mir::interpret::EvalContext<'a, 'mir, 'tcx, Evaluator<'tcx>>, - main_id: DefId, - start_wrapper: Option, - ) -> EvalResult<'tcx> { - let main_instance = ty::Instance::mono(ecx.tcx.tcx, main_id); - let main_mir = ecx.load_mir(main_instance.def)?; - let mut cleanup_ptr = None; // Scalar to be deallocated when we are done - - if !main_mir.return_ty().is_nil() || main_mir.arg_count != 0 { - return err!(Unimplemented( - "miri does not support main functions without `fn()` type signatures" - .to_owned(), - )); +) -> EvalResult<'tcx, (EvalContext<'a, 'mir, 'tcx, Evaluator<'tcx>>, Option)> { + let mut ecx = EvalContext::new(tcx.at(syntax::codemap::DUMMY_SP), ty::ParamEnv::reveal_all(), Default::default(), Default::default()); + + let main_instance = ty::Instance::mono(ecx.tcx.tcx, main_id); + let main_mir = ecx.load_mir(main_instance.def)?; + let mut cleanup_ptr = None; // Scalar to be deallocated when we are done + + if !main_mir.return_ty().is_nil() || main_mir.arg_count != 0 { + return err!(Unimplemented( + "miri does not support main functions without `fn()` type signatures" + .to_owned(), + )); + } + + if let Some(start_id) = start_wrapper { + let main_ret_ty = ecx.tcx.fn_sig(main_id).output(); + let main_ret_ty = main_ret_ty.no_late_bound_regions().unwrap(); + let start_instance = ty::Instance::resolve( + ecx.tcx.tcx, + ty::ParamEnv::reveal_all(), + start_id, + ecx.tcx.mk_substs( + ::std::iter::once(ty::subst::Kind::from(main_ret_ty))) + ).unwrap(); + let start_mir = ecx.load_mir(start_instance.def)?; + + if start_mir.arg_count != 3 { + return err!(AbiViolation(format!( + "'start' lang item should have three arguments, but has {}", + start_mir.arg_count + ))); } - if let Some(start_id) = start_wrapper { - let main_ret_ty = ecx.tcx.fn_sig(main_id).output(); - let main_ret_ty = main_ret_ty.no_late_bound_regions().unwrap(); - let start_instance = ty::Instance::resolve( - ecx.tcx.tcx, - ty::ParamEnv::reveal_all(), - start_id, - ecx.tcx.mk_substs( - ::std::iter::once(ty::subst::Kind::from(main_ret_ty)))).unwrap(); - let start_mir = ecx.load_mir(start_instance.def)?; - - if start_mir.arg_count != 3 { - return err!(AbiViolation(format!( - "'start' lang item should have three arguments, but has {}", - start_mir.arg_count - ))); - } + // Return value + let size = ecx.tcx.data_layout.pointer_size; + let align = ecx.tcx.data_layout.pointer_align; + let ret_ptr = ecx.memory_mut().allocate(size, align, Some(MemoryKind::Stack))?; + cleanup_ptr = Some(ret_ptr); - // Return value - let size = ecx.tcx.data_layout.pointer_size; - let align = ecx.tcx.data_layout.pointer_align; - let ret_ptr = ecx.memory_mut().allocate(size, align, Some(MemoryKind::Stack))?; - cleanup_ptr = Some(ret_ptr); - - // Push our stack frame - ecx.push_stack_frame( - start_instance, - start_mir.span, - start_mir, - Place::from_ptr(ret_ptr, align), - StackPopCleanup::None, - )?; + // Push our stack frame + ecx.push_stack_frame( + start_instance, + start_mir.span, + start_mir, + Place::from_ptr(ret_ptr, align), + StackPopCleanup::None, + )?; - let mut args = ecx.frame().mir.args_iter(); - - // First argument: pointer to main() - let main_ptr = ecx.memory_mut().create_fn_alloc(main_instance); - let dest = ecx.eval_place(&mir::Place::Local(args.next().unwrap()))?; - let main_ty = main_instance.ty(ecx.tcx.tcx); - 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)), - ty: main_ptr_ty, - }, - dest, - )?; + let mut args = ecx.frame().mir.args_iter(); - // 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)?; - - // 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, None)?; - ecx.memory.write_scalar(foo_ptr.into(), ptr_align, Scalar::Ptr(foo), ptr_size, false)?; - ecx.memory.mark_static_initialized(foo_ptr.alloc_id, Mutability::Immutable)?; - ecx.write_ptr(dest, foo_ptr.into(), ty)?; - - assert!(args.next().is_none(), "start lang item has more arguments than expected"); - } else { - ecx.push_stack_frame( - main_instance, - main_mir.span, - main_mir, - Place::from_scalar_ptr(Scalar::from_u128(1), ty::layout::Align::from_bytes(1, 1).unwrap()), - StackPopCleanup::None, - )?; + // First argument: pointer to main() + let main_ptr = ecx.memory_mut().create_fn_alloc(main_instance); + let dest = ecx.eval_place(&mir::Place::Local(args.next().unwrap()))?; + let main_ty = main_instance.ty(ecx.tcx.tcx); + 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)), + ty: main_ptr_ty, + }, + dest, + )?; - // No arguments - let mut args = ecx.frame().mir.args_iter(); - assert!(args.next().is_none(), "main function must not have arguments"); - } + // 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)?; + // 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, None)?; + ecx.memory.write_scalar(foo_ptr.into(), ptr_align, Scalar::Ptr(foo), ptr_size, false)?; + ecx.memory.mark_static_initialized(foo_ptr.alloc_id, Mutability::Immutable)?; + ecx.write_ptr(dest, foo_ptr.into(), ty)?; + + assert!(args.next().is_none(), "start lang item has more arguments than expected"); + } else { + ecx.push_stack_frame( + main_instance, + main_mir.span, + main_mir, + Place::from_scalar_ptr(Scalar::from_u128(1), ty::layout::Align::from_bytes(1, 1).unwrap()), + StackPopCleanup::None, + )?; + + // No arguments + let mut args = ecx.frame().mir.args_iter(); + assert!(args.next().is_none(), "main function must not have arguments"); + } + + Ok((ecx, cleanup_ptr)) +} + +pub fn eval_main<'a, 'tcx: 'a>( + tcx: TyCtxt<'a, 'tcx, 'tcx>, + main_id: DefId, + start_wrapper: Option, +) { + let (mut ecx, cleanup_ptr) = create_ecx(tcx, main_id, start_wrapper).expect("Couldn't create ecx"); + + let res: EvalResult = do catch { while ecx.step()? {} ecx.run_tls_dtors()?; if let Some(cleanup_ptr) = cleanup_ptr { @@ -242,11 +251,9 @@ pub fn eval_main<'a, 'tcx: 'a>( MemoryKind::Stack, )?; } - Ok(()) - } + }; - let mut ecx = EvalContext::new(tcx.at(syntax::codemap::DUMMY_SP), ty::ParamEnv::reveal_all(), Default::default(), Default::default()); - match run_main(&mut ecx, main_id, start_wrapper) { + match res { Ok(()) => { let leaks = ecx.memory().leak_report(); if leaks != 0 { From d1de6781e83969a03b59d5fffdda59c69ad68d49 Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Tue, 12 Jun 2018 07:30:29 +0200 Subject: [PATCH 0108/3747] Add missing pub --- src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index cfe79f7602d7f..e3fd5b8a068b4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -132,7 +132,7 @@ impl ScalarExt for Scalar { } } -fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( +pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( tcx: TyCtxt<'a, 'tcx, 'tcx>, main_id: DefId, start_wrapper: Option, From d4b98b221ddc74524e3c3824e28126b9965150bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Miku=C5=82a?= Date: Fri, 29 Jun 2018 12:52:04 +0200 Subject: [PATCH 0109/3747] Rusutp --- rustc_tests/src/main.rs | 2 +- src/bin/miri.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/rustc_tests/src/main.rs b/rustc_tests/src/main.rs index 3e2cd032a80e8..64cd380970e4d 100644 --- a/rustc_tests/src/main.rs +++ b/rustc_tests/src/main.rs @@ -90,7 +90,7 @@ fn after_analysis<'a, 'tcx>(state: &mut CompileState<'a, 'tcx>) { struct Visitor<'a, 'tcx: 'a>(TyCtxt<'a, 'tcx, 'tcx>, &'a CompileState<'a, 'tcx>); impl<'a, 'tcx: 'a, 'hir> itemlikevisit::ItemLikeVisitor<'hir> for Visitor<'a, 'tcx> { fn visit_item(&mut self, i: &'hir hir::Item) { - if let hir::Item_::ItemFn(_, _, _, _, _, body_id) = i.node { + if let hir::Item_::ItemFn(.., body_id) = i.node { if i.attrs.iter().any(|attr| attr.name() == "test") { let did = self.0.hir.body_owner_def_id(body_id); println!("running test: {}", self.0.def_path_debug_str(did)); diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 35e83d49125e0..3001500d2e07b 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -25,7 +25,7 @@ use std::path::PathBuf; struct MiriCompilerCalls { default: Box, /// Whether to begin interpretation at the start_fn lang item or not - /// + /// /// If false, the interpretation begins at the `main` function start_fn: bool, } @@ -115,7 +115,7 @@ fn after_analysis<'a, 'tcx>(state: &mut CompileState<'a, 'tcx>, use_start_fn: bo ); impl<'a, 'tcx: 'a, 'hir> itemlikevisit::ItemLikeVisitor<'hir> for Visitor<'a, 'tcx> { fn visit_item(&mut self, i: &'hir hir::Item) { - if let hir::Item_::ItemFn(_, _, _, _, _, body_id) = i.node { + if let hir::Item_::ItemFn(.., body_id) = i.node { if i.attrs.iter().any(|attr| { attr.name() == "test" }) From 5a7f4412eed61ac82880d67d2bc5275c5dee4922 Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Fri, 29 Jun 2018 12:48:55 -0700 Subject: [PATCH 0110/3747] Implement `Eq` and `Hash` for MemoryData and Evaluator In order to implement infinite loop detection while executing MIR, both the implementor of `Machine` (`Evaluator`) and its associated type (`MemoryData`), must implement `Eq` and `Hash`. This PR adds the required trait implementations. It's possible that the `Hash` implementations need to be improved; only the `env_vars` field of `Evaluator` and the `thread_local` field of `MemoryData` are actually being hashed. Omitting fields from a `Hash` implementation is not incorrect, but could lead to collisions if the ignored fields are changing constantly. Perhaps I should instead derive `Hash` on a few more fields related to MIR validation? --- src/lib.rs | 41 ++++++++++++++++++++++++++++++++++++++--- src/locks.rs | 2 +- src/range_map.rs | 2 +- 3 files changed, 40 insertions(+), 5 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index e3fd5b8a068b4..ffb17527ad04f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -26,10 +26,13 @@ use rustc::hir::def_id::DefId; use rustc::mir; use rustc::middle::const_val; +use rustc_data_structures::fx::FxHasher; + use syntax::ast::Mutability; use syntax::codemap::Span; use std::collections::{HashMap, BTreeMap}; +use std::hash::{Hash, Hasher}; pub use rustc::mir::interpret::*; pub use rustc_mir::interpret::*; @@ -295,7 +298,7 @@ pub fn eval_main<'a, 'tcx: 'a>( } } -#[derive(Default)] +#[derive(Clone, Default, PartialEq, Eq)] pub struct Evaluator<'tcx> { /// Environment variables set by `setenv` /// Miri does not expose env vars from the host to the emulated program @@ -305,15 +308,34 @@ pub struct Evaluator<'tcx> { pub(crate) suspended: HashMap>>, } +impl<'tcx> Hash for Evaluator<'tcx> { + fn hash(&self, state: &mut H) { + let Evaluator { + env_vars, + suspended: _, + } = self; + + env_vars.iter() + .map(|(env, ptr)| { + let mut h = FxHasher::default(); + env.hash(&mut h); + ptr.hash(&mut h); + h.finish() + }) + .fold(0u64, |acc, hash| acc.wrapping_add(hash)) + .hash(state); + } +} + pub type TlsKey = u128; -#[derive(Copy, Clone, Debug)] +#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] pub struct TlsEntry<'tcx> { data: Scalar, // Will eventually become a map from thread IDs to `Scalar`s, if we ever support more than one thread. dtor: Option>, } -#[derive(Default)] +#[derive(Clone, Default, PartialEq, Eq)] pub struct MemoryData<'tcx> { /// The Key to use for the next thread-local allocation. next_thread_local: TlsKey, @@ -330,6 +352,19 @@ pub struct MemoryData<'tcx> { statics: HashMap, AllocId>, } +impl<'tcx> Hash for MemoryData<'tcx> { + fn hash(&self, state: &mut H) { + let MemoryData { + next_thread_local: _, + thread_local, + locks: _, + statics: _, + } = self; + + thread_local.hash(state); + } +} + impl<'mir, 'tcx: 'mir> Machine<'mir, 'tcx> for Evaluator<'tcx> { type MemoryData = MemoryData<'tcx>; type MemoryKinds = memory::MemoryKind; diff --git a/src/locks.rs b/src/locks.rs index a463f8ba575e8..9947609d37550 100644 --- a/src/locks.rs +++ b/src/locks.rs @@ -7,7 +7,7 @@ use rustc::ty::layout::Size; //////////////////////////////////////////////////////////////////////////////// /// Information about a lock that is currently held. -#[derive(Clone, Debug)] +#[derive(Clone, Debug, PartialEq, Eq)] pub struct LockInfo<'tcx> { /// Stores for which lifetimes (of the original write lock) we got /// which suspensions. diff --git a/src/range_map.rs b/src/range_map.rs index 5cdcbe35121a5..118be32a2993b 100644 --- a/src/range_map.rs +++ b/src/range_map.rs @@ -7,7 +7,7 @@ use std::collections::BTreeMap; use std::ops; -#[derive(Clone, Debug)] +#[derive(Clone, Debug, PartialEq, Eq)] pub struct RangeMap { map: BTreeMap, } From e1dbbe538f5fe978333dfa9f63533f5ead2866ae Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Sun, 1 Jul 2018 16:01:42 +0200 Subject: [PATCH 0111/3747] Rustup --- src/lib.rs | 5 ++--- src/validation.rs | 5 ++--- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index e3fd5b8a068b4..896c8c5428fbd 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -24,7 +24,6 @@ use rustc::ty::layout::{TyLayout, LayoutOf, Size}; use rustc::ty::subst::Subst; use rustc::hir::def_id::DefId; use rustc::mir; -use rustc::middle::const_val; use syntax::ast::Mutability; use syntax::codemap::Span; @@ -270,10 +269,10 @@ pub fn eval_main<'a, 'tcx: 'a>( block.terminator().source_info.span }; - let mut err = const_val::struct_error(ecx.tcx.tcx.at(span), "constant evaluation error"); + let mut err = mir::interpret::struct_error(ecx.tcx.tcx.at(span), "constant evaluation error"); let (frames, span) = ecx.generate_stacktrace(None); err.span_label(span, e.to_string()); - for const_val::FrameInfo { span, location, .. } in frames { + for mir::interpret::FrameInfo { span, location, .. } in frames { err.span_note(span, &format!("inside call to `{}`", location)); } err.emit(); diff --git a/src/validation.rs b/src/validation.rs index d82a345c2512a..90ac0a803f9b3 100644 --- a/src/validation.rs +++ b/src/validation.rs @@ -8,7 +8,6 @@ use rustc::ty::subst::{Substs, Subst}; use rustc::traits::{self, TraitEngine}; use rustc::infer::InferCtxt; use rustc::middle::region; -use rustc::middle::const_val::ConstVal; use rustc_data_structures::indexed_vec::Idx; use rustc_mir::interpret::HasMemory; @@ -719,14 +718,14 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' } TyArray(elem_ty, len) => { let len = match len.val { - ConstVal::Unevaluated(def_id, substs) => { + mir::interpret::ConstValue::Unevaluated(def_id, substs) => { self.tcx.const_eval(self.tcx.param_env(def_id).and(GlobalId { instance: Instance::new(def_id, substs), promoted: None, })) .map_err(|_err|EvalErrorKind::MachineError("".to_string()))? } - ConstVal::Value(_) => len, + _ => len, }; let len = len.unwrap_usize(self.tcx.tcx); for i in 0..len { From 5b7bb32b0e46d195b80c4da09b560ac7fc92015d Mon Sep 17 00:00:00 2001 From: Alexander Regueiro Date: Mon, 2 Jul 2018 17:00:36 +0100 Subject: [PATCH 0112/3747] Rustup --- src/fn_call.rs | 8 ++++---- src/lib.rs | 10 +++++----- src/validation.rs | 3 ++- 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index 36cc29a2b5b5b..1c3998a4f022f 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -199,7 +199,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' self.write_null(dest, dest_ty)?; } else { let align = self.tcx.data_layout.pointer_align; - let ptr = self.memory.allocate(Size::from_bytes(size), align, Some(MemoryKind::C.into()))?; + let ptr = self.memory.allocate(Size::from_bytes(size), align, MemoryKind::C.into())?; self.write_scalar(dest, Scalar::Ptr(ptr), dest_ty)?; } } @@ -395,7 +395,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' let value_copy = self.memory.allocate( Size::from_bytes((value.len() + 1) as u64), Align::from_bytes(1, 1).unwrap(), - Some(MemoryKind::Env.into()), + MemoryKind::Env.into(), )?; self.memory.write_bytes(value_copy.into(), &value)?; let trailing_zero_ptr = value_copy.offset(Size::from_bytes(value.len() as u64), &self)?.into(); @@ -656,7 +656,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' } let ptr = self.memory.allocate(Size::from_bytes(size), Align::from_bytes(align, align).unwrap(), - Some(MemoryKind::Rust.into()))?; + MemoryKind::Rust.into())?; self.write_scalar(dest, Scalar::Ptr(ptr), dest_ty)?; } "alloc::alloc::::__rust_alloc_zeroed" => { @@ -670,7 +670,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' } let ptr = self.memory.allocate(Size::from_bytes(size), Align::from_bytes(align, align).unwrap(), - Some(MemoryKind::Rust.into()))?; + MemoryKind::Rust.into())?; self.memory.write_repeat(ptr.into(), 0, Size::from_bytes(size))?; self.write_scalar(dest, Scalar::Ptr(ptr), dest_ty)?; } diff --git a/src/lib.rs b/src/lib.rs index 896c8c5428fbd..d6b0bd045099e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -171,7 +171,7 @@ pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( // Return value let size = ecx.tcx.data_layout.pointer_size; let align = ecx.tcx.data_layout.pointer_align; - let ret_ptr = ecx.memory_mut().allocate(size, align, Some(MemoryKind::Stack))?; + let ret_ptr = ecx.memory_mut().allocate(size, align, MemoryKind::Stack)?; cleanup_ptr = Some(ret_ptr); // Push our stack frame @@ -210,7 +210,7 @@ pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( let foo = ecx.memory.allocate_bytes(b"foo\0"); let ptr_size = ecx.memory.pointer_size(); let ptr_align = ecx.tcx.data_layout.pointer_align; - let foo_ptr = ecx.memory.allocate(ptr_size, ptr_align, None)?; + 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.mark_static_initialized(foo_ptr.alloc_id, Mutability::Immutable)?; ecx.write_ptr(dest, foo_ptr.into(), ty)?; @@ -269,10 +269,10 @@ pub fn eval_main<'a, 'tcx: 'a>( block.terminator().source_info.span }; - let mut err = mir::interpret::struct_error(ecx.tcx.tcx.at(span), "constant evaluation error"); + let mut err = struct_error(ecx.tcx.tcx.at(span), "constant evaluation error"); let (frames, span) = ecx.generate_stacktrace(None); err.span_label(span, e.to_string()); - for mir::interpret::FrameInfo { span, location, .. } in frames { + for FrameInfo { span, location, .. } in frames { err.span_note(span, &format!("inside call to `{}`", location)); } err.emit(); @@ -404,7 +404,7 @@ impl<'mir, 'tcx: 'mir> Machine<'mir, 'tcx> for Evaluator<'tcx> { let ptr = ecx.memory.allocate( layout.size, layout.align, - None, + MemoryKind::Stack, )?; // Step 4: Cache allocation id for recursive statics diff --git a/src/validation.rs b/src/validation.rs index 90ac0a803f9b3..851f5df9792e4 100644 --- a/src/validation.rs +++ b/src/validation.rs @@ -8,6 +8,7 @@ use rustc::ty::subst::{Substs, Subst}; use rustc::traits::{self, TraitEngine}; use rustc::infer::InferCtxt; use rustc::middle::region; +use rustc::mir::interpret::{ConstValue}; use rustc_data_structures::indexed_vec::Idx; use rustc_mir::interpret::HasMemory; @@ -718,7 +719,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' } TyArray(elem_ty, len) => { let len = match len.val { - mir::interpret::ConstValue::Unevaluated(def_id, substs) => { + ConstValue::Unevaluated(def_id, substs) => { self.tcx.const_eval(self.tcx.param_env(def_id).and(GlobalId { instance: Instance::new(def_id, substs), promoted: None, From f321593655b9ba2d5e475474dbc9ee2b5ae6285d Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Tue, 10 Jul 2018 17:20:07 +0200 Subject: [PATCH 0113/3747] Workaround for rustc bug --- src/range_map.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/range_map.rs b/src/range_map.rs index 5cdcbe35121a5..df1235f96c0d2 100644 --- a/src/range_map.rs +++ b/src/range_map.rs @@ -19,7 +19,7 @@ pub struct RangeMap { // At the same time the `end` is irrelevant for the sorting and range searching, but used for the check. // This kind of search breaks, if `end < start`, so don't do that! #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Debug)] -struct Range { +pub struct Range { start: u64, end: u64, // Invariant: end > start } From 52bf4732fd51332632f4154bb45df13871320ceb Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Tue, 10 Jul 2018 17:32:38 +0200 Subject: [PATCH 0114/3747] Fix some clippy lints --- src/fn_call.rs | 6 +++--- src/helpers.rs | 4 ++-- src/lib.rs | 15 +++++++-------- src/locks.rs | 10 ++++------ src/operator.rs | 2 +- src/range_map.rs | 2 +- src/tls.rs | 20 ++++++++++---------- src/validation.rs | 26 +++++++++++--------------- 8 files changed, 39 insertions(+), 46 deletions(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index 1c3998a4f022f..d2149ee5dbe7d 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -268,7 +268,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' )?; let mut args = self.frame().mir.args_iter(); - let arg_local = args.next().ok_or( + let arg_local = args.next().ok_or_else(|| EvalErrorKind::AbiViolation( "Argument to __rust_maybe_catch_panic does not take enough arguments." .to_owned(), @@ -504,7 +504,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' // 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(EvalErrorKind::AbiViolation("Wrong signature used for pthread_key_create: First argument must be a raw pointer.".to_owned()))?.ty; + .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; // Create key and write it into the memory where key_ptr wants it @@ -747,7 +747,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' // current frame. self.dump_local(dest); self.goto_block(dest_block); - return Ok(()); + Ok(()) } fn write_null(&mut self, dest: Place, dest_ty: Ty<'tcx>) -> EvalResult<'tcx> { diff --git a/src/helpers.rs b/src/helpers.rs index d881d5c271104..aa699b509fad8 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -75,7 +75,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; - return if let Some(offset) = offset.checked_mul(pointee_size) { + if let Some(offset) = offset.checked_mul(pointee_size) { let ptr = ptr.ptr_signed_offset(offset, self)?; // Do not do bounds-checking for integers; they can never alias a normal pointer anyway. if let Scalar::Ptr(ptr) = ptr { @@ -87,7 +87,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: Ok(ptr) } else { err!(Overflow(mir::BinOp::Mul)) - }; + } } fn value_to_isize( diff --git a/src/lib.rs b/src/lib.rs index d6b0bd045099e..88bca91aa2de5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -5,6 +5,8 @@ inclusive_range_methods, )] +#![cfg_attr(feature = "cargo-clippy", allow(cast_lossless))] + #[macro_use] extern crate log; @@ -427,14 +429,11 @@ impl<'mir, 'tcx: 'mir> Machine<'mir, 'tcx> for Evaluator<'tcx> { let frame = ecx.frame_mut(); let bb = &frame.mir.basic_blocks()[frame.block]; if bb.statements.len() == frame.stmt && !bb.is_cleanup { - match bb.terminator().kind { - ::rustc::mir::TerminatorKind::Return => { - for (local, _local_decl) in mir.local_decls.iter_enumerated().skip(1) { - // Don't deallocate locals, because the return value might reference them - frame.storage_dead(local); - } + if let ::rustc::mir::TerminatorKind::Return = bb.terminator().kind { + for (local, _local_decl) in mir.local_decls.iter_enumerated().skip(1) { + // Don't deallocate locals, because the return value might reference them + frame.storage_dead(local); } - _ => {} } } } @@ -478,7 +477,7 @@ impl<'mir, 'tcx: 'mir> Machine<'mir, 'tcx> for Evaluator<'tcx> { value: Value::Scalar(Scalar::from_u128(match layout.size.bytes() { 0 => 1 as u128, size => size as u128, - }.into())), + })), ty: usize, }, dest, diff --git a/src/locks.rs b/src/locks.rs index a463f8ba575e8..3b67c9bb7f3e4 100644 --- a/src/locks.rs +++ b/src/locks.rs @@ -241,11 +241,9 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> MemoryExt<'tcx> for Memory<'a, 'mir, 'tcx, Evalu // All is well continue 'locks; } - } else { - if !is_our_lock { - // All is well. - continue 'locks; - } + } else if !is_our_lock { + // All is well. + continue 'locks; } // If we get here, releasing this is an error except for NoLock. if lock.active != NoLock { @@ -377,7 +375,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> MemoryExt<'tcx> for Memory<'a, 'mir, 'tcx, Evalu } // Clean up the map alloc_locks.retain(|lock| match lock.active { - NoLock => lock.suspended.len() > 0, + NoLock => !lock.suspended.is_empty(), _ => true, }); } diff --git a/src/operator.rs b/src/operator.rs index f36e749dc9279..1440f1dab4e0f 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -69,7 +69,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: .expect("Offset called on non-ptr type") .ty; let ptr = self.pointer_offset( - left.into(), + left, pointee_ty, right.to_bits(self.memory.pointer_size())? as i64, )?; diff --git a/src/range_map.rs b/src/range_map.rs index df1235f96c0d2..fcffaf7128f11 100644 --- a/src/range_map.rs +++ b/src/range_map.rs @@ -189,7 +189,7 @@ impl RangeMap { F: FnMut(&T) -> bool, { let mut remove = Vec::new(); - for (range, data) in self.map.iter() { + for (range, data) in &self.map { if !f(data) { remove.push(*range); } diff --git a/src/tls.rs b/src/tls.rs index 7f49509ef42ea..45805f3aa8cc1 100644 --- a/src/tls.rs +++ b/src/tls.rs @@ -30,38 +30,38 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> MemoryExt<'tcx> for Memory<'a, 'mir, 'tcx, Evalu }, ); trace!("New TLS key allocated: {} with dtor {:?}", new_key, dtor); - return new_key; + new_key } fn delete_tls_key(&mut self, key: TlsKey) -> EvalResult<'tcx> { - return match self.data.thread_local.remove(&key) { + match self.data.thread_local.remove(&key) { Some(_) => { trace!("TLS key {} removed", key); Ok(()) } None => err!(TlsOutOfBounds), - }; + } } fn load_tls(&mut self, key: TlsKey) -> EvalResult<'tcx, Scalar> { - return match self.data.thread_local.get(&key) { + match self.data.thread_local.get(&key) { Some(&TlsEntry { data, .. }) => { trace!("TLS key {} loaded: {:?}", key, data); Ok(data) } None => err!(TlsOutOfBounds), - }; + } } fn store_tls(&mut self, key: TlsKey, new_data: Scalar) -> EvalResult<'tcx> { - return match self.data.thread_local.get_mut(&key) { + match self.data.thread_local.get_mut(&key) { Some(&mut TlsEntry { ref mut data, .. }) => { trace!("TLS key {} stored: {:?}", key, new_data); *data = new_data; Ok(()) } None => err!(TlsOutOfBounds), - }; + } } /// Returns a dtor, its argument and its index, if one is supposed to run @@ -104,7 +104,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> MemoryExt<'tcx> for Memory<'a, 'mir, 'tcx, Evalu } } } - return Ok(None); + Ok(None) } } @@ -124,8 +124,8 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' Place::undef(), StackPopCleanup::None, )?; - let arg_local = self.frame().mir.args_iter().next().ok_or( - EvalErrorKind::AbiViolation("TLS dtor does not take enough arguments.".to_owned()), + let arg_local = self.frame().mir.args_iter().next().ok_or_else( + || EvalErrorKind::AbiViolation("TLS dtor does not take enough arguments.".to_owned()), )?; let dest = self.eval_place(&mir::Place::Local(arg_local))?; let ty = self.tcx.mk_mut_ptr(self.tcx.types.u8); diff --git a/src/validation.rs b/src/validation.rs index 851f5df9792e4..758fd5d274701 100644 --- a/src/validation.rs +++ b/src/validation.rs @@ -135,10 +135,10 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' } fn abstract_place(&self, place: &mir::Place<'tcx>) -> EvalResult<'tcx, AbsPlace<'tcx>> { - Ok(match place { - &mir::Place::Local(l) => AbsPlace::Local(l), - &mir::Place::Static(ref s) => AbsPlace::Static(s.def_id), - &mir::Place::Projection(ref p) => + Ok(match *place { + mir::Place::Local(l) => AbsPlace::Local(l), + mir::Place::Static(ref s) => AbsPlace::Static(s.def_id), + mir::Place::Projection(ref p) => AbsPlace::Projection(Box::new(self.abstract_place_projection(&*p)?)), }) } @@ -378,11 +378,8 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' mut layout: ty::layout::TyLayout<'tcx>, i: usize, ) -> EvalResult<'tcx, Ty<'tcx>> { - match base { - Place::Ptr { extra: PlaceExtra::DowncastVariant(variant_index), .. } => { - layout = layout.for_variant(&self, variant_index); - } - _ => {} + if let Place::Ptr { extra: PlaceExtra::DowncastVariant(variant_index), .. } = base { + layout = layout.for_variant(&self, variant_index); } let tcx = self.tcx.tcx; Ok(match layout.ty.sty { @@ -667,12 +664,11 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' // Inner lifetimes *outlive* outer ones, so only if we have no lifetime restriction yet, // we record the region of this borrow to the context. if query.re == None { - match *region { - ReScope(scope) => query.re = Some(scope), - // It is possible for us to encounter erased lifetimes here because the lifetimes in - // this functions' Subst will be erased. - _ => {} + if let ReScope(scope) = *region { + query.re = Some(scope); } + // It is possible for us to encounter erased lifetimes here because the lifetimes in + // this functions' Subst will be erased. } self.validate_ptr(val, query.place.0, pointee_ty, query.re, query.mutbl, mode)?; } @@ -772,7 +768,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' let variant_idx = self.read_discriminant_as_variant_index(query.place.1, query.ty)?; let variant = &adt.variants[variant_idx]; - if variant.fields.len() > 0 { + if !variant.fields.is_empty() { // Downcast to this variant, if needed let place = if adt.is_enum() { ( From d4e8d0b935900e716b6154a9458730c29a67c182 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 11 Jul 2018 17:42:35 +0200 Subject: [PATCH 0115/3747] fix deprecation warning: use dirs crate for home_dir --- Cargo.toml | 1 + tests/compiletest.rs | 5 +++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 86ac2c040fd1c..54a1c5456e47d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -31,3 +31,4 @@ cargo_miri = ["cargo_metadata"] [dev-dependencies] compiletest_rs = { version = "0.3.4", features = ["tmp"] } +dirs = "1.0.2" diff --git a/tests/compiletest.rs b/tests/compiletest.rs index e62fa4e65e630..342ea92280de0 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -1,6 +1,7 @@ #![feature(slice_concat_ext)] extern crate compiletest_rs as compiletest; +extern crate dirs; use std::slice::SliceConcatExt; use std::path::{PathBuf, Path}; @@ -50,7 +51,7 @@ fn compile_fail(sysroot: &Path, path: &str, target: &str, host: &str, fullmir: b // skip fullmir on nonhost return; } - let sysroot = std::env::home_dir().unwrap() + let sysroot = dirs::home_dir().unwrap() .join(".xargo") .join("HOST"); flags.push(format!("--sysroot {}", sysroot.to_str().unwrap())); @@ -110,7 +111,7 @@ fn miri_pass(path: &str, target: &str, host: &str, fullmir: bool, opt: bool) { // skip fullmir on nonhost return; } - let sysroot = std::env::home_dir().unwrap() + let sysroot = dirs::home_dir().unwrap() .join(".xargo") .join("HOST"); From 7023126094a33c0be77f9c5c3dbdd5ef9e136064 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 11 Jul 2018 17:53:44 +0200 Subject: [PATCH 0116/3747] stop producing binaries --- src/bin/miri.rs | 5 +---- tests/run-pass/aux_test.rs | 9 --------- tests/run-pass/auxiliary/dep.rs | 1 - 3 files changed, 1 insertion(+), 14 deletions(-) delete mode 100644 tests/run-pass/aux_test.rs delete mode 100644 tests/run-pass/auxiliary/dep.rs diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 3001500d2e07b..f6dc65a0d27c3 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -87,10 +87,7 @@ impl<'a> CompilerCalls<'a> for MiriCompilerCalls { control.after_hir_lowering.callback = Box::new(after_hir_lowering); let start_fn = this.start_fn; control.after_analysis.callback = Box::new(move |state| after_analysis(state, start_fn)); - if sess.target.target != sess.host { - // only fully compile targets on the host. linking will fail for cross-compilation. - control.after_analysis.stop = Compilation::Stop; - } + control.after_analysis.stop = Compilation::Stop; control } } diff --git a/tests/run-pass/aux_test.rs b/tests/run-pass/aux_test.rs deleted file mode 100644 index beed82e058029..0000000000000 --- a/tests/run-pass/aux_test.rs +++ /dev/null @@ -1,9 +0,0 @@ -// aux-build:dep.rs - -// ignore-cross-compile - -extern crate dep; - -fn main() { - dep::foo(); -} diff --git a/tests/run-pass/auxiliary/dep.rs b/tests/run-pass/auxiliary/dep.rs deleted file mode 100644 index b76b4321d62aa..0000000000000 --- a/tests/run-pass/auxiliary/dep.rs +++ /dev/null @@ -1 +0,0 @@ -pub fn foo() {} From 197b75764cb1069c7fb063e9ef25d41cb36729d2 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 11 Jul 2018 19:33:52 +0200 Subject: [PATCH 0117/3747] without aux builds, we don't need to set always-encode-mir any more --- src/bin/miri.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/bin/miri.rs b/src/bin/miri.rs index f6dc65a0d27c3..2cc22d7a7debc 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -229,9 +229,6 @@ fn main() { } }); - // Make sure we always have all the MIR (e.g. for auxilary builds in unit tests). - args.push("-Zalways-encode-mir".to_owned()); - rustc_driver::run_compiler(&args, Box::new(MiriCompilerCalls { default: Box::new(RustcDefaultCalls), start_fn, From dd7cc47e5c73eeff21c358e6bf10d6db656ce0c4 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 11 Jul 2018 19:39:09 +0200 Subject: [PATCH 0118/3747] document -Zmiri-start-fn; make its logic more clear --- README.md | 3 +++ src/bin/miri.rs | 9 ++------- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 7660735a7cefa..32eca3652945f 100644 --- a/README.md +++ b/README.md @@ -76,6 +76,9 @@ MIRI_SYSROOT=~/.xargo/HOST cargo run --bin miri tests/run-pass-fullmir/vecs.rs Notice that you will have to re-run the last step of the preparations above when your toolchain changes (e.g., when you update the nightly). +You can also set `-Zmiri-start-fn` to make miri start evaluation with the +`start_fn` lang item, instead of starting at the `main` function. + ## Contributing and getting help Check out the issues on this GitHub repository for some ideas. There's lots that diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 3001500d2e07b..bd0a930471b24 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -138,13 +138,8 @@ fn after_analysis<'a, 'tcx>(state: &mut CompileState<'a, 'tcx>, use_start_fn: bo ); } else if let Some((entry_node_id, _, _)) = *state.session.entry_fn.borrow() { let entry_def_id = tcx.hir.local_def_id(entry_node_id); - let start_wrapper = tcx.lang_items().start_fn().and_then(|start_fn| { - if use_start_fn { - Some(start_fn) - } else { - None - } - }); + // Use start_fn lang item if it is available and we have -Zmiri-start-fn set + let start_wrapper = if use_start_fn { tcx.lang_items().start_fn() } else { None }; miri::eval_main(tcx, entry_def_id, start_wrapper); state.session.abort_if_errors(); From e5de51a322e944f5dc7a0bcf9d8afcb3275c7daf Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 11 Jul 2018 19:50:13 +0200 Subject: [PATCH 0119/3747] use -Zmiri-start-fn as a clue to REQUIRE the lang item to be present --- src/bin/miri.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/bin/miri.rs b/src/bin/miri.rs index bd0a930471b24..82261f9dfac99 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -138,8 +138,12 @@ fn after_analysis<'a, 'tcx>(state: &mut CompileState<'a, 'tcx>, use_start_fn: bo ); } else if let Some((entry_node_id, _, _)) = *state.session.entry_fn.borrow() { let entry_def_id = tcx.hir.local_def_id(entry_node_id); - // Use start_fn lang item if it is available and we have -Zmiri-start-fn set - let start_wrapper = if use_start_fn { tcx.lang_items().start_fn() } else { None }; + // Use start_fn lang item if we have -Zmiri-start-fn set + let start_wrapper = if use_start_fn { + Some(tcx.lang_items().start_fn().unwrap()) + } else { + None + }; miri::eval_main(tcx, entry_def_id, start_wrapper); state.session.abort_if_errors(); From 5fc990cebdf2c3732b65ab921f9c7e2c8ba79dc3 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 12 Jul 2018 10:17:50 +0200 Subject: [PATCH 0120/3747] bump dependencies --- Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 54a1c5456e47d..c6128b2405aa2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,8 +20,8 @@ required-features = ["cargo_miri"] [dependencies] byteorder = { version = "1.1", features = ["i128"]} -cargo_metadata = { version = "0.5", optional = true } -regex = "0.2.2" +cargo_metadata = { version = "0.6", optional = true } +regex = "1.0" lazy_static = "1.0" env_logger = "0.5.0-rc.1" log = "0.4" From ff5b0fee33b38f15d1bac51e19c6cb2b739e2879 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 11 Jul 2018 21:07:17 +0200 Subject: [PATCH 0121/3747] fix many tests and ignore some others; enable compile_fail tests again --- tests/compile-fail-fullmir/undefined_byte_read.rs | 3 ++- tests/compile-fail/deallocate-bad-alignment.rs | 2 +- tests/compile-fail/deallocate-bad-size.rs | 2 +- tests/compile-fail/deallocate-twice.rs | 2 +- tests/compile-fail/match_char.rs | 2 ++ tests/compile-fail/memleak.rs | 1 + tests/compile-fail/memleak_rc.rs | 1 + tests/compile-fail/overflowing-rsh-2.rs | 2 +- tests/compile-fail/reallocate-bad-size.rs | 4 ++-- tests/compile-fail/reallocate-change-alloc.rs | 6 +++--- tests/compile-fail/reallocate-dangling.rs | 4 ++-- tests/compile-fail/static_memory_modification.rs | 1 + tests/compiletest.rs | 6 +++--- 13 files changed, 21 insertions(+), 15 deletions(-) diff --git a/tests/compile-fail-fullmir/undefined_byte_read.rs b/tests/compile-fail-fullmir/undefined_byte_read.rs index 99404b7d5f3f5..24718bce7db96 100644 --- a/tests/compile-fail-fullmir/undefined_byte_read.rs +++ b/tests/compile-fail-fullmir/undefined_byte_read.rs @@ -4,6 +4,7 @@ fn main() { let v: Vec = Vec::with_capacity(10); let undef = unsafe { *v.get_unchecked(5) }; - let x = undef + 1; //~ ERROR: attempted to read undefined bytes + let x = undef + 1; //~ ERROR: error + //~^ NOTE attempted to read undefined bytes panic!("this should never print: {}", x); } diff --git a/tests/compile-fail/deallocate-bad-alignment.rs b/tests/compile-fail/deallocate-bad-alignment.rs index 36e99cb11f725..4b89f0ac70c79 100644 --- a/tests/compile-fail/deallocate-bad-alignment.rs +++ b/tests/compile-fail/deallocate-bad-alignment.rs @@ -9,7 +9,7 @@ use std::alloc::*; fn main() { unsafe { - let x = Global.alloc(Layout::from_size_align_unchecked(1, 1)); + let x = Global.alloc(Layout::from_size_align_unchecked(1, 1)).unwrap(); Global.dealloc(x, Layout::from_size_align_unchecked(1, 2)); } } diff --git a/tests/compile-fail/deallocate-bad-size.rs b/tests/compile-fail/deallocate-bad-size.rs index f1271cefd1ac1..3a74245816c46 100644 --- a/tests/compile-fail/deallocate-bad-size.rs +++ b/tests/compile-fail/deallocate-bad-size.rs @@ -9,7 +9,7 @@ use std::alloc::*; fn main() { unsafe { - let x = Global.alloc(Layout::from_size_align_unchecked(1, 1)); + let x = Global.alloc(Layout::from_size_align_unchecked(1, 1)).unwrap(); Global.dealloc(x, Layout::from_size_align_unchecked(2, 1)); } } diff --git a/tests/compile-fail/deallocate-twice.rs b/tests/compile-fail/deallocate-twice.rs index 58fcb7409495c..613edf3c6af95 100644 --- a/tests/compile-fail/deallocate-twice.rs +++ b/tests/compile-fail/deallocate-twice.rs @@ -9,7 +9,7 @@ use std::alloc::*; fn main() { unsafe { - let x = Global.alloc(Layout::from_size_align_unchecked(1, 1)); + let x = Global.alloc(Layout::from_size_align_unchecked(1, 1)).unwrap(); Global.dealloc(x, Layout::from_size_align_unchecked(1, 1)); Global.dealloc(x, Layout::from_size_align_unchecked(1, 1)); } diff --git a/tests/compile-fail/match_char.rs b/tests/compile-fail/match_char.rs index 15ce2f2f79525..0d45d70eb781a 100644 --- a/tests/compile-fail/match_char.rs +++ b/tests/compile-fail/match_char.rs @@ -1,3 +1,5 @@ +// ignore-test FIXME: we are not checking these things on match any more? + fn main() { assert!(std::char::from_u32(-1_i32 as u32).is_none()); match unsafe { std::mem::transmute::(-1) } { //~ ERROR constant evaluation error [E0080] diff --git a/tests/compile-fail/memleak.rs b/tests/compile-fail/memleak.rs index 71b4e2f442f31..c03cf50eb27f6 100644 --- a/tests/compile-fail/memleak.rs +++ b/tests/compile-fail/memleak.rs @@ -1,3 +1,4 @@ +// ignore-test FIXME: leak detection is disabled //error-pattern: the evaluated program leaked memory fn main() { diff --git a/tests/compile-fail/memleak_rc.rs b/tests/compile-fail/memleak_rc.rs index b2bc6722afb04..da3a58118a2a5 100644 --- a/tests/compile-fail/memleak_rc.rs +++ b/tests/compile-fail/memleak_rc.rs @@ -1,3 +1,4 @@ +// ignore-test FIXME: leak detection is disabled //error-pattern: the evaluated program leaked memory use std::rc::Rc; diff --git a/tests/compile-fail/overflowing-rsh-2.rs b/tests/compile-fail/overflowing-rsh-2.rs index 4447b9d7579a7..967c8b020cca0 100644 --- a/tests/compile-fail/overflowing-rsh-2.rs +++ b/tests/compile-fail/overflowing-rsh-2.rs @@ -13,5 +13,5 @@ fn main() { // Make sure we catch overflows that would be hidden by first casting the RHS to u32 let _n = 1i64 >> (u32::max_value() as i64 + 1); //~ ERROR constant evaluation error [E0080] - //~^ NOTE suiriuruihrihue + //~^ NOTE attempt to shift right with overflow } diff --git a/tests/compile-fail/reallocate-bad-size.rs b/tests/compile-fail/reallocate-bad-size.rs index d75c195d521e0..f85b651e85730 100644 --- a/tests/compile-fail/reallocate-bad-size.rs +++ b/tests/compile-fail/reallocate-bad-size.rs @@ -9,7 +9,7 @@ use std::alloc::*; fn main() { unsafe { - let x = Global.alloc(Layout::from_size_align_unchecked(1, 1)); - let _y = Global.realloc(x, Layout::from_size_align_unchecked(2, 1), 1); + let x = Global.alloc(Layout::from_size_align_unchecked(1, 1)).unwrap(); + let _y = Global.realloc(x, Layout::from_size_align_unchecked(2, 1), 1).unwrap(); } } diff --git a/tests/compile-fail/reallocate-change-alloc.rs b/tests/compile-fail/reallocate-change-alloc.rs index d8234e933300b..03040cd178da2 100644 --- a/tests/compile-fail/reallocate-change-alloc.rs +++ b/tests/compile-fail/reallocate-change-alloc.rs @@ -7,9 +7,9 @@ use std::alloc::*; fn main() { unsafe { - let x = Global.alloc(Layout::from_size_align_unchecked(1, 1)); - let _y = Global.realloc(x, Layout::from_size_align_unchecked(1, 1), 1); - let _z = *(x as *mut u8); //~ ERROR constant evaluation error [E0080] + let x = Global.alloc(Layout::from_size_align_unchecked(1, 1)).unwrap(); + let _y = Global.realloc(x, Layout::from_size_align_unchecked(1, 1), 1).unwrap(); + let _z = *(x.as_ptr() as *mut u8); //~ ERROR constant evaluation error [E0080] //~^ NOTE dangling pointer was dereferenced } } diff --git a/tests/compile-fail/reallocate-dangling.rs b/tests/compile-fail/reallocate-dangling.rs index 39b60407160e4..6dfb7fe2b9663 100644 --- a/tests/compile-fail/reallocate-dangling.rs +++ b/tests/compile-fail/reallocate-dangling.rs @@ -9,8 +9,8 @@ use std::alloc::*; fn main() { unsafe { - let x = Global.alloc(Layout::from_size_align_unchecked(1, 1)); + let x = Global.alloc(Layout::from_size_align_unchecked(1, 1)).unwrap(); Global.dealloc(x, Layout::from_size_align_unchecked(1, 1)); - Global.realloc(x, Layout::from_size_align_unchecked(1, 1), 1); + Global.realloc(x, Layout::from_size_align_unchecked(1, 1), 1).unwrap(); } } diff --git a/tests/compile-fail/static_memory_modification.rs b/tests/compile-fail/static_memory_modification.rs index 7182f40d994dd..a85ff545ee423 100644 --- a/tests/compile-fail/static_memory_modification.rs +++ b/tests/compile-fail/static_memory_modification.rs @@ -1,3 +1,4 @@ +// ignore-test FIXME: we are not making these statics read-only any more? static X: usize = 5; #[allow(mutable_transmutes)] diff --git a/tests/compiletest.rs b/tests/compiletest.rs index 342ea92280de0..401499f6c5fa7 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -192,7 +192,9 @@ fn run_pass_miri_noopt() { } #[test] -#[ignore] // FIXME: Disabled for now, as the optimizer is pretty broken and crashes... +#[ignore] +// FIXME: Disabled for now, as the optimizer is pretty broken and crashes... +// See https://github.com/rust-lang/rust/issues/50411 fn run_pass_miri_opt() { run_pass_miri(true); } @@ -204,13 +206,11 @@ fn run_pass_rustc() { } #[test] -#[should_panic] // TODO: update test errors fn compile_fail_miri() { let sysroot = get_sysroot(); let host = get_host(); // FIXME: run tests for other targets, too compile_fail(&sysroot, "tests/compile-fail", &host, &host, true); - compile_fail(&sysroot, "tests/compile-fail-fullmir", &host, &host, true); } From 5f2f2546957e473bf146bcb35a96d80d60e4022d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 11 Jul 2018 21:13:42 +0200 Subject: [PATCH 0122/3747] move tests that no longer need MIR out of fullmir --- README.md | 2 +- .../undefined_byte_read.rs | 0 tests/compiletest.rs | 2 +- tests/{run-pass-fullmir => run-pass}/heap.rs | 0 tests/{run-pass-fullmir => run-pass}/issue-15080.rs | 0 tests/{run-pass-fullmir => run-pass}/move-arg-2-unique.rs | 0 tests/{run-pass-fullmir => run-pass}/regions-mock-trans.rs | 0 tests/{run-pass-fullmir => run-pass}/vecs.rs | 0 8 files changed, 2 insertions(+), 2 deletions(-) rename tests/{compile-fail-fullmir => compile-fail}/undefined_byte_read.rs (100%) rename tests/{run-pass-fullmir => run-pass}/heap.rs (100%) rename tests/{run-pass-fullmir => run-pass}/issue-15080.rs (100%) rename tests/{run-pass-fullmir => run-pass}/move-arg-2-unique.rs (100%) rename tests/{run-pass-fullmir => run-pass}/regions-mock-trans.rs (100%) rename tests/{run-pass-fullmir => run-pass}/vecs.rs (100%) diff --git a/README.md b/README.md index 32eca3652945f..38bf1147dab03 100644 --- a/README.md +++ b/README.md @@ -70,7 +70,7 @@ RUSTFLAGS='-Zalways-encode-mir' xargo build Now you can run miri against the libstd compiled by xargo: ```sh -MIRI_SYSROOT=~/.xargo/HOST cargo run --bin miri tests/run-pass-fullmir/vecs.rs +MIRI_SYSROOT=~/.xargo/HOST cargo run --bin miri tests/run-pass-fullmir/hashmap.rs ``` Notice that you will have to re-run the last step of the preparations above when diff --git a/tests/compile-fail-fullmir/undefined_byte_read.rs b/tests/compile-fail/undefined_byte_read.rs similarity index 100% rename from tests/compile-fail-fullmir/undefined_byte_read.rs rename to tests/compile-fail/undefined_byte_read.rs diff --git a/tests/compiletest.rs b/tests/compiletest.rs index 401499f6c5fa7..d5ed02504ab67 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -212,5 +212,5 @@ fn compile_fail_miri() { // FIXME: run tests for other targets, too compile_fail(&sysroot, "tests/compile-fail", &host, &host, true); - compile_fail(&sysroot, "tests/compile-fail-fullmir", &host, &host, true); + //compile_fail(&sysroot, "tests/compile-fail-fullmir", &host, &host, true); } diff --git a/tests/run-pass-fullmir/heap.rs b/tests/run-pass/heap.rs similarity index 100% rename from tests/run-pass-fullmir/heap.rs rename to tests/run-pass/heap.rs diff --git a/tests/run-pass-fullmir/issue-15080.rs b/tests/run-pass/issue-15080.rs similarity index 100% rename from tests/run-pass-fullmir/issue-15080.rs rename to tests/run-pass/issue-15080.rs diff --git a/tests/run-pass-fullmir/move-arg-2-unique.rs b/tests/run-pass/move-arg-2-unique.rs similarity index 100% rename from tests/run-pass-fullmir/move-arg-2-unique.rs rename to tests/run-pass/move-arg-2-unique.rs diff --git a/tests/run-pass-fullmir/regions-mock-trans.rs b/tests/run-pass/regions-mock-trans.rs similarity index 100% rename from tests/run-pass-fullmir/regions-mock-trans.rs rename to tests/run-pass/regions-mock-trans.rs diff --git a/tests/run-pass-fullmir/vecs.rs b/tests/run-pass/vecs.rs similarity index 100% rename from tests/run-pass-fullmir/vecs.rs rename to tests/run-pass/vecs.rs From eb8195f095e651842a93710ad005e6f1724373f4 Mon Sep 17 00:00:00 2001 From: memoryleak47 Date: Thu, 5 Apr 2018 04:25:43 +0200 Subject: [PATCH 0123/3747] typo --- tests/run-pass/regions-mock-trans.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/run-pass/regions-mock-trans.rs b/tests/run-pass/regions-mock-trans.rs index cef62e47a56c2..74e94ddbf84f6 100644 --- a/tests/run-pass/regions-mock-trans.rs +++ b/tests/run-pass/regions-mock-trans.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// FIXME: We handle uninitialzied storage here, which currently makes validation fail. +// FIXME: We handle uninitialized storage here, which currently makes validation fail. // compile-flags: -Zmir-emit-validate=0 //ignore-msvc From 949106148cb7611ee2d8288b1092d1fa3ccdcbb0 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 12 Jul 2018 10:24:25 +0200 Subject: [PATCH 0124/3747] ignore panic test on Windows --- tests/compile-fail/panic.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/compile-fail/panic.rs b/tests/compile-fail/panic.rs index 80149eeffaa64..1f9e8f6e1d0b0 100644 --- a/tests/compile-fail/panic.rs +++ b/tests/compile-fail/panic.rs @@ -1,3 +1,4 @@ +//ignore-windows // FIXME: Something in panic handling fails validation with full-MIR // compile-flags: -Zmir-emit-validate=0 //error-pattern: the evaluated program panicked From 01578ca6b3b976799c6cc6ba607143ed81f09a79 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 12 Jul 2018 10:58:48 +0200 Subject: [PATCH 0125/3747] don't run all compile-fail tests with full MIR --- .../deallocate-bad-alignment.rs | 0 .../deallocate-bad-size.rs | 0 .../deallocate-twice.rs | 0 .../out_of_bounds_ptr_1.rs | 0 .../out_of_bounds_ptr_2.rs | 0 .../ptr_offset_overflow.rs | 0 .../reallocate-bad-size.rs | 0 .../reallocate-change-alloc.rs | 0 .../reallocate-dangling.rs | 0 tests/{compile-fail => compile-fail-fullmir}/stack_free.rs | 0 tests/compiletest.rs | 4 ++-- 11 files changed, 2 insertions(+), 2 deletions(-) rename tests/{compile-fail => compile-fail-fullmir}/deallocate-bad-alignment.rs (100%) rename tests/{compile-fail => compile-fail-fullmir}/deallocate-bad-size.rs (100%) rename tests/{compile-fail => compile-fail-fullmir}/deallocate-twice.rs (100%) rename tests/{compile-fail => compile-fail-fullmir}/out_of_bounds_ptr_1.rs (100%) rename tests/{compile-fail => compile-fail-fullmir}/out_of_bounds_ptr_2.rs (100%) rename tests/{compile-fail => compile-fail-fullmir}/ptr_offset_overflow.rs (100%) rename tests/{compile-fail => compile-fail-fullmir}/reallocate-bad-size.rs (100%) rename tests/{compile-fail => compile-fail-fullmir}/reallocate-change-alloc.rs (100%) rename tests/{compile-fail => compile-fail-fullmir}/reallocate-dangling.rs (100%) rename tests/{compile-fail => compile-fail-fullmir}/stack_free.rs (100%) diff --git a/tests/compile-fail/deallocate-bad-alignment.rs b/tests/compile-fail-fullmir/deallocate-bad-alignment.rs similarity index 100% rename from tests/compile-fail/deallocate-bad-alignment.rs rename to tests/compile-fail-fullmir/deallocate-bad-alignment.rs diff --git a/tests/compile-fail/deallocate-bad-size.rs b/tests/compile-fail-fullmir/deallocate-bad-size.rs similarity index 100% rename from tests/compile-fail/deallocate-bad-size.rs rename to tests/compile-fail-fullmir/deallocate-bad-size.rs diff --git a/tests/compile-fail/deallocate-twice.rs b/tests/compile-fail-fullmir/deallocate-twice.rs similarity index 100% rename from tests/compile-fail/deallocate-twice.rs rename to tests/compile-fail-fullmir/deallocate-twice.rs diff --git a/tests/compile-fail/out_of_bounds_ptr_1.rs b/tests/compile-fail-fullmir/out_of_bounds_ptr_1.rs similarity index 100% rename from tests/compile-fail/out_of_bounds_ptr_1.rs rename to tests/compile-fail-fullmir/out_of_bounds_ptr_1.rs diff --git a/tests/compile-fail/out_of_bounds_ptr_2.rs b/tests/compile-fail-fullmir/out_of_bounds_ptr_2.rs similarity index 100% rename from tests/compile-fail/out_of_bounds_ptr_2.rs rename to tests/compile-fail-fullmir/out_of_bounds_ptr_2.rs diff --git a/tests/compile-fail/ptr_offset_overflow.rs b/tests/compile-fail-fullmir/ptr_offset_overflow.rs similarity index 100% rename from tests/compile-fail/ptr_offset_overflow.rs rename to tests/compile-fail-fullmir/ptr_offset_overflow.rs diff --git a/tests/compile-fail/reallocate-bad-size.rs b/tests/compile-fail-fullmir/reallocate-bad-size.rs similarity index 100% rename from tests/compile-fail/reallocate-bad-size.rs rename to tests/compile-fail-fullmir/reallocate-bad-size.rs diff --git a/tests/compile-fail/reallocate-change-alloc.rs b/tests/compile-fail-fullmir/reallocate-change-alloc.rs similarity index 100% rename from tests/compile-fail/reallocate-change-alloc.rs rename to tests/compile-fail-fullmir/reallocate-change-alloc.rs diff --git a/tests/compile-fail/reallocate-dangling.rs b/tests/compile-fail-fullmir/reallocate-dangling.rs similarity index 100% rename from tests/compile-fail/reallocate-dangling.rs rename to tests/compile-fail-fullmir/reallocate-dangling.rs diff --git a/tests/compile-fail/stack_free.rs b/tests/compile-fail-fullmir/stack_free.rs similarity index 100% rename from tests/compile-fail/stack_free.rs rename to tests/compile-fail-fullmir/stack_free.rs diff --git a/tests/compiletest.rs b/tests/compiletest.rs index d5ed02504ab67..a521217fc5c27 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -211,6 +211,6 @@ fn compile_fail_miri() { let host = get_host(); // FIXME: run tests for other targets, too - compile_fail(&sysroot, "tests/compile-fail", &host, &host, true); - //compile_fail(&sysroot, "tests/compile-fail-fullmir", &host, &host, true); + compile_fail(&sysroot, "tests/compile-fail", &host, &host, false); + compile_fail(&sysroot, "tests/compile-fail-fullmir", &host, &host, true); } From 8ce16a7c30b551cf36314af183fd5c49308d60cc Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 12 Jul 2018 11:01:09 +0200 Subject: [PATCH 0126/3747] remove xargo logic; instead rely on MIRI_SYSROOT being set to run full MIR tests --- Cargo.toml | 1 - tests/compiletest.rs | 78 +++++++++++++++++++++++--------------------- 2 files changed, 40 insertions(+), 39 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 54a1c5456e47d..86ac2c040fd1c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -31,4 +31,3 @@ cargo_miri = ["cargo_metadata"] [dev-dependencies] compiletest_rs = { version = "0.3.4", features = ["tmp"] } -dirs = "1.0.2" diff --git a/tests/compiletest.rs b/tests/compiletest.rs index a521217fc5c27..9a2fd02f88cda 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -1,7 +1,6 @@ #![feature(slice_concat_ext)] extern crate compiletest_rs as compiletest; -extern crate dirs; use std::slice::SliceConcatExt; use std::path::{PathBuf, Path}; @@ -31,7 +30,21 @@ fn rustc_lib_path() -> PathBuf { option_env!("RUSTC_LIB_PATH").unwrap().into() } -fn compile_fail(sysroot: &Path, path: &str, target: &str, host: &str, fullmir: bool) { +fn have_fullmir() -> bool { + // We assume we have full MIR when MIRI_SYSROOT is set or when we are in rustc + std::env::var("MIRI_SYSROOT").is_ok() || rustc_test_suite().is_some() +} + +fn compile_fail(sysroot: &Path, path: &str, target: &str, host: &str, need_fullmir: bool) { + if need_fullmir && !have_fullmir() { + eprintln!( + "## Skipping compile-fail tests in {} against miri for target {} due to missing mir", + path, + target + ); + return; + } + eprintln!( "## Running compile-fail tests in {} against miri for target {}", path, @@ -45,28 +58,16 @@ fn compile_fail(sysroot: &Path, path: &str, target: &str, host: &str, fullmir: b config.run_lib_path = rustc_lib_path(); config.compile_lib_path = rustc_lib_path(); } - // if we are building as part of the rustc test suite, we already have fullmir for everything - if fullmir && rustc_test_suite().is_none() { - if host != target { - // skip fullmir on nonhost - return; - } - let sysroot = dirs::home_dir().unwrap() - .join(".xargo") - .join("HOST"); - flags.push(format!("--sysroot {}", sysroot.to_str().unwrap())); - config.src_base = PathBuf::from(path.to_string()); - } else { - flags.push(format!("--sysroot {}", sysroot.to_str().unwrap())); - config.src_base = PathBuf::from(path.to_string()); - } + flags.push(format!("--sysroot {}", sysroot.display())); + config.src_base = PathBuf::from(path.to_string()); flags.push("-Zmir-emit-validate=1".to_owned()); config.target_rustcflags = Some(flags.join(" ")); config.target = target.to_owned(); + config.host = host.to_owned(); compiletest::run_tests(&config); } -fn run_pass(path: &str) { +fn rustc_pass(sysroot: &Path, path: &str) { eprintln!("## Running run-pass tests in {} against rustc", path); let mut config = compiletest::Config::default().tempdir(); config.mode = "run-pass".parse().expect("Invalid mode"); @@ -75,7 +76,7 @@ fn run_pass(path: &str) { config.rustc_path = rustc_path; config.run_lib_path = rustc_lib_path(); config.compile_lib_path = rustc_lib_path(); - config.target_rustcflags = Some(format!("-Dwarnings --sysroot {}", get_sysroot().display())); + config.target_rustcflags = Some(format!("-Dwarnings --sysroot {}", sysroot.display())); } else { config.target_rustcflags = Some("-Dwarnings".to_owned()); } @@ -83,7 +84,16 @@ fn run_pass(path: &str) { compiletest::run_tests(&config); } -fn miri_pass(path: &str, target: &str, host: &str, fullmir: bool, opt: bool) { +fn miri_pass(sysroot: &Path, path: &str, target: &str, host: &str, need_fullmir: bool, opt: bool) { + if need_fullmir && !have_fullmir() { + eprintln!( + "## Skipping run-pass tests in {} against miri for target {} due to missing mir", + path, + target + ); + return; + } + let opt_str = if opt { " with optimizations" } else { "" }; eprintln!( "## Running run-pass tests in {} against miri for target {}{}", @@ -102,21 +112,9 @@ fn miri_pass(path: &str, target: &str, host: &str, fullmir: bool, opt: bool) { config.compile_lib_path = rustc_lib_path(); } let mut flags = Vec::new(); - // Control miri logging. This is okay despite concurrent test execution as all tests - // will set this env var to the same value. - env::set_var("MIRI_LOG", "warn"); - // if we are building as part of the rustc test suite, we already have fullmir for everything - if fullmir && rustc_test_suite().is_none() { - if host != target { - // skip fullmir on nonhost - return; - } - let sysroot = dirs::home_dir().unwrap() - .join(".xargo") - .join("HOST"); - + flags.push(format!("--sysroot {}", sysroot.display())); + if have_fullmir() { flags.push("-Zmiri-start-fn".to_owned()); - flags.push(format!("--sysroot {}", sysroot.to_str().unwrap())); } if opt { flags.push("-Zmir-opt-level=3".to_owned()); @@ -125,6 +123,9 @@ 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()); } + // Control miri logging. This is okay despite concurrent test execution as all tests + // will set this env var to the same value. + env::set_var("MIRI_LOG", "warn"); config.target_rustcflags = Some(flags.join(" ")); compiletest::run_tests(&config); } @@ -181,9 +182,9 @@ fn run_pass_miri(opt: bool) { let host = get_host(); for_all_targets(&sysroot, |target| { - miri_pass("tests/run-pass", &target, &host, false, opt); + miri_pass(&sysroot, "tests/run-pass", &target, &host, false, opt); }); - miri_pass("tests/run-pass-fullmir", &host, &host, true, opt); + miri_pass(&sysroot, "tests/run-pass-fullmir", &host, &host, true, opt); } #[test] @@ -201,8 +202,9 @@ fn run_pass_miri_opt() { #[test] fn run_pass_rustc() { - run_pass("tests/run-pass"); - run_pass("tests/run-pass-fullmir"); + let sysroot = get_sysroot(); + rustc_pass(&sysroot, "tests/run-pass"); + rustc_pass(&sysroot, "tests/run-pass-fullmir"); } #[test] From 9718d73ac86a428b7e11de8ef0215ff6ac85d9fb Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 12 Jul 2018 11:26:09 +0200 Subject: [PATCH 0127/3747] colored test output! --- Cargo.toml | 1 + tests/compiletest.rs | 21 ++++++++++++--------- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 86ac2c040fd1c..d01ce4f5baf8c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -31,3 +31,4 @@ cargo_miri = ["cargo_metadata"] [dev-dependencies] compiletest_rs = { version = "0.3.4", features = ["tmp"] } +colored = "1.6" diff --git a/tests/compiletest.rs b/tests/compiletest.rs index 9a2fd02f88cda..cfbfa70d42eea 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -1,6 +1,9 @@ #![feature(slice_concat_ext)] extern crate compiletest_rs as compiletest; +extern crate colored; + +use colored::*; use std::slice::SliceConcatExt; use std::path::{PathBuf, Path}; @@ -37,19 +40,19 @@ fn have_fullmir() -> bool { fn compile_fail(sysroot: &Path, path: &str, target: &str, host: &str, need_fullmir: bool) { if need_fullmir && !have_fullmir() { - eprintln!( + eprintln!("{}", format!( "## Skipping compile-fail tests in {} against miri for target {} due to missing mir", path, target - ); + ).yellow().bold()); return; } - eprintln!( + eprintln!("{}", format!( "## Running compile-fail tests in {} against miri for target {}", path, target - ); + ).green().bold()); let mut config = compiletest::Config::default().tempdir(); config.mode = "compile-fail".parse().expect("Invalid mode"); config.rustc_path = miri_path(); @@ -68,7 +71,7 @@ fn compile_fail(sysroot: &Path, path: &str, target: &str, host: &str, need_fullm } fn rustc_pass(sysroot: &Path, path: &str) { - eprintln!("## Running run-pass tests in {} against rustc", path); + eprintln!("{}", format!("## Running run-pass tests in {} against rustc", path).green().bold()); let mut config = compiletest::Config::default().tempdir(); config.mode = "run-pass".parse().expect("Invalid mode"); config.src_base = PathBuf::from(path); @@ -86,21 +89,21 @@ fn rustc_pass(sysroot: &Path, path: &str) { fn miri_pass(sysroot: &Path, path: &str, target: &str, host: &str, need_fullmir: bool, opt: bool) { if need_fullmir && !have_fullmir() { - eprintln!( + eprintln!("{}", format!( "## Skipping run-pass tests in {} against miri for target {} due to missing mir", path, target - ); + ).yellow().bold()); return; } let opt_str = if opt { " with optimizations" } else { "" }; - eprintln!( + eprintln!("{}", format!( "## Running run-pass tests in {} against miri for target {}{}", path, target, opt_str - ); + ).green().bold()); let mut config = compiletest::Config::default().tempdir(); config.mode = "ui".parse().expect("Invalid mode"); config.src_base = PathBuf::from(path); From 105f7e7fb28041a7e0fb13123d5caadbaf881f24 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 12 Jul 2018 14:24:35 +0200 Subject: [PATCH 0128/3747] update debugging instructions in the README --- README.md | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 38bf1147dab03..d0ae5ec46ff9d 100644 --- a/README.md +++ b/README.md @@ -42,10 +42,22 @@ cargo run --bin miri tests/run-pass-fullmir/vecs.rs # Or whatever test you like. ## Debugging -You can get detailed, statement-by-statement traces by setting the `MIRI_LOG` -environment variable to `trace`. These traces are indented based on call stack -depth. You can get a much less verbose set of information with other logging -levels such as `warn`. +Since the heart of miri (the main interpreter engine) lives in rustc, tracing +the interpreter requires a version of rustc compiled with tracing. To this +end, you will have to compile your own rustc: +``` +git clone https://github.com/rust-lang/rust/ rustc +cd rustc +cp config.toml.example config.toml +# Now edit `config.toml` and set `debug-assertions = true` +./x.py build +rustup toolchain link custom build/x86_64-unknown-linux-gnu/stage2 +``` +The `build` step can take 30 to 60 minutes. + +Now, in the miri directory, you can `rustup override set custom` and re-build +everything. Finally, if you now set `RUST_LOG=rustc_mir::interpret=trace` as +environment variable, you will get detailed step-by-step tracing information. ## Running miri on your own project('s test suite) From 25c067ac7a82027c01035824257010dd6f84cb42 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 12 Jul 2018 15:01:10 +0200 Subject: [PATCH 0129/3747] testsuite: put everything into a single test to fix interleaved output mess --- tests/compiletest.rs | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/tests/compiletest.rs b/tests/compiletest.rs index cfbfa70d42eea..896d1cae5969e 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -190,27 +190,12 @@ fn run_pass_miri(opt: bool) { miri_pass(&sysroot, "tests/run-pass-fullmir", &host, &host, true, opt); } -#[test] -fn run_pass_miri_noopt() { - run_pass_miri(false); -} - -#[test] -#[ignore] -// FIXME: Disabled for now, as the optimizer is pretty broken and crashes... -// See https://github.com/rust-lang/rust/issues/50411 -fn run_pass_miri_opt() { - run_pass_miri(true); -} - -#[test] fn run_pass_rustc() { let sysroot = get_sysroot(); rustc_pass(&sysroot, "tests/run-pass"); rustc_pass(&sysroot, "tests/run-pass-fullmir"); } -#[test] fn compile_fail_miri() { let sysroot = get_sysroot(); let host = get_host(); @@ -219,3 +204,20 @@ fn compile_fail_miri() { compile_fail(&sysroot, "tests/compile-fail", &host, &host, false); compile_fail(&sysroot, "tests/compile-fail-fullmir", &host, &host, true); } + +#[test] +fn test() { + // We put everything into a single test to avoid the parallelism `cargo test` + // introduces. We still get parallelism within our tests because `compiletest` + // uses `libtest` which runs jobs in parallel. + + run_pass_rustc(); + + run_pass_miri(false); + + // FIXME: Disabled for now, as the optimizer is pretty broken and crashes... + // See https://github.com/rust-lang/rust/issues/50411 + //run_pass_miri(true); + + compile_fail_miri(); +} From 473c50405da7f11d2b33921d2910ae82184ad7fa Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 14 Jul 2018 11:02:09 +0200 Subject: [PATCH 0130/3747] refine rustc build instructions --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d0ae5ec46ff9d..4891575c05e52 100644 --- a/README.md +++ b/README.md @@ -50,7 +50,7 @@ git clone https://github.com/rust-lang/rust/ rustc cd rustc cp config.toml.example config.toml # Now edit `config.toml` and set `debug-assertions = true` -./x.py build +./x.py build src/rustc rustup toolchain link custom build/x86_64-unknown-linux-gnu/stage2 ``` The `build` step can take 30 to 60 minutes. From 30185d09f627e15effbb346bcacf06a37c7299e7 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 15 Jul 2018 11:21:56 +0200 Subject: [PATCH 0131/3747] make sure we show error messages even when we cannot show span --- src/lib.rs | 6 ++++-- tests/compile-fail-fullmir/reallocate-change-alloc.rs | 2 +- tests/compile-fail/alignment.rs | 2 +- tests/compile-fail/assume.rs | 2 +- tests/compile-fail/bitop-beyond-alignment.rs | 2 +- tests/compile-fail/cast_box_int_to_fn_ptr.rs | 2 +- tests/compile-fail/cast_fn_ptr.rs | 2 +- tests/compile-fail/cast_fn_ptr2.rs | 2 +- tests/compile-fail/cast_int_to_fn_ptr.rs | 2 +- tests/compile-fail/ctlz_nonzero.rs | 2 +- tests/compile-fail/cttz_nonzero.rs | 2 +- tests/compile-fail/dangling_pointer_deref.rs | 2 +- tests/compile-fail/deref_fn_ptr.rs | 2 +- tests/compile-fail/div-by-zero-2.rs | 2 +- tests/compile-fail/execute_memory.rs | 2 +- tests/compile-fail/fn_ptr_offset.rs | 2 +- tests/compile-fail/invalid_bool.rs | 2 +- tests/compile-fail/invalid_enum_discriminant.rs | 2 +- tests/compile-fail/match_char.rs | 2 +- tests/compile-fail/modifying_constants.rs | 2 +- tests/compile-fail/never_say_never.rs | 2 +- tests/compile-fail/never_transmute_humans.rs | 2 +- tests/compile-fail/never_transmute_void.rs | 2 +- tests/compile-fail/null_pointer_deref.rs | 2 +- tests/compile-fail/out_of_bounds_read.rs | 2 +- tests/compile-fail/out_of_bounds_read2.rs | 2 +- tests/compile-fail/overflowing-lsh-neg.rs | 2 +- tests/compile-fail/overflowing-rsh-2.rs | 2 +- tests/compile-fail/overflowing-rsh.rs | 2 +- ...erwriting_part_of_relocation_makes_the_rest_undefined.rs | 2 +- tests/compile-fail/pointer_byte_read_1.rs | 2 +- tests/compile-fail/pointer_byte_read_2.rs | 2 +- .../pointers_to_different_allocations_are_unorderable.rs | 2 +- tests/compile-fail/ptr_bitops.rs | 2 +- tests/compile-fail/ptr_int_cast.rs | 2 +- tests/compile-fail/reading_half_a_pointer.rs | 2 +- tests/compile-fail/reference_to_packed.rs | 2 +- tests/compile-fail/static_memory_modification.rs | 2 +- tests/compile-fail/static_memory_modification2.rs | 2 +- tests/compile-fail/static_memory_modification3.rs | 2 +- tests/compile-fail/transmute-pair-undef.rs | 2 +- tests/compile-fail/transmute_fat.rs | 2 +- tests/compile-fail/transmute_fat2.rs | 2 +- tests/compile-fail/unaligned_ptr_cast.rs | 2 +- tests/compile-fail/unaligned_ptr_cast2.rs | 2 +- tests/compile-fail/unaligned_ptr_cast_zst.rs | 2 +- tests/compile-fail/wild_pointer_deref.rs | 2 +- tests/compile-fail/zst.rs | 2 +- 48 files changed, 51 insertions(+), 49 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 75397262b225a..520d696405a1b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -274,9 +274,11 @@ pub fn eval_main<'a, 'tcx: 'a>( block.terminator().source_info.span }; - let mut err = struct_error(ecx.tcx.tcx.at(span), "constant evaluation error"); + let e = e.to_string(); + let msg = format!("constant evaluation error: {}", e); + let mut err = struct_error(ecx.tcx.tcx.at(span), msg.as_str()); let (frames, span) = ecx.generate_stacktrace(None); - err.span_label(span, e.to_string()); + err.span_label(span, e); for FrameInfo { span, location, .. } in frames { err.span_note(span, &format!("inside call to `{}`", location)); } diff --git a/tests/compile-fail-fullmir/reallocate-change-alloc.rs b/tests/compile-fail-fullmir/reallocate-change-alloc.rs index 03040cd178da2..a44ccf4c49cd8 100644 --- a/tests/compile-fail-fullmir/reallocate-change-alloc.rs +++ b/tests/compile-fail-fullmir/reallocate-change-alloc.rs @@ -9,7 +9,7 @@ fn main() { unsafe { let x = Global.alloc(Layout::from_size_align_unchecked(1, 1)).unwrap(); let _y = Global.realloc(x, Layout::from_size_align_unchecked(1, 1), 1).unwrap(); - let _z = *(x.as_ptr() as *mut u8); //~ ERROR constant evaluation error [E0080] + let _z = *(x.as_ptr() as *mut u8); //~ ERROR constant evaluation error //~^ NOTE dangling pointer was dereferenced } } diff --git a/tests/compile-fail/alignment.rs b/tests/compile-fail/alignment.rs index 9730fe473aa5d..71161f5d6da00 100644 --- a/tests/compile-fail/alignment.rs +++ b/tests/compile-fail/alignment.rs @@ -5,7 +5,7 @@ fn main() { let x_ptr: *mut u8 = &mut x[0]; let y_ptr = x_ptr as *mut u64; unsafe { - *y_ptr = 42; //~ ERROR constant evaluation error [E0080] + *y_ptr = 42; //~ ERROR constant evaluation error //~^ NOTE tried to access memory with alignment 1, but alignment } panic!("unreachable in miri"); diff --git a/tests/compile-fail/assume.rs b/tests/compile-fail/assume.rs index cf0632393ad6d..d9eec480cd0c6 100644 --- a/tests/compile-fail/assume.rs +++ b/tests/compile-fail/assume.rs @@ -5,7 +5,7 @@ fn main() { unsafe { std::intrinsics::assume(x < 10); std::intrinsics::assume(x > 1); - std::intrinsics::assume(x > 42); //~ ERROR constant evaluation error [E0080] + std::intrinsics::assume(x > 42); //~ ERROR constant evaluation error //~^ NOTE `assume` argument was false } } diff --git a/tests/compile-fail/bitop-beyond-alignment.rs b/tests/compile-fail/bitop-beyond-alignment.rs index 89f5e048a36d9..c8cbc9a918416 100644 --- a/tests/compile-fail/bitop-beyond-alignment.rs +++ b/tests/compile-fail/bitop-beyond-alignment.rs @@ -28,7 +28,7 @@ fn mk_rec() -> Rec { fn is_u64_aligned(u: &Tag) -> bool { let p: usize = unsafe { mem::transmute(u) }; let u64_align = std::mem::align_of::(); - return (p & (u64_align + 1)) == 0; //~ ERROR constant evaluation error [E0080] + return (p & (u64_align + 1)) == 0; //~ ERROR constant evaluation error //~^ NOTE a raw memory access tried to access part of a pointer value as raw bytes } diff --git a/tests/compile-fail/cast_box_int_to_fn_ptr.rs b/tests/compile-fail/cast_box_int_to_fn_ptr.rs index 39b53da0b75cd..2a317f579f5e0 100644 --- a/tests/compile-fail/cast_box_int_to_fn_ptr.rs +++ b/tests/compile-fail/cast_box_int_to_fn_ptr.rs @@ -7,6 +7,6 @@ fn main() { std::mem::transmute::<&usize, &fn(i32)>(&b) }; - (*g)(42) //~ ERROR constant evaluation error [E0080] + (*g)(42) //~ ERROR constant evaluation error //~^ NOTE a memory access tried to interpret some bytes as a pointer } diff --git a/tests/compile-fail/cast_fn_ptr.rs b/tests/compile-fail/cast_fn_ptr.rs index 19344b13ba7c9..0a8f5ef752a6d 100644 --- a/tests/compile-fail/cast_fn_ptr.rs +++ b/tests/compile-fail/cast_fn_ptr.rs @@ -5,6 +5,6 @@ fn main() { std::mem::transmute::(f) }; - g(42) //~ ERROR constant evaluation error [E0080] + g(42) //~ ERROR constant evaluation error //~^ NOTE tried to call a function with sig fn() through a function pointer of type fn(i32) } diff --git a/tests/compile-fail/cast_fn_ptr2.rs b/tests/compile-fail/cast_fn_ptr2.rs index 23868c0e57db4..cb80521c60eeb 100644 --- a/tests/compile-fail/cast_fn_ptr2.rs +++ b/tests/compile-fail/cast_fn_ptr2.rs @@ -5,6 +5,6 @@ fn main() { std::mem::transmute::(f) }; - g(42) //~ ERROR constant evaluation error [E0080] + g(42) //~ ERROR constant evaluation error //~^ NOTE tried to call a function with sig fn((i32, i32)) through a function pointer of type fn(i32) } diff --git a/tests/compile-fail/cast_int_to_fn_ptr.rs b/tests/compile-fail/cast_int_to_fn_ptr.rs index c7556ae06b93e..29d16e9a4259a 100644 --- a/tests/compile-fail/cast_int_to_fn_ptr.rs +++ b/tests/compile-fail/cast_int_to_fn_ptr.rs @@ -6,6 +6,6 @@ fn main() { std::mem::transmute::(42) }; - g(42) //~ ERROR constant evaluation error [E0080] + g(42) //~ ERROR constant evaluation error //~^ NOTE a memory access tried to interpret some bytes as a pointer } diff --git a/tests/compile-fail/ctlz_nonzero.rs b/tests/compile-fail/ctlz_nonzero.rs index d952187eba456..167100903f4db 100644 --- a/tests/compile-fail/ctlz_nonzero.rs +++ b/tests/compile-fail/ctlz_nonzero.rs @@ -10,7 +10,7 @@ pub fn main() { unsafe { use rusti::*; - ctlz_nonzero(0u8); //~ ERROR constant evaluation error [E0080] + ctlz_nonzero(0u8); //~ ERROR constant evaluation error //~^ NOTE ctlz_nonzero called on 0 } } diff --git a/tests/compile-fail/cttz_nonzero.rs b/tests/compile-fail/cttz_nonzero.rs index b308484622bc4..7d9ac5a0212d3 100644 --- a/tests/compile-fail/cttz_nonzero.rs +++ b/tests/compile-fail/cttz_nonzero.rs @@ -10,7 +10,7 @@ pub fn main() { unsafe { use rusti::*; - cttz_nonzero(0u8); //~ ERROR constant evaluation error [E0080] + cttz_nonzero(0u8); //~ ERROR constant evaluation error //~^ NOTE cttz_nonzero called on 0 } } diff --git a/tests/compile-fail/dangling_pointer_deref.rs b/tests/compile-fail/dangling_pointer_deref.rs index d42c1d33b530a..434f5c780b46f 100644 --- a/tests/compile-fail/dangling_pointer_deref.rs +++ b/tests/compile-fail/dangling_pointer_deref.rs @@ -3,7 +3,7 @@ fn main() { let b = Box::new(42); &*b as *const i32 }; - let x = unsafe { *p }; //~ ERROR constant evaluation error [E0080] + let x = unsafe { *p }; //~ ERROR constant evaluation error //~^ NOTE dangling pointer was dereferenced panic!("this should never print: {}", x); } diff --git a/tests/compile-fail/deref_fn_ptr.rs b/tests/compile-fail/deref_fn_ptr.rs index a56df5bce408e..fb3aea67e821f 100644 --- a/tests/compile-fail/deref_fn_ptr.rs +++ b/tests/compile-fail/deref_fn_ptr.rs @@ -2,7 +2,7 @@ fn f() {} fn main() { let x: i32 = unsafe { - *std::mem::transmute::(f) //~ ERROR constant evaluation error [E0080] + *std::mem::transmute::(f) //~ ERROR constant evaluation error //~^ NOTE tried to dereference a function pointer }; panic!("this should never print: {}", x); diff --git a/tests/compile-fail/div-by-zero-2.rs b/tests/compile-fail/div-by-zero-2.rs index c90ca8d15ccea..94145c2cf32f3 100644 --- a/tests/compile-fail/div-by-zero-2.rs +++ b/tests/compile-fail/div-by-zero-2.rs @@ -11,6 +11,6 @@ #![allow(const_err)] fn main() { - let _n = 1 / 0; //~ ERROR constant evaluation error [E0080] + let _n = 1 / 0; //~ ERROR constant evaluation error //~^ NOTE attempt to divide by zero } diff --git a/tests/compile-fail/execute_memory.rs b/tests/compile-fail/execute_memory.rs index 014c551df0f13..bcde13d13ee77 100644 --- a/tests/compile-fail/execute_memory.rs +++ b/tests/compile-fail/execute_memory.rs @@ -7,7 +7,7 @@ fn main() { let x = box 42; unsafe { let f = std::mem::transmute::, fn()>(x); - f() //~ ERROR constant evaluation error [E0080] + f() //~ ERROR constant evaluation error //~^ NOTE tried to treat a memory pointer as a function pointer } } diff --git a/tests/compile-fail/fn_ptr_offset.rs b/tests/compile-fail/fn_ptr_offset.rs index 20eb6573989c0..0c0590e375bbc 100644 --- a/tests/compile-fail/fn_ptr_offset.rs +++ b/tests/compile-fail/fn_ptr_offset.rs @@ -10,6 +10,6 @@ fn main() { let y : *mut u8 = unsafe { mem::transmute(x) }; let y = y.wrapping_offset(1); let x : fn() = unsafe { mem::transmute(y) }; - x(); //~ ERROR constant evaluation error [E0080] + x(); //~ ERROR constant evaluation error //~^ NOTE tried to use a function pointer after offsetting it } diff --git a/tests/compile-fail/invalid_bool.rs b/tests/compile-fail/invalid_bool.rs index 07c407966a8fd..1aa5d9bf77bcc 100644 --- a/tests/compile-fail/invalid_bool.rs +++ b/tests/compile-fail/invalid_bool.rs @@ -1,5 +1,5 @@ fn main() { let b = unsafe { std::mem::transmute::(2) }; - if b { unreachable!() } else { unreachable!() } //~ ERROR constant evaluation error [E0080] + if b { unreachable!() } else { unreachable!() } //~ ERROR constant evaluation error //~^ NOTE invalid boolean value read } diff --git a/tests/compile-fail/invalid_enum_discriminant.rs b/tests/compile-fail/invalid_enum_discriminant.rs index 69d7e3e427d4b..760b6563d27cc 100644 --- a/tests/compile-fail/invalid_enum_discriminant.rs +++ b/tests/compile-fail/invalid_enum_discriminant.rs @@ -14,5 +14,5 @@ fn main() { Foo::C => {}, Foo::D => {}, } -} //~ ERROR constant evaluation error [E0080] +} //~ ERROR constant evaluation error //~^ NOTE entered unreachable code diff --git a/tests/compile-fail/match_char.rs b/tests/compile-fail/match_char.rs index 0d45d70eb781a..52f33b58e6fb6 100644 --- a/tests/compile-fail/match_char.rs +++ b/tests/compile-fail/match_char.rs @@ -2,7 +2,7 @@ fn main() { assert!(std::char::from_u32(-1_i32 as u32).is_none()); - match unsafe { std::mem::transmute::(-1) } { //~ ERROR constant evaluation error [E0080] + match unsafe { std::mem::transmute::(-1) } { //~ ERROR constant evaluation error //~^ NOTE tried to interpret an invalid 32-bit value as a char: 4294967295 'a' => {}, 'b' => {}, diff --git a/tests/compile-fail/modifying_constants.rs b/tests/compile-fail/modifying_constants.rs index 06920fa0acf16..c10657ae75a77 100644 --- a/tests/compile-fail/modifying_constants.rs +++ b/tests/compile-fail/modifying_constants.rs @@ -1,7 +1,7 @@ fn main() { let x = &1; // the `&1` is promoted to a constant, but it used to be that only the pointer is marked static, not the pointee let y = unsafe { &mut *(x as *const i32 as *mut i32) }; - *y = 42; //~ ERROR constant evaluation error [E0080] + *y = 42; //~ ERROR constant evaluation error //~^ NOTE tried to modify constant memory assert_eq!(*x, 42); } diff --git a/tests/compile-fail/never_say_never.rs b/tests/compile-fail/never_say_never.rs index de8815ffd9c4e..fd76ecbd1503e 100644 --- a/tests/compile-fail/never_say_never.rs +++ b/tests/compile-fail/never_say_never.rs @@ -7,7 +7,7 @@ fn main() { let y = &5; let x: ! = unsafe { - *(y as *const _ as *const !) //~ ERROR constant evaluation error [E0080] + *(y as *const _ as *const !) //~ ERROR constant evaluation error //~^ NOTE entered unreachable code }; f(x) diff --git a/tests/compile-fail/never_transmute_humans.rs b/tests/compile-fail/never_transmute_humans.rs index 3422d52f9c044..7652cdfdd3df5 100644 --- a/tests/compile-fail/never_transmute_humans.rs +++ b/tests/compile-fail/never_transmute_humans.rs @@ -9,7 +9,7 @@ struct Human; fn main() { let x: ! = unsafe { - std::mem::transmute::(Human) //~ ERROR constant evaluation error [E0080] + std::mem::transmute::(Human) //~ ERROR constant evaluation error //^~ NOTE entered unreachable code }; f(x) diff --git a/tests/compile-fail/never_transmute_void.rs b/tests/compile-fail/never_transmute_void.rs index 4f1499483eda2..9329cd365994e 100644 --- a/tests/compile-fail/never_transmute_void.rs +++ b/tests/compile-fail/never_transmute_void.rs @@ -8,7 +8,7 @@ enum Void {} fn f(v: Void) -> ! { - match v {} //~ ERROR constant evaluation error [E0080] + match v {} //~ ERROR constant evaluation error //~^ NOTE entered unreachable code } diff --git a/tests/compile-fail/null_pointer_deref.rs b/tests/compile-fail/null_pointer_deref.rs index 70df937c4c7c5..f69308296bc24 100644 --- a/tests/compile-fail/null_pointer_deref.rs +++ b/tests/compile-fail/null_pointer_deref.rs @@ -1,5 +1,5 @@ fn main() { - let x: i32 = unsafe { *std::ptr::null() }; //~ ERROR constant evaluation error [E0080] + let x: i32 = unsafe { *std::ptr::null() }; //~ ERROR constant evaluation error //~^ NOTE invalid use of NULL pointer panic!("this should never print: {}", x); } diff --git a/tests/compile-fail/out_of_bounds_read.rs b/tests/compile-fail/out_of_bounds_read.rs index d8811e7abcd25..3ccdb365feebc 100644 --- a/tests/compile-fail/out_of_bounds_read.rs +++ b/tests/compile-fail/out_of_bounds_read.rs @@ -1,6 +1,6 @@ fn main() { let v: Vec = vec![1, 2]; - let x = unsafe { *v.as_ptr().wrapping_offset(5) }; //~ ERROR constant evaluation error [E0080] + let x = unsafe { *v.as_ptr().wrapping_offset(5) }; //~ ERROR constant evaluation error //~^ NOTE which has size 2 panic!("this should never print: {}", x); } diff --git a/tests/compile-fail/out_of_bounds_read2.rs b/tests/compile-fail/out_of_bounds_read2.rs index 54738cf81fbd8..811ba7d4b26cf 100644 --- a/tests/compile-fail/out_of_bounds_read2.rs +++ b/tests/compile-fail/out_of_bounds_read2.rs @@ -1,6 +1,6 @@ fn main() { let v: Vec = vec![1, 2]; - let x = unsafe { *v.as_ptr().wrapping_offset(5) }; //~ ERROR constant evaluation error [E0080] + let x = unsafe { *v.as_ptr().wrapping_offset(5) }; //~ ERROR constant evaluation error //~^ NOTE memory access at offset 6, outside bounds of allocation panic!("this should never print: {}", x); } diff --git a/tests/compile-fail/overflowing-lsh-neg.rs b/tests/compile-fail/overflowing-lsh-neg.rs index e50e425036499..825a822266349 100644 --- a/tests/compile-fail/overflowing-lsh-neg.rs +++ b/tests/compile-fail/overflowing-lsh-neg.rs @@ -12,6 +12,6 @@ #![allow(const_err)] fn main() { - let _n = 2i64 << -1; //~ ERROR constant evaluation error [E0080] + let _n = 2i64 << -1; //~ ERROR constant evaluation error //~^ NOTE attempt to shift left with overflow } diff --git a/tests/compile-fail/overflowing-rsh-2.rs b/tests/compile-fail/overflowing-rsh-2.rs index 967c8b020cca0..cf107a76ae29d 100644 --- a/tests/compile-fail/overflowing-rsh-2.rs +++ b/tests/compile-fail/overflowing-rsh-2.rs @@ -12,6 +12,6 @@ fn main() { // Make sure we catch overflows that would be hidden by first casting the RHS to u32 - let _n = 1i64 >> (u32::max_value() as i64 + 1); //~ ERROR constant evaluation error [E0080] + let _n = 1i64 >> (u32::max_value() as i64 + 1); //~ ERROR constant evaluation error //~^ NOTE attempt to shift right with overflow } diff --git a/tests/compile-fail/overflowing-rsh.rs b/tests/compile-fail/overflowing-rsh.rs index c291815e2e79a..ea53d7e730925 100644 --- a/tests/compile-fail/overflowing-rsh.rs +++ b/tests/compile-fail/overflowing-rsh.rs @@ -11,6 +11,6 @@ #![allow(exceeding_bitshifts)] fn main() { - let _n = 1i64 >> 64; //~ ERROR constant evaluation error [E0080] + let _n = 1i64 >> 64; //~ ERROR constant evaluation error //~^ NOTE attempt to shift right with overflow } diff --git a/tests/compile-fail/overwriting_part_of_relocation_makes_the_rest_undefined.rs b/tests/compile-fail/overwriting_part_of_relocation_makes_the_rest_undefined.rs index fabbef5004d77..7c38c05746983 100644 --- a/tests/compile-fail/overwriting_part_of_relocation_makes_the_rest_undefined.rs +++ b/tests/compile-fail/overwriting_part_of_relocation_makes_the_rest_undefined.rs @@ -6,7 +6,7 @@ fn main() { // "attempted to interpret some raw bytes as a pointer address" instead of // "attempted to read undefined bytes" } - let x = *p; //~ ERROR constant evaluation error [E0080] + let x = *p; //~ ERROR constant evaluation error //~^ NOTE attempted to read undefined bytes panic!("this should never print: {}", x); } diff --git a/tests/compile-fail/pointer_byte_read_1.rs b/tests/compile-fail/pointer_byte_read_1.rs index 012af897e8370..b3aaec759ce02 100644 --- a/tests/compile-fail/pointer_byte_read_1.rs +++ b/tests/compile-fail/pointer_byte_read_1.rs @@ -3,6 +3,6 @@ fn main() { let y = &x; let z = &y as *const &i32 as *const usize; let ptr_bytes = unsafe { *z }; // the actual deref is fine, because we read the entire pointer at once - let _ = ptr_bytes % 432; //~ ERROR constant evaluation error [E0080] + let _ = ptr_bytes % 432; //~ ERROR constant evaluation error //~^ NOTE tried to access part of a pointer value as raw bytes } diff --git a/tests/compile-fail/pointer_byte_read_2.rs b/tests/compile-fail/pointer_byte_read_2.rs index 4d25a36a3c883..c8a1a2e10f500 100644 --- a/tests/compile-fail/pointer_byte_read_2.rs +++ b/tests/compile-fail/pointer_byte_read_2.rs @@ -3,6 +3,6 @@ fn main() { let y = &x; let z = &y as *const &i32 as *const u8; // the deref fails, because we are reading only a part of the pointer - let _ = unsafe { *z }; //~ ERROR constant evaluation error [E0080] + let _ = unsafe { *z }; //~ ERROR constant evaluation error //~^ NOTE tried to access part of a pointer value as raw bytes } diff --git a/tests/compile-fail/pointers_to_different_allocations_are_unorderable.rs b/tests/compile-fail/pointers_to_different_allocations_are_unorderable.rs index 72ae1b123e8a2..89cf357e201cf 100644 --- a/tests/compile-fail/pointers_to_different_allocations_are_unorderable.rs +++ b/tests/compile-fail/pointers_to_different_allocations_are_unorderable.rs @@ -1,7 +1,7 @@ fn main() { let x: *const u8 = &1; let y: *const u8 = &2; - if x < y { //~ ERROR constant evaluation error [E0080] + if x < y { //~ ERROR constant evaluation error //~^ NOTE attempted to do invalid arithmetic on pointers unreachable!() } diff --git a/tests/compile-fail/ptr_bitops.rs b/tests/compile-fail/ptr_bitops.rs index 52bcf24cf6b8f..ecd47a186efb1 100644 --- a/tests/compile-fail/ptr_bitops.rs +++ b/tests/compile-fail/ptr_bitops.rs @@ -2,7 +2,7 @@ fn main() { let bytes = [0i8, 1, 2, 3, 4, 5, 6, 7, 8, 9]; let one = bytes.as_ptr().wrapping_offset(1); let three = bytes.as_ptr().wrapping_offset(3); - let res = (one as usize) | (three as usize); //~ ERROR constant evaluation error [E0080] + let res = (one as usize) | (three as usize); //~ ERROR constant evaluation error //~^ NOTE a raw memory access tried to access part of a pointer value as raw bytes println!("{}", res); } diff --git a/tests/compile-fail/ptr_int_cast.rs b/tests/compile-fail/ptr_int_cast.rs index 56403d619ffad..11243921bfd48 100644 --- a/tests/compile-fail/ptr_int_cast.rs +++ b/tests/compile-fail/ptr_int_cast.rs @@ -2,7 +2,7 @@ fn main() { let x = &1; // Casting down to u8 and back up to a pointer loses too much precision; this must not work. let x = x as *const i32; - let x = x as u8; //~ ERROR constant evaluation error [E0080] + let x = x as u8; //~ ERROR constant evaluation error //~^ NOTE a raw memory access tried to access part of a pointer value as raw bytes let x = x as *const i32; let _ = unsafe { *x }; diff --git a/tests/compile-fail/reading_half_a_pointer.rs b/tests/compile-fail/reading_half_a_pointer.rs index e44f26c4c4cfb..3ea693a3f0fbb 100644 --- a/tests/compile-fail/reading_half_a_pointer.rs +++ b/tests/compile-fail/reading_half_a_pointer.rs @@ -24,7 +24,7 @@ fn main() { // starts 1 byte to the right, so using it would actually be wrong! let d_alias = &mut w.data as *mut _ as *mut *const u8; unsafe { - let _x = *d_alias; //~ ERROR constant evaluation error [E0080] + let _x = *d_alias; //~ ERROR constant evaluation error //~^ NOTE tried to access part of a pointer value as raw bytes } } diff --git a/tests/compile-fail/reference_to_packed.rs b/tests/compile-fail/reference_to_packed.rs index 16b452ca0e3c9..946a6b89a777a 100644 --- a/tests/compile-fail/reference_to_packed.rs +++ b/tests/compile-fail/reference_to_packed.rs @@ -15,6 +15,6 @@ fn main() { y: 99, }; let p = unsafe { &foo.x }; - let i = *p; //~ ERROR constant evaluation error [E0080] + let i = *p; //~ ERROR constant evaluation error //~^ NOTE tried to access memory with alignment 1, but alignment 4 is required } diff --git a/tests/compile-fail/static_memory_modification.rs b/tests/compile-fail/static_memory_modification.rs index a85ff545ee423..e28bcb37fb72d 100644 --- a/tests/compile-fail/static_memory_modification.rs +++ b/tests/compile-fail/static_memory_modification.rs @@ -4,7 +4,7 @@ static X: usize = 5; #[allow(mutable_transmutes)] fn main() { unsafe { - *std::mem::transmute::<&usize, &mut usize>(&X) = 6; //~ ERROR constant evaluation error [E0080] + *std::mem::transmute::<&usize, &mut usize>(&X) = 6; //~ ERROR constant evaluation error //~^ NOTE tried to modify constant memory assert_eq!(X, 6); } diff --git a/tests/compile-fail/static_memory_modification2.rs b/tests/compile-fail/static_memory_modification2.rs index 6abe6de1fcf41..2f702f09c8047 100644 --- a/tests/compile-fail/static_memory_modification2.rs +++ b/tests/compile-fail/static_memory_modification2.rs @@ -7,7 +7,7 @@ use std::mem::transmute; fn main() { unsafe { let s = "this is a test"; - transmute::<&[u8], &mut [u8]>(s.as_bytes())[4] = 42; //~ ERROR constant evaluation error [E0080] + transmute::<&[u8], &mut [u8]>(s.as_bytes())[4] = 42; //~ ERROR constant evaluation error //~^ NOTE tried to modify constant memory } } diff --git a/tests/compile-fail/static_memory_modification3.rs b/tests/compile-fail/static_memory_modification3.rs index 0891756f0ec61..37d8bfe02ceb2 100644 --- a/tests/compile-fail/static_memory_modification3.rs +++ b/tests/compile-fail/static_memory_modification3.rs @@ -4,7 +4,7 @@ use std::mem::transmute; fn main() { unsafe { let bs = b"this is a test"; - transmute::<&[u8], &mut [u8]>(bs)[4] = 42; //~ ERROR constant evaluation error [E0080] + transmute::<&[u8], &mut [u8]>(bs)[4] = 42; //~ ERROR constant evaluation error //~^ NOTE tried to modify constant memory } } diff --git a/tests/compile-fail/transmute-pair-undef.rs b/tests/compile-fail/transmute-pair-undef.rs index 6b4fe2273a080..9509bb60e8b11 100644 --- a/tests/compile-fail/transmute-pair-undef.rs +++ b/tests/compile-fail/transmute-pair-undef.rs @@ -16,6 +16,6 @@ fn main() { assert_eq!(byte, 0); } let v = unsafe { *z.offset(first_undef) }; - if v == 0 {} //~ ERROR constant evaluation error [E0080] + if v == 0 {} //~ ERROR constant evaluation error //~^ NOTE attempted to read undefined bytes } diff --git a/tests/compile-fail/transmute_fat.rs b/tests/compile-fail/transmute_fat.rs index 81d783807c586..dad5f4df2da3c 100644 --- a/tests/compile-fail/transmute_fat.rs +++ b/tests/compile-fail/transmute_fat.rs @@ -10,6 +10,6 @@ fn main() { let bad = unsafe { std::mem::transmute::<&[u8], u64>(&[1u8]) }; - let _ = bad + 1; //~ ERROR constant evaluation error [E0080] + let _ = bad + 1; //~ ERROR constant evaluation error //~^ NOTE a raw memory access tried to access part of a pointer value as raw bytes } diff --git a/tests/compile-fail/transmute_fat2.rs b/tests/compile-fail/transmute_fat2.rs index 96a713305e6bd..e9e21a84294dc 100644 --- a/tests/compile-fail/transmute_fat2.rs +++ b/tests/compile-fail/transmute_fat2.rs @@ -7,6 +7,6 @@ fn main() { let bad = unsafe { std::mem::transmute::(42) }; - bad[0]; //~ ERROR constant evaluation error [E0080] + bad[0]; //~ ERROR constant evaluation error //~^ NOTE index out of bounds: the len is 0 but the index is 0 } diff --git a/tests/compile-fail/unaligned_ptr_cast.rs b/tests/compile-fail/unaligned_ptr_cast.rs index cb9523395391f..f91def30d1205 100644 --- a/tests/compile-fail/unaligned_ptr_cast.rs +++ b/tests/compile-fail/unaligned_ptr_cast.rs @@ -2,6 +2,6 @@ fn main() { let x = &2u16; let x = x as *const _ as *const u32; // This must fail because alignment is violated - let _x = unsafe { *x }; //~ ERROR constant evaluation error [E0080] + let _x = unsafe { *x }; //~ ERROR constant evaluation error //~^ NOTE tried to access memory with alignment 2, but alignment 4 is required } diff --git a/tests/compile-fail/unaligned_ptr_cast2.rs b/tests/compile-fail/unaligned_ptr_cast2.rs index dee2bbc9972f7..f87dab76ba300 100644 --- a/tests/compile-fail/unaligned_ptr_cast2.rs +++ b/tests/compile-fail/unaligned_ptr_cast2.rs @@ -3,6 +3,6 @@ fn main() { let x = x as *const _ as *const *const u8; // This must fail because alignment is violated. Test specifically for loading pointers, which have special code // in miri's memory. - let _x = unsafe { *x }; //~ ERROR constant evaluation error [E0080] + let _x = unsafe { *x }; //~ ERROR constant evaluation error //~^ NOTE tried to access memory with alignment 2, but alignment } diff --git a/tests/compile-fail/unaligned_ptr_cast_zst.rs b/tests/compile-fail/unaligned_ptr_cast_zst.rs index eba17ab6c6406..45016473c9752 100644 --- a/tests/compile-fail/unaligned_ptr_cast_zst.rs +++ b/tests/compile-fail/unaligned_ptr_cast_zst.rs @@ -2,6 +2,6 @@ fn main() { let x = &2u16; let x = x as *const _ as *const [u32; 0]; // This must fail because alignment is violated. Test specifically for loading ZST. - let _x = unsafe { *x }; //~ ERROR constant evaluation error [E0080] + let _x = unsafe { *x }; //~ ERROR constant evaluation error //~^ NOTE tried to access memory with alignment 2, but alignment 4 is required } diff --git a/tests/compile-fail/wild_pointer_deref.rs b/tests/compile-fail/wild_pointer_deref.rs index 035d979c5b07e..4096cfb93e722 100644 --- a/tests/compile-fail/wild_pointer_deref.rs +++ b/tests/compile-fail/wild_pointer_deref.rs @@ -1,6 +1,6 @@ fn main() { let p = 44 as *const i32; - let x = unsafe { *p }; //~ ERROR constant evaluation error [E0080] + let x = unsafe { *p }; //~ ERROR constant evaluation error //~^ NOTE a memory access tried to interpret some bytes as a pointer panic!("this should never print: {}", x); } diff --git a/tests/compile-fail/zst.rs b/tests/compile-fail/zst.rs index d6518a48aa828..efb2dafd36fc5 100644 --- a/tests/compile-fail/zst.rs +++ b/tests/compile-fail/zst.rs @@ -1,5 +1,5 @@ fn main() { let x = &() as *const () as *const i32; - let _ = unsafe { *x }; //~ ERROR constant evaluation error [E0080] + let _ = unsafe { *x }; //~ ERROR constant evaluation error //~^ NOTE tried to access memory with alignment 1, but alignment 4 is required } From 0b8809bf5f1616082da31c63b0119fd45869ddbe Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 15 Jul 2018 12:00:02 +0200 Subject: [PATCH 0132/3747] port some tests to check the new error format --- tests/compile-fail/ctlz_nonzero.rs | 3 +-- tests/compile-fail/cttz_nonzero.rs | 3 +-- tests/compile-fail/deref_fn_ptr.rs | 3 +-- tests/compile-fail/null_pointer_deref.rs | 3 +-- 4 files changed, 4 insertions(+), 8 deletions(-) diff --git a/tests/compile-fail/ctlz_nonzero.rs b/tests/compile-fail/ctlz_nonzero.rs index 167100903f4db..4e2ccd0ac508a 100644 --- a/tests/compile-fail/ctlz_nonzero.rs +++ b/tests/compile-fail/ctlz_nonzero.rs @@ -10,7 +10,6 @@ pub fn main() { unsafe { use rusti::*; - ctlz_nonzero(0u8); //~ ERROR constant evaluation error - //~^ NOTE ctlz_nonzero called on 0 + ctlz_nonzero(0u8); //~ ERROR constant evaluation error: ctlz_nonzero called on 0 } } diff --git a/tests/compile-fail/cttz_nonzero.rs b/tests/compile-fail/cttz_nonzero.rs index 7d9ac5a0212d3..50b8df6199827 100644 --- a/tests/compile-fail/cttz_nonzero.rs +++ b/tests/compile-fail/cttz_nonzero.rs @@ -10,7 +10,6 @@ pub fn main() { unsafe { use rusti::*; - cttz_nonzero(0u8); //~ ERROR constant evaluation error - //~^ NOTE cttz_nonzero called on 0 + cttz_nonzero(0u8); //~ ERROR constant evaluation error: cttz_nonzero called on 0 } } diff --git a/tests/compile-fail/deref_fn_ptr.rs b/tests/compile-fail/deref_fn_ptr.rs index fb3aea67e821f..1b36c77bd32ab 100644 --- a/tests/compile-fail/deref_fn_ptr.rs +++ b/tests/compile-fail/deref_fn_ptr.rs @@ -2,8 +2,7 @@ fn f() {} fn main() { let x: i32 = unsafe { - *std::mem::transmute::(f) //~ ERROR constant evaluation error - //~^ NOTE tried to dereference a function pointer + *std::mem::transmute::(f) //~ ERROR constant evaluation error: tried to dereference a function pointer }; panic!("this should never print: {}", x); } diff --git a/tests/compile-fail/null_pointer_deref.rs b/tests/compile-fail/null_pointer_deref.rs index f69308296bc24..08ea63f58ff59 100644 --- a/tests/compile-fail/null_pointer_deref.rs +++ b/tests/compile-fail/null_pointer_deref.rs @@ -1,5 +1,4 @@ fn main() { - let x: i32 = unsafe { *std::ptr::null() }; //~ ERROR constant evaluation error - //~^ NOTE invalid use of NULL pointer + let x: i32 = unsafe { *std::ptr::null() }; //~ ERROR constant evaluation error: invalid use of NULL pointer panic!("this should never print: {}", x); } From 60d18dbf87cbb1baceccb69a87b109de93ff1ff0 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 15 Jul 2018 21:03:52 +0200 Subject: [PATCH 0133/3747] handle all foreign items like we handle C ABI shims --- src/fn_call.rs | 167 ++++++++++++++++++++++++------------------------- 1 file changed, 83 insertions(+), 84 deletions(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index d2149ee5dbe7d..8105330b3263e 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -3,7 +3,6 @@ use rustc::ty::layout::{self, Align, LayoutOf, Size}; use rustc::hir::def_id::{DefId, CRATE_DEF_INDEX}; use rustc::mir; use rustc_data_structures::indexed_vec::Idx; -use rustc_target::spec::abi::Abi; use syntax::attr; use syntax::codemap::Span; @@ -60,7 +59,7 @@ fn write_discriminant_value<'a, 'mir, 'tcx: 'a + 'mir>( } pub trait EvalContextExt<'tcx> { - fn call_c_abi( + fn call_foreign_item( &mut self, def_id: DefId, args: &[ValTy<'tcx>], @@ -105,9 +104,6 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' let def_id = instance.def_id(); let item_path = self.tcx.absolute_item_path_str(def_id); - if item_path.starts_with("std::") { - //println!("{}", item_path); - } match &*item_path { "std::sys::unix::thread::guard::init" | "std::sys::unix::thread::guard::current" => { // Return None, as it doesn't make sense to return Some, because miri detects stack overflow itself. @@ -178,7 +174,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' Ok(false) } - fn call_c_abi( + fn call_foreign_item( &mut self, def_id: DefId, args: &[ValTy<'tcx>], @@ -215,6 +211,73 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' } } + "__rust_alloc" => { + let size = self.value_to_scalar(args[0])?.to_usize(self)?; + let align = self.value_to_scalar(args[1])?.to_usize(self)?; + if size == 0 { + return err!(HeapAllocZeroBytes); + } + if !align.is_power_of_two() { + return err!(HeapAllocNonPowerOfTwoAlignment(align)); + } + let ptr = self.memory.allocate(Size::from_bytes(size), + Align::from_bytes(align, align).unwrap(), + MemoryKind::Rust.into())?; + self.write_scalar(dest, Scalar::Ptr(ptr), dest_ty)?; + } + "__rust_alloc_zeroed" => { + let size = self.value_to_scalar(args[0])?.to_usize(self)?; + let align = self.value_to_scalar(args[1])?.to_usize(self)?; + if size == 0 { + return err!(HeapAllocZeroBytes); + } + if !align.is_power_of_two() { + return err!(HeapAllocNonPowerOfTwoAlignment(align)); + } + let ptr = self.memory.allocate(Size::from_bytes(size), + Align::from_bytes(align, align).unwrap(), + MemoryKind::Rust.into())?; + self.memory.write_repeat(ptr.into(), 0, Size::from_bytes(size))?; + self.write_scalar(dest, Scalar::Ptr(ptr), dest_ty)?; + } + "__rust_dealloc" => { + let ptr = self.into_ptr(args[0].value)?.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 { + return err!(HeapAllocZeroBytes); + } + if !align.is_power_of_two() { + return err!(HeapAllocNonPowerOfTwoAlignment(align)); + } + self.memory.deallocate( + ptr, + Some((Size::from_bytes(old_size), Align::from_bytes(align, align).unwrap())), + MemoryKind::Rust.into(), + )?; + } + "__rust_realloc" => { + let ptr = self.into_ptr(args[0].value)?.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)?; + if old_size == 0 || new_size == 0 { + return err!(HeapAllocZeroBytes); + } + if !align.is_power_of_two() { + return err!(HeapAllocNonPowerOfTwoAlignment(align)); + } + let new_ptr = self.memory.reallocate( + ptr, + Size::from_bytes(old_size), + Align::from_bytes(align, align).unwrap(), + Size::from_bytes(new_size), + Align::from_bytes(align, align).unwrap(), + MemoryKind::Rust.into(), + )?; + self.write_scalar(dest, Scalar::Ptr(new_ptr), dest_ty)?; + } + "syscall" => { // TODO: read `syscall` ids like `sysconf` ids and // figure out some way to actually process some of them @@ -559,9 +622,18 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' self.write_ptr(dest, addr, dest_ty)?; } + // Windows API subs + "AddVectoredExceptionHandler" | + "SetThreadStackGuarantee" => { + let usize = self.tcx.types.usize; + // any non zero value works for the stdlib. This is just used for stackoverflows anyway + self.write_scalar(dest, Scalar::from_u128(1), usize)?; + }, + + // We can't execute anything else _ => { return err!(Unimplemented( - format!("can't call C ABI function: {}", link_name), + format!("can't call foreign function: {}", link_name), )); } } @@ -629,11 +701,11 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' || EvalErrorKind::NoMirFor(path.clone()), )?; - if sig.abi == Abi::C { - // An external C function + if self.tcx.is_foreign_item(instance.def_id()) { + // An external function // TODO: That functions actually has a similar preamble to what follows here. May make sense to // unify these two mechanisms for "hooking into missing functions". - self.call_c_abi( + self.call_foreign_item( instance.def_id(), args, dest, @@ -644,74 +716,6 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' } match &path[..] { - // Allocators are magic. They have no MIR, even when the rest of libstd does. - "alloc::alloc::::__rust_alloc" => { - let size = self.value_to_scalar(args[0])?.to_usize(self)?; - let align = self.value_to_scalar(args[1])?.to_usize(self)?; - if size == 0 { - return err!(HeapAllocZeroBytes); - } - if !align.is_power_of_two() { - return err!(HeapAllocNonPowerOfTwoAlignment(align)); - } - let ptr = self.memory.allocate(Size::from_bytes(size), - Align::from_bytes(align, align).unwrap(), - MemoryKind::Rust.into())?; - self.write_scalar(dest, Scalar::Ptr(ptr), dest_ty)?; - } - "alloc::alloc::::__rust_alloc_zeroed" => { - let size = self.value_to_scalar(args[0])?.to_usize(self)?; - let align = self.value_to_scalar(args[1])?.to_usize(self)?; - if size == 0 { - return err!(HeapAllocZeroBytes); - } - if !align.is_power_of_two() { - return err!(HeapAllocNonPowerOfTwoAlignment(align)); - } - let ptr = self.memory.allocate(Size::from_bytes(size), - Align::from_bytes(align, align).unwrap(), - MemoryKind::Rust.into())?; - self.memory.write_repeat(ptr.into(), 0, Size::from_bytes(size))?; - self.write_scalar(dest, Scalar::Ptr(ptr), dest_ty)?; - } - "alloc::alloc::::__rust_dealloc" => { - let ptr = self.into_ptr(args[0].value)?.to_ptr()?; - let old_size = self.value_to_scalar(args[1])?.to_usize(self)?; - let align = self.value_to_scalar(args[2])?.to_usize(self)?; - if old_size == 0 { - return err!(HeapAllocZeroBytes); - } - if !align.is_power_of_two() { - return err!(HeapAllocNonPowerOfTwoAlignment(align)); - } - self.memory.deallocate( - ptr, - Some((Size::from_bytes(old_size), Align::from_bytes(align, align).unwrap())), - MemoryKind::Rust.into(), - )?; - } - "alloc::alloc::::__rust_realloc" => { - let ptr = self.into_ptr(args[0].value)?.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)?; - if old_size == 0 || new_size == 0 { - return err!(HeapAllocZeroBytes); - } - if !align.is_power_of_two() { - return err!(HeapAllocNonPowerOfTwoAlignment(align)); - } - let new_ptr = self.memory.reallocate( - ptr, - Size::from_bytes(old_size), - Align::from_bytes(align, align).unwrap(), - Size::from_bytes(new_size), - Align::from_bytes(align, align).unwrap(), - MemoryKind::Rust.into(), - )?; - self.write_scalar(dest, Scalar::Ptr(new_ptr), dest_ty)?; - } - // A Rust function is missing, which means we are running with MIR missing for libstd (or other dependencies). // Still, we can make many things mostly work by "emulating" or ignoring some functions. "std::io::_print" => { @@ -733,12 +737,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' let bool = self.tcx.types.bool; self.write_scalar(dest, Scalar::from_bool(false), bool)?; } - "std::sys::imp::c::::AddVectoredExceptionHandler" | - "std::sys::imp::c::::SetThreadStackGuarantee" => { - let usize = self.tcx.types.usize; - // any non zero value works for the stdlib. This is just used for stackoverflows anyway - self.write_scalar(dest, Scalar::from_u128(1), usize)?; - }, + _ => return err!(NoMirFor(path)), } From 5be8bd987de6cf72d858b21bdc62fe4125b2890d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 15 Jul 2018 21:25:03 +0200 Subject: [PATCH 0134/3747] Test some new capabilities we gained from a rustc update --- src/operator.rs | 4 ++++ tests/run-pass/pointers.rs | 1 + 2 files changed, 5 insertions(+) diff --git a/src/operator.rs b/src/operator.rs index 1440f1dab4e0f..207324cfcb00c 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -34,6 +34,8 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: right: Scalar, right_ty: ty::Ty<'tcx>, ) -> EvalResult<'tcx, Option<(Scalar, bool)>> { + trace!("ptr_op: {:?} {:?} {:?}", left, bin_op, right); + use rustc::mir::BinOp::*; use rustc::ty::layout::Integer::*; let usize = Primitive::Int(match self.memory.pointer_size().bytes() { @@ -81,7 +83,9 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: (Scalar::Bits { .. }, Scalar::Bits { .. }) => { left.to_bits(left_layout.size)? == right.to_bits(right_layout.size)? }, + // FIXME: Test if both allocations are still live *or* if they are in the same allocation? (same for Ne below) (Scalar::Ptr(left), Scalar::Ptr(right)) => left == right, + // FIXME: We should probably error out when comparing anything but NULL with a pointer (same for Ne below) _ => false, }; Ok(Some((Scalar::from_bool(result), false))) diff --git a/tests/run-pass/pointers.rs b/tests/run-pass/pointers.rs index f3ae3ab913a36..936ec73bcb8c0 100644 --- a/tests/run-pass/pointers.rs +++ b/tests/run-pass/pointers.rs @@ -57,4 +57,5 @@ fn main() { assert_eq!(match_ref_mut(), 42); // FIXME: improve this test... how? assert!(dangling_pointer() != std::ptr::null()); + assert!(match dangling_pointer() as usize { 0 => false, _ => true }); } From a39f25c8132950212d46c5989f906e98c5604a59 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 15 Jul 2018 23:17:06 +0200 Subject: [PATCH 0135/3747] update rustc build instructions to mention keep-stage Also move them further down because it is probably less relevant than some of the other stuff. --- README.md | 54 +++++++++++++++++++++++++++++++++--------------------- 1 file changed, 33 insertions(+), 21 deletions(-) diff --git a/README.md b/README.md index 4891575c05e52..d515aad8bea51 100644 --- a/README.md +++ b/README.md @@ -40,25 +40,6 @@ how to fix it, you could send a PR. :smile: cargo run --bin miri tests/run-pass-fullmir/vecs.rs # Or whatever test you like. ``` -## Debugging - -Since the heart of miri (the main interpreter engine) lives in rustc, tracing -the interpreter requires a version of rustc compiled with tracing. To this -end, you will have to compile your own rustc: -``` -git clone https://github.com/rust-lang/rust/ rustc -cd rustc -cp config.toml.example config.toml -# Now edit `config.toml` and set `debug-assertions = true` -./x.py build src/rustc -rustup toolchain link custom build/x86_64-unknown-linux-gnu/stage2 -``` -The `build` step can take 30 to 60 minutes. - -Now, in the miri directory, you can `rustup override set custom` and re-build -everything. Finally, if you now set `RUST_LOG=rustc_mir::interpret=trace` as -environment variable, you will get detailed step-by-step tracing information. - ## Running miri on your own project('s test suite) Install miri as a cargo subcommand with `cargo install --debug`. @@ -68,8 +49,8 @@ through miri. ## Running miri with full libstd -Per default libstd does not contain the MIR of non-polymorphic functions. When -miri hits a call to such a function, execution terminates. To fix this, it is +Per default libstd does not contain the MIR of non-polymorphic functions. When +miri hits a call to such a function, execution terminates. To fix this, it is possible to compile libstd with full MIR: ```sh @@ -91,6 +72,37 @@ your toolchain changes (e.g., when you update the nightly). You can also set `-Zmiri-start-fn` to make miri start evaluation with the `start_fn` lang item, instead of starting at the `main` function. +## Development and Debugging + +Since the heart of miri (the main interpreter engine) lives in rustc, working on +miri will often require using a locally built rustc. This includes getting a +trace of the execution, as distributed rustc has `trace!` disabled. + +The first-time setup for a local rustc looks as follows: +``` +git clone https://github.com/rust-lang/rust/ rustc +cd rustc +cp config.toml.example config.toml +# Now edit `config.toml` and set `debug-assertions = true` +./x.py build src/rustc +# You may have to change the architecture in the next command +rustup toolchain link custom build/x86_64-unknown-linux-gnu/stage2 +# Now cd to your miri directory +rustup override set custom +``` +The `build` step can take 30 minutes and more. + +Now you can `cargo build` miri, and you can `cargo test --tests`. (`--tests` +is needed to skip doctests because we have not built rustdoc for your custom +toolchain.) You can also set `RUST_LOG=rustc_mir::interpret=trace` as +environment variable to get a step-by-step trace. + +If you changed something in rustc and want to re-build, run +``` +./x.py build src/rustc --keep-stage 0 +``` +This avoids rebuilding the entire stage 0, which can save a lot of time. + ## Contributing and getting help Check out the issues on this GitHub repository for some ideas. There's lots that From d11c668a3900fcbad336eb470da8748a04000253 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 16 Jul 2018 08:39:06 +0200 Subject: [PATCH 0136/3747] no longer run rustc on the tests; instead make sure we actually deny all warnings Also fix the fallout from that --- .../reallocate-bad-size.rs | 2 +- .../reallocate-change-alloc.rs | 2 +- tests/compiletest.rs | 28 ++----------------- tests/run-pass/box_box_trait.rs | 2 ++ 4 files changed, 6 insertions(+), 28 deletions(-) diff --git a/tests/compile-fail-fullmir/reallocate-bad-size.rs b/tests/compile-fail-fullmir/reallocate-bad-size.rs index f85b651e85730..489b7bebcdc8f 100644 --- a/tests/compile-fail-fullmir/reallocate-bad-size.rs +++ b/tests/compile-fail-fullmir/reallocate-bad-size.rs @@ -10,6 +10,6 @@ use std::alloc::*; fn main() { unsafe { let x = Global.alloc(Layout::from_size_align_unchecked(1, 1)).unwrap(); - let _y = Global.realloc(x, Layout::from_size_align_unchecked(2, 1), 1).unwrap(); + Global.realloc(x, Layout::from_size_align_unchecked(2, 1), 1).unwrap(); } } diff --git a/tests/compile-fail-fullmir/reallocate-change-alloc.rs b/tests/compile-fail-fullmir/reallocate-change-alloc.rs index a44ccf4c49cd8..c73f86bc1721c 100644 --- a/tests/compile-fail-fullmir/reallocate-change-alloc.rs +++ b/tests/compile-fail-fullmir/reallocate-change-alloc.rs @@ -8,7 +8,7 @@ use std::alloc::*; fn main() { unsafe { let x = Global.alloc(Layout::from_size_align_unchecked(1, 1)).unwrap(); - let _y = Global.realloc(x, Layout::from_size_align_unchecked(1, 1), 1).unwrap(); + Global.realloc(x, Layout::from_size_align_unchecked(1, 1), 1).unwrap(); let _z = *(x.as_ptr() as *mut u8); //~ ERROR constant evaluation error //~^ NOTE dangling pointer was dereferenced } diff --git a/tests/compiletest.rs b/tests/compiletest.rs index 896d1cae5969e..38d8069672814 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -62,6 +62,7 @@ fn compile_fail(sysroot: &Path, path: &str, target: &str, host: &str, need_fullm config.compile_lib_path = rustc_lib_path(); } flags.push(format!("--sysroot {}", sysroot.display())); + flags.push("-Dwarnings -Dunused".to_owned()); // overwrite the -Aunused in compiletest-rs config.src_base = PathBuf::from(path.to_string()); flags.push("-Zmir-emit-validate=1".to_owned()); config.target_rustcflags = Some(flags.join(" ")); @@ -70,23 +71,6 @@ fn compile_fail(sysroot: &Path, path: &str, target: &str, host: &str, need_fullm compiletest::run_tests(&config); } -fn rustc_pass(sysroot: &Path, path: &str) { - eprintln!("{}", format!("## Running run-pass tests in {} against rustc", path).green().bold()); - let mut config = compiletest::Config::default().tempdir(); - config.mode = "run-pass".parse().expect("Invalid mode"); - config.src_base = PathBuf::from(path); - if let Some(rustc_path) = rustc_test_suite() { - config.rustc_path = rustc_path; - config.run_lib_path = rustc_lib_path(); - config.compile_lib_path = rustc_lib_path(); - config.target_rustcflags = Some(format!("-Dwarnings --sysroot {}", sysroot.display())); - } else { - config.target_rustcflags = Some("-Dwarnings".to_owned()); - } - config.host_rustcflags = Some("-Dwarnings".to_string()); - compiletest::run_tests(&config); -} - fn miri_pass(sysroot: &Path, path: &str, target: &str, host: &str, need_fullmir: bool, opt: bool) { if need_fullmir && !have_fullmir() { eprintln!("{}", format!( @@ -116,6 +100,7 @@ fn miri_pass(sysroot: &Path, path: &str, target: &str, host: &str, need_fullmir: } let mut flags = Vec::new(); flags.push(format!("--sysroot {}", sysroot.display())); + flags.push("-Dwarnings -Dunused".to_owned()); // overwrite the -Aunused in compiletest-rs if have_fullmir() { flags.push("-Zmiri-start-fn".to_owned()); } @@ -190,12 +175,6 @@ fn run_pass_miri(opt: bool) { miri_pass(&sysroot, "tests/run-pass-fullmir", &host, &host, true, opt); } -fn run_pass_rustc() { - let sysroot = get_sysroot(); - rustc_pass(&sysroot, "tests/run-pass"); - rustc_pass(&sysroot, "tests/run-pass-fullmir"); -} - fn compile_fail_miri() { let sysroot = get_sysroot(); let host = get_host(); @@ -211,10 +190,7 @@ fn test() { // introduces. We still get parallelism within our tests because `compiletest` // uses `libtest` which runs jobs in parallel. - run_pass_rustc(); - run_pass_miri(false); - // FIXME: Disabled for now, as the optimizer is pretty broken and crashes... // See https://github.com/rust-lang/rust/issues/50411 //run_pass_miri(true); diff --git a/tests/run-pass/box_box_trait.rs b/tests/run-pass/box_box_trait.rs index 57eef52d573b9..7fe568522d53e 100644 --- a/tests/run-pass/box_box_trait.rs +++ b/tests/run-pass/box_box_trait.rs @@ -13,7 +13,9 @@ impl Drop for DroppableStruct { trait MyTrait { fn dummy(&self) { } } impl MyTrait for Box {} +#[allow(dead_code)] struct Whatever { w: Box } + impl Whatever { fn new(w: Box) -> Whatever { Whatever { w: w } From fb3ac376ad61e2b57a2f110a1f71d7318bf4238f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 13 Jul 2018 16:29:00 +0200 Subject: [PATCH 0137/3747] run fullMIR tests in appveyor --- appveyor.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/appveyor.yml b/appveyor.yml index 46580f274bf62..2e2920591f762 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -35,6 +35,8 @@ test_script: - set RUST_BACKTRACE=1 - cargo build --release - cargo test --release + - set MIRI_SYSROOT=C:\Users\appveyor\.xargo\HOST + - cargo test --release notifications: - provider: Email From 9396310317481963aeb0aa44d8f54911e94f8a1d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 13 Jul 2018 16:30:27 +0200 Subject: [PATCH 0138/3747] appveyor: put 64bit config first, it seems to usually be faster --- appveyor.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index 2e2920591f762..6aee7e75a956e 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -2,10 +2,10 @@ environment: global: PROJECT_NAME: miri matrix: - - TARGET: i686-pc-windows-msvc - MSYS2_BITS: 32 - TARGET: x86_64-pc-windows-msvc MSYS2_BITS: 64 + - TARGET: i686-pc-windows-msvc + MSYS2_BITS: 32 # branches to build branches: From 216b8f74075a6f555c3cc1bf8a2dab16af35ca0a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 15 Jul 2018 23:47:28 +0200 Subject: [PATCH 0139/3747] shim some Windows functions --- src/fn_call.rs | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index 8105330b3263e..de40ef943a559 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -623,11 +623,24 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' } // Windows API subs - "AddVectoredExceptionHandler" | - "SetThreadStackGuarantee" => { - let usize = self.tcx.types.usize; + "AddVectoredExceptionHandler" => { // any non zero value works for the stdlib. This is just used for stackoverflows anyway - self.write_scalar(dest, Scalar::from_u128(1), usize)?; + self.write_scalar(dest, Scalar::from_u128(1), dest_ty)?; + }, + "GetModuleHandleW" | + "GetProcAddress" | + "InitializeCriticalSection" | + "EnterCriticalSection" | + "TryEnterCriticalSection" | + "LeaveCriticalSection" | + "DeleteCriticalSection" | + "SetLastError" => { + // pretend these do not exist/nothing happened, by returning zero + self.write_scalar(dest, Scalar::from_u128(0), dest_ty)?; + }, + "GetLastError" => { + // this is c::ERROR_CALL_NOT_IMPLEMENTED + self.write_scalar(dest, Scalar::from_u128(120), dest_ty)?; }, // We can't execute anything else From e1a3b9606e712dac18bae566498d2fa93ca0c276 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 16 Jul 2018 11:42:46 +0200 Subject: [PATCH 0140/3747] TLS on Windows --- src/fn_call.rs | 30 +++++++++++++++++++++++++++++- src/lib.rs | 20 ++++++++++++++++++-- src/tls.rs | 1 + 3 files changed, 48 insertions(+), 3 deletions(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index de40ef943a559..31b3b4b18d171 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -607,7 +607,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' } "_tlv_atexit" => { - return err!(Unimplemented("can't interpret with full mir for osx target".to_owned())); + return err!(Unimplemented("Thread-local store is not fully supported on macOS".to_owned())); }, // Stub out all the other pthread calls to just return 0 @@ -643,6 +643,34 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' self.write_scalar(dest, Scalar::from_u128(120), 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) { + return err!(OutOfTls); + } + self.write_scalar(dest, Scalar::from_u128(key), dest_ty)?; + } + "TlsGetValue" => { + let key = self.value_to_scalar(args[0])?.to_bytes()?; + let ptr = self.memory.load_tls(key)?; + self.write_ptr(dest, ptr, dest_ty)?; + } + "TlsSetValue" => { + let key = self.value_to_scalar(args[0])?.to_bytes()?; + let new_ptr = self.into_ptr(args[1].value)?; + self.memory.store_tls(key, new_ptr)?; + + // Return success (1) + self.write_scalar(dest, Scalar::from_u128(1), dest_ty)?; + } + // We can't execute anything else _ => { return err!(Unimplemented( diff --git a/src/lib.rs b/src/lib.rs index 520d696405a1b..5a2d7e77d65fe 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -141,7 +141,12 @@ pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( main_id: DefId, start_wrapper: Option, ) -> EvalResult<'tcx, (EvalContext<'a, 'mir, 'tcx, Evaluator<'tcx>>, Option)> { - let mut ecx = EvalContext::new(tcx.at(syntax::codemap::DUMMY_SP), ty::ParamEnv::reveal_all(), Default::default(), Default::default()); + let mut ecx = EvalContext::new( + tcx.at(syntax::codemap::DUMMY_SP), + ty::ParamEnv::reveal_all(), + Default::default(), + MemoryData::new() + ); let main_instance = ty::Instance::mono(ecx.tcx.tcx, main_id); let main_mir = ecx.load_mir(main_instance.def)?; @@ -338,7 +343,7 @@ pub struct TlsEntry<'tcx> { dtor: Option>, } -#[derive(Clone, Default, PartialEq, Eq)] +#[derive(Clone, PartialEq, Eq)] pub struct MemoryData<'tcx> { /// The Key to use for the next thread-local allocation. next_thread_local: TlsKey, @@ -355,6 +360,17 @@ pub struct MemoryData<'tcx> { statics: HashMap, AllocId>, } +impl<'tcx> MemoryData<'tcx> { + fn new() -> Self { + MemoryData { + next_thread_local: 1, // start with 1 as we must not use 0 on Windows + thread_local: BTreeMap::new(), + locks: HashMap::new(), + statics: HashMap::new(), + } + } +} + impl<'tcx> Hash for MemoryData<'tcx> { fn hash(&self, state: &mut H) { let MemoryData { diff --git a/src/tls.rs b/src/tls.rs index 45805f3aa8cc1..ffcf86291590d 100644 --- a/src/tls.rs +++ b/src/tls.rs @@ -139,6 +139,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' None => self.memory.fetch_tls_dtor(None)?, }; } + // FIXME: On a windows target, call `unsafe extern "system" fn on_tls_callback`. Ok(()) } } From f9a8d2618e0f6e7f8070a6b367bcdf101df75481 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 16 Jul 2018 22:26:32 +0200 Subject: [PATCH 0141/3747] fix for latest rust nightly --- src/bin/miri.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 51c53b4af275d..29e2e50d5d68b 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -112,7 +112,7 @@ fn after_analysis<'a, 'tcx>(state: &mut CompileState<'a, 'tcx>, use_start_fn: bo ); impl<'a, 'tcx: 'a, 'hir> itemlikevisit::ItemLikeVisitor<'hir> for Visitor<'a, 'tcx> { fn visit_item(&mut self, i: &'hir hir::Item) { - if let hir::Item_::ItemFn(.., body_id) = i.node { + if let hir::ItemKind::Fn(.., body_id) = i.node { if i.attrs.iter().any(|attr| { attr.name() == "test" }) From 72756b7071953413aee87c4f9f17ebcf75a16b7e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 17 Jul 2018 08:56:06 +0200 Subject: [PATCH 0142/3747] also fix rustc_tests --- rustc_tests/Cargo.lock | 21 +-------------------- rustc_tests/src/main.rs | 2 +- 2 files changed, 2 insertions(+), 21 deletions(-) diff --git a/rustc_tests/Cargo.lock b/rustc_tests/Cargo.lock index 9cf4fe0d1342a..0154ecc2ccbdc 100644 --- a/rustc_tests/Cargo.lock +++ b/rustc_tests/Cargo.lock @@ -93,7 +93,7 @@ dependencies = [ "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 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -114,18 +114,6 @@ dependencies = [ "redox_syscall 0.1.40 (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" -dependencies = [ - "aho-corasick 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", - "memchr 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "regex-syntax 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "thread_local 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "regex" version = "1.0.0" @@ -138,11 +126,6 @@ dependencies = [ "utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "regex-syntax" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "regex-syntax" version = "0.6.0" @@ -251,9 +234,7 @@ dependencies = [ "checksum quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9274b940887ce9addde99c4eee6b5c44cc494b182b97e73dc8ffdcb3397fd3f0" "checksum redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "c214e91d3ecf43e9a4e41e578973adeb14b474f2bee858742d127af75a0112b1" "checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76" -"checksum regex 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1731164734096285ec2a5ec7fea5248ae2f5485b3feeb0115af4fda2183b2d1b" "checksum regex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "75ecf88252dce580404a22444fc7d626c01815debba56a7f4f536772a5ff19d3" -"checksum regex-syntax 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ad890a5eef7953f55427c50575c680c42841653abd2b028b68cd223d157f62db" "checksum regex-syntax 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8f1ac0f60d675cc6cf13a20ec076568254472551051ad5dd050364d70671bf6b" "checksum termcolor 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "adc4587ead41bf016f11af03e55a624c06568b5a19db4e90fde573d805074f83" "checksum termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "689a3bdfaab439fd92bc87df5c4c78417d3cbe537487274e9b0b2dce76e92096" diff --git a/rustc_tests/src/main.rs b/rustc_tests/src/main.rs index 64cd380970e4d..1891e3dba103d 100644 --- a/rustc_tests/src/main.rs +++ b/rustc_tests/src/main.rs @@ -90,7 +90,7 @@ fn after_analysis<'a, 'tcx>(state: &mut CompileState<'a, 'tcx>) { struct Visitor<'a, 'tcx: 'a>(TyCtxt<'a, 'tcx, 'tcx>, &'a CompileState<'a, 'tcx>); impl<'a, 'tcx: 'a, 'hir> itemlikevisit::ItemLikeVisitor<'hir> for Visitor<'a, 'tcx> { fn visit_item(&mut self, i: &'hir hir::Item) { - if let hir::Item_::ItemFn(.., body_id) = i.node { + if let hir::ItemKind::Fn(.., body_id) = i.node { if i.attrs.iter().any(|attr| attr.name() == "test") { let did = self.0.hir.body_owner_def_id(body_id); println!("running test: {}", self.0.def_path_debug_str(did)); From 2a29ed01427b50eeb10ed2ea02128d7bb55cab8f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 22 Jul 2018 09:48:49 +0200 Subject: [PATCH 0143/3747] use default-run --- Cargo.toml | 3 +++ README.md | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index c46ba7c414295..417d76c54cb33 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,3 +1,5 @@ +cargo-features = ["default-run"] + [package] authors = ["Scott Olson "] description = "An experimental interpreter for Rust MIR." @@ -6,6 +8,7 @@ name = "miri" repository = "https://github.com/solson/miri" version = "0.1.0" build = "build.rs" +default-run = "miri" [[bin]] doc = false diff --git a/README.md b/README.md index d515aad8bea51..b7dfab27ef1c1 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ how to fix it, you could send a PR. :smile: ## Running tests ```sh -cargo run --bin miri tests/run-pass-fullmir/vecs.rs # Or whatever test you like. +cargo run tests/run-pass-fullmir/vecs.rs # Or whatever test you like. ``` ## Running miri on your own project('s test suite) @@ -63,7 +63,7 @@ RUSTFLAGS='-Zalways-encode-mir' xargo build Now you can run miri against the libstd compiled by xargo: ```sh -MIRI_SYSROOT=~/.xargo/HOST cargo run --bin miri tests/run-pass-fullmir/hashmap.rs +MIRI_SYSROOT=~/.xargo/HOST cargo run tests/run-pass-fullmir/hashmap.rs ``` Notice that you will have to re-run the last step of the preparations above when From 444d97fc7d94c9a8bb2f9d87c7393c6e3a6c2f12 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 22 Jul 2018 09:51:23 +0200 Subject: [PATCH 0144/3747] fix vecs.rs path --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index b7dfab27ef1c1..8c476270db1a2 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ how to fix it, you could send a PR. :smile: ## Running tests ```sh -cargo run tests/run-pass-fullmir/vecs.rs # Or whatever test you like. +cargo run tests/run-pass/vecs.rs # Or whatever test you like. ``` ## Running miri on your own project('s test suite) From b055ff03f13a668c44fda89768205cf69bf67f56 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Wed, 25 Jul 2018 17:28:16 +0200 Subject: [PATCH 0145/3747] Produce the exit codes that compiletest expects --- src/bin/miri.rs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 29e2e50d5d68b..e380317138aa2 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -228,8 +228,12 @@ fn main() { } }); - rustc_driver::run_compiler(&args, Box::new(MiriCompilerCalls { - default: Box::new(RustcDefaultCalls), - start_fn, - }), None, None); + + let result = rustc_driver::run(move || { + rustc_driver::run_compiler(&args, Box::new(MiriCompilerCalls { + default: Box::new(RustcDefaultCalls), + start_fn, + }), None, None) + }); + std::process::exit(result as i32); } From 53114e3b36942138d4f9dd575f61e5493bc578f6 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Tue, 5 Jun 2018 10:21:28 +0200 Subject: [PATCH 0146/3747] Update to rustc sanity check branch --- src/intrinsic.rs | 3 ++- src/validation.rs | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/intrinsic.rs b/src/intrinsic.rs index cee2f1ab7682f..6c8fd0af40363 100644 --- a/src/intrinsic.rs +++ b/src/intrinsic.rs @@ -245,10 +245,11 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: "discriminant_value" => { let ty = substs.type_at(0); + let layout = self.layout_of(ty)?; let adt_ptr = self.into_ptr(args[0].value)?; 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, ty)?; + let discr_val = self.read_discriminant_value(place, layout)?; self.write_scalar(dest, Scalar::from_u128(discr_val), dest_layout.ty)?; } diff --git a/src/validation.rs b/src/validation.rs index 758fd5d274701..caa5b702e61a9 100644 --- a/src/validation.rs +++ b/src/validation.rs @@ -765,7 +765,8 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' match adt.adt_kind() { AdtKind::Enum => { - let variant_idx = self.read_discriminant_as_variant_index(query.place.1, query.ty)?; + let layout = self.layout_of(query.ty)?; + let variant_idx = self.read_discriminant_as_variant_index(query.place.1, layout)?; let variant = &adt.variants[variant_idx]; if !variant.fields.is_empty() { From e849fa47fb121caa30b408e84cf28a7d078f542b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 24 Jul 2018 22:20:50 +0200 Subject: [PATCH 0147/3747] make miri compile again --- src/intrinsic.rs | 2 +- src/validation.rs | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/intrinsic.rs b/src/intrinsic.rs index 6c8fd0af40363..dc2224c4ceefa 100644 --- a/src/intrinsic.rs +++ b/src/intrinsic.rs @@ -344,7 +344,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: ty::layout::Abi::Scalar(_) => Value::Scalar(Scalar::null()), _ => { // FIXME(oli-obk): pass TyLayout to alloc_ptr instead of Ty - let ptr = this.alloc_ptr(dest_layout.ty)?; + let ptr = this.alloc_ptr(dest_layout)?; let ptr = Scalar::Ptr(ptr); this.memory.write_repeat(ptr, 0, size)?; Value::ByRef(ptr, dest_layout.align) diff --git a/src/validation.rs b/src/validation.rs index caa5b702e61a9..676718ad7fe76 100644 --- a/src/validation.rs +++ b/src/validation.rs @@ -140,6 +140,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' mir::Place::Static(ref s) => AbsPlace::Static(s.def_id), mir::Place::Projection(ref p) => AbsPlace::Projection(Box::new(self.abstract_place_projection(&*p)?)), + _ => unimplemented!("validation is not currently maintained"), }) } From b7c57fee610f8128b454e22898371167287b0ddc Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 24 Jul 2018 22:29:08 +0200 Subject: [PATCH 0148/3747] Ignore tests the bool thing will be fixed by the validation I have planned, and we already ignored another test around modifing constants. --- tests/compile-fail/invalid_bool.rs | 2 ++ tests/compile-fail/modifying_constants.rs | 2 ++ 2 files changed, 4 insertions(+) diff --git a/tests/compile-fail/invalid_bool.rs b/tests/compile-fail/invalid_bool.rs index 1aa5d9bf77bcc..6ac7f3e60c0d4 100644 --- a/tests/compile-fail/invalid_bool.rs +++ b/tests/compile-fail/invalid_bool.rs @@ -1,3 +1,5 @@ +//ignore-test FIXME (do some basic validation of invariants for all values in flight) + fn main() { let b = unsafe { std::mem::transmute::(2) }; if b { unreachable!() } else { unreachable!() } //~ ERROR constant evaluation error diff --git a/tests/compile-fail/modifying_constants.rs b/tests/compile-fail/modifying_constants.rs index c10657ae75a77..6ffba89fa5efb 100644 --- a/tests/compile-fail/modifying_constants.rs +++ b/tests/compile-fail/modifying_constants.rs @@ -1,3 +1,5 @@ +// ignore-test FIXME: we are not making these statics read-only any more? + fn main() { let x = &1; // the `&1` is promoted to a constant, but it used to be that only the pointer is marked static, not the pointee let y = unsafe { &mut *(x as *const i32 as *mut i32) }; From 305d8aeafe4ab53d7809ec6a1b9227166bd4fa63 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Wed, 25 Jul 2018 15:48:20 +0200 Subject: [PATCH 0149/3747] Disable blood letting edge features --- Cargo.toml | 3 --- 1 file changed, 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 417d76c54cb33..c46ba7c414295 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,3 @@ -cargo-features = ["default-run"] - [package] authors = ["Scott Olson "] description = "An experimental interpreter for Rust MIR." @@ -8,7 +6,6 @@ name = "miri" repository = "https://github.com/solson/miri" version = "0.1.0" build = "build.rs" -default-run = "miri" [[bin]] doc = false From e6f1e15676c26fdc7c4713647fe007b26f361a8e Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Thu, 26 Jul 2018 14:37:43 +0200 Subject: [PATCH 0150/3747] Bump min dependency version --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index c46ba7c414295..07ebca6491dd0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -30,5 +30,5 @@ log = "0.4" cargo_miri = ["cargo_metadata"] [dev-dependencies] -compiletest_rs = { version = "0.3.4", features = ["tmp"] } +compiletest_rs = { version = "0.3.12", features = ["tmp"] } colored = "1.6" From 851f2ab98e9ff67bdfb2bb20c9a639b35bc71799 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 26 Jul 2018 16:43:45 +0200 Subject: [PATCH 0151/3747] test `cargo miri` output --- .travis.yml | 8 ++++++-- cargo-miri-test/.gitignore | 1 + cargo-miri-test/src/main.rs | 2 ++ cargo-miri-test/stderr.ref | 1 + cargo-miri-test/stdout.ref | 1 + src/fn_call.rs | 2 +- 6 files changed, 12 insertions(+), 3 deletions(-) create mode 100644 cargo-miri-test/.gitignore create mode 100644 cargo-miri-test/stderr.ref create mode 100644 cargo-miri-test/stdout.ref diff --git a/.travis.yml b/.travis.yml index 9aa632da05e0e..b130c6dc5b2b4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -30,9 +30,13 @@ script: RUST_BACKTRACE=1 cargo test --release --all-features --all && cargo install --all-features --force - | - # Test cargo miri + # Test `cargo miri` cd cargo-miri-test && - cargo miri && + MIRI_SYSROOT=~/.xargo/HOST cargo miri -q -- -Zmiri-start-fn >stdout.real 2>stderr.real && + # Test `cargo miri` output. + diff stdout.ref stdout.real && + diff stderr.ref stderr.real && + # Test `cargo miri test` #cargo miri test && cd .. - | diff --git a/cargo-miri-test/.gitignore b/cargo-miri-test/.gitignore new file mode 100644 index 0000000000000..56f307a7fb133 --- /dev/null +++ b/cargo-miri-test/.gitignore @@ -0,0 +1 @@ +*.real diff --git a/cargo-miri-test/src/main.rs b/cargo-miri-test/src/main.rs index 07b0e4cee4e5c..6ad516710e1b1 100644 --- a/cargo-miri-test/src/main.rs +++ b/cargo-miri-test/src/main.rs @@ -6,4 +6,6 @@ fn main() { let buf = &[1,2,3,4]; let n = ::read_u32(buf); assert_eq!(n, 0x01020304); + println!("{:#x}", n); + eprintln!("standard error"); } diff --git a/cargo-miri-test/stderr.ref b/cargo-miri-test/stderr.ref new file mode 100644 index 0000000000000..aa7d1a2bdec7d --- /dev/null +++ b/cargo-miri-test/stderr.ref @@ -0,0 +1 @@ +standard error diff --git a/cargo-miri-test/stdout.ref b/cargo-miri-test/stdout.ref new file mode 100644 index 0000000000000..53fefc734c853 --- /dev/null +++ b/cargo-miri-test/stdout.ref @@ -0,0 +1 @@ +0x1020304 diff --git a/src/fn_call.rs b/src/fn_call.rs index 31b3b4b18d171..a51ff73008ec8 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -612,7 +612,7 @@ 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_") => { - info!("ignoring C ABI call: {}", link_name); + debug!("ignoring C ABI call: {}", link_name); self.write_null(dest, dest_ty)?; } From ee9879918541e55f246d1f969022303c33e7feb4 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 26 Jul 2018 16:49:10 +0200 Subject: [PATCH 0152/3747] we no longer need to mess with the environment in our test suite --- tests/compiletest.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/tests/compiletest.rs b/tests/compiletest.rs index 38d8069672814..82a2144a337de 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -8,7 +8,6 @@ use colored::*; use std::slice::SliceConcatExt; use std::path::{PathBuf, Path}; use std::io::Write; -use std::env; macro_rules! eprintln { ($($arg:tt)*) => { @@ -111,9 +110,6 @@ fn miri_pass(sysroot: &Path, path: &str, target: &str, host: &str, need_fullmir: // For now, only validate without optimizations. Inlining breaks validation. flags.push("-Zmir-emit-validate=1".to_owned()); } - // Control miri logging. This is okay despite concurrent test execution as all tests - // will set this env var to the same value. - env::set_var("MIRI_LOG", "warn"); config.target_rustcflags = Some(flags.join(" ")); compiletest::run_tests(&config); } From 5bd02b7c075802df68e215125e0b0cf7cce1aaa4 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 26 Jul 2018 17:08:29 +0200 Subject: [PATCH 0153/3747] also show the output (though we lost the interleaving) --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index b130c6dc5b2b4..44a124efda3aa 100644 --- a/.travis.yml +++ b/.travis.yml @@ -33,6 +33,7 @@ script: # Test `cargo miri` cd cargo-miri-test && MIRI_SYSROOT=~/.xargo/HOST cargo miri -q -- -Zmiri-start-fn >stdout.real 2>stderr.real && + cat stdout.real stderr.real && # Test `cargo miri` output. diff stdout.ref stdout.real && diff stderr.ref stderr.real && From f6d4814fb34e5ed3e35f0bd0e070d244fd48f485 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 26 Jul 2018 17:30:52 +0200 Subject: [PATCH 0154/3747] detect another printing function for nicer error --- src/fn_call.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index a51ff73008ec8..9dfff9f553982 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -759,7 +759,8 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' match &path[..] { // A Rust function is missing, which means we are running with MIR missing for libstd (or other dependencies). // Still, we can make many things mostly work by "emulating" or ignoring some functions. - "std::io::_print" => { + "std::io::_print" | + "std::io::_eprint" => { warn!( "Ignoring output. To run programs that print, make sure you have a libstd with full MIR." ); From ae830f61153e079e0ed030351f22cd0fa14abf1a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 26 Jul 2018 17:41:45 +0200 Subject: [PATCH 0155/3747] dont test cargo miri output on mac. no idea what that system is doing. --- .travis.yml | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/.travis.yml b/.travis.yml index 44a124efda3aa..865da6f664990 100644 --- a/.travis.yml +++ b/.travis.yml @@ -32,11 +32,16 @@ script: - | # Test `cargo miri` cd cargo-miri-test && - MIRI_SYSROOT=~/.xargo/HOST cargo miri -q -- -Zmiri-start-fn >stdout.real 2>stderr.real && - cat stdout.real stderr.real && - # Test `cargo miri` output. - diff stdout.ref stdout.real && - diff stderr.ref stderr.real && + if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then + MIRI_SYSROOT=~/.xargo/HOST cargo miri -q -- -Zmiri-start-fn + else + MIRI_SYSROOT=~/.xargo/HOST cargo miri -q -- -Zmiri-start-fn >stdout.real 2>stderr.real && + cat stdout.real stderr.real && + # Test `cargo miri` output. Not on mac because output redirecting doesn't + # work. There is no error. It just stops CI. + diff stdout.ref stdout.real && + diff stderr.ref stderr.real + fi && # Test `cargo miri test` #cargo miri test && cd .. From c490151b16a07ccd261af44b4ddf5832ceda8c5a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 26 Jul 2018 17:58:37 +0200 Subject: [PATCH 0156/3747] memrchr currently does not work --- cargo-miri-test/src/main.rs | 2 +- cargo-miri-test/stdout.ref | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/cargo-miri-test/src/main.rs b/cargo-miri-test/src/main.rs index 6ad516710e1b1..3fb265f6a7ba9 100644 --- a/cargo-miri-test/src/main.rs +++ b/cargo-miri-test/src/main.rs @@ -6,6 +6,6 @@ fn main() { let buf = &[1,2,3,4]; let n = ::read_u32(buf); assert_eq!(n, 0x01020304); - println!("{:#x}", n); + //println!("{:#x}", n); FIXME enable once memrchr works in miri eprintln!("standard error"); } diff --git a/cargo-miri-test/stdout.ref b/cargo-miri-test/stdout.ref index 53fefc734c853..e69de29bb2d1d 100644 --- a/cargo-miri-test/stdout.ref +++ b/cargo-miri-test/stdout.ref @@ -1 +0,0 @@ -0x1020304 From e2c1b7008642cfea12b347ed3dc4a7dd0e1f0ad0 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 26 Jul 2018 18:15:51 +0200 Subject: [PATCH 0157/3747] nicer diff formating --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 865da6f664990..d05661a484874 100644 --- a/.travis.yml +++ b/.travis.yml @@ -39,8 +39,8 @@ script: cat stdout.real stderr.real && # Test `cargo miri` output. Not on mac because output redirecting doesn't # work. There is no error. It just stops CI. - diff stdout.ref stdout.real && - diff stderr.ref stderr.real + diff -u stdout.ref stdout.real && + diff -u stderr.ref stderr.real fi && # Test `cargo miri test` #cargo miri test && From ff3efb4e04ed2e915bda0cef3d2c7c9e4145ab34 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 30 Jul 2018 14:49:01 +0200 Subject: [PATCH 0158/3747] clarify error message when sysroot was not found --- src/bin/miri.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/bin/miri.rs b/src/bin/miri.rs index e380317138aa2..58897541491de 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -200,7 +200,8 @@ fn find_sysroot() -> String { _ => { option_env!("RUST_SYSROOT") .expect( - "need to specify RUST_SYSROOT env var or use rustup or multirust", + "Could not find sysroot. Either set MIRI_SYSROOT at run-time, or at \ + build-time specify RUST_SYSROOT env var or use rustup or multirust", ) .to_owned() } From 1538b36c8042f22f7c3fe191016c8469991c1c89 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 31 Jul 2018 20:27:36 +0200 Subject: [PATCH 0159/3747] make sure that StorageDead invalidates the backing store --- tests/compile-fail/storage_dead_dangling.rs | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 tests/compile-fail/storage_dead_dangling.rs diff --git a/tests/compile-fail/storage_dead_dangling.rs b/tests/compile-fail/storage_dead_dangling.rs new file mode 100644 index 0000000000000..6abae2069fc2b --- /dev/null +++ b/tests/compile-fail/storage_dead_dangling.rs @@ -0,0 +1,20 @@ +static mut LEAK: usize = 0; + +fn fill(v: &mut i32) { + unsafe { LEAK = v as *mut _ as usize; } +} + +fn evil() { + let v = unsafe { &mut *(LEAK as *mut i32) }; + let _x = *v; //~ ERROR dangling pointer was dereferenced +} + +fn main() { + let _y; + { + let mut x = 0i32; + fill(&mut x); + _y = x; + } + evil(); +} From b45885d31fb32d0c9e05b054ef18698579c244ab Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 1 Aug 2018 16:34:39 +0200 Subject: [PATCH 0160/3747] Revert "Disable blood letting edge features" This reverts commit 305d8aeafe4ab53d7809ec6a1b9227166bd4fa63. --- Cargo.toml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Cargo.toml b/Cargo.toml index 07ebca6491dd0..23c7856cc7735 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,3 +1,5 @@ +cargo-features = ["default-run"] + [package] authors = ["Scott Olson "] description = "An experimental interpreter for Rust MIR." @@ -6,6 +8,7 @@ name = "miri" repository = "https://github.com/solson/miri" version = "0.1.0" build = "build.rs" +default-run = "miri" [[bin]] doc = false From 18546308cefd4edd51aaab6fbf5e896130b3532e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 2 Aug 2018 00:17:02 +0200 Subject: [PATCH 0161/3747] mem(r)chr is working in miri now --- cargo-miri-test/src/main.rs | 2 +- cargo-miri-test/stdout.ref | 1 + tests/run-pass-fullmir/memchr.rs | 90 ++++++++++++++++++++++++++++++++ 3 files changed, 92 insertions(+), 1 deletion(-) create mode 100644 tests/run-pass-fullmir/memchr.rs diff --git a/cargo-miri-test/src/main.rs b/cargo-miri-test/src/main.rs index 3fb265f6a7ba9..6ad516710e1b1 100644 --- a/cargo-miri-test/src/main.rs +++ b/cargo-miri-test/src/main.rs @@ -6,6 +6,6 @@ fn main() { let buf = &[1,2,3,4]; let n = ::read_u32(buf); assert_eq!(n, 0x01020304); - //println!("{:#x}", n); FIXME enable once memrchr works in miri + println!("{:#x}", n); eprintln!("standard error"); } diff --git a/cargo-miri-test/stdout.ref b/cargo-miri-test/stdout.ref index e69de29bb2d1d..6710f307cb26d 100644 --- a/cargo-miri-test/stdout.ref +++ b/cargo-miri-test/stdout.ref @@ -0,0 +1 @@ +0x01020304 diff --git a/tests/run-pass-fullmir/memchr.rs b/tests/run-pass-fullmir/memchr.rs new file mode 100644 index 0000000000000..36eb85dcf7e8d --- /dev/null +++ b/tests/run-pass-fullmir/memchr.rs @@ -0,0 +1,90 @@ +#![feature(slice_internals)] + +extern crate core; +use core::slice::memchr::{memchr, memrchr}; + +// test fallback implementations on all platforms +fn matches_one() { + assert_eq!(Some(0), memchr(b'a', b"a")); +} + +fn matches_begin() { + assert_eq!(Some(0), memchr(b'a', b"aaaa")); +} + +fn matches_end() { + assert_eq!(Some(4), memchr(b'z', b"aaaaz")); +} + +fn matches_nul() { + assert_eq!(Some(4), memchr(b'\x00', b"aaaa\x00")); +} + +fn matches_past_nul() { + assert_eq!(Some(5), memchr(b'z', b"aaaa\x00z")); +} + +fn no_match_empty() { + assert_eq!(None, memchr(b'a', b"")); +} + +fn no_match() { + assert_eq!(None, memchr(b'a', b"xyz")); +} + +fn matches_one_reversed() { + assert_eq!(Some(0), memrchr(b'a', b"a")); +} + +fn matches_begin_reversed() { + assert_eq!(Some(3), memrchr(b'a', b"aaaa")); +} + +fn matches_end_reversed() { + assert_eq!(Some(0), memrchr(b'z', b"zaaaa")); +} + +fn matches_nul_reversed() { + assert_eq!(Some(4), memrchr(b'\x00', b"aaaa\x00")); +} + +fn matches_past_nul_reversed() { + assert_eq!(Some(0), memrchr(b'z', b"z\x00aaaa")); +} + +fn no_match_empty_reversed() { + assert_eq!(None, memrchr(b'a', b"")); +} + +fn no_match_reversed() { + assert_eq!(None, memrchr(b'a', b"xyz")); +} + +fn each_alignment_reversed() { + let mut data = [1u8; 64]; + let needle = 2; + let pos = 40; + data[pos] = needle; + for start in 0..16 { + assert_eq!(Some(pos - start), memrchr(needle, &data[start..])); + } +} + +fn main() { + matches_one(); + matches_begin(); + matches_end(); + matches_nul(); + matches_past_nul(); + no_match_empty(); + no_match(); + + matches_one_reversed(); + matches_begin_reversed(); + matches_end_reversed(); + matches_nul_reversed(); + matches_past_nul_reversed(); + no_match_empty_reversed(); + no_match_reversed(); + each_alignment_reversed(); +} From d844792d761b920fb05aedb6d84e071afe805545 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 2 Aug 2018 10:45:08 +0200 Subject: [PATCH 0162/3747] fix format string to obtain desired output --- cargo-miri-test/src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cargo-miri-test/src/main.rs b/cargo-miri-test/src/main.rs index 6ad516710e1b1..4e1501dd57f27 100644 --- a/cargo-miri-test/src/main.rs +++ b/cargo-miri-test/src/main.rs @@ -6,6 +6,6 @@ fn main() { let buf = &[1,2,3,4]; let n = ::read_u32(buf); assert_eq!(n, 0x01020304); - println!("{:#x}", n); + println!("{:#010x}", n); eprintln!("standard error"); } From 3783cebe80b3ac0b6acb28452962e6131bb03a2c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 2 Aug 2018 12:16:02 +0200 Subject: [PATCH 0163/3747] remove dependency on lazy_static and regex by getting rid of some dead validation hack --- Cargo.toml | 4 +--- src/lib.rs | 3 --- src/validation.rs | 28 ---------------------------- 3 files changed, 1 insertion(+), 34 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 07ebca6491dd0..fd62625be131a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,9 +21,7 @@ required-features = ["cargo_miri"] [dependencies] byteorder = { version = "1.1", features = ["i128"]} cargo_metadata = { version = "0.6", optional = true } -regex = "1.0" -lazy_static = "1.0" -env_logger = "0.5.0-rc.1" +env_logger = "0.5" log = "0.4" [features] diff --git a/src/lib.rs b/src/lib.rs index 5a2d7e77d65fe..f16471352c8fa 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -17,9 +17,6 @@ extern crate rustc_data_structures; extern crate rustc_mir; extern crate rustc_target; extern crate syntax; -extern crate regex; -#[macro_use] -extern crate lazy_static; use rustc::ty::{self, TyCtxt}; use rustc::ty::layout::{TyLayout, LayoutOf, Size}; diff --git a/src/validation.rs b/src/validation.rs index 676718ad7fe76..8d55f8ab0afe9 100644 --- a/src/validation.rs +++ b/src/validation.rs @@ -159,34 +159,6 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' } debug_assert!(self.memory.cur_frame == self.cur_frame()); - // HACK: Determine if this method is whitelisted and hence we do not perform any validation. - // We currently insta-UB on anything passing around uninitialized memory, so we have to whitelist - // the places that are allowed to do that. - // The second group is stuff libstd does that is forbidden even under relaxed validation. - { - // The regexp we use for filtering - use regex::Regex; - lazy_static! { - static ref RE: Regex = Regex::new("^(\ - (std|alloc::heap::__core)::mem::(uninitialized|forget)::|\ - <(std|alloc)::heap::Heap as (std::heap|alloc::allocator)::Alloc>::|\ - <(std|alloc::heap::__core)::mem::ManuallyDrop><.*>::new$|\ - <(std|alloc::heap::__core)::mem::ManuallyDrop as std::ops::DerefMut><.*>::deref_mut$|\ - (std|alloc::heap::__core)::ptr::read::|\ - \ - ><.*>::inner$|\ - ><.*>::drop_slow$|\ - (std::heap|alloc::allocator)::Layout::for_value::|\ - (std|alloc::heap::__core)::mem::(size|align)_of_val::\ - )").unwrap(); - } - // Now test - let name = self.frame().instance.to_string(); - if RE.is_match(&name) { - return Ok(()); - } - } - // We need to monomorphize ty *without* erasing lifetimes trace!("validation_op1: {:?}", operand.ty.sty); let ty = operand.ty.subst(self.tcx.tcx, self.substs()); From be91aea0fa285a86291e70259fb7be1d472674a8 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Tue, 7 Aug 2018 15:22:11 +0200 Subject: [PATCH 0164/3747] Rustup --- src/bin/miri.rs | 5 +- src/fn_call.rs | 142 +++++++++++++++++++++++--------------------- src/helpers.rs | 10 ++-- src/intrinsic.rs | 148 ++++++++++++++++++++++------------------------ src/lib.rs | 77 ++++++++++-------------- src/operator.rs | 7 ++- src/tls.rs | 22 +++---- src/validation.rs | 8 +-- 8 files changed, 206 insertions(+), 213 deletions(-) diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 58897541491de..57d49b2e6bc5f 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -3,6 +3,7 @@ extern crate getopts; extern crate miri; extern crate rustc; +extern crate rustc_metadata; extern crate rustc_driver; extern crate rustc_errors; extern crate rustc_codegen_utils; @@ -12,7 +13,7 @@ extern crate syntax; extern crate log; use rustc::session::Session; -use rustc::middle::cstore::CrateStore; +use rustc_metadata::cstore::CStore; use rustc_driver::{Compilation, CompilerCalls, RustcDefaultCalls}; use rustc_driver::driver::{CompileState, CompileController}; use rustc::session::config::{self, Input, ErrorOutputType}; @@ -70,7 +71,7 @@ impl<'a> CompilerCalls<'a> for MiriCompilerCalls { codegen_backend: &CodegenBackend, matches: &getopts::Matches, sess: &Session, - cstore: &CrateStore, + cstore: &CStore, input: &Input, odir: &Option, ofile: &Option, diff --git a/src/fn_call.rs b/src/fn_call.rs index 9dfff9f553982..11b0ae345c7fd 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -37,7 +37,7 @@ fn write_discriminant_value<'a, 'mir, 'tcx: 'a + 'mir>( .val; let (discr_dest, discr) = ecx.place_field(dest, mir::Field::new(0), layout)?; - ecx.write_scalar(discr_dest, Scalar::from_u128(discr_val), discr.ty)?; + ecx.write_scalar(discr_dest, Scalar::from_uint(discr_val, discr.size), discr.ty)?; } layout::Variants::NicheFilling { dataful_variant, @@ -50,7 +50,7 @@ fn write_discriminant_value<'a, 'mir, 'tcx: 'a + 'mir>( ecx.place_field(dest, mir::Field::new(0), layout)?; let niche_value = ((variant_index - niche_variants.start()) as u128) .wrapping_add(niche_start); - ecx.write_scalar(niche_dest, Scalar::from_u128(niche_value), niche.ty)?; + ecx.write_scalar(niche_dest, Scalar::from_uint(niche_value, niche.size), niche.ty)?; } } } @@ -88,7 +88,7 @@ pub trait EvalContextExt<'tcx> { sig: ty::FnSig<'tcx>, ) -> EvalResult<'tcx, bool>; - fn write_null(&mut self, dest: Place, dest_ty: Ty<'tcx>) -> EvalResult<'tcx>; + fn write_null(&mut self, dest: Place, dest_layout: TyLayout<'tcx>) -> EvalResult<'tcx>; } impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super::Evaluator<'tcx>> { @@ -138,7 +138,8 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' let amt = 128 - self.memory.pointer_size().bytes() * 8; let (dest, return_to_block) = destination.unwrap(); let ty = self.tcx.types.usize; - self.write_scalar(dest, Scalar::from_u128((n << amt) >> amt), ty)?; + let ptr_size = self.memory.pointer_size(); + self.write_scalar(dest, Scalar::from_uint((n << amt) >> amt, ptr_size), ty)?; self.goto_block(return_to_block); return Ok(true); } @@ -187,12 +188,13 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' Some(name) => name.as_str(), None => self.tcx.item_name(def_id).as_str(), }; + let dest_layout = self.layout_of(dest_ty)?; match &link_name[..] { "malloc" => { let size = self.value_to_scalar(args[0])?.to_usize(self)?; if size == 0 { - self.write_null(dest, dest_ty)?; + self.write_null(dest, dest_layout)?; } else { let align = self.tcx.data_layout.pointer_align; let ptr = self.memory.allocate(Size::from_bytes(size), align, MemoryKind::C.into())?; @@ -201,8 +203,8 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' } "free" => { - let ptr = self.into_ptr(args[0].value)?; - if !ptr.is_null()? { + let ptr = self.into_ptr(args[0].value)?.unwrap_or_err()?; + if !ptr.is_null() { self.memory.deallocate( ptr.to_ptr()?, None, @@ -241,7 +243,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' self.write_scalar(dest, Scalar::Ptr(ptr), dest_ty)?; } "__rust_dealloc" => { - let ptr = self.into_ptr(args[0].value)?.to_ptr()?; + let ptr = self.into_ptr(args[0].value)?.unwrap_or_err()?.to_ptr()?; let old_size = self.value_to_scalar(args[1])?.to_usize(self)?; let align = self.value_to_scalar(args[2])?.to_usize(self)?; if old_size == 0 { @@ -257,7 +259,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' )?; } "__rust_realloc" => { - let ptr = self.into_ptr(args[0].value)?.to_ptr()?; + let ptr = self.into_ptr(args[0].value)?.unwrap_or_err()?.to_ptr()?; let old_size = self.value_to_scalar(args[1])?.to_usize(self)?; let align = self.value_to_scalar(args[2])?.to_usize(self)?; let new_size = self.value_to_scalar(args[3])?.to_usize(self)?; @@ -300,7 +302,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' "dlsym" => { let _handle = self.into_ptr(args[0].value)?; - let symbol = self.into_ptr(args[1].value)?.to_ptr()?; + let symbol = self.into_ptr(args[1].value)?.unwrap_or_err()?.to_ptr()?; let symbol_name = self.memory.read_c_str(symbol)?; let err = format!("bad c unicode symbol: {:?}", symbol_name); let symbol_name = ::std::str::from_utf8(symbol_name).unwrap_or(&err); @@ -314,10 +316,10 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' // fn __rust_maybe_catch_panic(f: fn(*mut u8), data: *mut u8, data_ptr: *mut usize, vtable_ptr: *mut usize) -> u32 // We abort on panic, so not much is going on here, but we still have to call the closure let u8_ptr_ty = self.tcx.mk_mut_ptr(self.tcx.types.u8); - let f = self.into_ptr(args[0].value)?.to_ptr()?; - let data = self.into_ptr(args[1].value)?; + let f = self.into_ptr(args[0].value)?.unwrap_or_err()?.to_ptr()?; + let data = self.into_ptr(args[1].value)?.unwrap_or_err()?; let f_instance = self.memory.get_fn(f)?; - self.write_null(dest, dest_ty)?; + self.write_null(dest, dest_layout)?; // Now we make a function call. TODO: Consider making this re-usable? EvalContext::step does sth. similar for the TLS dtors, // and of course eval_main. @@ -343,7 +345,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' assert!(args.next().is_none(), "__rust_maybe_catch_panic argument has more arguments than expected"); // We ourselves return 0 - self.write_null(dest, dest_ty)?; + self.write_null(dest, dest_layout)?; // Don't fall through return Ok(()); @@ -354,8 +356,8 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' } "memcmp" => { - let left = self.into_ptr(args[0].value)?; - let right = self.into_ptr(args[1].value)?; + let left = self.into_ptr(args[0].value)?.unwrap_or_err()?; + let right = self.into_ptr(args[1].value)?.unwrap_or_err()?; let n = Size::from_bytes(self.value_to_scalar(args[2])?.to_usize(self)?); let result = { @@ -378,7 +380,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' } "memrchr" => { - let ptr = self.into_ptr(args[0].value)?; + let ptr = self.into_ptr(args[0].value)?.unwrap_or_err()?; let val = self.value_to_scalar(args[1])?.to_bytes()? as u8; let num = self.value_to_scalar(args[2])?.to_usize(self)?; if let Some(idx) = self.memory.read_bytes(ptr, Size::from_bytes(num))?.iter().rev().position( @@ -388,12 +390,12 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' let new_ptr = ptr.ptr_offset(Size::from_bytes(num - idx as u64 - 1), &self)?; self.write_ptr(dest, new_ptr, dest_ty)?; } else { - self.write_null(dest, dest_ty)?; + self.write_null(dest, dest_layout)?; } } "memchr" => { - let ptr = self.into_ptr(args[0].value)?; + let ptr = self.into_ptr(args[0].value)?.unwrap_or_err()?; let val = self.value_to_scalar(args[1])?.to_bytes()? as u8; let num = self.value_to_scalar(args[2])?.to_usize(self)?; if let Some(idx) = self.memory.read_bytes(ptr, Size::from_bytes(num))?.iter().position( @@ -403,17 +405,17 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' let new_ptr = ptr.ptr_offset(Size::from_bytes(idx as u64), &self)?; self.write_ptr(dest, new_ptr, dest_ty)?; } else { - self.write_null(dest, dest_ty)?; + self.write_null(dest, dest_layout)?; } } "getenv" => { let result = { - let name_ptr = self.into_ptr(args[0].value)?.to_ptr()?; + let name_ptr = self.into_ptr(args[0].value)?.unwrap_or_err()?.to_ptr()?; let name = self.memory.read_c_str(name_ptr)?; match self.machine.env_vars.get(name) { Some(&var) => Scalar::Ptr(var), - None => Scalar::null(), + None => Scalar::null(self.memory.pointer_size()), } }; self.write_scalar(dest, result, dest_ty)?; @@ -422,8 +424,8 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' "unsetenv" => { let mut success = None; { - let name_ptr = self.into_ptr(args[0].value)?; - if !name_ptr.is_null()? { + let name_ptr = self.into_ptr(args[0].value)?.unwrap_or_err()?; + if !name_ptr.is_null() { let name = self.memory.read_c_str(name_ptr.to_ptr()?)?; if !name.is_empty() && !name.contains(&b'=') { success = Some(self.machine.env_vars.remove(name)); @@ -434,19 +436,19 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' if let Some(var) = old { self.memory.deallocate(var, None, MemoryKind::Env.into())?; } - self.write_null(dest, dest_ty)?; + self.write_null(dest, dest_layout)?; } else { - self.write_scalar(dest, Scalar::from_i128(-1), dest_ty)?; + self.write_scalar(dest, Scalar::from_int(-1, dest_layout.size), dest_ty)?; } } "setenv" => { let mut new = None; { - let name_ptr = self.into_ptr(args[0].value)?; - let value_ptr = self.into_ptr(args[1].value)?.to_ptr()?; + let name_ptr = self.into_ptr(args[0].value)?.unwrap_or_err()?; + let value_ptr = self.into_ptr(args[1].value)?.unwrap_or_err()?.to_ptr()?; let value = self.memory.read_c_str(value_ptr)?; - if !name_ptr.is_null()? { + if !name_ptr.is_null() { let name = self.memory.read_c_str(name_ptr.to_ptr()?)?; if !name.is_empty() && !name.contains(&b'=') { new = Some((name.to_owned(), value.to_owned())); @@ -470,15 +472,15 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' { self.memory.deallocate(var, None, MemoryKind::Env.into())?; } - self.write_null(dest, dest_ty)?; + self.write_null(dest, dest_layout)?; } else { - self.write_scalar(dest, Scalar::from_i128(-1), dest_ty)?; + self.write_scalar(dest, Scalar::from_int(-1, dest_layout.size), dest_ty)?; } } "write" => { let fd = self.value_to_scalar(args[0])?.to_bytes()?; - let buf = self.into_ptr(args[1].value)?; + let buf = self.into_ptr(args[1].value)?.unwrap_or_err()?; let n = self.value_to_scalar(args[2])?.to_bytes()? as u64; trace!("Called write({:?}, {:?}, {:?})", fd, buf, n); let result = if fd == 1 || fd == 2 { @@ -502,31 +504,33 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' let ptr_size = self.memory.pointer_size(); self.write_scalar( dest, - Scalar::from_isize(result, ptr_size), + Scalar::from_int(result, ptr_size), dest_ty, )?; } "strlen" => { - let ptr = self.into_ptr(args[0].value)?.to_ptr()?; + let ptr = self.into_ptr(args[0].value)?.unwrap_or_err()?.to_ptr()?; let n = self.memory.read_c_str(ptr)?.len(); let ptr_size = self.memory.pointer_size(); - self.write_scalar(dest, Scalar::from_usize(n as u64, ptr_size), dest_ty)?; + self.write_scalar(dest, Scalar::from_uint(n as u64, ptr_size), dest_ty)?; } // Some things needed for sys::thread initialization to go through "signal" | "sigaction" | "sigaltstack" => { - self.write_scalar(dest, Scalar::null(), dest_ty)?; + let ptr_size = self.memory.pointer_size(); + self.write_scalar(dest, Scalar::null(ptr_size), dest_ty)?; } "sysconf" => { let name = self.value_to_scalar(args[0])?.to_usize(self)?; + let ptr_size = self.memory.pointer_size(); trace!("sysconf() called with name {}", name); // cache the sysconf integers via miri's global cache let paths = &[ - (&["libc", "_SC_PAGESIZE"], Scalar::from_i128(4096)), - (&["libc", "_SC_GETPW_R_SIZE_MAX"], Scalar::from_i128(-1)), + (&["libc", "_SC_PAGESIZE"], Scalar::from_int(4096, ptr_size)), + (&["libc", "_SC_GETPW_R_SIZE_MAX"], Scalar::from_int(-1, ptr_size)), ]; let mut result = None; for &(path, path_value) in paths { @@ -554,43 +558,45 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' // Hook pthread calls that go to the thread-local storage memory subsystem "pthread_key_create" => { - let key_ptr = self.into_ptr(args[0].value)?; - let key_align = self.layout_of(args[0].ty)?.align; + let key_ptr = self.into_ptr(args[0].value)?.unwrap_or_err()?; // Extract the function type out of the signature (that seems easier than constructing it ourselves...) - let dtor = match self.into_ptr(args[1].value)? { + let dtor = match self.into_ptr(args[1].value)?.unwrap_or_err()? { Scalar::Ptr(dtor_ptr) => Some(self.memory.get_fn(dtor_ptr)?), - Scalar::Bits { defined: 0, .. } => return err!(ReadUndefBytes), - Scalar::Bits { bits: 0, .. } => None, + Scalar::Bits { bits: 0, size } => { + assert_eq!(size as u64, self.memory.pointer_size().bytes()); + None + }, Scalar::Bits { .. } => return err!(ReadBytesAsPointer), }; // Figure out how large a pthread TLS key actually is. This is libc::pthread_key_t. let key_type = args[0].ty.builtin_deref(true) .ok_or_else(|| EvalErrorKind::AbiViolation("Wrong signature used for pthread_key_create: First argument must be a raw pointer.".to_owned()))?.ty; - let key_size = self.layout_of(key_type)?.size; + let key_layout = self.layout_of(key_type)?; // Create key and write it into the memory where key_ptr wants it let key = self.memory.create_tls_key(dtor) as u128; - if key_size.bits() < 128 && key >= (1u128 << key_size.bits() as u128) { + if key_layout.size.bits() < 128 && key >= (1u128 << key_layout.size.bits() as u128) { return err!(OutOfTls); } self.memory.write_scalar( key_ptr, - key_align, - Scalar::from_u128(key), - key_size, + key_layout.align, + Scalar::from_uint(key, key_layout.size).into(), + key_layout.size, + key_layout.align, false, )?; // Return success (0) - self.write_null(dest, dest_ty)?; + self.write_null(dest, dest_layout)?; } "pthread_key_delete" => { let key = self.value_to_scalar(args[0])?.to_bytes()?; self.memory.delete_tls_key(key)?; // Return success (0) - self.write_null(dest, dest_ty)?; + self.write_null(dest, dest_layout)?; } "pthread_getspecific" => { let key = self.value_to_scalar(args[0])?.to_bytes()?; @@ -599,11 +605,11 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' } "pthread_setspecific" => { let key = self.value_to_scalar(args[0])?.to_bytes()?; - let new_ptr = self.into_ptr(args[1].value)?; + let new_ptr = self.into_ptr(args[1].value)?.unwrap_or_err()?; self.memory.store_tls(key, new_ptr)?; // Return success (0) - self.write_null(dest, dest_ty)?; + self.write_null(dest, dest_layout)?; } "_tlv_atexit" => { @@ -613,19 +619,20 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' // Stub out all the other pthread calls to just return 0 link_name if link_name.starts_with("pthread_") => { debug!("ignoring C ABI call: {}", link_name); - self.write_null(dest, dest_ty)?; + self.write_null(dest, dest_layout)?; } "mmap" => { // This is a horrible hack, but well... the guard page mechanism calls mmap and expects a particular return value, so we give it that value - let addr = self.into_ptr(args[0].value)?; + let addr = self.into_ptr(args[0].value)?.unwrap_or_err()?; self.write_ptr(dest, addr, dest_ty)?; } // Windows API subs "AddVectoredExceptionHandler" => { // any non zero value works for the stdlib. This is just used for stackoverflows anyway - self.write_scalar(dest, Scalar::from_u128(1), dest_ty)?; + let ptr_size = self.memory.pointer_size(); + self.write_scalar(dest, Scalar::from_int(1, ptr_size), dest_ty)?; }, "GetModuleHandleW" | "GetProcAddress" | @@ -636,26 +643,28 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' "DeleteCriticalSection" | "SetLastError" => { // pretend these do not exist/nothing happened, by returning zero - self.write_scalar(dest, Scalar::from_u128(0), dest_ty)?; + let ptr_size = self.memory.pointer_size(); + self.write_scalar(dest, Scalar::from_int(0, ptr_size), dest_ty)?; }, "GetLastError" => { // this is c::ERROR_CALL_NOT_IMPLEMENTED - self.write_scalar(dest, Scalar::from_u128(120), dest_ty)?; + let ptr_size = self.memory.pointer_size(); + self.write_scalar(dest, Scalar::from_int(120, ptr_size), dest_ty)?; }, // Windows TLS "TlsAlloc" => { // This just creates a key; Windows does not natively support TLS dtors. - // Figure out how large a TLS key actually is. This is c::DWORD. - let key_size = self.layout_of(dest_ty)?.size; - // Create key and return it let key = self.memory.create_tls_key(None) as u128; - if key_size.bits() < 128 && key >= (1u128 << key_size.bits() as u128) { + + // Figure out how large a TLS key actually is. This is c::DWORD. + if dest_layout.size.bits() < 128 && key >= (1u128 << dest_layout.size.bits() as u128) { return err!(OutOfTls); } - self.write_scalar(dest, Scalar::from_u128(key), dest_ty)?; + let ptr_size = self.memory.pointer_size(); + self.write_scalar(dest, Scalar::from_uint(key, ptr_size), dest_layout.ty)?; } "TlsGetValue" => { let key = self.value_to_scalar(args[0])?.to_bytes()?; @@ -664,11 +673,12 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' } "TlsSetValue" => { let key = self.value_to_scalar(args[0])?.to_bytes()?; - let new_ptr = self.into_ptr(args[1].value)?; + let new_ptr = self.into_ptr(args[1].value)?.unwrap_or_err()?; self.memory.store_tls(key, new_ptr)?; + let ptr_size = self.memory.pointer_size(); // Return success (1) - self.write_scalar(dest, Scalar::from_u128(1), dest_ty)?; + self.write_scalar(dest, Scalar::from_int(1, ptr_size), dest_ty)?; } // We can't execute anything else @@ -791,7 +801,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' Ok(()) } - fn write_null(&mut self, dest: Place, dest_ty: Ty<'tcx>) -> EvalResult<'tcx> { - self.write_scalar(dest, Scalar::null(), dest_ty) + fn write_null(&mut self, dest: Place, dest_layout: TyLayout<'tcx>) -> EvalResult<'tcx> { + self.write_scalar(dest, Scalar::null(dest_layout.size), dest_layout.ty) } } diff --git a/src/helpers.rs b/src/helpers.rs index aa699b509fad8..8482c484608b7 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -51,7 +51,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: // FIXME: assuming here that type size is < i64::max_value() let pointee_size = self.layout_of(pointee_ty)?.size.bytes() as i64; let offset = offset.overflowing_mul(pointee_size).0; - ptr.ptr_wrapping_signed_offset(offset, self) + Ok(ptr.ptr_wrapping_signed_offset(offset, self)) } fn pointer_offset( @@ -65,7 +65,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: // We also consider the NULL pointer its own separate allocation, and all the remaining integers pointers their own // allocation. - if ptr.is_null()? { + if ptr.is_null() { // NULL pointers must only be offset by 0 return if offset == 0 { Ok(ptr) @@ -80,7 +80,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: // Do not do bounds-checking for integers; they can never alias a normal pointer anyway. if let Scalar::Ptr(ptr) = ptr { self.memory.check_bounds(ptr, false)?; - } else if ptr.is_null()? { + } else if ptr.is_null() { // We moved *to* a NULL pointer. That seems wrong, LLVM considers the NULL pointer its own small allocation. Reject this, for now. return err!(InvalidNullPointerUsage); } @@ -96,7 +96,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: ) -> EvalResult<'tcx, i64> { assert_eq!(value.ty, self.tcx.types.isize); let raw = self.value_to_scalar(value)?.to_bits(self.memory.pointer_size())?; - let raw = sign_extend(self.tcx.tcx, raw, self.tcx.types.isize)?; + let raw = sign_extend(raw, self.layout_of(self.tcx.types.isize).unwrap()); Ok(raw as i64) } @@ -114,7 +114,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: ) -> EvalResult<'tcx, i32> { assert_eq!(value.ty, self.tcx.types.i32); let raw = self.value_to_scalar(value)?.to_bits(Size::from_bits(32))?; - let raw = sign_extend(self.tcx.tcx, raw, self.tcx.types.i32)?; + let raw = sign_extend(raw, self.layout_of(self.tcx.types.i32).unwrap()); Ok(raw as i32) } diff --git a/src/intrinsic.rs b/src/intrinsic.rs index dc2224c4ceefa..5c6e7f9b2dc1b 100644 --- a/src/intrinsic.rs +++ b/src/intrinsic.rs @@ -2,7 +2,7 @@ use rustc::mir; use rustc::ty::layout::{TyLayout, LayoutOf, Size, Primitive, Integer::*}; use rustc::ty; -use rustc::mir::interpret::{EvalResult, Scalar, Value}; +use rustc::mir::interpret::{EvalResult, Scalar, Value, ScalarMaybeUndef}; use rustc_mir::interpret::{Place, PlaceExtra, HasMemory, EvalContext, ValTy}; use helpers::EvalContextExt as HelperEvalContextExt; @@ -65,7 +65,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: "arith_offset" => { let offset = self.value_to_isize(args[1])?; - let ptr = self.into_ptr(args[0].value)?; + let ptr = self.into_ptr(args[0].value)?.unwrap_or_err()?; let result_ptr = self.wrapping_pointer_offset(ptr, substs.type_at(0), offset)?; self.write_ptr(dest, result_ptr, dest_layout.ty)?; } @@ -81,7 +81,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: "atomic_load_relaxed" | "atomic_load_acq" | "volatile_load" => { - let ptr = self.into_ptr(args[0].value)?; + let ptr = self.into_ptr(args[0].value)?.unwrap_or_err()?; let align = self.layout_of(args[0].ty)?.align; let valty = ValTy { @@ -97,7 +97,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: "volatile_store" => { let ty = substs.type_at(0); let align = self.layout_of(ty)?.align; - let dest = self.into_ptr(args[0].value)?; + let dest = self.into_ptr(args[0].value)?.unwrap_or_err()?; self.write_value_to_ptr(args[1].value, dest, align, ty)?; } @@ -108,7 +108,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: _ if intrinsic_name.starts_with("atomic_xchg") => { let ty = substs.type_at(0); let align = self.layout_of(ty)?.align; - let ptr = self.into_ptr(args[0].value)?; + let ptr = self.into_ptr(args[0].value)?.unwrap_or_err()?; let change = self.value_to_scalar(args[1])?; let old = self.read_value(ptr, align, ty)?; let old = match old { @@ -118,7 +118,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: }; self.write_scalar(dest, old, ty)?; self.write_scalar( - Place::from_scalar_ptr(ptr, align), + Place::from_scalar_ptr(ptr.into(), align), change, ty, )?; @@ -127,23 +127,23 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: _ if intrinsic_name.starts_with("atomic_cxchg") => { let ty = substs.type_at(0); let align = self.layout_of(ty)?.align; - let ptr = self.into_ptr(args[0].value)?; + let ptr = self.into_ptr(args[0].value)?.unwrap_or_err()?; let expect_old = self.value_to_scalar(args[1])?; let change = self.value_to_scalar(args[2])?; let old = self.read_value(ptr, align, ty)?; let old = match old { - Value::Scalar(val) => val, + Value::Scalar(val) => val.unwrap_or_err()?, Value::ByRef { .. } => bug!("just read the value, can't be byref"), Value::ScalarPair(..) => bug!("atomic_cxchg doesn't work with nonprimitives"), }; let (val, _) = self.binary_op(mir::BinOp::Eq, old, ty, expect_old, ty)?; let valty = ValTy { - value: Value::ScalarPair(old, val), + value: Value::ScalarPair(old.into(), val.into()), ty: dest_layout.ty, }; self.write_value(valty, dest)?; self.write_scalar( - Place::from_scalar_ptr(ptr, dest_layout.align), + Place::from_scalar_ptr(ptr.into(), dest_layout.align), change, ty, )?; @@ -176,7 +176,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: "atomic_xsub_relaxed" => { let ty = substs.type_at(0); let align = self.layout_of(ty)?.align; - let ptr = self.into_ptr(args[0].value)?; + let ptr = self.into_ptr(args[0].value)?.unwrap_or_err()?; let change = self.value_to_scalar(args[1])?; let old = self.read_value(ptr, align, ty)?; let old = match old { @@ -196,8 +196,8 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: _ => bug!(), }; // FIXME: what do atomics do on overflow? - let (val, _) = self.binary_op(op, old, ty, change, ty)?; - self.write_scalar(Place::from_scalar_ptr(ptr, dest_layout.align), val, ty)?; + let (val, _) = self.binary_op(op, old.unwrap_or_err()?, ty, change, ty)?; + self.write_scalar(Place::from_scalar_ptr(ptr.into(), dest_layout.align), val, ty)?; } "breakpoint" => unimplemented!(), // halt miri @@ -212,8 +212,8 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: // TODO: We do not even validate alignment for the 0-bytes case. libstd relies on this in vec::IntoIter::next. // Also see the write_bytes intrinsic. let elem_align = elem_layout.align; - let src = self.into_ptr(args[0].value)?; - let dest = self.into_ptr(args[1].value)?; + let src = self.into_ptr(args[0].value)?.unwrap_or_err()?; + let dest = self.into_ptr(args[1].value)?.unwrap_or_err()?; self.memory.copy( src, elem_align, @@ -250,7 +250,8 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: let adt_align = self.layout_of(args[0].ty)?.align; let place = Place::from_scalar_ptr(adt_ptr, adt_align); let discr_val = self.read_discriminant_value(place, layout)?; - self.write_scalar(dest, Scalar::from_u128(discr_val), dest_layout.ty)?; + let ptr_size = self.memory.pointer_size(); + self.write_scalar(dest, Scalar::from_uint(discr_val, ptr_size), dest_layout.ty)?; } "sinf32" | "fabsf32" | "cosf32" | "sqrtf32" | "expf32" | "exp2f32" | "logf32" | @@ -320,7 +321,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: let a = self.value_to_scalar(args[0])?; let b = self.value_to_scalar(args[1])?; // check x % y != 0 - if !self.binary_op(mir::BinOp::Rem, a, ty, b, ty)?.0.is_null()? { + if !self.binary_op(mir::BinOp::Rem, a, ty, b, ty)?.0.is_null() { return err!(ValidationFailure(format!("exact_div: {:?} cannot be divided by {:?}", a, b))); } let result = self.binary_op(mir::BinOp::Div, a, ty, b, ty)?; @@ -330,41 +331,24 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: "likely" | "unlikely" | "forget" => {} "init" => { - let size = dest_layout.size; - let init = |this: &mut Self, val: Value| { - let zero_val = match val { - Value::ByRef(ptr, _) => { - // These writes have no alignment restriction anyway. - this.memory.write_repeat(ptr, 0, size)?; - val - } - // TODO(solson): Revisit this, it's fishy to check for Undef here. - Value::Scalar(Scalar::Bits { defined: 0, .. }) => { - match this.layout_of(dest_layout.ty)?.abi { - ty::layout::Abi::Scalar(_) => Value::Scalar(Scalar::null()), - _ => { - // FIXME(oli-obk): pass TyLayout to alloc_ptr instead of Ty - let ptr = this.alloc_ptr(dest_layout)?; - let ptr = Scalar::Ptr(ptr); - this.memory.write_repeat(ptr, 0, size)?; - Value::ByRef(ptr, dest_layout.align) - } + match dest { + Place::Local { frame, local } => { + match self.stack()[frame].locals[local].access()? { + Value::ByRef(ptr, _) => { + // These writes have no alignment restriction anyway. + self.memory.write_repeat(ptr, 0, dest_layout.size)?; + } + Value::Scalar(_) => self.write_value(ValTy { value: Value::Scalar(Scalar::null(dest_layout.size).into()), ty: dest_layout.ty }, dest)?, + Value::ScalarPair(..) => { + self.write_value(ValTy { value: Value::ScalarPair(Scalar::null(dest_layout.size).into(), Scalar::null(dest_layout.size).into()), ty: dest_layout.ty }, dest)?; } } - Value::Scalar(_) => Value::Scalar(Scalar::null()), - Value::ScalarPair(..) => { - Value::ScalarPair(Scalar::null(), Scalar::null()) - } - }; - Ok(zero_val) - }; - match dest { - Place::Local { frame, local } => self.modify_local(frame, local, init)?, + }, Place::Ptr { ptr, align: _align, extra: PlaceExtra::None, - } => self.memory.write_repeat(ptr, 0, size)?, + } => self.memory.write_repeat(ptr.unwrap_or_err()?, 0, dest_layout.size)?, Place::Ptr { .. } => { bug!("init intrinsic tried to write to fat or unaligned ptr target") } @@ -374,7 +358,8 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: "min_align_of" => { let elem_ty = substs.type_at(0); let elem_align = self.layout_of(elem_ty)?.align.abi(); - let align_val = Scalar::from_u128(elem_align as u128); + let ptr_size = self.memory.pointer_size(); + let align_val = Scalar::from_uint(elem_align as u128, ptr_size); self.write_scalar(dest, align_val, dest_layout.ty)?; } @@ -382,13 +367,14 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: let ty = substs.type_at(0); let layout = self.layout_of(ty)?; let align = layout.align.pref(); - let align_val = Scalar::from_u128(align as u128); + let ptr_size = self.memory.pointer_size(); + let align_val = Scalar::from_uint(align as u128, ptr_size); self.write_scalar(dest, align_val, dest_layout.ty)?; } "move_val_init" => { let ty = substs.type_at(0); - let ptr = self.into_ptr(args[0].value)?; + let ptr = self.into_ptr(args[0].value)?.unwrap_or_err()?; let align = self.layout_of(args[0].ty)?.align; self.write_value_to_ptr(args[1].value, ptr, align, ty)?; } @@ -406,7 +392,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: "offset" => { let offset = self.value_to_isize(args[1])?; - let ptr = self.into_ptr(args[0].value)?; + let ptr = self.into_ptr(args[0].value)?.unwrap_or_err()?; let result_ptr = self.pointer_offset(ptr, substs.type_at(0), offset)?; self.write_ptr(dest, result_ptr, dest_layout.ty)?; } @@ -517,16 +503,18 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: "size_of" => { let ty = substs.type_at(0); - let size = self.layout_of(ty)?.size.bytes().into(); - self.write_scalar(dest, Scalar::from_u128(size), dest_layout.ty)?; + let size = self.layout_of(ty)?.size.bytes(); + let ptr_size = self.memory.pointer_size(); + self.write_scalar(dest, Scalar::from_uint(size, ptr_size), dest_layout.ty)?; } "size_of_val" => { let ty = substs.type_at(0); let (size, _) = self.size_and_align_of_dst(ty, args[0].value)?; + let ptr_size = self.memory.pointer_size(); self.write_scalar( dest, - Scalar::from_u128(size.bytes() as u128), + Scalar::from_uint(size.bytes() as u128, ptr_size), dest_layout.ty, )?; } @@ -535,9 +523,10 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: "align_of_val" => { let ty = substs.type_at(0); let (_, align) = self.size_and_align_of_dst(ty, args[0].value)?; + let ptr_size = self.memory.pointer_size(); self.write_scalar( dest, - Scalar::from_u128(align.abi() as u128), + Scalar::from_uint(align.abi(), ptr_size), dest_layout.ty, )?; } @@ -551,7 +540,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: "type_id" => { let ty = substs.type_at(0); let n = self.tcx.type_id_hash(ty); - self.write_scalar(dest, Scalar::Bits { bits: n as u128, defined: 64 }, dest_layout.ty)?; + self.write_scalar(dest, Scalar::Bits { bits: n as u128, size: 8 }, dest_layout.ty)?; } "transmute" => { @@ -629,21 +618,24 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: } "uninit" => { - let size = dest_layout.size; - let uninit = |this: &mut Self, val: Value| match val { - Value::ByRef(ptr, _) => { - this.memory.mark_definedness(ptr, size, false)?; - Ok(val) - } - _ => Ok(Value::Scalar(Scalar::undef())), - }; match dest { - Place::Local { frame, local } => self.modify_local(frame, local, uninit)?, + Place::Local { frame, local } => { + match self.stack()[frame].locals[local].access()? { + Value::ByRef(ptr, _) => { + // These writes have no alignment restriction anyway. + self.memory.mark_definedness(ptr, dest_layout.size, false)?; + } + Value::Scalar(_) => self.write_value(ValTy { value: Value::Scalar(ScalarMaybeUndef::Undef), ty: dest_layout.ty }, dest)?, + Value::ScalarPair(..) => { + self.write_value(ValTy { value: Value::ScalarPair(ScalarMaybeUndef::Undef, ScalarMaybeUndef::Undef), ty: dest_layout.ty }, dest)?; + } + } + }, Place::Ptr { ptr, align: _align, extra: PlaceExtra::None, - } => self.memory.mark_definedness(ptr, size, false)?, + } => self.memory.mark_definedness(ptr.unwrap_or_err()?, dest_layout.size, false)?, Place::Ptr { .. } => { bug!("uninit intrinsic tried to write to fat or unaligned ptr target") } @@ -654,7 +646,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: let ty = substs.type_at(0); let ty_layout = self.layout_of(ty)?; let val_byte = self.value_to_u8(args[1])?; - let ptr = self.into_ptr(args[0].value)?; + let ptr = self.into_ptr(args[0].value)?.unwrap_or_err()?; let count = self.value_to_usize(args[2])?; if count > 0 { // HashMap relies on write_bytes on a NULL ptr with count == 0 to work @@ -683,21 +675,21 @@ fn numeric_intrinsic<'tcx>( ) -> EvalResult<'tcx, Scalar> { macro_rules! integer_intrinsic { ($method:ident) => ({ - let result_bytes = match kind { - Primitive::Int(I8, true) => (bytes as i8).$method() as u128, - Primitive::Int(I8, false) => (bytes as u8).$method() as u128, - Primitive::Int(I16, true) => (bytes as i16).$method() as u128, - Primitive::Int(I16, false) => (bytes as u16).$method() as u128, - Primitive::Int(I32, true) => (bytes as i32).$method() as u128, - Primitive::Int(I32, false) => (bytes as u32).$method() as u128, - Primitive::Int(I64, true) => (bytes as i64).$method() as u128, - Primitive::Int(I64, false) => (bytes as u64).$method() as u128, - Primitive::Int(I128, true) => (bytes as i128).$method() as u128, - Primitive::Int(I128, false) => bytes.$method() as u128, + let (result_bytes, size) = match kind { + Primitive::Int(I8, true) => ((bytes as i8).$method() as u128, 1), + Primitive::Int(I8, false) => ((bytes as u8).$method() as u128, 1), + Primitive::Int(I16, true) => ((bytes as i16).$method() as u128, 2), + Primitive::Int(I16, false) => ((bytes as u16).$method() as u128, 2), + Primitive::Int(I32, true) => ((bytes as i32).$method() as u128, 4), + Primitive::Int(I32, false) => ((bytes as u32).$method() as u128, 4), + Primitive::Int(I64, true) => ((bytes as i64).$method() as u128, 8), + Primitive::Int(I64, false) => ((bytes as u64).$method() as u128, 8), + Primitive::Int(I128, true) => ((bytes as i128).$method() as u128, 16), + Primitive::Int(I128, false) => (bytes.$method() as u128, 16), _ => bug!("invalid `{}` argument: {:?}", name, bytes), }; - Scalar::from_u128(result_bytes) + Scalar::from_uint(result_bytes, Size::from_bytes(size)) }); } diff --git a/src/lib.rs b/src/lib.rs index f16471352c8fa..b08f63e095d84 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -56,16 +56,14 @@ use range_map::RangeMap; use validation::{ValidationQuery, AbsPlace}; pub trait ScalarExt { - fn null() -> Self; + fn null(size: Size) -> Self; fn from_i32(i: i32) -> Self; - fn from_u128(i: u128) -> Self; - fn from_i128(i: i128) -> Self; - fn from_usize(i: u64, ptr_size: Size) -> Self; - fn from_isize(i: i64, ptr_size: Size) -> Self; + fn from_uint(i: impl Into, ptr_size: Size) -> Self; + fn from_int(i: impl Into, ptr_size: Size) -> Self; fn from_f32(f: f32) -> Self; fn from_f64(f: f64) -> Self; fn to_usize<'a, 'mir, 'tcx>(self, ecx: &rustc_mir::interpret::EvalContext<'a, 'mir, 'tcx, Evaluator<'tcx>>) -> EvalResult<'static, u64>; - fn is_null(self) -> EvalResult<'static, bool>; + fn is_null(self) -> bool; /// HACK: this function just extracts all bits if `defined != 0` /// Mainly used for args of C-functions and we should totally correctly fetch the size /// of their arguments @@ -73,36 +71,28 @@ pub trait ScalarExt { } impl ScalarExt for Scalar { - fn null() -> Self { - Scalar::Bits { bits: 0, defined: 128 } + fn null(size: Size) -> Self { + Scalar::Bits { bits: 0, size: size.bytes() as u8 } } fn from_i32(i: i32) -> Self { - Scalar::Bits { bits: i as u32 as u128, defined: 32 } + Scalar::Bits { bits: i as u32 as u128, size: 4 } } - fn from_u128(i: u128) -> Self { - Scalar::Bits { bits: i, defined: 128 } + fn from_uint(i: impl Into, ptr_size: Size) -> Self { + Scalar::Bits { bits: i.into(), size: ptr_size.bytes() as u8 } } - fn from_i128(i: i128) -> Self { - Scalar::Bits { bits: i as u128, defined: 128 } - } - - fn from_usize(i: u64, ptr_size: Size) -> Self { - Scalar::Bits { bits: i as u128, defined: ptr_size.bits() as u8 } - } - - fn from_isize(i: i64, ptr_size: Size) -> Self { - Scalar::Bits { bits: i as i128 as u128, defined: ptr_size.bits() as u8 } + fn from_int(i: impl Into, ptr_size: Size) -> Self { + Scalar::Bits { bits: i.into() as u128, size: ptr_size.bytes() as u8 } } fn from_f32(f: f32) -> Self { - Scalar::Bits { bits: f.to_bits() as u128, defined: 32 } + Scalar::Bits { bits: f.to_bits() as u128, size: 4 } } fn from_f64(f: f64) -> Self { - Scalar::Bits { bits: f.to_bits() as u128, defined: 64 } + Scalar::Bits { bits: f.to_bits() as u128, size: 8 } } fn to_usize<'a, 'mir, 'tcx>(self, ecx: &rustc_mir::interpret::EvalContext<'a, 'mir, 'tcx, Evaluator<'tcx>>) -> EvalResult<'static, u64> { @@ -111,23 +101,19 @@ impl ScalarExt for Scalar { Ok(b as u64) } - fn is_null(self) -> EvalResult<'static, bool> { + fn is_null(self) -> bool { match self { - Scalar::Bits { bits, defined } => { - if defined > 0 { - Ok(bits == 0) - } else { - err!(ReadUndefBytes) - } - } - Scalar::Ptr(_) => Ok(false) + Scalar::Bits { bits, .. } => bits == 0, + Scalar::Ptr(_) => false } } fn to_bytes(self) -> EvalResult<'static, u128> { match self { - Scalar::Bits { defined: 0, .. } => err!(ReadUndefBytes), - Scalar::Bits { bits, .. } => Ok(bits), + Scalar::Bits { bits, size } => { + assert_ne!(size, 0); + Ok(bits) + }, Scalar::Ptr(_) => err!(ReadPointerAsBytes), } } @@ -155,6 +141,7 @@ pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( .to_owned(), )); } + let ptr_size = ecx.memory.pointer_size(); if let Some(start_id) = start_wrapper { let main_ret_ty = ecx.tcx.fn_sig(main_id).output(); @@ -199,7 +186,7 @@ pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( let main_ptr_ty = ecx.tcx.mk_fn_ptr(main_ty.fn_sig(ecx.tcx.tcx)); ecx.write_value( ValTy { - value: Value::Scalar(Scalar::Ptr(main_ptr)), + value: Value::Scalar(Scalar::Ptr(main_ptr).into()), ty: main_ptr_ty, }, dest, @@ -208,17 +195,16 @@ pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( // Second argument (argc): 1 let dest = ecx.eval_place(&mir::Place::Local(args.next().unwrap()))?; let ty = ecx.tcx.types.isize; - ecx.write_scalar(dest, Scalar::from_u128(1), ty)?; + ecx.write_scalar(dest, Scalar::from_int(1, ptr_size), ty)?; // FIXME: extract main source file path // Third argument (argv): &[b"foo"] let dest = ecx.eval_place(&mir::Place::Local(args.next().unwrap()))?; let ty = ecx.tcx.mk_imm_ptr(ecx.tcx.mk_imm_ptr(ecx.tcx.types.u8)); let foo = ecx.memory.allocate_bytes(b"foo\0"); - let ptr_size = ecx.memory.pointer_size(); let ptr_align = ecx.tcx.data_layout.pointer_align; let foo_ptr = ecx.memory.allocate(ptr_size, ptr_align, MemoryKind::Stack)?; - ecx.memory.write_scalar(foo_ptr.into(), ptr_align, Scalar::Ptr(foo), ptr_size, false)?; + ecx.memory.write_scalar(foo_ptr.into(), ptr_align, Scalar::Ptr(foo).into(), ptr_size, ptr_align, false)?; ecx.memory.mark_static_initialized(foo_ptr.alloc_id, Mutability::Immutable)?; ecx.write_ptr(dest, foo_ptr.into(), ty)?; @@ -228,7 +214,7 @@ pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( main_instance, main_mir.span, main_mir, - Place::from_scalar_ptr(Scalar::from_u128(1), ty::layout::Align::from_bytes(1, 1).unwrap()), + Place::from_scalar_ptr(Scalar::from_int(1, ptr_size).into(), ty::layout::Align::from_bytes(1, 1).unwrap()), StackPopCleanup::None, )?; @@ -294,7 +280,7 @@ pub fn eval_main<'a, 'tcx: 'a>( trace!("Frame {}", i); trace!(" return: {:#?}", frame.return_place); for (i, local) in frame.locals.iter().enumerate() { - if let Some(local) = local { + if let Ok(local) = local.access() { trace!(" local {}: {:?}", i, local); } } @@ -519,15 +505,16 @@ impl<'mir, 'tcx: 'mir> Machine<'mir, 'tcx> for Evaluator<'tcx> { let mut args = ecx.frame().mir.args_iter(); let usize = ecx.tcx.types.usize; + let ptr_size = ecx.memory.pointer_size(); // First argument: size let dest = ecx.eval_place(&mir::Place::Local(args.next().unwrap()))?; ecx.write_value( ValTy { - value: Value::Scalar(Scalar::from_u128(match layout.size.bytes() { - 0 => 1 as u128, - size => size as u128, - })), + value: Value::Scalar(Scalar::from_uint(match layout.size.bytes() { + 0 => 1, + size => size, + }, ptr_size).into()), ty: usize, }, dest, @@ -537,7 +524,7 @@ impl<'mir, 'tcx: 'mir> Machine<'mir, 'tcx> for Evaluator<'tcx> { let dest = ecx.eval_place(&mir::Place::Local(args.next().unwrap()))?; ecx.write_value( ValTy { - value: Value::Scalar(Scalar::from_u128(layout.align.abi().into())), + value: Value::Scalar(Scalar::from_uint(layout.align.abi(), ptr_size).into()), ty: usize, }, dest, diff --git a/src/operator.rs b/src/operator.rs index 207324cfcb00c..7be77771a7caf 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -116,9 +116,9 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: Sub => { return self.binary_op( Sub, - Scalar::Bits { bits: left.offset.bytes() as u128, defined: self.memory.pointer_size().bits() as u8 }, + Scalar::Bits { bits: left.offset.bytes() as u128, size: self.memory.pointer_size().bytes() as u8 }, self.tcx.types.usize, - Scalar::Bits { bits: right.offset.bytes() as u128, defined: self.memory.pointer_size().bits() as u8 }, + Scalar::Bits { bits: right.offset.bytes() as u128, size: self.memory.pointer_size().bytes() as u8 }, self.tcx.types.usize, ).map(Some) } @@ -182,12 +182,13 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: BitAnd if !signed => { let base_mask : u64 = !(self.memory.get(left.alloc_id)?.align.abi() - 1); let right = right as u64; + let ptr_size = self.memory.pointer_size().bytes() as u8; if right & base_mask == base_mask { // Case 1: The base address bits are all preserved, i.e., right is all-1 there (Scalar::Ptr(Pointer::new(left.alloc_id, Size::from_bytes(left.offset.bytes() & right))), false) } else if right & base_mask == 0 { // Case 2: The base address bits are all taken away, i.e., right is all-0 there - (Scalar::Bits { bits: (left.offset.bytes() & right) as u128, defined: 128 }, false) + (Scalar::Bits { bits: (left.offset.bytes() & right) as u128, size: ptr_size }, false) } else { return err!(ReadPointerAsBytes); } diff --git a/src/tls.rs b/src/tls.rs index ffcf86291590d..9f0fb2c8f62a1 100644 --- a/src/tls.rs +++ b/src/tls.rs @@ -11,7 +11,7 @@ pub trait MemoryExt<'tcx> { fn fetch_tls_dtor( &mut self, key: Option, - ) -> EvalResult<'tcx, Option<(ty::Instance<'tcx>, Scalar, TlsKey)>>; + ) -> Option<(ty::Instance<'tcx>, Scalar, TlsKey)>; } pub trait EvalContextExt<'tcx> { @@ -22,10 +22,11 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> MemoryExt<'tcx> for Memory<'a, 'mir, 'tcx, Evalu fn create_tls_key(&mut self, dtor: Option>) -> TlsKey { let new_key = self.data.next_thread_local; self.data.next_thread_local += 1; + let ptr_size = self.pointer_size(); self.data.thread_local.insert( new_key, TlsEntry { - data: Scalar::null(), + data: Scalar::null(ptr_size).into(), dtor, }, ); @@ -85,9 +86,10 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> MemoryExt<'tcx> for Memory<'a, 'mir, 'tcx, Evalu fn fetch_tls_dtor( &mut self, key: Option, - ) -> EvalResult<'tcx, Option<(ty::Instance<'tcx>, Scalar, TlsKey)>> { + ) -> Option<(ty::Instance<'tcx>, Scalar, TlsKey)> { use std::collections::Bound::*; + let ptr_size = self.pointer_size(); let thread_local = &mut self.data.thread_local; let start = match key { Some(key) => Excluded(key), @@ -96,21 +98,21 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> MemoryExt<'tcx> for Memory<'a, 'mir, 'tcx, Evalu for (&key, &mut TlsEntry { ref mut data, dtor }) in thread_local.range_mut((start, Unbounded)) { - if !data.is_null()? { + if !data.is_null() { if let Some(dtor) = dtor { let ret = Some((dtor, *data, key)); - *data = Scalar::null(); - return Ok(ret); + *data = Scalar::null(ptr_size); + return ret; } } } - Ok(None) + None } } impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, Evaluator<'tcx>> { fn run_tls_dtors(&mut self) -> EvalResult<'tcx> { - let mut dtor = self.memory.fetch_tls_dtor(None)?; + let mut dtor = self.memory.fetch_tls_dtor(None); // FIXME: replace loop by some structure that works with stepping while let Some((instance, ptr, key)) = dtor { trace!("Running TLS dtor {:?} on {:?}", instance, ptr); @@ -134,9 +136,9 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' // step until out of stackframes while self.step()? {} - dtor = match self.memory.fetch_tls_dtor(Some(key))? { + dtor = match self.memory.fetch_tls_dtor(Some(key)) { dtor @ Some(_) => dtor, - None => self.memory.fetch_tls_dtor(None)?, + None => self.memory.fetch_tls_dtor(None), }; } // FIXME: On a windows target, call `unsafe extern "system" fn on_tls_callback`. diff --git a/src/validation.rs b/src/validation.rs index 8d55f8ab0afe9..7f0abb9ae0bad 100644 --- a/src/validation.rs +++ b/src/validation.rs @@ -117,7 +117,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' Deref => Deref, Field(f, _) => Field(f, ()), Index(v) => { - let value = self.frame().get_local(v)?; + let value = self.frame().locals[v].access()?; let ty = self.tcx.tcx.types.usize; let n = self.value_to_scalar(ValTy { value, ty })?.to_usize(self)?; Index(n) @@ -480,7 +480,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' ) -> EvalResult<'tcx> { // Check alignment and non-NULLness let (_, align) = self.size_and_align_of_dst(pointee_ty, val)?; - let ptr = self.into_ptr(val)?; + let ptr = self.into_ptr(val)?.unwrap_or_err()?; self.memory.check_align(ptr, align)?; // Recurse @@ -562,7 +562,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' }; // Handle locking if len > 0 { - let ptr = ptr.to_ptr()?; + let ptr = ptr.unwrap_or_err()?.to_ptr()?; match query.mutbl { MutImmutable => { if mode.acquiring() { @@ -651,7 +651,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' } TyFnPtr(_sig) => { let ptr = self.read_place(query.place.1)?; - let ptr = self.into_ptr(ptr)?.to_ptr()?; + let ptr = self.into_ptr(ptr)?.unwrap_or_err()?.to_ptr()?; self.memory.get_fn(ptr)?; // TODO: Check if the signature matches (should be the same check as what terminator/mod.rs already does on call?). } From 7b4402746fca13ea8901ed9f440b22073123c6c9 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Wed, 8 Aug 2018 10:34:49 +0200 Subject: [PATCH 0165/3747] Add comments explaining why we do something complex for (un)init --- src/intrinsic.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/intrinsic.rs b/src/intrinsic.rs index 5c6e7f9b2dc1b..f31156a03e495 100644 --- a/src/intrinsic.rs +++ b/src/intrinsic.rs @@ -331,6 +331,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: "likely" | "unlikely" | "forget" => {} "init" => { + // 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()? { @@ -618,6 +619,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: } "uninit" => { + // 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()? { From 1ec87283259b38d0e729495953dddc206d74a52f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 14 Aug 2018 00:54:04 +0200 Subject: [PATCH 0166/3747] document and fully use rust-toolchain file --- .travis.yml | 2 ++ README.md | 27 ++++----------------------- rust-toolchain | 2 +- 3 files changed, 7 insertions(+), 24 deletions(-) diff --git a/.travis.yml b/.travis.yml index d05661a484874..bded347b825aa 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,6 +11,8 @@ 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 - export PATH=$HOME/.local/bin:$PATH - rustup target add i686-unknown-linux-gnu diff --git a/README.md b/README.md index 8c476270db1a2..d14467be91443 100644 --- a/README.md +++ b/README.md @@ -5,35 +5,16 @@ An experimental interpreter for [Rust][rust]'s [mid-level intermediate representation][mir] (MIR). This project began as part of my work for the undergraduate research course at the [University of Saskatchewan][usask]. -## Installing Rust - -I recommend that you install [rustup][rustup] and then use it to install the -current Rust nightly version: - -```sh -rustup update nightly -``` - -You should also make `nightly` the default version for your Miri directory by -running the following command while you're in it. If you don't do this, you can -run the later `cargo` commands by using `cargo +nightly` instead. - -```sh -rustup override add nightly -``` - ## Building Miri +I recommend that you install [rustup][rustup] to obtain Rust. miri comes with a +`rust-toolchain` file so rustup will automatically pick a suitable nightly +version. Then all you have to do is: + ```sh cargo build ``` -If Miri fails to build, it's likely because a change in the latest nightly -compiler broke it. You could try an older nightly with `rustup update -nightly-` where `` is a few days or weeks ago, e.g. `2016-05-20` for -May 20th. Otherwise, you could notify me in an issue or on IRC. Or, if you know -how to fix it, you could send a PR. :smile: - ## Running tests ```sh diff --git a/rust-toolchain b/rust-toolchain index bf867e0ae5b6c..8e23548106cb9 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1 +1 @@ -nightly +nightly-2018-08-03 From f0070fca1e47c836cd2c13524a37e0781fd76a3d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 14 Aug 2018 09:35:31 +0200 Subject: [PATCH 0167/3747] remove unnecessary features --- src/lib.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index b08f63e095d84..705f56d38f39d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,8 +1,6 @@ #![feature( rustc_private, catch_expr, - inclusive_range_fields, - inclusive_range_methods, )] #![cfg_attr(feature = "cargo-clippy", allow(cast_lossless))] From bed48ce5dfcda3423037e9cfcba0ba2ea5870f27 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 14 Aug 2018 09:40:00 +0200 Subject: [PATCH 0168/3747] bump toolchain --- rust-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-toolchain b/rust-toolchain index 8e23548106cb9..ec8c56dc6248b 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1 +1 @@ -nightly-2018-08-03 +nightly-2018-08-14 From 034bb25f548fff29d9caab6f0ebe232b9ba11278 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 14 Aug 2018 09:34:41 +0200 Subject: [PATCH 0169/3747] fix 'cargo miri test' for full MIR, and run it on CI --- .travis.yml | 27 ++++++++++++++------------- xargo/Xargo.toml | 7 +++++-- 2 files changed, 19 insertions(+), 15 deletions(-) diff --git a/.travis.yml b/.travis.yml index bded347b825aa..1be324cba35e8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -24,20 +24,26 @@ before_script: script: - set -e - | - # get ourselves a MIR-ful libstd - xargo/build.sh -- | - # Test plain miri + # Test and install plain miri cargo build --release --all-features && RUST_BACKTRACE=1 cargo test --release --all-features --all && cargo install --all-features --force +- | + # test that the rustc_tests binary compiles + cd rustc_tests && + cargo build --release && + cd .. +- | + # get ourselves a MIR-full libstd + xargo/build.sh && + export MIRI_SYSROOT=~/.xargo/HOST - | # Test `cargo miri` cd cargo-miri-test && if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then - MIRI_SYSROOT=~/.xargo/HOST cargo miri -q -- -Zmiri-start-fn + cargo miri -q -- -Zmiri-start-fn else - MIRI_SYSROOT=~/.xargo/HOST cargo miri -q -- -Zmiri-start-fn >stdout.real 2>stderr.real && + cargo miri -q -- -Zmiri-start-fn >stdout.real 2>stderr.real && cat stdout.real stderr.real && # Test `cargo miri` output. Not on mac because output redirecting doesn't # work. There is no error. It just stops CI. @@ -45,16 +51,11 @@ script: diff -u stderr.ref stderr.real fi && # Test `cargo miri test` - #cargo miri test && + cargo miri test && cd .. - | # and run all tests with full mir - MIRI_SYSROOT=~/.xargo/HOST cargo test --release -- | - # test that the rustc_tests binary compiles - cd rustc_tests && - cargo build --release && - cd .. + cargo test --release notifications: email: on_success: never diff --git a/xargo/Xargo.toml b/xargo/Xargo.toml index 4b650b97de56a..c022837a5e61c 100644 --- a/xargo/Xargo.toml +++ b/xargo/Xargo.toml @@ -1,2 +1,5 @@ -[dependencies] -std = {features = ["panic_unwind", "jemalloc", "backtrace"]} +[dependencies.std] +features = ["panic_unwind", "jemalloc", "backtrace"] + +[dependencies.test] +stage = 1 From c4c8c60279aa58616412289c0d832251b62d7ad3 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 14 Aug 2018 09:35:00 +0200 Subject: [PATCH 0170/3747] update README: 'cargo miri' with full MIR; consistent capitalization --- README.md | 40 +++++++++++++++++++++------------------- 1 file changed, 21 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index d14467be91443..314e27de0aa23 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ undergraduate research course at the [University of Saskatchewan][usask]. ## Building Miri -I recommend that you install [rustup][rustup] to obtain Rust. miri comes with a +I recommend that you install [rustup][rustup] to obtain Rust. Miri comes with a `rust-toolchain` file so rustup will automatically pick a suitable nightly version. Then all you have to do is: @@ -15,33 +15,25 @@ version. Then all you have to do is: cargo build ``` -## Running tests +## Running Miri ```sh cargo run tests/run-pass/vecs.rs # Or whatever test you like. ``` -## Running miri on your own project('s test suite) - -Install miri as a cargo subcommand with `cargo install --debug`. -Then, inside your own project, use `cargo +nightly miri` to run your project, if it is -a bin project, or run `cargo +nightly miri test` to run all tests in your project -through miri. - -## Running miri with full libstd +## Running Miri with full libstd Per default libstd does not contain the MIR of non-polymorphic functions. When -miri hits a call to such a function, execution terminates. To fix this, it is +Miri hits a call to such a function, execution terminates. To fix this, it is possible to compile libstd with full MIR: ```sh rustup component add rust-src cargo install xargo -cd xargo/ -RUSTFLAGS='-Zalways-encode-mir' xargo build +xargo/build.sh ``` -Now you can run miri against the libstd compiled by xargo: +Now you can run Miri against the libstd compiled by xargo: ```sh MIRI_SYSROOT=~/.xargo/HOST cargo run tests/run-pass-fullmir/hashmap.rs @@ -50,13 +42,23 @@ MIRI_SYSROOT=~/.xargo/HOST cargo run tests/run-pass-fullmir/hashmap.rs Notice that you will have to re-run the last step of the preparations above when your toolchain changes (e.g., when you update the nightly). -You can also set `-Zmiri-start-fn` to make miri start evaluation with the +You can also set `-Zmiri-start-fn` to make Miri start evaluation with the `start_fn` lang item, instead of starting at the `main` function. +## Running Miri on your own project('s test suite) + +Install Miri as a cargo subcommand with `cargo install --all-features`, and install +a full libstd as described above. + +Then, inside your own project, use `MIRI_SYSROOT=~/.xargo/HOST cargo +nightly +miri` to run your project, if it is a bin project, or run +`MIRI_SYSROOT=~/.xargo/HOST cargo +nightly miri test` to run all tests in your +project through Miri. + ## Development and Debugging -Since the heart of miri (the main interpreter engine) lives in rustc, working on -miri will often require using a locally built rustc. This includes getting a +Since the heart of Miri (the main interpreter engine) lives in rustc, working on +Miri will often require using a locally built rustc. This includes getting a trace of the execution, as distributed rustc has `trace!` disabled. The first-time setup for a local rustc looks as follows: @@ -68,12 +70,12 @@ cp config.toml.example config.toml ./x.py build src/rustc # You may have to change the architecture in the next command rustup toolchain link custom build/x86_64-unknown-linux-gnu/stage2 -# Now cd to your miri directory +# Now cd to your Miri directory rustup override set custom ``` The `build` step can take 30 minutes and more. -Now you can `cargo build` miri, and you can `cargo test --tests`. (`--tests` +Now you can `cargo build` Miri, and you can `cargo test --tests`. (`--tests` is needed to skip doctests because we have not built rustdoc for your custom toolchain.) You can also set `RUST_LOG=rustc_mir::interpret=trace` as environment variable to get a step-by-step trace. From ad5403e2e5d071583d741701f00f56e9a4336f1b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 14 Aug 2018 15:58:29 +0200 Subject: [PATCH 0171/3747] fix layout in discriminant_value --- src/intrinsic.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/intrinsic.rs b/src/intrinsic.rs index f31156a03e495..cd953ba7c5693 100644 --- a/src/intrinsic.rs +++ b/src/intrinsic.rs @@ -250,8 +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)?; - let ptr_size = self.memory.pointer_size(); - self.write_scalar(dest, Scalar::from_uint(discr_val, ptr_size), 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" | From 30cef4e9a1fe0312803357f4141ceea8700c770b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 14 Aug 2018 16:45:18 +0200 Subject: [PATCH 0172/3747] fix rustc_tests --- rustc_tests/Cargo.lock | 8 -------- rustc_tests/src/main.rs | 5 +++-- 2 files changed, 3 insertions(+), 10 deletions(-) diff --git a/rustc_tests/Cargo.lock b/rustc_tests/Cargo.lock index 0154ecc2ccbdc..c206ecd644928 100644 --- a/rustc_tests/Cargo.lock +++ b/rustc_tests/Cargo.lock @@ -51,11 +51,6 @@ name = "lazy_static" version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "lazy_static" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "libc" version = "0.2.30" @@ -91,9 +86,7 @@ version = "0.1.0" dependencies = [ "byteorder 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -226,7 +219,6 @@ dependencies = [ "checksum env_logger 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)" = "0e6e40ebb0e66918a37b38c7acab4e10d299e0463fe2af5d29b9cc86710cfd2a" "checksum humantime 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0484fda3e7007f2a4a0d9c3a703ca38c71c54c55602ce4660c419fd32e188c9e" "checksum lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "3b37545ab726dd833ec6420aaba8231c5b320814b9029ad585555d2a03e94fbf" -"checksum lazy_static 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e6412c5e2ad9584b0b8e979393122026cdd6d2a80b933f890dcd694ddbe73739" "checksum libc 0.2.30 (registry+https://github.com/rust-lang/crates.io-index)" = "2370ca07ec338939e356443dac2296f581453c35fe1e3a3ed06023c49435f915" "checksum log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "89f010e843f2b1a31dbd316b3b8d443758bc634bed37aabade59c686d644e0a2" "checksum memchr 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1dbccc0e46f1ea47b9f17e6d67c5a96bd27030519c519c9c91327e31275a47b4" diff --git a/rustc_tests/src/main.rs b/rustc_tests/src/main.rs index 1891e3dba103d..969888ec991ea 100644 --- a/rustc_tests/src/main.rs +++ b/rustc_tests/src/main.rs @@ -2,6 +2,7 @@ extern crate miri; extern crate getopts; extern crate rustc; +extern crate rustc_metadata; extern crate rustc_driver; extern crate rustc_errors; extern crate rustc_codegen_utils; @@ -14,7 +15,7 @@ use std::io; use rustc::session::Session; -use rustc::middle::cstore::CrateStore; +use rustc_metadata::cstore::CStore; use rustc_driver::{Compilation, CompilerCalls, RustcDefaultCalls}; use rustc_driver::driver::{CompileState, CompileController}; use rustc::session::config::{self, Input, ErrorOutputType}; @@ -56,7 +57,7 @@ impl<'a> CompilerCalls<'a> for MiriCompilerCalls { trans: &CodegenBackend, matches: &getopts::Matches, sess: &Session, - cstore: &CrateStore, + cstore: &CStore, input: &Input, odir: &Option, ofile: &Option, From 354ec11c3e1e29a2ee2241f74d8fcb4f5376b5d2 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 14 Aug 2018 17:19:46 +0200 Subject: [PATCH 0173/3747] try using types with lower alignment, maybe that helps for Windows --- tests/compile-fail/transmute_fat.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/compile-fail/transmute_fat.rs b/tests/compile-fail/transmute_fat.rs index dad5f4df2da3c..3e3bf51c3f277 100644 --- a/tests/compile-fail/transmute_fat.rs +++ b/tests/compile-fail/transmute_fat.rs @@ -4,12 +4,12 @@ fn main() { #[cfg(target_pointer_width="64")] let bad = unsafe { - std::mem::transmute::<&[u8], u128>(&[1u8]) + std::mem::transmute::<&[u8], [u8; 16]>(&[1u8]) }; #[cfg(target_pointer_width="32")] let bad = unsafe { - std::mem::transmute::<&[u8], u64>(&[1u8]) + std::mem::transmute::<&[u8], [u8; 8]>(&[1u8]) }; - let _ = bad + 1; //~ ERROR constant evaluation error + let _ = bad[0] + bad[bad.len()-1]; //~ ERROR constant evaluation error //~^ NOTE a raw memory access tried to access part of a pointer value as raw bytes } From e10d83c8bb3436398ef47183e15d4ab3a2036547 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 14 Aug 2018 18:44:31 +0200 Subject: [PATCH 0174/3747] fix windows hooks --- src/fn_call.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index 11b0ae345c7fd..b475837a6e528 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -634,14 +634,16 @@ 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_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 let ptr_size = self.memory.pointer_size(); self.write_scalar(dest, Scalar::from_int(0, ptr_size), dest_ty)?; From 7c73df9985871a5a76c55d48f1dc0797111181be Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 14 Aug 2018 17:21:02 +0200 Subject: [PATCH 0175/3747] avoid recompiling miri for 2nd test run; avoid unreadable output due to backtraces also some travis config cleanup --- .travis.yml | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/.travis.yml b/.travis.yml index 1be324cba35e8..7f346b5104c27 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,32 +1,32 @@ language: rust cache: cargo +rust: +- nightly os: -- osx - linux +- osx -rust: -- nightly before_script: # mac os weirdness (https://github.com/travis-ci/travis-ci/issues/6307) - curl -sSL https://rvm.io/mpapis.asc | gpg --import - - rvm get stable # in a cronjob, use latest (not pinned) nightly - if [ "$TRAVIS_EVENT_TYPE" = cron ]; then rustup override set nightly; fi -# actual travis code +# prepare - export PATH=$HOME/.local/bin:$PATH - rustup target add i686-unknown-linux-gnu - rustup target add i686-pc-windows-gnu - rustup target add i686-pc-windows-msvc - rustup component add rust-src - cargo install xargo || echo "skipping xargo install" -- export RUST_SYSROOT=$HOME/rust + script: - set -e - | # Test and install plain miri cargo build --release --all-features && - RUST_BACKTRACE=1 cargo test --release --all-features --all && + cargo test --release --all-features && cargo install --all-features --force - | # test that the rustc_tests binary compiles @@ -55,7 +55,8 @@ script: cd .. - | # and run all tests with full mir - cargo test --release + cargo test --release --all-features + notifications: email: on_success: never From 1fbf998b652af1c3e1cf888a9dfceb9eaeecc475 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 14 Aug 2018 19:00:18 +0200 Subject: [PATCH 0176/3747] Fix remaining windows hooks --- appveyor.yml | 2 +- src/fn_call.rs | 12 ++++-------- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index 6aee7e75a956e..14532416978c8 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -26,12 +26,12 @@ install: - cd xargo - set RUSTFLAGS=-Zalways-encode-mir -Zmir-emit-validate=1 - xargo build - - set RUSTFLAGS= - cd .. build: false test_script: + - set RUSTFLAGS=-g - set RUST_BACKTRACE=1 - cargo build --release - cargo test --release diff --git a/src/fn_call.rs b/src/fn_call.rs index b475837a6e528..509119beb35c4 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -645,13 +645,11 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' "GetProcAddress" | "TryEnterCriticalSection" => { // pretend these do not exist/nothing happened, by returning zero - let ptr_size = self.memory.pointer_size(); - self.write_scalar(dest, Scalar::from_int(0, ptr_size), dest_ty)?; + self.write_scalar(dest, Scalar::from_int(0, dest_layout.size), dest_ty)?; }, "GetLastError" => { // this is c::ERROR_CALL_NOT_IMPLEMENTED - let ptr_size = self.memory.pointer_size(); - self.write_scalar(dest, Scalar::from_int(120, ptr_size), dest_ty)?; + self.write_scalar(dest, Scalar::from_int(120, dest_layout.size), dest_ty)?; }, // Windows TLS @@ -665,8 +663,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' if dest_layout.size.bits() < 128 && key >= (1u128 << dest_layout.size.bits() as u128) { return err!(OutOfTls); } - let ptr_size = self.memory.pointer_size(); - self.write_scalar(dest, Scalar::from_uint(key, ptr_size), dest_layout.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()?; @@ -677,10 +674,9 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' let key = self.value_to_scalar(args[0])?.to_bytes()?; let new_ptr = self.into_ptr(args[1].value)?.unwrap_or_err()?; self.memory.store_tls(key, new_ptr)?; - let ptr_size = self.memory.pointer_size(); // Return success (1) - self.write_scalar(dest, Scalar::from_int(1, ptr_size), dest_ty)?; + self.write_scalar(dest, Scalar::from_int(1, dest_layout.size), dest_ty)?; } // We can't execute anything else From 93fef9a6a2958a0cef2cef64afd1ffa478aef5fe Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 14 Aug 2018 09:51:31 +0200 Subject: [PATCH 0177/3747] reenable an old test --- tests/run-pass/intrinsics.rs | 0 tests/run-pass/{packed_struct.rs_broken => packed_struct.rs} | 2 -- 2 files changed, 2 deletions(-) mode change 100755 => 100644 tests/run-pass/intrinsics.rs rename tests/run-pass/{packed_struct.rs_broken => packed_struct.rs} (91%) diff --git a/tests/run-pass/intrinsics.rs b/tests/run-pass/intrinsics.rs old mode 100755 new mode 100644 diff --git a/tests/run-pass/packed_struct.rs_broken b/tests/run-pass/packed_struct.rs similarity index 91% rename from tests/run-pass/packed_struct.rs_broken rename to tests/run-pass/packed_struct.rs index e0387a5f405f3..7bd04c44438c2 100644 --- a/tests/run-pass/packed_struct.rs_broken +++ b/tests/run-pass/packed_struct.rs @@ -1,5 +1,3 @@ -// FIXME: We have to disable this, force_allocation fails. -// TODO: I think this can be triggered even without validation. // compile-flags: -Zmir-emit-validate=0 #![allow(dead_code)] #![feature(unsize, coerce_unsized)] From 2b40d39c1e26c0964180fde51c5bfcf9247a70a8 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 14 Aug 2018 20:00:18 +0200 Subject: [PATCH 0178/3747] support computing the remainder of a ptr, if covered by alignment --- src/operator.rs | 25 ++++++++++++++++++++--- tests/compile-fail/pointer_byte_read_1.rs | 2 +- tests/compile-fail/ptr_bitops2.rs | 5 +++++ tests/compile-fail/ptr_rem.rs | 5 +++++ tests/run-pass/ptr_int_ops.rs | 20 ++++++++++++++++++ 5 files changed, 53 insertions(+), 4 deletions(-) create mode 100644 tests/compile-fail/ptr_bitops2.rs create mode 100644 tests/compile-fail/ptr_rem.rs create mode 100644 tests/run-pass/ptr_int_ops.rs diff --git a/src/operator.rs b/src/operator.rs index 7be77771a7caf..ab1701c6cbf17 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -130,8 +130,8 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: err!(InvalidPointerMath) } } - // These work if one operand is a pointer, the other an integer - Add | BitAnd | Sub + // These work if the left operand is a pointer, the right an integer + Add | BitAnd | Sub | Rem if left_kind == right_kind && (left_kind == usize || left_kind == isize) && left.is_ptr() && right.is_bits() => { // Cast to i128 is fine as we checked the kind to be ptr-sized @@ -142,6 +142,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: left_kind == isize, ).map(Some) } + // Commutative operators also work if the integer is on the left Add | BitAnd if left_kind == right_kind && (left_kind == usize || left_kind == isize) && left.is_bits() && right.is_ptr() => { @@ -180,7 +181,8 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: map_to_primval(left.overflowing_offset(Size::from_bytes(right as u64), self)), BitAnd if !signed => { - let base_mask : u64 = !(self.memory.get(left.alloc_id)?.align.abi() - 1); + let ptr_base_align = self.memory.get(left.alloc_id)?.align.abi(); + let base_mask : u64 = !(ptr_base_align - 1); let right = right as u64; let ptr_size = self.memory.pointer_size().bytes() as u8; if right & base_mask == base_mask { @@ -194,6 +196,23 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: } } + Rem if !signed => { + // Doing modulo a multiple of the alignment is allowed + let ptr_base_align = self.memory.get(left.alloc_id)?.align.abi(); + let right = right as u64; + let ptr_size = self.memory.pointer_size().bytes() as u8; + if right == 1 { + // modulo 1 is always 0 + (Scalar::Bits { bits: 0, size: ptr_size }, false) + } else if right % ptr_base_align == 0 { + // the base address would be cancelled out by the modulo operation, so we can + // just take the modulo of the offset + (Scalar::Bits { bits: (left.offset.bytes() % right) as u128, size: ptr_size }, false) + } else { + return err!(ReadPointerAsBytes); + } + } + _ => { let msg = format!("unimplemented binary op on pointer {:?}: {:?}, {:?} ({})", bin_op, left, right, if signed { "signed" } else { "unsigned" }); return err!(Unimplemented(msg)); diff --git a/tests/compile-fail/pointer_byte_read_1.rs b/tests/compile-fail/pointer_byte_read_1.rs index b3aaec759ce02..4cfdfb62e27f5 100644 --- a/tests/compile-fail/pointer_byte_read_1.rs +++ b/tests/compile-fail/pointer_byte_read_1.rs @@ -3,6 +3,6 @@ fn main() { let y = &x; let z = &y as *const &i32 as *const usize; let ptr_bytes = unsafe { *z }; // the actual deref is fine, because we read the entire pointer at once - let _ = ptr_bytes % 432; //~ ERROR constant evaluation error + let _ = ptr_bytes / 432; //~ ERROR constant evaluation error //~^ NOTE tried to access part of a pointer value as raw bytes } diff --git a/tests/compile-fail/ptr_bitops2.rs b/tests/compile-fail/ptr_bitops2.rs new file mode 100644 index 0000000000000..233c9a733c999 --- /dev/null +++ b/tests/compile-fail/ptr_bitops2.rs @@ -0,0 +1,5 @@ +fn main() { + let val = 13usize; + let addr = &val as *const _ as usize; + let _ = addr & 13; //~ ERROR access part of a pointer value as raw bytes +} diff --git a/tests/compile-fail/ptr_rem.rs b/tests/compile-fail/ptr_rem.rs new file mode 100644 index 0000000000000..26fba9b82c533 --- /dev/null +++ b/tests/compile-fail/ptr_rem.rs @@ -0,0 +1,5 @@ +fn main() { + let val = 13usize; + let addr = &val as *const _ as usize; + let _ = addr % 2; //~ ERROR access part of a pointer value as raw bytes +} diff --git a/tests/run-pass/ptr_int_ops.rs b/tests/run-pass/ptr_int_ops.rs new file mode 100644 index 0000000000000..9a29c2d30837d --- /dev/null +++ b/tests/run-pass/ptr_int_ops.rs @@ -0,0 +1,20 @@ +fn main() { + let v = [1i16, 2]; + let x = &v[1] as *const i16 as usize; + // arithmetic + let _y = x + 4; + let _y = 4 + x; + let _y = x - 2; + // bit-operations, covered by alignment + assert_eq!(x & 1, 0); + assert_eq!(x & 0, 0); + assert_eq!(1 & (x+1), 1); + let _y = !1 & x; + let _y = !0 & x; + let _y = x & !1; + // remainder, covered by alignment + assert_eq!(x % 2, 0); + assert_eq!((x+1) % 2, 1); + // remainder with 1 is always 0 + assert_eq!(x % 1, 0); +} From 04b925135d2e2078340618c7fae1ac776b9d9028 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 14 Aug 2018 12:16:29 +0200 Subject: [PATCH 0179/3747] fix modulo logic --- src/operator.rs | 5 +++-- tests/compile-fail/ptr_rem.rs | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/operator.rs b/src/operator.rs index ab1701c6cbf17..ef297397fc5e1 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -197,14 +197,15 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: } Rem if !signed => { - // Doing modulo a multiple of the alignment is allowed + // Doing modulo a divisor of the alignment is allowed. + // (Intuition: Modulo a divisor leaks less information.) let ptr_base_align = self.memory.get(left.alloc_id)?.align.abi(); let right = right as u64; let ptr_size = self.memory.pointer_size().bytes() as u8; if right == 1 { // modulo 1 is always 0 (Scalar::Bits { bits: 0, size: ptr_size }, false) - } else if right % ptr_base_align == 0 { + } else if ptr_base_align % right == 0 { // the base address would be cancelled out by the modulo operation, so we can // just take the modulo of the offset (Scalar::Bits { bits: (left.offset.bytes() % right) as u128, size: ptr_size }, false) diff --git a/tests/compile-fail/ptr_rem.rs b/tests/compile-fail/ptr_rem.rs index 26fba9b82c533..8a3665872f7cb 100644 --- a/tests/compile-fail/ptr_rem.rs +++ b/tests/compile-fail/ptr_rem.rs @@ -1,5 +1,5 @@ fn main() { let val = 13usize; let addr = &val as *const _ as usize; - let _ = addr % 2; //~ ERROR access part of a pointer value as raw bytes + let _ = addr % 16; //~ ERROR access part of a pointer value as raw bytes } From bfda0a0a90bc37f683e99bbff75fbf59abe48991 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 14 Aug 2018 18:51:15 +0200 Subject: [PATCH 0180/3747] add a scary test case --- tests/run-pass/transmute_fat.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 tests/run-pass/transmute_fat.rs diff --git a/tests/run-pass/transmute_fat.rs b/tests/run-pass/transmute_fat.rs new file mode 100644 index 0000000000000..ec887902d0542 --- /dev/null +++ b/tests/run-pass/transmute_fat.rs @@ -0,0 +1,10 @@ +fn main() { + // If we are careful, we can exploit data layout... + let raw = unsafe { + std::mem::transmute::<&[u8], [usize; 2]>(&[42]) + }; + let ptr = raw[0] + raw[1]; + let ptr = ptr as *const u8; + // The pointer is one-past-the end, but we decrement it into bounds before using it + assert_eq!(unsafe { *ptr.offset(-1) }, 42); +} From 98a5b24ef7eb05ae52d63ce9e050d6ac144ba345 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 14 Aug 2018 20:09:07 +0200 Subject: [PATCH 0181/3747] test some more things around packed structs --- tests/run-pass/dst-struct.rs | 4 ++-- tests/run-pass/packed_struct.rs | 39 +++++++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+), 2 deletions(-) diff --git a/tests/run-pass/dst-struct.rs b/tests/run-pass/dst-struct.rs index 932b571eccdbb..0820614ab5c81 100644 --- a/tests/run-pass/dst-struct.rs +++ b/tests/run-pass/dst-struct.rs @@ -65,9 +65,9 @@ impl ToBar for Bar { pub fn main() { // With a vec of ints. - let f1 = Fat { f1: 5, f2: "some str", ptr: [1, 2, 3] }; + let f1 : Fat<[isize; 3]> = Fat { f1: 5, f2: "some str", ptr: [1, 2, 3] }; foo(&f1); - let f2 = &f1; + let f2 : &Fat<[isize; 3]> = &f1; foo(f2); let f3: &Fat<[isize]> = f2; foo(f3); diff --git a/tests/run-pass/packed_struct.rs b/tests/run-pass/packed_struct.rs index 7bd04c44438c2..e10781e656058 100644 --- a/tests/run-pass/packed_struct.rs +++ b/tests/run-pass/packed_struct.rs @@ -45,6 +45,43 @@ fn test_unsizing() { let _unused = &arr_unaligned; // forcing an allocation, which could also yield "unaligned write"-errors } +fn test_drop() { + struct Wrap(u32); + impl Drop for Wrap { + fn drop(&mut self) { + // Do an (aligned) load + let _test = self.0; + // For the fun of it, test alignment + assert_eq!(&self.0 as *const _ as usize % std::mem::align_of::(), 0); + } + } + + #[repr(packed,C)] + struct Packed { + f1: u8, // this should move the second field to something not very aligned + f2: T, + } + + let p = Packed { f1: 42, f2: Wrap(23) }; + drop(p); +} + +fn test_inner_packed() { + // Even if just the inner struct is packed, accesses to the outer field can get unaligned. + // Make sure that works. + #[repr(packed)] + #[derive(Clone,Copy)] + struct Inner(u32); + + #[derive(Clone,Copy)] + struct Outer(u8, Inner); + + let o = Outer(0, Inner(42)); + let _x = o.1; + let _y = (o.1).0; + let _o2 = o.clone(); +} + fn main() { let mut x = S { a: 42, @@ -64,4 +101,6 @@ fn main() { test(Test2 { x: 0, other: &Test1 { x: 0, other: &42 }}); test_unsizing(); + test_drop(); + test_inner_packed(); } From 1179d4f8a4286f8ad0555b56ce65871f242a5d5b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 14 Aug 2018 20:25:56 +0200 Subject: [PATCH 0182/3747] fix int ptr ops on 32bit --- src/operator.rs | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/src/operator.rs b/src/operator.rs index ef297397fc5e1..078cbc12369f3 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -20,7 +20,7 @@ pub trait EvalContextExt<'tcx> { &self, bin_op: mir::BinOp, left: Pointer, - right: i128, + right: u128, signed: bool, ) -> EvalResult<'tcx, (Scalar, bool)>; } @@ -138,7 +138,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: self.ptr_int_arithmetic( bin_op, left.to_ptr()?, - right.to_bits(self.memory.pointer_size())? as i128, + right.to_bits(self.memory.pointer_size())?, left_kind == isize, ).map(Some) } @@ -150,7 +150,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: self.ptr_int_arithmetic( bin_op, right.to_ptr()?, - left.to_bits(self.memory.pointer_size())? as i128, + left.to_bits(self.memory.pointer_size())?, left_kind == isize, ).map(Some) } @@ -162,7 +162,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: &self, bin_op: mir::BinOp, left: Pointer, - right: i128, + right: u128, signed: bool, ) -> EvalResult<'tcx, (Scalar, bool)> { use rustc::mir::BinOp::*; @@ -174,23 +174,31 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: Ok(match bin_op { Sub => // The only way this can overflow is by underflowing, so signdeness of the right operands does not matter - map_to_primval(left.overflowing_signed_offset(-right, self)), + map_to_primval(left.overflowing_signed_offset(-(right as i128), self)), Add if signed => - map_to_primval(left.overflowing_signed_offset(right, self)), + map_to_primval(left.overflowing_signed_offset(right as i128, self)), Add if !signed => map_to_primval(left.overflowing_offset(Size::from_bytes(right as u64), self)), BitAnd if !signed => { let ptr_base_align = self.memory.get(left.alloc_id)?.align.abi(); - let base_mask : u64 = !(ptr_base_align - 1); - let right = right as u64; + let base_mask = { + // FIXME: Use interpret::truncate, once that takes a Size instead of a Layout + let shift = 128 - self.memory.pointer_size().bits(); + let value = !(ptr_base_align as u128 - 1); + // truncate (shift left to drop out leftover values, shift right to fill with zeroes) + (value << shift) >> shift + }; let ptr_size = self.memory.pointer_size().bytes() as u8; + trace!("Ptr BitAnd, align {}, operand {:#010x}, base_mask {:#010x}", + ptr_base_align, right, base_mask); 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) + let offset = (left.offset.bytes() as u128 & right) as u64; + (Scalar::Ptr(Pointer::new(left.alloc_id, Size::from_bytes(offset))), 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, size: ptr_size }, false) + (Scalar::Bits { bits: (left.offset.bytes() as u128) & right, size: ptr_size }, false) } else { return err!(ReadPointerAsBytes); } From 51dbb5aa29f2ba8f0e694291299be1c22c5e6419 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 14 Aug 2018 20:57:58 +0200 Subject: [PATCH 0183/3747] tweak test config in Cargo.toml --- Cargo.toml | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 7773bd3812f12..3f7aabe03ce27 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,15 +10,19 @@ version = "0.1.0" build = "build.rs" default-run = "miri" +[lib] +test = true # we have unit tests +doctest = false # but no doc tests + [[bin]] -doc = false name = "miri" -path = "src/bin/miri.rs" +test = false # we have no unit tests +doctest = false # and no doc tests [[bin]] -doc = false name = "cargo-miri" -path = "src/bin/cargo-miri.rs" +test = false # we have no unit tests +doctest = false # and no doc tests required-features = ["cargo_miri"] [dependencies] From 259cc6e3dccdf7dd7f9c8e2052c6dea19fe066d9 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 15 Aug 2018 21:01:40 +0200 Subject: [PATCH 0184/3747] rustup for big refactor; kill most of validation --- src/fn_call.rs | 295 ++++---- src/helpers.rs | 227 +++--- src/intrinsic.rs | 474 ++++++------- src/lib.rs | 226 ++---- src/locks.rs | 320 +-------- src/operator.rs | 83 ++- src/range_map.rs | 2 + src/tls.rs | 6 +- src/validation.rs | 803 ---------------------- tests/run-pass/atomic-compare_exchange.rs | 18 +- 10 files changed, 576 insertions(+), 1878 deletions(-) delete mode 100644 src/validation.rs diff --git a/src/fn_call.rs b/src/fn_call.rs index 509119beb35c4..559f3adb90f13 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -1,8 +1,7 @@ -use rustc::ty::{self, Ty}; -use rustc::ty::layout::{self, Align, LayoutOf, Size}; +use rustc::ty; +use rustc::ty::layout::{Align, LayoutOf, Size}; use rustc::hir::def_id::{DefId, CRATE_DEF_INDEX}; use rustc::mir; -use rustc_data_structures::indexed_vec::Idx; use syntax::attr; use syntax::codemap::Span; @@ -14,57 +13,12 @@ use tls::MemoryExt; use super::memory::MemoryKind; -fn write_discriminant_value<'a, 'mir, 'tcx: 'a + 'mir>( - ecx: &mut EvalContext<'a, 'mir, 'tcx, super::Evaluator<'tcx>>, - dest_ty: Ty<'tcx>, - dest: Place, - variant_index: usize, - ) -> EvalResult<'tcx> { - let layout = ecx.layout_of(dest_ty)?; - - match layout.variants { - layout::Variants::Single { index } => { - if index != variant_index { - // If the layout of an enum is `Single`, all - // other variants are necessarily uninhabited. - assert_eq!(layout.for_variant(&ecx, variant_index).abi, - layout::Abi::Uninhabited); - } - } - layout::Variants::Tagged { .. } => { - let discr_val = dest_ty.ty_adt_def().unwrap() - .discriminant_for_variant(*ecx.tcx, variant_index) - .val; - - let (discr_dest, discr) = ecx.place_field(dest, mir::Field::new(0), layout)?; - ecx.write_scalar(discr_dest, Scalar::from_uint(discr_val, discr.size), discr.ty)?; - } - layout::Variants::NicheFilling { - dataful_variant, - ref niche_variants, - niche_start, - .. - } => { - if variant_index != dataful_variant { - let (niche_dest, niche) = - 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_uint(niche_value, niche.size), niche.ty)?; - } - } - } - - Ok(()) - } - pub trait EvalContextExt<'tcx> { fn call_foreign_item( &mut self, def_id: DefId, - args: &[ValTy<'tcx>], - dest: Place, - dest_ty: Ty<'tcx>, + args: &[OpTy<'tcx>], + dest: PlaceTy<'tcx>, dest_block: mir::BasicBlock, ) -> EvalResult<'tcx>; @@ -73,49 +27,46 @@ pub trait EvalContextExt<'tcx> { fn call_missing_fn( &mut self, instance: ty::Instance<'tcx>, - destination: Option<(Place, mir::BasicBlock)>, - args: &[ValTy<'tcx>], - sig: ty::FnSig<'tcx>, + destination: Option<(PlaceTy<'tcx>, mir::BasicBlock)>, + args: &[OpTy<'tcx>], path: String, ) -> EvalResult<'tcx>; fn eval_fn_call( &mut self, instance: ty::Instance<'tcx>, - destination: Option<(Place, mir::BasicBlock)>, - args: &[ValTy<'tcx>], + destination: Option<(PlaceTy<'tcx>, mir::BasicBlock)>, + args: &[OpTy<'tcx>], span: Span, - sig: ty::FnSig<'tcx>, ) -> EvalResult<'tcx, bool>; - fn write_null(&mut self, dest: Place, dest_layout: TyLayout<'tcx>) -> EvalResult<'tcx>; + fn write_null(&mut self, dest: PlaceTy<'tcx>) -> EvalResult<'tcx>; } impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super::Evaluator<'tcx>> { fn eval_fn_call( &mut self, instance: ty::Instance<'tcx>, - destination: Option<(Place, mir::BasicBlock)>, - args: &[ValTy<'tcx>], + destination: Option<(PlaceTy<'tcx>, mir::BasicBlock)>, + args: &[OpTy<'tcx>], span: Span, - sig: ty::FnSig<'tcx>, ) -> EvalResult<'tcx, bool> { - trace!("eval_fn_call: {:#?}, {:#?}", instance, destination); + trace!("eval_fn_call: {:#?}, {:?}", instance, destination.map(|(place, bb)| (*place, bb))); let def_id = instance.def_id(); let item_path = self.tcx.absolute_item_path_str(def_id); match &*item_path { "std::sys::unix::thread::guard::init" | "std::sys::unix::thread::guard::current" => { // Return None, as it doesn't make sense to return Some, because miri detects stack overflow itself. - let ret_ty = sig.output(); - match ret_ty.sty { + let (return_place, return_to_block) = destination.unwrap(); + match return_place.layout.ty.sty { ty::TyAdt(ref adt_def, _) => { assert!(adt_def.is_enum(), "Unexpected return type for {}", item_path); let none_variant_index = adt_def.variants.iter().position(|def| { def.name.as_str() == "None" }).expect("No None variant"); - let (return_place, return_to_block) = destination.unwrap(); - write_discriminant_value(self, ret_ty, return_place, none_variant_index)?; + + self.write_discriminant_value(none_variant_index, return_place)?; self.goto_block(return_to_block); return Ok(true); } @@ -135,11 +86,9 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' // FIXME: return a real value in case the target allocation has an // alignment bigger than the one requested let n = u128::max_value(); - let amt = 128 - self.memory.pointer_size().bytes() * 8; let (dest, return_to_block) = destination.unwrap(); - let ty = self.tcx.types.usize; - let ptr_size = self.memory.pointer_size(); - self.write_scalar(dest, Scalar::from_uint((n << amt) >> amt, ptr_size), ty)?; + let n = self.truncate(n, dest.layout); + self.write_scalar(Scalar::from_uint(n, dest.layout.size), dest)?; self.goto_block(return_to_block); return Ok(true); } @@ -151,7 +100,6 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' instance, destination, args, - sig, path, )?; return Ok(true); @@ -160,8 +108,8 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' }; let (return_place, return_to_block) = match destination { - Some((place, block)) => (place, StackPopCleanup::Goto(block)), - None => (Place::undef(), StackPopCleanup::None), + Some((place, block)) => (*place, StackPopCleanup::Goto(block)), + None => (Place::null(&self), StackPopCleanup::None), }; self.push_stack_frame( @@ -178,9 +126,8 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' fn call_foreign_item( &mut self, def_id: DefId, - args: &[ValTy<'tcx>], - dest: Place, - dest_ty: Ty<'tcx>, + args: &[OpTy<'tcx>], + dest: PlaceTy<'tcx>, dest_block: mir::BasicBlock, ) -> EvalResult<'tcx> { let attrs = self.tcx.get_attrs(def_id); @@ -188,22 +135,21 @@ 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)?; + let size = self.read_scalar(args[0])?.to_usize(&self)?; if size == 0 { - self.write_null(dest, dest_layout)?; + self.write_null(dest)?; } else { let align = self.tcx.data_layout.pointer_align; let ptr = self.memory.allocate(Size::from_bytes(size), align, MemoryKind::C.into())?; - self.write_scalar(dest, Scalar::Ptr(ptr), dest_ty)?; + self.write_scalar(Scalar::Ptr(ptr), dest)?; } } "free" => { - let ptr = self.into_ptr(args[0].value)?.unwrap_or_err()?; + let ptr = self.read_scalar(args[0])?.not_undef()?; if !ptr.is_null() { self.memory.deallocate( ptr.to_ptr()?, @@ -214,8 +160,8 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' } "__rust_alloc" => { - let size = self.value_to_scalar(args[0])?.to_usize(self)?; - let align = self.value_to_scalar(args[1])?.to_usize(self)?; + let size = self.read_scalar(args[0])?.to_usize(&self)?; + let align = self.read_scalar(args[1])?.to_usize(&self)?; if size == 0 { return err!(HeapAllocZeroBytes); } @@ -225,11 +171,11 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' let ptr = self.memory.allocate(Size::from_bytes(size), Align::from_bytes(align, align).unwrap(), MemoryKind::Rust.into())?; - self.write_scalar(dest, Scalar::Ptr(ptr), dest_ty)?; + self.write_scalar(Scalar::Ptr(ptr), dest)?; } "__rust_alloc_zeroed" => { - let size = self.value_to_scalar(args[0])?.to_usize(self)?; - let align = self.value_to_scalar(args[1])?.to_usize(self)?; + let size = self.read_scalar(args[0])?.to_usize(&self)?; + let align = self.read_scalar(args[1])?.to_usize(&self)?; if size == 0 { return err!(HeapAllocZeroBytes); } @@ -240,12 +186,12 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' Align::from_bytes(align, align).unwrap(), MemoryKind::Rust.into())?; self.memory.write_repeat(ptr.into(), 0, Size::from_bytes(size))?; - self.write_scalar(dest, Scalar::Ptr(ptr), dest_ty)?; + self.write_scalar(Scalar::Ptr(ptr), dest)?; } "__rust_dealloc" => { - 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 ptr = self.read_scalar(args[0])?.to_ptr()?; + let old_size = self.read_scalar(args[1])?.to_usize(&self)?; + let align = self.read_scalar(args[2])?.to_usize(&self)?; if old_size == 0 { return err!(HeapAllocZeroBytes); } @@ -259,10 +205,10 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' )?; } "__rust_realloc" => { - 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)?; + let ptr = self.read_scalar(args[0])?.to_ptr()?; + let old_size = self.read_scalar(args[1])?.to_usize(&self)?; + let align = self.read_scalar(args[2])?.to_usize(&self)?; + let new_size = self.read_scalar(args[3])?.to_usize(&self)?; if old_size == 0 || new_size == 0 { return err!(HeapAllocZeroBytes); } @@ -277,7 +223,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' Align::from_bytes(align, align).unwrap(), MemoryKind::Rust.into(), )?; - self.write_scalar(dest, Scalar::Ptr(new_ptr), dest_ty)?; + self.write_scalar(Scalar::Ptr(new_ptr), dest)?; } "syscall" => { @@ -286,7 +232,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' // // libc::syscall(NR_GETRANDOM, buf.as_mut_ptr(), buf.len(), GRND_NONBLOCK) // is called if a `HashMap` is created the regular way. - match self.value_to_scalar(args[0])?.to_usize(self)? { + match self.read_scalar(args[0])?.to_usize(&self)? { 318 | 511 => { return err!(Unimplemented( "miri does not support random number generators".to_owned(), @@ -301,8 +247,8 @@ 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)?.unwrap_or_err()?.to_ptr()?; + let _handle = self.read_scalar(args[0])?; + let symbol = self.read_scalar(args[1])?.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); @@ -315,20 +261,20 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' "__rust_maybe_catch_panic" => { // 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)?.unwrap_or_err()?.to_ptr()?; - let data = self.into_ptr(args[1].value)?.unwrap_or_err()?; + let f = self.read_scalar(args[0])?.to_ptr()?; + let data = self.read_scalar(args[1])?.not_undef()?; let f_instance = self.memory.get_fn(f)?; - self.write_null(dest, dest_layout)?; + self.write_null(dest)?; // 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. let mir = self.load_mir(f_instance.def)?; + let ret = Place::null(&self); self.push_stack_frame( f_instance, mir.span, mir, - Place::undef(), + ret, StackPopCleanup::Goto(dest_block), )?; let mut args = self.frame().mir.args_iter(); @@ -340,12 +286,12 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' ), )?; let arg_dest = self.eval_place(&mir::Place::Local(arg_local))?; - self.write_ptr(arg_dest, data, u8_ptr_ty)?; + self.write_scalar(data, arg_dest)?; assert!(args.next().is_none(), "__rust_maybe_catch_panic argument has more arguments than expected"); // We ourselves return 0 - self.write_null(dest, dest_layout)?; + self.write_null(dest)?; // Don't fall through return Ok(()); @@ -356,9 +302,9 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' } "memcmp" => { - 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 left = self.read_scalar(args[0])?.not_undef()?; + let right = self.read_scalar(args[1])?.not_undef()?; + let n = Size::from_bytes(self.read_scalar(args[2])?.to_usize(&self)?); let result = { let left_bytes = self.memory.read_bytes(left, n)?; @@ -373,58 +319,57 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' }; self.write_scalar( - dest, Scalar::from_i32(result), - dest_ty, + dest, )?; } "memrchr" => { - 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)?; + let ptr = self.read_scalar(args[0])?.not_undef()?; + let val = self.read_scalar(args[1])?.to_bytes()? as u8; + let num = self.read_scalar(args[2])?.to_usize(&self)?; if let Some(idx) = self.memory.read_bytes(ptr, Size::from_bytes(num))?.iter().rev().position( |&c| c == val, ) { let new_ptr = ptr.ptr_offset(Size::from_bytes(num - idx as u64 - 1), &self)?; - self.write_ptr(dest, new_ptr, dest_ty)?; + self.write_scalar(new_ptr, dest)?; } else { - self.write_null(dest, dest_layout)?; + self.write_null(dest)?; } } "memchr" => { - 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)?; + let ptr = self.read_scalar(args[0])?.not_undef()?; + let val = self.read_scalar(args[1])?.to_bytes()? as u8; + let num = self.read_scalar(args[2])?.to_usize(&self)?; if let Some(idx) = self.memory.read_bytes(ptr, Size::from_bytes(num))?.iter().position( |&c| c == val, ) { let new_ptr = ptr.ptr_offset(Size::from_bytes(idx as u64), &self)?; - self.write_ptr(dest, new_ptr, dest_ty)?; + self.write_scalar(new_ptr, dest)?; } else { - self.write_null(dest, dest_layout)?; + self.write_null(dest)?; } } "getenv" => { let result = { - let name_ptr = self.into_ptr(args[0].value)?.unwrap_or_err()?.to_ptr()?; + let name_ptr = self.read_scalar(args[0])?.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(self.memory.pointer_size()), } }; - self.write_scalar(dest, result, dest_ty)?; + self.write_scalar(result, dest)?; } "unsetenv" => { let mut success = None; { - let name_ptr = self.into_ptr(args[0].value)?.unwrap_or_err()?; + let name_ptr = self.read_scalar(args[0])?.not_undef()?; if !name_ptr.is_null() { let name = self.memory.read_c_str(name_ptr.to_ptr()?)?; if !name.is_empty() && !name.contains(&b'=') { @@ -436,17 +381,17 @@ 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_layout)?; + self.write_null(dest)?; } else { - self.write_scalar(dest, Scalar::from_int(-1, dest_layout.size), dest_ty)?; + self.write_scalar(Scalar::from_int(-1, dest.layout.size), dest)?; } } "setenv" => { let mut new = None; { - 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 name_ptr = self.read_scalar(args[0])?.not_undef()?; + let value_ptr = self.read_scalar(args[1])?.to_ptr()?; let value = self.memory.read_c_str(value_ptr)?; if !name_ptr.is_null() { let name = self.memory.read_c_str(name_ptr.to_ptr()?)?; @@ -472,16 +417,16 @@ 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_layout)?; + self.write_null(dest)?; } else { - self.write_scalar(dest, Scalar::from_int(-1, dest_layout.size), dest_ty)?; + self.write_scalar(Scalar::from_int(-1, dest.layout.size), dest)?; } } "write" => { - let fd = self.value_to_scalar(args[0])?.to_bytes()?; - let buf = self.into_ptr(args[1].value)?.unwrap_or_err()?; - let n = self.value_to_scalar(args[2])?.to_bytes()? as u64; + let fd = self.read_scalar(args[0])?.to_bytes()?; + let buf = self.read_scalar(args[1])?.not_undef()?; + let n = self.read_scalar(args[2])?.to_bytes()? as u64; trace!("Called write({:?}, {:?}, {:?})", fd, buf, n); let result = if fd == 1 || fd == 2 { // stdout/stderr @@ -501,36 +446,31 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' warn!("Ignored output to FD {}", fd); n as i64 // pretend it all went well }; // now result is the value we return back to the program - let ptr_size = self.memory.pointer_size(); self.write_scalar( + Scalar::from_int(result, dest.layout.size), dest, - Scalar::from_int(result, ptr_size), - dest_ty, )?; } "strlen" => { - let ptr = self.into_ptr(args[0].value)?.unwrap_or_err()?.to_ptr()?; + let ptr = self.read_scalar(args[0])?.to_ptr()?; let n = self.memory.read_c_str(ptr)?.len(); - let ptr_size = self.memory.pointer_size(); - self.write_scalar(dest, Scalar::from_uint(n as u64, ptr_size), dest_ty)?; + self.write_scalar(Scalar::from_uint(n as u64, dest.layout.size), dest)?; } // Some things needed for sys::thread initialization to go through "signal" | "sigaction" | "sigaltstack" => { - let ptr_size = self.memory.pointer_size(); - self.write_scalar(dest, Scalar::null(ptr_size), dest_ty)?; + self.write_scalar(Scalar::null(dest.layout.size), dest)?; } "sysconf" => { - let name = self.value_to_scalar(args[0])?.to_usize(self)?; - let ptr_size = self.memory.pointer_size(); + let name = self.read_scalar(args[0])?.to_usize(&self)?; trace!("sysconf() called with name {}", name); // cache the sysconf integers via miri's global cache let paths = &[ - (&["libc", "_SC_PAGESIZE"], Scalar::from_int(4096, ptr_size)), - (&["libc", "_SC_GETPW_R_SIZE_MAX"], Scalar::from_int(-1, ptr_size)), + (&["libc", "_SC_PAGESIZE"], Scalar::from_int(4096, dest.layout.size)), + (&["libc", "_SC_GETPW_R_SIZE_MAX"], Scalar::from_int(-1, dest.layout.size)), ]; let mut result = None; for &(path, path_value) in paths { @@ -548,7 +488,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' } } if let Some(result) = result { - self.write_scalar(dest, result, dest_ty)?; + self.write_scalar(result, dest)?; } else { return err!(Unimplemented( format!("Unimplemented sysconf name: {}", name), @@ -558,10 +498,10 @@ 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)?.unwrap_or_err()?; + let key_ptr = self.read_scalar(args[0])?.not_undef()?; // Extract the function type out of the signature (that seems easier than constructing it ourselves...) - let dtor = match self.into_ptr(args[1].value)?.unwrap_or_err()? { + let dtor = match self.read_scalar(args[1])?.not_undef()? { Scalar::Ptr(dtor_ptr) => Some(self.memory.get_fn(dtor_ptr)?), Scalar::Bits { bits: 0, size } => { assert_eq!(size as u64, self.memory.pointer_size().bytes()); @@ -571,7 +511,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' }; // 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) + let key_type = args[0].layout.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_layout = self.layout_of(key_type)?; @@ -590,26 +530,26 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' )?; // Return success (0) - self.write_null(dest, dest_layout)?; + self.write_null(dest)?; } "pthread_key_delete" => { - let key = self.value_to_scalar(args[0])?.to_bytes()?; + let key = self.read_scalar(args[0])?.to_bytes()?; self.memory.delete_tls_key(key)?; // Return success (0) - self.write_null(dest, dest_layout)?; + self.write_null(dest)?; } "pthread_getspecific" => { - let key = self.value_to_scalar(args[0])?.to_bytes()?; + let key = self.read_scalar(args[0])?.to_bytes()?; let ptr = self.memory.load_tls(key)?; - self.write_ptr(dest, ptr, dest_ty)?; + self.write_scalar(ptr, dest)?; } "pthread_setspecific" => { - let key = self.value_to_scalar(args[0])?.to_bytes()?; - let new_ptr = self.into_ptr(args[1].value)?.unwrap_or_err()?; + let key = self.read_scalar(args[0])?.to_bytes()?; + let new_ptr = self.read_scalar(args[1])?.not_undef()?; self.memory.store_tls(key, new_ptr)?; // Return success (0) - self.write_null(dest, dest_layout)?; + self.write_null(dest)?; } "_tlv_atexit" => { @@ -619,20 +559,19 @@ 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_layout)?; + self.write_null(dest)?; } "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)?.unwrap_or_err()?; - self.write_ptr(dest, addr, dest_ty)?; + let addr = self.read_scalar(args[0])?.not_undef()?; + self.write_scalar(addr, dest)?; } // Windows API subs "AddVectoredExceptionHandler" => { // any non zero value works for the stdlib. This is just used for stackoverflows anyway - let ptr_size = self.memory.pointer_size(); - self.write_scalar(dest, Scalar::from_int(1, ptr_size), dest_ty)?; + self.write_scalar(Scalar::from_int(1, dest.layout.size), dest)?; }, "InitializeCriticalSection" | "EnterCriticalSection" | @@ -645,11 +584,11 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' "GetProcAddress" | "TryEnterCriticalSection" => { // pretend these do not exist/nothing happened, by returning zero - self.write_scalar(dest, Scalar::from_int(0, dest_layout.size), dest_ty)?; + self.write_null(dest)?; }, "GetLastError" => { // this is c::ERROR_CALL_NOT_IMPLEMENTED - self.write_scalar(dest, Scalar::from_int(120, dest_layout.size), dest_ty)?; + self.write_scalar(Scalar::from_int(120, dest.layout.size), dest)?; }, // Windows TLS @@ -660,23 +599,23 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' let key = self.memory.create_tls_key(None) 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) { + if dest.layout.size.bits() < 128 && key >= (1u128 << dest.layout.size.bits() as u128) { return err!(OutOfTls); } - self.write_scalar(dest, Scalar::from_uint(key, dest_layout.size), dest_layout.ty)?; + self.write_scalar(Scalar::from_uint(key, dest.layout.size), dest)?; } "TlsGetValue" => { - let key = self.value_to_scalar(args[0])?.to_bytes()?; + let key = self.read_scalar(args[0])?.to_bytes()?; let ptr = self.memory.load_tls(key)?; - self.write_ptr(dest, ptr, dest_ty)?; + self.write_scalar(ptr, dest)?; } "TlsSetValue" => { - let key = self.value_to_scalar(args[0])?.to_bytes()?; - let new_ptr = self.into_ptr(args[1].value)?.unwrap_or_err()?; + let key = self.read_scalar(args[0])?.to_bytes()?; + let new_ptr = self.read_scalar(args[1])?.not_undef()?; self.memory.store_tls(key, new_ptr)?; // Return success (1) - self.write_scalar(dest, Scalar::from_int(1, dest_layout.size), dest_ty)?; + self.write_scalar(Scalar::from_int(1, dest.layout.size), dest)?; } // We can't execute anything else @@ -690,7 +629,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' // Since we pushed no stack frame, the main loop will act // as if the call just completed and it's returning to the // current frame. - self.dump_local(dest); + self.dump_place(*dest); self.goto_block(dest_block); Ok(()) } @@ -732,9 +671,8 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' fn call_missing_fn( &mut self, instance: ty::Instance<'tcx>, - destination: Option<(Place, mir::BasicBlock)>, - args: &[ValTy<'tcx>], - sig: ty::FnSig<'tcx>, + destination: Option<(PlaceTy<'tcx>, mir::BasicBlock)>, + args: &[OpTy<'tcx>], path: String, ) -> EvalResult<'tcx> { // In some cases in non-MIR libstd-mode, not having a destination is legit. Handle these early. @@ -745,7 +683,6 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' _ => {} } - let dest_ty = sig.output(); let (dest, dest_block) = destination.ok_or_else( || EvalErrorKind::NoMirFor(path.clone()), )?; @@ -758,7 +695,6 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' instance.def_id(), args, dest, - dest_ty, dest_block, )?; return Ok(()); @@ -784,8 +720,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' "std::panicking::panicking" | "std::rt::panicking" => { // we abort on panic -> `std::rt::panicking` always returns false - let bool = self.tcx.types.bool; - self.write_scalar(dest, Scalar::from_bool(false), bool)?; + self.write_scalar(Scalar::from_bool(false), dest)?; } _ => return err!(NoMirFor(path)), @@ -794,12 +729,12 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' // Since we pushed no stack frame, the main loop will act // as if the call just completed and it's returning to the // current frame. - self.dump_local(dest); + self.dump_place(*dest); self.goto_block(dest_block); Ok(()) } - 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) + fn write_null(&mut self, dest: PlaceTy<'tcx>) -> EvalResult<'tcx> { + self.write_scalar(Scalar::null(dest.layout.size), dest) } } diff --git a/src/helpers.rs b/src/helpers.rs index 8482c484608b7..606f1bb4ecb44 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -1,128 +1,121 @@ -use mir; -use rustc::ty::Ty; -use rustc::ty::layout::{LayoutOf, Size}; +use rustc::ty::layout::{Size, HasDataLayout}; -use super::{Scalar, ScalarExt, EvalResult, EvalContext, ValTy}; +use super::{Scalar, ScalarMaybeUndef, EvalResult}; use rustc_mir::interpret::sign_extend; -pub trait EvalContextExt<'tcx> { - fn wrapping_pointer_offset( - &self, - ptr: Scalar, - pointee_ty: Ty<'tcx>, - offset: i64, - ) -> EvalResult<'tcx, Scalar>; - - fn pointer_offset( - &self, - ptr: Scalar, - pointee_ty: Ty<'tcx>, - offset: i64, - ) -> EvalResult<'tcx, Scalar>; - - fn value_to_isize( - &self, - value: ValTy<'tcx>, - ) -> EvalResult<'tcx, i64>; - - fn value_to_usize( - &self, - value: ValTy<'tcx>, - ) -> EvalResult<'tcx, u64>; - - fn value_to_i32( - &self, - value: ValTy<'tcx>, - ) -> EvalResult<'tcx, i32>; - - fn value_to_u8( - &self, - value: ValTy<'tcx>, - ) -> EvalResult<'tcx, u8>; +pub trait ScalarExt { + fn null(size: Size) -> Self; + fn from_i32(i: i32) -> Self; + fn from_uint(i: impl Into, ptr_size: Size) -> Self; + fn from_int(i: impl Into, ptr_size: Size) -> Self; + fn from_f32(f: f32) -> Self; + fn from_f64(f: f64) -> Self; + fn is_null(self) -> bool; } -impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super::Evaluator<'tcx>> { - fn wrapping_pointer_offset( - &self, - ptr: Scalar, - pointee_ty: Ty<'tcx>, - offset: i64, - ) -> EvalResult<'tcx, Scalar> { - // FIXME: assuming here that type size is < i64::max_value() - let pointee_size = self.layout_of(pointee_ty)?.size.bytes() as i64; - let offset = offset.overflowing_mul(pointee_size).0; - Ok(ptr.ptr_wrapping_signed_offset(offset, self)) - } - - fn pointer_offset( - &self, - ptr: Scalar, - pointee_ty: Ty<'tcx>, - offset: i64, - ) -> EvalResult<'tcx, Scalar> { - // This function raises an error if the offset moves the pointer outside of its allocation. We consider - // ZSTs their own huge allocation that doesn't overlap with anything (and nothing moves in there because the size is 0). - // We also consider the NULL pointer its own separate allocation, and all the remaining integers pointers their own - // allocation. - - if ptr.is_null() { - // NULL pointers must only be offset by 0 - return if offset == 0 { - Ok(ptr) - } else { - err!(InvalidNullPointerUsage) - }; +pub trait FalibleScalarExt { + fn to_usize(self, cx: impl HasDataLayout) -> EvalResult<'static, u64>; + fn to_isize(self, cx: impl HasDataLayout) -> EvalResult<'static, i64>; + fn to_i32(self) -> EvalResult<'static, i32>; + fn to_u8(self) -> EvalResult<'static, u8>; + + /// 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 + fn to_bytes(self) -> EvalResult<'static, u128>; +} + +impl ScalarExt for Scalar { + 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, size: 4 } + } + + fn from_uint(i: impl Into, size: Size) -> Self { + Scalar::Bits { bits: i.into(), size: size.bytes() as u8 } + } + + fn from_int(i: impl Into, size: Size) -> Self { + Scalar::Bits { bits: i.into() as u128, size: size.bytes() as u8 } + } + + fn from_f32(f: f32) -> Self { + Scalar::Bits { bits: f.to_bits() as u128, size: 4 } + } + + fn from_f64(f: f64) -> Self { + Scalar::Bits { bits: f.to_bits() as u128, size: 8 } + } + + fn is_null(self) -> bool { + match self { + Scalar::Bits { bits, .. } => bits == 0, + Scalar::Ptr(_) => false } - // FIXME: assuming here that type size is < i64::max_value() - let pointee_size = self.layout_of(pointee_ty)?.size.bytes() as i64; - if let Some(offset) = offset.checked_mul(pointee_size) { - let ptr = ptr.ptr_signed_offset(offset, self)?; - // Do not do bounds-checking for integers; they can never alias a normal pointer anyway. - if let Scalar::Ptr(ptr) = ptr { - self.memory.check_bounds(ptr, false)?; - } else if ptr.is_null() { - // We moved *to* a NULL pointer. That seems wrong, LLVM considers the NULL pointer its own small allocation. Reject this, for now. - return err!(InvalidNullPointerUsage); - } - Ok(ptr) - } else { - err!(Overflow(mir::BinOp::Mul)) + } +} + +impl FalibleScalarExt for Scalar { + fn to_usize(self, cx: impl HasDataLayout) -> EvalResult<'static, u64> { + let b = self.to_bits(cx.data_layout().pointer_size)?; + assert_eq!(b as u64 as u128, b); + Ok(b as u64) + } + + fn to_u8(self) -> EvalResult<'static, u8> { + let sz = Size::from_bits(8); + let b = self.to_bits(sz)?; + assert_eq!(b as u8 as u128, b); + Ok(b as u8) + } + + fn to_isize(self, cx: impl HasDataLayout) -> EvalResult<'static, i64> { + let b = self.to_bits(cx.data_layout().pointer_size)?; + let b = sign_extend(b, cx.data_layout().pointer_size) as i128; + assert_eq!(b as i64 as i128, b); + Ok(b as i64) + } + + fn to_i32(self) -> EvalResult<'static, i32> { + let sz = Size::from_bits(32); + let b = self.to_bits(sz)?; + let b = sign_extend(b, sz) as i128; + assert_eq!(b as i32 as i128, b); + Ok(b as i32) + } + + fn to_bytes(self) -> EvalResult<'static, u128> { + match self { + Scalar::Bits { bits, size } => { + assert_ne!(size, 0); + Ok(bits) + }, + Scalar::Ptr(_) => err!(ReadPointerAsBytes), } } +} + +impl FalibleScalarExt for ScalarMaybeUndef { + fn to_usize(self, cx: impl HasDataLayout) -> EvalResult<'static, u64> { + self.not_undef()?.to_usize(cx) + } + + fn to_u8(self) -> EvalResult<'static, u8> { + self.not_undef()?.to_u8() + } + + fn to_isize(self, cx: impl HasDataLayout) -> EvalResult<'static, i64> { + self.not_undef()?.to_isize(cx) + } + + fn to_i32(self) -> EvalResult<'static, i32> { + self.not_undef()?.to_i32() + } - fn value_to_isize( - &self, - value: ValTy<'tcx>, - ) -> 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(raw, self.layout_of(self.tcx.types.isize).unwrap()); - Ok(raw as i64) - } - - fn value_to_usize( - &self, - value: ValTy<'tcx>, - ) -> EvalResult<'tcx, u64> { - assert_eq!(value.ty, self.tcx.types.usize); - self.value_to_scalar(value)?.to_bits(self.memory.pointer_size()).map(|v| v as u64) - } - - fn value_to_i32( - &self, - value: ValTy<'tcx>, - ) -> 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(raw, self.layout_of(self.tcx.types.i32).unwrap()); - Ok(raw as i32) - } - - fn value_to_u8( - &self, - value: ValTy<'tcx>, - ) -> EvalResult<'tcx, u8> { - assert_eq!(value.ty, self.tcx.types.u8); - self.value_to_scalar(value)?.to_bits(Size::from_bits(8)).map(|v| v as u8) + fn to_bytes(self) -> EvalResult<'static, u128> { + self.not_undef()?.to_bytes() } } diff --git a/src/intrinsic.rs b/src/intrinsic.rs index cd953ba7c5693..631653b97b6b6 100644 --- a/src/intrinsic.rs +++ b/src/intrinsic.rs @@ -1,21 +1,20 @@ use rustc::mir; -use rustc::ty::layout::{TyLayout, LayoutOf, Size, Primitive, Integer::*}; +use rustc::ty::layout::{self, LayoutOf, Size, Primitive, Integer::*}; use rustc::ty; -use rustc::mir::interpret::{EvalResult, Scalar, Value, ScalarMaybeUndef}; -use rustc_mir::interpret::{Place, PlaceExtra, HasMemory, EvalContext, ValTy}; +use rustc::mir::interpret::{EvalResult, Scalar, ScalarMaybeUndef}; +use rustc_mir::interpret::{ + PlaceExtra, PlaceTy, EvalContext, OpTy, Value +}; -use helpers::EvalContextExt as HelperEvalContextExt; - -use super::ScalarExt; +use super::{ScalarExt, FalibleScalarExt, OperatorEvalContextExt}; pub trait EvalContextExt<'tcx> { fn call_intrinsic( &mut self, instance: ty::Instance<'tcx>, - args: &[ValTy<'tcx>], - dest: Place, - dest_layout: TyLayout<'tcx>, + args: &[OpTy<'tcx>], + dest: PlaceTy<'tcx>, target: mir::BasicBlock, ) -> EvalResult<'tcx>; } @@ -24,9 +23,8 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: fn call_intrinsic( &mut self, instance: ty::Instance<'tcx>, - args: &[ValTy<'tcx>], - dest: Place, - dest_layout: TyLayout<'tcx>, + args: &[OpTy<'tcx>], + dest: PlaceTy<'tcx>, target: mir::BasicBlock, ) -> EvalResult<'tcx> { let substs = instance.substs; @@ -34,44 +32,51 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: let intrinsic_name = &self.tcx.item_name(instance.def_id()).as_str()[..]; match intrinsic_name { "add_with_overflow" => { - self.intrinsic_with_overflow( + let l = self.read_value(args[0])?; + let r = self.read_value(args[1])?; + self.binop_with_overflow( mir::BinOp::Add, - args[0], - args[1], + l, + r, dest, - dest_layout.ty, )? } "sub_with_overflow" => { - self.intrinsic_with_overflow( + let l = self.read_value(args[0])?; + let r = self.read_value(args[1])?; + self.binop_with_overflow( mir::BinOp::Sub, - args[0], - args[1], + l, + r, dest, - dest_layout.ty, )? } "mul_with_overflow" => { - self.intrinsic_with_overflow( + let l = self.read_value(args[0])?; + let r = self.read_value(args[1])?; + self.binop_with_overflow( mir::BinOp::Mul, - args[0], - args[1], + l, + r, dest, - dest_layout.ty, )? } "arith_offset" => { - let offset = self.value_to_isize(args[1])?; - 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)?; + let offset = self.read_scalar(args[1])?.to_isize(&self)?; + let ptr = self.read_scalar(args[0])?.not_undef()?; + + let pointee_ty = substs.type_at(0); + let pointee_size = self.layout_of(pointee_ty)?.size.bytes() as i64; + let offset = offset.overflowing_mul(pointee_size).0; + let result_ptr = ptr.ptr_wrapping_signed_offset(offset, &self); + self.write_scalar(result_ptr, dest)?; } "assume" => { - let cond = self.value_to_scalar(args[0])?.to_bool()?; + let cond = self.read_scalar(args[0])?.to_bool()?; if !cond { return err!(AssumptionNotHeld); } @@ -81,24 +86,18 @@ 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)?.unwrap_or_err()?; - let align = self.layout_of(args[0].ty)?.align; - - let valty = ValTy { - value: Value::ByRef(ptr, align), - ty: substs.type_at(0), - }; - self.write_value(valty, dest)?; + let ptr = self.ref_to_mplace(self.read_value(args[0])?)?; + let val = self.read_scalar(ptr.into())?; // make sure it fits into a scalar; otherwise it cannot be atomic + self.write_scalar(val, dest)?; } "atomic_store" | "atomic_store_relaxed" | "atomic_store_rel" | "volatile_store" => { - let ty = substs.type_at(0); - let align = self.layout_of(ty)?.align; - let dest = self.into_ptr(args[0].value)?.unwrap_or_err()?; - self.write_value_to_ptr(args[1].value, dest, align, ty)?; + let ptr = self.ref_to_mplace(self.read_value(args[0])?)?; + let val = self.read_scalar(args[1])?; // make sure it fits into a scalar; otherwise it cannot be atomic + self.write_scalar(val, ptr.into())?; } "atomic_fence_acq" => { @@ -106,47 +105,26 @@ 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)?.unwrap_or_err()?; - let change = self.value_to_scalar(args[1])?; - let old = self.read_value(ptr, align, ty)?; - let old = match old { - Value::Scalar(val) => val, - Value::ByRef { .. } => bug!("just read the value, can't be byref"), - Value::ScalarPair(..) => bug!("atomic_xchg doesn't work with nonprimitives"), - }; - self.write_scalar(dest, old, ty)?; - self.write_scalar( - Place::from_scalar_ptr(ptr.into(), align), - change, - ty, - )?; + let ptr = self.ref_to_mplace(self.read_value(args[0])?)?; + let new = self.read_scalar(args[1])?; + let old = self.read_scalar(ptr.into())?; + self.write_scalar(old, dest)?; // old value is returned + self.write_scalar(new, ptr.into())?; } _ 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)?.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.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.into(), val.into()), - ty: dest_layout.ty, - }; - self.write_value(valty, dest)?; - self.write_scalar( - Place::from_scalar_ptr(ptr.into(), dest_layout.align), - change, - ty, - )?; + let ptr = self.ref_to_mplace(self.read_value(args[0])?)?; + let expect_old = self.read_value(args[1])?; // read as value for the sake of `binary_op()` + let new = self.read_scalar(args[2])?; + let old = self.read_value(ptr.into())?; // read as value for the sake of `binary_op()` + // binary_op will bail if either of them is not a scalar + let (eq, _) = self.binary_op(mir::BinOp::Eq, old, expect_old)?; + let res = Value::ScalarPair(old.to_scalar_or_undef(), eq.into()); + self.write_value(res, dest)?; // old value is returned + // update ptr depending on comparison + if eq.to_bool()? { + self.write_scalar(new, ptr.into())?; + } } "atomic_or" | @@ -174,19 +152,10 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: "atomic_xsub_rel" | "atomic_xsub_acqrel" | "atomic_xsub_relaxed" => { - let ty = substs.type_at(0); - let align = self.layout_of(ty)?.align; - 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 { - Value::Scalar(val) => val, - Value::ByRef { .. } => bug!("just read the value, can't be byref"), - Value::ScalarPair(..) => { - bug!("atomic_xadd_relaxed doesn't work with nonprimitives") - } - }; - self.write_scalar(dest, old, ty)?; + let ptr = self.ref_to_mplace(self.read_value(args[0])?)?; + let rhs = self.read_value(args[1])?; + let old = self.read_value(ptr.into())?; + self.write_value(*old, dest)?; // old value is returned let op = match intrinsic_name.split('_').nth(1).unwrap() { "or" => mir::BinOp::BitOr, "xor" => mir::BinOp::BitXor, @@ -196,8 +165,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.unwrap_or_err()?, ty, change, ty)?; - self.write_scalar(Place::from_scalar_ptr(ptr.into(), dest_layout.align), val, ty)?; + let (val, _) = self.binary_op(op, old, rhs)?; + self.write_scalar(val, ptr.into())?; } "breakpoint" => unimplemented!(), // halt miri @@ -207,13 +176,13 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: let elem_ty = substs.type_at(0); let elem_layout = self.layout_of(elem_ty)?; let elem_size = elem_layout.size.bytes(); - let count = self.value_to_usize(args[2])?; + let count = self.read_scalar(args[2])?.to_usize(&self)?; if count * elem_size != 0 { // 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)?.unwrap_or_err()?; - let dest = self.into_ptr(args[1].value)?.unwrap_or_err()?; + let src = self.read_scalar(args[0])?.not_undef()?; + let dest = self.read_scalar(args[1])?.not_undef()?; self.memory.copy( src, elem_align, @@ -227,7 +196,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: "ctpop" | "cttz" | "cttz_nonzero" | "ctlz" | "ctlz_nonzero" | "bswap" => { let ty = substs.type_at(0); - let num = self.value_to_scalar(args[0])?.to_bytes()?; + let num = self.read_scalar(args[0])?.to_bytes()?; let kind = match self.layout_of(ty)?.abi { ty::layout::Abi::Scalar(ref scalar) => scalar.value, _ => Err(::rustc::mir::interpret::EvalErrorKind::TypeNotPrimitive(ty))?, @@ -240,22 +209,18 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: } else { numeric_intrinsic(intrinsic_name, num, kind)? }; - self.write_scalar(dest, num, ty)?; + self.write_scalar(num, dest)?; } "discriminant_value" => { - let ty = substs.type_at(0); - let layout = self.layout_of(ty)?; - let adt_ptr = self.into_ptr(args[0].value)?; - 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_uint(discr_val, dest_layout.size), dest_layout.ty)?; + let place = self.ref_to_mplace(self.read_value(args[0])?)?; + let discr_val = self.read_discriminant_value(place.into())?; + self.write_scalar(Scalar::from_uint(discr_val, dest.layout.size), dest)?; } "sinf32" | "fabsf32" | "cosf32" | "sqrtf32" | "expf32" | "exp2f32" | "logf32" | "log10f32" | "log2f32" | "floorf32" | "ceilf32" | "truncf32" => { - let f = self.value_to_scalar(args[0])?.to_bytes()?; + let f = self.read_scalar(args[0])?.to_bytes()?; let f = f32::from_bits(f as u32); let f = match intrinsic_name { "sinf32" => f.sin(), @@ -272,12 +237,12 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: "truncf32" => f.trunc(), _ => bug!(), }; - self.write_scalar(dest, Scalar::from_f32(f), dest_layout.ty)?; + self.write_scalar(Scalar::from_f32(f), dest)?; } "sinf64" | "fabsf64" | "cosf64" | "sqrtf64" | "expf64" | "exp2f64" | "logf64" | "log10f64" | "log2f64" | "floorf64" | "ceilf64" | "truncf64" => { - let f = self.value_to_scalar(args[0])?.to_bytes()?; + let f = self.read_scalar(args[0])?.to_bytes()?; let f = f64::from_bits(f as u64); let f = match intrinsic_name { "sinf64" => f.sin(), @@ -294,13 +259,12 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: "truncf64" => f.trunc(), _ => bug!(), }; - self.write_scalar(dest, Scalar::from_f64(f), dest_layout.ty)?; + self.write_scalar(Scalar::from_f64(f), dest)?; } "fadd_fast" | "fsub_fast" | "fmul_fast" | "fdiv_fast" | "frem_fast" => { - let ty = substs.type_at(0); - let a = self.value_to_scalar(args[0])?; - let b = self.value_to_scalar(args[1])?; + let a = self.read_value(args[0])?; + let b = self.read_value(args[1])?; let op = match intrinsic_name { "fadd_fast" => mir::BinOp::Add, "fsub_fast" => mir::BinOp::Sub, @@ -309,48 +273,43 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: "frem_fast" => mir::BinOp::Rem, _ => bug!(), }; - let result = self.binary_op(op, a, ty, b, ty)?; - self.write_scalar(dest, result.0, dest_layout.ty)?; + let result = self.binary_op(op, a, b)?; + self.write_scalar(result.0, dest)?; } "exact_div" => { // Performs an exact division, resulting in undefined behavior where // `x % y != 0` or `y == 0` or `x == T::min_value() && y == -1` - let ty = substs.type_at(0); - let a = self.value_to_scalar(args[0])?; - let b = self.value_to_scalar(args[1])?; + let a = self.read_value(args[0])?; + let b = self.read_value(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, b)?.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)?; - self.write_scalar(dest, result.0, dest_layout.ty)?; + let result = self.binary_op(mir::BinOp::Div, a, b)?; + self.write_scalar(result.0, dest)?; }, "likely" | "unlikely" | "forget" => {} "init" => { - // 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)?; - } - } - }, - Place::Ptr { - ptr, - align: _align, - extra: PlaceExtra::None, - } => 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") + // Check fast path: we don't want to force an allocation in case the destination is a simple value, + // but we also do not want to create a new allocation with 0s and then copy that over. + match dest.layout.abi { + layout::Abi::Scalar(ref s) => { + let x = Scalar::null(s.value.size(&self)); + self.write_value(Value::Scalar(x.into()), dest)?; + } + layout::Abi::ScalarPair(ref s1, ref s2) => { + let x = Scalar::null(s1.value.size(&self)); + let y = Scalar::null(s2.value.size(&self)); + self.write_value(Value::ScalarPair(x.into(), y.into()), dest)?; + } + _ => { + // Do it in memory + let mplace = self.force_allocation(dest)?; + assert_eq!(mplace.extra, PlaceExtra::None); + self.memory.write_repeat(mplace.ptr, 0, dest.layout.size)?; } } } @@ -360,7 +319,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: let elem_align = self.layout_of(elem_ty)?.align.abi(); 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)?; + self.write_scalar(align_val, dest)?; } "pref_align_of" => { @@ -369,14 +328,12 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: let align = layout.align.pref(); 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)?; + self.write_scalar(align_val, dest)?; } "move_val_init" => { - let ty = substs.type_at(0); - 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)?; + let ptr = self.ref_to_mplace(self.read_value(args[0])?)?; + self.copy_op(args[1], ptr.into())?; } "needs_drop" => { @@ -384,120 +341,116 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: let env = ty::ParamEnv::reveal_all(); let needs_drop = ty.needs_drop(self.tcx.tcx, env); self.write_scalar( - dest, Scalar::from_bool(needs_drop), - dest_layout.ty, + dest, )?; } "offset" => { - let offset = self.value_to_isize(args[1])?; - 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)?; + let offset = self.read_scalar(args[1])?.to_isize(&self)?; + let ptr = self.read_scalar(args[0])?.not_undef()?; + let result_ptr = self.pointer_offset_inbounds(ptr, substs.type_at(0), offset)?; + self.write_scalar(result_ptr, dest)?; } "overflowing_sub" => { - self.intrinsic_overflowing( + let l = self.read_value(args[0])?; + let r = self.read_value(args[1])?; + self.binop_ignore_overflow( mir::BinOp::Sub, - args[0], - args[1], + l, + r, dest, - dest_layout.ty, )?; } "overflowing_mul" => { - self.intrinsic_overflowing( + let l = self.read_value(args[0])?; + let r = self.read_value(args[1])?; + self.binop_ignore_overflow( mir::BinOp::Mul, - args[0], - args[1], + r, + l, dest, - dest_layout.ty, )?; } "overflowing_add" => { - self.intrinsic_overflowing( + let l = self.read_value(args[0])?; + let r = self.read_value(args[1])?; + self.binop_ignore_overflow( mir::BinOp::Add, - args[0], - args[1], + r, + l, dest, - dest_layout.ty, )?; } "powf32" => { - let f = self.value_to_scalar(args[0])?.to_bits(Size::from_bits(32))?; + let f = self.read_scalar(args[0])?.to_bits(Size::from_bits(32))?; let f = f32::from_bits(f as u32); - let f2 = self.value_to_scalar(args[1])?.to_bits(Size::from_bits(32))?; + let f2 = self.read_scalar(args[1])?.to_bits(Size::from_bits(32))?; let f2 = f32::from_bits(f2 as u32); self.write_scalar( - dest, Scalar::from_f32(f.powf(f2)), - dest_layout.ty, + dest, )?; } "powf64" => { - let f = self.value_to_scalar(args[0])?.to_bits(Size::from_bits(64))?; + let f = self.read_scalar(args[0])?.to_bits(Size::from_bits(64))?; let f = f64::from_bits(f as u64); - let f2 = self.value_to_scalar(args[1])?.to_bits(Size::from_bits(64))?; + let f2 = self.read_scalar(args[1])?.to_bits(Size::from_bits(64))?; let f2 = f64::from_bits(f2 as u64); self.write_scalar( - dest, Scalar::from_f64(f.powf(f2)), - dest_layout.ty, + dest, )?; } "fmaf32" => { - let a = self.value_to_scalar(args[0])?.to_bits(Size::from_bits(32))?; + let a = self.read_scalar(args[0])?.to_bits(Size::from_bits(32))?; let a = f32::from_bits(a as u32); - let b = self.value_to_scalar(args[1])?.to_bits(Size::from_bits(32))?; + let b = self.read_scalar(args[1])?.to_bits(Size::from_bits(32))?; let b = f32::from_bits(b as u32); - let c = self.value_to_scalar(args[2])?.to_bits(Size::from_bits(32))?; + let c = self.read_scalar(args[2])?.to_bits(Size::from_bits(32))?; let c = f32::from_bits(c as u32); self.write_scalar( - dest, Scalar::from_f32(a * b + c), - dest_layout.ty, + dest, )?; } "fmaf64" => { - let a = self.value_to_scalar(args[0])?.to_bits(Size::from_bits(64))?; + let a = self.read_scalar(args[0])?.to_bits(Size::from_bits(64))?; let a = f64::from_bits(a as u64); - let b = self.value_to_scalar(args[1])?.to_bits(Size::from_bits(64))?; + let b = self.read_scalar(args[1])?.to_bits(Size::from_bits(64))?; let b = f64::from_bits(b as u64); - let c = self.value_to_scalar(args[2])?.to_bits(Size::from_bits(64))?; + let c = self.read_scalar(args[2])?.to_bits(Size::from_bits(64))?; let c = f64::from_bits(c as u64); self.write_scalar( - dest, Scalar::from_f64(a * b + c), - dest_layout.ty, + dest, )?; } "powif32" => { - let f = self.value_to_scalar(args[0])?.to_bits(Size::from_bits(32))?; + let f = self.read_scalar(args[0])?.to_bits(Size::from_bits(32))?; let f = f32::from_bits(f as u32); - let i = self.value_to_i32(args[1])?; + let i = self.read_scalar(args[1])?.to_i32()?; self.write_scalar( - dest, Scalar::from_f32(f.powi(i)), - dest_layout.ty, + dest, )?; } "powif64" => { - let f = self.value_to_scalar(args[0])?.to_bits(Size::from_bits(64))?; + let f = self.read_scalar(args[0])?.to_bits(Size::from_bits(64))?; let f = f64::from_bits(f as u64); - let i = self.value_to_i32(args[1])?; + let i = self.read_scalar(args[1])?.to_i32()?; self.write_scalar( - dest, Scalar::from_f64(f.powi(i)), - dest_layout.ty, + dest, )?; } @@ -505,29 +458,27 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: let ty = substs.type_at(0); 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)?; + self.write_scalar(Scalar::from_uint(size, ptr_size), dest)?; } "size_of_val" => { - let ty = substs.type_at(0); - let (size, _) = self.size_and_align_of_dst(ty, args[0].value)?; + let mplace = self.ref_to_mplace(self.read_value(args[0])?)?; + let (size, _) = self.size_and_align_of_mplace(mplace)?; let ptr_size = self.memory.pointer_size(); self.write_scalar( - dest, Scalar::from_uint(size.bytes() as u128, ptr_size), - dest_layout.ty, + dest, )?; } "min_align_of_val" | "align_of_val" => { - let ty = substs.type_at(0); - let (_, align) = self.size_and_align_of_dst(ty, args[0].value)?; + let mplace = self.ref_to_mplace(self.read_value(args[0])?)?; + let (_, align) = self.size_and_align_of_mplace(mplace)?; let ptr_size = self.memory.pointer_size(); self.write_scalar( - dest, Scalar::from_uint(align.abi(), ptr_size), - dest_layout.ty, + dest, )?; } @@ -535,110 +486,105 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: let ty = substs.type_at(0); let ty_name = ty.to_string(); let value = self.str_to_value(&ty_name)?; - self.write_value(ValTy { value, ty: dest_layout.ty }, dest)?; + self.write_value(value, dest)?; } "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, size: 8 }, dest_layout.ty)?; + self.write_scalar(Scalar::Bits { bits: n as u128, size: 8 }, dest)?; } "transmute" => { - let src_ty = substs.type_at(0); - let _src_align = self.layout_of(src_ty)?.align; - let ptr = self.force_allocation(dest)?.to_ptr()?; - let dest_align = self.layout_of(substs.type_at(1))?.align; - self.write_value_to_ptr(args[0].value, ptr.into(), dest_align, src_ty).unwrap(); + // Go through an allocation, to make sure the completely different layouts + // do not pose a problem. (When the user transmutes through a union, + // there will not be a layout mismatch.) + let dest = self.force_allocation(dest)?; + self.copy_op(args[0], dest.into())?; } "unchecked_shl" => { - let bits = dest_layout.size.bytes() as u128 * 8; - let rhs = self.value_to_scalar(args[1])? - .to_bytes()?; - if rhs >= bits { + let bits = dest.layout.size.bytes() as u128 * 8; + let l = self.read_value(args[0])?; + let r = self.read_value(args[1])?; + let rval = r.to_scalar()?.to_bytes()?; + if rval >= bits { return err!(Intrinsic( - format!("Overflowing shift by {} in unchecked_shl", rhs), + format!("Overflowing shift by {} in unchecked_shl", rval), )); } - self.intrinsic_overflowing( + self.binop_ignore_overflow( mir::BinOp::Shl, - args[0], - args[1], + l, + r, dest, - dest_layout.ty, )?; } "unchecked_shr" => { - let bits = dest_layout.size.bytes() as u128 * 8; - let rhs = self.value_to_scalar(args[1])? - .to_bytes()?; - if rhs >= bits { + let bits = dest.layout.size.bytes() as u128 * 8; + let l = self.read_value(args[0])?; + let r = self.read_value(args[1])?; + let rval = r.to_scalar()?.to_bytes()?; + if rval >= bits { return err!(Intrinsic( - format!("Overflowing shift by {} in unchecked_shr", rhs), + format!("Overflowing shift by {} in unchecked_shr", rval), )); } - self.intrinsic_overflowing( + self.binop_ignore_overflow( mir::BinOp::Shr, - args[0], - args[1], + l, + r, dest, - dest_layout.ty, )?; } "unchecked_div" => { - let rhs = self.value_to_scalar(args[1])? - .to_bytes()?; - if rhs == 0 { + let l = self.read_value(args[0])?; + let r = self.read_value(args[1])?; + let rval = r.to_scalar()?.to_bytes()?; + if rval == 0 { return err!(Intrinsic(format!("Division by 0 in unchecked_div"))); } - self.intrinsic_overflowing( + self.binop_ignore_overflow( mir::BinOp::Div, - args[0], - args[1], + l, + r, dest, - dest_layout.ty, )?; } "unchecked_rem" => { - let rhs = self.value_to_scalar(args[1])? - .to_bytes()?; - if rhs == 0 { + let l = self.read_value(args[0])?; + let r = self.read_value(args[1])?; + let rval = r.to_scalar()?.to_bytes()?; + if rval == 0 { return err!(Intrinsic(format!("Division by 0 in unchecked_rem"))); } - self.intrinsic_overflowing( + self.binop_ignore_overflow( mir::BinOp::Rem, - args[0], - args[1], + l, + r, dest, - dest_layout.ty, )?; } "uninit" => { - // 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.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.unwrap_or_err()?, dest_layout.size, false)?, - Place::Ptr { .. } => { - bug!("uninit intrinsic tried to write to fat or unaligned ptr target") + // Check fast path: we don't want to force an allocation in case the destination is a simple value, + // but we also do not want to create a new allocation with 0s and then copy that over. + match dest.layout.abi { + layout::Abi::Scalar(..) => { + let x = ScalarMaybeUndef::Undef; + self.write_value(Value::Scalar(x), dest)?; + } + layout::Abi::ScalarPair(..) => { + let x = ScalarMaybeUndef::Undef; + self.write_value(Value::ScalarPair(x, x), dest)?; + } + _ => { + // Do it in memory + let mplace = self.force_allocation(dest)?; + assert_eq!(mplace.extra, PlaceExtra::None); + self.memory.mark_definedness(mplace.ptr, dest.layout.size, false)?; } } } @@ -646,9 +592,9 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: "write_bytes" => { 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)?.unwrap_or_err()?; - let count = self.value_to_usize(args[2])?; + let val_byte = self.read_scalar(args[1])?.to_u8()?; + let ptr = self.read_scalar(args[0])?.not_undef()?; + let count = self.read_scalar(args[2])?.to_usize(&self)?; 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) diff --git a/src/lib.rs b/src/lib.rs index 705f56d38f39d..3680d49836fb5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -27,6 +27,7 @@ use rustc_data_structures::fx::FxHasher; use syntax::ast::Mutability; use syntax::codemap::Span; +use std::marker::PhantomData; use std::collections::{HashMap, BTreeMap}; use std::hash::{Hash, Hasher}; @@ -41,81 +42,14 @@ mod memory; mod tls; mod locks; mod range_map; -mod validation; use fn_call::EvalContextExt as MissingFnsEvalContextExt; use operator::EvalContextExt as OperatorEvalContextExt; use intrinsic::EvalContextExt as IntrinsicEvalContextExt; use tls::EvalContextExt as TlsEvalContextExt; use locks::LockInfo; -use locks::MemoryExt as LockMemoryExt; -use validation::EvalContextExt as ValidationEvalContextExt; use range_map::RangeMap; -use validation::{ValidationQuery, AbsPlace}; - -pub trait ScalarExt { - fn null(size: Size) -> Self; - fn from_i32(i: i32) -> Self; - fn from_uint(i: impl Into, ptr_size: Size) -> Self; - fn from_int(i: impl Into, ptr_size: Size) -> Self; - fn from_f32(f: f32) -> Self; - fn from_f64(f: f64) -> Self; - fn to_usize<'a, 'mir, 'tcx>(self, ecx: &rustc_mir::interpret::EvalContext<'a, 'mir, 'tcx, Evaluator<'tcx>>) -> EvalResult<'static, u64>; - fn is_null(self) -> 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 - fn to_bytes(self) -> EvalResult<'static, u128>; -} - -impl ScalarExt for Scalar { - 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, size: 4 } - } - - fn from_uint(i: impl Into, ptr_size: Size) -> Self { - Scalar::Bits { bits: i.into(), size: ptr_size.bytes() as u8 } - } - - fn from_int(i: impl Into, ptr_size: Size) -> Self { - Scalar::Bits { bits: i.into() as u128, size: ptr_size.bytes() as u8 } - } - - fn from_f32(f: f32) -> Self { - Scalar::Bits { bits: f.to_bits() as u128, size: 4 } - } - - fn from_f64(f: f64) -> Self { - 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> { - let b = self.to_bits(ecx.memory.pointer_size())?; - assert_eq!(b as u64 as u128, b); - Ok(b as u64) - } - - fn is_null(self) -> bool { - match self { - Scalar::Bits { bits, .. } => bits == 0, - Scalar::Ptr(_) => false - } - } - - fn to_bytes(self) -> EvalResult<'static, u128> { - match self { - Scalar::Bits { bits, size } => { - assert_ne!(size, 0); - Ok(bits) - }, - Scalar::Ptr(_) => err!(ReadPointerAsBytes), - } - } -} +use helpers::{ScalarExt, FalibleScalarExt}; pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( tcx: TyCtxt<'a, 'tcx, 'tcx>, @@ -180,31 +114,22 @@ pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( // First argument: pointer to main() let main_ptr = ecx.memory_mut().create_fn_alloc(main_instance); let dest = ecx.eval_place(&mir::Place::Local(args.next().unwrap()))?; - let main_ty = main_instance.ty(ecx.tcx.tcx); - 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).into()), - ty: main_ptr_ty, - }, - dest, - )?; + ecx.write_scalar(Scalar::Ptr(main_ptr), dest)?; // 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_int(1, ptr_size), ty)?; + ecx.write_scalar(Scalar::from_int(1, dest.layout.size), dest)?; // 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_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).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)?; + let foo_ty = ecx.tcx.mk_imm_ptr(ecx.tcx.types.u8); + let foo_layout = ecx.layout_of(foo_ty)?; + let foo_place = ecx.allocate(foo_layout, MemoryKind::Stack)?; + ecx.write_scalar(Scalar::Ptr(foo), foo_place.into())?; + ecx.memory.mark_static_initialized(foo_place.to_ptr()?.alloc_id, Mutability::Immutable)?; + ecx.write_scalar(foo_place.ptr, dest)?; assert!(args.next().is_none(), "start lang item has more arguments than expected"); } else { @@ -293,15 +218,15 @@ pub struct Evaluator<'tcx> { /// Miri does not expose env vars from the host to the emulated program pub(crate) env_vars: HashMap, Pointer>, - /// Places that were suspended by the validation subsystem, and will be recovered later - pub(crate) suspended: HashMap>>, + /// Use the lifetime + _dummy : PhantomData<&'tcx ()>, } impl<'tcx> Hash for Evaluator<'tcx> { fn hash(&self, state: &mut H) { let Evaluator { env_vars, - suspended: _, + _dummy: _, } = self; env_vars.iter() @@ -373,34 +298,32 @@ impl<'mir, 'tcx: 'mir> Machine<'mir, 'tcx> for Evaluator<'tcx> { fn eval_fn_call<'a>( ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, instance: ty::Instance<'tcx>, - destination: Option<(Place, mir::BasicBlock)>, - args: &[ValTy<'tcx>], + destination: Option<(PlaceTy<'tcx>, mir::BasicBlock)>, + args: &[OpTy<'tcx>], span: Span, - sig: ty::FnSig<'tcx>, ) -> EvalResult<'tcx, bool> { - ecx.eval_fn_call(instance, destination, args, span, sig) + ecx.eval_fn_call(instance, destination, args, span) } fn call_intrinsic<'a>( ecx: &mut rustc_mir::interpret::EvalContext<'a, 'mir, 'tcx, Self>, instance: ty::Instance<'tcx>, - args: &[ValTy<'tcx>], - dest: Place, - dest_layout: TyLayout<'tcx>, + args: &[OpTy<'tcx>], + dest: PlaceTy<'tcx>, target: mir::BasicBlock, ) -> EvalResult<'tcx> { - ecx.call_intrinsic(instance, args, dest, dest_layout, target) + ecx.call_intrinsic(instance, args, dest, target) } fn try_ptr_op<'a>( ecx: &rustc_mir::interpret::EvalContext<'a, 'mir, 'tcx, Self>, bin_op: mir::BinOp, left: Scalar, - left_ty: ty::Ty<'tcx>, + left_layout: TyLayout<'tcx>, right: Scalar, - right_ty: ty::Ty<'tcx>, + right_layout: TyLayout<'tcx>, ) -> EvalResult<'tcx, Option<(Scalar, bool)>> { - ecx.ptr_op(bin_op, left, left_ty, right, right_ty) + ecx.ptr_op(bin_op, left, left_layout, right, right_layout) } fn mark_static_initialized<'a>( @@ -460,14 +383,16 @@ impl<'mir, 'tcx: 'mir> Machine<'mir, 'tcx> for Evaluator<'tcx> { let call_stackframe = ecx.stack().len(); while ecx.step()? && ecx.stack().len() >= call_stackframe { if ecx.stack().len() == call_stackframe { - let frame = ecx.frame_mut(); - let bb = &frame.mir.basic_blocks()[frame.block]; - if bb.statements.len() == frame.stmt && !bb.is_cleanup { - if let ::rustc::mir::TerminatorKind::Return = bb.terminator().kind { - for (local, _local_decl) in mir.local_decls.iter_enumerated().skip(1) { - // Don't deallocate locals, because the return value might reference them - frame.storage_dead(local); - } + let cleanup = { + let frame = ecx.frame(); + let bb = &frame.mir.basic_blocks()[frame.block]; + bb.statements.len() == frame.stmt && !bb.is_cleanup && + if let ::rustc::mir::TerminatorKind::Return = bb.terminator().kind { true } else { false } + }; + if cleanup { + for (local, _local_decl) in mir.local_decls.iter_enumerated().skip(1) { + // Don't deallocate locals, because the return value might reference them + ecx.storage_dead(local); } } } @@ -481,11 +406,9 @@ impl<'mir, 'tcx: 'mir> Machine<'mir, 'tcx> for Evaluator<'tcx> { fn box_alloc<'a>( ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, - ty: ty::Ty<'tcx>, - dest: Place, + dest: PlaceTy<'tcx>, ) -> EvalResult<'tcx> { - let layout = ecx.layout_of(ty)?; - + trace!("box_alloc for {:?}", dest.layout.ty); // Call the `exchange_malloc` lang item let malloc = ecx.tcx.lang_items().exchange_malloc_fn().unwrap(); let malloc = ty::Instance::mono(ecx.tcx.tcx, malloc); @@ -494,7 +417,7 @@ impl<'mir, 'tcx: 'mir> Machine<'mir, 'tcx> for Evaluator<'tcx> { malloc, malloc_mir.span, malloc_mir, - dest, + *dest, // Don't do anything when we are done. The statement() function will increment // the old stack frame's stmt counter to the next statement, which means that when // exchange_malloc returns, we go on evaluating exactly where we want to be. @@ -502,31 +425,18 @@ 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(); + let layout = ecx.layout_of(dest.layout.ty.builtin_deref(false).unwrap().ty)?; // First argument: size - let dest = ecx.eval_place(&mir::Place::Local(args.next().unwrap()))?; - ecx.write_value( - ValTy { - value: Value::Scalar(Scalar::from_uint(match layout.size.bytes() { - 0 => 1, - size => size, - }, ptr_size).into()), - ty: usize, - }, - dest, - )?; + // (0 is allowed here, this is expected to be handled by the lang item) + let arg = ecx.eval_place(&mir::Place::Local(args.next().unwrap()))?; + let size = layout.size.bytes(); + ecx.write_scalar(Scalar::from_uint(size, arg.layout.size), arg)?; // Second argument: align - let dest = ecx.eval_place(&mir::Place::Local(args.next().unwrap()))?; - ecx.write_value( - ValTy { - value: Value::Scalar(Scalar::from_uint(layout.align.abi(), ptr_size).into()), - ty: usize, - }, - dest, - )?; + let arg = ecx.eval_place(&mir::Place::Local(args.next().unwrap()))?; + let align = layout.align.abi(); + ecx.write_scalar(Scalar::from_uint(align, arg.layout.size), arg)?; // No more arguments assert!(args.next().is_none(), "exchange_malloc lang item has more arguments than expected"); @@ -542,52 +452,32 @@ impl<'mir, 'tcx: 'mir> Machine<'mir, 'tcx> for Evaluator<'tcx> { } fn check_locks<'a>( - mem: &Memory<'a, 'mir, 'tcx, Self>, - ptr: Pointer, - size: Size, - access: AccessKind, + _mem: &Memory<'a, 'mir, 'tcx, Self>, + _ptr: Pointer, + _size: Size, + _access: AccessKind, ) -> EvalResult<'tcx> { - mem.check_locks(ptr, size.bytes(), access) + Ok(()) } fn add_lock<'a>( - mem: &mut Memory<'a, 'mir, 'tcx, Self>, - id: AllocId, - ) { - mem.data.locks.insert(id, RangeMap::new()); - } + _mem: &mut Memory<'a, 'mir, 'tcx, Self>, + _id: AllocId, + ) { } fn free_lock<'a>( - mem: &mut Memory<'a, 'mir, 'tcx, Self>, - id: AllocId, - len: u64, + _mem: &mut Memory<'a, 'mir, 'tcx, Self>, + _id: AllocId, + _len: u64, ) -> EvalResult<'tcx> { - mem.data.locks - .remove(&id) - .expect("allocation has no corresponding locks") - .check( - Some(mem.cur_frame), - 0, - len, - AccessKind::Read, - ) - .map_err(|lock| { - EvalErrorKind::DeallocatedLockedMemory { - //ptr, FIXME - ptr: Pointer { - alloc_id: AllocId(0), - offset: Size::from_bytes(0), - }, - lock: lock.active, - }.into() - }) + Ok(()) } fn end_region<'a>( - ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, - reg: Option<::rustc::middle::region::Scope>, + _ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, + _reg: Option<::rustc::middle::region::Scope>, ) -> EvalResult<'tcx> { - ecx.end_region(reg) + Ok(()) } fn validation_op<'a>( diff --git a/src/locks.rs b/src/locks.rs index 9f4126ad82b60..a87ff6367e3ad 100644 --- a/src/locks.rs +++ b/src/locks.rs @@ -1,3 +1,5 @@ +#![allow(unused)] + use super::*; use rustc::middle::region; use rustc::ty::layout::Size; @@ -6,6 +8,9 @@ use rustc::ty::layout::Size; // Locks //////////////////////////////////////////////////////////////////////////////// +// Just some dummy to keep this compiling; I think some of this will be useful later +type AbsPlace<'tcx> = ::rustc::ty::Ty<'tcx>; + /// Information about a lock that is currently held. #[derive(Clone, Debug, PartialEq, Eq)] pub struct LockInfo<'tcx> { @@ -67,321 +72,6 @@ impl<'tcx> LockInfo<'tcx> { } } -pub trait MemoryExt<'tcx> { - fn check_locks( - &self, - ptr: Pointer, - len: u64, - access: AccessKind, - ) -> EvalResult<'tcx>; - fn acquire_lock( - &mut self, - ptr: Pointer, - len: u64, - region: Option, - kind: AccessKind, - ) -> EvalResult<'tcx>; - fn suspend_write_lock( - &mut self, - ptr: Pointer, - len: u64, - lock_path: &AbsPlace<'tcx>, - suspend: Option, - ) -> EvalResult<'tcx>; - fn recover_write_lock( - &mut self, - ptr: Pointer, - len: u64, - lock_path: &AbsPlace<'tcx>, - lock_region: Option, - suspended_region: region::Scope, - ) -> EvalResult<'tcx>; - fn locks_lifetime_ended(&mut self, ending_region: Option); -} - - -impl<'a, 'mir, 'tcx: 'mir + 'a> MemoryExt<'tcx> for Memory<'a, 'mir, 'tcx, Evaluator<'tcx>> { - fn check_locks( - &self, - ptr: Pointer, - len: u64, - access: AccessKind, - ) -> EvalResult<'tcx> { - if len == 0 { - return Ok(()); - } - let locks = match self.data.locks.get(&ptr.alloc_id) { - Some(locks) => locks, - // immutable static or other constant memory - None => return Ok(()), - }; - let frame = self.cur_frame; - locks - .check(Some(frame), ptr.offset.bytes(), len, access) - .map_err(|lock| { - EvalErrorKind::MemoryLockViolation { - ptr, - len, - frame, - access, - lock: lock.active, - }.into() - }) - } - - /// Acquire the lock for the given lifetime - fn acquire_lock( - &mut self, - ptr: Pointer, - len: u64, - region: Option, - kind: AccessKind, - ) -> EvalResult<'tcx> { - let frame = self.cur_frame; - assert!(len > 0); - trace!( - "Frame {} acquiring {:?} lock at {:?}, size {} for region {:?}", - frame, - kind, - ptr, - len, - region - ); - self.check_bounds(ptr.offset(Size::from_bytes(len), &*self)?, true)?; // if ptr.offset is in bounds, then so is ptr (because offset checks for overflow) - - let locks = match self.data.locks.get_mut(&ptr.alloc_id) { - Some(locks) => locks, - // immutable static or other constant memory - None => return Ok(()), - }; - - // Iterate over our range and acquire the lock. If the range is already split into pieces, - // we have to manipulate all of them. - let lifetime = DynamicLifetime { frame, region }; - for lock in locks.iter_mut(ptr.offset.bytes(), len) { - if !lock.access_permitted(None, kind) { - return err!(MemoryAcquireConflict { - ptr, - len, - kind, - lock: lock.active.clone(), - }); - } - // See what we have to do - match (&mut lock.active, kind) { - (active @ &mut NoLock, AccessKind::Write) => { - *active = WriteLock(lifetime); - } - (active @ &mut NoLock, AccessKind::Read) => { - *active = ReadLock(vec![lifetime]); - } - (&mut ReadLock(ref mut lifetimes), AccessKind::Read) => { - lifetimes.push(lifetime); - } - _ => bug!("We already checked that there is no conflicting lock"), - } - } - Ok(()) - } - - /// Release or suspend a write lock of the given lifetime prematurely. - /// When releasing, if there is a read lock or someone else's write lock, that's an error. - /// If no lock is held, that's fine. This can happen when e.g. a local is initialized - /// from a constant, and then suspended. - /// When suspending, the same cases are fine; we just register an additional suspension. - fn suspend_write_lock( - &mut self, - ptr: Pointer, - len: u64, - lock_path: &AbsPlace<'tcx>, - suspend: Option, - ) -> EvalResult<'tcx> { - assert!(len > 0); - let cur_frame = self.cur_frame; - let locks = match self.data.locks.get_mut(&ptr.alloc_id) { - Some(locks) => locks, - // immutable static or other constant memory - None => return Ok(()), - }; - - 'locks: for lock in locks.iter_mut(ptr.offset.bytes(), len) { - let is_our_lock = match lock.active { - WriteLock(lft) => - // Double-check that we are holding the lock. - // (Due to subtyping, checking the region would not make any sense.) - lft.frame == cur_frame, - ReadLock(_) | NoLock => false, - }; - if is_our_lock { - trace!("Releasing {:?}", lock.active); - // Disable the lock - lock.active = NoLock; - } else { - trace!( - "Not touching {:?} as it is not our lock", - lock.active, - ); - } - // Check if we want to register a suspension - if let Some(suspend_region) = suspend { - let lock_id = WriteLockId { - frame: cur_frame, - path: lock_path.clone(), - }; - trace!("Adding suspension to {:?}", lock_id); - let mut new_suspension = false; - lock.suspended - .entry(lock_id) - // Remember whether we added a new suspension or not - .or_insert_with(|| { new_suspension = true; Vec::new() }) - .push(suspend_region); - // If the suspension is new, we should have owned this. - // If there already was a suspension, we should NOT have owned this. - if new_suspension == is_our_lock { - // All is well - continue 'locks; - } - } else if !is_our_lock { - // All is well. - continue 'locks; - } - // If we get here, releasing this is an error except for NoLock. - if lock.active != NoLock { - return err!(InvalidMemoryLockRelease { - ptr, - len, - frame: cur_frame, - lock: lock.active.clone(), - }); - } - } - - Ok(()) - } - - /// Release a suspension from the write lock. If this is the last suspension or if there is no suspension, acquire the lock. - fn recover_write_lock( - &mut self, - ptr: Pointer, - len: u64, - lock_path: &AbsPlace<'tcx>, - lock_region: Option, - suspended_region: region::Scope, - ) -> EvalResult<'tcx> { - assert!(len > 0); - let cur_frame = self.cur_frame; - let lock_id = WriteLockId { - frame: cur_frame, - path: lock_path.clone(), - }; - let locks = match self.data.locks.get_mut(&ptr.alloc_id) { - Some(locks) => locks, - // immutable static or other constant memory - None => return Ok(()), - }; - - for lock in locks.iter_mut(ptr.offset.bytes(), len) { - // Check if we have a suspension here - let (got_the_lock, remove_suspension) = match lock.suspended.get_mut(&lock_id) { - None => { - trace!("No suspension around, we can just acquire"); - (true, false) - } - Some(suspensions) => { - trace!("Found suspension of {:?}, removing it", lock_id); - // That's us! Remove suspension (it should be in there). The same suspension can - // occur multiple times (when there are multiple shared borrows of this that have the same - // lifetime); only remove one of them. - let idx = match suspensions.iter().enumerate().find(|&(_, re)| re == &suspended_region) { - None => // TODO: Can the user trigger this? - bug!("We have this lock suspended, but not for the given region."), - Some((idx, _)) => idx - }; - suspensions.remove(idx); - let got_lock = suspensions.is_empty(); - if got_lock { - trace!("All suspensions are gone, we can have the lock again"); - } - (got_lock, got_lock) - } - }; - if remove_suspension { - // with NLL, we could do that up in the match above... - assert!(got_the_lock); - lock.suspended.remove(&lock_id); - } - if got_the_lock { - match lock.active { - ref mut active @ NoLock => { - *active = WriteLock( - DynamicLifetime { - frame: cur_frame, - region: lock_region, - } - ); - } - _ => { - return err!(MemoryAcquireConflict { - ptr, - len, - kind: AccessKind::Write, - lock: lock.active.clone(), - }) - } - } - } - } - - Ok(()) - } - - fn locks_lifetime_ended(&mut self, ending_region: Option) { - let cur_frame = self.cur_frame; - trace!( - "Releasing frame {} locks that expire at {:?}", - cur_frame, - ending_region - ); - let has_ended = |lifetime: &DynamicLifetime| -> bool { - if lifetime.frame != cur_frame { - return false; - } - match ending_region { - None => true, // When a function ends, we end *all* its locks. It's okay for a function to still have lifetime-related locks - // when it returns, that can happen e.g. with NLL when a lifetime can, but does not have to, extend beyond the - // end of a function. Same for a function still having recoveries. - Some(ending_region) => lifetime.region == Some(ending_region), - } - }; - - for alloc_locks in self.data.locks.values_mut() { - for lock in alloc_locks.iter_mut_all() { - // Delete everything that ends now -- i.e., keep only all the other lifetimes. - let lock_ended = match lock.active { - WriteLock(ref lft) => has_ended(lft), - ReadLock(ref mut lfts) => { - lfts.retain(|lft| !has_ended(lft)); - lfts.is_empty() - } - NoLock => false, - }; - if lock_ended { - lock.active = NoLock; - } - // Also clean up suspended write locks when the function returns - if ending_region.is_none() { - lock.suspended.retain(|id, _suspensions| id.frame != cur_frame); - } - } - // Clean up the map - alloc_locks.retain(|lock| match lock.active { - NoLock => !lock.suspended.is_empty(), - _ => true, - }); - } - } -} - impl<'tcx> RangeMap> { pub fn check( &self, diff --git a/src/operator.rs b/src/operator.rs index 7be77771a7caf..3ff38008abd0b 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -1,19 +1,17 @@ -use rustc::ty; -use rustc::ty::layout::Primitive; +use rustc::ty::{self, Ty}; +use rustc::ty::layout::{TyLayout, Primitive}; use rustc::mir; use super::*; -use helpers::EvalContextExt as HelperEvalContextExt; - pub trait EvalContextExt<'tcx> { fn ptr_op( &self, bin_op: mir::BinOp, left: Scalar, - left_ty: ty::Ty<'tcx>, + left_layout: TyLayout<'tcx>, right: Scalar, - right_ty: ty::Ty<'tcx>, + right_layout: TyLayout<'tcx>, ) -> EvalResult<'tcx, Option<(Scalar, bool)>>; fn ptr_int_arithmetic( @@ -23,6 +21,13 @@ pub trait EvalContextExt<'tcx> { right: i128, signed: bool, ) -> EvalResult<'tcx, (Scalar, bool)>; + + fn pointer_offset_inbounds( + &self, + ptr: Scalar, + pointee_ty: Ty<'tcx>, + offset: i64, + ) -> EvalResult<'tcx, Scalar>; } impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super::Evaluator<'tcx>> { @@ -30,9 +35,9 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: &self, bin_op: mir::BinOp, left: Scalar, - left_ty: ty::Ty<'tcx>, + left_layout: TyLayout<'tcx>, right: Scalar, - right_ty: ty::Ty<'tcx>, + right_layout: TyLayout<'tcx>, ) -> EvalResult<'tcx, Option<(Scalar, bool)>> { trace!("ptr_op: {:?} {:?} {:?}", left, bin_op, right); @@ -45,7 +50,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: 8 => I64, 16 => I128, _ => unreachable!(), - }, false); + }, /*signed*/ false); let isize = Primitive::Int(match self.memory.pointer_size().bytes() { 1 => I8, 2 => I16, @@ -53,24 +58,23 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: 8 => I64, 16 => I128, _ => unreachable!(), - }, true); - let left_layout = self.layout_of(left_ty)?; + }, /*signed*/ true); let left_kind = match left_layout.abi { ty::layout::Abi::Scalar(ref scalar) => scalar.value, - _ => Err(EvalErrorKind::TypeNotPrimitive(left_ty))?, + _ => Err(EvalErrorKind::TypeNotPrimitive(left_layout.ty))?, }; - let right_layout = self.layout_of(right_ty)?; let right_kind = match right_layout.abi { ty::layout::Abi::Scalar(ref scalar) => scalar.value, - _ => Err(EvalErrorKind::TypeNotPrimitive(right_ty))?, + _ => Err(EvalErrorKind::TypeNotPrimitive(right_layout.ty))?, }; match bin_op { - Offset if left_kind == Primitive::Pointer && right_kind == usize => { - let pointee_ty = left_ty + Offset => { + assert!(left_kind == Primitive::Pointer && right_kind == usize); + let pointee_ty = left_layout.ty .builtin_deref(true) .expect("Offset called on non-ptr type") .ty; - let ptr = self.pointer_offset( + let ptr = self.pointer_offset_inbounds( left, pointee_ty, right.to_bits(self.memory.pointer_size())? as i64, @@ -114,12 +118,13 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: Gt => left.offset > right.offset, Ge => left.offset >= right.offset, Sub => { + let left_offset = Scalar::from_uint(left.offset.bytes(), self.memory.pointer_size()); + let right_offset = Scalar::from_uint(right.offset.bytes(), self.memory.pointer_size()); + let layout = self.layout_of(self.tcx.types.usize)?; return self.binary_op( Sub, - 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, size: self.memory.pointer_size().bytes() as u8 }, - self.tcx.types.usize, + ValTy { value: Value::Scalar(left_offset.into()), layout }, + ValTy { value: Value::Scalar(right_offset.into()), layout }, ).map(Some) } _ => bug!("We already established it has to be one of these operators."), @@ -200,4 +205,40 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: } }) } + + /// This function raises an error if the offset moves the pointer outside of its allocation. We consider + /// ZSTs their own huge allocation that doesn't overlap with anything (and nothing moves in there because the size is 0). + /// We also consider the NULL pointer its own separate allocation, and all the remaining integers pointers their own + /// allocation. + fn pointer_offset_inbounds( + &self, + ptr: Scalar, + pointee_ty: Ty<'tcx>, + offset: i64, + ) -> EvalResult<'tcx, Scalar> { + if ptr.is_null() { + // NULL pointers must only be offset by 0 + return if offset == 0 { + Ok(ptr) + } else { + err!(InvalidNullPointerUsage) + }; + } + // 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.checked_mul(pointee_size).ok_or_else(|| EvalErrorKind::Overflow(mir::BinOp::Mul))?; + // Now let's see what kind of pointer this is + if let Scalar::Ptr(ptr) = ptr { + // Both old and new pointer must be in-bounds. + // (Of the same allocation, but that part is trivial with our representation.) + self.memory.check_bounds(ptr, false)?; + let ptr = ptr.signed_offset(offset, self)?; + self.memory.check_bounds(ptr, false)?; + Ok(Scalar::Ptr(ptr)) + } else { + // An integer pointer. They can move around freely, as long as they do not overflow + // (which ptr_signed_offset checks). + ptr.ptr_signed_offset(offset, self) + } + } } diff --git a/src/range_map.rs b/src/range_map.rs index 76d01ad19e3ab..e55534e36fd2e 100644 --- a/src/range_map.rs +++ b/src/range_map.rs @@ -1,3 +1,5 @@ +#![allow(unused)] + //! Implements a map from integer indices to data. //! Rather than storing data for every index, internally, this maps entire ranges to the data. //! To this end, the APIs all work on ranges, not on individual integers. Ranges are split as diff --git a/src/tls.rs b/src/tls.rs index 9f0fb2c8f62a1..878884065bb71 100644 --- a/src/tls.rs +++ b/src/tls.rs @@ -119,19 +119,19 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' // TODO: Potentially, this has to support all the other possible instances? // See eval_fn_call in interpret/terminator/mod.rs let mir = self.load_mir(instance.def)?; + let ret = Place::null(&self); self.push_stack_frame( instance, mir.span, mir, - Place::undef(), + ret, StackPopCleanup::None, )?; let arg_local = self.frame().mir.args_iter().next().ok_or_else( || EvalErrorKind::AbiViolation("TLS dtor does not take enough arguments.".to_owned()), )?; let dest = self.eval_place(&mir::Place::Local(arg_local))?; - let ty = self.tcx.mk_mut_ptr(self.tcx.types.u8); - self.write_ptr(dest, ptr, ty)?; + self.write_scalar(ptr, dest)?; // step until out of stackframes while self.step()? {} diff --git a/src/validation.rs b/src/validation.rs deleted file mode 100644 index 7f0abb9ae0bad..0000000000000 --- a/src/validation.rs +++ /dev/null @@ -1,803 +0,0 @@ -use rustc::hir::{self, Mutability}; -use rustc::hir::Mutability::*; -use rustc::mir::{self, ValidationOp, ValidationOperand}; -use rustc::mir::interpret::GlobalId; -use rustc::ty::{self, Ty, TypeFoldable, TyCtxt, Instance}; -use rustc::ty::layout::{LayoutOf, PrimitiveExt}; -use rustc::ty::subst::{Substs, Subst}; -use rustc::traits::{self, TraitEngine}; -use rustc::infer::InferCtxt; -use rustc::middle::region; -use rustc::mir::interpret::{ConstValue}; -use rustc_data_structures::indexed_vec::Idx; -use rustc_mir::interpret::HasMemory; - -use super::{EvalContext, Place, PlaceExtra, ValTy, ScalarExt}; -use rustc::mir::interpret::{DynamicLifetime, AccessKind, EvalErrorKind, Value, EvalError, EvalResult}; -use locks::MemoryExt; - -pub type ValidationQuery<'tcx> = ValidationOperand<'tcx, (AbsPlace<'tcx>, Place)>; - -#[derive(Copy, Clone, Debug, PartialEq)] -pub(crate) enum ValidationMode { - Acquire, - /// Recover because the given region ended - Recover(region::Scope), - ReleaseUntil(Option), -} - -impl ValidationMode { - fn acquiring(self) -> bool { - use self::ValidationMode::*; - match self { - Acquire | Recover(_) => true, - ReleaseUntil(_) => false, - } - } -} - -// Abstract places -#[derive(Clone, Debug, PartialEq, Eq, Hash)] -pub enum AbsPlace<'tcx> { - Local(mir::Local), - Static(hir::def_id::DefId), - Projection(Box>), -} - -type AbsPlaceProjection<'tcx> = mir::Projection<'tcx, AbsPlace<'tcx>, u64, ()>; -type AbsPlaceElem<'tcx> = mir::ProjectionElem<'tcx, u64, ()>; - -impl<'tcx> AbsPlace<'tcx> { - pub fn field(self, f: mir::Field) -> AbsPlace<'tcx> { - self.elem(mir::ProjectionElem::Field(f, ())) - } - - pub fn deref(self) -> AbsPlace<'tcx> { - self.elem(mir::ProjectionElem::Deref) - } - - pub fn downcast(self, adt_def: &'tcx ty::AdtDef, variant_index: usize) -> AbsPlace<'tcx> { - self.elem(mir::ProjectionElem::Downcast(adt_def, variant_index)) - } - - pub fn index(self, index: u64) -> AbsPlace<'tcx> { - self.elem(mir::ProjectionElem::Index(index)) - } - - fn elem(self, elem: AbsPlaceElem<'tcx>) -> AbsPlace<'tcx> { - AbsPlace::Projection(Box::new(AbsPlaceProjection { - base: self, - elem, - })) - } -} - -pub(crate) trait EvalContextExt<'tcx> { - fn abstract_place_projection(&self, proj: &mir::PlaceProjection<'tcx>) -> EvalResult<'tcx, AbsPlaceProjection<'tcx>>; - fn abstract_place(&self, place: &mir::Place<'tcx>) -> EvalResult<'tcx, AbsPlace<'tcx>>; - fn validation_op( - &mut self, - op: ValidationOp, - operand: &ValidationOperand<'tcx, mir::Place<'tcx>>, - ) -> EvalResult<'tcx>; - fn end_region(&mut self, scope: Option) -> EvalResult<'tcx>; - fn normalize_type_unerased(&self, ty: Ty<'tcx>) -> Ty<'tcx>; - fn field_with_lifetimes( - &mut self, - base: Place, - layout: ty::layout::TyLayout<'tcx>, - i: usize, - ) -> EvalResult<'tcx, Ty<'tcx>>; - fn validate_fields( - &mut self, - query: ValidationQuery<'tcx>, - mode: ValidationMode, - ) -> EvalResult<'tcx>; - fn validate_ptr( - &mut self, - val: Value, - abs_place: AbsPlace<'tcx>, - pointee_ty: Ty<'tcx>, - re: Option, - mutbl: Mutability, - mode: ValidationMode, - ) -> EvalResult<'tcx>; - fn validate( - &mut self, - query: ValidationQuery<'tcx>, - mode: ValidationMode, - ) -> EvalResult<'tcx>; -} - -impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super::Evaluator<'tcx>> { - fn abstract_place_projection(&self, proj: &mir::PlaceProjection<'tcx>) -> EvalResult<'tcx, AbsPlaceProjection<'tcx>> { - use self::mir::ProjectionElem::*; - - let elem = match proj.elem { - Deref => Deref, - Field(f, _) => Field(f, ()), - Index(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) - }, - ConstantIndex { offset, min_length, from_end } => - ConstantIndex { offset, min_length, from_end }, - Subslice { from, to } => - Subslice { from, to }, - Downcast(adt, sz) => Downcast(adt, sz), - }; - Ok(AbsPlaceProjection { - base: self.abstract_place(&proj.base)?, - elem - }) - } - - fn abstract_place(&self, place: &mir::Place<'tcx>) -> EvalResult<'tcx, AbsPlace<'tcx>> { - Ok(match *place { - mir::Place::Local(l) => AbsPlace::Local(l), - mir::Place::Static(ref s) => AbsPlace::Static(s.def_id), - mir::Place::Projection(ref p) => - AbsPlace::Projection(Box::new(self.abstract_place_projection(&*p)?)), - _ => unimplemented!("validation is not currently maintained"), - }) - } - - // Validity checks - fn validation_op( - &mut self, - op: ValidationOp, - operand: &ValidationOperand<'tcx, mir::Place<'tcx>>, - ) -> EvalResult<'tcx> { - // If mir-emit-validate is set to 0 (i.e., disabled), we may still see validation commands - // because other crates may have been compiled with mir-emit-validate > 0. Ignore those - // commands. This makes mir-emit-validate also a flag to control whether miri will do - // validation or not. - if self.tcx.tcx.sess.opts.debugging_opts.mir_emit_validate == 0 { - return Ok(()); - } - debug_assert!(self.memory.cur_frame == self.cur_frame()); - - // We need to monomorphize ty *without* erasing lifetimes - trace!("validation_op1: {:?}", operand.ty.sty); - let ty = operand.ty.subst(self.tcx.tcx, self.substs()); - trace!("validation_op2: {:?}", operand.ty.sty); - let place = self.eval_place(&operand.place)?; - let abs_place = self.abstract_place(&operand.place)?; - let query = ValidationQuery { - place: (abs_place, place), - ty, - re: operand.re, - mutbl: operand.mutbl, - }; - - // Check the mode, and also perform mode-specific operations - let mode = match op { - ValidationOp::Acquire => ValidationMode::Acquire, - ValidationOp::Release => ValidationMode::ReleaseUntil(None), - ValidationOp::Suspend(scope) => { - if query.mutbl == MutMutable { - let lft = DynamicLifetime { - frame: self.cur_frame(), - region: Some(scope), // Notably, we only ever suspend things for given regions. - // Suspending for the entire function does not make any sense. - }; - trace!("Suspending {:?} until {:?}", query, scope); - self.machine.suspended.entry(lft).or_insert_with(Vec::new).push( - query.clone(), - ); - } - ValidationMode::ReleaseUntil(Some(scope)) - } - }; - self.validate(query, mode) - } - - /// Release locks and executes suspensions of the given region (or the entire fn, in case of None). - fn end_region(&mut self, scope: Option) -> EvalResult<'tcx> { - debug_assert!(self.memory.cur_frame == self.cur_frame()); - self.memory.locks_lifetime_ended(scope); - match scope { - Some(scope) => { - // Recover suspended places - let lft = DynamicLifetime { - frame: self.cur_frame(), - region: Some(scope), - }; - if let Some(queries) = self.machine.suspended.remove(&lft) { - for query in queries { - trace!("Recovering {:?} from suspension", query); - self.validate(query, ValidationMode::Recover(scope))?; - } - } - } - None => { - // Clean suspension table of current frame - let cur_frame = self.cur_frame(); - self.machine.suspended.retain(|lft, _| { - lft.frame != cur_frame // keep only what is in the other (lower) frames - }); - } - } - Ok(()) - } - - fn normalize_type_unerased(&self, ty: Ty<'tcx>) -> Ty<'tcx> { - return normalize_associated_type(self.tcx.tcx, &ty); - - use syntax::codemap::{Span, DUMMY_SP}; - - // We copy a bunch of stuff from rustc/infer/mod.rs to be able to tweak its behavior - fn normalize_projections_in<'a, 'gcx, 'tcx, T>( - self_: &InferCtxt<'a, 'gcx, 'tcx>, - param_env: ty::ParamEnv<'tcx>, - value: &T, - ) -> T::Lifted - where - T: TypeFoldable<'tcx> + ty::Lift<'gcx>, - { - let mut selcx = traits::SelectionContext::new(self_); - let cause = traits::ObligationCause::dummy(); - let traits::Normalized { - value: result, - obligations, - } = traits::normalize(&mut selcx, param_env, cause, value); - - let mut fulfill_cx = traits::FulfillmentContext::new(); - - for obligation in obligations { - fulfill_cx.register_predicate_obligation(self_, obligation); - } - - drain_fulfillment_cx_or_panic(self_, DUMMY_SP, &mut fulfill_cx, &result) - } - - fn drain_fulfillment_cx_or_panic<'a, 'gcx, 'tcx, T>( - self_: &InferCtxt<'a, 'gcx, 'tcx>, - span: Span, - fulfill_cx: &mut traits::FulfillmentContext<'tcx>, - result: &T, - ) -> T::Lifted - where - T: TypeFoldable<'tcx> + ty::Lift<'gcx>, - { - // In principle, we only need to do this so long as `result` - // contains unbound type parameters. It could be a slight - // optimization to stop iterating early. - match fulfill_cx.select_all_or_error(self_) { - Ok(()) => { } - Err(errors) => { - span_bug!( - span, - "Encountered errors `{:?}` resolving bounds after type-checking", - errors - ); - } - } - - let result = self_.resolve_type_vars_if_possible(result); - let result = self_.tcx.fold_regions( - &result, - &mut false, - |r, _| match *r { - ty::ReVar(_) => self_.tcx.types.re_erased, - _ => r, - }, - ); - - match self_.tcx.lift_to_global(&result) { - Some(result) => result, - None => { - span_bug!(span, "Uninferred types/regions in `{:?}`", result); - } - } - } - - trait MyTransNormalize<'gcx>: TypeFoldable<'gcx> { - fn my_trans_normalize<'a, 'tcx>( - &self, - infcx: &InferCtxt<'a, 'gcx, 'tcx>, - param_env: ty::ParamEnv<'tcx>, - ) -> Self; - } - - macro_rules! items { ($($item:item)+) => ($($item)+) } - macro_rules! impl_trans_normalize { - ($lt_gcx:tt, $($ty:ty),+) => { - items!($(impl<$lt_gcx> MyTransNormalize<$lt_gcx> for $ty { - fn my_trans_normalize<'a, 'tcx>(&self, - infcx: &InferCtxt<'a, $lt_gcx, 'tcx>, - param_env: ty::ParamEnv<'tcx>) - -> Self { - normalize_projections_in(infcx, param_env, self) - } - })+); - } - } - - impl_trans_normalize!('gcx, - Ty<'gcx>, - &'gcx Substs<'gcx>, - ty::FnSig<'gcx>, - ty::PolyFnSig<'gcx>, - ty::ClosureSubsts<'gcx>, - ty::PolyTraitRef<'gcx>, - ty::ExistentialTraitRef<'gcx> - ); - - fn normalize_associated_type<'a, 'tcx, T>(self_: TyCtxt<'a, 'tcx, 'tcx>, value: &T) -> T - where - T: MyTransNormalize<'tcx>, - { - let param_env = ty::ParamEnv::reveal_all(); - - if !value.has_projections() { - return value.clone(); - } - - self_.infer_ctxt().enter(|infcx| { - value.my_trans_normalize(&infcx, param_env) - }) - } - } - - // This is a copy of `Layout::field` - // - // FIXME: remove once validation does not depend on lifetimes - fn field_with_lifetimes( - &mut self, - base: Place, - mut layout: ty::layout::TyLayout<'tcx>, - i: usize, - ) -> EvalResult<'tcx, Ty<'tcx>> { - if let Place::Ptr { extra: PlaceExtra::DowncastVariant(variant_index), .. } = base { - layout = layout.for_variant(&self, variant_index); - } - let tcx = self.tcx.tcx; - Ok(match layout.ty.sty { - ty::TyBool | - ty::TyChar | - ty::TyInt(_) | - ty::TyUint(_) | - ty::TyFloat(_) | - ty::TyFnPtr(_) | - ty::TyNever | - ty::TyFnDef(..) | - ty::TyGeneratorWitness(..) | - ty::TyDynamic(..) | - ty::TyForeign(..) => { - bug!("TyLayout::field_type({:?}): not applicable", layout) - } - - // Potentially-fat pointers. - ty::TyRef(_, pointee, _) | - ty::TyRawPtr(ty::TypeAndMut { ty: pointee, .. }) => { - assert!(i < 2); - - // Reuse the fat *T type as its own thin pointer data field. - // This provides information about e.g. DST struct pointees - // (which may have no non-DST form), and will work as long - // as the `Abi` or `FieldPlacement` is checked by users. - if i == 0 { - return Ok(layout.ty); - } - - match tcx.struct_tail(pointee).sty { - ty::TySlice(_) | - ty::TyStr => tcx.types.usize, - ty::TyDynamic(..) => { - // FIXME(eddyb) use an usize/fn() array with - // the correct number of vtables slots. - tcx.mk_imm_ref(tcx.types.re_static, tcx.mk_nil()) - } - _ => bug!("TyLayout::field_type({:?}): not applicable", layout) - } - } - - // Arrays and slices. - ty::TyArray(element, _) | - ty::TySlice(element) => element, - ty::TyStr => tcx.types.u8, - - // Tuples, generators and closures. - ty::TyClosure(def_id, ref substs) => { - substs.upvar_tys(def_id, tcx).nth(i).unwrap() - } - - ty::TyGenerator(def_id, ref substs, _) => { - substs.field_tys(def_id, tcx).nth(i).unwrap() - } - - ty::TyTuple(tys) => tys[i], - - // SIMD vector types. - ty::TyAdt(def, ..) if def.repr.simd() => { - layout.ty.simd_type(tcx) - } - - // ADTs. - ty::TyAdt(def, substs) => { - use rustc::ty::layout::Variants; - match layout.variants { - Variants::Single { index } => { - def.variants[index].fields[i].ty(tcx, substs) - } - - // Discriminant field for enums (where applicable). - Variants::Tagged { tag: ref discr, .. } | - Variants::NicheFilling { niche: ref discr, .. } => { - assert_eq!(i, 0); - return Ok(discr.value.to_ty(tcx)) - } - } - } - - ty::TyProjection(_) | ty::TyAnon(..) | ty::TyParam(_) | - ty::TyInfer(_) | ty::TyError => { - bug!("TyLayout::field_type: unexpected type `{}`", layout.ty) - } - }) - } - - fn validate_fields( - &mut self, - query: ValidationQuery<'tcx>, - mode: ValidationMode, - ) -> EvalResult<'tcx> { - let mut layout = self.layout_of(query.ty)?; - layout.ty = query.ty; - - // TODO: Maybe take visibility/privacy into account. - for idx in 0..layout.fields.count() { - let field = mir::Field::new(idx); - let (field_place, field_layout) = - self.place_field(query.place.1, field, layout)?; - // layout stuff erases lifetimes, get the field ourselves - let field_ty = self.field_with_lifetimes(query.place.1, layout, idx)?; - trace!("assuming \n{:?}\n == \n{:?}\n except for lifetimes", field_layout.ty, field_ty); - self.validate( - ValidationQuery { - place: (query.place.0.clone().field(field), field_place), - ty: field_ty, - ..query - }, - mode, - )?; - } - - Ok(()) - } - - fn validate_ptr( - &mut self, - val: Value, - abs_place: AbsPlace<'tcx>, - pointee_ty: Ty<'tcx>, - re: Option, - mutbl: Mutability, - mode: ValidationMode, - ) -> EvalResult<'tcx> { - // Check alignment and non-NULLness - let (_, align) = self.size_and_align_of_dst(pointee_ty, val)?; - let ptr = self.into_ptr(val)?.unwrap_or_err()?; - self.memory.check_align(ptr, align)?; - - // Recurse - let pointee_place = self.val_to_place(val, pointee_ty)?; - self.validate( - ValidationQuery { - place: (abs_place.deref(), pointee_place), - ty: pointee_ty, - re, - mutbl, - }, - mode, - ) - } - - /// Validate the place at the given type. If `acquire` is false, just do a release of all write locks - fn validate( - &mut self, - mut query: ValidationQuery<'tcx>, - mode: ValidationMode, - ) -> EvalResult<'tcx> { - use rustc::ty::TypeVariants::*; - use rustc::ty::RegionKind::*; - use rustc::ty::AdtKind; - - // No point releasing shared stuff. - if !mode.acquiring() && query.mutbl == MutImmutable { - return Ok(()); - } - // When we recover, we may see data whose validity *just* ended. Do not acquire it. - if let ValidationMode::Recover(ending_ce) = mode { - if query.re == Some(ending_ce) { - return Ok(()); - } - } - - query.ty = self.normalize_type_unerased(&query.ty); - trace!("{:?} on {:#?}", mode, query); - trace!("{:#?}", query.ty.sty); - - // Decide whether this type *owns* the memory it covers (like integers), or whether it - // just assembles pieces (that each own their memory) together to a larger whole. - // TODO: Currently, we don't acquire locks for padding and discriminants. We should. - let is_owning = match query.ty.sty { - TyInt(_) | TyUint(_) | TyRawPtr(_) | TyBool | TyFloat(_) | TyChar | TyStr | - TyRef(..) | TyFnPtr(..) | TyFnDef(..) | TyNever => true, - TyAdt(adt, _) if adt.is_box() => true, - TySlice(_) | TyAdt(_, _) | TyTuple(..) | TyClosure(..) | TyArray(..) | - TyDynamic(..) | TyGenerator(..) | TyForeign(_) => false, - TyGeneratorWitness(..) => unreachable!("TyGeneratorWitness in validate"), - TyParam(_) | TyInfer(_) | TyProjection(_) | TyAnon(..) | TyError => { - bug!("I got an incomplete/unnormalized type for validation") - } - }; - if is_owning { - // We need to lock. So we need memory. So we have to force_acquire. - // Tracking the same state for locals not backed by memory would just duplicate too - // much machinery. - // FIXME: We ignore alignment. - let (ptr, _, extra) = self.force_allocation(query.place.1)?.to_ptr_align_extra(); - // Determine the size - // FIXME: Can we reuse size_and_align_of_dst for Places? - let layout = self.layout_of(query.ty)?; - let len = if !layout.is_unsized() { - assert_eq!(extra, PlaceExtra::None, "Got a fat ptr to a sized type"); - layout.size.bytes() - } else { - // The only unsized typ we concider "owning" is TyStr. - assert_eq!( - query.ty.sty, - TyStr, - "Found a surprising unsized owning type" - ); - // The extra must be the length, in bytes. - match extra { - PlaceExtra::Length(len) => len, - _ => bug!("TyStr must have a length as extra"), - } - }; - // Handle locking - if len > 0 { - let ptr = ptr.unwrap_or_err()?.to_ptr()?; - match query.mutbl { - MutImmutable => { - if mode.acquiring() { - self.memory.acquire_lock( - ptr, - len, - query.re, - AccessKind::Read, - )?; - } - } - // No releasing of read locks, ever. - MutMutable => { - match mode { - ValidationMode::Acquire => { - self.memory.acquire_lock( - ptr, - len, - query.re, - AccessKind::Write, - )? - } - ValidationMode::Recover(ending_ce) => { - self.memory.recover_write_lock( - ptr, - len, - &query.place.0, - query.re, - ending_ce, - )? - } - ValidationMode::ReleaseUntil(suspended_ce) => { - self.memory.suspend_write_lock( - ptr, - len, - &query.place.0, - suspended_ce, - )? - } - } - } - } - } - } - - let res: EvalResult<'tcx> = do catch { - match query.ty.sty { - TyInt(_) | TyUint(_) | TyRawPtr(_) => { - if mode.acquiring() { - // Make sure we can read this. - let val = self.read_place(query.place.1)?; - self.follow_by_ref_value(val, query.ty)?; - // FIXME: It would be great to rule out Undef here, but that doesn't actually work. - // Passing around undef data is a thing that e.g. Vec::extend_with does. - } - } - TyBool | TyFloat(_) | TyChar => { - if mode.acquiring() { - let val = self.read_place(query.place.1)?; - let val = self.value_to_scalar(ValTy { value: val, ty: query.ty })?; - val.to_bytes()?; - // TODO: Check if these are valid bool/float/codepoint/UTF-8 - } - } - TyNever => return err!(ValidationFailure(format!("The empty type is never valid."))), - TyRef(region, pointee_ty, mutbl) => { - let val = self.read_place(query.place.1)?; - // Sharing restricts our context - if mutbl == MutImmutable { - query.mutbl = MutImmutable; - } - // Inner lifetimes *outlive* outer ones, so only if we have no lifetime restriction yet, - // we record the region of this borrow to the context. - if query.re == None { - if let ReScope(scope) = *region { - query.re = Some(scope); - } - // It is possible for us to encounter erased lifetimes here because the lifetimes in - // this functions' Subst will be erased. - } - self.validate_ptr(val, query.place.0, pointee_ty, query.re, query.mutbl, mode)?; - } - TyAdt(adt, _) if adt.is_box() => { - let val = self.read_place(query.place.1)?; - self.validate_ptr(val, query.place.0, query.ty.boxed_ty(), query.re, query.mutbl, mode)?; - } - TyFnPtr(_sig) => { - let ptr = self.read_place(query.place.1)?; - 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?). - } - TyFnDef(..) => { - // This is a zero-sized type with all relevant data sitting in the type. - // There is nothing to validate. - } - - // Compound types - TyStr => { - // TODO: Validate strings - } - TySlice(elem_ty) => { - let len = match query.place.1 { - Place::Ptr { extra: PlaceExtra::Length(len), .. } => len, - _ => { - bug!( - "acquire_valid of a TySlice given non-slice place: {:?}", - query.place - ) - } - }; - for i in 0..len { - let inner_place = self.place_index(query.place.1, query.ty, i)?; - self.validate( - ValidationQuery { - place: (query.place.0.clone().index(i), inner_place), - ty: elem_ty, - ..query - }, - mode, - )?; - } - } - TyArray(elem_ty, len) => { - let len = match len.val { - ConstValue::Unevaluated(def_id, substs) => { - self.tcx.const_eval(self.tcx.param_env(def_id).and(GlobalId { - instance: Instance::new(def_id, substs), - promoted: None, - })) - .map_err(|_err|EvalErrorKind::MachineError("".to_string()))? - } - _ => len, - }; - let len = len.unwrap_usize(self.tcx.tcx); - for i in 0..len { - let inner_place = self.place_index(query.place.1, query.ty, i as u64)?; - self.validate( - ValidationQuery { - place: (query.place.0.clone().index(i as u64), inner_place), - ty: elem_ty, - ..query - }, - mode, - )?; - } - } - TyDynamic(_data, _region) => { - // Check that this is a valid vtable - let vtable = match query.place.1 { - Place::Ptr { extra: PlaceExtra::Vtable(vtable), .. } => vtable, - _ => { - bug!( - "acquire_valid of a TyDynamic given non-trait-object place: {:?}", - query.place - ) - } - }; - self.read_size_and_align_from_vtable(vtable)?; - // TODO: Check that the vtable contains all the function pointers we expect it to have. - // Trait objects cannot have any operations performed - // on them directly. We cannot, in general, even acquire any locks as the trait object *could* - // contain an UnsafeCell. If we call functions to get access to data, we will validate - // their return values. So, it doesn't seem like there's anything else to do. - } - TyAdt(adt, _) => { - if Some(adt.did) == self.tcx.tcx.lang_items().unsafe_cell_type() && - query.mutbl == MutImmutable - { - // No locks for shared unsafe cells. Also no other validation, the only field is private anyway. - return Ok(()); - } - - match adt.adt_kind() { - AdtKind::Enum => { - let layout = self.layout_of(query.ty)?; - let variant_idx = self.read_discriminant_as_variant_index(query.place.1, layout)?; - let variant = &adt.variants[variant_idx]; - - if !variant.fields.is_empty() { - // Downcast to this variant, if needed - let place = if adt.is_enum() { - ( - query.place.0.downcast(adt, variant_idx), - self.eval_place_projection( - query.place.1, - query.ty, - &mir::ProjectionElem::Downcast(adt, variant_idx), - )?, - ) - } else { - query.place - }; - - // Recursively validate the fields - self.validate_fields( - ValidationQuery { place, ..query }, - mode, - )?; - } else { - // No fields, nothing left to check. Downcasting may fail, e.g. in case of a CEnum. - } - } - AdtKind::Struct => { - self.validate_fields(query, mode)?; - } - AdtKind::Union => { - // No guarantees are provided for union types. - // TODO: Make sure that all access to union fields is unsafe; otherwise, we may have some checking to do (but what exactly?) - } - } - } - TyTuple(..) | - TyClosure(..) => { - // TODO: Check if the signature matches for `TyClosure` - // (should be the same check as what terminator/mod.rs already does on call?). - // Is there other things we can/should check? Like vtable pointers? - self.validate_fields(query, mode)?; - } - // FIXME: generators aren't validated right now - TyGenerator(..) => {}, - _ => bug!("We already established that this is a type we support. ({})", query.ty), - } - }; - match res { - // ReleaseUntil(None) of an uninitalized variable is a NOP. This is needed because - // we have to release the return value of a function; due to destination-passing-style - // the callee may directly write there. - // TODO: Ideally we would know whether the destination is already initialized, and only - // release if it is. But of course that can't even always be statically determined. - Err(EvalError { kind: EvalErrorKind::ReadUndefBytes, .. }) - if mode == ValidationMode::ReleaseUntil(None) => { - Ok(()) - } - res => res, - } - } -} diff --git a/tests/run-pass/atomic-compare_exchange.rs b/tests/run-pass/atomic-compare_exchange.rs index 61e9a96588966..ec8e16d33e42b 100644 --- a/tests/run-pass/atomic-compare_exchange.rs +++ b/tests/run-pass/atomic-compare_exchange.rs @@ -15,18 +15,22 @@ static ATOMIC: AtomicIsize = ATOMIC_ISIZE_INIT; fn main() { // Make sure trans can emit all the intrinsics correctly - ATOMIC.compare_exchange(0, 1, Relaxed, Relaxed).ok(); - ATOMIC.compare_exchange(0, 1, Acquire, Relaxed).ok(); - ATOMIC.compare_exchange(0, 1, Release, Relaxed).ok(); - ATOMIC.compare_exchange(0, 1, AcqRel, Relaxed).ok(); + assert_eq!(ATOMIC.compare_exchange(0, 1, Relaxed, Relaxed), Ok(0)); + assert_eq!(ATOMIC.compare_exchange(0, 2, Acquire, Relaxed), Err(1)); + assert_eq!(ATOMIC.compare_exchange(0, 1, Release, Relaxed), Err(1)); + assert_eq!(ATOMIC.compare_exchange(1, 0, AcqRel, Relaxed), Ok(1)); ATOMIC.compare_exchange(0, 1, SeqCst, Relaxed).ok(); ATOMIC.compare_exchange(0, 1, Acquire, Acquire).ok(); ATOMIC.compare_exchange(0, 1, AcqRel, Acquire).ok(); ATOMIC.compare_exchange(0, 1, SeqCst, Acquire).ok(); ATOMIC.compare_exchange(0, 1, SeqCst, SeqCst).ok(); - ATOMIC.compare_exchange_weak(0, 1, Relaxed, Relaxed).ok(); - ATOMIC.compare_exchange_weak(0, 1, Acquire, Relaxed).ok(); - ATOMIC.compare_exchange_weak(0, 1, Release, Relaxed).ok(); + + ATOMIC.store(0, SeqCst); + + assert_eq!(ATOMIC.compare_exchange_weak(0, 1, Relaxed, Relaxed), Ok(0)); + assert_eq!(ATOMIC.compare_exchange_weak(0, 2, Acquire, Relaxed), Err(1)); + assert_eq!(ATOMIC.compare_exchange_weak(0, 1, Release, Relaxed), Err(1)); + assert_eq!(ATOMIC.compare_exchange_weak(1, 0, AcqRel, Relaxed), Ok(1)); ATOMIC.compare_exchange_weak(0, 1, AcqRel, Relaxed).ok(); ATOMIC.compare_exchange_weak(0, 1, SeqCst, Relaxed).ok(); ATOMIC.compare_exchange_weak(0, 1, Acquire, Acquire).ok(); From c424e21692835963cab65949d4c2421fcd05a614 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 16 Aug 2018 11:35:38 +0200 Subject: [PATCH 0185/3747] update for memory signedness removal; test some float casts --- src/fn_call.rs | 1 - tests/run-pass/floats.rs | 4 ++++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index 559f3adb90f13..08db6a029cbee 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -526,7 +526,6 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' Scalar::from_uint(key, key_layout.size).into(), key_layout.size, key_layout.align, - false, )?; // Return success (0) diff --git a/tests/run-pass/floats.rs b/tests/run-pass/floats.rs index 9c4d0594d1c99..39fdbce49202e 100644 --- a/tests/run-pass/floats.rs +++ b/tests/run-pass/floats.rs @@ -8,4 +8,8 @@ fn main() { let x: u64 = unsafe { std::mem::transmute(42.0_f64) }; let y: f64 = unsafe { std::mem::transmute(x) }; assert_eq!(y, 42.0_f64); + + assert_eq!(5.0f32 as u32, 5); + assert_eq!(5.0f32 as i32, 5); + assert_eq!(-5.0f32 as i32, -5); } From ea27e46a3859d20b8740738ee3efea16e0a87e2e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 17 Aug 2018 09:36:53 +0200 Subject: [PATCH 0186/3747] fix compilation after rustc change --- src/helpers.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/helpers.rs b/src/helpers.rs index 606f1bb4ecb44..88dd351513a53 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -1,7 +1,7 @@ use rustc::ty::layout::{Size, HasDataLayout}; +use rustc::mir::interpret::sign_extend; use super::{Scalar, ScalarMaybeUndef, EvalResult}; -use rustc_mir::interpret::sign_extend; pub trait ScalarExt { fn null(size: Size) -> Self; From 6203bf445f1c7abd958ea1f79feb311381ace502 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 18 Aug 2018 11:59:28 +0200 Subject: [PATCH 0187/3747] update for rustc memory changes; fix (un)init intrinsic for ZST --- src/fn_call.rs | 3 +-- src/intrinsic.rs | 62 ++++++++++++++++++++++++++---------------------- 2 files changed, 34 insertions(+), 31 deletions(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index 08db6a029cbee..605b63a10ea47 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -498,7 +498,7 @@ 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.read_scalar(args[0])?.not_undef()?; + let key_ptr = self.read_scalar(args[0])?.to_ptr()?; // Extract the function type out of the signature (that seems easier than constructing it ourselves...) let dtor = match self.read_scalar(args[1])?.not_undef()? { @@ -525,7 +525,6 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' key_layout.align, Scalar::from_uint(key, key_layout.size).into(), key_layout.size, - key_layout.align, )?; // Return success (0) diff --git a/src/intrinsic.rs b/src/intrinsic.rs index 631653b97b6b6..47399c390796b 100644 --- a/src/intrinsic.rs +++ b/src/intrinsic.rs @@ -295,21 +295,23 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: "init" => { // Check fast path: we don't want to force an allocation in case the destination is a simple value, // but we also do not want to create a new allocation with 0s and then copy that over. - match dest.layout.abi { - layout::Abi::Scalar(ref s) => { - let x = Scalar::null(s.value.size(&self)); - self.write_value(Value::Scalar(x.into()), dest)?; - } - layout::Abi::ScalarPair(ref s1, ref s2) => { - let x = Scalar::null(s1.value.size(&self)); - let y = Scalar::null(s2.value.size(&self)); - self.write_value(Value::ScalarPair(x.into(), y.into()), dest)?; - } - _ => { - // Do it in memory - let mplace = self.force_allocation(dest)?; - assert_eq!(mplace.extra, PlaceExtra::None); - self.memory.write_repeat(mplace.ptr, 0, dest.layout.size)?; + if !dest.layout.is_zst() { // notzhing to do for ZST + match dest.layout.abi { + layout::Abi::Scalar(ref s) => { + let x = Scalar::null(s.value.size(&self)); + self.write_value(Value::Scalar(x.into()), dest)?; + } + layout::Abi::ScalarPair(ref s1, ref s2) => { + let x = Scalar::null(s1.value.size(&self)); + let y = Scalar::null(s2.value.size(&self)); + self.write_value(Value::ScalarPair(x.into(), y.into()), dest)?; + } + _ => { + // Do it in memory + let mplace = self.force_allocation(dest)?; + assert_eq!(mplace.extra, PlaceExtra::None); + self.memory.write_repeat(mplace.ptr, 0, dest.layout.size)?; + } } } } @@ -571,20 +573,22 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: "uninit" => { // Check fast path: we don't want to force an allocation in case the destination is a simple value, // but we also do not want to create a new allocation with 0s and then copy that over. - match dest.layout.abi { - layout::Abi::Scalar(..) => { - let x = ScalarMaybeUndef::Undef; - self.write_value(Value::Scalar(x), dest)?; - } - layout::Abi::ScalarPair(..) => { - let x = ScalarMaybeUndef::Undef; - self.write_value(Value::ScalarPair(x, x), dest)?; - } - _ => { - // Do it in memory - let mplace = self.force_allocation(dest)?; - assert_eq!(mplace.extra, PlaceExtra::None); - self.memory.mark_definedness(mplace.ptr, dest.layout.size, false)?; + if !dest.layout.is_zst() { // nothing to do for ZST + match dest.layout.abi { + layout::Abi::Scalar(..) => { + let x = ScalarMaybeUndef::Undef; + self.write_value(Value::Scalar(x), dest)?; + } + layout::Abi::ScalarPair(..) => { + let x = ScalarMaybeUndef::Undef; + self.write_value(Value::ScalarPair(x, x), dest)?; + } + _ => { + // Do it in memory + let mplace = self.force_allocation(dest)?; + assert_eq!(mplace.extra, PlaceExtra::None); + self.memory.mark_definedness(mplace.ptr.to_ptr()?, dest.layout.size, false)?; + } } } } From 1a23b3c313507c89d1fb3af9023ba058231f4254 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 20 Aug 2018 16:27:23 +0200 Subject: [PATCH 0188/3747] rustup --- src/fn_call.rs | 2 +- src/lib.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index 605b63a10ea47..b4c8c6f0f4313 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -3,7 +3,7 @@ use rustc::ty::layout::{Align, LayoutOf, Size}; use rustc::hir::def_id::{DefId, CRATE_DEF_INDEX}; use rustc::mir; use syntax::attr; -use syntax::codemap::Span; +use syntax::source_map::Span; use std::mem; diff --git a/src/lib.rs b/src/lib.rs index 3680d49836fb5..044ce28b30141 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -25,7 +25,7 @@ use rustc::mir; use rustc_data_structures::fx::FxHasher; use syntax::ast::Mutability; -use syntax::codemap::Span; +use syntax::source_map::Span; use std::marker::PhantomData; use std::collections::{HashMap, BTreeMap}; @@ -57,7 +57,7 @@ pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( start_wrapper: Option, ) -> EvalResult<'tcx, (EvalContext<'a, 'mir, 'tcx, Evaluator<'tcx>>, Option)> { let mut ecx = EvalContext::new( - tcx.at(syntax::codemap::DUMMY_SP), + tcx.at(syntax::source_map::DUMMY_SP), ty::ParamEnv::reveal_all(), Default::default(), MemoryData::new() From 68194180a835f30b4fec5fd04b754c4a38107167 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 23 Aug 2018 09:29:27 +0200 Subject: [PATCH 0189/3747] fix type renaming --- src/fn_call.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index b4c8c6f0f4313..d8afe0878998a 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -60,7 +60,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' // Return None, as it doesn't make sense to return Some, because miri detects stack overflow itself. let (return_place, return_to_block) = destination.unwrap(); match return_place.layout.ty.sty { - ty::TyAdt(ref adt_def, _) => { + ty::Adt(ref adt_def, _) => { assert!(adt_def.is_enum(), "Unexpected return type for {}", item_path); let none_variant_index = adt_def.variants.iter().position(|def| { def.name.as_str() == "None" From 1a4ad2bb9fe3216010f33b47c6b05debaef7d604 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 23 Aug 2018 19:28:48 +0200 Subject: [PATCH 0190/3747] update for miri engine: new function handling, new static handling, fixed leaks --- src/fn_call.rs | 179 +++++++++--------- src/helpers.rs | 52 +---- src/intrinsic.rs | 87 +-------- src/lib.rs | 163 +++------------- src/memory.rs | 18 +- src/tls.rs | 2 +- tests/compile-fail/memleak.rs | 1 - tests/compile-fail/memleak_rc.rs | 1 - tests/compile-fail/modifying_constants.rs | 1 - .../static_memory_modification.rs | 1 - tests/run-pass/pthreads.rs | 14 ++ 11 files changed, 149 insertions(+), 370 deletions(-) create mode 100644 tests/run-pass/pthreads.rs diff --git a/src/fn_call.rs b/src/fn_call.rs index d8afe0878998a..6e3fcf7d4489b 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -3,7 +3,6 @@ use rustc::ty::layout::{Align, LayoutOf, Size}; use rustc::hir::def_id::{DefId, CRATE_DEF_INDEX}; use rustc::mir; use syntax::attr; -use syntax::source_map::Span; use std::mem; @@ -13,122 +12,138 @@ use tls::MemoryExt; use super::memory::MemoryKind; -pub trait EvalContextExt<'tcx> { - fn call_foreign_item( +pub trait EvalContextExt<'tcx, 'mir> { + /// Emulate calling a foreign item, fail if the item is not supported. + /// This function will handle `goto_block` if needed. + fn emulate_foreign_item( &mut self, def_id: DefId, args: &[OpTy<'tcx>], dest: PlaceTy<'tcx>, - dest_block: mir::BasicBlock, + ret: mir::BasicBlock, ) -> EvalResult<'tcx>; fn resolve_path(&self, path: &[&str]) -> EvalResult<'tcx, ty::Instance<'tcx>>; - fn call_missing_fn( + /// Emulate a function that should have MIR but does not. + /// This is solely to support execution without full MIR. + /// Fail if emulating this function is not supported. + /// This function will handle `goto_block` if needed. + fn emulate_missing_fn( &mut self, - instance: ty::Instance<'tcx>, - destination: Option<(PlaceTy<'tcx>, mir::BasicBlock)>, - args: &[OpTy<'tcx>], path: String, + args: &[OpTy<'tcx>], + dest: Option>, + ret: Option, ) -> EvalResult<'tcx>; - fn eval_fn_call( + fn find_fn( &mut self, instance: ty::Instance<'tcx>, - destination: Option<(PlaceTy<'tcx>, mir::BasicBlock)>, args: &[OpTy<'tcx>], - span: Span, - ) -> EvalResult<'tcx, bool>; + dest: Option>, + ret: Option, + ) -> EvalResult<'tcx, Option<&'mir mir::Mir<'tcx>>>; fn write_null(&mut self, dest: PlaceTy<'tcx>) -> EvalResult<'tcx>; } -impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super::Evaluator<'tcx>> { - fn eval_fn_call( +impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for EvalContext<'a, 'mir, 'tcx, super::Evaluator<'tcx>> { + fn find_fn( &mut self, instance: ty::Instance<'tcx>, - destination: Option<(PlaceTy<'tcx>, mir::BasicBlock)>, args: &[OpTy<'tcx>], - span: Span, - ) -> EvalResult<'tcx, bool> { - trace!("eval_fn_call: {:#?}, {:?}", instance, destination.map(|(place, bb)| (*place, bb))); + dest: Option>, + ret: Option, + ) -> EvalResult<'tcx, Option<&'mir mir::Mir<'tcx>>> { + trace!("eval_fn_call: {:#?}, {:?}", instance, dest.map(|place| *place)); + + // first run the common hooks also supported by CTFE + if self.hook_fn(instance, args, dest)? { + self.goto_block(ret)?; + return Ok(None); + } + // there are some more lang items we want to hook that CTFE does not hook (yet) + if self.tcx.lang_items().align_offset_fn() == Some(instance.def.def_id()) { + // FIXME: return a real value in case the target allocation has an + // alignment bigger than the one requested + let n = u128::max_value(); + let dest = dest.unwrap(); + let n = self.truncate(n, dest.layout); + self.write_scalar(Scalar::from_uint(n, dest.layout.size), dest)?; + self.goto_block(ret)?; + return Ok(None); + } + // FIXME: Why are these hooked here, not in `emulate_missing_fn` or so? let def_id = instance.def_id(); let item_path = self.tcx.absolute_item_path_str(def_id); match &*item_path { "std::sys::unix::thread::guard::init" | "std::sys::unix::thread::guard::current" => { // Return None, as it doesn't make sense to return Some, because miri detects stack overflow itself. - let (return_place, return_to_block) = destination.unwrap(); - match return_place.layout.ty.sty { + let dest = dest.unwrap(); + match dest.layout.ty.sty { ty::Adt(ref adt_def, _) => { assert!(adt_def.is_enum(), "Unexpected return type for {}", item_path); let none_variant_index = adt_def.variants.iter().position(|def| { def.name.as_str() == "None" }).expect("No None variant"); - self.write_discriminant_value(none_variant_index, return_place)?; - self.goto_block(return_to_block); - return Ok(true); + self.write_discriminant_value(none_variant_index, dest)?; + self.goto_block(ret)?; + return Ok(None); } _ => panic!("Unexpected return type for {}", item_path) } } "std::sys::unix::fast_thread_local::register_dtor" => { // TODO: register the dtor - let (_return_place, return_to_block) = destination.unwrap(); - self.goto_block(return_to_block); - return Ok(true); + self.goto_block(ret)?; + return Ok(None); } _ => {} } - if self.tcx.lang_items().align_offset_fn() == Some(instance.def.def_id()) { - // FIXME: return a real value in case the target allocation has an - // alignment bigger than the one requested - let n = u128::max_value(); - let (dest, return_to_block) = destination.unwrap(); - let n = self.truncate(n, dest.layout); - self.write_scalar(Scalar::from_uint(n, dest.layout.size), dest)?; - self.goto_block(return_to_block); - return Ok(true); + // Try to see if we can do something about foreign items + if self.tcx.is_foreign_item(instance.def_id()) { + // An external function that we cannot find MIR for, but we can still run enough + // of them to make miri viable. + self.emulate_foreign_item( + instance.def_id(), + args, + dest.unwrap(), + ret.unwrap(), + )?; + // `goto_block` already handled + return Ok(None); } + // Otherwise we really want to see the MIR -- but if we do not have it, maybe we can + // emulate something. This is a HACK to support running without a full-MIR libstd. let mir = match self.load_mir(instance.def) { Ok(mir) => mir, Err(EvalError { kind: EvalErrorKind::NoMirFor(path), .. }) => { - self.call_missing_fn( - instance, - destination, - args, + self.emulate_missing_fn( path, + args, + dest, + ret, )?; - return Ok(true); + // `goto_block` already handled + return Ok(None); } Err(other) => return Err(other), }; - let (return_place, return_to_block) = match destination { - Some((place, block)) => (*place, StackPopCleanup::Goto(block)), - None => (Place::null(&self), StackPopCleanup::None), - }; - - self.push_stack_frame( - instance, - span, - mir, - return_place, - return_to_block, - )?; - - Ok(false) + Ok(Some(mir)) } - fn call_foreign_item( + fn emulate_foreign_item( &mut self, def_id: DefId, args: &[OpTy<'tcx>], dest: PlaceTy<'tcx>, - dest_block: mir::BasicBlock, + ret: mir::BasicBlock, ) -> EvalResult<'tcx> { let attrs = self.tcx.get_attrs(def_id); let link_name = match attr::first_attr_value_str_by_name(&attrs, "link_name") { @@ -269,13 +284,13 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' // 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. let mir = self.load_mir(f_instance.def)?; - let ret = Place::null(&self); + let closure_dest = Place::null(&self); self.push_stack_frame( f_instance, mir.span, mir, - ret, - StackPopCleanup::Goto(dest_block), + closure_dest, + StackPopCleanup::Goto(Some(ret)), // directly return to caller )?; let mut args = self.frame().mir.args_iter(); @@ -290,16 +305,15 @@ 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 + // We ourselves will return 0, eventually (because we will not return if we paniced) self.write_null(dest)?; - // Don't fall through + // Don't fall through, we do NOT want to `goto_block`! return Ok(()); } - "__rust_start_panic" => { - return err!(Panic); - } + "__rust_start_panic" => + return err!(MachineError("the evaluated program panicked".to_string())), "memcmp" => { let left = self.read_scalar(args[0])?.not_undef()?; @@ -624,11 +638,8 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' } } - // Since we pushed no stack frame, the main loop will act - // as if the call just completed and it's returning to the - // current frame. + self.goto_block(Some(ret))?; self.dump_place(*dest); - self.goto_block(dest_block); Ok(()) } @@ -666,38 +677,27 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' }) } - fn call_missing_fn( + fn emulate_missing_fn( &mut self, - instance: ty::Instance<'tcx>, - destination: Option<(PlaceTy<'tcx>, mir::BasicBlock)>, - args: &[OpTy<'tcx>], path: String, + _args: &[OpTy<'tcx>], + dest: Option>, + ret: Option, ) -> EvalResult<'tcx> { // In some cases in non-MIR libstd-mode, not having a destination is legit. Handle these early. match &path[..] { "std::panicking::rust_panic_with_hook" | "core::panicking::panic_fmt::::panic_impl" | - "std::rt::begin_panic_fmt" => return err!(Panic), + "std::rt::begin_panic_fmt" => + return err!(MachineError("the evaluated program panicked".to_string())), _ => {} } - let (dest, dest_block) = destination.ok_or_else( + let dest = dest.ok_or_else( + // Must be some function we do not support || EvalErrorKind::NoMirFor(path.clone()), )?; - if self.tcx.is_foreign_item(instance.def_id()) { - // An external function - // TODO: That functions actually has a similar preamble to what follows here. May make sense to - // unify these two mechanisms for "hooking into missing functions". - self.call_foreign_item( - instance.def_id(), - args, - dest, - dest_block, - )?; - return Ok(()); - } - match &path[..] { // A Rust function is missing, which means we are running with MIR missing for libstd (or other dependencies). // Still, we can make many things mostly work by "emulating" or ignoring some functions. @@ -724,11 +724,8 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' _ => return err!(NoMirFor(path)), } - // Since we pushed no stack frame, the main loop will act - // as if the call just completed and it's returning to the - // current frame. + self.goto_block(ret)?; self.dump_place(*dest); - self.goto_block(dest_block); Ok(()) } diff --git a/src/helpers.rs b/src/helpers.rs index 88dd351513a53..24285fa4a6e8f 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -1,5 +1,4 @@ -use rustc::ty::layout::{Size, HasDataLayout}; -use rustc::mir::interpret::sign_extend; +use rustc::ty::layout::Size; use super::{Scalar, ScalarMaybeUndef, EvalResult}; @@ -14,11 +13,6 @@ pub trait ScalarExt { } pub trait FalibleScalarExt { - fn to_usize(self, cx: impl HasDataLayout) -> EvalResult<'static, u64>; - fn to_isize(self, cx: impl HasDataLayout) -> EvalResult<'static, i64>; - fn to_i32(self) -> EvalResult<'static, i32>; - fn to_u8(self) -> EvalResult<'static, u8>; - /// 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 @@ -59,34 +53,6 @@ impl ScalarExt for Scalar { } impl FalibleScalarExt for Scalar { - fn to_usize(self, cx: impl HasDataLayout) -> EvalResult<'static, u64> { - let b = self.to_bits(cx.data_layout().pointer_size)?; - assert_eq!(b as u64 as u128, b); - Ok(b as u64) - } - - fn to_u8(self) -> EvalResult<'static, u8> { - let sz = Size::from_bits(8); - let b = self.to_bits(sz)?; - assert_eq!(b as u8 as u128, b); - Ok(b as u8) - } - - fn to_isize(self, cx: impl HasDataLayout) -> EvalResult<'static, i64> { - let b = self.to_bits(cx.data_layout().pointer_size)?; - let b = sign_extend(b, cx.data_layout().pointer_size) as i128; - assert_eq!(b as i64 as i128, b); - Ok(b as i64) - } - - fn to_i32(self) -> EvalResult<'static, i32> { - let sz = Size::from_bits(32); - let b = self.to_bits(sz)?; - let b = sign_extend(b, sz) as i128; - assert_eq!(b as i32 as i128, b); - Ok(b as i32) - } - fn to_bytes(self) -> EvalResult<'static, u128> { match self { Scalar::Bits { bits, size } => { @@ -99,22 +65,6 @@ impl FalibleScalarExt for Scalar { } impl FalibleScalarExt for ScalarMaybeUndef { - fn to_usize(self, cx: impl HasDataLayout) -> EvalResult<'static, u64> { - self.not_undef()?.to_usize(cx) - } - - fn to_u8(self) -> EvalResult<'static, u8> { - self.not_undef()?.to_u8() - } - - fn to_isize(self, cx: impl HasDataLayout) -> EvalResult<'static, i64> { - self.not_undef()?.to_isize(cx) - } - - fn to_i32(self) -> EvalResult<'static, i32> { - self.not_undef()?.to_i32() - } - fn to_bytes(self) -> EvalResult<'static, u128> { self.not_undef()?.to_bytes() } diff --git a/src/intrinsic.rs b/src/intrinsic.rs index 47399c390796b..62a1938d0fc1f 100644 --- a/src/intrinsic.rs +++ b/src/intrinsic.rs @@ -1,5 +1,5 @@ use rustc::mir; -use rustc::ty::layout::{self, LayoutOf, Size, Primitive, Integer::*}; +use rustc::ty::layout::{self, LayoutOf, Size}; use rustc::ty; use rustc::mir::interpret::{EvalResult, Scalar, ScalarMaybeUndef}; @@ -15,7 +15,6 @@ pub trait EvalContextExt<'tcx> { instance: ty::Instance<'tcx>, args: &[OpTy<'tcx>], dest: PlaceTy<'tcx>, - target: mir::BasicBlock, ) -> EvalResult<'tcx>; } @@ -25,8 +24,11 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: instance: ty::Instance<'tcx>, args: &[OpTy<'tcx>], dest: PlaceTy<'tcx>, - target: mir::BasicBlock, ) -> EvalResult<'tcx> { + if self.emulate_intrinsic(instance, args, dest)? { + return Ok(()); + } + let substs = instance.substs; let intrinsic_name = &self.tcx.item_name(instance.def_id()).as_str()[..]; @@ -194,24 +196,6 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: } } - "ctpop" | "cttz" | "cttz_nonzero" | "ctlz" | "ctlz_nonzero" | "bswap" => { - let ty = substs.type_at(0); - let num = self.read_scalar(args[0])?.to_bytes()?; - let kind = match self.layout_of(ty)?.abi { - ty::layout::Abi::Scalar(ref scalar) => scalar.value, - _ => Err(::rustc::mir::interpret::EvalErrorKind::TypeNotPrimitive(ty))?, - }; - let num = if intrinsic_name.ends_with("_nonzero") { - if num == 0 { - return err!(Intrinsic(format!("{} called on 0", intrinsic_name))); - } - numeric_intrinsic(intrinsic_name.trim_right_matches("_nonzero"), num, kind)? - } else { - numeric_intrinsic(intrinsic_name, num, kind)? - }; - self.write_scalar(num, dest)?; - } - "discriminant_value" => { let place = self.ref_to_mplace(self.read_value(args[0])?)?; let discr_val = self.read_discriminant_value(place.into())?; @@ -316,14 +300,6 @@ 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 ptr_size = self.memory.pointer_size(); - let align_val = Scalar::from_uint(elem_align as u128, ptr_size); - self.write_scalar(align_val, dest)?; - } - "pref_align_of" => { let ty = substs.type_at(0); let layout = self.layout_of(ty)?; @@ -456,13 +432,6 @@ 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(); - let ptr_size = self.memory.pointer_size(); - self.write_scalar(Scalar::from_uint(size, ptr_size), dest)?; - } - "size_of_val" => { let mplace = self.ref_to_mplace(self.read_value(args[0])?)?; let (size, _) = self.size_and_align_of_mplace(mplace)?; @@ -490,11 +459,6 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: let value = self.str_to_value(&ty_name)?; self.write_value(value, dest)?; } - "type_id" => { - let ty = substs.type_at(0); - let n = self.tcx.type_id_hash(ty); - self.write_scalar(Scalar::Bits { bits: n as u128, size: 8 }, dest)?; - } "transmute" => { // Go through an allocation, to make sure the completely different layouts @@ -610,47 +574,6 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: name => return err!(Unimplemented(format!("unimplemented intrinsic: {}", name))), } - self.goto_block(target); - - // Since we pushed no stack frame, the main loop will act - // as if the call just completed and it's returning to the - // current frame. Ok(()) } } - -fn numeric_intrinsic<'tcx>( - name: &str, - bytes: u128, - kind: Primitive, -) -> EvalResult<'tcx, Scalar> { - macro_rules! integer_intrinsic { - ($method:ident) => ({ - 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_uint(result_bytes, Size::from_bytes(size)) - }); - } - - let result_val = match name { - "bswap" => integer_intrinsic!(swap_bytes), - "ctlz" => integer_intrinsic!(leading_zeros), - "ctpop" => integer_intrinsic!(count_ones), - "cttz" => integer_intrinsic!(trailing_zeros), - _ => bug!("not a numeric intrinsic: {}", name), - }; - - Ok(result_val) -} diff --git a/src/lib.rs b/src/lib.rs index 044ce28b30141..81cee6fbe42eb 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -18,14 +18,12 @@ extern crate syntax; use rustc::ty::{self, TyCtxt}; use rustc::ty::layout::{TyLayout, LayoutOf, Size}; -use rustc::ty::subst::Subst; use rustc::hir::def_id::DefId; use rustc::mir; use rustc_data_structures::fx::FxHasher; use syntax::ast::Mutability; -use syntax::source_map::Span; use std::marker::PhantomData; use std::collections::{HashMap, BTreeMap}; @@ -47,6 +45,7 @@ use fn_call::EvalContextExt as MissingFnsEvalContextExt; use operator::EvalContextExt as OperatorEvalContextExt; use intrinsic::EvalContextExt as IntrinsicEvalContextExt; use tls::EvalContextExt as TlsEvalContextExt; +use memory::MemoryKind as MiriMemoryKind; use locks::LockInfo; use range_map::RangeMap; use helpers::{ScalarExt, FalibleScalarExt}; @@ -55,7 +54,7 @@ pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( tcx: TyCtxt<'a, 'tcx, 'tcx>, main_id: DefId, start_wrapper: Option, -) -> EvalResult<'tcx, (EvalContext<'a, 'mir, 'tcx, Evaluator<'tcx>>, Option)> { +) -> EvalResult<'tcx, EvalContext<'a, 'mir, 'tcx, Evaluator<'tcx>>> { let mut ecx = EvalContext::new( tcx.at(syntax::source_map::DUMMY_SP), ty::ParamEnv::reveal_all(), @@ -65,7 +64,6 @@ pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( let main_instance = ty::Instance::mono(ecx.tcx.tcx, main_id); let main_mir = ecx.load_mir(main_instance.def)?; - let mut cleanup_ptr = None; // Scalar to be deallocated when we are done if !main_mir.return_ty().is_nil() || main_mir.arg_count != 0 { return err!(Unimplemented( @@ -94,11 +92,10 @@ pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( ))); } - // Return value + // Return value (in static memory so that it does not count as leak) let size = ecx.tcx.data_layout.pointer_size; let align = ecx.tcx.data_layout.pointer_align; - let ret_ptr = ecx.memory_mut().allocate(size, align, MemoryKind::Stack)?; - cleanup_ptr = Some(ret_ptr); + let ret_ptr = ecx.memory_mut().allocate(size, align, MiriMemoryKind::MutStatic.into())?; // Push our stack frame ecx.push_stack_frame( @@ -123,12 +120,12 @@ pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( // FIXME: extract main source file path // Third argument (argv): &[b"foo"] let dest = ecx.eval_place(&mir::Place::Local(args.next().unwrap()))?; - let foo = ecx.memory.allocate_bytes(b"foo\0"); + let foo = ecx.memory.allocate_static_bytes(b"foo\0"); let foo_ty = ecx.tcx.mk_imm_ptr(ecx.tcx.types.u8); let foo_layout = ecx.layout_of(foo_ty)?; - let foo_place = ecx.allocate(foo_layout, MemoryKind::Stack)?; + let foo_place = ecx.allocate(foo_layout, MemoryKind::Stack)?; // will be marked as static in just a second ecx.write_scalar(Scalar::Ptr(foo), foo_place.into())?; - ecx.memory.mark_static_initialized(foo_place.to_ptr()?.alloc_id, Mutability::Immutable)?; + ecx.memory.mark_static_initialized(foo_place.to_ptr()?.alloc_id, Mutability::Immutable)?; // marked as static ecx.write_scalar(foo_place.ptr, dest)?; assert!(args.next().is_none(), "start lang item has more arguments than expected"); @@ -146,7 +143,7 @@ pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( assert!(args.next().is_none(), "main function must not have arguments"); } - Ok((ecx, cleanup_ptr)) + Ok(ecx) } pub fn eval_main<'a, 'tcx: 'a>( @@ -154,26 +151,18 @@ pub fn eval_main<'a, 'tcx: 'a>( main_id: DefId, start_wrapper: Option, ) { - let (mut ecx, cleanup_ptr) = create_ecx(tcx, main_id, start_wrapper).expect("Couldn't create ecx"); + let mut ecx = create_ecx(tcx, main_id, start_wrapper).expect("Couldn't create ecx"); let res: EvalResult = do catch { - while ecx.step()? {} + ecx.run()?; ecx.run_tls_dtors()?; - if let Some(cleanup_ptr) = cleanup_ptr { - ecx.memory_mut().deallocate( - cleanup_ptr, - None, - MemoryKind::Stack, - )?; - } }; match res { Ok(()) => { let leaks = ecx.memory().leak_report(); if leaks != 0 { - // TODO: Prevent leaks which aren't supposed to be there - //tcx.sess.err("the evaluated program leaked memory"); + tcx.sess.err("the evaluated program leaked memory"); } } Err(e) => { @@ -198,6 +187,7 @@ pub fn eval_main<'a, 'tcx: 'a>( ecx.tcx.sess.err(&e.to_string()); } + /* Nice try, but with MIRI_BACKTRACE this shows 100s of backtraces. for (i, frame) in ecx.stack().iter().enumerate() { trace!("-------------------"); trace!("Frame {}", i); @@ -207,7 +197,7 @@ pub fn eval_main<'a, 'tcx: 'a>( trace!(" local {}: {:?}", i, local); } } - } + }*/ } } } @@ -262,8 +252,6 @@ pub struct MemoryData<'tcx> { /// Only mutable (static mut, heap, stack) allocations have an entry in this map. /// The entry is created when allocating the memory and deleted after deallocation. locks: HashMap>>, - - statics: HashMap, AllocId>, } impl<'tcx> MemoryData<'tcx> { @@ -272,7 +260,6 @@ impl<'tcx> MemoryData<'tcx> { next_thread_local: 1, // start with 1 as we must not use 0 on Windows thread_local: BTreeMap::new(), locks: HashMap::new(), - statics: HashMap::new(), } } } @@ -283,7 +270,6 @@ impl<'tcx> Hash for MemoryData<'tcx> { next_thread_local: _, thread_local, locks: _, - statics: _, } = self; thread_local.hash(state); @@ -295,14 +281,14 @@ impl<'mir, 'tcx: 'mir> Machine<'mir, 'tcx> for Evaluator<'tcx> { type MemoryKinds = memory::MemoryKind; /// Returns Ok() when the function was handled, fail otherwise - fn eval_fn_call<'a>( + fn find_fn<'a>( ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, instance: ty::Instance<'tcx>, - destination: Option<(PlaceTy<'tcx>, mir::BasicBlock)>, args: &[OpTy<'tcx>], - span: Span, - ) -> EvalResult<'tcx, bool> { - ecx.eval_fn_call(instance, destination, args, span) + dest: Option>, + ret: Option, + ) -> EvalResult<'tcx, Option<&'mir mir::Mir<'tcx>>> { + ecx.find_fn(instance, args, dest, ret) } fn call_intrinsic<'a>( @@ -310,9 +296,8 @@ impl<'mir, 'tcx: 'mir> Machine<'mir, 'tcx> for Evaluator<'tcx> { instance: ty::Instance<'tcx>, args: &[OpTy<'tcx>], dest: PlaceTy<'tcx>, - target: mir::BasicBlock, ) -> EvalResult<'tcx> { - ecx.call_intrinsic(instance, args, dest, target) + ecx.call_intrinsic(instance, args, dest) } fn try_ptr_op<'a>( @@ -326,82 +311,13 @@ impl<'mir, 'tcx: 'mir> Machine<'mir, 'tcx> for Evaluator<'tcx> { ecx.ptr_op(bin_op, left, left_layout, right, right_layout) } - fn mark_static_initialized<'a>( - mem: &mut Memory<'a, 'mir, 'tcx, Self>, + fn access_static_mut<'a, 'm>( + mem: &'m mut Memory<'a, 'mir, 'tcx, Self>, id: AllocId, - _mutability: Mutability, - ) -> EvalResult<'tcx, bool> { - use memory::MemoryKind::*; - match mem.get_alloc_kind(id) { - // FIXME: This could be allowed, but not for env vars set during miri execution - Some(MemoryKind::Machine(Env)) => err!(Unimplemented("statics can't refer to env vars".to_owned())), - _ => Ok(false), // TODO: What does the bool mean? - } - } - - fn init_static<'a>( - ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, - cid: GlobalId<'tcx>, - ) -> EvalResult<'tcx, AllocId> { - // Step 1: If the static has already been evaluated return the cached version - if let Some(alloc_id) = ecx.memory.data.statics.get(&cid) { - return Ok(*alloc_id); - } - - let tcx = ecx.tcx.tcx; - - // Step 2: Load mir - let mut mir = ecx.load_mir(cid.instance.def)?; - if let Some(index) = cid.promoted { - mir = &mir.promoted[index]; - } - assert!(mir.arg_count == 0); - - // Step 3: Allocate storage - let layout = ecx.layout_of(mir.return_ty().subst(tcx, cid.instance.substs))?; - assert!(!layout.is_unsized()); - let ptr = ecx.memory.allocate( - layout.size, - layout.align, - MemoryKind::Stack, - )?; - - // Step 4: Cache allocation id for recursive statics - assert!(ecx.memory.data.statics.insert(cid, ptr.alloc_id).is_none()); - - // Step 5: Push stackframe to evaluate static - let cleanup = StackPopCleanup::None; - ecx.push_stack_frame( - cid.instance, - mir.span, - mir, - Place::from_ptr(ptr, layout.align), - cleanup, - )?; - - // Step 6: Step until static has been initialized - let call_stackframe = ecx.stack().len(); - while ecx.step()? && ecx.stack().len() >= call_stackframe { - if ecx.stack().len() == call_stackframe { - let cleanup = { - let frame = ecx.frame(); - let bb = &frame.mir.basic_blocks()[frame.block]; - bb.statements.len() == frame.stmt && !bb.is_cleanup && - if let ::rustc::mir::TerminatorKind::Return = bb.terminator().kind { true } else { false } - }; - if cleanup { - for (local, _local_decl) in mir.local_decls.iter_enumerated().skip(1) { - // Don't deallocate locals, because the return value might reference them - ecx.storage_dead(local); - } - } - } - } - - // TODO: Freeze immutable statics without copying them to the global static cache - - // Step 7: Return the alloc - Ok(ptr.alloc_id) + ) -> EvalResult<'tcx, &'m mut Allocation> { + // Make a copy, use that. + mem.deep_copy_static(id, MiriMemoryKind::MutStatic.into())?; + mem.get_mut(id) // this is recursive, but now we know that `id` is in `alloc_map` } fn box_alloc<'a>( @@ -451,35 +367,6 @@ impl<'mir, 'tcx: 'mir> Machine<'mir, 'tcx> for Evaluator<'tcx> { panic!("remove this function from rustc"); } - fn check_locks<'a>( - _mem: &Memory<'a, 'mir, 'tcx, Self>, - _ptr: Pointer, - _size: Size, - _access: AccessKind, - ) -> EvalResult<'tcx> { - Ok(()) - } - - fn add_lock<'a>( - _mem: &mut Memory<'a, 'mir, 'tcx, Self>, - _id: AllocId, - ) { } - - fn free_lock<'a>( - _mem: &mut Memory<'a, 'mir, 'tcx, Self>, - _id: AllocId, - _len: u64, - ) -> EvalResult<'tcx> { - Ok(()) - } - - fn end_region<'a>( - _ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, - _reg: Option<::rustc::middle::region::Scope>, - ) -> EvalResult<'tcx> { - Ok(()) - } - fn validation_op<'a>( _ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, _op: ::rustc::mir::ValidationOp, diff --git a/src/memory.rs b/src/memory.rs index bed0eb28c25c6..bc4c5b70ece35 100644 --- a/src/memory.rs +++ b/src/memory.rs @@ -1,12 +1,24 @@ +use rustc_mir::interpret::IsStatic; -#[derive(Debug, PartialEq, Copy, Clone)] +#[derive(Debug, PartialEq, Copy, Clone, Hash, Eq)] pub enum MemoryKind { - /// Error if deallocated any other way than `rust_deallocate` + /// `__rust_alloc` memory Rust, - /// Error if deallocated any other way than `free` + /// `malloc` memory C, /// Part of env var emulation Env, + // mutable statics + MutStatic, +} + +impl IsStatic for MemoryKind { + fn is_static(self) -> bool { + match self { + MemoryKind::MutStatic => true, + _ => false, + } + } } impl Into<::rustc_mir::interpret::MemoryKind> for MemoryKind { diff --git a/src/tls.rs b/src/tls.rs index 878884065bb71..955ecb225685d 100644 --- a/src/tls.rs +++ b/src/tls.rs @@ -134,7 +134,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' self.write_scalar(ptr, dest)?; // step until out of stackframes - while self.step()? {} + self.run()?; dtor = match self.memory.fetch_tls_dtor(Some(key)) { dtor @ Some(_) => dtor, diff --git a/tests/compile-fail/memleak.rs b/tests/compile-fail/memleak.rs index c03cf50eb27f6..71b4e2f442f31 100644 --- a/tests/compile-fail/memleak.rs +++ b/tests/compile-fail/memleak.rs @@ -1,4 +1,3 @@ -// ignore-test FIXME: leak detection is disabled //error-pattern: the evaluated program leaked memory fn main() { diff --git a/tests/compile-fail/memleak_rc.rs b/tests/compile-fail/memleak_rc.rs index da3a58118a2a5..b2bc6722afb04 100644 --- a/tests/compile-fail/memleak_rc.rs +++ b/tests/compile-fail/memleak_rc.rs @@ -1,4 +1,3 @@ -// ignore-test FIXME: leak detection is disabled //error-pattern: the evaluated program leaked memory use std::rc::Rc; diff --git a/tests/compile-fail/modifying_constants.rs b/tests/compile-fail/modifying_constants.rs index 6ffba89fa5efb..ba46651f58ee4 100644 --- a/tests/compile-fail/modifying_constants.rs +++ b/tests/compile-fail/modifying_constants.rs @@ -1,4 +1,3 @@ -// ignore-test FIXME: we are not making these statics read-only any more? fn main() { let x = &1; // the `&1` is promoted to a constant, but it used to be that only the pointer is marked static, not the pointee diff --git a/tests/compile-fail/static_memory_modification.rs b/tests/compile-fail/static_memory_modification.rs index e28bcb37fb72d..9e39c2c01c2b2 100644 --- a/tests/compile-fail/static_memory_modification.rs +++ b/tests/compile-fail/static_memory_modification.rs @@ -1,4 +1,3 @@ -// ignore-test FIXME: we are not making these statics read-only any more? static X: usize = 5; #[allow(mutable_transmutes)] diff --git a/tests/run-pass/pthreads.rs b/tests/run-pass/pthreads.rs new file mode 100644 index 0000000000000..ec7e082a5d5f0 --- /dev/null +++ b/tests/run-pass/pthreads.rs @@ -0,0 +1,14 @@ +// Just instantiate some data structures to make sure we got all their foreign items covered + +use std::sync; + +fn main() { + let m = sync::Mutex::new(0); + let _ = m.lock(); + drop(m); + + let rw = sync::RwLock::new(0); + let _ = rw.read(); + let _ = rw.write(); + drop(rw); +} From 2ee4aac62f4f14204194c391f0eac267c2eee077 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 23 Aug 2018 21:22:57 +0200 Subject: [PATCH 0191/3747] fix leaks with -Zmiri-start-fn --- src/fn_call.rs | 59 +++++++++++++++++++++----------------------------- src/lib.rs | 31 ++++++++++++++++++++------ 2 files changed, 49 insertions(+), 41 deletions(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index 6e3fcf7d4489b..d16e024db47d4 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -75,35 +75,6 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for EvalContext<'a, ' return Ok(None); } - // FIXME: Why are these hooked here, not in `emulate_missing_fn` or so? - let def_id = instance.def_id(); - let item_path = self.tcx.absolute_item_path_str(def_id); - match &*item_path { - "std::sys::unix::thread::guard::init" | "std::sys::unix::thread::guard::current" => { - // Return None, as it doesn't make sense to return Some, because miri detects stack overflow itself. - let dest = dest.unwrap(); - match dest.layout.ty.sty { - ty::Adt(ref adt_def, _) => { - assert!(adt_def.is_enum(), "Unexpected return type for {}", item_path); - let none_variant_index = adt_def.variants.iter().position(|def| { - def.name.as_str() == "None" - }).expect("No None variant"); - - self.write_discriminant_value(none_variant_index, dest)?; - self.goto_block(ret)?; - return Ok(None); - } - _ => panic!("Unexpected return type for {}", item_path) - } - } - "std::sys::unix::fast_thread_local::register_dtor" => { - // TODO: register the dtor - self.goto_block(ret)?; - return Ok(None); - } - _ => {} - } - // Try to see if we can do something about foreign items if self.tcx.is_foreign_item(instance.def_id()) { // An external function that we cannot find MIR for, but we can still run enough @@ -280,6 +251,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for EvalContext<'a, ' let data = self.read_scalar(args[1])?.not_undef()?; let f_instance = self.memory.get_fn(f)?; self.write_null(dest)?; + trace!("__rust_maybe_catch_panic: {:?}", f_instance); // 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. @@ -478,7 +450,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for EvalContext<'a, ' } "sysconf" => { - let name = self.read_scalar(args[0])?.to_usize(&self)?; + let name = self.read_scalar(args[0])?.to_i32()?; trace!("sysconf() called with name {}", name); // cache the sysconf integers via miri's global cache @@ -494,7 +466,9 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for EvalContext<'a, ' promoted: None, }; let const_val = self.const_eval(cid)?; - let value = const_val.unwrap_usize(self.tcx.tcx); + let value = const_val.unwrap_bits( + self.tcx.tcx, + ty::ParamEnv::empty().and(self.tcx.types.i32)) as i32; if value == name { result = Some(path_value); break; @@ -568,9 +542,26 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for EvalContext<'a, ' return err!(Unimplemented("Thread-local store is not fully supported on macOS".to_owned())); }, - // 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); + // Determining stack base address + "pthread_attr_init" | "pthread_attr_destroy" | "pthread_attr_get_np" | + "pthread_getattr_np" | "pthread_self" => { + self.write_null(dest)?; + } + "pthread_attr_getstack" => { + // second argument is where we are supposed to write the stack size + let ptr = self.ref_to_mplace(self.read_value(args[1])?)?; + self.write_scalar(Scalar::from_int(0x80000, args[1].layout.size), ptr.into())?; + // return 0 + self.write_null(dest)?; + } + + // Stub out calls for condvar, mutex and rwlock to just return 0 + "pthread_mutexattr_init" | "pthread_mutexattr_settype" | "pthread_mutex_init" | + "pthread_mutexattr_destroy" | "pthread_mutex_lock" | "pthread_mutex_unlock" | + "pthread_mutex_destroy" | "pthread_rwlock_rdlock" | "pthread_rwlock_unlock" | + "pthread_rwlock_wrlock" | "pthread_rwlock_destroy" | "pthread_condattr_init" | + "pthread_condattr_setclock" | "pthread_cond_init" | "pthread_condattr_destroy" | + "pthread_cond_destroy" => { self.write_null(dest)?; } diff --git a/src/lib.rs b/src/lib.rs index 81cee6fbe42eb..a3810516eafd9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -16,7 +16,7 @@ extern crate rustc_mir; extern crate rustc_target; extern crate syntax; -use rustc::ty::{self, TyCtxt}; +use rustc::ty::{self, TyCtxt, query::TyCtxtAt}; use rustc::ty::layout::{TyLayout, LayoutOf, Size}; use rustc::hir::def_id::DefId; use rustc::mir; @@ -24,6 +24,7 @@ use rustc::mir; use rustc_data_structures::fx::FxHasher; use syntax::ast::Mutability; +use syntax::attr; use std::marker::PhantomData; use std::collections::{HashMap, BTreeMap}; @@ -359,12 +360,28 @@ impl<'mir, 'tcx: 'mir> Machine<'mir, 'tcx> for Evaluator<'tcx> { Ok(()) } - fn global_item_with_linkage<'a>( - _ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, - _instance: ty::Instance<'tcx>, - _mutability: Mutability, - ) -> EvalResult<'tcx> { - panic!("remove this function from rustc"); + fn find_foreign_static<'a>( + tcx: TyCtxtAt<'a, 'tcx, 'tcx>, + def_id: DefId, + ) -> EvalResult<'tcx, &'tcx Allocation> { + let attrs = tcx.get_attrs(def_id); + let link_name = match attr::first_attr_value_str_by_name(&attrs, "link_name") { + Some(name) => name.as_str(), + None => tcx.item_name(def_id).as_str(), + }; + + let alloc = match &link_name[..] { + "__cxa_thread_atexit_impl" => { + // This should be all-zero, pointer-sized + let data = vec![0; tcx.data_layout.pointer_size.bytes() as usize]; + let alloc = Allocation::from_bytes(&data[..], tcx.data_layout.pointer_align); + tcx.intern_const_alloc(alloc) + } + _ => return err!(Unimplemented( + format!("can't access foreign static: {}", link_name), + )), + }; + Ok(alloc) } fn validation_op<'a>( From 42bce6cb3605a36092ab86daffa52f8075e76a8b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 24 Aug 2018 17:44:04 +0200 Subject: [PATCH 0192/3747] rustup --- src/lib.rs | 10 +++++----- src/tls.rs | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index a3810516eafd9..b529e73690026 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -104,7 +104,7 @@ pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( start_mir.span, start_mir, Place::from_ptr(ret_ptr, align), - StackPopCleanup::None, + StackPopCleanup::None { cleanup: true }, )?; let mut args = ecx.frame().mir.args_iter(); @@ -124,9 +124,9 @@ pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( let foo = ecx.memory.allocate_static_bytes(b"foo\0"); let foo_ty = ecx.tcx.mk_imm_ptr(ecx.tcx.types.u8); let foo_layout = ecx.layout_of(foo_ty)?; - let foo_place = ecx.allocate(foo_layout, MemoryKind::Stack)?; // will be marked as static in just a second + let foo_place = ecx.allocate(foo_layout, MemoryKind::Stack)?; // will be interned in just a second ecx.write_scalar(Scalar::Ptr(foo), foo_place.into())?; - ecx.memory.mark_static_initialized(foo_place.to_ptr()?.alloc_id, Mutability::Immutable)?; // marked as static + ecx.memory.intern_static(foo_place.to_ptr()?.alloc_id, Mutability::Immutable)?; ecx.write_scalar(foo_place.ptr, dest)?; assert!(args.next().is_none(), "start lang item has more arguments than expected"); @@ -136,7 +136,7 @@ pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( main_mir.span, main_mir, Place::from_scalar_ptr(Scalar::from_int(1, ptr_size).into(), ty::layout::Align::from_bytes(1, 1).unwrap()), - StackPopCleanup::None, + StackPopCleanup::None { cleanup: true }, )?; // No arguments @@ -338,7 +338,7 @@ impl<'mir, 'tcx: 'mir> Machine<'mir, 'tcx> for Evaluator<'tcx> { // Don't do anything when we are done. The statement() function will increment // the old stack frame's stmt counter to the next statement, which means that when // exchange_malloc returns, we go on evaluating exactly where we want to be. - StackPopCleanup::None, + StackPopCleanup::None { cleanup: true }, )?; let mut args = ecx.frame().mir.args_iter(); diff --git a/src/tls.rs b/src/tls.rs index 955ecb225685d..6cec39483c465 100644 --- a/src/tls.rs +++ b/src/tls.rs @@ -125,7 +125,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' mir.span, mir, ret, - StackPopCleanup::None, + StackPopCleanup::None { cleanup: true }, )?; let arg_local = self.frame().mir.args_iter().next().ok_or_else( || EvalErrorKind::AbiViolation("TLS dtor does not take enough arguments.".to_owned()), From 40cc72604afa4c2fc89cca0a86cb5c0f6dd3bd63 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 24 Aug 2018 19:18:21 +0200 Subject: [PATCH 0193/3747] update for bool/char being checked at binops --- tests/compile-fail/invalid_bool.rs | 2 ++ tests/compile-fail/invalid_bool2.rs | 4 ++++ tests/compile-fail/match_char.rs | 12 +++++++----- tests/compile-fail/match_char2.rs | 5 +++++ tests/run-pass/bools.rs | 1 + 5 files changed, 19 insertions(+), 5 deletions(-) create mode 100644 tests/compile-fail/invalid_bool2.rs create mode 100644 tests/compile-fail/match_char2.rs diff --git a/tests/compile-fail/invalid_bool.rs b/tests/compile-fail/invalid_bool.rs index 6ac7f3e60c0d4..bd08c0ce4eb9d 100644 --- a/tests/compile-fail/invalid_bool.rs +++ b/tests/compile-fail/invalid_bool.rs @@ -1,4 +1,6 @@ //ignore-test FIXME (do some basic validation of invariants for all values in flight) +//This does currently not get caught becuase it compiles to SwitchInt, which +//has no knowledge about data invariants. fn main() { let b = unsafe { std::mem::transmute::(2) }; diff --git a/tests/compile-fail/invalid_bool2.rs b/tests/compile-fail/invalid_bool2.rs new file mode 100644 index 0000000000000..47c4e8b410ebe --- /dev/null +++ b/tests/compile-fail/invalid_bool2.rs @@ -0,0 +1,4 @@ +fn main() { + let b = unsafe { std::mem::transmute::(2) }; + let _x = b == true; //~ ERROR invalid boolean value read +} diff --git a/tests/compile-fail/match_char.rs b/tests/compile-fail/match_char.rs index 52f33b58e6fb6..fd4431992d9b6 100644 --- a/tests/compile-fail/match_char.rs +++ b/tests/compile-fail/match_char.rs @@ -1,11 +1,13 @@ // ignore-test FIXME: we are not checking these things on match any more? +//This does currently not get caught becuase it compiles to SwitchInt, which +//has no knowledge about data invariants. fn main() { assert!(std::char::from_u32(-1_i32 as u32).is_none()); - match unsafe { std::mem::transmute::(-1) } { //~ ERROR constant evaluation error + let _ = match unsafe { std::mem::transmute::(-1) } { //~ ERROR constant evaluation error //~^ NOTE tried to interpret an invalid 32-bit value as a char: 4294967295 - 'a' => {}, - 'b' => {}, - _ => {}, - } + 'a' => {true}, + 'b' => {false}, + _ => {true}, + }; } diff --git a/tests/compile-fail/match_char2.rs b/tests/compile-fail/match_char2.rs new file mode 100644 index 0000000000000..786dd813a1eb9 --- /dev/null +++ b/tests/compile-fail/match_char2.rs @@ -0,0 +1,5 @@ +fn main() { + assert!(std::char::from_u32(-1_i32 as u32).is_none()); + let c = unsafe { std::mem::transmute::(-1) }; + let _x = c == 'x'; //~ ERROR tried to interpret an invalid 32-bit value as a char +} diff --git a/tests/run-pass/bools.rs b/tests/run-pass/bools.rs index 103d7eac27cde..30fc14704d9d0 100644 --- a/tests/run-pass/bools.rs +++ b/tests/run-pass/bools.rs @@ -25,4 +25,5 @@ fn main() { assert_eq!(if_false(), 0); assert_eq!(if_true(), 1); assert_eq!(match_bool(), 1); + assert_eq!(true == true, true); } From bb5079b2bfba034fc6ab8fed39348bc59c0d608b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 24 Aug 2018 19:49:57 +0200 Subject: [PATCH 0194/3747] rustup --- src/lib.rs | 11 ++++------- tests/compile-fail/stack_limit.rs | 2 +- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index b529e73690026..c3f411f230631 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,7 +1,4 @@ -#![feature( - rustc_private, - catch_expr, -)] +#![feature(rustc_private)] #![cfg_attr(feature = "cargo-clippy", allow(cast_lossless))] @@ -154,10 +151,10 @@ pub fn eval_main<'a, 'tcx: 'a>( ) { let mut ecx = create_ecx(tcx, main_id, start_wrapper).expect("Couldn't create ecx"); - let res: EvalResult = do catch { + let res: EvalResult = (|| { ecx.run()?; - ecx.run_tls_dtors()?; - }; + ecx.run_tls_dtors() + })(); match res { Ok(()) => { diff --git a/tests/compile-fail/stack_limit.rs b/tests/compile-fail/stack_limit.rs index c6aaf80e6ac00..5645217fe1ff0 100644 --- a/tests/compile-fail/stack_limit.rs +++ b/tests/compile-fail/stack_limit.rs @@ -1,4 +1,4 @@ -#![feature(custom_attribute, attr_literals)] +#![feature(custom_attribute)] #![miri(stack_limit=16)] //error-pattern: reached the configured maximum number of stack frames From 9280d17d981a17ab6c17069c3e4e2959d4372d14 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 24 Aug 2018 19:50:31 +0200 Subject: [PATCH 0195/3747] test VecDeque --- tests/run-pass/vecdeque.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 tests/run-pass/vecdeque.rs diff --git a/tests/run-pass/vecdeque.rs b/tests/run-pass/vecdeque.rs new file mode 100644 index 0000000000000..381169505ec9f --- /dev/null +++ b/tests/run-pass/vecdeque.rs @@ -0,0 +1,15 @@ +use std::collections::VecDeque; + +fn main() { + let mut dst = VecDeque::new(); + dst.push_front(Box::new(1)); + dst.push_front(Box::new(2)); + dst.pop_back(); + + let mut src = VecDeque::new(); + src.push_front(Box::new(2)); + dst.append(&mut src); + for a in dst { + assert_eq!(*a, 2); + } +} From 823837922bfc55c715a170fda3aa5823ead2e235 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 25 Aug 2018 11:07:21 +0200 Subject: [PATCH 0196/3747] update for enum discriminant changes --- src/intrinsic.rs | 2 +- tests/compile-fail/invalid_enum_discriminant.rs | 5 ++--- tests/compile-fail/invalid_enum_discriminant2.rs | 16 ++++++++++++++++ 3 files changed, 19 insertions(+), 4 deletions(-) create mode 100644 tests/compile-fail/invalid_enum_discriminant2.rs diff --git a/src/intrinsic.rs b/src/intrinsic.rs index 62a1938d0fc1f..ed8514863c197 100644 --- a/src/intrinsic.rs +++ b/src/intrinsic.rs @@ -198,7 +198,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: "discriminant_value" => { let place = self.ref_to_mplace(self.read_value(args[0])?)?; - let discr_val = self.read_discriminant_value(place.into())?; + let discr_val = self.read_discriminant(place.into())?.0; self.write_scalar(Scalar::from_uint(discr_val, dest.layout.size), dest)?; } diff --git a/tests/compile-fail/invalid_enum_discriminant.rs b/tests/compile-fail/invalid_enum_discriminant.rs index 760b6563d27cc..a188623a1e0ef 100644 --- a/tests/compile-fail/invalid_enum_discriminant.rs +++ b/tests/compile-fail/invalid_enum_discriminant.rs @@ -8,11 +8,10 @@ pub enum Foo { fn main() { let f = unsafe { std::mem::transmute::(42) }; - match f { + match f { //~ ERROR invalid enum discriminant Foo::A => {}, Foo::B => {}, Foo::C => {}, Foo::D => {}, } -} //~ ERROR constant evaluation error -//~^ NOTE entered unreachable code +} diff --git a/tests/compile-fail/invalid_enum_discriminant2.rs b/tests/compile-fail/invalid_enum_discriminant2.rs new file mode 100644 index 0000000000000..5a5a20c486953 --- /dev/null +++ b/tests/compile-fail/invalid_enum_discriminant2.rs @@ -0,0 +1,16 @@ +// Validation makes this fail in the wrong place +// compile-flags: -Zmir-emit-validate=0 + +// error-pattern: invalid enum discriminant + +use std::mem; + +#[repr(C)] +pub enum Foo { + A, B, C, D +} + +fn main() { + let f = unsafe { std::mem::transmute::(42) }; + let _ = mem::discriminant(&f); +} From 1ba6140891cb1ecaddcb097d22007938bbb34dcd Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 25 Aug 2018 21:22:06 +0200 Subject: [PATCH 0197/3747] rustup --- src/intrinsic.rs | 6 +++--- src/lib.rs | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/intrinsic.rs b/src/intrinsic.rs index ed8514863c197..6847d8e546f36 100644 --- a/src/intrinsic.rs +++ b/src/intrinsic.rs @@ -4,7 +4,7 @@ use rustc::ty; use rustc::mir::interpret::{EvalResult, Scalar, ScalarMaybeUndef}; use rustc_mir::interpret::{ - PlaceExtra, PlaceTy, EvalContext, OpTy, Value + PlaceTy, EvalContext, OpTy, Value }; use super::{ScalarExt, FalibleScalarExt, OperatorEvalContextExt}; @@ -293,7 +293,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: _ => { // Do it in memory let mplace = self.force_allocation(dest)?; - assert_eq!(mplace.extra, PlaceExtra::None); + assert!(mplace.extra.is_none()); self.memory.write_repeat(mplace.ptr, 0, dest.layout.size)?; } } @@ -550,7 +550,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: _ => { // Do it in memory let mplace = self.force_allocation(dest)?; - assert_eq!(mplace.extra, PlaceExtra::None); + assert!(mplace.extra.is_none()); self.memory.mark_definedness(mplace.ptr.to_ptr()?, dest.layout.size, false)?; } } diff --git a/src/lib.rs b/src/lib.rs index c3f411f230631..b0148c16f3e85 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -315,7 +315,7 @@ impl<'mir, 'tcx: 'mir> Machine<'mir, 'tcx> for Evaluator<'tcx> { ) -> EvalResult<'tcx, &'m mut Allocation> { // Make a copy, use that. mem.deep_copy_static(id, MiriMemoryKind::MutStatic.into())?; - mem.get_mut(id) // this is recursive, but now we know that `id` is in `alloc_map` + mem.get_mut(id) // this is recursive, but now we know that `id` is in `alloc_map` now } fn box_alloc<'a>( From 1b41b7182727801b186dfc03284356af6b0afd89 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 26 Aug 2018 13:19:03 +0200 Subject: [PATCH 0198/3747] update for MUT_STATIC_KIND --- src/lib.rs | 13 +++---------- src/memory.rs | 11 ----------- 2 files changed, 3 insertions(+), 21 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index b0148c16f3e85..27abd03f2f9fa 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -274,10 +274,12 @@ impl<'tcx> Hash for MemoryData<'tcx> { } } -impl<'mir, 'tcx: 'mir> Machine<'mir, 'tcx> for Evaluator<'tcx> { +impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { type MemoryData = MemoryData<'tcx>; type MemoryKinds = memory::MemoryKind; + const MUT_STATIC_KIND: Option = Some(memory::MemoryKind::MutStatic); + /// Returns Ok() when the function was handled, fail otherwise fn find_fn<'a>( ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, @@ -309,15 +311,6 @@ impl<'mir, 'tcx: 'mir> Machine<'mir, 'tcx> for Evaluator<'tcx> { ecx.ptr_op(bin_op, left, left_layout, right, right_layout) } - fn access_static_mut<'a, 'm>( - mem: &'m mut Memory<'a, 'mir, 'tcx, Self>, - id: AllocId, - ) -> EvalResult<'tcx, &'m mut Allocation> { - // Make a copy, use that. - mem.deep_copy_static(id, MiriMemoryKind::MutStatic.into())?; - mem.get_mut(id) // this is recursive, but now we know that `id` is in `alloc_map` now - } - fn box_alloc<'a>( ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, dest: PlaceTy<'tcx>, diff --git a/src/memory.rs b/src/memory.rs index bc4c5b70ece35..d4575d677fa14 100644 --- a/src/memory.rs +++ b/src/memory.rs @@ -1,5 +1,3 @@ -use rustc_mir::interpret::IsStatic; - #[derive(Debug, PartialEq, Copy, Clone, Hash, Eq)] pub enum MemoryKind { /// `__rust_alloc` memory @@ -12,15 +10,6 @@ pub enum MemoryKind { MutStatic, } -impl IsStatic for MemoryKind { - fn is_static(self) -> bool { - match self { - MemoryKind::MutStatic => true, - _ => false, - } - } -} - impl Into<::rustc_mir::interpret::MemoryKind> for MemoryKind { fn into(self) -> ::rustc_mir::interpret::MemoryKind { ::rustc_mir::interpret::MemoryKind::Machine(self) From 5ccdbb8de208663461ea57659d06b9e800ff8905 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 26 Aug 2018 14:34:21 +0200 Subject: [PATCH 0199/3747] small test for extern_type --- tests/run-pass/extern_types.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 tests/run-pass/extern_types.rs diff --git a/tests/run-pass/extern_types.rs b/tests/run-pass/extern_types.rs new file mode 100644 index 0000000000000..b37cd8408ba10 --- /dev/null +++ b/tests/run-pass/extern_types.rs @@ -0,0 +1,10 @@ +#![feature(extern_types)] + +extern { + type Foo; +} + +fn main() { + let x: &Foo = unsafe { &*(16 as *const Foo) }; + let _y: &Foo = &*x; +} From 755c68fdd872c9c11fb27f4290ae407381f17fcc Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 26 Aug 2018 20:42:02 +0200 Subject: [PATCH 0200/3747] some unary operator tests --- tests/run-pass/unops.rs | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 tests/run-pass/unops.rs diff --git a/tests/run-pass/unops.rs b/tests/run-pass/unops.rs new file mode 100644 index 0000000000000..650c51ba5d997 --- /dev/null +++ b/tests/run-pass/unops.rs @@ -0,0 +1,5 @@ +fn main() { + assert_eq!(!true, false); + assert_eq!(!0xFFu16, 0xFF00); + assert_eq!(-{1i16}, -1i16); +} From addcbd88684950071bca39d0d7408b1658a1db88 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 30 Aug 2018 08:21:05 +0200 Subject: [PATCH 0201/3747] VecDeque now requries full MIR; update to new nightly --- rust-toolchain | 2 +- tests/{run-pass => run-pass-fullmir}/vecdeque.rs | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename tests/{run-pass => run-pass-fullmir}/vecdeque.rs (100%) diff --git a/rust-toolchain b/rust-toolchain index ec8c56dc6248b..f54012d5e14b9 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1 +1 @@ -nightly-2018-08-14 +nightly-2018-08-30 diff --git a/tests/run-pass/vecdeque.rs b/tests/run-pass-fullmir/vecdeque.rs similarity index 100% rename from tests/run-pass/vecdeque.rs rename to tests/run-pass-fullmir/vecdeque.rs From d7a3e040eb49129ce79ee604fb593671d1f86901 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 30 Aug 2018 08:33:38 +0200 Subject: [PATCH 0202/3747] pthreads test needs full MIR on Windows --- tests/{run-pass/pthreads.rs => run-pass-fullmir/threads.rs} | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) rename tests/{run-pass/pthreads.rs => run-pass-fullmir/threads.rs} (80%) diff --git a/tests/run-pass/pthreads.rs b/tests/run-pass-fullmir/threads.rs similarity index 80% rename from tests/run-pass/pthreads.rs rename to tests/run-pass-fullmir/threads.rs index ec7e082a5d5f0..93a08bfc25884 100644 --- a/tests/run-pass/pthreads.rs +++ b/tests/run-pass-fullmir/threads.rs @@ -1,4 +1,5 @@ -// Just instantiate some data structures to make sure we got all their foreign items covered +// Just instantiate some data structures to make sure we got all their foreign items covered. +// Requires full MIR on Windows. use std::sync; From 0db1c6a1b0ec2fe5e7a3c15273e8a97b8747d7b7 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 30 Aug 2018 08:57:33 +0200 Subject: [PATCH 0203/3747] ignore memory leaks on Windows --- src/lib.rs | 5 ++++- tests/compile-fail/memleak.rs | 2 ++ tests/compile-fail/memleak_rc.rs | 2 ++ 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 27abd03f2f9fa..8fff4635fa0ef 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -159,7 +159,10 @@ pub fn eval_main<'a, 'tcx: 'a>( match res { Ok(()) => { let leaks = ecx.memory().leak_report(); - if leaks != 0 { + // Disable the leak test on some platforms where we likely do not + // correctly implement TLS destructors. + let target_os = &ecx.tcx.tcx.sess.target.target.target_os; + if target_os.to_lowercase() != "windows" && leaks != 0 { tcx.sess.err("the evaluated program leaked memory"); } } diff --git a/tests/compile-fail/memleak.rs b/tests/compile-fail/memleak.rs index 71b4e2f442f31..7f155edc35a51 100644 --- a/tests/compile-fail/memleak.rs +++ b/tests/compile-fail/memleak.rs @@ -1,3 +1,5 @@ +// ignore-windows + //error-pattern: the evaluated program leaked memory fn main() { diff --git a/tests/compile-fail/memleak_rc.rs b/tests/compile-fail/memleak_rc.rs index b2bc6722afb04..24e8363049c8c 100644 --- a/tests/compile-fail/memleak_rc.rs +++ b/tests/compile-fail/memleak_rc.rs @@ -1,3 +1,5 @@ +// ignore-windows + //error-pattern: the evaluated program leaked memory use std::rc::Rc; From b4ebe72b1be436d812ac758247ba6553b0d574c5 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 30 Aug 2018 09:04:57 +0200 Subject: [PATCH 0204/3747] stack address functions for macOS --- src/fn_call.rs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index d16e024db47d4..167703c0f04c0 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -544,16 +544,21 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for EvalContext<'a, ' // Determining stack base address "pthread_attr_init" | "pthread_attr_destroy" | "pthread_attr_get_np" | - "pthread_getattr_np" | "pthread_self" => { + "pthread_getattr_np" | "pthread_self" | "pthread_get_stacksize_np" => { self.write_null(dest)?; } "pthread_attr_getstack" => { // second argument is where we are supposed to write the stack size let ptr = self.ref_to_mplace(self.read_value(args[1])?)?; - self.write_scalar(Scalar::from_int(0x80000, args[1].layout.size), ptr.into())?; + let stackaddr = Scalar::from_int(0x80000, args[1].layout.size); // just any address + self.write_scalar(stackaddr, ptr.into())?; // return 0 self.write_null(dest)?; } + "pthread_get_stackaddr_np" => { + let stackaddr = Scalar::from_int(0x80000, dest.layout.size); // just any address + self.write_scalar(stackaddr, dest)?; + } // Stub out calls for condvar, mutex and rwlock to just return 0 "pthread_mutexattr_init" | "pthread_mutexattr_settype" | "pthread_mutex_init" | From d1cd2540030d9fe52584d04ba2c188b9f679cb16 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 30 Aug 2018 09:20:08 +0200 Subject: [PATCH 0205/3747] no RwLock on Windows --- tests/run-pass-fullmir/threads.rs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/tests/run-pass-fullmir/threads.rs b/tests/run-pass-fullmir/threads.rs index 93a08bfc25884..f920bc52edde3 100644 --- a/tests/run-pass-fullmir/threads.rs +++ b/tests/run-pass-fullmir/threads.rs @@ -8,8 +8,12 @@ fn main() { let _ = m.lock(); drop(m); - let rw = sync::RwLock::new(0); - let _ = rw.read(); - let _ = rw.write(); - drop(rw); + // We don't provide RwLock on Windows + #[cfg(not(target_os = "windows"))] + { + let rw = sync::RwLock::new(0); + let _ = rw.read(); + let _ = rw.write(); + drop(rw); + } } From e2ec521f218bbc1c3677021644fc5e63641b94d5 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 30 Aug 2018 09:22:01 +0200 Subject: [PATCH 0206/3747] pretend mprotect works --- src/fn_call.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/fn_call.rs b/src/fn_call.rs index 167703c0f04c0..fb77f01876d90 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -575,6 +575,9 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for EvalContext<'a, ' let addr = self.read_scalar(args[0])?.not_undef()?; self.write_scalar(addr, dest)?; } + "mprotect" => { + self.write_null(dest)?; + } // Windows API subs "AddVectoredExceptionHandler" => { From 2a244dcb4893a26b02ae2bd01309b8499685457b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 30 Aug 2018 09:41:57 +0200 Subject: [PATCH 0207/3747] no TLS dtor and no leak checks on macOS --- src/fn_call.rs | 2 +- src/lib.rs | 5 +++-- tests/compile-fail/memleak.rs | 3 ++- tests/compile-fail/memleak_rc.rs | 3 ++- 4 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index fb77f01876d90..a9791e2b7ca7f 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -539,7 +539,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for EvalContext<'a, ' } "_tlv_atexit" => { - return err!(Unimplemented("Thread-local store is not fully supported on macOS".to_owned())); + // FIXME: Register the dtor }, // Determining stack base address diff --git a/src/lib.rs b/src/lib.rs index 8fff4635fa0ef..42dac6a28d855 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -161,8 +161,9 @@ pub fn eval_main<'a, 'tcx: 'a>( let leaks = ecx.memory().leak_report(); // Disable the leak test on some platforms where we likely do not // correctly implement TLS destructors. - let target_os = &ecx.tcx.tcx.sess.target.target.target_os; - if target_os.to_lowercase() != "windows" && leaks != 0 { + let target_os = ecx.tcx.tcx.sess.target.target.target_os.to_lowercase(); + let ignore_leaks = target_os == "windows" || target_os == "macos"; + if !ignore_leaks && leaks != 0 { tcx.sess.err("the evaluated program leaked memory"); } } diff --git a/tests/compile-fail/memleak.rs b/tests/compile-fail/memleak.rs index 7f155edc35a51..06e01d7aea3a5 100644 --- a/tests/compile-fail/memleak.rs +++ b/tests/compile-fail/memleak.rs @@ -1,4 +1,5 @@ -// ignore-windows +// ignore-windows: We do not check leaks on Windows +// ignore-macos: We do not check leaks on macOS //error-pattern: the evaluated program leaked memory diff --git a/tests/compile-fail/memleak_rc.rs b/tests/compile-fail/memleak_rc.rs index 24e8363049c8c..14a85ecd8947c 100644 --- a/tests/compile-fail/memleak_rc.rs +++ b/tests/compile-fail/memleak_rc.rs @@ -1,4 +1,5 @@ -// ignore-windows +// ignore-windows: We do not check leaks on Windows +// ignore-macos: We do not check leaks on macOS //error-pattern: the evaluated program leaked memory From 904923fa7a4635636b0bc5c33e9901773e7f6747 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 26 Aug 2018 20:42:26 +0200 Subject: [PATCH 0208/3747] move some more helpers to rustc --- src/fn_call.rs | 8 +++--- src/helpers.rs | 45 -------------------------------- src/intrinsic.rs | 58 ++++++++++++++++-------------------------- src/lib.rs | 2 +- src/tls.rs | 8 +++--- tests/run-pass/char.rs | 4 +-- 6 files changed, 31 insertions(+), 94 deletions(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index a9791e2b7ca7f..0e768fcccf9e5 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -305,7 +305,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for EvalContext<'a, ' }; self.write_scalar( - Scalar::from_i32(result), + Scalar::from_int(result, Size::from_bits(32)), dest, )?; } @@ -346,7 +346,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for EvalContext<'a, ' let name = self.memory.read_c_str(name_ptr)?; match self.machine.env_vars.get(name) { Some(&var) => Scalar::Ptr(var), - None => Scalar::null(self.memory.pointer_size()), + None => Scalar::ptr_null(*self.tcx), } }; self.write_scalar(result, dest)?; @@ -446,7 +446,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for EvalContext<'a, ' // Some things needed for sys::thread initialization to go through "signal" | "sigaction" | "sigaltstack" => { - self.write_scalar(Scalar::null(dest.layout.size), dest)?; + self.write_scalar(Scalar::from_int(0, dest.layout.size), dest)?; } "sysconf" => { @@ -729,6 +729,6 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for EvalContext<'a, ' } fn write_null(&mut self, dest: PlaceTy<'tcx>) -> EvalResult<'tcx> { - self.write_scalar(Scalar::null(dest.layout.size), dest) + self.write_scalar(Scalar::from_int(0, dest.layout.size), dest) } } diff --git a/src/helpers.rs b/src/helpers.rs index 24285fa4a6e8f..27b2109d18a16 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -1,17 +1,5 @@ -use rustc::ty::layout::Size; - use super::{Scalar, ScalarMaybeUndef, EvalResult}; -pub trait ScalarExt { - fn null(size: Size) -> Self; - fn from_i32(i: i32) -> Self; - fn from_uint(i: impl Into, ptr_size: Size) -> Self; - fn from_int(i: impl Into, ptr_size: Size) -> Self; - fn from_f32(f: f32) -> Self; - fn from_f64(f: f64) -> Self; - fn is_null(self) -> bool; -} - pub trait FalibleScalarExt { /// 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 @@ -19,39 +7,6 @@ pub trait FalibleScalarExt { fn to_bytes(self) -> EvalResult<'static, u128>; } -impl ScalarExt for Scalar { - 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, size: 4 } - } - - fn from_uint(i: impl Into, size: Size) -> Self { - Scalar::Bits { bits: i.into(), size: size.bytes() as u8 } - } - - fn from_int(i: impl Into, size: Size) -> Self { - Scalar::Bits { bits: i.into() as u128, size: size.bytes() as u8 } - } - - fn from_f32(f: f32) -> Self { - Scalar::Bits { bits: f.to_bits() as u128, size: 4 } - } - - fn from_f64(f: f64) -> Self { - Scalar::Bits { bits: f.to_bits() as u128, size: 8 } - } - - fn is_null(self) -> bool { - match self { - Scalar::Bits { bits, .. } => bits == 0, - Scalar::Ptr(_) => false - } - } -} - impl FalibleScalarExt for Scalar { fn to_bytes(self) -> EvalResult<'static, u128> { match self { diff --git a/src/intrinsic.rs b/src/intrinsic.rs index 6847d8e546f36..695943d57b0c9 100644 --- a/src/intrinsic.rs +++ b/src/intrinsic.rs @@ -2,12 +2,12 @@ use rustc::mir; use rustc::ty::layout::{self, LayoutOf, Size}; use rustc::ty; -use rustc::mir::interpret::{EvalResult, Scalar, ScalarMaybeUndef}; +use rustc::mir::interpret::{EvalResult, Scalar, ScalarMaybeUndef, PointerArithmetic}; use rustc_mir::interpret::{ PlaceTy, EvalContext, OpTy, Value }; -use super::{ScalarExt, FalibleScalarExt, OperatorEvalContextExt}; +use super::{FalibleScalarExt, OperatorEvalContextExt}; pub trait EvalContextExt<'tcx> { fn call_intrinsic( @@ -204,8 +204,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: "sinf32" | "fabsf32" | "cosf32" | "sqrtf32" | "expf32" | "exp2f32" | "logf32" | "log10f32" | "log2f32" | "floorf32" | "ceilf32" | "truncf32" => { - let f = self.read_scalar(args[0])?.to_bytes()?; - let f = f32::from_bits(f as u32); + let f = self.read_scalar(args[0])?.to_f32()?; let f = match intrinsic_name { "sinf32" => f.sin(), "fabsf32" => f.abs(), @@ -226,8 +225,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: "sinf64" | "fabsf64" | "cosf64" | "sqrtf64" | "expf64" | "exp2f64" | "logf64" | "log10f64" | "log2f64" | "floorf64" | "ceilf64" | "truncf64" => { - let f = self.read_scalar(args[0])?.to_bytes()?; - let f = f64::from_bits(f as u64); + let f = self.read_scalar(args[0])?.to_f64()?; let f = match intrinsic_name { "sinf64" => f.sin(), "fabsf64" => f.abs(), @@ -282,12 +280,12 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: if !dest.layout.is_zst() { // notzhing to do for ZST match dest.layout.abi { layout::Abi::Scalar(ref s) => { - let x = Scalar::null(s.value.size(&self)); + let x = Scalar::from_int(0, s.value.size(&self)); self.write_value(Value::Scalar(x.into()), dest)?; } layout::Abi::ScalarPair(ref s1, ref s2) => { - let x = Scalar::null(s1.value.size(&self)); - let y = Scalar::null(s2.value.size(&self)); + let x = Scalar::from_int(0, s1.value.size(&self)); + let y = Scalar::from_int(0, s2.value.size(&self)); self.write_value(Value::ScalarPair(x.into(), y.into()), dest)?; } _ => { @@ -304,7 +302,7 @@ 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 ptr_size = self.memory.pointer_size(); + let ptr_size = self.pointer_size(); let align_val = Scalar::from_uint(align as u128, ptr_size); self.write_scalar(align_val, dest)?; } @@ -365,10 +363,8 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: } "powf32" => { - let f = self.read_scalar(args[0])?.to_bits(Size::from_bits(32))?; - let f = f32::from_bits(f as u32); - let f2 = self.read_scalar(args[1])?.to_bits(Size::from_bits(32))?; - let f2 = f32::from_bits(f2 as u32); + let f = self.read_scalar(args[0])?.to_f32()?; + let f2 = self.read_scalar(args[1])?.to_f32()?; self.write_scalar( Scalar::from_f32(f.powf(f2)), dest, @@ -376,10 +372,8 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: } "powf64" => { - let f = self.read_scalar(args[0])?.to_bits(Size::from_bits(64))?; - let f = f64::from_bits(f as u64); - let f2 = self.read_scalar(args[1])?.to_bits(Size::from_bits(64))?; - let f2 = f64::from_bits(f2 as u64); + let f = self.read_scalar(args[0])?.to_f64()?; + let f2 = self.read_scalar(args[1])?.to_f64()?; self.write_scalar( Scalar::from_f64(f.powf(f2)), dest, @@ -387,12 +381,9 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: } "fmaf32" => { - let a = self.read_scalar(args[0])?.to_bits(Size::from_bits(32))?; - let a = f32::from_bits(a as u32); - let b = self.read_scalar(args[1])?.to_bits(Size::from_bits(32))?; - let b = f32::from_bits(b as u32); - let c = self.read_scalar(args[2])?.to_bits(Size::from_bits(32))?; - let c = f32::from_bits(c as u32); + let a = self.read_scalar(args[0])?.to_f32()?; + let b = self.read_scalar(args[1])?.to_f32()?; + let c = self.read_scalar(args[2])?.to_f32()?; self.write_scalar( Scalar::from_f32(a * b + c), dest, @@ -400,12 +391,9 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: } "fmaf64" => { - let a = self.read_scalar(args[0])?.to_bits(Size::from_bits(64))?; - let a = f64::from_bits(a as u64); - let b = self.read_scalar(args[1])?.to_bits(Size::from_bits(64))?; - let b = f64::from_bits(b as u64); - let c = self.read_scalar(args[2])?.to_bits(Size::from_bits(64))?; - let c = f64::from_bits(c as u64); + let a = self.read_scalar(args[0])?.to_f64()?; + let b = self.read_scalar(args[1])?.to_f64()?; + let c = self.read_scalar(args[2])?.to_f64()?; self.write_scalar( Scalar::from_f64(a * b + c), dest, @@ -413,8 +401,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: } "powif32" => { - let f = self.read_scalar(args[0])?.to_bits(Size::from_bits(32))?; - let f = f32::from_bits(f as u32); + let f = self.read_scalar(args[0])?.to_f32()?; let i = self.read_scalar(args[1])?.to_i32()?; self.write_scalar( Scalar::from_f32(f.powi(i)), @@ -423,8 +410,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: } "powif64" => { - let f = self.read_scalar(args[0])?.to_bits(Size::from_bits(64))?; - let f = f64::from_bits(f as u64); + let f = self.read_scalar(args[0])?.to_f64()?; let i = self.read_scalar(args[1])?.to_i32()?; self.write_scalar( Scalar::from_f64(f.powi(i)), @@ -435,7 +421,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: "size_of_val" => { let mplace = self.ref_to_mplace(self.read_value(args[0])?)?; let (size, _) = self.size_and_align_of_mplace(mplace)?; - let ptr_size = self.memory.pointer_size(); + let ptr_size = self.pointer_size(); self.write_scalar( Scalar::from_uint(size.bytes() as u128, ptr_size), dest, @@ -446,7 +432,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: "align_of_val" => { let mplace = self.ref_to_mplace(self.read_value(args[0])?)?; let (_, align) = self.size_and_align_of_mplace(mplace)?; - let ptr_size = self.memory.pointer_size(); + let ptr_size = self.pointer_size(); self.write_scalar( Scalar::from_uint(align.abi(), ptr_size), dest, diff --git a/src/lib.rs b/src/lib.rs index 42dac6a28d855..0ce510a65983e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -46,7 +46,7 @@ use tls::EvalContextExt as TlsEvalContextExt; use memory::MemoryKind as MiriMemoryKind; use locks::LockInfo; use range_map::RangeMap; -use helpers::{ScalarExt, FalibleScalarExt}; +use helpers::FalibleScalarExt; pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( tcx: TyCtxt<'a, 'tcx, 'tcx>, diff --git a/src/tls.rs b/src/tls.rs index 6cec39483c465..bd0318a62ed45 100644 --- a/src/tls.rs +++ b/src/tls.rs @@ -1,6 +1,6 @@ use rustc::{ty, mir}; -use super::{TlsKey, TlsEntry, EvalResult, EvalErrorKind, Scalar, ScalarExt, Memory, Evaluator, +use super::{TlsKey, TlsEntry, EvalResult, EvalErrorKind, Scalar, Memory, Evaluator, Place, StackPopCleanup, EvalContext}; pub trait MemoryExt<'tcx> { @@ -22,11 +22,10 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> MemoryExt<'tcx> for Memory<'a, 'mir, 'tcx, Evalu fn create_tls_key(&mut self, dtor: Option>) -> TlsKey { let new_key = self.data.next_thread_local; self.data.next_thread_local += 1; - let ptr_size = self.pointer_size(); self.data.thread_local.insert( new_key, TlsEntry { - data: Scalar::null(ptr_size).into(), + data: Scalar::ptr_null(*self.tcx).into(), dtor, }, ); @@ -89,7 +88,6 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> MemoryExt<'tcx> for Memory<'a, 'mir, 'tcx, Evalu ) -> 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), @@ -101,7 +99,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> MemoryExt<'tcx> for Memory<'a, 'mir, 'tcx, Evalu if !data.is_null() { if let Some(dtor) = dtor { let ret = Some((dtor, *data, key)); - *data = Scalar::null(ptr_size); + *data = Scalar::ptr_null(*self.tcx); return ret; } } diff --git a/tests/run-pass/char.rs b/tests/run-pass/char.rs index 505c09b0ad885..5524f0ae7abea 100644 --- a/tests/run-pass/char.rs +++ b/tests/run-pass/char.rs @@ -3,7 +3,5 @@ fn main() { assert_eq!(c, 'x'); assert!('a' < 'z'); assert!('1' < '9'); - assert_eq!(std::char::from_u32('x' as u32).unwrap(), 'x'); - // FIXME: - // assert_eq!(std::char::from_u32('x' as u32), Some('x')); + assert_eq!(std::char::from_u32('x' as u32), Some('x')); } From e239fcffc1a211ff3f2f7dce4d084615aaa73715 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 27 Aug 2018 17:08:42 +0200 Subject: [PATCH 0209/3747] new tests for new fn arg passing code --- tests/compile-fail/cast_fn_ptr.rs | 3 +-- tests/compile-fail/cast_fn_ptr2.rs | 3 +-- tests/compile-fail/cast_fn_ptr3.rs | 10 ++++++++++ tests/compile-fail/cast_fn_ptr4.rs | 9 +++++++++ tests/run-pass/non_capture_closure_to_fn_ptr.rs | 6 ++++++ 5 files changed, 27 insertions(+), 4 deletions(-) create mode 100644 tests/compile-fail/cast_fn_ptr3.rs create mode 100644 tests/compile-fail/cast_fn_ptr4.rs diff --git a/tests/compile-fail/cast_fn_ptr.rs b/tests/compile-fail/cast_fn_ptr.rs index 0a8f5ef752a6d..0add977bf97b4 100644 --- a/tests/compile-fail/cast_fn_ptr.rs +++ b/tests/compile-fail/cast_fn_ptr.rs @@ -5,6 +5,5 @@ fn main() { std::mem::transmute::(f) }; - g(42) //~ ERROR constant evaluation error - //~^ NOTE tried to call a function with sig fn() through a function pointer of type fn(i32) + g(42) //~ ERROR tried to call a function with incorrect number of arguments } diff --git a/tests/compile-fail/cast_fn_ptr2.rs b/tests/compile-fail/cast_fn_ptr2.rs index cb80521c60eeb..5af527016fb6f 100644 --- a/tests/compile-fail/cast_fn_ptr2.rs +++ b/tests/compile-fail/cast_fn_ptr2.rs @@ -5,6 +5,5 @@ fn main() { std::mem::transmute::(f) }; - g(42) //~ ERROR constant evaluation error - //~^ NOTE tried to call a function with sig fn((i32, i32)) through a function pointer of type fn(i32) + g(42) //~ ERROR tried to call a function with argument of type (i32, i32) passing data of type i32 } diff --git a/tests/compile-fail/cast_fn_ptr3.rs b/tests/compile-fail/cast_fn_ptr3.rs new file mode 100644 index 0000000000000..29507e7c7cf54 --- /dev/null +++ b/tests/compile-fail/cast_fn_ptr3.rs @@ -0,0 +1,10 @@ +fn main() { + fn f(_ : (i32,i32)) {} + + let g = unsafe { + std::mem::transmute::(f) + }; + + g() //~ ERROR tried to call a function with incorrect number of arguments +} + diff --git a/tests/compile-fail/cast_fn_ptr4.rs b/tests/compile-fail/cast_fn_ptr4.rs new file mode 100644 index 0000000000000..f9a2cf9f6965e --- /dev/null +++ b/tests/compile-fail/cast_fn_ptr4.rs @@ -0,0 +1,9 @@ +fn main() { + fn f(_ : *const [i32]) {} + + let g = unsafe { + std::mem::transmute::(f) + }; + + g(&42 as *const i32) //~ ERROR tried to call a function with argument of type *const [i32] passing data of type *const i32 +} diff --git a/tests/run-pass/non_capture_closure_to_fn_ptr.rs b/tests/run-pass/non_capture_closure_to_fn_ptr.rs index c9daff9c9f469..d48c4df45944a 100644 --- a/tests/run-pass/non_capture_closure_to_fn_ptr.rs +++ b/tests/run-pass/non_capture_closure_to_fn_ptr.rs @@ -4,6 +4,9 @@ static FOO: fn() = || { assert_ne!(42, 43) }; #[allow(const_err)] static BAR: fn(i32, i32) = |a, b| { assert_ne!(a, b) }; +// use to first make the closure FnOnce() before making it fn() +fn magic(f: F) -> F { f } + fn main() { FOO(); BAR(44, 45); @@ -11,4 +14,7 @@ fn main() { unsafe { bar(46, 47) }; let boo: &Fn(i32, i32) = &BAR; boo(48, 49); + + let f = magic(||{}) as fn(); + f(); } From c44267960f4642a1875de9e39ef7287961c56d3a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 28 Aug 2018 18:13:58 +0200 Subject: [PATCH 0210/3747] ptr equality: only defined for ptrs in the same allocation and live ptrs --- src/intrinsic.rs | 19 ++- src/lib.rs | 4 +- src/operator.rs | 157 +++++++++++----------- tests/compile-fail/pointer_byte_read_1.rs | 3 +- tests/compile-fail/ptr_bitops.rs | 3 +- 5 files changed, 87 insertions(+), 99 deletions(-) diff --git a/src/intrinsic.rs b/src/intrinsic.rs index 695943d57b0c9..1b877256c31fa 100644 --- a/src/intrinsic.rs +++ b/src/intrinsic.rs @@ -116,11 +116,11 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: _ if intrinsic_name.starts_with("atomic_cxchg") => { let ptr = self.ref_to_mplace(self.read_value(args[0])?)?; - let expect_old = self.read_value(args[1])?; // read as value for the sake of `binary_op()` + let expect_old = self.read_value(args[1])?; // read as value for the sake of `binary_op_val()` let new = self.read_scalar(args[2])?; - let old = self.read_value(ptr.into())?; // read as value for the sake of `binary_op()` - // binary_op will bail if either of them is not a scalar - let (eq, _) = self.binary_op(mir::BinOp::Eq, old, expect_old)?; + let old = self.read_value(ptr.into())?; // read as value for the sake of `binary_op_val()` + // binary_op_val will bail if either of them is not a scalar + let (eq, _) = self.binary_op_val(mir::BinOp::Eq, old, expect_old)?; let res = Value::ScalarPair(old.to_scalar_or_undef(), eq.into()); self.write_value(res, dest)?; // old value is returned // update ptr depending on comparison @@ -167,8 +167,7 @@ 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, rhs)?; - self.write_scalar(val, ptr.into())?; + self.binop_ignore_overflow(op, old, rhs, ptr.into())?; } "breakpoint" => unimplemented!(), // halt miri @@ -255,8 +254,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: "frem_fast" => mir::BinOp::Rem, _ => bug!(), }; - let result = self.binary_op(op, a, b)?; - self.write_scalar(result.0, dest)?; + self.binop_ignore_overflow(op, a, b, dest)?; } "exact_div" => { @@ -265,11 +263,10 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: let a = self.read_value(args[0])?; let b = self.read_value(args[1])?; // check x % y != 0 - if !self.binary_op(mir::BinOp::Rem, a, b)?.0.is_null() { + if !self.binary_op_val(mir::BinOp::Rem, a, b)?.0.is_null() { return err!(ValidationFailure(format!("exact_div: {:?} cannot be divided by {:?}", a, b))); } - let result = self.binary_op(mir::BinOp::Div, a, b)?; - self.write_scalar(result.0, dest)?; + self.binop_ignore_overflow(mir::BinOp::Div, a, b, dest)?; }, "likely" | "unlikely" | "forget" => {} diff --git a/src/lib.rs b/src/lib.rs index 0ce510a65983e..b8d3c18c01cba 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -304,14 +304,14 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { ecx.call_intrinsic(instance, args, dest) } - fn try_ptr_op<'a>( + fn ptr_op<'a>( ecx: &rustc_mir::interpret::EvalContext<'a, 'mir, 'tcx, Self>, bin_op: mir::BinOp, left: Scalar, left_layout: TyLayout<'tcx>, right: Scalar, right_layout: TyLayout<'tcx>, - ) -> EvalResult<'tcx, Option<(Scalar, bool)>> { + ) -> EvalResult<'tcx, (Scalar, bool)> { ecx.ptr_op(bin_op, left, left_layout, right, right_layout) } diff --git a/src/operator.rs b/src/operator.rs index 03383ae61c894..550e7014afa97 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -1,5 +1,4 @@ -use rustc::ty::{self, Ty}; -use rustc::ty::layout::{TyLayout, Primitive}; +use rustc::ty::{Ty, layout::TyLayout}; use rustc::mir; use super::*; @@ -12,7 +11,7 @@ pub trait EvalContextExt<'tcx> { left_layout: TyLayout<'tcx>, right: Scalar, right_layout: TyLayout<'tcx>, - ) -> EvalResult<'tcx, Option<(Scalar, bool)>>; + ) -> EvalResult<'tcx, (Scalar, bool)>; fn ptr_int_arithmetic( &self, @@ -22,6 +21,13 @@ pub trait EvalContextExt<'tcx> { signed: bool, ) -> EvalResult<'tcx, (Scalar, bool)>; + fn ptr_eq( + &self, + left: Scalar, + right: Scalar, + size: Size, + ) -> EvalResult<'tcx, bool>; + fn pointer_offset_inbounds( &self, ptr: Scalar, @@ -38,38 +44,14 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: left_layout: TyLayout<'tcx>, right: Scalar, right_layout: TyLayout<'tcx>, - ) -> EvalResult<'tcx, Option<(Scalar, bool)>> { + ) -> EvalResult<'tcx, (Scalar, bool)> { + use rustc::mir::BinOp::*; + trace!("ptr_op: {:?} {:?} {:?}", left, bin_op, right); + debug_assert!(left.is_ptr() || right.is_ptr() || bin_op == Offset); - use rustc::mir::BinOp::*; - use rustc::ty::layout::Integer::*; - let usize = Primitive::Int(match self.memory.pointer_size().bytes() { - 1 => I8, - 2 => I16, - 4 => I32, - 8 => I64, - 16 => I128, - _ => unreachable!(), - }, /*signed*/ false); - let isize = Primitive::Int(match self.memory.pointer_size().bytes() { - 1 => I8, - 2 => I16, - 4 => I32, - 8 => I64, - 16 => I128, - _ => unreachable!(), - }, /*signed*/ true); - let left_kind = match left_layout.abi { - ty::layout::Abi::Scalar(ref scalar) => scalar.value, - _ => Err(EvalErrorKind::TypeNotPrimitive(left_layout.ty))?, - }; - let right_kind = match right_layout.abi { - ty::layout::Abi::Scalar(ref scalar) => scalar.value, - _ => Err(EvalErrorKind::TypeNotPrimitive(right_layout.ty))?, - }; match bin_op { Offset => { - assert!(left_kind == Primitive::Pointer && right_kind == usize); let pointee_ty = left_layout.ty .builtin_deref(true) .expect("Offset called on non-ptr type") @@ -77,40 +59,19 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: let ptr = self.pointer_offset_inbounds( left, pointee_ty, - right.to_bits(self.memory.pointer_size())? as i64, + right.to_isize(self)?, )?; - Ok(Some((ptr, false))) + Ok((ptr, false)) } // These work on anything - Eq if left_kind == right_kind => { - let result = match (left, right) { - (Scalar::Bits { .. }, Scalar::Bits { .. }) => { - left.to_bits(left_layout.size)? == right.to_bits(right_layout.size)? - }, - // FIXME: Test if both allocations are still live *or* if they are in the same allocation? (same for Ne below) - (Scalar::Ptr(left), Scalar::Ptr(right)) => left == right, - // FIXME: We should probably error out when comparing anything but NULL with a pointer (same for Ne below) - _ => false, - }; - Ok(Some((Scalar::from_bool(result), false))) - } - Ne if left_kind == right_kind => { - let result = match (left, right) { - (Scalar::Bits { .. }, Scalar::Bits { .. }) => { - left.to_bits(left_layout.size)? != right.to_bits(right_layout.size)? - }, - (Scalar::Ptr(left), Scalar::Ptr(right)) => left != right, - _ => true, - }; - Ok(Some((Scalar::from_bool(result), false))) - } - // These need both pointers to be in the same allocation - Lt | Le | Gt | Ge | Sub - if left_kind == right_kind && - (left_kind == Primitive::Pointer || left_kind == usize || left_kind == isize) && - left.is_ptr() && right.is_ptr() => { - let left = left.to_ptr()?; - let right = right.to_ptr()?; + Eq => + Ok((Scalar::from_bool(self.ptr_eq(left, right, left_layout.size)?), false)), + Ne => + Ok((Scalar::from_bool(!self.ptr_eq(left, right, left_layout.size)?), false)), + // These need both to be pointer, and fail if they are not in the same location + Lt | Le | Gt | Ge | Sub if left.is_ptr() && right.is_ptr() => { + let left = left.to_ptr().expect("we checked is_ptr"); + let right = right.to_ptr().expect("we checked is_ptr"); if left.alloc_id == right.alloc_id { let res = match bin_op { Lt => left.offset < right.offset, @@ -118,51 +79,83 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: Gt => left.offset > right.offset, Ge => left.offset >= right.offset, Sub => { + // subtract the offsets let left_offset = Scalar::from_uint(left.offset.bytes(), self.memory.pointer_size()); let right_offset = Scalar::from_uint(right.offset.bytes(), self.memory.pointer_size()); let layout = self.layout_of(self.tcx.types.usize)?; return self.binary_op( Sub, - ValTy { value: Value::Scalar(left_offset.into()), layout }, - ValTy { value: Value::Scalar(right_offset.into()), layout }, - ).map(Some) + left_offset, layout, + right_offset, layout, + ) } _ => bug!("We already established it has to be one of these operators."), }; - Ok(Some((Scalar::from_bool(res), false))) + Ok((Scalar::from_bool(res), false)) } else { // Both are pointers, but from different allocations. err!(InvalidPointerMath) } } - // These work if the left operand is a pointer, the right an integer - Add | BitAnd | Sub | Rem - if left_kind == right_kind && (left_kind == usize || left_kind == isize) && - left.is_ptr() && right.is_bits() => { + // These work if the left operand is a pointer, and the right an integer + Add | BitAnd | Sub | Rem if left.is_ptr() && right.is_bits() => { // Cast to i128 is fine as we checked the kind to be ptr-sized self.ptr_int_arithmetic( bin_op, - left.to_ptr()?, - right.to_bits(self.memory.pointer_size())?, - left_kind == isize, - ).map(Some) + left.to_ptr().expect("we checked is_ptr"), + right.to_bits(self.memory.pointer_size()).expect("we checked is_bits"), + right_layout.abi.is_signed(), + ) } // Commutative operators also work if the integer is on the left - Add | BitAnd - if left_kind == right_kind && (left_kind == usize || left_kind == isize) && - left.is_bits() && right.is_ptr() => { + Add | BitAnd if left.is_bits() && right.is_ptr() => { // This is a commutative operation, just swap the operands self.ptr_int_arithmetic( bin_op, - right.to_ptr()?, - left.to_bits(self.memory.pointer_size())?, - left_kind == isize, - ).map(Some) + right.to_ptr().expect("we checked is_ptr"), + left.to_bits(self.memory.pointer_size()).expect("we checked is_bits"), + left_layout.abi.is_signed(), + ) } - _ => Ok(None), + // Nothing else works + _ => err!(InvalidPointerMath), } } + fn ptr_eq( + &self, + left: Scalar, + right: Scalar, + size: Size, + ) -> EvalResult<'tcx, bool> { + Ok(match (left, right) { + (Scalar::Bits { .. }, Scalar::Bits { .. }) => + left.to_bits(size)? == right.to_bits(size)?, + (Scalar::Ptr(left), Scalar::Ptr(right)) => { + // Comparison illegal if one of them is out-of-bounds, *unless* they + // are in the same allocation. + if left.alloc_id == right.alloc_id { + left.offset == right.offset + } else { + // This accepts one-past-the end. So technically there is still + // some non-determinism that we do not fully rule out when two + // allocations sit right next to each other. The C/C++ standards are + // somewhat fuzzy about this case, so I think for now this check is + // "good enough". + self.memory.check_bounds(left, false)?; + self.memory.check_bounds(right, false)?; + // Two live in-bounds pointers, we can compare across allocations + left == right + } + } + // Comparing ptr and integer -- we only allow compating with NULL + (Scalar::Ptr(_), Scalar::Bits { bits: 0, .. }) | + (Scalar::Bits { bits: 0, .. }, Scalar::Ptr(_)) => false, + // Nothing else is supported + _ => return err!(InvalidPointerMath), + }) + } + fn ptr_int_arithmetic( &self, bin_op: mir::BinOp, diff --git a/tests/compile-fail/pointer_byte_read_1.rs b/tests/compile-fail/pointer_byte_read_1.rs index 4cfdfb62e27f5..b25f09d485fb3 100644 --- a/tests/compile-fail/pointer_byte_read_1.rs +++ b/tests/compile-fail/pointer_byte_read_1.rs @@ -3,6 +3,5 @@ fn main() { let y = &x; let z = &y as *const &i32 as *const usize; let ptr_bytes = unsafe { *z }; // the actual deref is fine, because we read the entire pointer at once - let _ = ptr_bytes / 432; //~ ERROR constant evaluation error - //~^ NOTE tried to access part of a pointer value as raw bytes + let _ = ptr_bytes / 432; //~ ERROR invalid arithmetic on pointers that would leak base addresses } diff --git a/tests/compile-fail/ptr_bitops.rs b/tests/compile-fail/ptr_bitops.rs index ecd47a186efb1..2706b0970d7d5 100644 --- a/tests/compile-fail/ptr_bitops.rs +++ b/tests/compile-fail/ptr_bitops.rs @@ -2,7 +2,6 @@ fn main() { let bytes = [0i8, 1, 2, 3, 4, 5, 6, 7, 8, 9]; let one = bytes.as_ptr().wrapping_offset(1); let three = bytes.as_ptr().wrapping_offset(3); - let res = (one as usize) | (three as usize); //~ ERROR constant evaluation error - //~^ NOTE a raw memory access tried to access part of a pointer value as raw bytes + let res = (one as usize) | (three as usize); //~ ERROR invalid arithmetic on pointers that would leak base addresses println!("{}", res); } From fe9cd1c98d5ca861986eaf2bc0aaf953a375ca5c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 30 Aug 2018 10:50:13 +0200 Subject: [PATCH 0211/3747] strictly enforce pointer validity even for zero-sized accesses --- src/intrinsic.rs | 34 +++++++++++++--------------------- 1 file changed, 13 insertions(+), 21 deletions(-) diff --git a/src/intrinsic.rs b/src/intrinsic.rs index 6847d8e546f36..f562aec323377 100644 --- a/src/intrinsic.rs +++ b/src/intrinsic.rs @@ -179,21 +179,17 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: let elem_layout = self.layout_of(elem_ty)?; let elem_size = elem_layout.size.bytes(); let count = self.read_scalar(args[2])?.to_usize(&self)?; - if count * elem_size != 0 { - // 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.read_scalar(args[0])?.not_undef()?; - let dest = self.read_scalar(args[1])?.not_undef()?; - self.memory.copy( - src, - elem_align, - dest, - elem_align, - Size::from_bytes(count * elem_size), - intrinsic_name.ends_with("_nonoverlapping"), - )?; - } + let elem_align = elem_layout.align; + let src = self.read_scalar(args[0])?.not_undef()?; + let dest = self.read_scalar(args[1])?.not_undef()?; + self.memory.copy( + src, + elem_align, + dest, + elem_align, + Size::from_bytes(count * elem_size), + intrinsic_name.ends_with("_nonoverlapping"), + )?; } "discriminant_value" => { @@ -563,12 +559,8 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: let val_byte = self.read_scalar(args[1])?.to_u8()?; let ptr = self.read_scalar(args[0])?.not_undef()?; let count = self.read_scalar(args[2])?.to_usize(&self)?; - 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_layout.align)?; - self.memory.write_repeat(ptr, val_byte, ty_layout.size * count)?; - } + self.memory.check_align(ptr, ty_layout.align)?; + self.memory.write_repeat(ptr, val_byte, ty_layout.size * count)?; } name => return err!(Unimplemented(format!("unimplemented intrinsic: {}", name))), From 2a318264ea493c62b8ec2fe110654e3177b49939 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 30 Aug 2018 11:04:48 +0200 Subject: [PATCH 0212/3747] also allow comparing pointers with integers so big that they cannot be equal --- src/operator.rs | 29 ++++++++++++++++++++++++----- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/src/operator.rs b/src/operator.rs index 550e7014afa97..576c4a271f96a 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -148,11 +148,30 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: left == right } } - // Comparing ptr and integer -- we only allow compating with NULL - (Scalar::Ptr(_), Scalar::Bits { bits: 0, .. }) | - (Scalar::Bits { bits: 0, .. }, Scalar::Ptr(_)) => false, - // Nothing else is supported - _ => return err!(InvalidPointerMath), + // Comparing ptr and integer -- we allow compating with NULL, and with addresses + // so close to the end of the `usize` range that they cannot overlap with an allocation + // of the given size. + (Scalar::Ptr(ptr), Scalar::Bits { bits, size }) | + (Scalar::Bits { bits, size }, Scalar::Ptr(ptr)) => { + assert_eq!(size as u64, self.pointer_size().bytes()); + if bits == 0 { + // Nothing equals 0 + false + } else { + // Compute the highest address at which this allocation could live + let alloc = self.memory.get(ptr.alloc_id)?; + let max_base_addr = + (1u128 << self.pointer_size().bits()) - alloc.bytes.len() as u128; + let max_addr = max_base_addr + ptr.offset.bytes() as u128; + if bits > max_addr { + // The integer is too big, this cannot possibly be equal + false + } else { + // TODO: We could also take alignment into account + return err!(InvalidPointerMath); + } + } + } }) } From f56841d974056509969180e03c528963b2a76481 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 30 Aug 2018 15:57:17 +0200 Subject: [PATCH 0213/3747] unignore a bunch of tests that actually work --- tests/compile-fail/invalid_bool.rs | 2 +- tests/compile-fail/match_char.rs | 2 +- tests/compile-fail/panic.rs | 1 - tests/run-pass-fullmir/catch.rs | 3 +-- tests/run-pass-fullmir/foreign-fn-linkname.rs | 2 +- tests/run-pass-fullmir/format.rs | 3 +-- tests/run-pass-fullmir/from_utf8.rs | 1 - tests/run-pass-fullmir/hashmap.rs | 1 - tests/run-pass-fullmir/hello.rs | 3 +-- tests/run-pass-fullmir/integer-ops.rs | 3 +-- tests/run-pass-fullmir/issue-3794.rs | 3 +-- tests/run-pass-fullmir/loop-break-value.rs | 2 -- .../send-is-not-static-par-for.rs | 2 -- tests/run-pass-fullmir/u128.rs | 2 -- tests/run-pass-fullmir/unsized-tuple-impls.rs | 2 -- tests/run-pass/heap.rs | 1 - tests/run-pass/issue-15080.rs | 2 -- tests/run-pass/issue-17877.rs | 3 ++- tests/run-pass/move-arg-2-unique.rs | 2 -- tests/run-pass/regions-mock-trans.rs | 2 +- tests/run-pass/thread-local.rs | 2 +- tests/run-pass/vecs.rs | 2 -- 22 files changed, 12 insertions(+), 34 deletions(-) rename tests/{run-pass => run-pass-fullmir}/send-is-not-static-par-for.rs (98%) diff --git a/tests/compile-fail/invalid_bool.rs b/tests/compile-fail/invalid_bool.rs index bd08c0ce4eb9d..49328ef5d74e2 100644 --- a/tests/compile-fail/invalid_bool.rs +++ b/tests/compile-fail/invalid_bool.rs @@ -1,4 +1,4 @@ -//ignore-test FIXME (do some basic validation of invariants for all values in flight) +//ignore-test FIXME: do some basic validation of invariants for all values in flight //This does currently not get caught becuase it compiles to SwitchInt, which //has no knowledge about data invariants. diff --git a/tests/compile-fail/match_char.rs b/tests/compile-fail/match_char.rs index fd4431992d9b6..e7fee1e3e3611 100644 --- a/tests/compile-fail/match_char.rs +++ b/tests/compile-fail/match_char.rs @@ -1,4 +1,4 @@ -// ignore-test FIXME: we are not checking these things on match any more? +//ignore-test FIXME: do some basic validation of invariants for all values in flight //This does currently not get caught becuase it compiles to SwitchInt, which //has no knowledge about data invariants. diff --git a/tests/compile-fail/panic.rs b/tests/compile-fail/panic.rs index 1f9e8f6e1d0b0..80149eeffaa64 100644 --- a/tests/compile-fail/panic.rs +++ b/tests/compile-fail/panic.rs @@ -1,4 +1,3 @@ -//ignore-windows // FIXME: Something in panic handling fails validation with full-MIR // compile-flags: -Zmir-emit-validate=0 //error-pattern: the evaluated program panicked diff --git a/tests/run-pass-fullmir/catch.rs b/tests/run-pass-fullmir/catch.rs index 60c86c99e9aaf..960297daa7ef5 100644 --- a/tests/run-pass-fullmir/catch.rs +++ b/tests/run-pass-fullmir/catch.rs @@ -1,5 +1,4 @@ -//ignore-msvc -//ignore-macos +//ignore-msvc: Stdout not implemented on Windows use std::panic::{catch_unwind, AssertUnwindSafe}; fn main() { diff --git a/tests/run-pass-fullmir/foreign-fn-linkname.rs b/tests/run-pass-fullmir/foreign-fn-linkname.rs index 20cb713590c95..789e3eccceb7c 100644 --- a/tests/run-pass-fullmir/foreign-fn-linkname.rs +++ b/tests/run-pass-fullmir/foreign-fn-linkname.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//ignore-msvc +//ignore-windows: Uses POSIX APIs #![feature(libc)] extern crate libc; diff --git a/tests/run-pass-fullmir/format.rs b/tests/run-pass-fullmir/format.rs index 59af803b59f0f..b1b05abd29655 100644 --- a/tests/run-pass-fullmir/format.rs +++ b/tests/run-pass-fullmir/format.rs @@ -1,5 +1,4 @@ -//ignore-msvc -//ignore-macos +//ignore-msvc: Stdout not implemented on Windows fn main() { println!("Hello {}", 13); } diff --git a/tests/run-pass-fullmir/from_utf8.rs b/tests/run-pass-fullmir/from_utf8.rs index c5d4abcfdaeff..69e6c521af6ef 100644 --- a/tests/run-pass-fullmir/from_utf8.rs +++ b/tests/run-pass-fullmir/from_utf8.rs @@ -1,4 +1,3 @@ -//ignore-msvc fn main() { let _ = ::std::str::from_utf8(b"a"); } diff --git a/tests/run-pass-fullmir/hashmap.rs b/tests/run-pass-fullmir/hashmap.rs index 99f05e25985ee..f4a358174f555 100644 --- a/tests/run-pass-fullmir/hashmap.rs +++ b/tests/run-pass-fullmir/hashmap.rs @@ -1,4 +1,3 @@ -//ignore-msvc use std::collections::{self, HashMap}; use std::hash::BuildHasherDefault; diff --git a/tests/run-pass-fullmir/hello.rs b/tests/run-pass-fullmir/hello.rs index a0d73733bdfc8..c92c1567f5ae2 100644 --- a/tests/run-pass-fullmir/hello.rs +++ b/tests/run-pass-fullmir/hello.rs @@ -1,5 +1,4 @@ -//ignore-msvc -//ignore-macos +//ignore-msvc: Stdout not implemented on Windows fn main() { println!("Hello, world!"); } diff --git a/tests/run-pass-fullmir/integer-ops.rs b/tests/run-pass-fullmir/integer-ops.rs index 97c694fd5674e..7a2335c829efe 100644 --- a/tests/run-pass-fullmir/integer-ops.rs +++ b/tests/run-pass-fullmir/integer-ops.rs @@ -11,7 +11,6 @@ // FIXME: remove -Zmir-opt-level once https://github.com/rust-lang/rust/issues/43359 is fixed // compile-flags: -Zmir-opt-level=0 -//ignore-msvc use std::i32; pub fn main() { @@ -168,7 +167,7 @@ pub fn main() { assert_eq!(0x10i32.overflowing_shr(4), (0x1, false)); assert_eq!(0x10i32.overflowing_shr(36), (0x1, true)); - + assert_eq!(10i8.overflowing_abs(), (10,false)); assert_eq!((-10i8).overflowing_abs(), (10,false)); assert_eq!((-128i8).overflowing_abs(), (-128,true)); diff --git a/tests/run-pass-fullmir/issue-3794.rs b/tests/run-pass-fullmir/issue-3794.rs index 8b653f0f95fc9..32b4d27f11f5a 100644 --- a/tests/run-pass-fullmir/issue-3794.rs +++ b/tests/run-pass-fullmir/issue-3794.rs @@ -8,8 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//ignore-msvc -//ignore-macos +//ignore-msvc: Stdout not implemented on Windows #![feature(box_syntax)] trait T { diff --git a/tests/run-pass-fullmir/loop-break-value.rs b/tests/run-pass-fullmir/loop-break-value.rs index 8a0ea113c5d62..8631909a2a966 100644 --- a/tests/run-pass-fullmir/loop-break-value.rs +++ b/tests/run-pass-fullmir/loop-break-value.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//ignore-msvc - #![feature(never_type)] #![allow(unreachable_code)] diff --git a/tests/run-pass/send-is-not-static-par-for.rs b/tests/run-pass-fullmir/send-is-not-static-par-for.rs similarity index 98% rename from tests/run-pass/send-is-not-static-par-for.rs rename to tests/run-pass-fullmir/send-is-not-static-par-for.rs index 4ac1b5436f522..1b913aed4c89e 100644 --- a/tests/run-pass/send-is-not-static-par-for.rs +++ b/tests/run-pass-fullmir/send-is-not-static-par-for.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//ignore-windows - use std::sync::Mutex; fn par_for(iter: I, f: F) diff --git a/tests/run-pass-fullmir/u128.rs b/tests/run-pass-fullmir/u128.rs index d7764bf6201ae..ca33bd5f9e3d8 100644 --- a/tests/run-pass-fullmir/u128.rs +++ b/tests/run-pass-fullmir/u128.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//ignore-msvc - fn b(t: T) -> T { t } fn main() { diff --git a/tests/run-pass-fullmir/unsized-tuple-impls.rs b/tests/run-pass-fullmir/unsized-tuple-impls.rs index 828e5c26927ec..ccb6883e8733a 100644 --- a/tests/run-pass-fullmir/unsized-tuple-impls.rs +++ b/tests/run-pass-fullmir/unsized-tuple-impls.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//ignore-msvc - #![feature(unsized_tuple_coercion)] use std::mem; diff --git a/tests/run-pass/heap.rs b/tests/run-pass/heap.rs index 917d51d0e4b65..b533f91646988 100644 --- a/tests/run-pass/heap.rs +++ b/tests/run-pass/heap.rs @@ -1,4 +1,3 @@ -//ignore-msvc #![feature(box_syntax)] fn make_box() -> Box<(i16, i16)> { diff --git a/tests/run-pass/issue-15080.rs b/tests/run-pass/issue-15080.rs index 4a84f2bc5d62d..b5b1edcfddd01 100644 --- a/tests/run-pass/issue-15080.rs +++ b/tests/run-pass/issue-15080.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//ignore-msvc - #![feature(slice_patterns)] fn main() { diff --git a/tests/run-pass/issue-17877.rs b/tests/run-pass/issue-17877.rs index b4b74b9905fbb..762bacbe0e6f5 100644 --- a/tests/run-pass/issue-17877.rs +++ b/tests/run-pass/issue-17877.rs @@ -8,7 +8,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//ignore-msvc +//ignore-windows: Causes a stack overflow?!? Likely a rustc bug: https://github.com/rust-lang/rust/issues/53820 +//Once that bug is fixed, increase the size to 16*1024 and enable on all platforms. #![feature(slice_patterns)] diff --git a/tests/run-pass/move-arg-2-unique.rs b/tests/run-pass/move-arg-2-unique.rs index f3c656623765f..d44c83763b7c4 100644 --- a/tests/run-pass/move-arg-2-unique.rs +++ b/tests/run-pass/move-arg-2-unique.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//ignore-msvc - #![allow(unused_features, unused_variables)] #![feature(box_syntax)] diff --git a/tests/run-pass/regions-mock-trans.rs b/tests/run-pass/regions-mock-trans.rs index 74e94ddbf84f6..039175e9acd60 100644 --- a/tests/run-pass/regions-mock-trans.rs +++ b/tests/run-pass/regions-mock-trans.rs @@ -11,7 +11,7 @@ // FIXME: We handle uninitialized storage here, which currently makes validation fail. // compile-flags: -Zmir-emit-validate=0 -//ignore-msvc +//ignore-windows: Uses POSIX APIs #![feature(libc)] diff --git a/tests/run-pass/thread-local.rs b/tests/run-pass/thread-local.rs index db00e42d99ac8..8c20e89ab52db 100644 --- a/tests/run-pass/thread-local.rs +++ b/tests/run-pass/thread-local.rs @@ -1,4 +1,4 @@ -//ignore-windows +//ignore-windows: Uses POSIX APIs #![feature(libc)] extern crate libc; diff --git a/tests/run-pass/vecs.rs b/tests/run-pass/vecs.rs index 9a8912a6b9889..776791bbc9b9e 100644 --- a/tests/run-pass/vecs.rs +++ b/tests/run-pass/vecs.rs @@ -1,5 +1,3 @@ -//ignore-msvc - fn make_vec() -> Vec { let mut v = Vec::with_capacity(4); v.push(1); From 74c6a1aa49cadfc463f275a6b8d21ea5dd8d561b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 1 Sep 2018 10:33:53 +0200 Subject: [PATCH 0214/3747] bump toolchain --- rust-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-toolchain b/rust-toolchain index f54012d5e14b9..448c24468e5c0 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1 +1 @@ -nightly-2018-08-30 +nightly-2018-09-01 From d3928f6356de808b1df402cc66e9e6d36a9dce8c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 1 Sep 2018 11:26:54 +0200 Subject: [PATCH 0215/3747] more permissive pointer comparison logic --- src/operator.rs | 25 +++++++++---------------- 1 file changed, 9 insertions(+), 16 deletions(-) diff --git a/src/operator.rs b/src/operator.rs index 576c4a271f96a..4f697dbd5b748 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -148,28 +148,21 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: left == right } } - // Comparing ptr and integer -- we allow compating with NULL, and with addresses - // so close to the end of the `usize` range that they cannot overlap with an allocation - // of the given size. + // Comparing ptr and integer (Scalar::Ptr(ptr), Scalar::Bits { bits, size }) | (Scalar::Bits { bits, size }, Scalar::Ptr(ptr)) => { assert_eq!(size as u64, self.pointer_size().bytes()); + if bits == 0 { - // Nothing equals 0 + // Nothing equals 0, not even dangling pointers. Ideally we would + // require them to be in-bounds of their (possilby dead) allocation, + // but with the allocation gonew e cannot check that. false } else { - // Compute the highest address at which this allocation could live - let alloc = self.memory.get(ptr.alloc_id)?; - let max_base_addr = - (1u128 << self.pointer_size().bits()) - alloc.bytes.len() as u128; - let max_addr = max_base_addr + ptr.offset.bytes() as u128; - if bits > max_addr { - // The integer is too big, this cannot possibly be equal - false - } else { - // TODO: We could also take alignment into account - return err!(InvalidPointerMath); - } + // Live pointers cannot equal an integer, but again do not + // allow comparing dead pointers. + self.memory.check_bounds(ptr, false)?; + false } } }) From 90d7cb24934e26bec907d221e1709ae8b8473601 Mon Sep 17 00:00:00 2001 From: thedarkula Date: Thu, 30 Aug 2018 21:06:53 +0100 Subject: [PATCH 0216/3747] Removed transmute from intrinsic.rs --- src/intrinsic.rs | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/intrinsic.rs b/src/intrinsic.rs index 6847d8e546f36..2c5b204b060a0 100644 --- a/src/intrinsic.rs +++ b/src/intrinsic.rs @@ -460,14 +460,6 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: self.write_value(value, dest)?; } - "transmute" => { - // Go through an allocation, to make sure the completely different layouts - // do not pose a problem. (When the user transmutes through a union, - // there will not be a layout mismatch.) - let dest = self.force_allocation(dest)?; - self.copy_op(args[0], dest.into())?; - } - "unchecked_shl" => { let bits = dest.layout.size.bytes() as u128 * 8; let l = self.read_value(args[0])?; From 055c63ab0d299c47464bb37ee1f766e3e95a50b2 Mon Sep 17 00:00:00 2001 From: Tim Date: Thu, 6 Sep 2018 16:07:13 +0200 Subject: [PATCH 0217/3747] Remove unchecked_shr/shl from intrinsics --- src/intrinsic.rs | 36 ------------------------------------ 1 file changed, 36 deletions(-) diff --git a/src/intrinsic.rs b/src/intrinsic.rs index 056caf3cd9e1c..a57307ed12e78 100644 --- a/src/intrinsic.rs +++ b/src/intrinsic.rs @@ -443,42 +443,6 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: self.write_value(value, dest)?; } - "unchecked_shl" => { - let bits = dest.layout.size.bytes() as u128 * 8; - let l = self.read_value(args[0])?; - let r = self.read_value(args[1])?; - let rval = r.to_scalar()?.to_bytes()?; - if rval >= bits { - return err!(Intrinsic( - format!("Overflowing shift by {} in unchecked_shl", rval), - )); - } - self.binop_ignore_overflow( - mir::BinOp::Shl, - l, - r, - dest, - )?; - } - - "unchecked_shr" => { - let bits = dest.layout.size.bytes() as u128 * 8; - let l = self.read_value(args[0])?; - let r = self.read_value(args[1])?; - let rval = r.to_scalar()?.to_bytes()?; - if rval >= bits { - return err!(Intrinsic( - format!("Overflowing shift by {} in unchecked_shr", rval), - )); - } - self.binop_ignore_overflow( - mir::BinOp::Shr, - l, - r, - dest, - )?; - } - "unchecked_div" => { let l = self.read_value(args[0])?; let r = self.read_value(args[1])?; From 72918c1a97458fb30163677af8dfb4fb573cdeb6 Mon Sep 17 00:00:00 2001 From: Tim Date: Thu, 6 Sep 2018 16:49:08 +0200 Subject: [PATCH 0218/3747] Remove (overflowing_)add/mul/sub(_with_overflow) --- src/intrinsic.rs | 66 ------------------------------------------------ 1 file changed, 66 deletions(-) diff --git a/src/intrinsic.rs b/src/intrinsic.rs index a57307ed12e78..a8cb58fdddfe4 100644 --- a/src/intrinsic.rs +++ b/src/intrinsic.rs @@ -33,39 +33,6 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: let intrinsic_name = &self.tcx.item_name(instance.def_id()).as_str()[..]; match intrinsic_name { - "add_with_overflow" => { - let l = self.read_value(args[0])?; - let r = self.read_value(args[1])?; - self.binop_with_overflow( - mir::BinOp::Add, - l, - r, - dest, - )? - } - - "sub_with_overflow" => { - let l = self.read_value(args[0])?; - let r = self.read_value(args[1])?; - self.binop_with_overflow( - mir::BinOp::Sub, - l, - r, - dest, - )? - } - - "mul_with_overflow" => { - let l = self.read_value(args[0])?; - let r = self.read_value(args[1])?; - self.binop_with_overflow( - mir::BinOp::Mul, - l, - r, - dest, - )? - } - "arith_offset" => { let offset = self.read_scalar(args[1])?.to_isize(&self)?; let ptr = self.read_scalar(args[0])?.not_undef()?; @@ -326,39 +293,6 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: self.write_scalar(result_ptr, dest)?; } - "overflowing_sub" => { - let l = self.read_value(args[0])?; - let r = self.read_value(args[1])?; - self.binop_ignore_overflow( - mir::BinOp::Sub, - l, - r, - dest, - )?; - } - - "overflowing_mul" => { - let l = self.read_value(args[0])?; - let r = self.read_value(args[1])?; - self.binop_ignore_overflow( - mir::BinOp::Mul, - r, - l, - dest, - )?; - } - - "overflowing_add" => { - let l = self.read_value(args[0])?; - let r = self.read_value(args[1])?; - self.binop_ignore_overflow( - mir::BinOp::Add, - r, - l, - dest, - )?; - } - "powf32" => { let f = self.read_scalar(args[0])?.to_f32()?; let f2 = self.read_scalar(args[1])?.to_f32()?; From d889da43f8f55d2ca1a795915d2375342e2a520c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 9 Sep 2018 10:57:39 +0200 Subject: [PATCH 0219/3747] move MemoryData to memory.rs; remove all the Hashing stuff --- src/lib.rs | 74 +++------------------------------------------------ src/memory.rs | 42 ++++++++++++++++++++++++++++- 2 files changed, 45 insertions(+), 71 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index b8d3c18c01cba..6758cbeb95394 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -18,14 +18,11 @@ use rustc::ty::layout::{TyLayout, LayoutOf, Size}; use rustc::hir::def_id::DefId; use rustc::mir; -use rustc_data_structures::fx::FxHasher; - use syntax::ast::Mutability; use syntax::attr; use std::marker::PhantomData; -use std::collections::{HashMap, BTreeMap}; -use std::hash::{Hash, Hasher}; +use std::collections::HashMap; pub use rustc::mir::interpret::*; pub use rustc_mir::interpret::*; @@ -43,7 +40,7 @@ use fn_call::EvalContextExt as MissingFnsEvalContextExt; use operator::EvalContextExt as OperatorEvalContextExt; use intrinsic::EvalContextExt as IntrinsicEvalContextExt; use tls::EvalContextExt as TlsEvalContextExt; -use memory::MemoryKind as MiriMemoryKind; +use memory::{MemoryKind as MiriMemoryKind, TlsKey, TlsEntry, MemoryData}; use locks::LockInfo; use range_map::RangeMap; use helpers::FalibleScalarExt; @@ -214,75 +211,12 @@ pub struct Evaluator<'tcx> { _dummy : PhantomData<&'tcx ()>, } -impl<'tcx> Hash for Evaluator<'tcx> { - fn hash(&self, state: &mut H) { - let Evaluator { - env_vars, - _dummy: _, - } = self; - - env_vars.iter() - .map(|(env, ptr)| { - let mut h = FxHasher::default(); - env.hash(&mut h); - ptr.hash(&mut h); - h.finish() - }) - .fold(0u64, |acc, hash| acc.wrapping_add(hash)) - .hash(state); - } -} - -pub type TlsKey = u128; - -#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] -pub struct TlsEntry<'tcx> { - data: Scalar, // Will eventually become a map from thread IDs to `Scalar`s, if we ever support more than one thread. - dtor: Option>, -} - -#[derive(Clone, PartialEq, Eq)] -pub struct MemoryData<'tcx> { - /// The Key to use for the next thread-local allocation. - next_thread_local: TlsKey, - - /// pthreads-style thread-local storage. - thread_local: BTreeMap>, - - /// Memory regions that are locked by some function - /// - /// Only mutable (static mut, heap, stack) allocations have an entry in this map. - /// The entry is created when allocating the memory and deleted after deallocation. - locks: HashMap>>, -} - -impl<'tcx> MemoryData<'tcx> { - fn new() -> Self { - MemoryData { - next_thread_local: 1, // start with 1 as we must not use 0 on Windows - thread_local: BTreeMap::new(), - locks: HashMap::new(), - } - } -} - -impl<'tcx> Hash for MemoryData<'tcx> { - fn hash(&self, state: &mut H) { - let MemoryData { - next_thread_local: _, - thread_local, - locks: _, - } = self; - - thread_local.hash(state); - } -} - impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { - type MemoryData = MemoryData<'tcx>; + type MemoryData = memory::MemoryData<'tcx>; type MemoryKinds = memory::MemoryKind; const MUT_STATIC_KIND: Option = Some(memory::MemoryKind::MutStatic); + const DETECT_LOOPS: bool = false; /// Returns Ok() when the function was handled, fail otherwise fn find_fn<'a>( diff --git a/src/memory.rs b/src/memory.rs index d4575d677fa14..9f8118a223bc2 100644 --- a/src/memory.rs +++ b/src/memory.rs @@ -1,4 +1,44 @@ -#[derive(Debug, PartialEq, Copy, Clone, Hash, Eq)] +use std::collections::{HashMap, BTreeMap}; + +use rustc::ty; + +use super::{AllocId, Scalar, LockInfo, RangeMap}; + +pub type TlsKey = u128; + +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub struct TlsEntry<'tcx> { + pub(crate) data: Scalar, // Will eventually become a map from thread IDs to `Scalar`s, if we ever support more than one thread. + pub(crate) dtor: Option>, +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct MemoryData<'tcx> { + /// The Key to use for the next thread-local allocation. + pub(crate) next_thread_local: TlsKey, + + /// pthreads-style thread-local storage. + pub(crate) thread_local: BTreeMap>, + + /// Memory regions that are locked by some function + /// + /// Only mutable (static mut, heap, stack) allocations have an entry in this map. + /// The entry is created when allocating the memory and deleted after deallocation. + pub(crate) locks: HashMap>>, +} + +impl<'tcx> MemoryData<'tcx> { + pub(crate) fn new() -> Self { + MemoryData { + next_thread_local: 1, // start with 1 as we must not use 0 on Windows + thread_local: BTreeMap::new(), + locks: HashMap::new(), + } + } +} + + +#[derive(Debug, Copy, Clone, PartialEq, Eq)] pub enum MemoryKind { /// `__rust_alloc` memory Rust, From b488b51b66c8740f8e8e3e68d225e7ef14e8cf55 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 15 Sep 2018 10:31:20 +0200 Subject: [PATCH 0220/3747] bump Rust --- rust-toolchain | 2 +- src/lib.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/rust-toolchain b/rust-toolchain index 448c24468e5c0..125ee2d988549 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1 +1 @@ -nightly-2018-09-01 +nightly-2018-09-15 diff --git a/src/lib.rs b/src/lib.rs index 6758cbeb95394..8bf66999c3dec 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -60,7 +60,7 @@ pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( let main_instance = ty::Instance::mono(ecx.tcx.tcx, main_id); let main_mir = ecx.load_mir(main_instance.def)?; - if !main_mir.return_ty().is_nil() || main_mir.arg_count != 0 { + if !main_mir.return_ty().is_unit() || main_mir.arg_count != 0 { return err!(Unimplemented( "miri does not support main functions without `fn()` type signatures" .to_owned(), From f925e5dafdbd5aeb14cf6626e059456b23b8f613 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 16 Sep 2018 15:06:05 +0200 Subject: [PATCH 0221/3747] cargo miri: show version number --- Cargo.toml | 3 +++ build.rs | 16 ++++++++++++++++ src/bin/cargo-miri.rs | 3 ++- 3 files changed, 21 insertions(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 3f7aabe03ce27..d690f87b536c6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -31,6 +31,9 @@ cargo_metadata = { version = "0.6", optional = true } env_logger = "0.5" log = "0.4" +[build-dependencies] +vergen = "2" + [features] cargo_miri = ["cargo_metadata"] diff --git a/build.rs b/build.rs index 2f74f7f4f6162..73eb68359a821 100644 --- a/build.rs +++ b/build.rs @@ -1,3 +1,5 @@ +extern crate vergen; + use std::env; fn main() { @@ -5,4 +7,18 @@ fn main() { println!("cargo:rustc-env=PROFILE={}", env::var("PROFILE").unwrap()); // Don't rebuild miri even if nothing changed println!("cargo:rerun-if-changed=build.rs"); + // vergen + vergen().expect("Unable to generate vergen constants!"); +} + +fn vergen() -> vergen::Result<()> { + use vergen::{ConstantsFlags, Vergen}; + + let vergen = Vergen::new(ConstantsFlags::all())?; + + for (k, v) in vergen.build_info() { + println!("cargo:rustc-env={}={}", k.name(), v); + } + + Ok(()) } diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 010f25e8152dc..95ce9cc7ecb5f 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -30,7 +30,8 @@ fn show_help() { } fn show_version() { - println!("{}", env!("CARGO_PKG_VERSION")); + println!("miri {} ({} {})", + env!("CARGO_PKG_VERSION"), env!("VERGEN_SHA_SHORT"), env!("VERGEN_COMMIT_DATE")); } fn main() { From 95eb77c18e8532d490efbedff6424d369b7e83df Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 16 Sep 2018 16:47:37 +0200 Subject: [PATCH 0222/3747] add some compile-fail tests --- tests/compile-fail/copy_null.rs | 18 ++++++++++++++++++ tests/compile-fail/copy_unaligned.rs | 18 ++++++++++++++++++ 2 files changed, 36 insertions(+) create mode 100644 tests/compile-fail/copy_null.rs create mode 100644 tests/compile-fail/copy_unaligned.rs diff --git a/tests/compile-fail/copy_null.rs b/tests/compile-fail/copy_null.rs new file mode 100644 index 0000000000000..e46e327e6111e --- /dev/null +++ b/tests/compile-fail/copy_null.rs @@ -0,0 +1,18 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//error-pattern: invalid use of NULL pointer + +fn main() { + let mut data = [0u16; 4]; + let ptr = &mut data[0] as *mut u16; + // Even copying 0 elements from NULL should error + unsafe { ptr.copy_from(std::ptr::null(), 0); } +} diff --git a/tests/compile-fail/copy_unaligned.rs b/tests/compile-fail/copy_unaligned.rs new file mode 100644 index 0000000000000..0f04dc68db90c --- /dev/null +++ b/tests/compile-fail/copy_unaligned.rs @@ -0,0 +1,18 @@ +// Copyright 2015 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//error-pattern: tried to access memory with alignment 1, but alignment 2 is required + +fn main() { + let mut data = [0u16; 8]; + let ptr = (&mut data[0] as *mut u16 as *mut u8).wrapping_add(1) as *mut u16; + // Even copying 0 elements to something unaligned should error + unsafe { ptr.copy_from(&data[5], 0); } +} From c096d3405389089bab4379161a1546094b1db479 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 17 Sep 2018 08:40:17 +0200 Subject: [PATCH 0223/3747] bump toolchain --- rust-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-toolchain b/rust-toolchain index 125ee2d988549..60c47a9305764 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1 +1 @@ -nightly-2018-09-15 +nightly-2018-09-17 From 130d803b3243a92f5c2d9230935cba7fa88e263e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 17 Sep 2018 09:18:57 +0200 Subject: [PATCH 0224/3747] fix test for rustup --- tests/compile-fail/out_of_bounds_read2.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/compile-fail/out_of_bounds_read2.rs b/tests/compile-fail/out_of_bounds_read2.rs index 811ba7d4b26cf..e8bcf4558401c 100644 --- a/tests/compile-fail/out_of_bounds_read2.rs +++ b/tests/compile-fail/out_of_bounds_read2.rs @@ -1,6 +1,6 @@ fn main() { let v: Vec = vec![1, 2]; let x = unsafe { *v.as_ptr().wrapping_offset(5) }; //~ ERROR constant evaluation error - //~^ NOTE memory access at offset 6, outside bounds of allocation + //~^ NOTE outside bounds of allocation panic!("this should never print: {}", x); } From cd138bcd0b30b7af40fe0c13ce4f71f49cb59d3c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 15 Sep 2018 16:35:37 +0200 Subject: [PATCH 0225/3747] test more operations on dangling ZST pointers --- .../maybe_null_pointer_deref_zst.rs | 5 +++++ .../maybe_null_pointer_write_zst.rs | 8 ++++++++ tests/compile-fail/null_pointer_deref_zst.rs | 4 ++++ tests/compile-fail/null_pointer_write.rs | 3 +++ tests/compile-fail/null_pointer_write_zst.rs | 6 ++++++ tests/run-pass/cast-rfc0401-vtable-kinds.rs | 4 ---- tests/run-pass/const-vec-of-fns.rs | 2 -- tests/run-pass/issue-20575.rs | 2 -- tests/run-pass/pointers.rs | 6 +++++- .../regions-lifetime-nonfree-late-bound.rs | 2 -- tests/run-pass/sendable-class.rs | 2 -- tests/run-pass/zst.rs | 19 +++++++++++++++++-- tests/run-pass/zst2.rs | 12 ------------ 13 files changed, 48 insertions(+), 27 deletions(-) create mode 100644 tests/compile-fail/maybe_null_pointer_deref_zst.rs create mode 100644 tests/compile-fail/maybe_null_pointer_write_zst.rs create mode 100644 tests/compile-fail/null_pointer_deref_zst.rs create mode 100644 tests/compile-fail/null_pointer_write.rs create mode 100644 tests/compile-fail/null_pointer_write_zst.rs delete mode 100644 tests/run-pass/zst2.rs diff --git a/tests/compile-fail/maybe_null_pointer_deref_zst.rs b/tests/compile-fail/maybe_null_pointer_deref_zst.rs new file mode 100644 index 0000000000000..d9f5ad4c696e1 --- /dev/null +++ b/tests/compile-fail/maybe_null_pointer_deref_zst.rs @@ -0,0 +1,5 @@ +fn main() { + // This pointer *could* be NULL so we cannot load from it, not even at ZST + let ptr = (&0u8 as *const u8).wrapping_sub(0x800) as *const (); + let _x: () = unsafe { *ptr }; //~ ERROR outside bounds +} diff --git a/tests/compile-fail/maybe_null_pointer_write_zst.rs b/tests/compile-fail/maybe_null_pointer_write_zst.rs new file mode 100644 index 0000000000000..ef46a469c3ad1 --- /dev/null +++ b/tests/compile-fail/maybe_null_pointer_write_zst.rs @@ -0,0 +1,8 @@ +fn main() { + // This pointer *could* be NULL so we cannot load from it, not even at ZST. + // Not using the () type here, as writes of that type do not even have MIR generated. + // Also not assigning directly as that's array initialization, not assignment. + let zst_val = [1u8; 0]; + let ptr = (&0u8 as *const u8).wrapping_sub(0x800) as *mut [u8; 0]; + unsafe { *ptr = zst_val; } //~ ERROR outside bounds +} diff --git a/tests/compile-fail/null_pointer_deref_zst.rs b/tests/compile-fail/null_pointer_deref_zst.rs new file mode 100644 index 0000000000000..a8b23368616ea --- /dev/null +++ b/tests/compile-fail/null_pointer_deref_zst.rs @@ -0,0 +1,4 @@ +fn main() { + let x: () = unsafe { *std::ptr::null() }; //~ ERROR constant evaluation error: invalid use of NULL pointer + panic!("this should never print: {:?}", x); +} diff --git a/tests/compile-fail/null_pointer_write.rs b/tests/compile-fail/null_pointer_write.rs new file mode 100644 index 0000000000000..affb040bdedfa --- /dev/null +++ b/tests/compile-fail/null_pointer_write.rs @@ -0,0 +1,3 @@ +fn main() { + unsafe { *std::ptr::null_mut() = 0i32 }; //~ ERROR constant evaluation error: invalid use of NULL pointer +} diff --git a/tests/compile-fail/null_pointer_write_zst.rs b/tests/compile-fail/null_pointer_write_zst.rs new file mode 100644 index 0000000000000..433c69dbb032b --- /dev/null +++ b/tests/compile-fail/null_pointer_write_zst.rs @@ -0,0 +1,6 @@ +fn main() { + // Not using the () type here, as writes of that type do not even have MIR generated. + // Also not assigning directly as that's array initialization, not assignment. + let zst_val = [1u8; 0]; + unsafe { *std::ptr::null_mut() = zst_val }; //~ ERROR constant evaluation error: invalid use of NULL pointer +} diff --git a/tests/run-pass/cast-rfc0401-vtable-kinds.rs b/tests/run-pass/cast-rfc0401-vtable-kinds.rs index afbd4760a3c9b..ebae26996b7b1 100644 --- a/tests/run-pass/cast-rfc0401-vtable-kinds.rs +++ b/tests/run-pass/cast-rfc0401-vtable-kinds.rs @@ -8,10 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. - -// FIXME: remove the next line when https://github.com/rust-lang/rust/issues/43358 is resolved -// compile-flags: -Zmir-opt-level=0 - // Check that you can cast between different pointers to trait objects // whose vtable have the same kind (both lengths, or both trait pointers). diff --git a/tests/run-pass/const-vec-of-fns.rs b/tests/run-pass/const-vec-of-fns.rs index 0338a766e2627..e100ad5f4692e 100644 --- a/tests/run-pass/const-vec-of-fns.rs +++ b/tests/run-pass/const-vec-of-fns.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// pretty-expanded FIXME #23616 - /*! * Try to double-check that static fns have the right size (with or * without dummy env ptr, as appropriate) by iterating a size-2 array. diff --git a/tests/run-pass/issue-20575.rs b/tests/run-pass/issue-20575.rs index 7db7e3b28e8e6..137d84c256bef 100644 --- a/tests/run-pass/issue-20575.rs +++ b/tests/run-pass/issue-20575.rs @@ -10,8 +10,6 @@ // Test that overloaded calls work with zero arity closures -// pretty-expanded FIXME #23616 - fn main() { let functions: [Box Option<()>>; 1] = [Box::new(|| None)]; diff --git a/tests/run-pass/pointers.rs b/tests/run-pass/pointers.rs index 936ec73bcb8c0..d8f030de07231 100644 --- a/tests/run-pass/pointers.rs +++ b/tests/run-pass/pointers.rs @@ -55,7 +55,11 @@ fn main() { assert_eq!(basic_ref_mut_var(), 3); assert_eq!(tuple_ref_mut(), (10, 22)); assert_eq!(match_ref_mut(), 42); - // FIXME: improve this test... how? + + // Compare even dangling pointers with NULL, and with others in the same allocation. assert!(dangling_pointer() != std::ptr::null()); assert!(match dangling_pointer() as usize { 0 => false, _ => true }); + let dangling = dangling_pointer(); + assert!(dangling == dangling); + assert!(dangling.wrapping_add(1) != dangling); } diff --git a/tests/run-pass/regions-lifetime-nonfree-late-bound.rs b/tests/run-pass/regions-lifetime-nonfree-late-bound.rs index 1aef95d8a3f30..96f1217a254ed 100644 --- a/tests/run-pass/regions-lifetime-nonfree-late-bound.rs +++ b/tests/run-pass/regions-lifetime-nonfree-late-bound.rs @@ -22,8 +22,6 @@ // doing region-folding, when really all clients of the region-folding // case only want to see FREE lifetime variables, not bound ones. -// pretty-expanded FIXME #23616 - #![allow(unused_features)] #![feature(box_syntax)] diff --git a/tests/run-pass/sendable-class.rs b/tests/run-pass/sendable-class.rs index b3e07d00f010f..66f0c84e23c1a 100644 --- a/tests/run-pass/sendable-class.rs +++ b/tests/run-pass/sendable-class.rs @@ -10,8 +10,6 @@ // Test that a class with only sendable fields can be sent -// pretty-expanded FIXME #23616 - use std::sync::mpsc::channel; #[allow(dead_code)] diff --git a/tests/run-pass/zst.rs b/tests/run-pass/zst.rs index c1c88875c5c80..c3bae4062fc29 100644 --- a/tests/run-pass/zst.rs +++ b/tests/run-pass/zst.rs @@ -11,8 +11,23 @@ fn use_zst() -> A { } fn main() { + // Not using the () type here, as writes of that type do not even have MIR generated. + // Also not assigning directly as that's array initialization, not assignment. + let zst_val = [1u8; 0]; + assert_eq!(zst_ret(), A); assert_eq!(use_zst(), A); - let x = 42 as *mut (); - unsafe { *x = (); } + let x = 42 as *mut [u8; 0]; + // reading and writing is okay + unsafe { *x = zst_val; } + unsafe { let _y = *x; } + + // We should even be able to use "true" pointers for ZST when the allocation has been + // removed already. The box is for a non-ZST to make sure there actually is an allocation. + let mut x_box = Box::new(((), 1u8)); + let x = &mut x_box.0 as *mut _ as *mut [u8; 0]; + drop(x_box); + // reading and writing is okay + unsafe { *x = zst_val; } + unsafe { let _y = *x; } } diff --git a/tests/run-pass/zst2.rs b/tests/run-pass/zst2.rs deleted file mode 100644 index c2d7b88ea0757..0000000000000 --- a/tests/run-pass/zst2.rs +++ /dev/null @@ -1,12 +0,0 @@ -#![allow(dead_code)] - -#[derive(Debug)] -struct A; - -fn main() { - // can't use assert_eq, b/c that will try to print the pointer addresses with full MIR enabled - - // FIXME: Test disabled for now, see . - //assert!(&A as *const A as *const () == &() as *const _); - //assert!(&A as *const A == &A as *const A); -} From 18d7394071713092fd6d491fb7bcc3d98bb9a621 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 15 Sep 2018 17:12:48 +0200 Subject: [PATCH 0226/3747] more compile-fail ptr equality tests, to rule out any non-determinism; and fix ptr equality to fail all of them. At least these are the cases I can think of right now. --- src/memory.rs | 2 +- src/operator.rs | 50 +++++++++++++++---- tests/compile-fail/ptr_eq_dangling.rs | 10 ++++ tests/compile-fail/ptr_eq_integer.rs | 8 +++ tests/compile-fail/ptr_eq_out_of_bounds.rs | 9 ++++ .../compile-fail/ptr_eq_out_of_bounds_null.rs | 6 +++ tests/run-pass-fullmir/loop-break-value.rs | 4 +- tests/run-pass/pointers.rs | 27 ++++++++-- 8 files changed, 102 insertions(+), 14 deletions(-) create mode 100644 tests/compile-fail/ptr_eq_dangling.rs create mode 100644 tests/compile-fail/ptr_eq_integer.rs create mode 100644 tests/compile-fail/ptr_eq_out_of_bounds.rs create mode 100644 tests/compile-fail/ptr_eq_out_of_bounds_null.rs diff --git a/src/memory.rs b/src/memory.rs index 9f8118a223bc2..4e0fcd4f511ff 100644 --- a/src/memory.rs +++ b/src/memory.rs @@ -46,7 +46,7 @@ pub enum MemoryKind { C, /// Part of env var emulation Env, - // mutable statics + /// mutable statics MutStatic, } diff --git a/src/operator.rs b/src/operator.rs index 4f697dbd5b748..cf416c44c11fd 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -152,18 +152,50 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: (Scalar::Ptr(ptr), Scalar::Bits { bits, size }) | (Scalar::Bits { bits, size }, Scalar::Ptr(ptr)) => { assert_eq!(size as u64, self.pointer_size().bytes()); + let bits = bits as u64; + let (alloc_size, alloc_align) = self.memory.get_size_and_align(ptr.alloc_id)?; + // Case I: Comparing with NULL if bits == 0 { - // Nothing equals 0, not even dangling pointers. Ideally we would - // require them to be in-bounds of their (possilby dead) allocation, - // but with the allocation gonew e cannot check that. - false - } else { - // Live pointers cannot equal an integer, but again do not - // allow comparing dead pointers. - self.memory.check_bounds(ptr, false)?; - false + // Test if the ptr is in-bounds. Then it cannot be NULL. + if ptr.offset <= alloc_size { + return Ok(false); + } + } + // Case II: Alignment gives it away + if ptr.offset.bytes() % alloc_align.abi() == 0 { + // The offset maintains the allocation alignment, so we know `base+offset` + // is aligned by `alloc_align`. + // FIXME: We could be even more general, e.g. offset 2 into a 4-aligned + // allocation cannot equal 3. + if bits % alloc_align.abi() != 0 { + // The integer is *not* aligned. So they cannot be equal. + return Ok(false); + } } + // Case III: The integer is too big, and the allocation goes on a bit + // without wrapping around the address space. + { + // Compute the highest address at which this allocation could live. + // Substract one more, because it must be possible to add the size + // to the base address without overflowing -- IOW, the very last address + // of the address space is never dereferencable (but it can be in-bounds, i.e., + // one-past-the-end). + let max_base_addr = + ((1u128 << self.pointer_size().bits()) + - u128::from(alloc_size.bytes()) + - 1 + ) as u64; + if let Some(max_addr) = max_base_addr.checked_add(ptr.offset.bytes()) { + if bits > max_addr { + // The integer is too big, this cannot possibly be equal + return Ok(false) + } + } + } + + // None of the supported cases. + return err!(InvalidPointerMath); } }) } diff --git a/tests/compile-fail/ptr_eq_dangling.rs b/tests/compile-fail/ptr_eq_dangling.rs new file mode 100644 index 0000000000000..d05996a13d562 --- /dev/null +++ b/tests/compile-fail/ptr_eq_dangling.rs @@ -0,0 +1,10 @@ +fn main() { + let b = Box::new(0); + let x = &*b as *const i32; // soon-to-be dangling + drop(b); + let b = Box::new(0); + let y = &*b as *const i32; // different allocation + // We cannot compare these even though both are inbounds -- they *could* be + // equal if memory was reused. + assert!(x != y); //~ ERROR dangling pointer +} diff --git a/tests/compile-fail/ptr_eq_integer.rs b/tests/compile-fail/ptr_eq_integer.rs new file mode 100644 index 0000000000000..10d5fbd517a3c --- /dev/null +++ b/tests/compile-fail/ptr_eq_integer.rs @@ -0,0 +1,8 @@ +use std::mem; + +fn main() { + let b = Box::new(0); + let x = &*b as *const i32; + // We cannot compare this with a non-NULL integer. After all, these *could* be equal (with the right base address). + assert!(x != mem::align_of::() as *const i32); //~ ERROR invalid arithmetic on pointers +} diff --git a/tests/compile-fail/ptr_eq_out_of_bounds.rs b/tests/compile-fail/ptr_eq_out_of_bounds.rs new file mode 100644 index 0000000000000..af4eed8d4e32d --- /dev/null +++ b/tests/compile-fail/ptr_eq_out_of_bounds.rs @@ -0,0 +1,9 @@ +fn main() { + let b = Box::new(0); + let x = (&*b as *const i32).wrapping_sub(0x800); // out-of-bounds + let b = Box::new(0); + let y = &*b as *const i32; // different allocation + // We cannot compare these even though both allocations are live -- they *could* be + // equal (with the right base addresses). + assert!(x != y); //~ ERROR outside bounds +} diff --git a/tests/compile-fail/ptr_eq_out_of_bounds_null.rs b/tests/compile-fail/ptr_eq_out_of_bounds_null.rs new file mode 100644 index 0000000000000..3b7b51fc19954 --- /dev/null +++ b/tests/compile-fail/ptr_eq_out_of_bounds_null.rs @@ -0,0 +1,6 @@ +fn main() { + let b = Box::new(0); + let x = (&*b as *const i32).wrapping_sub(0x800); // out-of-bounds + // We cannot compare this with NULL. After all, this *could* be NULL (with the right base address). + assert!(x != std::ptr::null()); //~ ERROR invalid arithmetic on pointers +} diff --git a/tests/run-pass-fullmir/loop-break-value.rs b/tests/run-pass-fullmir/loop-break-value.rs index 8631909a2a966..ab79a64b56e2a 100644 --- a/tests/run-pass-fullmir/loop-break-value.rs +++ b/tests/run-pass-fullmir/loop-break-value.rs @@ -61,7 +61,9 @@ pub fn main() { break Default::default() }; }; - assert_eq!(trait_unified_2, [""]); + // compare lengths; ptr comparison is not deterministic + assert_eq!(trait_unified_2.len(), 1); + assert_eq!(trait_unified_2[0].len(), 0); let trait_unified_3 = loop { break if false { diff --git a/tests/run-pass/pointers.rs b/tests/run-pass/pointers.rs index d8f030de07231..2b26791328df6 100644 --- a/tests/run-pass/pointers.rs +++ b/tests/run-pass/pointers.rs @@ -1,3 +1,5 @@ +use std::usize; + fn one_line_ref() -> i16 { *&1 } @@ -44,8 +46,8 @@ fn match_ref_mut() -> i8 { } fn dangling_pointer() -> *const i32 { - let b = Box::new(42); - &*b as *const i32 + let b = Box::new((42, 42)); // make it bigger than the alignment, so that there is some "room" after this pointer + &b.0 as *const i32 } fn main() { @@ -56,10 +58,29 @@ fn main() { assert_eq!(tuple_ref_mut(), (10, 22)); assert_eq!(match_ref_mut(), 42); - // Compare even dangling pointers with NULL, and with others in the same allocation. + // Compare even dangling pointers with NULL, and with others in the same allocation, including + // out-of-bounds. assert!(dangling_pointer() != std::ptr::null()); assert!(match dangling_pointer() as usize { 0 => false, _ => true }); let dangling = dangling_pointer(); assert!(dangling == dangling); assert!(dangling.wrapping_add(1) != dangling); + assert!(dangling.wrapping_sub(1) != dangling); + + // Compare pointer with BIG integers + let dangling = dangling as usize; + assert!(dangling != usize::MAX); + assert!(dangling != usize::MAX - 1); + assert!(dangling != usize::MAX - 2); + assert!(dangling != usize::MAX - 3); // this is even 4-aligned, but it still cannot be equal because of the extra "room" after this pointer + assert_eq!((usize::MAX - 3) % 4, 0); // just to be sure we got this right + + // Compare pointer with unaligned integers + assert!(dangling != 1usize); + assert!(dangling != 2usize); + assert!(dangling != 3usize); + // 4 is a possible choice! So we cannot compare with that. + assert!(dangling != 5usize); + assert!(dangling != 6usize); + assert!(dangling != 7usize); } From 83ae0530a71ad21b13cb9a1acd3ce14e8d6688d4 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 18 Sep 2018 08:32:23 +0200 Subject: [PATCH 0227/3747] update toolchain --- rust-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-toolchain b/rust-toolchain index 60c47a9305764..48282503c5079 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1 +1 @@ -nightly-2018-09-17 +nightly-2018-09-18 From ea4232cf22613aa06fb3d273dadf58f003df9388 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 20 Sep 2018 01:00:59 +0200 Subject: [PATCH 0228/3747] Move TLS data to machine data There is no good reason to let the machine store stuff in the machine *and* in memory. I plan to get rid of the latter. --- src/fn_call.rs | 36 +++++++++++------------ src/lib.rs | 39 ++++++++++++++++++------- src/memory.rs | 57 ------------------------------------ src/tls.rs | 78 ++++++++++++++++++++++++++++++++------------------ 4 files changed, 94 insertions(+), 116 deletions(-) delete mode 100644 src/memory.rs diff --git a/src/fn_call.rs b/src/fn_call.rs index 0e768fcccf9e5..3e795f1653318 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -8,10 +8,6 @@ use std::mem; use super::*; -use tls::MemoryExt; - -use super::memory::MemoryKind; - pub trait EvalContextExt<'tcx, 'mir> { /// Emulate calling a foreign item, fail if the item is not supported. /// This function will handle `goto_block` if needed. @@ -129,7 +125,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for EvalContext<'a, ' self.write_null(dest)?; } else { let align = self.tcx.data_layout.pointer_align; - let ptr = self.memory.allocate(Size::from_bytes(size), align, MemoryKind::C.into())?; + let ptr = self.memory.allocate(Size::from_bytes(size), align, MiriMemoryKind::C.into())?; self.write_scalar(Scalar::Ptr(ptr), dest)?; } } @@ -140,7 +136,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for EvalContext<'a, ' self.memory.deallocate( ptr.to_ptr()?, None, - MemoryKind::C.into(), + MiriMemoryKind::C.into(), )?; } } @@ -156,7 +152,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for EvalContext<'a, ' } let ptr = self.memory.allocate(Size::from_bytes(size), Align::from_bytes(align, align).unwrap(), - MemoryKind::Rust.into())?; + MiriMemoryKind::Rust.into())?; self.write_scalar(Scalar::Ptr(ptr), dest)?; } "__rust_alloc_zeroed" => { @@ -170,7 +166,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for EvalContext<'a, ' } let ptr = self.memory.allocate(Size::from_bytes(size), Align::from_bytes(align, align).unwrap(), - MemoryKind::Rust.into())?; + MiriMemoryKind::Rust.into())?; self.memory.write_repeat(ptr.into(), 0, Size::from_bytes(size))?; self.write_scalar(Scalar::Ptr(ptr), dest)?; } @@ -187,7 +183,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for EvalContext<'a, ' self.memory.deallocate( ptr, Some((Size::from_bytes(old_size), Align::from_bytes(align, align).unwrap())), - MemoryKind::Rust.into(), + MiriMemoryKind::Rust.into(), )?; } "__rust_realloc" => { @@ -207,7 +203,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for EvalContext<'a, ' Align::from_bytes(align, align).unwrap(), Size::from_bytes(new_size), Align::from_bytes(align, align).unwrap(), - MemoryKind::Rust.into(), + MiriMemoryKind::Rust.into(), )?; self.write_scalar(Scalar::Ptr(new_ptr), dest)?; } @@ -365,7 +361,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for EvalContext<'a, ' } if let Some(old) = success { if let Some(var) = old { - self.memory.deallocate(var, None, MemoryKind::Env.into())?; + self.memory.deallocate(var, None, MiriMemoryKind::Env.into())?; } self.write_null(dest)?; } else { @@ -391,7 +387,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for EvalContext<'a, ' let value_copy = self.memory.allocate( Size::from_bytes((value.len() + 1) as u64), Align::from_bytes(1, 1).unwrap(), - MemoryKind::Env.into(), + MiriMemoryKind::Env.into(), )?; self.memory.write_bytes(value_copy.into(), &value)?; let trailing_zero_ptr = value_copy.offset(Size::from_bytes(value.len() as u64), &self)?.into(); @@ -401,7 +397,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for EvalContext<'a, ' value_copy, ) { - self.memory.deallocate(var, None, MemoryKind::Env.into())?; + self.memory.deallocate(var, None, MiriMemoryKind::Env.into())?; } self.write_null(dest)?; } else { @@ -504,7 +500,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for EvalContext<'a, ' 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; + let key = self.machine.tls.create_tls_key(dtor, *self.tcx) as u128; if key_layout.size.bits() < 128 && key >= (1u128 << key_layout.size.bits() as u128) { return err!(OutOfTls); } @@ -520,19 +516,19 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for EvalContext<'a, ' } "pthread_key_delete" => { let key = self.read_scalar(args[0])?.to_bytes()?; - self.memory.delete_tls_key(key)?; + self.machine.tls.delete_tls_key(key)?; // Return success (0) self.write_null(dest)?; } "pthread_getspecific" => { let key = self.read_scalar(args[0])?.to_bytes()?; - let ptr = self.memory.load_tls(key)?; + let ptr = self.machine.tls.load_tls(key)?; self.write_scalar(ptr, dest)?; } "pthread_setspecific" => { let key = self.read_scalar(args[0])?.to_bytes()?; let new_ptr = self.read_scalar(args[1])?.not_undef()?; - self.memory.store_tls(key, new_ptr)?; + self.machine.tls.store_tls(key, new_ptr)?; // Return success (0) self.write_null(dest)?; @@ -607,7 +603,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for EvalContext<'a, ' // This just creates a key; Windows does not natively support TLS dtors. // Create key and return it - let key = self.memory.create_tls_key(None) as u128; + let key = self.machine.tls.create_tls_key(None, *self.tcx) 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) { @@ -617,13 +613,13 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for EvalContext<'a, ' } "TlsGetValue" => { let key = self.read_scalar(args[0])?.to_bytes()?; - let ptr = self.memory.load_tls(key)?; + let ptr = self.machine.tls.load_tls(key)?; self.write_scalar(ptr, dest)?; } "TlsSetValue" => { let key = self.read_scalar(args[0])?.to_bytes()?; let new_ptr = self.read_scalar(args[1])?.not_undef()?; - self.memory.store_tls(key, new_ptr)?; + self.machine.tls.store_tls(key, new_ptr)?; // Return success (1) self.write_scalar(Scalar::from_int(1, dest.layout.size), dest)?; diff --git a/src/lib.rs b/src/lib.rs index 8bf66999c3dec..98d89510251c9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -21,17 +21,16 @@ use rustc::mir; use syntax::ast::Mutability; use syntax::attr; -use std::marker::PhantomData; use std::collections::HashMap; pub use rustc::mir::interpret::*; pub use rustc_mir::interpret::*; +pub use rustc_mir::interpret; mod fn_call; mod operator; mod intrinsic; mod helpers; -mod memory; mod tls; mod locks; mod range_map; @@ -39,9 +38,7 @@ mod range_map; use fn_call::EvalContextExt as MissingFnsEvalContextExt; use operator::EvalContextExt as OperatorEvalContextExt; use intrinsic::EvalContextExt as IntrinsicEvalContextExt; -use tls::EvalContextExt as TlsEvalContextExt; -use memory::{MemoryKind as MiriMemoryKind, TlsKey, TlsEntry, MemoryData}; -use locks::LockInfo; +use tls::{EvalContextExt as TlsEvalContextExt, TlsData}; use range_map::RangeMap; use helpers::FalibleScalarExt; @@ -54,7 +51,7 @@ pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( tcx.at(syntax::source_map::DUMMY_SP), ty::ParamEnv::reveal_all(), Default::default(), - MemoryData::new() + Default::default(), ); let main_instance = ty::Instance::mono(ecx.tcx.tcx, main_id); @@ -201,21 +198,41 @@ pub fn eval_main<'a, 'tcx: 'a>( } } + +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub enum MiriMemoryKind { + /// `__rust_alloc` memory + Rust, + /// `malloc` memory + C, + /// Part of env var emulation + Env, + /// mutable statics + MutStatic, +} + +impl Into> for MiriMemoryKind { + fn into(self) -> MemoryKind { + MemoryKind::Machine(self) + } +} + + #[derive(Clone, Default, PartialEq, Eq)] pub struct Evaluator<'tcx> { /// Environment variables set by `setenv` /// Miri does not expose env vars from the host to the emulated program pub(crate) env_vars: HashMap, Pointer>, - /// Use the lifetime - _dummy : PhantomData<&'tcx ()>, + /// TLS state + pub(crate) tls: TlsData<'tcx>, } impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { - type MemoryData = memory::MemoryData<'tcx>; - type MemoryKinds = memory::MemoryKind; + type MemoryData = (); + type MemoryKinds = MiriMemoryKind; - const MUT_STATIC_KIND: Option = Some(memory::MemoryKind::MutStatic); + const MUT_STATIC_KIND: Option = Some(MiriMemoryKind::MutStatic); const DETECT_LOOPS: bool = false; /// Returns Ok() when the function was handled, fail otherwise diff --git a/src/memory.rs b/src/memory.rs deleted file mode 100644 index 4e0fcd4f511ff..0000000000000 --- a/src/memory.rs +++ /dev/null @@ -1,57 +0,0 @@ -use std::collections::{HashMap, BTreeMap}; - -use rustc::ty; - -use super::{AllocId, Scalar, LockInfo, RangeMap}; - -pub type TlsKey = u128; - -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -pub struct TlsEntry<'tcx> { - pub(crate) data: Scalar, // Will eventually become a map from thread IDs to `Scalar`s, if we ever support more than one thread. - pub(crate) dtor: Option>, -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct MemoryData<'tcx> { - /// The Key to use for the next thread-local allocation. - pub(crate) next_thread_local: TlsKey, - - /// pthreads-style thread-local storage. - pub(crate) thread_local: BTreeMap>, - - /// Memory regions that are locked by some function - /// - /// Only mutable (static mut, heap, stack) allocations have an entry in this map. - /// The entry is created when allocating the memory and deleted after deallocation. - pub(crate) locks: HashMap>>, -} - -impl<'tcx> MemoryData<'tcx> { - pub(crate) fn new() -> Self { - MemoryData { - next_thread_local: 1, // start with 1 as we must not use 0 on Windows - thread_local: BTreeMap::new(), - locks: HashMap::new(), - } - } -} - - -#[derive(Debug, Copy, Clone, PartialEq, Eq)] -pub enum MemoryKind { - /// `__rust_alloc` memory - Rust, - /// `malloc` memory - C, - /// Part of env var emulation - Env, - /// mutable statics - MutStatic, -} - -impl Into<::rustc_mir::interpret::MemoryKind> for MemoryKind { - fn into(self) -> ::rustc_mir::interpret::MemoryKind { - ::rustc_mir::interpret::MemoryKind::Machine(self) - } -} diff --git a/src/tls.rs b/src/tls.rs index bd0318a62ed45..a1ddaf64cc0f3 100644 --- a/src/tls.rs +++ b/src/tls.rs @@ -1,31 +1,52 @@ -use rustc::{ty, mir}; +use std::collections::BTreeMap; -use super::{TlsKey, TlsEntry, EvalResult, EvalErrorKind, Scalar, Memory, Evaluator, +use rustc::{ty, ty::layout::HasDataLayout, mir}; + +use super::{EvalResult, EvalErrorKind, Scalar, Evaluator, Place, StackPopCleanup, EvalContext}; -pub trait MemoryExt<'tcx> { - fn create_tls_key(&mut self, dtor: Option>) -> TlsKey; - fn delete_tls_key(&mut self, key: TlsKey) -> EvalResult<'tcx>; - fn load_tls(&mut self, key: TlsKey) -> EvalResult<'tcx, Scalar>; - fn store_tls(&mut self, key: TlsKey, new_data: Scalar) -> EvalResult<'tcx>; - fn fetch_tls_dtor( - &mut self, - key: Option, - ) -> Option<(ty::Instance<'tcx>, Scalar, TlsKey)>; +pub type TlsKey = u128; + +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub struct TlsEntry<'tcx> { + pub(crate) data: Scalar, // Will eventually become a map from thread IDs to `Scalar`s, if we ever support more than one thread. + pub(crate) dtor: Option>, +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct TlsData<'tcx> { + /// The Key to use for the next thread-local allocation. + pub(crate) next_key: TlsKey, + + /// pthreads-style thread-local storage. + pub(crate) keys: BTreeMap>, +} + +impl<'tcx> Default for TlsData<'tcx> { + fn default() -> Self { + TlsData { + next_key: 1, // start with 1 as we must not use 0 on Windows + keys: Default::default(), + } + } } pub trait EvalContextExt<'tcx> { fn run_tls_dtors(&mut self) -> EvalResult<'tcx>; } -impl<'a, 'mir, 'tcx: 'mir + 'a> MemoryExt<'tcx> for Memory<'a, 'mir, 'tcx, Evaluator<'tcx>> { - fn create_tls_key(&mut self, dtor: Option>) -> TlsKey { - let new_key = self.data.next_thread_local; - self.data.next_thread_local += 1; - self.data.thread_local.insert( +impl<'tcx> TlsData<'tcx> { + pub fn create_tls_key( + &mut self, + dtor: Option>, + cx: impl HasDataLayout, + ) -> TlsKey { + let new_key = self.next_key; + self.next_key += 1; + self.keys.insert( new_key, TlsEntry { - data: Scalar::ptr_null(*self.tcx).into(), + data: Scalar::ptr_null(cx).into(), dtor, }, ); @@ -33,8 +54,8 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> MemoryExt<'tcx> for Memory<'a, 'mir, 'tcx, Evalu new_key } - fn delete_tls_key(&mut self, key: TlsKey) -> EvalResult<'tcx> { - match self.data.thread_local.remove(&key) { + pub fn delete_tls_key(&mut self, key: TlsKey) -> EvalResult<'tcx> { + match self.keys.remove(&key) { Some(_) => { trace!("TLS key {} removed", key); Ok(()) @@ -43,8 +64,8 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> MemoryExt<'tcx> for Memory<'a, 'mir, 'tcx, Evalu } } - fn load_tls(&mut self, key: TlsKey) -> EvalResult<'tcx, Scalar> { - match self.data.thread_local.get(&key) { + pub fn load_tls(&mut self, key: TlsKey) -> EvalResult<'tcx, Scalar> { + match self.keys.get(&key) { Some(&TlsEntry { data, .. }) => { trace!("TLS key {} loaded: {:?}", key, data); Ok(data) @@ -53,8 +74,8 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> MemoryExt<'tcx> for Memory<'a, 'mir, 'tcx, Evalu } } - fn store_tls(&mut self, key: TlsKey, new_data: Scalar) -> EvalResult<'tcx> { - match self.data.thread_local.get_mut(&key) { + pub fn store_tls(&mut self, key: TlsKey, new_data: Scalar) -> EvalResult<'tcx> { + match self.keys.get_mut(&key) { Some(&mut TlsEntry { ref mut data, .. }) => { trace!("TLS key {} stored: {:?}", key, new_data); *data = new_data; @@ -85,10 +106,11 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> MemoryExt<'tcx> for Memory<'a, 'mir, 'tcx, Evalu fn fetch_tls_dtor( &mut self, key: Option, + cx: impl HasDataLayout, ) -> Option<(ty::Instance<'tcx>, Scalar, TlsKey)> { use std::collections::Bound::*; - let thread_local = &mut self.data.thread_local; + let thread_local = &mut self.keys; let start = match key { Some(key) => Excluded(key), None => Unbounded, @@ -99,7 +121,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> MemoryExt<'tcx> for Memory<'a, 'mir, 'tcx, Evalu if !data.is_null() { if let Some(dtor) = dtor { let ret = Some((dtor, *data, key)); - *data = Scalar::ptr_null(*self.tcx); + *data = Scalar::ptr_null(cx); return ret; } } @@ -110,7 +132,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> MemoryExt<'tcx> for Memory<'a, 'mir, 'tcx, Evalu 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.machine.tls.fetch_tls_dtor(None, *self.tcx); // 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 +156,9 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' // step until out of stackframes self.run()?; - dtor = match self.memory.fetch_tls_dtor(Some(key)) { + dtor = match self.machine.tls.fetch_tls_dtor(Some(key), *self.tcx) { dtor @ Some(_) => dtor, - None => self.memory.fetch_tls_dtor(None), + None => self.machine.tls.fetch_tls_dtor(None, *self.tcx), }; } // FIXME: On a windows target, call `unsafe extern "system" fn on_tls_callback`. From 8d7cdbb8536d853be6199666a72fcae5ca44d3a9 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 20 Sep 2018 12:24:55 +0200 Subject: [PATCH 0229/3747] rustup --- src/lib.rs | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 98d89510251c9..e25ae3a27d1ef 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -228,15 +228,14 @@ pub struct Evaluator<'tcx> { pub(crate) tls: TlsData<'tcx>, } -impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { +impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { type MemoryData = (); type MemoryKinds = MiriMemoryKind; const MUT_STATIC_KIND: Option = Some(MiriMemoryKind::MutStatic); - const DETECT_LOOPS: bool = false; /// Returns Ok() when the function was handled, fail otherwise - fn find_fn<'a>( + fn find_fn( ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, instance: ty::Instance<'tcx>, args: &[OpTy<'tcx>], @@ -246,7 +245,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { ecx.find_fn(instance, args, dest, ret) } - fn call_intrinsic<'a>( + fn call_intrinsic( ecx: &mut rustc_mir::interpret::EvalContext<'a, 'mir, 'tcx, Self>, instance: ty::Instance<'tcx>, args: &[OpTy<'tcx>], @@ -255,7 +254,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { ecx.call_intrinsic(instance, args, dest) } - fn ptr_op<'a>( + fn ptr_op( ecx: &rustc_mir::interpret::EvalContext<'a, 'mir, 'tcx, Self>, bin_op: mir::BinOp, left: Scalar, @@ -266,7 +265,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { ecx.ptr_op(bin_op, left, left_layout, right, right_layout) } - fn box_alloc<'a>( + fn box_alloc( ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, dest: PlaceTy<'tcx>, ) -> EvalResult<'tcx> { @@ -305,7 +304,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { Ok(()) } - fn find_foreign_static<'a>( + fn find_foreign_static( tcx: TyCtxtAt<'a, 'tcx, 'tcx>, def_id: DefId, ) -> EvalResult<'tcx, &'tcx Allocation> { @@ -329,7 +328,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { Ok(alloc) } - fn validation_op<'a>( + fn validation_op( _ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, _op: ::rustc::mir::ValidationOp, _operand: &::rustc::mir::ValidationOperand<'tcx, ::rustc::mir::Place<'tcx>>, @@ -338,4 +337,10 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { //ecx.validation_op(op, operand) Ok(()) } + + fn before_terminator(_ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>) -> EvalResult<'tcx> + { + // We are not interested in detecting loops + Ok(()) + } } From a85b78d30c6e5b6c8b20c10a785679c11565cabd Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 17 Sep 2018 18:05:36 +0200 Subject: [PATCH 0230/3747] test for interestingly aligned field access --- tests/run-pass/issue-53728.rs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 tests/run-pass/issue-53728.rs diff --git a/tests/run-pass/issue-53728.rs b/tests/run-pass/issue-53728.rs new file mode 100644 index 0000000000000..6d440b66b35a0 --- /dev/null +++ b/tests/run-pass/issue-53728.rs @@ -0,0 +1,16 @@ +#![allow(dead_code)] + +#[repr(u16)] +enum DeviceKind { + Nil = 0, +} +#[repr(packed)] +struct DeviceInfo { + endianness: u8, + device_kind: DeviceKind, +} +fn main() { + let _x = None::<(DeviceInfo, u8)>; + let _y = None::<(DeviceInfo, u16)>; + let _z = None::<(DeviceInfo, u64)>; +} From 6b404011cc06bcbaa9badc1db12bbdca0358ceee Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 22 Sep 2018 08:44:38 +0200 Subject: [PATCH 0231/3747] bump toolchain --- rust-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-toolchain b/rust-toolchain index 48282503c5079..c1bf4c3de8045 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1 +1 @@ -nightly-2018-09-18 +nightly-2018-09-22 From f18cb40e4ce0d0fa7ce60c17d2783edffde783f2 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 23 Sep 2018 09:14:55 +0200 Subject: [PATCH 0232/3747] test mutating a non-mut static with interior mutability --- tests/run-pass/static_memory_modification.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/run-pass/static_memory_modification.rs b/tests/run-pass/static_memory_modification.rs index a68f727322e29..6a41078177983 100644 --- a/tests/run-pass/static_memory_modification.rs +++ b/tests/run-pass/static_memory_modification.rs @@ -1,8 +1,14 @@ +use std::sync::atomic::{Ordering, AtomicUsize}; + static mut X: usize = 5; +static Y: AtomicUsize = AtomicUsize::new(5); fn main() { unsafe { X = 6; assert_eq!(X, 6); } + + Y.store(6, Ordering::Relaxed); + assert_eq!(Y.load(Ordering::Relaxed), 6); } From 4b11792259698b056615cffe06c84f6329eff9e0 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 24 Sep 2018 23:01:12 +0200 Subject: [PATCH 0233/3747] bump toolchain --- rust-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-toolchain b/rust-toolchain index c1bf4c3de8045..8a63ffb87c6af 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1 +1 @@ -nightly-2018-09-22 +nightly-2018-09-24 From e8f6973e2d40ab39e30cdbe0cf8e77a72c867d4f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 29 Sep 2018 19:39:34 +0200 Subject: [PATCH 0234/3747] fix test for latest rustc --- rust-toolchain | 2 +- tests/compile-fail/invalid_enum_discriminant.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/rust-toolchain b/rust-toolchain index 8a63ffb87c6af..27d32f29541ae 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1 +1 @@ -nightly-2018-09-24 +nightly-2018-09-29 diff --git a/tests/compile-fail/invalid_enum_discriminant.rs b/tests/compile-fail/invalid_enum_discriminant.rs index a188623a1e0ef..94c100b9ef51a 100644 --- a/tests/compile-fail/invalid_enum_discriminant.rs +++ b/tests/compile-fail/invalid_enum_discriminant.rs @@ -8,8 +8,8 @@ pub enum Foo { fn main() { let f = unsafe { std::mem::transmute::(42) }; - match f { //~ ERROR invalid enum discriminant - Foo::A => {}, + match f { + Foo::A => {}, //~ ERROR invalid enum discriminant Foo::B => {}, Foo::C => {}, Foo::D => {}, From 1ce05523c41d97a26cc037a5fe8b2d6a8907fbd3 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 1 Oct 2018 08:24:42 +0200 Subject: [PATCH 0235/3747] remove needs_drop impl --- rust-toolchain | 2 +- src/intrinsic.rs | 10 ---------- 2 files changed, 1 insertion(+), 11 deletions(-) diff --git a/rust-toolchain b/rust-toolchain index 27d32f29541ae..c062614a6f936 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1 +1 @@ -nightly-2018-09-29 +nightly-2018-10-01 diff --git a/src/intrinsic.rs b/src/intrinsic.rs index 5ee82bf56adb3..53462488b6f73 100644 --- a/src/intrinsic.rs +++ b/src/intrinsic.rs @@ -272,16 +272,6 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: self.copy_op(args[1], ptr.into())?; } - "needs_drop" => { - let ty = substs.type_at(0); - let env = ty::ParamEnv::reveal_all(); - let needs_drop = ty.needs_drop(self.tcx.tcx, env); - self.write_scalar( - Scalar::from_bool(needs_drop), - dest, - )?; - } - "offset" => { let offset = self.read_scalar(args[1])?.to_isize(&self)?; let ptr = self.read_scalar(args[0])?.not_undef()?; From eaff451d5e8e489ec34b161022d4b82360362465 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 1 Oct 2018 08:27:03 +0200 Subject: [PATCH 0236/3747] move 'cargo miri' test down so it is not the first thing testing start-fn --- .travis.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.travis.yml b/.travis.yml index 7f346b5104c27..414b407e92fe8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -38,7 +38,10 @@ script: xargo/build.sh && export MIRI_SYSROOT=~/.xargo/HOST - | - # Test `cargo miri` + # run all tests with full mir + cargo test --release --all-features +- | + # test `cargo miri` cd cargo-miri-test && if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then cargo miri -q -- -Zmiri-start-fn @@ -50,12 +53,9 @@ script: diff -u stdout.ref stdout.real && diff -u stderr.ref stderr.real fi && - # Test `cargo miri test` + # test `cargo miri test` cargo miri test && cd .. -- | - # and run all tests with full mir - cargo test --release --all-features notifications: email: From aa30540ce7d940fcc8e6779832e1c51311078a58 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 1 Oct 2018 12:32:22 +0200 Subject: [PATCH 0237/3747] update CI: Avoid downloading Rust twice --- .travis.yml | 34 ++++++++++++++++++++++------------ appveyor.yml | 17 ++++++++++------- 2 files changed, 32 insertions(+), 19 deletions(-) diff --git a/.travis.yml b/.travis.yml index 414b407e92fe8..137e612598819 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,10 @@ -language: rust -cache: cargo -rust: -- nightly +language: generic +cache: + # Cache the global cargo directory, but NOT the local `target` directory which + # we cannot reuse anyway when the nightly changes (and it grows quite large + # over time). + directories: + - /home/travis/.cargo os: - linux @@ -9,17 +12,25 @@ os: 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 -# prepare -- export PATH=$HOME/.local/bin:$PATH +# Compute the rust version we use. We do not use "language: rust" to have more control here. +- | + if [ "$TRAVIS_EVENT_TYPE" = cron ]; then + RUST_TOOLCHAIN=nightly + else + RUST_TOOLCHAIN=$(cat rust-toolchain) + fi +- rm rust-toolchain +# install Rust +- curl https://build.travis-ci.org/files/rustup-init.sh -sSf | sh -s -- -y --default-toolchain "$RUST_TOOLCHAIN" +- export PATH=$HOME/.cargo/bin:$PATH +- rustc --version +# customize installation - 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" +- cargo install xargo || echo "Skipping xargo install" script: - set -e @@ -27,7 +38,7 @@ script: # Test and install plain miri cargo build --release --all-features && cargo test --release --all-features && - cargo install --all-features --force + cargo install --all-features --force --path . - | # test that the rustc_tests binary compiles cd rustc_tests && @@ -66,4 +77,3 @@ branches: env: global: - RUST_TEST_NOCAPTURE=1 - - TRAVIS_CARGO_NIGHTLY_FEATURE="" diff --git a/appveyor.yml b/appveyor.yml index 14532416978c8..4614891a31297 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -14,18 +14,21 @@ branches: - master install: - - set PATH=C:\Program Files\Git\mingw64\bin;%PATH% + # install Rust + - set PATH=C:\Program Files\Git\mingw64\bin;C:\msys64\mingw%MSYS2_BITS%\bin;%PATH% + - set /p RUST_TOOLCHAIN= Date: Tue, 2 Oct 2018 09:25:55 +0200 Subject: [PATCH 0238/3747] rustup --- src/intrinsic.rs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/intrinsic.rs b/src/intrinsic.rs index 53462488b6f73..e9a5714587fb0 100644 --- a/src/intrinsic.rs +++ b/src/intrinsic.rs @@ -2,12 +2,13 @@ use rustc::mir; use rustc::ty::layout::{self, LayoutOf, Size}; use rustc::ty; -use rustc::mir::interpret::{EvalResult, Scalar, ScalarMaybeUndef, PointerArithmetic}; -use rustc_mir::interpret::{ - PlaceTy, EvalContext, OpTy, Value -}; +use rustc::mir::interpret::{EvalResult, PointerArithmetic}; +use rustc_mir::interpret::{EvalContext, PlaceTy, OpTy}; -use super::{FalibleScalarExt, OperatorEvalContextExt}; +use super::{ + Value, Scalar, ScalarMaybeUndef, + FalibleScalarExt, OperatorEvalContextExt +}; pub trait EvalContextExt<'tcx> { fn call_intrinsic( From 146f5d8d1063ba3ea92eba33b64fcc2b59310643 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 2 Oct 2018 21:16:55 +0200 Subject: [PATCH 0239/3747] rustup; test for return type mismatch --- src/lib.rs | 1 + src/operator.rs | 8 ++++---- tests/compile-fail/cast_fn_ptr5.rs | 9 +++++++++ 3 files changed, 14 insertions(+), 4 deletions(-) create mode 100644 tests/compile-fail/cast_fn_ptr5.rs diff --git a/src/lib.rs b/src/lib.rs index e25ae3a27d1ef..e4a389427c52a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -233,6 +233,7 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { type MemoryKinds = MiriMemoryKind; const MUT_STATIC_KIND: Option = Some(MiriMemoryKind::MutStatic); + const ENFORCE_VALIDITY: bool = false; // this is still WIP /// Returns Ok() when the function was handled, fail otherwise fn find_fn( diff --git a/src/operator.rs b/src/operator.rs index cf416c44c11fd..13532764c973b 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -142,8 +142,8 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: // allocations sit right next to each other. The C/C++ standards are // somewhat fuzzy about this case, so I think for now this check is // "good enough". - self.memory.check_bounds(left, false)?; - self.memory.check_bounds(right, false)?; + self.memory.check_bounds_ptr(left, false)?; + self.memory.check_bounds_ptr(right, false)?; // Two live in-bounds pointers, we can compare across allocations left == right } @@ -296,9 +296,9 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: if let Scalar::Ptr(ptr) = ptr { // Both old and new pointer must be in-bounds. // (Of the same allocation, but that part is trivial with our representation.) - self.memory.check_bounds(ptr, false)?; + self.memory.check_bounds_ptr(ptr, false)?; let ptr = ptr.signed_offset(offset, self)?; - self.memory.check_bounds(ptr, false)?; + self.memory.check_bounds_ptr(ptr, false)?; Ok(Scalar::Ptr(ptr)) } else { // An integer pointer. They can move around freely, as long as they do not overflow diff --git a/tests/compile-fail/cast_fn_ptr5.rs b/tests/compile-fail/cast_fn_ptr5.rs new file mode 100644 index 0000000000000..e4ac95e676764 --- /dev/null +++ b/tests/compile-fail/cast_fn_ptr5.rs @@ -0,0 +1,9 @@ +fn main() { + fn f() -> u32 { 42 } + + let g = unsafe { + std::mem::transmute:: u32, fn()>(f) + }; + + g() //~ ERROR tried to call a function with return type u32 passing return place of type () +} From 959693f1e5fd8b504f0690a34b8da4673d44f8b2 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 6 Oct 2018 18:32:39 +0200 Subject: [PATCH 0240/3747] ensure that we cannot use (wrapping_)offset to go from an int ptr to a real ptr --- tests/compile-fail/ptr_offset_int_plus_ptr.rs | 9 +++++++++ tests/compile-fail/ptr_wrapping_offset_int_plus_ptr.rs | 8 ++++++++ 2 files changed, 17 insertions(+) create mode 100644 tests/compile-fail/ptr_offset_int_plus_ptr.rs create mode 100644 tests/compile-fail/ptr_wrapping_offset_int_plus_ptr.rs diff --git a/tests/compile-fail/ptr_offset_int_plus_ptr.rs b/tests/compile-fail/ptr_offset_int_plus_ptr.rs new file mode 100644 index 0000000000000..a3895a71b1bdc --- /dev/null +++ b/tests/compile-fail/ptr_offset_int_plus_ptr.rs @@ -0,0 +1,9 @@ +// error-pattern: pointer value as raw bytes + +fn main() { + let ptr = &mut *Box::new(0u32) as *mut u32; + // Can't start with an integer pointer and get to something usable + unsafe { + let _ = (1 as *mut u8).offset(ptr as isize); + } +} diff --git a/tests/compile-fail/ptr_wrapping_offset_int_plus_ptr.rs b/tests/compile-fail/ptr_wrapping_offset_int_plus_ptr.rs new file mode 100644 index 0000000000000..0f53c1d895165 --- /dev/null +++ b/tests/compile-fail/ptr_wrapping_offset_int_plus_ptr.rs @@ -0,0 +1,8 @@ +// error-pattern: pointer value as raw bytes + +fn main() { + let ptr = &mut *Box::new(0u32) as *mut u32; + // Can't start with an integer pointer and get to something usable + let ptr = (1 as *mut u8).wrapping_offset(ptr as isize); + let _ = unsafe { *ptr }; +} From 59eb3dbdae487f67d81c2e5d46dcbd636c9d0cf9 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 7 Oct 2018 10:35:34 +0200 Subject: [PATCH 0241/3747] use Box::into_raw --- tests/compile-fail/ptr_offset_int_plus_ptr.rs | 2 +- tests/compile-fail/ptr_wrapping_offset_int_plus_ptr.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/compile-fail/ptr_offset_int_plus_ptr.rs b/tests/compile-fail/ptr_offset_int_plus_ptr.rs index a3895a71b1bdc..b45548935807c 100644 --- a/tests/compile-fail/ptr_offset_int_plus_ptr.rs +++ b/tests/compile-fail/ptr_offset_int_plus_ptr.rs @@ -1,7 +1,7 @@ // error-pattern: pointer value as raw bytes fn main() { - let ptr = &mut *Box::new(0u32) as *mut u32; + let ptr = Box::into_raw(Box::new(0u32)); // Can't start with an integer pointer and get to something usable unsafe { let _ = (1 as *mut u8).offset(ptr as isize); diff --git a/tests/compile-fail/ptr_wrapping_offset_int_plus_ptr.rs b/tests/compile-fail/ptr_wrapping_offset_int_plus_ptr.rs index 0f53c1d895165..b3dda27fad1e7 100644 --- a/tests/compile-fail/ptr_wrapping_offset_int_plus_ptr.rs +++ b/tests/compile-fail/ptr_wrapping_offset_int_plus_ptr.rs @@ -1,7 +1,7 @@ // error-pattern: pointer value as raw bytes fn main() { - let ptr = &mut *Box::new(0u32) as *mut u32; + let ptr = Box::into_raw(Box::new(0u32)); // Can't start with an integer pointer and get to something usable let ptr = (1 as *mut u8).wrapping_offset(ptr as isize); let _ = unsafe { *ptr }; From cc275c63a90d4bea394e76607b2e10611eb1be36 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 8 Oct 2018 13:35:54 +0200 Subject: [PATCH 0242/3747] fix for fn allocations now having an alignment (1) and a size (0) --- src/operator.rs | 2 +- tests/compile-fail/deref_fn_ptr.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/operator.rs b/src/operator.rs index 13532764c973b..6e903a8f46b3b 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -153,7 +153,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: (Scalar::Bits { bits, size }, Scalar::Ptr(ptr)) => { assert_eq!(size as u64, self.pointer_size().bytes()); let bits = bits as u64; - let (alloc_size, alloc_align) = self.memory.get_size_and_align(ptr.alloc_id)?; + let (alloc_size, alloc_align) = self.memory.get_size_and_align(ptr.alloc_id); // Case I: Comparing with NULL if bits == 0 { diff --git a/tests/compile-fail/deref_fn_ptr.rs b/tests/compile-fail/deref_fn_ptr.rs index 1b36c77bd32ab..68826a6ff03d5 100644 --- a/tests/compile-fail/deref_fn_ptr.rs +++ b/tests/compile-fail/deref_fn_ptr.rs @@ -1,8 +1,8 @@ fn f() {} fn main() { - let x: i32 = unsafe { - *std::mem::transmute::(f) //~ ERROR constant evaluation error: tried to dereference a function pointer + let x: u8 = unsafe { + *std::mem::transmute::(f) //~ ERROR constant evaluation error: tried to dereference a function pointer }; panic!("this should never print: {}", x); } From edf28fa227c68267153dc42119f3170f46b14389 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 8 Oct 2018 10:22:26 +0200 Subject: [PATCH 0243/3747] only allow offset-by-0 on integer pointers --- src/operator.rs | 18 +++++++----------- tests/compile-fail/ptr_offset_int_plus_int.rs | 8 ++++++++ 2 files changed, 15 insertions(+), 11 deletions(-) create mode 100644 tests/compile-fail/ptr_offset_int_plus_int.rs diff --git a/src/operator.rs b/src/operator.rs index cf416c44c11fd..6fed43914e16d 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -281,14 +281,6 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: pointee_ty: Ty<'tcx>, offset: i64, ) -> EvalResult<'tcx, Scalar> { - if ptr.is_null() { - // NULL pointers must only be offset by 0 - return if offset == 0 { - Ok(ptr) - } else { - err!(InvalidNullPointerUsage) - }; - } // 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.checked_mul(pointee_size).ok_or_else(|| EvalErrorKind::Overflow(mir::BinOp::Mul))?; @@ -301,9 +293,13 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: self.memory.check_bounds(ptr, false)?; Ok(Scalar::Ptr(ptr)) } else { - // An integer pointer. They can move around freely, as long as they do not overflow - // (which ptr_signed_offset checks). - ptr.ptr_signed_offset(offset, self) + // An integer pointer. They can only be offset by 0, and we pretend there + // is a little zero-sized allocation here. + if offset == 0 { + Ok(ptr) + } else { + err!(InvalidPointerMath) + } } } } diff --git a/tests/compile-fail/ptr_offset_int_plus_int.rs b/tests/compile-fail/ptr_offset_int_plus_int.rs new file mode 100644 index 0000000000000..fa4efa323654a --- /dev/null +++ b/tests/compile-fail/ptr_offset_int_plus_int.rs @@ -0,0 +1,8 @@ +// error-pattern: invalid arithmetic on pointers + +fn main() { + // Can't offset an integer pointer by non-zero offset. + unsafe { + let _ = (1 as *mut u8).offset(1); + } +} From 0641d5b6d30a6f66bfd8ec1ff06bc7170569e6a1 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 8 Oct 2018 11:22:52 +0200 Subject: [PATCH 0244/3747] 0-offset is also not always okay --- tests/compile-fail/ptr_offset_ptr_plus_0.rs | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 tests/compile-fail/ptr_offset_ptr_plus_0.rs diff --git a/tests/compile-fail/ptr_offset_ptr_plus_0.rs b/tests/compile-fail/ptr_offset_ptr_plus_0.rs new file mode 100644 index 0000000000000..46937b1c8ce41 --- /dev/null +++ b/tests/compile-fail/ptr_offset_ptr_plus_0.rs @@ -0,0 +1,7 @@ +// error-pattern: outside bounds of allocation + +fn main() { + let x = Box::into_raw(Box::new(0u32)); + let x = x.wrapping_offset(8); // okay, this has no inbounds tag + let _x = unsafe { x.offset(0) }; // UB despite offset 0, the pointer is not inbounds of the only object it can point to +} From 5f2c74e022d5e2202c53fa2b92d5f727be0f2b13 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 9 Oct 2018 20:17:54 +0200 Subject: [PATCH 0245/3747] update to vergen 3 --- Cargo.toml | 2 +- build.rs | 15 ++------------- 2 files changed, 3 insertions(+), 14 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index d690f87b536c6..f7caa4d1c2c89 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -32,7 +32,7 @@ env_logger = "0.5" log = "0.4" [build-dependencies] -vergen = "2" +vergen = "3" [features] cargo_miri = ["cargo_metadata"] diff --git a/build.rs b/build.rs index 73eb68359a821..97bb9358832c4 100644 --- a/build.rs +++ b/build.rs @@ -8,17 +8,6 @@ fn main() { // Don't rebuild miri even if nothing changed println!("cargo:rerun-if-changed=build.rs"); // vergen - vergen().expect("Unable to generate vergen constants!"); -} - -fn vergen() -> vergen::Result<()> { - use vergen::{ConstantsFlags, Vergen}; - - let vergen = Vergen::new(ConstantsFlags::all())?; - - for (k, v) in vergen.build_info() { - println!("cargo:rustc-env={}={}", k.name(), v); - } - - Ok(()) + vergen::generate_cargo_keys(vergen::ConstantsFlags::all()) + .expect("Unable to generate vergen keys!"); } From 57afd396a65d9501002feef1a7a436dd78e7dd83 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 10 Oct 2018 09:08:03 +0200 Subject: [PATCH 0246/3747] bump toolchain --- rust-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-toolchain b/rust-toolchain index c062614a6f936..5fb054b088e46 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1 +1 @@ -nightly-2018-10-01 +nightly-2018-10-10 From 8ea8cd29190cae7ea50dc939ad63b0e8bc650373 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 5 Oct 2018 18:08:50 +0200 Subject: [PATCH 0247/3747] update for ptr provenance --- src/intrinsic.rs | 4 +- src/lib.rs | 27 +++++++++---- src/mono_hash_map.rs | 91 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 113 insertions(+), 9 deletions(-) create mode 100644 src/mono_hash_map.rs diff --git a/src/intrinsic.rs b/src/intrinsic.rs index e9a5714587fb0..b7338d4d52143 100644 --- a/src/intrinsic.rs +++ b/src/intrinsic.rs @@ -252,7 +252,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: _ => { // Do it in memory let mplace = self.force_allocation(dest)?; - assert!(mplace.extra.is_none()); + assert!(mplace.meta.is_none()); self.memory.write_repeat(mplace.ptr, 0, dest.layout.size)?; } } @@ -410,7 +410,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: _ => { // Do it in memory let mplace = self.force_allocation(dest)?; - assert!(mplace.extra.is_none()); + assert!(mplace.meta.is_none()); self.memory.mark_definedness(mplace.ptr.to_ptr()?, dest.layout.size, false)?; } } diff --git a/src/lib.rs b/src/lib.rs index e4a389427c52a..81a2ceead0a62 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -13,6 +13,9 @@ extern crate rustc_mir; extern crate rustc_target; extern crate syntax; +use std::collections::HashMap; +use std::borrow::Cow; + use rustc::ty::{self, TyCtxt, query::TyCtxtAt}; use rustc::ty::layout::{TyLayout, LayoutOf, Size}; use rustc::hir::def_id::DefId; @@ -21,11 +24,10 @@ use rustc::mir; use syntax::ast::Mutability; use syntax::attr; -use std::collections::HashMap; pub use rustc::mir::interpret::*; pub use rustc_mir::interpret::*; -pub use rustc_mir::interpret; +pub use rustc_mir::interpret::{self, AllocMap}; // resolve ambiguity mod fn_call; mod operator; @@ -34,6 +36,7 @@ mod helpers; mod tls; mod locks; mod range_map; +mod mono_hash_map; use fn_call::EvalContextExt as MissingFnsEvalContextExt; use operator::EvalContextExt as OperatorEvalContextExt; @@ -41,6 +44,7 @@ use intrinsic::EvalContextExt as IntrinsicEvalContextExt; use tls::{EvalContextExt as TlsEvalContextExt, TlsData}; use range_map::RangeMap; use helpers::FalibleScalarExt; +use mono_hash_map::MonoHashMap; pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( tcx: TyCtxt<'a, 'tcx, 'tcx>, @@ -231,8 +235,11 @@ pub struct Evaluator<'tcx> { impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { type MemoryData = (); type MemoryKinds = MiriMemoryKind; + type PointerTag = (); // still WIP - const MUT_STATIC_KIND: Option = Some(MiriMemoryKind::MutStatic); + type MemoryMap = MonoHashMap, Allocation<()>)>; + + const STATIC_KIND: Option = Some(MiriMemoryKind::MutStatic); const ENFORCE_VALIDITY: bool = false; // this is still WIP /// Returns Ok() when the function was handled, fail otherwise @@ -308,7 +315,7 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { fn find_foreign_static( tcx: TyCtxtAt<'a, 'tcx, 'tcx>, def_id: DefId, - ) -> EvalResult<'tcx, &'tcx Allocation> { + ) -> EvalResult<'tcx, Cow<'tcx, Allocation>> { let attrs = tcx.get_attrs(def_id); let link_name = match attr::first_attr_value_str_by_name(&attrs, "link_name") { Some(name) => name.as_str(), @@ -319,14 +326,13 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { "__cxa_thread_atexit_impl" => { // This should be all-zero, pointer-sized let data = vec![0; tcx.data_layout.pointer_size.bytes() as usize]; - let alloc = Allocation::from_bytes(&data[..], tcx.data_layout.pointer_align); - tcx.intern_const_alloc(alloc) + Allocation::from_bytes(&data[..], tcx.data_layout.pointer_align) } _ => return err!(Unimplemented( format!("can't access foreign static: {}", link_name), )), }; - Ok(alloc) + Ok(Cow::Owned(alloc)) } fn validation_op( @@ -344,4 +350,11 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { // We are not interested in detecting loops Ok(()) } + + fn static_with_default_tag( + alloc: &'_ Allocation + ) -> Cow<'_, Allocation> { + let alloc = alloc.clone(); + Cow::Owned(alloc) + } } diff --git a/src/mono_hash_map.rs b/src/mono_hash_map.rs new file mode 100644 index 0000000000000..76ca7ac6a133a --- /dev/null +++ b/src/mono_hash_map.rs @@ -0,0 +1,91 @@ +//! This is a "monotonic HashMap": A HashMap that, when shared, can be pushed to but not +//! otherwise mutated. We also Box items in the map. This means we can safely provide +//! shared references into existing items in the HashMap, because they will not be dropped +//! (from being removed) or moved (because they are boxed). +//! The API is is completely tailored to what `memory.rs` needs. It is still in +//! a separate file to minimize the amount of code that has to care about the unsafety. + +use std::collections::hash_map::Entry; +use std::cell::RefCell; +use std::hash::Hash; +use std::borrow::Borrow; + +use rustc_data_structures::fx::FxHashMap; + +use super::AllocMap; + +#[derive(Debug, Clone)] +pub struct MonoHashMap(RefCell>>); + +impl Default for MonoHashMap { + fn default() -> Self { + MonoHashMap(RefCell::new(Default::default())) + } +} + +impl AllocMap for MonoHashMap { + #[inline(always)] + fn contains_key(&mut self, k: &Q) -> bool + where K: Borrow + { + self.0.get_mut().contains_key(k) + } + + #[inline(always)] + fn insert(&mut self, k: K, v: V) -> Option + { + self.0.get_mut().insert(k, Box::new(v)).map(|x| *x) + } + + #[inline(always)] + fn remove(&mut self, k: &Q) -> Option + where K: Borrow + { + self.0.get_mut().remove(k).map(|x| *x) + } + + #[inline(always)] + fn filter_map_collect(&self, mut f: impl FnMut(&K, &V) -> Option) -> Vec { + self.0.borrow() + .iter() + .filter_map(move |(k, v)| f(k, &*v)) + .collect() + } + + /// The most interesting method: Providing a shared ref without + /// holding the `RefCell` open, and inserting new data if the key + /// is not used yet. + /// `vacant` is called if the key is not found in the map; + /// if it returns a reference, that is used directly, if it + /// returns owned data, that is put into the map and returned. + #[inline(always)] + fn get_or( + &self, + k: K, + vacant: impl FnOnce() -> Result + ) -> Result<&V, E> { + let val: *const V = match self.0.borrow_mut().entry(k) { + Entry::Occupied(entry) => &**entry.get(), + Entry::Vacant(entry) => &**entry.insert(Box::new(vacant()?)), + }; + // This is safe because `val` points into a `Box`, that we know will not move and + // will also not be dropped as long as the shared reference `self` is live. + unsafe { Ok(&*val) } + } + + #[inline(always)] + fn get_mut_or( + &mut self, + k: K, + vacant: impl FnOnce() -> Result + ) -> Result<&mut V, E> + { + match self.0.get_mut().entry(k) { + Entry::Occupied(e) => Ok(e.into_mut()), + Entry::Vacant(e) => { + let v = vacant()?; + Ok(e.insert(Box::new(v))) + } + } + } +} From cde707d28b1e3489c5bb34c0f86d650537436790 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 11 Oct 2018 08:45:57 +0200 Subject: [PATCH 0248/3747] bump toolchain --- rust-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-toolchain b/rust-toolchain index 5fb054b088e46..721790eb1a83d 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1 +1 @@ -nightly-2018-10-10 +nightly-2018-10-11 From ce5b183e8bbaa7a2fa7d20077808027e0cc5bd78 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 9 Oct 2018 22:03:14 +0200 Subject: [PATCH 0249/3747] update for new return place handling --- src/fn_call.rs | 3 +-- src/lib.rs | 13 ++++++------- src/tls.rs | 11 +++++++---- 3 files changed, 14 insertions(+), 13 deletions(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index 3e795f1653318..9b6a9c67b16af 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -252,12 +252,11 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for EvalContext<'a, ' // 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. let mir = self.load_mir(f_instance.def)?; - let closure_dest = Place::null(&self); self.push_stack_frame( f_instance, mir.span, mir, - closure_dest, + None, StackPopCleanup::Goto(Some(ret)), // directly return to caller )?; let mut args = self.frame().mir.args_iter(); diff --git a/src/lib.rs b/src/lib.rs index 81a2ceead0a62..04405f383d122 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -67,7 +67,6 @@ 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(); @@ -89,16 +88,15 @@ pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( } // Return value (in static memory so that it does not count as leak) - let size = ecx.tcx.data_layout.pointer_size; - let align = ecx.tcx.data_layout.pointer_align; - let ret_ptr = ecx.memory_mut().allocate(size, align, MiriMemoryKind::MutStatic.into())?; + let ret = ecx.layout_of(start_mir.return_ty())?; + let ret_ptr = ecx.allocate(ret, MiriMemoryKind::MutStatic.into())?; // Push our stack frame ecx.push_stack_frame( start_instance, start_mir.span, start_mir, - Place::from_ptr(ret_ptr, align), + Some(ret_ptr.into()), StackPopCleanup::None { cleanup: true }, )?; @@ -126,11 +124,12 @@ pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( assert!(args.next().is_none(), "start lang item has more arguments than expected"); } else { + let ret_place = MPlaceTy::dangling(ecx.layout_of(tcx.mk_unit())?, &ecx).into(); ecx.push_stack_frame( main_instance, main_mir.span, main_mir, - Place::from_scalar_ptr(Scalar::from_int(1, ptr_size).into(), ty::layout::Align::from_bytes(1, 1).unwrap()), + Some(ret_place), StackPopCleanup::None { cleanup: true }, )?; @@ -286,7 +285,7 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { malloc, malloc_mir.span, malloc_mir, - *dest, + Some(dest), // Don't do anything when we are done. The statement() function will increment // the old stack frame's stmt counter to the next statement, which means that when // exchange_malloc returns, we go on evaluating exactly where we want to be. diff --git a/src/tls.rs b/src/tls.rs index a1ddaf64cc0f3..c04f7a9c35020 100644 --- a/src/tls.rs +++ b/src/tls.rs @@ -1,9 +1,12 @@ use std::collections::BTreeMap; +use rustc_target::abi::LayoutOf; use rustc::{ty, ty::layout::HasDataLayout, mir}; -use super::{EvalResult, EvalErrorKind, Scalar, Evaluator, - Place, StackPopCleanup, EvalContext}; +use super::{ + EvalResult, EvalErrorKind, StackPopCleanup, EvalContext, Evaluator, + MPlaceTy, Scalar, +}; pub type TlsKey = u128; @@ -139,12 +142,12 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, ' // TODO: Potentially, this has to support all the other possible instances? // See eval_fn_call in interpret/terminator/mod.rs let mir = self.load_mir(instance.def)?; - let ret = Place::null(&self); + let ret_place = MPlaceTy::dangling(self.layout_of(self.tcx.mk_unit())?, &self).into(); self.push_stack_frame( instance, mir.span, mir, - ret, + Some(ret_place), StackPopCleanup::None { cleanup: true }, )?; let arg_local = self.frame().mir.args_iter().next().ok_or_else( From 791f464ea02d017f6499627223a1981b6531ca48 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 9 Oct 2018 22:35:14 +0200 Subject: [PATCH 0250/3747] update for size_and_align considering extern types --- src/intrinsic.rs | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/intrinsic.rs b/src/intrinsic.rs index b7338d4d52143..2128ff5d7aca2 100644 --- a/src/intrinsic.rs +++ b/src/intrinsic.rs @@ -238,7 +238,10 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: "init" => { // Check fast path: we don't want to force an allocation in case the destination is a simple value, // but we also do not want to create a new allocation with 0s and then copy that over. - if !dest.layout.is_zst() { // notzhing to do for ZST + // FIXME: We do not properly validate in case of ZSTs and when doing it in memory! + // However, this only affects direct calls of the intrinsic; calls to the stable + // functions wrapping them do get their validation. + if !dest.layout.is_zst() { // nothing to do for ZST match dest.layout.abi { layout::Abi::Scalar(ref s) => { let x = Scalar::from_int(0, s.value.size(&self)); @@ -338,7 +341,8 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: "size_of_val" => { let mplace = self.ref_to_mplace(self.read_value(args[0])?)?; - let (size, _) = self.size_and_align_of_mplace(mplace)?; + let (size, _) = self.size_and_align_of_mplace(mplace)? + .expect("size_of_val called on extern type"); let ptr_size = self.pointer_size(); self.write_scalar( Scalar::from_uint(size.bytes() as u128, ptr_size), @@ -349,7 +353,8 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: "min_align_of_val" | "align_of_val" => { let mplace = self.ref_to_mplace(self.read_value(args[0])?)?; - let (_, align) = self.size_and_align_of_mplace(mplace)?; + let (_, align) = self.size_and_align_of_mplace(mplace)? + .expect("size_of_val called on extern type"); let ptr_size = self.pointer_size(); self.write_scalar( Scalar::from_uint(align.abi(), ptr_size), @@ -397,6 +402,9 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: "uninit" => { // Check fast path: we don't want to force an allocation in case the destination is a simple value, // but we also do not want to create a new allocation with 0s and then copy that over. + // FIXME: We do not properly validate in case of ZSTs and when doing it in memory! + // However, this only affects direct calls of the intrinsic; calls to the stable + // functions wrapping them do get their validation. if !dest.layout.is_zst() { // nothing to do for ZST match dest.layout.abi { layout::Abi::Scalar(..) => { From a090edbc03b95eb21f75675c026e674d646cae74 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 10 Oct 2018 09:06:44 +0200 Subject: [PATCH 0251/3747] explain a test --- tests/run-pass/ref-invalid-ptr.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/run-pass/ref-invalid-ptr.rs b/tests/run-pass/ref-invalid-ptr.rs index ebbbb77748d43..8edc944c7c889 100644 --- a/tests/run-pass/ref-invalid-ptr.rs +++ b/tests/run-pass/ref-invalid-ptr.rs @@ -1,7 +1,9 @@ fn main() { let x = 2usize as *const u32; + // this is not aligned, but we immediately cast it to a raw ptr so that must be okay let _y = unsafe { &*x as *const u32 }; let x = 0usize as *const u32; + // this is NULL, but we immediately cast it to a raw ptr so that must be okay let _y = unsafe { &*x as *const u32 }; } From d94d32e937c672317527cb440788138f688bf3c4 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 11 Oct 2018 09:02:28 +0200 Subject: [PATCH 0252/3747] enforce_validity became a function --- src/lib.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 04405f383d122..965810d0e40f8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -239,7 +239,11 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { type MemoryMap = MonoHashMap, Allocation<()>)>; const STATIC_KIND: Option = Some(MiriMemoryKind::MutStatic); - const ENFORCE_VALIDITY: bool = false; // this is still WIP + + #[inline(always)] + fn enforce_validity(_ecx: &EvalContext<'a, 'mir, 'tcx, Self>) -> bool { + false // this is still WIP + } /// Returns Ok() when the function was handled, fail otherwise fn find_fn( From e4dfb7013b71b9c6f573aed24e76eab5fdf088e0 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 11 Oct 2018 11:24:22 +0200 Subject: [PATCH 0253/3747] enable validation per default, but add a flag to disable it and use that for some run-pass tests compile-fail does not do validation yet --- src/bin/miri.rs | 56 ++++++++++++------- src/lib.rs | 25 +++++++-- tests/compiletest.rs | 1 + tests/run-pass/btreemap.rs | 6 +- .../run-pass/call_drop_through_owned_slice.rs | 3 + tests/run-pass/issue-29746.rs | 3 + tests/run-pass/rc.rs | 3 + tests/run-pass/ref-invalid-ptr.rs | 3 + tests/run-pass/sendable-class.rs | 3 + tests/run-pass/unique-send.rs | 3 + 10 files changed, 80 insertions(+), 26 deletions(-) diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 57d49b2e6bc5f..d7207da0b3c08 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -25,10 +25,14 @@ use std::path::PathBuf; struct MiriCompilerCalls { default: Box, - /// Whether to begin interpretation at the start_fn lang item or not + + /// Whether to begin interpretation at the start_fn lang item or not. /// - /// If false, the interpretation begins at the `main` function + /// If false, the interpretation begins at the `main` function. start_fn: bool, + + /// Whether to enforce the validity invariant. + validate: bool, } impl<'a> CompilerCalls<'a> for MiriCompilerCalls { @@ -87,7 +91,9 @@ impl<'a> CompilerCalls<'a> for MiriCompilerCalls { let mut control = this.default.build_controller(sess, matches); control.after_hir_lowering.callback = Box::new(after_hir_lowering); let start_fn = this.start_fn; - control.after_analysis.callback = Box::new(move |state| after_analysis(state, start_fn)); + let validate = this.validate; + control.after_analysis.callback = + Box::new(move |state| after_analysis(state, start_fn, validate)); control.after_analysis.stop = Compilation::Stop; control } @@ -101,16 +107,21 @@ fn after_hir_lowering(state: &mut CompileState) { state.session.plugin_attributes.borrow_mut().push(attr); } -fn after_analysis<'a, 'tcx>(state: &mut CompileState<'a, 'tcx>, use_start_fn: bool) { +fn after_analysis<'a, 'tcx>( + state: &mut CompileState<'a, 'tcx>, + use_start_fn: bool, + validate: bool, +) { state.session.abort_if_errors(); let tcx = state.tcx.unwrap(); if std::env::args().any(|arg| arg == "--test") { - struct Visitor<'a, 'tcx: 'a>( - TyCtxt<'a, 'tcx, 'tcx>, - &'a CompileState<'a, 'tcx> - ); + struct Visitor<'a, 'tcx: 'a> { + tcx: TyCtxt<'a, 'tcx, 'tcx>, + state: &'a CompileState<'a, 'tcx>, + validate: bool, + }; impl<'a, 'tcx: 'a, 'hir> itemlikevisit::ItemLikeVisitor<'hir> for Visitor<'a, 'tcx> { fn visit_item(&mut self, i: &'hir hir::Item) { if let hir::ItemKind::Fn(.., body_id) = i.node { @@ -118,13 +129,13 @@ fn after_analysis<'a, 'tcx>(state: &mut CompileState<'a, 'tcx>, use_start_fn: bo attr.name() == "test" }) { - let did = self.0.hir.body_owner_def_id(body_id); + let did = self.tcx.hir.body_owner_def_id(body_id); println!( "running test: {}", - self.0.def_path_debug_str(did), + self.tcx.def_path_debug_str(did), ); - miri::eval_main(self.0, did, None); - self.1.session.abort_if_errors(); + miri::eval_main(self.tcx, did, None, self.validate); + self.state.session.abort_if_errors(); } } } @@ -132,7 +143,7 @@ fn after_analysis<'a, 'tcx>(state: &mut CompileState<'a, 'tcx>, use_start_fn: bo fn visit_impl_item(&mut self, _impl_item: &'hir hir::ImplItem) {} } state.hir_crate.unwrap().visit_all_item_likes( - &mut Visitor(tcx, state), + &mut Visitor { tcx, state, validate } ); } else if let Some((entry_node_id, _, _)) = *state.session.entry_fn.borrow() { let entry_def_id = tcx.hir.local_def_id(entry_node_id); @@ -142,7 +153,7 @@ fn after_analysis<'a, 'tcx>(state: &mut CompileState<'a, 'tcx>, use_start_fn: bo } else { None }; - miri::eval_main(tcx, entry_def_id, start_wrapper); + miri::eval_main(tcx, entry_def_id, start_wrapper, validate); state.session.abort_if_errors(); } else { @@ -221,12 +232,18 @@ fn main() { } let mut start_fn = false; + let mut validate = true; args.retain(|arg| { - if arg == "-Zmiri-start-fn" { - start_fn = true; - false - } else { - true + match arg.as_str() { + "-Zmiri-start-fn" => { + start_fn = true; + false + }, + "-Zmiri-disable-validation" => { + validate = false; + false + }, + _ => true } }); @@ -235,6 +252,7 @@ fn main() { rustc_driver::run_compiler(&args, Box::new(MiriCompilerCalls { default: Box::new(RustcDefaultCalls), start_fn, + validate, }), None, None) }); std::process::exit(result as i32); diff --git a/src/lib.rs b/src/lib.rs index 965810d0e40f8..13b42d8e3c272 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -50,11 +50,12 @@ pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( tcx: TyCtxt<'a, 'tcx, 'tcx>, main_id: DefId, start_wrapper: Option, + validate: bool, ) -> EvalResult<'tcx, EvalContext<'a, 'mir, 'tcx, Evaluator<'tcx>>> { let mut ecx = EvalContext::new( tcx.at(syntax::source_map::DUMMY_SP), ty::ParamEnv::reveal_all(), - Default::default(), + Evaluator::new(validate), Default::default(), ); @@ -145,8 +146,9 @@ pub fn eval_main<'a, 'tcx: 'a>( tcx: TyCtxt<'a, 'tcx, 'tcx>, main_id: DefId, start_wrapper: Option, + validate: bool, ) { - let mut ecx = create_ecx(tcx, main_id, start_wrapper).expect("Couldn't create ecx"); + let mut ecx = create_ecx(tcx, main_id, start_wrapper, validate).expect("Couldn't create ecx"); let res: EvalResult = (|| { ecx.run()?; @@ -221,7 +223,7 @@ impl Into> for MiriMemoryKind { } -#[derive(Clone, Default, PartialEq, Eq)] +#[derive(Clone, PartialEq, Eq)] pub struct Evaluator<'tcx> { /// Environment variables set by `setenv` /// Miri does not expose env vars from the host to the emulated program @@ -229,6 +231,19 @@ pub struct Evaluator<'tcx> { /// TLS state pub(crate) tls: TlsData<'tcx>, + + /// Whether to enforce the validity invariant + pub(crate) validate: bool, +} + +impl<'tcx> Evaluator<'tcx> { + fn new(validate: bool) -> Self { + Evaluator { + env_vars: HashMap::default(), + tls: TlsData::default(), + validate, + } + } } impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { @@ -241,8 +256,8 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { const STATIC_KIND: Option = Some(MiriMemoryKind::MutStatic); #[inline(always)] - fn enforce_validity(_ecx: &EvalContext<'a, 'mir, 'tcx, Self>) -> bool { - false // this is still WIP + fn enforce_validity(ecx: &EvalContext<'a, 'mir, 'tcx, Self>) -> bool { + ecx.machine.validate } /// Returns Ok() when the function was handled, fail otherwise diff --git a/tests/compiletest.rs b/tests/compiletest.rs index 82a2144a337de..151aa89be3f3a 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -64,6 +64,7 @@ fn compile_fail(sysroot: &Path, path: &str, target: &str, host: &str, need_fullm flags.push("-Dwarnings -Dunused".to_owned()); // overwrite the -Aunused in compiletest-rs config.src_base = PathBuf::from(path.to_string()); flags.push("-Zmir-emit-validate=1".to_owned()); + flags.push("-Zmiri-disable-validation".to_owned()); config.target_rustcflags = Some(flags.join(" ")); config.target = target.to_owned(); config.host = host.to_owned(); diff --git a/tests/run-pass/btreemap.rs b/tests/run-pass/btreemap.rs index 0fd28d6f1e8df..dc0fa0987aebb 100644 --- a/tests/run-pass/btreemap.rs +++ b/tests/run-pass/btreemap.rs @@ -1,5 +1,5 @@ -// mir validation can't cope with `mem::uninitialized()`, so this test fails with validation & full-MIR. -// compile-flags: -Zmir-emit-validate=0 +// FIXME: Validation disabled due to https://github.com/rust-lang/rust/issues/54957 +// compile-flags: -Zmiri-disable-validation #[derive(PartialEq, Eq, PartialOrd, Ord)] pub enum Foo { @@ -14,4 +14,6 @@ pub fn main() { b.insert(Foo::A("/=")); b.insert(Foo::A("#")); b.insert(Foo::A("0o")); + assert!(b.remove(&Foo::A("/="))); + assert!(!b.remove(&Foo::A("/="))); } diff --git a/tests/run-pass/call_drop_through_owned_slice.rs b/tests/run-pass/call_drop_through_owned_slice.rs index 3ec6be65ed8b6..b0e336c0480a9 100644 --- a/tests/run-pass/call_drop_through_owned_slice.rs +++ b/tests/run-pass/call_drop_through_owned_slice.rs @@ -1,3 +1,6 @@ +// FIXME validation disabled because ptr::read uses mem::uninitialized +// compile-flags: -Zmiri-disable-validation + struct Bar; static mut DROP_COUNT: usize = 0; diff --git a/tests/run-pass/issue-29746.rs b/tests/run-pass/issue-29746.rs index 61c601ac6a903..94ca146db1cdf 100644 --- a/tests/run-pass/issue-29746.rs +++ b/tests/run-pass/issue-29746.rs @@ -8,6 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// FIXME validation disabled because ptr::read uses mem::uninitialized +// compile-flags: -Zmiri-disable-validation + // zip!(a1,a2,a3,a4) is equivalent to: // a1.zip(a2).zip(a3).zip(a4).map(|(((x1,x2),x3),x4)| (x1,x2,x3,x4)) macro_rules! zip { diff --git a/tests/run-pass/rc.rs b/tests/run-pass/rc.rs index 0bf7075031120..4d89066035ceb 100644 --- a/tests/run-pass/rc.rs +++ b/tests/run-pass/rc.rs @@ -1,3 +1,6 @@ +// FIXME: Validation disabled due to https://github.com/rust-lang/rust/issues/54908 +// compile-flags: -Zmiri-disable-validation + use std::cell::RefCell; use std::rc::Rc; diff --git a/tests/run-pass/ref-invalid-ptr.rs b/tests/run-pass/ref-invalid-ptr.rs index 8edc944c7c889..627c821a9f307 100644 --- a/tests/run-pass/ref-invalid-ptr.rs +++ b/tests/run-pass/ref-invalid-ptr.rs @@ -1,3 +1,6 @@ +// FIXME validation disabled because it checks these references too eagerly +// compile-flags: -Zmiri-disable-validation + fn main() { let x = 2usize as *const u32; // this is not aligned, but we immediately cast it to a raw ptr so that must be okay diff --git a/tests/run-pass/sendable-class.rs b/tests/run-pass/sendable-class.rs index 66f0c84e23c1a..7ca4e1a90841a 100644 --- a/tests/run-pass/sendable-class.rs +++ b/tests/run-pass/sendable-class.rs @@ -8,6 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// FIXME validation disabled because ptr::read uses mem::uninitialized +// compile-flags: -Zmiri-disable-validation + // Test that a class with only sendable fields can be sent use std::sync::mpsc::channel; diff --git a/tests/run-pass/unique-send.rs b/tests/run-pass/unique-send.rs index 7644da08e4afa..8a48d331f4544 100644 --- a/tests/run-pass/unique-send.rs +++ b/tests/run-pass/unique-send.rs @@ -8,6 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// FIXME validation disabled because ptr::read uses mem::uninitialized +// compile-flags: -Zmiri-disable-validation + #![feature(box_syntax)] use std::sync::mpsc::channel; From 1846f111c987e160f880c6893b834c24ff5b816c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 11 Oct 2018 15:28:21 +0200 Subject: [PATCH 0254/3747] fix return place for __rust_maybe_catch_panic --- src/fn_call.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index 9b6a9c67b16af..812df49b0b8fa 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -252,11 +252,12 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for EvalContext<'a, ' // 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. let mir = self.load_mir(f_instance.def)?; + let ret_place = MPlaceTy::dangling(self.layout_of(self.tcx.mk_unit())?, &self).into(); self.push_stack_frame( f_instance, mir.span, mir, - None, + Some(ret_place), StackPopCleanup::Goto(Some(ret)), // directly return to caller )?; let mut args = self.frame().mir.args_iter(); From 26f9d617c347185433b77c481a5c50c55d9b72ce Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 11 Oct 2018 16:10:04 +0200 Subject: [PATCH 0255/3747] do not validate start-fn code --- tests/compiletest.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/compiletest.rs b/tests/compiletest.rs index 151aa89be3f3a..43989a49b3088 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -103,6 +103,8 @@ fn miri_pass(sysroot: &Path, path: &str, target: &str, host: &str, need_fullmir: flags.push("-Dwarnings -Dunused".to_owned()); // overwrite the -Aunused in compiletest-rs if have_fullmir() { flags.push("-Zmiri-start-fn".to_owned()); + // start-fn uses ptr::read, and so fails validation + flags.push("-Zmiri-disable-validation".to_owned()); } if opt { flags.push("-Zmir-opt-level=3".to_owned()); From b99e1267be95e608fb165982a7b77fc0432be360 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 12 Oct 2018 09:07:56 +0200 Subject: [PATCH 0256/3747] atomics wrap around on overflow --- src/intrinsic.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/intrinsic.rs b/src/intrinsic.rs index b7338d4d52143..b62838fbc8bb6 100644 --- a/src/intrinsic.rs +++ b/src/intrinsic.rs @@ -134,7 +134,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: "xsub" => mir::BinOp::Sub, _ => bug!(), }; - // FIXME: what do atomics do on overflow? + // Atomics wrap around on overflow. self.binop_ignore_overflow(op, old, rhs, ptr.into())?; } From 62b819ba18a4a32833bb823afeb32778fd28bbde Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 12 Oct 2018 10:40:44 +0200 Subject: [PATCH 0257/3747] whitelist std::ptr::read --- src/lib.rs | 21 +++++++++++++++++-- tests/compiletest.rs | 2 -- .../run-pass/call_drop_through_owned_slice.rs | 3 --- tests/run-pass/issue-29746.rs | 3 --- tests/run-pass/sendable-class.rs | 3 --- tests/run-pass/unique-send.rs | 3 --- 6 files changed, 19 insertions(+), 16 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 13b42d8e3c272..d52fd0028039d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -255,9 +255,26 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { const STATIC_KIND: Option = Some(MiriMemoryKind::MutStatic); - #[inline(always)] fn enforce_validity(ecx: &EvalContext<'a, 'mir, 'tcx, Self>) -> bool { - ecx.machine.validate + if !ecx.machine.validate { + return false; + } + + // Some functions are whitelisted until we figure out how to fix them. + // We walk up the stack a few frames to also cover their callees. + const WHITELIST: &[&str] = &[ + // Uses mem::uninitialized + "std::ptr::read", + ]; + for frame in ecx.stack().iter() + .rev().take(3) + { + let name = frame.instance.to_string(); + if WHITELIST.iter().any(|white| name.starts_with(white)) { + return false; + } + } + true } /// Returns Ok() when the function was handled, fail otherwise diff --git a/tests/compiletest.rs b/tests/compiletest.rs index 43989a49b3088..151aa89be3f3a 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -103,8 +103,6 @@ fn miri_pass(sysroot: &Path, path: &str, target: &str, host: &str, need_fullmir: flags.push("-Dwarnings -Dunused".to_owned()); // overwrite the -Aunused in compiletest-rs if have_fullmir() { flags.push("-Zmiri-start-fn".to_owned()); - // start-fn uses ptr::read, and so fails validation - flags.push("-Zmiri-disable-validation".to_owned()); } if opt { flags.push("-Zmir-opt-level=3".to_owned()); diff --git a/tests/run-pass/call_drop_through_owned_slice.rs b/tests/run-pass/call_drop_through_owned_slice.rs index b0e336c0480a9..3ec6be65ed8b6 100644 --- a/tests/run-pass/call_drop_through_owned_slice.rs +++ b/tests/run-pass/call_drop_through_owned_slice.rs @@ -1,6 +1,3 @@ -// FIXME validation disabled because ptr::read uses mem::uninitialized -// compile-flags: -Zmiri-disable-validation - struct Bar; static mut DROP_COUNT: usize = 0; diff --git a/tests/run-pass/issue-29746.rs b/tests/run-pass/issue-29746.rs index 94ca146db1cdf..61c601ac6a903 100644 --- a/tests/run-pass/issue-29746.rs +++ b/tests/run-pass/issue-29746.rs @@ -8,9 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// FIXME validation disabled because ptr::read uses mem::uninitialized -// compile-flags: -Zmiri-disable-validation - // zip!(a1,a2,a3,a4) is equivalent to: // a1.zip(a2).zip(a3).zip(a4).map(|(((x1,x2),x3),x4)| (x1,x2,x3,x4)) macro_rules! zip { diff --git a/tests/run-pass/sendable-class.rs b/tests/run-pass/sendable-class.rs index 7ca4e1a90841a..66f0c84e23c1a 100644 --- a/tests/run-pass/sendable-class.rs +++ b/tests/run-pass/sendable-class.rs @@ -8,9 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// FIXME validation disabled because ptr::read uses mem::uninitialized -// compile-flags: -Zmiri-disable-validation - // Test that a class with only sendable fields can be sent use std::sync::mpsc::channel; diff --git a/tests/run-pass/unique-send.rs b/tests/run-pass/unique-send.rs index 8a48d331f4544..7644da08e4afa 100644 --- a/tests/run-pass/unique-send.rs +++ b/tests/run-pass/unique-send.rs @@ -8,9 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// FIXME validation disabled because ptr::read uses mem::uninitialized -// compile-flags: -Zmiri-disable-validation - #![feature(box_syntax)] use std::sync::mpsc::channel; From c9cf0344eed9a5a475c86a7a1e8be426d1f899ef Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 12 Oct 2018 10:54:37 +0200 Subject: [PATCH 0258/3747] enable validation for compile-fail tests, and add some new ones --- tests/compile-fail/cast_box_int_to_fn_ptr.rs | 2 +- tests/compile-fail/cast_int_to_fn_ptr.rs | 2 +- tests/compile-fail/execute_memory.rs | 2 +- tests/compile-fail/fn_ptr_offset.rs | 2 +- tests/compile-fail/invalid_bool.rs | 8 +------- tests/compile-fail/invalid_bool2.rs | 3 +++ tests/compile-fail/invalid_char.rs | 8 ++++++++ .../{match_char2.rs => invalid_char2.rs} | 3 +++ tests/compile-fail/invalid_enum_discriminant.rs | 11 +---------- tests/compile-fail/invalid_enum_discriminant2.rs | 2 +- tests/compile-fail/match_char.rs | 13 ------------- tests/compile-fail/never_say_never.rs | 2 +- tests/compile-fail/never_transmute_humans.rs | 2 +- tests/compile-fail/never_transmute_void.rs | 2 +- tests/compile-fail/reference_to_packed.rs | 2 +- tests/compile-fail/storage_dead_dangling.rs | 3 +++ tests/compile-fail/validation_cast_fn_ptr1.rs | 10 ++++++++++ tests/compile-fail/validation_cast_fn_ptr2.rs | 10 ++++++++++ tests/compiletest.rs | 1 - 19 files changed, 48 insertions(+), 40 deletions(-) create mode 100644 tests/compile-fail/invalid_char.rs rename tests/compile-fail/{match_char2.rs => invalid_char2.rs} (65%) delete mode 100644 tests/compile-fail/match_char.rs create mode 100644 tests/compile-fail/validation_cast_fn_ptr1.rs create mode 100644 tests/compile-fail/validation_cast_fn_ptr2.rs diff --git a/tests/compile-fail/cast_box_int_to_fn_ptr.rs b/tests/compile-fail/cast_box_int_to_fn_ptr.rs index 2a317f579f5e0..cbf370e023630 100644 --- a/tests/compile-fail/cast_box_int_to_fn_ptr.rs +++ b/tests/compile-fail/cast_box_int_to_fn_ptr.rs @@ -1,5 +1,5 @@ // Validation makes this fail in the wrong place -// compile-flags: -Zmir-emit-validate=0 +// compile-flags: -Zmir-emit-validate=0 -Zmiri-disable-validation fn main() { let b = Box::new(42); diff --git a/tests/compile-fail/cast_int_to_fn_ptr.rs b/tests/compile-fail/cast_int_to_fn_ptr.rs index 29d16e9a4259a..2a08d9f1f9f85 100644 --- a/tests/compile-fail/cast_int_to_fn_ptr.rs +++ b/tests/compile-fail/cast_int_to_fn_ptr.rs @@ -1,5 +1,5 @@ // Validation makes this fail in the wrong place -// compile-flags: -Zmir-emit-validate=0 +// compile-flags: -Zmir-emit-validate=0 -Zmiri-disable-validation fn main() { let g = unsafe { diff --git a/tests/compile-fail/execute_memory.rs b/tests/compile-fail/execute_memory.rs index bcde13d13ee77..2f8fea38d8f9f 100644 --- a/tests/compile-fail/execute_memory.rs +++ b/tests/compile-fail/execute_memory.rs @@ -1,5 +1,5 @@ // Validation makes this fail in the wrong place -// compile-flags: -Zmir-emit-validate=0 +// compile-flags: -Zmir-emit-validate=0 -Zmiri-disable-validation #![feature(box_syntax)] diff --git a/tests/compile-fail/fn_ptr_offset.rs b/tests/compile-fail/fn_ptr_offset.rs index 0c0590e375bbc..e6d1da1e0736a 100644 --- a/tests/compile-fail/fn_ptr_offset.rs +++ b/tests/compile-fail/fn_ptr_offset.rs @@ -1,5 +1,5 @@ // Validation makes this fail in the wrong place -// compile-flags: -Zmir-emit-validate=0 +// compile-flags: -Zmir-emit-validate=0 -Zmiri-disable-validation use std::mem; diff --git a/tests/compile-fail/invalid_bool.rs b/tests/compile-fail/invalid_bool.rs index 49328ef5d74e2..af4ad67a4f099 100644 --- a/tests/compile-fail/invalid_bool.rs +++ b/tests/compile-fail/invalid_bool.rs @@ -1,9 +1,3 @@ -//ignore-test FIXME: do some basic validation of invariants for all values in flight -//This does currently not get caught becuase it compiles to SwitchInt, which -//has no knowledge about data invariants. - fn main() { - let b = unsafe { std::mem::transmute::(2) }; - if b { unreachable!() } else { unreachable!() } //~ ERROR constant evaluation error - //~^ NOTE invalid boolean value read + let _b = unsafe { std::mem::transmute::(2) }; //~ ERROR encountered 2, but expected something in the range 0..=1 } diff --git a/tests/compile-fail/invalid_bool2.rs b/tests/compile-fail/invalid_bool2.rs index 47c4e8b410ebe..2348c62559b00 100644 --- a/tests/compile-fail/invalid_bool2.rs +++ b/tests/compile-fail/invalid_bool2.rs @@ -1,3 +1,6 @@ +// Validation makes this fail in the wrong place +// compile-flags: -Zmir-emit-validate=0 -Zmiri-disable-validation + fn main() { let b = unsafe { std::mem::transmute::(2) }; let _x = b == true; //~ ERROR invalid boolean value read diff --git a/tests/compile-fail/invalid_char.rs b/tests/compile-fail/invalid_char.rs new file mode 100644 index 0000000000000..3ff0ed60f664c --- /dev/null +++ b/tests/compile-fail/invalid_char.rs @@ -0,0 +1,8 @@ +fn main() { + assert!(std::char::from_u32(-1_i32 as u32).is_none()); + let _ = match unsafe { std::mem::transmute::(-1) } { //~ ERROR encountered 4294967295, but expected something in the range 0..=1114111 + 'a' => {true}, + 'b' => {false}, + _ => {true}, + }; +} diff --git a/tests/compile-fail/match_char2.rs b/tests/compile-fail/invalid_char2.rs similarity index 65% rename from tests/compile-fail/match_char2.rs rename to tests/compile-fail/invalid_char2.rs index 786dd813a1eb9..5de2d073f3231 100644 --- a/tests/compile-fail/match_char2.rs +++ b/tests/compile-fail/invalid_char2.rs @@ -1,3 +1,6 @@ +// Validation makes this fail in the wrong place +// compile-flags: -Zmir-emit-validate=0 -Zmiri-disable-validation + fn main() { assert!(std::char::from_u32(-1_i32 as u32).is_none()); let c = unsafe { std::mem::transmute::(-1) }; diff --git a/tests/compile-fail/invalid_enum_discriminant.rs b/tests/compile-fail/invalid_enum_discriminant.rs index 94c100b9ef51a..543a797d44f20 100644 --- a/tests/compile-fail/invalid_enum_discriminant.rs +++ b/tests/compile-fail/invalid_enum_discriminant.rs @@ -1,17 +1,8 @@ -// Validation makes this fail in the wrong place -// compile-flags: -Zmir-emit-validate=0 - #[repr(C)] pub enum Foo { A, B, C, D } fn main() { - let f = unsafe { std::mem::transmute::(42) }; - match f { - Foo::A => {}, //~ ERROR invalid enum discriminant - Foo::B => {}, - Foo::C => {}, - Foo::D => {}, - } + let _f = unsafe { std::mem::transmute::(42) }; //~ ERROR encountered invalid enum discriminant 42 } diff --git a/tests/compile-fail/invalid_enum_discriminant2.rs b/tests/compile-fail/invalid_enum_discriminant2.rs index 5a5a20c486953..ea94081693e1b 100644 --- a/tests/compile-fail/invalid_enum_discriminant2.rs +++ b/tests/compile-fail/invalid_enum_discriminant2.rs @@ -1,5 +1,5 @@ // Validation makes this fail in the wrong place -// compile-flags: -Zmir-emit-validate=0 +// compile-flags: -Zmir-emit-validate=0 -Zmiri-disable-validation // error-pattern: invalid enum discriminant diff --git a/tests/compile-fail/match_char.rs b/tests/compile-fail/match_char.rs deleted file mode 100644 index e7fee1e3e3611..0000000000000 --- a/tests/compile-fail/match_char.rs +++ /dev/null @@ -1,13 +0,0 @@ -//ignore-test FIXME: do some basic validation of invariants for all values in flight -//This does currently not get caught becuase it compiles to SwitchInt, which -//has no knowledge about data invariants. - -fn main() { - assert!(std::char::from_u32(-1_i32 as u32).is_none()); - let _ = match unsafe { std::mem::transmute::(-1) } { //~ ERROR constant evaluation error - //~^ NOTE tried to interpret an invalid 32-bit value as a char: 4294967295 - 'a' => {true}, - 'b' => {false}, - _ => {true}, - }; -} diff --git a/tests/compile-fail/never_say_never.rs b/tests/compile-fail/never_say_never.rs index fd76ecbd1503e..9821723deb3bc 100644 --- a/tests/compile-fail/never_say_never.rs +++ b/tests/compile-fail/never_say_never.rs @@ -1,5 +1,5 @@ // This should fail even without validation -// compile-flags: -Zmir-emit-validate=0 +// compile-flags: -Zmir-emit-validate=0 -Zmiri-disable-validation #![feature(never_type)] #![allow(unreachable_code)] diff --git a/tests/compile-fail/never_transmute_humans.rs b/tests/compile-fail/never_transmute_humans.rs index 7652cdfdd3df5..c5c53d4231c7c 100644 --- a/tests/compile-fail/never_transmute_humans.rs +++ b/tests/compile-fail/never_transmute_humans.rs @@ -1,5 +1,5 @@ // This should fail even without validation -// compile-flags: -Zmir-emit-validate=0 +// compile-flags: -Zmir-emit-validate=0 -Zmiri-disable-validation #![feature(never_type)] #![allow(unreachable_code)] diff --git a/tests/compile-fail/never_transmute_void.rs b/tests/compile-fail/never_transmute_void.rs index 9329cd365994e..11fc0f068de0d 100644 --- a/tests/compile-fail/never_transmute_void.rs +++ b/tests/compile-fail/never_transmute_void.rs @@ -1,5 +1,5 @@ // This should fail even without validation -// compile-flags: -Zmir-emit-validate=0 +// compile-flags: -Zmir-emit-validate=0 -Zmiri-disable-validation #![feature(never_type)] #![allow(unreachable_code)] diff --git a/tests/compile-fail/reference_to_packed.rs b/tests/compile-fail/reference_to_packed.rs index 946a6b89a777a..d18f314c8aaa1 100644 --- a/tests/compile-fail/reference_to_packed.rs +++ b/tests/compile-fail/reference_to_packed.rs @@ -1,5 +1,5 @@ // This should fail even without validation -// compile-flags: -Zmir-emit-validate=0 +// compile-flags: -Zmir-emit-validate=0 -Zmiri-disable-validation #![allow(dead_code, unused_variables)] diff --git a/tests/compile-fail/storage_dead_dangling.rs b/tests/compile-fail/storage_dead_dangling.rs index 6abae2069fc2b..69917dce85910 100644 --- a/tests/compile-fail/storage_dead_dangling.rs +++ b/tests/compile-fail/storage_dead_dangling.rs @@ -1,3 +1,6 @@ +// This should fail even without validation +// compile-flags: -Zmir-emit-validate=0 -Zmiri-disable-validation + static mut LEAK: usize = 0; fn fill(v: &mut i32) { diff --git a/tests/compile-fail/validation_cast_fn_ptr1.rs b/tests/compile-fail/validation_cast_fn_ptr1.rs new file mode 100644 index 0000000000000..82f2d10ee4bb5 --- /dev/null +++ b/tests/compile-fail/validation_cast_fn_ptr1.rs @@ -0,0 +1,10 @@ +fn main() { + // Cast a function pointer such that on a call, the argument gets transmuted + // from raw ptr to reference. This is ABI-compatible, so it's not the call that + // should fail, but validation should. + fn f(_x: &i32) { } + + let g: fn(*const i32) = unsafe { std::mem::transmute(f as fn(&i32)) }; + + g(0usize as *const i32) //~ ERROR encountered 0, but expected something greater or equal to 1 +} diff --git a/tests/compile-fail/validation_cast_fn_ptr2.rs b/tests/compile-fail/validation_cast_fn_ptr2.rs new file mode 100644 index 0000000000000..2f3b91a53e622 --- /dev/null +++ b/tests/compile-fail/validation_cast_fn_ptr2.rs @@ -0,0 +1,10 @@ +fn main() { + // Cast a function pointer such that when returning, the return value gets transmuted + // from raw ptr to reference. This is ABI-compatible, so it's not the call that + // should fail, but validation should. + fn f() -> *const i32 { 0usize as *const i32 } + + let g: fn() -> &'static i32 = unsafe { std::mem::transmute(f as fn() -> *const i32) }; + + let _x = g(); //~ ERROR encountered 0, but expected something greater or equal to 1 +} diff --git a/tests/compiletest.rs b/tests/compiletest.rs index 151aa89be3f3a..82a2144a337de 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -64,7 +64,6 @@ fn compile_fail(sysroot: &Path, path: &str, target: &str, host: &str, need_fullm flags.push("-Dwarnings -Dunused".to_owned()); // overwrite the -Aunused in compiletest-rs config.src_base = PathBuf::from(path.to_string()); flags.push("-Zmir-emit-validate=1".to_owned()); - flags.push("-Zmiri-disable-validation".to_owned()); config.target_rustcflags = Some(flags.join(" ")); config.target = target.to_owned(); config.host = host.to_owned(); From 99ca3820e7097f654d4ad49330534a8e49e2165a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 14 Oct 2018 10:35:48 +0200 Subject: [PATCH 0259/3747] bump toolchain --- rust-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-toolchain b/rust-toolchain index 721790eb1a83d..abbc6c90452ac 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1 +1 @@ -nightly-2018-10-11 +nightly-2018-10-14 From b24e1b789dbf765b34c82924b1d8494fc8d84397 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 14 Oct 2018 10:50:35 +0200 Subject: [PATCH 0260/3747] fix rustc_test compilation --- rustc_tests/src/main.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rustc_tests/src/main.rs b/rustc_tests/src/main.rs index 969888ec991ea..73a8d19c309b2 100644 --- a/rustc_tests/src/main.rs +++ b/rustc_tests/src/main.rs @@ -95,7 +95,7 @@ fn after_analysis<'a, 'tcx>(state: &mut CompileState<'a, 'tcx>) { if i.attrs.iter().any(|attr| attr.name() == "test") { let did = self.0.hir.body_owner_def_id(body_id); println!("running test: {}", self.0.def_path_debug_str(did)); - miri::eval_main(self.0, did, None); + miri::eval_main(self.0, did, None, /*validate*/true); self.1.session.abort_if_errors(); } } @@ -106,7 +106,7 @@ fn after_analysis<'a, 'tcx>(state: &mut CompileState<'a, 'tcx>) { state.hir_crate.unwrap().visit_all_item_likes(&mut Visitor(tcx, state)); } else if let Some((entry_node_id, _, _)) = *state.session.entry_fn.borrow() { let entry_def_id = tcx.hir.local_def_id(entry_node_id); - miri::eval_main(tcx, entry_def_id, None); + miri::eval_main(tcx, entry_def_id, None, /*validate*/true); state.session.abort_if_errors(); } else { From 9a1dd865c1d91d6ad8561ba16209998388d98309 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 14 Oct 2018 11:06:36 +0200 Subject: [PATCH 0261/3747] whitelist Windows Mutex --- src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/lib.rs b/src/lib.rs index d52fd0028039d..0bebe40d529af 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -265,6 +265,7 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { const WHITELIST: &[&str] = &[ // Uses mem::uninitialized "std::ptr::read", + "std::sys::windows::mutex::Mutex::", ]; for frame in ecx.stack().iter() .rev().take(3) From 88ec62640e15c2227328266790f309b198e21071 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 14 Oct 2018 11:45:56 +0200 Subject: [PATCH 0262/3747] make rustc-tests a binary in the main project --- .travis.yml | 5 - Cargo.toml | 7 + rustc_tests/Cargo.lock | 241 ------------------ rustc_tests/Cargo.toml | 7 - .../main.rs => src/bin/miri-rustc-tests.rs | 0 5 files changed, 7 insertions(+), 253 deletions(-) delete mode 100644 rustc_tests/Cargo.lock delete mode 100644 rustc_tests/Cargo.toml rename rustc_tests/src/main.rs => src/bin/miri-rustc-tests.rs (100%) diff --git a/.travis.yml b/.travis.yml index 137e612598819..9b4f75ab29cf6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -39,11 +39,6 @@ script: cargo build --release --all-features && cargo test --release --all-features && cargo install --all-features --force --path . -- | - # test that the rustc_tests binary compiles - cd rustc_tests && - cargo build --release && - cd .. - | # get ourselves a MIR-full libstd xargo/build.sh && diff --git a/Cargo.toml b/Cargo.toml index f7caa4d1c2c89..f79609c76394a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,6 +25,12 @@ test = false # we have no unit tests doctest = false # and no doc tests required-features = ["cargo_miri"] +[[bin]] +name = "miri-rustc-tests" +test = false # we have no unit tests +doctest = false # and no doc tests +required-features = ["rustc_tests"] + [dependencies] byteorder = { version = "1.1", features = ["i128"]} cargo_metadata = { version = "0.6", optional = true } @@ -36,6 +42,7 @@ vergen = "3" [features] cargo_miri = ["cargo_metadata"] +rustc_tests = [] [dev-dependencies] compiletest_rs = { version = "0.3.12", features = ["tmp"] } diff --git a/rustc_tests/Cargo.lock b/rustc_tests/Cargo.lock deleted file mode 100644 index c206ecd644928..0000000000000 --- a/rustc_tests/Cargo.lock +++ /dev/null @@ -1,241 +0,0 @@ -[[package]] -name = "aho-corasick" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "memchr 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "atty" -version = "0.2.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.30 (registry+https://github.com/rust-lang/crates.io-index)", - "termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.4 (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 = "cfg-if" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "env_logger" -version = "0.5.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "atty 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", - "humantime 1.1.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)", - "termcolor 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "humantime" -version = "1.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "quick-error 1.2.2 (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" - -[[package]] -name = "libc" -version = "0.2.30" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "log" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "memchr" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.30 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "memchr" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.30 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "miri" -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)", - "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "quick-error" -version = "1.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "redox_syscall" -version = "0.1.40" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "redox_termios" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "regex" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "aho-corasick 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", - "memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "regex-syntax 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "thread_local 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "regex-syntax" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "ucd-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rustc_tests" -version = "0.1.0" -dependencies = [ - "miri 0.1.0", -] - -[[package]] -name = "termcolor" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "wincolor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "termion" -version = "1.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.30 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_termios 0.1.1 (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" -dependencies = [ - "lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "ucd-util" -version = "0.1.1" -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" -dependencies = [ - "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "utf8-ranges" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "void" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "winapi" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "wincolor" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "winapi 0.3.4 (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 atty 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "2fc4a1aa4c24c0718a250f0681885c1af91419d242f29eb8f2ab28502d80dbd1" -"checksum byteorder 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ff81738b726f5d099632ceaffe7fb65b90212e8dce59d518729e7e8634032d3d" -"checksum cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d4c819a1287eb618df47cc647173c5c4c66ba19d888a6e50d605672aed3140de" -"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 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" -"checksum memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "796fba70e76612589ed2ce7f45282f5af869e0fdd7cc6199fa1aa1f1d591ba9d" -"checksum quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9274b940887ce9addde99c4eee6b5c44cc494b182b97e73dc8ffdcb3397fd3f0" -"checksum redox_syscall 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "c214e91d3ecf43e9a4e41e578973adeb14b474f2bee858742d127af75a0112b1" -"checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76" -"checksum regex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "75ecf88252dce580404a22444fc7d626c01815debba56a7f4f536772a5ff19d3" -"checksum regex-syntax 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8f1ac0f60d675cc6cf13a20ec076568254472551051ad5dd050364d70671bf6b" -"checksum termcolor 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "adc4587ead41bf016f11af03e55a624c06568b5a19db4e90fde573d805074f83" -"checksum termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "689a3bdfaab439fd92bc87df5c4c78417d3cbe537487274e9b0b2dce76e92096" -"checksum thread_local 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "1697c4b57aeeb7a536b647165a2825faddffb1d3bad386d507709bd51a90bb14" -"checksum ucd-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "fd2be2d6639d0f8fe6cdda291ad456e23629558d466e2789d2c3e9892bda285d" -"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.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "04e3bd221fcbe8a271359c04f21a76db7d0c6028862d1bb5512d85e1e2eb5bb3" -"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" -"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" -"checksum wincolor 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "eeb06499a3a4d44302791052df005d5232b927ed1a9658146d842165c4de7767" diff --git a/rustc_tests/Cargo.toml b/rustc_tests/Cargo.toml deleted file mode 100644 index 736f0629768f2..0000000000000 --- a/rustc_tests/Cargo.toml +++ /dev/null @@ -1,7 +0,0 @@ -[package] -name = "rustc_tests" -version = "0.1.0" -authors = ["Oliver Schneider "] - -[dependencies] -miri = { path = ".." } diff --git a/rustc_tests/src/main.rs b/src/bin/miri-rustc-tests.rs similarity index 100% rename from rustc_tests/src/main.rs rename to src/bin/miri-rustc-tests.rs From 4faf8fad106bbcff03a22b64cba57b8c09c4bb6e Mon Sep 17 00:00:00 2001 From: Andrew Poelstra Date: Mon, 15 Oct 2018 18:38:07 +0000 Subject: [PATCH 0263/3747] cargo-miri: support running unit tests for libraries as well as test binaries --- src/bin/cargo-miri.rs | 46 ++++++++++++++++++++++++++++--------------- 1 file changed, 30 insertions(+), 16 deletions(-) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 95ce9cc7ecb5f..4cd2090133307 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -97,24 +97,38 @@ fn main() { let kind = target.kind.get(0).expect( "badly formatted cargo metadata: target::kind is an empty array", ); - if test && kind == "test" { - if let Err(code) = process( - vec!["--test".to_string(), target.name].into_iter().chain( - args, - ), - ) - { - std::process::exit(code); + match (test, &kind[..]) { + (true, "test") => { + if let Err(code) = process( + vec!["--test".to_string(), target.name].into_iter().chain( + args, + ), + ) + { + std::process::exit(code); + } } - } else if !test && kind == "bin" { - if let Err(code) = process( - vec!["--bin".to_string(), target.name].into_iter().chain( - args, - ), - ) - { - std::process::exit(code); + (true, "lib") => { + if let Err(code) = process( + vec!["--".to_string(), "--test".to_string()].into_iter().chain( + args, + ), + ) + { + std::process::exit(code); + } } + (false, "bin") => { + if let Err(code) = process( + vec!["--bin".to_string(), target.name].into_iter().chain( + args, + ), + ) + { + std::process::exit(code); + } + } + _ => {} } } } else { From 37de74f01572ece6042a73139a95ff050cb7713a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 16 Oct 2018 17:57:03 +0200 Subject: [PATCH 0264/3747] test with opt levels 0 and 1 --- tests/compiletest.rs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/tests/compiletest.rs b/tests/compiletest.rs index 82a2144a337de..b240fb31d2223 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -104,7 +104,11 @@ fn miri_pass(sysroot: &Path, path: &str, target: &str, host: &str, need_fullmir: flags.push("-Zmiri-start-fn".to_owned()); } if opt { - flags.push("-Zmir-opt-level=3".to_owned()); + // FIXME: Using level 1 (instead of 3) for now, as the optimizer is pretty broken + // and crashes... + // Level 0 and 1 are not the same, so this still gives us *some* coverage. + // See https://github.com/rust-lang/rust/issues/50411 + flags.push("-Zmir-opt-level=1".to_owned()); } else { flags.push("-Zmir-opt-level=0".to_owned()); // For now, only validate without optimizations. Inlining breaks validation. @@ -187,9 +191,7 @@ fn test() { // uses `libtest` which runs jobs in parallel. run_pass_miri(false); - // FIXME: Disabled for now, as the optimizer is pretty broken and crashes... - // See https://github.com/rust-lang/rust/issues/50411 - //run_pass_miri(true); + run_pass_miri(true); compile_fail_miri(); } From f5e3cdbf03dfe27b5e64a71cf58f9f096bd25b93 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 15 Oct 2018 09:21:29 +0200 Subject: [PATCH 0265/3747] explain our flags in the README --- README.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/README.md b/README.md index 314e27de0aa23..e59accaea1b9b 100644 --- a/README.md +++ b/README.md @@ -55,6 +55,14 @@ miri` to run your project, if it is a bin project, or run `MIRI_SYSROOT=~/.xargo/HOST cargo +nightly miri test` to run all tests in your project through Miri. +## Miri `-Z` flags + +Miri adds some extra `-Z` flags to control its behavior: + +* `-Zmiri-start-fn`: This makes interpretation start with `lang_start` (defined + in libstd) instead of starting with `main`. Requires full MIR! +* `-Zmiri-disable-validation` disables enforcing the validity invariant. + ## Development and Debugging Since the heart of Miri (the main interpreter engine) lives in rustc, working on From b84f7e20293cd1cebee011dbb485583c79f7ede3 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 16 Oct 2018 11:21:38 +0200 Subject: [PATCH 0266/3747] add Borrow tag to pointers; remove old locking code --- src/fn_call.rs | 28 ++++++------- src/helpers.rs | 4 +- src/intrinsic.rs | 10 ++--- src/lib.rs | 61 ++++++++++++++------------- src/locks.rs | 94 ------------------------------------------ src/operator.rs | 47 ++++++++++++--------- src/stacked_borrows.rs | 36 ++++++++++++++++ src/tls.rs | 10 ++--- 8 files changed, 119 insertions(+), 171 deletions(-) delete mode 100644 src/locks.rs create mode 100644 src/stacked_borrows.rs diff --git a/src/fn_call.rs b/src/fn_call.rs index 812df49b0b8fa..280cc2bdea589 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -14,8 +14,8 @@ pub trait EvalContextExt<'tcx, 'mir> { fn emulate_foreign_item( &mut self, def_id: DefId, - args: &[OpTy<'tcx>], - dest: PlaceTy<'tcx>, + args: &[OpTy<'tcx, Borrow>], + dest: PlaceTy<'tcx, Borrow>, ret: mir::BasicBlock, ) -> EvalResult<'tcx>; @@ -28,28 +28,28 @@ pub trait EvalContextExt<'tcx, 'mir> { fn emulate_missing_fn( &mut self, path: String, - args: &[OpTy<'tcx>], - dest: Option>, + args: &[OpTy<'tcx, Borrow>], + dest: Option>, ret: Option, ) -> EvalResult<'tcx>; fn find_fn( &mut self, instance: ty::Instance<'tcx>, - args: &[OpTy<'tcx>], - dest: Option>, + args: &[OpTy<'tcx, Borrow>], + dest: Option>, ret: Option, ) -> EvalResult<'tcx, Option<&'mir mir::Mir<'tcx>>>; - fn write_null(&mut self, dest: PlaceTy<'tcx>) -> EvalResult<'tcx>; + fn write_null(&mut self, dest: PlaceTy<'tcx, Borrow>) -> EvalResult<'tcx>; } impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for EvalContext<'a, 'mir, 'tcx, super::Evaluator<'tcx>> { fn find_fn( &mut self, instance: ty::Instance<'tcx>, - args: &[OpTy<'tcx>], - dest: Option>, + args: &[OpTy<'tcx, Borrow>], + dest: Option>, ret: Option, ) -> EvalResult<'tcx, Option<&'mir mir::Mir<'tcx>>> { trace!("eval_fn_call: {:#?}, {:?}", instance, dest.map(|place| *place)); @@ -108,8 +108,8 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for EvalContext<'a, ' fn emulate_foreign_item( &mut self, def_id: DefId, - args: &[OpTy<'tcx>], - dest: PlaceTy<'tcx>, + args: &[OpTy<'tcx, Borrow>], + dest: PlaceTy<'tcx, Borrow>, ret: mir::BasicBlock, ) -> EvalResult<'tcx> { let attrs = self.tcx.get_attrs(def_id); @@ -675,8 +675,8 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for EvalContext<'a, ' fn emulate_missing_fn( &mut self, path: String, - _args: &[OpTy<'tcx>], - dest: Option>, + _args: &[OpTy<'tcx, Borrow>], + dest: Option>, ret: Option, ) -> EvalResult<'tcx> { // In some cases in non-MIR libstd-mode, not having a destination is legit. Handle these early. @@ -724,7 +724,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for EvalContext<'a, ' Ok(()) } - fn write_null(&mut self, dest: PlaceTy<'tcx>) -> EvalResult<'tcx> { + fn write_null(&mut self, dest: PlaceTy<'tcx, Borrow>) -> EvalResult<'tcx> { self.write_scalar(Scalar::from_int(0, dest.layout.size), dest) } } diff --git a/src/helpers.rs b/src/helpers.rs index 27b2109d18a16..de787145e22c7 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -7,7 +7,7 @@ pub trait FalibleScalarExt { fn to_bytes(self) -> EvalResult<'static, u128>; } -impl FalibleScalarExt for Scalar { +impl FalibleScalarExt for Scalar { fn to_bytes(self) -> EvalResult<'static, u128> { match self { Scalar::Bits { bits, size } => { @@ -19,7 +19,7 @@ impl FalibleScalarExt for Scalar { } } -impl FalibleScalarExt for ScalarMaybeUndef { +impl FalibleScalarExt for ScalarMaybeUndef { fn to_bytes(self) -> EvalResult<'static, u128> { self.not_undef()?.to_bytes() } diff --git a/src/intrinsic.rs b/src/intrinsic.rs index 19c4f04f4826e..11c0bd7907c15 100644 --- a/src/intrinsic.rs +++ b/src/intrinsic.rs @@ -6,7 +6,7 @@ use rustc::mir::interpret::{EvalResult, PointerArithmetic}; use rustc_mir::interpret::{EvalContext, PlaceTy, OpTy}; use super::{ - Value, Scalar, ScalarMaybeUndef, + Value, Scalar, ScalarMaybeUndef, Borrow, FalibleScalarExt, OperatorEvalContextExt }; @@ -14,8 +14,8 @@ pub trait EvalContextExt<'tcx> { fn call_intrinsic( &mut self, instance: ty::Instance<'tcx>, - args: &[OpTy<'tcx>], - dest: PlaceTy<'tcx>, + args: &[OpTy<'tcx, Borrow>], + dest: PlaceTy<'tcx, Borrow>, ) -> EvalResult<'tcx>; } @@ -23,8 +23,8 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: fn call_intrinsic( &mut self, instance: ty::Instance<'tcx>, - args: &[OpTy<'tcx>], - dest: PlaceTy<'tcx>, + args: &[OpTy<'tcx, Borrow>], + dest: PlaceTy<'tcx, Borrow>, ) -> EvalResult<'tcx> { if self.emulate_intrinsic(instance, args, dest)? { return Ok(()); diff --git a/src/lib.rs b/src/lib.rs index 0bebe40d529af..9ac703e2675b1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -21,11 +21,9 @@ use rustc::ty::layout::{TyLayout, LayoutOf, Size}; use rustc::hir::def_id::DefId; use rustc::mir; -use syntax::ast::Mutability; use syntax::attr; -pub use rustc::mir::interpret::*; pub use rustc_mir::interpret::*; pub use rustc_mir::interpret::{self, AllocMap}; // resolve ambiguity @@ -34,9 +32,9 @@ mod operator; mod intrinsic; mod helpers; mod tls; -mod locks; mod range_map; mod mono_hash_map; +mod stacked_borrows; use fn_call::EvalContextExt as MissingFnsEvalContextExt; use operator::EvalContextExt as OperatorEvalContextExt; @@ -45,6 +43,7 @@ use tls::{EvalContextExt as TlsEvalContextExt, TlsData}; use range_map::RangeMap; use helpers::FalibleScalarExt; use mono_hash_map::MonoHashMap; +use stacked_borrows::Borrow; pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( tcx: TyCtxt<'a, 'tcx, 'tcx>, @@ -56,7 +55,6 @@ pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( tcx.at(syntax::source_map::DUMMY_SP), ty::ParamEnv::reveal_all(), Evaluator::new(validate), - Default::default(), ); let main_instance = ty::Instance::mono(ecx.tcx.tcx, main_id); @@ -118,9 +116,9 @@ pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( let foo = ecx.memory.allocate_static_bytes(b"foo\0"); let foo_ty = ecx.tcx.mk_imm_ptr(ecx.tcx.types.u8); let foo_layout = ecx.layout_of(foo_ty)?; - let foo_place = ecx.allocate(foo_layout, MemoryKind::Stack)?; // will be interned in just a second + let foo_place = ecx.allocate(foo_layout, MiriMemoryKind::Env.into())?; ecx.write_scalar(Scalar::Ptr(foo), foo_place.into())?; - ecx.memory.intern_static(foo_place.to_ptr()?.alloc_id, Mutability::Immutable)?; + ecx.memory.mark_immutable(foo_place.to_ptr()?.alloc_id)?; ecx.write_scalar(foo_place.ptr, dest)?; assert!(args.next().is_none(), "start lang item has more arguments than expected"); @@ -227,7 +225,7 @@ impl Into> for MiriMemoryKind { pub struct Evaluator<'tcx> { /// Environment variables set by `setenv` /// Miri does not expose env vars from the host to the emulated program - pub(crate) env_vars: HashMap, Pointer>, + pub(crate) env_vars: HashMap, Pointer>, /// TLS state pub(crate) tls: TlsData<'tcx>, @@ -247,11 +245,11 @@ impl<'tcx> Evaluator<'tcx> { } impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { - type MemoryData = (); type MemoryKinds = MiriMemoryKind; - type PointerTag = (); // still WIP + type AllocExtra = (); + type PointerTag = Borrow; - type MemoryMap = MonoHashMap, Allocation<()>)>; + type MemoryMap = MonoHashMap, Allocation)>; const STATIC_KIND: Option = Some(MiriMemoryKind::MutStatic); @@ -282,8 +280,8 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { fn find_fn( ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, instance: ty::Instance<'tcx>, - args: &[OpTy<'tcx>], - dest: Option>, + args: &[OpTy<'tcx, Borrow>], + dest: Option>, ret: Option, ) -> EvalResult<'tcx, Option<&'mir mir::Mir<'tcx>>> { ecx.find_fn(instance, args, dest, ret) @@ -292,8 +290,8 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { fn call_intrinsic( ecx: &mut rustc_mir::interpret::EvalContext<'a, 'mir, 'tcx, Self>, instance: ty::Instance<'tcx>, - args: &[OpTy<'tcx>], - dest: PlaceTy<'tcx>, + args: &[OpTy<'tcx, Borrow>], + dest: PlaceTy<'tcx, Borrow>, ) -> EvalResult<'tcx> { ecx.call_intrinsic(instance, args, dest) } @@ -301,17 +299,17 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { fn ptr_op( ecx: &rustc_mir::interpret::EvalContext<'a, 'mir, 'tcx, Self>, bin_op: mir::BinOp, - left: Scalar, + left: Scalar, left_layout: TyLayout<'tcx>, - right: Scalar, + right: Scalar, right_layout: TyLayout<'tcx>, - ) -> EvalResult<'tcx, (Scalar, bool)> { + ) -> EvalResult<'tcx, (Scalar, bool)> { ecx.ptr_op(bin_op, left, left_layout, right, right_layout) } fn box_alloc( ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, - dest: PlaceTy<'tcx>, + dest: PlaceTy<'tcx, Borrow>, ) -> EvalResult<'tcx> { trace!("box_alloc for {:?}", dest.layout.ty); // Call the `exchange_malloc` lang item @@ -351,7 +349,7 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { fn find_foreign_static( tcx: TyCtxtAt<'a, 'tcx, 'tcx>, def_id: DefId, - ) -> EvalResult<'tcx, Cow<'tcx, Allocation>> { + ) -> EvalResult<'tcx, Cow<'tcx, Allocation>> { let attrs = tcx.get_attrs(def_id); let link_name = match attr::first_attr_value_str_by_name(&attrs, "link_name") { Some(name) => name.as_str(), @@ -371,16 +369,6 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { Ok(Cow::Owned(alloc)) } - fn validation_op( - _ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, - _op: ::rustc::mir::ValidationOp, - _operand: &::rustc::mir::ValidationOperand<'tcx, ::rustc::mir::Place<'tcx>>, - ) -> EvalResult<'tcx> { - // FIXME: prevent this from ICEing - //ecx.validation_op(op, operand) - Ok(()) - } - fn before_terminator(_ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>) -> EvalResult<'tcx> { // We are not interested in detecting loops @@ -389,8 +377,19 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { fn static_with_default_tag( alloc: &'_ Allocation - ) -> Cow<'_, Allocation> { - let alloc = alloc.clone(); + ) -> Cow<'_, Allocation> { + let alloc: Allocation = Allocation { + bytes: alloc.bytes.clone(), + relocations: Relocations::from_presorted( + alloc.relocations.iter() + .map(|&(offset, ((), alloc))| (offset, (Borrow::default(), alloc))) + .collect() + ), + undef_mask: alloc.undef_mask.clone(), + align: alloc.align, + mutability: alloc.mutability, + extra: Self::AllocExtra::default(), + }; Cow::Owned(alloc) } } diff --git a/src/locks.rs b/src/locks.rs deleted file mode 100644 index a87ff6367e3ad..0000000000000 --- a/src/locks.rs +++ /dev/null @@ -1,94 +0,0 @@ -#![allow(unused)] - -use super::*; -use rustc::middle::region; -use rustc::ty::layout::Size; - -//////////////////////////////////////////////////////////////////////////////// -// Locks -//////////////////////////////////////////////////////////////////////////////// - -// Just some dummy to keep this compiling; I think some of this will be useful later -type AbsPlace<'tcx> = ::rustc::ty::Ty<'tcx>; - -/// Information about a lock that is currently held. -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct LockInfo<'tcx> { - /// Stores for which lifetimes (of the original write lock) we got - /// which suspensions. - suspended: HashMap, Vec>, - /// The current state of the lock that's actually effective. - pub active: Lock, -} - -/// Write locks are identified by a stack frame and an "abstract" (untyped) place. -/// It may be tempting to use the lifetime as identifier, but that does not work -/// for two reasons: -/// * First of all, due to subtyping, the same lock may be referred to with different -/// lifetimes. -/// * Secondly, different write locks may actually have the same lifetime. See `test2` -/// in `run-pass/many_shr_bor.rs`. -/// The Id is "captured" when the lock is first suspended; at that point, the borrow checker -/// considers the path frozen and hence the Id remains stable. -#[derive(Clone, Debug, PartialEq, Eq, Hash)] -pub struct WriteLockId<'tcx> { - frame: usize, - path: AbsPlace<'tcx>, -} - - -use rustc::mir::interpret::Lock::*; -use rustc::mir::interpret::Lock; - -impl<'tcx> Default for LockInfo<'tcx> { - fn default() -> Self { - LockInfo::new(NoLock) - } -} - -impl<'tcx> LockInfo<'tcx> { - fn new(lock: Lock) -> LockInfo<'tcx> { - LockInfo { - suspended: HashMap::new(), - active: lock, - } - } - - fn access_permitted(&self, frame: Option, access: AccessKind) -> bool { - use super::AccessKind::*; - match (&self.active, access) { - (&NoLock, _) => true, - (&ReadLock(ref lfts), Read) => { - assert!(!lfts.is_empty(), "Someone left an empty read lock behind."); - // Read access to read-locked region is okay, no matter who's holding the read lock. - true - } - (&WriteLock(ref lft), _) => { - // All access is okay if we are the ones holding it - Some(lft.frame) == frame - } - _ => false, // Nothing else is okay. - } - } -} - -impl<'tcx> RangeMap> { - pub fn check( - &self, - frame: Option, - offset: u64, - len: u64, - access: AccessKind, - ) -> Result<(), LockInfo<'tcx>> { - if len == 0 { - return Ok(()); - } - for lock in self.iter(offset, len) { - // Check if the lock is in conflict with the access. - if !lock.access_permitted(frame, access) { - return Err(lock.clone()); - } - } - Ok(()) - } -} diff --git a/src/operator.rs b/src/operator.rs index 4662a162679e3..dd79f293134f1 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -7,44 +7,44 @@ pub trait EvalContextExt<'tcx> { fn ptr_op( &self, bin_op: mir::BinOp, - left: Scalar, + left: Scalar, left_layout: TyLayout<'tcx>, - right: Scalar, + right: Scalar, right_layout: TyLayout<'tcx>, - ) -> EvalResult<'tcx, (Scalar, bool)>; + ) -> EvalResult<'tcx, (Scalar, bool)>; fn ptr_int_arithmetic( &self, bin_op: mir::BinOp, - left: Pointer, + left: Pointer, right: u128, signed: bool, - ) -> EvalResult<'tcx, (Scalar, bool)>; + ) -> EvalResult<'tcx, (Scalar, bool)>; fn ptr_eq( &self, - left: Scalar, - right: Scalar, + left: Scalar, + right: Scalar, size: Size, ) -> EvalResult<'tcx, bool>; fn pointer_offset_inbounds( &self, - ptr: Scalar, + ptr: Scalar, pointee_ty: Ty<'tcx>, offset: i64, - ) -> EvalResult<'tcx, Scalar>; + ) -> EvalResult<'tcx, Scalar>; } impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super::Evaluator<'tcx>> { fn ptr_op( &self, bin_op: mir::BinOp, - left: Scalar, + left: Scalar, left_layout: TyLayout<'tcx>, - right: Scalar, + right: Scalar, right_layout: TyLayout<'tcx>, - ) -> EvalResult<'tcx, (Scalar, bool)> { + ) -> EvalResult<'tcx, (Scalar, bool)> { use rustc::mir::BinOp::*; trace!("ptr_op: {:?} {:?} {:?}", left, bin_op, right); @@ -124,8 +124,8 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: fn ptr_eq( &self, - left: Scalar, - right: Scalar, + left: Scalar, + right: Scalar, size: Size, ) -> EvalResult<'tcx, bool> { Ok(match (left, right) { @@ -203,13 +203,13 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: fn ptr_int_arithmetic( &self, bin_op: mir::BinOp, - left: Pointer, + left: Pointer, right: u128, signed: bool, - ) -> EvalResult<'tcx, (Scalar, bool)> { + ) -> EvalResult<'tcx, (Scalar, bool)> { use rustc::mir::BinOp::*; - fn map_to_primval((res, over): (Pointer, bool)) -> (Scalar, bool) { + fn map_to_primval((res, over): (Pointer, bool)) -> (Scalar, bool) { (Scalar::Ptr(res), over) } @@ -237,7 +237,14 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: if right & base_mask == base_mask { // Case 1: The base address bits are all preserved, i.e., right is all-1 there let offset = (left.offset.bytes() as u128 & right) as u64; - (Scalar::Ptr(Pointer::new(left.alloc_id, Size::from_bytes(offset))), false) + ( + Scalar::Ptr(Pointer::new_with_tag( + left.alloc_id, + Size::from_bytes(offset), + left.tag, + )), + 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() as u128) & right, size: ptr_size }, false) @@ -277,10 +284,10 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: /// allocation. fn pointer_offset_inbounds( &self, - ptr: Scalar, + ptr: Scalar, pointee_ty: Ty<'tcx>, offset: i64, - ) -> EvalResult<'tcx, Scalar> { + ) -> EvalResult<'tcx, Scalar> { // FIXME: assuming here that type size is < i64::max_value() let pointee_size = self.layout_of(pointee_ty)?.size.bytes() as i64; let offset = offset.checked_mul(pointee_size).ok_or_else(|| EvalErrorKind::Overflow(mir::BinOp::Mul))?; diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs new file mode 100644 index 0000000000000..dd9f1b370890d --- /dev/null +++ b/src/stacked_borrows.rs @@ -0,0 +1,36 @@ +use super::RangeMap; + +pub type Timestamp = u64; + +/// Information about a potentially mutable borrow +#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] +pub enum Mut { + /// A unique, mutable reference + Uniq(Timestamp), + /// Any raw pointer, or a shared borrow with interior mutability + Raw, +} + +/// Information about any kind of borrow +#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] +pub enum Borrow { + /// A mutable borrow, a raw pointer, or a shared borrow with interior mutability + Mut(Mut), + /// A shared borrow without interior mutability + Frz(Timestamp) +} + +/// An item in the borrow stack +#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] +pub enum BorStackItem { + /// Defines which references are permitted to mutate *if* the location is not frozen + Mut(Mut), + /// A barrier, tracking the function it belongs to by its index on the call stack + FnBarrier(usize) +} + +impl Default for Borrow { + fn default() -> Self { + Borrow::Mut(Mut::Raw) + } +} diff --git a/src/tls.rs b/src/tls.rs index c04f7a9c35020..c5d119ec7f5bf 100644 --- a/src/tls.rs +++ b/src/tls.rs @@ -5,14 +5,14 @@ use rustc::{ty, ty::layout::HasDataLayout, mir}; use super::{ EvalResult, EvalErrorKind, StackPopCleanup, EvalContext, Evaluator, - MPlaceTy, Scalar, + MPlaceTy, Scalar, Borrow, }; pub type TlsKey = u128; #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub struct TlsEntry<'tcx> { - pub(crate) data: Scalar, // Will eventually become a map from thread IDs to `Scalar`s, if we ever support more than one thread. + pub(crate) data: Scalar, // Will eventually become a map from thread IDs to `Scalar`s, if we ever support more than one thread. pub(crate) dtor: Option>, } @@ -67,7 +67,7 @@ impl<'tcx> TlsData<'tcx> { } } - pub fn load_tls(&mut self, key: TlsKey) -> EvalResult<'tcx, Scalar> { + pub fn load_tls(&mut self, key: TlsKey) -> EvalResult<'tcx, Scalar> { match self.keys.get(&key) { Some(&TlsEntry { data, .. }) => { trace!("TLS key {} loaded: {:?}", key, data); @@ -77,7 +77,7 @@ impl<'tcx> TlsData<'tcx> { } } - pub fn store_tls(&mut self, key: TlsKey, new_data: Scalar) -> EvalResult<'tcx> { + pub fn store_tls(&mut self, key: TlsKey, new_data: Scalar) -> EvalResult<'tcx> { match self.keys.get_mut(&key) { Some(&mut TlsEntry { ref mut data, .. }) => { trace!("TLS key {} stored: {:?}", key, new_data); @@ -110,7 +110,7 @@ impl<'tcx> TlsData<'tcx> { &mut self, key: Option, cx: impl HasDataLayout, - ) -> Option<(ty::Instance<'tcx>, Scalar, TlsKey)> { + ) -> Option<(ty::Instance<'tcx>, Scalar, TlsKey)> { use std::collections::Bound::*; let thread_local = &mut self.keys; From 348f782085ea60cbda5a1bd0beb8cd62b0ebd142 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 16 Oct 2018 12:44:04 +0200 Subject: [PATCH 0267/3747] add env var emulation test, and fix it complaining about leaks --- src/lib.rs | 11 +++++++++++ tests/run-pass/env.rs | 7 +++++++ 2 files changed, 18 insertions(+) create mode 100644 tests/run-pass/env.rs diff --git a/src/lib.rs b/src/lib.rs index 9ac703e2675b1..47eaee6dfac32 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -215,11 +215,22 @@ pub enum MiriMemoryKind { } impl Into> for MiriMemoryKind { + #[inline(always)] fn into(self) -> MemoryKind { MemoryKind::Machine(self) } } +impl MayLeak for MiriMemoryKind { + #[inline(always)] + fn may_leak(self) -> bool { + use MiriMemoryKind::*; + match self { + Rust | C => false, + Env | MutStatic => true, + } + } +} #[derive(Clone, PartialEq, Eq)] pub struct Evaluator<'tcx> { diff --git a/tests/run-pass/env.rs b/tests/run-pass/env.rs new file mode 100644 index 0000000000000..c0bf883daf9ce --- /dev/null +++ b/tests/run-pass/env.rs @@ -0,0 +1,7 @@ +use std::env; + +fn main() { + assert_eq!(env::var("MIRI_TEST"), Err(env::VarError::NotPresent)); + env::set_var("MIRI_TEST", "the answer"); + assert_eq!(env::var("MIRI_TEST"), Ok("the answer".to_owned())); +} From 66b4bb7cf2e7136ca0a31d04a2abe1754e89a5b6 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 16 Oct 2018 18:01:50 +0200 Subject: [PATCH 0268/3747] stacked borrows: track refs and derefs --- src/fn_call.rs | 2 +- src/intrinsic.rs | 5 +- src/lib.rs | 49 ++++++++- src/operator.rs | 2 +- src/range_map.rs | 150 +++++++++++++++++--------- src/stacked_borrows.rs | 238 ++++++++++++++++++++++++++++++++++++++++- src/tls.rs | 8 +- 7 files changed, 388 insertions(+), 66 deletions(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index 280cc2bdea589..1613da4a487af 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -44,7 +44,7 @@ pub trait EvalContextExt<'tcx, 'mir> { fn write_null(&mut self, dest: PlaceTy<'tcx, Borrow>) -> EvalResult<'tcx>; } -impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for EvalContext<'a, 'mir, 'tcx, super::Evaluator<'tcx>> { +impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalContext<'a, 'mir, 'tcx> { fn find_fn( &mut self, instance: ty::Instance<'tcx>, diff --git a/src/intrinsic.rs b/src/intrinsic.rs index 11c0bd7907c15..719bc93939589 100644 --- a/src/intrinsic.rs +++ b/src/intrinsic.rs @@ -3,10 +3,9 @@ use rustc::ty::layout::{self, LayoutOf, Size}; use rustc::ty; use rustc::mir::interpret::{EvalResult, PointerArithmetic}; -use rustc_mir::interpret::{EvalContext, PlaceTy, OpTy}; use super::{ - Value, Scalar, ScalarMaybeUndef, Borrow, + PlaceTy, OpTy, Value, Scalar, ScalarMaybeUndef, Borrow, FalibleScalarExt, OperatorEvalContextExt }; @@ -19,7 +18,7 @@ pub trait EvalContextExt<'tcx> { ) -> EvalResult<'tcx>; } -impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super::Evaluator<'tcx>> { +impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, 'tcx> { fn call_intrinsic( &mut self, instance: ty::Instance<'tcx>, diff --git a/src/lib.rs b/src/lib.rs index 47eaee6dfac32..97b73e60692cd 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -16,7 +16,7 @@ extern crate syntax; use std::collections::HashMap; use std::borrow::Cow; -use rustc::ty::{self, TyCtxt, query::TyCtxtAt}; +use rustc::ty::{self, Ty, TyCtxt, query::TyCtxtAt}; use rustc::ty::layout::{TyLayout, LayoutOf, Size}; use rustc::hir::def_id::DefId; use rustc::mir; @@ -43,7 +43,7 @@ use tls::{EvalContextExt as TlsEvalContextExt, TlsData}; use range_map::RangeMap; use helpers::FalibleScalarExt; use mono_hash_map::MonoHashMap; -use stacked_borrows::Borrow; +use stacked_borrows::{EvalContextExt as StackedBorEvalContextExt, Borrow}; pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( tcx: TyCtxt<'a, 'tcx, 'tcx>, @@ -232,7 +232,6 @@ impl MayLeak for MiriMemoryKind { } } -#[derive(Clone, PartialEq, Eq)] pub struct Evaluator<'tcx> { /// Environment variables set by `setenv` /// Miri does not expose env vars from the host to the emulated program @@ -243,6 +242,9 @@ pub struct Evaluator<'tcx> { /// Whether to enforce the validity invariant pub(crate) validate: bool, + + /// Stacked Borrows state + pub(crate) stacked_borrows: stacked_borrows::State, } impl<'tcx> Evaluator<'tcx> { @@ -251,13 +253,18 @@ impl<'tcx> Evaluator<'tcx> { env_vars: HashMap::default(), tls: TlsData::default(), validate, + stacked_borrows: stacked_borrows::State::new(), } } } +#[allow(dead_code)] // FIXME https://github.com/rust-lang/rust/issues/47131 +type MiriEvalContext<'a, 'mir, 'tcx> = EvalContext<'a, 'mir, 'tcx, Evaluator<'tcx>>; + + impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { type MemoryKinds = MiriMemoryKind; - type AllocExtra = (); + type AllocExtra = stacked_borrows::Stacks; type PointerTag = Borrow; type MemoryMap = MonoHashMap, Allocation)>; @@ -288,6 +295,7 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { } /// Returns Ok() when the function was handled, fail otherwise + #[inline(always)] fn find_fn( ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, instance: ty::Instance<'tcx>, @@ -298,6 +306,7 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { ecx.find_fn(instance, args, dest, ret) } + #[inline(always)] fn call_intrinsic( ecx: &mut rustc_mir::interpret::EvalContext<'a, 'mir, 'tcx, Self>, instance: ty::Instance<'tcx>, @@ -307,6 +316,7 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { ecx.call_intrinsic(instance, args, dest) } + #[inline(always)] fn ptr_op( ecx: &rustc_mir::interpret::EvalContext<'a, 'mir, 'tcx, Self>, bin_op: mir::BinOp, @@ -380,6 +390,7 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { Ok(Cow::Owned(alloc)) } + #[inline(always)] fn before_terminator(_ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>) -> EvalResult<'tcx> { // We are not interested in detecting loops @@ -403,4 +414,34 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { }; Cow::Owned(alloc) } + + #[inline(always)] + fn tag_reference( + ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, + ptr: Pointer, + pointee_ty: Ty<'tcx>, + pointee_size: Size, + borrow_kind: mir::BorrowKind, + ) -> EvalResult<'tcx, Self::PointerTag> { + if !ecx.machine.validate { + // No tracking + Ok(Borrow::default()) + } else { + ecx.tag_reference(ptr, pointee_ty, pointee_size, borrow_kind) + } + } + + #[inline(always)] + fn tag_dereference( + ecx: &EvalContext<'a, 'mir, 'tcx, Self>, + ptr: Pointer, + ptr_ty: Ty<'tcx>, + ) -> EvalResult<'tcx, Self::PointerTag> { + if !ecx.machine.validate { + // No tracking + Ok(Borrow::default()) + } else { + ecx.tag_dereference(ptr, ptr_ty) + } + } } diff --git a/src/operator.rs b/src/operator.rs index dd79f293134f1..a11f8f34e7e86 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -36,7 +36,7 @@ pub trait EvalContextExt<'tcx> { ) -> EvalResult<'tcx, Scalar>; } -impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super::Evaluator<'tcx>> { +impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, 'tcx> { fn ptr_op( &self, bin_op: mir::BinOp, diff --git a/src/range_map.rs b/src/range_map.rs index e55534e36fd2e..1d9a38cb5ef53 100644 --- a/src/range_map.rs +++ b/src/range_map.rs @@ -9,11 +9,20 @@ use std::collections::BTreeMap; use std::ops; +use rustc::ty::layout::Size; + #[derive(Clone, Debug, PartialEq, Eq)] pub struct RangeMap { map: BTreeMap, } +impl Default for RangeMap { + #[inline(always)] + fn default() -> Self { + RangeMap::new() + } +} + // The derived `Ord` impl sorts first by the first field, then, if the fields are the same, // by the second field. // This is exactly what we need for our purposes, since a range query on a BTReeSet/BTreeMap will give us all @@ -21,14 +30,19 @@ pub struct RangeMap { // At the same time the `end` is irrelevant for the sorting and range searching, but used for the check. // This kind of search breaks, if `end < start`, so don't do that! #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Debug)] -pub struct Range { +struct Range { start: u64, end: u64, // Invariant: end > start } impl Range { + /// Compute a range of ranges that contains all ranges overlaping with [offset, offset+len) fn range(offset: u64, len: u64) -> ops::Range { - assert!(len > 0); + if len == 0 { + // We can produce an empty range, nothing overlaps with this. + let r = Range { start: 0, end: 1 }; + return r..r; + } // We select all elements that are within // the range given by the offset into the allocation and the length. // This is sound if all ranges that intersect with the argument range, are in the @@ -46,14 +60,20 @@ impl Range { left..right } - /// Tests if all of [offset, offset+len) are contained in this range. + /// Tests if any element of [offset, offset+len) is contained in this range. + #[inline(always)] fn overlaps(&self, offset: u64, len: u64) -> bool { - assert!(len > 0); - offset < self.end && offset + len >= self.start + if len == 0 { + // `offset` totally does not matter, we cannot overlap with an empty interval + false + } else { + offset < self.end && offset.checked_add(len).unwrap() >= self.start + } } } impl RangeMap { + #[inline(always)] pub fn new() -> RangeMap { RangeMap { map: BTreeMap::new() } } @@ -63,10 +83,9 @@ impl RangeMap { offset: u64, len: u64, ) -> impl Iterator + 'a { - assert!(len > 0); self.map.range(Range::range(offset, len)).filter_map( - move |(range, - data)| { + move |(range, data)| { + debug_assert!(len > 0); if range.overlaps(offset, len) { Some((range, data)) } else { @@ -76,8 +95,8 @@ impl RangeMap { ) } - pub fn iter<'a>(&'a self, offset: u64, len: u64) -> impl Iterator + 'a { - self.iter_with_range(offset, len).map(|(_, data)| data) + pub fn iter<'a>(&'a self, offset: Size, len: Size) -> impl Iterator + 'a { + self.iter_with_range(offset.bytes(), len.bytes()).map(|(_, data)| data) } fn split_entry_at(&mut self, offset: u64) @@ -114,28 +133,30 @@ impl RangeMap { } } - pub fn iter_mut_all<'a>(&'a mut self) -> impl Iterator + 'a { - self.map.values_mut() - } - /// Provide mutable iteration over everything in the given range. As a side-effect, /// this will split entries in the map that are only partially hit by the given range, /// to make sure that when they are mutated, the effect is constrained to the given range. + /// If there are gaps, leave them be. pub fn iter_mut_with_gaps<'a>( &'a mut self, - offset: u64, - len: u64, + offset: Size, + len: Size, ) -> impl Iterator + 'a where T: Clone, { - assert!(len > 0); - // Preparation: Split first and last entry as needed. - self.split_entry_at(offset); - self.split_entry_at(offset + len); + let offset = offset.bytes(); + let len = len.bytes(); + + if len > 0 { + // Preparation: Split first and last entry as needed. + self.split_entry_at(offset); + self.split_entry_at(offset + len); + } // Now we can provide a mutable iterator self.map.range_mut(Range::range(offset, len)).filter_map( move |(&range, data)| { + debug_assert!(len > 0); if range.overlaps(offset, len) { assert!( offset <= range.start && offset + len >= range.end, @@ -151,35 +172,41 @@ impl RangeMap { } /// Provide a mutable iterator over everything in the given range, with the same side-effects as - /// iter_mut_with_gaps. Furthermore, if there are gaps between ranges, fill them with the given default. + /// iter_mut_with_gaps. Furthermore, if there are gaps between ranges, fill them with the given default + /// before yielding them in the iterator. /// This is also how you insert. - pub fn iter_mut<'a>(&'a mut self, offset: u64, len: u64) -> impl Iterator + 'a + pub fn iter_mut<'a>(&'a mut self, offset: Size, len: Size) -> impl Iterator + 'a where T: Clone + Default, { - // Do a first iteration to collect the gaps - let mut gaps = Vec::new(); - let mut last_end = offset; - for (range, _) in self.iter_with_range(offset, len) { - if last_end < range.start { + if len.bytes() > 0 { + let offset = offset.bytes(); + let len = len.bytes(); + + // Do a first iteration to collect the gaps + let mut gaps = Vec::new(); + let mut last_end = offset; + for (range, _) in self.iter_with_range(offset, len) { + if last_end < range.start { + gaps.push(Range { + start: last_end, + end: range.start, + }); + } + last_end = range.end; + } + if last_end < offset + len { gaps.push(Range { start: last_end, - end: range.start, + end: offset + len, }); } - last_end = range.end; - } - if last_end < offset + len { - gaps.push(Range { - start: last_end, - end: offset + len, - }); - } - // Add default for all gaps - for gap in gaps { - let old = self.map.insert(gap, Default::default()); - assert!(old.is_none()); + // Add default for all gaps + for gap in gaps { + let old = self.map.insert(gap, Default::default()); + assert!(old.is_none()); + } } // Now provide mutable iteration @@ -208,10 +235,16 @@ mod tests { use super::*; /// Query the map at every offset in the range and collect the results. - fn to_vec(map: &RangeMap, offset: u64, len: u64) -> Vec { + fn to_vec(map: &RangeMap, offset: u64, len: u64, default: Option) -> Vec { (offset..offset + len) .into_iter() - .map(|i| *map.iter(i, 1).next().unwrap()) + .map(|i| map + .iter(Size::from_bytes(i), Size::from_bytes(1)) + .next() + .map(|&t| t) + .or(default) + .unwrap() + ) .collect() } @@ -219,34 +252,47 @@ mod tests { fn basic_insert() { let mut map = RangeMap::::new(); // Insert - for x in map.iter_mut(10, 1) { + for x in map.iter_mut(Size::from_bytes(10), Size::from_bytes(1)) { *x = 42; } // Check - assert_eq!(to_vec(&map, 10, 1), vec![42]); + assert_eq!(to_vec(&map, 10, 1, None), vec![42]); + + // Insert with size 0 + for x in map.iter_mut(Size::from_bytes(10), Size::from_bytes(0)) { + *x = 19; + } + for x in map.iter_mut(Size::from_bytes(11), Size::from_bytes(0)) { + *x = 19; + } + assert_eq!(to_vec(&map, 10, 2, Some(-1)), vec![42, -1]); } #[test] fn gaps() { let mut map = RangeMap::::new(); - for x in map.iter_mut(11, 1) { + for x in map.iter_mut(Size::from_bytes(11), Size::from_bytes(1)) { *x = 42; } - for x in map.iter_mut(15, 1) { - *x = 42; + for x in map.iter_mut(Size::from_bytes(15), Size::from_bytes(1)) { + *x = 43; } + assert_eq!( + to_vec(&map, 10, 10, Some(-1)), + vec![-1, 42, -1, -1, -1, 43, -1, -1, -1, -1] + ); // Now request a range that needs three gaps filled - for x in map.iter_mut(10, 10) { - if *x != 42 { + for x in map.iter_mut(Size::from_bytes(10), Size::from_bytes(10)) { + if *x < 42 { *x = 23; } } assert_eq!( - to_vec(&map, 10, 10), - vec![23, 42, 23, 23, 23, 42, 23, 23, 23, 23] + to_vec(&map, 10, 10, None), + vec![23, 42, 23, 23, 23, 43, 23, 23, 23, 23] ); - assert_eq!(to_vec(&map, 13, 5), vec![23, 23, 42, 23, 23]); + assert_eq!(to_vec(&map, 13, 5, None), vec![23, 23, 43, 23, 23]); } } diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index dd9f1b370890d..c3514efdbe71e 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -1,4 +1,12 @@ -use super::RangeMap; +use std::cell::RefCell; + +use rustc::ty::{Ty, layout::Size}; +use rustc::mir; + +use super::{ + RangeMap, EvalResult, + Pointer, +}; pub type Timestamp = u64; @@ -11,6 +19,24 @@ pub enum Mut { Raw, } +impl Mut { + #[inline(always)] + fn is_raw(self) -> bool { + match self { + Mut::Raw => true, + _ => false, + } + } + + #[inline(always)] + fn is_uniq(self) -> bool { + match self { + Mut::Uniq(_) => true, + _ => false, + } + } +} + /// Information about any kind of borrow #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] pub enum Borrow { @@ -20,6 +46,24 @@ pub enum Borrow { Frz(Timestamp) } +impl Borrow { + #[inline(always)] + fn is_mut(self) -> bool { + match self { + Borrow::Mut(_) => true, + _ => false, + } + } + + #[inline(always)] + fn is_uniq(self) -> bool { + match self { + Borrow::Mut(Mut::Uniq(_)) => true, + _ => false, + } + } +} + /// An item in the borrow stack #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] pub enum BorStackItem { @@ -34,3 +78,195 @@ impl Default for Borrow { Borrow::Mut(Mut::Raw) } } + +/// Extra global machine state +#[derive(Clone, Debug)] +pub struct State { + clock: Timestamp +} + +impl State { + pub fn new() -> State { + State { clock: 0 } + } +} + +/// Extra per-location state +#[derive(Clone, Debug)] +struct Stack { + borrows: Vec, // used as a stack + frozen_since: Option, +} + +impl Default for Stack { + fn default() -> Self { + Stack { + borrows: Vec::new(), + frozen_since: None, + } + } +} + +/// Extra per-allocation state +#[derive(Clone, Debug, Default)] +pub struct Stacks { + stacks: RefCell>, +} + +/// Core operations +impl<'tcx> Stack { + fn check(&self, bor: Borrow) -> bool { + match bor { + Borrow::Frz(acc_t) => + // Must be frozen at least as long as the `acc_t` says. + self.frozen_since.map_or(false, |loc_t| loc_t <= acc_t), + Borrow::Mut(acc_m) => + // Raw pointers are fine with frozen locations. This is important because &Cell is raw! + if self.frozen_since.is_some() { + acc_m.is_raw() + } else { + self.borrows.last().map_or(false, |&loc_itm| loc_itm == BorStackItem::Mut(acc_m)) + } + } + } + + /// Reactive `bor` for this stack. If `force_mut` is set, we want to aggressively + /// unfreeze this location (because we are about to push a `Uniq`). + fn reactivate(&mut self, bor: Borrow, force_mut: bool) -> EvalResult<'tcx> { + assert!(!force_mut || bor.is_mut()); // if `force_mut` is set, this must be a mutable borrow + // Do NOT change anything if `bor` is already active -- in particular, if + // it is a `Mut(Raw)` and we are frozen. + if !force_mut && self.check(bor) { + return Ok(()); + } + + let acc_m = match bor { + Borrow::Frz(_) => return err!(MachineError(format!("Location should be frozen but it is not"))), + Borrow::Mut(acc_m) => acc_m, + }; + // We definitely have to unfreeze this, even if we use the topmost item. + self.frozen_since = None; + // Pop until we see the one we are looking for. + while let Some(&itm) = self.borrows.last() { + match itm { + BorStackItem::FnBarrier(_) => { + return err!(MachineError(format!("Trying to reactivate a borrow that lives behind a barrier"))); + } + BorStackItem::Mut(loc_m) => { + if loc_m == acc_m { return Ok(()); } + self.borrows.pop(); + } + } + } + // Nothing to be found. Simulate a "virtual raw" element at the bottom of the stack. + if acc_m.is_raw() { + Ok(()) + } else { + err!(MachineError(format!("Borrow-to-reactivate does not exist on the stack"))) + } + } + + fn initiate(&mut self, bor: Borrow) -> EvalResult<'tcx> { + match bor { + Borrow::Frz(t) => { + match self.frozen_since { + None => self.frozen_since = Some(t), + Some(since) => assert!(since <= t), + } + } + Borrow::Mut(m) => { + match self.frozen_since { + None => self.borrows.push(BorStackItem::Mut(m)), + Some(_) => + // FIXME: Do we want an exception for raw borrows? + return err!(MachineError(format!("Trying to mutate frozen location"))) + } + } + } + Ok(()) + } +} + +impl State { + fn increment_clock(&mut self) -> Timestamp { + self.clock += 1; + self.clock + } +} + +/// Machine hooks +pub trait EvalContextExt<'tcx> { + fn tag_reference( + &mut self, + ptr: Pointer, + pointee_ty: Ty<'tcx>, + size: Size, + borrow_kind: mir::BorrowKind, + ) -> EvalResult<'tcx, Borrow>; + + fn tag_dereference( + &self, + ptr: Pointer, + ptr_ty: Ty<'tcx>, + ) -> EvalResult<'tcx, Borrow>; +} + +impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, 'tcx> { + fn tag_reference( + &mut self, + ptr: Pointer, + pointee_ty: Ty<'tcx>, + size: Size, + borrow_kind: mir::BorrowKind, + ) -> EvalResult<'tcx, Borrow> { + let old_bor = ptr.tag; + let time = self.machine.stacked_borrows.increment_clock(); + // FIXME This does not do enough checking when only part of the data lacks + // interior mutability. + let new_bor = match borrow_kind { + mir::BorrowKind::Mut { .. } => Borrow::Mut(Mut::Uniq(time)), + _ => + if self.type_is_freeze(pointee_ty) { + Borrow::Frz(time) + } else { + Borrow::Mut(Mut::Raw) + } + }; + trace!("tag_reference: Creating new tag for {:?} (pointee {}, size {}): {:?}", ptr, pointee_ty, size.bytes(), new_bor); + + // Make sure this reference is not dangling or so + self.memory.check_bounds(ptr, size, false)?; + + // Update the stacks. We cannot use `get_mut` becuse this might be immutable + // memory. + let alloc = self.memory.get(ptr.alloc_id).expect("We checked that the ptr is fine!"); + let mut stacks = alloc.extra.stacks.borrow_mut(); + for stack in stacks.iter_mut(ptr.offset, size) { + if stack.check(new_bor) { + // The new borrow is already active! This can happen when creating multiple + // shared references from the same mutable reference. Do nothing. + } else { + // FIXME: The blog post says we should `reset` if this is a local. + stack.reactivate(old_bor, /*force_mut*/new_bor.is_uniq())?; + stack.initiate(new_bor)?; + } + } + + Ok(new_bor) + } + + fn tag_dereference( + &self, + ptr: Pointer, + ptr_ty: Ty<'tcx>, + ) -> EvalResult<'tcx, Borrow> { + // If this is a raw ptr, forget about the tag. + Ok(if ptr_ty.is_unsafe_ptr() { + trace!("tag_dereference: Erasing tag for {:?} ({})", ptr, ptr_ty); + Borrow::Mut(Mut::Raw) + } else { + // FIXME: Do we want to adjust the tag if it does not match the type? + ptr.tag + }) + } +} diff --git a/src/tls.rs b/src/tls.rs index c5d119ec7f5bf..2bddc43df8c4a 100644 --- a/src/tls.rs +++ b/src/tls.rs @@ -4,19 +4,19 @@ use rustc_target::abi::LayoutOf; use rustc::{ty, ty::layout::HasDataLayout, mir}; use super::{ - EvalResult, EvalErrorKind, StackPopCleanup, EvalContext, Evaluator, + EvalResult, EvalErrorKind, StackPopCleanup, MPlaceTy, Scalar, Borrow, }; pub type TlsKey = u128; -#[derive(Copy, Clone, Debug, PartialEq, Eq)] +#[derive(Copy, Clone, Debug)] pub struct TlsEntry<'tcx> { pub(crate) data: Scalar, // Will eventually become a map from thread IDs to `Scalar`s, if we ever support more than one thread. pub(crate) dtor: Option>, } -#[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Debug)] pub struct TlsData<'tcx> { /// The Key to use for the next thread-local allocation. pub(crate) next_key: TlsKey, @@ -133,7 +133,7 @@ impl<'tcx> TlsData<'tcx> { } } -impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, Evaluator<'tcx>> { +impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, 'tcx> { fn run_tls_dtors(&mut self) -> EvalResult<'tcx> { let mut dtor = self.machine.tls.fetch_tls_dtor(None, *self.tcx); // FIXME: replace loop by some structure that works with stepping From d4b78b36abe896556ba04785610148b51aa67572 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 17 Oct 2018 15:15:53 +0200 Subject: [PATCH 0269/3747] stacked borrows: enforcement at memory accesses --- src/fn_call.rs | 67 +++++++++------- src/intrinsic.rs | 15 ++-- src/lib.rs | 44 ++++++++-- src/range_map.rs | 4 + src/stacked_borrows.rs | 165 ++++++++++++++++++++++++++------------ tests/run-pass/raw.rs | 21 +++++ tests/run-pass/refcell.rs | 33 ++++++++ tests/run-pass/std.rs | 5 +- 8 files changed, 259 insertions(+), 95 deletions(-) create mode 100644 tests/run-pass/raw.rs create mode 100644 tests/run-pass/refcell.rs diff --git a/src/fn_call.rs b/src/fn_call.rs index 1613da4a487af..eb889c1d495ac 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -118,6 +118,10 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo None => self.tcx.item_name(def_id).as_str(), }; + // All these functions take raw pointers, so if we access memory directly + // (as opposed to through a place), we have to remember to erase any tag + // that might still hang around! + match &link_name[..] { "malloc" => { let size = self.read_scalar(args[0])?.to_usize(&self)?; @@ -131,10 +135,10 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo } "free" => { - let ptr = self.read_scalar(args[0])?.not_undef()?; + let ptr = self.read_scalar(args[0])?.not_undef()?.erase_tag(); // raw ptr operation, no tag if !ptr.is_null() { self.memory.deallocate( - ptr.to_ptr()?, + ptr.to_ptr()?.with_default_tag(), None, MiriMemoryKind::C.into(), )?; @@ -171,7 +175,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo self.write_scalar(Scalar::Ptr(ptr), dest)?; } "__rust_dealloc" => { - let ptr = self.read_scalar(args[0])?.to_ptr()?; + let ptr = self.read_scalar(args[0])?.to_ptr()?.erase_tag(); // raw ptr operation, no tag let old_size = self.read_scalar(args[1])?.to_usize(&self)?; let align = self.read_scalar(args[2])?.to_usize(&self)?; if old_size == 0 { @@ -181,13 +185,13 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo return err!(HeapAllocNonPowerOfTwoAlignment(align)); } self.memory.deallocate( - ptr, + ptr.with_default_tag(), Some((Size::from_bytes(old_size), Align::from_bytes(align, align).unwrap())), MiriMemoryKind::Rust.into(), )?; } "__rust_realloc" => { - let ptr = self.read_scalar(args[0])?.to_ptr()?; + let ptr = self.read_scalar(args[0])?.to_ptr()?.erase_tag(); // raw ptr operation, no tag let old_size = self.read_scalar(args[1])?.to_usize(&self)?; let align = self.read_scalar(args[2])?.to_usize(&self)?; let new_size = self.read_scalar(args[3])?.to_usize(&self)?; @@ -198,7 +202,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo return err!(HeapAllocNonPowerOfTwoAlignment(align)); } let new_ptr = self.memory.reallocate( - ptr, + ptr.with_default_tag(), Size::from_bytes(old_size), Align::from_bytes(align, align).unwrap(), Size::from_bytes(new_size), @@ -230,8 +234,8 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo "dlsym" => { let _handle = self.read_scalar(args[0])?; - let symbol = self.read_scalar(args[1])?.to_ptr()?; - let symbol_name = self.memory.read_c_str(symbol)?; + let symbol = self.read_scalar(args[1])?.to_ptr()?.erase_tag(); + let symbol_name = self.memory.read_c_str(symbol.with_default_tag())?; let err = format!("bad c unicode symbol: {:?}", symbol_name); let symbol_name = ::std::str::from_utf8(symbol_name).unwrap_or(&err); return err!(Unimplemented(format!( @@ -284,13 +288,13 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo return err!(MachineError("the evaluated program panicked".to_string())), "memcmp" => { - let left = self.read_scalar(args[0])?.not_undef()?; - let right = self.read_scalar(args[1])?.not_undef()?; + let left = self.read_scalar(args[0])?.not_undef()?.erase_tag(); // raw ptr operation + let right = self.read_scalar(args[1])?.not_undef()?.erase_tag(); // raw ptr operation let n = Size::from_bytes(self.read_scalar(args[2])?.to_usize(&self)?); let result = { - let left_bytes = self.memory.read_bytes(left, n)?; - let right_bytes = self.memory.read_bytes(right, n)?; + let left_bytes = self.memory.read_bytes(left.with_default_tag(), n)?; + let right_bytes = self.memory.read_bytes(right.with_default_tag(), n)?; use std::cmp::Ordering::*; match left_bytes.cmp(right_bytes) { @@ -307,12 +311,12 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo } "memrchr" => { - let ptr = self.read_scalar(args[0])?.not_undef()?; + let ptr = self.read_scalar(args[0])?.not_undef()?.erase_tag(); // raw ptr operation + let ptr = ptr.with_default_tag(); let val = self.read_scalar(args[1])?.to_bytes()? as u8; let num = self.read_scalar(args[2])?.to_usize(&self)?; - if let Some(idx) = self.memory.read_bytes(ptr, Size::from_bytes(num))?.iter().rev().position( - |&c| c == val, - ) + if let Some(idx) = self.memory.read_bytes(ptr, Size::from_bytes(num))? + .iter().rev().position(|&c| c == val) { let new_ptr = ptr.ptr_offset(Size::from_bytes(num - idx as u64 - 1), &self)?; self.write_scalar(new_ptr, dest)?; @@ -322,7 +326,8 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo } "memchr" => { - let ptr = self.read_scalar(args[0])?.not_undef()?; + let ptr = self.read_scalar(args[0])?.not_undef()?.erase_tag(); // raw ptr operation + let ptr = ptr.with_default_tag(); let val = self.read_scalar(args[1])?.to_bytes()? as u8; let num = self.read_scalar(args[2])?.to_usize(&self)?; if let Some(idx) = self.memory.read_bytes(ptr, Size::from_bytes(num))?.iter().position( @@ -338,8 +343,8 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo "getenv" => { let result = { - let name_ptr = self.read_scalar(args[0])?.to_ptr()?; - let name = self.memory.read_c_str(name_ptr)?; + let name_ptr = self.read_scalar(args[0])?.to_ptr()?.erase_tag(); // raw ptr operation + let name = self.memory.read_c_str(name_ptr.with_default_tag())?; match self.machine.env_vars.get(name) { Some(&var) => Scalar::Ptr(var), None => Scalar::ptr_null(*self.tcx), @@ -351,9 +356,9 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo "unsetenv" => { let mut success = None; { - let name_ptr = self.read_scalar(args[0])?.not_undef()?; + let name_ptr = self.read_scalar(args[0])?.not_undef()?.erase_tag(); // raw ptr operation if !name_ptr.is_null() { - let name = self.memory.read_c_str(name_ptr.to_ptr()?)?; + let name = self.memory.read_c_str(name_ptr.to_ptr()?.with_default_tag())?; if !name.is_empty() && !name.contains(&b'=') { success = Some(self.machine.env_vars.remove(name)); } @@ -372,11 +377,11 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo "setenv" => { let mut new = None; { - let name_ptr = self.read_scalar(args[0])?.not_undef()?; - let value_ptr = self.read_scalar(args[1])?.to_ptr()?; - let value = self.memory.read_c_str(value_ptr)?; + let name_ptr = self.read_scalar(args[0])?.not_undef()?.erase_tag(); // raw ptr operation + let value_ptr = self.read_scalar(args[1])?.to_ptr()?.erase_tag(); // raw ptr operation + let value = self.memory.read_c_str(value_ptr.with_default_tag())?; if !name_ptr.is_null() { - let name = self.memory.read_c_str(name_ptr.to_ptr()?)?; + let name = self.memory.read_c_str(name_ptr.to_ptr()?.with_default_tag())?; if !name.is_empty() && !name.contains(&b'=') { new = Some((name.to_owned(), value.to_owned())); } @@ -407,14 +412,14 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo "write" => { let fd = self.read_scalar(args[0])?.to_bytes()?; - let buf = self.read_scalar(args[1])?.not_undef()?; + let buf = self.read_scalar(args[1])?.not_undef()?.erase_tag(); let n = self.read_scalar(args[2])?.to_bytes()? as u64; trace!("Called write({:?}, {:?}, {:?})", fd, buf, n); let result = if fd == 1 || fd == 2 { // stdout/stderr use std::io::{self, Write}; - let buf_cont = self.memory.read_bytes(buf, Size::from_bytes(n))?; + let buf_cont = self.memory.read_bytes(buf.with_default_tag(), Size::from_bytes(n))?; let res = if fd == 1 { io::stdout().write(buf_cont) } else { @@ -435,8 +440,8 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo } "strlen" => { - let ptr = self.read_scalar(args[0])?.to_ptr()?; - let n = self.memory.read_c_str(ptr)?.len(); + let ptr = self.read_scalar(args[0])?.to_ptr()?.erase_tag(); + let n = self.memory.read_c_str(ptr.with_default_tag())?.len(); self.write_scalar(Scalar::from_uint(n as u64, dest.layout.size), dest)?; } @@ -482,7 +487,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo // Hook pthread calls that go to the thread-local storage memory subsystem "pthread_key_create" => { - let key_ptr = self.read_scalar(args[0])?.to_ptr()?; + let key_ptr = self.read_scalar(args[0])?.to_ptr()?.erase_tag(); // raw ptr operation // Extract the function type out of the signature (that seems easier than constructing it ourselves...) let dtor = match self.read_scalar(args[1])?.not_undef()? { @@ -505,7 +510,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo return err!(OutOfTls); } self.memory.write_scalar( - key_ptr, + key_ptr.with_default_tag(), key_layout.align, Scalar::from_uint(key, key_layout.size).into(), key_layout.size, diff --git a/src/intrinsic.rs b/src/intrinsic.rs index 719bc93939589..2b02f22a382b0 100644 --- a/src/intrinsic.rs +++ b/src/intrinsic.rs @@ -31,6 +31,10 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' let substs = instance.substs; + // All these intrinsics take raw pointers, so if we access memory directly + // (as opposed to through a place), we have to remember to erase any tag + // that might still hang around! + let intrinsic_name = &self.tcx.item_name(instance.def_id()).as_str()[..]; match intrinsic_name { "arith_offset" => { @@ -146,12 +150,13 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' let elem_size = elem_layout.size.bytes(); let count = self.read_scalar(args[2])?.to_usize(&self)?; let elem_align = elem_layout.align; - let src = self.read_scalar(args[0])?.not_undef()?; - let dest = self.read_scalar(args[1])?.not_undef()?; + // erase tags: this is a raw ptr operation + let src = self.read_scalar(args[0])?.not_undef()?.erase_tag(); + let dest = self.read_scalar(args[1])?.not_undef()?.erase_tag(); self.memory.copy( - src, + src.with_default_tag(), elem_align, - dest, + dest.with_default_tag(), elem_align, Size::from_bytes(count * elem_size), intrinsic_name.ends_with("_nonoverlapping"), @@ -428,7 +433,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' let ty = substs.type_at(0); let ty_layout = self.layout_of(ty)?; let val_byte = self.read_scalar(args[1])?.to_u8()?; - let ptr = self.read_scalar(args[0])?.not_undef()?; + let ptr = self.read_scalar(args[0])?.not_undef()?.erase_tag().with_default_tag(); let count = self.read_scalar(args[2])?.to_usize(&self)?; self.memory.check_align(ptr, ty_layout.align)?; self.memory.write_repeat(ptr, val_byte, ty_layout.size * count)?; diff --git a/src/lib.rs b/src/lib.rs index 97b73e60692cd..c910911f5762b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -415,14 +415,48 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { Cow::Owned(alloc) } + #[inline(always)] + fn memory_accessed( + alloc: &Allocation, + ptr: Pointer, + size: Size, + access: MemoryAccess, + ) -> EvalResult<'tcx> { + alloc.extra.memory_accessed(ptr, size, access) + } + + #[inline(always)] + fn memory_deallocated( + alloc: &mut Allocation, + ptr: Pointer, + ) -> EvalResult<'tcx> { + alloc.extra.memory_deallocated(ptr) + } + + /*/// Hook for when a reference is cast to a raw pointer + #[inline(always)] + fn ref_to_raw_cast( + ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, + ptr: Pointer, + ptr_ty: Ty<'tcx>, + size: Size, + ) -> EvalResult<'tcx> { + if !ecx.machine.validate { + // No tracking. + Ok(()) + } else { + ecx.ref_to_raw_cast(ptr, ptr_ty, size) + } + }*/ + #[inline(always)] fn tag_reference( ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, - ptr: Pointer, + ptr: Pointer, pointee_ty: Ty<'tcx>, pointee_size: Size, - borrow_kind: mir::BorrowKind, - ) -> EvalResult<'tcx, Self::PointerTag> { + borrow_kind: Option, + ) -> EvalResult<'tcx, Borrow> { if !ecx.machine.validate { // No tracking Ok(Borrow::default()) @@ -434,9 +468,9 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { #[inline(always)] fn tag_dereference( ecx: &EvalContext<'a, 'mir, 'tcx, Self>, - ptr: Pointer, + ptr: Pointer, ptr_ty: Ty<'tcx>, - ) -> EvalResult<'tcx, Self::PointerTag> { + ) -> EvalResult<'tcx, Borrow> { if !ecx.machine.validate { // No tracking Ok(Borrow::default()) diff --git a/src/range_map.rs b/src/range_map.rs index 1d9a38cb5ef53..74a49bf83b819 100644 --- a/src/range_map.rs +++ b/src/range_map.rs @@ -99,6 +99,10 @@ impl RangeMap { self.iter_with_range(offset.bytes(), len.bytes()).map(|(_, data)| data) } + pub fn iter_mut_all<'a>(&'a mut self) -> impl Iterator + 'a { + self.map.values_mut() + } + fn split_entry_at(&mut self, offset: u64) where T: Clone, diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index c3514efdbe71e..e4d2289bf34c7 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -4,7 +4,7 @@ use rustc::ty::{Ty, layout::Size}; use rustc::mir; use super::{ - RangeMap, EvalResult, + MemoryAccess, RangeMap, EvalResult, Pointer, }; @@ -13,10 +13,10 @@ pub type Timestamp = u64; /// Information about a potentially mutable borrow #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] pub enum Mut { - /// A unique, mutable reference - Uniq(Timestamp), - /// Any raw pointer, or a shared borrow with interior mutability - Raw, + /// A unique, mutable reference + Uniq(Timestamp), + /// Any raw pointer, or a shared borrow with interior mutability + Raw, } impl Mut { @@ -27,34 +27,18 @@ impl Mut { _ => false, } } - - #[inline(always)] - fn is_uniq(self) -> bool { - match self { - Mut::Uniq(_) => true, - _ => false, - } - } } /// Information about any kind of borrow #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] pub enum Borrow { - /// A mutable borrow, a raw pointer, or a shared borrow with interior mutability - Mut(Mut), - /// A shared borrow without interior mutability - Frz(Timestamp) + /// A mutable borrow, a raw pointer, or a shared borrow with interior mutability + Mut(Mut), + /// A shared borrow without interior mutability + Frz(Timestamp) } impl Borrow { - #[inline(always)] - fn is_mut(self) -> bool { - match self { - Borrow::Mut(_) => true, - _ => false, - } - } - #[inline(always)] fn is_uniq(self) -> bool { match self { @@ -67,10 +51,11 @@ impl Borrow { /// An item in the borrow stack #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] pub enum BorStackItem { - /// Defines which references are permitted to mutate *if* the location is not frozen - Mut(Mut), - /// A barrier, tracking the function it belongs to by its index on the call stack - FnBarrier(usize) + /// Defines which references are permitted to mutate *if* the location is not frozen + Mut(Mut), + /// A barrier, tracking the function it belongs to by its index on the call stack + #[allow(dead_code)] // for future use + FnBarrier(usize) } impl Default for Borrow { @@ -133,15 +118,19 @@ impl<'tcx> Stack { /// Reactive `bor` for this stack. If `force_mut` is set, we want to aggressively /// unfreeze this location (because we are about to push a `Uniq`). fn reactivate(&mut self, bor: Borrow, force_mut: bool) -> EvalResult<'tcx> { - assert!(!force_mut || bor.is_mut()); // if `force_mut` is set, this must be a mutable borrow - // Do NOT change anything if `bor` is already active -- in particular, if - // it is a `Mut(Raw)` and we are frozen. + // Unless mutation is bound to happen, do NOT change anything if `bor` is already active. + // In particular, if it is a `Mut(Raw)` and we are frozen, this should be a NOP. if !force_mut && self.check(bor) { return Ok(()); } let acc_m = match bor { - Borrow::Frz(_) => return err!(MachineError(format!("Location should be frozen but it is not"))), + Borrow::Frz(_) => + if force_mut { + return err!(MachineError(format!("Using a shared borrow for mutation"))) + } else { + return err!(MachineError(format!("Location should be frozen but it is not"))) + } Borrow::Mut(acc_m) => acc_m, }; // We definitely have to unfreeze this, even if we use the topmost item. @@ -154,6 +143,7 @@ impl<'tcx> Stack { } BorStackItem::Mut(loc_m) => { if loc_m == acc_m { return Ok(()); } + trace!("reactivate: Popping {:?}", itm); self.borrows.pop(); } } @@ -169,12 +159,14 @@ impl<'tcx> Stack { fn initiate(&mut self, bor: Borrow) -> EvalResult<'tcx> { match bor { Borrow::Frz(t) => { + trace!("initiate: Freezing"); match self.frozen_since { None => self.frozen_since = Some(t), Some(since) => assert!(since <= t), } } Borrow::Mut(m) => { + trace!("initiate: Pushing {:?}", bor); match self.frozen_since { None => self.borrows.push(BorStackItem::Mut(m)), Some(_) => @@ -194,6 +186,58 @@ impl State { } } +/// Higher-level operations +impl<'tcx> Stacks { + pub fn memory_accessed( + &self, + ptr: Pointer, + size: Size, + access: MemoryAccess, + ) -> EvalResult<'tcx> { + trace!("memory_accessed({:?}) with tag {:?}: {:?}, size {}", access, ptr.tag, ptr, size.bytes()); + let mut stacks = self.stacks.borrow_mut(); + for stack in stacks.iter_mut(ptr.offset, size) { + // FIXME: Compare this with what the blog post says. + stack.reactivate(ptr.tag, /*force_mut*/access == MemoryAccess::Write)?; + } + Ok(()) + } + + pub fn memory_deallocated( + &mut self, + ptr: Pointer, + ) -> EvalResult<'tcx> { + trace!("memory_deallocated with tag {:?}: {:?}", ptr.tag, ptr); + let stacks = self.stacks.get_mut(); + for stack in stacks.iter_mut_all() { + // This is like mutating. + stack.reactivate(ptr.tag, /*force_mut*/true)?; + } + Ok(()) + } + + fn reborrow( + &self, + ptr: Pointer, + size: Size, + new_bor: Borrow, + ) -> EvalResult<'tcx> { + let mut stacks = self.stacks.borrow_mut(); + for stack in stacks.iter_mut(ptr.offset, size) { + if stack.check(new_bor) { + // The new borrow is already active! This can happen when creating multiple + // shared references from the same mutable reference. Do nothing. + } else { + // FIXME: The blog post says we should `reset` if this is a local. + stack.reactivate(ptr.tag, /*force_mut*/new_bor.is_uniq())?; + stack.initiate(new_bor)?; + } + } + + Ok(()) + } +} + /// Machine hooks pub trait EvalContextExt<'tcx> { fn tag_reference( @@ -201,7 +245,7 @@ pub trait EvalContextExt<'tcx> { ptr: Pointer, pointee_ty: Ty<'tcx>, size: Size, - borrow_kind: mir::BorrowKind, + borrow_kind: Option, ) -> EvalResult<'tcx, Borrow>; fn tag_dereference( @@ -209,6 +253,13 @@ pub trait EvalContextExt<'tcx> { ptr: Pointer, ptr_ty: Ty<'tcx>, ) -> EvalResult<'tcx, Borrow>; + + fn ref_to_raw_cast( + &mut self, + ptr: Pointer, + ptr_ty: Ty<'tcx>, + size: Size, + ) -> EvalResult<'tcx>; } impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, 'tcx> { @@ -217,22 +268,23 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' ptr: Pointer, pointee_ty: Ty<'tcx>, size: Size, - borrow_kind: mir::BorrowKind, + borrow_kind: Option, ) -> EvalResult<'tcx, Borrow> { - let old_bor = ptr.tag; let time = self.machine.stacked_borrows.increment_clock(); - // FIXME This does not do enough checking when only part of the data lacks + // FIXME This does not do enough checking when only part of the data has // interior mutability. let new_bor = match borrow_kind { - mir::BorrowKind::Mut { .. } => Borrow::Mut(Mut::Uniq(time)), - _ => + Some(mir::BorrowKind::Mut { .. }) => Borrow::Mut(Mut::Uniq(time)), + Some(_) => if self.type_is_freeze(pointee_ty) { Borrow::Frz(time) } else { Borrow::Mut(Mut::Raw) - } + }, + None => Borrow::Mut(Mut::Raw), }; - trace!("tag_reference: Creating new tag for {:?} (pointee {}, size {}): {:?}", ptr, pointee_ty, size.bytes(), new_bor); + trace!("tag_reference: Creating new reference ({:?}) for {:?} (pointee {}, size {}): {:?}", + borrow_kind, ptr, pointee_ty, size.bytes(), new_bor); // Make sure this reference is not dangling or so self.memory.check_bounds(ptr, size, false)?; @@ -240,17 +292,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' // Update the stacks. We cannot use `get_mut` becuse this might be immutable // memory. let alloc = self.memory.get(ptr.alloc_id).expect("We checked that the ptr is fine!"); - let mut stacks = alloc.extra.stacks.borrow_mut(); - for stack in stacks.iter_mut(ptr.offset, size) { - if stack.check(new_bor) { - // The new borrow is already active! This can happen when creating multiple - // shared references from the same mutable reference. Do nothing. - } else { - // FIXME: The blog post says we should `reset` if this is a local. - stack.reactivate(old_bor, /*force_mut*/new_bor.is_uniq())?; - stack.initiate(new_bor)?; - } - } + alloc.extra.reborrow(ptr, size, new_bor)?; Ok(new_bor) } @@ -269,4 +311,23 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' ptr.tag }) } + + fn ref_to_raw_cast( + &mut self, + ptr: Pointer, + _ptr_ty: Ty<'tcx>, + size: Size, + ) -> EvalResult<'tcx> { + trace!("ref_to_raw_cast: Escaping {:?}", ptr); + + // Make sure this reference is not dangling or so + self.memory.check_bounds(ptr, size, false)?; + + // Update the stacks. We cannot use `get_mut` becuse this might be immutable + // memory. + let alloc = self.memory.get(ptr.alloc_id).expect("We checked that the ptr is fine!"); + alloc.extra.reborrow(ptr, size, Borrow::Mut(Mut::Raw))?; + + Ok(()) + } } diff --git a/tests/run-pass/raw.rs b/tests/run-pass/raw.rs new file mode 100644 index 0000000000000..4fbbb270957b3 --- /dev/null +++ b/tests/run-pass/raw.rs @@ -0,0 +1,21 @@ +fn basic_raw() { + let mut x = 12; + let x = &mut x; + + assert_eq!(*x, 12); + + let raw = x as *mut i32; + unsafe { *raw = 42; } + + assert_eq!(*x, 42); + + let raw = x as *mut i32; + unsafe { *raw = 12; } + *x = 23; + + assert_eq!(*x, 23); +} + +fn main() { + basic_raw(); +} diff --git a/tests/run-pass/refcell.rs b/tests/run-pass/refcell.rs new file mode 100644 index 0000000000000..93cef1572a3e1 --- /dev/null +++ b/tests/run-pass/refcell.rs @@ -0,0 +1,33 @@ +use std::cell::RefCell; + +fn main() { + let c = RefCell::new(42); + { + let s1 = c.borrow(); + let _x: i32 = *s1; + let s2 = c.borrow(); + let _x: i32 = *s1; + let _y: i32 = *s2; + let _x: i32 = *s1; + let _y: i32 = *s2; + } + { + let mut m = c.borrow_mut(); + let _z: i32 = *m; + { + let s: &i32 = &*m; + let _x = *s; + } + *m = 23; + let _z: i32 = *m; + } + { + let s1 = c.borrow(); + let _x: i32 = *s1; + let s2 = c.borrow(); + let _x: i32 = *s1; + let _y: i32 = *s2; + let _x: i32 = *s1; + let _y: i32 = *s2; + } +} diff --git a/tests/run-pass/std.rs b/tests/run-pass/std.rs index e0e23812d275e..7ff967b29f344 100644 --- a/tests/run-pass/std.rs +++ b/tests/run-pass/std.rs @@ -12,8 +12,9 @@ fn rc_cell() -> Rc> { fn rc_refcell() -> i32 { let r = Rc::new(RefCell::new(42)); *r.borrow_mut() += 10; - let x = *r.borrow(); - x + let x = r.borrow(); + let y = r.borrow(); + (*x + *y)/2 } fn arc() -> Arc { From 1907782b64c36f41802a41f1f784f877870293ff Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 17 Oct 2018 16:55:59 +0200 Subject: [PATCH 0270/3747] reenable some tests that work now, and organize them better with directories --- .../stacked_borrows/alias_through_mutation.rs | 15 +++++++++++ .../aliasing_mut1.rs} | 0 .../aliasing_mut2.rs} | 0 .../aliasing_mut3.rs} | 0 .../aliasing_mut4.rs} | 0 .../buggy_as_mut_slice.rs} | 11 +++----- .../buggy_split_at_mut.rs} | 6 ++--- .../stacked_borrows/illegal_write.rs | 11 ++++++++ .../stacked_borrows/illegal_write2.rs | 10 +++++++ .../stacked_borrows/pointer_smuggling.rs | 22 ++++++++++++++++ .../stacked_borrows/shared_confusion.rs | 21 +++++++++++++++ .../compile-fail/validation_illegal_write.rs | 17 ------------ .../compile-fail/validation_lock_confusion.rs | 26 ------------------- .../validation_pointer_smuggling.rs | 22 ---------------- tests/compile-fail/validation_recover1.rs | 18 ------------- tests/compile-fail/validation_recover2.rs | 16 ------------ tests/compile-fail/validation_recover3.rs | 17 ------------ tests/compile-fail/validation_undef.rs | 16 ------------ .../cast_fn_ptr1.rs} | 0 .../cast_fn_ptr2.rs} | 0 .../{ => validity}/invalid_bool.rs | 0 .../{ => validity}/invalid_char.rs | 0 .../invalid_enum_discriminant.rs | 0 .../validity/transmute_through_ptr.rs | 16 ++++++++++++ tests/compile-fail/validity/undef.rs | 12 +++++++++ tests/compiletest.rs | 1 + 26 files changed, 114 insertions(+), 143 deletions(-) create mode 100644 tests/compile-fail/stacked_borrows/alias_through_mutation.rs rename tests/compile-fail/{validation_aliasing_mut1.rs => stacked_borrows/aliasing_mut1.rs} (100%) rename tests/compile-fail/{validation_aliasing_mut2.rs => stacked_borrows/aliasing_mut2.rs} (100%) rename tests/compile-fail/{validation_aliasing_mut3.rs => stacked_borrows/aliasing_mut3.rs} (100%) rename tests/compile-fail/{validation_aliasing_mut4.rs => stacked_borrows/aliasing_mut4.rs} (100%) rename tests/compile-fail/{validation_buggy_as_mut_slice.rs => stacked_borrows/buggy_as_mut_slice.rs} (52%) rename tests/compile-fail/{validation_buggy_split_at_mut.rs => stacked_borrows/buggy_split_at_mut.rs} (79%) create mode 100644 tests/compile-fail/stacked_borrows/illegal_write.rs create mode 100644 tests/compile-fail/stacked_borrows/illegal_write2.rs create mode 100644 tests/compile-fail/stacked_borrows/pointer_smuggling.rs create mode 100644 tests/compile-fail/stacked_borrows/shared_confusion.rs delete mode 100644 tests/compile-fail/validation_illegal_write.rs delete mode 100644 tests/compile-fail/validation_lock_confusion.rs delete mode 100644 tests/compile-fail/validation_pointer_smuggling.rs delete mode 100644 tests/compile-fail/validation_recover1.rs delete mode 100644 tests/compile-fail/validation_recover2.rs delete mode 100644 tests/compile-fail/validation_recover3.rs delete mode 100644 tests/compile-fail/validation_undef.rs rename tests/compile-fail/{validation_cast_fn_ptr1.rs => validity/cast_fn_ptr1.rs} (100%) rename tests/compile-fail/{validation_cast_fn_ptr2.rs => validity/cast_fn_ptr2.rs} (100%) rename tests/compile-fail/{ => validity}/invalid_bool.rs (100%) rename tests/compile-fail/{ => validity}/invalid_char.rs (100%) rename tests/compile-fail/{ => validity}/invalid_enum_discriminant.rs (100%) create mode 100644 tests/compile-fail/validity/transmute_through_ptr.rs create mode 100644 tests/compile-fail/validity/undef.rs diff --git a/tests/compile-fail/stacked_borrows/alias_through_mutation.rs b/tests/compile-fail/stacked_borrows/alias_through_mutation.rs new file mode 100644 index 0000000000000..9fa50da45bd0f --- /dev/null +++ b/tests/compile-fail/stacked_borrows/alias_through_mutation.rs @@ -0,0 +1,15 @@ +#![allow(unused_variables)] + +// This makes a ref that was passed to us via &mut alias with things it should not alias with +fn retarget(x: &mut &u32, target: &mut u32) { + unsafe { *x = &mut *(target as *mut _); } +} + +fn main() { + let target = &mut 42; + let mut target_alias = &42; // initial dummy value + retarget(&mut target_alias, target); + // now `target_alias` points to the same thing as `target` + *target = 13; + let _val = *target_alias; //~ ERROR should be frozen +} diff --git a/tests/compile-fail/validation_aliasing_mut1.rs b/tests/compile-fail/stacked_borrows/aliasing_mut1.rs similarity index 100% rename from tests/compile-fail/validation_aliasing_mut1.rs rename to tests/compile-fail/stacked_borrows/aliasing_mut1.rs diff --git a/tests/compile-fail/validation_aliasing_mut2.rs b/tests/compile-fail/stacked_borrows/aliasing_mut2.rs similarity index 100% rename from tests/compile-fail/validation_aliasing_mut2.rs rename to tests/compile-fail/stacked_borrows/aliasing_mut2.rs diff --git a/tests/compile-fail/validation_aliasing_mut3.rs b/tests/compile-fail/stacked_borrows/aliasing_mut3.rs similarity index 100% rename from tests/compile-fail/validation_aliasing_mut3.rs rename to tests/compile-fail/stacked_borrows/aliasing_mut3.rs diff --git a/tests/compile-fail/validation_aliasing_mut4.rs b/tests/compile-fail/stacked_borrows/aliasing_mut4.rs similarity index 100% rename from tests/compile-fail/validation_aliasing_mut4.rs rename to tests/compile-fail/stacked_borrows/aliasing_mut4.rs diff --git a/tests/compile-fail/validation_buggy_as_mut_slice.rs b/tests/compile-fail/stacked_borrows/buggy_as_mut_slice.rs similarity index 52% rename from tests/compile-fail/validation_buggy_as_mut_slice.rs rename to tests/compile-fail/stacked_borrows/buggy_as_mut_slice.rs index 282e536ce9b73..3345668cee00c 100644 --- a/tests/compile-fail/validation_buggy_as_mut_slice.rs +++ b/tests/compile-fail/stacked_borrows/buggy_as_mut_slice.rs @@ -1,22 +1,17 @@ -// ignore-test validation_op is disabled - #![allow(unused_variables)] -// For some reason, the error location is different when using fullmir -// error-pattern: in conflict with lock WriteLock - mod safe { use std::slice::from_raw_parts_mut; pub fn as_mut_slice(self_: &Vec) -> &mut [T] { unsafe { - from_raw_parts_mut(self_.as_ptr() as *mut T, self_.len()) + from_raw_parts_mut(self_.as_ptr() as *mut T, self_.len()) //~ ERROR shared borrow for mutation } } } fn main() { let v = vec![0,1,2]; - let v1_ = safe::as_mut_slice(&v); - let v2_ = safe::as_mut_slice(&v); + let v1 = safe::as_mut_slice(&v); + let v2 = safe::as_mut_slice(&v); } diff --git a/tests/compile-fail/validation_buggy_split_at_mut.rs b/tests/compile-fail/stacked_borrows/buggy_split_at_mut.rs similarity index 79% rename from tests/compile-fail/validation_buggy_split_at_mut.rs rename to tests/compile-fail/stacked_borrows/buggy_split_at_mut.rs index a750f1466f51b..d7f4300f82c05 100644 --- a/tests/compile-fail/validation_buggy_split_at_mut.rs +++ b/tests/compile-fail/stacked_borrows/buggy_split_at_mut.rs @@ -1,5 +1,3 @@ -// ignore-test validation_op is disabled - #![allow(unused_variables)] mod safe { @@ -20,5 +18,7 @@ mod safe { fn main() { let mut array = [1,2,3,4]; - let _x = safe::split_at_mut(&mut array, 0); //~ ERROR: in conflict with lock WriteLock + let (a, b) = safe::split_at_mut(&mut array, 0); + a[1] = 5; //~ ERROR does not exist on the stack + b[1] = 6; } diff --git a/tests/compile-fail/stacked_borrows/illegal_write.rs b/tests/compile-fail/stacked_borrows/illegal_write.rs new file mode 100644 index 0000000000000..6a7ccc84012c6 --- /dev/null +++ b/tests/compile-fail/stacked_borrows/illegal_write.rs @@ -0,0 +1,11 @@ +fn evil(x: &u32) { + let x : &mut u32 = unsafe { &mut *(x as *const _ as *mut _) }; + *x = 42; // mutating shared ref without `UnsafeCell` +} + +fn main() { + let target = 42; + let ref_ = ⌖ + evil(ref_); // invalidates shared ref + let _x = *ref_; //~ ERROR should be frozen +} diff --git a/tests/compile-fail/stacked_borrows/illegal_write2.rs b/tests/compile-fail/stacked_borrows/illegal_write2.rs new file mode 100644 index 0000000000000..1d61b1b988965 --- /dev/null +++ b/tests/compile-fail/stacked_borrows/illegal_write2.rs @@ -0,0 +1,10 @@ +#![allow(unused_variables)] + +fn main() { + let target = &mut 42; + let target2 = target as *mut _; + drop(&mut *target); // reborrow + // Now make sure our ref is still the only one + unsafe { *target2 = 13; } // invalidate our ref + let _val = *target; //~ ERROR does not exist on the stack +} diff --git a/tests/compile-fail/stacked_borrows/pointer_smuggling.rs b/tests/compile-fail/stacked_borrows/pointer_smuggling.rs new file mode 100644 index 0000000000000..3576aa52b753c --- /dev/null +++ b/tests/compile-fail/stacked_borrows/pointer_smuggling.rs @@ -0,0 +1,22 @@ +#![allow(unused_variables)] + +static mut PTR: *mut u8 = 0 as *mut _; + +fn fun1(x: &mut u8) { + unsafe { + PTR = x; + } +} + +fn fun2() { + // Now we use a pointer we are not allowed to use + let _x = unsafe { *PTR }; +} + +fn main() { + let val = &mut 0; // FIXME: This should also work with a local variable, but currently it does not. + fun1(val); + *val = 2; // this invalidates any raw ptrs `fun1` might have created. + fun2(); // if they now use a raw ptr they break our reference + *val = 3; //~ ERROR does not exist on the stack +} diff --git a/tests/compile-fail/stacked_borrows/shared_confusion.rs b/tests/compile-fail/stacked_borrows/shared_confusion.rs new file mode 100644 index 0000000000000..584053f59323b --- /dev/null +++ b/tests/compile-fail/stacked_borrows/shared_confusion.rs @@ -0,0 +1,21 @@ +#![allow(unused_variables)] +use std::cell::RefCell; + +fn test(r: &mut RefCell) { + let x = &*r; // not freezing because interior mutability + let mut x_ref = x.borrow_mut(); + let x_inner : &mut i32 = &mut *x_ref; // Uniq reference + let x_evil = x_inner as *mut _; + { + let x_inner_shr = &*x_inner; // frozen + let y = &*r; // outer ref, not freezing + let x_inner_shr2 = &*x_inner; // freezing again + } + // Our old raw should be dead by now + unsafe { *x_evil = 0; } // this falls back to some Raw higher up the stack + *x_inner = 12; //~ ERROR does not exist on the stack +} + +fn main() { + test(&mut RefCell::new(0)); +} diff --git a/tests/compile-fail/validation_illegal_write.rs b/tests/compile-fail/validation_illegal_write.rs deleted file mode 100644 index cb3e4b3c1a204..0000000000000 --- a/tests/compile-fail/validation_illegal_write.rs +++ /dev/null @@ -1,17 +0,0 @@ -// ignore-test validation_op is disabled - -#![allow(unused_variables)] - -mod safe { - pub(crate) fn safe(x: &u32) { - let x : &mut u32 = unsafe { &mut *(x as *const _ as *mut _) }; - *x = 42; //~ ERROR: in conflict with lock ReadLock - } -} - -fn main() { - let target = &mut 42; - let target_ref = ⌖ - // do a reborrow, but we keep the lock - safe::safe(&*target); -} diff --git a/tests/compile-fail/validation_lock_confusion.rs b/tests/compile-fail/validation_lock_confusion.rs deleted file mode 100644 index 2a0857659622f..0000000000000 --- a/tests/compile-fail/validation_lock_confusion.rs +++ /dev/null @@ -1,26 +0,0 @@ -// ignore-test validation_op is disabled - -// Make sure validation can handle many overlapping shared borrows for different parts of a data structure -#![allow(unused_variables)] -use std::cell::RefCell; - -fn evil(x: *mut i32) { - unsafe { *x = 0; } //~ ERROR: in conflict with lock WriteLock -} - -fn test(r: &mut RefCell) { - let x = &*r; // releasing write lock, first suspension recorded - let mut x_ref = x.borrow_mut(); - let x_inner : &mut i32 = &mut *x_ref; // new inner write lock, with same lifetime as outer lock - { - let x_inner_shr = &*x_inner; // releasing inner write lock, recording suspension - let y = &*r; // second suspension for the outer write lock - let x_inner_shr2 = &*x_inner; // 2nd suspension for inner write lock - } - // If the two locks are mixed up, here we should have a write lock, but we do not. - evil(x_inner as *mut _); -} - -fn main() { - test(&mut RefCell::new(0)); -} diff --git a/tests/compile-fail/validation_pointer_smuggling.rs b/tests/compile-fail/validation_pointer_smuggling.rs deleted file mode 100644 index 14d6242860382..0000000000000 --- a/tests/compile-fail/validation_pointer_smuggling.rs +++ /dev/null @@ -1,22 +0,0 @@ -// ignore-test validation_op is disabled - -#![allow(unused_variables)] - -static mut PTR: *mut u8 = 0 as *mut _; - -fn fun1(x: &mut u8) { - unsafe { - PTR = x; - } -} - -fn fun2() { - // Now we use a pointer we are not allowed to use - let _x = unsafe { *PTR }; //~ ERROR: in conflict with lock WriteLock -} - -fn main() { - let mut val = 0; - fun1(&mut val); - fun2(); -} diff --git a/tests/compile-fail/validation_recover1.rs b/tests/compile-fail/validation_recover1.rs deleted file mode 100644 index 9061070ef67eb..0000000000000 --- a/tests/compile-fail/validation_recover1.rs +++ /dev/null @@ -1,18 +0,0 @@ -// ignore-test validation_op is disabled - -#![allow(unused_variables)] - -#[repr(u32)] -enum Bool { True } - -mod safe { - pub(crate) fn safe(x: &mut super::Bool) { - let x = x as *mut _ as *mut u32; - unsafe { *x = 44; } // out-of-bounds enum discriminant - } -} - -fn main() { - let mut x = Bool::True; - safe::safe(&mut x); //~ ERROR: invalid enum discriminant -} diff --git a/tests/compile-fail/validation_recover2.rs b/tests/compile-fail/validation_recover2.rs deleted file mode 100644 index 7a4a417ab1db9..0000000000000 --- a/tests/compile-fail/validation_recover2.rs +++ /dev/null @@ -1,16 +0,0 @@ -// ignore-test validation_op is disabled - -#![allow(unused_variables)] - -mod safe { - // This makes a ref that was passed to us via &mut alias with things it should not alias with - pub(crate) fn safe(x: &mut &u32, target: &mut u32) { - unsafe { *x = &mut *(target as *mut _); } - } -} - -fn main() { - let target = &mut 42; - let mut target_alias = &42; // initial dummy value - safe::safe(&mut target_alias, target); //~ ERROR: in conflict with lock ReadLock -} diff --git a/tests/compile-fail/validation_recover3.rs b/tests/compile-fail/validation_recover3.rs deleted file mode 100644 index 5cfc8aaa66b5f..0000000000000 --- a/tests/compile-fail/validation_recover3.rs +++ /dev/null @@ -1,17 +0,0 @@ -// ignore-test validation_op is disabled - -#![allow(unused_variables)] - -mod safe { - pub(crate) fn safe(x: *mut u32) { - unsafe { *x = 42; } //~ ERROR: in conflict with lock WriteLock - } -} - -fn main() { - let target = &mut 42u32; - let target2 = target as *mut _; - drop(&mut *target); // reborrow - // Now make sure we still got the lock - safe::safe(target2); -} diff --git a/tests/compile-fail/validation_undef.rs b/tests/compile-fail/validation_undef.rs deleted file mode 100644 index 939e93a264e8c..0000000000000 --- a/tests/compile-fail/validation_undef.rs +++ /dev/null @@ -1,16 +0,0 @@ -// ignore-test validation_op is disabled - -#![allow(unused_variables)] -// error-pattern: attempted to read undefined bytes - -mod safe { - use std::mem; - - pub(crate) fn make_float() -> f32 { - unsafe { mem::uninitialized() } - } -} - -fn main() { - let _x = safe::make_float(); -} diff --git a/tests/compile-fail/validation_cast_fn_ptr1.rs b/tests/compile-fail/validity/cast_fn_ptr1.rs similarity index 100% rename from tests/compile-fail/validation_cast_fn_ptr1.rs rename to tests/compile-fail/validity/cast_fn_ptr1.rs diff --git a/tests/compile-fail/validation_cast_fn_ptr2.rs b/tests/compile-fail/validity/cast_fn_ptr2.rs similarity index 100% rename from tests/compile-fail/validation_cast_fn_ptr2.rs rename to tests/compile-fail/validity/cast_fn_ptr2.rs diff --git a/tests/compile-fail/invalid_bool.rs b/tests/compile-fail/validity/invalid_bool.rs similarity index 100% rename from tests/compile-fail/invalid_bool.rs rename to tests/compile-fail/validity/invalid_bool.rs diff --git a/tests/compile-fail/invalid_char.rs b/tests/compile-fail/validity/invalid_char.rs similarity index 100% rename from tests/compile-fail/invalid_char.rs rename to tests/compile-fail/validity/invalid_char.rs diff --git a/tests/compile-fail/invalid_enum_discriminant.rs b/tests/compile-fail/validity/invalid_enum_discriminant.rs similarity index 100% rename from tests/compile-fail/invalid_enum_discriminant.rs rename to tests/compile-fail/validity/invalid_enum_discriminant.rs diff --git a/tests/compile-fail/validity/transmute_through_ptr.rs b/tests/compile-fail/validity/transmute_through_ptr.rs new file mode 100644 index 0000000000000..0a4c64bb9bb11 --- /dev/null +++ b/tests/compile-fail/validity/transmute_through_ptr.rs @@ -0,0 +1,16 @@ +#![allow(unused_variables)] + +#[repr(u32)] +enum Bool { True } + +fn evil(x: &mut Bool) { + let x = x as *mut _ as *mut u32; + unsafe { *x = 44; } // out-of-bounds enum discriminant +} + +fn main() { + let mut x = Bool::True; + evil(&mut x); + let _y = x; // reading this ought to be enough to trigger validation + //~^ ERROR invalid enum discriminant 44 +} diff --git a/tests/compile-fail/validity/undef.rs b/tests/compile-fail/validity/undef.rs new file mode 100644 index 0000000000000..58d3926dadafa --- /dev/null +++ b/tests/compile-fail/validity/undef.rs @@ -0,0 +1,12 @@ +#![allow(unused_variables)] +// error-pattern: encountered undefined data in pointer + +use std::mem; + +fn make_raw() -> *const f32 { + unsafe { mem::uninitialized() } +} + +fn main() { + let _x = make_raw(); +} diff --git a/tests/compiletest.rs b/tests/compiletest.rs index b240fb31d2223..7bec3fa8de2cd 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -63,6 +63,7 @@ fn compile_fail(sysroot: &Path, path: &str, target: &str, host: &str, need_fullm flags.push(format!("--sysroot {}", sysroot.display())); flags.push("-Dwarnings -Dunused".to_owned()); // overwrite the -Aunused in compiletest-rs config.src_base = PathBuf::from(path.to_string()); + flags.push("-Zmir-opt-level=0".to_owned()); // optimization circumvents some stacked borrow checks flags.push("-Zmir-emit-validate=1".to_owned()); config.target_rustcflags = Some(flags.join(" ")); config.target = target.to_owned(); From b259512c5783f1ebda367a3094aecc5f9b7da7fd Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 17 Oct 2018 17:36:07 +0200 Subject: [PATCH 0271/3747] bump for ENABLE_PTR_TRACKING_HOOKS, and remove some dead code --- src/lib.rs | 18 ++---------------- src/stacked_borrows.rs | 26 -------------------------- 2 files changed, 2 insertions(+), 42 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index c910911f5762b..1ff29828dab49 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -264,8 +264,10 @@ type MiriEvalContext<'a, 'mir, 'tcx> = EvalContext<'a, 'mir, 'tcx, Evaluator<'tc impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { type MemoryKinds = MiriMemoryKind; + type AllocExtra = stacked_borrows::Stacks; type PointerTag = Borrow; + const ENABLE_PTR_TRACKING_HOOKS: bool = true; type MemoryMap = MonoHashMap, Allocation)>; @@ -433,22 +435,6 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { alloc.extra.memory_deallocated(ptr) } - /*/// Hook for when a reference is cast to a raw pointer - #[inline(always)] - fn ref_to_raw_cast( - ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, - ptr: Pointer, - ptr_ty: Ty<'tcx>, - size: Size, - ) -> EvalResult<'tcx> { - if !ecx.machine.validate { - // No tracking. - Ok(()) - } else { - ecx.ref_to_raw_cast(ptr, ptr_ty, size) - } - }*/ - #[inline(always)] fn tag_reference( ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index e4d2289bf34c7..19d5c723d403b 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -253,13 +253,6 @@ pub trait EvalContextExt<'tcx> { ptr: Pointer, ptr_ty: Ty<'tcx>, ) -> EvalResult<'tcx, Borrow>; - - fn ref_to_raw_cast( - &mut self, - ptr: Pointer, - ptr_ty: Ty<'tcx>, - size: Size, - ) -> EvalResult<'tcx>; } impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, 'tcx> { @@ -311,23 +304,4 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' ptr.tag }) } - - fn ref_to_raw_cast( - &mut self, - ptr: Pointer, - _ptr_ty: Ty<'tcx>, - size: Size, - ) -> EvalResult<'tcx> { - trace!("ref_to_raw_cast: Escaping {:?}", ptr); - - // Make sure this reference is not dangling or so - self.memory.check_bounds(ptr, size, false)?; - - // Update the stacks. We cannot use `get_mut` becuse this might be immutable - // memory. - let alloc = self.memory.get(ptr.alloc_id).expect("We checked that the ptr is fine!"); - alloc.extra.reborrow(ptr, size, Borrow::Mut(Mut::Raw))?; - - Ok(()) - } } From 4fa5bfa2bb1d985ef69a7c09b876fc4d5319ad13 Mon Sep 17 00:00:00 2001 From: Andrew Poelstra Date: Tue, 16 Oct 2018 18:06:24 +0000 Subject: [PATCH 0272/3747] add some comments to clarify command-line argument munging in #482 --- src/bin/cargo-miri.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 4cd2090133307..3deb5b5a314aa 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -99,6 +99,7 @@ fn main() { ); match (test, &kind[..]) { (true, "test") => { + // For test binaries we call `cargo rustc --test target -- ` if let Err(code) = process( vec!["--test".to_string(), target.name].into_iter().chain( args, @@ -109,6 +110,11 @@ fn main() { } } (true, "lib") => { + // For libraries we call `cargo rustc -- --test ` + // Notice now that `--test` is a rustc arg rather than a cargo arg. This tells + // rustc to build a test harness which calls all #[test] functions. We don't + // use the harness since we execute each #[test] function's MIR ourselves before + // compilation even completes, but this option is necessary to build the library. if let Err(code) = process( vec!["--".to_string(), "--test".to_string()].into_iter().chain( args, @@ -119,6 +125,7 @@ fn main() { } } (false, "bin") => { + // For ordinary binaries we call `cargo rustc --bin target -- ` if let Err(code) = process( vec!["--bin".to_string(), target.name].into_iter().chain( args, From b9fe91e48627cde55aaf9b55d016746db0b4907f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 18 Oct 2018 12:04:41 +0200 Subject: [PATCH 0273/3747] fix for ptr-to-raw casts properly erasing the tag --- tests/compile-fail/stacked_borrows/buggy_as_mut_slice.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/compile-fail/stacked_borrows/buggy_as_mut_slice.rs b/tests/compile-fail/stacked_borrows/buggy_as_mut_slice.rs index 3345668cee00c..4857ada7fb2c7 100644 --- a/tests/compile-fail/stacked_borrows/buggy_as_mut_slice.rs +++ b/tests/compile-fail/stacked_borrows/buggy_as_mut_slice.rs @@ -5,7 +5,7 @@ mod safe { pub fn as_mut_slice(self_: &Vec) -> &mut [T] { unsafe { - from_raw_parts_mut(self_.as_ptr() as *mut T, self_.len()) //~ ERROR shared borrow for mutation + from_raw_parts_mut(self_.as_ptr() as *mut T, self_.len()) } } } @@ -14,4 +14,6 @@ fn main() { let v = vec![0,1,2]; let v1 = safe::as_mut_slice(&v); let v2 = safe::as_mut_slice(&v); + v1[1] = 5; //~ ERROR does not exist on the stack + v1[1] = 6; } From 186e42d088bb485c156cef93f2d27aa461523fad Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 19 Oct 2018 09:51:04 +0200 Subject: [PATCH 0274/3747] move resolve_path to helpers module --- src/fn_call.rs | 40 +---------------------------------- src/helpers.rs | 54 ++++++++++++++++++++++++++++++++++++++++++++---- src/intrinsic.rs | 2 +- src/lib.rs | 3 ++- 4 files changed, 54 insertions(+), 45 deletions(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index 812df49b0b8fa..ce5b17e7b5775 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -1,11 +1,9 @@ use rustc::ty; use rustc::ty::layout::{Align, LayoutOf, Size}; -use rustc::hir::def_id::{DefId, CRATE_DEF_INDEX}; +use rustc::hir::def_id::DefId; use rustc::mir; use syntax::attr; -use std::mem; - use super::*; pub trait EvalContextExt<'tcx, 'mir> { @@ -19,8 +17,6 @@ pub trait EvalContextExt<'tcx, 'mir> { ret: mir::BasicBlock, ) -> EvalResult<'tcx>; - fn resolve_path(&self, path: &[&str]) -> EvalResult<'tcx, ty::Instance<'tcx>>; - /// Emulate a function that should have MIR but does not. /// This is solely to support execution without full MIR. /// Fail if emulating this function is not supported. @@ -638,40 +634,6 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for EvalContext<'a, ' Ok(()) } - /// Get an instance for a path. - fn resolve_path(&self, path: &[&str]) -> EvalResult<'tcx, ty::Instance<'tcx>> { - self.tcx - .crates() - .iter() - .find(|&&krate| self.tcx.original_crate_name(krate) == path[0]) - .and_then(|krate| { - let krate = DefId { - krate: *krate, - index: CRATE_DEF_INDEX, - }; - let mut items = self.tcx.item_children(krate); - let mut path_it = path.iter().skip(1).peekable(); - - while let Some(segment) = path_it.next() { - for item in mem::replace(&mut items, Default::default()).iter() { - if item.ident.name == *segment { - if path_it.peek().is_none() { - return Some(ty::Instance::mono(self.tcx.tcx, item.def.def_id())); - } - - items = self.tcx.item_children(item.def.def_id()); - break; - } - } - } - None - }) - .ok_or_else(|| { - let path = path.iter().map(|&s| s.to_owned()).collect(); - EvalErrorKind::PathNotFound(path).into() - }) - } - fn emulate_missing_fn( &mut self, path: String, diff --git a/src/helpers.rs b/src/helpers.rs index 27b2109d18a16..1c63316f60806 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -1,13 +1,18 @@ -use super::{Scalar, ScalarMaybeUndef, EvalResult}; +use std::mem; -pub trait FalibleScalarExt { +use rustc::ty; +use rustc::hir::def_id::{DefId, CRATE_DEF_INDEX}; + +use super::*; + +pub trait ScalarExt { /// 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 fn to_bytes(self) -> EvalResult<'static, u128>; } -impl FalibleScalarExt for Scalar { +impl ScalarExt for Scalar { fn to_bytes(self) -> EvalResult<'static, u128> { match self { Scalar::Bits { bits, size } => { @@ -19,8 +24,49 @@ impl FalibleScalarExt for Scalar { } } -impl FalibleScalarExt for ScalarMaybeUndef { +impl ScalarExt for ScalarMaybeUndef { fn to_bytes(self) -> EvalResult<'static, u128> { self.not_undef()?.to_bytes() } } + +pub trait EvalContextExt<'tcx> { + fn resolve_path(&self, path: &[&str]) -> EvalResult<'tcx, ty::Instance<'tcx>>; +} + + +impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super::Evaluator<'tcx>> { + /// Get an instance for a path. + fn resolve_path(&self, path: &[&str]) -> EvalResult<'tcx, ty::Instance<'tcx>> { + self.tcx + .crates() + .iter() + .find(|&&krate| self.tcx.original_crate_name(krate) == path[0]) + .and_then(|krate| { + let krate = DefId { + krate: *krate, + index: CRATE_DEF_INDEX, + }; + let mut items = self.tcx.item_children(krate); + let mut path_it = path.iter().skip(1).peekable(); + + while let Some(segment) = path_it.next() { + for item in mem::replace(&mut items, Default::default()).iter() { + if item.ident.name == *segment { + if path_it.peek().is_none() { + return Some(ty::Instance::mono(self.tcx.tcx, item.def.def_id())); + } + + items = self.tcx.item_children(item.def.def_id()); + break; + } + } + } + None + }) + .ok_or_else(|| { + let path = path.iter().map(|&s| s.to_owned()).collect(); + EvalErrorKind::PathNotFound(path).into() + }) + } +} diff --git a/src/intrinsic.rs b/src/intrinsic.rs index 19c4f04f4826e..9e209af98e3af 100644 --- a/src/intrinsic.rs +++ b/src/intrinsic.rs @@ -7,7 +7,7 @@ use rustc_mir::interpret::{EvalContext, PlaceTy, OpTy}; use super::{ Value, Scalar, ScalarMaybeUndef, - FalibleScalarExt, OperatorEvalContextExt + ScalarExt, OperatorEvalContextExt }; pub trait EvalContextExt<'tcx> { diff --git a/src/lib.rs b/src/lib.rs index 0bebe40d529af..ec2bc4a69f4e6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -43,7 +43,8 @@ use operator::EvalContextExt as OperatorEvalContextExt; use intrinsic::EvalContextExt as IntrinsicEvalContextExt; use tls::{EvalContextExt as TlsEvalContextExt, TlsData}; use range_map::RangeMap; -use helpers::FalibleScalarExt; +#[allow(unused_imports)] // FIXME rustc bug https://github.com/rust-lang/rust/issues/53682 +use helpers::{ScalarExt, EvalContextExt as HelpersEvalContextExt}; use mono_hash_map::MonoHashMap; pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( From 0b6e3494177d436c64bb80e71662ea54ad2aeaa9 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 19 Oct 2018 10:07:17 +0200 Subject: [PATCH 0275/3747] automalically use start-fn if we have all the MIR --- .travis.yml | 4 ++-- src/bin/miri-rustc-tests.rs | 4 ++-- src/bin/miri.rs | 25 +++---------------------- src/lib.rs | 14 +++++++++----- tests/compiletest.rs | 3 --- 5 files changed, 16 insertions(+), 34 deletions(-) diff --git a/.travis.yml b/.travis.yml index 9b4f75ab29cf6..d2315c7e9538e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -50,9 +50,9 @@ script: # test `cargo miri` cd cargo-miri-test && if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then - cargo miri -q -- -Zmiri-start-fn + cargo miri -q else - cargo miri -q -- -Zmiri-start-fn >stdout.real 2>stderr.real && + cargo miri -q >stdout.real 2>stderr.real && cat stdout.real stderr.real && # Test `cargo miri` output. Not on mac because output redirecting doesn't # work. There is no error. It just stops CI. diff --git a/src/bin/miri-rustc-tests.rs b/src/bin/miri-rustc-tests.rs index 73a8d19c309b2..fb3b231d41cef 100644 --- a/src/bin/miri-rustc-tests.rs +++ b/src/bin/miri-rustc-tests.rs @@ -95,7 +95,7 @@ fn after_analysis<'a, 'tcx>(state: &mut CompileState<'a, 'tcx>) { if i.attrs.iter().any(|attr| attr.name() == "test") { let did = self.0.hir.body_owner_def_id(body_id); println!("running test: {}", self.0.def_path_debug_str(did)); - miri::eval_main(self.0, did, None, /*validate*/true); + miri::eval_main(self.0, did, /*validate*/true); self.1.session.abort_if_errors(); } } @@ -106,7 +106,7 @@ fn after_analysis<'a, 'tcx>(state: &mut CompileState<'a, 'tcx>) { state.hir_crate.unwrap().visit_all_item_likes(&mut Visitor(tcx, state)); } else if let Some((entry_node_id, _, _)) = *state.session.entry_fn.borrow() { let entry_def_id = tcx.hir.local_def_id(entry_node_id); - miri::eval_main(tcx, entry_def_id, None, /*validate*/true); + miri::eval_main(tcx, entry_def_id, /*validate*/true); state.session.abort_if_errors(); } else { diff --git a/src/bin/miri.rs b/src/bin/miri.rs index d7207da0b3c08..d4494a8388527 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -26,11 +26,6 @@ use std::path::PathBuf; struct MiriCompilerCalls { default: Box, - /// Whether to begin interpretation at the start_fn lang item or not. - /// - /// If false, the interpretation begins at the `main` function. - start_fn: bool, - /// Whether to enforce the validity invariant. validate: bool, } @@ -90,10 +85,9 @@ impl<'a> CompilerCalls<'a> for MiriCompilerCalls { let this = *self; let mut control = this.default.build_controller(sess, matches); control.after_hir_lowering.callback = Box::new(after_hir_lowering); - let start_fn = this.start_fn; let validate = this.validate; control.after_analysis.callback = - Box::new(move |state| after_analysis(state, start_fn, validate)); + Box::new(move |state| after_analysis(state, validate)); control.after_analysis.stop = Compilation::Stop; control } @@ -109,7 +103,6 @@ fn after_hir_lowering(state: &mut CompileState) { fn after_analysis<'a, 'tcx>( state: &mut CompileState<'a, 'tcx>, - use_start_fn: bool, validate: bool, ) { state.session.abort_if_errors(); @@ -134,7 +127,7 @@ fn after_analysis<'a, 'tcx>( "running test: {}", self.tcx.def_path_debug_str(did), ); - miri::eval_main(self.tcx, did, None, self.validate); + miri::eval_main(self.tcx, did, self.validate); self.state.session.abort_if_errors(); } } @@ -147,13 +140,7 @@ fn after_analysis<'a, 'tcx>( ); } else if let Some((entry_node_id, _, _)) = *state.session.entry_fn.borrow() { let entry_def_id = tcx.hir.local_def_id(entry_node_id); - // Use start_fn lang item if we have -Zmiri-start-fn set - let start_wrapper = if use_start_fn { - Some(tcx.lang_items().start_fn().unwrap()) - } else { - None - }; - miri::eval_main(tcx, entry_def_id, start_wrapper, validate); + miri::eval_main(tcx, entry_def_id, validate); state.session.abort_if_errors(); } else { @@ -231,14 +218,9 @@ fn main() { args.push(find_sysroot()); } - let mut start_fn = false; let mut validate = true; args.retain(|arg| { match arg.as_str() { - "-Zmiri-start-fn" => { - start_fn = true; - false - }, "-Zmiri-disable-validation" => { validate = false; false @@ -251,7 +233,6 @@ fn main() { let result = rustc_driver::run(move || { rustc_driver::run_compiler(&args, Box::new(MiriCompilerCalls { default: Box::new(RustcDefaultCalls), - start_fn, validate, }), None, None) }); diff --git a/src/lib.rs b/src/lib.rs index ec2bc4a69f4e6..eba88a88487e0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -50,7 +50,6 @@ use mono_hash_map::MonoHashMap; pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( tcx: TyCtxt<'a, 'tcx, 'tcx>, main_id: DefId, - start_wrapper: Option, validate: bool, ) -> EvalResult<'tcx, EvalContext<'a, 'mir, 'tcx, Evaluator<'tcx>>> { let mut ecx = EvalContext::new( @@ -70,8 +69,14 @@ pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( )); } - if let Some(start_id) = start_wrapper { - let main_ret_ty = ecx.tcx.fn_sig(main_id).output(); + let libstd_has_mir = { + let rustc_panic = ecx.resolve_path(&["std", "panicking", "rust_panic"])?; + ecx.load_mir(rustc_panic.def).is_ok() + }; + + if libstd_has_mir { + let start_id = tcx.lang_items().start_fn().unwrap(); + let main_ret_ty = tcx.fn_sig(main_id).output(); let main_ret_ty = main_ret_ty.no_late_bound_regions().unwrap(); let start_instance = ty::Instance::resolve( ecx.tcx.tcx, @@ -146,10 +151,9 @@ pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( pub fn eval_main<'a, 'tcx: 'a>( tcx: TyCtxt<'a, 'tcx, 'tcx>, main_id: DefId, - start_wrapper: Option, validate: bool, ) { - let mut ecx = create_ecx(tcx, main_id, start_wrapper, validate).expect("Couldn't create ecx"); + let mut ecx = create_ecx(tcx, main_id, validate).expect("Couldn't create ecx"); let res: EvalResult = (|| { ecx.run()?; diff --git a/tests/compiletest.rs b/tests/compiletest.rs index b240fb31d2223..fa57df94dabc2 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -100,9 +100,6 @@ fn miri_pass(sysroot: &Path, path: &str, target: &str, host: &str, need_fullmir: let mut flags = Vec::new(); flags.push(format!("--sysroot {}", sysroot.display())); flags.push("-Dwarnings -Dunused".to_owned()); // overwrite the -Aunused in compiletest-rs - if have_fullmir() { - flags.push("-Zmiri-start-fn".to_owned()); - } if opt { // FIXME: Using level 1 (instead of 3) for now, as the optimizer is pretty broken // and crashes... From 069b661a10773bf5f9753ccf556fd101f6b492d6 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 19 Oct 2018 10:09:53 +0200 Subject: [PATCH 0276/3747] typo --- src/fn_call.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index ce5b17e7b5775..0a46c6a1fdb41 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -661,7 +661,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for EvalContext<'a, ' "std::io::_print" | "std::io::_eprint" => { warn!( - "Ignoring output. To run programs that print, make sure you have a libstd with full MIR." + "Ignoring output. To run programs that prints, make sure you have a libstd with full MIR." ); } "std::thread::Builder::new" => { From 8134918390d29d591c0078e3ecf71cdeb20687b5 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 19 Oct 2018 11:50:17 +0200 Subject: [PATCH 0277/3747] don't use NOTE in tests --- tests/compile-fail-fullmir/reallocate-change-alloc.rs | 3 +-- tests/compile-fail/alignment.rs | 3 +-- tests/compile-fail/assume.rs | 3 +-- tests/compile-fail/bitop-beyond-alignment.rs | 5 ++--- tests/compile-fail/cast_box_int_to_fn_ptr.rs | 3 +-- tests/compile-fail/cast_int_to_fn_ptr.rs | 3 +-- tests/compile-fail/dangling_pointer_deref.rs | 3 +-- tests/compile-fail/div-by-zero-2.rs | 3 +-- tests/compile-fail/execute_memory.rs | 3 +-- tests/compile-fail/fn_ptr_offset.rs | 3 +-- tests/compile-fail/modifying_constants.rs | 3 +-- tests/compile-fail/never_say_never.rs | 3 +-- tests/compile-fail/never_transmute_void.rs | 3 +-- tests/compile-fail/out_of_bounds_read.rs | 3 +-- tests/compile-fail/out_of_bounds_read2.rs | 3 +-- tests/compile-fail/overflowing-lsh-neg.rs | 3 +-- tests/compile-fail/overflowing-rsh-2.rs | 3 +-- tests/compile-fail/overflowing-rsh.rs | 3 +-- ...verwriting_part_of_relocation_makes_the_rest_undefined.rs | 3 +-- tests/compile-fail/pointer_byte_read_2.rs | 3 +-- .../pointers_to_different_allocations_are_unorderable.rs | 3 +-- tests/compile-fail/ptr_int_cast.rs | 3 +-- tests/compile-fail/reading_half_a_pointer.rs | 3 +-- tests/compile-fail/reference_to_packed.rs | 3 +-- tests/compile-fail/static_memory_modification.rs | 3 +-- tests/compile-fail/static_memory_modification2.rs | 3 +-- tests/compile-fail/static_memory_modification3.rs | 3 +-- tests/compile-fail/transmute-pair-undef.rs | 3 +-- tests/compile-fail/transmute_fat.rs | 3 +-- tests/compile-fail/transmute_fat2.rs | 3 +-- tests/compile-fail/unaligned_ptr_cast.rs | 3 +-- tests/compile-fail/unaligned_ptr_cast2.rs | 3 +-- tests/compile-fail/unaligned_ptr_cast_zst.rs | 3 +-- tests/compile-fail/undefined_byte_read.rs | 3 +-- tests/compile-fail/wild_pointer_deref.rs | 3 +-- tests/compile-fail/zst.rs | 3 +-- 36 files changed, 37 insertions(+), 73 deletions(-) diff --git a/tests/compile-fail-fullmir/reallocate-change-alloc.rs b/tests/compile-fail-fullmir/reallocate-change-alloc.rs index c73f86bc1721c..1e2178811ea3a 100644 --- a/tests/compile-fail-fullmir/reallocate-change-alloc.rs +++ b/tests/compile-fail-fullmir/reallocate-change-alloc.rs @@ -9,7 +9,6 @@ fn main() { unsafe { let x = Global.alloc(Layout::from_size_align_unchecked(1, 1)).unwrap(); Global.realloc(x, Layout::from_size_align_unchecked(1, 1), 1).unwrap(); - let _z = *(x.as_ptr() as *mut u8); //~ ERROR constant evaluation error - //~^ NOTE dangling pointer was dereferenced + let _z = *(x.as_ptr() as *mut u8); //~ ERROR dangling pointer was dereferenced } } diff --git a/tests/compile-fail/alignment.rs b/tests/compile-fail/alignment.rs index 71161f5d6da00..4faaa359df624 100644 --- a/tests/compile-fail/alignment.rs +++ b/tests/compile-fail/alignment.rs @@ -5,8 +5,7 @@ fn main() { let x_ptr: *mut u8 = &mut x[0]; let y_ptr = x_ptr as *mut u64; unsafe { - *y_ptr = 42; //~ ERROR constant evaluation error - //~^ NOTE tried to access memory with alignment 1, but alignment + *y_ptr = 42; //~ ERROR tried to access memory with alignment 1, but alignment } panic!("unreachable in miri"); } diff --git a/tests/compile-fail/assume.rs b/tests/compile-fail/assume.rs index d9eec480cd0c6..3026124e1f9af 100644 --- a/tests/compile-fail/assume.rs +++ b/tests/compile-fail/assume.rs @@ -5,7 +5,6 @@ fn main() { unsafe { std::intrinsics::assume(x < 10); std::intrinsics::assume(x > 1); - std::intrinsics::assume(x > 42); //~ ERROR constant evaluation error - //~^ NOTE `assume` argument was false + std::intrinsics::assume(x > 42); //~ `assume` argument was false } } diff --git a/tests/compile-fail/bitop-beyond-alignment.rs b/tests/compile-fail/bitop-beyond-alignment.rs index c8cbc9a918416..a30c054ab5d04 100644 --- a/tests/compile-fail/bitop-beyond-alignment.rs +++ b/tests/compile-fail/bitop-beyond-alignment.rs @@ -28,11 +28,10 @@ fn mk_rec() -> Rec { fn is_u64_aligned(u: &Tag) -> bool { let p: usize = unsafe { mem::transmute(u) }; let u64_align = std::mem::align_of::(); - return (p & (u64_align + 1)) == 0; //~ ERROR constant evaluation error - //~^ NOTE a raw memory access tried to access part of a pointer value as raw bytes + return (p & (u64_align + 1)) == 0; //~ ERROR a raw memory access tried to access part of a pointer value as raw bytes } pub fn main() { let x = mk_rec(); - assert!(is_u64_aligned(&x.t)); //~ NOTE inside call to `is_u64_aligned + assert!(is_u64_aligned(&x.t)); } diff --git a/tests/compile-fail/cast_box_int_to_fn_ptr.rs b/tests/compile-fail/cast_box_int_to_fn_ptr.rs index cbf370e023630..c3b1fa5958885 100644 --- a/tests/compile-fail/cast_box_int_to_fn_ptr.rs +++ b/tests/compile-fail/cast_box_int_to_fn_ptr.rs @@ -7,6 +7,5 @@ fn main() { std::mem::transmute::<&usize, &fn(i32)>(&b) }; - (*g)(42) //~ ERROR constant evaluation error - //~^ NOTE a memory access tried to interpret some bytes as a pointer + (*g)(42) //~ ERROR a memory access tried to interpret some bytes as a pointer } diff --git a/tests/compile-fail/cast_int_to_fn_ptr.rs b/tests/compile-fail/cast_int_to_fn_ptr.rs index 2a08d9f1f9f85..1971ce1557e79 100644 --- a/tests/compile-fail/cast_int_to_fn_ptr.rs +++ b/tests/compile-fail/cast_int_to_fn_ptr.rs @@ -6,6 +6,5 @@ fn main() { std::mem::transmute::(42) }; - g(42) //~ ERROR constant evaluation error - //~^ NOTE a memory access tried to interpret some bytes as a pointer + g(42) //~ ERROR a memory access tried to interpret some bytes as a pointer } diff --git a/tests/compile-fail/dangling_pointer_deref.rs b/tests/compile-fail/dangling_pointer_deref.rs index 434f5c780b46f..e807207730573 100644 --- a/tests/compile-fail/dangling_pointer_deref.rs +++ b/tests/compile-fail/dangling_pointer_deref.rs @@ -3,7 +3,6 @@ fn main() { let b = Box::new(42); &*b as *const i32 }; - let x = unsafe { *p }; //~ ERROR constant evaluation error - //~^ NOTE dangling pointer was dereferenced + let x = unsafe { *p }; //~ ERROR dangling pointer was dereferenced panic!("this should never print: {}", x); } diff --git a/tests/compile-fail/div-by-zero-2.rs b/tests/compile-fail/div-by-zero-2.rs index 94145c2cf32f3..181a41ce3b23e 100644 --- a/tests/compile-fail/div-by-zero-2.rs +++ b/tests/compile-fail/div-by-zero-2.rs @@ -11,6 +11,5 @@ #![allow(const_err)] fn main() { - let _n = 1 / 0; //~ ERROR constant evaluation error - //~^ NOTE attempt to divide by zero + let _n = 1 / 0; //~ ERROR attempt to divide by zero } diff --git a/tests/compile-fail/execute_memory.rs b/tests/compile-fail/execute_memory.rs index 2f8fea38d8f9f..d859e9072e324 100644 --- a/tests/compile-fail/execute_memory.rs +++ b/tests/compile-fail/execute_memory.rs @@ -7,7 +7,6 @@ fn main() { let x = box 42; unsafe { let f = std::mem::transmute::, fn()>(x); - f() //~ ERROR constant evaluation error - //~^ NOTE tried to treat a memory pointer as a function pointer + f() //~ ERROR tried to treat a memory pointer as a function pointer } } diff --git a/tests/compile-fail/fn_ptr_offset.rs b/tests/compile-fail/fn_ptr_offset.rs index e6d1da1e0736a..cccb21790d650 100644 --- a/tests/compile-fail/fn_ptr_offset.rs +++ b/tests/compile-fail/fn_ptr_offset.rs @@ -10,6 +10,5 @@ fn main() { let y : *mut u8 = unsafe { mem::transmute(x) }; let y = y.wrapping_offset(1); let x : fn() = unsafe { mem::transmute(y) }; - x(); //~ ERROR constant evaluation error - //~^ NOTE tried to use a function pointer after offsetting it + x(); //~ ERROR tried to use a function pointer after offsetting it } diff --git a/tests/compile-fail/modifying_constants.rs b/tests/compile-fail/modifying_constants.rs index ba46651f58ee4..27c74e8dc87ee 100644 --- a/tests/compile-fail/modifying_constants.rs +++ b/tests/compile-fail/modifying_constants.rs @@ -2,7 +2,6 @@ fn main() { let x = &1; // the `&1` is promoted to a constant, but it used to be that only the pointer is marked static, not the pointee let y = unsafe { &mut *(x as *const i32 as *mut i32) }; - *y = 42; //~ ERROR constant evaluation error - //~^ NOTE tried to modify constant memory + *y = 42; //~ ERROR tried to modify constant memory assert_eq!(*x, 42); } diff --git a/tests/compile-fail/never_say_never.rs b/tests/compile-fail/never_say_never.rs index 9821723deb3bc..634488489b539 100644 --- a/tests/compile-fail/never_say_never.rs +++ b/tests/compile-fail/never_say_never.rs @@ -7,8 +7,7 @@ fn main() { let y = &5; let x: ! = unsafe { - *(y as *const _ as *const !) //~ ERROR constant evaluation error - //~^ NOTE entered unreachable code + *(y as *const _ as *const !) //~ ERROR entered unreachable code }; f(x) } diff --git a/tests/compile-fail/never_transmute_void.rs b/tests/compile-fail/never_transmute_void.rs index 11fc0f068de0d..5620b6559cfde 100644 --- a/tests/compile-fail/never_transmute_void.rs +++ b/tests/compile-fail/never_transmute_void.rs @@ -8,8 +8,7 @@ enum Void {} fn f(v: Void) -> ! { - match v {} //~ ERROR constant evaluation error - //~^ NOTE entered unreachable code + match v {} //~ ERROR entered unreachable code } fn main() { diff --git a/tests/compile-fail/out_of_bounds_read.rs b/tests/compile-fail/out_of_bounds_read.rs index 3ccdb365feebc..1ab2d97147792 100644 --- a/tests/compile-fail/out_of_bounds_read.rs +++ b/tests/compile-fail/out_of_bounds_read.rs @@ -1,6 +1,5 @@ fn main() { let v: Vec = vec![1, 2]; - let x = unsafe { *v.as_ptr().wrapping_offset(5) }; //~ ERROR constant evaluation error - //~^ NOTE which has size 2 + let x = unsafe { *v.as_ptr().wrapping_offset(5) }; //~ ERROR outside bounds of allocation panic!("this should never print: {}", x); } diff --git a/tests/compile-fail/out_of_bounds_read2.rs b/tests/compile-fail/out_of_bounds_read2.rs index e8bcf4558401c..1ab2d97147792 100644 --- a/tests/compile-fail/out_of_bounds_read2.rs +++ b/tests/compile-fail/out_of_bounds_read2.rs @@ -1,6 +1,5 @@ fn main() { let v: Vec = vec![1, 2]; - let x = unsafe { *v.as_ptr().wrapping_offset(5) }; //~ ERROR constant evaluation error - //~^ NOTE outside bounds of allocation + let x = unsafe { *v.as_ptr().wrapping_offset(5) }; //~ ERROR outside bounds of allocation panic!("this should never print: {}", x); } diff --git a/tests/compile-fail/overflowing-lsh-neg.rs b/tests/compile-fail/overflowing-lsh-neg.rs index 825a822266349..8c70c9c7df7dd 100644 --- a/tests/compile-fail/overflowing-lsh-neg.rs +++ b/tests/compile-fail/overflowing-lsh-neg.rs @@ -12,6 +12,5 @@ #![allow(const_err)] fn main() { - let _n = 2i64 << -1; //~ ERROR constant evaluation error - //~^ NOTE attempt to shift left with overflow + let _n = 2i64 << -1; //~ ERROR attempt to shift left with overflow } diff --git a/tests/compile-fail/overflowing-rsh-2.rs b/tests/compile-fail/overflowing-rsh-2.rs index cf107a76ae29d..7b7486343c335 100644 --- a/tests/compile-fail/overflowing-rsh-2.rs +++ b/tests/compile-fail/overflowing-rsh-2.rs @@ -12,6 +12,5 @@ fn main() { // Make sure we catch overflows that would be hidden by first casting the RHS to u32 - let _n = 1i64 >> (u32::max_value() as i64 + 1); //~ ERROR constant evaluation error - //~^ NOTE attempt to shift right with overflow + let _n = 1i64 >> (u32::max_value() as i64 + 1); //~ ERROR attempt to shift right with overflow } diff --git a/tests/compile-fail/overflowing-rsh.rs b/tests/compile-fail/overflowing-rsh.rs index ea53d7e730925..355cbd8698888 100644 --- a/tests/compile-fail/overflowing-rsh.rs +++ b/tests/compile-fail/overflowing-rsh.rs @@ -11,6 +11,5 @@ #![allow(exceeding_bitshifts)] fn main() { - let _n = 1i64 >> 64; //~ ERROR constant evaluation error - //~^ NOTE attempt to shift right with overflow + let _n = 1i64 >> 64; //~ ERROR attempt to shift right with overflow } diff --git a/tests/compile-fail/overwriting_part_of_relocation_makes_the_rest_undefined.rs b/tests/compile-fail/overwriting_part_of_relocation_makes_the_rest_undefined.rs index 7c38c05746983..5c0d5b463d51f 100644 --- a/tests/compile-fail/overwriting_part_of_relocation_makes_the_rest_undefined.rs +++ b/tests/compile-fail/overwriting_part_of_relocation_makes_the_rest_undefined.rs @@ -6,7 +6,6 @@ fn main() { // "attempted to interpret some raw bytes as a pointer address" instead of // "attempted to read undefined bytes" } - let x = *p; //~ ERROR constant evaluation error - //~^ NOTE attempted to read undefined bytes + let x = *p; //~ ERROR attempted to read undefined bytes panic!("this should never print: {}", x); } diff --git a/tests/compile-fail/pointer_byte_read_2.rs b/tests/compile-fail/pointer_byte_read_2.rs index c8a1a2e10f500..5df8c4782c7f8 100644 --- a/tests/compile-fail/pointer_byte_read_2.rs +++ b/tests/compile-fail/pointer_byte_read_2.rs @@ -3,6 +3,5 @@ fn main() { let y = &x; let z = &y as *const &i32 as *const u8; // the deref fails, because we are reading only a part of the pointer - let _ = unsafe { *z }; //~ ERROR constant evaluation error - //~^ NOTE tried to access part of a pointer value as raw bytes + let _ = unsafe { *z }; //~ ERROR tried to access part of a pointer value as raw bytes } diff --git a/tests/compile-fail/pointers_to_different_allocations_are_unorderable.rs b/tests/compile-fail/pointers_to_different_allocations_are_unorderable.rs index 89cf357e201cf..124f84de5bf45 100644 --- a/tests/compile-fail/pointers_to_different_allocations_are_unorderable.rs +++ b/tests/compile-fail/pointers_to_different_allocations_are_unorderable.rs @@ -1,8 +1,7 @@ fn main() { let x: *const u8 = &1; let y: *const u8 = &2; - if x < y { //~ ERROR constant evaluation error - //~^ NOTE attempted to do invalid arithmetic on pointers + if x < y { //~ ERROR attempted to do invalid arithmetic on pointers unreachable!() } } diff --git a/tests/compile-fail/ptr_int_cast.rs b/tests/compile-fail/ptr_int_cast.rs index 11243921bfd48..576f0c333d189 100644 --- a/tests/compile-fail/ptr_int_cast.rs +++ b/tests/compile-fail/ptr_int_cast.rs @@ -2,8 +2,7 @@ fn main() { let x = &1; // Casting down to u8 and back up to a pointer loses too much precision; this must not work. let x = x as *const i32; - let x = x as u8; //~ ERROR constant evaluation error - //~^ NOTE a raw memory access tried to access part of a pointer value as raw bytes + let x = x as u8; //~ ERROR a raw memory access tried to access part of a pointer value as raw bytes let x = x as *const i32; let _ = unsafe { *x }; } diff --git a/tests/compile-fail/reading_half_a_pointer.rs b/tests/compile-fail/reading_half_a_pointer.rs index 3ea693a3f0fbb..049dfca340ed9 100644 --- a/tests/compile-fail/reading_half_a_pointer.rs +++ b/tests/compile-fail/reading_half_a_pointer.rs @@ -24,7 +24,6 @@ fn main() { // starts 1 byte to the right, so using it would actually be wrong! let d_alias = &mut w.data as *mut _ as *mut *const u8; unsafe { - let _x = *d_alias; //~ ERROR constant evaluation error - //~^ NOTE tried to access part of a pointer value as raw bytes + let _x = *d_alias; //~ ERROR tried to access part of a pointer value as raw bytes } } diff --git a/tests/compile-fail/reference_to_packed.rs b/tests/compile-fail/reference_to_packed.rs index d18f314c8aaa1..14a2afc33f7fe 100644 --- a/tests/compile-fail/reference_to_packed.rs +++ b/tests/compile-fail/reference_to_packed.rs @@ -15,6 +15,5 @@ fn main() { y: 99, }; let p = unsafe { &foo.x }; - let i = *p; //~ ERROR constant evaluation error - //~^ NOTE tried to access memory with alignment 1, but alignment 4 is required + let i = *p; //~ ERROR tried to access memory with alignment 1, but alignment 4 is required } diff --git a/tests/compile-fail/static_memory_modification.rs b/tests/compile-fail/static_memory_modification.rs index 9e39c2c01c2b2..304ab6c6b7409 100644 --- a/tests/compile-fail/static_memory_modification.rs +++ b/tests/compile-fail/static_memory_modification.rs @@ -3,8 +3,7 @@ static X: usize = 5; #[allow(mutable_transmutes)] fn main() { unsafe { - *std::mem::transmute::<&usize, &mut usize>(&X) = 6; //~ ERROR constant evaluation error - //~^ NOTE tried to modify constant memory + *std::mem::transmute::<&usize, &mut usize>(&X) = 6; //~ ERROR tried to modify constant memory assert_eq!(X, 6); } } diff --git a/tests/compile-fail/static_memory_modification2.rs b/tests/compile-fail/static_memory_modification2.rs index 2f702f09c8047..01c3b9bb2d8da 100644 --- a/tests/compile-fail/static_memory_modification2.rs +++ b/tests/compile-fail/static_memory_modification2.rs @@ -7,7 +7,6 @@ use std::mem::transmute; fn main() { unsafe { let s = "this is a test"; - transmute::<&[u8], &mut [u8]>(s.as_bytes())[4] = 42; //~ ERROR constant evaluation error - //~^ NOTE tried to modify constant memory + transmute::<&[u8], &mut [u8]>(s.as_bytes())[4] = 42; //~ ERROR tried to modify constant memory } } diff --git a/tests/compile-fail/static_memory_modification3.rs b/tests/compile-fail/static_memory_modification3.rs index 37d8bfe02ceb2..ff09aad1bd564 100644 --- a/tests/compile-fail/static_memory_modification3.rs +++ b/tests/compile-fail/static_memory_modification3.rs @@ -4,7 +4,6 @@ use std::mem::transmute; fn main() { unsafe { let bs = b"this is a test"; - transmute::<&[u8], &mut [u8]>(bs)[4] = 42; //~ ERROR constant evaluation error - //~^ NOTE tried to modify constant memory + transmute::<&[u8], &mut [u8]>(bs)[4] = 42; //~ ERROR tried to modify constant memory } } diff --git a/tests/compile-fail/transmute-pair-undef.rs b/tests/compile-fail/transmute-pair-undef.rs index 9509bb60e8b11..acc6098af7ee0 100644 --- a/tests/compile-fail/transmute-pair-undef.rs +++ b/tests/compile-fail/transmute-pair-undef.rs @@ -16,6 +16,5 @@ fn main() { assert_eq!(byte, 0); } let v = unsafe { *z.offset(first_undef) }; - if v == 0 {} //~ ERROR constant evaluation error - //~^ NOTE attempted to read undefined bytes + if v == 0 {} //~ ERROR attempted to read undefined bytes } diff --git a/tests/compile-fail/transmute_fat.rs b/tests/compile-fail/transmute_fat.rs index 3e3bf51c3f277..e1f916910d732 100644 --- a/tests/compile-fail/transmute_fat.rs +++ b/tests/compile-fail/transmute_fat.rs @@ -10,6 +10,5 @@ fn main() { let bad = unsafe { std::mem::transmute::<&[u8], [u8; 8]>(&[1u8]) }; - 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 + let _ = bad[0] + bad[bad.len()-1]; //~ ERROR a raw memory access tried to access part of a pointer value as raw bytes } diff --git a/tests/compile-fail/transmute_fat2.rs b/tests/compile-fail/transmute_fat2.rs index e9e21a84294dc..3121a139d9204 100644 --- a/tests/compile-fail/transmute_fat2.rs +++ b/tests/compile-fail/transmute_fat2.rs @@ -7,6 +7,5 @@ fn main() { let bad = unsafe { std::mem::transmute::(42) }; - bad[0]; //~ ERROR constant evaluation error - //~^ NOTE index out of bounds: the len is 0 but the index is 0 + bad[0]; //~ ERROR index out of bounds: the len is 0 but the index is 0 } diff --git a/tests/compile-fail/unaligned_ptr_cast.rs b/tests/compile-fail/unaligned_ptr_cast.rs index f91def30d1205..88285dc69f317 100644 --- a/tests/compile-fail/unaligned_ptr_cast.rs +++ b/tests/compile-fail/unaligned_ptr_cast.rs @@ -2,6 +2,5 @@ fn main() { let x = &2u16; let x = x as *const _ as *const u32; // This must fail because alignment is violated - let _x = unsafe { *x }; //~ ERROR constant evaluation error - //~^ NOTE tried to access memory with alignment 2, but alignment 4 is required + let _x = unsafe { *x }; //~ ERROR tried to access memory with alignment 2, but alignment 4 is required } diff --git a/tests/compile-fail/unaligned_ptr_cast2.rs b/tests/compile-fail/unaligned_ptr_cast2.rs index f87dab76ba300..7541079def2c0 100644 --- a/tests/compile-fail/unaligned_ptr_cast2.rs +++ b/tests/compile-fail/unaligned_ptr_cast2.rs @@ -3,6 +3,5 @@ fn main() { let x = x as *const _ as *const *const u8; // This must fail because alignment is violated. Test specifically for loading pointers, which have special code // in miri's memory. - let _x = unsafe { *x }; //~ ERROR constant evaluation error - //~^ NOTE tried to access memory with alignment 2, but alignment + let _x = unsafe { *x }; //~ ERROR tried to access memory with alignment 2, but alignment } diff --git a/tests/compile-fail/unaligned_ptr_cast_zst.rs b/tests/compile-fail/unaligned_ptr_cast_zst.rs index 45016473c9752..1b9b55c6be1f2 100644 --- a/tests/compile-fail/unaligned_ptr_cast_zst.rs +++ b/tests/compile-fail/unaligned_ptr_cast_zst.rs @@ -2,6 +2,5 @@ fn main() { let x = &2u16; let x = x as *const _ as *const [u32; 0]; // This must fail because alignment is violated. Test specifically for loading ZST. - let _x = unsafe { *x }; //~ ERROR constant evaluation error - //~^ NOTE tried to access memory with alignment 2, but alignment 4 is required + let _x = unsafe { *x }; //~ ERROR tried to access memory with alignment 2, but alignment 4 is required } diff --git a/tests/compile-fail/undefined_byte_read.rs b/tests/compile-fail/undefined_byte_read.rs index 24718bce7db96..1f092936148e0 100644 --- a/tests/compile-fail/undefined_byte_read.rs +++ b/tests/compile-fail/undefined_byte_read.rs @@ -4,7 +4,6 @@ fn main() { let v: Vec = Vec::with_capacity(10); let undef = unsafe { *v.get_unchecked(5) }; - let x = undef + 1; //~ ERROR: error - //~^ NOTE attempted to read undefined bytes + let x = undef + 1; //~ ERROR attempted to read undefined bytes 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 4096cfb93e722..8eec9737546b3 100644 --- a/tests/compile-fail/wild_pointer_deref.rs +++ b/tests/compile-fail/wild_pointer_deref.rs @@ -1,6 +1,5 @@ fn main() { let p = 44 as *const i32; - let x = unsafe { *p }; //~ ERROR constant evaluation error - //~^ NOTE a memory access tried to interpret some bytes as a pointer + 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/compile-fail/zst.rs b/tests/compile-fail/zst.rs index efb2dafd36fc5..2b179dcc8a452 100644 --- a/tests/compile-fail/zst.rs +++ b/tests/compile-fail/zst.rs @@ -1,5 +1,4 @@ fn main() { let x = &() as *const () as *const i32; - let _ = unsafe { *x }; //~ ERROR constant evaluation error - //~^ NOTE tried to access memory with alignment 1, but alignment 4 is required + let _ = unsafe { *x }; //~ ERROR tried to access memory with alignment 1, but alignment 4 is required } From bbb1d80703f272a5592ceeb3832a489776512251 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 21 Oct 2018 01:31:46 +0200 Subject: [PATCH 0278/3747] disable env var test on macOS, win --- tests/run-pass/env.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/run-pass/env.rs b/tests/run-pass/env.rs index c0bf883daf9ce..8c655b953f823 100644 --- a/tests/run-pass/env.rs +++ b/tests/run-pass/env.rs @@ -1,3 +1,6 @@ +//ignore-windows: env var emulation not implemented on Windows +//ignore-macos: env var emulation not implemented on macOS + use std::env; fn main() { From 41eabb658e7a27ba77500f36341a108804c8e0d0 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 22 Oct 2018 08:41:06 +0200 Subject: [PATCH 0279/3747] bump Rust version --- rust-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-toolchain b/rust-toolchain index abbc6c90452ac..cc0787f877e6f 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1 +1 @@ -nightly-2018-10-14 +nightly-2018-10-22 From fdb3022a1195965acf26746bf6d4c8dcae5608af Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 22 Oct 2018 08:41:48 +0200 Subject: [PATCH 0280/3747] env vars are only available with full MIR --- tests/{run-pass => run-pass-fullmir}/env.rs | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename tests/{run-pass => run-pass-fullmir}/env.rs (100%) diff --git a/tests/run-pass/env.rs b/tests/run-pass-fullmir/env.rs similarity index 100% rename from tests/run-pass/env.rs rename to tests/run-pass-fullmir/env.rs From 0b22a1c9d950f741db8f144a61891166df69dbbd Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 22 Oct 2018 09:04:32 +0200 Subject: [PATCH 0281/3747] env vars should work on macOS --- tests/run-pass-fullmir/env.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/run-pass-fullmir/env.rs b/tests/run-pass-fullmir/env.rs index 8c655b953f823..0ca63e148fdbb 100644 --- a/tests/run-pass-fullmir/env.rs +++ b/tests/run-pass-fullmir/env.rs @@ -1,5 +1,4 @@ //ignore-windows: env var emulation not implemented on Windows -//ignore-macos: env var emulation not implemented on macOS use std::env; From 1a7fb7ec3ce5be7205fc1b3fb40642792985d501 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 22 Oct 2018 12:51:30 +0200 Subject: [PATCH 0282/3747] expand comment about incomplete support for interior mutability --- src/stacked_borrows.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 19d5c723d403b..077deceecf2a6 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -264,11 +264,12 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' borrow_kind: Option, ) -> EvalResult<'tcx, Borrow> { let time = self.machine.stacked_borrows.increment_clock(); - // FIXME This does not do enough checking when only part of the data has - // interior mutability. let new_bor = match borrow_kind { Some(mir::BorrowKind::Mut { .. }) => Borrow::Mut(Mut::Uniq(time)), Some(_) => + // FIXME This does not do enough checking when only part of the data has + // interior mutability. When the type is `(i32, Cell)`, we want the + // first field to be frozen but not the second. if self.type_is_freeze(pointee_ty) { Borrow::Frz(time) } else { From 1ae1b9bfeab22038a6c4674be8adb9b0606dea16 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 18 Oct 2018 16:59:08 +0200 Subject: [PATCH 0283/3747] adapt to rustc API changes and factor out computing the tag for ty+mutbl --- src/lib.rs | 12 ++++--- src/stacked_borrows.rs | 72 +++++++++++++++++++++++++++--------------- 2 files changed, 54 insertions(+), 30 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index ed23eef3f5500..7841a4d3a2c08 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -18,7 +18,7 @@ use std::borrow::Cow; use rustc::ty::{self, Ty, TyCtxt, query::TyCtxtAt}; use rustc::ty::layout::{TyLayout, LayoutOf, Size}; -use rustc::hir::def_id::DefId; +use rustc::hir::{self, def_id::DefId}; use rustc::mir; use syntax::attr; @@ -446,13 +446,13 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { ptr: Pointer, pointee_ty: Ty<'tcx>, pointee_size: Size, - borrow_kind: Option, + mutability: Option, ) -> EvalResult<'tcx, Borrow> { if !ecx.machine.validate { // No tracking Ok(Borrow::default()) } else { - ecx.tag_reference(ptr, pointee_ty, pointee_size, borrow_kind) + ecx.tag_reference(ptr, pointee_ty, pointee_size, mutability) } } @@ -460,13 +460,15 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { fn tag_dereference( ecx: &EvalContext<'a, 'mir, 'tcx, Self>, ptr: Pointer, - ptr_ty: Ty<'tcx>, + pointee_ty: Ty<'tcx>, + pointee_size: Size, + mutability: Option, ) -> EvalResult<'tcx, Borrow> { if !ecx.machine.validate { // No tracking Ok(Borrow::default()) } else { - ecx.tag_dereference(ptr, ptr_ty) + ecx.tag_dereference(ptr, pointee_ty, pointee_size, mutability) } } } diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 077deceecf2a6..169c8abe2b08b 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -1,7 +1,8 @@ -use std::cell::RefCell; +use std::cell::{Cell, RefCell}; -use rustc::ty::{Ty, layout::Size}; +use rustc::ty::{self, Ty, layout::Size}; use rustc::mir; +use rustc::hir; use super::{ MemoryAccess, RangeMap, EvalResult, @@ -67,12 +68,12 @@ impl Default for Borrow { /// Extra global machine state #[derive(Clone, Debug)] pub struct State { - clock: Timestamp + clock: Cell } impl State { pub fn new() -> State { - State { clock: 0 } + State { clock: Cell::new(0) } } } @@ -180,9 +181,10 @@ impl<'tcx> Stack { } impl State { - fn increment_clock(&mut self) -> Timestamp { - self.clock += 1; - self.clock + fn increment_clock(&self) -> Timestamp { + let val = self.clock.get(); + self.clock.set(val+1); + val } } @@ -238,47 +240,64 @@ impl<'tcx> Stacks { } } -/// Machine hooks pub trait EvalContextExt<'tcx> { fn tag_reference( &mut self, ptr: Pointer, pointee_ty: Ty<'tcx>, size: Size, - borrow_kind: Option, + mutability: Option, ) -> EvalResult<'tcx, Borrow>; fn tag_dereference( &self, ptr: Pointer, - ptr_ty: Ty<'tcx>, + pointee_ty: Ty<'tcx>, + size: Size, + mutability: Option, ) -> EvalResult<'tcx, Borrow>; + + fn tag_for_pointee( + &self, + pointee_ty: Ty<'tcx>, + borrow_kind: Option, + ) -> Borrow; } impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, 'tcx> { - fn tag_reference( - &mut self, - ptr: Pointer, + fn tag_for_pointee( + &self, pointee_ty: Ty<'tcx>, - size: Size, - borrow_kind: Option, - ) -> EvalResult<'tcx, Borrow> { + borrow_kind: Option, + ) -> Borrow { let time = self.machine.stacked_borrows.increment_clock(); - let new_bor = match borrow_kind { - Some(mir::BorrowKind::Mut { .. }) => Borrow::Mut(Mut::Uniq(time)), - Some(_) => + match borrow_kind { + Some(hir::MutMutable) => Borrow::Mut(Mut::Uniq(time)), + Some(hir::MutImmutable) => // FIXME This does not do enough checking when only part of the data has // interior mutability. When the type is `(i32, Cell)`, we want the // first field to be frozen but not the second. if self.type_is_freeze(pointee_ty) { Borrow::Frz(time) } else { + // Shared reference with interior mutability. Borrow::Mut(Mut::Raw) }, None => Borrow::Mut(Mut::Raw), - }; + } + } + + /// Called for place-to-value conversion. + fn tag_reference( + &mut self, + ptr: Pointer, + pointee_ty: Ty<'tcx>, + size: Size, + mutability: Option, + ) -> EvalResult<'tcx, Borrow> { + let new_bor = self.tag_for_pointee(pointee_ty, mutability); trace!("tag_reference: Creating new reference ({:?}) for {:?} (pointee {}, size {}): {:?}", - borrow_kind, ptr, pointee_ty, size.bytes(), new_bor); + mutability, ptr, pointee_ty, size.bytes(), new_bor); // Make sure this reference is not dangling or so self.memory.check_bounds(ptr, size, false)?; @@ -291,14 +310,17 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' Ok(new_bor) } + /// Called for value-to-place conversion. fn tag_dereference( &self, ptr: Pointer, - ptr_ty: Ty<'tcx>, + pointee_ty: Ty<'tcx>, + size: Size, + mutability: Option, ) -> EvalResult<'tcx, Borrow> { - // If this is a raw ptr, forget about the tag. - Ok(if ptr_ty.is_unsafe_ptr() { - trace!("tag_dereference: Erasing tag for {:?} ({})", ptr, ptr_ty); + // If this is a raw situation, forget about the tag. + Ok(if mutability.is_none() { + trace!("tag_dereference: Erasing tag for {:?} (pointee {})", ptr, pointee_ty); Borrow::Mut(Mut::Raw) } else { // FIXME: Do we want to adjust the tag if it does not match the type? From dd1558f33719facb84726f9489ee9e2abb279e8b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 19 Oct 2018 16:07:40 +0200 Subject: [PATCH 0284/3747] rustc update and be very selective about what we accept on a deref --- src/lib.rs | 36 ++-- src/stacked_borrows.rs | 204 ++++++++++++++---- .../stacked_borrows/alias_through_mutation.rs | 2 +- .../stacked_borrows/buggy_as_mut_slice.rs | 2 +- .../stacked_borrows/buggy_split_at_mut.rs | 3 +- .../stacked_borrows/illegal_write.rs | 11 - .../stacked_borrows/illegal_write2.rs | 2 +- .../stacked_borrows/pointer_smuggling.rs | 2 +- .../stacked_borrows/shared_confusion.rs | 2 +- .../static_memory_modification.rs | 3 + .../static_memory_modification2.rs | 2 +- .../static_memory_modification3.rs | 3 + tests/compile-fail/unaligned_ptr_cast.rs | 3 + tests/compile-fail/unaligned_ptr_cast2.rs | 3 + tests/compile-fail/validity/undef.rs | 2 +- tests/compile-fail/zst.rs | 2 +- 16 files changed, 207 insertions(+), 75 deletions(-) delete mode 100644 tests/compile-fail/stacked_borrows/illegal_write.rs diff --git a/src/lib.rs b/src/lib.rs index 7841a4d3a2c08..6ca64356ff9f2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -434,7 +434,7 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { #[inline(always)] fn memory_deallocated( - alloc: &mut Allocation, + alloc: &mut Allocation, ptr: Pointer, ) -> EvalResult<'tcx> { alloc.extra.memory_deallocated(ptr) @@ -443,32 +443,38 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { #[inline(always)] fn tag_reference( ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, - ptr: Pointer, - pointee_ty: Ty<'tcx>, - pointee_size: Size, + place: MemPlace, + ty: Ty<'tcx>, + size: Size, mutability: Option, - ) -> EvalResult<'tcx, Borrow> { - if !ecx.machine.validate { + ) -> EvalResult<'tcx, MemPlace> { + if !ecx.machine.validate || size == Size::ZERO { // No tracking - Ok(Borrow::default()) + Ok(place) } else { - ecx.tag_reference(ptr, pointee_ty, pointee_size, mutability) + let ptr = place.ptr.to_ptr()?; + let tag = ecx.tag_reference(ptr, ty, size, mutability.into())?; + let ptr = Scalar::Ptr(Pointer::new_with_tag(ptr.alloc_id, ptr.offset, tag)); + Ok(MemPlace { ptr, ..place }) } } #[inline(always)] fn tag_dereference( ecx: &EvalContext<'a, 'mir, 'tcx, Self>, - ptr: Pointer, - pointee_ty: Ty<'tcx>, - pointee_size: Size, + place: MemPlace, + ty: Ty<'tcx>, + size: Size, mutability: Option, - ) -> EvalResult<'tcx, Borrow> { - if !ecx.machine.validate { + ) -> EvalResult<'tcx, MemPlace> { + if !ecx.machine.validate || size == Size::ZERO { // No tracking - Ok(Borrow::default()) + Ok(place) } else { - ecx.tag_dereference(ptr, pointee_ty, pointee_size, mutability) + let ptr = place.ptr.to_ptr()?; + let tag = ecx.tag_dereference(ptr, ty, size, mutability.into())?; + let ptr = Scalar::Ptr(Pointer::new_with_tag(ptr.alloc_id, ptr.offset, tag)); + Ok(MemPlace { ptr, ..place }) } } } diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 169c8abe2b08b..3ed3f6d9540f5 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -1,7 +1,6 @@ use std::cell::{Cell, RefCell}; -use rustc::ty::{self, Ty, layout::Size}; -use rustc::mir; +use rustc::ty::{Ty, layout::Size}; use rustc::hir; use super::{ @@ -65,6 +64,24 @@ impl Default for Borrow { } } +/// What kind of reference are we talking about? +#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] +pub enum RefKind { + Mut, + Shr, + Raw, +} + +impl From> for RefKind { + fn from(mutbl: Option) -> Self { + match mutbl { + None => RefKind::Raw, + Some(hir::MutMutable) => RefKind::Mut, + Some(hir::MutImmutable) => RefKind::Shr, + } + } +} + /// Extra global machine state #[derive(Clone, Debug)] pub struct State { @@ -101,6 +118,9 @@ pub struct Stacks { /// Core operations impl<'tcx> Stack { + /// Check if `bor` is currently active. We accept a `Raw` on a frozen location + /// because this could be a shared (re)borrow. If you want to mutate, this + /// is not the right function to call! fn check(&self, bor: Borrow) -> bool { match bor { Borrow::Frz(acc_t) => @@ -116,8 +136,33 @@ impl<'tcx> Stack { } } + /// Check if `bor` could be activated by unfreezing and popping. + /// This should be in sync with `reactivate`! + fn reactivatable(&self, bor: Borrow) -> bool { + if self.check(bor) { + return true; + } + + let acc_m = match bor { + Borrow::Frz(_) => return false, + Borrow::Mut(acc_m) => acc_m + }; + // This is where we would unfreeze. + for &itm in self.borrows.iter().rev() { + match itm { + BorStackItem::FnBarrier(_) => return false, + BorStackItem::Mut(loc_m) => { + if loc_m == acc_m { return true; } + // Go on looking. + } + } + } + // Simulate a "virtual raw" element at the bottom of the stack. + acc_m.is_raw() + } + /// Reactive `bor` for this stack. If `force_mut` is set, we want to aggressively - /// unfreeze this location (because we are about to push a `Uniq`). + /// unfreeze this location (because we are about to mutate, so a frozen `Raw` is not okay). fn reactivate(&mut self, bor: Borrow, force_mut: bool) -> EvalResult<'tcx> { // Unless mutation is bound to happen, do NOT change anything if `bor` is already active. // In particular, if it is a `Mut(Raw)` and we are frozen, this should be a NOP. @@ -126,15 +171,25 @@ impl<'tcx> Stack { } let acc_m = match bor { - Borrow::Frz(_) => + Borrow::Frz(since) => if force_mut { return err!(MachineError(format!("Using a shared borrow for mutation"))) } else { - return err!(MachineError(format!("Location should be frozen but it is not"))) + return err!(MachineError(format!( + "Location should be frozen since {} but {}", + since, + match self.frozen_since { + None => format!("it is not frozen at all"), + Some(since) => format!("it is only frozen since {}", since), + } + ))) } Borrow::Mut(acc_m) => acc_m, }; // We definitely have to unfreeze this, even if we use the topmost item. + if self.frozen_since.is_some() { + trace!("reactivate: Unfreezing"); + } self.frozen_since = None; // Pop until we see the one we are looking for. while let Some(&itm) = self.borrows.last() { @@ -157,21 +212,33 @@ impl<'tcx> Stack { } } + /// Initiate `bor`; mostly this means freezing or pushing. fn initiate(&mut self, bor: Borrow) -> EvalResult<'tcx> { match bor { Borrow::Frz(t) => { - trace!("initiate: Freezing"); match self.frozen_since { - None => self.frozen_since = Some(t), - Some(since) => assert!(since <= t), + None => { + trace!("initiate: Freezing"); + self.frozen_since = Some(t); + } + Some(since) => { + trace!("initiate: Already frozen"); + assert!(since <= t); + } } } Borrow::Mut(m) => { - trace!("initiate: Pushing {:?}", bor); match self.frozen_since { - None => self.borrows.push(BorStackItem::Mut(m)), + None => { + trace!("initiate: Pushing {:?}", bor); + self.borrows.push(BorStackItem::Mut(m)) + } + Some(_) if m.is_raw() => + // We only ever initiate right after activating the ref we come from. + // If the source ref is fine being frozen, then a raw ref we create + // from it is fine with this as well. + trace!("initiate: Initiating a raw on a frozen location, not doing a thing"), Some(_) => - // FIXME: Do we want an exception for raw borrows? return err!(MachineError(format!("Trying to mutate frozen location"))) } } @@ -223,13 +290,17 @@ impl<'tcx> Stacks { ptr: Pointer, size: Size, new_bor: Borrow, + permit_redundant: bool, ) -> EvalResult<'tcx> { let mut stacks = self.stacks.borrow_mut(); for stack in stacks.iter_mut(ptr.offset, size) { - if stack.check(new_bor) { + if permit_redundant && stack.check(new_bor) { // The new borrow is already active! This can happen when creating multiple // shared references from the same mutable reference. Do nothing. + trace!("reborrow: New borrow {:?} is already active, not doing a thing", new_bor); } else { + // If we are creating a uniq ref, we certainly want to unfreeze. + // Even if we are doing so from a raw. // FIXME: The blog post says we should `reset` if this is a local. stack.reactivate(ptr.tag, /*force_mut*/new_bor.is_uniq())?; stack.initiate(new_bor)?; @@ -241,39 +312,40 @@ impl<'tcx> Stacks { } pub trait EvalContextExt<'tcx> { + fn tag_for_pointee( + &self, + pointee_ty: Ty<'tcx>, + ref_kind: RefKind, + ) -> Borrow; + fn tag_reference( - &mut self, + &self, ptr: Pointer, pointee_ty: Ty<'tcx>, size: Size, - mutability: Option, + ref_kind: RefKind, ) -> EvalResult<'tcx, Borrow>; + fn tag_dereference( &self, ptr: Pointer, pointee_ty: Ty<'tcx>, size: Size, - mutability: Option, + ref_kind: RefKind, ) -> EvalResult<'tcx, Borrow>; - - fn tag_for_pointee( - &self, - pointee_ty: Ty<'tcx>, - borrow_kind: Option, - ) -> Borrow; } impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, 'tcx> { fn tag_for_pointee( &self, pointee_ty: Ty<'tcx>, - borrow_kind: Option, + ref_kind: RefKind, ) -> Borrow { let time = self.machine.stacked_borrows.increment_clock(); - match borrow_kind { - Some(hir::MutMutable) => Borrow::Mut(Mut::Uniq(time)), - Some(hir::MutImmutable) => + match ref_kind { + RefKind::Mut => Borrow::Mut(Mut::Uniq(time)), + RefKind::Shr => // FIXME This does not do enough checking when only part of the data has // interior mutability. When the type is `(i32, Cell)`, we want the // first field to be frozen but not the second. @@ -283,21 +355,21 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' // Shared reference with interior mutability. Borrow::Mut(Mut::Raw) }, - None => Borrow::Mut(Mut::Raw), + RefKind::Raw => Borrow::Mut(Mut::Raw), } } /// Called for place-to-value conversion. fn tag_reference( - &mut self, + &self, ptr: Pointer, pointee_ty: Ty<'tcx>, size: Size, - mutability: Option, + ref_kind: RefKind, ) -> EvalResult<'tcx, Borrow> { - let new_bor = self.tag_for_pointee(pointee_ty, mutability); + let new_bor = self.tag_for_pointee(pointee_ty, ref_kind); trace!("tag_reference: Creating new reference ({:?}) for {:?} (pointee {}, size {}): {:?}", - mutability, ptr, pointee_ty, size.bytes(), new_bor); + ref_kind, ptr, pointee_ty, size.bytes(), new_bor); // Make sure this reference is not dangling or so self.memory.check_bounds(ptr, size, false)?; @@ -305,26 +377,78 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' // Update the stacks. We cannot use `get_mut` becuse this might be immutable // memory. let alloc = self.memory.get(ptr.alloc_id).expect("We checked that the ptr is fine!"); - alloc.extra.reborrow(ptr, size, new_bor)?; + let permit_redundant = ref_kind == RefKind::Shr; // redundant shared refs are okay + alloc.extra.reborrow(ptr, size, new_bor, permit_redundant)?; Ok(new_bor) } /// Called for value-to-place conversion. + /// + /// Note that this does NOT mean that all this memory will actually get accessed/referenced! + /// We could be in the middle of `&(*var).1`. fn tag_dereference( &self, ptr: Pointer, pointee_ty: Ty<'tcx>, size: Size, - mutability: Option, + ref_kind: RefKind, ) -> EvalResult<'tcx, Borrow> { - // If this is a raw situation, forget about the tag. - Ok(if mutability.is_none() { - trace!("tag_dereference: Erasing tag for {:?} (pointee {})", ptr, pointee_ty); - Borrow::Mut(Mut::Raw) - } else { - // FIXME: Do we want to adjust the tag if it does not match the type? - ptr.tag - }) + // In principle we should not have to do anything here. However, with transmutes involved, + // it can happen that the tag of `ptr` does not actually match `ref_kind`, and we + // should adjust for that. + // Notably, the compiler can introduce such transmutes by optimizing away `&[mut]*`. + // That can transmute a raw ptr to a (shared/mut) ref, and a mut ref to a shared one. + match (ref_kind, ptr.tag) { + (RefKind::Raw, Borrow::Mut(Mut::Raw)) | + (RefKind::Mut, Borrow::Mut(Mut::Uniq(_))) | + (RefKind::Shr, Borrow::Frz(_)) | + (RefKind::Shr, Borrow::Mut(Mut::Raw)) => { + // Expected combinations. Nothing to do. + // FIXME: We probably shouldn't accept this if we got a raw shr without + // interior mutability. + } + (_, Borrow::Mut(Mut::Raw)) => { + // Raw transmuted to (shr/mut) ref. Keep this as raw access. + // We cannot reborrow here; there might be a raw in `&(*var).1` where + // `var` is an `&mut`. The other field of the struct might be already frozen, + // also using `var`, and that would be okay. + } + (RefKind::Raw, _) => { + // Someone transmuted a ref to a raw. Treat this like a ref, their fault. + } + (RefKind::Shr, Borrow::Mut(Mut::Uniq(_))) => { + // A mut got transmuted to shr. High time we freeze this location! + // Make this a delayed reborrow. Redundant reborows to shr are okay, + // so we do not have to be worried about doing too much. + trace!("tag_dereference: Lazy freezing of {:?}", ptr); + return self.tag_reference(ptr, pointee_ty, size, ref_kind); + } + (RefKind::Mut, Borrow::Frz(_)) => { + // This is just invalid. + // If we ever allow this, we have to consider what we do when a turn a + // `Raw`-tagged `&mut` into a raw pointer pointing to a frozen location. + // We probably do not want to allow that, but we have to allow + // turning a `Raw`-tagged `&` into a raw ptr to a frozen location. + return err!(MachineError(format!("Encountered mutable reference with frozen tag {:?}", ptr.tag))) + } + } + // Even if we don't touch the tag, this operation is only okay if we *could* + // activate it. Also it must not be dangling. + self.memory.check_bounds(ptr, size, false)?; + let alloc = self.memory.get(ptr.alloc_id).expect("We checked that the ptr is fine!"); + let mut stacks = alloc.extra.stacks.borrow_mut(); + // We need `iter_mut` because `iter` would skip gaps! + for stack in stacks.iter_mut(ptr.offset, size) { + // We accept &mut to a frozen location here, that is just normal. There might + // be shared reborrows that we are about to invalidate with this access. + // We cannot invalidate them aggressively here because the deref might also be + // to just create more shared refs. + if !stack.reactivatable(ptr.tag) { + return err!(MachineError(format!("Encountered {:?} reference with non-reactivatable tag {:?}", ref_kind, ptr.tag))) + } + } + // All is good. + Ok(ptr.tag) } } diff --git a/tests/compile-fail/stacked_borrows/alias_through_mutation.rs b/tests/compile-fail/stacked_borrows/alias_through_mutation.rs index 9fa50da45bd0f..3fcf20e156256 100644 --- a/tests/compile-fail/stacked_borrows/alias_through_mutation.rs +++ b/tests/compile-fail/stacked_borrows/alias_through_mutation.rs @@ -11,5 +11,5 @@ fn main() { retarget(&mut target_alias, target); // now `target_alias` points to the same thing as `target` *target = 13; - let _val = *target_alias; //~ ERROR should be frozen + let _val = *target_alias; //~ ERROR Shr reference with non-reactivatable tag Frz } diff --git a/tests/compile-fail/stacked_borrows/buggy_as_mut_slice.rs b/tests/compile-fail/stacked_borrows/buggy_as_mut_slice.rs index 4857ada7fb2c7..5f729af30bbe6 100644 --- a/tests/compile-fail/stacked_borrows/buggy_as_mut_slice.rs +++ b/tests/compile-fail/stacked_borrows/buggy_as_mut_slice.rs @@ -14,6 +14,6 @@ fn main() { let v = vec![0,1,2]; let v1 = safe::as_mut_slice(&v); let v2 = safe::as_mut_slice(&v); - v1[1] = 5; //~ ERROR does not exist on the stack + v1[1] = 5; //~ ERROR Mut reference with non-reactivatable tag Mut(Uniq v1[1] = 6; } diff --git a/tests/compile-fail/stacked_borrows/buggy_split_at_mut.rs b/tests/compile-fail/stacked_borrows/buggy_split_at_mut.rs index d7f4300f82c05..0a890b1cebaa1 100644 --- a/tests/compile-fail/stacked_borrows/buggy_split_at_mut.rs +++ b/tests/compile-fail/stacked_borrows/buggy_split_at_mut.rs @@ -11,6 +11,7 @@ mod safe { assert!(mid <= len); (from_raw_parts_mut(ptr, len - mid), // BUG: should be "mid" instead of "len - mid" + //~^ ERROR Mut reference with non-reactivatable tag Mut(Uniq from_raw_parts_mut(ptr.offset(mid as isize), len - mid)) } } @@ -19,6 +20,6 @@ mod safe { fn main() { let mut array = [1,2,3,4]; let (a, b) = safe::split_at_mut(&mut array, 0); - a[1] = 5; //~ ERROR does not exist on the stack + a[1] = 5; b[1] = 6; } diff --git a/tests/compile-fail/stacked_borrows/illegal_write.rs b/tests/compile-fail/stacked_borrows/illegal_write.rs deleted file mode 100644 index 6a7ccc84012c6..0000000000000 --- a/tests/compile-fail/stacked_borrows/illegal_write.rs +++ /dev/null @@ -1,11 +0,0 @@ -fn evil(x: &u32) { - let x : &mut u32 = unsafe { &mut *(x as *const _ as *mut _) }; - *x = 42; // mutating shared ref without `UnsafeCell` -} - -fn main() { - let target = 42; - let ref_ = ⌖ - evil(ref_); // invalidates shared ref - let _x = *ref_; //~ ERROR should be frozen -} diff --git a/tests/compile-fail/stacked_borrows/illegal_write2.rs b/tests/compile-fail/stacked_borrows/illegal_write2.rs index 1d61b1b988965..22648ba71184d 100644 --- a/tests/compile-fail/stacked_borrows/illegal_write2.rs +++ b/tests/compile-fail/stacked_borrows/illegal_write2.rs @@ -6,5 +6,5 @@ fn main() { drop(&mut *target); // reborrow // Now make sure our ref is still the only one unsafe { *target2 = 13; } // invalidate our ref - let _val = *target; //~ ERROR does not exist on the stack + let _val = *target; //~ ERROR Mut reference with non-reactivatable tag Mut(Uniq } diff --git a/tests/compile-fail/stacked_borrows/pointer_smuggling.rs b/tests/compile-fail/stacked_borrows/pointer_smuggling.rs index 3576aa52b753c..678b9b21ba8c4 100644 --- a/tests/compile-fail/stacked_borrows/pointer_smuggling.rs +++ b/tests/compile-fail/stacked_borrows/pointer_smuggling.rs @@ -18,5 +18,5 @@ fn main() { fun1(val); *val = 2; // this invalidates any raw ptrs `fun1` might have created. fun2(); // if they now use a raw ptr they break our reference - *val = 3; //~ ERROR does not exist on the stack + *val = 3; //~ ERROR Mut reference with non-reactivatable tag Mut(Uniq } diff --git a/tests/compile-fail/stacked_borrows/shared_confusion.rs b/tests/compile-fail/stacked_borrows/shared_confusion.rs index 584053f59323b..5098f493ccd73 100644 --- a/tests/compile-fail/stacked_borrows/shared_confusion.rs +++ b/tests/compile-fail/stacked_borrows/shared_confusion.rs @@ -13,7 +13,7 @@ fn test(r: &mut RefCell) { } // Our old raw should be dead by now unsafe { *x_evil = 0; } // this falls back to some Raw higher up the stack - *x_inner = 12; //~ ERROR does not exist on the stack + *x_inner = 12; //~ ERROR Mut reference with non-reactivatable tag Mut(Uniq } fn main() { diff --git a/tests/compile-fail/static_memory_modification.rs b/tests/compile-fail/static_memory_modification.rs index 304ab6c6b7409..c758926458651 100644 --- a/tests/compile-fail/static_memory_modification.rs +++ b/tests/compile-fail/static_memory_modification.rs @@ -1,3 +1,6 @@ +// Validation detects that we are casting & to &mut and so it changes why we fail +// compile-flags: -Zmir-emit-validate=0 -Zmiri-disable-validation + static X: usize = 5; #[allow(mutable_transmutes)] diff --git a/tests/compile-fail/static_memory_modification2.rs b/tests/compile-fail/static_memory_modification2.rs index 01c3b9bb2d8da..c9857b20592e4 100644 --- a/tests/compile-fail/static_memory_modification2.rs +++ b/tests/compile-fail/static_memory_modification2.rs @@ -1,5 +1,5 @@ // Validation detects that we are casting & to &mut and so it changes why we fail -// compile-flags: -Zmir-emit-validate=0 +// compile-flags: -Zmir-emit-validate=0 -Zmiri-disable-validation use std::mem::transmute; diff --git a/tests/compile-fail/static_memory_modification3.rs b/tests/compile-fail/static_memory_modification3.rs index ff09aad1bd564..41a62787296f0 100644 --- a/tests/compile-fail/static_memory_modification3.rs +++ b/tests/compile-fail/static_memory_modification3.rs @@ -1,3 +1,6 @@ +// Validation detects that we are casting & to &mut and so it changes why we fail +// compile-flags: -Zmir-emit-validate=0 -Zmiri-disable-validation + use std::mem::transmute; #[allow(mutable_transmutes)] diff --git a/tests/compile-fail/unaligned_ptr_cast.rs b/tests/compile-fail/unaligned_ptr_cast.rs index 88285dc69f317..47317afd36ec9 100644 --- a/tests/compile-fail/unaligned_ptr_cast.rs +++ b/tests/compile-fail/unaligned_ptr_cast.rs @@ -1,3 +1,6 @@ +// This should fail even without validation +// compile-flags: -Zmir-emit-validate=0 -Zmiri-disable-validation + fn main() { let x = &2u16; let x = x as *const _ as *const u32; diff --git a/tests/compile-fail/unaligned_ptr_cast2.rs b/tests/compile-fail/unaligned_ptr_cast2.rs index 7541079def2c0..d146f21dfe60f 100644 --- a/tests/compile-fail/unaligned_ptr_cast2.rs +++ b/tests/compile-fail/unaligned_ptr_cast2.rs @@ -1,3 +1,6 @@ +// This should fail even without validation +// compile-flags: -Zmir-emit-validate=0 -Zmiri-disable-validation + fn main() { let x = &2u16; let x = x as *const _ as *const *const u8; diff --git a/tests/compile-fail/validity/undef.rs b/tests/compile-fail/validity/undef.rs index 58d3926dadafa..f86fef9454e82 100644 --- a/tests/compile-fail/validity/undef.rs +++ b/tests/compile-fail/validity/undef.rs @@ -1,5 +1,5 @@ #![allow(unused_variables)] -// error-pattern: encountered undefined data in pointer +// error-pattern: encountered undefined address in pointer use std::mem; diff --git a/tests/compile-fail/zst.rs b/tests/compile-fail/zst.rs index 2b179dcc8a452..0f4c945c85b49 100644 --- a/tests/compile-fail/zst.rs +++ b/tests/compile-fail/zst.rs @@ -1,4 +1,4 @@ fn main() { let x = &() as *const () as *const i32; - let _ = unsafe { *x }; //~ ERROR tried to access memory with alignment 1, but alignment 4 is required + let _ = unsafe { *x }; //~ ERROR outside bounds of allocation } From fda03e9d7db66f59f4c1ae9ca752b68c53d1fe88 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 19 Oct 2018 18:38:23 +0200 Subject: [PATCH 0285/3747] some more compile-fail tests --- tests/compile-fail-fullmir/stack_free.rs | 3 ++ .../stacked_borrows/illegal_write1.rs | 11 +++++++ .../stacked_borrows/illegal_write3.rs | 8 +++++ .../stacked_borrows/illegal_write4.rs | 31 +++++++++++++++++++ tests/compile-fail/validity/dangling_ref1.rs | 5 +++ tests/compile-fail/validity/dangling_ref2.rs | 7 +++++ 6 files changed, 65 insertions(+) create mode 100644 tests/compile-fail/stacked_borrows/illegal_write1.rs create mode 100644 tests/compile-fail/stacked_borrows/illegal_write3.rs create mode 100644 tests/compile-fail/stacked_borrows/illegal_write4.rs create mode 100644 tests/compile-fail/validity/dangling_ref1.rs create mode 100644 tests/compile-fail/validity/dangling_ref2.rs diff --git a/tests/compile-fail-fullmir/stack_free.rs b/tests/compile-fail-fullmir/stack_free.rs index 96006c884e580..6d853e75fb4ae 100644 --- a/tests/compile-fail-fullmir/stack_free.rs +++ b/tests/compile-fail-fullmir/stack_free.rs @@ -1,3 +1,6 @@ +// Validation changes why we fail +// compile-flags: -Zmir-emit-validate=0 -Zmiri-disable-validation + // error-pattern: tried to deallocate Stack memory but gave Machine(Rust) as the kind fn main() { diff --git a/tests/compile-fail/stacked_borrows/illegal_write1.rs b/tests/compile-fail/stacked_borrows/illegal_write1.rs new file mode 100644 index 0000000000000..86b96e2880ec3 --- /dev/null +++ b/tests/compile-fail/stacked_borrows/illegal_write1.rs @@ -0,0 +1,11 @@ +fn evil(x: &u32) { + let x : &mut u32 = unsafe { &mut *(x as *const _ as *mut _) }; + *x = 42; // mutating shared ref without `UnsafeCell` +} + +fn main() { + let target = 42; + let ref_ = ⌖ + evil(ref_); // invalidates shared ref + let _x = *ref_; //~ ERROR Shr reference with non-reactivatable tag Frz +} diff --git a/tests/compile-fail/stacked_borrows/illegal_write3.rs b/tests/compile-fail/stacked_borrows/illegal_write3.rs new file mode 100644 index 0000000000000..26c30a4122b40 --- /dev/null +++ b/tests/compile-fail/stacked_borrows/illegal_write3.rs @@ -0,0 +1,8 @@ +fn main() { + let target = 42; + // Make sure raw ptr with raw tag cannot mutate frozen location without breaking the shared ref. + let r#ref = ⌖ // freeze + let ptr = r#ref as *const _ as *mut _; // raw ptr, with raw tag + unsafe { *ptr = 42; } + let _val = *r#ref; //~ ERROR Shr reference with non-reactivatable tag Frz +} diff --git a/tests/compile-fail/stacked_borrows/illegal_write4.rs b/tests/compile-fail/stacked_borrows/illegal_write4.rs new file mode 100644 index 0000000000000..b2ffac865bd42 --- /dev/null +++ b/tests/compile-fail/stacked_borrows/illegal_write4.rs @@ -0,0 +1,31 @@ +// The compiler inserts some reborrows, enable optimizations to +// get rid of them. +// compile-flags: -Zmir-opt-level=1 + +use std::mem; + +// This is an example of a piece of code that intuitively seems like we might +// want to reject it, but that doesn't turn out to be possible. + +fn main() { + let target = 42; + // Make sure a cannot use a raw-tagged `&mut` pointing to a frozen location, not + // even to create a raw. + let r#ref = ⌖ // freeze + let ptr = r#ref as *const _ as *mut i32; // raw ptr, with raw tag + let mut_ref: &mut i32 = unsafe { mem::transmute(ptr) }; // &mut, with raw tag + // Now we have an &mut to a frozen location, but that is completely normal: + // We'd just unfreeze the location if we used it. + let bad_ptr = mut_ref as *mut i32; // even just creating this is like a use of `mut_ref`. + // That violates the location being frozen! However, we do not properly detect this: + // We first see a `&mut` with a `Raw` tag being deref'd for a frozen location, + // which can happen legitimately if the compiler optimized away an `&mut*` that + // turns a raw into a `&mut`. Next, we create a raw ref to a frozen location + // from a `Raw` tag, which can happen legitimately when interior mutability + // is involved. + let _val = *r#ref; // Make sure it is still frozen. + + // We only actually unfreeze once we muteate through the bad pointer. + unsafe { *bad_ptr = 42 }; + let _val = *r#ref; //~ ERROR Shr reference with non-reactivatable tag Frz +} diff --git a/tests/compile-fail/validity/dangling_ref1.rs b/tests/compile-fail/validity/dangling_ref1.rs new file mode 100644 index 0000000000000..c5845cb693bb3 --- /dev/null +++ b/tests/compile-fail/validity/dangling_ref1.rs @@ -0,0 +1,5 @@ +use std::mem; + +fn main() { + let _x: &i32 = unsafe { mem::transmute(16usize) }; //~ ERROR tried to interpret some bytes as a pointer +} diff --git a/tests/compile-fail/validity/dangling_ref2.rs b/tests/compile-fail/validity/dangling_ref2.rs new file mode 100644 index 0000000000000..21650ebf95067 --- /dev/null +++ b/tests/compile-fail/validity/dangling_ref2.rs @@ -0,0 +1,7 @@ +use std::mem; + +fn main() { + let val = 14; + let ptr = (&val as *const i32).wrapping_offset(1); + let _x: &i32 = unsafe { mem::transmute(ptr) }; //~ ERROR outside bounds of allocation +} From 01828fde5345299636f6c029b333f42e91ffd140 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 19 Oct 2018 19:51:41 +0200 Subject: [PATCH 0286/3747] respect memory's privacy --- src/fn_call.rs | 57 +++++++++++++++++++++--------------------- src/intrinsic.rs | 10 ++++---- src/lib.rs | 4 +-- src/operator.rs | 28 ++++++++++----------- src/stacked_borrows.rs | 8 +++--- 5 files changed, 54 insertions(+), 53 deletions(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index 0cbd891a34e4c..04601b3cd1ff7 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -125,7 +125,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo self.write_null(dest)?; } else { let align = self.tcx.data_layout.pointer_align; - let ptr = self.memory.allocate(Size::from_bytes(size), align, MiriMemoryKind::C.into())?; + let ptr = self.memory_mut().allocate(Size::from_bytes(size), align, MiriMemoryKind::C.into())?; self.write_scalar(Scalar::Ptr(ptr), dest)?; } } @@ -133,7 +133,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo "free" => { let ptr = self.read_scalar(args[0])?.not_undef()?.erase_tag(); // raw ptr operation, no tag if !ptr.is_null() { - self.memory.deallocate( + self.memory_mut().deallocate( ptr.to_ptr()?.with_default_tag(), None, MiriMemoryKind::C.into(), @@ -150,7 +150,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo if !align.is_power_of_two() { return err!(HeapAllocNonPowerOfTwoAlignment(align)); } - let ptr = self.memory.allocate(Size::from_bytes(size), + let ptr = self.memory_mut().allocate(Size::from_bytes(size), Align::from_bytes(align, align).unwrap(), MiriMemoryKind::Rust.into())?; self.write_scalar(Scalar::Ptr(ptr), dest)?; @@ -164,10 +164,10 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo if !align.is_power_of_two() { return err!(HeapAllocNonPowerOfTwoAlignment(align)); } - let ptr = self.memory.allocate(Size::from_bytes(size), + let ptr = self.memory_mut().allocate(Size::from_bytes(size), Align::from_bytes(align, align).unwrap(), MiriMemoryKind::Rust.into())?; - self.memory.write_repeat(ptr.into(), 0, Size::from_bytes(size))?; + self.memory_mut().write_repeat(ptr.into(), 0, Size::from_bytes(size))?; self.write_scalar(Scalar::Ptr(ptr), dest)?; } "__rust_dealloc" => { @@ -180,7 +180,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo if !align.is_power_of_two() { return err!(HeapAllocNonPowerOfTwoAlignment(align)); } - self.memory.deallocate( + self.memory_mut().deallocate( ptr.with_default_tag(), Some((Size::from_bytes(old_size), Align::from_bytes(align, align).unwrap())), MiriMemoryKind::Rust.into(), @@ -197,7 +197,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo if !align.is_power_of_two() { return err!(HeapAllocNonPowerOfTwoAlignment(align)); } - let new_ptr = self.memory.reallocate( + let new_ptr = self.memory_mut().reallocate( ptr.with_default_tag(), Size::from_bytes(old_size), Align::from_bytes(align, align).unwrap(), @@ -231,7 +231,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo "dlsym" => { let _handle = self.read_scalar(args[0])?; let symbol = self.read_scalar(args[1])?.to_ptr()?.erase_tag(); - let symbol_name = self.memory.read_c_str(symbol.with_default_tag())?; + let symbol_name = self.memory().read_c_str(symbol.with_default_tag())?; let err = format!("bad c unicode symbol: {:?}", symbol_name); let symbol_name = ::std::str::from_utf8(symbol_name).unwrap_or(&err); return err!(Unimplemented(format!( @@ -245,7 +245,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo // We abort on panic, so not much is going on here, but we still have to call the closure let f = self.read_scalar(args[0])?.to_ptr()?; let data = self.read_scalar(args[1])?.not_undef()?; - let f_instance = self.memory.get_fn(f)?; + let f_instance = self.memory().get_fn(f)?; self.write_null(dest)?; trace!("__rust_maybe_catch_panic: {:?}", f_instance); @@ -289,8 +289,8 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo let n = Size::from_bytes(self.read_scalar(args[2])?.to_usize(&self)?); let result = { - let left_bytes = self.memory.read_bytes(left.with_default_tag(), n)?; - let right_bytes = self.memory.read_bytes(right.with_default_tag(), n)?; + let left_bytes = self.memory().read_bytes(left.with_default_tag(), n)?; + let right_bytes = self.memory().read_bytes(right.with_default_tag(), n)?; use std::cmp::Ordering::*; match left_bytes.cmp(right_bytes) { @@ -311,7 +311,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo let ptr = ptr.with_default_tag(); let val = self.read_scalar(args[1])?.to_bytes()? as u8; let num = self.read_scalar(args[2])?.to_usize(&self)?; - if let Some(idx) = self.memory.read_bytes(ptr, Size::from_bytes(num))? + if let Some(idx) = self.memory().read_bytes(ptr, Size::from_bytes(num))? .iter().rev().position(|&c| c == val) { let new_ptr = ptr.ptr_offset(Size::from_bytes(num - idx as u64 - 1), &self)?; @@ -326,7 +326,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo let ptr = ptr.with_default_tag(); let val = self.read_scalar(args[1])?.to_bytes()? as u8; let num = self.read_scalar(args[2])?.to_usize(&self)?; - if let Some(idx) = self.memory.read_bytes(ptr, Size::from_bytes(num))?.iter().position( + if let Some(idx) = self.memory().read_bytes(ptr, Size::from_bytes(num))?.iter().position( |&c| c == val, ) { @@ -340,7 +340,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo "getenv" => { let result = { let name_ptr = self.read_scalar(args[0])?.to_ptr()?.erase_tag(); // raw ptr operation - let name = self.memory.read_c_str(name_ptr.with_default_tag())?; + let name = self.memory().read_c_str(name_ptr.with_default_tag())?; match self.machine.env_vars.get(name) { Some(&var) => Scalar::Ptr(var), None => Scalar::ptr_null(*self.tcx), @@ -354,15 +354,16 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo { let name_ptr = self.read_scalar(args[0])?.not_undef()?.erase_tag(); // raw ptr operation if !name_ptr.is_null() { - let name = self.memory.read_c_str(name_ptr.to_ptr()?.with_default_tag())?; + let name = self.memory().read_c_str(name_ptr.to_ptr()? + .with_default_tag())?.to_owned(); if !name.is_empty() && !name.contains(&b'=') { - success = Some(self.machine.env_vars.remove(name)); + success = Some(self.machine.env_vars.remove(&name)); } } } if let Some(old) = success { if let Some(var) = old { - self.memory.deallocate(var, None, MiriMemoryKind::Env.into())?; + self.memory_mut().deallocate(var, None, MiriMemoryKind::Env.into())?; } self.write_null(dest)?; } else { @@ -375,9 +376,9 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo { let name_ptr = self.read_scalar(args[0])?.not_undef()?.erase_tag(); // raw ptr operation let value_ptr = self.read_scalar(args[1])?.to_ptr()?.erase_tag(); // raw ptr operation - let value = self.memory.read_c_str(value_ptr.with_default_tag())?; + let value = self.memory().read_c_str(value_ptr.with_default_tag())?; if !name_ptr.is_null() { - let name = self.memory.read_c_str(name_ptr.to_ptr()?.with_default_tag())?; + let name = self.memory().read_c_str(name_ptr.to_ptr()?.with_default_tag())?; if !name.is_empty() && !name.contains(&b'=') { new = Some((name.to_owned(), value.to_owned())); } @@ -385,20 +386,20 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo } if let Some((name, value)) = new { // +1 for the null terminator - let value_copy = self.memory.allocate( + let value_copy = self.memory_mut().allocate( Size::from_bytes((value.len() + 1) as u64), Align::from_bytes(1, 1).unwrap(), MiriMemoryKind::Env.into(), )?; - self.memory.write_bytes(value_copy.into(), &value)?; + self.memory_mut().write_bytes(value_copy.into(), &value)?; let trailing_zero_ptr = value_copy.offset(Size::from_bytes(value.len() as u64), &self)?.into(); - self.memory.write_bytes(trailing_zero_ptr, &[0])?; + self.memory_mut().write_bytes(trailing_zero_ptr, &[0])?; if let Some(var) = self.machine.env_vars.insert( name.to_owned(), value_copy, ) { - self.memory.deallocate(var, None, MiriMemoryKind::Env.into())?; + self.memory_mut().deallocate(var, None, MiriMemoryKind::Env.into())?; } self.write_null(dest)?; } else { @@ -415,7 +416,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo // stdout/stderr use std::io::{self, Write}; - let buf_cont = self.memory.read_bytes(buf.with_default_tag(), Size::from_bytes(n))?; + let buf_cont = self.memory().read_bytes(buf.with_default_tag(), Size::from_bytes(n))?; let res = if fd == 1 { io::stdout().write(buf_cont) } else { @@ -437,7 +438,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo "strlen" => { let ptr = self.read_scalar(args[0])?.to_ptr()?.erase_tag(); - let n = self.memory.read_c_str(ptr.with_default_tag())?.len(); + let n = self.memory().read_c_str(ptr.with_default_tag())?.len(); self.write_scalar(Scalar::from_uint(n as u64, dest.layout.size), dest)?; } @@ -487,9 +488,9 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo // Extract the function type out of the signature (that seems easier than constructing it ourselves...) let dtor = match self.read_scalar(args[1])?.not_undef()? { - Scalar::Ptr(dtor_ptr) => Some(self.memory.get_fn(dtor_ptr)?), + Scalar::Ptr(dtor_ptr) => Some(self.memory().get_fn(dtor_ptr)?), Scalar::Bits { bits: 0, size } => { - assert_eq!(size as u64, self.memory.pointer_size().bytes()); + assert_eq!(size as u64, self.memory().pointer_size().bytes()); None }, Scalar::Bits { .. } => return err!(ReadBytesAsPointer), @@ -505,7 +506,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo if key_layout.size.bits() < 128 && key >= (1u128 << key_layout.size.bits() as u128) { return err!(OutOfTls); } - self.memory.write_scalar( + self.memory_mut().write_scalar( key_ptr.with_default_tag(), key_layout.align, Scalar::from_uint(key, key_layout.size).into(), diff --git a/src/intrinsic.rs b/src/intrinsic.rs index 5c86075883b0b..98c57894a9d62 100644 --- a/src/intrinsic.rs +++ b/src/intrinsic.rs @@ -153,7 +153,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' // erase tags: this is a raw ptr operation let src = self.read_scalar(args[0])?.not_undef()?.erase_tag(); let dest = self.read_scalar(args[1])?.not_undef()?.erase_tag(); - self.memory.copy( + self.memory_mut().copy( src.with_default_tag(), elem_align, dest.with_default_tag(), @@ -260,7 +260,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' // Do it in memory let mplace = self.force_allocation(dest)?; assert!(mplace.meta.is_none()); - self.memory.write_repeat(mplace.ptr, 0, dest.layout.size)?; + self.memory_mut().write_repeat(mplace.ptr, 0, dest.layout.size)?; } } } @@ -423,7 +423,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' // Do it in memory let mplace = self.force_allocation(dest)?; assert!(mplace.meta.is_none()); - self.memory.mark_definedness(mplace.ptr.to_ptr()?, dest.layout.size, false)?; + self.memory_mut().mark_definedness(mplace.ptr.to_ptr()?, dest.layout.size, false)?; } } } @@ -435,8 +435,8 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' let val_byte = self.read_scalar(args[1])?.to_u8()?; let ptr = self.read_scalar(args[0])?.not_undef()?.erase_tag().with_default_tag(); let count = self.read_scalar(args[2])?.to_usize(&self)?; - self.memory.check_align(ptr, ty_layout.align)?; - self.memory.write_repeat(ptr, val_byte, ty_layout.size * count)?; + self.memory().check_align(ptr, ty_layout.align)?; + self.memory_mut().write_repeat(ptr, val_byte, ty_layout.size * count)?; } name => return err!(Unimplemented(format!("unimplemented intrinsic: {}", name))), diff --git a/src/lib.rs b/src/lib.rs index 6ca64356ff9f2..8925afa5f6001 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -119,12 +119,12 @@ pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( // FIXME: extract main source file path // Third argument (argv): &[b"foo"] let dest = ecx.eval_place(&mir::Place::Local(args.next().unwrap()))?; - let foo = ecx.memory.allocate_static_bytes(b"foo\0"); + let foo = ecx.memory_mut().allocate_static_bytes(b"foo\0"); let foo_ty = ecx.tcx.mk_imm_ptr(ecx.tcx.types.u8); let foo_layout = ecx.layout_of(foo_ty)?; let foo_place = ecx.allocate(foo_layout, MiriMemoryKind::Env.into())?; ecx.write_scalar(Scalar::Ptr(foo), foo_place.into())?; - ecx.memory.mark_immutable(foo_place.to_ptr()?.alloc_id)?; + ecx.memory_mut().mark_immutable(foo_place.to_ptr()?.alloc_id)?; ecx.write_scalar(foo_place.ptr, dest)?; assert!(args.next().is_none(), "start lang item has more arguments than expected"); diff --git a/src/operator.rs b/src/operator.rs index a11f8f34e7e86..0eac5c11276a7 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -80,8 +80,8 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' Ge => left.offset >= right.offset, Sub => { // subtract the offsets - let left_offset = Scalar::from_uint(left.offset.bytes(), self.memory.pointer_size()); - let right_offset = Scalar::from_uint(right.offset.bytes(), self.memory.pointer_size()); + let left_offset = Scalar::from_uint(left.offset.bytes(), self.memory().pointer_size()); + let right_offset = Scalar::from_uint(right.offset.bytes(), self.memory().pointer_size()); let layout = self.layout_of(self.tcx.types.usize)?; return self.binary_op( Sub, @@ -103,7 +103,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' self.ptr_int_arithmetic( bin_op, left.to_ptr().expect("we checked is_ptr"), - right.to_bits(self.memory.pointer_size()).expect("we checked is_bits"), + right.to_bits(self.memory().pointer_size()).expect("we checked is_bits"), right_layout.abi.is_signed(), ) } @@ -113,7 +113,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' self.ptr_int_arithmetic( bin_op, right.to_ptr().expect("we checked is_ptr"), - left.to_bits(self.memory.pointer_size()).expect("we checked is_bits"), + left.to_bits(self.memory().pointer_size()).expect("we checked is_bits"), left_layout.abi.is_signed(), ) } @@ -142,8 +142,8 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' // allocations sit right next to each other. The C/C++ standards are // somewhat fuzzy about this case, so I think for now this check is // "good enough". - self.memory.check_bounds_ptr(left, false)?; - self.memory.check_bounds_ptr(right, false)?; + self.memory().check_bounds_ptr(left, false)?; + self.memory().check_bounds_ptr(right, false)?; // Two live in-bounds pointers, we can compare across allocations left == right } @@ -153,7 +153,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' (Scalar::Bits { bits, size }, Scalar::Ptr(ptr)) => { assert_eq!(size as u64, self.pointer_size().bytes()); let bits = bits as u64; - let (alloc_size, alloc_align) = self.memory.get_size_and_align(ptr.alloc_id); + let (alloc_size, alloc_align) = self.memory().get_size_and_align(ptr.alloc_id); // Case I: Comparing with NULL if bits == 0 { @@ -223,15 +223,15 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' map_to_primval(left.overflowing_offset(Size::from_bytes(right as u64), self)), BitAnd if !signed => { - let ptr_base_align = self.memory.get(left.alloc_id)?.align.abi(); + let ptr_base_align = self.memory().get(left.alloc_id)?.align.abi(); let base_mask = { // FIXME: Use interpret::truncate, once that takes a Size instead of a Layout - let shift = 128 - self.memory.pointer_size().bits(); + let shift = 128 - self.memory().pointer_size().bits(); let value = !(ptr_base_align as u128 - 1); // truncate (shift left to drop out leftover values, shift right to fill with zeroes) (value << shift) >> shift }; - let ptr_size = self.memory.pointer_size().bytes() as u8; + let ptr_size = self.memory().pointer_size().bytes() as u8; trace!("Ptr BitAnd, align {}, operand {:#010x}, base_mask {:#010x}", ptr_base_align, right, base_mask); if right & base_mask == base_mask { @@ -256,9 +256,9 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' Rem if !signed => { // Doing modulo a divisor of the alignment is allowed. // (Intuition: Modulo a divisor leaks less information.) - let ptr_base_align = self.memory.get(left.alloc_id)?.align.abi(); + let ptr_base_align = self.memory().get(left.alloc_id)?.align.abi(); let right = right as u64; - let ptr_size = self.memory.pointer_size().bytes() as u8; + let ptr_size = self.memory().pointer_size().bytes() as u8; if right == 1 { // modulo 1 is always 0 (Scalar::Bits { bits: 0, size: ptr_size }, false) @@ -295,9 +295,9 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' if let Scalar::Ptr(ptr) = ptr { // Both old and new pointer must be in-bounds. // (Of the same allocation, but that part is trivial with our representation.) - self.memory.check_bounds_ptr(ptr, false)?; + self.memory().check_bounds_ptr(ptr, false)?; let ptr = ptr.signed_offset(offset, self)?; - self.memory.check_bounds_ptr(ptr, false)?; + self.memory().check_bounds_ptr(ptr, false)?; Ok(Scalar::Ptr(ptr)) } else { // An integer pointer. They can only be offset by 0, and we pretend there diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 3ed3f6d9540f5..993287502ae00 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -372,11 +372,11 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' ref_kind, ptr, pointee_ty, size.bytes(), new_bor); // Make sure this reference is not dangling or so - self.memory.check_bounds(ptr, size, false)?; + self.memory().check_bounds(ptr, size, false)?; // Update the stacks. We cannot use `get_mut` becuse this might be immutable // memory. - let alloc = self.memory.get(ptr.alloc_id).expect("We checked that the ptr is fine!"); + let alloc = self.memory().get(ptr.alloc_id).expect("We checked that the ptr is fine!"); let permit_redundant = ref_kind == RefKind::Shr; // redundant shared refs are okay alloc.extra.reborrow(ptr, size, new_bor, permit_redundant)?; @@ -435,8 +435,8 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' } // Even if we don't touch the tag, this operation is only okay if we *could* // activate it. Also it must not be dangling. - self.memory.check_bounds(ptr, size, false)?; - let alloc = self.memory.get(ptr.alloc_id).expect("We checked that the ptr is fine!"); + self.memory().check_bounds(ptr, size, false)?; + let alloc = self.memory().get(ptr.alloc_id).expect("We checked that the ptr is fine!"); let mut stacks = alloc.extra.stacks.borrow_mut(); // We need `iter_mut` because `iter` would skip gaps! for stack in stacks.iter_mut(ptr.offset, size) { From 26bb4f79dc4897b3ddbae196f793c7ee3cecdeab Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 22 Oct 2018 18:01:32 +0200 Subject: [PATCH 0287/3747] get rid of implicit Raw at bottom of stack; locals get a uniq at their bottom --- src/fn_call.rs | 16 ++-- src/lib.rs | 21 ++++- src/stacked_borrows.rs | 82 +++++++++++++++---- tests/compile-fail/copy_nonoverlapping.rs | 4 + .../stacked_borrows/illegal_write1.rs | 11 +-- .../stacked_borrows/illegal_write2.rs | 6 +- .../stacked_borrows/illegal_write3.rs | 4 +- .../stacked_borrows/illegal_write4.rs | 4 +- .../stacked_borrows/outdated_local.rs | 9 ++ .../stacked_borrows/pointer_smuggling.rs | 3 +- .../stacked_borrows/unescaped_local.rs | 10 +++ tests/compile-fail/zst.rs | 2 +- tests/run-pass/observed_local_mut.rs | 3 + tests/run-pass/ptr_arith_offset_overflow.rs | 1 + 14 files changed, 134 insertions(+), 42 deletions(-) create mode 100644 tests/compile-fail/stacked_borrows/outdated_local.rs create mode 100644 tests/compile-fail/stacked_borrows/unescaped_local.rs diff --git a/src/fn_call.rs b/src/fn_call.rs index 04601b3cd1ff7..88c31f63fbb17 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -126,7 +126,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo } else { let align = self.tcx.data_layout.pointer_align; let ptr = self.memory_mut().allocate(Size::from_bytes(size), align, MiriMemoryKind::C.into())?; - self.write_scalar(Scalar::Ptr(ptr), dest)?; + self.write_scalar(Scalar::Ptr(ptr.with_default_tag()), dest)?; } } @@ -153,7 +153,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo let ptr = self.memory_mut().allocate(Size::from_bytes(size), Align::from_bytes(align, align).unwrap(), MiriMemoryKind::Rust.into())?; - self.write_scalar(Scalar::Ptr(ptr), dest)?; + self.write_scalar(Scalar::Ptr(ptr.with_default_tag()), dest)?; } "__rust_alloc_zeroed" => { let size = self.read_scalar(args[0])?.to_usize(&self)?; @@ -164,9 +164,11 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo if !align.is_power_of_two() { return err!(HeapAllocNonPowerOfTwoAlignment(align)); } - let ptr = self.memory_mut().allocate(Size::from_bytes(size), - Align::from_bytes(align, align).unwrap(), - MiriMemoryKind::Rust.into())?; + let ptr = self.memory_mut().allocate( + Size::from_bytes(size), + Align::from_bytes(align, align).unwrap(), + MiriMemoryKind::Rust.into() + )?.with_default_tag(); self.memory_mut().write_repeat(ptr.into(), 0, Size::from_bytes(size))?; self.write_scalar(Scalar::Ptr(ptr), dest)?; } @@ -205,7 +207,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo Align::from_bytes(align, align).unwrap(), MiriMemoryKind::Rust.into(), )?; - self.write_scalar(Scalar::Ptr(new_ptr), dest)?; + self.write_scalar(Scalar::Ptr(new_ptr.with_default_tag()), dest)?; } "syscall" => { @@ -390,7 +392,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo Size::from_bytes((value.len() + 1) as u64), Align::from_bytes(1, 1).unwrap(), MiriMemoryKind::Env.into(), - )?; + )?.with_default_tag(); self.memory_mut().write_bytes(value_copy.into(), &value)?; let trailing_zero_ptr = value_copy.offset(Size::from_bytes(value.len() as u64), &self)?.into(); self.memory_mut().write_bytes(trailing_zero_ptr, &[0])?; diff --git a/src/lib.rs b/src/lib.rs index 8925afa5f6001..128b338f943dc 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -108,7 +108,7 @@ pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( let mut args = ecx.frame().mir.args_iter(); // First argument: pointer to main() - let main_ptr = ecx.memory_mut().create_fn_alloc(main_instance); + let main_ptr = ecx.memory_mut().create_fn_alloc(main_instance).with_default_tag(); let dest = ecx.eval_place(&mir::Place::Local(args.next().unwrap()))?; ecx.write_scalar(Scalar::Ptr(main_ptr), dest)?; @@ -119,7 +119,7 @@ pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( // FIXME: extract main source file path // Third argument (argv): &[b"foo"] let dest = ecx.eval_place(&mir::Place::Local(args.next().unwrap()))?; - let foo = ecx.memory_mut().allocate_static_bytes(b"foo\0"); + let foo = ecx.memory_mut().allocate_static_bytes(b"foo\0").with_default_tag(); let foo_ty = ecx.tcx.mk_imm_ptr(ecx.tcx.types.u8); let foo_layout = ecx.layout_of(foo_ty)?; let foo_place = ecx.allocate(foo_layout, MiriMemoryKind::Env.into())?; @@ -404,7 +404,7 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { Ok(()) } - fn static_with_default_tag( + fn adjust_static_allocation( alloc: &'_ Allocation ) -> Cow<'_, Allocation> { let alloc: Allocation = Allocation { @@ -477,4 +477,19 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { Ok(MemPlace { ptr, ..place }) } } + + #[inline(always)] + fn tag_new_allocation( + ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, + ptr: Pointer, + kind: MemoryKind, + ) -> EvalResult<'tcx, Pointer> { + if !ecx.machine.validate { + // No tracking + Ok(ptr.with_default_tag()) + } else { + let tag = ecx.tag_new_allocation(ptr.alloc_id, kind); + Ok(Pointer::new_with_tag(ptr.alloc_id, ptr.offset, tag)) + } + } } diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 993287502ae00..127958476bcb3 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -4,7 +4,7 @@ use rustc::ty::{Ty, layout::Size}; use rustc::hir; use super::{ - MemoryAccess, RangeMap, EvalResult, + MemoryAccess, MemoryKind, MiriMemoryKind, RangeMap, EvalResult, AllocId, Pointer, }; @@ -104,7 +104,7 @@ struct Stack { impl Default for Stack { fn default() -> Self { Stack { - borrows: Vec::new(), + borrows: vec![BorStackItem::Mut(Mut::Raw)], frozen_since: None, } } @@ -157,8 +157,8 @@ impl<'tcx> Stack { } } } - // Simulate a "virtual raw" element at the bottom of the stack. - acc_m.is_raw() + // Nothing to be found. + false } /// Reactive `bor` for this stack. If `force_mut` is set, we want to aggressively @@ -204,12 +204,8 @@ impl<'tcx> Stack { } } } - // Nothing to be found. Simulate a "virtual raw" element at the bottom of the stack. - if acc_m.is_raw() { - Ok(()) - } else { - err!(MachineError(format!("Borrow-to-reactivate does not exist on the stack"))) - } + // Nothing to be found. + err!(MachineError(format!("Borrow-to-reactivate does not exist on the stack"))) } /// Initiate `bor`; mostly this means freezing or pushing. @@ -301,7 +297,15 @@ impl<'tcx> Stacks { } else { // If we are creating a uniq ref, we certainly want to unfreeze. // Even if we are doing so from a raw. - // FIXME: The blog post says we should `reset` if this is a local. + // Notice that if this is a local, whenever we access it directly the + // tag here will be the bottommost `Uniq` for that local. That `Uniq` + // never is accessible by the program, so it will not be used by any + // other access. IOW, whenever we directly use a local this will pop + // everything else off the stack, invalidating all previous pointers + // and, in particular, *all* raw pointers. This subsumes the explicit + // `reset` which the blog post [1] says to perform when accessing a local. + // + // [1] https://www.ralfj.de/blog/2018/08/07/stacked-borrows.html stack.reactivate(ptr.tag, /*force_mut*/new_bor.is_uniq())?; stack.initiate(new_bor)?; } @@ -309,6 +313,19 @@ impl<'tcx> Stacks { Ok(()) } + + /// Pushes the first borrow to the stacks, must be a mutable one. + pub fn first_borrow( + &mut self, + r#mut: Mut, + size: Size + ) { + for stack in self.stacks.get_mut().iter_mut(Size::ZERO, size) { + assert!(stack.borrows.len() == 1 && stack.frozen_since.is_none()); + assert_eq!(stack.borrows.pop().unwrap(), BorStackItem::Mut(Mut::Raw)); + stack.borrows.push(BorStackItem::Mut(r#mut)); + } + } } pub trait EvalContextExt<'tcx> { @@ -334,6 +351,12 @@ pub trait EvalContextExt<'tcx> { size: Size, ref_kind: RefKind, ) -> EvalResult<'tcx, Borrow>; + + fn tag_new_allocation( + &mut self, + id: AllocId, + kind: MemoryKind, + ) -> Borrow; } impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, 'tcx> { @@ -400,7 +423,12 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' // Notably, the compiler can introduce such transmutes by optimizing away `&[mut]*`. // That can transmute a raw ptr to a (shared/mut) ref, and a mut ref to a shared one. match (ref_kind, ptr.tag) { - (RefKind::Raw, Borrow::Mut(Mut::Raw)) | + (RefKind::Raw, _) => { + // Don't use the tag, this is a raw access! Even if there is a tag, + // that means transmute happened and we ignore the tag. + // Also don't do any further validation, this is raw after all. + return Ok(Borrow::Mut(Mut::Raw)); + } (RefKind::Mut, Borrow::Mut(Mut::Uniq(_))) | (RefKind::Shr, Borrow::Frz(_)) | (RefKind::Shr, Borrow::Mut(Mut::Raw)) => { @@ -408,15 +436,12 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' // FIXME: We probably shouldn't accept this if we got a raw shr without // interior mutability. } - (_, Borrow::Mut(Mut::Raw)) => { - // Raw transmuted to (shr/mut) ref. Keep this as raw access. + (RefKind::Mut, Borrow::Mut(Mut::Raw)) => { + // Raw transmuted to mut ref. Keep this as raw access. // We cannot reborrow here; there might be a raw in `&(*var).1` where // `var` is an `&mut`. The other field of the struct might be already frozen, // also using `var`, and that would be okay. } - (RefKind::Raw, _) => { - // Someone transmuted a ref to a raw. Treat this like a ref, their fault. - } (RefKind::Shr, Borrow::Mut(Mut::Uniq(_))) => { // A mut got transmuted to shr. High time we freeze this location! // Make this a delayed reborrow. Redundant reborows to shr are okay, @@ -451,4 +476,27 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' // All is good. Ok(ptr.tag) } + + fn tag_new_allocation( + &mut self, + id: AllocId, + kind: MemoryKind, + ) -> Borrow { + let r#mut = match kind { + MemoryKind::Stack => { + // New unique borrow + let time = self.machine.stacked_borrows.increment_clock(); + Mut::Uniq(time) + } + _ => { + // Raw for everything else + Mut::Raw + } + }; + // Make this the active borrow for this allocation + let alloc = self.memory_mut().get_mut(id).expect("This is a new allocation, it must still exist"); + let size = Size::from_bytes(alloc.bytes.len() as u64); + alloc.extra.first_borrow(r#mut, size); + Borrow::Mut(r#mut) + } } diff --git a/tests/compile-fail/copy_nonoverlapping.rs b/tests/compile-fail/copy_nonoverlapping.rs index 18fbc61b6d070..704711640f7d9 100644 --- a/tests/compile-fail/copy_nonoverlapping.rs +++ b/tests/compile-fail/copy_nonoverlapping.rs @@ -10,6 +10,10 @@ #![feature(core_intrinsics)] +// FIXME: Validation disabled because it doesn't let us escape an entire slice +// to the raw universe. +// compile-flags: -Zmiri-disable-validation + //error-pattern: copy_nonoverlapping called on overlapping ranges fn main() { diff --git a/tests/compile-fail/stacked_borrows/illegal_write1.rs b/tests/compile-fail/stacked_borrows/illegal_write1.rs index 86b96e2880ec3..ff3a3cd82245c 100644 --- a/tests/compile-fail/stacked_borrows/illegal_write1.rs +++ b/tests/compile-fail/stacked_borrows/illegal_write1.rs @@ -1,11 +1,12 @@ fn evil(x: &u32) { - let x : &mut u32 = unsafe { &mut *(x as *const _ as *mut _) }; - *x = 42; // mutating shared ref without `UnsafeCell` + // mutating shared ref without `UnsafeCell` + let x : *mut u32 = x as *const _ as *mut _; + unsafe { *x = 42; } } fn main() { - let target = 42; - let ref_ = ⌖ - evil(ref_); // invalidates shared ref + let target = Box::new(42); // has an implicit raw + let ref_ = &*target; + evil(ref_); // invalidates shared ref, activates raw let _x = *ref_; //~ ERROR Shr reference with non-reactivatable tag Frz } diff --git a/tests/compile-fail/stacked_borrows/illegal_write2.rs b/tests/compile-fail/stacked_borrows/illegal_write2.rs index 22648ba71184d..f4fefaad5e22d 100644 --- a/tests/compile-fail/stacked_borrows/illegal_write2.rs +++ b/tests/compile-fail/stacked_borrows/illegal_write2.rs @@ -4,7 +4,7 @@ fn main() { let target = &mut 42; let target2 = target as *mut _; drop(&mut *target); // reborrow - // Now make sure our ref is still the only one - unsafe { *target2 = 13; } // invalidate our ref - let _val = *target; //~ ERROR Mut reference with non-reactivatable tag Mut(Uniq + // Now make sure our ref is still the only one. + unsafe { *target2 = 13; } //~ ERROR does not exist on the stack + let _val = *target; } diff --git a/tests/compile-fail/stacked_borrows/illegal_write3.rs b/tests/compile-fail/stacked_borrows/illegal_write3.rs index 26c30a4122b40..a653aa5003f6d 100644 --- a/tests/compile-fail/stacked_borrows/illegal_write3.rs +++ b/tests/compile-fail/stacked_borrows/illegal_write3.rs @@ -3,6 +3,6 @@ fn main() { // Make sure raw ptr with raw tag cannot mutate frozen location without breaking the shared ref. let r#ref = ⌖ // freeze let ptr = r#ref as *const _ as *mut _; // raw ptr, with raw tag - unsafe { *ptr = 42; } - let _val = *r#ref; //~ ERROR Shr reference with non-reactivatable tag Frz + unsafe { *ptr = 42; } //~ ERROR does not exist on the stack + let _val = *r#ref; } diff --git a/tests/compile-fail/stacked_borrows/illegal_write4.rs b/tests/compile-fail/stacked_borrows/illegal_write4.rs index b2ffac865bd42..2006d7262f813 100644 --- a/tests/compile-fail/stacked_borrows/illegal_write4.rs +++ b/tests/compile-fail/stacked_borrows/illegal_write4.rs @@ -26,6 +26,6 @@ fn main() { let _val = *r#ref; // Make sure it is still frozen. // We only actually unfreeze once we muteate through the bad pointer. - unsafe { *bad_ptr = 42 }; - let _val = *r#ref; //~ ERROR Shr reference with non-reactivatable tag Frz + unsafe { *bad_ptr = 42 }; //~ ERROR does not exist on the stack + let _val = *r#ref; } diff --git a/tests/compile-fail/stacked_borrows/outdated_local.rs b/tests/compile-fail/stacked_borrows/outdated_local.rs new file mode 100644 index 0000000000000..64a8ff69108ec --- /dev/null +++ b/tests/compile-fail/stacked_borrows/outdated_local.rs @@ -0,0 +1,9 @@ +fn main() { + let mut x = 0; + let y: *const i32 = &x; + x = 1; // this invalidates y by reactivating the lowermost uniq borrow for this local + + assert_eq!(unsafe { *y }, 1); //~ ERROR does not exist on the stack + + assert_eq!(x, 1); +} diff --git a/tests/compile-fail/stacked_borrows/pointer_smuggling.rs b/tests/compile-fail/stacked_borrows/pointer_smuggling.rs index 678b9b21ba8c4..68f3d2923b15f 100644 --- a/tests/compile-fail/stacked_borrows/pointer_smuggling.rs +++ b/tests/compile-fail/stacked_borrows/pointer_smuggling.rs @@ -10,7 +10,7 @@ fn fun1(x: &mut u8) { fn fun2() { // Now we use a pointer we are not allowed to use - let _x = unsafe { *PTR }; + let _x = unsafe { *PTR }; //~ ERROR does not exist on the stack } fn main() { @@ -18,5 +18,4 @@ fn main() { fun1(val); *val = 2; // this invalidates any raw ptrs `fun1` might have created. fun2(); // if they now use a raw ptr they break our reference - *val = 3; //~ ERROR Mut reference with non-reactivatable tag Mut(Uniq } diff --git a/tests/compile-fail/stacked_borrows/unescaped_local.rs b/tests/compile-fail/stacked_borrows/unescaped_local.rs new file mode 100644 index 0000000000000..8627cc44c2e50 --- /dev/null +++ b/tests/compile-fail/stacked_borrows/unescaped_local.rs @@ -0,0 +1,10 @@ +use std::mem; + +// Make sure we cannot use raw ptrs to access a local that +// has never been escaped to the raw world. +fn main() { + let mut x = 42; + let ptr = &mut x; + let raw: *mut i32 = unsafe { mem::transmute(ptr) }; + unsafe { *raw = 13; } //~ ERROR does not exist on the stack +} diff --git a/tests/compile-fail/zst.rs b/tests/compile-fail/zst.rs index 0f4c945c85b49..544d65a1bffa6 100644 --- a/tests/compile-fail/zst.rs +++ b/tests/compile-fail/zst.rs @@ -1,4 +1,4 @@ fn main() { let x = &() as *const () as *const i32; - let _ = unsafe { *x }; //~ ERROR outside bounds of allocation + let _ = unsafe { *x }; //~ ERROR access memory with alignment 1, but alignment 4 is required } diff --git a/tests/run-pass/observed_local_mut.rs b/tests/run-pass/observed_local_mut.rs index a4ecf1e635d24..c58e8c84bb2e7 100644 --- a/tests/run-pass/observed_local_mut.rs +++ b/tests/run-pass/observed_local_mut.rs @@ -1,3 +1,6 @@ +// Validation catches this (correctly) as UB. +// compile-flags: -Zmiri-disable-validation + // This test is intended to guard against the problem described in commit // 39bb1254d1eaf74f45a4e741097e33fc942168d5. // diff --git a/tests/run-pass/ptr_arith_offset_overflow.rs b/tests/run-pass/ptr_arith_offset_overflow.rs index 3383c3b801482..9eabc91426044 100644 --- a/tests/run-pass/ptr_arith_offset_overflow.rs +++ b/tests/run-pass/ptr_arith_offset_overflow.rs @@ -1,6 +1,7 @@ fn main() { let v = [1i16, 2]; let x = &v[1] as *const i16; + let _ = &v[0] as *const i16; // we need to leak the 2nd thing too or it cannot be accessed through a raw ptr // Adding 2*isize::max and then 1 is like substracting 1 let x = x.wrapping_offset(isize::max_value()); let x = x.wrapping_offset(isize::max_value()); From 44b3c38b440f9b251ad62e5bd78a0af2015d545d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 22 Oct 2018 18:34:48 +0200 Subject: [PATCH 0288/3747] make sure raw ptrs only have to be valid as far as they are used --- tests/run-pass/deref_partially_dangling_raw.rs | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 tests/run-pass/deref_partially_dangling_raw.rs diff --git a/tests/run-pass/deref_partially_dangling_raw.rs b/tests/run-pass/deref_partially_dangling_raw.rs new file mode 100644 index 0000000000000..8639a289363ba --- /dev/null +++ b/tests/run-pass/deref_partially_dangling_raw.rs @@ -0,0 +1,9 @@ +// Deref a raw ptr to access a field of a large struct, where the field +// is allocated but not the entire struct is. +// For now, we want to allow this. + +fn main() { + let x = (1, 1); + let xptr = &x as *const _ as *const (i32, i32, i32); + let _val = unsafe { (*xptr).1 }; +} From 8cd73e534f3ecc96286c626376a05c1adb48ca64 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 22 Oct 2018 18:51:06 +0200 Subject: [PATCH 0289/3747] use as(_mut)_ptr on slices to entirely escape them to raw --- tests/compile-fail/copy_nonoverlapping.rs | 8 ++------ tests/run-pass/ptr_arith_offset_overflow.rs | 3 +-- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/tests/compile-fail/copy_nonoverlapping.rs b/tests/compile-fail/copy_nonoverlapping.rs index 704711640f7d9..8e8912c81fe90 100644 --- a/tests/compile-fail/copy_nonoverlapping.rs +++ b/tests/compile-fail/copy_nonoverlapping.rs @@ -10,17 +10,13 @@ #![feature(core_intrinsics)] -// FIXME: Validation disabled because it doesn't let us escape an entire slice -// to the raw universe. -// compile-flags: -Zmiri-disable-validation - //error-pattern: copy_nonoverlapping called on overlapping ranges fn main() { let mut data = [0u8; 16]; unsafe { - let a = &data[0] as *const _; - let b = &mut data[1] as *mut _; + let a = data.as_mut_ptr(); + let b = a.wrapping_offset(1) as *mut _; std::ptr::copy_nonoverlapping(a, b, 2); } } diff --git a/tests/run-pass/ptr_arith_offset_overflow.rs b/tests/run-pass/ptr_arith_offset_overflow.rs index 9eabc91426044..6b778248be5c6 100644 --- a/tests/run-pass/ptr_arith_offset_overflow.rs +++ b/tests/run-pass/ptr_arith_offset_overflow.rs @@ -1,7 +1,6 @@ fn main() { let v = [1i16, 2]; - let x = &v[1] as *const i16; - let _ = &v[0] as *const i16; // we need to leak the 2nd thing too or it cannot be accessed through a raw ptr + let x = v.as_ptr().wrapping_offset(1); // ptr to the 2nd element // Adding 2*isize::max and then 1 is like substracting 1 let x = x.wrapping_offset(isize::max_value()); let x = x.wrapping_offset(isize::max_value()); From cc328f6374263f0c4aa9f37b9965e25b25b0515f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 23 Oct 2018 11:18:50 +0200 Subject: [PATCH 0290/3747] test passing invalid refs around --- .../compile-fail/stacked_borrows/load_invalid_mut.rs | 9 +++++++++ .../compile-fail/stacked_borrows/pass_invalid_mut.rs | 10 ++++++++++ .../stacked_borrows/return_invalid_mut.rs | 11 +++++++++++ 3 files changed, 30 insertions(+) create mode 100644 tests/compile-fail/stacked_borrows/load_invalid_mut.rs create mode 100644 tests/compile-fail/stacked_borrows/pass_invalid_mut.rs create mode 100644 tests/compile-fail/stacked_borrows/return_invalid_mut.rs diff --git a/tests/compile-fail/stacked_borrows/load_invalid_mut.rs b/tests/compile-fail/stacked_borrows/load_invalid_mut.rs new file mode 100644 index 0000000000000..e52b84a907e9d --- /dev/null +++ b/tests/compile-fail/stacked_borrows/load_invalid_mut.rs @@ -0,0 +1,9 @@ +// Make sure that we cannot load from memory a `&mut` that got already invalidated. +fn main() { + let x = &mut 42; + let xraw = x as *mut _; + let xref = unsafe { &mut *xraw }; + let xref_in_mem = Box::new(xref); + let _val = *x; // invalidate xraw + let _val = *xref_in_mem; //~ ERROR Mut reference with non-reactivatable tag Mut(Uniq +} diff --git a/tests/compile-fail/stacked_borrows/pass_invalid_mut.rs b/tests/compile-fail/stacked_borrows/pass_invalid_mut.rs new file mode 100644 index 0000000000000..f3de3f0c4ac37 --- /dev/null +++ b/tests/compile-fail/stacked_borrows/pass_invalid_mut.rs @@ -0,0 +1,10 @@ +// Make sure that we cannot pass by argument a `&mut` that got already invalidated. +fn foo(_: &mut i32) {} + +fn main() { + let x = &mut 42; + let xraw = x as *mut _; + let xref = unsafe { &mut *xraw }; + let _val = *x; // invalidate xraw + foo(xref); //~ ERROR Mut reference with non-reactivatable tag Mut(Uniq +} diff --git a/tests/compile-fail/stacked_borrows/return_invalid_mut.rs b/tests/compile-fail/stacked_borrows/return_invalid_mut.rs new file mode 100644 index 0000000000000..6a4123d325b41 --- /dev/null +++ b/tests/compile-fail/stacked_borrows/return_invalid_mut.rs @@ -0,0 +1,11 @@ +// Make sure that we cannot return a `&mut` that got already invalidated. +fn foo(x: &mut (i32, i32)) -> &mut i32 { + let xraw = x as *mut (i32, i32); + let ret = unsafe { &mut (*xraw).1 }; + let _val = *x; // invalidate xraw and its children + ret //~ ERROR Mut reference with non-reactivatable tag Mut(Uniq +} + +fn main() { + foo(&mut (1, 2)); +} From fe83ef323cec57465948bdba654201eed22c3355 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 23 Oct 2018 13:09:17 +0200 Subject: [PATCH 0291/3747] also run compile-fail tests with and without optimizations --- src/stacked_borrows.rs | 2 + .../stacked_borrows/alias_through_mutation.rs | 3 + .../stacked_borrows/buggy_as_mut_slice.rs | 3 + .../stacked_borrows/buggy_split_at_mut.rs | 3 + .../stacked_borrows/illegal_write2.rs | 3 + tests/compiletest.rs | 60 +++++++++++-------- tests/run-pass-fullmir/integer-ops.rs | 3 - 7 files changed, 50 insertions(+), 27 deletions(-) diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 127958476bcb3..316316351863a 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -446,6 +446,8 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' // A mut got transmuted to shr. High time we freeze this location! // Make this a delayed reborrow. Redundant reborows to shr are okay, // so we do not have to be worried about doing too much. + // FIXME: Reconsider if we really want to mutate things while doing just a deref, + // which, in particular, validation does. trace!("tag_dereference: Lazy freezing of {:?}", ptr); return self.tag_reference(ptr, pointee_ty, size, ref_kind); } diff --git a/tests/compile-fail/stacked_borrows/alias_through_mutation.rs b/tests/compile-fail/stacked_borrows/alias_through_mutation.rs index 3fcf20e156256..83132195fe465 100644 --- a/tests/compile-fail/stacked_borrows/alias_through_mutation.rs +++ b/tests/compile-fail/stacked_borrows/alias_through_mutation.rs @@ -1,3 +1,6 @@ +// With optimizations, we just store a raw in `x`, and there is no problem. +// compile-flags: -Zmir-opt-level=0 + #![allow(unused_variables)] // This makes a ref that was passed to us via &mut alias with things it should not alias with diff --git a/tests/compile-fail/stacked_borrows/buggy_as_mut_slice.rs b/tests/compile-fail/stacked_borrows/buggy_as_mut_slice.rs index 5f729af30bbe6..9e94aa8885d2c 100644 --- a/tests/compile-fail/stacked_borrows/buggy_as_mut_slice.rs +++ b/tests/compile-fail/stacked_borrows/buggy_as_mut_slice.rs @@ -1,3 +1,6 @@ +// FIXME: Without retagging, optimization kills finding this problem +// compile-flags: -Zmir-opt-level=0 + #![allow(unused_variables)] mod safe { diff --git a/tests/compile-fail/stacked_borrows/buggy_split_at_mut.rs b/tests/compile-fail/stacked_borrows/buggy_split_at_mut.rs index 0a890b1cebaa1..9fbcec4a8ef80 100644 --- a/tests/compile-fail/stacked_borrows/buggy_split_at_mut.rs +++ b/tests/compile-fail/stacked_borrows/buggy_split_at_mut.rs @@ -1,3 +1,6 @@ +// FIXME: Without retagging, optimization kills finding this problem +// compile-flags: -Zmir-opt-level=0 + #![allow(unused_variables)] mod safe { diff --git a/tests/compile-fail/stacked_borrows/illegal_write2.rs b/tests/compile-fail/stacked_borrows/illegal_write2.rs index f4fefaad5e22d..ac9c3397f5348 100644 --- a/tests/compile-fail/stacked_borrows/illegal_write2.rs +++ b/tests/compile-fail/stacked_borrows/illegal_write2.rs @@ -1,3 +1,6 @@ +// The reborow gets optimized away, so we can only detect this issue without optimizations +// compile-flags: -Zmir-opt-level=0 + #![allow(unused_variables)] fn main() { diff --git a/tests/compiletest.rs b/tests/compiletest.rs index 7a7d7e49b2db5..8070f817bcf6a 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -37,7 +37,7 @@ fn have_fullmir() -> bool { std::env::var("MIRI_SYSROOT").is_ok() || rustc_test_suite().is_some() } -fn compile_fail(sysroot: &Path, path: &str, target: &str, host: &str, need_fullmir: bool) { +fn compile_fail(sysroot: &Path, path: &str, target: &str, host: &str, need_fullmir: bool, opt: bool) { if need_fullmir && !have_fullmir() { eprintln!("{}", format!( "## Skipping compile-fail tests in {} against miri for target {} due to missing mir", @@ -47,24 +47,34 @@ fn compile_fail(sysroot: &Path, path: &str, target: &str, host: &str, need_fullm return; } + let opt_str = if opt { " with optimizations" } else { "" }; eprintln!("{}", format!( - "## Running compile-fail tests in {} against miri for target {}", + "## Running compile-fail tests in {} against miri for target {}{}", path, - target + target, + opt_str ).green().bold()); + + let mut flags = Vec::new(); + flags.push(format!("--sysroot {}", sysroot.display())); + flags.push("-Dwarnings -Dunused".to_owned()); // overwrite the -Aunused in compiletest-rs + flags.push("-Zmir-emit-validate=1".to_owned()); + if opt { + // Optimizing too aggressivley makes UB detection harder, but test at least + // the default value. + flags.push("-Zmir-opt-level=1".to_owned()); + } else { + flags.push("-Zmir-opt-level=0".to_owned()); + } + let mut config = compiletest::Config::default().tempdir(); config.mode = "compile-fail".parse().expect("Invalid mode"); config.rustc_path = miri_path(); - let mut flags = Vec::new(); if rustc_test_suite().is_some() { config.run_lib_path = rustc_lib_path(); config.compile_lib_path = rustc_lib_path(); } - flags.push(format!("--sysroot {}", sysroot.display())); - flags.push("-Dwarnings -Dunused".to_owned()); // overwrite the -Aunused in compiletest-rs config.src_base = PathBuf::from(path.to_string()); - flags.push("-Zmir-opt-level=0".to_owned()); // optimization circumvents some stacked borrow checks - flags.push("-Zmir-emit-validate=1".to_owned()); config.target_rustcflags = Some(flags.join(" ")); config.target = target.to_owned(); config.host = host.to_owned(); @@ -88,19 +98,11 @@ fn miri_pass(sysroot: &Path, path: &str, target: &str, host: &str, need_fullmir: target, opt_str ).green().bold()); - let mut config = compiletest::Config::default().tempdir(); - config.mode = "ui".parse().expect("Invalid mode"); - config.src_base = PathBuf::from(path); - config.target = target.to_owned(); - config.host = host.to_owned(); - config.rustc_path = miri_path(); - if rustc_test_suite().is_some() { - config.run_lib_path = rustc_lib_path(); - config.compile_lib_path = rustc_lib_path(); - } + let mut flags = Vec::new(); flags.push(format!("--sysroot {}", sysroot.display())); flags.push("-Dwarnings -Dunused".to_owned()); // overwrite the -Aunused in compiletest-rs + flags.push("-Zmir-emit-validate=1".to_owned()); if opt { // FIXME: Using level 1 (instead of 3) for now, as the optimizer is pretty broken // and crashes... @@ -109,8 +111,17 @@ fn miri_pass(sysroot: &Path, path: &str, target: &str, host: &str, need_fullmir: flags.push("-Zmir-opt-level=1".to_owned()); } else { flags.push("-Zmir-opt-level=0".to_owned()); - // For now, only validate without optimizations. Inlining breaks validation. - flags.push("-Zmir-emit-validate=1".to_owned()); + } + + let mut config = compiletest::Config::default().tempdir(); + config.mode = "ui".parse().expect("Invalid mode"); + config.src_base = PathBuf::from(path); + config.target = target.to_owned(); + config.host = host.to_owned(); + config.rustc_path = miri_path(); + if rustc_test_suite().is_some() { + config.run_lib_path = rustc_lib_path(); + config.compile_lib_path = rustc_lib_path(); } config.target_rustcflags = Some(flags.join(" ")); compiletest::run_tests(&config); @@ -173,13 +184,13 @@ fn run_pass_miri(opt: bool) { miri_pass(&sysroot, "tests/run-pass-fullmir", &host, &host, true, opt); } -fn compile_fail_miri() { +fn compile_fail_miri(opt: bool) { let sysroot = get_sysroot(); let host = get_host(); // FIXME: run tests for other targets, too - compile_fail(&sysroot, "tests/compile-fail", &host, &host, false); - compile_fail(&sysroot, "tests/compile-fail-fullmir", &host, &host, true); + compile_fail(&sysroot, "tests/compile-fail", &host, &host, false, opt); + compile_fail(&sysroot, "tests/compile-fail-fullmir", &host, &host, true, opt); } #[test] @@ -191,5 +202,6 @@ fn test() { run_pass_miri(false); run_pass_miri(true); - compile_fail_miri(); + compile_fail_miri(false); + compile_fail_miri(true); } diff --git a/tests/run-pass-fullmir/integer-ops.rs b/tests/run-pass-fullmir/integer-ops.rs index 7a2335c829efe..0264099eb68dc 100644 --- a/tests/run-pass-fullmir/integer-ops.rs +++ b/tests/run-pass-fullmir/integer-ops.rs @@ -8,9 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// FIXME: remove -Zmir-opt-level once https://github.com/rust-lang/rust/issues/43359 is fixed -// compile-flags: -Zmir-opt-level=0 - use std::i32; pub fn main() { From 5388037f8a16d3bf443f348e28873d255db044d0 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 23 Oct 2018 15:59:50 +0200 Subject: [PATCH 0292/3747] remove code duplication by letting reactivatable() compute what reactivate() has to do --- src/stacked_borrows.rs | 89 ++++++++----------- .../stacked_borrows/alias_through_mutation.rs | 2 +- .../stacked_borrows/buggy_as_mut_slice.rs | 2 +- .../stacked_borrows/buggy_split_at_mut.rs | 2 +- .../stacked_borrows/illegal_write1.rs | 2 +- .../stacked_borrows/load_invalid_mut.rs | 2 +- .../stacked_borrows/pass_invalid_mut.rs | 2 +- .../stacked_borrows/return_invalid_mut.rs | 2 +- .../stacked_borrows/shared_confusion.rs | 2 +- 9 files changed, 47 insertions(+), 58 deletions(-) diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 316316351863a..f634f17109c74 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -137,75 +137,64 @@ impl<'tcx> Stack { } /// Check if `bor` could be activated by unfreezing and popping. - /// This should be in sync with `reactivate`! - fn reactivatable(&self, bor: Borrow) -> bool { - if self.check(bor) { - return true; - } - - let acc_m = match bor { - Borrow::Frz(_) => return false, - Borrow::Mut(acc_m) => acc_m - }; - // This is where we would unfreeze. - for &itm in self.borrows.iter().rev() { - match itm { - BorStackItem::FnBarrier(_) => return false, - BorStackItem::Mut(loc_m) => { - if loc_m == acc_m { return true; } - // Go on looking. - } - } - } - // Nothing to be found. - false - } - - /// Reactive `bor` for this stack. If `force_mut` is set, we want to aggressively - /// unfreeze this location (because we are about to mutate, so a frozen `Raw` is not okay). - fn reactivate(&mut self, bor: Borrow, force_mut: bool) -> EvalResult<'tcx> { + /// `force_mut` indicates whether being frozen is potentially acceptable. + /// Returns `Err` if the answer is "no"; otherwise the data says + /// what needs to happen to activate this: `None` = nothing, + /// `Some(n)` = unfreeze and make item `n` the top item of the stack. + fn reactivatable(&self, bor: Borrow, force_mut: bool) -> Result, String> { // Unless mutation is bound to happen, do NOT change anything if `bor` is already active. // In particular, if it is a `Mut(Raw)` and we are frozen, this should be a NOP. if !force_mut && self.check(bor) { - return Ok(()); + return Ok(None); } let acc_m = match bor { Borrow::Frz(since) => - if force_mut { - return err!(MachineError(format!("Using a shared borrow for mutation"))) + return Err(if force_mut { + format!("Using a shared borrow for mutation") } else { - return err!(MachineError(format!( + format!( "Location should be frozen since {} but {}", since, match self.frozen_since { None => format!("it is not frozen at all"), Some(since) => format!("it is only frozen since {}", since), } - ))) - } - Borrow::Mut(acc_m) => acc_m, + ) + }), + Borrow::Mut(acc_m) => acc_m }; - // We definitely have to unfreeze this, even if we use the topmost item. - if self.frozen_since.is_some() { - trace!("reactivate: Unfreezing"); - } - self.frozen_since = None; - // Pop until we see the one we are looking for. - while let Some(&itm) = self.borrows.last() { + // This is where we would unfreeze. + for (idx, &itm) in self.borrows.iter().enumerate().rev() { match itm { - BorStackItem::FnBarrier(_) => { - return err!(MachineError(format!("Trying to reactivate a borrow that lives behind a barrier"))); - } + BorStackItem::FnBarrier(_) => + return Err(format!("Trying to reactivate a mutable borrow ({:?}) that lives behind a barrier", acc_m)), BorStackItem::Mut(loc_m) => { - if loc_m == acc_m { return Ok(()); } - trace!("reactivate: Popping {:?}", itm); - self.borrows.pop(); + if loc_m == acc_m { return Ok(Some(idx)); } } } } // Nothing to be found. - err!(MachineError(format!("Borrow-to-reactivate does not exist on the stack"))) + Err(format!("Mutable borrow-to-reactivate ({:?}) does not exist on the stack", acc_m)) + } + + /// Reactive `bor` for this stack. If `force_mut` is set, we want to aggressively + /// unfreeze this location (because we are about to mutate, so a frozen `Raw` is not okay). + fn reactivate(&mut self, bor: Borrow, force_mut: bool) -> EvalResult<'tcx> { + let action = match self.reactivatable(bor, force_mut) { + Ok(action) => action, + Err(err) => return err!(MachineError(err)), + }; + + match action { + None => {}, // nothing to do + Some(top) => { + self.frozen_since = None; + self.borrows.truncate(top+1); + } + } + + Ok(()) } /// Initiate `bor`; mostly this means freezing or pushing. @@ -471,8 +460,8 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' // be shared reborrows that we are about to invalidate with this access. // We cannot invalidate them aggressively here because the deref might also be // to just create more shared refs. - if !stack.reactivatable(ptr.tag) { - return err!(MachineError(format!("Encountered {:?} reference with non-reactivatable tag {:?}", ref_kind, ptr.tag))) + if let Err(err) = stack.reactivatable(ptr.tag, /*force_mut*/false) { + return err!(MachineError(format!("Encountered {:?} reference with non-reactivatable tag: {}", ref_kind, err))) } } // All is good. diff --git a/tests/compile-fail/stacked_borrows/alias_through_mutation.rs b/tests/compile-fail/stacked_borrows/alias_through_mutation.rs index 83132195fe465..7d56f30b3e69d 100644 --- a/tests/compile-fail/stacked_borrows/alias_through_mutation.rs +++ b/tests/compile-fail/stacked_borrows/alias_through_mutation.rs @@ -14,5 +14,5 @@ fn main() { retarget(&mut target_alias, target); // now `target_alias` points to the same thing as `target` *target = 13; - let _val = *target_alias; //~ ERROR Shr reference with non-reactivatable tag Frz + let _val = *target_alias; //~ ERROR Shr reference with non-reactivatable tag } diff --git a/tests/compile-fail/stacked_borrows/buggy_as_mut_slice.rs b/tests/compile-fail/stacked_borrows/buggy_as_mut_slice.rs index 9e94aa8885d2c..dc1e3cc81e9e8 100644 --- a/tests/compile-fail/stacked_borrows/buggy_as_mut_slice.rs +++ b/tests/compile-fail/stacked_borrows/buggy_as_mut_slice.rs @@ -17,6 +17,6 @@ fn main() { let v = vec![0,1,2]; let v1 = safe::as_mut_slice(&v); let v2 = safe::as_mut_slice(&v); - v1[1] = 5; //~ ERROR Mut reference with non-reactivatable tag Mut(Uniq + v1[1] = 5; //~ ERROR Mut reference with non-reactivatable tag v1[1] = 6; } diff --git a/tests/compile-fail/stacked_borrows/buggy_split_at_mut.rs b/tests/compile-fail/stacked_borrows/buggy_split_at_mut.rs index 9fbcec4a8ef80..a697ba9167c07 100644 --- a/tests/compile-fail/stacked_borrows/buggy_split_at_mut.rs +++ b/tests/compile-fail/stacked_borrows/buggy_split_at_mut.rs @@ -14,7 +14,7 @@ mod safe { assert!(mid <= len); (from_raw_parts_mut(ptr, len - mid), // BUG: should be "mid" instead of "len - mid" - //~^ ERROR Mut reference with non-reactivatable tag Mut(Uniq + //~^ ERROR Mut reference with non-reactivatable tag from_raw_parts_mut(ptr.offset(mid as isize), len - mid)) } } diff --git a/tests/compile-fail/stacked_borrows/illegal_write1.rs b/tests/compile-fail/stacked_borrows/illegal_write1.rs index ff3a3cd82245c..131e89572a501 100644 --- a/tests/compile-fail/stacked_borrows/illegal_write1.rs +++ b/tests/compile-fail/stacked_borrows/illegal_write1.rs @@ -8,5 +8,5 @@ fn main() { let target = Box::new(42); // has an implicit raw let ref_ = &*target; evil(ref_); // invalidates shared ref, activates raw - let _x = *ref_; //~ ERROR Shr reference with non-reactivatable tag Frz + let _x = *ref_; //~ ERROR Shr reference with non-reactivatable tag } diff --git a/tests/compile-fail/stacked_borrows/load_invalid_mut.rs b/tests/compile-fail/stacked_borrows/load_invalid_mut.rs index e52b84a907e9d..060cec962c477 100644 --- a/tests/compile-fail/stacked_borrows/load_invalid_mut.rs +++ b/tests/compile-fail/stacked_borrows/load_invalid_mut.rs @@ -5,5 +5,5 @@ fn main() { let xref = unsafe { &mut *xraw }; let xref_in_mem = Box::new(xref); let _val = *x; // invalidate xraw - let _val = *xref_in_mem; //~ ERROR Mut reference with non-reactivatable tag Mut(Uniq + let _val = *xref_in_mem; //~ ERROR Mut reference with non-reactivatable tag } diff --git a/tests/compile-fail/stacked_borrows/pass_invalid_mut.rs b/tests/compile-fail/stacked_borrows/pass_invalid_mut.rs index f3de3f0c4ac37..bc950771add4f 100644 --- a/tests/compile-fail/stacked_borrows/pass_invalid_mut.rs +++ b/tests/compile-fail/stacked_borrows/pass_invalid_mut.rs @@ -6,5 +6,5 @@ fn main() { let xraw = x as *mut _; let xref = unsafe { &mut *xraw }; let _val = *x; // invalidate xraw - foo(xref); //~ ERROR Mut reference with non-reactivatable tag Mut(Uniq + foo(xref); //~ ERROR Mut reference with non-reactivatable tag } diff --git a/tests/compile-fail/stacked_borrows/return_invalid_mut.rs b/tests/compile-fail/stacked_borrows/return_invalid_mut.rs index 6a4123d325b41..c02892671e907 100644 --- a/tests/compile-fail/stacked_borrows/return_invalid_mut.rs +++ b/tests/compile-fail/stacked_borrows/return_invalid_mut.rs @@ -3,7 +3,7 @@ fn foo(x: &mut (i32, i32)) -> &mut i32 { let xraw = x as *mut (i32, i32); let ret = unsafe { &mut (*xraw).1 }; let _val = *x; // invalidate xraw and its children - ret //~ ERROR Mut reference with non-reactivatable tag Mut(Uniq + ret //~ ERROR Mut reference with non-reactivatable tag } fn main() { diff --git a/tests/compile-fail/stacked_borrows/shared_confusion.rs b/tests/compile-fail/stacked_borrows/shared_confusion.rs index 5098f493ccd73..e3e4c4da7765e 100644 --- a/tests/compile-fail/stacked_borrows/shared_confusion.rs +++ b/tests/compile-fail/stacked_borrows/shared_confusion.rs @@ -13,7 +13,7 @@ fn test(r: &mut RefCell) { } // Our old raw should be dead by now unsafe { *x_evil = 0; } // this falls back to some Raw higher up the stack - *x_inner = 12; //~ ERROR Mut reference with non-reactivatable tag Mut(Uniq + *x_inner = 12; //~ ERROR Mut reference with non-reactivatable tag } fn main() { From 356369dd08f968b74b8bdee3a177f9919194914b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 23 Oct 2018 16:01:22 +0200 Subject: [PATCH 0293/3747] test against passing invalid shared refs around --- .../compile-fail/stacked_borrows/load_invalid_shr.rs | 9 +++++++++ .../compile-fail/stacked_borrows/pass_invalid_shr.rs | 10 ++++++++++ .../stacked_borrows/return_invalid_shr.rs | 11 +++++++++++ 3 files changed, 30 insertions(+) create mode 100644 tests/compile-fail/stacked_borrows/load_invalid_shr.rs create mode 100644 tests/compile-fail/stacked_borrows/pass_invalid_shr.rs create mode 100644 tests/compile-fail/stacked_borrows/return_invalid_shr.rs diff --git a/tests/compile-fail/stacked_borrows/load_invalid_shr.rs b/tests/compile-fail/stacked_borrows/load_invalid_shr.rs new file mode 100644 index 0000000000000..785a15c4704a3 --- /dev/null +++ b/tests/compile-fail/stacked_borrows/load_invalid_shr.rs @@ -0,0 +1,9 @@ +// Make sure that we cannot load from memory a `&` that got already invalidated. +fn main() { + let x = &mut 42; + let xraw = x as *mut _; + let xref = unsafe { &*xraw }; + let xref_in_mem = Box::new(xref); + let _val = *x; // invalidate xraw + let _val = *xref_in_mem; //~ ERROR Shr reference with non-reactivatable tag: Location should be frozen +} diff --git a/tests/compile-fail/stacked_borrows/pass_invalid_shr.rs b/tests/compile-fail/stacked_borrows/pass_invalid_shr.rs new file mode 100644 index 0000000000000..8b7a846d849c0 --- /dev/null +++ b/tests/compile-fail/stacked_borrows/pass_invalid_shr.rs @@ -0,0 +1,10 @@ +// Make sure that we cannot pass by argument a `&` that got already invalidated. +fn foo(_: &i32) {} + +fn main() { + let x = &mut 42; + let xraw = &*x as *const _; + let xref = unsafe { &*xraw }; + let _val = *x; // invalidate xraw + foo(xref); //~ ERROR Shr reference with non-reactivatable tag: Location should be frozen +} diff --git a/tests/compile-fail/stacked_borrows/return_invalid_shr.rs b/tests/compile-fail/stacked_borrows/return_invalid_shr.rs new file mode 100644 index 0000000000000..89c94127b0b71 --- /dev/null +++ b/tests/compile-fail/stacked_borrows/return_invalid_shr.rs @@ -0,0 +1,11 @@ +// Make sure that we cannot return a `&` that got already invalidated. +fn foo(x: &mut (i32, i32)) -> &i32 { + let xraw = x as *mut (i32, i32); + let ret = unsafe { &(*xraw).1 }; + let _val = *x; // invalidate xraw and its children + ret //~ ERROR Shr reference with non-reactivatable tag: Location should be frozen +} + +fn main() { + foo(&mut (1, 2)); +} From 95f740600c530658a40687f169e2337171cbe612 Mon Sep 17 00:00:00 2001 From: Andrew Poelstra Date: Mon, 15 Oct 2018 18:45:55 +0000 Subject: [PATCH 0294/3747] improve README instructions for using `rustup` and for compiling separate Cargo projects --- README.md | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index e59accaea1b9b..9c6128643c95a 100644 --- a/README.md +++ b/README.md @@ -47,13 +47,29 @@ You can also set `-Zmiri-start-fn` to make Miri start evaluation with the ## Running Miri on your own project('s test suite) -Install Miri as a cargo subcommand with `cargo install --all-features`, and install -a full libstd as described above. +Install Miri as a cargo subcommand with `cargo install --all-features --path .`. -Then, inside your own project, use `MIRI_SYSROOT=~/.xargo/HOST cargo +nightly -miri` to run your project, if it is a bin project, or run -`MIRI_SYSROOT=~/.xargo/HOST cargo +nightly miri test` to run all tests in your -project through Miri. +Compile your project and its dependencies against a MIR-enabled libstd as described +above: + +1. Run `cargo clean` to eliminate any cached dependencies that were built against +the non-MIR `libstd`. +2. For a binary project, run `MIRI_SYSROOT=~/.xargo/HOST cargo +nightly miri` to +build and run your project; for a binary or library, use `MIRI_SYSROOT=~/.xargo/HOST cargo +nightly miri test` +to run all tests in your project through Miri. + +If you forget to set `MIRI_SYSROOT`, be sure to run `cargo clean` again before +correcting it. Otherwise you are likely to get "dependency was built against possibly +newer std" errors. + +## Using Rustup To Specify a Specific Nightly + +To target a specific nightly, modify the above instructions as follows. + +1. Install Miri using `cargo +nightly-2018-10-15 install --all-features --path .`, +with the date replaced as appropriate. +2. Run `xargo/build.sh` as `rustup run nightly-2018-10-15 build.sh`. +3. When running tests, use `MIRI_SYSROOT=~/.xargo/HOST cargo +nightly-2018-10-15 miri test`. ## Miri `-Z` flags From f77b29294829564f6d95148ef1e3749587518dfa Mon Sep 17 00:00:00 2001 From: Andrew Poelstra Date: Fri, 19 Oct 2018 15:07:19 +0000 Subject: [PATCH 0295/3747] added line indicating that `build.sh` and `cargo miri` need the same toolchain --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 9c6128643c95a..087a2a44cff75 100644 --- a/README.md +++ b/README.md @@ -71,6 +71,10 @@ with the date replaced as appropriate. 2. Run `xargo/build.sh` as `rustup run nightly-2018-10-15 build.sh`. 3. When running tests, use `MIRI_SYSROOT=~/.xargo/HOST cargo +nightly-2018-10-15 miri test`. +You may prefer to do this rather than depending on the rustup default toolchain, +if you routinely update the default, since **it is essential that `xargo/build.sh` +is run with the same toolchain as `cargo miri`.** + ## Miri `-Z` flags Miri adds some extra `-Z` flags to control its behavior: From 3dcf655eead8aa4f041d881a91200fc9998d4405 Mon Sep 17 00:00:00 2001 From: Andrew Poelstra Date: Sat, 20 Oct 2018 16:31:15 +0000 Subject: [PATCH 0296/3747] readme: pull "common problems" into their own section --- README.md | 38 +++++++++++++++++++++++++++----------- 1 file changed, 27 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 087a2a44cff75..e5c2850ef3eb1 100644 --- a/README.md +++ b/README.md @@ -54,13 +54,33 @@ above: 1. Run `cargo clean` to eliminate any cached dependencies that were built against the non-MIR `libstd`. -2. For a binary project, run `MIRI_SYSROOT=~/.xargo/HOST cargo +nightly miri` to -build and run your project; for a binary or library, use `MIRI_SYSROOT=~/.xargo/HOST cargo +nightly miri test` -to run all tests in your project through Miri. +2. To run all tests in your project through, Miri, use +`MIRI_SYSROOT=~/.xargo/HOST cargo +nightly miri test`. +3. If you have a binary project, you can run it through Miri using +`MIRI_SYSROOT=~/.xargo/HOST cargo +nightly miri`. -If you forget to set `MIRI_SYSROOT`, be sure to run `cargo clean` again before -correcting it. Otherwise you are likely to get "dependency was built against possibly -newer std" errors. +### Common Problems + +When modifying the above instructions, you may encounter a number of confusing compiler +errors. + +#### "constant evaluation error: no mir for ``" + +You may have forgotten to set `MIRI_SYSROOT` when calling `cargo miri test`, and +your program called into `std` or `core`. Be sure to set `MIRI_SYSROOT=~/.xargo/HOST`. + +#### "found possibly newer version of crate `std` which `` depends on" + +Your build directory may contain artifacts from an earlier build that did/did not +have `MIRI_SYSROOT` set. Run `cargo clean` before switching from non-Miri to Miri +builds and vice-versa. + +#### "found crate `std` compiled by an incompatible version of rustc" + +You may be running `cargo miri test` with a different compiler version than the one +used to build the MIR-enabled `std`. Be sure to consistently use the same toolchain, +perhaps by following the below instructions to specify a specific nightly for use +with Miri. ## Using Rustup To Specify a Specific Nightly @@ -68,13 +88,9 @@ To target a specific nightly, modify the above instructions as follows. 1. Install Miri using `cargo +nightly-2018-10-15 install --all-features --path .`, with the date replaced as appropriate. -2. Run `xargo/build.sh` as `rustup run nightly-2018-10-15 build.sh`. +2. Run `xargo/build.sh` as `rustup run nightly-2018-10-15 xargo/build.sh`. 3. When running tests, use `MIRI_SYSROOT=~/.xargo/HOST cargo +nightly-2018-10-15 miri test`. -You may prefer to do this rather than depending on the rustup default toolchain, -if you routinely update the default, since **it is essential that `xargo/build.sh` -is run with the same toolchain as `cargo miri`.** - ## Miri `-Z` flags Miri adds some extra `-Z` flags to control its behavior: From abda1a8ebb4f38929a6f62e73b81ce6deb95ef61 Mon Sep 17 00:00:00 2001 From: Andrew Poelstra Date: Sun, 21 Oct 2018 16:46:28 +0000 Subject: [PATCH 0297/3747] rename `rust-toolchain` to `rust-version`; add note to README about usage --- .travis.yml | 3 +-- README.md | 4 +++- appveyor.yml | 2 +- rust-toolchain => rust-version | 0 4 files changed, 5 insertions(+), 4 deletions(-) rename rust-toolchain => rust-version (100%) diff --git a/.travis.yml b/.travis.yml index d2315c7e9538e..095af11627fac 100644 --- a/.travis.yml +++ b/.travis.yml @@ -18,9 +18,8 @@ before_script: if [ "$TRAVIS_EVENT_TYPE" = cron ]; then RUST_TOOLCHAIN=nightly else - RUST_TOOLCHAIN=$(cat rust-toolchain) + RUST_TOOLCHAIN=$(cat rust-version) fi -- rm rust-toolchain # install Rust - curl https://build.travis-ci.org/files/rustup-init.sh -sSf | sh -s -- -y --default-toolchain "$RUST_TOOLCHAIN" - export PATH=$HOME/.cargo/bin:$PATH diff --git a/README.md b/README.md index e5c2850ef3eb1..76127d8b62a98 100644 --- a/README.md +++ b/README.md @@ -84,7 +84,9 @@ with Miri. ## Using Rustup To Specify a Specific Nightly -To target a specific nightly, modify the above instructions as follows. +To target a specific nightly, modify the above instructions as follows. It is recommended +to use the nightly specified in the `rust-version` file in this repo, since that is the +most recent nightly supported by Miri. 1. Install Miri using `cargo +nightly-2018-10-15 install --all-features --path .`, with the date replaced as appropriate. diff --git a/appveyor.yml b/appveyor.yml index 4614891a31297..cf578120c9ddf 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -16,7 +16,7 @@ branches: install: # install Rust - set PATH=C:\Program Files\Git\mingw64\bin;C:\msys64\mingw%MSYS2_BITS%\bin;%PATH% - - set /p RUST_TOOLCHAIN= Date: Tue, 23 Oct 2018 15:21:19 +0000 Subject: [PATCH 0298/3747] README: remove "specific nightly" instructions and use +nightly throughout Also replace `cargo miri test` with `cargo miri` in general examples. --- README.md | 40 +++++++++++++++------------------------- 1 file changed, 15 insertions(+), 25 deletions(-) diff --git a/README.md b/README.md index 76127d8b62a98..7597c9a0e11bd 100644 --- a/README.md +++ b/README.md @@ -8,17 +8,19 @@ undergraduate research course at the [University of Saskatchewan][usask]. ## Building Miri I recommend that you install [rustup][rustup] to obtain Rust. Miri comes with a -`rust-toolchain` file so rustup will automatically pick a suitable nightly -version. Then all you have to do is: +`rust-version` file describing the latest supported nightly version of the Rust +compiler toolchain. Then all you have to do is: ```sh -cargo build +cargo +nightly build ``` +with `+nightly` replaced with the appropriate nightly version of Rust. + ## Running Miri ```sh -cargo run tests/run-pass/vecs.rs # Or whatever test you like. +cargo +nightly run tests/run-pass/vecs.rs # Or whatever test you like. ``` ## Running Miri with full libstd @@ -28,15 +30,15 @@ Miri hits a call to such a function, execution terminates. To fix this, it is possible to compile libstd with full MIR: ```sh -rustup component add rust-src -cargo install xargo -xargo/build.sh +rustup component add --toolchain nightly rust-src +cargo +nightly install xargo +rustup run nightly xargo/build.sh ``` Now you can run Miri against the libstd compiled by xargo: ```sh -MIRI_SYSROOT=~/.xargo/HOST cargo run tests/run-pass-fullmir/hashmap.rs +MIRI_SYSROOT=~/.xargo/HOST cargo +nightly run tests/run-pass-fullmir/hashmap.rs ``` Notice that you will have to re-run the last step of the preparations above when @@ -47,7 +49,7 @@ You can also set `-Zmiri-start-fn` to make Miri start evaluation with the ## Running Miri on your own project('s test suite) -Install Miri as a cargo subcommand with `cargo install --all-features --path .`. +Install Miri as a cargo subcommand with `cargo install +nightly --all-features --path .`. Compile your project and its dependencies against a MIR-enabled libstd as described above: @@ -61,12 +63,12 @@ the non-MIR `libstd`. ### Common Problems -When modifying the above instructions, you may encounter a number of confusing compiler +When using the above instructions, you may encounter a number of confusing compiler errors. #### "constant evaluation error: no mir for ``" -You may have forgotten to set `MIRI_SYSROOT` when calling `cargo miri test`, and +You may have forgotten to set `MIRI_SYSROOT` when calling `cargo miri`, and your program called into `std` or `core`. Be sure to set `MIRI_SYSROOT=~/.xargo/HOST`. #### "found possibly newer version of crate `std` which `` depends on" @@ -77,21 +79,9 @@ builds and vice-versa. #### "found crate `std` compiled by an incompatible version of rustc" -You may be running `cargo miri test` with a different compiler version than the one +You may be running `cargo miri` with a different compiler version than the one used to build the MIR-enabled `std`. Be sure to consistently use the same toolchain, -perhaps by following the below instructions to specify a specific nightly for use -with Miri. - -## Using Rustup To Specify a Specific Nightly - -To target a specific nightly, modify the above instructions as follows. It is recommended -to use the nightly specified in the `rust-version` file in this repo, since that is the -most recent nightly supported by Miri. - -1. Install Miri using `cargo +nightly-2018-10-15 install --all-features --path .`, -with the date replaced as appropriate. -2. Run `xargo/build.sh` as `rustup run nightly-2018-10-15 xargo/build.sh`. -3. When running tests, use `MIRI_SYSROOT=~/.xargo/HOST cargo +nightly-2018-10-15 miri test`. +which should be the toolchain specified in the `rust-version` file. ## Miri `-Z` flags From a34b9c7b70f52b10becbee7606c10afd13712f95 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 24 Oct 2018 11:39:31 +0200 Subject: [PATCH 0299/3747] make some things public for the benefit of priroda --- src/lib.rs | 6 +++++- src/stacked_borrows.rs | 22 +++++++++++++++++++--- 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 128b338f943dc..50b1305e52c83 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -44,8 +44,12 @@ use range_map::RangeMap; #[allow(unused_imports)] // FIXME rustc bug https://github.com/rust-lang/rust/issues/53682 use helpers::{ScalarExt, EvalContextExt as HelpersEvalContextExt}; use mono_hash_map::MonoHashMap; -use stacked_borrows::{EvalContextExt as StackedBorEvalContextExt, Borrow}; +use stacked_borrows::{EvalContextExt as StackedBorEvalContextExt}; +// Used by priroda +pub use stacked_borrows::{Borrow, Stacks, Mut as MutBorrow}; + +// Used by priroda pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( tcx: TyCtxt<'a, 'tcx, 'tcx>, main_id: DefId, diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index f634f17109c74..96ae2aa5c5769 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -21,12 +21,20 @@ pub enum Mut { impl Mut { #[inline(always)] - fn is_raw(self) -> bool { + pub fn is_raw(self) -> bool { match self { Mut::Raw => true, _ => false, } } + + #[inline(always)] + pub fn is_uniq(self) -> bool { + match self { + Mut::Uniq(_) => true, + _ => false, + } + } } /// Information about any kind of borrow @@ -40,9 +48,17 @@ pub enum Borrow { impl Borrow { #[inline(always)] - fn is_uniq(self) -> bool { + pub fn is_uniq(self) -> bool { + match self { + Borrow::Mut(m) => m.is_uniq(), + _ => false, + } + } + + #[inline(always)] + pub fn is_frz(self) -> bool { match self { - Borrow::Mut(Mut::Uniq(_)) => true, + Borrow::Frz(_) => true, _ => false, } } From 86aa8352c695a59db5822f267b6c64ccf601220d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 24 Oct 2018 15:29:48 +0200 Subject: [PATCH 0300/3747] Work on miri installation and usage instructions --- README.md | 39 ++++++++++++++++++++++++++------------- 1 file changed, 26 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 7597c9a0e11bd..c5ac817299940 100644 --- a/README.md +++ b/README.md @@ -7,15 +7,23 @@ undergraduate research course at the [University of Saskatchewan][usask]. ## Building Miri -I recommend that you install [rustup][rustup] to obtain Rust. Miri comes with a -`rust-version` file describing the latest supported nightly version of the Rust -compiler toolchain. Then all you have to do is: +I recommend that you install [rustup][rustup] to obtain Rust. Then all you have +to do is: ```sh cargo +nightly build ``` -with `+nightly` replaced with the appropriate nightly version of Rust. +This uses the very latest Rust version. If you experience any problem, refer to +the `rust-version` file which contains a particular Rust nightly version that +has been tested against the version of miri you are using. Make sure to use +that particular `nightly-YYYY-MM-DD` whenever the instructions just say +`nightly`. + +To avoid repeating the nightly version all the time, you can use +`rustup override set nightly` (or `rustup override set nightly-YYYY-MM-DD`), +which means `nightly` Rust will automatically be used whenever you are working +in this directory. ## Running Miri @@ -41,18 +49,23 @@ Now you can run Miri against the libstd compiled by xargo: MIRI_SYSROOT=~/.xargo/HOST cargo +nightly run tests/run-pass-fullmir/hashmap.rs ``` -Notice that you will have to re-run the last step of the preparations above when -your toolchain changes (e.g., when you update the nightly). - -You can also set `-Zmiri-start-fn` to make Miri start evaluation with the -`start_fn` lang item, instead of starting at the `main` function. +Notice that you will have to re-run the last step of the preparations above +(`xargo/build.sh`) when your toolchain changes (e.g., when you update the +nightly). ## Running Miri on your own project('s test suite) -Install Miri as a cargo subcommand with `cargo install +nightly --all-features --path .`. - -Compile your project and its dependencies against a MIR-enabled libstd as described -above: +Install Miri as a cargo subcommand with `cargo install +nightly --all-features +--path .`. Be aware that if you used `rustup override set` to fix a particular +Rust version for the miri directory, that will *not* apply to your own project +directory! You have to use a consistent Rust version for building miri and your +project for this to work, so remember to either always specify the nightly +version manually, overriding it in your project directory as well, or use +`rustup default nightly` (or `rustup default nightly-YYYY-MM-DD`) to globally +make `nightly` the default toolchain. + +We assume that you have prepared a MIR-enabled libstd as described above. Now +compile your project and its dependencies against that libstd: 1. Run `cargo clean` to eliminate any cached dependencies that were built against the non-MIR `libstd`. From 8f9ca242fad4b17a505d26b41e8168cc051d4fe9 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 24 Oct 2018 15:32:51 +0200 Subject: [PATCH 0301/3747] expand -Z flag docs --- README.md | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index c5ac817299940..0e88c8138a516 100644 --- a/README.md +++ b/README.md @@ -98,11 +98,17 @@ which should be the toolchain specified in the `rust-version` file. ## Miri `-Z` flags -Miri adds some extra `-Z` flags to control its behavior: - -* `-Zmiri-start-fn`: This makes interpretation start with `lang_start` (defined - in libstd) instead of starting with `main`. Requires full MIR! -* `-Zmiri-disable-validation` disables enforcing the validity invariant. +Several `-Z` flags are relevant for miri: + +* `-Zmir-opt-level` controls how many MIR optimizations are performed. miri + overrides the default to be `0`; be advised that using any higher level can + make miri miss bugs in your program because they got optimized away. +* `-Zalways-encode-mir` makes rustc dump MIR even for completely monomorphic + functions. This is needed so that miri can execute such functions, so miri + sets this flag per default. +* `-Zmiri-disable-validation` is a custom `-Z` flag added by miri. It disables + enforcing the validity invariant, which is enforced by default. This is + mostly useful for debugging; it means miri will miss bugs in your program. ## Development and Debugging From d890a70c39affeb9db3cfa9545905284a981114d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 25 Oct 2018 11:37:42 +0200 Subject: [PATCH 0302/3747] update for is_null removal --- src/fn_call.rs | 6 +++--- src/intrinsic.rs | 2 +- src/tls.rs | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index 0cbd891a34e4c..2d142ab20dc61 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -132,7 +132,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo "free" => { let ptr = self.read_scalar(args[0])?.not_undef()?.erase_tag(); // raw ptr operation, no tag - if !ptr.is_null() { + if !ptr.is_null_ptr(&self) { self.memory.deallocate( ptr.to_ptr()?.with_default_tag(), None, @@ -353,7 +353,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo let mut success = None; { let name_ptr = self.read_scalar(args[0])?.not_undef()?.erase_tag(); // raw ptr operation - if !name_ptr.is_null() { + if !name_ptr.is_null_ptr(&self) { let name = self.memory.read_c_str(name_ptr.to_ptr()?.with_default_tag())?; if !name.is_empty() && !name.contains(&b'=') { success = Some(self.machine.env_vars.remove(name)); @@ -376,7 +376,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo let name_ptr = self.read_scalar(args[0])?.not_undef()?.erase_tag(); // raw ptr operation let value_ptr = self.read_scalar(args[1])?.to_ptr()?.erase_tag(); // raw ptr operation let value = self.memory.read_c_str(value_ptr.with_default_tag())?; - if !name_ptr.is_null() { + if !name_ptr.is_null_ptr(&self) { let name = self.memory.read_c_str(name_ptr.to_ptr()?.with_default_tag())?; if !name.is_empty() && !name.contains(&b'=') { new = Some((name.to_owned(), value.to_owned())); diff --git a/src/intrinsic.rs b/src/intrinsic.rs index 5c86075883b0b..dceeaf89aa5d3 100644 --- a/src/intrinsic.rs +++ b/src/intrinsic.rs @@ -231,7 +231,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' let a = self.read_value(args[0])?; let b = self.read_value(args[1])?; // check x % y != 0 - if !self.binary_op_val(mir::BinOp::Rem, a, b)?.0.is_null() { + if self.binary_op_val(mir::BinOp::Rem, a, b)?.0.to_bytes()? != 0 { return err!(ValidationFailure(format!("exact_div: {:?} cannot be divided by {:?}", a, b))); } self.binop_ignore_overflow(mir::BinOp::Div, a, b, dest)?; diff --git a/src/tls.rs b/src/tls.rs index 2bddc43df8c4a..b315e27c45d0a 100644 --- a/src/tls.rs +++ b/src/tls.rs @@ -121,7 +121,7 @@ impl<'tcx> TlsData<'tcx> { for (&key, &mut TlsEntry { ref mut data, dtor }) in thread_local.range_mut((start, Unbounded)) { - if !data.is_null() { + if !data.is_null_ptr(cx) { if let Some(dtor) = dtor { let ret = Some((dtor, *data, key)); *data = Scalar::ptr_null(cx); From 4ccdcdcace3ccea08d27e24669b8b635d1722541 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 29 Oct 2018 09:09:03 +0100 Subject: [PATCH 0303/3747] rustup --- rust-version | 2 +- src/lib.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/rust-version b/rust-version index cc0787f877e6f..feed920a16685 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -nightly-2018-10-22 +nightly-2018-10-29 diff --git a/src/lib.rs b/src/lib.rs index ed23eef3f5500..a93a48cb09d4d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -181,7 +181,7 @@ pub fn eval_main<'a, 'tcx: 'a>( let e = e.to_string(); let msg = format!("constant evaluation error: {}", e); let mut err = struct_error(ecx.tcx.tcx.at(span), msg.as_str()); - let (frames, span) = ecx.generate_stacktrace(None); + let frames = ecx.generate_stacktrace(None); err.span_label(span, e); for FrameInfo { span, location, .. } in frames { err.span_note(span, &format!("inside call to `{}`", location)); From f7741bcfe0a6a751961a9c7a1ef01cfc439eb4eb Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 29 Oct 2018 09:15:58 +0100 Subject: [PATCH 0304/3747] bump compiletest --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index f79609c76394a..dcf93fa14104f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -45,5 +45,5 @@ cargo_miri = ["cargo_metadata"] rustc_tests = [] [dev-dependencies] -compiletest_rs = { version = "0.3.12", features = ["tmp"] } +compiletest_rs = { version = "0.3.16", features = ["tmp"] } colored = "1.6" From cba30e8e8b14067750a0aec279737bcadd90cfcd Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 29 Oct 2018 11:51:22 +0100 Subject: [PATCH 0305/3747] opt level 3 works again :) --- tests/compiletest.rs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/tests/compiletest.rs b/tests/compiletest.rs index 7a7d7e49b2db5..0e6fa3d2a1fc7 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -102,11 +102,7 @@ fn miri_pass(sysroot: &Path, path: &str, target: &str, host: &str, need_fullmir: flags.push(format!("--sysroot {}", sysroot.display())); flags.push("-Dwarnings -Dunused".to_owned()); // overwrite the -Aunused in compiletest-rs if opt { - // FIXME: Using level 1 (instead of 3) for now, as the optimizer is pretty broken - // and crashes... - // Level 0 and 1 are not the same, so this still gives us *some* coverage. - // See https://github.com/rust-lang/rust/issues/50411 - flags.push("-Zmir-opt-level=1".to_owned()); + flags.push("-Zmir-opt-level=3".to_owned()); } else { flags.push("-Zmir-opt-level=0".to_owned()); // For now, only validate without optimizations. Inlining breaks validation. From 942204ee321f57033c65ece3b667bf63c7c65ff0 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 30 Oct 2018 08:40:50 +0100 Subject: [PATCH 0306/3747] bump Rust version --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index feed920a16685..d025ddacf0092 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -nightly-2018-10-29 +nightly-2018-10-30 From a48b2cc4e940d63cadccb775401618015afbe0cc Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 30 Oct 2018 09:40:01 +0100 Subject: [PATCH 0307/3747] disable validation for some tests that need further investigation --- tests/run-pass-fullmir/send-is-not-static-par-for.rs | 3 +++ tests/run-pass-fullmir/u128.rs | 3 +++ tests/run-pass-fullmir/vecdeque.rs | 3 +++ 3 files changed, 9 insertions(+) diff --git a/tests/run-pass-fullmir/send-is-not-static-par-for.rs b/tests/run-pass-fullmir/send-is-not-static-par-for.rs index 1b913aed4c89e..282f7a3595032 100644 --- a/tests/run-pass-fullmir/send-is-not-static-par-for.rs +++ b/tests/run-pass-fullmir/send-is-not-static-par-for.rs @@ -8,6 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// FIXME: Still investigating whether there is UB here +// compile-flags: -Zmiri-disable-validation + use std::sync::Mutex; fn par_for(iter: I, f: F) diff --git a/tests/run-pass-fullmir/u128.rs b/tests/run-pass-fullmir/u128.rs index ca33bd5f9e3d8..0f1b6e8b58708 100644 --- a/tests/run-pass-fullmir/u128.rs +++ b/tests/run-pass-fullmir/u128.rs @@ -8,6 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +// FIXME: Still investigating whether there is UB here +// compile-flags: -Zmiri-disable-validation + fn b(t: T) -> T { t } fn main() { diff --git a/tests/run-pass-fullmir/vecdeque.rs b/tests/run-pass-fullmir/vecdeque.rs index 381169505ec9f..ffbb116684985 100644 --- a/tests/run-pass-fullmir/vecdeque.rs +++ b/tests/run-pass-fullmir/vecdeque.rs @@ -1,3 +1,6 @@ +// FIXME: Still investigating whether there is UB here +// compile-flags: -Zmiri-disable-validation + use std::collections::VecDeque; fn main() { From 9c9552260c03f72f1de840de092775fd03ed05b5 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 30 Oct 2018 10:14:09 +0100 Subject: [PATCH 0308/3747] test cargo-miri without validation, and fix how we invoke it so we see output in case of failure --- .travis.yml | 34 +++++++++++++++++++--------------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/.travis.yml b/.travis.yml index 095af11627fac..dd7bcd49200b0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -36,30 +36,34 @@ script: - | # Test and install plain miri cargo build --release --all-features && - cargo test --release --all-features && + #cargo test --release --all-features && cargo install --all-features --force --path . - | # get ourselves a MIR-full libstd xargo/build.sh && export MIRI_SYSROOT=~/.xargo/HOST +#- | +# # run all tests with full mir +# cargo test --release --all-features - | - # run all tests with full mir - cargo test --release --all-features -- | - # test `cargo miri` + # Test cargo integration cd cargo-miri-test && - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then - cargo miri -q - else - cargo miri -q >stdout.real 2>stderr.real && - cat stdout.real stderr.real && - # Test `cargo miri` output. Not on mac because output redirecting doesn't - # work. There is no error. It just stops CI. + # Test `cargo miri` + # We ignore the exit code because we want to see the output even on failure, and + # I found no way to preserve the exit code so that we can test for it later. + # Variables set in this subshell in the parenthesis are not available + # on the outside. + # We assume that if this fails, it'll also print something about the failure on + # stdout/stderr and we'll catch that. + # FIXME: Disabling validation, still investigating whether there is UB here + (cargo miri -q >stdout.real 2>stderr.real -- -Zmiri-disable-validation || true) && + # Print file names and contents (`cat` would just print contents) + tail -n +0 stdout.real stderr.real && + # Verify output diff -u stdout.ref stdout.real && - diff -u stderr.ref stderr.real - fi && + diff -u stderr.ref stderr.real && # test `cargo miri test` - cargo miri test && + cargo miri test && cd .. notifications: From 1fa0ff88c03284421d99662909a4c24a8651d47d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 30 Oct 2018 10:41:01 +0100 Subject: [PATCH 0309/3747] fix nits --- src/fn_call.rs | 18 ++++++++++++------ src/stacked_borrows.rs | 12 ++++++------ .../stacked_borrows/illegal_write4.rs | 8 ++++---- 3 files changed, 22 insertions(+), 16 deletions(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index a65329a1e7bb2..9e3f49ac9fd32 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -150,10 +150,14 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo if !align.is_power_of_two() { return err!(HeapAllocNonPowerOfTwoAlignment(align)); } - let ptr = self.memory_mut().allocate(Size::from_bytes(size), - Align::from_bytes(align, align).unwrap(), - MiriMemoryKind::Rust.into())?; - self.write_scalar(Scalar::Ptr(ptr.with_default_tag()), dest)?; + let ptr = self.memory_mut() + .allocate( + Size::from_bytes(size), + Align::from_bytes(align, align).unwrap(), + MiriMemoryKind::Rust.into() + )? + .with_default_tag(); + self.write_scalar(Scalar::Ptr(ptr), dest)?; } "__rust_alloc_zeroed" => { let size = self.read_scalar(args[0])?.to_usize(&self)?; @@ -164,11 +168,13 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo if !align.is_power_of_two() { return err!(HeapAllocNonPowerOfTwoAlignment(align)); } - let ptr = self.memory_mut().allocate( + let ptr = self.memory_mut() + .allocate( Size::from_bytes(size), Align::from_bytes(align, align).unwrap(), MiriMemoryKind::Rust.into() - )?.with_default_tag(); + )? + .with_default_tag(); self.memory_mut().write_repeat(ptr.into(), 0, Size::from_bytes(size))?; self.write_scalar(Scalar::Ptr(ptr), dest)?; } diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 96ae2aa5c5769..a569ed4e55513 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -251,7 +251,7 @@ impl<'tcx> Stack { impl State { fn increment_clock(&self) -> Timestamp { let val = self.clock.get(); - self.clock.set(val+1); + self.clock.set(val + 1); val } } @@ -322,13 +322,13 @@ impl<'tcx> Stacks { /// Pushes the first borrow to the stacks, must be a mutable one. pub fn first_borrow( &mut self, - r#mut: Mut, + mut_borrow: Mut, size: Size ) { for stack in self.stacks.get_mut().iter_mut(Size::ZERO, size) { assert!(stack.borrows.len() == 1 && stack.frozen_since.is_none()); assert_eq!(stack.borrows.pop().unwrap(), BorStackItem::Mut(Mut::Raw)); - stack.borrows.push(BorStackItem::Mut(r#mut)); + stack.borrows.push(BorStackItem::Mut(mut_borrow)); } } } @@ -489,7 +489,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' id: AllocId, kind: MemoryKind, ) -> Borrow { - let r#mut = match kind { + let mut_borrow = match kind { MemoryKind::Stack => { // New unique borrow let time = self.machine.stacked_borrows.increment_clock(); @@ -503,7 +503,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' // Make this the active borrow for this allocation let alloc = self.memory_mut().get_mut(id).expect("This is a new allocation, it must still exist"); let size = Size::from_bytes(alloc.bytes.len() as u64); - alloc.extra.first_borrow(r#mut, size); - Borrow::Mut(r#mut) + alloc.extra.first_borrow(mut_borrow, size); + Borrow::Mut(mut_borrow) } } diff --git a/tests/compile-fail/stacked_borrows/illegal_write4.rs b/tests/compile-fail/stacked_borrows/illegal_write4.rs index 2006d7262f813..094a38951974b 100644 --- a/tests/compile-fail/stacked_borrows/illegal_write4.rs +++ b/tests/compile-fail/stacked_borrows/illegal_write4.rs @@ -11,8 +11,8 @@ fn main() { let target = 42; // Make sure a cannot use a raw-tagged `&mut` pointing to a frozen location, not // even to create a raw. - let r#ref = ⌖ // freeze - let ptr = r#ref as *const _ as *mut i32; // raw ptr, with raw tag + let reference = ⌖ // freeze + let ptr = reference as *const _ as *mut i32; // raw ptr, with raw tag let mut_ref: &mut i32 = unsafe { mem::transmute(ptr) }; // &mut, with raw tag // Now we have an &mut to a frozen location, but that is completely normal: // We'd just unfreeze the location if we used it. @@ -23,9 +23,9 @@ fn main() { // turns a raw into a `&mut`. Next, we create a raw ref to a frozen location // from a `Raw` tag, which can happen legitimately when interior mutability // is involved. - let _val = *r#ref; // Make sure it is still frozen. + let _val = *reference; // Make sure it is still frozen. // We only actually unfreeze once we muteate through the bad pointer. unsafe { *bad_ptr = 42 }; //~ ERROR does not exist on the stack - let _val = *r#ref; + let _val = *reference; } From f6b1f9e48756c35f2d23baedb1a111aec33bc7d2 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 30 Oct 2018 11:26:53 +0100 Subject: [PATCH 0310/3747] rewrite cargo-miri test in Python --- .travis.yml | 27 +++++------------------ cargo-miri-test/run-test.py | 43 +++++++++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+), 22 deletions(-) create mode 100755 cargo-miri-test/run-test.py diff --git a/.travis.yml b/.travis.yml index dd7bcd49200b0..d845eb0ec9f31 100644 --- a/.travis.yml +++ b/.travis.yml @@ -36,35 +36,18 @@ script: - | # Test and install plain miri cargo build --release --all-features && - #cargo test --release --all-features && + cargo test --release --all-features && cargo install --all-features --force --path . - | # get ourselves a MIR-full libstd xargo/build.sh && export MIRI_SYSROOT=~/.xargo/HOST -#- | -# # run all tests with full mir -# cargo test --release --all-features +- | + # run all tests with full mir + cargo test --release --all-features - | # Test cargo integration - cd cargo-miri-test && - # Test `cargo miri` - # We ignore the exit code because we want to see the output even on failure, and - # I found no way to preserve the exit code so that we can test for it later. - # Variables set in this subshell in the parenthesis are not available - # on the outside. - # We assume that if this fails, it'll also print something about the failure on - # stdout/stderr and we'll catch that. - # FIXME: Disabling validation, still investigating whether there is UB here - (cargo miri -q >stdout.real 2>stderr.real -- -Zmiri-disable-validation || true) && - # Print file names and contents (`cat` would just print contents) - tail -n +0 stdout.real stderr.real && - # Verify output - diff -u stdout.ref stdout.real && - diff -u stderr.ref stderr.real && - # test `cargo miri test` - cargo miri test && - cd .. + (cd cargo-miri-test && ./run-test.py) notifications: email: diff --git a/cargo-miri-test/run-test.py b/cargo-miri-test/run-test.py new file mode 100755 index 0000000000000..90f0a8ac6c883 --- /dev/null +++ b/cargo-miri-test/run-test.py @@ -0,0 +1,43 @@ +#!/usr/bin/python3 +''' +Test whether cargo-miri works properly. +Assumes the `MIRI_SYSROOT` env var to be set appropriately, +and the working directory to contain the cargo-miri-test project. +''' + +import sys, subprocess + +def test_cargo_miri(): + print("==> Testing `cargo miri` <==") + ## Call `cargo miri`, capture all output + # FIXME: Disabling validation, still investigating whether there is UB here + p = subprocess.Popen( + ["cargo", "miri", "-q", "--", "-Zmiri-disable-validation"], + stdout=subprocess.PIPE, + stderr=subprocess.PIPE + ) + (stdout, stderr) = p.communicate() + stdout = stdout.decode("UTF-8") + stderr = stderr.decode("UTF-8") + # Show output + print("=> captured stdout <=") + print(stdout, end="") + print("=> captured stderr <=") + print(stderr, end="") + # Test for failures + if p.returncode != 0: + sys.exit(1) + if stdout != open('stdout.ref').read(): + print("stdout does not match reference") + sys.exit(1) + if stderr != open('stderr.ref').read(): + print("stderr does not match reference") + sys.exit(1) + +def test_cargo_miri_test(): + print("==> Testing `cargo miri test` <==") + subprocess.check_call(["cargo", "miri", "test"]) + +test_cargo_miri() +test_cargo_miri_test() +sys.exit(0) From 8fe51ca669bd257795759816bfb29e986ca3217e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 30 Oct 2018 15:07:40 +0100 Subject: [PATCH 0311/3747] try to find python3 on macOS --- .travis.yml | 4 ++-- cargo-miri-test/run-test.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index d845eb0ec9f31..f989c7705b19a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,8 +11,8 @@ os: - osx before_script: -# mac os weirdness (https://github.com/travis-ci/travis-ci/issues/6307) -- rvm get stable +# macOS weirdness (https://github.com/travis-ci/travis-ci/issues/6307) +- if [[ "$TRAVIS_OS_NAME" == osx ]]; then rvm get stable; fi # Compute the rust version we use. We do not use "language: rust" to have more control here. - | if [ "$TRAVIS_EVENT_TYPE" = cron ]; then diff --git a/cargo-miri-test/run-test.py b/cargo-miri-test/run-test.py index 90f0a8ac6c883..506de85ffcb2c 100755 --- a/cargo-miri-test/run-test.py +++ b/cargo-miri-test/run-test.py @@ -1,4 +1,4 @@ -#!/usr/bin/python3 +#!/usr/bin/env python3 ''' Test whether cargo-miri works properly. Assumes the `MIRI_SYSROOT` env var to be set appropriately, From eb153810e35748d2b4556d39dd6778d35ceb1a9e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 31 Oct 2018 10:09:55 +0100 Subject: [PATCH 0312/3747] Use MIRI_ env vars to set RUST_ ones This means we can do `MIRI_LOG=debug cargo run` and get something reasonable, even if cargo has to build some dependencies first. --- src/bin/miri.rs | 64 +++++++++++++++++++++---------------------------- src/lib.rs | 15 +++++++++++- 2 files changed, 41 insertions(+), 38 deletions(-) diff --git a/src/bin/miri.rs b/src/bin/miri.rs index d4494a8388527..c8103c2a1176b 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -12,6 +12,9 @@ extern crate log_settings; extern crate syntax; extern crate log; +use std::path::PathBuf; +use std::env; + use rustc::session::Session; use rustc_metadata::cstore::CStore; use rustc_driver::{Compilation, CompilerCalls, RustcDefaultCalls}; @@ -21,7 +24,6 @@ use rustc::hir::{self, itemlikevisit}; use rustc::ty::TyCtxt; use rustc_codegen_utils::codegen_backend::CodegenBackend; use syntax::ast; -use std::path::PathBuf; struct MiriCompilerCalls { default: Box, @@ -148,42 +150,31 @@ fn after_analysis<'a, 'tcx>( } } -fn init_logger() { - let format = |formatter: &mut env_logger::fmt::Formatter, record: &log::Record| { - use std::io::Write; - if record.level() == log::Level::Trace { - // prepend frame number - let indentation = log_settings::settings().indentation; - writeln!( - formatter, - "{indentation}:{lvl}:{module}: {text}", - lvl = record.level(), - module = record.module_path().unwrap_or(""), - indentation = indentation, - text = record.args(), - ) - } else { - writeln!( - formatter, - "{lvl}:{module}: {text}", - lvl = record.level(), - module = record.module_path().unwrap_or(""), - text = record.args(), - ) +fn init_loggers() { + // Notice that our `extern crate log` is NOT the same as rustc's! So we have to initialize + // them both. + // First, miri. + let env = env_logger::Env::new().filter("MIRI_LOG").write_style("MIRI_LOG_STYLE"); + env_logger::init_from_env(env); + // Now, change the RUST_LOG env var to control rustc's logger. + // If MIRI_LOG is set and RUST_LOG is not, set RUST_LOG. + if let Ok(var) = env::var("MIRI_LOG") { + if env::var("RUST_LOG") == Err(env::VarError::NotPresent) { + // We try to be a bit clever here: If MIRI_LOG is just a single level + // used for everything, we only apply it to the parts of rustc that are + // CTFE-related. Only if MIRI_LOG contains `module=level`, we just + // use the same value for RUST_LOG. + // This way, if you set `MIRI_LOG=trace`, you get only the right parts of + // rustc traced, but you can also do `MIRI_LOG=miri=trace,rustc_mir::interpret=debug`. + if var.contains('=') { + env::set_var("RUST_LOG", &var); + } else { + env::set_var("RUST_LOG", + &format!("rustc::mir::interpret={0},rustc_mir::interpret={0}", var)); + } } - }; - - let mut builder = env_logger::Builder::new(); - builder.format(format).filter( - None, - log::LevelFilter::Info, - ); - - if std::env::var("MIRI_LOG").is_ok() { - builder.parse(&std::env::var("MIRI_LOG").unwrap()); } - - builder.init(); + rustc_driver::init_rustc_env_logger(); } fn find_sysroot() -> String { @@ -208,8 +199,7 @@ fn find_sysroot() -> String { } fn main() { - rustc_driver::init_rustc_env_logger(); - init_logger(); + init_loggers(); let mut args: Vec = std::env::args().collect(); let sysroot_flag = String::from("--sysroot"); diff --git a/src/lib.rs b/src/lib.rs index 9f4eb00877e4b..fa60a0da00d5a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -11,10 +11,12 @@ extern crate rustc; extern crate rustc_data_structures; extern crate rustc_mir; extern crate rustc_target; +extern crate rustc_driver; extern crate syntax; use std::collections::HashMap; use std::borrow::Cow; +use std::env; use rustc::ty::{self, Ty, TyCtxt, query::TyCtxtAt}; use rustc::ty::layout::{TyLayout, LayoutOf, Size}; @@ -157,11 +159,21 @@ pub fn eval_main<'a, 'tcx: 'a>( ) { let mut ecx = create_ecx(tcx, main_id, validate).expect("Couldn't create ecx"); + // If MIRI_BACKTRACE is set and RUST_CTFE_BACKTRACE is not, set RUST_CTFE_BACKTRACE. + // Do this late, so we really only apply this to miri's errors. + if let Ok(var) = env::var("MIRI_BACKTRACE") { + if env::var("RUST_CTFE_BACKTRACE") == Err(env::VarError::NotPresent) { + env::set_var("RUST_CTFE_BACKTRACE", &var); + } + } + + // Run! The main execution. let res: EvalResult = (|| { ecx.run()?; ecx.run_tls_dtors() })(); + // Process the result. match res { Ok(()) => { let leaks = ecx.memory().leak_report(); @@ -173,7 +185,8 @@ pub fn eval_main<'a, 'tcx: 'a>( tcx.sess.err("the evaluated program leaked memory"); } } - Err(e) => { + Err(mut e) => { + e.print_backtrace(); if let Some(frame) = ecx.stack().last() { let block = &frame.mir.basic_blocks()[frame.block]; let span = if frame.stmt < block.statements.len() { From cd256448d5483bb8ad6200aada68639a14ae9543 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 31 Oct 2018 10:16:42 +0100 Subject: [PATCH 0313/3747] dumping locals with MIRI_BACKTRACE=1 is feasible now --- src/lib.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index fa60a0da00d5a..ee265f8b0a89e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -208,7 +208,6 @@ pub fn eval_main<'a, 'tcx: 'a>( ecx.tcx.sess.err(&e.to_string()); } - /* Nice try, but with MIRI_BACKTRACE this shows 100s of backtraces. for (i, frame) in ecx.stack().iter().enumerate() { trace!("-------------------"); trace!("Frame {}", i); @@ -218,7 +217,7 @@ pub fn eval_main<'a, 'tcx: 'a>( trace!(" local {}: {:?}", i, local); } } - }*/ + } } } } From 8f811fe12f20e6f969490d2db9e05319d6856721 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 31 Oct 2018 10:16:50 +0100 Subject: [PATCH 0314/3747] update README --- README.md | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 0e88c8138a516..a905c2aeffb72 100644 --- a/README.md +++ b/README.md @@ -114,7 +114,7 @@ Several `-Z` flags are relevant for miri: Since the heart of Miri (the main interpreter engine) lives in rustc, working on Miri will often require using a locally built rustc. This includes getting a -trace of the execution, as distributed rustc has `trace!` disabled. +trace of the execution, as distributed rustc has `debug!` and `trace!` disabled. The first-time setup for a local rustc looks as follows: ``` @@ -130,14 +130,28 @@ rustup override set custom ``` The `build` step can take 30 minutes and more. -Now you can `cargo build` Miri, and you can `cargo test --tests`. (`--tests` -is needed to skip doctests because we have not built rustdoc for your custom -toolchain.) You can also set `RUST_LOG=rustc_mir::interpret=trace` as -environment variable to get a step-by-step trace. +Now you can `cargo build` Miri, and you can `cargo test` it. But the key point +is, you can now run Miri with a trace of all execution steps: + +```sh +MIRI_LOG=debug cargo run tests/run-pass/vecs.rs +``` + +Setting `MIRI_LOG` like this will configure logging for miri itself as well as +the `rustc::mir::interpret` and `rustc_mir::interpret` modules in rustc. You +can also do more targeted configuration, e.g. to debug the stacked borrows +implementation: + +```sh +MIRI_LOG=miri::stacked_borrows=trace,rustc_mir::interpret=debug cargo run tests/run-pass/vecs.rs +``` + +In addition, you can set `MIRI_BACKTRACE=1` to get a backtrace of where an +evaluation error was originally created. If you changed something in rustc and want to re-build, run ``` -./x.py build src/rustc --keep-stage 0 +./x.py --keep-stage 0 build src/rustc ``` This avoids rebuilding the entire stage 0, which can save a lot of time. From 7a6a68731e670aeda7cdabc1478e3fd1c34472b0 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 31 Oct 2018 10:19:20 +0100 Subject: [PATCH 0315/3747] remove unused extern crate --- src/lib.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index ee265f8b0a89e..650998c3e16c8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -6,13 +6,12 @@ extern crate log; // From rustc. +extern crate syntax; #[macro_use] extern crate rustc; extern crate rustc_data_structures; extern crate rustc_mir; extern crate rustc_target; -extern crate rustc_driver; -extern crate syntax; use std::collections::HashMap; use std::borrow::Cow; From 5397f2e43647d1a78c3a4637cdcb398120b603f6 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 31 Oct 2018 10:53:37 +0100 Subject: [PATCH 0316/3747] when using MIRI_LOG, avoid logging for what rustc does before miri gets started --- src/bin/miri.rs | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/src/bin/miri.rs b/src/bin/miri.rs index c8103c2a1176b..6d0f0b5f6a230 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -107,6 +107,7 @@ fn after_analysis<'a, 'tcx>( state: &mut CompileState<'a, 'tcx>, validate: bool, ) { + init_late_loggers(); state.session.abort_if_errors(); let tcx = state.tcx.unwrap(); @@ -150,16 +151,25 @@ fn after_analysis<'a, 'tcx>( } } -fn init_loggers() { +fn init_early_loggers() { // Notice that our `extern crate log` is NOT the same as rustc's! So we have to initialize - // them both. - // First, miri. + // them both. We always initialize miri early. let env = env_logger::Env::new().filter("MIRI_LOG").write_style("MIRI_LOG_STYLE"); env_logger::init_from_env(env); - // Now, change the RUST_LOG env var to control rustc's logger. - // If MIRI_LOG is set and RUST_LOG is not, set RUST_LOG. + // We only initialize rustc if the env var is set (so the user asked for it). + // If it is not set, we avoid initializing now so that we can initialize + // later with our custom settings, and NOT log anything for what happens before + // miri gets started. + if env::var("RUST_LOG").is_ok() { + rustc_driver::init_rustc_env_logger(); + } +} + +fn init_late_loggers() { + // Initializing loggers right before we start evaluation. We overwrite the RUST_LOG + // env var if it is not set, control it based on MIRI_LOG. if let Ok(var) = env::var("MIRI_LOG") { - if env::var("RUST_LOG") == Err(env::VarError::NotPresent) { + if env::var("RUST_LOG").is_err() { // We try to be a bit clever here: If MIRI_LOG is just a single level // used for everything, we only apply it to the parts of rustc that are // CTFE-related. Only if MIRI_LOG contains `module=level`, we just @@ -172,9 +182,9 @@ fn init_loggers() { env::set_var("RUST_LOG", &format!("rustc::mir::interpret={0},rustc_mir::interpret={0}", var)); } + rustc_driver::init_rustc_env_logger(); } } - rustc_driver::init_rustc_env_logger(); } fn find_sysroot() -> String { @@ -199,7 +209,7 @@ fn find_sysroot() -> String { } fn main() { - init_loggers(); + init_early_loggers(); let mut args: Vec = std::env::args().collect(); let sysroot_flag = String::from("--sysroot"); From 016009a3016dde768806a352aaa5da9c852d9dc5 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 31 Oct 2018 10:58:19 +0100 Subject: [PATCH 0317/3747] properly recognize log levels --- src/bin/miri.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 6d0f0b5f6a230..bacea04c97686 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -13,6 +13,7 @@ extern crate syntax; extern crate log; use std::path::PathBuf; +use std::str::FromStr; use std::env; use rustc::session::Session; @@ -172,15 +173,14 @@ fn init_late_loggers() { if env::var("RUST_LOG").is_err() { // We try to be a bit clever here: If MIRI_LOG is just a single level // used for everything, we only apply it to the parts of rustc that are - // CTFE-related. Only if MIRI_LOG contains `module=level`, we just - // use the same value for RUST_LOG. + // CTFE-related. Otherwise, we use it verbatim for RUST_LOG. // This way, if you set `MIRI_LOG=trace`, you get only the right parts of // rustc traced, but you can also do `MIRI_LOG=miri=trace,rustc_mir::interpret=debug`. - if var.contains('=') { - env::set_var("RUST_LOG", &var); - } else { + if log::Level::from_str(&var).is_ok() { env::set_var("RUST_LOG", &format!("rustc::mir::interpret={0},rustc_mir::interpret={0}", var)); + } else { + env::set_var("RUST_LOG", &var); } rustc_driver::init_rustc_env_logger(); } From 40b75026136eea8b7b1d4d93f7972be852d636f6 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 31 Oct 2018 11:04:35 +0100 Subject: [PATCH 0318/3747] Reject atomic arithmetic on non-integer types Fixes #181 --- src/intrinsic.rs | 3 +++ tests/compile-fail/atomic_non_integer_arithmetic.rs | 9 +++++++++ 2 files changed, 12 insertions(+) create mode 100644 tests/compile-fail/atomic_non_integer_arithmetic.rs diff --git a/src/intrinsic.rs b/src/intrinsic.rs index ee8df3e25ec13..852c93f650dfb 100644 --- a/src/intrinsic.rs +++ b/src/intrinsic.rs @@ -126,6 +126,9 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' "atomic_xsub_acqrel" | "atomic_xsub_relaxed" => { let ptr = self.ref_to_mplace(self.read_value(args[0])?)?; + if !ptr.layout.ty.is_integral() { + return err!(Unimplemented(format!("Atomic arithmetic operations only work on integer types"))); + } let rhs = self.read_value(args[1])?; let old = self.read_value(ptr.into())?; self.write_value(*old, dest)?; // old value is returned diff --git a/tests/compile-fail/atomic_non_integer_arithmetic.rs b/tests/compile-fail/atomic_non_integer_arithmetic.rs new file mode 100644 index 0000000000000..8c2ed98b7dfab --- /dev/null +++ b/tests/compile-fail/atomic_non_integer_arithmetic.rs @@ -0,0 +1,9 @@ +#![feature(core_intrinsics)] + +pub fn main() { + let mut z: f64 = 1.0; + unsafe { + ::std::intrinsics::atomic_xadd(&mut z, 2.0); + //~^ ERROR: Atomic arithmetic operations only work on integer types + } +} From 27b1f47b0a947f8867d3d0840ea40c5902b7191c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 1 Nov 2018 08:56:41 +0100 Subject: [PATCH 0319/3747] use crate:: where appropriate --- src/fn_call.rs | 2 +- src/helpers.rs | 2 +- src/intrinsic.rs | 2 +- src/lib.rs | 16 ++++++++-------- src/mono_hash_map.rs | 2 +- src/operator.rs | 2 +- src/tls.rs | 2 +- 7 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index 9e3f49ac9fd32..7e1ff3233f21e 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -4,7 +4,7 @@ use rustc::hir::def_id::DefId; use rustc::mir; use syntax::attr; -use super::*; +use crate::*; pub trait EvalContextExt<'tcx, 'mir> { /// Emulate calling a foreign item, fail if the item is not supported. diff --git a/src/helpers.rs b/src/helpers.rs index c4aad2033e570..6dc5b768ea63f 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -3,7 +3,7 @@ use std::mem; use rustc::ty; use rustc::hir::def_id::{DefId, CRATE_DEF_INDEX}; -use super::*; +use crate::*; pub trait ScalarExt { /// HACK: this function just extracts all bits if `defined != 0` diff --git a/src/intrinsic.rs b/src/intrinsic.rs index 852c93f650dfb..caf5687b231cb 100644 --- a/src/intrinsic.rs +++ b/src/intrinsic.rs @@ -4,7 +4,7 @@ use rustc::ty; use rustc::mir::interpret::{EvalResult, PointerArithmetic}; -use super::{ +use crate::{ PlaceTy, OpTy, Value, Scalar, ScalarMaybeUndef, Borrow, ScalarExt, OperatorEvalContextExt }; diff --git a/src/lib.rs b/src/lib.rs index 650998c3e16c8..cb544e9bb386b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -37,15 +37,15 @@ mod range_map; mod mono_hash_map; mod stacked_borrows; -use fn_call::EvalContextExt as MissingFnsEvalContextExt; -use operator::EvalContextExt as OperatorEvalContextExt; -use intrinsic::EvalContextExt as IntrinsicEvalContextExt; -use tls::{EvalContextExt as TlsEvalContextExt, TlsData}; -use range_map::RangeMap; +use crate::fn_call::EvalContextExt as MissingFnsEvalContextExt; +use crate::operator::EvalContextExt as OperatorEvalContextExt; +use crate::intrinsic::EvalContextExt as IntrinsicEvalContextExt; +use crate::tls::{EvalContextExt as TlsEvalContextExt, TlsData}; +use crate::range_map::RangeMap; #[allow(unused_imports)] // FIXME rustc bug https://github.com/rust-lang/rust/issues/53682 -use helpers::{ScalarExt, EvalContextExt as HelpersEvalContextExt}; -use mono_hash_map::MonoHashMap; -use stacked_borrows::{EvalContextExt as StackedBorEvalContextExt}; +use crate::helpers::{ScalarExt, EvalContextExt as HelpersEvalContextExt}; +use crate::mono_hash_map::MonoHashMap; +use crate::stacked_borrows::{EvalContextExt as StackedBorEvalContextExt}; // Used by priroda pub use stacked_borrows::{Borrow, Stacks, Mut as MutBorrow}; diff --git a/src/mono_hash_map.rs b/src/mono_hash_map.rs index 76ca7ac6a133a..e30578a5a77b9 100644 --- a/src/mono_hash_map.rs +++ b/src/mono_hash_map.rs @@ -12,7 +12,7 @@ use std::borrow::Borrow; use rustc_data_structures::fx::FxHashMap; -use super::AllocMap; +use crate::AllocMap; #[derive(Debug, Clone)] pub struct MonoHashMap(RefCell>>); diff --git a/src/operator.rs b/src/operator.rs index 0eac5c11276a7..e5c695009cfae 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -1,7 +1,7 @@ use rustc::ty::{Ty, layout::TyLayout}; use rustc::mir; -use super::*; +use crate::*; pub trait EvalContextExt<'tcx> { fn ptr_op( diff --git a/src/tls.rs b/src/tls.rs index b315e27c45d0a..001da10ddc216 100644 --- a/src/tls.rs +++ b/src/tls.rs @@ -3,7 +3,7 @@ use std::collections::BTreeMap; use rustc_target::abi::LayoutOf; use rustc::{ty, ty::layout::HasDataLayout, mir}; -use super::{ +use crate::{ EvalResult, EvalErrorKind, StackPopCleanup, MPlaceTy, Scalar, Borrow, }; From fba55ba2a9f9d906dc584e2c8dc6a97a8c137b92 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 24 Oct 2018 17:16:41 +0200 Subject: [PATCH 0320/3747] make the -Z flags we use more consistent --- appveyor.yml | 9 +++++---- src/bin/cargo-miri.rs | 2 +- src/bin/miri-rustc-tests.rs | 4 +--- src/bin/miri.rs | 18 ++++++++++++------ src/lib.rs | 14 ++++++++++++++ xargo/build.sh | 3 ++- 6 files changed, 35 insertions(+), 15 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index cf578120c9ddf..1e9ccbdf95000 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -14,19 +14,20 @@ branches: - master install: - # install Rust + # Install Rust. - set PATH=C:\Program Files\Git\mingw64\bin;C:\msys64\mingw%MSYS2_BITS%\bin;%PATH% - set /p RUST_TOOLCHAIN= = std::env::args().collect(); - let sysroot_flag = String::from("--sysroot"); - if !args.contains(&sysroot_flag) { - args.push(sysroot_flag); - args.push(find_sysroot()); - } - + // Parse our own -Z flags and remove them before rustc gets their hand on them. let mut validate = true; args.retain(|arg| { match arg.as_str() { @@ -229,7 +226,16 @@ fn main() { } }); + // Determine sysroot and let rustc know about it + let sysroot_flag = String::from("--sysroot"); + if !args.contains(&sysroot_flag) { + args.push(sysroot_flag); + args.push(find_sysroot()); + } + // Finally, add the default flags all the way in the beginning. + miri::add_miri_default_args(&mut args); + trace!("rustc arguments: {:?}", args); let result = rustc_driver::run(move || { rustc_driver::run_compiler(&args, Box::new(MiriCompilerCalls { default: Box::new(RustcDefaultCalls), diff --git a/src/lib.rs b/src/lib.rs index 650998c3e16c8..2de6665186bf7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -50,6 +50,20 @@ use stacked_borrows::{EvalContextExt as StackedBorEvalContextExt}; // Used by priroda pub use stacked_borrows::{Borrow, Stacks, Mut as MutBorrow}; +/// Insert rustc arguments at the beginning of the argument listthat miri wants to be +/// set per default, for maximal validation power. +pub fn add_miri_default_args(args: &mut Vec) { + // The flags here should be kept in sync with what bootstrap adds when `test-miri` is + // set, which happens in `bootstrap/bin/rustc.rs` in the rustc sources; and also + // kept in sync with `xargo/build.sh` in this repo and `appveyor.yml`. + + // Inserting at index 1, after the binary name + args.splice(1..1, + ["-Zalways-encode-mir", "-Zmir-emit-retag", "-Zmir-opt-level=0"] + .iter().map(|s| s.to_string()) + ); +} + // Used by priroda pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( tcx: TyCtxt<'a, 'tcx, 'tcx>, diff --git a/xargo/build.sh b/xargo/build.sh index 15a7c770910dd..25c56d31ab56a 100755 --- a/xargo/build.sh +++ b/xargo/build.sh @@ -1,3 +1,4 @@ #!/bin/sh cd "$(dirname "$0")" -RUSTFLAGS='-Zalways-encode-mir -Zmir-emit-validate=1' xargo build +# The flags here should be kept in sync with `add_miri_default_args` in `src/lib.rs`. +RUSTFLAGS='-Zalways-encode-mir -Zmir-emit-retag -Zmir-opt-level=0' xargo build From 7ac0e79ad5bcd8d7e4f8317c15238d5911faf11c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 24 Oct 2018 17:17:44 +0200 Subject: [PATCH 0321/3747] stub Retag hook; fix tests for removal of -Zmir-emit-validate --- src/lib.rs | 16 +++++++++++++++- src/stacked_borrows.rs | 17 ++++++++++++++++- tests/compile-fail-fullmir/stack_free.rs | 2 +- tests/compile-fail/cast_box_int_to_fn_ptr.rs | 2 +- tests/compile-fail/cast_int_to_fn_ptr.rs | 2 +- tests/compile-fail/execute_memory.rs | 2 +- tests/compile-fail/fn_ptr_offset.rs | 2 +- .../{invalid_bool2.rs => invalid_bool.rs} | 2 +- .../{invalid_char2.rs => invalid_char.rs} | 2 +- ...iminant2.rs => invalid_enum_discriminant.rs} | 2 +- tests/compile-fail/never_say_never.rs | 2 +- tests/compile-fail/never_transmute_humans.rs | 2 +- tests/compile-fail/never_transmute_void.rs | 2 +- tests/compile-fail/panic.rs | 2 -- tests/compile-fail/reference_to_packed.rs | 2 +- .../static_memory_modification.rs | 8 ++++++++ .../compile-fail/static_memory_modification.rs | 2 +- .../compile-fail/static_memory_modification2.rs | 2 +- .../compile-fail/static_memory_modification3.rs | 2 +- tests/compile-fail/storage_dead_dangling.rs | 2 +- tests/compile-fail/transmute_fat.rs | 2 +- tests/compile-fail/unaligned_ptr_cast.rs | 2 +- tests/compile-fail/unaligned_ptr_cast2.rs | 2 +- tests/compile-fail/undefined_byte_read.rs | 3 --- tests/compile-fail/validity/execute_memory.rs | 8 ++++++++ tests/compile-fail/validity/fn_ptr_offset.rs | 10 ++++++++++ tests/compiletest.rs | 7 +------ tests/run-pass/move-undef-primval.rs | 3 --- tests/run-pass/packed_struct.rs | 1 - tests/run-pass/recursive_static.rs | 3 --- tests/run-pass/regions-mock-trans.rs | 3 --- tests/run-pass/slice-of-zero-size-elements.rs | 2 -- 32 files changed, 77 insertions(+), 44 deletions(-) rename tests/compile-fail/{invalid_bool2.rs => invalid_bool.rs} (73%) rename tests/compile-fail/{invalid_char2.rs => invalid_char.rs} (80%) rename tests/compile-fail/{invalid_enum_discriminant2.rs => invalid_enum_discriminant.rs} (79%) create mode 100644 tests/compile-fail/stacked_borrows/static_memory_modification.rs create mode 100644 tests/compile-fail/validity/execute_memory.rs create mode 100644 tests/compile-fail/validity/fn_ptr_offset.rs diff --git a/src/lib.rs b/src/lib.rs index 2de6665186bf7..5d20078082f97 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -26,7 +26,7 @@ use syntax::attr; pub use rustc_mir::interpret::*; -pub use rustc_mir::interpret::{self, AllocMap}; // resolve ambiguity +pub use rustc_mir::interpret::{self, AllocMap, PlaceTy}; // resolve ambiguity mod fn_call; mod operator; @@ -521,4 +521,18 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { Ok(Pointer::new_with_tag(ptr.alloc_id, ptr.offset, tag)) } } + + #[inline(always)] + fn retag( + ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, + fn_entry: bool, + place: PlaceTy<'tcx, Borrow>, + ) -> EvalResult<'tcx> { + if !ecx.tcx.sess.opts.debugging_opts.mir_emit_retag || !ecx.machine.validate { + // No tracking, or no retagging. This is possible because a dependency of ours might be + // called with different flags than we are, + return Ok(()) + } + ecx.retag(fn_entry, place) + } } diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index a569ed4e55513..22216345b65e7 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -5,7 +5,7 @@ use rustc::hir; use super::{ MemoryAccess, MemoryKind, MiriMemoryKind, RangeMap, EvalResult, AllocId, - Pointer, + Pointer, PlaceTy, }; pub type Timestamp = u64; @@ -362,6 +362,12 @@ pub trait EvalContextExt<'tcx> { id: AllocId, kind: MemoryKind, ) -> Borrow; + + fn retag( + &mut self, + fn_entry: bool, + place: PlaceTy<'tcx, Borrow> + ) -> EvalResult<'tcx>; } impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, 'tcx> { @@ -506,4 +512,13 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' alloc.extra.first_borrow(mut_borrow, size); Borrow::Mut(mut_borrow) } + + fn retag( + &mut self, + _fn_entry: bool, + _place: PlaceTy<'tcx, Borrow> + ) -> EvalResult<'tcx> { + // TODO do something + Ok(()) + } } diff --git a/tests/compile-fail-fullmir/stack_free.rs b/tests/compile-fail-fullmir/stack_free.rs index 6d853e75fb4ae..a33bca1267595 100644 --- a/tests/compile-fail-fullmir/stack_free.rs +++ b/tests/compile-fail-fullmir/stack_free.rs @@ -1,5 +1,5 @@ // Validation changes why we fail -// compile-flags: -Zmir-emit-validate=0 -Zmiri-disable-validation +// compile-flags: -Zmiri-disable-validation // error-pattern: tried to deallocate Stack memory but gave Machine(Rust) as the kind diff --git a/tests/compile-fail/cast_box_int_to_fn_ptr.rs b/tests/compile-fail/cast_box_int_to_fn_ptr.rs index c3b1fa5958885..7ee3bc62767fb 100644 --- a/tests/compile-fail/cast_box_int_to_fn_ptr.rs +++ b/tests/compile-fail/cast_box_int_to_fn_ptr.rs @@ -1,5 +1,5 @@ // Validation makes this fail in the wrong place -// compile-flags: -Zmir-emit-validate=0 -Zmiri-disable-validation +// compile-flags: -Zmiri-disable-validation fn main() { let b = Box::new(42); diff --git a/tests/compile-fail/cast_int_to_fn_ptr.rs b/tests/compile-fail/cast_int_to_fn_ptr.rs index 1971ce1557e79..207af4ae2cefb 100644 --- a/tests/compile-fail/cast_int_to_fn_ptr.rs +++ b/tests/compile-fail/cast_int_to_fn_ptr.rs @@ -1,5 +1,5 @@ // Validation makes this fail in the wrong place -// compile-flags: -Zmir-emit-validate=0 -Zmiri-disable-validation +// compile-flags: -Zmiri-disable-validation fn main() { let g = unsafe { diff --git a/tests/compile-fail/execute_memory.rs b/tests/compile-fail/execute_memory.rs index d859e9072e324..295756ef0f561 100644 --- a/tests/compile-fail/execute_memory.rs +++ b/tests/compile-fail/execute_memory.rs @@ -1,5 +1,5 @@ // Validation makes this fail in the wrong place -// compile-flags: -Zmir-emit-validate=0 -Zmiri-disable-validation +// compile-flags: -Zmiri-disable-validation #![feature(box_syntax)] diff --git a/tests/compile-fail/fn_ptr_offset.rs b/tests/compile-fail/fn_ptr_offset.rs index cccb21790d650..9d29316fe24fe 100644 --- a/tests/compile-fail/fn_ptr_offset.rs +++ b/tests/compile-fail/fn_ptr_offset.rs @@ -1,5 +1,5 @@ // Validation makes this fail in the wrong place -// compile-flags: -Zmir-emit-validate=0 -Zmiri-disable-validation +// compile-flags: -Zmiri-disable-validation use std::mem; diff --git a/tests/compile-fail/invalid_bool2.rs b/tests/compile-fail/invalid_bool.rs similarity index 73% rename from tests/compile-fail/invalid_bool2.rs rename to tests/compile-fail/invalid_bool.rs index 2348c62559b00..e80dc15efaec9 100644 --- a/tests/compile-fail/invalid_bool2.rs +++ b/tests/compile-fail/invalid_bool.rs @@ -1,5 +1,5 @@ // Validation makes this fail in the wrong place -// compile-flags: -Zmir-emit-validate=0 -Zmiri-disable-validation +// compile-flags: -Zmiri-disable-validation fn main() { let b = unsafe { std::mem::transmute::(2) }; diff --git a/tests/compile-fail/invalid_char2.rs b/tests/compile-fail/invalid_char.rs similarity index 80% rename from tests/compile-fail/invalid_char2.rs rename to tests/compile-fail/invalid_char.rs index 5de2d073f3231..b67ed9ba520d2 100644 --- a/tests/compile-fail/invalid_char2.rs +++ b/tests/compile-fail/invalid_char.rs @@ -1,5 +1,5 @@ // Validation makes this fail in the wrong place -// compile-flags: -Zmir-emit-validate=0 -Zmiri-disable-validation +// compile-flags: -Zmiri-disable-validation fn main() { assert!(std::char::from_u32(-1_i32 as u32).is_none()); diff --git a/tests/compile-fail/invalid_enum_discriminant2.rs b/tests/compile-fail/invalid_enum_discriminant.rs similarity index 79% rename from tests/compile-fail/invalid_enum_discriminant2.rs rename to tests/compile-fail/invalid_enum_discriminant.rs index ea94081693e1b..bd5cb55b6c92b 100644 --- a/tests/compile-fail/invalid_enum_discriminant2.rs +++ b/tests/compile-fail/invalid_enum_discriminant.rs @@ -1,5 +1,5 @@ // Validation makes this fail in the wrong place -// compile-flags: -Zmir-emit-validate=0 -Zmiri-disable-validation +// compile-flags: -Zmiri-disable-validation // error-pattern: invalid enum discriminant diff --git a/tests/compile-fail/never_say_never.rs b/tests/compile-fail/never_say_never.rs index 634488489b539..d7e6a8c09f64e 100644 --- a/tests/compile-fail/never_say_never.rs +++ b/tests/compile-fail/never_say_never.rs @@ -1,5 +1,5 @@ // This should fail even without validation -// compile-flags: -Zmir-emit-validate=0 -Zmiri-disable-validation +// compile-flags: -Zmiri-disable-validation #![feature(never_type)] #![allow(unreachable_code)] diff --git a/tests/compile-fail/never_transmute_humans.rs b/tests/compile-fail/never_transmute_humans.rs index c5c53d4231c7c..169e861be0b1f 100644 --- a/tests/compile-fail/never_transmute_humans.rs +++ b/tests/compile-fail/never_transmute_humans.rs @@ -1,5 +1,5 @@ // This should fail even without validation -// compile-flags: -Zmir-emit-validate=0 -Zmiri-disable-validation +// compile-flags: -Zmiri-disable-validation #![feature(never_type)] #![allow(unreachable_code)] diff --git a/tests/compile-fail/never_transmute_void.rs b/tests/compile-fail/never_transmute_void.rs index 5620b6559cfde..9c0165fed222a 100644 --- a/tests/compile-fail/never_transmute_void.rs +++ b/tests/compile-fail/never_transmute_void.rs @@ -1,5 +1,5 @@ // This should fail even without validation -// compile-flags: -Zmir-emit-validate=0 -Zmiri-disable-validation +// compile-flags: -Zmiri-disable-validation #![feature(never_type)] #![allow(unreachable_code)] diff --git a/tests/compile-fail/panic.rs b/tests/compile-fail/panic.rs index 80149eeffaa64..0d594f9bd4c3b 100644 --- a/tests/compile-fail/panic.rs +++ b/tests/compile-fail/panic.rs @@ -1,5 +1,3 @@ -// FIXME: Something in panic handling fails validation with full-MIR -// compile-flags: -Zmir-emit-validate=0 //error-pattern: the evaluated program panicked fn main() { diff --git a/tests/compile-fail/reference_to_packed.rs b/tests/compile-fail/reference_to_packed.rs index 14a2afc33f7fe..befe96f2b35d9 100644 --- a/tests/compile-fail/reference_to_packed.rs +++ b/tests/compile-fail/reference_to_packed.rs @@ -1,5 +1,5 @@ // This should fail even without validation -// compile-flags: -Zmir-emit-validate=0 -Zmiri-disable-validation +// compile-flags: -Zmiri-disable-validation #![allow(dead_code, unused_variables)] diff --git a/tests/compile-fail/stacked_borrows/static_memory_modification.rs b/tests/compile-fail/stacked_borrows/static_memory_modification.rs new file mode 100644 index 0000000000000..c092cbfe50985 --- /dev/null +++ b/tests/compile-fail/stacked_borrows/static_memory_modification.rs @@ -0,0 +1,8 @@ +static X: usize = 5; + +#[allow(mutable_transmutes)] +fn main() { + let _x = unsafe { + std::mem::transmute::<&usize, &mut usize>(&X) //~ ERROR mutable reference with frozen tag + }; +} diff --git a/tests/compile-fail/static_memory_modification.rs b/tests/compile-fail/static_memory_modification.rs index c758926458651..07a277a16f3ae 100644 --- a/tests/compile-fail/static_memory_modification.rs +++ b/tests/compile-fail/static_memory_modification.rs @@ -1,5 +1,5 @@ // Validation detects that we are casting & to &mut and so it changes why we fail -// compile-flags: -Zmir-emit-validate=0 -Zmiri-disable-validation +// compile-flags: -Zmiri-disable-validation static X: usize = 5; diff --git a/tests/compile-fail/static_memory_modification2.rs b/tests/compile-fail/static_memory_modification2.rs index c9857b20592e4..73928f533cb70 100644 --- a/tests/compile-fail/static_memory_modification2.rs +++ b/tests/compile-fail/static_memory_modification2.rs @@ -1,5 +1,5 @@ // Validation detects that we are casting & to &mut and so it changes why we fail -// compile-flags: -Zmir-emit-validate=0 -Zmiri-disable-validation +// compile-flags: -Zmiri-disable-validation use std::mem::transmute; diff --git a/tests/compile-fail/static_memory_modification3.rs b/tests/compile-fail/static_memory_modification3.rs index 41a62787296f0..280f34a5a0213 100644 --- a/tests/compile-fail/static_memory_modification3.rs +++ b/tests/compile-fail/static_memory_modification3.rs @@ -1,5 +1,5 @@ // Validation detects that we are casting & to &mut and so it changes why we fail -// compile-flags: -Zmir-emit-validate=0 -Zmiri-disable-validation +// compile-flags: -Zmiri-disable-validation use std::mem::transmute; diff --git a/tests/compile-fail/storage_dead_dangling.rs b/tests/compile-fail/storage_dead_dangling.rs index 69917dce85910..85c76f6f41f6e 100644 --- a/tests/compile-fail/storage_dead_dangling.rs +++ b/tests/compile-fail/storage_dead_dangling.rs @@ -1,5 +1,5 @@ // This should fail even without validation -// compile-flags: -Zmir-emit-validate=0 -Zmiri-disable-validation +// compile-flags: -Zmiri-disable-validation static mut LEAK: usize = 0; diff --git a/tests/compile-fail/transmute_fat.rs b/tests/compile-fail/transmute_fat.rs index e1f916910d732..ede0486be4130 100644 --- a/tests/compile-fail/transmute_fat.rs +++ b/tests/compile-fail/transmute_fat.rs @@ -1,5 +1,5 @@ // This should fail even without validation -// compile-flags: -Zmir-emit-validate=0 +// compile-flags: -Zmiri-disable-validation fn main() { #[cfg(target_pointer_width="64")] diff --git a/tests/compile-fail/unaligned_ptr_cast.rs b/tests/compile-fail/unaligned_ptr_cast.rs index 47317afd36ec9..e64594d3e7eda 100644 --- a/tests/compile-fail/unaligned_ptr_cast.rs +++ b/tests/compile-fail/unaligned_ptr_cast.rs @@ -1,5 +1,5 @@ // This should fail even without validation -// compile-flags: -Zmir-emit-validate=0 -Zmiri-disable-validation +// compile-flags: -Zmiri-disable-validation fn main() { let x = &2u16; diff --git a/tests/compile-fail/unaligned_ptr_cast2.rs b/tests/compile-fail/unaligned_ptr_cast2.rs index d146f21dfe60f..1112f2f33c148 100644 --- a/tests/compile-fail/unaligned_ptr_cast2.rs +++ b/tests/compile-fail/unaligned_ptr_cast2.rs @@ -1,5 +1,5 @@ // This should fail even without validation -// compile-flags: -Zmir-emit-validate=0 -Zmiri-disable-validation +// compile-flags: -Zmiri-disable-validation fn main() { let x = &2u16; diff --git a/tests/compile-fail/undefined_byte_read.rs b/tests/compile-fail/undefined_byte_read.rs index 1f092936148e0..fca749ef9ccbd 100644 --- a/tests/compile-fail/undefined_byte_read.rs +++ b/tests/compile-fail/undefined_byte_read.rs @@ -1,6 +1,3 @@ -// This should fail even without validation -// compile-flags: -Zmir-emit-validate=0 - fn main() { let v: Vec = Vec::with_capacity(10); let undef = unsafe { *v.get_unchecked(5) }; diff --git a/tests/compile-fail/validity/execute_memory.rs b/tests/compile-fail/validity/execute_memory.rs new file mode 100644 index 0000000000000..426a51faf8a37 --- /dev/null +++ b/tests/compile-fail/validity/execute_memory.rs @@ -0,0 +1,8 @@ +#![feature(box_syntax)] + +fn main() { + let x = box 42; + unsafe { + let _f = std::mem::transmute::, fn()>(x); //~ ERROR encountered a pointer, but expected a function pointer + } +} diff --git a/tests/compile-fail/validity/fn_ptr_offset.rs b/tests/compile-fail/validity/fn_ptr_offset.rs new file mode 100644 index 0000000000000..4989f4d3af7bd --- /dev/null +++ b/tests/compile-fail/validity/fn_ptr_offset.rs @@ -0,0 +1,10 @@ +use std::mem; + +fn f() {} + +fn main() { + let x : fn() = f; + let y : *mut u8 = unsafe { mem::transmute(x) }; + let y = y.wrapping_offset(1); + let _x : fn() = unsafe { mem::transmute(y) }; //~ ERROR encountered a potentially NULL pointer +} diff --git a/tests/compiletest.rs b/tests/compiletest.rs index 0b2058597e185..98e3fde54e69e 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -58,13 +58,11 @@ fn compile_fail(sysroot: &Path, path: &str, target: &str, host: &str, need_fullm let mut flags = Vec::new(); flags.push(format!("--sysroot {}", sysroot.display())); flags.push("-Dwarnings -Dunused".to_owned()); // overwrite the -Aunused in compiletest-rs - flags.push("-Zmir-emit-validate=1".to_owned()); if opt { // Optimizing too aggressivley makes UB detection harder, but test at least // the default value. + // FIXME: Opt level 3 ICEs during stack trace generation. flags.push("-Zmir-opt-level=1".to_owned()); - } else { - flags.push("-Zmir-opt-level=0".to_owned()); } let mut config = compiletest::Config::default().tempdir(); @@ -102,11 +100,8 @@ fn miri_pass(sysroot: &Path, path: &str, target: &str, host: &str, need_fullmir: let mut flags = Vec::new(); flags.push(format!("--sysroot {}", sysroot.display())); flags.push("-Dwarnings -Dunused".to_owned()); // overwrite the -Aunused in compiletest-rs - flags.push("-Zmir-emit-validate=1".to_owned()); if opt { flags.push("-Zmir-opt-level=3".to_owned()); - } else { - flags.push("-Zmir-opt-level=0".to_owned()); } let mut config = compiletest::Config::default().tempdir(); diff --git a/tests/run-pass/move-undef-primval.rs b/tests/run-pass/move-undef-primval.rs index 2c18c2d3687a5..73c33943a63ac 100644 --- a/tests/run-pass/move-undef-primval.rs +++ b/tests/run-pass/move-undef-primval.rs @@ -1,6 +1,3 @@ -// Moving around undef is not allowed by validation -// compile-flags: -Zmir-emit-validate=0 - struct Foo { _inner: i32, } diff --git a/tests/run-pass/packed_struct.rs b/tests/run-pass/packed_struct.rs index e10781e656058..303e90742fc11 100644 --- a/tests/run-pass/packed_struct.rs +++ b/tests/run-pass/packed_struct.rs @@ -1,4 +1,3 @@ -// compile-flags: -Zmir-emit-validate=0 #![allow(dead_code)] #![feature(unsize, coerce_unsized)] diff --git a/tests/run-pass/recursive_static.rs b/tests/run-pass/recursive_static.rs index d259ca6361c97..77f2902917a1c 100644 --- a/tests/run-pass/recursive_static.rs +++ b/tests/run-pass/recursive_static.rs @@ -1,6 +1,3 @@ -// FIXME: Disable validation until we figure out how to handle recursive statics. -// compile-flags: -Zmir-emit-validate=0 - struct S(&'static S); static S1: S = S(&S2); static S2: S = S(&S1); diff --git a/tests/run-pass/regions-mock-trans.rs b/tests/run-pass/regions-mock-trans.rs index 039175e9acd60..130eaa288ebef 100644 --- a/tests/run-pass/regions-mock-trans.rs +++ b/tests/run-pass/regions-mock-trans.rs @@ -8,9 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// FIXME: We handle uninitialized storage here, which currently makes validation fail. -// compile-flags: -Zmir-emit-validate=0 - //ignore-windows: Uses POSIX APIs #![feature(libc)] diff --git a/tests/run-pass/slice-of-zero-size-elements.rs b/tests/run-pass/slice-of-zero-size-elements.rs index dbe8ec9addacc..aa9d117d726f1 100644 --- a/tests/run-pass/slice-of-zero-size-elements.rs +++ b/tests/run-pass/slice-of-zero-size-elements.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// compile-flags: -C debug-assertions - use std::slice; fn foo(v: &[T]) -> Option<&[T]> { From bba3c49e844895cdc32dc6ea1acbf0c6555beefd Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 26 Oct 2018 11:31:20 +0200 Subject: [PATCH 0322/3747] basic retagging (no fn_entry); this also makes us catch more bugs even with optimizations and we can finally stop mutating the state on deref --- src/lib.rs | 4 +- src/stacked_borrows.rs | 76 +++++++++---------- .../stacked_borrows/alias_through_mutation.rs | 3 - .../stacked_borrows/buggy_as_mut_slice.rs | 3 - .../stacked_borrows/buggy_split_at_mut.rs | 3 - .../stacked_borrows/illegal_write2.rs | 3 - .../stacked_borrows/illegal_write4.rs | 34 ++------- .../stacked_borrows/shared_confusion.rs | 10 ++- .../stacked_borrows/shared_confusion_opt.rs | 25 ++++++ 9 files changed, 81 insertions(+), 80 deletions(-) create mode 100644 tests/compile-fail/stacked_borrows/shared_confusion_opt.rs diff --git a/src/lib.rs b/src/lib.rs index 5d20078082f97..e1ae805fb15f4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -528,9 +528,11 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { fn_entry: bool, place: PlaceTy<'tcx, Borrow>, ) -> EvalResult<'tcx> { - if !ecx.tcx.sess.opts.debugging_opts.mir_emit_retag || !ecx.machine.validate { + if !ecx.tcx.sess.opts.debugging_opts.mir_emit_retag || !Self::enforce_validity(ecx) { // No tracking, or no retagging. This is possible because a dependency of ours might be // called with different flags than we are, + // Also, honor the whitelist in `enforce_validity` because otherwise we might retag + // uninitialized data. return Ok(()) } ecx.retag(fn_entry, place) diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 22216345b65e7..cb8c2a3e5e61d 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -1,6 +1,6 @@ -use std::cell::{Cell, RefCell}; +use std::cell::RefCell; -use rustc::ty::{Ty, layout::Size}; +use rustc::ty::{self, Ty, layout::Size}; use rustc::hir; use super::{ @@ -101,12 +101,12 @@ impl From> for RefKind { /// Extra global machine state #[derive(Clone, Debug)] pub struct State { - clock: Cell + clock: Timestamp } impl State { pub fn new() -> State { - State { clock: Cell::new(0) } + State { clock: 0 } } } @@ -129,6 +129,7 @@ impl Default for Stack { /// Extra per-allocation state #[derive(Clone, Debug, Default)] pub struct Stacks { + // Even reading memory can have effects on the stack, so we need a `RefCell` here. stacks: RefCell>, } @@ -249,9 +250,9 @@ impl<'tcx> Stack { } impl State { - fn increment_clock(&self) -> Timestamp { - let val = self.clock.get(); - self.clock.set(val + 1); + fn increment_clock(&mut self) -> Timestamp { + let val = self.clock; + self.clock = val + 1; val } } @@ -334,14 +335,8 @@ impl<'tcx> Stacks { } pub trait EvalContextExt<'tcx> { - fn tag_for_pointee( - &self, - pointee_ty: Ty<'tcx>, - ref_kind: RefKind, - ) -> Borrow; - fn tag_reference( - &self, + &mut self, ptr: Pointer, pointee_ty: Ty<'tcx>, size: Size, @@ -371,13 +366,16 @@ pub trait EvalContextExt<'tcx> { } impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, 'tcx> { - fn tag_for_pointee( - &self, + /// Called for place-to-value conversion. + fn tag_reference( + &mut self, + ptr: Pointer, pointee_ty: Ty<'tcx>, + size: Size, ref_kind: RefKind, - ) -> Borrow { + ) -> EvalResult<'tcx, Borrow> { let time = self.machine.stacked_borrows.increment_clock(); - match ref_kind { + let new_bor = match ref_kind { RefKind::Mut => Borrow::Mut(Mut::Uniq(time)), RefKind::Shr => // FIXME This does not do enough checking when only part of the data has @@ -390,18 +388,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' Borrow::Mut(Mut::Raw) }, RefKind::Raw => Borrow::Mut(Mut::Raw), - } - } - - /// Called for place-to-value conversion. - fn tag_reference( - &self, - ptr: Pointer, - pointee_ty: Ty<'tcx>, - size: Size, - ref_kind: RefKind, - ) -> EvalResult<'tcx, Borrow> { - let new_bor = self.tag_for_pointee(pointee_ty, ref_kind); + }; trace!("tag_reference: Creating new reference ({:?}) for {:?} (pointee {}, size {}): {:?}", ref_kind, ptr, pointee_ty, size.bytes(), new_bor); @@ -424,7 +411,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' fn tag_dereference( &self, ptr: Pointer, - pointee_ty: Ty<'tcx>, + _pointee_ty: Ty<'tcx>, size: Size, ref_kind: RefKind, ) -> EvalResult<'tcx, Borrow> { @@ -454,13 +441,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' // also using `var`, and that would be okay. } (RefKind::Shr, Borrow::Mut(Mut::Uniq(_))) => { - // A mut got transmuted to shr. High time we freeze this location! - // Make this a delayed reborrow. Redundant reborows to shr are okay, - // so we do not have to be worried about doing too much. - // FIXME: Reconsider if we really want to mutate things while doing just a deref, - // which, in particular, validation does. - trace!("tag_dereference: Lazy freezing of {:?}", ptr); - return self.tag_reference(ptr, pointee_ty, size, ref_kind); + // A mut got transmuted to shr. The mut borrow must be reactivatable. } (RefKind::Mut, Borrow::Frz(_)) => { // This is just invalid. @@ -516,9 +497,24 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' fn retag( &mut self, _fn_entry: bool, - _place: PlaceTy<'tcx, Borrow> + place: PlaceTy<'tcx, Borrow> ) -> EvalResult<'tcx> { - // TODO do something + // For now, we only retag if the toplevel type is a reference. + // TODO: Recurse into structs and enums, sharing code with validation. + let mutbl = match place.layout.ty.sty { + ty::Ref(_, _, mutbl) => mutbl, // go ahead + _ => return Ok(()), // don't do a thing + }; + // We want to reborrow the reference stored there. This will call the hooks + // above. First deref. + // (This is somewhat redundant because validation already did the same thing, + // but what can you do.) + let val = self.read_value(self.place_to_op(place)?)?; + let dest = self.ref_to_mplace(val)?; + // Now put a new ref into the old place. + // FIXME: Honor `fn_entry`! + let val = self.create_ref(dest, Some(mutbl))?; + self.write_value(val, place)?; Ok(()) } } diff --git a/tests/compile-fail/stacked_borrows/alias_through_mutation.rs b/tests/compile-fail/stacked_borrows/alias_through_mutation.rs index 7d56f30b3e69d..eb8966f3a5c71 100644 --- a/tests/compile-fail/stacked_borrows/alias_through_mutation.rs +++ b/tests/compile-fail/stacked_borrows/alias_through_mutation.rs @@ -1,6 +1,3 @@ -// With optimizations, we just store a raw in `x`, and there is no problem. -// compile-flags: -Zmir-opt-level=0 - #![allow(unused_variables)] // This makes a ref that was passed to us via &mut alias with things it should not alias with diff --git a/tests/compile-fail/stacked_borrows/buggy_as_mut_slice.rs b/tests/compile-fail/stacked_borrows/buggy_as_mut_slice.rs index dc1e3cc81e9e8..e86eb9ba6de80 100644 --- a/tests/compile-fail/stacked_borrows/buggy_as_mut_slice.rs +++ b/tests/compile-fail/stacked_borrows/buggy_as_mut_slice.rs @@ -1,6 +1,3 @@ -// FIXME: Without retagging, optimization kills finding this problem -// compile-flags: -Zmir-opt-level=0 - #![allow(unused_variables)] mod safe { diff --git a/tests/compile-fail/stacked_borrows/buggy_split_at_mut.rs b/tests/compile-fail/stacked_borrows/buggy_split_at_mut.rs index a697ba9167c07..a4f5f536b770d 100644 --- a/tests/compile-fail/stacked_borrows/buggy_split_at_mut.rs +++ b/tests/compile-fail/stacked_borrows/buggy_split_at_mut.rs @@ -1,6 +1,3 @@ -// FIXME: Without retagging, optimization kills finding this problem -// compile-flags: -Zmir-opt-level=0 - #![allow(unused_variables)] mod safe { diff --git a/tests/compile-fail/stacked_borrows/illegal_write2.rs b/tests/compile-fail/stacked_borrows/illegal_write2.rs index ac9c3397f5348..f4fefaad5e22d 100644 --- a/tests/compile-fail/stacked_borrows/illegal_write2.rs +++ b/tests/compile-fail/stacked_borrows/illegal_write2.rs @@ -1,6 +1,3 @@ -// The reborow gets optimized away, so we can only detect this issue without optimizations -// compile-flags: -Zmir-opt-level=0 - #![allow(unused_variables)] fn main() { diff --git a/tests/compile-fail/stacked_borrows/illegal_write4.rs b/tests/compile-fail/stacked_borrows/illegal_write4.rs index 094a38951974b..12deb518b4e7c 100644 --- a/tests/compile-fail/stacked_borrows/illegal_write4.rs +++ b/tests/compile-fail/stacked_borrows/illegal_write4.rs @@ -1,31 +1,13 @@ -// The compiler inserts some reborrows, enable optimizations to -// get rid of them. -// compile-flags: -Zmir-opt-level=1 - use std::mem; -// This is an example of a piece of code that intuitively seems like we might -// want to reject it, but that doesn't turn out to be possible. - fn main() { - let target = 42; - // Make sure a cannot use a raw-tagged `&mut` pointing to a frozen location, not - // even to create a raw. - let reference = ⌖ // freeze + let mut target = 42; + // Make sure we cannot use a raw-tagged `&mut` pointing to a frozen location. + // Even just creating it unfreezes. + let raw = &mut target as *mut _; // let this leak to raw + let reference = unsafe { &*raw }; // freeze let ptr = reference as *const _ as *mut i32; // raw ptr, with raw tag - let mut_ref: &mut i32 = unsafe { mem::transmute(ptr) }; // &mut, with raw tag - // Now we have an &mut to a frozen location, but that is completely normal: - // We'd just unfreeze the location if we used it. - let bad_ptr = mut_ref as *mut i32; // even just creating this is like a use of `mut_ref`. - // That violates the location being frozen! However, we do not properly detect this: - // We first see a `&mut` with a `Raw` tag being deref'd for a frozen location, - // which can happen legitimately if the compiler optimized away an `&mut*` that - // turns a raw into a `&mut`. Next, we create a raw ref to a frozen location - // from a `Raw` tag, which can happen legitimately when interior mutability - // is involved. - let _val = *reference; // Make sure it is still frozen. - - // We only actually unfreeze once we muteate through the bad pointer. - unsafe { *bad_ptr = 42 }; //~ ERROR does not exist on the stack - let _val = *reference; + let _mut_ref: &mut i32 = unsafe { mem::transmute(ptr) }; // &mut, with raw tag + // Now we retag, making our ref top-of-stack -- and, in particular, unfreezing. + let _val = *reference; //~ ERROR Location should be frozen } diff --git a/tests/compile-fail/stacked_borrows/shared_confusion.rs b/tests/compile-fail/stacked_borrows/shared_confusion.rs index e3e4c4da7765e..c02822ed4d3da 100644 --- a/tests/compile-fail/stacked_borrows/shared_confusion.rs +++ b/tests/compile-fail/stacked_borrows/shared_confusion.rs @@ -1,3 +1,11 @@ +// Optimization kills all the reborrows, enough to make this error go away. There are +// no retags either because we don't retag immediately after a `&[mut]`; we rely on +// that creating a fresh reference. +// See `shared_confusion_opt.rs` for a variant that is caught even with optimizations. +// Keep this test to make sure that without optimizations, we do not have to actually +// use the `x_inner_shr`. +// compile-flags: -Zmir-opt-level=0 + #![allow(unused_variables)] use std::cell::RefCell; @@ -9,7 +17,7 @@ fn test(r: &mut RefCell) { { let x_inner_shr = &*x_inner; // frozen let y = &*r; // outer ref, not freezing - let x_inner_shr2 = &*x_inner; // freezing again + let x_inner_shr = &*x_inner; // freezing again } // Our old raw should be dead by now unsafe { *x_evil = 0; } // this falls back to some Raw higher up the stack diff --git a/tests/compile-fail/stacked_borrows/shared_confusion_opt.rs b/tests/compile-fail/stacked_borrows/shared_confusion_opt.rs new file mode 100644 index 0000000000000..4a88d4d64133d --- /dev/null +++ b/tests/compile-fail/stacked_borrows/shared_confusion_opt.rs @@ -0,0 +1,25 @@ +// A variant of `shared_confusion.rs` that gets flagged even with optimizations. + +#![allow(unused_variables)] +use std::cell::RefCell; + +fn test(r: &mut RefCell) { + let x = &*r; // not freezing because interior mutability + let mut x_ref = x.borrow_mut(); + let x_inner : &mut i32 = &mut *x_ref; // Uniq reference + let x_evil = x_inner as *mut _; + { + let x_inner_shr = &*x_inner; // frozen + let _val = *x_inner_shr; + let y = &*r; // outer ref, not freezing + let x_inner_shr = &*x_inner; // freezing again + let _val = *x_inner_shr; + } + // Our old raw should be dead by now + unsafe { *x_evil = 0; } // this falls back to some Raw higher up the stack + *x_inner = 12; //~ ERROR Mut reference with non-reactivatable tag +} + +fn main() { + test(&mut RefCell::new(0)); +} From 85f821d7e9c1f920e6584821ffa0dbccded8f657 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 29 Oct 2018 19:48:43 +0100 Subject: [PATCH 0323/3747] unify checks on memory access and reborrowing, and update for Machine trait change --- src/lib.rs | 17 ++- src/stacked_borrows.rs | 121 +++++++++++------- .../stacked_borrows/illegal_read1.rs | 15 +++ .../stacked_borrows/illegal_read2.rs | 18 +++ .../stacked_borrows/illegal_write5.rs | 15 +++ .../stacked_borrows/load_invalid_shr.rs | 2 +- .../stacked_borrows/pass_invalid_shr.rs | 2 +- .../stacked_borrows/return_invalid_shr.rs | 2 +- 8 files changed, 137 insertions(+), 55 deletions(-) create mode 100644 tests/compile-fail/stacked_borrows/illegal_read1.rs create mode 100644 tests/compile-fail/stacked_borrows/illegal_read2.rs create mode 100644 tests/compile-fail/stacked_borrows/illegal_write5.rs diff --git a/src/lib.rs b/src/lib.rs index e1ae805fb15f4..b397e9a6d224b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -452,21 +452,30 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { } #[inline(always)] - fn memory_accessed( + fn memory_read( alloc: &Allocation, ptr: Pointer, size: Size, - access: MemoryAccess, ) -> EvalResult<'tcx> { - alloc.extra.memory_accessed(ptr, size, access) + alloc.extra.memory_read(ptr, size) + } + + #[inline(always)] + fn memory_written( + alloc: &mut Allocation, + ptr: Pointer, + size: Size, + ) -> EvalResult<'tcx> { + alloc.extra.memory_written(ptr, size) } #[inline(always)] fn memory_deallocated( alloc: &mut Allocation, ptr: Pointer, + size: Size, ) -> EvalResult<'tcx> { - alloc.extra.memory_deallocated(ptr) + alloc.extra.memory_deallocated(ptr, size) } #[inline(always)] diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index cb8c2a3e5e61d..baeb04b44ea75 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -4,7 +4,7 @@ use rustc::ty::{self, Ty, layout::Size}; use rustc::hir; use super::{ - MemoryAccess, MemoryKind, MiriMemoryKind, RangeMap, EvalResult, AllocId, + MemoryKind, MiriMemoryKind, RangeMap, EvalResult, AllocId, Pointer, PlaceTy, }; @@ -126,6 +126,13 @@ impl Default for Stack { } } +impl Stack { + #[inline(always)] + fn is_frozen(&self) -> bool { + self.frozen_since.is_some() + } +} + /// Extra per-allocation state #[derive(Clone, Debug, Default)] pub struct Stacks { @@ -206,8 +213,13 @@ impl<'tcx> Stack { match action { None => {}, // nothing to do Some(top) => { + if self.frozen_since.is_some() { + trace!("reactivate: Unfreezing"); + } self.frozen_since = None; - self.borrows.truncate(top+1); + for itm in self.borrows.drain(top+1..).rev() { + trace!("reactivate: Popping {:?}", itm); + } } } @@ -215,7 +227,9 @@ impl<'tcx> Stack { } /// Initiate `bor`; mostly this means freezing or pushing. - fn initiate(&mut self, bor: Borrow) -> EvalResult<'tcx> { + /// This operation cannot fail; it is up to the caller to ensure that the precondition + /// is met: We cannot push onto frozen stacks. + fn initiate(&mut self, bor: Borrow) { match bor { Borrow::Frz(t) => { match self.frozen_since { @@ -241,11 +255,10 @@ impl<'tcx> Stack { // from it is fine with this as well. trace!("initiate: Initiating a raw on a frozen location, not doing a thing"), Some(_) => - return err!(MachineError(format!("Trying to mutate frozen location"))) + bug!("Trying to mutate frozen location") } } } - Ok(()) } } @@ -259,49 +272,27 @@ impl State { /// Higher-level operations impl<'tcx> Stacks { - pub fn memory_accessed( - &self, - ptr: Pointer, - size: Size, - access: MemoryAccess, - ) -> EvalResult<'tcx> { - trace!("memory_accessed({:?}) with tag {:?}: {:?}, size {}", access, ptr.tag, ptr, size.bytes()); - let mut stacks = self.stacks.borrow_mut(); - for stack in stacks.iter_mut(ptr.offset, size) { - // FIXME: Compare this with what the blog post says. - stack.reactivate(ptr.tag, /*force_mut*/access == MemoryAccess::Write)?; - } - Ok(()) - } - - pub fn memory_deallocated( - &mut self, - ptr: Pointer, - ) -> EvalResult<'tcx> { - trace!("memory_deallocated with tag {:?}: {:?}", ptr.tag, ptr); - let stacks = self.stacks.get_mut(); - for stack in stacks.iter_mut_all() { - // This is like mutating. - stack.reactivate(ptr.tag, /*force_mut*/true)?; - } - Ok(()) - } - - fn reborrow( + /// The single most operation: Make sure that using `ptr` as `ref_kind` is okay, + /// and if `new_bor` is present then make that the new current borrow. + fn use_and_maybe_re_borrow( &self, ptr: Pointer, size: Size, - new_bor: Borrow, - permit_redundant: bool, + ref_kind: RefKind, + new_bor: Option, ) -> EvalResult<'tcx> { + trace!("use_and_maybe_re_borrow of tag {:?} as {:?}, new {:?}: {:?}, size {}", + ptr.tag, ref_kind, new_bor, ptr, size.bytes()); let mut stacks = self.stacks.borrow_mut(); for stack in stacks.iter_mut(ptr.offset, size) { - if permit_redundant && stack.check(new_bor) { - // The new borrow is already active! This can happen when creating multiple - // shared references from the same mutable reference. Do nothing. - trace!("reborrow: New borrow {:?} is already active, not doing a thing", new_bor); + if ref_kind == RefKind::Shr && stack.is_frozen() { + // Location already frozen. We don't want to unfreeze, but make sure + // the ref makes some sense. + if let Err(err) = stack.reactivatable(ptr.tag, /*force_mut*/false) { + return err!(MachineError(err)); + } } else { - // If we are creating a uniq ref, we certainly want to unfreeze. + // If we are creating a mutable ref, we certainly want to unfreeze. // Even if we are doing so from a raw. // Notice that if this is a local, whenever we access it directly the // tag here will be the bottommost `Uniq` for that local. That `Uniq` @@ -312,14 +303,47 @@ impl<'tcx> Stacks { // `reset` which the blog post [1] says to perform when accessing a local. // // [1] https://www.ralfj.de/blog/2018/08/07/stacked-borrows.html - stack.reactivate(ptr.tag, /*force_mut*/new_bor.is_uniq())?; - stack.initiate(new_bor)?; + let force_mut = ref_kind == RefKind::Mut; + stack.reactivate(ptr.tag, force_mut)?; + } + if let Some(new_bor) = new_bor { + stack.initiate(new_bor); } } Ok(()) } + #[inline(always)] + pub fn memory_read( + &self, + ptr: Pointer, + size: Size, + ) -> EvalResult<'tcx> { + // Reads behave exactly like the first half of a reborrow-to-shr + self.use_and_maybe_re_borrow(ptr, size, RefKind::Shr, None) + } + + #[inline(always)] + pub fn memory_written( + &mut self, + ptr: Pointer, + size: Size, + ) -> EvalResult<'tcx> { + // Writes behave exactly like the first half of a reborrow-to-mut + self.use_and_maybe_re_borrow(ptr, size, RefKind::Mut, None) + } + + pub fn memory_deallocated( + &mut self, + ptr: Pointer, + size: Size, + ) -> EvalResult<'tcx> { + // This is like mutating + self.use_and_maybe_re_borrow(ptr, size, RefKind::Mut, None) + // FIXME: Error out of there are any barriers? + } + /// Pushes the first borrow to the stacks, must be a mutable one. pub fn first_borrow( &mut self, @@ -398,8 +422,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' // Update the stacks. We cannot use `get_mut` becuse this might be immutable // memory. let alloc = self.memory().get(ptr.alloc_id).expect("We checked that the ptr is fine!"); - let permit_redundant = ref_kind == RefKind::Shr; // redundant shared refs are okay - alloc.extra.reborrow(ptr, size, new_bor, permit_redundant)?; + alloc.extra.use_and_maybe_re_borrow(ptr, size, ref_kind, Some(new_bor))?; Ok(new_bor) } @@ -411,10 +434,12 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' fn tag_dereference( &self, ptr: Pointer, - _pointee_ty: Ty<'tcx>, + pointee_ty: Ty<'tcx>, size: Size, ref_kind: RefKind, ) -> EvalResult<'tcx, Borrow> { + trace!("tag_reference: Accessing reference ({:?}) for {:?} (pointee {}, size {})", + ref_kind, ptr, pointee_ty, size.bytes()); // In principle we should not have to do anything here. However, with transmutes involved, // it can happen that the tag of `ptr` does not actually match `ref_kind`, and we // should adjust for that. @@ -506,12 +531,12 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' _ => return Ok(()), // don't do a thing }; // We want to reborrow the reference stored there. This will call the hooks - // above. First deref. + // above. First deref, which will call `tag_dereference`. // (This is somewhat redundant because validation already did the same thing, // but what can you do.) let val = self.read_value(self.place_to_op(place)?)?; let dest = self.ref_to_mplace(val)?; - // Now put a new ref into the old place. + // Now put a new ref into the old place, which will call `tag_reference`. // FIXME: Honor `fn_entry`! let val = self.create_ref(dest, Some(mutbl))?; self.write_value(val, place)?; diff --git a/tests/compile-fail/stacked_borrows/illegal_read1.rs b/tests/compile-fail/stacked_borrows/illegal_read1.rs new file mode 100644 index 0000000000000..f0e696c457cb3 --- /dev/null +++ b/tests/compile-fail/stacked_borrows/illegal_read1.rs @@ -0,0 +1,15 @@ +// A callee may not read the destination of our `&mut` without +// us noticing. + +fn main() { + let mut x = 15; + let xraw = &mut x as *mut _; + let xref = unsafe { &mut *xraw }; // derived from raw, so using raw is still okay... + callee(xraw); + let _val = *xref; // ...but any use of raw will invalidate our ref. + //~^ ERROR: Mut reference with non-reactivatable tag +} + +fn callee(xraw: *mut i32) { + let _val = unsafe { *xraw }; +} diff --git a/tests/compile-fail/stacked_borrows/illegal_read2.rs b/tests/compile-fail/stacked_borrows/illegal_read2.rs new file mode 100644 index 0000000000000..ec59c57d31b72 --- /dev/null +++ b/tests/compile-fail/stacked_borrows/illegal_read2.rs @@ -0,0 +1,18 @@ +// A callee may not read the destination of our `&mut` without +// us noticing. + +fn main() { + let mut x = 15; + let xraw = &mut x as *mut _; + let xref = unsafe { &mut *xraw }; // derived from raw, so using raw is still okay... + callee(xraw); + let _val = *xref; // ...but any use of raw will invalidate our ref. + //~^ ERROR: Mut reference with non-reactivatable tag +} + +fn callee(xraw: *mut i32) { + // We are a bit sneaky: We first create a shared ref, exploiting the reborrowing rules, + // and then we read through that. + let shr = unsafe { &*xraw }; + let _val = *shr; +} diff --git a/tests/compile-fail/stacked_borrows/illegal_write5.rs b/tests/compile-fail/stacked_borrows/illegal_write5.rs new file mode 100644 index 0000000000000..4b5d08c03a479 --- /dev/null +++ b/tests/compile-fail/stacked_borrows/illegal_write5.rs @@ -0,0 +1,15 @@ +// A callee may not write to the destination of our `&mut` without +// us noticing. + +fn main() { + let mut x = 15; + let xraw = &mut x as *mut _; + let xref = unsafe { &mut *xraw }; // derived from raw, so using raw is still okay... + callee(xraw); + let _val = *xref; // ...but any use of raw will invalidate our ref. + //~^ ERROR: Mut reference with non-reactivatable tag +} + +fn callee(xraw: *mut i32) { + unsafe { *xraw = 15 }; +} diff --git a/tests/compile-fail/stacked_borrows/load_invalid_shr.rs b/tests/compile-fail/stacked_borrows/load_invalid_shr.rs index 785a15c4704a3..b4b180e350f1f 100644 --- a/tests/compile-fail/stacked_borrows/load_invalid_shr.rs +++ b/tests/compile-fail/stacked_borrows/load_invalid_shr.rs @@ -4,6 +4,6 @@ fn main() { let xraw = x as *mut _; let xref = unsafe { &*xraw }; let xref_in_mem = Box::new(xref); - let _val = *x; // invalidate xraw + *x = 42; // invalidate xraw let _val = *xref_in_mem; //~ ERROR Shr reference with non-reactivatable tag: Location should be frozen } diff --git a/tests/compile-fail/stacked_borrows/pass_invalid_shr.rs b/tests/compile-fail/stacked_borrows/pass_invalid_shr.rs index 8b7a846d849c0..477c86f6060d6 100644 --- a/tests/compile-fail/stacked_borrows/pass_invalid_shr.rs +++ b/tests/compile-fail/stacked_borrows/pass_invalid_shr.rs @@ -5,6 +5,6 @@ fn main() { let x = &mut 42; let xraw = &*x as *const _; let xref = unsafe { &*xraw }; - let _val = *x; // invalidate xraw + *x = 42; // invalidate xraw foo(xref); //~ ERROR Shr reference with non-reactivatable tag: Location should be frozen } diff --git a/tests/compile-fail/stacked_borrows/return_invalid_shr.rs b/tests/compile-fail/stacked_borrows/return_invalid_shr.rs index 89c94127b0b71..954b5ec8e5920 100644 --- a/tests/compile-fail/stacked_borrows/return_invalid_shr.rs +++ b/tests/compile-fail/stacked_borrows/return_invalid_shr.rs @@ -2,7 +2,7 @@ fn foo(x: &mut (i32, i32)) -> &i32 { let xraw = x as *mut (i32, i32); let ret = unsafe { &(*xraw).1 }; - let _val = *x; // invalidate xraw and its children + x.1 = 42; // invalidate xraw on the 2nd field ret //~ ERROR Shr reference with non-reactivatable tag: Location should be frozen } From 430e047a6f2364f9c6d7d950816eef09f3db0428 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 29 Oct 2018 21:04:56 +0100 Subject: [PATCH 0324/3747] start collecting some things ALLOWED by stacked borrows in a run-pass test --- .../run-pass/deref_partially_dangling_raw.rs | 9 ------- tests/run-pass/stacked-borrows.rs | 27 +++++++++++++++++++ 2 files changed, 27 insertions(+), 9 deletions(-) delete mode 100644 tests/run-pass/deref_partially_dangling_raw.rs create mode 100644 tests/run-pass/stacked-borrows.rs diff --git a/tests/run-pass/deref_partially_dangling_raw.rs b/tests/run-pass/deref_partially_dangling_raw.rs deleted file mode 100644 index 8639a289363ba..0000000000000 --- a/tests/run-pass/deref_partially_dangling_raw.rs +++ /dev/null @@ -1,9 +0,0 @@ -// Deref a raw ptr to access a field of a large struct, where the field -// is allocated but not the entire struct is. -// For now, we want to allow this. - -fn main() { - let x = (1, 1); - let xptr = &x as *const _ as *const (i32, i32, i32); - let _val = unsafe { (*xptr).1 }; -} diff --git a/tests/run-pass/stacked-borrows.rs b/tests/run-pass/stacked-borrows.rs new file mode 100644 index 0000000000000..cde6968a26415 --- /dev/null +++ b/tests/run-pass/stacked-borrows.rs @@ -0,0 +1,27 @@ +// Test various stacked-borrows-related things. +fn main() { + deref_partially_dangling_raw(); + read_does_not_invalidate(); +} + +// Deref a raw ptr to access a field of a large struct, where the field +// is allocated but not the entire struct is. +// For now, we want to allow this. +fn deref_partially_dangling_raw() { + let x = (1, 1); + let xptr = &x as *const _ as *const (i32, i32, i32); + let _val = unsafe { (*xptr).1 }; +} + +// Make sure that reading from an `&mut` does, like reborrowing to `&`, +// NOT invalidate other reborrows. +fn read_does_not_invalidate() { + fn foo(x: &mut (i32, i32)) -> &i32 { + let xraw = x as *mut (i32, i32); + let ret = unsafe { &(*xraw).1 }; + let _val = x.1; // we just read, this does NOT invalidate the reborrows. + ret + } + + foo(&mut (1, 2)); +} From 3302656247438d89936bbbfd55fe696c82fa98e4 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 30 Oct 2018 13:56:19 +0100 Subject: [PATCH 0325/3747] More extensive slice and vec tests Not all of them pass validation... --- tests/run-pass/slice-of-zero-size-elements.rs | 56 ------ tests/run-pass/slices.rs | 178 ++++++++++++++++++ tests/run-pass/vecs.rs | 38 ++++ 3 files changed, 216 insertions(+), 56 deletions(-) delete mode 100644 tests/run-pass/slice-of-zero-size-elements.rs create mode 100644 tests/run-pass/slices.rs diff --git a/tests/run-pass/slice-of-zero-size-elements.rs b/tests/run-pass/slice-of-zero-size-elements.rs deleted file mode 100644 index aa9d117d726f1..0000000000000 --- a/tests/run-pass/slice-of-zero-size-elements.rs +++ /dev/null @@ -1,56 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use std::slice; - -fn foo(v: &[T]) -> Option<&[T]> { - let mut it = v.iter(); - for _ in 0..5 { - let _ = it.next(); - } - Some(it.as_slice()) -} - -fn foo_mut(v: &mut [T]) -> Option<&mut [T]> { - let mut it = v.iter_mut(); - for _ in 0..5 { - let _ = it.next(); - } - Some(it.into_slice()) -} - -pub fn main() { - // In a slice of zero-size elements the pointer is meaningless. - // Ensure iteration still works even if the pointer is at the end of the address space. - let slice: &[()] = unsafe { slice::from_raw_parts(-5isize as *const (), 10) }; - assert_eq!(slice.len(), 10); - assert_eq!(slice.iter().count(), 10); - - // .nth() on the iterator should also behave correctly - let mut it = slice.iter(); - assert!(it.nth(5).is_some()); - assert_eq!(it.count(), 4); - - // Converting Iter to a slice should never have a null pointer - assert!(foo(slice).is_some()); - - // Test mutable iterators as well - let slice: &mut [()] = unsafe { slice::from_raw_parts_mut(-5isize as *mut (), 10) }; - assert_eq!(slice.len(), 10); - assert_eq!(slice.iter_mut().count(), 10); - - { - let mut it = slice.iter_mut(); - assert!(it.nth(5).is_some()); - assert_eq!(it.count(), 4); - } - - assert!(foo_mut(slice).is_some()) -} diff --git a/tests/run-pass/slices.rs b/tests/run-pass/slices.rs new file mode 100644 index 0000000000000..119c9b90a05c1 --- /dev/null +++ b/tests/run-pass/slices.rs @@ -0,0 +1,178 @@ +// FIXME: Still investigating whether there is UB here +// compile-flags: -Zmiri-disable-validation + +use std::slice; + +fn slice_of_zst() { + fn foo(v: &[T]) -> Option<&[T]> { + let mut it = v.iter(); + for _ in 0..5 { + let _ = it.next(); + } + Some(it.as_slice()) + } + + fn foo_mut(v: &mut [T]) -> Option<&mut [T]> { + let mut it = v.iter_mut(); + for _ in 0..5 { + let _ = it.next(); + } + Some(it.into_slice()) + } + + // In a slice of zero-size elements the pointer is meaningless. + // Ensure iteration still works even if the pointer is at the end of the address space. + let slice: &[()] = unsafe { slice::from_raw_parts(-5isize as *const (), 10) }; + assert_eq!(slice.len(), 10); + assert_eq!(slice.iter().count(), 10); + + // .nth() on the iterator should also behave correctly + let mut it = slice.iter(); + assert!(it.nth(5).is_some()); + assert_eq!(it.count(), 4); + + // Converting Iter to a slice should never have a null pointer + assert!(foo(slice).is_some()); + + // Test mutable iterators as well + let slice: &mut [()] = unsafe { slice::from_raw_parts_mut(-5isize as *mut (), 10) }; + assert_eq!(slice.len(), 10); + assert_eq!(slice.iter_mut().count(), 10); + + { + let mut it = slice.iter_mut(); + assert!(it.nth(5).is_some()); + assert_eq!(it.count(), 4); + } + + assert!(foo_mut(slice).is_some()) +} + +fn test_iter_ref_consistency() { + use std::fmt::Debug; + + fn test(x : T) { + let v : &[T] = &[x, x, x]; + let v_ptrs : [*const T; 3] = match v { + [ref v1, ref v2, ref v3] => [v1 as *const _, v2 as *const _, v3 as *const _], + _ => unreachable!() + }; + let len = v.len(); + + // nth(i) + for i in 0..len { + assert_eq!(&v[i] as *const _, v_ptrs[i]); // check the v_ptrs array, just to be sure + let nth = v.iter().nth(i).unwrap(); + assert_eq!(nth as *const _, v_ptrs[i]); + } + assert_eq!(v.iter().nth(len), None, "nth(len) should return None"); + + // stepping through with nth(0) + { + let mut it = v.iter(); + for i in 0..len { + let next = it.nth(0).unwrap(); + assert_eq!(next as *const _, v_ptrs[i]); + } + assert_eq!(it.nth(0), None); + } + + // next() + { + let mut it = v.iter(); + for i in 0..len { + let remaining = len - i; + assert_eq!(it.size_hint(), (remaining, Some(remaining))); + + let next = it.next().unwrap(); + assert_eq!(next as *const _, v_ptrs[i]); + } + assert_eq!(it.size_hint(), (0, Some(0))); + assert_eq!(it.next(), None, "The final call to next() should return None"); + } + + // next_back() + { + let mut it = v.iter(); + for i in 0..len { + let remaining = len - i; + assert_eq!(it.size_hint(), (remaining, Some(remaining))); + + let prev = it.next_back().unwrap(); + assert_eq!(prev as *const _, v_ptrs[remaining-1]); + } + assert_eq!(it.size_hint(), (0, Some(0))); + assert_eq!(it.next_back(), None, "The final call to next_back() should return None"); + } + } + + fn test_mut(x : T) { + let v : &mut [T] = &mut [x, x, x]; + let v_ptrs : [*mut T; 3] = match v { + [ref v1, ref v2, ref v3] => + [v1 as *const _ as *mut _, v2 as *const _ as *mut _, v3 as *const _ as *mut _], + _ => unreachable!() + }; + let len = v.len(); + + // nth(i) + for i in 0..len { + assert_eq!(&mut v[i] as *mut _, v_ptrs[i]); // check the v_ptrs array, just to be sure + let nth = v.iter_mut().nth(i).unwrap(); + assert_eq!(nth as *mut _, v_ptrs[i]); + } + assert_eq!(v.iter().nth(len), None, "nth(len) should return None"); + + // stepping through with nth(0) + { + let mut it = v.iter(); + for i in 0..len { + let next = it.nth(0).unwrap(); + assert_eq!(next as *const _, v_ptrs[i]); + } + assert_eq!(it.nth(0), None); + } + + // next() + { + let mut it = v.iter_mut(); + for i in 0..len { + let remaining = len - i; + assert_eq!(it.size_hint(), (remaining, Some(remaining))); + + let next = it.next().unwrap(); + assert_eq!(next as *mut _, v_ptrs[i]); + } + assert_eq!(it.size_hint(), (0, Some(0))); + assert_eq!(it.next(), None, "The final call to next() should return None"); + } + + // next_back() + { + let mut it = v.iter_mut(); + for i in 0..len { + let remaining = len - i; + assert_eq!(it.size_hint(), (remaining, Some(remaining))); + + let prev = it.next_back().unwrap(); + assert_eq!(prev as *mut _, v_ptrs[remaining-1]); + } + assert_eq!(it.size_hint(), (0, Some(0))); + assert_eq!(it.next_back(), None, "The final call to next_back() should return None"); + } + } + + // Make sure iterators and slice patterns yield consistent addresses for various types, + // including ZSTs. + test(0u32); + test(()); + test([0u32; 0]); // ZST with alignment > 0 + test_mut(0u32); + test_mut(()); + test_mut([0u32; 0]); // ZST with alignment > 0 +} + +fn main() { + slice_of_zst(); + test_iter_ref_consistency(); +} diff --git a/tests/run-pass/vecs.rs b/tests/run-pass/vecs.rs index 776791bbc9b9e..bb9e5068f91e8 100644 --- a/tests/run-pass/vecs.rs +++ b/tests/run-pass/vecs.rs @@ -24,13 +24,45 @@ fn vec_into_iter() -> u8 { .fold(0, |x, y| x + y) } +fn vec_into_iter_rev() -> u8 { + vec![1, 2, 3, 4] + .into_iter() + .map(|x| x * x) + .fold(0, |x, y| x + y) +} + fn vec_into_iter_zst() -> usize { vec![[0u64; 0], [0u64; 0]] .into_iter() + .rev() + .map(|x| x.len()) + .sum() +} + +fn vec_into_iter_rev_zst() -> usize { + vec![[0u64; 0], [0u64; 0]] + .into_iter() + .rev() .map(|x| x.len()) .sum() } +fn vec_iter_and_mut() { + let mut v = vec![1,2,3,4]; + for i in v.iter_mut() { + *i += 1; + } + assert_eq!(v.iter().sum::(), 2+3+4+5); +} + +fn vec_iter_and_mut_rev() { + let mut v = vec![1,2,3,4]; + for i in v.iter_mut().rev() { + *i += 1; + } + assert_eq!(v.iter().sum::(), 2+3+4+5); +} + fn vec_reallocate() -> Vec { let mut v = vec![1, 2]; v.push(3); @@ -41,8 +73,14 @@ fn vec_reallocate() -> Vec { fn main() { assert_eq!(vec_reallocate().len(), 5); + assert_eq!(vec_into_iter(), 30); + assert_eq!(vec_into_iter_rev(), 30); + vec_iter_and_mut(); assert_eq!(vec_into_iter_zst(), 0); + assert_eq!(vec_into_iter_rev_zst(), 0); + vec_iter_and_mut_rev(); + assert_eq!(make_vec().capacity(), 4); assert_eq!(make_vec_macro(), [1, 2]); assert_eq!(make_vec_macro_repeat(), [42; 5]); From 478f137c39b827e6de39056b5c27a8e5d797aa4d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 30 Oct 2018 15:08:18 +0100 Subject: [PATCH 0326/3747] put all the logic into reactivatable() --- src/stacked_borrows.rs | 140 +++++++++++++++++++---------------------- 1 file changed, 63 insertions(+), 77 deletions(-) diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index baeb04b44ea75..dcb284b1bc3fd 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -142,74 +142,76 @@ pub struct Stacks { /// Core operations impl<'tcx> Stack { - /// Check if `bor` is currently active. We accept a `Raw` on a frozen location - /// because this could be a shared (re)borrow. If you want to mutate, this - /// is not the right function to call! - fn check(&self, bor: Borrow) -> bool { - match bor { - Borrow::Frz(acc_t) => - // Must be frozen at least as long as the `acc_t` says. - self.frozen_since.map_or(false, |loc_t| loc_t <= acc_t), - Borrow::Mut(acc_m) => - // Raw pointers are fine with frozen locations. This is important because &Cell is raw! - if self.frozen_since.is_some() { - acc_m.is_raw() - } else { - self.borrows.last().map_or(false, |&loc_itm| loc_itm == BorStackItem::Mut(acc_m)) - } - } - } - /// Check if `bor` could be activated by unfreezing and popping. - /// `force_mut` indicates whether being frozen is potentially acceptable. + /// `ref_kind` indicates whether this is being used to read/write (or, equivalently, to + /// borrow as &/&mut), or to borrow as raw. /// Returns `Err` if the answer is "no"; otherwise the data says /// what needs to happen to activate this: `None` = nothing, /// `Some(n)` = unfreeze and make item `n` the top item of the stack. - fn reactivatable(&self, bor: Borrow, force_mut: bool) -> Result, String> { - // Unless mutation is bound to happen, do NOT change anything if `bor` is already active. - // In particular, if it is a `Mut(Raw)` and we are frozen, this should be a NOP. - if !force_mut && self.check(bor) { - return Ok(None); - } - - let acc_m = match bor { + fn reactivatable(&self, bor: Borrow, ref_kind: RefKind) -> Result, String> { + let mut_borrow = match bor { Borrow::Frz(since) => - return Err(if force_mut { - format!("Using a shared borrow for mutation") - } else { - format!( - "Location should be frozen since {} but {}", - since, - match self.frozen_since { - None => format!("it is not frozen at all"), - Some(since) => format!("it is only frozen since {}", since), - } - ) - }), - Borrow::Mut(acc_m) => acc_m + // The only way to reactivate a `Frz` is if this is already frozen. + return match self.frozen_since { + _ if ref_kind == RefKind::Mut => + Err(format!("Using a shared borrow for mutation")), + None => + Err(format!("Location should be frozen but it is not")), + Some(loc) if loc <= since => + Ok(None), + Some(loc) => + Err(format!("Location should be frozen since {} but it is only frozen \ + since {}", since, loc)), + }, + Borrow::Mut(Mut::Raw) if self.is_frozen() && ref_kind != RefKind::Mut => + // Non-mutating access with a raw from a frozen location is a special case: The + // shared refs do not mind raw reads, and the raw itself does not assume any + // exclusivity. So we do not even require there to be a raw on the stack. + // This does not break the assumption that an `&mut` we own is + // exclusive for reads, because there we have the invariant that + // the location is *not* frozen. + return Ok(None), + Borrow::Mut(mut_borrow) => mut_borrow }; - // This is where we would unfreeze. + // See if we can get there via popping. for (idx, &itm) in self.borrows.iter().enumerate().rev() { match itm { BorStackItem::FnBarrier(_) => - return Err(format!("Trying to reactivate a mutable borrow ({:?}) that lives behind a barrier", acc_m)), - BorStackItem::Mut(loc_m) => { - if loc_m == acc_m { return Ok(Some(idx)); } + return Err(format!("Trying to reactivate a mutable borrow ({:?}) that lives \ + behind a barrier", mut_borrow)), + BorStackItem::Mut(loc) => { + if loc == mut_borrow { + // We found it! This is good to know. + // Yet, maybe we do not really want to pop? + if ref_kind == RefKind::Shr && self.is_frozen() { + // Whoever had exclusive access to this location allowed it + // to become frozen. That can only happen if they reborrowed + // to a shared ref, at which point they gave up on exclusive access. + // Hence we allow more reads, entirely ignoring everything above + // on the stack (but still making sure it is on the stack). + // This does not break the assumption that an `&mut` we own is + // exclusive for reads, because there we have the invariant that + // the location is *not* frozen. + return Ok(None); + } else { + return Ok(Some(idx)); + } + } } } } // Nothing to be found. - Err(format!("Mutable borrow-to-reactivate ({:?}) does not exist on the stack", acc_m)) + Err(format!("Mutable borrow-to-reactivate ({:?}) does not exist on the stack", mut_borrow)) } - /// Reactive `bor` for this stack. If `force_mut` is set, we want to aggressively - /// unfreeze this location (because we are about to mutate, so a frozen `Raw` is not okay). - fn reactivate(&mut self, bor: Borrow, force_mut: bool) -> EvalResult<'tcx> { - let action = match self.reactivatable(bor, force_mut) { + /// Reactive `bor` for this stack. `ref_kind` indicates whether this is being + /// used to read/write (or, equivalently, to borrow as &/&mut), or to borrow as raw. + fn reactivate(&mut self, bor: Borrow, ref_kind: RefKind) -> EvalResult<'tcx> { + let action = match self.reactivatable(bor, ref_kind) { Ok(action) => action, Err(err) => return err!(MachineError(err)), }; - + // Execute what `reactivatable` told us to do. match action { None => {}, // nothing to do Some(top) => { @@ -285,27 +287,7 @@ impl<'tcx> Stacks { ptr.tag, ref_kind, new_bor, ptr, size.bytes()); let mut stacks = self.stacks.borrow_mut(); for stack in stacks.iter_mut(ptr.offset, size) { - if ref_kind == RefKind::Shr && stack.is_frozen() { - // Location already frozen. We don't want to unfreeze, but make sure - // the ref makes some sense. - if let Err(err) = stack.reactivatable(ptr.tag, /*force_mut*/false) { - return err!(MachineError(err)); - } - } else { - // If we are creating a mutable ref, we certainly want to unfreeze. - // Even if we are doing so from a raw. - // Notice that if this is a local, whenever we access it directly the - // tag here will be the bottommost `Uniq` for that local. That `Uniq` - // never is accessible by the program, so it will not be used by any - // other access. IOW, whenever we directly use a local this will pop - // everything else off the stack, invalidating all previous pointers - // and, in particular, *all* raw pointers. This subsumes the explicit - // `reset` which the blog post [1] says to perform when accessing a local. - // - // [1] https://www.ralfj.de/blog/2018/08/07/stacked-borrows.html - let force_mut = ref_kind == RefKind::Mut; - stack.reactivate(ptr.tag, force_mut)?; - } + stack.reactivate(ptr.tag, ref_kind)?; if let Some(new_bor) = new_bor { stack.initiate(new_bor); } @@ -484,11 +466,8 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' let mut stacks = alloc.extra.stacks.borrow_mut(); // We need `iter_mut` because `iter` would skip gaps! for stack in stacks.iter_mut(ptr.offset, size) { - // We accept &mut to a frozen location here, that is just normal. There might - // be shared reborrows that we are about to invalidate with this access. - // We cannot invalidate them aggressively here because the deref might also be - // to just create more shared refs. - if let Err(err) = stack.reactivatable(ptr.tag, /*force_mut*/false) { + // Conservatively assume that we will only read. + if let Err(err) = stack.reactivatable(ptr.tag, RefKind::Shr) { return err!(MachineError(format!("Encountered {:?} reference with non-reactivatable tag: {}", ref_kind, err))) } } @@ -503,7 +482,14 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' ) -> Borrow { let mut_borrow = match kind { MemoryKind::Stack => { - // New unique borrow + // New unique borrow. This `Uniq` is not accessible by the program, + // so it will only ever be used when using the local directly (i.e., + // not through a pointer). IOW, whenever we directly use a local this will pop + // everything else off the stack, invalidating all previous pointers + // and, in particular, *all* raw pointers. This subsumes the explicit + // `reset` which the blog post [1] says to perform when accessing a local. + // + // [1] https://www.ralfj.de/blog/2018/08/07/stacked-borrows.html let time = self.machine.stacked_borrows.increment_clock(); Mut::Uniq(time) } From 81534496dc3356d5794300d513be200f939350c7 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 30 Oct 2018 16:46:28 +0100 Subject: [PATCH 0327/3747] rename RefKind to UsageKind, because it not only used for references now --- src/lib.rs | 2 +- src/stacked_borrows.rs | 118 ++++++++++-------- .../stacked_borrows/alias_through_mutation.rs | 2 +- .../stacked_borrows/buggy_as_mut_slice.rs | 2 +- .../stacked_borrows/buggy_split_at_mut.rs | 2 +- .../stacked_borrows/illegal_read1.rs | 2 +- .../stacked_borrows/illegal_read2.rs | 2 +- .../stacked_borrows/illegal_write1.rs | 2 +- .../stacked_borrows/illegal_write5.rs | 2 +- .../stacked_borrows/load_invalid_mut.rs | 2 +- .../stacked_borrows/load_invalid_shr.rs | 2 +- .../stacked_borrows/pass_invalid_mut.rs | 2 +- .../stacked_borrows/pass_invalid_shr.rs | 2 +- .../stacked_borrows/return_invalid_mut.rs | 2 +- .../stacked_borrows/return_invalid_shr.rs | 2 +- .../stacked_borrows/shared_confusion.rs | 2 +- .../stacked_borrows/shared_confusion_opt.rs | 2 +- 17 files changed, 84 insertions(+), 66 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index b397e9a6d224b..5a3e1c7cab054 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -48,7 +48,7 @@ use mono_hash_map::MonoHashMap; use stacked_borrows::{EvalContextExt as StackedBorEvalContextExt}; // Used by priroda -pub use stacked_borrows::{Borrow, Stacks, Mut as MutBorrow}; +pub use stacked_borrows::{Borrow, Stack, Stacks, Mut as MutBorrow, BorStackItem}; /// Insert rustc arguments at the beginning of the argument listthat miri wants to be /// set per default, for maximal validation power. diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index dcb284b1bc3fd..d520c6ff5d47b 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -64,6 +64,12 @@ impl Borrow { } } +impl Default for Borrow { + fn default() -> Self { + Borrow::Mut(Mut::Raw) + } +} + /// An item in the borrow stack #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] pub enum BorStackItem { @@ -74,26 +80,33 @@ pub enum BorStackItem { FnBarrier(usize) } -impl Default for Borrow { - fn default() -> Self { - Borrow::Mut(Mut::Raw) +impl BorStackItem { + #[inline(always)] + pub fn is_fn_barrier(self) -> bool { + match self { + BorStackItem::FnBarrier(_) => true, + _ => false, + } } } -/// What kind of reference are we talking about? +/// What kind of usage of the pointer are we talking about? #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] -pub enum RefKind { - Mut, - Shr, +pub enum UsageKind { + /// Write, or create &mut + Write, + /// Read, or create & + Read, + /// Create * Raw, } -impl From> for RefKind { +impl From> for UsageKind { fn from(mutbl: Option) -> Self { match mutbl { - None => RefKind::Raw, - Some(hir::MutMutable) => RefKind::Mut, - Some(hir::MutImmutable) => RefKind::Shr, + None => UsageKind::Raw, + Some(hir::MutMutable) => UsageKind::Write, + Some(hir::MutImmutable) => UsageKind::Read, } } } @@ -112,7 +125,7 @@ impl State { /// Extra per-location state #[derive(Clone, Debug)] -struct Stack { +pub struct Stack { borrows: Vec, // used as a stack frozen_since: Option, } @@ -143,17 +156,17 @@ pub struct Stacks { /// Core operations impl<'tcx> Stack { /// Check if `bor` could be activated by unfreezing and popping. - /// `ref_kind` indicates whether this is being used to read/write (or, equivalently, to + /// `usage` indicates whether this is being used to read/write (or, equivalently, to /// borrow as &/&mut), or to borrow as raw. /// Returns `Err` if the answer is "no"; otherwise the data says /// what needs to happen to activate this: `None` = nothing, /// `Some(n)` = unfreeze and make item `n` the top item of the stack. - fn reactivatable(&self, bor: Borrow, ref_kind: RefKind) -> Result, String> { + fn reactivatable(&self, bor: Borrow, usage: UsageKind) -> Result, String> { let mut_borrow = match bor { Borrow::Frz(since) => // The only way to reactivate a `Frz` is if this is already frozen. return match self.frozen_since { - _ if ref_kind == RefKind::Mut => + _ if usage == UsageKind::Write => Err(format!("Using a shared borrow for mutation")), None => Err(format!("Location should be frozen but it is not")), @@ -163,10 +176,11 @@ impl<'tcx> Stack { Err(format!("Location should be frozen since {} but it is only frozen \ since {}", since, loc)), }, - Borrow::Mut(Mut::Raw) if self.is_frozen() && ref_kind != RefKind::Mut => + Borrow::Mut(Mut::Raw) if self.is_frozen() && usage != UsageKind::Write => // Non-mutating access with a raw from a frozen location is a special case: The // shared refs do not mind raw reads, and the raw itself does not assume any - // exclusivity. So we do not even require there to be a raw on the stack. + // exclusivity. So we do not even require there to be a raw on the stack, + // the raw is instead "matched" by the fact that this location is frozen. // This does not break the assumption that an `&mut` we own is // exclusive for reads, because there we have the invariant that // the location is *not* frozen. @@ -183,7 +197,7 @@ impl<'tcx> Stack { if loc == mut_borrow { // We found it! This is good to know. // Yet, maybe we do not really want to pop? - if ref_kind == RefKind::Shr && self.is_frozen() { + if usage == UsageKind::Read && self.is_frozen() { // Whoever had exclusive access to this location allowed it // to become frozen. That can only happen if they reborrowed // to a shared ref, at which point they gave up on exclusive access. @@ -204,10 +218,10 @@ impl<'tcx> Stack { Err(format!("Mutable borrow-to-reactivate ({:?}) does not exist on the stack", mut_borrow)) } - /// Reactive `bor` for this stack. `ref_kind` indicates whether this is being + /// Reactive `bor` for this stack. `usage` indicates whether this is being /// used to read/write (or, equivalently, to borrow as &/&mut), or to borrow as raw. - fn reactivate(&mut self, bor: Borrow, ref_kind: RefKind) -> EvalResult<'tcx> { - let action = match self.reactivatable(bor, ref_kind) { + fn reactivate(&mut self, bor: Borrow, usage: UsageKind) -> EvalResult<'tcx> { + let action = match self.reactivatable(bor, usage) { Ok(action) => action, Err(err) => return err!(MachineError(err)), }; @@ -274,20 +288,20 @@ impl State { /// Higher-level operations impl<'tcx> Stacks { - /// The single most operation: Make sure that using `ptr` as `ref_kind` is okay, + /// The single most operation: Make sure that using `ptr` as `usage` is okay, /// and if `new_bor` is present then make that the new current borrow. fn use_and_maybe_re_borrow( &self, ptr: Pointer, size: Size, - ref_kind: RefKind, + usage: UsageKind, new_bor: Option, ) -> EvalResult<'tcx> { trace!("use_and_maybe_re_borrow of tag {:?} as {:?}, new {:?}: {:?}, size {}", - ptr.tag, ref_kind, new_bor, ptr, size.bytes()); + ptr.tag, usage, new_bor, ptr, size.bytes()); let mut stacks = self.stacks.borrow_mut(); for stack in stacks.iter_mut(ptr.offset, size) { - stack.reactivate(ptr.tag, ref_kind)?; + stack.reactivate(ptr.tag, usage)?; if let Some(new_bor) = new_bor { stack.initiate(new_bor); } @@ -303,7 +317,7 @@ impl<'tcx> Stacks { size: Size, ) -> EvalResult<'tcx> { // Reads behave exactly like the first half of a reborrow-to-shr - self.use_and_maybe_re_borrow(ptr, size, RefKind::Shr, None) + self.use_and_maybe_re_borrow(ptr, size, UsageKind::Read, None) } #[inline(always)] @@ -313,7 +327,7 @@ impl<'tcx> Stacks { size: Size, ) -> EvalResult<'tcx> { // Writes behave exactly like the first half of a reborrow-to-mut - self.use_and_maybe_re_borrow(ptr, size, RefKind::Mut, None) + self.use_and_maybe_re_borrow(ptr, size, UsageKind::Write, None) } pub fn memory_deallocated( @@ -322,7 +336,7 @@ impl<'tcx> Stacks { size: Size, ) -> EvalResult<'tcx> { // This is like mutating - self.use_and_maybe_re_borrow(ptr, size, RefKind::Mut, None) + self.use_and_maybe_re_borrow(ptr, size, UsageKind::Write, None) // FIXME: Error out of there are any barriers? } @@ -346,7 +360,7 @@ pub trait EvalContextExt<'tcx> { ptr: Pointer, pointee_ty: Ty<'tcx>, size: Size, - ref_kind: RefKind, + usage: UsageKind, ) -> EvalResult<'tcx, Borrow>; @@ -355,7 +369,7 @@ pub trait EvalContextExt<'tcx> { ptr: Pointer, pointee_ty: Ty<'tcx>, size: Size, - ref_kind: RefKind, + usage: UsageKind, ) -> EvalResult<'tcx, Borrow>; fn tag_new_allocation( @@ -378,12 +392,12 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' ptr: Pointer, pointee_ty: Ty<'tcx>, size: Size, - ref_kind: RefKind, + usage: UsageKind, ) -> EvalResult<'tcx, Borrow> { let time = self.machine.stacked_borrows.increment_clock(); - let new_bor = match ref_kind { - RefKind::Mut => Borrow::Mut(Mut::Uniq(time)), - RefKind::Shr => + let new_bor = match usage { + UsageKind::Write => Borrow::Mut(Mut::Uniq(time)), + UsageKind::Read => // FIXME This does not do enough checking when only part of the data has // interior mutability. When the type is `(i32, Cell)`, we want the // first field to be frozen but not the second. @@ -393,10 +407,10 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' // Shared reference with interior mutability. Borrow::Mut(Mut::Raw) }, - RefKind::Raw => Borrow::Mut(Mut::Raw), + UsageKind::Raw => Borrow::Mut(Mut::Raw), }; trace!("tag_reference: Creating new reference ({:?}) for {:?} (pointee {}, size {}): {:?}", - ref_kind, ptr, pointee_ty, size.bytes(), new_bor); + usage, ptr, pointee_ty, size.bytes(), new_bor); // Make sure this reference is not dangling or so self.memory().check_bounds(ptr, size, false)?; @@ -404,7 +418,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' // Update the stacks. We cannot use `get_mut` becuse this might be immutable // memory. let alloc = self.memory().get(ptr.alloc_id).expect("We checked that the ptr is fine!"); - alloc.extra.use_and_maybe_re_borrow(ptr, size, ref_kind, Some(new_bor))?; + alloc.extra.use_and_maybe_re_borrow(ptr, size, usage, Some(new_bor))?; Ok(new_bor) } @@ -418,39 +432,39 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' ptr: Pointer, pointee_ty: Ty<'tcx>, size: Size, - ref_kind: RefKind, + usage: UsageKind, ) -> EvalResult<'tcx, Borrow> { trace!("tag_reference: Accessing reference ({:?}) for {:?} (pointee {}, size {})", - ref_kind, ptr, pointee_ty, size.bytes()); + usage, ptr, pointee_ty, size.bytes()); // In principle we should not have to do anything here. However, with transmutes involved, - // it can happen that the tag of `ptr` does not actually match `ref_kind`, and we + // it can happen that the tag of `ptr` does not actually match `usage`, and we // should adjust for that. // Notably, the compiler can introduce such transmutes by optimizing away `&[mut]*`. // That can transmute a raw ptr to a (shared/mut) ref, and a mut ref to a shared one. - match (ref_kind, ptr.tag) { - (RefKind::Raw, _) => { + match (usage, ptr.tag) { + (UsageKind::Raw, _) => { // Don't use the tag, this is a raw access! Even if there is a tag, // that means transmute happened and we ignore the tag. // Also don't do any further validation, this is raw after all. return Ok(Borrow::Mut(Mut::Raw)); } - (RefKind::Mut, Borrow::Mut(Mut::Uniq(_))) | - (RefKind::Shr, Borrow::Frz(_)) | - (RefKind::Shr, Borrow::Mut(Mut::Raw)) => { + (UsageKind::Write, Borrow::Mut(Mut::Uniq(_))) | + (UsageKind::Read, Borrow::Frz(_)) | + (UsageKind::Read, Borrow::Mut(Mut::Raw)) => { // Expected combinations. Nothing to do. // FIXME: We probably shouldn't accept this if we got a raw shr without // interior mutability. } - (RefKind::Mut, Borrow::Mut(Mut::Raw)) => { + (UsageKind::Write, Borrow::Mut(Mut::Raw)) => { // Raw transmuted to mut ref. Keep this as raw access. // We cannot reborrow here; there might be a raw in `&(*var).1` where // `var` is an `&mut`. The other field of the struct might be already frozen, // also using `var`, and that would be okay. } - (RefKind::Shr, Borrow::Mut(Mut::Uniq(_))) => { + (UsageKind::Read, Borrow::Mut(Mut::Uniq(_))) => { // A mut got transmuted to shr. The mut borrow must be reactivatable. } - (RefKind::Mut, Borrow::Frz(_)) => { + (UsageKind::Write, Borrow::Frz(_)) => { // This is just invalid. // If we ever allow this, we have to consider what we do when a turn a // `Raw`-tagged `&mut` into a raw pointer pointing to a frozen location. @@ -467,8 +481,12 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' // We need `iter_mut` because `iter` would skip gaps! for stack in stacks.iter_mut(ptr.offset, size) { // Conservatively assume that we will only read. - if let Err(err) = stack.reactivatable(ptr.tag, RefKind::Shr) { - return err!(MachineError(format!("Encountered {:?} reference with non-reactivatable tag: {}", ref_kind, err))) + if let Err(err) = stack.reactivatable(ptr.tag, UsageKind::Read) { + return err!(MachineError(format!( + "Encountered {} reference with non-reactivatable tag: {}", + if usage == UsageKind::Write { "mutable" } else { "shared" }, + err + ))) } } // All is good. diff --git a/tests/compile-fail/stacked_borrows/alias_through_mutation.rs b/tests/compile-fail/stacked_borrows/alias_through_mutation.rs index eb8966f3a5c71..0b2d459366ceb 100644 --- a/tests/compile-fail/stacked_borrows/alias_through_mutation.rs +++ b/tests/compile-fail/stacked_borrows/alias_through_mutation.rs @@ -11,5 +11,5 @@ fn main() { retarget(&mut target_alias, target); // now `target_alias` points to the same thing as `target` *target = 13; - let _val = *target_alias; //~ ERROR Shr reference with non-reactivatable tag + let _val = *target_alias; //~ ERROR reference with non-reactivatable tag } diff --git a/tests/compile-fail/stacked_borrows/buggy_as_mut_slice.rs b/tests/compile-fail/stacked_borrows/buggy_as_mut_slice.rs index e86eb9ba6de80..2c48404ddf364 100644 --- a/tests/compile-fail/stacked_borrows/buggy_as_mut_slice.rs +++ b/tests/compile-fail/stacked_borrows/buggy_as_mut_slice.rs @@ -14,6 +14,6 @@ fn main() { let v = vec![0,1,2]; let v1 = safe::as_mut_slice(&v); let v2 = safe::as_mut_slice(&v); - v1[1] = 5; //~ ERROR Mut reference with non-reactivatable tag + v1[1] = 5; //~ ERROR reference with non-reactivatable tag v1[1] = 6; } diff --git a/tests/compile-fail/stacked_borrows/buggy_split_at_mut.rs b/tests/compile-fail/stacked_borrows/buggy_split_at_mut.rs index a4f5f536b770d..d8a241cab5d49 100644 --- a/tests/compile-fail/stacked_borrows/buggy_split_at_mut.rs +++ b/tests/compile-fail/stacked_borrows/buggy_split_at_mut.rs @@ -11,7 +11,7 @@ mod safe { assert!(mid <= len); (from_raw_parts_mut(ptr, len - mid), // BUG: should be "mid" instead of "len - mid" - //~^ ERROR Mut reference with non-reactivatable tag + //~^ ERROR reference with non-reactivatable tag from_raw_parts_mut(ptr.offset(mid as isize), len - mid)) } } diff --git a/tests/compile-fail/stacked_borrows/illegal_read1.rs b/tests/compile-fail/stacked_borrows/illegal_read1.rs index f0e696c457cb3..59190a15db440 100644 --- a/tests/compile-fail/stacked_borrows/illegal_read1.rs +++ b/tests/compile-fail/stacked_borrows/illegal_read1.rs @@ -7,7 +7,7 @@ fn main() { let xref = unsafe { &mut *xraw }; // derived from raw, so using raw is still okay... callee(xraw); let _val = *xref; // ...but any use of raw will invalidate our ref. - //~^ ERROR: Mut reference with non-reactivatable tag + //~^ ERROR: mutable reference with non-reactivatable tag } fn callee(xraw: *mut i32) { diff --git a/tests/compile-fail/stacked_borrows/illegal_read2.rs b/tests/compile-fail/stacked_borrows/illegal_read2.rs index ec59c57d31b72..594117d28ab84 100644 --- a/tests/compile-fail/stacked_borrows/illegal_read2.rs +++ b/tests/compile-fail/stacked_borrows/illegal_read2.rs @@ -7,7 +7,7 @@ fn main() { let xref = unsafe { &mut *xraw }; // derived from raw, so using raw is still okay... callee(xraw); let _val = *xref; // ...but any use of raw will invalidate our ref. - //~^ ERROR: Mut reference with non-reactivatable tag + //~^ ERROR: mutable reference with non-reactivatable tag } fn callee(xraw: *mut i32) { diff --git a/tests/compile-fail/stacked_borrows/illegal_write1.rs b/tests/compile-fail/stacked_borrows/illegal_write1.rs index 131e89572a501..ab951be5ec911 100644 --- a/tests/compile-fail/stacked_borrows/illegal_write1.rs +++ b/tests/compile-fail/stacked_borrows/illegal_write1.rs @@ -8,5 +8,5 @@ fn main() { let target = Box::new(42); // has an implicit raw let ref_ = &*target; evil(ref_); // invalidates shared ref, activates raw - let _x = *ref_; //~ ERROR Shr reference with non-reactivatable tag + let _x = *ref_; //~ ERROR reference with non-reactivatable tag } diff --git a/tests/compile-fail/stacked_borrows/illegal_write5.rs b/tests/compile-fail/stacked_borrows/illegal_write5.rs index 4b5d08c03a479..f4704ad57161f 100644 --- a/tests/compile-fail/stacked_borrows/illegal_write5.rs +++ b/tests/compile-fail/stacked_borrows/illegal_write5.rs @@ -7,7 +7,7 @@ fn main() { let xref = unsafe { &mut *xraw }; // derived from raw, so using raw is still okay... callee(xraw); let _val = *xref; // ...but any use of raw will invalidate our ref. - //~^ ERROR: Mut reference with non-reactivatable tag + //~^ ERROR: reference with non-reactivatable tag } fn callee(xraw: *mut i32) { diff --git a/tests/compile-fail/stacked_borrows/load_invalid_mut.rs b/tests/compile-fail/stacked_borrows/load_invalid_mut.rs index 060cec962c477..4ea61cd606fff 100644 --- a/tests/compile-fail/stacked_borrows/load_invalid_mut.rs +++ b/tests/compile-fail/stacked_borrows/load_invalid_mut.rs @@ -5,5 +5,5 @@ fn main() { let xref = unsafe { &mut *xraw }; let xref_in_mem = Box::new(xref); let _val = *x; // invalidate xraw - let _val = *xref_in_mem; //~ ERROR Mut reference with non-reactivatable tag + let _val = *xref_in_mem; //~ ERROR mutable reference with non-reactivatable tag } diff --git a/tests/compile-fail/stacked_borrows/load_invalid_shr.rs b/tests/compile-fail/stacked_borrows/load_invalid_shr.rs index b4b180e350f1f..53179c954dea2 100644 --- a/tests/compile-fail/stacked_borrows/load_invalid_shr.rs +++ b/tests/compile-fail/stacked_borrows/load_invalid_shr.rs @@ -5,5 +5,5 @@ fn main() { let xref = unsafe { &*xraw }; let xref_in_mem = Box::new(xref); *x = 42; // invalidate xraw - let _val = *xref_in_mem; //~ ERROR Shr reference with non-reactivatable tag: Location should be frozen + let _val = *xref_in_mem; //~ ERROR shared reference with non-reactivatable tag: Location should be frozen } diff --git a/tests/compile-fail/stacked_borrows/pass_invalid_mut.rs b/tests/compile-fail/stacked_borrows/pass_invalid_mut.rs index bc950771add4f..5e1118160a327 100644 --- a/tests/compile-fail/stacked_borrows/pass_invalid_mut.rs +++ b/tests/compile-fail/stacked_borrows/pass_invalid_mut.rs @@ -6,5 +6,5 @@ fn main() { let xraw = x as *mut _; let xref = unsafe { &mut *xraw }; let _val = *x; // invalidate xraw - foo(xref); //~ ERROR Mut reference with non-reactivatable tag + foo(xref); //~ ERROR mutable reference with non-reactivatable tag } diff --git a/tests/compile-fail/stacked_borrows/pass_invalid_shr.rs b/tests/compile-fail/stacked_borrows/pass_invalid_shr.rs index 477c86f6060d6..e4b26cfff6da4 100644 --- a/tests/compile-fail/stacked_borrows/pass_invalid_shr.rs +++ b/tests/compile-fail/stacked_borrows/pass_invalid_shr.rs @@ -6,5 +6,5 @@ fn main() { let xraw = &*x as *const _; let xref = unsafe { &*xraw }; *x = 42; // invalidate xraw - foo(xref); //~ ERROR Shr reference with non-reactivatable tag: Location should be frozen + foo(xref); //~ ERROR shared reference with non-reactivatable tag: Location should be frozen } diff --git a/tests/compile-fail/stacked_borrows/return_invalid_mut.rs b/tests/compile-fail/stacked_borrows/return_invalid_mut.rs index c02892671e907..949b3829ff8fe 100644 --- a/tests/compile-fail/stacked_borrows/return_invalid_mut.rs +++ b/tests/compile-fail/stacked_borrows/return_invalid_mut.rs @@ -3,7 +3,7 @@ fn foo(x: &mut (i32, i32)) -> &mut i32 { let xraw = x as *mut (i32, i32); let ret = unsafe { &mut (*xraw).1 }; let _val = *x; // invalidate xraw and its children - ret //~ ERROR Mut reference with non-reactivatable tag + ret //~ ERROR mutable reference with non-reactivatable tag } fn main() { diff --git a/tests/compile-fail/stacked_borrows/return_invalid_shr.rs b/tests/compile-fail/stacked_borrows/return_invalid_shr.rs index 954b5ec8e5920..2d34350359d13 100644 --- a/tests/compile-fail/stacked_borrows/return_invalid_shr.rs +++ b/tests/compile-fail/stacked_borrows/return_invalid_shr.rs @@ -3,7 +3,7 @@ fn foo(x: &mut (i32, i32)) -> &i32 { let xraw = x as *mut (i32, i32); let ret = unsafe { &(*xraw).1 }; x.1 = 42; // invalidate xraw on the 2nd field - ret //~ ERROR Shr reference with non-reactivatable tag: Location should be frozen + ret //~ ERROR shared reference with non-reactivatable tag: Location should be frozen } fn main() { diff --git a/tests/compile-fail/stacked_borrows/shared_confusion.rs b/tests/compile-fail/stacked_borrows/shared_confusion.rs index c02822ed4d3da..624587932cb83 100644 --- a/tests/compile-fail/stacked_borrows/shared_confusion.rs +++ b/tests/compile-fail/stacked_borrows/shared_confusion.rs @@ -21,7 +21,7 @@ fn test(r: &mut RefCell) { } // Our old raw should be dead by now unsafe { *x_evil = 0; } // this falls back to some Raw higher up the stack - *x_inner = 12; //~ ERROR Mut reference with non-reactivatable tag + *x_inner = 12; //~ ERROR reference with non-reactivatable tag } fn main() { diff --git a/tests/compile-fail/stacked_borrows/shared_confusion_opt.rs b/tests/compile-fail/stacked_borrows/shared_confusion_opt.rs index 4a88d4d64133d..3030f5dd4001b 100644 --- a/tests/compile-fail/stacked_borrows/shared_confusion_opt.rs +++ b/tests/compile-fail/stacked_borrows/shared_confusion_opt.rs @@ -17,7 +17,7 @@ fn test(r: &mut RefCell) { } // Our old raw should be dead by now unsafe { *x_evil = 0; } // this falls back to some Raw higher up the stack - *x_inner = 12; //~ ERROR Mut reference with non-reactivatable tag + *x_inner = 12; //~ ERROR reference with non-reactivatable tag } fn main() { From a68779fd16a851fbdb0e25297044da7f5a410845 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 1 Nov 2018 08:55:03 +0100 Subject: [PATCH 0328/3747] use crate:: import to make edition port easier later --- src/lib.rs | 2 +- src/stacked_borrows.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 5a3e1c7cab054..82ffb5e454d5f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -48,7 +48,7 @@ use mono_hash_map::MonoHashMap; use stacked_borrows::{EvalContextExt as StackedBorEvalContextExt}; // Used by priroda -pub use stacked_borrows::{Borrow, Stack, Stacks, Mut as MutBorrow, BorStackItem}; +pub use crate::stacked_borrows::{Borrow, Stack, Stacks, Mut as MutBorrow, BorStackItem}; /// Insert rustc arguments at the beginning of the argument listthat miri wants to be /// set per default, for maximal validation power. diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index d520c6ff5d47b..4d78519be61d5 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -3,7 +3,7 @@ use std::cell::RefCell; use rustc::ty::{self, Ty, layout::Size}; use rustc::hir; -use super::{ +use crate::{ MemoryKind, MiriMemoryKind, RangeMap, EvalResult, AllocId, Pointer, PlaceTy, }; From e9f79f5f6f73d933d3cabbda9ae8058d54bb9f9a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 3 Nov 2018 09:11:37 +0100 Subject: [PATCH 0329/3747] bump Rust version --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index d025ddacf0092..6b277cc26bc90 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -nightly-2018-10-30 +nightly-2018-11-03 From 5f42aa61d578c8bb2f41ea6e5baf29565d8ee32a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 3 Nov 2018 10:23:41 +0100 Subject: [PATCH 0330/3747] illegal_write2 does not work with optimizations --- tests/compile-fail/stacked_borrows/illegal_write2.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/compile-fail/stacked_borrows/illegal_write2.rs b/tests/compile-fail/stacked_borrows/illegal_write2.rs index f4fefaad5e22d..b53655c82147e 100644 --- a/tests/compile-fail/stacked_borrows/illegal_write2.rs +++ b/tests/compile-fail/stacked_borrows/illegal_write2.rs @@ -1,3 +1,7 @@ +// We fail to detect this when neither this nor libstd are optimized/have retagging. +// FIXME: Investigate that. +// compile-flags: -Zmir-opt-level=0 + #![allow(unused_variables)] fn main() { From 8da2c9e34e836e12bfa9912c5df4e62afc21b634 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 3 Nov 2018 11:03:53 +0100 Subject: [PATCH 0331/3747] fix adding default arguments --- src/bin/cargo-miri.rs | 2 +- src/bin/miri-rustc-tests.rs | 3 +-- src/bin/miri.rs | 4 ++-- src/lib.rs | 9 ++------- 4 files changed, 6 insertions(+), 12 deletions(-) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 20fb0fa353199..69c4f122544a5 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -173,6 +173,7 @@ fn main() { .chain(Some(sys_root)) .collect() }; + args.splice(0..0, miri::miri_default_args().iter().map(ToString::to_string)); // this check ensures that dependencies are built but not interpreted and the final crate is // interpreted but not built @@ -186,7 +187,6 @@ fn main() { Command::new("rustc") }; - miri::add_miri_default_args(&mut args); args.extend_from_slice(&["--cfg".to_owned(), r#"feature="cargo-miri""#.to_owned()]); match command.args(&args).status() { diff --git a/src/bin/miri-rustc-tests.rs b/src/bin/miri-rustc-tests.rs index d14d7a2e4bd1f..6fa9b817ffee7 100644 --- a/src/bin/miri-rustc-tests.rs +++ b/src/bin/miri-rustc-tests.rs @@ -156,6 +156,7 @@ fn main() { true } }).collect(); + args.splice(1..1, miri::miri_default_args().iter().map(ToString::to_string)); // file to process args.push(path.display().to_string()); @@ -165,8 +166,6 @@ fn main() { args.push(Path::new(&std::env::var("HOME").unwrap()).join(".xargo").join("HOST").display().to_string()); } - miri::add_miri_default_args(&mut args); - // A threadsafe buffer for writing. #[derive(Default, Clone)] struct BufWriter(Arc>>); diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 686f685b831ca..1bbf3c8c4a4a8 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -232,8 +232,8 @@ fn main() { args.push(sysroot_flag); args.push(find_sysroot()); } - // Finally, add the default flags all the way in the beginning. - miri::add_miri_default_args(&mut args); + // Finally, add the default flags all the way in the beginning, but after the binary name. + args.splice(1..1, miri::miri_default_args().iter().map(ToString::to_string)); trace!("rustc arguments: {:?}", args); let result = rustc_driver::run(move || { diff --git a/src/lib.rs b/src/lib.rs index 88a2689ba9dca..6445dca1e80a1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -52,16 +52,11 @@ pub use crate::stacked_borrows::{Borrow, Stack, Stacks, Mut as MutBorrow, BorSta /// Insert rustc arguments at the beginning of the argument listthat miri wants to be /// set per default, for maximal validation power. -pub fn add_miri_default_args(args: &mut Vec) { +pub fn miri_default_args() -> &'static [&'static str] { // The flags here should be kept in sync with what bootstrap adds when `test-miri` is // set, which happens in `bootstrap/bin/rustc.rs` in the rustc sources; and also // kept in sync with `xargo/build.sh` in this repo and `appveyor.yml`. - - // Inserting at index 1, after the binary name - args.splice(1..1, - ["-Zalways-encode-mir", "-Zmir-emit-retag", "-Zmir-opt-level=0"] - .iter().map(|s| s.to_string()) - ); + &["-Zalways-encode-mir", "-Zmir-emit-retag", "-Zmir-opt-level=0"] } // Used by priroda From 8ac5d988e237570e24208a05f65bf0b06137d101 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oliver=20S=CC=B6c=CC=B6h=CC=B6n=CC=B6e=CC=B6i=CC=B6d=CC=B6?= =?UTF-8?q?e=CC=B6r=20Scherer?= Date: Sat, 3 Nov 2018 11:39:50 +0100 Subject: [PATCH 0332/3747] typo Co-Authored-By: RalfJung --- src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 6445dca1e80a1..a2271a5898b7f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -50,7 +50,7 @@ use crate::stacked_borrows::{EvalContextExt as StackedBorEvalContextExt}; // Used by priroda pub use crate::stacked_borrows::{Borrow, Stack, Stacks, Mut as MutBorrow, BorStackItem}; -/// Insert rustc arguments at the beginning of the argument listthat miri wants to be +/// Insert rustc arguments at the beginning of the argument list that miri wants to be /// set per default, for maximal validation power. pub fn miri_default_args() -> &'static [&'static str] { // The flags here should be kept in sync with what bootstrap adds when `test-miri` is From cb691b7ed9f0b6c37828d85126b2aaed4c2b57af Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 3 Nov 2018 11:42:38 +0100 Subject: [PATCH 0333/3747] comment on mut-to-shr transmutes --- src/stacked_borrows.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 4d78519be61d5..afc76fa375bc3 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -462,7 +462,8 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' // also using `var`, and that would be okay. } (UsageKind::Read, Borrow::Mut(Mut::Uniq(_))) => { - // A mut got transmuted to shr. The mut borrow must be reactivatable. + // A mut got transmuted to shr. Can happen even from compiler transformations: + // `&*x` gets optimized to `x` even when `x` is a `&mut`. } (UsageKind::Write, Borrow::Frz(_)) => { // This is just invalid. From e68687b8402720001a25bc45677b747690aefd3a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 3 Nov 2018 12:07:16 +0100 Subject: [PATCH 0334/3747] test that we check the layout constraints as early as we can --- tests/compile-fail/nonzero.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 tests/compile-fail/nonzero.rs diff --git a/tests/compile-fail/nonzero.rs b/tests/compile-fail/nonzero.rs new file mode 100644 index 0000000000000..d1de0f8095e34 --- /dev/null +++ b/tests/compile-fail/nonzero.rs @@ -0,0 +1,11 @@ +#![feature(rustc_attrs)] +#![allow(unused_attributes)] + +#[rustc_layout_scalar_valid_range_start(1)] +#[repr(transparent)] +pub(crate) struct NonZero(pub(crate) T); + +fn main() { + // Make sure that we detect this even when no function call is happening along the way + let _x = Some(NonZero(0)); //~ ERROR encountered 0, but expected something greater or equal to 1 +} From efd2f0e0e49d19f322b28f49291bb60b972b8f65 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 3 Nov 2018 12:33:14 +0100 Subject: [PATCH 0335/3747] move new test to correct dir --- tests/compile-fail/{ => validity}/nonzero.rs | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename tests/compile-fail/{ => validity}/nonzero.rs (100%) diff --git a/tests/compile-fail/nonzero.rs b/tests/compile-fail/validity/nonzero.rs similarity index 100% rename from tests/compile-fail/nonzero.rs rename to tests/compile-fail/validity/nonzero.rs From a8af5ae139b61a6a2b2b04718e0943476259c7ec Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 4 Nov 2018 10:21:22 +0100 Subject: [PATCH 0336/3747] fix for latest nightly --- rust-version | 2 +- src/lib.rs | 2 +- xargo/Xargo.toml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/rust-version b/rust-version index 6b277cc26bc90..f5e9fdb9f6af1 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -nightly-2018-11-03 +nightly-2018-11-04 diff --git a/src/lib.rs b/src/lib.rs index a2271a5898b7f..2fdd27b842e43 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -89,7 +89,7 @@ pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( if libstd_has_mir { let start_id = tcx.lang_items().start_fn().unwrap(); let main_ret_ty = tcx.fn_sig(main_id).output(); - let main_ret_ty = main_ret_ty.no_late_bound_regions().unwrap(); + let main_ret_ty = main_ret_ty.no_bound_vars().unwrap(); let start_instance = ty::Instance::resolve( ecx.tcx.tcx, ty::ParamEnv::reveal_all(), diff --git a/xargo/Xargo.toml b/xargo/Xargo.toml index c022837a5e61c..e49b0dbe743b4 100644 --- a/xargo/Xargo.toml +++ b/xargo/Xargo.toml @@ -1,5 +1,5 @@ [dependencies.std] -features = ["panic_unwind", "jemalloc", "backtrace"] +features = ["panic_unwind", "backtrace"] [dependencies.test] stage = 1 From 9edac3189a12772c5dde55c52c8eb5a8292d1274 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 5 Nov 2018 08:51:55 +0100 Subject: [PATCH 0337/3747] rustup --- rust-version | 2 +- src/fn_call.rs | 50 +++++++++++++-------------- src/intrinsic.rs | 78 +++++++++++++++++++++--------------------- src/stacked_borrows.rs | 4 +-- src/tls.rs | 12 +++---- 5 files changed, 73 insertions(+), 73 deletions(-) diff --git a/rust-version b/rust-version index f5e9fdb9f6af1..734df301d8e0e 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -nightly-2018-11-04 +nightly-2018-11-05 diff --git a/src/fn_call.rs b/src/fn_call.rs index 7e1ff3233f21e..d9bf049df704a 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -120,7 +120,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo match &link_name[..] { "malloc" => { - let size = self.read_scalar(args[0])?.to_usize(&self)?; + let size = self.read_scalar(args[0])?.to_usize(self)?; if size == 0 { self.write_null(dest)?; } else { @@ -132,7 +132,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo "free" => { let ptr = self.read_scalar(args[0])?.not_undef()?.erase_tag(); // raw ptr operation, no tag - if !ptr.is_null_ptr(&self) { + if !ptr.is_null_ptr(self) { self.memory_mut().deallocate( ptr.to_ptr()?.with_default_tag(), None, @@ -142,8 +142,8 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo } "__rust_alloc" => { - let size = self.read_scalar(args[0])?.to_usize(&self)?; - let align = self.read_scalar(args[1])?.to_usize(&self)?; + let size = self.read_scalar(args[0])?.to_usize(self)?; + let align = self.read_scalar(args[1])?.to_usize(self)?; if size == 0 { return err!(HeapAllocZeroBytes); } @@ -160,8 +160,8 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo self.write_scalar(Scalar::Ptr(ptr), dest)?; } "__rust_alloc_zeroed" => { - let size = self.read_scalar(args[0])?.to_usize(&self)?; - let align = self.read_scalar(args[1])?.to_usize(&self)?; + let size = self.read_scalar(args[0])?.to_usize(self)?; + let align = self.read_scalar(args[1])?.to_usize(self)?; if size == 0 { return err!(HeapAllocZeroBytes); } @@ -180,8 +180,8 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo } "__rust_dealloc" => { let ptr = self.read_scalar(args[0])?.to_ptr()?.erase_tag(); // raw ptr operation, no tag - let old_size = self.read_scalar(args[1])?.to_usize(&self)?; - let align = self.read_scalar(args[2])?.to_usize(&self)?; + let old_size = self.read_scalar(args[1])?.to_usize(self)?; + let align = self.read_scalar(args[2])?.to_usize(self)?; if old_size == 0 { return err!(HeapAllocZeroBytes); } @@ -196,9 +196,9 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo } "__rust_realloc" => { let ptr = self.read_scalar(args[0])?.to_ptr()?.erase_tag(); // raw ptr operation, no tag - let old_size = self.read_scalar(args[1])?.to_usize(&self)?; - let align = self.read_scalar(args[2])?.to_usize(&self)?; - let new_size = self.read_scalar(args[3])?.to_usize(&self)?; + let old_size = self.read_scalar(args[1])?.to_usize(self)?; + let align = self.read_scalar(args[2])?.to_usize(self)?; + let new_size = self.read_scalar(args[3])?.to_usize(self)?; if old_size == 0 || new_size == 0 { return err!(HeapAllocZeroBytes); } @@ -222,7 +222,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo // // libc::syscall(NR_GETRANDOM, buf.as_mut_ptr(), buf.len(), GRND_NONBLOCK) // is called if a `HashMap` is created the regular way. - match self.read_scalar(args[0])?.to_usize(&self)? { + match self.read_scalar(args[0])?.to_usize(self)? { 318 | 511 => { return err!(Unimplemented( "miri does not support random number generators".to_owned(), @@ -260,7 +260,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo // 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. let mir = self.load_mir(f_instance.def)?; - let ret_place = MPlaceTy::dangling(self.layout_of(self.tcx.mk_unit())?, &self).into(); + let ret_place = MPlaceTy::dangling(self.layout_of(self.tcx.mk_unit())?, self).into(); self.push_stack_frame( f_instance, mir.span, @@ -294,7 +294,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo "memcmp" => { let left = self.read_scalar(args[0])?.not_undef()?.erase_tag(); // raw ptr operation let right = self.read_scalar(args[1])?.not_undef()?.erase_tag(); // raw ptr operation - let n = Size::from_bytes(self.read_scalar(args[2])?.to_usize(&self)?); + let n = Size::from_bytes(self.read_scalar(args[2])?.to_usize(self)?); let result = { let left_bytes = self.memory().read_bytes(left.with_default_tag(), n)?; @@ -318,11 +318,11 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo let ptr = self.read_scalar(args[0])?.not_undef()?.erase_tag(); // raw ptr operation let ptr = ptr.with_default_tag(); let val = self.read_scalar(args[1])?.to_bytes()? as u8; - let num = self.read_scalar(args[2])?.to_usize(&self)?; + let num = self.read_scalar(args[2])?.to_usize(self)?; if let Some(idx) = self.memory().read_bytes(ptr, Size::from_bytes(num))? .iter().rev().position(|&c| c == val) { - let new_ptr = ptr.ptr_offset(Size::from_bytes(num - idx as u64 - 1), &self)?; + let new_ptr = ptr.ptr_offset(Size::from_bytes(num - idx as u64 - 1), self)?; self.write_scalar(new_ptr, dest)?; } else { self.write_null(dest)?; @@ -333,12 +333,12 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo let ptr = self.read_scalar(args[0])?.not_undef()?.erase_tag(); // raw ptr operation let ptr = ptr.with_default_tag(); let val = self.read_scalar(args[1])?.to_bytes()? as u8; - let num = self.read_scalar(args[2])?.to_usize(&self)?; + let num = self.read_scalar(args[2])?.to_usize(self)?; if let Some(idx) = self.memory().read_bytes(ptr, Size::from_bytes(num))?.iter().position( |&c| c == val, ) { - let new_ptr = ptr.ptr_offset(Size::from_bytes(idx as u64), &self)?; + let new_ptr = ptr.ptr_offset(Size::from_bytes(idx as u64), self)?; self.write_scalar(new_ptr, dest)?; } else { self.write_null(dest)?; @@ -351,7 +351,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo let name = self.memory().read_c_str(name_ptr.with_default_tag())?; match self.machine.env_vars.get(name) { Some(&var) => Scalar::Ptr(var), - None => Scalar::ptr_null(*self.tcx), + None => Scalar::ptr_null(&*self.tcx), } }; self.write_scalar(result, dest)?; @@ -361,7 +361,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo let mut success = None; { let name_ptr = self.read_scalar(args[0])?.not_undef()?.erase_tag(); // raw ptr operation - if !name_ptr.is_null_ptr(&self) { + if !name_ptr.is_null_ptr(self) { let name = self.memory().read_c_str(name_ptr.to_ptr()? .with_default_tag())?.to_owned(); if !name.is_empty() && !name.contains(&b'=') { @@ -385,7 +385,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo let name_ptr = self.read_scalar(args[0])?.not_undef()?.erase_tag(); // raw ptr operation let value_ptr = self.read_scalar(args[1])?.to_ptr()?.erase_tag(); // raw ptr operation let value = self.memory().read_c_str(value_ptr.with_default_tag())?; - if !name_ptr.is_null_ptr(&self) { + if !name_ptr.is_null_ptr(self) { let name = self.memory().read_c_str(name_ptr.to_ptr()?.with_default_tag())?; if !name.is_empty() && !name.contains(&b'=') { new = Some((name.to_owned(), value.to_owned())); @@ -400,7 +400,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo MiriMemoryKind::Env.into(), )?.with_default_tag(); self.memory_mut().write_bytes(value_copy.into(), &value)?; - let trailing_zero_ptr = value_copy.offset(Size::from_bytes(value.len() as u64), &self)?.into(); + let trailing_zero_ptr = value_copy.offset(Size::from_bytes(value.len() as u64), self)?.into(); self.memory_mut().write_bytes(trailing_zero_ptr, &[0])?; if let Some(var) = self.machine.env_vars.insert( name.to_owned(), @@ -510,7 +510,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo let key_layout = self.layout_of(key_type)?; // Create key and write it into the memory where key_ptr wants it - let key = self.machine.tls.create_tls_key(dtor, *self.tcx) as u128; + let key = self.machine.tls.create_tls_key(dtor, &*self.tcx) as u128; if key_layout.size.bits() < 128 && key >= (1u128 << key_layout.size.bits() as u128) { return err!(OutOfTls); } @@ -555,7 +555,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo } "pthread_attr_getstack" => { // second argument is where we are supposed to write the stack size - let ptr = self.ref_to_mplace(self.read_value(args[1])?)?; + let ptr = self.ref_to_mplace(self.read_immediate(args[1])?)?; let stackaddr = Scalar::from_int(0x80000, args[1].layout.size); // just any address self.write_scalar(stackaddr, ptr.into())?; // return 0 @@ -613,7 +613,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo // This just creates a key; Windows does not natively support TLS dtors. // Create key and return it - let key = self.machine.tls.create_tls_key(None, *self.tcx) as u128; + let key = self.machine.tls.create_tls_key(None, &*self.tcx) 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) { diff --git a/src/intrinsic.rs b/src/intrinsic.rs index caf5687b231cb..9aad6f95f316a 100644 --- a/src/intrinsic.rs +++ b/src/intrinsic.rs @@ -5,7 +5,7 @@ use rustc::ty; use rustc::mir::interpret::{EvalResult, PointerArithmetic}; use crate::{ - PlaceTy, OpTy, Value, Scalar, ScalarMaybeUndef, Borrow, + PlaceTy, OpTy, Immediate, Scalar, ScalarMaybeUndef, Borrow, ScalarExt, OperatorEvalContextExt }; @@ -38,13 +38,13 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' let intrinsic_name = &self.tcx.item_name(instance.def_id()).as_str()[..]; match intrinsic_name { "arith_offset" => { - let offset = self.read_scalar(args[1])?.to_isize(&self)?; + let offset = self.read_scalar(args[1])?.to_isize(self)?; let ptr = self.read_scalar(args[0])?.not_undef()?; let pointee_ty = substs.type_at(0); let pointee_size = self.layout_of(pointee_ty)?.size.bytes() as i64; let offset = offset.overflowing_mul(pointee_size).0; - let result_ptr = ptr.ptr_wrapping_signed_offset(offset, &self); + let result_ptr = ptr.ptr_wrapping_signed_offset(offset, self); self.write_scalar(result_ptr, dest)?; } @@ -59,7 +59,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' "atomic_load_relaxed" | "atomic_load_acq" | "volatile_load" => { - let ptr = self.ref_to_mplace(self.read_value(args[0])?)?; + let ptr = self.ref_to_mplace(self.read_immediate(args[0])?)?; let val = self.read_scalar(ptr.into())?; // make sure it fits into a scalar; otherwise it cannot be atomic self.write_scalar(val, dest)?; } @@ -68,7 +68,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' "atomic_store_relaxed" | "atomic_store_rel" | "volatile_store" => { - let ptr = self.ref_to_mplace(self.read_value(args[0])?)?; + let ptr = self.ref_to_mplace(self.read_immediate(args[0])?)?; let val = self.read_scalar(args[1])?; // make sure it fits into a scalar; otherwise it cannot be atomic self.write_scalar(val, ptr.into())?; } @@ -78,7 +78,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' } _ if intrinsic_name.starts_with("atomic_xchg") => { - let ptr = self.ref_to_mplace(self.read_value(args[0])?)?; + let ptr = self.ref_to_mplace(self.read_immediate(args[0])?)?; let new = self.read_scalar(args[1])?; let old = self.read_scalar(ptr.into())?; self.write_scalar(old, dest)?; // old value is returned @@ -86,14 +86,14 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' } _ if intrinsic_name.starts_with("atomic_cxchg") => { - let ptr = self.ref_to_mplace(self.read_value(args[0])?)?; - let expect_old = self.read_value(args[1])?; // read as value for the sake of `binary_op_val()` + let ptr = self.ref_to_mplace(self.read_immediate(args[0])?)?; + let expect_old = self.read_immediate(args[1])?; // read as value for the sake of `binary_op_val()` let new = self.read_scalar(args[2])?; - let old = self.read_value(ptr.into())?; // read as value for the sake of `binary_op_val()` + let old = self.read_immediate(ptr.into())?; // read as value for the sake of `binary_op_val()` // binary_op_val will bail if either of them is not a scalar let (eq, _) = self.binary_op_val(mir::BinOp::Eq, old, expect_old)?; - let res = Value::ScalarPair(old.to_scalar_or_undef(), eq.into()); - self.write_value(res, dest)?; // old value is returned + let res = Immediate::ScalarPair(old.to_scalar_or_undef(), eq.into()); + self.write_immediate(res, dest)?; // old value is returned // update ptr depending on comparison if eq.to_bool()? { self.write_scalar(new, ptr.into())?; @@ -125,13 +125,13 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' "atomic_xsub_rel" | "atomic_xsub_acqrel" | "atomic_xsub_relaxed" => { - let ptr = self.ref_to_mplace(self.read_value(args[0])?)?; + let ptr = self.ref_to_mplace(self.read_immediate(args[0])?)?; if !ptr.layout.ty.is_integral() { return err!(Unimplemented(format!("Atomic arithmetic operations only work on integer types"))); } - let rhs = self.read_value(args[1])?; - let old = self.read_value(ptr.into())?; - self.write_value(*old, dest)?; // old value is returned + let rhs = self.read_immediate(args[1])?; + let old = self.read_immediate(ptr.into())?; + self.write_immediate(*old, dest)?; // old value is returned let op = match intrinsic_name.split('_').nth(1).unwrap() { "or" => mir::BinOp::BitOr, "xor" => mir::BinOp::BitXor, @@ -151,7 +151,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' let elem_ty = substs.type_at(0); let elem_layout = self.layout_of(elem_ty)?; let elem_size = elem_layout.size.bytes(); - let count = self.read_scalar(args[2])?.to_usize(&self)?; + let count = self.read_scalar(args[2])?.to_usize(self)?; let elem_align = elem_layout.align; // erase tags: this is a raw ptr operation let src = self.read_scalar(args[0])?.not_undef()?.erase_tag(); @@ -167,7 +167,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' } "discriminant_value" => { - let place = self.ref_to_mplace(self.read_value(args[0])?)?; + let place = self.ref_to_mplace(self.read_immediate(args[0])?)?; let discr_val = self.read_discriminant(place.into())?.0; self.write_scalar(Scalar::from_uint(discr_val, dest.layout.size), dest)?; } @@ -215,8 +215,8 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' } "fadd_fast" | "fsub_fast" | "fmul_fast" | "fdiv_fast" | "frem_fast" => { - let a = self.read_value(args[0])?; - let b = self.read_value(args[1])?; + let a = self.read_immediate(args[0])?; + let b = self.read_immediate(args[1])?; let op = match intrinsic_name { "fadd_fast" => mir::BinOp::Add, "fsub_fast" => mir::BinOp::Sub, @@ -231,8 +231,8 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' "exact_div" => { // Performs an exact division, resulting in undefined behavior where // `x % y != 0` or `y == 0` or `x == T::min_value() && y == -1` - let a = self.read_value(args[0])?; - let b = self.read_value(args[1])?; + let a = self.read_immediate(args[0])?; + let b = self.read_immediate(args[1])?; // check x % y != 0 if self.binary_op_val(mir::BinOp::Rem, a, b)?.0.to_bytes()? != 0 { return err!(ValidationFailure(format!("exact_div: {:?} cannot be divided by {:?}", a, b))); @@ -251,13 +251,13 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' if !dest.layout.is_zst() { // nothing to do for ZST match dest.layout.abi { layout::Abi::Scalar(ref s) => { - let x = Scalar::from_int(0, s.value.size(&self)); - self.write_value(Value::Scalar(x.into()), dest)?; + let x = Scalar::from_int(0, s.value.size(self)); + self.write_immediate(Immediate::Scalar(x.into()), dest)?; } layout::Abi::ScalarPair(ref s1, ref s2) => { - let x = Scalar::from_int(0, s1.value.size(&self)); - let y = Scalar::from_int(0, s2.value.size(&self)); - self.write_value(Value::ScalarPair(x.into(), y.into()), dest)?; + let x = Scalar::from_int(0, s1.value.size(self)); + let y = Scalar::from_int(0, s2.value.size(self)); + self.write_immediate(Immediate::ScalarPair(x.into(), y.into()), dest)?; } _ => { // Do it in memory @@ -279,12 +279,12 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' } "move_val_init" => { - let ptr = self.ref_to_mplace(self.read_value(args[0])?)?; + let ptr = self.ref_to_mplace(self.read_immediate(args[0])?)?; self.copy_op(args[1], ptr.into())?; } "offset" => { - let offset = self.read_scalar(args[1])?.to_isize(&self)?; + let offset = self.read_scalar(args[1])?.to_isize(self)?; let ptr = self.read_scalar(args[0])?.not_undef()?; let result_ptr = self.pointer_offset_inbounds(ptr, substs.type_at(0), offset)?; self.write_scalar(result_ptr, dest)?; @@ -347,7 +347,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' } "size_of_val" => { - let mplace = self.ref_to_mplace(self.read_value(args[0])?)?; + let mplace = self.ref_to_mplace(self.read_immediate(args[0])?)?; let (size, _) = self.size_and_align_of_mplace(mplace)? .expect("size_of_val called on extern type"); let ptr_size = self.pointer_size(); @@ -359,7 +359,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' "min_align_of_val" | "align_of_val" => { - let mplace = self.ref_to_mplace(self.read_value(args[0])?)?; + let mplace = self.ref_to_mplace(self.read_immediate(args[0])?)?; let (_, align) = self.size_and_align_of_mplace(mplace)? .expect("size_of_val called on extern type"); let ptr_size = self.pointer_size(); @@ -372,13 +372,13 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' "type_name" => { let ty = substs.type_at(0); let ty_name = ty.to_string(); - let value = self.str_to_value(&ty_name)?; - self.write_value(value, dest)?; + let value = self.str_to_immediate(&ty_name)?; + self.write_immediate(value, dest)?; } "unchecked_div" => { - let l = self.read_value(args[0])?; - let r = self.read_value(args[1])?; + let l = self.read_immediate(args[0])?; + let r = self.read_immediate(args[1])?; let rval = r.to_scalar()?.to_bytes()?; if rval == 0 { return err!(Intrinsic(format!("Division by 0 in unchecked_div"))); @@ -392,8 +392,8 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' } "unchecked_rem" => { - let l = self.read_value(args[0])?; - let r = self.read_value(args[1])?; + let l = self.read_immediate(args[0])?; + let r = self.read_immediate(args[1])?; let rval = r.to_scalar()?.to_bytes()?; if rval == 0 { return err!(Intrinsic(format!("Division by 0 in unchecked_rem"))); @@ -416,11 +416,11 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' match dest.layout.abi { layout::Abi::Scalar(..) => { let x = ScalarMaybeUndef::Undef; - self.write_value(Value::Scalar(x), dest)?; + self.write_immediate(Immediate::Scalar(x), dest)?; } layout::Abi::ScalarPair(..) => { let x = ScalarMaybeUndef::Undef; - self.write_value(Value::ScalarPair(x, x), dest)?; + self.write_immediate(Immediate::ScalarPair(x, x), dest)?; } _ => { // Do it in memory @@ -437,7 +437,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' let ty_layout = self.layout_of(ty)?; let val_byte = self.read_scalar(args[1])?.to_u8()?; let ptr = self.read_scalar(args[0])?.not_undef()?.erase_tag().with_default_tag(); - let count = self.read_scalar(args[2])?.to_usize(&self)?; + let count = self.read_scalar(args[2])?.to_usize(self)?; self.memory().check_align(ptr, ty_layout.align)?; self.memory_mut().write_repeat(ptr, val_byte, ty_layout.size * count)?; } diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index afc76fa375bc3..6d3abbcc31521 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -539,12 +539,12 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' // above. First deref, which will call `tag_dereference`. // (This is somewhat redundant because validation already did the same thing, // but what can you do.) - let val = self.read_value(self.place_to_op(place)?)?; + let val = self.read_immediate(self.place_to_op(place)?)?; let dest = self.ref_to_mplace(val)?; // Now put a new ref into the old place, which will call `tag_reference`. // FIXME: Honor `fn_entry`! let val = self.create_ref(dest, Some(mutbl))?; - self.write_value(val, place)?; + self.write_immediate(val, place)?; Ok(()) } } diff --git a/src/tls.rs b/src/tls.rs index 001da10ddc216..1aacc67f5ccae 100644 --- a/src/tls.rs +++ b/src/tls.rs @@ -42,7 +42,7 @@ impl<'tcx> TlsData<'tcx> { pub fn create_tls_key( &mut self, dtor: Option>, - cx: impl HasDataLayout, + cx: &impl HasDataLayout, ) -> TlsKey { let new_key = self.next_key; self.next_key += 1; @@ -109,7 +109,7 @@ impl<'tcx> TlsData<'tcx> { fn fetch_tls_dtor( &mut self, key: Option, - cx: impl HasDataLayout, + cx: &impl HasDataLayout, ) -> Option<(ty::Instance<'tcx>, Scalar, TlsKey)> { use std::collections::Bound::*; @@ -135,14 +135,14 @@ impl<'tcx> TlsData<'tcx> { impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, 'tcx> { fn run_tls_dtors(&mut self) -> EvalResult<'tcx> { - let mut dtor = self.machine.tls.fetch_tls_dtor(None, *self.tcx); + let mut dtor = self.machine.tls.fetch_tls_dtor(None, &*self.tcx); // FIXME: replace loop by some structure that works with stepping while let Some((instance, ptr, key)) = dtor { trace!("Running TLS dtor {:?} on {:?}", instance, ptr); // TODO: Potentially, this has to support all the other possible instances? // See eval_fn_call in interpret/terminator/mod.rs let mir = self.load_mir(instance.def)?; - let ret_place = MPlaceTy::dangling(self.layout_of(self.tcx.mk_unit())?, &self).into(); + let ret_place = MPlaceTy::dangling(self.layout_of(self.tcx.mk_unit())?, self).into(); self.push_stack_frame( instance, mir.span, @@ -159,9 +159,9 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for super::MiriEvalContext< // step until out of stackframes self.run()?; - dtor = match self.machine.tls.fetch_tls_dtor(Some(key), *self.tcx) { + dtor = match self.machine.tls.fetch_tls_dtor(Some(key), &*self.tcx) { dtor @ Some(_) => dtor, - None => self.machine.tls.fetch_tls_dtor(None, *self.tcx), + None => self.machine.tls.fetch_tls_dtor(None, &*self.tcx), }; } // FIXME: On a windows target, call `unsafe extern "system" fn on_tls_callback`. From f6d6470bc4e332eadaba27d9c494f79aafd75a66 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 5 Nov 2018 15:45:24 +0100 Subject: [PATCH 0338/3747] move to 2018 edition I want NLL :D --- Cargo.toml | 1 + src/bin/miri-rustc-tests.rs | 2 +- src/bin/miri.rs | 2 +- src/lib.rs | 4 ++-- 4 files changed, 5 insertions(+), 4 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index dcf93fa14104f..390efe0a073a1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,6 +9,7 @@ repository = "https://github.com/solson/miri" version = "0.1.0" build = "build.rs" default-run = "miri" +edition = "2018" [lib] test = true # we have unit tests diff --git a/src/bin/miri-rustc-tests.rs b/src/bin/miri-rustc-tests.rs index 6fa9b817ffee7..c9ec1011ddbb9 100644 --- a/src/bin/miri-rustc-tests.rs +++ b/src/bin/miri-rustc-tests.rs @@ -1,4 +1,4 @@ -#![feature(rustc_private)] +#![feature(rustc_private, extern_crate_item_prelude)] extern crate miri; extern crate getopts; extern crate rustc; diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 1bbf3c8c4a4a8..bfe631b51f0fd 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -1,4 +1,4 @@ -#![feature(rustc_private)] +#![feature(rustc_private, extern_crate_item_prelude)] extern crate getopts; extern crate miri; diff --git a/src/lib.rs b/src/lib.rs index 2fdd27b842e43..b4b7a310ca9d9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,4 @@ -#![feature(rustc_private)] +#![feature(rustc_private, extern_crate_item_prelude)] #![cfg_attr(feature = "cargo-clippy", allow(cast_lossless))] @@ -253,7 +253,7 @@ impl Into> for MiriMemoryKind { impl MayLeak for MiriMemoryKind { #[inline(always)] fn may_leak(self) -> bool { - use MiriMemoryKind::*; + use self::MiriMemoryKind::*; match self { Rust | C => false, Env | MutStatic => true, From 2ff1f24f2b95604b43518f334c445b9a5ab47c21 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 7 Nov 2018 10:11:16 +0100 Subject: [PATCH 0339/3747] bump rust --- rust-version | 2 +- src/intrinsic.rs | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/rust-version b/rust-version index 734df301d8e0e..48887947cdf79 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -nightly-2018-11-05 +nightly-2018-11-07 diff --git a/src/intrinsic.rs b/src/intrinsic.rs index 9aad6f95f316a..20402f4a23293 100644 --- a/src/intrinsic.rs +++ b/src/intrinsic.rs @@ -87,11 +87,11 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' _ if intrinsic_name.starts_with("atomic_cxchg") => { let ptr = self.ref_to_mplace(self.read_immediate(args[0])?)?; - let expect_old = self.read_immediate(args[1])?; // read as value for the sake of `binary_op_val()` + let expect_old = self.read_immediate(args[1])?; // read as value for the sake of `binary_op_imm()` let new = self.read_scalar(args[2])?; - let old = self.read_immediate(ptr.into())?; // read as value for the sake of `binary_op_val()` - // binary_op_val will bail if either of them is not a scalar - let (eq, _) = self.binary_op_val(mir::BinOp::Eq, old, expect_old)?; + let old = self.read_immediate(ptr.into())?; // read as value for the sake of `binary_op_imm()` + // binary_op_imm will bail if either of them is not a scalar + let (eq, _) = self.binary_op_imm(mir::BinOp::Eq, old, expect_old)?; let res = Immediate::ScalarPair(old.to_scalar_or_undef(), eq.into()); self.write_immediate(res, dest)?; // old value is returned // update ptr depending on comparison @@ -234,7 +234,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' let a = self.read_immediate(args[0])?; let b = self.read_immediate(args[1])?; // check x % y != 0 - if self.binary_op_val(mir::BinOp::Rem, a, b)?.0.to_bytes()? != 0 { + if self.binary_op_imm(mir::BinOp::Rem, a, b)?.0.to_bytes()? != 0 { return err!(ValidationFailure(format!("exact_div: {:?} cannot be divided by {:?}", a, b))); } self.binop_ignore_overflow(mir::BinOp::Div, a, b, dest)?; From a05ba90300743f4035a5b8df0d65b916e2c7f11d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 7 Nov 2018 14:24:11 +0100 Subject: [PATCH 0340/3747] disable Rc test for now, it ain't working --- tests/run-pass/rc.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/run-pass/rc.rs b/tests/run-pass/rc.rs index 4d89066035ceb..f4a8855bea2f2 100644 --- a/tests/run-pass/rc.rs +++ b/tests/run-pass/rc.rs @@ -1,5 +1,5 @@ -// FIXME: Validation disabled due to https://github.com/rust-lang/rust/issues/54908 -// compile-flags: -Zmiri-disable-validation +// FIXME: Disabled due to https://github.com/rust-lang/rust/issues/55747 +// ignore-test use std::cell::RefCell; use std::rc::Rc; From 74635a57e2c0d8791a49170bb8c06042a9b3a62e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 5 Nov 2018 16:05:17 +0100 Subject: [PATCH 0341/3747] re-do large parts of stacked borrows, now with proper support for partiall frozen data --- cargo-miri-test/run-test.py | 3 +- src/helpers.rs | 131 +++++ src/lib.rs | 36 +- src/stacked_borrows.rs | 482 +++++++++--------- src/tls.rs | 2 +- .../stacked_borrows/buggy_as_mut_slice.rs | 2 +- .../stacked_borrows/buggy_split_at_mut.rs | 2 +- .../stacked_borrows/illegal_read1.rs | 2 +- .../stacked_borrows/illegal_read2.rs | 2 +- .../stacked_borrows/illegal_write1.rs | 2 +- .../stacked_borrows/illegal_write3.rs | 4 +- .../stacked_borrows/illegal_write4.rs | 2 +- .../stacked_borrows/load_invalid_mut.rs | 2 +- .../stacked_borrows/load_invalid_shr.rs | 2 +- .../stacked_borrows/pass_invalid_mut.rs | 2 +- .../stacked_borrows/pass_invalid_shr.rs | 2 +- .../stacked_borrows/return_invalid_mut.rs | 2 +- .../stacked_borrows/return_invalid_shr.rs | 2 +- .../stacked_borrows/shared_confusion.rs | 29 -- .../stacked_borrows/shared_confusion_opt.rs | 25 - .../validity/invalid_enum_discriminant.rs | 2 +- .../validity/transmute_through_ptr.rs | 2 +- .../send-is-not-static-par-for.rs | 3 - tests/run-pass-fullmir/u128.rs | 3 - tests/run-pass-fullmir/vecdeque.rs | 3 - tests/run-pass/slices.rs | 3 - tests/run-pass/stacked-borrows.rs | 17 +- 27 files changed, 434 insertions(+), 335 deletions(-) delete mode 100644 tests/compile-fail/stacked_borrows/shared_confusion.rs delete mode 100644 tests/compile-fail/stacked_borrows/shared_confusion_opt.rs diff --git a/cargo-miri-test/run-test.py b/cargo-miri-test/run-test.py index 506de85ffcb2c..f686cc47449dd 100755 --- a/cargo-miri-test/run-test.py +++ b/cargo-miri-test/run-test.py @@ -10,9 +10,8 @@ def test_cargo_miri(): print("==> Testing `cargo miri` <==") ## Call `cargo miri`, capture all output - # FIXME: Disabling validation, still investigating whether there is UB here p = subprocess.Popen( - ["cargo", "miri", "-q", "--", "-Zmiri-disable-validation"], + ["cargo", "miri", "-q"], stdout=subprocess.PIPE, stderr=subprocess.PIPE ) diff --git a/src/helpers.rs b/src/helpers.rs index 6dc5b768ea63f..52d3db8ac46fd 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -32,6 +32,15 @@ impl ScalarExt for ScalarMaybeUndef { pub trait EvalContextExt<'tcx> { fn resolve_path(&self, path: &[&str]) -> EvalResult<'tcx, ty::Instance<'tcx>>; + + /// Visit the memory covered by `place` that is frozen -- i.e., NOT + /// what is inside an `UnsafeCell`. + fn visit_frozen( + &self, + place: MPlaceTy<'tcx, Borrow>, + size: Size, + action: impl FnMut(Pointer, Size) -> EvalResult<'tcx>, + ) -> EvalResult<'tcx>; } @@ -69,4 +78,126 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: EvalErrorKind::PathNotFound(path).into() }) } + + /// Visit the memory covered by `place` that is frozen -- i.e., NOT + /// what is inside an `UnsafeCell`. + fn visit_frozen( + &self, + place: MPlaceTy<'tcx, Borrow>, + size: Size, + mut frozen_action: impl FnMut(Pointer, Size) -> EvalResult<'tcx>, + ) -> EvalResult<'tcx> { + trace!("visit_frozen(place={:?}, size={:?})", *place, size); + debug_assert_eq!(size, + self.size_and_align_of_mplace(place)? + .map(|(size, _)| size) + .unwrap_or_else(|| place.layout.size) + ); + // Store how far we proceeded into the place so far. Everything to the left of + // this offset has already been handled, in the sense that the frozen parts + // have had `action` called on them. + let mut end_ptr = place.ptr; + // Called when we detected an `UnsafeCell` at the given offset and size. + // Calls `action` and advances `end_ptr`. + let mut unsafe_cell_action = |unsafe_cell_offset, unsafe_cell_size| { + // We assume that we are given the fields in increasing offset order, + // and nothing else changes. + let end_offset = end_ptr.get_ptr_offset(self); + assert!(unsafe_cell_offset >= end_offset); + let frozen_size = unsafe_cell_offset - end_offset; + // Everything between the end_ptr and this `UnsafeCell` is frozen. + if frozen_size != Size::ZERO { + frozen_action(end_ptr.to_ptr()?, frozen_size)?; + } + // Update end end_ptr. + end_ptr = end_ptr.ptr_wrapping_offset(frozen_size+unsafe_cell_size, self); + // Done + Ok(()) + }; + // Run a visitor + { + let mut visitor = UnsafeCellVisitor { + ecx: self, + unsafe_cell_action: |place| { + trace!("unsafe_cell_action on {:?}", place.ptr); + // We need a size to go on. + let (unsafe_cell_size, _) = self.size_and_align_of_mplace(place)? + // for extern types, just cover what we can + .unwrap_or_else(|| place.layout.size_and_align()); + // Now handle this `UnsafeCell`. + unsafe_cell_action(place.ptr.get_ptr_offset(self), unsafe_cell_size) + }, + }; + visitor.visit_value(place)?; + } + // The part between the end_ptr and the end of the place is also frozen. + // So pretend there is a 0-sized `UnsafeCell` at the end. + unsafe_cell_action(place.ptr.get_ptr_offset(self) + size, Size::ZERO)?; + // Done! + return Ok(()); + + /// Visiting the memory covered by a `MemPlace`, being aware of + /// whether we are inside an `UnsafeCell` or not. + struct UnsafeCellVisitor<'ecx, 'a, 'mir, 'tcx, F> + where F: FnMut(MPlaceTy<'tcx, Borrow>) -> EvalResult<'tcx> + { + ecx: &'ecx MiriEvalContext<'a, 'mir, 'tcx>, + unsafe_cell_action: F, + } + + impl<'ecx, 'a, 'mir, 'tcx, F> ValueVisitor<'a, 'mir, 'tcx, Evaluator<'tcx>> + for UnsafeCellVisitor<'ecx, 'a, 'mir, 'tcx, F> + where + F: FnMut(MPlaceTy<'tcx, Borrow>) -> EvalResult<'tcx> + { + type V = MPlaceTy<'tcx, Borrow>; + + const WANT_FIELDS_SORTED: bool = true; // sorted? yes please! + + #[inline(always)] + fn ecx(&self) -> &MiriEvalContext<'a, 'mir, 'tcx> { + &self.ecx + } + + // Hook to detect `UnsafeCell` + fn visit_value(&mut self, v: MPlaceTy<'tcx, Borrow>) -> EvalResult<'tcx> + { + trace!("UnsafeCellVisitor: {:?} {:?}", *v, v.layout.ty); + let is_unsafe_cell = match v.layout.ty.sty { + ty::Adt(adt, _) => Some(adt.did) == self.ecx.tcx.lang_items().unsafe_cell_type(), + _ => false, + }; + if is_unsafe_cell { + // We do not have to recurse further, this is an `UnsafeCell`. + (self.unsafe_cell_action)(v) + } else if self.ecx.type_is_freeze(v.layout.ty) { + // This is `Freeze`, there cannot be an `UnsafeCell` + Ok(()) + } else { + // Proceed further + self.walk_value(v) + } + } + + // We have to do *something* for unions + fn visit_union(&mut self, v: MPlaceTy<'tcx, Borrow>) -> EvalResult<'tcx> + { + // With unions, we fall back to whatever the type says, to hopefully be consistent + // with LLVM IR. + // FIXME Are we consistent? And is this really the behavior we want? + let frozen = self.ecx.type_is_freeze(v.layout.ty); + if frozen { + Ok(()) + } else { + (self.unsafe_cell_action)(v) + } + } + + // We should never get to a primitive, but always short-circuit somewhere above + fn visit_primitive(&mut self, _val: ImmTy<'tcx, Borrow>) -> EvalResult<'tcx> + { + bug!("We should always short-circit before coming to a primitive") + } + } + } } diff --git a/src/lib.rs b/src/lib.rs index b4b7a310ca9d9..134986c814de0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -17,7 +17,7 @@ use std::collections::HashMap; use std::borrow::Cow; use std::env; -use rustc::ty::{self, Ty, TyCtxt, query::TyCtxtAt}; +use rustc::ty::{self, TyCtxt, query::TyCtxtAt}; use rustc::ty::layout::{TyLayout, LayoutOf, Size}; use rustc::hir::{self, def_id::DefId}; use rustc::mir; @@ -48,7 +48,7 @@ use crate::mono_hash_map::MonoHashMap; use crate::stacked_borrows::{EvalContextExt as StackedBorEvalContextExt}; // Used by priroda -pub use crate::stacked_borrows::{Borrow, Stack, Stacks, Mut as MutBorrow, BorStackItem}; +pub use crate::stacked_borrows::{Borrow, Stack, Stacks, BorStackItem}; /// Insert rustc arguments at the beginning of the argument list that miri wants to be /// set per default, for maximal validation power. @@ -476,38 +476,38 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { #[inline(always)] fn tag_reference( ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, - place: MemPlace, - ty: Ty<'tcx>, - size: Size, + place: MPlaceTy<'tcx, Borrow>, mutability: Option, - ) -> EvalResult<'tcx, MemPlace> { + ) -> EvalResult<'tcx, Scalar> { + let (size, _) = ecx.size_and_align_of_mplace(place)? + // for extern types, just cover what we can + .unwrap_or_else(|| place.layout.size_and_align()); if !ecx.machine.validate || size == Size::ZERO { // No tracking - Ok(place) + Ok(place.ptr) } else { let ptr = place.ptr.to_ptr()?; - let tag = ecx.tag_reference(ptr, ty, size, mutability.into())?; - let ptr = Scalar::Ptr(Pointer::new_with_tag(ptr.alloc_id, ptr.offset, tag)); - Ok(MemPlace { ptr, ..place }) + let tag = ecx.tag_reference(place, size, mutability.into())?; + Ok(Scalar::Ptr(Pointer::new_with_tag(ptr.alloc_id, ptr.offset, tag))) } } #[inline(always)] fn tag_dereference( ecx: &EvalContext<'a, 'mir, 'tcx, Self>, - place: MemPlace, - ty: Ty<'tcx>, - size: Size, + place: MPlaceTy<'tcx, Borrow>, mutability: Option, - ) -> EvalResult<'tcx, MemPlace> { + ) -> EvalResult<'tcx, Scalar> { + let (size, _) = ecx.size_and_align_of_mplace(place)? + // for extern types, just cover what we can + .unwrap_or_else(|| place.layout.size_and_align()); if !ecx.machine.validate || size == Size::ZERO { // No tracking - Ok(place) + Ok(place.ptr) } else { let ptr = place.ptr.to_ptr()?; - let tag = ecx.tag_dereference(ptr, ty, size, mutability.into())?; - let ptr = Scalar::Ptr(Pointer::new_with_tag(ptr.alloc_id, ptr.offset, tag)); - Ok(MemPlace { ptr, ..place }) + let tag = ecx.tag_dereference(place, size, mutability.into())?; + Ok(Scalar::Ptr(Pointer::new_with_tag(ptr.alloc_id, ptr.offset, tag))) } } diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 6d3abbcc31521..1ab6edcf398c4 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -1,64 +1,43 @@ use std::cell::RefCell; -use rustc::ty::{self, Ty, layout::Size}; +use rustc::ty::{self, layout::Size}; use rustc::hir; use crate::{ - MemoryKind, MiriMemoryKind, RangeMap, EvalResult, AllocId, - Pointer, PlaceTy, + EvalResult, MiriEvalContext, HelpersEvalContextExt, + MemoryKind, MiriMemoryKind, RangeMap, AllocId, + Pointer, PlaceTy, MPlaceTy, }; pub type Timestamp = u64; -/// Information about a potentially mutable borrow -#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] -pub enum Mut { - /// A unique, mutable reference - Uniq(Timestamp), - /// Any raw pointer, or a shared borrow with interior mutability - Raw, -} - -impl Mut { - #[inline(always)] - pub fn is_raw(self) -> bool { - match self { - Mut::Raw => true, - _ => false, - } - } - - #[inline(always)] - pub fn is_uniq(self) -> bool { - match self { - Mut::Uniq(_) => true, - _ => false, - } - } -} - -/// Information about any kind of borrow +/// Information about which kind of borrow was used to create the reference this is tagged +/// with. #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] pub enum Borrow { - /// A mutable borrow, a raw pointer, or a shared borrow with interior mutability - Mut(Mut), - /// A shared borrow without interior mutability - Frz(Timestamp) + /// A unique (mutable) reference. + Uniq(Timestamp), + /// A shared reference. This is also used by raw pointers, which do not track details + /// of how or when they were created, hence the timestamp is optional. + /// Shr(Some(_)) does NOT mean that the destination of this reference is frozen; + /// that depends on the type! Only those parts outside of an `UnsafeCell` are actually + /// frozen. + Shr(Option), } impl Borrow { #[inline(always)] - pub fn is_uniq(self) -> bool { + pub fn is_shr(self) -> bool { match self { - Borrow::Mut(m) => m.is_uniq(), + Borrow::Shr(_) => true, _ => false, } } #[inline(always)] - pub fn is_frz(self) -> bool { + pub fn is_uniq(self) -> bool { match self { - Borrow::Frz(_) => true, + Borrow::Uniq(_) => true, _ => false, } } @@ -66,15 +45,19 @@ impl Borrow { impl Default for Borrow { fn default() -> Self { - Borrow::Mut(Mut::Raw) + Borrow::Shr(None) } } -/// An item in the borrow stack +/// An item in the per-location borrow stack #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] pub enum BorStackItem { - /// Defines which references are permitted to mutate *if* the location is not frozen - Mut(Mut), + /// Indicates the unique reference that may mutate. + Uniq(Timestamp), + /// Indicates that the location has been shared. Used for raw pointers, but + /// also for shared references. The latter *additionally* get frozen + /// when there is no `UnsafeCell`. + Shr, /// A barrier, tracking the function it belongs to by its index on the call stack #[allow(dead_code)] // for future use FnBarrier(usize) @@ -90,6 +73,29 @@ impl BorStackItem { } } +/// Extra per-location state +#[derive(Clone, Debug)] +pub struct Stack { + borrows: Vec, // used as a stack; never empty + frozen_since: Option, // virtual frozen "item" on top of the stack +} + +impl Default for Stack { + fn default() -> Self { + Stack { + borrows: vec![BorStackItem::Shr], + frozen_since: None, + } + } +} + +impl Stack { + #[inline(always)] + pub fn is_frozen(&self) -> bool { + self.frozen_since.is_some() + } +} + /// What kind of usage of the pointer are we talking about? #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] pub enum UsageKind { @@ -97,7 +103,7 @@ pub enum UsageKind { Write, /// Read, or create & Read, - /// Create * + /// Create * (raw ptr) Raw, } @@ -123,29 +129,6 @@ impl State { } } -/// Extra per-location state -#[derive(Clone, Debug)] -pub struct Stack { - borrows: Vec, // used as a stack - frozen_since: Option, -} - -impl Default for Stack { - fn default() -> Self { - Stack { - borrows: vec![BorStackItem::Mut(Mut::Raw)], - frozen_since: None, - } - } -} - -impl Stack { - #[inline(always)] - fn is_frozen(&self) -> bool { - self.frozen_since.is_some() - } -} - /// Extra per-allocation state #[derive(Clone, Debug, Default)] pub struct Stacks { @@ -158,122 +141,123 @@ impl<'tcx> Stack { /// Check if `bor` could be activated by unfreezing and popping. /// `usage` indicates whether this is being used to read/write (or, equivalently, to /// borrow as &/&mut), or to borrow as raw. - /// Returns `Err` if the answer is "no"; otherwise the data says - /// what needs to happen to activate this: `None` = nothing, - /// `Some(n)` = unfreeze and make item `n` the top item of the stack. + /// Returns `Err` if the answer is "no"; otherwise the return value indicates what to + /// do: With `Some(n)` you need to unfreeze, and then additionally pop `n` items. fn reactivatable(&self, bor: Borrow, usage: UsageKind) -> Result, String> { - let mut_borrow = match bor { - Borrow::Frz(since) => - // The only way to reactivate a `Frz` is if this is already frozen. - return match self.frozen_since { - _ if usage == UsageKind::Write => - Err(format!("Using a shared borrow for mutation")), - None => - Err(format!("Location should be frozen but it is not")), - Some(loc) if loc <= since => - Ok(None), - Some(loc) => - Err(format!("Location should be frozen since {} but it is only frozen \ - since {}", since, loc)), - }, - Borrow::Mut(Mut::Raw) if self.is_frozen() && usage != UsageKind::Write => - // Non-mutating access with a raw from a frozen location is a special case: The - // shared refs do not mind raw reads, and the raw itself does not assume any - // exclusivity. So we do not even require there to be a raw on the stack, - // the raw is instead "matched" by the fact that this location is frozen. - // This does not break the assumption that an `&mut` we own is - // exclusive for reads, because there we have the invariant that - // the location is *not* frozen. - return Ok(None), - Borrow::Mut(mut_borrow) => mut_borrow - }; - // See if we can get there via popping. - for (idx, &itm) in self.borrows.iter().enumerate().rev() { - match itm { - BorStackItem::FnBarrier(_) => - return Err(format!("Trying to reactivate a mutable borrow ({:?}) that lives \ - behind a barrier", mut_borrow)), - BorStackItem::Mut(loc) => { - if loc == mut_borrow { - // We found it! This is good to know. - // Yet, maybe we do not really want to pop? - if usage == UsageKind::Read && self.is_frozen() { - // Whoever had exclusive access to this location allowed it - // to become frozen. That can only happen if they reborrowed - // to a shared ref, at which point they gave up on exclusive access. - // Hence we allow more reads, entirely ignoring everything above - // on the stack (but still making sure it is on the stack). - // This does not break the assumption that an `&mut` we own is - // exclusive for reads, because there we have the invariant that - // the location is *not* frozen. - return Ok(None); - } else { - return Ok(Some(idx)); + // Check if we can match the frozen "item". Not possible on writes! + if usage != UsageKind::Write { + // For now, we do NOT check the timestamp. That might be surprising, but + // we cannot even notice when a location should be frozen but is not! + // Those checks are both done in `tag_dereference`, where we have type information. + // Either way, it is crucial that the frozen "item" matches raw pointers: + // Reading through a raw should not unfreeze. + match (self.frozen_since, bor) { + (Some(_), Borrow::Shr(_)) => { + return Ok(None) + } + _ => {}, + } + } + // See if we can find this borrow. + for (idx, &itm) in self.borrows.iter().rev().enumerate() { + // Check borrow and stack item for compatibility. + match (itm, bor) { + (BorStackItem::FnBarrier(_), _) => { + return Err(format!("Trying to reactivate a borrow ({:?}) that lives \ + behind a barrier", bor)) + } + (BorStackItem::Uniq(itm_t), Borrow::Uniq(bor_t)) if itm_t == bor_t => { + // Found matching unique item. + if usage == UsageKind::Read { + // As a special case, if we are reading and since we *did* find the `Uniq`, + // we try to pop less: We are happy with making a `Shr` or `Frz` active; + // that one will not mind concurrent reads. + match self.reactivatable(Borrow::default(), usage) { + // If we got something better that `idx`, use that + Ok(None) => return Ok(None), + Ok(Some(shr_idx)) if shr_idx <= idx => return Ok(Some(shr_idx)), + // Otherwise just go on. + _ => {}, } } + return Ok(Some(idx)) } + (BorStackItem::Shr, Borrow::Shr(_)) => { + // Found matching shared/raw item. + return Ok(Some(idx)) + } + // Go on looking. + _ => {} } } // Nothing to be found. - Err(format!("Mutable borrow-to-reactivate ({:?}) does not exist on the stack", mut_borrow)) + Err(format!("Borrow-to-reactivate {:?} does not exist on the stack", bor)) } /// Reactive `bor` for this stack. `usage` indicates whether this is being /// used to read/write (or, equivalently, to borrow as &/&mut), or to borrow as raw. fn reactivate(&mut self, bor: Borrow, usage: UsageKind) -> EvalResult<'tcx> { - let action = match self.reactivatable(bor, usage) { - Ok(action) => action, + let mut pop = match self.reactivatable(bor, usage) { + Ok(None) => return Ok(()), + Ok(Some(pop)) => pop, Err(err) => return err!(MachineError(err)), }; - // Execute what `reactivatable` told us to do. - match action { - None => {}, // nothing to do - Some(top) => { - if self.frozen_since.is_some() { - trace!("reactivate: Unfreezing"); - } - self.frozen_since = None; - for itm in self.borrows.drain(top+1..).rev() { - trace!("reactivate: Popping {:?}", itm); - } - } + // Pop what `reactivatable` told us to pop. Always unfreeze. + if self.is_frozen() { + trace!("reactivate: Unfreezing"); + } + self.frozen_since = None; + while pop > 0 { + let itm = self.borrows.pop().unwrap(); + trace!("reactivate: Popping {:?}", itm); + pop -= 1; } - Ok(()) } - /// Initiate `bor`; mostly this means freezing or pushing. + /// Initiate `bor`; mostly this means pushing. /// This operation cannot fail; it is up to the caller to ensure that the precondition /// is met: We cannot push onto frozen stacks. fn initiate(&mut self, bor: Borrow) { - match bor { - Borrow::Frz(t) => { - match self.frozen_since { - None => { - trace!("initiate: Freezing"); - self.frozen_since = Some(t); - } - Some(since) => { - trace!("initiate: Already frozen"); - assert!(since <= t); - } - } - } - Borrow::Mut(m) => { - match self.frozen_since { - None => { - trace!("initiate: Pushing {:?}", bor); - self.borrows.push(BorStackItem::Mut(m)) - } - Some(_) if m.is_raw() => - // We only ever initiate right after activating the ref we come from. - // If the source ref is fine being frozen, then a raw ref we create - // from it is fine with this as well. - trace!("initiate: Initiating a raw on a frozen location, not doing a thing"), - Some(_) => - bug!("Trying to mutate frozen location") - } + if let Some(_) = self.frozen_since { + // "Pushing" a Shr or Frz on top is redundant. + match bor { + Borrow::Uniq(_) => bug!("Trying to create unique ref to frozen location"), + Borrow::Shr(_) => trace!("initiate: New shared ref to frozen location is a NOP"), } + } else { + // Just push. + let itm = match bor { + Borrow::Uniq(t) => BorStackItem::Uniq(t), + Borrow::Shr(_) if *self.borrows.last().unwrap() == BorStackItem::Shr => { + // Optimization: Don't push a Shr onto a Shr. + trace!("initiate: New shared ref to already shared location is a NOP"); + return + }, + Borrow::Shr(_) => BorStackItem::Shr, + }; + trace!("initiate: Pushing {:?}", itm); + self.borrows.push(itm) + } + } + + /// Check if this location is "frozen enough". + fn check_frozen(&self, bor_t: Timestamp) -> EvalResult<'tcx> { + let frozen = self.frozen_since.map_or(false, |itm_t| itm_t <= bor_t); + if !frozen { + err!(MachineError(format!("Location is not frozen long enough"))) + } else { + Ok(()) + } + } + + /// Freeze this location, since `bor_t`. + fn freeze(&mut self, bor_t: Timestamp) { + if let Some(itm_t) = self.frozen_since { + assert!(itm_t <= bor_t, "Trying to freeze shorter than it was frozen?"); + } else { + trace!("Freezing"); + self.frozen_since = Some(bor_t); } } } @@ -288,7 +272,7 @@ impl State { /// Higher-level operations impl<'tcx> Stacks { - /// The single most operation: Make sure that using `ptr` as `usage` is okay, + /// The single most important operation: Make sure that using `ptr` as `usage` is okay, /// and if `new_bor` is present then make that the new current borrow. fn use_and_maybe_re_borrow( &self, @@ -306,10 +290,60 @@ impl<'tcx> Stacks { stack.initiate(new_bor); } } + Ok(()) + } + /// Freeze the given memory range. + fn freeze( + &self, + ptr: Pointer, + size: Size, + bor_t: Timestamp + ) -> EvalResult<'tcx> { + let mut stacks = self.stacks.borrow_mut(); + for stack in stacks.iter_mut(ptr.offset, size) { + stack.freeze(bor_t); + } Ok(()) } + /// Check that this stack is fine with being dereferenced + fn check_deref( + &self, + ptr: Pointer, + size: Size, + ) -> EvalResult<'tcx> { + let mut stacks = self.stacks.borrow_mut(); + // We need `iter_mut` because `iter` would skip gaps! + for stack in stacks.iter_mut(ptr.offset, size) { + // Conservatively assume we will just read + if let Err(err) = stack.reactivatable(ptr.tag, UsageKind::Read) { + return err!(MachineError(format!( + "Encountered reference with non-reactivatable tag: {}", + err + ))) + } + } + Ok(()) + } + + /// Check that this stack is appropriately frozen + fn check_frozen( + &self, + ptr: Pointer, + size: Size, + bor_t: Timestamp + ) -> EvalResult<'tcx> { + let mut stacks = self.stacks.borrow_mut(); + for stack in stacks.iter_mut(ptr.offset, size) { + stack.check_frozen(bor_t)?; + } + Ok(()) + } +} + +/// Hooks and glue +impl<'tcx> Stacks { #[inline(always)] pub fn memory_read( &self, @@ -340,34 +374,34 @@ impl<'tcx> Stacks { // FIXME: Error out of there are any barriers? } - /// Pushes the first borrow to the stacks, must be a mutable one. - pub fn first_borrow( + /// Pushes the first item to the stacks. + pub fn first_item( &mut self, - mut_borrow: Mut, + itm: BorStackItem, size: Size ) { + assert!(!itm.is_fn_barrier()); for stack in self.stacks.get_mut().iter_mut(Size::ZERO, size) { - assert!(stack.borrows.len() == 1 && stack.frozen_since.is_none()); - assert_eq!(stack.borrows.pop().unwrap(), BorStackItem::Mut(Mut::Raw)); - stack.borrows.push(BorStackItem::Mut(mut_borrow)); + assert!(stack.borrows.len() == 1); + assert_eq!(stack.borrows.pop().unwrap(), BorStackItem::Shr); + stack.borrows.push(itm); } } } + + pub trait EvalContextExt<'tcx> { fn tag_reference( &mut self, - ptr: Pointer, - pointee_ty: Ty<'tcx>, + place: MPlaceTy<'tcx, Borrow>, size: Size, usage: UsageKind, ) -> EvalResult<'tcx, Borrow>; - fn tag_dereference( &self, - ptr: Pointer, - pointee_ty: Ty<'tcx>, + place: MPlaceTy<'tcx, Borrow>, size: Size, usage: UsageKind, ) -> EvalResult<'tcx, Borrow>; @@ -385,40 +419,36 @@ pub trait EvalContextExt<'tcx> { ) -> EvalResult<'tcx>; } -impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, 'tcx> { +impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for MiriEvalContext<'a, 'mir, 'tcx> { /// Called for place-to-value conversion. fn tag_reference( &mut self, - ptr: Pointer, - pointee_ty: Ty<'tcx>, + place: MPlaceTy<'tcx, Borrow>, size: Size, usage: UsageKind, ) -> EvalResult<'tcx, Borrow> { + let ptr = place.ptr.to_ptr()?; let time = self.machine.stacked_borrows.increment_clock(); let new_bor = match usage { - UsageKind::Write => Borrow::Mut(Mut::Uniq(time)), - UsageKind::Read => - // FIXME This does not do enough checking when only part of the data has - // interior mutability. When the type is `(i32, Cell)`, we want the - // first field to be frozen but not the second. - if self.type_is_freeze(pointee_ty) { - Borrow::Frz(time) - } else { - // Shared reference with interior mutability. - Borrow::Mut(Mut::Raw) - }, - UsageKind::Raw => Borrow::Mut(Mut::Raw), + UsageKind::Write => Borrow::Uniq(time), + UsageKind::Read => Borrow::Shr(Some(time)), + UsageKind::Raw => Borrow::Shr(None), }; - trace!("tag_reference: Creating new reference ({:?}) for {:?} (pointee {}, size {}): {:?}", - usage, ptr, pointee_ty, size.bytes(), new_bor); + trace!("tag_reference: Creating new reference ({:?}) for {:?} (pointee {}): {:?}", + usage, ptr, place.layout.ty, new_bor); - // Make sure this reference is not dangling or so + // Update the stacks. First create the new ref as usual, then maybe freeze stuff. self.memory().check_bounds(ptr, size, false)?; - - // Update the stacks. We cannot use `get_mut` becuse this might be immutable - // memory. let alloc = self.memory().get(ptr.alloc_id).expect("We checked that the ptr is fine!"); alloc.extra.use_and_maybe_re_borrow(ptr, size, usage, Some(new_bor))?; + // Maybe freeze stuff + if let Borrow::Shr(Some(bor_t)) = new_bor { + self.visit_frozen(place, size, |frz_ptr, size| { + debug_assert_eq!(frz_ptr.alloc_id, ptr.alloc_id); + // Be frozen! + alloc.extra.freeze(frz_ptr, size, bor_t) + })?; + } Ok(new_bor) } @@ -429,13 +459,13 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' /// We could be in the middle of `&(*var).1`. fn tag_dereference( &self, - ptr: Pointer, - pointee_ty: Ty<'tcx>, + place: MPlaceTy<'tcx, Borrow>, size: Size, usage: UsageKind, ) -> EvalResult<'tcx, Borrow> { - trace!("tag_reference: Accessing reference ({:?}) for {:?} (pointee {}, size {})", - usage, ptr, pointee_ty, size.bytes()); + let ptr = place.ptr.to_ptr()?; + trace!("tag_dereference: Accessing reference ({:?}) for {:?} (pointee {})", + usage, ptr, place.layout.ty); // In principle we should not have to do anything here. However, with transmutes involved, // it can happen that the tag of `ptr` does not actually match `usage`, and we // should adjust for that. @@ -446,27 +476,24 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' // Don't use the tag, this is a raw access! Even if there is a tag, // that means transmute happened and we ignore the tag. // Also don't do any further validation, this is raw after all. - return Ok(Borrow::Mut(Mut::Raw)); + return Ok(Borrow::default()); } - (UsageKind::Write, Borrow::Mut(Mut::Uniq(_))) | - (UsageKind::Read, Borrow::Frz(_)) | - (UsageKind::Read, Borrow::Mut(Mut::Raw)) => { + (UsageKind::Write, Borrow::Uniq(_)) | + (UsageKind::Read, Borrow::Shr(_)) => { // Expected combinations. Nothing to do. - // FIXME: We probably shouldn't accept this if we got a raw shr without - // interior mutability. } - (UsageKind::Write, Borrow::Mut(Mut::Raw)) => { + (UsageKind::Write, Borrow::Shr(None)) => { // Raw transmuted to mut ref. Keep this as raw access. // We cannot reborrow here; there might be a raw in `&(*var).1` where // `var` is an `&mut`. The other field of the struct might be already frozen, // also using `var`, and that would be okay. } - (UsageKind::Read, Borrow::Mut(Mut::Uniq(_))) => { + (UsageKind::Read, Borrow::Uniq(_)) => { // A mut got transmuted to shr. Can happen even from compiler transformations: // `&*x` gets optimized to `x` even when `x` is a `&mut`. } - (UsageKind::Write, Borrow::Frz(_)) => { - // This is just invalid. + (UsageKind::Write, Borrow::Shr(Some(_))) => { + // This is just invalid: A shr got transmuted to a mut. // If we ever allow this, we have to consider what we do when a turn a // `Raw`-tagged `&mut` into a raw pointer pointing to a frozen location. // We probably do not want to allow that, but we have to allow @@ -474,23 +501,21 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' return err!(MachineError(format!("Encountered mutable reference with frozen tag {:?}", ptr.tag))) } } - // Even if we don't touch the tag, this operation is only okay if we *could* - // activate it. Also it must not be dangling. + + // If we got here, we do some checking, *but* we leave the tag unchanged. self.memory().check_bounds(ptr, size, false)?; let alloc = self.memory().get(ptr.alloc_id).expect("We checked that the ptr is fine!"); - let mut stacks = alloc.extra.stacks.borrow_mut(); - // We need `iter_mut` because `iter` would skip gaps! - for stack in stacks.iter_mut(ptr.offset, size) { - // Conservatively assume that we will only read. - if let Err(err) = stack.reactivatable(ptr.tag, UsageKind::Read) { - return err!(MachineError(format!( - "Encountered {} reference with non-reactivatable tag: {}", - if usage == UsageKind::Write { "mutable" } else { "shared" }, - err - ))) - } + alloc.extra.check_deref(ptr, size)?; + // Maybe check frozen stuff + if let Borrow::Shr(Some(bor_t)) = ptr.tag { + self.visit_frozen(place, size, |frz_ptr, size| { + debug_assert_eq!(frz_ptr.alloc_id, ptr.alloc_id); + // Are you frozen? + alloc.extra.check_frozen(frz_ptr, size, bor_t) + })?; } - // All is good. + + // All is good, and do not change the tag Ok(ptr.tag) } @@ -499,7 +524,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' id: AllocId, kind: MemoryKind, ) -> Borrow { - let mut_borrow = match kind { + let time = match kind { MemoryKind::Stack => { // New unique borrow. This `Uniq` is not accessible by the program, // so it will only ever be used when using the local directly (i.e., @@ -509,19 +534,18 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' // `reset` which the blog post [1] says to perform when accessing a local. // // [1] https://www.ralfj.de/blog/2018/08/07/stacked-borrows.html - let time = self.machine.stacked_borrows.increment_clock(); - Mut::Uniq(time) + self.machine.stacked_borrows.increment_clock() } _ => { - // Raw for everything else - Mut::Raw + // Nothing to do for everything else + return Borrow::default() } }; // Make this the active borrow for this allocation let alloc = self.memory_mut().get_mut(id).expect("This is a new allocation, it must still exist"); let size = Size::from_bytes(alloc.bytes.len() as u64); - alloc.extra.first_borrow(mut_borrow, size); - Borrow::Mut(mut_borrow) + alloc.extra.first_item(BorStackItem::Uniq(time), size); + Borrow::Uniq(time) } fn retag( diff --git a/src/tls.rs b/src/tls.rs index 1aacc67f5ccae..af1d7b138b859 100644 --- a/src/tls.rs +++ b/src/tls.rs @@ -133,7 +133,7 @@ impl<'tcx> TlsData<'tcx> { } } -impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, 'tcx> { +impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, 'tcx> { fn run_tls_dtors(&mut self) -> EvalResult<'tcx> { let mut dtor = self.machine.tls.fetch_tls_dtor(None, &*self.tcx); // FIXME: replace loop by some structure that works with stepping diff --git a/tests/compile-fail/stacked_borrows/buggy_as_mut_slice.rs b/tests/compile-fail/stacked_borrows/buggy_as_mut_slice.rs index 2c48404ddf364..4857ada7fb2c7 100644 --- a/tests/compile-fail/stacked_borrows/buggy_as_mut_slice.rs +++ b/tests/compile-fail/stacked_borrows/buggy_as_mut_slice.rs @@ -14,6 +14,6 @@ fn main() { let v = vec![0,1,2]; let v1 = safe::as_mut_slice(&v); let v2 = safe::as_mut_slice(&v); - v1[1] = 5; //~ ERROR reference with non-reactivatable tag + v1[1] = 5; //~ ERROR does not exist on the stack v1[1] = 6; } diff --git a/tests/compile-fail/stacked_borrows/buggy_split_at_mut.rs b/tests/compile-fail/stacked_borrows/buggy_split_at_mut.rs index d8a241cab5d49..a6daa5d93d772 100644 --- a/tests/compile-fail/stacked_borrows/buggy_split_at_mut.rs +++ b/tests/compile-fail/stacked_borrows/buggy_split_at_mut.rs @@ -11,7 +11,7 @@ mod safe { assert!(mid <= len); (from_raw_parts_mut(ptr, len - mid), // BUG: should be "mid" instead of "len - mid" - //~^ ERROR reference with non-reactivatable tag + //~^ ERROR does not exist on the stack from_raw_parts_mut(ptr.offset(mid as isize), len - mid)) } } diff --git a/tests/compile-fail/stacked_borrows/illegal_read1.rs b/tests/compile-fail/stacked_borrows/illegal_read1.rs index 59190a15db440..dbaccae882721 100644 --- a/tests/compile-fail/stacked_borrows/illegal_read1.rs +++ b/tests/compile-fail/stacked_borrows/illegal_read1.rs @@ -7,7 +7,7 @@ fn main() { let xref = unsafe { &mut *xraw }; // derived from raw, so using raw is still okay... callee(xraw); let _val = *xref; // ...but any use of raw will invalidate our ref. - //~^ ERROR: mutable reference with non-reactivatable tag + //~^ ERROR: does not exist on the stack } fn callee(xraw: *mut i32) { diff --git a/tests/compile-fail/stacked_borrows/illegal_read2.rs b/tests/compile-fail/stacked_borrows/illegal_read2.rs index 594117d28ab84..2da755d9aabc1 100644 --- a/tests/compile-fail/stacked_borrows/illegal_read2.rs +++ b/tests/compile-fail/stacked_borrows/illegal_read2.rs @@ -7,7 +7,7 @@ fn main() { let xref = unsafe { &mut *xraw }; // derived from raw, so using raw is still okay... callee(xraw); let _val = *xref; // ...but any use of raw will invalidate our ref. - //~^ ERROR: mutable reference with non-reactivatable tag + //~^ ERROR: does not exist on the stack } fn callee(xraw: *mut i32) { diff --git a/tests/compile-fail/stacked_borrows/illegal_write1.rs b/tests/compile-fail/stacked_borrows/illegal_write1.rs index ab951be5ec911..7378907fa7456 100644 --- a/tests/compile-fail/stacked_borrows/illegal_write1.rs +++ b/tests/compile-fail/stacked_borrows/illegal_write1.rs @@ -8,5 +8,5 @@ fn main() { let target = Box::new(42); // has an implicit raw let ref_ = &*target; evil(ref_); // invalidates shared ref, activates raw - let _x = *ref_; //~ ERROR reference with non-reactivatable tag + let _x = *ref_; //~ ERROR is not frozen long enough } diff --git a/tests/compile-fail/stacked_borrows/illegal_write3.rs b/tests/compile-fail/stacked_borrows/illegal_write3.rs index a653aa5003f6d..c82da1e9c4677 100644 --- a/tests/compile-fail/stacked_borrows/illegal_write3.rs +++ b/tests/compile-fail/stacked_borrows/illegal_write3.rs @@ -3,6 +3,6 @@ fn main() { // Make sure raw ptr with raw tag cannot mutate frozen location without breaking the shared ref. let r#ref = ⌖ // freeze let ptr = r#ref as *const _ as *mut _; // raw ptr, with raw tag - unsafe { *ptr = 42; } //~ ERROR does not exist on the stack - let _val = *r#ref; + unsafe { *ptr = 42; } + let _val = *r#ref; //~ ERROR is not frozen long enough } diff --git a/tests/compile-fail/stacked_borrows/illegal_write4.rs b/tests/compile-fail/stacked_borrows/illegal_write4.rs index 12deb518b4e7c..49bf9279faa2e 100644 --- a/tests/compile-fail/stacked_borrows/illegal_write4.rs +++ b/tests/compile-fail/stacked_borrows/illegal_write4.rs @@ -9,5 +9,5 @@ fn main() { let ptr = reference as *const _ as *mut i32; // raw ptr, with raw tag let _mut_ref: &mut i32 = unsafe { mem::transmute(ptr) }; // &mut, with raw tag // Now we retag, making our ref top-of-stack -- and, in particular, unfreezing. - let _val = *reference; //~ ERROR Location should be frozen + let _val = *reference; //~ ERROR is not frozen long enough } diff --git a/tests/compile-fail/stacked_borrows/load_invalid_mut.rs b/tests/compile-fail/stacked_borrows/load_invalid_mut.rs index 4ea61cd606fff..d3db462343e84 100644 --- a/tests/compile-fail/stacked_borrows/load_invalid_mut.rs +++ b/tests/compile-fail/stacked_borrows/load_invalid_mut.rs @@ -5,5 +5,5 @@ fn main() { let xref = unsafe { &mut *xraw }; let xref_in_mem = Box::new(xref); let _val = *x; // invalidate xraw - let _val = *xref_in_mem; //~ ERROR mutable reference with non-reactivatable tag + let _val = *xref_in_mem; //~ ERROR does not exist on the stack } diff --git a/tests/compile-fail/stacked_borrows/load_invalid_shr.rs b/tests/compile-fail/stacked_borrows/load_invalid_shr.rs index 53179c954dea2..71b578817a774 100644 --- a/tests/compile-fail/stacked_borrows/load_invalid_shr.rs +++ b/tests/compile-fail/stacked_borrows/load_invalid_shr.rs @@ -5,5 +5,5 @@ fn main() { let xref = unsafe { &*xraw }; let xref_in_mem = Box::new(xref); *x = 42; // invalidate xraw - let _val = *xref_in_mem; //~ ERROR shared reference with non-reactivatable tag: Location should be frozen + let _val = *xref_in_mem; //~ ERROR does not exist on the stack } diff --git a/tests/compile-fail/stacked_borrows/pass_invalid_mut.rs b/tests/compile-fail/stacked_borrows/pass_invalid_mut.rs index 5e1118160a327..41cf89d874d71 100644 --- a/tests/compile-fail/stacked_borrows/pass_invalid_mut.rs +++ b/tests/compile-fail/stacked_borrows/pass_invalid_mut.rs @@ -6,5 +6,5 @@ fn main() { let xraw = x as *mut _; let xref = unsafe { &mut *xraw }; let _val = *x; // invalidate xraw - foo(xref); //~ ERROR mutable reference with non-reactivatable tag + foo(xref); //~ ERROR does not exist on the stack } diff --git a/tests/compile-fail/stacked_borrows/pass_invalid_shr.rs b/tests/compile-fail/stacked_borrows/pass_invalid_shr.rs index e4b26cfff6da4..0bdb1b4a41e59 100644 --- a/tests/compile-fail/stacked_borrows/pass_invalid_shr.rs +++ b/tests/compile-fail/stacked_borrows/pass_invalid_shr.rs @@ -6,5 +6,5 @@ fn main() { let xraw = &*x as *const _; let xref = unsafe { &*xraw }; *x = 42; // invalidate xraw - foo(xref); //~ ERROR shared reference with non-reactivatable tag: Location should be frozen + foo(xref); //~ ERROR does not exist on the stack } diff --git a/tests/compile-fail/stacked_borrows/return_invalid_mut.rs b/tests/compile-fail/stacked_borrows/return_invalid_mut.rs index 949b3829ff8fe..aef8fafdf5d59 100644 --- a/tests/compile-fail/stacked_borrows/return_invalid_mut.rs +++ b/tests/compile-fail/stacked_borrows/return_invalid_mut.rs @@ -3,7 +3,7 @@ fn foo(x: &mut (i32, i32)) -> &mut i32 { let xraw = x as *mut (i32, i32); let ret = unsafe { &mut (*xraw).1 }; let _val = *x; // invalidate xraw and its children - ret //~ ERROR mutable reference with non-reactivatable tag + ret //~ ERROR does not exist on the stack } fn main() { diff --git a/tests/compile-fail/stacked_borrows/return_invalid_shr.rs b/tests/compile-fail/stacked_borrows/return_invalid_shr.rs index 2d34350359d13..074942eb95bca 100644 --- a/tests/compile-fail/stacked_borrows/return_invalid_shr.rs +++ b/tests/compile-fail/stacked_borrows/return_invalid_shr.rs @@ -3,7 +3,7 @@ fn foo(x: &mut (i32, i32)) -> &i32 { let xraw = x as *mut (i32, i32); let ret = unsafe { &(*xraw).1 }; x.1 = 42; // invalidate xraw on the 2nd field - ret //~ ERROR shared reference with non-reactivatable tag: Location should be frozen + ret //~ ERROR does not exist on the stack } fn main() { diff --git a/tests/compile-fail/stacked_borrows/shared_confusion.rs b/tests/compile-fail/stacked_borrows/shared_confusion.rs deleted file mode 100644 index 624587932cb83..0000000000000 --- a/tests/compile-fail/stacked_borrows/shared_confusion.rs +++ /dev/null @@ -1,29 +0,0 @@ -// Optimization kills all the reborrows, enough to make this error go away. There are -// no retags either because we don't retag immediately after a `&[mut]`; we rely on -// that creating a fresh reference. -// See `shared_confusion_opt.rs` for a variant that is caught even with optimizations. -// Keep this test to make sure that without optimizations, we do not have to actually -// use the `x_inner_shr`. -// compile-flags: -Zmir-opt-level=0 - -#![allow(unused_variables)] -use std::cell::RefCell; - -fn test(r: &mut RefCell) { - let x = &*r; // not freezing because interior mutability - let mut x_ref = x.borrow_mut(); - let x_inner : &mut i32 = &mut *x_ref; // Uniq reference - let x_evil = x_inner as *mut _; - { - let x_inner_shr = &*x_inner; // frozen - let y = &*r; // outer ref, not freezing - let x_inner_shr = &*x_inner; // freezing again - } - // Our old raw should be dead by now - unsafe { *x_evil = 0; } // this falls back to some Raw higher up the stack - *x_inner = 12; //~ ERROR reference with non-reactivatable tag -} - -fn main() { - test(&mut RefCell::new(0)); -} diff --git a/tests/compile-fail/stacked_borrows/shared_confusion_opt.rs b/tests/compile-fail/stacked_borrows/shared_confusion_opt.rs deleted file mode 100644 index 3030f5dd4001b..0000000000000 --- a/tests/compile-fail/stacked_borrows/shared_confusion_opt.rs +++ /dev/null @@ -1,25 +0,0 @@ -// A variant of `shared_confusion.rs` that gets flagged even with optimizations. - -#![allow(unused_variables)] -use std::cell::RefCell; - -fn test(r: &mut RefCell) { - let x = &*r; // not freezing because interior mutability - let mut x_ref = x.borrow_mut(); - let x_inner : &mut i32 = &mut *x_ref; // Uniq reference - let x_evil = x_inner as *mut _; - { - let x_inner_shr = &*x_inner; // frozen - let _val = *x_inner_shr; - let y = &*r; // outer ref, not freezing - let x_inner_shr = &*x_inner; // freezing again - let _val = *x_inner_shr; - } - // Our old raw should be dead by now - unsafe { *x_evil = 0; } // this falls back to some Raw higher up the stack - *x_inner = 12; //~ ERROR reference with non-reactivatable tag -} - -fn main() { - test(&mut RefCell::new(0)); -} diff --git a/tests/compile-fail/validity/invalid_enum_discriminant.rs b/tests/compile-fail/validity/invalid_enum_discriminant.rs index 543a797d44f20..13be4e7dcea81 100644 --- a/tests/compile-fail/validity/invalid_enum_discriminant.rs +++ b/tests/compile-fail/validity/invalid_enum_discriminant.rs @@ -4,5 +4,5 @@ pub enum Foo { } fn main() { - let _f = unsafe { std::mem::transmute::(42) }; //~ ERROR encountered invalid enum discriminant 42 + let _f = unsafe { std::mem::transmute::(42) }; //~ ERROR encountered 42, but expected a valid enum discriminant } diff --git a/tests/compile-fail/validity/transmute_through_ptr.rs b/tests/compile-fail/validity/transmute_through_ptr.rs index 0a4c64bb9bb11..d6bc0305e69dc 100644 --- a/tests/compile-fail/validity/transmute_through_ptr.rs +++ b/tests/compile-fail/validity/transmute_through_ptr.rs @@ -12,5 +12,5 @@ fn main() { let mut x = Bool::True; evil(&mut x); let _y = x; // reading this ought to be enough to trigger validation - //~^ ERROR invalid enum discriminant 44 + //~^ ERROR encountered 44, but expected a valid enum discriminant } diff --git a/tests/run-pass-fullmir/send-is-not-static-par-for.rs b/tests/run-pass-fullmir/send-is-not-static-par-for.rs index 282f7a3595032..1b913aed4c89e 100644 --- a/tests/run-pass-fullmir/send-is-not-static-par-for.rs +++ b/tests/run-pass-fullmir/send-is-not-static-par-for.rs @@ -8,9 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// FIXME: Still investigating whether there is UB here -// compile-flags: -Zmiri-disable-validation - use std::sync::Mutex; fn par_for(iter: I, f: F) diff --git a/tests/run-pass-fullmir/u128.rs b/tests/run-pass-fullmir/u128.rs index 0f1b6e8b58708..ca33bd5f9e3d8 100644 --- a/tests/run-pass-fullmir/u128.rs +++ b/tests/run-pass-fullmir/u128.rs @@ -8,9 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -// FIXME: Still investigating whether there is UB here -// compile-flags: -Zmiri-disable-validation - fn b(t: T) -> T { t } fn main() { diff --git a/tests/run-pass-fullmir/vecdeque.rs b/tests/run-pass-fullmir/vecdeque.rs index ffbb116684985..381169505ec9f 100644 --- a/tests/run-pass-fullmir/vecdeque.rs +++ b/tests/run-pass-fullmir/vecdeque.rs @@ -1,6 +1,3 @@ -// FIXME: Still investigating whether there is UB here -// compile-flags: -Zmiri-disable-validation - use std::collections::VecDeque; fn main() { diff --git a/tests/run-pass/slices.rs b/tests/run-pass/slices.rs index 119c9b90a05c1..45a2a74db08da 100644 --- a/tests/run-pass/slices.rs +++ b/tests/run-pass/slices.rs @@ -1,6 +1,3 @@ -// FIXME: Still investigating whether there is UB here -// compile-flags: -Zmiri-disable-validation - use std::slice; fn slice_of_zst() { diff --git a/tests/run-pass/stacked-borrows.rs b/tests/run-pass/stacked-borrows.rs index cde6968a26415..8faa4d6591156 100644 --- a/tests/run-pass/stacked-borrows.rs +++ b/tests/run-pass/stacked-borrows.rs @@ -1,7 +1,8 @@ // Test various stacked-borrows-related things. fn main() { deref_partially_dangling_raw(); - read_does_not_invalidate(); + read_does_not_invalidate1(); + read_does_not_invalidate2(); } // Deref a raw ptr to access a field of a large struct, where the field @@ -15,13 +16,23 @@ fn deref_partially_dangling_raw() { // Make sure that reading from an `&mut` does, like reborrowing to `&`, // NOT invalidate other reborrows. -fn read_does_not_invalidate() { +fn read_does_not_invalidate1() { fn foo(x: &mut (i32, i32)) -> &i32 { let xraw = x as *mut (i32, i32); let ret = unsafe { &(*xraw).1 }; let _val = x.1; // we just read, this does NOT invalidate the reborrows. ret } - + foo(&mut (1, 2)); +} +// Same as above, but this time we first create a raw, then read from `&mut` +// and then freeze from the raw. +fn read_does_not_invalidate2() { + fn foo(x: &mut (i32, i32)) -> &i32 { + let xraw = x as *mut (i32, i32); + let _val = x.1; // we just read, this does NOT invalidate the raw reborrow. + let ret = unsafe { &(*xraw).1 }; + ret + } foo(&mut (1, 2)); } From 00936316d18b3c1cfa7924f119bbe6061c8cb9f6 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 5 Nov 2018 16:23:22 +0100 Subject: [PATCH 0342/3747] treat shared and raw borrows alike --- src/stacked_borrows.rs | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 1ab6edcf398c4..e1abcb20af756 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -139,13 +139,13 @@ pub struct Stacks { /// Core operations impl<'tcx> Stack { /// Check if `bor` could be activated by unfreezing and popping. - /// `usage` indicates whether this is being used to read/write (or, equivalently, to - /// borrow as &/&mut), or to borrow as raw. + /// `is_write` indicates whether this is being used to write (or, equivalently, to + /// borrow as &mut). /// Returns `Err` if the answer is "no"; otherwise the return value indicates what to /// do: With `Some(n)` you need to unfreeze, and then additionally pop `n` items. - fn reactivatable(&self, bor: Borrow, usage: UsageKind) -> Result, String> { + fn reactivatable(&self, bor: Borrow, is_write: bool) -> Result, String> { // Check if we can match the frozen "item". Not possible on writes! - if usage != UsageKind::Write { + if !is_write { // For now, we do NOT check the timestamp. That might be surprising, but // we cannot even notice when a location should be frozen but is not! // Those checks are both done in `tag_dereference`, where we have type information. @@ -168,11 +168,11 @@ impl<'tcx> Stack { } (BorStackItem::Uniq(itm_t), Borrow::Uniq(bor_t)) if itm_t == bor_t => { // Found matching unique item. - if usage == UsageKind::Read { + if !is_write { // As a special case, if we are reading and since we *did* find the `Uniq`, // we try to pop less: We are happy with making a `Shr` or `Frz` active; // that one will not mind concurrent reads. - match self.reactivatable(Borrow::default(), usage) { + match self.reactivatable(Borrow::default(), is_write) { // If we got something better that `idx`, use that Ok(None) => return Ok(None), Ok(Some(shr_idx)) if shr_idx <= idx => return Ok(Some(shr_idx)), @@ -194,10 +194,10 @@ impl<'tcx> Stack { Err(format!("Borrow-to-reactivate {:?} does not exist on the stack", bor)) } - /// Reactive `bor` for this stack. `usage` indicates whether this is being - /// used to read/write (or, equivalently, to borrow as &/&mut), or to borrow as raw. - fn reactivate(&mut self, bor: Borrow, usage: UsageKind) -> EvalResult<'tcx> { - let mut pop = match self.reactivatable(bor, usage) { + /// Reactive `bor` for this stack. `is_write` indicates whether this is being + /// used to write (or, equivalently, to borrow as &mut). + fn reactivate(&mut self, bor: Borrow, is_write: bool) -> EvalResult<'tcx> { + let mut pop = match self.reactivatable(bor, is_write) { Ok(None) => return Ok(()), Ok(Some(pop)) => pop, Err(err) => return err!(MachineError(err)), @@ -272,7 +272,7 @@ impl State { /// Higher-level operations impl<'tcx> Stacks { - /// The single most important operation: Make sure that using `ptr` as `usage` is okay, + /// The single most important operation: Make sure that using `ptr` is okay, /// and if `new_bor` is present then make that the new current borrow. fn use_and_maybe_re_borrow( &self, @@ -285,7 +285,7 @@ impl<'tcx> Stacks { ptr.tag, usage, new_bor, ptr, size.bytes()); let mut stacks = self.stacks.borrow_mut(); for stack in stacks.iter_mut(ptr.offset, size) { - stack.reactivate(ptr.tag, usage)?; + stack.reactivate(ptr.tag, usage == UsageKind::Write)?; if let Some(new_bor) = new_bor { stack.initiate(new_bor); } @@ -317,7 +317,7 @@ impl<'tcx> Stacks { // We need `iter_mut` because `iter` would skip gaps! for stack in stacks.iter_mut(ptr.offset, size) { // Conservatively assume we will just read - if let Err(err) = stack.reactivatable(ptr.tag, UsageKind::Read) { + if let Err(err) = stack.reactivatable(ptr.tag, /*is_write*/false) { return err!(MachineError(format!( "Encountered reference with non-reactivatable tag: {}", err From f4e45ff2b7fc60152ba5bbc595c4ba602dfe7680 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 6 Nov 2018 17:46:54 +0100 Subject: [PATCH 0343/3747] sort the fields ourselves --- src/helpers.rs | 37 ++++++++++++++++++++++++++++++++----- 1 file changed, 32 insertions(+), 5 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index 52d3db8ac46fd..880b18c7d5426 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -1,6 +1,6 @@ use std::mem; -use rustc::ty; +use rustc::ty::{self, layout}; use rustc::hir::def_id::{DefId, CRATE_DEF_INDEX}; use crate::*; @@ -124,8 +124,12 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: let (unsafe_cell_size, _) = self.size_and_align_of_mplace(place)? // for extern types, just cover what we can .unwrap_or_else(|| place.layout.size_and_align()); - // Now handle this `UnsafeCell`. - unsafe_cell_action(place.ptr.get_ptr_offset(self), unsafe_cell_size) + // Now handle this `UnsafeCell`, unless it is empty. + if unsafe_cell_size != Size::ZERO { + unsafe_cell_action(place.ptr.get_ptr_offset(self), unsafe_cell_size) + } else { + Ok(()) + } }, }; visitor.visit_value(place)?; @@ -152,8 +156,6 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: { type V = MPlaceTy<'tcx, Borrow>; - const WANT_FIELDS_SORTED: bool = true; // sorted? yes please! - #[inline(always)] fn ecx(&self) -> &MiriEvalContext<'a, 'mir, 'tcx> { &self.ecx @@ -179,6 +181,31 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: } } + // Make sure we visit aggregrates in increasing offset order + fn visit_aggregate( + &mut self, + place: MPlaceTy<'tcx, Borrow>, + fields: impl Iterator>>, + ) -> EvalResult<'tcx> { + match place.layout.fields { + layout::FieldPlacement::Array { .. } => { + // For the array layout, we know the iterator will yield sorted elements so + // we can avoid the allocation. + self.walk_aggregate(place, fields) + } + layout::FieldPlacement::Arbitrary { .. } => { + // Gather the subplaces and sort them before visiting. + let mut places = fields.collect::>>>()?; + places[..].sort_by_key(|place| place.ptr.get_ptr_offset(self.ecx())); + self.walk_aggregate(place, places.into_iter().map(Ok)) + } + layout::FieldPlacement::Union { .. } => { + // Uh, what? + bug!("A union is not an aggregate we should ever visit") + } + } + } + // We have to do *something* for unions fn visit_union(&mut self, v: MPlaceTy<'tcx, Borrow>) -> EvalResult<'tcx> { From d694dc43f4e4c459f908b8ded939fa1fc359ad9a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 8 Nov 2018 08:29:55 +0100 Subject: [PATCH 0344/3747] bump Rust version --- rust-version | 2 +- tests/compile-fail/validity/invalid_bool.rs | 2 +- tests/compile-fail/validity/invalid_char.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/rust-version b/rust-version index 48887947cdf79..0ad815872411a 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -nightly-2018-11-07 +nightly-2018-11-08 diff --git a/tests/compile-fail/validity/invalid_bool.rs b/tests/compile-fail/validity/invalid_bool.rs index af4ad67a4f099..ce464616195df 100644 --- a/tests/compile-fail/validity/invalid_bool.rs +++ b/tests/compile-fail/validity/invalid_bool.rs @@ -1,3 +1,3 @@ fn main() { - let _b = unsafe { std::mem::transmute::(2) }; //~ ERROR encountered 2, but expected something in the range 0..=1 + let _b = unsafe { std::mem::transmute::(2) }; //~ ERROR encountered 2, but expected something less or equal to 1 } diff --git a/tests/compile-fail/validity/invalid_char.rs b/tests/compile-fail/validity/invalid_char.rs index 3ff0ed60f664c..0d75ad9d28905 100644 --- a/tests/compile-fail/validity/invalid_char.rs +++ b/tests/compile-fail/validity/invalid_char.rs @@ -1,6 +1,6 @@ fn main() { assert!(std::char::from_u32(-1_i32 as u32).is_none()); - let _ = match unsafe { std::mem::transmute::(-1) } { //~ ERROR encountered 4294967295, but expected something in the range 0..=1114111 + let _ = match unsafe { std::mem::transmute::(-1) } { //~ ERROR encountered 4294967295, but expected something less or equal to 1114111 'a' => {true}, 'b' => {false}, _ => {true}, From 45e14f8dc59310c8d647f7c76736650dfc8a3fb5 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 9 Nov 2018 11:48:10 +0100 Subject: [PATCH 0345/3747] use custom test runner so that we can get proper test filtering --- README.md | 25 +++++++++++++----- tests/compiletest.rs | 61 +++++++++++++++++++------------------------- 2 files changed, 44 insertions(+), 42 deletions(-) diff --git a/README.md b/README.md index a905c2aeffb72..94b5f8fea79d9 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ undergraduate research course at the [University of Saskatchewan][usask]. ## Building Miri -I recommend that you install [rustup][rustup] to obtain Rust. Then all you have +We recommend that you install [rustup][rustup] to obtain Rust. Then all you have to do is: ```sh @@ -117,11 +117,12 @@ Miri will often require using a locally built rustc. This includes getting a trace of the execution, as distributed rustc has `debug!` and `trace!` disabled. The first-time setup for a local rustc looks as follows: -``` +```sh git clone https://github.com/rust-lang/rust/ rustc cd rustc cp config.toml.example config.toml -# Now edit `config.toml` and set `debug-assertions = true` +# Now edit `config.toml` and set `debug-assertions = true` and `test-miri = true`. +# The latter is important to build libstd with the right flags for miri. ./x.py build src/rustc # You may have to change the architecture in the next command rustup toolchain link custom build/x86_64-unknown-linux-gnu/stage2 @@ -130,9 +131,20 @@ rustup override set custom ``` The `build` step can take 30 minutes and more. -Now you can `cargo build` Miri, and you can `cargo test` it. But the key point -is, you can now run Miri with a trace of all execution steps: +Now you can `cargo build` Miri, and you can `cargo test --release` it. `cargo +test --release FILTER` only runs those tests that contain `FILTER` in their +filename (including the base directory, e.g. `cargo test --release fail` will +run all compile-fail tests). We recommend using `--release` to make test +running take less time. + +Notice that the "fullmir" tests only run if you have `MIRI_SYSROOT` set, the +test runner does not realized that your libstd comes with full MIR. The +following will set it correctly: +```sh +MIRI_SYSROOT=$(rustc --print sysroot) cargo test --release +``` +Moreover, you can now run Miri with a trace of all execution steps: ```sh MIRI_LOG=debug cargo run tests/run-pass/vecs.rs ``` @@ -141,9 +153,8 @@ Setting `MIRI_LOG` like this will configure logging for miri itself as well as the `rustc::mir::interpret` and `rustc_mir::interpret` modules in rustc. You can also do more targeted configuration, e.g. to debug the stacked borrows implementation: - ```sh -MIRI_LOG=miri::stacked_borrows=trace,rustc_mir::interpret=debug cargo run tests/run-pass/vecs.rs +MIRI_LOG=rustc_mir::interpret=debug,miri::stacked_borrows cargo run tests/run-pass/vecs.rs ``` In addition, you can set `MIRI_BACKTRACE=1` to get a backtrace of where an diff --git a/tests/compiletest.rs b/tests/compiletest.rs index 98e3fde54e69e..5771478cb557a 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -1,20 +1,13 @@ -#![feature(slice_concat_ext)] - -extern crate compiletest_rs as compiletest; -extern crate colored; - -use colored::*; +#![feature(slice_concat_ext, custom_test_frameworks)] +#![test_runner(test_runner)] use std::slice::SliceConcatExt; use std::path::{PathBuf, Path}; use std::io::Write; +use std::env; -macro_rules! eprintln { - ($($arg:tt)*) => { - let stderr = std::io::stderr(); - writeln!(stderr.lock(), $($arg)*).unwrap(); - } -} +use compiletest_rs as compiletest; +use colored::*; fn miri_path() -> PathBuf { if rustc_test_suite().is_some() { @@ -37,9 +30,21 @@ fn have_fullmir() -> bool { std::env::var("MIRI_SYSROOT").is_ok() || rustc_test_suite().is_some() } +fn mk_config(mode: &str) -> compiletest::Config { + let mut config = compiletest::Config::default(); + config.mode = mode.parse().expect("Invalid mode"); + config.rustc_path = miri_path(); + if rustc_test_suite().is_some() { + config.run_lib_path = rustc_lib_path(); + config.compile_lib_path = rustc_lib_path(); + } + config.filter = env::args().nth(1); + config +} + fn compile_fail(sysroot: &Path, path: &str, target: &str, host: &str, need_fullmir: bool, opt: bool) { if need_fullmir && !have_fullmir() { - eprintln!("{}", format!( + eprintln!("{}\n", format!( "## Skipping compile-fail tests in {} against miri for target {} due to missing mir", path, target @@ -65,23 +70,17 @@ fn compile_fail(sysroot: &Path, path: &str, target: &str, host: &str, need_fullm flags.push("-Zmir-opt-level=1".to_owned()); } - let mut config = compiletest::Config::default().tempdir(); - config.mode = "compile-fail".parse().expect("Invalid mode"); - config.rustc_path = miri_path(); - if rustc_test_suite().is_some() { - config.run_lib_path = rustc_lib_path(); - config.compile_lib_path = rustc_lib_path(); - } - config.src_base = PathBuf::from(path.to_string()); - config.target_rustcflags = Some(flags.join(" ")); + let mut config = mk_config("compile-fail"); + config.src_base = PathBuf::from(path); config.target = target.to_owned(); config.host = host.to_owned(); - compiletest::run_tests(&config); + config.target_rustcflags = Some(flags.join(" ")); + compiletest::run_tests(&config.tempdir()); // FIXME: `tempdir` can be done by `mk_config` once `ConfigWithTemp` is exposed as type from compiletest } fn miri_pass(sysroot: &Path, path: &str, target: &str, host: &str, need_fullmir: bool, opt: bool) { if need_fullmir && !have_fullmir() { - eprintln!("{}", format!( + eprintln!("{}\n", format!( "## Skipping run-pass tests in {} against miri for target {} due to missing mir", path, target @@ -104,18 +103,12 @@ fn miri_pass(sysroot: &Path, path: &str, target: &str, host: &str, need_fullmir: flags.push("-Zmir-opt-level=3".to_owned()); } - let mut config = compiletest::Config::default().tempdir(); - config.mode = "ui".parse().expect("Invalid mode"); + let mut config = mk_config("ui"); config.src_base = PathBuf::from(path); config.target = target.to_owned(); config.host = host.to_owned(); - config.rustc_path = miri_path(); - if rustc_test_suite().is_some() { - config.run_lib_path = rustc_lib_path(); - config.compile_lib_path = rustc_lib_path(); - } config.target_rustcflags = Some(flags.join(" ")); - compiletest::run_tests(&config); + compiletest::run_tests(&config.tempdir()); // FIXME: `tempdir` can be done by `mk_config` once `ConfigWithTemp` is exposed as type from compiletest } fn is_target_dir>(path: P) -> bool { @@ -151,7 +144,6 @@ fn get_sysroot() -> PathBuf { fn get_host() -> String { let rustc = rustc_test_suite().unwrap_or(PathBuf::from("rustc")); - println!("using rustc at {}", rustc.display()); let host = std::process::Command::new(rustc) .arg("-vV") .output() @@ -184,8 +176,7 @@ fn compile_fail_miri(opt: bool) { compile_fail(&sysroot, "tests/compile-fail-fullmir", &host, &host, true, opt); } -#[test] -fn test() { +fn test_runner(_tests: &[&()]) { // We put everything into a single test to avoid the parallelism `cargo test` // introduces. We still get parallelism within our tests because `compiletest` // uses `libtest` which runs jobs in parallel. From 97302e86c29cea97863cb1c977366c696d681755 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 9 Nov 2018 11:51:39 +0100 Subject: [PATCH 0346/3747] remove unused import --- tests/compiletest.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/compiletest.rs b/tests/compiletest.rs index 5771478cb557a..7644ab1dd723b 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -3,7 +3,6 @@ use std::slice::SliceConcatExt; use std::path::{PathBuf, Path}; -use std::io::Write; use std::env; use compiletest_rs as compiletest; From 54307cd88847e099b021cad788b51013d1453820 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 9 Nov 2018 14:04:22 +0100 Subject: [PATCH 0347/3747] bump compiletest so that we can share the tempdir() call --- Cargo.toml | 2 +- tests/compiletest.rs | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 390efe0a073a1..94d13a83fafd5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -46,5 +46,5 @@ cargo_miri = ["cargo_metadata"] rustc_tests = [] [dev-dependencies] -compiletest_rs = { version = "0.3.16", features = ["tmp"] } +compiletest_rs = { version = "0.3.17", features = ["tmp"] } colored = "1.6" diff --git a/tests/compiletest.rs b/tests/compiletest.rs index 7644ab1dd723b..55eaa7bfbab68 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -29,8 +29,8 @@ fn have_fullmir() -> bool { std::env::var("MIRI_SYSROOT").is_ok() || rustc_test_suite().is_some() } -fn mk_config(mode: &str) -> compiletest::Config { - let mut config = compiletest::Config::default(); +fn mk_config(mode: &str) -> compiletest::common::ConfigWithTemp { + let mut config = compiletest::Config::default().tempdir(); config.mode = mode.parse().expect("Invalid mode"); config.rustc_path = miri_path(); if rustc_test_suite().is_some() { @@ -74,7 +74,7 @@ fn compile_fail(sysroot: &Path, path: &str, target: &str, host: &str, need_fullm config.target = target.to_owned(); config.host = host.to_owned(); config.target_rustcflags = Some(flags.join(" ")); - compiletest::run_tests(&config.tempdir()); // FIXME: `tempdir` can be done by `mk_config` once `ConfigWithTemp` is exposed as type from compiletest + compiletest::run_tests(&config); } fn miri_pass(sysroot: &Path, path: &str, target: &str, host: &str, need_fullmir: bool, opt: bool) { @@ -107,7 +107,7 @@ fn miri_pass(sysroot: &Path, path: &str, target: &str, host: &str, need_fullmir: config.target = target.to_owned(); config.host = host.to_owned(); config.target_rustcflags = Some(flags.join(" ")); - compiletest::run_tests(&config.tempdir()); // FIXME: `tempdir` can be done by `mk_config` once `ConfigWithTemp` is exposed as type from compiletest + compiletest::run_tests(&config); } fn is_target_dir>(path: P) -> bool { From f233dc0687143025d375fbc3d3ea64f17ecd7d99 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 11 Nov 2018 10:12:44 +0100 Subject: [PATCH 0348/3747] Rc should be fixed --- tests/run-pass/rc.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/tests/run-pass/rc.rs b/tests/run-pass/rc.rs index f4a8855bea2f2..0bf7075031120 100644 --- a/tests/run-pass/rc.rs +++ b/tests/run-pass/rc.rs @@ -1,6 +1,3 @@ -// FIXME: Disabled due to https://github.com/rust-lang/rust/issues/55747 -// ignore-test - use std::cell::RefCell; use std::rc::Rc; From e7aa5c68ffc221ee07d37ee1d29b96282729b7fe Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 12 Nov 2018 08:54:12 +0100 Subject: [PATCH 0349/3747] Update rustc for AllocationExtra trait Based on https://github.com/solson/miri/pull/493 but there were more conflicts than code so I opted not to cherry-pick. --- rust-version | 2 +- src/lib.rs | 18 ------------------ src/stacked_borrows.rs | 19 +++++++++++-------- 3 files changed, 12 insertions(+), 27 deletions(-) diff --git a/rust-version b/rust-version index 0ad815872411a..fb6d167ec6422 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -nightly-2018-11-08 +nightly-2018-11-12 diff --git a/src/lib.rs b/src/lib.rs index 134986c814de0..ab34841df89e2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -446,24 +446,6 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { Cow::Owned(alloc) } - #[inline(always)] - fn memory_read( - alloc: &Allocation, - ptr: Pointer, - size: Size, - ) -> EvalResult<'tcx> { - alloc.extra.memory_read(ptr, size) - } - - #[inline(always)] - fn memory_written( - alloc: &mut Allocation, - ptr: Pointer, - size: Size, - ) -> EvalResult<'tcx> { - alloc.extra.memory_written(ptr, size) - } - #[inline(always)] fn memory_deallocated( alloc: &mut Allocation, diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index e1abcb20af756..475033d74c66c 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -5,7 +5,7 @@ use rustc::hir; use crate::{ EvalResult, MiriEvalContext, HelpersEvalContextExt, - MemoryKind, MiriMemoryKind, RangeMap, AllocId, + MemoryKind, MiriMemoryKind, RangeMap, AllocId, Allocation, AllocationExtra, Pointer, PlaceTy, MPlaceTy, }; @@ -343,27 +343,30 @@ impl<'tcx> Stacks { } /// Hooks and glue -impl<'tcx> Stacks { +impl AllocationExtra for Stacks { #[inline(always)] - pub fn memory_read( - &self, + fn memory_read<'tcx>( + alloc: &Allocation, ptr: Pointer, size: Size, ) -> EvalResult<'tcx> { // Reads behave exactly like the first half of a reborrow-to-shr - self.use_and_maybe_re_borrow(ptr, size, UsageKind::Read, None) + alloc.extra.use_and_maybe_re_borrow(ptr, size, UsageKind::Read, None) } #[inline(always)] - pub fn memory_written( - &mut self, + fn memory_written<'tcx>( + alloc: &mut Allocation, ptr: Pointer, size: Size, ) -> EvalResult<'tcx> { // Writes behave exactly like the first half of a reborrow-to-mut - self.use_and_maybe_re_borrow(ptr, size, UsageKind::Write, None) + alloc.extra.use_and_maybe_re_borrow(ptr, size, UsageKind::Write, None) } +} +impl<'tcx> Stacks { + #[inline(always)] pub fn memory_deallocated( &mut self, ptr: Pointer, From f37fc5eb7a527124dedb29d75e4f85eb0335c44a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 12 Nov 2018 20:20:35 +0100 Subject: [PATCH 0350/3747] cargo miri test currently does not work --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 94b5f8fea79d9..3c695fbc676af 100644 --- a/README.md +++ b/README.md @@ -70,7 +70,9 @@ compile your project and its dependencies against that libstd: 1. Run `cargo clean` to eliminate any cached dependencies that were built against the non-MIR `libstd`. 2. To run all tests in your project through, Miri, use -`MIRI_SYSROOT=~/.xargo/HOST cargo +nightly miri test`. +`MIRI_SYSROOT=~/.xargo/HOST cargo +nightly miri test`. **NOTE**: This is +currently broken, see the discussion in +[#479](https://github.com/solson/miri/issues/479). 3. If you have a binary project, you can run it through Miri using `MIRI_SYSROOT=~/.xargo/HOST cargo +nightly miri`. From c81e45f73afaccca991de35e14c8e2ae77b98a9b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 13 Nov 2018 13:28:09 +0100 Subject: [PATCH 0351/3747] add a description of what miri can do for you --- README.md | 35 ++++++++++++++++++++++++++--------- 1 file changed, 26 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 3c695fbc676af..919c31177f580 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,33 @@ # Miri [[slides](https://solson.me/miri-slides.pdf)] [[report](https://solson.me/miri-report.pdf)] [![Build Status](https://travis-ci.org/solson/miri.svg?branch=master)](https://travis-ci.org/solson/miri) [![Windows build status](https://ci.appveyor.com/api/projects/status/github/solson/miri?svg=true)](https://ci.appveyor.com/project/solson63299/miri) -An experimental interpreter for [Rust][rust]'s [mid-level intermediate -representation][mir] (MIR). This project began as part of my work for the -undergraduate research course at the [University of Saskatchewan][usask]. +An experimental interpreter for [Rust][rust]'s +[mid-level intermediate representation][mir] (MIR). It can run binaries and +test suites of cargo projects and detect certain classes of undefined behavior, +for example: + +* Out-of-bounds memory accesses and use-after-free +* Invalid use of uninitialized data +* Violation of intrinsic preconditions (an [`unreachable_unchecked`] being + reached, calling [`copy_nonoverlapping`] with overlapping ranges, ...) +* Not sufficiently aligned memory accesses and references +* Violation of basic type invariants (a `bool` that is not 0 or 1, for example, + or an invalid enum discriminant) +* WIP: Violations of the rules governing aliasing for reference types + +This project began as part of an undergraduate research course at the +[University of Saskatchewan][usask]. + + +[rust]: https://www.rust-lang.org/ +[mir]: https://github.com/rust-lang/rfcs/blob/master/text/1211-mir.md +[usask]: https://www.usask.ca/ +[`unreachable_unchecked`]: https://doc.rust-lang.org/stable/std/hint/fn.unreachable_unchecked.html +[`copy_nonoverlapping`]: https://doc.rust-lang.org/stable/std/ptr/fn.copy_nonoverlapping.html ## Building Miri -We recommend that you install [rustup][rustup] to obtain Rust. Then all you have +We recommend that you install [rustup] to obtain Rust. Then all you have to do is: ```sh @@ -25,6 +45,8 @@ To avoid repeating the nightly version all the time, you can use which means `nightly` Rust will automatically be used whenever you are working in this directory. +[rustup]: https://www.rustup.rs + ## Running Miri ```sh @@ -188,8 +210,3 @@ Licensed under either of Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you shall be dual licensed as above, without any additional terms or conditions. - -[rust]: https://www.rust-lang.org/ -[mir]: https://github.com/rust-lang/rfcs/blob/master/text/1211-mir.md -[usask]: https://www.usask.ca/ -[rustup]: https://www.rustup.rs From 8368fe89bc9c9bc15b11050b99408e36c2b7e55e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 13 Nov 2018 14:16:08 +0100 Subject: [PATCH 0352/3747] miri history --- README.md | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 919c31177f580..dece1c8f72fe5 100644 --- a/README.md +++ b/README.md @@ -15,13 +15,8 @@ for example: or an invalid enum discriminant) * WIP: Violations of the rules governing aliasing for reference types -This project began as part of an undergraduate research course at the -[University of Saskatchewan][usask]. - - [rust]: https://www.rust-lang.org/ [mir]: https://github.com/rust-lang/rfcs/blob/master/text/1211-mir.md -[usask]: https://www.usask.ca/ [`unreachable_unchecked`]: https://doc.rust-lang.org/stable/std/hint/fn.unreachable_unchecked.html [`copy_nonoverlapping`]: https://doc.rust-lang.org/stable/std/ptr/fn.copy_nonoverlapping.html @@ -197,6 +192,23 @@ needs to be done that I haven't documented in the issues yet, however. For more ideas or help with running or hacking on Miri, you can contact me (`scott`) on Mozilla IRC in any of the Rust IRC channels (`#rust`, `#rust-offtopic`, etc). +## History + +This project began as part of an undergraduate research course in 2015 by +@solson at the [University of Saskatchewan][usask]. In 2016, @oli-obk joined to +prepare miri for eventually being used as const evaluator in the Rust compiler +itself (basically, for `const` and `static` stuff), replacing the old evaluator +that worked directly on the AST. In 2017, @RalfJung did an internship with +Mozilla and began developing miri towards a tool for detecting undefined +behavior, and also using miri as a way to explore the consequences of various +possible definitions for undefined behavior in Rust. @oli-obk's move of the +miri engine into the compiler finally came to completion in early 2018. +Meanwhile, later that year, @RalfJung did a second internship, developing miri +further with support for checking basic type invariants and verifying that +references are used according to their aliasing restrictions. + +[usask]: https://www.usask.ca/ + ## License Licensed under either of From bf3e376049d122ca47d692cca8cff7134a9746f4 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 14 Nov 2018 08:23:43 +0100 Subject: [PATCH 0353/3747] move slide and report links to history --- README.md | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index dece1c8f72fe5..04a263597c0b2 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Miri [[slides](https://solson.me/miri-slides.pdf)] [[report](https://solson.me/miri-report.pdf)] [![Build Status](https://travis-ci.org/solson/miri.svg?branch=master)](https://travis-ci.org/solson/miri) [![Windows build status](https://ci.appveyor.com/api/projects/status/github/solson/miri?svg=true)](https://ci.appveyor.com/project/solson63299/miri) +# Miri [![Build Status](https://travis-ci.org/solson/miri.svg?branch=master)](https://travis-ci.org/solson/miri) [![Windows build status](https://ci.appveyor.com/api/projects/status/github/solson/miri?svg=true)](https://ci.appveyor.com/project/solson63299/miri) An experimental interpreter for [Rust][rust]'s @@ -195,19 +195,22 @@ Mozilla IRC in any of the Rust IRC channels (`#rust`, `#rust-offtopic`, etc). ## History This project began as part of an undergraduate research course in 2015 by -@solson at the [University of Saskatchewan][usask]. In 2016, @oli-obk joined to -prepare miri for eventually being used as const evaluator in the Rust compiler -itself (basically, for `const` and `static` stuff), replacing the old evaluator -that worked directly on the AST. In 2017, @RalfJung did an internship with -Mozilla and began developing miri towards a tool for detecting undefined -behavior, and also using miri as a way to explore the consequences of various -possible definitions for undefined behavior in Rust. @oli-obk's move of the -miri engine into the compiler finally came to completion in early 2018. -Meanwhile, later that year, @RalfJung did a second internship, developing miri -further with support for checking basic type invariants and verifying that -references are used according to their aliasing restrictions. +@solson at the [University of Saskatchewan][usask]. There are [slides] and a +[report] available from that project. In 2016, @oli-obk joined to prepare miri +for eventually being used as const evaluator in the Rust compiler itself +(basically, for `const` and `static` stuff), replacing the old evaluator that +worked directly on the AST. In 2017, @RalfJung did an internship with Mozilla +and began developing miri towards a tool for detecting undefined behavior, and +also using miri as a way to explore the consequences of various possible +definitions for undefined behavior in Rust. @oli-obk's move of the miri engine +into the compiler finally came to completion in early 2018. Meanwhile, later +that year, @RalfJung did a second internship, developing miri further with +support for checking basic type invariants and verifying that references are +used according to their aliasing restrictions. [usask]: https://www.usask.ca/ +[slides]: https://solson.me/miri-slides.pdf +[report]: https://solson.me/miri-report.pdf ## License From f5bd85d009536dfb587991e611ab5211f2bb3f10 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 14 Nov 2018 16:03:38 +0100 Subject: [PATCH 0354/3747] update for memory_deallocated moving to AllocExtra --- src/lib.rs | 9 --------- src/stacked_borrows.rs | 10 +++++----- 2 files changed, 5 insertions(+), 14 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index ab34841df89e2..b7deb8ee11609 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -446,15 +446,6 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { Cow::Owned(alloc) } - #[inline(always)] - fn memory_deallocated( - alloc: &mut Allocation, - ptr: Pointer, - size: Size, - ) -> EvalResult<'tcx> { - alloc.extra.memory_deallocated(ptr, size) - } - #[inline(always)] fn tag_reference( ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 475033d74c66c..c6cd7f5005d2a 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -363,20 +363,20 @@ impl AllocationExtra for Stacks { // Writes behave exactly like the first half of a reborrow-to-mut alloc.extra.use_and_maybe_re_borrow(ptr, size, UsageKind::Write, None) } -} -impl<'tcx> Stacks { #[inline(always)] - pub fn memory_deallocated( - &mut self, + fn memory_deallocated<'tcx>( + alloc: &mut Allocation, ptr: Pointer, size: Size, ) -> EvalResult<'tcx> { // This is like mutating - self.use_and_maybe_re_borrow(ptr, size, UsageKind::Write, None) + alloc.extra.use_and_maybe_re_borrow(ptr, size, UsageKind::Write, None) // FIXME: Error out of there are any barriers? } +} +impl<'tcx> Stacks { /// Pushes the first item to the stacks. pub fn first_item( &mut self, From 5120abc0c65540b25a0d69768a462e269fc402a8 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 15 Nov 2018 08:49:51 +0100 Subject: [PATCH 0355/3747] bump Rust --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index fb6d167ec6422..a829ec0f5a0a1 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -nightly-2018-11-12 +nightly-2018-11-15 From 1e51a382edcebf72ef50995cf2450b05f9f0270b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 15 Nov 2018 09:09:48 +0100 Subject: [PATCH 0356/3747] update for changed FrameInfo, do not print span for all frames --- src/lib.rs | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index b7deb8ee11609..f0b59d03945bb 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -23,7 +23,7 @@ use rustc::hir::{self, def_id::DefId}; use rustc::mir; use syntax::attr; - +use syntax::source_map::DUMMY_SP; pub use rustc_mir::interpret::*; pub use rustc_mir::interpret::{self, AllocMap, PlaceTy}; // resolve ambiguity @@ -113,7 +113,7 @@ pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( // Push our stack frame ecx.push_stack_frame( start_instance, - start_mir.span, + DUMMY_SP, // there is no call site, we want no span start_mir, Some(ret_ptr.into()), StackPopCleanup::None { cleanup: true }, @@ -146,7 +146,7 @@ pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( let ret_place = MPlaceTy::dangling(ecx.layout_of(tcx.mk_unit())?, &ecx).into(); ecx.push_stack_frame( main_instance, - main_mir.span, + DUMMY_SP, // there is no call site, we want no span main_mir, Some(ret_place), StackPopCleanup::None { cleanup: true }, @@ -185,7 +185,7 @@ pub fn eval_main<'a, 'tcx: 'a>( match res { Ok(()) => { let leaks = ecx.memory().leak_report(); - // Disable the leak test on some platforms where we likely do not + // Disable the leak test on some platforms where we do not // correctly implement TLS destructors. let target_os = ecx.tcx.tcx.sess.target.target.target_os.to_lowercase(); let ignore_leaks = target_os == "windows" || target_os == "macos"; @@ -208,8 +208,16 @@ pub fn eval_main<'a, 'tcx: 'a>( let mut err = struct_error(ecx.tcx.tcx.at(span), msg.as_str()); let frames = ecx.generate_stacktrace(None); err.span_label(span, e); - for FrameInfo { span, location, .. } in frames { - err.span_note(span, &format!("inside call to `{}`", location)); + // we iterate with indices because we need to look at the next frame (the caller) + for idx in 0..frames.len() { + let frame_info = &frames[idx]; + let call_site_is_local = frames.get(idx+1).map_or(false, + |caller_info| caller_info.instance.def_id().is_local()); + if call_site_is_local { + err.span_note(frame_info.call_site, &frame_info.to_string()); + } else { + err.note(&frame_info.to_string()); + } } err.emit(); } else { From 09919c2b596b19ad36850b77d8f6ea00b3b60612 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 7 Nov 2018 14:56:25 +0100 Subject: [PATCH 0357/3747] Retag is the only operation that generates new tags --- .gitignore | 1 - src/fn_call.rs | 2 +- src/intrinsic.rs | 22 +-- src/lib.rs | 58 ++++---- src/stacked_borrows.rs | 127 +++++++++++------- .../stacked_borrows/buggy_as_mut_slice.rs | 8 +- .../stacked_borrows/buggy_split_at_mut.rs | 2 +- .../static_memory_modification.rs | 3 + .../stacked_borrows/transmute-is-no-escape.rs | 12 ++ .../stacked_borrows/unescaped_local.rs | 8 +- tests/run-pass/stacked-borrows.rs | 20 ++- 11 files changed, 161 insertions(+), 102 deletions(-) create mode 100644 tests/compile-fail/stacked_borrows/transmute-is-no-escape.rs diff --git a/.gitignore b/.gitignore index dcca7ec10a30d..ca23de4208823 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,5 @@ target /doc tex/*/out *.dot -*.mir *.rs.bk Cargo.lock diff --git a/src/fn_call.rs b/src/fn_call.rs index d9bf049df704a..150cf7402a6dd 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -555,7 +555,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo } "pthread_attr_getstack" => { // second argument is where we are supposed to write the stack size - let ptr = self.ref_to_mplace(self.read_immediate(args[1])?)?; + let ptr = self.deref_operand(args[1])?; let stackaddr = Scalar::from_int(0x80000, args[1].layout.size); // just any address self.write_scalar(stackaddr, ptr.into())?; // return 0 diff --git a/src/intrinsic.rs b/src/intrinsic.rs index 20402f4a23293..e23cadfcaf0b7 100644 --- a/src/intrinsic.rs +++ b/src/intrinsic.rs @@ -59,7 +59,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' "atomic_load_relaxed" | "atomic_load_acq" | "volatile_load" => { - let ptr = self.ref_to_mplace(self.read_immediate(args[0])?)?; + let ptr = self.deref_operand(args[0])?; let val = self.read_scalar(ptr.into())?; // make sure it fits into a scalar; otherwise it cannot be atomic self.write_scalar(val, dest)?; } @@ -68,7 +68,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' "atomic_store_relaxed" | "atomic_store_rel" | "volatile_store" => { - let ptr = self.ref_to_mplace(self.read_immediate(args[0])?)?; + let ptr = self.deref_operand(args[0])?; let val = self.read_scalar(args[1])?; // make sure it fits into a scalar; otherwise it cannot be atomic self.write_scalar(val, ptr.into())?; } @@ -78,7 +78,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' } _ if intrinsic_name.starts_with("atomic_xchg") => { - let ptr = self.ref_to_mplace(self.read_immediate(args[0])?)?; + let ptr = self.deref_operand(args[0])?; let new = self.read_scalar(args[1])?; let old = self.read_scalar(ptr.into())?; self.write_scalar(old, dest)?; // old value is returned @@ -86,10 +86,10 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' } _ if intrinsic_name.starts_with("atomic_cxchg") => { - let ptr = self.ref_to_mplace(self.read_immediate(args[0])?)?; - let expect_old = self.read_immediate(args[1])?; // read as value for the sake of `binary_op_imm()` + let ptr = self.deref_operand(args[0])?; + let expect_old = self.read_immediate(args[1])?; // read as immediate for the sake of `binary_op_imm()` let new = self.read_scalar(args[2])?; - let old = self.read_immediate(ptr.into())?; // read as value for the sake of `binary_op_imm()` + let old = self.read_immediate(ptr.into())?; // read as immediate for the sake of `binary_op_imm()` // binary_op_imm will bail if either of them is not a scalar let (eq, _) = self.binary_op_imm(mir::BinOp::Eq, old, expect_old)?; let res = Immediate::ScalarPair(old.to_scalar_or_undef(), eq.into()); @@ -125,7 +125,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' "atomic_xsub_rel" | "atomic_xsub_acqrel" | "atomic_xsub_relaxed" => { - let ptr = self.ref_to_mplace(self.read_immediate(args[0])?)?; + let ptr = self.deref_operand(args[0])?; if !ptr.layout.ty.is_integral() { return err!(Unimplemented(format!("Atomic arithmetic operations only work on integer types"))); } @@ -167,7 +167,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' } "discriminant_value" => { - let place = self.ref_to_mplace(self.read_immediate(args[0])?)?; + let place = self.deref_operand(args[0])?; let discr_val = self.read_discriminant(place.into())?.0; self.write_scalar(Scalar::from_uint(discr_val, dest.layout.size), dest)?; } @@ -279,7 +279,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' } "move_val_init" => { - let ptr = self.ref_to_mplace(self.read_immediate(args[0])?)?; + let ptr = self.deref_operand(args[0])?; self.copy_op(args[1], ptr.into())?; } @@ -347,7 +347,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' } "size_of_val" => { - let mplace = self.ref_to_mplace(self.read_immediate(args[0])?)?; + let mplace = self.deref_operand(args[0])?; let (size, _) = self.size_and_align_of_mplace(mplace)? .expect("size_of_val called on extern type"); let ptr_size = self.pointer_size(); @@ -359,7 +359,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' "min_align_of_val" | "align_of_val" => { - let mplace = self.ref_to_mplace(self.read_immediate(args[0])?)?; + let mplace = self.deref_operand(args[0])?; let (_, align) = self.size_and_align_of_mplace(mplace)? .expect("size_of_val called on extern type"); let ptr_size = self.pointer_size(); diff --git a/src/lib.rs b/src/lib.rs index b7deb8ee11609..e8691409b1ab4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -296,7 +296,6 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { type AllocExtra = stacked_borrows::Stacks; type PointerTag = Borrow; - const ENABLE_PTR_TRACKING_HOOKS: bool = true; type MemoryMap = MonoHashMap, Allocation)>; @@ -446,26 +445,6 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { Cow::Owned(alloc) } - #[inline(always)] - fn tag_reference( - ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, - place: MPlaceTy<'tcx, Borrow>, - mutability: Option, - ) -> EvalResult<'tcx, Scalar> { - let (size, _) = ecx.size_and_align_of_mplace(place)? - // for extern types, just cover what we can - .unwrap_or_else(|| place.layout.size_and_align()); - if !ecx.machine.validate || size == Size::ZERO { - // No tracking - Ok(place.ptr) - } else { - let ptr = place.ptr.to_ptr()?; - let tag = ecx.tag_reference(place, size, mutability.into())?; - Ok(Scalar::Ptr(Pointer::new_with_tag(ptr.alloc_id, ptr.offset, tag))) - } - } - - #[inline(always)] fn tag_dereference( ecx: &EvalContext<'a, 'mir, 'tcx, Self>, place: MPlaceTy<'tcx, Borrow>, @@ -478,7 +457,7 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { // No tracking Ok(place.ptr) } else { - let ptr = place.ptr.to_ptr()?; + let ptr = place.ptr.to_ptr()?; // assert this is not a scalar let tag = ecx.tag_dereference(place, size, mutability.into())?; Ok(Scalar::Ptr(Pointer::new_with_tag(ptr.alloc_id, ptr.offset, tag))) } @@ -499,6 +478,31 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { } } + #[inline] + fn escape_to_raw( + ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, + ptr: OpTy<'tcx, Self::PointerTag>, + ) -> EvalResult<'tcx> { + // It is tempting to check the type here, but drop glue does EscapeToRaw + // on a raw pointer. + // This is deliberately NOT `deref_operand` as we do not want `tag_dereference` + // to be called! That would kill the original tag if we got a raw ptr. + let place = ecx.ref_to_mplace(ecx.read_immediate(ptr)?)?; + let (size, _) = ecx.size_and_align_of_mplace(place)? + // for extern types, just cover what we can + .unwrap_or_else(|| place.layout.size_and_align()); + if !ecx.tcx.sess.opts.debugging_opts.mir_emit_retag || + !ecx.machine.validate || size == Size::ZERO + { + // No tracking, or no retagging. The latter is possible because a dependency of ours + // might be called with different flags than we are, so there are `Retag` + // statements but we do not want to execute them. + Ok(()) + } else { + ecx.escape_to_raw(place, size) + } + } + #[inline(always)] fn retag( ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, @@ -506,12 +510,14 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { place: PlaceTy<'tcx, Borrow>, ) -> EvalResult<'tcx> { if !ecx.tcx.sess.opts.debugging_opts.mir_emit_retag || !Self::enforce_validity(ecx) { - // No tracking, or no retagging. This is possible because a dependency of ours might be - // called with different flags than we are, + // No tracking, or no retagging. The latter is possible because a dependency of ours + // might be called with different flags than we are, so there are `Retag` + // statements but we do not want to execute them. // Also, honor the whitelist in `enforce_validity` because otherwise we might retag // uninitialized data. - return Ok(()) + Ok(()) + } else { + ecx.retag(fn_entry, place) } - ecx.retag(fn_entry, place) } } diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index c6cd7f5005d2a..e7c595f1c6ccc 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -6,7 +6,7 @@ use rustc::hir; use crate::{ EvalResult, MiriEvalContext, HelpersEvalContextExt, MemoryKind, MiriMemoryKind, RangeMap, AllocId, Allocation, AllocationExtra, - Pointer, PlaceTy, MPlaceTy, + Pointer, MemPlace, Scalar, Immediate, ImmTy, PlaceTy, MPlaceTy, }; pub type Timestamp = u64; @@ -395,13 +395,6 @@ impl<'tcx> Stacks { pub trait EvalContextExt<'tcx> { - fn tag_reference( - &mut self, - place: MPlaceTy<'tcx, Borrow>, - size: Size, - usage: UsageKind, - ) -> EvalResult<'tcx, Borrow>; - fn tag_dereference( &self, place: MPlaceTy<'tcx, Borrow>, @@ -415,47 +408,27 @@ pub trait EvalContextExt<'tcx> { kind: MemoryKind, ) -> Borrow; + /// Retag an indidual pointer, returning the retagged version. + fn retag_ptr( + &mut self, + ptr: ImmTy<'tcx, Borrow>, + mutbl: hir::Mutability, + ) -> EvalResult<'tcx, Immediate>; + fn retag( &mut self, fn_entry: bool, place: PlaceTy<'tcx, Borrow> ) -> EvalResult<'tcx>; -} -impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for MiriEvalContext<'a, 'mir, 'tcx> { - /// Called for place-to-value conversion. - fn tag_reference( + fn escape_to_raw( &mut self, place: MPlaceTy<'tcx, Borrow>, size: Size, - usage: UsageKind, - ) -> EvalResult<'tcx, Borrow> { - let ptr = place.ptr.to_ptr()?; - let time = self.machine.stacked_borrows.increment_clock(); - let new_bor = match usage { - UsageKind::Write => Borrow::Uniq(time), - UsageKind::Read => Borrow::Shr(Some(time)), - UsageKind::Raw => Borrow::Shr(None), - }; - trace!("tag_reference: Creating new reference ({:?}) for {:?} (pointee {}): {:?}", - usage, ptr, place.layout.ty, new_bor); - - // Update the stacks. First create the new ref as usual, then maybe freeze stuff. - self.memory().check_bounds(ptr, size, false)?; - let alloc = self.memory().get(ptr.alloc_id).expect("We checked that the ptr is fine!"); - alloc.extra.use_and_maybe_re_borrow(ptr, size, usage, Some(new_bor))?; - // Maybe freeze stuff - if let Borrow::Shr(Some(bor_t)) = new_bor { - self.visit_frozen(place, size, |frz_ptr, size| { - debug_assert_eq!(frz_ptr.alloc_id, ptr.alloc_id); - // Be frozen! - alloc.extra.freeze(frz_ptr, size, bor_t) - })?; - } - - Ok(new_bor) - } + ) -> EvalResult<'tcx>; +} +impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for MiriEvalContext<'a, 'mir, 'tcx> { /// Called for value-to-place conversion. /// /// Note that this does NOT mean that all this memory will actually get accessed/referenced! @@ -466,9 +439,9 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for MiriEvalContext<'a, 'mir, 'tcx> { size: Size, usage: UsageKind, ) -> EvalResult<'tcx, Borrow> { - let ptr = place.ptr.to_ptr()?; trace!("tag_dereference: Accessing reference ({:?}) for {:?} (pointee {})", - usage, ptr, place.layout.ty); + usage, place.ptr, place.layout.ty); + let ptr = place.ptr.to_ptr()?; // In principle we should not have to do anything here. However, with transmutes involved, // it can happen that the tag of `ptr` does not actually match `usage`, and we // should adjust for that. @@ -551,6 +524,50 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for MiriEvalContext<'a, 'mir, 'tcx> { Borrow::Uniq(time) } + fn retag_ptr( + &mut self, + val: ImmTy<'tcx, Borrow>, + mutbl: hir::Mutability, + ) -> EvalResult<'tcx, Immediate> { + // We want a place for where the ptr *points to*, so we get one. + let place = self.ref_to_mplace(val)?; + let size = self.size_and_align_of_mplace(place)? + .map(|(size, _)| size) + .unwrap_or_else(|| place.layout.size); + if size == Size::ZERO { + // Nothing to do for ZSTs. + return Ok(*val); + } + + // Prepare to re-borrow this place. + let ptr = place.ptr.to_ptr()?; + let time = self.machine.stacked_borrows.increment_clock(); + let new_bor = match mutbl { + hir::MutMutable => Borrow::Uniq(time), + hir::MutImmutable => Borrow::Shr(Some(time)), + }; + trace!("retag: Creating new reference ({:?}) for {:?} (pointee {}): {:?}", + mutbl, ptr, place.layout.ty, new_bor); + + // Update the stacks. First create a new borrow, then maybe freeze stuff. + self.memory().check_bounds(ptr, size, false)?; // `ptr_dereference` wouldn't do any checks if this is a raw ptr + let alloc = self.memory().get(ptr.alloc_id).expect("We checked that the ptr is fine!"); + alloc.extra.use_and_maybe_re_borrow(ptr, size, Some(mutbl).into(), Some(new_bor))?; + // Maybe freeze stuff + if let Borrow::Shr(Some(bor_t)) = new_bor { + self.visit_frozen(place, size, |frz_ptr, size| { + debug_assert_eq!(frz_ptr.alloc_id, ptr.alloc_id); + // Be frozen! + alloc.extra.freeze(frz_ptr, size, bor_t) + })?; + } + + // Compute the new value and return that + let new_ptr = Scalar::Ptr(Pointer::new_with_tag(ptr.alloc_id, ptr.offset, new_bor)); + let new_place = MemPlace { ptr: new_ptr, ..*place }; + Ok(new_place.to_ref()) + } + fn retag( &mut self, _fn_entry: bool, @@ -558,20 +575,30 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for MiriEvalContext<'a, 'mir, 'tcx> { ) -> EvalResult<'tcx> { // For now, we only retag if the toplevel type is a reference. // TODO: Recurse into structs and enums, sharing code with validation. + // TODO: Honor `fn_entry`. let mutbl = match place.layout.ty.sty { ty::Ref(_, _, mutbl) => mutbl, // go ahead - _ => return Ok(()), // don't do a thing + _ => return Ok(()), // do nothing, for now }; - // We want to reborrow the reference stored there. This will call the hooks - // above. First deref, which will call `tag_dereference`. - // (This is somewhat redundant because validation already did the same thing, - // but what can you do.) + // Retag the pointer and write it back. let val = self.read_immediate(self.place_to_op(place)?)?; - let dest = self.ref_to_mplace(val)?; - // Now put a new ref into the old place, which will call `tag_reference`. - // FIXME: Honor `fn_entry`! - let val = self.create_ref(dest, Some(mutbl))?; + let val = self.retag_ptr(val, mutbl)?; self.write_immediate(val, place)?; Ok(()) } + + fn escape_to_raw( + &mut self, + place: MPlaceTy<'tcx, Borrow>, + size: Size, + ) -> EvalResult<'tcx> { + trace!("self: {:?} is now accessible by raw pointers", *place); + // Re-borrow to raw. This is a NOP for shared borrows, but we do not know the borrow + // type here and that's also okay. + let ptr = place.ptr.to_ptr()?; + self.memory().check_bounds(ptr, size, false)?; // `ptr_dereference` wouldn't do any checks if this is a raw ptr + let alloc = self.memory().get(ptr.alloc_id).expect("We checked that the ptr is fine!"); + alloc.extra.use_and_maybe_re_borrow(ptr, size, UsageKind::Raw, Some(Borrow::default()))?; + Ok(()) + } } diff --git a/tests/compile-fail/stacked_borrows/buggy_as_mut_slice.rs b/tests/compile-fail/stacked_borrows/buggy_as_mut_slice.rs index 4857ada7fb2c7..2f3d0793f63e1 100644 --- a/tests/compile-fail/stacked_borrows/buggy_as_mut_slice.rs +++ b/tests/compile-fail/stacked_borrows/buggy_as_mut_slice.rs @@ -1,4 +1,4 @@ -#![allow(unused_variables)] +// error-pattern: mutable reference with frozen tag mod safe { use std::slice::from_raw_parts_mut; @@ -12,8 +12,10 @@ mod safe { fn main() { let v = vec![0,1,2]; - let v1 = safe::as_mut_slice(&v); + let _v1 = safe::as_mut_slice(&v); +/* let v2 = safe::as_mut_slice(&v); - v1[1] = 5; //~ ERROR does not exist on the stack + v1[1] = 5; v1[1] = 6; +*/ } diff --git a/tests/compile-fail/stacked_borrows/buggy_split_at_mut.rs b/tests/compile-fail/stacked_borrows/buggy_split_at_mut.rs index a6daa5d93d772..711544f80149c 100644 --- a/tests/compile-fail/stacked_borrows/buggy_split_at_mut.rs +++ b/tests/compile-fail/stacked_borrows/buggy_split_at_mut.rs @@ -11,7 +11,6 @@ mod safe { assert!(mid <= len); (from_raw_parts_mut(ptr, len - mid), // BUG: should be "mid" instead of "len - mid" - //~^ ERROR does not exist on the stack from_raw_parts_mut(ptr.offset(mid as isize), len - mid)) } } @@ -20,6 +19,7 @@ mod safe { fn main() { let mut array = [1,2,3,4]; let (a, b) = safe::split_at_mut(&mut array, 0); + //~^ ERROR does not exist on the stack a[1] = 5; b[1] = 6; } diff --git a/tests/compile-fail/stacked_borrows/static_memory_modification.rs b/tests/compile-fail/stacked_borrows/static_memory_modification.rs index c092cbfe50985..5c605eff67843 100644 --- a/tests/compile-fail/stacked_borrows/static_memory_modification.rs +++ b/tests/compile-fail/stacked_borrows/static_memory_modification.rs @@ -1,3 +1,6 @@ +// FIXME still considering whether we are okay with this not being an error +// ignore-test + static X: usize = 5; #[allow(mutable_transmutes)] diff --git a/tests/compile-fail/stacked_borrows/transmute-is-no-escape.rs b/tests/compile-fail/stacked_borrows/transmute-is-no-escape.rs new file mode 100644 index 0000000000000..1ab005e3fa17d --- /dev/null +++ b/tests/compile-fail/stacked_borrows/transmute-is-no-escape.rs @@ -0,0 +1,12 @@ +// Make sure we cannot use raw ptrs that got transmuted from mutable references +// (i.e, no EscapeToRaw happened). +// We could, in principle, to EscapeToRaw lazily to allow this code, but that +// would no alleviate the need for EscapeToRaw (see `ref_raw_int_raw` in +// `run-pass/stacked-borrows.rs`), and thus increase overall complexity. +use std::mem; + +fn main() { + let mut x: i32 = 42; + let raw: *mut i32 = unsafe { mem::transmute(&mut x) }; + unsafe { *raw = 13; } //~ ERROR does not exist on the stack +} diff --git a/tests/compile-fail/stacked_borrows/unescaped_local.rs b/tests/compile-fail/stacked_borrows/unescaped_local.rs index 8627cc44c2e50..054697b04a09d 100644 --- a/tests/compile-fail/stacked_borrows/unescaped_local.rs +++ b/tests/compile-fail/stacked_borrows/unescaped_local.rs @@ -1,10 +1,8 @@ -use std::mem; - // Make sure we cannot use raw ptrs to access a local that -// has never been escaped to the raw world. +// we took the direct address of. fn main() { let mut x = 42; - let ptr = &mut x; - let raw: *mut i32 = unsafe { mem::transmute(ptr) }; + let raw = &mut x as *mut i32 as usize as *mut i32; + let _ptr = &mut x; unsafe { *raw = 13; } //~ ERROR does not exist on the stack } diff --git a/tests/run-pass/stacked-borrows.rs b/tests/run-pass/stacked-borrows.rs index 8faa4d6591156..adab2b5a5683a 100644 --- a/tests/run-pass/stacked-borrows.rs +++ b/tests/run-pass/stacked-borrows.rs @@ -3,15 +3,17 @@ fn main() { deref_partially_dangling_raw(); read_does_not_invalidate1(); read_does_not_invalidate2(); + ref_raw_int_raw(); } // Deref a raw ptr to access a field of a large struct, where the field // is allocated but not the entire struct is. // For now, we want to allow this. fn deref_partially_dangling_raw() { - let x = (1, 1); + let x = (1, 13); let xptr = &x as *const _ as *const (i32, i32, i32); - let _val = unsafe { (*xptr).1 }; + let val = unsafe { (*xptr).1 }; + assert_eq!(val, 13); } // Make sure that reading from an `&mut` does, like reborrowing to `&`, @@ -23,7 +25,7 @@ fn read_does_not_invalidate1() { let _val = x.1; // we just read, this does NOT invalidate the reborrows. ret } - foo(&mut (1, 2)); + assert_eq!(*foo(&mut (1, 2)), 2); } // Same as above, but this time we first create a raw, then read from `&mut` // and then freeze from the raw. @@ -34,5 +36,15 @@ fn read_does_not_invalidate2() { let ret = unsafe { &(*xraw).1 }; ret } - foo(&mut (1, 2)); + assert_eq!(*foo(&mut (1, 2)), 2); +} + +// Just to make sure that casting a ref to raw, to int and back to raw +// and only then using it works. This rules out ideas like "do escape-to-raw lazily": +// After casting to int and back, we lost the tag that could have let us do that. +fn ref_raw_int_raw() { + let mut x = 3; + let xref = &mut x; + let xraw = xref as *mut i32 as usize as *mut i32; + assert_eq!(unsafe { *xraw }, 3); } From 020313dd8506d3704a71d2ec1499f0e7ee93f3dd Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 7 Nov 2018 16:56:25 +0100 Subject: [PATCH 0358/3747] make freezing inherently part of the high-level reactivate/initiate operations --- src/helpers.rs | 35 +++++--- src/stacked_borrows.rs | 199 +++++++++++++++++++++-------------------- 2 files changed, 125 insertions(+), 109 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index 880b18c7d5426..31e2972957035 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -33,13 +33,13 @@ impl ScalarExt for ScalarMaybeUndef { pub trait EvalContextExt<'tcx> { fn resolve_path(&self, path: &[&str]) -> EvalResult<'tcx, ty::Instance<'tcx>>; - /// Visit the memory covered by `place` that is frozen -- i.e., NOT - /// what is inside an `UnsafeCell`. - fn visit_frozen( + /// Visit the memory covered by `place`, sensitive to freezing: The 3rd parameter + /// will be true if this is frozen, false if this is in an `UnsafeCell`. + fn visit_freeze_sensitive( &self, place: MPlaceTy<'tcx, Borrow>, size: Size, - action: impl FnMut(Pointer, Size) -> EvalResult<'tcx>, + action: impl FnMut(Pointer, Size, bool) -> EvalResult<'tcx>, ) -> EvalResult<'tcx>; } @@ -79,13 +79,11 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: }) } - /// Visit the memory covered by `place` that is frozen -- i.e., NOT - /// what is inside an `UnsafeCell`. - fn visit_frozen( + fn visit_freeze_sensitive( &self, place: MPlaceTy<'tcx, Borrow>, size: Size, - mut frozen_action: impl FnMut(Pointer, Size) -> EvalResult<'tcx>, + mut action: impl FnMut(Pointer, Size, bool) -> EvalResult<'tcx>, ) -> EvalResult<'tcx> { trace!("visit_frozen(place={:?}, size={:?})", *place, size); debug_assert_eq!(size, @@ -99,18 +97,29 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: let mut end_ptr = place.ptr; // Called when we detected an `UnsafeCell` at the given offset and size. // Calls `action` and advances `end_ptr`. - let mut unsafe_cell_action = |unsafe_cell_offset, unsafe_cell_size| { + let mut unsafe_cell_action = |unsafe_cell_ptr: Scalar, unsafe_cell_size: Size| { + if unsafe_cell_size != Size::ZERO { + debug_assert_eq!(unsafe_cell_ptr.to_ptr().unwrap().alloc_id, + end_ptr.to_ptr().unwrap().alloc_id); + debug_assert_eq!(unsafe_cell_ptr.to_ptr().unwrap().tag, + end_ptr.to_ptr().unwrap().tag); + } // We assume that we are given the fields in increasing offset order, // and nothing else changes. + let unsafe_cell_offset = unsafe_cell_ptr.get_ptr_offset(self); let end_offset = end_ptr.get_ptr_offset(self); assert!(unsafe_cell_offset >= end_offset); let frozen_size = unsafe_cell_offset - end_offset; // Everything between the end_ptr and this `UnsafeCell` is frozen. if frozen_size != Size::ZERO { - frozen_action(end_ptr.to_ptr()?, frozen_size)?; + action(end_ptr.to_ptr()?, frozen_size, /*frozen*/true)?; + } + // This `UnsafeCell` is NOT frozen. + if unsafe_cell_size != Size::ZERO { + action(unsafe_cell_ptr.to_ptr()?, unsafe_cell_size, /*frozen*/false)?; } // Update end end_ptr. - end_ptr = end_ptr.ptr_wrapping_offset(frozen_size+unsafe_cell_size, self); + end_ptr = unsafe_cell_ptr.ptr_wrapping_offset(unsafe_cell_size, self); // Done Ok(()) }; @@ -126,7 +135,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: .unwrap_or_else(|| place.layout.size_and_align()); // Now handle this `UnsafeCell`, unless it is empty. if unsafe_cell_size != Size::ZERO { - unsafe_cell_action(place.ptr.get_ptr_offset(self), unsafe_cell_size) + unsafe_cell_action(place.ptr, unsafe_cell_size) } else { Ok(()) } @@ -136,7 +145,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: } // The part between the end_ptr and the end of the place is also frozen. // So pretend there is a 0-sized `UnsafeCell` at the end. - unsafe_cell_action(place.ptr.get_ptr_offset(self) + size, Size::ZERO)?; + unsafe_cell_action(place.ptr.ptr_wrapping_offset(size, self), Size::ZERO)?; // Done! return Ok(()); diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index e7c595f1c6ccc..ab0c3f8994c51 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -217,10 +217,12 @@ impl<'tcx> Stack { /// Initiate `bor`; mostly this means pushing. /// This operation cannot fail; it is up to the caller to ensure that the precondition - /// is met: We cannot push onto frozen stacks. + /// is met: We cannot push `Uniq` onto frozen stacks. + /// Crucially, this makes pushing a `Shr` onto a frozen location a NOP. We do not want + /// such a location to get mutably shared this way! fn initiate(&mut self, bor: Borrow) { if let Some(_) = self.frozen_since { - // "Pushing" a Shr or Frz on top is redundant. + // A frozen location, we won't change anything here! match bor { Borrow::Uniq(_) => bug!("Trying to create unique ref to frozen location"), Borrow::Shr(_) => trace!("initiate: New shared ref to frozen location is a NOP"), @@ -272,39 +274,41 @@ impl State { /// Higher-level operations impl<'tcx> Stacks { - /// The single most important operation: Make sure that using `ptr` is okay, - /// and if `new_bor` is present then make that the new current borrow. - fn use_and_maybe_re_borrow( + /// `ptr` got used, reflect that in the stack. + fn reactivate( &self, ptr: Pointer, size: Size, usage: UsageKind, - new_bor: Option, ) -> EvalResult<'tcx> { - trace!("use_and_maybe_re_borrow of tag {:?} as {:?}, new {:?}: {:?}, size {}", - ptr.tag, usage, new_bor, ptr, size.bytes()); + trace!("use_borrow of tag {:?} as {:?}: {:?}, size {}", + ptr.tag, usage, ptr, size.bytes()); let mut stacks = self.stacks.borrow_mut(); for stack in stacks.iter_mut(ptr.offset, size) { stack.reactivate(ptr.tag, usage == UsageKind::Write)?; - if let Some(new_bor) = new_bor { - stack.initiate(new_bor); - } } Ok(()) } - /// Freeze the given memory range. - fn freeze( + /// Create a new borrow, the ptr must already have the new tag. + /// Also freezes the location if `freeze` is set and the tag is a timestamped `Shr`. + fn initiate( &self, ptr: Pointer, size: Size, - bor_t: Timestamp - ) -> EvalResult<'tcx> { + freeze: bool, + ) { + trace!("reborrow for tag {:?}: {:?}, size {}", + ptr.tag, ptr, size.bytes()); let mut stacks = self.stacks.borrow_mut(); for stack in stacks.iter_mut(ptr.offset, size) { - stack.freeze(bor_t); + stack.initiate(ptr.tag); + if freeze { + if let Borrow::Shr(Some(bor_t)) = ptr.tag { + stack.freeze(bor_t); + } + } } - Ok(()) } /// Check that this stack is fine with being dereferenced @@ -312,6 +316,7 @@ impl<'tcx> Stacks { &self, ptr: Pointer, size: Size, + frozen: bool, ) -> EvalResult<'tcx> { let mut stacks = self.stacks.borrow_mut(); // We need `iter_mut` because `iter` would skip gaps! @@ -323,20 +328,14 @@ impl<'tcx> Stacks { err ))) } - } - Ok(()) - } - - /// Check that this stack is appropriately frozen - fn check_frozen( - &self, - ptr: Pointer, - size: Size, - bor_t: Timestamp - ) -> EvalResult<'tcx> { - let mut stacks = self.stacks.borrow_mut(); - for stack in stacks.iter_mut(ptr.offset, size) { - stack.check_frozen(bor_t)?; + // Sometimes we also need to be frozen. + if frozen { + // Even shared refs can have uniq tags (after transmute). That's not an error + // but they do not get any freezing benefits. + if let Borrow::Shr(Some(bor_t)) = ptr.tag { + stack.check_frozen(bor_t)?; + } + } } Ok(()) } @@ -351,7 +350,7 @@ impl AllocationExtra for Stacks { size: Size, ) -> EvalResult<'tcx> { // Reads behave exactly like the first half of a reborrow-to-shr - alloc.extra.use_and_maybe_re_borrow(ptr, size, UsageKind::Read, None) + alloc.extra.reactivate(ptr, size, UsageKind::Read) } #[inline(always)] @@ -361,7 +360,7 @@ impl AllocationExtra for Stacks { size: Size, ) -> EvalResult<'tcx> { // Writes behave exactly like the first half of a reborrow-to-mut - alloc.extra.use_and_maybe_re_borrow(ptr, size, UsageKind::Write, None) + alloc.extra.reactivate(ptr, size, UsageKind::Read) } #[inline(always)] @@ -371,7 +370,7 @@ impl AllocationExtra for Stacks { size: Size, ) -> EvalResult<'tcx> { // This is like mutating - alloc.extra.use_and_maybe_re_borrow(ptr, size, UsageKind::Write, None) + alloc.extra.reactivate(ptr, size, UsageKind::Write) // FIXME: Error out of there are any barriers? } } @@ -429,6 +428,35 @@ pub trait EvalContextExt<'tcx> { } impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for MiriEvalContext<'a, 'mir, 'tcx> { + fn tag_new_allocation( + &mut self, + id: AllocId, + kind: MemoryKind, + ) -> Borrow { + let time = match kind { + MemoryKind::Stack => { + // New unique borrow. This `Uniq` is not accessible by the program, + // so it will only ever be used when using the local directly (i.e., + // not through a pointer). IOW, whenever we directly use a local this will pop + // everything else off the stack, invalidating all previous pointers + // and, in particular, *all* raw pointers. This subsumes the explicit + // `reset` which the blog post [1] says to perform when accessing a local. + // + // [1] https://www.ralfj.de/blog/2018/08/07/stacked-borrows.html + self.machine.stacked_borrows.increment_clock() + } + _ => { + // Nothing to do for everything else + return Borrow::default() + } + }; + // Make this the active borrow for this allocation + let alloc = self.memory_mut().get_mut(id).expect("This is a new allocation, it must still exist"); + let size = Size::from_bytes(alloc.bytes.len() as u64); + alloc.extra.first_item(BorStackItem::Uniq(time), size); + Borrow::Uniq(time) + } + /// Called for value-to-place conversion. /// /// Note that this does NOT mean that all this memory will actually get accessed/referenced! @@ -449,8 +477,8 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for MiriEvalContext<'a, 'mir, 'tcx> { // That can transmute a raw ptr to a (shared/mut) ref, and a mut ref to a shared one. match (usage, ptr.tag) { (UsageKind::Raw, _) => { - // Don't use the tag, this is a raw access! Even if there is a tag, - // that means transmute happened and we ignore the tag. + // Don't use the tag, this is a raw access! They should happen tagless. + // This does mean, however, that `&*foo` is *not* a NOP *if* `foo` is a raw ptr. // Also don't do any further validation, this is raw after all. return Ok(Borrow::default()); } @@ -478,50 +506,41 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for MiriEvalContext<'a, 'mir, 'tcx> { } } - // If we got here, we do some checking, *but* we leave the tag unchanged. + // Get the allocation self.memory().check_bounds(ptr, size, false)?; let alloc = self.memory().get(ptr.alloc_id).expect("We checked that the ptr is fine!"); - alloc.extra.check_deref(ptr, size)?; - // Maybe check frozen stuff - if let Borrow::Shr(Some(bor_t)) = ptr.tag { - self.visit_frozen(place, size, |frz_ptr, size| { - debug_assert_eq!(frz_ptr.alloc_id, ptr.alloc_id); - // Are you frozen? - alloc.extra.check_frozen(frz_ptr, size, bor_t) + // If we got here, we do some checking, *but* we leave the tag unchanged. + if let Borrow::Shr(Some(_)) = ptr.tag { + // We need a frozen-sensitive check + self.visit_freeze_sensitive(place, size, |cur_ptr, size, frozen| { + alloc.extra.check_deref(cur_ptr, size, frozen) })?; + } else { + // Just treat this as one big chunk + alloc.extra.check_deref(ptr, size, /*frozen*/false)?; } // All is good, and do not change the tag Ok(ptr.tag) } - fn tag_new_allocation( + /// The given place may henceforth be accessed through raw pointers. + fn escape_to_raw( &mut self, - id: AllocId, - kind: MemoryKind, - ) -> Borrow { - let time = match kind { - MemoryKind::Stack => { - // New unique borrow. This `Uniq` is not accessible by the program, - // so it will only ever be used when using the local directly (i.e., - // not through a pointer). IOW, whenever we directly use a local this will pop - // everything else off the stack, invalidating all previous pointers - // and, in particular, *all* raw pointers. This subsumes the explicit - // `reset` which the blog post [1] says to perform when accessing a local. - // - // [1] https://www.ralfj.de/blog/2018/08/07/stacked-borrows.html - self.machine.stacked_borrows.increment_clock() - } - _ => { - // Nothing to do for everything else - return Borrow::default() - } - }; - // Make this the active borrow for this allocation - let alloc = self.memory_mut().get_mut(id).expect("This is a new allocation, it must still exist"); - let size = Size::from_bytes(alloc.bytes.len() as u64); - alloc.extra.first_item(BorStackItem::Uniq(time), size); - Borrow::Uniq(time) + place: MPlaceTy<'tcx, Borrow>, + size: Size, + ) -> EvalResult<'tcx> { + trace!("self: {:?} is now accessible by raw pointers", *place); + // Get the allocation + let mut ptr = place.ptr.to_ptr()?; + self.memory().check_bounds(ptr, size, false)?; // `ptr_dereference` wouldn't do any checks if this is a raw ptr + let alloc = self.memory().get(ptr.alloc_id).expect("We checked that the ptr is fine!"); + // Re-borrow to raw. This is a NOP for shared borrows, but we do not know the borrow + // type here and that's also okay. Freezing does not matter here. + alloc.extra.reactivate(ptr, size, UsageKind::Raw)?; + ptr.tag = Borrow::default(); + alloc.extra.initiate(ptr, size, /*freeze*/false); + Ok(()) } fn retag_ptr( @@ -546,25 +565,28 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for MiriEvalContext<'a, 'mir, 'tcx> { hir::MutMutable => Borrow::Uniq(time), hir::MutImmutable => Borrow::Shr(Some(time)), }; + let new_ptr = Pointer::new_with_tag(ptr.alloc_id, ptr.offset, new_bor); trace!("retag: Creating new reference ({:?}) for {:?} (pointee {}): {:?}", mutbl, ptr, place.layout.ty, new_bor); - // Update the stacks. First create a new borrow, then maybe freeze stuff. + // Get the allocation self.memory().check_bounds(ptr, size, false)?; // `ptr_dereference` wouldn't do any checks if this is a raw ptr let alloc = self.memory().get(ptr.alloc_id).expect("We checked that the ptr is fine!"); - alloc.extra.use_and_maybe_re_borrow(ptr, size, Some(mutbl).into(), Some(new_bor))?; - // Maybe freeze stuff - if let Borrow::Shr(Some(bor_t)) = new_bor { - self.visit_frozen(place, size, |frz_ptr, size| { - debug_assert_eq!(frz_ptr.alloc_id, ptr.alloc_id); - // Be frozen! - alloc.extra.freeze(frz_ptr, size, bor_t) + // Update the stacks. First use old borrow, then initiate new one. + alloc.extra.reactivate(ptr, size, Some(mutbl).into())?; + if mutbl == hir::MutImmutable { + // We need a frozen-sensitive initiate + self.visit_freeze_sensitive(place, size, |mut cur_ptr, size, frozen| { + cur_ptr.tag = new_bor; + Ok(alloc.extra.initiate(cur_ptr, size, frozen)) })?; + } else { + // Just treat this as one big chunk + alloc.extra.initiate(new_ptr, size, /*frozen*/false); } - // Compute the new value and return that - let new_ptr = Scalar::Ptr(Pointer::new_with_tag(ptr.alloc_id, ptr.offset, new_bor)); - let new_place = MemPlace { ptr: new_ptr, ..*place }; + // Return new ptr + let new_place = MemPlace { ptr: Scalar::Ptr(new_ptr), ..*place }; Ok(new_place.to_ref()) } @@ -586,19 +608,4 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for MiriEvalContext<'a, 'mir, 'tcx> { self.write_immediate(val, place)?; Ok(()) } - - fn escape_to_raw( - &mut self, - place: MPlaceTy<'tcx, Borrow>, - size: Size, - ) -> EvalResult<'tcx> { - trace!("self: {:?} is now accessible by raw pointers", *place); - // Re-borrow to raw. This is a NOP for shared borrows, but we do not know the borrow - // type here and that's also okay. - let ptr = place.ptr.to_ptr()?; - self.memory().check_bounds(ptr, size, false)?; // `ptr_dereference` wouldn't do any checks if this is a raw ptr - let alloc = self.memory().get(ptr.alloc_id).expect("We checked that the ptr is fine!"); - alloc.extra.use_and_maybe_re_borrow(ptr, size, UsageKind::Raw, Some(Borrow::default()))?; - Ok(()) - } } From 94e751267c881bc26219853733222e4fe8fdc87a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 7 Nov 2018 17:33:41 +0100 Subject: [PATCH 0359/3747] add another mean test case --- .../stacked_borrows/illegal_read3.rs | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 tests/compile-fail/stacked_borrows/illegal_read3.rs diff --git a/tests/compile-fail/stacked_borrows/illegal_read3.rs b/tests/compile-fail/stacked_borrows/illegal_read3.rs new file mode 100644 index 0000000000000..b0da0511dee3f --- /dev/null +++ b/tests/compile-fail/stacked_borrows/illegal_read3.rs @@ -0,0 +1,29 @@ +#![feature(untagged_unions)] +// A callee may not read the destination of our `&mut` without +// us noticing. +// Thise code got carefully checked to not introduce any reborrows +// that are not explicit in the source. Let's hope the compiler does not break this later! + +use std::mem; + +fn main() { + let mut x: i32 = 15; + let xref1 = &mut x; + let xref1_sneaky: usize = unsafe { mem::transmute_copy(&xref1) }; + let xref2 = &mut *xref1; // derived from xref1, so using raw is still okay... + callee(xref1_sneaky); + let _val = *xref2; // ...but any use of it will invalidate our ref. + //~^ ERROR: does not exist on the stack +} + +fn callee(xref1: usize) { + // Transmuting through a union to avoid retagging + union UsizeToRef { + from: usize, + to: &'static mut i32, + } + let xref1 = UsizeToRef { from: xref1 }; + // Doing the deref and the transmute (through the union) in the same place expression + // should avoid retagging. + let _val = unsafe { *xref1.to }; +} From aa8f523df6447a32c15d2620a52a55761f94da97 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 7 Nov 2018 21:08:34 +0100 Subject: [PATCH 0360/3747] test for special things that are now possible --- tests/run-pass/stacked-borrows.rs | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/tests/run-pass/stacked-borrows.rs b/tests/run-pass/stacked-borrows.rs index adab2b5a5683a..00b21c746c268 100644 --- a/tests/run-pass/stacked-borrows.rs +++ b/tests/run-pass/stacked-borrows.rs @@ -4,6 +4,8 @@ fn main() { read_does_not_invalidate1(); read_does_not_invalidate2(); ref_raw_int_raw(); + mut_shr_raw(); + mut_raw_then_mut_shr(); } // Deref a raw ptr to access a field of a large struct, where the field @@ -48,3 +50,29 @@ fn ref_raw_int_raw() { let xraw = xref as *mut i32 as usize as *mut i32; assert_eq!(unsafe { *xraw }, 3); } + +// Creating a raw from a `&mut` through an `&` works, even if we +// write through that raw. +fn mut_shr_raw() { + let mut x = 2; + { + let xref = &mut x; + let xraw = &*xref as *const i32 as *mut i32; + unsafe { *xraw = 4; } + } + assert_eq!(x, 4); +} + +// Escape a mut to raw, then share the same mut and use the share, then the raw. +// That should work. +fn mut_raw_then_mut_shr() { + let mut x = 2; + { + let xref = &mut x; + let xraw = &mut *xref as *mut _; + let xshr = &*xref; + assert_eq!(*xshr, 2); + unsafe { *xraw = 4; } + } + assert_eq!(x, 4); +} From a94e197105a0ce67cba816299cdd59efdb6df7a4 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 7 Nov 2018 21:08:20 +0100 Subject: [PATCH 0361/3747] better test the special exception for reading through unique when things are shared --- src/stacked_borrows.rs | 14 +++++++---- .../stacked_borrows/illegal_read4.rs | 9 ++++++++ tests/run-pass/stacked-borrows.rs | 23 +++++++++++++++++++ 3 files changed, 41 insertions(+), 5 deletions(-) create mode 100644 tests/compile-fail/stacked_borrows/illegal_read4.rs diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index ab0c3f8994c51..56688ca10f49a 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -167,13 +167,15 @@ impl<'tcx> Stack { behind a barrier", bor)) } (BorStackItem::Uniq(itm_t), Borrow::Uniq(bor_t)) if itm_t == bor_t => { - // Found matching unique item. + // Found matching unique item. This is *always* required to use a `Uniq`: + // The item must still be on the stack. if !is_write { - // As a special case, if we are reading and since we *did* find the `Uniq`, - // we try to pop less: We are happy with making a `Shr` or `Frz` active; - // that one will not mind concurrent reads. + // As a special case, if we are reading, let us see if it would be + // beneficial to pretend we are a raw pointer instead. If + // raw pointers are allowed to read while popping *less* than we + // would have to pop, there is no reason not to let them do this. match self.reactivatable(Borrow::default(), is_write) { - // If we got something better that `idx`, use that + // If we got something better (popping less) that `idx`, use that Ok(None) => return Ok(None), Ok(Some(shr_idx)) if shr_idx <= idx => return Ok(Some(shr_idx)), // Otherwise just go on. @@ -329,6 +331,8 @@ impl<'tcx> Stacks { ))) } // Sometimes we also need to be frozen. + // In this case we *both* push `Shr` and then freeze. This means that a `&mut` + // to `*const` to `*mut` cast through `&` actually works. if frozen { // Even shared refs can have uniq tags (after transmute). That's not an error // but they do not get any freezing benefits. diff --git a/tests/compile-fail/stacked_borrows/illegal_read4.rs b/tests/compile-fail/stacked_borrows/illegal_read4.rs new file mode 100644 index 0000000000000..c86ec1286daad --- /dev/null +++ b/tests/compile-fail/stacked_borrows/illegal_read4.rs @@ -0,0 +1,9 @@ +// Using a raw invalidates derived `&mut` even for reading. +fn main() { + let mut x = 2; + let xref1 = &mut x; + let xraw = xref1 as *mut _; + let xref2 = unsafe { &mut *xraw }; + let _val = unsafe { *xraw }; // use the raw again, this invalidates xref2 *even* with the special read except for uniq refs + let _illegal = *xref2; //~ ERROR does not exist on the stack +} diff --git a/tests/run-pass/stacked-borrows.rs b/tests/run-pass/stacked-borrows.rs index 00b21c746c268..7b7a7c9be2030 100644 --- a/tests/run-pass/stacked-borrows.rs +++ b/tests/run-pass/stacked-borrows.rs @@ -6,6 +6,7 @@ fn main() { ref_raw_int_raw(); mut_shr_raw(); mut_raw_then_mut_shr(); + mut_raw_mut(); } // Deref a raw ptr to access a field of a large struct, where the field @@ -76,3 +77,25 @@ fn mut_raw_then_mut_shr() { } assert_eq!(x, 4); } + +// Ensure that if we derive from a mut a raw, and then from that a mut, +// and then read through the original mut, that does not invalidate the raw. +// This shows that the read-exception for `&mut` applies even if the `Shr` item +// on the stack is not at the top. +fn mut_raw_mut() { + let mut x = 2; + { + let xref1 = &mut x; + let xraw = xref1 as *mut _; + let _xref2 = unsafe { &mut *xraw }; + let _val = *xref1; + unsafe { *xraw = 4; } + // we can now use both xraw and xref1, for reading + assert_eq!(*xref1, 4); + assert_eq!(unsafe { *xraw }, 4); + assert_eq!(*xref1, 4); + assert_eq!(unsafe { *xraw }, 4); + // we cannot use xref2; see `compile-fail/stacked-borows/illegal_read4.rs` + } + assert_eq!(x, 4); +} From 224d03dbdc642a60a3326c7bb9b9206082d4cda4 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 8 Nov 2018 08:58:03 +0100 Subject: [PATCH 0362/3747] organize std tests a bit better --- tests/run-pass/rc.rs | 35 +++++++++++++++++++++++++++++++++-- tests/run-pass/refcell.rs | 6 +++++- tests/run-pass/std.rs | 34 ---------------------------------- 3 files changed, 38 insertions(+), 37 deletions(-) delete mode 100644 tests/run-pass/std.rs diff --git a/tests/run-pass/rc.rs b/tests/run-pass/rc.rs index 0bf7075031120..bc89d752e0b62 100644 --- a/tests/run-pass/rc.rs +++ b/tests/run-pass/rc.rs @@ -1,13 +1,33 @@ -use std::cell::RefCell; +use std::cell::{Cell, RefCell}; use std::rc::Rc; +use std::sync::Arc; fn rc_refcell() { let r = Rc::new(RefCell::new(42)); + let r2 = r.clone(); *r.borrow_mut() += 10; - let x = *r.borrow(); + let x = *r2.borrow(); assert_eq!(x, 52); } +fn rc_cell() { + let r = Rc::new(Cell::new(42)); + let r2 = r.clone(); + let x = r.get(); + r2.set(x + x); + assert_eq!(r.get(), 84); +} + +fn rc_refcell2() { + let r = Rc::new(RefCell::new(42)); + let r2 = r.clone(); + *r.borrow_mut() += 10; + let x = r2.borrow(); + let r3 = r.clone(); + let y = r3.borrow(); + assert_eq!((*x + *y)/2, 52); +} + fn rc_raw() { let r = Rc::new(0); let r2 = Rc::into_raw(r.clone()); @@ -17,6 +37,14 @@ fn rc_raw() { assert!(Rc::try_unwrap(r2).is_ok()); } +fn arc() { + fn test() -> Arc { + let a = Arc::new(42); + a + } + assert_eq!(*test(), 42); +} + // Make sure this Rc doesn't fall apart when touched fn check_unique_rc(mut r: Rc) { let r2 = r.clone(); @@ -34,6 +62,9 @@ fn rc_from() { fn main() { rc_refcell(); + rc_refcell2(); + rc_cell(); rc_raw(); rc_from(); + arc(); } diff --git a/tests/run-pass/refcell.rs b/tests/run-pass/refcell.rs index 93cef1572a3e1..52dcdbd36d0fb 100644 --- a/tests/run-pass/refcell.rs +++ b/tests/run-pass/refcell.rs @@ -1,6 +1,6 @@ use std::cell::RefCell; -fn main() { +fn lots_of_funny_borrows() { let c = RefCell::new(42); { let s1 = c.borrow(); @@ -31,3 +31,7 @@ fn main() { let _y: i32 = *s2; } } + +fn main() { + lots_of_funny_borrows(); +} diff --git a/tests/run-pass/std.rs b/tests/run-pass/std.rs deleted file mode 100644 index 7ff967b29f344..0000000000000 --- a/tests/run-pass/std.rs +++ /dev/null @@ -1,34 +0,0 @@ -use std::cell::{Cell, RefCell}; -use std::rc::Rc; -use std::sync::Arc; - -fn rc_cell() -> Rc> { - let r = Rc::new(Cell::new(42)); - let x = r.get(); - r.set(x + x); - r -} - -fn rc_refcell() -> i32 { - let r = Rc::new(RefCell::new(42)); - *r.borrow_mut() += 10; - let x = r.borrow(); - let y = r.borrow(); - (*x + *y)/2 -} - -fn arc() -> Arc { - let a = Arc::new(42); - a -} - -fn true_assert() { - assert_eq!(1, 1); -} - -fn main() { - assert_eq!(*arc(), 42); - assert_eq!(rc_cell().get(), 84); - assert_eq!(rc_refcell(), 52); - true_assert(); -} From a87e9521029fdc319b5c86680d6645f411751943 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 9 Nov 2018 10:53:28 +0100 Subject: [PATCH 0363/3747] Separate deref and access into different operations; add special exception for creating raw references --- src/lib.rs | 14 +- src/stacked_borrows.rs | 423 +++++++++--------- .../stacked_borrows/alias_through_mutation.rs | 2 +- .../stacked_borrows/illegal_read5.rs | 16 + .../stacked_borrows/illegal_write1.rs | 2 +- .../stacked_borrows/illegal_write3.rs | 2 +- .../stacked_borrows/illegal_write4.rs | 2 +- .../stacked_borrows/illegal_write5.rs | 2 +- .../stacked_borrows/load_invalid_mut.rs | 2 +- .../stacked_borrows/load_invalid_shr.rs | 4 +- .../stacked_borrows/pass_invalid_mut.rs | 2 +- .../stacked_borrows/pass_invalid_shr.rs | 6 +- .../stacked_borrows/return_invalid_mut.rs | 2 +- .../stacked_borrows/return_invalid_shr.rs | 4 +- tests/compiletest.rs | 4 +- tests/run-pass/refcell.rs | 17 + 16 files changed, 280 insertions(+), 224 deletions(-) create mode 100644 tests/compile-fail/stacked_borrows/illegal_read5.rs diff --git a/src/lib.rs b/src/lib.rs index e8691409b1ab4..a0ed7c8e4fdbd 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -308,16 +308,18 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { // Some functions are whitelisted until we figure out how to fix them. // We walk up the stack a few frames to also cover their callees. - const WHITELIST: &[&str] = &[ + const WHITELIST: &[(&str, &str)] = &[ // Uses mem::uninitialized - "std::ptr::read", - "std::sys::windows::mutex::Mutex::", + ("std::ptr::read", ""), + ("std::sys::windows::mutex::Mutex::", ""), + // Should directly take a raw reference + (">", "::get"), ]; for frame in ecx.stack().iter() .rev().take(3) { let name = frame.instance.to_string(); - if WHITELIST.iter().any(|white| name.starts_with(white)) { + if WHITELIST.iter().any(|(prefix, suffix)| name.starts_with(prefix) && name.ends_with(suffix)) { return false; } } @@ -453,7 +455,9 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { let (size, _) = ecx.size_and_align_of_mplace(place)? // for extern types, just cover what we can .unwrap_or_else(|| place.layout.size_and_align()); - if !ecx.machine.validate || size == Size::ZERO { + if !ecx.tcx.sess.opts.debugging_opts.mir_emit_retag || + !Self::enforce_validity(ecx) || size == Size::ZERO + { // No tracking Ok(place.ptr) } else { diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 56688ca10f49a..ab536b5785c98 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -1,10 +1,10 @@ use std::cell::RefCell; use rustc::ty::{self, layout::Size}; -use rustc::hir; +use rustc::hir::{Mutability, MutMutable, MutImmutable}; use crate::{ - EvalResult, MiriEvalContext, HelpersEvalContextExt, + EvalResult, EvalErrorKind, MiriEvalContext, HelpersEvalContextExt, MemoryKind, MiriMemoryKind, RangeMap, AllocId, Allocation, AllocationExtra, Pointer, MemPlace, Scalar, Immediate, ImmTy, PlaceTy, MPlaceTy, }; @@ -27,7 +27,7 @@ pub enum Borrow { impl Borrow { #[inline(always)] - pub fn is_shr(self) -> bool { + pub fn is_shared(self) -> bool { match self { Borrow::Shr(_) => true, _ => false, @@ -35,7 +35,7 @@ impl Borrow { } #[inline(always)] - pub fn is_uniq(self) -> bool { + pub fn is_unique(self) -> bool { match self { Borrow::Uniq(_) => true, _ => false, @@ -96,27 +96,17 @@ impl Stack { } } -/// What kind of usage of the pointer are we talking about? +/// What kind of reference is being used? #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] -pub enum UsageKind { - /// Write, or create &mut - Write, - /// Read, or create & - Read, - /// Create * (raw ptr) +pub enum RefKind { + /// &mut + Unique, + /// & without interior mutability + Frozen, + /// * (raw pointer) or & to `UnsafeCell` Raw, } -impl From> for UsageKind { - fn from(mutbl: Option) -> Self { - match mutbl { - None => UsageKind::Raw, - Some(hir::MutMutable) => UsageKind::Write, - Some(hir::MutImmutable) => UsageKind::Read, - } - } -} - /// Extra global machine state #[derive(Clone, Debug)] pub struct State { @@ -127,6 +117,12 @@ impl State { pub fn new() -> State { State { clock: 0 } } + + fn increment_clock(&mut self) -> Timestamp { + let val = self.clock; + self.clock = val + 1; + val + } } /// Extra per-allocation state @@ -136,52 +132,45 @@ pub struct Stacks { stacks: RefCell>, } -/// Core operations +/// Core per-location operations: deref, access, create. +/// We need to make at least the following things true: +/// +/// U1: After creating a Uniq, it is at the top (+unfrozen). +/// U2: If the top is Uniq (+unfrozen), accesses must be through that Uniq or pop it. +/// U3: If an access (deref sufficient?) happens with a Uniq, it requires the Uniq to be in the stack. +/// +/// F1: After creating a &, the parts outside `UnsafeCell` are frozen. +/// F2: If a write access happens, it unfreezes. +/// F3: If an access (well, a deref) happens with an & outside `UnsafeCell`, it requires the location to still be frozen. impl<'tcx> Stack { - /// Check if `bor` could be activated by unfreezing and popping. - /// `is_write` indicates whether this is being used to write (or, equivalently, to - /// borrow as &mut). - /// Returns `Err` if the answer is "no"; otherwise the return value indicates what to - /// do: With `Some(n)` you need to unfreeze, and then additionally pop `n` items. - fn reactivatable(&self, bor: Borrow, is_write: bool) -> Result, String> { - // Check if we can match the frozen "item". Not possible on writes! - if !is_write { - // For now, we do NOT check the timestamp. That might be surprising, but - // we cannot even notice when a location should be frozen but is not! - // Those checks are both done in `tag_dereference`, where we have type information. - // Either way, it is crucial that the frozen "item" matches raw pointers: - // Reading through a raw should not unfreeze. - match (self.frozen_since, bor) { - (Some(_), Borrow::Shr(_)) => { - return Ok(None) + /// Deref `bor`: Check if the location is frozen and the tag in the stack. + /// This dos *not* constitute an access! "Deref" refers to the `*` operator + /// in Rust, and includs cases like `&*x` or `(*x).foo` where no or only part + /// of the memory actually gets accessed. Also we cannot know if we are + /// going to read or write. + /// Returns the index of the item we matched, `None` if it was the frozen one. + /// `kind` indicates which kind of reference is being dereferenced. + fn deref(&self, bor: Borrow, kind: RefKind) -> Result, String> { + // Checks related to freezing + match bor { + Borrow::Shr(Some(bor_t)) if kind == RefKind::Frozen => { + // We need the location to be frozen. This ensures F3. + let frozen = self.frozen_since.map_or(false, |itm_t| itm_t <= bor_t); + return if frozen { Ok(None) } else { + Err(format!("Location is not frozen long enough")) } - _ => {}, } + Borrow::Shr(_) if self.frozen_since.is_some() => { + return Ok(None) // Shared deref to frozen location, looking good + } + _ => {} // Not sufficient, go on looking. } - // See if we can find this borrow. - for (idx, &itm) in self.borrows.iter().rev().enumerate() { - // Check borrow and stack item for compatibility. + // If we got here, we have to look for our item in the stack. + for (idx, &itm) in self.borrows.iter().enumerate().rev() { match (itm, bor) { - (BorStackItem::FnBarrier(_), _) => { - return Err(format!("Trying to reactivate a borrow ({:?}) that lives \ - behind a barrier", bor)) - } + (BorStackItem::FnBarrier(_), _) => break, (BorStackItem::Uniq(itm_t), Borrow::Uniq(bor_t)) if itm_t == bor_t => { - // Found matching unique item. This is *always* required to use a `Uniq`: - // The item must still be on the stack. - if !is_write { - // As a special case, if we are reading, let us see if it would be - // beneficial to pretend we are a raw pointer instead. If - // raw pointers are allowed to read while popping *less* than we - // would have to pop, there is no reason not to let them do this. - match self.reactivatable(Borrow::default(), is_write) { - // If we got something better (popping less) that `idx`, use that - Ok(None) => return Ok(None), - Ok(Some(shr_idx)) if shr_idx <= idx => return Ok(Some(shr_idx)), - // Otherwise just go on. - _ => {}, - } - } + // Found matching unique item. This satisfies U3. return Ok(Some(idx)) } (BorStackItem::Shr, Borrow::Shr(_)) => { @@ -192,154 +181,182 @@ impl<'tcx> Stack { _ => {} } } - // Nothing to be found. - Err(format!("Borrow-to-reactivate {:?} does not exist on the stack", bor)) + // If we got here, we did not find our item. We have to error to satisfy U3. + Err(format!( + "Borrow being dereferenced ({:?}) does not exist on the stack, or is guarded by a barrier", + bor + )) } - /// Reactive `bor` for this stack. `is_write` indicates whether this is being - /// used to write (or, equivalently, to borrow as &mut). - fn reactivate(&mut self, bor: Borrow, is_write: bool) -> EvalResult<'tcx> { - let mut pop = match self.reactivatable(bor, is_write) { - Ok(None) => return Ok(()), - Ok(Some(pop)) => pop, - Err(err) => return err!(MachineError(err)), - }; - // Pop what `reactivatable` told us to pop. Always unfreeze. + /// Perform an actual memory access using `bor`. We do not know any types here + /// or whether things should be frozen, but we *do* know if this is reading + /// or writing. + fn access(&mut self, bor: Borrow, is_write: bool) -> EvalResult<'tcx> { + // Check if we can match the frozen "item". + // Not possible on writes! if self.is_frozen() { - trace!("reactivate: Unfreezing"); + if !is_write { + // When we are frozen, we just accept all reads. No harm in this. + // The deref already checked that `Uniq` items are in the stack, and that + // the location is frozen if it should be. + return Ok(()); + } + trace!("access: Unfreezing"); } + // Unfreeze on writes. This ensures F2. self.frozen_since = None; - while pop > 0 { - let itm = self.borrows.pop().unwrap(); - trace!("reactivate: Popping {:?}", itm); - pop -= 1; + // Pop the stack until we have something matching. + while let Some(&itm) = self.borrows.last() { + match (itm, bor) { + (BorStackItem::FnBarrier(_), _) => break, + (BorStackItem::Uniq(itm_t), Borrow::Uniq(bor_t)) if itm_t == bor_t => { + // Found matching unique item. + return Ok(()) + } + (BorStackItem::Shr, _) if !is_write => { + // When reading, everything can use a shared item! + // We do not want to do this when writing: Writing to an `&mut` + // should reaffirm its exclusivity (i.e., make sure it is + // on top of the stack). + return Ok(()) + } + (BorStackItem::Shr, Borrow::Shr(_)) => { + // Found matching shared item. + return Ok(()) + } + _ => { + // Pop this. This ensures U2. + let itm = self.borrows.pop().unwrap(); + trace!("access: Popping {:?}", itm); + } + } } - Ok(()) + // If we got here, we did not find our item. + err!(MachineError(format!( + "Borrow being accessed ({:?}) does not exist on the stack, or is guarded by a barrier", + bor + ))) } /// Initiate `bor`; mostly this means pushing. /// This operation cannot fail; it is up to the caller to ensure that the precondition /// is met: We cannot push `Uniq` onto frozen stacks. - /// Crucially, this makes pushing a `Shr` onto a frozen location a NOP. We do not want - /// such a location to get mutably shared this way! - fn initiate(&mut self, bor: Borrow) { - if let Some(_) = self.frozen_since { + /// `kind` indicates which kind of reference is being created. + fn create(&mut self, bor: Borrow, kind: RefKind) { + // First, push the item. We do this even if we will later freeze, because we + // will allow mutation of shared data at the expense of unfreezing. + if let Some(itm_t) = self.frozen_since { // A frozen location, we won't change anything here! match bor { Borrow::Uniq(_) => bug!("Trying to create unique ref to frozen location"), - Borrow::Shr(_) => trace!("initiate: New shared ref to frozen location is a NOP"), + Borrow::Shr(Some(bor_t)) if kind == RefKind::Frozen => { + // Make sure we are frozen long enough. This is part 1 of ensuring F1. + assert!(itm_t <= bor_t, "Trying to freeze shorter than it was frozen?"); + trace!("create: Freezing a frozen location is a NOP"); + } + Borrow::Shr(_) => trace!("create: Sharing a frozen location is a NOP"), } } else { - // Just push. + // First push. let itm = match bor { Borrow::Uniq(t) => BorStackItem::Uniq(t), - Borrow::Shr(_) if *self.borrows.last().unwrap() == BorStackItem::Shr => { - // Optimization: Don't push a Shr onto a Shr. - trace!("initiate: New shared ref to already shared location is a NOP"); - return - }, Borrow::Shr(_) => BorStackItem::Shr, }; - trace!("initiate: Pushing {:?}", itm); - self.borrows.push(itm) - } - } - - /// Check if this location is "frozen enough". - fn check_frozen(&self, bor_t: Timestamp) -> EvalResult<'tcx> { - let frozen = self.frozen_since.map_or(false, |itm_t| itm_t <= bor_t); - if !frozen { - err!(MachineError(format!("Location is not frozen long enough"))) - } else { - Ok(()) - } - } - - /// Freeze this location, since `bor_t`. - fn freeze(&mut self, bor_t: Timestamp) { - if let Some(itm_t) = self.frozen_since { - assert!(itm_t <= bor_t, "Trying to freeze shorter than it was frozen?"); - } else { - trace!("Freezing"); - self.frozen_since = Some(bor_t); + if *self.borrows.last().unwrap() == itm { + assert!(bor.is_shared()); + trace!("create: Sharing a shared location is a NOP"); + } else { + // This ensures U1. + trace!("create: Pushing {:?}", itm); + self.borrows.push(itm); + } + // Now, maybe freeze. This is part 2 of ensuring F1. + if kind == RefKind::Frozen { + let bor_t = match bor { + Borrow::Shr(Some(t)) => t, + _ => bug!("Creating illegal borrow {:?} for frozen ref", bor), + }; + trace!("create: Freezing"); + self.frozen_since = Some(bor_t); + } } } } -impl State { - fn increment_clock(&mut self) -> Timestamp { - let val = self.clock; - self.clock = val + 1; - val - } -} - -/// Higher-level operations +/// Higher-level per-location operations: deref, access, reborrow. impl<'tcx> Stacks { - /// `ptr` got used, reflect that in the stack. - fn reactivate( + /// Check that this stack is fine with being dereferenced + fn deref( &self, ptr: Pointer, size: Size, - usage: UsageKind, + kind: RefKind, ) -> EvalResult<'tcx> { - trace!("use_borrow of tag {:?} as {:?}: {:?}, size {}", - ptr.tag, usage, ptr, size.bytes()); + trace!("deref for tag {:?} as {:?}: {:?}, size {}", + ptr.tag, kind, ptr, size.bytes()); let mut stacks = self.stacks.borrow_mut(); + // We need `iter_mut` because `iter` would skip gaps! for stack in stacks.iter_mut(ptr.offset, size) { - stack.reactivate(ptr.tag, usage == UsageKind::Write)?; + stack.deref(ptr.tag, kind).map_err(EvalErrorKind::MachineError)?; } Ok(()) } - /// Create a new borrow, the ptr must already have the new tag. - /// Also freezes the location if `freeze` is set and the tag is a timestamped `Shr`. - fn initiate( + /// `ptr` got used, reflect that in the stack. + fn access( &self, ptr: Pointer, size: Size, - freeze: bool, - ) { - trace!("reborrow for tag {:?}: {:?}, size {}", + is_write: bool, + ) -> EvalResult<'tcx> { + trace!("{} access of tag {:?}: {:?}, size {}", + if is_write { "read" } else { "write" }, ptr.tag, ptr, size.bytes()); let mut stacks = self.stacks.borrow_mut(); for stack in stacks.iter_mut(ptr.offset, size) { - stack.initiate(ptr.tag); - if freeze { - if let Borrow::Shr(Some(bor_t)) = ptr.tag { - stack.freeze(bor_t); - } - } + stack.access(ptr.tag, is_write)?; } + Ok(()) } - /// Check that this stack is fine with being dereferenced - fn check_deref( + /// Reborrow the given pointer to the new tag for the given kind of reference. + fn reborrow( &self, ptr: Pointer, size: Size, - frozen: bool, + new_bor: Borrow, + new_kind: RefKind, ) -> EvalResult<'tcx> { + trace!("reborrow for tag {:?} to {:?} as {:?}: {:?}, size {}", + ptr.tag, new_bor, new_kind, ptr, size.bytes()); let mut stacks = self.stacks.borrow_mut(); - // We need `iter_mut` because `iter` would skip gaps! for stack in stacks.iter_mut(ptr.offset, size) { - // Conservatively assume we will just read - if let Err(err) = stack.reactivatable(ptr.tag, /*is_write*/false) { - return err!(MachineError(format!( - "Encountered reference with non-reactivatable tag: {}", - err - ))) - } - // Sometimes we also need to be frozen. - // In this case we *both* push `Shr` and then freeze. This means that a `&mut` - // to `*const` to `*mut` cast through `&` actually works. - if frozen { - // Even shared refs can have uniq tags (after transmute). That's not an error - // but they do not get any freezing benefits. - if let Borrow::Shr(Some(bor_t)) = ptr.tag { - stack.check_frozen(bor_t)?; + // Access source `ptr`, create new ref. + let ptr_idx = stack.deref(ptr.tag, new_kind).map_err(EvalErrorKind::MachineError)?; + if new_kind == RefKind::Raw { + assert!(new_bor.is_shared()); + // Raw references do not get quite as many guarantees as the other kinds: + // If we can deref the new tag already, and if that tag lives higher on + // the stack than the one we come from, just use that. + // IOW, we check if `new_bor` *already* is "derived from" `ptr.tag`. + match (ptr_idx, stack.deref(new_bor, new_kind)) { + // If the new borrow works with the forzen item, or else if it lives + // above the old one in the stack, our job here is done. + (_, Ok(None)) => { + trace!("reborrow-to-raw on a frozen location is a NOP"); + continue + }, + (Some(ptr_idx), Ok(Some(new_idx))) if new_idx >= ptr_idx => { + trace!("reborrow-to-raw is a NOP because the src ptr already got reborrowed-to-raw"); + continue + }, + _ => {}, } } + // Non-raw reborrows should behave exactly as if we also did a + // read/write to the given location. + stack.access(ptr.tag, new_kind == RefKind::Unique)?; + stack.create(new_bor, new_kind); } Ok(()) } @@ -353,8 +370,7 @@ impl AllocationExtra for Stacks { ptr: Pointer, size: Size, ) -> EvalResult<'tcx> { - // Reads behave exactly like the first half of a reborrow-to-shr - alloc.extra.reactivate(ptr, size, UsageKind::Read) + alloc.extra.access(ptr, size, /*is_write*/false) } #[inline(always)] @@ -363,8 +379,7 @@ impl AllocationExtra for Stacks { ptr: Pointer, size: Size, ) -> EvalResult<'tcx> { - // Writes behave exactly like the first half of a reborrow-to-mut - alloc.extra.reactivate(ptr, size, UsageKind::Read) + alloc.extra.access(ptr, size, /*is_write*/true) } #[inline(always)] @@ -374,7 +389,7 @@ impl AllocationExtra for Stacks { size: Size, ) -> EvalResult<'tcx> { // This is like mutating - alloc.extra.reactivate(ptr, size, UsageKind::Write) + alloc.extra.access(ptr, size, /*is_write*/true) // FIXME: Error out of there are any barriers? } } @@ -402,7 +417,7 @@ pub trait EvalContextExt<'tcx> { &self, place: MPlaceTy<'tcx, Borrow>, size: Size, - usage: UsageKind, + mutability: Option, ) -> EvalResult<'tcx, Borrow>; fn tag_new_allocation( @@ -412,10 +427,10 @@ pub trait EvalContextExt<'tcx> { ) -> Borrow; /// Retag an indidual pointer, returning the retagged version. - fn retag_ptr( + fn reborrow( &mut self, ptr: ImmTy<'tcx, Borrow>, - mutbl: hir::Mutability, + mutbl: Mutability, ) -> EvalResult<'tcx, Immediate>; fn retag( @@ -461,7 +476,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for MiriEvalContext<'a, 'mir, 'tcx> { Borrow::Uniq(time) } - /// Called for value-to-place conversion. + /// Called for value-to-place conversion. `mutability` is `None` for raw pointers. /// /// Note that this does NOT mean that all this memory will actually get accessed/referenced! /// We could be in the middle of `&(*var).1`. @@ -469,38 +484,41 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for MiriEvalContext<'a, 'mir, 'tcx> { &self, place: MPlaceTy<'tcx, Borrow>, size: Size, - usage: UsageKind, + mutability: Option, ) -> EvalResult<'tcx, Borrow> { - trace!("tag_dereference: Accessing reference ({:?}) for {:?} (pointee {})", - usage, place.ptr, place.layout.ty); + trace!("tag_dereference: Accessing {} reference for {:?} (pointee {})", + if let Some(mutability) = mutability { format!("{:?}", mutability) } else { format!("raw") }, + place.ptr, place.layout.ty); let ptr = place.ptr.to_ptr()?; // In principle we should not have to do anything here. However, with transmutes involved, - // it can happen that the tag of `ptr` does not actually match `usage`, and we + // it can happen that the tag of `ptr` does not actually match `mutability`, and we // should adjust for that. // Notably, the compiler can introduce such transmutes by optimizing away `&[mut]*`. // That can transmute a raw ptr to a (shared/mut) ref, and a mut ref to a shared one. - match (usage, ptr.tag) { - (UsageKind::Raw, _) => { + match (mutability, ptr.tag) { + (None, _) => { // Don't use the tag, this is a raw access! They should happen tagless. + // This is needed for `*mut` to make any sense: Writes *do* enforce the + // `Uniq` tag to be up top, but we must make sure raw writes do not do that. // This does mean, however, that `&*foo` is *not* a NOP *if* `foo` is a raw ptr. // Also don't do any further validation, this is raw after all. return Ok(Borrow::default()); } - (UsageKind::Write, Borrow::Uniq(_)) | - (UsageKind::Read, Borrow::Shr(_)) => { + (Some(MutMutable), Borrow::Uniq(_)) | + (Some(MutImmutable), Borrow::Shr(_)) => { // Expected combinations. Nothing to do. } - (UsageKind::Write, Borrow::Shr(None)) => { + (Some(MutMutable), Borrow::Shr(None)) => { // Raw transmuted to mut ref. Keep this as raw access. // We cannot reborrow here; there might be a raw in `&(*var).1` where // `var` is an `&mut`. The other field of the struct might be already frozen, // also using `var`, and that would be okay. } - (UsageKind::Read, Borrow::Uniq(_)) => { + (Some(MutImmutable), Borrow::Uniq(_)) => { // A mut got transmuted to shr. Can happen even from compiler transformations: // `&*x` gets optimized to `x` even when `x` is a `&mut`. } - (UsageKind::Write, Borrow::Shr(Some(_))) => { + (Some(MutMutable), Borrow::Shr(Some(_))) => { // This is just invalid: A shr got transmuted to a mut. // If we ever allow this, we have to consider what we do when a turn a // `Raw`-tagged `&mut` into a raw pointer pointing to a frozen location. @@ -515,13 +533,16 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for MiriEvalContext<'a, 'mir, 'tcx> { let alloc = self.memory().get(ptr.alloc_id).expect("We checked that the ptr is fine!"); // If we got here, we do some checking, *but* we leave the tag unchanged. if let Borrow::Shr(Some(_)) = ptr.tag { + assert_eq!(mutability, Some(MutImmutable)); // We need a frozen-sensitive check self.visit_freeze_sensitive(place, size, |cur_ptr, size, frozen| { - alloc.extra.check_deref(cur_ptr, size, frozen) + let kind = if frozen { RefKind::Frozen } else { RefKind::Raw }; + alloc.extra.deref(cur_ptr, size, kind) })?; } else { // Just treat this as one big chunk - alloc.extra.check_deref(ptr, size, /*frozen*/false)?; + let kind = if mutability == Some(MutMutable) { RefKind::Unique } else { RefKind::Raw }; + alloc.extra.deref(ptr, size, kind)?; } // All is good, and do not change the tag @@ -534,23 +555,20 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for MiriEvalContext<'a, 'mir, 'tcx> { place: MPlaceTy<'tcx, Borrow>, size: Size, ) -> EvalResult<'tcx> { - trace!("self: {:?} is now accessible by raw pointers", *place); + trace!("escape_to_raw: {:?} is now accessible by raw pointers", *place); // Get the allocation - let mut ptr = place.ptr.to_ptr()?; + let ptr = place.ptr.to_ptr()?; self.memory().check_bounds(ptr, size, false)?; // `ptr_dereference` wouldn't do any checks if this is a raw ptr let alloc = self.memory().get(ptr.alloc_id).expect("We checked that the ptr is fine!"); // Re-borrow to raw. This is a NOP for shared borrows, but we do not know the borrow // type here and that's also okay. Freezing does not matter here. - alloc.extra.reactivate(ptr, size, UsageKind::Raw)?; - ptr.tag = Borrow::default(); - alloc.extra.initiate(ptr, size, /*freeze*/false); - Ok(()) + alloc.extra.reborrow(ptr, size, Borrow::default(), RefKind::Raw) } - fn retag_ptr( + fn reborrow( &mut self, val: ImmTy<'tcx, Borrow>, - mutbl: hir::Mutability, + mutbl: Mutability, ) -> EvalResult<'tcx, Immediate> { // We want a place for where the ptr *points to*, so we get one. let place = self.ref_to_mplace(val)?; @@ -566,30 +584,29 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for MiriEvalContext<'a, 'mir, 'tcx> { let ptr = place.ptr.to_ptr()?; let time = self.machine.stacked_borrows.increment_clock(); let new_bor = match mutbl { - hir::MutMutable => Borrow::Uniq(time), - hir::MutImmutable => Borrow::Shr(Some(time)), + MutMutable => Borrow::Uniq(time), + MutImmutable => Borrow::Shr(Some(time)), }; - let new_ptr = Pointer::new_with_tag(ptr.alloc_id, ptr.offset, new_bor); - trace!("retag: Creating new reference ({:?}) for {:?} (pointee {}): {:?}", + trace!("reborrow: Creating new {:?} reference for {:?} (pointee {}): {:?}", mutbl, ptr, place.layout.ty, new_bor); - // Get the allocation - self.memory().check_bounds(ptr, size, false)?; // `ptr_dereference` wouldn't do any checks if this is a raw ptr + // Get the allocation. It might not be mutable, so we cannot use `get_mut`. + self.memory().check_bounds(ptr, size, false)?; let alloc = self.memory().get(ptr.alloc_id).expect("We checked that the ptr is fine!"); - // Update the stacks. First use old borrow, then initiate new one. - alloc.extra.reactivate(ptr, size, Some(mutbl).into())?; - if mutbl == hir::MutImmutable { - // We need a frozen-sensitive initiate - self.visit_freeze_sensitive(place, size, |mut cur_ptr, size, frozen| { - cur_ptr.tag = new_bor; - Ok(alloc.extra.initiate(cur_ptr, size, frozen)) + // Update the stacks. + if mutbl == MutImmutable { + // Shared reference. We need a frozen-sensitive reborrow. + self.visit_freeze_sensitive(place, size, |cur_ptr, size, frozen| { + let kind = if frozen { RefKind::Frozen } else { RefKind::Raw }; + alloc.extra.reborrow(cur_ptr, size, new_bor, kind) })?; } else { - // Just treat this as one big chunk - alloc.extra.initiate(new_ptr, size, /*frozen*/false); + // Mutable reference. Just treat this as one big chunk. + alloc.extra.reborrow(ptr, size, new_bor, RefKind::Unique)?; } // Return new ptr + let new_ptr = Pointer::new_with_tag(ptr.alloc_id, ptr.offset, new_bor); let new_place = MemPlace { ptr: Scalar::Ptr(new_ptr), ..*place }; Ok(new_place.to_ref()) } @@ -608,7 +625,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for MiriEvalContext<'a, 'mir, 'tcx> { }; // Retag the pointer and write it back. let val = self.read_immediate(self.place_to_op(place)?)?; - let val = self.retag_ptr(val, mutbl)?; + let val = self.reborrow(val, mutbl)?; self.write_immediate(val, place)?; Ok(()) } diff --git a/tests/compile-fail/stacked_borrows/alias_through_mutation.rs b/tests/compile-fail/stacked_borrows/alias_through_mutation.rs index 0b2d459366ceb..092f3f09ed196 100644 --- a/tests/compile-fail/stacked_borrows/alias_through_mutation.rs +++ b/tests/compile-fail/stacked_borrows/alias_through_mutation.rs @@ -11,5 +11,5 @@ fn main() { retarget(&mut target_alias, target); // now `target_alias` points to the same thing as `target` *target = 13; - let _val = *target_alias; //~ ERROR reference with non-reactivatable tag + let _val = *target_alias; //~ ERROR does not exist on the stack } diff --git a/tests/compile-fail/stacked_borrows/illegal_read5.rs b/tests/compile-fail/stacked_borrows/illegal_read5.rs new file mode 100644 index 0000000000000..863649a47b5ef --- /dev/null +++ b/tests/compile-fail/stacked_borrows/illegal_read5.rs @@ -0,0 +1,16 @@ +// We *can* have aliasing &RefCell and &mut T, but we cannot read through the former. +// Else we couldn't optimize based on the assumption that `xref` below is truly unique. + +use std::cell::RefCell; +use std::{mem, ptr}; + +fn main() { + let rc = RefCell::new(0); + let mut refmut = rc.borrow_mut(); + let xref: &mut i32 = &mut *refmut; + let xshr = &rc; // creating this is okay + let _val = *xref; // we can even still use our mutable reference + mem::forget(unsafe { ptr::read(xshr) }); // but after reading through the shared ref + let _val = *xref; // the mutable one is dead and gone + //~^ ERROR does not exist on the stack +} diff --git a/tests/compile-fail/stacked_borrows/illegal_write1.rs b/tests/compile-fail/stacked_borrows/illegal_write1.rs index 7378907fa7456..b106cc8dc403c 100644 --- a/tests/compile-fail/stacked_borrows/illegal_write1.rs +++ b/tests/compile-fail/stacked_borrows/illegal_write1.rs @@ -8,5 +8,5 @@ fn main() { let target = Box::new(42); // has an implicit raw let ref_ = &*target; evil(ref_); // invalidates shared ref, activates raw - let _x = *ref_; //~ ERROR is not frozen long enough + let _x = *ref_; //~ ERROR is not frozen } diff --git a/tests/compile-fail/stacked_borrows/illegal_write3.rs b/tests/compile-fail/stacked_borrows/illegal_write3.rs index c82da1e9c4677..01559af21e7c6 100644 --- a/tests/compile-fail/stacked_borrows/illegal_write3.rs +++ b/tests/compile-fail/stacked_borrows/illegal_write3.rs @@ -4,5 +4,5 @@ fn main() { let r#ref = ⌖ // freeze let ptr = r#ref as *const _ as *mut _; // raw ptr, with raw tag unsafe { *ptr = 42; } - let _val = *r#ref; //~ ERROR is not frozen long enough + let _val = *r#ref; //~ ERROR is not frozen } diff --git a/tests/compile-fail/stacked_borrows/illegal_write4.rs b/tests/compile-fail/stacked_borrows/illegal_write4.rs index 49bf9279faa2e..37ae0f055f0ee 100644 --- a/tests/compile-fail/stacked_borrows/illegal_write4.rs +++ b/tests/compile-fail/stacked_borrows/illegal_write4.rs @@ -9,5 +9,5 @@ fn main() { let ptr = reference as *const _ as *mut i32; // raw ptr, with raw tag let _mut_ref: &mut i32 = unsafe { mem::transmute(ptr) }; // &mut, with raw tag // Now we retag, making our ref top-of-stack -- and, in particular, unfreezing. - let _val = *reference; //~ ERROR is not frozen long enough + let _val = *reference; //~ ERROR is not frozen } diff --git a/tests/compile-fail/stacked_borrows/illegal_write5.rs b/tests/compile-fail/stacked_borrows/illegal_write5.rs index f4704ad57161f..57b2ca87d8102 100644 --- a/tests/compile-fail/stacked_borrows/illegal_write5.rs +++ b/tests/compile-fail/stacked_borrows/illegal_write5.rs @@ -7,7 +7,7 @@ fn main() { let xref = unsafe { &mut *xraw }; // derived from raw, so using raw is still okay... callee(xraw); let _val = *xref; // ...but any use of raw will invalidate our ref. - //~^ ERROR: reference with non-reactivatable tag + //~^ ERROR: does not exist on the stack } fn callee(xraw: *mut i32) { diff --git a/tests/compile-fail/stacked_borrows/load_invalid_mut.rs b/tests/compile-fail/stacked_borrows/load_invalid_mut.rs index d3db462343e84..98b9451eda87e 100644 --- a/tests/compile-fail/stacked_borrows/load_invalid_mut.rs +++ b/tests/compile-fail/stacked_borrows/load_invalid_mut.rs @@ -4,6 +4,6 @@ fn main() { let xraw = x as *mut _; let xref = unsafe { &mut *xraw }; let xref_in_mem = Box::new(xref); - let _val = *x; // invalidate xraw + let _val = unsafe { *xraw }; // invalidate xref let _val = *xref_in_mem; //~ ERROR does not exist on the stack } diff --git a/tests/compile-fail/stacked_borrows/load_invalid_shr.rs b/tests/compile-fail/stacked_borrows/load_invalid_shr.rs index 71b578817a774..6599924f0f4c4 100644 --- a/tests/compile-fail/stacked_borrows/load_invalid_shr.rs +++ b/tests/compile-fail/stacked_borrows/load_invalid_shr.rs @@ -4,6 +4,6 @@ fn main() { let xraw = x as *mut _; let xref = unsafe { &*xraw }; let xref_in_mem = Box::new(xref); - *x = 42; // invalidate xraw - let _val = *xref_in_mem; //~ ERROR does not exist on the stack + unsafe { *xraw = 42 }; // unfreeze + let _val = *xref_in_mem; //~ ERROR is not frozen } diff --git a/tests/compile-fail/stacked_borrows/pass_invalid_mut.rs b/tests/compile-fail/stacked_borrows/pass_invalid_mut.rs index 41cf89d874d71..28288c6c63623 100644 --- a/tests/compile-fail/stacked_borrows/pass_invalid_mut.rs +++ b/tests/compile-fail/stacked_borrows/pass_invalid_mut.rs @@ -5,6 +5,6 @@ fn main() { let x = &mut 42; let xraw = x as *mut _; let xref = unsafe { &mut *xraw }; - let _val = *x; // invalidate xraw + let _val = unsafe { *xraw }; // invalidate xref foo(xref); //~ ERROR does not exist on the stack } diff --git a/tests/compile-fail/stacked_borrows/pass_invalid_shr.rs b/tests/compile-fail/stacked_borrows/pass_invalid_shr.rs index 0bdb1b4a41e59..67bbc88e40fb0 100644 --- a/tests/compile-fail/stacked_borrows/pass_invalid_shr.rs +++ b/tests/compile-fail/stacked_borrows/pass_invalid_shr.rs @@ -3,8 +3,8 @@ fn foo(_: &i32) {} fn main() { let x = &mut 42; - let xraw = &*x as *const _; + let xraw = &*x as *const _ as *mut _; let xref = unsafe { &*xraw }; - *x = 42; // invalidate xraw - foo(xref); //~ ERROR does not exist on the stack + unsafe { *xraw = 42 }; // unfreeze + foo(xref); //~ ERROR is not frozen } diff --git a/tests/compile-fail/stacked_borrows/return_invalid_mut.rs b/tests/compile-fail/stacked_borrows/return_invalid_mut.rs index aef8fafdf5d59..e7f0b9bc9ddd0 100644 --- a/tests/compile-fail/stacked_borrows/return_invalid_mut.rs +++ b/tests/compile-fail/stacked_borrows/return_invalid_mut.rs @@ -2,7 +2,7 @@ fn foo(x: &mut (i32, i32)) -> &mut i32 { let xraw = x as *mut (i32, i32); let ret = unsafe { &mut (*xraw).1 }; - let _val = *x; // invalidate xraw and its children + let _val = unsafe { *xraw }; // invalidate xref ret //~ ERROR does not exist on the stack } diff --git a/tests/compile-fail/stacked_borrows/return_invalid_shr.rs b/tests/compile-fail/stacked_borrows/return_invalid_shr.rs index 074942eb95bca..986dd18b2e0b4 100644 --- a/tests/compile-fail/stacked_borrows/return_invalid_shr.rs +++ b/tests/compile-fail/stacked_borrows/return_invalid_shr.rs @@ -2,8 +2,8 @@ fn foo(x: &mut (i32, i32)) -> &i32 { let xraw = x as *mut (i32, i32); let ret = unsafe { &(*xraw).1 }; - x.1 = 42; // invalidate xraw on the 2nd field - ret //~ ERROR does not exist on the stack + unsafe { *xraw = (42, 23) }; // unfreeze + ret //~ ERROR is not frozen } fn main() { diff --git a/tests/compiletest.rs b/tests/compiletest.rs index 55eaa7bfbab68..f393fcb2c226f 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -99,7 +99,9 @@ fn miri_pass(sysroot: &Path, path: &str, target: &str, host: &str, need_fullmir: flags.push(format!("--sysroot {}", sysroot.display())); flags.push("-Dwarnings -Dunused".to_owned()); // overwrite the -Aunused in compiletest-rs if opt { - flags.push("-Zmir-opt-level=3".to_owned()); + // FIXME: We use opt level 1 because MIR inlining defeats the validation + // whitelist. + flags.push("-Zmir-opt-level=1".to_owned()); } let mut config = mk_config("ui"); diff --git a/tests/run-pass/refcell.rs b/tests/run-pass/refcell.rs index 52dcdbd36d0fb..5f2f3523b96b1 100644 --- a/tests/run-pass/refcell.rs +++ b/tests/run-pass/refcell.rs @@ -32,6 +32,23 @@ fn lots_of_funny_borrows() { } } +fn aliasing_mut_and_shr() { + fn inner(rc: &RefCell, aliasing: &mut i32) { + *aliasing += 4; + let _escape_to_raw = rc as *const _; + *aliasing += 4; + let _shr = &*rc; + *aliasing += 4; + } + + let rc = RefCell::new(23); + let mut bmut = rc.borrow_mut(); + inner(&rc, &mut *bmut); + drop(bmut); + assert_eq!(*rc.borrow(), 23+12); +} + fn main() { lots_of_funny_borrows(); + aliasing_mut_and_shr(); } From 5a801c0dc1620948108e23ab9c75b75137eb7691 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 12 Nov 2018 16:18:02 +0100 Subject: [PATCH 0364/3747] adjust comment --- src/stacked_borrows.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index ab536b5785c98..f5ae7cb933f96 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -509,10 +509,8 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for MiriEvalContext<'a, 'mir, 'tcx> { // Expected combinations. Nothing to do. } (Some(MutMutable), Borrow::Shr(None)) => { - // Raw transmuted to mut ref. Keep this as raw access. - // We cannot reborrow here; there might be a raw in `&(*var).1` where - // `var` is an `&mut`. The other field of the struct might be already frozen, - // also using `var`, and that would be okay. + // Raw transmuted to mut ref. This is something real unsafe code does. + // We cannot reborrow here because we do not want to mutate state on a deref. } (Some(MutImmutable), Borrow::Uniq(_)) => { // A mut got transmuted to shr. Can happen even from compiler transformations: From ba8eb7608ea6520238a1d587197a795e9dc7147a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 12 Nov 2018 19:30:35 +0100 Subject: [PATCH 0365/3747] add an interesting demo for &mut being unique --- .../mut_exclusive_violation1.rs | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 tests/compile-fail/stacked_borrows/mut_exclusive_violation1.rs diff --git a/tests/compile-fail/stacked_borrows/mut_exclusive_violation1.rs b/tests/compile-fail/stacked_borrows/mut_exclusive_violation1.rs new file mode 100644 index 0000000000000..255e35b145588 --- /dev/null +++ b/tests/compile-fail/stacked_borrows/mut_exclusive_violation1.rs @@ -0,0 +1,29 @@ +fn demo_mut_advanced_unique(our: &mut i32) -> i32 { + unknown_code_1(&*our); + + // This "re-asserts" uniqueness of the reference: After writing, we know + // our tag is at the top of the stack. + *our = 5; + + unknown_code_2(); + + // We know this will return 5 + *our +} + +// Now comes the evil context +use std::ptr; + +static mut LEAK: *mut i32 = ptr::null_mut(); + +fn unknown_code_1(x: &i32) { unsafe { + LEAK = x as *const _ as *mut _; +} } + +fn unknown_code_2() { unsafe { + *LEAK = 7; //~ ERROR does not exist on the stack +} } + +fn main() { + assert_eq!(demo_mut_advanced_unique(&mut 0), 5); +} From c234009fddf3a58c486a06f1c40980149df114f7 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 13 Nov 2018 13:39:03 +0100 Subject: [PATCH 0366/3747] generalize reborrow-to-raw exception to a general redundancy check --- src/stacked_borrows.rs | 38 +++++++++++++++++--------------------- 1 file changed, 17 insertions(+), 21 deletions(-) diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index f5ae7cb933f96..d2abfbc9dfcb3 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -333,28 +333,24 @@ impl<'tcx> Stacks { for stack in stacks.iter_mut(ptr.offset, size) { // Access source `ptr`, create new ref. let ptr_idx = stack.deref(ptr.tag, new_kind).map_err(EvalErrorKind::MachineError)?; - if new_kind == RefKind::Raw { - assert!(new_bor.is_shared()); - // Raw references do not get quite as many guarantees as the other kinds: - // If we can deref the new tag already, and if that tag lives higher on - // the stack than the one we come from, just use that. - // IOW, we check if `new_bor` *already* is "derived from" `ptr.tag`. - match (ptr_idx, stack.deref(new_bor, new_kind)) { - // If the new borrow works with the forzen item, or else if it lives - // above the old one in the stack, our job here is done. - (_, Ok(None)) => { - trace!("reborrow-to-raw on a frozen location is a NOP"); - continue - }, - (Some(ptr_idx), Ok(Some(new_idx))) if new_idx >= ptr_idx => { - trace!("reborrow-to-raw is a NOP because the src ptr already got reborrowed-to-raw"); - continue - }, - _ => {}, - } + // If we can deref the new tag already, and if that tag lives higher on + // the stack than the one we come from, just use that. + // IOW, we check if `new_bor` *already* is "derived from" `ptr.tag`. + // This also checks frozenness, if required. + let bor_already_happened = match (ptr_idx, stack.deref(new_bor, new_kind)) { + // If the new borrow works with the frozen item, or else if it lives + // above the old one in the stack, our job here is done. + (_, Ok(None)) => true, + (Some(ptr_idx), Ok(Some(new_idx))) if new_idx >= ptr_idx => true, + // Otherwise we need to create a new borrow. + _ => false, + }; + if bor_already_happened { + assert!(new_bor.is_shared(), "A unique reborrow can never be redundant"); + trace!("Reborrow is a NOP"); + continue; } - // Non-raw reborrows should behave exactly as if we also did a - // read/write to the given location. + // We need to do some actual work. stack.access(ptr.tag, new_kind == RefKind::Unique)?; stack.create(new_bor, new_kind); } From f521fd5e0fbaa54d5a07f61a794a91a0576ff557 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 13 Nov 2018 14:49:04 +0100 Subject: [PATCH 0367/3747] let's call this a redundant reborrow --- src/stacked_borrows.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index d2abfbc9dfcb3..8c409030164d3 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -337,7 +337,7 @@ impl<'tcx> Stacks { // the stack than the one we come from, just use that. // IOW, we check if `new_bor` *already* is "derived from" `ptr.tag`. // This also checks frozenness, if required. - let bor_already_happened = match (ptr_idx, stack.deref(new_bor, new_kind)) { + let bor_redundant = match (ptr_idx, stack.deref(new_bor, new_kind)) { // If the new borrow works with the frozen item, or else if it lives // above the old one in the stack, our job here is done. (_, Ok(None)) => true, @@ -345,9 +345,9 @@ impl<'tcx> Stacks { // Otherwise we need to create a new borrow. _ => false, }; - if bor_already_happened { + if bor_redundant { assert!(new_bor.is_shared(), "A unique reborrow can never be redundant"); - trace!("Reborrow is a NOP"); + trace!("reborrow is redundant"); continue; } // We need to do some actual work. From cf1746222ee01eefb8c076fd48f05755b4cdc81a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 13 Nov 2018 17:05:47 +0100 Subject: [PATCH 0368/3747] we no longer even try pushing to a frozen location --- src/stacked_borrows.rs | 55 ++++++++++++++++++------------------------ 1 file changed, 23 insertions(+), 32 deletions(-) diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 8c409030164d3..3790b5d13fed5 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -245,40 +245,31 @@ impl<'tcx> Stack { fn create(&mut self, bor: Borrow, kind: RefKind) { // First, push the item. We do this even if we will later freeze, because we // will allow mutation of shared data at the expense of unfreezing. - if let Some(itm_t) = self.frozen_since { - // A frozen location, we won't change anything here! - match bor { - Borrow::Uniq(_) => bug!("Trying to create unique ref to frozen location"), - Borrow::Shr(Some(bor_t)) if kind == RefKind::Frozen => { - // Make sure we are frozen long enough. This is part 1 of ensuring F1. - assert!(itm_t <= bor_t, "Trying to freeze shorter than it was frozen?"); - trace!("create: Freezing a frozen location is a NOP"); - } - Borrow::Shr(_) => trace!("create: Sharing a frozen location is a NOP"), - } + if self.frozen_since.is_some() { + // A frozen location, this should be impossible! + bug!("We should never try pushing to a frozen stack"); + } + // First, push. + let itm = match bor { + Borrow::Uniq(t) => BorStackItem::Uniq(t), + Borrow::Shr(_) => BorStackItem::Shr, + }; + if *self.borrows.last().unwrap() == itm { + assert!(bor.is_shared()); + trace!("create: Sharing a shared location is a NOP"); } else { - // First push. - let itm = match bor { - Borrow::Uniq(t) => BorStackItem::Uniq(t), - Borrow::Shr(_) => BorStackItem::Shr, + // This ensures U1. + trace!("create: Pushing {:?}", itm); + self.borrows.push(itm); + } + // Then, maybe freeze. This is part 2 of ensuring F1. + if kind == RefKind::Frozen { + let bor_t = match bor { + Borrow::Shr(Some(t)) => t, + _ => bug!("Creating illegal borrow {:?} for frozen ref", bor), }; - if *self.borrows.last().unwrap() == itm { - assert!(bor.is_shared()); - trace!("create: Sharing a shared location is a NOP"); - } else { - // This ensures U1. - trace!("create: Pushing {:?}", itm); - self.borrows.push(itm); - } - // Now, maybe freeze. This is part 2 of ensuring F1. - if kind == RefKind::Frozen { - let bor_t = match bor { - Borrow::Shr(Some(t)) => t, - _ => bug!("Creating illegal borrow {:?} for frozen ref", bor), - }; - trace!("create: Freezing"); - self.frozen_since = Some(bor_t); - } + trace!("create: Freezing"); + self.frozen_since = Some(bor_t); } } } From 60e26af3236480a73c7116a20fce49e4e8f74b5e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 16 Nov 2018 08:40:00 +0100 Subject: [PATCH 0369/3747] add a sanity assertion --- src/stacked_borrows.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 3790b5d13fed5..f564bf9ab7612 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -318,6 +318,7 @@ impl<'tcx> Stacks { new_bor: Borrow, new_kind: RefKind, ) -> EvalResult<'tcx> { + assert_eq!(new_bor.is_unique(), new_kind == RefKind::Unique); trace!("reborrow for tag {:?} to {:?} as {:?}: {:?}, size {}", ptr.tag, new_bor, new_kind, ptr, size.bytes()); let mut stacks = self.stacks.borrow_mut(); From 4e34457715cd06eee13b49806e1d157e1add9a66 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 16 Nov 2018 08:40:08 +0100 Subject: [PATCH 0370/3747] bump Rust --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index a829ec0f5a0a1..6c3858ccc9cd7 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -nightly-2018-11-15 +nightly-2018-11-16 From ca7b088aba92efb6643cbb1b69303db35bc1c631 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 16 Nov 2018 08:50:44 +0100 Subject: [PATCH 0371/3747] remove type system tests --- tests/compile-fail/cast_fn_ptr_unsafe.rs | 10 ---------- tests/compile-fail/cast_fn_ptr_unsafe2.rs | 10 ---------- 2 files changed, 20 deletions(-) delete mode 100644 tests/compile-fail/cast_fn_ptr_unsafe.rs delete mode 100644 tests/compile-fail/cast_fn_ptr_unsafe2.rs diff --git a/tests/compile-fail/cast_fn_ptr_unsafe.rs b/tests/compile-fail/cast_fn_ptr_unsafe.rs deleted file mode 100644 index 568681da3c5d3..0000000000000 --- a/tests/compile-fail/cast_fn_ptr_unsafe.rs +++ /dev/null @@ -1,10 +0,0 @@ -// just making sure that fn -> unsafe fn casts are handled by rustc so miri doesn't have to -fn main() { - fn f() {} - - let g = f as fn() as unsafe fn(i32); //~ERROR: non-primitive cast: `fn()` as `unsafe fn(i32)` - - unsafe { - g(42); - } -} diff --git a/tests/compile-fail/cast_fn_ptr_unsafe2.rs b/tests/compile-fail/cast_fn_ptr_unsafe2.rs deleted file mode 100644 index 314365939fe80..0000000000000 --- a/tests/compile-fail/cast_fn_ptr_unsafe2.rs +++ /dev/null @@ -1,10 +0,0 @@ -// just making sure that fn -> unsafe fn casts are handled by rustc so miri doesn't have to -fn main() { - fn f() {} - - let g = f as fn() as fn(i32) as unsafe fn(i32); //~ERROR: non-primitive cast: `fn()` as `fn(i32)` - - unsafe { - g(42); - } -} From 70738bf8cc6b5399f2810d0a2a846fddb877f511 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 16 Nov 2018 08:53:43 +0100 Subject: [PATCH 0372/3747] where there is 2, there should be 1 --- tests/compile-fail/{cast_fn_ptr.rs => cast_fn_ptr1.rs} | 0 tests/compile-fail/{div-by-zero.rs => div-by-zero-1.rs} | 0 .../{out_of_bounds_read.rs => out_of_bounds_read1.rs} | 0 tests/compile-fail/{overflowing-rsh.rs => overflowing-rsh-1.rs} | 0 tests/compile-fail/{ptr_bitops.rs => ptr_bitops1.rs} | 0 ...atic_memory_modification.rs => static_memory_modification1.rs} | 0 tests/compile-fail/{transmute_fat.rs => transmute_fat1.rs} | 0 .../{unaligned_ptr_cast.rs => unaligned_ptr_cast1.rs} | 0 8 files changed, 0 insertions(+), 0 deletions(-) rename tests/compile-fail/{cast_fn_ptr.rs => cast_fn_ptr1.rs} (100%) rename tests/compile-fail/{div-by-zero.rs => div-by-zero-1.rs} (100%) rename tests/compile-fail/{out_of_bounds_read.rs => out_of_bounds_read1.rs} (100%) rename tests/compile-fail/{overflowing-rsh.rs => overflowing-rsh-1.rs} (100%) rename tests/compile-fail/{ptr_bitops.rs => ptr_bitops1.rs} (100%) rename tests/compile-fail/{static_memory_modification.rs => static_memory_modification1.rs} (100%) rename tests/compile-fail/{transmute_fat.rs => transmute_fat1.rs} (100%) rename tests/compile-fail/{unaligned_ptr_cast.rs => unaligned_ptr_cast1.rs} (100%) diff --git a/tests/compile-fail/cast_fn_ptr.rs b/tests/compile-fail/cast_fn_ptr1.rs similarity index 100% rename from tests/compile-fail/cast_fn_ptr.rs rename to tests/compile-fail/cast_fn_ptr1.rs diff --git a/tests/compile-fail/div-by-zero.rs b/tests/compile-fail/div-by-zero-1.rs similarity index 100% rename from tests/compile-fail/div-by-zero.rs rename to tests/compile-fail/div-by-zero-1.rs diff --git a/tests/compile-fail/out_of_bounds_read.rs b/tests/compile-fail/out_of_bounds_read1.rs similarity index 100% rename from tests/compile-fail/out_of_bounds_read.rs rename to tests/compile-fail/out_of_bounds_read1.rs diff --git a/tests/compile-fail/overflowing-rsh.rs b/tests/compile-fail/overflowing-rsh-1.rs similarity index 100% rename from tests/compile-fail/overflowing-rsh.rs rename to tests/compile-fail/overflowing-rsh-1.rs diff --git a/tests/compile-fail/ptr_bitops.rs b/tests/compile-fail/ptr_bitops1.rs similarity index 100% rename from tests/compile-fail/ptr_bitops.rs rename to tests/compile-fail/ptr_bitops1.rs diff --git a/tests/compile-fail/static_memory_modification.rs b/tests/compile-fail/static_memory_modification1.rs similarity index 100% rename from tests/compile-fail/static_memory_modification.rs rename to tests/compile-fail/static_memory_modification1.rs diff --git a/tests/compile-fail/transmute_fat.rs b/tests/compile-fail/transmute_fat1.rs similarity index 100% rename from tests/compile-fail/transmute_fat.rs rename to tests/compile-fail/transmute_fat1.rs diff --git a/tests/compile-fail/unaligned_ptr_cast.rs b/tests/compile-fail/unaligned_ptr_cast1.rs similarity index 100% rename from tests/compile-fail/unaligned_ptr_cast.rs rename to tests/compile-fail/unaligned_ptr_cast1.rs From 827e5180f20ebeec990ab8f92a4196ad8c5feb19 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 16 Nov 2018 10:01:54 +0100 Subject: [PATCH 0373/3747] stacked borrows is broken without full MIR --- README.md | 13 +++++++++---- .../copy_nonoverlapping.rs | 0 .../memleak_rc.rs | 0 .../stacked_borrows/alias_through_mutation.rs | 0 .../stacked_borrows/aliasing_mut1.rs | 0 .../stacked_borrows/aliasing_mut2.rs | 0 .../stacked_borrows/aliasing_mut3.rs | 0 .../stacked_borrows/aliasing_mut4.rs | 0 .../stacked_borrows/buggy_as_mut_slice.rs | 0 .../stacked_borrows/buggy_split_at_mut.rs | 0 .../stacked_borrows/illegal_read1.rs | 0 .../stacked_borrows/illegal_read2.rs | 0 .../stacked_borrows/illegal_read3.rs | 0 .../stacked_borrows/illegal_read4.rs | 0 .../stacked_borrows/illegal_read5.rs | 0 .../stacked_borrows/illegal_write1.rs | 0 .../stacked_borrows/illegal_write2.rs | 0 .../stacked_borrows/illegal_write3.rs | 0 .../stacked_borrows/illegal_write4.rs | 0 .../stacked_borrows/illegal_write5.rs | 0 .../stacked_borrows/load_invalid_mut.rs | 0 .../stacked_borrows/load_invalid_shr.rs | 0 .../stacked_borrows/mut_exclusive_violation1.rs | 0 .../stacked_borrows/outdated_local.rs | 0 .../stacked_borrows/pass_invalid_mut.rs | 0 .../stacked_borrows/pass_invalid_shr.rs | 0 .../stacked_borrows/pointer_smuggling.rs | 0 .../stacked_borrows/return_invalid_mut.rs | 0 .../stacked_borrows/return_invalid_shr.rs | 0 .../stacked_borrows/static_memory_modification.rs | 0 .../stacked_borrows/transmute-is-no-escape.rs | 0 .../stacked_borrows/unescaped_local.rs | 0 .../transmute-pair-undef.rs | 0 tests/compiletest.rs | 4 ++++ 34 files changed, 13 insertions(+), 4 deletions(-) rename tests/{compile-fail => compile-fail-fullmir}/copy_nonoverlapping.rs (100%) rename tests/{compile-fail => compile-fail-fullmir}/memleak_rc.rs (100%) rename tests/{compile-fail => compile-fail-fullmir}/stacked_borrows/alias_through_mutation.rs (100%) rename tests/{compile-fail => compile-fail-fullmir}/stacked_borrows/aliasing_mut1.rs (100%) rename tests/{compile-fail => compile-fail-fullmir}/stacked_borrows/aliasing_mut2.rs (100%) rename tests/{compile-fail => compile-fail-fullmir}/stacked_borrows/aliasing_mut3.rs (100%) rename tests/{compile-fail => compile-fail-fullmir}/stacked_borrows/aliasing_mut4.rs (100%) rename tests/{compile-fail => compile-fail-fullmir}/stacked_borrows/buggy_as_mut_slice.rs (100%) rename tests/{compile-fail => compile-fail-fullmir}/stacked_borrows/buggy_split_at_mut.rs (100%) rename tests/{compile-fail => compile-fail-fullmir}/stacked_borrows/illegal_read1.rs (100%) rename tests/{compile-fail => compile-fail-fullmir}/stacked_borrows/illegal_read2.rs (100%) rename tests/{compile-fail => compile-fail-fullmir}/stacked_borrows/illegal_read3.rs (100%) rename tests/{compile-fail => compile-fail-fullmir}/stacked_borrows/illegal_read4.rs (100%) rename tests/{compile-fail => compile-fail-fullmir}/stacked_borrows/illegal_read5.rs (100%) rename tests/{compile-fail => compile-fail-fullmir}/stacked_borrows/illegal_write1.rs (100%) rename tests/{compile-fail => compile-fail-fullmir}/stacked_borrows/illegal_write2.rs (100%) rename tests/{compile-fail => compile-fail-fullmir}/stacked_borrows/illegal_write3.rs (100%) rename tests/{compile-fail => compile-fail-fullmir}/stacked_borrows/illegal_write4.rs (100%) rename tests/{compile-fail => compile-fail-fullmir}/stacked_borrows/illegal_write5.rs (100%) rename tests/{compile-fail => compile-fail-fullmir}/stacked_borrows/load_invalid_mut.rs (100%) rename tests/{compile-fail => compile-fail-fullmir}/stacked_borrows/load_invalid_shr.rs (100%) rename tests/{compile-fail => compile-fail-fullmir}/stacked_borrows/mut_exclusive_violation1.rs (100%) rename tests/{compile-fail => compile-fail-fullmir}/stacked_borrows/outdated_local.rs (100%) rename tests/{compile-fail => compile-fail-fullmir}/stacked_borrows/pass_invalid_mut.rs (100%) rename tests/{compile-fail => compile-fail-fullmir}/stacked_borrows/pass_invalid_shr.rs (100%) rename tests/{compile-fail => compile-fail-fullmir}/stacked_borrows/pointer_smuggling.rs (100%) rename tests/{compile-fail => compile-fail-fullmir}/stacked_borrows/return_invalid_mut.rs (100%) rename tests/{compile-fail => compile-fail-fullmir}/stacked_borrows/return_invalid_shr.rs (100%) rename tests/{compile-fail => compile-fail-fullmir}/stacked_borrows/static_memory_modification.rs (100%) rename tests/{compile-fail => compile-fail-fullmir}/stacked_borrows/transmute-is-no-escape.rs (100%) rename tests/{compile-fail => compile-fail-fullmir}/stacked_borrows/unescaped_local.rs (100%) rename tests/{compile-fail => compile-fail-fullmir}/transmute-pair-undef.rs (100%) diff --git a/README.md b/README.md index 04a263597c0b2..5eb7b34425e6e 100644 --- a/README.md +++ b/README.md @@ -45,14 +45,19 @@ in this directory. ## Running Miri ```sh -cargo +nightly run tests/run-pass/vecs.rs # Or whatever test you like. +cargo +nightly run -- -Zmiri-disable-validation tests/run-pass/vecs.rs # Or whatever test you like. ``` +We have to disable validation because that can lead to errors when libstd is not +compiled the right way. + ## Running Miri with full libstd -Per default libstd does not contain the MIR of non-polymorphic functions. When -Miri hits a call to such a function, execution terminates. To fix this, it is -possible to compile libstd with full MIR: +Per default libstd does not contain the MIR of non-polymorphic functions, and +also does not contain some extra MIR statements that miri needs for validation. +When Miri hits a call to such a function, execution terminates, and even when +the MIR is present, validation can fail. To fix this, it is possible to compile +libstd with full MIR: ```sh rustup component add --toolchain nightly rust-src diff --git a/tests/compile-fail/copy_nonoverlapping.rs b/tests/compile-fail-fullmir/copy_nonoverlapping.rs similarity index 100% rename from tests/compile-fail/copy_nonoverlapping.rs rename to tests/compile-fail-fullmir/copy_nonoverlapping.rs diff --git a/tests/compile-fail/memleak_rc.rs b/tests/compile-fail-fullmir/memleak_rc.rs similarity index 100% rename from tests/compile-fail/memleak_rc.rs rename to tests/compile-fail-fullmir/memleak_rc.rs diff --git a/tests/compile-fail/stacked_borrows/alias_through_mutation.rs b/tests/compile-fail-fullmir/stacked_borrows/alias_through_mutation.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/alias_through_mutation.rs rename to tests/compile-fail-fullmir/stacked_borrows/alias_through_mutation.rs diff --git a/tests/compile-fail/stacked_borrows/aliasing_mut1.rs b/tests/compile-fail-fullmir/stacked_borrows/aliasing_mut1.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/aliasing_mut1.rs rename to tests/compile-fail-fullmir/stacked_borrows/aliasing_mut1.rs diff --git a/tests/compile-fail/stacked_borrows/aliasing_mut2.rs b/tests/compile-fail-fullmir/stacked_borrows/aliasing_mut2.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/aliasing_mut2.rs rename to tests/compile-fail-fullmir/stacked_borrows/aliasing_mut2.rs diff --git a/tests/compile-fail/stacked_borrows/aliasing_mut3.rs b/tests/compile-fail-fullmir/stacked_borrows/aliasing_mut3.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/aliasing_mut3.rs rename to tests/compile-fail-fullmir/stacked_borrows/aliasing_mut3.rs diff --git a/tests/compile-fail/stacked_borrows/aliasing_mut4.rs b/tests/compile-fail-fullmir/stacked_borrows/aliasing_mut4.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/aliasing_mut4.rs rename to tests/compile-fail-fullmir/stacked_borrows/aliasing_mut4.rs diff --git a/tests/compile-fail/stacked_borrows/buggy_as_mut_slice.rs b/tests/compile-fail-fullmir/stacked_borrows/buggy_as_mut_slice.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/buggy_as_mut_slice.rs rename to tests/compile-fail-fullmir/stacked_borrows/buggy_as_mut_slice.rs diff --git a/tests/compile-fail/stacked_borrows/buggy_split_at_mut.rs b/tests/compile-fail-fullmir/stacked_borrows/buggy_split_at_mut.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/buggy_split_at_mut.rs rename to tests/compile-fail-fullmir/stacked_borrows/buggy_split_at_mut.rs diff --git a/tests/compile-fail/stacked_borrows/illegal_read1.rs b/tests/compile-fail-fullmir/stacked_borrows/illegal_read1.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/illegal_read1.rs rename to tests/compile-fail-fullmir/stacked_borrows/illegal_read1.rs diff --git a/tests/compile-fail/stacked_borrows/illegal_read2.rs b/tests/compile-fail-fullmir/stacked_borrows/illegal_read2.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/illegal_read2.rs rename to tests/compile-fail-fullmir/stacked_borrows/illegal_read2.rs diff --git a/tests/compile-fail/stacked_borrows/illegal_read3.rs b/tests/compile-fail-fullmir/stacked_borrows/illegal_read3.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/illegal_read3.rs rename to tests/compile-fail-fullmir/stacked_borrows/illegal_read3.rs diff --git a/tests/compile-fail/stacked_borrows/illegal_read4.rs b/tests/compile-fail-fullmir/stacked_borrows/illegal_read4.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/illegal_read4.rs rename to tests/compile-fail-fullmir/stacked_borrows/illegal_read4.rs diff --git a/tests/compile-fail/stacked_borrows/illegal_read5.rs b/tests/compile-fail-fullmir/stacked_borrows/illegal_read5.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/illegal_read5.rs rename to tests/compile-fail-fullmir/stacked_borrows/illegal_read5.rs diff --git a/tests/compile-fail/stacked_borrows/illegal_write1.rs b/tests/compile-fail-fullmir/stacked_borrows/illegal_write1.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/illegal_write1.rs rename to tests/compile-fail-fullmir/stacked_borrows/illegal_write1.rs diff --git a/tests/compile-fail/stacked_borrows/illegal_write2.rs b/tests/compile-fail-fullmir/stacked_borrows/illegal_write2.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/illegal_write2.rs rename to tests/compile-fail-fullmir/stacked_borrows/illegal_write2.rs diff --git a/tests/compile-fail/stacked_borrows/illegal_write3.rs b/tests/compile-fail-fullmir/stacked_borrows/illegal_write3.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/illegal_write3.rs rename to tests/compile-fail-fullmir/stacked_borrows/illegal_write3.rs diff --git a/tests/compile-fail/stacked_borrows/illegal_write4.rs b/tests/compile-fail-fullmir/stacked_borrows/illegal_write4.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/illegal_write4.rs rename to tests/compile-fail-fullmir/stacked_borrows/illegal_write4.rs diff --git a/tests/compile-fail/stacked_borrows/illegal_write5.rs b/tests/compile-fail-fullmir/stacked_borrows/illegal_write5.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/illegal_write5.rs rename to tests/compile-fail-fullmir/stacked_borrows/illegal_write5.rs diff --git a/tests/compile-fail/stacked_borrows/load_invalid_mut.rs b/tests/compile-fail-fullmir/stacked_borrows/load_invalid_mut.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/load_invalid_mut.rs rename to tests/compile-fail-fullmir/stacked_borrows/load_invalid_mut.rs diff --git a/tests/compile-fail/stacked_borrows/load_invalid_shr.rs b/tests/compile-fail-fullmir/stacked_borrows/load_invalid_shr.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/load_invalid_shr.rs rename to tests/compile-fail-fullmir/stacked_borrows/load_invalid_shr.rs diff --git a/tests/compile-fail/stacked_borrows/mut_exclusive_violation1.rs b/tests/compile-fail-fullmir/stacked_borrows/mut_exclusive_violation1.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/mut_exclusive_violation1.rs rename to tests/compile-fail-fullmir/stacked_borrows/mut_exclusive_violation1.rs diff --git a/tests/compile-fail/stacked_borrows/outdated_local.rs b/tests/compile-fail-fullmir/stacked_borrows/outdated_local.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/outdated_local.rs rename to tests/compile-fail-fullmir/stacked_borrows/outdated_local.rs diff --git a/tests/compile-fail/stacked_borrows/pass_invalid_mut.rs b/tests/compile-fail-fullmir/stacked_borrows/pass_invalid_mut.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/pass_invalid_mut.rs rename to tests/compile-fail-fullmir/stacked_borrows/pass_invalid_mut.rs diff --git a/tests/compile-fail/stacked_borrows/pass_invalid_shr.rs b/tests/compile-fail-fullmir/stacked_borrows/pass_invalid_shr.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/pass_invalid_shr.rs rename to tests/compile-fail-fullmir/stacked_borrows/pass_invalid_shr.rs diff --git a/tests/compile-fail/stacked_borrows/pointer_smuggling.rs b/tests/compile-fail-fullmir/stacked_borrows/pointer_smuggling.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/pointer_smuggling.rs rename to tests/compile-fail-fullmir/stacked_borrows/pointer_smuggling.rs diff --git a/tests/compile-fail/stacked_borrows/return_invalid_mut.rs b/tests/compile-fail-fullmir/stacked_borrows/return_invalid_mut.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/return_invalid_mut.rs rename to tests/compile-fail-fullmir/stacked_borrows/return_invalid_mut.rs diff --git a/tests/compile-fail/stacked_borrows/return_invalid_shr.rs b/tests/compile-fail-fullmir/stacked_borrows/return_invalid_shr.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/return_invalid_shr.rs rename to tests/compile-fail-fullmir/stacked_borrows/return_invalid_shr.rs diff --git a/tests/compile-fail/stacked_borrows/static_memory_modification.rs b/tests/compile-fail-fullmir/stacked_borrows/static_memory_modification.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/static_memory_modification.rs rename to tests/compile-fail-fullmir/stacked_borrows/static_memory_modification.rs diff --git a/tests/compile-fail/stacked_borrows/transmute-is-no-escape.rs b/tests/compile-fail-fullmir/stacked_borrows/transmute-is-no-escape.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/transmute-is-no-escape.rs rename to tests/compile-fail-fullmir/stacked_borrows/transmute-is-no-escape.rs diff --git a/tests/compile-fail/stacked_borrows/unescaped_local.rs b/tests/compile-fail-fullmir/stacked_borrows/unescaped_local.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/unescaped_local.rs rename to tests/compile-fail-fullmir/stacked_borrows/unescaped_local.rs diff --git a/tests/compile-fail/transmute-pair-undef.rs b/tests/compile-fail-fullmir/transmute-pair-undef.rs similarity index 100% rename from tests/compile-fail/transmute-pair-undef.rs rename to tests/compile-fail-fullmir/transmute-pair-undef.rs diff --git a/tests/compiletest.rs b/tests/compiletest.rs index f393fcb2c226f..7ecf64590b614 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -103,6 +103,10 @@ fn miri_pass(sysroot: &Path, path: &str, target: &str, host: &str, need_fullmir: // whitelist. flags.push("-Zmir-opt-level=1".to_owned()); } + if !have_fullmir() { + // Validation relies on the EscapeToRaw statements being emitted + flags.push("-Zmiri-disable-validation".to_owned()); + } let mut config = mk_config("ui"); config.src_base = PathBuf::from(path); From a1f895d6f2cc9090623652fbbe9029becb102189 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 13 Nov 2018 12:48:20 +0100 Subject: [PATCH 0374/3747] retagging: descent into values, type-driven --- src/helpers.rs | 8 ++- src/stacked_borrows.rs | 59 +++++++++++++++---- .../stacked_borrows/buggy_split_at_mut.rs | 2 +- 3 files changed, 55 insertions(+), 14 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index 31e2972957035..85329ddcf17f5 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -158,8 +158,10 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: unsafe_cell_action: F, } - impl<'ecx, 'a, 'mir, 'tcx, F> ValueVisitor<'a, 'mir, 'tcx, Evaluator<'tcx>> - for UnsafeCellVisitor<'ecx, 'a, 'mir, 'tcx, F> + impl<'ecx, 'a, 'mir, 'tcx, F> + ValueVisitor<'a, 'mir, 'tcx, Evaluator<'tcx>> + for + UnsafeCellVisitor<'ecx, 'a, 'mir, 'tcx, F> where F: FnMut(MPlaceTy<'tcx, Borrow>) -> EvalResult<'tcx> { @@ -230,7 +232,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: } // We should never get to a primitive, but always short-circuit somewhere above - fn visit_primitive(&mut self, _val: ImmTy<'tcx, Borrow>) -> EvalResult<'tcx> + fn visit_primitive(&mut self, _v: MPlaceTy<'tcx, Borrow>) -> EvalResult<'tcx> { bug!("We should always short-circit before coming to a primitive") } diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index f564bf9ab7612..44fa605fd6a23 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -4,7 +4,7 @@ use rustc::ty::{self, layout::Size}; use rustc::hir::{Mutability, MutMutable, MutImmutable}; use crate::{ - EvalResult, EvalErrorKind, MiriEvalContext, HelpersEvalContextExt, + EvalResult, EvalErrorKind, MiriEvalContext, HelpersEvalContextExt, Evaluator, MutValueVisitor, MemoryKind, MiriMemoryKind, RangeMap, AllocId, Allocation, AllocationExtra, Pointer, MemPlace, Scalar, Immediate, ImmTy, PlaceTy, MPlaceTy, }; @@ -602,17 +602,56 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for MiriEvalContext<'a, 'mir, 'tcx> { _fn_entry: bool, place: PlaceTy<'tcx, Borrow> ) -> EvalResult<'tcx> { - // For now, we only retag if the toplevel type is a reference. - // TODO: Recurse into structs and enums, sharing code with validation. // TODO: Honor `fn_entry`. - let mutbl = match place.layout.ty.sty { - ty::Ref(_, _, mutbl) => mutbl, // go ahead - _ => return Ok(()), // do nothing, for now + + // We need a visitor to visit all references. However, that requires + // a `MemPlace`, so we have a fast path for reference types that + // avoids allocating. + match place.layout.ty.sty { + ty::Ref(_, _, mutbl) => { + // fast path + let val = self.read_immediate(self.place_to_op(place)?)?; + let val = self.reborrow(val, mutbl)?; + self.write_immediate(val, place)?; + } + _ => {}, // handled with the general case below }; - // Retag the pointer and write it back. - let val = self.read_immediate(self.place_to_op(place)?)?; - let val = self.reborrow(val, mutbl)?; - self.write_immediate(val, place)?; + let place = self.force_allocation(place)?; + + let mut visitor = RetagVisitor { ecx: self }; + visitor.visit_value(place)?; + + // The actual visitor + struct RetagVisitor<'ecx, 'a, 'mir, 'tcx> { + ecx: &'ecx mut MiriEvalContext<'a, 'mir, 'tcx>, + } + impl<'ecx, 'a, 'mir, 'tcx> + MutValueVisitor<'a, 'mir, 'tcx, Evaluator<'tcx>> + for + RetagVisitor<'ecx, 'a, 'mir, 'tcx> + { + type V = MPlaceTy<'tcx, Borrow>; + + #[inline(always)] + fn ecx(&mut self) -> &mut MiriEvalContext<'a, 'mir, 'tcx> { + &mut self.ecx + } + + // Primitives of reference type, that is the one thing we are interested in. + fn visit_primitive(&mut self, place: MPlaceTy<'tcx, Borrow>) -> EvalResult<'tcx> + { + match place.layout.ty.sty { + ty::Ref(_, _, mutbl) => { + let val = self.ecx.read_immediate(place.into())?; + let val = self.ecx.reborrow(val, mutbl)?; + self.ecx.write_immediate(val, place.into())?; + } + _ => {}, // nothing to do + } + Ok(()) + } + } + Ok(()) } } diff --git a/tests/compile-fail-fullmir/stacked_borrows/buggy_split_at_mut.rs b/tests/compile-fail-fullmir/stacked_borrows/buggy_split_at_mut.rs index 711544f80149c..a6daa5d93d772 100644 --- a/tests/compile-fail-fullmir/stacked_borrows/buggy_split_at_mut.rs +++ b/tests/compile-fail-fullmir/stacked_borrows/buggy_split_at_mut.rs @@ -11,6 +11,7 @@ mod safe { assert!(mid <= len); (from_raw_parts_mut(ptr, len - mid), // BUG: should be "mid" instead of "len - mid" + //~^ ERROR does not exist on the stack from_raw_parts_mut(ptr.offset(mid as isize), len - mid)) } } @@ -19,7 +20,6 @@ mod safe { fn main() { let mut array = [1,2,3,4]; let (a, b) = safe::split_at_mut(&mut array, 0); - //~^ ERROR does not exist on the stack a[1] = 5; b[1] = 6; } From c54dcf59aed7f44260df41a800e7855436a205eb Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 13 Nov 2018 13:03:01 +0100 Subject: [PATCH 0375/3747] add some tests for retagging inside tuples and options --- .../stacked_borrows/return_invalid_mut_option.rs | 11 +++++++++++ .../stacked_borrows/return_invalid_mut_tuple.rs | 11 +++++++++++ .../stacked_borrows/return_invalid_shr_option.rs | 11 +++++++++++ .../stacked_borrows/return_invalid_shr_tuple.rs | 11 +++++++++++ 4 files changed, 44 insertions(+) create mode 100644 tests/compile-fail-fullmir/stacked_borrows/return_invalid_mut_option.rs create mode 100644 tests/compile-fail-fullmir/stacked_borrows/return_invalid_mut_tuple.rs create mode 100644 tests/compile-fail-fullmir/stacked_borrows/return_invalid_shr_option.rs create mode 100644 tests/compile-fail-fullmir/stacked_borrows/return_invalid_shr_tuple.rs diff --git a/tests/compile-fail-fullmir/stacked_borrows/return_invalid_mut_option.rs b/tests/compile-fail-fullmir/stacked_borrows/return_invalid_mut_option.rs new file mode 100644 index 0000000000000..28a1f74c6ac20 --- /dev/null +++ b/tests/compile-fail-fullmir/stacked_borrows/return_invalid_mut_option.rs @@ -0,0 +1,11 @@ +// Make sure that we cannot return a `&mut` that got already invalidated, not even in an `Option`. +fn foo(x: &mut (i32, i32)) -> Option<&mut i32> { + let xraw = x as *mut (i32, i32); + let ret = Some(unsafe { &mut (*xraw).1 }); + let _val = unsafe { *xraw }; // invalidate xref + ret //~ ERROR does not exist on the stack +} + +fn main() { + foo(&mut (1, 2)); +} diff --git a/tests/compile-fail-fullmir/stacked_borrows/return_invalid_mut_tuple.rs b/tests/compile-fail-fullmir/stacked_borrows/return_invalid_mut_tuple.rs new file mode 100644 index 0000000000000..3357af68a8411 --- /dev/null +++ b/tests/compile-fail-fullmir/stacked_borrows/return_invalid_mut_tuple.rs @@ -0,0 +1,11 @@ +// Make sure that we cannot return a `&mut` that got already invalidated, not even in a tuple. +fn foo(x: &mut (i32, i32)) -> (&mut i32,) { + let xraw = x as *mut (i32, i32); + let ret = (unsafe { &mut (*xraw).1 },); + let _val = unsafe { *xraw }; // invalidate xref + ret //~ ERROR does not exist on the stack +} + +fn main() { + foo(&mut (1, 2)); +} diff --git a/tests/compile-fail-fullmir/stacked_borrows/return_invalid_shr_option.rs b/tests/compile-fail-fullmir/stacked_borrows/return_invalid_shr_option.rs new file mode 100644 index 0000000000000..9d220991c3302 --- /dev/null +++ b/tests/compile-fail-fullmir/stacked_borrows/return_invalid_shr_option.rs @@ -0,0 +1,11 @@ +// Make sure that we cannot return a `&` that got already invalidated, not even in an `Option`. +fn foo(x: &mut (i32, i32)) -> Option<&i32> { + let xraw = x as *mut (i32, i32); + let ret = Some(unsafe { &(*xraw).1 }); + unsafe { *xraw = (42, 23) }; // unfreeze + ret //~ ERROR is not frozen +} + +fn main() { + foo(&mut (1, 2)); +} diff --git a/tests/compile-fail-fullmir/stacked_borrows/return_invalid_shr_tuple.rs b/tests/compile-fail-fullmir/stacked_borrows/return_invalid_shr_tuple.rs new file mode 100644 index 0000000000000..060fa25c2307e --- /dev/null +++ b/tests/compile-fail-fullmir/stacked_borrows/return_invalid_shr_tuple.rs @@ -0,0 +1,11 @@ +// Make sure that we cannot return a `&` that got already invalidated, not even in a tuple. +fn foo(x: &mut (i32, i32)) -> (&i32,) { + let xraw = x as *mut (i32, i32); + let ret = (unsafe { &(*xraw).1 },); + unsafe { *xraw = (42, 23) }; // unfreeze + ret //~ ERROR is not frozen +} + +fn main() { + foo(&mut (1, 2)); +} From 36b97cd76c478d56820e1e18647841e1d144d852 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 15 Nov 2018 14:25:23 +0100 Subject: [PATCH 0376/3747] Factor out common top-level code from escape-to-raw and retag --- src/stacked_borrows.rs | 79 ++++++++++++++++++++++++++---------------- 1 file changed, 50 insertions(+), 29 deletions(-) diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 44fa605fd6a23..b088a6e845f54 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -303,6 +303,9 @@ impl<'tcx> Stacks { trace!("{} access of tag {:?}: {:?}, size {}", if is_write { "read" } else { "write" }, ptr.tag, ptr, size.bytes()); + // Even reads can have a side-effect, by invalidating other references. + // This is fundamentally necessary since `&mut` asserts that there + // are no accesses through other references, not even reads. let mut stacks = self.stacks.borrow_mut(); for stack in stacks.iter_mut(ptr.offset, size) { stack.access(ptr.tag, is_write)?; @@ -311,6 +314,7 @@ impl<'tcx> Stacks { } /// Reborrow the given pointer to the new tag for the given kind of reference. + /// This works on `&self` because we might encounter references to constant memory. fn reborrow( &self, ptr: Pointer, @@ -414,8 +418,16 @@ pub trait EvalContextExt<'tcx> { kind: MemoryKind, ) -> Borrow; - /// Retag an indidual pointer, returning the retagged version. + /// Reborrow the given place, returning the newly tagged ptr to it. fn reborrow( + &mut self, + place: MPlaceTy<'tcx, Borrow>, + size: Size, + new_bor: Borrow + ) -> EvalResult<'tcx, Pointer>; + + /// Retag an indidual pointer, returning the retagged version. + fn retag_reference( &mut self, ptr: ImmTy<'tcx, Borrow>, mutbl: Mutability, @@ -536,22 +548,46 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for MiriEvalContext<'a, 'mir, 'tcx> { } /// The given place may henceforth be accessed through raw pointers. + #[inline(always)] fn escape_to_raw( &mut self, place: MPlaceTy<'tcx, Borrow>, size: Size, ) -> EvalResult<'tcx> { - trace!("escape_to_raw: {:?} is now accessible by raw pointers", *place); - // Get the allocation + self.reborrow(place, size, Borrow::default())?; + Ok(()) + } + + fn reborrow( + &mut self, + place: MPlaceTy<'tcx, Borrow>, + size: Size, + new_bor: Borrow + ) -> EvalResult<'tcx, Pointer> { let ptr = place.ptr.to_ptr()?; - self.memory().check_bounds(ptr, size, false)?; // `ptr_dereference` wouldn't do any checks if this is a raw ptr + let new_ptr = Pointer::new_with_tag(ptr.alloc_id, ptr.offset, new_bor); + trace!("reborrow: Creating new reference for {:?} (pointee {}): {:?}", + ptr, place.layout.ty, new_bor); + + // Get the allocation. It might not be mutable, so we cannot use `get_mut`. + self.memory().check_bounds(ptr, size, false)?; let alloc = self.memory().get(ptr.alloc_id).expect("We checked that the ptr is fine!"); - // Re-borrow to raw. This is a NOP for shared borrows, but we do not know the borrow - // type here and that's also okay. Freezing does not matter here. - alloc.extra.reborrow(ptr, size, Borrow::default(), RefKind::Raw) + // Update the stacks. + if let Borrow::Shr(Some(_)) = new_bor { + // Reference that cares about freezing. We need a frozen-sensitive reborrow. + self.visit_freeze_sensitive(place, size, |cur_ptr, size, frozen| { + let kind = if frozen { RefKind::Frozen } else { RefKind::Raw }; + alloc.extra.reborrow(cur_ptr, size, new_bor, kind) + })?; + } else { + // Just treat this as one big chunk. + let kind = if new_bor.is_unique() { RefKind::Unique } else { RefKind::Raw }; + alloc.extra.reborrow(ptr, size, new_bor, kind)?; + } + Ok(new_ptr) } - fn reborrow( + fn retag_reference( &mut self, val: ImmTy<'tcx, Borrow>, mutbl: Mutability, @@ -566,33 +602,17 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for MiriEvalContext<'a, 'mir, 'tcx> { return Ok(*val); } - // Prepare to re-borrow this place. - let ptr = place.ptr.to_ptr()?; + // Compute new borrow. let time = self.machine.stacked_borrows.increment_clock(); let new_bor = match mutbl { MutMutable => Borrow::Uniq(time), MutImmutable => Borrow::Shr(Some(time)), }; - trace!("reborrow: Creating new {:?} reference for {:?} (pointee {}): {:?}", - mutbl, ptr, place.layout.ty, new_bor); - // Get the allocation. It might not be mutable, so we cannot use `get_mut`. - self.memory().check_bounds(ptr, size, false)?; - let alloc = self.memory().get(ptr.alloc_id).expect("We checked that the ptr is fine!"); - // Update the stacks. - if mutbl == MutImmutable { - // Shared reference. We need a frozen-sensitive reborrow. - self.visit_freeze_sensitive(place, size, |cur_ptr, size, frozen| { - let kind = if frozen { RefKind::Frozen } else { RefKind::Raw }; - alloc.extra.reborrow(cur_ptr, size, new_bor, kind) - })?; - } else { - // Mutable reference. Just treat this as one big chunk. - alloc.extra.reborrow(ptr, size, new_bor, RefKind::Unique)?; - } + // Reborrow. + let new_ptr = self.reborrow(place, size, new_bor)?; // Return new ptr - let new_ptr = Pointer::new_with_tag(ptr.alloc_id, ptr.offset, new_bor); let new_place = MemPlace { ptr: Scalar::Ptr(new_ptr), ..*place }; Ok(new_place.to_ref()) } @@ -611,8 +631,9 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for MiriEvalContext<'a, 'mir, 'tcx> { ty::Ref(_, _, mutbl) => { // fast path let val = self.read_immediate(self.place_to_op(place)?)?; - let val = self.reborrow(val, mutbl)?; + let val = self.retag_reference(val, mutbl)?; self.write_immediate(val, place)?; + return Ok(()); } _ => {}, // handled with the general case below }; @@ -643,7 +664,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for MiriEvalContext<'a, 'mir, 'tcx> { match place.layout.ty.sty { ty::Ref(_, _, mutbl) => { let val = self.ecx.read_immediate(place.into())?; - let val = self.ecx.reborrow(val, mutbl)?; + let val = self.ecx.retag_reference(val, mutbl)?; self.ecx.write_immediate(val, place.into())?; } _ => {}, // nothing to do From 733f675bccbd23a38d89e66a7ae4d9e5afcdf8bd Mon Sep 17 00:00:00 2001 From: Steve Klabnik Date: Fri, 16 Nov 2018 15:14:44 -0500 Subject: [PATCH 0377/3747] fix cargo invocation in the readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 5eb7b34425e6e..5e5a7a23c6afe 100644 --- a/README.md +++ b/README.md @@ -77,7 +77,7 @@ nightly). ## Running Miri on your own project('s test suite) -Install Miri as a cargo subcommand with `cargo install +nightly --all-features +Install Miri as a cargo subcommand with `cargo +nightly install --all-features --path .`. Be aware that if you used `rustup override set` to fix a particular Rust version for the miri directory, that will *not* apply to your own project directory! You have to use a consistent Rust version for building miri and your From b7dbb5e2a71e222b984c2ef062deccb1d9dd7c17 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 17 Nov 2018 10:05:30 +0100 Subject: [PATCH 0378/3747] also consider boxes like unique references --- src/stacked_borrows.rs | 16 +++++----- .../box_exclusive_violation1.rs | 29 +++++++++++++++++++ 2 files changed, 37 insertions(+), 8 deletions(-) create mode 100644 tests/compile-fail-fullmir/stacked_borrows/box_exclusive_violation1.rs diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index b088a6e845f54..3cf4365e35aa5 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -661,14 +661,14 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for MiriEvalContext<'a, 'mir, 'tcx> { // Primitives of reference type, that is the one thing we are interested in. fn visit_primitive(&mut self, place: MPlaceTy<'tcx, Borrow>) -> EvalResult<'tcx> { - match place.layout.ty.sty { - ty::Ref(_, _, mutbl) => { - let val = self.ecx.read_immediate(place.into())?; - let val = self.ecx.retag_reference(val, mutbl)?; - self.ecx.write_immediate(val, place.into())?; - } - _ => {}, // nothing to do - } + let mutbl = match place.layout.ty.sty { + ty::Ref(_, _, mutbl) => mutbl, + ty::Adt(..) if place.layout.ty.is_box() => MutMutable, + _ => return Ok(()), // nothing to do + }; + let val = self.ecx.read_immediate(place.into())?; + let val = self.ecx.retag_reference(val, mutbl)?; + self.ecx.write_immediate(val, place.into())?; Ok(()) } } diff --git a/tests/compile-fail-fullmir/stacked_borrows/box_exclusive_violation1.rs b/tests/compile-fail-fullmir/stacked_borrows/box_exclusive_violation1.rs new file mode 100644 index 0000000000000..73631173b932a --- /dev/null +++ b/tests/compile-fail-fullmir/stacked_borrows/box_exclusive_violation1.rs @@ -0,0 +1,29 @@ +fn demo_mut_advanced_unique(mut our: Box) -> i32 { + unknown_code_1(&*our); + + // This "re-asserts" uniqueness of the reference: After writing, we know + // our tag is at the top of the stack. + *our = 5; + + unknown_code_2(); + + // We know this will return 5 + *our //~ ERROR does not exist on the stack +} + +// Now comes the evil context +use std::ptr; + +static mut LEAK: *mut i32 = ptr::null_mut(); + +fn unknown_code_1(x: &i32) { unsafe { + LEAK = x as *const _ as *mut _; +} } + +fn unknown_code_2() { unsafe { + *LEAK = 7; +} } + +fn main() { + assert_eq!(demo_mut_advanced_unique(Box::new(0)), 5); +} From 880229d4c3c4032cb3e1c2b4c599af8a0ad0d1dc Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 17 Nov 2018 09:54:58 +0100 Subject: [PATCH 0379/3747] escape-on-cast, now ptr-deref does not change the tag at all, ever --- src/lib.rs | 6 ++--- src/stacked_borrows.rs | 22 ++++++++----------- .../stacked_borrows/buggy_as_mut_slice.rs | 10 +++------ .../stacked_borrows/transmute-is-no-escape.rs | 1 + 4 files changed, 16 insertions(+), 23 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index a0ed7c8e4fdbd..a5de02f6421b7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -461,9 +461,9 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { // No tracking Ok(place.ptr) } else { - let ptr = place.ptr.to_ptr()?; // assert this is not a scalar - let tag = ecx.tag_dereference(place, size, mutability.into())?; - Ok(Scalar::Ptr(Pointer::new_with_tag(ptr.alloc_id, ptr.offset, tag))) + ecx.ptr_dereference(place, size, mutability.into())?; + // We never change the pointer + Ok(place.ptr) } } diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 3cf4365e35aa5..2726c7dccb4ff 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -405,12 +405,12 @@ impl<'tcx> Stacks { pub trait EvalContextExt<'tcx> { - fn tag_dereference( + fn ptr_dereference( &self, place: MPlaceTy<'tcx, Borrow>, size: Size, mutability: Option, - ) -> EvalResult<'tcx, Borrow>; + ) -> EvalResult<'tcx>; fn tag_new_allocation( &mut self, @@ -480,13 +480,13 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for MiriEvalContext<'a, 'mir, 'tcx> { /// /// Note that this does NOT mean that all this memory will actually get accessed/referenced! /// We could be in the middle of `&(*var).1`. - fn tag_dereference( + fn ptr_dereference( &self, place: MPlaceTy<'tcx, Borrow>, size: Size, mutability: Option, - ) -> EvalResult<'tcx, Borrow> { - trace!("tag_dereference: Accessing {} reference for {:?} (pointee {})", + ) -> EvalResult<'tcx> { + trace!("ptr_dereference: Accessing {} reference for {:?} (pointee {})", if let Some(mutability) = mutability { format!("{:?}", mutability) } else { format!("raw") }, place.ptr, place.layout.ty); let ptr = place.ptr.to_ptr()?; @@ -497,12 +497,8 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for MiriEvalContext<'a, 'mir, 'tcx> { // That can transmute a raw ptr to a (shared/mut) ref, and a mut ref to a shared one. match (mutability, ptr.tag) { (None, _) => { - // Don't use the tag, this is a raw access! They should happen tagless. - // This is needed for `*mut` to make any sense: Writes *do* enforce the - // `Uniq` tag to be up top, but we must make sure raw writes do not do that. - // This does mean, however, that `&*foo` is *not* a NOP *if* `foo` is a raw ptr. - // Also don't do any further validation, this is raw after all. - return Ok(Borrow::default()); + // No further validation on raw accesses. + return Ok(()); } (Some(MutMutable), Borrow::Uniq(_)) | (Some(MutImmutable), Borrow::Shr(_)) => { @@ -543,8 +539,8 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for MiriEvalContext<'a, 'mir, 'tcx> { alloc.extra.deref(ptr, size, kind)?; } - // All is good, and do not change the tag - Ok(ptr.tag) + // All is good + Ok(()) } /// The given place may henceforth be accessed through raw pointers. diff --git a/tests/compile-fail-fullmir/stacked_borrows/buggy_as_mut_slice.rs b/tests/compile-fail-fullmir/stacked_borrows/buggy_as_mut_slice.rs index 2f3d0793f63e1..e08e3bba6840d 100644 --- a/tests/compile-fail-fullmir/stacked_borrows/buggy_as_mut_slice.rs +++ b/tests/compile-fail-fullmir/stacked_borrows/buggy_as_mut_slice.rs @@ -1,5 +1,3 @@ -// error-pattern: mutable reference with frozen tag - mod safe { use std::slice::from_raw_parts_mut; @@ -12,10 +10,8 @@ mod safe { fn main() { let v = vec![0,1,2]; - let _v1 = safe::as_mut_slice(&v); -/* - let v2 = safe::as_mut_slice(&v); + let v1 = safe::as_mut_slice(&v); + let _v2 = safe::as_mut_slice(&v); v1[1] = 5; - v1[1] = 6; -*/ + //~^ ERROR does not exist on the stack } diff --git a/tests/compile-fail-fullmir/stacked_borrows/transmute-is-no-escape.rs b/tests/compile-fail-fullmir/stacked_borrows/transmute-is-no-escape.rs index 1ab005e3fa17d..75abce3111f88 100644 --- a/tests/compile-fail-fullmir/stacked_borrows/transmute-is-no-escape.rs +++ b/tests/compile-fail-fullmir/stacked_borrows/transmute-is-no-escape.rs @@ -8,5 +8,6 @@ use std::mem; fn main() { let mut x: i32 = 42; let raw: *mut i32 = unsafe { mem::transmute(&mut x) }; + let raw = raw as usize as *mut i32; // make sure we killed the tag unsafe { *raw = 13; } //~ ERROR does not exist on the stack } From 662821f7f732f85e05b85e59ee45747dc52fc2c8 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 17 Nov 2018 10:11:21 +0100 Subject: [PATCH 0380/3747] raw ptr deref no longer erases the tag --- src/fn_call.rs | 60 ++++++++++++++++++++++++------------------------ src/intrinsic.rs | 10 ++++---- 2 files changed, 35 insertions(+), 35 deletions(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index 150cf7402a6dd..41b3c1f7e6603 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -131,10 +131,10 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo } "free" => { - let ptr = self.read_scalar(args[0])?.not_undef()?.erase_tag(); // raw ptr operation, no tag + let ptr = self.read_scalar(args[0])?.not_undef()?; if !ptr.is_null_ptr(self) { self.memory_mut().deallocate( - ptr.to_ptr()?.with_default_tag(), + ptr.to_ptr()?, None, MiriMemoryKind::C.into(), )?; @@ -179,7 +179,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo self.write_scalar(Scalar::Ptr(ptr), dest)?; } "__rust_dealloc" => { - let ptr = self.read_scalar(args[0])?.to_ptr()?.erase_tag(); // raw ptr operation, no tag + let ptr = self.read_scalar(args[0])?.to_ptr()?; let old_size = self.read_scalar(args[1])?.to_usize(self)?; let align = self.read_scalar(args[2])?.to_usize(self)?; if old_size == 0 { @@ -189,13 +189,13 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo return err!(HeapAllocNonPowerOfTwoAlignment(align)); } self.memory_mut().deallocate( - ptr.with_default_tag(), + ptr, Some((Size::from_bytes(old_size), Align::from_bytes(align, align).unwrap())), MiriMemoryKind::Rust.into(), )?; } "__rust_realloc" => { - let ptr = self.read_scalar(args[0])?.to_ptr()?.erase_tag(); // raw ptr operation, no tag + let ptr = self.read_scalar(args[0])?.to_ptr()?; let old_size = self.read_scalar(args[1])?.to_usize(self)?; let align = self.read_scalar(args[2])?.to_usize(self)?; let new_size = self.read_scalar(args[3])?.to_usize(self)?; @@ -206,7 +206,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo return err!(HeapAllocNonPowerOfTwoAlignment(align)); } let new_ptr = self.memory_mut().reallocate( - ptr.with_default_tag(), + ptr, Size::from_bytes(old_size), Align::from_bytes(align, align).unwrap(), Size::from_bytes(new_size), @@ -238,8 +238,8 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo "dlsym" => { let _handle = self.read_scalar(args[0])?; - let symbol = self.read_scalar(args[1])?.to_ptr()?.erase_tag(); - let symbol_name = self.memory().read_c_str(symbol.with_default_tag())?; + let symbol = self.read_scalar(args[1])?.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); return err!(Unimplemented(format!( @@ -292,13 +292,13 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo return err!(MachineError("the evaluated program panicked".to_string())), "memcmp" => { - let left = self.read_scalar(args[0])?.not_undef()?.erase_tag(); // raw ptr operation - let right = self.read_scalar(args[1])?.not_undef()?.erase_tag(); // raw ptr operation + let left = self.read_scalar(args[0])?.not_undef()?; + let right = self.read_scalar(args[1])?.not_undef()?; let n = Size::from_bytes(self.read_scalar(args[2])?.to_usize(self)?); let result = { - let left_bytes = self.memory().read_bytes(left.with_default_tag(), n)?; - let right_bytes = self.memory().read_bytes(right.with_default_tag(), n)?; + let left_bytes = self.memory().read_bytes(left, n)?; + let right_bytes = self.memory().read_bytes(right, n)?; use std::cmp::Ordering::*; match left_bytes.cmp(right_bytes) { @@ -315,8 +315,8 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo } "memrchr" => { - let ptr = self.read_scalar(args[0])?.not_undef()?.erase_tag(); // raw ptr operation - let ptr = ptr.with_default_tag(); + let ptr = self.read_scalar(args[0])?.not_undef()?; + let ptr = ptr; let val = self.read_scalar(args[1])?.to_bytes()? as u8; let num = self.read_scalar(args[2])?.to_usize(self)?; if let Some(idx) = self.memory().read_bytes(ptr, Size::from_bytes(num))? @@ -330,8 +330,8 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo } "memchr" => { - let ptr = self.read_scalar(args[0])?.not_undef()?.erase_tag(); // raw ptr operation - let ptr = ptr.with_default_tag(); + let ptr = self.read_scalar(args[0])?.not_undef()?; + let ptr = ptr; let val = self.read_scalar(args[1])?.to_bytes()? as u8; let num = self.read_scalar(args[2])?.to_usize(self)?; if let Some(idx) = self.memory().read_bytes(ptr, Size::from_bytes(num))?.iter().position( @@ -347,8 +347,8 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo "getenv" => { let result = { - let name_ptr = self.read_scalar(args[0])?.to_ptr()?.erase_tag(); // raw ptr operation - let name = self.memory().read_c_str(name_ptr.with_default_tag())?; + let name_ptr = self.read_scalar(args[0])?.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::ptr_null(&*self.tcx), @@ -360,10 +360,10 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo "unsetenv" => { let mut success = None; { - let name_ptr = self.read_scalar(args[0])?.not_undef()?.erase_tag(); // raw ptr operation + let name_ptr = self.read_scalar(args[0])?.not_undef()?; if !name_ptr.is_null_ptr(self) { let name = self.memory().read_c_str(name_ptr.to_ptr()? - .with_default_tag())?.to_owned(); + )?.to_owned(); if !name.is_empty() && !name.contains(&b'=') { success = Some(self.machine.env_vars.remove(&name)); } @@ -382,11 +382,11 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo "setenv" => { let mut new = None; { - let name_ptr = self.read_scalar(args[0])?.not_undef()?.erase_tag(); // raw ptr operation - let value_ptr = self.read_scalar(args[1])?.to_ptr()?.erase_tag(); // raw ptr operation - let value = self.memory().read_c_str(value_ptr.with_default_tag())?; + let name_ptr = self.read_scalar(args[0])?.not_undef()?; + let value_ptr = self.read_scalar(args[1])?.to_ptr()?; + let value = self.memory().read_c_str(value_ptr)?; if !name_ptr.is_null_ptr(self) { - let name = self.memory().read_c_str(name_ptr.to_ptr()?.with_default_tag())?; + 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())); } @@ -417,14 +417,14 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo "write" => { let fd = self.read_scalar(args[0])?.to_bytes()?; - let buf = self.read_scalar(args[1])?.not_undef()?.erase_tag(); + let buf = self.read_scalar(args[1])?.not_undef()?; let n = self.read_scalar(args[2])?.to_bytes()? as u64; trace!("Called write({:?}, {:?}, {:?})", fd, buf, n); let result = if fd == 1 || fd == 2 { // stdout/stderr use std::io::{self, Write}; - let buf_cont = self.memory().read_bytes(buf.with_default_tag(), Size::from_bytes(n))?; + let buf_cont = self.memory().read_bytes(buf, Size::from_bytes(n))?; let res = if fd == 1 { io::stdout().write(buf_cont) } else { @@ -445,8 +445,8 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo } "strlen" => { - let ptr = self.read_scalar(args[0])?.to_ptr()?.erase_tag(); - let n = self.memory().read_c_str(ptr.with_default_tag())?.len(); + let ptr = self.read_scalar(args[0])?.to_ptr()?; + let n = self.memory().read_c_str(ptr)?.len(); self.write_scalar(Scalar::from_uint(n as u64, dest.layout.size), dest)?; } @@ -492,7 +492,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo // Hook pthread calls that go to the thread-local storage memory subsystem "pthread_key_create" => { - let key_ptr = self.read_scalar(args[0])?.to_ptr()?.erase_tag(); // raw ptr operation + let key_ptr = self.read_scalar(args[0])?.to_ptr()?; // Extract the function type out of the signature (that seems easier than constructing it ourselves...) let dtor = match self.read_scalar(args[1])?.not_undef()? { @@ -515,7 +515,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo return err!(OutOfTls); } self.memory_mut().write_scalar( - key_ptr.with_default_tag(), + key_ptr, key_layout.align, Scalar::from_uint(key, key_layout.size).into(), key_layout.size, diff --git a/src/intrinsic.rs b/src/intrinsic.rs index e23cadfcaf0b7..6d5ac8d88bae2 100644 --- a/src/intrinsic.rs +++ b/src/intrinsic.rs @@ -154,12 +154,12 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' let count = self.read_scalar(args[2])?.to_usize(self)?; let elem_align = elem_layout.align; // erase tags: this is a raw ptr operation - let src = self.read_scalar(args[0])?.not_undef()?.erase_tag(); - let dest = self.read_scalar(args[1])?.not_undef()?.erase_tag(); + let src = self.read_scalar(args[0])?.not_undef()?; + let dest = self.read_scalar(args[1])?.not_undef()?; self.memory_mut().copy( - src.with_default_tag(), + src, elem_align, - dest.with_default_tag(), + dest, elem_align, Size::from_bytes(count * elem_size), intrinsic_name.ends_with("_nonoverlapping"), @@ -436,7 +436,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' let ty = substs.type_at(0); let ty_layout = self.layout_of(ty)?; let val_byte = self.read_scalar(args[1])?.to_u8()?; - let ptr = self.read_scalar(args[0])?.not_undef()?.erase_tag().with_default_tag(); + let ptr = self.read_scalar(args[0])?.not_undef()?; let count = self.read_scalar(args[2])?.to_usize(self)?; self.memory().check_align(ptr, ty_layout.align)?; self.memory_mut().write_repeat(ptr, val_byte, ty_layout.size * count)?; From 56f1ef325a193c366f327d7ec1d6633b36331242 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 17 Nov 2018 10:29:16 +0100 Subject: [PATCH 0381/3747] remove spurious assignments --- src/fn_call.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index 41b3c1f7e6603..509db0355e2ba 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -316,7 +316,6 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo "memrchr" => { let ptr = self.read_scalar(args[0])?.not_undef()?; - let ptr = ptr; let val = self.read_scalar(args[1])?.to_bytes()? as u8; let num = self.read_scalar(args[2])?.to_usize(self)?; if let Some(idx) = self.memory().read_bytes(ptr, Size::from_bytes(num))? @@ -331,7 +330,6 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo "memchr" => { let ptr = self.read_scalar(args[0])?.not_undef()?; - let ptr = ptr; let val = self.read_scalar(args[1])?.to_bytes()? as u8; let num = self.read_scalar(args[2])?.to_usize(self)?; if let Some(idx) = self.memory().read_bytes(ptr, Size::from_bytes(num))?.iter().position( From 731f35154376e01180d2c238920033ced2a9ae34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Kr=C3=BCger?= Date: Sat, 17 Nov 2018 12:24:27 +0100 Subject: [PATCH 0382/3747] benchmarks: make them build again --- benches/fibonacci.rs | 4 ++-- benches/helpers/miri_helper.rs | 4 ++-- benches/repeat.rs | 4 ++-- benches/smoke.rs | 4 ++-- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/benches/fibonacci.rs b/benches/fibonacci.rs index 90b231a32bfb0..10c119d9017ab 100644 --- a/benches/fibonacci.rs +++ b/benches/fibonacci.rs @@ -1,9 +1,9 @@ #![feature(test, rustc_private)] extern crate test; -use test::Bencher; +use crate::test::Bencher; mod helpers; -use helpers::*; +use crate::helpers::*; #[bench] fn fib(bencher: &mut Bencher) { diff --git a/benches/helpers/miri_helper.rs b/benches/helpers/miri_helper.rs index 0fbb46246aea8..015e36c4f5ad7 100644 --- a/benches/helpers/miri_helper.rs +++ b/benches/helpers/miri_helper.rs @@ -8,7 +8,7 @@ use self::miri::eval_main; use self::rustc_driver::{driver, Compilation}; use std::cell::RefCell; use std::rc::Rc; -use test::Bencher; +use crate::test::Bencher; pub struct MiriCompilerCalls<'a>(Rc>); @@ -50,7 +50,7 @@ pub fn run(filename: &str, bencher: &mut Bencher) { let entry_def_id = tcx.hir.local_def_id(entry_node_id); bencher.borrow_mut().iter(|| { - eval_main(tcx, entry_def_id, None); + eval_main(tcx, entry_def_id, false); }); state.session.abort_if_errors(); diff --git a/benches/repeat.rs b/benches/repeat.rs index f5920e83d9b07..0369b1f74cf59 100644 --- a/benches/repeat.rs +++ b/benches/repeat.rs @@ -1,9 +1,9 @@ #![feature(test, rustc_private)] extern crate test; -use test::Bencher; +use crate::test::Bencher; mod helpers; -use helpers::*; +use crate::helpers::*; #[bench] fn repeat(bencher: &mut Bencher) { diff --git a/benches/smoke.rs b/benches/smoke.rs index 1dbc4fed82f1c..7d614e2682988 100644 --- a/benches/smoke.rs +++ b/benches/smoke.rs @@ -1,9 +1,9 @@ #![feature(test, rustc_private)] extern crate test; -use test::Bencher; +use crate::test::Bencher; mod helpers; -use helpers::*; +use crate::helpers::*; #[bench] fn noop(bencher: &mut Bencher) { From c847071355eef7c8a1555d9c25d95e8fa9eccabf Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 17 Nov 2018 12:33:44 +0100 Subject: [PATCH 0383/3747] add comment about not using builtin_deref --- src/stacked_borrows.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 2726c7dccb4ff..c437eaf3fc70b 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -624,6 +624,8 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for MiriEvalContext<'a, 'mir, 'tcx> { // a `MemPlace`, so we have a fast path for reference types that // avoids allocating. match place.layout.ty.sty { + // Cannot use `builtin_deref` because that reports *immutable* for `Box`, + // making it useless. ty::Ref(_, _, mutbl) => { // fast path let val = self.read_immediate(self.place_to_op(place)?)?; @@ -657,6 +659,8 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for MiriEvalContext<'a, 'mir, 'tcx> { // Primitives of reference type, that is the one thing we are interested in. fn visit_primitive(&mut self, place: MPlaceTy<'tcx, Borrow>) -> EvalResult<'tcx> { + // Cannot use `builtin_deref` because that reports *immutable* for `Box`, + // making it useless. let mutbl = match place.layout.ty.sty { ty::Ref(_, _, mutbl) => mutbl, ty::Adt(..) if place.layout.ty.is_box() => MutMutable, From 19f8a9db7d2eca9f693827b1437108e9cc830a6b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 17 Nov 2018 12:35:43 +0100 Subject: [PATCH 0384/3747] Boxes can also use the fast path --- src/stacked_borrows.rs | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index c437eaf3fc70b..0da130260df27 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -623,18 +623,19 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for MiriEvalContext<'a, 'mir, 'tcx> { // We need a visitor to visit all references. However, that requires // a `MemPlace`, so we have a fast path for reference types that // avoids allocating. - match place.layout.ty.sty { - // Cannot use `builtin_deref` because that reports *immutable* for `Box`, - // making it useless. - ty::Ref(_, _, mutbl) => { - // fast path - let val = self.read_immediate(self.place_to_op(place)?)?; - let val = self.retag_reference(val, mutbl)?; - self.write_immediate(val, place)?; - return Ok(()); - } - _ => {}, // handled with the general case below - }; + // Cannot use `builtin_deref` because that reports *immutable* for `Box`, + // making it useless. + if let Some(mutbl) = match place.layout.ty.sty { + ty::Ref(_, _, mutbl) => Some(mutbl), + ty::Adt(..) if place.layout.ty.is_box() => Some(MutMutable), + _ => None, // handled with the general case below + } { + // fast path + let val = self.read_immediate(self.place_to_op(place)?)?; + let val = self.retag_reference(val, mutbl)?; + self.write_immediate(val, place)?; + return Ok(()); + } let place = self.force_allocation(place)?; let mut visitor = RetagVisitor { ecx: self }; From 3102b1346808b48419d037aba0dc18f36dd22ce8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Kr=C3=BCger?= Date: Sat, 17 Nov 2018 13:57:45 +0100 Subject: [PATCH 0385/3747] travis: build benchmarks as well --- .travis.yml | 2 +- appveyor.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index f989c7705b19a..85dd50cb5e3c3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -35,7 +35,7 @@ script: - set -e - | # Test and install plain miri - cargo build --release --all-features && + cargo build --release --all-features --all-targets && cargo test --release --all-features && cargo install --all-features --force --path . - | diff --git a/appveyor.yml b/appveyor.yml index 1e9ccbdf95000..f03251e669e6d 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -37,7 +37,7 @@ build: false test_script: - set RUSTFLAGS=-g - set RUST_BACKTRACE=1 - - cargo build --release + - cargo build --release --all-targets --all-features - cargo test --release - set MIRI_SYSROOT=%USERPROFILE%\.xargo\HOST - cargo test --release From 18b2426b1b55cd9262a60626d0622bee57fe9396 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 17 Nov 2018 14:49:24 +0100 Subject: [PATCH 0386/3747] AppVeyor: consistently use --all-features --- appveyor.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index f03251e669e6d..dddf8913149b2 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -38,9 +38,9 @@ test_script: - set RUSTFLAGS=-g - set RUST_BACKTRACE=1 - cargo build --release --all-targets --all-features - - cargo test --release + - cargo test --release --all-features - set MIRI_SYSROOT=%USERPROFILE%\.xargo\HOST - - cargo test --release + - cargo test --release --all-features notifications: - provider: Email From 06d77730dea354d3fe11920276eb13d7f1cca1f8 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 19 Nov 2018 09:42:03 +0100 Subject: [PATCH 0387/3747] reorder cargo flags for consistency --- appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index dddf8913149b2..3dc47f1c67b6a 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -37,7 +37,7 @@ build: false test_script: - set RUSTFLAGS=-g - set RUST_BACKTRACE=1 - - cargo build --release --all-targets --all-features + - cargo build --release --all-features --all-targets - cargo test --release --all-features - set MIRI_SYSROOT=%USERPROFILE%\.xargo\HOST - cargo test --release --all-features From a806805f2373a41f0c23604fc3bc6f9b07f6895a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 19 Nov 2018 10:26:40 +0100 Subject: [PATCH 0388/3747] add an interesting testcase --- tests/run-pass-fullmir/box-pair-to-vec.rs | 28 +++++++++++++++++++ tests/run-pass-fullmir/box-pair-to-vec.stdout | 3 ++ 2 files changed, 31 insertions(+) create mode 100644 tests/run-pass-fullmir/box-pair-to-vec.rs create mode 100644 tests/run-pass-fullmir/box-pair-to-vec.stdout diff --git a/tests/run-pass-fullmir/box-pair-to-vec.rs b/tests/run-pass-fullmir/box-pair-to-vec.rs new file mode 100644 index 0000000000000..353afb9d32100 --- /dev/null +++ b/tests/run-pass-fullmir/box-pair-to-vec.rs @@ -0,0 +1,28 @@ +#[repr(C)] +#[derive(Debug)] +struct PairFoo { + fst: Foo, + snd: Foo, +} + +#[derive(Debug)] +struct Foo(u64); +fn reinterstruct(box_pair: Box) -> Vec { + let ref_pair = Box::leak(box_pair) as *mut PairFoo; + let ptr_foo = unsafe { &mut (*ref_pair).fst as *mut Foo }; + unsafe { + Vec::from_raw_parts(ptr_foo, 2, 2) + } +} + +fn main() { + let pair_foo = Box::new(PairFoo { + fst: Foo(42), + snd: Foo(1337), + }); + println!("pair_foo = {:?}", pair_foo); + for (n, foo) in reinterstruct(pair_foo).into_iter().enumerate() { + println!("foo #{} = {:?}", n, foo); + } +} + diff --git a/tests/run-pass-fullmir/box-pair-to-vec.stdout b/tests/run-pass-fullmir/box-pair-to-vec.stdout new file mode 100644 index 0000000000000..230ef368da644 --- /dev/null +++ b/tests/run-pass-fullmir/box-pair-to-vec.stdout @@ -0,0 +1,3 @@ +pair_foo = PairFoo { fst: Foo(42), snd: Foo(1337) } +foo #0 = Foo(42) +foo #1 = Foo(1337) From ef2ffed93fcfa6f1731621919a1b29f8783a8fe9 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 19 Nov 2018 22:59:41 +0100 Subject: [PATCH 0389/3747] port cargo-miri-test to 2018 edition, mostly to test that that works with cargo miri --- cargo-miri-test/Cargo.toml | 3 ++- cargo-miri-test/src/main.rs | 2 -- src/bin/cargo-miri.rs | 12 ++++++++++-- 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/cargo-miri-test/Cargo.toml b/cargo-miri-test/Cargo.toml index 5fbe923f23d3b..4fe009e025e13 100644 --- a/cargo-miri-test/Cargo.toml +++ b/cargo-miri-test/Cargo.toml @@ -2,6 +2,7 @@ name = "cargo-miri-test" version = "0.1.0" authors = ["Oliver Schneider "] +edition = "2018" [dependencies] -byteorder = "1.0" \ No newline at end of file +byteorder = "1.0" diff --git a/cargo-miri-test/src/main.rs b/cargo-miri-test/src/main.rs index 4e1501dd57f27..1ae88a7db5940 100644 --- a/cargo-miri-test/src/main.rs +++ b/cargo-miri-test/src/main.rs @@ -1,5 +1,3 @@ -extern crate byteorder; - use byteorder::{BigEndian, ByteOrder}; fn main() { diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 69c4f122544a5..da4a351368d32 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -46,11 +46,15 @@ fn main() { } if let Some("miri") = std::env::args().nth(1).as_ref().map(AsRef::as_ref) { - // this arm is when `cargo miri` is called + // this arm is when `cargo miri` is called. We call `cargo rustc` for + // each applicable target, but with the RUSTC env var set to the `cargo-miri` + // binary so that we come back in the other branch, and dispatch + // the invocations to rustc and miri, respectively. let test = std::env::args().nth(2).map_or(false, |text| text == "test"); let skip = if test { 3 } else { 2 }; + // We need to get the manifest, and then the metadata, to enumerate targets. let manifest_path_arg = std::env::args().skip(skip).find(|val| { val.starts_with("--manifest-path=") }); @@ -92,6 +96,9 @@ fn main() { }) .expect("could not find matching package"); let package = metadata.packages.remove(package_index); + + // Finally we got the metadata, iterate all targets and see for which ones + // we do anything. for target in package.targets { let args = std::env::args().skip(skip); let kind = target.kind.get(0).expect( @@ -139,7 +146,8 @@ fn main() { } } } else { - // this arm is executed when cargo-miri runs `cargo rustc` with the `RUSTC` env var set to itself + // This arm is executed when cargo-miri runs `cargo rustc` with the `RUSTC` env var set to itself: + // Dependencies get dispatched to rustc, the final test/binary to miri. let home = option_env!("RUSTUP_HOME").or(option_env!("MULTIRUST_HOME")); let toolchain = option_env!("RUSTUP_TOOLCHAIN").or(option_env!("MULTIRUST_TOOLCHAIN")); From b8486ce9d693aa2aa987409690bf146cef20fe41 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 20 Nov 2018 08:30:18 +0100 Subject: [PATCH 0390/3747] bump Rust version --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 6c3858ccc9cd7..dcd90feeda812 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -nightly-2018-11-16 +nightly-2018-11-20 From 6085865975ee48283ddc7604c7be5caafabd3ccb Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 20 Nov 2018 08:42:51 +0100 Subject: [PATCH 0391/3747] adjust for InboundsCheck parameter of memory bounds check --- src/operator.rs | 17 ++++++++++------- src/stacked_borrows.rs | 6 +++--- .../compile-fail-fullmir/out_of_bounds_ptr_1.rs | 2 +- 3 files changed, 14 insertions(+), 11 deletions(-) diff --git a/src/operator.rs b/src/operator.rs index e5c695009cfae..be05c2259957e 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -142,8 +142,9 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' // allocations sit right next to each other. The C/C++ standards are // somewhat fuzzy about this case, so I think for now this check is // "good enough". - self.memory().check_bounds_ptr(left, false)?; - self.memory().check_bounds_ptr(right, false)?; + // We require liveness, as dead allocations can of course overlap. + self.memory().check_bounds_ptr(left, InboundsCheck::Live)?; + self.memory().check_bounds_ptr(right, InboundsCheck::Live)?; // Two live in-bounds pointers, we can compare across allocations left == right } @@ -153,15 +154,17 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' (Scalar::Bits { bits, size }, Scalar::Ptr(ptr)) => { assert_eq!(size as u64, self.pointer_size().bytes()); let bits = bits as u64; - let (alloc_size, alloc_align) = self.memory().get_size_and_align(ptr.alloc_id); // Case I: Comparing with NULL if bits == 0 { // Test if the ptr is in-bounds. Then it cannot be NULL. - if ptr.offset <= alloc_size { + if self.memory().check_bounds_ptr(ptr, InboundsCheck::MaybeDead).is_ok() { return Ok(false); } } + + let (alloc_size, alloc_align) = self.memory().get_size_and_align(ptr.alloc_id); + // Case II: Alignment gives it away if ptr.offset.bytes() % alloc_align.abi() == 0 { // The offset maintains the allocation alignment, so we know `base+offset` @@ -293,11 +296,11 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' let offset = offset.checked_mul(pointee_size).ok_or_else(|| EvalErrorKind::Overflow(mir::BinOp::Mul))?; // Now let's see what kind of pointer this is if let Scalar::Ptr(ptr) = ptr { - // Both old and new pointer must be in-bounds. + // Both old and new pointer must be in-bounds of a *live* allocation. // (Of the same allocation, but that part is trivial with our representation.) - self.memory().check_bounds_ptr(ptr, false)?; + self.memory().check_bounds_ptr(ptr, InboundsCheck::Live)?; let ptr = ptr.signed_offset(offset, self)?; - self.memory().check_bounds_ptr(ptr, false)?; + self.memory().check_bounds_ptr(ptr, InboundsCheck::Live)?; Ok(Scalar::Ptr(ptr)) } else { // An integer pointer. They can only be offset by 0, and we pretend there diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 0da130260df27..063a544baa655 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -5,7 +5,7 @@ use rustc::hir::{Mutability, MutMutable, MutImmutable}; use crate::{ EvalResult, EvalErrorKind, MiriEvalContext, HelpersEvalContextExt, Evaluator, MutValueVisitor, - MemoryKind, MiriMemoryKind, RangeMap, AllocId, Allocation, AllocationExtra, + MemoryKind, MiriMemoryKind, RangeMap, AllocId, Allocation, AllocationExtra, InboundsCheck, Pointer, MemPlace, Scalar, Immediate, ImmTy, PlaceTy, MPlaceTy, }; @@ -523,7 +523,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for MiriEvalContext<'a, 'mir, 'tcx> { } // Get the allocation - self.memory().check_bounds(ptr, size, false)?; + self.memory().check_bounds(ptr, size, InboundsCheck::Live)?; let alloc = self.memory().get(ptr.alloc_id).expect("We checked that the ptr is fine!"); // If we got here, we do some checking, *but* we leave the tag unchanged. if let Borrow::Shr(Some(_)) = ptr.tag { @@ -566,7 +566,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for MiriEvalContext<'a, 'mir, 'tcx> { ptr, place.layout.ty, new_bor); // Get the allocation. It might not be mutable, so we cannot use `get_mut`. - self.memory().check_bounds(ptr, size, false)?; + self.memory().check_bounds(ptr, size, InboundsCheck::Live)?; let alloc = self.memory().get(ptr.alloc_id).expect("We checked that the ptr is fine!"); // Update the stacks. if let Borrow::Shr(Some(_)) = new_bor { diff --git a/tests/compile-fail-fullmir/out_of_bounds_ptr_1.rs b/tests/compile-fail-fullmir/out_of_bounds_ptr_1.rs index 8dce7e5786264..ce1c89a2a0081 100644 --- a/tests/compile-fail-fullmir/out_of_bounds_ptr_1.rs +++ b/tests/compile-fail-fullmir/out_of_bounds_ptr_1.rs @@ -1,4 +1,4 @@ -// error-pattern: pointer computed at offset 5, outside bounds of allocation +// error-pattern: must be in-bounds and live at offset 5, but is outside bounds of allocation fn main() { let v = [0i8; 4]; let x = &v as *const i8; From cfa6397ad0b26c75fd7fbb5d6f89860d1662b14d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 20 Nov 2018 08:50:08 +0100 Subject: [PATCH 0392/3747] UnsafeCell no longer needs to be on the whitelist --- src/lib.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index d4dd198323ec4..418f8f60cecd9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -320,8 +320,6 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { // Uses mem::uninitialized ("std::ptr::read", ""), ("std::sys::windows::mutex::Mutex::", ""), - // Should directly take a raw reference - (">", "::get"), ]; for frame in ecx.stack().iter() .rev().take(3) From 5b095e16520e28ed2333879798f666c2a3d6c8f9 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 20 Nov 2018 09:12:29 +0100 Subject: [PATCH 0393/3747] stdout not implemented on windows --- tests/run-pass-fullmir/box-pair-to-vec.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/run-pass-fullmir/box-pair-to-vec.rs b/tests/run-pass-fullmir/box-pair-to-vec.rs index 353afb9d32100..3b829d0f1294f 100644 --- a/tests/run-pass-fullmir/box-pair-to-vec.rs +++ b/tests/run-pass-fullmir/box-pair-to-vec.rs @@ -1,3 +1,5 @@ +//ignore-msvc: Stdout not implemented on Windows + #[repr(C)] #[derive(Debug)] struct PairFoo { From 1ae536b03e90f3f2d9ef7bc0420deaf8362a85ff Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 20 Nov 2018 12:41:34 +0100 Subject: [PATCH 0394/3747] use 2018 edition for tests --- tests/compiletest.rs | 2 ++ tests/run-pass/stacked-borrows.rs | 12 +++++------- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/tests/compiletest.rs b/tests/compiletest.rs index 7ecf64590b614..7aa55ef663408 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -62,6 +62,7 @@ fn compile_fail(sysroot: &Path, path: &str, target: &str, host: &str, need_fullm let mut flags = Vec::new(); flags.push(format!("--sysroot {}", sysroot.display())); flags.push("-Dwarnings -Dunused".to_owned()); // overwrite the -Aunused in compiletest-rs + flags.push("--edition 2018".to_owned()); if opt { // Optimizing too aggressivley makes UB detection harder, but test at least // the default value. @@ -98,6 +99,7 @@ fn miri_pass(sysroot: &Path, path: &str, target: &str, host: &str, need_fullmir: let mut flags = Vec::new(); flags.push(format!("--sysroot {}", sysroot.display())); flags.push("-Dwarnings -Dunused".to_owned()); // overwrite the -Aunused in compiletest-rs + flags.push("--edition 2018".to_owned()); if opt { // FIXME: We use opt level 1 because MIR inlining defeats the validation // whitelist. diff --git a/tests/run-pass/stacked-borrows.rs b/tests/run-pass/stacked-borrows.rs index 7b7a7c9be2030..72f26763be140 100644 --- a/tests/run-pass/stacked-borrows.rs +++ b/tests/run-pass/stacked-borrows.rs @@ -68,13 +68,11 @@ fn mut_shr_raw() { // That should work. fn mut_raw_then_mut_shr() { let mut x = 2; - { - let xref = &mut x; - let xraw = &mut *xref as *mut _; - let xshr = &*xref; - assert_eq!(*xshr, 2); - unsafe { *xraw = 4; } - } + let xref = &mut x; + let xraw = &mut *xref as *mut _; + let xshr = &*xref; + assert_eq!(*xshr, 2); + unsafe { *xraw = 4; } assert_eq!(x, 4); } From 22f11b8eec844624a0285d2d6c6ee47880542636 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 20 Nov 2018 14:11:27 +0100 Subject: [PATCH 0395/3747] make tests compatible with 2018 edition --- tests/compile-fail/ctlz_nonzero.rs | 2 +- tests/compile-fail/cttz_nonzero.rs | 2 +- tests/run-pass-fullmir/foreign-fn-linkname.rs | 6 ++++-- tests/run-pass-fullmir/memchr.rs | 1 - tests/run-pass/intrinsics-integer.rs | 2 +- 5 files changed, 7 insertions(+), 6 deletions(-) diff --git a/tests/compile-fail/ctlz_nonzero.rs b/tests/compile-fail/ctlz_nonzero.rs index 4e2ccd0ac508a..86fd5ec46c202 100644 --- a/tests/compile-fail/ctlz_nonzero.rs +++ b/tests/compile-fail/ctlz_nonzero.rs @@ -8,7 +8,7 @@ mod rusti { pub fn main() { unsafe { - use rusti::*; + use crate::rusti::*; ctlz_nonzero(0u8); //~ ERROR constant evaluation error: ctlz_nonzero called on 0 } diff --git a/tests/compile-fail/cttz_nonzero.rs b/tests/compile-fail/cttz_nonzero.rs index 50b8df6199827..a6c3b03cfb5c1 100644 --- a/tests/compile-fail/cttz_nonzero.rs +++ b/tests/compile-fail/cttz_nonzero.rs @@ -8,7 +8,7 @@ mod rusti { pub fn main() { unsafe { - use rusti::*; + use crate::rusti::*; cttz_nonzero(0u8); //~ ERROR constant evaluation error: cttz_nonzero called on 0 } diff --git a/tests/run-pass-fullmir/foreign-fn-linkname.rs b/tests/run-pass-fullmir/foreign-fn-linkname.rs index 789e3eccceb7c..b61cfa84ef752 100644 --- a/tests/run-pass-fullmir/foreign-fn-linkname.rs +++ b/tests/run-pass-fullmir/foreign-fn-linkname.rs @@ -9,14 +9,16 @@ // except according to those terms. //ignore-windows: Uses POSIX APIs -#![feature(libc)] + +#![feature(libc, extern_crate_item_prelude)] +#![allow(unused_extern_crates)] // rustc bug https://github.com/rust-lang/rust/issues/56098 extern crate libc; + use std::ffi::CString; mod mlibc { use libc::{c_char, size_t}; - extern { #[link_name = "strlen"] pub fn my_strlen(str: *const c_char) -> size_t; diff --git a/tests/run-pass-fullmir/memchr.rs b/tests/run-pass-fullmir/memchr.rs index 36eb85dcf7e8d..2f5e2c4bb739e 100644 --- a/tests/run-pass-fullmir/memchr.rs +++ b/tests/run-pass-fullmir/memchr.rs @@ -1,6 +1,5 @@ #![feature(slice_internals)] -extern crate core; use core::slice::memchr::{memchr, memrchr}; // test fallback implementations on all platforms diff --git a/tests/run-pass/intrinsics-integer.rs b/tests/run-pass/intrinsics-integer.rs index 4896f02da20b0..de59314eff5a0 100644 --- a/tests/run-pass/intrinsics-integer.rs +++ b/tests/run-pass/intrinsics-integer.rs @@ -23,7 +23,7 @@ mod rusti { pub fn main() { unsafe { - use rusti::*; + use crate::rusti::*; assert_eq!(ctpop(0u8), 0); assert_eq!(ctpop(0i8), 0); assert_eq!(ctpop(0u16), 0); assert_eq!(ctpop(0i16), 0); From 8d6472a76c6615ad56c693b706e1232e07537b71 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 20 Nov 2018 12:51:55 +0100 Subject: [PATCH 0396/3747] test self-referential generator --- ...generator_control_flow.rs => generator.rs} | 40 ++++++++++++------- 1 file changed, 26 insertions(+), 14 deletions(-) rename tests/run-pass/{generator_control_flow.rs => generator.rs} (65%) diff --git a/tests/run-pass/generator_control_flow.rs b/tests/run-pass/generator.rs similarity index 65% rename from tests/run-pass/generator_control_flow.rs rename to tests/run-pass/generator.rs index 900ff0e34904c..603093a037c73 100644 --- a/tests/run-pass/generator_control_flow.rs +++ b/tests/run-pass/generator.rs @@ -13,11 +13,11 @@ use std::ops::{GeneratorState, Generator}; fn finish(mut amt: usize, mut t: T) -> T::Return - where T: Generator + where T: Generator { loop { match unsafe { t.resume() } { - GeneratorState::Yielded(()) => amt -= 1, + GeneratorState::Yielded(y) => amt -= y, GeneratorState::Complete(ret) => { assert_eq!(amt, 0); return ret @@ -28,38 +28,50 @@ fn finish(mut amt: usize, mut t: T) -> T::Return } fn main() { - finish(1, || yield); + finish(1, || yield 1); finish(3, || { let mut x = 0; - yield; + yield 1; x += 1; - yield; + yield 1; x += 1; - yield; + yield 1; assert_eq!(x, 2); }); - finish(8, || { - for _ in 0..8 { - yield; + finish(7*8/2, || { + for i in 0..8 { + yield i; } }); finish(1, || { if true { - yield; + yield 1; } else { } }); finish(1, || { if false { } else { - yield; + yield 1; } }); finish(2, || { - if { yield; false } { - yield; + if { yield 1; false } { + yield 1; panic!() } - yield + yield 1; }); + // also test a self-referential generator + assert_eq!( + finish(5, || { + let mut x = Box::new(5); + let y = &mut *x; + *y = 5; + yield *y; + *y = 10; + *x + }), + 10 + ); } From 7fe24a2b86bd355b20bc772e4613554ea5105ec0 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 20 Nov 2018 16:09:06 +0100 Subject: [PATCH 0397/3747] also add an async fn test --- tests/run-pass-fullmir/async-fn.rs | 35 ++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 tests/run-pass-fullmir/async-fn.rs diff --git a/tests/run-pass-fullmir/async-fn.rs b/tests/run-pass-fullmir/async-fn.rs new file mode 100644 index 0000000000000..7c32b026df67b --- /dev/null +++ b/tests/run-pass-fullmir/async-fn.rs @@ -0,0 +1,35 @@ +#![feature( + async_await, + await_macro, + futures_api, + pin, +)] + +use std::{future::Future, pin::Pin, task::Poll}; + +// See if we can run a basic `async fn` +pub async fn foo(x: &u32, y: u32) -> u32 { + let y = &y; + let z = 9; + let z = &z; + let y = await!(async { *y + *z }); + let a = 10; + let a = &a; + *x + y + *a +} + +fn main() { + use std::{sync::Arc, task::{Wake, local_waker}}; + + struct NoWake; + impl Wake for NoWake { + fn wake(_arc_self: &Arc) { + panic!(); + } + } + + let lw = unsafe { local_waker(Arc::new(NoWake)) }; + let x = 5; + let mut fut = foo(&x, 7); + assert_eq!(unsafe { Pin::new_unchecked(&mut fut) }.poll(&lw), Poll::Ready(31)); +} From 6181b29f5d9e81eb16826825da4a679e5da3f57a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 21 Nov 2018 09:52:31 +0100 Subject: [PATCH 0398/3747] bump Rust --- rust-version | 2 +- src/fn_call.rs | 7 +++---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/rust-version b/rust-version index dcd90feeda812..a3718d44da91d 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -nightly-2018-11-20 +nightly-2018-11-21 diff --git a/src/fn_call.rs b/src/fn_call.rs index 509db0355e2ba..5fc706c04d805 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -469,10 +469,9 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo instance, promoted: None, }; - let const_val = self.const_eval(cid)?; - let value = const_val.unwrap_bits( - self.tcx.tcx, - ty::ParamEnv::empty().and(self.tcx.types.i32)) as i32; + let const_val = self.const_eval_raw(cid)?; + let const_val = self.read_scalar(const_val.into())?; + let value = const_val.to_i32()?; if value == name { result = Some(path_value); break; From 0b7625a0794b9997cdd60dcc5957d8991212b86b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 21 Nov 2018 10:19:00 +0100 Subject: [PATCH 0399/3747] make sure compile-fail tests would compile if we screw up --- .../stacked_borrows/box_exclusive_violation1.rs | 2 +- .../stacked_borrows/mut_exclusive_violation1.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/compile-fail-fullmir/stacked_borrows/box_exclusive_violation1.rs b/tests/compile-fail-fullmir/stacked_borrows/box_exclusive_violation1.rs index 73631173b932a..bd0fec859d8f7 100644 --- a/tests/compile-fail-fullmir/stacked_borrows/box_exclusive_violation1.rs +++ b/tests/compile-fail-fullmir/stacked_borrows/box_exclusive_violation1.rs @@ -25,5 +25,5 @@ fn unknown_code_2() { unsafe { } } fn main() { - assert_eq!(demo_mut_advanced_unique(Box::new(0)), 5); + demo_mut_advanced_unique(Box::new(0)); } diff --git a/tests/compile-fail-fullmir/stacked_borrows/mut_exclusive_violation1.rs b/tests/compile-fail-fullmir/stacked_borrows/mut_exclusive_violation1.rs index 255e35b145588..fec699e35bcfb 100644 --- a/tests/compile-fail-fullmir/stacked_borrows/mut_exclusive_violation1.rs +++ b/tests/compile-fail-fullmir/stacked_borrows/mut_exclusive_violation1.rs @@ -25,5 +25,5 @@ fn unknown_code_2() { unsafe { } } fn main() { - assert_eq!(demo_mut_advanced_unique(&mut 0), 5); + demo_mut_advanced_unique(&mut 0); } From 984c3368a9d362eb1523d47c9efce20c793cd825 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 21 Nov 2018 13:40:25 +0100 Subject: [PATCH 0400/3747] remove stabilized feature flag --- src/bin/miri-rustc-tests.rs | 2 +- src/bin/miri.rs | 2 +- src/lib.rs | 2 +- tests/run-pass-fullmir/foreign-fn-linkname.rs | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/bin/miri-rustc-tests.rs b/src/bin/miri-rustc-tests.rs index c9ec1011ddbb9..6fa9b817ffee7 100644 --- a/src/bin/miri-rustc-tests.rs +++ b/src/bin/miri-rustc-tests.rs @@ -1,4 +1,4 @@ -#![feature(rustc_private, extern_crate_item_prelude)] +#![feature(rustc_private)] extern crate miri; extern crate getopts; extern crate rustc; diff --git a/src/bin/miri.rs b/src/bin/miri.rs index bfe631b51f0fd..1bbf3c8c4a4a8 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -1,4 +1,4 @@ -#![feature(rustc_private, extern_crate_item_prelude)] +#![feature(rustc_private)] extern crate getopts; extern crate miri; diff --git a/src/lib.rs b/src/lib.rs index 418f8f60cecd9..8eae6418fa7c8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,4 @@ -#![feature(rustc_private, extern_crate_item_prelude)] +#![feature(rustc_private)] #![cfg_attr(feature = "cargo-clippy", allow(cast_lossless))] diff --git a/tests/run-pass-fullmir/foreign-fn-linkname.rs b/tests/run-pass-fullmir/foreign-fn-linkname.rs index b61cfa84ef752..3dd30fd676fd1 100644 --- a/tests/run-pass-fullmir/foreign-fn-linkname.rs +++ b/tests/run-pass-fullmir/foreign-fn-linkname.rs @@ -10,7 +10,7 @@ //ignore-windows: Uses POSIX APIs -#![feature(libc, extern_crate_item_prelude)] +#![feature(libc)] #![allow(unused_extern_crates)] // rustc bug https://github.com/rust-lang/rust/issues/56098 extern crate libc; From ec8cc029c1904bcbbb6ede8fba0251c2aaaf70f8 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 21 Nov 2018 15:44:47 +0100 Subject: [PATCH 0401/3747] on a deref, check that we are not using a mutable ref with a frozen tag --- src/stacked_borrows.rs | 39 +++++-------------- .../static_memory_modification.rs | 3 -- 2 files changed, 9 insertions(+), 33 deletions(-) diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 063a544baa655..16cd3e916434e 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -151,6 +151,12 @@ impl<'tcx> Stack { /// Returns the index of the item we matched, `None` if it was the frozen one. /// `kind` indicates which kind of reference is being dereferenced. fn deref(&self, bor: Borrow, kind: RefKind) -> Result, String> { + // Exclude unique ref and frozen tag. + match (kind, bor) { + (RefKind::Unique, Borrow::Shr(Some(_))) => + return Err(format!("Encountered mutable reference with frozen tag")), + _ => {} + } // Checks related to freezing match bor { Borrow::Shr(Some(bor_t)) if kind == RefKind::Frozen => { @@ -490,36 +496,9 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for MiriEvalContext<'a, 'mir, 'tcx> { if let Some(mutability) = mutability { format!("{:?}", mutability) } else { format!("raw") }, place.ptr, place.layout.ty); let ptr = place.ptr.to_ptr()?; - // In principle we should not have to do anything here. However, with transmutes involved, - // it can happen that the tag of `ptr` does not actually match `mutability`, and we - // should adjust for that. - // Notably, the compiler can introduce such transmutes by optimizing away `&[mut]*`. - // That can transmute a raw ptr to a (shared/mut) ref, and a mut ref to a shared one. - match (mutability, ptr.tag) { - (None, _) => { - // No further validation on raw accesses. - return Ok(()); - } - (Some(MutMutable), Borrow::Uniq(_)) | - (Some(MutImmutable), Borrow::Shr(_)) => { - // Expected combinations. Nothing to do. - } - (Some(MutMutable), Borrow::Shr(None)) => { - // Raw transmuted to mut ref. This is something real unsafe code does. - // We cannot reborrow here because we do not want to mutate state on a deref. - } - (Some(MutImmutable), Borrow::Uniq(_)) => { - // A mut got transmuted to shr. Can happen even from compiler transformations: - // `&*x` gets optimized to `x` even when `x` is a `&mut`. - } - (Some(MutMutable), Borrow::Shr(Some(_))) => { - // This is just invalid: A shr got transmuted to a mut. - // If we ever allow this, we have to consider what we do when a turn a - // `Raw`-tagged `&mut` into a raw pointer pointing to a frozen location. - // We probably do not want to allow that, but we have to allow - // turning a `Raw`-tagged `&` into a raw ptr to a frozen location. - return err!(MachineError(format!("Encountered mutable reference with frozen tag {:?}", ptr.tag))) - } + if mutability.is_none() { + // No further checks on raw derefs -- only the access itself will be checked. + return Ok(()); } // Get the allocation diff --git a/tests/compile-fail-fullmir/stacked_borrows/static_memory_modification.rs b/tests/compile-fail-fullmir/stacked_borrows/static_memory_modification.rs index 5c605eff67843..c092cbfe50985 100644 --- a/tests/compile-fail-fullmir/stacked_borrows/static_memory_modification.rs +++ b/tests/compile-fail-fullmir/stacked_borrows/static_memory_modification.rs @@ -1,6 +1,3 @@ -// FIXME still considering whether we are okay with this not being an error -// ignore-test - static X: usize = 5; #[allow(mutable_transmutes)] From 41f89beb3f03cb7cdbfbd754ac2eee9e1f153f18 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 21 Nov 2018 16:01:39 +0100 Subject: [PATCH 0402/3747] if let --- src/stacked_borrows.rs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 16cd3e916434e..21addbfbf789f 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -151,11 +151,9 @@ impl<'tcx> Stack { /// Returns the index of the item we matched, `None` if it was the frozen one. /// `kind` indicates which kind of reference is being dereferenced. fn deref(&self, bor: Borrow, kind: RefKind) -> Result, String> { - // Exclude unique ref and frozen tag. - match (kind, bor) { - (RefKind::Unique, Borrow::Shr(Some(_))) => - return Err(format!("Encountered mutable reference with frozen tag")), - _ => {} + // Exclude unique ref with frozen tag. + if let (RefKind::Unique, Borrow::Shr(Some(_))) = (kind, bor) { + return Err(format!("Encountered mutable reference with frozen tag")); } // Checks related to freezing match bor { From 694d2490f1f10cc46aff0452874ade547e4936b9 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 21 Nov 2018 16:02:38 +0100 Subject: [PATCH 0403/3747] slightly more verbose error msg --- src/stacked_borrows.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 21addbfbf789f..f26ef40ea9f83 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -153,7 +153,7 @@ impl<'tcx> Stack { fn deref(&self, bor: Borrow, kind: RefKind) -> Result, String> { // Exclude unique ref with frozen tag. if let (RefKind::Unique, Borrow::Shr(Some(_))) = (kind, bor) { - return Err(format!("Encountered mutable reference with frozen tag")); + return Err(format!("Encountered mutable reference with frozen tag ({:?})", bor)); } // Checks related to freezing match bor { From 04794c4c2ac20e66043c235b45c19f6759f48dc9 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 21 Nov 2018 16:08:46 +0100 Subject: [PATCH 0404/3747] test that we support partial invalidation of mutable references --- tests/run-pass/stacked-borrows.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tests/run-pass/stacked-borrows.rs b/tests/run-pass/stacked-borrows.rs index 72f26763be140..93bdf5ffbf326 100644 --- a/tests/run-pass/stacked-borrows.rs +++ b/tests/run-pass/stacked-borrows.rs @@ -7,6 +7,7 @@ fn main() { mut_shr_raw(); mut_raw_then_mut_shr(); mut_raw_mut(); + partially_invalidate_mut(); } // Deref a raw ptr to access a field of a large struct, where the field @@ -97,3 +98,12 @@ fn mut_raw_mut() { } assert_eq!(x, 4); } + +fn partially_invalidate_mut() { + let data = &mut (0u8, 0u8); + let reborrow = &mut *data as *mut (u8, u8); + let shard = unsafe { &mut (*reborrow).0 }; + data.1 += 1; // the deref overlaps with `shard`, but that is okay; the access does not overlap. + *shard += 1; // so we can still use `shard`. + assert_eq!(*data, (1, 1)); +} From 1703d31eacccc80beedc8bc4b393df0027531e60 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 22 Nov 2018 08:21:26 +0100 Subject: [PATCH 0405/3747] bump rust --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index a3718d44da91d..23a0fa102b00a 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -nightly-2018-11-21 +nightly-2018-11-22 From 68ba6cdbaa758484f56d8c7f5628ccfcb772756e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 23 Nov 2018 09:46:51 +0100 Subject: [PATCH 0406/3747] fix for new Align type --- src/fn_call.rs | 16 ++++++++-------- src/helpers.rs | 5 +++-- src/intrinsic.rs | 8 ++++---- src/lib.rs | 12 ++++++------ src/operator.rs | 8 ++++---- 5 files changed, 25 insertions(+), 24 deletions(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index 5fc706c04d805..e64d4f6954878 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -124,7 +124,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo if size == 0 { self.write_null(dest)?; } else { - let align = self.tcx.data_layout.pointer_align; + let align = self.tcx.data_layout.pointer_align.abi; let ptr = self.memory_mut().allocate(Size::from_bytes(size), align, MiriMemoryKind::C.into())?; self.write_scalar(Scalar::Ptr(ptr.with_default_tag()), dest)?; } @@ -153,7 +153,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo let ptr = self.memory_mut() .allocate( Size::from_bytes(size), - Align::from_bytes(align, align).unwrap(), + Align::from_bytes(align).unwrap(), MiriMemoryKind::Rust.into() )? .with_default_tag(); @@ -171,7 +171,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo let ptr = self.memory_mut() .allocate( Size::from_bytes(size), - Align::from_bytes(align, align).unwrap(), + Align::from_bytes(align).unwrap(), MiriMemoryKind::Rust.into() )? .with_default_tag(); @@ -190,7 +190,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo } self.memory_mut().deallocate( ptr, - Some((Size::from_bytes(old_size), Align::from_bytes(align, align).unwrap())), + Some((Size::from_bytes(old_size), Align::from_bytes(align).unwrap())), MiriMemoryKind::Rust.into(), )?; } @@ -208,9 +208,9 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo let new_ptr = self.memory_mut().reallocate( ptr, Size::from_bytes(old_size), - Align::from_bytes(align, align).unwrap(), + Align::from_bytes(align).unwrap(), Size::from_bytes(new_size), - Align::from_bytes(align, align).unwrap(), + Align::from_bytes(align).unwrap(), MiriMemoryKind::Rust.into(), )?; self.write_scalar(Scalar::Ptr(new_ptr.with_default_tag()), dest)?; @@ -394,7 +394,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo // +1 for the null terminator let value_copy = self.memory_mut().allocate( Size::from_bytes((value.len() + 1) as u64), - Align::from_bytes(1, 1).unwrap(), + Align::from_bytes(1).unwrap(), MiriMemoryKind::Env.into(), )?.with_default_tag(); self.memory_mut().write_bytes(value_copy.into(), &value)?; @@ -513,7 +513,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo } self.memory_mut().write_scalar( key_ptr, - key_layout.align, + key_layout.align.abi, Scalar::from_uint(key, key_layout.size).into(), key_layout.size, )?; diff --git a/src/helpers.rs b/src/helpers.rs index 85329ddcf17f5..2b1a28fe9e0d0 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -130,9 +130,10 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: unsafe_cell_action: |place| { trace!("unsafe_cell_action on {:?}", place.ptr); // We need a size to go on. - let (unsafe_cell_size, _) = self.size_and_align_of_mplace(place)? + let unsafe_cell_size = self.size_and_align_of_mplace(place)? + .map(|(size, _)| size) // for extern types, just cover what we can - .unwrap_or_else(|| place.layout.size_and_align()); + .unwrap_or_else(|| place.layout.size); // Now handle this `UnsafeCell`, unless it is empty. if unsafe_cell_size != Size::ZERO { unsafe_cell_action(place.ptr, unsafe_cell_size) diff --git a/src/intrinsic.rs b/src/intrinsic.rs index 6d5ac8d88bae2..66dab00e0975c 100644 --- a/src/intrinsic.rs +++ b/src/intrinsic.rs @@ -152,7 +152,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' let elem_layout = self.layout_of(elem_ty)?; let elem_size = elem_layout.size.bytes(); let count = self.read_scalar(args[2])?.to_usize(self)?; - let elem_align = elem_layout.align; + let elem_align = elem_layout.align.abi; // erase tags: this is a raw ptr operation let src = self.read_scalar(args[0])?.not_undef()?; let dest = self.read_scalar(args[1])?.not_undef()?; @@ -272,7 +272,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' "pref_align_of" => { let ty = substs.type_at(0); let layout = self.layout_of(ty)?; - let align = layout.align.pref(); + let align = layout.align.pref.bytes(); let ptr_size = self.pointer_size(); let align_val = Scalar::from_uint(align as u128, ptr_size); self.write_scalar(align_val, dest)?; @@ -364,7 +364,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' .expect("size_of_val called on extern type"); let ptr_size = self.pointer_size(); self.write_scalar( - Scalar::from_uint(align.abi(), ptr_size), + Scalar::from_uint(align.bytes(), ptr_size), dest, )?; } @@ -438,7 +438,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' let val_byte = self.read_scalar(args[1])?.to_u8()?; let ptr = self.read_scalar(args[0])?.not_undef()?; let count = self.read_scalar(args[2])?.to_usize(self)?; - self.memory().check_align(ptr, ty_layout.align)?; + self.memory().check_align(ptr, ty_layout.align.abi)?; self.memory_mut().write_repeat(ptr, val_byte, ty_layout.size * count)?; } diff --git a/src/lib.rs b/src/lib.rs index 8eae6418fa7c8..10a1405b2a628 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -397,7 +397,7 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { // Second argument: align let arg = ecx.eval_place(&mir::Place::Local(args.next().unwrap()))?; - let align = layout.align.abi(); + let align = layout.align.abi.bytes(); ecx.write_scalar(Scalar::from_uint(align, arg.layout.size), arg)?; // No more arguments @@ -419,7 +419,7 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { "__cxa_thread_atexit_impl" => { // This should be all-zero, pointer-sized let data = vec![0; tcx.data_layout.pointer_size.bytes() as usize]; - Allocation::from_bytes(&data[..], tcx.data_layout.pointer_align) + Allocation::from_bytes(&data[..], tcx.data_layout.pointer_align.abi) } _ => return err!(Unimplemented( format!("can't access foreign static: {}", link_name), @@ -458,9 +458,9 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { place: MPlaceTy<'tcx, Borrow>, mutability: Option, ) -> EvalResult<'tcx, Scalar> { - let (size, _) = ecx.size_and_align_of_mplace(place)? + let size = ecx.size_and_align_of_mplace(place)?.map(|(size, _)| size) // for extern types, just cover what we can - .unwrap_or_else(|| place.layout.size_and_align()); + .unwrap_or_else(|| place.layout.size); if !ecx.tcx.sess.opts.debugging_opts.mir_emit_retag || !Self::enforce_validity(ecx) || size == Size::ZERO { @@ -498,9 +498,9 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { // This is deliberately NOT `deref_operand` as we do not want `tag_dereference` // to be called! That would kill the original tag if we got a raw ptr. let place = ecx.ref_to_mplace(ecx.read_immediate(ptr)?)?; - let (size, _) = ecx.size_and_align_of_mplace(place)? + let size = ecx.size_and_align_of_mplace(place)?.map(|(size, _)| size) // for extern types, just cover what we can - .unwrap_or_else(|| place.layout.size_and_align()); + .unwrap_or_else(|| place.layout.size); if !ecx.tcx.sess.opts.debugging_opts.mir_emit_retag || !ecx.machine.validate || size == Size::ZERO { diff --git a/src/operator.rs b/src/operator.rs index be05c2259957e..2f3a0de999adf 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -166,12 +166,12 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' let (alloc_size, alloc_align) = self.memory().get_size_and_align(ptr.alloc_id); // Case II: Alignment gives it away - if ptr.offset.bytes() % alloc_align.abi() == 0 { + if ptr.offset.bytes() % alloc_align.bytes() == 0 { // The offset maintains the allocation alignment, so we know `base+offset` // is aligned by `alloc_align`. // FIXME: We could be even more general, e.g. offset 2 into a 4-aligned // allocation cannot equal 3. - if bits % alloc_align.abi() != 0 { + if bits % alloc_align.bytes() != 0 { // The integer is *not* aligned. So they cannot be equal. return Ok(false); } @@ -226,7 +226,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' map_to_primval(left.overflowing_offset(Size::from_bytes(right as u64), self)), BitAnd if !signed => { - let ptr_base_align = self.memory().get(left.alloc_id)?.align.abi(); + let ptr_base_align = self.memory().get(left.alloc_id)?.align.bytes(); let base_mask = { // FIXME: Use interpret::truncate, once that takes a Size instead of a Layout let shift = 128 - self.memory().pointer_size().bits(); @@ -259,7 +259,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' Rem if !signed => { // Doing modulo a divisor of the alignment is allowed. // (Intuition: Modulo a divisor leaks less information.) - let ptr_base_align = self.memory().get(left.alloc_id)?.align.abi(); + let ptr_base_align = self.memory().get(left.alloc_id)?.align.bytes(); let right = right as u64; let ptr_size = self.memory().pointer_size().bytes() as u8; if right == 1 { From 32e93ed7762e5aa1a721636096848fc3c7bc7218 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Tue, 13 Nov 2018 17:19:42 +0100 Subject: [PATCH 0407/3747] Update to Memory -> Allocation method move --- src/fn_call.rs | 40 +++++++++++++++++++++++++--------------- src/intrinsic.rs | 21 +++++++++++++++++---- src/operator.rs | 18 +++++++++++------- src/stacked_borrows.rs | 10 +++++----- 4 files changed, 58 insertions(+), 31 deletions(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index e64d4f6954878..e9d3255a5b325 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -114,6 +114,8 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo None => self.tcx.item_name(def_id).as_str(), }; + let tcx = &{self.tcx.tcx}; + // All these functions take raw pointers, so if we access memory directly // (as opposed to through a place), we have to remember to erase any tag // that might still hang around! @@ -175,7 +177,9 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo MiriMemoryKind::Rust.into() )? .with_default_tag(); - self.memory_mut().write_repeat(ptr.into(), 0, Size::from_bytes(size))?; + self.memory_mut() + .get_mut(ptr.alloc_id)? + .write_repeat(tcx, ptr, 0, Size::from_bytes(size))?; self.write_scalar(Scalar::Ptr(ptr), dest)?; } "__rust_dealloc" => { @@ -239,7 +243,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo "dlsym" => { let _handle = self.read_scalar(args[0])?; let symbol = self.read_scalar(args[1])?.to_ptr()?; - let symbol_name = self.memory().read_c_str(symbol)?; + let symbol_name = self.memory().get(symbol.alloc_id)?.read_c_str(tcx, symbol)?; let err = format!("bad c unicode symbol: {:?}", symbol_name); let symbol_name = ::std::str::from_utf8(symbol_name).unwrap_or(&err); return err!(Unimplemented(format!( @@ -346,7 +350,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo "getenv" => { let result = { let name_ptr = self.read_scalar(args[0])?.to_ptr()?; - let name = self.memory().read_c_str(name_ptr)?; + let name = self.memory().get(name_ptr.alloc_id)?.read_c_str(tcx, name_ptr)?; match self.machine.env_vars.get(name) { Some(&var) => Scalar::Ptr(var), None => Scalar::ptr_null(&*self.tcx), @@ -360,8 +364,8 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo { let name_ptr = self.read_scalar(args[0])?.not_undef()?; if !name_ptr.is_null_ptr(self) { - let name = self.memory().read_c_str(name_ptr.to_ptr()? - )?.to_owned(); + let name_ptr = name_ptr.to_ptr()?; + let name = self.memory().get(name_ptr.alloc_id)?.read_c_str(tcx, name_ptr)?.to_owned(); if !name.is_empty() && !name.contains(&b'=') { success = Some(self.machine.env_vars.remove(&name)); } @@ -382,9 +386,10 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo { let name_ptr = self.read_scalar(args[0])?.not_undef()?; let value_ptr = self.read_scalar(args[1])?.to_ptr()?; - let value = self.memory().read_c_str(value_ptr)?; + let value = self.memory().get(value_ptr.alloc_id)?.read_c_str(tcx, value_ptr)?; if !name_ptr.is_null_ptr(self) { - let name = self.memory().read_c_str(name_ptr.to_ptr()?)?; + let name_ptr = name_ptr.to_ptr()?; + let name = self.memory().get(name_ptr.alloc_id)?.read_c_str(tcx, name_ptr)?; if !name.is_empty() && !name.contains(&b'=') { new = Some((name.to_owned(), value.to_owned())); } @@ -397,9 +402,12 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo Align::from_bytes(1).unwrap(), MiriMemoryKind::Env.into(), )?.with_default_tag(); - self.memory_mut().write_bytes(value_copy.into(), &value)?; - let trailing_zero_ptr = value_copy.offset(Size::from_bytes(value.len() as u64), self)?.into(); - self.memory_mut().write_bytes(trailing_zero_ptr, &[0])?; + { + let alloc = self.memory_mut().get_mut(value_copy.alloc_id)?; + alloc.write_bytes(tcx, value_copy, &value)?; + let trailing_zero_ptr = value_copy.offset(Size::from_bytes(value.len() as u64), tcx)?; + alloc.write_bytes(tcx, trailing_zero_ptr, &[0])?; + } if let Some(var) = self.machine.env_vars.insert( name.to_owned(), value_copy, @@ -444,7 +452,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo "strlen" => { let ptr = self.read_scalar(args[0])?.to_ptr()?; - let n = self.memory().read_c_str(ptr)?.len(); + let n = self.memory().get(ptr.alloc_id)?.read_c_str(tcx, ptr)?.len(); self.write_scalar(Scalar::from_uint(n as u64, dest.layout.size), dest)?; } @@ -507,13 +515,15 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo let key_layout = self.layout_of(key_type)?; // Create key and write it into the memory where key_ptr wants it - let key = self.machine.tls.create_tls_key(dtor, &*self.tcx) as u128; + let key = self.machine.tls.create_tls_key(dtor, tcx) as u128; if key_layout.size.bits() < 128 && key >= (1u128 << key_layout.size.bits() as u128) { return err!(OutOfTls); } - self.memory_mut().write_scalar( + + self.memory().check_align(key_ptr.into(), key_layout.align.abi)?; + self.memory_mut().get_mut(key_ptr.alloc_id)?.write_scalar( + tcx, key_ptr, - key_layout.align.abi, Scalar::from_uint(key, key_layout.size).into(), key_layout.size, )?; @@ -610,7 +620,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo // This just creates a key; Windows does not natively support TLS dtors. // Create key and return it - let key = self.machine.tls.create_tls_key(None, &*self.tcx) as u128; + let key = self.machine.tls.create_tls_key(None, tcx) 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) { diff --git a/src/intrinsic.rs b/src/intrinsic.rs index 66dab00e0975c..c9b16525e5662 100644 --- a/src/intrinsic.rs +++ b/src/intrinsic.rs @@ -28,7 +28,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' if self.emulate_intrinsic(instance, args, dest)? { return Ok(()); } - + let tcx = &{self.tcx.tcx}; let substs = instance.substs; // All these intrinsics take raw pointers, so if we access memory directly @@ -248,6 +248,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' // FIXME: We do not properly validate in case of ZSTs and when doing it in memory! // However, this only affects direct calls of the intrinsic; calls to the stable // functions wrapping them do get their validation. + // FIXME: should we check that the destination pointer is aligned even for ZSTs? if !dest.layout.is_zst() { // nothing to do for ZST match dest.layout.abi { layout::Abi::Scalar(ref s) => { @@ -263,7 +264,9 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' // Do it in memory let mplace = self.force_allocation(dest)?; assert!(mplace.meta.is_none()); - self.memory_mut().write_repeat(mplace.ptr, 0, dest.layout.size)?; + // not a zst, must be valid pointer + let ptr = mplace.ptr.to_ptr()?; + self.memory_mut().get_mut(ptr.alloc_id)?.write_repeat(tcx, ptr, 0, dest.layout.size)?; } } } @@ -412,6 +415,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' // FIXME: We do not properly validate in case of ZSTs and when doing it in memory! // However, this only affects direct calls of the intrinsic; calls to the stable // functions wrapping them do get their validation. + // FIXME: should we check alignment for ZSTs? if !dest.layout.is_zst() { // nothing to do for ZST match dest.layout.abi { layout::Abi::Scalar(..) => { @@ -426,7 +430,10 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' // Do it in memory let mplace = self.force_allocation(dest)?; assert!(mplace.meta.is_none()); - self.memory_mut().mark_definedness(mplace.ptr.to_ptr()?, dest.layout.size, false)?; + let ptr = mplace.ptr.to_ptr()?; + self.memory_mut() + .get_mut(ptr.alloc_id)? + .mark_definedness(ptr, dest.layout.size, false)?; } } } @@ -439,7 +446,13 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' let ptr = self.read_scalar(args[0])?.not_undef()?; let count = self.read_scalar(args[2])?.to_usize(self)?; self.memory().check_align(ptr, ty_layout.align.abi)?; - self.memory_mut().write_repeat(ptr, val_byte, ty_layout.size * count)?; + let byte_count = ty_layout.size * count; + if byte_count.bytes() != 0 { + let ptr = ptr.to_ptr()?; + self.memory_mut() + .get_mut(ptr.alloc_id)? + .write_repeat(tcx, ptr, val_byte, byte_count)?; + } } name => return err!(Unimplemented(format!("unimplemented intrinsic: {}", name))), diff --git a/src/operator.rs b/src/operator.rs index 2f3a0de999adf..e1ccdf91995ef 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -142,10 +142,12 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' // allocations sit right next to each other. The C/C++ standards are // somewhat fuzzy about this case, so I think for now this check is // "good enough". - // We require liveness, as dead allocations can of course overlap. - self.memory().check_bounds_ptr(left, InboundsCheck::Live)?; - self.memory().check_bounds_ptr(right, InboundsCheck::Live)?; - // Two live in-bounds pointers, we can compare across allocations + // Dead allocations in miri cannot overlap with live allocations, but + // on read hardware this can easily happen. Thus for comparisons we require + // both pointers to be live. + self.memory().get(left.alloc_id)?.check_bounds_ptr(left)?; + self.memory().get(right.alloc_id)?.check_bounds_ptr(right)?; + // Two in-bounds pointers, we can compare across allocations left == right } } @@ -158,7 +160,8 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' // Case I: Comparing with NULL if bits == 0 { // Test if the ptr is in-bounds. Then it cannot be NULL. - if self.memory().check_bounds_ptr(ptr, InboundsCheck::MaybeDead).is_ok() { + // Even dangling pointers cannot be NULL. + if self.memory().check_bounds_ptr_maybe_dead(ptr).is_ok() { return Ok(false); } } @@ -298,9 +301,10 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' if let Scalar::Ptr(ptr) = ptr { // Both old and new pointer must be in-bounds of a *live* allocation. // (Of the same allocation, but that part is trivial with our representation.) - self.memory().check_bounds_ptr(ptr, InboundsCheck::Live)?; + let alloc = self.memory().get(ptr.alloc_id)?; + alloc.check_bounds_ptr(ptr)?; let ptr = ptr.signed_offset(offset, self)?; - self.memory().check_bounds_ptr(ptr, InboundsCheck::Live)?; + alloc.check_bounds_ptr(ptr)?; Ok(Scalar::Ptr(ptr)) } else { // An integer pointer. They can only be offset by 0, and we pretend there diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index f26ef40ea9f83..f292d083637ac 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -5,7 +5,7 @@ use rustc::hir::{Mutability, MutMutable, MutImmutable}; use crate::{ EvalResult, EvalErrorKind, MiriEvalContext, HelpersEvalContextExt, Evaluator, MutValueVisitor, - MemoryKind, MiriMemoryKind, RangeMap, AllocId, Allocation, AllocationExtra, InboundsCheck, + MemoryKind, MiriMemoryKind, RangeMap, AllocId, Allocation, AllocationExtra, Pointer, MemPlace, Scalar, Immediate, ImmTy, PlaceTy, MPlaceTy, }; @@ -500,8 +500,8 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for MiriEvalContext<'a, 'mir, 'tcx> { } // Get the allocation - self.memory().check_bounds(ptr, size, InboundsCheck::Live)?; - let alloc = self.memory().get(ptr.alloc_id).expect("We checked that the ptr is fine!"); + let alloc = self.memory().get(ptr.alloc_id)?; + alloc.check_bounds(self, ptr, size)?; // If we got here, we do some checking, *but* we leave the tag unchanged. if let Borrow::Shr(Some(_)) = ptr.tag { assert_eq!(mutability, Some(MutImmutable)); @@ -543,8 +543,8 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for MiriEvalContext<'a, 'mir, 'tcx> { ptr, place.layout.ty, new_bor); // Get the allocation. It might not be mutable, so we cannot use `get_mut`. - self.memory().check_bounds(ptr, size, InboundsCheck::Live)?; - let alloc = self.memory().get(ptr.alloc_id).expect("We checked that the ptr is fine!"); + let alloc = self.memory().get(ptr.alloc_id)?; + alloc.check_bounds(self, ptr, size)?; // Update the stacks. if let Borrow::Shr(Some(_)) = new_bor { // Reference that cares about freezing. We need a frozen-sensitive reborrow. From 82d4146a6c3fec5d0f87e3df6423f123dec784f6 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 24 Nov 2018 11:58:28 +0100 Subject: [PATCH 0408/3747] bump Rust --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 23a0fa102b00a..5bdac314d1693 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -nightly-2018-11-22 +nightly-2018-11-24 From ac9649b7c0fc0f106d4dc93ab3c4d9ff25228f32 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 26 Nov 2018 08:54:24 +0100 Subject: [PATCH 0409/3747] bump Rust version --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 5bdac314d1693..0268b07ac411a 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -nightly-2018-11-24 +nightly-2018-11-26 From 7d623f73cc5c592c703f68d8079f78055841e113 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 26 Nov 2018 15:31:53 +0100 Subject: [PATCH 0410/3747] do not use 'let _', it is strange --- tests/compile-fail-fullmir/ptr_offset_overflow.rs | 2 +- tests/compile-fail/invalid_enum_discriminant.rs | 2 +- tests/compile-fail/pointer_byte_read_1.rs | 2 +- tests/compile-fail/pointer_byte_read_2.rs | 2 +- tests/compile-fail/ptr_bitops2.rs | 2 +- tests/compile-fail/ptr_int_cast.rs | 2 +- tests/compile-fail/ptr_offset_int_plus_int.rs | 2 +- tests/compile-fail/ptr_offset_int_plus_ptr.rs | 2 +- tests/compile-fail/ptr_rem.rs | 2 +- tests/compile-fail/ptr_wrapping_offset_int_plus_ptr.rs | 2 +- tests/compile-fail/transmute_fat1.rs | 2 +- tests/compile-fail/validity/invalid_char.rs | 2 +- tests/compile-fail/zst.rs | 2 +- tests/run-pass-fullmir/catch.rs | 2 +- tests/run-pass-fullmir/from_utf8.rs | 2 +- tests/run-pass-fullmir/threads.rs | 6 +++--- tests/run-pass/closure-drop.rs | 2 +- tests/run-pass/drop_empty_slice.rs | 2 +- tests/run-pass/issue-20575.rs | 2 +- tests/run-pass/issue-26709.rs | 2 +- tests/run-pass/issue-33387.rs | 2 +- tests/run-pass/issue-miri-184.rs | 2 +- tests/run-pass/sendable-class.rs | 4 ++-- tests/run-pass/slices.rs | 4 ++-- 24 files changed, 28 insertions(+), 28 deletions(-) diff --git a/tests/compile-fail-fullmir/ptr_offset_overflow.rs b/tests/compile-fail-fullmir/ptr_offset_overflow.rs index 32ab2daebf0d0..babd0246e7e1a 100644 --- a/tests/compile-fail-fullmir/ptr_offset_overflow.rs +++ b/tests/compile-fail-fullmir/ptr_offset_overflow.rs @@ -2,5 +2,5 @@ fn main() { let v = [1i8, 2]; let x = &v[1] as *const i8; - let _ = unsafe { x.offset(isize::min_value()) }; + let _val = unsafe { x.offset(isize::min_value()) }; } diff --git a/tests/compile-fail/invalid_enum_discriminant.rs b/tests/compile-fail/invalid_enum_discriminant.rs index bd5cb55b6c92b..c1b8727c129b9 100644 --- a/tests/compile-fail/invalid_enum_discriminant.rs +++ b/tests/compile-fail/invalid_enum_discriminant.rs @@ -12,5 +12,5 @@ pub enum Foo { fn main() { let f = unsafe { std::mem::transmute::(42) }; - let _ = mem::discriminant(&f); + let _val = mem::discriminant(&f); } diff --git a/tests/compile-fail/pointer_byte_read_1.rs b/tests/compile-fail/pointer_byte_read_1.rs index b25f09d485fb3..a584863654cef 100644 --- a/tests/compile-fail/pointer_byte_read_1.rs +++ b/tests/compile-fail/pointer_byte_read_1.rs @@ -3,5 +3,5 @@ fn main() { let y = &x; let z = &y as *const &i32 as *const usize; let ptr_bytes = unsafe { *z }; // the actual deref is fine, because we read the entire pointer at once - let _ = ptr_bytes / 432; //~ ERROR invalid arithmetic on pointers that would leak base addresses + let _val = ptr_bytes / 432; //~ ERROR invalid arithmetic on pointers that would leak base addresses } diff --git a/tests/compile-fail/pointer_byte_read_2.rs b/tests/compile-fail/pointer_byte_read_2.rs index 5df8c4782c7f8..ddb9bc1f995f2 100644 --- a/tests/compile-fail/pointer_byte_read_2.rs +++ b/tests/compile-fail/pointer_byte_read_2.rs @@ -3,5 +3,5 @@ fn main() { let y = &x; let z = &y as *const &i32 as *const u8; // the deref fails, because we are reading only a part of the pointer - let _ = unsafe { *z }; //~ ERROR tried to access part of a pointer value as raw bytes + let _val = unsafe { *z }; //~ ERROR tried to access part of a pointer value as raw bytes } diff --git a/tests/compile-fail/ptr_bitops2.rs b/tests/compile-fail/ptr_bitops2.rs index 233c9a733c999..5d5eab155083b 100644 --- a/tests/compile-fail/ptr_bitops2.rs +++ b/tests/compile-fail/ptr_bitops2.rs @@ -1,5 +1,5 @@ fn main() { let val = 13usize; let addr = &val as *const _ as usize; - let _ = addr & 13; //~ ERROR access part of a pointer value as raw bytes + let _val = addr & 13; //~ ERROR access part of a pointer value as raw bytes } diff --git a/tests/compile-fail/ptr_int_cast.rs b/tests/compile-fail/ptr_int_cast.rs index 576f0c333d189..a823a0f49b630 100644 --- a/tests/compile-fail/ptr_int_cast.rs +++ b/tests/compile-fail/ptr_int_cast.rs @@ -4,5 +4,5 @@ fn main() { let x = x as *const i32; let x = x as u8; //~ ERROR a raw memory access tried to access part of a pointer value as raw bytes let x = x as *const i32; - let _ = unsafe { *x }; + let _val = unsafe { *x }; } diff --git a/tests/compile-fail/ptr_offset_int_plus_int.rs b/tests/compile-fail/ptr_offset_int_plus_int.rs index fa4efa323654a..d027396108144 100644 --- a/tests/compile-fail/ptr_offset_int_plus_int.rs +++ b/tests/compile-fail/ptr_offset_int_plus_int.rs @@ -3,6 +3,6 @@ fn main() { // Can't offset an integer pointer by non-zero offset. unsafe { - let _ = (1 as *mut u8).offset(1); + let _val = (1 as *mut u8).offset(1); } } diff --git a/tests/compile-fail/ptr_offset_int_plus_ptr.rs b/tests/compile-fail/ptr_offset_int_plus_ptr.rs index b45548935807c..b49c758c72f78 100644 --- a/tests/compile-fail/ptr_offset_int_plus_ptr.rs +++ b/tests/compile-fail/ptr_offset_int_plus_ptr.rs @@ -4,6 +4,6 @@ fn main() { let ptr = Box::into_raw(Box::new(0u32)); // Can't start with an integer pointer and get to something usable unsafe { - let _ = (1 as *mut u8).offset(ptr as isize); + let _val = (1 as *mut u8).offset(ptr as isize); } } diff --git a/tests/compile-fail/ptr_rem.rs b/tests/compile-fail/ptr_rem.rs index 8a3665872f7cb..dfc91e9dc1b12 100644 --- a/tests/compile-fail/ptr_rem.rs +++ b/tests/compile-fail/ptr_rem.rs @@ -1,5 +1,5 @@ fn main() { let val = 13usize; let addr = &val as *const _ as usize; - let _ = addr % 16; //~ ERROR access part of a pointer value as raw bytes + let _val = addr % 16; //~ ERROR access part of a pointer value as raw bytes } diff --git a/tests/compile-fail/ptr_wrapping_offset_int_plus_ptr.rs b/tests/compile-fail/ptr_wrapping_offset_int_plus_ptr.rs index b3dda27fad1e7..eacb9f07fffd7 100644 --- a/tests/compile-fail/ptr_wrapping_offset_int_plus_ptr.rs +++ b/tests/compile-fail/ptr_wrapping_offset_int_plus_ptr.rs @@ -4,5 +4,5 @@ fn main() { let ptr = Box::into_raw(Box::new(0u32)); // Can't start with an integer pointer and get to something usable let ptr = (1 as *mut u8).wrapping_offset(ptr as isize); - let _ = unsafe { *ptr }; + let _val = unsafe { *ptr }; } diff --git a/tests/compile-fail/transmute_fat1.rs b/tests/compile-fail/transmute_fat1.rs index ede0486be4130..ddc78c8bf1d4a 100644 --- a/tests/compile-fail/transmute_fat1.rs +++ b/tests/compile-fail/transmute_fat1.rs @@ -10,5 +10,5 @@ fn main() { let bad = unsafe { std::mem::transmute::<&[u8], [u8; 8]>(&[1u8]) }; - let _ = bad[0] + bad[bad.len()-1]; //~ ERROR a raw memory access tried to access part of a pointer value as raw bytes + let _val = bad[0] + bad[bad.len()-1]; //~ ERROR a raw memory access tried to access part of a pointer value as raw bytes } diff --git a/tests/compile-fail/validity/invalid_char.rs b/tests/compile-fail/validity/invalid_char.rs index 0d75ad9d28905..a3f9070363491 100644 --- a/tests/compile-fail/validity/invalid_char.rs +++ b/tests/compile-fail/validity/invalid_char.rs @@ -1,6 +1,6 @@ fn main() { assert!(std::char::from_u32(-1_i32 as u32).is_none()); - let _ = match unsafe { std::mem::transmute::(-1) } { //~ ERROR encountered 4294967295, but expected something less or equal to 1114111 + let _val = match unsafe { std::mem::transmute::(-1) } { //~ ERROR encountered 4294967295, but expected something less or equal to 1114111 'a' => {true}, 'b' => {false}, _ => {true}, diff --git a/tests/compile-fail/zst.rs b/tests/compile-fail/zst.rs index 544d65a1bffa6..0488926870a21 100644 --- a/tests/compile-fail/zst.rs +++ b/tests/compile-fail/zst.rs @@ -1,4 +1,4 @@ fn main() { let x = &() as *const () as *const i32; - let _ = unsafe { *x }; //~ ERROR access memory with alignment 1, but alignment 4 is required + let _val = unsafe { *x }; //~ ERROR access memory with alignment 1, but alignment 4 is required } diff --git a/tests/run-pass-fullmir/catch.rs b/tests/run-pass-fullmir/catch.rs index 960297daa7ef5..aa7bccaa5ff3a 100644 --- a/tests/run-pass-fullmir/catch.rs +++ b/tests/run-pass-fullmir/catch.rs @@ -3,6 +3,6 @@ use std::panic::{catch_unwind, AssertUnwindSafe}; fn main() { let mut i = 3; - let _ = catch_unwind(AssertUnwindSafe(|| {i -= 2;} )); + let _val = catch_unwind(AssertUnwindSafe(|| {i -= 2;} )); println!("{}", i); } diff --git a/tests/run-pass-fullmir/from_utf8.rs b/tests/run-pass-fullmir/from_utf8.rs index 69e6c521af6ef..ce59e60a932d5 100644 --- a/tests/run-pass-fullmir/from_utf8.rs +++ b/tests/run-pass-fullmir/from_utf8.rs @@ -1,3 +1,3 @@ fn main() { - let _ = ::std::str::from_utf8(b"a"); + let _val = ::std::str::from_utf8(b"a"); } diff --git a/tests/run-pass-fullmir/threads.rs b/tests/run-pass-fullmir/threads.rs index f920bc52edde3..dad47d85a2466 100644 --- a/tests/run-pass-fullmir/threads.rs +++ b/tests/run-pass-fullmir/threads.rs @@ -5,15 +5,15 @@ use std::sync; fn main() { let m = sync::Mutex::new(0); - let _ = m.lock(); + drop(m.lock()); drop(m); // We don't provide RwLock on Windows #[cfg(not(target_os = "windows"))] { let rw = sync::RwLock::new(0); - let _ = rw.read(); - let _ = rw.write(); + drop(rw.read()); + drop(rw.write()); drop(rw); } } diff --git a/tests/run-pass/closure-drop.rs b/tests/run-pass/closure-drop.rs index f1bdafaeb1354..374efb6032bf5 100644 --- a/tests/run-pass/closure-drop.rs +++ b/tests/run-pass/closure-drop.rs @@ -17,7 +17,7 @@ fn main() { // this closure never by val uses its captures // so it's basically a fn(&self) // the shim used to not drop the `x` - let x = move || { let _ = x; }; + let x = move || { let _val = x; }; f(x); } assert!(ran_drop); diff --git a/tests/run-pass/drop_empty_slice.rs b/tests/run-pass/drop_empty_slice.rs index b21c8a612c57b..8b481a0a2dd89 100644 --- a/tests/run-pass/drop_empty_slice.rs +++ b/tests/run-pass/drop_empty_slice.rs @@ -3,5 +3,5 @@ fn main() { // With the nested Vec, this is calling Offset(Unique::empty(), 0) on drop. let args : Vec> = Vec::new(); - let _ = box args; + let _val = box args; } diff --git a/tests/run-pass/issue-20575.rs b/tests/run-pass/issue-20575.rs index 137d84c256bef..01371f5bec683 100644 --- a/tests/run-pass/issue-20575.rs +++ b/tests/run-pass/issue-20575.rs @@ -13,5 +13,5 @@ fn main() { let functions: [Box Option<()>>; 1] = [Box::new(|| None)]; - let _: Option> = functions.iter().map(|f| (*f)()).collect(); + let _val: Option> = functions.iter().map(|f| (*f)()).collect(); } diff --git a/tests/run-pass/issue-26709.rs b/tests/run-pass/issue-26709.rs index 62626d75865cf..e29e5fbcc4081 100644 --- a/tests/run-pass/issue-26709.rs +++ b/tests/run-pass/issue-26709.rs @@ -20,7 +20,7 @@ fn main() { let mut x = 0; { let wrapper = Box::new(Wrapper(&mut x, 123)); - let _: Box> = wrapper; + let _val: Box> = wrapper; } assert_eq!(432, x) } diff --git a/tests/run-pass/issue-33387.rs b/tests/run-pass/issue-33387.rs index edbf2b81ce941..62a4263c1069b 100644 --- a/tests/run-pass/issue-33387.rs +++ b/tests/run-pass/issue-33387.rs @@ -15,5 +15,5 @@ trait Foo {} impl Foo for [u8; 2] {} fn main() { - let _: Arc = Arc::new([3, 4]); + let _val: Arc = Arc::new([3, 4]); } diff --git a/tests/run-pass/issue-miri-184.rs b/tests/run-pass/issue-miri-184.rs index 24775fe8a2d9d..39c841403ef0c 100644 --- a/tests/run-pass/issue-miri-184.rs +++ b/tests/run-pass/issue-miri-184.rs @@ -1,4 +1,4 @@ pub fn main() { let bytes: [u8; 8] = unsafe { ::std::mem::transmute(0u64) }; - let _: &[u8] = &bytes; + let _val: &[u8] = &bytes; } diff --git a/tests/run-pass/sendable-class.rs b/tests/run-pass/sendable-class.rs index 66f0c84e23c1a..3280c36e0a729 100644 --- a/tests/run-pass/sendable-class.rs +++ b/tests/run-pass/sendable-class.rs @@ -27,6 +27,6 @@ fn foo(i:isize, j: char) -> Foo { pub fn main() { let (tx, rx) = channel(); - let _ = tx.send(foo(42, 'c')); - let _ = rx; + tx.send(foo(42, 'c')).unwrap(); + let _val = rx; } diff --git a/tests/run-pass/slices.rs b/tests/run-pass/slices.rs index 45a2a74db08da..4506a72e8dd02 100644 --- a/tests/run-pass/slices.rs +++ b/tests/run-pass/slices.rs @@ -4,7 +4,7 @@ fn slice_of_zst() { fn foo(v: &[T]) -> Option<&[T]> { let mut it = v.iter(); for _ in 0..5 { - let _ = it.next(); + it.next(); } Some(it.as_slice()) } @@ -12,7 +12,7 @@ fn slice_of_zst() { fn foo_mut(v: &mut [T]) -> Option<&mut [T]> { let mut it = v.iter_mut(); for _ in 0..5 { - let _ = it.next(); + it.next(); } Some(it.into_slice()) } From 14d58ca8a90677e76908bcaa0df22e1ccbd5909f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 25 Nov 2018 15:44:28 +0100 Subject: [PATCH 0411/3747] fix clippy lint whitelisting --- src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 10a1405b2a628..78481979479a0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,6 +1,6 @@ #![feature(rustc_private)] -#![cfg_attr(feature = "cargo-clippy", allow(cast_lossless))] +#![allow(clippy::cast_lossless)] #[macro_use] extern crate log; From 6bd76c7ee1d81f97a797022c0f3cee01769d7178 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 25 Nov 2018 16:08:24 +0100 Subject: [PATCH 0412/3747] cargo miri: factor package manifest logic into separate function --- Cargo.toml | 1 + src/bin/cargo-miri.rs | 125 +++++++++++++++++++++++++----------------- 2 files changed, 75 insertions(+), 51 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 94d13a83fafd5..8408053805224 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -42,6 +42,7 @@ log = "0.4" vergen = "3" [features] +default = ["cargo_miri"] cargo_miri = ["cargo_metadata"] rustc_tests = [] diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index da4a351368d32..19296238e2b28 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -1,3 +1,5 @@ +#![feature(inner_deref)] + extern crate cargo_metadata; use std::path::{PathBuf, Path}; @@ -25,6 +27,13 @@ it to configure the resource limits available resource limits are `memory_size`, `step_limit`, `stack_limit` "#; +#[derive(Copy, Clone, Debug)] +enum MiriCommand { + Run, + Test, + Setup, +} + fn show_help() { println!("{}", CARGO_MIRI_HELP); } @@ -34,6 +43,54 @@ fn show_version() { env!("CARGO_PKG_VERSION"), env!("VERGEN_SHA_SHORT"), env!("VERGEN_COMMIT_DATE")); } +fn list_targets(mut args: impl Iterator) -> impl Iterator { + // We need to get the manifest, and then the metadata, to enumerate targets. + let manifest_path_arg = args.find(|val| { + val.starts_with("--manifest-path=") + }); + + let mut metadata = if let Ok(metadata) = cargo_metadata::metadata( + manifest_path_arg.as_ref().map(AsRef::as_ref), + ) + { + metadata + } else { + let _ = std::io::stderr().write_fmt(format_args!( + "error: Could not obtain cargo metadata." + )); + std::process::exit(101); + }; + + let manifest_path = manifest_path_arg.map(|arg| { + PathBuf::from(Path::new(&arg["--manifest-path=".len()..])) + }); + + let current_dir = std::env::current_dir(); + + let package_index = metadata + .packages + .iter() + .position(|package| { + let package_manifest_path = Path::new(&package.manifest_path); + if let Some(ref manifest_path) = manifest_path { + package_manifest_path == manifest_path + } else { + let current_dir = current_dir.as_ref().expect( + "could not read current directory", + ); + let package_manifest_directory = package_manifest_path.parent().expect( + "could not find parent directory of package manifest", + ); + package_manifest_directory == current_dir + } + }) + .expect("could not find matching package"); + let package = metadata.packages.remove(package_index); + + // Finally we got the list of targets to build + package.targets.into_iter() +} + fn main() { // Check for version and help flags even when invoked as 'cargo-miri' if std::env::args().any(|a| a == "--help" || a == "-h") { @@ -51,61 +108,27 @@ fn main() { // binary so that we come back in the other branch, and dispatch // the invocations to rustc and miri, respectively. - let test = std::env::args().nth(2).map_or(false, |text| text == "test"); - let skip = if test { 3 } else { 2 }; - - // We need to get the manifest, and then the metadata, to enumerate targets. - let manifest_path_arg = std::env::args().skip(skip).find(|val| { - val.starts_with("--manifest-path=") - }); - - let mut metadata = if let Ok(metadata) = cargo_metadata::metadata( - manifest_path_arg.as_ref().map(AsRef::as_ref), - ) - { - metadata - } else { - let _ = std::io::stderr().write_fmt(format_args!( - "error: Could not obtain cargo metadata." - )); - std::process::exit(101); + let (subcommand, skip) = match std::env::args().nth(2).deref() { + Some("test") => (MiriCommand::Test, 3), + Some("run") => (MiriCommand::Run, 3), + Some("setup") => (MiriCommand::Setup, 3), + // Default command, if there is an option or nothing + Some(s) if s.starts_with("-") => (MiriCommand::Run, 2), + None => (MiriCommand::Run, 2), + // Unvalid command + Some(s) => { + eprintln!("Unknown command `{}`", s); + std::process::exit(1) + } }; - let manifest_path = manifest_path_arg.map(|arg| { - PathBuf::from(Path::new(&arg["--manifest-path=".len()..])) - }); - - let current_dir = std::env::current_dir(); - - let package_index = metadata - .packages - .iter() - .position(|package| { - let package_manifest_path = Path::new(&package.manifest_path); - if let Some(ref manifest_path) = manifest_path { - package_manifest_path == manifest_path - } else { - let current_dir = current_dir.as_ref().expect( - "could not read current directory", - ); - let package_manifest_directory = package_manifest_path.parent().expect( - "could not find parent directory of package manifest", - ); - package_manifest_directory == current_dir - } - }) - .expect("could not find matching package"); - let package = metadata.packages.remove(package_index); - - // Finally we got the metadata, iterate all targets and see for which ones - // we do anything. - for target in package.targets { + for target in list_targets(std::env::args().skip(skip)) { let args = std::env::args().skip(skip); let kind = target.kind.get(0).expect( "badly formatted cargo metadata: target::kind is an empty array", ); - match (test, &kind[..]) { - (true, "test") => { + match (subcommand, &kind[..]) { + (MiriCommand::Test, "test") => { // For test binaries we call `cargo rustc --test target -- ` if let Err(code) = process( vec!["--test".to_string(), target.name].into_iter().chain( @@ -116,7 +139,7 @@ fn main() { std::process::exit(code); } } - (true, "lib") => { + (MiriCommand::Test, "lib") => { // For libraries we call `cargo rustc -- --test ` // Notice now that `--test` is a rustc arg rather than a cargo arg. This tells // rustc to build a test harness which calls all #[test] functions. We don't @@ -131,7 +154,7 @@ fn main() { std::process::exit(code); } } - (false, "bin") => { + (MiriCommand::Run, "bin") => { // For ordinary binaries we call `cargo rustc --bin target -- ` if let Err(code) = process( vec!["--bin".to_string(), target.name].into_iter().chain( From c945e30d100a79a2d2c73358d54d7545d03093ac Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 25 Nov 2018 16:30:11 +0100 Subject: [PATCH 0413/3747] setup routine to install xargo when missing --- src/bin/cargo-miri.rs | 58 +++++++++++++++++++++++++++++++++++++++---- 1 file changed, 53 insertions(+), 5 deletions(-) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 19296238e2b28..e39011db5ca70 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -3,14 +3,19 @@ extern crate cargo_metadata; use std::path::{PathBuf, Path}; -use std::io::Write; +use std::io::{self, Write}; use std::process::Command; const CARGO_MIRI_HELP: &str = r#"Interprets bin crates Usage: - cargo miri [options] [--] [...] + cargo miri [subcommand] [options] [--] [...] + +Subcommands: + run Run binaries (default) + test Run tests + setup Only perform automatic setup, but without asking questions (for getting a proper libstd) Common options: -h, --help Print this message @@ -27,7 +32,7 @@ it to configure the resource limits available resource limits are `memory_size`, `step_limit`, `stack_limit` "#; -#[derive(Copy, Clone, Debug)] +#[derive(Copy, Clone, Debug, PartialEq, Eq)] enum MiriCommand { Run, Test, @@ -43,6 +48,11 @@ fn show_version() { env!("CARGO_PKG_VERSION"), env!("VERGEN_SHA_SHORT"), env!("VERGEN_COMMIT_DATE")); } +fn show_error(msg: String) -> ! { + eprintln!("fatal error: {}", msg); + std::process::exit(1) +} + fn list_targets(mut args: impl Iterator) -> impl Iterator { // We need to get the manifest, and then the metadata, to enumerate targets. let manifest_path_arg = args.find(|val| { @@ -91,6 +101,40 @@ fn list_targets(mut args: impl Iterator) -> impl Iterator true, + "n" | "no" => false, + a => show_error(format!("I do not understand `{}`", a)) + }; + if !answer { + show_error(format!("Aborting as per your request")) + } +} + +/// Perform the setup requires to make `cargo miri` work: Getting a custom-built libstd. Then sets MIRI_SYSROOT. +/// Skipped if MIRI_SYSROOT is already set, in that case we expect the user has done all this already. +fn setup(ask_user: bool) { + if std::env::var("MIRI_SYSROOT").is_ok() { + return; + } + + // First, we need xargo + if Command::new("xargo").arg("--version").output().is_err() + { + if ask_user { + ask("It seems you do not have xargo installed. I will run `cargo install xargo`. Proceed?"); + } + if !Command::new("cargo").args(&["install", "xargo"]).status().unwrap().success() { + show_error(format!("Failed to install xargo")); + } + } +} + fn main() { // Check for version and help flags even when invoked as 'cargo-miri' if std::env::args().any(|a| a == "--help" || a == "-h") { @@ -117,11 +161,15 @@ fn main() { None => (MiriCommand::Run, 2), // Unvalid command Some(s) => { - eprintln!("Unknown command `{}`", s); - std::process::exit(1) + show_error(format!("Unknown command `{}`", s)) } }; + // We always setup + let ask = subcommand != MiriCommand::Setup; + setup(ask); + + // Now run the command. for target in list_targets(std::env::args().skip(skip)) { let args = std::env::args().skip(skip); let kind = target.kind.get(0).expect( From 738133b379b172a37f8699085daff62b5a7d16a5 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 25 Nov 2018 17:09:49 +0100 Subject: [PATCH 0414/3747] complete setup routine: instal rust-src, build libstd, use it --- Cargo.toml | 3 ++- src/bin/cargo-miri.rs | 55 ++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 56 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 8408053805224..111b47a551a82 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -35,6 +35,7 @@ required-features = ["rustc_tests"] [dependencies] byteorder = { version = "1.1", features = ["i128"]} cargo_metadata = { version = "0.6", optional = true } +dirs = { version = "1.0.4", optional = true } env_logger = "0.5" log = "0.4" @@ -43,7 +44,7 @@ vergen = "3" [features] default = ["cargo_miri"] -cargo_miri = ["cargo_metadata"] +cargo_miri = ["cargo_metadata", "dirs"] rustc_tests = [] [dev-dependencies] diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index e39011db5ca70..1a5553ca10945 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -5,7 +5,7 @@ extern crate cargo_metadata; use std::path::{PathBuf, Path}; use std::io::{self, Write}; use std::process::Command; - +use std::fs::{self, File}; const CARGO_MIRI_HELP: &str = r#"Interprets bin crates @@ -133,6 +133,59 @@ fn setup(ask_user: bool) { show_error(format!("Failed to install xargo")); } } + + // Then, we also need rust-src. Let's see if it is already installed. + let sysroot = Command::new("rustc").args(&["--print", "sysroot"]).output().unwrap().stdout; + let sysroot = std::str::from_utf8(&sysroot[..]).unwrap(); + let src = Path::new(sysroot.trim_end_matches('\n')).join("lib/rustlib/src"); + if !src.exists() { + println!("Could not find {:?}", src); + if ask_user { + ask("It seems you do not have the rust-src component installed. I will run `rustup component add rust-src`. Proceed?"); + } + if !Command::new("rustup").args(&["component", "add", "rust-src"]).status().unwrap().success() { + show_error(format!("Failed to install rust-src component")); + } + } + + // Next, we need our own libstd. We will do this work in ~/.miri. + let dir = dirs::home_dir().unwrap().join(".miri"); + if !dir.exists() { + fs::create_dir(&dir).unwrap(); + } + // The interesting bit: Xargo.toml + File::create(dir.join("Xargo.toml")).unwrap() + .write_all(br#" +[dependencies.std] +features = ["panic_unwind", "backtrace"] + +[dependencies.test] +stage = 1 + "#).unwrap(); + // The boring bits: A dummy project for xargo + File::create(dir.join("Cargo.toml")).unwrap() + .write_all(br#" +[package] +name = "miri-xargo" +description = "A dummy project for building libstd with xargo." +version = "0.0.0" + +[lib] +path = "lib.rs" + "#).unwrap(); + File::create(dir.join("lib.rs")).unwrap(); + // Run xargo + if !Command::new("xargo").arg("build") + .current_dir(&dir) + .env("RUSTFLAGS", miri::miri_default_args().join(" ")) + .env("XARGO_HOME", dir.to_str().unwrap()) + .status().unwrap().success() + { + show_error(format!("Failed to run xargo")); + } + + // That should be it! + std::env::set_var("MIRI_SYSROOT", dir.join("HOST")); } fn main() { From bb47df94ddf8620b10f18b528cb21b1b785f4226 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 25 Nov 2018 17:17:21 +0100 Subject: [PATCH 0415/3747] use cargo miri setup for CI --- .travis.yml | 8 +++----- appveyor.yml | 13 ++----------- 2 files changed, 5 insertions(+), 16 deletions(-) diff --git a/.travis.yml b/.travis.yml index 85dd50cb5e3c3..e5a47a40a9bef 100644 --- a/.travis.yml +++ b/.travis.yml @@ -28,8 +28,6 @@ before_script: - 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" script: - set -e @@ -39,9 +37,9 @@ script: cargo test --release --all-features && cargo install --all-features --force --path . - | - # get ourselves a MIR-full libstd - xargo/build.sh && - export MIRI_SYSROOT=~/.xargo/HOST + # starting here, use MIR-full libstd + cargo miri setup && + export MIRI_SYSROOT=~/.miri/HOST - | # run all tests with full mir cargo test --release --all-features diff --git a/appveyor.yml b/appveyor.yml index 3dc47f1c67b6a..5757d1d27967c 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -21,16 +21,6 @@ install: - rustup-init.exe -y --default-host %TARGET% --default-toolchain %RUST_TOOLCHAIN% - set PATH=%USERPROFILE%\.cargo\bin;%PATH% - rustc --version - # Customize installation. - - rustup component add rust-src - - cargo install xargo - # Prepare a libstd with MIR (cannot use bash script, obviously). - # The flags here should be kept in sync with `add_miri_default_args` in `src/lib.rs`. - - cd xargo - - set RUSTFLAGS=-Zalways-encode-mir -Zmir-emit-retag -Zmir-opt-level=0 - - xargo build - - set RUSTFLAGS= - - cd .. build: false @@ -39,7 +29,8 @@ test_script: - set RUST_BACKTRACE=1 - cargo build --release --all-features --all-targets - cargo test --release --all-features - - set MIRI_SYSROOT=%USERPROFILE%\.xargo\HOST + - cargo run --release --all-features --bin cargo-miri -- miri setup + - set MIRI_SYSROOT=%USERPROFILE%\.miri\HOST - cargo test --release --all-features notifications: From 16ac7ec1b1a7d07a1806d42e0f350580d537c121 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 25 Nov 2018 17:30:50 +0100 Subject: [PATCH 0416/3747] tweak comments, remove debug output --- .travis.yml | 6 +++--- appveyor.yml | 3 +++ src/bin/cargo-miri.rs | 3 +-- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/.travis.yml b/.travis.yml index e5a47a40a9bef..9a8b806890003 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,7 +11,7 @@ os: - osx before_script: -# macOS weirdness (https://github.com/travis-ci/travis-ci/issues/6307) +# macOS weirdness (https://github.com/travis-ci/travis-ci/issues/6307, https://github.com/travis-ci/travis-ci/issues/10165) - if [[ "$TRAVIS_OS_NAME" == osx ]]; then rvm get stable; fi # Compute the rust version we use. We do not use "language: rust" to have more control here. - | @@ -37,11 +37,11 @@ script: cargo test --release --all-features && cargo install --all-features --force --path . - | - # starting here, use MIR-full libstd + # Get ourselves a MIR-full libstd cargo miri setup && export MIRI_SYSROOT=~/.miri/HOST - | - # run all tests with full mir + # Test miri with full MIR cargo test --release --all-features - | # Test cargo integration diff --git a/appveyor.yml b/appveyor.yml index 5757d1d27967c..4287a08613f19 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -27,10 +27,13 @@ build: false test_script: - set RUSTFLAGS=-g - set RUST_BACKTRACE=1 + # Test plain miri - cargo build --release --all-features --all-targets - cargo test --release --all-features + # Get ourselves a MIR-full libstd - cargo run --release --all-features --bin cargo-miri -- miri setup - set MIRI_SYSROOT=%USERPROFILE%\.miri\HOST + # Test miri with full MIR - cargo test --release --all-features notifications: diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 1a5553ca10945..20d9e9ba71e4c 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -137,9 +137,8 @@ fn setup(ask_user: bool) { // Then, we also need rust-src. Let's see if it is already installed. let sysroot = Command::new("rustc").args(&["--print", "sysroot"]).output().unwrap().stdout; let sysroot = std::str::from_utf8(&sysroot[..]).unwrap(); - let src = Path::new(sysroot.trim_end_matches('\n')).join("lib/rustlib/src"); + let src = Path::new(sysroot.trim_end_matches('\n')).join("lib").join("rustlib").join("src"); if !src.exists() { - println!("Could not find {:?}", src); if ask_user { ask("It seems you do not have the rust-src component installed. I will run `rustup component add rust-src`. Proceed?"); } From cc4dd29f547ae96d6b6eb76441f166d7b3f734b7 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 25 Nov 2018 18:27:24 +0100 Subject: [PATCH 0417/3747] kill xargo dir and update docs --- README.md | 78 +++++++++++-------------------------- cargo-miri-test/run-test.py | 4 +- src/bin/cargo-miri.rs | 2 +- xargo/Cargo.lock | 4 -- xargo/Cargo.toml | 6 --- xargo/Xargo.toml | 5 --- xargo/build.sh | 4 -- xargo/src/lib.rs | 0 8 files changed, 26 insertions(+), 77 deletions(-) delete mode 100644 xargo/Cargo.lock delete mode 100644 xargo/Cargo.toml delete mode 100644 xargo/Xargo.toml delete mode 100755 xargo/build.sh delete mode 100644 xargo/src/lib.rs diff --git a/README.md b/README.md index 5e5a7a23c6afe..5dced653bb007 100644 --- a/README.md +++ b/README.md @@ -42,7 +42,7 @@ in this directory. [rustup]: https://www.rustup.rs -## Running Miri +## Running Miri on tiny examples ```sh cargo +nightly run -- -Zmiri-disable-validation tests/run-pass/vecs.rs # Or whatever test you like. @@ -51,74 +51,42 @@ cargo +nightly run -- -Zmiri-disable-validation tests/run-pass/vecs.rs # Or what We have to disable validation because that can lead to errors when libstd is not compiled the right way. -## Running Miri with full libstd - -Per default libstd does not contain the MIR of non-polymorphic functions, and -also does not contain some extra MIR statements that miri needs for validation. -When Miri hits a call to such a function, execution terminates, and even when -the MIR is present, validation can fail. To fix this, it is possible to compile -libstd with full MIR: - -```sh -rustup component add --toolchain nightly rust-src -cargo +nightly install xargo -rustup run nightly xargo/build.sh -``` - -Now you can run Miri against the libstd compiled by xargo: - -```sh -MIRI_SYSROOT=~/.xargo/HOST cargo +nightly run tests/run-pass-fullmir/hashmap.rs -``` - -Notice that you will have to re-run the last step of the preparations above -(`xargo/build.sh`) when your toolchain changes (e.g., when you update the -nightly). - ## Running Miri on your own project('s test suite) -Install Miri as a cargo subcommand with `cargo +nightly install --all-features ---path .`. Be aware that if you used `rustup override set` to fix a particular -Rust version for the miri directory, that will *not* apply to your own project -directory! You have to use a consistent Rust version for building miri and your -project for this to work, so remember to either always specify the nightly -version manually, overriding it in your project directory as well, or use -`rustup default nightly` (or `rustup default nightly-YYYY-MM-DD`) to globally -make `nightly` the default toolchain. - -We assume that you have prepared a MIR-enabled libstd as described above. Now -compile your project and its dependencies against that libstd: - -1. Run `cargo clean` to eliminate any cached dependencies that were built against -the non-MIR `libstd`. -2. To run all tests in your project through, Miri, use -`MIRI_SYSROOT=~/.xargo/HOST cargo +nightly miri test`. **NOTE**: This is -currently broken, see the discussion in -[#479](https://github.com/solson/miri/issues/479). -3. If you have a binary project, you can run it through Miri using -`MIRI_SYSROOT=~/.xargo/HOST cargo +nightly miri`. +Install Miri as a cargo subcommand with `cargo +nightly install --path .`. Be +aware that if you used `rustup override set` to fix a particular Rust version +for the miri directory, that will *not* apply to your own project directory! +You have to use a consistent Rust version for building miri and your project for +this to work, so remember to either always specify the nightly version manually, +overriding it in your project directory as well, or use `rustup default nightly` +(or `rustup default nightly-YYYY-MM-DD`) to globally make `nightly` the default +toolchain. + +1. Run `cargo clean` to eliminate any cached dependencies. Miri needs your + dependencies to be compiled the right way, that would not happen if they have + previously already been compiled. +2. To run all tests in your project through Miri, use `cargo +nightly miri test`. + **NOTE**: This is currently broken, see the discussion in + [#479](https://github.com/solson/miri/issues/479). +3. If you have a binary project, you can run it through Miri using `cargo + +nightly miri run`. ### Common Problems When using the above instructions, you may encounter a number of confusing compiler errors. -#### "constant evaluation error: no mir for ``" - -You may have forgotten to set `MIRI_SYSROOT` when calling `cargo miri`, and -your program called into `std` or `core`. Be sure to set `MIRI_SYSROOT=~/.xargo/HOST`. - #### "found possibly newer version of crate `std` which `` depends on" -Your build directory may contain artifacts from an earlier build that did/did not -have `MIRI_SYSROOT` set. Run `cargo clean` before switching from non-Miri to Miri -builds and vice-versa. +Your build directory may contain artifacts from an earlier build that have/have +not been built for Miri. Run `cargo clean` before switching from non-Miri to +Miri builds and vice-versa. #### "found crate `std` compiled by an incompatible version of rustc" You may be running `cargo miri` with a different compiler version than the one -used to build the MIR-enabled `std`. Be sure to consistently use the same toolchain, -which should be the toolchain specified in the `rust-version` file. +used to build the custom libstd that Miri uses, and Miri failed to detect that. +Try deleting `~/.miri`. ## Miri `-Z` flags diff --git a/cargo-miri-test/run-test.py b/cargo-miri-test/run-test.py index f686cc47449dd..42745535e0ef4 100755 --- a/cargo-miri-test/run-test.py +++ b/cargo-miri-test/run-test.py @@ -8,10 +8,10 @@ import sys, subprocess def test_cargo_miri(): - print("==> Testing `cargo miri` <==") + print("==> Testing `cargo miri run` <==") ## Call `cargo miri`, capture all output p = subprocess.Popen( - ["cargo", "miri", "-q"], + ["cargo", "miri", "run", "-q"], stdout=subprocess.PIPE, stderr=subprocess.PIPE ) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 20d9e9ba71e4c..5b6ff084024d9 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -174,7 +174,7 @@ path = "lib.rs" "#).unwrap(); File::create(dir.join("lib.rs")).unwrap(); // Run xargo - if !Command::new("xargo").arg("build") + if !Command::new("xargo").arg("build").arg("-q") .current_dir(&dir) .env("RUSTFLAGS", miri::miri_default_args().join(" ")) .env("XARGO_HOME", dir.to_str().unwrap()) diff --git a/xargo/Cargo.lock b/xargo/Cargo.lock deleted file mode 100644 index c85820b708b67..0000000000000 --- a/xargo/Cargo.lock +++ /dev/null @@ -1,4 +0,0 @@ -[[package]] -name = "miri-xargo" -version = "0.0.0" - diff --git a/xargo/Cargo.toml b/xargo/Cargo.toml deleted file mode 100644 index 9129c105b112b..0000000000000 --- a/xargo/Cargo.toml +++ /dev/null @@ -1,6 +0,0 @@ -[package] -name = "miri-xargo" -description = "A dummy project for building libstd with xargo." -version = "0.0.0" - -[dependencies] diff --git a/xargo/Xargo.toml b/xargo/Xargo.toml deleted file mode 100644 index e49b0dbe743b4..0000000000000 --- a/xargo/Xargo.toml +++ /dev/null @@ -1,5 +0,0 @@ -[dependencies.std] -features = ["panic_unwind", "backtrace"] - -[dependencies.test] -stage = 1 diff --git a/xargo/build.sh b/xargo/build.sh deleted file mode 100755 index 25c56d31ab56a..0000000000000 --- a/xargo/build.sh +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/sh -cd "$(dirname "$0")" -# The flags here should be kept in sync with `add_miri_default_args` in `src/lib.rs`. -RUSTFLAGS='-Zalways-encode-mir -Zmir-emit-retag -Zmir-opt-level=0' xargo build diff --git a/xargo/src/lib.rs b/xargo/src/lib.rs deleted file mode 100644 index e69de29bb2d1d..0000000000000 From 9dd0048e665710fb29e967b3a96c7fbd9d66ee76 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 25 Nov 2018 22:17:48 +0100 Subject: [PATCH 0418/3747] install directly from git repo --- README.md | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 5dced653bb007..d33b92f6de40e 100644 --- a/README.md +++ b/README.md @@ -53,8 +53,13 @@ compiled the right way. ## Running Miri on your own project('s test suite) -Install Miri as a cargo subcommand with `cargo +nightly install --path .`. Be -aware that if you used `rustup override set` to fix a particular Rust version +Install Miri as a cargo subcommand: + +```sh +cargo +nightly install --git https://github.com/solson/miri/ +``` + +Be aware that if you used `rustup override set` to fix a particular Rust version for the miri directory, that will *not* apply to your own project directory! You have to use a consistent Rust version for building miri and your project for this to work, so remember to either always specify the nightly version manually, From b09dfc14a0e9dc4ace798dbcf9d381159808406b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 25 Nov 2018 22:23:54 +0100 Subject: [PATCH 0419/3747] there are less places now to keep the flags in sync --- src/lib.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 78481979479a0..d2ead2493c041 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -54,8 +54,7 @@ pub use crate::stacked_borrows::{Borrow, Stack, Stacks, BorStackItem}; /// set per default, for maximal validation power. pub fn miri_default_args() -> &'static [&'static str] { // The flags here should be kept in sync with what bootstrap adds when `test-miri` is - // set, which happens in `bootstrap/bin/rustc.rs` in the rustc sources; and also - // kept in sync with `xargo/build.sh` in this repo and `appveyor.yml`. + // set, which happens in `bootstrap/bin/rustc.rs` in the rustc sources. &["-Zalways-encode-mir", "-Zmir-emit-retag", "-Zmir-opt-level=0"] } From 82caed1a483f3e02f9e92987b88a87751bde4552 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 25 Nov 2018 22:29:25 +0100 Subject: [PATCH 0420/3747] cargo miri setup: print when we are executing commands --- src/bin/cargo-miri.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 5b6ff084024d9..edc0d35fa8dd9 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -128,6 +128,8 @@ fn setup(ask_user: bool) { { if ask_user { ask("It seems you do not have xargo installed. I will run `cargo install xargo`. Proceed?"); + } else { + println!("Installing xargo: `cargo install xargo`"); } if !Command::new("cargo").args(&["install", "xargo"]).status().unwrap().success() { show_error(format!("Failed to install xargo")); @@ -141,6 +143,8 @@ fn setup(ask_user: bool) { if !src.exists() { if ask_user { ask("It seems you do not have the rust-src component installed. I will run `rustup component add rust-src`. Proceed?"); + } else { + println!("Installing rust-src component: `rustup component add rust-src`"); } if !Command::new("rustup").args(&["component", "add", "rust-src"]).status().unwrap().success() { show_error(format!("Failed to install rust-src component")); From 58982d655a3544486e8d827035e6acc4da1f0ccd Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 26 Nov 2018 08:37:31 +0100 Subject: [PATCH 0421/3747] remove unneeded backtrace feature --- src/bin/cargo-miri.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index edc0d35fa8dd9..28cc9f9308403 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -160,7 +160,7 @@ fn setup(ask_user: bool) { File::create(dir.join("Xargo.toml")).unwrap() .write_all(br#" [dependencies.std] -features = ["panic_unwind", "backtrace"] +features = ["panic_unwind"] [dependencies.test] stage = 1 From 07f78a37d4e8d7c55330e90e0a36815bf615a8d9 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 27 Nov 2018 08:16:52 +0100 Subject: [PATCH 0422/3747] tweaks --- Cargo.toml | 4 ++-- src/bin/cargo-miri.rs | 16 +++++----------- 2 files changed, 7 insertions(+), 13 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 111b47a551a82..becb5c69e5612 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -35,7 +35,7 @@ required-features = ["rustc_tests"] [dependencies] byteorder = { version = "1.1", features = ["i128"]} cargo_metadata = { version = "0.6", optional = true } -dirs = { version = "1.0.4", optional = true } +directories = { version = "1.0", optional = true } env_logger = "0.5" log = "0.4" @@ -44,7 +44,7 @@ vergen = "3" [features] default = ["cargo_miri"] -cargo_miri = ["cargo_metadata", "dirs"] +cargo_miri = ["cargo_metadata", "directories"] rustc_tests = [] [dev-dependencies] diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 28cc9f9308403..05d1bf3220812 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -65,10 +65,7 @@ fn list_targets(mut args: impl Iterator) -> impl Iterator true, - "n" | "no" => false, + match buf.trim().to_lowercase().as_ref() { + "" | "y" | "yes" => {}, // proceed + "n" | "no" => show_error(format!("Aborting as per your request")), a => show_error(format!("I do not understand `{}`", a)) }; - if !answer { - show_error(format!("Aborting as per your request")) - } } /// Perform the setup requires to make `cargo miri` work: Getting a custom-built libstd. Then sets MIRI_SYSROOT. @@ -152,7 +146,7 @@ fn setup(ask_user: bool) { } // Next, we need our own libstd. We will do this work in ~/.miri. - let dir = dirs::home_dir().unwrap().join(".miri"); + let dir = directories::UserDirs::new().unwrap().home_dir().join(".miri"); if !dir.exists() { fs::create_dir(&dir).unwrap(); } From 464dee8edf786117f9806ed88d7b238cd4b8abf5 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 27 Nov 2018 09:23:22 +0100 Subject: [PATCH 0423/3747] std::ptr no longer needs whitelisting --- src/lib.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 10a1405b2a628..47f00658e5cba 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -318,7 +318,6 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { // We walk up the stack a few frames to also cover their callees. const WHITELIST: &[(&str, &str)] = &[ // Uses mem::uninitialized - ("std::ptr::read", ""), ("std::sys::windows::mutex::Mutex::", ""), ]; for frame in ecx.stack().iter() From b91679539e7fbbd4ee4bccbdb5de5589c77cc322 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 27 Nov 2018 11:26:53 +0100 Subject: [PATCH 0424/3747] use proper platform cache dir --- src/bin/cargo-miri.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 05d1bf3220812..f06bb2d372352 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -145,8 +145,9 @@ fn setup(ask_user: bool) { } } - // Next, we need our own libstd. We will do this work in ~/.miri. - let dir = directories::UserDirs::new().unwrap().home_dir().join(".miri"); + // Next, we need our own libstd. We will do this work in whatever is a good cache dir for this platform. + let dirs = directories::ProjectDirs::from("miri", "miri", "miri").unwrap(); + let dir = dirs.cache_dir(); if !dir.exists() { fs::create_dir(&dir).unwrap(); } From bd7f4076cdac11fb87629cc5aab1ba0fd77a806a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 27 Nov 2018 11:43:02 +0100 Subject: [PATCH 0425/3747] we need to recursively create the dir --- src/bin/cargo-miri.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index f06bb2d372352..fb1b97269aa7d 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -149,7 +149,7 @@ fn setup(ask_user: bool) { let dirs = directories::ProjectDirs::from("miri", "miri", "miri").unwrap(); let dir = dirs.cache_dir(); if !dir.exists() { - fs::create_dir(&dir).unwrap(); + fs::create_dir_all(&dir).unwrap(); } // The interesting bit: Xargo.toml File::create(dir.join("Xargo.toml")).unwrap() From 53196554ec5c96f067611b96ffd3e1409274e4d0 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 27 Nov 2018 12:08:46 +0100 Subject: [PATCH 0426/3747] inform the user when and where we are creating a cache dir --- src/bin/cargo-miri.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index fb1b97269aa7d..ed4ffa43dbce3 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -149,6 +149,7 @@ fn setup(ask_user: bool) { let dirs = directories::ProjectDirs::from("miri", "miri", "miri").unwrap(); let dir = dirs.cache_dir(); if !dir.exists() { + println!("Creating `{}` and using it for miri's build of libstd", dir.display()); fs::create_dir_all(&dir).unwrap(); } // The interesting bit: Xargo.toml From fbd7d119aecca4019467b2b191fcb1d88af2ed81 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 27 Nov 2018 11:46:09 +0100 Subject: [PATCH 0427/3747] use new dir for CI and docs --- .travis.yml | 8 ++++++-- README.md | 2 +- appveyor.yml | 4 ++-- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/.travis.yml b/.travis.yml index 9a8b806890003..ba3b8d3639917 100644 --- a/.travis.yml +++ b/.travis.yml @@ -37,9 +37,13 @@ script: cargo test --release --all-features && cargo install --all-features --force --path . - | - # Get ourselves a MIR-full libstd + # Get ourselves a MIR-full libstd, and use it henceforth cargo miri setup && - export MIRI_SYSROOT=~/.miri/HOST + if [ "$TRAVIS_OS_NAME" == osx ]; then + export MIRI_SYSROOT=~/Library/Caches/miri.miri.miri/HOST + else + export MIRI_SYSROOT=~/.cache/miri/HOST + fi - | # Test miri with full MIR cargo test --release --all-features diff --git a/README.md b/README.md index d33b92f6de40e..d6e0be40cacf4 100644 --- a/README.md +++ b/README.md @@ -91,7 +91,7 @@ Miri builds and vice-versa. You may be running `cargo miri` with a different compiler version than the one used to build the custom libstd that Miri uses, and Miri failed to detect that. -Try deleting `~/.miri`. +Try deleting `~/.cache/miri`. ## Miri `-Z` flags diff --git a/appveyor.yml b/appveyor.yml index 4287a08613f19..1f38b848c0059 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -30,9 +30,9 @@ test_script: # Test plain miri - cargo build --release --all-features --all-targets - cargo test --release --all-features - # Get ourselves a MIR-full libstd + # Get ourselves a MIR-full libstd, and use it henceforth - cargo run --release --all-features --bin cargo-miri -- miri setup - - set MIRI_SYSROOT=%USERPROFILE%\.miri\HOST + - set MIRI_SYSROOT=%USERPROFILE%\AppData\Local\miri\miri\cache\HOST # Test miri with full MIR - cargo test --release --all-features From e9370d2b74d38720fed7887fc708b8fa67fe7adb Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 15 Nov 2018 13:29:55 +0100 Subject: [PATCH 0428/3747] adjust for memory_allocated hook, make RangeMap preallocated with a fixed size --- src/lib.rs | 23 ++++++--- src/range_map.rs | 108 +++++++++++------------------------------ src/stacked_borrows.rs | 16 ++++-- 3 files changed, 56 insertions(+), 91 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index d2ead2493c041..591cf5766234b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -301,6 +301,7 @@ type MiriEvalContext<'a, 'mir, 'tcx> = EvalContext<'a, 'mir, 'tcx, Evaluator<'tc impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { type MemoryKinds = MiriMemoryKind; + type MemoryExtra = (); type AllocExtra = stacked_borrows::Stacks; type PointerTag = Borrow; @@ -405,8 +406,9 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { } fn find_foreign_static( - tcx: TyCtxtAt<'a, 'tcx, 'tcx>, def_id: DefId, + tcx: TyCtxtAt<'a, 'tcx, 'tcx>, + memory_extra: &Self::MemoryExtra, ) -> EvalResult<'tcx, Cow<'tcx, Allocation>> { let attrs = tcx.get_attrs(def_id); let link_name = match attr::first_attr_value_str_by_name(&attrs, "link_name") { @@ -417,8 +419,10 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { let alloc = match &link_name[..] { "__cxa_thread_atexit_impl" => { // This should be all-zero, pointer-sized - let data = vec![0; tcx.data_layout.pointer_size.bytes() as usize]; - Allocation::from_bytes(&data[..], tcx.data_layout.pointer_align.abi) + let size = tcx.data_layout.pointer_size; + let data = vec![0; size.bytes() as usize]; + let extra = AllocationExtra::memory_allocated(size, memory_extra); + Allocation::from_bytes(&data[..], tcx.data_layout.pointer_align.abi, extra) } _ => return err!(Unimplemented( format!("can't access foreign static: {}", link_name), @@ -434,9 +438,14 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { Ok(()) } - fn adjust_static_allocation( - alloc: &'_ Allocation - ) -> Cow<'_, Allocation> { + fn adjust_static_allocation<'b>( + alloc: &'b Allocation, + memory_extra: &Self::MemoryExtra, + ) -> Cow<'b, Allocation> { + let extra = AllocationExtra::memory_allocated( + Size::from_bytes(alloc.bytes.len() as u64), + memory_extra, + ); let alloc: Allocation = Allocation { bytes: alloc.bytes.clone(), relocations: Relocations::from_presorted( @@ -447,7 +456,7 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { undef_mask: alloc.undef_mask.clone(), align: alloc.align, mutability: alloc.mutability, - extra: Self::AllocExtra::default(), + extra, }; Cow::Owned(alloc) } diff --git a/src/range_map.rs b/src/range_map.rs index 74a49bf83b819..762b17b1ae338 100644 --- a/src/range_map.rs +++ b/src/range_map.rs @@ -16,13 +16,6 @@ pub struct RangeMap { map: BTreeMap, } -impl Default for RangeMap { - #[inline(always)] - fn default() -> Self { - RangeMap::new() - } -} - // The derived `Ord` impl sorts first by the first field, then, if the fields are the same, // by the second field. // This is exactly what we need for our purposes, since a range query on a BTReeSet/BTreeMap will give us all @@ -73,9 +66,15 @@ impl Range { } impl RangeMap { + /// Create a new RangeMap for the given size, and with the given initial value used for + /// the entire range. #[inline(always)] - pub fn new() -> RangeMap { - RangeMap { map: BTreeMap::new() } + pub fn new(size: Size, init: T) -> RangeMap { + let mut map = RangeMap { map: BTreeMap::new() }; + if size.bytes() > 0 { + map.map.insert(Range { start: 0, end: size.bytes() }, init); + } + map } fn iter_with_range<'a>( @@ -95,6 +94,9 @@ impl RangeMap { ) } + /// Provide read-only iteration over everything in the given range. This does + /// *not* split items if they overlap with the edges. Do not use this to mutate + /// through interior mutability. pub fn iter<'a>(&'a self, offset: Size, len: Size) -> impl Iterator + 'a { self.iter_with_range(offset.bytes(), len.bytes()).map(|(_, data)| data) } @@ -140,8 +142,7 @@ impl RangeMap { /// Provide mutable iteration over everything in the given range. As a side-effect, /// this will split entries in the map that are only partially hit by the given range, /// to make sure that when they are mutated, the effect is constrained to the given range. - /// If there are gaps, leave them be. - pub fn iter_mut_with_gaps<'a>( + pub fn iter_mut<'a>( &'a mut self, offset: Size, len: Size, @@ -174,64 +175,6 @@ impl RangeMap { }, ) } - - /// Provide a mutable iterator over everything in the given range, with the same side-effects as - /// iter_mut_with_gaps. Furthermore, if there are gaps between ranges, fill them with the given default - /// before yielding them in the iterator. - /// This is also how you insert. - pub fn iter_mut<'a>(&'a mut self, offset: Size, len: Size) -> impl Iterator + 'a - where - T: Clone + Default, - { - if len.bytes() > 0 { - let offset = offset.bytes(); - let len = len.bytes(); - - // Do a first iteration to collect the gaps - let mut gaps = Vec::new(); - let mut last_end = offset; - for (range, _) in self.iter_with_range(offset, len) { - if last_end < range.start { - gaps.push(Range { - start: last_end, - end: range.start, - }); - } - last_end = range.end; - } - if last_end < offset + len { - gaps.push(Range { - start: last_end, - end: offset + len, - }); - } - - // Add default for all gaps - for gap in gaps { - let old = self.map.insert(gap, Default::default()); - assert!(old.is_none()); - } - } - - // Now provide mutable iteration - self.iter_mut_with_gaps(offset, len) - } - - pub fn retain(&mut self, mut f: F) - where - F: FnMut(&T) -> bool, - { - let mut remove = Vec::new(); - for (range, data) in &self.map { - if !f(data) { - remove.push(*range); - } - } - - for range in remove { - self.map.remove(&range); - } - } } #[cfg(test)] @@ -239,14 +182,13 @@ mod tests { use super::*; /// Query the map at every offset in the range and collect the results. - fn to_vec(map: &RangeMap, offset: u64, len: u64, default: Option) -> Vec { + fn to_vec(map: &RangeMap, offset: u64, len: u64) -> Vec { (offset..offset + len) .into_iter() .map(|i| map .iter(Size::from_bytes(i), Size::from_bytes(1)) .next() .map(|&t| t) - .or(default) .unwrap() ) .collect() @@ -254,13 +196,13 @@ mod tests { #[test] fn basic_insert() { - let mut map = RangeMap::::new(); + let mut map = RangeMap::::new(Size::from_bytes(20), -1); // Insert for x in map.iter_mut(Size::from_bytes(10), Size::from_bytes(1)) { *x = 42; } // Check - assert_eq!(to_vec(&map, 10, 1, None), vec![42]); + assert_eq!(to_vec(&map, 10, 1), vec![42]); // Insert with size 0 for x in map.iter_mut(Size::from_bytes(10), Size::from_bytes(0)) { @@ -269,12 +211,12 @@ mod tests { for x in map.iter_mut(Size::from_bytes(11), Size::from_bytes(0)) { *x = 19; } - assert_eq!(to_vec(&map, 10, 2, Some(-1)), vec![42, -1]); + assert_eq!(to_vec(&map, 10, 2), vec![42, -1]); } #[test] fn gaps() { - let mut map = RangeMap::::new(); + let mut map = RangeMap::::new(Size::from_bytes(20), -1); for x in map.iter_mut(Size::from_bytes(11), Size::from_bytes(1)) { *x = 42; } @@ -282,11 +224,10 @@ mod tests { *x = 43; } assert_eq!( - to_vec(&map, 10, 10, Some(-1)), + to_vec(&map, 10, 10), vec![-1, 42, -1, -1, -1, 43, -1, -1, -1, -1] ); - // Now request a range that needs three gaps filled for x in map.iter_mut(Size::from_bytes(10), Size::from_bytes(10)) { if *x < 42 { *x = 23; @@ -294,9 +235,18 @@ mod tests { } assert_eq!( - to_vec(&map, 10, 10, None), + to_vec(&map, 10, 10), vec![23, 42, 23, 23, 23, 43, 23, 23, 23, 23] ); - assert_eq!(to_vec(&map, 13, 5, None), vec![23, 23, 43, 23, 23]); + assert_eq!(to_vec(&map, 13, 5), vec![23, 23, 43, 23, 23]); + + // Now request a range that goes beyond the initial size + for x in map.iter_mut(Size::from_bytes(15), Size::from_bytes(10)) { + *x = 19; + } + assert_eq!(map.iter(Size::from_bytes(19), Size::from_bytes(1)) + .map(|&t| t).collect::>(), vec![19]); + assert_eq!(map.iter(Size::from_bytes(20), Size::from_bytes(1)) + .map(|&t| t).collect::>(), vec![]); } } diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index f292d083637ac..22ec6ffe6f50a 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -126,7 +126,7 @@ impl State { } /// Extra per-allocation state -#[derive(Clone, Debug, Default)] +#[derive(Clone, Debug)] pub struct Stacks { // Even reading memory can have effects on the stack, so we need a `RefCell` here. stacks: RefCell>, @@ -289,9 +289,8 @@ impl<'tcx> Stacks { ) -> EvalResult<'tcx> { trace!("deref for tag {:?} as {:?}: {:?}, size {}", ptr.tag, kind, ptr, size.bytes()); - let mut stacks = self.stacks.borrow_mut(); - // We need `iter_mut` because `iter` would skip gaps! - for stack in stacks.iter_mut(ptr.offset, size) { + let stacks = self.stacks.borrow(); + for stack in stacks.iter(ptr.offset, size) { stack.deref(ptr.tag, kind).map_err(EvalErrorKind::MachineError)?; } Ok(()) @@ -359,7 +358,14 @@ impl<'tcx> Stacks { } /// Hooks and glue -impl AllocationExtra for Stacks { +impl AllocationExtra for Stacks { + #[inline(always)] + fn memory_allocated<'tcx>(size: Size, _extra: &()) -> Self { + Stacks { + stacks: RefCell::new(RangeMap::new(size, Stack::default())) + } + } + #[inline(always)] fn memory_read<'tcx>( alloc: &Allocation, From 215ec38624818c4df9889c702fecb10c33b646ee Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 15 Nov 2018 18:15:05 +0100 Subject: [PATCH 0429/3747] track call IDs --- src/lib.rs | 20 ++++++++++++-- src/stacked_borrows.rs | 61 ++++++++++++++++++++++++++++++++---------- 2 files changed, 65 insertions(+), 16 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 591cf5766234b..3211f9c5bd951 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -289,7 +289,7 @@ impl<'tcx> Evaluator<'tcx> { env_vars: HashMap::default(), tls: TlsData::default(), validate, - stacked_borrows: stacked_borrows::State::new(), + stacked_borrows: stacked_borrows::State::default(), } } } @@ -301,7 +301,8 @@ type MiriEvalContext<'a, 'mir, 'tcx> = EvalContext<'a, 'mir, 'tcx, Evaluator<'tc impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { type MemoryKinds = MiriMemoryKind; - type MemoryExtra = (); + type FrameExtra = stacked_borrows::CallId; + type MemoryExtra = stacked_borrows::MemoryState; type AllocExtra = stacked_borrows::Stacks; type PointerTag = Borrow; @@ -538,4 +539,19 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { ecx.retag(fn_entry, place) } } + + #[inline(always)] + fn stack_push( + ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, + ) -> EvalResult<'tcx, stacked_borrows::CallId> { + Ok(ecx.memory().extra.borrow_mut().new_call()) + } + + #[inline(always)] + fn stack_pop( + ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, + extra: stacked_borrows::CallId, + ) -> EvalResult<'tcx> { + Ok(ecx.memory().extra.borrow_mut().end_call(extra)) + } } diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 22ec6ffe6f50a..067e3bb8445f0 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -1,4 +1,6 @@ use std::cell::RefCell; +use std::collections::HashSet; +use std::rc::Rc; use rustc::ty::{self, layout::Size}; use rustc::hir::{Mutability, MutMutable, MutImmutable}; @@ -10,6 +12,7 @@ use crate::{ }; pub type Timestamp = u64; +pub type CallId = u64; /// Information about which kind of borrow was used to create the reference this is tagged /// with. @@ -80,15 +83,6 @@ pub struct Stack { frozen_since: Option, // virtual frozen "item" on top of the stack } -impl Default for Stack { - fn default() -> Self { - Stack { - borrows: vec![BorStackItem::Shr], - frozen_since: None, - } - } -} - impl Stack { #[inline(always)] pub fn is_frozen(&self) -> bool { @@ -107,17 +101,50 @@ pub enum RefKind { Raw, } +/// Extra global state in the memory, available to the memory access hooks +#[derive(Debug)] +pub struct BarrierTracking { + next_id: CallId, + active_calls: HashSet, +} +pub type MemoryState = Rc>; + +impl Default for BarrierTracking { + fn default() -> Self { + BarrierTracking { + next_id: 0, + active_calls: HashSet::default(), + } + } +} + +impl BarrierTracking { + pub fn new_call(&mut self) -> CallId { + let id = self.next_id; + trace!("new_call: Assigning ID {}", id); + self.active_calls.insert(id); + self.next_id += 1; + id + } + + pub fn end_call(&mut self, id: CallId) { + assert!(self.active_calls.remove(&id)); + } +} + /// Extra global machine state #[derive(Clone, Debug)] pub struct State { clock: Timestamp } -impl State { - pub fn new() -> State { +impl Default for State { + fn default() -> Self { State { clock: 0 } } +} +impl State { fn increment_clock(&mut self) -> Timestamp { let val = self.clock; self.clock = val + 1; @@ -130,6 +157,7 @@ impl State { pub struct Stacks { // Even reading memory can have effects on the stack, so we need a `RefCell` here. stacks: RefCell>, + barrier_tracking: MemoryState, } /// Core per-location operations: deref, access, create. @@ -358,11 +386,16 @@ impl<'tcx> Stacks { } /// Hooks and glue -impl AllocationExtra for Stacks { +impl AllocationExtra for Stacks { #[inline(always)] - fn memory_allocated<'tcx>(size: Size, _extra: &()) -> Self { + fn memory_allocated<'tcx>(size: Size, extra: &MemoryState) -> Self { + let stack = Stack { + borrows: vec![BorStackItem::Shr], + frozen_since: None, + }; Stacks { - stacks: RefCell::new(RangeMap::new(size, Stack::default())) + stacks: RefCell::new(RangeMap::new(size, stack)), + barrier_tracking: Rc::clone(extra), } } From dd94930ee3d928c4029b4d118befdd620eaf0919 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 15 Nov 2018 19:49:00 +0100 Subject: [PATCH 0430/3747] implement function barriers --- src/stacked_borrows.rs | 142 +++++++++++------- .../stacked_borrows/aliasing_mut1.rs | 19 ++- .../stacked_borrows/aliasing_mut2.rs | 19 ++- .../stacked_borrows/aliasing_mut3.rs | 19 ++- .../stacked_borrows/aliasing_mut4.rs | 22 +-- .../box_exclusive_violation1.rs | 4 +- .../stacked_borrows/illegal_write1.rs | 15 +- .../invalidate_against_barrier1.rs | 13 ++ .../invalidate_against_barrier2.rs | 13 ++ .../mut_exclusive_violation1.rs | 2 +- 10 files changed, 174 insertions(+), 94 deletions(-) create mode 100644 tests/compile-fail-fullmir/stacked_borrows/invalidate_against_barrier1.rs create mode 100644 tests/compile-fail-fullmir/stacked_borrows/invalidate_against_barrier2.rs diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 067e3bb8445f0..6b851cd65b5ee 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -62,18 +62,7 @@ pub enum BorStackItem { /// when there is no `UnsafeCell`. Shr, /// A barrier, tracking the function it belongs to by its index on the call stack - #[allow(dead_code)] // for future use - FnBarrier(usize) -} - -impl BorStackItem { - #[inline(always)] - pub fn is_fn_barrier(self) -> bool { - match self { - BorStackItem::FnBarrier(_) => true, - _ => false, - } - } + FnBarrier(CallId) } /// Extra per-location state @@ -130,6 +119,10 @@ impl BarrierTracking { pub fn end_call(&mut self, id: CallId) { assert!(self.active_calls.remove(&id)); } + + fn is_active(&self, id: CallId) -> bool { + self.active_calls.contains(&id) + } } /// Extra global machine state @@ -178,7 +171,11 @@ impl<'tcx> Stack { /// going to read or write. /// Returns the index of the item we matched, `None` if it was the frozen one. /// `kind` indicates which kind of reference is being dereferenced. - fn deref(&self, bor: Borrow, kind: RefKind) -> Result, String> { + fn deref( + &self, + bor: Borrow, + kind: RefKind, + ) -> Result, String> { // Exclude unique ref with frozen tag. if let (RefKind::Unique, Borrow::Shr(Some(_))) = (kind, bor) { return Err(format!("Encountered mutable reference with frozen tag ({:?})", bor)); @@ -200,7 +197,6 @@ impl<'tcx> Stack { // If we got here, we have to look for our item in the stack. for (idx, &itm) in self.borrows.iter().enumerate().rev() { match (itm, bor) { - (BorStackItem::FnBarrier(_), _) => break, (BorStackItem::Uniq(itm_t), Borrow::Uniq(bor_t)) if itm_t == bor_t => { // Found matching unique item. This satisfies U3. return Ok(Some(idx)) @@ -209,21 +205,25 @@ impl<'tcx> Stack { // Found matching shared/raw item. return Ok(Some(idx)) } - // Go on looking. + // Go on looking. We ignore barriers! When an `&mut` and an `&` alias, + // dereferencing the `&` is still possible (to reborrow), but doing + // an access is not. _ => {} } } // If we got here, we did not find our item. We have to error to satisfy U3. - Err(format!( - "Borrow being dereferenced ({:?}) does not exist on the stack, or is guarded by a barrier", - bor - )) + Err(format!("Borrow being dereferenced ({:?}) does not exist on the stack", bor)) } /// Perform an actual memory access using `bor`. We do not know any types here /// or whether things should be frozen, but we *do* know if this is reading /// or writing. - fn access(&mut self, bor: Borrow, is_write: bool) -> EvalResult<'tcx> { + fn access( + &mut self, + bor: Borrow, + is_write: bool, + barrier_tracking: &BarrierTracking, + ) -> EvalResult<'tcx> { // Check if we can match the frozen "item". // Not possible on writes! if self.is_frozen() { @@ -240,7 +240,12 @@ impl<'tcx> Stack { // Pop the stack until we have something matching. while let Some(&itm) = self.borrows.last() { match (itm, bor) { - (BorStackItem::FnBarrier(_), _) => break, + (BorStackItem::FnBarrier(call), _) if barrier_tracking.is_active(call) => { + return err!(MachineError(format!( + "Stopping looking for borrow being accessed ({:?}) because of barrier ({})", + bor, call + ))) + } (BorStackItem::Uniq(itm_t), Borrow::Uniq(bor_t)) if itm_t == bor_t => { // Found matching unique item. return Ok(()) @@ -265,7 +270,7 @@ impl<'tcx> Stack { } // If we got here, we did not find our item. err!(MachineError(format!( - "Borrow being accessed ({:?}) does not exist on the stack, or is guarded by a barrier", + "Borrow being accessed ({:?}) does not exist on the stack", bor ))) } @@ -275,18 +280,21 @@ impl<'tcx> Stack { /// is met: We cannot push `Uniq` onto frozen stacks. /// `kind` indicates which kind of reference is being created. fn create(&mut self, bor: Borrow, kind: RefKind) { - // First, push the item. We do this even if we will later freeze, because we - // will allow mutation of shared data at the expense of unfreezing. if self.frozen_since.is_some() { - // A frozen location, this should be impossible! - bug!("We should never try pushing to a frozen stack"); + // A frozen location? Possible if we create a barrier, then push again. + assert!(bor.is_shared(), "We should never try creating a unique borrow for a frozen stack"); + trace!("create: Not doing anything on frozen location"); + return; } - // First, push. + // First, push. We do this even if we will later freeze, because we + // will allow mutation of shared data at the expense of unfreezing. let itm = match bor { Borrow::Uniq(t) => BorStackItem::Uniq(t), Borrow::Shr(_) => BorStackItem::Shr, }; if *self.borrows.last().unwrap() == itm { + // This is just an optimization, no functional change: Avoid stacking + // multiple `Shr` on top of each other. assert!(bor.is_shared()); trace!("create: Sharing a shared location is a NOP"); } else { @@ -304,6 +312,21 @@ impl<'tcx> Stack { self.frozen_since = Some(bor_t); } } + + /// Add a barrier + fn barrier(&mut self, call: CallId) { + let itm = BorStackItem::FnBarrier(call); + if *self.borrows.last().unwrap() == itm { + // This is just an optimization, no functional change: Avoid stacking + // multiple identical barriers on top of each other. + // This can happen when a function receives several shared references + // that overlap. + trace!("barrier: Avoiding redundant extra barrier"); + } else { + trace!("barrier: Pushing barrier for call {}", call); + self.borrows.push(itm); + } + } } /// Higher-level per-location operations: deref, access, reborrow. @@ -330,6 +353,7 @@ impl<'tcx> Stacks { ptr: Pointer, size: Size, is_write: bool, + barrier_tracking: &BarrierTracking, ) -> EvalResult<'tcx> { trace!("{} access of tag {:?}: {:?}, size {}", if is_write { "read" } else { "write" }, @@ -339,7 +363,7 @@ impl<'tcx> Stacks { // are no accesses through other references, not even reads. let mut stacks = self.stacks.borrow_mut(); for stack in stacks.iter_mut(ptr.offset, size) { - stack.access(ptr.tag, is_write)?; + stack.access(ptr.tag, is_write, barrier_tracking)?; } Ok(()) } @@ -350,12 +374,19 @@ impl<'tcx> Stacks { &self, ptr: Pointer, size: Size, + mut barrier: Option, new_bor: Borrow, new_kind: RefKind, + barrier_tracking: &BarrierTracking, ) -> EvalResult<'tcx> { assert_eq!(new_bor.is_unique(), new_kind == RefKind::Unique); trace!("reborrow for tag {:?} to {:?} as {:?}: {:?}, size {}", ptr.tag, new_bor, new_kind, ptr, size.bytes()); + if new_kind == RefKind::Raw { + // No barrier for raw, including `&UnsafeCell`. They can rightfully + // alias with `&mut`. + barrier = None; + } let mut stacks = self.stacks.borrow_mut(); for stack in stacks.iter_mut(ptr.offset, size) { // Access source `ptr`, create new ref. @@ -364,21 +395,25 @@ impl<'tcx> Stacks { // the stack than the one we come from, just use that. // IOW, we check if `new_bor` *already* is "derived from" `ptr.tag`. // This also checks frozenness, if required. - let bor_redundant = match (ptr_idx, stack.deref(new_bor, new_kind)) { - // If the new borrow works with the frozen item, or else if it lives - // above the old one in the stack, our job here is done. - (_, Ok(None)) => true, - (Some(ptr_idx), Ok(Some(new_idx))) if new_idx >= ptr_idx => true, - // Otherwise we need to create a new borrow. - _ => false, - }; + let bor_redundant = barrier.is_none() && + match (ptr_idx, stack.deref(new_bor, new_kind)) { + // If the new borrow works with the frozen item, or else if it lives + // above the old one in the stack, our job here is done. + (_, Ok(None)) => true, + (Some(ptr_idx), Ok(Some(new_idx))) if new_idx >= ptr_idx => true, + // Otherwise we need to create a new borrow. + _ => false, + }; if bor_redundant { assert!(new_bor.is_shared(), "A unique reborrow can never be redundant"); trace!("reborrow is redundant"); continue; } // We need to do some actual work. - stack.access(ptr.tag, new_kind == RefKind::Unique)?; + stack.access(ptr.tag, new_kind == RefKind::Unique, barrier_tracking)?; + if let Some(call) = barrier { + stack.barrier(call); + } stack.create(new_bor, new_kind); } Ok(()) @@ -405,7 +440,7 @@ impl AllocationExtra for Stacks { ptr: Pointer, size: Size, ) -> EvalResult<'tcx> { - alloc.extra.access(ptr, size, /*is_write*/false) + alloc.extra.access(ptr, size, /*is_write*/false, &*alloc.extra.barrier_tracking.borrow()) } #[inline(always)] @@ -414,7 +449,7 @@ impl AllocationExtra for Stacks { ptr: Pointer, size: Size, ) -> EvalResult<'tcx> { - alloc.extra.access(ptr, size, /*is_write*/true) + alloc.extra.access(ptr, size, /*is_write*/true, &*alloc.extra.barrier_tracking.borrow()) } #[inline(always)] @@ -424,19 +459,18 @@ impl AllocationExtra for Stacks { size: Size, ) -> EvalResult<'tcx> { // This is like mutating - alloc.extra.access(ptr, size, /*is_write*/true) + alloc.extra.access(ptr, size, /*is_write*/true, &*alloc.extra.barrier_tracking.borrow()) // FIXME: Error out of there are any barriers? } } impl<'tcx> Stacks { /// Pushes the first item to the stacks. - pub fn first_item( + pub(crate) fn first_item( &mut self, itm: BorStackItem, size: Size ) { - assert!(!itm.is_fn_barrier()); for stack in self.stacks.get_mut().iter_mut(Size::ZERO, size) { assert!(stack.borrows.len() == 1); assert_eq!(stack.borrows.pop().unwrap(), BorStackItem::Shr); @@ -466,6 +500,7 @@ pub trait EvalContextExt<'tcx> { &mut self, place: MPlaceTy<'tcx, Borrow>, size: Size, + fn_barrier: bool, new_bor: Borrow ) -> EvalResult<'tcx, Pointer>; @@ -474,6 +509,7 @@ pub trait EvalContextExt<'tcx> { &mut self, ptr: ImmTy<'tcx, Borrow>, mutbl: Mutability, + fn_barrier: bool, ) -> EvalResult<'tcx, Immediate>; fn retag( @@ -566,7 +602,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for MiriEvalContext<'a, 'mir, 'tcx> { place: MPlaceTy<'tcx, Borrow>, size: Size, ) -> EvalResult<'tcx> { - self.reborrow(place, size, Borrow::default())?; + self.reborrow(place, size, /*fn_barrier*/ false, Borrow::default())?; Ok(()) } @@ -574,10 +610,12 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for MiriEvalContext<'a, 'mir, 'tcx> { &mut self, place: MPlaceTy<'tcx, Borrow>, size: Size, + fn_barrier: bool, new_bor: Borrow ) -> EvalResult<'tcx, Pointer> { let ptr = place.ptr.to_ptr()?; let new_ptr = Pointer::new_with_tag(ptr.alloc_id, ptr.offset, new_bor); + let barrier = if fn_barrier { Some(self.frame().extra) } else { None }; trace!("reborrow: Creating new reference for {:?} (pointee {}): {:?}", ptr, place.layout.ty, new_bor); @@ -589,12 +627,12 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for MiriEvalContext<'a, 'mir, 'tcx> { // Reference that cares about freezing. We need a frozen-sensitive reborrow. self.visit_freeze_sensitive(place, size, |cur_ptr, size, frozen| { let kind = if frozen { RefKind::Frozen } else { RefKind::Raw }; - alloc.extra.reborrow(cur_ptr, size, new_bor, kind) + alloc.extra.reborrow(cur_ptr, size, barrier, new_bor, kind, &*self.memory().extra.borrow()) })?; } else { // Just treat this as one big chunk. let kind = if new_bor.is_unique() { RefKind::Unique } else { RefKind::Raw }; - alloc.extra.reborrow(ptr, size, new_bor, kind)?; + alloc.extra.reborrow(ptr, size, barrier, new_bor, kind, &*self.memory().extra.borrow())?; } Ok(new_ptr) } @@ -603,6 +641,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for MiriEvalContext<'a, 'mir, 'tcx> { &mut self, val: ImmTy<'tcx, Borrow>, mutbl: Mutability, + fn_barrier: bool, ) -> EvalResult<'tcx, Immediate> { // We want a place for where the ptr *points to*, so we get one. let place = self.ref_to_mplace(val)?; @@ -622,7 +661,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for MiriEvalContext<'a, 'mir, 'tcx> { }; // Reborrow. - let new_ptr = self.reborrow(place, size, new_bor)?; + let new_ptr = self.reborrow(place, size, fn_barrier, new_bor)?; // Return new ptr let new_place = MemPlace { ptr: Scalar::Ptr(new_ptr), ..*place }; @@ -631,11 +670,9 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for MiriEvalContext<'a, 'mir, 'tcx> { fn retag( &mut self, - _fn_entry: bool, + fn_entry: bool, place: PlaceTy<'tcx, Borrow> ) -> EvalResult<'tcx> { - // TODO: Honor `fn_entry`. - // We need a visitor to visit all references. However, that requires // a `MemPlace`, so we have a fast path for reference types that // avoids allocating. @@ -648,18 +685,19 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for MiriEvalContext<'a, 'mir, 'tcx> { } { // fast path let val = self.read_immediate(self.place_to_op(place)?)?; - let val = self.retag_reference(val, mutbl)?; + let val = self.retag_reference(val, mutbl, fn_entry)?; self.write_immediate(val, place)?; return Ok(()); } let place = self.force_allocation(place)?; - let mut visitor = RetagVisitor { ecx: self }; + let mut visitor = RetagVisitor { ecx: self, fn_entry }; visitor.visit_value(place)?; // The actual visitor struct RetagVisitor<'ecx, 'a, 'mir, 'tcx> { ecx: &'ecx mut MiriEvalContext<'a, 'mir, 'tcx>, + fn_entry: bool, } impl<'ecx, 'a, 'mir, 'tcx> MutValueVisitor<'a, 'mir, 'tcx, Evaluator<'tcx>> @@ -684,7 +722,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for MiriEvalContext<'a, 'mir, 'tcx> { _ => return Ok(()), // nothing to do }; let val = self.ecx.read_immediate(place.into())?; - let val = self.ecx.retag_reference(val, mutbl)?; + let val = self.ecx.retag_reference(val, mutbl, self.fn_entry)?; self.ecx.write_immediate(val, place.into())?; Ok(()) } diff --git a/tests/compile-fail-fullmir/stacked_borrows/aliasing_mut1.rs b/tests/compile-fail-fullmir/stacked_borrows/aliasing_mut1.rs index e812e13e702ca..b82901985b781 100644 --- a/tests/compile-fail-fullmir/stacked_borrows/aliasing_mut1.rs +++ b/tests/compile-fail-fullmir/stacked_borrows/aliasing_mut1.rs @@ -1,12 +1,17 @@ -// ignore-test validation_op is disabled - #![allow(unused_variables)] -mod safe { - pub fn safe(x: &mut i32, y: &mut i32) {} //~ ERROR: in conflict with lock WriteLock -} +use std::mem; + +pub fn safe(x: &mut i32, y: &mut i32) {} //~ ERROR barrier fn main() { - let x = &mut 0 as *mut _; - unsafe { safe::safe(&mut *x, &mut *x) }; + let mut x = 0; + let xraw: *mut i32 = unsafe { mem::transmute(&mut x) }; + // We need to apply some tricky to be able to call `safe` with two mutable references + // with the same tag: We transmute both the fn ptr (to take raw ptrs) and the argument + // (to be raw, but still have the unique tag). + let safe_raw: fn(x: *mut i32, y: *mut i32) = unsafe { + mem::transmute::(safe) + }; + safe_raw(xraw, xraw); } diff --git a/tests/compile-fail-fullmir/stacked_borrows/aliasing_mut2.rs b/tests/compile-fail-fullmir/stacked_borrows/aliasing_mut2.rs index 36ebcc2b4ac6f..69caddfa8c389 100644 --- a/tests/compile-fail-fullmir/stacked_borrows/aliasing_mut2.rs +++ b/tests/compile-fail-fullmir/stacked_borrows/aliasing_mut2.rs @@ -1,12 +1,17 @@ -// ignore-test validation_op is disabled - #![allow(unused_variables)] -mod safe { - pub fn safe(x: &i32, y: &mut i32) {} //~ ERROR: in conflict with lock ReadLock -} +use std::mem; + +pub fn safe(x: &i32, y: &mut i32) {} //~ ERROR barrier fn main() { - let x = &mut 0 as *mut _; - unsafe { safe::safe(&*x, &mut *x) }; + let mut x = 0; + let xref = &mut x; + let xraw: *mut i32 = unsafe { mem::transmute_copy(&xref) }; + let xshr = &*xref; + // transmute fn ptr around so that we can avoid retagging + let safe_raw: fn(x: *const i32, y: *mut i32) = unsafe { + mem::transmute::(safe) + }; + safe_raw(xshr, xraw); } diff --git a/tests/compile-fail-fullmir/stacked_borrows/aliasing_mut3.rs b/tests/compile-fail-fullmir/stacked_borrows/aliasing_mut3.rs index ad50fbd61b451..d37f9e63f60d9 100644 --- a/tests/compile-fail-fullmir/stacked_borrows/aliasing_mut3.rs +++ b/tests/compile-fail-fullmir/stacked_borrows/aliasing_mut3.rs @@ -1,12 +1,17 @@ -// ignore-test validation_op is disabled - #![allow(unused_variables)] -mod safe { - pub fn safe(x: &mut i32, y: &i32) {} //~ ERROR: in conflict with lock WriteLock -} +use std::mem; + +pub fn safe(x: &mut i32, y: &i32) {} //~ ERROR does not exist on the stack fn main() { - let x = &mut 0 as *mut _; - unsafe { safe::safe(&mut *x, &*x) }; + let mut x = 0; + let xref = &mut x; + let xraw: *mut i32 = unsafe { mem::transmute_copy(&xref) }; + let xshr = &*xref; + // transmute fn ptr around so that we can avoid retagging + let safe_raw: fn(x: *mut i32, y: *const i32) = unsafe { + mem::transmute::(safe) + }; + safe_raw(xraw, xshr); } diff --git a/tests/compile-fail-fullmir/stacked_borrows/aliasing_mut4.rs b/tests/compile-fail-fullmir/stacked_borrows/aliasing_mut4.rs index a0f0a3cf9753a..bf65d6e230358 100644 --- a/tests/compile-fail-fullmir/stacked_borrows/aliasing_mut4.rs +++ b/tests/compile-fail-fullmir/stacked_borrows/aliasing_mut4.rs @@ -1,15 +1,19 @@ -// ignore-test validation_op is disabled - #![allow(unused_variables)] -mod safe { - use std::cell::Cell; +use std::mem; +use std::cell::Cell; - // Make sure &mut UnsafeCell also has a lock to it - pub fn safe(x: &mut Cell, y: &i32) {} //~ ERROR: in conflict with lock WriteLock -} +// Make sure &mut UnsafeCell also is exclusive +pub fn safe(x: &i32, y: &mut Cell) {} //~ ERROR barrier fn main() { - let x = &mut 0 as *mut _; - unsafe { safe::safe(&mut *(x as *mut _), &*x) }; + let mut x = 0; + let xref = &mut x; + let xraw: *mut i32 = unsafe { mem::transmute_copy(&xref) }; + let xshr = &*xref; + // transmute fn ptr around so that we can avoid retagging + let safe_raw: fn(x: *const i32, y: *mut Cell) = unsafe { + mem::transmute::), _>(safe) + }; + safe_raw(xshr, xraw as *mut _); } diff --git a/tests/compile-fail-fullmir/stacked_borrows/box_exclusive_violation1.rs b/tests/compile-fail-fullmir/stacked_borrows/box_exclusive_violation1.rs index bd0fec859d8f7..e8a182779adec 100644 --- a/tests/compile-fail-fullmir/stacked_borrows/box_exclusive_violation1.rs +++ b/tests/compile-fail-fullmir/stacked_borrows/box_exclusive_violation1.rs @@ -8,7 +8,7 @@ fn demo_mut_advanced_unique(mut our: Box) -> i32 { unknown_code_2(); // We know this will return 5 - *our //~ ERROR does not exist on the stack + *our } // Now comes the evil context @@ -21,7 +21,7 @@ fn unknown_code_1(x: &i32) { unsafe { } } fn unknown_code_2() { unsafe { - *LEAK = 7; + *LEAK = 7; //~ ERROR barrier } } fn main() { diff --git a/tests/compile-fail-fullmir/stacked_borrows/illegal_write1.rs b/tests/compile-fail-fullmir/stacked_borrows/illegal_write1.rs index b106cc8dc403c..d0a23cb44489a 100644 --- a/tests/compile-fail-fullmir/stacked_borrows/illegal_write1.rs +++ b/tests/compile-fail-fullmir/stacked_borrows/illegal_write1.rs @@ -1,12 +1,9 @@ -fn evil(x: &u32) { - // mutating shared ref without `UnsafeCell` - let x : *mut u32 = x as *const _ as *mut _; - unsafe { *x = 42; } -} - fn main() { let target = Box::new(42); // has an implicit raw - let ref_ = &*target; - evil(ref_); // invalidates shared ref, activates raw - let _x = *ref_; //~ ERROR is not frozen + let xref = &*target; + { + let x : *mut u32 = xref as *const _ as *mut _; + unsafe { *x = 42; } // invalidates shared ref, activates raw + } + let _x = *xref; //~ ERROR is not frozen } diff --git a/tests/compile-fail-fullmir/stacked_borrows/invalidate_against_barrier1.rs b/tests/compile-fail-fullmir/stacked_borrows/invalidate_against_barrier1.rs new file mode 100644 index 0000000000000..fc0dbb9e13133 --- /dev/null +++ b/tests/compile-fail-fullmir/stacked_borrows/invalidate_against_barrier1.rs @@ -0,0 +1,13 @@ +fn inner(x: *mut i32, _y: &mut i32) { + // If `x` and `y` alias, retagging is fine with this... but we really + // shouldn't be allowed to use `x` at all because `y` was assumed to be + // unique for the duration of this call. + let _val = unsafe { *x }; //~ ERROR barrier +} + +fn main() { + let mut x = 0; + let xraw = &mut x as *mut _; + let xref = unsafe { &mut *xraw }; + inner(xraw, xref); +} diff --git a/tests/compile-fail-fullmir/stacked_borrows/invalidate_against_barrier2.rs b/tests/compile-fail-fullmir/stacked_borrows/invalidate_against_barrier2.rs new file mode 100644 index 0000000000000..a080c0958e400 --- /dev/null +++ b/tests/compile-fail-fullmir/stacked_borrows/invalidate_against_barrier2.rs @@ -0,0 +1,13 @@ +fn inner(x: *mut i32, _y: &i32) { + // If `x` and `y` alias, retagging is fine with this... but we really + // shouldn't be allowed to write to `x` at all because `y` was assumed to be + // immutable for the duration of this call. + unsafe { *x = 0 }; //~ ERROR barrier +} + +fn main() { + let mut x = 0; + let xraw = &mut x as *mut _; + let xref = unsafe { &*xraw }; + inner(xraw, xref); +} diff --git a/tests/compile-fail-fullmir/stacked_borrows/mut_exclusive_violation1.rs b/tests/compile-fail-fullmir/stacked_borrows/mut_exclusive_violation1.rs index fec699e35bcfb..3fe6b6567423c 100644 --- a/tests/compile-fail-fullmir/stacked_borrows/mut_exclusive_violation1.rs +++ b/tests/compile-fail-fullmir/stacked_borrows/mut_exclusive_violation1.rs @@ -21,7 +21,7 @@ fn unknown_code_1(x: &i32) { unsafe { } } fn unknown_code_2() { unsafe { - *LEAK = 7; //~ ERROR does not exist on the stack + *LEAK = 7; //~ ERROR barrier } } fn main() { From 58309956c10914d55171666abd1782063e921d18 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 21 Nov 2018 13:43:55 +0100 Subject: [PATCH 0431/3747] for now, we allow Undef in raw pointers as we do in integers --- tests/compile-fail/validity/undef.rs | 12 ------------ 1 file changed, 12 deletions(-) delete mode 100644 tests/compile-fail/validity/undef.rs diff --git a/tests/compile-fail/validity/undef.rs b/tests/compile-fail/validity/undef.rs deleted file mode 100644 index f86fef9454e82..0000000000000 --- a/tests/compile-fail/validity/undef.rs +++ /dev/null @@ -1,12 +0,0 @@ -#![allow(unused_variables)] -// error-pattern: encountered undefined address in pointer - -use std::mem; - -fn make_raw() -> *const f32 { - unsafe { mem::uninitialized() } -} - -fn main() { - let _x = make_raw(); -} From 194710e112ef5cc7bd9f8a7f5924c4574eca0406 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 21 Nov 2018 15:21:41 +0100 Subject: [PATCH 0432/3747] no barriers for boxes --- src/stacked_borrows.rs | 37 +++++++++++-------- .../box_exclusive_violation1.rs | 4 +- 2 files changed, 23 insertions(+), 18 deletions(-) diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 6b851cd65b5ee..a31fd462e526c 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -673,19 +673,27 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for MiriEvalContext<'a, 'mir, 'tcx> { fn_entry: bool, place: PlaceTy<'tcx, Borrow> ) -> EvalResult<'tcx> { + // Determine mutability and whether to add a barrier. + // Cannot use `builtin_deref` because that reports *immutable* for `Box`, + // making it useless. + fn qualify(ty: ty::Ty<'_>, fn_entry: bool) -> Option<(Mutability, bool)> { + match ty.sty { + // References are simple + ty::Ref(_, _, mutbl) => Some((mutbl, fn_entry)), + // Boxes do not get a barrier: Barriers reflect that references outlive the call + // they were passed in to; that's just not the case for boxes. + ty::Adt(..) if ty.is_box() => Some((MutMutable, false)), + _ => None, + } + } + // We need a visitor to visit all references. However, that requires // a `MemPlace`, so we have a fast path for reference types that // avoids allocating. - // Cannot use `builtin_deref` because that reports *immutable* for `Box`, - // making it useless. - if let Some(mutbl) = match place.layout.ty.sty { - ty::Ref(_, _, mutbl) => Some(mutbl), - ty::Adt(..) if place.layout.ty.is_box() => Some(MutMutable), - _ => None, // handled with the general case below - } { + if let Some((mutbl, barrier)) = qualify(place.layout.ty, fn_entry) { // fast path let val = self.read_immediate(self.place_to_op(place)?)?; - let val = self.retag_reference(val, mutbl, fn_entry)?; + let val = self.retag_reference(val, mutbl, barrier)?; self.write_immediate(val, place)?; return Ok(()); } @@ -716,14 +724,11 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for MiriEvalContext<'a, 'mir, 'tcx> { { // Cannot use `builtin_deref` because that reports *immutable* for `Box`, // making it useless. - let mutbl = match place.layout.ty.sty { - ty::Ref(_, _, mutbl) => mutbl, - ty::Adt(..) if place.layout.ty.is_box() => MutMutable, - _ => return Ok(()), // nothing to do - }; - let val = self.ecx.read_immediate(place.into())?; - let val = self.ecx.retag_reference(val, mutbl, self.fn_entry)?; - self.ecx.write_immediate(val, place.into())?; + if let Some((mutbl, barrier)) = qualify(place.layout.ty, self.fn_entry) { + let val = self.ecx.read_immediate(place.into())?; + let val = self.ecx.retag_reference(val, mutbl, barrier)?; + self.ecx.write_immediate(val, place.into())?; + } Ok(()) } } diff --git a/tests/compile-fail-fullmir/stacked_borrows/box_exclusive_violation1.rs b/tests/compile-fail-fullmir/stacked_borrows/box_exclusive_violation1.rs index e8a182779adec..bd0fec859d8f7 100644 --- a/tests/compile-fail-fullmir/stacked_borrows/box_exclusive_violation1.rs +++ b/tests/compile-fail-fullmir/stacked_borrows/box_exclusive_violation1.rs @@ -8,7 +8,7 @@ fn demo_mut_advanced_unique(mut our: Box) -> i32 { unknown_code_2(); // We know this will return 5 - *our + *our //~ ERROR does not exist on the stack } // Now comes the evil context @@ -21,7 +21,7 @@ fn unknown_code_1(x: &i32) { unsafe { } } fn unknown_code_2() { unsafe { - *LEAK = 7; //~ ERROR barrier + *LEAK = 7; } } fn main() { From 97e010f5b97f767f4eceadd3d4ea9556052e8393 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 21 Nov 2018 15:25:47 +0100 Subject: [PATCH 0433/3747] barriers prevent deallocation --- src/stacked_borrows.rs | 82 +++++++++++++------ .../deallocate_against_barrier.rs | 13 +++ 2 files changed, 70 insertions(+), 25 deletions(-) create mode 100644 tests/compile-fail-fullmir/stacked_borrows/deallocate_against_barrier.rs diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index a31fd462e526c..e06943f2ba069 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -90,6 +90,14 @@ pub enum RefKind { Raw, } +/// What kind of access is being performed? +#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] +pub enum AccessKind { + Read, + Write, + Dealloc, +} + /// Extra global state in the memory, available to the memory access hooks #[derive(Debug)] pub struct BarrierTracking { @@ -221,13 +229,13 @@ impl<'tcx> Stack { fn access( &mut self, bor: Borrow, - is_write: bool, + kind: AccessKind, barrier_tracking: &BarrierTracking, ) -> EvalResult<'tcx> { // Check if we can match the frozen "item". // Not possible on writes! if self.is_frozen() { - if !is_write { + if kind == AccessKind::Read { // When we are frozen, we just accept all reads. No harm in this. // The deref already checked that `Uniq` items are in the stack, and that // the location is frozen if it should be. @@ -247,26 +255,41 @@ impl<'tcx> Stack { ))) } (BorStackItem::Uniq(itm_t), Borrow::Uniq(bor_t)) if itm_t == bor_t => { - // Found matching unique item. - return Ok(()) + // Found matching unique item. Continue after the match. } - (BorStackItem::Shr, _) if !is_write => { + (BorStackItem::Shr, _) if kind == AccessKind::Read => { // When reading, everything can use a shared item! // We do not want to do this when writing: Writing to an `&mut` // should reaffirm its exclusivity (i.e., make sure it is - // on top of the stack). - return Ok(()) + // on top of the stack). Continue after the match. } (BorStackItem::Shr, Borrow::Shr(_)) => { - // Found matching shared item. - return Ok(()) + // Found matching shared item. Continue after the match. } _ => { - // Pop this. This ensures U2. + // Pop this, go on. This ensures U2. let itm = self.borrows.pop().unwrap(); trace!("access: Popping {:?}", itm); + continue + } + } + // If we got here, we found a matching item. Congratulations! + // However, we are not done yet: If this access is deallocating, we must make sure + // there are no active barriers remaining on the stack. + if kind == AccessKind::Dealloc { + for &itm in self.borrows.iter().rev() { + match itm { + BorStackItem::FnBarrier(call) if barrier_tracking.is_active(call) => { + return err!(MachineError(format!( + "Deallocating with active barrier ({})", call + ))) + } + _ => {}, + } } } + // NOW we are done. + return Ok(()) } // If we got here, we did not find our item. err!(MachineError(format!( @@ -352,18 +375,16 @@ impl<'tcx> Stacks { &self, ptr: Pointer, size: Size, - is_write: bool, - barrier_tracking: &BarrierTracking, + kind: AccessKind, ) -> EvalResult<'tcx> { - trace!("{} access of tag {:?}: {:?}, size {}", - if is_write { "read" } else { "write" }, - ptr.tag, ptr, size.bytes()); + trace!("{:?} access of tag {:?}: {:?}, size {}", kind, ptr.tag, ptr, size.bytes()); // Even reads can have a side-effect, by invalidating other references. // This is fundamentally necessary since `&mut` asserts that there // are no accesses through other references, not even reads. + let barrier_tracking = self.barrier_tracking.borrow(); let mut stacks = self.stacks.borrow_mut(); for stack in stacks.iter_mut(ptr.offset, size) { - stack.access(ptr.tag, is_write, barrier_tracking)?; + stack.access(ptr.tag, kind, &*barrier_tracking)?; } Ok(()) } @@ -377,7 +398,6 @@ impl<'tcx> Stacks { mut barrier: Option, new_bor: Borrow, new_kind: RefKind, - barrier_tracking: &BarrierTracking, ) -> EvalResult<'tcx> { assert_eq!(new_bor.is_unique(), new_kind == RefKind::Unique); trace!("reborrow for tag {:?} to {:?} as {:?}: {:?}, size {}", @@ -385,8 +405,17 @@ impl<'tcx> Stacks { if new_kind == RefKind::Raw { // No barrier for raw, including `&UnsafeCell`. They can rightfully // alias with `&mut`. + // FIXME: This means that the `dereferencable` attribute on non-frozen shared + // references is incorrect! They are dereferencable when the function is + // called, but might become non-dereferencable during the coruse of execution. + // Also see [1], [2]. + // + // [1]: , + // [2]: barrier = None; } + let barrier_tracking = self.barrier_tracking.borrow(); let mut stacks = self.stacks.borrow_mut(); for stack in stacks.iter_mut(ptr.offset, size) { // Access source `ptr`, create new ref. @@ -410,7 +439,12 @@ impl<'tcx> Stacks { continue; } // We need to do some actual work. - stack.access(ptr.tag, new_kind == RefKind::Unique, barrier_tracking)?; + let access_kind = if new_kind == RefKind::Unique { + AccessKind::Write + } else { + AccessKind::Read + }; + stack.access(ptr.tag, access_kind, &*barrier_tracking)?; if let Some(call) = barrier { stack.barrier(call); } @@ -440,7 +474,7 @@ impl AllocationExtra for Stacks { ptr: Pointer, size: Size, ) -> EvalResult<'tcx> { - alloc.extra.access(ptr, size, /*is_write*/false, &*alloc.extra.barrier_tracking.borrow()) + alloc.extra.access(ptr, size, AccessKind::Read) } #[inline(always)] @@ -449,7 +483,7 @@ impl AllocationExtra for Stacks { ptr: Pointer, size: Size, ) -> EvalResult<'tcx> { - alloc.extra.access(ptr, size, /*is_write*/true, &*alloc.extra.barrier_tracking.borrow()) + alloc.extra.access(ptr, size, AccessKind::Write) } #[inline(always)] @@ -458,9 +492,7 @@ impl AllocationExtra for Stacks { ptr: Pointer, size: Size, ) -> EvalResult<'tcx> { - // This is like mutating - alloc.extra.access(ptr, size, /*is_write*/true, &*alloc.extra.barrier_tracking.borrow()) - // FIXME: Error out of there are any barriers? + alloc.extra.access(ptr, size, AccessKind::Dealloc) } } @@ -627,12 +659,12 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for MiriEvalContext<'a, 'mir, 'tcx> { // Reference that cares about freezing. We need a frozen-sensitive reborrow. self.visit_freeze_sensitive(place, size, |cur_ptr, size, frozen| { let kind = if frozen { RefKind::Frozen } else { RefKind::Raw }; - alloc.extra.reborrow(cur_ptr, size, barrier, new_bor, kind, &*self.memory().extra.borrow()) + alloc.extra.reborrow(cur_ptr, size, barrier, new_bor, kind) })?; } else { // Just treat this as one big chunk. let kind = if new_bor.is_unique() { RefKind::Unique } else { RefKind::Raw }; - alloc.extra.reborrow(ptr, size, barrier, new_bor, kind, &*self.memory().extra.borrow())?; + alloc.extra.reborrow(ptr, size, barrier, new_bor, kind)?; } Ok(new_ptr) } diff --git a/tests/compile-fail-fullmir/stacked_borrows/deallocate_against_barrier.rs b/tests/compile-fail-fullmir/stacked_borrows/deallocate_against_barrier.rs new file mode 100644 index 0000000000000..eb988a5899593 --- /dev/null +++ b/tests/compile-fail-fullmir/stacked_borrows/deallocate_against_barrier.rs @@ -0,0 +1,13 @@ +// error-pattern: Deallocating with active barrier + +fn inner(x: &mut i32, f: fn(&mut i32)) { + // `f` may mutate, but it may not deallocate! + f(x) +} + +fn main() { + inner(Box::leak(Box::new(0)), |x| { + let raw = x as *mut _; + drop(unsafe { Box::from_raw(raw) }); + }); +} From edc2fb5f60232ddd629986accc553acf75ab78de Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Tue, 27 Nov 2018 14:41:53 +0100 Subject: [PATCH 0434/3747] Expose some internals for priroda --- src/lib.rs | 12 ++++++------ src/mono_hash_map.rs | 6 ++++++ 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 10a1405b2a628..1625223ecd45f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -37,15 +37,15 @@ mod range_map; mod mono_hash_map; mod stacked_borrows; -use crate::fn_call::EvalContextExt as MissingFnsEvalContextExt; -use crate::operator::EvalContextExt as OperatorEvalContextExt; -use crate::intrinsic::EvalContextExt as IntrinsicEvalContextExt; -use crate::tls::{EvalContextExt as TlsEvalContextExt, TlsData}; +pub use crate::fn_call::EvalContextExt as MissingFnsEvalContextExt; +pub use crate::operator::EvalContextExt as OperatorEvalContextExt; +pub use crate::intrinsic::EvalContextExt as IntrinsicEvalContextExt; +pub use crate::tls::{EvalContextExt as TlsEvalContextExt, TlsData}; use crate::range_map::RangeMap; #[allow(unused_imports)] // FIXME rustc bug https://github.com/rust-lang/rust/issues/53682 -use crate::helpers::{ScalarExt, EvalContextExt as HelpersEvalContextExt}; +pub use crate::helpers::{ScalarExt, EvalContextExt as HelpersEvalContextExt}; use crate::mono_hash_map::MonoHashMap; -use crate::stacked_borrows::{EvalContextExt as StackedBorEvalContextExt}; +pub use crate::stacked_borrows::{EvalContextExt as StackedBorEvalContextExt}; // Used by priroda pub use crate::stacked_borrows::{Borrow, Stack, Stacks, BorStackItem}; diff --git a/src/mono_hash_map.rs b/src/mono_hash_map.rs index e30578a5a77b9..42ac42544f00b 100644 --- a/src/mono_hash_map.rs +++ b/src/mono_hash_map.rs @@ -17,6 +17,12 @@ use crate::AllocMap; #[derive(Debug, Clone)] pub struct MonoHashMap(RefCell>>); +impl MonoHashMap { + pub fn values(&self, f: impl FnOnce(&mut Iterator) -> T) -> T { + f(&mut self.0.borrow().values().map(|v| &**v)) + } +} + impl Default for MonoHashMap { fn default() -> Self { MonoHashMap(RefCell::new(Default::default())) From b72398de74161c0228d61501680ab653b9019b55 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 27 Nov 2018 14:48:46 +0100 Subject: [PATCH 0435/3747] fix README install instructions --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d6e0be40cacf4..dcf13a8af4a28 100644 --- a/README.md +++ b/README.md @@ -56,7 +56,7 @@ compiled the right way. Install Miri as a cargo subcommand: ```sh -cargo +nightly install --git https://github.com/solson/miri/ +cargo +nightly install --git https://github.com/solson/miri/ miri ``` Be aware that if you used `rustup override set` to fix a particular Rust version From 5958fa6a7049cd003e87d6d8502ae1237262c378 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Tue, 27 Nov 2018 16:20:15 +0100 Subject: [PATCH 0436/3747] Use explicit `dyn` trait object --- src/mono_hash_map.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mono_hash_map.rs b/src/mono_hash_map.rs index 42ac42544f00b..278bbd9cf2b13 100644 --- a/src/mono_hash_map.rs +++ b/src/mono_hash_map.rs @@ -18,7 +18,7 @@ use crate::AllocMap; pub struct MonoHashMap(RefCell>>); impl MonoHashMap { - pub fn values(&self, f: impl FnOnce(&mut Iterator) -> T) -> T { + pub fn values(&self, f: impl FnOnce(&mut dyn Iterator) -> T) -> T { f(&mut self.0.borrow().values().map(|v| &**v)) } } From 26fe778c55ef562e88bb59fd4d43adc1b7885e24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oliver=20S=CC=B6c=CC=B6h=CC=B6n=CC=B6e=CC=B6i=CC=B6d=CC=B6?= =?UTF-8?q?e=CC=B6r=20Scherer?= Date: Wed, 28 Nov 2018 09:58:23 +0100 Subject: [PATCH 0437/3747] Typo Co-Authored-By: RalfJung --- src/stacked_borrows.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index e06943f2ba069..31f80fe2f6c68 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -407,7 +407,7 @@ impl<'tcx> Stacks { // alias with `&mut`. // FIXME: This means that the `dereferencable` attribute on non-frozen shared // references is incorrect! They are dereferencable when the function is - // called, but might become non-dereferencable during the coruse of execution. + // called, but might become non-dereferencable during the course of execution. // Also see [1], [2]. // // [1]: Date: Wed, 28 Nov 2018 16:14:41 +0100 Subject: [PATCH 0438/3747] bump Rust version --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 0268b07ac411a..826965c66dea6 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -nightly-2018-11-26 +nightly-2018-11-28 From fb72348e5f4bd396d91c808b1e404f233908fb05 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 28 Nov 2018 19:02:56 +0100 Subject: [PATCH 0439/3747] disable async-fn, for now --- tests/run-pass-fullmir/async-fn.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/run-pass-fullmir/async-fn.rs b/tests/run-pass-fullmir/async-fn.rs index 7c32b026df67b..56e6031ceb5ae 100644 --- a/tests/run-pass-fullmir/async-fn.rs +++ b/tests/run-pass-fullmir/async-fn.rs @@ -1,3 +1,6 @@ +// FIXME: investigate why this fails since barriers have been added +// compile-flags: -Zmiri-disable-validation + #![feature( async_await, await_macro, From 42e73b5536ff01c4ba846197fc18b5e051ba8515 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 29 Nov 2018 17:29:00 +0100 Subject: [PATCH 0440/3747] async fn got fixed --- tests/run-pass-fullmir/async-fn.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/tests/run-pass-fullmir/async-fn.rs b/tests/run-pass-fullmir/async-fn.rs index 56e6031ceb5ae..7c32b026df67b 100644 --- a/tests/run-pass-fullmir/async-fn.rs +++ b/tests/run-pass-fullmir/async-fn.rs @@ -1,6 +1,3 @@ -// FIXME: investigate why this fails since barriers have been added -// compile-flags: -Zmiri-disable-validation - #![feature( async_await, await_macro, From 3999db1159f06672c25ba661b3a5e4de26f5b58e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 30 Nov 2018 07:26:20 +0100 Subject: [PATCH 0441/3747] new nightly, new luck --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 826965c66dea6..6fd720c5c785d 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -nightly-2018-11-28 +nightly-2018-11-30 From 86e6470a12cc4afc00d2446a6ba0270de95f120c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 30 Nov 2018 09:23:44 +0100 Subject: [PATCH 0442/3747] update README to first describe the usual user setup, and to always set up a proper libstd --- README.md | 150 ++++++++++++++++++++++-------------------- src/bin/cargo-miri.rs | 7 +- 2 files changed, 84 insertions(+), 73 deletions(-) diff --git a/README.md b/README.md index dcf13a8af4a28..f232cf25f9fe2 100644 --- a/README.md +++ b/README.md @@ -20,36 +20,6 @@ for example: [`unreachable_unchecked`]: https://doc.rust-lang.org/stable/std/hint/fn.unreachable_unchecked.html [`copy_nonoverlapping`]: https://doc.rust-lang.org/stable/std/ptr/fn.copy_nonoverlapping.html -## Building Miri - -We recommend that you install [rustup] to obtain Rust. Then all you have -to do is: - -```sh -cargo +nightly build -``` - -This uses the very latest Rust version. If you experience any problem, refer to -the `rust-version` file which contains a particular Rust nightly version that -has been tested against the version of miri you are using. Make sure to use -that particular `nightly-YYYY-MM-DD` whenever the instructions just say -`nightly`. - -To avoid repeating the nightly version all the time, you can use -`rustup override set nightly` (or `rustup override set nightly-YYYY-MM-DD`), -which means `nightly` Rust will automatically be used whenever you are working -in this directory. - -[rustup]: https://www.rustup.rs - -## Running Miri on tiny examples - -```sh -cargo +nightly run -- -Zmiri-disable-validation tests/run-pass/vecs.rs # Or whatever test you like. -``` - -We have to disable validation because that can lead to errors when libstd is not -compiled the right way. ## Running Miri on your own project('s test suite) @@ -59,13 +29,17 @@ Install Miri as a cargo subcommand: cargo +nightly install --git https://github.com/solson/miri/ miri ``` -Be aware that if you used `rustup override set` to fix a particular Rust version -for the miri directory, that will *not* apply to your own project directory! -You have to use a consistent Rust version for building miri and your project for -this to work, so remember to either always specify the nightly version manually, -overriding it in your project directory as well, or use `rustup default nightly` -(or `rustup default nightly-YYYY-MM-DD`) to globally make `nightly` the default -toolchain. +If this does not work, try using the nightly version given in +[this file](https://raw.githubusercontent.com/solson/miri/master/rust-version). CI +should ensure that this nightly always works. + +You have to use a consistent Rust version for building miri and your project, so +remember to either always specify the nightly version manually (like in the +example above), overriding it in your project directory as well, or use `rustup +default nightly` (or `rustup default nightly-YYYY-MM-DD`) to globally make +`nightly` the default toolchain. + +Now you can run your project in miri: 1. Run `cargo clean` to eliminate any cached dependencies. Miri needs your dependencies to be compiled the right way, that would not happen if they have @@ -93,53 +67,79 @@ You may be running `cargo miri` with a different compiler version than the one used to build the custom libstd that Miri uses, and Miri failed to detect that. Try deleting `~/.cache/miri`. -## Miri `-Z` flags +## Development and Debugging -Several `-Z` flags are relevant for miri: +If you want to hack on miri yourself, great! Here are some resources you might +find useful. -* `-Zmir-opt-level` controls how many MIR optimizations are performed. miri - overrides the default to be `0`; be advised that using any higher level can - make miri miss bugs in your program because they got optimized away. -* `-Zalways-encode-mir` makes rustc dump MIR even for completely monomorphic - functions. This is needed so that miri can execute such functions, so miri - sets this flag per default. -* `-Zmiri-disable-validation` is a custom `-Z` flag added by miri. It disables - enforcing the validity invariant, which is enforced by default. This is - mostly useful for debugging; it means miri will miss bugs in your program. +### Using a nightly rustc -## Development and Debugging +miri heavily relies on internal rustc interfaces to execute MIR. Still, some +things (like adding support for a new intrinsic) can be done by working just on +the miri side. + +To prepare, make sure you are using a nightly Rust compiler. You also need to +set up a libstd that enables execution with miri: + +```sh +rustup override set nightly # or the nightly in `rust-version` +cargo run --bin cargo-miri -- miri setup +``` + +The last command should end in printing the directory where the libstd was +built. Set that as your MIRI_SYSROOT environment variable: + +```sh +export MIRI_SYSROOT=~/.cache/miri/HOST # or whatever the previous command said +``` + +### Testing Miri + +Now you can run Miri directly, without going through `cargo miri`: + +```sh +cargo run tests/run-pass-fullmir/format.rs # or whatever test you like +``` + +You can also run the test suite with `cargo test --release`. `cargo test +--release FILTER` only runs those tests that contain `FILTER` in their filename +(including the base directory, e.g. `cargo test --release fail` will run all +compile-fail tests). We recommend using `--release` to make test running take +less time. + +Now you are set up! You can write a failing test case, and tweak miri until it +fails no more. + +### Using a locally built rustc Since the heart of Miri (the main interpreter engine) lives in rustc, working on -Miri will often require using a locally built rustc. This includes getting a -trace of the execution, as distributed rustc has `debug!` and `trace!` disabled. +Miri will often require using a locally built rustc. The bug you want to fix +may actually be on the rustc side, or you just need to get more detailed trace +of the execution -- in both cases, you should develop miri against a rustc you +compiled yourself, with debug assertions (and hence tracing) enabled. -The first-time setup for a local rustc looks as follows: +The setup for a local rustc works as follows: ```sh git clone https://github.com/rust-lang/rust/ rustc cd rustc cp config.toml.example config.toml # Now edit `config.toml` and set `debug-assertions = true` and `test-miri = true`. # The latter is important to build libstd with the right flags for miri. +# This step can take 30 minutes and more. ./x.py build src/rustc +# If you change something, you can get a faster rebuild by doing +./x.py --keep-stage 0 build src/rustc # You may have to change the architecture in the next command rustup toolchain link custom build/x86_64-unknown-linux-gnu/stage2 -# Now cd to your Miri directory +# Now cd to your Miri directory, then configure rustup rustup override set custom +# We also need to tell Miri where to find its sysroot. Since we set +# `test-miri` above, we can just use rustc' sysroot. +export MIRI_SYSROOT=$(rustc --print sysroot) ``` -The `build` step can take 30 minutes and more. -Now you can `cargo build` Miri, and you can `cargo test --release` it. `cargo -test --release FILTER` only runs those tests that contain `FILTER` in their -filename (including the base directory, e.g. `cargo test --release fail` will -run all compile-fail tests). We recommend using `--release` to make test -running take less time. - -Notice that the "fullmir" tests only run if you have `MIRI_SYSROOT` set, the -test runner does not realized that your libstd comes with full MIR. The -following will set it correctly: -```sh -MIRI_SYSROOT=$(rustc --print sysroot) cargo test --release -``` +With this, you should now have a working development setup! See "Testing Miri" +above for how to proceed. Moreover, you can now run Miri with a trace of all execution steps: ```sh @@ -157,11 +157,19 @@ MIRI_LOG=rustc_mir::interpret=debug,miri::stacked_borrows cargo run tests/run-pa In addition, you can set `MIRI_BACKTRACE=1` to get a backtrace of where an evaluation error was originally created. -If you changed something in rustc and want to re-build, run -``` -./x.py --keep-stage 0 build src/rustc -``` -This avoids rebuilding the entire stage 0, which can save a lot of time. +### Miri `-Z` flags + +Several `-Z` flags are relevant for miri: + +* `-Zmir-opt-level` controls how many MIR optimizations are performed. miri + overrides the default to be `0`; be advised that using any higher level can + make miri miss bugs in your program because they got optimized away. +* `-Zalways-encode-mir` makes rustc dump MIR even for completely monomorphic + functions. This is needed so that miri can execute such functions, so miri + sets this flag per default. +* `-Zmiri-disable-validation` is a custom `-Z` flag added by miri. It disables + enforcing the validity invariant, which is enforced by default. This is + mostly useful for debugging; it means miri will miss bugs in your program. ## Contributing and getting help diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index ed4ffa43dbce3..70e75eec649ce 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -149,7 +149,6 @@ fn setup(ask_user: bool) { let dirs = directories::ProjectDirs::from("miri", "miri", "miri").unwrap(); let dir = dirs.cache_dir(); if !dir.exists() { - println!("Creating `{}` and using it for miri's build of libstd", dir.display()); fs::create_dir_all(&dir).unwrap(); } // The interesting bit: Xargo.toml @@ -184,7 +183,11 @@ path = "lib.rs" } // That should be it! - std::env::set_var("MIRI_SYSROOT", dir.join("HOST")); + let sysroot = dir.join("HOST"); + std::env::set_var("MIRI_SYSROOT", &sysroot); + if !ask_user { + println!("A libstd for miri is now available in `{}`", sysroot.display()); + } } fn main() { From 5032560eaa68b5e6a16c67e42d8b22b10612bc22 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 30 Nov 2018 09:31:09 +0100 Subject: [PATCH 0443/3747] add link within document --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index f232cf25f9fe2..c300c72628ddc 100644 --- a/README.md +++ b/README.md @@ -138,8 +138,8 @@ rustup override set custom export MIRI_SYSROOT=$(rustc --print sysroot) ``` -With this, you should now have a working development setup! See "Testing Miri" -above for how to proceed. +With this, you should now have a working development setup! See +["Testing Miri"](#testing-miri) above for how to proceed. Moreover, you can now run Miri with a trace of all execution steps: ```sh From 3478c0c1e6883c2a9385f410d01bfa2203135ca3 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 30 Nov 2018 22:23:20 +0100 Subject: [PATCH 0444/3747] update contact channels --- README.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index c300c72628ddc..5f8f8fb8502f0 100644 --- a/README.md +++ b/README.md @@ -175,8 +175,10 @@ Several `-Z` flags are relevant for miri: Check out the issues on this GitHub repository for some ideas. There's lots that needs to be done that I haven't documented in the issues yet, however. For more -ideas or help with running or hacking on Miri, you can contact me (`scott`) on -Mozilla IRC in any of the Rust IRC channels (`#rust`, `#rust-offtopic`, etc). +ideas or help with running or hacking on Miri, you can open an issue here on +GitHub or contact us (`oli-obk` and `RalfJ`) on the [Rust Zulip]. + +[Rust Zulip]: https://rust-lang.zulipchat.com ## History From dcfc2f207e40da620557ab31e0e71589a0e26552 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 2 Dec 2018 10:29:57 +0100 Subject: [PATCH 0445/3747] do not even look for cargo metadata in 'cargo miri setup' --- src/bin/cargo-miri.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 70e75eec649ce..4c83c5bd3dc0a 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -223,6 +223,10 @@ fn main() { // We always setup let ask = subcommand != MiriCommand::Setup; setup(ask); + if subcommand == MiriCommand::Setup { + // Stop here. + return; + } // Now run the command. for target in list_targets(std::env::args().skip(skip)) { From 429d84f0681f048661a7377b7acb57eeee77baef Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 2 Dec 2018 11:14:24 +0100 Subject: [PATCH 0446/3747] remove/fix outdated FIXMEs in tests --- tests/compile-fail-fullmir/stacked_borrows/illegal_write2.rs | 4 ---- .../stacked_borrows/pointer_smuggling.rs | 5 ++--- tests/compiletest.rs | 2 +- tests/run-pass/dst-struct.rs | 3 ++- tests/run-pass/sums.rs | 3 --- tests/run-pass/vec-matching-fold.rs | 2 -- 6 files changed, 5 insertions(+), 14 deletions(-) diff --git a/tests/compile-fail-fullmir/stacked_borrows/illegal_write2.rs b/tests/compile-fail-fullmir/stacked_borrows/illegal_write2.rs index b53655c82147e..f4fefaad5e22d 100644 --- a/tests/compile-fail-fullmir/stacked_borrows/illegal_write2.rs +++ b/tests/compile-fail-fullmir/stacked_borrows/illegal_write2.rs @@ -1,7 +1,3 @@ -// We fail to detect this when neither this nor libstd are optimized/have retagging. -// FIXME: Investigate that. -// compile-flags: -Zmir-opt-level=0 - #![allow(unused_variables)] fn main() { diff --git a/tests/compile-fail-fullmir/stacked_borrows/pointer_smuggling.rs b/tests/compile-fail-fullmir/stacked_borrows/pointer_smuggling.rs index 68f3d2923b15f..bd5e28b47e867 100644 --- a/tests/compile-fail-fullmir/stacked_borrows/pointer_smuggling.rs +++ b/tests/compile-fail-fullmir/stacked_borrows/pointer_smuggling.rs @@ -1,5 +1,3 @@ -#![allow(unused_variables)] - static mut PTR: *mut u8 = 0 as *mut _; fn fun1(x: &mut u8) { @@ -14,7 +12,8 @@ fn fun2() { } fn main() { - let val = &mut 0; // FIXME: This should also work with a local variable, but currently it does not. + let mut val = 0; + let val = &mut val; fun1(val); *val = 2; // this invalidates any raw ptrs `fun1` might have created. fun2(); // if they now use a raw ptr they break our reference diff --git a/tests/compiletest.rs b/tests/compiletest.rs index 7aa55ef663408..de693bd463209 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -106,7 +106,7 @@ fn miri_pass(sysroot: &Path, path: &str, target: &str, host: &str, need_fullmir: flags.push("-Zmir-opt-level=1".to_owned()); } if !have_fullmir() { - // Validation relies on the EscapeToRaw statements being emitted + // FIXME: Validation relies on the EscapeToRaw statements being emitted flags.push("-Zmiri-disable-validation".to_owned()); } diff --git a/tests/run-pass/dst-struct.rs b/tests/run-pass/dst-struct.rs index 0820614ab5c81..6ef0a6330f739 100644 --- a/tests/run-pass/dst-struct.rs +++ b/tests/run-pass/dst-struct.rs @@ -127,8 +127,9 @@ pub fn main() { let f2 : Box> = f1; foo(&*f2); - // FIXME (#22405): Replace `Box::new` with `box` here when/if possible. let f3 : Box> = Box::>::new(Fat { f1: 5, f2: "some str", ptr: [1, 2, 3] }); foo(&*f3); + let f4 : Box> = box Fat { f1: 5, f2: "some str", ptr: [1, 2, 3] }; + foo(&*f4); } diff --git a/tests/run-pass/sums.rs b/tests/run-pass/sums.rs index a8dfd5ed66ae7..daeba060a78bf 100644 --- a/tests/run-pass/sums.rs +++ b/tests/run-pass/sums.rs @@ -1,6 +1,3 @@ -// FIXME(solson): 32-bit mode doesn't test anything currently. -#![cfg_attr(target_pointer_width = "32", allow(dead_code))] - #[derive(Debug, PartialEq)] enum Unit { Unit(()) } // Force non-C-enum representation. diff --git a/tests/run-pass/vec-matching-fold.rs b/tests/run-pass/vec-matching-fold.rs index 1a30f875580c2..396846b23236e 100644 --- a/tests/run-pass/vec-matching-fold.rs +++ b/tests/run-pass/vec-matching-fold.rs @@ -22,7 +22,6 @@ fn foldl(values: &[T], &[ref head, ref tail..] => foldl(tail, function(initial, head), function), &[] => { - // FIXME: call guards let res = initial.clone(); res } } @@ -39,7 +38,6 @@ fn foldr(values: &[T], &[ref head.., ref tail] => foldr(head, function(tail, initial), function), &[] => { - // FIXME: call guards let res = initial.clone(); res } } From 36a2b8952283e1cb86f4133ebd6ea778da1a5b50 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 2 Dec 2018 11:26:09 +0100 Subject: [PATCH 0447/3747] remove a whole lot of unnecessary attributes --- .../stacked_borrows/alias_through_mutation.rs | 2 -- .../compile-fail-fullmir/stacked_borrows/aliasing_mut1.rs | 4 +--- .../compile-fail-fullmir/stacked_borrows/aliasing_mut2.rs | 4 +--- .../compile-fail-fullmir/stacked_borrows/aliasing_mut3.rs | 4 +--- .../compile-fail-fullmir/stacked_borrows/aliasing_mut4.rs | 4 +--- .../stacked_borrows/buggy_split_at_mut.rs | 2 -- .../compile-fail-fullmir/stacked_borrows/illegal_write2.rs | 2 -- tests/compile-fail/never_transmute_humans.rs | 7 +------ tests/compile-fail/never_transmute_void.rs | 2 -- tests/compile-fail/validity/transmute_through_ptr.rs | 2 -- tests/run-pass/dst-struct.rs | 2 -- tests/run-pass/issue-31267-additional.rs | 4 +--- tests/run-pass/many_shr_bor.rs | 7 +++---- tests/run-pass/move-arg-2-unique.rs | 1 - tests/run-pass/move-arg-3-unique.rs | 1 - tests/run-pass/regions-lifetime-nonfree-late-bound.rs | 1 - 16 files changed, 9 insertions(+), 40 deletions(-) diff --git a/tests/compile-fail-fullmir/stacked_borrows/alias_through_mutation.rs b/tests/compile-fail-fullmir/stacked_borrows/alias_through_mutation.rs index 092f3f09ed196..db9ac93279f15 100644 --- a/tests/compile-fail-fullmir/stacked_borrows/alias_through_mutation.rs +++ b/tests/compile-fail-fullmir/stacked_borrows/alias_through_mutation.rs @@ -1,5 +1,3 @@ -#![allow(unused_variables)] - // This makes a ref that was passed to us via &mut alias with things it should not alias with fn retarget(x: &mut &u32, target: &mut u32) { unsafe { *x = &mut *(target as *mut _); } diff --git a/tests/compile-fail-fullmir/stacked_borrows/aliasing_mut1.rs b/tests/compile-fail-fullmir/stacked_borrows/aliasing_mut1.rs index b82901985b781..9bced43f6e856 100644 --- a/tests/compile-fail-fullmir/stacked_borrows/aliasing_mut1.rs +++ b/tests/compile-fail-fullmir/stacked_borrows/aliasing_mut1.rs @@ -1,8 +1,6 @@ -#![allow(unused_variables)] - use std::mem; -pub fn safe(x: &mut i32, y: &mut i32) {} //~ ERROR barrier +pub fn safe(_x: &mut i32, _y: &mut i32) {} //~ ERROR barrier fn main() { let mut x = 0; diff --git a/tests/compile-fail-fullmir/stacked_borrows/aliasing_mut2.rs b/tests/compile-fail-fullmir/stacked_borrows/aliasing_mut2.rs index 69caddfa8c389..ea24f1bd27488 100644 --- a/tests/compile-fail-fullmir/stacked_borrows/aliasing_mut2.rs +++ b/tests/compile-fail-fullmir/stacked_borrows/aliasing_mut2.rs @@ -1,8 +1,6 @@ -#![allow(unused_variables)] - use std::mem; -pub fn safe(x: &i32, y: &mut i32) {} //~ ERROR barrier +pub fn safe(_x: &i32, _y: &mut i32) {} //~ ERROR barrier fn main() { let mut x = 0; diff --git a/tests/compile-fail-fullmir/stacked_borrows/aliasing_mut3.rs b/tests/compile-fail-fullmir/stacked_borrows/aliasing_mut3.rs index d37f9e63f60d9..e564e878ddb19 100644 --- a/tests/compile-fail-fullmir/stacked_borrows/aliasing_mut3.rs +++ b/tests/compile-fail-fullmir/stacked_borrows/aliasing_mut3.rs @@ -1,8 +1,6 @@ -#![allow(unused_variables)] - use std::mem; -pub fn safe(x: &mut i32, y: &i32) {} //~ ERROR does not exist on the stack +pub fn safe(_x: &mut i32, _y: &i32) {} //~ ERROR does not exist on the stack fn main() { let mut x = 0; diff --git a/tests/compile-fail-fullmir/stacked_borrows/aliasing_mut4.rs b/tests/compile-fail-fullmir/stacked_borrows/aliasing_mut4.rs index bf65d6e230358..15f67d0f8728b 100644 --- a/tests/compile-fail-fullmir/stacked_borrows/aliasing_mut4.rs +++ b/tests/compile-fail-fullmir/stacked_borrows/aliasing_mut4.rs @@ -1,10 +1,8 @@ -#![allow(unused_variables)] - use std::mem; use std::cell::Cell; // Make sure &mut UnsafeCell also is exclusive -pub fn safe(x: &i32, y: &mut Cell) {} //~ ERROR barrier +pub fn safe(_x: &i32, _y: &mut Cell) {} //~ ERROR barrier fn main() { let mut x = 0; diff --git a/tests/compile-fail-fullmir/stacked_borrows/buggy_split_at_mut.rs b/tests/compile-fail-fullmir/stacked_borrows/buggy_split_at_mut.rs index a6daa5d93d772..959c6314690d2 100644 --- a/tests/compile-fail-fullmir/stacked_borrows/buggy_split_at_mut.rs +++ b/tests/compile-fail-fullmir/stacked_borrows/buggy_split_at_mut.rs @@ -1,5 +1,3 @@ -#![allow(unused_variables)] - mod safe { use std::slice::from_raw_parts_mut; diff --git a/tests/compile-fail-fullmir/stacked_borrows/illegal_write2.rs b/tests/compile-fail-fullmir/stacked_borrows/illegal_write2.rs index f4fefaad5e22d..ba3b6686b84cb 100644 --- a/tests/compile-fail-fullmir/stacked_borrows/illegal_write2.rs +++ b/tests/compile-fail-fullmir/stacked_borrows/illegal_write2.rs @@ -1,5 +1,3 @@ -#![allow(unused_variables)] - fn main() { let target = &mut 42; let target2 = target as *mut _; diff --git a/tests/compile-fail/never_transmute_humans.rs b/tests/compile-fail/never_transmute_humans.rs index 169e861be0b1f..34203338696cb 100644 --- a/tests/compile-fail/never_transmute_humans.rs +++ b/tests/compile-fail/never_transmute_humans.rs @@ -2,17 +2,12 @@ // compile-flags: -Zmiri-disable-validation #![feature(never_type)] -#![allow(unreachable_code)] -#![allow(unused_variables)] struct Human; fn main() { - let x: ! = unsafe { + let _x: ! = unsafe { std::mem::transmute::(Human) //~ ERROR constant evaluation error //^~ NOTE entered unreachable code }; - f(x) } - -fn f(x: !) -> ! { x } diff --git a/tests/compile-fail/never_transmute_void.rs b/tests/compile-fail/never_transmute_void.rs index 9c0165fed222a..fab4981047f8d 100644 --- a/tests/compile-fail/never_transmute_void.rs +++ b/tests/compile-fail/never_transmute_void.rs @@ -2,8 +2,6 @@ // compile-flags: -Zmiri-disable-validation #![feature(never_type)] -#![allow(unreachable_code)] -#![allow(unused_variables)] enum Void {} diff --git a/tests/compile-fail/validity/transmute_through_ptr.rs b/tests/compile-fail/validity/transmute_through_ptr.rs index d6bc0305e69dc..4b6a3c95928ae 100644 --- a/tests/compile-fail/validity/transmute_through_ptr.rs +++ b/tests/compile-fail/validity/transmute_through_ptr.rs @@ -1,5 +1,3 @@ -#![allow(unused_variables)] - #[repr(u32)] enum Bool { True } diff --git a/tests/run-pass/dst-struct.rs b/tests/run-pass/dst-struct.rs index 6ef0a6330f739..4c9e598e6ba33 100644 --- a/tests/run-pass/dst-struct.rs +++ b/tests/run-pass/dst-struct.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. - -#![allow(unused_features)] #![feature(box_syntax)] struct Fat { diff --git a/tests/run-pass/issue-31267-additional.rs b/tests/run-pass/issue-31267-additional.rs index 14e38f43c527b..aaeeef8bf98be 100644 --- a/tests/run-pass/issue-31267-additional.rs +++ b/tests/run-pass/issue-31267-additional.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![allow(unused_variables)] - #[derive(Clone, Copy, Debug)] struct Bar; @@ -25,5 +23,5 @@ impl Biz { } fn main() { - let foo = Biz::BAZ; + let _foo = Biz::BAZ; } diff --git a/tests/run-pass/many_shr_bor.rs b/tests/run-pass/many_shr_bor.rs index 393bafebfe4d6..d4901abb808f4 100644 --- a/tests/run-pass/many_shr_bor.rs +++ b/tests/run-pass/many_shr_bor.rs @@ -1,5 +1,4 @@ // Make sure validation can handle many overlapping shared borrows for different parts of a data structure -#![allow(unused_variables)] use std::cell::RefCell; struct Test { @@ -25,9 +24,9 @@ fn test2(r: &mut RefCell) { let x = &*r; // releasing write lock, first suspension recorded let mut x_ref = x.borrow_mut(); let x_inner : &mut i32 = &mut *x_ref; // new inner write lock, with same lifetime as outer lock - let x_inner_shr = &*x_inner; // releasing inner write lock, recording suspension - let y = &*r; // second suspension for the outer write lock - let x_inner_shr2 = &*x_inner; // 2nd suspension for inner write lock + let _x_inner_shr = &*x_inner; // releasing inner write lock, recording suspension + let _y = &*r; // second suspension for the outer write lock + let _x_inner_shr2 = &*x_inner; // 2nd suspension for inner write lock } fn main() { diff --git a/tests/run-pass/move-arg-2-unique.rs b/tests/run-pass/move-arg-2-unique.rs index d44c83763b7c4..77f763888eae1 100644 --- a/tests/run-pass/move-arg-2-unique.rs +++ b/tests/run-pass/move-arg-2-unique.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![allow(unused_features, unused_variables)] #![feature(box_syntax)] fn test(foo: Box> ) { assert_eq!((*foo)[0], 10); } diff --git a/tests/run-pass/move-arg-3-unique.rs b/tests/run-pass/move-arg-3-unique.rs index 2e6320eb80257..0754a3f60d360 100644 --- a/tests/run-pass/move-arg-3-unique.rs +++ b/tests/run-pass/move-arg-3-unique.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![allow(unused_features, unused_variables)] #![feature(box_syntax)] pub fn main() { diff --git a/tests/run-pass/regions-lifetime-nonfree-late-bound.rs b/tests/run-pass/regions-lifetime-nonfree-late-bound.rs index 96f1217a254ed..dfdf89c9c1cd9 100644 --- a/tests/run-pass/regions-lifetime-nonfree-late-bound.rs +++ b/tests/run-pass/regions-lifetime-nonfree-late-bound.rs @@ -22,7 +22,6 @@ // doing region-folding, when really all clients of the region-folding // case only want to see FREE lifetime variables, not bound ones. -#![allow(unused_features)] #![feature(box_syntax)] pub fn main() { From 91f0b28ecc780f291ed716c9126719b0f3110f92 Mon Sep 17 00:00:00 2001 From: Wim Looman Date: Fri, 30 Nov 2018 17:05:37 +0100 Subject: [PATCH 0448/3747] Skip testing targets that don't ship libstd --- tests/compiletest.rs | 33 +++++++++++++++++++++++++-------- 1 file changed, 25 insertions(+), 8 deletions(-) diff --git a/tests/compiletest.rs b/tests/compiletest.rs index 7aa55ef663408..859890aba9f2e 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -124,16 +124,33 @@ fn is_target_dir>(path: P) -> bool { path.metadata().map(|m| m.is_dir()).unwrap_or(false) } -fn for_all_targets(sysroot: &Path, mut f: F) { +fn target_has_std>(path: P) -> bool { + let mut path = path.into(); + path.push("lib"); + std::fs::read_dir(path) + .expect("invalid target") + .map(|entry| entry.unwrap()) + .filter(|entry| entry.file_type().unwrap().is_file()) + .filter_map(|entry| entry.file_name().into_string().ok()) + .any(|file_name| file_name.starts_with("libstd") && file_name.ends_with(".rlib")) +} + + +fn for_all_targets(sysroot: &Path, f: F) { let target_dir = sysroot.join("lib").join("rustlib"); - for entry in std::fs::read_dir(target_dir).expect("invalid sysroot") { - let entry = entry.unwrap(); - if !is_target_dir(entry.path()) { - continue; - } - let target = entry.file_name().into_string().unwrap(); - f(target); + let mut targets = std::fs::read_dir(target_dir) + .expect("invalid sysroot") + .map(|entry| entry.unwrap()) + .filter(|entry| is_target_dir(entry.path())) + .filter(|entry| target_has_std(entry.path())) + .map(|entry| entry.file_name().into_string().unwrap()) + .peekable(); + + if targets.peek().is_none() { + panic!("No valid targets found"); } + + targets.for_each(f); } fn get_sysroot() -> PathBuf { From 479eb3bd2b538c9108880d1b6cafef648a2c8b12 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 28 Nov 2018 09:33:33 +0100 Subject: [PATCH 0449/3747] support for basic (non-overlapping) 2-phase borrows --- src/lib.rs | 3 +- src/stacked_borrows.rs | 33 ++++++++++++------- tests/run-pass/2phase.rs | 69 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 93 insertions(+), 12 deletions(-) create mode 100644 tests/run-pass/2phase.rs diff --git a/src/lib.rs b/src/lib.rs index 9739a7a95b6dc..165b152900316 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -525,6 +525,7 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { fn retag( ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, fn_entry: bool, + two_phase: bool, place: PlaceTy<'tcx, Borrow>, ) -> EvalResult<'tcx> { if !ecx.tcx.sess.opts.debugging_opts.mir_emit_retag || !Self::enforce_validity(ecx) { @@ -535,7 +536,7 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { // uninitialized data. Ok(()) } else { - ecx.retag(fn_entry, place) + ecx.retag(fn_entry, two_phase, place) } } diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 31f80fe2f6c68..3ea434f00f79d 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -8,7 +8,7 @@ use rustc::hir::{Mutability, MutMutable, MutImmutable}; use crate::{ EvalResult, EvalErrorKind, MiriEvalContext, HelpersEvalContextExt, Evaluator, MutValueVisitor, MemoryKind, MiriMemoryKind, RangeMap, AllocId, Allocation, AllocationExtra, - Pointer, MemPlace, Scalar, Immediate, ImmTy, PlaceTy, MPlaceTy, + Pointer, Immediate, ImmTy, PlaceTy, MPlaceTy, }; pub type Timestamp = u64; @@ -534,7 +534,7 @@ pub trait EvalContextExt<'tcx> { size: Size, fn_barrier: bool, new_bor: Borrow - ) -> EvalResult<'tcx, Pointer>; + ) -> EvalResult<'tcx>; /// Retag an indidual pointer, returning the retagged version. fn retag_reference( @@ -542,11 +542,13 @@ pub trait EvalContextExt<'tcx> { ptr: ImmTy<'tcx, Borrow>, mutbl: Mutability, fn_barrier: bool, + two_phase: bool, ) -> EvalResult<'tcx, Immediate>; fn retag( &mut self, fn_entry: bool, + two_phase: bool, place: PlaceTy<'tcx, Borrow> ) -> EvalResult<'tcx>; @@ -644,9 +646,8 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for MiriEvalContext<'a, 'mir, 'tcx> { size: Size, fn_barrier: bool, new_bor: Borrow - ) -> EvalResult<'tcx, Pointer> { + ) -> EvalResult<'tcx> { let ptr = place.ptr.to_ptr()?; - let new_ptr = Pointer::new_with_tag(ptr.alloc_id, ptr.offset, new_bor); let barrier = if fn_barrier { Some(self.frame().extra) } else { None }; trace!("reborrow: Creating new reference for {:?} (pointee {}): {:?}", ptr, place.layout.ty, new_bor); @@ -666,7 +667,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for MiriEvalContext<'a, 'mir, 'tcx> { let kind = if new_bor.is_unique() { RefKind::Unique } else { RefKind::Raw }; alloc.extra.reborrow(ptr, size, barrier, new_bor, kind)?; } - Ok(new_ptr) + Ok(()) } fn retag_reference( @@ -674,6 +675,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for MiriEvalContext<'a, 'mir, 'tcx> { val: ImmTy<'tcx, Borrow>, mutbl: Mutability, fn_barrier: bool, + two_phase: bool, ) -> EvalResult<'tcx, Immediate> { // We want a place for where the ptr *points to*, so we get one. let place = self.ref_to_mplace(val)?; @@ -693,16 +695,24 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for MiriEvalContext<'a, 'mir, 'tcx> { }; // Reborrow. - let new_ptr = self.reborrow(place, size, fn_barrier, new_bor)?; + self.reborrow(place, size, fn_barrier, new_bor)?; + let new_place = place.with_tag(new_bor); + // Handle two-phase borrows. + if two_phase { + // We immediately share it, to allow read accesses + let two_phase_time = self.machine.stacked_borrows.increment_clock(); + let two_phase_bor = Borrow::Shr(Some(two_phase_time)); + self.reborrow(new_place, size, /*fn_barrier*/false, two_phase_bor)?; + } - // Return new ptr - let new_place = MemPlace { ptr: Scalar::Ptr(new_ptr), ..*place }; + // Return new ptr. Ok(new_place.to_ref()) } fn retag( &mut self, fn_entry: bool, + two_phase: bool, place: PlaceTy<'tcx, Borrow> ) -> EvalResult<'tcx> { // Determine mutability and whether to add a barrier. @@ -725,19 +735,20 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for MiriEvalContext<'a, 'mir, 'tcx> { if let Some((mutbl, barrier)) = qualify(place.layout.ty, fn_entry) { // fast path let val = self.read_immediate(self.place_to_op(place)?)?; - let val = self.retag_reference(val, mutbl, barrier)?; + let val = self.retag_reference(val, mutbl, barrier, two_phase)?; self.write_immediate(val, place)?; return Ok(()); } let place = self.force_allocation(place)?; - let mut visitor = RetagVisitor { ecx: self, fn_entry }; + let mut visitor = RetagVisitor { ecx: self, fn_entry, two_phase }; visitor.visit_value(place)?; // The actual visitor struct RetagVisitor<'ecx, 'a, 'mir, 'tcx> { ecx: &'ecx mut MiriEvalContext<'a, 'mir, 'tcx>, fn_entry: bool, + two_phase: bool, } impl<'ecx, 'a, 'mir, 'tcx> MutValueVisitor<'a, 'mir, 'tcx, Evaluator<'tcx>> @@ -758,7 +769,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for MiriEvalContext<'a, 'mir, 'tcx> { // making it useless. if let Some((mutbl, barrier)) = qualify(place.layout.ty, self.fn_entry) { let val = self.ecx.read_immediate(place.into())?; - let val = self.ecx.retag_reference(val, mutbl, barrier)?; + let val = self.ecx.retag_reference(val, mutbl, barrier, self.two_phase)?; self.ecx.write_immediate(val, place.into())?; } Ok(()) diff --git a/tests/run-pass/2phase.rs b/tests/run-pass/2phase.rs new file mode 100644 index 0000000000000..0b2a7d53c8554 --- /dev/null +++ b/tests/run-pass/2phase.rs @@ -0,0 +1,69 @@ +#![feature(nll)] + +trait S: Sized { + fn tpb(&mut self, _s: Self) {} +} + +impl S for i32 {} + +fn two_phase1() { + let mut x = 3; + x.tpb(x); +} + +fn two_phase2() { + let mut v = vec![]; + v.push(v.len()); +} + +/* +fn two_phase_overlapping1() { + let mut x = vec![]; + let p = &x; + x.push(p.len()); +} + +fn two_phase_overlapping2() { + use std::ops::AddAssign; + let mut x = 1; + let l = &x; + x.add_assign(x + *l); +} +*/ + +fn match_two_phase() { + let mut x = 3; + match x { + ref mut y if { let _val = x; let _val = *y; true } => {}, + _ => (), + } +} + +fn with_interior_mutability() { + use std::cell::Cell; + + trait Thing: Sized { + fn do_the_thing(&mut self, _s: i32) {} + } + + impl Thing for Cell {} + + let mut x = Cell::new(1); + let l = &x; + x + .do_the_thing({ + x.set(3); + l.set(4); + x.get() + l.get() + }) + ; +} + +fn main() { + two_phase1(); + two_phase2(); + //two_phase_overlapping1(); + //two_phase_overlapping2(); + match_two_phase(); + with_interior_mutability(); +} From b2305da8d0f4932cad3cea444d598a6e4054f804 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 28 Nov 2018 10:35:10 +0100 Subject: [PATCH 0450/3747] assert some sense --- src/stacked_borrows.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 3ea434f00f79d..1c8224ef17841 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -699,6 +699,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for MiriEvalContext<'a, 'mir, 'tcx> { let new_place = place.with_tag(new_bor); // Handle two-phase borrows. if two_phase { + assert!(mutbl == MutMutable, "two-phase shared borrows make no sense"); // We immediately share it, to allow read accesses let two_phase_time = self.machine.stacked_borrows.increment_clock(); let two_phase_bor = Borrow::Shr(Some(two_phase_time)); From e12d4bc70c018e366e0ac896f60b456019e63986 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 2 Dec 2018 14:03:29 +0100 Subject: [PATCH 0451/3747] build libstd with minimal features --- src/bin/cargo-miri.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 4c83c5bd3dc0a..2dc6eee5de9db 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -155,6 +155,9 @@ fn setup(ask_user: bool) { File::create(dir.join("Xargo.toml")).unwrap() .write_all(br#" [dependencies.std] +default_features = false +# We need the `panic_unwind` feature because we use the `unwind` panic strategy. +# Using `abort` works for libstd, but then libtest will not compile. features = ["panic_unwind"] [dependencies.test] From 6df89de68a21f538173fa833f5965ac4d5da7f23 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 2 Dec 2018 17:18:25 +0100 Subject: [PATCH 0452/3747] we don't need no whitelist --- src/lib.rs | 21 ++------------------- 1 file changed, 2 insertions(+), 19 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 9739a7a95b6dc..ec4e621a24a91 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -310,26 +310,9 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { const STATIC_KIND: Option = Some(MiriMemoryKind::MutStatic); + #[inline(always)] fn enforce_validity(ecx: &EvalContext<'a, 'mir, 'tcx, Self>) -> bool { - if !ecx.machine.validate { - return false; - } - - // Some functions are whitelisted until we figure out how to fix them. - // We walk up the stack a few frames to also cover their callees. - const WHITELIST: &[(&str, &str)] = &[ - // Uses mem::uninitialized - ("std::sys::windows::mutex::Mutex::", ""), - ]; - for frame in ecx.stack().iter() - .rev().take(3) - { - let name = frame.instance.to_string(); - if WHITELIST.iter().any(|(prefix, suffix)| name.starts_with(prefix) && name.ends_with(suffix)) { - return false; - } - } - true + ecx.machine.validate } /// Returns Ok() when the function was handled, fail otherwise From 0e44876a2d37dda4dc57a6eb20588654e5e92562 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 22 Nov 2018 16:26:06 +0100 Subject: [PATCH 0453/3747] fix mutability gap: do not allow shared mutation when creating frozen reference --- src/stacked_borrows.rs | 37 +++++++++++-------- .../stacked_borrows/illegal_write3.rs | 4 +- .../stacked_borrows/pass_invalid_shr.rs | 2 +- .../stacked_borrows/shr_frozen_violation1.rs | 16 ++++++++ tests/run-pass/refcell.rs | 23 ++++++++++++ tests/run-pass/stacked-borrows.rs | 31 +++++++++------- 6 files changed, 82 insertions(+), 31 deletions(-) create mode 100644 tests/compile-fail-fullmir/stacked_borrows/shr_frozen_violation1.rs diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 31f80fe2f6c68..a90be317705a8 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -303,14 +303,30 @@ impl<'tcx> Stack { /// is met: We cannot push `Uniq` onto frozen stacks. /// `kind` indicates which kind of reference is being created. fn create(&mut self, bor: Borrow, kind: RefKind) { - if self.frozen_since.is_some() { - // A frozen location? Possible if we create a barrier, then push again. - assert!(bor.is_shared(), "We should never try creating a unique borrow for a frozen stack"); - trace!("create: Not doing anything on frozen location"); + // When creating a frozen reference, freeze. This ensures F1. + // We also do *not* push anything else to the stack, making sure that no nother kind + // of access (like writing through raw pointers) is permitted. + if kind == RefKind::Frozen { + let bor_t = match bor { + Borrow::Shr(Some(t)) => t, + _ => bug!("Creating illegal borrow {:?} for frozen ref", bor), + }; + // It is possible that we already are frozen (e.g. if we just pushed a barrier, + // the redundancy check would not have kicked in). + match self.frozen_since { + Some(loc_t) => assert!(loc_t <= bor_t, "Trying to freeze location for longer than it was already frozen"), + None => { + trace!("create: Freezing"); + self.frozen_since = Some(bor_t); + } + } return; } - // First, push. We do this even if we will later freeze, because we - // will allow mutation of shared data at the expense of unfreezing. + if self.frozen_since.is_some() { + bug!("Trying to create non-frozen reference to frozen location"); + } + + // Push new item to the stack. let itm = match bor { Borrow::Uniq(t) => BorStackItem::Uniq(t), Borrow::Shr(_) => BorStackItem::Shr, @@ -325,15 +341,6 @@ impl<'tcx> Stack { trace!("create: Pushing {:?}", itm); self.borrows.push(itm); } - // Then, maybe freeze. This is part 2 of ensuring F1. - if kind == RefKind::Frozen { - let bor_t = match bor { - Borrow::Shr(Some(t)) => t, - _ => bug!("Creating illegal borrow {:?} for frozen ref", bor), - }; - trace!("create: Freezing"); - self.frozen_since = Some(bor_t); - } } /// Add a barrier diff --git a/tests/compile-fail-fullmir/stacked_borrows/illegal_write3.rs b/tests/compile-fail-fullmir/stacked_borrows/illegal_write3.rs index 01559af21e7c6..a653aa5003f6d 100644 --- a/tests/compile-fail-fullmir/stacked_borrows/illegal_write3.rs +++ b/tests/compile-fail-fullmir/stacked_borrows/illegal_write3.rs @@ -3,6 +3,6 @@ fn main() { // Make sure raw ptr with raw tag cannot mutate frozen location without breaking the shared ref. let r#ref = ⌖ // freeze let ptr = r#ref as *const _ as *mut _; // raw ptr, with raw tag - unsafe { *ptr = 42; } - let _val = *r#ref; //~ ERROR is not frozen + unsafe { *ptr = 42; } //~ ERROR does not exist on the stack + let _val = *r#ref; } diff --git a/tests/compile-fail-fullmir/stacked_borrows/pass_invalid_shr.rs b/tests/compile-fail-fullmir/stacked_borrows/pass_invalid_shr.rs index 67bbc88e40fb0..22a80e27103e1 100644 --- a/tests/compile-fail-fullmir/stacked_borrows/pass_invalid_shr.rs +++ b/tests/compile-fail-fullmir/stacked_borrows/pass_invalid_shr.rs @@ -3,7 +3,7 @@ fn foo(_: &i32) {} fn main() { let x = &mut 42; - let xraw = &*x as *const _ as *mut _; + let xraw = x as *mut _; let xref = unsafe { &*xraw }; unsafe { *xraw = 42 }; // unfreeze foo(xref); //~ ERROR is not frozen diff --git a/tests/compile-fail-fullmir/stacked_borrows/shr_frozen_violation1.rs b/tests/compile-fail-fullmir/stacked_borrows/shr_frozen_violation1.rs new file mode 100644 index 0000000000000..560c9dfb665dd --- /dev/null +++ b/tests/compile-fail-fullmir/stacked_borrows/shr_frozen_violation1.rs @@ -0,0 +1,16 @@ +fn foo(x: &mut i32) -> i32 { + *x = 5; + unknown_code(&*x); + *x // must return 5 +} + +fn main() { + println!("{}", foo(&mut 0)); +} + +// If we replace the `*const` by `&`, my current dev version of miri +// *does* find the problem, but not for a good reason: It finds it because +// of barriers, and we shouldn't rely on unknown code using barriers. +fn unknown_code(x: *const i32) { + unsafe { *(x as *mut i32) = 7; } //~ ERROR barrier +} diff --git a/tests/run-pass/refcell.rs b/tests/run-pass/refcell.rs index 5f2f3523b96b1..0bc8b15c5f24e 100644 --- a/tests/run-pass/refcell.rs +++ b/tests/run-pass/refcell.rs @@ -39,6 +39,13 @@ fn aliasing_mut_and_shr() { *aliasing += 4; let _shr = &*rc; *aliasing += 4; + // also turning this into a frozen ref now must work + let aliasing = &*aliasing; + let _val = *aliasing; + let _escape_to_raw = rc as *const _; // this must NOT unfreeze + let _val = *aliasing; + let _shr = &*rc; // this must NOT unfreeze + let _val = *aliasing; } let rc = RefCell::new(23); @@ -48,7 +55,23 @@ fn aliasing_mut_and_shr() { assert_eq!(*rc.borrow(), 23+12); } +fn aliasing_frz_and_shr() { + fn inner(rc: &RefCell, aliasing: &i32) { + let _val = *aliasing; + let _escape_to_raw = rc as *const _; // this must NOT unfreeze + let _val = *aliasing; + let _shr = &*rc; // this must NOT unfreeze + let _val = *aliasing; + } + + let rc = RefCell::new(23); + let bshr = rc.borrow(); + inner(&rc, &*bshr); + assert_eq!(*rc.borrow(), 23); +} + fn main() { lots_of_funny_borrows(); aliasing_mut_and_shr(); + aliasing_frz_and_shr(); } diff --git a/tests/run-pass/stacked-borrows.rs b/tests/run-pass/stacked-borrows.rs index 93bdf5ffbf326..388765c29eabd 100644 --- a/tests/run-pass/stacked-borrows.rs +++ b/tests/run-pass/stacked-borrows.rs @@ -4,10 +4,11 @@ fn main() { read_does_not_invalidate1(); read_does_not_invalidate2(); ref_raw_int_raw(); - mut_shr_raw(); mut_raw_then_mut_shr(); + mut_shr_then_mut_raw(); mut_raw_mut(); partially_invalidate_mut(); + drop_after_sharing(); } // Deref a raw ptr to access a field of a large struct, where the field @@ -53,18 +54,6 @@ fn ref_raw_int_raw() { assert_eq!(unsafe { *xraw }, 3); } -// Creating a raw from a `&mut` through an `&` works, even if we -// write through that raw. -fn mut_shr_raw() { - let mut x = 2; - { - let xref = &mut x; - let xraw = &*xref as *const i32 as *mut i32; - unsafe { *xraw = 4; } - } - assert_eq!(x, 4); -} - // Escape a mut to raw, then share the same mut and use the share, then the raw. // That should work. fn mut_raw_then_mut_shr() { @@ -77,6 +66,16 @@ fn mut_raw_then_mut_shr() { assert_eq!(x, 4); } +// Create first a shared reference and then a raw pointer from a `&mut` +// should permit mutation through that raw pointer. +fn mut_shr_then_mut_raw() { + let xref = &mut 2; + let _xshr = &*xref; + let xraw = xref as *mut _; + unsafe { *xraw = 3; } + assert_eq!(*xref, 3); +} + // Ensure that if we derive from a mut a raw, and then from that a mut, // and then read through the original mut, that does not invalidate the raw. // This shows that the read-exception for `&mut` applies even if the `Shr` item @@ -107,3 +106,9 @@ fn partially_invalidate_mut() { *shard += 1; // so we can still use `shard`. assert_eq!(*data, (1, 1)); } + +// Make sure that we can handle the situation where a loaction is frozen when being dropped. +fn drop_after_sharing() { + let x = String::from("hello!"); + let _len = x.len(); +} From 9d0c1dd676ee542af15bff3c4cd34c5c8cacaad0 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 2 Dec 2018 23:24:08 +0100 Subject: [PATCH 0454/3747] disable VecDeque test until the fix lands in rustc --- tests/run-pass-fullmir/vecdeque.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/run-pass-fullmir/vecdeque.rs b/tests/run-pass-fullmir/vecdeque.rs index 381169505ec9f..d92cff0b084e6 100644 --- a/tests/run-pass-fullmir/vecdeque.rs +++ b/tests/run-pass-fullmir/vecdeque.rs @@ -1,3 +1,6 @@ +// FIXME: Validation disabled until https://github.com/rust-lang/rust/pull/56161 lands +// compile-flags: -Zmiri-disable-validation + use std::collections::VecDeque; fn main() { From 04057432c1045564bf8b917cacde931df4894d41 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 3 Dec 2018 09:15:00 +0100 Subject: [PATCH 0455/3747] bump nightly --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 6fd720c5c785d..087b7c6642729 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -nightly-2018-11-30 +nightly-2018-12-03 From d11a6766ad388c97e3a95b26a9350ff4ddefd004 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 3 Dec 2018 10:26:39 +0100 Subject: [PATCH 0456/3747] use assert --- src/stacked_borrows.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index a90be317705a8..41b5cc2a239d1 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -322,9 +322,7 @@ impl<'tcx> Stack { } return; } - if self.frozen_since.is_some() { - bug!("Trying to create non-frozen reference to frozen location"); - } + assert!(self.frozen_since.is_none(), "Trying to create non-frozen reference to frozen location"); // Push new item to the stack. let itm = match bor { From b6e5822601beb443faed97d7d7333ba543ea119d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 3 Dec 2018 10:28:32 +0100 Subject: [PATCH 0457/3747] add FIXME --- tests/run-pass/2phase.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/run-pass/2phase.rs b/tests/run-pass/2phase.rs index 0b2a7d53c8554..5b9e5d3ea5ff7 100644 --- a/tests/run-pass/2phase.rs +++ b/tests/run-pass/2phase.rs @@ -62,8 +62,9 @@ fn with_interior_mutability() { fn main() { two_phase1(); two_phase2(); - //two_phase_overlapping1(); - //two_phase_overlapping2(); match_two_phase(); with_interior_mutability(); + //FIXME: enable these, or remove them, depending on how https://github.com/rust-lang/rust/issues/56254 gets resolved + //two_phase_overlapping1(); + //two_phase_overlapping2(); } From bbdc3380d57fafbe66d2f6422df35d542331555f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 7 Dec 2018 10:15:25 +0100 Subject: [PATCH 0458/3747] fix tests --- tests/compile-fail/validity/nonzero.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/compile-fail/validity/nonzero.rs b/tests/compile-fail/validity/nonzero.rs index d1de0f8095e34..f820b0e810b83 100644 --- a/tests/compile-fail/validity/nonzero.rs +++ b/tests/compile-fail/validity/nonzero.rs @@ -7,5 +7,5 @@ pub(crate) struct NonZero(pub(crate) T); fn main() { // Make sure that we detect this even when no function call is happening along the way - let _x = Some(NonZero(0)); //~ ERROR encountered 0, but expected something greater or equal to 1 + let _x = Some(unsafe { NonZero(0) }); //~ ERROR encountered 0, but expected something greater or equal to 1 } From d5d1b1e4f3df26b70c77b9c21437db2127b8e2b8 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 7 Dec 2018 18:01:23 +0100 Subject: [PATCH 0459/3747] add FIXME test for coercing &mut to *const --- tests/run-pass/stacked-borrows.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/tests/run-pass/stacked-borrows.rs b/tests/run-pass/stacked-borrows.rs index 388765c29eabd..223c69a9a3ad7 100644 --- a/tests/run-pass/stacked-borrows.rs +++ b/tests/run-pass/stacked-borrows.rs @@ -9,6 +9,7 @@ fn main() { mut_raw_mut(); partially_invalidate_mut(); drop_after_sharing(); + direct_mut_to_const_raw(); } // Deref a raw ptr to access a field of a large struct, where the field @@ -112,3 +113,13 @@ fn drop_after_sharing() { let x = String::from("hello!"); let _len = x.len(); } + +// Make sure that coercing &mut T to *const T produces a writeable pointer. +fn direct_mut_to_const_raw() { + // FIXME: This is currently disabled, waiting on a fix for + /*let x = &mut 0; + let y: *const i32 = x; + unsafe { *(y as *mut i32) = 1; } + assert_eq!(*x, 1); + */ +} From f06e25f9b201dafe5f402e116b0ab7ec16727093 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 8 Dec 2018 10:33:29 +0100 Subject: [PATCH 0460/3747] bump Rust version, fix build --- rust-version | 2 +- src/bin/miri-rustc-tests.rs | 4 ++-- src/bin/miri.rs | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/rust-version b/rust-version index 087b7c6642729..69d072f1bfa01 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -nightly-2018-12-03 +nightly-2018-12-08 diff --git a/src/bin/miri-rustc-tests.rs b/src/bin/miri-rustc-tests.rs index 6fa9b817ffee7..92d4237146dcf 100644 --- a/src/bin/miri-rustc-tests.rs +++ b/src/bin/miri-rustc-tests.rs @@ -93,7 +93,7 @@ fn after_analysis<'a, 'tcx>(state: &mut CompileState<'a, 'tcx>) { fn visit_item(&mut self, i: &'hir hir::Item) { if let hir::ItemKind::Fn(.., body_id) = i.node { if i.attrs.iter().any(|attr| attr.name() == "test") { - let did = self.0.hir.body_owner_def_id(body_id); + let did = self.0.hir().body_owner_def_id(body_id); println!("running test: {}", self.0.def_path_debug_str(did)); miri::eval_main(self.0, did, /*validate*/true); self.1.session.abort_if_errors(); @@ -105,7 +105,7 @@ fn after_analysis<'a, 'tcx>(state: &mut CompileState<'a, 'tcx>) { } state.hir_crate.unwrap().visit_all_item_likes(&mut Visitor(tcx, state)); } else if let Some((entry_node_id, _, _)) = *state.session.entry_fn.borrow() { - let entry_def_id = tcx.hir.local_def_id(entry_node_id); + let entry_def_id = tcx.hir().local_def_id(entry_node_id); miri::eval_main(tcx, entry_def_id, /*validate*/true); state.session.abort_if_errors(); diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 1bbf3c8c4a4a8..e88c13305d154 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -128,7 +128,7 @@ fn after_analysis<'a, 'tcx>( attr.name() == "test" }) { - let did = self.tcx.hir.body_owner_def_id(body_id); + let did = self.tcx.hir().body_owner_def_id(body_id); println!( "running test: {}", self.tcx.def_path_debug_str(did), @@ -145,7 +145,7 @@ fn after_analysis<'a, 'tcx>( &mut Visitor { tcx, state, validate } ); } else if let Some((entry_node_id, _, _)) = *state.session.entry_fn.borrow() { - let entry_def_id = tcx.hir.local_def_id(entry_node_id); + let entry_def_id = tcx.hir().local_def_id(entry_node_id); miri::eval_main(tcx, entry_def_id, validate); state.session.abort_if_errors(); From 8d1e1179a17bc2aba017a5a16f0b42772032e00d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 8 Dec 2018 10:47:50 +0100 Subject: [PATCH 0461/3747] fix benches --- benches/helpers/miri_helper.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/benches/helpers/miri_helper.rs b/benches/helpers/miri_helper.rs index 015e36c4f5ad7..c7df34eaf706d 100644 --- a/benches/helpers/miri_helper.rs +++ b/benches/helpers/miri_helper.rs @@ -47,7 +47,7 @@ pub fn run(filename: &str, bencher: &mut Bencher) { let (entry_node_id, _, _) = state.session.entry_fn.borrow().expect( "no main or start function found", ); - let entry_def_id = tcx.hir.local_def_id(entry_node_id); + let entry_def_id = tcx.hir().local_def_id(entry_node_id); bencher.borrow_mut().iter(|| { eval_main(tcx, entry_def_id, false); From c84c1527e2d486437efa5e3851a2b4b421c99133 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 10 Dec 2018 09:23:27 +0100 Subject: [PATCH 0462/3747] factor grabbing of cargo options into separate function and make it better --- src/bin/cargo-miri.rs | 34 ++++++++++++++++++++++++---------- 1 file changed, 24 insertions(+), 10 deletions(-) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 2dc6eee5de9db..436b6a9430bf4 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -53,14 +53,32 @@ fn show_error(msg: String) -> ! { std::process::exit(1) } -fn list_targets(mut args: impl Iterator) -> impl Iterator { +fn get_arg_flag_value(name: &str) -> Option { + // stop searching at `--` + let mut args = std::env::args().skip_while(|val| !(val.starts_with(name) || val == "--")); + + match args.next() { + Some(ref p) if p == "--" => None, + Some(ref p) if p == name => args.next(), + Some(p) => { + // Make sure this really starts with `$name=`, we didn't test for the `=` yet. + let v = &p[name.len()..]; // strip leading `$name` + if v.starts_with('=') { + Some(v[1..].to_owned()) // strip leading `=` + } else { + None + } + }, + None => None, + } +} + +fn list_targets() -> impl Iterator { // We need to get the manifest, and then the metadata, to enumerate targets. - let manifest_path_arg = args.find(|val| { - val.starts_with("--manifest-path=") - }); + let manifest_path = get_arg_flag_value("--manifest-path").map(PathBuf::from); let mut metadata = if let Ok(metadata) = cargo_metadata::metadata( - manifest_path_arg.as_ref().map(AsRef::as_ref), + manifest_path.as_ref().map(AsRef::as_ref), ) { metadata @@ -68,10 +86,6 @@ fn list_targets(mut args: impl Iterator) -> impl Iterator Date: Mon, 10 Dec 2018 09:32:54 +0100 Subject: [PATCH 0463/3747] cargo miri: support foreign targets --- Cargo.toml | 3 ++- src/bin/cargo-miri.rs | 21 ++++++++++++++++----- 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index becb5c69e5612..ca670df0f2034 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -36,6 +36,7 @@ required-features = ["rustc_tests"] byteorder = { version = "1.1", features = ["i128"]} cargo_metadata = { version = "0.6", optional = true } directories = { version = "1.0", optional = true } +rustc_version = { version = "0.2.3", optional = true } env_logger = "0.5" log = "0.4" @@ -44,7 +45,7 @@ vergen = "3" [features] default = ["cargo_miri"] -cargo_miri = ["cargo_metadata", "directories"] +cargo_miri = ["cargo_metadata", "directories", "rustc_version"] rustc_tests = [] [dev-dependencies] diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 436b6a9430bf4..68da028a81c64 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -190,17 +190,28 @@ path = "lib.rs" "#).unwrap(); File::create(dir.join("lib.rs")).unwrap(); // Run xargo - if !Command::new("xargo").arg("build").arg("-q") + let target = get_arg_flag_value("--target"); + let mut command = Command::new("xargo"); + command.arg("build").arg("-q") .current_dir(&dir) .env("RUSTFLAGS", miri::miri_default_args().join(" ")) - .env("XARGO_HOME", dir.to_str().unwrap()) - .status().unwrap().success() + .env("XARGO_HOME", dir.to_str().unwrap()); + if let Some(ref target) = target { + command.arg("--target").arg(&target); + } + if !command.status().unwrap().success() { show_error(format!("Failed to run xargo")); } - // That should be it! - let sysroot = dir.join("HOST"); + // That should be it! But we need to figure out where xargo built stuff. + // Unfortunately, it puts things into a different directory when the + // architecture matches the host. + let is_host = match target { + None => true, + Some(target) => target == rustc_version::version_meta().unwrap().host, + }; + let sysroot = if is_host { dir.join("HOST") } else { PathBuf::from(dir) }; std::env::set_var("MIRI_SYSROOT", &sysroot); if !ask_user { println!("A libstd for miri is now available in `{}`", sysroot.display()); From f044205b5fab8b48a583f613f995519d6895e8ea Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 10 Dec 2018 10:04:55 +0100 Subject: [PATCH 0464/3747] the test suite assumes a libstd with full MIR; run test suite on xargo-built foreign libstds --- .travis.yml | 29 ++++++------- .../.gitignore | 0 .../Cargo.lock | 0 .../Cargo.toml | 0 .../run-test.py | 0 .../src/main.rs | 0 .../stderr.ref | 0 .../stdout.ref | 0 .../tests/foo.rs | 0 .../copy_nonoverlapping.rs | 0 .../deallocate-bad-alignment.rs | 0 .../deallocate-bad-size.rs | 0 .../deallocate-twice.rs | 0 .../memleak_rc.rs | 0 .../out_of_bounds_ptr_1.rs | 0 .../out_of_bounds_ptr_2.rs | 0 .../ptr_offset_overflow.rs | 0 .../reallocate-bad-size.rs | 0 .../reallocate-change-alloc.rs | 0 .../reallocate-dangling.rs | 0 .../stack_free.rs | 0 .../stacked_borrows/alias_through_mutation.rs | 0 .../stacked_borrows/aliasing_mut1.rs | 0 .../stacked_borrows/aliasing_mut2.rs | 0 .../stacked_borrows/aliasing_mut3.rs | 0 .../stacked_borrows/aliasing_mut4.rs | 0 .../box_exclusive_violation1.rs | 0 .../stacked_borrows/buggy_as_mut_slice.rs | 0 .../stacked_borrows/buggy_split_at_mut.rs | 0 .../deallocate_against_barrier.rs | 0 .../stacked_borrows/illegal_read1.rs | 0 .../stacked_borrows/illegal_read2.rs | 0 .../stacked_borrows/illegal_read3.rs | 0 .../stacked_borrows/illegal_read4.rs | 0 .../stacked_borrows/illegal_read5.rs | 0 .../stacked_borrows/illegal_write1.rs | 0 .../stacked_borrows/illegal_write2.rs | 0 .../stacked_borrows/illegal_write3.rs | 0 .../stacked_borrows/illegal_write4.rs | 0 .../stacked_borrows/illegal_write5.rs | 0 .../invalidate_against_barrier1.rs | 0 .../invalidate_against_barrier2.rs | 0 .../stacked_borrows/load_invalid_mut.rs | 0 .../stacked_borrows/load_invalid_shr.rs | 0 .../mut_exclusive_violation1.rs | 0 .../stacked_borrows/outdated_local.rs | 0 .../stacked_borrows/pass_invalid_mut.rs | 0 .../stacked_borrows/pass_invalid_shr.rs | 0 .../stacked_borrows/pointer_smuggling.rs | 0 .../stacked_borrows/return_invalid_mut.rs | 0 .../return_invalid_mut_option.rs | 0 .../return_invalid_mut_tuple.rs | 0 .../stacked_borrows/return_invalid_shr.rs | 0 .../return_invalid_shr_option.rs | 0 .../return_invalid_shr_tuple.rs | 0 .../stacked_borrows/shr_frozen_violation1.rs | 0 .../static_memory_modification.rs | 0 .../stacked_borrows/transmute-is-no-escape.rs | 0 .../stacked_borrows/unescaped_local.rs | 0 .../transmute-pair-undef.rs | 0 tests/compiletest.rs | 43 ++++--------------- .../async-fn.rs | 0 .../box-pair-to-vec.rs | 0 .../box-pair-to-vec.stdout | 0 tests/{run-pass-fullmir => run-pass}/catch.rs | 0 .../catch.stdout | 0 tests/{run-pass-fullmir => run-pass}/env.rs | 0 .../foreign-fn-linkname.rs | 0 .../{run-pass-fullmir => run-pass}/format.rs | 0 .../format.stdout | 0 .../from_utf8.rs | 0 .../{run-pass-fullmir => run-pass}/hashmap.rs | 0 tests/{run-pass-fullmir => run-pass}/hello.rs | 0 .../hello.stdout | 0 .../integer-ops.rs | 0 .../issue-3794.rs | 0 .../issue-3794.stdout | 0 .../loop-break-value.rs | 0 .../{run-pass-fullmir => run-pass}/memchr.rs | 0 .../send-is-not-static-par-for.rs | 0 .../{run-pass-fullmir => run-pass}/threads.rs | 0 tests/{run-pass-fullmir => run-pass}/u128.rs | 0 .../unsized-tuple-impls.rs | 0 .../vecdeque.rs | 0 84 files changed, 22 insertions(+), 50 deletions(-) rename {cargo-miri-test => test-cargo-miri}/.gitignore (100%) rename {cargo-miri-test => test-cargo-miri}/Cargo.lock (100%) rename {cargo-miri-test => test-cargo-miri}/Cargo.toml (100%) rename {cargo-miri-test => test-cargo-miri}/run-test.py (100%) rename {cargo-miri-test => test-cargo-miri}/src/main.rs (100%) rename {cargo-miri-test => test-cargo-miri}/stderr.ref (100%) rename {cargo-miri-test => test-cargo-miri}/stdout.ref (100%) rename {cargo-miri-test => test-cargo-miri}/tests/foo.rs (100%) rename tests/{compile-fail-fullmir => compile-fail}/copy_nonoverlapping.rs (100%) rename tests/{compile-fail-fullmir => compile-fail}/deallocate-bad-alignment.rs (100%) rename tests/{compile-fail-fullmir => compile-fail}/deallocate-bad-size.rs (100%) rename tests/{compile-fail-fullmir => compile-fail}/deallocate-twice.rs (100%) rename tests/{compile-fail-fullmir => compile-fail}/memleak_rc.rs (100%) rename tests/{compile-fail-fullmir => compile-fail}/out_of_bounds_ptr_1.rs (100%) rename tests/{compile-fail-fullmir => compile-fail}/out_of_bounds_ptr_2.rs (100%) rename tests/{compile-fail-fullmir => compile-fail}/ptr_offset_overflow.rs (100%) rename tests/{compile-fail-fullmir => compile-fail}/reallocate-bad-size.rs (100%) rename tests/{compile-fail-fullmir => compile-fail}/reallocate-change-alloc.rs (100%) rename tests/{compile-fail-fullmir => compile-fail}/reallocate-dangling.rs (100%) rename tests/{compile-fail-fullmir => compile-fail}/stack_free.rs (100%) rename tests/{compile-fail-fullmir => compile-fail}/stacked_borrows/alias_through_mutation.rs (100%) rename tests/{compile-fail-fullmir => compile-fail}/stacked_borrows/aliasing_mut1.rs (100%) rename tests/{compile-fail-fullmir => compile-fail}/stacked_borrows/aliasing_mut2.rs (100%) rename tests/{compile-fail-fullmir => compile-fail}/stacked_borrows/aliasing_mut3.rs (100%) rename tests/{compile-fail-fullmir => compile-fail}/stacked_borrows/aliasing_mut4.rs (100%) rename tests/{compile-fail-fullmir => compile-fail}/stacked_borrows/box_exclusive_violation1.rs (100%) rename tests/{compile-fail-fullmir => compile-fail}/stacked_borrows/buggy_as_mut_slice.rs (100%) rename tests/{compile-fail-fullmir => compile-fail}/stacked_borrows/buggy_split_at_mut.rs (100%) rename tests/{compile-fail-fullmir => compile-fail}/stacked_borrows/deallocate_against_barrier.rs (100%) rename tests/{compile-fail-fullmir => compile-fail}/stacked_borrows/illegal_read1.rs (100%) rename tests/{compile-fail-fullmir => compile-fail}/stacked_borrows/illegal_read2.rs (100%) rename tests/{compile-fail-fullmir => compile-fail}/stacked_borrows/illegal_read3.rs (100%) rename tests/{compile-fail-fullmir => compile-fail}/stacked_borrows/illegal_read4.rs (100%) rename tests/{compile-fail-fullmir => compile-fail}/stacked_borrows/illegal_read5.rs (100%) rename tests/{compile-fail-fullmir => compile-fail}/stacked_borrows/illegal_write1.rs (100%) rename tests/{compile-fail-fullmir => compile-fail}/stacked_borrows/illegal_write2.rs (100%) rename tests/{compile-fail-fullmir => compile-fail}/stacked_borrows/illegal_write3.rs (100%) rename tests/{compile-fail-fullmir => compile-fail}/stacked_borrows/illegal_write4.rs (100%) rename tests/{compile-fail-fullmir => compile-fail}/stacked_borrows/illegal_write5.rs (100%) rename tests/{compile-fail-fullmir => compile-fail}/stacked_borrows/invalidate_against_barrier1.rs (100%) rename tests/{compile-fail-fullmir => compile-fail}/stacked_borrows/invalidate_against_barrier2.rs (100%) rename tests/{compile-fail-fullmir => compile-fail}/stacked_borrows/load_invalid_mut.rs (100%) rename tests/{compile-fail-fullmir => compile-fail}/stacked_borrows/load_invalid_shr.rs (100%) rename tests/{compile-fail-fullmir => compile-fail}/stacked_borrows/mut_exclusive_violation1.rs (100%) rename tests/{compile-fail-fullmir => compile-fail}/stacked_borrows/outdated_local.rs (100%) rename tests/{compile-fail-fullmir => compile-fail}/stacked_borrows/pass_invalid_mut.rs (100%) rename tests/{compile-fail-fullmir => compile-fail}/stacked_borrows/pass_invalid_shr.rs (100%) rename tests/{compile-fail-fullmir => compile-fail}/stacked_borrows/pointer_smuggling.rs (100%) rename tests/{compile-fail-fullmir => compile-fail}/stacked_borrows/return_invalid_mut.rs (100%) rename tests/{compile-fail-fullmir => compile-fail}/stacked_borrows/return_invalid_mut_option.rs (100%) rename tests/{compile-fail-fullmir => compile-fail}/stacked_borrows/return_invalid_mut_tuple.rs (100%) rename tests/{compile-fail-fullmir => compile-fail}/stacked_borrows/return_invalid_shr.rs (100%) rename tests/{compile-fail-fullmir => compile-fail}/stacked_borrows/return_invalid_shr_option.rs (100%) rename tests/{compile-fail-fullmir => compile-fail}/stacked_borrows/return_invalid_shr_tuple.rs (100%) rename tests/{compile-fail-fullmir => compile-fail}/stacked_borrows/shr_frozen_violation1.rs (100%) rename tests/{compile-fail-fullmir => compile-fail}/stacked_borrows/static_memory_modification.rs (100%) rename tests/{compile-fail-fullmir => compile-fail}/stacked_borrows/transmute-is-no-escape.rs (100%) rename tests/{compile-fail-fullmir => compile-fail}/stacked_borrows/unescaped_local.rs (100%) rename tests/{compile-fail-fullmir => compile-fail}/transmute-pair-undef.rs (100%) rename tests/{run-pass-fullmir => run-pass}/async-fn.rs (100%) rename tests/{run-pass-fullmir => run-pass}/box-pair-to-vec.rs (100%) rename tests/{run-pass-fullmir => run-pass}/box-pair-to-vec.stdout (100%) rename tests/{run-pass-fullmir => run-pass}/catch.rs (100%) rename tests/{run-pass-fullmir => run-pass}/catch.stdout (100%) rename tests/{run-pass-fullmir => run-pass}/env.rs (100%) rename tests/{run-pass-fullmir => run-pass}/foreign-fn-linkname.rs (100%) rename tests/{run-pass-fullmir => run-pass}/format.rs (100%) rename tests/{run-pass-fullmir => run-pass}/format.stdout (100%) rename tests/{run-pass-fullmir => run-pass}/from_utf8.rs (100%) rename tests/{run-pass-fullmir => run-pass}/hashmap.rs (100%) rename tests/{run-pass-fullmir => run-pass}/hello.rs (100%) rename tests/{run-pass-fullmir => run-pass}/hello.stdout (100%) rename tests/{run-pass-fullmir => run-pass}/integer-ops.rs (100%) rename tests/{run-pass-fullmir => run-pass}/issue-3794.rs (100%) rename tests/{run-pass-fullmir => run-pass}/issue-3794.stdout (100%) rename tests/{run-pass-fullmir => run-pass}/loop-break-value.rs (100%) rename tests/{run-pass-fullmir => run-pass}/memchr.rs (100%) rename tests/{run-pass-fullmir => run-pass}/send-is-not-static-par-for.rs (100%) rename tests/{run-pass-fullmir => run-pass}/threads.rs (100%) rename tests/{run-pass-fullmir => run-pass}/u128.rs (100%) rename tests/{run-pass-fullmir => run-pass}/unsized-tuple-impls.rs (100%) rename tests/{run-pass-fullmir => run-pass}/vecdeque.rs (100%) diff --git a/.travis.yml b/.travis.yml index ba3b8d3639917..ac3f16ce13530 100644 --- a/.travis.yml +++ b/.travis.yml @@ -20,36 +20,35 @@ before_script: else RUST_TOOLCHAIN=$(cat rust-version) fi +- | + if [ "$TRAVIS_OS_NAME" == osx ]; then + export MIRI_SYSROOT_BASE=~/Library/Caches/miri.miri.miri/ + else + export MIRI_SYSROOT_BASE=~/.cache/miri/HOST + fi # install Rust - curl https://build.travis-ci.org/files/rustup-init.sh -sSf | sh -s -- -y --default-toolchain "$RUST_TOOLCHAIN" - export PATH=$HOME/.cargo/bin:$PATH - rustc --version -# customize installation -- rustup target add i686-unknown-linux-gnu -- rustup target add i686-pc-windows-gnu -- rustup target add i686-pc-windows-msvc script: - set -e - | - # Test and install plain miri + # Build and install miri cargo build --release --all-features --all-targets && - cargo test --release --all-features && cargo install --all-features --force --path . - | - # Get ourselves a MIR-full libstd, and use it henceforth + # Get ourselves a MIR-full libstd cargo miri setup && - if [ "$TRAVIS_OS_NAME" == osx ]; then - export MIRI_SYSROOT=~/Library/Caches/miri.miri.miri/HOST - else - export MIRI_SYSROOT=~/.cache/miri/HOST - fi + cargo miri setup --target i686-unknown-linux-gnu && + cargo miri setup --target i686-apple-darwin - | - # Test miri with full MIR - cargo test --release --all-features + # Test miri with full MIR, on the host and other architectures + MIRI_SYSROOT=$MIRI_SYSROOT_BASE/HOST cargo test --release --all-features && + MIRI_SYSROOT=$MIRI_SYSROOT_BASE cargo test --release --all-features - | # Test cargo integration - (cd cargo-miri-test && ./run-test.py) + (cd test-cargo-miri && MIRI_SYSROOT=$MIRI_SYSROOT_BASE/HOST ./run-test.py) notifications: email: diff --git a/cargo-miri-test/.gitignore b/test-cargo-miri/.gitignore similarity index 100% rename from cargo-miri-test/.gitignore rename to test-cargo-miri/.gitignore diff --git a/cargo-miri-test/Cargo.lock b/test-cargo-miri/Cargo.lock similarity index 100% rename from cargo-miri-test/Cargo.lock rename to test-cargo-miri/Cargo.lock diff --git a/cargo-miri-test/Cargo.toml b/test-cargo-miri/Cargo.toml similarity index 100% rename from cargo-miri-test/Cargo.toml rename to test-cargo-miri/Cargo.toml diff --git a/cargo-miri-test/run-test.py b/test-cargo-miri/run-test.py similarity index 100% rename from cargo-miri-test/run-test.py rename to test-cargo-miri/run-test.py diff --git a/cargo-miri-test/src/main.rs b/test-cargo-miri/src/main.rs similarity index 100% rename from cargo-miri-test/src/main.rs rename to test-cargo-miri/src/main.rs diff --git a/cargo-miri-test/stderr.ref b/test-cargo-miri/stderr.ref similarity index 100% rename from cargo-miri-test/stderr.ref rename to test-cargo-miri/stderr.ref diff --git a/cargo-miri-test/stdout.ref b/test-cargo-miri/stdout.ref similarity index 100% rename from cargo-miri-test/stdout.ref rename to test-cargo-miri/stdout.ref diff --git a/cargo-miri-test/tests/foo.rs b/test-cargo-miri/tests/foo.rs similarity index 100% rename from cargo-miri-test/tests/foo.rs rename to test-cargo-miri/tests/foo.rs diff --git a/tests/compile-fail-fullmir/copy_nonoverlapping.rs b/tests/compile-fail/copy_nonoverlapping.rs similarity index 100% rename from tests/compile-fail-fullmir/copy_nonoverlapping.rs rename to tests/compile-fail/copy_nonoverlapping.rs diff --git a/tests/compile-fail-fullmir/deallocate-bad-alignment.rs b/tests/compile-fail/deallocate-bad-alignment.rs similarity index 100% rename from tests/compile-fail-fullmir/deallocate-bad-alignment.rs rename to tests/compile-fail/deallocate-bad-alignment.rs diff --git a/tests/compile-fail-fullmir/deallocate-bad-size.rs b/tests/compile-fail/deallocate-bad-size.rs similarity index 100% rename from tests/compile-fail-fullmir/deallocate-bad-size.rs rename to tests/compile-fail/deallocate-bad-size.rs diff --git a/tests/compile-fail-fullmir/deallocate-twice.rs b/tests/compile-fail/deallocate-twice.rs similarity index 100% rename from tests/compile-fail-fullmir/deallocate-twice.rs rename to tests/compile-fail/deallocate-twice.rs diff --git a/tests/compile-fail-fullmir/memleak_rc.rs b/tests/compile-fail/memleak_rc.rs similarity index 100% rename from tests/compile-fail-fullmir/memleak_rc.rs rename to tests/compile-fail/memleak_rc.rs diff --git a/tests/compile-fail-fullmir/out_of_bounds_ptr_1.rs b/tests/compile-fail/out_of_bounds_ptr_1.rs similarity index 100% rename from tests/compile-fail-fullmir/out_of_bounds_ptr_1.rs rename to tests/compile-fail/out_of_bounds_ptr_1.rs diff --git a/tests/compile-fail-fullmir/out_of_bounds_ptr_2.rs b/tests/compile-fail/out_of_bounds_ptr_2.rs similarity index 100% rename from tests/compile-fail-fullmir/out_of_bounds_ptr_2.rs rename to tests/compile-fail/out_of_bounds_ptr_2.rs diff --git a/tests/compile-fail-fullmir/ptr_offset_overflow.rs b/tests/compile-fail/ptr_offset_overflow.rs similarity index 100% rename from tests/compile-fail-fullmir/ptr_offset_overflow.rs rename to tests/compile-fail/ptr_offset_overflow.rs diff --git a/tests/compile-fail-fullmir/reallocate-bad-size.rs b/tests/compile-fail/reallocate-bad-size.rs similarity index 100% rename from tests/compile-fail-fullmir/reallocate-bad-size.rs rename to tests/compile-fail/reallocate-bad-size.rs diff --git a/tests/compile-fail-fullmir/reallocate-change-alloc.rs b/tests/compile-fail/reallocate-change-alloc.rs similarity index 100% rename from tests/compile-fail-fullmir/reallocate-change-alloc.rs rename to tests/compile-fail/reallocate-change-alloc.rs diff --git a/tests/compile-fail-fullmir/reallocate-dangling.rs b/tests/compile-fail/reallocate-dangling.rs similarity index 100% rename from tests/compile-fail-fullmir/reallocate-dangling.rs rename to tests/compile-fail/reallocate-dangling.rs diff --git a/tests/compile-fail-fullmir/stack_free.rs b/tests/compile-fail/stack_free.rs similarity index 100% rename from tests/compile-fail-fullmir/stack_free.rs rename to tests/compile-fail/stack_free.rs diff --git a/tests/compile-fail-fullmir/stacked_borrows/alias_through_mutation.rs b/tests/compile-fail/stacked_borrows/alias_through_mutation.rs similarity index 100% rename from tests/compile-fail-fullmir/stacked_borrows/alias_through_mutation.rs rename to tests/compile-fail/stacked_borrows/alias_through_mutation.rs diff --git a/tests/compile-fail-fullmir/stacked_borrows/aliasing_mut1.rs b/tests/compile-fail/stacked_borrows/aliasing_mut1.rs similarity index 100% rename from tests/compile-fail-fullmir/stacked_borrows/aliasing_mut1.rs rename to tests/compile-fail/stacked_borrows/aliasing_mut1.rs diff --git a/tests/compile-fail-fullmir/stacked_borrows/aliasing_mut2.rs b/tests/compile-fail/stacked_borrows/aliasing_mut2.rs similarity index 100% rename from tests/compile-fail-fullmir/stacked_borrows/aliasing_mut2.rs rename to tests/compile-fail/stacked_borrows/aliasing_mut2.rs diff --git a/tests/compile-fail-fullmir/stacked_borrows/aliasing_mut3.rs b/tests/compile-fail/stacked_borrows/aliasing_mut3.rs similarity index 100% rename from tests/compile-fail-fullmir/stacked_borrows/aliasing_mut3.rs rename to tests/compile-fail/stacked_borrows/aliasing_mut3.rs diff --git a/tests/compile-fail-fullmir/stacked_borrows/aliasing_mut4.rs b/tests/compile-fail/stacked_borrows/aliasing_mut4.rs similarity index 100% rename from tests/compile-fail-fullmir/stacked_borrows/aliasing_mut4.rs rename to tests/compile-fail/stacked_borrows/aliasing_mut4.rs diff --git a/tests/compile-fail-fullmir/stacked_borrows/box_exclusive_violation1.rs b/tests/compile-fail/stacked_borrows/box_exclusive_violation1.rs similarity index 100% rename from tests/compile-fail-fullmir/stacked_borrows/box_exclusive_violation1.rs rename to tests/compile-fail/stacked_borrows/box_exclusive_violation1.rs diff --git a/tests/compile-fail-fullmir/stacked_borrows/buggy_as_mut_slice.rs b/tests/compile-fail/stacked_borrows/buggy_as_mut_slice.rs similarity index 100% rename from tests/compile-fail-fullmir/stacked_borrows/buggy_as_mut_slice.rs rename to tests/compile-fail/stacked_borrows/buggy_as_mut_slice.rs diff --git a/tests/compile-fail-fullmir/stacked_borrows/buggy_split_at_mut.rs b/tests/compile-fail/stacked_borrows/buggy_split_at_mut.rs similarity index 100% rename from tests/compile-fail-fullmir/stacked_borrows/buggy_split_at_mut.rs rename to tests/compile-fail/stacked_borrows/buggy_split_at_mut.rs diff --git a/tests/compile-fail-fullmir/stacked_borrows/deallocate_against_barrier.rs b/tests/compile-fail/stacked_borrows/deallocate_against_barrier.rs similarity index 100% rename from tests/compile-fail-fullmir/stacked_borrows/deallocate_against_barrier.rs rename to tests/compile-fail/stacked_borrows/deallocate_against_barrier.rs diff --git a/tests/compile-fail-fullmir/stacked_borrows/illegal_read1.rs b/tests/compile-fail/stacked_borrows/illegal_read1.rs similarity index 100% rename from tests/compile-fail-fullmir/stacked_borrows/illegal_read1.rs rename to tests/compile-fail/stacked_borrows/illegal_read1.rs diff --git a/tests/compile-fail-fullmir/stacked_borrows/illegal_read2.rs b/tests/compile-fail/stacked_borrows/illegal_read2.rs similarity index 100% rename from tests/compile-fail-fullmir/stacked_borrows/illegal_read2.rs rename to tests/compile-fail/stacked_borrows/illegal_read2.rs diff --git a/tests/compile-fail-fullmir/stacked_borrows/illegal_read3.rs b/tests/compile-fail/stacked_borrows/illegal_read3.rs similarity index 100% rename from tests/compile-fail-fullmir/stacked_borrows/illegal_read3.rs rename to tests/compile-fail/stacked_borrows/illegal_read3.rs diff --git a/tests/compile-fail-fullmir/stacked_borrows/illegal_read4.rs b/tests/compile-fail/stacked_borrows/illegal_read4.rs similarity index 100% rename from tests/compile-fail-fullmir/stacked_borrows/illegal_read4.rs rename to tests/compile-fail/stacked_borrows/illegal_read4.rs diff --git a/tests/compile-fail-fullmir/stacked_borrows/illegal_read5.rs b/tests/compile-fail/stacked_borrows/illegal_read5.rs similarity index 100% rename from tests/compile-fail-fullmir/stacked_borrows/illegal_read5.rs rename to tests/compile-fail/stacked_borrows/illegal_read5.rs diff --git a/tests/compile-fail-fullmir/stacked_borrows/illegal_write1.rs b/tests/compile-fail/stacked_borrows/illegal_write1.rs similarity index 100% rename from tests/compile-fail-fullmir/stacked_borrows/illegal_write1.rs rename to tests/compile-fail/stacked_borrows/illegal_write1.rs diff --git a/tests/compile-fail-fullmir/stacked_borrows/illegal_write2.rs b/tests/compile-fail/stacked_borrows/illegal_write2.rs similarity index 100% rename from tests/compile-fail-fullmir/stacked_borrows/illegal_write2.rs rename to tests/compile-fail/stacked_borrows/illegal_write2.rs diff --git a/tests/compile-fail-fullmir/stacked_borrows/illegal_write3.rs b/tests/compile-fail/stacked_borrows/illegal_write3.rs similarity index 100% rename from tests/compile-fail-fullmir/stacked_borrows/illegal_write3.rs rename to tests/compile-fail/stacked_borrows/illegal_write3.rs diff --git a/tests/compile-fail-fullmir/stacked_borrows/illegal_write4.rs b/tests/compile-fail/stacked_borrows/illegal_write4.rs similarity index 100% rename from tests/compile-fail-fullmir/stacked_borrows/illegal_write4.rs rename to tests/compile-fail/stacked_borrows/illegal_write4.rs diff --git a/tests/compile-fail-fullmir/stacked_borrows/illegal_write5.rs b/tests/compile-fail/stacked_borrows/illegal_write5.rs similarity index 100% rename from tests/compile-fail-fullmir/stacked_borrows/illegal_write5.rs rename to tests/compile-fail/stacked_borrows/illegal_write5.rs diff --git a/tests/compile-fail-fullmir/stacked_borrows/invalidate_against_barrier1.rs b/tests/compile-fail/stacked_borrows/invalidate_against_barrier1.rs similarity index 100% rename from tests/compile-fail-fullmir/stacked_borrows/invalidate_against_barrier1.rs rename to tests/compile-fail/stacked_borrows/invalidate_against_barrier1.rs diff --git a/tests/compile-fail-fullmir/stacked_borrows/invalidate_against_barrier2.rs b/tests/compile-fail/stacked_borrows/invalidate_against_barrier2.rs similarity index 100% rename from tests/compile-fail-fullmir/stacked_borrows/invalidate_against_barrier2.rs rename to tests/compile-fail/stacked_borrows/invalidate_against_barrier2.rs diff --git a/tests/compile-fail-fullmir/stacked_borrows/load_invalid_mut.rs b/tests/compile-fail/stacked_borrows/load_invalid_mut.rs similarity index 100% rename from tests/compile-fail-fullmir/stacked_borrows/load_invalid_mut.rs rename to tests/compile-fail/stacked_borrows/load_invalid_mut.rs diff --git a/tests/compile-fail-fullmir/stacked_borrows/load_invalid_shr.rs b/tests/compile-fail/stacked_borrows/load_invalid_shr.rs similarity index 100% rename from tests/compile-fail-fullmir/stacked_borrows/load_invalid_shr.rs rename to tests/compile-fail/stacked_borrows/load_invalid_shr.rs diff --git a/tests/compile-fail-fullmir/stacked_borrows/mut_exclusive_violation1.rs b/tests/compile-fail/stacked_borrows/mut_exclusive_violation1.rs similarity index 100% rename from tests/compile-fail-fullmir/stacked_borrows/mut_exclusive_violation1.rs rename to tests/compile-fail/stacked_borrows/mut_exclusive_violation1.rs diff --git a/tests/compile-fail-fullmir/stacked_borrows/outdated_local.rs b/tests/compile-fail/stacked_borrows/outdated_local.rs similarity index 100% rename from tests/compile-fail-fullmir/stacked_borrows/outdated_local.rs rename to tests/compile-fail/stacked_borrows/outdated_local.rs diff --git a/tests/compile-fail-fullmir/stacked_borrows/pass_invalid_mut.rs b/tests/compile-fail/stacked_borrows/pass_invalid_mut.rs similarity index 100% rename from tests/compile-fail-fullmir/stacked_borrows/pass_invalid_mut.rs rename to tests/compile-fail/stacked_borrows/pass_invalid_mut.rs diff --git a/tests/compile-fail-fullmir/stacked_borrows/pass_invalid_shr.rs b/tests/compile-fail/stacked_borrows/pass_invalid_shr.rs similarity index 100% rename from tests/compile-fail-fullmir/stacked_borrows/pass_invalid_shr.rs rename to tests/compile-fail/stacked_borrows/pass_invalid_shr.rs diff --git a/tests/compile-fail-fullmir/stacked_borrows/pointer_smuggling.rs b/tests/compile-fail/stacked_borrows/pointer_smuggling.rs similarity index 100% rename from tests/compile-fail-fullmir/stacked_borrows/pointer_smuggling.rs rename to tests/compile-fail/stacked_borrows/pointer_smuggling.rs diff --git a/tests/compile-fail-fullmir/stacked_borrows/return_invalid_mut.rs b/tests/compile-fail/stacked_borrows/return_invalid_mut.rs similarity index 100% rename from tests/compile-fail-fullmir/stacked_borrows/return_invalid_mut.rs rename to tests/compile-fail/stacked_borrows/return_invalid_mut.rs diff --git a/tests/compile-fail-fullmir/stacked_borrows/return_invalid_mut_option.rs b/tests/compile-fail/stacked_borrows/return_invalid_mut_option.rs similarity index 100% rename from tests/compile-fail-fullmir/stacked_borrows/return_invalid_mut_option.rs rename to tests/compile-fail/stacked_borrows/return_invalid_mut_option.rs diff --git a/tests/compile-fail-fullmir/stacked_borrows/return_invalid_mut_tuple.rs b/tests/compile-fail/stacked_borrows/return_invalid_mut_tuple.rs similarity index 100% rename from tests/compile-fail-fullmir/stacked_borrows/return_invalid_mut_tuple.rs rename to tests/compile-fail/stacked_borrows/return_invalid_mut_tuple.rs diff --git a/tests/compile-fail-fullmir/stacked_borrows/return_invalid_shr.rs b/tests/compile-fail/stacked_borrows/return_invalid_shr.rs similarity index 100% rename from tests/compile-fail-fullmir/stacked_borrows/return_invalid_shr.rs rename to tests/compile-fail/stacked_borrows/return_invalid_shr.rs diff --git a/tests/compile-fail-fullmir/stacked_borrows/return_invalid_shr_option.rs b/tests/compile-fail/stacked_borrows/return_invalid_shr_option.rs similarity index 100% rename from tests/compile-fail-fullmir/stacked_borrows/return_invalid_shr_option.rs rename to tests/compile-fail/stacked_borrows/return_invalid_shr_option.rs diff --git a/tests/compile-fail-fullmir/stacked_borrows/return_invalid_shr_tuple.rs b/tests/compile-fail/stacked_borrows/return_invalid_shr_tuple.rs similarity index 100% rename from tests/compile-fail-fullmir/stacked_borrows/return_invalid_shr_tuple.rs rename to tests/compile-fail/stacked_borrows/return_invalid_shr_tuple.rs diff --git a/tests/compile-fail-fullmir/stacked_borrows/shr_frozen_violation1.rs b/tests/compile-fail/stacked_borrows/shr_frozen_violation1.rs similarity index 100% rename from tests/compile-fail-fullmir/stacked_borrows/shr_frozen_violation1.rs rename to tests/compile-fail/stacked_borrows/shr_frozen_violation1.rs diff --git a/tests/compile-fail-fullmir/stacked_borrows/static_memory_modification.rs b/tests/compile-fail/stacked_borrows/static_memory_modification.rs similarity index 100% rename from tests/compile-fail-fullmir/stacked_borrows/static_memory_modification.rs rename to tests/compile-fail/stacked_borrows/static_memory_modification.rs diff --git a/tests/compile-fail-fullmir/stacked_borrows/transmute-is-no-escape.rs b/tests/compile-fail/stacked_borrows/transmute-is-no-escape.rs similarity index 100% rename from tests/compile-fail-fullmir/stacked_borrows/transmute-is-no-escape.rs rename to tests/compile-fail/stacked_borrows/transmute-is-no-escape.rs diff --git a/tests/compile-fail-fullmir/stacked_borrows/unescaped_local.rs b/tests/compile-fail/stacked_borrows/unescaped_local.rs similarity index 100% rename from tests/compile-fail-fullmir/stacked_borrows/unescaped_local.rs rename to tests/compile-fail/stacked_borrows/unescaped_local.rs diff --git a/tests/compile-fail-fullmir/transmute-pair-undef.rs b/tests/compile-fail/transmute-pair-undef.rs similarity index 100% rename from tests/compile-fail-fullmir/transmute-pair-undef.rs rename to tests/compile-fail/transmute-pair-undef.rs diff --git a/tests/compiletest.rs b/tests/compiletest.rs index 1c11d07c1bcc5..f0ebbf6b071bd 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -1,4 +1,5 @@ #![feature(slice_concat_ext, custom_test_frameworks)] +// Custom test runner, to avoid libtest being wrapped around compiletest which wraps libtest. #![test_runner(test_runner)] use std::slice::SliceConcatExt; @@ -24,11 +25,6 @@ fn rustc_lib_path() -> PathBuf { option_env!("RUSTC_LIB_PATH").unwrap().into() } -fn have_fullmir() -> bool { - // We assume we have full MIR when MIRI_SYSROOT is set or when we are in rustc - std::env::var("MIRI_SYSROOT").is_ok() || rustc_test_suite().is_some() -} - fn mk_config(mode: &str) -> compiletest::common::ConfigWithTemp { let mut config = compiletest::Config::default().tempdir(); config.mode = mode.parse().expect("Invalid mode"); @@ -41,16 +37,7 @@ fn mk_config(mode: &str) -> compiletest::common::ConfigWithTemp { config } -fn compile_fail(sysroot: &Path, path: &str, target: &str, host: &str, need_fullmir: bool, opt: bool) { - if need_fullmir && !have_fullmir() { - eprintln!("{}\n", format!( - "## Skipping compile-fail tests in {} against miri for target {} due to missing mir", - path, - target - ).yellow().bold()); - return; - } - +fn compile_fail(sysroot: &Path, path: &str, target: &str, host: &str, opt: bool) { let opt_str = if opt { " with optimizations" } else { "" }; eprintln!("{}", format!( "## Running compile-fail tests in {} against miri for target {}{}", @@ -78,16 +65,7 @@ fn compile_fail(sysroot: &Path, path: &str, target: &str, host: &str, need_fullm compiletest::run_tests(&config); } -fn miri_pass(sysroot: &Path, path: &str, target: &str, host: &str, need_fullmir: bool, opt: bool) { - if need_fullmir && !have_fullmir() { - eprintln!("{}\n", format!( - "## Skipping run-pass tests in {} against miri for target {} due to missing mir", - path, - target - ).yellow().bold()); - return; - } - +fn miri_pass(sysroot: &Path, path: &str, target: &str, host: &str, opt: bool) { let opt_str = if opt { " with optimizations" } else { "" }; eprintln!("{}", format!( "## Running run-pass tests in {} against miri for target {}{}", @@ -105,10 +83,6 @@ fn miri_pass(sysroot: &Path, path: &str, target: &str, host: &str, need_fullmir: // whitelist. flags.push("-Zmir-opt-level=1".to_owned()); } - if !have_fullmir() { - // FIXME: Validation relies on the EscapeToRaw statements being emitted - flags.push("-Zmiri-disable-validation".to_owned()); - } let mut config = mk_config("ui"); config.src_base = PathBuf::from(path); @@ -132,7 +106,7 @@ fn target_has_std>(path: P) -> bool { .map(|entry| entry.unwrap()) .filter(|entry| entry.file_type().unwrap().is_file()) .filter_map(|entry| entry.file_name().into_string().ok()) - .any(|file_name| file_name.starts_with("libstd") && file_name.ends_with(".rlib")) + .any(|file_name| file_name == "libstd.rlib") } @@ -186,18 +160,17 @@ fn run_pass_miri(opt: bool) { let host = get_host(); for_all_targets(&sysroot, |target| { - miri_pass(&sysroot, "tests/run-pass", &target, &host, false, opt); + miri_pass(&sysroot, "tests/run-pass", &target, &host, opt); }); - miri_pass(&sysroot, "tests/run-pass-fullmir", &host, &host, true, opt); } fn compile_fail_miri(opt: bool) { let sysroot = get_sysroot(); let host = get_host(); - // FIXME: run tests for other targets, too - compile_fail(&sysroot, "tests/compile-fail", &host, &host, false, opt); - compile_fail(&sysroot, "tests/compile-fail-fullmir", &host, &host, true, opt); + for_all_targets(&sysroot, |target| { + compile_fail(&sysroot, "tests/compile-fail", &target, &host, opt); + }); } fn test_runner(_tests: &[&()]) { diff --git a/tests/run-pass-fullmir/async-fn.rs b/tests/run-pass/async-fn.rs similarity index 100% rename from tests/run-pass-fullmir/async-fn.rs rename to tests/run-pass/async-fn.rs diff --git a/tests/run-pass-fullmir/box-pair-to-vec.rs b/tests/run-pass/box-pair-to-vec.rs similarity index 100% rename from tests/run-pass-fullmir/box-pair-to-vec.rs rename to tests/run-pass/box-pair-to-vec.rs diff --git a/tests/run-pass-fullmir/box-pair-to-vec.stdout b/tests/run-pass/box-pair-to-vec.stdout similarity index 100% rename from tests/run-pass-fullmir/box-pair-to-vec.stdout rename to tests/run-pass/box-pair-to-vec.stdout diff --git a/tests/run-pass-fullmir/catch.rs b/tests/run-pass/catch.rs similarity index 100% rename from tests/run-pass-fullmir/catch.rs rename to tests/run-pass/catch.rs diff --git a/tests/run-pass-fullmir/catch.stdout b/tests/run-pass/catch.stdout similarity index 100% rename from tests/run-pass-fullmir/catch.stdout rename to tests/run-pass/catch.stdout diff --git a/tests/run-pass-fullmir/env.rs b/tests/run-pass/env.rs similarity index 100% rename from tests/run-pass-fullmir/env.rs rename to tests/run-pass/env.rs diff --git a/tests/run-pass-fullmir/foreign-fn-linkname.rs b/tests/run-pass/foreign-fn-linkname.rs similarity index 100% rename from tests/run-pass-fullmir/foreign-fn-linkname.rs rename to tests/run-pass/foreign-fn-linkname.rs diff --git a/tests/run-pass-fullmir/format.rs b/tests/run-pass/format.rs similarity index 100% rename from tests/run-pass-fullmir/format.rs rename to tests/run-pass/format.rs diff --git a/tests/run-pass-fullmir/format.stdout b/tests/run-pass/format.stdout similarity index 100% rename from tests/run-pass-fullmir/format.stdout rename to tests/run-pass/format.stdout diff --git a/tests/run-pass-fullmir/from_utf8.rs b/tests/run-pass/from_utf8.rs similarity index 100% rename from tests/run-pass-fullmir/from_utf8.rs rename to tests/run-pass/from_utf8.rs diff --git a/tests/run-pass-fullmir/hashmap.rs b/tests/run-pass/hashmap.rs similarity index 100% rename from tests/run-pass-fullmir/hashmap.rs rename to tests/run-pass/hashmap.rs diff --git a/tests/run-pass-fullmir/hello.rs b/tests/run-pass/hello.rs similarity index 100% rename from tests/run-pass-fullmir/hello.rs rename to tests/run-pass/hello.rs diff --git a/tests/run-pass-fullmir/hello.stdout b/tests/run-pass/hello.stdout similarity index 100% rename from tests/run-pass-fullmir/hello.stdout rename to tests/run-pass/hello.stdout diff --git a/tests/run-pass-fullmir/integer-ops.rs b/tests/run-pass/integer-ops.rs similarity index 100% rename from tests/run-pass-fullmir/integer-ops.rs rename to tests/run-pass/integer-ops.rs diff --git a/tests/run-pass-fullmir/issue-3794.rs b/tests/run-pass/issue-3794.rs similarity index 100% rename from tests/run-pass-fullmir/issue-3794.rs rename to tests/run-pass/issue-3794.rs diff --git a/tests/run-pass-fullmir/issue-3794.stdout b/tests/run-pass/issue-3794.stdout similarity index 100% rename from tests/run-pass-fullmir/issue-3794.stdout rename to tests/run-pass/issue-3794.stdout diff --git a/tests/run-pass-fullmir/loop-break-value.rs b/tests/run-pass/loop-break-value.rs similarity index 100% rename from tests/run-pass-fullmir/loop-break-value.rs rename to tests/run-pass/loop-break-value.rs diff --git a/tests/run-pass-fullmir/memchr.rs b/tests/run-pass/memchr.rs similarity index 100% rename from tests/run-pass-fullmir/memchr.rs rename to tests/run-pass/memchr.rs diff --git a/tests/run-pass-fullmir/send-is-not-static-par-for.rs b/tests/run-pass/send-is-not-static-par-for.rs similarity index 100% rename from tests/run-pass-fullmir/send-is-not-static-par-for.rs rename to tests/run-pass/send-is-not-static-par-for.rs diff --git a/tests/run-pass-fullmir/threads.rs b/tests/run-pass/threads.rs similarity index 100% rename from tests/run-pass-fullmir/threads.rs rename to tests/run-pass/threads.rs diff --git a/tests/run-pass-fullmir/u128.rs b/tests/run-pass/u128.rs similarity index 100% rename from tests/run-pass-fullmir/u128.rs rename to tests/run-pass/u128.rs diff --git a/tests/run-pass-fullmir/unsized-tuple-impls.rs b/tests/run-pass/unsized-tuple-impls.rs similarity index 100% rename from tests/run-pass-fullmir/unsized-tuple-impls.rs rename to tests/run-pass/unsized-tuple-impls.rs diff --git a/tests/run-pass-fullmir/vecdeque.rs b/tests/run-pass/vecdeque.rs similarity index 100% rename from tests/run-pass-fullmir/vecdeque.rs rename to tests/run-pass/vecdeque.rs From 4d767e1f415967a4ff58a2e88905d5c9f9c98453 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 10 Dec 2018 10:10:03 +0100 Subject: [PATCH 0465/3747] MIRI_SYSROOT is no longer needed for development agains a locally built rustc --- README.md | 3 --- 1 file changed, 3 deletions(-) diff --git a/README.md b/README.md index 5f8f8fb8502f0..1b9e5304bd037 100644 --- a/README.md +++ b/README.md @@ -133,9 +133,6 @@ cp config.toml.example config.toml rustup toolchain link custom build/x86_64-unknown-linux-gnu/stage2 # Now cd to your Miri directory, then configure rustup rustup override set custom -# We also need to tell Miri where to find its sysroot. Since we set -# `test-miri` above, we can just use rustc' sysroot. -export MIRI_SYSROOT=$(rustc --print sysroot) ``` With this, you should now have a working development setup! See From b8e6af49d946b123181a15f34a7c0dad24a48d5e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 10 Dec 2018 10:52:59 +0100 Subject: [PATCH 0466/3747] fix setting the manifest path manually when using cargo miri --- src/bin/cargo-miri.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 68da028a81c64..8a1a9d0554abe 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -75,7 +75,9 @@ fn get_arg_flag_value(name: &str) -> Option { fn list_targets() -> impl Iterator { // We need to get the manifest, and then the metadata, to enumerate targets. - let manifest_path = get_arg_flag_value("--manifest-path").map(PathBuf::from); + let manifest_path = get_arg_flag_value("--manifest-path").map(|m| + Path::new(&m).canonicalize().unwrap() + ); let mut metadata = if let Ok(metadata) = cargo_metadata::metadata( manifest_path.as_ref().map(AsRef::as_ref), From b50662d68c886de44628e7ce55e331515df6c5e0 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 10 Dec 2018 10:19:44 +0100 Subject: [PATCH 0467/3747] fix CI --- .travis.yml | 16 +++++++++++----- appveyor.yml | 5 ++--- src/bin/cargo-miri.rs | 9 ++++----- src/fn_call.rs | 2 ++ 4 files changed, 19 insertions(+), 13 deletions(-) diff --git a/.travis.yml b/.travis.yml index ac3f16ce13530..1d49394e29b8e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,13 +9,16 @@ cache: os: - linux - osx +dist: xenial before_script: +# install extra stuff for cross-compilation +- if [[ "$TRAVIS_OS_NAME" == linux ]]; then sudo apt update && sudo apt install gcc-multilib; fi # macOS weirdness (https://github.com/travis-ci/travis-ci/issues/6307, https://github.com/travis-ci/travis-ci/issues/10165) - if [[ "$TRAVIS_OS_NAME" == osx ]]; then rvm get stable; fi # Compute the rust version we use. We do not use "language: rust" to have more control here. - | - if [ "$TRAVIS_EVENT_TYPE" = cron ]; then + if [[ "$TRAVIS_EVENT_TYPE" == cron ]]; then RUST_TOOLCHAIN=nightly else RUST_TOOLCHAIN=$(cat rust-version) @@ -24,7 +27,7 @@ before_script: if [ "$TRAVIS_OS_NAME" == osx ]; then export MIRI_SYSROOT_BASE=~/Library/Caches/miri.miri.miri/ else - export MIRI_SYSROOT_BASE=~/.cache/miri/HOST + export MIRI_SYSROOT_BASE=~/.cache/miri/ fi # install Rust - curl https://build.travis-ci.org/files/rustup-init.sh -sSf | sh -s -- -y --default-toolchain "$RUST_TOOLCHAIN" @@ -38,10 +41,13 @@ script: cargo build --release --all-features --all-targets && cargo install --all-features --force --path . - | - # Get ourselves a MIR-full libstd + # Get ourselves a MIR-full libstd for the host and a foreign architecture cargo miri setup && - cargo miri setup --target i686-unknown-linux-gnu && - cargo miri setup --target i686-apple-darwin + if [[ "$TRAVIS_OS_NAME" == osx ]]; then + cargo miri setup --target i686-apple-darwin + else + cargo miri setup --target i686-unknown-linux-gnu + fi - | # Test miri with full MIR, on the host and other architectures MIRI_SYSROOT=$MIRI_SYSROOT_BASE/HOST cargo test --release --all-features && diff --git a/appveyor.yml b/appveyor.yml index 1f38b848c0059..4f4aebd807915 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -27,13 +27,12 @@ build: false test_script: - set RUSTFLAGS=-g - set RUST_BACKTRACE=1 - # Test plain miri + # Build miri - cargo build --release --all-features --all-targets - - cargo test --release --all-features # Get ourselves a MIR-full libstd, and use it henceforth - cargo run --release --all-features --bin cargo-miri -- miri setup - set MIRI_SYSROOT=%USERPROFILE%\AppData\Local\miri\miri\cache\HOST - # Test miri with full MIR + # Test miri - cargo test --release --all-features notifications: diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 8a1a9d0554abe..7e1785fd3b938 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -342,11 +342,11 @@ fn main() { .collect() }; args.splice(0..0, miri::miri_default_args().iter().map(ToString::to_string)); + args.extend_from_slice(&["--cfg".to_owned(), r#"feature="cargo-miri""#.to_owned()]); // this check ensures that dependencies are built but not interpreted and the final crate is // interpreted but not built let miri_enabled = std::env::args().any(|s| s == "--emit=dep-info,metadata"); - let mut command = if miri_enabled { let mut path = std::env::current_exe().expect("current executable path invalid"); path.set_file_name("miri"); @@ -354,10 +354,9 @@ fn main() { } else { Command::new("rustc") }; + command.args(&args); - args.extend_from_slice(&["--cfg".to_owned(), r#"feature="cargo-miri""#.to_owned()]); - - match command.args(&args).status() { + match command.status() { Ok(exit) => { if !exit.success() { std::process::exit(exit.code().unwrap_or(42)); @@ -388,7 +387,7 @@ where args.push(r#"feature="cargo-miri""#.to_owned()); let path = std::env::current_exe().expect("current executable path invalid"); - let exit_status = std::process::Command::new("cargo") + let exit_status = Command::new("cargo") .args(&args) .env("RUSTC", path) .spawn() diff --git a/src/fn_call.rs b/src/fn_call.rs index e9d3255a5b325..701dc8ca92ca2 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -113,6 +113,8 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo Some(name) => name.as_str(), None => self.tcx.item_name(def_id).as_str(), }; + // Strip linker suffixes (seen on 32bit macOS) + let link_name = link_name.trim_end_matches("$UNIX2003"); let tcx = &{self.tcx.tcx}; From 05f2b2ed3da6f504ac31d61e8bffb9a989780847 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 10 Dec 2018 12:26:20 +0100 Subject: [PATCH 0468/3747] remove support for not having libstd MIR --- src/fn_call.rs | 84 +------------------------------- src/lib.rs | 128 +++++++++++++++++++++---------------------------- 2 files changed, 56 insertions(+), 156 deletions(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index 701dc8ca92ca2..e28497aa256fc 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -17,18 +17,6 @@ pub trait EvalContextExt<'tcx, 'mir> { ret: mir::BasicBlock, ) -> EvalResult<'tcx>; - /// Emulate a function that should have MIR but does not. - /// This is solely to support execution without full MIR. - /// Fail if emulating this function is not supported. - /// This function will handle `goto_block` if needed. - fn emulate_missing_fn( - &mut self, - path: String, - args: &[OpTy<'tcx, Borrow>], - dest: Option>, - ret: Option, - ) -> EvalResult<'tcx>; - fn find_fn( &mut self, instance: ty::Instance<'tcx>, @@ -81,24 +69,8 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo return Ok(None); } - // Otherwise we really want to see the MIR -- but if we do not have it, maybe we can - // emulate something. This is a HACK to support running without a full-MIR libstd. - let mir = match self.load_mir(instance.def) { - Ok(mir) => mir, - Err(EvalError { kind: EvalErrorKind::NoMirFor(path), .. }) => { - self.emulate_missing_fn( - path, - args, - dest, - ret, - )?; - // `goto_block` already handled - return Ok(None); - } - Err(other) => return Err(other), - }; - - Ok(Some(mir)) + // Otherwise, load the MIR + Ok(Some(self.load_mir(instance.def)?)) } fn emulate_foreign_item( @@ -657,58 +629,6 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo Ok(()) } - fn emulate_missing_fn( - &mut self, - path: String, - _args: &[OpTy<'tcx, Borrow>], - dest: Option>, - ret: Option, - ) -> EvalResult<'tcx> { - // In some cases in non-MIR libstd-mode, not having a destination is legit. Handle these early. - match &path[..] { - "std::panicking::rust_panic_with_hook" | - "core::panicking::panic_fmt::::panic_impl" | - "std::rt::begin_panic_fmt" => - return err!(MachineError("the evaluated program panicked".to_string())), - _ => {} - } - - let dest = dest.ok_or_else( - // Must be some function we do not support - || EvalErrorKind::NoMirFor(path.clone()), - )?; - - match &path[..] { - // A Rust function is missing, which means we are running with MIR missing for libstd (or other dependencies). - // Still, we can make many things mostly work by "emulating" or ignoring some functions. - "std::io::_print" | - "std::io::_eprint" => { - warn!( - "Ignoring output. To run programs that prints, make sure you have a libstd with full MIR." - ); - } - "std::thread::Builder::new" => { - return err!(Unimplemented("miri does not support threading".to_owned())) - } - "std::env::args" => { - return err!(Unimplemented( - "miri does not support program arguments".to_owned(), - )) - } - "std::panicking::panicking" | - "std::rt::panicking" => { - // we abort on panic -> `std::rt::panicking` always returns false - self.write_scalar(Scalar::from_bool(false), dest)?; - } - - _ => return err!(NoMirFor(path)), - } - - self.goto_block(ret)?; - self.dump_place(*dest); - Ok(()) - } - fn write_null(&mut self, dest: PlaceTy<'tcx, Borrow>) -> EvalResult<'tcx> { self.write_scalar(Scalar::from_int(0, dest.layout.size), dest) } diff --git a/src/lib.rs b/src/lib.rs index 71abff2675e3c..9641670a2edfb 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -80,82 +80,62 @@ pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( )); } - let libstd_has_mir = { - let rustc_panic = ecx.resolve_path(&["std", "panicking", "rust_panic"])?; - ecx.load_mir(rustc_panic.def).is_ok() - }; - - if libstd_has_mir { - let start_id = tcx.lang_items().start_fn().unwrap(); - let main_ret_ty = tcx.fn_sig(main_id).output(); - let main_ret_ty = main_ret_ty.no_bound_vars().unwrap(); - let start_instance = ty::Instance::resolve( - ecx.tcx.tcx, - ty::ParamEnv::reveal_all(), - start_id, - ecx.tcx.mk_substs( - ::std::iter::once(ty::subst::Kind::from(main_ret_ty))) - ).unwrap(); - let start_mir = ecx.load_mir(start_instance.def)?; - - if start_mir.arg_count != 3 { - return err!(AbiViolation(format!( - "'start' lang item should have three arguments, but has {}", - start_mir.arg_count - ))); - } - - // Return value (in static memory so that it does not count as leak) - let ret = ecx.layout_of(start_mir.return_ty())?; - let ret_ptr = ecx.allocate(ret, MiriMemoryKind::MutStatic.into())?; - - // Push our stack frame - ecx.push_stack_frame( - start_instance, - DUMMY_SP, // there is no call site, we want no span - start_mir, - Some(ret_ptr.into()), - StackPopCleanup::None { cleanup: true }, - )?; - - let mut args = ecx.frame().mir.args_iter(); - - // First argument: pointer to main() - let main_ptr = ecx.memory_mut().create_fn_alloc(main_instance).with_default_tag(); - let dest = ecx.eval_place(&mir::Place::Local(args.next().unwrap()))?; - ecx.write_scalar(Scalar::Ptr(main_ptr), dest)?; - - // Second argument (argc): 1 - let dest = ecx.eval_place(&mir::Place::Local(args.next().unwrap()))?; - ecx.write_scalar(Scalar::from_int(1, dest.layout.size), dest)?; - - // FIXME: extract main source file path - // Third argument (argv): &[b"foo"] - let dest = ecx.eval_place(&mir::Place::Local(args.next().unwrap()))?; - let foo = ecx.memory_mut().allocate_static_bytes(b"foo\0").with_default_tag(); - let foo_ty = ecx.tcx.mk_imm_ptr(ecx.tcx.types.u8); - let foo_layout = ecx.layout_of(foo_ty)?; - let foo_place = ecx.allocate(foo_layout, MiriMemoryKind::Env.into())?; - ecx.write_scalar(Scalar::Ptr(foo), foo_place.into())?; - ecx.memory_mut().mark_immutable(foo_place.to_ptr()?.alloc_id)?; - ecx.write_scalar(foo_place.ptr, dest)?; - - assert!(args.next().is_none(), "start lang item has more arguments than expected"); - } else { - let ret_place = MPlaceTy::dangling(ecx.layout_of(tcx.mk_unit())?, &ecx).into(); - ecx.push_stack_frame( - main_instance, - DUMMY_SP, // there is no call site, we want no span - main_mir, - Some(ret_place), - StackPopCleanup::None { cleanup: true }, - )?; - - // No arguments - let mut args = ecx.frame().mir.args_iter(); - assert!(args.next().is_none(), "main function must not have arguments"); + let start_id = tcx.lang_items().start_fn().unwrap(); + let main_ret_ty = tcx.fn_sig(main_id).output(); + let main_ret_ty = main_ret_ty.no_bound_vars().unwrap(); + let start_instance = ty::Instance::resolve( + ecx.tcx.tcx, + ty::ParamEnv::reveal_all(), + start_id, + ecx.tcx.mk_substs( + ::std::iter::once(ty::subst::Kind::from(main_ret_ty))) + ).unwrap(); + let start_mir = ecx.load_mir(start_instance.def)?; + + if start_mir.arg_count != 3 { + return err!(AbiViolation(format!( + "'start' lang item should have three arguments, but has {}", + start_mir.arg_count + ))); } + // Return value (in static memory so that it does not count as leak) + let ret = ecx.layout_of(start_mir.return_ty())?; + let ret_ptr = ecx.allocate(ret, MiriMemoryKind::MutStatic.into())?; + + // Push our stack frame + ecx.push_stack_frame( + start_instance, + DUMMY_SP, // there is no call site, we want no span + start_mir, + Some(ret_ptr.into()), + StackPopCleanup::None { cleanup: true }, + )?; + + let mut args = ecx.frame().mir.args_iter(); + + // First argument: pointer to main() + let main_ptr = ecx.memory_mut().create_fn_alloc(main_instance).with_default_tag(); + let dest = ecx.eval_place(&mir::Place::Local(args.next().unwrap()))?; + ecx.write_scalar(Scalar::Ptr(main_ptr), dest)?; + + // Second argument (argc): 1 + let dest = ecx.eval_place(&mir::Place::Local(args.next().unwrap()))?; + ecx.write_scalar(Scalar::from_int(1, dest.layout.size), dest)?; + + // FIXME: extract main source file path + // Third argument (argv): &[b"foo"] + let dest = ecx.eval_place(&mir::Place::Local(args.next().unwrap()))?; + let foo = ecx.memory_mut().allocate_static_bytes(b"foo\0").with_default_tag(); + let foo_ty = ecx.tcx.mk_imm_ptr(ecx.tcx.types.u8); + let foo_layout = ecx.layout_of(foo_ty)?; + let foo_place = ecx.allocate(foo_layout, MiriMemoryKind::Env.into())?; + ecx.write_scalar(Scalar::Ptr(foo), foo_place.into())?; + ecx.memory_mut().mark_immutable(foo_place.to_ptr()?.alloc_id)?; + ecx.write_scalar(foo_place.ptr, dest)?; + + assert!(args.next().is_none(), "start lang item has more arguments than expected"); + Ok(ecx) } From 5689366a0d47ced0e7ed85abed168493d82555c5 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 10 Dec 2018 13:14:46 +0100 Subject: [PATCH 0469/3747] use rustc_version also to parse host in compiletest --- tests/compiletest.rs | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/tests/compiletest.rs b/tests/compiletest.rs index f0ebbf6b071bd..7187a3caee25c 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -142,17 +142,15 @@ fn get_sysroot() -> PathBuf { fn get_host() -> String { let rustc = rustc_test_suite().unwrap_or(PathBuf::from("rustc")); - let host = std::process::Command::new(rustc) + let rustc_version = std::process::Command::new(rustc) .arg("-vV") .output() .expect("rustc not found for -vV") .stdout; - let host = std::str::from_utf8(&host).expect("sysroot is not utf8"); - let host = host.split("\nhost: ").nth(1).expect( - "no host: part in rustc -vV", - ); - let host = host.split('\n').next().expect("no \n after host"); - String::from(host) + let rustc_version = std::str::from_utf8(&rustc_version).expect("rustc -vV is not utf8"); + let version_meta = rustc_version::version_meta_for(&rustc_version) + .expect("failed to parse rustc version info"); + version_meta.host } fn run_pass_miri(opt: bool) { From 9de605b32f830ece9abaf3476bba418ab3b3d213 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 11 Dec 2018 14:16:58 +0100 Subject: [PATCH 0470/3747] avoid repeating signatures in EvalContext extension traits --- src/fn_call.rs | 337 +++++++++++++++++++---------------------- src/helpers.rs | 45 +++--- src/intrinsic.rs | 239 ++++++++++++++--------------- src/lib.rs | 15 ++ src/stacked_borrows.rs | 100 ++++-------- src/tls.rs | 28 ++-- 6 files changed, 352 insertions(+), 412 deletions(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index e28497aa256fc..ea913417a56e0 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -6,29 +6,8 @@ use syntax::attr; use crate::*; -pub trait EvalContextExt<'tcx, 'mir> { - /// Emulate calling a foreign item, fail if the item is not supported. - /// This function will handle `goto_block` if needed. - fn emulate_foreign_item( - &mut self, - def_id: DefId, - args: &[OpTy<'tcx, Borrow>], - dest: PlaceTy<'tcx, Borrow>, - ret: mir::BasicBlock, - ) -> EvalResult<'tcx>; - - fn find_fn( - &mut self, - instance: ty::Instance<'tcx>, - args: &[OpTy<'tcx, Borrow>], - dest: Option>, - ret: Option, - ) -> EvalResult<'tcx, Option<&'mir mir::Mir<'tcx>>>; - - fn write_null(&mut self, dest: PlaceTy<'tcx, Borrow>) -> EvalResult<'tcx>; -} - -impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalContext<'a, 'mir, 'tcx> { +impl<'a, 'mir, 'tcx> EvalContextExt<'a, 'mir, 'tcx> for crate::MiriEvalContext<'a, 'mir, 'tcx> {} +pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, 'mir, 'tcx> { fn find_fn( &mut self, instance: ty::Instance<'tcx>, @@ -36,30 +15,31 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo dest: Option>, ret: Option, ) -> EvalResult<'tcx, Option<&'mir mir::Mir<'tcx>>> { + let this = self.eval_context_mut(); trace!("eval_fn_call: {:#?}, {:?}", instance, dest.map(|place| *place)); // first run the common hooks also supported by CTFE - if self.hook_fn(instance, args, dest)? { - self.goto_block(ret)?; + if this.hook_fn(instance, args, dest)? { + this.goto_block(ret)?; return Ok(None); } // there are some more lang items we want to hook that CTFE does not hook (yet) - if self.tcx.lang_items().align_offset_fn() == Some(instance.def.def_id()) { + if this.tcx.lang_items().align_offset_fn() == Some(instance.def.def_id()) { // FIXME: return a real value in case the target allocation has an // alignment bigger than the one requested let n = u128::max_value(); let dest = dest.unwrap(); - let n = self.truncate(n, dest.layout); - self.write_scalar(Scalar::from_uint(n, dest.layout.size), dest)?; - self.goto_block(ret)?; + let n = this.truncate(n, dest.layout); + this.write_scalar(Scalar::from_uint(n, dest.layout.size), dest)?; + this.goto_block(ret)?; return Ok(None); } // Try to see if we can do something about foreign items - if self.tcx.is_foreign_item(instance.def_id()) { + if this.tcx.is_foreign_item(instance.def_id()) { // An external function that we cannot find MIR for, but we can still run enough // of them to make miri viable. - self.emulate_foreign_item( + this.emulate_foreign_item( instance.def_id(), args, dest.unwrap(), @@ -70,9 +50,11 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo } // Otherwise, load the MIR - Ok(Some(self.load_mir(instance.def)?)) + Ok(Some(this.load_mir(instance.def)?)) } + /// Emulate calling a foreign item, fail if the item is not supported. + /// This function will handle `goto_block` if needed. fn emulate_foreign_item( &mut self, def_id: DefId, @@ -80,15 +62,16 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo dest: PlaceTy<'tcx, Borrow>, ret: mir::BasicBlock, ) -> EvalResult<'tcx> { - let attrs = self.tcx.get_attrs(def_id); + let this = self.eval_context_mut(); + let attrs = this.tcx.get_attrs(def_id); let link_name = match attr::first_attr_value_str_by_name(&attrs, "link_name") { Some(name) => name.as_str(), - None => self.tcx.item_name(def_id).as_str(), + None => this.tcx.item_name(def_id).as_str(), }; // Strip linker suffixes (seen on 32bit macOS) let link_name = link_name.trim_end_matches("$UNIX2003"); - let tcx = &{self.tcx.tcx}; + let tcx = &{this.tcx.tcx}; // All these functions take raw pointers, so if we access memory directly // (as opposed to through a place), we have to remember to erase any tag @@ -96,20 +79,20 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo match &link_name[..] { "malloc" => { - let size = self.read_scalar(args[0])?.to_usize(self)?; + let size = this.read_scalar(args[0])?.to_usize(this)?; if size == 0 { - self.write_null(dest)?; + this.write_null(dest)?; } else { - let align = self.tcx.data_layout.pointer_align.abi; - let ptr = self.memory_mut().allocate(Size::from_bytes(size), align, MiriMemoryKind::C.into())?; - self.write_scalar(Scalar::Ptr(ptr.with_default_tag()), dest)?; + let align = this.tcx.data_layout.pointer_align.abi; + let ptr = this.memory_mut().allocate(Size::from_bytes(size), align, MiriMemoryKind::C.into())?; + this.write_scalar(Scalar::Ptr(ptr.with_default_tag()), dest)?; } } "free" => { - let ptr = self.read_scalar(args[0])?.not_undef()?; - if !ptr.is_null_ptr(self) { - self.memory_mut().deallocate( + let ptr = this.read_scalar(args[0])?.not_undef()?; + if !ptr.is_null_ptr(this) { + this.memory_mut().deallocate( ptr.to_ptr()?, None, MiriMemoryKind::C.into(), @@ -118,72 +101,72 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo } "__rust_alloc" => { - let size = self.read_scalar(args[0])?.to_usize(self)?; - let align = self.read_scalar(args[1])?.to_usize(self)?; + let size = this.read_scalar(args[0])?.to_usize(this)?; + let align = this.read_scalar(args[1])?.to_usize(this)?; if size == 0 { return err!(HeapAllocZeroBytes); } if !align.is_power_of_two() { return err!(HeapAllocNonPowerOfTwoAlignment(align)); } - let ptr = self.memory_mut() + let ptr = this.memory_mut() .allocate( Size::from_bytes(size), Align::from_bytes(align).unwrap(), MiriMemoryKind::Rust.into() )? .with_default_tag(); - self.write_scalar(Scalar::Ptr(ptr), dest)?; + this.write_scalar(Scalar::Ptr(ptr), dest)?; } "__rust_alloc_zeroed" => { - let size = self.read_scalar(args[0])?.to_usize(self)?; - let align = self.read_scalar(args[1])?.to_usize(self)?; + let size = this.read_scalar(args[0])?.to_usize(this)?; + let align = this.read_scalar(args[1])?.to_usize(this)?; if size == 0 { return err!(HeapAllocZeroBytes); } if !align.is_power_of_two() { return err!(HeapAllocNonPowerOfTwoAlignment(align)); } - let ptr = self.memory_mut() + let ptr = this.memory_mut() .allocate( Size::from_bytes(size), Align::from_bytes(align).unwrap(), MiriMemoryKind::Rust.into() )? .with_default_tag(); - self.memory_mut() + this.memory_mut() .get_mut(ptr.alloc_id)? .write_repeat(tcx, ptr, 0, Size::from_bytes(size))?; - self.write_scalar(Scalar::Ptr(ptr), dest)?; + this.write_scalar(Scalar::Ptr(ptr), dest)?; } "__rust_dealloc" => { - let ptr = self.read_scalar(args[0])?.to_ptr()?; - let old_size = self.read_scalar(args[1])?.to_usize(self)?; - let align = self.read_scalar(args[2])?.to_usize(self)?; + let ptr = this.read_scalar(args[0])?.to_ptr()?; + let old_size = this.read_scalar(args[1])?.to_usize(this)?; + let align = this.read_scalar(args[2])?.to_usize(this)?; if old_size == 0 { return err!(HeapAllocZeroBytes); } if !align.is_power_of_two() { return err!(HeapAllocNonPowerOfTwoAlignment(align)); } - self.memory_mut().deallocate( + this.memory_mut().deallocate( ptr, Some((Size::from_bytes(old_size), Align::from_bytes(align).unwrap())), MiriMemoryKind::Rust.into(), )?; } "__rust_realloc" => { - let ptr = self.read_scalar(args[0])?.to_ptr()?; - let old_size = self.read_scalar(args[1])?.to_usize(self)?; - let align = self.read_scalar(args[2])?.to_usize(self)?; - let new_size = self.read_scalar(args[3])?.to_usize(self)?; + let ptr = this.read_scalar(args[0])?.to_ptr()?; + let old_size = this.read_scalar(args[1])?.to_usize(this)?; + let align = this.read_scalar(args[2])?.to_usize(this)?; + let new_size = this.read_scalar(args[3])?.to_usize(this)?; if old_size == 0 || new_size == 0 { return err!(HeapAllocZeroBytes); } if !align.is_power_of_two() { return err!(HeapAllocNonPowerOfTwoAlignment(align)); } - let new_ptr = self.memory_mut().reallocate( + let new_ptr = this.memory_mut().reallocate( ptr, Size::from_bytes(old_size), Align::from_bytes(align).unwrap(), @@ -191,7 +174,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo Align::from_bytes(align).unwrap(), MiriMemoryKind::Rust.into(), )?; - self.write_scalar(Scalar::Ptr(new_ptr.with_default_tag()), dest)?; + this.write_scalar(Scalar::Ptr(new_ptr.with_default_tag()), dest)?; } "syscall" => { @@ -200,7 +183,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo // // libc::syscall(NR_GETRANDOM, buf.as_mut_ptr(), buf.len(), GRND_NONBLOCK) // is called if a `HashMap` is created the regular way. - match self.read_scalar(args[0])?.to_usize(self)? { + match this.read_scalar(args[0])?.to_usize(this)? { 318 | 511 => { return err!(Unimplemented( "miri does not support random number generators".to_owned(), @@ -215,9 +198,9 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo } "dlsym" => { - let _handle = self.read_scalar(args[0])?; - let symbol = self.read_scalar(args[1])?.to_ptr()?; - let symbol_name = self.memory().get(symbol.alloc_id)?.read_c_str(tcx, symbol)?; + let _handle = this.read_scalar(args[0])?; + let symbol = this.read_scalar(args[1])?.to_ptr()?; + let symbol_name = this.memory().get(symbol.alloc_id)?.read_c_str(tcx, symbol)?; let err = format!("bad c unicode symbol: {:?}", symbol_name); let symbol_name = ::std::str::from_utf8(symbol_name).unwrap_or(&err); return err!(Unimplemented(format!( @@ -229,24 +212,24 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo "__rust_maybe_catch_panic" => { // 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 f = self.read_scalar(args[0])?.to_ptr()?; - let data = self.read_scalar(args[1])?.not_undef()?; - let f_instance = self.memory().get_fn(f)?; - self.write_null(dest)?; + let f = this.read_scalar(args[0])?.to_ptr()?; + let data = this.read_scalar(args[1])?.not_undef()?; + let f_instance = this.memory().get_fn(f)?; + this.write_null(dest)?; trace!("__rust_maybe_catch_panic: {:?}", f_instance); // 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. - let mir = self.load_mir(f_instance.def)?; - let ret_place = MPlaceTy::dangling(self.layout_of(self.tcx.mk_unit())?, self).into(); - self.push_stack_frame( + let mir = this.load_mir(f_instance.def)?; + let ret_place = MPlaceTy::dangling(this.layout_of(this.tcx.mk_unit())?, this).into(); + this.push_stack_frame( f_instance, mir.span, mir, Some(ret_place), StackPopCleanup::Goto(Some(ret)), // directly return to caller )?; - let mut args = self.frame().mir.args_iter(); + let mut args = this.frame().mir.args_iter(); let arg_local = args.next().ok_or_else(|| EvalErrorKind::AbiViolation( @@ -254,13 +237,13 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo .to_owned(), ), )?; - let arg_dest = self.eval_place(&mir::Place::Local(arg_local))?; - self.write_scalar(data, arg_dest)?; + let arg_dest = this.eval_place(&mir::Place::Local(arg_local))?; + this.write_scalar(data, arg_dest)?; assert!(args.next().is_none(), "__rust_maybe_catch_panic argument has more arguments than expected"); // We ourselves will return 0, eventually (because we will not return if we paniced) - self.write_null(dest)?; + this.write_null(dest)?; // Don't fall through, we do NOT want to `goto_block`! return Ok(()); @@ -270,13 +253,13 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo return err!(MachineError("the evaluated program panicked".to_string())), "memcmp" => { - let left = self.read_scalar(args[0])?.not_undef()?; - let right = self.read_scalar(args[1])?.not_undef()?; - let n = Size::from_bytes(self.read_scalar(args[2])?.to_usize(self)?); + let left = this.read_scalar(args[0])?.not_undef()?; + let right = this.read_scalar(args[1])?.not_undef()?; + let n = Size::from_bytes(this.read_scalar(args[2])?.to_usize(this)?); let result = { - let left_bytes = self.memory().read_bytes(left, n)?; - let right_bytes = self.memory().read_bytes(right, n)?; + let left_bytes = this.memory().read_bytes(left, n)?; + let right_bytes = this.memory().read_bytes(right, n)?; use std::cmp::Ordering::*; match left_bytes.cmp(right_bytes) { @@ -286,84 +269,84 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo } }; - self.write_scalar( + this.write_scalar( Scalar::from_int(result, Size::from_bits(32)), dest, )?; } "memrchr" => { - let ptr = self.read_scalar(args[0])?.not_undef()?; - let val = self.read_scalar(args[1])?.to_bytes()? as u8; - let num = self.read_scalar(args[2])?.to_usize(self)?; - if let Some(idx) = self.memory().read_bytes(ptr, Size::from_bytes(num))? + let ptr = this.read_scalar(args[0])?.not_undef()?; + let val = this.read_scalar(args[1])?.to_bytes()? as u8; + let num = this.read_scalar(args[2])?.to_usize(this)?; + if let Some(idx) = this.memory().read_bytes(ptr, Size::from_bytes(num))? .iter().rev().position(|&c| c == val) { - let new_ptr = ptr.ptr_offset(Size::from_bytes(num - idx as u64 - 1), self)?; - self.write_scalar(new_ptr, dest)?; + let new_ptr = ptr.ptr_offset(Size::from_bytes(num - idx as u64 - 1), this)?; + this.write_scalar(new_ptr, dest)?; } else { - self.write_null(dest)?; + this.write_null(dest)?; } } "memchr" => { - let ptr = self.read_scalar(args[0])?.not_undef()?; - let val = self.read_scalar(args[1])?.to_bytes()? as u8; - let num = self.read_scalar(args[2])?.to_usize(self)?; - if let Some(idx) = self.memory().read_bytes(ptr, Size::from_bytes(num))?.iter().position( + let ptr = this.read_scalar(args[0])?.not_undef()?; + let val = this.read_scalar(args[1])?.to_bytes()? as u8; + let num = this.read_scalar(args[2])?.to_usize(this)?; + if let Some(idx) = this.memory().read_bytes(ptr, Size::from_bytes(num))?.iter().position( |&c| c == val, ) { - let new_ptr = ptr.ptr_offset(Size::from_bytes(idx as u64), self)?; - self.write_scalar(new_ptr, dest)?; + let new_ptr = ptr.ptr_offset(Size::from_bytes(idx as u64), this)?; + this.write_scalar(new_ptr, dest)?; } else { - self.write_null(dest)?; + this.write_null(dest)?; } } "getenv" => { let result = { - let name_ptr = self.read_scalar(args[0])?.to_ptr()?; - let name = self.memory().get(name_ptr.alloc_id)?.read_c_str(tcx, name_ptr)?; - match self.machine.env_vars.get(name) { + let name_ptr = this.read_scalar(args[0])?.to_ptr()?; + let name = this.memory().get(name_ptr.alloc_id)?.read_c_str(tcx, name_ptr)?; + match this.machine.env_vars.get(name) { Some(&var) => Scalar::Ptr(var), - None => Scalar::ptr_null(&*self.tcx), + None => Scalar::ptr_null(&*this.tcx), } }; - self.write_scalar(result, dest)?; + this.write_scalar(result, dest)?; } "unsetenv" => { let mut success = None; { - let name_ptr = self.read_scalar(args[0])?.not_undef()?; - if !name_ptr.is_null_ptr(self) { + let name_ptr = this.read_scalar(args[0])?.not_undef()?; + if !name_ptr.is_null_ptr(this) { let name_ptr = name_ptr.to_ptr()?; - let name = self.memory().get(name_ptr.alloc_id)?.read_c_str(tcx, name_ptr)?.to_owned(); + let name = this.memory().get(name_ptr.alloc_id)?.read_c_str(tcx, name_ptr)?.to_owned(); if !name.is_empty() && !name.contains(&b'=') { - success = Some(self.machine.env_vars.remove(&name)); + success = Some(this.machine.env_vars.remove(&name)); } } } if let Some(old) = success { if let Some(var) = old { - self.memory_mut().deallocate(var, None, MiriMemoryKind::Env.into())?; + this.memory_mut().deallocate(var, None, MiriMemoryKind::Env.into())?; } - self.write_null(dest)?; + this.write_null(dest)?; } else { - self.write_scalar(Scalar::from_int(-1, dest.layout.size), dest)?; + this.write_scalar(Scalar::from_int(-1, dest.layout.size), dest)?; } } "setenv" => { let mut new = None; { - let name_ptr = self.read_scalar(args[0])?.not_undef()?; - let value_ptr = self.read_scalar(args[1])?.to_ptr()?; - let value = self.memory().get(value_ptr.alloc_id)?.read_c_str(tcx, value_ptr)?; - if !name_ptr.is_null_ptr(self) { + let name_ptr = this.read_scalar(args[0])?.not_undef()?; + let value_ptr = this.read_scalar(args[1])?.to_ptr()?; + let value = this.memory().get(value_ptr.alloc_id)?.read_c_str(tcx, value_ptr)?; + if !name_ptr.is_null_ptr(this) { let name_ptr = name_ptr.to_ptr()?; - let name = self.memory().get(name_ptr.alloc_id)?.read_c_str(tcx, name_ptr)?; + let name = this.memory().get(name_ptr.alloc_id)?.read_c_str(tcx, name_ptr)?; if !name.is_empty() && !name.contains(&b'=') { new = Some((name.to_owned(), value.to_owned())); } @@ -371,40 +354,40 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo } if let Some((name, value)) = new { // +1 for the null terminator - let value_copy = self.memory_mut().allocate( + let value_copy = this.memory_mut().allocate( Size::from_bytes((value.len() + 1) as u64), Align::from_bytes(1).unwrap(), MiriMemoryKind::Env.into(), )?.with_default_tag(); { - let alloc = self.memory_mut().get_mut(value_copy.alloc_id)?; + let alloc = this.memory_mut().get_mut(value_copy.alloc_id)?; alloc.write_bytes(tcx, value_copy, &value)?; let trailing_zero_ptr = value_copy.offset(Size::from_bytes(value.len() as u64), tcx)?; alloc.write_bytes(tcx, trailing_zero_ptr, &[0])?; } - if let Some(var) = self.machine.env_vars.insert( + if let Some(var) = this.machine.env_vars.insert( name.to_owned(), value_copy, ) { - self.memory_mut().deallocate(var, None, MiriMemoryKind::Env.into())?; + this.memory_mut().deallocate(var, None, MiriMemoryKind::Env.into())?; } - self.write_null(dest)?; + this.write_null(dest)?; } else { - self.write_scalar(Scalar::from_int(-1, dest.layout.size), dest)?; + this.write_scalar(Scalar::from_int(-1, dest.layout.size), dest)?; } } "write" => { - let fd = self.read_scalar(args[0])?.to_bytes()?; - let buf = self.read_scalar(args[1])?.not_undef()?; - let n = self.read_scalar(args[2])?.to_bytes()? as u64; + let fd = this.read_scalar(args[0])?.to_bytes()?; + let buf = this.read_scalar(args[1])?.not_undef()?; + let n = this.read_scalar(args[2])?.to_bytes()? as u64; trace!("Called write({:?}, {:?}, {:?})", fd, buf, n); let result = if fd == 1 || fd == 2 { // stdout/stderr use std::io::{self, Write}; - let buf_cont = self.memory().read_bytes(buf, Size::from_bytes(n))?; + let buf_cont = this.memory().read_bytes(buf, Size::from_bytes(n))?; let res = if fd == 1 { io::stdout().write(buf_cont) } else { @@ -418,25 +401,25 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo warn!("Ignored output to FD {}", fd); n as i64 // pretend it all went well }; // now result is the value we return back to the program - self.write_scalar( + this.write_scalar( Scalar::from_int(result, dest.layout.size), dest, )?; } "strlen" => { - let ptr = self.read_scalar(args[0])?.to_ptr()?; - let n = self.memory().get(ptr.alloc_id)?.read_c_str(tcx, ptr)?.len(); - self.write_scalar(Scalar::from_uint(n as u64, dest.layout.size), dest)?; + let ptr = this.read_scalar(args[0])?.to_ptr()?; + let n = this.memory().get(ptr.alloc_id)?.read_c_str(tcx, ptr)?.len(); + this.write_scalar(Scalar::from_uint(n as u64, dest.layout.size), dest)?; } // Some things needed for sys::thread initialization to go through "signal" | "sigaction" | "sigaltstack" => { - self.write_scalar(Scalar::from_int(0, dest.layout.size), dest)?; + this.write_scalar(Scalar::from_int(0, dest.layout.size), dest)?; } "sysconf" => { - let name = self.read_scalar(args[0])?.to_i32()?; + let name = this.read_scalar(args[0])?.to_i32()?; trace!("sysconf() called with name {}", name); // cache the sysconf integers via miri's global cache @@ -446,13 +429,13 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo ]; let mut result = None; for &(path, path_value) in paths { - if let Ok(instance) = self.resolve_path(path) { + if let Ok(instance) = this.resolve_path(path) { let cid = GlobalId { instance, promoted: None, }; - let const_val = self.const_eval_raw(cid)?; - let const_val = self.read_scalar(const_val.into())?; + let const_val = this.const_eval_raw(cid)?; + let const_val = this.read_scalar(const_val.into())?; let value = const_val.to_i32()?; if value == name { result = Some(path_value); @@ -461,7 +444,7 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo } } if let Some(result) = result { - self.write_scalar(result, dest)?; + this.write_scalar(result, dest)?; } else { return err!(Unimplemented( format!("Unimplemented sysconf name: {}", name), @@ -471,13 +454,13 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo // Hook pthread calls that go to the thread-local storage memory subsystem "pthread_key_create" => { - let key_ptr = self.read_scalar(args[0])?.to_ptr()?; + let key_ptr = this.read_scalar(args[0])?.to_ptr()?; // Extract the function type out of the signature (that seems easier than constructing it ourselves...) - let dtor = match self.read_scalar(args[1])?.not_undef()? { - Scalar::Ptr(dtor_ptr) => Some(self.memory().get_fn(dtor_ptr)?), + let dtor = match this.read_scalar(args[1])?.not_undef()? { + Scalar::Ptr(dtor_ptr) => Some(this.memory().get_fn(dtor_ptr)?), Scalar::Bits { bits: 0, size } => { - assert_eq!(size as u64, self.memory().pointer_size().bytes()); + assert_eq!(size as u64, this.memory().pointer_size().bytes()); None }, Scalar::Bits { .. } => return err!(ReadBytesAsPointer), @@ -486,16 +469,16 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo // Figure out how large a pthread TLS key actually is. This is libc::pthread_key_t. let key_type = args[0].layout.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_layout = self.layout_of(key_type)?; + let key_layout = this.layout_of(key_type)?; // Create key and write it into the memory where key_ptr wants it - let key = self.machine.tls.create_tls_key(dtor, tcx) as u128; + let key = this.machine.tls.create_tls_key(dtor, tcx) as u128; if key_layout.size.bits() < 128 && key >= (1u128 << key_layout.size.bits() as u128) { return err!(OutOfTls); } - self.memory().check_align(key_ptr.into(), key_layout.align.abi)?; - self.memory_mut().get_mut(key_ptr.alloc_id)?.write_scalar( + this.memory().check_align(key_ptr.into(), key_layout.align.abi)?; + this.memory_mut().get_mut(key_ptr.alloc_id)?.write_scalar( tcx, key_ptr, Scalar::from_uint(key, key_layout.size).into(), @@ -503,26 +486,26 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo )?; // Return success (0) - self.write_null(dest)?; + this.write_null(dest)?; } "pthread_key_delete" => { - let key = self.read_scalar(args[0])?.to_bytes()?; - self.machine.tls.delete_tls_key(key)?; + let key = this.read_scalar(args[0])?.to_bytes()?; + this.machine.tls.delete_tls_key(key)?; // Return success (0) - self.write_null(dest)?; + this.write_null(dest)?; } "pthread_getspecific" => { - let key = self.read_scalar(args[0])?.to_bytes()?; - let ptr = self.machine.tls.load_tls(key)?; - self.write_scalar(ptr, dest)?; + let key = this.read_scalar(args[0])?.to_bytes()?; + let ptr = this.machine.tls.load_tls(key)?; + this.write_scalar(ptr, dest)?; } "pthread_setspecific" => { - let key = self.read_scalar(args[0])?.to_bytes()?; - let new_ptr = self.read_scalar(args[1])?.not_undef()?; - self.machine.tls.store_tls(key, new_ptr)?; + let key = this.read_scalar(args[0])?.to_bytes()?; + let new_ptr = this.read_scalar(args[1])?.not_undef()?; + this.machine.tls.store_tls(key, new_ptr)?; // Return success (0) - self.write_null(dest)?; + this.write_null(dest)?; } "_tlv_atexit" => { @@ -532,19 +515,19 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo // Determining stack base address "pthread_attr_init" | "pthread_attr_destroy" | "pthread_attr_get_np" | "pthread_getattr_np" | "pthread_self" | "pthread_get_stacksize_np" => { - self.write_null(dest)?; + this.write_null(dest)?; } "pthread_attr_getstack" => { // second argument is where we are supposed to write the stack size - let ptr = self.deref_operand(args[1])?; + let ptr = this.deref_operand(args[1])?; let stackaddr = Scalar::from_int(0x80000, args[1].layout.size); // just any address - self.write_scalar(stackaddr, ptr.into())?; + this.write_scalar(stackaddr, ptr.into())?; // return 0 - self.write_null(dest)?; + this.write_null(dest)?; } "pthread_get_stackaddr_np" => { let stackaddr = Scalar::from_int(0x80000, dest.layout.size); // just any address - self.write_scalar(stackaddr, dest)?; + this.write_scalar(stackaddr, dest)?; } // Stub out calls for condvar, mutex and rwlock to just return 0 @@ -554,22 +537,22 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo "pthread_rwlock_wrlock" | "pthread_rwlock_destroy" | "pthread_condattr_init" | "pthread_condattr_setclock" | "pthread_cond_init" | "pthread_condattr_destroy" | "pthread_cond_destroy" => { - self.write_null(dest)?; + this.write_null(dest)?; } "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.read_scalar(args[0])?.not_undef()?; - self.write_scalar(addr, dest)?; + let addr = this.read_scalar(args[0])?.not_undef()?; + this.write_scalar(addr, dest)?; } "mprotect" => { - self.write_null(dest)?; + this.write_null(dest)?; } // Windows API subs "AddVectoredExceptionHandler" => { // any non zero value works for the stdlib. This is just used for stackoverflows anyway - self.write_scalar(Scalar::from_int(1, dest.layout.size), dest)?; + this.write_scalar(Scalar::from_int(1, dest.layout.size), dest)?; }, "InitializeCriticalSection" | "EnterCriticalSection" | @@ -582,11 +565,11 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo "GetProcAddress" | "TryEnterCriticalSection" => { // pretend these do not exist/nothing happened, by returning zero - self.write_null(dest)?; + this.write_null(dest)?; }, "GetLastError" => { // this is c::ERROR_CALL_NOT_IMPLEMENTED - self.write_scalar(Scalar::from_int(120, dest.layout.size), dest)?; + this.write_scalar(Scalar::from_int(120, dest.layout.size), dest)?; }, // Windows TLS @@ -594,26 +577,26 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo // This just creates a key; Windows does not natively support TLS dtors. // Create key and return it - let key = self.machine.tls.create_tls_key(None, tcx) as u128; + let key = this.machine.tls.create_tls_key(None, tcx) 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(Scalar::from_uint(key, dest.layout.size), dest)?; + this.write_scalar(Scalar::from_uint(key, dest.layout.size), dest)?; } "TlsGetValue" => { - let key = self.read_scalar(args[0])?.to_bytes()?; - let ptr = self.machine.tls.load_tls(key)?; - self.write_scalar(ptr, dest)?; + let key = this.read_scalar(args[0])?.to_bytes()?; + let ptr = this.machine.tls.load_tls(key)?; + this.write_scalar(ptr, dest)?; } "TlsSetValue" => { - let key = self.read_scalar(args[0])?.to_bytes()?; - let new_ptr = self.read_scalar(args[1])?.not_undef()?; - self.machine.tls.store_tls(key, new_ptr)?; + let key = this.read_scalar(args[0])?.to_bytes()?; + let new_ptr = this.read_scalar(args[1])?.not_undef()?; + this.machine.tls.store_tls(key, new_ptr)?; // Return success (1) - self.write_scalar(Scalar::from_int(1, dest.layout.size), dest)?; + this.write_scalar(Scalar::from_int(1, dest.layout.size), dest)?; } // We can't execute anything else @@ -624,12 +607,12 @@ impl<'a, 'mir, 'tcx: 'mir + 'a> EvalContextExt<'tcx, 'mir> for super::MiriEvalCo } } - self.goto_block(Some(ret))?; - self.dump_place(*dest); + this.goto_block(Some(ret))?; + this.dump_place(*dest); Ok(()) } fn write_null(&mut self, dest: PlaceTy<'tcx, Borrow>) -> EvalResult<'tcx> { - self.write_scalar(Scalar::from_int(0, dest.layout.size), dest) + self.eval_context_mut().write_scalar(Scalar::from_int(0, dest.layout.size), dest) } } diff --git a/src/helpers.rs b/src/helpers.rs index 2b1a28fe9e0d0..7be1567605083 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -30,43 +30,31 @@ impl ScalarExt for ScalarMaybeUndef { } } -pub trait EvalContextExt<'tcx> { - fn resolve_path(&self, path: &[&str]) -> EvalResult<'tcx, ty::Instance<'tcx>>; - - /// Visit the memory covered by `place`, sensitive to freezing: The 3rd parameter - /// will be true if this is frozen, false if this is in an `UnsafeCell`. - fn visit_freeze_sensitive( - &self, - place: MPlaceTy<'tcx, Borrow>, - size: Size, - action: impl FnMut(Pointer, Size, bool) -> EvalResult<'tcx>, - ) -> EvalResult<'tcx>; -} - - -impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super::Evaluator<'tcx>> { +impl<'a, 'mir, 'tcx> EvalContextExt<'a, 'mir, 'tcx> for crate::MiriEvalContext<'a, 'mir, 'tcx> {} +pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, 'mir, 'tcx> { /// Get an instance for a path. fn resolve_path(&self, path: &[&str]) -> EvalResult<'tcx, ty::Instance<'tcx>> { - self.tcx + let this = self.eval_context_ref(); + this.tcx .crates() .iter() - .find(|&&krate| self.tcx.original_crate_name(krate) == path[0]) + .find(|&&krate| this.tcx.original_crate_name(krate) == path[0]) .and_then(|krate| { let krate = DefId { krate: *krate, index: CRATE_DEF_INDEX, }; - let mut items = self.tcx.item_children(krate); + let mut items = this.tcx.item_children(krate); let mut path_it = path.iter().skip(1).peekable(); while let Some(segment) = path_it.next() { for item in mem::replace(&mut items, Default::default()).iter() { if item.ident.name == *segment { if path_it.peek().is_none() { - return Some(ty::Instance::mono(self.tcx.tcx, item.def.def_id())); + return Some(ty::Instance::mono(this.tcx.tcx, item.def.def_id())); } - items = self.tcx.item_children(item.def.def_id()); + items = this.tcx.item_children(item.def.def_id()); break; } } @@ -79,15 +67,18 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: }) } + /// Visit the memory covered by `place`, sensitive to freezing: The 3rd parameter + /// will be true if this is frozen, false if this is in an `UnsafeCell`. fn visit_freeze_sensitive( &self, place: MPlaceTy<'tcx, Borrow>, size: Size, mut action: impl FnMut(Pointer, Size, bool) -> EvalResult<'tcx>, ) -> EvalResult<'tcx> { + let this = self.eval_context_ref(); trace!("visit_frozen(place={:?}, size={:?})", *place, size); debug_assert_eq!(size, - self.size_and_align_of_mplace(place)? + this.size_and_align_of_mplace(place)? .map(|(size, _)| size) .unwrap_or_else(|| place.layout.size) ); @@ -106,8 +97,8 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: } // We assume that we are given the fields in increasing offset order, // and nothing else changes. - let unsafe_cell_offset = unsafe_cell_ptr.get_ptr_offset(self); - let end_offset = end_ptr.get_ptr_offset(self); + let unsafe_cell_offset = unsafe_cell_ptr.get_ptr_offset(this); + let end_offset = end_ptr.get_ptr_offset(this); assert!(unsafe_cell_offset >= end_offset); let frozen_size = unsafe_cell_offset - end_offset; // Everything between the end_ptr and this `UnsafeCell` is frozen. @@ -119,18 +110,18 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: action(unsafe_cell_ptr.to_ptr()?, unsafe_cell_size, /*frozen*/false)?; } // Update end end_ptr. - end_ptr = unsafe_cell_ptr.ptr_wrapping_offset(unsafe_cell_size, self); + end_ptr = unsafe_cell_ptr.ptr_wrapping_offset(unsafe_cell_size, this); // Done Ok(()) }; // Run a visitor { let mut visitor = UnsafeCellVisitor { - ecx: self, + ecx: this, unsafe_cell_action: |place| { trace!("unsafe_cell_action on {:?}", place.ptr); // We need a size to go on. - let unsafe_cell_size = self.size_and_align_of_mplace(place)? + let unsafe_cell_size = this.size_and_align_of_mplace(place)? .map(|(size, _)| size) // for extern types, just cover what we can .unwrap_or_else(|| place.layout.size); @@ -146,7 +137,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super: } // The part between the end_ptr and the end of the place is also frozen. // So pretend there is a 0-sized `UnsafeCell` at the end. - unsafe_cell_action(place.ptr.ptr_wrapping_offset(size, self), Size::ZERO)?; + unsafe_cell_action(place.ptr.ptr_wrapping_offset(size, this), Size::ZERO)?; // Done! return Ok(()); diff --git a/src/intrinsic.rs b/src/intrinsic.rs index c9b16525e5662..35182ba5137ac 100644 --- a/src/intrinsic.rs +++ b/src/intrinsic.rs @@ -9,47 +9,40 @@ use crate::{ ScalarExt, OperatorEvalContextExt }; -pub trait EvalContextExt<'tcx> { - fn call_intrinsic( - &mut self, - instance: ty::Instance<'tcx>, - args: &[OpTy<'tcx, Borrow>], - dest: PlaceTy<'tcx, Borrow>, - ) -> EvalResult<'tcx>; -} - -impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, 'tcx> { +impl<'a, 'mir, 'tcx> EvalContextExt<'a, 'mir, 'tcx> for crate::MiriEvalContext<'a, 'mir, 'tcx> {} +pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, 'mir, 'tcx> { fn call_intrinsic( &mut self, instance: ty::Instance<'tcx>, args: &[OpTy<'tcx, Borrow>], dest: PlaceTy<'tcx, Borrow>, ) -> EvalResult<'tcx> { - if self.emulate_intrinsic(instance, args, dest)? { + let this = self.eval_context_mut(); + if this.emulate_intrinsic(instance, args, dest)? { return Ok(()); } - let tcx = &{self.tcx.tcx}; + let tcx = &{this.tcx.tcx}; let substs = instance.substs; // All these intrinsics take raw pointers, so if we access memory directly // (as opposed to through a place), we have to remember to erase any tag // that might still hang around! - let intrinsic_name = &self.tcx.item_name(instance.def_id()).as_str()[..]; + let intrinsic_name = &this.tcx.item_name(instance.def_id()).as_str()[..]; match intrinsic_name { "arith_offset" => { - let offset = self.read_scalar(args[1])?.to_isize(self)?; - let ptr = self.read_scalar(args[0])?.not_undef()?; + let offset = this.read_scalar(args[1])?.to_isize(this)?; + let ptr = this.read_scalar(args[0])?.not_undef()?; let pointee_ty = substs.type_at(0); - let pointee_size = self.layout_of(pointee_ty)?.size.bytes() as i64; + let pointee_size = this.layout_of(pointee_ty)?.size.bytes() as i64; let offset = offset.overflowing_mul(pointee_size).0; - let result_ptr = ptr.ptr_wrapping_signed_offset(offset, self); - self.write_scalar(result_ptr, dest)?; + let result_ptr = ptr.ptr_wrapping_signed_offset(offset, this); + this.write_scalar(result_ptr, dest)?; } "assume" => { - let cond = self.read_scalar(args[0])?.to_bool()?; + let cond = this.read_scalar(args[0])?.to_bool()?; if !cond { return err!(AssumptionNotHeld); } @@ -59,18 +52,18 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' "atomic_load_relaxed" | "atomic_load_acq" | "volatile_load" => { - let ptr = self.deref_operand(args[0])?; - let val = self.read_scalar(ptr.into())?; // make sure it fits into a scalar; otherwise it cannot be atomic - self.write_scalar(val, dest)?; + let ptr = this.deref_operand(args[0])?; + let val = this.read_scalar(ptr.into())?; // make sure it fits into a scalar; otherwise it cannot be atomic + this.write_scalar(val, dest)?; } "atomic_store" | "atomic_store_relaxed" | "atomic_store_rel" | "volatile_store" => { - let ptr = self.deref_operand(args[0])?; - let val = self.read_scalar(args[1])?; // make sure it fits into a scalar; otherwise it cannot be atomic - self.write_scalar(val, ptr.into())?; + let ptr = this.deref_operand(args[0])?; + let val = this.read_scalar(args[1])?; // make sure it fits into a scalar; otherwise it cannot be atomic + this.write_scalar(val, ptr.into())?; } "atomic_fence_acq" => { @@ -78,25 +71,25 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' } _ if intrinsic_name.starts_with("atomic_xchg") => { - let ptr = self.deref_operand(args[0])?; - let new = self.read_scalar(args[1])?; - let old = self.read_scalar(ptr.into())?; - self.write_scalar(old, dest)?; // old value is returned - self.write_scalar(new, ptr.into())?; + let ptr = this.deref_operand(args[0])?; + let new = this.read_scalar(args[1])?; + let old = this.read_scalar(ptr.into())?; + this.write_scalar(old, dest)?; // old value is returned + this.write_scalar(new, ptr.into())?; } _ if intrinsic_name.starts_with("atomic_cxchg") => { - let ptr = self.deref_operand(args[0])?; - let expect_old = self.read_immediate(args[1])?; // read as immediate for the sake of `binary_op_imm()` - let new = self.read_scalar(args[2])?; - let old = self.read_immediate(ptr.into())?; // read as immediate for the sake of `binary_op_imm()` + let ptr = this.deref_operand(args[0])?; + let expect_old = this.read_immediate(args[1])?; // read as immediate for the sake of `binary_op_imm()` + let new = this.read_scalar(args[2])?; + let old = this.read_immediate(ptr.into())?; // read as immediate for the sake of `binary_op_imm()` // binary_op_imm will bail if either of them is not a scalar - let (eq, _) = self.binary_op_imm(mir::BinOp::Eq, old, expect_old)?; + let (eq, _) = this.binary_op_imm(mir::BinOp::Eq, old, expect_old)?; let res = Immediate::ScalarPair(old.to_scalar_or_undef(), eq.into()); - self.write_immediate(res, dest)?; // old value is returned + this.write_immediate(res, dest)?; // old value is returned // update ptr depending on comparison if eq.to_bool()? { - self.write_scalar(new, ptr.into())?; + this.write_scalar(new, ptr.into())?; } } @@ -125,13 +118,13 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' "atomic_xsub_rel" | "atomic_xsub_acqrel" | "atomic_xsub_relaxed" => { - let ptr = self.deref_operand(args[0])?; + let ptr = this.deref_operand(args[0])?; if !ptr.layout.ty.is_integral() { return err!(Unimplemented(format!("Atomic arithmetic operations only work on integer types"))); } - let rhs = self.read_immediate(args[1])?; - let old = self.read_immediate(ptr.into())?; - self.write_immediate(*old, dest)?; // old value is returned + let rhs = this.read_immediate(args[1])?; + let old = this.read_immediate(ptr.into())?; + this.write_immediate(*old, dest)?; // old value is returned let op = match intrinsic_name.split('_').nth(1).unwrap() { "or" => mir::BinOp::BitOr, "xor" => mir::BinOp::BitXor, @@ -141,7 +134,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' _ => bug!(), }; // Atomics wrap around on overflow. - self.binop_ignore_overflow(op, old, rhs, ptr.into())?; + this.binop_ignore_overflow(op, old, rhs, ptr.into())?; } "breakpoint" => unimplemented!(), // halt miri @@ -149,14 +142,14 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' "copy" | "copy_nonoverlapping" => { let elem_ty = substs.type_at(0); - let elem_layout = self.layout_of(elem_ty)?; + let elem_layout = this.layout_of(elem_ty)?; let elem_size = elem_layout.size.bytes(); - let count = self.read_scalar(args[2])?.to_usize(self)?; + let count = this.read_scalar(args[2])?.to_usize(this)?; let elem_align = elem_layout.align.abi; // erase tags: this is a raw ptr operation - let src = self.read_scalar(args[0])?.not_undef()?; - let dest = self.read_scalar(args[1])?.not_undef()?; - self.memory_mut().copy( + let src = this.read_scalar(args[0])?.not_undef()?; + let dest = this.read_scalar(args[1])?.not_undef()?; + this.memory_mut().copy( src, elem_align, dest, @@ -167,14 +160,14 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' } "discriminant_value" => { - let place = self.deref_operand(args[0])?; - let discr_val = self.read_discriminant(place.into())?.0; - self.write_scalar(Scalar::from_uint(discr_val, dest.layout.size), dest)?; + let place = this.deref_operand(args[0])?; + let discr_val = this.read_discriminant(place.into())?.0; + this.write_scalar(Scalar::from_uint(discr_val, dest.layout.size), dest)?; } "sinf32" | "fabsf32" | "cosf32" | "sqrtf32" | "expf32" | "exp2f32" | "logf32" | "log10f32" | "log2f32" | "floorf32" | "ceilf32" | "truncf32" => { - let f = self.read_scalar(args[0])?.to_f32()?; + let f = this.read_scalar(args[0])?.to_f32()?; let f = match intrinsic_name { "sinf32" => f.sin(), "fabsf32" => f.abs(), @@ -190,12 +183,12 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' "truncf32" => f.trunc(), _ => bug!(), }; - self.write_scalar(Scalar::from_f32(f), dest)?; + this.write_scalar(Scalar::from_f32(f), dest)?; } "sinf64" | "fabsf64" | "cosf64" | "sqrtf64" | "expf64" | "exp2f64" | "logf64" | "log10f64" | "log2f64" | "floorf64" | "ceilf64" | "truncf64" => { - let f = self.read_scalar(args[0])?.to_f64()?; + let f = this.read_scalar(args[0])?.to_f64()?; let f = match intrinsic_name { "sinf64" => f.sin(), "fabsf64" => f.abs(), @@ -211,12 +204,12 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' "truncf64" => f.trunc(), _ => bug!(), }; - self.write_scalar(Scalar::from_f64(f), dest)?; + this.write_scalar(Scalar::from_f64(f), dest)?; } "fadd_fast" | "fsub_fast" | "fmul_fast" | "fdiv_fast" | "frem_fast" => { - let a = self.read_immediate(args[0])?; - let b = self.read_immediate(args[1])?; + let a = this.read_immediate(args[0])?; + let b = this.read_immediate(args[1])?; let op = match intrinsic_name { "fadd_fast" => mir::BinOp::Add, "fsub_fast" => mir::BinOp::Sub, @@ -225,19 +218,19 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' "frem_fast" => mir::BinOp::Rem, _ => bug!(), }; - self.binop_ignore_overflow(op, a, b, dest)?; + this.binop_ignore_overflow(op, a, b, dest)?; } "exact_div" => { // Performs an exact division, resulting in undefined behavior where // `x % y != 0` or `y == 0` or `x == T::min_value() && y == -1` - let a = self.read_immediate(args[0])?; - let b = self.read_immediate(args[1])?; + let a = this.read_immediate(args[0])?; + let b = this.read_immediate(args[1])?; // check x % y != 0 - if self.binary_op_imm(mir::BinOp::Rem, a, b)?.0.to_bytes()? != 0 { + if this.binary_op_imm(mir::BinOp::Rem, a, b)?.0.to_bytes()? != 0 { return err!(ValidationFailure(format!("exact_div: {:?} cannot be divided by {:?}", a, b))); } - self.binop_ignore_overflow(mir::BinOp::Div, a, b, dest)?; + this.binop_ignore_overflow(mir::BinOp::Div, a, b, dest)?; }, "likely" | "unlikely" | "forget" => {} @@ -252,21 +245,21 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' if !dest.layout.is_zst() { // nothing to do for ZST match dest.layout.abi { layout::Abi::Scalar(ref s) => { - let x = Scalar::from_int(0, s.value.size(self)); - self.write_immediate(Immediate::Scalar(x.into()), dest)?; + let x = Scalar::from_int(0, s.value.size(this)); + this.write_immediate(Immediate::Scalar(x.into()), dest)?; } layout::Abi::ScalarPair(ref s1, ref s2) => { - let x = Scalar::from_int(0, s1.value.size(self)); - let y = Scalar::from_int(0, s2.value.size(self)); - self.write_immediate(Immediate::ScalarPair(x.into(), y.into()), dest)?; + let x = Scalar::from_int(0, s1.value.size(this)); + let y = Scalar::from_int(0, s2.value.size(this)); + this.write_immediate(Immediate::ScalarPair(x.into(), y.into()), dest)?; } _ => { // Do it in memory - let mplace = self.force_allocation(dest)?; + let mplace = this.force_allocation(dest)?; assert!(mplace.meta.is_none()); // not a zst, must be valid pointer let ptr = mplace.ptr.to_ptr()?; - self.memory_mut().get_mut(ptr.alloc_id)?.write_repeat(tcx, ptr, 0, dest.layout.size)?; + this.memory_mut().get_mut(ptr.alloc_id)?.write_repeat(tcx, ptr, 0, dest.layout.size)?; } } } @@ -274,87 +267,87 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' "pref_align_of" => { let ty = substs.type_at(0); - let layout = self.layout_of(ty)?; + let layout = this.layout_of(ty)?; let align = layout.align.pref.bytes(); - let ptr_size = self.pointer_size(); + let ptr_size = this.pointer_size(); let align_val = Scalar::from_uint(align as u128, ptr_size); - self.write_scalar(align_val, dest)?; + this.write_scalar(align_val, dest)?; } "move_val_init" => { - let ptr = self.deref_operand(args[0])?; - self.copy_op(args[1], ptr.into())?; + let ptr = this.deref_operand(args[0])?; + this.copy_op(args[1], ptr.into())?; } "offset" => { - let offset = self.read_scalar(args[1])?.to_isize(self)?; - let ptr = self.read_scalar(args[0])?.not_undef()?; - let result_ptr = self.pointer_offset_inbounds(ptr, substs.type_at(0), offset)?; - self.write_scalar(result_ptr, dest)?; + let offset = this.read_scalar(args[1])?.to_isize(this)?; + let ptr = this.read_scalar(args[0])?.not_undef()?; + let result_ptr = this.pointer_offset_inbounds(ptr, substs.type_at(0), offset)?; + this.write_scalar(result_ptr, dest)?; } "powf32" => { - let f = self.read_scalar(args[0])?.to_f32()?; - let f2 = self.read_scalar(args[1])?.to_f32()?; - self.write_scalar( + let f = this.read_scalar(args[0])?.to_f32()?; + let f2 = this.read_scalar(args[1])?.to_f32()?; + this.write_scalar( Scalar::from_f32(f.powf(f2)), dest, )?; } "powf64" => { - let f = self.read_scalar(args[0])?.to_f64()?; - let f2 = self.read_scalar(args[1])?.to_f64()?; - self.write_scalar( + let f = this.read_scalar(args[0])?.to_f64()?; + let f2 = this.read_scalar(args[1])?.to_f64()?; + this.write_scalar( Scalar::from_f64(f.powf(f2)), dest, )?; } "fmaf32" => { - let a = self.read_scalar(args[0])?.to_f32()?; - let b = self.read_scalar(args[1])?.to_f32()?; - let c = self.read_scalar(args[2])?.to_f32()?; - self.write_scalar( + let a = this.read_scalar(args[0])?.to_f32()?; + let b = this.read_scalar(args[1])?.to_f32()?; + let c = this.read_scalar(args[2])?.to_f32()?; + this.write_scalar( Scalar::from_f32(a * b + c), dest, )?; } "fmaf64" => { - let a = self.read_scalar(args[0])?.to_f64()?; - let b = self.read_scalar(args[1])?.to_f64()?; - let c = self.read_scalar(args[2])?.to_f64()?; - self.write_scalar( + let a = this.read_scalar(args[0])?.to_f64()?; + let b = this.read_scalar(args[1])?.to_f64()?; + let c = this.read_scalar(args[2])?.to_f64()?; + this.write_scalar( Scalar::from_f64(a * b + c), dest, )?; } "powif32" => { - let f = self.read_scalar(args[0])?.to_f32()?; - let i = self.read_scalar(args[1])?.to_i32()?; - self.write_scalar( + let f = this.read_scalar(args[0])?.to_f32()?; + let i = this.read_scalar(args[1])?.to_i32()?; + this.write_scalar( Scalar::from_f32(f.powi(i)), dest, )?; } "powif64" => { - let f = self.read_scalar(args[0])?.to_f64()?; - let i = self.read_scalar(args[1])?.to_i32()?; - self.write_scalar( + let f = this.read_scalar(args[0])?.to_f64()?; + let i = this.read_scalar(args[1])?.to_i32()?; + this.write_scalar( Scalar::from_f64(f.powi(i)), dest, )?; } "size_of_val" => { - let mplace = self.deref_operand(args[0])?; - let (size, _) = self.size_and_align_of_mplace(mplace)? + let mplace = this.deref_operand(args[0])?; + let (size, _) = this.size_and_align_of_mplace(mplace)? .expect("size_of_val called on extern type"); - let ptr_size = self.pointer_size(); - self.write_scalar( + let ptr_size = this.pointer_size(); + this.write_scalar( Scalar::from_uint(size.bytes() as u128, ptr_size), dest, )?; @@ -362,11 +355,11 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' "min_align_of_val" | "align_of_val" => { - let mplace = self.deref_operand(args[0])?; - let (_, align) = self.size_and_align_of_mplace(mplace)? + let mplace = this.deref_operand(args[0])?; + let (_, align) = this.size_and_align_of_mplace(mplace)? .expect("size_of_val called on extern type"); - let ptr_size = self.pointer_size(); - self.write_scalar( + let ptr_size = this.pointer_size(); + this.write_scalar( Scalar::from_uint(align.bytes(), ptr_size), dest, )?; @@ -375,18 +368,18 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' "type_name" => { let ty = substs.type_at(0); let ty_name = ty.to_string(); - let value = self.str_to_immediate(&ty_name)?; - self.write_immediate(value, dest)?; + let value = this.str_to_immediate(&ty_name)?; + this.write_immediate(value, dest)?; } "unchecked_div" => { - let l = self.read_immediate(args[0])?; - let r = self.read_immediate(args[1])?; + let l = this.read_immediate(args[0])?; + let r = this.read_immediate(args[1])?; let rval = r.to_scalar()?.to_bytes()?; if rval == 0 { return err!(Intrinsic(format!("Division by 0 in unchecked_div"))); } - self.binop_ignore_overflow( + this.binop_ignore_overflow( mir::BinOp::Div, l, r, @@ -395,13 +388,13 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' } "unchecked_rem" => { - let l = self.read_immediate(args[0])?; - let r = self.read_immediate(args[1])?; + let l = this.read_immediate(args[0])?; + let r = this.read_immediate(args[1])?; let rval = r.to_scalar()?.to_bytes()?; if rval == 0 { return err!(Intrinsic(format!("Division by 0 in unchecked_rem"))); } - self.binop_ignore_overflow( + this.binop_ignore_overflow( mir::BinOp::Rem, l, r, @@ -420,18 +413,18 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' match dest.layout.abi { layout::Abi::Scalar(..) => { let x = ScalarMaybeUndef::Undef; - self.write_immediate(Immediate::Scalar(x), dest)?; + this.write_immediate(Immediate::Scalar(x), dest)?; } layout::Abi::ScalarPair(..) => { let x = ScalarMaybeUndef::Undef; - self.write_immediate(Immediate::ScalarPair(x, x), dest)?; + this.write_immediate(Immediate::ScalarPair(x, x), dest)?; } _ => { // Do it in memory - let mplace = self.force_allocation(dest)?; + let mplace = this.force_allocation(dest)?; assert!(mplace.meta.is_none()); let ptr = mplace.ptr.to_ptr()?; - self.memory_mut() + this.memory_mut() .get_mut(ptr.alloc_id)? .mark_definedness(ptr, dest.layout.size, false)?; } @@ -441,15 +434,15 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' "write_bytes" => { let ty = substs.type_at(0); - let ty_layout = self.layout_of(ty)?; - let val_byte = self.read_scalar(args[1])?.to_u8()?; - let ptr = self.read_scalar(args[0])?.not_undef()?; - let count = self.read_scalar(args[2])?.to_usize(self)?; - self.memory().check_align(ptr, ty_layout.align.abi)?; + let ty_layout = this.layout_of(ty)?; + let val_byte = this.read_scalar(args[1])?.to_u8()?; + let ptr = this.read_scalar(args[0])?.not_undef()?; + let count = this.read_scalar(args[2])?.to_usize(this)?; + this.memory().check_align(ptr, ty_layout.align.abi)?; let byte_count = ty_layout.size * count; if byte_count.bytes() != 0 { let ptr = ptr.to_ptr()?; - self.memory_mut() + this.memory_mut() .get_mut(ptr.alloc_id)? .write_repeat(tcx, ptr, val_byte, byte_count)?; } diff --git a/src/lib.rs b/src/lib.rs index 9641670a2edfb..aabfa36a4b5ba 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -277,6 +277,21 @@ impl<'tcx> Evaluator<'tcx> { #[allow(dead_code)] // FIXME https://github.com/rust-lang/rust/issues/47131 type MiriEvalContext<'a, 'mir, 'tcx> = EvalContext<'a, 'mir, 'tcx, Evaluator<'tcx>>; +// A little trait that's useful to be inherited by extension traits +pub trait MiriEvalContextExt<'a, 'mir, 'tcx> { + fn eval_context_ref(&self) -> &MiriEvalContext<'a, 'mir, 'tcx>; + fn eval_context_mut(&mut self) -> &mut MiriEvalContext<'a, 'mir, 'tcx>; +} +impl<'a, 'mir, 'tcx> MiriEvalContextExt<'a, 'mir, 'tcx> for MiriEvalContext<'a, 'mir, 'tcx> { + #[inline(always)] + fn eval_context_ref(&self) -> &MiriEvalContext<'a, 'mir, 'tcx> { + self + } + #[inline(always)] + fn eval_context_mut(&mut self) -> &mut MiriEvalContext<'a, 'mir, 'tcx> { + self + } +} impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { type MemoryKinds = MiriMemoryKind; diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index e9fb0aa777975..17da5c1526929 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -516,60 +516,14 @@ impl<'tcx> Stacks { } } - - -pub trait EvalContextExt<'tcx> { - fn ptr_dereference( - &self, - place: MPlaceTy<'tcx, Borrow>, - size: Size, - mutability: Option, - ) -> EvalResult<'tcx>; - - fn tag_new_allocation( - &mut self, - id: AllocId, - kind: MemoryKind, - ) -> Borrow; - - /// Reborrow the given place, returning the newly tagged ptr to it. - fn reborrow( - &mut self, - place: MPlaceTy<'tcx, Borrow>, - size: Size, - fn_barrier: bool, - new_bor: Borrow - ) -> EvalResult<'tcx>; - - /// Retag an indidual pointer, returning the retagged version. - fn retag_reference( - &mut self, - ptr: ImmTy<'tcx, Borrow>, - mutbl: Mutability, - fn_barrier: bool, - two_phase: bool, - ) -> EvalResult<'tcx, Immediate>; - - fn retag( - &mut self, - fn_entry: bool, - two_phase: bool, - place: PlaceTy<'tcx, Borrow> - ) -> EvalResult<'tcx>; - - fn escape_to_raw( - &mut self, - place: MPlaceTy<'tcx, Borrow>, - size: Size, - ) -> EvalResult<'tcx>; -} - -impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for MiriEvalContext<'a, 'mir, 'tcx> { +impl<'a, 'mir, 'tcx> EvalContextExt<'a, 'mir, 'tcx> for crate::MiriEvalContext<'a, 'mir, 'tcx> {} +pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, 'mir, 'tcx> { fn tag_new_allocation( &mut self, id: AllocId, kind: MemoryKind, ) -> Borrow { + let this = self.eval_context_mut(); let time = match kind { MemoryKind::Stack => { // New unique borrow. This `Uniq` is not accessible by the program, @@ -580,7 +534,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for MiriEvalContext<'a, 'mir, 'tcx> { // `reset` which the blog post [1] says to perform when accessing a local. // // [1] https://www.ralfj.de/blog/2018/08/07/stacked-borrows.html - self.machine.stacked_borrows.increment_clock() + this.machine.stacked_borrows.increment_clock() } _ => { // Nothing to do for everything else @@ -588,7 +542,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for MiriEvalContext<'a, 'mir, 'tcx> { } }; // Make this the active borrow for this allocation - let alloc = self.memory_mut().get_mut(id).expect("This is a new allocation, it must still exist"); + let alloc = this.memory_mut().get_mut(id).expect("This is a new allocation, it must still exist"); let size = Size::from_bytes(alloc.bytes.len() as u64); alloc.extra.first_item(BorStackItem::Uniq(time), size); Borrow::Uniq(time) @@ -604,6 +558,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for MiriEvalContext<'a, 'mir, 'tcx> { size: Size, mutability: Option, ) -> EvalResult<'tcx> { + let this = self.eval_context_ref(); trace!("ptr_dereference: Accessing {} reference for {:?} (pointee {})", if let Some(mutability) = mutability { format!("{:?}", mutability) } else { format!("raw") }, place.ptr, place.layout.ty); @@ -614,13 +569,13 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for MiriEvalContext<'a, 'mir, 'tcx> { } // Get the allocation - let alloc = self.memory().get(ptr.alloc_id)?; - alloc.check_bounds(self, ptr, size)?; + let alloc = this.memory().get(ptr.alloc_id)?; + alloc.check_bounds(this, ptr, size)?; // If we got here, we do some checking, *but* we leave the tag unchanged. if let Borrow::Shr(Some(_)) = ptr.tag { assert_eq!(mutability, Some(MutImmutable)); // We need a frozen-sensitive check - self.visit_freeze_sensitive(place, size, |cur_ptr, size, frozen| { + this.visit_freeze_sensitive(place, size, |cur_ptr, size, frozen| { let kind = if frozen { RefKind::Frozen } else { RefKind::Raw }; alloc.extra.deref(cur_ptr, size, kind) })?; @@ -641,7 +596,8 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for MiriEvalContext<'a, 'mir, 'tcx> { place: MPlaceTy<'tcx, Borrow>, size: Size, ) -> EvalResult<'tcx> { - self.reborrow(place, size, /*fn_barrier*/ false, Borrow::default())?; + let this = self.eval_context_mut(); + this.reborrow(place, size, /*fn_barrier*/ false, Borrow::default())?; Ok(()) } @@ -652,18 +608,19 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for MiriEvalContext<'a, 'mir, 'tcx> { fn_barrier: bool, new_bor: Borrow ) -> EvalResult<'tcx> { + let this = self.eval_context_mut(); let ptr = place.ptr.to_ptr()?; - let barrier = if fn_barrier { Some(self.frame().extra) } else { None }; + let barrier = if fn_barrier { Some(this.frame().extra) } else { None }; trace!("reborrow: Creating new reference for {:?} (pointee {}): {:?}", ptr, place.layout.ty, new_bor); // Get the allocation. It might not be mutable, so we cannot use `get_mut`. - let alloc = self.memory().get(ptr.alloc_id)?; - alloc.check_bounds(self, ptr, size)?; + let alloc = this.memory().get(ptr.alloc_id)?; + alloc.check_bounds(this, ptr, size)?; // Update the stacks. if let Borrow::Shr(Some(_)) = new_bor { // Reference that cares about freezing. We need a frozen-sensitive reborrow. - self.visit_freeze_sensitive(place, size, |cur_ptr, size, frozen| { + this.visit_freeze_sensitive(place, size, |cur_ptr, size, frozen| { let kind = if frozen { RefKind::Frozen } else { RefKind::Raw }; alloc.extra.reborrow(cur_ptr, size, barrier, new_bor, kind) })?; @@ -675,6 +632,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for MiriEvalContext<'a, 'mir, 'tcx> { Ok(()) } + /// Retag an indidual pointer, returning the retagged version. fn retag_reference( &mut self, val: ImmTy<'tcx, Borrow>, @@ -682,9 +640,10 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for MiriEvalContext<'a, 'mir, 'tcx> { fn_barrier: bool, two_phase: bool, ) -> EvalResult<'tcx, Immediate> { + let this = self.eval_context_mut(); // We want a place for where the ptr *points to*, so we get one. - let place = self.ref_to_mplace(val)?; - let size = self.size_and_align_of_mplace(place)? + let place = this.ref_to_mplace(val)?; + let size = this.size_and_align_of_mplace(place)? .map(|(size, _)| size) .unwrap_or_else(|| place.layout.size); if size == Size::ZERO { @@ -693,22 +652,22 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for MiriEvalContext<'a, 'mir, 'tcx> { } // Compute new borrow. - let time = self.machine.stacked_borrows.increment_clock(); + let time = this.machine.stacked_borrows.increment_clock(); let new_bor = match mutbl { MutMutable => Borrow::Uniq(time), MutImmutable => Borrow::Shr(Some(time)), }; // Reborrow. - self.reborrow(place, size, fn_barrier, new_bor)?; + this.reborrow(place, size, fn_barrier, new_bor)?; let new_place = place.with_tag(new_bor); // Handle two-phase borrows. if two_phase { assert!(mutbl == MutMutable, "two-phase shared borrows make no sense"); // We immediately share it, to allow read accesses - let two_phase_time = self.machine.stacked_borrows.increment_clock(); + let two_phase_time = this.machine.stacked_borrows.increment_clock(); let two_phase_bor = Borrow::Shr(Some(two_phase_time)); - self.reborrow(new_place, size, /*fn_barrier*/false, two_phase_bor)?; + this.reborrow(new_place, size, /*fn_barrier*/false, two_phase_bor)?; } // Return new ptr. @@ -721,6 +680,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for MiriEvalContext<'a, 'mir, 'tcx> { two_phase: bool, place: PlaceTy<'tcx, Borrow> ) -> EvalResult<'tcx> { + let this = self.eval_context_mut(); // Determine mutability and whether to add a barrier. // Cannot use `builtin_deref` because that reports *immutable* for `Box`, // making it useless. @@ -740,14 +700,14 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for MiriEvalContext<'a, 'mir, 'tcx> { // avoids allocating. if let Some((mutbl, barrier)) = qualify(place.layout.ty, fn_entry) { // fast path - let val = self.read_immediate(self.place_to_op(place)?)?; - let val = self.retag_reference(val, mutbl, barrier, two_phase)?; - self.write_immediate(val, place)?; + let val = this.read_immediate(this.place_to_op(place)?)?; + let val = this.retag_reference(val, mutbl, barrier, two_phase)?; + this.write_immediate(val, place)?; return Ok(()); } - let place = self.force_allocation(place)?; + let place = this.force_allocation(place)?; - let mut visitor = RetagVisitor { ecx: self, fn_entry, two_phase }; + let mut visitor = RetagVisitor { ecx: this, fn_entry, two_phase }; visitor.visit_value(place)?; // The actual visitor diff --git a/src/tls.rs b/src/tls.rs index af1d7b138b859..5411e021619c4 100644 --- a/src/tls.rs +++ b/src/tls.rs @@ -34,10 +34,6 @@ impl<'tcx> Default for TlsData<'tcx> { } } -pub trait EvalContextExt<'tcx> { - fn run_tls_dtors(&mut self) -> EvalResult<'tcx>; -} - impl<'tcx> TlsData<'tcx> { pub fn create_tls_key( &mut self, @@ -133,35 +129,37 @@ impl<'tcx> TlsData<'tcx> { } } -impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, 'tcx> { +impl<'a, 'mir, 'tcx> EvalContextExt<'a, 'mir, 'tcx> for crate::MiriEvalContext<'a, 'mir, 'tcx> {} +pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, 'mir, 'tcx> { fn run_tls_dtors(&mut self) -> EvalResult<'tcx> { - let mut dtor = self.machine.tls.fetch_tls_dtor(None, &*self.tcx); + let this = self.eval_context_mut(); + let mut dtor = this.machine.tls.fetch_tls_dtor(None, &*this.tcx); // FIXME: replace loop by some structure that works with stepping while let Some((instance, ptr, key)) = dtor { trace!("Running TLS dtor {:?} on {:?}", instance, ptr); // TODO: Potentially, this has to support all the other possible instances? // See eval_fn_call in interpret/terminator/mod.rs - let mir = self.load_mir(instance.def)?; - let ret_place = MPlaceTy::dangling(self.layout_of(self.tcx.mk_unit())?, self).into(); - self.push_stack_frame( + let mir = this.load_mir(instance.def)?; + let ret_place = MPlaceTy::dangling(this.layout_of(this.tcx.mk_unit())?, this).into(); + this.push_stack_frame( instance, mir.span, mir, Some(ret_place), StackPopCleanup::None { cleanup: true }, )?; - let arg_local = self.frame().mir.args_iter().next().ok_or_else( + let arg_local = this.frame().mir.args_iter().next().ok_or_else( || EvalErrorKind::AbiViolation("TLS dtor does not take enough arguments.".to_owned()), )?; - let dest = self.eval_place(&mir::Place::Local(arg_local))?; - self.write_scalar(ptr, dest)?; + let dest = this.eval_place(&mir::Place::Local(arg_local))?; + this.write_scalar(ptr, dest)?; // step until out of stackframes - self.run()?; + this.run()?; - dtor = match self.machine.tls.fetch_tls_dtor(Some(key), &*self.tcx) { + dtor = match this.machine.tls.fetch_tls_dtor(Some(key), &*this.tcx) { dtor @ Some(_) => dtor, - None => self.machine.tls.fetch_tls_dtor(None, &*self.tcx), + None => this.machine.tls.fetch_tls_dtor(None, &*this.tcx), }; } // FIXME: On a windows target, call `unsafe extern "system" fn on_tls_callback`. From 383d215386f7b9cb4b08bde9b7fd0db4c3f8112a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 11 Dec 2018 14:18:51 +0100 Subject: [PATCH 0471/3747] make some functions private to StackedBorrows --- src/stacked_borrows.rs | 149 +++++++++++++++++++++-------------------- 1 file changed, 76 insertions(+), 73 deletions(-) diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 17da5c1526929..748ac020d6a81 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -516,6 +516,82 @@ impl<'tcx> Stacks { } } +impl<'a, 'mir, 'tcx> EvalContextPrivExt<'a, 'mir, 'tcx> for crate::MiriEvalContext<'a, 'mir, 'tcx> {} +trait EvalContextPrivExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, 'mir, 'tcx> { + fn reborrow( + &mut self, + place: MPlaceTy<'tcx, Borrow>, + size: Size, + fn_barrier: bool, + new_bor: Borrow + ) -> EvalResult<'tcx> { + let this = self.eval_context_mut(); + let ptr = place.ptr.to_ptr()?; + let barrier = if fn_barrier { Some(this.frame().extra) } else { None }; + trace!("reborrow: Creating new reference for {:?} (pointee {}): {:?}", + ptr, place.layout.ty, new_bor); + + // Get the allocation. It might not be mutable, so we cannot use `get_mut`. + let alloc = this.memory().get(ptr.alloc_id)?; + alloc.check_bounds(this, ptr, size)?; + // Update the stacks. + if let Borrow::Shr(Some(_)) = new_bor { + // Reference that cares about freezing. We need a frozen-sensitive reborrow. + this.visit_freeze_sensitive(place, size, |cur_ptr, size, frozen| { + let kind = if frozen { RefKind::Frozen } else { RefKind::Raw }; + alloc.extra.reborrow(cur_ptr, size, barrier, new_bor, kind) + })?; + } else { + // Just treat this as one big chunk. + let kind = if new_bor.is_unique() { RefKind::Unique } else { RefKind::Raw }; + alloc.extra.reborrow(ptr, size, barrier, new_bor, kind)?; + } + Ok(()) + } + + /// Retag an indidual pointer, returning the retagged version. + fn retag_reference( + &mut self, + val: ImmTy<'tcx, Borrow>, + mutbl: Mutability, + fn_barrier: bool, + two_phase: bool, + ) -> EvalResult<'tcx, Immediate> { + let this = self.eval_context_mut(); + // We want a place for where the ptr *points to*, so we get one. + let place = this.ref_to_mplace(val)?; + let size = this.size_and_align_of_mplace(place)? + .map(|(size, _)| size) + .unwrap_or_else(|| place.layout.size); + if size == Size::ZERO { + // Nothing to do for ZSTs. + return Ok(*val); + } + + // Compute new borrow. + let time = this.machine.stacked_borrows.increment_clock(); + let new_bor = match mutbl { + MutMutable => Borrow::Uniq(time), + MutImmutable => Borrow::Shr(Some(time)), + }; + + // Reborrow. + this.reborrow(place, size, fn_barrier, new_bor)?; + let new_place = place.with_tag(new_bor); + // Handle two-phase borrows. + if two_phase { + assert!(mutbl == MutMutable, "two-phase shared borrows make no sense"); + // We immediately share it, to allow read accesses + let two_phase_time = this.machine.stacked_borrows.increment_clock(); + let two_phase_bor = Borrow::Shr(Some(two_phase_time)); + this.reborrow(new_place, size, /*fn_barrier*/false, two_phase_bor)?; + } + + // Return new ptr. + Ok(new_place.to_ref()) + } +} + impl<'a, 'mir, 'tcx> EvalContextExt<'a, 'mir, 'tcx> for crate::MiriEvalContext<'a, 'mir, 'tcx> {} pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, 'mir, 'tcx> { fn tag_new_allocation( @@ -601,79 +677,6 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, Ok(()) } - fn reborrow( - &mut self, - place: MPlaceTy<'tcx, Borrow>, - size: Size, - fn_barrier: bool, - new_bor: Borrow - ) -> EvalResult<'tcx> { - let this = self.eval_context_mut(); - let ptr = place.ptr.to_ptr()?; - let barrier = if fn_barrier { Some(this.frame().extra) } else { None }; - trace!("reborrow: Creating new reference for {:?} (pointee {}): {:?}", - ptr, place.layout.ty, new_bor); - - // Get the allocation. It might not be mutable, so we cannot use `get_mut`. - let alloc = this.memory().get(ptr.alloc_id)?; - alloc.check_bounds(this, ptr, size)?; - // Update the stacks. - if let Borrow::Shr(Some(_)) = new_bor { - // Reference that cares about freezing. We need a frozen-sensitive reborrow. - this.visit_freeze_sensitive(place, size, |cur_ptr, size, frozen| { - let kind = if frozen { RefKind::Frozen } else { RefKind::Raw }; - alloc.extra.reborrow(cur_ptr, size, barrier, new_bor, kind) - })?; - } else { - // Just treat this as one big chunk. - let kind = if new_bor.is_unique() { RefKind::Unique } else { RefKind::Raw }; - alloc.extra.reborrow(ptr, size, barrier, new_bor, kind)?; - } - Ok(()) - } - - /// Retag an indidual pointer, returning the retagged version. - fn retag_reference( - &mut self, - val: ImmTy<'tcx, Borrow>, - mutbl: Mutability, - fn_barrier: bool, - two_phase: bool, - ) -> EvalResult<'tcx, Immediate> { - let this = self.eval_context_mut(); - // We want a place for where the ptr *points to*, so we get one. - let place = this.ref_to_mplace(val)?; - let size = this.size_and_align_of_mplace(place)? - .map(|(size, _)| size) - .unwrap_or_else(|| place.layout.size); - if size == Size::ZERO { - // Nothing to do for ZSTs. - return Ok(*val); - } - - // Compute new borrow. - let time = this.machine.stacked_borrows.increment_clock(); - let new_bor = match mutbl { - MutMutable => Borrow::Uniq(time), - MutImmutable => Borrow::Shr(Some(time)), - }; - - // Reborrow. - this.reborrow(place, size, fn_barrier, new_bor)?; - let new_place = place.with_tag(new_bor); - // Handle two-phase borrows. - if two_phase { - assert!(mutbl == MutMutable, "two-phase shared borrows make no sense"); - // We immediately share it, to allow read accesses - let two_phase_time = this.machine.stacked_borrows.increment_clock(); - let two_phase_bor = Borrow::Shr(Some(two_phase_time)); - this.reborrow(new_place, size, /*fn_barrier*/false, two_phase_bor)?; - } - - // Return new ptr. - Ok(new_place.to_ref()) - } - fn retag( &mut self, fn_entry: bool, From 6b376dc3940513b5f7414333a42ce28b47268965 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 11 Dec 2018 14:32:59 +0100 Subject: [PATCH 0472/3747] get rid of to_bytes hack --- src/fn_call.rs | 18 +++++++++--------- src/helpers.rs | 25 ------------------------- src/intrinsic.rs | 8 ++++---- src/lib.rs | 2 +- 4 files changed, 14 insertions(+), 39 deletions(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index ea913417a56e0..5d41848b643e7 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -277,7 +277,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, "memrchr" => { let ptr = this.read_scalar(args[0])?.not_undef()?; - let val = this.read_scalar(args[1])?.to_bytes()? as u8; + let val = this.read_scalar(args[1])?.to_i32()? as u8; let num = this.read_scalar(args[2])?.to_usize(this)?; if let Some(idx) = this.memory().read_bytes(ptr, Size::from_bytes(num))? .iter().rev().position(|&c| c == val) @@ -291,7 +291,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, "memchr" => { let ptr = this.read_scalar(args[0])?.not_undef()?; - let val = this.read_scalar(args[1])?.to_bytes()? as u8; + let val = this.read_scalar(args[1])?.to_i32()? as u8; let num = this.read_scalar(args[2])?.to_usize(this)?; if let Some(idx) = this.memory().read_bytes(ptr, Size::from_bytes(num))?.iter().position( |&c| c == val, @@ -379,9 +379,9 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, } "write" => { - let fd = this.read_scalar(args[0])?.to_bytes()?; + let fd = this.read_scalar(args[0])?.to_i32()?; let buf = this.read_scalar(args[1])?.not_undef()?; - let n = this.read_scalar(args[2])?.to_bytes()? as u64; + let n = this.read_scalar(args[2])?.to_usize(&*this.tcx)?; trace!("Called write({:?}, {:?}, {:?})", fd, buf, n); let result = if fd == 1 || fd == 2 { // stdout/stderr @@ -489,18 +489,18 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, this.write_null(dest)?; } "pthread_key_delete" => { - let key = this.read_scalar(args[0])?.to_bytes()?; + let key = this.read_scalar(args[0])?.to_bits(args[0].layout.size)?; this.machine.tls.delete_tls_key(key)?; // Return success (0) this.write_null(dest)?; } "pthread_getspecific" => { - let key = this.read_scalar(args[0])?.to_bytes()?; + let key = this.read_scalar(args[0])?.to_bits(args[0].layout.size)?; let ptr = this.machine.tls.load_tls(key)?; this.write_scalar(ptr, dest)?; } "pthread_setspecific" => { - let key = this.read_scalar(args[0])?.to_bytes()?; + let key = this.read_scalar(args[0])?.to_bits(args[0].layout.size)?; let new_ptr = this.read_scalar(args[1])?.not_undef()?; this.machine.tls.store_tls(key, new_ptr)?; @@ -586,12 +586,12 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, this.write_scalar(Scalar::from_uint(key, dest.layout.size), dest)?; } "TlsGetValue" => { - let key = this.read_scalar(args[0])?.to_bytes()?; + let key = this.read_scalar(args[0])?.to_bits(args[0].layout.size)?; let ptr = this.machine.tls.load_tls(key)?; this.write_scalar(ptr, dest)?; } "TlsSetValue" => { - let key = this.read_scalar(args[0])?.to_bytes()?; + let key = this.read_scalar(args[0])?.to_bits(args[0].layout.size)?; let new_ptr = this.read_scalar(args[1])?.not_undef()?; this.machine.tls.store_tls(key, new_ptr)?; diff --git a/src/helpers.rs b/src/helpers.rs index 7be1567605083..fab0c67d0aa4b 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -5,31 +5,6 @@ use rustc::hir::def_id::{DefId, CRATE_DEF_INDEX}; use crate::*; -pub trait ScalarExt { - /// 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 - fn to_bytes(self) -> EvalResult<'static, u128>; -} - -impl ScalarExt for Scalar { - fn to_bytes(self) -> EvalResult<'static, u128> { - match self { - Scalar::Bits { bits, size } => { - assert_ne!(size, 0); - Ok(bits) - }, - Scalar::Ptr(_) => err!(ReadPointerAsBytes), - } - } -} - -impl ScalarExt for ScalarMaybeUndef { - fn to_bytes(self) -> EvalResult<'static, u128> { - self.not_undef()?.to_bytes() - } -} - impl<'a, 'mir, 'tcx> EvalContextExt<'a, 'mir, 'tcx> for crate::MiriEvalContext<'a, 'mir, 'tcx> {} pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, 'mir, 'tcx> { /// Get an instance for a path. diff --git a/src/intrinsic.rs b/src/intrinsic.rs index 35182ba5137ac..0f7382b61b726 100644 --- a/src/intrinsic.rs +++ b/src/intrinsic.rs @@ -6,7 +6,7 @@ use rustc::mir::interpret::{EvalResult, PointerArithmetic}; use crate::{ PlaceTy, OpTy, Immediate, Scalar, ScalarMaybeUndef, Borrow, - ScalarExt, OperatorEvalContextExt + OperatorEvalContextExt }; impl<'a, 'mir, 'tcx> EvalContextExt<'a, 'mir, 'tcx> for crate::MiriEvalContext<'a, 'mir, 'tcx> {} @@ -227,7 +227,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, let a = this.read_immediate(args[0])?; let b = this.read_immediate(args[1])?; // check x % y != 0 - if this.binary_op_imm(mir::BinOp::Rem, a, b)?.0.to_bytes()? != 0 { + if this.binary_op_imm(mir::BinOp::Rem, a, b)?.0.to_bits(dest.layout.size)? != 0 { return err!(ValidationFailure(format!("exact_div: {:?} cannot be divided by {:?}", a, b))); } this.binop_ignore_overflow(mir::BinOp::Div, a, b, dest)?; @@ -375,7 +375,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, "unchecked_div" => { let l = this.read_immediate(args[0])?; let r = this.read_immediate(args[1])?; - let rval = r.to_scalar()?.to_bytes()?; + let rval = r.to_scalar()?.to_bits(args[1].layout.size)?; if rval == 0 { return err!(Intrinsic(format!("Division by 0 in unchecked_div"))); } @@ -390,7 +390,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, "unchecked_rem" => { let l = this.read_immediate(args[0])?; let r = this.read_immediate(args[1])?; - let rval = r.to_scalar()?.to_bytes()?; + let rval = r.to_scalar()?.to_bits(args[1].layout.size)?; if rval == 0 { return err!(Intrinsic(format!("Division by 0 in unchecked_rem"))); } diff --git a/src/lib.rs b/src/lib.rs index aabfa36a4b5ba..28639976aa03f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -43,7 +43,7 @@ pub use crate::intrinsic::EvalContextExt as IntrinsicEvalContextExt; pub use crate::tls::{EvalContextExt as TlsEvalContextExt, TlsData}; use crate::range_map::RangeMap; #[allow(unused_imports)] // FIXME rustc bug https://github.com/rust-lang/rust/issues/53682 -pub use crate::helpers::{ScalarExt, EvalContextExt as HelpersEvalContextExt}; +pub use crate::helpers::{EvalContextExt as HelpersEvalContextExt}; use crate::mono_hash_map::MonoHashMap; pub use crate::stacked_borrows::{EvalContextExt as StackedBorEvalContextExt}; From f31bb43804fd70452eb8e20f83065aad186f8ec5 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 27 Nov 2018 15:06:08 +0100 Subject: [PATCH 0473/3747] implement some libc hooks needed by libtest --- src/fn_call.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/fn_call.rs b/src/fn_call.rs index 5d41848b643e7..8909223a31d7c 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -426,6 +426,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, let paths = &[ (&["libc", "_SC_PAGESIZE"], Scalar::from_int(4096, dest.layout.size)), (&["libc", "_SC_GETPW_R_SIZE_MAX"], Scalar::from_int(-1, dest.layout.size)), + (&["libc", "_SC_NPROCESSORS_ONLN"], Scalar::from_int(1, dest.layout.size)), ]; let mut result = None; for &(path, path_value) in paths { @@ -452,6 +453,10 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, } } + "isatty" => { + self.write_null(dest)?; + } + // Hook pthread calls that go to the thread-local storage memory subsystem "pthread_key_create" => { let key_ptr = this.read_scalar(args[0])?.to_ptr()?; From 9417b28de55888d99aeefcd03243294b658b4d97 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 27 Nov 2018 15:06:23 +0100 Subject: [PATCH 0474/3747] treat test binaries like all others --- src/bin/cargo-miri.rs | 5 ++--- src/bin/miri.rs | 45 ++++++------------------------------------- 2 files changed, 8 insertions(+), 42 deletions(-) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 7e1785fd3b938..179f11dd56a3d 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -279,9 +279,8 @@ fn main() { (MiriCommand::Test, "lib") => { // For libraries we call `cargo rustc -- --test ` // Notice now that `--test` is a rustc arg rather than a cargo arg. This tells - // rustc to build a test harness which calls all #[test] functions. We don't - // use the harness since we execute each #[test] function's MIR ourselves before - // compilation even completes, but this option is necessary to build the library. + // rustc to build a test harness which calls all #[test] functions. + // We then execute that harness just like any other binary. if let Err(code) = process( vec!["--".to_string(), "--test".to_string()].into_iter().chain( args, diff --git a/src/bin/miri.rs b/src/bin/miri.rs index e88c13305d154..c2255d706339d 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -23,8 +23,6 @@ use rustc_metadata::cstore::CStore; use rustc_driver::{Compilation, CompilerCalls, RustcDefaultCalls}; use rustc_driver::driver::{CompileState, CompileController}; use rustc::session::config::{self, Input, ErrorOutputType}; -use rustc::hir::{self, itemlikevisit}; -use rustc::ty::TyCtxt; use rustc_codegen_utils::codegen_backend::CodegenBackend; use syntax::ast; @@ -115,43 +113,12 @@ fn after_analysis<'a, 'tcx>( let tcx = state.tcx.unwrap(); - if std::env::args().any(|arg| arg == "--test") { - struct Visitor<'a, 'tcx: 'a> { - tcx: TyCtxt<'a, 'tcx, 'tcx>, - state: &'a CompileState<'a, 'tcx>, - validate: bool, - }; - impl<'a, 'tcx: 'a, 'hir> itemlikevisit::ItemLikeVisitor<'hir> for Visitor<'a, 'tcx> { - fn visit_item(&mut self, i: &'hir hir::Item) { - if let hir::ItemKind::Fn(.., body_id) = i.node { - if i.attrs.iter().any(|attr| { - attr.name() == "test" - }) - { - let did = self.tcx.hir().body_owner_def_id(body_id); - println!( - "running test: {}", - self.tcx.def_path_debug_str(did), - ); - miri::eval_main(self.tcx, did, self.validate); - self.state.session.abort_if_errors(); - } - } - } - fn visit_trait_item(&mut self, _trait_item: &'hir hir::TraitItem) {} - fn visit_impl_item(&mut self, _impl_item: &'hir hir::ImplItem) {} - } - state.hir_crate.unwrap().visit_all_item_likes( - &mut Visitor { tcx, state, validate } - ); - } else if let Some((entry_node_id, _, _)) = *state.session.entry_fn.borrow() { - let entry_def_id = tcx.hir().local_def_id(entry_node_id); - miri::eval_main(tcx, entry_def_id, validate); - - state.session.abort_if_errors(); - } else { - println!("no main function found, assuming auxiliary build"); - } + let (entry_node_id, _, _) = state.session.entry_fn.borrow().expect("no main function found!"); + let entry_def_id = tcx.hir().local_def_id(entry_node_id); + + miri::eval_main(tcx, entry_def_id, validate); + + state.session.abort_if_errors(); } fn init_early_loggers() { From 3fda8294bdc8dedfc299cd15d0d40c19d7da598f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 27 Nov 2018 15:06:51 +0100 Subject: [PATCH 0475/3747] test cargo miri test output when testing cargo miri --- test-cargo-miri/run-test.py | 19 +++++++++++-------- test-cargo-miri/test.stderr.ref | 0 test-cargo-miri/test.stdout.ref | 7 +++++++ test-cargo-miri/tests/foo.rs | 7 +++++++ 4 files changed, 25 insertions(+), 8 deletions(-) create mode 100644 test-cargo-miri/test.stderr.ref create mode 100644 test-cargo-miri/test.stdout.ref diff --git a/test-cargo-miri/run-test.py b/test-cargo-miri/run-test.py index 42745535e0ef4..c7ab8f14df883 100755 --- a/test-cargo-miri/run-test.py +++ b/test-cargo-miri/run-test.py @@ -7,11 +7,11 @@ import sys, subprocess -def test_cargo_miri(): - print("==> Testing `cargo miri run` <==") +def test(name, cmd, stdout_ref, stderr_ref): + print("==> Testing `{}` <==".format(name)) ## Call `cargo miri`, capture all output p = subprocess.Popen( - ["cargo", "miri", "run", "-q"], + cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE ) @@ -26,17 +26,20 @@ def test_cargo_miri(): # Test for failures if p.returncode != 0: sys.exit(1) - if stdout != open('stdout.ref').read(): + if stdout != open(stdout_ref).read(): print("stdout does not match reference") sys.exit(1) - if stderr != open('stderr.ref').read(): + if stderr != open(stderr_ref).read(): print("stderr does not match reference") sys.exit(1) +def test_cargo_miri_run(): + test("cargo miri run", ["cargo", "miri", "run", "-q"], "stout.ref", "stderr.ref") + def test_cargo_miri_test(): - print("==> Testing `cargo miri test` <==") - subprocess.check_call(["cargo", "miri", "test"]) + # FIXME: validation disabled for now because of https://github.com/rust-lang/rust/issues/54957 + test("cargo miri test", ["cargo", "miri", "test", "-q", "--", "-Zmiri-disable-validation"], "stout.ref", "stderr.ref") -test_cargo_miri() +test_cargo_miri_run() test_cargo_miri_test() sys.exit(0) diff --git a/test-cargo-miri/test.stderr.ref b/test-cargo-miri/test.stderr.ref new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/test-cargo-miri/test.stdout.ref b/test-cargo-miri/test.stdout.ref new file mode 100644 index 0000000000000..94fd56b0cd6f3 --- /dev/null +++ b/test-cargo-miri/test.stdout.ref @@ -0,0 +1,7 @@ + +running 2 tests +test bar ... ok +test baz ... ok + +test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out + diff --git a/test-cargo-miri/tests/foo.rs b/test-cargo-miri/tests/foo.rs index fb7fad21c9db8..9827ae82d6cfd 100644 --- a/test-cargo-miri/tests/foo.rs +++ b/test-cargo-miri/tests/foo.rs @@ -2,3 +2,10 @@ fn bar() { assert_eq!(4, 4); } + +// Having more than 1 test does seem to make a difference +// (i.e., this calls ptr::swap which having just one test does not). +#[test] +fn baz() { + assert_eq!(5, 5); +} From ce5089c3905f7051a9bcdc92ef24ba934dc75098 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 11 Dec 2018 17:54:39 +0100 Subject: [PATCH 0476/3747] rebase fallout --- src/fn_call.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index 8909223a31d7c..d11364ce0d180 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -454,7 +454,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, } "isatty" => { - self.write_null(dest)?; + this.write_null(dest)?; } // Hook pthread calls that go to the thread-local storage memory subsystem From 8ec371747a742d8f96effe80b9bfcfa53ff6fa62 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 12 Dec 2018 11:03:42 +0100 Subject: [PATCH 0477/3747] do not auto-detect the targets in the sysroot, instead specify target manually through env var --- .travis.yml | 14 ++++--- README.md | 12 +++++- tests/compiletest.rs | 89 ++++++++++++-------------------------------- 3 files changed, 41 insertions(+), 74 deletions(-) diff --git a/.travis.yml b/.travis.yml index 1d49394e29b8e..a58ff4f67d8d1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -29,6 +29,12 @@ before_script: else export MIRI_SYSROOT_BASE=~/.cache/miri/ fi +- | + if [[ "$TRAVIS_OS_NAME" == osx ]]; then + FOREIGN_TARGET=i686-apple-darwin + else + FOREIGN_TARGET=i686-unknown-linux-gnu + fi # install Rust - curl https://build.travis-ci.org/files/rustup-init.sh -sSf | sh -s -- -y --default-toolchain "$RUST_TOOLCHAIN" - export PATH=$HOME/.cargo/bin:$PATH @@ -43,15 +49,11 @@ script: - | # Get ourselves a MIR-full libstd for the host and a foreign architecture cargo miri setup && - if [[ "$TRAVIS_OS_NAME" == osx ]]; then - cargo miri setup --target i686-apple-darwin - else - cargo miri setup --target i686-unknown-linux-gnu - fi + cargo miri setup --target "$FOREIGN_TARGET" - | # Test miri with full MIR, on the host and other architectures MIRI_SYSROOT=$MIRI_SYSROOT_BASE/HOST cargo test --release --all-features && - MIRI_SYSROOT=$MIRI_SYSROOT_BASE cargo test --release --all-features + MIRI_SYSROOT=$MIRI_SYSROOT_BASE MIRI_TARGET=$FOREIGN_TARGET cargo test --release --all-features - | # Test cargo integration (cd test-cargo-miri && MIRI_SYSROOT=$MIRI_SYSROOT_BASE/HOST ./run-test.py) diff --git a/README.md b/README.md index 1b9e5304bd037..b6e1c20076de9 100644 --- a/README.md +++ b/README.md @@ -154,9 +154,9 @@ MIRI_LOG=rustc_mir::interpret=debug,miri::stacked_borrows cargo run tests/run-pa In addition, you can set `MIRI_BACKTRACE=1` to get a backtrace of where an evaluation error was originally created. -### Miri `-Z` flags +### Miri `-Z` flags and environment variables -Several `-Z` flags are relevant for miri: +Several `-Z` flags are relevant for Miri: * `-Zmir-opt-level` controls how many MIR optimizations are performed. miri overrides the default to be `0`; be advised that using any higher level can @@ -168,6 +168,14 @@ Several `-Z` flags are relevant for miri: enforcing the validity invariant, which is enforced by default. This is mostly useful for debugging; it means miri will miss bugs in your program. +Moreover, Miri recognizes some environment variables: + +* `MIRI_SYSROOT` (recognized by `miri`, `cargo miri` and the test suite) + indicates the sysroot to use. +* `MIRI_TARGET` (recognized by the test suite) indicates which target + architecture to test against. `miri` and `cargo miri` accept the `--target` + flag for the same purpose. + ## Contributing and getting help Check out the issues on this GitHub repository for some ideas. There's lots that diff --git a/tests/compiletest.rs b/tests/compiletest.rs index 7187a3caee25c..a0862d00326ca 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -34,10 +34,11 @@ fn mk_config(mode: &str) -> compiletest::common::ConfigWithTemp { config.compile_lib_path = rustc_lib_path(); } config.filter = env::args().nth(1); + config.host = get_host(); config } -fn compile_fail(sysroot: &Path, path: &str, target: &str, host: &str, opt: bool) { +fn compile_fail(path: &str, target: &str, opt: bool) { let opt_str = if opt { " with optimizations" } else { "" }; eprintln!("{}", format!( "## Running compile-fail tests in {} against miri for target {}{}", @@ -47,7 +48,6 @@ fn compile_fail(sysroot: &Path, path: &str, target: &str, host: &str, opt: bool) ).green().bold()); let mut flags = Vec::new(); - flags.push(format!("--sysroot {}", sysroot.display())); flags.push("-Dwarnings -Dunused".to_owned()); // overwrite the -Aunused in compiletest-rs flags.push("--edition 2018".to_owned()); if opt { @@ -60,12 +60,11 @@ fn compile_fail(sysroot: &Path, path: &str, target: &str, host: &str, opt: bool) let mut config = mk_config("compile-fail"); config.src_base = PathBuf::from(path); config.target = target.to_owned(); - config.host = host.to_owned(); config.target_rustcflags = Some(flags.join(" ")); compiletest::run_tests(&config); } -fn miri_pass(sysroot: &Path, path: &str, target: &str, host: &str, opt: bool) { +fn miri_pass(path: &str, target: &str, opt: bool) { let opt_str = if opt { " with optimizations" } else { "" }; eprintln!("{}", format!( "## Running run-pass tests in {} against miri for target {}{}", @@ -75,7 +74,6 @@ fn miri_pass(sysroot: &Path, path: &str, target: &str, host: &str, opt: bool) { ).green().bold()); let mut flags = Vec::new(); - flags.push(format!("--sysroot {}", sysroot.display())); flags.push("-Dwarnings -Dunused".to_owned()); // overwrite the -Aunused in compiletest-rs flags.push("--edition 2018".to_owned()); if opt { @@ -87,57 +85,24 @@ fn miri_pass(sysroot: &Path, path: &str, target: &str, host: &str, opt: bool) { let mut config = mk_config("ui"); config.src_base = PathBuf::from(path); config.target = target.to_owned(); - config.host = host.to_owned(); config.target_rustcflags = Some(flags.join(" ")); compiletest::run_tests(&config); } -fn is_target_dir>(path: P) -> bool { - let mut path = path.into(); - path.push("lib"); - path.metadata().map(|m| m.is_dir()).unwrap_or(false) -} - -fn target_has_std>(path: P) -> bool { - let mut path = path.into(); - path.push("lib"); - std::fs::read_dir(path) - .expect("invalid target") - .map(|entry| entry.unwrap()) - .filter(|entry| entry.file_type().unwrap().is_file()) - .filter_map(|entry| entry.file_name().into_string().ok()) - .any(|file_name| file_name == "libstd.rlib") -} - - -fn for_all_targets(sysroot: &Path, f: F) { - let target_dir = sysroot.join("lib").join("rustlib"); - let mut targets = std::fs::read_dir(target_dir) - .expect("invalid sysroot") - .map(|entry| entry.unwrap()) - .filter(|entry| is_target_dir(entry.path())) - .filter(|entry| target_has_std(entry.path())) - .map(|entry| entry.file_name().into_string().unwrap()) - .peekable(); - - if targets.peek().is_none() { - panic!("No valid targets found"); +/// Make sure the MIRI_SYSROOT env var is set +fn set_sysroot() { + if std::env::var("MIRI_SYSROOT").is_ok() { + // Nothing to do + return; } - - targets.for_each(f); -} - -fn get_sysroot() -> PathBuf { - let sysroot = std::env::var("MIRI_SYSROOT").unwrap_or_else(|_| { - let sysroot = std::process::Command::new("rustc") - .arg("--print") - .arg("sysroot") - .output() - .expect("rustc not found") - .stdout; - String::from_utf8(sysroot).expect("sysroot is not utf8") - }); - PathBuf::from(sysroot.trim()) + let sysroot = std::process::Command::new("rustc") + .arg("--print") + .arg("sysroot") + .output() + .expect("rustc not found") + .stdout; + let sysroot = String::from_utf8(sysroot).expect("sysroot is not utf8"); + std::env::set_var("MIRI_SYSROOT", sysroot.trim()); } fn get_host() -> String { @@ -153,28 +118,20 @@ fn get_host() -> String { version_meta.host } -fn run_pass_miri(opt: bool) { - let sysroot = get_sysroot(); - let host = get_host(); +fn get_target() -> String { + std::env::var("MIRI_TARGET").unwrap_or_else(|_| get_host()) +} - for_all_targets(&sysroot, |target| { - miri_pass(&sysroot, "tests/run-pass", &target, &host, opt); - }); +fn run_pass_miri(opt: bool) { + miri_pass("tests/run-pass", &get_target(), opt); } fn compile_fail_miri(opt: bool) { - let sysroot = get_sysroot(); - let host = get_host(); - - for_all_targets(&sysroot, |target| { - compile_fail(&sysroot, "tests/compile-fail", &target, &host, opt); - }); + compile_fail("tests/compile-fail", &get_target(), opt); } fn test_runner(_tests: &[&()]) { - // We put everything into a single test to avoid the parallelism `cargo test` - // introduces. We still get parallelism within our tests because `compiletest` - // uses `libtest` which runs jobs in parallel. + set_sysroot(); run_pass_miri(false); run_pass_miri(true); From 7e9098ff692eccd07c509f1a6bee1328e8882d34 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 12 Dec 2018 11:11:20 +0100 Subject: [PATCH 0478/3747] treat ref-to-raw cast like a reborrow: do a special kind of retag --- src/lib.rs | 30 +---------- src/stacked_borrows.rs | 52 +++++++++---------- .../stacked_borrows/transmute-is-no-escape.rs | 9 ++-- 3 files changed, 31 insertions(+), 60 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 28639976aa03f..e821b4f76a341 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -474,36 +474,10 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { } } - #[inline] - fn escape_to_raw( - ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, - ptr: OpTy<'tcx, Self::PointerTag>, - ) -> EvalResult<'tcx> { - // It is tempting to check the type here, but drop glue does EscapeToRaw - // on a raw pointer. - // This is deliberately NOT `deref_operand` as we do not want `tag_dereference` - // to be called! That would kill the original tag if we got a raw ptr. - let place = ecx.ref_to_mplace(ecx.read_immediate(ptr)?)?; - let size = ecx.size_and_align_of_mplace(place)?.map(|(size, _)| size) - // for extern types, just cover what we can - .unwrap_or_else(|| place.layout.size); - if !ecx.tcx.sess.opts.debugging_opts.mir_emit_retag || - !ecx.machine.validate || size == Size::ZERO - { - // No tracking, or no retagging. The latter is possible because a dependency of ours - // might be called with different flags than we are, so there are `Retag` - // statements but we do not want to execute them. - Ok(()) - } else { - ecx.escape_to_raw(place, size) - } - } - #[inline(always)] fn retag( ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, - fn_entry: bool, - two_phase: bool, + kind: mir::RetagKind, place: PlaceTy<'tcx, Borrow>, ) -> EvalResult<'tcx> { if !ecx.tcx.sess.opts.debugging_opts.mir_emit_retag || !Self::enforce_validity(ecx) { @@ -514,7 +488,7 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { // uninitialized data. Ok(()) } else { - ecx.retag(fn_entry, two_phase, place) + ecx.retag(kind, place) } } diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 748ac020d6a81..27d4a4f7f7b58 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -4,6 +4,7 @@ use std::rc::Rc; use rustc::ty::{self, layout::Size}; use rustc::hir::{Mutability, MutMutable, MutImmutable}; +use rustc::mir::RetagKind; use crate::{ EvalResult, EvalErrorKind, MiriEvalContext, HelpersEvalContextExt, Evaluator, MutValueVisitor, @@ -550,10 +551,11 @@ trait EvalContextPrivExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, } /// Retag an indidual pointer, returning the retagged version. + /// `mutbl` can be `None` to make this a raw pointer. fn retag_reference( &mut self, val: ImmTy<'tcx, Borrow>, - mutbl: Mutability, + mutbl: Option, fn_barrier: bool, two_phase: bool, ) -> EvalResult<'tcx, Immediate> { @@ -571,8 +573,9 @@ trait EvalContextPrivExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, // Compute new borrow. let time = this.machine.stacked_borrows.increment_clock(); let new_bor = match mutbl { - MutMutable => Borrow::Uniq(time), - MutImmutable => Borrow::Shr(Some(time)), + Some(MutMutable) => Borrow::Uniq(time), + Some(MutImmutable) => Borrow::Shr(Some(time)), + None => Borrow::default(), }; // Reborrow. @@ -580,7 +583,7 @@ trait EvalContextPrivExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, let new_place = place.with_tag(new_bor); // Handle two-phase borrows. if two_phase { - assert!(mutbl == MutMutable, "two-phase shared borrows make no sense"); + assert!(mutbl == Some(MutMutable), "two-phase shared borrows make no sense"); // We immediately share it, to allow read accesses let two_phase_time = this.machine.stacked_borrows.increment_clock(); let two_phase_bor = Borrow::Shr(Some(two_phase_time)); @@ -665,35 +668,24 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, Ok(()) } - /// The given place may henceforth be accessed through raw pointers. - #[inline(always)] - fn escape_to_raw( - &mut self, - place: MPlaceTy<'tcx, Borrow>, - size: Size, - ) -> EvalResult<'tcx> { - let this = self.eval_context_mut(); - this.reborrow(place, size, /*fn_barrier*/ false, Borrow::default())?; - Ok(()) - } - fn retag( &mut self, - fn_entry: bool, - two_phase: bool, + kind: RetagKind, place: PlaceTy<'tcx, Borrow> ) -> EvalResult<'tcx> { let this = self.eval_context_mut(); // Determine mutability and whether to add a barrier. // Cannot use `builtin_deref` because that reports *immutable* for `Box`, // making it useless. - fn qualify(ty: ty::Ty<'_>, fn_entry: bool) -> Option<(Mutability, bool)> { + fn qualify(ty: ty::Ty<'_>, kind: RetagKind) -> Option<(Option, bool)> { match ty.sty { // References are simple - ty::Ref(_, _, mutbl) => Some((mutbl, fn_entry)), + ty::Ref(_, _, mutbl) => Some((Some(mutbl), kind == RetagKind::FnEntry)), + // Raw pointers need to be enabled + ty::RawPtr(..) if kind == RetagKind::Raw => Some((None, false)), // Boxes do not get a barrier: Barriers reflect that references outlive the call // they were passed in to; that's just not the case for boxes. - ty::Adt(..) if ty.is_box() => Some((MutMutable, false)), + ty::Adt(..) if ty.is_box() => Some((Some(MutMutable), false)), _ => None, } } @@ -701,23 +693,22 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, // We need a visitor to visit all references. However, that requires // a `MemPlace`, so we have a fast path for reference types that // avoids allocating. - if let Some((mutbl, barrier)) = qualify(place.layout.ty, fn_entry) { + if let Some((mutbl, barrier)) = qualify(place.layout.ty, kind) { // fast path let val = this.read_immediate(this.place_to_op(place)?)?; - let val = this.retag_reference(val, mutbl, barrier, two_phase)?; + let val = this.retag_reference(val, mutbl, barrier, kind == RetagKind::TwoPhase)?; this.write_immediate(val, place)?; return Ok(()); } let place = this.force_allocation(place)?; - let mut visitor = RetagVisitor { ecx: this, fn_entry, two_phase }; + let mut visitor = RetagVisitor { ecx: this, kind }; visitor.visit_value(place)?; // The actual visitor struct RetagVisitor<'ecx, 'a, 'mir, 'tcx> { ecx: &'ecx mut MiriEvalContext<'a, 'mir, 'tcx>, - fn_entry: bool, - two_phase: bool, + kind: RetagKind, } impl<'ecx, 'a, 'mir, 'tcx> MutValueVisitor<'a, 'mir, 'tcx, Evaluator<'tcx>> @@ -736,9 +727,14 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, { // Cannot use `builtin_deref` because that reports *immutable* for `Box`, // making it useless. - if let Some((mutbl, barrier)) = qualify(place.layout.ty, self.fn_entry) { + if let Some((mutbl, barrier)) = qualify(place.layout.ty, self.kind) { let val = self.ecx.read_immediate(place.into())?; - let val = self.ecx.retag_reference(val, mutbl, barrier, self.two_phase)?; + let val = self.ecx.retag_reference( + val, + mutbl, + barrier, + self.kind == RetagKind::TwoPhase + )?; self.ecx.write_immediate(val, place.into())?; } Ok(()) diff --git a/tests/compile-fail/stacked_borrows/transmute-is-no-escape.rs b/tests/compile-fail/stacked_borrows/transmute-is-no-escape.rs index 75abce3111f88..197c11197efa6 100644 --- a/tests/compile-fail/stacked_borrows/transmute-is-no-escape.rs +++ b/tests/compile-fail/stacked_borrows/transmute-is-no-escape.rs @@ -1,13 +1,14 @@ // Make sure we cannot use raw ptrs that got transmuted from mutable references // (i.e, no EscapeToRaw happened). -// We could, in principle, to EscapeToRaw lazily to allow this code, but that +// We could, in principle, do EscapeToRaw lazily to allow this code, but that // would no alleviate the need for EscapeToRaw (see `ref_raw_int_raw` in // `run-pass/stacked-borrows.rs`), and thus increase overall complexity. use std::mem; fn main() { - let mut x: i32 = 42; - let raw: *mut i32 = unsafe { mem::transmute(&mut x) }; - let raw = raw as usize as *mut i32; // make sure we killed the tag + let mut x: [i32; 2] = [42, 43]; + let _raw: *mut i32 = unsafe { mem::transmute(&mut x[0]) }; + // `raw` still carries a tag, so we get another pointer to the same location that does not carry a tag + let raw = (&mut x[1] as *mut i32).wrapping_offset(-1); unsafe { *raw = 13; } //~ ERROR does not exist on the stack } From ed83cc2600049adaf7d142ff7f5defb3c691d6b2 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 12 Dec 2018 17:03:40 +0100 Subject: [PATCH 0479/3747] use RUSTC_WRAPPER for the cargo hook --- src/bin/cargo-miri.rs | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 7e1785fd3b938..f428062b3fc4a 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -305,8 +305,8 @@ fn main() { _ => {} } } - } else { - // This arm is executed when cargo-miri runs `cargo rustc` with the `RUSTC` env var set to itself: + } else if let Some("rustc") = std::env::args().nth(1).as_ref().map(AsRef::as_ref) { + // This arm is executed when cargo-miri runs `cargo rustc` with the `RUSTC_WRAPPER` env var set to itself: // Dependencies get dispatched to rustc, the final test/binary to miri. let home = option_env!("RUSTUP_HOME").or(option_env!("MULTIRUST_HOME")); @@ -332,11 +332,11 @@ fn main() { // this conditional check for the --sysroot flag is there so users can call `cargo-miri` directly // without having to pass --sysroot or anything + let rustc_args = std::env::args().skip(2); let mut args: Vec = if std::env::args().any(|s| s == "--sysroot") { - std::env::args().skip(1).collect() + rustc_args.collect() } else { - std::env::args() - .skip(1) + rustc_args .chain(Some("--sysroot".to_owned())) .chain(Some(sys_root)) .collect() @@ -365,6 +365,8 @@ fn main() { Err(ref e) if miri_enabled => panic!("error during miri run: {:?}", e), Err(ref e) => panic!("error during rustc call: {:?}", e), } + } else { + eprintln!("Unexpected call: Must be called with either `miri` or `rustc` as first argument.") } } @@ -389,7 +391,7 @@ where let path = std::env::current_exe().expect("current executable path invalid"); let exit_status = Command::new("cargo") .args(&args) - .env("RUSTC", path) + .env("RUSTC_WRAPPER", path) .spawn() .expect("could not run cargo") .wait() From b6a4556cb9d6458bb97c8e8ff91e71b7c13d094b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 12 Dec 2018 17:05:23 +0100 Subject: [PATCH 0480/3747] use show_error to terminate --- src/bin/cargo-miri.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index f428062b3fc4a..71cd46314b5a2 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -366,7 +366,7 @@ fn main() { Err(ref e) => panic!("error during rustc call: {:?}", e), } } else { - eprintln!("Unexpected call: Must be called with either `miri` or `rustc` as first argument.") + show_error!("Must be called with either `miri` or `rustc` as first argument.") } } From e6147ae67eaad7ba2de11ae8e4a57c5cc022dd29 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 12 Dec 2018 17:30:20 +0100 Subject: [PATCH 0481/3747] *oops* --- src/bin/cargo-miri.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 71cd46314b5a2..6d2dc1dd2f1a0 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -366,7 +366,7 @@ fn main() { Err(ref e) => panic!("error during rustc call: {:?}", e), } } else { - show_error!("Must be called with either `miri` or `rustc` as first argument.") + show_error(format!("Must be called with either `miri` or `rustc` as first argument.")) } } From 74e9ed998b68de78c6bde206537cdb05b6cd2a6a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 12 Dec 2018 19:15:57 +0100 Subject: [PATCH 0482/3747] move travis commands to script file, maybe that fixes the macOS weirdness --- .travis.yml | 33 ++------------------------------- travis.sh | 26 ++++++++++++++++++++++++++ 2 files changed, 28 insertions(+), 31 deletions(-) create mode 100755 travis.sh diff --git a/.travis.yml b/.travis.yml index a58ff4f67d8d1..dfc4238a6c03d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -12,10 +12,8 @@ os: dist: xenial before_script: -# install extra stuff for cross-compilation +# Linux: install extra stuff for cross-compilation - if [[ "$TRAVIS_OS_NAME" == linux ]]; then sudo apt update && sudo apt install gcc-multilib; fi -# macOS weirdness (https://github.com/travis-ci/travis-ci/issues/6307, https://github.com/travis-ci/travis-ci/issues/10165) -- if [[ "$TRAVIS_OS_NAME" == osx ]]; then rvm get stable; fi # Compute the rust version we use. We do not use "language: rust" to have more control here. - | if [[ "$TRAVIS_EVENT_TYPE" == cron ]]; then @@ -23,40 +21,13 @@ before_script: else RUST_TOOLCHAIN=$(cat rust-version) fi -- | - if [ "$TRAVIS_OS_NAME" == osx ]; then - export MIRI_SYSROOT_BASE=~/Library/Caches/miri.miri.miri/ - else - export MIRI_SYSROOT_BASE=~/.cache/miri/ - fi -- | - if [[ "$TRAVIS_OS_NAME" == osx ]]; then - FOREIGN_TARGET=i686-apple-darwin - else - FOREIGN_TARGET=i686-unknown-linux-gnu - fi # install Rust - curl https://build.travis-ci.org/files/rustup-init.sh -sSf | sh -s -- -y --default-toolchain "$RUST_TOOLCHAIN" - export PATH=$HOME/.cargo/bin:$PATH - rustc --version script: -- set -e -- | - # Build and install miri - cargo build --release --all-features --all-targets && - cargo install --all-features --force --path . -- | - # Get ourselves a MIR-full libstd for the host and a foreign architecture - cargo miri setup && - cargo miri setup --target "$FOREIGN_TARGET" -- | - # Test miri with full MIR, on the host and other architectures - MIRI_SYSROOT=$MIRI_SYSROOT_BASE/HOST cargo test --release --all-features && - MIRI_SYSROOT=$MIRI_SYSROOT_BASE MIRI_TARGET=$FOREIGN_TARGET cargo test --release --all-features -- | - # Test cargo integration - (cd test-cargo-miri && MIRI_SYSROOT=$MIRI_SYSROOT_BASE/HOST ./run-test.py) +- ./travis.sh notifications: email: diff --git a/travis.sh b/travis.sh new file mode 100755 index 0000000000000..4dc368155cb9f --- /dev/null +++ b/travis.sh @@ -0,0 +1,26 @@ +#!/bin/bash +set -e + +# Determine configuration +if [ "$TRAVIS_OS_NAME" == osx ]; then + export MIRI_SYSROOT_BASE=~/Library/Caches/miri.miri.miri/ + FOREIGN_TARGET=i686-apple-darwin +else + export MIRI_SYSROOT_BASE=~/.cache/miri/ + FOREIGN_TARGET=i686-unknown-linux-gnu +fi + +# Build and install miri +cargo build --release --all-features --all-targets && +cargo install --all-features --force --path . + +# Get ourselves a MIR-full libstd for the host and a foreign architecture +cargo miri setup && +cargo miri setup --target "$FOREIGN_TARGET" + +# Test miri with full MIR, on the host and other architectures +MIRI_SYSROOT=$MIRI_SYSROOT_BASE/HOST cargo test --release --all-features && +MIRI_SYSROOT=$MIRI_SYSROOT_BASE MIRI_TARGET=$FOREIGN_TARGET cargo test --release --all-features + +# Test cargo integration +(cd test-cargo-miri && MIRI_SYSROOT=$MIRI_SYSROOT_BASE/HOST ./run-test.py) From 5ff67363cbb6a0818c53b5cfa6a985a24614722f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 12 Dec 2018 19:51:52 +0100 Subject: [PATCH 0483/3747] fix warning --- tests/compiletest.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/compiletest.rs b/tests/compiletest.rs index a0862d00326ca..31f0eb0c13860 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -3,7 +3,7 @@ #![test_runner(test_runner)] use std::slice::SliceConcatExt; -use std::path::{PathBuf, Path}; +use std::path::PathBuf; use std::env; use compiletest_rs as compiletest; From ee2b5bb6bbd8867bc964a25a464278d61e5ff112 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 12 Dec 2018 19:52:49 +0100 Subject: [PATCH 0484/3747] travis: explain what we are doing --- travis.sh | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/travis.sh b/travis.sh index 4dc368155cb9f..e11d3e17c023b 100755 --- a/travis.sh +++ b/travis.sh @@ -10,17 +10,21 @@ else FOREIGN_TARGET=i686-unknown-linux-gnu fi -# Build and install miri +echo "Build and install miri" cargo build --release --all-features --all-targets && cargo install --all-features --force --path . +echo -# Get ourselves a MIR-full libstd for the host and a foreign architecture +echo "Get ourselves a MIR-full libstd for the host and a foreign architecture" cargo miri setup && cargo miri setup --target "$FOREIGN_TARGET" +echo -# Test miri with full MIR, on the host and other architectures +echo "Test miri with full MIR, on the host and other architectures" MIRI_SYSROOT=$MIRI_SYSROOT_BASE/HOST cargo test --release --all-features && MIRI_SYSROOT=$MIRI_SYSROOT_BASE MIRI_TARGET=$FOREIGN_TARGET cargo test --release --all-features +echo -# Test cargo integration +echo "Test cargo integration" (cd test-cargo-miri && MIRI_SYSROOT=$MIRI_SYSROOT_BASE/HOST ./run-test.py) +echo From 8bd1f78563b33bfc8664289ca3dad88cf4da613e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 13 Dec 2018 20:25:24 +0100 Subject: [PATCH 0485/3747] fix libc feature gate --- tests/run-pass/foreign-fn-linkname.rs | 2 +- tests/run-pass/regions-mock-trans.rs | 2 +- tests/run-pass/thread-local.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/run-pass/foreign-fn-linkname.rs b/tests/run-pass/foreign-fn-linkname.rs index 3dd30fd676fd1..f2ed67385cdc7 100644 --- a/tests/run-pass/foreign-fn-linkname.rs +++ b/tests/run-pass/foreign-fn-linkname.rs @@ -10,7 +10,7 @@ //ignore-windows: Uses POSIX APIs -#![feature(libc)] +#![feature(rustc_private)] #![allow(unused_extern_crates)] // rustc bug https://github.com/rust-lang/rust/issues/56098 extern crate libc; diff --git a/tests/run-pass/regions-mock-trans.rs b/tests/run-pass/regions-mock-trans.rs index 130eaa288ebef..62931493aa00c 100644 --- a/tests/run-pass/regions-mock-trans.rs +++ b/tests/run-pass/regions-mock-trans.rs @@ -10,7 +10,7 @@ //ignore-windows: Uses POSIX APIs -#![feature(libc)] +#![feature(rustc_private)] #![allow(dead_code)] diff --git a/tests/run-pass/thread-local.rs b/tests/run-pass/thread-local.rs index 8c20e89ab52db..aeedb7034ce5e 100644 --- a/tests/run-pass/thread-local.rs +++ b/tests/run-pass/thread-local.rs @@ -1,6 +1,6 @@ //ignore-windows: Uses POSIX APIs -#![feature(libc)] +#![feature(rustc_private)] extern crate libc; use std::mem; From b0581caeef3278d020aee44c7f5a7736504df401 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 13 Dec 2018 22:05:46 +0100 Subject: [PATCH 0486/3747] VecDeque got fixed --- tests/run-pass/vecdeque.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/tests/run-pass/vecdeque.rs b/tests/run-pass/vecdeque.rs index d92cff0b084e6..381169505ec9f 100644 --- a/tests/run-pass/vecdeque.rs +++ b/tests/run-pass/vecdeque.rs @@ -1,6 +1,3 @@ -// FIXME: Validation disabled until https://github.com/rust-lang/rust/pull/56161 lands -// compile-flags: -Zmiri-disable-validation - use std::collections::VecDeque; fn main() { From e2505dd945923fa5ed057a2ee3080154fa356e0a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 13 Dec 2018 22:07:57 +0100 Subject: [PATCH 0487/3747] we have no whitelist any more, go back to opt-level 3 --- tests/compiletest.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/tests/compiletest.rs b/tests/compiletest.rs index 31f0eb0c13860..f125100f83438 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -77,9 +77,7 @@ fn miri_pass(path: &str, target: &str, opt: bool) { flags.push("-Dwarnings -Dunused".to_owned()); // overwrite the -Aunused in compiletest-rs flags.push("--edition 2018".to_owned()); if opt { - // FIXME: We use opt level 1 because MIR inlining defeats the validation - // whitelist. - flags.push("-Zmir-opt-level=1".to_owned()); + flags.push("-Zmir-opt-level=3".to_owned()); } let mut config = mk_config("ui"); From fbad6c031083d6c30b6e3dd7d685f9c0c688b716 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 14 Dec 2018 08:12:39 +0100 Subject: [PATCH 0488/3747] bump Rust nightly --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 69d072f1bfa01..2ad896fe0519d 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -nightly-2018-12-08 +nightly-2018-12-14 From 6bc3a488025b5525173b64fc691785aa67fced47 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 15 Dec 2018 14:13:46 +0100 Subject: [PATCH 0489/3747] tweak travis.sh --- travis.sh | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/travis.sh b/travis.sh index e11d3e17c023b..aded53b1579d6 100755 --- a/travis.sh +++ b/travis.sh @@ -11,20 +11,20 @@ else fi echo "Build and install miri" -cargo build --release --all-features --all-targets && +cargo build --release --all-features --all-targets cargo install --all-features --force --path . echo echo "Get ourselves a MIR-full libstd for the host and a foreign architecture" -cargo miri setup && +cargo miri setup cargo miri setup --target "$FOREIGN_TARGET" echo echo "Test miri with full MIR, on the host and other architectures" -MIRI_SYSROOT=$MIRI_SYSROOT_BASE/HOST cargo test --release --all-features && -MIRI_SYSROOT=$MIRI_SYSROOT_BASE MIRI_TARGET=$FOREIGN_TARGET cargo test --release --all-features +MIRI_SYSROOT="$MIRI_SYSROOT_BASE"/HOST cargo test --release --all-features +MIRI_SYSROOT="$MIRI_SYSROOT_BASE" MIRI_TARGET="$FOREIGN_TARGET" cargo test --release --all-features echo echo "Test cargo integration" -(cd test-cargo-miri && MIRI_SYSROOT=$MIRI_SYSROOT_BASE/HOST ./run-test.py) +(cd test-cargo-miri && MIRI_SYSROOT="$MIRI_SYSROOT_BASE"/HOST ./run-test.py) echo From 6a37e723c4af5760cec21d6a1684ed6d7f344a93 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 15 Dec 2018 15:08:03 +0100 Subject: [PATCH 0490/3747] detect outdated xargo version --- src/bin/cargo-miri.rs | 42 ++++++++++++++++++++++++++++++++++++------ 1 file changed, 36 insertions(+), 6 deletions(-) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 6d2dc1dd2f1a0..310bf4f583ea1 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -3,7 +3,7 @@ extern crate cargo_metadata; use std::path::{PathBuf, Path}; -use std::io::{self, Write}; +use std::io::{self, Write, BufRead}; use std::process::Command; use std::fs::{self, File}; @@ -114,6 +114,36 @@ fn list_targets() -> impl Iterator { package.targets.into_iter() } +fn xargo_version() -> Option<(u32, u32, u32)> { + let out = Command::new("xargo").arg("--version").output().ok()?; + if !out.status.success() { + return None; + } + // Parse output. The first line looks like "xargo 0.3.12 (b004f1c 2018-12-13)". + let line = out.stderr.lines().nth(0) + .expect("malformed `xargo --version` output: not at least one line") + .expect("malformed `xargo --version` output: error reading first line"); + let version = line.split(' ').nth(1) + .expect("malformed `xargo --version` output: not at least two words"); + let mut version_pieces = version.split('.'); + let major = version_pieces.next() + .expect("malformed `xargo --version` output: not a major version piece") + .parse() + .expect("malformed `xargo --version` output: major version is not an integer"); + let minor = version_pieces.next() + .expect("malformed `xargo --version` output: not a minor version piece") + .parse() + .expect("malformed `xargo --version` output: minor version is not an integer"); + let patch = version_pieces.next() + .expect("malformed `xargo --version` output: not a patch version piece") + .parse() + .expect("malformed `xargo --version` output: patch version is not an integer"); + if !version_pieces.next().is_none() { + panic!("malformed `xargo --version` output: more than three pieces in version"); + } + Some((major, minor, patch)) +} + fn ask(question: &str) { let mut buf = String::new(); print!("{} [Y/n] ", question); @@ -134,14 +164,14 @@ fn setup(ask_user: bool) { } // First, we need xargo - if Command::new("xargo").arg("--version").output().is_err() - { + let xargo = xargo_version(); + if xargo.map_or(true, |v| v < (0, 3, 13)) { if ask_user { - ask("It seems you do not have xargo installed. I will run `cargo install xargo`. Proceed?"); + ask("It seems you do not have a recent enough xargo installed. I will run `cargo install xargo -f`. Proceed?"); } else { - println!("Installing xargo: `cargo install xargo`"); + println!("Installing xargo: `cargo install xargo -f`"); } - if !Command::new("cargo").args(&["install", "xargo"]).status().unwrap().success() { + if !Command::new("cargo").args(&["install", "xargo", "-f"]).status().unwrap().success() { show_error(format!("Failed to install xargo")); } } From 96b2c347d74cef4b93ddb681fb3244b98ab883f1 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 15 Dec 2018 18:39:42 +0100 Subject: [PATCH 0491/3747] temporarily use git version of xargo --- src/bin/cargo-miri.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 310bf4f583ea1..5b1b720da749b 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -171,7 +171,8 @@ fn setup(ask_user: bool) { } else { println!("Installing xargo: `cargo install xargo -f`"); } - if !Command::new("cargo").args(&["install", "xargo", "-f"]).status().unwrap().success() { + // FIXME: Go back to using releases, once a 0.3.13 got released. + if !Command::new("cargo").args(&["install", "xargo", "-f", "--git", "https://github.com/japaric/xargo"]).status().unwrap().success() { show_error(format!("Failed to install xargo")); } } From d801daf3e589da9726eec2d8f07c611ca7b9f3c6 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Sun, 16 Dec 2018 19:34:00 -0800 Subject: [PATCH 0492/3747] Add rustc-workspace-hack. --- Cargo.toml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Cargo.toml b/Cargo.toml index ca670df0f2034..6fd45b0c74178 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -39,6 +39,10 @@ directories = { version = "1.0", optional = true } rustc_version = { version = "0.2.3", optional = true } env_logger = "0.5" log = "0.4" +# A noop dependency that changes in the Rust repository, it's a bit of a hack. +# See the `src/tools/rustc-workspace-hack/README.md` file in `rust-lang/rust` +# for more information. +rustc-workspace-hack = "1.0.0" [build-dependencies] vergen = "3" From 77ef84e1e8a48ffa1a7d63e858e3d158bc1a8ecb Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Mon, 17 Dec 2018 10:12:04 +0100 Subject: [PATCH 0493/3747] Adjust tests for funciton pointer changes --- tests/run-pass/function_pointers.rs | 9 +++++---- tests/run-pass/mir_coercions.rs | 5 ++++- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/tests/run-pass/function_pointers.rs b/tests/run-pass/function_pointers.rs index 4f597d4a2e94f..6819a2af3ed8f 100644 --- a/tests/run-pass/function_pointers.rs +++ b/tests/run-pass/function_pointers.rs @@ -10,12 +10,12 @@ fn h(i: i32, j: i32) -> i32 { j * i * 7 } -fn return_fn_ptr() -> fn() -> i32 { +fn return_fn_ptr(f: fn() -> i32) -> fn() -> i32 { f } fn call_fn_ptr() -> i32 { - return_fn_ptr()() + return_fn_ptr(f)() } fn indirect i32>(f: F) -> i32 { f() } @@ -41,6 +41,7 @@ fn main() { assert_eq!(indirect3(h), 210); assert_eq!(indirect_mut3(h), 210); assert_eq!(indirect_once3(h), 210); - assert!(return_fn_ptr() == f); - assert!(return_fn_ptr() as unsafe fn() -> i32 == f as fn() -> i32 as unsafe fn() -> i32); + let g = f as fn() -> i32; + assert!(return_fn_ptr(g) == g); + assert!(return_fn_ptr(g) as unsafe fn() -> i32 == g as fn() -> i32 as unsafe fn() -> i32); } diff --git a/tests/run-pass/mir_coercions.rs b/tests/run-pass/mir_coercions.rs index 36155297e32f0..1dab492f9da3b 100644 --- a/tests/run-pass/mir_coercions.rs +++ b/tests/run-pass/mir_coercions.rs @@ -60,7 +60,10 @@ fn main() { let a = [0,1,2]; let square_local : fn(u32) -> u32 = square; let (f,g) = fn_coercions(&square_local); - assert_eq!(f as *const (), square as *const()); + // cannot use `square as *const ()` because we can't know whether the compiler duplicates + // functions, so two function pointers are only equal if they result from the same function + // to function pointer cast + assert_eq!(f as *const (), square_local as *const()); assert_eq!(g(4), 16); assert_eq!(identity_coercion(g)(5), 25); From 3e603c38d74935689d7454ec961c49ab2470bf46 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 18 Dec 2018 18:40:06 +0100 Subject: [PATCH 0494/3747] bump Rust version, fix test-cargo-miri and it no longer needs to disable validation --- rust-version | 2 +- test-cargo-miri/run-test.py | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/rust-version b/rust-version index 2ad896fe0519d..d1ff80dec08af 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -nightly-2018-12-14 +nightly-2018-12-18 diff --git a/test-cargo-miri/run-test.py b/test-cargo-miri/run-test.py index c7ab8f14df883..19e0a147408f2 100755 --- a/test-cargo-miri/run-test.py +++ b/test-cargo-miri/run-test.py @@ -34,11 +34,10 @@ def test(name, cmd, stdout_ref, stderr_ref): sys.exit(1) def test_cargo_miri_run(): - test("cargo miri run", ["cargo", "miri", "run", "-q"], "stout.ref", "stderr.ref") + test("cargo miri run", ["cargo", "miri", "run", "-q"], "stdout.ref", "stderr.ref") def test_cargo_miri_test(): - # FIXME: validation disabled for now because of https://github.com/rust-lang/rust/issues/54957 - test("cargo miri test", ["cargo", "miri", "test", "-q", "--", "-Zmiri-disable-validation"], "stout.ref", "stderr.ref") + test("cargo miri test", ["cargo", "miri", "test", "-q"], "test.stdout.ref", "test.stderr.ref") test_cargo_miri_run() test_cargo_miri_test() From b3f799136778a1d034bc621bc41ed42a68d1cc48 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 18 Dec 2018 18:41:52 +0100 Subject: [PATCH 0495/3747] btree is fixed --- tests/run-pass/btreemap.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/tests/run-pass/btreemap.rs b/tests/run-pass/btreemap.rs index dc0fa0987aebb..b7140d72ac3a6 100644 --- a/tests/run-pass/btreemap.rs +++ b/tests/run-pass/btreemap.rs @@ -1,6 +1,3 @@ -// FIXME: Validation disabled due to https://github.com/rust-lang/rust/issues/54957 -// compile-flags: -Zmiri-disable-validation - #[derive(PartialEq, Eq, PartialOrd, Ord)] pub enum Foo { A(&'static str), From e8c53e81f8ec8de08cc1f2a1c026c9055fc37445 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 18 Dec 2018 19:26:57 +0100 Subject: [PATCH 0496/3747] implement macOS functions for argc, argv --- src/fn_call.rs | 19 ++++++++++++------- src/lib.rs | 19 +++++++++++++++++-- 2 files changed, 29 insertions(+), 9 deletions(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index d11364ce0d180..ab82223f234d0 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -513,10 +513,6 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, this.write_null(dest)?; } - "_tlv_atexit" => { - // FIXME: Register the dtor - }, - // Determining stack base address "pthread_attr_init" | "pthread_attr_destroy" | "pthread_attr_get_np" | "pthread_getattr_np" | "pthread_self" | "pthread_get_stacksize_np" => { @@ -554,7 +550,18 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, this.write_null(dest)?; } - // Windows API subs + // macOS API stubs + "_tlv_atexit" => { + // FIXME: Register the dtor + }, + "_NSGetArgc" => { + this.write_scalar(Scalar::Ptr(this.machine.argc.unwrap()), dest)?; + }, + "_NSGetArgv" => { + this.write_scalar(Scalar::Ptr(this.machine.argv.unwrap()), dest)?; + }, + + // Windows API stubs "AddVectoredExceptionHandler" => { // any non zero value works for the stdlib. This is just used for stackoverflows anyway this.write_scalar(Scalar::from_int(1, dest.layout.size), dest)?; @@ -576,8 +583,6 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, // this is c::ERROR_CALL_NOT_IMPLEMENTED this.write_scalar(Scalar::from_int(120, dest.layout.size), dest)?; }, - - // Windows TLS "TlsAlloc" => { // This just creates a key; Windows does not natively support TLS dtors. diff --git a/src/lib.rs b/src/lib.rs index 28639976aa03f..e6e1a338c9d18 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -121,7 +121,11 @@ pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( // Second argument (argc): 1 let dest = ecx.eval_place(&mir::Place::Local(args.next().unwrap()))?; - ecx.write_scalar(Scalar::from_int(1, dest.layout.size), dest)?; + let argc = Scalar::from_int(1, dest.layout.size); + ecx.write_scalar(argc, dest)?; + let argc_place = ecx.allocate(dest.layout, MiriMemoryKind::Env.into())?; + ecx.write_scalar(argc, argc_place.into())?; + ecx.machine.argc = Some(argc_place.ptr.to_ptr()?); // FIXME: extract main source file path // Third argument (argv): &[b"foo"] @@ -132,7 +136,11 @@ pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( let foo_place = ecx.allocate(foo_layout, MiriMemoryKind::Env.into())?; ecx.write_scalar(Scalar::Ptr(foo), foo_place.into())?; ecx.memory_mut().mark_immutable(foo_place.to_ptr()?.alloc_id)?; - ecx.write_scalar(foo_place.ptr, dest)?; + let argv = foo_place.ptr; + ecx.write_scalar(argv, dest)?; + let argv_place = ecx.allocate(dest.layout, MiriMemoryKind::Env.into())?; + ecx.write_scalar(argv, argv_place.into())?; + ecx.machine.argc = Some(argv_place.ptr.to_ptr()?); assert!(args.next().is_none(), "start lang item has more arguments than expected"); @@ -253,6 +261,11 @@ pub struct Evaluator<'tcx> { /// Miri does not expose env vars from the host to the emulated program pub(crate) env_vars: HashMap, Pointer>, + /// Program arguments (`Option` because we can only initialize them after creating the ecx). + /// These are *pointers* to argc/argv because macOS. + pub(crate) argc: Option>, + pub(crate) argv: Option>, + /// TLS state pub(crate) tls: TlsData<'tcx>, @@ -267,6 +280,8 @@ impl<'tcx> Evaluator<'tcx> { fn new(validate: bool) -> Self { Evaluator { env_vars: HashMap::default(), + argc: None, + argv: None, tls: TlsData::default(), validate, stacked_borrows: stacked_borrows::State::default(), From e4fd710606c346cad3e64dc7edc18201699560c7 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 18 Dec 2018 19:41:32 +0100 Subject: [PATCH 0497/3747] there is a new xargo released, use that --- src/bin/cargo-miri.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 2a2cbdb8155d0..0a8ddd95a76e5 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -171,8 +171,7 @@ fn setup(ask_user: bool) { } else { println!("Installing xargo: `cargo install xargo -f`"); } - // FIXME: Go back to using releases, once a 0.3.13 got released. - if !Command::new("cargo").args(&["install", "xargo", "-f", "--git", "https://github.com/japaric/xargo"]).status().unwrap().success() { + if !Command::new("cargo").args(&["install", "xargo", "-f"]).status().unwrap().success() { show_error(format!("Failed to install xargo")); } } From 4e0fe62bd90bffcec376e7b0877e87ebfece3cfb Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 18 Dec 2018 19:45:10 +0100 Subject: [PATCH 0498/3747] typo --- src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index e6e1a338c9d18..e41a92e55f72f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -140,7 +140,7 @@ pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( ecx.write_scalar(argv, dest)?; let argv_place = ecx.allocate(dest.layout, MiriMemoryKind::Env.into())?; ecx.write_scalar(argv, argv_place.into())?; - ecx.machine.argc = Some(argv_place.ptr.to_ptr()?); + ecx.machine.argv = Some(argv_place.ptr.to_ptr()?); assert!(args.next().is_none(), "start lang item has more arguments than expected"); From 61c0df793060e60e5bd106dec82fd0951decd63b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 18 Dec 2018 21:49:21 +0100 Subject: [PATCH 0499/3747] remove outdated README comment --- README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/README.md b/README.md index b6e1c20076de9..02e13ad56a7ed 100644 --- a/README.md +++ b/README.md @@ -45,8 +45,6 @@ Now you can run your project in miri: dependencies to be compiled the right way, that would not happen if they have previously already been compiled. 2. To run all tests in your project through Miri, use `cargo +nightly miri test`. - **NOTE**: This is currently broken, see the discussion in - [#479](https://github.com/solson/miri/issues/479). 3. If you have a binary project, you can run it through Miri using `cargo +nightly miri run`. From bf846a637c6755bd4fe215b6103d7aba28a282a5 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 18 Dec 2018 21:49:38 +0100 Subject: [PATCH 0500/3747] test-cargo-miri: be more clear that and why the test failed --- test-cargo-miri/run-test.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/test-cargo-miri/run-test.py b/test-cargo-miri/run-test.py index 19e0a147408f2..7f7f2660c0622 100755 --- a/test-cargo-miri/run-test.py +++ b/test-cargo-miri/run-test.py @@ -7,6 +7,10 @@ import sys, subprocess +def fail(msg): + print("TEST FAIL: {}".format(msg)) + sys.exit(1) + def test(name, cmd, stdout_ref, stderr_ref): print("==> Testing `{}` <==".format(name)) ## Call `cargo miri`, capture all output @@ -25,13 +29,11 @@ def test(name, cmd, stdout_ref, stderr_ref): print(stderr, end="") # Test for failures if p.returncode != 0: - sys.exit(1) + fail("Non-zero exit status") if stdout != open(stdout_ref).read(): - print("stdout does not match reference") - sys.exit(1) + fail("stdout does not match reference") if stderr != open(stderr_ref).read(): - print("stderr does not match reference") - sys.exit(1) + fail("stderr does not match reference") def test_cargo_miri_run(): test("cargo miri run", ["cargo", "miri", "run", "-q"], "stdout.ref", "stderr.ref") From 133e012cec90e220f5c7f50d454e8d93b0f79332 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 19 Dec 2018 11:06:35 +0100 Subject: [PATCH 0501/3747] sync env vars between appveyor and travis --- .travis.yml | 1 + appveyor.yml | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index dfc4238a6c03d..51b14a1b345bf 100644 --- a/.travis.yml +++ b/.travis.yml @@ -38,3 +38,4 @@ branches: env: global: - RUST_TEST_NOCAPTURE=1 + - RUST_BACKTRACE=1 diff --git a/appveyor.yml b/appveyor.yml index 4f4aebd807915..09040ed42a58c 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -25,7 +25,7 @@ install: build: false test_script: - - set RUSTFLAGS=-g + - set RUST_TEST_NOCAPTURE=1 - set RUST_BACKTRACE=1 # Build miri - cargo build --release --all-features --all-targets From ecf659905145ba9430b54f72c2328edd74462117 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 19 Dec 2018 08:41:31 +0100 Subject: [PATCH 0502/3747] xargo version check: also check application name, just to be sure --- src/bin/cargo-miri.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 0a8ddd95a76e5..4ac1d1a3b4755 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -123,8 +123,14 @@ fn xargo_version() -> Option<(u32, u32, u32)> { let line = out.stderr.lines().nth(0) .expect("malformed `xargo --version` output: not at least one line") .expect("malformed `xargo --version` output: error reading first line"); - let version = line.split(' ').nth(1) - .expect("malformed `xargo --version` output: not at least two words"); + let (name, version) = { + let mut split = line.split(' '); + (split.next().expect("malformed `xargo --version` output: empty"), + split.next().expect("malformed `xargo --version` output: not at least two words")) + }; + if name != "xargo" { + panic!("malformed `xargo --version` output: application name is not `xargo`"); + } let mut version_pieces = version.split('.'); let major = version_pieces.next() .expect("malformed `xargo --version` output: not a major version piece") From 11433bf38e586ae517d5caa3ddb82c283cb8a1b3 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 19 Dec 2018 09:03:10 +0100 Subject: [PATCH 0503/3747] actually show warnings about suppressed output --- src/fn_call.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index ab82223f234d0..ab38270724f4c 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -398,7 +398,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, Err(_) => -1, } } else { - warn!("Ignored output to FD {}", fd); + eprintln!("Miri: Ignored output to FD {}", fd); n as i64 // pretend it all went well }; // now result is the value we return back to the program this.write_scalar( From e10a26fd3cdcb9a8442fb21b1e13e8425d3e29d7 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 19 Dec 2018 11:11:01 +0100 Subject: [PATCH 0504/3747] add a test for excluding tests on miri --- test-cargo-miri/tests/foo.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/test-cargo-miri/tests/foo.rs b/test-cargo-miri/tests/foo.rs index 9827ae82d6cfd..bd7b2c569a19b 100644 --- a/test-cargo-miri/tests/foo.rs +++ b/test-cargo-miri/tests/foo.rs @@ -9,3 +9,11 @@ fn bar() { fn baz() { assert_eq!(5, 5); } + +// A test that won't work on miri +#[cfg(not(feature = "cargo-miri"))] +#[test] +fn does_not_work_on_miri() { + let x = 0u8; + assert!(&x as *const _ as usize % 4 < 4); +} From d67da9f04bf2acf7ecec1438c28015cd75d01c83 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 19 Dec 2018 11:12:56 +0100 Subject: [PATCH 0505/3747] no need to set the cargo-miri feature twice --- src/bin/cargo-miri.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 4ac1d1a3b4755..21cc7ee0e398e 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -420,8 +420,6 @@ where args.push("--".to_owned()); } args.push("--emit=dep-info,metadata".to_owned()); - args.push("--cfg".to_owned()); - args.push(r#"feature="cargo-miri""#.to_owned()); let path = std::env::current_exe().expect("current executable path invalid"); let exit_status = Command::new("cargo") From adba97e4b24aa5ec920330a549690f664a3e1ab6 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 19 Dec 2018 11:16:19 +0100 Subject: [PATCH 0506/3747] document the cargo-miri feature --- README.md | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 02e13ad56a7ed..5a615e656d742 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ example above), overriding it in your project directory as well, or use `rustup default nightly` (or `rustup default nightly-YYYY-MM-DD`) to globally make `nightly` the default toolchain. -Now you can run your project in miri: +Now you can run your project in Miri: 1. Run `cargo clean` to eliminate any cached dependencies. Miri needs your dependencies to be compiled the right way, that would not happen if they have @@ -48,6 +48,19 @@ Now you can run your project in miri: 3. If you have a binary project, you can run it through Miri using `cargo +nightly miri run`. +When running code via `cargo miri`, the `cargo-miri` feature is set. You can +use this to exclude test cases that will fail under Miri because they do things +Miri does not support: + +```rust +#[cfg(not(feature = "cargo-miri"))] +#[test] +fn does_not_work_on_miri() { + let x = 0u8; + assert!(&x as *const _ as usize % 4 < 4); +} +``` + ### Common Problems When using the above instructions, you may encounter a number of confusing compiler From 51ed485ba4eb19083f7da719c55edb8a11f7f28e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 18 Dec 2018 21:49:01 +0100 Subject: [PATCH 0507/3747] implement stdout/stderr on Windows --- src/fn_call.rs | 45 +++++++++++++++++++++++++++++-- tests/run-pass/box-pair-to-vec.rs | 2 -- tests/run-pass/catch.rs | 1 - tests/run-pass/format.rs | 1 - tests/run-pass/hello.rs | 1 - tests/run-pass/issue-17877.rs | 2 +- tests/run-pass/issue-3794.rs | 1 - 7 files changed, 44 insertions(+), 9 deletions(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index ab38270724f4c..7815c1ce40e1d 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -596,18 +596,59 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, this.write_scalar(Scalar::from_uint(key, dest.layout.size), dest)?; } "TlsGetValue" => { - let key = this.read_scalar(args[0])?.to_bits(args[0].layout.size)?; + let key = this.read_scalar(args[0])?.to_u32()? as u128; let ptr = this.machine.tls.load_tls(key)?; this.write_scalar(ptr, dest)?; } "TlsSetValue" => { - let key = this.read_scalar(args[0])?.to_bits(args[0].layout.size)?; + let key = this.read_scalar(args[0])?.to_u32()? as u128; let new_ptr = this.read_scalar(args[1])?.not_undef()?; this.machine.tls.store_tls(key, new_ptr)?; // Return success (1) this.write_scalar(Scalar::from_int(1, dest.layout.size), dest)?; } + "GetStdHandle" => { + let which = this.read_scalar(args[0])?.to_i32()?; + // We just make this the identity function, so we know later in "WriteFile" + // which one it is. + this.write_scalar(Scalar::from_int(which, this.pointer_size()), dest)?; + } + "WriteFile" => { + let handle = this.read_scalar(args[0])?.to_isize(this)?; + let buf = this.read_scalar(args[1])?.not_undef()?; + let n = this.read_scalar(args[2])?.to_u32()?; + let written_place = this.deref_operand(args[3])?; + this.write_null(written_place.into())?; // spec says we always write 0 first + let written = if handle == -11 || handle == -12 { + // stdout/stderr + use std::io::{self, Write}; + + let buf_cont = this.memory().read_bytes(buf, Size::from_bytes(u64::from(n)))?; + let res = if handle == -11 { + io::stdout().write(buf_cont) + } else { + io::stderr().write(buf_cont) + }; + res.ok().map(|n| n as u32) + } else { + eprintln!("Miri: Ignored output to handle {}", handle); + Some(n) // pretend it all went well + }; + // If there was no error, write back how much was written + if let Some(n) = written { + this.write_scalar(Scalar::from_uint(n, Size::from_bits(32)), written_place.into())?; + } + // Return whether this was a success + this.write_scalar( + Scalar::from_int(if written.is_some() { 1 } else { 0 }, dest.layout.size), + dest, + )?; + } + "GetConsoleMode" => { + // Everything is a pipe + this.write_null(dest)?; + } // We can't execute anything else _ => { diff --git a/tests/run-pass/box-pair-to-vec.rs b/tests/run-pass/box-pair-to-vec.rs index 3b829d0f1294f..353afb9d32100 100644 --- a/tests/run-pass/box-pair-to-vec.rs +++ b/tests/run-pass/box-pair-to-vec.rs @@ -1,5 +1,3 @@ -//ignore-msvc: Stdout not implemented on Windows - #[repr(C)] #[derive(Debug)] struct PairFoo { diff --git a/tests/run-pass/catch.rs b/tests/run-pass/catch.rs index aa7bccaa5ff3a..5fd65f138aaf9 100644 --- a/tests/run-pass/catch.rs +++ b/tests/run-pass/catch.rs @@ -1,4 +1,3 @@ -//ignore-msvc: Stdout not implemented on Windows use std::panic::{catch_unwind, AssertUnwindSafe}; fn main() { diff --git a/tests/run-pass/format.rs b/tests/run-pass/format.rs index b1b05abd29655..78729b915613a 100644 --- a/tests/run-pass/format.rs +++ b/tests/run-pass/format.rs @@ -1,4 +1,3 @@ -//ignore-msvc: Stdout not implemented on Windows fn main() { println!("Hello {}", 13); } diff --git a/tests/run-pass/hello.rs b/tests/run-pass/hello.rs index c92c1567f5ae2..e7a11a969c037 100644 --- a/tests/run-pass/hello.rs +++ b/tests/run-pass/hello.rs @@ -1,4 +1,3 @@ -//ignore-msvc: Stdout not implemented on Windows fn main() { println!("Hello, world!"); } diff --git a/tests/run-pass/issue-17877.rs b/tests/run-pass/issue-17877.rs index 762bacbe0e6f5..91d17683e39e8 100644 --- a/tests/run-pass/issue-17877.rs +++ b/tests/run-pass/issue-17877.rs @@ -9,7 +9,7 @@ // except according to those terms. //ignore-windows: Causes a stack overflow?!? Likely a rustc bug: https://github.com/rust-lang/rust/issues/53820 -//Once that bug is fixed, increase the size to 16*1024 and enable on all platforms. +//FIXME: Once that bug is fixed, increase the size to 16*1024 and enable on all platforms. #![feature(slice_patterns)] diff --git a/tests/run-pass/issue-3794.rs b/tests/run-pass/issue-3794.rs index 32b4d27f11f5a..badb833ee800b 100644 --- a/tests/run-pass/issue-3794.rs +++ b/tests/run-pass/issue-3794.rs @@ -8,7 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//ignore-msvc: Stdout not implemented on Windows #![feature(box_syntax)] trait T { From e7c523f72ee0850972cc8a37b6780d2fe1666b0c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 18 Dec 2018 19:52:30 +0100 Subject: [PATCH 0508/3747] run test-cargo-miri on Windows --- appveyor.yml | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index 09040ed42a58c..a46214a3c45c6 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -27,13 +27,17 @@ build: false test_script: - set RUST_TEST_NOCAPTURE=1 - set RUST_BACKTRACE=1 - # Build miri + # Build and install miri - cargo build --release --all-features --all-targets + - cargo install --all-features --force --path . # Get ourselves a MIR-full libstd, and use it henceforth - - cargo run --release --all-features --bin cargo-miri -- miri setup + - cargo miri setup - set MIRI_SYSROOT=%USERPROFILE%\AppData\Local\miri\miri\cache\HOST # Test miri - cargo test --release --all-features + # Test cargo integration + - cd test-cargo-miri + - python3 run-test.py notifications: - provider: Email From af4fb6655e9a09d4154250bcff99fc80eb2c402f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 19 Dec 2018 15:25:25 +0100 Subject: [PATCH 0509/3747] implement GetCommandLineW, GetEnvironmentVariableW, GetConsoleScreenBufferInfo, SetConsoleTextAttribute, GetSystemInfo --- src/fn_call.rs | 47 ++++++++++++++++++++++++++++------ src/lib.rs | 69 +++++++++++++++++++++++++++++++++++++++----------- 2 files changed, 93 insertions(+), 23 deletions(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index 7815c1ce40e1d..16d18dbfe6dc2 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -562,6 +562,14 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, }, // Windows API stubs + "SetLastError" => { + let err = this.read_scalar(args[0])?.to_u32()?; + this.machine.last_error = err; + } + "GetLastError" => { + this.write_scalar(Scalar::from_uint(this.machine.last_error, Size::from_bits(32)), dest)?; + } + "AddVectoredExceptionHandler" => { // any non zero value works for the stdlib. This is just used for stackoverflows anyway this.write_scalar(Scalar::from_int(1, dest.layout.size), dest)?; @@ -569,20 +577,35 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, "InitializeCriticalSection" | "EnterCriticalSection" | "LeaveCriticalSection" | - "DeleteCriticalSection" | - "SetLastError" => { - // Function does not return anything, nothing to do + "DeleteCriticalSection" => { + // Nothing to do, not even a return value }, "GetModuleHandleW" | "GetProcAddress" | - "TryEnterCriticalSection" => { + "TryEnterCriticalSection" | + "GetConsoleScreenBufferInfo" | + "SetConsoleTextAttribute" => { // pretend these do not exist/nothing happened, by returning zero this.write_null(dest)?; }, - "GetLastError" => { - // this is c::ERROR_CALL_NOT_IMPLEMENTED - this.write_scalar(Scalar::from_int(120, dest.layout.size), dest)?; - }, + "GetSystemInfo" => { + let system_info = this.deref_operand(args[0])?; + let system_info_ptr = system_info.ptr.to_ptr()?; + // initialize with 0 + this.memory_mut().get_mut(system_info_ptr.alloc_id)? + .write_repeat(tcx, system_info_ptr, 0, system_info.layout.size)?; + // set number of processors to 1 + let dword_size = Size::from_bytes(4); + let offset = 2*dword_size + 3*tcx.pointer_size(); + this.memory_mut().get_mut(system_info_ptr.alloc_id)? + .write_scalar( + tcx, + system_info_ptr.offset(offset, tcx)?, + Scalar::from_int(1, dword_size).into(), + dword_size, + )?; + } + "TlsAlloc" => { // This just creates a key; Windows does not natively support TLS dtors. @@ -649,6 +672,14 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, // Everything is a pipe this.write_null(dest)?; } + "GetEnvironmentVariableW" => { + // This is not the env var you are looking for + this.machine.last_error = 203; // ERROR_ENVVAR_NOT_FOUND + this.write_null(dest)?; + } + "GetCommandLineW" => { + this.write_scalar(Scalar::Ptr(this.machine.cmd_line.unwrap()), dest)?; + } // We can't execute anything else _ => { diff --git a/src/lib.rs b/src/lib.rs index e41a92e55f72f..bc5e8363e89e0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -18,7 +18,7 @@ use std::borrow::Cow; use std::env; use rustc::ty::{self, TyCtxt, query::TyCtxtAt}; -use rustc::ty::layout::{TyLayout, LayoutOf, Size}; +use rustc::ty::layout::{TyLayout, LayoutOf, Size, Align}; use rustc::hir::{self, def_id::DefId}; use rustc::mir; @@ -123,24 +123,56 @@ pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( let dest = ecx.eval_place(&mir::Place::Local(args.next().unwrap()))?; let argc = Scalar::from_int(1, dest.layout.size); ecx.write_scalar(argc, dest)?; - let argc_place = ecx.allocate(dest.layout, MiriMemoryKind::Env.into())?; - ecx.write_scalar(argc, argc_place.into())?; - ecx.machine.argc = Some(argc_place.ptr.to_ptr()?); + // Store argc for macOS _NSGetArgc + { + let argc_place = ecx.allocate(dest.layout, MiriMemoryKind::Env.into())?; + ecx.write_scalar(argc, argc_place.into())?; + ecx.machine.argc = Some(argc_place.ptr.to_ptr()?); + } // FIXME: extract main source file path // Third argument (argv): &[b"foo"] + const CMD: &str = "running-in-miri"; let dest = ecx.eval_place(&mir::Place::Local(args.next().unwrap()))?; - let foo = ecx.memory_mut().allocate_static_bytes(b"foo\0").with_default_tag(); - let foo_ty = ecx.tcx.mk_imm_ptr(ecx.tcx.types.u8); - let foo_layout = ecx.layout_of(foo_ty)?; - let foo_place = ecx.allocate(foo_layout, MiriMemoryKind::Env.into())?; - ecx.write_scalar(Scalar::Ptr(foo), foo_place.into())?; - ecx.memory_mut().mark_immutable(foo_place.to_ptr()?.alloc_id)?; - let argv = foo_place.ptr; - ecx.write_scalar(argv, dest)?; - let argv_place = ecx.allocate(dest.layout, MiriMemoryKind::Env.into())?; - ecx.write_scalar(argv, argv_place.into())?; - ecx.machine.argv = Some(argv_place.ptr.to_ptr()?); + let cmd = ecx.memory_mut().allocate_static_bytes(CMD.as_bytes()).with_default_tag(); + let raw_str_layout = ecx.layout_of(ecx.tcx.mk_imm_ptr(ecx.tcx.types.u8))?; + let cmd_place = ecx.allocate(raw_str_layout, MiriMemoryKind::Env.into())?; + ecx.write_scalar(Scalar::Ptr(cmd), cmd_place.into())?; + ecx.memory_mut().mark_immutable(cmd_place.to_ptr()?.alloc_id)?; + // Store argv for macOS _NSGetArgv + { + let argv = cmd_place.ptr; + ecx.write_scalar(argv, dest)?; + let argv_place = ecx.allocate(dest.layout, MiriMemoryKind::Env.into())?; + ecx.write_scalar(argv, argv_place.into())?; + ecx.machine.argv = Some(argv_place.ptr.to_ptr()?); + } + // Store cmdline as UTF-16 for Windows GetCommandLineW + { + let tcx = &{ecx.tcx.tcx}; + let cmd_utf16: Vec = CMD.encode_utf16() + .chain(Some(0)) // add 0-terminator + .collect(); + let cmd_ptr = ecx.memory_mut().allocate( + Size::from_bytes(cmd_utf16.len() as u64 * 2), + Align::from_bytes(2).unwrap(), + MiriMemoryKind::Env.into(), + )?.with_default_tag(); + ecx.machine.cmd_line = Some(cmd_ptr); + // store the UTF-16 string + let char_size = Size::from_bytes(2); + let cmd_alloc = ecx.memory_mut().get_mut(cmd_ptr.alloc_id)?; + let mut cur_ptr = cmd_ptr; + for &c in cmd_utf16.iter() { + cmd_alloc.write_scalar( + tcx, + cur_ptr, + Scalar::from_uint(c, char_size).into(), + char_size, + )?; + cur_ptr = cur_ptr.offset(char_size, tcx)?; + } + } assert!(args.next().is_none(), "start lang item has more arguments than expected"); @@ -263,8 +295,13 @@ pub struct Evaluator<'tcx> { /// Program arguments (`Option` because we can only initialize them after creating the ecx). /// These are *pointers* to argc/argv because macOS. + /// We also need the full cmdline as one string because Window. pub(crate) argc: Option>, pub(crate) argv: Option>, + pub(crate) cmd_line: Option>, + + /// Last OS error + pub(crate) last_error: u32, /// TLS state pub(crate) tls: TlsData<'tcx>, @@ -282,6 +319,8 @@ impl<'tcx> Evaluator<'tcx> { env_vars: HashMap::default(), argc: None, argv: None, + cmd_line: None, + last_error: 0, tls: TlsData::default(), validate, stacked_borrows: stacked_borrows::State::default(), From 750cd442beb0009df6ee3dc80b88582f3b8730d9 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 19 Dec 2018 15:45:23 +0100 Subject: [PATCH 0510/3747] fix argv null terminator --- src/lib.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index bc5e8363e89e0..cf2c39f61ef8a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -132,7 +132,7 @@ pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( // FIXME: extract main source file path // Third argument (argv): &[b"foo"] - const CMD: &str = "running-in-miri"; + const CMD: &str = "running-in-miri\0"; let dest = ecx.eval_place(&mir::Place::Local(args.next().unwrap()))?; let cmd = ecx.memory_mut().allocate_static_bytes(CMD.as_bytes()).with_default_tag(); let raw_str_layout = ecx.layout_of(ecx.tcx.mk_imm_ptr(ecx.tcx.types.u8))?; @@ -150,9 +150,7 @@ pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( // Store cmdline as UTF-16 for Windows GetCommandLineW { let tcx = &{ecx.tcx.tcx}; - let cmd_utf16: Vec = CMD.encode_utf16() - .chain(Some(0)) // add 0-terminator - .collect(); + let cmd_utf16: Vec = CMD.encode_utf16().collect(); let cmd_ptr = ecx.memory_mut().allocate( Size::from_bytes(cmd_utf16.len() as u64 * 2), Align::from_bytes(2).unwrap(), From 2c2587bc8d18f9fea886b9a852218fe8c89d6f73 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 21 Dec 2018 09:29:42 +0100 Subject: [PATCH 0511/3747] bump Rust version --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index d1ff80dec08af..7a16560006d5c 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -nightly-2018-12-18 +nightly-2018-12-21 From 79bdec8a9cb18ce8ba9c93183bbefbf680241bec Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 22 Dec 2018 16:07:40 +0100 Subject: [PATCH 0512/3747] fix test for latest nightly --- rust-version | 2 +- tests/compile-fail/never_transmute_void.rs | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 7a16560006d5c..0c2bc318c67fb 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -nightly-2018-12-21 +nightly-2018-12-22 diff --git a/tests/compile-fail/never_transmute_void.rs b/tests/compile-fail/never_transmute_void.rs index fab4981047f8d..5993cfad86993 100644 --- a/tests/compile-fail/never_transmute_void.rs +++ b/tests/compile-fail/never_transmute_void.rs @@ -2,6 +2,7 @@ // compile-flags: -Zmiri-disable-validation #![feature(never_type)] +#![allow(unused)] enum Void {} From 4f659ed507761563748e1ee286adc2aea685923c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 23 Dec 2018 14:13:16 +0100 Subject: [PATCH 0513/3747] fix for infallible allocation --- src/fn_call.rs | 8 ++++---- src/lib.rs | 16 ++++++++-------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index 16d18dbfe6dc2..0f54295182399 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -84,7 +84,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, this.write_null(dest)?; } else { let align = this.tcx.data_layout.pointer_align.abi; - let ptr = this.memory_mut().allocate(Size::from_bytes(size), align, MiriMemoryKind::C.into())?; + let ptr = this.memory_mut().allocate(Size::from_bytes(size), align, MiriMemoryKind::C.into()); this.write_scalar(Scalar::Ptr(ptr.with_default_tag()), dest)?; } } @@ -114,7 +114,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, Size::from_bytes(size), Align::from_bytes(align).unwrap(), MiriMemoryKind::Rust.into() - )? + ) .with_default_tag(); this.write_scalar(Scalar::Ptr(ptr), dest)?; } @@ -132,7 +132,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, Size::from_bytes(size), Align::from_bytes(align).unwrap(), MiriMemoryKind::Rust.into() - )? + ) .with_default_tag(); this.memory_mut() .get_mut(ptr.alloc_id)? @@ -358,7 +358,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, Size::from_bytes((value.len() + 1) as u64), Align::from_bytes(1).unwrap(), MiriMemoryKind::Env.into(), - )?.with_default_tag(); + ).with_default_tag(); { let alloc = this.memory_mut().get_mut(value_copy.alloc_id)?; alloc.write_bytes(tcx, value_copy, &value)?; diff --git a/src/lib.rs b/src/lib.rs index aa65220305502..7643f93fdc2cf 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -101,7 +101,7 @@ pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( // Return value (in static memory so that it does not count as leak) let ret = ecx.layout_of(start_mir.return_ty())?; - let ret_ptr = ecx.allocate(ret, MiriMemoryKind::MutStatic.into())?; + let ret_ptr = ecx.allocate(ret, MiriMemoryKind::MutStatic.into()); // Push our stack frame ecx.push_stack_frame( @@ -125,7 +125,7 @@ pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( ecx.write_scalar(argc, dest)?; // Store argc for macOS _NSGetArgc { - let argc_place = ecx.allocate(dest.layout, MiriMemoryKind::Env.into())?; + let argc_place = ecx.allocate(dest.layout, MiriMemoryKind::Env.into()); ecx.write_scalar(argc, argc_place.into())?; ecx.machine.argc = Some(argc_place.ptr.to_ptr()?); } @@ -136,14 +136,14 @@ pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( let dest = ecx.eval_place(&mir::Place::Local(args.next().unwrap()))?; let cmd = ecx.memory_mut().allocate_static_bytes(CMD.as_bytes()).with_default_tag(); let raw_str_layout = ecx.layout_of(ecx.tcx.mk_imm_ptr(ecx.tcx.types.u8))?; - let cmd_place = ecx.allocate(raw_str_layout, MiriMemoryKind::Env.into())?; + let cmd_place = ecx.allocate(raw_str_layout, MiriMemoryKind::Env.into()); ecx.write_scalar(Scalar::Ptr(cmd), cmd_place.into())?; ecx.memory_mut().mark_immutable(cmd_place.to_ptr()?.alloc_id)?; // Store argv for macOS _NSGetArgv { let argv = cmd_place.ptr; ecx.write_scalar(argv, dest)?; - let argv_place = ecx.allocate(dest.layout, MiriMemoryKind::Env.into())?; + let argv_place = ecx.allocate(dest.layout, MiriMemoryKind::Env.into()); ecx.write_scalar(argv, argv_place.into())?; ecx.machine.argv = Some(argv_place.ptr.to_ptr()?); } @@ -155,7 +155,7 @@ pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( Size::from_bytes(cmd_utf16.len() as u64 * 2), Align::from_bytes(2).unwrap(), MiriMemoryKind::Env.into(), - )?.with_default_tag(); + ).with_default_tag(); ecx.machine.cmd_line = Some(cmd_ptr); // store the UTF-16 string let char_size = Size::from_bytes(2); @@ -516,13 +516,13 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, ptr: Pointer, kind: MemoryKind, - ) -> EvalResult<'tcx, Pointer> { + ) -> Pointer { if !ecx.machine.validate { // No tracking - Ok(ptr.with_default_tag()) + ptr.with_default_tag() } else { let tag = ecx.tag_new_allocation(ptr.alloc_id, kind); - Ok(Pointer::new_with_tag(ptr.alloc_id, ptr.offset, tag)) + Pointer::new_with_tag(ptr.alloc_id, ptr.offset, tag) } } From d8c9c9dd4f49fbb78f82c7407daff5e403b6f274 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 23 Dec 2018 14:21:15 +0100 Subject: [PATCH 0514/3747] update README for some tracing being available on nightlies --- README.md | 45 ++++++++++++++++++++++++--------------------- 1 file changed, 24 insertions(+), 21 deletions(-) diff --git a/README.md b/README.md index 5a615e656d742..879d27dc97e07 100644 --- a/README.md +++ b/README.md @@ -90,7 +90,7 @@ things (like adding support for a new intrinsic) can be done by working just on the miri side. To prepare, make sure you are using a nightly Rust compiler. You also need to -set up a libstd that enables execution with miri: +set up a libstd that enables execution with Miri: ```sh rustup override set nightly # or the nightly in `rust-version` @@ -98,7 +98,7 @@ cargo run --bin cargo-miri -- miri setup ``` The last command should end in printing the directory where the libstd was -built. Set that as your MIRI_SYSROOT environment variable: +built. Set that as your `MIRI_SYSROOT` environment variable: ```sh export MIRI_SYSROOT=~/.cache/miri/HOST # or whatever the previous command said @@ -109,7 +109,7 @@ export MIRI_SYSROOT=~/.cache/miri/HOST # or whatever the previous command said Now you can run Miri directly, without going through `cargo miri`: ```sh -cargo run tests/run-pass-fullmir/format.rs # or whatever test you like +cargo run tests/run-pass/format.rs # or whatever test you like ``` You can also run the test suite with `cargo test --release`. `cargo test @@ -120,14 +120,33 @@ less time. Now you are set up! You can write a failing test case, and tweak miri until it fails no more. +You can get a trace of which MIR statements are being executed by setting the +`MIRI_LOG` environment variable. For example: + +```sh +MIRI_LOG=info cargo run tests/run-pass/vecs.rs +``` + +Setting `MIRI_LOG` like this will configure logging for miri itself as well as +the `rustc::mir::interpret` and `rustc_mir::interpret` modules in rustc. You +can also do more targeted configuration, e.g. to debug the stacked borrows +implementation: +```sh +MIRI_LOG=rustc_mir::interpret=info,miri::stacked_borrows cargo run tests/run-pass/vecs.rs +``` + +In addition, you can set `MIRI_BACKTRACE=1` to get a backtrace of where an +evaluation error was originally created. + ### Using a locally built rustc Since the heart of Miri (the main interpreter engine) lives in rustc, working on Miri will often require using a locally built rustc. The bug you want to fix may actually be on the rustc side, or you just need to get more detailed trace -of the execution -- in both cases, you should develop miri against a rustc you -compiled yourself, with debug assertions (and hence tracing) enabled. +of the execution than what is possible with release builds -- in both cases, you +should develop miri against a rustc you compiled yourself, with debug assertions +(and hence tracing) enabled. The setup for a local rustc works as follows: ```sh @@ -149,22 +168,6 @@ rustup override set custom With this, you should now have a working development setup! See ["Testing Miri"](#testing-miri) above for how to proceed. -Moreover, you can now run Miri with a trace of all execution steps: -```sh -MIRI_LOG=debug cargo run tests/run-pass/vecs.rs -``` - -Setting `MIRI_LOG` like this will configure logging for miri itself as well as -the `rustc::mir::interpret` and `rustc_mir::interpret` modules in rustc. You -can also do more targeted configuration, e.g. to debug the stacked borrows -implementation: -```sh -MIRI_LOG=rustc_mir::interpret=debug,miri::stacked_borrows cargo run tests/run-pass/vecs.rs -``` - -In addition, you can set `MIRI_BACKTRACE=1` to get a backtrace of where an -evaluation error was originally created. - ### Miri `-Z` flags and environment variables Several `-Z` flags are relevant for Miri: From d0f06a5f0daa73731f2ebe7763f2c48192220392 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 24 Dec 2018 14:30:29 +0100 Subject: [PATCH 0515/3747] bump Rust version --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 0c2bc318c67fb..ea30c4512ee7c 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -nightly-2018-12-22 +nightly-2018-12-24 From 4e4569cf4b5f044b030f9a3de61e4167395c5145 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 25 Dec 2018 13:26:40 +0100 Subject: [PATCH 0516/3747] fix build and tests with latest nightly --- src/operator.rs | 6 ++++-- tests/run-pass/async-fn.rs | 1 - 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/operator.rs b/src/operator.rs index e1ccdf91995ef..abc1c98a1dede 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -161,12 +161,14 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' if bits == 0 { // Test if the ptr is in-bounds. Then it cannot be NULL. // Even dangling pointers cannot be NULL. - if self.memory().check_bounds_ptr_maybe_dead(ptr).is_ok() { + if self.memory().check_bounds_ptr(ptr, InboundsCheck::MaybeDead).is_ok() { return Ok(false); } } - let (alloc_size, alloc_align) = self.memory().get_size_and_align(ptr.alloc_id); + let (alloc_size, alloc_align) = self.memory() + .get_size_and_align(ptr.alloc_id, InboundsCheck::MaybeDead) + .expect("determining size+align of dead ptr cannot fail"); // Case II: Alignment gives it away if ptr.offset.bytes() % alloc_align.bytes() == 0 { diff --git a/tests/run-pass/async-fn.rs b/tests/run-pass/async-fn.rs index 7c32b026df67b..9094a9fd3a680 100644 --- a/tests/run-pass/async-fn.rs +++ b/tests/run-pass/async-fn.rs @@ -2,7 +2,6 @@ async_await, await_macro, futures_api, - pin, )] use std::{future::Future, pin::Pin, task::Poll}; From 5a8f9e58f72a8b8ad284475c8992c664c548f776 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 25 Dec 2018 13:29:38 +0100 Subject: [PATCH 0517/3747] properly compare unequal function pointers --- src/operator.rs | 4 ++-- tests/run-pass/function_pointers.rs | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/operator.rs b/src/operator.rs index abc1c98a1dede..cc803c4ea9548 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -145,8 +145,8 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' // Dead allocations in miri cannot overlap with live allocations, but // on read hardware this can easily happen. Thus for comparisons we require // both pointers to be live. - self.memory().get(left.alloc_id)?.check_bounds_ptr(left)?; - self.memory().get(right.alloc_id)?.check_bounds_ptr(right)?; + self.memory().check_bounds_ptr(left, InboundsCheck::Live)?; + self.memory().check_bounds_ptr(right, InboundsCheck::Live)?; // Two in-bounds pointers, we can compare across allocations left == right } diff --git a/tests/run-pass/function_pointers.rs b/tests/run-pass/function_pointers.rs index 6819a2af3ed8f..cc888630d3eea 100644 --- a/tests/run-pass/function_pointers.rs +++ b/tests/run-pass/function_pointers.rs @@ -44,4 +44,5 @@ fn main() { let g = f as fn() -> i32; assert!(return_fn_ptr(g) == g); assert!(return_fn_ptr(g) as unsafe fn() -> i32 == g as fn() -> i32 as unsafe fn() -> i32); + assert!(return_fn_ptr(f) != f); } From 55107d5dd34d73af891f117ace2c25bb8ac33680 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 26 Dec 2018 11:01:22 +0100 Subject: [PATCH 0518/3747] bump Rust version --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index ea30c4512ee7c..a2909dd32898c 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -nightly-2018-12-24 +nightly-2018-12-26 From e759da6b4b7d64d9561fa988765acbc6215aecbb Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 26 Dec 2018 11:25:20 +0100 Subject: [PATCH 0519/3747] bump env_logger --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 6fd45b0c74178..5e78661c2196f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -37,7 +37,7 @@ byteorder = { version = "1.1", features = ["i128"]} cargo_metadata = { version = "0.6", optional = true } directories = { version = "1.0", optional = true } rustc_version = { version = "0.2.3", optional = true } -env_logger = "0.5" +env_logger = "0.6" log = "0.4" # A noop dependency that changes in the Rust repository, it's a bit of a hack. # See the `src/tools/rustc-workspace-hack/README.md` file in `rust-lang/rust` From f2e14d931417f5037aea6212a5294a641caf5512 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 26 Dec 2018 13:16:47 +0100 Subject: [PATCH 0520/3747] use memory::check_bounds_ptr for offset check --- src/operator.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/operator.rs b/src/operator.rs index cc803c4ea9548..4b110224a0a2d 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -303,10 +303,9 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' if let Scalar::Ptr(ptr) = ptr { // Both old and new pointer must be in-bounds of a *live* allocation. // (Of the same allocation, but that part is trivial with our representation.) - let alloc = self.memory().get(ptr.alloc_id)?; - alloc.check_bounds_ptr(ptr)?; + self.memory().check_bounds_ptr(ptr, InboundsCheck::Live)?; let ptr = ptr.signed_offset(offset, self)?; - alloc.check_bounds_ptr(ptr)?; + self.memory().check_bounds_ptr(ptr, InboundsCheck::Live)?; Ok(Scalar::Ptr(ptr)) } else { // An integer pointer. They can only be offset by 0, and we pretend there From 3715245a3688de8f82ffbb127b09a0dd517458c3 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 26 Dec 2018 16:23:04 +0100 Subject: [PATCH 0521/3747] add test for offseting fn ptr --- tests/run-pass/ptr_offset.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tests/run-pass/ptr_offset.rs b/tests/run-pass/ptr_offset.rs index 6add5212db9f6..9e2e26fad3654 100644 --- a/tests/run-pass/ptr_offset.rs +++ b/tests/run-pass/ptr_offset.rs @@ -1,6 +1,16 @@ +fn f() -> i32 { 42 } + fn main() { let v = [1i16, 2]; let x = &v as *const i16; let x = unsafe { x.offset(1) }; assert_eq!(unsafe { *x }, 2); + + // fn ptr offset + unsafe { + let p = f as fn() -> i32 as usize; + let x = (p as *mut u32).offset(0) as usize; + let f: fn() -> i32 = std::mem::transmute(x); + assert_eq!(f(), 42); + } } From 1cda220b4b2403774feae5e37b8e8517875762b6 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 28 Dec 2018 18:16:55 +0100 Subject: [PATCH 0522/3747] fix install command --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 879d27dc97e07..c6dd0d8b06c60 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,7 @@ for example: Install Miri as a cargo subcommand: ```sh -cargo +nightly install --git https://github.com/solson/miri/ miri +cargo +nightly install --force --git https://github.com/solson/miri miri ``` If this does not work, try using the nightly version given in From b344f0fd43d6042d540ad209309fd859d595180c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 4 Jan 2019 10:15:53 +0100 Subject: [PATCH 0523/3747] test some more 2PB stuff --- tests/run-pass/2phase.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/tests/run-pass/2phase.rs b/tests/run-pass/2phase.rs index 5b9e5d3ea5ff7..987adca477a6f 100644 --- a/tests/run-pass/2phase.rs +++ b/tests/run-pass/2phase.rs @@ -16,6 +16,18 @@ fn two_phase2() { v.push(v.len()); } +fn two_phase3(b: bool) { + let mut x = &mut vec![]; + let mut y = vec![]; + x.push(( + { + if b { x = &mut y }; + 22 + }, + x.len(), + )); +} + /* fn two_phase_overlapping1() { let mut x = vec![]; @@ -62,6 +74,8 @@ fn with_interior_mutability() { fn main() { two_phase1(); two_phase2(); + two_phase3(false); + two_phase3(true); match_two_phase(); with_interior_mutability(); //FIXME: enable these, or remove them, depending on how https://github.com/rust-lang/rust/issues/56254 gets resolved From fced2ac8653bd7adb7edb81d312b09352ab572f0 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 4 Jan 2019 15:37:51 +0100 Subject: [PATCH 0524/3747] move env var stuff out of the miri lib --- src/bin/miri.rs | 8 ++++++++ src/lib.rs | 9 --------- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/src/bin/miri.rs b/src/bin/miri.rs index c2255d706339d..d8d7cfe0702e5 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -154,6 +154,14 @@ fn init_late_loggers() { rustc_driver::init_rustc_env_logger(); } } + + // If MIRI_BACKTRACE is set and RUST_CTFE_BACKTRACE is not, set RUST_CTFE_BACKTRACE. + // Do this late, so we really only apply this to miri's errors. + if let Ok(var) = env::var("MIRI_BACKTRACE") { + if env::var("RUST_CTFE_BACKTRACE") == Err(env::VarError::NotPresent) { + env::set_var("RUST_CTFE_BACKTRACE", &var); + } + } } fn find_sysroot() -> String { diff --git a/src/lib.rs b/src/lib.rs index 7643f93fdc2cf..bb6c9e3ca503f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -15,7 +15,6 @@ extern crate rustc_target; use std::collections::HashMap; use std::borrow::Cow; -use std::env; use rustc::ty::{self, TyCtxt, query::TyCtxtAt}; use rustc::ty::layout::{TyLayout, LayoutOf, Size, Align}; @@ -184,14 +183,6 @@ pub fn eval_main<'a, 'tcx: 'a>( ) { let mut ecx = create_ecx(tcx, main_id, validate).expect("Couldn't create ecx"); - // If MIRI_BACKTRACE is set and RUST_CTFE_BACKTRACE is not, set RUST_CTFE_BACKTRACE. - // Do this late, so we really only apply this to miri's errors. - if let Ok(var) = env::var("MIRI_BACKTRACE") { - if env::var("RUST_CTFE_BACKTRACE") == Err(env::VarError::NotPresent) { - env::set_var("RUST_CTFE_BACKTRACE", &var); - } - } - // Run! The main execution. let res: EvalResult = (|| { ecx.run()?; From e81d81e5af07f65a51e8496fda524b4cfbc09677 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 7 Jan 2019 11:23:08 +0100 Subject: [PATCH 0525/3747] implement panic_if_uninhabited intrinsic --- src/intrinsic.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/intrinsic.rs b/src/intrinsic.rs index 0f7382b61b726..0ef847236418c 100644 --- a/src/intrinsic.rs +++ b/src/intrinsic.rs @@ -286,6 +286,14 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, this.write_scalar(result_ptr, dest)?; } + "panic_if_uninhabited" => { + let ty = substs.type_at(0); + let layout = this.layout_of(ty)?; + if layout.abi.is_uninhabited() { + return err!(Intrinsic(format!("Trying to instantiate uninhabited type {}", ty))) + } + } + "powf32" => { let f = this.read_scalar(args[0])?.to_f32()?; let f2 = this.read_scalar(args[1])?.to_f32()?; From 6c9e702d9bdcef31a73949617cf5cb53c94c5dcb Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 4 Jan 2019 16:03:39 +0100 Subject: [PATCH 0526/3747] range_map: also test size of the internal representation --- src/range_map.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/range_map.rs b/src/range_map.rs index 762b17b1ae338..84965fd4cf739 100644 --- a/src/range_map.rs +++ b/src/range_map.rs @@ -203,6 +203,7 @@ mod tests { } // Check assert_eq!(to_vec(&map, 10, 1), vec![42]); + assert_eq!(map.map.len(), 3); // Insert with size 0 for x in map.iter_mut(Size::from_bytes(10), Size::from_bytes(0)) { @@ -212,6 +213,7 @@ mod tests { *x = 19; } assert_eq!(to_vec(&map, 10, 2), vec![42, -1]); + assert_eq!(map.map.len(), 3); } #[test] @@ -223,6 +225,7 @@ mod tests { for x in map.iter_mut(Size::from_bytes(15), Size::from_bytes(1)) { *x = 43; } + assert_eq!(map.map.len(), 5); assert_eq!( to_vec(&map, 10, 10), vec![-1, 42, -1, -1, -1, 43, -1, -1, -1, -1] @@ -233,6 +236,7 @@ mod tests { *x = 23; } } + assert_eq!(map.map.len(), 6); assert_eq!( to_vec(&map, 10, 10), @@ -244,6 +248,7 @@ mod tests { for x in map.iter_mut(Size::from_bytes(15), Size::from_bytes(10)) { *x = 19; } + assert_eq!(map.map.len(), 6); assert_eq!(map.iter(Size::from_bytes(19), Size::from_bytes(1)) .map(|&t| t).collect::>(), vec![19]); assert_eq!(map.iter(Size::from_bytes(20), Size::from_bytes(1)) From f24d0354f95615731d49a993adf2ea2983b661c1 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 5 Jan 2019 12:59:33 +0100 Subject: [PATCH 0527/3747] rewrite RangeMap to use a sorted Vec instead of a RangeMap This gives us a 20% perf improve for the benchmark from https://github.com/solson/miri/issues/593 --- src/range_map.rs | 253 ++++++++++++++++++++++++----------------------- 1 file changed, 127 insertions(+), 126 deletions(-) diff --git a/src/range_map.rs b/src/range_map.rs index 84965fd4cf739..5b7a940329b09 100644 --- a/src/range_map.rs +++ b/src/range_map.rs @@ -6,62 +6,29 @@ //! necessary (e.g. when [0,5) is first associated with X, and then [1,2) is mutated). //! Users must not depend on whether a range is coalesced or not, even though this is observable //! via the iteration APIs. -use std::collections::BTreeMap; + use std::ops; +use std::num::NonZeroU64; use rustc::ty::layout::Size; -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct RangeMap { - map: BTreeMap, +// Representation: offset-length-data tuples, sorted by offset. +#[derive(Clone, Debug)] +struct Elem { + offset: u64, + len: NonZeroU64, + data: T, } - -// The derived `Ord` impl sorts first by the first field, then, if the fields are the same, -// by the second field. -// This is exactly what we need for our purposes, since a range query on a BTReeSet/BTreeMap will give us all -// `MemoryRange`s whose `start` is <= than the one we're looking for, but not > the end of the range we're checking. -// At the same time the `end` is irrelevant for the sorting and range searching, but used for the check. -// This kind of search breaks, if `end < start`, so don't do that! -#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Debug)] -struct Range { - start: u64, - end: u64, // Invariant: end > start +// Length is always > 0. +#[derive(Clone, Debug)] +pub struct RangeMap { + v: Vec>, } -impl Range { - /// Compute a range of ranges that contains all ranges overlaping with [offset, offset+len) - fn range(offset: u64, len: u64) -> ops::Range { - if len == 0 { - // We can produce an empty range, nothing overlaps with this. - let r = Range { start: 0, end: 1 }; - return r..r; - } - // We select all elements that are within - // the range given by the offset into the allocation and the length. - // This is sound if all ranges that intersect with the argument range, are in the - // resulting range of ranges. - let left = Range { - // lowest range to include `offset` - start: 0, - end: offset + 1, - }; - let right = Range { - // lowest (valid) range not to include `offset+len` - start: offset + len, - end: offset + len + 1, - }; - left..right - } - - /// Tests if any element of [offset, offset+len) is contained in this range. +impl Elem { #[inline(always)] - fn overlaps(&self, offset: u64, len: u64) -> bool { - if len == 0 { - // `offset` totally does not matter, we cannot overlap with an empty interval - false - } else { - offset < self.end && offset.checked_add(len).unwrap() >= self.start - } + fn contains(&self, offset: u64) -> bool { + offset >= self.offset && offset < self.offset + self.len.get() } } @@ -70,73 +37,95 @@ impl RangeMap { /// the entire range. #[inline(always)] pub fn new(size: Size, init: T) -> RangeMap { - let mut map = RangeMap { map: BTreeMap::new() }; - if size.bytes() > 0 { - map.map.insert(Range { start: 0, end: size.bytes() }, init); + let size = size.bytes(); + let mut map = RangeMap { v: Vec::new() }; + if size > 0 { + map.v.push(Elem { + offset: 0, + len: NonZeroU64::new(size).unwrap(), + data: init + }); } map } - fn iter_with_range<'a>( - &'a self, - offset: u64, - len: u64, - ) -> impl Iterator + 'a { - self.map.range(Range::range(offset, len)).filter_map( - move |(range, data)| { - debug_assert!(len > 0); - if range.overlaps(offset, len) { - Some((range, data)) - } else { - None - } - }, - ) + /// Find the index containing the given offset. + fn find_offset(&self, offset: u64) -> usize { + debug_assert!(self.v.len() > 0); + let mut left = 0usize; // inclusive + let mut right = self.v.len(); // exclusive + loop { + let candidate = left.checked_add(right).unwrap() / 2; + let elem = &self.v[candidate]; + if elem.offset > offset { + // we are too far right (offset is further left) + debug_assert!(candidate < right); // we are making progress + right = candidate; + } else if offset >= elem.offset + elem.len.get() { + // we are too far left (offset is further right) + debug_assert!(candidate >= left); // we are making progress + left = candidate+1; + debug_assert!(left < right, "find_offset: offset {} is out-of-bounds", offset); + } else { + // This is it! + return candidate; + } + } } /// Provide read-only iteration over everything in the given range. This does /// *not* split items if they overlap with the edges. Do not use this to mutate /// through interior mutability. pub fn iter<'a>(&'a self, offset: Size, len: Size) -> impl Iterator + 'a { - self.iter_with_range(offset.bytes(), len.bytes()).map(|(_, data)| data) + let offset = offset.bytes(); + let len = len.bytes(); + // Compute a slice starting with the elements we care about + let slice: &[Elem] = if len == 0 { + // We just need any empty iterator. We don't even want to + // yield the element that surrounds this position. + &[] + } else { + let first = self.find_offset(offset); + &self.v[first..] + }; + let end = offset + len; // the first offset that is not included any more + slice.iter() + .take_while(move |elem| elem.offset < end) + .map(|elem| &elem.data) } pub fn iter_mut_all<'a>(&'a mut self) -> impl Iterator + 'a { - self.map.values_mut() + self.v.iter_mut().map(|elem| &mut elem.data) } - fn split_entry_at(&mut self, offset: u64) + // Split the element situated at the given `index`, such that the 2nd one starts at offset `split_offset`. + // Do nothing if the element already starts there. + // Return whether a split was necessary. + fn split_index(&mut self, index: usize, split_offset: u64) -> bool where T: Clone, { - let range = match self.iter_with_range(offset, 1).next() { - Some((&range, _)) => range, - None => return, - }; - assert!( - range.start <= offset && range.end > offset, - "We got a range that doesn't even contain what we asked for." - ); - // There is an entry overlapping this position, see if we have to split it - if range.start < offset { - let data = self.map.remove(&range).unwrap(); - let old = self.map.insert( - Range { - start: range.start, - end: offset, - }, - data.clone(), - ); - assert!(old.is_none()); - let old = self.map.insert( - Range { - start: offset, - end: range.end, - }, - data, - ); - assert!(old.is_none()); + let elem = &mut self.v[index]; + let first_len = split_offset.checked_sub(elem.offset) + .expect("The split_offset is before the element to be split"); + assert!(first_len <= elem.len.get(), + "The split_offset is after the element to be split"); + if first_len == 0 || first_len == elem.len.get() { + // Nothing to do + return false; } + + // Now we really have to split. Reduce length of first element. + let second_len = elem.len.get() - first_len; + elem.len = NonZeroU64::new(first_len).unwrap(); + // Copy the data, and insert 2nd element + let second = Elem { + offset: split_offset, + len: NonZeroU64::new(second_len).unwrap(), + data: elem.data.clone(), + }; + self.v.insert(index+1, second); + return true; } /// Provide mutable iteration over everything in the given range. As a side-effect, @@ -152,28 +141,43 @@ impl RangeMap { { let offset = offset.bytes(); let len = len.bytes(); - - if len > 0 { - // Preparation: Split first and last entry as needed. - self.split_entry_at(offset); - self.split_entry_at(offset + len); - } - // Now we can provide a mutable iterator - self.map.range_mut(Range::range(offset, len)).filter_map( - move |(&range, data)| { - debug_assert!(len > 0); - if range.overlaps(offset, len) { - assert!( - offset <= range.start && offset + len >= range.end, - "The splitting went wrong" - ); - Some(data) - } else { - // Skip this one - None + // Compute a slice containing exactly the elements we care about + let slice: &mut [Elem] = if len == 0 { + // We just need any empty iterator. We don't even want to + // yield the element that surrounds this position, nor do + // any splitting. + &mut [] + } else { + // Make sure we got a clear beginning + let mut first = self.find_offset(offset); + if self.split_index(first, offset) { + // The newly created 2nd element is ours + first += 1; + } + let first = first; // no more mutation + // Find our end. Linear scan, but that's okay because the iteration + // is doing the same linear scan anyway -- no increase in complexity. + let mut end = first; // the last element to be included + loop { + let elem = &self.v[end]; + if elem.offset+elem.len.get() < offset+len { + // We need to scan further. + end += 1; + debug_assert!(end < self.v.len(), "iter_mut: end-offset {} is out-of-bounds", offset+len); + } else { + // `elem` is the last included element. Stop search. + break; + } } - }, - ) + let end = end; // no more mutation + // We need to split the end as well. Even if this performs a + // split, we don't have to adjust our index as we only care about + // the first part of the split. + self.split_index(end, offset+len); + // Now we yield the slice. `end` is inclusive. + &mut self.v[first..=end] + }; + slice.iter_mut().map(|elem| &mut elem.data) } } @@ -203,7 +207,7 @@ mod tests { } // Check assert_eq!(to_vec(&map, 10, 1), vec![42]); - assert_eq!(map.map.len(), 3); + assert_eq!(map.v.len(), 3); // Insert with size 0 for x in map.iter_mut(Size::from_bytes(10), Size::from_bytes(0)) { @@ -213,7 +217,7 @@ mod tests { *x = 19; } assert_eq!(to_vec(&map, 10, 2), vec![42, -1]); - assert_eq!(map.map.len(), 3); + assert_eq!(map.v.len(), 3); } #[test] @@ -225,7 +229,7 @@ mod tests { for x in map.iter_mut(Size::from_bytes(15), Size::from_bytes(1)) { *x = 43; } - assert_eq!(map.map.len(), 5); + assert_eq!(map.v.len(), 5); assert_eq!( to_vec(&map, 10, 10), vec![-1, 42, -1, -1, -1, 43, -1, -1, -1, -1] @@ -236,7 +240,7 @@ mod tests { *x = 23; } } - assert_eq!(map.map.len(), 6); + assert_eq!(map.v.len(), 6); assert_eq!( to_vec(&map, 10, 10), @@ -244,14 +248,11 @@ mod tests { ); assert_eq!(to_vec(&map, 13, 5), vec![23, 23, 43, 23, 23]); - // Now request a range that goes beyond the initial size - for x in map.iter_mut(Size::from_bytes(15), Size::from_bytes(10)) { + for x in map.iter_mut(Size::from_bytes(15), Size::from_bytes(5)) { *x = 19; } - assert_eq!(map.map.len(), 6); + assert_eq!(map.v.len(), 6); assert_eq!(map.iter(Size::from_bytes(19), Size::from_bytes(1)) .map(|&t| t).collect::>(), vec![19]); - assert_eq!(map.iter(Size::from_bytes(20), Size::from_bytes(1)) - .map(|&t| t).collect::>(), vec![]); } } From 4f9c14c256b08458c873290a5e34eb493156532e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 5 Jan 2019 15:26:16 +0100 Subject: [PATCH 0528/3747] deduplicate RangeMap elements in iter_mut This cuts down execution time of the benchmark in the OP of https://github.com/solson/miri/issues/593 by another 25%, and it cuts max-RSS by 90% (!) --- src/lib.rs | 2 +- src/range_map.rs | 111 ++++++++++++++++++++++++----------------- src/stacked_borrows.rs | 2 +- 3 files changed, 67 insertions(+), 48 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index bb6c9e3ca503f..a8fd432282a10 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,4 @@ -#![feature(rustc_private)] +#![feature(rustc_private, range_contains)] #![allow(clippy::cast_lossless)] diff --git a/src/range_map.rs b/src/range_map.rs index 5b7a940329b09..d157cbf0549f2 100644 --- a/src/range_map.rs +++ b/src/range_map.rs @@ -12,26 +12,16 @@ use std::num::NonZeroU64; use rustc::ty::layout::Size; -// Representation: offset-length-data tuples, sorted by offset. #[derive(Clone, Debug)] struct Elem { - offset: u64, - len: NonZeroU64, + range: ops::Range, // the range covered by this element, never empty data: T, } -// Length is always > 0. #[derive(Clone, Debug)] pub struct RangeMap { v: Vec>, } -impl Elem { - #[inline(always)] - fn contains(&self, offset: u64) -> bool { - offset >= self.offset && offset < self.offset + self.len.get() - } -} - impl RangeMap { /// Create a new RangeMap for the given size, and with the given initial value used for /// the entire range. @@ -41,8 +31,7 @@ impl RangeMap { let mut map = RangeMap { v: Vec::new() }; if size > 0 { map.v.push(Elem { - offset: 0, - len: NonZeroU64::new(size).unwrap(), + range: 0..size, data: init }); } @@ -57,11 +46,11 @@ impl RangeMap { loop { let candidate = left.checked_add(right).unwrap() / 2; let elem = &self.v[candidate]; - if elem.offset > offset { + if offset < elem.range.start { // we are too far right (offset is further left) debug_assert!(candidate < right); // we are making progress right = candidate; - } else if offset >= elem.offset + elem.len.get() { + } else if offset >= elem.range.end { // we are too far left (offset is further right) debug_assert!(candidate >= left); // we are making progress left = candidate+1; @@ -85,12 +74,12 @@ impl RangeMap { // yield the element that surrounds this position. &[] } else { - let first = self.find_offset(offset); - &self.v[first..] + let first_idx = self.find_offset(offset); + &self.v[first_idx..] }; let end = offset + len; // the first offset that is not included any more slice.iter() - .take_while(move |elem| elem.offset < end) + .take_while(move |elem| elem.range.start < end) .map(|elem| &elem.data) } @@ -106,22 +95,19 @@ impl RangeMap { T: Clone, { let elem = &mut self.v[index]; - let first_len = split_offset.checked_sub(elem.offset) - .expect("The split_offset is before the element to be split"); - assert!(first_len <= elem.len.get(), - "The split_offset is after the element to be split"); - if first_len == 0 || first_len == elem.len.get() { + if split_offset == elem.range.start || split_offset == elem.range.end { // Nothing to do return false; } + debug_assert!(elem.range.contains(&split_offset), + "The split_offset is not in the element to be split"); // Now we really have to split. Reduce length of first element. - let second_len = elem.len.get() - first_len; - elem.len = NonZeroU64::new(first_len).unwrap(); + let second_range = split_offset..elem.range.end; + elem.range.end = split_offset; // Copy the data, and insert 2nd element let second = Elem { - offset: split_offset, - len: NonZeroU64::new(second_len).unwrap(), + range: second_range, data: elem.data.clone(), }; self.v.insert(index+1, second); @@ -137,7 +123,7 @@ impl RangeMap { len: Size, ) -> impl Iterator + 'a where - T: Clone, + T: Clone + PartialEq, { let offset = offset.bytes(); let len = len.bytes(); @@ -149,33 +135,53 @@ impl RangeMap { &mut [] } else { // Make sure we got a clear beginning - let mut first = self.find_offset(offset); - if self.split_index(first, offset) { + let mut first_idx = self.find_offset(offset); + if self.split_index(first_idx, offset) { // The newly created 2nd element is ours - first += 1; + first_idx += 1; } - let first = first; // no more mutation + let first_idx = first_idx; // no more mutation // Find our end. Linear scan, but that's okay because the iteration // is doing the same linear scan anyway -- no increase in complexity. - let mut end = first; // the last element to be included + // We combine this scan with a scan for duplicates that we can merge, to reduce + // the number of elements. + let mut equal_since_idx = first_idx; + let mut end_idx = first_idx; // when the loop is done, this is the first excluded element. loop { - let elem = &self.v[end]; - if elem.offset+elem.len.get() < offset+len { - // We need to scan further. - end += 1; - debug_assert!(end < self.v.len(), "iter_mut: end-offset {} is out-of-bounds", offset+len); - } else { - // `elem` is the last included element. Stop search. + // Compute if `end` is the last element we need to look at. + let done = (self.v[end_idx].range.end >= offset+len); + // We definitely need to include `end`, so move the index. + end_idx += 1; + debug_assert!(done || end_idx < self.v.len(), "iter_mut: end-offset {} is out-of-bounds", offset+len); + // see if we want to merge everything in `equal_since..end` (exclusive at the end!) + if done || self.v[end_idx].data != self.v[equal_since_idx].data { + // Everything in `equal_since..end` was equal. Make them just one element covering + // the entire range. + let equal_elems = end_idx - equal_since_idx; // number of equal elements + if equal_elems > 1 { + // Adjust the range of the first element to cover all of them. + let equal_until = self.v[end_idx - 1].range.end; // end of range of last of the equal elements + self.v[equal_since_idx].range.end = equal_until; + // Delete the rest of them. + self.v.splice(equal_since_idx+1..end_idx, std::iter::empty()); + // Adjust `end_idx` because we made the list shorter. + end_idx -= (equal_elems - 1); + } + // Go on scanning. + equal_since_idx = end_idx; + } + // Leave loop if this is the last element. + if done { break; } } - let end = end; // no more mutation + let end_idx = end_idx-1; // Move to last included instead of first excluded index. // We need to split the end as well. Even if this performs a // split, we don't have to adjust our index as we only care about // the first part of the split. - self.split_index(end, offset+len); + self.split_index(end_idx, offset+len); // Now we yield the slice. `end` is inclusive. - &mut self.v[first..=end] + &mut self.v[first_idx..=end_idx] }; slice.iter_mut().map(|elem| &mut elem.data) } @@ -241,18 +247,31 @@ mod tests { } } assert_eq!(map.v.len(), 6); - assert_eq!( to_vec(&map, 10, 10), vec![23, 42, 23, 23, 23, 43, 23, 23, 23, 23] ); assert_eq!(to_vec(&map, 13, 5), vec![23, 23, 43, 23, 23]); + for x in map.iter_mut(Size::from_bytes(15), Size::from_bytes(5)) { *x = 19; } assert_eq!(map.v.len(), 6); - assert_eq!(map.iter(Size::from_bytes(19), Size::from_bytes(1)) - .map(|&t| t).collect::>(), vec![19]); + assert_eq!( + to_vec(&map, 10, 10), + vec![23, 42, 23, 23, 23, 19, 19, 19, 19, 19] + ); + // Should be seeing two blocks with 19 + assert_eq!(map.iter(Size::from_bytes(15), Size::from_bytes(2)) + .map(|&t| t).collect::>(), vec![19, 19]); + + // a NOP iter_mut should trigger merging + for x in map.iter_mut(Size::from_bytes(15), Size::from_bytes(5)) { } + assert_eq!(map.v.len(), 5); + assert_eq!( + to_vec(&map, 10, 10), + vec![23, 42, 23, 23, 23, 19, 19, 19, 19, 19] + ); } } diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 27d4a4f7f7b58..1fc705c03bb5e 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -67,7 +67,7 @@ pub enum BorStackItem { } /// Extra per-location state -#[derive(Clone, Debug)] +#[derive(Clone, Debug, PartialEq, Eq)] pub struct Stack { borrows: Vec, // used as a stack; never empty frozen_since: Option, // virtual frozen "item" on top of the stack From 17d11ebe6e9599d804c0378900b92a5a8054aec3 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 5 Jan 2019 16:16:08 +0100 Subject: [PATCH 0529/3747] be explicit about doing a binary search; fix out-of-bounds check --- src/range_map.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/range_map.rs b/src/range_map.rs index d157cbf0549f2..d21f1ed8964d1 100644 --- a/src/range_map.rs +++ b/src/range_map.rs @@ -40,10 +40,11 @@ impl RangeMap { /// Find the index containing the given offset. fn find_offset(&self, offset: u64) -> usize { - debug_assert!(self.v.len() > 0); + // We do a binary search let mut left = 0usize; // inclusive let mut right = self.v.len(); // exclusive loop { + debug_assert!(left < right, "find_offset: offset {} is out-of-bounds", offset); let candidate = left.checked_add(right).unwrap() / 2; let elem = &self.v[candidate]; if offset < elem.range.start { @@ -54,7 +55,6 @@ impl RangeMap { // we are too far left (offset is further right) debug_assert!(candidate >= left); // we are making progress left = candidate+1; - debug_assert!(left < right, "find_offset: offset {} is out-of-bounds", offset); } else { // This is it! return candidate; From a957a36ddcb1a735719a96f1fb35c9ac0d604bf3 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 7 Jan 2019 19:36:25 +0100 Subject: [PATCH 0530/3747] tweak merging to give up if we don't make any progress --- src/range_map.rs | 40 ++++++++++++++++++++++++++-------------- 1 file changed, 26 insertions(+), 14 deletions(-) diff --git a/src/range_map.rs b/src/range_map.rs index d21f1ed8964d1..48cbc57f0ebce 100644 --- a/src/range_map.rs +++ b/src/range_map.rs @@ -145,7 +145,12 @@ impl RangeMap { // is doing the same linear scan anyway -- no increase in complexity. // We combine this scan with a scan for duplicates that we can merge, to reduce // the number of elements. + // We stop searching after the first "block" of size 1, to avoid spending excessive + // amounts of time on the merging. let mut equal_since_idx = first_idx; + // Once we see too many non-mergeable blocks, we stop. + // The initial value is chosen via... magic. Benchmarking and magic. + let mut successful_merge_count = 3usize; let mut end_idx = first_idx; // when the loop is done, this is the first excluded element. loop { // Compute if `end` is the last element we need to look at. @@ -154,21 +159,28 @@ impl RangeMap { end_idx += 1; debug_assert!(done || end_idx < self.v.len(), "iter_mut: end-offset {} is out-of-bounds", offset+len); // see if we want to merge everything in `equal_since..end` (exclusive at the end!) - if done || self.v[end_idx].data != self.v[equal_since_idx].data { - // Everything in `equal_since..end` was equal. Make them just one element covering - // the entire range. - let equal_elems = end_idx - equal_since_idx; // number of equal elements - if equal_elems > 1 { - // Adjust the range of the first element to cover all of them. - let equal_until = self.v[end_idx - 1].range.end; // end of range of last of the equal elements - self.v[equal_since_idx].range.end = equal_until; - // Delete the rest of them. - self.v.splice(equal_since_idx+1..end_idx, std::iter::empty()); - // Adjust `end_idx` because we made the list shorter. - end_idx -= (equal_elems - 1); + if successful_merge_count > 0 { + if done || self.v[end_idx].data != self.v[equal_since_idx].data { + // Everything in `equal_since..end` was equal. Make them just one element covering + // the entire range. + let removed_elems = end_idx - equal_since_idx - 1; // number of elements that we would remove + if removed_elems > 0 { + // Adjust the range of the first element to cover all of them. + let equal_until = self.v[end_idx - 1].range.end; // end of range of last of the equal elements + self.v[equal_since_idx].range.end = equal_until; + // Delete the rest of them. + self.v.splice(equal_since_idx+1..end_idx, std::iter::empty()); + // Adjust `end_idx` because we made the list shorter. + end_idx -= removed_elems; + // adjust the count for the cutoff + successful_merge_count += removed_elems; + } else { + // adjust the count for the cutoff + successful_merge_count -= 1; + } + // Go on scanning for the next block starting here. + equal_since_idx = end_idx; } - // Go on scanning. - equal_since_idx = end_idx; } // Leave loop if this is the last element. if done { From 44612aa8348fd204b0678b385e285271874ebc26 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 7 Jan 2019 19:39:49 +0100 Subject: [PATCH 0531/3747] add the benchmarks I used --- bench-cargo-miri/mse/Cargo.toml | 7 +++++++ bench-cargo-miri/mse/src/main.rs | 26 ++++++++++++++++++++++++++ bench-cargo-miri/serde1/Cargo.toml | 9 +++++++++ bench-cargo-miri/serde1/src/main.rs | 13 +++++++++++++ 4 files changed, 55 insertions(+) create mode 100644 bench-cargo-miri/mse/Cargo.toml create mode 100644 bench-cargo-miri/mse/src/main.rs create mode 100644 bench-cargo-miri/serde1/Cargo.toml create mode 100644 bench-cargo-miri/serde1/src/main.rs diff --git a/bench-cargo-miri/mse/Cargo.toml b/bench-cargo-miri/mse/Cargo.toml new file mode 100644 index 0000000000000..7b4c2dc758faa --- /dev/null +++ b/bench-cargo-miri/mse/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "mse" +version = "0.1.0" +authors = ["Ralf Jung "] +edition = "2018" + +[dependencies] diff --git a/bench-cargo-miri/mse/src/main.rs b/bench-cargo-miri/mse/src/main.rs new file mode 100644 index 0000000000000..7d00a623468ed --- /dev/null +++ b/bench-cargo-miri/mse/src/main.rs @@ -0,0 +1,26 @@ +static EXPECTED: &[u8] = &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 0, 0, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 1, 0, 255, 255, 1, 0, 255, 255, 1, 0, 255, 255, 1, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 254, 255, 0, 0, 254, 255, 0, 0, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 255, 255, 1, 0, 255, 255, 1, 0, 0, 0, 1, 0, 255, 255, 2, 0, 255, 255, 2, 0, 255, 255, 2, 0, 255, 255, 2, 0, 255, 255, 2, 0, 255, 255, 1, 0, 255, 255, 1, 0, 255, 255, 0, 0, 254, 255, 0, 0, 254, 255, 0, 0, 254, 255, 255, 255, 254, 255, 254, 255, 254, 255, 253, 255, 253, 255, 253, 255, 253, 255, 252, 255, 254, 255, 251, 255, 254, 255, 251, 255, 254, 255, 252, 255, 255, 255, 252, 255, 0, 0, 252, 255, 0, 0, 252, 255, 1, 0, 252, 255, 1, 0, 252, 255, 2, 0, 252, 255, 2, 0, 252, 255, 2, 0, 252, 255, 2, 0, 252, 255, 2, 0, 253, 255, 1, 0, 252, 255, 0, 0, 252, 255, 255, 255, 251, 255, 0, 0, 251, 255, 0, 0, 251, 255, 0, 0, 252, 255, 2, 0, 252, 255, 3, 0, 252, 255, 4, 0, 253, 255, 5, 0, 254, 255, 5, 0, 253, 255, 6, 0, 253, 255, 6, 0, 253, 255, 5, 0, 253, 255, 5, 0, 254, 255, 4, 0, 254, 255, 3, 0, 251, 255, 0, 0, 250, 255, 255, 255, 253, 255, 254, 255, 252, 255, 252, 255, 247, 255, 251, 255, 247, 255, 252, 255, 252, 255, 254, 255, 252, 255, 254, 255, 252, 255, 255, 255, 254, 255, 1, 0, 1, 0, 1, 0, 4, 0, 2, 0, 8, 0, 2, 0, 12, 0, 1, 0, 13, 0, 0, 0, 12, 0, 0, 0, 11, 0, 255, 255, 8, 0, 254, 255, 7, 0, 0, 0, 7, 0, 253, 255, 11, 0, 248, 255, 15, 0, 247, 255, 17, 0, 250, 255, 17, 0, 251, 255, 13, 0, 253, 255, 7, 0, 255, 255, 3, 0, 255, 255, 254, 255, 255, 255, 252, 255, 255, 255, 252, 255, 254, 255, 250, 255, 255, 255, 242, 255, 254, 255, 239, 255, 252, 255, 248, 255, 255, 255, 249, 255, 5, 0, 239, 255, 7, 0, 238, 255, 10, 0, 249, 255, 18, 0, 254, 255, 25, 0, 253, 255, 27, 0, 0, 0, 31, 0, 4, 0, 34, 0, 4, 0, 34, 0, 8, 0, 36, 0, 8, 0, 37, 0, 2, 0, 36, 0, 4, 0, 34, 0, 8, 0, 28, 0, 3, 0, 15, 0, 255, 255, 11, 0, 0, 0, 12, 0, 251, 255, 8, 0, 252, 255, 10, 0, 0, 0, 23, 0, 252, 255, 31, 0, 248, 255, 30, 0, 254, 255, 30, 0, 255, 255, 26, 0, 250, 255, 22, 0, 250, 255, 20, 0, 244, 255, 15, 0, 237, 255, 10, 0, 246, 255, 13, 0, 242, 255, 6, 0, 213, 255, 243, 255, 213, 255, 240, 255, 247, 255, 244, 255, 246, 255, 227, 255, 214, 255, 216, 255, 219, 255, 228, 255, 251, 255, 235, 255, 1, 0, 232, 255, 248, 255, 236, 255, 4, 0, 238, 255, 26, 0, 232, 255, 44, 0, 230, 255, 66, 0, 226, 255, 86, 0, 219, 255, 88, 0, 215, 255, 72, 0, 210, 255, 50, 0, 225, 255, 28, 0, 23, 0, 14, 0, 64, 0, 16, 0, 51, 0, 26, 0, 32, 0, 34, 0, 39, 0, 42, 0, 48, 0, 35, 0, 58, 0, 255, 255, 72, 0, 220, 255, 69, 0, 197, 255, 58, 0, 158, 255, 54, 0, 132, 255, 36, 0, 153, 255, 12, 0, 146, 255, 5, 0, 83, 255, 237, 255, 110, 255, 197, 255, 252, 255, 214, 255, 51, 0, 1, 0, 233, 255, 250, 255, 226, 255, 250, 255, 45, 0, 46, 0, 47, 0, 70, 0, 6, 0, 55, 0, 19, 0, 60, 0, 38, 0, 62, 0, 42, 0, 47, 0, 61, 0, 46, 0, 40, 0, 42, 0, 237, 255, 22, 0, 222, 255, 6, 0, 221, 255, 206, 255, 195, 255, 115, 255, 219, 255, 85, 255, 17, 0, 93, 255, 26, 0, 76, 255, 46, 0, 102, 255, 80, 0, 193, 255, 48, 0, 252, 255, 18, 0, 20, 0, 50, 0, 47, 0, 58, 0, 53, 0, 44, 0, 61, 0, 57, 0, 85, 0, 37, 0, 80, 0, 0, 0, 86, 0, 248, 255, 106, 0, 161, 255, 49, 0, 43, 255, 248, 255, 125, 255, 47, 0, 49, 0, 63, 0, 40, 0, 217, 255, 187, 255, 182, 255, 219, 255, 236, 255, 63, 0, 244, 255, 58, 0, 242, 255, 244, 255, 25, 0, 225, 255, 41, 0, 11, 0, 45, 0, 76, 0, 47, 0, 167, 0, 5, 0, 5, 1, 219, 255, 21, 1, 173, 255, 183, 0, 84, 255, 35, 0, 134, 255, 177, 255, 138, 0, 186, 255, 10, 1, 69, 0, 124, 0, 228, 0, 0, 0, 135, 1, 227, 255, 82, 2, 172, 255, 190, 2, 178, 255, 115, 2, 248, 255, 39, 2, 243, 255, 253, 1, 13, 0, 116, 1, 120, 0, 96, 1, 125, 0, 110, 2, 127, 0, 179, 2, 223, 0, 106, 1, 126, 0, 130, 1, 223, 255, 147, 3, 198, 0, 190, 3, 201, 1, 200, 1, 42, 1, 244, 1, 233, 0, 3, 4, 213, 1, 72, 4, 170, 1, 150, 3, 160, 0, 43, 4, 141, 0, 196, 4, 189, 0, 221, 4, 164, 0, 95, 5, 41, 1, 98, 5, 247, 1, 19, 5, 190, 2, 14, 6, 161, 3, 7, 7, 87, 3, 216, 6, 35, 2, 38, 7, 90, 2, 136, 7, 64, 3, 200, 6, 28, 3, 199, 6, 165, 3, 169, 7, 105, 5, 143, 7, 26, 6, 57, 8, 205, 5, 156, 10, 169, 5, 132, 11, 25, 5, 208, 10, 181, 4, 156, 10, 66, 5, 227, 9, 170, 5, 166, 9, 117, 6, 45, 12, 63, 8, 42, 13, 128, 8, 136, 10, 155, 7, 109, 11, 1, 9, 6, 15, 98, 10, 121, 9, 136, 8, 147, 252, 189, 7, 43, 247, 63, 10, 147, 249, 92, 11, 172, 248, 172, 10, 112, 245, 137, 11, 76, 246, 44, 12, 184, 247, 138, 11, 118, 246, 144, 12, 94, 246, 171, 13, 112, 247, 162, 12, 168, 246, 33, 13, 63, 246, 29, 15, 226, 247, 188, 14, 190, 248, 75, 15, 238, 247, 86, 17, 19, 247, 118, 11, 10, 247, 232, 254, 238, 247, 30, 249, 56, 248, 124, 250, 6, 247, 1, 250, 161, 246, 3, 249, 81, 247, 117, 250, 60, 247, 202, 250, 212, 247, 60, 250, 15, 249, 140, 250, 34, 248, 221, 249, 105, 247, 218, 249, 205, 248, 113, 251, 138, 248, 90, 250, 41, 248, 230, 248]; +static PCM: &[i16] = &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, -2, 0, -2, 0, -2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 1, 0, 1, 0, 0, -2, 0, -2, 0, -2, 0, -2, -2, -2, -3, -3, -3, -3, -4, -2, -5, -2, -5, -2, -4, 0, -4, 0, -4, 0, -4, 1, -4, 1, -4, 2, -4, 2, -4, 2, -4, 2, -4, 2, -3, 1, -4, 0, -4, 0, -5, 0, -5, 0, -5, 0, -4, 2, -4, 3, -4, 4, -3, 5, -2, 5, -3, 6, -3, 6, -3, 5, -3, 5, -2, 4, -2, 3, -5, 0, -6, 0, -3, -2, -4, -4, -9, -5, -9, -4, -4, -2, -4, -2, -4, 0, -2, 1, 1, 1, 4, 2, 8, 2, 12, 1, 13, 0, 12, 0, 11, 0, 8, -2, 7, 0, 7, -3, 11, -8, 15, -9, 17, -6, 17, -5, 13, -3, 7, 0, 3, 0, -2, 0, -4, 0, -4, -2, -6, 0, -14, -2, -17, -4, -8, 0, -7, 5, -17, 7, -18, 10, -7, 18, -2, 25, -3, 27, 0, 31, 4, 34, 4, 34, 8, 36, 8, 37, 2, 36, 4, 34, 8, 28, 3, 15, 0, 11, 0, 12, -5, 8, -4, 10, 0, 23, -4, 31, -8, 30, -2, 30, 0, 26, -6, 22, -6, 20, -12, 15, -19, 10, -10, 13, -14, 6, -43, -13, -43, -16, -9, -12, -10, -29, -42, -40, -37, -28, -5, -21, 1, -24, -8, -20, 4, -18, 26, -24, 44, -26, 66, -30, 86, -37, 88, -41, 72, -46, 50, -31, 28, 23, 14, 64, 16, 51, 26, 32, 34, 39, 42, 48, 35, 58, 0, 72, -36, 69, -59, 58, -98, 54, -124, 36, -103, 12, -110, 5, -173, -19, -146, -59, -4, -42, 51, 1, -23, -6, -30, -6, 45, 46, 47, 70, 6, 55, 19, 60, 38, 62, 42, 47, 61, 46, 40, 42, -19, 22, -34, 6, -35, -50, -61, -141, -37, -171, 17, -163, 26, -180, 46, -154, 80, -63, 48, -4, 18, 20, 50, 47, 58, 53, 44, 61, 57, 85, 37, 80, 0, 86, -8, 106, -95, 49, -213, -8, -131, 47, 49, 63, 40, -39, -69, -74, -37, -20, 63, -12, 58, -14, -12, 25, -31, 41, 11, 45, 76, 47, 167, 5, 261, -37, 277, -83, 183, -172, 35, -122, -79, 138, -70, 266, 69, 124, 228, 0, 391, -29, 594, -84, 702, -78, 627, -8, 551, -13, 509, 13, 372, 120, 352, 125, 622, 127, 691, 223, 362, 126, 386, -33, 915, 198, 958, 457, 456, 298, 500, 233, 1027, 469, 1096, 426, 918, 160, 1067, 141, 1220, 189, 1245, 164, 1375, 297, 1378, 503, 1299, 702, 1550, 929, 1799, 855, 1752, 547, 1830, 602, 1928, 832, 1736, 796, 1735, 933, 1961, 1385, 1935, 1562, 2105, 1485, 2716, 1449, 2948, 1305, 2768, 1205, 2716, 1346, 2531, 1450, 2470, 1653, 3117, 2111, 3370, 2176, 2696, 1947, 2925, 2305, 3846, 2658, 2425, 2184, -877, 1981, -2261, 2623, -1645, 2908, -1876, 2732, -2704, 2953, -2484, 3116, -2120, 2954, -2442, 3216, -2466, 3499, -2192, 3234, -2392, 3361, -2497, 3869, -2078, 3772, -1858, 3915, -2066, 4438, -2285, 2934, -2294, -280, -2066, -1762, -1992, -1412, -2298, -1535, -2399, -1789, -2223, -1419, -2244, -1334, -2092, -1476, -1777, -1396, -2014, -1571, -2199, -1574, -1843, -1167, -1910, -1446, -2007, -1818]; + +fn main() { + mse(PCM.len(), PCM, EXPECTED); +} + +fn read_i16(buffer: &[u8], index: usize) -> i16 { + const SIZE: usize = std::mem::size_of::(); + let mut bytes: [u8; SIZE] = [0u8; SIZE]; + bytes.copy_from_slice(&buffer[(index * SIZE)..(index * SIZE + SIZE)]); + unsafe { std::mem::transmute(bytes) } +} + +fn mse(samples: usize, frame_buf: &[i16], buf_ref: &[u8]) -> f64 { + let mut mse = 0.0; + let max_samples = std::cmp::min(buf_ref.len() / 2, samples as usize); + for i in 0..max_samples { + let ref_res = read_i16(buf_ref, i); + let info_res = frame_buf[i as usize]; + let diff = (ref_res - info_res).abs(); + mse += f64::from(diff.pow(2)); + } + mse / max_samples as f64 +} + diff --git a/bench-cargo-miri/serde1/Cargo.toml b/bench-cargo-miri/serde1/Cargo.toml new file mode 100644 index 0000000000000..29f0abff5d73d --- /dev/null +++ b/bench-cargo-miri/serde1/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "cargo-miri-test" +version = "0.1.0" +authors = ["Oliver Schneider "] +edition = "2018" + +[dependencies] +serde = { version = "*", features = ["derive"] } +serde_json = "*" diff --git a/bench-cargo-miri/serde1/src/main.rs b/bench-cargo-miri/serde1/src/main.rs new file mode 100644 index 0000000000000..2712156d61b4a --- /dev/null +++ b/bench-cargo-miri/serde1/src/main.rs @@ -0,0 +1,13 @@ +static JSON: &str = r#"{"buffer":[-29,-42,-40,-37,-28,-5,-21,1,-24,-8,-20,4,-18,26,-24,44,-26,66,-30,86,-37,88,-41,72,-46,50,-31,28,23,14,64,16,51,26,32,34,39,42,48,35,58,0,72,-36,69,-59,58,-98,54,-124,36,-103,12,-110,5,-173,-19,-146,-59,-4,-42,51,1,-23,-6,-30,-6,45,46,47,70,6,55,19,60,38,62,42,47,61,46,40,42,-19,22,-34,6,-35,-50,-61,-141,-37,-171,17,-163,26,-180,46,-154,80,-63,48,-4,18,20,50,47,58,53,44,61,57,85,37,80,0,86,-8,106,-95,49,-213,-8,-131,47,49,63,40,-39,-69,-74,-37,-20,63,-12,58,-14,-12,25,-31,41,11,45,76,47,167,5,261,-37,277,-83,183,-172,35,-122,-79,138,-70,266,69,124,228,0,391,-29,594,-84,702,-78,627,-8,551,-13,509,13,372,120,352,125,622,127,691,223,362,126,386,-33,915,198,958,457,456,298,500,233,1027,469,1096,426,918,160,1067,141,1220,189,1245,164,1375,297,1378,503,1299,702,1550,929,1799,855,1752,547,1830,602,1928,832,1736,796,1735,933,1961,1385,1935,1562,2105,1485,2716,1449,2948,1305,2768,1205,2716,1346,2531,1450,2470,1653,3117,2111,3370,2176,2696,1947,2925,2305,3846,2658,2425,2184,-877,1981,-2261,2623,-1645,2908,-1876,2732,-2704,2953,-2484,3116,-2120,2954,-2442,3216,-2466,3499,-2192,3234,-2392,3361,-2497,3869,-2078,3772,-1858,3915,-2066,4438,-2285,2934,-2294,-280,-2066,-1762,-1992,-1412,-2298,-1535,-2399,-1789,-2223,-1419,-2244,-1334,-2092,-1476,-1777,-1396,-2014,-1571,-2199,-1574,-1843,-1167,-1910,-1446,-2007,-1818,-1506,-1331,-2526,-2048,-5535,-4573,-7148,-5828,-6422,-5327,-5840,-5488,-5992,-6144,-6014,-6164,-6109,-6234,-6271,-6388,-6288,-6156,-6517,-6249,-6794,-6602,-6822,-6418,-6788,-6245,-6490,-6560,-6394,-6794,-7920,-6937,-10397,-7140,-11428,-6972,-11019,-6610,-11141,-6665,-11913,-7046,-11979,-7235,-11599,-7015,-11854,-6912,-12161,-7441,-12136,-7761,-12861,-7292,-13390,-7254,-12345,-7809,-12490,-7463,-13983,-6969,-10489,-8465,-2382,-11054,1272,-12247,-270,-12060,-323,-12113,502,-12486,-697,-12251,-1086,-12141,-181,-13116,-670,-13509,-1173,-12592,-443,-12811,-449,-13698,-934,-12850,-747,-13083,-873,-15036,-1161,-11478,-1047,-2669,-1407,1006,-1658,-1146,-1195,-1297,-1421,-73,-1946,-977,-1590,-1499,-1577,-1010,-1862,-1256,-1389,-962,-1692,-509,-2613,-1317,-2087,-1359,-1997,-1034,-2891,-2024,-119,-84,5651,5723,8074,8306,7156,6870,6985,7106,7312,8403,7114,8096,7173,7848,7082,7827,6761,7189,6985,7368,7076,7835,6992,7297,7453,7260,7016,7755,6025,7429,8533,7352,14150,7628,17142,7077,16399,6947,15939,7475,16564,7069,16463,6882,16400,7602,17031,7233,16543,6517,15395,7018,15985,7104,16689,6869,15655,7622,16155,7198,17884,6022,14056,8856,5665,14484,1815,16782,3034,15786,3107,15664,2312,16517,2965,16443,3036,16120,2287,16584,2479,16720,2693,16073,2535,16159,2958,16609,3067,16086,2716,16579,3035,17752,3092,13704,2499,5265,2620,1452,2808,3024,2444,3275,2839,2267,3340,2857,2968,3232,3066,2867,3152,3072,2248,2961,2413,2807,3238,3237,2368,2699,2262,2392,3537,3339,827,823,-5020,-5359,-7095,-7857,-5973,-6274,-6208,-6279,-6934,-7181,-6893,-6647,-7146,-6687,-7026,-7328,-6451,-6924,-6763,-6535,-7109,-6639,-6926,-6559,-7188,-6799,-6727,-6955,-5786,-6554,-8543,-6796,-14465,-7190,-17356,-6641,-16372,-6529,-15941,-6898,-16526,-6434,-16219,-6520,-16222,-7449,-17077,-7097,-16665,-6476,-15675,-7026,-16498,-6848,-17147,-6271,-15894,-7069,-16266,-7032,-17817,-5991,-13796,-8594,-5421,-14349,-1649,-17288,-2847,-16525,-2974,-15945,-2324,-16482,-3022,-16593,-3097,-16451,-2420,-16780,-2649,-16641,-2836,-15900,-2660,-16214,-3050,-16827,-3111,-15993,-2741,-16151,-2994,-17537,-2933,-13812,-2314,-5216,-2475,-1125,-2648,-2801,-2290,-3285,-2796,-2243,-3415,-2642,-3109,-3000,-3271,-2839,-3408,-3161,-2497,-2876,-2603,-2570,-3351,-3173,-2416,-2832,-2235,-2408,-3405,-3186,-613,-768,5271,5201,7376,7644,6241,6176,6366,6275,6964,7124,6831,6508,6998,6566,6836,7230,6277,6777,6589,6376,6934,6536,6819,6494,7160,6749,6736,6900,5822,6476,8593,6747,14520,7204,17448,6637,16490,6483,16033,6906,16600,6511,16304,6568,16279,7438,17079,7072,16624,6463,15577,7028,16343,6877,16990,6331,15760,7121,16140,7023,17719,5944,13748,8575,5401,14336,1645,17210,2880,16419,3036,15896,2382,16483,3074,16584,3143,16425,2443,16782,2650,16695,2825,15978,2632,16272,3015,16880,3084,16096,2709,16289,2965,17641,2932,13887,2323,5330,2474,1286,2656,2954,2309,3410,2803,2373,3414,2795,3106,3151,3263,2952,3403,3241,2483,2969,2568,2681,3316,3245,2383,2837,2199,2390,3396,3165,641,706,-5230,-5323,-7307,-7790,-6136,-6317,-6268,-6419,-6884,-7278,-6766,-6666,-6976,-6731,-6853,-7406,-6308,-6958,-6636,-6553,-6978,-6703,-6829,-6647,-7156,-6883,-6737,-7017,-5814,-6581,-8575,-6833,-14490,-7270,-17411,-6699,-16466,-6539,-16016,-6931,-16571,-6504,-16257,-6551,-16202,-7408,-16983,-7021,-16545,-6410,-15512,-6976,-16305,-6803,-17017,-6243,-15820,-7037,-16197,-6923,-17802,-5820,-13840,-8455,-5475,-14227,-1724,-17099,-2923,-16314,-3008,-15801,-2362,-16392,-3088,-16506,-3163,-16356,-2503,-16700,-2717,-16605,-2855,-15904,-2710,-16226,-3108,-16870,-3089,-16101,-2747,-16257,-3087,-17584,-2975,-13868,-2324,-5343,-2548,-1275,-2673,-2917,-2213,-3363,-2694,-2311,-3251,-2744,-2867,-3129,-3034,-2939,-3190,-3234,-2346,-2964,-2639,-2658,-3558,-3241,-2670,-2892,-2453,-2437,-3564,-3175,-771,-779,5105,5171,7308,7655,6265,6204,6397,6288,7024,7172,6903,6586,7002,6627,6777,7308,6190,6889,6537,6465,7011,6613,6985,6631,7393,6934,7073,7072,6112,6615,8751,6859,14672,7282,17448,6652,16146,6448,15565,6899,16151,6547,15860,6591,16048,7446,17065,7064,16661,6368,15774,6857,16524,6677,16825,6071,15577,6900,16119,7040,17490,6118,13495,8696,5432,14446,1678,17366,3036,16488,3624,15834,3012,16382,3575,16465,3685,16301,2815,16708,2982,16679,3356,15952,2934,16049,3290,16352,3964,15605,3612,16222,3647,17764,4272,13865,3977,5384,3592,1580,3794,3243,3627,3670,3622,2758,4007,3130,3835,3294,3964,3065,4468,3408,3933,3234,3789,3118,4634,3643,4211,3174,4155,3176,5512,4400,2792,1730,-3702,-4499,-5940,-6691,-4265,-5094,-4381,-5215,-4918,-5746,-4217,-4871,-4402,-4981,-4479,-5525,-3732,-4968,-4118,-4924,-4300,-5349,-3422,-5021,-3876,-4886,-4087,-4860,-2790,-4254,-5025,-4196,-10898,-4415,-13419,-4007,-12198,-4121,-11995,-4413,-12471,-3808,-11937,-3920,-11792,-4583,-12284,-3776,-12085,-3107,-11421,-3583,-11226,-3081,-11157,-2768,-10580,-3914,-10424,-3197,-11040,-1715,-9822,-5144,-6189,-11154,-4236,-13029,-5134,-11598,-5507,-10949,-4921,-11142,-4999,-11180,-4883,-11184,-4366,-11090,-4548,-10887,-4818,-10708,-4866,-10534,-5253,-10272,-5179,-9894,-4633,-10029,-4773,-10382,-4977,-8674,-4668,-5292,-4651,-3928,-4629,-4465,-4312,-3994,-4459,-3528,-4570,-4400,-4272,-4601,-4482,-4035,-4627,-4334,-4080,-4498,-4045,-3835,-4204,-3526,-3695,-3646,-4045,-4101,-4856,-4628,-3338,-3235,-673,-508,28,147,-453,-639,11,0,8,-2,7,0,7,-3,11,-8,15,-9,17,-6,17,-5,13,-3,7,0,3,0,-2,0,-4,0,-4,-2,-6,0,-14,-2,-17,-4,-8,0,-7,5,-17,7,-18,10,-7,18,-2,25,-3,27,0,31,4,34,4,34,8,36,8,37,2,36,4,34,8,28,3,15,0,11,0,12,-5,8,-4,10,0,23,-4,31,-8,30,-2,30,0,26,-6,22,-6,20,-12,15,-19,10,-10,13,-14,6,-43,-13,-43,-16,-9,-12,-10,-29,-42,-40,-37,-28,-5,-21,1,-24,-8,-20,4,-18,26,-24,44,-26,66,-30,86,-37,88,-41,72,-46,50,-31,28,23,14,64,16,51,26,32,34,39,42,48,35,58,0,72,-36,69,-59,58,-98,54,-124,36,-103,12,-110,5,-173,-19,-146,-59,-4,-42,51,1,-23,-6,-30,-6,45,46,47,70,6,55,19,60,38,62,42,47,61,46,40,42,-19,22,-34,6,-35,-50,-61,-141,-37,-171,17,-163,26,-180,46,-154,80,-63,48,-4,18,20,50,47,58,53,44,61,57,85,37,80,0,86,-8,106,-95,49,-213,-8,-131,47,49,63,40,-39,-69,-74,-37,-20,63,-12,58,-14,-12,25,-31,41,11,45,76,47,167,5,261,-37,277,-83,183,-172,35,-122,-79,138,-70,266,69,124,228,0,391,-29,594,-84,702,-78,627,-8,551,-13,509,13,372,120,352,125,622,127,691,223,362,126,386,-33,915,198,958,457,456,298,500,233,1027,469,1096,426,918,160,1067,141,1220,189,1245,164,1375,297,1378,503,1299,702,1550,929,1799,855,1752,547,1830,602,1928,832,1736,796,1735,933,1961,1385,1935,1562,2105,1485,2716,1449,2948,1305,2768,1205,2716,1346,2531,1450,2470,1653,3117,2111,3370,2176,2696,1947,2925,2305,3846,2658,2425,2184,-877,1981,-2261,2623,-1645,2908,-1876,2732,-2704,2953,-2484,3116,-2120,2954,-2442,3216,-2466,3499,-2192,3234,-2392,3361,-2497,3869,-2078,3772,-1858,3915,-2066,4438,-2285,2934,-2294,-280,-2066,-1762,-1992,-1412,-2298,-1535,-2399,-1789,-2223,-1419,-2244,-1334,-2092,-1476,-1777,-1396,-2014,-1571,-2199,-1574,-1843,-1167,-1910,-1446,-2007,-1818,-1506,-1331,-2526,-2048,-5535,-4573,-7148,-5828,-6422,-5327,-5840,-5488,-5992,-6144,-6014,-6164,-6109,-6234,-6271,-6388,-6288,-6156,-6517,-6249,-6794,-6602,-6822,-6418,-6788,-6245,-6490,-6560,-6394,-6794,-7920,-6937,-10397,-7140,-11428,-6972,-11019,-6610,-11141,-6665,-11913,-7046,-11979,-7235,-11599,-7015,-11854,-6912,-12161,-7441,-12136,-7761,-12861,-7292,-13390,-7254,-12345,-7809,-12490,-7463,-13983,-6969,-10489,-8465,-2382,-11054,1272,-12247,-270,-12060,-323,-12113,502,-12486,-697,-12251,-1086,-12141,-181,-13116,-670,-13509,-1173,-12592,-443,-12811,-449,-13698,-934,-12850,-747,-13083,-873,-15036,-1161,-11478,-1047,-2669,-1407,1006,-1658,-1146,-1195,-1297,-1421,-73,-1946,-977,-1590,-1499,-1577,-1010,-1862,-1256,-1389,-962,-1692,-509,-2613,-1317,-2087,-1359,-1997,-1034,-2891,-2024,-119,-84,5651,5723,8074,8306,7156,6870,6985,7106,7312,8403,7114,8096,7173,7848,7082,7827,6761,7189,6985,7368]}"#; + +use serde::Deserialize; + +#[derive(Deserialize)] +struct DeriveStruct { + buffer: Vec, +} + +fn main() { + let info: DeriveStruct = serde_json::from_str(JSON).unwrap(); + println!("{}", info.buffer.len()); +} From c54d7eef07f91d64665c1ed673ce5c535ce023d9 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 7 Jan 2019 19:41:18 +0100 Subject: [PATCH 0532/3747] expand docs --- src/range_map.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/range_map.rs b/src/range_map.rs index 48cbc57f0ebce..80fc98a86965d 100644 --- a/src/range_map.rs +++ b/src/range_map.rs @@ -117,6 +117,7 @@ impl RangeMap { /// Provide mutable iteration over everything in the given range. As a side-effect, /// this will split entries in the map that are only partially hit by the given range, /// to make sure that when they are mutated, the effect is constrained to the given range. + /// Moreover, this will opportunistically merge neighbouring equal blocks. pub fn iter_mut<'a>( &'a mut self, offset: Size, From a13b6f183b519025fe181fd4d1230287d34b1f3e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 7 Jan 2019 22:57:05 +0100 Subject: [PATCH 0533/3747] make MSE bench run a bit longer (less noise) --- bench-cargo-miri/mse/src/main.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/bench-cargo-miri/mse/src/main.rs b/bench-cargo-miri/mse/src/main.rs index 7d00a623468ed..696de93442ed1 100644 --- a/bench-cargo-miri/mse/src/main.rs +++ b/bench-cargo-miri/mse/src/main.rs @@ -2,7 +2,9 @@ static EXPECTED: &[u8] = &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, static PCM: &[i16] = &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, -2, 0, -2, 0, -2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 1, 0, 1, 0, 0, -2, 0, -2, 0, -2, 0, -2, -2, -2, -3, -3, -3, -3, -4, -2, -5, -2, -5, -2, -4, 0, -4, 0, -4, 0, -4, 1, -4, 1, -4, 2, -4, 2, -4, 2, -4, 2, -4, 2, -3, 1, -4, 0, -4, 0, -5, 0, -5, 0, -5, 0, -4, 2, -4, 3, -4, 4, -3, 5, -2, 5, -3, 6, -3, 6, -3, 5, -3, 5, -2, 4, -2, 3, -5, 0, -6, 0, -3, -2, -4, -4, -9, -5, -9, -4, -4, -2, -4, -2, -4, 0, -2, 1, 1, 1, 4, 2, 8, 2, 12, 1, 13, 0, 12, 0, 11, 0, 8, -2, 7, 0, 7, -3, 11, -8, 15, -9, 17, -6, 17, -5, 13, -3, 7, 0, 3, 0, -2, 0, -4, 0, -4, -2, -6, 0, -14, -2, -17, -4, -8, 0, -7, 5, -17, 7, -18, 10, -7, 18, -2, 25, -3, 27, 0, 31, 4, 34, 4, 34, 8, 36, 8, 37, 2, 36, 4, 34, 8, 28, 3, 15, 0, 11, 0, 12, -5, 8, -4, 10, 0, 23, -4, 31, -8, 30, -2, 30, 0, 26, -6, 22, -6, 20, -12, 15, -19, 10, -10, 13, -14, 6, -43, -13, -43, -16, -9, -12, -10, -29, -42, -40, -37, -28, -5, -21, 1, -24, -8, -20, 4, -18, 26, -24, 44, -26, 66, -30, 86, -37, 88, -41, 72, -46, 50, -31, 28, 23, 14, 64, 16, 51, 26, 32, 34, 39, 42, 48, 35, 58, 0, 72, -36, 69, -59, 58, -98, 54, -124, 36, -103, 12, -110, 5, -173, -19, -146, -59, -4, -42, 51, 1, -23, -6, -30, -6, 45, 46, 47, 70, 6, 55, 19, 60, 38, 62, 42, 47, 61, 46, 40, 42, -19, 22, -34, 6, -35, -50, -61, -141, -37, -171, 17, -163, 26, -180, 46, -154, 80, -63, 48, -4, 18, 20, 50, 47, 58, 53, 44, 61, 57, 85, 37, 80, 0, 86, -8, 106, -95, 49, -213, -8, -131, 47, 49, 63, 40, -39, -69, -74, -37, -20, 63, -12, 58, -14, -12, 25, -31, 41, 11, 45, 76, 47, 167, 5, 261, -37, 277, -83, 183, -172, 35, -122, -79, 138, -70, 266, 69, 124, 228, 0, 391, -29, 594, -84, 702, -78, 627, -8, 551, -13, 509, 13, 372, 120, 352, 125, 622, 127, 691, 223, 362, 126, 386, -33, 915, 198, 958, 457, 456, 298, 500, 233, 1027, 469, 1096, 426, 918, 160, 1067, 141, 1220, 189, 1245, 164, 1375, 297, 1378, 503, 1299, 702, 1550, 929, 1799, 855, 1752, 547, 1830, 602, 1928, 832, 1736, 796, 1735, 933, 1961, 1385, 1935, 1562, 2105, 1485, 2716, 1449, 2948, 1305, 2768, 1205, 2716, 1346, 2531, 1450, 2470, 1653, 3117, 2111, 3370, 2176, 2696, 1947, 2925, 2305, 3846, 2658, 2425, 2184, -877, 1981, -2261, 2623, -1645, 2908, -1876, 2732, -2704, 2953, -2484, 3116, -2120, 2954, -2442, 3216, -2466, 3499, -2192, 3234, -2392, 3361, -2497, 3869, -2078, 3772, -1858, 3915, -2066, 4438, -2285, 2934, -2294, -280, -2066, -1762, -1992, -1412, -2298, -1535, -2399, -1789, -2223, -1419, -2244, -1334, -2092, -1476, -1777, -1396, -2014, -1571, -2199, -1574, -1843, -1167, -1910, -1446, -2007, -1818]; fn main() { + for i in 0..5 { mse(PCM.len(), PCM, EXPECTED); + } } fn read_i16(buffer: &[u8], index: usize) -> i16 { From 9c1c407a02b6d465f3b583760657d355f75b2b94 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Mon, 21 Jan 2019 17:29:09 +0100 Subject: [PATCH 0534/3747] Update to latest rustc master --- benches/helpers/miri_helper.rs | 4 ++-- src/bin/miri-rustc-tests.rs | 4 ++-- src/bin/miri.rs | 5 +++-- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/benches/helpers/miri_helper.rs b/benches/helpers/miri_helper.rs index c7df34eaf706d..a34e137694cba 100644 --- a/benches/helpers/miri_helper.rs +++ b/benches/helpers/miri_helper.rs @@ -6,6 +6,7 @@ extern crate test; use self::miri::eval_main; use self::rustc_driver::{driver, Compilation}; +use rustc::hir::def_id::LOCAL_CRATE; use std::cell::RefCell; use std::rc::Rc; use crate::test::Bencher; @@ -44,10 +45,9 @@ pub fn run(filename: &str, bencher: &mut Bencher) { state.session.abort_if_errors(); let tcx = state.tcx.unwrap(); - let (entry_node_id, _, _) = state.session.entry_fn.borrow().expect( + let (entry_def_id, _) = tcx.entry_fn(LOCAL_CRATE).expect( "no main or start function found", ); - let entry_def_id = tcx.hir().local_def_id(entry_node_id); bencher.borrow_mut().iter(|| { eval_main(tcx, entry_def_id, false); diff --git a/src/bin/miri-rustc-tests.rs b/src/bin/miri-rustc-tests.rs index 92d4237146dcf..45902dc6722f3 100644 --- a/src/bin/miri-rustc-tests.rs +++ b/src/bin/miri-rustc-tests.rs @@ -23,6 +23,7 @@ use rustc::hir::{self, itemlikevisit}; use rustc_codegen_utils::codegen_backend::CodegenBackend; use rustc::ty::TyCtxt; use syntax::ast; +use rustc::hir::def_id::LOCAL_CRATE; struct MiriCompilerCalls { default: Box, @@ -104,8 +105,7 @@ fn after_analysis<'a, 'tcx>(state: &mut CompileState<'a, 'tcx>) { fn visit_impl_item(&mut self, _impl_item: &'hir hir::ImplItem) {} } state.hir_crate.unwrap().visit_all_item_likes(&mut Visitor(tcx, state)); - } else if let Some((entry_node_id, _, _)) = *state.session.entry_fn.borrow() { - let entry_def_id = tcx.hir().local_def_id(entry_node_id); + } else if let Some((entry_def_id, _)) = tcx.entry_fn(LOCAL_CRATE) { miri::eval_main(tcx, entry_def_id, /*validate*/true); state.session.abort_if_errors(); diff --git a/src/bin/miri.rs b/src/bin/miri.rs index d8d7cfe0702e5..acfc429ed805c 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -24,6 +24,7 @@ use rustc_driver::{Compilation, CompilerCalls, RustcDefaultCalls}; use rustc_driver::driver::{CompileState, CompileController}; use rustc::session::config::{self, Input, ErrorOutputType}; use rustc_codegen_utils::codegen_backend::CodegenBackend; +use rustc::hir::def_id::LOCAL_CRATE; use syntax::ast; struct MiriCompilerCalls { @@ -113,8 +114,8 @@ fn after_analysis<'a, 'tcx>( let tcx = state.tcx.unwrap(); - let (entry_node_id, _, _) = state.session.entry_fn.borrow().expect("no main function found!"); - let entry_def_id = tcx.hir().local_def_id(entry_node_id); + + let (entry_def_id, _) = tcx.entry_fn(LOCAL_CRATE).expect("no main function found!"); miri::eval_main(tcx, entry_def_id, validate); From 6943ba8a633d0437a3e60c3d4dcdc07ab218c18d Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Mon, 21 Jan 2019 17:43:11 +0100 Subject: [PATCH 0535/3747] Bump version file --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index a2909dd32898c..a34ac2b252162 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -nightly-2018-12-26 +nightly-2019-01-21 From 7269a884c91d539c6e6ec275a6d9ef6d6bd5f142 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Tue, 22 Jan 2019 16:46:05 +0100 Subject: [PATCH 0536/3747] Expose `AllocId`s for priroda --- src/mono_hash_map.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/mono_hash_map.rs b/src/mono_hash_map.rs index 278bbd9cf2b13..56d6e1400f3ea 100644 --- a/src/mono_hash_map.rs +++ b/src/mono_hash_map.rs @@ -18,8 +18,11 @@ use crate::AllocMap; pub struct MonoHashMap(RefCell>>); impl MonoHashMap { - pub fn values(&self, f: impl FnOnce(&mut dyn Iterator) -> T) -> T { - f(&mut self.0.borrow().values().map(|v| &**v)) + /// This function exists for priroda to be able to iterate over all evaluator memory + /// + /// The memory of constants does not show up in this list. + pub fn iter(&self, f: impl FnOnce(&mut dyn Iterator) -> T) -> T { + f(&mut self.0.borrow().iter().map(|(k, v)| (k, &**v))) } } From 9f06cdc87a450b486a5bfea209acf958de92dfc8 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Tue, 22 Jan 2019 17:19:19 +0100 Subject: [PATCH 0537/3747] Explain Ref problems --- src/mono_hash_map.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/mono_hash_map.rs b/src/mono_hash_map.rs index 56d6e1400f3ea..ec1a5fdb4288f 100644 --- a/src/mono_hash_map.rs +++ b/src/mono_hash_map.rs @@ -20,7 +20,12 @@ pub struct MonoHashMap(RefCell>>); impl MonoHashMap { /// This function exists for priroda to be able to iterate over all evaluator memory /// - /// The memory of constants does not show up in this list. + /// The function is somewhat roundabout with the closure argument because internally the + /// `MonoHashMap` uses a `RefCell`. When iterating over the `HashMap` inside the `RefCell`, + /// we need to keep a borrow to the `HashMap` inside the iterator. The borrow is only alive + /// as long as the `Ref` returned by `RefCell::borrow()` is alive. So we can't return the + /// iterator, as that would drop the `Ref`. We can't return both, as it's not possible in Rust + /// to have a struct/tuple with a field that refers to another field. pub fn iter(&self, f: impl FnOnce(&mut dyn Iterator) -> T) -> T { f(&mut self.0.borrow().iter().map(|(k, v)| (k, &**v))) } From 76985f1e2d56fda022edee360b0deb5fdb7fb9f7 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 25 Jan 2019 08:59:12 +0100 Subject: [PATCH 0538/3747] remove outdated comment --- src/fn_call.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index 0f54295182399..720737b539650 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -73,10 +73,6 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, let tcx = &{this.tcx.tcx}; - // All these functions take raw pointers, so if we access memory directly - // (as opposed to through a place), we have to remember to erase any tag - // that might still hang around! - match &link_name[..] { "malloc" => { let size = this.read_scalar(args[0])?.to_usize(this)?; From f7519f36e67b6a9547670d6635a754465ad3c09f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 28 Jan 2019 09:19:56 +0100 Subject: [PATCH 0539/3747] fix tests to avoid deprecated constants --- tests/run-pass/atomic-access-bool.rs | 5 ++--- tests/run-pass/atomic-compare_exchange.rs | 5 ++--- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/tests/run-pass/atomic-access-bool.rs b/tests/run-pass/atomic-access-bool.rs index ada584705401f..8a3db796a087c 100644 --- a/tests/run-pass/atomic-access-bool.rs +++ b/tests/run-pass/atomic-access-bool.rs @@ -8,10 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::sync::atomic::{AtomicBool, ATOMIC_BOOL_INIT}; -use std::sync::atomic::Ordering::*; +use std::sync::atomic::{AtomicBool, Ordering::*}; -static mut ATOMIC: AtomicBool = ATOMIC_BOOL_INIT; +static mut ATOMIC: AtomicBool = AtomicBool::new(false); fn main() { unsafe { diff --git a/tests/run-pass/atomic-compare_exchange.rs b/tests/run-pass/atomic-compare_exchange.rs index ec8e16d33e42b..67280096073d8 100644 --- a/tests/run-pass/atomic-compare_exchange.rs +++ b/tests/run-pass/atomic-compare_exchange.rs @@ -8,10 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::sync::atomic::{AtomicIsize, ATOMIC_ISIZE_INIT}; -use std::sync::atomic::Ordering::*; +use std::sync::atomic::{AtomicIsize, Ordering::*}; -static ATOMIC: AtomicIsize = ATOMIC_ISIZE_INIT; +static ATOMIC: AtomicIsize = AtomicIsize::new(0); fn main() { // Make sure trans can emit all the intrinsics correctly From ce8cf6425e85b58840686cd1556f4ea537fc2bca Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 28 Jan 2019 09:20:06 +0100 Subject: [PATCH 0540/3747] bump Rust --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index a34ac2b252162..452bb5c2b97ff 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -nightly-2019-01-21 +nightly-2019-01-28 From 6b855573bd488cc11efb1f8cf1eeaf0f51327776 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 30 Jan 2019 11:51:06 +0100 Subject: [PATCH 0541/3747] fix generator test case --- tests/run-pass/generator.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tests/run-pass/generator.rs b/tests/run-pass/generator.rs index 603093a037c73..c9c114aacccae 100644 --- a/tests/run-pass/generator.rs +++ b/tests/run-pass/generator.rs @@ -11,12 +11,15 @@ #![feature(generators, generator_trait)] use std::ops::{GeneratorState, Generator}; +use std::pin::Pin; fn finish(mut amt: usize, mut t: T) -> T::Return where T: Generator { + // We are not moving the `t` around until it gets dropped, so this is okay. + let mut t = unsafe { Pin::new_unchecked(&mut t) }; loop { - match unsafe { t.resume() } { + match t.as_mut().resume() { GeneratorState::Yielded(y) => amt -= y, GeneratorState::Complete(ret) => { assert_eq!(amt, 0); From e827f7b2383adddaced2a9af404455224d7be6c0 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 30 Jan 2019 11:51:17 +0100 Subject: [PATCH 0542/3747] bump Rust --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 452bb5c2b97ff..0c7f46922122a 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -nightly-2019-01-28 +nightly-2019-01-30 From 35809441cd9fba2797982906b657a16b63e5aa29 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Wed, 30 Jan 2019 13:21:43 +0100 Subject: [PATCH 0543/3747] Try out more email notifications --- .travis.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.travis.yml b/.travis.yml index 51b14a1b345bf..ee58f73c36439 100644 --- a/.travis.yml +++ b/.travis.yml @@ -32,6 +32,9 @@ script: notifications: email: on_success: never + recipients: + - post+travis@ralfj.de + - travis-miri@oli-obk.de branches: only: - master From 7dbd23626e2df2b129a31bc341d029bbf4439a70 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 5 Feb 2019 15:03:11 +0100 Subject: [PATCH 0544/3747] update development instructions in README --- README.md | 36 +++++++++++++++++++++++++++--------- 1 file changed, 27 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index c6dd0d8b06c60..c7e7cb8c4a557 100644 --- a/README.md +++ b/README.md @@ -85,27 +85,45 @@ find useful. ### Using a nightly rustc -miri heavily relies on internal rustc interfaces to execute MIR. Still, some +Miri heavily relies on internal rustc interfaces to execute MIR. Still, some things (like adding support for a new intrinsic) can be done by working just on -the miri side. +the Miri side. -To prepare, make sure you are using a nightly Rust compiler. You also need to -set up a libstd that enables execution with Miri: +To prepare, make sure you are using a nightly Rust compiler. The most +convenient way is to install Miri using cargo, then you can easily run it on +other projects: ```sh -rustup override set nightly # or the nightly in `rust-version` -cargo run --bin cargo-miri -- miri setup +cargo +nightly install --path "$DIR" --force # or the nightly in `rust-version` +cargo +nightly miri setup ``` -The last command should end in printing the directory where the libstd was -built. Set that as your `MIRI_SYSROOT` environment variable: +If you want to use a different libstd (not the one that comes with the +nightly), you can do that by running ```sh -export MIRI_SYSROOT=~/.cache/miri/HOST # or whatever the previous command said +XARGO_RUST_SRC=~/src/rust/rustc/src/ cargo +nightly miri setup ``` +Either way, you can now do `cargo +nightly miri run` to run Miri with your +local changes on whatever project you are debugging. + +(We are giving `+nightly` explicitly here all the time because it is important +that all of these commands get executed with the same toolchain.) + ### Testing Miri +Instead of running an entire project using `cargo miri`, you can also use the +Miri "driver" directly to run just a single file. That can be easier during +debugging. + +`cargo miri setup` should end in printing the directory where the libstd was +built. Set that as your `MIRI_SYSROOT` environment variable: + +```sh +export MIRI_SYSROOT=~/.cache/miri/HOST # or whatever the previous command said +``` + Now you can run Miri directly, without going through `cargo miri`: ```sh From f3becd810eead697d31c5d73624d16996160efa6 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 5 Feb 2019 21:35:15 +0100 Subject: [PATCH 0545/3747] explain how to run cargo miri with a locally compiled rustc --- README.md | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index c7e7cb8c4a557..46a46b3e7a800 100644 --- a/README.md +++ b/README.md @@ -111,20 +111,19 @@ local changes on whatever project you are debugging. (We are giving `+nightly` explicitly here all the time because it is important that all of these commands get executed with the same toolchain.) -### Testing Miri - -Instead of running an entire project using `cargo miri`, you can also use the -Miri "driver" directly to run just a single file. That can be easier during -debugging. - `cargo miri setup` should end in printing the directory where the libstd was -built. Set that as your `MIRI_SYSROOT` environment variable: +built. For the next step to work, set that as your `MIRI_SYSROOT` environment +variable: ```sh export MIRI_SYSROOT=~/.cache/miri/HOST # or whatever the previous command said ``` -Now you can run Miri directly, without going through `cargo miri`: +### Testing Miri + +Instead of running an entire project using `cargo miri`, you can also use the +Miri "driver" directly to run just a single file. That can be easier during +debugging. ```sh cargo run tests/run-pass/format.rs # or whatever test you like @@ -186,6 +185,15 @@ rustup override set custom With this, you should now have a working development setup! See ["Testing Miri"](#testing-miri) above for how to proceed. +Running `cargo miri` in this setup is a bit more complicated, because the Miri +binary you just created does not actually run without some enviroment variables. +But you can contort cargo into calling `cargo miri` the right way for you: + +```sh +# in some other project's directory, to run `cargo miri test`: +MIRI_SYSROOT=$(rustc +custom --print sysroot) cargo +custom run --manifest-path /path/to/miri/Cargo.toml --bin cargo-miri --release -- miri test +``` + ### Miri `-Z` flags and environment variables Several `-Z` flags are relevant for Miri: From 661ed7b82dc7b9ab597a274f10055f58f9db6f4b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 6 Feb 2019 11:38:40 +0100 Subject: [PATCH 0546/3747] implement atomic_nand --- src/intrinsic.rs | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/src/intrinsic.rs b/src/intrinsic.rs index 0ef847236418c..b7c5d8d07c255 100644 --- a/src/intrinsic.rs +++ b/src/intrinsic.rs @@ -108,6 +108,11 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, "atomic_and_rel" | "atomic_and_acqrel" | "atomic_and_relaxed" | + "atomic_nand" | + "atomic_nand_acq" | + "atomic_nand_rel" | + "atomic_nand_acqrel" | + "atomic_nand_relaxed" | "atomic_xadd" | "atomic_xadd_acq" | "atomic_xadd_rel" | @@ -125,16 +130,23 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, let rhs = this.read_immediate(args[1])?; let old = this.read_immediate(ptr.into())?; this.write_immediate(*old, dest)?; // old value is returned - let op = match intrinsic_name.split('_').nth(1).unwrap() { - "or" => mir::BinOp::BitOr, - "xor" => mir::BinOp::BitXor, - "and" => mir::BinOp::BitAnd, - "xadd" => mir::BinOp::Add, - "xsub" => mir::BinOp::Sub, + let (op, neg) = match intrinsic_name.split('_').nth(1).unwrap() { + "or" => (mir::BinOp::BitOr, false), + "xor" => (mir::BinOp::BitXor, false), + "and" => (mir::BinOp::BitAnd, false), + "xadd" => (mir::BinOp::Add, false), + "xsub" => (mir::BinOp::Sub, false), + "nand" => (mir::BinOp::BitAnd, true), _ => bug!(), }; // Atomics wrap around on overflow. - this.binop_ignore_overflow(op, old, rhs, ptr.into())?; + let (val, _overflowed) = this.binary_op_imm(op, old, rhs)?; + let val = if neg { + this.unary_op(mir::UnOp::Not, val, old.layout)? + } else { + val + }; + this.write_scalar(val, ptr.into())?; } "breakpoint" => unimplemented!(), // halt miri From 48ac35f0727e1c660fa95012a941cf65de8b9443 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 6 Feb 2019 11:39:16 +0100 Subject: [PATCH 0547/3747] panic_impl is another way to panic --- src/fn_call.rs | 30 +++++++++++++--------- tests/compile-fail/{panic.rs => panic1.rs} | 2 +- tests/compile-fail/panic2.rs | 5 ++++ tests/compile-fail/panic3.rs | 5 ++++ tests/compile-fail/panic4.rs | 5 ++++ 5 files changed, 34 insertions(+), 13 deletions(-) rename tests/compile-fail/{panic.rs => panic1.rs} (60%) create mode 100644 tests/compile-fail/panic2.rs create mode 100644 tests/compile-fail/panic3.rs create mode 100644 tests/compile-fail/panic4.rs diff --git a/src/fn_call.rs b/src/fn_call.rs index 720737b539650..abb239ad7d627 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -39,12 +39,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, if this.tcx.is_foreign_item(instance.def_id()) { // An external function that we cannot find MIR for, but we can still run enough // of them to make miri viable. - this.emulate_foreign_item( - instance.def_id(), - args, - dest.unwrap(), - ret.unwrap(), - )?; + this.emulate_foreign_item(instance.def_id(), args, dest, ret)?; // `goto_block` already handled return Ok(None); } @@ -59,8 +54,8 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, &mut self, def_id: DefId, args: &[OpTy<'tcx, Borrow>], - dest: PlaceTy<'tcx, Borrow>, - ret: mir::BasicBlock, + dest: Option>, + ret: Option, ) -> EvalResult<'tcx> { let this = self.eval_context_mut(); let attrs = this.tcx.get_attrs(def_id); @@ -70,9 +65,23 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, }; // Strip linker suffixes (seen on 32bit macOS) let link_name = link_name.trim_end_matches("$UNIX2003"); - let tcx = &{this.tcx.tcx}; + // first: functions that could diverge + match &link_name[..] { + "__rust_start_panic" | "panic_impl" => { + return err!(MachineError("the evaluated program panicked".to_string())); + } + _ => if dest.is_none() { + return err!(Unimplemented( + format!("can't call diverging foreign function: {}", link_name), + )); + } + } + + // now: functions that assume a ret and dest + let dest = dest.expect("we already checked for a dest"); + let ret = ret.expect("dest is Some but ret is None"); match &link_name[..] { "malloc" => { let size = this.read_scalar(args[0])?.to_usize(this)?; @@ -245,9 +254,6 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, return Ok(()); } - "__rust_start_panic" => - return err!(MachineError("the evaluated program panicked".to_string())), - "memcmp" => { let left = this.read_scalar(args[0])?.not_undef()?; let right = this.read_scalar(args[1])?.not_undef()?; diff --git a/tests/compile-fail/panic.rs b/tests/compile-fail/panic1.rs similarity index 60% rename from tests/compile-fail/panic.rs rename to tests/compile-fail/panic1.rs index 0d594f9bd4c3b..1163c8708287c 100644 --- a/tests/compile-fail/panic.rs +++ b/tests/compile-fail/panic1.rs @@ -1,5 +1,5 @@ //error-pattern: the evaluated program panicked fn main() { - assert_eq!(5, 6); + std::panic!("panicking from libstd"); } diff --git a/tests/compile-fail/panic2.rs b/tests/compile-fail/panic2.rs new file mode 100644 index 0000000000000..e643e69224139 --- /dev/null +++ b/tests/compile-fail/panic2.rs @@ -0,0 +1,5 @@ +//error-pattern: the evaluated program panicked + +fn main() { + std::panic!("{}-panicking from libstd", 42); +} diff --git a/tests/compile-fail/panic3.rs b/tests/compile-fail/panic3.rs new file mode 100644 index 0000000000000..b22f95d9c69d1 --- /dev/null +++ b/tests/compile-fail/panic3.rs @@ -0,0 +1,5 @@ +//error-pattern: the evaluated program panicked + +fn main() { + core::panic!("panicking from libcore"); +} diff --git a/tests/compile-fail/panic4.rs b/tests/compile-fail/panic4.rs new file mode 100644 index 0000000000000..449e716e161cf --- /dev/null +++ b/tests/compile-fail/panic4.rs @@ -0,0 +1,5 @@ +//error-pattern: the evaluated program panicked + +fn main() { + core::panic!("{}-panicking from libcore", 42); +} From e5972c38a3322e8ab98aead64d75f63fe4c7c75d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 6 Feb 2019 11:47:32 +0100 Subject: [PATCH 0548/3747] test mutable string slice indexing --- tests/run-pass/strings.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tests/run-pass/strings.rs b/tests/run-pass/strings.rs index d5fc80b41f012..fa692ba3de1be 100644 --- a/tests/run-pass/strings.rs +++ b/tests/run-pass/strings.rs @@ -18,10 +18,17 @@ fn fat_pointer_on_32_bit() { Some(5).expect("foo"); } +fn str_indexing() { + let mut x = "Hello".to_string(); + let _v = &mut x[..3]; // Test IndexMut on String. +} + fn main() { assert_eq!(empty(), ""); assert_eq!(hello(), "Hello, world!"); assert_eq!(hello_bytes(), b"Hello, world!"); assert_eq!(hello_bytes_fat(), b"Hello, world!"); + fat_pointer_on_32_bit(); // Should run without crashing. + str_indexing(); } From e36a90de98b77bc3dccaa2910206ab15581c1755 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 7 Feb 2019 12:59:35 +0100 Subject: [PATCH 0549/3747] make release builds have debug info --- Cargo.toml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Cargo.toml b/Cargo.toml index 5e78661c2196f..16b5b2361bd4c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -55,3 +55,6 @@ rustc_tests = [] [dev-dependencies] compiletest_rs = { version = "0.3.17", features = ["tmp"] } colored = "1.6" + +[profile.release] +debug = true From 4309539efe85b03ae34076372327ae80c9b81552 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 7 Feb 2019 13:00:27 +0100 Subject: [PATCH 0550/3747] cargo miri: refactor how we detect what to interpret and how we run cargo rustc, fix running unit tests --- src/bin/cargo-miri.rs | 344 +++++++++++++++++++++--------------------- src/lib.rs | 2 +- 2 files changed, 176 insertions(+), 170 deletions(-) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 21cc7ee0e398e..b952aeea2f7f4 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -7,10 +7,10 @@ use std::io::{self, Write, BufRead}; use std::process::Command; use std::fs::{self, File}; -const CARGO_MIRI_HELP: &str = r#"Interprets bin crates +const CARGO_MIRI_HELP: &str = r#"Interprets bin crates and runs test suites Usage: - cargo miri [subcommand] [options] [--] [...] + cargo miri [subcommand] [options] [--] [...] Subcommands: run Run binaries (default) @@ -22,12 +22,13 @@ Common options: --features Features to compile for the package -V, --version Print version info and exit -Other options are the same as `cargo rustc`. +Other [options] are the same as `cargo rustc`. Everything after the "--" is +passed verbatim to Miri. -The feature `cargo-miri` is automatically defined for convenience. You can use +The config flag `miri` is automatically defined for convenience. You can use it to configure the resource limits - #![cfg_attr(feature = "cargo-miri", memory_size = 42)] + #![cfg_attr(miri, memory_size = 42)] available resource limits are `memory_size`, `step_limit`, `stack_limit` "#; @@ -53,23 +54,32 @@ fn show_error(msg: String) -> ! { std::process::exit(1) } +// Determines whether a --flag is present +fn has_arg_flag(name: &str) -> bool { + let mut args = std::env::args().take_while(|val| val != "--"); + args.any(|val| val == name) +} + +/// Gets the value of a --flag fn get_arg_flag_value(name: &str) -> Option { // stop searching at `--` - let mut args = std::env::args().skip_while(|val| !(val.starts_with(name) || val == "--")); - - match args.next() { - Some(ref p) if p == "--" => None, - Some(ref p) if p == name => args.next(), - Some(p) => { - // Make sure this really starts with `$name=`, we didn't test for the `=` yet. - let v = &p[name.len()..]; // strip leading `$name` - if v.starts_with('=') { - Some(v[1..].to_owned()) // strip leading `=` - } else { - None - } - }, - None => None, + let mut args = std::env::args().take_while(|val| val != "--"); + loop { + let arg = match args.next() { + Some(arg) => arg, + None => return None, + }; + if !arg.starts_with(name) { + continue; + } + let suffix = &arg[name.len()..]; // strip leading `name` + if suffix.is_empty() { + // This argument is exactly `name`, the next one is the value + return args.next(); + } else if suffix.starts_with('=') { + // This argument is `name=value`, get the value + return Some(suffix[1..].to_owned()); // strip leading `=` + } } } @@ -272,167 +282,163 @@ fn main() { // each applicable target, but with the RUSTC env var set to the `cargo-miri` // binary so that we come back in the other branch, and dispatch // the invocations to rustc and miri, respectively. - - let (subcommand, skip) = match std::env::args().nth(2).deref() { - Some("test") => (MiriCommand::Test, 3), - Some("run") => (MiriCommand::Run, 3), - Some("setup") => (MiriCommand::Setup, 3), - // Default command, if there is an option or nothing - Some(s) if s.starts_with("-") => (MiriCommand::Run, 2), - None => (MiriCommand::Run, 2), - // Unvalid command - Some(s) => { - show_error(format!("Unknown command `{}`", s)) - } - }; - - // We always setup - let ask = subcommand != MiriCommand::Setup; - setup(ask); - if subcommand == MiriCommand::Setup { - // Stop here. - return; - } - - // Now run the command. - for target in list_targets() { - let args = std::env::args().skip(skip); - let kind = target.kind.get(0).expect( - "badly formatted cargo metadata: target::kind is an empty array", - ); - match (subcommand, &kind[..]) { - (MiriCommand::Test, "test") => { - // For test binaries we call `cargo rustc --test target -- ` - if let Err(code) = process( - vec!["--test".to_string(), target.name].into_iter().chain( - args, - ), - ) - { - std::process::exit(code); - } - } - (MiriCommand::Test, "lib") => { - // For libraries we call `cargo rustc -- --test ` - // Notice now that `--test` is a rustc arg rather than a cargo arg. This tells - // rustc to build a test harness which calls all #[test] functions. - // We then execute that harness just like any other binary. - if let Err(code) = process( - vec!["--".to_string(), "--test".to_string()].into_iter().chain( - args, - ), - ) - { - std::process::exit(code); - } - } - (MiriCommand::Run, "bin") => { - // For ordinary binaries we call `cargo rustc --bin target -- ` - if let Err(code) = process( - vec!["--bin".to_string(), target.name].into_iter().chain( - args, - ), - ) - { - std::process::exit(code); - } - } - _ => {} - } - } + in_cargo_miri(); } else if let Some("rustc") = std::env::args().nth(1).as_ref().map(AsRef::as_ref) { // This arm is executed when cargo-miri runs `cargo rustc` with the `RUSTC_WRAPPER` env var set to itself: // Dependencies get dispatched to rustc, the final test/binary to miri. + inside_cargo_rustc(); + } else { + show_error(format!("Must be called with either `miri` or `rustc` as first argument.")) + } +} - let home = option_env!("RUSTUP_HOME").or(option_env!("MULTIRUST_HOME")); - let toolchain = option_env!("RUSTUP_TOOLCHAIN").or(option_env!("MULTIRUST_TOOLCHAIN")); - let sys_root = if let Ok(sysroot) = ::std::env::var("MIRI_SYSROOT") { - sysroot - } else if let (Some(home), Some(toolchain)) = (home, toolchain) { - format!("{}/toolchains/{}", home, toolchain) - } else { - option_env!("RUST_SYSROOT") - .map(|s| s.to_owned()) - .or_else(|| { - Command::new("rustc") - .arg("--print") - .arg("sysroot") - .output() - .ok() - .and_then(|out| String::from_utf8(out.stdout).ok()) - .map(|s| s.trim().to_owned()) - }) - .expect("need to specify RUST_SYSROOT env var during miri compilation, or use rustup or multirust") - }; +fn in_cargo_miri() { + let (subcommand, skip) = match std::env::args().nth(2).deref() { + Some("test") => (MiriCommand::Test, 3), + Some("run") => (MiriCommand::Run, 3), + Some("setup") => (MiriCommand::Setup, 3), + // Default command, if there is an option or nothing + Some(s) if s.starts_with("-") => (MiriCommand::Run, 2), + None => (MiriCommand::Run, 2), + // Unvalid command + Some(s) => { + show_error(format!("Unknown command `{}`", s)) + } + }; + let verbose = has_arg_flag("-v"); - // this conditional check for the --sysroot flag is there so users can call `cargo-miri` directly - // without having to pass --sysroot or anything - let rustc_args = std::env::args().skip(2); - let mut args: Vec = if std::env::args().any(|s| s == "--sysroot") { - rustc_args.collect() - } else { - rustc_args - .chain(Some("--sysroot".to_owned())) - .chain(Some(sys_root)) - .collect() - }; - args.splice(0..0, miri::miri_default_args().iter().map(ToString::to_string)); - args.extend_from_slice(&["--cfg".to_owned(), r#"feature="cargo-miri""#.to_owned()]); - - // this check ensures that dependencies are built but not interpreted and the final crate is - // interpreted but not built - let miri_enabled = std::env::args().any(|s| s == "--emit=dep-info,metadata"); - let mut command = if miri_enabled { - let mut path = std::env::current_exe().expect("current executable path invalid"); - path.set_file_name("miri"); - Command::new(path) - } else { - Command::new("rustc") - }; - command.args(&args); + // We always setup + let ask = subcommand != MiriCommand::Setup; + setup(ask); + if subcommand == MiriCommand::Setup { + // Stop here. + return; + } - match command.status() { - Ok(exit) => { - if !exit.success() { - std::process::exit(exit.code().unwrap_or(42)); - } + // Now run the command. + for target in list_targets() { + let mut args = std::env::args().skip(skip); + let kind = target.kind.get(0).expect( + "badly formatted cargo metadata: target::kind is an empty array", + ); + // Now we run `cargo rustc $FLAGS $ARGS`, giving the user the + // change to add additional flags. "FLAGS" is set to identify + // this target. The user gets to control what gets actually passed to Miri. + // However, we need to add a flag to what gets passed to rustc for the finaly + // binary, so that we know to interpret that with Miri. + // So after the first "--", we add "-Zcargo-miri-marker". + let mut cmd = Command::new("cargo"); + cmd.arg("rustc"); + match (subcommand, &kind[..]) { + (MiriCommand::Run, "bin") => { + // FIXME: We just run all the binaries here. + // We should instead support `cargo miri --bin foo`. + cmd.arg("--bin").arg(target.name); + } + (MiriCommand::Test, "test") => { + cmd.arg("--test").arg(target.name); } - Err(ref e) if miri_enabled => panic!("error during miri run: {:?}", e), - Err(ref e) => panic!("error during rustc call: {:?}", e), + (MiriCommand::Test, "lib") | + (MiriCommand::Test, "bin") => { + cmd.arg(format!("--{}", kind)).arg(target.name).arg("--profile").arg("test"); + } + // The remaining targets we do not even want to build + _ => continue, + } + // add user-defined args until first "--" + while let Some(arg) = args.next() { + if arg == "--" { + break; + } + cmd.arg(arg); + } + // add "--" "-Zcargo-miri-marker" and the remaining user flags + cmd + .arg("--") + .arg("cargo-miri-marker") + .args(args); + let path = std::env::current_exe().expect("current executable path invalid"); + cmd.env("RUSTC_WRAPPER", path); + if verbose { + eprintln!("+ {:?}", cmd); + } + + let exit_status = cmd + .spawn() + .expect("could not run cargo") + .wait() + .expect("failed to wait for cargo?"); + + if !exit_status.success() { + std::process::exit(exit_status.code().unwrap_or(-1)) } - } else { - show_error(format!("Must be called with either `miri` or `rustc` as first argument.")) } } -fn process(old_args: I) -> Result<(), i32> -where - I: Iterator, -{ - let mut args = vec!["rustc".to_owned()]; +fn inside_cargo_rustc() { + let home = option_env!("RUSTUP_HOME").or(option_env!("MULTIRUST_HOME")); + let toolchain = option_env!("RUSTUP_TOOLCHAIN").or(option_env!("MULTIRUST_TOOLCHAIN")); + let sys_root = if let Ok(sysroot) = ::std::env::var("MIRI_SYSROOT") { + sysroot + } else if let (Some(home), Some(toolchain)) = (home, toolchain) { + format!("{}/toolchains/{}", home, toolchain) + } else { + option_env!("RUST_SYSROOT") + .map(|s| s.to_owned()) + .or_else(|| { + Command::new("rustc") + .arg("--print") + .arg("sysroot") + .output() + .ok() + .and_then(|out| String::from_utf8(out.stdout).ok()) + .map(|s| s.trim().to_owned()) + }) + .expect("need to specify RUST_SYSROOT env var during miri compilation, or use rustup or multirust") + }; - let mut found_dashes = false; - for arg in old_args { - found_dashes |= arg == "--"; - args.push(arg); - } - if !found_dashes { - args.push("--".to_owned()); - } - args.push("--emit=dep-info,metadata".to_owned()); - - let path = std::env::current_exe().expect("current executable path invalid"); - let exit_status = Command::new("cargo") - .args(&args) - .env("RUSTC_WRAPPER", path) - .spawn() - .expect("could not run cargo") - .wait() - .expect("failed to wait for cargo?"); - - if exit_status.success() { - Ok(()) + // this conditional check for the --sysroot flag is there so users can call `cargo-miri` directly + // without having to pass --sysroot or anything + let rustc_args = std::env::args().skip(2); + let mut args: Vec = if std::env::args().any(|s| s == "--sysroot") { + rustc_args.collect() + } else { + rustc_args + .chain(Some("--sysroot".to_owned())) + .chain(Some(sys_root)) + .collect() + }; + args.splice(0..0, miri::miri_default_args().iter().map(ToString::to_string)); + + // see if we have cargo-miri-marker, which means we want to interpret this crate in Miri + // (and remove the marker). + let needs_miri = if let Some(pos) = args.iter().position(|arg| arg == "cargo-miri-marker") { + args.remove(pos); + true } else { - Err(exit_status.code().unwrap_or(-1)) + false + }; + + + let mut command = if needs_miri { + let mut path = std::env::current_exe().expect("current executable path invalid"); + path.set_file_name("miri"); + Command::new(path) + } else { + Command::new("rustc") + }; + command.args(&args); + if has_arg_flag("-v") { + eprintln!("+ {:?}", command); + } + + match command.status() { + Ok(exit) => { + if !exit.success() { + std::process::exit(exit.code().unwrap_or(42)); + } + } + Err(ref e) if needs_miri => panic!("error during miri run: {:?}", e), + Err(ref e) => panic!("error during rustc call: {:?}", e), } } diff --git a/src/lib.rs b/src/lib.rs index a8fd432282a10..4ff3e011c6ae5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -54,7 +54,7 @@ pub use crate::stacked_borrows::{Borrow, Stack, Stacks, BorStackItem}; pub fn miri_default_args() -> &'static [&'static str] { // The flags here should be kept in sync with what bootstrap adds when `test-miri` is // set, which happens in `bootstrap/bin/rustc.rs` in the rustc sources. - &["-Zalways-encode-mir", "-Zmir-emit-retag", "-Zmir-opt-level=0"] + &["-Zalways-encode-mir", "-Zmir-emit-retag", "-Zmir-opt-level=0", "--cfg=miri"] } // Used by priroda From 5766b328713410dc0bc8e2d349b569937fb79e50 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 7 Feb 2019 13:00:42 +0100 Subject: [PATCH 0551/3747] update test for cargo-miri --- src/bin/cargo-miri.rs | 2 +- test-cargo-miri/Cargo.lock | 197 ++++++++++++++++++++++ test-cargo-miri/Cargo.toml | 3 + test-cargo-miri/src/main.rs | 18 ++ test-cargo-miri/test.stdout.ref | 10 +- test-cargo-miri/tests/{foo.rs => test.rs} | 15 +- 6 files changed, 238 insertions(+), 7 deletions(-) rename test-cargo-miri/tests/{foo.rs => test.rs} (56%) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index b952aeea2f7f4..677c38d7c2954 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -7,7 +7,7 @@ use std::io::{self, Write, BufRead}; use std::process::Command; use std::fs::{self, File}; -const CARGO_MIRI_HELP: &str = r#"Interprets bin crates and runs test suites +const CARGO_MIRI_HELP: &str = r#"Interprets bin crates and tests in Miri Usage: cargo miri [subcommand] [options] [--] [...] diff --git a/test-cargo-miri/Cargo.lock b/test-cargo-miri/Cargo.lock index 85c3c08dba019..76fb04c6672aa 100644 --- a/test-cargo-miri/Cargo.lock +++ b/test-cargo-miri/Cargo.lock @@ -1,3 +1,15 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "autocfg" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "bitflags" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "byteorder" version = "1.0.0" @@ -8,7 +20,192 @@ name = "cargo-miri-test" version = "0.1.0" dependencies = [ "byteorder 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "cloudabi" +version = "0.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "fuchsia-cprng" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "libc" +version = "0.2.48" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "rand" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_jitter 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_os 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_pcg 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_chacha" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_core" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_core" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "rand_hc" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_isaac" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "rand_jitter" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_os" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_pcg" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_xorshift" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rdrand" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rustc_version" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "semver" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "semver-parser" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "winapi" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [metadata] +"checksum autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a6d640bee2da49f60a4068a7fae53acde8982514ab7bae8b8cea9e88cbcfd799" +"checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12" "checksum byteorder 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c40977b0ee6b9885c9013cd41d9feffdd22deb3bb4dc3a71d901cc7a77de18c8" +"checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" +"checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" +"checksum libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)" = "e962c7641008ac010fa60a7dfdc1712449f29c44ef2d4702394aea943ee75047" +"checksum rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca" +"checksum rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef" +"checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" +"checksum rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d0e7a549d590831370895ab7ba4ea0c1b6b011d106b5ff2da6eee112615e6dc0" +"checksum rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b40677c7be09ae76218dc623efbf7b18e34bced3f38883af07bb75630a21bc4" +"checksum rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ded997c9d5f13925be2a6fd7e66bf1872597f759fd9dd93513dd7e92e5a5ee08" +"checksum rand_jitter 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "080723c6145e37503a2224f801f252e14ac5531cb450f4502698542d188cb3c0" +"checksum rand_os 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b7c690732391ae0abafced5015ffb53656abfaec61b342290e5eb56b286a679d" +"checksum rand_pcg 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "086bd09a33c7044e56bb44d5bdde5a60e7f119a9e95b0775f545de759a32fe05" +"checksum rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c" +"checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" +"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" +"checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" +"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" +"checksum winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "92c1eb33641e276cfa214a0522acad57be5c56b10cb348b3c5117db75f3ac4b0" +"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/test-cargo-miri/Cargo.toml b/test-cargo-miri/Cargo.toml index 4fe009e025e13..04f259a0aedba 100644 --- a/test-cargo-miri/Cargo.toml +++ b/test-cargo-miri/Cargo.toml @@ -6,3 +6,6 @@ edition = "2018" [dependencies] byteorder = "1.0" + +[dev-dependencies] +rand = "0.6.5" diff --git a/test-cargo-miri/src/main.rs b/test-cargo-miri/src/main.rs index 1ae88a7db5940..25e2cfdfa0368 100644 --- a/test-cargo-miri/src/main.rs +++ b/test-cargo-miri/src/main.rs @@ -1,3 +1,7 @@ +extern crate byteorder; +#[cfg(test)] +extern crate rand; + use byteorder::{BigEndian, ByteOrder}; fn main() { @@ -7,3 +11,17 @@ fn main() { println!("{:#010x}", n); eprintln!("standard error"); } + +#[cfg(test)] +mod test { + use rand::{Rng, SeedableRng}; + + // Make sure in-crate tests with dev-dependencies work + #[test] + fn rng() { + let mut rng = rand::rngs::StdRng::seed_from_u64(0xcafebeef); + let x: u32 = rng.gen(); + let y: u32 = rng.gen(); + assert_ne!(x, y); + } +} diff --git a/test-cargo-miri/test.stdout.ref b/test-cargo-miri/test.stdout.ref index 94fd56b0cd6f3..9c3621f21535b 100644 --- a/test-cargo-miri/test.stdout.ref +++ b/test-cargo-miri/test.stdout.ref @@ -1,7 +1,13 @@ +running 1 test +test test::rng ... ok + +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out + + running 2 tests -test bar ... ok -test baz ... ok +test rng ... ok +test simple ... ok test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out diff --git a/test-cargo-miri/tests/foo.rs b/test-cargo-miri/tests/test.rs similarity index 56% rename from test-cargo-miri/tests/foo.rs rename to test-cargo-miri/tests/test.rs index bd7b2c569a19b..e9faaf2fb2f19 100644 --- a/test-cargo-miri/tests/foo.rs +++ b/test-cargo-miri/tests/test.rs @@ -1,17 +1,24 @@ +extern crate rand; + +use rand::{Rng, SeedableRng}; + #[test] -fn bar() { +fn simple() { assert_eq!(4, 4); } // Having more than 1 test does seem to make a difference // (i.e., this calls ptr::swap which having just one test does not). #[test] -fn baz() { - assert_eq!(5, 5); +fn rng() { + let mut rng = rand::rngs::StdRng::seed_from_u64(0xdeadcafe); + let x: u32 = rng.gen(); + let y: u32 = rng.gen(); + assert_ne!(x, y); } // A test that won't work on miri -#[cfg(not(feature = "cargo-miri"))] +#[cfg(not(miri))] #[test] fn does_not_work_on_miri() { let x = 0u8; From 08180f07baca0ea1fdc7672eca7dfdee9f860851 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 7 Feb 2019 13:07:47 +0100 Subject: [PATCH 0552/3747] update docs --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 46a46b3e7a800..1d97b61f43d56 100644 --- a/README.md +++ b/README.md @@ -48,12 +48,12 @@ Now you can run your project in Miri: 3. If you have a binary project, you can run it through Miri using `cargo +nightly miri run`. -When running code via `cargo miri`, the `cargo-miri` feature is set. You can +When running code via `cargo miri`, the `miri` config flag is set. You can use this to exclude test cases that will fail under Miri because they do things Miri does not support: ```rust -#[cfg(not(feature = "cargo-miri"))] +#[cfg(not(miri))] #[test] fn does_not_work_on_miri() { let x = 0u8; From e0891bd619deaa7a7d91766710703f9fa631c059 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 7 Feb 2019 16:33:46 +0100 Subject: [PATCH 0553/3747] Fix cargo miri test on lib crates --- src/bin/cargo-miri.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 677c38d7c2954..9b97822b4754f 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -338,9 +338,12 @@ fn in_cargo_miri() { (MiriCommand::Test, "test") => { cmd.arg("--test").arg(target.name); } - (MiriCommand::Test, "lib") | + (MiriCommand::Test, "lib") => { + // There can be only one lib + cmd.arg("--lib").arg("--profile").arg("test"); + } (MiriCommand::Test, "bin") => { - cmd.arg(format!("--{}", kind)).arg(target.name).arg("--profile").arg("test"); + cmd.arg("--bin").arg(target.name).arg("--profile").arg("test"); } // The remaining targets we do not even want to build _ => continue, From 68e8ff1a097fa561a19eeb5d1f0328b8ef20cef4 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 7 Feb 2019 18:04:54 +0100 Subject: [PATCH 0554/3747] flush stdout/stderr to make sure it appears on the screen --- src/fn_call.rs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index abb239ad7d627..56cb386450908 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -390,10 +390,15 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, use std::io::{self, Write}; let buf_cont = this.memory().read_bytes(buf, Size::from_bytes(n))?; + // We need to flush to make sure this actually appears on the screen let res = if fd == 1 { - io::stdout().write(buf_cont) + let res = io::stdout().write(buf_cont); + io::stdout().flush().unwrap(); + res } else { - io::stderr().write(buf_cont) + let res = io::stderr().write(buf_cont); + io::stderr().flush().unwrap(); + res }; match res { Ok(n) => n as i64, From 7af75abdd79c4c72f7eea5d136b95dc882c705f1 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 8 Feb 2019 10:28:43 +0100 Subject: [PATCH 0555/3747] we don't need to flush stderr --- src/fn_call.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index 56cb386450908..a5708305a9762 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -392,13 +392,16 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, let buf_cont = this.memory().read_bytes(buf, Size::from_bytes(n))?; // We need to flush to make sure this actually appears on the screen let res = if fd == 1 { + // Stdout is buffered, flush to make sure it appears on the screen. + // This is the write() syscall of the interpreted program, we want it + // to correspond to a write() syscall on the host -- there is no good + // in adding extra buffering here. let res = io::stdout().write(buf_cont); io::stdout().flush().unwrap(); res } else { - let res = io::stderr().write(buf_cont); - io::stderr().flush().unwrap(); - res + // No need to flush, stderr is not buffered. + io::stderr().write(buf_cont) }; match res { Ok(n) => n as i64, From e747c65f8dbb898f4fad2e500cd2fe01d87fac1c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 8 Feb 2019 12:13:07 +0100 Subject: [PATCH 0556/3747] make bash more strict --- travis.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/travis.sh b/travis.sh index aded53b1579d6..8ec1d56ab7709 100755 --- a/travis.sh +++ b/travis.sh @@ -1,5 +1,5 @@ #!/bin/bash -set -e +set -euo pipefail # Determine configuration if [ "$TRAVIS_OS_NAME" == osx ]; then From 0f6e82db361b58d8332a1f793232cbe396d526c5 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 9 Feb 2019 13:07:55 +0100 Subject: [PATCH 0557/3747] fix (un)likely intrinsics --- src/intrinsic.rs | 8 +++++++- tests/run-pass/iter.rs | 40 ++++++++++++++++++++++++++++++++++++ tests/run-pass/iter_any.rs | 12 ----------- tests/run-pass/iter_slice.rs | 12 ----------- 4 files changed, 47 insertions(+), 25 deletions(-) create mode 100644 tests/run-pass/iter.rs delete mode 100644 tests/run-pass/iter_any.rs delete mode 100644 tests/run-pass/iter_slice.rs diff --git a/src/intrinsic.rs b/src/intrinsic.rs index b7c5d8d07c255..09df91b3ab388 100644 --- a/src/intrinsic.rs +++ b/src/intrinsic.rs @@ -245,7 +245,13 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, this.binop_ignore_overflow(mir::BinOp::Div, a, b, dest)?; }, - "likely" | "unlikely" | "forget" => {} + "forget" => {} + + "likely" | "unlikely" => { + // These just return their argument + let b = this.read_immediate(args[0])?; + this.write_immediate(*b, dest)?; + } "init" => { // Check fast path: we don't want to force an allocation in case the destination is a simple value, diff --git a/tests/run-pass/iter.rs b/tests/run-pass/iter.rs new file mode 100644 index 0000000000000..1bef21d83bda3 --- /dev/null +++ b/tests/run-pass/iter.rs @@ -0,0 +1,40 @@ +fn iter_empty_and_zst() { + for _ in Vec::::new().iter() { // this iterates over a Unique::empty() + panic!("We should never be here."); + } + + // Iterate over a ZST (uses arith_offset internally) + let mut count = 0; + for _ in &[(), (), ()] { + count += 1; + } + assert_eq!(count, 3); +} + +fn test_iterator_step_by_nth() { + let mut it = (0..16).step_by(5); + assert_eq!(it.nth(0), Some(0)); + assert_eq!(it.nth(0), Some(5)); + assert_eq!(it.nth(0), Some(10)); + assert_eq!(it.nth(0), Some(15)); + assert_eq!(it.nth(0), None); +} + +fn iter_any() { + let f = |x: &u8| { 10u8 == *x }; + f(&1u8); + + let g = |(), x: &u8| { 10u8 == *x }; + g((), &1u8); + + let h = |(), (), x: &u8| { 10u8 == *x }; + h((), (), &1u8); + + [1, 2, 3u8].into_iter().any(|elt| 10 == *elt); +} + +fn main() { + test_iterator_step_by_nth(); + iter_any(); + iter_empty_and_zst(); +} diff --git a/tests/run-pass/iter_any.rs b/tests/run-pass/iter_any.rs deleted file mode 100644 index b14eb074488b2..0000000000000 --- a/tests/run-pass/iter_any.rs +++ /dev/null @@ -1,12 +0,0 @@ -pub fn main() { - let f = |x: &u8| { 10u8 == *x }; - f(&1u8); - - let g = |(), x: &u8| { 10u8 == *x }; - g((), &1u8); - - let h = |(), (), x: &u8| { 10u8 == *x }; - h((), (), &1u8); - - [1, 2, 3u8].into_iter().any(|elt| 10 == *elt); -} diff --git a/tests/run-pass/iter_slice.rs b/tests/run-pass/iter_slice.rs deleted file mode 100644 index fd7229c3455e4..0000000000000 --- a/tests/run-pass/iter_slice.rs +++ /dev/null @@ -1,12 +0,0 @@ -fn main() { - for _ in Vec::::new().iter() { // this iterates over a Unique::empty() - panic!("We should never be here."); - } - - // Iterate over a ZST (uses arith_offset internally) - let mut count = 0; - for _ in &[(), (), ()] { - count += 1; - } - assert_eq!(count, 3); -} From 7827924bfc920bc171f3c68e25dc47065f5ae6e4 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 9 Feb 2019 15:52:59 +0100 Subject: [PATCH 0558/3747] test padding in format strings --- tests/run-pass/format.rs | 1 + tests/run-pass/format.stdout | 1 + 2 files changed, 2 insertions(+) diff --git a/tests/run-pass/format.rs b/tests/run-pass/format.rs index 78729b915613a..053cce36130c7 100644 --- a/tests/run-pass/format.rs +++ b/tests/run-pass/format.rs @@ -1,3 +1,4 @@ fn main() { println!("Hello {}", 13); + println!("{:0 Date: Fri, 8 Feb 2019 19:21:44 +0100 Subject: [PATCH 0559/3747] implement passing arguments to the interpreted program --- src/bin/miri.rs | 67 ++++++++++++++++++++++++------------- src/lib.rs | 46 +++++++++++++++++-------- test-cargo-miri/src/main.rs | 4 ++- test-cargo-miri/stderr.ref | 2 +- tests/run-pass/args.rs | 5 +++ tests/run-pass/args.stdout | 1 + 6 files changed, 85 insertions(+), 40 deletions(-) create mode 100644 tests/run-pass/args.rs create mode 100644 tests/run-pass/args.stdout diff --git a/src/bin/miri.rs b/src/bin/miri.rs index acfc429ed805c..31bd1deb10f57 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -27,11 +27,11 @@ use rustc_codegen_utils::codegen_backend::CodegenBackend; use rustc::hir::def_id::LOCAL_CRATE; use syntax::ast; +use miri::MiriConfig; + struct MiriCompilerCalls { default: Box, - - /// Whether to enforce the validity invariant. - validate: bool, + miri_config: MiriConfig, } impl<'a> CompilerCalls<'a> for MiriCompilerCalls { @@ -79,6 +79,8 @@ impl<'a> CompilerCalls<'a> for MiriCompilerCalls { odir: &Option, ofile: &Option, ) -> Compilation { + // Called *before* build_controller. Add filename to miri arguments. + self.miri_config.args.insert(0, input.filestem().to_string()); self.default.late_callback(codegen_backend, matches, sess, cstore, input, odir, ofile) } fn build_controller( @@ -89,9 +91,9 @@ impl<'a> CompilerCalls<'a> for MiriCompilerCalls { let this = *self; let mut control = this.default.build_controller(sess, matches); control.after_hir_lowering.callback = Box::new(after_hir_lowering); - let validate = this.validate; + let miri_config = this.miri_config; control.after_analysis.callback = - Box::new(move |state| after_analysis(state, validate)); + Box::new(move |state| after_analysis(state, miri_config.clone())); control.after_analysis.stop = Compilation::Stop; control } @@ -107,7 +109,7 @@ fn after_hir_lowering(state: &mut CompileState) { fn after_analysis<'a, 'tcx>( state: &mut CompileState<'a, 'tcx>, - validate: bool, + miri_config: MiriConfig, ) { init_late_loggers(); state.session.abort_if_errors(); @@ -117,7 +119,7 @@ fn after_analysis<'a, 'tcx>( let (entry_def_id, _) = tcx.entry_fn(LOCAL_CRATE).expect("no main function found!"); - miri::eval_main(tcx, entry_def_id, validate); + miri::eval_main(tcx, entry_def_id, miri_config); state.session.abort_if_errors(); } @@ -188,34 +190,51 @@ fn find_sysroot() -> String { fn main() { init_early_loggers(); - let mut args: Vec = std::env::args().collect(); - // Parse our own -Z flags and remove them before rustc gets their hand on them. + // Parse our arguments and split them across rustc and miri let mut validate = true; - args.retain(|arg| { - match arg.as_str() { - "-Zmiri-disable-validation" => { - validate = false; - false - }, - _ => true + let mut rustc_args = vec![]; + let mut miri_args = vec![]; + let mut after_dashdash = false; + for arg in std::env::args() { + if rustc_args.is_empty() { + // Very first arg: for rustc + rustc_args.push(arg); } - }); + else if after_dashdash { + // Everything that comes is Miri args + miri_args.push(arg); + } else { + match arg.as_str() { + "-Zmiri-disable-validation" => { + validate = false; + }, + "--" => { + after_dashdash = true; + } + _ => { + rustc_args.push(arg); + } + } + } + } // Determine sysroot and let rustc know about it let sysroot_flag = String::from("--sysroot"); - if !args.contains(&sysroot_flag) { - args.push(sysroot_flag); - args.push(find_sysroot()); + if !rustc_args.contains(&sysroot_flag) { + rustc_args.push(sysroot_flag); + rustc_args.push(find_sysroot()); } // Finally, add the default flags all the way in the beginning, but after the binary name. - args.splice(1..1, miri::miri_default_args().iter().map(ToString::to_string)); + rustc_args.splice(1..1, miri::miri_default_args().iter().map(ToString::to_string)); - trace!("rustc arguments: {:?}", args); + debug!("rustc arguments: {:?}", rustc_args); + debug!("miri arguments: {:?}", miri_args); + let miri_config = MiriConfig { validate, args: miri_args }; let result = rustc_driver::run(move || { - rustc_driver::run_compiler(&args, Box::new(MiriCompilerCalls { + rustc_driver::run_compiler(&rustc_args, Box::new(MiriCompilerCalls { default: Box::new(RustcDefaultCalls), - validate, + miri_config, }), None, None) }); std::process::exit(result as i32); diff --git a/src/lib.rs b/src/lib.rs index 4ff3e011c6ae5..49c39201d006c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -57,16 +57,23 @@ pub fn miri_default_args() -> &'static [&'static str] { &["-Zalways-encode-mir", "-Zmir-emit-retag", "-Zmir-opt-level=0", "--cfg=miri"] } +/// Configuration needed to spawn a Miri instance +#[derive(Clone)] +pub struct MiriConfig { + pub validate: bool, + pub args: Vec, +} + // Used by priroda pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( tcx: TyCtxt<'a, 'tcx, 'tcx>, main_id: DefId, - validate: bool, + config: MiriConfig, ) -> EvalResult<'tcx, EvalContext<'a, 'mir, 'tcx, Evaluator<'tcx>>> { let mut ecx = EvalContext::new( tcx.at(syntax::source_map::DUMMY_SP), ty::ParamEnv::reveal_all(), - Evaluator::new(validate), + Evaluator::new(config.validate), ); let main_instance = ty::Instance::mono(ecx.tcx.tcx, main_id); @@ -120,7 +127,7 @@ 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 argc = Scalar::from_int(1, dest.layout.size); + let argc = Scalar::from_uint(config.args.len() as u128, dest.layout.size); ecx.write_scalar(argc, dest)?; // Store argc for macOS _NSGetArgc { @@ -130,24 +137,35 @@ pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( } // FIXME: extract main source file path - // Third argument (argv): &[b"foo"] - const CMD: &str = "running-in-miri\0"; + // Third argument (argv): Created from config.args let dest = ecx.eval_place(&mir::Place::Local(args.next().unwrap()))?; - let cmd = ecx.memory_mut().allocate_static_bytes(CMD.as_bytes()).with_default_tag(); - let raw_str_layout = ecx.layout_of(ecx.tcx.mk_imm_ptr(ecx.tcx.types.u8))?; - let cmd_place = ecx.allocate(raw_str_layout, MiriMemoryKind::Env.into()); - ecx.write_scalar(Scalar::Ptr(cmd), cmd_place.into())?; - ecx.memory_mut().mark_immutable(cmd_place.to_ptr()?.alloc_id)?; + // Collect the pointers to the individual strings. + let mut argvs = Vec::>::new(); + for arg in config.args { + let mut arg = arg.into_bytes(); + arg.push(0); + argvs.push(ecx.memory_mut().allocate_static_bytes(arg.as_slice()).with_default_tag()); + } + // Make an array with all these pointers, in the Miri memory. + let argvs_layout = ecx.layout_of(ecx.tcx.mk_array(ecx.tcx.mk_imm_ptr(ecx.tcx.types.u8), argvs.len() as u64))?; + let argvs_place = ecx.allocate(argvs_layout, MiriMemoryKind::Env.into()); + for (idx, arg) in argvs.into_iter().enumerate() { + let place = ecx.mplace_field(argvs_place, idx as u64)?; + ecx.write_scalar(Scalar::Ptr(arg), place.into())?; + } + ecx.memory_mut().mark_immutable(argvs_place.to_ptr()?.alloc_id)?; + // Write a pointe to that place as the argument. + let argv = argvs_place.ptr; + ecx.write_scalar(argv, dest)?; // Store argv for macOS _NSGetArgv { - let argv = cmd_place.ptr; - ecx.write_scalar(argv, dest)?; let argv_place = ecx.allocate(dest.layout, MiriMemoryKind::Env.into()); ecx.write_scalar(argv, argv_place.into())?; ecx.machine.argv = Some(argv_place.ptr.to_ptr()?); } // Store cmdline as UTF-16 for Windows GetCommandLineW { + const CMD: &str = "running-in-miri\0"; let tcx = &{ecx.tcx.tcx}; let cmd_utf16: Vec = CMD.encode_utf16().collect(); let cmd_ptr = ecx.memory_mut().allocate( @@ -179,9 +197,9 @@ pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( pub fn eval_main<'a, 'tcx: 'a>( tcx: TyCtxt<'a, 'tcx, 'tcx>, main_id: DefId, - validate: bool, + config: MiriConfig, ) { - let mut ecx = create_ecx(tcx, main_id, validate).expect("Couldn't create ecx"); + let mut ecx = create_ecx(tcx, main_id, config).expect("Couldn't create ecx"); // Run! The main execution. let res: EvalResult = (|| { diff --git a/test-cargo-miri/src/main.rs b/test-cargo-miri/src/main.rs index 25e2cfdfa0368..32f1bac57d20f 100644 --- a/test-cargo-miri/src/main.rs +++ b/test-cargo-miri/src/main.rs @@ -9,7 +9,9 @@ fn main() { let n = ::read_u32(buf); assert_eq!(n, 0x01020304); println!("{:#010x}", n); - eprintln!("standard error"); + for arg in std::env::args() { + eprintln!("{}", arg); + } } #[cfg(test)] diff --git a/test-cargo-miri/stderr.ref b/test-cargo-miri/stderr.ref index aa7d1a2bdec7d..ba2906d0666cf 100644 --- a/test-cargo-miri/stderr.ref +++ b/test-cargo-miri/stderr.ref @@ -1 +1 @@ -standard error +main diff --git a/tests/run-pass/args.rs b/tests/run-pass/args.rs new file mode 100644 index 0000000000000..0116dce4992dc --- /dev/null +++ b/tests/run-pass/args.rs @@ -0,0 +1,5 @@ +fn main() { + for arg in std::env::args() { + println!("{}", arg); + } +} diff --git a/tests/run-pass/args.stdout b/tests/run-pass/args.stdout new file mode 100644 index 0000000000000..9564f5a1aa056 --- /dev/null +++ b/tests/run-pass/args.stdout @@ -0,0 +1 @@ +args From e400b42c216cc88ba1689fb72a704ee4aacbb2b3 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 8 Feb 2019 20:07:49 +0100 Subject: [PATCH 0560/3747] fix build --- benches/helpers/miri_helper.rs | 9 ++++++--- src/bin/miri-rustc-tests.rs | 8 ++++++-- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/benches/helpers/miri_helper.rs b/benches/helpers/miri_helper.rs index a34e137694cba..404fe7ae91501 100644 --- a/benches/helpers/miri_helper.rs +++ b/benches/helpers/miri_helper.rs @@ -4,11 +4,13 @@ extern crate rustc; extern crate rustc_driver; extern crate test; -use self::miri::eval_main; -use self::rustc_driver::{driver, Compilation}; +use rustc_driver::{driver, Compilation}; use rustc::hir::def_id::LOCAL_CRATE; use std::cell::RefCell; use std::rc::Rc; + +use miri::{MiriConfig, eval_main}; + use crate::test::Bencher; pub struct MiriCompilerCalls<'a>(Rc>); @@ -50,7 +52,8 @@ pub fn run(filename: &str, bencher: &mut Bencher) { ); bencher.borrow_mut().iter(|| { - eval_main(tcx, entry_def_id, false); + let config = MiriConfig { validate: true, args: vec![] }; + eval_main(tcx, entry_def_id, config); }); state.session.abort_if_errors(); diff --git a/src/bin/miri-rustc-tests.rs b/src/bin/miri-rustc-tests.rs index 45902dc6722f3..3a70577cb7f22 100644 --- a/src/bin/miri-rustc-tests.rs +++ b/src/bin/miri-rustc-tests.rs @@ -25,6 +25,8 @@ use rustc::ty::TyCtxt; use syntax::ast; use rustc::hir::def_id::LOCAL_CRATE; +use miri::MiriConfig; + struct MiriCompilerCalls { default: Box, /// whether we are building for the host @@ -94,9 +96,10 @@ fn after_analysis<'a, 'tcx>(state: &mut CompileState<'a, 'tcx>) { fn visit_item(&mut self, i: &'hir hir::Item) { if let hir::ItemKind::Fn(.., body_id) = i.node { if i.attrs.iter().any(|attr| attr.name() == "test") { + let config = MiriConfig { validate: true, args: vec![] }; let did = self.0.hir().body_owner_def_id(body_id); println!("running test: {}", self.0.def_path_debug_str(did)); - miri::eval_main(self.0, did, /*validate*/true); + miri::eval_main(self.0, did, config); self.1.session.abort_if_errors(); } } @@ -106,7 +109,8 @@ fn after_analysis<'a, 'tcx>(state: &mut CompileState<'a, 'tcx>) { } state.hir_crate.unwrap().visit_all_item_likes(&mut Visitor(tcx, state)); } else if let Some((entry_def_id, _)) = tcx.entry_fn(LOCAL_CRATE) { - miri::eval_main(tcx, entry_def_id, /*validate*/true); + let config = MiriConfig { validate: true, args: vec![] }; + miri::eval_main(tcx, entry_def_id, config); state.session.abort_if_errors(); } else { From 5e468766b79d3efb0b46f0cd2cefb451ac0a710b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 8 Feb 2019 20:37:07 +0100 Subject: [PATCH 0561/3747] also pass actual arguments to Windows --- Cargo.toml | 1 + src/lib.rs | 13 +++++++++++-- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 16b5b2361bd4c..721ebe5cfd46b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -39,6 +39,7 @@ directories = { version = "1.0", optional = true } rustc_version = { version = "0.2.3", optional = true } env_logger = "0.6" log = "0.4" +shell-escape = "0.1.4" # A noop dependency that changes in the Rust repository, it's a bit of a hack. # See the `src/tools/rustc-workspace-hack/README.md` file in `rust-lang/rust` # for more information. diff --git a/src/lib.rs b/src/lib.rs index 49c39201d006c..f59a476ed94e8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -139,9 +139,19 @@ pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( // FIXME: extract main source file path // Third argument (argv): Created from config.args let dest = ecx.eval_place(&mir::Place::Local(args.next().unwrap()))?; + // For Windows, construct a command string with all the aguments + let mut cmd = String::new(); + for arg in config.args.iter() { + if !cmd.is_empty() { + cmd.push(' '); + } + cmd.push_str(&*shell_escape::windows::escape(arg.as_str().into())); + } + cmd.push(std::char::from_u32(0).unwrap()); // don't forget 0 terminator // Collect the pointers to the individual strings. let mut argvs = Vec::>::new(); for arg in config.args { + // Add 0 terminator let mut arg = arg.into_bytes(); arg.push(0); argvs.push(ecx.memory_mut().allocate_static_bytes(arg.as_slice()).with_default_tag()); @@ -165,9 +175,8 @@ pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( } // Store cmdline as UTF-16 for Windows GetCommandLineW { - const CMD: &str = "running-in-miri\0"; let tcx = &{ecx.tcx.tcx}; - let cmd_utf16: Vec = CMD.encode_utf16().collect(); + let cmd_utf16: Vec = cmd.encode_utf16().collect(); let cmd_ptr = ecx.memory_mut().allocate( Size::from_bytes(cmd_utf16.len() as u64 * 2), Align::from_bytes(2).unwrap(), From 35ed590075bc1018bb5863f8f7d3d4ae079aea73 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 9 Feb 2019 12:42:16 +0100 Subject: [PATCH 0562/3747] also enable passing arguments through from cargo-miri --- src/bin/cargo-miri.rs | 32 ++++++++++++++++++++++---------- test-cargo-miri/run-test.py | 9 +++++++++ test-cargo-miri/stderr.ref2 | 3 +++ test-cargo-miri/test.stdout.ref2 | 11 +++++++++++ 4 files changed, 45 insertions(+), 10 deletions(-) create mode 100644 test-cargo-miri/stderr.ref2 create mode 100644 test-cargo-miri/test.stdout.ref2 diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 9b97822b4754f..93200f33a2606 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -10,7 +10,7 @@ use std::fs::{self, File}; const CARGO_MIRI_HELP: &str = r#"Interprets bin crates and tests in Miri Usage: - cargo miri [subcommand] [options] [--] [...] + cargo miri [subcommand] [options] [--] [...] [--] [...] Subcommands: run Run binaries (default) @@ -22,8 +22,9 @@ Common options: --features Features to compile for the package -V, --version Print version info and exit -Other [options] are the same as `cargo rustc`. Everything after the "--" is -passed verbatim to Miri. +Other [options] are the same as `cargo rustc`. Everything after the first "--" is +passed verbatim to Miri, which will pass everything after the second "--" verbatim +to the interpreted program. The config flag `miri` is automatically defined for convenience. You can use it to configure the resource limits @@ -355,11 +356,13 @@ fn in_cargo_miri() { } cmd.arg(arg); } - // add "--" "-Zcargo-miri-marker" and the remaining user flags + // Add "--" (to end the cargo flags), and then the user flags. We add markers around the user flags + // to be able to identify them later. cmd .arg("--") - .arg("cargo-miri-marker") - .args(args); + .arg("cargo-miri-marker-begin") + .args(args) + .arg("cargo-miri-marker-end"); let path = std::env::current_exe().expect("current executable path invalid"); cmd.env("RUSTC_WRAPPER", path); if verbose { @@ -413,10 +416,19 @@ fn inside_cargo_rustc() { }; args.splice(0..0, miri::miri_default_args().iter().map(ToString::to_string)); - // see if we have cargo-miri-marker, which means we want to interpret this crate in Miri - // (and remove the marker). - let needs_miri = if let Some(pos) = args.iter().position(|arg| arg == "cargo-miri-marker") { - args.remove(pos); + // See if we can find the cargo-miri markers. Those only get added to the binary we want to + // run. They also serve to mark the user-defined arguments, which we have to move all the way to the + // end (they get added somewhere in the middle). + let needs_miri = if let Some(begin) = args.iter().position(|arg| arg == "cargo-miri-marker-begin") { + let end = args.iter().position(|arg| arg == "cargo-miri-marker-end").expect("Cannot find end marker"); + // These mark the user arguments. We remove the first and last as they are the markers. + let mut user_args = args.drain(begin..=end); + assert_eq!(user_args.next().unwrap(), "cargo-miri-marker-begin"); + assert_eq!(user_args.next_back().unwrap(), "cargo-miri-marker-end"); + // Collect the rest and add it back at the end + let mut user_args = user_args.collect::>(); + args.append(&mut user_args); + // Run this in Miri true } else { false diff --git a/test-cargo-miri/run-test.py b/test-cargo-miri/run-test.py index 7f7f2660c0622..8c59b6bcdead6 100755 --- a/test-cargo-miri/run-test.py +++ b/test-cargo-miri/run-test.py @@ -37,10 +37,19 @@ def test(name, cmd, stdout_ref, stderr_ref): def test_cargo_miri_run(): test("cargo miri run", ["cargo", "miri", "run", "-q"], "stdout.ref", "stderr.ref") + test("cargo miri run (with arguments)", + ["cargo", "miri", "run", "-q", "--", "--", "hello world", '"hello world"'], + "stdout.ref", "stderr.ref2" + ) def test_cargo_miri_test(): test("cargo miri test", ["cargo", "miri", "test", "-q"], "test.stdout.ref", "test.stderr.ref") + test("cargo miri test (with filter)", + ["cargo", "miri", "test", "-q", "--", "--", "impl"], + "test.stdout.ref2", "test.stderr.ref" + ) test_cargo_miri_run() test_cargo_miri_test() +print("TEST SUCCESSFUL!") sys.exit(0) diff --git a/test-cargo-miri/stderr.ref2 b/test-cargo-miri/stderr.ref2 new file mode 100644 index 0000000000000..8226b1b7cdec7 --- /dev/null +++ b/test-cargo-miri/stderr.ref2 @@ -0,0 +1,3 @@ +main +hello world +"hello world" diff --git a/test-cargo-miri/test.stdout.ref2 b/test-cargo-miri/test.stdout.ref2 new file mode 100644 index 0000000000000..ce3506709d5a0 --- /dev/null +++ b/test-cargo-miri/test.stdout.ref2 @@ -0,0 +1,11 @@ + +running 0 tests + +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 1 filtered out + + +running 1 test +test simple ... ok + +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 1 filtered out + From 866aeaecfc35cc54f03ab6bf777c39587dd4b042 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 9 Feb 2019 12:44:56 +0100 Subject: [PATCH 0563/3747] explain arument passing in the docs --- README.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/README.md b/README.md index 1d97b61f43d56..21e9fa43a8f8c 100644 --- a/README.md +++ b/README.md @@ -48,6 +48,13 @@ Now you can run your project in Miri: 3. If you have a binary project, you can run it through Miri using `cargo +nightly miri run`. +You can pass arguments to Miri after the first `--`, and pass arguments to the +interpreted program or test suite after the second `--`. For example, `cargo ++nightly miri run -- -Zmiri-disable-validation` runs the program without +validation of basic type invariants and references. `cargo +nightly miri test +-- -- filter` passes `filter` to the test suite the same way `cargo test filter` +would. + When running code via `cargo miri`, the `miri` config flag is set. You can use this to exclude test cases that will fail under Miri because they do things Miri does not support: From 88bb7a1525fa03173c5f04b3dcdac34ca2bce082 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 11 Feb 2019 10:02:59 +0100 Subject: [PATCH 0564/3747] TIL that you can also use .appveyor.yml --- appveyor.yml => .appveyor.yml | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename appveyor.yml => .appveyor.yml (100%) diff --git a/appveyor.yml b/.appveyor.yml similarity index 100% rename from appveyor.yml rename to .appveyor.yml From 3c652032c0223de205c28e6e0ded117ca4e46e61 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 12 Feb 2019 10:51:03 +0100 Subject: [PATCH 0565/3747] be more clear which stack we are talking about --- src/stacked_borrows.rs | 4 ++-- tests/compile-fail/stacked_borrows/alias_through_mutation.rs | 2 +- tests/compile-fail/stacked_borrows/aliasing_mut3.rs | 2 +- .../compile-fail/stacked_borrows/box_exclusive_violation1.rs | 2 +- tests/compile-fail/stacked_borrows/buggy_as_mut_slice.rs | 2 +- tests/compile-fail/stacked_borrows/buggy_split_at_mut.rs | 2 +- tests/compile-fail/stacked_borrows/illegal_read1.rs | 2 +- tests/compile-fail/stacked_borrows/illegal_read2.rs | 2 +- tests/compile-fail/stacked_borrows/illegal_read3.rs | 2 +- tests/compile-fail/stacked_borrows/illegal_read4.rs | 2 +- tests/compile-fail/stacked_borrows/illegal_read5.rs | 2 +- tests/compile-fail/stacked_borrows/illegal_write2.rs | 2 +- tests/compile-fail/stacked_borrows/illegal_write3.rs | 2 +- tests/compile-fail/stacked_borrows/illegal_write5.rs | 2 +- tests/compile-fail/stacked_borrows/load_invalid_mut.rs | 2 +- tests/compile-fail/stacked_borrows/outdated_local.rs | 2 +- tests/compile-fail/stacked_borrows/pass_invalid_mut.rs | 2 +- tests/compile-fail/stacked_borrows/pointer_smuggling.rs | 2 +- tests/compile-fail/stacked_borrows/return_invalid_mut.rs | 2 +- .../compile-fail/stacked_borrows/return_invalid_mut_option.rs | 2 +- .../compile-fail/stacked_borrows/return_invalid_mut_tuple.rs | 2 +- tests/compile-fail/stacked_borrows/transmute-is-no-escape.rs | 2 +- tests/compile-fail/stacked_borrows/unescaped_local.rs | 2 +- 23 files changed, 24 insertions(+), 24 deletions(-) diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 1fc705c03bb5e..be4a607961f3e 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -221,7 +221,7 @@ impl<'tcx> Stack { } } // If we got here, we did not find our item. We have to error to satisfy U3. - Err(format!("Borrow being dereferenced ({:?}) does not exist on the stack", bor)) + Err(format!("Borrow being dereferenced ({:?}) does not exist on the borrow stack", bor)) } /// Perform an actual memory access using `bor`. We do not know any types here @@ -294,7 +294,7 @@ impl<'tcx> Stack { } // If we got here, we did not find our item. err!(MachineError(format!( - "Borrow being accessed ({:?}) does not exist on the stack", + "Borrow being accessed ({:?}) does not exist on the borrow stack", bor ))) } diff --git a/tests/compile-fail/stacked_borrows/alias_through_mutation.rs b/tests/compile-fail/stacked_borrows/alias_through_mutation.rs index db9ac93279f15..30f5921202c3f 100644 --- a/tests/compile-fail/stacked_borrows/alias_through_mutation.rs +++ b/tests/compile-fail/stacked_borrows/alias_through_mutation.rs @@ -9,5 +9,5 @@ fn main() { retarget(&mut target_alias, target); // now `target_alias` points to the same thing as `target` *target = 13; - let _val = *target_alias; //~ ERROR does not exist on the stack + let _val = *target_alias; //~ ERROR does not exist on the borrow stack } diff --git a/tests/compile-fail/stacked_borrows/aliasing_mut3.rs b/tests/compile-fail/stacked_borrows/aliasing_mut3.rs index e564e878ddb19..e3c59d1566142 100644 --- a/tests/compile-fail/stacked_borrows/aliasing_mut3.rs +++ b/tests/compile-fail/stacked_borrows/aliasing_mut3.rs @@ -1,6 +1,6 @@ use std::mem; -pub fn safe(_x: &mut i32, _y: &i32) {} //~ ERROR does not exist on the stack +pub fn safe(_x: &mut i32, _y: &i32) {} //~ ERROR does not exist on the borrow stack fn main() { let mut x = 0; diff --git a/tests/compile-fail/stacked_borrows/box_exclusive_violation1.rs b/tests/compile-fail/stacked_borrows/box_exclusive_violation1.rs index bd0fec859d8f7..481915faed040 100644 --- a/tests/compile-fail/stacked_borrows/box_exclusive_violation1.rs +++ b/tests/compile-fail/stacked_borrows/box_exclusive_violation1.rs @@ -8,7 +8,7 @@ fn demo_mut_advanced_unique(mut our: Box) -> i32 { unknown_code_2(); // We know this will return 5 - *our //~ ERROR does not exist on the stack + *our //~ ERROR does not exist on the borrow stack } // Now comes the evil context diff --git a/tests/compile-fail/stacked_borrows/buggy_as_mut_slice.rs b/tests/compile-fail/stacked_borrows/buggy_as_mut_slice.rs index e08e3bba6840d..98d4e6f22965d 100644 --- a/tests/compile-fail/stacked_borrows/buggy_as_mut_slice.rs +++ b/tests/compile-fail/stacked_borrows/buggy_as_mut_slice.rs @@ -13,5 +13,5 @@ fn main() { let v1 = safe::as_mut_slice(&v); let _v2 = safe::as_mut_slice(&v); v1[1] = 5; - //~^ ERROR does not exist on the stack + //~^ ERROR does not exist on the borrow stack } diff --git a/tests/compile-fail/stacked_borrows/buggy_split_at_mut.rs b/tests/compile-fail/stacked_borrows/buggy_split_at_mut.rs index 959c6314690d2..42f345f55144c 100644 --- a/tests/compile-fail/stacked_borrows/buggy_split_at_mut.rs +++ b/tests/compile-fail/stacked_borrows/buggy_split_at_mut.rs @@ -9,7 +9,7 @@ mod safe { assert!(mid <= len); (from_raw_parts_mut(ptr, len - mid), // BUG: should be "mid" instead of "len - mid" - //~^ ERROR does not exist on the stack + //~^ ERROR does not exist on the borrow stack from_raw_parts_mut(ptr.offset(mid as isize), len - mid)) } } diff --git a/tests/compile-fail/stacked_borrows/illegal_read1.rs b/tests/compile-fail/stacked_borrows/illegal_read1.rs index dbaccae882721..0181f739a899d 100644 --- a/tests/compile-fail/stacked_borrows/illegal_read1.rs +++ b/tests/compile-fail/stacked_borrows/illegal_read1.rs @@ -7,7 +7,7 @@ fn main() { let xref = unsafe { &mut *xraw }; // derived from raw, so using raw is still okay... callee(xraw); let _val = *xref; // ...but any use of raw will invalidate our ref. - //~^ ERROR: does not exist on the stack + //~^ ERROR: does not exist on the borrow stack } fn callee(xraw: *mut i32) { diff --git a/tests/compile-fail/stacked_borrows/illegal_read2.rs b/tests/compile-fail/stacked_borrows/illegal_read2.rs index 2da755d9aabc1..b55fe1c6c88a4 100644 --- a/tests/compile-fail/stacked_borrows/illegal_read2.rs +++ b/tests/compile-fail/stacked_borrows/illegal_read2.rs @@ -7,7 +7,7 @@ fn main() { let xref = unsafe { &mut *xraw }; // derived from raw, so using raw is still okay... callee(xraw); let _val = *xref; // ...but any use of raw will invalidate our ref. - //~^ ERROR: does not exist on the stack + //~^ ERROR: does not exist on the borrow stack } fn callee(xraw: *mut i32) { diff --git a/tests/compile-fail/stacked_borrows/illegal_read3.rs b/tests/compile-fail/stacked_borrows/illegal_read3.rs index b0da0511dee3f..9da4ca09606e7 100644 --- a/tests/compile-fail/stacked_borrows/illegal_read3.rs +++ b/tests/compile-fail/stacked_borrows/illegal_read3.rs @@ -13,7 +13,7 @@ fn main() { let xref2 = &mut *xref1; // derived from xref1, so using raw is still okay... callee(xref1_sneaky); let _val = *xref2; // ...but any use of it will invalidate our ref. - //~^ ERROR: does not exist on the stack + //~^ ERROR: does not exist on the borrow stack } fn callee(xref1: usize) { diff --git a/tests/compile-fail/stacked_borrows/illegal_read4.rs b/tests/compile-fail/stacked_borrows/illegal_read4.rs index c86ec1286daad..bb889de8f839e 100644 --- a/tests/compile-fail/stacked_borrows/illegal_read4.rs +++ b/tests/compile-fail/stacked_borrows/illegal_read4.rs @@ -5,5 +5,5 @@ fn main() { let xraw = xref1 as *mut _; let xref2 = unsafe { &mut *xraw }; let _val = unsafe { *xraw }; // use the raw again, this invalidates xref2 *even* with the special read except for uniq refs - let _illegal = *xref2; //~ ERROR does not exist on the stack + let _illegal = *xref2; //~ ERROR does not exist on the borrow stack } diff --git a/tests/compile-fail/stacked_borrows/illegal_read5.rs b/tests/compile-fail/stacked_borrows/illegal_read5.rs index 863649a47b5ef..5f800e754a5d0 100644 --- a/tests/compile-fail/stacked_borrows/illegal_read5.rs +++ b/tests/compile-fail/stacked_borrows/illegal_read5.rs @@ -12,5 +12,5 @@ fn main() { let _val = *xref; // we can even still use our mutable reference mem::forget(unsafe { ptr::read(xshr) }); // but after reading through the shared ref let _val = *xref; // the mutable one is dead and gone - //~^ ERROR does not exist on the stack + //~^ ERROR does not exist on the borrow stack } diff --git a/tests/compile-fail/stacked_borrows/illegal_write2.rs b/tests/compile-fail/stacked_borrows/illegal_write2.rs index ba3b6686b84cb..affa21c7625ea 100644 --- a/tests/compile-fail/stacked_borrows/illegal_write2.rs +++ b/tests/compile-fail/stacked_borrows/illegal_write2.rs @@ -3,6 +3,6 @@ fn main() { let target2 = target as *mut _; drop(&mut *target); // reborrow // Now make sure our ref is still the only one. - unsafe { *target2 = 13; } //~ ERROR does not exist on the stack + unsafe { *target2 = 13; } //~ ERROR does not exist on the borrow stack let _val = *target; } diff --git a/tests/compile-fail/stacked_borrows/illegal_write3.rs b/tests/compile-fail/stacked_borrows/illegal_write3.rs index a653aa5003f6d..dc4edcc3a5b44 100644 --- a/tests/compile-fail/stacked_borrows/illegal_write3.rs +++ b/tests/compile-fail/stacked_borrows/illegal_write3.rs @@ -3,6 +3,6 @@ fn main() { // Make sure raw ptr with raw tag cannot mutate frozen location without breaking the shared ref. let r#ref = ⌖ // freeze let ptr = r#ref as *const _ as *mut _; // raw ptr, with raw tag - unsafe { *ptr = 42; } //~ ERROR does not exist on the stack + unsafe { *ptr = 42; } //~ ERROR does not exist on the borrow stack let _val = *r#ref; } diff --git a/tests/compile-fail/stacked_borrows/illegal_write5.rs b/tests/compile-fail/stacked_borrows/illegal_write5.rs index 57b2ca87d8102..af57221260ce8 100644 --- a/tests/compile-fail/stacked_borrows/illegal_write5.rs +++ b/tests/compile-fail/stacked_borrows/illegal_write5.rs @@ -7,7 +7,7 @@ fn main() { let xref = unsafe { &mut *xraw }; // derived from raw, so using raw is still okay... callee(xraw); let _val = *xref; // ...but any use of raw will invalidate our ref. - //~^ ERROR: does not exist on the stack + //~^ ERROR: does not exist on the borrow stack } fn callee(xraw: *mut i32) { diff --git a/tests/compile-fail/stacked_borrows/load_invalid_mut.rs b/tests/compile-fail/stacked_borrows/load_invalid_mut.rs index 98b9451eda87e..f2e4b36f85cc2 100644 --- a/tests/compile-fail/stacked_borrows/load_invalid_mut.rs +++ b/tests/compile-fail/stacked_borrows/load_invalid_mut.rs @@ -5,5 +5,5 @@ fn main() { let xref = unsafe { &mut *xraw }; let xref_in_mem = Box::new(xref); let _val = unsafe { *xraw }; // invalidate xref - let _val = *xref_in_mem; //~ ERROR does not exist on the stack + let _val = *xref_in_mem; //~ ERROR does not exist on the borrow stack } diff --git a/tests/compile-fail/stacked_borrows/outdated_local.rs b/tests/compile-fail/stacked_borrows/outdated_local.rs index 64a8ff69108ec..ba36e43e0c5d4 100644 --- a/tests/compile-fail/stacked_borrows/outdated_local.rs +++ b/tests/compile-fail/stacked_borrows/outdated_local.rs @@ -3,7 +3,7 @@ fn main() { let y: *const i32 = &x; x = 1; // this invalidates y by reactivating the lowermost uniq borrow for this local - assert_eq!(unsafe { *y }, 1); //~ ERROR does not exist on the stack + assert_eq!(unsafe { *y }, 1); //~ ERROR does not exist on the borrow stack assert_eq!(x, 1); } diff --git a/tests/compile-fail/stacked_borrows/pass_invalid_mut.rs b/tests/compile-fail/stacked_borrows/pass_invalid_mut.rs index 28288c6c63623..b239237f01992 100644 --- a/tests/compile-fail/stacked_borrows/pass_invalid_mut.rs +++ b/tests/compile-fail/stacked_borrows/pass_invalid_mut.rs @@ -6,5 +6,5 @@ fn main() { let xraw = x as *mut _; let xref = unsafe { &mut *xraw }; let _val = unsafe { *xraw }; // invalidate xref - foo(xref); //~ ERROR does not exist on the stack + foo(xref); //~ ERROR does not exist on the borrow stack } diff --git a/tests/compile-fail/stacked_borrows/pointer_smuggling.rs b/tests/compile-fail/stacked_borrows/pointer_smuggling.rs index bd5e28b47e867..a8207d58e99b2 100644 --- a/tests/compile-fail/stacked_borrows/pointer_smuggling.rs +++ b/tests/compile-fail/stacked_borrows/pointer_smuggling.rs @@ -8,7 +8,7 @@ fn fun1(x: &mut u8) { fn fun2() { // Now we use a pointer we are not allowed to use - let _x = unsafe { *PTR }; //~ ERROR does not exist on the stack + let _x = unsafe { *PTR }; //~ ERROR does not exist on the borrow stack } fn main() { diff --git a/tests/compile-fail/stacked_borrows/return_invalid_mut.rs b/tests/compile-fail/stacked_borrows/return_invalid_mut.rs index e7f0b9bc9ddd0..31f8a4e33afd9 100644 --- a/tests/compile-fail/stacked_borrows/return_invalid_mut.rs +++ b/tests/compile-fail/stacked_borrows/return_invalid_mut.rs @@ -3,7 +3,7 @@ fn foo(x: &mut (i32, i32)) -> &mut i32 { let xraw = x as *mut (i32, i32); let ret = unsafe { &mut (*xraw).1 }; let _val = unsafe { *xraw }; // invalidate xref - ret //~ ERROR does not exist on the stack + ret //~ ERROR does not exist on the borrow stack } fn main() { diff --git a/tests/compile-fail/stacked_borrows/return_invalid_mut_option.rs b/tests/compile-fail/stacked_borrows/return_invalid_mut_option.rs index 28a1f74c6ac20..750d507d6f660 100644 --- a/tests/compile-fail/stacked_borrows/return_invalid_mut_option.rs +++ b/tests/compile-fail/stacked_borrows/return_invalid_mut_option.rs @@ -3,7 +3,7 @@ fn foo(x: &mut (i32, i32)) -> Option<&mut i32> { let xraw = x as *mut (i32, i32); let ret = Some(unsafe { &mut (*xraw).1 }); let _val = unsafe { *xraw }; // invalidate xref - ret //~ ERROR does not exist on the stack + ret //~ ERROR does not exist on the borrow stack } fn main() { diff --git a/tests/compile-fail/stacked_borrows/return_invalid_mut_tuple.rs b/tests/compile-fail/stacked_borrows/return_invalid_mut_tuple.rs index 3357af68a8411..bb712e9e486cd 100644 --- a/tests/compile-fail/stacked_borrows/return_invalid_mut_tuple.rs +++ b/tests/compile-fail/stacked_borrows/return_invalid_mut_tuple.rs @@ -3,7 +3,7 @@ fn foo(x: &mut (i32, i32)) -> (&mut i32,) { let xraw = x as *mut (i32, i32); let ret = (unsafe { &mut (*xraw).1 },); let _val = unsafe { *xraw }; // invalidate xref - ret //~ ERROR does not exist on the stack + ret //~ ERROR does not exist on the borrow stack } fn main() { diff --git a/tests/compile-fail/stacked_borrows/transmute-is-no-escape.rs b/tests/compile-fail/stacked_borrows/transmute-is-no-escape.rs index 197c11197efa6..45ada88977788 100644 --- a/tests/compile-fail/stacked_borrows/transmute-is-no-escape.rs +++ b/tests/compile-fail/stacked_borrows/transmute-is-no-escape.rs @@ -10,5 +10,5 @@ fn main() { let _raw: *mut i32 = unsafe { mem::transmute(&mut x[0]) }; // `raw` still carries a tag, so we get another pointer to the same location that does not carry a tag let raw = (&mut x[1] as *mut i32).wrapping_offset(-1); - unsafe { *raw = 13; } //~ ERROR does not exist on the stack + unsafe { *raw = 13; } //~ ERROR does not exist on the borrow stack } diff --git a/tests/compile-fail/stacked_borrows/unescaped_local.rs b/tests/compile-fail/stacked_borrows/unescaped_local.rs index 054697b04a09d..1db14ea7eda54 100644 --- a/tests/compile-fail/stacked_borrows/unescaped_local.rs +++ b/tests/compile-fail/stacked_borrows/unescaped_local.rs @@ -4,5 +4,5 @@ fn main() { let mut x = 42; let raw = &mut x as *mut i32 as usize as *mut i32; let _ptr = &mut x; - unsafe { *raw = 13; } //~ ERROR does not exist on the stack + unsafe { *raw = 13; } //~ ERROR does not exist on the borrow stack } From fd6bd5ba4b55da0c7056d91ed3cae85bb2029b95 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 12 Feb 2019 10:56:27 +0100 Subject: [PATCH 0566/3747] rename things away from 'Shr' that are used for much more than just shared references --- src/stacked_borrows.rs | 58 +++++++++++++++++++++--------------------- 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index be4a607961f3e..a52e115323c6f 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -21,19 +21,19 @@ pub type CallId = u64; pub enum Borrow { /// A unique (mutable) reference. Uniq(Timestamp), - /// A shared reference. This is also used by raw pointers, which do not track details + /// An aliasing reference. This is also used by raw pointers, which do not track details /// of how or when they were created, hence the timestamp is optional. /// Shr(Some(_)) does NOT mean that the destination of this reference is frozen; /// that depends on the type! Only those parts outside of an `UnsafeCell` are actually /// frozen. - Shr(Option), + Alias(Option), } impl Borrow { #[inline(always)] - pub fn is_shared(self) -> bool { + pub fn is_aliasing(self) -> bool { match self { - Borrow::Shr(_) => true, + Borrow::Alias(_) => true, _ => false, } } @@ -49,7 +49,7 @@ impl Borrow { impl Default for Borrow { fn default() -> Self { - Borrow::Shr(None) + Borrow::Alias(None) } } @@ -58,10 +58,9 @@ impl Default for Borrow { pub enum BorStackItem { /// Indicates the unique reference that may mutate. Uniq(Timestamp), - /// Indicates that the location has been shared. Used for raw pointers, but - /// also for shared references. The latter *additionally* get frozen - /// when there is no `UnsafeCell`. - Shr, + /// Indicates that the location has been mutably shared. Used for raw pointers as + /// well as for unfrozen shared references. + Raw, /// A barrier, tracking the function it belongs to by its index on the call stack FnBarrier(CallId) } @@ -186,19 +185,19 @@ impl<'tcx> Stack { kind: RefKind, ) -> Result, String> { // Exclude unique ref with frozen tag. - if let (RefKind::Unique, Borrow::Shr(Some(_))) = (kind, bor) { + if let (RefKind::Unique, Borrow::Alias(Some(_))) = (kind, bor) { return Err(format!("Encountered mutable reference with frozen tag ({:?})", bor)); } // Checks related to freezing match bor { - Borrow::Shr(Some(bor_t)) if kind == RefKind::Frozen => { + Borrow::Alias(Some(bor_t)) if kind == RefKind::Frozen => { // We need the location to be frozen. This ensures F3. let frozen = self.frozen_since.map_or(false, |itm_t| itm_t <= bor_t); return if frozen { Ok(None) } else { Err(format!("Location is not frozen long enough")) } } - Borrow::Shr(_) if self.frozen_since.is_some() => { + Borrow::Alias(_) if self.frozen_since.is_some() => { return Ok(None) // Shared deref to frozen location, looking good } _ => {} // Not sufficient, go on looking. @@ -210,8 +209,8 @@ impl<'tcx> Stack { // Found matching unique item. This satisfies U3. return Ok(Some(idx)) } - (BorStackItem::Shr, Borrow::Shr(_)) => { - // Found matching shared/raw item. + (BorStackItem::Raw, Borrow::Alias(_)) => { + // Found matching aliasing/raw item. return Ok(Some(idx)) } // Go on looking. We ignore barriers! When an `&mut` and an `&` alias, @@ -258,14 +257,15 @@ impl<'tcx> Stack { (BorStackItem::Uniq(itm_t), Borrow::Uniq(bor_t)) if itm_t == bor_t => { // Found matching unique item. Continue after the match. } - (BorStackItem::Shr, _) if kind == AccessKind::Read => { - // When reading, everything can use a shared item! + (BorStackItem::Raw, _) if kind == AccessKind::Read => { + // When reading, everything can use a raw item! // We do not want to do this when writing: Writing to an `&mut` // should reaffirm its exclusivity (i.e., make sure it is - // on top of the stack). Continue after the match. + // on top of the stack). + // Continue after the match. } - (BorStackItem::Shr, Borrow::Shr(_)) => { - // Found matching shared item. Continue after the match. + (BorStackItem::Raw, Borrow::Alias(_)) => { + // Found matching raw item. Continue after the match. } _ => { // Pop this, go on. This ensures U2. @@ -309,7 +309,7 @@ impl<'tcx> Stack { // of access (like writing through raw pointers) is permitted. if kind == RefKind::Frozen { let bor_t = match bor { - Borrow::Shr(Some(t)) => t, + Borrow::Alias(Some(t)) => t, _ => bug!("Creating illegal borrow {:?} for frozen ref", bor), }; // It is possible that we already are frozen (e.g. if we just pushed a barrier, @@ -328,12 +328,12 @@ impl<'tcx> Stack { // Push new item to the stack. let itm = match bor { Borrow::Uniq(t) => BorStackItem::Uniq(t), - Borrow::Shr(_) => BorStackItem::Shr, + Borrow::Alias(_) => BorStackItem::Raw, }; if *self.borrows.last().unwrap() == itm { // This is just an optimization, no functional change: Avoid stacking // multiple `Shr` on top of each other. - assert!(bor.is_shared()); + assert!(bor.is_aliasing()); trace!("create: Sharing a shared location is a NOP"); } else { // This ensures U1. @@ -440,7 +440,7 @@ impl<'tcx> Stacks { _ => false, }; if bor_redundant { - assert!(new_bor.is_shared(), "A unique reborrow can never be redundant"); + assert!(new_bor.is_aliasing(), "A unique reborrow can never be redundant"); trace!("reborrow is redundant"); continue; } @@ -465,7 +465,7 @@ impl AllocationExtra for Stacks { #[inline(always)] fn memory_allocated<'tcx>(size: Size, extra: &MemoryState) -> Self { let stack = Stack { - borrows: vec![BorStackItem::Shr], + borrows: vec![BorStackItem::Raw], frozen_since: None, }; Stacks { @@ -511,7 +511,7 @@ impl<'tcx> Stacks { ) { for stack in self.stacks.get_mut().iter_mut(Size::ZERO, size) { assert!(stack.borrows.len() == 1); - assert_eq!(stack.borrows.pop().unwrap(), BorStackItem::Shr); + assert_eq!(stack.borrows.pop().unwrap(), BorStackItem::Raw); stack.borrows.push(itm); } } @@ -536,7 +536,7 @@ trait EvalContextPrivExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, let alloc = this.memory().get(ptr.alloc_id)?; alloc.check_bounds(this, ptr, size)?; // Update the stacks. - if let Borrow::Shr(Some(_)) = new_bor { + if let Borrow::Alias(Some(_)) = new_bor { // Reference that cares about freezing. We need a frozen-sensitive reborrow. this.visit_freeze_sensitive(place, size, |cur_ptr, size, frozen| { let kind = if frozen { RefKind::Frozen } else { RefKind::Raw }; @@ -574,7 +574,7 @@ trait EvalContextPrivExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, let time = this.machine.stacked_borrows.increment_clock(); let new_bor = match mutbl { Some(MutMutable) => Borrow::Uniq(time), - Some(MutImmutable) => Borrow::Shr(Some(time)), + Some(MutImmutable) => Borrow::Alias(Some(time)), None => Borrow::default(), }; @@ -586,7 +586,7 @@ trait EvalContextPrivExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, assert!(mutbl == Some(MutMutable), "two-phase shared borrows make no sense"); // We immediately share it, to allow read accesses let two_phase_time = this.machine.stacked_borrows.increment_clock(); - let two_phase_bor = Borrow::Shr(Some(two_phase_time)); + let two_phase_bor = Borrow::Alias(Some(two_phase_time)); this.reborrow(new_place, size, /*fn_barrier*/false, two_phase_bor)?; } @@ -651,7 +651,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, let alloc = this.memory().get(ptr.alloc_id)?; alloc.check_bounds(this, ptr, size)?; // If we got here, we do some checking, *but* we leave the tag unchanged. - if let Borrow::Shr(Some(_)) = ptr.tag { + if let Borrow::Alias(Some(_)) = ptr.tag { assert_eq!(mutability, Some(MutImmutable)); // We need a frozen-sensitive check this.visit_freeze_sensitive(place, size, |cur_ptr, size, frozen| { From 93cf2e5491acc90ae6a08a9acbb55be512124071 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 13 Feb 2019 08:13:07 +0100 Subject: [PATCH 0567/3747] update Rust --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 0c7f46922122a..b265e000950eb 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -nightly-2019-01-30 +nightly-2019-02-13 From d91ab9a7a63d3e4a6bd1071f32aada6e0194ef11 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 13 Feb 2019 10:07:31 +0100 Subject: [PATCH 0568/3747] fix ptr comparison test --- tests/run-pass/function_pointers.rs | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/tests/run-pass/function_pointers.rs b/tests/run-pass/function_pointers.rs index cc888630d3eea..26a2d5a6c2a9e 100644 --- a/tests/run-pass/function_pointers.rs +++ b/tests/run-pass/function_pointers.rs @@ -1,5 +1,16 @@ -fn f() -> i32 { - 42 +trait Answer { + fn answer() -> Self; +} + +impl Answer for i32 { + fn answer() -> i32 { + 42 + } +} + +// A generic function, to make its address unstable +fn f() -> T { + Answer::answer() } fn g(i: i32) -> i32 { From 2d892c160b3aaaf3ec0a002eb38a4b50379cb759 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 13 Feb 2019 12:09:53 +0100 Subject: [PATCH 0569/3747] skip installing rust-src if XARGO_RUST_SRC is set --- src/bin/cargo-miri.rs | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 93200f33a2606..bca2b6df1b40b 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -193,18 +193,21 @@ fn setup(ask_user: bool) { } } - // Then, we also need rust-src. Let's see if it is already installed. - let sysroot = Command::new("rustc").args(&["--print", "sysroot"]).output().unwrap().stdout; - let sysroot = std::str::from_utf8(&sysroot[..]).unwrap(); - let src = Path::new(sysroot.trim_end_matches('\n')).join("lib").join("rustlib").join("src"); - if !src.exists() { - if ask_user { - ask("It seems you do not have the rust-src component installed. I will run `rustup component add rust-src`. Proceed?"); - } else { - println!("Installing rust-src component: `rustup component add rust-src`"); - } - if !Command::new("rustup").args(&["component", "add", "rust-src"]).status().unwrap().success() { - show_error(format!("Failed to install rust-src component")); + // Then, unless XARGO_RUST_SRC is set, we also need rust-src. + // Let's see if it is already installed. + if std::env::var("XARGO_RUST_SRC").is_err() { + let sysroot = Command::new("rustc").args(&["--print", "sysroot"]).output().unwrap().stdout; + let sysroot = std::str::from_utf8(&sysroot[..]).unwrap(); + let src = Path::new(sysroot.trim_end_matches('\n')).join("lib").join("rustlib").join("src"); + if !src.exists() { + if ask_user { + ask("It seems you do not have the rust-src component installed. I will run `rustup component add rust-src`. Proceed?"); + } else { + println!("Installing rust-src component: `rustup component add rust-src`"); + } + if !Command::new("rustup").args(&["component", "add", "rust-src"]).status().unwrap().success() { + show_error(format!("Failed to install rust-src component")); + } } } From 2d323857e91f3f73bd9d15a83af079a3f6d9ff43 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 13 Feb 2019 17:47:47 +0100 Subject: [PATCH 0570/3747] implement and test posix_memalign --- src/fn_call.rs | 26 ++++++++++++++++++++++++++ tests/run-pass/heap.rs | 26 ++++++++++++++++++++++++++ 2 files changed, 52 insertions(+) diff --git a/src/fn_call.rs b/src/fn_call.rs index a5708305a9762..fa68f1d0d703a 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -93,6 +93,32 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, this.write_scalar(Scalar::Ptr(ptr.with_default_tag()), dest)?; } } + "posix_memalign" => { + let ret = this.deref_operand(args[0])?; + let align = this.read_scalar(args[1])?.to_usize(this)?; + let size = this.read_scalar(args[2])?.to_usize(this)?; + // align must be a power of 2, and also at least ptr-sized (wtf, POSIX) + if !align.is_power_of_two() { + return err!(HeapAllocNonPowerOfTwoAlignment(align)); + } + if align < this.pointer_size().bytes() { + return err!(MachineError(format!( + "posix_memalign: alignment must be at least the size of a pointer, but is {}", + align, + ))); + } + if size == 0 { + this.write_null(ret.into())?; + } else { + let ptr = this.memory_mut().allocate( + Size::from_bytes(size), + Align::from_bytes(align).unwrap(), + MiriMemoryKind::C.into() + ); + this.write_scalar(Scalar::Ptr(ptr.with_default_tag()), ret.into())?; + } + this.write_null(dest)?; + } "free" => { let ptr = this.read_scalar(args[0])?.not_undef()?; diff --git a/tests/run-pass/heap.rs b/tests/run-pass/heap.rs index b533f91646988..8421dce9c21bf 100644 --- a/tests/run-pass/heap.rs +++ b/tests/run-pass/heap.rs @@ -1,4 +1,7 @@ #![feature(box_syntax)] +#![feature(allocator_api)] + +use std::alloc::{Global, Alloc, Layout, System}; fn make_box() -> Box<(i16, i16)> { Box::new((1, 2)) @@ -27,8 +30,31 @@ fn allocate_reallocate() { assert_eq!(s.capacity(), 9); } +fn check_overalign_requests(mut allocator: T) { + let size = 8; + let align = 16; // greater than size + let iterations = 1; // Miri is deterministic, no need to try many times + unsafe { + let pointers: Vec<_> = (0..iterations).map(|_| { + allocator.alloc(Layout::from_size_align(size, align).unwrap()).unwrap() + }).collect(); + for &ptr in &pointers { + assert_eq!((ptr.as_ptr() as usize) % align, 0, + "Got a pointer less aligned than requested") + } + + // Clean up + for &ptr in &pointers { + allocator.dealloc(ptr, Layout::from_size_align(size, align).unwrap()) + } + } +} + fn main() { assert_eq!(*make_box(), (1, 2)); assert_eq!(*make_box_syntax(), (1, 2)); allocate_reallocate(); + + check_overalign_requests(System); + check_overalign_requests(Global); } From 8466f78e83799ddee5f9bfd19f883c627036d096 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 13 Feb 2019 19:47:51 +0100 Subject: [PATCH 0571/3747] ignore overaligned tests on Windows (because, of course, Windows' API is broken here) --- tests/run-pass/heap.rs | 26 -------------------------- tests/run-pass/heap_system.rs | 29 +++++++++++++++++++++++++++++ 2 files changed, 29 insertions(+), 26 deletions(-) create mode 100644 tests/run-pass/heap_system.rs diff --git a/tests/run-pass/heap.rs b/tests/run-pass/heap.rs index 8421dce9c21bf..b533f91646988 100644 --- a/tests/run-pass/heap.rs +++ b/tests/run-pass/heap.rs @@ -1,7 +1,4 @@ #![feature(box_syntax)] -#![feature(allocator_api)] - -use std::alloc::{Global, Alloc, Layout, System}; fn make_box() -> Box<(i16, i16)> { Box::new((1, 2)) @@ -30,31 +27,8 @@ fn allocate_reallocate() { assert_eq!(s.capacity(), 9); } -fn check_overalign_requests(mut allocator: T) { - let size = 8; - let align = 16; // greater than size - let iterations = 1; // Miri is deterministic, no need to try many times - unsafe { - let pointers: Vec<_> = (0..iterations).map(|_| { - allocator.alloc(Layout::from_size_align(size, align).unwrap()).unwrap() - }).collect(); - for &ptr in &pointers { - assert_eq!((ptr.as_ptr() as usize) % align, 0, - "Got a pointer less aligned than requested") - } - - // Clean up - for &ptr in &pointers { - allocator.dealloc(ptr, Layout::from_size_align(size, align).unwrap()) - } - } -} - fn main() { assert_eq!(*make_box(), (1, 2)); assert_eq!(*make_box_syntax(), (1, 2)); allocate_reallocate(); - - check_overalign_requests(System); - check_overalign_requests(Global); } diff --git a/tests/run-pass/heap_system.rs b/tests/run-pass/heap_system.rs new file mode 100644 index 0000000000000..0eb2097047135 --- /dev/null +++ b/tests/run-pass/heap_system.rs @@ -0,0 +1,29 @@ +//ignore-windows: Inspects allocation base address on Windows +#![feature(allocator_api)] + +use std::alloc::{Global, Alloc, Layout, System}; + +fn check_overalign_requests(mut allocator: T) { + let size = 8; + let align = 16; // greater than size + let iterations = 1; // Miri is deterministic, no need to try many times + unsafe { + let pointers: Vec<_> = (0..iterations).map(|_| { + allocator.alloc(Layout::from_size_align(size, align).unwrap()).unwrap() + }).collect(); + for &ptr in &pointers { + assert_eq!((ptr.as_ptr() as usize) % align, 0, + "Got a pointer less aligned than requested") + } + + // Clean up + for &ptr in &pointers { + allocator.dealloc(ptr, Layout::from_size_align(size, align).unwrap()) + } + } +} + +fn main() { + check_overalign_requests(System); + check_overalign_requests(Global); +} From ad8a5d965bab87d662b3e9297e062e48e3ff3718 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 14 Feb 2019 08:33:48 +0100 Subject: [PATCH 0572/3747] bump Rust --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index b265e000950eb..edd1c533d9833 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -nightly-2019-02-13 +nightly-2019-02-14 From 457741d6d2eb6c869fb95ba76dae55daa44b5a3f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 8 Feb 2019 14:01:40 +0100 Subject: [PATCH 0573/3747] update for new bin_op APIs --- src/intrinsic.rs | 16 ++++++++-------- src/lib.rs | 8 +++----- src/operator.rs | 21 +++++++++++---------- 3 files changed, 22 insertions(+), 23 deletions(-) diff --git a/src/intrinsic.rs b/src/intrinsic.rs index 09df91b3ab388..5a9939db2e7da 100644 --- a/src/intrinsic.rs +++ b/src/intrinsic.rs @@ -5,7 +5,7 @@ use rustc::ty; use rustc::mir::interpret::{EvalResult, PointerArithmetic}; use crate::{ - PlaceTy, OpTy, Immediate, Scalar, ScalarMaybeUndef, Borrow, + PlaceTy, OpTy, ImmTy, Immediate, Scalar, ScalarMaybeUndef, Borrow, OperatorEvalContextExt }; @@ -80,11 +80,11 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, _ if intrinsic_name.starts_with("atomic_cxchg") => { let ptr = this.deref_operand(args[0])?; - let expect_old = this.read_immediate(args[1])?; // read as immediate for the sake of `binary_op_imm()` + let expect_old = this.read_immediate(args[1])?; // read as immediate for the sake of `binary_op()` let new = this.read_scalar(args[2])?; - let old = this.read_immediate(ptr.into())?; // read as immediate for the sake of `binary_op_imm()` - // binary_op_imm will bail if either of them is not a scalar - let (eq, _) = this.binary_op_imm(mir::BinOp::Eq, old, expect_old)?; + let old = this.read_immediate(ptr.into())?; // read as immediate for the sake of `binary_op()` + // binary_op will bail if either of them is not a scalar + let (eq, _) = this.binary_op(mir::BinOp::Eq, old, expect_old)?; let res = Immediate::ScalarPair(old.to_scalar_or_undef(), eq.into()); this.write_immediate(res, dest)?; // old value is returned // update ptr depending on comparison @@ -140,9 +140,9 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, _ => bug!(), }; // Atomics wrap around on overflow. - let (val, _overflowed) = this.binary_op_imm(op, old, rhs)?; + let (val, _overflowed) = this.binary_op(op, old, rhs)?; let val = if neg { - this.unary_op(mir::UnOp::Not, val, old.layout)? + this.unary_op(mir::UnOp::Not, ImmTy::from_scalar(val, old.layout))? } else { val }; @@ -239,7 +239,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, let a = this.read_immediate(args[0])?; let b = this.read_immediate(args[1])?; // check x % y != 0 - if this.binary_op_imm(mir::BinOp::Rem, a, b)?.0.to_bits(dest.layout.size)? != 0 { + if this.binary_op(mir::BinOp::Rem, a, b)?.0.to_bits(dest.layout.size)? != 0 { return err!(ValidationFailure(format!("exact_div: {:?} cannot be divided by {:?}", a, b))); } this.binop_ignore_overflow(mir::BinOp::Div, a, b, dest)?; diff --git a/src/lib.rs b/src/lib.rs index f59a476ed94e8..67bd54872f82a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -406,12 +406,10 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { fn ptr_op( ecx: &rustc_mir::interpret::EvalContext<'a, 'mir, 'tcx, Self>, bin_op: mir::BinOp, - left: Scalar, - left_layout: TyLayout<'tcx>, - right: Scalar, - right_layout: TyLayout<'tcx>, + left: ImmTy<'tcx, Borrow>, + right: ImmTy<'tcx, Borrow>, ) -> EvalResult<'tcx, (Scalar, bool)> { - ecx.ptr_op(bin_op, left, left_layout, right, right_layout) + ecx.ptr_op(bin_op, left, right) } fn box_alloc( diff --git a/src/operator.rs b/src/operator.rs index 4b110224a0a2d..0bdec0349778d 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -7,10 +7,8 @@ pub trait EvalContextExt<'tcx> { fn ptr_op( &self, bin_op: mir::BinOp, - left: Scalar, - left_layout: TyLayout<'tcx>, - right: Scalar, - right_layout: TyLayout<'tcx>, + left: ImmTy<'tcx, Borrow>, + right: ImmTy<'tcx, Borrow>, ) -> EvalResult<'tcx, (Scalar, bool)>; fn ptr_int_arithmetic( @@ -40,13 +38,16 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' fn ptr_op( &self, bin_op: mir::BinOp, - left: Scalar, - left_layout: TyLayout<'tcx>, - right: Scalar, - right_layout: TyLayout<'tcx>, + left: ImmTy<'tcx, Borrow>, + right: ImmTy<'tcx, Borrow>, ) -> EvalResult<'tcx, (Scalar, bool)> { use rustc::mir::BinOp::*; + let left_layout = left.layout; + let left = left.to_scalar()?; + let right_layout = right.layout; + let right = right.to_scalar()?; + trace!("ptr_op: {:?} {:?} {:?}", left, bin_op, right); debug_assert!(left.is_ptr() || right.is_ptr() || bin_op == Offset); @@ -85,8 +86,8 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' let layout = self.layout_of(self.tcx.types.usize)?; return self.binary_op( Sub, - left_offset, layout, - right_offset, layout, + ImmTy::from_scalar(left_offset, layout), + ImmTy::from_scalar(right_offset, layout), ) } _ => bug!("We already established it has to be one of these operators."), From 2c3ee678b127629396908199d298f66edb0b0b2d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 8 Feb 2019 16:27:00 +0100 Subject: [PATCH 0574/3747] Fix comparing fat pointers --- src/lib.rs | 2 +- src/operator.rs | 31 +++++++++++++++++++++---------- tests/run-pass/rc.rs | 10 ++++++++++ 3 files changed, 32 insertions(+), 11 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 67bd54872f82a..1608bc1f3028b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -17,7 +17,7 @@ use std::collections::HashMap; use std::borrow::Cow; use rustc::ty::{self, TyCtxt, query::TyCtxtAt}; -use rustc::ty::layout::{TyLayout, LayoutOf, Size, Align}; +use rustc::ty::layout::{LayoutOf, Size, Align}; use rustc::hir::{self, def_id::DefId}; use rustc::mir; diff --git a/src/operator.rs b/src/operator.rs index 0bdec0349778d..b64ccf5462d6a 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -1,4 +1,4 @@ -use rustc::ty::{Ty, layout::TyLayout}; +use rustc::ty::Ty; use rustc::mir; use crate::*; @@ -23,7 +23,6 @@ pub trait EvalContextExt<'tcx> { &self, left: Scalar, right: Scalar, - size: Size, ) -> EvalResult<'tcx, bool>; fn pointer_offset_inbounds( @@ -43,12 +42,29 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' ) -> EvalResult<'tcx, (Scalar, bool)> { use rustc::mir::BinOp::*; + trace!("ptr_op: {:?} {:?} {:?}", *left, bin_op, *right); + + // Operations that support fat pointers + match bin_op { + Eq | Ne => { + let eq = match (*left, *right) { + (Immediate::Scalar(left), Immediate::Scalar(right)) => + self.ptr_eq(left.not_undef()?, right.not_undef()?)?, + (Immediate::ScalarPair(left1, left2), Immediate::ScalarPair(right1, right2)) => + self.ptr_eq(left1.not_undef()?, right1.not_undef()?)? && + self.ptr_eq(left2.not_undef()?, right2.not_undef()?)?, + _ => bug!("Type system should not allow comparing Scalar with ScalarPair"), + }; + return Ok((Scalar::from_bool(if bin_op == Eq { eq } else { !eq }), false)); + } + _ => {}, + } + + // Now we expect no more fat pointers let left_layout = left.layout; let left = left.to_scalar()?; let right_layout = right.layout; let right = right.to_scalar()?; - - trace!("ptr_op: {:?} {:?} {:?}", left, bin_op, right); debug_assert!(left.is_ptr() || right.is_ptr() || bin_op == Offset); match bin_op { @@ -64,11 +80,6 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' )?; Ok((ptr, false)) } - // These work on anything - Eq => - Ok((Scalar::from_bool(self.ptr_eq(left, right, left_layout.size)?), false)), - Ne => - Ok((Scalar::from_bool(!self.ptr_eq(left, right, left_layout.size)?), false)), // These need both to be pointer, and fail if they are not in the same location Lt | Le | Gt | Ge | Sub if left.is_ptr() && right.is_ptr() => { let left = left.to_ptr().expect("we checked is_ptr"); @@ -127,8 +138,8 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' &self, left: Scalar, right: Scalar, - size: Size, ) -> EvalResult<'tcx, bool> { + let size = self.pointer_size(); Ok(match (left, right) { (Scalar::Bits { .. }, Scalar::Bits { .. }) => left.to_bits(size)? == right.to_bits(size)?, diff --git a/tests/run-pass/rc.rs b/tests/run-pass/rc.rs index bc89d752e0b62..af68e5cfd1faa 100644 --- a/tests/run-pass/rc.rs +++ b/tests/run-pass/rc.rs @@ -1,6 +1,7 @@ use std::cell::{Cell, RefCell}; use std::rc::Rc; use std::sync::Arc; +use std::fmt::Debug; fn rc_refcell() { let r = Rc::new(RefCell::new(42)); @@ -60,7 +61,16 @@ fn rc_from() { check_unique_rc::(Rc::from("Hello, World!")); } +fn rc_fat_ptr_eq() { + let p = Rc::new(1) as Rc; + let a: *const Debug = &*p; + let r = Rc::into_raw(p); + let _b = a == r; + drop(unsafe { Rc::from_raw(r) }); +} + fn main() { + rc_fat_ptr_eq(); rc_refcell(); rc_refcell2(); rc_cell(); From 1921fa5766292a8b4ddd6c44deaedccfb2f85b7e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 8 Feb 2019 23:48:37 +0100 Subject: [PATCH 0575/3747] actually they should be equal --- tests/run-pass/rc.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/run-pass/rc.rs b/tests/run-pass/rc.rs index af68e5cfd1faa..164842ab4d976 100644 --- a/tests/run-pass/rc.rs +++ b/tests/run-pass/rc.rs @@ -65,7 +65,7 @@ fn rc_fat_ptr_eq() { let p = Rc::new(1) as Rc; let a: *const Debug = &*p; let r = Rc::into_raw(p); - let _b = a == r; + assert!(a == r); drop(unsafe { Rc::from_raw(r) }); } From 9397b36ab813376d5af354c25f8d875b281802c9 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 13 Feb 2019 17:21:46 +0100 Subject: [PATCH 0576/3747] typo and comments --- src/bin/cargo-miri.rs | 2 +- tests/run-pass/hashmap.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index bca2b6df1b40b..0de835f45d0a8 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -266,7 +266,7 @@ path = "lib.rs" let sysroot = if is_host { dir.join("HOST") } else { PathBuf::from(dir) }; std::env::set_var("MIRI_SYSROOT", &sysroot); if !ask_user { - println!("A libstd for miri is now available in `{}`", sysroot.display()); + println!("A libstd for Miri is now available in `{}`", sysroot.display()); } } diff --git a/tests/run-pass/hashmap.rs b/tests/run-pass/hashmap.rs index f4a358174f555..d89a5ab535f64 100644 --- a/tests/run-pass/hashmap.rs +++ b/tests/run-pass/hashmap.rs @@ -21,5 +21,5 @@ fn main() { } assert_eq!(map.values().fold(0, |x, y| x+y), num*(num-1)/2); - // TODO: Test Entry API + // TODO: Test Entry API, Iterators, ... } From 15722fab51fadd484694dd01498f35ebba2b1999 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 15 Feb 2019 08:28:02 +0100 Subject: [PATCH 0577/3747] update Rust --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index edd1c533d9833..cb6d9f177dded 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -nightly-2019-02-14 +nightly-2019-02-15 From e630175867b00a81e4125ece04e5f14cc88d9970 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 15 Feb 2019 09:32:54 +0100 Subject: [PATCH 0578/3747] fix async-fn test --- tests/run-pass/async-fn.rs | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/tests/run-pass/async-fn.rs b/tests/run-pass/async-fn.rs index 9094a9fd3a680..48f8fc1223c94 100644 --- a/tests/run-pass/async-fn.rs +++ b/tests/run-pass/async-fn.rs @@ -4,7 +4,8 @@ futures_api, )] -use std::{future::Future, pin::Pin, task::Poll}; +use std::{future::Future, pin::Pin, task::Poll, ptr}; +use std::task::{Waker, RawWaker, RawWakerVTable}; // See if we can run a basic `async fn` pub async fn foo(x: &u32, y: u32) -> u32 { @@ -17,18 +18,23 @@ pub async fn foo(x: &u32, y: u32) -> u32 { *x + y + *a } -fn main() { - use std::{sync::Arc, task::{Wake, local_waker}}; +fn raw_waker_clone(_this: *const ()) -> RawWaker { + panic!("unimplemented"); +} +fn raw_waker_wake(_this: *const ()) { + panic!("unimplemented"); +} +fn raw_waker_drop(_this: *const ()) {} - struct NoWake; - impl Wake for NoWake { - fn wake(_arc_self: &Arc) { - panic!(); - } - } +static RAW_WAKER: RawWakerVTable = RawWakerVTable { + clone: raw_waker_clone, + wake: raw_waker_wake, + drop: raw_waker_drop, +}; - let lw = unsafe { local_waker(Arc::new(NoWake)) }; +fn main() { let x = 5; let mut fut = foo(&x, 7); - assert_eq!(unsafe { Pin::new_unchecked(&mut fut) }.poll(&lw), Poll::Ready(31)); + let waker = unsafe { Waker::new_unchecked(RawWaker::new(ptr::null(), &RAW_WAKER)) }; + assert_eq!(unsafe { Pin::new_unchecked(&mut fut) }.poll(&waker), Poll::Ready(31)); } From 5190b5b1e817977994ddb7afd2c27a1a9818236a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 15 Feb 2019 10:41:12 +0100 Subject: [PATCH 0579/3747] test VecDeque debug printing --- tests/run-pass/vecdeque.rs | 8 ++++++++ tests/run-pass/vecdeque.stdout | 2 ++ 2 files changed, 10 insertions(+) create mode 100644 tests/run-pass/vecdeque.stdout diff --git a/tests/run-pass/vecdeque.rs b/tests/run-pass/vecdeque.rs index 381169505ec9f..9c9909802e207 100644 --- a/tests/run-pass/vecdeque.rs +++ b/tests/run-pass/vecdeque.rs @@ -9,6 +9,14 @@ fn main() { let mut src = VecDeque::new(); src.push_front(Box::new(2)); dst.append(&mut src); + for a in dst.iter() { + assert_eq!(**a, 2); + } + + // Regression test for Debug and Diaplay impl's + println!("{:?} {:?}", dst, dst.iter()); + println!("{:?}", VecDeque::::new().iter()); + for a in dst { assert_eq!(*a, 2); } diff --git a/tests/run-pass/vecdeque.stdout b/tests/run-pass/vecdeque.stdout new file mode 100644 index 0000000000000..63de960ee2bdf --- /dev/null +++ b/tests/run-pass/vecdeque.stdout @@ -0,0 +1,2 @@ +[2, 2] Iter([2, 2], []) +Iter([], []) From a3eae6c8ab0ac190066c8ebefb0ef0314aa1e7ef Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 15 Feb 2019 10:41:25 +0100 Subject: [PATCH 0580/3747] collect some bugs that we found --- README.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/README.md b/README.md index 21e9fa43a8f8c..a9e9ee0a1e3cf 100644 --- a/README.md +++ b/README.md @@ -252,6 +252,18 @@ used according to their aliasing restrictions. [slides]: https://solson.me/miri-slides.pdf [report]: https://solson.me/miri-report.pdf +## Bugs found by Miri + +Miri has already found a number of bugs in the Rust standard library, which we collect here. + +* [`vec_deque::Iter` having an unsound `Debug` implementation](https://github.com/rust-lang/rust/issues/53566) +* [`From<&[T]> for Rc` creating a not sufficiently aligned reference](https://github.com/rust-lang/rust/issues/54908) +* [`BTreeMap` creating a shared reference pointing to a too small allocation](https://github.com/rust-lang/rust/issues/54957) +* [`VecDeque` creating overlapping mutable references](https://github.com/rust-lang/rust/pull/56161) +* [Futures turning a shared reference into a mutable one](https://github.com/rust-lang/rust/pull/56319) +* [`str` turning a shared reference into a mutable one](https://github.com/rust-lang/rust/pull/58200) +* [`BTreeMap` creating mutable references that overlap with shared references](https://github.com/rust-lang/rust/pull/58431) + ## License Licensed under either of From a4c852ddfe95b8726ca4e23f49290f2a561dbd40 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 15 Feb 2019 10:43:27 +0100 Subject: [PATCH 0581/3747] link to bug list from intro --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index a9e9ee0a1e3cf..897bf0b66e7e0 100644 --- a/README.md +++ b/README.md @@ -15,6 +15,8 @@ for example: or an invalid enum discriminant) * WIP: Violations of the rules governing aliasing for reference types +Miri has already discovered some [real-world bugs](#bugs-found-by-miri). + [rust]: https://www.rust-lang.org/ [mir]: https://github.com/rust-lang/rfcs/blob/master/text/1211-mir.md [`unreachable_unchecked`]: https://doc.rust-lang.org/stable/std/hint/fn.unreachable_unchecked.html @@ -256,7 +258,7 @@ used according to their aliasing restrictions. Miri has already found a number of bugs in the Rust standard library, which we collect here. -* [`vec_deque::Iter` having an unsound `Debug` implementation](https://github.com/rust-lang/rust/issues/53566) +* [`Debug for vec_deque::Iter` accessing uninitialized memory](https://github.com/rust-lang/rust/issues/53566) * [`From<&[T]> for Rc` creating a not sufficiently aligned reference](https://github.com/rust-lang/rust/issues/54908) * [`BTreeMap` creating a shared reference pointing to a too small allocation](https://github.com/rust-lang/rust/issues/54957) * [`VecDeque` creating overlapping mutable references](https://github.com/rust-lang/rust/pull/56161) From 17e05540adadd4643aab3098cc594801c9532d77 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 17 Feb 2019 12:09:38 +0100 Subject: [PATCH 0582/3747] we can't have profiles because we are also in the rustc worksapce --- Cargo.toml | 3 --- 1 file changed, 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 721ebe5cfd46b..da876423ce9bb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -56,6 +56,3 @@ rustc_tests = [] [dev-dependencies] compiletest_rs = { version = "0.3.17", features = ["tmp"] } colored = "1.6" - -[profile.release] -debug = true From edd9e5b7b12ed1093a87ba51e25443f7e1098c4f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 13 Feb 2019 17:22:06 +0100 Subject: [PATCH 0583/3747] test BTree a bit more --- tests/run-pass/btreemap.rs | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/tests/run-pass/btreemap.rs b/tests/run-pass/btreemap.rs index b7140d72ac3a6..e2049d9480322 100644 --- a/tests/run-pass/btreemap.rs +++ b/tests/run-pass/btreemap.rs @@ -1,3 +1,5 @@ +use std::collections::{BTreeMap, BTreeSet}; + #[derive(PartialEq, Eq, PartialOrd, Ord)] pub enum Foo { A(&'static str), @@ -6,11 +8,22 @@ pub enum Foo { } pub fn main() { - let mut b = std::collections::BTreeSet::new(); + let mut b = BTreeSet::new(); b.insert(Foo::A("\'")); b.insert(Foo::A("/=")); b.insert(Foo::A("#")); b.insert(Foo::A("0o")); assert!(b.remove(&Foo::A("/="))); assert!(!b.remove(&Foo::A("/="))); + + // Also test a lower-alignment type, where the NodeHeader overlaps with + // the keys. + let mut b = BTreeSet::new(); + b.insert(1024); + b.insert(7); + + let mut b = BTreeMap::new(); + b.insert("bar", 1024); + b.insert("baz", 7); + for _val in b.iter_mut() {} } From 441442e07113ae9cad93243fb6e178b1b6b1665e Mon Sep 17 00:00:00 2001 From: Taiki Endo Date: Sat, 23 Feb 2019 19:56:29 +0900 Subject: [PATCH 0584/3747] Update some links --- Cargo.toml | 2 +- README.md | 6 +++--- tests/run-pass/validation_lifetime_resolution.rs | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index da876423ce9bb..1a1a1fa2330ae 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,7 +5,7 @@ authors = ["Scott Olson "] description = "An experimental interpreter for Rust MIR." license = "MIT/Apache-2.0" name = "miri" -repository = "https://github.com/solson/miri" +repository = "https://github.com/rust-lang/miri" version = "0.1.0" build = "build.rs" default-run = "miri" diff --git a/README.md b/README.md index 897bf0b66e7e0..856e1273131a7 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Miri [![Build Status](https://travis-ci.org/solson/miri.svg?branch=master)](https://travis-ci.org/solson/miri) [![Windows build status](https://ci.appveyor.com/api/projects/status/github/solson/miri?svg=true)](https://ci.appveyor.com/project/solson63299/miri) +# Miri [![Build Status](https://travis-ci.com/rust-lang/miri.svg?branch=master)](https://travis-ci.com/rust-lang/miri) [![Windows build status](https://ci.appveyor.com/api/projects/status/github/rust-lang/miri?svg=true)](https://ci.appveyor.com/project/rust-lang-libs/miri) An experimental interpreter for [Rust][rust]'s @@ -28,11 +28,11 @@ Miri has already discovered some [real-world bugs](#bugs-found-by-miri). Install Miri as a cargo subcommand: ```sh -cargo +nightly install --force --git https://github.com/solson/miri miri +cargo +nightly install --force --git https://github.com/rust-lang/miri miri ``` If this does not work, try using the nightly version given in -[this file](https://raw.githubusercontent.com/solson/miri/master/rust-version). CI +[this file](https://raw.githubusercontent.com/rust-lang/miri/master/rust-version). CI should ensure that this nightly always works. You have to use a consistent Rust version for building miri and your project, so diff --git a/tests/run-pass/validation_lifetime_resolution.rs b/tests/run-pass/validation_lifetime_resolution.rs index 4d919f735255d..3375632c9d70b 100644 --- a/tests/run-pass/validation_lifetime_resolution.rs +++ b/tests/run-pass/validation_lifetime_resolution.rs @@ -22,7 +22,7 @@ fn foo(mut x: T) where for<'a> &'a mut T: Id let _y = x.id(); // Inspecting the trace should show that _y has a type involving a local lifetime, when it gets validated. // Unfortunately, there doesn't seem to be a way to actually have a test fail if it does not have the right - // type. Currently, this is NOT working correctly; see . + // type. Currently, this is NOT working correctly; see . } fn main() { From acc304c0bd3f5459c104be99a3270d7909988b55 Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Sun, 24 Feb 2019 08:16:21 +0000 Subject: [PATCH 0585/3747] Remove test of two-phase borrows in match --- tests/run-pass/2phase.rs | 9 --------- 1 file changed, 9 deletions(-) diff --git a/tests/run-pass/2phase.rs b/tests/run-pass/2phase.rs index 987adca477a6f..5ca0ff5d8df86 100644 --- a/tests/run-pass/2phase.rs +++ b/tests/run-pass/2phase.rs @@ -43,14 +43,6 @@ fn two_phase_overlapping2() { } */ -fn match_two_phase() { - let mut x = 3; - match x { - ref mut y if { let _val = x; let _val = *y; true } => {}, - _ => (), - } -} - fn with_interior_mutability() { use std::cell::Cell; @@ -76,7 +68,6 @@ fn main() { two_phase2(); two_phase3(false); two_phase3(true); - match_two_phase(); with_interior_mutability(); //FIXME: enable these, or remove them, depending on how https://github.com/rust-lang/rust/issues/56254 gets resolved //two_phase_overlapping1(); From 8a779bc260646f7fb16ab24a463ad977a9e05c90 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 24 Feb 2019 12:22:53 +0100 Subject: [PATCH 0586/3747] bump Rust --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index cb6d9f177dded..091e10fde3c24 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -nightly-2019-02-15 +nightly-2019-02-24 From ac23bcd2980c98cf6145524f31c63320431d5d4a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 25 Feb 2019 09:47:34 +0100 Subject: [PATCH 0587/3747] test using the Global allocator trait to alloc/free a Box --- .../{heap_system.rs => heap_allocator.rs} | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) rename tests/run-pass/{heap_system.rs => heap_allocator.rs} (57%) diff --git a/tests/run-pass/heap_system.rs b/tests/run-pass/heap_allocator.rs similarity index 57% rename from tests/run-pass/heap_system.rs rename to tests/run-pass/heap_allocator.rs index 0eb2097047135..e1aace8cecaf1 100644 --- a/tests/run-pass/heap_system.rs +++ b/tests/run-pass/heap_allocator.rs @@ -1,6 +1,7 @@ //ignore-windows: Inspects allocation base address on Windows #![feature(allocator_api)] +use std::ptr::NonNull; use std::alloc::{Global, Alloc, Layout, System}; fn check_overalign_requests(mut allocator: T) { @@ -23,7 +24,31 @@ fn check_overalign_requests(mut allocator: T) { } } +fn global_to_box() { + type T = [i32; 4]; + let l = Layout::new::(); + // allocate manually with global allocator, then turn into Box and free there + unsafe { + let ptr = Global.alloc(l).unwrap().as_ptr() as *mut T; + let b = Box::from_raw(ptr); + drop(b); + } +} + +fn box_to_global() { + type T = [i32; 4]; + let l = Layout::new::(); + // allocate with the Box, then deallocate manually with global allocator + unsafe { + let b = Box::new(T::default()); + let ptr = Box::into_raw(b); + Global.dealloc(NonNull::new(ptr as *mut u8).unwrap(), l); + } +} + fn main() { check_overalign_requests(System); check_overalign_requests(Global); + global_to_box(); + box_to_global(); } From b1c0cf2ef94eec6a8e84e1a1d91fb561a1f50519 Mon Sep 17 00:00:00 2001 From: rchaser53 Date: Mon, 25 Feb 2019 00:08:38 +0900 Subject: [PATCH 0588/3747] use copy_op directly insteadof write_scalar - fix volatile_store logic - rename test to be able to read back from later - expand test to use assert_eq! and confirm to fix volatile_store - expand test to use assert_eq! and confirm normal load --- src/intrinsic.rs | 16 ++++++++++++---- tests/run-pass/volatile.rs | 12 ++++++++++++ 2 files changed, 24 insertions(+), 4 deletions(-) create mode 100644 tests/run-pass/volatile.rs diff --git a/src/intrinsic.rs b/src/intrinsic.rs index 5a9939db2e7da..6f9dfb3971675 100644 --- a/src/intrinsic.rs +++ b/src/intrinsic.rs @@ -50,22 +50,30 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, "atomic_load" | "atomic_load_relaxed" | - "atomic_load_acq" | - "volatile_load" => { + "atomic_load_acq" => { let ptr = this.deref_operand(args[0])?; let val = this.read_scalar(ptr.into())?; // make sure it fits into a scalar; otherwise it cannot be atomic this.write_scalar(val, dest)?; } + "volatile_load" => { + let ptr = this.deref_operand(args[0])?; + this.copy_op(ptr.into(), dest)?; + } + "atomic_store" | "atomic_store_relaxed" | - "atomic_store_rel" | - "volatile_store" => { + "atomic_store_rel" => { let ptr = this.deref_operand(args[0])?; let val = this.read_scalar(args[1])?; // make sure it fits into a scalar; otherwise it cannot be atomic this.write_scalar(val, ptr.into())?; } + "volatile_store" => { + let ptr = this.deref_operand(args[0])?; + this.copy_op(args[1], ptr.into())?; + } + "atomic_fence_acq" => { // we are inherently singlethreaded and singlecored, this is a nop } diff --git a/tests/run-pass/volatile.rs b/tests/run-pass/volatile.rs new file mode 100644 index 0000000000000..c9799801455c6 --- /dev/null +++ b/tests/run-pass/volatile.rs @@ -0,0 +1,12 @@ +// related: #58645 +#![feature(core_intrinsics)] +use std::intrinsics::{volatile_load, volatile_store}; + +pub fn main() { + unsafe { + let i: &mut (isize, isize) = &mut (0, 0); + volatile_store(i, (1, 2)); + assert_eq!(volatile_load(i), (1, 2)); + assert_eq!(i, &mut (1, 2)); + } +} From a478bfebd2aef26287268fd0c0e255184a24a7a1 Mon Sep 17 00:00:00 2001 From: Alexander Regueiro Date: Sat, 16 Feb 2019 01:43:56 +0000 Subject: [PATCH 0589/3747] Removed copyright notices. --- tests/compile-fail/copy_nonoverlapping.rs | 10 ---------- tests/compile-fail/copy_null.rs | 12 +----------- tests/compile-fail/copy_unaligned.rs | 10 ---------- tests/compile-fail/div-by-zero-1.rs | 10 ---------- tests/compile-fail/div-by-zero-2.rs | 10 ---------- tests/compile-fail/overflowing-lsh-neg.rs | 10 ---------- tests/compile-fail/overflowing-rsh-1.rs | 10 ---------- tests/compile-fail/overflowing-rsh-2.rs | 10 ---------- tests/compile-fail/overflowing-unchecked-rsh.rs | 10 ---------- tests/compile-fail/ptr_offset_ptr_plus_0.rs | 2 +- tests/compile-fail/reading_half_a_pointer.rs | 2 +- .../stacked_borrows/illegal_read1.rs | 2 +- .../stacked_borrows/illegal_read2.rs | 2 +- .../stacked_borrows/illegal_read3.rs | 16 +++++++++------- .../stacked_borrows/illegal_read5.rs | 2 +- .../stacked_borrows/illegal_write5.rs | 9 +++++---- tests/compile-fail/transmute-pair-undef.rs | 6 ++++-- tests/compile-fail/unaligned_ptr_cast2.rs | 9 +++++---- tests/compile-fail/unaligned_ptr_cast_zst.rs | 5 +++-- tests/compile-fail/validity/cast_fn_ptr1.rs | 5 +++-- tests/compile-fail/validity/cast_fn_ptr2.rs | 5 +++-- tests/compiletest.rs | 4 ++-- tests/run-pass/associated-const.rs | 10 ---------- tests/run-pass/atomic-access-bool.rs | 10 ---------- tests/run-pass/atomic-compare_exchange.rs | 10 ---------- tests/run-pass/binops.rs | 10 ---------- tests/run-pass/cast-rfc0401-vtable-kinds.rs | 10 ---------- tests/run-pass/deriving-associated-types.rs | 10 ---------- tests/run-pass/dst-field-align.rs | 10 ---------- tests/run-pass/dst-irrefutable-bind.rs | 10 ---------- tests/run-pass/dst-raw.rs | 10 ---------- tests/run-pass/dst-struct-sole.rs | 10 ---------- tests/run-pass/dst-struct.rs | 10 ---------- .../enum-nullable-const-null-with-fields.rs | 10 ---------- tests/run-pass/float_fast_math.rs | 10 ---------- tests/run-pass/foreign-fn-linkname.rs | 10 ---------- tests/run-pass/generator.rs | 10 ---------- tests/run-pass/issue-15063.rs | 10 ---------- tests/run-pass/issue-15080.rs | 10 ---------- tests/run-pass/issue-15523-big.rs | 10 ---------- tests/run-pass/issue-17877.rs | 10 ---------- tests/run-pass/issue-20575.rs | 10 ---------- tests/run-pass/issue-23261.rs | 10 ---------- tests/run-pass/issue-26709.rs | 10 ---------- tests/run-pass/issue-27901.rs | 10 ---------- tests/run-pass/issue-29746.rs | 10 ---------- tests/run-pass/issue-31267-additional.rs | 10 ---------- tests/run-pass/issue-33387.rs | 10 ---------- tests/run-pass/issue-34571.rs | 10 ---------- tests/run-pass/issue-35815.rs | 10 ---------- tests/run-pass/issue-36278-prefix-nesting.rs | 10 ---------- tests/run-pass/issue-3794.rs | 10 ---------- tests/run-pass/issue-5917.rs | 10 ---------- tests/run-pass/last-use-in-cap-clause.rs | 10 ---------- tests/run-pass/loop-break-value.rs | 10 ---------- tests/run-pass/mir_coercions.rs | 10 ---------- tests/run-pass/mir_fat_ptr.rs | 10 ---------- tests/run-pass/move-arg-2-unique.rs | 10 ---------- tests/run-pass/move-arg-3-unique.rs | 10 ---------- tests/run-pass/overloaded-calls-simple.rs | 10 ---------- tests/run-pass/ref-invalid-ptr.rs | 6 +++--- .../regions-lifetime-nonfree-late-bound.rs | 14 ++------------ tests/run-pass/regions-mock-trans.rs | 10 ---------- tests/run-pass/rfc1623.rs | 10 ---------- tests/run-pass/send-is-not-static-par-for.rs | 10 ---------- tests/run-pass/sendable-class.rs | 10 ---------- .../run-pass/simd-intrinsic-generic-elements.rs | 10 ---------- tests/run-pass/stacked-borrows.rs | 6 +++--- tests/run-pass/try-operator-custom.rs | 10 ---------- tests/run-pass/u128.rs | 10 ---------- tests/run-pass/union-overwrite.rs | 10 ---------- tests/run-pass/unique-send.rs | 10 ---------- tests/run-pass/unsized-tuple-impls.rs | 10 ---------- tests/run-pass/validation_lifetime_resolution.rs | 4 ++-- tests/run-pass/vec-matching-fold.rs | 10 ---------- tests/run-pass/zero-sized-binary-heap-push.rs | 10 ---------- tests/run-pass/zst.rs | 6 +++--- 77 files changed, 53 insertions(+), 644 deletions(-) diff --git a/tests/compile-fail/copy_nonoverlapping.rs b/tests/compile-fail/copy_nonoverlapping.rs index 8e8912c81fe90..748bccff5d3ac 100644 --- a/tests/compile-fail/copy_nonoverlapping.rs +++ b/tests/compile-fail/copy_nonoverlapping.rs @@ -1,13 +1,3 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![feature(core_intrinsics)] //error-pattern: copy_nonoverlapping called on overlapping ranges diff --git a/tests/compile-fail/copy_null.rs b/tests/compile-fail/copy_null.rs index e46e327e6111e..08391b12ae1bc 100644 --- a/tests/compile-fail/copy_null.rs +++ b/tests/compile-fail/copy_null.rs @@ -1,18 +1,8 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - //error-pattern: invalid use of NULL pointer fn main() { let mut data = [0u16; 4]; let ptr = &mut data[0] as *mut u16; - // Even copying 0 elements from NULL should error + // Even copying 0 elements from NULL should error. unsafe { ptr.copy_from(std::ptr::null(), 0); } } diff --git a/tests/compile-fail/copy_unaligned.rs b/tests/compile-fail/copy_unaligned.rs index 0f04dc68db90c..e1f243210ade0 100644 --- a/tests/compile-fail/copy_unaligned.rs +++ b/tests/compile-fail/copy_unaligned.rs @@ -1,13 +1,3 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - //error-pattern: tried to access memory with alignment 1, but alignment 2 is required fn main() { diff --git a/tests/compile-fail/div-by-zero-1.rs b/tests/compile-fail/div-by-zero-1.rs index 4ac6214d88abb..987c18e4c492a 100644 --- a/tests/compile-fail/div-by-zero-1.rs +++ b/tests/compile-fail/div-by-zero-1.rs @@ -1,13 +1,3 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![feature(core_intrinsics)] use std::intrinsics::*; diff --git a/tests/compile-fail/div-by-zero-2.rs b/tests/compile-fail/div-by-zero-2.rs index 181a41ce3b23e..302d26a41f369 100644 --- a/tests/compile-fail/div-by-zero-2.rs +++ b/tests/compile-fail/div-by-zero-2.rs @@ -1,13 +1,3 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![allow(const_err)] fn main() { diff --git a/tests/compile-fail/overflowing-lsh-neg.rs b/tests/compile-fail/overflowing-lsh-neg.rs index 8c70c9c7df7dd..253294d1f53b7 100644 --- a/tests/compile-fail/overflowing-lsh-neg.rs +++ b/tests/compile-fail/overflowing-lsh-neg.rs @@ -1,13 +1,3 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![allow(exceeding_bitshifts)] #![allow(const_err)] diff --git a/tests/compile-fail/overflowing-rsh-1.rs b/tests/compile-fail/overflowing-rsh-1.rs index 355cbd8698888..7a4646a0ebf3a 100644 --- a/tests/compile-fail/overflowing-rsh-1.rs +++ b/tests/compile-fail/overflowing-rsh-1.rs @@ -1,13 +1,3 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![allow(exceeding_bitshifts)] fn main() { diff --git a/tests/compile-fail/overflowing-rsh-2.rs b/tests/compile-fail/overflowing-rsh-2.rs index 7b7486343c335..3f7f31f4c2351 100644 --- a/tests/compile-fail/overflowing-rsh-2.rs +++ b/tests/compile-fail/overflowing-rsh-2.rs @@ -1,13 +1,3 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![allow(exceeding_bitshifts, const_err)] fn main() { diff --git a/tests/compile-fail/overflowing-unchecked-rsh.rs b/tests/compile-fail/overflowing-unchecked-rsh.rs index b8291e1300edf..0d67aef430883 100644 --- a/tests/compile-fail/overflowing-unchecked-rsh.rs +++ b/tests/compile-fail/overflowing-unchecked-rsh.rs @@ -1,13 +1,3 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![feature(core_intrinsics)] use std::intrinsics::*; diff --git a/tests/compile-fail/ptr_offset_ptr_plus_0.rs b/tests/compile-fail/ptr_offset_ptr_plus_0.rs index 46937b1c8ce41..a089a8b821316 100644 --- a/tests/compile-fail/ptr_offset_ptr_plus_0.rs +++ b/tests/compile-fail/ptr_offset_ptr_plus_0.rs @@ -2,6 +2,6 @@ fn main() { let x = Box::into_raw(Box::new(0u32)); - let x = x.wrapping_offset(8); // okay, this has no inbounds tag + let x = x.wrapping_offset(8); // ok, this has no inbounds tag let _x = unsafe { x.offset(0) }; // UB despite offset 0, the pointer is not inbounds of the only object it can point to } diff --git a/tests/compile-fail/reading_half_a_pointer.rs b/tests/compile-fail/reading_half_a_pointer.rs index 049dfca340ed9..f8e9e5781e39d 100644 --- a/tests/compile-fail/reading_half_a_pointer.rs +++ b/tests/compile-fail/reading_half_a_pointer.rs @@ -20,7 +20,7 @@ fn main() { // Get a pointer to the beginning of the Data struct (one u8 byte, then the pointer bytes). // Thanks to the wrapper, we know this is aligned-enough to perform a load at ptr size. - // We load at pointer type, so having a relocation is okay -- but here, the relocation + // We load at pointer type, so having a relocation is ok -- but here, the relocation // starts 1 byte to the right, so using it would actually be wrong! let d_alias = &mut w.data as *mut _ as *mut *const u8; unsafe { diff --git a/tests/compile-fail/stacked_borrows/illegal_read1.rs b/tests/compile-fail/stacked_borrows/illegal_read1.rs index 0181f739a899d..3fb38abefdae4 100644 --- a/tests/compile-fail/stacked_borrows/illegal_read1.rs +++ b/tests/compile-fail/stacked_borrows/illegal_read1.rs @@ -4,7 +4,7 @@ fn main() { let mut x = 15; let xraw = &mut x as *mut _; - let xref = unsafe { &mut *xraw }; // derived from raw, so using raw is still okay... + let xref = unsafe { &mut *xraw }; // derived from raw, so using raw is still ok... callee(xraw); let _val = *xref; // ...but any use of raw will invalidate our ref. //~^ ERROR: does not exist on the borrow stack diff --git a/tests/compile-fail/stacked_borrows/illegal_read2.rs b/tests/compile-fail/stacked_borrows/illegal_read2.rs index b55fe1c6c88a4..e43340f0b8eed 100644 --- a/tests/compile-fail/stacked_borrows/illegal_read2.rs +++ b/tests/compile-fail/stacked_borrows/illegal_read2.rs @@ -4,7 +4,7 @@ fn main() { let mut x = 15; let xraw = &mut x as *mut _; - let xref = unsafe { &mut *xraw }; // derived from raw, so using raw is still okay... + let xref = unsafe { &mut *xraw }; // derived from raw, so using raw is still ok... callee(xraw); let _val = *xref; // ...but any use of raw will invalidate our ref. //~^ ERROR: does not exist on the borrow stack diff --git a/tests/compile-fail/stacked_borrows/illegal_read3.rs b/tests/compile-fail/stacked_borrows/illegal_read3.rs index 9da4ca09606e7..b4abbb4a1aedf 100644 --- a/tests/compile-fail/stacked_borrows/illegal_read3.rs +++ b/tests/compile-fail/stacked_borrows/illegal_read3.rs @@ -1,8 +1,8 @@ -#![feature(untagged_unions)] -// A callee may not read the destination of our `&mut` without -// us noticing. +// A callee may not read the destination of our `&mut` without us noticing. // Thise code got carefully checked to not introduce any reborrows -// that are not explicit in the source. Let's hope the compiler does not break this later! +// that are not explicit in the source. Let's hope the compiler does not break this later! + +#![feature(untagged_unions)] use std::mem; @@ -10,14 +10,16 @@ fn main() { let mut x: i32 = 15; let xref1 = &mut x; let xref1_sneaky: usize = unsafe { mem::transmute_copy(&xref1) }; - let xref2 = &mut *xref1; // derived from xref1, so using raw is still okay... + // Derived from `xref1`, so using raw value is still ok, ... + let xref2 = &mut *xref1; callee(xref1_sneaky); - let _val = *xref2; // ...but any use of it will invalidate our ref. + // ... though any use of it will invalidate our ref. + let _val = *xref2; //~^ ERROR: does not exist on the borrow stack } fn callee(xref1: usize) { - // Transmuting through a union to avoid retagging + // Transmuting through a union to avoid retagging. union UsizeToRef { from: usize, to: &'static mut i32, diff --git a/tests/compile-fail/stacked_borrows/illegal_read5.rs b/tests/compile-fail/stacked_borrows/illegal_read5.rs index 5f800e754a5d0..0f4737f16e63d 100644 --- a/tests/compile-fail/stacked_borrows/illegal_read5.rs +++ b/tests/compile-fail/stacked_borrows/illegal_read5.rs @@ -8,7 +8,7 @@ fn main() { let rc = RefCell::new(0); let mut refmut = rc.borrow_mut(); let xref: &mut i32 = &mut *refmut; - let xshr = &rc; // creating this is okay + let xshr = &rc; // creating this is ok let _val = *xref; // we can even still use our mutable reference mem::forget(unsafe { ptr::read(xshr) }); // but after reading through the shared ref let _val = *xref; // the mutable one is dead and gone diff --git a/tests/compile-fail/stacked_borrows/illegal_write5.rs b/tests/compile-fail/stacked_borrows/illegal_write5.rs index af57221260ce8..3a0738bfd0b85 100644 --- a/tests/compile-fail/stacked_borrows/illegal_write5.rs +++ b/tests/compile-fail/stacked_borrows/illegal_write5.rs @@ -1,12 +1,13 @@ -// A callee may not write to the destination of our `&mut` without -// us noticing. +// A callee may not write to the destination of our `&mut` without us noticing. fn main() { let mut x = 15; let xraw = &mut x as *mut _; - let xref = unsafe { &mut *xraw }; // derived from raw, so using raw is still okay... + // Derived from raw value, so using raw value is still ok ... + let xref = unsafe { &mut *xraw }; callee(xraw); - let _val = *xref; // ...but any use of raw will invalidate our ref. + // ... though any use of raw value will invalidate our ref. + let _val = *xref; //~^ ERROR: does not exist on the borrow stack } diff --git a/tests/compile-fail/transmute-pair-undef.rs b/tests/compile-fail/transmute-pair-undef.rs index acc6098af7ee0..43f1eed42d07a 100644 --- a/tests/compile-fail/transmute-pair-undef.rs +++ b/tests/compile-fail/transmute-pair-undef.rs @@ -8,7 +8,8 @@ fn main() { std::mem::transmute::<(usize, bool), Option>>(z) }; let y = &x; - // Now read this bytewise. There should be (ptr_size+1) def bytes followed by (ptr_size-1) undef bytes (the padding after the bool) in there. + // Now read this bytewise. There should be (`ptr_size + 1`) def bytes followed by + // (`ptr_size - 1`) undef bytes (the padding after the bool) in there. let z : *const u8 = y as *const _ as *const _; let first_undef = mem::size_of::() as isize + 1; for i in 0..first_undef { @@ -16,5 +17,6 @@ fn main() { assert_eq!(byte, 0); } let v = unsafe { *z.offset(first_undef) }; - if v == 0 {} //~ ERROR attempted to read undefined bytes + if v == 0 {} + //~^ ERROR attempted to read undefined bytes } diff --git a/tests/compile-fail/unaligned_ptr_cast2.rs b/tests/compile-fail/unaligned_ptr_cast2.rs index 1112f2f33c148..9fb138e353fe7 100644 --- a/tests/compile-fail/unaligned_ptr_cast2.rs +++ b/tests/compile-fail/unaligned_ptr_cast2.rs @@ -1,10 +1,11 @@ -// This should fail even without validation +// This should fail even without validation. // compile-flags: -Zmiri-disable-validation fn main() { let x = &2u16; let x = x as *const _ as *const *const u8; - // This must fail because alignment is violated. Test specifically for loading pointers, which have special code - // in miri's memory. - let _x = unsafe { *x }; //~ ERROR tried to access memory with alignment 2, but alignment + // This must fail because alignment is violated. Test specifically for loading pointers, + // which have special code in miri's memory. + let _x = unsafe { *x }; + //~^ ERROR tried to access memory with alignment 2, but alignment } diff --git a/tests/compile-fail/unaligned_ptr_cast_zst.rs b/tests/compile-fail/unaligned_ptr_cast_zst.rs index 1b9b55c6be1f2..d52b569175c1d 100644 --- a/tests/compile-fail/unaligned_ptr_cast_zst.rs +++ b/tests/compile-fail/unaligned_ptr_cast_zst.rs @@ -1,6 +1,7 @@ fn main() { let x = &2u16; let x = x as *const _ as *const [u32; 0]; - // This must fail because alignment is violated. Test specifically for loading ZST. - let _x = unsafe { *x }; //~ ERROR tried to access memory with alignment 2, but alignment 4 is required + // This must fail because alignment is violated. Test specifically for loading ZST. + let _x = unsafe { *x }; + //~^ ERROR tried to access memory with alignment 2, but alignment 4 is required } diff --git a/tests/compile-fail/validity/cast_fn_ptr1.rs b/tests/compile-fail/validity/cast_fn_ptr1.rs index 82f2d10ee4bb5..d1f6e33e45982 100644 --- a/tests/compile-fail/validity/cast_fn_ptr1.rs +++ b/tests/compile-fail/validity/cast_fn_ptr1.rs @@ -1,10 +1,11 @@ fn main() { // Cast a function pointer such that on a call, the argument gets transmuted - // from raw ptr to reference. This is ABI-compatible, so it's not the call that + // from raw ptr to reference. This is ABI-compatible, so it's not the call that // should fail, but validation should. fn f(_x: &i32) { } let g: fn(*const i32) = unsafe { std::mem::transmute(f as fn(&i32)) }; - g(0usize as *const i32) //~ ERROR encountered 0, but expected something greater or equal to 1 + g(0usize as *const i32) + //~^ ERROR encountered 0, but expected something greater or equal to 1 } diff --git a/tests/compile-fail/validity/cast_fn_ptr2.rs b/tests/compile-fail/validity/cast_fn_ptr2.rs index 2f3b91a53e622..809f118c1df15 100644 --- a/tests/compile-fail/validity/cast_fn_ptr2.rs +++ b/tests/compile-fail/validity/cast_fn_ptr2.rs @@ -1,10 +1,11 @@ fn main() { // Cast a function pointer such that when returning, the return value gets transmuted - // from raw ptr to reference. This is ABI-compatible, so it's not the call that + // from raw ptr to reference. This is ABI-compatible, so it's not the call that // should fail, but validation should. fn f() -> *const i32 { 0usize as *const i32 } let g: fn() -> &'static i32 = unsafe { std::mem::transmute(f as fn() -> *const i32) }; - let _x = g(); //~ ERROR encountered 0, but expected something greater or equal to 1 + let _x = g(); + //~^ ERROR encountered 0, but expected something greater or equal to 1 } diff --git a/tests/compiletest.rs b/tests/compiletest.rs index f125100f83438..38a9d31d6e891 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -87,10 +87,10 @@ fn miri_pass(path: &str, target: &str, opt: bool) { compiletest::run_tests(&config); } -/// Make sure the MIRI_SYSROOT env var is set +/// Ensures that the `MIRI_SYSROOT` env var is set. fn set_sysroot() { if std::env::var("MIRI_SYSROOT").is_ok() { - // Nothing to do + // Nothing to do. return; } let sysroot = std::process::Command::new("rustc") diff --git a/tests/run-pass/associated-const.rs b/tests/run-pass/associated-const.rs index fe5da49f807d5..2ff08ffc4bf6a 100644 --- a/tests/run-pass/associated-const.rs +++ b/tests/run-pass/associated-const.rs @@ -1,13 +1,3 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - trait Foo { const ID: i32; } diff --git a/tests/run-pass/atomic-access-bool.rs b/tests/run-pass/atomic-access-bool.rs index 8a3db796a087c..68a5d7295f176 100644 --- a/tests/run-pass/atomic-access-bool.rs +++ b/tests/run-pass/atomic-access-bool.rs @@ -1,13 +1,3 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - use std::sync::atomic::{AtomicBool, Ordering::*}; static mut ATOMIC: AtomicBool = AtomicBool::new(false); diff --git a/tests/run-pass/atomic-compare_exchange.rs b/tests/run-pass/atomic-compare_exchange.rs index 67280096073d8..575b53fb44b0e 100644 --- a/tests/run-pass/atomic-compare_exchange.rs +++ b/tests/run-pass/atomic-compare_exchange.rs @@ -1,13 +1,3 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - use std::sync::atomic::{AtomicIsize, Ordering::*}; static ATOMIC: AtomicIsize = AtomicIsize::new(0); diff --git a/tests/run-pass/binops.rs b/tests/run-pass/binops.rs index a03b96fa499fd..1d03c8b3d0aa5 100644 --- a/tests/run-pass/binops.rs +++ b/tests/run-pass/binops.rs @@ -1,13 +1,3 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - // Binop corner cases fn test_nil() { diff --git a/tests/run-pass/cast-rfc0401-vtable-kinds.rs b/tests/run-pass/cast-rfc0401-vtable-kinds.rs index ebae26996b7b1..6442eab30a132 100644 --- a/tests/run-pass/cast-rfc0401-vtable-kinds.rs +++ b/tests/run-pass/cast-rfc0401-vtable-kinds.rs @@ -1,13 +1,3 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - // Check that you can cast between different pointers to trait objects // whose vtable have the same kind (both lengths, or both trait pointers). diff --git a/tests/run-pass/deriving-associated-types.rs b/tests/run-pass/deriving-associated-types.rs index b67ef85acf62d..52104d8486b05 100644 --- a/tests/run-pass/deriving-associated-types.rs +++ b/tests/run-pass/deriving-associated-types.rs @@ -1,13 +1,3 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - pub trait DeclaredTrait { type Type; } diff --git a/tests/run-pass/dst-field-align.rs b/tests/run-pass/dst-field-align.rs index 5631b65ed9d8a..b8e9815640c28 100644 --- a/tests/run-pass/dst-field-align.rs +++ b/tests/run-pass/dst-field-align.rs @@ -1,13 +1,3 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![allow(dead_code)] struct Foo { diff --git a/tests/run-pass/dst-irrefutable-bind.rs b/tests/run-pass/dst-irrefutable-bind.rs index 9f8067f372aef..eeddfce75fd9f 100644 --- a/tests/run-pass/dst-irrefutable-bind.rs +++ b/tests/run-pass/dst-irrefutable-bind.rs @@ -1,13 +1,3 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - struct Test(T); fn main() { diff --git a/tests/run-pass/dst-raw.rs b/tests/run-pass/dst-raw.rs index 3a74626b0299f..a3ee982d19aa6 100644 --- a/tests/run-pass/dst-raw.rs +++ b/tests/run-pass/dst-raw.rs @@ -1,13 +1,3 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - // Test DST raw pointers diff --git a/tests/run-pass/dst-struct-sole.rs b/tests/run-pass/dst-struct-sole.rs index 58d7b35a5275c..770af864a44c0 100644 --- a/tests/run-pass/dst-struct-sole.rs +++ b/tests/run-pass/dst-struct-sole.rs @@ -1,13 +1,3 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - // As dst-struct.rs, but the unsized field is the only field in the struct. diff --git a/tests/run-pass/dst-struct.rs b/tests/run-pass/dst-struct.rs index 4c9e598e6ba33..bd6517bd1fd77 100644 --- a/tests/run-pass/dst-struct.rs +++ b/tests/run-pass/dst-struct.rs @@ -1,13 +1,3 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![feature(box_syntax)] struct Fat { diff --git a/tests/run-pass/enum-nullable-const-null-with-fields.rs b/tests/run-pass/enum-nullable-const-null-with-fields.rs index 1342c4e104de5..87389c9c3a819 100644 --- a/tests/run-pass/enum-nullable-const-null-with-fields.rs +++ b/tests/run-pass/enum-nullable-const-null-with-fields.rs @@ -1,13 +1,3 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - use std::result::Result; use std::result::Result::Ok; diff --git a/tests/run-pass/float_fast_math.rs b/tests/run-pass/float_fast_math.rs index c1b4b55bd3723..ba7e6ac3ec063 100644 --- a/tests/run-pass/float_fast_math.rs +++ b/tests/run-pass/float_fast_math.rs @@ -1,13 +1,3 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![feature(core_intrinsics)] use std::intrinsics::{fadd_fast, fsub_fast, fmul_fast, fdiv_fast, frem_fast}; diff --git a/tests/run-pass/foreign-fn-linkname.rs b/tests/run-pass/foreign-fn-linkname.rs index f2ed67385cdc7..ebb0e5364b94e 100644 --- a/tests/run-pass/foreign-fn-linkname.rs +++ b/tests/run-pass/foreign-fn-linkname.rs @@ -1,13 +1,3 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - //ignore-windows: Uses POSIX APIs #![feature(rustc_private)] diff --git a/tests/run-pass/generator.rs b/tests/run-pass/generator.rs index c9c114aacccae..477f548a7b065 100644 --- a/tests/run-pass/generator.rs +++ b/tests/run-pass/generator.rs @@ -1,13 +1,3 @@ -// Copyright 2017 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![feature(generators, generator_trait)] use std::ops::{GeneratorState, Generator}; diff --git a/tests/run-pass/issue-15063.rs b/tests/run-pass/issue-15063.rs index 726aee283e292..8ccf87ee7079e 100644 --- a/tests/run-pass/issue-15063.rs +++ b/tests/run-pass/issue-15063.rs @@ -1,13 +1,3 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![allow(dead_code)] enum Two { A, B } diff --git a/tests/run-pass/issue-15080.rs b/tests/run-pass/issue-15080.rs index b5b1edcfddd01..3ef3718d52276 100644 --- a/tests/run-pass/issue-15080.rs +++ b/tests/run-pass/issue-15080.rs @@ -1,13 +1,3 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![feature(slice_patterns)] fn main() { diff --git a/tests/run-pass/issue-15523-big.rs b/tests/run-pass/issue-15523-big.rs index 33c81cab3817b..75fd8d8dfce8f 100644 --- a/tests/run-pass/issue-15523-big.rs +++ b/tests/run-pass/issue-15523-big.rs @@ -1,13 +1,3 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - // Issue 15523: derive(PartialOrd) should use the provided // discriminant values for the derived ordering. // diff --git a/tests/run-pass/issue-17877.rs b/tests/run-pass/issue-17877.rs index 91d17683e39e8..caad8b27766fe 100644 --- a/tests/run-pass/issue-17877.rs +++ b/tests/run-pass/issue-17877.rs @@ -1,13 +1,3 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - //ignore-windows: Causes a stack overflow?!? Likely a rustc bug: https://github.com/rust-lang/rust/issues/53820 //FIXME: Once that bug is fixed, increase the size to 16*1024 and enable on all platforms. diff --git a/tests/run-pass/issue-20575.rs b/tests/run-pass/issue-20575.rs index 01371f5bec683..1443ec78fd75e 100644 --- a/tests/run-pass/issue-20575.rs +++ b/tests/run-pass/issue-20575.rs @@ -1,13 +1,3 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - // Test that overloaded calls work with zero arity closures fn main() { diff --git a/tests/run-pass/issue-23261.rs b/tests/run-pass/issue-23261.rs index fc806f5429a47..3e1aa295af1ea 100644 --- a/tests/run-pass/issue-23261.rs +++ b/tests/run-pass/issue-23261.rs @@ -1,13 +1,3 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - // Matching on a DST struct should not trigger an LLVM assertion. struct Foo { diff --git a/tests/run-pass/issue-26709.rs b/tests/run-pass/issue-26709.rs index e29e5fbcc4081..a283d8743ccff 100644 --- a/tests/run-pass/issue-26709.rs +++ b/tests/run-pass/issue-26709.rs @@ -1,13 +1,3 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - struct Wrapper<'a, T: ?Sized>(&'a mut i32, T); impl<'a, T: ?Sized> Drop for Wrapper<'a, T> { diff --git a/tests/run-pass/issue-27901.rs b/tests/run-pass/issue-27901.rs index b7a9daaf8abd4..b0822accb6b6b 100644 --- a/tests/run-pass/issue-27901.rs +++ b/tests/run-pass/issue-27901.rs @@ -1,13 +1,3 @@ -// Copyright 2017 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - trait Stream { type Item; } impl<'a> Stream for &'a str { type Item = u8; } fn f<'s>(s: &'s str) -> (&'s str, <&'s str as Stream>::Item) { diff --git a/tests/run-pass/issue-29746.rs b/tests/run-pass/issue-29746.rs index 61c601ac6a903..d04703d6877c8 100644 --- a/tests/run-pass/issue-29746.rs +++ b/tests/run-pass/issue-29746.rs @@ -1,13 +1,3 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - // zip!(a1,a2,a3,a4) is equivalent to: // a1.zip(a2).zip(a3).zip(a4).map(|(((x1,x2),x3),x4)| (x1,x2,x3,x4)) macro_rules! zip { diff --git a/tests/run-pass/issue-31267-additional.rs b/tests/run-pass/issue-31267-additional.rs index aaeeef8bf98be..f6d7209369b70 100644 --- a/tests/run-pass/issue-31267-additional.rs +++ b/tests/run-pass/issue-31267-additional.rs @@ -1,13 +1,3 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #[derive(Clone, Copy, Debug)] struct Bar; diff --git a/tests/run-pass/issue-33387.rs b/tests/run-pass/issue-33387.rs index 62a4263c1069b..2335f9c1b9412 100644 --- a/tests/run-pass/issue-33387.rs +++ b/tests/run-pass/issue-33387.rs @@ -1,13 +1,3 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - use std::sync::Arc; trait Foo {} diff --git a/tests/run-pass/issue-34571.rs b/tests/run-pass/issue-34571.rs index 7d80415657655..28fe076b644d4 100644 --- a/tests/run-pass/issue-34571.rs +++ b/tests/run-pass/issue-34571.rs @@ -1,13 +1,3 @@ -// Copyright 2017 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #[repr(u8)] enum Foo { Foo(u8), diff --git a/tests/run-pass/issue-35815.rs b/tests/run-pass/issue-35815.rs index 216e06c0732c8..e17c37f92a501 100644 --- a/tests/run-pass/issue-35815.rs +++ b/tests/run-pass/issue-35815.rs @@ -1,13 +1,3 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![allow(dead_code)] use std::mem; diff --git a/tests/run-pass/issue-36278-prefix-nesting.rs b/tests/run-pass/issue-36278-prefix-nesting.rs index dc807bfde7a34..cbffbbc0e0f86 100644 --- a/tests/run-pass/issue-36278-prefix-nesting.rs +++ b/tests/run-pass/issue-36278-prefix-nesting.rs @@ -1,13 +1,3 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - // Issue 36278: On an unsized struct with >1 level of nontrivial // nesting, ensure we are computing dynamic size of prefix correctly. diff --git a/tests/run-pass/issue-3794.rs b/tests/run-pass/issue-3794.rs index badb833ee800b..9161fefef30cf 100644 --- a/tests/run-pass/issue-3794.rs +++ b/tests/run-pass/issue-3794.rs @@ -1,13 +1,3 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![feature(box_syntax)] trait T { diff --git a/tests/run-pass/issue-5917.rs b/tests/run-pass/issue-5917.rs index 69b95f2cd7e10..eb506dd3a17eb 100644 --- a/tests/run-pass/issue-5917.rs +++ b/tests/run-pass/issue-5917.rs @@ -1,13 +1,3 @@ -// Copyright 2013 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - struct T (&'static [isize]); static STATIC : T = T (&[5, 4, 3]); diff --git a/tests/run-pass/last-use-in-cap-clause.rs b/tests/run-pass/last-use-in-cap-clause.rs index de2d815ca54eb..f75f00b87fd48 100644 --- a/tests/run-pass/last-use-in-cap-clause.rs +++ b/tests/run-pass/last-use-in-cap-clause.rs @@ -1,13 +1,3 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - // Make sure #1399 stays fixed #[allow(dead_code)] diff --git a/tests/run-pass/loop-break-value.rs b/tests/run-pass/loop-break-value.rs index ab79a64b56e2a..bd7afa7ec1a80 100644 --- a/tests/run-pass/loop-break-value.rs +++ b/tests/run-pass/loop-break-value.rs @@ -1,13 +1,3 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![feature(never_type)] #![allow(unreachable_code)] diff --git a/tests/run-pass/mir_coercions.rs b/tests/run-pass/mir_coercions.rs index 1dab492f9da3b..f3d8e519d23ed 100644 --- a/tests/run-pass/mir_coercions.rs +++ b/tests/run-pass/mir_coercions.rs @@ -1,13 +1,3 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![feature(coerce_unsized, unsize)] use std::ops::CoerceUnsized; diff --git a/tests/run-pass/mir_fat_ptr.rs b/tests/run-pass/mir_fat_ptr.rs index e5c9e3577d1c3..55418c4802a7c 100644 --- a/tests/run-pass/mir_fat_ptr.rs +++ b/tests/run-pass/mir_fat_ptr.rs @@ -1,13 +1,3 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - // test that ordinary fat pointer operations work. struct Wrapper(u32, T); diff --git a/tests/run-pass/move-arg-2-unique.rs b/tests/run-pass/move-arg-2-unique.rs index 77f763888eae1..b31b868bb96d5 100644 --- a/tests/run-pass/move-arg-2-unique.rs +++ b/tests/run-pass/move-arg-2-unique.rs @@ -1,13 +1,3 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![feature(box_syntax)] fn test(foo: Box> ) { assert_eq!((*foo)[0], 10); } diff --git a/tests/run-pass/move-arg-3-unique.rs b/tests/run-pass/move-arg-3-unique.rs index 0754a3f60d360..3b5c7cbbd42ca 100644 --- a/tests/run-pass/move-arg-3-unique.rs +++ b/tests/run-pass/move-arg-3-unique.rs @@ -1,13 +1,3 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![feature(box_syntax)] pub fn main() { diff --git a/tests/run-pass/overloaded-calls-simple.rs b/tests/run-pass/overloaded-calls-simple.rs index 1eeda12ca06f8..12e632c251b42 100644 --- a/tests/run-pass/overloaded-calls-simple.rs +++ b/tests/run-pass/overloaded-calls-simple.rs @@ -1,13 +1,3 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![feature(lang_items, unboxed_closures, fn_traits)] diff --git a/tests/run-pass/ref-invalid-ptr.rs b/tests/run-pass/ref-invalid-ptr.rs index 627c821a9f307..e0e7d2afefc52 100644 --- a/tests/run-pass/ref-invalid-ptr.rs +++ b/tests/run-pass/ref-invalid-ptr.rs @@ -1,12 +1,12 @@ -// FIXME validation disabled because it checks these references too eagerly +// FIXME: validation disabled because it checks these references too eagerly. // compile-flags: -Zmiri-disable-validation fn main() { let x = 2usize as *const u32; - // this is not aligned, but we immediately cast it to a raw ptr so that must be okay + // This is not aligned, but we immediately cast it to a raw ptr so that must be ok. let _y = unsafe { &*x as *const u32 }; let x = 0usize as *const u32; - // this is NULL, but we immediately cast it to a raw ptr so that must be okay + // This is NULL, but we immediately cast it to a raw ptr so that must be ok. let _y = unsafe { &*x as *const u32 }; } diff --git a/tests/run-pass/regions-lifetime-nonfree-late-bound.rs b/tests/run-pass/regions-lifetime-nonfree-late-bound.rs index dfdf89c9c1cd9..85a189007c3de 100644 --- a/tests/run-pass/regions-lifetime-nonfree-late-bound.rs +++ b/tests/run-pass/regions-lifetime-nonfree-late-bound.rs @@ -1,13 +1,3 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - // This is a regression test for the ICE from issue #10846. // // The original issue causing the ICE: the LUB-computations during @@ -17,10 +7,10 @@ // // However, those encounters were occurring within the lexical scope // of the binding for the late-bound lifetime; that is, the late-bound -// lifetimes were perfectly valid. The core problem was that the type +// lifetimes were perfectly valid. The core problem was that the type // folding code was over-zealously passing back all lifetimes when // doing region-folding, when really all clients of the region-folding -// case only want to see FREE lifetime variables, not bound ones. +// case only want to see *free* lifetime variables, not bound ones. #![feature(box_syntax)] diff --git a/tests/run-pass/regions-mock-trans.rs b/tests/run-pass/regions-mock-trans.rs index 62931493aa00c..ac8a1c04fbe4f 100644 --- a/tests/run-pass/regions-mock-trans.rs +++ b/tests/run-pass/regions-mock-trans.rs @@ -1,13 +1,3 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - //ignore-windows: Uses POSIX APIs #![feature(rustc_private)] diff --git a/tests/run-pass/rfc1623.rs b/tests/run-pass/rfc1623.rs index 0ee523a5be00a..2f893d8150c94 100644 --- a/tests/run-pass/rfc1623.rs +++ b/tests/run-pass/rfc1623.rs @@ -1,13 +1,3 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![allow(dead_code)] // very simple test for a 'static static with default lifetime diff --git a/tests/run-pass/send-is-not-static-par-for.rs b/tests/run-pass/send-is-not-static-par-for.rs index 1b913aed4c89e..396a87fca060d 100644 --- a/tests/run-pass/send-is-not-static-par-for.rs +++ b/tests/run-pass/send-is-not-static-par-for.rs @@ -1,13 +1,3 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - use std::sync::Mutex; fn par_for(iter: I, f: F) diff --git a/tests/run-pass/sendable-class.rs b/tests/run-pass/sendable-class.rs index 3280c36e0a729..b2feb5316f873 100644 --- a/tests/run-pass/sendable-class.rs +++ b/tests/run-pass/sendable-class.rs @@ -1,13 +1,3 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - // Test that a class with only sendable fields can be sent use std::sync::mpsc::channel; diff --git a/tests/run-pass/simd-intrinsic-generic-elements.rs b/tests/run-pass/simd-intrinsic-generic-elements.rs index 36567f4c03310..e8fba6707db1e 100644 --- a/tests/run-pass/simd-intrinsic-generic-elements.rs +++ b/tests/run-pass/simd-intrinsic-generic-elements.rs @@ -1,13 +1,3 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![feature(repr_simd, platform_intrinsics)] #[repr(simd)] diff --git a/tests/run-pass/stacked-borrows.rs b/tests/run-pass/stacked-borrows.rs index 223c69a9a3ad7..711026c02dfc0 100644 --- a/tests/run-pass/stacked-borrows.rs +++ b/tests/run-pass/stacked-borrows.rs @@ -46,8 +46,8 @@ fn read_does_not_invalidate2() { } // Just to make sure that casting a ref to raw, to int and back to raw -// and only then using it works. This rules out ideas like "do escape-to-raw lazily": -// After casting to int and back, we lost the tag that could have let us do that. +// and only then using it works. This rules out ideas like "do escape-to-raw lazily"; +// after casting to int and back, we lost the tag that could have let us do that. fn ref_raw_int_raw() { let mut x = 3; let xref = &mut x; @@ -103,7 +103,7 @@ fn partially_invalidate_mut() { let data = &mut (0u8, 0u8); let reborrow = &mut *data as *mut (u8, u8); let shard = unsafe { &mut (*reborrow).0 }; - data.1 += 1; // the deref overlaps with `shard`, but that is okay; the access does not overlap. + data.1 += 1; // the deref overlaps with `shard`, but that is ok; the access does not overlap. *shard += 1; // so we can still use `shard`. assert_eq!(*data, (1, 1)); } diff --git a/tests/run-pass/try-operator-custom.rs b/tests/run-pass/try-operator-custom.rs index 3b447f36ece1e..ccbf63796af5b 100644 --- a/tests/run-pass/try-operator-custom.rs +++ b/tests/run-pass/try-operator-custom.rs @@ -1,13 +1,3 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - fn main() { assert!(Ok::(42) == Ok(42)); } diff --git a/tests/run-pass/u128.rs b/tests/run-pass/u128.rs index ca33bd5f9e3d8..5a5d7c1f94421 100644 --- a/tests/run-pass/u128.rs +++ b/tests/run-pass/u128.rs @@ -1,13 +1,3 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - fn b(t: T) -> T { t } fn main() { diff --git a/tests/run-pass/union-overwrite.rs b/tests/run-pass/union-overwrite.rs index df2ff6e51a593..5c618763c0d28 100644 --- a/tests/run-pass/union-overwrite.rs +++ b/tests/run-pass/union-overwrite.rs @@ -1,13 +1,3 @@ -// Copyright 2016 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![feature(untagged_unions)] #![allow(unions_with_drop_fields)] diff --git a/tests/run-pass/unique-send.rs b/tests/run-pass/unique-send.rs index 7644da08e4afa..04dbf495f8bfd 100644 --- a/tests/run-pass/unique-send.rs +++ b/tests/run-pass/unique-send.rs @@ -1,13 +1,3 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![feature(box_syntax)] use std::sync::mpsc::channel; diff --git a/tests/run-pass/unsized-tuple-impls.rs b/tests/run-pass/unsized-tuple-impls.rs index ccb6883e8733a..54bd6f5c34f83 100644 --- a/tests/run-pass/unsized-tuple-impls.rs +++ b/tests/run-pass/unsized-tuple-impls.rs @@ -1,13 +1,3 @@ -// Copyright 2017 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![feature(unsized_tuple_coercion)] use std::mem; diff --git a/tests/run-pass/validation_lifetime_resolution.rs b/tests/run-pass/validation_lifetime_resolution.rs index 3375632c9d70b..a0eea517095bf 100644 --- a/tests/run-pass/validation_lifetime_resolution.rs +++ b/tests/run-pass/validation_lifetime_resolution.rs @@ -20,9 +20,9 @@ fn foo(mut x: T) where for<'a> &'a mut T: Id { let x = &mut x; let _y = x.id(); - // Inspecting the trace should show that _y has a type involving a local lifetime, when it gets validated. + // Inspecting the trace should show that `_y` has a type involving a local lifetime, when it gets validated. // Unfortunately, there doesn't seem to be a way to actually have a test fail if it does not have the right - // type. Currently, this is NOT working correctly; see . + // type. Currently, this is *not* working correctly; see . } fn main() { diff --git a/tests/run-pass/vec-matching-fold.rs b/tests/run-pass/vec-matching-fold.rs index 396846b23236e..f953e04747050 100644 --- a/tests/run-pass/vec-matching-fold.rs +++ b/tests/run-pass/vec-matching-fold.rs @@ -1,13 +1,3 @@ -// Copyright 2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - #![feature(slice_patterns)] use std::fmt::Debug; diff --git a/tests/run-pass/zero-sized-binary-heap-push.rs b/tests/run-pass/zero-sized-binary-heap-push.rs index 63a0d65f017de..c9312d79bfda0 100644 --- a/tests/run-pass/zero-sized-binary-heap-push.rs +++ b/tests/run-pass/zero-sized-binary-heap-push.rs @@ -1,13 +1,3 @@ -// Copyright 2013 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - use std::collections::BinaryHeap; use std::iter::Iterator; diff --git a/tests/run-pass/zst.rs b/tests/run-pass/zst.rs index c3bae4062fc29..9d97210b73db6 100644 --- a/tests/run-pass/zst.rs +++ b/tests/run-pass/zst.rs @@ -18,16 +18,16 @@ fn main() { assert_eq!(zst_ret(), A); assert_eq!(use_zst(), A); let x = 42 as *mut [u8; 0]; - // reading and writing is okay + // Reading and writing is ok. unsafe { *x = zst_val; } unsafe { let _y = *x; } // We should even be able to use "true" pointers for ZST when the allocation has been - // removed already. The box is for a non-ZST to make sure there actually is an allocation. + // removed already. The box is for a non-ZST to make sure there actually is an allocation. let mut x_box = Box::new(((), 1u8)); let x = &mut x_box.0 as *mut _ as *mut [u8; 0]; drop(x_box); - // reading and writing is okay + // Reading and writing is ok. unsafe { *x = zst_val; } unsafe { let _y = *x; } } From 12d3ecbaff9e7b627e79404fa21e2a52278e1368 Mon Sep 17 00:00:00 2001 From: Alexander Regueiro Date: Sat, 16 Feb 2019 01:29:38 +0000 Subject: [PATCH 0590/3747] Various cosmetic improvements. --- README.md | 2 +- src/bin/cargo-miri.rs | 101 +++++---- src/bin/miri.rs | 48 ++-- src/fn_call.rs | 172 ++++++++------ src/helpers.rs | 23 +- src/intrinsic.rs | 7 +- src/lib.rs | 136 +++++------ src/mono_hash_map.rs | 8 +- src/operator.rs | 71 +++--- src/range_map.rs | 65 +++--- src/stacked_borrows.rs | 211 ++++++++++-------- .../deallocate_against_barrier.rs | 2 +- tests/run-pass/const-vec-of-fns.rs | 10 - tests/run-pass/heap_allocator.rs | 11 +- .../too-large-primval-write-problem.rs | 2 +- 15 files changed, 466 insertions(+), 403 deletions(-) diff --git a/README.md b/README.md index 856e1273131a7..c11cb46b31df4 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,7 @@ Miri has already discovered some [real-world bugs](#bugs-found-by-miri). [`copy_nonoverlapping`]: https://doc.rust-lang.org/stable/std/ptr/fn.copy_nonoverlapping.html -## Running Miri on your own project('s test suite) +## Running Miri on your own project (and its test suite) Install Miri as a cargo subcommand: diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 0de835f45d0a8..c88912c83d786 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -2,10 +2,10 @@ extern crate cargo_metadata; -use std::path::{PathBuf, Path}; +use std::fs::{self, File}; use std::io::{self, Write, BufRead}; +use std::path::{PathBuf, Path}; use std::process::Command; -use std::fs::{self, File}; const CARGO_MIRI_HELP: &str = r#"Interprets bin crates and tests in Miri @@ -55,15 +55,15 @@ fn show_error(msg: String) -> ! { std::process::exit(1) } -// Determines whether a --flag is present +// Determines whether a `--flag` is present. fn has_arg_flag(name: &str) -> bool { let mut args = std::env::args().take_while(|val| val != "--"); args.any(|val| val == name) } -/// Gets the value of a --flag +/// Gets the value of a `--flag`. fn get_arg_flag_value(name: &str) -> Option { - // stop searching at `--` + // Stop searching at `--`. let mut args = std::env::args().take_while(|val| val != "--"); loop { let arg = match args.next() { @@ -73,13 +73,15 @@ fn get_arg_flag_value(name: &str) -> Option { if !arg.starts_with(name) { continue; } - let suffix = &arg[name.len()..]; // strip leading `name` + // Strip leading `name`. + let suffix = &arg[name.len()..]; if suffix.is_empty() { - // This argument is exactly `name`, the next one is the value + // This argument is exactly `name`; the next one is the value. return args.next(); } else if suffix.starts_with('=') { - // This argument is `name=value`, get the value - return Some(suffix[1..].to_owned()); // strip leading `=` + // This argument is `name=value`; get the value. + // Strip leading `=`. + return Some(suffix[1..].to_owned()); } } } @@ -96,7 +98,7 @@ fn list_targets() -> impl Iterator { { metadata } else { - show_error(format!("error: Could not obtain cargo metadata.")); + show_error(format!("Could not obtain Cargo metadata")); }; let current_dir = std::env::current_dir(); @@ -167,20 +169,22 @@ fn ask(question: &str) { io::stdout().flush().unwrap(); io::stdin().read_line(&mut buf).unwrap(); match buf.trim().to_lowercase().as_ref() { - "" | "y" | "yes" => {}, // proceed + // Proceed. + "" | "y" | "yes" => {}, "n" | "no" => show_error(format!("Aborting as per your request")), a => show_error(format!("I do not understand `{}`", a)) }; } -/// Perform the setup requires to make `cargo miri` work: Getting a custom-built libstd. Then sets MIRI_SYSROOT. -/// Skipped if MIRI_SYSROOT is already set, in that case we expect the user has done all this already. +/// Performs the setup required to make `cargo miri` work: Getting a custom-built libstd. Then sets +/// `MIRI_SYSROOT`. Skipped if `MIRI_SYSROOT` is already set, in which case we expect the user has +/// done all this already. fn setup(ask_user: bool) { if std::env::var("MIRI_SYSROOT").is_ok() { return; } - // First, we need xargo + // First, we need xargo. let xargo = xargo_version(); if xargo.map_or(true, |v| v < (0, 3, 13)) { if ask_user { @@ -193,7 +197,7 @@ fn setup(ask_user: bool) { } } - // Then, unless XARGO_RUST_SRC is set, we also need rust-src. + // Then, unless `XARGO_RUST_SRC` is set, we also need rust-src. // Let's see if it is already installed. if std::env::var("XARGO_RUST_SRC").is_err() { let sysroot = Command::new("rustc").args(&["--print", "sysroot"]).output().unwrap().stdout; @@ -229,7 +233,7 @@ features = ["panic_unwind"] [dependencies.test] stage = 1 "#).unwrap(); - // The boring bits: A dummy project for xargo + // The boring bits: a dummy project for xargo. File::create(dir.join("Cargo.toml")).unwrap() .write_all(br#" [package] @@ -241,7 +245,7 @@ version = "0.0.0" path = "lib.rs" "#).unwrap(); File::create(dir.join("lib.rs")).unwrap(); - // Run xargo + // Run xargo. let target = get_arg_flag_value("--target"); let mut command = Command::new("xargo"); command.arg("build").arg("-q") @@ -256,7 +260,7 @@ path = "lib.rs" show_error(format!("Failed to run xargo")); } - // That should be it! But we need to figure out where xargo built stuff. + // That should be it! But we need to figure out where xargo built stuff. // Unfortunately, it puts things into a different directory when the // architecture matches the host. let is_host = match target { @@ -271,7 +275,7 @@ path = "lib.rs" } fn main() { - // Check for version and help flags even when invoked as 'cargo-miri' + // Check for version and help flags even when invoked as `cargo-miri`. if std::env::args().any(|a| a == "--help" || a == "-h") { show_help(); return; @@ -282,17 +286,16 @@ fn main() { } if let Some("miri") = std::env::args().nth(1).as_ref().map(AsRef::as_ref) { - // this arm is when `cargo miri` is called. We call `cargo rustc` for - // each applicable target, but with the RUSTC env var set to the `cargo-miri` - // binary so that we come back in the other branch, and dispatch - // the invocations to rustc and miri, respectively. + // This arm is for when `cargo miri` is called. We call `cargo rustc` for each applicable target, + // but with the `RUSTC` env var set to the `cargo-miri` binary so that we come back in the other branch, + // and dispatch the invocations to `rustc` and `miri`, respectively. in_cargo_miri(); } else if let Some("rustc") = std::env::args().nth(1).as_ref().map(AsRef::as_ref) { - // This arm is executed when cargo-miri runs `cargo rustc` with the `RUSTC_WRAPPER` env var set to itself: - // Dependencies get dispatched to rustc, the final test/binary to miri. + // This arm is executed when `cargo-miri` runs `cargo rustc` with the `RUSTC_WRAPPER` env var set to itself: + // dependencies get dispatched to `rustc`, the final test/binary to `miri`. inside_cargo_rustc(); } else { - show_error(format!("Must be called with either `miri` or `rustc` as first argument.")) + show_error(format!("must be called with either `miri` or `rustc` as first argument.")) } } @@ -301,17 +304,17 @@ fn in_cargo_miri() { Some("test") => (MiriCommand::Test, 3), Some("run") => (MiriCommand::Run, 3), Some("setup") => (MiriCommand::Setup, 3), - // Default command, if there is an option or nothing + // Default command, if there is an option or nothing. Some(s) if s.starts_with("-") => (MiriCommand::Run, 2), None => (MiriCommand::Run, 2), - // Unvalid command + // Invalid command. Some(s) => { show_error(format!("Unknown command `{}`", s)) } }; let verbose = has_arg_flag("-v"); - // We always setup + // We always setup. let ask = subcommand != MiriCommand::Setup; setup(ask); if subcommand == MiriCommand::Setup { @@ -326,16 +329,16 @@ fn in_cargo_miri() { "badly formatted cargo metadata: target::kind is an empty array", ); // Now we run `cargo rustc $FLAGS $ARGS`, giving the user the - // change to add additional flags. "FLAGS" is set to identify + // change to add additional flags. `FLAGS` is set to identify // this target. The user gets to control what gets actually passed to Miri. // However, we need to add a flag to what gets passed to rustc for the finaly // binary, so that we know to interpret that with Miri. - // So after the first "--", we add "-Zcargo-miri-marker". + // So after the first `--`, we add `-Zcargo-miri-marker`. let mut cmd = Command::new("cargo"); cmd.arg("rustc"); match (subcommand, &kind[..]) { (MiriCommand::Run, "bin") => { - // FIXME: We just run all the binaries here. + // FIXME: we just run all the binaries here. // We should instead support `cargo miri --bin foo`. cmd.arg("--bin").arg(target.name); } @@ -343,24 +346,24 @@ fn in_cargo_miri() { cmd.arg("--test").arg(target.name); } (MiriCommand::Test, "lib") => { - // There can be only one lib + // There can be only one lib. cmd.arg("--lib").arg("--profile").arg("test"); } (MiriCommand::Test, "bin") => { cmd.arg("--bin").arg(target.name).arg("--profile").arg("test"); } - // The remaining targets we do not even want to build + // The remaining targets we do not even want to build. _ => continue, } - // add user-defined args until first "--" + // Add user-defined args until first `--`. while let Some(arg) = args.next() { if arg == "--" { break; } cmd.arg(arg); } - // Add "--" (to end the cargo flags), and then the user flags. We add markers around the user flags - // to be able to identify them later. + // Add `--` (to end the `cargo` flags), and then the user flags. We add markers around the + // user flags to be able to identify them later. cmd .arg("--") .arg("cargo-miri-marker-begin") @@ -403,11 +406,11 @@ fn inside_cargo_rustc() { .and_then(|out| String::from_utf8(out.stdout).ok()) .map(|s| s.trim().to_owned()) }) - .expect("need to specify RUST_SYSROOT env var during miri compilation, or use rustup or multirust") + .expect("need to specify `RUST_SYSROOT` env var during miri compilation, or use rustup or multirust") }; - // this conditional check for the --sysroot flag is there so users can call `cargo-miri` directly - // without having to pass --sysroot or anything + // This conditional check for the `--sysroot` flag is there so that users can call `cargo-miri` + // directly without having to pass `--sysroot` or anything. let rustc_args = std::env::args().skip(2); let mut args: Vec = if std::env::args().any(|s| s == "--sysroot") { rustc_args.collect() @@ -419,25 +422,27 @@ fn inside_cargo_rustc() { }; args.splice(0..0, miri::miri_default_args().iter().map(ToString::to_string)); - // See if we can find the cargo-miri markers. Those only get added to the binary we want to - // run. They also serve to mark the user-defined arguments, which we have to move all the way to the - // end (they get added somewhere in the middle). + // See if we can find the `cargo-miri` markers. Those only get added to the binary we want to + // run. They also serve to mark the user-defined arguments, which we have to move all the way + // to the end (they get added somewhere in the middle). let needs_miri = if let Some(begin) = args.iter().position(|arg| arg == "cargo-miri-marker-begin") { - let end = args.iter().position(|arg| arg == "cargo-miri-marker-end").expect("Cannot find end marker"); - // These mark the user arguments. We remove the first and last as they are the markers. + let end = args + .iter() + .position(|arg| arg == "cargo-miri-marker-end") + .expect("cannot find end marker"); + // These mark the user arguments. We remove the first and last as they are the markers. let mut user_args = args.drain(begin..=end); assert_eq!(user_args.next().unwrap(), "cargo-miri-marker-begin"); assert_eq!(user_args.next_back().unwrap(), "cargo-miri-marker-end"); - // Collect the rest and add it back at the end + // Collect the rest and add it back at the end. let mut user_args = user_args.collect::>(); args.append(&mut user_args); - // Run this in Miri + // Run this in Miri. true } else { false }; - let mut command = if needs_miri { let mut path = std::env::current_exe().expect("current executable path invalid"); path.set_file_name("miri"); diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 31bd1deb10f57..0f1501d5913b2 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -1,23 +1,23 @@ #![feature(rustc_private)] +extern crate env_logger; extern crate getopts; +#[macro_use] +extern crate log; +extern crate log_settings; extern crate miri; extern crate rustc; extern crate rustc_metadata; extern crate rustc_driver; extern crate rustc_errors; extern crate rustc_codegen_utils; -extern crate env_logger; -extern crate log_settings; extern crate syntax; -#[macro_use] -extern crate log; - use std::path::PathBuf; use std::str::FromStr; use std::env; +use miri::MiriConfig; use rustc::session::Session; use rustc_metadata::cstore::CStore; use rustc_driver::{Compilation, CompilerCalls, RustcDefaultCalls}; @@ -27,8 +27,6 @@ use rustc_codegen_utils::codegen_backend::CodegenBackend; use rustc::hir::def_id::LOCAL_CRATE; use syntax::ast; -use miri::MiriConfig; - struct MiriCompilerCalls { default: Box, miri_config: MiriConfig, @@ -79,7 +77,7 @@ impl<'a> CompilerCalls<'a> for MiriCompilerCalls { odir: &Option, ofile: &Option, ) -> Compilation { - // Called *before* build_controller. Add filename to miri arguments. + // Called *before* `build_controller`. Add filename to `miri` arguments. self.miri_config.args.insert(0, input.filestem().to_string()); self.default.late_callback(codegen_backend, matches, sess, cstore, input, odir, ofile) } @@ -125,27 +123,27 @@ fn after_analysis<'a, 'tcx>( } fn init_early_loggers() { - // Notice that our `extern crate log` is NOT the same as rustc's! So we have to initialize - // them both. We always initialize miri early. + // Note that our `extern crate log` is *not* the same as rustc's; as a result, we have to + // initialize them both, and we always initialize `miri`'s first. let env = env_logger::Env::new().filter("MIRI_LOG").write_style("MIRI_LOG_STYLE"); env_logger::init_from_env(env); - // We only initialize rustc if the env var is set (so the user asked for it). + // We only initialize `rustc` if the env var is set (so the user asked for it). // If it is not set, we avoid initializing now so that we can initialize - // later with our custom settings, and NOT log anything for what happens before - // miri gets started. + // later with our custom settings, and *not* log anything for what happens before + // `miri` gets started. if env::var("RUST_LOG").is_ok() { rustc_driver::init_rustc_env_logger(); } } fn init_late_loggers() { - // Initializing loggers right before we start evaluation. We overwrite the RUST_LOG - // env var if it is not set, control it based on MIRI_LOG. + // We initialize loggers right before we start evaluation. We overwrite the `RUST_LOG` + // env var if it is not set, control it based on `MIRI_LOG`. if let Ok(var) = env::var("MIRI_LOG") { if env::var("RUST_LOG").is_err() { - // We try to be a bit clever here: If MIRI_LOG is just a single level + // We try to be a bit clever here: if `MIRI_LOG` is just a single level // used for everything, we only apply it to the parts of rustc that are - // CTFE-related. Otherwise, we use it verbatim for RUST_LOG. + // CTFE-related. Otherwise, we use it verbatim for `RUST_LOG`. // This way, if you set `MIRI_LOG=trace`, you get only the right parts of // rustc traced, but you can also do `MIRI_LOG=miri=trace,rustc_mir::interpret=debug`. if log::Level::from_str(&var).is_ok() { @@ -158,7 +156,7 @@ fn init_late_loggers() { } } - // If MIRI_BACKTRACE is set and RUST_CTFE_BACKTRACE is not, set RUST_CTFE_BACKTRACE. + // If `MIRI_BACKTRACE` is set and `RUST_CTFE_BACKTRACE` is not, set `RUST_CTFE_BACKTRACE`. // Do this late, so we really only apply this to miri's errors. if let Ok(var) = env::var("MIRI_BACKTRACE") { if env::var("RUST_CTFE_BACKTRACE") == Err(env::VarError::NotPresent) { @@ -172,7 +170,7 @@ fn find_sysroot() -> String { return sysroot; } - // Taken from https://github.com/Manishearth/rust-clippy/pull/911. + // Taken from PR . let home = option_env!("RUSTUP_HOME").or(option_env!("MULTIRUST_HOME")); let toolchain = option_env!("RUSTUP_TOOLCHAIN").or(option_env!("MULTIRUST_TOOLCHAIN")); match (home, toolchain) { @@ -180,8 +178,8 @@ fn find_sysroot() -> String { _ => { option_env!("RUST_SYSROOT") .expect( - "Could not find sysroot. Either set MIRI_SYSROOT at run-time, or at \ - build-time specify RUST_SYSROOT env var or use rustup or multirust", + "could not find sysroot. either set `MIRI_SYSROOT` at run-time, or at \ + build-time specify `RUST_SYSROOT` env var or use rustup or multirust", ) .to_owned() } @@ -191,18 +189,18 @@ fn find_sysroot() -> String { fn main() { init_early_loggers(); - // Parse our arguments and split them across rustc and miri + // Parse our arguments and split them across `rustc` and `miri`. let mut validate = true; let mut rustc_args = vec![]; let mut miri_args = vec![]; let mut after_dashdash = false; for arg in std::env::args() { if rustc_args.is_empty() { - // Very first arg: for rustc + // Very first arg: for `rustc`. rustc_args.push(arg); } else if after_dashdash { - // Everything that comes is Miri args + // Everything that comes after are `miri` args. miri_args.push(arg); } else { match arg.as_str() { @@ -219,7 +217,7 @@ fn main() { } } - // Determine sysroot and let rustc know about it + // Determine sysroot and let rustc know about it. let sysroot_flag = String::from("--sysroot"); if !rustc_args.contains(&sysroot_flag) { rustc_args.push(sysroot_flag); diff --git a/src/fn_call.rs b/src/fn_call.rs index fa68f1d0d703a..fa8c61e678beb 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -7,7 +7,7 @@ use syntax::attr; use crate::*; impl<'a, 'mir, 'tcx> EvalContextExt<'a, 'mir, 'tcx> for crate::MiriEvalContext<'a, 'mir, 'tcx> {} -pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, 'mir, 'tcx> { +pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<'a, 'mir, 'tcx> { fn find_fn( &mut self, instance: ty::Instance<'tcx>, @@ -18,15 +18,15 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, let this = self.eval_context_mut(); trace!("eval_fn_call: {:#?}, {:?}", instance, dest.map(|place| *place)); - // first run the common hooks also supported by CTFE + // First, run the common hooks also supported by CTFE. if this.hook_fn(instance, args, dest)? { this.goto_block(ret)?; return Ok(None); } - // there are some more lang items we want to hook that CTFE does not hook (yet) + // There are some more lang items we want to hook that CTFE does not hook (yet). if this.tcx.lang_items().align_offset_fn() == Some(instance.def.def_id()) { // FIXME: return a real value in case the target allocation has an - // alignment bigger than the one requested + // alignment bigger than the one requested. let n = u128::max_value(); let dest = dest.unwrap(); let n = this.truncate(n, dest.layout); @@ -35,20 +35,20 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, return Ok(None); } - // Try to see if we can do something about foreign items + // Try to see if we can do something about foreign items. if this.tcx.is_foreign_item(instance.def_id()) { // An external function that we cannot find MIR for, but we can still run enough // of them to make miri viable. this.emulate_foreign_item(instance.def_id(), args, dest, ret)?; - // `goto_block` already handled + // `goto_block` already handled. return Ok(None); } - // Otherwise, load the MIR + // Otherwise, load the MIR. Ok(Some(this.load_mir(instance.def)?)) } - /// Emulate calling a foreign item, fail if the item is not supported. + /// Emulates calling a foreign item, failing if the item is not supported. /// This function will handle `goto_block` if needed. fn emulate_foreign_item( &mut self, @@ -63,11 +63,11 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, Some(name) => name.as_str(), None => this.tcx.item_name(def_id).as_str(), }; - // Strip linker suffixes (seen on 32bit macOS) + // Strip linker suffixes (seen on 32-bit macOS). let link_name = link_name.trim_end_matches("$UNIX2003"); let tcx = &{this.tcx.tcx}; - // first: functions that could diverge + // First: functions that could diverge. match &link_name[..] { "__rust_start_panic" | "panic_impl" => { return err!(MachineError("the evaluated program panicked".to_string())); @@ -79,9 +79,9 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, } } - // now: functions that assume a ret and dest + // Next: functions that assume a ret and dest. let dest = dest.expect("we already checked for a dest"); - let ret = ret.expect("dest is Some but ret is None"); + let ret = ret.expect("dest is `Some` but ret is `None`"); match &link_name[..] { "malloc" => { let size = this.read_scalar(args[0])?.to_usize(this)?; @@ -97,7 +97,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, let ret = this.deref_operand(args[0])?; let align = this.read_scalar(args[1])?.to_usize(this)?; let size = this.read_scalar(args[2])?.to_usize(this)?; - // align must be a power of 2, and also at least ptr-sized (wtf, POSIX) + // Align must be power of 2, and also at least ptr-sized (POSIX rules). if !align.is_power_of_two() { return err!(HeapAllocNonPowerOfTwoAlignment(align)); } @@ -209,10 +209,10 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, } "syscall" => { - // TODO: read `syscall` ids like `sysconf` ids and - // figure out some way to actually process some of them + // TODO: read `syscall` IDs like `sysconf` IDs and + // figure out some way to actually process some of them. // - // libc::syscall(NR_GETRANDOM, buf.as_mut_ptr(), buf.len(), GRND_NONBLOCK) + // `libc::syscall(NR_GETRANDOM, buf.as_mut_ptr(), buf.len(), GRND_NONBLOCK)` // is called if a `HashMap` is created the regular way. match this.read_scalar(args[0])?.to_usize(this)? { 318 | 511 => { @@ -222,7 +222,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, } id => { return err!(Unimplemented( - format!("miri does not support syscall id {}", id), + format!("miri does not support syscall ID {}", id), )) } } @@ -241,16 +241,22 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, } "__rust_maybe_catch_panic" => { - // 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 + // 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 f = this.read_scalar(args[0])?.to_ptr()?; let data = this.read_scalar(args[1])?.not_undef()?; let f_instance = this.memory().get_fn(f)?; this.write_null(dest)?; trace!("__rust_maybe_catch_panic: {:?}", f_instance); - // 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. + // Now we make a function call. + // TODO: consider making this reusable? `EvalContext::step` does something similar + // for the TLS destructors, and of course `eval_main`. let mir = this.load_mir(f_instance.def)?; let ret_place = MPlaceTy::dangling(this.layout_of(this.tcx.mk_unit())?, this).into(); this.push_stack_frame( @@ -258,7 +264,8 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, mir.span, mir, Some(ret_place), - StackPopCleanup::Goto(Some(ret)), // directly return to caller + // Directly return to caller. + StackPopCleanup::Goto(Some(ret)), )?; let mut args = this.frame().mir.args_iter(); @@ -273,10 +280,10 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, assert!(args.next().is_none(), "__rust_maybe_catch_panic argument has more arguments than expected"); - // We ourselves will return 0, eventually (because we will not return if we paniced) + // We ourselves will return `0`, eventually (because we will not return if we paniced). this.write_null(dest)?; - // Don't fall through, we do NOT want to `goto_block`! + // Don't fall through, we do *not* want to `goto_block`! return Ok(()); } @@ -321,10 +328,12 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, let ptr = this.read_scalar(args[0])?.not_undef()?; let val = this.read_scalar(args[1])?.to_i32()? as u8; let num = this.read_scalar(args[2])?.to_usize(this)?; - if let Some(idx) = this.memory().read_bytes(ptr, Size::from_bytes(num))?.iter().position( - |&c| c == val, - ) - { + let idx = this + .memory() + .read_bytes(ptr, Size::from_bytes(num))? + .iter() + .position(|&c| c == val); + if let Some(idx) = idx { let new_ptr = ptr.ptr_offset(Size::from_bytes(idx as u64), this)?; this.write_scalar(new_ptr, dest)?; } else { @@ -350,7 +359,11 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, let name_ptr = this.read_scalar(args[0])?.not_undef()?; if !name_ptr.is_null_ptr(this) { let name_ptr = name_ptr.to_ptr()?; - let name = this.memory().get(name_ptr.alloc_id)?.read_c_str(tcx, name_ptr)?.to_owned(); + let name = this + .memory() + .get(name_ptr.alloc_id)? + .read_c_str(tcx, name_ptr)? + .to_owned(); if !name.is_empty() && !name.contains(&b'=') { success = Some(this.machine.env_vars.remove(&name)); } @@ -381,7 +394,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, } } if let Some((name, value)) = new { - // +1 for the null terminator + // `+1` for the null terminator. let value_copy = this.memory_mut().allocate( Size::from_bytes((value.len() + 1) as u64), Align::from_bytes(1).unwrap(), @@ -390,7 +403,10 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, { let alloc = this.memory_mut().get_mut(value_copy.alloc_id)?; alloc.write_bytes(tcx, value_copy, &value)?; - let trailing_zero_ptr = value_copy.offset(Size::from_bytes(value.len() as u64), tcx)?; + let trailing_zero_ptr = value_copy.offset( + Size::from_bytes(value.len() as u64), + tcx, + )?; alloc.write_bytes(tcx, trailing_zero_ptr, &[0])?; } if let Some(var) = this.machine.env_vars.insert( @@ -435,8 +451,10 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, } } else { eprintln!("Miri: Ignored output to FD {}", fd); - n as i64 // pretend it all went well - }; // now result is the value we return back to the program + // Pretend it all went well. + n as i64 + }; + // Now, `result` is the value we return back to the program. this.write_scalar( Scalar::from_int(result, dest.layout.size), dest, @@ -449,7 +467,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, this.write_scalar(Scalar::from_uint(n as u64, dest.layout.size), dest)?; } - // Some things needed for sys::thread initialization to go through + // Some things needed for `sys::thread` initialization to go through. "signal" | "sigaction" | "sigaltstack" => { this.write_scalar(Scalar::from_int(0, dest.layout.size), dest)?; } @@ -458,7 +476,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, let name = this.read_scalar(args[0])?.to_i32()?; trace!("sysconf() called with name {}", name); - // cache the sysconf integers via miri's global cache + // Cache the sysconf integers via Miri's global cache. let paths = &[ (&["libc", "_SC_PAGESIZE"], Scalar::from_int(4096, dest.layout.size)), (&["libc", "_SC_GETPW_R_SIZE_MAX"], Scalar::from_int(-1, dest.layout.size)), @@ -493,11 +511,11 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, this.write_null(dest)?; } - // Hook pthread calls that go to the thread-local storage memory subsystem + // Hook pthread calls that go to the thread-local storage memory subsystem. "pthread_key_create" => { let key_ptr = this.read_scalar(args[0])?.to_ptr()?; - // Extract the function type out of the signature (that seems easier than constructing it ourselves...) + // Extract the function type out of the signature (that seems easier than constructing it ourselves). let dtor = match this.read_scalar(args[1])?.not_undef()? { Scalar::Ptr(dtor_ptr) => Some(this.memory().get_fn(dtor_ptr)?), Scalar::Bits { bits: 0, size } => { @@ -507,12 +525,15 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, 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].layout.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; + // Figure out how large a pthread TLS key actually is. + // This is `libc::pthread_key_t`. + let key_type = args[0].layout.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_layout = this.layout_of(key_type)?; - // Create key and write it into the memory where key_ptr wants it + // Create key and write it into the memory where `key_ptr` wants it. let key = this.machine.tls.create_tls_key(dtor, tcx) as u128; if key_layout.size.bits() < 128 && key >= (1u128 << key_layout.size.bits() as u128) { return err!(OutOfTls); @@ -526,7 +547,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, key_layout.size, )?; - // Return success (0) + // Return success (`0`). this.write_null(dest)?; } "pthread_key_delete" => { @@ -545,29 +566,31 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, let new_ptr = this.read_scalar(args[1])?.not_undef()?; this.machine.tls.store_tls(key, new_ptr)?; - // Return success (0) + // Return success (`0`). this.write_null(dest)?; } - // Determining stack base address + // Determine stack base address. "pthread_attr_init" | "pthread_attr_destroy" | "pthread_attr_get_np" | "pthread_getattr_np" | "pthread_self" | "pthread_get_stacksize_np" => { this.write_null(dest)?; } "pthread_attr_getstack" => { - // second argument is where we are supposed to write the stack size + // Second argument is where we are supposed to write the stack size. let ptr = this.deref_operand(args[1])?; - let stackaddr = Scalar::from_int(0x80000, args[1].layout.size); // just any address - this.write_scalar(stackaddr, ptr.into())?; - // return 0 + // Just any address. + let stack_addr = Scalar::from_int(0x80000, args[1].layout.size); + this.write_scalar(stack_addr, ptr.into())?; + // Return success (`0`). this.write_null(dest)?; } "pthread_get_stackaddr_np" => { - let stackaddr = Scalar::from_int(0x80000, dest.layout.size); // just any address - this.write_scalar(stackaddr, dest)?; + // Just any address. + let stack_addr = Scalar::from_int(0x80000, dest.layout.size); + this.write_scalar(stack_addr, dest)?; } - // Stub out calls for condvar, mutex and rwlock to just return 0 + // Stub out calls for condvar, mutex and rwlock, to just return `0`. "pthread_mutexattr_init" | "pthread_mutexattr_settype" | "pthread_mutex_init" | "pthread_mutexattr_destroy" | "pthread_mutex_lock" | "pthread_mutex_unlock" | "pthread_mutex_destroy" | "pthread_rwlock_rdlock" | "pthread_rwlock_unlock" | @@ -578,7 +601,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, } "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 + // This is a horrible hack, but since the guard page mechanism calls mmap and expects a particular return value, we just give it that value. let addr = this.read_scalar(args[0])?.not_undef()?; this.write_scalar(addr, dest)?; } @@ -586,9 +609,9 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, this.write_null(dest)?; } - // macOS API stubs + // macOS API stubs. "_tlv_atexit" => { - // FIXME: Register the dtor + // FIXME: register the destructor. }, "_NSGetArgc" => { this.write_scalar(Scalar::Ptr(this.machine.argc.unwrap()), dest)?; @@ -597,7 +620,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, this.write_scalar(Scalar::Ptr(this.machine.argv.unwrap()), dest)?; }, - // Windows API stubs + // Windows API stubs. "SetLastError" => { let err = this.read_scalar(args[0])?.to_u32()?; this.machine.last_error = err; @@ -607,30 +630,30 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, } "AddVectoredExceptionHandler" => { - // any non zero value works for the stdlib. This is just used for stackoverflows anyway + // Any non zero value works for the stdlib. This is just used for stack overflows anyway. this.write_scalar(Scalar::from_int(1, dest.layout.size), dest)?; }, "InitializeCriticalSection" | "EnterCriticalSection" | "LeaveCriticalSection" | "DeleteCriticalSection" => { - // Nothing to do, not even a return value + // Nothing to do, not even a return value. }, "GetModuleHandleW" | "GetProcAddress" | "TryEnterCriticalSection" | "GetConsoleScreenBufferInfo" | "SetConsoleTextAttribute" => { - // pretend these do not exist/nothing happened, by returning zero + // Pretend these do not exist / nothing happened, by returning zero. this.write_null(dest)?; }, "GetSystemInfo" => { let system_info = this.deref_operand(args[0])?; let system_info_ptr = system_info.ptr.to_ptr()?; - // initialize with 0 + // Initialize with `0`. this.memory_mut().get_mut(system_info_ptr.alloc_id)? .write_repeat(tcx, system_info_ptr, 0, system_info.layout.size)?; - // set number of processors to 1 + // Set number of processors to `1`. let dword_size = Size::from_bytes(4); let offset = 2*dword_size + 3*tcx.pointer_size(); this.memory_mut().get_mut(system_info_ptr.alloc_id)? @@ -643,13 +666,14 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, } "TlsAlloc" => { - // This just creates a key; Windows does not natively support TLS dtors. + // This just creates a key; Windows does not natively support TLS destructors. - // Create key and return it + // Create key and return it. let key = this.machine.tls.create_tls_key(None, tcx) 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) { + // 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); } this.write_scalar(Scalar::from_uint(key, dest.layout.size), dest)?; @@ -664,12 +688,12 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, let new_ptr = this.read_scalar(args[1])?.not_undef()?; this.machine.tls.store_tls(key, new_ptr)?; - // Return success (1) + // Return success (`1`). this.write_scalar(Scalar::from_int(1, dest.layout.size), dest)?; } "GetStdHandle" => { let which = this.read_scalar(args[0])?.to_i32()?; - // We just make this the identity function, so we know later in "WriteFile" + // We just make this the identity function, so we know later in `WriteFile` // which one it is. this.write_scalar(Scalar::from_int(which, this.pointer_size()), dest)?; } @@ -678,7 +702,8 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, let buf = this.read_scalar(args[1])?.not_undef()?; let n = this.read_scalar(args[2])?.to_u32()?; let written_place = this.deref_operand(args[3])?; - this.write_null(written_place.into())?; // spec says we always write 0 first + // Spec says to always write `0` first. + this.write_null(written_place.into())?; let written = if handle == -11 || handle == -12 { // stdout/stderr use std::io::{self, Write}; @@ -692,24 +717,25 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, res.ok().map(|n| n as u32) } else { eprintln!("Miri: Ignored output to handle {}", handle); - Some(n) // pretend it all went well + // Pretend it all went well. + Some(n) }; - // If there was no error, write back how much was written + // If there was no error, write back how much was written. if let Some(n) = written { this.write_scalar(Scalar::from_uint(n, Size::from_bits(32)), written_place.into())?; } - // Return whether this was a success + // Return whether this was a success. this.write_scalar( Scalar::from_int(if written.is_some() { 1 } else { 0 }, dest.layout.size), dest, )?; } "GetConsoleMode" => { - // Everything is a pipe + // Everything is a pipe. this.write_null(dest)?; } "GetEnvironmentVariableW" => { - // This is not the env var you are looking for + // This is not the env var you are looking for. this.machine.last_error = 203; // ERROR_ENVVAR_NOT_FOUND this.write_null(dest)?; } @@ -717,7 +743,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, this.write_scalar(Scalar::Ptr(this.machine.cmd_line.unwrap()), dest)?; } - // We can't execute anything else + // We can't execute anything else. _ => { return err!(Unimplemented( format!("can't call foreign function: {}", link_name), diff --git a/src/helpers.rs b/src/helpers.rs index fab0c67d0aa4b..cdef224b3e990 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -6,8 +6,9 @@ use rustc::hir::def_id::{DefId, CRATE_DEF_INDEX}; use crate::*; impl<'a, 'mir, 'tcx> EvalContextExt<'a, 'mir, 'tcx> for crate::MiriEvalContext<'a, 'mir, 'tcx> {} -pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, 'mir, 'tcx> { - /// Get an instance for a path. + +pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<'a, 'mir, 'tcx> { + /// Gets an instance for a path. fn resolve_path(&self, path: &[&str]) -> EvalResult<'tcx, ty::Instance<'tcx>> { let this = self.eval_context_ref(); this.tcx @@ -42,7 +43,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, }) } - /// Visit the memory covered by `place`, sensitive to freezing: The 3rd parameter + /// Visits the memory covered by `place`, sensitive to freezing: the 3rd parameter /// will be true if this is frozen, false if this is in an `UnsafeCell`. fn visit_freeze_sensitive( &self, @@ -57,7 +58,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, .map(|(size, _)| size) .unwrap_or_else(|| place.layout.size) ); - // Store how far we proceeded into the place so far. Everything to the left of + // Store how far we proceeded into the place so far. Everything to the left of // this offset has already been handled, in the sense that the frozen parts // have had `action` called on them. let mut end_ptr = place.ptr; @@ -139,7 +140,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, &self.ecx } - // Hook to detect `UnsafeCell` + // Hook to detect `UnsafeCell`. fn visit_value(&mut self, v: MPlaceTy<'tcx, Borrow>) -> EvalResult<'tcx> { trace!("UnsafeCellVisitor: {:?} {:?}", *v, v.layout.ty); @@ -159,7 +160,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, } } - // Make sure we visit aggregrates in increasing offset order + // Make sure we visit aggregrates in increasing offset order. fn visit_aggregate( &mut self, place: MPlaceTy<'tcx, Borrow>, @@ -179,17 +180,17 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, } layout::FieldPlacement::Union { .. } => { // Uh, what? - bug!("A union is not an aggregate we should ever visit") + bug!("a union is not an aggregate we should ever visit") } } } - // We have to do *something* for unions + // We have to do *something* for unions. fn visit_union(&mut self, v: MPlaceTy<'tcx, Borrow>) -> EvalResult<'tcx> { // With unions, we fall back to whatever the type says, to hopefully be consistent // with LLVM IR. - // FIXME Are we consistent? And is this really the behavior we want? + // FIXME: are we consistent, and is this really the behavior we want? let frozen = self.ecx.type_is_freeze(v.layout.ty); if frozen { Ok(()) @@ -198,10 +199,10 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, } } - // We should never get to a primitive, but always short-circuit somewhere above + // We should never get to a primitive, but always short-circuit somewhere above. fn visit_primitive(&mut self, _v: MPlaceTy<'tcx, Borrow>) -> EvalResult<'tcx> { - bug!("We should always short-circit before coming to a primitive") + bug!("we should always short-circuit before coming to a primitive") } } } diff --git a/src/intrinsic.rs b/src/intrinsic.rs index 6f9dfb3971675..70880c4f7da82 100644 --- a/src/intrinsic.rs +++ b/src/intrinsic.rs @@ -1,9 +1,8 @@ use rustc::mir; +use rustc::mir::interpret::{EvalResult, PointerArithmetic}; use rustc::ty::layout::{self, LayoutOf, Size}; use rustc::ty; -use rustc::mir::interpret::{EvalResult, PointerArithmetic}; - use crate::{ PlaceTy, OpTy, ImmTy, Immediate, Scalar, ScalarMaybeUndef, Borrow, OperatorEvalContextExt @@ -268,7 +267,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, // However, this only affects direct calls of the intrinsic; calls to the stable // functions wrapping them do get their validation. // FIXME: should we check that the destination pointer is aligned even for ZSTs? - if !dest.layout.is_zst() { // nothing to do for ZST + if !dest.layout.is_zst() { match dest.layout.abi { layout::Abi::Scalar(ref s) => { let x = Scalar::from_int(0, s.value.size(this)); @@ -443,7 +442,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, // However, this only affects direct calls of the intrinsic; calls to the stable // functions wrapping them do get their validation. // FIXME: should we check alignment for ZSTs? - if !dest.layout.is_zst() { // nothing to do for ZST + if !dest.layout.is_zst() { match dest.layout.abi { layout::Abi::Scalar(..) => { let x = ScalarMaybeUndef::Undef; diff --git a/src/lib.rs b/src/lib.rs index 1608bc1f3028b..df118ea09828f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -4,7 +4,6 @@ #[macro_use] extern crate log; - // From rustc. extern crate syntax; #[macro_use] @@ -13,6 +12,15 @@ extern crate rustc_data_structures; extern crate rustc_mir; extern crate rustc_target; +mod fn_call; +mod operator; +mod intrinsic; +mod helpers; +mod tls; +mod range_map; +mod mono_hash_map; +mod stacked_borrows; + use std::collections::HashMap; use std::borrow::Cow; @@ -20,36 +28,27 @@ use rustc::ty::{self, TyCtxt, query::TyCtxtAt}; use rustc::ty::layout::{LayoutOf, Size, Align}; use rustc::hir::{self, def_id::DefId}; use rustc::mir; - +pub use rustc_mir::interpret::*; +// Resolve ambiguity. +pub use rustc_mir::interpret::{self, AllocMap, PlaceTy}; use syntax::attr; use syntax::source_map::DUMMY_SP; -pub use rustc_mir::interpret::*; -pub use rustc_mir::interpret::{self, AllocMap, PlaceTy}; // resolve ambiguity - -mod fn_call; -mod operator; -mod intrinsic; -mod helpers; -mod tls; -mod range_map; -mod mono_hash_map; -mod stacked_borrows; - pub use crate::fn_call::EvalContextExt as MissingFnsEvalContextExt; pub use crate::operator::EvalContextExt as OperatorEvalContextExt; pub use crate::intrinsic::EvalContextExt as IntrinsicEvalContextExt; pub use crate::tls::{EvalContextExt as TlsEvalContextExt, TlsData}; use crate::range_map::RangeMap; -#[allow(unused_imports)] // FIXME rustc bug https://github.com/rust-lang/rust/issues/53682 +// FIXME: rustc bug, issue . +#[allow(unused_imports)] pub use crate::helpers::{EvalContextExt as HelpersEvalContextExt}; use crate::mono_hash_map::MonoHashMap; pub use crate::stacked_borrows::{EvalContextExt as StackedBorEvalContextExt}; -// Used by priroda +// Used by priroda. pub use crate::stacked_borrows::{Borrow, Stack, Stacks, BorStackItem}; -/// Insert rustc arguments at the beginning of the argument list that miri wants to be +/// Insert rustc arguments at the beginning of the argument list that Miri wants to be /// set per default, for maximal validation power. pub fn miri_default_args() -> &'static [&'static str] { // The flags here should be kept in sync with what bootstrap adds when `test-miri` is @@ -57,14 +56,14 @@ pub fn miri_default_args() -> &'static [&'static str] { &["-Zalways-encode-mir", "-Zmir-emit-retag", "-Zmir-opt-level=0", "--cfg=miri"] } -/// Configuration needed to spawn a Miri instance +/// Configuration needed to spawn a Miri instance. #[derive(Clone)] pub struct MiriConfig { pub validate: bool, pub args: Vec, } -// Used by priroda +// Used by priroda. pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( tcx: TyCtxt<'a, 'tcx, 'tcx>, main_id: DefId, @@ -105,14 +104,15 @@ pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( ))); } - // Return value (in static memory so that it does not count as leak) + // Return value (in static memory so that it does not count as leak). let ret = ecx.layout_of(start_mir.return_ty())?; let ret_ptr = ecx.allocate(ret, MiriMemoryKind::MutStatic.into()); - // Push our stack frame + // Push our stack frame. ecx.push_stack_frame( start_instance, - DUMMY_SP, // there is no call site, we want no span + // There is no call site. + DUMMY_SP, start_mir, Some(ret_ptr.into()), StackPopCleanup::None { cleanup: true }, @@ -120,26 +120,26 @@ pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( let mut args = ecx.frame().mir.args_iter(); - // First argument: pointer to main() + // First argument: pointer to `main()`. let main_ptr = ecx.memory_mut().create_fn_alloc(main_instance).with_default_tag(); let dest = ecx.eval_place(&mir::Place::Local(args.next().unwrap()))?; ecx.write_scalar(Scalar::Ptr(main_ptr), dest)?; - // Second argument (argc): 1 + // Second argument (argc): `1`. let dest = ecx.eval_place(&mir::Place::Local(args.next().unwrap()))?; let argc = Scalar::from_uint(config.args.len() as u128, dest.layout.size); ecx.write_scalar(argc, dest)?; - // Store argc for macOS _NSGetArgc + // Store argc for macOS: `_NSGetArgc`. { let argc_place = ecx.allocate(dest.layout, MiriMemoryKind::Env.into()); ecx.write_scalar(argc, argc_place.into())?; ecx.machine.argc = Some(argc_place.ptr.to_ptr()?); } - // FIXME: extract main source file path - // Third argument (argv): Created from config.args + // FIXME: extract main source file path. + // Third argument (`argv`): created from `config.args`. let dest = ecx.eval_place(&mir::Place::Local(args.next().unwrap()))?; - // For Windows, construct a command string with all the aguments + // For Windows, construct a command string with all the aguments. let mut cmd = String::new(); for arg in config.args.iter() { if !cmd.is_empty() { @@ -147,11 +147,12 @@ pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( } cmd.push_str(&*shell_escape::windows::escape(arg.as_str().into())); } - cmd.push(std::char::from_u32(0).unwrap()); // don't forget 0 terminator + // Don't forget `0` terminator. + cmd.push(std::char::from_u32(0).unwrap()); // Collect the pointers to the individual strings. let mut argvs = Vec::>::new(); for arg in config.args { - // Add 0 terminator + // Add `0` terminator. let mut arg = arg.into_bytes(); arg.push(0); argvs.push(ecx.memory_mut().allocate_static_bytes(arg.as_slice()).with_default_tag()); @@ -164,16 +165,16 @@ pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( ecx.write_scalar(Scalar::Ptr(arg), place.into())?; } ecx.memory_mut().mark_immutable(argvs_place.to_ptr()?.alloc_id)?; - // Write a pointe to that place as the argument. + // Write a pointer to that place as the argument. let argv = argvs_place.ptr; ecx.write_scalar(argv, dest)?; - // Store argv for macOS _NSGetArgv + // Store `argv` for macOS `_NSGetArgv`. { let argv_place = ecx.allocate(dest.layout, MiriMemoryKind::Env.into()); ecx.write_scalar(argv, argv_place.into())?; ecx.machine.argv = Some(argv_place.ptr.to_ptr()?); } - // Store cmdline as UTF-16 for Windows GetCommandLineW + // Store command line as UTF-16 for Windows `GetCommandLineW`. { let tcx = &{ecx.tcx.tcx}; let cmd_utf16: Vec = cmd.encode_utf16().collect(); @@ -183,7 +184,7 @@ pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( MiriMemoryKind::Env.into(), ).with_default_tag(); ecx.machine.cmd_line = Some(cmd_ptr); - // store the UTF-16 string + // Store the UTF-16 string. let char_size = Size::from_bytes(2); let cmd_alloc = ecx.memory_mut().get_mut(cmd_ptr.alloc_id)?; let mut cur_ptr = cmd_ptr; @@ -208,9 +209,9 @@ pub fn eval_main<'a, 'tcx: 'a>( main_id: DefId, config: MiriConfig, ) { - let mut ecx = create_ecx(tcx, main_id, config).expect("Couldn't create ecx"); + let mut ecx = create_ecx(tcx, main_id, config).expect("couldn't create ecx"); - // Run! The main execution. + // Perform the main execution. let res: EvalResult = (|| { ecx.run()?; ecx.run_tls_dtors() @@ -243,7 +244,7 @@ pub fn eval_main<'a, 'tcx: 'a>( let mut err = struct_error(ecx.tcx.tcx.at(span), msg.as_str()); let frames = ecx.generate_stacktrace(None); err.span_label(span, e); - // we iterate with indices because we need to look at the next frame (the caller) + // We iterate with indices because we need to look at the next frame (the caller). for idx in 0..frames.len() { let frame_info = &frames[idx]; let call_site_is_local = frames.get(idx+1).map_or(false, @@ -273,16 +274,15 @@ pub fn eval_main<'a, 'tcx: 'a>( } } - #[derive(Debug, Copy, Clone, PartialEq, Eq)] pub enum MiriMemoryKind { - /// `__rust_alloc` memory + /// `__rust_alloc` memory. Rust, - /// `malloc` memory + /// `malloc` memory. C, - /// Part of env var emulation + /// Part of env var emulation. Env, - /// mutable statics + /// Mutable statics. MutStatic, } @@ -305,27 +305,27 @@ impl MayLeak for MiriMemoryKind { } pub struct Evaluator<'tcx> { - /// Environment variables set by `setenv` - /// Miri does not expose env vars from the host to the emulated program + /// Environment variables set by `setenv`. + /// Miri does not expose env vars from the host to the emulated program. pub(crate) env_vars: HashMap, Pointer>, /// Program arguments (`Option` because we can only initialize them after creating the ecx). /// These are *pointers* to argc/argv because macOS. - /// We also need the full cmdline as one string because Window. + /// We also need the full command line as one string because of Windows. pub(crate) argc: Option>, pub(crate) argv: Option>, pub(crate) cmd_line: Option>, - /// Last OS error + /// Last OS error. pub(crate) last_error: u32, - /// TLS state + /// TLS state. pub(crate) tls: TlsData<'tcx>, - /// Whether to enforce the validity invariant + /// Whether to enforce the validity invariant. pub(crate) validate: bool, - /// Stacked Borrows state + /// Stacked Borrows state. pub(crate) stacked_borrows: stacked_borrows::State, } @@ -344,10 +344,11 @@ impl<'tcx> Evaluator<'tcx> { } } -#[allow(dead_code)] // FIXME https://github.com/rust-lang/rust/issues/47131 +// FIXME: rustc issue . +#[allow(dead_code)] type MiriEvalContext<'a, 'mir, 'tcx> = EvalContext<'a, 'mir, 'tcx, Evaluator<'tcx>>; -// A little trait that's useful to be inherited by extension traits +// A little trait that's useful to be inherited by extension traits. pub trait MiriEvalContextExt<'a, 'mir, 'tcx> { fn eval_context_ref(&self) -> &MiriEvalContext<'a, 'mir, 'tcx>; fn eval_context_mut(&mut self) -> &mut MiriEvalContext<'a, 'mir, 'tcx>; @@ -380,7 +381,7 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { ecx.machine.validate } - /// Returns Ok() when the function was handled, fail otherwise + /// Returns `Ok()` when the function was handled; fail otherwise. #[inline(always)] fn find_fn( ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, @@ -417,7 +418,7 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { dest: PlaceTy<'tcx, Borrow>, ) -> EvalResult<'tcx> { trace!("box_alloc for {:?}", dest.layout.ty); - // Call the `exchange_malloc` lang item + // Call the `exchange_malloc` lang item. let malloc = ecx.tcx.lang_items().exchange_malloc_fn().unwrap(); let malloc = ty::Instance::mono(ecx.tcx.tcx, malloc); let malloc_mir = ecx.load_mir(malloc.def)?; @@ -426,28 +427,31 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { malloc_mir.span, malloc_mir, Some(dest), - // Don't do anything when we are done. The statement() function will increment + // Don't do anything when we are done. The `statement()` function will increment // the old stack frame's stmt counter to the next statement, which means that when - // exchange_malloc returns, we go on evaluating exactly where we want to be. + // `exchange_malloc` returns, we go on evaluating exactly where we want to be. StackPopCleanup::None { cleanup: true }, )?; let mut args = ecx.frame().mir.args_iter(); let layout = ecx.layout_of(dest.layout.ty.builtin_deref(false).unwrap().ty)?; - // First argument: size - // (0 is allowed here, this is expected to be handled by the lang item) + // First argument: `size`. + // (`0` is allowed here -- this is expected to be handled by the lang item). let arg = ecx.eval_place(&mir::Place::Local(args.next().unwrap()))?; let size = layout.size.bytes(); ecx.write_scalar(Scalar::from_uint(size, arg.layout.size), arg)?; - // Second argument: align + // Second argument: `align`. let arg = ecx.eval_place(&mir::Place::Local(args.next().unwrap()))?; let align = layout.align.abi.bytes(); ecx.write_scalar(Scalar::from_uint(align, arg.layout.size), arg)?; - // No more arguments - assert!(args.next().is_none(), "exchange_malloc lang item has more arguments than expected"); + // No more arguments. + assert!( + args.next().is_none(), + "`exchange_malloc` lang item has more arguments than expected" + ); Ok(()) } @@ -464,7 +468,7 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { let alloc = match &link_name[..] { "__cxa_thread_atexit_impl" => { - // This should be all-zero, pointer-sized + // This should be all-zero, pointer-sized. let size = tcx.data_layout.pointer_size; let data = vec![0; size.bytes() as usize]; let extra = AllocationExtra::memory_allocated(size, memory_extra); @@ -480,7 +484,7 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { #[inline(always)] fn before_terminator(_ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>) -> EvalResult<'tcx> { - // We are not interested in detecting loops + // We are not interested in detecting loops. Ok(()) } @@ -513,16 +517,16 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { mutability: Option, ) -> EvalResult<'tcx, Scalar> { let size = ecx.size_and_align_of_mplace(place)?.map(|(size, _)| size) - // for extern types, just cover what we can + // For extern types, just cover what we can. .unwrap_or_else(|| place.layout.size); if !ecx.tcx.sess.opts.debugging_opts.mir_emit_retag || !Self::enforce_validity(ecx) || size == Size::ZERO { - // No tracking + // No tracking. Ok(place.ptr) } else { ecx.ptr_dereference(place, size, mutability.into())?; - // We never change the pointer + // We never change the pointer. Ok(place.ptr) } } @@ -534,7 +538,7 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { kind: MemoryKind, ) -> Pointer { if !ecx.machine.validate { - // No tracking + // No tracking. ptr.with_default_tag() } else { let tag = ecx.tag_new_allocation(ptr.alloc_id, kind); diff --git a/src/mono_hash_map.rs b/src/mono_hash_map.rs index ec1a5fdb4288f..f2abe4217306c 100644 --- a/src/mono_hash_map.rs +++ b/src/mono_hash_map.rs @@ -1,6 +1,6 @@ -//! This is a "monotonic HashMap": A HashMap that, when shared, can be pushed to but not -//! otherwise mutated. We also Box items in the map. This means we can safely provide -//! shared references into existing items in the HashMap, because they will not be dropped +//! This is a "monotonic `HashMap`": A `HashMap` that, when shared, can be pushed to but not +//! otherwise mutated. We also box items in the map. This means we can safely provide +//! shared references into existing items in the `HashMap`, because they will not be dropped //! (from being removed) or moved (because they are boxed). //! The API is is completely tailored to what `memory.rs` needs. It is still in //! a separate file to minimize the amount of code that has to care about the unsafety. @@ -18,7 +18,7 @@ use crate::AllocMap; pub struct MonoHashMap(RefCell>>); impl MonoHashMap { - /// This function exists for priroda to be able to iterate over all evaluator memory + /// This function exists for priroda to be able to iterate over all evaluator memory. /// /// The function is somewhat roundabout with the closure argument because internally the /// `MonoHashMap` uses a `RefCell`. When iterating over the `HashMap` inside the `RefCell`, diff --git a/src/operator.rs b/src/operator.rs index b64ccf5462d6a..0cba240a7d0fe 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -60,7 +60,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' _ => {}, } - // Now we expect no more fat pointers + // Now we expect no more fat pointers. let left_layout = left.layout; let left = left.to_scalar()?; let right_layout = right.layout; @@ -149,9 +149,9 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' if left.alloc_id == right.alloc_id { left.offset == right.offset } else { - // This accepts one-past-the end. So technically there is still + // This accepts one-past-the end. Thus, there is still technically // some non-determinism that we do not fully rule out when two - // allocations sit right next to each other. The C/C++ standards are + // allocations sit right next to each other. The C/C++ standards are // somewhat fuzzy about this case, so I think for now this check is // "good enough". // Dead allocations in miri cannot overlap with live allocations, but @@ -159,17 +159,17 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' // both pointers to be live. self.memory().check_bounds_ptr(left, InboundsCheck::Live)?; self.memory().check_bounds_ptr(right, InboundsCheck::Live)?; - // Two in-bounds pointers, we can compare across allocations + // Two in-bounds pointers, we can compare across allocations. left == right } } - // Comparing ptr and integer + // Comparing ptr and integer. (Scalar::Ptr(ptr), Scalar::Bits { bits, size }) | (Scalar::Bits { bits, size }, Scalar::Ptr(ptr)) => { assert_eq!(size as u64, self.pointer_size().bytes()); let bits = bits as u64; - // Case I: Comparing with NULL + // Case I: Comparing with NULL. if bits == 0 { // Test if the ptr is in-bounds. Then it cannot be NULL. // Even dangling pointers cannot be NULL. @@ -186,7 +186,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' if ptr.offset.bytes() % alloc_align.bytes() == 0 { // The offset maintains the allocation alignment, so we know `base+offset` // is aligned by `alloc_align`. - // FIXME: We could be even more general, e.g. offset 2 into a 4-aligned + // FIXME: We could be even more general, e.g., offset 2 into a 4-aligned // allocation cannot equal 3. if bits % alloc_align.bytes() != 0 { // The integer is *not* aligned. So they cannot be equal. @@ -198,7 +198,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' { // Compute the highest address at which this allocation could live. // Substract one more, because it must be possible to add the size - // to the base address without overflowing -- IOW, the very last address + // to the base address without overflowing; that is, the very last address // of the address space is never dereferencable (but it can be in-bounds, i.e., // one-past-the-end). let max_base_addr = @@ -208,7 +208,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' ) as u64; if let Some(max_addr) = max_base_addr.checked_add(ptr.offset.bytes()) { if bits > max_addr { - // The integer is too big, this cannot possibly be equal + // The integer is too big, this cannot possibly be equal. return Ok(false) } } @@ -235,7 +235,8 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' Ok(match bin_op { Sub => - // The only way this can overflow is by underflowing, so signdeness of the right operands does not matter + // The only way this can overflow is by underflowing, so signdeness of the right + // operands does not matter. map_to_primval(left.overflowing_signed_offset(-(right as i128), self)), Add if signed => map_to_primval(left.overflowing_signed_offset(right as i128, self)), @@ -245,17 +246,17 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' BitAnd if !signed => { let ptr_base_align = self.memory().get(left.alloc_id)?.align.bytes(); let base_mask = { - // FIXME: Use interpret::truncate, once that takes a Size instead of a Layout + // FIXME: use `interpret::truncate`, once that takes a `Size` instead of a `Layout`. let shift = 128 - self.memory().pointer_size().bits(); let value = !(ptr_base_align as u128 - 1); - // truncate (shift left to drop out leftover values, shift right to fill with zeroes) + // Truncate (shift left to drop out leftover values, shift right to fill with zeroes). (value << shift) >> shift }; let ptr_size = self.memory().pointer_size().bytes() as u8; - trace!("Ptr BitAnd, align {}, operand {:#010x}, base_mask {:#010x}", + trace!("ptr BitAnd, align {}, operand {:#010x}, base_mask {:#010x}", ptr_base_align, right, base_mask); if right & base_mask == base_mask { - // Case 1: The base address bits are all preserved, i.e., right is all-1 there + // Case 1: the base address bits are all preserved, i.e., right is all-1 there. let offset = (left.offset.bytes() as u128 & right) as u64; ( Scalar::Ptr(Pointer::new_with_tag( @@ -266,7 +267,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' false, ) } else if right & base_mask == 0 { - // Case 2: The base address bits are all taken away, i.e., right is all-0 there + // Case 2: the base address bits are all taken away, i.e., right is all-0 there. (Scalar::Bits { bits: (left.offset.bytes() as u128) & right, size: ptr_size }, false) } else { return err!(ReadPointerAsBytes); @@ -275,43 +276,57 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' Rem if !signed => { // Doing modulo a divisor of the alignment is allowed. - // (Intuition: Modulo a divisor leaks less information.) + // (Intuition: modulo a divisor leaks less information.) let ptr_base_align = self.memory().get(left.alloc_id)?.align.bytes(); let right = right as u64; let ptr_size = self.memory().pointer_size().bytes() as u8; if right == 1 { - // modulo 1 is always 0 + // Modulo 1 is always 0. (Scalar::Bits { bits: 0, size: ptr_size }, false) } else if ptr_base_align % right == 0 { - // the base address would be cancelled out by the modulo operation, so we can - // just take the modulo of the offset - (Scalar::Bits { bits: (left.offset.bytes() % right) as u128, size: ptr_size }, false) + // The base address would be cancelled out by the modulo operation, so we can + // just take the modulo of the offset. + ( + Scalar::Bits { + bits: (left.offset.bytes() % right) as u128, + size: ptr_size + }, + false, + ) } else { return err!(ReadPointerAsBytes); } } _ => { - let msg = format!("unimplemented binary op on pointer {:?}: {:?}, {:?} ({})", bin_op, left, right, if signed { "signed" } else { "unsigned" }); + let msg = format!( + "unimplemented binary op on pointer {:?}: {:?}, {:?} ({})", + bin_op, + left, + right, + if signed { "signed" } else { "unsigned" } + ); return err!(Unimplemented(msg)); } }) } - /// This function raises an error if the offset moves the pointer outside of its allocation. We consider - /// ZSTs their own huge allocation that doesn't overlap with anything (and nothing moves in there because the size is 0). - /// We also consider the NULL pointer its own separate allocation, and all the remaining integers pointers their own - /// allocation. + /// Raises an error if the offset moves the pointer outside of its allocation. + /// We consider ZSTs their own huge allocation that doesn't overlap with anything (and nothing + /// moves in there because the size is 0). We also consider the NULL pointer its own separate + /// allocation, and all the remaining integers pointers their own allocation. fn pointer_offset_inbounds( &self, ptr: Scalar, pointee_ty: Ty<'tcx>, offset: i64, ) -> EvalResult<'tcx, Scalar> { - // FIXME: assuming here that type size is < i64::max_value() + // FIXME: assuming here that type size is less than `i64::max_value()`. let pointee_size = self.layout_of(pointee_ty)?.size.bytes() as i64; - let offset = offset.checked_mul(pointee_size).ok_or_else(|| EvalErrorKind::Overflow(mir::BinOp::Mul))?; - // Now let's see what kind of pointer this is + let offset = offset + .checked_mul(pointee_size) + .ok_or_else(|| EvalErrorKind::Overflow(mir::BinOp::Mul))?; + // Now let's see what kind of pointer this is. if let Scalar::Ptr(ptr) = ptr { // Both old and new pointer must be in-bounds of a *live* allocation. // (Of the same allocation, but that part is trivial with our representation.) diff --git a/src/range_map.rs b/src/range_map.rs index 80fc98a86965d..f94917e612a8f 100644 --- a/src/range_map.rs +++ b/src/range_map.rs @@ -3,7 +3,7 @@ //! Implements a map from integer indices to data. //! Rather than storing data for every index, internally, this maps entire ranges to the data. //! To this end, the APIs all work on ranges, not on individual integers. Ranges are split as -//! necessary (e.g. when [0,5) is first associated with X, and then [1,2) is mutated). +//! necessary (e.g., when [0,5) is first associated with X, and then [1,2) is mutated). //! Users must not depend on whether a range is coalesced or not, even though this is observable //! via the iteration APIs. @@ -14,7 +14,8 @@ use rustc::ty::layout::Size; #[derive(Clone, Debug)] struct Elem { - range: ops::Range, // the range covered by this element, never empty + /// The range covered by this element, never empty. + range: ops::Range, data: T, } #[derive(Clone, Debug)] @@ -23,7 +24,7 @@ pub struct RangeMap { } impl RangeMap { - /// Create a new RangeMap for the given size, and with the given initial value used for + /// Creates a new `RangeMap` for the given size, and with the given initial value used for /// the entire range. #[inline(always)] pub fn new(size: Size, init: T) -> RangeMap { @@ -38,9 +39,9 @@ impl RangeMap { map } - /// Find the index containing the given offset. + /// Finds the index containing the given offset. fn find_offset(&self, offset: u64) -> usize { - // We do a binary search + // We do a binary search. let mut left = 0usize; // inclusive let mut right = self.v.len(); // exclusive loop { @@ -62,22 +63,23 @@ impl RangeMap { } } - /// Provide read-only iteration over everything in the given range. This does - /// *not* split items if they overlap with the edges. Do not use this to mutate + /// Provides read-only iteration over everything in the given range. This does + /// *not* split items if they overlap with the edges. Do not use this to mutate /// through interior mutability. pub fn iter<'a>(&'a self, offset: Size, len: Size) -> impl Iterator + 'a { let offset = offset.bytes(); let len = len.bytes(); - // Compute a slice starting with the elements we care about + // Compute a slice starting with the elements we care about. let slice: &[Elem] = if len == 0 { - // We just need any empty iterator. We don't even want to + // We just need any empty iterator. We don't even want to // yield the element that surrounds this position. &[] } else { let first_idx = self.find_offset(offset); &self.v[first_idx..] }; - let end = offset + len; // the first offset that is not included any more + // The first offset that is not included any more. + let end = offset + len; slice.iter() .take_while(move |elem| elem.range.start < end) .map(|elem| &elem.data) @@ -87,25 +89,25 @@ impl RangeMap { self.v.iter_mut().map(|elem| &mut elem.data) } - // Split the element situated at the given `index`, such that the 2nd one starts at offset `split_offset`. - // Do nothing if the element already starts there. - // Return whether a split was necessary. + // Splits the element situated at the given `index`, such that the 2nd one starts at offset + // `split_offset`. Do nothing if the element already starts there. + // Returns whether a split was necessary. fn split_index(&mut self, index: usize, split_offset: u64) -> bool where T: Clone, { let elem = &mut self.v[index]; if split_offset == elem.range.start || split_offset == elem.range.end { - // Nothing to do + // Nothing to do. return false; } debug_assert!(elem.range.contains(&split_offset), - "The split_offset is not in the element to be split"); + "the `split_offset` is not in the element to be split"); - // Now we really have to split. Reduce length of first element. + // Now we really have to split. Reduce length of first element. let second_range = split_offset..elem.range.end; elem.range.end = split_offset; - // Copy the data, and insert 2nd element + // Copy the data, and insert second element. let second = Elem { range: second_range, data: elem.data.clone(), @@ -114,7 +116,7 @@ impl RangeMap { return true; } - /// Provide mutable iteration over everything in the given range. As a side-effect, + /// Provides mutable iteration over everything in the given range. As a side-effect, /// this will split entries in the map that are only partially hit by the given range, /// to make sure that when they are mutated, the effect is constrained to the given range. /// Moreover, this will opportunistically merge neighbouring equal blocks. @@ -130,7 +132,7 @@ impl RangeMap { let len = len.bytes(); // Compute a slice containing exactly the elements we care about let slice: &mut [Elem] = if len == 0 { - // We just need any empty iterator. We don't even want to + // We just need any empty iterator. We don't even want to // yield the element that surrounds this position, nor do // any splitting. &mut [] @@ -142,7 +144,7 @@ impl RangeMap { first_idx += 1; } let first_idx = first_idx; // no more mutation - // Find our end. Linear scan, but that's okay because the iteration + // Find our end. Linear scan, but that's ok because the iteration // is doing the same linear scan anyway -- no increase in complexity. // We combine this scan with a scan for duplicates that we can merge, to reduce // the number of elements. @@ -150,7 +152,7 @@ impl RangeMap { // amounts of time on the merging. let mut equal_since_idx = first_idx; // Once we see too many non-mergeable blocks, we stop. - // The initial value is chosen via... magic. Benchmarking and magic. + // The initial value is chosen via... magic. Benchmarking and magic. let mut successful_merge_count = 3usize; let mut end_idx = first_idx; // when the loop is done, this is the first excluded element. loop { @@ -162,7 +164,7 @@ impl RangeMap { // see if we want to merge everything in `equal_since..end` (exclusive at the end!) if successful_merge_count > 0 { if done || self.v[end_idx].data != self.v[equal_since_idx].data { - // Everything in `equal_since..end` was equal. Make them just one element covering + // Everything in `equal_since..end` was equal. Make them just one element covering // the entire range. let removed_elems = end_idx - equal_since_idx - 1; // number of elements that we would remove if removed_elems > 0 { @@ -173,10 +175,10 @@ impl RangeMap { self.v.splice(equal_since_idx+1..end_idx, std::iter::empty()); // Adjust `end_idx` because we made the list shorter. end_idx -= removed_elems; - // adjust the count for the cutoff + // Adjust the count for the cutoff. successful_merge_count += removed_elems; } else { - // adjust the count for the cutoff + // Adjust the count for the cutoff. successful_merge_count -= 1; } // Go on scanning for the next block starting here. @@ -188,8 +190,9 @@ impl RangeMap { break; } } - let end_idx = end_idx-1; // Move to last included instead of first excluded index. - // We need to split the end as well. Even if this performs a + // Move to last included instead of first excluded index. + let end_idx = end_idx-1; + // We need to split the end as well. Even if this performs a // split, we don't have to adjust our index as we only care about // the first part of the split. self.split_index(end_idx, offset+len); @@ -220,15 +223,15 @@ mod tests { #[test] fn basic_insert() { let mut map = RangeMap::::new(Size::from_bytes(20), -1); - // Insert + // Insert. for x in map.iter_mut(Size::from_bytes(10), Size::from_bytes(1)) { *x = 42; } - // Check + // Check. assert_eq!(to_vec(&map, 10, 1), vec![42]); assert_eq!(map.v.len(), 3); - // Insert with size 0 + // Insert with size 0. for x in map.iter_mut(Size::from_bytes(10), Size::from_bytes(0)) { *x = 19; } @@ -275,11 +278,11 @@ mod tests { to_vec(&map, 10, 10), vec![23, 42, 23, 23, 23, 19, 19, 19, 19, 19] ); - // Should be seeing two blocks with 19 + // Should be seeing two blocks with 19. assert_eq!(map.iter(Size::from_bytes(15), Size::from_bytes(2)) .map(|&t| t).collect::>(), vec![19, 19]); - // a NOP iter_mut should trigger merging + // A NOP `iter_mut` should trigger merging. for x in map.iter_mut(Size::from_bytes(15), Size::from_bytes(5)) { } assert_eq!(map.v.len(), 5); assert_eq!( diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index a52e115323c6f..c9ca1c84e0f70 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -15,16 +15,15 @@ use crate::{ pub type Timestamp = u64; pub type CallId = u64; -/// Information about which kind of borrow was used to create the reference this is tagged -/// with. +/// Information about which kind of borrow was used to create the reference this is tagged with. #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] pub enum Borrow { /// A unique (mutable) reference. Uniq(Timestamp), - /// An aliasing reference. This is also used by raw pointers, which do not track details + /// An aliasing reference. This is also used by raw pointers, which do not track details /// of how or when they were created, hence the timestamp is optional. - /// Shr(Some(_)) does NOT mean that the destination of this reference is frozen; - /// that depends on the type! Only those parts outside of an `UnsafeCell` are actually + /// `Shr(Some(_))` does *not* mean that the destination of this reference is frozen; + /// that depends on the type! Only those parts outside of an `UnsafeCell` are actually /// frozen. Alias(Option), } @@ -53,23 +52,25 @@ impl Default for Borrow { } } -/// An item in the per-location borrow stack +/// An item in the per-location borrow stack. #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] pub enum BorStackItem { /// Indicates the unique reference that may mutate. Uniq(Timestamp), - /// Indicates that the location has been mutably shared. Used for raw pointers as + /// Indicates that the location has been mutably shared. Used for raw pointers as /// well as for unfrozen shared references. Raw, - /// A barrier, tracking the function it belongs to by its index on the call stack + /// A barrier, tracking the function it belongs to by its index on the call stack. FnBarrier(CallId) } -/// Extra per-location state +/// Extra per-location state. #[derive(Clone, Debug, PartialEq, Eq)] pub struct Stack { - borrows: Vec, // used as a stack; never empty - frozen_since: Option, // virtual frozen "item" on top of the stack + /// Used as the stack; never empty. + borrows: Vec, + /// A virtual frozen "item" on top of the stack. + frozen_since: Option, } impl Stack { @@ -79,18 +80,18 @@ impl Stack { } } -/// What kind of reference is being used? +/// Indicates which kind of reference is being used. #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] pub enum RefKind { - /// &mut + /// `&mut`. Unique, - /// & without interior mutability + /// `&` without interior mutability. Frozen, - /// * (raw pointer) or & to `UnsafeCell` + /// `*` (raw pointer) or `&` to `UnsafeCell`. Raw, } -/// What kind of access is being performed? +/// Indicates which kind of access is being performed. #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] pub enum AccessKind { Read, @@ -98,7 +99,7 @@ pub enum AccessKind { Dealloc, } -/// Extra global state in the memory, available to the memory access hooks +/// Extra global state in the memory, available to the memory access hooks. #[derive(Debug)] pub struct BarrierTracking { next_id: CallId, @@ -133,7 +134,7 @@ impl BarrierTracking { } } -/// Extra global machine state +/// Extra global machine state. #[derive(Clone, Debug)] pub struct State { clock: Timestamp @@ -153,7 +154,7 @@ impl State { } } -/// Extra per-allocation state +/// Extra per-allocation state. #[derive(Clone, Debug)] pub struct Stacks { // Even reading memory can have effects on the stack, so we need a `RefCell` here. @@ -164,18 +165,19 @@ pub struct Stacks { /// Core per-location operations: deref, access, create. /// We need to make at least the following things true: /// -/// U1: After creating a Uniq, it is at the top (+unfrozen). -/// U2: If the top is Uniq (+unfrozen), accesses must be through that Uniq or pop it. -/// U3: If an access (deref sufficient?) happens with a Uniq, it requires the Uniq to be in the stack. +/// U1: After creating a `Uniq`, it is at the top (and unfrozen). +/// U2: If the top is `Uniq` (and unfrozen), accesses must be through that `Uniq` or pop it. +/// U3: If an access (deref sufficient?) happens with a `Uniq`, it requires the `Uniq` to be in the stack. /// -/// F1: After creating a &, the parts outside `UnsafeCell` are frozen. +/// F1: After creating a `&`, the parts outside `UnsafeCell` are frozen. /// F2: If a write access happens, it unfreezes. -/// F3: If an access (well, a deref) happens with an & outside `UnsafeCell`, it requires the location to still be frozen. +/// F3: If an access (well, a deref) happens with an `&` outside `UnsafeCell`, +/// it requires the location to still be frozen. impl<'tcx> Stack { - /// Deref `bor`: Check if the location is frozen and the tag in the stack. - /// This dos *not* constitute an access! "Deref" refers to the `*` operator + /// Deref `bor`: check if the location is frozen and the tag in the stack. + /// This dos *not* constitute an access! "Deref" refers to the `*` operator /// in Rust, and includs cases like `&*x` or `(*x).foo` where no or only part - /// of the memory actually gets accessed. Also we cannot know if we are + /// of the memory actually gets accessed. Also we cannot know if we are /// going to read or write. /// Returns the index of the item we matched, `None` if it was the frozen one. /// `kind` indicates which kind of reference is being dereferenced. @@ -186,44 +188,46 @@ impl<'tcx> Stack { ) -> Result, String> { // Exclude unique ref with frozen tag. if let (RefKind::Unique, Borrow::Alias(Some(_))) = (kind, bor) { - return Err(format!("Encountered mutable reference with frozen tag ({:?})", bor)); + return Err(format!("encountered mutable reference with frozen tag ({:?})", bor)); } - // Checks related to freezing + // Checks related to freezing. match bor { Borrow::Alias(Some(bor_t)) if kind == RefKind::Frozen => { // We need the location to be frozen. This ensures F3. let frozen = self.frozen_since.map_or(false, |itm_t| itm_t <= bor_t); return if frozen { Ok(None) } else { - Err(format!("Location is not frozen long enough")) + Err(format!("location is not frozen long enough")) } } Borrow::Alias(_) if self.frozen_since.is_some() => { - return Ok(None) // Shared deref to frozen location, looking good + // Shared deref to frozen location; looking good. + return Ok(None) } - _ => {} // Not sufficient, go on looking. + // Not sufficient; go on looking. + _ => {} } // If we got here, we have to look for our item in the stack. for (idx, &itm) in self.borrows.iter().enumerate().rev() { match (itm, bor) { (BorStackItem::Uniq(itm_t), Borrow::Uniq(bor_t)) if itm_t == bor_t => { - // Found matching unique item. This satisfies U3. + // Found matching unique item. This satisfies U3. return Ok(Some(idx)) } (BorStackItem::Raw, Borrow::Alias(_)) => { // Found matching aliasing/raw item. return Ok(Some(idx)) } - // Go on looking. We ignore barriers! When an `&mut` and an `&` alias, + // Go on looking. We ignore barriers! When an `&mut` and an `&` alias, // dereferencing the `&` is still possible (to reborrow), but doing // an access is not. _ => {} } } - // If we got here, we did not find our item. We have to error to satisfy U3. + // If we got here, we did not find our item. We have to error to satisfy U3. Err(format!("Borrow being dereferenced ({:?}) does not exist on the borrow stack", bor)) } - /// Perform an actual memory access using `bor`. We do not know any types here + /// Performs an actual memory access using `bor`. We do not know any types here /// or whether things should be frozen, but we *do* know if this is reading /// or writing. fn access( @@ -236,45 +240,44 @@ impl<'tcx> Stack { // Not possible on writes! if self.is_frozen() { if kind == AccessKind::Read { - // When we are frozen, we just accept all reads. No harm in this. + // When we are frozen, we just accept all reads. No harm in this. // The deref already checked that `Uniq` items are in the stack, and that // the location is frozen if it should be. return Ok(()); } - trace!("access: Unfreezing"); + trace!("access: unfreezing"); } - // Unfreeze on writes. This ensures F2. + // Unfreeze on writes. This ensures F2. self.frozen_since = None; // Pop the stack until we have something matching. while let Some(&itm) = self.borrows.last() { match (itm, bor) { (BorStackItem::FnBarrier(call), _) if barrier_tracking.is_active(call) => { return err!(MachineError(format!( - "Stopping looking for borrow being accessed ({:?}) because of barrier ({})", + "stopping looking for borrow being accessed ({:?}) because of barrier ({})", bor, call ))) } (BorStackItem::Uniq(itm_t), Borrow::Uniq(bor_t)) if itm_t == bor_t => { - // Found matching unique item. Continue after the match. + // Found matching unique item. Continue after the match. } (BorStackItem::Raw, _) if kind == AccessKind::Read => { // When reading, everything can use a raw item! // We do not want to do this when writing: Writing to an `&mut` // should reaffirm its exclusivity (i.e., make sure it is - // on top of the stack). - // Continue after the match. + // on top of the stack). Continue after the match. } (BorStackItem::Raw, Borrow::Alias(_)) => { - // Found matching raw item. Continue after the match. + // Found matching raw item. Continue after the match. } _ => { - // Pop this, go on. This ensures U2. + // Pop this, go on. This ensures U2. let itm = self.borrows.pop().unwrap(); trace!("access: Popping {:?}", itm); continue } } - // If we got here, we found a matching item. Congratulations! + // If we got here, we found a matching item. Congratulations! // However, we are not done yet: If this access is deallocating, we must make sure // there are no active barriers remaining on the stack. if kind == AccessKind::Dealloc { @@ -282,19 +285,19 @@ impl<'tcx> Stack { match itm { BorStackItem::FnBarrier(call) if barrier_tracking.is_active(call) => { return err!(MachineError(format!( - "Deallocating with active barrier ({})", call + "deallocating with active barrier ({})", call ))) } _ => {}, } } } - // NOW we are done. + // Now we are done. return Ok(()) } // If we got here, we did not find our item. err!(MachineError(format!( - "Borrow being accessed ({:?}) does not exist on the borrow stack", + "borrow being accessed ({:?}) does not exist on the borrow stack", bor ))) } @@ -304,7 +307,7 @@ impl<'tcx> Stack { /// is met: We cannot push `Uniq` onto frozen stacks. /// `kind` indicates which kind of reference is being created. fn create(&mut self, bor: Borrow, kind: RefKind) { - // When creating a frozen reference, freeze. This ensures F1. + // When creating a frozen reference, freeze. This ensures F1. // We also do *not* push anything else to the stack, making sure that no nother kind // of access (like writing through raw pointers) is permitted. if kind == RefKind::Frozen { @@ -312,10 +315,13 @@ impl<'tcx> Stack { Borrow::Alias(Some(t)) => t, _ => bug!("Creating illegal borrow {:?} for frozen ref", bor), }; - // It is possible that we already are frozen (e.g. if we just pushed a barrier, + // It is possible that we already are frozen (e.g., if we just pushed a barrier, // the redundancy check would not have kicked in). match self.frozen_since { - Some(loc_t) => assert!(loc_t <= bor_t, "Trying to freeze location for longer than it was already frozen"), + Some(loc_t) => assert!( + loc_t <= bor_t, + "trying to freeze location for longer than it was already frozen" + ), None => { trace!("create: Freezing"); self.frozen_since = Some(bor_t); @@ -323,7 +329,10 @@ impl<'tcx> Stack { } return; } - assert!(self.frozen_since.is_none(), "Trying to create non-frozen reference to frozen location"); + assert!( + self.frozen_since.is_none(), + "trying to create non-frozen reference to frozen location" + ); // Push new item to the stack. let itm = match bor { @@ -334,15 +343,15 @@ impl<'tcx> Stack { // This is just an optimization, no functional change: Avoid stacking // multiple `Shr` on top of each other. assert!(bor.is_aliasing()); - trace!("create: Sharing a shared location is a NOP"); + trace!("create: sharing a shared location is a NOP"); } else { // This ensures U1. - trace!("create: Pushing {:?}", itm); + trace!("create: pushing {:?}", itm); self.borrows.push(itm); } } - /// Add a barrier + /// Adds a barrier. fn barrier(&mut self, call: CallId) { let itm = BorStackItem::FnBarrier(call); if *self.borrows.last().unwrap() == itm { @@ -350,9 +359,9 @@ impl<'tcx> Stack { // multiple identical barriers on top of each other. // This can happen when a function receives several shared references // that overlap. - trace!("barrier: Avoiding redundant extra barrier"); + trace!("barrier: avoiding redundant extra barrier"); } else { - trace!("barrier: Pushing barrier for call {}", call); + trace!("barrier: pushing barrier for call {}", call); self.borrows.push(itm); } } @@ -360,7 +369,7 @@ impl<'tcx> Stack { /// Higher-level per-location operations: deref, access, reborrow. impl<'tcx> Stacks { - /// Check that this stack is fine with being dereferenced + /// Checks that this stack is fine with being dereferenced. fn deref( &self, ptr: Pointer, @@ -406,14 +415,15 @@ impl<'tcx> Stacks { new_kind: RefKind, ) -> EvalResult<'tcx> { assert_eq!(new_bor.is_unique(), new_kind == RefKind::Unique); - trace!("reborrow for tag {:?} to {:?} as {:?}: {:?}, size {}", - ptr.tag, new_bor, new_kind, ptr, size.bytes()); + trace!( + "reborrow for tag {:?} to {:?} as {:?}: {:?}, size {}", + ptr.tag, new_bor, new_kind, ptr, size.bytes(), + ); if new_kind == RefKind::Raw { - // No barrier for raw, including `&UnsafeCell`. They can rightfully - // alias with `&mut`. - // FIXME: This means that the `dereferencable` attribute on non-frozen shared - // references is incorrect! They are dereferencable when the function is - // called, but might become non-dereferencable during the course of execution. + // No barrier for raw, including `&UnsafeCell`. They can rightfully alias with `&mut`. + // FIXME: This means that the `dereferencable` attribute on non-frozen shared references + // is incorrect! They are dereferencable when the function is called, but might become + // non-dereferencable during the course of execution. // Also see [1], [2]. // // [1]: Stacks { let ptr_idx = stack.deref(ptr.tag, new_kind).map_err(EvalErrorKind::MachineError)?; // If we can deref the new tag already, and if that tag lives higher on // the stack than the one we come from, just use that. - // IOW, we check if `new_bor` *already* is "derived from" `ptr.tag`. + // That is, we check if `new_bor` *already* is "derived from" `ptr.tag`. // This also checks frozenness, if required. let bor_redundant = barrier.is_none() && match (ptr_idx, stack.deref(new_bor, new_kind)) { @@ -436,11 +446,11 @@ impl<'tcx> Stacks { // above the old one in the stack, our job here is done. (_, Ok(None)) => true, (Some(ptr_idx), Ok(Some(new_idx))) if new_idx >= ptr_idx => true, - // Otherwise we need to create a new borrow. + // Otherwise, we need to create a new borrow. _ => false, }; if bor_redundant { - assert!(new_bor.is_aliasing(), "A unique reborrow can never be redundant"); + assert!(new_bor.is_aliasing(), "a unique reborrow can never be redundant"); trace!("reborrow is redundant"); continue; } @@ -460,7 +470,7 @@ impl<'tcx> Stacks { } } -/// Hooks and glue +/// Hooks and glue. impl AllocationExtra for Stacks { #[inline(always)] fn memory_allocated<'tcx>(size: Size, extra: &MemoryState) -> Self { @@ -529,10 +539,10 @@ trait EvalContextPrivExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, let this = self.eval_context_mut(); let ptr = place.ptr.to_ptr()?; let barrier = if fn_barrier { Some(this.frame().extra) } else { None }; - trace!("reborrow: Creating new reference for {:?} (pointee {}): {:?}", + trace!("reborrow: creating new reference for {:?} (pointee {}): {:?}", ptr, place.layout.ty, new_bor); - // Get the allocation. It might not be mutable, so we cannot use `get_mut`. + // Get the allocation. It might not be mutable, so we cannot use `get_mut`. let alloc = this.memory().get(ptr.alloc_id)?; alloc.check_bounds(this, ptr, size)?; // Update the stacks. @@ -550,7 +560,7 @@ trait EvalContextPrivExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, Ok(()) } - /// Retag an indidual pointer, returning the retagged version. + /// Retags an indidual pointer, returning the retagged version. /// `mutbl` can be `None` to make this a raw pointer. fn retag_reference( &mut self, @@ -587,10 +597,10 @@ trait EvalContextPrivExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, // We immediately share it, to allow read accesses let two_phase_time = this.machine.stacked_borrows.increment_clock(); let two_phase_bor = Borrow::Alias(Some(two_phase_time)); - this.reborrow(new_place, size, /*fn_barrier*/false, two_phase_bor)?; + this.reborrow(new_place, size, false /* fn_barrier */, two_phase_bor)?; } - // Return new ptr. + // Return new pointer. Ok(new_place.to_ref()) } } @@ -607,29 +617,32 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, MemoryKind::Stack => { // New unique borrow. This `Uniq` is not accessible by the program, // so it will only ever be used when using the local directly (i.e., - // not through a pointer). IOW, whenever we directly use a local this will pop - // everything else off the stack, invalidating all previous pointers - // and, in particular, *all* raw pointers. This subsumes the explicit + // not through a pointer). That is, whenever we directly use a local, this will pop + // everything else off the stack, invalidating all previous pointers, + // and in particular, *all* raw pointers. This subsumes the explicit // `reset` which the blog post [1] says to perform when accessing a local. // - // [1] https://www.ralfj.de/blog/2018/08/07/stacked-borrows.html + // [1]: this.machine.stacked_borrows.increment_clock() } _ => { - // Nothing to do for everything else + // Nothing to do for everything else. return Borrow::default() } }; - // Make this the active borrow for this allocation - let alloc = this.memory_mut().get_mut(id).expect("This is a new allocation, it must still exist"); + // Make this the active borrow for this allocation. + let alloc = this + .memory_mut() + .get_mut(id) + .expect("this is a new allocation; it must still exist"); let size = Size::from_bytes(alloc.bytes.len() as u64); alloc.extra.first_item(BorStackItem::Uniq(time), size); Borrow::Uniq(time) } - /// Called for value-to-place conversion. `mutability` is `None` for raw pointers. + /// Called for value-to-place conversion. `mutability` is `None` for raw pointers. /// - /// Note that this does NOT mean that all this memory will actually get accessed/referenced! + /// Note that this does *not* mean that all this memory will actually get accessed/referenced! /// We could be in the middle of `&(*var).1`. fn ptr_dereference( &self, @@ -638,9 +651,15 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, mutability: Option, ) -> EvalResult<'tcx> { let this = self.eval_context_ref(); - trace!("ptr_dereference: Accessing {} reference for {:?} (pointee {})", - if let Some(mutability) = mutability { format!("{:?}", mutability) } else { format!("raw") }, - place.ptr, place.layout.ty); + trace!( + "ptr_dereference: Accessing {} reference for {:?} (pointee {})", + if let Some(mutability) = mutability { + format!("{:?}", mutability) + } else { + format!("raw") + }, + place.ptr, place.layout.ty + ); let ptr = place.ptr.to_ptr()?; if mutability.is_none() { // No further checks on raw derefs -- only the access itself will be checked. @@ -653,18 +672,18 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, // If we got here, we do some checking, *but* we leave the tag unchanged. if let Borrow::Alias(Some(_)) = ptr.tag { assert_eq!(mutability, Some(MutImmutable)); - // We need a frozen-sensitive check + // We need a frozen-sensitive check. this.visit_freeze_sensitive(place, size, |cur_ptr, size, frozen| { let kind = if frozen { RefKind::Frozen } else { RefKind::Raw }; alloc.extra.deref(cur_ptr, size, kind) })?; } else { - // Just treat this as one big chunk + // Just treat this as one big chunk. let kind = if mutability == Some(MutMutable) { RefKind::Unique } else { RefKind::Raw }; alloc.extra.deref(ptr, size, kind)?; } - // All is good + // All is good. Ok(()) } @@ -679,22 +698,22 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, // making it useless. fn qualify(ty: ty::Ty<'_>, kind: RetagKind) -> Option<(Option, bool)> { match ty.sty { - // References are simple + // References are simple. ty::Ref(_, _, mutbl) => Some((Some(mutbl), kind == RetagKind::FnEntry)), - // Raw pointers need to be enabled + // Raw pointers need to be enabled. ty::RawPtr(..) if kind == RetagKind::Raw => Some((None, false)), - // Boxes do not get a barrier: Barriers reflect that references outlive the call + // Boxes do not get a barrier: barriers reflect that references outlive the call // they were passed in to; that's just not the case for boxes. ty::Adt(..) if ty.is_box() => Some((Some(MutMutable), false)), _ => None, } } - // We need a visitor to visit all references. However, that requires + // We need a visitor to visit all references. However, that requires // a `MemPlace`, so we have a fast path for reference types that // avoids allocating. if let Some((mutbl, barrier)) = qualify(place.layout.ty, kind) { - // fast path + // Fast path. let val = this.read_immediate(this.place_to_op(place)?)?; let val = this.retag_reference(val, mutbl, barrier, kind == RetagKind::TwoPhase)?; this.write_immediate(val, place)?; @@ -705,7 +724,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, let mut visitor = RetagVisitor { ecx: this, kind }; visitor.visit_value(place)?; - // The actual visitor + // The actual visitor. struct RetagVisitor<'ecx, 'a, 'mir, 'tcx> { ecx: &'ecx mut MiriEvalContext<'a, 'mir, 'tcx>, kind: RetagKind, diff --git a/tests/compile-fail/stacked_borrows/deallocate_against_barrier.rs b/tests/compile-fail/stacked_borrows/deallocate_against_barrier.rs index eb988a5899593..b2f1c824f1b45 100644 --- a/tests/compile-fail/stacked_borrows/deallocate_against_barrier.rs +++ b/tests/compile-fail/stacked_borrows/deallocate_against_barrier.rs @@ -1,4 +1,4 @@ -// error-pattern: Deallocating with active barrier +// error-pattern: deallocating with active barrier fn inner(x: &mut i32, f: fn(&mut i32)) { // `f` may mutate, but it may not deallocate! diff --git a/tests/run-pass/const-vec-of-fns.rs b/tests/run-pass/const-vec-of-fns.rs index e100ad5f4692e..9b6c6fcc32efd 100644 --- a/tests/run-pass/const-vec-of-fns.rs +++ b/tests/run-pass/const-vec-of-fns.rs @@ -1,13 +1,3 @@ -// Copyright 2013 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - /*! * Try to double-check that static fns have the right size (with or * without dummy env ptr, as appropriate) by iterating a size-2 array. diff --git a/tests/run-pass/heap_allocator.rs b/tests/run-pass/heap_allocator.rs index e1aace8cecaf1..bfed725a497cc 100644 --- a/tests/run-pass/heap_allocator.rs +++ b/tests/run-pass/heap_allocator.rs @@ -1,4 +1,5 @@ -//ignore-windows: Inspects allocation base address on Windows +//ignore-windows: inspects allocation base address on Windows + #![feature(allocator_api)] use std::ptr::NonNull; @@ -6,8 +7,10 @@ use std::alloc::{Global, Alloc, Layout, System}; fn check_overalign_requests(mut allocator: T) { let size = 8; - let align = 16; // greater than size - let iterations = 1; // Miri is deterministic, no need to try many times + // Greater than `size`. + let align = 16; + // Miri is deterministic; no need to try many times. + let iterations = 1; unsafe { let pointers: Vec<_> = (0..iterations).map(|_| { allocator.alloc(Layout::from_size_align(size, align).unwrap()).unwrap() @@ -17,7 +20,7 @@ fn check_overalign_requests(mut allocator: T) { "Got a pointer less aligned than requested") } - // Clean up + // Clean up. for &ptr in &pointers { allocator.dealloc(ptr, Layout::from_size_align(size, align).unwrap()) } diff --git a/tests/run-pass/too-large-primval-write-problem.rs b/tests/run-pass/too-large-primval-write-problem.rs index 1bbe45277c43f..ebd6dbb61ee4e 100644 --- a/tests/run-pass/too-large-primval-write-problem.rs +++ b/tests/run-pass/too-large-primval-write-problem.rs @@ -1,4 +1,4 @@ -// PrimVals in Miri are represented with 8 bytes (u64) and at the time of writing, the `-x` +// `PrimVal`s in Miri are represented with 8 bytes (u64) and at the time of writing, the `-x` // will sign extend into the entire 8 bytes. Then, if you tried to write the `-x` into // something smaller than 8 bytes, like a 4 byte pointer, it would crash in byteorder crate // code that assumed only the low 4 bytes would be set. Actually, we were masking properly for From 205490b85c5024006e89c6443a1ba6f21bda4b89 Mon Sep 17 00:00:00 2001 From: Alexander Regueiro Date: Tue, 26 Feb 2019 18:37:05 +0000 Subject: [PATCH 0591/3747] Fixed nits raised in review. --- src/bin/miri.rs | 2 +- src/lib.rs | 5 ++--- src/range_map.rs | 7 ++++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 0f1501d5913b2..c1cad6edc0abb 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -178,7 +178,7 @@ fn find_sysroot() -> String { _ => { option_env!("RUST_SYSROOT") .expect( - "could not find sysroot. either set `MIRI_SYSROOT` at run-time, or at \ + "could not find sysroot. Either set `MIRI_SYSROOT` at run-time, or at \ build-time specify `RUST_SYSROOT` env var or use rustup or multirust", ) .to_owned() diff --git a/src/lib.rs b/src/lib.rs index df118ea09828f..31a02a7466e31 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -39,8 +39,7 @@ pub use crate::operator::EvalContextExt as OperatorEvalContextExt; pub use crate::intrinsic::EvalContextExt as IntrinsicEvalContextExt; pub use crate::tls::{EvalContextExt as TlsEvalContextExt, TlsData}; use crate::range_map::RangeMap; -// FIXME: rustc bug, issue . -#[allow(unused_imports)] +#[allow(unused_imports)] // FIXME: rustc bug, issue . pub use crate::helpers::{EvalContextExt as HelpersEvalContextExt}; use crate::mono_hash_map::MonoHashMap; pub use crate::stacked_borrows::{EvalContextExt as StackedBorEvalContextExt}; @@ -129,7 +128,7 @@ pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( let dest = ecx.eval_place(&mir::Place::Local(args.next().unwrap()))?; let argc = Scalar::from_uint(config.args.len() as u128, dest.layout.size); ecx.write_scalar(argc, dest)?; - // Store argc for macOS: `_NSGetArgc`. + // Store argc for macOS's `_NSGetArgc`. { let argc_place = ecx.allocate(dest.layout, MiriMemoryKind::Env.into()); ecx.write_scalar(argc, argc_place.into())?; diff --git a/src/range_map.rs b/src/range_map.rs index f94917e612a8f..16e7e27241798 100644 --- a/src/range_map.rs +++ b/src/range_map.rs @@ -14,8 +14,9 @@ use rustc::ty::layout::Size; #[derive(Clone, Debug)] struct Elem { - /// The range covered by this element, never empty. + /// The range covered by this element; never empty. range: ops::Range, + /// The data stored for this element. data: T, } #[derive(Clone, Debug)] @@ -49,11 +50,11 @@ impl RangeMap { let candidate = left.checked_add(right).unwrap() / 2; let elem = &self.v[candidate]; if offset < elem.range.start { - // we are too far right (offset is further left) + // We are too far right (offset is further left). debug_assert!(candidate < right); // we are making progress right = candidate; } else if offset >= elem.range.end { - // we are too far left (offset is further right) + // We are too far left (offset is further right). debug_assert!(candidate >= left); // we are making progress left = candidate+1; } else { From a9b03f94110a7ab9a8185acd06eed5aa56e0c56d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 27 Feb 2019 11:38:43 +0100 Subject: [PATCH 0592/3747] avoid [..] --- src/bin/cargo-miri.rs | 4 ++-- src/fn_call.rs | 8 ++++---- src/helpers.rs | 2 +- src/intrinsic.rs | 2 +- src/lib.rs | 8 ++++---- 5 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index c88912c83d786..0c90e8ade0d26 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -201,7 +201,7 @@ fn setup(ask_user: bool) { // Let's see if it is already installed. if std::env::var("XARGO_RUST_SRC").is_err() { let sysroot = Command::new("rustc").args(&["--print", "sysroot"]).output().unwrap().stdout; - let sysroot = std::str::from_utf8(&sysroot[..]).unwrap(); + let sysroot = std::str::from_utf8(&sysroot).unwrap(); let src = Path::new(sysroot.trim_end_matches('\n')).join("lib").join("rustlib").join("src"); if !src.exists() { if ask_user { @@ -336,7 +336,7 @@ fn in_cargo_miri() { // So after the first `--`, we add `-Zcargo-miri-marker`. let mut cmd = Command::new("cargo"); cmd.arg("rustc"); - match (subcommand, &kind[..]) { + match (subcommand, kind.as_str()) { (MiriCommand::Run, "bin") => { // FIXME: we just run all the binaries here. // We should instead support `cargo miri --bin foo`. diff --git a/src/fn_call.rs b/src/fn_call.rs index fa8c61e678beb..ce07b04c29c36 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -60,15 +60,15 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' let this = self.eval_context_mut(); let attrs = this.tcx.get_attrs(def_id); let link_name = match attr::first_attr_value_str_by_name(&attrs, "link_name") { - Some(name) => name.as_str(), - None => this.tcx.item_name(def_id).as_str(), + Some(name) => name.as_str().get(), + None => this.tcx.item_name(def_id).as_str().get(), }; // Strip linker suffixes (seen on 32-bit macOS). let link_name = link_name.trim_end_matches("$UNIX2003"); let tcx = &{this.tcx.tcx}; // First: functions that could diverge. - match &link_name[..] { + match link_name { "__rust_start_panic" | "panic_impl" => { return err!(MachineError("the evaluated program panicked".to_string())); } @@ -82,7 +82,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' // Next: functions that assume a ret and dest. let dest = dest.expect("we already checked for a dest"); let ret = ret.expect("dest is `Some` but ret is `None`"); - match &link_name[..] { + match link_name { "malloc" => { let size = this.read_scalar(args[0])?.to_usize(this)?; if size == 0 { diff --git a/src/helpers.rs b/src/helpers.rs index cdef224b3e990..2e4c955413ab7 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -175,7 +175,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' layout::FieldPlacement::Arbitrary { .. } => { // Gather the subplaces and sort them before visiting. let mut places = fields.collect::>>>()?; - places[..].sort_by_key(|place| place.ptr.get_ptr_offset(self.ecx())); + places.sort_by_key(|place| place.ptr.get_ptr_offset(self.ecx())); self.walk_aggregate(place, places.into_iter().map(Ok)) } layout::FieldPlacement::Union { .. } => { diff --git a/src/intrinsic.rs b/src/intrinsic.rs index 70880c4f7da82..5b0f0e99ad84e 100644 --- a/src/intrinsic.rs +++ b/src/intrinsic.rs @@ -27,7 +27,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, // (as opposed to through a place), we have to remember to erase any tag // that might still hang around! - let intrinsic_name = &this.tcx.item_name(instance.def_id()).as_str()[..]; + let intrinsic_name = this.tcx.item_name(instance.def_id()).as_str().get(); match intrinsic_name { "arith_offset" => { let offset = this.read_scalar(args[1])?.to_isize(this)?; diff --git a/src/lib.rs b/src/lib.rs index 31a02a7466e31..8fc3efd7c23b6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -461,17 +461,17 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { ) -> EvalResult<'tcx, Cow<'tcx, Allocation>> { let attrs = tcx.get_attrs(def_id); let link_name = match attr::first_attr_value_str_by_name(&attrs, "link_name") { - Some(name) => name.as_str(), - None => tcx.item_name(def_id).as_str(), + Some(name) => name.as_str().get(), + None => tcx.item_name(def_id).as_str().get(), }; - let alloc = match &link_name[..] { + let alloc = match link_name { "__cxa_thread_atexit_impl" => { // This should be all-zero, pointer-sized. let size = tcx.data_layout.pointer_size; let data = vec![0; size.bytes() as usize]; let extra = AllocationExtra::memory_allocated(size, memory_extra); - Allocation::from_bytes(&data[..], tcx.data_layout.pointer_align.abi, extra) + Allocation::from_bytes(&data, tcx.data_layout.pointer_align.abi, extra) } _ => return err!(Unimplemented( format!("can't access foreign static: {}", link_name), From 6265f6658ee56e5493339249f6b1f6a83bee865e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 1 Mar 2019 09:16:14 +0100 Subject: [PATCH 0593/3747] the stable part of compiletest_rs is enough --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 1a1a1fa2330ae..a68c04092f66a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -54,5 +54,5 @@ cargo_miri = ["cargo_metadata", "directories", "rustc_version"] rustc_tests = [] [dev-dependencies] -compiletest_rs = { version = "0.3.17", features = ["tmp"] } +compiletest_rs = { version = "0.3.17", features = ["tmp", "stable"] } colored = "1.6" From 0bb6ae8f62d3239a1c666c566693dfedc8652ad3 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Tue, 26 Feb 2019 14:58:13 -0300 Subject: [PATCH 0594/3747] Place::Local(x) is now Place::Base(PlaceBase::Local(x)) --- src/fn_call.rs | 2 +- src/lib.rs | 10 +++++----- src/tls.rs | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index ce07b04c29c36..b496a9b7d41d7 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -275,7 +275,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' .to_owned(), ), )?; - let arg_dest = this.eval_place(&mir::Place::Local(arg_local))?; + let arg_dest = this.eval_place(&mir::Place::Base(mir::PlaceBase::Local(arg_local)))?; this.write_scalar(data, arg_dest)?; assert!(args.next().is_none(), "__rust_maybe_catch_panic argument has more arguments than expected"); diff --git a/src/lib.rs b/src/lib.rs index 8fc3efd7c23b6..cf6a885c605c2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -121,11 +121,11 @@ pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( // First argument: pointer to `main()`. let main_ptr = ecx.memory_mut().create_fn_alloc(main_instance).with_default_tag(); - let dest = ecx.eval_place(&mir::Place::Local(args.next().unwrap()))?; + let dest = ecx.eval_place(&mir::Place::Base(mir::PlaceBase::Local(args.next().unwrap())))?; ecx.write_scalar(Scalar::Ptr(main_ptr), dest)?; // Second argument (argc): `1`. - let dest = ecx.eval_place(&mir::Place::Local(args.next().unwrap()))?; + let dest = ecx.eval_place(&mir::Place::Base(mir::PlaceBase::Local(args.next().unwrap())))?; let argc = Scalar::from_uint(config.args.len() as u128, dest.layout.size); ecx.write_scalar(argc, dest)?; // Store argc for macOS's `_NSGetArgc`. @@ -137,7 +137,7 @@ pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( // FIXME: extract main source file path. // Third argument (`argv`): created from `config.args`. - let dest = ecx.eval_place(&mir::Place::Local(args.next().unwrap()))?; + let dest = ecx.eval_place(&mir::Place::Base(mir::PlaceBase::Local(args.next().unwrap())))?; // For Windows, construct a command string with all the aguments. let mut cmd = String::new(); for arg in config.args.iter() { @@ -437,12 +437,12 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { // First argument: `size`. // (`0` is allowed here -- this is expected to be handled by the lang item). - let arg = ecx.eval_place(&mir::Place::Local(args.next().unwrap()))?; + let arg = ecx.eval_place(&mir::Place::Base(mir::PlaceBase::Local(args.next().unwrap())))?; let size = layout.size.bytes(); ecx.write_scalar(Scalar::from_uint(size, arg.layout.size), arg)?; // Second argument: `align`. - let arg = ecx.eval_place(&mir::Place::Local(args.next().unwrap()))?; + let arg = ecx.eval_place(&mir::Place::Base(mir::PlaceBase::Local(args.next().unwrap())))?; let align = layout.align.abi.bytes(); ecx.write_scalar(Scalar::from_uint(align, arg.layout.size), arg)?; diff --git a/src/tls.rs b/src/tls.rs index 5411e021619c4..796c2e5f9827a 100644 --- a/src/tls.rs +++ b/src/tls.rs @@ -151,7 +151,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, let arg_local = this.frame().mir.args_iter().next().ok_or_else( || EvalErrorKind::AbiViolation("TLS dtor does not take enough arguments.".to_owned()), )?; - let dest = this.eval_place(&mir::Place::Local(arg_local))?; + let dest = this.eval_place(&mir::Place::Base(mir::PlaceBase::Local(arg_local)))?; this.write_scalar(ptr, dest)?; // step until out of stackframes From 355135bb895c16e9011d6b83ad13663de47d2c64 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 2 Mar 2019 09:01:03 +0100 Subject: [PATCH 0595/3747] bump Rust version --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 091e10fde3c24..bf8995fe8a3ed 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -nightly-2019-02-24 +nightly-2019-03-02 From 2ef399979b5801efb64c68b57ccb34007ad9b012 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 8 Mar 2019 10:50:31 +0100 Subject: [PATCH 0596/3747] README --- README.md | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index c11cb46b31df4..aef74d6a5fe64 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,9 @@ for example: or an invalid enum discriminant) * WIP: Violations of the rules governing aliasing for reference types -Miri has already discovered some [real-world bugs](#bugs-found-by-miri). +Miri has already discovered some [real-world bugs](#bugs-found-by-miri). If you +found a bug with Miri, we'd appreciate if you tell us and we'll add it to the +list! [rust]: https://www.rust-lang.org/ [mir]: https://github.com/rust-lang/rfcs/blob/master/text/1211-mir.md @@ -50,6 +52,11 @@ Now you can run your project in Miri: 3. If you have a binary project, you can run it through Miri using `cargo +nightly miri run`. +The first time you run Miri, it will perform some extra setup and install some +dependencies. It will ask you for confirmation before installing anything. If +you run Miri on CI, run `cargo +nightly miri setup` to avoid getting interactive +questions. + You can pass arguments to Miri after the first `--`, and pass arguments to the interpreted program or test suite after the second `--`. For example, `cargo +nightly miri run -- -Zmiri-disable-validation` runs the program without From 8c74325441c3d571f0439a772f9287ac94975f54 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 10 Mar 2019 17:53:30 +0100 Subject: [PATCH 0597/3747] mention --exclude-should-panic --- README.md | 4 ++-- src/bin/cargo-miri.rs | 8 +++----- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index aef74d6a5fe64..184e37a894a9e 100644 --- a/README.md +++ b/README.md @@ -61,8 +61,8 @@ You can pass arguments to Miri after the first `--`, and pass arguments to the interpreted program or test suite after the second `--`. For example, `cargo +nightly miri run -- -Zmiri-disable-validation` runs the program without validation of basic type invariants and references. `cargo +nightly miri test --- -- filter` passes `filter` to the test suite the same way `cargo test filter` -would. +-- -- -Zunstable-options --exclude-should-panic` skips `#[should_panic]` tests, +which is a good idea because Miri does not support unwinding or catching panics. When running code via `cargo miri`, the `miri` config flag is set. You can use this to exclude test cases that will fail under Miri because they do things diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 0c90e8ade0d26..50570554f450c 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -329,11 +329,8 @@ fn in_cargo_miri() { "badly formatted cargo metadata: target::kind is an empty array", ); // Now we run `cargo rustc $FLAGS $ARGS`, giving the user the - // change to add additional flags. `FLAGS` is set to identify + // change to add additional arguments. `FLAGS` is set to identify // this target. The user gets to control what gets actually passed to Miri. - // However, we need to add a flag to what gets passed to rustc for the finaly - // binary, so that we know to interpret that with Miri. - // So after the first `--`, we add `-Zcargo-miri-marker`. let mut cmd = Command::new("cargo"); cmd.arg("rustc"); match (subcommand, kind.as_str()) { @@ -363,7 +360,8 @@ fn in_cargo_miri() { cmd.arg(arg); } // Add `--` (to end the `cargo` flags), and then the user flags. We add markers around the - // user flags to be able to identify them later. + // user flags to be able to identify them later. "cargo rustc" adds more stuff after this, + // so we have to mark both the beginning and the end. cmd .arg("--") .arg("cargo-miri-marker-begin") From 7d142ecf75cc347213502311253cd41f5d87dfaf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20K=C3=A5re=20Alsaker?= Date: Fri, 1 Feb 2019 23:26:42 +0100 Subject: [PATCH 0598/3747] Use the new rustc interface --- benches/helpers/miri_helper.rs | 56 +++++++------- src/bin/miri-rustc-tests.rs | 126 +++++++++++--------------------- src/bin/miri.rs | 130 ++++++++------------------------- 3 files changed, 99 insertions(+), 213 deletions(-) diff --git a/benches/helpers/miri_helper.rs b/benches/helpers/miri_helper.rs index 404fe7ae91501..3e3c3a53f754e 100644 --- a/benches/helpers/miri_helper.rs +++ b/benches/helpers/miri_helper.rs @@ -2,18 +2,39 @@ extern crate getopts; extern crate miri; extern crate rustc; extern crate rustc_driver; +extern crate rustc_interface; extern crate test; -use rustc_driver::{driver, Compilation}; +use self::miri::eval_main; use rustc::hir::def_id::LOCAL_CRATE; -use std::cell::RefCell; -use std::rc::Rc; +use rustc_interface::interface; +use crate::test::Bencher; + +struct MiriCompilerCalls<'a> { + bencher: &'a mut Bencher, +} -use miri::{MiriConfig, eval_main}; +impl rustc_driver::Callbacks for MiriCompilerCalls<'_> { + fn after_analysis(&mut self, compiler: &interface::Compiler<'_>) -> bool { + compiler.session().abort_if_errors(); -use crate::test::Bencher; + compiler.global_ctxt().unwrap().peek_mut().enter(|tcx| { + let (entry_def_id, _) = tcx.entry_fn(LOCAL_CRATE).expect( + "no main or start function found", + ); -pub struct MiriCompilerCalls<'a>(Rc>); + self.bencher.iter(|| { + let config = MiriConfig { validate: true, args: vec![] }; + eval_main(tcx, entry_def_id, config); + }); + }); + + compiler.session().abort_if_errors(); + + // Don't continue execution + false + } +} fn find_sysroot() -> String { // Taken from https://github.com/Manishearth/rust-clippy/pull/911. @@ -38,26 +59,5 @@ pub fn run(filename: &str, bencher: &mut Bencher) { "--sysroot".to_string(), find_sysroot(), ]; - let bencher = RefCell::new(bencher); - - let mut control = driver::CompileController::basic(); - - control.after_analysis.stop = Compilation::Stop; - control.after_analysis.callback = Box::new(move |state| { - state.session.abort_if_errors(); - - let tcx = state.tcx.unwrap(); - let (entry_def_id, _) = tcx.entry_fn(LOCAL_CRATE).expect( - "no main or start function found", - ); - - bencher.borrow_mut().iter(|| { - let config = MiriConfig { validate: true, args: vec![] }; - eval_main(tcx, entry_def_id, config); - }); - - state.session.abort_if_errors(); - }); - - rustc_driver::run_compiler(args, Box::new(control), None, None); + rustc_driver::run_compiler(args, &mut MiriCompilerCalls { bencher }, None, None); } diff --git a/src/bin/miri-rustc-tests.rs b/src/bin/miri-rustc-tests.rs index 3a70577cb7f22..cab8d845fc0d1 100644 --- a/src/bin/miri-rustc-tests.rs +++ b/src/bin/miri-rustc-tests.rs @@ -6,6 +6,7 @@ extern crate rustc_metadata; extern crate rustc_driver; extern crate rustc_errors; extern crate rustc_codegen_utils; +extern crate rustc_interface; extern crate syntax; use std::path::{PathBuf, Path}; @@ -15,12 +16,10 @@ use std::io; use rustc::session::Session; +use rustc_interface::interface; use rustc_metadata::cstore::CStore; -use rustc_driver::{Compilation, CompilerCalls, RustcDefaultCalls}; -use rustc_driver::driver::{CompileState, CompileController}; use rustc::session::config::{self, Input, ErrorOutputType}; use rustc::hir::{self, itemlikevisit}; -use rustc_codegen_utils::codegen_backend::CodegenBackend; use rustc::ty::TyCtxt; use syntax::ast; use rustc::hir::def_id::LOCAL_CRATE; @@ -28,93 +27,55 @@ use rustc::hir::def_id::LOCAL_CRATE; use miri::MiriConfig; struct MiriCompilerCalls { - default: Box, /// whether we are building for the host host_target: bool, } -impl<'a> CompilerCalls<'a> for MiriCompilerCalls { - fn early_callback( - &mut self, - matches: &getopts::Matches, - sopts: &config::Options, - cfg: &ast::CrateConfig, - descriptions: &rustc_errors::registry::Registry, - output: ErrorOutputType - ) -> Compilation { - self.default.early_callback(matches, sopts, cfg, descriptions, output) - } - fn no_input( - &mut self, - matches: &getopts::Matches, - sopts: &config::Options, - cfg: &ast::CrateConfig, - odir: &Option, - ofile: &Option, - descriptions: &rustc_errors::registry::Registry - ) -> Option<(Input, Option)> { - self.default.no_input(matches, sopts, cfg, odir, ofile, descriptions) - } - fn late_callback( - &mut self, - trans: &CodegenBackend, - matches: &getopts::Matches, - sess: &Session, - cstore: &CStore, - input: &Input, - odir: &Option, - ofile: &Option, - ) -> Compilation { - self.default.late_callback(trans, matches, sess, cstore, input, odir, ofile) - } - fn build_controller(self: Box, sess: &Session, matches: &getopts::Matches) -> CompileController<'a> { - let this = *self; - let mut control = this.default.build_controller(sess, matches); - control.after_hir_lowering.callback = Box::new(after_hir_lowering); - control.after_analysis.callback = Box::new(after_analysis); - if !this.host_target { - // only fully compile targets on the host - control.after_analysis.stop = Compilation::Stop; - } - control - } -} - -fn after_hir_lowering(state: &mut CompileState) { - let attr = (String::from("miri"), syntax::feature_gate::AttributeType::Whitelisted); - state.session.plugin_attributes.borrow_mut().push(attr); -} +impl rustc_driver::Callbacks for MiriCompilerCalls { + fn after_parsing(&mut self, compiler: &interface::Compiler<'_>) -> bool { + let attr = ( + String::from("miri"), + syntax::feature_gate::AttributeType::Whitelisted, + ); + compiler.session().plugin_attributes.borrow_mut().push(attr); -fn after_analysis<'a, 'tcx>(state: &mut CompileState<'a, 'tcx>) { - state.session.abort_if_errors(); - - let tcx = state.tcx.unwrap(); + // Continue execution + true + } - if std::env::args().any(|arg| arg == "--test") { - struct Visitor<'a, 'tcx: 'a>(TyCtxt<'a, 'tcx, 'tcx>, &'a CompileState<'a, 'tcx>); - impl<'a, 'tcx: 'a, 'hir> itemlikevisit::ItemLikeVisitor<'hir> for Visitor<'a, 'tcx> { - fn visit_item(&mut self, i: &'hir hir::Item) { - if let hir::ItemKind::Fn(.., body_id) = i.node { - if i.attrs.iter().any(|attr| attr.name() == "test") { - let config = MiriConfig { validate: true, args: vec![] }; - let did = self.0.hir().body_owner_def_id(body_id); - println!("running test: {}", self.0.def_path_debug_str(did)); - miri::eval_main(self.0, did, config); - self.1.session.abort_if_errors(); + fn after_analysis(&mut self, compiler: &interface::Compiler<'_>) -> bool { + compiler.session().abort_if_errors(); + compiler.global_ctxt().unwrap().peek_mut().enter(|tcx| { + if std::env::args().any(|arg| arg == "--test") { + struct Visitor<'a, 'tcx: 'a>(TyCtxt<'a, 'tcx, 'tcx>); + impl<'a, 'tcx: 'a, 'hir> itemlikevisit::ItemLikeVisitor<'hir> for Visitor<'a, 'tcx> { + fn visit_item(&mut self, i: &'hir hir::Item) { + if let hir::ItemKind::Fn(.., body_id) = i.node { + if i.attrs.iter().any(|attr| attr.name() == "test") { + let config = MiriConfig { validate: true, args: vec![] }; + let did = self.0.hir().body_owner_def_id(body_id); + println!("running test: {}", self.0.def_path_debug_str(did)); + miri::eval_main(self.0, did, config); + self.0.sess.abort_if_errors(); + } + } } + fn visit_trait_item(&mut self, _trait_item: &'hir hir::TraitItem) {} + fn visit_impl_item(&mut self, _impl_item: &'hir hir::ImplItem) {} } + tcx.hir().krate().visit_all_item_likes(&mut Visitor(tcx)); + } else if let Some((entry_def_id, _)) = tcx.entry_fn(LOCAL_CRATE) { + let config = MiriConfig { validate: true, args: vec![] }; + miri::eval_main(tcx, entry_def_id, config); + + compiler.session().abort_if_errors(); + } else { + println!("no main function found, assuming auxiliary build"); } - fn visit_trait_item(&mut self, _trait_item: &'hir hir::TraitItem) {} - fn visit_impl_item(&mut self, _impl_item: &'hir hir::ImplItem) {} - } - state.hir_crate.unwrap().visit_all_item_likes(&mut Visitor(tcx, state)); - } else if let Some((entry_def_id, _)) = tcx.entry_fn(LOCAL_CRATE) { - let config = MiriConfig { validate: true, args: vec![] }; - miri::eval_main(tcx, entry_def_id, config); + }); - state.session.abort_if_errors(); - } else { - println!("no main function found, assuming auxiliary build"); + // Continue execution on host target + self.host_target } } @@ -185,10 +146,7 @@ fn main() { let buf = BufWriter::default(); let output = buf.clone(); let result = std::panic::catch_unwind(|| { - rustc_driver::run_compiler(&args, Box::new(MiriCompilerCalls { - default: Box::new(RustcDefaultCalls), - host_target, - }), None, Some(Box::new(buf))); + rustc_driver::run_compiler(&args, &mut MiriCompilerCalls { host_target }, None, Some(Box::new(buf))); }); match result { diff --git a/src/bin/miri.rs b/src/bin/miri.rs index c1cad6edc0abb..27e52d5f1a069 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -11,115 +11,46 @@ extern crate rustc_metadata; extern crate rustc_driver; extern crate rustc_errors; extern crate rustc_codegen_utils; +extern crate rustc_interface; extern crate syntax; -use std::path::PathBuf; use std::str::FromStr; use std::env; -use miri::MiriConfig; -use rustc::session::Session; -use rustc_metadata::cstore::CStore; -use rustc_driver::{Compilation, CompilerCalls, RustcDefaultCalls}; -use rustc_driver::driver::{CompileState, CompileController}; -use rustc::session::config::{self, Input, ErrorOutputType}; -use rustc_codegen_utils::codegen_backend::CodegenBackend; +use rustc_interface::interface; use rustc::hir::def_id::LOCAL_CRATE; -use syntax::ast; struct MiriCompilerCalls { - default: Box, - miri_config: MiriConfig, + miri_config: miri::MiriConfig, } -impl<'a> CompilerCalls<'a> for MiriCompilerCalls { - fn early_callback( - &mut self, - matches: &getopts::Matches, - sopts: &config::Options, - cfg: &ast::CrateConfig, - descriptions: &rustc_errors::registry::Registry, - output: ErrorOutputType, - ) -> Compilation { - self.default.early_callback( - matches, - sopts, - cfg, - descriptions, - output, - ) - } - fn no_input( - &mut self, - matches: &getopts::Matches, - sopts: &config::Options, - cfg: &ast::CrateConfig, - odir: &Option, - ofile: &Option, - descriptions: &rustc_errors::registry::Registry, - ) -> Option<(Input, Option)> { - self.default.no_input( - matches, - sopts, - cfg, - odir, - ofile, - descriptions, - ) - } - fn late_callback( - &mut self, - codegen_backend: &CodegenBackend, - matches: &getopts::Matches, - sess: &Session, - cstore: &CStore, - input: &Input, - odir: &Option, - ofile: &Option, - ) -> Compilation { - // Called *before* `build_controller`. Add filename to `miri` arguments. - self.miri_config.args.insert(0, input.filestem().to_string()); - self.default.late_callback(codegen_backend, matches, sess, cstore, input, odir, ofile) - } - fn build_controller( - self: Box, - sess: &Session, - matches: &getopts::Matches, - ) -> CompileController<'a> { - let this = *self; - let mut control = this.default.build_controller(sess, matches); - control.after_hir_lowering.callback = Box::new(after_hir_lowering); - let miri_config = this.miri_config; - control.after_analysis.callback = - Box::new(move |state| after_analysis(state, miri_config.clone())); - control.after_analysis.stop = Compilation::Stop; - control - } -} +impl rustc_driver::Callbacks for MiriCompilerCalls { + fn after_parsing(&mut self, compiler: &interface::Compiler) -> bool { + let attr = ( + String::from("miri"), + syntax::feature_gate::AttributeType::Whitelisted, + ); + compiler.session().plugin_attributes.borrow_mut().push(attr); -fn after_hir_lowering(state: &mut CompileState) { - let attr = ( - String::from("miri"), - syntax::feature_gate::AttributeType::Whitelisted, - ); - state.session.plugin_attributes.borrow_mut().push(attr); -} - -fn after_analysis<'a, 'tcx>( - state: &mut CompileState<'a, 'tcx>, - miri_config: MiriConfig, -) { - init_late_loggers(); - state.session.abort_if_errors(); + // Continue execution + true + } - let tcx = state.tcx.unwrap(); + fn after_analysis(&mut self, compiler: &interface::Compiler) -> bool { + init_late_loggers(); + compiler.session().abort_if_errors(); + compiler.global_ctxt().unwrap().peek_mut().enter(|tcx| { + let (entry_def_id, _) = tcx.entry_fn(LOCAL_CRATE).expect("no main function found!"); - let (entry_def_id, _) = tcx.entry_fn(LOCAL_CRATE).expect("no main function found!"); + miri::eval_main(tcx, entry_def_id, self.miri_config.clone()); + }); - miri::eval_main(tcx, entry_def_id, miri_config); + compiler.session().abort_if_errors(); - state.session.abort_if_errors(); + // Don't continue execution + false + } } fn init_early_loggers() { @@ -228,12 +159,9 @@ fn main() { debug!("rustc arguments: {:?}", rustc_args); debug!("miri arguments: {:?}", miri_args); - let miri_config = MiriConfig { validate, args: miri_args }; - let result = rustc_driver::run(move || { - rustc_driver::run_compiler(&rustc_args, Box::new(MiriCompilerCalls { - default: Box::new(RustcDefaultCalls), - miri_config, - }), None, None) - }); - std::process::exit(result as i32); + let miri_config = miri::MiriConfig { validate, args: miri_args }; + let result = rustc_driver::report_ices_to_stderr_if_any(move || { + rustc_driver::run_compiler(&rustc_args, &mut MiriCompilerCalls { miri_config }, None, None) + }).and_then(|result| result); + std::process::exit(result.is_err() as i32); } From ecae3751b4016a76346d5495282111e7d36a013a Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Sun, 10 Mar 2019 12:03:51 +0100 Subject: [PATCH 0599/3747] Reintroduce prepending the input file name to the miri arguments --- src/bin/miri.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 27e52d5f1a069..4cc0d955d3c21 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -42,8 +42,12 @@ impl rustc_driver::Callbacks for MiriCompilerCalls { compiler.global_ctxt().unwrap().peek_mut().enter(|tcx| { let (entry_def_id, _) = tcx.entry_fn(LOCAL_CRATE).expect("no main function found!"); + let mut config = self.miri_config.clone(); - miri::eval_main(tcx, entry_def_id, self.miri_config.clone()); + // Add filename to `miri` arguments. + config.args.insert(0, compiler.input().filestem().to_string()); + + miri::eval_main(tcx, entry_def_id, config); }); compiler.session().abort_if_errors(); From 2c7357dc54f7f7b201074d35614bb7d9559a61e1 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 11 Mar 2019 10:09:08 +0100 Subject: [PATCH 0600/3747] bump Rust --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index bf8995fe8a3ed..7abca8ef46941 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -nightly-2019-03-02 +nightly-2019-03-11 From a672abddfa4fa544dc5f4e1fd5fe22244bd8b718 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Mon, 11 Mar 2019 10:25:21 +0100 Subject: [PATCH 0601/3747] Make the rustc test runner build again --- src/bin/miri-rustc-tests.rs | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/src/bin/miri-rustc-tests.rs b/src/bin/miri-rustc-tests.rs index cab8d845fc0d1..43bf466c70ee3 100644 --- a/src/bin/miri-rustc-tests.rs +++ b/src/bin/miri-rustc-tests.rs @@ -9,19 +9,15 @@ extern crate rustc_codegen_utils; extern crate rustc_interface; extern crate syntax; -use std::path::{PathBuf, Path}; +use std::path::Path; use std::io::Write; use std::sync::{Mutex, Arc}; use std::io; -use rustc::session::Session; use rustc_interface::interface; -use rustc_metadata::cstore::CStore; -use rustc::session::config::{self, Input, ErrorOutputType}; use rustc::hir::{self, itemlikevisit}; use rustc::ty::TyCtxt; -use syntax::ast; use rustc::hir::def_id::LOCAL_CRATE; use miri::MiriConfig; @@ -32,7 +28,7 @@ struct MiriCompilerCalls { } impl rustc_driver::Callbacks for MiriCompilerCalls { - fn after_parsing(&mut self, compiler: &interface::Compiler<'_>) -> bool { + fn after_parsing(&mut self, compiler: &interface::Compiler) -> bool { let attr = ( String::from("miri"), syntax::feature_gate::AttributeType::Whitelisted, @@ -43,7 +39,7 @@ impl rustc_driver::Callbacks for MiriCompilerCalls { true } - fn after_analysis(&mut self, compiler: &interface::Compiler<'_>) -> bool { + fn after_analysis(&mut self, compiler: &interface::Compiler) -> bool { compiler.session().abort_if_errors(); compiler.global_ctxt().unwrap().peek_mut().enter(|tcx| { if std::env::args().any(|arg| arg == "--test") { @@ -146,7 +142,7 @@ fn main() { let buf = BufWriter::default(); let output = buf.clone(); let result = std::panic::catch_unwind(|| { - rustc_driver::run_compiler(&args, &mut MiriCompilerCalls { host_target }, None, Some(Box::new(buf))); + let _ = rustc_driver::run_compiler(&args, &mut MiriCompilerCalls { host_target }, None, Some(Box::new(buf))); }); match result { From 56c7656568911bbe2e438d18348af67a6935573f Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Mon, 11 Mar 2019 10:28:03 +0100 Subject: [PATCH 0602/3747] Remove dead code and docs --- src/bin/cargo-miri.rs | 7 ------- tests/compile-fail/stack_limit.rs | 20 -------------------- 2 files changed, 27 deletions(-) delete mode 100644 tests/compile-fail/stack_limit.rs diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 50570554f450c..8984a0bc4f915 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -25,13 +25,6 @@ Common options: Other [options] are the same as `cargo rustc`. Everything after the first "--" is passed verbatim to Miri, which will pass everything after the second "--" verbatim to the interpreted program. - -The config flag `miri` is automatically defined for convenience. You can use -it to configure the resource limits - - #![cfg_attr(miri, memory_size = 42)] - -available resource limits are `memory_size`, `step_limit`, `stack_limit` "#; #[derive(Copy, Clone, Debug, PartialEq, Eq)] diff --git a/tests/compile-fail/stack_limit.rs b/tests/compile-fail/stack_limit.rs deleted file mode 100644 index 5645217fe1ff0..0000000000000 --- a/tests/compile-fail/stack_limit.rs +++ /dev/null @@ -1,20 +0,0 @@ -#![feature(custom_attribute)] -#![miri(stack_limit=16)] - -//error-pattern: reached the configured maximum number of stack frames - -fn bar() { - foo(); -} - -fn foo() { - cake(); -} - -fn cake() { - bar(); -} - -fn main() { - bar(); -} From 40ce1fcf267e8819c1e0699833beed087671e473 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Mon, 11 Mar 2019 11:28:56 +0100 Subject: [PATCH 0603/3747] Update bencher API --- benches/helpers/miri_helper.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/benches/helpers/miri_helper.rs b/benches/helpers/miri_helper.rs index 3e3c3a53f754e..d82f9f8b92892 100644 --- a/benches/helpers/miri_helper.rs +++ b/benches/helpers/miri_helper.rs @@ -15,7 +15,7 @@ struct MiriCompilerCalls<'a> { } impl rustc_driver::Callbacks for MiriCompilerCalls<'_> { - fn after_analysis(&mut self, compiler: &interface::Compiler<'_>) -> bool { + fn after_analysis(&mut self, compiler: &interface::Compiler) -> bool { compiler.session().abort_if_errors(); compiler.global_ctxt().unwrap().peek_mut().enter(|tcx| { @@ -24,7 +24,7 @@ impl rustc_driver::Callbacks for MiriCompilerCalls<'_> { ); self.bencher.iter(|| { - let config = MiriConfig { validate: true, args: vec![] }; + let config = miri::MiriConfig { validate: true, args: vec![] }; eval_main(tcx, entry_def_id, config); }); }); From 8568c20f4de4b52d3cc625c9f9c5052ee0e74d67 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Mon, 11 Mar 2019 12:41:11 +0100 Subject: [PATCH 0604/3747] Silence some warnings --- benches/helpers/miri_helper.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/benches/helpers/miri_helper.rs b/benches/helpers/miri_helper.rs index d82f9f8b92892..01fef16e4a970 100644 --- a/benches/helpers/miri_helper.rs +++ b/benches/helpers/miri_helper.rs @@ -59,5 +59,5 @@ pub fn run(filename: &str, bencher: &mut Bencher) { "--sysroot".to_string(), find_sysroot(), ]; - rustc_driver::run_compiler(args, &mut MiriCompilerCalls { bencher }, None, None); + rustc_driver::run_compiler(args, &mut MiriCompilerCalls { bencher }, None, None).unwrap() } From 687c5d13ea09aceaa79b4eb1b854791ad0f27b89 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 18 Mar 2019 13:30:57 +0100 Subject: [PATCH 0605/3747] bump Rust; remove stabilized feature --- rust-version | 2 +- src/lib.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/rust-version b/rust-version index 7abca8ef46941..0979a384dd325 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -nightly-2019-03-11 +nightly-2019-03-18 diff --git a/src/lib.rs b/src/lib.rs index cf6a885c605c2..ee739a5435acc 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,4 @@ -#![feature(rustc_private, range_contains)] +#![feature(rustc_private)] #![allow(clippy::cast_lossless)] From 8ee67994cc2ef98efb3f820a8f7012d24812cc06 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 18 Mar 2019 13:48:37 +0100 Subject: [PATCH 0606/3747] fix for rustc change --- src/bin/miri-rustc-tests.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bin/miri-rustc-tests.rs b/src/bin/miri-rustc-tests.rs index 43bf466c70ee3..f1f1e1a7c6bef 100644 --- a/src/bin/miri-rustc-tests.rs +++ b/src/bin/miri-rustc-tests.rs @@ -47,7 +47,7 @@ impl rustc_driver::Callbacks for MiriCompilerCalls { impl<'a, 'tcx: 'a, 'hir> itemlikevisit::ItemLikeVisitor<'hir> for Visitor<'a, 'tcx> { fn visit_item(&mut self, i: &'hir hir::Item) { if let hir::ItemKind::Fn(.., body_id) = i.node { - if i.attrs.iter().any(|attr| attr.name() == "test") { + if i.attrs.iter().any(|attr| attr.ident_str() == Some("test")) { let config = MiriConfig { validate: true, args: vec![] }; let did = self.0.hir().body_owner_def_id(body_id); println!("running test: {}", self.0.def_path_debug_str(did)); From 5d3825fc4800a04ded444ba442d5080abe7c4c38 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Mon, 18 Mar 2019 15:08:36 +0100 Subject: [PATCH 0607/3747] Update src/bin/miri-rustc-tests.rs Co-Authored-By: RalfJung --- src/bin/miri-rustc-tests.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bin/miri-rustc-tests.rs b/src/bin/miri-rustc-tests.rs index f1f1e1a7c6bef..e54be4644f25e 100644 --- a/src/bin/miri-rustc-tests.rs +++ b/src/bin/miri-rustc-tests.rs @@ -47,7 +47,7 @@ impl rustc_driver::Callbacks for MiriCompilerCalls { impl<'a, 'tcx: 'a, 'hir> itemlikevisit::ItemLikeVisitor<'hir> for Visitor<'a, 'tcx> { fn visit_item(&mut self, i: &'hir hir::Item) { if let hir::ItemKind::Fn(.., body_id) = i.node { - if i.attrs.iter().any(|attr| attr.ident_str() == Some("test")) { + if i.attrs.iter().any(|attr| attr.check_name("test")) { let config = MiriConfig { validate: true, args: vec![] }; let did = self.0.hir().body_owner_def_id(body_id); println!("running test: {}", self.0.def_path_debug_str(did)); From d96ece3806d0ac4c670dc7ed1cda07e1339a450b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 20 Mar 2019 10:09:49 +0100 Subject: [PATCH 0608/3747] move back to unstable compiletest; the stable one broke --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index a68c04092f66a..1a1a1fa2330ae 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -54,5 +54,5 @@ cargo_miri = ["cargo_metadata", "directories", "rustc_version"] rustc_tests = [] [dev-dependencies] -compiletest_rs = { version = "0.3.17", features = ["tmp", "stable"] } +compiletest_rs = { version = "0.3.17", features = ["tmp"] } colored = "1.6" From d0d7f221637951587d647b4d37f89955db9ce43b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 20 Mar 2019 10:20:29 +0100 Subject: [PATCH 0609/3747] bump Rust --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 0979a384dd325..04dab0fba1aff 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -nightly-2019-03-18 +nightly-2019-03-20 From 133f2ce4e511f555486d63f35c56d3e0b863126f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 21 Mar 2019 10:24:22 +0100 Subject: [PATCH 0610/3747] pin old compiletest, for now --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 1a1a1fa2330ae..bc0109a2ffbb8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -54,5 +54,5 @@ cargo_miri = ["cargo_metadata", "directories", "rustc_version"] rustc_tests = [] [dev-dependencies] -compiletest_rs = { version = "0.3.17", features = ["tmp"] } +compiletest_rs = { version = "=0.3.19", features = ["tmp", "stable"] } colored = "1.6" From 90dac3d4bd861c9b46aab646cc1abe90dcc3f4a1 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 25 Mar 2019 22:47:31 +0100 Subject: [PATCH 0611/3747] update README to suggest installing Miri as a component --- README.md | 36 +++++++++++++----------------------- 1 file changed, 13 insertions(+), 23 deletions(-) diff --git a/README.md b/README.md index 184e37a894a9e..09fa329dc4ecf 100644 --- a/README.md +++ b/README.md @@ -27,42 +27,31 @@ list! ## Running Miri on your own project (and its test suite) -Install Miri as a cargo subcommand: +Install Miri via `rustup`: ```sh -cargo +nightly install --force --git https://github.com/rust-lang/miri miri +rustup component add miri ``` -If this does not work, try using the nightly version given in -[this file](https://raw.githubusercontent.com/rust-lang/miri/master/rust-version). CI -should ensure that this nightly always works. - -You have to use a consistent Rust version for building miri and your project, so -remember to either always specify the nightly version manually (like in the -example above), overriding it in your project directory as well, or use `rustup -default nightly` (or `rustup default nightly-YYYY-MM-DD`) to globally make -`nightly` the default toolchain. - Now you can run your project in Miri: 1. Run `cargo clean` to eliminate any cached dependencies. Miri needs your dependencies to be compiled the right way, that would not happen if they have previously already been compiled. -2. To run all tests in your project through Miri, use `cargo +nightly miri test`. -3. If you have a binary project, you can run it through Miri using `cargo - +nightly miri run`. +2. To run all tests in your project through Miri, use `cargo miri test`. +3. If you have a binary project, you can run it through Miri using `cargo miri run`. The first time you run Miri, it will perform some extra setup and install some dependencies. It will ask you for confirmation before installing anything. If -you run Miri on CI, run `cargo +nightly miri setup` to avoid getting interactive +you run Miri on CI, run `cargo miri setup` to avoid getting interactive questions. You can pass arguments to Miri after the first `--`, and pass arguments to the interpreted program or test suite after the second `--`. For example, `cargo -+nightly miri run -- -Zmiri-disable-validation` runs the program without -validation of basic type invariants and references. `cargo +nightly miri test --- -- -Zunstable-options --exclude-should-panic` skips `#[should_panic]` tests, -which is a good idea because Miri does not support unwinding or catching panics. +miri run -- -Zmiri-disable-validation` runs the program without validation of +basic type invariants and references. `cargo miri test -- -- -Zunstable-options +--exclude-should-panic` skips `#[should_panic]` tests, which is a good idea +because Miri does not support unwinding or catching panics. When running code via `cargo miri`, the `miri` config flag is set. You can use this to exclude test cases that will fail under Miri because they do things @@ -110,10 +99,14 @@ convenient way is to install Miri using cargo, then you can easily run it on other projects: ```sh +rustup component remove miri # avoid having Miri installed twice cargo +nightly install --path "$DIR" --force # or the nightly in `rust-version` cargo +nightly miri setup ``` +(We are giving `+nightly` explicitly here all the time because it is important +that all of these commands get executed with the same toolchain.) + If you want to use a different libstd (not the one that comes with the nightly), you can do that by running @@ -124,9 +117,6 @@ XARGO_RUST_SRC=~/src/rust/rustc/src/ cargo +nightly miri setup Either way, you can now do `cargo +nightly miri run` to run Miri with your local changes on whatever project you are debugging. -(We are giving `+nightly` explicitly here all the time because it is important -that all of these commands get executed with the same toolchain.) - `cargo miri setup` should end in printing the directory where the libstd was built. For the next step to work, set that as your `MIRI_SYSROOT` environment variable: From 63b4a7661d620e804f5fc682c05aec3c499fe88a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 26 Mar 2019 10:07:22 +0100 Subject: [PATCH 0612/3747] explain Miri limitations --- README.md | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/README.md b/README.md index 09fa329dc4ecf..81a1220ae2958 100644 --- a/README.md +++ b/README.md @@ -19,6 +19,26 @@ Miri has already discovered some [real-world bugs](#bugs-found-by-miri). If you found a bug with Miri, we'd appreciate if you tell us and we'll add it to the list! +Be aware that Miri will not catch all possible errors in your program, and +cannot run all programs: + +* There are still plenty of open questions around the basic invariants for some + types and when these invariants even have to hold, so if you program runs fine + in Miri right now that is by no means a guarantee that it is UB-free when + these questions get answered. +* If the program relies on unspecified details of how data is laid out, it will + still run fine in Miri -- but might break (including causing UB) on different + compiler versions or different platforms. +* Miri is fully deterministic and does not actually pick a base address in + virtual memory for the program's allocations. If program behavior depends on + the base address of an allocation, Miri will stop execution (with a few + exceptions to make some common pointer comparisons work). +* Miri runs the program as a platform-independent interpreter, so the program + has no access to any platform-specific APIs or FFI. A few APIs have been + implemented (such as printing to stdout) but most have not: for example, Miri + currently does not support concurrency, or networking, or file system access, + or gathering entropy from the system. + [rust]: https://www.rust-lang.org/ [mir]: https://github.com/rust-lang/rfcs/blob/master/text/1211-mir.md [`unreachable_unchecked`]: https://doc.rust-lang.org/stable/std/hint/fn.unreachable_unchecked.html From 1100b4819c64d2554e2bff0ac3bd505ff44809bb Mon Sep 17 00:00:00 2001 From: 0xflotus <0xflotus@gmail.com> Date: Thu, 28 Mar 2019 11:47:51 +0100 Subject: [PATCH 0613/3747] fixed environment --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 81a1220ae2958..cf7bc9e32d0bc 100644 --- a/README.md +++ b/README.md @@ -212,7 +212,7 @@ With this, you should now have a working development setup! See ["Testing Miri"](#testing-miri) above for how to proceed. Running `cargo miri` in this setup is a bit more complicated, because the Miri -binary you just created does not actually run without some enviroment variables. +binary you just created does not actually run without some environment variables. But you can contort cargo into calling `cargo miri` the right way for you: ```sh From d9178b9300d884b54ea9892bfa3b6892148bee9d Mon Sep 17 00:00:00 2001 From: kenta7777 Date: Wed, 27 Mar 2019 17:58:11 +0900 Subject: [PATCH 0614/3747] renames EvalContext to InterpretCx --- src/fn_call.rs | 2 +- src/lib.rs | 28 ++++++++++++++-------------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index b496a9b7d41d7..3c6384e1a79ef 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -255,7 +255,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' trace!("__rust_maybe_catch_panic: {:?}", f_instance); // Now we make a function call. - // TODO: consider making this reusable? `EvalContext::step` does something similar + // TODO: consider making this reusable? `InterpretCx::step` does something similar // for the TLS destructors, and of course `eval_main`. let mir = this.load_mir(f_instance.def)?; let ret_place = MPlaceTy::dangling(this.layout_of(this.tcx.mk_unit())?, this).into(); diff --git a/src/lib.rs b/src/lib.rs index ee739a5435acc..be58c6a6a4642 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -67,8 +67,8 @@ pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( tcx: TyCtxt<'a, 'tcx, 'tcx>, main_id: DefId, config: MiriConfig, -) -> EvalResult<'tcx, EvalContext<'a, 'mir, 'tcx, Evaluator<'tcx>>> { - let mut ecx = EvalContext::new( +) -> EvalResult<'tcx, InterpretCx<'a, 'mir, 'tcx, Evaluator<'tcx>>> { + let mut ecx = InterpretCx::new( tcx.at(syntax::source_map::DUMMY_SP), ty::ParamEnv::reveal_all(), Evaluator::new(config.validate), @@ -345,7 +345,7 @@ impl<'tcx> Evaluator<'tcx> { // FIXME: rustc issue . #[allow(dead_code)] -type MiriEvalContext<'a, 'mir, 'tcx> = EvalContext<'a, 'mir, 'tcx, Evaluator<'tcx>>; +type MiriEvalContext<'a, 'mir, 'tcx> = InterpretCx<'a, 'mir, 'tcx, Evaluator<'tcx>>; // A little trait that's useful to be inherited by extension traits. pub trait MiriEvalContextExt<'a, 'mir, 'tcx> { @@ -376,14 +376,14 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { const STATIC_KIND: Option = Some(MiriMemoryKind::MutStatic); #[inline(always)] - fn enforce_validity(ecx: &EvalContext<'a, 'mir, 'tcx, Self>) -> bool { + fn enforce_validity(ecx: &InterpretCx<'a, 'mir, 'tcx, Self>) -> bool { ecx.machine.validate } /// Returns `Ok()` when the function was handled; fail otherwise. #[inline(always)] fn find_fn( - ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, + ecx: &mut InterpretCx<'a, 'mir, 'tcx, Self>, instance: ty::Instance<'tcx>, args: &[OpTy<'tcx, Borrow>], dest: Option>, @@ -394,7 +394,7 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { #[inline(always)] fn call_intrinsic( - ecx: &mut rustc_mir::interpret::EvalContext<'a, 'mir, 'tcx, Self>, + ecx: &mut rustc_mir::interpret::InterpretCx<'a, 'mir, 'tcx, Self>, instance: ty::Instance<'tcx>, args: &[OpTy<'tcx, Borrow>], dest: PlaceTy<'tcx, Borrow>, @@ -404,7 +404,7 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { #[inline(always)] fn ptr_op( - ecx: &rustc_mir::interpret::EvalContext<'a, 'mir, 'tcx, Self>, + ecx: &rustc_mir::interpret::InterpretCx<'a, 'mir, 'tcx, Self>, bin_op: mir::BinOp, left: ImmTy<'tcx, Borrow>, right: ImmTy<'tcx, Borrow>, @@ -413,7 +413,7 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { } fn box_alloc( - ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, + ecx: &mut InterpretCx<'a, 'mir, 'tcx, Self>, dest: PlaceTy<'tcx, Borrow>, ) -> EvalResult<'tcx> { trace!("box_alloc for {:?}", dest.layout.ty); @@ -481,7 +481,7 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { } #[inline(always)] - fn before_terminator(_ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>) -> EvalResult<'tcx> + fn before_terminator(_ecx: &mut InterpretCx<'a, 'mir, 'tcx, Self>) -> EvalResult<'tcx> { // We are not interested in detecting loops. Ok(()) @@ -511,7 +511,7 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { } fn tag_dereference( - ecx: &EvalContext<'a, 'mir, 'tcx, Self>, + ecx: &InterpretCx<'a, 'mir, 'tcx, Self>, place: MPlaceTy<'tcx, Borrow>, mutability: Option, ) -> EvalResult<'tcx, Scalar> { @@ -532,7 +532,7 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { #[inline(always)] fn tag_new_allocation( - ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, + ecx: &mut InterpretCx<'a, 'mir, 'tcx, Self>, ptr: Pointer, kind: MemoryKind, ) -> Pointer { @@ -547,7 +547,7 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { #[inline(always)] fn retag( - ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, + ecx: &mut InterpretCx<'a, 'mir, 'tcx, Self>, kind: mir::RetagKind, place: PlaceTy<'tcx, Borrow>, ) -> EvalResult<'tcx> { @@ -565,14 +565,14 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { #[inline(always)] fn stack_push( - ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, + ecx: &mut InterpretCx<'a, 'mir, 'tcx, Self>, ) -> EvalResult<'tcx, stacked_borrows::CallId> { Ok(ecx.memory().extra.borrow_mut().new_call()) } #[inline(always)] fn stack_pop( - ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>, + ecx: &mut InterpretCx<'a, 'mir, 'tcx, Self>, extra: stacked_borrows::CallId, ) -> EvalResult<'tcx> { Ok(ecx.memory().extra.borrow_mut().end_call(extra)) From 83b7f2edc90028fa8dafa696a45da6d0d44c5c70 Mon Sep 17 00:00:00 2001 From: 0xflotus <0xflotus@gmail.com> Date: Thu, 28 Mar 2019 11:47:51 +0100 Subject: [PATCH 0615/3747] fixed environment --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 81a1220ae2958..cf7bc9e32d0bc 100644 --- a/README.md +++ b/README.md @@ -212,7 +212,7 @@ With this, you should now have a working development setup! See ["Testing Miri"](#testing-miri) above for how to proceed. Running `cargo miri` in this setup is a bit more complicated, because the Miri -binary you just created does not actually run without some enviroment variables. +binary you just created does not actually run without some environment variables. But you can contort cargo into calling `cargo miri` the right way for you: ```sh From adbda8ca24f044506684bbe3d48f5c096f6b02e3 Mon Sep 17 00:00:00 2001 From: kenta7777 Date: Sat, 30 Mar 2019 11:01:44 +0900 Subject: [PATCH 0616/3747] adjust rust-version to the latest nightly --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 04dab0fba1aff..eadee7c5f5de4 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -nightly-2019-03-20 +nightly-2019-03-29 From d5cdba5ee6025374be0942cf103740603216604e Mon Sep 17 00:00:00 2001 From: Timo Date: Sat, 30 Mar 2019 17:53:15 -0400 Subject: [PATCH 0617/3747] Add alternative for how to install if rustup fails As is the case now: https://rust-lang-nursery.github.io/rust-toolstate/ --- README.md | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index cf7bc9e32d0bc..115f29f09abe5 100644 --- a/README.md +++ b/README.md @@ -88,9 +88,19 @@ fn does_not_work_on_miri() { ### Common Problems -When using the above instructions, you may encounter a number of confusing compiler +When using the above instructions, you may encounter a number of confusing errors. +#### "component 'miri' for target '\' is unavailable for download for channel 'nightly'" + +The latest nightly may have broken Miri. If [this is the case][rust-toolstate], instead try to install Miri the old way with + +```sh +cargo +nightly install --force --git https://github.com/rust-lang/miri miri +``` + +[rust-toolstate]: + #### "found possibly newer version of crate `std` which `` depends on" Your build directory may contain artifacts from an earlier build that have/have From 67e123502c50dd2c24c34ff6886233d6721cfb5a Mon Sep 17 00:00:00 2001 From: Timo Date: Sun, 31 Mar 2019 10:03:03 -0400 Subject: [PATCH 0618/3747] README: Suggest using a previous nightly, revert other approach --- README.md | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 115f29f09abe5..e64f4a6cb3b5a 100644 --- a/README.md +++ b/README.md @@ -53,6 +53,16 @@ Install Miri via `rustup`: rustup component add miri ``` +### error: component 'miri' is unavailable for download (nightly) + +The development of rustc's internals is quite fast paced. Downstream projects that rely on nightly internals, particularly clippy, can break fairly often because of this. + +When such breakages occur the nightly release will be missing Miri. This is a trade-off compared with the other option of just not publishing the night's release, but does avoid blocking the rust nightly releases for people that don't need clippy/Miri. + +To mitigate the issues we have: +* rustup will warn if the update is missing any components you currently have. This means you can no longer accidentally update to a no-Miri release. Once Miri is available again it'll update. +* However, if you need latest nightly Miri you can use to find and install a dated nightly release e.g. `rustup install nightly-2018-12-06`. + Now you can run your project in Miri: 1. Run `cargo clean` to eliminate any cached dependencies. Miri needs your @@ -88,19 +98,9 @@ fn does_not_work_on_miri() { ### Common Problems -When using the above instructions, you may encounter a number of confusing +When using the above instructions, you may encounter a number of confusing compiler errors. -#### "component 'miri' for target '\' is unavailable for download for channel 'nightly'" - -The latest nightly may have broken Miri. If [this is the case][rust-toolstate], instead try to install Miri the old way with - -```sh -cargo +nightly install --force --git https://github.com/rust-lang/miri miri -``` - -[rust-toolstate]: - #### "found possibly newer version of crate `std` which `` depends on" Your build directory may contain artifacts from an earlier build that have/have From d54f9dc75cf3e9405ff56240c685eb7cf994c26e Mon Sep 17 00:00:00 2001 From: Timo Date: Sun, 31 Mar 2019 11:05:14 -0400 Subject: [PATCH 0619/3747] README: Update to RalfJung's suggestion... ...verbatim. Thanks :) --- README.md | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/README.md b/README.md index e64f4a6cb3b5a..a366e433b0f39 100644 --- a/README.md +++ b/README.md @@ -53,15 +53,7 @@ Install Miri via `rustup`: rustup component add miri ``` -### error: component 'miri' is unavailable for download (nightly) - -The development of rustc's internals is quite fast paced. Downstream projects that rely on nightly internals, particularly clippy, can break fairly often because of this. - -When such breakages occur the nightly release will be missing Miri. This is a trade-off compared with the other option of just not publishing the night's release, but does avoid blocking the rust nightly releases for people that don't need clippy/Miri. - -To mitigate the issues we have: -* rustup will warn if the update is missing any components you currently have. This means you can no longer accidentally update to a no-Miri release. Once Miri is available again it'll update. -* However, if you need latest nightly Miri you can use to find and install a dated nightly release e.g. `rustup install nightly-2018-12-06`. +If `rustup` says the `miri` component is unavailable, that's because not all nightly releases come with all tools. Check out this website to determine a nightly version that comes with Miri and install that, e.g. using `rustup install nightly-2019-03-28`. Now you can run your project in Miri: From 7d6c8ad24b490c633b608849af504dcb3a71fa5e Mon Sep 17 00:00:00 2001 From: Timo Date: Sun, 31 Mar 2019 14:52:57 -0400 Subject: [PATCH 0620/3747] README: Fix missing link Thanks for your patience :man_facepalming: --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index a366e433b0f39..495d74dcc41ac 100644 --- a/README.md +++ b/README.md @@ -53,7 +53,7 @@ Install Miri via `rustup`: rustup component add miri ``` -If `rustup` says the `miri` component is unavailable, that's because not all nightly releases come with all tools. Check out this website to determine a nightly version that comes with Miri and install that, e.g. using `rustup install nightly-2019-03-28`. +If `rustup` says the `miri` component is unavailable, that's because not all nightly releases come with all tools. Check out [this website](https://rust-lang.github.io/rustup-components-history) to determine a nightly version that comes with Miri and install that, e.g. using `rustup install nightly-2019-03-28`. Now you can run your project in Miri: From 9a0eaf6ebd6165a071ce3cf6d30921e02a115660 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Wed, 3 Apr 2019 10:48:11 +0200 Subject: [PATCH 0621/3747] Update to rustc nightly --- rust-version | 2 +- src/fn_call.rs | 4 ++-- src/helpers.rs | 2 +- src/operator.rs | 2 +- src/stacked_borrows.rs | 6 +++--- src/tls.rs | 4 ++-- 6 files changed, 10 insertions(+), 10 deletions(-) diff --git a/rust-version b/rust-version index eadee7c5f5de4..b621471218021 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -nightly-2019-03-29 +nightly-2019-04-03 diff --git a/src/fn_call.rs b/src/fn_call.rs index 3c6384e1a79ef..038f5ed8a0475 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -270,7 +270,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' let mut args = this.frame().mir.args_iter(); let arg_local = args.next().ok_or_else(|| - EvalErrorKind::AbiViolation( + InterpError::AbiViolation( "Argument to __rust_maybe_catch_panic does not take enough arguments." .to_owned(), ), @@ -529,7 +529,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' // This is `libc::pthread_key_t`. let key_type = args[0].layout.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()))? + .ok_or_else(|| InterpError::AbiViolation("wrong signature used for `pthread_key_create`: first argument must be a raw pointer.".to_owned()))? .ty; let key_layout = this.layout_of(key_type)?; diff --git a/src/helpers.rs b/src/helpers.rs index 2e4c955413ab7..8a4cccc743e6f 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -39,7 +39,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' }) .ok_or_else(|| { let path = path.iter().map(|&s| s.to_owned()).collect(); - EvalErrorKind::PathNotFound(path).into() + InterpError::PathNotFound(path).into() }) } diff --git a/src/operator.rs b/src/operator.rs index 0cba240a7d0fe..a30b11aeb27de 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -325,7 +325,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' let pointee_size = self.layout_of(pointee_ty)?.size.bytes() as i64; let offset = offset .checked_mul(pointee_size) - .ok_or_else(|| EvalErrorKind::Overflow(mir::BinOp::Mul))?; + .ok_or_else(|| InterpError::Overflow(mir::BinOp::Mul))?; // Now let's see what kind of pointer this is. if let Scalar::Ptr(ptr) = ptr { // Both old and new pointer must be in-bounds of a *live* allocation. diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index c9ca1c84e0f70..bea6aaf9cf892 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -7,7 +7,7 @@ use rustc::hir::{Mutability, MutMutable, MutImmutable}; use rustc::mir::RetagKind; use crate::{ - EvalResult, EvalErrorKind, MiriEvalContext, HelpersEvalContextExt, Evaluator, MutValueVisitor, + EvalResult, InterpError, MiriEvalContext, HelpersEvalContextExt, Evaluator, MutValueVisitor, MemoryKind, MiriMemoryKind, RangeMap, AllocId, Allocation, AllocationExtra, Pointer, Immediate, ImmTy, PlaceTy, MPlaceTy, }; @@ -380,7 +380,7 @@ impl<'tcx> Stacks { ptr.tag, kind, ptr, size.bytes()); let stacks = self.stacks.borrow(); for stack in stacks.iter(ptr.offset, size) { - stack.deref(ptr.tag, kind).map_err(EvalErrorKind::MachineError)?; + stack.deref(ptr.tag, kind).map_err(InterpError::MachineError)?; } Ok(()) } @@ -435,7 +435,7 @@ impl<'tcx> Stacks { let mut stacks = self.stacks.borrow_mut(); for stack in stacks.iter_mut(ptr.offset, size) { // Access source `ptr`, create new ref. - let ptr_idx = stack.deref(ptr.tag, new_kind).map_err(EvalErrorKind::MachineError)?; + let ptr_idx = stack.deref(ptr.tag, new_kind).map_err(InterpError::MachineError)?; // If we can deref the new tag already, and if that tag lives higher on // the stack than the one we come from, just use that. // That is, we check if `new_bor` *already* is "derived from" `ptr.tag`. diff --git a/src/tls.rs b/src/tls.rs index 796c2e5f9827a..992e4fd056190 100644 --- a/src/tls.rs +++ b/src/tls.rs @@ -4,7 +4,7 @@ use rustc_target::abi::LayoutOf; use rustc::{ty, ty::layout::HasDataLayout, mir}; use crate::{ - EvalResult, EvalErrorKind, StackPopCleanup, + EvalResult, InterpError, StackPopCleanup, MPlaceTy, Scalar, Borrow, }; @@ -149,7 +149,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, StackPopCleanup::None { cleanup: true }, )?; let arg_local = this.frame().mir.args_iter().next().ok_or_else( - || EvalErrorKind::AbiViolation("TLS dtor does not take enough arguments.".to_owned()), + || InterpError::AbiViolation("TLS dtor does not take enough arguments.".to_owned()), )?; let dest = this.eval_place(&mir::Place::Base(mir::PlaceBase::Local(arg_local)))?; this.write_scalar(ptr, dest)?; From bebb5bfa38bdfe80970a105a758474bbb29bb95b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 4 Apr 2019 10:19:18 +0100 Subject: [PATCH 0622/3747] use rustup-toolchain-install-master for CI --- .travis.yml | 14 +++++++++++--- rust-version | 2 +- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index ee58f73c36439..29e680cbae523 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,6 +5,7 @@ cache: # over time). directories: - /home/travis/.cargo + - /home/travis/.rustup os: - linux @@ -17,18 +18,25 @@ before_script: # Compute the rust version we use. We do not use "language: rust" to have more control here. - | if [[ "$TRAVIS_EVENT_TYPE" == cron ]]; then - RUST_TOOLCHAIN=nightly + RUSTC_HASH=$(git ls-remote https://github.com/rust-lang/rust.git master | awk '{print $1}') else - RUST_TOOLCHAIN=$(cat rust-version) + RUSTC_HASH=$(cat rust-version) fi # install Rust -- curl https://build.travis-ci.org/files/rustup-init.sh -sSf | sh -s -- -y --default-toolchain "$RUST_TOOLCHAIN" +- curl https://build.travis-ci.org/files/rustup-init.sh -sSf | sh -s -- -y --default-toolchain stable - export PATH=$HOME/.cargo/bin:$PATH +- cargo install rustup-toolchain-install-master || echo "rustup-toolchain-install-master already installed" +- rustup-toolchain-install-master -f -n master $RUSTC_HASH +- rustup default master - rustc --version script: - ./travis.sh +after_script: +# Don't cache this, it's a waste +- rustup toolchain uninstall master + notifications: email: on_success: never diff --git a/rust-version b/rust-version index b621471218021..a2b3daad97ec8 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -nightly-2019-04-03 +f717b58dd70829f105960a071c7992b440720482 From 31bc4355aaa27627d96696c03faa61ec35c5b7b4 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 4 Apr 2019 10:21:32 +0100 Subject: [PATCH 0623/3747] adjust README --- README.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index cf7bc9e32d0bc..54d8411b2fe74 100644 --- a/README.md +++ b/README.md @@ -120,13 +120,18 @@ other projects: ```sh rustup component remove miri # avoid having Miri installed twice -cargo +nightly install --path "$DIR" --force # or the nightly in `rust-version` +cargo +nightly install --path "$DIR" --force cargo +nightly miri setup ``` (We are giving `+nightly` explicitly here all the time because it is important that all of these commands get executed with the same toolchain.) +In case this fails, your nightly might be incompatible with Miri master. The +`rust-version` file contains the commit hash of rustc that Miri is currently +tested against; you can use that to find a nightly that works or you might have +to wait for the next nightly to get released. + If you want to use a different libstd (not the one that comes with the nightly), you can do that by running From 081837eff0c6f8dde9c6d87b8b9ddab1d2ecfd60 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 4 Apr 2019 10:38:49 +0100 Subject: [PATCH 0624/3747] fix Travis and adjust AppVeyor --- .appveyor.yml | 30 ++++++++++++++++++++---------- .travis.yml | 14 ++++++++------ 2 files changed, 28 insertions(+), 16 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index a46214a3c45c6..e99b0cc33c9b3 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -3,9 +3,7 @@ environment: PROJECT_NAME: miri matrix: - TARGET: x86_64-pc-windows-msvc - MSYS2_BITS: 64 - - TARGET: i686-pc-windows-msvc - MSYS2_BITS: 32 + #- TARGET: i686-pc-windows-msvc # branches to build branches: @@ -13,18 +11,23 @@ branches: only: - master +cache: + - '%USERPROFILE%\.cargo' + - '%USERPROFILE%\.rustup' + install: - # Install Rust. - - set PATH=C:\Program Files\Git\mingw64\bin;C:\msys64\mingw%MSYS2_BITS%\bin;%PATH% - - set /p RUST_TOOLCHAIN= Date: Thu, 4 Apr 2019 16:49:16 +0100 Subject: [PATCH 0625/3747] fix AppVeyor --- .appveyor.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index e99b0cc33c9b3..e97380cb932fe 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -3,7 +3,7 @@ environment: PROJECT_NAME: miri matrix: - TARGET: x86_64-pc-windows-msvc - #- TARGET: i686-pc-windows-msvc + - TARGET: i686-pc-windows-msvc # branches to build branches: @@ -42,7 +42,7 @@ test_script: - cargo test --release --all-features # Test cargo integration - cd test-cargo-miri - - python3 run-test.py + - '"C:\msys64\mingw64\bin\python3.exe" run-test.py' after_test: # Don't cache "master" toolchain, it's a waste From 7213b91cd4870ad878eb486e176346e832b5ed0b Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Fri, 5 Apr 2019 10:00:44 +0100 Subject: [PATCH 0626/3747] Use edition flag for 2phase test The compiler now rejects one of the examples with #![feature(nll)] --- tests/run-pass/2phase.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/run-pass/2phase.rs b/tests/run-pass/2phase.rs index 5ca0ff5d8df86..9e50829fade83 100644 --- a/tests/run-pass/2phase.rs +++ b/tests/run-pass/2phase.rs @@ -1,4 +1,4 @@ -#![feature(nll)] +// edition:2018 trait S: Sized { fn tpb(&mut self, _s: Self) {} @@ -54,6 +54,8 @@ fn with_interior_mutability() { let mut x = Cell::new(1); let l = &x; + + #[allow(unknown_lints, mutable_borrow_reservation_conflict)] x .do_the_thing({ x.set(3); From 3d491884c5487487c002b5d6669a5992796ff328 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 6 Apr 2019 11:29:35 +0200 Subject: [PATCH 0627/3747] AppVeyor: ignore already existing rustup-toolchain-install-master (WTF windows batch makes no sense) --- .appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.appveyor.yml b/.appveyor.yml index e97380cb932fe..7db60514ada7a 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -21,7 +21,7 @@ install: - rustup-init.exe -y --default-host %TARGET% --default-toolchain stable - set PATH=%USERPROFILE%\.cargo\bin;%PATH% # Install "master" toolchain - - cargo install rustup-toolchain-install-master + - cargo install rustup-toolchain-install-master & exit 0 - set /p RUSTC_HASH= Date: Sat, 6 Apr 2019 16:17:33 +0100 Subject: [PATCH 0628/3747] Remove unnecessary test directive --- tests/run-pass/2phase.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/run-pass/2phase.rs b/tests/run-pass/2phase.rs index 9e50829fade83..57f3631143706 100644 --- a/tests/run-pass/2phase.rs +++ b/tests/run-pass/2phase.rs @@ -1,5 +1,3 @@ -// edition:2018 - trait S: Sized { fn tpb(&mut self, _s: Self) {} } From ddb04966422eaba33328416806f45370a0a95711 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 6 Apr 2019 22:11:59 +0200 Subject: [PATCH 0629/3747] temporarily ignore async fn test --- tests/run-pass/async-fn.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/run-pass/async-fn.rs b/tests/run-pass/async-fn.rs index 48f8fc1223c94..79fcb59011f69 100644 --- a/tests/run-pass/async-fn.rs +++ b/tests/run-pass/async-fn.rs @@ -1,3 +1,4 @@ +// ignore-test FIXME ignored to let https://github.com/rust-lang/rust/pull/59119 land #![feature( async_await, await_macro, From 72cd133d1babc088661d52525e4f3a8a4e5d2d2d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 7 Apr 2019 10:55:34 +0200 Subject: [PATCH 0630/3747] compiletest can just propagate MIRI_SYSROOT from the outside --- tests/compiletest.rs | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/tests/compiletest.rs b/tests/compiletest.rs index 38a9d31d6e891..0ee8ca130ae0b 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -87,22 +87,6 @@ fn miri_pass(path: &str, target: &str, opt: bool) { compiletest::run_tests(&config); } -/// Ensures that the `MIRI_SYSROOT` env var is set. -fn set_sysroot() { - if std::env::var("MIRI_SYSROOT").is_ok() { - // Nothing to do. - return; - } - let sysroot = std::process::Command::new("rustc") - .arg("--print") - .arg("sysroot") - .output() - .expect("rustc not found") - .stdout; - let sysroot = String::from_utf8(sysroot).expect("sysroot is not utf8"); - std::env::set_var("MIRI_SYSROOT", sysroot.trim()); -} - fn get_host() -> String { let rustc = rustc_test_suite().unwrap_or(PathBuf::from("rustc")); let rustc_version = std::process::Command::new(rustc) @@ -129,8 +113,6 @@ fn compile_fail_miri(opt: bool) { } fn test_runner(_tests: &[&()]) { - set_sysroot(); - run_pass_miri(false); run_pass_miri(true); From 336a59d2640377af3a51c1133c0394d99cbd5ef5 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 7 Apr 2019 10:57:25 +0200 Subject: [PATCH 0631/3747] rename MIRI_TARGET -> MIRI_COMPILETEST_TARGET to clarify that this affects compiletest only --- tests/compiletest.rs | 2 +- travis.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/compiletest.rs b/tests/compiletest.rs index 0ee8ca130ae0b..ff83eca1c9f0b 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -101,7 +101,7 @@ fn get_host() -> String { } fn get_target() -> String { - std::env::var("MIRI_TARGET").unwrap_or_else(|_| get_host()) + std::env::var("MIRI_COMPILETEST_TARGET").unwrap_or_else(|_| get_host()) } fn run_pass_miri(opt: bool) { diff --git a/travis.sh b/travis.sh index 8ec1d56ab7709..8951cdc89644f 100755 --- a/travis.sh +++ b/travis.sh @@ -22,7 +22,7 @@ echo echo "Test miri with full MIR, on the host and other architectures" MIRI_SYSROOT="$MIRI_SYSROOT_BASE"/HOST cargo test --release --all-features -MIRI_SYSROOT="$MIRI_SYSROOT_BASE" MIRI_TARGET="$FOREIGN_TARGET" cargo test --release --all-features +MIRI_SYSROOT="$MIRI_SYSROOT_BASE" MIRI_COMPILETEST_TARGET="$FOREIGN_TARGET" cargo test --release --all-features echo echo "Test cargo integration" From 3f552fea269850a16b3e5f9743f0ab783c668787 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 7 Apr 2019 20:05:57 +0200 Subject: [PATCH 0632/3747] test calling Box --- tests/run-pass/closures.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/run-pass/closures.rs b/tests/run-pass/closures.rs index 9b379051eb774..141e6cd6d08a2 100644 --- a/tests/run-pass/closures.rs +++ b/tests/run-pass/closures.rs @@ -40,9 +40,14 @@ fn fn_once_closure_with_multiple_args() -> i64 { } } +fn boxed(f: Box i32>) -> i32 { + f() +} + fn main() { assert_eq!(simple(), 12); assert_eq!(crazy_closure(), (84, 10, 10)); assert_eq!(closure_arg_adjustment_problem(), 3); assert_eq!(fn_once_closure_with_multiple_args(), 6); + assert_eq!(boxed(Box::new({let x = 13; move || x})), 13); } From 6e4264bf27882dfee5276e18834ceb9edb040c23 Mon Sep 17 00:00:00 2001 From: Tim Diekmann <21277928+TimDiekmann@users.noreply.github.com> Date: Sun, 7 Apr 2019 20:52:12 +0200 Subject: [PATCH 0633/3747] Add `calloc` --- src/fn_call.rs | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/fn_call.rs b/src/fn_call.rs index 038f5ed8a0475..911f76929d5a4 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -93,6 +93,28 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' this.write_scalar(Scalar::Ptr(ptr.with_default_tag()), dest)?; } } + "calloc" => { + let items = this.read_scalar(args[0])?.to_usize(this)?; + let count = this.read_scalar(args[1])?.to_usize(this)?; + let size = if let Some(size) = items.checked_add(count) { + size + } else { + return err!(MachineError(format!( + "calloc: overflow of items * size: {} * {}", + items, size, + ))); + }; + if size == 0 { + this.write_null(dest)?; + } else { + let align = this.tcx.data_layout.pointer_align.abi; + let ptr = this.memory_mut().allocate(Size::from_bytes(size), align, MiriMemoryKind::C.into()); + this.memory_mut() + .get_mut(ptr.alloc_id)? + .write_repeat(tcx, ptr, 0, Size::from_bytes(size))?; + this.write_scalar(Scalar::Ptr(ptr.with_default_tag()), dest)?; + } + } "posix_memalign" => { let ret = this.deref_operand(args[0])?; let align = this.read_scalar(args[1])?.to_usize(this)?; From d1d05c8b4127295717b6f893e22cf657b4dbf1db Mon Sep 17 00:00:00 2001 From: Tim Diekmann Date: Sun, 7 Apr 2019 21:09:21 +0200 Subject: [PATCH 0634/3747] Fix tagging order --- src/fn_call.rs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index 911f76929d5a4..062cc900e1760 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -100,19 +100,21 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' size } else { return err!(MachineError(format!( - "calloc: overflow of items * size: {} * {}", - items, size, + "calloc: overflow of items * count: {} * {}", + items, count, ))); }; if size == 0 { this.write_null(dest)?; } else { let align = this.tcx.data_layout.pointer_align.abi; - let ptr = this.memory_mut().allocate(Size::from_bytes(size), align, MiriMemoryKind::C.into()); + let ptr = this.memory_mut() + .allocate(Size::from_bytes(size), align, MiriMemoryKind::C.into()) + .with_default_tag(); this.memory_mut() .get_mut(ptr.alloc_id)? .write_repeat(tcx, ptr, 0, Size::from_bytes(size))?; - this.write_scalar(Scalar::Ptr(ptr.with_default_tag()), dest)?; + this.write_scalar(Scalar::Ptr(ptr), dest)?; } } "posix_memalign" => { From 3002bbd4ac9e4b64ed546550b54d3511395dd1ff Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Sun, 7 Apr 2019 14:33:28 -0700 Subject: [PATCH 0635/3747] Update compiletest --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index bc0109a2ffbb8..d580d4b8ec17e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -54,5 +54,5 @@ cargo_miri = ["cargo_metadata", "directories", "rustc_version"] rustc_tests = [] [dev-dependencies] -compiletest_rs = { version = "=0.3.19", features = ["tmp", "stable"] } +compiletest_rs = { version = "0.3.21", features = ["tmp", "stable"] } colored = "1.6" From a59e155206ca596722a67e967848fa2d3e516e8c Mon Sep 17 00:00:00 2001 From: Tim Diekmann Date: Mon, 8 Apr 2019 01:12:44 +0200 Subject: [PATCH 0636/3747] Tidy up calloc code --- src/fn_call.rs | 23 +++++++---------------- 1 file changed, 7 insertions(+), 16 deletions(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index 062cc900e1760..2db23bd48c541 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -95,25 +95,16 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' } "calloc" => { let items = this.read_scalar(args[0])?.to_usize(this)?; - let count = this.read_scalar(args[1])?.to_usize(this)?; - let size = if let Some(size) = items.checked_add(count) { - size - } else { - return err!(MachineError(format!( - "calloc: overflow of items * count: {} * {}", - items, count, - ))); - }; - if size == 0 { + let len = this.read_scalar(args[1])?.to_usize(this)?; + let bytes = items.checked_mul(len).ok_or_else(|| InterpError::Overflow(mir::BinOp::Mul))?; + + if bytes== 0 { this.write_null(dest)?; } else { + let size = Size::from_bytes(bytes); let align = this.tcx.data_layout.pointer_align.abi; - let ptr = this.memory_mut() - .allocate(Size::from_bytes(size), align, MiriMemoryKind::C.into()) - .with_default_tag(); - this.memory_mut() - .get_mut(ptr.alloc_id)? - .write_repeat(tcx, ptr, 0, Size::from_bytes(size))?; + let ptr = this.memory_mut().allocate(size, align, MiriMemoryKind::C.into()).with_default_tag(); + this.memory_mut().get_mut(ptr.alloc_id)?.write_repeat(tcx, ptr, 0, size)?; this.write_scalar(Scalar::Ptr(ptr), dest)?; } } From fa0755c9fd9f7c43fbd313db32935ff37e588ee2 Mon Sep 17 00:00:00 2001 From: Tim Diekmann Date: Mon, 8 Apr 2019 01:12:50 +0200 Subject: [PATCH 0637/3747] Add calloc test --- tests/run-pass/calloc.rs | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 tests/run-pass/calloc.rs diff --git a/tests/run-pass/calloc.rs b/tests/run-pass/calloc.rs new file mode 100644 index 0000000000000..8e8e2e5f10f4f --- /dev/null +++ b/tests/run-pass/calloc.rs @@ -0,0 +1,26 @@ +//ignore-windows: Uses POSIX APIs + +#![feature(rustc_private)] + +use core::slice; + +extern crate libc; + +fn main() { + unsafe { + let p1 = libc::calloc(0, 0); + assert!(p1.is_null()); + + let p2 = libc::calloc(20, 0); + assert!(p2.is_null()); + + let p3 = libc::calloc(0, 20); + assert!(p3.is_null()); + + let p4 = libc::calloc(4, 8) as *const u8; + assert!(!p4.is_null()); + + let slice = slice::from_raw_parts(p4, 4 * 8); + assert_eq!(&slice, &[0_u8; 4 * 8]); + } +} From 73239573c9290346dd31c50cd3565cb754d86c80 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Sun, 7 Apr 2019 18:17:43 -0400 Subject: [PATCH 0638/3747] Implement non-deterministc mode Part of #653 This allows us to properly implement getrandom(), which unlocks the default HashMap type (e.g. HashMap) with RandomState) This commit adds a new '-Zmiri-seed=' option. When present, this option takes a 64-bit hex value, which is used as the seed to an internal PRNG. This PRNG is used to implement the 'getrandom()' syscall. When '-Zmiri-seed' is not passed, 'getrandom()' will be disabled. --- Cargo.toml | 2 ++ src/bin/miri-rustc-tests.rs | 4 ++-- src/bin/miri.rs | 20 ++++++++++++++++++-- src/fn_call.rs | 31 ++++++++++++++++++++++++++++--- src/lib.rs | 16 ++++++++++++++-- tests/compile-fail/getrandom.rs | 10 ++++++++++ tests/run-pass/hashmap.rs | 16 +++++++++++++--- 7 files changed, 87 insertions(+), 12 deletions(-) create mode 100644 tests/compile-fail/getrandom.rs diff --git a/Cargo.toml b/Cargo.toml index d580d4b8ec17e..6c77315bea48b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -44,6 +44,8 @@ shell-escape = "0.1.4" # See the `src/tools/rustc-workspace-hack/README.md` file in `rust-lang/rust` # for more information. rustc-workspace-hack = "1.0.0" +hex = "0.3.2" +rand = "0.6.5" [build-dependencies] vergen = "3" diff --git a/src/bin/miri-rustc-tests.rs b/src/bin/miri-rustc-tests.rs index e54be4644f25e..ce2ad1a2715db 100644 --- a/src/bin/miri-rustc-tests.rs +++ b/src/bin/miri-rustc-tests.rs @@ -48,7 +48,7 @@ impl rustc_driver::Callbacks for MiriCompilerCalls { fn visit_item(&mut self, i: &'hir hir::Item) { if let hir::ItemKind::Fn(.., body_id) = i.node { if i.attrs.iter().any(|attr| attr.check_name("test")) { - let config = MiriConfig { validate: true, args: vec![] }; + let config = MiriConfig { validate: true, args: vec![], seed: None }; let did = self.0.hir().body_owner_def_id(body_id); println!("running test: {}", self.0.def_path_debug_str(did)); miri::eval_main(self.0, did, config); @@ -61,7 +61,7 @@ impl rustc_driver::Callbacks for MiriCompilerCalls { } tcx.hir().krate().visit_all_item_likes(&mut Visitor(tcx)); } else if let Some((entry_def_id, _)) = tcx.entry_fn(LOCAL_CRATE) { - let config = MiriConfig { validate: true, args: vec![] }; + let config = MiriConfig { validate: true, args: vec![], seed: None }; miri::eval_main(tcx, entry_def_id, config); compiler.session().abort_if_errors(); diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 4cc0d955d3c21..7f15d00e2c8ab 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -126,6 +126,7 @@ fn main() { // Parse our arguments and split them across `rustc` and `miri`. let mut validate = true; + let mut seed: Option = None; let mut rustc_args = vec![]; let mut miri_args = vec![]; let mut after_dashdash = false; @@ -146,7 +147,22 @@ fn main() { after_dashdash = true; } _ => { - rustc_args.push(arg); + let split: Vec = arg.split("-Zmiri-seed=").map(|s| s.to_owned()).collect(); + if split.len() == 2 { + if seed.is_some() { + panic!("Cannot specify -Zmiri-seed multiple times!"); + } + let seed_raw = hex::decode(&split[1]).unwrap(); + if seed_raw.len() > 8 { + panic!(format!("-Zmiri-seed must be at most 8 bytes, was {}", seed_raw.len())); + } + + let mut bytes = [0; 8]; + bytes[..seed_raw.len()].copy_from_slice(&hex::decode(&split[1]).unwrap()); + seed = Some(u64::from_be_bytes(bytes)); + } else { + rustc_args.push(arg); + } } } } @@ -163,7 +179,7 @@ fn main() { debug!("rustc arguments: {:?}", rustc_args); debug!("miri arguments: {:?}", miri_args); - let miri_config = miri::MiriConfig { validate, args: miri_args }; + let miri_config = miri::MiriConfig { validate, args: miri_args, seed }; let result = rustc_driver::report_ices_to_stderr_if_any(move || { rustc_driver::run_compiler(&rustc_args, &mut MiriCompilerCalls { miri_config }, None, None) }).and_then(|result| result); diff --git a/src/fn_call.rs b/src/fn_call.rs index 038f5ed8a0475..ba610e8b230c2 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -4,6 +4,8 @@ use rustc::hir::def_id::DefId; use rustc::mir; use syntax::attr; +use rand::RngCore; + use crate::*; impl<'a, 'mir, 'tcx> EvalContextExt<'a, 'mir, 'tcx> for crate::MiriEvalContext<'a, 'mir, 'tcx> {} @@ -216,9 +218,32 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' // is called if a `HashMap` is created the regular way. match this.read_scalar(args[0])?.to_usize(this)? { 318 | 511 => { - return err!(Unimplemented( - "miri does not support random number generators".to_owned(), - )) + match this.machine.rng.as_ref() { + Some(rng) => { + let ptr = this.read_scalar(args[1])?.to_ptr()?; + let len = this.read_scalar(args[2])?.to_usize(this)?; + + // The only supported flags are GRND_RANDOM and GRND_NONBLOCK, + // neither of which have any effect on our current PRNG + let _flags = this.read_scalar(args[3])?.to_i32()?; + + let mut data = vec![0; len as usize]; + rng.borrow_mut().fill_bytes(&mut data); + + this.memory_mut().get_mut(ptr.alloc_id)? + .write_bytes(tcx, ptr, &data)?; + + this.write_scalar(Scalar::from_uint(len, dest.layout.size), dest)?; + + }, + None => { + return err!(Unimplemented( + "miri does not support random number generators in deterministic mode! + Use '-Zmiri-seed=' to enable random number generation".to_owned(), + )) + } + } + } id => { return err!(Unimplemented( diff --git a/src/lib.rs b/src/lib.rs index be58c6a6a4642..9b4b69b6d7072 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -23,6 +23,10 @@ mod stacked_borrows; use std::collections::HashMap; use std::borrow::Cow; +use std::cell::RefCell; + +use rand::rngs::StdRng; +use rand::SeedableRng; use rustc::ty::{self, TyCtxt, query::TyCtxtAt}; use rustc::ty::layout::{LayoutOf, Size, Align}; @@ -60,6 +64,9 @@ pub fn miri_default_args() -> &'static [&'static str] { pub struct MiriConfig { pub validate: bool, pub args: Vec, + + // The seed to use when non-determinism is required (e.g. getrandom()) + pub seed: Option } // Used by priroda. @@ -71,7 +78,7 @@ pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( let mut ecx = InterpretCx::new( tcx.at(syntax::source_map::DUMMY_SP), ty::ParamEnv::reveal_all(), - Evaluator::new(config.validate), + Evaluator::new(config.validate, config.seed), ); let main_instance = ty::Instance::mono(ecx.tcx.tcx, main_id); @@ -326,10 +333,14 @@ pub struct Evaluator<'tcx> { /// Stacked Borrows state. pub(crate) stacked_borrows: stacked_borrows::State, + + /// The random number generator to use if Miri + /// is running in non-deterministic mode + pub(crate) rng: Option> } impl<'tcx> Evaluator<'tcx> { - fn new(validate: bool) -> Self { + fn new(validate: bool, seed: Option) -> Self { Evaluator { env_vars: HashMap::default(), argc: None, @@ -339,6 +350,7 @@ impl<'tcx> Evaluator<'tcx> { tls: TlsData::default(), validate, stacked_borrows: stacked_borrows::State::default(), + rng: seed.map(|s| RefCell::new(StdRng::seed_from_u64(s))) } } } diff --git a/tests/compile-fail/getrandom.rs b/tests/compile-fail/getrandom.rs new file mode 100644 index 0000000000000..85148a724ebc6 --- /dev/null +++ b/tests/compile-fail/getrandom.rs @@ -0,0 +1,10 @@ +#![feature(rustc_private)] +extern crate libc; + +fn main() { + let mut buf = [0u8; 5]; + unsafe { + libc::syscall(libc::SYS_getrandom, &mut buf as &mut [u8] as *mut [u8] as *mut u8 as *mut libc::c_void, 5, 0); + //~^ ERROR constant evaluation error: miri does not support random number generators in deterministic mode! + } +} diff --git a/tests/run-pass/hashmap.rs b/tests/run-pass/hashmap.rs index d89a5ab535f64..a663c9659524c 100644 --- a/tests/run-pass/hashmap.rs +++ b/tests/run-pass/hashmap.rs @@ -1,8 +1,9 @@ +// compile-flags: -Zmiri-seed=0000000000000000 + use std::collections::{self, HashMap}; -use std::hash::BuildHasherDefault; +use std::hash::{BuildHasherDefault, BuildHasher}; -fn main() { - let mut map : HashMap> = Default::default(); +fn test_map(mut map: HashMap) { map.insert(0, 0); assert_eq!(map.values().fold(0, |x, y| x+y), 0); @@ -22,4 +23,13 @@ fn main() { assert_eq!(map.values().fold(0, |x, y| x+y), num*(num-1)/2); // TODO: Test Entry API, Iterators, ... + +} + +fn main() { + let map : HashMap> = Default::default(); + let map_normal: HashMap = HashMap::new(); + + test_map(map); + test_map(map_normal); } From fdefac8599a385a87de02f06d5a77f726a524904 Mon Sep 17 00:00:00 2001 From: Tim Diekmann Date: Mon, 8 Apr 2019 01:26:52 +0200 Subject: [PATCH 0639/3747] Fix calloc test Forgot to free the memory. Miri found the bug :) --- tests/run-pass/calloc.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/run-pass/calloc.rs b/tests/run-pass/calloc.rs index 8e8e2e5f10f4f..4c520da85e876 100644 --- a/tests/run-pass/calloc.rs +++ b/tests/run-pass/calloc.rs @@ -17,10 +17,10 @@ fn main() { let p3 = libc::calloc(0, 20); assert!(p3.is_null()); - let p4 = libc::calloc(4, 8) as *const u8; + let p4 = libc::calloc(4, 8); assert!(!p4.is_null()); - - let slice = slice::from_raw_parts(p4, 4 * 8); + let slice = slice::from_raw_parts(p4 as *const u8, 4 * 8); assert_eq!(&slice, &[0_u8; 4 * 8]); + libc::free(p4); } } From 312f938e791178eccca51ee22126d1ef06f50f9b Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Sun, 7 Apr 2019 19:30:37 -0400 Subject: [PATCH 0640/3747] Fix benchmark --- benches/helpers/miri_helper.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/benches/helpers/miri_helper.rs b/benches/helpers/miri_helper.rs index 01fef16e4a970..44a94cd61a0b4 100644 --- a/benches/helpers/miri_helper.rs +++ b/benches/helpers/miri_helper.rs @@ -24,7 +24,7 @@ impl rustc_driver::Callbacks for MiriCompilerCalls<'_> { ); self.bencher.iter(|| { - let config = miri::MiriConfig { validate: true, args: vec![] }; + let config = miri::MiriConfig { validate: true, args: vec![], seed: None }; eval_main(tcx, entry_def_id, config); }); }); From dddeda7f7d14ef410bf938e3197587cc8d5ac7da Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Sun, 7 Apr 2019 19:57:14 -0400 Subject: [PATCH 0641/3747] Use getrandom() syscall number from libc --- Cargo.toml | 1 + src/fn_call.rs | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 6c77315bea48b..b0e278c1b54c0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -46,6 +46,7 @@ shell-escape = "0.1.4" rustc-workspace-hack = "1.0.0" hex = "0.3.2" rand = "0.6.5" +libc = "0.2.51" [build-dependencies] vergen = "3" diff --git a/src/fn_call.rs b/src/fn_call.rs index ba610e8b230c2..74352302f36e1 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -216,8 +216,8 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' // // `libc::syscall(NR_GETRANDOM, buf.as_mut_ptr(), buf.len(), GRND_NONBLOCK)` // is called if a `HashMap` is created the regular way. - match this.read_scalar(args[0])?.to_usize(this)? { - 318 | 511 => { + match this.read_scalar(args[0])?.to_usize(this)? as i64 { + libc::SYS_getrandom => { match this.machine.rng.as_ref() { Some(rng) => { let ptr = this.read_scalar(args[1])?.to_ptr()?; From 808b1496710b369ceeddc0ef833af12c663ef6e4 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Sun, 7 Apr 2019 20:08:15 -0400 Subject: [PATCH 0642/3747] Use raw syscall numbers --- Cargo.toml | 1 - src/fn_call.rs | 3 ++- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index b0e278c1b54c0..6c77315bea48b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -46,7 +46,6 @@ shell-escape = "0.1.4" rustc-workspace-hack = "1.0.0" hex = "0.3.2" rand = "0.6.5" -libc = "0.2.51" [build-dependencies] vergen = "3" diff --git a/src/fn_call.rs b/src/fn_call.rs index 74352302f36e1..52f252da5cfa8 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -217,7 +217,8 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' // `libc::syscall(NR_GETRANDOM, buf.as_mut_ptr(), buf.len(), GRND_NONBLOCK)` // is called if a `HashMap` is created the regular way. match this.read_scalar(args[0])?.to_usize(this)? as i64 { - libc::SYS_getrandom => { + // SYS_getrandom on x86_64 and x86 respectively + 318 | 355 => { match this.machine.rng.as_ref() { Some(rng) => { let ptr = this.read_scalar(args[1])?.to_ptr()?; From 32d01263a96d1dfca9b484aba74f97a887c4a24a Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Mon, 8 Apr 2019 10:44:02 +0200 Subject: [PATCH 0643/3747] Update src/fn_call.rs Co-Authored-By: TimDiekmann <21277928+TimDiekmann@users.noreply.github.com> --- src/fn_call.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index 2db23bd48c541..83eb37708e8e4 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -98,7 +98,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' let len = this.read_scalar(args[1])?.to_usize(this)?; let bytes = items.checked_mul(len).ok_or_else(|| InterpError::Overflow(mir::BinOp::Mul))?; - if bytes== 0 { + if bytes == 0 { this.write_null(dest)?; } else { let size = Size::from_bytes(bytes); From 06af617b92680b791875a2b0d88700ac9253b8f0 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 8 Apr 2019 13:40:11 +0200 Subject: [PATCH 0644/3747] fix dumping uninitialized locals --- src/lib.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index be58c6a6a4642..728d32f969d3f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -264,9 +264,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 Ok(local) = local.access() { - trace!(" local {}: {:?}", i, local); - } + trace!(" local {}: {:?}", i, local.value); } } } From 5530d295ad2c4900c3c8ab80abb5b5258b99446b Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Mon, 8 Apr 2019 21:36:35 -0400 Subject: [PATCH 0645/3747] Simplify cast using as_mut_ptr() --- tests/compile-fail/getrandom.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/compile-fail/getrandom.rs b/tests/compile-fail/getrandom.rs index 85148a724ebc6..58a39ea3156d0 100644 --- a/tests/compile-fail/getrandom.rs +++ b/tests/compile-fail/getrandom.rs @@ -4,7 +4,7 @@ extern crate libc; fn main() { let mut buf = [0u8; 5]; unsafe { - libc::syscall(libc::SYS_getrandom, &mut buf as &mut [u8] as *mut [u8] as *mut u8 as *mut libc::c_void, 5, 0); + libc::syscall(libc::SYS_getrandom, buf.as_mut_ptr() as *mut libc::c_void, 5, 0); //~^ ERROR constant evaluation error: miri does not support random number generators in deterministic mode! } } From 6b0440e26d3e51aef9841ac47914b729416b25c9 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Mon, 8 Apr 2019 21:40:52 -0400 Subject: [PATCH 0646/3747] Cleanup argument parsing --- src/bin/miri.rs | 31 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 7f15d00e2c8ab..6e68f803f8584 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -146,23 +146,22 @@ fn main() { "--" => { after_dashdash = true; } - _ => { - let split: Vec = arg.split("-Zmiri-seed=").map(|s| s.to_owned()).collect(); - if split.len() == 2 { - if seed.is_some() { - panic!("Cannot specify -Zmiri-seed multiple times!"); - } - let seed_raw = hex::decode(&split[1]).unwrap(); - if seed_raw.len() > 8 { - panic!(format!("-Zmiri-seed must be at most 8 bytes, was {}", seed_raw.len())); - } - - let mut bytes = [0; 8]; - bytes[..seed_raw.len()].copy_from_slice(&hex::decode(&split[1]).unwrap()); - seed = Some(u64::from_be_bytes(bytes)); - } else { - rustc_args.push(arg); + arg if arg.starts_with("-Zmiri-seed=") => { + if seed.is_some() { + panic!("Cannot specify -Zmiri-seed multiple times!"); + } + let seed_raw = hex::decode(arg.trim_start_matches("-Zmiri-seed=")).unwrap(); + if seed_raw.len() > 8 { + panic!(format!("-Zmiri-seed must be at most 8 bytes, was {}", seed_raw.len())); } + + let mut bytes = [0; 8]; + bytes[..seed_raw.len()].copy_from_slice(&seed_raw); + seed = Some(u64::from_be_bytes(bytes)); + + }, + _ => { + rustc_args.push(arg); } } } From b120e8bb88271bc7fbe68651f230ead35de098a1 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Mon, 8 Apr 2019 21:42:12 -0400 Subject: [PATCH 0647/3747] Only run test with default hasher --- tests/run-pass/hashmap.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/run-pass/hashmap.rs b/tests/run-pass/hashmap.rs index a663c9659524c..94add0078f7c3 100644 --- a/tests/run-pass/hashmap.rs +++ b/tests/run-pass/hashmap.rs @@ -27,9 +27,8 @@ fn test_map(mut map: HashMap) { } fn main() { - let map : HashMap> = Default::default(); + let _map : HashMap> = Default::default(); let map_normal: HashMap = HashMap::new(); - test_map(map); test_map(map_normal); } From 6d3e93c2815c61e3293c85189dce1424c842bfc5 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Mon, 8 Apr 2019 22:22:41 -0400 Subject: [PATCH 0648/3747] Refactor random number generation --- src/fn_call.rs | 61 ++++++++++++++++++++------------- tests/compile-fail/getrandom.rs | 2 +- 2 files changed, 39 insertions(+), 24 deletions(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index 52f252da5cfa8..0f1814a0c42c1 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -215,36 +215,22 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' // figure out some way to actually process some of them. // // `libc::syscall(NR_GETRANDOM, buf.as_mut_ptr(), buf.len(), GRND_NONBLOCK)` - // is called if a `HashMap` is created the regular way. + // is called if a `HashMap` is created the regular way (e.g. HashMap). match this.read_scalar(args[0])?.to_usize(this)? as i64 { // SYS_getrandom on x86_64 and x86 respectively 318 | 355 => { - match this.machine.rng.as_ref() { - Some(rng) => { - let ptr = this.read_scalar(args[1])?.to_ptr()?; - let len = this.read_scalar(args[2])?.to_usize(this)?; + let ptr = this.read_scalar(args[1])?.to_ptr()?; + let len = this.read_scalar(args[2])?.to_usize(this)?; - // The only supported flags are GRND_RANDOM and GRND_NONBLOCK, - // neither of which have any effect on our current PRNG - let _flags = this.read_scalar(args[3])?.to_i32()?; + // The only supported flags are GRND_RANDOM and GRND_NONBLOCK, + // neither of which have any effect on our current PRNG + let _flags = this.read_scalar(args[3])?.to_i32()?; - let mut data = vec![0; len as usize]; - rng.borrow_mut().fill_bytes(&mut data); - - this.memory_mut().get_mut(ptr.alloc_id)? + let data = gen_random(this, len as usize)?; + this.memory_mut().get_mut(ptr.alloc_id)? .write_bytes(tcx, ptr, &data)?; - this.write_scalar(Scalar::from_uint(len, dest.layout.size), dest)?; - - }, - None => { - return err!(Unimplemented( - "miri does not support random number generators in deterministic mode! - Use '-Zmiri-seed=' to enable random number generation".to_owned(), - )) - } - } - + this.write_scalar(Scalar::from_uint(len, dest.layout.size), dest)?; } id => { return err!(Unimplemented( @@ -768,6 +754,17 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' "GetCommandLineW" => { this.write_scalar(Scalar::Ptr(this.machine.cmd_line.unwrap()), dest)?; } + // The actual name of 'RtlGenRandom' + "SystemFunction036" => { + let ptr = this.read_scalar(args[1])?.to_ptr()?; + let len = this.read_scalar(args[2])?.to_usize(this)?; + + let data = gen_random(this, len as usize)?; + this.memory_mut().get_mut(ptr.alloc_id)? + .write_bytes(tcx, ptr, &data)?; + + this.write_scalar(Scalar::from_bool(true), dest)?; + } // We can't execute anything else. _ => { @@ -786,3 +783,21 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' self.eval_context_mut().write_scalar(Scalar::from_int(0, dest.layout.size), dest) } } + +fn gen_random<'a, 'mir, 'tcx>(this: &mut MiriEvalContext<'a, 'mir, 'tcx>, + len: usize) -> Result, EvalError<'tcx>> { + + match this.machine.rng.as_ref() { + Some(rng) => { + let mut data = vec![0; len]; + rng.borrow_mut().fill_bytes(&mut data); + Ok(data) + } + None => { + err!(Unimplemented( + "miri does not support random number generators in deterministic mode! + Use '-Zmiri-seed=' to enable random number generation".to_owned(), + )) + } + } +} diff --git a/tests/compile-fail/getrandom.rs b/tests/compile-fail/getrandom.rs index 58a39ea3156d0..efa7a86fee08c 100644 --- a/tests/compile-fail/getrandom.rs +++ b/tests/compile-fail/getrandom.rs @@ -4,7 +4,7 @@ extern crate libc; fn main() { let mut buf = [0u8; 5]; unsafe { - libc::syscall(libc::SYS_getrandom, buf.as_mut_ptr() as *mut libc::c_void, 5, 0); + libc::syscall(libc::SYS_getrandom, buf.as_mut_ptr() as *mut libc::c_void, 5 as libc::size_t, 0 as libc::c_uint); //~^ ERROR constant evaluation error: miri does not support random number generators in deterministic mode! } } From 858e82bc6f56114545f2be472210ebef84d2e4b2 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Mon, 8 Apr 2019 22:29:40 -0400 Subject: [PATCH 0649/3747] Disable normal HashMap test on OS X Implementing random number generation on OS X will require special-casing the 'openat' system call to special-case reading from /dev/urandom --- tests/run-pass/hashmap.rs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/tests/run-pass/hashmap.rs b/tests/run-pass/hashmap.rs index 94add0078f7c3..d0de8b448b099 100644 --- a/tests/run-pass/hashmap.rs +++ b/tests/run-pass/hashmap.rs @@ -28,7 +28,12 @@ fn test_map(mut map: HashMap) { fn main() { let _map : HashMap> = Default::default(); - let map_normal: HashMap = HashMap::new(); - test_map(map_normal); + // TODO: Implement random number generation on OS X + if cfg!(not(target_os = "darwin")) { + let map_normal: HashMap = HashMap::new(); + test_map(map_normal); + } else { + test_map(_map); + } } From 5f997645bccb5776d17deafb8101c7575b41c08f Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Mon, 8 Apr 2019 22:37:58 -0400 Subject: [PATCH 0650/3747] Interpret system call numbers relative to target architecture --- src/fn_call.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index 0f1814a0c42c1..94e1f11ccf793 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -216,9 +216,9 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' // // `libc::syscall(NR_GETRANDOM, buf.as_mut_ptr(), buf.len(), GRND_NONBLOCK)` // is called if a `HashMap` is created the regular way (e.g. HashMap). - match this.read_scalar(args[0])?.to_usize(this)? as i64 { + match (this.read_scalar(args[0])?.to_usize(this)? as i64, tcx.data_layout.pointer_size.bits()) { // SYS_getrandom on x86_64 and x86 respectively - 318 | 355 => { + (318, 64) | (355, 32) => { let ptr = this.read_scalar(args[1])?.to_ptr()?; let len = this.read_scalar(args[2])?.to_usize(this)?; @@ -232,7 +232,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' this.write_scalar(Scalar::from_uint(len, dest.layout.size), dest)?; } - id => { + (id, _size) => { return err!(Unimplemented( format!("miri does not support syscall ID {}", id), )) From 174874420b09082d4feef0fe25a6cdf14fca3309 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Mon, 8 Apr 2019 22:48:57 -0400 Subject: [PATCH 0651/3747] OS X is "macos", not "darwin" --- tests/run-pass/hashmap.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/run-pass/hashmap.rs b/tests/run-pass/hashmap.rs index d0de8b448b099..a95f7170aa1b1 100644 --- a/tests/run-pass/hashmap.rs +++ b/tests/run-pass/hashmap.rs @@ -30,7 +30,7 @@ fn main() { let _map : HashMap> = Default::default(); // TODO: Implement random number generation on OS X - if cfg!(not(target_os = "darwin")) { + if cfg!(not(target_os = "macos")) { let map_normal: HashMap = HashMap::new(); test_map(map_normal); } else { From 5e07ff6b1f1f5e8906a571a59855013ee49bdd30 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Mon, 8 Apr 2019 23:16:13 -0400 Subject: [PATCH 0652/3747] Only run 'getrandom' test on Linux --- tests/compile-fail/getrandom.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/compile-fail/getrandom.rs b/tests/compile-fail/getrandom.rs index efa7a86fee08c..dcd3869c1445d 100644 --- a/tests/compile-fail/getrandom.rs +++ b/tests/compile-fail/getrandom.rs @@ -1,3 +1,5 @@ +// only-linux + #![feature(rustc_private)] extern crate libc; From 6b4c5b81da314ff29adcf341ba80faff00fa1bb0 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Mon, 8 Apr 2019 23:18:10 -0400 Subject: [PATCH 0653/3747] Fix 'RtlGenRandom' argument slots --- src/fn_call.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index 94e1f11ccf793..8a586c7705b33 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -756,8 +756,8 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' } // The actual name of 'RtlGenRandom' "SystemFunction036" => { - let ptr = this.read_scalar(args[1])?.to_ptr()?; - let len = this.read_scalar(args[2])?.to_usize(this)?; + let ptr = this.read_scalar(args[0])?.to_ptr()?; + let len = this.read_scalar(args[1])?.to_usize(this)?; let data = gen_random(this, len as usize)?; this.memory_mut().get_mut(ptr.alloc_id)? From 92436805885c28cfee7cb52d2b2fe742e4c3cb4f Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Mon, 8 Apr 2019 23:52:33 -0400 Subject: [PATCH 0654/3747] Use 'ignore-' instead of 'only-' Apparently 'ignore-' doesn't work with compiletest_rs --- tests/compile-fail/getrandom.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/compile-fail/getrandom.rs b/tests/compile-fail/getrandom.rs index dcd3869c1445d..7f2087a320a43 100644 --- a/tests/compile-fail/getrandom.rs +++ b/tests/compile-fail/getrandom.rs @@ -1,4 +1,5 @@ -// only-linux +// ignore-macos +// ignore-windows #![feature(rustc_private)] extern crate libc; From 22044c878d2a29902d05a4d66604f797207570d7 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Tue, 9 Apr 2019 10:16:32 -0400 Subject: [PATCH 0655/3747] Improve deterministic mode error message --- src/fn_call.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index 8a586c7705b33..b97c237412818 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -795,8 +795,10 @@ fn gen_random<'a, 'mir, 'tcx>(this: &mut MiriEvalContext<'a, 'mir, 'tcx>, } None => { err!(Unimplemented( - "miri does not support random number generators in deterministic mode! - Use '-Zmiri-seed=' to enable random number generation".to_owned(), + "miri does not support gathering system entropy in deterministic mode! + Use '-Zmiri-seed=' to enable random number generation. + WARNING: Miri does *not* generate cryptographically secure entropy - + do not use Miri to run any program that need secure random number generation".to_owned(), )) } } From ae8e7f654a002d182fe66cdbd3ebfe0ee1e74ae2 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Tue, 9 Apr 2019 10:19:29 -0400 Subject: [PATCH 0656/3747] Fix compile-fail error message --- tests/compile-fail/getrandom.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/compile-fail/getrandom.rs b/tests/compile-fail/getrandom.rs index 7f2087a320a43..4dc3e863aaaec 100644 --- a/tests/compile-fail/getrandom.rs +++ b/tests/compile-fail/getrandom.rs @@ -8,6 +8,6 @@ fn main() { let mut buf = [0u8; 5]; unsafe { libc::syscall(libc::SYS_getrandom, buf.as_mut_ptr() as *mut libc::c_void, 5 as libc::size_t, 0 as libc::c_uint); - //~^ ERROR constant evaluation error: miri does not support random number generators in deterministic mode! + //~^ ERROR constant evaluation error: miri does not support gathering system entropy in deterministic mode! } } From c6e0d097143a90ec8512a087b6cd3a475d2aeff1 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Tue, 9 Apr 2019 11:04:30 -0400 Subject: [PATCH 0657/3747] Retrieve SYS_getrandom from libc using const-eval --- src/fn_call.rs | 43 +++++++++++++++++++++++++++---------------- 1 file changed, 27 insertions(+), 16 deletions(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index b97c237412818..3eacaaa74e653 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -211,14 +211,14 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' } "syscall" => { - // TODO: read `syscall` IDs like `sysconf` IDs and - // figure out some way to actually process some of them. - // + let sys_getrandom = this.eval_path_scalar(&["libc", "SYS_getrandom"])? + .expect("Failed to get libc::SYS_getrandom") + .to_usize(this)? as i64; + // `libc::syscall(NR_GETRANDOM, buf.as_mut_ptr(), buf.len(), GRND_NONBLOCK)` // is called if a `HashMap` is created the regular way (e.g. HashMap). - match (this.read_scalar(args[0])?.to_usize(this)? as i64, tcx.data_layout.pointer_size.bits()) { - // SYS_getrandom on x86_64 and x86 respectively - (318, 64) | (355, 32) => { + match this.read_scalar(args[0])?.to_usize(this)? as i64 { + id if id == sys_getrandom => { let ptr = this.read_scalar(args[1])?.to_ptr()?; let len = this.read_scalar(args[2])?.to_usize(this)?; @@ -232,7 +232,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' this.write_scalar(Scalar::from_uint(len, dest.layout.size), dest)?; } - (id, _size) => { + id => { return err!(Unimplemented( format!("miri does not support syscall ID {}", id), )) @@ -496,18 +496,13 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' ]; let mut result = None; for &(path, path_value) in paths { - if let Ok(instance) = this.resolve_path(path) { - let cid = GlobalId { - instance, - promoted: None, - }; - let const_val = this.const_eval_raw(cid)?; - let const_val = this.read_scalar(const_val.into())?; - let value = const_val.to_i32()?; - if value == name { + if let Some(val) = this.eval_path_scalar(path)? { + let val = val.to_i32()?; + if val == name { result = Some(path_value); break; } + } } if let Some(result) = result { @@ -782,6 +777,22 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' fn write_null(&mut self, dest: PlaceTy<'tcx, Borrow>) -> EvalResult<'tcx> { self.eval_context_mut().write_scalar(Scalar::from_int(0, dest.layout.size), dest) } + + /// Evaluates the scalar at the specified path. Returns Some(val) + /// if the path could be resolved, and None otherwise + fn eval_path_scalar(&mut self, path: &[&str]) -> EvalResult<'tcx, Option>> { + let this = self.eval_context_mut(); + if let Ok(instance) = this.resolve_path(path) { + let cid = GlobalId { + instance, + promoted: None, + }; + let const_val = this.const_eval_raw(cid)?; + let const_val = this.read_scalar(const_val.into())?; + return Ok(Some(const_val)); + } + return Ok(None); + } } fn gen_random<'a, 'mir, 'tcx>(this: &mut MiriEvalContext<'a, 'mir, 'tcx>, From 0837d630f7becb8259074a2adc35e77476e5083e Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Tue, 9 Apr 2019 15:49:34 -0400 Subject: [PATCH 0658/3747] Some final cleanup --- src/fn_call.rs | 14 ++++++++------ src/lib.rs | 5 ++--- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index 3eacaaa74e653..50351e2c70454 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -213,11 +213,11 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' "syscall" => { let sys_getrandom = this.eval_path_scalar(&["libc", "SYS_getrandom"])? .expect("Failed to get libc::SYS_getrandom") - .to_usize(this)? as i64; + .to_usize(this)?; // `libc::syscall(NR_GETRANDOM, buf.as_mut_ptr(), buf.len(), GRND_NONBLOCK)` // is called if a `HashMap` is created the regular way (e.g. HashMap). - match this.read_scalar(args[0])?.to_usize(this)? as i64 { + match this.read_scalar(args[0])?.to_usize(this)? { id if id == sys_getrandom => { let ptr = this.read_scalar(args[1])?.to_ptr()?; let len = this.read_scalar(args[2])?.to_usize(this)?; @@ -795,13 +795,15 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' } } -fn gen_random<'a, 'mir, 'tcx>(this: &mut MiriEvalContext<'a, 'mir, 'tcx>, - len: usize) -> Result, EvalError<'tcx>> { +fn gen_random<'a, 'mir, 'tcx>( + this: &mut MiriEvalContext<'a, 'mir, 'tcx>, + len: usize, +) -> Result, EvalError<'tcx>> { - match this.machine.rng.as_ref() { + match &mut this.machine.rng { Some(rng) => { let mut data = vec![0; len]; - rng.borrow_mut().fill_bytes(&mut data); + rng.fill_bytes(&mut data); Ok(data) } None => { diff --git a/src/lib.rs b/src/lib.rs index 9b4b69b6d7072..d185ec610c9a5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -23,7 +23,6 @@ mod stacked_borrows; use std::collections::HashMap; use std::borrow::Cow; -use std::cell::RefCell; use rand::rngs::StdRng; use rand::SeedableRng; @@ -336,7 +335,7 @@ pub struct Evaluator<'tcx> { /// The random number generator to use if Miri /// is running in non-deterministic mode - pub(crate) rng: Option> + pub(crate) rng: Option } impl<'tcx> Evaluator<'tcx> { @@ -350,7 +349,7 @@ impl<'tcx> Evaluator<'tcx> { tls: TlsData::default(), validate, stacked_borrows: stacked_borrows::State::default(), - rng: seed.map(|s| RefCell::new(StdRng::seed_from_u64(s))) + rng: seed.map(|s| StdRng::seed_from_u64(s)) } } } From 48b22b80c5e4977fd638d67e9494d85df5cb912e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 9 Apr 2019 23:33:13 -0400 Subject: [PATCH 0659/3747] Fix typo Co-Authored-By: Aaron1011 --- src/fn_call.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index a0ff614de20a0..3e12c1dd1c6dc 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -826,7 +826,7 @@ fn gen_random<'a, 'mir, 'tcx>( "miri does not support gathering system entropy in deterministic mode! Use '-Zmiri-seed=' to enable random number generation. WARNING: Miri does *not* generate cryptographically secure entropy - - do not use Miri to run any program that need secure random number generation".to_owned(), + do not use Miri to run any program that needs secure random number generation".to_owned(), )) } } From a8763f3d8d8e362f49090e8d99a86920f2e55fef Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Tue, 9 Apr 2019 23:36:27 -0400 Subject: [PATCH 0660/3747] Don't create HashMap when not needed --- tests/run-pass/hashmap.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/tests/run-pass/hashmap.rs b/tests/run-pass/hashmap.rs index a95f7170aa1b1..b29b681939794 100644 --- a/tests/run-pass/hashmap.rs +++ b/tests/run-pass/hashmap.rs @@ -27,13 +27,12 @@ fn test_map(mut map: HashMap) { } fn main() { - let _map : HashMap> = Default::default(); - // TODO: Implement random number generation on OS X if cfg!(not(target_os = "macos")) { let map_normal: HashMap = HashMap::new(); test_map(map_normal); } else { - test_map(_map); + let map : HashMap> = Default::default(); + test_map(map); } } From 83d199eb86c107087ad40fab1c98ceb1d799b2de Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 10 Apr 2019 17:20:54 +0200 Subject: [PATCH 0661/3747] fix async-fn test --- tests/run-pass/async-fn.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/tests/run-pass/async-fn.rs b/tests/run-pass/async-fn.rs index 79fcb59011f69..7af2304cb400e 100644 --- a/tests/run-pass/async-fn.rs +++ b/tests/run-pass/async-fn.rs @@ -1,4 +1,3 @@ -// ignore-test FIXME ignored to let https://github.com/rust-lang/rust/pull/59119 land #![feature( async_await, await_macro, @@ -6,7 +5,7 @@ )] use std::{future::Future, pin::Pin, task::Poll, ptr}; -use std::task::{Waker, RawWaker, RawWakerVTable}; +use std::task::{Waker, RawWaker, RawWakerVTable, Context}; // See if we can run a basic `async fn` pub async fn foo(x: &u32, y: u32) -> u32 { @@ -27,15 +26,16 @@ fn raw_waker_wake(_this: *const ()) { } fn raw_waker_drop(_this: *const ()) {} -static RAW_WAKER: RawWakerVTable = RawWakerVTable { - clone: raw_waker_clone, - wake: raw_waker_wake, - drop: raw_waker_drop, -}; +static RAW_WAKER: RawWakerVTable = RawWakerVTable::new( + raw_waker_clone, + raw_waker_wake, + raw_waker_drop, +); fn main() { let x = 5; let mut fut = foo(&x, 7); let waker = unsafe { Waker::new_unchecked(RawWaker::new(ptr::null(), &RAW_WAKER)) }; - assert_eq!(unsafe { Pin::new_unchecked(&mut fut) }.poll(&waker), Poll::Ready(31)); + let mut context = Context::from_waker(&waker); + assert_eq!(unsafe { Pin::new_unchecked(&mut fut) }.poll(&mut context), Poll::Ready(31)); } From 8235f5694cccdb131f1a26f94eb7a9bc8f9e3117 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 11 Apr 2019 22:09:27 +0200 Subject: [PATCH 0662/3747] bump Rust version --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index a2b3daad97ec8..69a46de1d45d0 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -f717b58dd70829f105960a071c7992b440720482 +3de0106789468b211bcc3a25c09c0cf07119186d From 5f29a539921298fd4d36b1574c01de35e8f6e7a3 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 12 Apr 2019 12:32:14 +0200 Subject: [PATCH 0663/3747] rustup --- rust-version | 2 +- src/fn_call.rs | 6 +++--- src/intrinsic.rs | 10 +++++----- src/lib.rs | 6 +++--- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/rust-version b/rust-version index 69a46de1d45d0..9e2c1a36bb4f6 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -3de0106789468b211bcc3a25c09c0cf07119186d +2226c09699a96520238e162777f44504f4a0a1a7 diff --git a/src/fn_call.rs b/src/fn_call.rs index 3e12c1dd1c6dc..bb6d6aed49054 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -62,11 +62,11 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' let this = self.eval_context_mut(); let attrs = this.tcx.get_attrs(def_id); let link_name = match attr::first_attr_value_str_by_name(&attrs, "link_name") { - Some(name) => name.as_str().get(), - None => this.tcx.item_name(def_id).as_str().get(), + Some(name) => name.as_str(), + None => this.tcx.item_name(def_id).as_str(), }; // Strip linker suffixes (seen on 32-bit macOS). - let link_name = link_name.trim_end_matches("$UNIX2003"); + let link_name = link_name.get().trim_end_matches("$UNIX2003"); let tcx = &{this.tcx.tcx}; // First: functions that could diverge. diff --git a/src/intrinsic.rs b/src/intrinsic.rs index 5b0f0e99ad84e..bb156c95dfea7 100644 --- a/src/intrinsic.rs +++ b/src/intrinsic.rs @@ -27,8 +27,8 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, // (as opposed to through a place), we have to remember to erase any tag // that might still hang around! - let intrinsic_name = this.tcx.item_name(instance.def_id()).as_str().get(); - match intrinsic_name { + let intrinsic_name = this.tcx.item_name(instance.def_id()).as_str(); + match intrinsic_name.get() { "arith_offset" => { let offset = this.read_scalar(args[1])?.to_isize(this)?; let ptr = this.read_scalar(args[0])?.not_undef()?; @@ -187,7 +187,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, "sinf32" | "fabsf32" | "cosf32" | "sqrtf32" | "expf32" | "exp2f32" | "logf32" | "log10f32" | "log2f32" | "floorf32" | "ceilf32" | "truncf32" => { let f = this.read_scalar(args[0])?.to_f32()?; - let f = match intrinsic_name { + let f = match intrinsic_name.get() { "sinf32" => f.sin(), "fabsf32" => f.abs(), "cosf32" => f.cos(), @@ -208,7 +208,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, "sinf64" | "fabsf64" | "cosf64" | "sqrtf64" | "expf64" | "exp2f64" | "logf64" | "log10f64" | "log2f64" | "floorf64" | "ceilf64" | "truncf64" => { let f = this.read_scalar(args[0])?.to_f64()?; - let f = match intrinsic_name { + let f = match intrinsic_name.get() { "sinf64" => f.sin(), "fabsf64" => f.abs(), "cosf64" => f.cos(), @@ -229,7 +229,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, "fadd_fast" | "fsub_fast" | "fmul_fast" | "fdiv_fast" | "frem_fast" => { let a = this.read_immediate(args[0])?; let b = this.read_immediate(args[1])?; - let op = match intrinsic_name { + let op = match intrinsic_name.get() { "fadd_fast" => mir::BinOp::Add, "fsub_fast" => mir::BinOp::Sub, "fmul_fast" => mir::BinOp::Mul, diff --git a/src/lib.rs b/src/lib.rs index ba9b69703a416..541986de55171 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -470,11 +470,11 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { ) -> EvalResult<'tcx, Cow<'tcx, Allocation>> { let attrs = tcx.get_attrs(def_id); let link_name = match attr::first_attr_value_str_by_name(&attrs, "link_name") { - Some(name) => name.as_str().get(), - None => tcx.item_name(def_id).as_str().get(), + Some(name) => name.as_str(), + None => tcx.item_name(def_id).as_str(), }; - let alloc = match link_name { + let alloc = match link_name.get() { "__cxa_thread_atexit_impl" => { // This should be all-zero, pointer-sized. let size = tcx.data_layout.pointer_size; From aa79244b62c7a4506213829629f4993daa6f0cf5 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 12 Apr 2019 22:15:55 +0200 Subject: [PATCH 0664/3747] rustup --- rust-version | 2 +- tests/run-pass/async-fn.rs | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/rust-version b/rust-version index 9e2c1a36bb4f6..29649e957f2cd 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -2226c09699a96520238e162777f44504f4a0a1a7 +df25d79a33b0c82b716699a75a41bfdc6089850a diff --git a/tests/run-pass/async-fn.rs b/tests/run-pass/async-fn.rs index 7af2304cb400e..1608ea1888942 100644 --- a/tests/run-pass/async-fn.rs +++ b/tests/run-pass/async-fn.rs @@ -24,18 +24,22 @@ fn raw_waker_clone(_this: *const ()) -> RawWaker { fn raw_waker_wake(_this: *const ()) { panic!("unimplemented"); } +fn raw_waker_wake_by_ref(_this: *const ()) { + panic!("unimplemented"); +} fn raw_waker_drop(_this: *const ()) {} static RAW_WAKER: RawWakerVTable = RawWakerVTable::new( raw_waker_clone, raw_waker_wake, + raw_waker_wake_by_ref, raw_waker_drop, ); fn main() { let x = 5; let mut fut = foo(&x, 7); - let waker = unsafe { Waker::new_unchecked(RawWaker::new(ptr::null(), &RAW_WAKER)) }; + let waker = unsafe { Waker::from_raw(RawWaker::new(ptr::null(), &RAW_WAKER)) }; let mut context = Context::from_waker(&waker); assert_eq!(unsafe { Pin::new_unchecked(&mut fut) }.poll(&mut context), Poll::Ready(31)); } From 98296d60e7d5db8296748e263eca2c55026ef056 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 12 Apr 2019 23:17:58 +0200 Subject: [PATCH 0665/3747] lower rand version requirement --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 6c77315bea48b..bb86795270fa7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -45,7 +45,7 @@ shell-escape = "0.1.4" # for more information. rustc-workspace-hack = "1.0.0" hex = "0.3.2" -rand = "0.6.5" +rand = "0.6" [build-dependencies] vergen = "3" From a246116bdc6bc42fed360a1267de4f99492be791 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 14 Apr 2019 10:30:00 +0200 Subject: [PATCH 0666/3747] rustup --- rust-version | 2 +- tests/compile-fail/deallocate-bad-alignment.rs | 2 +- tests/compile-fail/deallocate-bad-size.rs | 2 +- tests/compile-fail/deallocate-twice.rs | 2 +- tests/compile-fail/reallocate-bad-size.rs | 2 +- tests/compile-fail/reallocate-change-alloc.rs | 2 +- tests/compile-fail/reallocate-dangling.rs | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/rust-version b/rust-version index 29649e957f2cd..dcee3ec5daa73 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -df25d79a33b0c82b716699a75a41bfdc6089850a +ee621f42329069c296b4c2066b3743cc4ff0f369 diff --git a/tests/compile-fail/deallocate-bad-alignment.rs b/tests/compile-fail/deallocate-bad-alignment.rs index 4b89f0ac70c79..d124136a96537 100644 --- a/tests/compile-fail/deallocate-bad-alignment.rs +++ b/tests/compile-fail/deallocate-bad-alignment.rs @@ -1,4 +1,4 @@ -#![feature(alloc, allocator_api)] +#![feature(allocator_api)] extern crate alloc; diff --git a/tests/compile-fail/deallocate-bad-size.rs b/tests/compile-fail/deallocate-bad-size.rs index 3a74245816c46..7a95b0ac7e90a 100644 --- a/tests/compile-fail/deallocate-bad-size.rs +++ b/tests/compile-fail/deallocate-bad-size.rs @@ -1,4 +1,4 @@ -#![feature(alloc, allocator_api)] +#![feature(allocator_api)] extern crate alloc; diff --git a/tests/compile-fail/deallocate-twice.rs b/tests/compile-fail/deallocate-twice.rs index 613edf3c6af95..03fab76d601b5 100644 --- a/tests/compile-fail/deallocate-twice.rs +++ b/tests/compile-fail/deallocate-twice.rs @@ -1,4 +1,4 @@ -#![feature(alloc, allocator_api)] +#![feature(allocator_api)] extern crate alloc; diff --git a/tests/compile-fail/reallocate-bad-size.rs b/tests/compile-fail/reallocate-bad-size.rs index 489b7bebcdc8f..24d913205447d 100644 --- a/tests/compile-fail/reallocate-bad-size.rs +++ b/tests/compile-fail/reallocate-bad-size.rs @@ -1,4 +1,4 @@ -#![feature(alloc, allocator_api)] +#![feature(allocator_api)] extern crate alloc; diff --git a/tests/compile-fail/reallocate-change-alloc.rs b/tests/compile-fail/reallocate-change-alloc.rs index 1e2178811ea3a..312edfd52b277 100644 --- a/tests/compile-fail/reallocate-change-alloc.rs +++ b/tests/compile-fail/reallocate-change-alloc.rs @@ -1,4 +1,4 @@ -#![feature(alloc, allocator_api)] +#![feature(allocator_api)] extern crate alloc; diff --git a/tests/compile-fail/reallocate-dangling.rs b/tests/compile-fail/reallocate-dangling.rs index 6dfb7fe2b9663..450f63cc40d35 100644 --- a/tests/compile-fail/reallocate-dangling.rs +++ b/tests/compile-fail/reallocate-dangling.rs @@ -1,4 +1,4 @@ -#![feature(alloc, allocator_api)] +#![feature(allocator_api)] extern crate alloc; From 378d9d41720fe2a8a2aec1b39551d11fac6d8ec6 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 16 Apr 2019 17:47:37 +0200 Subject: [PATCH 0667/3747] be pragmatic about ptr-int comparisons, for now --- src/operator.rs | 18 ++++++++++++++---- tests/run-pass/vecs.rs | 4 ++++ 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/src/operator.rs b/src/operator.rs index a30b11aeb27de..45c0e63542dc2 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -152,8 +152,9 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' // This accepts one-past-the end. Thus, there is still technically // some non-determinism that we do not fully rule out when two // allocations sit right next to each other. The C/C++ standards are - // somewhat fuzzy about this case, so I think for now this check is - // "good enough". + // somewhat fuzzy about this case, so pragmatically speaking I think + // for now this check is "good enough". + // FIXME: Once we support intptrcast, we could try to fix these holes. // Dead allocations in miri cannot overlap with live allocations, but // on read hardware this can easily happen. Thus for comparisons we require // both pointers to be live. @@ -169,8 +170,17 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' assert_eq!(size as u64, self.pointer_size().bytes()); let bits = bits as u64; - // Case I: Comparing with NULL. - if bits == 0 { + // Case I: Comparing real pointers with "small" integers. + // Really we should only do this for NULL, but pragmatically speaking on non-bare-metal systems, + // an allocation will never be at the very bottom of the address space. + // Such comparisons can arise when comparing empty slices, which sometimes are "fake" + // integer pointers (okay because the slice is empty) and sometimes point into a + // real allocation. + // The most common source of such integer pointers is `NonNull::dangling()`, which + // equals the type's alignment. i128 might have an alignment of 16 bytes, but few types have + // alignment 32 or higher, hence the limit of 32. + // FIXME: Once we support intptrcast, we could try to fix these holes. + if bits < 32 { // Test if the ptr is in-bounds. Then it cannot be NULL. // Even dangling pointers cannot be NULL. if self.memory().check_bounds_ptr(ptr, InboundsCheck::MaybeDead).is_ok() { diff --git a/tests/run-pass/vecs.rs b/tests/run-pass/vecs.rs index bb9e5068f91e8..739def804975d 100644 --- a/tests/run-pass/vecs.rs +++ b/tests/run-pass/vecs.rs @@ -85,4 +85,8 @@ fn main() { assert_eq!(make_vec_macro(), [1, 2]); assert_eq!(make_vec_macro_repeat(), [42; 5]); assert_eq!(make_vec_macro_repeat_zeroed(), [0; 7]); + + // Test interesting empty slice comparison + // (one is a real pointer, one an integer pointer). + assert_eq!((200..-5).step_by(1).collect::>(), []); } From ceca7c502057fedee2e77329df4ec23b1bebaa03 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 16 Apr 2019 19:06:08 +0200 Subject: [PATCH 0668/3747] tweak entropy tests a bit --- tests/compile-fail/getrandom.rs | 4 ++-- tests/run-pass/hashmap.rs | 9 +++++---- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/tests/compile-fail/getrandom.rs b/tests/compile-fail/getrandom.rs index 4dc3e863aaaec..d54c95c82385c 100644 --- a/tests/compile-fail/getrandom.rs +++ b/tests/compile-fail/getrandom.rs @@ -1,5 +1,5 @@ -// ignore-macos -// ignore-windows +// ignore-macos: Uses Linux-only APIs +// ignore-windows: Uses Linux-only APIs #![feature(rustc_private)] extern crate libc; diff --git a/tests/run-pass/hashmap.rs b/tests/run-pass/hashmap.rs index b29b681939794..796e63c81a412 100644 --- a/tests/run-pass/hashmap.rs +++ b/tests/run-pass/hashmap.rs @@ -27,12 +27,13 @@ fn test_map(mut map: HashMap) { } fn main() { - // TODO: Implement random number generation on OS X if cfg!(not(target_os = "macos")) { - let map_normal: HashMap = HashMap::new(); - test_map(map_normal); + let map: HashMap = HashMap::default(); + test_map(map); } else { - let map : HashMap> = Default::default(); + // TODO: Implement random number generation on OS X. + // Until then, use a deterministic map. + let map : HashMap> = HashMap::default(); test_map(map); } } From af2b42de0a43c0bf656e290e73a431acd033e79d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 16 Apr 2019 19:09:37 +0200 Subject: [PATCH 0669/3747] fix compile-fail test --- tests/compile-fail/ptr_eq_integer.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/tests/compile-fail/ptr_eq_integer.rs b/tests/compile-fail/ptr_eq_integer.rs index 10d5fbd517a3c..396abaf4493b1 100644 --- a/tests/compile-fail/ptr_eq_integer.rs +++ b/tests/compile-fail/ptr_eq_integer.rs @@ -1,8 +1,6 @@ -use std::mem; - fn main() { let b = Box::new(0); let x = &*b as *const i32; // We cannot compare this with a non-NULL integer. After all, these *could* be equal (with the right base address). - assert!(x != mem::align_of::() as *const i32); //~ ERROR invalid arithmetic on pointers + assert!(x != 64 as *const i32); //~ ERROR invalid arithmetic on pointers } From bd4a772e1a87180f31da81f7d11ef07cff042bbf Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 16 Apr 2019 19:12:56 +0200 Subject: [PATCH 0670/3747] update cargo miri test to test rng crate a bit; this currently fails --- test-cargo-miri/run-test.py | 2 +- test-cargo-miri/test.stdout.ref | 5 +++-- test-cargo-miri/tests/test.rs | 10 +++++++++- 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/test-cargo-miri/run-test.py b/test-cargo-miri/run-test.py index 8c59b6bcdead6..f1412dbf3969e 100755 --- a/test-cargo-miri/run-test.py +++ b/test-cargo-miri/run-test.py @@ -43,7 +43,7 @@ def test_cargo_miri_run(): ) def test_cargo_miri_test(): - test("cargo miri test", ["cargo", "miri", "test", "-q"], "test.stdout.ref", "test.stderr.ref") + test("cargo miri test", ["cargo", "miri", "test", "-q", "--", "-Zmiri-seed=feed"], "test.stdout.ref", "test.stderr.ref") test("cargo miri test (with filter)", ["cargo", "miri", "test", "-q", "--", "--", "impl"], "test.stdout.ref2", "test.stderr.ref" diff --git a/test-cargo-miri/test.stdout.ref b/test-cargo-miri/test.stdout.ref index 9c3621f21535b..318057a7d9e64 100644 --- a/test-cargo-miri/test.stdout.ref +++ b/test-cargo-miri/test.stdout.ref @@ -5,9 +5,10 @@ test test::rng ... ok test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out -running 2 tests +running 3 tests test rng ... ok +test seeded_rng ... ok test simple ... ok -test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out +test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out diff --git a/test-cargo-miri/tests/test.rs b/test-cargo-miri/tests/test.rs index e9faaf2fb2f19..6f7876d679b63 100644 --- a/test-cargo-miri/tests/test.rs +++ b/test-cargo-miri/tests/test.rs @@ -1,6 +1,6 @@ extern crate rand; -use rand::{Rng, SeedableRng}; +use rand::{SeedableRng, FromEntropy, Rng, rngs::SmallRng}; #[test] fn simple() { @@ -17,6 +17,14 @@ fn rng() { assert_ne!(x, y); } +#[test] +#[cfg(not(target_os="macos"))] // FIXME entropy does not work on macOS +fn seeded_rng() { + // Use this opportunity to test querying the RNG (needs an external crate, hence tested here and not in the compiletest suite) + let mut rng = SmallRng::from_entropy(); + let _val = rng.gen::(); +} + // A test that won't work on miri #[cfg(not(miri))] #[test] From 9c8ad5f9e199d45b7c2425389ef718ce65071be2 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 16 Apr 2019 19:26:02 +0200 Subject: [PATCH 0671/3747] fix 0-sized getrandom --- src/fn_call.rs | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index bb6d6aed49054..718f1c24ac79c 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -241,9 +241,11 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' // neither of which have any effect on our current PRNG let _flags = this.read_scalar(args[3])?.to_i32()?; - let data = gen_random(this, len as usize)?; - this.memory_mut().get_mut(ptr.alloc_id)? - .write_bytes(tcx, ptr, &data)?; + if len > 0 { + let data = gen_random(this, len as usize)?; + this.memory_mut().get_mut(ptr.alloc_id)? + .write_bytes(tcx, ptr, &data)?; + } this.write_scalar(Scalar::from_uint(len, dest.layout.size), dest)?; } @@ -769,9 +771,11 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' let ptr = this.read_scalar(args[0])?.to_ptr()?; let len = this.read_scalar(args[1])?.to_usize(this)?; - let data = gen_random(this, len as usize)?; - this.memory_mut().get_mut(ptr.alloc_id)? - .write_bytes(tcx, ptr, &data)?; + if len > 0 { + let data = gen_random(this, len as usize)?; + this.memory_mut().get_mut(ptr.alloc_id)? + .write_bytes(tcx, ptr, &data)?; + } this.write_scalar(Scalar::from_bool(true), dest)?; } From ba567d19f09f105d7ed03808d2220b27fc0b8893 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 16 Apr 2019 19:49:36 +0200 Subject: [PATCH 0672/3747] stub out pthread_atfork to that we support thread_rng() --- src/fn_call.rs | 5 +++++ test-cargo-miri/tests/test.rs | 4 ++++ 2 files changed, 9 insertions(+) diff --git a/src/fn_call.rs b/src/fn_call.rs index 718f1c24ac79c..bb9eef0c87210 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -624,6 +624,11 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' this.write_null(dest)?; } + // We don't support fork so we don't have to do anything for atfork. + "pthread_atfork" => { + this.write_null(dest)?; + } + "mmap" => { // This is a horrible hack, but since the guard page mechanism calls mmap and expects a particular return value, we just give it that value. let addr = this.read_scalar(args[0])?.not_undef()?; diff --git a/test-cargo-miri/tests/test.rs b/test-cargo-miri/tests/test.rs index 6f7876d679b63..1812ca59c4175 100644 --- a/test-cargo-miri/tests/test.rs +++ b/test-cargo-miri/tests/test.rs @@ -23,6 +23,10 @@ fn seeded_rng() { // Use this opportunity to test querying the RNG (needs an external crate, hence tested here and not in the compiletest suite) let mut rng = SmallRng::from_entropy(); let _val = rng.gen::(); + + // Also try per-thread RNG. + let mut rng = rand::thread_rng(); + let _val = rng.gen::(); } // A test that won't work on miri From 5761a0bf61fe932699c0547849da792f4fb2c4fa Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 16 Apr 2019 19:55:22 +0200 Subject: [PATCH 0673/3747] fix ref file --- test-cargo-miri/test.stdout.ref2 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test-cargo-miri/test.stdout.ref2 b/test-cargo-miri/test.stdout.ref2 index ce3506709d5a0..32d943623a919 100644 --- a/test-cargo-miri/test.stdout.ref2 +++ b/test-cargo-miri/test.stdout.ref2 @@ -7,5 +7,5 @@ test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 1 filtered out running 1 test test simple ... ok -test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 1 filtered out +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 2 filtered out From 59541d446aabc3b0a15bc1ba2a3f28eeb7608285 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 16 Apr 2019 20:12:55 +0200 Subject: [PATCH 0674/3747] pick better test names --- test-cargo-miri/test.stdout.ref | 4 ++-- test-cargo-miri/tests/test.rs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/test-cargo-miri/test.stdout.ref b/test-cargo-miri/test.stdout.ref index 318057a7d9e64..97589e9a16351 100644 --- a/test-cargo-miri/test.stdout.ref +++ b/test-cargo-miri/test.stdout.ref @@ -6,8 +6,8 @@ test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out running 3 tests -test rng ... ok -test seeded_rng ... ok +test entropy_rng ... ok +test fixed_rng ... ok test simple ... ok test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out diff --git a/test-cargo-miri/tests/test.rs b/test-cargo-miri/tests/test.rs index 1812ca59c4175..cea14d0d1ca2e 100644 --- a/test-cargo-miri/tests/test.rs +++ b/test-cargo-miri/tests/test.rs @@ -10,7 +10,7 @@ fn simple() { // Having more than 1 test does seem to make a difference // (i.e., this calls ptr::swap which having just one test does not). #[test] -fn rng() { +fn fixed_rng() { let mut rng = rand::rngs::StdRng::seed_from_u64(0xdeadcafe); let x: u32 = rng.gen(); let y: u32 = rng.gen(); @@ -19,7 +19,7 @@ fn rng() { #[test] #[cfg(not(target_os="macos"))] // FIXME entropy does not work on macOS -fn seeded_rng() { +fn entropy_rng() { // Use this opportunity to test querying the RNG (needs an external crate, hence tested here and not in the compiletest suite) let mut rng = SmallRng::from_entropy(); let _val = rng.gen::(); From 341798f09da757d18aa6e139748134561b610d00 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 16 Apr 2019 20:14:23 +0200 Subject: [PATCH 0675/3747] fix tests on macOS --- test-cargo-miri/tests/test.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test-cargo-miri/tests/test.rs b/test-cargo-miri/tests/test.rs index cea14d0d1ca2e..7b6aaf934ec73 100644 --- a/test-cargo-miri/tests/test.rs +++ b/test-cargo-miri/tests/test.rs @@ -1,3 +1,5 @@ +#![allow(unused_imports)] // FIXME for macOS + extern crate rand; use rand::{SeedableRng, FromEntropy, Rng, rngs::SmallRng}; From 54039cafa83e58f271261d730dd9bf6bf78fffba Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 16 Apr 2019 20:36:33 +0200 Subject: [PATCH 0676/3747] try to really fix tests on macOS --- test-cargo-miri/tests/test.rs | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/test-cargo-miri/tests/test.rs b/test-cargo-miri/tests/test.rs index 7b6aaf934ec73..69a31c42a75c1 100644 --- a/test-cargo-miri/tests/test.rs +++ b/test-cargo-miri/tests/test.rs @@ -20,15 +20,18 @@ fn fixed_rng() { } #[test] -#[cfg(not(target_os="macos"))] // FIXME entropy does not work on macOS fn entropy_rng() { - // Use this opportunity to test querying the RNG (needs an external crate, hence tested here and not in the compiletest suite) - let mut rng = SmallRng::from_entropy(); - let _val = rng.gen::(); + #[cfg(not(target_os="macos"))] // FIXME entropy does not work on macOS + // (Not disabling the entire test as that would change the output.) + { + // Use this opportunity to test querying the RNG (needs an external crate, hence tested here and not in the compiletest suite) + let mut rng = SmallRng::from_entropy(); + let _val = rng.gen::(); - // Also try per-thread RNG. - let mut rng = rand::thread_rng(); - let _val = rng.gen::(); + // Also try per-thread RNG. + let mut rng = rand::thread_rng(); + let _val = rng.gen::(); + } } // A test that won't work on miri From a50512f75134d13a71c0cd99d698f21f17523f7f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 16 Apr 2019 21:04:44 +0200 Subject: [PATCH 0677/3747] fix RtlGenRandom argument size --- src/fn_call.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index bb9eef0c87210..64dcce161dd78 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -774,7 +774,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' // The actual name of 'RtlGenRandom' "SystemFunction036" => { let ptr = this.read_scalar(args[0])?.to_ptr()?; - let len = this.read_scalar(args[1])?.to_usize(this)?; + let len = this.read_scalar(args[1])?.to_u32()?; if len > 0 { let data = gen_random(this, len as usize)?; From d7bcaab7375120da4a08e295f0b8bd7109987998 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 17 Apr 2019 08:20:02 +0200 Subject: [PATCH 0678/3747] document -Zmiri-seed --- README.md | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 75ad2b81bf4b5..716c26c03a735 100644 --- a/README.md +++ b/README.md @@ -231,15 +231,23 @@ MIRI_SYSROOT=$(rustc +custom --print sysroot) cargo +custom run --manifest-path Several `-Z` flags are relevant for Miri: -* `-Zmir-opt-level` controls how many MIR optimizations are performed. miri +* `-Zmiri-seed=` is a custom `-Z` flag added by Miri. It enables the + interpreted program to seed an RNG with system entropy. Miri will keep an RNG + on its own that is seeded with the given seed, and use that to generate the + "system entropy" that seeds the RNG(s) in the interpreted program. + **NOTE**: This entropy is not good enough for cryptographic use! Do not + generate secret keys in Miri or perform other kinds of cryptographic + operations that rely on proper random numbers. +* `-Zmiri-disable-validation` disables enforcing the validity invariant, which + is enforced by default. This is mostly useful for debugging; it means Miri + will miss bugs in your program. However, this can also help to make Miri run + faster. +* `-Zmir-opt-level` controls how many MIR optimizations are performed. Miri overrides the default to be `0`; be advised that using any higher level can - make miri miss bugs in your program because they got optimized away. + make Miri miss bugs in your program because they got optimized away. * `-Zalways-encode-mir` makes rustc dump MIR even for completely monomorphic - functions. This is needed so that miri can execute such functions, so miri + functions. This is needed so that Miri can execute such functions, so Miri sets this flag per default. -* `-Zmiri-disable-validation` is a custom `-Z` flag added by miri. It disables - enforcing the validity invariant, which is enforced by default. This is - mostly useful for debugging; it means miri will miss bugs in your program. Moreover, Miri recognizes some environment variables: From 3f0a2a29414a67d9c52241a94ce373546ca2ddcf Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 15 Apr 2019 15:36:09 +0200 Subject: [PATCH 0679/3747] rewrite Stacked Borrows Core. this passes stacked-borrows.rs! --- src/fn_call.rs | 28 +- src/helpers.rs | 24 +- src/intrinsic.rs | 6 +- src/lib.rs | 108 +++-- src/operator.rs | 38 +- src/stacked_borrows.rs | 937 +++++++++++++++++++++-------------------- src/tls.rs | 10 +- 7 files changed, 573 insertions(+), 578 deletions(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index 64dcce161dd78..d8794fed46942 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -13,8 +13,8 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' fn find_fn( &mut self, instance: ty::Instance<'tcx>, - args: &[OpTy<'tcx, Borrow>], - dest: Option>, + args: &[OpTy<'tcx, Tag>], + dest: Option>, ret: Option, ) -> EvalResult<'tcx, Option<&'mir mir::Mir<'tcx>>> { let this = self.eval_context_mut(); @@ -55,8 +55,8 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' fn emulate_foreign_item( &mut self, def_id: DefId, - args: &[OpTy<'tcx, Borrow>], - dest: Option>, + args: &[OpTy<'tcx, Tag>], + dest: Option>, ret: Option, ) -> EvalResult<'tcx> { let this = self.eval_context_mut(); @@ -92,7 +92,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' } else { let align = this.tcx.data_layout.pointer_align.abi; let ptr = this.memory_mut().allocate(Size::from_bytes(size), align, MiriMemoryKind::C.into()); - this.write_scalar(Scalar::Ptr(ptr.with_default_tag()), dest)?; + this.write_scalar(Scalar::Ptr(ptr), dest)?; } } "calloc" => { @@ -105,7 +105,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' } else { let size = Size::from_bytes(bytes); let align = this.tcx.data_layout.pointer_align.abi; - let ptr = this.memory_mut().allocate(size, align, MiriMemoryKind::C.into()).with_default_tag(); + let ptr = this.memory_mut().allocate(size, align, MiriMemoryKind::C.into()); this.memory_mut().get_mut(ptr.alloc_id)?.write_repeat(tcx, ptr, 0, size)?; this.write_scalar(Scalar::Ptr(ptr), dest)?; } @@ -132,7 +132,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' Align::from_bytes(align).unwrap(), MiriMemoryKind::C.into() ); - this.write_scalar(Scalar::Ptr(ptr.with_default_tag()), ret.into())?; + this.write_scalar(Scalar::Ptr(ptr), ret.into())?; } this.write_null(dest)?; } @@ -162,8 +162,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' Size::from_bytes(size), Align::from_bytes(align).unwrap(), MiriMemoryKind::Rust.into() - ) - .with_default_tag(); + ); this.write_scalar(Scalar::Ptr(ptr), dest)?; } "__rust_alloc_zeroed" => { @@ -180,8 +179,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' Size::from_bytes(size), Align::from_bytes(align).unwrap(), MiriMemoryKind::Rust.into() - ) - .with_default_tag(); + ); this.memory_mut() .get_mut(ptr.alloc_id)? .write_repeat(tcx, ptr, 0, Size::from_bytes(size))?; @@ -222,7 +220,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' Align::from_bytes(align).unwrap(), MiriMemoryKind::Rust.into(), )?; - this.write_scalar(Scalar::Ptr(new_ptr.with_default_tag()), dest)?; + this.write_scalar(Scalar::Ptr(new_ptr), dest)?; } "syscall" => { @@ -428,7 +426,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' Size::from_bytes((value.len() + 1) as u64), Align::from_bytes(1).unwrap(), MiriMemoryKind::Env.into(), - ).with_default_tag(); + ); { let alloc = this.memory_mut().get_mut(value_copy.alloc_id)?; alloc.write_bytes(tcx, value_copy, &value)?; @@ -798,13 +796,13 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' Ok(()) } - fn write_null(&mut self, dest: PlaceTy<'tcx, Borrow>) -> EvalResult<'tcx> { + fn write_null(&mut self, dest: PlaceTy<'tcx, Tag>) -> EvalResult<'tcx> { self.eval_context_mut().write_scalar(Scalar::from_int(0, dest.layout.size), dest) } /// Evaluates the scalar at the specified path. Returns Some(val) /// if the path could be resolved, and None otherwise - fn eval_path_scalar(&mut self, path: &[&str]) -> EvalResult<'tcx, Option>> { + fn eval_path_scalar(&mut self, path: &[&str]) -> EvalResult<'tcx, Option>> { let this = self.eval_context_mut(); if let Ok(instance) = this.resolve_path(path) { let cid = GlobalId { diff --git a/src/helpers.rs b/src/helpers.rs index 8a4cccc743e6f..f468d256031ca 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -47,9 +47,9 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' /// will be true if this is frozen, false if this is in an `UnsafeCell`. fn visit_freeze_sensitive( &self, - place: MPlaceTy<'tcx, Borrow>, + place: MPlaceTy<'tcx, Tag>, size: Size, - mut action: impl FnMut(Pointer, Size, bool) -> EvalResult<'tcx>, + mut action: impl FnMut(Pointer, Size, bool) -> EvalResult<'tcx>, ) -> EvalResult<'tcx> { let this = self.eval_context_ref(); trace!("visit_frozen(place={:?}, size={:?})", *place, size); @@ -64,7 +64,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' let mut end_ptr = place.ptr; // Called when we detected an `UnsafeCell` at the given offset and size. // Calls `action` and advances `end_ptr`. - let mut unsafe_cell_action = |unsafe_cell_ptr: Scalar, unsafe_cell_size: Size| { + let mut unsafe_cell_action = |unsafe_cell_ptr: Scalar, unsafe_cell_size: Size| { if unsafe_cell_size != Size::ZERO { debug_assert_eq!(unsafe_cell_ptr.to_ptr().unwrap().alloc_id, end_ptr.to_ptr().unwrap().alloc_id); @@ -120,7 +120,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' /// Visiting the memory covered by a `MemPlace`, being aware of /// whether we are inside an `UnsafeCell` or not. struct UnsafeCellVisitor<'ecx, 'a, 'mir, 'tcx, F> - where F: FnMut(MPlaceTy<'tcx, Borrow>) -> EvalResult<'tcx> + where F: FnMut(MPlaceTy<'tcx, Tag>) -> EvalResult<'tcx> { ecx: &'ecx MiriEvalContext<'a, 'mir, 'tcx>, unsafe_cell_action: F, @@ -131,9 +131,9 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' for UnsafeCellVisitor<'ecx, 'a, 'mir, 'tcx, F> where - F: FnMut(MPlaceTy<'tcx, Borrow>) -> EvalResult<'tcx> + F: FnMut(MPlaceTy<'tcx, Tag>) -> EvalResult<'tcx> { - type V = MPlaceTy<'tcx, Borrow>; + type V = MPlaceTy<'tcx, Tag>; #[inline(always)] fn ecx(&self) -> &MiriEvalContext<'a, 'mir, 'tcx> { @@ -141,7 +141,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' } // Hook to detect `UnsafeCell`. - fn visit_value(&mut self, v: MPlaceTy<'tcx, Borrow>) -> EvalResult<'tcx> + fn visit_value(&mut self, v: MPlaceTy<'tcx, Tag>) -> EvalResult<'tcx> { trace!("UnsafeCellVisitor: {:?} {:?}", *v, v.layout.ty); let is_unsafe_cell = match v.layout.ty.sty { @@ -163,8 +163,8 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' // Make sure we visit aggregrates in increasing offset order. fn visit_aggregate( &mut self, - place: MPlaceTy<'tcx, Borrow>, - fields: impl Iterator>>, + place: MPlaceTy<'tcx, Tag>, + fields: impl Iterator>>, ) -> EvalResult<'tcx> { match place.layout.fields { layout::FieldPlacement::Array { .. } => { @@ -174,7 +174,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' } layout::FieldPlacement::Arbitrary { .. } => { // Gather the subplaces and sort them before visiting. - let mut places = fields.collect::>>>()?; + let mut places = fields.collect::>>>()?; places.sort_by_key(|place| place.ptr.get_ptr_offset(self.ecx())); self.walk_aggregate(place, places.into_iter().map(Ok)) } @@ -186,7 +186,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' } // We have to do *something* for unions. - fn visit_union(&mut self, v: MPlaceTy<'tcx, Borrow>) -> EvalResult<'tcx> + fn visit_union(&mut self, v: MPlaceTy<'tcx, Tag>) -> EvalResult<'tcx> { // With unions, we fall back to whatever the type says, to hopefully be consistent // with LLVM IR. @@ -200,7 +200,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' } // We should never get to a primitive, but always short-circuit somewhere above. - fn visit_primitive(&mut self, _v: MPlaceTy<'tcx, Borrow>) -> EvalResult<'tcx> + fn visit_primitive(&mut self, _v: MPlaceTy<'tcx, Tag>) -> EvalResult<'tcx> { bug!("we should always short-circuit before coming to a primitive") } diff --git a/src/intrinsic.rs b/src/intrinsic.rs index bb156c95dfea7..a17f576b43b7f 100644 --- a/src/intrinsic.rs +++ b/src/intrinsic.rs @@ -4,7 +4,7 @@ use rustc::ty::layout::{self, LayoutOf, Size}; use rustc::ty; use crate::{ - PlaceTy, OpTy, ImmTy, Immediate, Scalar, ScalarMaybeUndef, Borrow, + PlaceTy, OpTy, ImmTy, Immediate, Scalar, ScalarMaybeUndef, Tag, OperatorEvalContextExt }; @@ -13,8 +13,8 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, fn call_intrinsic( &mut self, instance: ty::Instance<'tcx>, - args: &[OpTy<'tcx, Borrow>], - dest: PlaceTy<'tcx, Borrow>, + args: &[OpTy<'tcx, Tag>], + dest: PlaceTy<'tcx, Tag>, ) -> EvalResult<'tcx> { let this = self.eval_context_mut(); if this.emulate_intrinsic(instance, args, dest)? { diff --git a/src/lib.rs b/src/lib.rs index 541986de55171..3dbe922999dab 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -23,6 +23,7 @@ mod stacked_borrows; use std::collections::HashMap; use std::borrow::Cow; +use std::rc::Rc; use rand::rngs::StdRng; use rand::SeedableRng; @@ -48,7 +49,7 @@ use crate::mono_hash_map::MonoHashMap; pub use crate::stacked_borrows::{EvalContextExt as StackedBorEvalContextExt}; // Used by priroda. -pub use crate::stacked_borrows::{Borrow, Stack, Stacks, BorStackItem}; +pub use crate::stacked_borrows::{Tag, Permission, Stack, Stacks, Item}; /// Insert rustc arguments at the beginning of the argument list that Miri wants to be /// set per default, for maximal validation power. @@ -155,7 +156,7 @@ pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( // Don't forget `0` terminator. cmd.push(std::char::from_u32(0).unwrap()); // Collect the pointers to the individual strings. - let mut argvs = Vec::>::new(); + let mut argvs = Vec::>::new(); for arg in config.args { // Add `0` terminator. let mut arg = arg.into_bytes(); @@ -187,7 +188,7 @@ pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( Size::from_bytes(cmd_utf16.len() as u64 * 2), Align::from_bytes(2).unwrap(), MiriMemoryKind::Env.into(), - ).with_default_tag(); + ); ecx.machine.cmd_line = Some(cmd_ptr); // Store the UTF-16 string. let char_size = Size::from_bytes(2); @@ -214,7 +215,13 @@ pub fn eval_main<'a, 'tcx: 'a>( main_id: DefId, config: MiriConfig, ) { - let mut ecx = create_ecx(tcx, main_id, config).expect("couldn't create ecx"); + let mut ecx = match create_ecx(tcx, main_id, config) { + Ok(ecx) => ecx, + Err(mut err) => { + err.print_backtrace(); + panic!("Miri initialziation error: {}", err.kind) + } + }; // Perform the main execution. let res: EvalResult = (|| { @@ -310,14 +317,14 @@ impl MayLeak for MiriMemoryKind { pub struct Evaluator<'tcx> { /// Environment variables set by `setenv`. /// Miri does not expose env vars from the host to the emulated program. - pub(crate) env_vars: HashMap, Pointer>, + pub(crate) env_vars: HashMap, Pointer>, /// Program arguments (`Option` because we can only initialize them after creating the ecx). /// These are *pointers* to argc/argv because macOS. /// We also need the full command line as one string because of Windows. - pub(crate) argc: Option>, - pub(crate) argv: Option>, - pub(crate) cmd_line: Option>, + pub(crate) argc: Option>, + pub(crate) argv: Option>, + pub(crate) cmd_line: Option>, /// Last OS error. pub(crate) last_error: u32, @@ -328,9 +335,6 @@ pub struct Evaluator<'tcx> { /// Whether to enforce the validity invariant. pub(crate) validate: bool, - /// Stacked Borrows state. - pub(crate) stacked_borrows: stacked_borrows::State, - /// The random number generator to use if Miri /// is running in non-deterministic mode pub(crate) rng: Option @@ -346,7 +350,6 @@ impl<'tcx> Evaluator<'tcx> { last_error: 0, tls: TlsData::default(), validate, - stacked_borrows: stacked_borrows::State::default(), rng: seed.map(|s| StdRng::seed_from_u64(s)) } } @@ -378,9 +381,9 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { type FrameExtra = stacked_borrows::CallId; type MemoryExtra = stacked_borrows::MemoryState; type AllocExtra = stacked_borrows::Stacks; - type PointerTag = Borrow; + type PointerTag = Tag; - type MemoryMap = MonoHashMap, Allocation)>; + type MemoryMap = MonoHashMap, Allocation)>; const STATIC_KIND: Option = Some(MiriMemoryKind::MutStatic); @@ -394,8 +397,8 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { fn find_fn( ecx: &mut InterpretCx<'a, 'mir, 'tcx, Self>, instance: ty::Instance<'tcx>, - args: &[OpTy<'tcx, Borrow>], - dest: Option>, + args: &[OpTy<'tcx, Tag>], + dest: Option>, ret: Option, ) -> EvalResult<'tcx, Option<&'mir mir::Mir<'tcx>>> { ecx.find_fn(instance, args, dest, ret) @@ -405,8 +408,8 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { fn call_intrinsic( ecx: &mut rustc_mir::interpret::InterpretCx<'a, 'mir, 'tcx, Self>, instance: ty::Instance<'tcx>, - args: &[OpTy<'tcx, Borrow>], - dest: PlaceTy<'tcx, Borrow>, + args: &[OpTy<'tcx, Tag>], + dest: PlaceTy<'tcx, Tag>, ) -> EvalResult<'tcx> { ecx.call_intrinsic(instance, args, dest) } @@ -415,15 +418,15 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { fn ptr_op( ecx: &rustc_mir::interpret::InterpretCx<'a, 'mir, 'tcx, Self>, bin_op: mir::BinOp, - left: ImmTy<'tcx, Borrow>, - right: ImmTy<'tcx, Borrow>, - ) -> EvalResult<'tcx, (Scalar, bool)> { + left: ImmTy<'tcx, Tag>, + right: ImmTy<'tcx, Tag>, + ) -> EvalResult<'tcx, (Scalar, bool)> { ecx.ptr_op(bin_op, left, right) } fn box_alloc( ecx: &mut InterpretCx<'a, 'mir, 'tcx, Self>, - dest: PlaceTy<'tcx, Borrow>, + dest: PlaceTy<'tcx, Tag>, ) -> EvalResult<'tcx> { trace!("box_alloc for {:?}", dest.layout.ty); // Call the `exchange_malloc` lang item. @@ -467,7 +470,7 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { def_id: DefId, tcx: TyCtxtAt<'a, 'tcx, 'tcx>, memory_extra: &Self::MemoryExtra, - ) -> EvalResult<'tcx, Cow<'tcx, Allocation>> { + ) -> EvalResult<'tcx, Cow<'tcx, Allocation>> { let attrs = tcx.get_attrs(def_id); let link_name = match attr::first_attr_value_str_by_name(&attrs, "link_name") { Some(name) => name.as_str(), @@ -479,7 +482,7 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { // This should be all-zero, pointer-sized. let size = tcx.data_layout.pointer_size; let data = vec![0; size.bytes() as usize]; - let extra = AllocationExtra::memory_allocated(size, memory_extra); + let extra = Stacks::new(size, Tag::default(), Rc::clone(memory_extra)); Allocation::from_bytes(&data, tcx.data_layout.pointer_align.abi, extra) } _ => return err!(Unimplemented( @@ -499,16 +502,17 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { fn adjust_static_allocation<'b>( alloc: &'b Allocation, memory_extra: &Self::MemoryExtra, - ) -> Cow<'b, Allocation> { - let extra = AllocationExtra::memory_allocated( + ) -> Cow<'b, Allocation> { + let extra = Stacks::new( Size::from_bytes(alloc.bytes.len() as u64), - memory_extra, + Tag::default(), + Rc::clone(memory_extra), ); - let alloc: Allocation = Allocation { + let alloc: Allocation = Allocation { bytes: alloc.bytes.clone(), relocations: Relocations::from_presorted( alloc.relocations.iter() - .map(|&(offset, ((), alloc))| (offset, (Borrow::default(), alloc))) + .map(|&(offset, ((), alloc))| (offset, (Tag::default(), alloc))) .collect() ), undef_mask: alloc.undef_mask.clone(), @@ -519,46 +523,30 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { Cow::Owned(alloc) } - fn tag_dereference( - ecx: &InterpretCx<'a, 'mir, 'tcx, Self>, - place: MPlaceTy<'tcx, Borrow>, - mutability: Option, - ) -> EvalResult<'tcx, Scalar> { - let size = ecx.size_and_align_of_mplace(place)?.map(|(size, _)| size) - // For extern types, just cover what we can. - .unwrap_or_else(|| place.layout.size); - if !ecx.tcx.sess.opts.debugging_opts.mir_emit_retag || - !Self::enforce_validity(ecx) || size == Size::ZERO - { - // No tracking. - Ok(place.ptr) - } else { - ecx.ptr_dereference(place, size, mutability.into())?; - // We never change the pointer. - Ok(place.ptr) - } + #[inline(always)] + fn new_allocation( + size: Size, + extra: &Self::MemoryExtra, + kind: MemoryKind, + ) -> (Self::AllocExtra, Self::PointerTag) { + Stacks::new_allocation(size, extra, kind) } #[inline(always)] - fn tag_new_allocation( - ecx: &mut InterpretCx<'a, 'mir, 'tcx, Self>, - ptr: Pointer, - kind: MemoryKind, - ) -> Pointer { - if !ecx.machine.validate { - // No tracking. - ptr.with_default_tag() - } else { - let tag = ecx.tag_new_allocation(ptr.alloc_id, kind); - Pointer::new_with_tag(ptr.alloc_id, ptr.offset, tag) - } + fn tag_dereference( + _ecx: &InterpretCx<'a, 'mir, 'tcx, Self>, + place: MPlaceTy<'tcx, Tag>, + _mutability: Option, + ) -> EvalResult<'tcx, Scalar> { + // Nothing happens. + Ok(place.ptr) } #[inline(always)] fn retag( ecx: &mut InterpretCx<'a, 'mir, 'tcx, Self>, kind: mir::RetagKind, - place: PlaceTy<'tcx, Borrow>, + place: PlaceTy<'tcx, Tag>, ) -> EvalResult<'tcx> { if !ecx.tcx.sess.opts.debugging_opts.mir_emit_retag || !Self::enforce_validity(ecx) { // No tracking, or no retagging. The latter is possible because a dependency of ours diff --git a/src/operator.rs b/src/operator.rs index 45c0e63542dc2..386fc4307b87f 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -7,39 +7,39 @@ pub trait EvalContextExt<'tcx> { fn ptr_op( &self, bin_op: mir::BinOp, - left: ImmTy<'tcx, Borrow>, - right: ImmTy<'tcx, Borrow>, - ) -> EvalResult<'tcx, (Scalar, bool)>; + left: ImmTy<'tcx, Tag>, + right: ImmTy<'tcx, Tag>, + ) -> EvalResult<'tcx, (Scalar, bool)>; fn ptr_int_arithmetic( &self, bin_op: mir::BinOp, - left: Pointer, + left: Pointer, right: u128, signed: bool, - ) -> EvalResult<'tcx, (Scalar, bool)>; + ) -> EvalResult<'tcx, (Scalar, bool)>; fn ptr_eq( &self, - left: Scalar, - right: Scalar, + left: Scalar, + right: Scalar, ) -> EvalResult<'tcx, bool>; fn pointer_offset_inbounds( &self, - ptr: Scalar, + ptr: Scalar, pointee_ty: Ty<'tcx>, offset: i64, - ) -> EvalResult<'tcx, Scalar>; + ) -> EvalResult<'tcx, Scalar>; } impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, 'tcx> { fn ptr_op( &self, bin_op: mir::BinOp, - left: ImmTy<'tcx, Borrow>, - right: ImmTy<'tcx, Borrow>, - ) -> EvalResult<'tcx, (Scalar, bool)> { + left: ImmTy<'tcx, Tag>, + right: ImmTy<'tcx, Tag>, + ) -> EvalResult<'tcx, (Scalar, bool)> { use rustc::mir::BinOp::*; trace!("ptr_op: {:?} {:?} {:?}", *left, bin_op, *right); @@ -136,8 +136,8 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' fn ptr_eq( &self, - left: Scalar, - right: Scalar, + left: Scalar, + right: Scalar, ) -> EvalResult<'tcx, bool> { let size = self.pointer_size(); Ok(match (left, right) { @@ -233,13 +233,13 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' fn ptr_int_arithmetic( &self, bin_op: mir::BinOp, - left: Pointer, + left: Pointer, right: u128, signed: bool, - ) -> EvalResult<'tcx, (Scalar, bool)> { + ) -> EvalResult<'tcx, (Scalar, bool)> { use rustc::mir::BinOp::*; - fn map_to_primval((res, over): (Pointer, bool)) -> (Scalar, bool) { + fn map_to_primval((res, over): (Pointer, bool)) -> (Scalar, bool) { (Scalar::Ptr(res), over) } @@ -327,10 +327,10 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' /// allocation, and all the remaining integers pointers their own allocation. fn pointer_offset_inbounds( &self, - ptr: Scalar, + ptr: Scalar, pointee_ty: Ty<'tcx>, offset: i64, - ) -> EvalResult<'tcx, Scalar> { + ) -> EvalResult<'tcx, Scalar> { // FIXME: assuming here that type size is less than `i64::max_value()`. let pointee_size = self.layout_of(pointee_ty)?.size.bytes() as i64; let offset = offset diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index bea6aaf9cf892..080200b12a4ea 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -1,6 +1,8 @@ use std::cell::RefCell; use std::collections::HashSet; use std::rc::Rc; +use std::fmt; +use std::num::NonZeroU64; use rustc::ty::{self, layout::Size}; use rustc::hir::{Mutability, MutMutable, MutImmutable}; @@ -8,120 +10,163 @@ use rustc::mir::RetagKind; use crate::{ EvalResult, InterpError, MiriEvalContext, HelpersEvalContextExt, Evaluator, MutValueVisitor, - MemoryKind, MiriMemoryKind, RangeMap, AllocId, Allocation, AllocationExtra, + MemoryKind, MiriMemoryKind, RangeMap, Allocation, AllocationExtra, Pointer, Immediate, ImmTy, PlaceTy, MPlaceTy, }; -pub type Timestamp = u64; +pub type PtrId = NonZeroU64; pub type CallId = u64; -/// Information about which kind of borrow was used to create the reference this is tagged with. +/// Tracking pointer provenance #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] -pub enum Borrow { - /// A unique (mutable) reference. - Uniq(Timestamp), - /// An aliasing reference. This is also used by raw pointers, which do not track details - /// of how or when they were created, hence the timestamp is optional. - /// `Shr(Some(_))` does *not* mean that the destination of this reference is frozen; - /// that depends on the type! Only those parts outside of an `UnsafeCell` are actually - /// frozen. - Alias(Option), +pub enum Tag { + Tagged(PtrId), + Untagged, } -impl Borrow { - #[inline(always)] - pub fn is_aliasing(self) -> bool { - match self { - Borrow::Alias(_) => true, - _ => false, - } - } - - #[inline(always)] - pub fn is_unique(self) -> bool { +impl fmt::Display for Tag { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { - Borrow::Uniq(_) => true, - _ => false, + Tag::Tagged(id) => write!(f, "{}", id), + Tag::Untagged => write!(f, ""), } } } -impl Default for Borrow { - fn default() -> Self { - Borrow::Alias(None) - } +/// Indicates which permission is granted (by this item to some pointers) +#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] +pub enum Permission { + /// Grants unique mutable access. + Unique, + /// Grants shared mutable access. + SharedReadWrite, + /// Greants shared read-only access. + SharedReadOnly, } /// An item in the per-location borrow stack. #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] -pub enum BorStackItem { - /// Indicates the unique reference that may mutate. - Uniq(Timestamp), - /// Indicates that the location has been mutably shared. Used for raw pointers as - /// well as for unfrozen shared references. - Raw, +pub enum Item { + /// Grants the given permission for pointers with this tag. + Permission(Permission, Tag), /// A barrier, tracking the function it belongs to by its index on the call stack. - FnBarrier(CallId) + FnBarrier(CallId), +} + +impl fmt::Display for Item { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + Item::Permission(perm, tag) => write!(f, "[{:?} for {}]", perm, tag), + Item::FnBarrier(call) => write!(f, "[barrier {}]", call), + } + } } /// Extra per-location state. #[derive(Clone, Debug, PartialEq, Eq)] pub struct Stack { - /// Used as the stack; never empty. - borrows: Vec, - /// A virtual frozen "item" on top of the stack. - frozen_since: Option, + /// Used *mostly* as a stack; never empty. + /// We sometimes push into the middle but never remove from the middle. + /// The same tag may occur multiple times, e.g. from a two-phase borrow. + /// Invariants: + /// * Above a `SharedReadOnly` there can only be barriers and more `SharedReadOnly`. + borrows: Vec, } -impl Stack { - #[inline(always)] - pub fn is_frozen(&self) -> bool { - self.frozen_since.is_some() - } + +/// Extra per-allocation state. +#[derive(Clone, Debug)] +pub struct Stacks { + // Even reading memory can have effects on the stack, so we need a `RefCell` here. + stacks: RefCell>, + // Pointer to global state + global: MemoryState, } -/// Indicates which kind of reference is being used. -#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] -pub enum RefKind { - /// `&mut`. - Unique, - /// `&` without interior mutability. - Frozen, - /// `*` (raw pointer) or `&` to `UnsafeCell`. - Raw, +/// Extra global state, available to the memory access hooks. +#[derive(Debug)] +pub struct GlobalState { + next_ptr_id: PtrId, + next_call_id: CallId, + active_calls: HashSet, } +pub type MemoryState = Rc>; /// Indicates which kind of access is being performed. #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] pub enum AccessKind { Read, - Write, - Dealloc, + Write { dealloc: bool }, } -/// Extra global state in the memory, available to the memory access hooks. -#[derive(Debug)] -pub struct BarrierTracking { - next_id: CallId, - active_calls: HashSet, +// "Fake" constructors +impl AccessKind { + fn write() -> AccessKind { + AccessKind::Write { dealloc: false } + } + + fn dealloc() -> AccessKind { + AccessKind::Write { dealloc: true } + } +} + +impl fmt::Display for AccessKind { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + AccessKind::Read => write!(f, "read"), + AccessKind::Write { dealloc: false } => write!(f, "write"), + AccessKind::Write { dealloc: true } => write!(f, "deallocation"), + } + } +} + +/// Indicates which kind of reference is being created. +/// Used by `reborrow` to compute which permissions to grant to the +/// new pointer. +#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] +pub enum RefKind { + /// `&mut`. + Mutable, + /// `&` with or without interior mutability. + Shared { frozen: bool }, + /// `*` (raw pointer). + Raw, +} + +impl fmt::Display for RefKind { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + RefKind::Mutable => write!(f, "mutable"), + RefKind::Shared { frozen: true } => write!(f, "shared (frozen)"), + RefKind::Shared { frozen: false } => write!(f, "shared (mutable)"), + RefKind::Raw => write!(f, "raw"), + } + } } -pub type MemoryState = Rc>; -impl Default for BarrierTracking { +/// Utilities for initialization and ID generation +impl Default for GlobalState { fn default() -> Self { - BarrierTracking { - next_id: 0, + GlobalState { + next_ptr_id: NonZeroU64::new(1).unwrap(), + next_call_id: 0, active_calls: HashSet::default(), } } } -impl BarrierTracking { +impl GlobalState { + pub fn new_ptr(&mut self) -> PtrId { + let id = self.next_ptr_id; + self.next_ptr_id = NonZeroU64::new(id.get() + 1).unwrap(); + id + } + pub fn new_call(&mut self) -> CallId { - let id = self.next_id; + let id = self.next_call_id; trace!("new_call: Assigning ID {}", id); self.active_calls.insert(id); - self.next_id += 1; + self.next_call_id = id+1; id } @@ -134,272 +179,354 @@ impl BarrierTracking { } } -/// Extra global machine state. -#[derive(Clone, Debug)] -pub struct State { - clock: Timestamp -} - -impl Default for State { - fn default() -> Self { - State { clock: 0 } - } -} +// # Stacked Borrows Core Begin -impl State { - fn increment_clock(&mut self) -> Timestamp { - let val = self.clock; - self.clock = val + 1; - val - } -} - -/// Extra per-allocation state. -#[derive(Clone, Debug)] -pub struct Stacks { - // Even reading memory can have effects on the stack, so we need a `RefCell` here. - stacks: RefCell>, - barrier_tracking: MemoryState, -} - -/// Core per-location operations: deref, access, create. /// We need to make at least the following things true: /// /// U1: After creating a `Uniq`, it is at the top (and unfrozen). /// U2: If the top is `Uniq` (and unfrozen), accesses must be through that `Uniq` or pop it. -/// U3: If an access (deref sufficient?) happens with a `Uniq`, it requires the `Uniq` to be in the stack. +/// U3: If an access happens with a `Uniq`, it requires the `Uniq` to be in the stack. /// /// F1: After creating a `&`, the parts outside `UnsafeCell` are frozen. /// F2: If a write access happens, it unfreezes. -/// F3: If an access (well, a deref) happens with an `&` outside `UnsafeCell`, +/// F3: If an access happens with an `&` outside `UnsafeCell`, /// it requires the location to still be frozen. -impl<'tcx> Stack { - /// Deref `bor`: check if the location is frozen and the tag in the stack. - /// This dos *not* constitute an access! "Deref" refers to the `*` operator - /// in Rust, and includs cases like `&*x` or `(*x).foo` where no or only part - /// of the memory actually gets accessed. Also we cannot know if we are - /// going to read or write. - /// Returns the index of the item we matched, `None` if it was the frozen one. - /// `kind` indicates which kind of reference is being dereferenced. - fn deref( - &self, - bor: Borrow, - kind: RefKind, - ) -> Result, String> { - // Exclude unique ref with frozen tag. - if let (RefKind::Unique, Borrow::Alias(Some(_))) = (kind, bor) { - return Err(format!("encountered mutable reference with frozen tag ({:?})", bor)); + +impl Default for Tag { + #[inline(always)] + fn default() -> Tag { + Tag::Untagged + } +} + +/// Core relations on `Permission` define which accesses are allowed: +/// On every access, we try to find a *granting* item, and then we remove all +/// *incompatible* items above it. +impl Permission { + /// This defines for a given permission, whether it permits the given kind of access. + fn grants(self, access: AccessKind) -> bool { + match (self, access) { + // Unique and SharedReadWrite allow any kind of access. + (Permission::Unique, _) | + (Permission::SharedReadWrite, _) => + true, + // SharedReadOnly only permits read access. + (Permission::SharedReadOnly, AccessKind::Read) => + true, + (Permission::SharedReadOnly, AccessKind::Write { .. }) => + false, } - // Checks related to freezing. - match bor { - Borrow::Alias(Some(bor_t)) if kind == RefKind::Frozen => { - // We need the location to be frozen. This ensures F3. - let frozen = self.frozen_since.map_or(false, |itm_t| itm_t <= bor_t); - return if frozen { Ok(None) } else { - Err(format!("location is not frozen long enough")) - } - } - Borrow::Alias(_) if self.frozen_since.is_some() => { - // Shared deref to frozen location; looking good. - return Ok(None) - } - // Not sufficient; go on looking. - _ => {} + } + + /// This defines for a given permission, which other items it can tolerate "above" itself + /// for which kinds of accesses. + /// If true, then `other` is allowed to remain on top of `self` when `access` happens. + fn compatible_with(self, access: AccessKind, other: Item) -> bool { + use self::Permission::*; + + let other = match other { + Item::Permission(perm, _) => perm, + Item::FnBarrier(_) => return false, // Remove all barriers -- if they are active, cause UB. + }; + + match (self, access, other) { + // Some cases are impossible. + (SharedReadOnly, _, SharedReadWrite) | + (SharedReadOnly, _, Unique) => + bug!("There can never be a SharedReadWrite or a Unique on top of a SharedReadOnly"), + // When `other` is `SharedReadOnly`, that is NEVER compatible with + // write accesses. + // This makes sure read-only pointers become invalid on write accesses. + (_, AccessKind::Write { .. }, SharedReadOnly) => + false, + // When `other` is `Unique`, that is compatible with nothing. + // This makes sure unique pointers become invalid on incompatible accesses (ensures U2). + (_, _, Unique) => + false, + // When we are unique and this is a write/dealloc, we tolerate nothing. + // This makes sure we re-assert uniqueness on write accesses. + // (This is particularily important such that when a new mutable ref gets created, it gets + // pushed into the right item -- this behaves like a write and we assert uniqueness of the + // pointer from which this comes, *if* it was a unique pointer.) + (Unique, AccessKind::Write { .. }, _) => + false, + // `SharedReadWrite` items can tolerate any other akin items for any kind of access. + (SharedReadWrite, _, SharedReadWrite) => + true, + // Any item can tolerate read accesses for shared items. + // This includes unique items! Reads from unique pointers do not invalidate + // other pointers. + (_, AccessKind::Read, SharedReadWrite) | + (_, AccessKind::Read, SharedReadOnly) => + true, + // That's it. } - // If we got here, we have to look for our item in the stack. - for (idx, &itm) in self.borrows.iter().enumerate().rev() { - match (itm, bor) { - (BorStackItem::Uniq(itm_t), Borrow::Uniq(bor_t)) if itm_t == bor_t => { - // Found matching unique item. This satisfies U3. - return Ok(Some(idx)) - } - (BorStackItem::Raw, Borrow::Alias(_)) => { - // Found matching aliasing/raw item. - return Ok(Some(idx)) - } - // Go on looking. We ignore barriers! When an `&mut` and an `&` alias, - // dereferencing the `&` is still possible (to reborrow), but doing - // an access is not. - _ => {} - } + } +} + +impl<'tcx> RefKind { + /// Defines which kind of access the "parent" must grant to create this reference. + fn access(self) -> AccessKind { + match self { + RefKind::Mutable | RefKind::Shared { frozen: false } => AccessKind::write(), + RefKind::Raw | RefKind::Shared { frozen: true } => AccessKind::Read, + // FIXME: Just requiring read-only access for raw means that a raw ptr might not be writeable + // even when we think it should be! Think about this some more. } - // If we got here, we did not find our item. We have to error to satisfy U3. - Err(format!("Borrow being dereferenced ({:?}) does not exist on the borrow stack", bor)) } - /// Performs an actual memory access using `bor`. We do not know any types here - /// or whether things should be frozen, but we *do* know if this is reading - /// or writing. + /// This defines the new permission used when a pointer gets created: For raw pointers, whether these are read-only + /// or read-write depends on the permission from which they derive. + fn new_perm(self, derived_from: Permission) -> EvalResult<'tcx, Permission> { + Ok(match (self, derived_from) { + // Do not derive writable safe pointer from read-only pointer! + (RefKind::Mutable, Permission::SharedReadOnly) => + return err!(MachineError(format!( + "deriving mutable reference from read-only pointer" + ))), + (RefKind::Shared { frozen: false }, Permission::SharedReadOnly) => + return err!(MachineError(format!( + "deriving shared reference with interior mutability from read-only pointer" + ))), + // Safe pointer cases. + (RefKind::Mutable, _) => Permission::Unique, + (RefKind::Shared { frozen: true }, _) => Permission::SharedReadOnly, + (RefKind::Shared { frozen: false }, _) => Permission::SharedReadWrite, + // Raw pointer cases. + (RefKind::Raw, Permission::SharedReadOnly) => Permission::SharedReadOnly, + (RefKind::Raw, _) => Permission::SharedReadWrite, + }) + } +} + +/// Core per-location operations: access, create. +impl<'tcx> Stack { + /// Find the item granting the given kind of access to the given tag, and where that item is in the stack. + fn find_granting(&self, access: AccessKind, tag: Tag) -> Option<(usize, Permission)> { + self.borrows.iter() + .enumerate() // we also need to know *where* in the stack + .rev() // search top-to-bottom + // Return permission of first item that grants access. + .filter_map(|(idx, item)| match item { + &Item::Permission(perm, item_tag) if perm.grants(access) && tag == item_tag => + Some((idx, perm)), + _ => None, + }) + .next() + } + + /// Test if a memory `access` using pointer tagged `tag` is granted. + /// If yes, return the index of the item that granted it. fn access( &mut self, - bor: Borrow, - kind: AccessKind, - barrier_tracking: &BarrierTracking, - ) -> EvalResult<'tcx> { - // Check if we can match the frozen "item". - // Not possible on writes! - if self.is_frozen() { - if kind == AccessKind::Read { - // When we are frozen, we just accept all reads. No harm in this. - // The deref already checked that `Uniq` items are in the stack, and that - // the location is frozen if it should be. - return Ok(()); - } - trace!("access: unfreezing"); - } - // Unfreeze on writes. This ensures F2. - self.frozen_since = None; - // Pop the stack until we have something matching. - while let Some(&itm) = self.borrows.last() { - match (itm, bor) { - (BorStackItem::FnBarrier(call), _) if barrier_tracking.is_active(call) => { - return err!(MachineError(format!( - "stopping looking for borrow being accessed ({:?}) because of barrier ({})", - bor, call - ))) - } - (BorStackItem::Uniq(itm_t), Borrow::Uniq(bor_t)) if itm_t == bor_t => { - // Found matching unique item. Continue after the match. - } - (BorStackItem::Raw, _) if kind == AccessKind::Read => { - // When reading, everything can use a raw item! - // We do not want to do this when writing: Writing to an `&mut` - // should reaffirm its exclusivity (i.e., make sure it is - // on top of the stack). Continue after the match. - } - (BorStackItem::Raw, Borrow::Alias(_)) => { - // Found matching raw item. Continue after the match. - } - _ => { - // Pop this, go on. This ensures U2. - let itm = self.borrows.pop().unwrap(); - trace!("access: Popping {:?}", itm); - continue - } - } - // If we got here, we found a matching item. Congratulations! - // However, we are not done yet: If this access is deallocating, we must make sure - // there are no active barriers remaining on the stack. - if kind == AccessKind::Dealloc { - for &itm in self.borrows.iter().rev() { - match itm { - BorStackItem::FnBarrier(call) if barrier_tracking.is_active(call) => { + access: AccessKind, + tag: Tag, + global: &GlobalState, + ) -> EvalResult<'tcx, usize> { + // Two main steps: Find granting item, remove all incompatible items above. + // Afterwards we just do some post-processing for deallocation accesses. + + // Step 1: Find granting item. + let (granting_idx, granting_perm) = self.find_granting(access, tag) + .ok_or_else(|| InterpError::MachineError(format!( + "no item granting {} access to tag {} found in borrow stack", + access, tag, + )))?; + + // Step 2: Remove everything incompatible above them. + // Implemented with indices because there does not seem to be a nice iterator and range-based + // API for this. + { + let mut cur = granting_idx + 1; + while let Some(item) = self.borrows.get(cur) { + if granting_perm.compatible_with(access, *item) { + // Keep this, check next. + cur += 1; + } else { + // Aha! This is a bad one, remove it, and if it is an *active* barrier + // we have a problem. + match self.borrows.remove(cur) { + Item::FnBarrier(call) if global.is_active(call) => { return err!(MachineError(format!( - "deallocating with active barrier ({})", call - ))) + "not granting access because of barrier ({})", call + ))); } - _ => {}, + _ => {} } } } - // Now we are done. - return Ok(()) } - // If we got here, we did not find our item. - err!(MachineError(format!( - "borrow being accessed ({:?}) does not exist on the borrow stack", - bor - ))) - } - - /// Initiate `bor`; mostly this means pushing. - /// This operation cannot fail; it is up to the caller to ensure that the precondition - /// is met: We cannot push `Uniq` onto frozen stacks. - /// `kind` indicates which kind of reference is being created. - fn create(&mut self, bor: Borrow, kind: RefKind) { - // When creating a frozen reference, freeze. This ensures F1. - // We also do *not* push anything else to the stack, making sure that no nother kind - // of access (like writing through raw pointers) is permitted. - if kind == RefKind::Frozen { - let bor_t = match bor { - Borrow::Alias(Some(t)) => t, - _ => bug!("Creating illegal borrow {:?} for frozen ref", bor), - }; - // It is possible that we already are frozen (e.g., if we just pushed a barrier, - // the redundancy check would not have kicked in). - match self.frozen_since { - Some(loc_t) => assert!( - loc_t <= bor_t, - "trying to freeze location for longer than it was already frozen" - ), - None => { - trace!("create: Freezing"); - self.frozen_since = Some(bor_t); + + // Post-processing. + // If we got here, we found a matching item. Congratulations! + // However, we are not done yet: If this access is deallocating, we must make sure + // there are no active barriers remaining on the stack. + if access == AccessKind::dealloc() { + for &itm in self.borrows.iter().rev() { + match itm { + Item::FnBarrier(call) if global.is_active(call) => { + return err!(MachineError(format!( + "deallocating with active barrier ({})", call + ))) + } + _ => {}, } } - return; } - assert!( - self.frozen_since.is_none(), - "trying to create non-frozen reference to frozen location" - ); - // Push new item to the stack. - let itm = match bor { - Borrow::Uniq(t) => BorStackItem::Uniq(t), - Borrow::Alias(_) => BorStackItem::Raw, - }; - if *self.borrows.last().unwrap() == itm { - // This is just an optimization, no functional change: Avoid stacking - // multiple `Shr` on top of each other. - assert!(bor.is_aliasing()); - trace!("create: sharing a shared location is a NOP"); - } else { - // This ensures U1. - trace!("create: pushing {:?}", itm); - self.borrows.push(itm); + // Done. + return Ok(granting_idx); + } + + /// `reborrow` helper function. + /// Grant `permisson` to new pointer tagged `tag`, added at `position` in the stack. + fn grant(&mut self, perm: Permission, tag: Tag, position: usize) { + // Simply add it to the "stack" -- this might add in the middle. + // As an optimization, do nothing if the new item is identical to one of its neighbors. + let item = Item::Permission(perm, tag); + if self.borrows[position-1] == item || self.borrows.get(position) == Some(&item) { + // Optimization applies, done. + trace!("reborrow: avoiding redundant item {}", item); + return; } + trace!("reborrow: pushing item {}", item); + self.borrows.insert(position, item); } + /// `reborrow` helper function. /// Adds a barrier. fn barrier(&mut self, call: CallId) { - let itm = BorStackItem::FnBarrier(call); + let itm = Item::FnBarrier(call); if *self.borrows.last().unwrap() == itm { // This is just an optimization, no functional change: Avoid stacking // multiple identical barriers on top of each other. // This can happen when a function receives several shared references // that overlap. - trace!("barrier: avoiding redundant extra barrier"); + trace!("reborrow: avoiding redundant extra barrier"); } else { - trace!("barrier: pushing barrier for call {}", call); + trace!("reborrow: pushing barrier for call {}", call); self.borrows.push(itm); } } + + /// `reborrow` helper function: test that the stack invariants are still maintained. + fn test_invariants(&self) { + let mut saw_shared_read_only = false; + for item in self.borrows.iter() { + match item { + Item::Permission(Permission::SharedReadOnly, _) => { + saw_shared_read_only = true; + } + Item::Permission(perm, _) if saw_shared_read_only => { + panic!("Found {:?} on top of a SharedReadOnly!", perm); + } + _ => {} + } + } + } + + /// Derived a new pointer from one with the given tag . + fn reborrow( + &mut self, + derived_from: Tag, + barrier: Option, + new_kind: RefKind, + new_tag: Tag, + global: &GlobalState, + ) -> EvalResult<'tcx> { + // Find the permission "from which we derive". To this end we first have to decide + // if we derive from a permission that grants writes or just reads. + let access = new_kind.access(); + let (derived_from_idx, derived_from_perm) = self.find_granting(access, derived_from) + .ok_or_else(|| InterpError::MachineError(format!( + "no item to reborrow as {} from tag {} found in borrow stack", new_kind, derived_from, + )))?; + // With this we can compute the permission for the new pointer. + let new_perm = new_kind.new_perm(derived_from_perm)?; + + // We behave very differently for the "unsafe" case of a shared-read-write pointer + // ("unsafe" because this also applies to shared references with interior mutability). + // This is because such pointers may be reborrowed to unique pointers that actually + // remain valid when their "parents" get further reborrows! + if new_perm == Permission::SharedReadWrite { + // A very liberal reborrow because the new pointer does not expect any kind of aliasing guarantee. + // Just insert new permission as child of old permission, and maintain everything else. + // This inserts "as far down as possible", which is good because it makes this pointer as + // long-lived as possible *and* we want all the items that are incompatible with this + // to actually get removed from the stack. If we pushed a `SharedReadWrite` on top of + // a `SharedReadOnly`, we'd violate the invariant that `SaredReadOnly` are at the top + // and we'd allow write access without invalidating frozen shared references! + self.grant(new_perm, new_tag, derived_from_idx+1); + + // No barrier. They can rightfully alias with `&mut`. + // FIXME: This means that the `dereferencable` attribute on non-frozen shared references + // is incorrect! They are dereferencable when the function is called, but might become + // non-dereferencable during the course of execution. + // Also see [1], [2]. + // + // [1]: , + // [2]: + } else { + // A "safe" reborrow for a pointer that actually expects some aliasing guarantees. + // Here, creating a reference actually counts as an access, and pops incompatible + // stuff off the stack. + let check_idx = self.access(access, derived_from, global)?; + assert_eq!(check_idx, derived_from_idx, "somehow we saw different items??"); + + // Now is a good time to add the barrier. + if let Some(call) = barrier { + self.barrier(call); + } + + // We insert "as far up as possible": We know only compatible items are remaining + // on top of `derived_from`, and we want the new item at the top so that we + // get the strongest possible guarantees. + self.grant(new_perm, new_tag, self.borrows.len()); + } + + // Make sure that after all this, the stack's invariant is still maintained. + if cfg!(debug_assertions) { + self.test_invariants(); + } + + Ok(()) + } } /// Higher-level per-location operations: deref, access, reborrow. impl<'tcx> Stacks { - /// Checks that this stack is fine with being dereferenced. - fn deref( - &self, - ptr: Pointer, + /// Creates new stack with initial tag. + pub(crate) fn new( size: Size, - kind: RefKind, - ) -> EvalResult<'tcx> { - trace!("deref for tag {:?} as {:?}: {:?}, size {}", - ptr.tag, kind, ptr, size.bytes()); - let stacks = self.stacks.borrow(); - for stack in stacks.iter(ptr.offset, size) { - stack.deref(ptr.tag, kind).map_err(InterpError::MachineError)?; + tag: Tag, + extra: MemoryState, + ) -> Self { + let item = Item::Permission(Permission::Unique, tag); + let stack = Stack { + borrows: vec![item], + }; + Stacks { + stacks: RefCell::new(RangeMap::new(size, stack)), + global: extra, } - Ok(()) } /// `ptr` got used, reflect that in the stack. fn access( &self, - ptr: Pointer, + ptr: Pointer, size: Size, kind: AccessKind, ) -> EvalResult<'tcx> { - trace!("{:?} access of tag {:?}: {:?}, size {}", kind, ptr.tag, ptr, size.bytes()); + trace!("{} access of tag {}: {:?}, size {}", kind, ptr.tag, ptr, size.bytes()); // Even reads can have a side-effect, by invalidating other references. // This is fundamentally necessary since `&mut` asserts that there // are no accesses through other references, not even reads. - let barrier_tracking = self.barrier_tracking.borrow(); + let global = self.global.borrow(); let mut stacks = self.stacks.borrow_mut(); for stack in stacks.iter_mut(ptr.offset, size) { - stack.access(ptr.tag, kind, &*barrier_tracking)?; + stack.access(kind, ptr.tag, &*global)?; } Ok(()) } @@ -408,86 +535,61 @@ impl<'tcx> Stacks { /// This works on `&self` because we might encounter references to constant memory. fn reborrow( &self, - ptr: Pointer, + ptr: Pointer, size: Size, - mut barrier: Option, - new_bor: Borrow, + barrier: Option, new_kind: RefKind, + new_tag: Tag, ) -> EvalResult<'tcx> { - assert_eq!(new_bor.is_unique(), new_kind == RefKind::Unique); trace!( - "reborrow for tag {:?} to {:?} as {:?}: {:?}, size {}", - ptr.tag, new_bor, new_kind, ptr, size.bytes(), + "{} reborrow for tag {} to {}: {:?}, size {}", + new_kind, ptr.tag, new_tag, ptr, size.bytes(), ); - if new_kind == RefKind::Raw { - // No barrier for raw, including `&UnsafeCell`. They can rightfully alias with `&mut`. - // FIXME: This means that the `dereferencable` attribute on non-frozen shared references - // is incorrect! They are dereferencable when the function is called, but might become - // non-dereferencable during the course of execution. - // Also see [1], [2]. - // - // [1]: , - // [2]: - barrier = None; - } - let barrier_tracking = self.barrier_tracking.borrow(); + let global = self.global.borrow(); let mut stacks = self.stacks.borrow_mut(); for stack in stacks.iter_mut(ptr.offset, size) { - // Access source `ptr`, create new ref. - let ptr_idx = stack.deref(ptr.tag, new_kind).map_err(InterpError::MachineError)?; - // If we can deref the new tag already, and if that tag lives higher on - // the stack than the one we come from, just use that. - // That is, we check if `new_bor` *already* is "derived from" `ptr.tag`. - // This also checks frozenness, if required. - let bor_redundant = barrier.is_none() && - match (ptr_idx, stack.deref(new_bor, new_kind)) { - // If the new borrow works with the frozen item, or else if it lives - // above the old one in the stack, our job here is done. - (_, Ok(None)) => true, - (Some(ptr_idx), Ok(Some(new_idx))) if new_idx >= ptr_idx => true, - // Otherwise, we need to create a new borrow. - _ => false, - }; - if bor_redundant { - assert!(new_bor.is_aliasing(), "a unique reborrow can never be redundant"); - trace!("reborrow is redundant"); - continue; - } - // We need to do some actual work. - let access_kind = if new_kind == RefKind::Unique { - AccessKind::Write - } else { - AccessKind::Read - }; - stack.access(ptr.tag, access_kind, &*barrier_tracking)?; - if let Some(call) = barrier { - stack.barrier(call); - } - stack.create(new_bor, new_kind); + stack.reborrow(ptr.tag, barrier, new_kind, new_tag, &*global)?; } Ok(()) } } -/// Hooks and glue. -impl AllocationExtra for Stacks { - #[inline(always)] - fn memory_allocated<'tcx>(size: Size, extra: &MemoryState) -> Self { - let stack = Stack { - borrows: vec![BorStackItem::Raw], - frozen_since: None, +// # Stacked Borrows Core End + +// Glue code to connect with Miri Machine Hooks + +impl Stacks { + pub fn new_allocation( + size: Size, + extra: &MemoryState, + kind: MemoryKind, + ) -> (Self, Tag) { + let tag = match kind { + MemoryKind::Stack => { + // New unique borrow. This `Uniq` is not accessible by the program, + // so it will only ever be used when using the local directly (i.e., + // not through a pointer). That is, whenever we directly use a local, this will pop + // everything else off the stack, invalidating all previous pointers, + // and in particular, *all* raw pointers. This subsumes the explicit + // `reset` which the blog post [1] says to perform when accessing a local. + // + // [1]: + Tag::Tagged(extra.borrow_mut().new_ptr()) + } + _ => { + Tag::Untagged + } }; - Stacks { - stacks: RefCell::new(RangeMap::new(size, stack)), - barrier_tracking: Rc::clone(extra), - } + let stack = Stacks::new(size, tag, Rc::clone(extra)); + (stack, tag) } +} +impl AllocationExtra for Stacks { #[inline(always)] fn memory_read<'tcx>( - alloc: &Allocation, - ptr: Pointer, + alloc: &Allocation, + ptr: Pointer, size: Size, ) -> EvalResult<'tcx> { alloc.extra.access(ptr, size, AccessKind::Read) @@ -495,35 +597,20 @@ impl AllocationExtra for Stacks { #[inline(always)] fn memory_written<'tcx>( - alloc: &mut Allocation, - ptr: Pointer, + alloc: &mut Allocation, + ptr: Pointer, size: Size, ) -> EvalResult<'tcx> { - alloc.extra.access(ptr, size, AccessKind::Write) + alloc.extra.access(ptr, size, AccessKind::write()) } #[inline(always)] fn memory_deallocated<'tcx>( - alloc: &mut Allocation, - ptr: Pointer, + alloc: &mut Allocation, + ptr: Pointer, size: Size, ) -> EvalResult<'tcx> { - alloc.extra.access(ptr, size, AccessKind::Dealloc) - } -} - -impl<'tcx> Stacks { - /// Pushes the first item to the stacks. - pub(crate) fn first_item( - &mut self, - itm: BorStackItem, - size: Size - ) { - for stack in self.stacks.get_mut().iter_mut(Size::ZERO, size) { - assert!(stack.borrows.len() == 1); - assert_eq!(stack.borrows.pop().unwrap(), BorStackItem::Raw); - stack.borrows.push(itm); - } + alloc.extra.access(ptr, size, AccessKind::dealloc()) } } @@ -531,31 +618,32 @@ impl<'a, 'mir, 'tcx> EvalContextPrivExt<'a, 'mir, 'tcx> for crate::MiriEvalConte trait EvalContextPrivExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, 'mir, 'tcx> { fn reborrow( &mut self, - place: MPlaceTy<'tcx, Borrow>, + place: MPlaceTy<'tcx, Tag>, size: Size, + mutbl: Option, + new_tag: Tag, fn_barrier: bool, - new_bor: Borrow ) -> EvalResult<'tcx> { let this = self.eval_context_mut(); - let ptr = place.ptr.to_ptr()?; let barrier = if fn_barrier { Some(this.frame().extra) } else { None }; + let ptr = place.ptr.to_ptr()?; trace!("reborrow: creating new reference for {:?} (pointee {}): {:?}", - ptr, place.layout.ty, new_bor); + ptr, place.layout.ty, new_tag); // Get the allocation. It might not be mutable, so we cannot use `get_mut`. let alloc = this.memory().get(ptr.alloc_id)?; alloc.check_bounds(this, ptr, size)?; // Update the stacks. - if let Borrow::Alias(Some(_)) = new_bor { + if mutbl == Some(MutImmutable) { // Reference that cares about freezing. We need a frozen-sensitive reborrow. this.visit_freeze_sensitive(place, size, |cur_ptr, size, frozen| { - let kind = if frozen { RefKind::Frozen } else { RefKind::Raw }; - alloc.extra.reborrow(cur_ptr, size, barrier, new_bor, kind) + let new_kind = RefKind::Shared { frozen }; + alloc.extra.reborrow(cur_ptr, size, barrier, new_kind, new_tag) })?; } else { // Just treat this as one big chunk. - let kind = if new_bor.is_unique() { RefKind::Unique } else { RefKind::Raw }; - alloc.extra.reborrow(ptr, size, barrier, new_bor, kind)?; + let new_kind = if mutbl == Some(MutMutable) { RefKind::Mutable } else { RefKind::Raw }; + alloc.extra.reborrow(ptr, size, barrier, new_kind, new_tag)?; } Ok(()) } @@ -564,11 +652,11 @@ trait EvalContextPrivExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, /// `mutbl` can be `None` to make this a raw pointer. fn retag_reference( &mut self, - val: ImmTy<'tcx, Borrow>, + val: ImmTy<'tcx, Tag>, mutbl: Option, fn_barrier: bool, two_phase: bool, - ) -> EvalResult<'tcx, Immediate> { + ) -> EvalResult<'tcx, Immediate> { let this = self.eval_context_mut(); // We want a place for where the ptr *points to*, so we get one. let place = this.ref_to_mplace(val)?; @@ -581,23 +669,24 @@ trait EvalContextPrivExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, } // Compute new borrow. - let time = this.machine.stacked_borrows.increment_clock(); - let new_bor = match mutbl { - Some(MutMutable) => Borrow::Uniq(time), - Some(MutImmutable) => Borrow::Alias(Some(time)), - None => Borrow::default(), + let new_tag = match mutbl { + Some(_) => Tag::Tagged(this.memory().extra.borrow_mut().new_ptr()), + None => Tag::Untagged, }; // Reborrow. - this.reborrow(place, size, fn_barrier, new_bor)?; - let new_place = place.with_tag(new_bor); + this.reborrow(place, size, mutbl, new_tag, fn_barrier)?; + let new_place = place.replace_tag(new_tag); // Handle two-phase borrows. if two_phase { assert!(mutbl == Some(MutMutable), "two-phase shared borrows make no sense"); - // We immediately share it, to allow read accesses - let two_phase_time = this.machine.stacked_borrows.increment_clock(); - let two_phase_bor = Borrow::Alias(Some(two_phase_time)); - this.reborrow(new_place, size, false /* fn_barrier */, two_phase_bor)?; + // Grant read access *to the parent pointer* with the old tag. This means the same pointer + // has multiple items in the stack now! + // FIXME: Think about this some more, in particular about the interaction with cast-to-raw. + // Maybe find a better way to express 2-phase, now that we have a "more expressive language" + // in the stack. + let old_tag = place.ptr.to_ptr().unwrap().tag; + this.reborrow(new_place, size, Some(MutImmutable), old_tag, /* fn_barrier: */ false)?; } // Return new pointer. @@ -607,90 +696,10 @@ trait EvalContextPrivExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, impl<'a, 'mir, 'tcx> EvalContextExt<'a, 'mir, 'tcx> for crate::MiriEvalContext<'a, 'mir, 'tcx> {} pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, 'mir, 'tcx> { - fn tag_new_allocation( - &mut self, - id: AllocId, - kind: MemoryKind, - ) -> Borrow { - let this = self.eval_context_mut(); - let time = match kind { - MemoryKind::Stack => { - // New unique borrow. This `Uniq` is not accessible by the program, - // so it will only ever be used when using the local directly (i.e., - // not through a pointer). That is, whenever we directly use a local, this will pop - // everything else off the stack, invalidating all previous pointers, - // and in particular, *all* raw pointers. This subsumes the explicit - // `reset` which the blog post [1] says to perform when accessing a local. - // - // [1]: - this.machine.stacked_borrows.increment_clock() - } - _ => { - // Nothing to do for everything else. - return Borrow::default() - } - }; - // Make this the active borrow for this allocation. - let alloc = this - .memory_mut() - .get_mut(id) - .expect("this is a new allocation; it must still exist"); - let size = Size::from_bytes(alloc.bytes.len() as u64); - alloc.extra.first_item(BorStackItem::Uniq(time), size); - Borrow::Uniq(time) - } - - /// Called for value-to-place conversion. `mutability` is `None` for raw pointers. - /// - /// Note that this does *not* mean that all this memory will actually get accessed/referenced! - /// We could be in the middle of `&(*var).1`. - fn ptr_dereference( - &self, - place: MPlaceTy<'tcx, Borrow>, - size: Size, - mutability: Option, - ) -> EvalResult<'tcx> { - let this = self.eval_context_ref(); - trace!( - "ptr_dereference: Accessing {} reference for {:?} (pointee {})", - if let Some(mutability) = mutability { - format!("{:?}", mutability) - } else { - format!("raw") - }, - place.ptr, place.layout.ty - ); - let ptr = place.ptr.to_ptr()?; - if mutability.is_none() { - // No further checks on raw derefs -- only the access itself will be checked. - return Ok(()); - } - - // Get the allocation - let alloc = this.memory().get(ptr.alloc_id)?; - alloc.check_bounds(this, ptr, size)?; - // If we got here, we do some checking, *but* we leave the tag unchanged. - if let Borrow::Alias(Some(_)) = ptr.tag { - assert_eq!(mutability, Some(MutImmutable)); - // We need a frozen-sensitive check. - this.visit_freeze_sensitive(place, size, |cur_ptr, size, frozen| { - let kind = if frozen { RefKind::Frozen } else { RefKind::Raw }; - alloc.extra.deref(cur_ptr, size, kind) - })?; - } else { - // Just treat this as one big chunk. - let kind = if mutability == Some(MutMutable) { RefKind::Unique } else { RefKind::Raw }; - alloc.extra.deref(ptr, size, kind)?; - } - - // All is good. - Ok(()) - } - fn retag( &mut self, kind: RetagKind, - place: PlaceTy<'tcx, Borrow> + place: PlaceTy<'tcx, Tag> ) -> EvalResult<'tcx> { let this = self.eval_context_mut(); // Determine mutability and whether to add a barrier. @@ -734,7 +743,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, for RetagVisitor<'ecx, 'a, 'mir, 'tcx> { - type V = MPlaceTy<'tcx, Borrow>; + type V = MPlaceTy<'tcx, Tag>; #[inline(always)] fn ecx(&mut self) -> &mut MiriEvalContext<'a, 'mir, 'tcx> { @@ -742,7 +751,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, } // Primitives of reference type, that is the one thing we are interested in. - fn visit_primitive(&mut self, place: MPlaceTy<'tcx, Borrow>) -> EvalResult<'tcx> + fn visit_primitive(&mut self, place: MPlaceTy<'tcx, Tag>) -> EvalResult<'tcx> { // Cannot use `builtin_deref` because that reports *immutable* for `Box`, // making it useless. diff --git a/src/tls.rs b/src/tls.rs index 992e4fd056190..9346fba0dcc4b 100644 --- a/src/tls.rs +++ b/src/tls.rs @@ -5,14 +5,14 @@ use rustc::{ty, ty::layout::HasDataLayout, mir}; use crate::{ EvalResult, InterpError, StackPopCleanup, - MPlaceTy, Scalar, Borrow, + MPlaceTy, Scalar, Tag, }; pub type TlsKey = u128; #[derive(Copy, Clone, Debug)] pub struct TlsEntry<'tcx> { - pub(crate) data: Scalar, // Will eventually become a map from thread IDs to `Scalar`s, if we ever support more than one thread. + pub(crate) data: Scalar, // Will eventually become a map from thread IDs to `Scalar`s, if we ever support more than one thread. pub(crate) dtor: Option>, } @@ -63,7 +63,7 @@ impl<'tcx> TlsData<'tcx> { } } - pub fn load_tls(&mut self, key: TlsKey) -> EvalResult<'tcx, Scalar> { + pub fn load_tls(&mut self, key: TlsKey) -> EvalResult<'tcx, Scalar> { match self.keys.get(&key) { Some(&TlsEntry { data, .. }) => { trace!("TLS key {} loaded: {:?}", key, data); @@ -73,7 +73,7 @@ impl<'tcx> TlsData<'tcx> { } } - pub fn store_tls(&mut self, key: TlsKey, new_data: Scalar) -> EvalResult<'tcx> { + pub fn store_tls(&mut self, key: TlsKey, new_data: Scalar) -> EvalResult<'tcx> { match self.keys.get_mut(&key) { Some(&mut TlsEntry { ref mut data, .. }) => { trace!("TLS key {} stored: {:?}", key, new_data); @@ -106,7 +106,7 @@ impl<'tcx> TlsData<'tcx> { &mut self, key: Option, cx: &impl HasDataLayout, - ) -> Option<(ty::Instance<'tcx>, Scalar, TlsKey)> { + ) -> Option<(ty::Instance<'tcx>, Scalar, TlsKey)> { use std::collections::Bound::*; let thread_local = &mut self.keys; From 966d638760d391db49e691479cb06062a19add0e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 15 Apr 2019 17:06:42 +0200 Subject: [PATCH 0680/3747] make run-pass tests pass. tweak how we remove barriers. --- src/stacked_borrows.rs | 85 ++++++++++++++++++---------- tests/run-pass/2phase.rs | 7 +-- tests/run-pass/ptr_arith_offset.rs | 2 +- tests/run-pass/ptr_offset.rs | 2 +- tests/run-pass/regions-mock-trans.rs | 4 +- 5 files changed, 61 insertions(+), 39 deletions(-) diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 080200b12a4ea..c55ebecea71d6 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -183,14 +183,17 @@ impl GlobalState { /// We need to make at least the following things true: /// -/// U1: After creating a `Uniq`, it is at the top (and unfrozen). -/// U2: If the top is `Uniq` (and unfrozen), accesses must be through that `Uniq` or pop it. +/// U1: After creating a `Uniq`, it is at the top. +/// U2: If the top is `Uniq`, accesses must be through that `Uniq` or remove it it. /// U3: If an access happens with a `Uniq`, it requires the `Uniq` to be in the stack. /// -/// F1: After creating a `&`, the parts outside `UnsafeCell` are frozen. -/// F2: If a write access happens, it unfreezes. +/// F1: After creating a `&`, the parts outside `UnsafeCell` have our `SharedReadOnly` on top. +/// F2: If a write access happens, it pops the `SharedReadOnly`. This has three pieces: +/// F2a: If a write happens granted by an item below our `SharedReadOnly`, the `SharedReadOnly` +/// gets popped. +/// F2b: No `SharedReadWrite` or `Unique` will ever be added on top of our `SharedReadOnly`. /// F3: If an access happens with an `&` outside `UnsafeCell`, -/// it requires the location to still be frozen. +/// it requires the `SharedReadOnly` to still be in the stack. impl Default for Tag { #[inline(always)] @@ -218,17 +221,12 @@ impl Permission { } } - /// This defines for a given permission, which other items it can tolerate "above" itself + /// This defines for a given permission, which other permissions it can tolerate "above" itself /// for which kinds of accesses. /// If true, then `other` is allowed to remain on top of `self` when `access` happens. - fn compatible_with(self, access: AccessKind, other: Item) -> bool { + fn compatible_with(self, access: AccessKind, other: Permission) -> bool { use self::Permission::*; - let other = match other { - Item::Permission(perm, _) => perm, - Item::FnBarrier(_) => return false, // Remove all barriers -- if they are active, cause UB. - }; - match (self, access, other) { // Some cases are impossible. (SharedReadOnly, _, SharedReadWrite) | @@ -236,7 +234,7 @@ impl Permission { bug!("There can never be a SharedReadWrite or a Unique on top of a SharedReadOnly"), // When `other` is `SharedReadOnly`, that is NEVER compatible with // write accesses. - // This makes sure read-only pointers become invalid on write accesses. + // This makes sure read-only pointers become invalid on write accesses (ensures F2a). (_, AccessKind::Write { .. }, SharedReadOnly) => false, // When `other` is `Unique`, that is compatible with nothing. @@ -244,7 +242,7 @@ impl Permission { (_, _, Unique) => false, // When we are unique and this is a write/dealloc, we tolerate nothing. - // This makes sure we re-assert uniqueness on write accesses. + // This makes sure we re-assert uniqueness ("being on top") on write accesses. // (This is particularily important such that when a new mutable ref gets created, it gets // pushed into the right item -- this behaves like a write and we assert uniqueness of the // pointer from which this comes, *if* it was a unique pointer.) @@ -307,6 +305,7 @@ impl<'tcx> Stack { .enumerate() // we also need to know *where* in the stack .rev() // search top-to-bottom // Return permission of first item that grants access. + // We require a permission with the right tag, ensuring U3 and F3. .filter_map(|(idx, item)| match item { &Item::Permission(perm, item_tag) if perm.grants(access) && tag == item_tag => Some((idx, perm)), @@ -324,6 +323,9 @@ impl<'tcx> Stack { global: &GlobalState, ) -> EvalResult<'tcx, usize> { // Two main steps: Find granting item, remove all incompatible items above. + // The second step is where barriers get implemented: they "protect" the items + // below them, meaning that if we remove an item and then further up encounter a barrier, + // we raise an error. // Afterwards we just do some post-processing for deallocation accesses. // Step 1: Find granting item. @@ -338,20 +340,35 @@ impl<'tcx> Stack { // API for this. { let mut cur = granting_idx + 1; + let mut removed_item = None; while let Some(item) = self.borrows.get(cur) { - if granting_perm.compatible_with(access, *item) { - // Keep this, check next. - cur += 1; - } else { - // Aha! This is a bad one, remove it, and if it is an *active* barrier - // we have a problem. - match self.borrows.remove(cur) { - Item::FnBarrier(call) if global.is_active(call) => { + match *item { + Item::Permission(perm, _) => { + if granting_perm.compatible_with(access, perm) { + // Keep this, check next. + cur += 1; + } else { + // Aha! This is a bad one, remove it. + let item = self.borrows.remove(cur); + trace!("access: popping item {}", item); + removed_item = Some(item); + } + } + Item::FnBarrier(call) if !global.is_active(call) => { + // An inactive barrier, just get rid of it. (Housekeeping.) + self.borrows.remove(cur); + } + Item::FnBarrier(call) => { + // We hit an active barrier! If we have already removed an item, + // we got a problem! The barrier was supposed to protect this item. + if let Some(removed_item) = removed_item { return err!(MachineError(format!( - "not granting access because of barrier ({})", call - ))); + "not granting {} access to tag {} because barrier ({}) protects incompatible item {}", + access, tag, call, removed_item + ))); } - _ => {} + // Keep this, check next. + cur += 1; } } } @@ -425,7 +442,7 @@ impl<'tcx> Stack { } } - /// Derived a new pointer from one with the given tag . + /// Derived a new pointer from one with the given tag. fn reborrow( &mut self, derived_from: Tag, @@ -448,6 +465,8 @@ impl<'tcx> Stack { // ("unsafe" because this also applies to shared references with interior mutability). // This is because such pointers may be reborrowed to unique pointers that actually // remain valid when their "parents" get further reborrows! + // However, either way, we ensure that we insert the new item in a way that between + // `derived_from` and the new one, there are only items *compatible with* `derived_from`. if new_perm == Permission::SharedReadWrite { // A very liberal reborrow because the new pointer does not expect any kind of aliasing guarantee. // Just insert new permission as child of old permission, and maintain everything else. @@ -456,6 +475,8 @@ impl<'tcx> Stack { // to actually get removed from the stack. If we pushed a `SharedReadWrite` on top of // a `SharedReadOnly`, we'd violate the invariant that `SaredReadOnly` are at the top // and we'd allow write access without invalidating frozen shared references! + // This ensures F2b for `SharedReadWrite` by adding the new item below any + // potentially existing `SharedReadOnly`. self.grant(new_perm, new_tag, derived_from_idx+1); // No barrier. They can rightfully alias with `&mut`. @@ -471,18 +492,20 @@ impl<'tcx> Stack { // A "safe" reborrow for a pointer that actually expects some aliasing guarantees. // Here, creating a reference actually counts as an access, and pops incompatible // stuff off the stack. + // This ensures F2b for `Unique`, by removing offending `SharedReadOnly`. let check_idx = self.access(access, derived_from, global)?; assert_eq!(check_idx, derived_from_idx, "somehow we saw different items??"); - // Now is a good time to add the barrier. - if let Some(call) = barrier { - self.barrier(call); - } - // We insert "as far up as possible": We know only compatible items are remaining // on top of `derived_from`, and we want the new item at the top so that we // get the strongest possible guarantees. + // This ensures U1 and F1. self.grant(new_perm, new_tag, self.borrows.len()); + + // Now is a good time to add the barrier, protecting the item we just added. + if let Some(call) = barrier { + self.barrier(call); + } } // Make sure that after all this, the stack's invariant is still maintained. diff --git a/tests/run-pass/2phase.rs b/tests/run-pass/2phase.rs index 57f3631143706..78ddf566a9d39 100644 --- a/tests/run-pass/2phase.rs +++ b/tests/run-pass/2phase.rs @@ -51,14 +51,13 @@ fn with_interior_mutability() { impl Thing for Cell {} let mut x = Cell::new(1); - let l = &x; + //let l = &x; - #[allow(unknown_lints, mutable_borrow_reservation_conflict)] x .do_the_thing({ x.set(3); - l.set(4); - x.get() + l.get() + // l.set(4); // FIXME: Enable this as an example of overlapping 2PB! + x.get() // FIXME same: + l.get() }) ; } diff --git a/tests/run-pass/ptr_arith_offset.rs b/tests/run-pass/ptr_arith_offset.rs index 7912da9fd437c..a6ee151e3e13b 100644 --- a/tests/run-pass/ptr_arith_offset.rs +++ b/tests/run-pass/ptr_arith_offset.rs @@ -1,6 +1,6 @@ fn main() { let v = [1i16, 2]; - let x = &v as *const i16; + let x = &v as *const [i16] as *const i16; let x = x.wrapping_offset(1); assert_eq!(unsafe { *x }, 2); } diff --git a/tests/run-pass/ptr_offset.rs b/tests/run-pass/ptr_offset.rs index 9e2e26fad3654..1c7f0eb717974 100644 --- a/tests/run-pass/ptr_offset.rs +++ b/tests/run-pass/ptr_offset.rs @@ -2,7 +2,7 @@ fn f() -> i32 { 42 } fn main() { let v = [1i16, 2]; - let x = &v as *const i16; + let x = &v as *const [i16; 2] as *const i16; let x = unsafe { x.offset(1) }; assert_eq!(unsafe { *x }, 2); diff --git a/tests/run-pass/regions-mock-trans.rs b/tests/run-pass/regions-mock-trans.rs index ac8a1c04fbe4f..020ed4927a88b 100644 --- a/tests/run-pass/regions-mock-trans.rs +++ b/tests/run-pass/regions-mock-trans.rs @@ -22,14 +22,14 @@ struct Ccx { x: isize } -fn alloc<'a>(_bcx : &'a Arena) -> &'a Bcx<'a> { +fn alloc<'a>(_bcx : &'a Arena) -> &'a mut Bcx<'a> { unsafe { mem::transmute(libc::malloc(mem::size_of::>() as libc::size_t)) } } -fn h<'a>(bcx : &'a Bcx<'a>) -> &'a Bcx<'a> { +fn h<'a>(bcx : &'a Bcx<'a>) -> &'a mut Bcx<'a> { return alloc(bcx.fcx.arena); } From a6d377ca0b883355b40a2aff9d29fde195dd0a20 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 16 Apr 2019 15:26:21 +0200 Subject: [PATCH 0681/3747] more comments --- src/stacked_borrows.rs | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index c55ebecea71d6..40cbf92e96553 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -334,11 +334,17 @@ impl<'tcx> Stack { "no item granting {} access to tag {} found in borrow stack", access, tag, )))?; - + // Step 2: Remove everything incompatible above them. - // Implemented with indices because there does not seem to be a nice iterator and range-based - // API for this. + // Items below an active barrier however may not be removed, so we check that as well. + // We do *not* maintain a stack discipline here. We could, in principle, decide to only + // keep the items immediately above `granting_idx` that are compatible, and then pop the rest. + // However, that kills off entire "branches" of pointer derivation too easily: + // in `let raw = &mut *x as *mut _; let _val = *x;`, the second statement would pop the `Unique` + // from the reborrow of the first statement, and subequently also pop the `SharedReadWrite` for `raw`. { + // Implemented with indices because there does not seem to be a nice iterator and range-based + // API for this. let mut cur = granting_idx + 1; let mut removed_item = None; while let Some(item) = self.borrows.get(cur) { @@ -454,6 +460,14 @@ impl<'tcx> Stack { // Find the permission "from which we derive". To this end we first have to decide // if we derive from a permission that grants writes or just reads. let access = new_kind.access(); + // Now we figure out which item grants our parent (`derived_from`) permission. + // We use that to determine (a) where to put the new item, and for raw pointers + // (b) whether to given read-only or read-write access. + // FIXME: This handling of raw pointers is fragile, very fragile. What if we do + // not get "the right one", like when there are multiple items granting `derived_from` + // and we accidentally create a read-only pointer? This can happen for two-phase borrows + // (then there's a `Unique` and a `SharedReadOnly` for the same tag), and for raw pointers + // (which currently all are `Untagged`). let (derived_from_idx, derived_from_perm) = self.find_granting(access, derived_from) .ok_or_else(|| InterpError::MachineError(format!( "no item to reborrow as {} from tag {} found in borrow stack", new_kind, derived_from, From ef52be031ca7a75863b937e68799de66557563ce Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 16 Apr 2019 17:17:28 +0200 Subject: [PATCH 0682/3747] adjust compile-fail error messages This also passes miri-test-libstd! --- .../compile-fail/stacked_borrows/alias_through_mutation.rs | 2 +- tests/compile-fail/stacked_borrows/aliasing_mut3.rs | 2 +- .../stacked_borrows/box_exclusive_violation1.rs | 2 +- tests/compile-fail/stacked_borrows/buggy_as_mut_slice.rs | 2 +- tests/compile-fail/stacked_borrows/buggy_split_at_mut.rs | 2 +- tests/compile-fail/stacked_borrows/illegal_read1.rs | 2 +- tests/compile-fail/stacked_borrows/illegal_read2.rs | 2 +- tests/compile-fail/stacked_borrows/illegal_read3.rs | 2 +- tests/compile-fail/stacked_borrows/illegal_read4.rs | 2 +- tests/compile-fail/stacked_borrows/illegal_read5.rs | 2 +- tests/compile-fail/stacked_borrows/illegal_write1.rs | 2 +- tests/compile-fail/stacked_borrows/illegal_write2.rs | 2 +- tests/compile-fail/stacked_borrows/illegal_write3.rs | 2 +- tests/compile-fail/stacked_borrows/illegal_write4.rs | 2 +- tests/compile-fail/stacked_borrows/illegal_write5.rs | 2 +- tests/compile-fail/stacked_borrows/load_invalid_mut.rs | 2 +- tests/compile-fail/stacked_borrows/load_invalid_shr.rs | 2 +- .../stacked_borrows/mut_exclusive_violation1.rs | 2 +- tests/compile-fail/stacked_borrows/outdated_local.rs | 2 +- tests/compile-fail/stacked_borrows/pass_invalid_mut.rs | 2 +- tests/compile-fail/stacked_borrows/pass_invalid_shr.rs | 2 +- tests/compile-fail/stacked_borrows/pointer_smuggling.rs | 2 +- tests/compile-fail/stacked_borrows/return_invalid_mut.rs | 2 +- .../stacked_borrows/return_invalid_mut_option.rs | 2 +- .../stacked_borrows/return_invalid_mut_tuple.rs | 2 +- tests/compile-fail/stacked_borrows/return_invalid_shr.rs | 2 +- .../stacked_borrows/return_invalid_shr_option.rs | 2 +- .../stacked_borrows/return_invalid_shr_tuple.rs | 2 +- .../compile-fail/stacked_borrows/shr_frozen_violation1.rs | 7 ++----- .../stacked_borrows/static_memory_modification.rs | 2 +- .../compile-fail/stacked_borrows/transmute-is-no-escape.rs | 2 +- tests/compile-fail/stacked_borrows/unescaped_local.rs | 2 +- 32 files changed, 33 insertions(+), 36 deletions(-) diff --git a/tests/compile-fail/stacked_borrows/alias_through_mutation.rs b/tests/compile-fail/stacked_borrows/alias_through_mutation.rs index 30f5921202c3f..4a153d74ffb0b 100644 --- a/tests/compile-fail/stacked_borrows/alias_through_mutation.rs +++ b/tests/compile-fail/stacked_borrows/alias_through_mutation.rs @@ -9,5 +9,5 @@ fn main() { retarget(&mut target_alias, target); // now `target_alias` points to the same thing as `target` *target = 13; - let _val = *target_alias; //~ ERROR does not exist on the borrow stack + let _val = *target_alias; //~ ERROR borrow stack } diff --git a/tests/compile-fail/stacked_borrows/aliasing_mut3.rs b/tests/compile-fail/stacked_borrows/aliasing_mut3.rs index e3c59d1566142..3943e9576158c 100644 --- a/tests/compile-fail/stacked_borrows/aliasing_mut3.rs +++ b/tests/compile-fail/stacked_borrows/aliasing_mut3.rs @@ -1,6 +1,6 @@ use std::mem; -pub fn safe(_x: &mut i32, _y: &i32) {} //~ ERROR does not exist on the borrow stack +pub fn safe(_x: &mut i32, _y: &i32) {} //~ ERROR borrow stack fn main() { let mut x = 0; diff --git a/tests/compile-fail/stacked_borrows/box_exclusive_violation1.rs b/tests/compile-fail/stacked_borrows/box_exclusive_violation1.rs index 481915faed040..7d7f5e24e2b0b 100644 --- a/tests/compile-fail/stacked_borrows/box_exclusive_violation1.rs +++ b/tests/compile-fail/stacked_borrows/box_exclusive_violation1.rs @@ -8,7 +8,7 @@ fn demo_mut_advanced_unique(mut our: Box) -> i32 { unknown_code_2(); // We know this will return 5 - *our //~ ERROR does not exist on the borrow stack + *our //~ ERROR borrow stack } // Now comes the evil context diff --git a/tests/compile-fail/stacked_borrows/buggy_as_mut_slice.rs b/tests/compile-fail/stacked_borrows/buggy_as_mut_slice.rs index 98d4e6f22965d..9ff67ae354220 100644 --- a/tests/compile-fail/stacked_borrows/buggy_as_mut_slice.rs +++ b/tests/compile-fail/stacked_borrows/buggy_as_mut_slice.rs @@ -13,5 +13,5 @@ fn main() { let v1 = safe::as_mut_slice(&v); let _v2 = safe::as_mut_slice(&v); v1[1] = 5; - //~^ ERROR does not exist on the borrow stack + //~^ ERROR borrow stack } diff --git a/tests/compile-fail/stacked_borrows/buggy_split_at_mut.rs b/tests/compile-fail/stacked_borrows/buggy_split_at_mut.rs index 42f345f55144c..812dd47ef1d90 100644 --- a/tests/compile-fail/stacked_borrows/buggy_split_at_mut.rs +++ b/tests/compile-fail/stacked_borrows/buggy_split_at_mut.rs @@ -9,7 +9,7 @@ mod safe { assert!(mid <= len); (from_raw_parts_mut(ptr, len - mid), // BUG: should be "mid" instead of "len - mid" - //~^ ERROR does not exist on the borrow stack + //~^ ERROR borrow stack from_raw_parts_mut(ptr.offset(mid as isize), len - mid)) } } diff --git a/tests/compile-fail/stacked_borrows/illegal_read1.rs b/tests/compile-fail/stacked_borrows/illegal_read1.rs index 3fb38abefdae4..d942d2b27b999 100644 --- a/tests/compile-fail/stacked_borrows/illegal_read1.rs +++ b/tests/compile-fail/stacked_borrows/illegal_read1.rs @@ -7,7 +7,7 @@ fn main() { let xref = unsafe { &mut *xraw }; // derived from raw, so using raw is still ok... callee(xraw); let _val = *xref; // ...but any use of raw will invalidate our ref. - //~^ ERROR: does not exist on the borrow stack + //~^ ERROR: borrow stack } fn callee(xraw: *mut i32) { diff --git a/tests/compile-fail/stacked_borrows/illegal_read2.rs b/tests/compile-fail/stacked_borrows/illegal_read2.rs index e43340f0b8eed..c50c88d48f8c9 100644 --- a/tests/compile-fail/stacked_borrows/illegal_read2.rs +++ b/tests/compile-fail/stacked_borrows/illegal_read2.rs @@ -7,7 +7,7 @@ fn main() { let xref = unsafe { &mut *xraw }; // derived from raw, so using raw is still ok... callee(xraw); let _val = *xref; // ...but any use of raw will invalidate our ref. - //~^ ERROR: does not exist on the borrow stack + //~^ ERROR: borrow stack } fn callee(xraw: *mut i32) { diff --git a/tests/compile-fail/stacked_borrows/illegal_read3.rs b/tests/compile-fail/stacked_borrows/illegal_read3.rs index b4abbb4a1aedf..09fd5d534cf7d 100644 --- a/tests/compile-fail/stacked_borrows/illegal_read3.rs +++ b/tests/compile-fail/stacked_borrows/illegal_read3.rs @@ -15,7 +15,7 @@ fn main() { callee(xref1_sneaky); // ... though any use of it will invalidate our ref. let _val = *xref2; - //~^ ERROR: does not exist on the borrow stack + //~^ ERROR: borrow stack } fn callee(xref1: usize) { diff --git a/tests/compile-fail/stacked_borrows/illegal_read4.rs b/tests/compile-fail/stacked_borrows/illegal_read4.rs index bb889de8f839e..d7e281e3ffe5c 100644 --- a/tests/compile-fail/stacked_borrows/illegal_read4.rs +++ b/tests/compile-fail/stacked_borrows/illegal_read4.rs @@ -5,5 +5,5 @@ fn main() { let xraw = xref1 as *mut _; let xref2 = unsafe { &mut *xraw }; let _val = unsafe { *xraw }; // use the raw again, this invalidates xref2 *even* with the special read except for uniq refs - let _illegal = *xref2; //~ ERROR does not exist on the borrow stack + let _illegal = *xref2; //~ ERROR borrow stack } diff --git a/tests/compile-fail/stacked_borrows/illegal_read5.rs b/tests/compile-fail/stacked_borrows/illegal_read5.rs index 0f4737f16e63d..d6120cd64ad00 100644 --- a/tests/compile-fail/stacked_borrows/illegal_read5.rs +++ b/tests/compile-fail/stacked_borrows/illegal_read5.rs @@ -12,5 +12,5 @@ fn main() { let _val = *xref; // we can even still use our mutable reference mem::forget(unsafe { ptr::read(xshr) }); // but after reading through the shared ref let _val = *xref; // the mutable one is dead and gone - //~^ ERROR does not exist on the borrow stack + //~^ ERROR borrow stack } diff --git a/tests/compile-fail/stacked_borrows/illegal_write1.rs b/tests/compile-fail/stacked_borrows/illegal_write1.rs index d0a23cb44489a..dd262a341ed2d 100644 --- a/tests/compile-fail/stacked_borrows/illegal_write1.rs +++ b/tests/compile-fail/stacked_borrows/illegal_write1.rs @@ -5,5 +5,5 @@ fn main() { let x : *mut u32 = xref as *const _ as *mut _; unsafe { *x = 42; } // invalidates shared ref, activates raw } - let _x = *xref; //~ ERROR is not frozen + let _x = *xref; //~ ERROR borrow stack } diff --git a/tests/compile-fail/stacked_borrows/illegal_write2.rs b/tests/compile-fail/stacked_borrows/illegal_write2.rs index affa21c7625ea..62ea05e1811e7 100644 --- a/tests/compile-fail/stacked_borrows/illegal_write2.rs +++ b/tests/compile-fail/stacked_borrows/illegal_write2.rs @@ -3,6 +3,6 @@ fn main() { let target2 = target as *mut _; drop(&mut *target); // reborrow // Now make sure our ref is still the only one. - unsafe { *target2 = 13; } //~ ERROR does not exist on the borrow stack + unsafe { *target2 = 13; } //~ ERROR borrow stack let _val = *target; } diff --git a/tests/compile-fail/stacked_borrows/illegal_write3.rs b/tests/compile-fail/stacked_borrows/illegal_write3.rs index dc4edcc3a5b44..d2d8528d90786 100644 --- a/tests/compile-fail/stacked_borrows/illegal_write3.rs +++ b/tests/compile-fail/stacked_borrows/illegal_write3.rs @@ -3,6 +3,6 @@ fn main() { // Make sure raw ptr with raw tag cannot mutate frozen location without breaking the shared ref. let r#ref = ⌖ // freeze let ptr = r#ref as *const _ as *mut _; // raw ptr, with raw tag - unsafe { *ptr = 42; } //~ ERROR does not exist on the borrow stack + unsafe { *ptr = 42; } //~ ERROR borrow stack let _val = *r#ref; } diff --git a/tests/compile-fail/stacked_borrows/illegal_write4.rs b/tests/compile-fail/stacked_borrows/illegal_write4.rs index 37ae0f055f0ee..be4f89ba289a1 100644 --- a/tests/compile-fail/stacked_borrows/illegal_write4.rs +++ b/tests/compile-fail/stacked_borrows/illegal_write4.rs @@ -9,5 +9,5 @@ fn main() { let ptr = reference as *const _ as *mut i32; // raw ptr, with raw tag let _mut_ref: &mut i32 = unsafe { mem::transmute(ptr) }; // &mut, with raw tag // Now we retag, making our ref top-of-stack -- and, in particular, unfreezing. - let _val = *reference; //~ ERROR is not frozen + let _val = *reference; //~ ERROR borrow stack } diff --git a/tests/compile-fail/stacked_borrows/illegal_write5.rs b/tests/compile-fail/stacked_borrows/illegal_write5.rs index 3a0738bfd0b85..c60fe90fe05c7 100644 --- a/tests/compile-fail/stacked_borrows/illegal_write5.rs +++ b/tests/compile-fail/stacked_borrows/illegal_write5.rs @@ -8,7 +8,7 @@ fn main() { callee(xraw); // ... though any use of raw value will invalidate our ref. let _val = *xref; - //~^ ERROR: does not exist on the borrow stack + //~^ ERROR: borrow stack } fn callee(xraw: *mut i32) { diff --git a/tests/compile-fail/stacked_borrows/load_invalid_mut.rs b/tests/compile-fail/stacked_borrows/load_invalid_mut.rs index f2e4b36f85cc2..1704b7fe19b2e 100644 --- a/tests/compile-fail/stacked_borrows/load_invalid_mut.rs +++ b/tests/compile-fail/stacked_borrows/load_invalid_mut.rs @@ -5,5 +5,5 @@ fn main() { let xref = unsafe { &mut *xraw }; let xref_in_mem = Box::new(xref); let _val = unsafe { *xraw }; // invalidate xref - let _val = *xref_in_mem; //~ ERROR does not exist on the borrow stack + let _val = *xref_in_mem; //~ ERROR borrow stack } diff --git a/tests/compile-fail/stacked_borrows/load_invalid_shr.rs b/tests/compile-fail/stacked_borrows/load_invalid_shr.rs index 6599924f0f4c4..4757a2c1e5894 100644 --- a/tests/compile-fail/stacked_borrows/load_invalid_shr.rs +++ b/tests/compile-fail/stacked_borrows/load_invalid_shr.rs @@ -5,5 +5,5 @@ fn main() { let xref = unsafe { &*xraw }; let xref_in_mem = Box::new(xref); unsafe { *xraw = 42 }; // unfreeze - let _val = *xref_in_mem; //~ ERROR is not frozen + let _val = *xref_in_mem; //~ ERROR borrow stack } diff --git a/tests/compile-fail/stacked_borrows/mut_exclusive_violation1.rs b/tests/compile-fail/stacked_borrows/mut_exclusive_violation1.rs index 3fe6b6567423c..03343b985a021 100644 --- a/tests/compile-fail/stacked_borrows/mut_exclusive_violation1.rs +++ b/tests/compile-fail/stacked_borrows/mut_exclusive_violation1.rs @@ -21,7 +21,7 @@ fn unknown_code_1(x: &i32) { unsafe { } } fn unknown_code_2() { unsafe { - *LEAK = 7; //~ ERROR barrier + *LEAK = 7; //~ ERROR borrow stack } } fn main() { diff --git a/tests/compile-fail/stacked_borrows/outdated_local.rs b/tests/compile-fail/stacked_borrows/outdated_local.rs index ba36e43e0c5d4..4cb655366ef1f 100644 --- a/tests/compile-fail/stacked_borrows/outdated_local.rs +++ b/tests/compile-fail/stacked_borrows/outdated_local.rs @@ -3,7 +3,7 @@ fn main() { let y: *const i32 = &x; x = 1; // this invalidates y by reactivating the lowermost uniq borrow for this local - assert_eq!(unsafe { *y }, 1); //~ ERROR does not exist on the borrow stack + assert_eq!(unsafe { *y }, 1); //~ ERROR borrow stack assert_eq!(x, 1); } diff --git a/tests/compile-fail/stacked_borrows/pass_invalid_mut.rs b/tests/compile-fail/stacked_borrows/pass_invalid_mut.rs index b239237f01992..d8a53b7a96309 100644 --- a/tests/compile-fail/stacked_borrows/pass_invalid_mut.rs +++ b/tests/compile-fail/stacked_borrows/pass_invalid_mut.rs @@ -6,5 +6,5 @@ fn main() { let xraw = x as *mut _; let xref = unsafe { &mut *xraw }; let _val = unsafe { *xraw }; // invalidate xref - foo(xref); //~ ERROR does not exist on the borrow stack + foo(xref); //~ ERROR borrow stack } diff --git a/tests/compile-fail/stacked_borrows/pass_invalid_shr.rs b/tests/compile-fail/stacked_borrows/pass_invalid_shr.rs index 22a80e27103e1..091604a283b9c 100644 --- a/tests/compile-fail/stacked_borrows/pass_invalid_shr.rs +++ b/tests/compile-fail/stacked_borrows/pass_invalid_shr.rs @@ -6,5 +6,5 @@ fn main() { let xraw = x as *mut _; let xref = unsafe { &*xraw }; unsafe { *xraw = 42 }; // unfreeze - foo(xref); //~ ERROR is not frozen + foo(xref); //~ ERROR borrow stack } diff --git a/tests/compile-fail/stacked_borrows/pointer_smuggling.rs b/tests/compile-fail/stacked_borrows/pointer_smuggling.rs index a8207d58e99b2..f724cdd2a7694 100644 --- a/tests/compile-fail/stacked_borrows/pointer_smuggling.rs +++ b/tests/compile-fail/stacked_borrows/pointer_smuggling.rs @@ -8,7 +8,7 @@ fn fun1(x: &mut u8) { fn fun2() { // Now we use a pointer we are not allowed to use - let _x = unsafe { *PTR }; //~ ERROR does not exist on the borrow stack + let _x = unsafe { *PTR }; //~ ERROR borrow stack } fn main() { diff --git a/tests/compile-fail/stacked_borrows/return_invalid_mut.rs b/tests/compile-fail/stacked_borrows/return_invalid_mut.rs index 31f8a4e33afd9..54004ec438823 100644 --- a/tests/compile-fail/stacked_borrows/return_invalid_mut.rs +++ b/tests/compile-fail/stacked_borrows/return_invalid_mut.rs @@ -3,7 +3,7 @@ fn foo(x: &mut (i32, i32)) -> &mut i32 { let xraw = x as *mut (i32, i32); let ret = unsafe { &mut (*xraw).1 }; let _val = unsafe { *xraw }; // invalidate xref - ret //~ ERROR does not exist on the borrow stack + ret //~ ERROR borrow stack } fn main() { diff --git a/tests/compile-fail/stacked_borrows/return_invalid_mut_option.rs b/tests/compile-fail/stacked_borrows/return_invalid_mut_option.rs index 750d507d6f660..2eb2df81f5f16 100644 --- a/tests/compile-fail/stacked_borrows/return_invalid_mut_option.rs +++ b/tests/compile-fail/stacked_borrows/return_invalid_mut_option.rs @@ -3,7 +3,7 @@ fn foo(x: &mut (i32, i32)) -> Option<&mut i32> { let xraw = x as *mut (i32, i32); let ret = Some(unsafe { &mut (*xraw).1 }); let _val = unsafe { *xraw }; // invalidate xref - ret //~ ERROR does not exist on the borrow stack + ret //~ ERROR borrow stack } fn main() { diff --git a/tests/compile-fail/stacked_borrows/return_invalid_mut_tuple.rs b/tests/compile-fail/stacked_borrows/return_invalid_mut_tuple.rs index bb712e9e486cd..8b73df4bd1ac3 100644 --- a/tests/compile-fail/stacked_borrows/return_invalid_mut_tuple.rs +++ b/tests/compile-fail/stacked_borrows/return_invalid_mut_tuple.rs @@ -3,7 +3,7 @@ fn foo(x: &mut (i32, i32)) -> (&mut i32,) { let xraw = x as *mut (i32, i32); let ret = (unsafe { &mut (*xraw).1 },); let _val = unsafe { *xraw }; // invalidate xref - ret //~ ERROR does not exist on the borrow stack + ret //~ ERROR borrow stack } fn main() { diff --git a/tests/compile-fail/stacked_borrows/return_invalid_shr.rs b/tests/compile-fail/stacked_borrows/return_invalid_shr.rs index 986dd18b2e0b4..eab026f9a47c6 100644 --- a/tests/compile-fail/stacked_borrows/return_invalid_shr.rs +++ b/tests/compile-fail/stacked_borrows/return_invalid_shr.rs @@ -3,7 +3,7 @@ fn foo(x: &mut (i32, i32)) -> &i32 { let xraw = x as *mut (i32, i32); let ret = unsafe { &(*xraw).1 }; unsafe { *xraw = (42, 23) }; // unfreeze - ret //~ ERROR is not frozen + ret //~ ERROR borrow stack } fn main() { diff --git a/tests/compile-fail/stacked_borrows/return_invalid_shr_option.rs b/tests/compile-fail/stacked_borrows/return_invalid_shr_option.rs index 9d220991c3302..f3a35ca266c6b 100644 --- a/tests/compile-fail/stacked_borrows/return_invalid_shr_option.rs +++ b/tests/compile-fail/stacked_borrows/return_invalid_shr_option.rs @@ -3,7 +3,7 @@ fn foo(x: &mut (i32, i32)) -> Option<&i32> { let xraw = x as *mut (i32, i32); let ret = Some(unsafe { &(*xraw).1 }); unsafe { *xraw = (42, 23) }; // unfreeze - ret //~ ERROR is not frozen + ret //~ ERROR borrow stack } fn main() { diff --git a/tests/compile-fail/stacked_borrows/return_invalid_shr_tuple.rs b/tests/compile-fail/stacked_borrows/return_invalid_shr_tuple.rs index 060fa25c2307e..82723bade27d7 100644 --- a/tests/compile-fail/stacked_borrows/return_invalid_shr_tuple.rs +++ b/tests/compile-fail/stacked_borrows/return_invalid_shr_tuple.rs @@ -3,7 +3,7 @@ fn foo(x: &mut (i32, i32)) -> (&i32,) { let xraw = x as *mut (i32, i32); let ret = (unsafe { &(*xraw).1 },); unsafe { *xraw = (42, 23) }; // unfreeze - ret //~ ERROR is not frozen + ret //~ ERROR borrow stack } fn main() { diff --git a/tests/compile-fail/stacked_borrows/shr_frozen_violation1.rs b/tests/compile-fail/stacked_borrows/shr_frozen_violation1.rs index 560c9dfb665dd..5031210c547b1 100644 --- a/tests/compile-fail/stacked_borrows/shr_frozen_violation1.rs +++ b/tests/compile-fail/stacked_borrows/shr_frozen_violation1.rs @@ -8,9 +8,6 @@ fn main() { println!("{}", foo(&mut 0)); } -// If we replace the `*const` by `&`, my current dev version of miri -// *does* find the problem, but not for a good reason: It finds it because -// of barriers, and we shouldn't rely on unknown code using barriers. -fn unknown_code(x: *const i32) { - unsafe { *(x as *mut i32) = 7; } //~ ERROR barrier +fn unknown_code(x: &i32) { + unsafe { *(x as *const i32 as *mut i32) = 7; } //~ ERROR borrow stack } diff --git a/tests/compile-fail/stacked_borrows/static_memory_modification.rs b/tests/compile-fail/stacked_borrows/static_memory_modification.rs index c092cbfe50985..88ac164947660 100644 --- a/tests/compile-fail/stacked_borrows/static_memory_modification.rs +++ b/tests/compile-fail/stacked_borrows/static_memory_modification.rs @@ -3,6 +3,6 @@ static X: usize = 5; #[allow(mutable_transmutes)] fn main() { let _x = unsafe { - std::mem::transmute::<&usize, &mut usize>(&X) //~ ERROR mutable reference with frozen tag + std::mem::transmute::<&usize, &mut usize>(&X) //~ ERROR borrow stack }; } diff --git a/tests/compile-fail/stacked_borrows/transmute-is-no-escape.rs b/tests/compile-fail/stacked_borrows/transmute-is-no-escape.rs index 45ada88977788..e9282c5ba8f27 100644 --- a/tests/compile-fail/stacked_borrows/transmute-is-no-escape.rs +++ b/tests/compile-fail/stacked_borrows/transmute-is-no-escape.rs @@ -10,5 +10,5 @@ fn main() { let _raw: *mut i32 = unsafe { mem::transmute(&mut x[0]) }; // `raw` still carries a tag, so we get another pointer to the same location that does not carry a tag let raw = (&mut x[1] as *mut i32).wrapping_offset(-1); - unsafe { *raw = 13; } //~ ERROR does not exist on the borrow stack + unsafe { *raw = 13; } //~ ERROR borrow stack } diff --git a/tests/compile-fail/stacked_borrows/unescaped_local.rs b/tests/compile-fail/stacked_borrows/unescaped_local.rs index 1db14ea7eda54..b49e6cce63bc3 100644 --- a/tests/compile-fail/stacked_borrows/unescaped_local.rs +++ b/tests/compile-fail/stacked_borrows/unescaped_local.rs @@ -4,5 +4,5 @@ fn main() { let mut x = 42; let raw = &mut x as *mut i32 as usize as *mut i32; let _ptr = &mut x; - unsafe { *raw = 13; } //~ ERROR does not exist on the borrow stack + unsafe { *raw = 13; } //~ ERROR borrow stack } From 924624f810bd70078074c62ea94061927d2516bd Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 16 Apr 2019 23:37:37 +0200 Subject: [PATCH 0683/3747] some failures are impossible --- src/stacked_borrows.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 40cbf92e96553..152171aed066a 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -473,7 +473,7 @@ impl<'tcx> Stack { "no item to reborrow as {} from tag {} found in borrow stack", new_kind, derived_from, )))?; // With this we can compute the permission for the new pointer. - let new_perm = new_kind.new_perm(derived_from_perm)?; + let new_perm = new_kind.new_perm(derived_from_perm).expect("this should never fail"); // We behave very differently for the "unsafe" case of a shared-read-write pointer // ("unsafe" because this also applies to shared references with interior mutability). From 97c34c266f492ff548ca1584ccb7f1c3c49dcf82 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 17 Apr 2019 08:25:21 +0200 Subject: [PATCH 0684/3747] try to test the problematic cast-to-raw case... unfortunately with the implicit reborrow that's not currently possible --- tests/run-pass/2phase.rs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/tests/run-pass/2phase.rs b/tests/run-pass/2phase.rs index 78ddf566a9d39..87ecb4aef065b 100644 --- a/tests/run-pass/2phase.rs +++ b/tests/run-pass/2phase.rs @@ -26,6 +26,21 @@ fn two_phase3(b: bool) { )); } +#[allow(unreachable_code)] +fn two_phase_raw() { + let x: &mut Vec = &mut vec![]; + x.push( + { + // Unfortunately this does not trigger the problem of creating a + // raw ponter from a pointer that had a two-phase borrow derived from + // it because of the implicit &mut reborrow. + let raw = x as *mut _; + unsafe { *raw = vec![1]; } + return + } + ); +} + /* fn two_phase_overlapping1() { let mut x = vec![]; @@ -67,6 +82,7 @@ fn main() { two_phase2(); two_phase3(false); two_phase3(true); + two_phase_raw(); with_interior_mutability(); //FIXME: enable these, or remove them, depending on how https://github.com/rust-lang/rust/issues/56254 gets resolved //two_phase_overlapping1(); From a503259d8b6437550fd1563368cfae618f8ab426 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 17 Apr 2019 08:35:06 +0200 Subject: [PATCH 0685/3747] organize stacked borrows run-pass tests --- tests/run-pass/refcell.rs | 46 +------------------ .../run-pass/{ => stacked-borrows}/2phase.rs | 0 tests/run-pass/stacked-borrows/refcell.rs | 44 ++++++++++++++++++ .../{ => stacked-borrows}/stacked-borrows.rs | 0 4 files changed, 45 insertions(+), 45 deletions(-) rename tests/run-pass/{ => stacked-borrows}/2phase.rs (100%) create mode 100644 tests/run-pass/stacked-borrows/refcell.rs rename tests/run-pass/{ => stacked-borrows}/stacked-borrows.rs (100%) diff --git a/tests/run-pass/refcell.rs b/tests/run-pass/refcell.rs index 0bc8b15c5f24e..93cef1572a3e1 100644 --- a/tests/run-pass/refcell.rs +++ b/tests/run-pass/refcell.rs @@ -1,6 +1,6 @@ use std::cell::RefCell; -fn lots_of_funny_borrows() { +fn main() { let c = RefCell::new(42); { let s1 = c.borrow(); @@ -31,47 +31,3 @@ fn lots_of_funny_borrows() { let _y: i32 = *s2; } } - -fn aliasing_mut_and_shr() { - fn inner(rc: &RefCell, aliasing: &mut i32) { - *aliasing += 4; - let _escape_to_raw = rc as *const _; - *aliasing += 4; - let _shr = &*rc; - *aliasing += 4; - // also turning this into a frozen ref now must work - let aliasing = &*aliasing; - let _val = *aliasing; - let _escape_to_raw = rc as *const _; // this must NOT unfreeze - let _val = *aliasing; - let _shr = &*rc; // this must NOT unfreeze - let _val = *aliasing; - } - - let rc = RefCell::new(23); - let mut bmut = rc.borrow_mut(); - inner(&rc, &mut *bmut); - drop(bmut); - assert_eq!(*rc.borrow(), 23+12); -} - -fn aliasing_frz_and_shr() { - fn inner(rc: &RefCell, aliasing: &i32) { - let _val = *aliasing; - let _escape_to_raw = rc as *const _; // this must NOT unfreeze - let _val = *aliasing; - let _shr = &*rc; // this must NOT unfreeze - let _val = *aliasing; - } - - let rc = RefCell::new(23); - let bshr = rc.borrow(); - inner(&rc, &*bshr); - assert_eq!(*rc.borrow(), 23); -} - -fn main() { - lots_of_funny_borrows(); - aliasing_mut_and_shr(); - aliasing_frz_and_shr(); -} diff --git a/tests/run-pass/2phase.rs b/tests/run-pass/stacked-borrows/2phase.rs similarity index 100% rename from tests/run-pass/2phase.rs rename to tests/run-pass/stacked-borrows/2phase.rs diff --git a/tests/run-pass/stacked-borrows/refcell.rs b/tests/run-pass/stacked-borrows/refcell.rs new file mode 100644 index 0000000000000..dddc7089d02d0 --- /dev/null +++ b/tests/run-pass/stacked-borrows/refcell.rs @@ -0,0 +1,44 @@ +use std::cell::RefCell; + +fn main() { + aliasing_mut_and_shr(); + aliasing_frz_and_shr(); +} + +fn aliasing_mut_and_shr() { + fn inner(rc: &RefCell, aliasing: &mut i32) { + *aliasing += 4; + let _escape_to_raw = rc as *const _; + *aliasing += 4; + let _shr = &*rc; + *aliasing += 4; + // also turning this into a frozen ref now must work + let aliasing = &*aliasing; + let _val = *aliasing; + let _escape_to_raw = rc as *const _; // this must NOT unfreeze + let _val = *aliasing; + let _shr = &*rc; // this must NOT unfreeze + let _val = *aliasing; + } + + let rc = RefCell::new(23); + let mut bmut = rc.borrow_mut(); + inner(&rc, &mut *bmut); + drop(bmut); + assert_eq!(*rc.borrow(), 23+12); +} + +fn aliasing_frz_and_shr() { + fn inner(rc: &RefCell, aliasing: &i32) { + let _val = *aliasing; + let _escape_to_raw = rc as *const _; // this must NOT unfreeze + let _val = *aliasing; + let _shr = &*rc; // this must NOT unfreeze + let _val = *aliasing; + } + + let rc = RefCell::new(23); + let bshr = rc.borrow(); + inner(&rc, &*bshr); + assert_eq!(*rc.borrow(), 23); +} diff --git a/tests/run-pass/stacked-borrows.rs b/tests/run-pass/stacked-borrows/stacked-borrows.rs similarity index 100% rename from tests/run-pass/stacked-borrows.rs rename to tests/run-pass/stacked-borrows/stacked-borrows.rs From 7b7fef1b53dab72a6a61951e166851ffc7d4bc82 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 17 Apr 2019 08:42:41 +0200 Subject: [PATCH 0686/3747] let the permission of a new pointer depend on the type only --- src/stacked_borrows.rs | 264 +++++++++++++++++++---------------------- 1 file changed, 125 insertions(+), 139 deletions(-) diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 152171aed066a..ca257aaf1feb1 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -5,7 +5,7 @@ use std::fmt; use std::num::NonZeroU64; use rustc::ty::{self, layout::Size}; -use rustc::hir::{Mutability, MutMutable, MutImmutable}; +use rustc::hir::{MutMutable, MutImmutable}; use rustc::mir::RetagKind; use crate::{ @@ -96,50 +96,38 @@ pub type MemoryState = Rc>; #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] pub enum AccessKind { Read, - Write { dealloc: bool }, -} - -// "Fake" constructors -impl AccessKind { - fn write() -> AccessKind { - AccessKind::Write { dealloc: false } - } - - fn dealloc() -> AccessKind { - AccessKind::Write { dealloc: true } - } + Write, } impl fmt::Display for AccessKind { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { AccessKind::Read => write!(f, "read"), - AccessKind::Write { dealloc: false } => write!(f, "write"), - AccessKind::Write { dealloc: true } => write!(f, "deallocation"), + AccessKind::Write => write!(f, "write"), } } } /// Indicates which kind of reference is being created. -/// Used by `reborrow` to compute which permissions to grant to the +/// Used by high-level `reborrow` to compute which permissions to grant to the /// new pointer. #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] pub enum RefKind { - /// `&mut`. - Mutable, + /// `&mut` and `Box`. + Unique, /// `&` with or without interior mutability. - Shared { frozen: bool }, - /// `*` (raw pointer). - Raw, + Shared, + /// `*mut`/`*const` (raw pointers). + Raw { mutable: bool }, } impl fmt::Display for RefKind { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { - RefKind::Mutable => write!(f, "mutable"), - RefKind::Shared { frozen: true } => write!(f, "shared (frozen)"), - RefKind::Shared { frozen: false } => write!(f, "shared (mutable)"), - RefKind::Raw => write!(f, "raw"), + RefKind::Unique => write!(f, "unique"), + RefKind::Shared => write!(f, "shared"), + RefKind::Raw { mutable: true } => write!(f, "raw (mutable)"), + RefKind::Raw { mutable: false } => write!(f, "raw (constant)"), } } } @@ -216,7 +204,7 @@ impl Permission { // SharedReadOnly only permits read access. (Permission::SharedReadOnly, AccessKind::Read) => true, - (Permission::SharedReadOnly, AccessKind::Write { .. }) => + (Permission::SharedReadOnly, AccessKind::Write) => false, } } @@ -235,7 +223,7 @@ impl Permission { // When `other` is `SharedReadOnly`, that is NEVER compatible with // write accesses. // This makes sure read-only pointers become invalid on write accesses (ensures F2a). - (_, AccessKind::Write { .. }, SharedReadOnly) => + (_, AccessKind::Write, SharedReadOnly) => false, // When `other` is `Unique`, that is compatible with nothing. // This makes sure unique pointers become invalid on incompatible accesses (ensures U2). @@ -246,7 +234,7 @@ impl Permission { // (This is particularily important such that when a new mutable ref gets created, it gets // pushed into the right item -- this behaves like a write and we assert uniqueness of the // pointer from which this comes, *if* it was a unique pointer.) - (Unique, AccessKind::Write { .. }, _) => + (Unique, AccessKind::Write, _) => false, // `SharedReadWrite` items can tolerate any other akin items for any kind of access. (SharedReadWrite, _, SharedReadWrite) => @@ -262,42 +250,7 @@ impl Permission { } } -impl<'tcx> RefKind { - /// Defines which kind of access the "parent" must grant to create this reference. - fn access(self) -> AccessKind { - match self { - RefKind::Mutable | RefKind::Shared { frozen: false } => AccessKind::write(), - RefKind::Raw | RefKind::Shared { frozen: true } => AccessKind::Read, - // FIXME: Just requiring read-only access for raw means that a raw ptr might not be writeable - // even when we think it should be! Think about this some more. - } - } - - /// This defines the new permission used when a pointer gets created: For raw pointers, whether these are read-only - /// or read-write depends on the permission from which they derive. - fn new_perm(self, derived_from: Permission) -> EvalResult<'tcx, Permission> { - Ok(match (self, derived_from) { - // Do not derive writable safe pointer from read-only pointer! - (RefKind::Mutable, Permission::SharedReadOnly) => - return err!(MachineError(format!( - "deriving mutable reference from read-only pointer" - ))), - (RefKind::Shared { frozen: false }, Permission::SharedReadOnly) => - return err!(MachineError(format!( - "deriving shared reference with interior mutability from read-only pointer" - ))), - // Safe pointer cases. - (RefKind::Mutable, _) => Permission::Unique, - (RefKind::Shared { frozen: true }, _) => Permission::SharedReadOnly, - (RefKind::Shared { frozen: false }, _) => Permission::SharedReadWrite, - // Raw pointer cases. - (RefKind::Raw, Permission::SharedReadOnly) => Permission::SharedReadOnly, - (RefKind::Raw, _) => Permission::SharedReadWrite, - }) - } -} - -/// Core per-location operations: access, create. +/// Core per-location operations: access, dealloc, reborrow. impl<'tcx> Stack { /// Find the item granting the given kind of access to the given tag, and where that item is in the stack. fn find_granting(&self, access: AccessKind, tag: Tag) -> Option<(usize, Permission)> { @@ -326,7 +279,6 @@ impl<'tcx> Stack { // The second step is where barriers get implemented: they "protect" the items // below them, meaning that if we remove an item and then further up encounter a barrier, // we raise an error. - // Afterwards we just do some post-processing for deallocation accesses. // Step 1: Find granting item. let (granting_idx, granting_perm) = self.find_granting(access, tag) @@ -356,7 +308,7 @@ impl<'tcx> Stack { } else { // Aha! This is a bad one, remove it. let item = self.borrows.remove(cur); - trace!("access: popping item {}", item); + trace!("access: removing item {}", item); removed_item = Some(item); } } @@ -380,25 +332,38 @@ impl<'tcx> Stack { } } - // Post-processing. - // If we got here, we found a matching item. Congratulations! - // However, we are not done yet: If this access is deallocating, we must make sure - // there are no active barriers remaining on the stack. - if access == AccessKind::dealloc() { - for &itm in self.borrows.iter().rev() { - match itm { - Item::FnBarrier(call) if global.is_active(call) => { - return err!(MachineError(format!( - "deallocating with active barrier ({})", call - ))) - } - _ => {}, + // Done. + return Ok(granting_idx); + } + + /// Deallocate a location: Like a write access, but also there must be no + /// barriers at all. + fn dealloc( + &mut self, + tag: Tag, + global: &GlobalState, + ) -> EvalResult<'tcx> { + // Step 1: Find granting item. + self.find_granting(AccessKind::Write, tag) + .ok_or_else(|| InterpError::MachineError(format!( + "no item granting write access for deallocation to tag {} found in borrow stack", + tag, + )))?; + + // We must make sure there are no active barriers remaining on the stack. + // Also clear the stack, no more accesses are possible. + while let Some(itm) = self.borrows.pop() { + match itm { + Item::FnBarrier(call) if global.is_active(call) => { + return err!(MachineError(format!( + "deallocating with active barrier ({})", call + ))) } + _ => {}, } } - // Done. - return Ok(granting_idx); + Ok(()) } /// `reborrow` helper function. @@ -412,7 +377,7 @@ impl<'tcx> Stack { trace!("reborrow: avoiding redundant item {}", item); return; } - trace!("reborrow: pushing item {}", item); + trace!("reborrow: adding item {}", item); self.borrows.insert(position, item); } @@ -427,7 +392,7 @@ impl<'tcx> Stack { // that overlap. trace!("reborrow: avoiding redundant extra barrier"); } else { - trace!("reborrow: pushing barrier for call {}", call); + trace!("reborrow: adding barrier for call {}", call); self.borrows.push(itm); } } @@ -453,27 +418,22 @@ impl<'tcx> Stack { &mut self, derived_from: Tag, barrier: Option, - new_kind: RefKind, + new_perm: Permission, new_tag: Tag, global: &GlobalState, ) -> EvalResult<'tcx> { - // Find the permission "from which we derive". To this end we first have to decide - // if we derive from a permission that grants writes or just reads. - let access = new_kind.access(); - // Now we figure out which item grants our parent (`derived_from`) permission. - // We use that to determine (a) where to put the new item, and for raw pointers - // (b) whether to given read-only or read-write access. - // FIXME: This handling of raw pointers is fragile, very fragile. What if we do - // not get "the right one", like when there are multiple items granting `derived_from` - // and we accidentally create a read-only pointer? This can happen for two-phase borrows - // (then there's a `Unique` and a `SharedReadOnly` for the same tag), and for raw pointers - // (which currently all are `Untagged`). - let (derived_from_idx, derived_from_perm) = self.find_granting(access, derived_from) + // Figure out which access `perm` corresponds to. + let access = if new_perm.grants(AccessKind::Write) { + AccessKind::Write + } else { + AccessKind::Read + }; + // Now we figure out which item grants our parent (`derived_from`) this kind of access. + // We use that to determine where to put the new item. + let (derived_from_idx, _) = self.find_granting(access, derived_from) .ok_or_else(|| InterpError::MachineError(format!( - "no item to reborrow as {} from tag {} found in borrow stack", new_kind, derived_from, + "no item to reborrow for {:?} from tag {} found in borrow stack", new_perm, derived_from, )))?; - // With this we can compute the permission for the new pointer. - let new_perm = new_kind.new_perm(derived_from_perm).expect("this should never fail"); // We behave very differently for the "unsafe" case of a shared-read-write pointer // ("unsafe" because this also applies to shared references with interior mutability). @@ -530,8 +490,9 @@ impl<'tcx> Stack { Ok(()) } } +// # Stacked Borrows Core End -/// Higher-level per-location operations: deref, access, reborrow. +/// Higher-level per-location operations: deref, access, dealloc, reborrow. impl<'tcx> Stacks { /// Creates new stack with initial tag. pub(crate) fn new( @@ -554,16 +515,34 @@ impl<'tcx> Stacks { &self, ptr: Pointer, size: Size, - kind: AccessKind, + access: AccessKind, + ) -> EvalResult<'tcx> { + trace!("{} access of tag {}: {:?}, size {}", access, ptr.tag, ptr, size.bytes()); + // Even reads can have a side-effect, by invalidating other references. + // This is fundamentally necessary since `&mut` asserts that there + // are no accesses through other references, not even reads. + let global = self.global.borrow(); + let mut stacks = self.stacks.borrow_mut(); + for stack in stacks.iter_mut(ptr.offset, size) { + stack.access(access, ptr.tag, &*global)?; + } + Ok(()) + } + + /// `ptr` is used to deallocate. + fn dealloc( + &self, + ptr: Pointer, + size: Size, ) -> EvalResult<'tcx> { - trace!("{} access of tag {}: {:?}, size {}", kind, ptr.tag, ptr, size.bytes()); + trace!("deallocation with tag {}: {:?}, size {}", ptr.tag, ptr, size.bytes()); // Even reads can have a side-effect, by invalidating other references. // This is fundamentally necessary since `&mut` asserts that there // are no accesses through other references, not even reads. let global = self.global.borrow(); let mut stacks = self.stacks.borrow_mut(); for stack in stacks.iter_mut(ptr.offset, size) { - stack.access(kind, ptr.tag, &*global)?; + stack.dealloc(ptr.tag, &*global)?; } Ok(()) } @@ -575,26 +554,23 @@ impl<'tcx> Stacks { ptr: Pointer, size: Size, barrier: Option, - new_kind: RefKind, + new_perm: Permission, new_tag: Tag, ) -> EvalResult<'tcx> { trace!( - "{} reborrow for tag {} to {}: {:?}, size {}", - new_kind, ptr.tag, new_tag, ptr, size.bytes(), + "reborrow tag {} as {:?} {}: {:?}, size {}", + ptr.tag, new_perm, new_tag, ptr, size.bytes(), ); let global = self.global.borrow(); let mut stacks = self.stacks.borrow_mut(); for stack in stacks.iter_mut(ptr.offset, size) { - stack.reborrow(ptr.tag, barrier, new_kind, new_tag, &*global)?; + stack.reborrow(ptr.tag, barrier, new_perm, new_tag, &*global)?; } Ok(()) } } -// # Stacked Borrows Core End - -// Glue code to connect with Miri Machine Hooks - +/// Glue code to connect with Miri Machine Hooks impl Stacks { pub fn new_allocation( size: Size, @@ -638,7 +614,7 @@ impl AllocationExtra for Stacks { ptr: Pointer, size: Size, ) -> EvalResult<'tcx> { - alloc.extra.access(ptr, size, AccessKind::write()) + alloc.extra.access(ptr, size, AccessKind::Write) } #[inline(always)] @@ -647,42 +623,48 @@ impl AllocationExtra for Stacks { ptr: Pointer, size: Size, ) -> EvalResult<'tcx> { - alloc.extra.access(ptr, size, AccessKind::dealloc()) + alloc.extra.dealloc(ptr, size) } } impl<'a, 'mir, 'tcx> EvalContextPrivExt<'a, 'mir, 'tcx> for crate::MiriEvalContext<'a, 'mir, 'tcx> {} trait EvalContextPrivExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, 'mir, 'tcx> { + /// High-level `reborrow` operation. This decides which reference gets which kind + /// of permission! fn reborrow( &mut self, place: MPlaceTy<'tcx, Tag>, size: Size, - mutbl: Option, + kind: RefKind, new_tag: Tag, fn_barrier: bool, ) -> EvalResult<'tcx> { let this = self.eval_context_mut(); let barrier = if fn_barrier { Some(this.frame().extra) } else { None }; let ptr = place.ptr.to_ptr()?; - trace!("reborrow: creating new reference for {:?} (pointee {}): {:?}", - ptr, place.layout.ty, new_tag); + trace!("reborrow: creating new reference for {:?} (pointee {}): {}, {:?}", + ptr, place.layout.ty, kind, new_tag); // Get the allocation. It might not be mutable, so we cannot use `get_mut`. let alloc = this.memory().get(ptr.alloc_id)?; alloc.check_bounds(this, ptr, size)?; // Update the stacks. - if mutbl == Some(MutImmutable) { - // Reference that cares about freezing. We need a frozen-sensitive reborrow. - this.visit_freeze_sensitive(place, size, |cur_ptr, size, frozen| { - let new_kind = RefKind::Shared { frozen }; - alloc.extra.reborrow(cur_ptr, size, barrier, new_kind, new_tag) - })?; - } else { - // Just treat this as one big chunk. - let new_kind = if mutbl == Some(MutMutable) { RefKind::Mutable } else { RefKind::Raw }; - alloc.extra.reborrow(ptr, size, barrier, new_kind, new_tag)?; - } - Ok(()) + let perm = match kind { + RefKind::Unique => Permission::Unique, + RefKind::Raw { mutable: true } => Permission::SharedReadWrite, + RefKind::Shared | RefKind::Raw { mutable: false } => { + // Shared references and *const are a whole different kind of game, the + // permission is not uniform across the entire range! + // We need a frozen-sensitive reborrow. + return this.visit_freeze_sensitive(place, size, |cur_ptr, size, frozen| { + // We are only ever `SharedReadOnly` inside the frozen bits. + let perm = if frozen { Permission::SharedReadOnly } else { Permission::SharedReadWrite }; + alloc.extra.reborrow(cur_ptr, size, barrier, perm, new_tag) + }); + } + }; + debug_assert_ne!(perm, Permission::SharedReadOnly, "SharedReadOnly must be used frozen-sensitive"); + return alloc.extra.reborrow(ptr, size, barrier, perm, new_tag); } /// Retags an indidual pointer, returning the retagged version. @@ -690,7 +672,7 @@ trait EvalContextPrivExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, fn retag_reference( &mut self, val: ImmTy<'tcx, Tag>, - mutbl: Option, + kind: RefKind, fn_barrier: bool, two_phase: bool, ) -> EvalResult<'tcx, Immediate> { @@ -706,24 +688,24 @@ trait EvalContextPrivExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, } // Compute new borrow. - let new_tag = match mutbl { - Some(_) => Tag::Tagged(this.memory().extra.borrow_mut().new_ptr()), - None => Tag::Untagged, + let new_tag = match kind { + RefKind::Raw { .. } => Tag::Untagged, + _ => Tag::Tagged(this.memory().extra.borrow_mut().new_ptr()), }; // Reborrow. - this.reborrow(place, size, mutbl, new_tag, fn_barrier)?; + this.reborrow(place, size, kind, new_tag, fn_barrier)?; let new_place = place.replace_tag(new_tag); // Handle two-phase borrows. if two_phase { - assert!(mutbl == Some(MutMutable), "two-phase shared borrows make no sense"); + assert!(kind == RefKind::Unique, "two-phase shared borrows make no sense"); // Grant read access *to the parent pointer* with the old tag. This means the same pointer // has multiple items in the stack now! // FIXME: Think about this some more, in particular about the interaction with cast-to-raw. // Maybe find a better way to express 2-phase, now that we have a "more expressive language" // in the stack. let old_tag = place.ptr.to_ptr().unwrap().tag; - this.reborrow(new_place, size, Some(MutImmutable), old_tag, /* fn_barrier: */ false)?; + this.reborrow(new_place, size, RefKind::Shared, old_tag, /* fn_barrier: */ false)?; } // Return new pointer. @@ -742,15 +724,19 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, // Determine mutability and whether to add a barrier. // Cannot use `builtin_deref` because that reports *immutable* for `Box`, // making it useless. - fn qualify(ty: ty::Ty<'_>, kind: RetagKind) -> Option<(Option, bool)> { + fn qualify(ty: ty::Ty<'_>, kind: RetagKind) -> Option<(RefKind, bool)> { match ty.sty { // References are simple. - ty::Ref(_, _, mutbl) => Some((Some(mutbl), kind == RetagKind::FnEntry)), + ty::Ref(_, _, MutMutable) => + Some((RefKind::Unique, kind == RetagKind::FnEntry)), + ty::Ref(_, _, MutImmutable) => + Some((RefKind::Shared, kind == RetagKind::FnEntry)), // Raw pointers need to be enabled. - ty::RawPtr(..) if kind == RetagKind::Raw => Some((None, false)), + ty::RawPtr(tym) if kind == RetagKind::Raw => + Some((RefKind::Raw { mutable: tym.mutbl == MutMutable }, false)), // Boxes do not get a barrier: barriers reflect that references outlive the call // they were passed in to; that's just not the case for boxes. - ty::Adt(..) if ty.is_box() => Some((Some(MutMutable), false)), + ty::Adt(..) if ty.is_box() => Some((RefKind::Unique, false)), _ => None, } } From 14e701f7d8008656327094056e800af506b0f6a4 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 17 Apr 2019 14:23:21 +0200 Subject: [PATCH 0687/3747] abstract mapping over all the stacks in some memory range --- src/stacked_borrows.rs | 83 ++++++++++++++---------------------------- 1 file changed, 27 insertions(+), 56 deletions(-) diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index ca257aaf1feb1..7c0a72cde3c0a 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -492,7 +492,7 @@ impl<'tcx> Stack { } // # Stacked Borrows Core End -/// Higher-level per-location operations: deref, access, dealloc, reborrow. +/// Map per-stack operations to higher-level per-location-range operations. impl<'tcx> Stacks { /// Creates new stack with initial tag. pub(crate) fn new( @@ -510,61 +510,17 @@ impl<'tcx> Stacks { } } - /// `ptr` got used, reflect that in the stack. - fn access( - &self, - ptr: Pointer, - size: Size, - access: AccessKind, - ) -> EvalResult<'tcx> { - trace!("{} access of tag {}: {:?}, size {}", access, ptr.tag, ptr, size.bytes()); - // Even reads can have a side-effect, by invalidating other references. - // This is fundamentally necessary since `&mut` asserts that there - // are no accesses through other references, not even reads. - let global = self.global.borrow(); - let mut stacks = self.stacks.borrow_mut(); - for stack in stacks.iter_mut(ptr.offset, size) { - stack.access(access, ptr.tag, &*global)?; - } - Ok(()) - } - - /// `ptr` is used to deallocate. - fn dealloc( + /// Call `f` on every stack in the range. + fn for_each( &self, ptr: Pointer, size: Size, + f: impl Fn(&mut Stack, Tag, &GlobalState) -> EvalResult<'tcx>, ) -> EvalResult<'tcx> { - trace!("deallocation with tag {}: {:?}, size {}", ptr.tag, ptr, size.bytes()); - // Even reads can have a side-effect, by invalidating other references. - // This is fundamentally necessary since `&mut` asserts that there - // are no accesses through other references, not even reads. let global = self.global.borrow(); let mut stacks = self.stacks.borrow_mut(); for stack in stacks.iter_mut(ptr.offset, size) { - stack.dealloc(ptr.tag, &*global)?; - } - Ok(()) - } - - /// Reborrow the given pointer to the new tag for the given kind of reference. - /// This works on `&self` because we might encounter references to constant memory. - fn reborrow( - &self, - ptr: Pointer, - size: Size, - barrier: Option, - new_perm: Permission, - new_tag: Tag, - ) -> EvalResult<'tcx> { - trace!( - "reborrow tag {} as {:?} {}: {:?}, size {}", - ptr.tag, new_perm, new_tag, ptr, size.bytes(), - ); - let global = self.global.borrow(); - let mut stacks = self.stacks.borrow_mut(); - for stack in stacks.iter_mut(ptr.offset, size) { - stack.reborrow(ptr.tag, barrier, new_perm, new_tag, &*global)?; + f(stack, ptr.tag, &*global)?; } Ok(()) } @@ -605,7 +561,11 @@ impl AllocationExtra for Stacks { ptr: Pointer, size: Size, ) -> EvalResult<'tcx> { - alloc.extra.access(ptr, size, AccessKind::Read) + trace!("read access with tag {}: {:?}, size {}", ptr.tag, ptr, size.bytes()); + alloc.extra.for_each(ptr, size, |stack, tag, global| { + stack.access(AccessKind::Read, tag, global)?; + Ok(()) + }) } #[inline(always)] @@ -614,7 +574,11 @@ impl AllocationExtra for Stacks { ptr: Pointer, size: Size, ) -> EvalResult<'tcx> { - alloc.extra.access(ptr, size, AccessKind::Write) + trace!("write access with tag {}: {:?}, size {}", ptr.tag, ptr, size.bytes()); + alloc.extra.for_each(ptr, size, |stack, tag, global| { + stack.access(AccessKind::Write, tag, global)?; + Ok(()) + }) } #[inline(always)] @@ -623,7 +587,10 @@ impl AllocationExtra for Stacks { ptr: Pointer, size: Size, ) -> EvalResult<'tcx> { - alloc.extra.dealloc(ptr, size) + trace!("deallocation with tag {}: {:?}, size {}", ptr.tag, ptr, size.bytes()); + alloc.extra.for_each(ptr, size, |stack, tag, global| { + stack.dealloc(tag, global) + }) } } @@ -642,8 +609,8 @@ trait EvalContextPrivExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, let this = self.eval_context_mut(); let barrier = if fn_barrier { Some(this.frame().extra) } else { None }; let ptr = place.ptr.to_ptr()?; - trace!("reborrow: creating new reference for {:?} (pointee {}): {}, {:?}", - ptr, place.layout.ty, kind, new_tag); + trace!("reborrow: {:?} reference {} derived from {} (pointee {}): {:?}, size {}", + kind, new_tag, ptr.tag, place.layout.ty, ptr, size.bytes()); // Get the allocation. It might not be mutable, so we cannot use `get_mut`. let alloc = this.memory().get(ptr.alloc_id)?; @@ -659,12 +626,16 @@ trait EvalContextPrivExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, return this.visit_freeze_sensitive(place, size, |cur_ptr, size, frozen| { // We are only ever `SharedReadOnly` inside the frozen bits. let perm = if frozen { Permission::SharedReadOnly } else { Permission::SharedReadWrite }; - alloc.extra.reborrow(cur_ptr, size, barrier, perm, new_tag) + alloc.extra.for_each(cur_ptr, size, |stack, tag, global| { + stack.reborrow(tag, barrier, perm, new_tag, global) + }) }); } }; debug_assert_ne!(perm, Permission::SharedReadOnly, "SharedReadOnly must be used frozen-sensitive"); - return alloc.extra.reborrow(ptr, size, barrier, perm, new_tag); + alloc.extra.for_each(ptr, size, |stack, tag, global| { + stack.reborrow(tag, barrier, perm, new_tag, global) + }) } /// Retags an indidual pointer, returning the retagged version. From e7a500b7e112be64e90517316a527e3a4a239437 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 17 Apr 2019 14:28:45 +0200 Subject: [PATCH 0688/3747] test creating two raw pointers from the same mutable ref --- tests/run-pass/stacked-borrows/stacked-borrows.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/tests/run-pass/stacked-borrows/stacked-borrows.rs b/tests/run-pass/stacked-borrows/stacked-borrows.rs index 711026c02dfc0..791e97f0eb1e1 100644 --- a/tests/run-pass/stacked-borrows/stacked-borrows.rs +++ b/tests/run-pass/stacked-borrows/stacked-borrows.rs @@ -10,6 +10,7 @@ fn main() { partially_invalidate_mut(); drop_after_sharing(); direct_mut_to_const_raw(); + two_raw(); } // Deref a raw ptr to access a field of a large struct, where the field @@ -123,3 +124,15 @@ fn direct_mut_to_const_raw() { assert_eq!(*x, 1); */ } + +// Make sure that we can create two raw pointers from a mutable reference and use them both. +fn two_raw() { unsafe { + let x = &mut 0; + // Given the implicit reborrows, the only reason this currently works is that we + // do not track raw pointers: The creation of `y2` reborrows `x` and thus pops + // `y1` off the stack. + let y1 = x as *mut _; + let y2 = x as *mut _; + *y1 += 2; + *y2 += 1; +} } From 46d5fd848773dcb3699344a8927a21e285d9207a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 17 Apr 2019 14:57:13 +0200 Subject: [PATCH 0689/3747] barriers are dead, long live protectors -- this enables overlapping two-phase borrows! --- src/stacked_borrows.rs | 255 ++++++++---------- .../stacked_borrows/aliasing_mut1.rs | 2 +- .../stacked_borrows/aliasing_mut2.rs | 2 +- .../stacked_borrows/aliasing_mut4.rs | 2 +- .../deallocate_against_barrier.rs | 2 +- .../invalidate_against_barrier1.rs | 2 +- .../invalidate_against_barrier2.rs | 2 +- tests/run-pass/stacked-borrows/2phase.rs | 15 +- 8 files changed, 120 insertions(+), 162 deletions(-) diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 7c0a72cde3c0a..98b6ca6543f23 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -15,7 +15,7 @@ use crate::{ }; pub type PtrId = NonZeroU64; -pub type CallId = u64; +pub type CallId = NonZeroU64; /// Tracking pointer provenance #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] @@ -46,19 +46,23 @@ pub enum Permission { /// An item in the per-location borrow stack. #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] -pub enum Item { - /// Grants the given permission for pointers with this tag. - Permission(Permission, Tag), - /// A barrier, tracking the function it belongs to by its index on the call stack. - FnBarrier(CallId), +pub struct Item { + /// The permission this item grants. + perm: Permission, + /// The pointers the permission is granted to. + tag: Tag, + /// An optional protector, ensuring the item cannot get popped until `CallId` is over. + protector: Option, } impl fmt::Display for Item { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match self { - Item::Permission(perm, tag) => write!(f, "[{:?} for {}]", perm, tag), - Item::FnBarrier(call) => write!(f, "[barrier {}]", call), + write!(f, "[{:?} for {}", self.perm, self.tag)?; + if let Some(call) = self.protector { + write!(f, " (call {})", call)?; } + write!(f, "]")?; + Ok(()) } } @@ -69,7 +73,7 @@ pub struct Stack { /// We sometimes push into the middle but never remove from the middle. /// The same tag may occur multiple times, e.g. from a two-phase borrow. /// Invariants: - /// * Above a `SharedReadOnly` there can only be barriers and more `SharedReadOnly`. + /// * Above a `SharedReadOnly` there can only be more `SharedReadOnly`. borrows: Vec, } @@ -137,7 +141,7 @@ impl Default for GlobalState { fn default() -> Self { GlobalState { next_ptr_id: NonZeroU64::new(1).unwrap(), - next_call_id: 0, + next_call_id: NonZeroU64::new(1).unwrap(), active_calls: HashSet::default(), } } @@ -154,7 +158,7 @@ impl GlobalState { let id = self.next_call_id; trace!("new_call: Assigning ID {}", id); self.active_calls.insert(id); - self.next_call_id = id+1; + self.next_call_id = NonZeroU64::new(id.get() + 1).unwrap(); id } @@ -232,7 +236,7 @@ impl Permission { // When we are unique and this is a write/dealloc, we tolerate nothing. // This makes sure we re-assert uniqueness ("being on top") on write accesses. // (This is particularily important such that when a new mutable ref gets created, it gets - // pushed into the right item -- this behaves like a write and we assert uniqueness of the + // pushed onto the right item -- this behaves like a write and we assert uniqueness of the // pointer from which this comes, *if* it was a unique pointer.) (Unique, AccessKind::Write, _) => false, @@ -259,11 +263,13 @@ impl<'tcx> Stack { .rev() // search top-to-bottom // Return permission of first item that grants access. // We require a permission with the right tag, ensuring U3 and F3. - .filter_map(|(idx, item)| match item { - &Item::Permission(perm, item_tag) if perm.grants(access) && tag == item_tag => - Some((idx, perm)), - _ => None, - }) + .filter_map(|(idx, item)| + if item.perm.grants(access) && tag == item.tag { + Some((idx, item.perm)) + } else { + None + } + ) .next() } @@ -276,9 +282,6 @@ impl<'tcx> Stack { global: &GlobalState, ) -> EvalResult<'tcx, usize> { // Two main steps: Find granting item, remove all incompatible items above. - // The second step is where barriers get implemented: they "protect" the items - // below them, meaning that if we remove an item and then further up encounter a barrier, - // we raise an error. // Step 1: Find granting item. let (granting_idx, granting_perm) = self.find_granting(access, tag) @@ -287,47 +290,35 @@ impl<'tcx> Stack { access, tag, )))?; - // Step 2: Remove everything incompatible above them. - // Items below an active barrier however may not be removed, so we check that as well. + // Step 2: Remove everything incompatible above them. Make sure we do not remove protected + // items. // We do *not* maintain a stack discipline here. We could, in principle, decide to only // keep the items immediately above `granting_idx` that are compatible, and then pop the rest. // However, that kills off entire "branches" of pointer derivation too easily: // in `let raw = &mut *x as *mut _; let _val = *x;`, the second statement would pop the `Unique` // from the reborrow of the first statement, and subequently also pop the `SharedReadWrite` for `raw`. + // This pattern occurs a lot in the standard library: create a raw pointer, then also create a shared + // reference and use that. { // Implemented with indices because there does not seem to be a nice iterator and range-based // API for this. let mut cur = granting_idx + 1; - let mut removed_item = None; while let Some(item) = self.borrows.get(cur) { - match *item { - Item::Permission(perm, _) => { - if granting_perm.compatible_with(access, perm) { - // Keep this, check next. - cur += 1; - } else { - // Aha! This is a bad one, remove it. - let item = self.borrows.remove(cur); - trace!("access: removing item {}", item); - removed_item = Some(item); - } - } - Item::FnBarrier(call) if !global.is_active(call) => { - // An inactive barrier, just get rid of it. (Housekeeping.) - self.borrows.remove(cur); - } - Item::FnBarrier(call) => { - // We hit an active barrier! If we have already removed an item, - // we got a problem! The barrier was supposed to protect this item. - if let Some(removed_item) = removed_item { + if granting_perm.compatible_with(access, item.perm) { + // Keep this, check next. + cur += 1; + } else { + // Aha! This is a bad one, remove it, and make sure it is not protected. + let item = self.borrows.remove(cur); + if let Some(call) = item.protector { + if global.is_active(call) { return err!(MachineError(format!( - "not granting {} access to tag {} because barrier ({}) protects incompatible item {}", - access, tag, call, removed_item + "not granting {} access to tag {} because incompatible item {} is protected", + access, tag, item ))); } - // Keep this, check next. - cur += 1; } + trace!("access: removing item {}", item); } } } @@ -337,7 +328,7 @@ impl<'tcx> Stack { } /// Deallocate a location: Like a write access, but also there must be no - /// barriers at all. + /// active protectors at all. fn dealloc( &mut self, tag: Tag, @@ -350,63 +341,32 @@ impl<'tcx> Stack { tag, )))?; - // We must make sure there are no active barriers remaining on the stack. + // We must make sure there are no protected items remaining on the stack. // Also clear the stack, no more accesses are possible. - while let Some(itm) = self.borrows.pop() { - match itm { - Item::FnBarrier(call) if global.is_active(call) => { + while let Some(item) = self.borrows.pop() { + if let Some(call) = item.protector { + if global.is_active(call) { return err!(MachineError(format!( - "deallocating with active barrier ({})", call + "deallocating with active protector ({})", call ))) } - _ => {}, } } Ok(()) } - /// `reborrow` helper function. - /// Grant `permisson` to new pointer tagged `tag`, added at `position` in the stack. - fn grant(&mut self, perm: Permission, tag: Tag, position: usize) { - // Simply add it to the "stack" -- this might add in the middle. - // As an optimization, do nothing if the new item is identical to one of its neighbors. - let item = Item::Permission(perm, tag); - if self.borrows[position-1] == item || self.borrows.get(position) == Some(&item) { - // Optimization applies, done. - trace!("reborrow: avoiding redundant item {}", item); - return; - } - trace!("reborrow: adding item {}", item); - self.borrows.insert(position, item); - } - - /// `reborrow` helper function. - /// Adds a barrier. - fn barrier(&mut self, call: CallId) { - let itm = Item::FnBarrier(call); - if *self.borrows.last().unwrap() == itm { - // This is just an optimization, no functional change: Avoid stacking - // multiple identical barriers on top of each other. - // This can happen when a function receives several shared references - // that overlap. - trace!("reborrow: avoiding redundant extra barrier"); - } else { - trace!("reborrow: adding barrier for call {}", call); - self.borrows.push(itm); - } - } - /// `reborrow` helper function: test that the stack invariants are still maintained. fn test_invariants(&self) { let mut saw_shared_read_only = false; for item in self.borrows.iter() { - match item { - Item::Permission(Permission::SharedReadOnly, _) => { + match item.perm { + Permission::SharedReadOnly => { saw_shared_read_only = true; } - Item::Permission(perm, _) if saw_shared_read_only => { - panic!("Found {:?} on top of a SharedReadOnly!", perm); + // Otherwise, if we saw one before, that's a bug. + perm if saw_shared_read_only => { + bug!("Found {:?} on top of a SharedReadOnly!", perm); } _ => {} } @@ -414,16 +374,18 @@ impl<'tcx> Stack { } /// Derived a new pointer from one with the given tag. + /// `weak` controls whether this is a weak reborrow: weak reborrows do not act as + /// accesses, and they add the new item directly on top of the one it is derived + /// from instead of all the way at the top of the stack. fn reborrow( &mut self, derived_from: Tag, - barrier: Option, - new_perm: Permission, - new_tag: Tag, + weak: bool, + new: Item, global: &GlobalState, ) -> EvalResult<'tcx> { // Figure out which access `perm` corresponds to. - let access = if new_perm.grants(AccessKind::Write) { + let access = if new.perm.grants(AccessKind::Write) { AccessKind::Write } else { AccessKind::Read @@ -432,16 +394,13 @@ impl<'tcx> Stack { // We use that to determine where to put the new item. let (derived_from_idx, _) = self.find_granting(access, derived_from) .ok_or_else(|| InterpError::MachineError(format!( - "no item to reborrow for {:?} from tag {} found in borrow stack", new_perm, derived_from, + "no item to reborrow for {:?} from tag {} found in borrow stack", new.perm, derived_from, )))?; - // We behave very differently for the "unsafe" case of a shared-read-write pointer - // ("unsafe" because this also applies to shared references with interior mutability). - // This is because such pointers may be reborrowed to unique pointers that actually - // remain valid when their "parents" get further reborrows! - // However, either way, we ensure that we insert the new item in a way that between + // Compute where to put the new item. + // Either way, we ensure that we insert the new item in a way that between // `derived_from` and the new one, there are only items *compatible with* `derived_from`. - if new_perm == Permission::SharedReadWrite { + let new_idx = if weak { // A very liberal reborrow because the new pointer does not expect any kind of aliasing guarantee. // Just insert new permission as child of old permission, and maintain everything else. // This inserts "as far down as possible", which is good because it makes this pointer as @@ -451,17 +410,7 @@ impl<'tcx> Stack { // and we'd allow write access without invalidating frozen shared references! // This ensures F2b for `SharedReadWrite` by adding the new item below any // potentially existing `SharedReadOnly`. - self.grant(new_perm, new_tag, derived_from_idx+1); - - // No barrier. They can rightfully alias with `&mut`. - // FIXME: This means that the `dereferencable` attribute on non-frozen shared references - // is incorrect! They are dereferencable when the function is called, but might become - // non-dereferencable during the course of execution. - // Also see [1], [2]. - // - // [1]: , - // [2]: + derived_from_idx+1 } else { // A "safe" reborrow for a pointer that actually expects some aliasing guarantees. // Here, creating a reference actually counts as an access, and pops incompatible @@ -474,12 +423,16 @@ impl<'tcx> Stack { // on top of `derived_from`, and we want the new item at the top so that we // get the strongest possible guarantees. // This ensures U1 and F1. - self.grant(new_perm, new_tag, self.borrows.len()); + self.borrows.len() + }; - // Now is a good time to add the barrier, protecting the item we just added. - if let Some(call) = barrier { - self.barrier(call); - } + // Put the new item there. As an optimization, deduplicate if it is equal to one of its new neighbors. + if self.borrows[new_idx-1] == new || self.borrows.get(new_idx) == Some(&new) { + // Optimization applies, done. + trace!("reborrow: avoiding adding redundant item {}", new); + } else { + trace!("reborrow: adding item {}", new); + self.borrows.insert(new_idx, new); } // Make sure that after all this, the stack's invariant is still maintained. @@ -500,7 +453,7 @@ impl<'tcx> Stacks { tag: Tag, extra: MemoryState, ) -> Self { - let item = Item::Permission(Permission::Unique, tag); + let item = Item { perm: Permission::Unique, tag, protector: None }; let stack = Stack { borrows: vec![item], }; @@ -515,12 +468,12 @@ impl<'tcx> Stacks { &self, ptr: Pointer, size: Size, - f: impl Fn(&mut Stack, Tag, &GlobalState) -> EvalResult<'tcx>, + f: impl Fn(&mut Stack, &GlobalState) -> EvalResult<'tcx>, ) -> EvalResult<'tcx> { let global = self.global.borrow(); let mut stacks = self.stacks.borrow_mut(); for stack in stacks.iter_mut(ptr.offset, size) { - f(stack, ptr.tag, &*global)?; + f(stack, &*global)?; } Ok(()) } @@ -562,8 +515,8 @@ impl AllocationExtra for Stacks { size: Size, ) -> EvalResult<'tcx> { trace!("read access with tag {}: {:?}, size {}", ptr.tag, ptr, size.bytes()); - alloc.extra.for_each(ptr, size, |stack, tag, global| { - stack.access(AccessKind::Read, tag, global)?; + alloc.extra.for_each(ptr, size, |stack, global| { + stack.access(AccessKind::Read, ptr.tag, global)?; Ok(()) }) } @@ -575,8 +528,8 @@ impl AllocationExtra for Stacks { size: Size, ) -> EvalResult<'tcx> { trace!("write access with tag {}: {:?}, size {}", ptr.tag, ptr, size.bytes()); - alloc.extra.for_each(ptr, size, |stack, tag, global| { - stack.access(AccessKind::Write, tag, global)?; + alloc.extra.for_each(ptr, size, |stack, global| { + stack.access(AccessKind::Write, ptr.tag, global)?; Ok(()) }) } @@ -588,26 +541,28 @@ impl AllocationExtra for Stacks { size: Size, ) -> EvalResult<'tcx> { trace!("deallocation with tag {}: {:?}, size {}", ptr.tag, ptr, size.bytes()); - alloc.extra.for_each(ptr, size, |stack, tag, global| { - stack.dealloc(tag, global) + alloc.extra.for_each(ptr, size, |stack, global| { + stack.dealloc(ptr.tag, global) }) } } +/// Retagging/reborrowing. There is some policy in here, such as which permissions +/// to grant for which references, when to add protectors, and how to realize two-phase +/// borrows in terms of the primitives above. impl<'a, 'mir, 'tcx> EvalContextPrivExt<'a, 'mir, 'tcx> for crate::MiriEvalContext<'a, 'mir, 'tcx> {} trait EvalContextPrivExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, 'mir, 'tcx> { - /// High-level `reborrow` operation. This decides which reference gets which kind - /// of permission! fn reborrow( &mut self, place: MPlaceTy<'tcx, Tag>, size: Size, kind: RefKind, new_tag: Tag, - fn_barrier: bool, + force_weak: bool, + protect: bool, ) -> EvalResult<'tcx> { let this = self.eval_context_mut(); - let barrier = if fn_barrier { Some(this.frame().extra) } else { None }; + let protector = if protect { Some(this.frame().extra) } else { None }; let ptr = place.ptr.to_ptr()?; trace!("reborrow: {:?} reference {} derived from {} (pointee {}): {:?}, size {}", kind, new_tag, ptr.tag, place.layout.ty, ptr, size.bytes()); @@ -616,6 +571,8 @@ trait EvalContextPrivExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, let alloc = this.memory().get(ptr.alloc_id)?; alloc.check_bounds(this, ptr, size)?; // Update the stacks. + // Make sure that raw pointers and mutable shared references are reborrowed "weak": + // There could be existing unique pointers reborrowed from them that should remain valid! let perm = match kind { RefKind::Unique => Permission::Unique, RefKind::Raw { mutable: true } => Permission::SharedReadWrite, @@ -625,16 +582,20 @@ trait EvalContextPrivExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, // We need a frozen-sensitive reborrow. return this.visit_freeze_sensitive(place, size, |cur_ptr, size, frozen| { // We are only ever `SharedReadOnly` inside the frozen bits. + let weak = !frozen || kind != RefKind::Shared; // `RefKind::Raw` is always weak, as is `SharedReadWrite`. let perm = if frozen { Permission::SharedReadOnly } else { Permission::SharedReadWrite }; - alloc.extra.for_each(cur_ptr, size, |stack, tag, global| { - stack.reborrow(tag, barrier, perm, new_tag, global) + let item = Item { perm, tag: new_tag, protector }; + alloc.extra.for_each(cur_ptr, size, |stack, global| { + stack.reborrow(cur_ptr.tag, force_weak || weak, item, global) }) }); } }; debug_assert_ne!(perm, Permission::SharedReadOnly, "SharedReadOnly must be used frozen-sensitive"); - alloc.extra.for_each(ptr, size, |stack, tag, global| { - stack.reborrow(tag, barrier, perm, new_tag, global) + let weak = perm == Permission::SharedReadWrite; + let item = Item { perm, tag: new_tag, protector }; + alloc.extra.for_each(ptr, size, |stack, global| { + stack.reborrow(ptr.tag, force_weak || weak, item, global) }) } @@ -644,7 +605,7 @@ trait EvalContextPrivExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, &mut self, val: ImmTy<'tcx, Tag>, kind: RefKind, - fn_barrier: bool, + protect: bool, two_phase: bool, ) -> EvalResult<'tcx, Immediate> { let this = self.eval_context_mut(); @@ -665,18 +626,16 @@ trait EvalContextPrivExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, }; // Reborrow. - this.reborrow(place, size, kind, new_tag, fn_barrier)?; + this.reborrow(place, size, kind, new_tag, /*force_weak:*/ two_phase, protect)?; let new_place = place.replace_tag(new_tag); // Handle two-phase borrows. if two_phase { assert!(kind == RefKind::Unique, "two-phase shared borrows make no sense"); - // Grant read access *to the parent pointer* with the old tag. This means the same pointer - // has multiple items in the stack now! - // FIXME: Think about this some more, in particular about the interaction with cast-to-raw. - // Maybe find a better way to express 2-phase, now that we have a "more expressive language" - // in the stack. + // Grant read access *to the parent pointer* with the old tag *derived from the new tag* (`new_place`). + // This means the old pointer has multiple items in the stack now, which otherwise cannot happen + // for unique references -- but in this case it precisely expresses the semantics we want. let old_tag = place.ptr.to_ptr().unwrap().tag; - this.reborrow(new_place, size, RefKind::Shared, old_tag, /* fn_barrier: */ false)?; + this.reborrow(new_place, size, RefKind::Shared, old_tag, /*force_weak:*/ false, /*protect:*/ false)?; } // Return new pointer. @@ -692,7 +651,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, place: PlaceTy<'tcx, Tag> ) -> EvalResult<'tcx> { let this = self.eval_context_mut(); - // Determine mutability and whether to add a barrier. + // Determine mutability and whether to add a protector. // Cannot use `builtin_deref` because that reports *immutable* for `Box`, // making it useless. fn qualify(ty: ty::Ty<'_>, kind: RetagKind) -> Option<(RefKind, bool)> { @@ -705,7 +664,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, // Raw pointers need to be enabled. ty::RawPtr(tym) if kind == RetagKind::Raw => Some((RefKind::Raw { mutable: tym.mutbl == MutMutable }, false)), - // Boxes do not get a barrier: barriers reflect that references outlive the call + // Boxes do not get a protector: protectors reflect that references outlive the call // they were passed in to; that's just not the case for boxes. ty::Adt(..) if ty.is_box() => Some((RefKind::Unique, false)), _ => None, @@ -715,10 +674,10 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, // We need a visitor to visit all references. However, that requires // a `MemPlace`, so we have a fast path for reference types that // avoids allocating. - if let Some((mutbl, barrier)) = qualify(place.layout.ty, kind) { + if let Some((mutbl, protector)) = qualify(place.layout.ty, kind) { // Fast path. let val = this.read_immediate(this.place_to_op(place)?)?; - let val = this.retag_reference(val, mutbl, barrier, kind == RetagKind::TwoPhase)?; + let val = this.retag_reference(val, mutbl, protector, kind == RetagKind::TwoPhase)?; this.write_immediate(val, place)?; return Ok(()); } @@ -749,12 +708,12 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, { // Cannot use `builtin_deref` because that reports *immutable* for `Box`, // making it useless. - if let Some((mutbl, barrier)) = qualify(place.layout.ty, self.kind) { + if let Some((mutbl, protector)) = qualify(place.layout.ty, self.kind) { let val = self.ecx.read_immediate(place.into())?; let val = self.ecx.retag_reference( val, mutbl, - barrier, + protector, self.kind == RetagKind::TwoPhase )?; self.ecx.write_immediate(val, place.into())?; diff --git a/tests/compile-fail/stacked_borrows/aliasing_mut1.rs b/tests/compile-fail/stacked_borrows/aliasing_mut1.rs index 9bced43f6e856..d047925163bd6 100644 --- a/tests/compile-fail/stacked_borrows/aliasing_mut1.rs +++ b/tests/compile-fail/stacked_borrows/aliasing_mut1.rs @@ -1,6 +1,6 @@ use std::mem; -pub fn safe(_x: &mut i32, _y: &mut i32) {} //~ ERROR barrier +pub fn safe(_x: &mut i32, _y: &mut i32) {} //~ ERROR protect fn main() { let mut x = 0; diff --git a/tests/compile-fail/stacked_borrows/aliasing_mut2.rs b/tests/compile-fail/stacked_borrows/aliasing_mut2.rs index ea24f1bd27488..c679e01677eb5 100644 --- a/tests/compile-fail/stacked_borrows/aliasing_mut2.rs +++ b/tests/compile-fail/stacked_borrows/aliasing_mut2.rs @@ -1,6 +1,6 @@ use std::mem; -pub fn safe(_x: &i32, _y: &mut i32) {} //~ ERROR barrier +pub fn safe(_x: &i32, _y: &mut i32) {} //~ ERROR protect fn main() { let mut x = 0; diff --git a/tests/compile-fail/stacked_borrows/aliasing_mut4.rs b/tests/compile-fail/stacked_borrows/aliasing_mut4.rs index 15f67d0f8728b..778935a6d0b0d 100644 --- a/tests/compile-fail/stacked_borrows/aliasing_mut4.rs +++ b/tests/compile-fail/stacked_borrows/aliasing_mut4.rs @@ -2,7 +2,7 @@ use std::mem; use std::cell::Cell; // Make sure &mut UnsafeCell also is exclusive -pub fn safe(_x: &i32, _y: &mut Cell) {} //~ ERROR barrier +pub fn safe(_x: &i32, _y: &mut Cell) {} //~ ERROR protect fn main() { let mut x = 0; diff --git a/tests/compile-fail/stacked_borrows/deallocate_against_barrier.rs b/tests/compile-fail/stacked_borrows/deallocate_against_barrier.rs index b2f1c824f1b45..49e376c0287e8 100644 --- a/tests/compile-fail/stacked_borrows/deallocate_against_barrier.rs +++ b/tests/compile-fail/stacked_borrows/deallocate_against_barrier.rs @@ -1,4 +1,4 @@ -// error-pattern: deallocating with active barrier +// error-pattern: deallocating with active protect fn inner(x: &mut i32, f: fn(&mut i32)) { // `f` may mutate, but it may not deallocate! diff --git a/tests/compile-fail/stacked_borrows/invalidate_against_barrier1.rs b/tests/compile-fail/stacked_borrows/invalidate_against_barrier1.rs index fc0dbb9e13133..3a214a75b5059 100644 --- a/tests/compile-fail/stacked_borrows/invalidate_against_barrier1.rs +++ b/tests/compile-fail/stacked_borrows/invalidate_against_barrier1.rs @@ -2,7 +2,7 @@ fn inner(x: *mut i32, _y: &mut i32) { // If `x` and `y` alias, retagging is fine with this... but we really // shouldn't be allowed to use `x` at all because `y` was assumed to be // unique for the duration of this call. - let _val = unsafe { *x }; //~ ERROR barrier + let _val = unsafe { *x }; //~ ERROR protect } fn main() { diff --git a/tests/compile-fail/stacked_borrows/invalidate_against_barrier2.rs b/tests/compile-fail/stacked_borrows/invalidate_against_barrier2.rs index a080c0958e400..86e4a84287ec1 100644 --- a/tests/compile-fail/stacked_borrows/invalidate_against_barrier2.rs +++ b/tests/compile-fail/stacked_borrows/invalidate_against_barrier2.rs @@ -2,7 +2,7 @@ fn inner(x: *mut i32, _y: &i32) { // If `x` and `y` alias, retagging is fine with this... but we really // shouldn't be allowed to write to `x` at all because `y` was assumed to be // immutable for the duration of this call. - unsafe { *x = 0 }; //~ ERROR barrier + unsafe { *x = 0 }; //~ ERROR protect } fn main() { diff --git a/tests/run-pass/stacked-borrows/2phase.rs b/tests/run-pass/stacked-borrows/2phase.rs index 87ecb4aef065b..97f435472e300 100644 --- a/tests/run-pass/stacked-borrows/2phase.rs +++ b/tests/run-pass/stacked-borrows/2phase.rs @@ -1,3 +1,5 @@ +#![allow(mutable_borrow_reservation_conflict)] + trait S: Sized { fn tpb(&mut self, _s: Self) {} } @@ -41,7 +43,6 @@ fn two_phase_raw() { ); } -/* fn two_phase_overlapping1() { let mut x = vec![]; let p = &x; @@ -54,7 +55,6 @@ fn two_phase_overlapping2() { let l = &x; x.add_assign(x + *l); } -*/ fn with_interior_mutability() { use std::cell::Cell; @@ -66,13 +66,13 @@ fn with_interior_mutability() { impl Thing for Cell {} let mut x = Cell::new(1); - //let l = &x; + let l = &x; x .do_the_thing({ x.set(3); - // l.set(4); // FIXME: Enable this as an example of overlapping 2PB! - x.get() // FIXME same: + l.get() + l.set(4); + x.get() + l.get() }) ; } @@ -84,7 +84,6 @@ fn main() { two_phase3(true); two_phase_raw(); with_interior_mutability(); - //FIXME: enable these, or remove them, depending on how https://github.com/rust-lang/rust/issues/56254 gets resolved - //two_phase_overlapping1(); - //two_phase_overlapping2(); + two_phase_overlapping1(); + two_phase_overlapping2(); } From 72cec0562cf3ff5a50f4318e316e188325cda54c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 17 Apr 2019 15:20:33 +0200 Subject: [PATCH 0690/3747] add tests for fixes: sharing no longer leaks, and we can handle entering interior mutability --- .../compile-fail/stacked_borrows/illegal_read6.rs | 8 ++++++++ .../{refcell.rs => interior_mutability.rs} | 15 +++++++++++++++ 2 files changed, 23 insertions(+) create mode 100644 tests/compile-fail/stacked_borrows/illegal_read6.rs rename tests/run-pass/stacked-borrows/{refcell.rs => interior_mutability.rs} (70%) diff --git a/tests/compile-fail/stacked_borrows/illegal_read6.rs b/tests/compile-fail/stacked_borrows/illegal_read6.rs new file mode 100644 index 0000000000000..dc37814729000 --- /dev/null +++ b/tests/compile-fail/stacked_borrows/illegal_read6.rs @@ -0,0 +1,8 @@ +// Creating a shared reference does not leak the data to raw pointers. +fn main() { unsafe { + let x = &mut 0; + let raw = x as *mut _; + let x = &mut *x; // kill `raw` + let _y = &*x; // this should not activate `raw` again + let _val = *raw; //~ ERROR borrow stack +} } diff --git a/tests/run-pass/stacked-borrows/refcell.rs b/tests/run-pass/stacked-borrows/interior_mutability.rs similarity index 70% rename from tests/run-pass/stacked-borrows/refcell.rs rename to tests/run-pass/stacked-borrows/interior_mutability.rs index dddc7089d02d0..33f44d0093ed4 100644 --- a/tests/run-pass/stacked-borrows/refcell.rs +++ b/tests/run-pass/stacked-borrows/interior_mutability.rs @@ -1,8 +1,12 @@ +#![feature(maybe_uninit, maybe_uninit_ref)] +use std::mem::MaybeUninit; +use std::cell::Cell; use std::cell::RefCell; fn main() { aliasing_mut_and_shr(); aliasing_frz_and_shr(); + into_interior_mutability(); } fn aliasing_mut_and_shr() { @@ -42,3 +46,14 @@ fn aliasing_frz_and_shr() { inner(&rc, &*bshr); assert_eq!(*rc.borrow(), 23); } + +// Getting a pointer into a union with interior mutability used to be tricky +// business (https://github.com/rust-lang/miri/issues/615), but it should work +// now. +fn into_interior_mutability() { + let mut x: MaybeUninit<(Cell, u32)> = MaybeUninit::uninit(); + x.as_ptr(); + x.write((Cell::new(0), 1)); + let ptr = unsafe { x.get_ref() }; + assert_eq!(ptr.1, 1); +} From 0a313183b1bfe6f2324ae2dc30673e1649cf3859 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 17 Apr 2019 15:23:20 +0200 Subject: [PATCH 0691/3747] bump Rust --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index dcee3ec5daa73..40e42e6886472 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -ee621f42329069c296b4c2066b3743cc4ff0f369 +efe2f32a6b8217425f361ec7c206910c611c03ee From e1ed855a441dc6f7234104b4c3a6751b23ae588d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 17 Apr 2019 16:02:42 +0200 Subject: [PATCH 0692/3747] more tests -- also one showing why we are not done yet --- .../stacked_borrows/shared_rw_borrows_are_weak1.rs | 14 ++++++++++++++ .../stacked_borrows/shared_rw_borrows_are_weak2.rs | 14 ++++++++++++++ tests/run-pass/stacked-borrows/stacked-borrows.rs | 13 +++++++++++++ 3 files changed, 41 insertions(+) create mode 100644 tests/compile-fail/stacked_borrows/shared_rw_borrows_are_weak1.rs create mode 100644 tests/compile-fail/stacked_borrows/shared_rw_borrows_are_weak2.rs diff --git a/tests/compile-fail/stacked_borrows/shared_rw_borrows_are_weak1.rs b/tests/compile-fail/stacked_borrows/shared_rw_borrows_are_weak1.rs new file mode 100644 index 0000000000000..d734caf1d97ae --- /dev/null +++ b/tests/compile-fail/stacked_borrows/shared_rw_borrows_are_weak1.rs @@ -0,0 +1,14 @@ +// We want to test that granting a SharedReadWrite will be added +// *below* an already granted Unique -- so writing to +// the SharedReadWrite will invalidate the Unique. + +use std::mem; +use std::cell::Cell; + +fn main() { unsafe { + let x = &mut Cell::new(0); + let y: &mut Cell = mem::transmute(&mut *x); // launder lifetime + let shr_rw = &*x; // thanks to interior mutability this will be a SharedReadWrite + shr_rw.set(1); + y.get_mut(); //~ ERROR borrow stack +} } diff --git a/tests/compile-fail/stacked_borrows/shared_rw_borrows_are_weak2.rs b/tests/compile-fail/stacked_borrows/shared_rw_borrows_are_weak2.rs new file mode 100644 index 0000000000000..942bb503db027 --- /dev/null +++ b/tests/compile-fail/stacked_borrows/shared_rw_borrows_are_weak2.rs @@ -0,0 +1,14 @@ +// We want to test that granting a SharedReadWrite will be added +// *below* an already granted SharedReadWrite -- so writing to +// the SharedReadWrite will invalidate the SharedReadWrite. + +use std::mem; +use std::cell::RefCell; + +fn main() { unsafe { + let x = &mut RefCell::new(0); + let y: &i32 = mem::transmute(&*x.borrow()); // launder lifetime + let shr_rw = &*x; // thanks to interior mutability this will be a SharedReadWrite + shr_rw.replace(1); + let _val = *y; //~ ERROR borrow stack +} } diff --git a/tests/run-pass/stacked-borrows/stacked-borrows.rs b/tests/run-pass/stacked-borrows/stacked-borrows.rs index 791e97f0eb1e1..7d84e33b3d6b3 100644 --- a/tests/run-pass/stacked-borrows/stacked-borrows.rs +++ b/tests/run-pass/stacked-borrows/stacked-borrows.rs @@ -11,6 +11,7 @@ fn main() { drop_after_sharing(); direct_mut_to_const_raw(); two_raw(); + shr_and_raw(); } // Deref a raw ptr to access a field of a large struct, where the field @@ -136,3 +137,15 @@ fn two_raw() { unsafe { *y1 += 2; *y2 += 1; } } + +// Make sure that creating a *mut does not invalidate existing shared references. +fn shr_and_raw() { /* unsafe { + use std::mem; + // FIXME: This is currently disabled because "as *mut _" incurs a reborrow. + let x = &mut 0; + let y1: &i32 = mem::transmute(&*x); // launder lifetimes + let y2 = x as *mut _; + let _val = *y1; + *y2 += 1; + // TODO: Once this works, add compile-fail test that tries to read from y1 again. +} */ } From abe8959339c7fafbc4cba85bda1f64a59f88a88e Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Wed, 17 Apr 2019 16:22:33 +0200 Subject: [PATCH 0693/3747] Apply suggestions from code review Co-Authored-By: RalfJung --- src/stacked_borrows.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 98b6ca6543f23..dc2a78d2960cb 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -296,7 +296,7 @@ impl<'tcx> Stack { // keep the items immediately above `granting_idx` that are compatible, and then pop the rest. // However, that kills off entire "branches" of pointer derivation too easily: // in `let raw = &mut *x as *mut _; let _val = *x;`, the second statement would pop the `Unique` - // from the reborrow of the first statement, and subequently also pop the `SharedReadWrite` for `raw`. + // from the reborrow of the first statement, and subsequently also pop the `SharedReadWrite` for `raw`. // This pattern occurs a lot in the standard library: create a raw pointer, then also create a shared // reference and use that. { @@ -343,7 +343,7 @@ impl<'tcx> Stack { // We must make sure there are no protected items remaining on the stack. // Also clear the stack, no more accesses are possible. - while let Some(item) = self.borrows.pop() { + for item in self.borrows.drain(..) { if let Some(call) = item.protector { if global.is_active(call) { return err!(MachineError(format!( @@ -394,7 +394,7 @@ impl<'tcx> Stack { // We use that to determine where to put the new item. let (derived_from_idx, _) = self.find_granting(access, derived_from) .ok_or_else(|| InterpError::MachineError(format!( - "no item to reborrow for {:?} from tag {} found in borrow stack", new.perm, derived_from, + "no item to reborrow for {:?} from tag {} found in borrow stack", new.perm, derived_from, )))?; // Compute where to put the new item. @@ -410,7 +410,7 @@ impl<'tcx> Stack { // and we'd allow write access without invalidating frozen shared references! // This ensures F2b for `SharedReadWrite` by adding the new item below any // potentially existing `SharedReadOnly`. - derived_from_idx+1 + derived_from_idx + 1 } else { // A "safe" reborrow for a pointer that actually expects some aliasing guarantees. // Here, creating a reference actually counts as an access, and pops incompatible From 39ecd05c46e96e606561d22163ea05be5b1fa6e2 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 17 Apr 2019 16:25:38 +0200 Subject: [PATCH 0694/3747] embrace find_map and some whitespace changes --- src/stacked_borrows.rs | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index dc2a78d2960cb..250def0c7ce6b 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -263,14 +263,13 @@ impl<'tcx> Stack { .rev() // search top-to-bottom // Return permission of first item that grants access. // We require a permission with the right tag, ensuring U3 and F3. - .filter_map(|(idx, item)| + .find_map(|(idx, item)| if item.perm.grants(access) && tag == item.tag { Some((idx, item.perm)) } else { None } ) - .next() } /// Test if a memory `access` using pointer tagged `tag` is granted. @@ -286,8 +285,8 @@ impl<'tcx> Stack { // Step 1: Find granting item. let (granting_idx, granting_perm) = self.find_granting(access, tag) .ok_or_else(|| InterpError::MachineError(format!( - "no item granting {} access to tag {} found in borrow stack", - access, tag, + "no item granting {} access to tag {} found in borrow stack", + access, tag, )))?; // Step 2: Remove everything incompatible above them. Make sure we do not remove protected @@ -313,9 +312,9 @@ impl<'tcx> Stack { if let Some(call) = item.protector { if global.is_active(call) { return err!(MachineError(format!( - "not granting {} access to tag {} because incompatible item {} is protected", - access, tag, item - ))); + "not granting {} access to tag {} because incompatible item {} is protected", + access, tag, item + ))); } } trace!("access: removing item {}", item); @@ -337,8 +336,8 @@ impl<'tcx> Stack { // Step 1: Find granting item. self.find_granting(AccessKind::Write, tag) .ok_or_else(|| InterpError::MachineError(format!( - "no item granting write access for deallocation to tag {} found in borrow stack", - tag, + "no item granting write access for deallocation to tag {} found in borrow stack", + tag, )))?; // We must make sure there are no protected items remaining on the stack. @@ -386,10 +385,10 @@ impl<'tcx> Stack { ) -> EvalResult<'tcx> { // Figure out which access `perm` corresponds to. let access = if new.perm.grants(AccessKind::Write) { - AccessKind::Write - } else { - AccessKind::Read - }; + AccessKind::Write + } else { + AccessKind::Read + }; // Now we figure out which item grants our parent (`derived_from`) this kind of access. // We use that to determine where to put the new item. let (derived_from_idx, _) = self.find_granting(access, derived_from) From 0e6deee76ef49e44d1089d6f2b8f9966a1c2db0a Mon Sep 17 00:00:00 2001 From: Tim Diekmann Date: Thu, 18 Apr 2019 01:17:19 +0200 Subject: [PATCH 0695/3747] Add `realloc` --- src/fn_call.rs | 17 +++++++++++++++++ tests/run-pass/realloc.rs | 31 +++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+) create mode 100644 tests/run-pass/realloc.rs diff --git a/src/fn_call.rs b/src/fn_call.rs index 64dcce161dd78..6706cc1fbc3c8 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -148,6 +148,23 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' } } + "realloc" => { + let ptr = this.read_scalar(args[0])?.to_ptr()?; + let new_size = this.read_scalar(args[1])?.to_usize(this)?; + let align = this.tcx.data_layout.pointer_align.abi; + let memory = this.memory_mut(); + let old_size = memory.get(ptr.alloc_id)?.bytes.len(); + let new_ptr = memory.reallocate( + ptr, + Size::from_bytes(old_size as u64), + align, + Size::from_bytes(new_size), + align, + MiriMemoryKind::C.into(), + )?; + this.write_scalar(Scalar::Ptr(new_ptr.with_default_tag()), dest)?; + } + "__rust_alloc" => { let size = this.read_scalar(args[0])?.to_usize(this)?; let align = this.read_scalar(args[1])?.to_usize(this)?; diff --git a/tests/run-pass/realloc.rs b/tests/run-pass/realloc.rs new file mode 100644 index 0000000000000..594fec717e974 --- /dev/null +++ b/tests/run-pass/realloc.rs @@ -0,0 +1,31 @@ +//ignore-windows: Uses POSIX APIs + +#![feature(rustc_private)] + +use core::slice; + +extern crate libc; + +fn main() { + unsafe { + // Use calloc for initialized memory + let p1 = libc::calloc(20, 1); + + // old size < new size + let p2 = libc::realloc(p1, 40); + let slice = slice::from_raw_parts(p2 as *const u8, 20); + assert_eq!(&slice, &[0_u8; 20]); + + // old size == new size + let p3 = libc::realloc(p2, 40); + let slice = slice::from_raw_parts(p3 as *const u8, 20); + assert_eq!(&slice, &[0_u8; 20]); + + // old size > new size + let p4 = libc::realloc(p3, 10); + let slice = slice::from_raw_parts(p4 as *const u8, 10); + assert_eq!(&slice, &[0_u8; 10]); + + libc::free(p4); + } +} From afb64232dbc30047e001c1a24abc9de485b78d04 Mon Sep 17 00:00:00 2001 From: Tim Diekmann Date: Thu, 18 Apr 2019 12:39:18 +0200 Subject: [PATCH 0696/3747] Fix for latest upstream update --- src/fn_call.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index 7b1ea73eb80f2..310b576419044 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -162,7 +162,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' align, MiriMemoryKind::C.into(), )?; - this.write_scalar(Scalar::Ptr(new_ptr.with_default_tag()), dest)?; + this.write_scalar(Scalar::Ptr(new_ptr), dest)?; } "__rust_alloc" => { From 7d9dc6e698b5bddc5e63f11fc6d6f60bb1cd4359 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 18 Apr 2019 13:20:01 +0200 Subject: [PATCH 0697/3747] test that creating a 2nd mutable ref from a NonNull invalidates the first --- .../stacked_borrows/mut_exclusive_violation2.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 tests/compile-fail/stacked_borrows/mut_exclusive_violation2.rs diff --git a/tests/compile-fail/stacked_borrows/mut_exclusive_violation2.rs b/tests/compile-fail/stacked_borrows/mut_exclusive_violation2.rs new file mode 100644 index 0000000000000..c6802c5ec94ee --- /dev/null +++ b/tests/compile-fail/stacked_borrows/mut_exclusive_violation2.rs @@ -0,0 +1,10 @@ +use std::ptr::NonNull; + +fn main() { unsafe { + let x = &mut 0; + let mut ptr1 = NonNull::from(x); + let mut ptr2 = ptr1.clone(); + let raw1 = ptr1.as_mut(); + let _raw2 = ptr2.as_mut(); + let _val = *raw1; //~ ERROR borrow stack +} } From 78e11058d32fbea1dee2645a9060813dd8be17de Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 18 Apr 2019 14:58:30 +0200 Subject: [PATCH 0698/3747] CI: build with debug assertions --- .appveyor.yml | 1 + .travis.yml | 10 ++++++---- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index 7db60514ada7a..5b77b1895a631 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -30,6 +30,7 @@ install: build_script: - set RUST_TEST_NOCAPTURE=1 - set RUST_BACKTRACE=1 + - set RUSTFLAGS="-C debug-assertions" # Build and install miri - cargo build --release --all-features --all-targets - cargo install --all-features --force --path . diff --git a/.travis.yml b/.travis.yml index 883404fb4a087..fd8c1260215dd 100644 --- a/.travis.yml +++ b/.travis.yml @@ -12,6 +12,12 @@ os: - osx dist: xenial +env: + global: + - RUST_TEST_NOCAPTURE=1 + - RUST_BACKTRACE=1 + - RUSTFLAGS="-C debug-assertions" + before_script: # Linux: install extra stuff for cross-compilation - if [[ "$TRAVIS_OS_NAME" == linux ]]; then sudo apt update && sudo apt install gcc-multilib; fi @@ -48,7 +54,3 @@ notifications: branches: only: - master -env: - global: - - RUST_TEST_NOCAPTURE=1 - - RUST_BACKTRACE=1 From 9ecc07c9b2df3cf88223d97ddea95a61a548e09e Mon Sep 17 00:00:00 2001 From: Tim Diekmann Date: Thu, 18 Apr 2019 15:20:32 +0200 Subject: [PATCH 0699/3747] Add handling for `nullptr` and `size == 0` --- src/fn_call.rs | 48 ++++++++++++++++++++++++++++----------- tests/run-pass/realloc.rs | 16 ++++++++++++- 2 files changed, 50 insertions(+), 14 deletions(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index 310b576419044..ae6aff10ac209 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -147,22 +147,44 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' )?; } } - "realloc" => { - let ptr = this.read_scalar(args[0])?.to_ptr()?; + let old_ptr = this.read_scalar(args[0])?.not_undef()?; let new_size = this.read_scalar(args[1])?.to_usize(this)?; let align = this.tcx.data_layout.pointer_align.abi; - let memory = this.memory_mut(); - let old_size = memory.get(ptr.alloc_id)?.bytes.len(); - let new_ptr = memory.reallocate( - ptr, - Size::from_bytes(old_size as u64), - align, - Size::from_bytes(new_size), - align, - MiriMemoryKind::C.into(), - )?; - this.write_scalar(Scalar::Ptr(new_ptr), dest)?; + if old_ptr.is_null_ptr(this) { + if new_size == 0 { + this.write_null(dest)?; + } else { + let new_ptr = this.memory_mut().allocate( + Size::from_bytes(new_size), + align, + MiriMemoryKind::C.into() + ); + this.write_scalar(Scalar::Ptr(new_ptr), dest)?; + } + } else { + let old_ptr = old_ptr.to_ptr()?; + let memory = this.memory_mut(); + let old_size = Size::from_bytes(memory.get(old_ptr.alloc_id)?.bytes.len() as u64); + if new_size == 0 { + memory.deallocate( + old_ptr, + Some((old_size, align)), + MiriMemoryKind::C.into(), + )?; + this.write_null(dest)?; + } else { + let new_ptr = memory.reallocate( + old_ptr, + old_size, + align, + Size::from_bytes(new_size), + align, + MiriMemoryKind::C.into(), + )?; + this.write_scalar(Scalar::Ptr(new_ptr), dest)?; + } + } } "__rust_alloc" => { diff --git a/tests/run-pass/realloc.rs b/tests/run-pass/realloc.rs index 594fec717e974..c23b3e645c703 100644 --- a/tests/run-pass/realloc.rs +++ b/tests/run-pass/realloc.rs @@ -2,7 +2,7 @@ #![feature(rustc_private)] -use core::slice; +use core::{slice, ptr}; extern crate libc; @@ -28,4 +28,18 @@ fn main() { libc::free(p4); } + + unsafe { + let p1 = libc::malloc(20); + + let p2 = libc::realloc(p1, 0); + assert!(p2.is_null()); + } + + unsafe { + let p1 = libc::realloc(ptr::null_mut(), 20); + assert!(!p1.is_null()); + + libc::free(p1); + } } From 36e99a1bdaee7ff07e03ac074a5b3f291a16e373 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 18 Apr 2019 16:16:22 +0200 Subject: [PATCH 0700/3747] remove some unneeded 'extern crate' --- src/bin/cargo-miri.rs | 2 -- test-cargo-miri/src/main.rs | 4 ---- 2 files changed, 6 deletions(-) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 8984a0bc4f915..b6c448cc04574 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -1,7 +1,5 @@ #![feature(inner_deref)] -extern crate cargo_metadata; - use std::fs::{self, File}; use std::io::{self, Write, BufRead}; use std::path::{PathBuf, Path}; diff --git a/test-cargo-miri/src/main.rs b/test-cargo-miri/src/main.rs index 32f1bac57d20f..9ec8e85887a79 100644 --- a/test-cargo-miri/src/main.rs +++ b/test-cargo-miri/src/main.rs @@ -1,7 +1,3 @@ -extern crate byteorder; -#[cfg(test)] -extern crate rand; - use byteorder::{BigEndian, ByteOrder}; fn main() { From 107b8b8ed920f286a21273785a1deeacf0d68799 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 18 Apr 2019 16:44:43 +0200 Subject: [PATCH 0701/3747] try to fix Windows CI --- .appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.appveyor.yml b/.appveyor.yml index 5b77b1895a631..438a65880b870 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -30,7 +30,7 @@ install: build_script: - set RUST_TEST_NOCAPTURE=1 - set RUST_BACKTRACE=1 - - set RUSTFLAGS="-C debug-assertions" + - set RUSTFLAGS=-C debug-assertions # Build and install miri - cargo build --release --all-features --all-targets - cargo install --all-features --force --path . From 0a5e54127243f4ff9f847e91356c3a73f18126f2 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 19 Apr 2019 08:36:05 +0200 Subject: [PATCH 0702/3747] two-phase-borrow comment --- src/stacked_borrows.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 250def0c7ce6b..bac35796ed135 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -625,6 +625,11 @@ trait EvalContextPrivExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, }; // Reborrow. + // TODO: With `two_phase == true`, this performs a weak reborrow for a `Unique`. That + // can lead to some possibly surprising effects, if the parent permission is + // `SharedReadWrite` then we now have a `Unique` in the middle of them, which "splits" + // them in terms of what remains valid when the `Unique` gets used. Is that really + // what we want? this.reborrow(place, size, kind, new_tag, /*force_weak:*/ two_phase, protect)?; let new_place = place.replace_tag(new_tag); // Handle two-phase borrows. From 287ffb8bba8d137c9dc04ade49c0bc65e0ab07f7 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 19 Apr 2019 08:46:09 +0200 Subject: [PATCH 0703/3747] test another version of 'creating a shared ref must not leak the Unique' --- .../stacked_borrows/illegal_read7.rs | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 tests/compile-fail/stacked_borrows/illegal_read7.rs diff --git a/tests/compile-fail/stacked_borrows/illegal_read7.rs b/tests/compile-fail/stacked_borrows/illegal_read7.rs new file mode 100644 index 0000000000000..25d0878c04553 --- /dev/null +++ b/tests/compile-fail/stacked_borrows/illegal_read7.rs @@ -0,0 +1,20 @@ +// Creating a shared reference does not leak the data to raw pointers, +// not even when interior mutability is involved. + +use std::cell::Cell; +use std::ptr; + +fn main() { unsafe { + let x = &mut Cell::new(0); + let raw = x as *mut Cell; + let x = &mut *raw; + let _shr = &*x; + // The state here is interesting because the top of the stack is [Unique, SharedReadWrite], + // just like if we had done `x as *mut _`. + // If we said that reading from a lower item is fine if the top item is `SharedReadWrite` + // (one way to maybe preserve a stack discipline), then we could now read from `raw` + // without invalidating `x`. That would be bad! It would mean that creating `shr` + // leaked `x` to `raw`. + let _val = ptr::read(raw); + let _val = *x.get_mut(); //~ ERROR borrow stack +} } From e4cecb10dbfed3e66d8cb58978b26e5e464291a9 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 19 Apr 2019 18:30:53 +0200 Subject: [PATCH 0704/3747] bump compiletest --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index bb86795270fa7..ce9c3cc4f29c4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -56,5 +56,5 @@ cargo_miri = ["cargo_metadata", "directories", "rustc_version"] rustc_tests = [] [dev-dependencies] -compiletest_rs = { version = "0.3.21", features = ["tmp", "stable"] } +compiletest_rs = { version = "0.3.22", features = ["tmp", "stable"] } colored = "1.6" From 2481d6091ac59bec4e54be04b7361596c80412df Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 19 Apr 2019 19:27:19 +0200 Subject: [PATCH 0705/3747] warn when cargo miri setup does not do anything --- src/bin/cargo-miri.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index b6c448cc04574..b24bf65629b00 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -172,6 +172,9 @@ fn ask(question: &str) { /// done all this already. fn setup(ask_user: bool) { if std::env::var("MIRI_SYSROOT").is_ok() { + if !ask_user { + println!("WARNING: MIRI_SYSROOT already set, not doing anything.") + } return; } From bf6b7aa550125aa6520e261da4ddc930239fa007 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 19 Apr 2019 19:53:42 +0200 Subject: [PATCH 0706/3747] rewirte development part of README --- README.md | 119 ++++++++++++++++++++++++++++++------------------------ 1 file changed, 66 insertions(+), 53 deletions(-) diff --git a/README.md b/README.md index 716c26c03a735..eb86d5b2ee317 100644 --- a/README.md +++ b/README.md @@ -113,63 +113,56 @@ find useful. ### Using a nightly rustc Miri heavily relies on internal rustc interfaces to execute MIR. Still, some -things (like adding support for a new intrinsic) can be done by working just on -the Miri side. +things (like adding support for a new intrinsic or a shim for an external +function being called) can be done by working just on the Miri side. -To prepare, make sure you are using a nightly Rust compiler. The most -convenient way is to install Miri using cargo, then you can easily run it on -other projects: - -```sh -rustup component remove miri # avoid having Miri installed twice -cargo +nightly install --path "$DIR" --force -cargo +nightly miri setup -``` - -(We are giving `+nightly` explicitly here all the time because it is important -that all of these commands get executed with the same toolchain.) +To prepare, make sure you are using a nightly Rust compiler. Then you should be +able to just `cargo build` Miri. In case this fails, your nightly might be incompatible with Miri master. The `rust-version` file contains the commit hash of rustc that Miri is currently tested against; you can use that to find a nightly that works or you might have to wait for the next nightly to get released. -If you want to use a different libstd (not the one that comes with the -nightly), you can do that by running +### Testing the Miri driver +[testing-miri]: #testing-the-miri-driver -```sh -XARGO_RUST_SRC=~/src/rust/rustc/src/ cargo +nightly miri setup +The Miri driver in the `miri` binary is the "heart" of Miri: it is basically a +version of `rustc` that, instead of compiling your code, runs it. It accepts +all the same flags as `rustc` (though the ones only affecting code generation +and linking obviously will have no effect) [and more][miri-flags]. + +To run the Miri driver, you need to have the `MIRI_SYSROOT` environment variable +set to an appropriate sysroot. You can generate such a sysroot with the +following incantation: + +``` +cargo run --bin cargo-miri -- miri setup ``` -Either way, you can now do `cargo +nightly miri run` to run Miri with your -local changes on whatever project you are debugging. +This basically runs the `cargo-miri` binary (which backs the `cargo miri` +subcommand) with `cargo`, and asks it to `setup`. It should in the end print +the directory where the libstd was built. In the following, we will assume it +is `~/.cache/miri/HOST`; you may have to adjust that if you are not using Linux. -`cargo miri setup` should end in printing the directory where the libstd was -built. For the next step to work, set that as your `MIRI_SYSROOT` environment -variable: +Now you can run the driver directly using ```sh -export MIRI_SYSROOT=~/.cache/miri/HOST # or whatever the previous command said +MIRI_SYSROOT=~/.cache/miri/HOST cargo run tests/run-pass/format.rs # or whatever test you like ``` -### Testing Miri +and you can run the test suite using -Instead of running an entire project using `cargo miri`, you can also use the -Miri "driver" directly to run just a single file. That can be easier during -debugging. - -```sh -cargo run tests/run-pass/format.rs # or whatever test you like ``` +cargo test +``` + +We recommend adding the `--release` flag to make tests run faster. -You can also run the test suite with `cargo test --release`. `cargo test ---release FILTER` only runs those tests that contain `FILTER` in their filename -(including the base directory, e.g. `cargo test --release fail` will run all -compile-fail tests). We recommend using `--release` to make test running take -less time. +`cargo test --release FILTER` only runs those tests that contain `FILTER` in +their filename (including the base directory, e.g. `cargo test --release fail` +will run all compile-fail tests). -Now you are set up! You can write a failing test case, and tweak miri until it -fails no more. You can get a trace of which MIR statements are being executed by setting the `MIRI_LOG` environment variable. For example: @@ -177,26 +170,43 @@ You can get a trace of which MIR statements are being executed by setting the MIRI_LOG=info cargo run tests/run-pass/vecs.rs ``` -Setting `MIRI_LOG` like this will configure logging for miri itself as well as +Setting `MIRI_LOG` like this will configure logging for Miri itself as well as the `rustc::mir::interpret` and `rustc_mir::interpret` modules in rustc. You -can also do more targeted configuration, e.g. to debug the stacked borrows -implementation: +can also do more targeted configuration, e.g. the following helps debug the +stacked borrows implementation: + ```sh MIRI_LOG=rustc_mir::interpret=info,miri::stacked_borrows cargo run tests/run-pass/vecs.rs ``` In addition, you can set `MIRI_BACKTRACE=1` to get a backtrace of where an -evaluation error was originally created. +evaluation error was originally raised. + +### Testing `cargo miri` + +Working with the driver directly gives you full control, but you also lose all +the convenience provided by cargo. Once your test case depends on a crate, it +is probably easier to test it with the cargo wrapper. You can install your +development version of Miri using + +``` +cargo install --path . --force +``` + +and then you can use it as if it was installed by `rustup`. Make sure you use +the same toolchain when calling `cargo miri` that you used when installing Miri! +There's a test for the cargo wrapper in the `test-cargo-miri` directory; run +`./run-test.py` in there to execute it. ### Using a locally built rustc -Since the heart of Miri (the main interpreter engine) lives in rustc, working on -Miri will often require using a locally built rustc. The bug you want to fix -may actually be on the rustc side, or you just need to get more detailed trace -of the execution than what is possible with release builds -- in both cases, you -should develop miri against a rustc you compiled yourself, with debug assertions -(and hence tracing) enabled. +A big part of the Miri driver lives in rustc, so working on Miri will sometimes +require using a locally built rustc. The bug you want to fix may actually be on +the rustc side, or you just need to get more detailed trace of the execution +than what is possible with release builds -- in both cases, you should develop +miri against a rustc you compiled yourself, with debug assertions (and hence +tracing) enabled. The setup for a local rustc works as follows: ```sh @@ -216,18 +226,21 @@ rustup override set custom ``` With this, you should now have a working development setup! See -["Testing Miri"](#testing-miri) above for how to proceed. +[above][testing-miri] for how to proceed working with the Miri driver. Notice +that rustc's sysroot is already built for Miri in this case, so you can set +`MIRI_SYSROOT=$(rustc --print sysroot)`. Running `cargo miri` in this setup is a bit more complicated, because the Miri -binary you just created does not actually run without some environment variables. -But you can contort cargo into calling `cargo miri` the right way for you: +binary you just created needs help to find the libraries it links against. On +Linux, you can set the rpath to make this "just work": ```sh -# in some other project's directory, to run `cargo miri test`: -MIRI_SYSROOT=$(rustc +custom --print sysroot) cargo +custom run --manifest-path /path/to/miri/Cargo.toml --bin cargo-miri --release -- miri test +export RUSTFLAGS="-C link-args=-Wl,-rpath,$(rustc --print sysroot)/lib/rustlib/x86_64-unknown-linux-gnu/lib" +cargo install --path . --force ``` ### Miri `-Z` flags and environment variables +[miri-flags]: #miri--z-flags-and-environment-variables Several `-Z` flags are relevant for Miri: From 677bd6f65646a6610ec2e3d11b203392477e3dd8 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 18 Apr 2019 11:54:21 +0200 Subject: [PATCH 0707/3747] add LinkedList test and mention the bug Miri found there --- README.md | 1 + tests/run-pass/linked-list.rs | 33 +++++++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+) create mode 100644 tests/run-pass/linked-list.rs diff --git a/README.md b/README.md index 716c26c03a735..464c1c33c2d33 100644 --- a/README.md +++ b/README.md @@ -297,6 +297,7 @@ Miri has already found a number of bugs in the Rust standard library, which we c * [Futures turning a shared reference into a mutable one](https://github.com/rust-lang/rust/pull/56319) * [`str` turning a shared reference into a mutable one](https://github.com/rust-lang/rust/pull/58200) * [`BTreeMap` creating mutable references that overlap with shared references](https://github.com/rust-lang/rust/pull/58431) +* [`LinkedList` creating overlapping mutable references](https://github.com/rust-lang/rust/pull/60072) ## License diff --git a/tests/run-pass/linked-list.rs b/tests/run-pass/linked-list.rs new file mode 100644 index 0000000000000..f1d21728b2f00 --- /dev/null +++ b/tests/run-pass/linked-list.rs @@ -0,0 +1,33 @@ +#![feature(linked_list_extras)] +use std::collections::LinkedList; + +fn list_from(v: &[T]) -> LinkedList { + v.iter().cloned().collect() +} + +fn main() { + let mut m = list_from(&[0, 2, 4, 6, 8]); + let len = m.len(); + { + let mut it = m.iter_mut(); + it.insert_next(-2); + loop { + match it.next() { + None => break, + Some(elt) => { + it.insert_next(*elt + 1); + match it.peek_next() { + Some(x) => assert_eq!(*x, *elt + 2), + None => assert_eq!(8, *elt), + } + } + } + } + it.insert_next(0); + it.insert_next(1); + } + + assert_eq!(m.len(), 3 + len * 2); + assert_eq!(m.into_iter().collect::>(), + [-2, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1]); +} From 791abb7a7e87c1ab20616d37184b661acc425753 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 19 Apr 2019 23:08:35 +0200 Subject: [PATCH 0708/3747] bump Rust version --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 40e42e6886472..f0c4e551b3a58 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -efe2f32a6b8217425f361ec7c206910c611c03ee +130dc3e7dac132cf30272ccf4541b512828e2108 From a20719cec68a7c1babcbe4ccee2633c1ffc89aed Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 20 Apr 2019 18:36:43 +0200 Subject: [PATCH 0709/3747] add section on the no MIR error --- README.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/README.md b/README.md index eb86d5b2ee317..64bf361d54b3e 100644 --- a/README.md +++ b/README.md @@ -105,6 +105,13 @@ You may be running `cargo miri` with a different compiler version than the one used to build the custom libstd that Miri uses, and Miri failed to detect that. Try deleting `~/.cache/miri`. +#### "no mir for `std::rt::lang_start_internal`" + +This means the sysroot you are using was not compiled with Miri in mind. This +should never happen when you use `cargo miri` because that takes care of setting +up the sysroot. If you are using `miri` (the Miri driver) directly, see +[below][testing-miri] for how to set up the sysroot. + ## Development and Debugging If you want to hack on miri yourself, great! Here are some resources you might From 0694435650adbd5965a30a14771bc142919bbfe4 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 19 Apr 2019 17:25:27 +0200 Subject: [PATCH 0710/3747] implement exit implement exit code via new error kind --- rust-version | 2 +- src/fn_call.rs | 6 +++++- src/lib.rs | 14 ++++++++++---- tests/run-pass/exit.rs | 3 +++ 4 files changed, 19 insertions(+), 6 deletions(-) create mode 100644 tests/run-pass/exit.rs diff --git a/rust-version b/rust-version index f0c4e551b3a58..fae9b1d599a42 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -130dc3e7dac132cf30272ccf4541b512828e2108 +9224be5fa39f6170f6e046342976efee5453a1ff diff --git a/src/fn_call.rs b/src/fn_call.rs index ae6aff10ac209..2f827510aa5d0 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -69,11 +69,15 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' let link_name = link_name.get().trim_end_matches("$UNIX2003"); let tcx = &{this.tcx.tcx}; - // First: functions that could diverge. + // First: functions that diverge. match link_name { "__rust_start_panic" | "panic_impl" => { return err!(MachineError("the evaluated program panicked".to_string())); } + "exit" => { + let code = this.read_scalar(args[0])?.to_i32()?; + return err!(Exit(code)); + } _ => if dest.is_none() { return err!(Unimplemented( format!("can't call diverging foreign function: {}", link_name), diff --git a/src/lib.rs b/src/lib.rs index 3dbe922999dab..683eee0cb7a38 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -242,6 +242,13 @@ pub fn eval_main<'a, 'tcx: 'a>( } } Err(mut e) => { + // Special treatment for some error kinds + let msg = match e.kind { + InterpError::Exit(code) => std::process::exit(code), + InterpError::NoMirFor(..) => + format!("{}. Did you set `MIRI_SYSROOT` to a Miri-enabled sysroot? You can prepare one with `cargo miri setup`.", e), + _ => e.to_string() + }; e.print_backtrace(); if let Some(frame) = ecx.stack().last() { let block = &frame.mir.basic_blocks()[frame.block]; @@ -251,11 +258,10 @@ pub fn eval_main<'a, 'tcx: 'a>( block.terminator().source_info.span }; - let e = e.to_string(); - let msg = format!("constant evaluation error: {}", e); + let msg = format!("Miri evaluation error: {}", msg); let mut err = struct_error(ecx.tcx.tcx.at(span), msg.as_str()); let frames = ecx.generate_stacktrace(None); - err.span_label(span, e); + err.span_label(span, msg); // We iterate with indices because we need to look at the next frame (the caller). for idx in 0..frames.len() { let frame_info = &frames[idx]; @@ -269,7 +275,7 @@ pub fn eval_main<'a, 'tcx: 'a>( } err.emit(); } else { - ecx.tcx.sess.err(&e.to_string()); + ecx.tcx.sess.err(&msg); } for (i, frame) in ecx.stack().iter().enumerate() { diff --git a/tests/run-pass/exit.rs b/tests/run-pass/exit.rs new file mode 100644 index 0000000000000..d93f0045377ef --- /dev/null +++ b/tests/run-pass/exit.rs @@ -0,0 +1,3 @@ +fn main() { + std::process::exit(0) +} From d410b131395ee0ba0cc02d6ca8cedc04e7c1fded Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 21 Apr 2019 13:18:05 +0200 Subject: [PATCH 0711/3747] fix compile-fail ref files --- tests/compile-fail/ctlz_nonzero.rs | 2 +- tests/compile-fail/cttz_nonzero.rs | 2 +- tests/compile-fail/deref_fn_ptr.rs | 2 +- tests/compile-fail/getrandom.rs | 2 +- tests/compile-fail/never_transmute_humans.rs | 3 +-- tests/compile-fail/null_pointer_deref.rs | 2 +- tests/compile-fail/null_pointer_deref_zst.rs | 2 +- tests/compile-fail/null_pointer_write.rs | 2 +- tests/compile-fail/null_pointer_write_zst.rs | 2 +- 9 files changed, 9 insertions(+), 10 deletions(-) diff --git a/tests/compile-fail/ctlz_nonzero.rs b/tests/compile-fail/ctlz_nonzero.rs index 86fd5ec46c202..61f41363589ca 100644 --- a/tests/compile-fail/ctlz_nonzero.rs +++ b/tests/compile-fail/ctlz_nonzero.rs @@ -10,6 +10,6 @@ pub fn main() { unsafe { use crate::rusti::*; - ctlz_nonzero(0u8); //~ ERROR constant evaluation error: ctlz_nonzero called on 0 + ctlz_nonzero(0u8); //~ ERROR ctlz_nonzero called on 0 } } diff --git a/tests/compile-fail/cttz_nonzero.rs b/tests/compile-fail/cttz_nonzero.rs index a6c3b03cfb5c1..69d2874ce9269 100644 --- a/tests/compile-fail/cttz_nonzero.rs +++ b/tests/compile-fail/cttz_nonzero.rs @@ -10,6 +10,6 @@ pub fn main() { unsafe { use crate::rusti::*; - cttz_nonzero(0u8); //~ ERROR constant evaluation error: cttz_nonzero called on 0 + cttz_nonzero(0u8); //~ ERROR cttz_nonzero called on 0 } } diff --git a/tests/compile-fail/deref_fn_ptr.rs b/tests/compile-fail/deref_fn_ptr.rs index 68826a6ff03d5..ed2ac60f43fe3 100644 --- a/tests/compile-fail/deref_fn_ptr.rs +++ b/tests/compile-fail/deref_fn_ptr.rs @@ -2,7 +2,7 @@ fn f() {} fn main() { let x: u8 = unsafe { - *std::mem::transmute::(f) //~ ERROR constant evaluation error: tried to dereference a function pointer + *std::mem::transmute::(f) //~ ERROR tried to dereference a function pointer }; panic!("this should never print: {}", x); } diff --git a/tests/compile-fail/getrandom.rs b/tests/compile-fail/getrandom.rs index d54c95c82385c..246893a5c640f 100644 --- a/tests/compile-fail/getrandom.rs +++ b/tests/compile-fail/getrandom.rs @@ -8,6 +8,6 @@ fn main() { let mut buf = [0u8; 5]; unsafe { libc::syscall(libc::SYS_getrandom, buf.as_mut_ptr() as *mut libc::c_void, 5 as libc::size_t, 0 as libc::c_uint); - //~^ ERROR constant evaluation error: miri does not support gathering system entropy in deterministic mode! + //~^ ERROR miri does not support gathering system entropy in deterministic mode! } } diff --git a/tests/compile-fail/never_transmute_humans.rs b/tests/compile-fail/never_transmute_humans.rs index 34203338696cb..ab25b1ffc7467 100644 --- a/tests/compile-fail/never_transmute_humans.rs +++ b/tests/compile-fail/never_transmute_humans.rs @@ -7,7 +7,6 @@ struct Human; fn main() { let _x: ! = unsafe { - std::mem::transmute::(Human) //~ ERROR constant evaluation error - //^~ NOTE entered unreachable code + std::mem::transmute::(Human) //~ ERROR entered unreachable code }; } diff --git a/tests/compile-fail/null_pointer_deref.rs b/tests/compile-fail/null_pointer_deref.rs index 08ea63f58ff59..8bf0392b8903b 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 constant evaluation error: invalid use of NULL 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/null_pointer_deref_zst.rs b/tests/compile-fail/null_pointer_deref_zst.rs index a8b23368616ea..b2800e96292d7 100644 --- a/tests/compile-fail/null_pointer_deref_zst.rs +++ b/tests/compile-fail/null_pointer_deref_zst.rs @@ -1,4 +1,4 @@ fn main() { - let x: () = unsafe { *std::ptr::null() }; //~ ERROR constant evaluation error: invalid use of NULL pointer + let x: () = unsafe { *std::ptr::null() }; //~ ERROR invalid use of NULL pointer panic!("this should never print: {:?}", x); } diff --git a/tests/compile-fail/null_pointer_write.rs b/tests/compile-fail/null_pointer_write.rs index affb040bdedfa..1577b2a1b13bc 100644 --- a/tests/compile-fail/null_pointer_write.rs +++ b/tests/compile-fail/null_pointer_write.rs @@ -1,3 +1,3 @@ fn main() { - unsafe { *std::ptr::null_mut() = 0i32 }; //~ ERROR constant evaluation error: invalid use of NULL pointer + unsafe { *std::ptr::null_mut() = 0i32 }; //~ ERROR invalid use of NULL pointer } diff --git a/tests/compile-fail/null_pointer_write_zst.rs b/tests/compile-fail/null_pointer_write_zst.rs index 433c69dbb032b..7e91d736bd295 100644 --- a/tests/compile-fail/null_pointer_write_zst.rs +++ b/tests/compile-fail/null_pointer_write_zst.rs @@ -2,5 +2,5 @@ fn main() { // Not using the () type here, as writes of that type do not even have MIR generated. // Also not assigning directly as that's array initialization, not assignment. let zst_val = [1u8; 0]; - unsafe { *std::ptr::null_mut() = zst_val }; //~ ERROR constant evaluation error: invalid use of NULL pointer + unsafe { *std::ptr::null_mut() = zst_val }; //~ ERROR invalid use of NULL pointer } From 6a6c0cd5f0f2e7283f2271f2188280e5ce9b9e69 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 21 Apr 2019 13:25:24 +0200 Subject: [PATCH 0712/3747] implement ExitProcess for Windows --- src/fn_call.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/fn_call.rs b/src/fn_call.rs index 2f827510aa5d0..84033e9e83074 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -78,6 +78,10 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' let code = this.read_scalar(args[0])?.to_i32()?; return err!(Exit(code)); } + "ExitProcess" => { + let code = this.read_scalar(args[0])?.to_u32()?; + return err!(Exit(code as i32)); + } _ => if dest.is_none() { return err!(Unimplemented( format!("can't call diverging foreign function: {}", link_name), From a87a7338e64001f60704a7bdd7d2ed6bfc64c397 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 21 Apr 2019 13:43:53 +0200 Subject: [PATCH 0713/3747] test System/Global allocator API: alloc_zeroed, realloc --- tests/run-pass/env.rs | 2 +- tests/run-pass/hashmap.rs | 9 ++++----- tests/run-pass/heap_allocator.rs | 30 ++++++++++++++++++++++++++++-- 3 files changed, 33 insertions(+), 8 deletions(-) diff --git a/tests/run-pass/env.rs b/tests/run-pass/env.rs index 0ca63e148fdbb..91e15f249d452 100644 --- a/tests/run-pass/env.rs +++ b/tests/run-pass/env.rs @@ -1,4 +1,4 @@ -//ignore-windows: env var emulation not implemented on Windows +//ignore-windows: TODO env var emulation stubbed out on Windows use std::env; diff --git a/tests/run-pass/hashmap.rs b/tests/run-pass/hashmap.rs index 796e63c81a412..25a816bcf2454 100644 --- a/tests/run-pass/hashmap.rs +++ b/tests/run-pass/hashmap.rs @@ -27,13 +27,12 @@ fn test_map(mut map: HashMap) { } fn main() { - if cfg!(not(target_os = "macos")) { - let map: HashMap = HashMap::default(); - test_map(map); - } else { - // TODO: Implement random number generation on OS X. + if cfg!(target_os = "macos") { // TODO: Implement random number generation on OS X. // Until then, use a deterministic map. let map : HashMap> = HashMap::default(); test_map(map); + } else { + let map: HashMap = HashMap::default(); + test_map(map); } } diff --git a/tests/run-pass/heap_allocator.rs b/tests/run-pass/heap_allocator.rs index bfed725a497cc..b201f24e25634 100644 --- a/tests/run-pass/heap_allocator.rs +++ b/tests/run-pass/heap_allocator.rs @@ -1,9 +1,32 @@ -//ignore-windows: inspects allocation base address on Windows - #![feature(allocator_api)] use std::ptr::NonNull; use std::alloc::{Global, Alloc, Layout, System}; +use std::slice; + +fn check_alloc(mut allocator: T) { unsafe { + let layout = Layout::from_size_align(20, 4).unwrap(); + let a = allocator.alloc(layout).unwrap(); + allocator.dealloc(a, layout); + + let p1 = allocator.alloc_zeroed(layout).unwrap(); + + let p2 = allocator.realloc(p1, Layout::from_size_align(20, 4).unwrap(), 40).unwrap(); + let slice = slice::from_raw_parts(p2.as_ptr(), 20); + assert_eq!(&slice, &[0_u8; 20]); + + // old size == new size + let p3 = allocator.realloc(p2, Layout::from_size_align(40, 4).unwrap(), 40).unwrap(); + let slice = slice::from_raw_parts(p3.as_ptr(), 20); + assert_eq!(&slice, &[0_u8; 20]); + + // old size > new size + let p4 = allocator.realloc(p3, Layout::from_size_align(40, 4).unwrap(), 10).unwrap(); + let slice = slice::from_raw_parts(p4.as_ptr(), 10); + assert_eq!(&slice, &[0_u8; 10]); + + allocator.dealloc(p4, Layout::from_size_align(10, 4).unwrap()); +} } fn check_overalign_requests(mut allocator: T) { let size = 8; @@ -50,6 +73,9 @@ fn box_to_global() { } fn main() { + check_alloc(System); + check_alloc(Global); + #[cfg(not(target_os = "windows"))] // TODO: Inspects allocation base address on Windows; needs intptrcast model check_overalign_requests(System); check_overalign_requests(Global); global_to_box(); From e4970fe6ffa3052d6b1a880c934d4465bf656df9 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 21 Apr 2019 14:34:30 +0200 Subject: [PATCH 0714/3747] Windows: implement heap functions --- src/fn_call.rs | 178 ++++++++++++++++++++++++++++++++----------------- 1 file changed, 117 insertions(+), 61 deletions(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index ae6aff10ac209..9789a76c6393e 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -50,6 +50,86 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' Ok(Some(this.load_mir(instance.def)?)) } + fn malloc( + &mut self, + size: u64, + zero_init: bool, + ) -> Scalar { + let this = self.eval_context_mut(); + let tcx = &{this.tcx.tcx}; + if size == 0 { + Scalar::from_int(0, this.pointer_size()) + } else { + let align = this.tcx.data_layout.pointer_align.abi; + let ptr = this.memory_mut().allocate(Size::from_bytes(size), align, MiriMemoryKind::C.into()); + if zero_init { + // We just allocated this, the access cannot fail + this.memory_mut() + .get_mut(ptr.alloc_id).unwrap() + .write_repeat(tcx, ptr, 0, Size::from_bytes(size)).unwrap(); + } + Scalar::Ptr(ptr) + } + } + + fn free( + &mut self, + ptr: Scalar, + ) -> EvalResult<'tcx> { + let this = self.eval_context_mut(); + if !ptr.is_null_ptr(this) { + this.memory_mut().deallocate( + ptr.to_ptr()?, + None, + MiriMemoryKind::C.into(), + )?; + } + Ok(()) + } + + fn realloc( + &mut self, + old_ptr: Scalar, + new_size: u64, + ) -> EvalResult<'tcx, Scalar> { + let this = self.eval_context_mut(); + let align = this.tcx.data_layout.pointer_align.abi; + if old_ptr.is_null_ptr(this) { + if new_size == 0 { + Ok(Scalar::from_int(0, this.pointer_size())) + } else { + let new_ptr = this.memory_mut().allocate( + Size::from_bytes(new_size), + align, + MiriMemoryKind::C.into() + ); + Ok(Scalar::Ptr(new_ptr)) + } + } else { + let old_ptr = old_ptr.to_ptr()?; + let memory = this.memory_mut(); + let old_size = Size::from_bytes(memory.get(old_ptr.alloc_id)?.bytes.len() as u64); + if new_size == 0 { + memory.deallocate( + old_ptr, + Some((old_size, align)), + MiriMemoryKind::C.into(), + )?; + Ok(Scalar::from_int(0, this.pointer_size())) + } else { + let new_ptr = memory.reallocate( + old_ptr, + old_size, + align, + Size::from_bytes(new_size), + align, + MiriMemoryKind::C.into(), + )?; + Ok(Scalar::Ptr(new_ptr)) + } + } + } + /// Emulates calling a foreign item, failing if the item is not supported. /// This function will handle `goto_block` if needed. fn emulate_foreign_item( @@ -87,28 +167,15 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' match link_name { "malloc" => { let size = this.read_scalar(args[0])?.to_usize(this)?; - if size == 0 { - this.write_null(dest)?; - } else { - let align = this.tcx.data_layout.pointer_align.abi; - let ptr = this.memory_mut().allocate(Size::from_bytes(size), align, MiriMemoryKind::C.into()); - this.write_scalar(Scalar::Ptr(ptr), dest)?; - } + let res = this.malloc(size, /*zero_init:*/ false); + this.write_scalar(res, dest)?; } "calloc" => { let items = this.read_scalar(args[0])?.to_usize(this)?; let len = this.read_scalar(args[1])?.to_usize(this)?; - let bytes = items.checked_mul(len).ok_or_else(|| InterpError::Overflow(mir::BinOp::Mul))?; - - if bytes == 0 { - this.write_null(dest)?; - } else { - let size = Size::from_bytes(bytes); - let align = this.tcx.data_layout.pointer_align.abi; - let ptr = this.memory_mut().allocate(size, align, MiriMemoryKind::C.into()); - this.memory_mut().get_mut(ptr.alloc_id)?.write_repeat(tcx, ptr, 0, size)?; - this.write_scalar(Scalar::Ptr(ptr), dest)?; - } + let size = items.checked_mul(len).ok_or_else(|| InterpError::Overflow(mir::BinOp::Mul))?; + let res = this.malloc(size, /*zero_init:*/ true); + this.write_scalar(res, dest)?; } "posix_memalign" => { let ret = this.deref_operand(args[0])?; @@ -136,55 +203,15 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' } this.write_null(dest)?; } - "free" => { let ptr = this.read_scalar(args[0])?.not_undef()?; - if !ptr.is_null_ptr(this) { - this.memory_mut().deallocate( - ptr.to_ptr()?, - None, - MiriMemoryKind::C.into(), - )?; - } + this.free(ptr)?; } "realloc" => { let old_ptr = this.read_scalar(args[0])?.not_undef()?; let new_size = this.read_scalar(args[1])?.to_usize(this)?; - let align = this.tcx.data_layout.pointer_align.abi; - if old_ptr.is_null_ptr(this) { - if new_size == 0 { - this.write_null(dest)?; - } else { - let new_ptr = this.memory_mut().allocate( - Size::from_bytes(new_size), - align, - MiriMemoryKind::C.into() - ); - this.write_scalar(Scalar::Ptr(new_ptr), dest)?; - } - } else { - let old_ptr = old_ptr.to_ptr()?; - let memory = this.memory_mut(); - let old_size = Size::from_bytes(memory.get(old_ptr.alloc_id)?.bytes.len() as u64); - if new_size == 0 { - memory.deallocate( - old_ptr, - Some((old_size, align)), - MiriMemoryKind::C.into(), - )?; - this.write_null(dest)?; - } else { - let new_ptr = memory.reallocate( - old_ptr, - old_size, - align, - Size::from_bytes(new_size), - align, - MiriMemoryKind::C.into(), - )?; - this.write_scalar(Scalar::Ptr(new_ptr), dest)?; - } - } + let res = this.realloc(old_ptr, new_size)?; + this.write_scalar(res, dest)?; } "__rust_alloc" => { @@ -687,6 +714,35 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' }, // Windows API stubs. + // HANDLE = isize + // DWORD = ULONG = u32 + "GetProcessHeap" => { + // Just fake a HANDLE + this.write_scalar(Scalar::from_int(1, this.pointer_size()), dest)?; + } + "HeapAlloc" => { + let _handle = this.read_scalar(args[0])?.to_isize(this)?; + let flags = this.read_scalar(args[1])?.to_u32()?; + let size = this.read_scalar(args[2])?.to_usize(this)?; + let zero_init = (flags & 0x00000008) != 0; // HEAP_ZERO_MEMORY + let res = this.malloc(size, zero_init); + this.write_scalar(res, dest)?; + } + "HeapFree" => { + let _handle = this.read_scalar(args[0])?.to_isize(this)?; + let _flags = this.read_scalar(args[1])?.to_u32()?; + let ptr = this.read_scalar(args[2])?.not_undef()?; + this.free(ptr)?; + } + "HeapReAlloc" => { + let _handle = this.read_scalar(args[0])?.to_isize(this)?; + let _flags = this.read_scalar(args[1])?.to_u32()?; + let ptr = this.read_scalar(args[2])?.not_undef()?; + let size = this.read_scalar(args[3])?.to_usize(this)?; + let res = this.realloc(ptr, size)?; + this.write_scalar(res, dest)?; + } + "SetLastError" => { let err = this.read_scalar(args[0])?.to_u32()?; this.machine.last_error = err; From 7bb461362e3078f471b5d25c27c01c60c55f1318 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 21 Apr 2019 22:35:47 +0200 Subject: [PATCH 0715/3747] Travis: test cargo miri on foreign arch --- test-cargo-miri/run-test.py | 22 +++++++++++++++++----- tests/compiletest.rs | 2 +- travis.sh | 22 +++++++++++++++------- 3 files changed, 33 insertions(+), 13 deletions(-) diff --git a/test-cargo-miri/run-test.py b/test-cargo-miri/run-test.py index f1412dbf3969e..ec77875d4900f 100755 --- a/test-cargo-miri/run-test.py +++ b/test-cargo-miri/run-test.py @@ -5,12 +5,18 @@ and the working directory to contain the cargo-miri-test project. ''' -import sys, subprocess +import sys, subprocess, os def fail(msg): print("TEST FAIL: {}".format(msg)) sys.exit(1) +def cargo_miri(cmd): + args = ["cargo", "miri", cmd, "-q"] + if 'MIRI_TEST_TARGET' in os.environ: + args += ["--target", os.environ['MIRI_TEST_TARGET']] + return args + def test(name, cmd, stdout_ref, stderr_ref): print("==> Testing `{}` <==".format(name)) ## Call `cargo miri`, capture all output @@ -36,16 +42,22 @@ def test(name, cmd, stdout_ref, stderr_ref): fail("stderr does not match reference") def test_cargo_miri_run(): - test("cargo miri run", ["cargo", "miri", "run", "-q"], "stdout.ref", "stderr.ref") + test("cargo miri run", + cargo_miri("run"), + "stdout.ref", "stderr.ref" + ) test("cargo miri run (with arguments)", - ["cargo", "miri", "run", "-q", "--", "--", "hello world", '"hello world"'], + cargo_miri("run") + ["--", "--", "hello world", '"hello world"'], "stdout.ref", "stderr.ref2" ) def test_cargo_miri_test(): - test("cargo miri test", ["cargo", "miri", "test", "-q", "--", "-Zmiri-seed=feed"], "test.stdout.ref", "test.stderr.ref") + test("cargo miri test", + cargo_miri("test") + ["--", "-Zmiri-seed=feed"], + "test.stdout.ref", "test.stderr.ref" + ) test("cargo miri test (with filter)", - ["cargo", "miri", "test", "-q", "--", "--", "impl"], + cargo_miri("test") + ["--", "--", "impl"], "test.stdout.ref2", "test.stderr.ref" ) diff --git a/tests/compiletest.rs b/tests/compiletest.rs index ff83eca1c9f0b..7f2c8966472fb 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -101,7 +101,7 @@ fn get_host() -> String { } fn get_target() -> String { - std::env::var("MIRI_COMPILETEST_TARGET").unwrap_or_else(|_| get_host()) + std::env::var("MIRI_TEST_TARGET").unwrap_or_else(|_| get_host()) } fn run_pass_miri(opt: bool) { diff --git a/travis.sh b/travis.sh index 8951cdc89644f..77768cf031148 100755 --- a/travis.sh +++ b/travis.sh @@ -3,13 +3,14 @@ set -euo pipefail # Determine configuration if [ "$TRAVIS_OS_NAME" == osx ]; then - export MIRI_SYSROOT_BASE=~/Library/Caches/miri.miri.miri/ + MIRI_SYSROOT_BASE=~/Library/Caches/miri.miri.miri/ FOREIGN_TARGET=i686-apple-darwin else - export MIRI_SYSROOT_BASE=~/.cache/miri/ + MIRI_SYSROOT_BASE=~/.cache/miri/ FOREIGN_TARGET=i686-unknown-linux-gnu fi +# Prepare echo "Build and install miri" cargo build --release --all-features --all-targets cargo install --all-features --force --path . @@ -20,11 +21,18 @@ cargo miri setup cargo miri setup --target "$FOREIGN_TARGET" echo -echo "Test miri with full MIR, on the host and other architectures" -MIRI_SYSROOT="$MIRI_SYSROOT_BASE"/HOST cargo test --release --all-features -MIRI_SYSROOT="$MIRI_SYSROOT_BASE" MIRI_COMPILETEST_TARGET="$FOREIGN_TARGET" cargo test --release --all-features +# Test +function run_tests { + cargo test --release --all-features + (cd test-cargo-miri && ./run-test.py) +} + +echo "Test host architecture" +export MIRI_SYSROOT="$MIRI_SYSROOT_BASE"/HOST +run_tests echo -echo "Test cargo integration" -(cd test-cargo-miri && MIRI_SYSROOT="$MIRI_SYSROOT_BASE"/HOST ./run-test.py) +echo "Test foreign architecture ($FOREIGN_TARGET)" +export MIRI_SYSROOT="$MIRI_SYSROOT_BASE" MIRI_TEST_TARGET="$FOREIGN_TARGET" +run_tests echo From 703b7f8a7e64fb2273fb516ecb8c953375d9deed Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 21 Apr 2019 21:37:06 +0200 Subject: [PATCH 0716/3747] implement SecRandomCopyBytes for macOS RNG --- src/fn_call.rs | 12 ++++++++++++ test-cargo-miri/tests/test.rs | 16 ++++++---------- 2 files changed, 18 insertions(+), 10 deletions(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index 9789a76c6393e..fa0373ec54ec8 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -712,6 +712,18 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' "_NSGetArgv" => { this.write_scalar(Scalar::Ptr(this.machine.argv.unwrap()), dest)?; }, + "SecRandomCopyBytes" => { + let len = this.read_scalar(args[1])?.to_usize(this)?; + let ptr = this.read_scalar(args[2])?.to_ptr()?; + + if len > 0 { + let data = gen_random(this, len as usize)?; + this.memory_mut().get_mut(ptr.alloc_id)? + .write_bytes(tcx, ptr, &data)?; + } + + this.write_null(dest)?; + } // Windows API stubs. // HANDLE = isize diff --git a/test-cargo-miri/tests/test.rs b/test-cargo-miri/tests/test.rs index 69a31c42a75c1..1f2f792148074 100644 --- a/test-cargo-miri/tests/test.rs +++ b/test-cargo-miri/tests/test.rs @@ -21,17 +21,13 @@ fn fixed_rng() { #[test] fn entropy_rng() { - #[cfg(not(target_os="macos"))] // FIXME entropy does not work on macOS - // (Not disabling the entire test as that would change the output.) - { - // Use this opportunity to test querying the RNG (needs an external crate, hence tested here and not in the compiletest suite) - let mut rng = SmallRng::from_entropy(); - let _val = rng.gen::(); + // Use this opportunity to test querying the RNG (needs an external crate, hence tested here and not in the compiletest suite) + let mut rng = SmallRng::from_entropy(); + let _val = rng.gen::(); - // Also try per-thread RNG. - let mut rng = rand::thread_rng(); - let _val = rng.gen::(); - } + // Also try per-thread RNG. + let mut rng = rand::thread_rng(); + let _val = rng.gen::(); } // A test that won't work on miri From 131548a748c2d508a544632697cfe9f7db5d4c6c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 21 Apr 2019 22:57:58 +0200 Subject: [PATCH 0717/3747] gen_random: handle size 0 and writing to mem --- src/fn_call.rs | 50 +++++++++++++++++++++----------------------------- 1 file changed, 21 insertions(+), 29 deletions(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index fa0373ec54ec8..7a684bdaa78f4 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -298,19 +298,14 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' // is called if a `HashMap` is created the regular way (e.g. HashMap). match this.read_scalar(args[0])?.to_usize(this)? { id if id == sys_getrandom => { - let ptr = this.read_scalar(args[1])?.to_ptr()?; + let ptr = this.read_scalar(args[1])?.not_undef()?; let len = this.read_scalar(args[2])?.to_usize(this)?; // The only supported flags are GRND_RANDOM and GRND_NONBLOCK, // neither of which have any effect on our current PRNG let _flags = this.read_scalar(args[3])?.to_i32()?; - if len > 0 { - let data = gen_random(this, len as usize)?; - this.memory_mut().get_mut(ptr.alloc_id)? - .write_bytes(tcx, ptr, &data)?; - } - + gen_random(this, len as usize, ptr)?; this.write_scalar(Scalar::from_uint(len, dest.layout.size), dest)?; } id => { @@ -714,14 +709,8 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' }, "SecRandomCopyBytes" => { let len = this.read_scalar(args[1])?.to_usize(this)?; - let ptr = this.read_scalar(args[2])?.to_ptr()?; - - if len > 0 { - let data = gen_random(this, len as usize)?; - this.memory_mut().get_mut(ptr.alloc_id)? - .write_bytes(tcx, ptr, &data)?; - } - + let ptr = this.read_scalar(args[2])?.not_undef()?; + gen_random(this, len as usize, ptr)?; this.write_null(dest)?; } @@ -878,15 +867,9 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' } // The actual name of 'RtlGenRandom' "SystemFunction036" => { - let ptr = this.read_scalar(args[0])?.to_ptr()?; + let ptr = this.read_scalar(args[0])?.not_undef()?; let len = this.read_scalar(args[1])?.to_u32()?; - - if len > 0 { - let data = gen_random(this, len as usize)?; - this.memory_mut().get_mut(ptr.alloc_id)? - .write_bytes(tcx, ptr, &data)?; - } - + gen_random(this, len as usize, ptr)?; this.write_scalar(Scalar::from_bool(true), dest)?; } @@ -927,21 +910,30 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' fn gen_random<'a, 'mir, 'tcx>( this: &mut MiriEvalContext<'a, 'mir, 'tcx>, len: usize, -) -> Result, EvalError<'tcx>> { + dest: Scalar, +) -> EvalResult<'tcx> { + if len == 0 { + // Nothing to do + return Ok(()); + } + let ptr = dest.to_ptr()?; - match &mut this.machine.rng { + let data = match &mut this.machine.rng { Some(rng) => { let mut data = vec![0; len]; rng.fill_bytes(&mut data); - Ok(data) + data } None => { - err!(Unimplemented( + return err!(Unimplemented( "miri does not support gathering system entropy in deterministic mode! Use '-Zmiri-seed=' to enable random number generation. WARNING: Miri does *not* generate cryptographically secure entropy - do not use Miri to run any program that needs secure random number generation".to_owned(), - )) + )); } - } + }; + let tcx = &{this.tcx.tcx}; + this.memory_mut().get_mut(ptr.alloc_id)? + .write_bytes(tcx, ptr, &data) } From 8cb0b23c08c8463db0de2d70a8df44fd8326236e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 22 Apr 2019 11:08:53 +0200 Subject: [PATCH 0718/3747] no need to allow any more --- test-cargo-miri/tests/test.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/test-cargo-miri/tests/test.rs b/test-cargo-miri/tests/test.rs index 1f2f792148074..ce15824f94a22 100644 --- a/test-cargo-miri/tests/test.rs +++ b/test-cargo-miri/tests/test.rs @@ -1,7 +1,3 @@ -#![allow(unused_imports)] // FIXME for macOS - -extern crate rand; - use rand::{SeedableRng, FromEntropy, Rng, rngs::SmallRng}; #[test] From b7314369e28560aa3358e5df221007ec304e023e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 22 Apr 2019 11:11:06 +0200 Subject: [PATCH 0719/3747] make run-test runnable from other directories --- test-cargo-miri/run-test.py | 3 +++ travis.sh | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/test-cargo-miri/run-test.py b/test-cargo-miri/run-test.py index ec77875d4900f..33664737709c0 100755 --- a/test-cargo-miri/run-test.py +++ b/test-cargo-miri/run-test.py @@ -61,7 +61,10 @@ def test_cargo_miri_test(): "test.stdout.ref2", "test.stderr.ref" ) +os.chdir(os.path.dirname(os.path.realpath(__file__))) + test_cargo_miri_run() test_cargo_miri_test() + print("TEST SUCCESSFUL!") sys.exit(0) diff --git a/travis.sh b/travis.sh index 77768cf031148..84f9c408dcba5 100755 --- a/travis.sh +++ b/travis.sh @@ -24,7 +24,7 @@ echo # Test function run_tests { cargo test --release --all-features - (cd test-cargo-miri && ./run-test.py) + test-cargo-miri/run-test.py } echo "Test host architecture" From aaa8ee743bca78d52018a025a525183405b2a1b1 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 22 Apr 2019 13:20:51 +0200 Subject: [PATCH 0720/3747] unify code paths --- src/fn_call.rs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index 62ad675218a4f..29a34a6968634 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -154,14 +154,11 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' "__rust_start_panic" | "panic_impl" => { return err!(MachineError("the evaluated program panicked".to_string())); } - "exit" => { + "exit" | "ExitProcess" => { + // it's really u32 for ExitProcess, but we have to put it into the `Exit` error variant anyway let code = this.read_scalar(args[0])?.to_i32()?; return err!(Exit(code)); } - "ExitProcess" => { - let code = this.read_scalar(args[0])?.to_u32()?; - return err!(Exit(code as i32)); - } _ => if dest.is_none() { return err!(Unimplemented( format!("can't call diverging foreign function: {}", link_name), From f9cf78d68525c37fbda04175fa9d9d9b98626ec7 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 26 Apr 2019 09:08:30 +0200 Subject: [PATCH 0721/3747] trophy case: add rand; separate definite bugs from stacked-borrows-is-not-yet-official bugs --- README.md | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 0517092a8790f..22eb41f949007 100644 --- a/README.md +++ b/README.md @@ -308,14 +308,20 @@ used according to their aliasing restrictions. ## Bugs found by Miri -Miri has already found a number of bugs in the Rust standard library, which we collect here. +Miri has already found a number of bugs in the Rust standard library and beyond, which we collect here. + +Definite bugs found: * [`Debug for vec_deque::Iter` accessing uninitialized memory](https://github.com/rust-lang/rust/issues/53566) * [`From<&[T]> for Rc` creating a not sufficiently aligned reference](https://github.com/rust-lang/rust/issues/54908) * [`BTreeMap` creating a shared reference pointing to a too small allocation](https://github.com/rust-lang/rust/issues/54957) -* [`VecDeque` creating overlapping mutable references](https://github.com/rust-lang/rust/pull/56161) * [Futures turning a shared reference into a mutable one](https://github.com/rust-lang/rust/pull/56319) * [`str` turning a shared reference into a mutable one](https://github.com/rust-lang/rust/pull/58200) +* [`rand` performing unaligned reads](https://github.com/rust-random/rand/issues/779) + +Violations of Stacked Borrows found that are likely bugs (but Stacked Borrows is currently just an experiment): + +* [`VecDeque` creating overlapping mutable references](https://github.com/rust-lang/rust/pull/56161) * [`BTreeMap` creating mutable references that overlap with shared references](https://github.com/rust-lang/rust/pull/58431) * [`LinkedList` creating overlapping mutable references](https://github.com/rust-lang/rust/pull/60072) From d30141693ef9e4add781cdfa0c5b880192489f26 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 23 Apr 2019 21:59:33 +0200 Subject: [PATCH 0722/3747] bump Rust --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index fae9b1d599a42..52b6685715d79 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -9224be5fa39f6170f6e046342976efee5453a1ff +fe0a415b4ba3310c2263f07e0253e2434310299c From 53f59431a5f2c16b8a6dd66d91008c97a4ed8884 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 27 Apr 2019 18:21:10 +0200 Subject: [PATCH 0723/3747] fix HeapFree return value --- src/fn_call.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/fn_call.rs b/src/fn_call.rs index 29a34a6968634..1fd10ff38506a 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -722,6 +722,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' // Windows API stubs. // HANDLE = isize // DWORD = ULONG = u32 + // BOOL = i32 "GetProcessHeap" => { // Just fake a HANDLE this.write_scalar(Scalar::from_int(1, this.pointer_size()), dest)?; @@ -739,6 +740,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' let _flags = this.read_scalar(args[1])?.to_u32()?; let ptr = this.read_scalar(args[2])?.not_undef()?; this.free(ptr)?; + this.write_scalar(Scalar::from_int(1, Size::from_bytes(4)), dest)?; } "HeapReAlloc" => { let _handle = this.read_scalar(args[0])?.to_isize(this)?; From 69a252c1b3492ea2902447a3331933c3fbe4d7f6 Mon Sep 17 00:00:00 2001 From: Bastien Orivel Date: Sat, 27 Apr 2019 23:31:48 +0200 Subject: [PATCH 0724/3747] Update cargo_metadata to 0.7 --- Cargo.toml | 2 +- src/bin/cargo-miri.rs | 9 +++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index ce9c3cc4f29c4..639fd50c75033 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -34,7 +34,7 @@ required-features = ["rustc_tests"] [dependencies] byteorder = { version = "1.1", features = ["i128"]} -cargo_metadata = { version = "0.6", optional = true } +cargo_metadata = { version = "0.7", optional = true } directories = { version = "1.0", optional = true } rustc_version = { version = "0.2.3", optional = true } env_logger = "0.6" diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index b24bf65629b00..5fc6f4af2b2d3 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -83,10 +83,11 @@ fn list_targets() -> impl Iterator { Path::new(&m).canonicalize().unwrap() ); - let mut metadata = if let Ok(metadata) = cargo_metadata::metadata( - manifest_path.as_ref().map(AsRef::as_ref), - ) - { + let mut cmd = cargo_metadata::MetadataCommand::new(); + if let Some(ref manifest_path) = manifest_path { + cmd.manifest_path(manifest_path); + } + let mut metadata = if let Ok(metadata) = cmd.exec() { metadata } else { show_error(format!("Could not obtain Cargo metadata")); From 59985157d3931861a709ff610b22114442aac9ba Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 30 Apr 2019 13:48:16 +0200 Subject: [PATCH 0725/3747] SharedReadOnly reborrows are never weak --- src/stacked_borrows.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index bac35796ed135..c2e4c72fb73dc 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -400,6 +400,9 @@ impl<'tcx> Stack { // Either way, we ensure that we insert the new item in a way that between // `derived_from` and the new one, there are only items *compatible with* `derived_from`. let new_idx = if weak { + // A weak ShareadReadOnly reborrow might be added below other items, violating the + // invariant that only SharedReadOnly can sit on top of SharedReadOnly. + assert!(new.perm != Permission::SharedReadOnly, "Weak ShareadReadOnly reborrows don't work"); // A very liberal reborrow because the new pointer does not expect any kind of aliasing guarantee. // Just insert new permission as child of old permission, and maintain everything else. // This inserts "as far down as possible", which is good because it makes this pointer as @@ -581,8 +584,8 @@ trait EvalContextPrivExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, // We need a frozen-sensitive reborrow. return this.visit_freeze_sensitive(place, size, |cur_ptr, size, frozen| { // We are only ever `SharedReadOnly` inside the frozen bits. - let weak = !frozen || kind != RefKind::Shared; // `RefKind::Raw` is always weak, as is `SharedReadWrite`. let perm = if frozen { Permission::SharedReadOnly } else { Permission::SharedReadWrite }; + let weak = perm == Permission::SharedReadWrite; let item = Item { perm, tag: new_tag, protector }; alloc.extra.for_each(cur_ptr, size, |stack, global| { stack.reborrow(cur_ptr.tag, force_weak || weak, item, global) From 17643af868c0310ec23c64d729e2f75ff19f21c7 Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Tue, 30 Apr 2019 15:31:53 +0200 Subject: [PATCH 0726/3747] Apply suggestions from code review Co-Authored-By: RalfJung --- src/stacked_borrows.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index c2e4c72fb73dc..2b4034d731378 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -400,9 +400,9 @@ impl<'tcx> Stack { // Either way, we ensure that we insert the new item in a way that between // `derived_from` and the new one, there are only items *compatible with* `derived_from`. let new_idx = if weak { - // A weak ShareadReadOnly reborrow might be added below other items, violating the + // A weak SharedReadOnly reborrow might be added below other items, violating the // invariant that only SharedReadOnly can sit on top of SharedReadOnly. - assert!(new.perm != Permission::SharedReadOnly, "Weak ShareadReadOnly reborrows don't work"); + assert!(new.perm != Permission::SharedReadOnly, "Weak SharedReadOnly reborrows don't work"); // A very liberal reborrow because the new pointer does not expect any kind of aliasing guarantee. // Just insert new permission as child of old permission, and maintain everything else. // This inserts "as far down as possible", which is good because it makes this pointer as From 617195eb12a439119d9ae8aa12eda7b5d1894e37 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 30 Apr 2019 20:18:29 +0200 Subject: [PATCH 0727/3747] add arielby's example --- tests/compile-fail/stacked_borrows/illegal_write6.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 tests/compile-fail/stacked_borrows/illegal_write6.rs diff --git a/tests/compile-fail/stacked_borrows/illegal_write6.rs b/tests/compile-fail/stacked_borrows/illegal_write6.rs new file mode 100644 index 0000000000000..86f2c0f350e3d --- /dev/null +++ b/tests/compile-fail/stacked_borrows/illegal_write6.rs @@ -0,0 +1,12 @@ +fn main() { + let x = &mut 0u32; + let p = x as *mut u32; + foo(x, p); +} + +fn foo(a: &mut u32, y: *mut u32) -> u32 { + *a = 1; + let _b = &*a; + unsafe { *y = 2; } //~ ERROR: borrow stack + return *a; +} From d05159f3a981abc294358b7f1880511ac6078d8f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 1 May 2019 20:37:08 +0200 Subject: [PATCH 0728/3747] switch to my xargo fork, because that one works with current libstd --- src/bin/cargo-miri.rs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 5fc6f4af2b2d3..8fb6d04aa07ef 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -133,7 +133,11 @@ fn xargo_version() -> Option<(u32, u32, u32)> { (split.next().expect("malformed `xargo --version` output: empty"), split.next().expect("malformed `xargo --version` output: not at least two words")) }; - if name != "xargo" { + if name == "xargo" { + // This is the upstream version which is currently broken, we need our fork. + return None; + } + if name != "xargo-rj" { panic!("malformed `xargo --version` output: application name is not `xargo`"); } let mut version_pieces = version.split('.'); @@ -183,11 +187,11 @@ fn setup(ask_user: bool) { let xargo = xargo_version(); if xargo.map_or(true, |v| v < (0, 3, 13)) { if ask_user { - ask("It seems you do not have a recent enough xargo installed. I will run `cargo install xargo -f`. Proceed?"); + ask("It seems you do not have a recent enough xargo installed. I will run `cargo install --git https://github.com/RalfJung/xargo -f`. Proceed?"); } else { - println!("Installing xargo: `cargo install xargo -f`"); + println!("Installing xargo: `cargo install --git https://github.com/RalfJung/xargo -f`"); } - if !Command::new("cargo").args(&["install", "xargo", "-f"]).status().unwrap().success() { + if !Command::new("cargo").args(&["install", "--git", "https://github.com/RalfJung/xargo", "-f"]).status().unwrap().success() { show_error(format!("Failed to install xargo")); } } From b08bf47606bbba0a966d6a722d85c740b315fcec Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 1 May 2019 20:43:43 +0200 Subject: [PATCH 0729/3747] fix tests for latest Rust --- rust-version | 2 +- tests/run-pass/async-fn.rs | 1 - tests/run-pass/hashmap.rs | 5 +---- 3 files changed, 2 insertions(+), 6 deletions(-) diff --git a/rust-version b/rust-version index 52b6685715d79..49e9739a2eb18 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -fe0a415b4ba3310c2263f07e0253e2434310299c +7c71bc3208031b1307573de45a3b3e18fa45787a diff --git a/tests/run-pass/async-fn.rs b/tests/run-pass/async-fn.rs index 1608ea1888942..8a0ac875f54d6 100644 --- a/tests/run-pass/async-fn.rs +++ b/tests/run-pass/async-fn.rs @@ -1,7 +1,6 @@ #![feature( async_await, await_macro, - futures_api, )] use std::{future::Future, pin::Pin, task::Poll, ptr}; diff --git a/tests/run-pass/hashmap.rs b/tests/run-pass/hashmap.rs index 25a816bcf2454..55037f55bf048 100644 --- a/tests/run-pass/hashmap.rs +++ b/tests/run-pass/hashmap.rs @@ -7,13 +7,10 @@ fn test_map(mut map: HashMap) { map.insert(0, 0); assert_eq!(map.values().fold(0, |x, y| x+y), 0); - let table_base = map.get(&0).unwrap() as *const _; - - let num = 22; // large enough to trigger a resize + let num = 25; for i in 1..num { map.insert(i, i); } - assert!(table_base != map.get(&0).unwrap() as *const _); // make sure relocation happened assert_eq!(map.values().fold(0, |x, y| x+y), num*(num-1)/2); // check the right things are in the table now // Inserting again replaces the existing entries From 0f96676f43b111c8e448bf8c8f35cac07a79894b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 10 May 2019 08:05:34 +0200 Subject: [PATCH 0730/3747] switch back to upstream xargo --- src/bin/cargo-miri.rs | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 8fb6d04aa07ef..5dc7a75fc764c 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -133,13 +133,10 @@ fn xargo_version() -> Option<(u32, u32, u32)> { (split.next().expect("malformed `xargo --version` output: empty"), split.next().expect("malformed `xargo --version` output: not at least two words")) }; - if name == "xargo" { - // This is the upstream version which is currently broken, we need our fork. + if name != "xargo" { + // This is some fork of xargo return None; } - if name != "xargo-rj" { - panic!("malformed `xargo --version` output: application name is not `xargo`"); - } let mut version_pieces = version.split('.'); let major = version_pieces.next() .expect("malformed `xargo --version` output: not a major version piece") @@ -185,13 +182,13 @@ fn setup(ask_user: bool) { // First, we need xargo. let xargo = xargo_version(); - if xargo.map_or(true, |v| v < (0, 3, 13)) { + if xargo.map_or(true, |v| v < (0, 3, 14)) { if ask_user { - ask("It seems you do not have a recent enough xargo installed. I will run `cargo install --git https://github.com/RalfJung/xargo -f`. Proceed?"); + ask("It seems you do not have a recent enough xargo installed. I will run `cargo install xargo -f`. Proceed?"); } else { - println!("Installing xargo: `cargo install --git https://github.com/RalfJung/xargo -f`"); + println!("Installing xargo: `cargo install xargo -f`"); } - if !Command::new("cargo").args(&["install", "--git", "https://github.com/RalfJung/xargo", "-f"]).status().unwrap().success() { + if !Command::new("cargo").args(&["install", "xargo", "-f"]).status().unwrap().success() { show_error(format!("Failed to install xargo")); } } From 8530080d03e852467d008ff2b4a4859f27e42daf Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 11 May 2019 11:03:53 +0200 Subject: [PATCH 0731/3747] rename per-location part of reborowing to 'granting' --- src/stacked_borrows.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 2b4034d731378..37288afe239ea 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -373,10 +373,10 @@ impl<'tcx> Stack { } /// Derived a new pointer from one with the given tag. - /// `weak` controls whether this is a weak reborrow: weak reborrows do not act as - /// accesses, and they add the new item directly on top of the one it is derived + /// `weak` controls whether this operation is weak or string: weak granting does not act as + /// an access, and they add the new item directly on top of the one it is derived /// from instead of all the way at the top of the stack. - fn reborrow( + fn grant( &mut self, derived_from: Tag, weak: bool, @@ -588,7 +588,7 @@ trait EvalContextPrivExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, let weak = perm == Permission::SharedReadWrite; let item = Item { perm, tag: new_tag, protector }; alloc.extra.for_each(cur_ptr, size, |stack, global| { - stack.reborrow(cur_ptr.tag, force_weak || weak, item, global) + stack.grant(cur_ptr.tag, force_weak || weak, item, global) }) }); } @@ -597,7 +597,7 @@ trait EvalContextPrivExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, let weak = perm == Permission::SharedReadWrite; let item = Item { perm, tag: new_tag, protector }; alloc.extra.for_each(ptr, size, |stack, global| { - stack.reborrow(ptr.tag, force_weak || weak, item, global) + stack.grant(ptr.tag, force_weak || weak, item, global) }) } From a9e66928d60a0d8564cc262d780f42ad0a2e900c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 11 May 2019 12:07:25 +0200 Subject: [PATCH 0732/3747] Update src/stacked_borrows.rs Co-Authored-By: bjorn3 --- src/stacked_borrows.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 37288afe239ea..910c4ce49f5aa 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -373,7 +373,7 @@ impl<'tcx> Stack { } /// Derived a new pointer from one with the given tag. - /// `weak` controls whether this operation is weak or string: weak granting does not act as + /// `weak` controls whether this operation is weak or strong: weak granting does not act as /// an access, and they add the new item directly on top of the one it is derived /// from instead of all the way at the top of the stack. fn grant( From be47fae17393106c4093849a696b9adbdb23e5f6 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 13 May 2019 11:37:54 +0200 Subject: [PATCH 0733/3747] build with latest version --- rust-version | 2 +- src/helpers.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/rust-version b/rust-version index 49e9739a2eb18..61205128dfe6c 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -7c71bc3208031b1307573de45a3b3e18fa45787a +d595b113584f8f446957469951fd5d31adc2a44e diff --git a/src/helpers.rs b/src/helpers.rs index f468d256031ca..e9f7741d31b9c 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -27,10 +27,10 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' for item in mem::replace(&mut items, Default::default()).iter() { if item.ident.name == *segment { if path_it.peek().is_none() { - return Some(ty::Instance::mono(this.tcx.tcx, item.def.def_id())); + return Some(ty::Instance::mono(this.tcx.tcx, item.res.def_id())); } - items = this.tcx.item_children(item.def.def_id()); + items = this.tcx.item_children(item.res.def_id()); break; } } From 7f09e61c31ffffc340495eca23e834d6159f61d6 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 13 May 2019 11:45:39 +0200 Subject: [PATCH 0734/3747] make HashMap test a bit nicer --- tests/run-pass/hashmap.rs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/tests/run-pass/hashmap.rs b/tests/run-pass/hashmap.rs index 55037f55bf048..e249238d48cbf 100644 --- a/tests/run-pass/hashmap.rs +++ b/tests/run-pass/hashmap.rs @@ -24,12 +24,10 @@ fn test_map(mut map: HashMap) { } fn main() { - if cfg!(target_os = "macos") { // TODO: Implement random number generation on OS X. + if cfg!(target_os = "macos") { // TODO: Implement libstd HashMap seeding for macOS (https://github.com/rust-lang/miri/issues/686). // Until then, use a deterministic map. - let map : HashMap> = HashMap::default(); - test_map(map); + test_map::>(HashMap::default()); } else { - let map: HashMap = HashMap::default(); - test_map(map); + test_map(HashMap::new()); } } From ada5edbf966b3e968e7a20e03484217dfa2ae551 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 13 May 2019 14:10:52 +0200 Subject: [PATCH 0735/3747] RUST_LOG got renamed to RUSTC_LOG --- src/bin/miri.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 6e68f803f8584..272fd17d433cb 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -66,26 +66,26 @@ fn init_early_loggers() { // If it is not set, we avoid initializing now so that we can initialize // later with our custom settings, and *not* log anything for what happens before // `miri` gets started. - if env::var("RUST_LOG").is_ok() { + if env::var("RUSTC_LOG").is_ok() { rustc_driver::init_rustc_env_logger(); } } fn init_late_loggers() { - // We initialize loggers right before we start evaluation. We overwrite the `RUST_LOG` + // We initialize loggers right before we start evaluation. We overwrite the `RUSTC_LOG` // env var if it is not set, control it based on `MIRI_LOG`. if let Ok(var) = env::var("MIRI_LOG") { - if env::var("RUST_LOG").is_err() { + if env::var("RUSTC_LOG").is_err() { // We try to be a bit clever here: if `MIRI_LOG` is just a single level // used for everything, we only apply it to the parts of rustc that are - // CTFE-related. Otherwise, we use it verbatim for `RUST_LOG`. + // CTFE-related. Otherwise, we use it verbatim for `RUSTC_LOG`. // This way, if you set `MIRI_LOG=trace`, you get only the right parts of // rustc traced, but you can also do `MIRI_LOG=miri=trace,rustc_mir::interpret=debug`. if log::Level::from_str(&var).is_ok() { - env::set_var("RUST_LOG", + env::set_var("RUSTC_LOG", &format!("rustc::mir::interpret={0},rustc_mir::interpret={0}", var)); } else { - env::set_var("RUST_LOG", &var); + env::set_var("RUSTC_LOG", &var); } rustc_driver::init_rustc_env_logger(); } From bc0c76d861a178911f3f506196a7404eda1e690d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 13 May 2019 21:55:58 +0200 Subject: [PATCH 0736/3747] fix for latest rustc --- rust-version | 2 +- src/bin/miri-rustc-tests.rs | 4 ++-- src/bin/miri.rs | 2 +- src/fn_call.rs | 3 ++- src/helpers.rs | 4 ++-- src/lib.rs | 3 ++- 6 files changed, 10 insertions(+), 8 deletions(-) diff --git a/rust-version b/rust-version index 61205128dfe6c..1567a48efcc99 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -d595b113584f8f446957469951fd5d31adc2a44e +a9ec99f4201ec33026a468ef1289f98a95b4d71a diff --git a/src/bin/miri-rustc-tests.rs b/src/bin/miri-rustc-tests.rs index ce2ad1a2715db..cf50f8125c4bd 100644 --- a/src/bin/miri-rustc-tests.rs +++ b/src/bin/miri-rustc-tests.rs @@ -30,7 +30,7 @@ struct MiriCompilerCalls { impl rustc_driver::Callbacks for MiriCompilerCalls { fn after_parsing(&mut self, compiler: &interface::Compiler) -> bool { let attr = ( - String::from("miri"), + syntax::symbol::Symbol::intern("miri"), syntax::feature_gate::AttributeType::Whitelisted, ); compiler.session().plugin_attributes.borrow_mut().push(attr); @@ -47,7 +47,7 @@ impl rustc_driver::Callbacks for MiriCompilerCalls { impl<'a, 'tcx: 'a, 'hir> itemlikevisit::ItemLikeVisitor<'hir> for Visitor<'a, 'tcx> { fn visit_item(&mut self, i: &'hir hir::Item) { if let hir::ItemKind::Fn(.., body_id) = i.node { - if i.attrs.iter().any(|attr| attr.check_name("test")) { + if i.attrs.iter().any(|attr| attr.check_name(syntax::symbol::sym::test)) { let config = MiriConfig { validate: true, args: vec![], seed: None }; let did = self.0.hir().body_owner_def_id(body_id); println!("running test: {}", self.0.def_path_debug_str(did)); diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 272fd17d433cb..31ed5f2ccd538 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -27,7 +27,7 @@ struct MiriCompilerCalls { impl rustc_driver::Callbacks for MiriCompilerCalls { fn after_parsing(&mut self, compiler: &interface::Compiler) -> bool { let attr = ( - String::from("miri"), + syntax::symbol::Symbol::intern("miri"), syntax::feature_gate::AttributeType::Whitelisted, ); compiler.session().plugin_attributes.borrow_mut().push(attr); diff --git a/src/fn_call.rs b/src/fn_call.rs index 1fd10ff38506a..3ff0c1eb18a0d 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -3,6 +3,7 @@ use rustc::ty::layout::{Align, LayoutOf, Size}; use rustc::hir::def_id::DefId; use rustc::mir; use syntax::attr; +use syntax::symbol::sym; use rand::RngCore; @@ -141,7 +142,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' ) -> EvalResult<'tcx> { let this = self.eval_context_mut(); let attrs = this.tcx.get_attrs(def_id); - let link_name = match attr::first_attr_value_str_by_name(&attrs, "link_name") { + let link_name = match attr::first_attr_value_str_by_name(&attrs, sym::link_name) { Some(name) => name.as_str(), None => this.tcx.item_name(def_id).as_str(), }; diff --git a/src/helpers.rs b/src/helpers.rs index e9f7741d31b9c..89aba494724ca 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -14,7 +14,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' this.tcx .crates() .iter() - .find(|&&krate| this.tcx.original_crate_name(krate) == path[0]) + .find(|&&krate| this.tcx.original_crate_name(krate).as_str() == path[0]) .and_then(|krate| { let krate = DefId { krate: *krate, @@ -25,7 +25,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' while let Some(segment) = path_it.next() { for item in mem::replace(&mut items, Default::default()).iter() { - if item.ident.name == *segment { + if item.ident.name.as_str() == *segment { if path_it.peek().is_none() { return Some(ty::Instance::mono(this.tcx.tcx, item.res.def_id())); } diff --git a/src/lib.rs b/src/lib.rs index 683eee0cb7a38..d3e30bbdde8f9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -37,6 +37,7 @@ pub use rustc_mir::interpret::*; pub use rustc_mir::interpret::{self, AllocMap, PlaceTy}; use syntax::attr; use syntax::source_map::DUMMY_SP; +use syntax::symbol::sym; pub use crate::fn_call::EvalContextExt as MissingFnsEvalContextExt; pub use crate::operator::EvalContextExt as OperatorEvalContextExt; @@ -478,7 +479,7 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { memory_extra: &Self::MemoryExtra, ) -> EvalResult<'tcx, Cow<'tcx, Allocation>> { let attrs = tcx.get_attrs(def_id); - let link_name = match attr::first_attr_value_str_by_name(&attrs, "link_name") { + let link_name = match attr::first_attr_value_str_by_name(&attrs, sym::link_name) { Some(name) => name.as_str(), None => tcx.item_name(def_id).as_str(), }; From 7a5a0303be8a053339d9fd88b4adee9d01e6469f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 15 May 2019 08:58:43 +0200 Subject: [PATCH 0737/3747] bump Rust --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 1567a48efcc99..4cf2697aa4212 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -a9ec99f4201ec33026a468ef1289f98a95b4d71a +372be4f360ce42b1a10126a711189796f8440ab4 From 9b3f07b161636a4453a15d5448ed1964dd451369 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 15 May 2019 15:19:19 +0200 Subject: [PATCH 0738/3747] make printing return place less verbose --- src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index d3e30bbdde8f9..a12493fbfbd62 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -282,7 +282,7 @@ pub fn eval_main<'a, 'tcx: 'a>( for (i, frame) in ecx.stack().iter().enumerate() { trace!("-------------------"); trace!("Frame {}", i); - trace!(" return: {:#?}", frame.return_place); + trace!(" return: {:?}", frame.return_place.map(|p| *p)); for (i, local) in frame.locals.iter().enumerate() { trace!(" local {}: {:?}", i, local.value); } From f676f2265b6473c4e84f38c0384ed1f6e3211255 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 15 May 2019 17:23:26 +0200 Subject: [PATCH 0739/3747] make writes act stack-like --- src/stacked_borrows.rs | 49 ++++++++++++------- .../stacked_borrows/interior_mut1.rs | 10 ++++ 2 files changed, 42 insertions(+), 17 deletions(-) create mode 100644 tests/compile-fail/stacked_borrows/interior_mut1.rs diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 910c4ce49f5aa..2f082bcc4c058 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -256,20 +256,33 @@ impl Permission { /// Core per-location operations: access, dealloc, reborrow. impl<'tcx> Stack { - /// Find the item granting the given kind of access to the given tag, and where that item is in the stack. - fn find_granting(&self, access: AccessKind, tag: Tag) -> Option<(usize, Permission)> { - self.borrows.iter() + /// Find the item granting the given kind of access to the given tag, and where + /// *the first incompatible item above it* is on the stack. + fn find_granting(&self, access: AccessKind, tag: Tag) -> Option<(Permission, usize)> { + let (perm, idx) = self.borrows.iter() .enumerate() // we also need to know *where* in the stack .rev() // search top-to-bottom // Return permission of first item that grants access. // We require a permission with the right tag, ensuring U3 and F3. .find_map(|(idx, item)| if item.perm.grants(access) && tag == item.tag { - Some((idx, item.perm)) + Some((item.perm, idx)) } else { None } - ) + )?; + + let mut first_incompatible_idx = idx+1; + while let Some(item) = self.borrows.get(first_incompatible_idx) { + if perm.compatible_with(access, item.perm) { + // Keep this, check next. + first_incompatible_idx += 1; + } else { + // Found it! + break; + } + } + return Some((perm, first_incompatible_idx)); } /// Test if a memory `access` using pointer tagged `tag` is granted. @@ -279,11 +292,11 @@ impl<'tcx> Stack { access: AccessKind, tag: Tag, global: &GlobalState, - ) -> EvalResult<'tcx, usize> { + ) -> EvalResult<'tcx> { // Two main steps: Find granting item, remove all incompatible items above. // Step 1: Find granting item. - let (granting_idx, granting_perm) = self.find_granting(access, tag) + let (granting_perm, first_incompatible_idx) = self.find_granting(access, tag) .ok_or_else(|| InterpError::MachineError(format!( "no item granting {} access to tag {} found in borrow stack", access, tag, @@ -291,9 +304,7 @@ impl<'tcx> Stack { // Step 2: Remove everything incompatible above them. Make sure we do not remove protected // items. - // We do *not* maintain a stack discipline here. We could, in principle, decide to only - // keep the items immediately above `granting_idx` that are compatible, and then pop the rest. - // However, that kills off entire "branches" of pointer derivation too easily: + // For writes, this is a simple stack. For reads, however, it is not: // in `let raw = &mut *x as *mut _; let _val = *x;`, the second statement would pop the `Unique` // from the reborrow of the first statement, and subsequently also pop the `SharedReadWrite` for `raw`. // This pattern occurs a lot in the standard library: create a raw pointer, then also create a shared @@ -301,9 +312,10 @@ impl<'tcx> Stack { { // Implemented with indices because there does not seem to be a nice iterator and range-based // API for this. - let mut cur = granting_idx + 1; + let mut cur = first_incompatible_idx; while let Some(item) = self.borrows.get(cur) { - if granting_perm.compatible_with(access, item.perm) { + // If this is a read, we double-check if we really want to kill this. + if access == AccessKind::Read && granting_perm.compatible_with(access, item.perm) { // Keep this, check next. cur += 1; } else { @@ -323,7 +335,7 @@ impl<'tcx> Stack { } // Done. - return Ok(granting_idx); + Ok(()) } /// Deallocate a location: Like a write access, but also there must be no @@ -391,7 +403,7 @@ impl<'tcx> Stack { }; // Now we figure out which item grants our parent (`derived_from`) this kind of access. // We use that to determine where to put the new item. - let (derived_from_idx, _) = self.find_granting(access, derived_from) + let (_, first_incompatible_idx) = self.find_granting(access, derived_from) .ok_or_else(|| InterpError::MachineError(format!( "no item to reborrow for {:?} from tag {} found in borrow stack", new.perm, derived_from, )))?; @@ -412,14 +424,17 @@ impl<'tcx> Stack { // and we'd allow write access without invalidating frozen shared references! // This ensures F2b for `SharedReadWrite` by adding the new item below any // potentially existing `SharedReadOnly`. - derived_from_idx + 1 + first_incompatible_idx } else { // A "safe" reborrow for a pointer that actually expects some aliasing guarantees. // Here, creating a reference actually counts as an access, and pops incompatible // stuff off the stack. // This ensures F2b for `Unique`, by removing offending `SharedReadOnly`. - let check_idx = self.access(access, derived_from, global)?; - assert_eq!(check_idx, derived_from_idx, "somehow we saw different items??"); + self.access(access, derived_from, global)?; + if access == AccessKind::Write { + // For write accesses, the position is the same as what it would have been weakly! + assert_eq!(first_incompatible_idx, self.borrows.len()); + } // We insert "as far up as possible": We know only compatible items are remaining // on top of `derived_from`, and we want the new item at the top so that we diff --git a/tests/compile-fail/stacked_borrows/interior_mut1.rs b/tests/compile-fail/stacked_borrows/interior_mut1.rs new file mode 100644 index 0000000000000..dd9fce110c2d3 --- /dev/null +++ b/tests/compile-fail/stacked_borrows/interior_mut1.rs @@ -0,0 +1,10 @@ +use std::cell::UnsafeCell; + +fn main() { unsafe { + let c = &UnsafeCell::new(UnsafeCell::new(0)); + let inner_uniq = &mut *c.get(); + let inner_shr = &*inner_uniq; // a SharedRW with a tag + *c.get() = UnsafeCell::new(1); // invalidates the SharedRW + let _val = *inner_shr.get(); //~ ERROR borrow stack + let _val = *inner_uniq.get(); +} } From 1447242bf98d7bf3e094d2e5d6029472cfdcc75d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 15 May 2019 17:50:43 +0200 Subject: [PATCH 0740/3747] refactor to simplify --- src/stacked_borrows.rs | 82 +++++++++++++++--------------------------- 1 file changed, 29 insertions(+), 53 deletions(-) diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 2f082bcc4c058..a3910fd0c43dd 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -214,51 +214,21 @@ impl Permission { } /// This defines for a given permission, which other permissions it can tolerate "above" itself - /// for which kinds of accesses. - /// If true, then `other` is allowed to remain on top of `self` when `access` happens. - fn compatible_with(self, access: AccessKind, other: Permission) -> bool { - use self::Permission::*; - - match (self, access, other) { - // Some cases are impossible. - (SharedReadOnly, _, SharedReadWrite) | - (SharedReadOnly, _, Unique) => - bug!("There can never be a SharedReadWrite or a Unique on top of a SharedReadOnly"), - // When `other` is `SharedReadOnly`, that is NEVER compatible with - // write accesses. - // This makes sure read-only pointers become invalid on write accesses (ensures F2a). - (_, AccessKind::Write, SharedReadOnly) => - false, - // When `other` is `Unique`, that is compatible with nothing. - // This makes sure unique pointers become invalid on incompatible accesses (ensures U2). - (_, _, Unique) => - false, - // When we are unique and this is a write/dealloc, we tolerate nothing. - // This makes sure we re-assert uniqueness ("being on top") on write accesses. - // (This is particularily important such that when a new mutable ref gets created, it gets - // pushed onto the right item -- this behaves like a write and we assert uniqueness of the - // pointer from which this comes, *if* it was a unique pointer.) - (Unique, AccessKind::Write, _) => - false, - // `SharedReadWrite` items can tolerate any other akin items for any kind of access. - (SharedReadWrite, _, SharedReadWrite) => - true, - // Any item can tolerate read accesses for shared items. - // This includes unique items! Reads from unique pointers do not invalidate - // other pointers. - (_, AccessKind::Read, SharedReadWrite) | - (_, AccessKind::Read, SharedReadOnly) => - true, - // That's it. - } + /// when it is written to. + /// If true, then `other` is allowed to remain on top of `self` when a write access happens. + fn write_compatible_with(self, other: Permission) -> bool { + // Only writes to SharedRW can tolerate any other items above them, and they only + // tolerate other SharedRW. So, basically, searching the first write-incompatible item above X treats + // consecutive SharedRW as one "group", and skips to the first item outside X's group. + return self == Permission::SharedReadWrite && other == Permission::SharedReadWrite; } } /// Core per-location operations: access, dealloc, reborrow. impl<'tcx> Stack { - /// Find the item granting the given kind of access to the given tag, and where - /// *the first incompatible item above it* is on the stack. - fn find_granting(&self, access: AccessKind, tag: Tag) -> Option<(Permission, usize)> { + /// Find the item granting the given kind of access to the given tag, and return where + /// *the first write-incompatible item above it* is on the stack. + fn check_granting(&self, access: AccessKind, tag: Tag) -> Option { let (perm, idx) = self.borrows.iter() .enumerate() // we also need to know *where* in the stack .rev() // search top-to-bottom @@ -274,7 +244,7 @@ impl<'tcx> Stack { let mut first_incompatible_idx = idx+1; while let Some(item) = self.borrows.get(first_incompatible_idx) { - if perm.compatible_with(access, item.perm) { + if perm.write_compatible_with(item.perm) { // Keep this, check next. first_incompatible_idx += 1; } else { @@ -282,7 +252,7 @@ impl<'tcx> Stack { break; } } - return Some((perm, first_incompatible_idx)); + return Some(first_incompatible_idx); } /// Test if a memory `access` using pointer tagged `tag` is granted. @@ -293,20 +263,26 @@ impl<'tcx> Stack { tag: Tag, global: &GlobalState, ) -> EvalResult<'tcx> { - // Two main steps: Find granting item, remove all incompatible items above. + // Two main steps: Find granting item, remove incompatible items above. // Step 1: Find granting item. - let (granting_perm, first_incompatible_idx) = self.find_granting(access, tag) + let first_incompatible_idx = self.check_granting(access, tag) .ok_or_else(|| InterpError::MachineError(format!( "no item granting {} access to tag {} found in borrow stack", access, tag, )))?; - // Step 2: Remove everything incompatible above them. Make sure we do not remove protected - // items. - // For writes, this is a simple stack. For reads, however, it is not: - // in `let raw = &mut *x as *mut _; let _val = *x;`, the second statement would pop the `Unique` - // from the reborrow of the first statement, and subsequently also pop the `SharedReadWrite` for `raw`. + // Step 2: Remove incompatible items above them. Make sure we do not remove protected + // items. Behavior differs for reads and writes. + // + // For writes, this is a simple stack, where everything starting with the first incompatible item + // gets removed. This makes sure read-only and unique pointers become invalid on write accesses + // (ensures F2a, and ensures U2 for write accesses). + // + // For reads, however, we just filter away the Unique items, which is sufficient to ensure U2 for read + // accesses. The reason is that in `let raw = &mut *x as *mut _; let _val = *x;`, the second statement + // would pop the `Unique` from the reborrow of the first statement, and subsequently also pop the + // `SharedReadWrite` for `raw`. // This pattern occurs a lot in the standard library: create a raw pointer, then also create a shared // reference and use that. { @@ -314,8 +290,8 @@ impl<'tcx> Stack { // API for this. let mut cur = first_incompatible_idx; while let Some(item) = self.borrows.get(cur) { - // If this is a read, we double-check if we really want to kill this. - if access == AccessKind::Read && granting_perm.compatible_with(access, item.perm) { + // If this is a read, only remove Unique items! + if access == AccessKind::Read && item.perm != Permission::Unique { // Keep this, check next. cur += 1; } else { @@ -346,7 +322,7 @@ impl<'tcx> Stack { global: &GlobalState, ) -> EvalResult<'tcx> { // Step 1: Find granting item. - self.find_granting(AccessKind::Write, tag) + self.check_granting(AccessKind::Write, tag) .ok_or_else(|| InterpError::MachineError(format!( "no item granting write access for deallocation to tag {} found in borrow stack", tag, @@ -403,7 +379,7 @@ impl<'tcx> Stack { }; // Now we figure out which item grants our parent (`derived_from`) this kind of access. // We use that to determine where to put the new item. - let (_, first_incompatible_idx) = self.find_granting(access, derived_from) + let first_incompatible_idx = self.check_granting(access, derived_from) .ok_or_else(|| InterpError::MachineError(format!( "no item to reborrow for {:?} from tag {} found in borrow stack", new.perm, derived_from, )))?; From b9517ca9f3c1d54dba369dca811ed30b291c2e17 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 15 May 2019 17:52:08 +0200 Subject: [PATCH 0741/3747] this also fixed our 2-phase woes --- .../run-pass/stacked-borrows/interior_mutability.rs | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/tests/run-pass/stacked-borrows/interior_mutability.rs b/tests/run-pass/stacked-borrows/interior_mutability.rs index 33f44d0093ed4..d27519df48a75 100644 --- a/tests/run-pass/stacked-borrows/interior_mutability.rs +++ b/tests/run-pass/stacked-borrows/interior_mutability.rs @@ -1,12 +1,12 @@ #![feature(maybe_uninit, maybe_uninit_ref)] use std::mem::MaybeUninit; -use std::cell::Cell; -use std::cell::RefCell; +use std::cell::{Cell, RefCell, UnsafeCell}; fn main() { aliasing_mut_and_shr(); aliasing_frz_and_shr(); into_interior_mutability(); + unsafe_cell_2phase(); } fn aliasing_mut_and_shr() { @@ -57,3 +57,12 @@ fn into_interior_mutability() { let ptr = unsafe { x.get_ref() }; assert_eq!(ptr.1, 1); } + +// Two-phase borrows of the pointer returned by UnsafeCell::get() should not +// invalidate aliases. +fn unsafe_cell_2phase() { unsafe { + let x = &UnsafeCell::new(vec![]); + let x2 = &*x; + (*x.get()).push(0); + let _val = (*x2.get()).get(0); +} } From 3618992a39d6ef81dea38bbf9cd3d332281e55f9 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 15 May 2019 14:45:15 +0200 Subject: [PATCH 0742/3747] deduplicate tests --- test-cargo-miri/tests/test.rs | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/test-cargo-miri/tests/test.rs b/test-cargo-miri/tests/test.rs index ce15824f94a22..b4f5563a3a8bc 100644 --- a/test-cargo-miri/tests/test.rs +++ b/test-cargo-miri/tests/test.rs @@ -1,5 +1,7 @@ use rand::{SeedableRng, FromEntropy, Rng, rngs::SmallRng}; +// Having more than 1 test does seem to make a difference +// (i.e., this calls ptr::swap which having just one test does not). #[test] fn simple() { assert_eq!(4, 4); @@ -7,14 +9,6 @@ fn simple() { // Having more than 1 test does seem to make a difference // (i.e., this calls ptr::swap which having just one test does not). -#[test] -fn fixed_rng() { - let mut rng = rand::rngs::StdRng::seed_from_u64(0xdeadcafe); - let x: u32 = rng.gen(); - let y: u32 = rng.gen(); - assert_ne!(x, y); -} - #[test] fn entropy_rng() { // Use this opportunity to test querying the RNG (needs an external crate, hence tested here and not in the compiletest suite) From 4b9e1544c214133dab7af874e0452dd8ae2894cd Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 17 May 2019 13:42:36 +0200 Subject: [PATCH 0743/3747] give up on two-phase borrows --- src/stacked_borrows.rs | 247 ++++++++---------- .../deallocate_against_barrier.rs | 2 +- 2 files changed, 106 insertions(+), 143 deletions(-) diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index a3910fd0c43dd..33d9509bd3f93 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -70,10 +70,9 @@ impl fmt::Display for Item { #[derive(Clone, Debug, PartialEq, Eq)] pub struct Stack { /// Used *mostly* as a stack; never empty. - /// We sometimes push into the middle but never remove from the middle. - /// The same tag may occur multiple times, e.g. from a two-phase borrow. /// Invariants: /// * Above a `SharedReadOnly` there can only be more `SharedReadOnly`. + /// * Except for `Untagged`, no tag occurs in the stack more than once. borrows: Vec, } @@ -118,7 +117,7 @@ impl fmt::Display for AccessKind { #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] pub enum RefKind { /// `&mut` and `Box`. - Unique, + Unique { two_phase: bool }, /// `&` with or without interior mutability. Shared, /// `*mut`/`*const` (raw pointers). @@ -128,7 +127,8 @@ pub enum RefKind { impl fmt::Display for RefKind { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { - RefKind::Unique => write!(f, "unique"), + RefKind::Unique { two_phase: false } => write!(f, "unique"), + RefKind::Unique { two_phase: true } => write!(f, "unique (two-phase)"), RefKind::Shared => write!(f, "shared"), RefKind::Raw { mutable: true } => write!(f, "raw (mutable)"), RefKind::Raw { mutable: false } => write!(f, "raw (constant)"), @@ -194,65 +194,82 @@ impl Default for Tag { } } -/// Core relations on `Permission` define which accesses are allowed: -/// On every access, we try to find a *granting* item, and then we remove all -/// *incompatible* items above it. + +/// Core relation on `Permission` to define which accesses are allowed impl Permission { /// This defines for a given permission, whether it permits the given kind of access. fn grants(self, access: AccessKind) -> bool { - match (self, access) { - // Unique and SharedReadWrite allow any kind of access. - (Permission::Unique, _) | - (Permission::SharedReadWrite, _) => - true, - // SharedReadOnly only permits read access. - (Permission::SharedReadOnly, AccessKind::Read) => - true, - (Permission::SharedReadOnly, AccessKind::Write) => - false, - } - } - - /// This defines for a given permission, which other permissions it can tolerate "above" itself - /// when it is written to. - /// If true, then `other` is allowed to remain on top of `self` when a write access happens. - fn write_compatible_with(self, other: Permission) -> bool { - // Only writes to SharedRW can tolerate any other items above them, and they only - // tolerate other SharedRW. So, basically, searching the first write-incompatible item above X treats - // consecutive SharedRW as one "group", and skips to the first item outside X's group. - return self == Permission::SharedReadWrite && other == Permission::SharedReadWrite; + // All items grant read access, and except for SharedReadOnly they grant write access. + access == AccessKind::Read || self != Permission::SharedReadOnly } } /// Core per-location operations: access, dealloc, reborrow. impl<'tcx> Stack { /// Find the item granting the given kind of access to the given tag, and return where - /// *the first write-incompatible item above it* is on the stack. - fn check_granting(&self, access: AccessKind, tag: Tag) -> Option { - let (perm, idx) = self.borrows.iter() + /// it is on the stack. + fn find_granting(&self, access: AccessKind, tag: Tag) -> Option { + self.borrows.iter() .enumerate() // we also need to know *where* in the stack .rev() // search top-to-bottom // Return permission of first item that grants access. // We require a permission with the right tag, ensuring U3 and F3. .find_map(|(idx, item)| - if item.perm.grants(access) && tag == item.tag { - Some((item.perm, idx)) + if tag == item.tag && item.perm.grants(access) { + Some(idx) } else { None } - )?; - - let mut first_incompatible_idx = idx+1; - while let Some(item) = self.borrows.get(first_incompatible_idx) { - if perm.write_compatible_with(item.perm) { - // Keep this, check next. - first_incompatible_idx += 1; - } else { - // Found it! - break; + ) + } + + /// Find the first write-incompatible item above the given one -- + /// i.e, find the heigh to which the stack will be truncated when writing to `granting`. + fn find_first_write_incompaible(&self, granting: usize) -> usize { + let perm = self.borrows[granting].perm; + match perm { + Permission::SharedReadOnly => + bug!("Cannot use SharedReadOnly for writing"), + Permission::Unique => + // On a write, everything above us is incompatible. + granting+1, + Permission::SharedReadWrite => { + // The SharedReadWrite *just* above us are compatible, to skip those. + let mut idx = granting+1; + while let Some(item) = self.borrows.get(idx) { + if item.perm == Permission::SharedReadWrite { + // Go on. + idx += 1; + } else { + // Found first incompatible! + break; + } + } + idx + } + } + } + + /// Remove the given item, enforcing barriers. + /// `tag` is just used for the error message. + fn remove(&mut self, idx: usize, tag: Option, global: &GlobalState) -> EvalResult<'tcx> { + let item = self.borrows.remove(idx); + if let Some(call) = item.protector { + if global.is_active(call) { + if let Some(tag) = tag { + return err!(MachineError(format!( + "not granting access to tag {} because incompatible item is protected: {}", + tag, item + ))); + } else { + return err!(MachineError(format!( + "deallocating while item is protected: {}", item + ))); + } } } - return Some(first_incompatible_idx); + trace!("access: removing item {}", item); + Ok(()) } /// Test if a memory `access` using pointer tagged `tag` is granted. @@ -266,7 +283,7 @@ impl<'tcx> Stack { // Two main steps: Find granting item, remove incompatible items above. // Step 1: Find granting item. - let first_incompatible_idx = self.check_granting(access, tag) + let granting_idx = self.find_granting(access, tag) .ok_or_else(|| InterpError::MachineError(format!( "no item granting {} access to tag {} found in borrow stack", access, tag, @@ -274,38 +291,24 @@ impl<'tcx> Stack { // Step 2: Remove incompatible items above them. Make sure we do not remove protected // items. Behavior differs for reads and writes. - // - // For writes, this is a simple stack, where everything starting with the first incompatible item - // gets removed. This makes sure read-only and unique pointers become invalid on write accesses - // (ensures F2a, and ensures U2 for write accesses). - // - // For reads, however, we just filter away the Unique items, which is sufficient to ensure U2 for read - // accesses. The reason is that in `let raw = &mut *x as *mut _; let _val = *x;`, the second statement - // would pop the `Unique` from the reborrow of the first statement, and subsequently also pop the - // `SharedReadWrite` for `raw`. - // This pattern occurs a lot in the standard library: create a raw pointer, then also create a shared - // reference and use that. - { - // Implemented with indices because there does not seem to be a nice iterator and range-based - // API for this. - let mut cur = first_incompatible_idx; - while let Some(item) = self.borrows.get(cur) { - // If this is a read, only remove Unique items! - if access == AccessKind::Read && item.perm != Permission::Unique { - // Keep this, check next. - cur += 1; - } else { - // Aha! This is a bad one, remove it, and make sure it is not protected. - let item = self.borrows.remove(cur); - if let Some(call) = item.protector { - if global.is_active(call) { - return err!(MachineError(format!( - "not granting {} access to tag {} because incompatible item {} is protected", - access, tag, item - ))); - } - } - trace!("access: removing item {}", item); + if access == AccessKind::Write { + // Remove everything above the write-compatible items, like a proper stack. This makes sure read-only and unique + // pointers become invalid on write accesses (ensures F2a, and ensures U2 for write accesses). + let first_incompatible_idx = self.find_first_write_incompaible(granting_idx); + for idx in (first_incompatible_idx..self.borrows.len()).rev() { + self.remove(idx, Some(tag), global)?; + } + } else { + // On a read, remove all `Unique` above the granting item. This ensures U2 for read accesses. + // The reason this is not following the stack discipline is that in + // `let raw = &mut *x as *mut _; let _val = *x;`, the second statement + // would pop the `Unique` from the reborrow of the first statement, and subsequently also pop the + // `SharedReadWrite` for `raw`. + // This pattern occurs a lot in the standard library: create a raw pointer, then also create a shared + // reference and use that. + for idx in (granting_idx+1 .. self.borrows.len()).rev() { + if self.borrows[idx].perm == Permission::Unique { + self.remove(idx, Some(tag), global)?; } } } @@ -315,29 +318,22 @@ impl<'tcx> Stack { } /// Deallocate a location: Like a write access, but also there must be no - /// active protectors at all. + /// active protectors at all because we will remove all items. fn dealloc( &mut self, tag: Tag, global: &GlobalState, ) -> EvalResult<'tcx> { // Step 1: Find granting item. - self.check_granting(AccessKind::Write, tag) + self.find_granting(AccessKind::Write, tag) .ok_or_else(|| InterpError::MachineError(format!( "no item granting write access for deallocation to tag {} found in borrow stack", tag, )))?; - // We must make sure there are no protected items remaining on the stack. - // Also clear the stack, no more accesses are possible. - for item in self.borrows.drain(..) { - if let Some(call) = item.protector { - if global.is_active(call) { - return err!(MachineError(format!( - "deallocating with active protector ({})", call - ))) - } - } + // Step 2: Remove all items. Also checks for protectors. + for idx in (0..self.borrows.len()).rev() { + self.remove(idx, None, global)?; } Ok(()) @@ -367,7 +363,6 @@ impl<'tcx> Stack { fn grant( &mut self, derived_from: Tag, - weak: bool, new: Item, global: &GlobalState, ) -> EvalResult<'tcx> { @@ -379,38 +374,26 @@ impl<'tcx> Stack { }; // Now we figure out which item grants our parent (`derived_from`) this kind of access. // We use that to determine where to put the new item. - let first_incompatible_idx = self.check_granting(access, derived_from) + let granting_idx = self.find_granting(access, derived_from) .ok_or_else(|| InterpError::MachineError(format!( "no item to reborrow for {:?} from tag {} found in borrow stack", new.perm, derived_from, )))?; // Compute where to put the new item. - // Either way, we ensure that we insert the new item in a way that between + // Either way, we ensure that we insert the new item in a way such that between // `derived_from` and the new one, there are only items *compatible with* `derived_from`. - let new_idx = if weak { - // A weak SharedReadOnly reborrow might be added below other items, violating the - // invariant that only SharedReadOnly can sit on top of SharedReadOnly. - assert!(new.perm != Permission::SharedReadOnly, "Weak SharedReadOnly reborrows don't work"); - // A very liberal reborrow because the new pointer does not expect any kind of aliasing guarantee. - // Just insert new permission as child of old permission, and maintain everything else. - // This inserts "as far down as possible", which is good because it makes this pointer as - // long-lived as possible *and* we want all the items that are incompatible with this - // to actually get removed from the stack. If we pushed a `SharedReadWrite` on top of - // a `SharedReadOnly`, we'd violate the invariant that `SaredReadOnly` are at the top - // and we'd allow write access without invalidating frozen shared references! - // This ensures F2b for `SharedReadWrite` by adding the new item below any - // potentially existing `SharedReadOnly`. - first_incompatible_idx + let new_idx = if new.perm == Permission::SharedReadWrite { + assert!(access == AccessKind::Write, "this case only makes sense for stack-like accesses"); + // SharedReadWrite can coexist with "existing loans", meaning they don't act like a write + // access. Instead of popping the stack, we insert the item at the place the stack would + // be popped to (i.e., we insert it above all the write-compatible items). + // This ensures F2b by adding the new item below any potentially existing `SharedReadOnly`. + self.find_first_write_incompaible(granting_idx) } else { // A "safe" reborrow for a pointer that actually expects some aliasing guarantees. - // Here, creating a reference actually counts as an access, and pops incompatible - // stuff off the stack. + // Here, creating a reference actually counts as an access. // This ensures F2b for `Unique`, by removing offending `SharedReadOnly`. self.access(access, derived_from, global)?; - if access == AccessKind::Write { - // For write accesses, the position is the same as what it would have been weakly! - assert_eq!(first_incompatible_idx, self.borrows.len()); - } // We insert "as far up as possible": We know only compatible items are remaining // on top of `derived_from`, and we want the new item at the top so that we @@ -541,8 +524,7 @@ impl AllocationExtra for Stacks { } /// Retagging/reborrowing. There is some policy in here, such as which permissions -/// to grant for which references, when to add protectors, and how to realize two-phase -/// borrows in terms of the primitives above. +/// to grant for which references, and when to add protectors. impl<'a, 'mir, 'tcx> EvalContextPrivExt<'a, 'mir, 'tcx> for crate::MiriEvalContext<'a, 'mir, 'tcx> {} trait EvalContextPrivExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, 'mir, 'tcx> { fn reborrow( @@ -551,7 +533,6 @@ trait EvalContextPrivExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, size: Size, kind: RefKind, new_tag: Tag, - force_weak: bool, protect: bool, ) -> EvalResult<'tcx> { let this = self.eval_context_mut(); @@ -567,7 +548,8 @@ trait EvalContextPrivExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, // Make sure that raw pointers and mutable shared references are reborrowed "weak": // There could be existing unique pointers reborrowed from them that should remain valid! let perm = match kind { - RefKind::Unique => Permission::Unique, + RefKind::Unique { two_phase: false } => Permission::Unique, + RefKind::Unique { two_phase: true } => Permission::SharedReadWrite, RefKind::Raw { mutable: true } => Permission::SharedReadWrite, RefKind::Shared | RefKind::Raw { mutable: false } => { // Shared references and *const are a whole different kind of game, the @@ -576,19 +558,16 @@ trait EvalContextPrivExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, return this.visit_freeze_sensitive(place, size, |cur_ptr, size, frozen| { // We are only ever `SharedReadOnly` inside the frozen bits. let perm = if frozen { Permission::SharedReadOnly } else { Permission::SharedReadWrite }; - let weak = perm == Permission::SharedReadWrite; let item = Item { perm, tag: new_tag, protector }; alloc.extra.for_each(cur_ptr, size, |stack, global| { - stack.grant(cur_ptr.tag, force_weak || weak, item, global) + stack.grant(cur_ptr.tag, item, global) }) }); } }; - debug_assert_ne!(perm, Permission::SharedReadOnly, "SharedReadOnly must be used frozen-sensitive"); - let weak = perm == Permission::SharedReadWrite; let item = Item { perm, tag: new_tag, protector }; alloc.extra.for_each(ptr, size, |stack, global| { - stack.grant(ptr.tag, force_weak || weak, item, global) + stack.grant(ptr.tag, item, global) }) } @@ -599,7 +578,6 @@ trait EvalContextPrivExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, val: ImmTy<'tcx, Tag>, kind: RefKind, protect: bool, - two_phase: bool, ) -> EvalResult<'tcx, Immediate> { let this = self.eval_context_mut(); // We want a place for where the ptr *points to*, so we get one. @@ -619,22 +597,8 @@ trait EvalContextPrivExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, }; // Reborrow. - // TODO: With `two_phase == true`, this performs a weak reborrow for a `Unique`. That - // can lead to some possibly surprising effects, if the parent permission is - // `SharedReadWrite` then we now have a `Unique` in the middle of them, which "splits" - // them in terms of what remains valid when the `Unique` gets used. Is that really - // what we want? - this.reborrow(place, size, kind, new_tag, /*force_weak:*/ two_phase, protect)?; + this.reborrow(place, size, kind, new_tag, protect)?; let new_place = place.replace_tag(new_tag); - // Handle two-phase borrows. - if two_phase { - assert!(kind == RefKind::Unique, "two-phase shared borrows make no sense"); - // Grant read access *to the parent pointer* with the old tag *derived from the new tag* (`new_place`). - // This means the old pointer has multiple items in the stack now, which otherwise cannot happen - // for unique references -- but in this case it precisely expresses the semantics we want. - let old_tag = place.ptr.to_ptr().unwrap().tag; - this.reborrow(new_place, size, RefKind::Shared, old_tag, /*force_weak:*/ false, /*protect:*/ false)?; - } // Return new pointer. Ok(new_place.to_ref()) @@ -656,7 +620,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, match ty.sty { // References are simple. ty::Ref(_, _, MutMutable) => - Some((RefKind::Unique, kind == RetagKind::FnEntry)), + Some((RefKind::Unique { two_phase: kind == RetagKind::TwoPhase}, kind == RetagKind::FnEntry)), ty::Ref(_, _, MutImmutable) => Some((RefKind::Shared, kind == RetagKind::FnEntry)), // Raw pointers need to be enabled. @@ -664,7 +628,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, Some((RefKind::Raw { mutable: tym.mutbl == MutMutable }, false)), // Boxes do not get a protector: protectors reflect that references outlive the call // they were passed in to; that's just not the case for boxes. - ty::Adt(..) if ty.is_box() => Some((RefKind::Unique, false)), + ty::Adt(..) if ty.is_box() => Some((RefKind::Unique { two_phase: false }, false)), _ => None, } } @@ -675,7 +639,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, if let Some((mutbl, protector)) = qualify(place.layout.ty, kind) { // Fast path. let val = this.read_immediate(this.place_to_op(place)?)?; - let val = this.retag_reference(val, mutbl, protector, kind == RetagKind::TwoPhase)?; + let val = this.retag_reference(val, mutbl, protector)?; this.write_immediate(val, place)?; return Ok(()); } @@ -711,8 +675,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, let val = self.ecx.retag_reference( val, mutbl, - protector, - self.kind == RetagKind::TwoPhase + protector )?; self.ecx.write_immediate(val, place.into())?; } diff --git a/tests/compile-fail/stacked_borrows/deallocate_against_barrier.rs b/tests/compile-fail/stacked_borrows/deallocate_against_barrier.rs index 49e376c0287e8..bf18c9a058cf9 100644 --- a/tests/compile-fail/stacked_borrows/deallocate_against_barrier.rs +++ b/tests/compile-fail/stacked_borrows/deallocate_against_barrier.rs @@ -1,4 +1,4 @@ -// error-pattern: deallocating with active protect +// error-pattern: deallocating while item is protected fn inner(x: &mut i32, f: fn(&mut i32)) { // `f` may mutate, but it may not deallocate! From 8212314441bc2a60f4f28d097eb6125c88859a13 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 17 May 2019 15:03:28 +0200 Subject: [PATCH 0744/3747] fix tests --- test-cargo-miri/test.stdout.ref | 5 ++--- test-cargo-miri/test.stdout.ref2 | 2 +- test-cargo-miri/tests/test.rs | 2 +- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/test-cargo-miri/test.stdout.ref b/test-cargo-miri/test.stdout.ref index 97589e9a16351..58b9b4794b902 100644 --- a/test-cargo-miri/test.stdout.ref +++ b/test-cargo-miri/test.stdout.ref @@ -5,10 +5,9 @@ test test::rng ... ok test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out -running 3 tests +running 2 tests test entropy_rng ... ok -test fixed_rng ... ok test simple ... ok -test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out +test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out diff --git a/test-cargo-miri/test.stdout.ref2 b/test-cargo-miri/test.stdout.ref2 index 32d943623a919..ce3506709d5a0 100644 --- a/test-cargo-miri/test.stdout.ref2 +++ b/test-cargo-miri/test.stdout.ref2 @@ -7,5 +7,5 @@ test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 1 filtered out running 1 test test simple ... ok -test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 2 filtered out +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 1 filtered out diff --git a/test-cargo-miri/tests/test.rs b/test-cargo-miri/tests/test.rs index b4f5563a3a8bc..ed9efa21e4fa9 100644 --- a/test-cargo-miri/tests/test.rs +++ b/test-cargo-miri/tests/test.rs @@ -1,4 +1,4 @@ -use rand::{SeedableRng, FromEntropy, Rng, rngs::SmallRng}; +use rand::{FromEntropy, Rng, rngs::SmallRng}; // Having more than 1 test does seem to make a difference // (i.e., this calls ptr::swap which having just one test does not). From 9c161b80d05250a0a8f6e6f5f8d462c510aecf32 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 17 May 2019 14:22:55 +0200 Subject: [PATCH 0745/3747] reading does not remove Unique, it just invalidates them --- src/stacked_borrows.rs | 43 +++++++++++++++++++++++++----------------- 1 file changed, 26 insertions(+), 17 deletions(-) diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 33d9509bd3f93..d14d00018a7ab 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -42,6 +42,9 @@ pub enum Permission { SharedReadWrite, /// Greants shared read-only access. SharedReadOnly, + /// Grants no access, but separates two groups of SharedReadWrite so they are not + /// all considered mutually compatible. + Disabled, } /// An item in the per-location borrow stack. @@ -199,8 +202,8 @@ impl Default for Tag { impl Permission { /// This defines for a given permission, whether it permits the given kind of access. fn grants(self, access: AccessKind) -> bool { - // All items grant read access, and except for SharedReadOnly they grant write access. - access == AccessKind::Read || self != Permission::SharedReadOnly + // Disabled grants nother. Otherwise, all items grant read access, and except for SharedReadOnly they grant write access. + self != Permission::Disabled && (access == AccessKind::Read || self != Permission::SharedReadOnly) } } @@ -224,12 +227,14 @@ impl<'tcx> Stack { } /// Find the first write-incompatible item above the given one -- - /// i.e, find the heigh to which the stack will be truncated when writing to `granting`. + /// i.e, find the height to which the stack will be truncated when writing to `granting`. fn find_first_write_incompaible(&self, granting: usize) -> usize { let perm = self.borrows[granting].perm; match perm { Permission::SharedReadOnly => bug!("Cannot use SharedReadOnly for writing"), + Permission::Disabled => + bug!("Cannot use Disabled for anything"), Permission::Unique => // On a write, everything above us is incompatible. granting+1, @@ -250,10 +255,8 @@ impl<'tcx> Stack { } } - /// Remove the given item, enforcing barriers. - /// `tag` is just used for the error message. - fn remove(&mut self, idx: usize, tag: Option, global: &GlobalState) -> EvalResult<'tcx> { - let item = self.borrows.remove(idx); + /// Check if the given item is protected. + fn check_protector(item: &Item, tag: Option, global: &GlobalState) -> EvalResult<'tcx> { if let Some(call) = item.protector { if global.is_active(call) { if let Some(tag) = tag { @@ -268,7 +271,6 @@ impl<'tcx> Stack { } } } - trace!("access: removing item {}", item); Ok(()) } @@ -295,20 +297,26 @@ impl<'tcx> Stack { // Remove everything above the write-compatible items, like a proper stack. This makes sure read-only and unique // pointers become invalid on write accesses (ensures F2a, and ensures U2 for write accesses). let first_incompatible_idx = self.find_first_write_incompaible(granting_idx); - for idx in (first_incompatible_idx..self.borrows.len()).rev() { - self.remove(idx, Some(tag), global)?; + while self.borrows.len() > first_incompatible_idx { + let item = self.borrows.pop().unwrap(); + trace!("access: popping item {}", item); + Stack::check_protector(&item, Some(tag), global)?; } } else { - // On a read, remove all `Unique` above the granting item. This ensures U2 for read accesses. - // The reason this is not following the stack discipline is that in - // `let raw = &mut *x as *mut _; let _val = *x;`, the second statement + // On a read, *disable* all `Unique` above the granting item. This ensures U2 for read accesses. + // The reason this is not following the stack discipline (by removing the first Unique and + // everything on top of it) is that in `let raw = &mut *x as *mut _; let _val = *x;`, the second statement // would pop the `Unique` from the reborrow of the first statement, and subsequently also pop the // `SharedReadWrite` for `raw`. // This pattern occurs a lot in the standard library: create a raw pointer, then also create a shared // reference and use that. + // We *disable* instead of removing `Unique` to avoid "connecting" two neighbouring blocks of SRWs. for idx in (granting_idx+1 .. self.borrows.len()).rev() { - if self.borrows[idx].perm == Permission::Unique { - self.remove(idx, Some(tag), global)?; + let item = &mut self.borrows[idx]; + if item.perm == Permission::Unique { + trace!("access: disabling item {}", item); + Stack::check_protector(item, Some(tag), global)?; + item.perm = Permission::Disabled; } } } @@ -332,8 +340,9 @@ impl<'tcx> Stack { )))?; // Step 2: Remove all items. Also checks for protectors. - for idx in (0..self.borrows.len()).rev() { - self.remove(idx, None, global)?; + while self.borrows.len() > 0 { + let item = self.borrows.pop().unwrap(); + Stack::check_protector(&item, None, global)?; } Ok(()) From 6b4164e0df2a4fb14bee133a026774728ecb35d9 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 17 May 2019 19:42:35 +0200 Subject: [PATCH 0746/3747] nits --- src/stacked_borrows.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index d14d00018a7ab..239752ea242e9 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -237,10 +237,10 @@ impl<'tcx> Stack { bug!("Cannot use Disabled for anything"), Permission::Unique => // On a write, everything above us is incompatible. - granting+1, + granting + 1, Permission::SharedReadWrite => { // The SharedReadWrite *just* above us are compatible, to skip those. - let mut idx = granting+1; + let mut idx = granting + 1; while let Some(item) = self.borrows.get(idx) { if item.perm == Permission::SharedReadWrite { // Go on. From 3fde45233bbca880e8ed0dbcb33a107bd0c07d86 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Sun, 19 May 2019 12:40:59 +0200 Subject: [PATCH 0747/3747] Prefer `drain` over manual implementation of `drain` --- src/stacked_borrows.rs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 239752ea242e9..e0ac6bf05a743 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -226,7 +226,7 @@ impl<'tcx> Stack { ) } - /// Find the first write-incompatible item above the given one -- + /// Find the first write-incompatible item above the given one -- /// i.e, find the height to which the stack will be truncated when writing to `granting`. fn find_first_write_incompaible(&self, granting: usize) -> usize { let perm = self.borrows[granting].perm; @@ -297,8 +297,7 @@ impl<'tcx> Stack { // Remove everything above the write-compatible items, like a proper stack. This makes sure read-only and unique // pointers become invalid on write accesses (ensures F2a, and ensures U2 for write accesses). let first_incompatible_idx = self.find_first_write_incompaible(granting_idx); - while self.borrows.len() > first_incompatible_idx { - let item = self.borrows.pop().unwrap(); + for item in self.borrows.drain(first_incompatible_idx..).rev() { trace!("access: popping item {}", item); Stack::check_protector(&item, Some(tag), global)?; } @@ -340,8 +339,7 @@ impl<'tcx> Stack { )))?; // Step 2: Remove all items. Also checks for protectors. - while self.borrows.len() > 0 { - let item = self.borrows.pop().unwrap(); + for item in self.borrows.drain(..).rev() { Stack::check_protector(&item, None, global)?; } From 5c54a58c066a7cc05f1106811cd78334ccdc727a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 19 May 2019 13:59:18 +0200 Subject: [PATCH 0748/3747] typo --- src/stacked_borrows.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index e0ac6bf05a743..be6bec60cfd43 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -40,7 +40,7 @@ pub enum Permission { Unique, /// Grants shared mutable access. SharedReadWrite, - /// Greants shared read-only access. + /// Grants shared read-only access. SharedReadOnly, /// Grants no access, but separates two groups of SharedReadWrite so they are not /// all considered mutually compatible. @@ -202,7 +202,7 @@ impl Default for Tag { impl Permission { /// This defines for a given permission, whether it permits the given kind of access. fn grants(self, access: AccessKind) -> bool { - // Disabled grants nother. Otherwise, all items grant read access, and except for SharedReadOnly they grant write access. + // Disabled grants nothing. Otherwise, all items grant read access, and except for SharedReadOnly they grant write access. self != Permission::Disabled && (access == AccessKind::Read || self != Permission::SharedReadOnly) } } From df36c2bb7d6a71d3fe420e1aba9a0bd0655e9758 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 20 May 2019 09:32:01 +0200 Subject: [PATCH 0749/3747] expand explanation of how we treat validity invariants --- README.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 22eb41f949007..ae2f5f506f16f 100644 --- a/README.md +++ b/README.md @@ -23,9 +23,11 @@ Be aware that Miri will not catch all possible errors in your program, and cannot run all programs: * There are still plenty of open questions around the basic invariants for some - types and when these invariants even have to hold, so if you program runs fine - in Miri right now that is by no means a guarantee that it is UB-free when - these questions get answered. + types and when these invariants even have to hold. Miri tries to avoid false + positives here, so if you program runs fine in Miri right now that is by no + means a guarantee that it is UB-free when these questions get answered. In + particular, Miri does currently not check that integers are initialized or + that references point to valid data. * If the program relies on unspecified details of how data is laid out, it will still run fine in Miri -- but might break (including causing UB) on different compiler versions or different platforms. From 0c85dbf3df0f545133dca24eccfc9f0f6107c7f8 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 20 May 2019 10:46:28 +0200 Subject: [PATCH 0750/3747] prepare for MaybeUninit stabilization --- tests/run-pass/stacked-borrows/interior_mutability.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/run-pass/stacked-borrows/interior_mutability.rs b/tests/run-pass/stacked-borrows/interior_mutability.rs index d27519df48a75..bd19f153deeb4 100644 --- a/tests/run-pass/stacked-borrows/interior_mutability.rs +++ b/tests/run-pass/stacked-borrows/interior_mutability.rs @@ -1,4 +1,4 @@ -#![feature(maybe_uninit, maybe_uninit_ref)] +#![feature(maybe_uninit_extra, maybe_uninit_ref)] use std::mem::MaybeUninit; use std::cell::{Cell, RefCell, UnsafeCell}; From 5a4e1cdd863d206b75e244895df6d05200b85c56 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 21 May 2019 08:54:15 +0200 Subject: [PATCH 0751/3747] update Rust --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 4cf2697aa4212..3c8fa005c32de 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -372be4f360ce42b1a10126a711189796f8440ab4 +d35181ad8785fa958e43580a29a982afe02c728f From 74f98b3803404dd86d6c6365081e2276fa7a0543 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 21 May 2019 15:41:26 +0200 Subject: [PATCH 0752/3747] test for new read rules --- .../stacked_borrows/interior_mut1.rs | 11 ++++++-- .../stacked_borrows/interior_mut2.rs | 28 +++++++++++++++++++ 2 files changed, 36 insertions(+), 3 deletions(-) create mode 100644 tests/compile-fail/stacked_borrows/interior_mut2.rs diff --git a/tests/compile-fail/stacked_borrows/interior_mut1.rs b/tests/compile-fail/stacked_borrows/interior_mut1.rs index dd9fce110c2d3..e2f8233bd86b2 100644 --- a/tests/compile-fail/stacked_borrows/interior_mut1.rs +++ b/tests/compile-fail/stacked_borrows/interior_mut1.rs @@ -3,8 +3,13 @@ use std::cell::UnsafeCell; fn main() { unsafe { let c = &UnsafeCell::new(UnsafeCell::new(0)); let inner_uniq = &mut *c.get(); - let inner_shr = &*inner_uniq; // a SharedRW with a tag - *c.get() = UnsafeCell::new(1); // invalidates the SharedRW + // stack: [c: SharedReadWrite, inner_uniq: Unique] + + let inner_shr = &*inner_uniq; // adds a SharedReadWrite + // stack: [c: SharedReadWrite, inner_uniq: Unique, inner_shr: SharedReadWrite] + + *c.get() = UnsafeCell::new(1); // invalidates inner_shr + // stack: [c: SharedReadWrite] + let _val = *inner_shr.get(); //~ ERROR borrow stack - let _val = *inner_uniq.get(); } } diff --git a/tests/compile-fail/stacked_borrows/interior_mut2.rs b/tests/compile-fail/stacked_borrows/interior_mut2.rs new file mode 100644 index 0000000000000..45770020d33d7 --- /dev/null +++ b/tests/compile-fail/stacked_borrows/interior_mut2.rs @@ -0,0 +1,28 @@ +use std::cell::UnsafeCell; +use std::mem; + +// Like `&mut *x.get()`, but without intermediate raw pointers. +#[allow(mutable_transmutes)] +unsafe fn unsafe_cell_get(x: &UnsafeCell) -> &'static mut T { + mem::transmute(x) +} + +fn main() { unsafe { + let c = &UnsafeCell::new(UnsafeCell::new(0)); + let inner_uniq = &mut *c.get(); + let inner_shr = &*inner_uniq; + // stack: [c: SharedReadWrite, inner_uniq: Unique, inner_shr: SharedReadWrite] + + let _val = c.get().read(); // invalidates inner_uniq + // stack: [c: SharedReadWrite, inner_uniq: Disabled, inner_shr: SharedReadWrite] + + // We have to be careful not to add any raw pointers above inner_uniq in + // the stack, hence the use of unsafe_cell_get. + let _val = *unsafe_cell_get(inner_shr); // this still works + + *c.get() = UnsafeCell::new(0); // now inner_shr gets invalidated + // stack: [c: SharedReadWrite] + + // now this does not work any more + let _val = *inner_shr.get(); //~ ERROR borrow stack +} } From 3e33e54b5be77d03df0962291f1480cc3876544d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 23 May 2019 11:03:04 +0200 Subject: [PATCH 0753/3747] hopefully improve error message a bit --- src/stacked_borrows.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index be6bec60cfd43..e76747ef8071f 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -383,7 +383,7 @@ impl<'tcx> Stack { // We use that to determine where to put the new item. let granting_idx = self.find_granting(access, derived_from) .ok_or_else(|| InterpError::MachineError(format!( - "no item to reborrow for {:?} from tag {} found in borrow stack", new.perm, derived_from, + "trying to reborrow for {:?}, but parent tag {} does not have an appropriate item in the borrow stack", new.perm, derived_from, )))?; // Compute where to put the new item. From 1d92791965f81f44f2d961396e4eda6d43392d8d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 23 May 2019 15:54:50 +0200 Subject: [PATCH 0754/3747] use prettier printing --- src/stacked_borrows.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index e76747ef8071f..332e44e6780e4 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -545,7 +545,7 @@ trait EvalContextPrivExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, let this = self.eval_context_mut(); let protector = if protect { Some(this.frame().extra) } else { None }; let ptr = place.ptr.to_ptr()?; - trace!("reborrow: {:?} reference {} derived from {} (pointee {}): {:?}, size {}", + trace!("reborrow: {} reference {} derived from {} (pointee {}): {:?}, size {}", kind, new_tag, ptr.tag, place.layout.ty, ptr, size.bytes()); // Get the allocation. It might not be mutable, so we cannot use `get_mut`. From ff6f1010747104db6af41b2a49d168af66328910 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 23 May 2019 16:33:44 +0200 Subject: [PATCH 0755/3747] add more bugs that Miri found --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index ae2f5f506f16f..d3a06dea6d276 100644 --- a/README.md +++ b/README.md @@ -317,6 +317,7 @@ Definite bugs found: * [`Debug for vec_deque::Iter` accessing uninitialized memory](https://github.com/rust-lang/rust/issues/53566) * [`From<&[T]> for Rc` creating a not sufficiently aligned reference](https://github.com/rust-lang/rust/issues/54908) * [`BTreeMap` creating a shared reference pointing to a too small allocation](https://github.com/rust-lang/rust/issues/54957) +* [`Vec::append` creating a dangling reference](https://github.com/rust-lang/rust/pull/61082) * [Futures turning a shared reference into a mutable one](https://github.com/rust-lang/rust/pull/56319) * [`str` turning a shared reference into a mutable one](https://github.com/rust-lang/rust/pull/58200) * [`rand` performing unaligned reads](https://github.com/rust-random/rand/issues/779) @@ -326,6 +327,7 @@ Violations of Stacked Borrows found that are likely bugs (but Stacked Borrows is * [`VecDeque` creating overlapping mutable references](https://github.com/rust-lang/rust/pull/56161) * [`BTreeMap` creating mutable references that overlap with shared references](https://github.com/rust-lang/rust/pull/58431) * [`LinkedList` creating overlapping mutable references](https://github.com/rust-lang/rust/pull/60072) +* [`Vec::push` invalidating existing references into the vector](https://github.com/rust-lang/rust/issues/60847) ## License From 5569fffe7d71ed52ce284d0ffc6691d0141874f2 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 24 May 2019 10:09:18 +0200 Subject: [PATCH 0756/3747] avoid having both Debug and Display for a type and using the wrong one --- src/stacked_borrows.rs | 46 +++++++++++++++++++++--------------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 332e44e6780e4..0c1e9b9c49aaf 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -18,16 +18,16 @@ pub type PtrId = NonZeroU64; pub type CallId = NonZeroU64; /// Tracking pointer provenance -#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] +#[derive(Copy, Clone, Hash, PartialEq, Eq)] pub enum Tag { Tagged(PtrId), Untagged, } -impl fmt::Display for Tag { +impl fmt::Debug for Tag { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { - Tag::Tagged(id) => write!(f, "{}", id), + Tag::Tagged(id) => write!(f, "<{}>", id), Tag::Untagged => write!(f, ""), } } @@ -48,7 +48,7 @@ pub enum Permission { } /// An item in the per-location borrow stack. -#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] +#[derive(Copy, Clone, Hash, PartialEq, Eq)] pub struct Item { /// The permission this item grants. perm: Permission, @@ -58,9 +58,9 @@ pub struct Item { protector: Option, } -impl fmt::Display for Item { +impl fmt::Debug for Item { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "[{:?} for {}", self.perm, self.tag)?; + write!(f, "[{:?} for {:?}", self.perm, self.tag)?; if let Some(call) = self.protector { write!(f, " (call {})", call)?; } @@ -99,7 +99,7 @@ pub struct GlobalState { pub type MemoryState = Rc>; /// Indicates which kind of access is being performed. -#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] +#[derive(Copy, Clone, Hash, PartialEq, Eq)] pub enum AccessKind { Read, Write, @@ -108,8 +108,8 @@ pub enum AccessKind { impl fmt::Display for AccessKind { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { - AccessKind::Read => write!(f, "read"), - AccessKind::Write => write!(f, "write"), + AccessKind::Read => write!(f, "read access"), + AccessKind::Write => write!(f, "write access"), } } } @@ -117,7 +117,7 @@ impl fmt::Display for AccessKind { /// Indicates which kind of reference is being created. /// Used by high-level `reborrow` to compute which permissions to grant to the /// new pointer. -#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] +#[derive(Copy, Clone, Hash, PartialEq, Eq)] pub enum RefKind { /// `&mut` and `Box`. Unique { two_phase: bool }, @@ -261,12 +261,12 @@ impl<'tcx> Stack { if global.is_active(call) { if let Some(tag) = tag { return err!(MachineError(format!( - "not granting access to tag {} because incompatible item is protected: {}", + "not granting access to tag {:?} because incompatible item is protected: {:?}", tag, item ))); } else { return err!(MachineError(format!( - "deallocating while item is protected: {}", item + "deallocating while item is protected: {:?}", item ))); } } @@ -287,7 +287,7 @@ impl<'tcx> Stack { // Step 1: Find granting item. let granting_idx = self.find_granting(access, tag) .ok_or_else(|| InterpError::MachineError(format!( - "no item granting {} access to tag {} found in borrow stack", + "no item granting {} to tag {:?} found in borrow stack", access, tag, )))?; @@ -298,7 +298,7 @@ impl<'tcx> Stack { // pointers become invalid on write accesses (ensures F2a, and ensures U2 for write accesses). let first_incompatible_idx = self.find_first_write_incompaible(granting_idx); for item in self.borrows.drain(first_incompatible_idx..).rev() { - trace!("access: popping item {}", item); + trace!("access: popping item {:?}", item); Stack::check_protector(&item, Some(tag), global)?; } } else { @@ -313,7 +313,7 @@ impl<'tcx> Stack { for idx in (granting_idx+1 .. self.borrows.len()).rev() { let item = &mut self.borrows[idx]; if item.perm == Permission::Unique { - trace!("access: disabling item {}", item); + trace!("access: disabling item {:?}", item); Stack::check_protector(item, Some(tag), global)?; item.perm = Permission::Disabled; } @@ -334,7 +334,7 @@ impl<'tcx> Stack { // Step 1: Find granting item. self.find_granting(AccessKind::Write, tag) .ok_or_else(|| InterpError::MachineError(format!( - "no item granting write access for deallocation to tag {} found in borrow stack", + "no item granting write access for deallocation to tag {:?} found in borrow stack", tag, )))?; @@ -383,7 +383,7 @@ impl<'tcx> Stack { // We use that to determine where to put the new item. let granting_idx = self.find_granting(access, derived_from) .ok_or_else(|| InterpError::MachineError(format!( - "trying to reborrow for {:?}, but parent tag {} does not have an appropriate item in the borrow stack", new.perm, derived_from, + "trying to reborrow for {:?}, but parent tag {:?} does not have an appropriate item in the borrow stack", new.perm, derived_from, )))?; // Compute where to put the new item. @@ -412,9 +412,9 @@ impl<'tcx> Stack { // Put the new item there. As an optimization, deduplicate if it is equal to one of its new neighbors. if self.borrows[new_idx-1] == new || self.borrows.get(new_idx) == Some(&new) { // Optimization applies, done. - trace!("reborrow: avoiding adding redundant item {}", new); + trace!("reborrow: avoiding adding redundant item {:?}", new); } else { - trace!("reborrow: adding item {}", new); + trace!("reborrow: adding item {:?}", new); self.borrows.insert(new_idx, new); } @@ -497,7 +497,7 @@ impl AllocationExtra for Stacks { ptr: Pointer, size: Size, ) -> EvalResult<'tcx> { - trace!("read access with tag {}: {:?}, size {}", ptr.tag, ptr, size.bytes()); + trace!("read access with tag {:?}: {:?}, size {}", ptr.tag, ptr, size.bytes()); alloc.extra.for_each(ptr, size, |stack, global| { stack.access(AccessKind::Read, ptr.tag, global)?; Ok(()) @@ -510,7 +510,7 @@ impl AllocationExtra for Stacks { ptr: Pointer, size: Size, ) -> EvalResult<'tcx> { - trace!("write access with tag {}: {:?}, size {}", ptr.tag, ptr, size.bytes()); + trace!("write access with tag {:?}: {:?}, size {}", ptr.tag, ptr, size.bytes()); alloc.extra.for_each(ptr, size, |stack, global| { stack.access(AccessKind::Write, ptr.tag, global)?; Ok(()) @@ -523,7 +523,7 @@ impl AllocationExtra for Stacks { ptr: Pointer, size: Size, ) -> EvalResult<'tcx> { - trace!("deallocation with tag {}: {:?}, size {}", ptr.tag, ptr, size.bytes()); + trace!("deallocation with tag {:?}: {:?}, size {}", ptr.tag, ptr, size.bytes()); alloc.extra.for_each(ptr, size, |stack, global| { stack.dealloc(ptr.tag, global) }) @@ -545,7 +545,7 @@ trait EvalContextPrivExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, let this = self.eval_context_mut(); let protector = if protect { Some(this.frame().extra) } else { None }; let ptr = place.ptr.to_ptr()?; - trace!("reborrow: {} reference {} derived from {} (pointee {}): {:?}, size {}", + trace!("reborrow: {} reference {:?} derived from {:?} (pointee {}): {:?}, size {}", kind, new_tag, ptr.tag, place.layout.ty, ptr, size.bytes()); // Get the allocation. It might not be mutable, so we cannot use `get_mut`. From 21fb14dba1649ef8f2be612df2943fc9313781be Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 24 May 2019 13:09:29 +0200 Subject: [PATCH 0757/3747] avoid printing the tag twice --- src/stacked_borrows.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 0c1e9b9c49aaf..f997e6316435a 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -497,7 +497,7 @@ impl AllocationExtra for Stacks { ptr: Pointer, size: Size, ) -> EvalResult<'tcx> { - trace!("read access with tag {:?}: {:?}, size {}", ptr.tag, ptr, size.bytes()); + trace!("read access with tag {:?}: {:?}, size {}", ptr.tag, ptr.erase_tag(), size.bytes()); alloc.extra.for_each(ptr, size, |stack, global| { stack.access(AccessKind::Read, ptr.tag, global)?; Ok(()) @@ -510,7 +510,7 @@ impl AllocationExtra for Stacks { ptr: Pointer, size: Size, ) -> EvalResult<'tcx> { - trace!("write access with tag {:?}: {:?}, size {}", ptr.tag, ptr, size.bytes()); + trace!("write access with tag {:?}: {:?}, size {}", ptr.tag, ptr.erase_tag(), size.bytes()); alloc.extra.for_each(ptr, size, |stack, global| { stack.access(AccessKind::Write, ptr.tag, global)?; Ok(()) @@ -523,7 +523,7 @@ impl AllocationExtra for Stacks { ptr: Pointer, size: Size, ) -> EvalResult<'tcx> { - trace!("deallocation with tag {:?}: {:?}, size {}", ptr.tag, ptr, size.bytes()); + trace!("deallocation with tag {:?}: {:?}, size {}", ptr.tag, ptr.erase_tag(), size.bytes()); alloc.extra.for_each(ptr, size, |stack, global| { stack.dealloc(ptr.tag, global) }) @@ -546,7 +546,7 @@ trait EvalContextPrivExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, let protector = if protect { Some(this.frame().extra) } else { None }; let ptr = place.ptr.to_ptr()?; trace!("reborrow: {} reference {:?} derived from {:?} (pointee {}): {:?}, size {}", - kind, new_tag, ptr.tag, place.layout.ty, ptr, size.bytes()); + kind, new_tag, ptr.tag, place.layout.ty, ptr.erase_tag(), size.bytes()); // Get the allocation. It might not be mutable, so we cannot use `get_mut`. let alloc = this.memory().get(ptr.alloc_id)?; From aa868a8a212656a965b25762fb3a45f0bd64666c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 27 May 2019 09:45:00 +0200 Subject: [PATCH 0758/3747] dependency management --- Cargo.toml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 639fd50c75033..6f7570edda5fd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -40,12 +40,15 @@ rustc_version = { version = "0.2.3", optional = true } env_logger = "0.6" log = "0.4" shell-escape = "0.1.4" +hex = "0.3.2" +rand = "0.6" # A noop dependency that changes in the Rust repository, it's a bit of a hack. # See the `src/tools/rustc-workspace-hack/README.md` file in `rust-lang/rust` # for more information. rustc-workspace-hack = "1.0.0" -hex = "0.3.2" -rand = "0.6" +# Depend on num-traits with default features to avoid having to rebuild +# between "cargo build" and "cargo intall". +num-traits = "*" [build-dependencies] vergen = "3" From c2791fc56abba235c4d0d56a746e24ac2cb778bf Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 27 May 2019 12:51:59 +0200 Subject: [PATCH 0759/3747] add 'miri' script to help build, test and run miri --- miri | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100755 miri diff --git a/miri b/miri new file mode 100755 index 0000000000000..fc8fdb7b5b25d --- /dev/null +++ b/miri @@ -0,0 +1,36 @@ +#!/bin/sh +set -e +TARGET=$(rustc --print target-spec-json -Z unstable-options | jq '.["llvm-target"]' -r) +SYSROOT=$(rustc --print sysroot) +export RUSTFLAGS="-C link-args=-Wl,-rpath,$SYSROOT/lib/rustlib/$TARGET/lib -C debug-assertions" + +COMMAND="$1" +shift + +case "$COMMAND" in +install) + exec cargo install --path "$(dirname "$0")" --force --locked --offline + ;; +build|test|run) + # Basic build + cargo build --release + + # We we want to just build, we are done. + if [ "$COMMAND" = "build" ]; then exit 0; fi + + # Get ourselves a sysroot + if [ -n "$MIRI_SYSROOT" ]; then + # sysroot already set + true + elif rustc --print sysroot | egrep -q 'build/[^/]+/stage'; then + # a local build, we have a proper libstd in $SYSROOT + true + else + # we have to build a sysroot + cargo run --release --bin cargo-miri -- miri setup + export MIRI_SYSROOT=$HOME/.cache/miri/HOST + fi + + exec cargo "$COMMAND" --release "$@" + ;; +esac From 6420293af4b87bca51c51661de1aa53d2158cdb5 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 27 May 2019 12:59:52 +0200 Subject: [PATCH 0760/3747] adjust readme to miri build script --- README.md | 47 +++++++++++------------------------------------ 1 file changed, 11 insertions(+), 36 deletions(-) diff --git a/README.md b/README.md index d3a06dea6d276..09b23b0db12f0 100644 --- a/README.md +++ b/README.md @@ -141,42 +141,28 @@ version of `rustc` that, instead of compiling your code, runs it. It accepts all the same flags as `rustc` (though the ones only affecting code generation and linking obviously will have no effect) [and more][miri-flags]. -To run the Miri driver, you need to have the `MIRI_SYSROOT` environment variable -set to an appropriate sysroot. You can generate such a sysroot with the -following incantation: - -``` -cargo run --bin cargo-miri -- miri setup -``` - -This basically runs the `cargo-miri` binary (which backs the `cargo miri` -subcommand) with `cargo`, and asks it to `setup`. It should in the end print -the directory where the libstd was built. In the following, we will assume it -is `~/.cache/miri/HOST`; you may have to adjust that if you are not using Linux. - -Now you can run the driver directly using +Running the Miri driver requires some fiddling with environment variables, so the `miri` script helps you do that. +For example, you can run the driver on a particular file by doing ```sh -MIRI_SYSROOT=~/.cache/miri/HOST cargo run tests/run-pass/format.rs # or whatever test you like +./miri run tests/run-pass/format.rs # or whatever test you like ``` and you can run the test suite using ``` -cargo test +./miri test ``` -We recommend adding the `--release` flag to make tests run faster. - -`cargo test --release FILTER` only runs those tests that contain `FILTER` in -their filename (including the base directory, e.g. `cargo test --release fail` -will run all compile-fail tests). +`./miri test FILTER` only runs those tests that contain `FILTER` in their +filename (including the base directory, e.g. `./miri test fail` will run all +compile-fail tests). You can get a trace of which MIR statements are being executed by setting the `MIRI_LOG` environment variable. For example: ```sh -MIRI_LOG=info cargo run tests/run-pass/vecs.rs +MIRI_LOG=info ./miri run tests/run-pass/vecs.rs ``` Setting `MIRI_LOG` like this will configure logging for Miri itself as well as @@ -185,7 +171,7 @@ can also do more targeted configuration, e.g. the following helps debug the stacked borrows implementation: ```sh -MIRI_LOG=rustc_mir::interpret=info,miri::stacked_borrows cargo run tests/run-pass/vecs.rs +MIRI_LOG=rustc_mir::interpret=info,miri::stacked_borrows ./miri run tests/run-pass/vecs.rs ``` In addition, you can set `MIRI_BACKTRACE=1` to get a backtrace of where an @@ -199,7 +185,7 @@ is probably easier to test it with the cargo wrapper. You can install your development version of Miri using ``` -cargo install --path . --force +./miri install ``` and then you can use it as if it was installed by `rustup`. Make sure you use @@ -235,18 +221,7 @@ rustup override set custom ``` With this, you should now have a working development setup! See -[above][testing-miri] for how to proceed working with the Miri driver. Notice -that rustc's sysroot is already built for Miri in this case, so you can set -`MIRI_SYSROOT=$(rustc --print sysroot)`. - -Running `cargo miri` in this setup is a bit more complicated, because the Miri -binary you just created needs help to find the libraries it links against. On -Linux, you can set the rpath to make this "just work": - -```sh -export RUSTFLAGS="-C link-args=-Wl,-rpath,$(rustc --print sysroot)/lib/rustlib/x86_64-unknown-linux-gnu/lib" -cargo install --path . --force -``` +[above][testing-miri] for how to proceed working with the Miri driver. ### Miri `-Z` flags and environment variables [miri-flags]: #miri--z-flags-and-environment-variables From ab1f60c9105f41f0ba3d6e7b87674828dcabc025 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 27 May 2019 13:04:18 +0200 Subject: [PATCH 0761/3747] comments --- miri | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/miri b/miri index fc8fdb7b5b25d..bc8bd59e5dd52 100755 --- a/miri +++ b/miri @@ -2,6 +2,8 @@ set -e TARGET=$(rustc --print target-spec-json -Z unstable-options | jq '.["llvm-target"]' -r) SYSROOT=$(rustc --print sysroot) +# We set the rpath so that Miri finds the private rustc libraries it needs. +# We enable debug-assertions to get tracing. export RUSTFLAGS="-C link-args=-Wl,-rpath,$SYSROOT/lib/rustlib/$TARGET/lib -C debug-assertions" COMMAND="$1" @@ -22,8 +24,8 @@ build|test|run) if [ -n "$MIRI_SYSROOT" ]; then # sysroot already set true - elif rustc --print sysroot | egrep -q 'build/[^/]+/stage'; then - # a local build, we have a proper libstd in $SYSROOT + elif echo "$SYSROOT" | egrep -q 'build/[^/]+/stage'; then + # a local rustc build, assume we have a proper libstd in $SYSROOT true else # we have to build a sysroot From eb85ced8c730ad6a0f0518dfd7db3166a18e8108 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 27 May 2019 13:08:47 +0200 Subject: [PATCH 0762/3747] improve backtraces --- miri | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/miri b/miri index bc8bd59e5dd52..99ae7c5811eec 100755 --- a/miri +++ b/miri @@ -4,7 +4,8 @@ TARGET=$(rustc --print target-spec-json -Z unstable-options | jq '.["llvm-target SYSROOT=$(rustc --print sysroot) # We set the rpath so that Miri finds the private rustc libraries it needs. # We enable debug-assertions to get tracing. -export RUSTFLAGS="-C link-args=-Wl,-rpath,$SYSROOT/lib/rustlib/$TARGET/lib -C debug-assertions" +# We enable line-only debuginfo for backtraces. +export RUSTFLAGS="-C link-args=-Wl,-rpath,$SYSROOT/lib/rustlib/$TARGET/lib -C debug-assertions -C debuginfo=1" COMMAND="$1" shift From cf96396fccbad2cce0f4a710d26951083a9864e6 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 27 May 2019 14:40:27 +0200 Subject: [PATCH 0763/3747] make miri script smarter: auto-determine MIRI_SYSROOT, handle MIRI_TEST_TARGET --- README.md | 10 +++--- miri | 79 +++++++++++++++++++++++++++++++++---------- src/bin/cargo-miri.rs | 5 ++- travis.sh | 19 +++-------- 4 files changed, 76 insertions(+), 37 deletions(-) diff --git a/README.md b/README.md index 09b23b0db12f0..130072825e1cf 100644 --- a/README.md +++ b/README.md @@ -141,14 +141,16 @@ version of `rustc` that, instead of compiling your code, runs it. It accepts all the same flags as `rustc` (though the ones only affecting code generation and linking obviously will have no effect) [and more][miri-flags]. -Running the Miri driver requires some fiddling with environment variables, so the `miri` script helps you do that. -For example, you can run the driver on a particular file by doing +Running the Miri driver requires some fiddling with environment variables, so +the `miri` script helps you do that. For example, you can run the driver on a +particular file by doing ```sh -./miri run tests/run-pass/format.rs # or whatever test you like +./miri run tests/run-pass/format.rs +./miri run tests/run-pass/hello.rs --target i686-unknown-linux-gnu ``` -and you can run the test suite using +and you can run the test suite using: ``` ./miri test diff --git a/miri b/miri index 99ae7c5811eec..1d090c8827fd1 100755 --- a/miri +++ b/miri @@ -7,33 +7,76 @@ SYSROOT=$(rustc --print sysroot) # We enable line-only debuginfo for backtraces. export RUSTFLAGS="-C link-args=-Wl,-rpath,$SYSROOT/lib/rustlib/$TARGET/lib -C debug-assertions -C debuginfo=1" -COMMAND="$1" -shift +## Helper functions -case "$COMMAND" in -install) - exec cargo install --path "$(dirname "$0")" --force --locked --offline - ;; -build|test|run) - # Basic build - cargo build --release - - # We we want to just build, we are done. - if [ "$COMMAND" = "build" ]; then exit 0; fi +# Build a sysroot and set MIRI_SYSROOT to use it. Arguments are passed to `cargo miri setup`. +build_sysroot() { + # Build once, for the user to see. + cargo run --release --bin cargo-miri -- miri setup "$@" + # Call again, to just set env var. + eval $(cargo run --release -q --bin cargo-miri -- miri setup --env "$@") + export MIRI_SYSROOT +} +# Prepare and set MIRI_SYSROOT. Respects `MIRI_TEST_TARGET` and takes into account +# locally built vs. distributed rustc. +find_sysroot() { # Get ourselves a sysroot if [ -n "$MIRI_SYSROOT" ]; then - # sysroot already set + # Sysroot already set, use that. true elif echo "$SYSROOT" | egrep -q 'build/[^/]+/stage'; then - # a local rustc build, assume we have a proper libstd in $SYSROOT - true + # A local rustc build. + if [ -n "$MIRI_TEST_TARGET" ]; then + # Foreign targets still need a build. Use the rustc sources. + export XARGO_RUST_SRC="$SYSROOT/../../../src" + build_sysroot --target "$MIRI_TEST_TARGET" + else + # Assume we have a proper host libstd in $SYSROOT. + true + fi else - # we have to build a sysroot - cargo run --release --bin cargo-miri -- miri setup - export MIRI_SYSROOT=$HOME/.cache/miri/HOST + # We have to build a sysroot either way. + if [ -n "$MIRI_TEST_TARGET" ]; then + build_sysroot --target "$MIRI_TEST_TARGET" + else + build_sysroot + fi fi +} + +## Main + +COMMAND="$1" +shift +case "$COMMAND" in +install) + # "--locked" to respect the Cargo.lock file if it exists, + # "--offline" to avoid querying the registry (for yanked packages). + exec cargo "$COMMAND" --path "$(dirname "$0")" --force --locked --offline "$@" + ;; +build) + # Build, and let caller control flags. + exec cargo "$COMMAND" --release "$@" + ;; +test|run) + # In "run" mode, scan for "--target" to set the "MIRI_TEST_TARGET" env var so + # that we set the MIRI_SYSROOT up the right way. + if [ "$COMMAND" = "run" ] && [ -z "$MIRI_TEST_TARGET" ]; then + for ARG in "$@"; do + if [ "$LAST_ARG" = "--target" ]; then + # Found it! + export MIRI_TEST_TARGET="$ARG" + break + fi + LAST_ARG="$ARG" + done + fi + # First build and get a sysroot. + cargo build --release + find_sysroot + # Then run the actual command. exec cargo "$COMMAND" --release "$@" ;; esac diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 5dc7a75fc764c..55c53e7361a51 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -243,6 +243,7 @@ path = "lib.rs" File::create(dir.join("lib.rs")).unwrap(); // Run xargo. let target = get_arg_flag_value("--target"); + let print_env = !ask_user && has_arg_flag("--env"); // whether we just print the necessary environment variable let mut command = Command::new("xargo"); command.arg("build").arg("-q") .current_dir(&dir) @@ -265,7 +266,9 @@ path = "lib.rs" }; let sysroot = if is_host { dir.join("HOST") } else { PathBuf::from(dir) }; std::env::set_var("MIRI_SYSROOT", &sysroot); - if !ask_user { + if print_env { + println!("MIRI_SYSROOT={}", sysroot.display()); + } else if !ask_user { println!("A libstd for Miri is now available in `{}`", sysroot.display()); } } diff --git a/travis.sh b/travis.sh index 84f9c408dcba5..dc98ca44ae58a 100755 --- a/travis.sh +++ b/travis.sh @@ -3,36 +3,27 @@ set -euo pipefail # Determine configuration if [ "$TRAVIS_OS_NAME" == osx ]; then - MIRI_SYSROOT_BASE=~/Library/Caches/miri.miri.miri/ FOREIGN_TARGET=i686-apple-darwin else - MIRI_SYSROOT_BASE=~/.cache/miri/ FOREIGN_TARGET=i686-unknown-linux-gnu fi # Prepare echo "Build and install miri" -cargo build --release --all-features --all-targets -cargo install --all-features --force --path . -echo - -echo "Get ourselves a MIR-full libstd for the host and a foreign architecture" -cargo miri setup -cargo miri setup --target "$FOREIGN_TARGET" +./miri build --all-features --all-targets +./miri install echo # Test function run_tests { - cargo test --release --all-features - test-cargo-miri/run-test.py + ./miri test + test-cargo-miri/run-test.py } echo "Test host architecture" -export MIRI_SYSROOT="$MIRI_SYSROOT_BASE"/HOST run_tests echo echo "Test foreign architecture ($FOREIGN_TARGET)" -export MIRI_SYSROOT="$MIRI_SYSROOT_BASE" MIRI_TEST_TARGET="$FOREIGN_TARGET" -run_tests +MIRI_TEST_TARGET="$FOREIGN_TARGET" run_tests echo From 7f3a298f6db4acdd33e29f5c4dc20cd91efa1859 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 27 May 2019 15:02:17 +0200 Subject: [PATCH 0764/3747] improve macOS-compatibility by being more awful --- miri | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/miri b/miri index 1d090c8827fd1..7c88309c4472a 100755 --- a/miri +++ b/miri @@ -1,6 +1,7 @@ #!/bin/sh set -e -TARGET=$(rustc --print target-spec-json -Z unstable-options | jq '.["llvm-target"]' -r) +# I'd love to use `jq` for parsing the JSON properly, but macOS is totally underequipped for this kind of work. +TARGET=$(rustc --print target-spec-json -Z unstable-options | grep llvm-target | cut -d '"' -f 4) SYSROOT=$(rustc --print sysroot) # We set the rpath so that Miri finds the private rustc libraries it needs. # We enable debug-assertions to get tracing. From a358590679df59d57ca66524f162c5b2f8f2bf18 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 27 May 2019 15:05:55 +0200 Subject: [PATCH 0765/3747] fix indentation --- miri | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/miri b/miri index 7c88309c4472a..effbd023f1989 100755 --- a/miri +++ b/miri @@ -33,8 +33,8 @@ find_sysroot() { export XARGO_RUST_SRC="$SYSROOT/../../../src" build_sysroot --target "$MIRI_TEST_TARGET" else - # Assume we have a proper host libstd in $SYSROOT. - true + # Assume we have a proper host libstd in $SYSROOT. + true fi else # We have to build a sysroot either way. From 3a837cdedd782dab48b98eb488c4c8f90c013cd2 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 27 May 2019 15:19:53 +0200 Subject: [PATCH 0766/3747] add comment --- travis.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/travis.sh b/travis.sh index dc98ca44ae58a..4df12613fb831 100755 --- a/travis.sh +++ b/travis.sh @@ -17,6 +17,8 @@ echo # Test function run_tests { ./miri test + # "miri test" has built the sysroot for us, now this should pass without + # any interactive questions. test-cargo-miri/run-test.py } From aa888c55936a473d5ff0c4f474a42bf94237a77d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 27 May 2019 15:24:37 +0200 Subject: [PATCH 0767/3747] remove redundant RUSTFLAGS --- .travis.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index fd8c1260215dd..1ba55e0c724a5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -16,7 +16,6 @@ env: global: - RUST_TEST_NOCAPTURE=1 - RUST_BACKTRACE=1 - - RUSTFLAGS="-C debug-assertions" before_script: # Linux: install extra stuff for cross-compilation From 0b6b7dad8f1aaeca31a8c298fa8fcae3831a69bf Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 27 May 2019 15:35:48 +0200 Subject: [PATCH 0768/3747] fix more indentation --- miri | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/miri b/miri index effbd023f1989..a5f7271b246e3 100755 --- a/miri +++ b/miri @@ -37,7 +37,7 @@ find_sysroot() { true fi else - # We have to build a sysroot either way. + # A normal toolchain. We have to build a sysroot either way. if [ -n "$MIRI_TEST_TARGET" ]; then build_sysroot --target "$MIRI_TEST_TARGET" else From 8b219a132902262db3285ed0cd57cb3bce8259a4 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 27 May 2019 18:50:32 +0200 Subject: [PATCH 0769/3747] fix for latest rustc --- rust-version | 2 +- src/operator.rs | 10 +++++----- src/stacked_borrows.rs | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/rust-version b/rust-version index 3c8fa005c32de..41821bcd73b78 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -d35181ad8785fa958e43580a29a982afe02c728f +1a56ec4dae92538ab6e0ecf993c61f3b50ed77cf diff --git a/src/operator.rs b/src/operator.rs index 386fc4307b87f..528da92c20f0f 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -158,8 +158,8 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' // Dead allocations in miri cannot overlap with live allocations, but // on read hardware this can easily happen. Thus for comparisons we require // both pointers to be live. - self.memory().check_bounds_ptr(left, InboundsCheck::Live)?; - self.memory().check_bounds_ptr(right, InboundsCheck::Live)?; + self.memory().check_bounds_ptr(left, InboundsCheck::Live, CheckInAllocMsg::InboundsTest)?; + self.memory().check_bounds_ptr(right, InboundsCheck::Live, CheckInAllocMsg::InboundsTest)?; // Two in-bounds pointers, we can compare across allocations. left == right } @@ -183,7 +183,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' if bits < 32 { // Test if the ptr is in-bounds. Then it cannot be NULL. // Even dangling pointers cannot be NULL. - if self.memory().check_bounds_ptr(ptr, InboundsCheck::MaybeDead).is_ok() { + if self.memory().check_bounds_ptr(ptr, InboundsCheck::MaybeDead, CheckInAllocMsg::NullPointerTest).is_ok() { return Ok(false); } } @@ -340,9 +340,9 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' if let Scalar::Ptr(ptr) = ptr { // Both old and new pointer must be in-bounds of a *live* allocation. // (Of the same allocation, but that part is trivial with our representation.) - self.memory().check_bounds_ptr(ptr, InboundsCheck::Live)?; + self.memory().check_bounds_ptr(ptr, InboundsCheck::Live, CheckInAllocMsg::InboundsTest)?; let ptr = ptr.signed_offset(offset, self)?; - self.memory().check_bounds_ptr(ptr, InboundsCheck::Live)?; + self.memory().check_bounds_ptr(ptr, InboundsCheck::Live, CheckInAllocMsg::InboundsTest)?; Ok(Scalar::Ptr(ptr)) } else { // An integer pointer. They can only be offset by 0, and we pretend there diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index f997e6316435a..8c46f7e1b2e90 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -10,7 +10,7 @@ use rustc::mir::RetagKind; use crate::{ EvalResult, InterpError, MiriEvalContext, HelpersEvalContextExt, Evaluator, MutValueVisitor, - MemoryKind, MiriMemoryKind, RangeMap, Allocation, AllocationExtra, + MemoryKind, MiriMemoryKind, RangeMap, Allocation, AllocationExtra, CheckInAllocMsg, Pointer, Immediate, ImmTy, PlaceTy, MPlaceTy, }; @@ -550,7 +550,7 @@ trait EvalContextPrivExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, // Get the allocation. It might not be mutable, so we cannot use `get_mut`. let alloc = this.memory().get(ptr.alloc_id)?; - alloc.check_bounds(this, ptr, size)?; + alloc.check_bounds(this, ptr, size, CheckInAllocMsg::InboundsTest)?; // Update the stacks. // Make sure that raw pointers and mutable shared references are reborrowed "weak": // There could be existing unique pointers reborrowed from them that should remain valid! From f10ab1991cc550dc0c5b5f636db535a0e4d1e21f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 27 May 2019 19:37:31 +0200 Subject: [PATCH 0770/3747] fix error pattern --- tests/compile-fail/out_of_bounds_ptr_1.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/compile-fail/out_of_bounds_ptr_1.rs b/tests/compile-fail/out_of_bounds_ptr_1.rs index ce1c89a2a0081..b466093053689 100644 --- a/tests/compile-fail/out_of_bounds_ptr_1.rs +++ b/tests/compile-fail/out_of_bounds_ptr_1.rs @@ -1,4 +1,4 @@ -// error-pattern: must be in-bounds and live at offset 5, but is outside bounds of allocation +// error-pattern: must be in-bounds at offset 5, but is outside bounds of allocation fn main() { let v = [0i8; 4]; let x = &v as *const i8; From ed0c6e833604364c8c7d454bdb66ed6a9c620ee6 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 28 May 2019 19:01:43 +0200 Subject: [PATCH 0771/3747] miri build script: support building miri in debug mode --- miri | 75 +++++++++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 64 insertions(+), 11 deletions(-) diff --git a/miri b/miri index a5f7271b246e3..f12a49afe4740 100755 --- a/miri +++ b/miri @@ -1,4 +1,36 @@ #!/bin/sh +## Usage +# +# COMMANDS +# +# ./miri install : +# Installs the miri driver and cargo-miri. are passed to `cargo +# install`. Sets up the rpath such that the installed binary should work in any +# working directory. +# +# ./miri build : +# Just build miri. are passed to `cargo build`. +# +# ./miri test : +# Build miri, set up a sysroot and then run the test suite. are passed +# to the final `cargo test` invocation. +# +# ./miri run : +# Build miri, set up a sysroot and then run the driver with the given . +# +# All commands also exist in a "-debug" variant (e.g. "./miri run-debug +# ") which uses debug builds instead of release builds, for faster build +# times and slower execution times. +# +# ENVIRONMENT VARIABLES +# +# MIRI_SYSROOT: +# If already set, the "sysroot setup" step is skipped. +# +# CARGO_EXTRA_FLAGS: +# Pass extra flags to all cargo invocations. + +## Preparation set -e # I'd love to use `jq` for parsing the JSON properly, but macOS is totally underequipped for this kind of work. TARGET=$(rustc --print target-spec-json -Z unstable-options | grep llvm-target | cut -d '"' -f 4) @@ -13,9 +45,9 @@ export RUSTFLAGS="-C link-args=-Wl,-rpath,$SYSROOT/lib/rustlib/$TARGET/lib -C de # Build a sysroot and set MIRI_SYSROOT to use it. Arguments are passed to `cargo miri setup`. build_sysroot() { # Build once, for the user to see. - cargo run --release --bin cargo-miri -- miri setup "$@" + cargo run $CARGO_BUILD_FLAGS --bin cargo-miri -- miri setup "$@" # Call again, to just set env var. - eval $(cargo run --release -q --bin cargo-miri -- miri setup --env "$@") + eval $(cargo run $CARGO_BUILD_FLAGS -q --bin cargo-miri -- miri setup --env "$@") export MIRI_SYSROOT } @@ -48,23 +80,44 @@ find_sysroot() { ## Main +# Determine command. COMMAND="$1" shift +# Determine flags passed to all cargo invocations. case "$COMMAND" in -install) +*-debug) + CARGO_INSTALL_FLAGS="--debug $CARGO_EXTRA_FLAGS" + CARGO_BUILD_FLAGS="$CARGO_EXTRA_FLAGS" + ;; +*) + CARGO_INSTALL_FLAGS="$CARGO_EXTRA_FLAGS" + CARGO_BUILD_FLAGS="--release $CARGO_EXTRA_FLAGS" + ;; +esac + +# Run command. +case "$COMMAND" in +install|install-debug) # "--locked" to respect the Cargo.lock file if it exists, # "--offline" to avoid querying the registry (for yanked packages). - exec cargo "$COMMAND" --path "$(dirname "$0")" --force --locked --offline "$@" + exec cargo install --path "$(dirname "$0")" --force --locked --offline "$@" ;; -build) +build|build-debug) # Build, and let caller control flags. - exec cargo "$COMMAND" --release "$@" + exec cargo build $CARGO_BUILD_FLAGS "$@" + ;; +test|test-debug) + # First build and get a sysroot. + cargo build $CARGO_BUILD_FLAGS + find_sysroot + # Then test, and let caller control flags. + exec cargo test $CARGO_BUILD_FLAGS "$@" ;; -test|run) - # In "run" mode, scan for "--target" to set the "MIRI_TEST_TARGET" env var so +run|run-debug) + # Scan for "--target" to set the "MIRI_TEST_TARGET" env var so # that we set the MIRI_SYSROOT up the right way. - if [ "$COMMAND" = "run" ] && [ -z "$MIRI_TEST_TARGET" ]; then + if [ -z "$MIRI_TEST_TARGET" ]; then for ARG in "$@"; do if [ "$LAST_ARG" = "--target" ]; then # Found it! @@ -75,9 +128,9 @@ test|run) done fi # First build and get a sysroot. - cargo build --release + cargo build $CARGO_BUILD_FLAGS find_sysroot # Then run the actual command. - exec cargo "$COMMAND" --release "$@" + exec cargo run $CARGO_BUILD_FLAGS "$@" ;; esac From 328ecd1abf4ca75499d2ed6b450c4ebf1535a6da Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 28 May 2019 19:02:54 +0200 Subject: [PATCH 0772/3747] avoid rebuilding Miri on CI --- travis.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/travis.sh b/travis.sh index 4df12613fb831..c06dbaee3638a 100755 --- a/travis.sh +++ b/travis.sh @@ -7,10 +7,11 @@ if [ "$TRAVIS_OS_NAME" == osx ]; then else FOREIGN_TARGET=i686-unknown-linux-gnu fi +export CARGO_EXTRA_FLAGS="--all-features" # Prepare echo "Build and install miri" -./miri build --all-features --all-targets +./miri build --all-targets ./miri install echo From d55d04780cbf966537c3f1d6e33b133a5319eeb8 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 28 May 2019 19:04:31 +0200 Subject: [PATCH 0773/3747] reference cargo issue --- miri | 2 ++ 1 file changed, 2 insertions(+) diff --git a/miri b/miri index f12a49afe4740..99b64b62028a2 100755 --- a/miri +++ b/miri @@ -85,6 +85,8 @@ COMMAND="$1" shift # Determine flags passed to all cargo invocations. +# This is a bit more annoying that one would hope due to +# . case "$COMMAND" in *-debug) CARGO_INSTALL_FLAGS="--debug $CARGO_EXTRA_FLAGS" From bf9f26401f8a41880203918ffbbfcac4ae5f16ac Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 28 May 2019 19:20:01 +0200 Subject: [PATCH 0774/3747] also pass flags to install --- miri | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/miri b/miri index 99b64b62028a2..64466951e9824 100755 --- a/miri +++ b/miri @@ -103,7 +103,7 @@ case "$COMMAND" in install|install-debug) # "--locked" to respect the Cargo.lock file if it exists, # "--offline" to avoid querying the registry (for yanked packages). - exec cargo install --path "$(dirname "$0")" --force --locked --offline "$@" + exec cargo install $CARGO_INSTALL_FLAGS --path "$(dirname "$0")" --force --locked --offline "$@" ;; build|build-debug) # Build, and let caller control flags. From 7a7b853120f84c90702802b96cfdb243a08d4cc0 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 26 May 2019 14:43:34 +0200 Subject: [PATCH 0775/3747] adjust for rustc changes --- src/fn_call.rs | 5 +++-- src/operator.rs | 22 ++++++++++------------ 2 files changed, 13 insertions(+), 14 deletions(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index 3ff0c1eb18a0d..dc43c65240962 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -607,11 +607,12 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' // Extract the function type out of the signature (that seems easier than constructing it ourselves). let dtor = match this.read_scalar(args[1])?.not_undef()? { Scalar::Ptr(dtor_ptr) => Some(this.memory().get_fn(dtor_ptr)?), - Scalar::Bits { bits: 0, size } => { + Scalar::Raw { data: 0, size } => { + // NULL pointer assert_eq!(size as u64, this.memory().pointer_size().bytes()); None }, - Scalar::Bits { .. } => return err!(ReadBytesAsPointer), + Scalar::Raw { .. } => return err!(ReadBytesAsPointer), }; // Figure out how large a pthread TLS key actually is. diff --git a/src/operator.rs b/src/operator.rs index 528da92c20f0f..28d0d7c960959 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -141,7 +141,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' ) -> EvalResult<'tcx, bool> { let size = self.pointer_size(); Ok(match (left, right) { - (Scalar::Bits { .. }, Scalar::Bits { .. }) => + (Scalar::Raw { .. }, Scalar::Raw { .. }) => left.to_bits(size)? == right.to_bits(size)?, (Scalar::Ptr(left), Scalar::Ptr(right)) => { // Comparison illegal if one of them is out-of-bounds, *unless* they @@ -165,10 +165,10 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' } } // Comparing ptr and integer. - (Scalar::Ptr(ptr), Scalar::Bits { bits, size }) | - (Scalar::Bits { bits, size }, Scalar::Ptr(ptr)) => { + (Scalar::Ptr(ptr), Scalar::Raw { data, size }) | + (Scalar::Raw { data, size }, Scalar::Ptr(ptr)) => { assert_eq!(size as u64, self.pointer_size().bytes()); - let bits = bits as u64; + let bits = data as u64; // Case I: Comparing real pointers with "small" integers. // Really we should only do this for NULL, but pragmatically speaking on non-bare-metal systems, @@ -262,7 +262,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' // Truncate (shift left to drop out leftover values, shift right to fill with zeroes). (value << shift) >> shift }; - let ptr_size = self.memory().pointer_size().bytes() as u8; + let ptr_size = self.memory().pointer_size(); trace!("ptr BitAnd, align {}, operand {:#010x}, base_mask {:#010x}", ptr_base_align, right, base_mask); if right & base_mask == base_mask { @@ -278,7 +278,8 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' ) } 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() as u128) & right, size: ptr_size }, false) + let v = Scalar::from_uint((left.offset.bytes() as u128) & right, ptr_size); + (v, false) } else { return err!(ReadPointerAsBytes); } @@ -289,18 +290,15 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' // (Intuition: modulo a divisor leaks less information.) let ptr_base_align = self.memory().get(left.alloc_id)?.align.bytes(); let right = right as u64; - let ptr_size = self.memory().pointer_size().bytes() as u8; + let ptr_size = self.memory().pointer_size(); if right == 1 { // Modulo 1 is always 0. - (Scalar::Bits { bits: 0, size: ptr_size }, false) + (Scalar::from_uint(0u32, ptr_size), false) } else if ptr_base_align % right == 0 { // The base address would be cancelled out by the modulo operation, so we can // just take the modulo of the offset. ( - Scalar::Bits { - bits: (left.offset.bytes() % right) as u128, - size: ptr_size - }, + Scalar::from_uint((left.offset.bytes() % right) as u128, ptr_size), false, ) } else { From 381c2897b065472d0a0fe7ee9f200e38fc2ca3ec Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 26 May 2019 14:47:37 +0200 Subject: [PATCH 0776/3747] test for pointer wrapping ICE --- tests/run-pass/ptr_arith_offset_overflow.rs | 13 ++++++++----- tests/run-pass/ptr_int_casts.rs | 7 +++++++ 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/tests/run-pass/ptr_arith_offset_overflow.rs b/tests/run-pass/ptr_arith_offset_overflow.rs index 6b778248be5c6..56fd448b0cc22 100644 --- a/tests/run-pass/ptr_arith_offset_overflow.rs +++ b/tests/run-pass/ptr_arith_offset_overflow.rs @@ -1,9 +1,12 @@ +use std::ptr; + fn main() { let v = [1i16, 2]; - let x = v.as_ptr().wrapping_offset(1); // ptr to the 2nd element + let x = &mut ptr::null(); // going through memory as there are more sanity checks along that path + *x = v.as_ptr().wrapping_offset(1); // ptr to the 2nd element // Adding 2*isize::max and then 1 is like substracting 1 - let x = x.wrapping_offset(isize::max_value()); - let x = x.wrapping_offset(isize::max_value()); - let x = x.wrapping_offset(1); - assert_eq!(unsafe { *x }, 1); + *x = x.wrapping_offset(isize::max_value()); + *x = x.wrapping_offset(isize::max_value()); + *x = x.wrapping_offset(1); + assert_eq!(unsafe { **x }, 1); } diff --git a/tests/run-pass/ptr_int_casts.rs b/tests/run-pass/ptr_int_casts.rs index b1b06263056d7..c279024f35eab 100644 --- a/tests/run-pass/ptr_int_casts.rs +++ b/tests/run-pass/ptr_int_casts.rs @@ -1,4 +1,5 @@ use std::mem; +use std::ptr; fn eq_ref(x: &T, y: &T) -> bool { x as *const _ == y as *const _ @@ -11,6 +12,12 @@ fn main() { assert_eq!(1 as *const i32 as usize, 1); assert_eq!((1 as *const i32).wrapping_offset(4) as usize, 1 + 4*4); + // negative overflowing wrapping_offset (going through memory because + // this used to trigger an ICE on 32bit) + let val = &mut ptr::null(); + *val = (1 as *const u8).wrapping_offset(-4); + assert_eq!(*val as usize, usize::max_value() - 2); + { // ptr-int-ptr let x = 13; let mut y = &x as &_ as *const _ as usize; From b62ddc2cff25d9ca29ee5dd5776b89413ee580eb Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 28 May 2019 22:47:22 +0200 Subject: [PATCH 0777/3747] bump Rust --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 41821bcd73b78..0af97e2a284c6 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -1a56ec4dae92538ab6e0ecf993c61f3b50ed77cf +721268583759224d0f6476e0b8b196cc8afbdea0 From e4cee77121d8ad3c547a67b6c8cff88e38183ec1 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 29 May 2019 09:30:36 +0200 Subject: [PATCH 0778/3747] fix for rustc changes --- rust-version | 2 +- src/fn_call.rs | 2 +- src/lib.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/rust-version b/rust-version index 0af97e2a284c6..7695b069436f2 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -721268583759224d0f6476e0b8b196cc8afbdea0 +4b9d80325a65b0375eea526409a0f3aaf1cbc23c diff --git a/src/fn_call.rs b/src/fn_call.rs index dc43c65240962..17679e26790cb 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -17,7 +17,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' args: &[OpTy<'tcx, Tag>], dest: Option>, ret: Option, - ) -> EvalResult<'tcx, Option<&'mir mir::Mir<'tcx>>> { + ) -> EvalResult<'tcx, Option<&'mir mir::Body<'tcx>>> { let this = self.eval_context_mut(); trace!("eval_fn_call: {:#?}, {:?}", instance, dest.map(|place| *place)); diff --git a/src/lib.rs b/src/lib.rs index a12493fbfbd62..89d7964913ae9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -407,7 +407,7 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { args: &[OpTy<'tcx, Tag>], dest: Option>, ret: Option, - ) -> EvalResult<'tcx, Option<&'mir mir::Mir<'tcx>>> { + ) -> EvalResult<'tcx, Option<&'mir mir::Body<'tcx>>> { ecx.find_fn(instance, args, dest, ret) } From 35b4d9fd8ac260bdfee5204ec2590420ca0782b2 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 29 May 2019 09:36:59 +0200 Subject: [PATCH 0779/3747] print usage information on invalid command --- miri | 68 +++++++++++++++++++++++++++++++++--------------------------- 1 file changed, 37 insertions(+), 31 deletions(-) diff --git a/miri b/miri index 64466951e9824..d683a08530083 100755 --- a/miri +++ b/miri @@ -1,37 +1,38 @@ #!/bin/sh -## Usage -# -# COMMANDS -# -# ./miri install : -# Installs the miri driver and cargo-miri. are passed to `cargo -# install`. Sets up the rpath such that the installed binary should work in any -# working directory. -# -# ./miri build : -# Just build miri. are passed to `cargo build`. -# -# ./miri test : -# Build miri, set up a sysroot and then run the test suite. are passed -# to the final `cargo test` invocation. -# -# ./miri run : -# Build miri, set up a sysroot and then run the driver with the given . -# -# All commands also exist in a "-debug" variant (e.g. "./miri run-debug -# ") which uses debug builds instead of release builds, for faster build -# times and slower execution times. -# -# ENVIRONMENT VARIABLES -# -# MIRI_SYSROOT: -# If already set, the "sysroot setup" step is skipped. -# -# CARGO_EXTRA_FLAGS: -# Pass extra flags to all cargo invocations. +set -e +USAGE=$(cat <<"EOF" + COMMANDS + +./miri install : +Installs the miri driver and cargo-miri. are passed to `cargo +install`. Sets up the rpath such that the installed binary should work in any +working directory. + +./miri build : +Just build miri. are passed to `cargo build`. + +./miri test : +Build miri, set up a sysroot and then run the test suite. are passed +to the final `cargo test` invocation. + +./miri run : +Build miri, set up a sysroot and then run the driver with the given . + +All commands also exist in a "-debug" variant (e.g. "./miri run-debug +") which uses debug builds instead of release builds, for faster build +times and slower execution times. + + ENVIRONMENT VARIABLES + +MIRI_SYSROOT: +If already set, the "sysroot setup" step is skipped. + +CARGO_EXTRA_FLAGS: +Pass extra flags to all cargo invocations. +EOF +) ## Preparation -set -e # I'd love to use `jq` for parsing the JSON properly, but macOS is totally underequipped for this kind of work. TARGET=$(rustc --print target-spec-json -Z unstable-options | grep llvm-target | cut -d '"' -f 4) SYSROOT=$(rustc --print sysroot) @@ -135,4 +136,9 @@ run|run-debug) # Then run the actual command. exec cargo run $CARGO_BUILD_FLAGS "$@" ;; +*) + echo "Unknown command: $COMMAND" + echo + echo "$USAGE" + exit 1 esac From 16cc5ddacbde23a71d05535f6b51298d295535df Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 29 May 2019 09:39:49 +0200 Subject: [PATCH 0780/3747] tweak logic for determining rustc default target --- miri | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/miri b/miri index d683a08530083..2181403b7bde9 100755 --- a/miri +++ b/miri @@ -33,13 +33,19 @@ EOF ) ## Preparation -# I'd love to use `jq` for parsing the JSON properly, but macOS is totally underequipped for this kind of work. -TARGET=$(rustc --print target-spec-json -Z unstable-options | grep llvm-target | cut -d '"' -f 4) +TARGET=$(rustc --version --verbose | grep "^host:" | cut -d ' ' -f 2) SYSROOT=$(rustc --print sysroot) +LIBDIR=$SYSROOT/lib/rustlib/$TARGET/lib +if ! test -d "$LIBDIR"; then + echo "Something went wrong determining the library dir." + echo "I got $LIBDIR but that does not exist." + echo "Please report a bug at https://github.com/rust-lang/miri/issues." + exit 2 +fi # We set the rpath so that Miri finds the private rustc libraries it needs. # We enable debug-assertions to get tracing. # We enable line-only debuginfo for backtraces. -export RUSTFLAGS="-C link-args=-Wl,-rpath,$SYSROOT/lib/rustlib/$TARGET/lib -C debug-assertions -C debuginfo=1" +export RUSTFLAGS="-C link-args=-Wl,-rpath,$LIBDIR -C debug-assertions -C debuginfo=1" ## Helper functions From 65a93eb3ee0ad5ded12666370029dbaca7c5e1ad Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 29 May 2019 12:54:19 +0200 Subject: [PATCH 0781/3747] try to make the Windows CI not rebuild Miri --- .appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.appveyor.yml b/.appveyor.yml index 438a65880b870..d13ce2b3974de 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -33,7 +33,7 @@ build_script: - set RUSTFLAGS=-C debug-assertions # Build and install miri - cargo build --release --all-features --all-targets - - cargo install --all-features --force --path . + - cargo install --all-features --force --path . --locked --offline # Get ourselves a MIR-full libstd, and use it henceforth - cargo miri setup - set MIRI_SYSROOT=%USERPROFILE%\AppData\Local\miri\miri\cache\HOST From 0dfc1c97c59361be750b0e15a181cd4d06712dd8 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 29 May 2019 19:35:47 +0200 Subject: [PATCH 0782/3747] test weak_into_raw --- rust-version | 2 +- tests/compile-fail/rc_as_raw.rs | 19 +++++++++++++++++ tests/run-pass/rc.rs | 38 ++++++++++++++++++++++++++++++++- 3 files changed, 57 insertions(+), 2 deletions(-) create mode 100644 tests/compile-fail/rc_as_raw.rs diff --git a/rust-version b/rust-version index 7695b069436f2..d93fb8b6950eb 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -4b9d80325a65b0375eea526409a0f3aaf1cbc23c +81970852e172c04322cbf8ba23effabeb491c83c diff --git a/tests/compile-fail/rc_as_raw.rs b/tests/compile-fail/rc_as_raw.rs new file mode 100644 index 0000000000000..3e6e96456fca6 --- /dev/null +++ b/tests/compile-fail/rc_as_raw.rs @@ -0,0 +1,19 @@ +#![feature(weak_into_raw)] + +use std::rc::{Rc, Weak}; +use std::ptr; + +/// Taken from the `Weak::as_raw` doctest. +fn main() { + let strong = Rc::new(Box::new(42)); + let weak = Rc::downgrade(&strong); + // Both point to the same object + assert!(ptr::eq(&*strong, Weak::as_raw(&weak))); + // The strong here keeps it alive, so we can still access the object. + assert_eq!(42, **unsafe { &*Weak::as_raw(&weak) }); + + drop(strong); + // But not any more. We can do Weak::as_raw(&weak), but accessing the pointer would lead to + // undefined behaviour. + assert_eq!(42, **unsafe { &*Weak::as_raw(&weak) }); //~ ERROR dangling pointer +} diff --git a/tests/run-pass/rc.rs b/tests/run-pass/rc.rs index 164842ab4d976..9b4d51ed376a6 100644 --- a/tests/run-pass/rc.rs +++ b/tests/run-pass/rc.rs @@ -1,5 +1,7 @@ +#![feature(weak_into_raw)] + use std::cell::{Cell, RefCell}; -use std::rc::Rc; +use std::rc::{Rc, Weak}; use std::sync::Arc; use std::fmt::Debug; @@ -69,6 +71,37 @@ fn rc_fat_ptr_eq() { drop(unsafe { Rc::from_raw(r) }); } +/// Taken from the `Weak::into_raw` doctest. +fn weak_into_raw() { + let strong = Rc::new(42); + let weak = Rc::downgrade(&strong); + let raw = Weak::into_raw(weak); + + assert_eq!(1, Rc::weak_count(&strong)); + assert_eq!(42, unsafe { *raw }); + + drop(unsafe { Weak::from_raw(raw) }); + assert_eq!(0, Rc::weak_count(&strong)); +} + +/// Taken from the `Weak::from_raw` doctest. +fn weak_from_raw() { + let strong = Rc::new(42); + + let raw_1 = Weak::into_raw(Rc::downgrade(&strong)); + let raw_2 = Weak::into_raw(Rc::downgrade(&strong)); + + assert_eq!(2, Rc::weak_count(&strong)); + + assert_eq!(42, *Weak::upgrade(&unsafe { Weak::from_raw(raw_1) }).unwrap()); + assert_eq!(1, Rc::weak_count(&strong)); + + drop(strong); + + // Decrement the last weak count. + assert!(Weak::upgrade(&unsafe { Weak::from_raw(raw_2) }).is_none()); +} + fn main() { rc_fat_ptr_eq(); rc_refcell(); @@ -76,5 +109,8 @@ fn main() { rc_cell(); rc_raw(); rc_from(); + weak_into_raw(); + weak_from_raw(); + arc(); } From badbd57cee570f25ebf6b31ea4d596a162a87188 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 30 May 2019 10:58:30 +0200 Subject: [PATCH 0783/3747] update for rustc warning about missing dyn --- rust-version | 2 +- tests/run-pass/box_box_trait.rs | 6 +++--- tests/run-pass/call_drop_on_fat_ptr_array_elements.rs | 2 +- tests/run-pass/call_drop_through_trait_object.rs | 2 +- tests/run-pass/call_drop_through_trait_object_rc.rs | 2 +- tests/run-pass/cast-rfc0401-vtable-kinds.rs | 10 +++++----- tests/run-pass/dst-field-align.rs | 8 ++++---- tests/run-pass/dst-raw.rs | 8 ++++---- tests/run-pass/fn_item_as_closure_trait_object.rs | 2 +- .../fn_item_with_args_as_closure_trait_object.rs | 2 +- ..._item_with_multiple_args_as_closure_trait_object.rs | 4 ++-- tests/run-pass/fn_ptr_as_closure_trait_object.rs | 6 +++--- tests/run-pass/issue-20575.rs | 2 +- tests/run-pass/issue-23261.rs | 4 ++-- tests/run-pass/issue-26709.rs | 2 +- tests/run-pass/issue-30530.rs | 4 ++-- tests/run-pass/issue-33387.rs | 2 +- tests/run-pass/issue-35815.rs | 2 +- tests/run-pass/issue-3794.rs | 4 ++-- tests/run-pass/last-use-in-cap-clause.rs | 2 +- tests/run-pass/mir_coercions.rs | 10 +++++----- tests/run-pass/multi_arg_closure.rs | 2 +- tests/run-pass/non_capture_closure_to_fn_ptr.rs | 2 +- tests/run-pass/rc.rs | 4 ++-- tests/run-pass/regions-lifetime-nonfree-late-bound.rs | 8 ++++---- tests/run-pass/traits.rs | 8 ++++---- 26 files changed, 55 insertions(+), 55 deletions(-) diff --git a/rust-version b/rust-version index d93fb8b6950eb..5504e77097b73 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -81970852e172c04322cbf8ba23effabeb491c83c +c28084ac16af4ab594b6860958df140e7c876a13 diff --git a/tests/run-pass/box_box_trait.rs b/tests/run-pass/box_box_trait.rs index 7fe568522d53e..e7620cd42f700 100644 --- a/tests/run-pass/box_box_trait.rs +++ b/tests/run-pass/box_box_trait.rs @@ -14,10 +14,10 @@ trait MyTrait { fn dummy(&self) { } } impl MyTrait for Box {} #[allow(dead_code)] -struct Whatever { w: Box } +struct Whatever { w: Box } impl Whatever { - fn new(w: Box) -> Whatever { + fn new(w: Box) -> Whatever { Whatever { w: w } } } @@ -25,7 +25,7 @@ impl Whatever { fn main() { { let f: Box<_> = box DroppableStruct; - let _a = Whatever::new(box f as Box); + let _a = Whatever::new(box f as Box); } assert!(unsafe { DROPPED }); } diff --git a/tests/run-pass/call_drop_on_fat_ptr_array_elements.rs b/tests/run-pass/call_drop_on_fat_ptr_array_elements.rs index a1ab5c45e358c..36162d320212a 100644 --- a/tests/run-pass/call_drop_on_fat_ptr_array_elements.rs +++ b/tests/run-pass/call_drop_on_fat_ptr_array_elements.rs @@ -13,7 +13,7 @@ impl Drop for Bar { } fn main() { - let b: [Box; 4] = [Box::new(Bar), Box::new(Bar), Box::new(Bar), Box::new(Bar)]; + let b: [Box; 4] = [Box::new(Bar), Box::new(Bar), Box::new(Bar), Box::new(Bar)]; assert_eq!(unsafe { DROP_COUNT }, 0); drop(b); assert_eq!(unsafe { DROP_COUNT }, 4); diff --git a/tests/run-pass/call_drop_through_trait_object.rs b/tests/run-pass/call_drop_through_trait_object.rs index 9b6acf0b14746..97ba69c9fe288 100644 --- a/tests/run-pass/call_drop_through_trait_object.rs +++ b/tests/run-pass/call_drop_through_trait_object.rs @@ -13,7 +13,7 @@ impl Drop for Bar { impl Foo for Bar {} fn main() { - let b: Box = Box::new(Bar); + let b: Box = Box::new(Bar); assert!(unsafe { !DROP_CALLED }); drop(b); assert!(unsafe { DROP_CALLED }); diff --git a/tests/run-pass/call_drop_through_trait_object_rc.rs b/tests/run-pass/call_drop_through_trait_object_rc.rs index ce56ca6a1cafd..172a4580dc105 100644 --- a/tests/run-pass/call_drop_through_trait_object_rc.rs +++ b/tests/run-pass/call_drop_through_trait_object_rc.rs @@ -15,7 +15,7 @@ impl Foo for Bar {} use std::rc::Rc; fn main() { - let b: Rc = Rc::new(Bar); + let b: Rc = Rc::new(Bar); assert!(unsafe { !DROP_CALLED }); drop(b); assert!(unsafe { DROP_CALLED }); diff --git a/tests/run-pass/cast-rfc0401-vtable-kinds.rs b/tests/run-pass/cast-rfc0401-vtable-kinds.rs index 6442eab30a132..544510be9bb09 100644 --- a/tests/run-pass/cast-rfc0401-vtable-kinds.rs +++ b/tests/run-pass/cast-rfc0401-vtable-kinds.rs @@ -13,9 +13,9 @@ impl Foo for () {} impl Foo for u32 { fn foo(&self, _: u32) -> u32 { self+43 } } impl Bar for () {} -unsafe fn round_trip_and_call<'a>(t: *const (Foo+'a)) -> u32 { - let foo_e : *const Foo = t as *const _; - let r_1 = foo_e as *mut Foo; +unsafe fn round_trip_and_call<'a>(t: *const (dyn Foo+'a)) -> u32 { + let foo_e : *const dyn Foo = t as *const _; + let r_1 = foo_e as *mut dyn Foo; (&*r_1).foo(0) } @@ -31,8 +31,8 @@ fn foo_to_bar(u: *const FooS) -> *const BarS { fn main() { let x = 4u32; - let y : &Foo = &x; - let fl = unsafe { round_trip_and_call(y as *const Foo) }; + let y : &dyn Foo = &x; + let fl = unsafe { round_trip_and_call(y as *const dyn Foo) }; assert_eq!(fl, (43+4)); let s = FooS([0,1,2]); diff --git a/tests/run-pass/dst-field-align.rs b/tests/run-pass/dst-field-align.rs index b8e9815640c28..7cd0c851b6387 100644 --- a/tests/run-pass/dst-field-align.rs +++ b/tests/run-pass/dst-field-align.rs @@ -26,7 +26,7 @@ fn main() { // Test that zero-offset works properly let b : Baz = Baz { a: 7 }; assert_eq!(b.a.get(), 7); - let b : &Baz = &b; + let b : &Baz = &b; assert_eq!(b.a.get(), 7); // Test that the field is aligned properly @@ -34,7 +34,7 @@ fn main() { assert_eq!(f.b.get(), 11); let ptr1 : *const u8 = &f.b as *const _ as *const u8; - let f : &Foo = &f; + let f : &Foo = &f; let ptr2 : *const u8 = &f.b as *const _ as *const u8; assert_eq!(f.b.get(), 11); @@ -44,13 +44,13 @@ fn main() { // Test that nested DSTs work properly let f : Foo> = Foo { a: 0, b: Foo { a: 1, b: 17 }}; assert_eq!(f.b.b.get(), 17); - let f : &Foo> = &f; + let f : &Foo> = &f; assert_eq!(f.b.b.get(), 17); // Test that get the pointer via destructuring works let f : Foo = Foo { a: 0, b: 11 }; - let f : &Foo = &f; + let f : &Foo = &f; let &Foo { a: _, b: ref bar } = f; assert_eq!(bar.get(), 11); diff --git a/tests/run-pass/dst-raw.rs b/tests/run-pass/dst-raw.rs index a3ee982d19aa6..0fe2b72b8c6ab 100644 --- a/tests/run-pass/dst-raw.rs +++ b/tests/run-pass/dst-raw.rs @@ -21,7 +21,7 @@ struct Foo { pub fn main() { // raw trait object let x = A { f: 42 }; - let z: *const Trait = &x; + let z: *const dyn Trait = &x; let r = unsafe { (&*z).foo() }; @@ -29,7 +29,7 @@ pub fn main() { // raw DST struct let p = Foo {f: A { f: 42 }}; - let o: *const Foo = &p; + let o: *const Foo = &p; let r = unsafe { (&*o).f.foo() }; @@ -64,14 +64,14 @@ pub fn main() { // all of the above with *mut let mut x = A { f: 42 }; - let z: *mut Trait = &mut x; + let z: *mut dyn Trait = &mut x; let r = unsafe { (&*z).foo() }; assert_eq!(r, 42); let mut p = Foo {f: A { f: 42 }}; - let o: *mut Foo = &mut p; + let o: *mut Foo = &mut p; let r = unsafe { (&*o).f.foo() }; diff --git a/tests/run-pass/fn_item_as_closure_trait_object.rs b/tests/run-pass/fn_item_as_closure_trait_object.rs index 799f97a4f6fde..dcbbb5cb6a2ce 100644 --- a/tests/run-pass/fn_item_as_closure_trait_object.rs +++ b/tests/run-pass/fn_item_as_closure_trait_object.rs @@ -1,6 +1,6 @@ fn foo() {} fn main() { - let f: &Fn() = &foo; + let f: &dyn Fn() = &foo; f(); } diff --git a/tests/run-pass/fn_item_with_args_as_closure_trait_object.rs b/tests/run-pass/fn_item_with_args_as_closure_trait_object.rs index 79ece75c773bb..257028c4f0d8e 100644 --- a/tests/run-pass/fn_item_with_args_as_closure_trait_object.rs +++ b/tests/run-pass/fn_item_with_args_as_closure_trait_object.rs @@ -3,6 +3,6 @@ fn foo(i: i32) { } fn main() { - let f: &Fn(i32) = &foo; + let f: &dyn Fn(i32) = &foo; f(42); } diff --git a/tests/run-pass/fn_item_with_multiple_args_as_closure_trait_object.rs b/tests/run-pass/fn_item_with_multiple_args_as_closure_trait_object.rs index f4b5b449aa587..98111f304c893 100644 --- a/tests/run-pass/fn_item_with_multiple_args_as_closure_trait_object.rs +++ b/tests/run-pass/fn_item_with_multiple_args_as_closure_trait_object.rs @@ -11,8 +11,8 @@ fn bar(i: i32, j: i32, k: f32) { fn main() { - let f: &Fn(i32, i32) = &foo; + let f: &dyn Fn(i32, i32) = &foo; f(42, 55); - let f: &Fn(i32, i32, f32) = &bar; + let f: &dyn Fn(i32, i32, f32) = &bar; f(42, 55, 3.14159); } diff --git a/tests/run-pass/fn_ptr_as_closure_trait_object.rs b/tests/run-pass/fn_ptr_as_closure_trait_object.rs index 24ae1f35bb60b..89daed81507f1 100644 --- a/tests/run-pass/fn_ptr_as_closure_trait_object.rs +++ b/tests/run-pass/fn_ptr_as_closure_trait_object.rs @@ -6,10 +6,10 @@ fn baa(u: u32, f: f32) { } fn main() { - let f: &Fn() = &(foo as fn()); + let f: &dyn Fn() = &(foo as fn()); f(); - let f: &Fn(u32) = &(bar as fn(u32)); + let f: &dyn Fn(u32) = &(bar as fn(u32)); f(42); - let f: &Fn(u32, f32) = &(baa as fn(u32, f32)); + let f: &dyn Fn(u32, f32) = &(baa as fn(u32, f32)); f(42, 3.141); } diff --git a/tests/run-pass/issue-20575.rs b/tests/run-pass/issue-20575.rs index 1443ec78fd75e..19049b9add5c1 100644 --- a/tests/run-pass/issue-20575.rs +++ b/tests/run-pass/issue-20575.rs @@ -1,7 +1,7 @@ // Test that overloaded calls work with zero arity closures fn main() { - let functions: [Box Option<()>>; 1] = [Box::new(|| None)]; + let functions: [Box Option<()>>; 1] = [Box::new(|| None)]; let _val: Option> = functions.iter().map(|f| (*f)()).collect(); } diff --git a/tests/run-pass/issue-23261.rs b/tests/run-pass/issue-23261.rs index 3e1aa295af1ea..f3c2f58ddbca1 100644 --- a/tests/run-pass/issue-23261.rs +++ b/tests/run-pass/issue-23261.rs @@ -40,7 +40,7 @@ fn check_both(val: &Foo<[u8]>) { } } -fn check_trait_obj(val: &Foo) { +fn check_trait_obj(val: &Foo) { match *val { Foo { a, ref inner } => { assert_eq!(a, 32); @@ -55,6 +55,6 @@ fn main() { check_dst_val(foo); check_both(foo); - let foo: &Foo = &Foo { a: 32, inner: 32 }; + let foo: &Foo = &Foo { a: 32, inner: 32 }; check_trait_obj(foo); } diff --git a/tests/run-pass/issue-26709.rs b/tests/run-pass/issue-26709.rs index a283d8743ccff..78f30e78db766 100644 --- a/tests/run-pass/issue-26709.rs +++ b/tests/run-pass/issue-26709.rs @@ -10,7 +10,7 @@ fn main() { let mut x = 0; { let wrapper = Box::new(Wrapper(&mut x, 123)); - let _val: Box> = wrapper; + let _val: Box> = wrapper; } assert_eq!(432, x) } diff --git a/tests/run-pass/issue-30530.rs b/tests/run-pass/issue-30530.rs index d5139c908bdac..10dec30c64ca7 100644 --- a/tests/run-pass/issue-30530.rs +++ b/tests/run-pass/issue-30530.rs @@ -17,7 +17,7 @@ pub enum Handler { Default, #[allow(dead_code)] - Custom(*mut Box), + Custom(*mut Box), } fn main() { @@ -25,7 +25,7 @@ fn main() { } #[inline(never)] -pub fn take(h: Handler, f: Box) -> Box { +pub fn take(h: Handler, f: Box) -> Box { unsafe { match h { Handler::Custom(ptr) => *Box::from_raw(ptr), diff --git a/tests/run-pass/issue-33387.rs b/tests/run-pass/issue-33387.rs index 2335f9c1b9412..36b58c642d7d5 100644 --- a/tests/run-pass/issue-33387.rs +++ b/tests/run-pass/issue-33387.rs @@ -5,5 +5,5 @@ trait Foo {} impl Foo for [u8; 2] {} fn main() { - let _val: Arc = Arc::new([3, 4]); + let _val: Arc = Arc::new([3, 4]); } diff --git a/tests/run-pass/issue-35815.rs b/tests/run-pass/issue-35815.rs index e17c37f92a501..fb0bd8e202fff 100644 --- a/tests/run-pass/issue-35815.rs +++ b/tests/run-pass/issue-35815.rs @@ -10,6 +10,6 @@ struct Foo { fn main() { let foo: &Foo = &Foo { a: 1, b: false, c: 2i32 }; - let foo_unsized: &Foo = foo; + let foo_unsized: &Foo = foo; assert_eq!(mem::size_of_val(foo), mem::size_of_val(foo_unsized)); } diff --git a/tests/run-pass/issue-3794.rs b/tests/run-pass/issue-3794.rs index 9161fefef30cf..fb1c19b04e998 100644 --- a/tests/run-pass/issue-3794.rs +++ b/tests/run-pass/issue-3794.rs @@ -15,7 +15,7 @@ impl T for S { } } -fn print_t(t: &T) { +fn print_t(t: &dyn T) { t.print(); } @@ -26,6 +26,6 @@ fn print_s(s: &S) { pub fn main() { let s: Box = box S { s: 5 }; print_s(&*s); - let t: Box = s as Box; + let t: Box = s as Box; print_t(&*t); } diff --git a/tests/run-pass/last-use-in-cap-clause.rs b/tests/run-pass/last-use-in-cap-clause.rs index f75f00b87fd48..9d137f706bd33 100644 --- a/tests/run-pass/last-use-in-cap-clause.rs +++ b/tests/run-pass/last-use-in-cap-clause.rs @@ -3,7 +3,7 @@ #[allow(dead_code)] struct A { a: Box } -fn foo() -> Box isize + 'static> { +fn foo() -> Box isize + 'static> { let k: Box<_> = Box::new(22); let _u = A {a: k.clone()}; let result = || 22; diff --git a/tests/run-pass/mir_coercions.rs b/tests/run-pass/mir_coercions.rs index f3d8e519d23ed..bfc821f799ee4 100644 --- a/tests/run-pass/mir_coercions.rs +++ b/tests/run-pass/mir_coercions.rs @@ -3,12 +3,12 @@ use std::ops::CoerceUnsized; use std::marker::Unsize; -fn identity_coercion(x: &(Fn(u32)->u32 + Send)) -> &Fn(u32)->u32 { +fn identity_coercion(x: &(dyn Fn(u32)->u32 + Send)) -> &dyn Fn(u32)->u32 { x } fn fn_coercions(f: &fn(u32) -> u32) -> (unsafe fn(u32) -> u32, - &(Fn(u32) -> u32+Send)) + &(dyn Fn(u32) -> u32 + Send)) { (*f, f) } @@ -34,8 +34,8 @@ fn coerce_triv_ptr_wrapper(p: TrivPtrWrapper<[u8; 3]>) -> TrivPtrWrapper<[u8]> { p } -fn coerce_fat_ptr_wrapper(p: PtrWrapper u32+Send>) - -> PtrWrapper u32> { +fn coerce_fat_ptr_wrapper(p: PtrWrapper u32 + Send>) + -> PtrWrapper u32> { p } @@ -67,7 +67,7 @@ fn main() { let z = coerce_fat_ptr_wrapper(PtrWrapper(2,3,(),&square_local)); assert_eq!((z.3)(6), 36); - let z: PtrWrapper u32> = + let z: PtrWrapper u32> = coerce_ptr_wrapper_poly(PtrWrapper(2,3,(),&square_local)); assert_eq!((z.3)(6), 36); } diff --git a/tests/run-pass/multi_arg_closure.rs b/tests/run-pass/multi_arg_closure.rs index 30cfb5b685b20..02d53540b83c3 100644 --- a/tests/run-pass/multi_arg_closure.rs +++ b/tests/run-pass/multi_arg_closure.rs @@ -1,4 +1,4 @@ -fn foo(f: &mut FnMut(isize, isize) -> isize) -> isize { +fn foo(f: &mut dyn FnMut(isize, isize) -> isize) -> isize { f(1, 2) } diff --git a/tests/run-pass/non_capture_closure_to_fn_ptr.rs b/tests/run-pass/non_capture_closure_to_fn_ptr.rs index d48c4df45944a..e6a5017847d4d 100644 --- a/tests/run-pass/non_capture_closure_to_fn_ptr.rs +++ b/tests/run-pass/non_capture_closure_to_fn_ptr.rs @@ -12,7 +12,7 @@ fn main() { BAR(44, 45); let bar: unsafe fn(i32, i32) = BAR; unsafe { bar(46, 47) }; - let boo: &Fn(i32, i32) = &BAR; + let boo: &dyn Fn(i32, i32) = &BAR; boo(48, 49); let f = magic(||{}) as fn(); diff --git a/tests/run-pass/rc.rs b/tests/run-pass/rc.rs index 9b4d51ed376a6..d731fe8fd4c30 100644 --- a/tests/run-pass/rc.rs +++ b/tests/run-pass/rc.rs @@ -64,8 +64,8 @@ fn rc_from() { } fn rc_fat_ptr_eq() { - let p = Rc::new(1) as Rc; - let a: *const Debug = &*p; + let p = Rc::new(1) as Rc; + let a: *const dyn Debug = &*p; let r = Rc::into_raw(p); assert!(a == r); drop(unsafe { Rc::from_raw(r) }); diff --git a/tests/run-pass/regions-lifetime-nonfree-late-bound.rs b/tests/run-pass/regions-lifetime-nonfree-late-bound.rs index 85a189007c3de..78aeea64814a7 100644 --- a/tests/run-pass/regions-lifetime-nonfree-late-bound.rs +++ b/tests/run-pass/regions-lifetime-nonfree-late-bound.rs @@ -16,15 +16,15 @@ pub fn main() { fn explicit() { - fn test(_x: Option>) where F: FnMut(Box FnMut(&'a isize)>) {} - test(Some(box |_f: Box FnMut(&'a isize)>| {})); + fn test(_x: Option>) where F: FnMut(Box FnMut(&'a isize)>) {} + test(Some(box |_f: Box FnMut(&'a isize)>| {})); } // The code below is shorthand for the code above (and more likely // to represent what one encounters in practice). fn implicit() { - fn test(_x: Option>) where F: FnMut(Box< FnMut(& isize)>) {} - test(Some(box |_f: Box< FnMut(& isize)>| {})); + fn test(_x: Option>) where F: FnMut(Box) {} + test(Some(box |_f: Box| {})); } explicit(); diff --git a/tests/run-pass/traits.rs b/tests/run-pass/traits.rs index b2eae5d04f41b..03d2db400f013 100644 --- a/tests/run-pass/traits.rs +++ b/tests/run-pass/traits.rs @@ -13,17 +13,17 @@ impl Trait for Struct { struct Foo(T); fn main() { - let y: &Trait = &Struct(42); + let y: &dyn Trait = &Struct(42); y.method(); let x: Foo = Foo(Struct(42)); - let y: &Foo = &x; + let y: &Foo = &x; y.0.method(); - let x: Box i32> = Box::new(|x| x * 2); + let x: Box i32> = Box::new(|x| x * 2); assert_eq!(x(21), 42); let mut i = 5; { - let mut x: Box = Box::new(|| i *= 2); + let mut x: Box = Box::new(|| i *= 2); x(); x(); } assert_eq!(i, 20); From c748323eb39ea10d63368a37a4f72260b9703702 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 30 May 2019 11:01:22 +0200 Subject: [PATCH 0784/3747] move fn_item/ptr tests to closures file --- tests/run-pass/closures.rs | 52 +++++++++++++++++++ .../fn_item_as_closure_trait_object.rs | 6 --- ..._item_with_args_as_closure_trait_object.rs | 8 --- ...h_multiple_args_as_closure_trait_object.rs | 18 ------- .../fn_ptr_as_closure_trait_object.rs | 15 ------ 5 files changed, 52 insertions(+), 47 deletions(-) delete mode 100644 tests/run-pass/fn_item_as_closure_trait_object.rs delete mode 100644 tests/run-pass/fn_item_with_args_as_closure_trait_object.rs delete mode 100644 tests/run-pass/fn_item_with_multiple_args_as_closure_trait_object.rs delete mode 100644 tests/run-pass/fn_ptr_as_closure_trait_object.rs diff --git a/tests/run-pass/closures.rs b/tests/run-pass/closures.rs index 141e6cd6d08a2..eb8d8f0d5b987 100644 --- a/tests/run-pass/closures.rs +++ b/tests/run-pass/closures.rs @@ -44,10 +44,62 @@ fn boxed(f: Box i32>) -> i32 { f() } +fn fn_item_as_closure_trait_object() { + fn foo() {} + let f: &dyn Fn() = &foo; + f(); +} + +fn fn_item_with_args_as_closure_trait_object() { + fn foo(i: i32) { + assert_eq!(i, 42); + } + let f: &dyn Fn(i32) = &foo; + f(42); +} + +fn fn_item_with_multiple_args_as_closure_trait_object() { + fn foo(i: i32, j: i32) { + assert_eq!(i, 42); + assert_eq!(j, 55); + } + + fn bar(i: i32, j: i32, k: f32) { + assert_eq!(i, 42); + assert_eq!(j, 55); + assert_eq!(k, 3.14159) + } + let f: &dyn Fn(i32, i32) = &foo; + f(42, 55); + let f: &dyn Fn(i32, i32, f32) = &bar; + f(42, 55, 3.14159); +} + +fn fn_ptr_as_closure_trait_object() { + fn foo() {} + fn bar(u: u32) { assert_eq!(u, 42); } + fn baa(u: u32, f: f32) { + assert_eq!(u, 42); + assert_eq!(f, 3.141); + } + let f: &dyn Fn() = &(foo as fn()); + f(); + let f: &dyn Fn(u32) = &(bar as fn(u32)); + f(42); + let f: &dyn Fn(u32, f32) = &(baa as fn(u32, f32)); + f(42, 3.141); +} + + fn main() { assert_eq!(simple(), 12); assert_eq!(crazy_closure(), (84, 10, 10)); assert_eq!(closure_arg_adjustment_problem(), 3); assert_eq!(fn_once_closure_with_multiple_args(), 6); assert_eq!(boxed(Box::new({let x = 13; move || x})), 13); + + fn_item_as_closure_trait_object(); + fn_item_with_args_as_closure_trait_object(); + fn_item_with_multiple_args_as_closure_trait_object(); + fn_ptr_as_closure_trait_object(); } diff --git a/tests/run-pass/fn_item_as_closure_trait_object.rs b/tests/run-pass/fn_item_as_closure_trait_object.rs deleted file mode 100644 index dcbbb5cb6a2ce..0000000000000 --- a/tests/run-pass/fn_item_as_closure_trait_object.rs +++ /dev/null @@ -1,6 +0,0 @@ -fn foo() {} - -fn main() { - let f: &dyn Fn() = &foo; - f(); -} diff --git a/tests/run-pass/fn_item_with_args_as_closure_trait_object.rs b/tests/run-pass/fn_item_with_args_as_closure_trait_object.rs deleted file mode 100644 index 257028c4f0d8e..0000000000000 --- a/tests/run-pass/fn_item_with_args_as_closure_trait_object.rs +++ /dev/null @@ -1,8 +0,0 @@ -fn foo(i: i32) { - assert_eq!(i, 42); -} - -fn main() { - let f: &dyn Fn(i32) = &foo; - f(42); -} diff --git a/tests/run-pass/fn_item_with_multiple_args_as_closure_trait_object.rs b/tests/run-pass/fn_item_with_multiple_args_as_closure_trait_object.rs deleted file mode 100644 index 98111f304c893..0000000000000 --- a/tests/run-pass/fn_item_with_multiple_args_as_closure_trait_object.rs +++ /dev/null @@ -1,18 +0,0 @@ -fn foo(i: i32, j: i32) { - assert_eq!(i, 42); - assert_eq!(j, 55); -} - -fn bar(i: i32, j: i32, k: f32) { - assert_eq!(i, 42); - assert_eq!(j, 55); - assert_eq!(k, 3.14159) -} - - -fn main() { - let f: &dyn Fn(i32, i32) = &foo; - f(42, 55); - let f: &dyn Fn(i32, i32, f32) = &bar; - f(42, 55, 3.14159); -} diff --git a/tests/run-pass/fn_ptr_as_closure_trait_object.rs b/tests/run-pass/fn_ptr_as_closure_trait_object.rs deleted file mode 100644 index 89daed81507f1..0000000000000 --- a/tests/run-pass/fn_ptr_as_closure_trait_object.rs +++ /dev/null @@ -1,15 +0,0 @@ -fn foo() {} -fn bar(u: u32) { assert_eq!(u, 42); } -fn baa(u: u32, f: f32) { - assert_eq!(u, 42); - assert_eq!(f, 3.141); -} - -fn main() { - let f: &dyn Fn() = &(foo as fn()); - f(); - let f: &dyn Fn(u32) = &(bar as fn(u32)); - f(42); - let f: &dyn Fn(u32, f32) = &(baa as fn(u32, f32)); - f(42, 3.141); -} From 96444c11eee3a6d29d22056eee7e1d2ea73ebb19 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 31 May 2019 16:34:22 +0200 Subject: [PATCH 0785/3747] remove too expensive debug assertion --- src/stacked_borrows.rs | 22 ---------------------- 1 file changed, 22 deletions(-) diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 8c46f7e1b2e90..289fab99ad64b 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -346,23 +346,6 @@ impl<'tcx> Stack { Ok(()) } - /// `reborrow` helper function: test that the stack invariants are still maintained. - fn test_invariants(&self) { - let mut saw_shared_read_only = false; - for item in self.borrows.iter() { - match item.perm { - Permission::SharedReadOnly => { - saw_shared_read_only = true; - } - // Otherwise, if we saw one before, that's a bug. - perm if saw_shared_read_only => { - bug!("Found {:?} on top of a SharedReadOnly!", perm); - } - _ => {} - } - } - } - /// Derived a new pointer from one with the given tag. /// `weak` controls whether this operation is weak or strong: weak granting does not act as /// an access, and they add the new item directly on top of the one it is derived @@ -418,11 +401,6 @@ impl<'tcx> Stack { self.borrows.insert(new_idx, new); } - // Make sure that after all this, the stack's invariant is still maintained. - if cfg!(debug_assertions) { - self.test_invariants(); - } - Ok(()) } } From dafd2e7202dbdc167b573e07f13a7ca1fd37e42f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 1 Jun 2019 10:04:49 +0200 Subject: [PATCH 0786/3747] rustup for ... deprecation --- rust-version | 2 +- tests/run-pass/ints.rs | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/rust-version b/rust-version index 5504e77097b73..60d0ba51f794c 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -c28084ac16af4ab594b6860958df140e7c876a13 +8b40a188cee5bef97526dfc271afbd2a98008183 diff --git a/tests/run-pass/ints.rs b/tests/run-pass/ints.rs index 4f23b5ec9c381..00ca2aa41dd35 100644 --- a/tests/run-pass/ints.rs +++ b/tests/run-pass/ints.rs @@ -34,11 +34,11 @@ fn match_int() -> i16 { fn match_int_range() -> i64 { let n = 42; match n { - 0...9 => 0, - 10...19 => 1, - 20...29 => 2, - 30...39 => 3, - 40...49 => 4, + 0..=9 => 0, + 10..=19 => 1, + 20..=29 => 2, + 30..=39 => 3, + 40..=42 => 4, _ => 5, } } From 0c704151f7c365ab8cd84e994b54b1bb424647cd Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 27 May 2019 20:04:37 +0200 Subject: [PATCH 0787/3747] use new rustc infrastructure to tag the base pointer of static allocations --- src/intrinsic.rs | 5 +-- src/lib.rs | 73 +++++++++++++++++++++--------------------- src/stacked_borrows.rs | 65 +++++++++++++++++++++---------------- 3 files changed, 76 insertions(+), 67 deletions(-) diff --git a/src/intrinsic.rs b/src/intrinsic.rs index a17f576b43b7f..d46d185c5f488 100644 --- a/src/intrinsic.rs +++ b/src/intrinsic.rs @@ -5,7 +5,7 @@ use rustc::ty; use crate::{ PlaceTy, OpTy, ImmTy, Immediate, Scalar, ScalarMaybeUndef, Tag, - OperatorEvalContextExt + OperatorEvalContextExt, MiriMemoryKind, }; impl<'a, 'mir, 'tcx> EvalContextExt<'a, 'mir, 'tcx> for crate::MiriEvalContext<'a, 'mir, 'tcx> {} @@ -401,7 +401,8 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, "type_name" => { let ty = substs.type_at(0); let ty_name = ty.to_string(); - let value = this.str_to_immediate(&ty_name)?; + let ptr = this.memory_mut().allocate_static_bytes(ty_name.as_bytes(), MiriMemoryKind::Static.into()); + let value = Immediate::new_slice(Scalar::Ptr(ptr), ty_name.len() as u64, this); this.write_immediate(value, dest)?; } diff --git a/src/lib.rs b/src/lib.rs index 89d7964913ae9..bf0c6cd38787e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -30,7 +30,7 @@ use rand::SeedableRng; use rustc::ty::{self, TyCtxt, query::TyCtxtAt}; use rustc::ty::layout::{LayoutOf, Size, Align}; -use rustc::hir::{self, def_id::DefId}; +use rustc::hir::def_id::DefId; use rustc::mir; pub use rustc_mir::interpret::*; // Resolve ambiguity. @@ -113,7 +113,7 @@ pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( // Return value (in static memory so that it does not count as leak). let ret = ecx.layout_of(start_mir.return_ty())?; - let ret_ptr = ecx.allocate(ret, MiriMemoryKind::MutStatic.into()); + let ret_ptr = ecx.allocate(ret, MiriMemoryKind::Static.into()); // Push our stack frame. ecx.push_stack_frame( @@ -128,7 +128,7 @@ pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( let mut args = ecx.frame().mir.args_iter(); // First argument: pointer to `main()`. - let main_ptr = ecx.memory_mut().create_fn_alloc(main_instance).with_default_tag(); + let main_ptr = ecx.memory_mut().create_fn_alloc(main_instance); let dest = ecx.eval_place(&mir::Place::Base(mir::PlaceBase::Local(args.next().unwrap())))?; ecx.write_scalar(Scalar::Ptr(main_ptr), dest)?; @@ -162,7 +162,7 @@ pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( // Add `0` terminator. let mut arg = arg.into_bytes(); arg.push(0); - argvs.push(ecx.memory_mut().allocate_static_bytes(arg.as_slice()).with_default_tag()); + argvs.push(ecx.memory_mut().allocate_static_bytes(arg.as_slice(), MiriMemoryKind::Static.into())); } // Make an array with all these pointers, in the Miri memory. let argvs_layout = ecx.layout_of(ecx.tcx.mk_array(ecx.tcx.mk_imm_ptr(ecx.tcx.types.u8), argvs.len() as u64))?; @@ -299,8 +299,8 @@ pub enum MiriMemoryKind { C, /// Part of env var emulation. Env, - /// Mutable statics. - MutStatic, + /// Statics. + Static, } impl Into> for MiriMemoryKind { @@ -316,7 +316,7 @@ impl MayLeak for MiriMemoryKind { use self::MiriMemoryKind::*; match self { Rust | C => false, - Env | MutStatic => true, + Env | Static => true, } } } @@ -392,7 +392,7 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { type MemoryMap = MonoHashMap, Allocation)>; - const STATIC_KIND: Option = Some(MiriMemoryKind::MutStatic); + const STATIC_KIND: Option = Some(MiriMemoryKind::Static); #[inline(always)] fn enforce_validity(ecx: &InterpretCx<'a, 'mir, 'tcx, Self>) -> bool { @@ -476,8 +476,7 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { fn find_foreign_static( def_id: DefId, tcx: TyCtxtAt<'a, 'tcx, 'tcx>, - memory_extra: &Self::MemoryExtra, - ) -> EvalResult<'tcx, Cow<'tcx, Allocation>> { + ) -> EvalResult<'tcx, Cow<'tcx, Allocation>> { let attrs = tcx.get_attrs(def_id); let link_name = match attr::first_attr_value_str_by_name(&attrs, sym::link_name) { Some(name) => name.as_str(), @@ -489,8 +488,7 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { // This should be all-zero, pointer-sized. let size = tcx.data_layout.pointer_size; let data = vec![0; size.bytes() as usize]; - let extra = Stacks::new(size, Tag::default(), Rc::clone(memory_extra)); - Allocation::from_bytes(&data, tcx.data_layout.pointer_align.abi, extra) + Allocation::from_bytes(&data, tcx.data_layout.pointer_align.abi) } _ => return err!(Unimplemented( format!("can't access foreign static: {}", link_name), @@ -506,47 +504,48 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { Ok(()) } - fn adjust_static_allocation<'b>( - alloc: &'b Allocation, + fn tag_allocation<'b>( + id: AllocId, + alloc: Cow<'b, Allocation>, + kind: Option>, memory_extra: &Self::MemoryExtra, - ) -> Cow<'b, Allocation> { - let extra = Stacks::new( + ) -> (Cow<'b, Allocation>, Self::PointerTag) { + let kind = kind.expect("we set our STATIC_KIND so this cannot be None"); + let alloc = alloc.into_owned(); + let (extra, base_tag) = Stacks::new_allocation( + id, Size::from_bytes(alloc.bytes.len() as u64), - Tag::default(), Rc::clone(memory_extra), + kind, ); + if kind != MiriMemoryKind::Static.into() { + assert!(alloc.relocations.is_empty(), "Only statics can come initialized with inner pointers"); + // Now we can rely on the inner pointers being static, too. + } + let mut memory_extra = memory_extra.borrow_mut(); let alloc: Allocation = Allocation { - bytes: alloc.bytes.clone(), + bytes: alloc.bytes, relocations: Relocations::from_presorted( alloc.relocations.iter() - .map(|&(offset, ((), alloc))| (offset, (Tag::default(), alloc))) + // The allocations in the relocations (pointers stored *inside* this allocation) + // all get the base pointer tag. + .map(|&(offset, ((), alloc))| (offset, (memory_extra.static_base_ptr(alloc), alloc))) .collect() ), - undef_mask: alloc.undef_mask.clone(), + undef_mask: alloc.undef_mask, align: alloc.align, mutability: alloc.mutability, extra, }; - Cow::Owned(alloc) - } - - #[inline(always)] - fn new_allocation( - size: Size, - extra: &Self::MemoryExtra, - kind: MemoryKind, - ) -> (Self::AllocExtra, Self::PointerTag) { - Stacks::new_allocation(size, extra, kind) + (Cow::Owned(alloc), base_tag) } #[inline(always)] - fn tag_dereference( - _ecx: &InterpretCx<'a, 'mir, 'tcx, Self>, - place: MPlaceTy<'tcx, Tag>, - _mutability: Option, - ) -> EvalResult<'tcx, Scalar> { - // Nothing happens. - Ok(place.ptr) + fn tag_static_base_pointer( + id: AllocId, + memory_extra: &Self::MemoryExtra, + ) -> Self::PointerTag { + memory_extra.borrow_mut().static_base_ptr(id) } #[inline(always)] diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 8c46f7e1b2e90..71779a6132d9d 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -1,5 +1,5 @@ use std::cell::RefCell; -use std::collections::HashSet; +use std::collections::{HashMap, HashSet}; use std::rc::Rc; use std::fmt; use std::num::NonZeroU64; @@ -10,7 +10,7 @@ use rustc::mir::RetagKind; use crate::{ EvalResult, InterpError, MiriEvalContext, HelpersEvalContextExt, Evaluator, MutValueVisitor, - MemoryKind, MiriMemoryKind, RangeMap, Allocation, AllocationExtra, CheckInAllocMsg, + MemoryKind, MiriMemoryKind, RangeMap, Allocation, AllocationExtra, AllocId, CheckInAllocMsg, Pointer, Immediate, ImmTy, PlaceTy, MPlaceTy, }; @@ -92,10 +92,18 @@ pub struct Stacks { /// Extra global state, available to the memory access hooks. #[derive(Debug)] pub struct GlobalState { + /// Next unused pointer ID (tag). next_ptr_id: PtrId, + /// Table storing the "base" tag for each allocation. + /// The base tag is the one used for the initial pointer. + /// We need this in a separate table to handle cyclic statics. + base_ptr_ids: HashMap, + /// Next unused call ID (for protectors). next_call_id: CallId, + /// Those call IDs corresponding to functions that are still running. active_calls: HashSet, } +/// Memory extra state gives us interior mutable access to the global state. pub type MemoryState = Rc>; /// Indicates which kind of access is being performed. @@ -144,6 +152,7 @@ impl Default for GlobalState { fn default() -> Self { GlobalState { next_ptr_id: NonZeroU64::new(1).unwrap(), + base_ptr_ids: HashMap::default(), next_call_id: NonZeroU64::new(1).unwrap(), active_calls: HashSet::default(), } @@ -151,7 +160,7 @@ impl Default for GlobalState { } impl GlobalState { - pub fn new_ptr(&mut self) -> PtrId { + fn new_ptr(&mut self) -> PtrId { let id = self.next_ptr_id; self.next_ptr_id = NonZeroU64::new(id.get() + 1).unwrap(); id @@ -172,6 +181,15 @@ impl GlobalState { fn is_active(&self, id: CallId) -> bool { self.active_calls.contains(&id) } + + pub fn static_base_ptr(&mut self, id: AllocId) -> Tag { + self.base_ptr_ids.get(&id).copied().unwrap_or_else(|| { + let tag = Tag::Tagged(self.new_ptr()); + trace!("New allocation {:?} has base tag {:?}", id, tag); + self.base_ptr_ids.insert(id, tag); + tag + }) + } } // # Stacked Borrows Core Begin @@ -190,14 +208,6 @@ impl GlobalState { /// F3: If an access happens with an `&` outside `UnsafeCell`, /// it requires the `SharedReadOnly` to still be in the stack. -impl Default for Tag { - #[inline(always)] - fn default() -> Tag { - Tag::Untagged - } -} - - /// Core relation on `Permission` to define which accesses are allowed impl Permission { /// This defines for a given permission, whether it permits the given kind of access. @@ -431,12 +441,13 @@ impl<'tcx> Stack { /// Map per-stack operations to higher-level per-location-range operations. impl<'tcx> Stacks { /// Creates new stack with initial tag. - pub(crate) fn new( + fn new( size: Size, + perm: Permission, tag: Tag, extra: MemoryState, ) -> Self { - let item = Item { perm: Permission::Unique, tag, protector: None }; + let item = Item { perm, tag, protector: None }; let stack = Stack { borrows: vec![item], }; @@ -465,27 +476,25 @@ impl<'tcx> Stacks { /// Glue code to connect with Miri Machine Hooks impl Stacks { pub fn new_allocation( + id: AllocId, size: Size, - extra: &MemoryState, + extra: MemoryState, kind: MemoryKind, ) -> (Self, Tag) { - let tag = match kind { - MemoryKind::Stack => { - // New unique borrow. This `Uniq` is not accessible by the program, + let (tag, perm) = match kind { + MemoryKind::Stack => + // New unique borrow. This tag is not accessible by the program, // so it will only ever be used when using the local directly (i.e., - // not through a pointer). That is, whenever we directly use a local, this will pop + // not through a pointer). That is, whenever we directly write to a local, this will pop // everything else off the stack, invalidating all previous pointers, - // and in particular, *all* raw pointers. This subsumes the explicit - // `reset` which the blog post [1] says to perform when accessing a local. - // - // [1]: - Tag::Tagged(extra.borrow_mut().new_ptr()) - } - _ => { - Tag::Untagged - } + // and in particular, *all* raw pointers. + (Tag::Tagged(extra.borrow_mut().new_ptr()), Permission::Unique), + MemoryKind::Machine(MiriMemoryKind::Static) => + (extra.borrow_mut().static_base_ptr(id), Permission::SharedReadWrite), + _ => + (Tag::Untagged, Permission::SharedReadWrite), }; - let stack = Stacks::new(size, tag, Rc::clone(extra)); + let stack = Stacks::new(size, perm, tag, extra); (stack, tag) } } From e03255d62554424805a1959a0cfdad13171429a1 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 28 May 2019 18:28:15 +0200 Subject: [PATCH 0788/3747] fix existing tests fix thread-local example to no longer write to pointers derived from a shared ref; fix compile-fail test --- tests/compile-fail/modifying_constants.rs | 2 ++ tests/run-pass/thread-local.rs | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/compile-fail/modifying_constants.rs b/tests/compile-fail/modifying_constants.rs index 27c74e8dc87ee..4546e8a4d7c9b 100644 --- a/tests/compile-fail/modifying_constants.rs +++ b/tests/compile-fail/modifying_constants.rs @@ -1,3 +1,5 @@ +// This should fail even without validation +// compile-flags: -Zmiri-disable-validation fn main() { let x = &1; // the `&1` is promoted to a constant, but it used to be that only the pointer is marked static, not the pointee diff --git a/tests/run-pass/thread-local.rs b/tests/run-pass/thread-local.rs index aeedb7034ce5e..8de45811be443 100644 --- a/tests/run-pass/thread-local.rs +++ b/tests/run-pass/thread-local.rs @@ -56,7 +56,7 @@ fn main() { create(None); // check that the no-dtor case works // Initialize the keys we use to check destructor ordering - for (key, global) in KEYS.iter_mut().zip(GLOBALS.iter()) { + for (key, global) in KEYS.iter_mut().zip(GLOBALS.iter_mut()) { *key = create(Some(mem::transmute(dtor as unsafe extern fn(*mut u64)))); set(*key, global as *const _ as *mut _); } From 9f48b3029ca51997945ae4170f1e2b0ebb23a7a2 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 28 May 2019 19:26:50 +0200 Subject: [PATCH 0789/3747] test that we cannot access unescaped static memory with a raw ptr --- tests/compile-fail/stacked_borrows/unescaped_static.rs | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 tests/compile-fail/stacked_borrows/unescaped_static.rs diff --git a/tests/compile-fail/stacked_borrows/unescaped_static.rs b/tests/compile-fail/stacked_borrows/unescaped_static.rs new file mode 100644 index 0000000000000..0f0467fc5cb99 --- /dev/null +++ b/tests/compile-fail/stacked_borrows/unescaped_static.rs @@ -0,0 +1,7 @@ +static ARRAY: [u8; 2] = [0, 1]; + +fn main() { + let ptr_to_first = &ARRAY[0] as *const u8; + // Illegally use this to access the 2nd element. + let _val = unsafe { *ptr_to_first.add(1) }; //~ ERROR borrow stack +} From b231a7ec9efa58496786c4eed623e150659f370d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 2 Jun 2019 22:16:18 +0200 Subject: [PATCH 0790/3747] bump Rust version --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 60d0ba51f794c..7604934a98b33 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -8b40a188cee5bef97526dfc271afbd2a98008183 +627486af15d222bcba336b12ea92a05237cc9ab1 From e4317e9e082b0b7b3c3162e4ad725194f09dd7e7 Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Mon, 3 Jun 2019 09:52:19 +0700 Subject: [PATCH 0791/3747] Bump cargo_metadata to 0.8 --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 6f7570edda5fd..e60205fc42088 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -34,7 +34,7 @@ required-features = ["rustc_tests"] [dependencies] byteorder = { version = "1.1", features = ["i128"]} -cargo_metadata = { version = "0.7", optional = true } +cargo_metadata = { version = "0.8", optional = true } directories = { version = "1.0", optional = true } rustc_version = { version = "0.2.3", optional = true } env_logger = "0.6" From 724a9276b1f382a000ceed27ba52bcb04ed436f4 Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Mon, 3 Jun 2019 09:55:02 +0700 Subject: [PATCH 0792/3747] Bump directories to 2.0 --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index e60205fc42088..0627c9986fb4a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -35,7 +35,7 @@ required-features = ["rustc_tests"] [dependencies] byteorder = { version = "1.1", features = ["i128"]} cargo_metadata = { version = "0.8", optional = true } -directories = { version = "1.0", optional = true } +directories = { version = "2.0", optional = true } rustc_version = { version = "0.2.3", optional = true } env_logger = "0.6" log = "0.4" From 27a66a1e4220afc859d3ee93a208a7f19b1c693f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 31 May 2019 19:05:31 +0200 Subject: [PATCH 0793/3747] test for no-validation-only failure --- tests/run-pass/without-validation.rs | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 tests/run-pass/without-validation.rs diff --git a/tests/run-pass/without-validation.rs b/tests/run-pass/without-validation.rs new file mode 100644 index 0000000000000..8cff3a5c4b2e8 --- /dev/null +++ b/tests/run-pass/without-validation.rs @@ -0,0 +1,24 @@ +// When we notice something breaks only without validation, we add a test here. +// compile-flags: -Zmiri-disable-validation +use std::cell::*; + +fn refcell_unsize() { + let cell: RefCell<[i32; 3]> = RefCell::new([1, 2, 3]); + { + let mut cellref: RefMut<'_, [i32; 3]> = cell.borrow_mut(); + cellref[0] = 4; + let mut coerced: RefMut<'_, [i32]> = cellref; + coerced[2] = 5; + } + { + let comp: &mut [i32] = &mut [4, 2, 5]; + let cellref: Ref<'_, [i32; 3]> = cell.borrow(); + assert_eq!(&*cellref, comp); + let coerced: Ref<'_, [i32]> = cellref; + assert_eq!(&*coerced, comp); + } +} + +fn main() { + refcell_unsize(); +} From c06134c4afdc82c298e424e8f3e43c7e5379197c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 4 Jun 2019 13:22:27 +0200 Subject: [PATCH 0794/3747] bump Rust --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 7604934a98b33..930c6c17ac6c2 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -627486af15d222bcba336b12ea92a05237cc9ab1 +021a5033098ff0e3f7126acc7ac35149d325f16d From 1ceb81b34552c0ff466f4ffaa00fe2f87cb5e16c Mon Sep 17 00:00:00 2001 From: Dylan MacKenzie Date: Sun, 2 Jun 2019 21:20:13 -0700 Subject: [PATCH 0795/3747] Use in-core implementation of `type_name`. We bump `rust-version` to pick up the new impl from https://github.com/rust-lang/rust/pull/61498 and add a test. --- rust-version | 2 +- src/intrinsic.rs | 10 +--------- tests/run-pass/intrinsics.rs | 5 +++++ 3 files changed, 7 insertions(+), 10 deletions(-) diff --git a/rust-version b/rust-version index 930c6c17ac6c2..b2c0aca42bdf5 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -021a5033098ff0e3f7126acc7ac35149d325f16d +7cdaffd7962c4aae0cadd82baa241901b03f9458 diff --git a/src/intrinsic.rs b/src/intrinsic.rs index d46d185c5f488..8d564456f4edf 100644 --- a/src/intrinsic.rs +++ b/src/intrinsic.rs @@ -5,7 +5,7 @@ use rustc::ty; use crate::{ PlaceTy, OpTy, ImmTy, Immediate, Scalar, ScalarMaybeUndef, Tag, - OperatorEvalContextExt, MiriMemoryKind, + OperatorEvalContextExt }; impl<'a, 'mir, 'tcx> EvalContextExt<'a, 'mir, 'tcx> for crate::MiriEvalContext<'a, 'mir, 'tcx> {} @@ -398,14 +398,6 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, )?; } - "type_name" => { - let ty = substs.type_at(0); - let ty_name = ty.to_string(); - let ptr = this.memory_mut().allocate_static_bytes(ty_name.as_bytes(), MiriMemoryKind::Static.into()); - let value = Immediate::new_slice(Scalar::Ptr(ptr), ty_name.len() as u64, this); - this.write_immediate(value, dest)?; - } - "unchecked_div" => { let l = this.read_immediate(args[0])?; let r = this.read_immediate(args[1])?; diff --git a/tests/run-pass/intrinsics.rs b/tests/run-pass/intrinsics.rs index 3152737a601ca..963265749d136 100644 --- a/tests/run-pass/intrinsics.rs +++ b/tests/run-pass/intrinsics.rs @@ -1,3 +1,6 @@ +#![feature(core_intrinsics)] + +use std::intrinsics::type_name; use std::mem::{size_of, size_of_val}; fn main() { @@ -7,4 +10,6 @@ fn main() { assert_eq!(size_of_val(&[] as &[i32]), 0); assert_eq!(size_of_val(&[1, 2, 3] as &[i32]), 12); assert_eq!(size_of_val("foobar"), 6); + + assert_eq!(unsafe { type_name::>() }, "core::option::Option"); } From d6bcfc58e3afe292cce167e8a419cf412c25e4cd Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 8 Jun 2019 22:14:47 +0200 Subject: [PATCH 0796/3747] rustup for EvalResult rename --- rust-version | 2 +- src/fn_call.rs | 14 +++++++------- src/helpers.rs | 22 +++++++++++----------- src/intrinsic.rs | 4 ++-- src/lib.rs | 22 +++++++++++----------- src/operator.rs | 16 ++++++++-------- src/stacked_borrows.rs | 28 ++++++++++++++-------------- src/tls.rs | 10 +++++----- 8 files changed, 59 insertions(+), 59 deletions(-) diff --git a/rust-version b/rust-version index b2c0aca42bdf5..3e7048ac72cc5 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -7cdaffd7962c4aae0cadd82baa241901b03f9458 +5c45343f11fbf93cf4e15568aee3ff3f2f287466 diff --git a/src/fn_call.rs b/src/fn_call.rs index 17679e26790cb..5397c048f9f46 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -17,7 +17,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' args: &[OpTy<'tcx, Tag>], dest: Option>, ret: Option, - ) -> EvalResult<'tcx, Option<&'mir mir::Body<'tcx>>> { + ) -> InterpResult<'tcx, Option<&'mir mir::Body<'tcx>>> { let this = self.eval_context_mut(); trace!("eval_fn_call: {:#?}, {:?}", instance, dest.map(|place| *place)); @@ -76,7 +76,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' fn free( &mut self, ptr: Scalar, - ) -> EvalResult<'tcx> { + ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); if !ptr.is_null_ptr(this) { this.memory_mut().deallocate( @@ -92,7 +92,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' &mut self, old_ptr: Scalar, new_size: u64, - ) -> EvalResult<'tcx, Scalar> { + ) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); let align = this.tcx.data_layout.pointer_align.abi; if old_ptr.is_null_ptr(this) { @@ -139,7 +139,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' args: &[OpTy<'tcx, Tag>], dest: Option>, ret: Option, - ) -> EvalResult<'tcx> { + ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let attrs = this.tcx.get_attrs(def_id); let link_name = match attr::first_attr_value_str_by_name(&attrs, sym::link_name) { @@ -895,13 +895,13 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' Ok(()) } - fn write_null(&mut self, dest: PlaceTy<'tcx, Tag>) -> EvalResult<'tcx> { + fn write_null(&mut self, dest: PlaceTy<'tcx, Tag>) -> InterpResult<'tcx> { self.eval_context_mut().write_scalar(Scalar::from_int(0, dest.layout.size), dest) } /// Evaluates the scalar at the specified path. Returns Some(val) /// if the path could be resolved, and None otherwise - fn eval_path_scalar(&mut self, path: &[&str]) -> EvalResult<'tcx, Option>> { + fn eval_path_scalar(&mut self, path: &[&str]) -> InterpResult<'tcx, Option>> { let this = self.eval_context_mut(); if let Ok(instance) = this.resolve_path(path) { let cid = GlobalId { @@ -920,7 +920,7 @@ fn gen_random<'a, 'mir, 'tcx>( this: &mut MiriEvalContext<'a, 'mir, 'tcx>, len: usize, dest: Scalar, -) -> EvalResult<'tcx> { +) -> InterpResult<'tcx> { if len == 0 { // Nothing to do return Ok(()); diff --git a/src/helpers.rs b/src/helpers.rs index 89aba494724ca..29bc1def9fda5 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -9,7 +9,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'a, 'mir, 'tcx> for crate::MiriEvalContext<' pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<'a, 'mir, 'tcx> { /// Gets an instance for a path. - fn resolve_path(&self, path: &[&str]) -> EvalResult<'tcx, ty::Instance<'tcx>> { + fn resolve_path(&self, path: &[&str]) -> InterpResult<'tcx, ty::Instance<'tcx>> { let this = self.eval_context_ref(); this.tcx .crates() @@ -49,8 +49,8 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' &self, place: MPlaceTy<'tcx, Tag>, size: Size, - mut action: impl FnMut(Pointer, Size, bool) -> EvalResult<'tcx>, - ) -> EvalResult<'tcx> { + mut action: impl FnMut(Pointer, Size, bool) -> InterpResult<'tcx>, + ) -> InterpResult<'tcx> { let this = self.eval_context_ref(); trace!("visit_frozen(place={:?}, size={:?})", *place, size); debug_assert_eq!(size, @@ -120,7 +120,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' /// Visiting the memory covered by a `MemPlace`, being aware of /// whether we are inside an `UnsafeCell` or not. struct UnsafeCellVisitor<'ecx, 'a, 'mir, 'tcx, F> - where F: FnMut(MPlaceTy<'tcx, Tag>) -> EvalResult<'tcx> + where F: FnMut(MPlaceTy<'tcx, Tag>) -> InterpResult<'tcx> { ecx: &'ecx MiriEvalContext<'a, 'mir, 'tcx>, unsafe_cell_action: F, @@ -131,7 +131,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' for UnsafeCellVisitor<'ecx, 'a, 'mir, 'tcx, F> where - F: FnMut(MPlaceTy<'tcx, Tag>) -> EvalResult<'tcx> + F: FnMut(MPlaceTy<'tcx, Tag>) -> InterpResult<'tcx> { type V = MPlaceTy<'tcx, Tag>; @@ -141,7 +141,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' } // Hook to detect `UnsafeCell`. - fn visit_value(&mut self, v: MPlaceTy<'tcx, Tag>) -> EvalResult<'tcx> + fn visit_value(&mut self, v: MPlaceTy<'tcx, Tag>) -> InterpResult<'tcx> { trace!("UnsafeCellVisitor: {:?} {:?}", *v, v.layout.ty); let is_unsafe_cell = match v.layout.ty.sty { @@ -164,8 +164,8 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' fn visit_aggregate( &mut self, place: MPlaceTy<'tcx, Tag>, - fields: impl Iterator>>, - ) -> EvalResult<'tcx> { + fields: impl Iterator>>, + ) -> InterpResult<'tcx> { match place.layout.fields { layout::FieldPlacement::Array { .. } => { // For the array layout, we know the iterator will yield sorted elements so @@ -174,7 +174,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' } layout::FieldPlacement::Arbitrary { .. } => { // Gather the subplaces and sort them before visiting. - let mut places = fields.collect::>>>()?; + let mut places = fields.collect::>>>()?; places.sort_by_key(|place| place.ptr.get_ptr_offset(self.ecx())); self.walk_aggregate(place, places.into_iter().map(Ok)) } @@ -186,7 +186,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' } // We have to do *something* for unions. - fn visit_union(&mut self, v: MPlaceTy<'tcx, Tag>) -> EvalResult<'tcx> + fn visit_union(&mut self, v: MPlaceTy<'tcx, Tag>) -> InterpResult<'tcx> { // With unions, we fall back to whatever the type says, to hopefully be consistent // with LLVM IR. @@ -200,7 +200,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' } // We should never get to a primitive, but always short-circuit somewhere above. - fn visit_primitive(&mut self, _v: MPlaceTy<'tcx, Tag>) -> EvalResult<'tcx> + fn visit_primitive(&mut self, _v: MPlaceTy<'tcx, Tag>) -> InterpResult<'tcx> { bug!("we should always short-circuit before coming to a primitive") } diff --git a/src/intrinsic.rs b/src/intrinsic.rs index 8d564456f4edf..822265bc2112d 100644 --- a/src/intrinsic.rs +++ b/src/intrinsic.rs @@ -1,5 +1,5 @@ use rustc::mir; -use rustc::mir::interpret::{EvalResult, PointerArithmetic}; +use rustc::mir::interpret::{InterpResult, PointerArithmetic}; use rustc::ty::layout::{self, LayoutOf, Size}; use rustc::ty; @@ -15,7 +15,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, instance: ty::Instance<'tcx>, args: &[OpTy<'tcx, Tag>], dest: PlaceTy<'tcx, Tag>, - ) -> EvalResult<'tcx> { + ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); if this.emulate_intrinsic(instance, args, dest)? { return Ok(()); diff --git a/src/lib.rs b/src/lib.rs index bf0c6cd38787e..8577bc4714e5f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -75,7 +75,7 @@ pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( tcx: TyCtxt<'a, 'tcx, 'tcx>, main_id: DefId, config: MiriConfig, -) -> EvalResult<'tcx, InterpretCx<'a, 'mir, 'tcx, Evaluator<'tcx>>> { +) -> InterpResult<'tcx, InterpretCx<'a, 'mir, 'tcx, Evaluator<'tcx>>> { let mut ecx = InterpretCx::new( tcx.at(syntax::source_map::DUMMY_SP), ty::ParamEnv::reveal_all(), @@ -225,7 +225,7 @@ pub fn eval_main<'a, 'tcx: 'a>( }; // Perform the main execution. - let res: EvalResult = (|| { + let res: InterpResult = (|| { ecx.run()?; ecx.run_tls_dtors() })(); @@ -407,7 +407,7 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { args: &[OpTy<'tcx, Tag>], dest: Option>, ret: Option, - ) -> EvalResult<'tcx, Option<&'mir mir::Body<'tcx>>> { + ) -> InterpResult<'tcx, Option<&'mir mir::Body<'tcx>>> { ecx.find_fn(instance, args, dest, ret) } @@ -417,7 +417,7 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { instance: ty::Instance<'tcx>, args: &[OpTy<'tcx, Tag>], dest: PlaceTy<'tcx, Tag>, - ) -> EvalResult<'tcx> { + ) -> InterpResult<'tcx> { ecx.call_intrinsic(instance, args, dest) } @@ -427,14 +427,14 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { bin_op: mir::BinOp, left: ImmTy<'tcx, Tag>, right: ImmTy<'tcx, Tag>, - ) -> EvalResult<'tcx, (Scalar, bool)> { + ) -> InterpResult<'tcx, (Scalar, bool)> { ecx.ptr_op(bin_op, left, right) } fn box_alloc( ecx: &mut InterpretCx<'a, 'mir, 'tcx, Self>, dest: PlaceTy<'tcx, Tag>, - ) -> EvalResult<'tcx> { + ) -> InterpResult<'tcx> { trace!("box_alloc for {:?}", dest.layout.ty); // Call the `exchange_malloc` lang item. let malloc = ecx.tcx.lang_items().exchange_malloc_fn().unwrap(); @@ -476,7 +476,7 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { fn find_foreign_static( def_id: DefId, tcx: TyCtxtAt<'a, 'tcx, 'tcx>, - ) -> EvalResult<'tcx, Cow<'tcx, Allocation>> { + ) -> InterpResult<'tcx, Cow<'tcx, Allocation>> { let attrs = tcx.get_attrs(def_id); let link_name = match attr::first_attr_value_str_by_name(&attrs, sym::link_name) { Some(name) => name.as_str(), @@ -498,7 +498,7 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { } #[inline(always)] - fn before_terminator(_ecx: &mut InterpretCx<'a, 'mir, 'tcx, Self>) -> EvalResult<'tcx> + fn before_terminator(_ecx: &mut InterpretCx<'a, 'mir, 'tcx, Self>) -> InterpResult<'tcx> { // We are not interested in detecting loops. Ok(()) @@ -553,7 +553,7 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { ecx: &mut InterpretCx<'a, 'mir, 'tcx, Self>, kind: mir::RetagKind, place: PlaceTy<'tcx, Tag>, - ) -> EvalResult<'tcx> { + ) -> InterpResult<'tcx> { if !ecx.tcx.sess.opts.debugging_opts.mir_emit_retag || !Self::enforce_validity(ecx) { // No tracking, or no retagging. The latter is possible because a dependency of ours // might be called with different flags than we are, so there are `Retag` @@ -569,7 +569,7 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { #[inline(always)] fn stack_push( ecx: &mut InterpretCx<'a, 'mir, 'tcx, Self>, - ) -> EvalResult<'tcx, stacked_borrows::CallId> { + ) -> InterpResult<'tcx, stacked_borrows::CallId> { Ok(ecx.memory().extra.borrow_mut().new_call()) } @@ -577,7 +577,7 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { fn stack_pop( ecx: &mut InterpretCx<'a, 'mir, 'tcx, Self>, extra: stacked_borrows::CallId, - ) -> EvalResult<'tcx> { + ) -> InterpResult<'tcx> { Ok(ecx.memory().extra.borrow_mut().end_call(extra)) } } diff --git a/src/operator.rs b/src/operator.rs index 28d0d7c960959..411df2155de0e 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -9,7 +9,7 @@ pub trait EvalContextExt<'tcx> { bin_op: mir::BinOp, left: ImmTy<'tcx, Tag>, right: ImmTy<'tcx, Tag>, - ) -> EvalResult<'tcx, (Scalar, bool)>; + ) -> InterpResult<'tcx, (Scalar, bool)>; fn ptr_int_arithmetic( &self, @@ -17,20 +17,20 @@ pub trait EvalContextExt<'tcx> { left: Pointer, right: u128, signed: bool, - ) -> EvalResult<'tcx, (Scalar, bool)>; + ) -> InterpResult<'tcx, (Scalar, bool)>; fn ptr_eq( &self, left: Scalar, right: Scalar, - ) -> EvalResult<'tcx, bool>; + ) -> InterpResult<'tcx, bool>; fn pointer_offset_inbounds( &self, ptr: Scalar, pointee_ty: Ty<'tcx>, offset: i64, - ) -> EvalResult<'tcx, Scalar>; + ) -> InterpResult<'tcx, Scalar>; } impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, 'tcx> { @@ -39,7 +39,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' bin_op: mir::BinOp, left: ImmTy<'tcx, Tag>, right: ImmTy<'tcx, Tag>, - ) -> EvalResult<'tcx, (Scalar, bool)> { + ) -> InterpResult<'tcx, (Scalar, bool)> { use rustc::mir::BinOp::*; trace!("ptr_op: {:?} {:?} {:?}", *left, bin_op, *right); @@ -138,7 +138,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' &self, left: Scalar, right: Scalar, - ) -> EvalResult<'tcx, bool> { + ) -> InterpResult<'tcx, bool> { let size = self.pointer_size(); Ok(match (left, right) { (Scalar::Raw { .. }, Scalar::Raw { .. }) => @@ -236,7 +236,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' left: Pointer, right: u128, signed: bool, - ) -> EvalResult<'tcx, (Scalar, bool)> { + ) -> InterpResult<'tcx, (Scalar, bool)> { use rustc::mir::BinOp::*; fn map_to_primval((res, over): (Pointer, bool)) -> (Scalar, bool) { @@ -328,7 +328,7 @@ impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, ' ptr: Scalar, pointee_ty: Ty<'tcx>, offset: i64, - ) -> EvalResult<'tcx, Scalar> { + ) -> InterpResult<'tcx, Scalar> { // FIXME: assuming here that type size is less than `i64::max_value()`. let pointee_size = self.layout_of(pointee_ty)?.size.bytes() as i64; let offset = offset diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index dee4ca33c25d3..bd81584790193 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -9,7 +9,7 @@ use rustc::hir::{MutMutable, MutImmutable}; use rustc::mir::RetagKind; use crate::{ - EvalResult, InterpError, MiriEvalContext, HelpersEvalContextExt, Evaluator, MutValueVisitor, + InterpResult, InterpError, MiriEvalContext, HelpersEvalContextExt, Evaluator, MutValueVisitor, MemoryKind, MiriMemoryKind, RangeMap, Allocation, AllocationExtra, AllocId, CheckInAllocMsg, Pointer, Immediate, ImmTy, PlaceTy, MPlaceTy, }; @@ -266,7 +266,7 @@ impl<'tcx> Stack { } /// Check if the given item is protected. - fn check_protector(item: &Item, tag: Option, global: &GlobalState) -> EvalResult<'tcx> { + fn check_protector(item: &Item, tag: Option, global: &GlobalState) -> InterpResult<'tcx> { if let Some(call) = item.protector { if global.is_active(call) { if let Some(tag) = tag { @@ -291,7 +291,7 @@ impl<'tcx> Stack { access: AccessKind, tag: Tag, global: &GlobalState, - ) -> EvalResult<'tcx> { + ) -> InterpResult<'tcx> { // Two main steps: Find granting item, remove incompatible items above. // Step 1: Find granting item. @@ -340,7 +340,7 @@ impl<'tcx> Stack { &mut self, tag: Tag, global: &GlobalState, - ) -> EvalResult<'tcx> { + ) -> InterpResult<'tcx> { // Step 1: Find granting item. self.find_granting(AccessKind::Write, tag) .ok_or_else(|| InterpError::MachineError(format!( @@ -365,7 +365,7 @@ impl<'tcx> Stack { derived_from: Tag, new: Item, global: &GlobalState, - ) -> EvalResult<'tcx> { + ) -> InterpResult<'tcx> { // Figure out which access `perm` corresponds to. let access = if new.perm.grants(AccessKind::Write) { AccessKind::Write @@ -440,8 +440,8 @@ impl<'tcx> Stacks { &self, ptr: Pointer, size: Size, - f: impl Fn(&mut Stack, &GlobalState) -> EvalResult<'tcx>, - ) -> EvalResult<'tcx> { + f: impl Fn(&mut Stack, &GlobalState) -> InterpResult<'tcx>, + ) -> InterpResult<'tcx> { let global = self.global.borrow(); let mut stacks = self.stacks.borrow_mut(); for stack in stacks.iter_mut(ptr.offset, size) { @@ -483,7 +483,7 @@ impl AllocationExtra for Stacks { alloc: &Allocation, ptr: Pointer, size: Size, - ) -> EvalResult<'tcx> { + ) -> InterpResult<'tcx> { trace!("read access with tag {:?}: {:?}, size {}", ptr.tag, ptr.erase_tag(), size.bytes()); alloc.extra.for_each(ptr, size, |stack, global| { stack.access(AccessKind::Read, ptr.tag, global)?; @@ -496,7 +496,7 @@ impl AllocationExtra for Stacks { alloc: &mut Allocation, ptr: Pointer, size: Size, - ) -> EvalResult<'tcx> { + ) -> InterpResult<'tcx> { trace!("write access with tag {:?}: {:?}, size {}", ptr.tag, ptr.erase_tag(), size.bytes()); alloc.extra.for_each(ptr, size, |stack, global| { stack.access(AccessKind::Write, ptr.tag, global)?; @@ -509,7 +509,7 @@ impl AllocationExtra for Stacks { alloc: &mut Allocation, ptr: Pointer, size: Size, - ) -> EvalResult<'tcx> { + ) -> InterpResult<'tcx> { trace!("deallocation with tag {:?}: {:?}, size {}", ptr.tag, ptr.erase_tag(), size.bytes()); alloc.extra.for_each(ptr, size, |stack, global| { stack.dealloc(ptr.tag, global) @@ -528,7 +528,7 @@ trait EvalContextPrivExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, kind: RefKind, new_tag: Tag, protect: bool, - ) -> EvalResult<'tcx> { + ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let protector = if protect { Some(this.frame().extra) } else { None }; let ptr = place.ptr.to_ptr()?; @@ -572,7 +572,7 @@ trait EvalContextPrivExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, val: ImmTy<'tcx, Tag>, kind: RefKind, protect: bool, - ) -> EvalResult<'tcx, Immediate> { + ) -> InterpResult<'tcx, Immediate> { let this = self.eval_context_mut(); // We want a place for where the ptr *points to*, so we get one. let place = this.ref_to_mplace(val)?; @@ -605,7 +605,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, &mut self, kind: RetagKind, place: PlaceTy<'tcx, Tag> - ) -> EvalResult<'tcx> { + ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); // Determine mutability and whether to add a protector. // Cannot use `builtin_deref` because that reports *immutable* for `Box`, @@ -660,7 +660,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, } // Primitives of reference type, that is the one thing we are interested in. - fn visit_primitive(&mut self, place: MPlaceTy<'tcx, Tag>) -> EvalResult<'tcx> + fn visit_primitive(&mut self, place: MPlaceTy<'tcx, Tag>) -> InterpResult<'tcx> { // Cannot use `builtin_deref` because that reports *immutable* for `Box`, // making it useless. diff --git a/src/tls.rs b/src/tls.rs index 9346fba0dcc4b..b38b15c3e18e4 100644 --- a/src/tls.rs +++ b/src/tls.rs @@ -4,7 +4,7 @@ use rustc_target::abi::LayoutOf; use rustc::{ty, ty::layout::HasDataLayout, mir}; use crate::{ - EvalResult, InterpError, StackPopCleanup, + InterpResult, InterpError, StackPopCleanup, MPlaceTy, Scalar, Tag, }; @@ -53,7 +53,7 @@ impl<'tcx> TlsData<'tcx> { new_key } - pub fn delete_tls_key(&mut self, key: TlsKey) -> EvalResult<'tcx> { + pub fn delete_tls_key(&mut self, key: TlsKey) -> InterpResult<'tcx> { match self.keys.remove(&key) { Some(_) => { trace!("TLS key {} removed", key); @@ -63,7 +63,7 @@ impl<'tcx> TlsData<'tcx> { } } - pub fn load_tls(&mut self, key: TlsKey) -> EvalResult<'tcx, Scalar> { + pub fn load_tls(&mut self, key: TlsKey) -> InterpResult<'tcx, Scalar> { match self.keys.get(&key) { Some(&TlsEntry { data, .. }) => { trace!("TLS key {} loaded: {:?}", key, data); @@ -73,7 +73,7 @@ impl<'tcx> TlsData<'tcx> { } } - pub fn store_tls(&mut self, key: TlsKey, new_data: Scalar) -> EvalResult<'tcx> { + pub fn store_tls(&mut self, key: TlsKey, new_data: Scalar) -> InterpResult<'tcx> { match self.keys.get_mut(&key) { Some(&mut TlsEntry { ref mut data, .. }) => { trace!("TLS key {} stored: {:?}", key, new_data); @@ -131,7 +131,7 @@ impl<'tcx> TlsData<'tcx> { impl<'a, 'mir, 'tcx> EvalContextExt<'a, 'mir, 'tcx> for crate::MiriEvalContext<'a, 'mir, 'tcx> {} pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, 'mir, 'tcx> { - fn run_tls_dtors(&mut self) -> EvalResult<'tcx> { + fn run_tls_dtors(&mut self) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let mut dtor = this.machine.tls.fetch_tls_dtor(None, &*this.tcx); // FIXME: replace loop by some structure that works with stepping From 09f30cabf0bb01131080032ae9858c065b64ac8b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 9 Jun 2019 13:48:18 +0200 Subject: [PATCH 0797/3747] cargo miri: make sure we see the same sysroot for rustc and miri --- src/bin/cargo-miri.rs | 38 +++++++++++++++++++++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 55c53e7361a51..5e3a35917b24a 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -119,6 +119,39 @@ fn list_targets() -> impl Iterator { package.targets.into_iter() } +/// Make sure that the `miri` and `rustc` binary are from the same sysroot. +/// This can be violated e.g. when miri is locally built and installed with a different +/// toolchain than what is used when `cargo miri` is run. +fn test_sysroot_consistency() { + fn get_sysroot(mut cmd: Command) -> PathBuf { + let out = cmd.arg("--print").arg("sysroot") + .env_remove("MIRI_SYSROOT") // We want to test their "native" sysroot, not the manually set one + .output().expect("Failed to run rustc to get sysroot info"); + assert!(out.status.success(), "Bad statuc code when getting sysroot info"); + let sysroot = out.stdout.lines().nth(0) + .expect("didn't get at least one line for the sysroot").unwrap(); + PathBuf::from(sysroot).canonicalize() + .expect("Failed to canonicalize sysroot") + } + + let rustc_sysroot = get_sysroot(Command::new("rustc")); + let miri_sysroot = { + let mut path = std::env::current_exe().expect("current executable path invalid"); + path.set_file_name("miri"); + get_sysroot(Command::new(path)) + }; + + if rustc_sysroot != miri_sysroot { + show_error(format!( + "miri was built for a different sysroot than the rustc in your current toolchain.\n\ + Make sure you use the same toolchain to run miri that you used to build it!\n\ + rustc sysroot: `{}`\n\ + miri sysroot: `{}`", + rustc_sysroot.display(), miri_sysroot.display() + )); + } +} + fn xargo_version() -> Option<(u32, u32, u32)> { let out = Command::new("xargo").arg("--version").output().ok()?; if !out.status.success() { @@ -269,7 +302,7 @@ path = "lib.rs" if print_env { println!("MIRI_SYSROOT={}", sysroot.display()); } else if !ask_user { - println!("A libstd for Miri is now available in `{}`", sysroot.display()); + println!("A libstd for Miri is now available in `{}`.", sysroot.display()); } } @@ -313,6 +346,9 @@ fn in_cargo_miri() { }; let verbose = has_arg_flag("-v"); + // Some basic sanity checks + test_sysroot_consistency(); + // We always setup. let ask = subcommand != MiriCommand::Setup; setup(ask); From 05b7e61977a0f7cc1b4bddab0275b5cc7deae660 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 9 Jun 2019 14:10:42 +0200 Subject: [PATCH 0798/3747] remove outdated sysroot management --- src/bin/cargo-miri.rs | 35 +++++------------------------------ 1 file changed, 5 insertions(+), 30 deletions(-) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 5e3a35917b24a..ae9b2efa67500 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -421,38 +421,13 @@ fn in_cargo_miri() { } fn inside_cargo_rustc() { - let home = option_env!("RUSTUP_HOME").or(option_env!("MULTIRUST_HOME")); - let toolchain = option_env!("RUSTUP_TOOLCHAIN").or(option_env!("MULTIRUST_TOOLCHAIN")); - let sys_root = if let Ok(sysroot) = ::std::env::var("MIRI_SYSROOT") { - sysroot - } else if let (Some(home), Some(toolchain)) = (home, toolchain) { - format!("{}/toolchains/{}", home, toolchain) - } else { - option_env!("RUST_SYSROOT") - .map(|s| s.to_owned()) - .or_else(|| { - Command::new("rustc") - .arg("--print") - .arg("sysroot") - .output() - .ok() - .and_then(|out| String::from_utf8(out.stdout).ok()) - .map(|s| s.trim().to_owned()) - }) - .expect("need to specify `RUST_SYSROOT` env var during miri compilation, or use rustup or multirust") - }; + let sysroot = std::env::var("MIRI_SYSROOT").expect("The wrapper should have set MIRI_SYSROOT"); - // This conditional check for the `--sysroot` flag is there so that users can call `cargo-miri` - // directly without having to pass `--sysroot` or anything. - let rustc_args = std::env::args().skip(2); - let mut args: Vec = if std::env::args().any(|s| s == "--sysroot") { - rustc_args.collect() - } else { - rustc_args + let rustc_args = std::env::args().skip(2); // skip `cargo rustc` + let mut args: Vec = rustc_args .chain(Some("--sysroot".to_owned())) - .chain(Some(sys_root)) - .collect() - }; + .chain(Some(sysroot)) + .collect(); args.splice(0..0, miri::miri_default_args().iter().map(ToString::to_string)); // See if we can find the `cargo-miri` markers. Those only get added to the binary we want to From 619f29646379dd9d3001804f4d73993f7099ab91 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 9 Jun 2019 14:31:05 +0200 Subject: [PATCH 0799/3747] explain why we always set a sysroot; make sure we error if both MIRI_SYSROOT and --sysroot are set --- src/bin/miri.rs | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 31ed5f2ccd538..660f1bec2d624 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -100,11 +100,7 @@ fn init_late_loggers() { } } -fn find_sysroot() -> String { - if let Ok(sysroot) = std::env::var("MIRI_SYSROOT") { - return sysroot; - } - +fn compile_time_sysroot() -> String { // Taken from PR . let home = option_env!("RUSTUP_HOME").or(option_env!("MULTIRUST_HOME")); let toolchain = option_env!("RUSTUP_TOOLCHAIN").or(option_env!("MULTIRUST_TOOLCHAIN")); @@ -167,12 +163,22 @@ fn main() { } } - // Determine sysroot and let rustc know about it. - let sysroot_flag = String::from("--sysroot"); - if !rustc_args.contains(&sysroot_flag) { + // Determine sysroot. + let sysroot_flag = "--sysroot".to_string(); + if let Ok(sysroot) = std::env::var("MIRI_SYSROOT") { + // MIRI_SYSROOT takes priority. rustc will ensure for us that this errors if there + // already is a "--sysroot" flag (because now there would be two). + rustc_args.push(sysroot_flag); + rustc_args.push(sysroot); + } else if !rustc_args.contains(&sysroot_flag) { + // We need to *always* set a --sysroot, as the "default" rustc uses is + // somewhere in the directory miri was built in. + // If neither MIRI_SYSROOT nor --sysroot are given, fall back to env + // vars that are read at *compile-time*. rustc_args.push(sysroot_flag); - rustc_args.push(find_sysroot()); + rustc_args.push(compile_time_sysroot()); } + // Finally, add the default flags all the way in the beginning, but after the binary name. rustc_args.splice(1..1, miri::miri_default_args().iter().map(ToString::to_string)); From 244011a47f1f6318d120035c1a3b6eb121bd95f1 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 9 Jun 2019 15:43:22 +0200 Subject: [PATCH 0800/3747] don't have both MIRI_SYSROOT and --sysroot --- src/bin/cargo-miri.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index ae9b2efa67500..53b849a1a70c2 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -458,6 +458,7 @@ fn inside_cargo_rustc() { } else { Command::new("rustc") }; + command.env_remove("MIRI_SYSROOT"); // we already set the --sysroot flag command.args(&args); if has_arg_flag("-v") { eprintln!("+ {:?}", command); From b0b082d4d896348bf6cee0df70ff933f7619c0e9 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 9 Jun 2019 17:10:04 +0200 Subject: [PATCH 0801/3747] do not handle MIRI_SYSROOT in the driver at all, rely fully on the --sysroot flag --- README.md | 9 ++++++--- miri | 2 +- src/bin/cargo-miri.rs | 10 ++++------ src/bin/miri.rs | 7 +------ tests/compiletest.rs | 31 +++++++++++++++---------------- 5 files changed, 27 insertions(+), 32 deletions(-) diff --git a/README.md b/README.md index 130072825e1cf..090694128e3ae 100644 --- a/README.md +++ b/README.md @@ -250,9 +250,12 @@ Several `-Z` flags are relevant for Miri: Moreover, Miri recognizes some environment variables: -* `MIRI_SYSROOT` (recognized by `miri`, `cargo miri` and the test suite) - indicates the sysroot to use. -* `MIRI_TARGET` (recognized by the test suite) indicates which target +* `MIRI_LOG`, `MIRI_BACKTRACE` control logging and backtrace printing during + Miri executions, also [see above][testing-miri]. +* `MIRI_SYSROOT` (recognized by `cargo miri` and the test suite) + indicates the sysroot to use. To do the same thing with `miri` + directly, use the `--sysroot` flag. +* `MIRI_TEST_TARGET` (recognized by the test suite) indicates which target architecture to test against. `miri` and `cargo miri` accept the `--target` flag for the same purpose. diff --git a/miri b/miri index 2181403b7bde9..bb6441bd97f93 100755 --- a/miri +++ b/miri @@ -140,7 +140,7 @@ run|run-debug) cargo build $CARGO_BUILD_FLAGS find_sysroot # Then run the actual command. - exec cargo run $CARGO_BUILD_FLAGS "$@" + exec cargo run $CARGO_BUILD_FLAGS -- --sysroot "$MIRI_SYSROOT" "$@" ;; *) echo "Unknown command: $COMMAND" diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 53b849a1a70c2..db53ca6ce7c1f 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -125,7 +125,6 @@ fn list_targets() -> impl Iterator { fn test_sysroot_consistency() { fn get_sysroot(mut cmd: Command) -> PathBuf { let out = cmd.arg("--print").arg("sysroot") - .env_remove("MIRI_SYSROOT") // We want to test their "native" sysroot, not the manually set one .output().expect("Failed to run rustc to get sysroot info"); assert!(out.status.success(), "Bad statuc code when getting sysroot info"); let sysroot = out.stdout.lines().nth(0) @@ -298,7 +297,7 @@ path = "lib.rs" Some(target) => target == rustc_version::version_meta().unwrap().host, }; let sysroot = if is_host { dir.join("HOST") } else { PathBuf::from(dir) }; - std::env::set_var("MIRI_SYSROOT", &sysroot); + std::env::set_var("MIRI_SYSROOT", &sysroot); // pass the env var to the processes we spawn, which will turn it into "--sysroot" flags if print_env { println!("MIRI_SYSROOT={}", sysroot.display()); } else if !ask_user { @@ -425,9 +424,9 @@ fn inside_cargo_rustc() { let rustc_args = std::env::args().skip(2); // skip `cargo rustc` let mut args: Vec = rustc_args - .chain(Some("--sysroot".to_owned())) - .chain(Some(sysroot)) - .collect(); + .chain(Some("--sysroot".to_owned())) + .chain(Some(sysroot)) + .collect(); args.splice(0..0, miri::miri_default_args().iter().map(ToString::to_string)); // See if we can find the `cargo-miri` markers. Those only get added to the binary we want to @@ -458,7 +457,6 @@ fn inside_cargo_rustc() { } else { Command::new("rustc") }; - command.env_remove("MIRI_SYSROOT"); // we already set the --sysroot flag command.args(&args); if has_arg_flag("-v") { eprintln!("+ {:?}", command); diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 660f1bec2d624..60f4751db8d24 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -165,12 +165,7 @@ fn main() { // Determine sysroot. let sysroot_flag = "--sysroot".to_string(); - if let Ok(sysroot) = std::env::var("MIRI_SYSROOT") { - // MIRI_SYSROOT takes priority. rustc will ensure for us that this errors if there - // already is a "--sysroot" flag (because now there would be two). - rustc_args.push(sysroot_flag); - rustc_args.push(sysroot); - } else if !rustc_args.contains(&sysroot_flag) { + if !rustc_args.contains(&sysroot_flag) { // We need to *always* set a --sysroot, as the "default" rustc uses is // somewhere in the directory miri was built in. // If neither MIRI_SYSROOT nor --sysroot are given, fall back to env diff --git a/tests/compiletest.rs b/tests/compiletest.rs index 7f2c8966472fb..d59be08c8e003 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -25,7 +25,15 @@ fn rustc_lib_path() -> PathBuf { option_env!("RUSTC_LIB_PATH").unwrap().into() } -fn mk_config(mode: &str) -> compiletest::common::ConfigWithTemp { +fn run_tests(mode: &str, path: &str, target: &str, mut flags: Vec) { + // Some flags we always want. + flags.push("-Dwarnings -Dunused".to_owned()); // overwrite the -Aunused in compiletest-rs + flags.push("--edition 2018".to_owned()); + if let Ok(sysroot) = std::env::var("MIRI_SYSROOT") { + flags.push(format!("--sysroot {}", sysroot)); + } + + // The rest of the configuration. let mut config = compiletest::Config::default().tempdir(); config.mode = mode.parse().expect("Invalid mode"); config.rustc_path = miri_path(); @@ -35,7 +43,10 @@ fn mk_config(mode: &str) -> compiletest::common::ConfigWithTemp { } config.filter = env::args().nth(1); config.host = get_host(); - config + config.src_base = PathBuf::from(path); + config.target = target.to_owned(); + config.target_rustcflags = Some(flags.join(" ")); + compiletest::run_tests(&config); } fn compile_fail(path: &str, target: &str, opt: bool) { @@ -48,8 +59,6 @@ fn compile_fail(path: &str, target: &str, opt: bool) { ).green().bold()); let mut flags = Vec::new(); - flags.push("-Dwarnings -Dunused".to_owned()); // overwrite the -Aunused in compiletest-rs - flags.push("--edition 2018".to_owned()); if opt { // Optimizing too aggressivley makes UB detection harder, but test at least // the default value. @@ -57,11 +66,7 @@ fn compile_fail(path: &str, target: &str, opt: bool) { flags.push("-Zmir-opt-level=1".to_owned()); } - let mut config = mk_config("compile-fail"); - config.src_base = PathBuf::from(path); - config.target = target.to_owned(); - config.target_rustcflags = Some(flags.join(" ")); - compiletest::run_tests(&config); + run_tests("compile-fail", path, target, flags); } fn miri_pass(path: &str, target: &str, opt: bool) { @@ -74,17 +79,11 @@ fn miri_pass(path: &str, target: &str, opt: bool) { ).green().bold()); let mut flags = Vec::new(); - flags.push("-Dwarnings -Dunused".to_owned()); // overwrite the -Aunused in compiletest-rs - flags.push("--edition 2018".to_owned()); if opt { flags.push("-Zmir-opt-level=3".to_owned()); } - let mut config = mk_config("ui"); - config.src_base = PathBuf::from(path); - config.target = target.to_owned(); - config.target_rustcflags = Some(flags.join(" ")); - compiletest::run_tests(&config); + run_tests("ui", path, target, flags); } fn get_host() -> String { From 5b91ecc066726527f439a983a4a75c852c631737 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 9 Jun 2019 17:12:41 +0200 Subject: [PATCH 0802/3747] fix comments --- src/bin/miri.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 60f4751db8d24..6346b2340b087 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -100,6 +100,8 @@ fn init_late_loggers() { } } +/// Returns the "default sysroot" that Miri will use if no `--sysroot` flag is set. +/// Should be a compile-time constant. fn compile_time_sysroot() -> String { // Taken from PR . let home = option_env!("RUSTUP_HOME").or(option_env!("MULTIRUST_HOME")); @@ -168,8 +170,7 @@ fn main() { if !rustc_args.contains(&sysroot_flag) { // We need to *always* set a --sysroot, as the "default" rustc uses is // somewhere in the directory miri was built in. - // If neither MIRI_SYSROOT nor --sysroot are given, fall back to env - // vars that are read at *compile-time*. + // If no --sysroot is given, fall back to env vars that are read at *compile-time*. rustc_args.push(sysroot_flag); rustc_args.push(compile_time_sysroot()); } From 3b7ae049eeb559b372ff16f0b4213ac21f72309e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 9 Jun 2019 19:41:58 +0200 Subject: [PATCH 0803/3747] make sure that find_sysroot always sets MIRI_SYSROOT --- miri | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/miri b/miri index bb6441bd97f93..89df4f2054478 100755 --- a/miri +++ b/miri @@ -55,7 +55,6 @@ build_sysroot() { cargo run $CARGO_BUILD_FLAGS --bin cargo-miri -- miri setup "$@" # Call again, to just set env var. eval $(cargo run $CARGO_BUILD_FLAGS -q --bin cargo-miri -- miri setup --env "$@") - export MIRI_SYSROOT } # Prepare and set MIRI_SYSROOT. Respects `MIRI_TEST_TARGET` and takes into account @@ -73,7 +72,7 @@ find_sysroot() { build_sysroot --target "$MIRI_TEST_TARGET" else # Assume we have a proper host libstd in $SYSROOT. - true + MIRI_SYSROOT="$SYSROOT" fi else # A normal toolchain. We have to build a sysroot either way. @@ -83,6 +82,7 @@ find_sysroot() { build_sysroot fi fi + export MIRI_SYSROOT } ## Main From 0a9f9e0a0bc4d2aab22c3d40309208b233bef1ed Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 9 Jun 2019 19:47:09 +0200 Subject: [PATCH 0804/3747] factor out common code to determine miri binary --- src/bin/cargo-miri.rs | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index db53ca6ce7c1f..121930bccce6d 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -119,6 +119,13 @@ fn list_targets() -> impl Iterator { package.targets.into_iter() } +/// Returns the path to the `miri` binary +fn find_miri() -> PathBuf { + let mut path = std::env::current_exe().expect("current executable path invalid"); + path.set_file_name("miri"); + path +} + /// Make sure that the `miri` and `rustc` binary are from the same sysroot. /// This can be violated e.g. when miri is locally built and installed with a different /// toolchain than what is used when `cargo miri` is run. @@ -126,7 +133,7 @@ fn test_sysroot_consistency() { fn get_sysroot(mut cmd: Command) -> PathBuf { let out = cmd.arg("--print").arg("sysroot") .output().expect("Failed to run rustc to get sysroot info"); - assert!(out.status.success(), "Bad statuc code when getting sysroot info"); + assert!(out.status.success(), "Bad status code when getting sysroot info"); let sysroot = out.stdout.lines().nth(0) .expect("didn't get at least one line for the sysroot").unwrap(); PathBuf::from(sysroot).canonicalize() @@ -134,11 +141,7 @@ fn test_sysroot_consistency() { } let rustc_sysroot = get_sysroot(Command::new("rustc")); - let miri_sysroot = { - let mut path = std::env::current_exe().expect("current executable path invalid"); - path.set_file_name("miri"); - get_sysroot(Command::new(path)) - }; + let miri_sysroot = get_sysroot(Command::new(find_miri())); if rustc_sysroot != miri_sysroot { show_error(format!( @@ -451,9 +454,7 @@ fn inside_cargo_rustc() { }; let mut command = if needs_miri { - let mut path = std::env::current_exe().expect("current executable path invalid"); - path.set_file_name("miri"); - Command::new(path) + Command::new(find_miri()) } else { Command::new("rustc") }; From 446478cce2219b48114f54ca424321f67cdd428e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 10 Jun 2019 13:01:55 +0200 Subject: [PATCH 0805/3747] fix for rustc rename mir -> body --- rust-version | 2 +- src/fn_call.rs | 2 +- src/lib.rs | 6 +++--- src/tls.rs | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/rust-version b/rust-version index 3e7048ac72cc5..b72e1f53ef1ff 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -5c45343f11fbf93cf4e15568aee3ff3f2f287466 +1cbd8a4d686d1411105f26cddf876c5994e69593 diff --git a/src/fn_call.rs b/src/fn_call.rs index 5397c048f9f46..e9377d89bcacd 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -361,7 +361,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' // Directly return to caller. StackPopCleanup::Goto(Some(ret)), )?; - let mut args = this.frame().mir.args_iter(); + let mut args = this.frame().body.args_iter(); let arg_local = args.next().ok_or_else(|| InterpError::AbiViolation( diff --git a/src/lib.rs b/src/lib.rs index 8577bc4714e5f..d0b7111bb0691 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -125,7 +125,7 @@ pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( StackPopCleanup::None { cleanup: true }, )?; - let mut args = ecx.frame().mir.args_iter(); + let mut args = ecx.frame().body.args_iter(); // First argument: pointer to `main()`. let main_ptr = ecx.memory_mut().create_fn_alloc(main_instance); @@ -252,7 +252,7 @@ pub fn eval_main<'a, 'tcx: 'a>( }; e.print_backtrace(); if let Some(frame) = ecx.stack().last() { - let block = &frame.mir.basic_blocks()[frame.block]; + let block = &frame.body.basic_blocks()[frame.block]; let span = if frame.stmt < block.statements.len() { block.statements[frame.stmt].source_info.span } else { @@ -451,7 +451,7 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { StackPopCleanup::None { cleanup: true }, )?; - let mut args = ecx.frame().mir.args_iter(); + let mut args = ecx.frame().body.args_iter(); let layout = ecx.layout_of(dest.layout.ty.builtin_deref(false).unwrap().ty)?; // First argument: `size`. diff --git a/src/tls.rs b/src/tls.rs index b38b15c3e18e4..4101a3ab39b7b 100644 --- a/src/tls.rs +++ b/src/tls.rs @@ -148,7 +148,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, Some(ret_place), StackPopCleanup::None { cleanup: true }, )?; - let arg_local = this.frame().mir.args_iter().next().ok_or_else( + let arg_local = this.frame().body.args_iter().next().ok_or_else( || InterpError::AbiViolation("TLS dtor does not take enough arguments.".to_owned()), )?; let dest = this.eval_place(&mir::Place::Base(mir::PlaceBase::Local(arg_local)))?; From 6eab94a459a16a4da0c6e18583bf70ee8c42cb1f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 9 Jun 2019 00:12:57 +0200 Subject: [PATCH 0806/3747] fix from to/from f32/f64 changes --- src/fn_call.rs | 4 ++-- src/intrinsic.rs | 40 ++++++++++++++++++++++++---------------- 2 files changed, 26 insertions(+), 18 deletions(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index e9377d89bcacd..3d2c523bf705a 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -758,7 +758,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' this.machine.last_error = err; } "GetLastError" => { - this.write_scalar(Scalar::from_uint(this.machine.last_error, Size::from_bits(32)), dest)?; + this.write_scalar(Scalar::from_u32(this.machine.last_error), dest)?; } "AddVectoredExceptionHandler" => { @@ -854,7 +854,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' }; // If there was no error, write back how much was written. if let Some(n) = written { - this.write_scalar(Scalar::from_uint(n, Size::from_bits(32)), written_place.into())?; + this.write_scalar(Scalar::from_u32(n), written_place.into())?; } // Return whether this was a success. this.write_scalar( diff --git a/src/intrinsic.rs b/src/intrinsic.rs index 822265bc2112d..faaa15d3ba965 100644 --- a/src/intrinsic.rs +++ b/src/intrinsic.rs @@ -186,7 +186,8 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, "sinf32" | "fabsf32" | "cosf32" | "sqrtf32" | "expf32" | "exp2f32" | "logf32" | "log10f32" | "log2f32" | "floorf32" | "ceilf32" | "truncf32" => { - let f = this.read_scalar(args[0])?.to_f32()?; + // FIXME: Using host floats. + let f = f32::from_bits(this.read_scalar(args[0])?.to_u32()?); let f = match intrinsic_name.get() { "sinf32" => f.sin(), "fabsf32" => f.abs(), @@ -202,12 +203,13 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, "truncf32" => f.trunc(), _ => bug!(), }; - this.write_scalar(Scalar::from_f32(f), dest)?; + this.write_scalar(Scalar::from_u32(f.to_bits()), dest)?; } "sinf64" | "fabsf64" | "cosf64" | "sqrtf64" | "expf64" | "exp2f64" | "logf64" | "log10f64" | "log2f64" | "floorf64" | "ceilf64" | "truncf64" => { - let f = this.read_scalar(args[0])?.to_f64()?; + // FIXME: Using host floats. + let f = f64::from_bits(this.read_scalar(args[0])?.to_u64()?); let f = match intrinsic_name.get() { "sinf64" => f.sin(), "fabsf64" => f.abs(), @@ -223,7 +225,7 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, "truncf64" => f.trunc(), _ => bug!(), }; - this.write_scalar(Scalar::from_f64(f), dest)?; + this.write_scalar(Scalar::from_u64(f.to_bits()), dest)?; } "fadd_fast" | "fsub_fast" | "fmul_fast" | "fdiv_fast" | "frem_fast" => { @@ -320,19 +322,21 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, } "powf32" => { - let f = this.read_scalar(args[0])?.to_f32()?; - let f2 = this.read_scalar(args[1])?.to_f32()?; + // FIXME: Using host floats. + let f = f32::from_bits(this.read_scalar(args[0])?.to_u32()?); + let f2 = f32::from_bits(this.read_scalar(args[1])?.to_u32()?); this.write_scalar( - Scalar::from_f32(f.powf(f2)), + Scalar::from_u32(f.powf(f2).to_bits()), dest, )?; } "powf64" => { - let f = this.read_scalar(args[0])?.to_f64()?; - let f2 = this.read_scalar(args[1])?.to_f64()?; + // FIXME: Using host floats. + let f = f64::from_bits(this.read_scalar(args[0])?.to_u64()?); + let f2 = f64::from_bits(this.read_scalar(args[1])?.to_u64()?); this.write_scalar( - Scalar::from_f64(f.powf(f2)), + Scalar::from_u64(f.powf(f2).to_bits()), dest, )?; } @@ -341,8 +345,9 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, let a = this.read_scalar(args[0])?.to_f32()?; let b = this.read_scalar(args[1])?.to_f32()?; let c = this.read_scalar(args[2])?.to_f32()?; + let res = (a*b).value + c; this.write_scalar( - Scalar::from_f32(a * b + c), + Scalar::from_f32(res.value), dest, )?; } @@ -351,26 +356,29 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, let a = this.read_scalar(args[0])?.to_f64()?; let b = this.read_scalar(args[1])?.to_f64()?; let c = this.read_scalar(args[2])?.to_f64()?; + let res = (a*b).value + c; this.write_scalar( - Scalar::from_f64(a * b + c), + Scalar::from_f64(res.value), dest, )?; } "powif32" => { - let f = this.read_scalar(args[0])?.to_f32()?; + // FIXME: Using host floats. + let f = f32::from_bits(this.read_scalar(args[0])?.to_u32()?); let i = this.read_scalar(args[1])?.to_i32()?; this.write_scalar( - Scalar::from_f32(f.powi(i)), + Scalar::from_u32(f.powi(i).to_bits()), dest, )?; } "powif64" => { - let f = this.read_scalar(args[0])?.to_f64()?; + // FIXME: Using host floats. + let f = f64::from_bits(this.read_scalar(args[0])?.to_u64()?); let i = this.read_scalar(args[1])?.to_i32()?; this.write_scalar( - Scalar::from_f64(f.powi(i)), + Scalar::from_u64(f.powi(i).to_bits()), dest, )?; } From 5e07ac335fe75aafd34394ff95bb2f153c11c967 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 9 Jun 2019 00:19:05 +0200 Subject: [PATCH 0807/3747] implement min and max floating point intrinsics --- src/intrinsic.rs | 23 +++++++++++++++++++++++ src/lib.rs | 4 ++-- tests/run-pass/floats.rs | 15 ++++++++++++++- 3 files changed, 39 insertions(+), 3 deletions(-) diff --git a/src/intrinsic.rs b/src/intrinsic.rs index faaa15d3ba965..a28c99db6bfa6 100644 --- a/src/intrinsic.rs +++ b/src/intrinsic.rs @@ -1,3 +1,4 @@ +use rustc_apfloat::Float; use rustc::mir; use rustc::mir::interpret::{InterpResult, PointerArithmetic}; use rustc::ty::layout::{self, LayoutOf, Size}; @@ -242,6 +243,28 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, this.binop_ignore_overflow(op, a, b, dest)?; } + "minnumf32" | "maxnumf32" => { + let a = this.read_scalar(args[0])?.to_f32()?; + let b = this.read_scalar(args[1])?.to_f32()?; + let res = if intrinsic_name.get().starts_with("min") { + a.min(b) + } else { + a.max(b) + }; + this.write_scalar(Scalar::from_f32(res), dest)?; + } + + "minnumf64" | "maxnumf64" => { + let a = this.read_scalar(args[0])?.to_f64()?; + let b = this.read_scalar(args[1])?.to_f64()?; + let res = if intrinsic_name.get().starts_with("min") { + a.min(b) + } else { + a.max(b) + }; + this.write_scalar(Scalar::from_f64(res), dest)?; + } + "exact_div" => { // Performs an exact division, resulting in undefined behavior where // `x % y != 0` or `y == 0` or `x == T::min_value() && y == -1` diff --git a/src/lib.rs b/src/lib.rs index d0b7111bb0691..d2b20db06d3ce 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -6,8 +6,8 @@ extern crate log; // From rustc. extern crate syntax; -#[macro_use] -extern crate rustc; +extern crate rustc_apfloat; +#[macro_use] extern crate rustc; extern crate rustc_data_structures; extern crate rustc_mir; extern crate rustc_target; diff --git a/tests/run-pass/floats.rs b/tests/run-pass/floats.rs index 39fdbce49202e..c1588dae249a5 100644 --- a/tests/run-pass/floats.rs +++ b/tests/run-pass/floats.rs @@ -1,4 +1,3 @@ - fn main() { assert_eq!(6.0_f32*6.0_f32, 36.0_f32); assert_eq!(6.0_f64*6.0_f64, 36.0_f64); @@ -12,4 +11,18 @@ fn main() { assert_eq!(5.0f32 as u32, 5); assert_eq!(5.0f32 as i32, 5); assert_eq!(-5.0f32 as i32, -5); + + assert_eq!((1.0 as f32).max(-1.0), 1.0); + assert_eq!((1.0 as f32).min(-1.0), -1.0); + assert_eq!(std::f32::NAN.min(9.0), 9.0); + assert_eq!(std::f32::NAN.max(-9.0), -9.0); + assert_eq!((9.0 as f32).min(std::f32::NAN), 9.0); + assert_eq!((-9.0 as f32).max(std::f32::NAN), -9.0); + + assert_eq!((1.0 as f64).max(-1.0), 1.0); + assert_eq!((1.0 as f64).min(-1.0), -1.0); + assert_eq!(std::f64::NAN.min(9.0), 9.0); + assert_eq!(std::f64::NAN.max(-9.0), -9.0); + assert_eq!((9.0 as f64).min(std::f64::NAN), 9.0); + assert_eq!((-9.0 as f64).max(std::f64::NAN), -9.0); } From a37953752d325e3a08ee7db27709a9d9c170b0ff Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 10 Jun 2019 09:49:06 +0200 Subject: [PATCH 0808/3747] use apfloat's FMA primitive --- src/intrinsic.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/intrinsic.rs b/src/intrinsic.rs index a28c99db6bfa6..451a97eeed724 100644 --- a/src/intrinsic.rs +++ b/src/intrinsic.rs @@ -368,9 +368,9 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, let a = this.read_scalar(args[0])?.to_f32()?; let b = this.read_scalar(args[1])?.to_f32()?; let c = this.read_scalar(args[2])?.to_f32()?; - let res = (a*b).value + c; + let res = a.mul_add(b, c).value; this.write_scalar( - Scalar::from_f32(res.value), + Scalar::from_f32(res), dest, )?; } @@ -379,9 +379,9 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, let a = this.read_scalar(args[0])?.to_f64()?; let b = this.read_scalar(args[1])?.to_f64()?; let c = this.read_scalar(args[2])?.to_f64()?; - let res = (a*b).value + c; + let res = a.mul_add(b, c).value; this.write_scalar( - Scalar::from_f64(res.value), + Scalar::from_f64(res), dest, )?; } From 9c9a947bf4b90623a9db50c9349808b45ca2fc11 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 10 Jun 2019 09:50:47 +0200 Subject: [PATCH 0809/3747] test more enum-int-cast code paths --- tests/run-pass/c_enums.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/run-pass/c_enums.rs b/tests/run-pass/c_enums.rs index 11897b73eb2ad..16b795342eab8 100644 --- a/tests/run-pass/c_enums.rs +++ b/tests/run-pass/c_enums.rs @@ -11,11 +11,13 @@ enum Signed { } fn foo() -> [u8; 3] { - [Foo::Bar as u8, Foo::Baz as u8, Foo::Quux as u8] + let baz = Foo::Baz; // let-expansion changes the MIR significantly + [Foo::Bar as u8, baz as u8, Foo::Quux as u8] } fn signed() -> [i8; 3] { - [Signed::Bar as i8, Signed::Baz as i8, Signed::Quux as i8] + let baz = Signed::Baz; // let-expansion changes the MIR significantly + [Signed::Bar as i8, baz as i8, Signed::Quux as i8] } fn unsafe_match() -> bool { From e2f114a5e071a1785024fdaf6260b656b226a696 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 10 Jun 2019 09:57:01 +0200 Subject: [PATCH 0810/3747] test FMA a bit more --- tests/run-pass/intrinsics-math.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/run-pass/intrinsics-math.rs b/tests/run-pass/intrinsics-math.rs index a2c55634749cb..6b3d15a5091fc 100644 --- a/tests/run-pass/intrinsics-math.rs +++ b/tests/run-pass/intrinsics-math.rs @@ -50,8 +50,10 @@ pub fn main() { assert_approx_eq!(8f32.log2(), 3f32); assert_approx_eq!(f64::consts::E.log2(), f64::consts::LOG2_E); - assert_approx_eq!(1.0f32.mul_add(2.0f32, 5.0f32), 7.0f32); - assert_approx_eq!(0.0f64.mul_add(-2.0f64, f64::consts::E), f64::consts::E); + assert_approx_eq!(3.0f32.mul_add(2.0f32, 5.0f32), 11.0); + assert_eq!(0.0f32.mul_add(-2.0, f32::consts::E), f32::consts::E); + assert_approx_eq!(3.0f64.mul_add(2.0, 5.0), 11.0); + assert_eq!(0.0f64.mul_add(-2.0f64, f64::consts::E), f64::consts::E); assert_approx_eq!((-1.0f32).abs(), 1.0f32); assert_approx_eq!(34.2f64.abs(), 34.2f64); From 6a0d092eaf3150a4ae2e509744c49d5cadc60efc Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 11 Jun 2019 19:42:01 +0200 Subject: [PATCH 0811/3747] bump Rust version --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index b72e1f53ef1ff..8ef35afca0545 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -1cbd8a4d686d1411105f26cddf876c5994e69593 +8e948df707ea8a3c88c65bf2ffdcb2f1cf5491be From 8f670e6b8bb343268c87143ecc8faa19bca7dd31 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 12 Jun 2019 18:19:50 +0200 Subject: [PATCH 0812/3747] test rand a bit more --- test-cargo-miri/src/main.rs | 6 ++++-- test-cargo-miri/tests/test.rs | 6 ++++-- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/test-cargo-miri/src/main.rs b/test-cargo-miri/src/main.rs index 9ec8e85887a79..c21547c29ff9c 100644 --- a/test-cargo-miri/src/main.rs +++ b/test-cargo-miri/src/main.rs @@ -19,7 +19,9 @@ mod test { fn rng() { let mut rng = rand::rngs::StdRng::seed_from_u64(0xcafebeef); let x: u32 = rng.gen(); - let y: u32 = rng.gen(); - assert_ne!(x, y); + let y: usize = rng.gen(); + let z: u128 = rng.gen(); + assert_ne!(x as usize, y); + assert_ne!(y as u128, z); } } diff --git a/test-cargo-miri/tests/test.rs b/test-cargo-miri/tests/test.rs index ed9efa21e4fa9..31425d5ad9733 100644 --- a/test-cargo-miri/tests/test.rs +++ b/test-cargo-miri/tests/test.rs @@ -7,17 +7,19 @@ fn simple() { assert_eq!(4, 4); } -// Having more than 1 test does seem to make a difference -// (i.e., this calls ptr::swap which having just one test does not). #[test] fn entropy_rng() { // Use this opportunity to test querying the RNG (needs an external crate, hence tested here and not in the compiletest suite) let mut rng = SmallRng::from_entropy(); let _val = rng.gen::(); + let _val = rng.gen::(); + let _val = rng.gen::(); // Also try per-thread RNG. let mut rng = rand::thread_rng(); let _val = rng.gen::(); + let _val = rng.gen::(); + let _val = rng.gen::(); } // A test that won't work on miri From f72f53c3adfbcfb5977429a4b81d08c9cd327cc1 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 12 Jun 2019 18:30:05 +0200 Subject: [PATCH 0813/3747] bump rand so that the test passes --- test-cargo-miri/Cargo.lock | 181 ++++++++++++---------------------- test-cargo-miri/Cargo.toml | 2 +- test-cargo-miri/tests/test.rs | 2 +- 3 files changed, 67 insertions(+), 118 deletions(-) diff --git a/test-cargo-miri/Cargo.lock b/test-cargo-miri/Cargo.lock index 76fb04c6672aa..972b6bf074de7 100644 --- a/test-cargo-miri/Cargo.lock +++ b/test-cargo-miri/Cargo.lock @@ -2,25 +2,34 @@ # It is not intended for manual editing. [[package]] name = "autocfg" -version = "0.1.2" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "bitflags" -version = "1.0.4" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "byteorder" -version = "1.0.0" +version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "c2-chacha" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ppv-lite86 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "cargo-miri-test" version = "0.1.0" dependencies = [ - "byteorder 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.7.0-pre.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -28,7 +37,7 @@ name = "cloudabi" version = "0.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -37,138 +46,83 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] -name = "libc" -version = "0.2.48" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "rand" -version = "0.6.5" +name = "getrandom" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_jitter 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_os 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_pcg 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] -name = "rand_chacha" -version = "0.1.1" +name = "lazy_static" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", -] [[package]] -name = "rand_core" -version = "0.3.1" +name = "libc" +version = "0.2.58" source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", -] [[package]] -name = "rand_core" -version = "0.4.0" +name = "ppv-lite86" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] -name = "rand_hc" -version = "0.1.0" +name = "rand" +version = "0.7.0-pre.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "getrandom 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_chacha 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_pcg 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] -name = "rand_isaac" -version = "0.1.1" +name = "rand_chacha" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "c2-chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] -name = "rand_jitter" -version = "0.1.2" +name = "rand_core" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "getrandom 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] -name = "rand_os" -version = "0.1.2" +name = "rand_hc" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rand_pcg" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rand_xorshift" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rdrand" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rustc_version" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "semver" -version = "0.9.0" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "semver-parser" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "winapi" -version = "0.3.6" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -186,26 +140,21 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" [metadata] -"checksum autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a6d640bee2da49f60a4068a7fae53acde8982514ab7bae8b8cea9e88cbcfd799" -"checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12" -"checksum byteorder 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c40977b0ee6b9885c9013cd41d9feffdd22deb3bb4dc3a71d901cc7a77de18c8" +"checksum autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "0e49efa51329a5fd37e7c79db4621af617cd4e3e5bc224939808d076077077bf" +"checksum bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3d155346769a6855b86399e9bc3814ab343cd3d62c7e985113d46a0ec3c281fd" +"checksum byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a7c3dd8985a7111efc5c80b44e23ecdd8c007de8ade3b96595387e812b957cf5" +"checksum c2-chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7d64d04786e0f528460fc884753cf8dddcc466be308f6026f8e355c41a0e4101" "checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" "checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" -"checksum libc 0.2.48 (registry+https://github.com/rust-lang/crates.io-index)" = "e962c7641008ac010fa60a7dfdc1712449f29c44ef2d4702394aea943ee75047" -"checksum rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca" -"checksum rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef" -"checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" -"checksum rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d0e7a549d590831370895ab7ba4ea0c1b6b011d106b5ff2da6eee112615e6dc0" -"checksum rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b40677c7be09ae76218dc623efbf7b18e34bced3f38883af07bb75630a21bc4" -"checksum rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ded997c9d5f13925be2a6fd7e66bf1872597f759fd9dd93513dd7e92e5a5ee08" -"checksum rand_jitter 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "080723c6145e37503a2224f801f252e14ac5531cb450f4502698542d188cb3c0" -"checksum rand_os 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b7c690732391ae0abafced5015ffb53656abfaec61b342290e5eb56b286a679d" -"checksum rand_pcg 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "086bd09a33c7044e56bb44d5bdde5a60e7f119a9e95b0775f545de759a32fe05" -"checksum rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c" -"checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" -"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" -"checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" -"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" -"checksum winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "92c1eb33641e276cfa214a0522acad57be5c56b10cb348b3c5117db75f3ac4b0" +"checksum getrandom 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8d1dffef07351aafe6ef177e4dd2b8dcf503e6bc765dea3b0de9ed149a3db1ec" +"checksum lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bc5729f27f159ddd61f4df6228e827e86643d4d3e7c32183cb30a1c08f604a14" +"checksum libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)" = "6281b86796ba5e4366000be6e9e18bf35580adf9e63fbe2294aadb587613a319" +"checksum ppv-lite86 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e3cbf9f658cdb5000fcf6f362b8ea2ba154b9f146a61c7a20d647034c6b6561b" +"checksum rand 0.7.0-pre.1 (registry+https://github.com/rust-lang/crates.io-index)" = "866531c9bb6613da04a1e6ad99d27a7c8acd488020d7a8b177b058a10c900eec" +"checksum rand_chacha 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e193067942ef6f485a349a113329140d0ab9e2168ce92274499bb0e9a4190d9d" +"checksum rand_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "615e683324e75af5d43d8f7a39ffe3ee4a9dc42c5c701167a71dc59c3a493aca" +"checksum rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" +"checksum rand_pcg 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3e196346cbbc5c70c77e7b4926147ee8e383a38ee4d15d58a08098b169e492b6" +"checksum winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "f10e386af2b13e47c89e7236a7a14a086791a2b88ebad6df9bf42040195cf770" "checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" "checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/test-cargo-miri/Cargo.toml b/test-cargo-miri/Cargo.toml index 04f259a0aedba..607514b995f61 100644 --- a/test-cargo-miri/Cargo.toml +++ b/test-cargo-miri/Cargo.toml @@ -8,4 +8,4 @@ edition = "2018" byteorder = "1.0" [dev-dependencies] -rand = "0.6.5" +rand = { version = "0.7.0-pre.0", features = ["small_rng"] } diff --git a/test-cargo-miri/tests/test.rs b/test-cargo-miri/tests/test.rs index 31425d5ad9733..ac0db2778cae2 100644 --- a/test-cargo-miri/tests/test.rs +++ b/test-cargo-miri/tests/test.rs @@ -1,4 +1,4 @@ -use rand::{FromEntropy, Rng, rngs::SmallRng}; +use rand::{SeedableRng, Rng, rngs::SmallRng}; // Having more than 1 test does seem to make a difference // (i.e., this calls ptr::swap which having just one test does not). From 535914e3dcd65fd2bb2cbb02f505ef200169a547 Mon Sep 17 00:00:00 2001 From: Kenny Goodin Date: Wed, 5 Jun 2019 01:26:46 -0400 Subject: [PATCH 0814/3747] Implement cbrt and hypot function calls Test cases are added to `tests/run-pass/intrinsics-math.rs` --- src/fn_call.rs | 14 ++++++++++++++ tests/run-pass/intrinsics-math.rs | 3 +++ 2 files changed, 17 insertions(+) diff --git a/src/fn_call.rs b/src/fn_call.rs index 3d2c523bf705a..b6b35bfc005e1 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -560,6 +560,20 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' let n = this.memory().get(ptr.alloc_id)?.read_c_str(tcx, ptr)?.len(); this.write_scalar(Scalar::from_uint(n as u64, dest.layout.size), dest)?; } + "cbrt" => { + // FIXME: Using host floats. + let f = f64::from_bits(this.read_scalar(args[0])?.to_u64()?); + let n = f.cbrt(); + this.write_scalar(Scalar::from_u64(n.to_bits()), dest)?; + } + // underscore case for windows + "_hypot" | "hypot" => { + // FIXME: Using host floats. + let f1 = f64::from_bits(this.read_scalar(args[0])?.to_u64()?); + let f2 = f64::from_bits(this.read_scalar(args[1])?.to_u64()?); + let n = f1.hypot(f2); + this.write_scalar(Scalar::from_u64(n.to_bits()), dest)?; + } // Some things needed for `sys::thread` initialization to go through. "signal" | "sigaction" | "sigaltstack" => { diff --git a/tests/run-pass/intrinsics-math.rs b/tests/run-pass/intrinsics-math.rs index 6b3d15a5091fc..504ef47897953 100644 --- a/tests/run-pass/intrinsics-math.rs +++ b/tests/run-pass/intrinsics-math.rs @@ -66,4 +66,7 @@ pub fn main() { assert_approx_eq!(0.1f32.trunc(), 0.0f32); assert_approx_eq!((-0.1f64).trunc(), 0.0f64); + + assert_approx_eq!(27f64.cbrt(), 3.0f64); + assert_approx_eq!(3f64.hypot(4f64), 5.0f64); } From 118274f300d60d8a450cdbc16a72101efde23b12 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 13 Jun 2019 08:43:35 +0200 Subject: [PATCH 0815/3747] README: mention to cargo update, mention rustup-toolchain-install-master --- README.md | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 090694128e3ae..82fe738e03100 100644 --- a/README.md +++ b/README.md @@ -55,7 +55,11 @@ Install Miri via `rustup`: rustup component add miri ``` -If `rustup` says the `miri` component is unavailable, that's because not all nightly releases come with all tools. Check out [this website](https://rust-lang.github.io/rustup-components-history) to determine a nightly version that comes with Miri and install that, e.g. using `rustup install nightly-2019-03-28`. +If `rustup` says the `miri` component is unavailable, that's because not all +nightly releases come with all tools. Check out +[this website](https://rust-lang.github.io/rustup-components-history) to +determine a nightly version that comes with Miri and install that, e.g. using +`rustup install nightly-2019-03-28`. Now you can run your project in Miri: @@ -131,7 +135,17 @@ able to just `cargo build` Miri. In case this fails, your nightly might be incompatible with Miri master. The `rust-version` file contains the commit hash of rustc that Miri is currently tested against; you can use that to find a nightly that works or you might have -to wait for the next nightly to get released. +to wait for the next nightly to get released. You can also use +[`rustup-toolchain-install-master`](https://github.com/kennytm/rustup-toolchain-install-master) +to install that exact version of rustc as a toolchain: +``` +rustup-toolchain-install-master $(cat rust-version) -c rust-src +``` + +Another common problem is outdated dependencies: Miri does not come with a +lockfile (it cannot, due to how it gets embedded into the rustc build). So you +have to run `cargo update` every now and then yourself to make sure you are +using the latest versions of everything (which is what gets tested on CI). ### Testing the Miri driver [testing-miri]: #testing-the-miri-driver From ad0c941547e36a9f2eb4c5ef254ba0e87817b0b6 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 13 Jun 2019 08:52:04 +0200 Subject: [PATCH 0816/3747] rustup for lifetime refactorings --- rust-version | 2 +- src/bin/miri-rustc-tests.rs | 4 ++-- src/fn_call.rs | 8 +++---- src/helpers.rs | 16 ++++++------- src/intrinsic.rs | 4 ++-- src/lib.rs | 46 ++++++++++++++++++------------------- src/operator.rs | 2 +- src/stacked_borrows.rs | 20 ++++++++-------- src/tls.rs | 4 ++-- 9 files changed, 53 insertions(+), 53 deletions(-) diff --git a/rust-version b/rust-version index 8ef35afca0545..b945d0b3a2651 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -8e948df707ea8a3c88c65bf2ffdcb2f1cf5491be +d8f50ab0ea6c529c24e575279acc72093caeb679 diff --git a/src/bin/miri-rustc-tests.rs b/src/bin/miri-rustc-tests.rs index cf50f8125c4bd..e8714123ceb06 100644 --- a/src/bin/miri-rustc-tests.rs +++ b/src/bin/miri-rustc-tests.rs @@ -43,8 +43,8 @@ impl rustc_driver::Callbacks for MiriCompilerCalls { compiler.session().abort_if_errors(); compiler.global_ctxt().unwrap().peek_mut().enter(|tcx| { if std::env::args().any(|arg| arg == "--test") { - struct Visitor<'a, 'tcx: 'a>(TyCtxt<'a, 'tcx, 'tcx>); - impl<'a, 'tcx: 'a, 'hir> itemlikevisit::ItemLikeVisitor<'hir> for Visitor<'a, 'tcx> { + struct Visitor<'tcx>(TyCtxt<'tcx, 'tcx>); + impl<'tcx, 'hir> itemlikevisit::ItemLikeVisitor<'hir> for Visitor<'tcx> { fn visit_item(&mut self, i: &'hir hir::Item) { if let hir::ItemKind::Fn(.., body_id) = i.node { if i.attrs.iter().any(|attr| attr.check_name(syntax::symbol::sym::test)) { diff --git a/src/fn_call.rs b/src/fn_call.rs index b6b35bfc005e1..4c40d24f7ff58 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -9,8 +9,8 @@ use rand::RngCore; use crate::*; -impl<'a, 'mir, 'tcx> EvalContextExt<'a, 'mir, 'tcx> for crate::MiriEvalContext<'a, 'mir, 'tcx> {} -pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<'a, 'mir, 'tcx> { +impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} +pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { fn find_fn( &mut self, instance: ty::Instance<'tcx>, @@ -930,8 +930,8 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' } } -fn gen_random<'a, 'mir, 'tcx>( - this: &mut MiriEvalContext<'a, 'mir, 'tcx>, +fn gen_random<'mir, 'tcx>( + this: &mut MiriEvalContext<'mir, 'tcx>, len: usize, dest: Scalar, ) -> InterpResult<'tcx> { diff --git a/src/helpers.rs b/src/helpers.rs index 29bc1def9fda5..62a546767e895 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -5,9 +5,9 @@ use rustc::hir::def_id::{DefId, CRATE_DEF_INDEX}; use crate::*; -impl<'a, 'mir, 'tcx> EvalContextExt<'a, 'mir, 'tcx> for crate::MiriEvalContext<'a, 'mir, 'tcx> {} +impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} -pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<'a, 'mir, 'tcx> { +pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { /// Gets an instance for a path. fn resolve_path(&self, path: &[&str]) -> InterpResult<'tcx, ty::Instance<'tcx>> { let this = self.eval_context_ref(); @@ -119,24 +119,24 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a + 'mir>: crate::MiriEvalContextExt<' /// Visiting the memory covered by a `MemPlace`, being aware of /// whether we are inside an `UnsafeCell` or not. - struct UnsafeCellVisitor<'ecx, 'a, 'mir, 'tcx, F> + struct UnsafeCellVisitor<'ecx, 'mir, 'tcx, F> where F: FnMut(MPlaceTy<'tcx, Tag>) -> InterpResult<'tcx> { - ecx: &'ecx MiriEvalContext<'a, 'mir, 'tcx>, + ecx: &'ecx MiriEvalContext<'mir, 'tcx>, unsafe_cell_action: F, } - impl<'ecx, 'a, 'mir, 'tcx, F> - ValueVisitor<'a, 'mir, 'tcx, Evaluator<'tcx>> + impl<'ecx, 'mir, 'tcx, F> + ValueVisitor<'mir, 'tcx, Evaluator<'tcx>> for - UnsafeCellVisitor<'ecx, 'a, 'mir, 'tcx, F> + UnsafeCellVisitor<'ecx, 'mir, 'tcx, F> where F: FnMut(MPlaceTy<'tcx, Tag>) -> InterpResult<'tcx> { type V = MPlaceTy<'tcx, Tag>; #[inline(always)] - fn ecx(&self) -> &MiriEvalContext<'a, 'mir, 'tcx> { + fn ecx(&self) -> &MiriEvalContext<'mir, 'tcx> { &self.ecx } diff --git a/src/intrinsic.rs b/src/intrinsic.rs index 451a97eeed724..cd89055b467af 100644 --- a/src/intrinsic.rs +++ b/src/intrinsic.rs @@ -9,8 +9,8 @@ use crate::{ OperatorEvalContextExt }; -impl<'a, 'mir, 'tcx> EvalContextExt<'a, 'mir, 'tcx> for crate::MiriEvalContext<'a, 'mir, 'tcx> {} -pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, 'mir, 'tcx> { +impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} +pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { fn call_intrinsic( &mut self, instance: ty::Instance<'tcx>, diff --git a/src/lib.rs b/src/lib.rs index d2b20db06d3ce..822b173e34a01 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -71,11 +71,11 @@ pub struct MiriConfig { } // Used by priroda. -pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( - tcx: TyCtxt<'a, 'tcx, 'tcx>, +pub fn create_ecx<'mir, 'tcx: 'mir>( + tcx: TyCtxt<'tcx, 'tcx>, main_id: DefId, config: MiriConfig, -) -> InterpResult<'tcx, InterpretCx<'a, 'mir, 'tcx, Evaluator<'tcx>>> { +) -> InterpResult<'tcx, InterpretCx<'mir, 'tcx, Evaluator<'tcx>>> { let mut ecx = InterpretCx::new( tcx.at(syntax::source_map::DUMMY_SP), ty::ParamEnv::reveal_all(), @@ -211,8 +211,8 @@ pub fn create_ecx<'a, 'mir: 'a, 'tcx: 'mir>( Ok(ecx) } -pub fn eval_main<'a, 'tcx: 'a>( - tcx: TyCtxt<'a, 'tcx, 'tcx>, +pub fn eval_main<'tcx>( + tcx: TyCtxt<'tcx, 'tcx>, main_id: DefId, config: MiriConfig, ) { @@ -364,25 +364,25 @@ impl<'tcx> Evaluator<'tcx> { // FIXME: rustc issue . #[allow(dead_code)] -type MiriEvalContext<'a, 'mir, 'tcx> = InterpretCx<'a, 'mir, 'tcx, Evaluator<'tcx>>; +type MiriEvalContext<'mir, 'tcx> = InterpretCx<'mir, 'tcx, Evaluator<'tcx>>; // A little trait that's useful to be inherited by extension traits. -pub trait MiriEvalContextExt<'a, 'mir, 'tcx> { - fn eval_context_ref(&self) -> &MiriEvalContext<'a, 'mir, 'tcx>; - fn eval_context_mut(&mut self) -> &mut MiriEvalContext<'a, 'mir, 'tcx>; +pub trait MiriEvalContextExt<'mir, 'tcx> { + fn eval_context_ref(&self) -> &MiriEvalContext<'mir, 'tcx>; + fn eval_context_mut(&mut self) -> &mut MiriEvalContext<'mir, 'tcx>; } -impl<'a, 'mir, 'tcx> MiriEvalContextExt<'a, 'mir, 'tcx> for MiriEvalContext<'a, 'mir, 'tcx> { +impl<'mir, 'tcx> MiriEvalContextExt<'mir, 'tcx> for MiriEvalContext<'mir, 'tcx> { #[inline(always)] - fn eval_context_ref(&self) -> &MiriEvalContext<'a, 'mir, 'tcx> { + fn eval_context_ref(&self) -> &MiriEvalContext<'mir, 'tcx> { self } #[inline(always)] - fn eval_context_mut(&mut self) -> &mut MiriEvalContext<'a, 'mir, 'tcx> { + fn eval_context_mut(&mut self) -> &mut MiriEvalContext<'mir, 'tcx> { self } } -impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { +impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { type MemoryKinds = MiriMemoryKind; type FrameExtra = stacked_borrows::CallId; @@ -395,14 +395,14 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { const STATIC_KIND: Option = Some(MiriMemoryKind::Static); #[inline(always)] - fn enforce_validity(ecx: &InterpretCx<'a, 'mir, 'tcx, Self>) -> bool { + fn enforce_validity(ecx: &InterpretCx<'mir, 'tcx, Self>) -> bool { ecx.machine.validate } /// Returns `Ok()` when the function was handled; fail otherwise. #[inline(always)] fn find_fn( - ecx: &mut InterpretCx<'a, 'mir, 'tcx, Self>, + ecx: &mut InterpretCx<'mir, 'tcx, Self>, instance: ty::Instance<'tcx>, args: &[OpTy<'tcx, Tag>], dest: Option>, @@ -413,7 +413,7 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { #[inline(always)] fn call_intrinsic( - ecx: &mut rustc_mir::interpret::InterpretCx<'a, 'mir, 'tcx, Self>, + ecx: &mut rustc_mir::interpret::InterpretCx<'mir, 'tcx, Self>, instance: ty::Instance<'tcx>, args: &[OpTy<'tcx, Tag>], dest: PlaceTy<'tcx, Tag>, @@ -423,7 +423,7 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { #[inline(always)] fn ptr_op( - ecx: &rustc_mir::interpret::InterpretCx<'a, 'mir, 'tcx, Self>, + ecx: &rustc_mir::interpret::InterpretCx<'mir, 'tcx, Self>, bin_op: mir::BinOp, left: ImmTy<'tcx, Tag>, right: ImmTy<'tcx, Tag>, @@ -432,7 +432,7 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { } fn box_alloc( - ecx: &mut InterpretCx<'a, 'mir, 'tcx, Self>, + ecx: &mut InterpretCx<'mir, 'tcx, Self>, dest: PlaceTy<'tcx, Tag>, ) -> InterpResult<'tcx> { trace!("box_alloc for {:?}", dest.layout.ty); @@ -475,7 +475,7 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { fn find_foreign_static( def_id: DefId, - tcx: TyCtxtAt<'a, 'tcx, 'tcx>, + tcx: TyCtxtAt<'tcx, 'tcx>, ) -> InterpResult<'tcx, Cow<'tcx, Allocation>> { let attrs = tcx.get_attrs(def_id); let link_name = match attr::first_attr_value_str_by_name(&attrs, sym::link_name) { @@ -498,7 +498,7 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { } #[inline(always)] - fn before_terminator(_ecx: &mut InterpretCx<'a, 'mir, 'tcx, Self>) -> InterpResult<'tcx> + fn before_terminator(_ecx: &mut InterpretCx<'mir, 'tcx, Self>) -> InterpResult<'tcx> { // We are not interested in detecting loops. Ok(()) @@ -550,7 +550,7 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { #[inline(always)] fn retag( - ecx: &mut InterpretCx<'a, 'mir, 'tcx, Self>, + ecx: &mut InterpretCx<'mir, 'tcx, Self>, kind: mir::RetagKind, place: PlaceTy<'tcx, Tag>, ) -> InterpResult<'tcx> { @@ -568,14 +568,14 @@ impl<'a, 'mir, 'tcx> Machine<'a, 'mir, 'tcx> for Evaluator<'tcx> { #[inline(always)] fn stack_push( - ecx: &mut InterpretCx<'a, 'mir, 'tcx, Self>, + ecx: &mut InterpretCx<'mir, 'tcx, Self>, ) -> InterpResult<'tcx, stacked_borrows::CallId> { Ok(ecx.memory().extra.borrow_mut().new_call()) } #[inline(always)] fn stack_pop( - ecx: &mut InterpretCx<'a, 'mir, 'tcx, Self>, + ecx: &mut InterpretCx<'mir, 'tcx, Self>, extra: stacked_borrows::CallId, ) -> InterpResult<'tcx> { Ok(ecx.memory().extra.borrow_mut().end_call(extra)) diff --git a/src/operator.rs b/src/operator.rs index 411df2155de0e..336f945c7847f 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -33,7 +33,7 @@ pub trait EvalContextExt<'tcx> { ) -> InterpResult<'tcx, Scalar>; } -impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'a, 'mir, 'tcx> { +impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { fn ptr_op( &self, bin_op: mir::BinOp, diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index bd81584790193..f7617676701c5 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -519,8 +519,8 @@ impl AllocationExtra for Stacks { /// Retagging/reborrowing. There is some policy in here, such as which permissions /// to grant for which references, and when to add protectors. -impl<'a, 'mir, 'tcx> EvalContextPrivExt<'a, 'mir, 'tcx> for crate::MiriEvalContext<'a, 'mir, 'tcx> {} -trait EvalContextPrivExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, 'mir, 'tcx> { +impl<'mir, 'tcx> EvalContextPrivExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} +trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { fn reborrow( &mut self, place: MPlaceTy<'tcx, Tag>, @@ -599,8 +599,8 @@ trait EvalContextPrivExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, } } -impl<'a, 'mir, 'tcx> EvalContextExt<'a, 'mir, 'tcx> for crate::MiriEvalContext<'a, 'mir, 'tcx> {} -pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, 'mir, 'tcx> { +impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} +pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { fn retag( &mut self, kind: RetagKind, @@ -643,19 +643,19 @@ pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, visitor.visit_value(place)?; // The actual visitor. - struct RetagVisitor<'ecx, 'a, 'mir, 'tcx> { - ecx: &'ecx mut MiriEvalContext<'a, 'mir, 'tcx>, + struct RetagVisitor<'ecx, 'mir, 'tcx> { + ecx: &'ecx mut MiriEvalContext<'mir, 'tcx>, kind: RetagKind, } - impl<'ecx, 'a, 'mir, 'tcx> - MutValueVisitor<'a, 'mir, 'tcx, Evaluator<'tcx>> + impl<'ecx, 'mir, 'tcx> + MutValueVisitor<'mir, 'tcx, Evaluator<'tcx>> for - RetagVisitor<'ecx, 'a, 'mir, 'tcx> + RetagVisitor<'ecx, 'mir, 'tcx> { type V = MPlaceTy<'tcx, Tag>; #[inline(always)] - fn ecx(&mut self) -> &mut MiriEvalContext<'a, 'mir, 'tcx> { + fn ecx(&mut self) -> &mut MiriEvalContext<'mir, 'tcx> { &mut self.ecx } diff --git a/src/tls.rs b/src/tls.rs index 4101a3ab39b7b..ddc301447c7e3 100644 --- a/src/tls.rs +++ b/src/tls.rs @@ -129,8 +129,8 @@ impl<'tcx> TlsData<'tcx> { } } -impl<'a, 'mir, 'tcx> EvalContextExt<'a, 'mir, 'tcx> for crate::MiriEvalContext<'a, 'mir, 'tcx> {} -pub trait EvalContextExt<'a, 'mir, 'tcx: 'a+'mir>: crate::MiriEvalContextExt<'a, 'mir, 'tcx> { +impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} +pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { fn run_tls_dtors(&mut self) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let mut dtor = this.machine.tls.fetch_tls_dtor(None, &*this.tcx); From 46b6a3fb7fbe10af1d5e8b2c527500130a4e317a Mon Sep 17 00:00:00 2001 From: Kenny Goodin Date: Thu, 13 Jun 2019 14:11:35 -0400 Subject: [PATCH 0817/3747] Add more missing math functions Add missing functions for atan2, cosh, sinh, and tan. Also add f32 calls and tests for cbrt and hypot. --- src/fn_call.rs | 48 +++++++++++++++++++++++++++---- tests/run-pass/intrinsics-math.rs | 20 +++++++++++-- 2 files changed, 61 insertions(+), 7 deletions(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index 4c40d24f7ff58..d7e52b4830327 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -560,18 +560,56 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let n = this.memory().get(ptr.alloc_id)?.read_c_str(tcx, ptr)?.len(); this.write_scalar(Scalar::from_uint(n as u64, dest.layout.size), dest)?; } - "cbrt" => { + + // math functions + + "cbrtf" | "coshf" | "sinhf" |"tanf" => { + // FIXME: Using host floats. + let f = f32::from_bits(this.read_scalar(args[0])?.to_u32()?); + let f = match link_name { + "cbrtf" => f.cbrt(), + "coshf" => f.cosh(), + "sinhf" => f.sinh(), + "tanf" => f.tan(), + _ => bug!(), + }; + this.write_scalar(Scalar::from_u32(f.to_bits()), dest)?; + } + // underscore case for windows + "_hypotf" | "hypotf" | "atan2f" => { + // FIXME: Using host floats. + let f1 = f32::from_bits(this.read_scalar(args[0])?.to_u32()?); + let f2 = f32::from_bits(this.read_scalar(args[1])?.to_u32()?); + let n = match link_name { + "_hypotf" | "hypotf" => f1.hypot(f2), + "atan2f" => f1.atan2(f2), + _ => bug!(), + }; + this.write_scalar(Scalar::from_u32(n.to_bits()), dest)?; + } + + "cbrt" | "cosh" | "sinh" | "tan" => { // FIXME: Using host floats. let f = f64::from_bits(this.read_scalar(args[0])?.to_u64()?); - let n = f.cbrt(); - this.write_scalar(Scalar::from_u64(n.to_bits()), dest)?; + let f = match link_name { + "cbrt" => f.cbrt(), + "cosh" => f.cosh(), + "sinh" => f.sinh(), + "tan" => f.tan(), + _ => bug!(), + }; + this.write_scalar(Scalar::from_u64(f.to_bits()), dest)?; } // underscore case for windows - "_hypot" | "hypot" => { + "_hypot" | "hypot" | "atan2" => { // FIXME: Using host floats. let f1 = f64::from_bits(this.read_scalar(args[0])?.to_u64()?); let f2 = f64::from_bits(this.read_scalar(args[1])?.to_u64()?); - let n = f1.hypot(f2); + let n = match link_name { + "_hypot" | "hypot" => f1.hypot(f2), + "atan2" => f1.atan2(f2), + _ => bug!(), + }; this.write_scalar(Scalar::from_u64(n.to_bits()), dest)?; } diff --git a/tests/run-pass/intrinsics-math.rs b/tests/run-pass/intrinsics-math.rs index 504ef47897953..20c0f67494886 100644 --- a/tests/run-pass/intrinsics-math.rs +++ b/tests/run-pass/intrinsics-math.rs @@ -67,6 +67,22 @@ pub fn main() { assert_approx_eq!(0.1f32.trunc(), 0.0f32); assert_approx_eq!((-0.1f64).trunc(), 0.0f64); - assert_approx_eq!(27f64.cbrt(), 3.0f64); - assert_approx_eq!(3f64.hypot(4f64), 5.0f64); + assert_approx_eq!(27.0f32.cbrt(), 3.0f32); + assert_approx_eq!(27.0f64.cbrt(), 3.0f64); + + assert_approx_eq!(3.0f32.hypot(4.0f32), 5.0f32); + assert_approx_eq!(3.0f64.hypot(4.0f64), 5.0f64); + + assert_approx_eq!(1.0f32.atan2(2.0f32), 0.46364761f32); + assert_approx_eq!(1.0f32.atan2(2.0f32), 0.46364761f32); + + assert_approx_eq!(1.0f32.cosh(), 1.54308f32); + assert_approx_eq!(1.0f64.cosh(), 1.54308f64); + + assert_approx_eq!(1.0f32.sinh(), 1.1752012f32); + assert_approx_eq!(1.0f64.sinh(), 1.1752012f64); + + assert_approx_eq!(1.0f32.tan(), 1.557408f32); + assert_approx_eq!(1.0f64.tan(), 1.557408f64); + } From 4db0eea010e7f490935b01e04feeedd4dc7dadf2 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Fri, 14 Jun 2019 10:44:08 +0200 Subject: [PATCH 0818/3747] Fix indentation --- src/fn_call.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index d7e52b4830327..eca1d9144ec4e 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -570,7 +570,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "cbrtf" => f.cbrt(), "coshf" => f.cosh(), "sinhf" => f.sinh(), - "tanf" => f.tan(), + "tanf" => f.tan(), _ => bug!(), }; this.write_scalar(Scalar::from_u32(f.to_bits()), dest)?; From ac2f6cbcde00eebcb696143e76177c1600f63410 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 14 Jun 2019 11:15:09 +0200 Subject: [PATCH 0819/3747] change sysroot check to print the output in case of an error --- src/bin/cargo-miri.rs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 121930bccce6d..3b7af93241945 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -133,11 +133,12 @@ fn test_sysroot_consistency() { fn get_sysroot(mut cmd: Command) -> PathBuf { let out = cmd.arg("--print").arg("sysroot") .output().expect("Failed to run rustc to get sysroot info"); - assert!(out.status.success(), "Bad status code when getting sysroot info"); - let sysroot = out.stdout.lines().nth(0) - .expect("didn't get at least one line for the sysroot").unwrap(); - PathBuf::from(sysroot).canonicalize() - .expect("Failed to canonicalize sysroot") + let stdout = String::from_utf8(out.stdout).expect("stdout is not valid UTF-8"); + let stderr = String::from_utf8(out.stderr).expect("stderr is not valid UTF-8"); + let stdout = stdout.trim(); + assert!(out.status.success(), "Bad status code when getting sysroot info.\nstdout:\n{}\nstderr:\n{}", stdout, stderr); + PathBuf::from(stdout).canonicalize() + .unwrap_or_else(|_| panic!("Failed to canonicalize sysroot: {}", stdout)) } let rustc_sysroot = get_sysroot(Command::new("rustc")); From 34b0922cec2eac41c7c204ca234fcd4a85b08615 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 14 Jun 2019 12:09:43 +0200 Subject: [PATCH 0820/3747] fix running a Miri that was built in bootstrap --- src/bin/miri.rs | 38 +++++++++++++++++++++++--------------- 1 file changed, 23 insertions(+), 15 deletions(-) diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 6346b2340b087..5a425baf0f61f 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -102,21 +102,26 @@ fn init_late_loggers() { /// Returns the "default sysroot" that Miri will use if no `--sysroot` flag is set. /// Should be a compile-time constant. -fn compile_time_sysroot() -> String { +fn compile_time_sysroot() -> Option { + if option_env!("RUSTC_STAGE").is_some() { + // This is being built as part of rustc, and gets shipped with rustup. + // We can rely on the sysroot computation in librustc. + return None; + } + // For builds outside rustc, we need to ensure that we got a sysroot + // that gets used as a default. The sysroot computation in librustc would + // end up somewhere in the build dir. // Taken from PR . let home = option_env!("RUSTUP_HOME").or(option_env!("MULTIRUST_HOME")); let toolchain = option_env!("RUSTUP_TOOLCHAIN").or(option_env!("MULTIRUST_TOOLCHAIN")); - match (home, toolchain) { + Some(match (home, toolchain) { (Some(home), Some(toolchain)) => format!("{}/toolchains/{}", home, toolchain), _ => { option_env!("RUST_SYSROOT") - .expect( - "could not find sysroot. Either set `MIRI_SYSROOT` at run-time, or at \ - build-time specify `RUST_SYSROOT` env var or use rustup or multirust", - ) + .expect("To build Miri without rustup, set the `RUST_SYSROOT` env var at build time") .to_owned() } - } + }) } fn main() { @@ -165,14 +170,17 @@ fn main() { } } - // Determine sysroot. - let sysroot_flag = "--sysroot".to_string(); - if !rustc_args.contains(&sysroot_flag) { - // We need to *always* set a --sysroot, as the "default" rustc uses is - // somewhere in the directory miri was built in. - // If no --sysroot is given, fall back to env vars that are read at *compile-time*. - rustc_args.push(sysroot_flag); - rustc_args.push(compile_time_sysroot()); + // Determine sysroot if needed. Make sure we always call `compile_time_sysroot` + // as that also does some sanity-checks of the environment we were built in. + // FIXME: Ideally we'd turn a bad build env into a compile-time error, but + // CTFE does not seem powerful enough for that yet. + if let Some(sysroot) = compile_time_sysroot() { + let sysroot_flag = "--sysroot".to_string(); + if !rustc_args.contains(&sysroot_flag) { + // We need to overwrite the default that librustc would compute. + rustc_args.push(sysroot_flag); + rustc_args.push(sysroot); + } } // Finally, add the default flags all the way in the beginning, but after the binary name. From fd0dccd4b12169e0aac42aff8addbb26b6d72197 Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Sat, 15 Jun 2019 02:34:11 +0700 Subject: [PATCH 0821/3747] Fix wrong lifetime of TyCtxt Rustup rust-lang/rust#61817 --- rust-version | 2 +- src/bin/miri-rustc-tests.rs | 2 +- src/lib.rs | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/rust-version b/rust-version index b945d0b3a2651..e60eb6c949542 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -d8f50ab0ea6c529c24e575279acc72093caeb679 +9606f6fa64926a84d82e3c62dbdc57f5c10f756d diff --git a/src/bin/miri-rustc-tests.rs b/src/bin/miri-rustc-tests.rs index e8714123ceb06..9b0d02f4b7e29 100644 --- a/src/bin/miri-rustc-tests.rs +++ b/src/bin/miri-rustc-tests.rs @@ -43,7 +43,7 @@ impl rustc_driver::Callbacks for MiriCompilerCalls { compiler.session().abort_if_errors(); compiler.global_ctxt().unwrap().peek_mut().enter(|tcx| { if std::env::args().any(|arg| arg == "--test") { - struct Visitor<'tcx>(TyCtxt<'tcx, 'tcx>); + struct Visitor<'tcx>(TyCtxt<'tcx>); impl<'tcx, 'hir> itemlikevisit::ItemLikeVisitor<'hir> for Visitor<'tcx> { fn visit_item(&mut self, i: &'hir hir::Item) { if let hir::ItemKind::Fn(.., body_id) = i.node { diff --git a/src/lib.rs b/src/lib.rs index 822b173e34a01..061b07478a28b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -72,7 +72,7 @@ pub struct MiriConfig { // Used by priroda. pub fn create_ecx<'mir, 'tcx: 'mir>( - tcx: TyCtxt<'tcx, 'tcx>, + tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig, ) -> InterpResult<'tcx, InterpretCx<'mir, 'tcx, Evaluator<'tcx>>> { @@ -212,7 +212,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( } pub fn eval_main<'tcx>( - tcx: TyCtxt<'tcx, 'tcx>, + tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig, ) { @@ -475,7 +475,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { fn find_foreign_static( def_id: DefId, - tcx: TyCtxtAt<'tcx, 'tcx>, + tcx: TyCtxtAt<'tcx>, ) -> InterpResult<'tcx, Cow<'tcx, Allocation>> { let attrs = tcx.get_attrs(def_id); let link_name = match attr::first_attr_value_str_by_name(&attrs, sym::link_name) { From a561f949ad214080054295035e5453c23c5a6ca5 Mon Sep 17 00:00:00 2001 From: soc Date: Fri, 14 Jun 2019 23:17:27 +0200 Subject: [PATCH 0822/3747] Fix project dirs path ProjectDirs::from("miri", "miri", "miri") would get you `miri\miri` on Windows and `miri.miri.miri` on macOS. I'm assuming here that your intention was to have only a `miri` directory on every OS. --- .appveyor.yml | 2 +- src/bin/cargo-miri.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index d13ce2b3974de..fe450922e044a 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -36,7 +36,7 @@ build_script: - cargo install --all-features --force --path . --locked --offline # Get ourselves a MIR-full libstd, and use it henceforth - cargo miri setup - - set MIRI_SYSROOT=%USERPROFILE%\AppData\Local\miri\miri\cache\HOST + - set MIRI_SYSROOT=%USERPROFILE%\AppData\Local\miri\cache\HOST test_script: # Test miri diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 3b7af93241945..0b2662fe3fb05 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -248,7 +248,7 @@ fn setup(ask_user: bool) { } // Next, we need our own libstd. We will do this work in whatever is a good cache dir for this platform. - let dirs = directories::ProjectDirs::from("miri", "miri", "miri").unwrap(); + let dirs = directories::ProjectDirs::from("", "", "miri").unwrap(); let dir = dirs.cache_dir(); if !dir.exists() { fs::create_dir_all(&dir).unwrap(); From d210ed7e122632b0904f8c077b94459fda92012f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 16 Jun 2019 09:49:27 +0200 Subject: [PATCH 0823/3747] bump rustc yet again --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index e60eb6c949542..9d2a8772234b3 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -9606f6fa64926a84d82e3c62dbdc57f5c10f756d +374c63e0fc356eb61b1966cb6026a2a49fe9226d From fc901244890cf2c0218027189d9d2311026dabbd Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 16 Jun 2019 10:51:08 +0200 Subject: [PATCH 0824/3747] test exact_div UB detection --- src/intrinsic.rs | 8 +++++++- tests/compile-fail/exact_div1.rs | 5 +++++ tests/compile-fail/exact_div2.rs | 5 +++++ tests/compile-fail/exact_div3.rs | 5 +++++ tests/compile-fail/exact_div4.rs | 5 +++++ 5 files changed, 27 insertions(+), 1 deletion(-) create mode 100644 tests/compile-fail/exact_div1.rs create mode 100644 tests/compile-fail/exact_div2.rs create mode 100644 tests/compile-fail/exact_div3.rs create mode 100644 tests/compile-fail/exact_div4.rs diff --git a/src/intrinsic.rs b/src/intrinsic.rs index cd89055b467af..cf2afe0a811a1 100644 --- a/src/intrinsic.rs +++ b/src/intrinsic.rs @@ -272,7 +272,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let b = this.read_immediate(args[1])?; // check x % y != 0 if this.binary_op(mir::BinOp::Rem, a, b)?.0.to_bits(dest.layout.size)? != 0 { - return err!(ValidationFailure(format!("exact_div: {:?} cannot be divided by {:?}", a, b))); + // Check if `b` is -1, which is the "min_value / -1" case. + let minus1 = Scalar::from_int(-1, dest.layout.size); + return if b.to_scalar().unwrap() == minus1 { + err!(Intrinsic(format!("exact_div: result of dividing MIN by -1 cannot be represented"))) + } else { + err!(Intrinsic(format!("exact_div: {:?} cannot be divided by {:?} without remainder", *a, *b))) + }; } this.binop_ignore_overflow(mir::BinOp::Div, a, b, dest)?; }, diff --git a/tests/compile-fail/exact_div1.rs b/tests/compile-fail/exact_div1.rs new file mode 100644 index 0000000000000..171bedeadc672 --- /dev/null +++ b/tests/compile-fail/exact_div1.rs @@ -0,0 +1,5 @@ +#![feature(core_intrinsics)] +fn main() { + // divison by 0 + unsafe { std::intrinsics::exact_div(2, 0); } //~ ERROR divisor of zero +} diff --git a/tests/compile-fail/exact_div2.rs b/tests/compile-fail/exact_div2.rs new file mode 100644 index 0000000000000..22bcf027dd05f --- /dev/null +++ b/tests/compile-fail/exact_div2.rs @@ -0,0 +1,5 @@ +#![feature(core_intrinsics)] +fn main() { + // divison with a remainder + unsafe { std::intrinsics::exact_div(2u16, 3); } //~ ERROR Scalar(0x0002) cannot be divided by Scalar(0x0003) without remainder +} diff --git a/tests/compile-fail/exact_div3.rs b/tests/compile-fail/exact_div3.rs new file mode 100644 index 0000000000000..2db62e0092d51 --- /dev/null +++ b/tests/compile-fail/exact_div3.rs @@ -0,0 +1,5 @@ +#![feature(core_intrinsics)] +fn main() { + // signed divison with a remainder + unsafe { std::intrinsics::exact_div(-19i8, 2); } //~ ERROR Scalar(0xed) cannot be divided by Scalar(0x02) without remainder +} diff --git a/tests/compile-fail/exact_div4.rs b/tests/compile-fail/exact_div4.rs new file mode 100644 index 0000000000000..736d4f2516d2d --- /dev/null +++ b/tests/compile-fail/exact_div4.rs @@ -0,0 +1,5 @@ +#![feature(core_intrinsics)] +fn main() { + // divison of min_value by -1 + unsafe { std::intrinsics::exact_div(i64::min_value(), -1); } //~ ERROR result of dividing MIN by -1 cannot be represented +} From cf748149ce6e4a8af1dcb387b6f5a19a856a6579 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 16 Jun 2019 10:53:49 +0200 Subject: [PATCH 0825/3747] test unchecked_rem --- tests/compile-fail/div-by-zero-3.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 tests/compile-fail/div-by-zero-3.rs diff --git a/tests/compile-fail/div-by-zero-3.rs b/tests/compile-fail/div-by-zero-3.rs new file mode 100644 index 0000000000000..3200504ddb6e1 --- /dev/null +++ b/tests/compile-fail/div-by-zero-3.rs @@ -0,0 +1,11 @@ +#![feature(core_intrinsics)] + +use std::intrinsics::*; + +//error-pattern: Division by 0 in unchecked_rem + +fn main() { + unsafe { + let _n = unchecked_rem(3u32, 0); + } +} From 7ce36226e6156e7aaf6da77833fd80cd83d8d623 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 16 Jun 2019 11:10:14 +0200 Subject: [PATCH 0826/3747] implement and test unchecked_{add,sub,mul} intrinsics --- src/intrinsic.rs | 16 +++++++++++ tests/compile-fail/unchecked_add1.rs | 5 ++++ tests/compile-fail/unchecked_add2.rs | 5 ++++ tests/compile-fail/unchecked_mul1.rs | 5 ++++ tests/compile-fail/unchecked_mul2.rs | 5 ++++ tests/compile-fail/unchecked_sub1.rs | 5 ++++ tests/compile-fail/unchecked_sub2.rs | 5 ++++ tests/run-pass/intrinsics-integer.rs | 40 ++++++++++++++++++---------- 8 files changed, 72 insertions(+), 14 deletions(-) create mode 100644 tests/compile-fail/unchecked_add1.rs create mode 100644 tests/compile-fail/unchecked_add2.rs create mode 100644 tests/compile-fail/unchecked_mul1.rs create mode 100644 tests/compile-fail/unchecked_mul2.rs create mode 100644 tests/compile-fail/unchecked_sub1.rs create mode 100644 tests/compile-fail/unchecked_sub2.rs diff --git a/src/intrinsic.rs b/src/intrinsic.rs index cf2afe0a811a1..0ecccd02d7e1b 100644 --- a/src/intrinsic.rs +++ b/src/intrinsic.rs @@ -465,6 +465,22 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx )?; } + "unchecked_add" | "unchecked_sub" | "unchecked_mul" => { + let l = this.read_immediate(args[0])?; + let r = this.read_immediate(args[1])?; + let op = match intrinsic_name.get() { + "unchecked_add" => mir::BinOp::Add, + "unchecked_sub" => mir::BinOp::Sub, + "unchecked_mul" => mir::BinOp::Mul, + _ => bug!(), + }; + let (res, overflowed) = this.binary_op(op, l, r)?; + if overflowed { + return err!(Intrinsic(format!("Overflowing arithmetic in {}", intrinsic_name.get()))); + } + this.write_scalar(res, dest)?; + } + "uninit" => { // Check fast path: we don't want to force an allocation in case the destination is a simple value, // but we also do not want to create a new allocation with 0s and then copy that over. diff --git a/tests/compile-fail/unchecked_add1.rs b/tests/compile-fail/unchecked_add1.rs new file mode 100644 index 0000000000000..2447c8ba4a818 --- /dev/null +++ b/tests/compile-fail/unchecked_add1.rs @@ -0,0 +1,5 @@ +#![feature(core_intrinsics)] +fn main() { + // MAX overflow + unsafe { std::intrinsics::unchecked_add(40000u16, 30000); } //~ ERROR Overflowing arithmetic in unchecked_add +} diff --git a/tests/compile-fail/unchecked_add2.rs b/tests/compile-fail/unchecked_add2.rs new file mode 100644 index 0000000000000..e292cdf6d961e --- /dev/null +++ b/tests/compile-fail/unchecked_add2.rs @@ -0,0 +1,5 @@ +#![feature(core_intrinsics)] +fn main() { + // MIN overflow + unsafe { std::intrinsics::unchecked_add(-30000i16, -8000); } //~ ERROR Overflowing arithmetic in unchecked_add +} diff --git a/tests/compile-fail/unchecked_mul1.rs b/tests/compile-fail/unchecked_mul1.rs new file mode 100644 index 0000000000000..57bfaf124c241 --- /dev/null +++ b/tests/compile-fail/unchecked_mul1.rs @@ -0,0 +1,5 @@ +#![feature(core_intrinsics)] +fn main() { + // MAX overflow + unsafe { std::intrinsics::unchecked_mul(300u16, 250u16); } //~ ERROR Overflowing arithmetic in unchecked_mul +} diff --git a/tests/compile-fail/unchecked_mul2.rs b/tests/compile-fail/unchecked_mul2.rs new file mode 100644 index 0000000000000..690f2dc76284c --- /dev/null +++ b/tests/compile-fail/unchecked_mul2.rs @@ -0,0 +1,5 @@ +#![feature(core_intrinsics)] +fn main() { + // MIN overflow + unsafe { std::intrinsics::unchecked_mul(1_000_000_000i32, -4); } //~ ERROR Overflowing arithmetic in unchecked_mul +} diff --git a/tests/compile-fail/unchecked_sub1.rs b/tests/compile-fail/unchecked_sub1.rs new file mode 100644 index 0000000000000..0be8afa2c34cc --- /dev/null +++ b/tests/compile-fail/unchecked_sub1.rs @@ -0,0 +1,5 @@ +#![feature(core_intrinsics)] +fn main() { + // MIN overflow + unsafe { std::intrinsics::unchecked_sub(14u32, 22); } //~ ERROR Overflowing arithmetic in unchecked_sub +} diff --git a/tests/compile-fail/unchecked_sub2.rs b/tests/compile-fail/unchecked_sub2.rs new file mode 100644 index 0000000000000..bc23fa37c3676 --- /dev/null +++ b/tests/compile-fail/unchecked_sub2.rs @@ -0,0 +1,5 @@ +#![feature(core_intrinsics)] +fn main() { + // MAX overflow + unsafe { std::intrinsics::unchecked_sub(30000i16, -7000); } //~ ERROR Overflowing arithmetic in unchecked_sub +} diff --git a/tests/run-pass/intrinsics-integer.rs b/tests/run-pass/intrinsics-integer.rs index de59314eff5a0..af3517af6f7a0 100644 --- a/tests/run-pass/intrinsics-integer.rs +++ b/tests/run-pass/intrinsics-integer.rs @@ -8,23 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![feature(intrinsics)] - -mod rusti { - extern "rust-intrinsic" { - pub fn ctpop(x: T) -> T; - pub fn ctlz(x: T) -> T; - pub fn ctlz_nonzero(x: T) -> T; - pub fn cttz(x: T) -> T; - pub fn cttz_nonzero(x: T) -> T; - pub fn bswap(x: T) -> T; - } -} +#![feature(core_intrinsics)] +use std::intrinsics::*; pub fn main() { unsafe { - use crate::rusti::*; - assert_eq!(ctpop(0u8), 0); assert_eq!(ctpop(0i8), 0); assert_eq!(ctpop(0u16), 0); assert_eq!(ctpop(0i16), 0); assert_eq!(ctpop(0u32), 0); assert_eq!(ctpop(0i32), 0); @@ -138,5 +126,29 @@ pub fn main() { assert_eq!(bswap(0x0ABBCC0Di32), 0x0DCCBB0A); assert_eq!(bswap(0x0122334455667708u64), 0x0877665544332201); assert_eq!(bswap(0x0122334455667708i64), 0x0877665544332201); + + assert_eq!(exact_div(9*9u32, 3), 27); + assert_eq!(exact_div(-9*9i32, 3), -27); + assert_eq!(exact_div(9*9i8, -3), -27); + assert_eq!(exact_div(-9*9i64, -3), 27); + + assert_eq!(unchecked_div(9*9u32, 2), 40); + assert_eq!(unchecked_div(-9*9i32, 2), -40); + assert_eq!(unchecked_div(9*9i8, -2), -40); + assert_eq!(unchecked_div(-9*9i64, -2), 40); + + assert_eq!(unchecked_rem(9*9u32, 2), 1); + assert_eq!(unchecked_rem(-9*9i32, 2), -1); + assert_eq!(unchecked_rem(9*9i8, -2), 1); + assert_eq!(unchecked_rem(-9*9i64, -2), -1); + + assert_eq!(unchecked_add(23u8, 19), 42); + assert_eq!(unchecked_add(5, -10), -5); + + assert_eq!(unchecked_sub(23u8, 19), 4); + assert_eq!(unchecked_sub(-17, -27), 10); + + assert_eq!(unchecked_mul(6u8, 7), 42); + assert_eq!(unchecked_mul(13, -5), -65); } } From 850a0d725fe4593645642b142e79037420030c4a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 20 Jun 2019 15:35:06 +0200 Subject: [PATCH 0827/3747] bump Rust, no changes needed --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 9d2a8772234b3..1999b58c89cb7 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -374c63e0fc356eb61b1966cb6026a2a49fe9226d +4fb77a0398d0339f35f1b18595b375428babd431 From 04fa38dd1bd52c098a731893bbf5b274a4911d0c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 20 Jun 2019 16:38:55 +0200 Subject: [PATCH 0828/3747] allow some inequality comparisons between pointers and integers --- src/operator.rs | 21 +++++++++++++++++++++ tests/compile-fail/ptr_ge_integer.rs | 7 +++++++ tests/run-pass/pointers.rs | 7 +++++++ 3 files changed, 35 insertions(+) create mode 100644 tests/compile-fail/ptr_ge_integer.rs diff --git a/src/operator.rs b/src/operator.rs index 336f945c7847f..b05d435ef644e 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -109,6 +109,27 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { err!(InvalidPointerMath) } } + Gt | Ge if left.is_ptr() && right.is_bits() => { + // "ptr >[=] integer" can be tested if the integer is small enough. + let left = left.to_ptr().expect("we checked is_ptr"); + let right = right.to_bits(self.memory().pointer_size()).expect("we checked is_bits"); + let (_alloc_size, alloc_align) = self.memory() + .get_size_and_align(left.alloc_id, InboundsCheck::MaybeDead) + .expect("determining size+align of dead ptr cannot fail"); + let min_ptr_val = u128::from(alloc_align.bytes()) + u128::from(left.offset.bytes()); + let result = match bin_op { + Gt => min_ptr_val > right, + Ge => min_ptr_val >= right, + _ => bug!(), + }; + if result { + // Definitely true! + Ok((Scalar::from_bool(true), false)) + } else { + // Sorry, can't tell. + err!(InvalidPointerMath) + } + } // These work if the left operand is a pointer, and the right an integer Add | BitAnd | Sub | Rem if left.is_ptr() && right.is_bits() => { // Cast to i128 is fine as we checked the kind to be ptr-sized diff --git a/tests/compile-fail/ptr_ge_integer.rs b/tests/compile-fail/ptr_ge_integer.rs new file mode 100644 index 0000000000000..43160249c3635 --- /dev/null +++ b/tests/compile-fail/ptr_ge_integer.rs @@ -0,0 +1,7 @@ +fn main() { + let b = Box::new(0); + let x = &*b as *const i32; + // We cannot test if this is >= 64. After all, depending on the base address, that + // might or might not be the case. + assert!(x >= 64 as *const i32); //~ ERROR invalid arithmetic on pointers +} diff --git a/tests/run-pass/pointers.rs b/tests/run-pass/pointers.rs index 2b26791328df6..e0847de97ba9c 100644 --- a/tests/run-pass/pointers.rs +++ b/tests/run-pass/pointers.rs @@ -83,4 +83,11 @@ fn main() { assert!(dangling != 5usize); assert!(dangling != 6usize); assert!(dangling != 7usize); + + // Using inequality to do the comparison. + assert!(dangling > 0); + assert!(dangling > 1); + assert!(dangling > 2); + assert!(dangling > 3); + assert!(dangling >= 4); } From 03eff5981b05ab20461e745a031bd6599a41af7d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 20 Jun 2019 19:45:39 +0200 Subject: [PATCH 0829/3747] use org.rust-lang.miri folder on macOS --- .appveyor.yml | 2 +- src/bin/cargo-miri.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index fe450922e044a..5080a22aded97 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -36,7 +36,7 @@ build_script: - cargo install --all-features --force --path . --locked --offline # Get ourselves a MIR-full libstd, and use it henceforth - cargo miri setup - - set MIRI_SYSROOT=%USERPROFILE%\AppData\Local\miri\cache\HOST + - set MIRI_SYSROOT=%USERPROFILE%\AppData\Local\rust-lang\miri\cache\HOST test_script: # Test miri diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 0b2662fe3fb05..cc95eeb7f3a0a 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -248,7 +248,7 @@ fn setup(ask_user: bool) { } // Next, we need our own libstd. We will do this work in whatever is a good cache dir for this platform. - let dirs = directories::ProjectDirs::from("", "", "miri").unwrap(); + let dirs = directories::ProjectDirs::from("org", "rust-lang", "miri").unwrap(); let dir = dirs.cache_dir(); if !dir.exists() { fs::create_dir_all(&dir).unwrap(); From 4211d7e1a0083456dfdb9ad466907ed17ed23cd4 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Thu, 20 Jun 2019 16:58:57 -0500 Subject: [PATCH 0830/3747] Update tag methods to match Machine changes --- src/lib.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 061b07478a28b..9072f141f89d9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -508,21 +508,21 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { id: AllocId, alloc: Cow<'b, Allocation>, kind: Option>, - memory_extra: &Self::MemoryExtra, + memory: &Memory<'mir, 'tcx, Self>, ) -> (Cow<'b, Allocation>, Self::PointerTag) { let kind = kind.expect("we set our STATIC_KIND so this cannot be None"); let alloc = alloc.into_owned(); let (extra, base_tag) = Stacks::new_allocation( id, Size::from_bytes(alloc.bytes.len() as u64), - Rc::clone(memory_extra), + Rc::clone(&memory.extra), kind, ); if kind != MiriMemoryKind::Static.into() { assert!(alloc.relocations.is_empty(), "Only statics can come initialized with inner pointers"); // Now we can rely on the inner pointers being static, too. } - let mut memory_extra = memory_extra.borrow_mut(); + let mut memory_extra = memory.extra.borrow_mut(); let alloc: Allocation = Allocation { bytes: alloc.bytes, relocations: Relocations::from_presorted( @@ -543,9 +543,9 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { #[inline(always)] fn tag_static_base_pointer( id: AllocId, - memory_extra: &Self::MemoryExtra, + memory: &Memory<'mir, 'tcx, Self>, ) -> Self::PointerTag { - memory_extra.borrow_mut().static_base_ptr(id) + memory.extra.borrow_mut().static_base_ptr(id) } #[inline(always)] From ef59fc420fad34801871e538e5e54c8ba8056c61 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Fri, 21 Jun 2019 12:36:19 +0200 Subject: [PATCH 0831/3747] Update rust-version --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 9d2a8772234b3..f09338fca150f 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -374c63e0fc356eb61b1966cb6026a2a49fe9226d +56a12b2ad058f22f1ef090713df15598525ba4a4 From 1a784ea21b5652ea4cbedca06fcb8c7249df7ce8 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 21 Jun 2019 20:51:05 +0200 Subject: [PATCH 0832/3747] Travis: also run on bors branches, and not on master --- .travis.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.travis.yml b/.travis.yml index 1ba55e0c724a5..4b56ea9aa6488 100644 --- a/.travis.yml +++ b/.travis.yml @@ -12,6 +12,9 @@ os: - osx dist: xenial +# Run in PRs and for bors, but not on master. +if: branch = staging OR branch = trying OR type = pull_request + env: global: - RUST_TEST_NOCAPTURE=1 @@ -53,3 +56,5 @@ notifications: branches: only: - master + - auto + - try From 38d19199c3945f1ae5f086bc4b8ab74e55a62bca Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 21 Jun 2019 20:55:24 +0200 Subject: [PATCH 0833/3747] AppVeyor: only run on bors branches --- .appveyor.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.appveyor.yml b/.appveyor.yml index 5080a22aded97..f7d3f990ac999 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -9,7 +9,8 @@ environment: branches: # whitelist only: - - master + - auto + - try cache: - '%USERPROFILE%\.cargo' From ab473bcda5a96cf83bca8cad6f35bd3068c19e60 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 21 Jun 2019 21:02:30 +0200 Subject: [PATCH 0834/3747] fix Travis bors branch names --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 4b56ea9aa6488..e78c4b9b8b4fa 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,7 +13,7 @@ os: dist: xenial # Run in PRs and for bors, but not on master. -if: branch = staging OR branch = trying OR type = pull_request +if: branch = auto OR branch = try OR type = pull_request env: global: From 5472755f1654f210d61c4f5003ff8e733b54f9a4 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 21 Jun 2019 21:48:27 +0200 Subject: [PATCH 0835/3747] add a failing test where an immovable generator gets moved --- tests/compile-fail/generator-pinned-moved.rs | 44 ++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 tests/compile-fail/generator-pinned-moved.rs diff --git a/tests/compile-fail/generator-pinned-moved.rs b/tests/compile-fail/generator-pinned-moved.rs new file mode 100644 index 0000000000000..2ae98adad7739 --- /dev/null +++ b/tests/compile-fail/generator-pinned-moved.rs @@ -0,0 +1,44 @@ +#![feature(generators, generator_trait)] + +use std::{ + ops::{Generator, GeneratorState}, + pin::Pin, +}; + +fn firstn() -> impl Generator { + static move || { + let mut num = 0; + let num = &mut num; + + yield *num; + *num += 1; //~ ERROR dangling pointer was dereferenced + } +} + +struct GeneratorIteratorAdapter(G); + +impl Iterator for GeneratorIteratorAdapter +where + G: Generator, +{ + type Item = G::Yield; + + fn next(&mut self) -> Option { + let me = unsafe { Pin::new_unchecked(&mut self.0) }; + match me.resume() { + GeneratorState::Yielded(x) => Some(x), + GeneratorState::Complete(_) => None, + } + } +} + +fn main() { + let mut generator_iterator_2 = { + let mut generator_iterator = GeneratorIteratorAdapter(firstn()); + generator_iterator.next(); // pin it + + generator_iterator // move it + }; // *deallocate* generator_iterator + + generator_iterator_2.next(); // and use moved value +} From fd3a291db49fbb6a0198f8bb05990f9163cc1f66 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Thu, 20 Jun 2019 14:21:47 -0500 Subject: [PATCH 0836/3747] Implement intptrcast methods --- src/intptrcast.rs | 20 +++++++++ src/lib.rs | 95 ++++++++++++++++++++++++++++++++++++++---- src/memory.rs | 60 ++++++++++++++++++++++++++ src/stacked_borrows.rs | 63 ++++++---------------------- 4 files changed, 179 insertions(+), 59 deletions(-) create mode 100644 src/intptrcast.rs create mode 100644 src/memory.rs diff --git a/src/intptrcast.rs b/src/intptrcast.rs new file mode 100644 index 0000000000000..3e07f54fbd3e8 --- /dev/null +++ b/src/intptrcast.rs @@ -0,0 +1,20 @@ +use std::cell::RefCell; + +use rustc::mir::interpret::AllocId; + +pub type MemoryState = RefCell; + +#[derive(Clone, Debug)] +pub struct GlobalState { + pub vec: Vec<(u64, AllocId)>, + pub addr: u64, +} + +impl Default for GlobalState { + fn default() -> Self { + GlobalState { + vec: Vec::default(), + addr: 2u64.pow(16) + } + } +} diff --git a/src/lib.rs b/src/lib.rs index 9072f141f89d9..f61abea62e0b6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -20,9 +20,12 @@ mod tls; mod range_map; mod mono_hash_map; mod stacked_borrows; +mod intptrcast; +mod memory; use std::collections::HashMap; use std::borrow::Cow; +use std::cell::RefCell; use std::rc::Rc; use rand::rngs::StdRng; @@ -48,6 +51,7 @@ use crate::range_map::RangeMap; pub use crate::helpers::{EvalContextExt as HelpersEvalContextExt}; use crate::mono_hash_map::MonoHashMap; pub use crate::stacked_borrows::{EvalContextExt as StackedBorEvalContextExt}; +use crate::memory::AllocExtra; // Used by priroda. pub use crate::stacked_borrows::{Tag, Permission, Stack, Stacks, Item}; @@ -206,6 +210,8 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( } } + ecx.memory_mut().extra.seed = config.seed.clone(); + assert!(args.next().is_none(), "start lang item has more arguments than expected"); Ok(ecx) @@ -386,8 +392,8 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { type MemoryKinds = MiriMemoryKind; type FrameExtra = stacked_borrows::CallId; - type MemoryExtra = stacked_borrows::MemoryState; - type AllocExtra = stacked_borrows::Stacks; + type MemoryExtra = memory::MemoryState; + type AllocExtra = memory::AllocExtra; type PointerTag = Tag; type MemoryMap = MonoHashMap, Allocation)>; @@ -515,14 +521,14 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { let (extra, base_tag) = Stacks::new_allocation( id, Size::from_bytes(alloc.bytes.len() as u64), - Rc::clone(&memory.extra), + Rc::clone(&memory.extra.stacked), kind, ); if kind != MiriMemoryKind::Static.into() { assert!(alloc.relocations.is_empty(), "Only statics can come initialized with inner pointers"); // Now we can rely on the inner pointers being static, too. } - let mut memory_extra = memory.extra.borrow_mut(); + let mut memory_extra = memory.extra.stacked.borrow_mut(); let alloc: Allocation = Allocation { bytes: alloc.bytes, relocations: Relocations::from_presorted( @@ -535,7 +541,10 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { undef_mask: alloc.undef_mask, align: alloc.align, mutability: alloc.mutability, - extra, + extra: AllocExtra { + stacks: extra, + base_addr: RefCell::new(None), + }, }; (Cow::Owned(alloc), base_tag) } @@ -545,7 +554,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { id: AllocId, memory: &Memory<'mir, 'tcx, Self>, ) -> Self::PointerTag { - memory.extra.borrow_mut().static_base_ptr(id) + memory.extra.stacked.borrow_mut().static_base_ptr(id) } #[inline(always)] @@ -570,7 +579,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { fn stack_push( ecx: &mut InterpretCx<'mir, 'tcx, Self>, ) -> InterpResult<'tcx, stacked_borrows::CallId> { - Ok(ecx.memory().extra.borrow_mut().new_call()) + Ok(ecx.memory().extra.stacked.borrow_mut().new_call()) } #[inline(always)] @@ -578,6 +587,76 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { ecx: &mut InterpretCx<'mir, 'tcx, Self>, extra: stacked_borrows::CallId, ) -> InterpResult<'tcx> { - Ok(ecx.memory().extra.borrow_mut().end_call(extra)) + Ok(ecx.memory().extra.stacked.borrow_mut().end_call(extra)) + } + + fn int_to_ptr( + int: u64, + memory: &Memory<'mir, 'tcx, Self>, + ) -> InterpResult<'tcx, Pointer> { + if int == 0 { + return err!(InvalidNullPointerUsage); + } + + if memory.extra.seed.is_none() { + return err!(ReadBytesAsPointer); + } + + let extra = memory.extra.intptrcast.borrow(); + + match extra.vec.binary_search_by_key(&int, |(int, _)| *int) { + Ok(pos) => { + let (_, alloc_id) = extra.vec[pos]; + Ok(Pointer::new_with_tag(alloc_id, Size::from_bytes(0), Tag::Untagged)) + } + Err(pos) => { + if pos > 0 { + let (glb, alloc_id) = extra.vec[pos - 1]; + let offset = int - glb; + if offset <= memory.get(alloc_id)?.bytes.len() as u64 { + Ok(Pointer::new_with_tag(alloc_id, Size::from_bytes(offset), Tag::Untagged)) + } else { + return err!(DanglingPointerDeref); + } + } else { + return err!(DanglingPointerDeref); + } + } + } + } + + fn ptr_to_int( + ptr: Pointer, + memory: &Memory<'mir, 'tcx, Self>, + ) -> InterpResult<'tcx, u64> { + if memory.extra.seed.is_none() { + return err!(ReadPointerAsBytes); + } + + let mut extra = memory.extra.intptrcast.borrow_mut(); + + let alloc = memory.get(ptr.alloc_id)?; + + let base_addr = match alloc.extra.base_addr.borrow().clone() { + Some(base_addr) => base_addr, + None => { + let base_addr = extra.addr; + extra.addr += alloc.bytes.len() as u64; + + *alloc.extra.base_addr.borrow_mut() = Some(base_addr); + + let elem = (base_addr, ptr.alloc_id); + + if let Err(pos) = extra.vec.binary_search(&elem) { + extra.vec.insert(pos, elem); + } else { + return err!(Unreachable); + } + + base_addr + } + }; + + Ok(base_addr + ptr.offset.bytes()) } } diff --git a/src/memory.rs b/src/memory.rs new file mode 100644 index 0000000000000..13ffd859adefa --- /dev/null +++ b/src/memory.rs @@ -0,0 +1,60 @@ +use std::cell::RefCell; + +use rustc_mir::interpret::{Pointer, Allocation, AllocationExtra, InterpResult}; +use rustc_target::abi::Size; + +use crate::{stacked_borrows, intptrcast}; +use crate::stacked_borrows::{Tag, AccessKind}; + +#[derive(Default, Clone, Debug)] +pub struct MemoryState { + pub stacked: stacked_borrows::MemoryState, + pub intptrcast: intptrcast::MemoryState, + pub seed: Option, +} + +#[derive(Debug, Clone,)] +pub struct AllocExtra { + pub stacks: stacked_borrows::Stacks, + pub base_addr: RefCell>, +} + +impl AllocationExtra for AllocExtra { + #[inline(always)] + fn memory_read<'tcx>( + alloc: &Allocation, + ptr: Pointer, + size: Size, + ) -> InterpResult<'tcx> { + trace!("read access with tag {:?}: {:?}, size {}", ptr.tag, ptr.erase_tag(), size.bytes()); + alloc.extra.stacks.for_each(ptr, size, |stack, global| { + stack.access(AccessKind::Read, ptr.tag, global)?; + Ok(()) + }) + } + + #[inline(always)] + fn memory_written<'tcx>( + alloc: &mut Allocation, + ptr: Pointer, + size: Size, + ) -> InterpResult<'tcx> { + trace!("write access with tag {:?}: {:?}, size {}", ptr.tag, ptr.erase_tag(), size.bytes()); + alloc.extra.stacks.for_each(ptr, size, |stack, global| { + stack.access(AccessKind::Write, ptr.tag, global)?; + Ok(()) + }) + } + + #[inline(always)] + fn memory_deallocated<'tcx>( + alloc: &mut Allocation, + ptr: Pointer, + size: Size, + ) -> InterpResult<'tcx> { + trace!("deallocation with tag {:?}: {:?}, size {}", ptr.tag, ptr.erase_tag(), size.bytes()); + alloc.extra.stacks.for_each(ptr, size, |stack, global| { + stack.dealloc(ptr.tag, global) + }) + } +} diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index f7617676701c5..ea70c28709cee 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -10,8 +10,8 @@ use rustc::mir::RetagKind; use crate::{ InterpResult, InterpError, MiriEvalContext, HelpersEvalContextExt, Evaluator, MutValueVisitor, - MemoryKind, MiriMemoryKind, RangeMap, Allocation, AllocationExtra, AllocId, CheckInAllocMsg, - Pointer, Immediate, ImmTy, PlaceTy, MPlaceTy, + MemoryKind, MiriMemoryKind, RangeMap, AllocId, CheckInAllocMsg, Pointer, Immediate, ImmTy, + PlaceTy, MPlaceTy, }; pub type PtrId = NonZeroU64; @@ -286,7 +286,7 @@ impl<'tcx> Stack { /// Test if a memory `access` using pointer tagged `tag` is granted. /// If yes, return the index of the item that granted it. - fn access( + pub(crate) fn access( &mut self, access: AccessKind, tag: Tag, @@ -336,7 +336,7 @@ impl<'tcx> Stack { /// Deallocate a location: Like a write access, but also there must be no /// active protectors at all because we will remove all items. - fn dealloc( + pub(crate) fn dealloc( &mut self, tag: Tag, global: &GlobalState, @@ -429,14 +429,15 @@ impl<'tcx> Stacks { let stack = Stack { borrows: vec![item], }; + Stacks { stacks: RefCell::new(RangeMap::new(size, stack)), - global: extra, + global: extra, } } /// Call `f` on every stack in the range. - fn for_each( + pub(crate) fn for_each( &self, ptr: Pointer, size: Size, @@ -456,7 +457,7 @@ impl Stacks { pub fn new_allocation( id: AllocId, size: Size, - extra: MemoryState, + extra: MemoryState, kind: MemoryKind, ) -> (Self, Tag) { let (tag, perm) = match kind { @@ -477,46 +478,6 @@ impl Stacks { } } -impl AllocationExtra for Stacks { - #[inline(always)] - fn memory_read<'tcx>( - alloc: &Allocation, - ptr: Pointer, - size: Size, - ) -> InterpResult<'tcx> { - trace!("read access with tag {:?}: {:?}, size {}", ptr.tag, ptr.erase_tag(), size.bytes()); - alloc.extra.for_each(ptr, size, |stack, global| { - stack.access(AccessKind::Read, ptr.tag, global)?; - Ok(()) - }) - } - - #[inline(always)] - fn memory_written<'tcx>( - alloc: &mut Allocation, - ptr: Pointer, - size: Size, - ) -> InterpResult<'tcx> { - trace!("write access with tag {:?}: {:?}, size {}", ptr.tag, ptr.erase_tag(), size.bytes()); - alloc.extra.for_each(ptr, size, |stack, global| { - stack.access(AccessKind::Write, ptr.tag, global)?; - Ok(()) - }) - } - - #[inline(always)] - fn memory_deallocated<'tcx>( - alloc: &mut Allocation, - ptr: Pointer, - size: Size, - ) -> InterpResult<'tcx> { - trace!("deallocation with tag {:?}: {:?}, size {}", ptr.tag, ptr.erase_tag(), size.bytes()); - alloc.extra.for_each(ptr, size, |stack, global| { - stack.dealloc(ptr.tag, global) - }) - } -} - /// Retagging/reborrowing. There is some policy in here, such as which permissions /// to grant for which references, and when to add protectors. impl<'mir, 'tcx> EvalContextPrivExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} @@ -553,14 +514,14 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // We are only ever `SharedReadOnly` inside the frozen bits. let perm = if frozen { Permission::SharedReadOnly } else { Permission::SharedReadWrite }; let item = Item { perm, tag: new_tag, protector }; - alloc.extra.for_each(cur_ptr, size, |stack, global| { + alloc.extra.stacks.for_each(cur_ptr, size, |stack, global| { stack.grant(cur_ptr.tag, item, global) }) }); } }; let item = Item { perm, tag: new_tag, protector }; - alloc.extra.for_each(ptr, size, |stack, global| { + alloc.extra.stacks.for_each(ptr, size, |stack, global| { stack.grant(ptr.tag, item, global) }) } @@ -587,7 +548,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Compute new borrow. let new_tag = match kind { RefKind::Raw { .. } => Tag::Untagged, - _ => Tag::Tagged(this.memory().extra.borrow_mut().new_ptr()), + _ => Tag::Tagged(this.memory().extra.stacked.borrow_mut().new_ptr()), }; // Reborrow. @@ -621,7 +582,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ty::RawPtr(tym) if kind == RetagKind::Raw => Some((RefKind::Raw { mutable: tym.mutbl == MutMutable }, false)), // Boxes do not get a protector: protectors reflect that references outlive the call - // they were passed in to; that's just not the case for boxes. + // they were passed in to; that's just not the case for boxes. ty::Adt(..) if ty.is_box() => Some((RefKind::Unique { two_phase: false }, false)), _ => None, } From e57447014d0cc8ab9ec86c30bc94e48c588d4526 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Fri, 21 Jun 2019 16:32:54 -0500 Subject: [PATCH 0837/3747] Duplicate compile-fail tests for intptrcast --- tests/compile-fail/intptrcast_cast_int_to_fn_ptr.rs | 10 ++++++++++ tests/compile-fail/intptrcast_null_pointer_deref.rs | 6 ++++++ tests/compile-fail/intptrcast_wild_pointer_deref.rs | 7 +++++++ 3 files changed, 23 insertions(+) create mode 100644 tests/compile-fail/intptrcast_cast_int_to_fn_ptr.rs create mode 100644 tests/compile-fail/intptrcast_null_pointer_deref.rs create mode 100644 tests/compile-fail/intptrcast_wild_pointer_deref.rs diff --git a/tests/compile-fail/intptrcast_cast_int_to_fn_ptr.rs b/tests/compile-fail/intptrcast_cast_int_to_fn_ptr.rs new file mode 100644 index 0000000000000..f4064cf92e2ca --- /dev/null +++ b/tests/compile-fail/intptrcast_cast_int_to_fn_ptr.rs @@ -0,0 +1,10 @@ +// Validation makes this fail in the wrong place +// compile-flags: -Zmiri-disable-validation -Zmiri-seed=0000000000000000 + +fn main() { + let g = unsafe { + std::mem::transmute::(42) + }; + + g(42) //~ ERROR dangling pointer was dereferenced +} diff --git a/tests/compile-fail/intptrcast_null_pointer_deref.rs b/tests/compile-fail/intptrcast_null_pointer_deref.rs new file mode 100644 index 0000000000000..0c5d46609cf83 --- /dev/null +++ b/tests/compile-fail/intptrcast_null_pointer_deref.rs @@ -0,0 +1,6 @@ +// compile-flags: -Zmiri-seed=0000000000000000 + +fn main() { + 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/intptrcast_wild_pointer_deref.rs b/tests/compile-fail/intptrcast_wild_pointer_deref.rs new file mode 100644 index 0000000000000..2ee664eb68bd3 --- /dev/null +++ b/tests/compile-fail/intptrcast_wild_pointer_deref.rs @@ -0,0 +1,7 @@ +// compile-flags: -Zmiri-seed=0000000000000000 + +fn main() { + let p = 44 as *const i32; + let x = unsafe { *p }; //~ ERROR dangling pointer was dereferenced + panic!("this should never print: {}", x); +} From 72c269eebe15141a570ad72a0e6bb87cc59fdc5e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 22 Jun 2019 11:05:12 +0200 Subject: [PATCH 0838/3747] fix compilation with latest rustc --- rust-version | 2 +- src/intrinsic.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/rust-version b/rust-version index f09338fca150f..5422121beb5ff 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -56a12b2ad058f22f1ef090713df15598525ba4a4 +305930cffeac1da0fd73a08d9f5680e4a49bfb9f diff --git a/src/intrinsic.rs b/src/intrinsic.rs index 0ecccd02d7e1b..33bab4642a90d 100644 --- a/src/intrinsic.rs +++ b/src/intrinsic.rs @@ -505,7 +505,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let ptr = mplace.ptr.to_ptr()?; this.memory_mut() .get_mut(ptr.alloc_id)? - .mark_definedness(ptr, dest.layout.size, false)?; + .mark_definedness(ptr, dest.layout.size, false); } } } From 2b1eeb39286c8f504c16e6d92da5d8dd1eac1845 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 22 Jun 2019 11:13:35 +0200 Subject: [PATCH 0839/3747] also run tests for cron jobs --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index e78c4b9b8b4fa..7db62bc74bd43 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,7 +13,7 @@ os: dist: xenial # Run in PRs and for bors, but not on master. -if: branch = auto OR branch = try OR type = pull_request +if: branch = auto OR branch = try OR type = pull_request OR type = cron env: global: From dd732e5862ba4601959bbae7993eb4924ddf8ee6 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Sat, 22 Jun 2019 09:25:16 -0500 Subject: [PATCH 0840/3747] Force intptrcast for binary operations --- src/lib.rs | 16 +++++++++------- src/operator.rs | 10 ++++++++++ tests/run-pass/intptrcast-truncate.rs | 8 ++++++++ 3 files changed, 27 insertions(+), 7 deletions(-) create mode 100644 tests/run-pass/intptrcast-truncate.rs diff --git a/src/lib.rs b/src/lib.rs index f61abea62e0b6..17b20d003e93d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -637,15 +637,17 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { let alloc = memory.get(ptr.alloc_id)?; - let base_addr = match alloc.extra.base_addr.borrow().clone() { - Some(base_addr) => base_addr, + let mut base_addr = alloc.extra.base_addr.borrow_mut(); + + let addr = match *base_addr { + Some(addr) => addr, None => { - let base_addr = extra.addr; + let addr = extra.addr; extra.addr += alloc.bytes.len() as u64; - *alloc.extra.base_addr.borrow_mut() = Some(base_addr); + *base_addr = Some(addr); - let elem = (base_addr, ptr.alloc_id); + let elem = (addr, ptr.alloc_id); if let Err(pos) = extra.vec.binary_search(&elem) { extra.vec.insert(pos, elem); @@ -653,10 +655,10 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { return err!(Unreachable); } - base_addr + addr } }; - Ok(base_addr + ptr.offset.bytes()) + Ok(addr + ptr.offset.bytes()) } } diff --git a/src/operator.rs b/src/operator.rs index b05d435ef644e..7dd3b3526cdc0 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -44,6 +44,16 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { trace!("ptr_op: {:?} {:?} {:?}", *left, bin_op, *right); + if self.memory().extra.seed.is_some() && bin_op != Offset { + let l_bits = self.force_bits(left.imm.to_scalar()?, left.layout.size)?; + let r_bits = self.force_bits(right.imm.to_scalar()?, right.layout.size)?; + + let left = ImmTy::from_scalar(Scalar::from_uint(l_bits, left.layout.size), left.layout); + let right = ImmTy::from_scalar(Scalar::from_uint(r_bits, left.layout.size), right.layout); + + return self.binary_op(bin_op, left, right); + } + // Operations that support fat pointers match bin_op { Eq | Ne => { diff --git a/tests/run-pass/intptrcast-truncate.rs b/tests/run-pass/intptrcast-truncate.rs new file mode 100644 index 0000000000000..7c49af87f8865 --- /dev/null +++ b/tests/run-pass/intptrcast-truncate.rs @@ -0,0 +1,8 @@ +// compile-flags: -Zmiri-seed=0000000000000000 + +fn main() { + let x = &42 as *const i32 as usize; + let y = x * 2; + let z = y as u8 as usize; + assert_eq!(z, y % 256); +} From 4dc188a60eb19dc770db071a5e368e90b5a1fab3 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 23 Jun 2019 17:26:12 +0200 Subject: [PATCH 0841/3747] adjust for refactored memory pointer checks --- src/fn_call.rs | 5 ++- src/intrinsic.rs | 15 ++++--- src/operator.rs | 41 +++++++++++++------- src/stacked_borrows.rs | 7 ++-- tests/compile-fail/ptr_eq_dangling.rs | 2 +- tests/compile-fail/ptr_eq_out_of_bounds.rs | 2 +- tests/compile-fail/rc_as_raw.rs | 2 + tests/compile-fail/unaligned_ptr_cast1.rs | 4 +- tests/compile-fail/unaligned_ptr_cast2.rs | 4 +- tests/compile-fail/validity/dangling_ref1.rs | 2 +- tests/compile-fail/validity/dangling_ref2.rs | 2 +- tests/compile-fail/zst.rs | 4 -- tests/compile-fail/zst1.rs | 5 +++ tests/compile-fail/zst2.rs | 12 ++++++ tests/compile-fail/zst3.rs | 15 +++++++ tests/run-pass/zst.rs | 9 ----- 16 files changed, 86 insertions(+), 45 deletions(-) delete mode 100644 tests/compile-fail/zst.rs create mode 100644 tests/compile-fail/zst1.rs create mode 100644 tests/compile-fail/zst2.rs create mode 100644 tests/compile-fail/zst3.rs diff --git a/src/fn_call.rs b/src/fn_call.rs index eca1d9144ec4e..b053d8c51e70c 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -654,7 +654,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Hook pthread calls that go to the thread-local storage memory subsystem. "pthread_key_create" => { - let key_ptr = this.read_scalar(args[0])?.to_ptr()?; + let key_ptr = this.read_scalar(args[0])?.not_undef()?; // Extract the function type out of the signature (that seems easier than constructing it ourselves). let dtor = match this.read_scalar(args[1])?.not_undef()? { @@ -681,7 +681,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx return err!(OutOfTls); } - this.memory().check_align(key_ptr.into(), key_layout.align.abi)?; + let key_ptr = this.memory().check_ptr_access(key_ptr, key_layout.size, key_layout.align.abi)? + .expect("cannot be a ZST"); this.memory_mut().get_mut(key_ptr.alloc_id)?.write_scalar( tcx, key_ptr, diff --git a/src/intrinsic.rs b/src/intrinsic.rs index 33bab4642a90d..3f9c4e53f09d6 100644 --- a/src/intrinsic.rs +++ b/src/intrinsic.rs @@ -517,13 +517,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let val_byte = this.read_scalar(args[1])?.to_u8()?; let ptr = this.read_scalar(args[0])?.not_undef()?; let count = this.read_scalar(args[2])?.to_usize(this)?; - this.memory().check_align(ptr, ty_layout.align.abi)?; let byte_count = ty_layout.size * count; - if byte_count.bytes() != 0 { - let ptr = ptr.to_ptr()?; - this.memory_mut() - .get_mut(ptr.alloc_id)? - .write_repeat(tcx, ptr, val_byte, byte_count)?; + match this.memory().check_ptr_access(ptr, byte_count, ty_layout.align.abi)? { + Some(ptr) => { + this.memory_mut() + .get_mut(ptr.alloc_id)? + .write_repeat(tcx, ptr, val_byte, byte_count)?; + } + None => { + // Size is 0, nothing to do. + } } } diff --git a/src/operator.rs b/src/operator.rs index b05d435ef644e..b735cbcba4ece 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -4,6 +4,11 @@ use rustc::mir; use crate::*; pub trait EvalContextExt<'tcx> { + fn pointer_inbounds( + &self, + ptr: Pointer + ) -> InterpResult<'tcx>; + fn ptr_op( &self, bin_op: mir::BinOp, @@ -34,6 +39,13 @@ pub trait EvalContextExt<'tcx> { } impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { + /// Test if the pointer is in-bounds of a live allocation. + #[inline] + fn pointer_inbounds(&self, ptr: Pointer) -> InterpResult<'tcx> { + let (size, _align) = self.memory().get_size_and_align(ptr.alloc_id, AllocCheck::Live)?; + ptr.check_in_alloc(size, CheckInAllocMsg::InboundsTest) + } + fn ptr_op( &self, bin_op: mir::BinOp, @@ -114,8 +126,8 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { let left = left.to_ptr().expect("we checked is_ptr"); let right = right.to_bits(self.memory().pointer_size()).expect("we checked is_bits"); let (_alloc_size, alloc_align) = self.memory() - .get_size_and_align(left.alloc_id, InboundsCheck::MaybeDead) - .expect("determining size+align of dead ptr cannot fail"); + .get_size_and_align(left.alloc_id, AllocCheck::MaybeDead) + .expect("alloc info with MaybeDead cannot fail"); let min_ptr_val = u128::from(alloc_align.bytes()) + u128::from(left.offset.bytes()); let result = match bin_op { Gt => min_ptr_val > right, @@ -170,6 +182,7 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { if left.alloc_id == right.alloc_id { left.offset == right.offset } else { + // Make sure both pointers are in-bounds. // This accepts one-past-the end. Thus, there is still technically // some non-determinism that we do not fully rule out when two // allocations sit right next to each other. The C/C++ standards are @@ -179,10 +192,12 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { // Dead allocations in miri cannot overlap with live allocations, but // on read hardware this can easily happen. Thus for comparisons we require // both pointers to be live. - self.memory().check_bounds_ptr(left, InboundsCheck::Live, CheckInAllocMsg::InboundsTest)?; - self.memory().check_bounds_ptr(right, InboundsCheck::Live, CheckInAllocMsg::InboundsTest)?; - // Two in-bounds pointers, we can compare across allocations. - left == right + if self.pointer_inbounds(left).is_ok() && self.pointer_inbounds(right).is_ok() { + // Two in-bounds pointers, we can compare across allocations. + left == right + } else { + return err!(InvalidPointerMath); + } } } // Comparing ptr and integer. @@ -202,16 +217,16 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { // alignment 32 or higher, hence the limit of 32. // FIXME: Once we support intptrcast, we could try to fix these holes. if bits < 32 { - // Test if the ptr is in-bounds. Then it cannot be NULL. - // Even dangling pointers cannot be NULL. - if self.memory().check_bounds_ptr(ptr, InboundsCheck::MaybeDead, CheckInAllocMsg::NullPointerTest).is_ok() { + // Test if the pointer can be different from NULL or not. + // We assume that pointers that are not NULL are also not "small". + if !self.memory().ptr_may_be_null(ptr) { return Ok(false); } } let (alloc_size, alloc_align) = self.memory() - .get_size_and_align(ptr.alloc_id, InboundsCheck::MaybeDead) - .expect("determining size+align of dead ptr cannot fail"); + .get_size_and_align(ptr.alloc_id, AllocCheck::MaybeDead) + .expect("alloc info with MaybeDead cannot fail"); // Case II: Alignment gives it away if ptr.offset.bytes() % alloc_align.bytes() == 0 { @@ -359,9 +374,9 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { if let Scalar::Ptr(ptr) = ptr { // Both old and new pointer must be in-bounds of a *live* allocation. // (Of the same allocation, but that part is trivial with our representation.) - self.memory().check_bounds_ptr(ptr, InboundsCheck::Live, CheckInAllocMsg::InboundsTest)?; + self.pointer_inbounds(ptr)?; let ptr = ptr.signed_offset(offset, self)?; - self.memory().check_bounds_ptr(ptr, InboundsCheck::Live, CheckInAllocMsg::InboundsTest)?; + self.pointer_inbounds(ptr)?; Ok(Scalar::Ptr(ptr)) } else { // An integer pointer. They can only be offset by 0, and we pretend there diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index f7617676701c5..3a0c257428e11 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -10,7 +10,7 @@ use rustc::mir::RetagKind; use crate::{ InterpResult, InterpError, MiriEvalContext, HelpersEvalContextExt, Evaluator, MutValueVisitor, - MemoryKind, MiriMemoryKind, RangeMap, Allocation, AllocationExtra, AllocId, CheckInAllocMsg, + MemoryKind, MiriMemoryKind, RangeMap, Allocation, AllocationExtra, AllocId, Pointer, Immediate, ImmTy, PlaceTy, MPlaceTy, }; @@ -531,13 +531,14 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let protector = if protect { Some(this.frame().extra) } else { None }; - let ptr = place.ptr.to_ptr()?; + let ptr = this.memory().check_ptr_access(place.ptr, size, place.align) + .expect("validity checks should have excluded dangling/unaligned pointer") + .expect("we shouldn't get here for ZST"); trace!("reborrow: {} reference {:?} derived from {:?} (pointee {}): {:?}, size {}", kind, new_tag, ptr.tag, place.layout.ty, ptr.erase_tag(), size.bytes()); // Get the allocation. It might not be mutable, so we cannot use `get_mut`. let alloc = this.memory().get(ptr.alloc_id)?; - alloc.check_bounds(this, ptr, size, CheckInAllocMsg::InboundsTest)?; // Update the stacks. // Make sure that raw pointers and mutable shared references are reborrowed "weak": // There could be existing unique pointers reborrowed from them that should remain valid! diff --git a/tests/compile-fail/ptr_eq_dangling.rs b/tests/compile-fail/ptr_eq_dangling.rs index d05996a13d562..5badf099e4391 100644 --- a/tests/compile-fail/ptr_eq_dangling.rs +++ b/tests/compile-fail/ptr_eq_dangling.rs @@ -6,5 +6,5 @@ fn main() { let y = &*b as *const i32; // different allocation // We cannot compare these even though both are inbounds -- they *could* be // equal if memory was reused. - assert!(x != y); //~ ERROR dangling pointer + assert!(x != y); //~ ERROR invalid arithmetic on pointers } diff --git a/tests/compile-fail/ptr_eq_out_of_bounds.rs b/tests/compile-fail/ptr_eq_out_of_bounds.rs index af4eed8d4e32d..7efa446d7fca4 100644 --- a/tests/compile-fail/ptr_eq_out_of_bounds.rs +++ b/tests/compile-fail/ptr_eq_out_of_bounds.rs @@ -5,5 +5,5 @@ fn main() { let y = &*b as *const i32; // different allocation // We cannot compare these even though both allocations are live -- they *could* be // equal (with the right base addresses). - assert!(x != y); //~ ERROR outside bounds + assert!(x != y); //~ ERROR invalid arithmetic on pointers } diff --git a/tests/compile-fail/rc_as_raw.rs b/tests/compile-fail/rc_as_raw.rs index 3e6e96456fca6..086467eea311b 100644 --- a/tests/compile-fail/rc_as_raw.rs +++ b/tests/compile-fail/rc_as_raw.rs @@ -1,3 +1,5 @@ +// This should fail even without validation +// compile-flags: -Zmiri-disable-validation #![feature(weak_into_raw)] use std::rc::{Rc, Weak}; diff --git a/tests/compile-fail/unaligned_ptr_cast1.rs b/tests/compile-fail/unaligned_ptr_cast1.rs index e64594d3e7eda..92e1fae75a045 100644 --- a/tests/compile-fail/unaligned_ptr_cast1.rs +++ b/tests/compile-fail/unaligned_ptr_cast1.rs @@ -2,8 +2,8 @@ // compile-flags: -Zmiri-disable-validation fn main() { - let x = &2u16; - let x = x as *const _ as *const u32; + let x = [2u16, 3, 4]; // Make it big enough so we don't get an out-of-bounds error. + let x = &x[0] as *const _ as *const u32; // This must fail because alignment is violated let _x = unsafe { *x }; //~ ERROR tried to access memory with alignment 2, but alignment 4 is required } diff --git a/tests/compile-fail/unaligned_ptr_cast2.rs b/tests/compile-fail/unaligned_ptr_cast2.rs index 9fb138e353fe7..783661c557103 100644 --- a/tests/compile-fail/unaligned_ptr_cast2.rs +++ b/tests/compile-fail/unaligned_ptr_cast2.rs @@ -2,8 +2,8 @@ // compile-flags: -Zmiri-disable-validation fn main() { - let x = &2u16; - let x = x as *const _ as *const *const u8; + let x = [2u16, 3, 4, 5]; // Make it big enough so we don't get an out-of-bounds error. + let x = &x[0] as *const _ as *const *const u8; // This must fail because alignment is violated. Test specifically for loading pointers, // which have special code in miri's memory. let _x = unsafe { *x }; diff --git a/tests/compile-fail/validity/dangling_ref1.rs b/tests/compile-fail/validity/dangling_ref1.rs index c5845cb693bb3..4318c7c90271f 100644 --- a/tests/compile-fail/validity/dangling_ref1.rs +++ b/tests/compile-fail/validity/dangling_ref1.rs @@ -1,5 +1,5 @@ use std::mem; fn main() { - let _x: &i32 = unsafe { mem::transmute(16usize) }; //~ ERROR tried to interpret some bytes as a pointer + let _x: &i32 = unsafe { mem::transmute(16usize) }; //~ ERROR integer pointer in non-ZST reference } diff --git a/tests/compile-fail/validity/dangling_ref2.rs b/tests/compile-fail/validity/dangling_ref2.rs index 21650ebf95067..ef76b93d11e2d 100644 --- a/tests/compile-fail/validity/dangling_ref2.rs +++ b/tests/compile-fail/validity/dangling_ref2.rs @@ -3,5 +3,5 @@ use std::mem; fn main() { let val = 14; let ptr = (&val as *const i32).wrapping_offset(1); - let _x: &i32 = unsafe { mem::transmute(ptr) }; //~ ERROR outside bounds of allocation + let _x: &i32 = unsafe { mem::transmute(ptr) }; //~ ERROR encountered dangling (not entirely in bounds) reference } diff --git a/tests/compile-fail/zst.rs b/tests/compile-fail/zst.rs deleted file mode 100644 index 0488926870a21..0000000000000 --- a/tests/compile-fail/zst.rs +++ /dev/null @@ -1,4 +0,0 @@ -fn main() { - let x = &() as *const () as *const i32; - let _val = unsafe { *x }; //~ ERROR access memory with alignment 1, but alignment 4 is required -} diff --git a/tests/compile-fail/zst1.rs b/tests/compile-fail/zst1.rs new file mode 100644 index 0000000000000..e4ce7b8ecdf8c --- /dev/null +++ b/tests/compile-fail/zst1.rs @@ -0,0 +1,5 @@ +fn main() { + // make sure ZST locals cannot be accessed + let x = &() as *const () as *const i8; + let _val = unsafe { *x }; //~ ERROR pointer must be in-bounds +} diff --git a/tests/compile-fail/zst2.rs b/tests/compile-fail/zst2.rs new file mode 100644 index 0000000000000..950f7b3d60e6d --- /dev/null +++ b/tests/compile-fail/zst2.rs @@ -0,0 +1,12 @@ +fn main() { + // Not using the () type here, as writes of that type do not even have MIR generated. + // Also not assigning directly as that's array initialization, not assignment. + let zst_val = [1u8; 0]; + + // make sure ZST accesses are checked against being "truly" dangling pointers + // (into deallocated allocations). + let mut x_box = Box::new(1u8); + let x = &mut *x_box as *mut _ as *mut [u8; 0]; + drop(x_box); + unsafe { *x = zst_val; } //~ ERROR dangling pointer was dereferenced +} diff --git a/tests/compile-fail/zst3.rs b/tests/compile-fail/zst3.rs new file mode 100644 index 0000000000000..a16ec0186d776 --- /dev/null +++ b/tests/compile-fail/zst3.rs @@ -0,0 +1,15 @@ +fn main() { + // Not using the () type here, as writes of that type do not even have MIR generated. + // Also not assigning directly as that's array initialization, not assignment. + let zst_val = [1u8; 0]; + + // make sure ZST accesses are checked against being "truly" dangling pointers + // (that are out-of-bounds). + let mut x_box = Box::new(1u8); + let x = (&mut *x_box as *mut u8).wrapping_offset(1); + // This one is just "at the egde", but still okay + unsafe { *(x as *mut [u8; 0]) = zst_val; } + // One byte further is OOB. + let x = x.wrapping_offset(1); + unsafe { *(x as *mut [u8; 0]) = zst_val; } //~ ERROR pointer must be in-bounds +} diff --git a/tests/run-pass/zst.rs b/tests/run-pass/zst.rs index 9d97210b73db6..9884735709139 100644 --- a/tests/run-pass/zst.rs +++ b/tests/run-pass/zst.rs @@ -21,13 +21,4 @@ fn main() { // Reading and writing is ok. unsafe { *x = zst_val; } unsafe { let _y = *x; } - - // We should even be able to use "true" pointers for ZST when the allocation has been - // removed already. The box is for a non-ZST to make sure there actually is an allocation. - let mut x_box = Box::new(((), 1u8)); - let x = &mut x_box.0 as *mut _ as *mut [u8; 0]; - drop(x_box); - // Reading and writing is ok. - unsafe { *x = zst_val; } - unsafe { let _y = *x; } } From 69e8318b602d0b6bab2dee9bc3476e831b6ea5a6 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 23 Jun 2019 20:30:33 +0200 Subject: [PATCH 0842/3747] de-obfuscate ptr comparison a bit --- src/operator.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/operator.rs b/src/operator.rs index b735cbcba4ece..5d1f33a570938 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -193,8 +193,8 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { // on read hardware this can easily happen. Thus for comparisons we require // both pointers to be live. if self.pointer_inbounds(left).is_ok() && self.pointer_inbounds(right).is_ok() { - // Two in-bounds pointers, we can compare across allocations. - left == right + // Two in-bounds pointers in different allocatons are different. + false } else { return err!(InvalidPointerMath); } From 4d65aa8f20ac80f7517af15f2dec8936325119c6 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 24 Jun 2019 08:40:45 +0200 Subject: [PATCH 0843/3747] expand and better explain alignment check tests --- .../{unaligned_ptr_cast1.rs => unaligned_ptr1.rs} | 2 +- tests/compile-fail/unaligned_ptr2.rs | 10 ++++++++++ .../{unaligned_ptr_cast2.rs => unaligned_ptr3.rs} | 2 +- ...{unaligned_ptr_cast_zst.rs => unaligned_ptr_zst.rs} | 3 +++ 4 files changed, 15 insertions(+), 2 deletions(-) rename tests/compile-fail/{unaligned_ptr_cast1.rs => unaligned_ptr1.rs} (76%) create mode 100644 tests/compile-fail/unaligned_ptr2.rs rename tests/compile-fail/{unaligned_ptr_cast2.rs => unaligned_ptr3.rs} (81%) rename tests/compile-fail/{unaligned_ptr_cast_zst.rs => unaligned_ptr_zst.rs} (75%) diff --git a/tests/compile-fail/unaligned_ptr_cast1.rs b/tests/compile-fail/unaligned_ptr1.rs similarity index 76% rename from tests/compile-fail/unaligned_ptr_cast1.rs rename to tests/compile-fail/unaligned_ptr1.rs index 92e1fae75a045..bcc4192d7d2ae 100644 --- a/tests/compile-fail/unaligned_ptr_cast1.rs +++ b/tests/compile-fail/unaligned_ptr1.rs @@ -4,6 +4,6 @@ fn main() { let x = [2u16, 3, 4]; // Make it big enough so we don't get an out-of-bounds error. let x = &x[0] as *const _ as *const u32; - // This must fail because alignment is violated + // This must fail because alignment is violated: the allocation's base is not sufficiently aligned. let _x = unsafe { *x }; //~ ERROR tried to access memory with alignment 2, but alignment 4 is required } diff --git a/tests/compile-fail/unaligned_ptr2.rs b/tests/compile-fail/unaligned_ptr2.rs new file mode 100644 index 0000000000000..225bd14ade619 --- /dev/null +++ b/tests/compile-fail/unaligned_ptr2.rs @@ -0,0 +1,10 @@ +// This should fail even without validation. +// compile-flags: -Zmiri-disable-validation + +fn main() { + let x = [2u32, 3]; // Make it big enough so we don't get an out-of-bounds error. + let x = (x.as_ptr() as *const u8).wrapping_offset(3) as *const u32; + // This must fail because alignment is violated: the offset is not sufficiently aligned. + // Also make the offset not a power of 2, that used to ICE. + let _x = unsafe { *x }; //~ ERROR tried to access memory with alignment 1, but alignment 4 is required +} diff --git a/tests/compile-fail/unaligned_ptr_cast2.rs b/tests/compile-fail/unaligned_ptr3.rs similarity index 81% rename from tests/compile-fail/unaligned_ptr_cast2.rs rename to tests/compile-fail/unaligned_ptr3.rs index 783661c557103..f33a80d4588b5 100644 --- a/tests/compile-fail/unaligned_ptr_cast2.rs +++ b/tests/compile-fail/unaligned_ptr3.rs @@ -3,7 +3,7 @@ fn main() { let x = [2u16, 3, 4, 5]; // Make it big enough so we don't get an out-of-bounds error. - let x = &x[0] as *const _ as *const *const u8; + let x = &x[0] as *const _ as *const *const u8; // cast to ptr-to-ptr, so that we load a ptr // This must fail because alignment is violated. Test specifically for loading pointers, // which have special code in miri's memory. let _x = unsafe { *x }; diff --git a/tests/compile-fail/unaligned_ptr_cast_zst.rs b/tests/compile-fail/unaligned_ptr_zst.rs similarity index 75% rename from tests/compile-fail/unaligned_ptr_cast_zst.rs rename to tests/compile-fail/unaligned_ptr_zst.rs index d52b569175c1d..127ec04027d1a 100644 --- a/tests/compile-fail/unaligned_ptr_cast_zst.rs +++ b/tests/compile-fail/unaligned_ptr_zst.rs @@ -1,3 +1,6 @@ +// This should fail even without validation +// compile-flags: -Zmiri-disable-validation + fn main() { let x = &2u16; let x = x as *const _ as *const [u32; 0]; From 7e7b5d42ba321aa4cc3da5e1da222344597b0c1d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 24 Jun 2019 14:50:27 +0200 Subject: [PATCH 0844/3747] Apply suggestions from code review Co-Authored-By: Oliver Scherer --- src/operator.rs | 2 +- tests/compile-fail/zst3.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/operator.rs b/src/operator.rs index 5d1f33a570938..cb258cf150d75 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -193,7 +193,7 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { // on read hardware this can easily happen. Thus for comparisons we require // both pointers to be live. if self.pointer_inbounds(left).is_ok() && self.pointer_inbounds(right).is_ok() { - // Two in-bounds pointers in different allocatons are different. + // Two in-bounds pointers in different allocations are different. false } else { return err!(InvalidPointerMath); diff --git a/tests/compile-fail/zst3.rs b/tests/compile-fail/zst3.rs index a16ec0186d776..c94591174ec5c 100644 --- a/tests/compile-fail/zst3.rs +++ b/tests/compile-fail/zst3.rs @@ -7,7 +7,7 @@ fn main() { // (that are out-of-bounds). let mut x_box = Box::new(1u8); let x = (&mut *x_box as *mut u8).wrapping_offset(1); - // This one is just "at the egde", but still okay + // This one is just "at the edge", but still okay unsafe { *(x as *mut [u8; 0]) = zst_val; } // One byte further is OOB. let x = x.wrapping_offset(1); From 2861ceb2fa1acc2c642abd4f2efb96c713a47e29 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Mon, 24 Jun 2019 10:03:16 -0500 Subject: [PATCH 0845/3747] Rename new fields and move rng to MemoryExtra --- src/fn_call.rs | 2 +- src/intptrcast.rs | 10 +++++---- src/lib.rs | 55 ++++++++++++++++++++--------------------------- src/memory.rs | 9 +++++--- src/operator.rs | 2 +- 5 files changed, 37 insertions(+), 41 deletions(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index eca1d9144ec4e..e47e216912117 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -979,7 +979,7 @@ fn gen_random<'mir, 'tcx>( } let ptr = dest.to_ptr()?; - let data = match &mut this.machine.rng { + let data = match &mut this.memory_mut().extra.rng { Some(rng) => { let mut data = vec![0; len]; rng.fill_bytes(&mut data); diff --git a/src/intptrcast.rs b/src/intptrcast.rs index 3e07f54fbd3e8..f95cf0fda46b2 100644 --- a/src/intptrcast.rs +++ b/src/intptrcast.rs @@ -6,15 +6,17 @@ pub type MemoryState = RefCell; #[derive(Clone, Debug)] pub struct GlobalState { - pub vec: Vec<(u64, AllocId)>, - pub addr: u64, + /// This field is used as a map between the address of each allocation and its `AllocId` + pub int_to_ptr_map: Vec<(u64, AllocId)>, + pub next_base_addr: u64, } impl Default for GlobalState { + // FIXME: Query the page size in the future fn default() -> Self { GlobalState { - vec: Vec::default(), - addr: 2u64.pow(16) + int_to_ptr_map: Vec::default(), + next_base_addr: 2u64.pow(16) } } } diff --git a/src/lib.rs b/src/lib.rs index 17b20d003e93d..5288537f20ee8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -25,7 +25,7 @@ mod memory; use std::collections::HashMap; use std::borrow::Cow; -use std::cell::RefCell; +use std::cell::Cell; use std::rc::Rc; use rand::rngs::StdRng; @@ -83,9 +83,11 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( let mut ecx = InterpretCx::new( tcx.at(syntax::source_map::DUMMY_SP), ty::ParamEnv::reveal_all(), - Evaluator::new(config.validate, config.seed), + Evaluator::new(config.validate), ); + ecx.memory_mut().extra.rng = config.seed.map(StdRng::seed_from_u64); + let main_instance = ty::Instance::mono(ecx.tcx.tcx, main_id); let main_mir = ecx.load_mir(main_instance.def)?; @@ -209,9 +211,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( cur_ptr = cur_ptr.offset(char_size, tcx)?; } } - - ecx.memory_mut().extra.seed = config.seed.clone(); - + assert!(args.next().is_none(), "start lang item has more arguments than expected"); Ok(ecx) @@ -347,14 +347,10 @@ pub struct Evaluator<'tcx> { /// Whether to enforce the validity invariant. pub(crate) validate: bool, - - /// The random number generator to use if Miri - /// is running in non-deterministic mode - pub(crate) rng: Option } impl<'tcx> Evaluator<'tcx> { - fn new(validate: bool, seed: Option) -> Self { + fn new(validate: bool) -> Self { Evaluator { env_vars: HashMap::default(), argc: None, @@ -363,7 +359,6 @@ impl<'tcx> Evaluator<'tcx> { last_error: 0, tls: TlsData::default(), validate, - rng: seed.map(|s| StdRng::seed_from_u64(s)) } } } @@ -543,7 +538,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { mutability: alloc.mutability, extra: AllocExtra { stacks: extra, - base_addr: RefCell::new(None), + base_addr: Cell::new(None), }, }; (Cow::Owned(alloc), base_tag) @@ -598,20 +593,20 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { return err!(InvalidNullPointerUsage); } - if memory.extra.seed.is_none() { + if memory.extra.rng.is_none() { return err!(ReadBytesAsPointer); } let extra = memory.extra.intptrcast.borrow(); - match extra.vec.binary_search_by_key(&int, |(int, _)| *int) { + match extra.int_to_ptr_map.binary_search_by_key(&int, |(int, _)| *int) { Ok(pos) => { - let (_, alloc_id) = extra.vec[pos]; + let (_, alloc_id) = extra.int_to_ptr_map[pos]; Ok(Pointer::new_with_tag(alloc_id, Size::from_bytes(0), Tag::Untagged)) } Err(pos) => { if pos > 0 { - let (glb, alloc_id) = extra.vec[pos - 1]; + let (glb, alloc_id) = extra.int_to_ptr_map[pos - 1]; let offset = int - glb; if offset <= memory.get(alloc_id)?.bytes.len() as u64 { Ok(Pointer::new_with_tag(alloc_id, Size::from_bytes(offset), Tag::Untagged)) @@ -629,7 +624,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { ptr: Pointer, memory: &Memory<'mir, 'tcx, Self>, ) -> InterpResult<'tcx, u64> { - if memory.extra.seed.is_none() { + if memory.extra.rng.is_none() { return err!(ReadPointerAsBytes); } @@ -637,28 +632,24 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { let alloc = memory.get(ptr.alloc_id)?; - let mut base_addr = alloc.extra.base_addr.borrow_mut(); - - let addr = match *base_addr { - Some(addr) => addr, + let base_addr = match alloc.extra.base_addr.get() { + Some(base_addr) => base_addr, None => { - let addr = extra.addr; - extra.addr += alloc.bytes.len() as u64; + let base_addr = extra.next_base_addr; + extra.next_base_addr += alloc.bytes.len() as u64; - *base_addr = Some(addr); + alloc.extra.base_addr.set(Some(base_addr)); - let elem = (addr, ptr.alloc_id); + let elem = (base_addr, ptr.alloc_id); - if let Err(pos) = extra.vec.binary_search(&elem) { - extra.vec.insert(pos, elem); - } else { - return err!(Unreachable); - } + // Given that `next_base_addr` increases in each allocation, pushing the + // corresponding tuple keeps `int_to_ptr_map` sorted + extra.int_to_ptr_map.push(elem); - addr + base_addr } }; - Ok(addr + ptr.offset.bytes()) + Ok(base_addr + ptr.offset.bytes()) } } diff --git a/src/memory.rs b/src/memory.rs index 13ffd859adefa..fafa9272bacd1 100644 --- a/src/memory.rs +++ b/src/memory.rs @@ -1,4 +1,5 @@ -use std::cell::RefCell; +use std::cell::Cell; +use rand::rngs::StdRng; use rustc_mir::interpret::{Pointer, Allocation, AllocationExtra, InterpResult}; use rustc_target::abi::Size; @@ -10,13 +11,15 @@ use crate::stacked_borrows::{Tag, AccessKind}; pub struct MemoryState { pub stacked: stacked_borrows::MemoryState, pub intptrcast: intptrcast::MemoryState, - pub seed: Option, + /// The random number generator to use if Miri + /// is running in non-deterministic mode + pub(crate) rng: Option } #[derive(Debug, Clone,)] pub struct AllocExtra { pub stacks: stacked_borrows::Stacks, - pub base_addr: RefCell>, + pub base_addr: Cell>, } impl AllocationExtra for AllocExtra { diff --git a/src/operator.rs b/src/operator.rs index 7dd3b3526cdc0..0ebb1e71610a6 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -44,7 +44,7 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { trace!("ptr_op: {:?} {:?} {:?}", *left, bin_op, *right); - if self.memory().extra.seed.is_some() && bin_op != Offset { + if self.memory().extra.rng.is_some() && bin_op != Offset { let l_bits = self.force_bits(left.imm.to_scalar()?, left.layout.size)?; let r_bits = self.force_bits(right.imm.to_scalar()?, right.layout.size)?; From b66cf703684b3678aae162ced43c6846f105a681 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 24 Jun 2019 23:58:12 +0200 Subject: [PATCH 0846/3747] bump Rust commit --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 5422121beb5ff..17338728254ad 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -305930cffeac1da0fd73a08d9f5680e4a49bfb9f +7e08576e4276a97b523c25bfd196d419c39c7b87 From 84cfbb01b7ad4c4ba3f3b987ef8c3f562c9e57cb Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Mon, 24 Jun 2019 16:34:38 -0500 Subject: [PATCH 0847/3747] Reorganize MemoryExtra and AllocExtra structures --- src/intptrcast.rs | 83 ++++++++++++++++++++++++++++++++++++++++-- src/lib.rs | 79 +++++++++------------------------------- src/memory.rs | 36 ++++++------------ src/operator.rs | 3 ++ src/stacked_borrows.rs | 61 +++++++++++++++++++++++++------ 5 files changed, 161 insertions(+), 101 deletions(-) diff --git a/src/intptrcast.rs b/src/intptrcast.rs index f95cf0fda46b2..c48e7b7772b1d 100644 --- a/src/intptrcast.rs +++ b/src/intptrcast.rs @@ -1,13 +1,26 @@ -use std::cell::RefCell; +use std::cell::{Cell, RefCell}; -use rustc::mir::interpret::AllocId; +use rustc::mir::interpret::{AllocId, Pointer, InterpResult}; +use rustc_mir::interpret::Memory; +use rustc_target::abi::Size; -pub type MemoryState = RefCell; +use crate::stacked_borrows::Tag; +use crate::Evaluator; + +pub type MemoryExtra = RefCell; + +#[derive(Clone, Debug, Default)] +pub struct AllocExtra { + base_addr: Cell> +} #[derive(Clone, Debug)] pub struct GlobalState { - /// This field is used as a map between the address of each allocation and its `AllocId` + /// This is used as a map between the address of each allocation and its `AllocId`. + /// It is always sorted pub int_to_ptr_map: Vec<(u64, AllocId)>, + /// This is used as a memory address when a new pointer is casted to an integer. It + /// is always larger than any address that was previously made part of a block. pub next_base_addr: u64, } @@ -20,3 +33,65 @@ impl Default for GlobalState { } } } + +impl<'mir, 'tcx> GlobalState { + pub fn int_to_ptr( + base_addr: u64, + memory: &Memory<'mir, 'tcx, Evaluator<'tcx>>, + ) -> InterpResult<'tcx, Pointer> { + let global_state = memory.extra.intptrcast.borrow(); + + match global_state.int_to_ptr_map.binary_search_by_key(&base_addr, |(addr, _)| *addr) { + Ok(pos) => { + let (_, alloc_id) = global_state.int_to_ptr_map[pos]; + // `base_addr` is the starting address for an allocation, the offset should be + // zero. The pointer is untagged because it was created from a cast + Ok(Pointer::new_with_tag(alloc_id, Size::from_bytes(0), Tag::Untagged)) + }, + Err(0) => err!(DanglingPointerDeref), + Err(pos) => { + // This is the gargest of the adresses smaller than `base_addr`, + // i.e. the greatest lower bound (glb) + let (glb, alloc_id) = global_state.int_to_ptr_map[pos - 1]; + // This never overflows because `base_addr >= glb` + let offset = base_addr - glb; + // If the offset exceeds the size of the allocation, this access is illegal + if offset <= memory.get(alloc_id)?.bytes.len() as u64 { + // This pointer is untagged because it was created from a cast + Ok(Pointer::new_with_tag(alloc_id, Size::from_bytes(offset), Tag::Untagged)) + } else { + err!(DanglingPointerDeref) + } + } + } + } + + pub fn ptr_to_int( + ptr: Pointer, + memory: &Memory<'mir, 'tcx, Evaluator<'tcx>>, + ) -> InterpResult<'tcx, u64> { + let mut global_state = memory.extra.intptrcast.borrow_mut(); + + let alloc = memory.get(ptr.alloc_id)?; + + let base_addr = match alloc.extra.intptrcast.base_addr.get() { + Some(base_addr) => base_addr, + None => { + let base_addr = global_state.next_base_addr; + global_state.next_base_addr += alloc.bytes.len() as u64; + + alloc.extra.intptrcast.base_addr.set(Some(base_addr)); + + let elem = (base_addr, ptr.alloc_id); + + // Given that `next_base_addr` increases in each allocation, pushing the + // corresponding tuple keeps `int_to_ptr_map` sorted + global_state.int_to_ptr_map.push(elem); + + base_addr + } + }; + + Ok(base_addr + ptr.offset.bytes()) + } +} diff --git a/src/lib.rs b/src/lib.rs index 5288537f20ee8..77acd3045da57 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -25,7 +25,6 @@ mod memory; use std::collections::HashMap; use std::borrow::Cow; -use std::cell::Cell; use std::rc::Rc; use rand::rngs::StdRng; @@ -387,7 +386,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { type MemoryKinds = MiriMemoryKind; type FrameExtra = stacked_borrows::CallId; - type MemoryExtra = memory::MemoryState; + type MemoryExtra = memory::MemoryExtra; type AllocExtra = memory::AllocExtra; type PointerTag = Tag; @@ -513,17 +512,17 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { ) -> (Cow<'b, Allocation>, Self::PointerTag) { let kind = kind.expect("we set our STATIC_KIND so this cannot be None"); let alloc = alloc.into_owned(); - let (extra, base_tag) = Stacks::new_allocation( + let (stacks, base_tag) = Stacks::new_allocation( id, Size::from_bytes(alloc.bytes.len() as u64), - Rc::clone(&memory.extra.stacked), + Rc::clone(&memory.extra.stacked_borrows), kind, ); if kind != MiriMemoryKind::Static.into() { assert!(alloc.relocations.is_empty(), "Only statics can come initialized with inner pointers"); // Now we can rely on the inner pointers being static, too. } - let mut memory_extra = memory.extra.stacked.borrow_mut(); + let mut memory_extra = memory.extra.stacked_borrows.borrow_mut(); let alloc: Allocation = Allocation { bytes: alloc.bytes, relocations: Relocations::from_presorted( @@ -537,8 +536,8 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { align: alloc.align, mutability: alloc.mutability, extra: AllocExtra { - stacks: extra, - base_addr: Cell::new(None), + stacked_borrows: stacks, + intptrcast: Default::default(), }, }; (Cow::Owned(alloc), base_tag) @@ -549,7 +548,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { id: AllocId, memory: &Memory<'mir, 'tcx, Self>, ) -> Self::PointerTag { - memory.extra.stacked.borrow_mut().static_base_ptr(id) + memory.extra.stacked_borrows.borrow_mut().static_base_ptr(id) } #[inline(always)] @@ -574,7 +573,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { fn stack_push( ecx: &mut InterpretCx<'mir, 'tcx, Self>, ) -> InterpResult<'tcx, stacked_borrows::CallId> { - Ok(ecx.memory().extra.stacked.borrow_mut().new_call()) + Ok(ecx.memory().extra.stacked_borrows.borrow_mut().new_call()) } #[inline(always)] @@ -582,7 +581,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { ecx: &mut InterpretCx<'mir, 'tcx, Self>, extra: stacked_borrows::CallId, ) -> InterpResult<'tcx> { - Ok(ecx.memory().extra.stacked.borrow_mut().end_call(extra)) + Ok(ecx.memory().extra.stacked_borrows.borrow_mut().end_call(extra)) } fn int_to_ptr( @@ -590,33 +589,11 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { memory: &Memory<'mir, 'tcx, Self>, ) -> InterpResult<'tcx, Pointer> { if int == 0 { - return err!(InvalidNullPointerUsage); - } - - if memory.extra.rng.is_none() { - return err!(ReadBytesAsPointer); - } - - let extra = memory.extra.intptrcast.borrow(); - - match extra.int_to_ptr_map.binary_search_by_key(&int, |(int, _)| *int) { - Ok(pos) => { - let (_, alloc_id) = extra.int_to_ptr_map[pos]; - Ok(Pointer::new_with_tag(alloc_id, Size::from_bytes(0), Tag::Untagged)) - } - Err(pos) => { - if pos > 0 { - let (glb, alloc_id) = extra.int_to_ptr_map[pos - 1]; - let offset = int - glb; - if offset <= memory.get(alloc_id)?.bytes.len() as u64 { - Ok(Pointer::new_with_tag(alloc_id, Size::from_bytes(offset), Tag::Untagged)) - } else { - return err!(DanglingPointerDeref); - } - } else { - return err!(DanglingPointerDeref); - } - } + err!(InvalidNullPointerUsage) + } else if memory.extra.rng.is_none() { + err!(ReadBytesAsPointer) + } else { + intptrcast::GlobalState::int_to_ptr(int, memory) } } @@ -625,31 +602,9 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { memory: &Memory<'mir, 'tcx, Self>, ) -> InterpResult<'tcx, u64> { if memory.extra.rng.is_none() { - return err!(ReadPointerAsBytes); + err!(ReadPointerAsBytes) + } else { + intptrcast::GlobalState::ptr_to_int(ptr, memory) } - - let mut extra = memory.extra.intptrcast.borrow_mut(); - - let alloc = memory.get(ptr.alloc_id)?; - - let base_addr = match alloc.extra.base_addr.get() { - Some(base_addr) => base_addr, - None => { - let base_addr = extra.next_base_addr; - extra.next_base_addr += alloc.bytes.len() as u64; - - alloc.extra.base_addr.set(Some(base_addr)); - - let elem = (base_addr, ptr.alloc_id); - - // Given that `next_base_addr` increases in each allocation, pushing the - // corresponding tuple keeps `int_to_ptr_map` sorted - extra.int_to_ptr_map.push(elem); - - base_addr - } - }; - - Ok(base_addr + ptr.offset.bytes()) } } diff --git a/src/memory.rs b/src/memory.rs index fafa9272bacd1..ea8f01a808c04 100644 --- a/src/memory.rs +++ b/src/memory.rs @@ -1,25 +1,24 @@ -use std::cell::Cell; use rand::rngs::StdRng; use rustc_mir::interpret::{Pointer, Allocation, AllocationExtra, InterpResult}; use rustc_target::abi::Size; use crate::{stacked_borrows, intptrcast}; -use crate::stacked_borrows::{Tag, AccessKind}; +use crate::stacked_borrows::Tag; #[derive(Default, Clone, Debug)] -pub struct MemoryState { - pub stacked: stacked_borrows::MemoryState, - pub intptrcast: intptrcast::MemoryState, - /// The random number generator to use if Miri - /// is running in non-deterministic mode +pub struct MemoryExtra { + pub stacked_borrows: stacked_borrows::MemoryExtra, + pub intptrcast: intptrcast::MemoryExtra, + /// The random number generator to use if Miri is running in non-deterministic mode and to + /// enable intptrcast pub(crate) rng: Option } -#[derive(Debug, Clone,)] +#[derive(Debug, Clone)] pub struct AllocExtra { - pub stacks: stacked_borrows::Stacks, - pub base_addr: Cell>, + pub stacked_borrows: stacked_borrows::AllocExtra, + pub intptrcast: intptrcast::AllocExtra, } impl AllocationExtra for AllocExtra { @@ -29,11 +28,7 @@ impl AllocationExtra for AllocExtra { ptr: Pointer, size: Size, ) -> InterpResult<'tcx> { - trace!("read access with tag {:?}: {:?}, size {}", ptr.tag, ptr.erase_tag(), size.bytes()); - alloc.extra.stacks.for_each(ptr, size, |stack, global| { - stack.access(AccessKind::Read, ptr.tag, global)?; - Ok(()) - }) + alloc.extra.stacked_borrows.memory_read(ptr, size) } #[inline(always)] @@ -42,11 +37,7 @@ impl AllocationExtra for AllocExtra { ptr: Pointer, size: Size, ) -> InterpResult<'tcx> { - trace!("write access with tag {:?}: {:?}, size {}", ptr.tag, ptr.erase_tag(), size.bytes()); - alloc.extra.stacks.for_each(ptr, size, |stack, global| { - stack.access(AccessKind::Write, ptr.tag, global)?; - Ok(()) - }) + alloc.extra.stacked_borrows.memory_written(ptr, size) } #[inline(always)] @@ -55,9 +46,6 @@ impl AllocationExtra for AllocExtra { ptr: Pointer, size: Size, ) -> InterpResult<'tcx> { - trace!("deallocation with tag {:?}: {:?}, size {}", ptr.tag, ptr.erase_tag(), size.bytes()); - alloc.extra.stacks.for_each(ptr, size, |stack, global| { - stack.dealloc(ptr.tag, global) - }) + alloc.extra.stacked_borrows.memory_deallocated(ptr, size) } } diff --git a/src/operator.rs b/src/operator.rs index 0ebb1e71610a6..8f2b75d6043ad 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -44,6 +44,9 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { trace!("ptr_op: {:?} {:?} {:?}", *left, bin_op, *right); + // If intptrcast is enabled and the operation is not an offset + // we can force the cast from pointers to integer addresses and + // then dispatch to rustc binary operation method if self.memory().extra.rng.is_some() && bin_op != Offset { let l_bits = self.force_bits(left.imm.to_scalar()?, left.layout.size)?; let r_bits = self.force_bits(right.imm.to_scalar()?, right.layout.size)?; diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index ea70c28709cee..c47ad95c04b3b 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -16,6 +16,7 @@ use crate::{ pub type PtrId = NonZeroU64; pub type CallId = NonZeroU64; +pub type AllocExtra = Stacks; /// Tracking pointer provenance #[derive(Copy, Clone, Hash, PartialEq, Eq)] @@ -86,7 +87,7 @@ pub struct Stacks { // Even reading memory can have effects on the stack, so we need a `RefCell` here. stacks: RefCell>, // Pointer to global state - global: MemoryState, + global: MemoryExtra, } /// Extra global state, available to the memory access hooks. @@ -104,7 +105,7 @@ pub struct GlobalState { active_calls: HashSet, } /// Memory extra state gives us interior mutable access to the global state. -pub type MemoryState = Rc>; +pub type MemoryExtra = Rc>; /// Indicates which kind of access is being performed. #[derive(Copy, Clone, Hash, PartialEq, Eq)] @@ -286,7 +287,7 @@ impl<'tcx> Stack { /// Test if a memory `access` using pointer tagged `tag` is granted. /// If yes, return the index of the item that granted it. - pub(crate) fn access( + fn access( &mut self, access: AccessKind, tag: Tag, @@ -336,7 +337,7 @@ impl<'tcx> Stack { /// Deallocate a location: Like a write access, but also there must be no /// active protectors at all because we will remove all items. - pub(crate) fn dealloc( + fn dealloc( &mut self, tag: Tag, global: &GlobalState, @@ -423,7 +424,7 @@ impl<'tcx> Stacks { size: Size, perm: Permission, tag: Tag, - extra: MemoryState, + extra: MemoryExtra, ) -> Self { let item = Item { perm, tag, protector: None }; let stack = Stack { @@ -437,7 +438,7 @@ impl<'tcx> Stacks { } /// Call `f` on every stack in the range. - pub(crate) fn for_each( + fn for_each( &self, ptr: Pointer, size: Size, @@ -457,7 +458,7 @@ impl Stacks { pub fn new_allocation( id: AllocId, size: Size, - extra: MemoryState, + extra: MemoryExtra, kind: MemoryKind, ) -> (Self, Tag) { let (tag, perm) = match kind { @@ -476,6 +477,44 @@ impl Stacks { let stack = Stacks::new(size, perm, tag, extra); (stack, tag) } + + #[inline(always)] + pub fn memory_read<'tcx>( + &self, + ptr: Pointer, + size: Size, + ) -> InterpResult<'tcx> { + trace!("read access with tag {:?}: {:?}, size {}", ptr.tag, ptr.erase_tag(), size.bytes()); + self.for_each(ptr, size, |stack, global| { + stack.access(AccessKind::Read, ptr.tag, global)?; + Ok(()) + }) + } + + #[inline(always)] + pub fn memory_written<'tcx>( + &mut self, + ptr: Pointer, + size: Size, + ) -> InterpResult<'tcx> { + trace!("write access with tag {:?}: {:?}, size {}", ptr.tag, ptr.erase_tag(), size.bytes()); + self.for_each(ptr, size, |stack, global| { + stack.access(AccessKind::Write, ptr.tag, global)?; + Ok(()) + }) + } + + #[inline(always)] + pub fn memory_deallocated<'tcx>( + &mut self, + ptr: Pointer, + size: Size, + ) -> InterpResult<'tcx> { + trace!("deallocation with tag {:?}: {:?}, size {}", ptr.tag, ptr.erase_tag(), size.bytes()); + self.for_each(ptr, size, |stack, global| { + stack.dealloc(ptr.tag, global) + }) + } } /// Retagging/reborrowing. There is some policy in here, such as which permissions @@ -514,14 +553,14 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // We are only ever `SharedReadOnly` inside the frozen bits. let perm = if frozen { Permission::SharedReadOnly } else { Permission::SharedReadWrite }; let item = Item { perm, tag: new_tag, protector }; - alloc.extra.stacks.for_each(cur_ptr, size, |stack, global| { + alloc.extra.stacked_borrows.for_each(cur_ptr, size, |stack, global| { stack.grant(cur_ptr.tag, item, global) }) }); } }; let item = Item { perm, tag: new_tag, protector }; - alloc.extra.stacks.for_each(ptr, size, |stack, global| { + alloc.extra.stacked_borrows.for_each(ptr, size, |stack, global| { stack.grant(ptr.tag, item, global) }) } @@ -548,7 +587,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Compute new borrow. let new_tag = match kind { RefKind::Raw { .. } => Tag::Untagged, - _ => Tag::Tagged(this.memory().extra.stacked.borrow_mut().new_ptr()), + _ => Tag::Tagged(this.memory().extra.stacked_borrows.borrow_mut().new_ptr()), }; // Reborrow. @@ -582,7 +621,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ty::RawPtr(tym) if kind == RetagKind::Raw => Some((RefKind::Raw { mutable: tym.mutbl == MutMutable }, false)), // Boxes do not get a protector: protectors reflect that references outlive the call - // they were passed in to; that's just not the case for boxes. + // they were passed in to; that's just not the case for boxes. ty::Adt(..) if ty.is_box() => Some((RefKind::Unique { two_phase: false }, false)), _ => None, } From 7a6438ada68b30f194985da5586b640138d768dc Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 25 Jun 2019 10:05:34 +0200 Subject: [PATCH 0848/3747] add snippet for running Miri on CI --- README.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/README.md b/README.md index 82fe738e03100..91dcfd7cf83b3 100644 --- a/README.md +++ b/README.md @@ -94,6 +94,24 @@ fn does_not_work_on_miri() { } ``` +### Running Miri on CI + +To run Miri on CI, make sure that you handle the case where the latest nightly +does not ship the Miri component because it currently does not build. For +example, you can use the following snippet to always test with the latest +nightly that *does* come with Miri: + +```sh +MIRI_NIGHTLY=nightly-$(curl -s https://rust-lang.github.io/rustup-components-history/x86_64-unknown-linux-gnu/miri) +echo "Installing latest nightly with Miri: $MIRI_NIGHTLY" +rustup default "$MIRI_NIGHTLY" + +rustup component add miri +cargo miri setup + +cargo miri test -- -- -Zunstable-options --exclude-should-panic +``` + ### Common Problems When using the above instructions, you may encounter a number of confusing compiler From 7fbf8e53a22925a5ff865b3546f881f7542c4f9e Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Tue, 25 Jun 2019 14:07:23 -0500 Subject: [PATCH 0849/3747] Fix alignment of base addresses --- src/intptrcast.rs | 29 ++++++++++--------- src/lib.rs | 1 + .../{intptrcast-truncate.rs => intptrcast.rs} | 0 3 files changed, 17 insertions(+), 13 deletions(-) rename tests/run-pass/{intptrcast-truncate.rs => intptrcast.rs} (100%) diff --git a/src/intptrcast.rs b/src/intptrcast.rs index c48e7b7772b1d..ad0489fa7de86 100644 --- a/src/intptrcast.rs +++ b/src/intptrcast.rs @@ -36,25 +36,25 @@ impl Default for GlobalState { impl<'mir, 'tcx> GlobalState { pub fn int_to_ptr( - base_addr: u64, + int: u64, memory: &Memory<'mir, 'tcx, Evaluator<'tcx>>, ) -> InterpResult<'tcx, Pointer> { let global_state = memory.extra.intptrcast.borrow(); - match global_state.int_to_ptr_map.binary_search_by_key(&base_addr, |(addr, _)| *addr) { + match global_state.int_to_ptr_map.binary_search_by_key(&int, |(addr, _)| *addr) { Ok(pos) => { let (_, alloc_id) = global_state.int_to_ptr_map[pos]; - // `base_addr` is the starting address for an allocation, the offset should be + // `int` is equal to the starting address for an allocation, the offset should be // zero. The pointer is untagged because it was created from a cast Ok(Pointer::new_with_tag(alloc_id, Size::from_bytes(0), Tag::Untagged)) }, Err(0) => err!(DanglingPointerDeref), Err(pos) => { - // This is the gargest of the adresses smaller than `base_addr`, + // This is the largest of the adresses smaller than `int`, // i.e. the greatest lower bound (glb) let (glb, alloc_id) = global_state.int_to_ptr_map[pos - 1]; - // This never overflows because `base_addr >= glb` - let offset = base_addr - glb; + // This never overflows because `int >= glb` + let offset = int - glb; // If the offset exceeds the size of the allocation, this access is illegal if offset <= memory.get(alloc_id)?.bytes.len() as u64 { // This pointer is untagged because it was created from a cast @@ -77,16 +77,13 @@ impl<'mir, 'tcx> GlobalState { let base_addr = match alloc.extra.intptrcast.base_addr.get() { Some(base_addr) => base_addr, None => { - let base_addr = global_state.next_base_addr; - global_state.next_base_addr += alloc.bytes.len() as u64; - + // This allocation does not have a base address yet, pick one. + let base_addr = Self::align_addr(global_state.next_base_addr, alloc.align.bytes()); + global_state.next_base_addr = base_addr + alloc.bytes.len() as u64; alloc.extra.intptrcast.base_addr.set(Some(base_addr)); - - let elem = (base_addr, ptr.alloc_id); - // Given that `next_base_addr` increases in each allocation, pushing the // corresponding tuple keeps `int_to_ptr_map` sorted - global_state.int_to_ptr_map.push(elem); + global_state.int_to_ptr_map.push((base_addr, ptr.alloc_id)); base_addr } @@ -94,4 +91,10 @@ impl<'mir, 'tcx> GlobalState { Ok(base_addr + ptr.offset.bytes()) } + + /// Shifts `addr` to make it aligned with `align` by rounding `addr` to the smallest multiple + /// of `align` that is strictly larger to `addr` + fn align_addr(addr: u64, align: u64) -> u64 { + addr + align - addr % align + } } diff --git a/src/lib.rs b/src/lib.rs index 77acd3045da57..6b1ada69d3975 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -85,6 +85,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( Evaluator::new(config.validate), ); + // FIXME: InterpretCx::new should take an initial MemoryExtra ecx.memory_mut().extra.rng = config.seed.map(StdRng::seed_from_u64); let main_instance = ty::Instance::mono(ecx.tcx.tcx, main_id); diff --git a/tests/run-pass/intptrcast-truncate.rs b/tests/run-pass/intptrcast.rs similarity index 100% rename from tests/run-pass/intptrcast-truncate.rs rename to tests/run-pass/intptrcast.rs From 413a3515525829e1ddd93dbb391da0fe45e16ff8 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Wed, 26 Jun 2019 13:09:50 -0500 Subject: [PATCH 0850/3747] Initialize MemoryExtra with StdRng --- src/lib.rs | 6 ++---- src/memory.rs | 10 ++++++++++ 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 6b1ada69d3975..7bab1762bdd6c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -50,7 +50,7 @@ use crate::range_map::RangeMap; pub use crate::helpers::{EvalContextExt as HelpersEvalContextExt}; use crate::mono_hash_map::MonoHashMap; pub use crate::stacked_borrows::{EvalContextExt as StackedBorEvalContextExt}; -use crate::memory::AllocExtra; +use crate::memory::{MemoryExtra, AllocExtra}; // Used by priroda. pub use crate::stacked_borrows::{Tag, Permission, Stack, Stacks, Item}; @@ -83,10 +83,8 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( tcx.at(syntax::source_map::DUMMY_SP), ty::ParamEnv::reveal_all(), Evaluator::new(config.validate), + MemoryExtra::with_rng(config.seed.map(StdRng::seed_from_u64)), ); - - // FIXME: InterpretCx::new should take an initial MemoryExtra - ecx.memory_mut().extra.rng = config.seed.map(StdRng::seed_from_u64); let main_instance = ty::Instance::mono(ecx.tcx.tcx, main_id); let main_mir = ecx.load_mir(main_instance.def)?; diff --git a/src/memory.rs b/src/memory.rs index ea8f01a808c04..252e1cc08ae52 100644 --- a/src/memory.rs +++ b/src/memory.rs @@ -15,6 +15,16 @@ pub struct MemoryExtra { pub(crate) rng: Option } +impl MemoryExtra { + pub fn with_rng(rng: Option) -> Self { + MemoryExtra { + stacked_borrows: Default::default(), + intptrcast: Default::default(), + rng, + } + } +} + #[derive(Debug, Clone)] pub struct AllocExtra { pub stacked_borrows: stacked_borrows::AllocExtra, From 373a4ee1e99661dd9d708626b41d0ed0e9fbe254 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Wed, 26 Jun 2019 13:55:56 -0500 Subject: [PATCH 0851/3747] Remove default derive for MemoryExtra --- src/memory.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/memory.rs b/src/memory.rs index 252e1cc08ae52..e1ccafaae2821 100644 --- a/src/memory.rs +++ b/src/memory.rs @@ -6,7 +6,7 @@ use rustc_target::abi::Size; use crate::{stacked_borrows, intptrcast}; use crate::stacked_borrows::Tag; -#[derive(Default, Clone, Debug)] +#[derive(Clone, Debug)] pub struct MemoryExtra { pub stacked_borrows: stacked_borrows::MemoryExtra, pub intptrcast: intptrcast::MemoryExtra, From 38b947b9535838d7e62aad684edc69f94b1f97f5 Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Thu, 27 Jun 2019 21:46:24 -0400 Subject: [PATCH 0852/3747] Show usage if run without arguments Before, running `./miri` without arguments gave './miri: 92: shift: can't shift that many' if run with /bin/sh, or no output at all when run with bash. Although that gives some indication of the error, it's not as helpful as showing the usage. --- miri | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/miri b/miri index 89df4f2054478..15bfeed4da06c 100755 --- a/miri +++ b/miri @@ -89,7 +89,7 @@ find_sysroot() { # Determine command. COMMAND="$1" -shift +[ $# -gt 0 ] && shift # Determine flags passed to all cargo invocations. # This is a bit more annoying that one would hope due to From 6886864862b6a66a5e9807e98300e6e3254d27bf Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 28 Jun 2019 09:12:11 +0200 Subject: [PATCH 0853/3747] ptr-to-int alignment sanity check --- src/intptrcast.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/intptrcast.rs b/src/intptrcast.rs index ad0489fa7de86..176e1bc591c2e 100644 --- a/src/intptrcast.rs +++ b/src/intptrcast.rs @@ -89,6 +89,7 @@ impl<'mir, 'tcx> GlobalState { } }; + debug_assert_eq!(base_addr % alloc.align.bytes(), 0); // sanity check Ok(base_addr + ptr.offset.bytes()) } From 4df5c6ac831c71f0c2b1dc2b6c0748798b42df4e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 28 Jun 2019 11:29:24 +0200 Subject: [PATCH 0854/3747] bump rand to released 0.7 --- test-cargo-miri/Cargo.lock | 7 +++---- test-cargo-miri/Cargo.toml | 2 +- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/test-cargo-miri/Cargo.lock b/test-cargo-miri/Cargo.lock index 972b6bf074de7..d404872f9db6d 100644 --- a/test-cargo-miri/Cargo.lock +++ b/test-cargo-miri/Cargo.lock @@ -29,7 +29,7 @@ name = "cargo-miri-test" version = "0.1.0" dependencies = [ "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.7.0-pre.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -73,10 +73,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "rand" -version = "0.7.0-pre.1" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "getrandom 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", "rand_chacha 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -150,7 +149,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bc5729f27f159ddd61f4df6228e827e86643d4d3e7c32183cb30a1c08f604a14" "checksum libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)" = "6281b86796ba5e4366000be6e9e18bf35580adf9e63fbe2294aadb587613a319" "checksum ppv-lite86 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e3cbf9f658cdb5000fcf6f362b8ea2ba154b9f146a61c7a20d647034c6b6561b" -"checksum rand 0.7.0-pre.1 (registry+https://github.com/rust-lang/crates.io-index)" = "866531c9bb6613da04a1e6ad99d27a7c8acd488020d7a8b177b058a10c900eec" +"checksum rand 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d47eab0e83d9693d40f825f86948aa16eff6750ead4bdffc4ab95b8b3a7f052c" "checksum rand_chacha 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e193067942ef6f485a349a113329140d0ab9e2168ce92274499bb0e9a4190d9d" "checksum rand_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "615e683324e75af5d43d8f7a39ffe3ee4a9dc42c5c701167a71dc59c3a493aca" "checksum rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" diff --git a/test-cargo-miri/Cargo.toml b/test-cargo-miri/Cargo.toml index 607514b995f61..c7fc62b79e840 100644 --- a/test-cargo-miri/Cargo.toml +++ b/test-cargo-miri/Cargo.toml @@ -8,4 +8,4 @@ edition = "2018" byteorder = "1.0" [dev-dependencies] -rand = { version = "0.7.0-pre.0", features = ["small_rng"] } +rand = { version = "0.7", features = ["small_rng"] } From afe42625e51c9b102895af86118354ada7ad8e26 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 28 Jun 2019 20:42:00 +0200 Subject: [PATCH 0855/3747] test pointer string formatting --- tests/run-pass/intptrcast.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/run-pass/intptrcast.rs b/tests/run-pass/intptrcast.rs index 4ff57caf95c27..40b21f9a4729e 100644 --- a/tests/run-pass/intptrcast.rs +++ b/tests/run-pass/intptrcast.rs @@ -1,9 +1,14 @@ // compile-flags: -Zmiri-seed=0000000000000000 fn main() { + // Some casting-to-int with arithmetic. let x = &42 as *const i32 as usize; let y = x * 2; assert_eq!(y, x + x); let z = y as u8 as usize; assert_eq!(z, y % 256); + + // Pointer string formatting! We can't check the output as it changes when libstd changes, + // but we can make sure Miri does not error. + format!("{:?}", &mut 13 as *mut _); } From 67d3779b0ce5a1f2e735e4497af5321a9000105a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 27 Jun 2019 23:59:00 +0200 Subject: [PATCH 0856/3747] move most of the stuff from lib.rs into machine.rs, and initialization + main loop into eval.rs --- src/eval.rs | 248 +++++++++++++++++++++ src/helpers.rs | 2 +- src/lib.rs | 578 +----------------------------------------------- src/machine.rs | 384 ++++++++++++++++++++++++++++++++ src/memory.rs | 51 ----- src/operator.rs | 2 +- 6 files changed, 642 insertions(+), 623 deletions(-) create mode 100644 src/eval.rs create mode 100644 src/machine.rs delete mode 100644 src/memory.rs diff --git a/src/eval.rs b/src/eval.rs new file mode 100644 index 0000000000000..5f7d85b7445f7 --- /dev/null +++ b/src/eval.rs @@ -0,0 +1,248 @@ +use rand::rngs::StdRng; +use rand::SeedableRng; + +use syntax::source_map::DUMMY_SP; +use rustc::ty::{self, TyCtxt}; +use rustc::ty::layout::{LayoutOf, Size, Align}; +use rustc::hir::def_id::DefId; +use rustc::mir; + +use crate::{ + InterpResult, InterpError, InterpretCx, StackPopCleanup, struct_error, + Scalar, Tag, Pointer, + MiriMemoryKind, Evaluator, TlsEvalContextExt, +}; + +/// Configuration needed to spawn a Miri instance. +#[derive(Clone)] +pub struct MiriConfig { + pub validate: bool, + pub args: Vec, + + // The seed to use when non-determinism is required (e.g. getrandom()) + pub seed: Option +} + +// Used by priroda. +pub fn create_ecx<'mir, 'tcx: 'mir>( + tcx: TyCtxt<'tcx>, + main_id: DefId, + config: MiriConfig, +) -> InterpResult<'tcx, InterpretCx<'mir, 'tcx, Evaluator<'tcx>>> { + let mut ecx = InterpretCx::new( + tcx.at(syntax::source_map::DUMMY_SP), + ty::ParamEnv::reveal_all(), + Evaluator::new(config.validate), + ); + + // FIXME: InterpretCx::new should take an initial MemoryExtra + ecx.memory_mut().extra.rng = config.seed.map(StdRng::seed_from_u64); + + let main_instance = ty::Instance::mono(ecx.tcx.tcx, main_id); + let main_mir = ecx.load_mir(main_instance.def)?; + + if !main_mir.return_ty().is_unit() || main_mir.arg_count != 0 { + return err!(Unimplemented( + "miri does not support main functions without `fn()` type signatures" + .to_owned(), + )); + } + + let start_id = tcx.lang_items().start_fn().unwrap(); + let main_ret_ty = tcx.fn_sig(main_id).output(); + let main_ret_ty = main_ret_ty.no_bound_vars().unwrap(); + let start_instance = ty::Instance::resolve( + ecx.tcx.tcx, + ty::ParamEnv::reveal_all(), + start_id, + ecx.tcx.mk_substs( + ::std::iter::once(ty::subst::Kind::from(main_ret_ty))) + ).unwrap(); + let start_mir = ecx.load_mir(start_instance.def)?; + + if start_mir.arg_count != 3 { + return err!(AbiViolation(format!( + "'start' lang item should have three arguments, but has {}", + start_mir.arg_count + ))); + } + + // Return value (in static memory so that it does not count as leak). + let ret = ecx.layout_of(start_mir.return_ty())?; + let ret_ptr = ecx.allocate(ret, MiriMemoryKind::Static.into()); + + // Push our stack frame. + ecx.push_stack_frame( + start_instance, + // There is no call site. + DUMMY_SP, + start_mir, + Some(ret_ptr.into()), + StackPopCleanup::None { cleanup: true }, + )?; + + let mut args = ecx.frame().body.args_iter(); + + // First argument: pointer to `main()`. + let main_ptr = ecx.memory_mut().create_fn_alloc(main_instance); + let dest = ecx.eval_place(&mir::Place::Base(mir::PlaceBase::Local(args.next().unwrap())))?; + ecx.write_scalar(Scalar::Ptr(main_ptr), dest)?; + + // Second argument (argc): `1`. + let dest = ecx.eval_place(&mir::Place::Base(mir::PlaceBase::Local(args.next().unwrap())))?; + let argc = Scalar::from_uint(config.args.len() as u128, dest.layout.size); + ecx.write_scalar(argc, dest)?; + // Store argc for macOS's `_NSGetArgc`. + { + let argc_place = ecx.allocate(dest.layout, MiriMemoryKind::Env.into()); + ecx.write_scalar(argc, argc_place.into())?; + ecx.machine.argc = Some(argc_place.ptr.to_ptr()?); + } + + // FIXME: extract main source file path. + // Third argument (`argv`): created from `config.args`. + let dest = ecx.eval_place(&mir::Place::Base(mir::PlaceBase::Local(args.next().unwrap())))?; + // For Windows, construct a command string with all the aguments. + let mut cmd = String::new(); + for arg in config.args.iter() { + if !cmd.is_empty() { + cmd.push(' '); + } + cmd.push_str(&*shell_escape::windows::escape(arg.as_str().into())); + } + // Don't forget `0` terminator. + cmd.push(std::char::from_u32(0).unwrap()); + // Collect the pointers to the individual strings. + let mut argvs = Vec::>::new(); + for arg in config.args { + // Add `0` terminator. + let mut arg = arg.into_bytes(); + arg.push(0); + argvs.push(ecx.memory_mut().allocate_static_bytes(arg.as_slice(), MiriMemoryKind::Static.into())); + } + // Make an array with all these pointers, in the Miri memory. + let argvs_layout = ecx.layout_of(ecx.tcx.mk_array(ecx.tcx.mk_imm_ptr(ecx.tcx.types.u8), argvs.len() as u64))?; + let argvs_place = ecx.allocate(argvs_layout, MiriMemoryKind::Env.into()); + for (idx, arg) in argvs.into_iter().enumerate() { + let place = ecx.mplace_field(argvs_place, idx as u64)?; + ecx.write_scalar(Scalar::Ptr(arg), place.into())?; + } + ecx.memory_mut().mark_immutable(argvs_place.to_ptr()?.alloc_id)?; + // Write a pointer to that place as the argument. + let argv = argvs_place.ptr; + ecx.write_scalar(argv, dest)?; + // Store `argv` for macOS `_NSGetArgv`. + { + let argv_place = ecx.allocate(dest.layout, MiriMemoryKind::Env.into()); + ecx.write_scalar(argv, argv_place.into())?; + ecx.machine.argv = Some(argv_place.ptr.to_ptr()?); + } + // Store command line as UTF-16 for Windows `GetCommandLineW`. + { + let tcx = &{ecx.tcx.tcx}; + let cmd_utf16: Vec = cmd.encode_utf16().collect(); + let cmd_ptr = ecx.memory_mut().allocate( + Size::from_bytes(cmd_utf16.len() as u64 * 2), + Align::from_bytes(2).unwrap(), + MiriMemoryKind::Env.into(), + ); + ecx.machine.cmd_line = Some(cmd_ptr); + // Store the UTF-16 string. + let char_size = Size::from_bytes(2); + let cmd_alloc = ecx.memory_mut().get_mut(cmd_ptr.alloc_id)?; + let mut cur_ptr = cmd_ptr; + for &c in cmd_utf16.iter() { + cmd_alloc.write_scalar( + tcx, + cur_ptr, + Scalar::from_uint(c, char_size).into(), + char_size, + )?; + cur_ptr = cur_ptr.offset(char_size, tcx)?; + } + } + + assert!(args.next().is_none(), "start lang item has more arguments than expected"); + + Ok(ecx) +} + +pub fn eval_main<'tcx>( + tcx: TyCtxt<'tcx>, + main_id: DefId, + config: MiriConfig, +) { + let mut ecx = match create_ecx(tcx, main_id, config) { + Ok(ecx) => ecx, + Err(mut err) => { + err.print_backtrace(); + panic!("Miri initialziation error: {}", err.kind) + } + }; + + // Perform the main execution. + let res: InterpResult = (|| { + ecx.run()?; + ecx.run_tls_dtors() + })(); + + // Process the result. + match res { + Ok(()) => { + let leaks = ecx.memory().leak_report(); + // Disable the leak test on some platforms where we do not + // correctly implement TLS destructors. + let target_os = ecx.tcx.tcx.sess.target.target.target_os.to_lowercase(); + let ignore_leaks = target_os == "windows" || target_os == "macos"; + if !ignore_leaks && leaks != 0 { + tcx.sess.err("the evaluated program leaked memory"); + } + } + Err(mut e) => { + // Special treatment for some error kinds + let msg = match e.kind { + InterpError::Exit(code) => std::process::exit(code), + InterpError::NoMirFor(..) => + format!("{}. Did you set `MIRI_SYSROOT` to a Miri-enabled sysroot? You can prepare one with `cargo miri setup`.", e), + _ => e.to_string() + }; + e.print_backtrace(); + if let Some(frame) = ecx.stack().last() { + let block = &frame.body.basic_blocks()[frame.block]; + let span = if frame.stmt < block.statements.len() { + block.statements[frame.stmt].source_info.span + } else { + block.terminator().source_info.span + }; + + let msg = format!("Miri evaluation error: {}", msg); + let mut err = struct_error(ecx.tcx.tcx.at(span), msg.as_str()); + let frames = ecx.generate_stacktrace(None); + err.span_label(span, msg); + // We iterate with indices because we need to look at the next frame (the caller). + for idx in 0..frames.len() { + let frame_info = &frames[idx]; + let call_site_is_local = frames.get(idx+1).map_or(false, + |caller_info| caller_info.instance.def_id().is_local()); + if call_site_is_local { + err.span_note(frame_info.call_site, &frame_info.to_string()); + } else { + err.note(&frame_info.to_string()); + } + } + err.emit(); + } else { + ecx.tcx.sess.err(&msg); + } + + for (i, frame) in ecx.stack().iter().enumerate() { + trace!("-------------------"); + trace!("Frame {}", i); + trace!(" return: {:?}", frame.return_place.map(|p| *p)); + for (i, local) in frame.locals.iter().enumerate() { + trace!(" local {}: {:?}", i, local.value); + } + } + } + } +} diff --git a/src/helpers.rs b/src/helpers.rs index 62a546767e895..f65eef557c967 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -1,6 +1,6 @@ use std::mem; -use rustc::ty::{self, layout}; +use rustc::ty::{self, layout::{self, Size}}; use rustc::hir::def_id::{DefId, CRATE_DEF_INDEX}; use crate::*; diff --git a/src/lib.rs b/src/lib.rs index 6b1ada69d3975..ab9e9854c34cb 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -21,39 +21,24 @@ mod range_map; mod mono_hash_map; mod stacked_borrows; mod intptrcast; -mod memory; +mod machine; +mod eval; -use std::collections::HashMap; -use std::borrow::Cow; -use std::rc::Rc; - -use rand::rngs::StdRng; -use rand::SeedableRng; - -use rustc::ty::{self, TyCtxt, query::TyCtxtAt}; -use rustc::ty::layout::{LayoutOf, Size, Align}; -use rustc::hir::def_id::DefId; -use rustc::mir; +// Make all those symbols available in the same place as our own. pub use rustc_mir::interpret::*; // Resolve ambiguity. pub use rustc_mir::interpret::{self, AllocMap, PlaceTy}; -use syntax::attr; -use syntax::source_map::DUMMY_SP; -use syntax::symbol::sym; pub use crate::fn_call::EvalContextExt as MissingFnsEvalContextExt; pub use crate::operator::EvalContextExt as OperatorEvalContextExt; pub use crate::intrinsic::EvalContextExt as IntrinsicEvalContextExt; pub use crate::tls::{EvalContextExt as TlsEvalContextExt, TlsData}; -use crate::range_map::RangeMap; -#[allow(unused_imports)] // FIXME: rustc bug, issue . +pub use crate::range_map::RangeMap; pub use crate::helpers::{EvalContextExt as HelpersEvalContextExt}; -use crate::mono_hash_map::MonoHashMap; -pub use crate::stacked_borrows::{EvalContextExt as StackedBorEvalContextExt}; -use crate::memory::AllocExtra; - -// Used by priroda. -pub use crate::stacked_borrows::{Tag, Permission, Stack, Stacks, Item}; +pub use crate::mono_hash_map::MonoHashMap; +pub use crate::stacked_borrows::{EvalContextExt as StackedBorEvalContextExt, Tag, Permission, Stack, Stacks, Item}; +pub use crate::machine::{MemoryExtra, AllocExtra, MiriMemoryKind, Evaluator, MiriEvalContext, MiriEvalContextExt}; +pub use crate::eval::{eval_main, create_ecx, MiriConfig}; /// Insert rustc arguments at the beginning of the argument list that Miri wants to be /// set per default, for maximal validation power. @@ -62,550 +47,3 @@ pub fn miri_default_args() -> &'static [&'static str] { // set, which happens in `bootstrap/bin/rustc.rs` in the rustc sources. &["-Zalways-encode-mir", "-Zmir-emit-retag", "-Zmir-opt-level=0", "--cfg=miri"] } - -/// Configuration needed to spawn a Miri instance. -#[derive(Clone)] -pub struct MiriConfig { - pub validate: bool, - pub args: Vec, - - // The seed to use when non-determinism is required (e.g. getrandom()) - pub seed: Option -} - -// Used by priroda. -pub fn create_ecx<'mir, 'tcx: 'mir>( - tcx: TyCtxt<'tcx>, - main_id: DefId, - config: MiriConfig, -) -> InterpResult<'tcx, InterpretCx<'mir, 'tcx, Evaluator<'tcx>>> { - let mut ecx = InterpretCx::new( - tcx.at(syntax::source_map::DUMMY_SP), - ty::ParamEnv::reveal_all(), - Evaluator::new(config.validate), - ); - - // FIXME: InterpretCx::new should take an initial MemoryExtra - ecx.memory_mut().extra.rng = config.seed.map(StdRng::seed_from_u64); - - let main_instance = ty::Instance::mono(ecx.tcx.tcx, main_id); - let main_mir = ecx.load_mir(main_instance.def)?; - - if !main_mir.return_ty().is_unit() || main_mir.arg_count != 0 { - return err!(Unimplemented( - "miri does not support main functions without `fn()` type signatures" - .to_owned(), - )); - } - - let start_id = tcx.lang_items().start_fn().unwrap(); - let main_ret_ty = tcx.fn_sig(main_id).output(); - let main_ret_ty = main_ret_ty.no_bound_vars().unwrap(); - let start_instance = ty::Instance::resolve( - ecx.tcx.tcx, - ty::ParamEnv::reveal_all(), - start_id, - ecx.tcx.mk_substs( - ::std::iter::once(ty::subst::Kind::from(main_ret_ty))) - ).unwrap(); - let start_mir = ecx.load_mir(start_instance.def)?; - - if start_mir.arg_count != 3 { - return err!(AbiViolation(format!( - "'start' lang item should have three arguments, but has {}", - start_mir.arg_count - ))); - } - - // Return value (in static memory so that it does not count as leak). - let ret = ecx.layout_of(start_mir.return_ty())?; - let ret_ptr = ecx.allocate(ret, MiriMemoryKind::Static.into()); - - // Push our stack frame. - ecx.push_stack_frame( - start_instance, - // There is no call site. - DUMMY_SP, - start_mir, - Some(ret_ptr.into()), - StackPopCleanup::None { cleanup: true }, - )?; - - let mut args = ecx.frame().body.args_iter(); - - // First argument: pointer to `main()`. - let main_ptr = ecx.memory_mut().create_fn_alloc(main_instance); - let dest = ecx.eval_place(&mir::Place::Base(mir::PlaceBase::Local(args.next().unwrap())))?; - ecx.write_scalar(Scalar::Ptr(main_ptr), dest)?; - - // Second argument (argc): `1`. - let dest = ecx.eval_place(&mir::Place::Base(mir::PlaceBase::Local(args.next().unwrap())))?; - let argc = Scalar::from_uint(config.args.len() as u128, dest.layout.size); - ecx.write_scalar(argc, dest)?; - // Store argc for macOS's `_NSGetArgc`. - { - let argc_place = ecx.allocate(dest.layout, MiriMemoryKind::Env.into()); - ecx.write_scalar(argc, argc_place.into())?; - ecx.machine.argc = Some(argc_place.ptr.to_ptr()?); - } - - // FIXME: extract main source file path. - // Third argument (`argv`): created from `config.args`. - let dest = ecx.eval_place(&mir::Place::Base(mir::PlaceBase::Local(args.next().unwrap())))?; - // For Windows, construct a command string with all the aguments. - let mut cmd = String::new(); - for arg in config.args.iter() { - if !cmd.is_empty() { - cmd.push(' '); - } - cmd.push_str(&*shell_escape::windows::escape(arg.as_str().into())); - } - // Don't forget `0` terminator. - cmd.push(std::char::from_u32(0).unwrap()); - // Collect the pointers to the individual strings. - let mut argvs = Vec::>::new(); - for arg in config.args { - // Add `0` terminator. - let mut arg = arg.into_bytes(); - arg.push(0); - argvs.push(ecx.memory_mut().allocate_static_bytes(arg.as_slice(), MiriMemoryKind::Static.into())); - } - // Make an array with all these pointers, in the Miri memory. - let argvs_layout = ecx.layout_of(ecx.tcx.mk_array(ecx.tcx.mk_imm_ptr(ecx.tcx.types.u8), argvs.len() as u64))?; - let argvs_place = ecx.allocate(argvs_layout, MiriMemoryKind::Env.into()); - for (idx, arg) in argvs.into_iter().enumerate() { - let place = ecx.mplace_field(argvs_place, idx as u64)?; - ecx.write_scalar(Scalar::Ptr(arg), place.into())?; - } - ecx.memory_mut().mark_immutable(argvs_place.to_ptr()?.alloc_id)?; - // Write a pointer to that place as the argument. - let argv = argvs_place.ptr; - ecx.write_scalar(argv, dest)?; - // Store `argv` for macOS `_NSGetArgv`. - { - let argv_place = ecx.allocate(dest.layout, MiriMemoryKind::Env.into()); - ecx.write_scalar(argv, argv_place.into())?; - ecx.machine.argv = Some(argv_place.ptr.to_ptr()?); - } - // Store command line as UTF-16 for Windows `GetCommandLineW`. - { - let tcx = &{ecx.tcx.tcx}; - let cmd_utf16: Vec = cmd.encode_utf16().collect(); - let cmd_ptr = ecx.memory_mut().allocate( - Size::from_bytes(cmd_utf16.len() as u64 * 2), - Align::from_bytes(2).unwrap(), - MiriMemoryKind::Env.into(), - ); - ecx.machine.cmd_line = Some(cmd_ptr); - // Store the UTF-16 string. - let char_size = Size::from_bytes(2); - let cmd_alloc = ecx.memory_mut().get_mut(cmd_ptr.alloc_id)?; - let mut cur_ptr = cmd_ptr; - for &c in cmd_utf16.iter() { - cmd_alloc.write_scalar( - tcx, - cur_ptr, - Scalar::from_uint(c, char_size).into(), - char_size, - )?; - cur_ptr = cur_ptr.offset(char_size, tcx)?; - } - } - - assert!(args.next().is_none(), "start lang item has more arguments than expected"); - - Ok(ecx) -} - -pub fn eval_main<'tcx>( - tcx: TyCtxt<'tcx>, - main_id: DefId, - config: MiriConfig, -) { - let mut ecx = match create_ecx(tcx, main_id, config) { - Ok(ecx) => ecx, - Err(mut err) => { - err.print_backtrace(); - panic!("Miri initialziation error: {}", err.kind) - } - }; - - // Perform the main execution. - let res: InterpResult = (|| { - ecx.run()?; - ecx.run_tls_dtors() - })(); - - // Process the result. - match res { - Ok(()) => { - let leaks = ecx.memory().leak_report(); - // Disable the leak test on some platforms where we do not - // correctly implement TLS destructors. - let target_os = ecx.tcx.tcx.sess.target.target.target_os.to_lowercase(); - let ignore_leaks = target_os == "windows" || target_os == "macos"; - if !ignore_leaks && leaks != 0 { - tcx.sess.err("the evaluated program leaked memory"); - } - } - Err(mut e) => { - // Special treatment for some error kinds - let msg = match e.kind { - InterpError::Exit(code) => std::process::exit(code), - InterpError::NoMirFor(..) => - format!("{}. Did you set `MIRI_SYSROOT` to a Miri-enabled sysroot? You can prepare one with `cargo miri setup`.", e), - _ => e.to_string() - }; - e.print_backtrace(); - if let Some(frame) = ecx.stack().last() { - let block = &frame.body.basic_blocks()[frame.block]; - let span = if frame.stmt < block.statements.len() { - block.statements[frame.stmt].source_info.span - } else { - block.terminator().source_info.span - }; - - let msg = format!("Miri evaluation error: {}", msg); - let mut err = struct_error(ecx.tcx.tcx.at(span), msg.as_str()); - let frames = ecx.generate_stacktrace(None); - err.span_label(span, msg); - // We iterate with indices because we need to look at the next frame (the caller). - for idx in 0..frames.len() { - let frame_info = &frames[idx]; - let call_site_is_local = frames.get(idx+1).map_or(false, - |caller_info| caller_info.instance.def_id().is_local()); - if call_site_is_local { - err.span_note(frame_info.call_site, &frame_info.to_string()); - } else { - err.note(&frame_info.to_string()); - } - } - err.emit(); - } else { - ecx.tcx.sess.err(&msg); - } - - for (i, frame) in ecx.stack().iter().enumerate() { - trace!("-------------------"); - trace!("Frame {}", i); - trace!(" return: {:?}", frame.return_place.map(|p| *p)); - for (i, local) in frame.locals.iter().enumerate() { - trace!(" local {}: {:?}", i, local.value); - } - } - } - } -} - -#[derive(Debug, Copy, Clone, PartialEq, Eq)] -pub enum MiriMemoryKind { - /// `__rust_alloc` memory. - Rust, - /// `malloc` memory. - C, - /// Part of env var emulation. - Env, - /// Statics. - Static, -} - -impl Into> for MiriMemoryKind { - #[inline(always)] - fn into(self) -> MemoryKind { - MemoryKind::Machine(self) - } -} - -impl MayLeak for MiriMemoryKind { - #[inline(always)] - fn may_leak(self) -> bool { - use self::MiriMemoryKind::*; - match self { - Rust | C => false, - Env | Static => true, - } - } -} - -pub struct Evaluator<'tcx> { - /// Environment variables set by `setenv`. - /// Miri does not expose env vars from the host to the emulated program. - pub(crate) env_vars: HashMap, Pointer>, - - /// Program arguments (`Option` because we can only initialize them after creating the ecx). - /// These are *pointers* to argc/argv because macOS. - /// We also need the full command line as one string because of Windows. - pub(crate) argc: Option>, - pub(crate) argv: Option>, - pub(crate) cmd_line: Option>, - - /// Last OS error. - pub(crate) last_error: u32, - - /// TLS state. - pub(crate) tls: TlsData<'tcx>, - - /// Whether to enforce the validity invariant. - pub(crate) validate: bool, -} - -impl<'tcx> Evaluator<'tcx> { - fn new(validate: bool) -> Self { - Evaluator { - env_vars: HashMap::default(), - argc: None, - argv: None, - cmd_line: None, - last_error: 0, - tls: TlsData::default(), - validate, - } - } -} - -// FIXME: rustc issue . -#[allow(dead_code)] -type MiriEvalContext<'mir, 'tcx> = InterpretCx<'mir, 'tcx, Evaluator<'tcx>>; - -// A little trait that's useful to be inherited by extension traits. -pub trait MiriEvalContextExt<'mir, 'tcx> { - fn eval_context_ref(&self) -> &MiriEvalContext<'mir, 'tcx>; - fn eval_context_mut(&mut self) -> &mut MiriEvalContext<'mir, 'tcx>; -} -impl<'mir, 'tcx> MiriEvalContextExt<'mir, 'tcx> for MiriEvalContext<'mir, 'tcx> { - #[inline(always)] - fn eval_context_ref(&self) -> &MiriEvalContext<'mir, 'tcx> { - self - } - #[inline(always)] - fn eval_context_mut(&mut self) -> &mut MiriEvalContext<'mir, 'tcx> { - self - } -} - -impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { - type MemoryKinds = MiriMemoryKind; - - type FrameExtra = stacked_borrows::CallId; - type MemoryExtra = memory::MemoryExtra; - type AllocExtra = memory::AllocExtra; - type PointerTag = Tag; - - type MemoryMap = MonoHashMap, Allocation)>; - - const STATIC_KIND: Option = Some(MiriMemoryKind::Static); - - #[inline(always)] - fn enforce_validity(ecx: &InterpretCx<'mir, 'tcx, Self>) -> bool { - ecx.machine.validate - } - - /// Returns `Ok()` when the function was handled; fail otherwise. - #[inline(always)] - fn find_fn( - ecx: &mut InterpretCx<'mir, 'tcx, Self>, - instance: ty::Instance<'tcx>, - args: &[OpTy<'tcx, Tag>], - dest: Option>, - ret: Option, - ) -> InterpResult<'tcx, Option<&'mir mir::Body<'tcx>>> { - ecx.find_fn(instance, args, dest, ret) - } - - #[inline(always)] - fn call_intrinsic( - ecx: &mut rustc_mir::interpret::InterpretCx<'mir, 'tcx, Self>, - instance: ty::Instance<'tcx>, - args: &[OpTy<'tcx, Tag>], - dest: PlaceTy<'tcx, Tag>, - ) -> InterpResult<'tcx> { - ecx.call_intrinsic(instance, args, dest) - } - - #[inline(always)] - fn ptr_op( - ecx: &rustc_mir::interpret::InterpretCx<'mir, 'tcx, Self>, - bin_op: mir::BinOp, - left: ImmTy<'tcx, Tag>, - right: ImmTy<'tcx, Tag>, - ) -> InterpResult<'tcx, (Scalar, bool)> { - ecx.ptr_op(bin_op, left, right) - } - - fn box_alloc( - ecx: &mut InterpretCx<'mir, 'tcx, Self>, - dest: PlaceTy<'tcx, Tag>, - ) -> InterpResult<'tcx> { - trace!("box_alloc for {:?}", dest.layout.ty); - // Call the `exchange_malloc` lang item. - let malloc = ecx.tcx.lang_items().exchange_malloc_fn().unwrap(); - let malloc = ty::Instance::mono(ecx.tcx.tcx, malloc); - let malloc_mir = ecx.load_mir(malloc.def)?; - ecx.push_stack_frame( - malloc, - malloc_mir.span, - malloc_mir, - Some(dest), - // Don't do anything when we are done. The `statement()` function will increment - // the old stack frame's stmt counter to the next statement, which means that when - // `exchange_malloc` returns, we go on evaluating exactly where we want to be. - StackPopCleanup::None { cleanup: true }, - )?; - - let mut args = ecx.frame().body.args_iter(); - let layout = ecx.layout_of(dest.layout.ty.builtin_deref(false).unwrap().ty)?; - - // First argument: `size`. - // (`0` is allowed here -- this is expected to be handled by the lang item). - let arg = ecx.eval_place(&mir::Place::Base(mir::PlaceBase::Local(args.next().unwrap())))?; - let size = layout.size.bytes(); - ecx.write_scalar(Scalar::from_uint(size, arg.layout.size), arg)?; - - // Second argument: `align`. - let arg = ecx.eval_place(&mir::Place::Base(mir::PlaceBase::Local(args.next().unwrap())))?; - let align = layout.align.abi.bytes(); - ecx.write_scalar(Scalar::from_uint(align, arg.layout.size), arg)?; - - // No more arguments. - assert!( - args.next().is_none(), - "`exchange_malloc` lang item has more arguments than expected" - ); - Ok(()) - } - - fn find_foreign_static( - def_id: DefId, - tcx: TyCtxtAt<'tcx>, - ) -> InterpResult<'tcx, Cow<'tcx, Allocation>> { - let attrs = tcx.get_attrs(def_id); - let link_name = match attr::first_attr_value_str_by_name(&attrs, sym::link_name) { - Some(name) => name.as_str(), - None => tcx.item_name(def_id).as_str(), - }; - - let alloc = match link_name.get() { - "__cxa_thread_atexit_impl" => { - // This should be all-zero, pointer-sized. - let size = tcx.data_layout.pointer_size; - let data = vec![0; size.bytes() as usize]; - Allocation::from_bytes(&data, tcx.data_layout.pointer_align.abi) - } - _ => return err!(Unimplemented( - format!("can't access foreign static: {}", link_name), - )), - }; - Ok(Cow::Owned(alloc)) - } - - #[inline(always)] - fn before_terminator(_ecx: &mut InterpretCx<'mir, 'tcx, Self>) -> InterpResult<'tcx> - { - // We are not interested in detecting loops. - Ok(()) - } - - fn tag_allocation<'b>( - id: AllocId, - alloc: Cow<'b, Allocation>, - kind: Option>, - memory: &Memory<'mir, 'tcx, Self>, - ) -> (Cow<'b, Allocation>, Self::PointerTag) { - let kind = kind.expect("we set our STATIC_KIND so this cannot be None"); - let alloc = alloc.into_owned(); - let (stacks, base_tag) = Stacks::new_allocation( - id, - Size::from_bytes(alloc.bytes.len() as u64), - Rc::clone(&memory.extra.stacked_borrows), - kind, - ); - if kind != MiriMemoryKind::Static.into() { - assert!(alloc.relocations.is_empty(), "Only statics can come initialized with inner pointers"); - // Now we can rely on the inner pointers being static, too. - } - let mut memory_extra = memory.extra.stacked_borrows.borrow_mut(); - let alloc: Allocation = Allocation { - bytes: alloc.bytes, - relocations: Relocations::from_presorted( - alloc.relocations.iter() - // The allocations in the relocations (pointers stored *inside* this allocation) - // all get the base pointer tag. - .map(|&(offset, ((), alloc))| (offset, (memory_extra.static_base_ptr(alloc), alloc))) - .collect() - ), - undef_mask: alloc.undef_mask, - align: alloc.align, - mutability: alloc.mutability, - extra: AllocExtra { - stacked_borrows: stacks, - intptrcast: Default::default(), - }, - }; - (Cow::Owned(alloc), base_tag) - } - - #[inline(always)] - fn tag_static_base_pointer( - id: AllocId, - memory: &Memory<'mir, 'tcx, Self>, - ) -> Self::PointerTag { - memory.extra.stacked_borrows.borrow_mut().static_base_ptr(id) - } - - #[inline(always)] - fn retag( - ecx: &mut InterpretCx<'mir, 'tcx, Self>, - kind: mir::RetagKind, - place: PlaceTy<'tcx, Tag>, - ) -> InterpResult<'tcx> { - if !ecx.tcx.sess.opts.debugging_opts.mir_emit_retag || !Self::enforce_validity(ecx) { - // No tracking, or no retagging. The latter is possible because a dependency of ours - // might be called with different flags than we are, so there are `Retag` - // statements but we do not want to execute them. - // Also, honor the whitelist in `enforce_validity` because otherwise we might retag - // uninitialized data. - Ok(()) - } else { - ecx.retag(kind, place) - } - } - - #[inline(always)] - fn stack_push( - ecx: &mut InterpretCx<'mir, 'tcx, Self>, - ) -> InterpResult<'tcx, stacked_borrows::CallId> { - Ok(ecx.memory().extra.stacked_borrows.borrow_mut().new_call()) - } - - #[inline(always)] - fn stack_pop( - ecx: &mut InterpretCx<'mir, 'tcx, Self>, - extra: stacked_borrows::CallId, - ) -> InterpResult<'tcx> { - Ok(ecx.memory().extra.stacked_borrows.borrow_mut().end_call(extra)) - } - - fn int_to_ptr( - int: u64, - memory: &Memory<'mir, 'tcx, Self>, - ) -> InterpResult<'tcx, Pointer> { - if int == 0 { - err!(InvalidNullPointerUsage) - } else if memory.extra.rng.is_none() { - err!(ReadBytesAsPointer) - } else { - intptrcast::GlobalState::int_to_ptr(int, memory) - } - } - - fn ptr_to_int( - ptr: Pointer, - memory: &Memory<'mir, 'tcx, Self>, - ) -> InterpResult<'tcx, u64> { - if memory.extra.rng.is_none() { - err!(ReadPointerAsBytes) - } else { - intptrcast::GlobalState::ptr_to_int(ptr, memory) - } - } -} diff --git a/src/machine.rs b/src/machine.rs new file mode 100644 index 0000000000000..eb177fa2a1859 --- /dev/null +++ b/src/machine.rs @@ -0,0 +1,384 @@ +use std::rc::Rc; +use std::borrow::Cow; +use std::collections::HashMap; + +use rand::rngs::StdRng; + +use syntax::attr; +use syntax::symbol::sym; +use rustc::hir::def_id::DefId; +use rustc::ty::{self, layout::{Size, LayoutOf}, query::TyCtxtAt}; +use rustc::mir; + +use crate::*; + +/// Extra memory kinds +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub enum MiriMemoryKind { + /// `__rust_alloc` memory. + Rust, + /// `malloc` memory. + C, + /// Part of env var emulation. + Env, + /// Statics. + Static, +} + +impl Into> for MiriMemoryKind { + #[inline(always)] + fn into(self) -> MemoryKind { + MemoryKind::Machine(self) + } +} + +/// Extra per-allocation data +#[derive(Debug, Clone)] +pub struct AllocExtra { + pub stacked_borrows: stacked_borrows::AllocExtra, + pub intptrcast: intptrcast::AllocExtra, +} + +/// Extra global memory data +#[derive(Default, Clone, Debug)] +pub struct MemoryExtra { + pub stacked_borrows: stacked_borrows::MemoryExtra, + pub intptrcast: intptrcast::MemoryExtra, + /// The random number generator to use if Miri is running in non-deterministic mode and to + /// enable intptrcast + pub(crate) rng: Option +} + +impl MemoryExtra { + pub fn with_rng(rng: Option) -> Self { + MemoryExtra { + stacked_borrows: Default::default(), + intptrcast: Default::default(), + rng, + } + } +} + +/// The machine itself. +pub struct Evaluator<'tcx> { + /// Environment variables set by `setenv`. + /// Miri does not expose env vars from the host to the emulated program. + pub(crate) env_vars: HashMap, Pointer>, + + /// Program arguments (`Option` because we can only initialize them after creating the ecx). + /// These are *pointers* to argc/argv because macOS. + /// We also need the full command line as one string because of Windows. + pub(crate) argc: Option>, + pub(crate) argv: Option>, + pub(crate) cmd_line: Option>, + + /// Last OS error. + pub(crate) last_error: u32, + + /// TLS state. + pub(crate) tls: TlsData<'tcx>, + + /// Whether to enforce the validity invariant. + pub(crate) validate: bool, +} + +impl<'tcx> Evaluator<'tcx> { + pub(crate) fn new(validate: bool) -> Self { + Evaluator { + env_vars: HashMap::default(), + argc: None, + argv: None, + cmd_line: None, + last_error: 0, + tls: TlsData::default(), + validate, + } + } +} + +/// A rustc InterpretCx for Miri. +pub type MiriEvalContext<'mir, 'tcx> = InterpretCx<'mir, 'tcx, Evaluator<'tcx>>; + +/// A little trait that's useful to be inherited by extension traits. +pub trait MiriEvalContextExt<'mir, 'tcx> { + fn eval_context_ref(&self) -> &MiriEvalContext<'mir, 'tcx>; + fn eval_context_mut(&mut self) -> &mut MiriEvalContext<'mir, 'tcx>; +} +impl<'mir, 'tcx> MiriEvalContextExt<'mir, 'tcx> for MiriEvalContext<'mir, 'tcx> { + #[inline(always)] + fn eval_context_ref(&self) -> &MiriEvalContext<'mir, 'tcx> { + self + } + #[inline(always)] + fn eval_context_mut(&mut self) -> &mut MiriEvalContext<'mir, 'tcx> { + self + } +} + +/// Machine hook implementations. +impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { + type MemoryKinds = MiriMemoryKind; + + type FrameExtra = stacked_borrows::CallId; + type MemoryExtra = MemoryExtra; + type AllocExtra = AllocExtra; + type PointerTag = Tag; + + type MemoryMap = MonoHashMap, Allocation)>; + + const STATIC_KIND: Option = Some(MiriMemoryKind::Static); + + #[inline(always)] + fn enforce_validity(ecx: &InterpretCx<'mir, 'tcx, Self>) -> bool { + ecx.machine.validate + } + + /// Returns `Ok()` when the function was handled; fail otherwise. + #[inline(always)] + fn find_fn( + ecx: &mut InterpretCx<'mir, 'tcx, Self>, + instance: ty::Instance<'tcx>, + args: &[OpTy<'tcx, Tag>], + dest: Option>, + ret: Option, + ) -> InterpResult<'tcx, Option<&'mir mir::Body<'tcx>>> { + ecx.find_fn(instance, args, dest, ret) + } + + #[inline(always)] + fn call_intrinsic( + ecx: &mut rustc_mir::interpret::InterpretCx<'mir, 'tcx, Self>, + instance: ty::Instance<'tcx>, + args: &[OpTy<'tcx, Tag>], + dest: PlaceTy<'tcx, Tag>, + ) -> InterpResult<'tcx> { + ecx.call_intrinsic(instance, args, dest) + } + + #[inline(always)] + fn ptr_op( + ecx: &rustc_mir::interpret::InterpretCx<'mir, 'tcx, Self>, + bin_op: mir::BinOp, + left: ImmTy<'tcx, Tag>, + right: ImmTy<'tcx, Tag>, + ) -> InterpResult<'tcx, (Scalar, bool)> { + ecx.ptr_op(bin_op, left, right) + } + + fn box_alloc( + ecx: &mut InterpretCx<'mir, 'tcx, Self>, + dest: PlaceTy<'tcx, Tag>, + ) -> InterpResult<'tcx> { + trace!("box_alloc for {:?}", dest.layout.ty); + // Call the `exchange_malloc` lang item. + let malloc = ecx.tcx.lang_items().exchange_malloc_fn().unwrap(); + let malloc = ty::Instance::mono(ecx.tcx.tcx, malloc); + let malloc_mir = ecx.load_mir(malloc.def)?; + ecx.push_stack_frame( + malloc, + malloc_mir.span, + malloc_mir, + Some(dest), + // Don't do anything when we are done. The `statement()` function will increment + // the old stack frame's stmt counter to the next statement, which means that when + // `exchange_malloc` returns, we go on evaluating exactly where we want to be. + StackPopCleanup::None { cleanup: true }, + )?; + + let mut args = ecx.frame().body.args_iter(); + let layout = ecx.layout_of(dest.layout.ty.builtin_deref(false).unwrap().ty)?; + + // First argument: `size`. + // (`0` is allowed here -- this is expected to be handled by the lang item). + let arg = ecx.eval_place(&mir::Place::Base(mir::PlaceBase::Local(args.next().unwrap())))?; + let size = layout.size.bytes(); + ecx.write_scalar(Scalar::from_uint(size, arg.layout.size), arg)?; + + // Second argument: `align`. + let arg = ecx.eval_place(&mir::Place::Base(mir::PlaceBase::Local(args.next().unwrap())))?; + let align = layout.align.abi.bytes(); + ecx.write_scalar(Scalar::from_uint(align, arg.layout.size), arg)?; + + // No more arguments. + assert!( + args.next().is_none(), + "`exchange_malloc` lang item has more arguments than expected" + ); + Ok(()) + } + + fn find_foreign_static( + def_id: DefId, + tcx: TyCtxtAt<'tcx>, + ) -> InterpResult<'tcx, Cow<'tcx, Allocation>> { + let attrs = tcx.get_attrs(def_id); + let link_name = match attr::first_attr_value_str_by_name(&attrs, sym::link_name) { + Some(name) => name.as_str(), + None => tcx.item_name(def_id).as_str(), + }; + + let alloc = match link_name.get() { + "__cxa_thread_atexit_impl" => { + // This should be all-zero, pointer-sized. + let size = tcx.data_layout.pointer_size; + let data = vec![0; size.bytes() as usize]; + Allocation::from_bytes(&data, tcx.data_layout.pointer_align.abi) + } + _ => return err!(Unimplemented( + format!("can't access foreign static: {}", link_name), + )), + }; + Ok(Cow::Owned(alloc)) + } + + #[inline(always)] + fn before_terminator(_ecx: &mut InterpretCx<'mir, 'tcx, Self>) -> InterpResult<'tcx> + { + // We are not interested in detecting loops. + Ok(()) + } + + fn tag_allocation<'b>( + id: AllocId, + alloc: Cow<'b, Allocation>, + kind: Option>, + memory: &Memory<'mir, 'tcx, Self>, + ) -> (Cow<'b, Allocation>, Self::PointerTag) { + let kind = kind.expect("we set our STATIC_KIND so this cannot be None"); + let alloc = alloc.into_owned(); + let (stacks, base_tag) = Stacks::new_allocation( + id, + Size::from_bytes(alloc.bytes.len() as u64), + Rc::clone(&memory.extra.stacked_borrows), + kind, + ); + if kind != MiriMemoryKind::Static.into() { + assert!(alloc.relocations.is_empty(), "Only statics can come initialized with inner pointers"); + // Now we can rely on the inner pointers being static, too. + } + let mut memory_extra = memory.extra.stacked_borrows.borrow_mut(); + let alloc: Allocation = Allocation { + bytes: alloc.bytes, + relocations: Relocations::from_presorted( + alloc.relocations.iter() + // The allocations in the relocations (pointers stored *inside* this allocation) + // all get the base pointer tag. + .map(|&(offset, ((), alloc))| (offset, (memory_extra.static_base_ptr(alloc), alloc))) + .collect() + ), + undef_mask: alloc.undef_mask, + align: alloc.align, + mutability: alloc.mutability, + extra: AllocExtra { + stacked_borrows: stacks, + intptrcast: Default::default(), + }, + }; + (Cow::Owned(alloc), base_tag) + } + + #[inline(always)] + fn tag_static_base_pointer( + id: AllocId, + memory: &Memory<'mir, 'tcx, Self>, + ) -> Self::PointerTag { + memory.extra.stacked_borrows.borrow_mut().static_base_ptr(id) + } + + #[inline(always)] + fn retag( + ecx: &mut InterpretCx<'mir, 'tcx, Self>, + kind: mir::RetagKind, + place: PlaceTy<'tcx, Tag>, + ) -> InterpResult<'tcx> { + if !ecx.tcx.sess.opts.debugging_opts.mir_emit_retag || !Self::enforce_validity(ecx) { + // No tracking, or no retagging. The latter is possible because a dependency of ours + // might be called with different flags than we are, so there are `Retag` + // statements but we do not want to execute them. + // Also, honor the whitelist in `enforce_validity` because otherwise we might retag + // uninitialized data. + Ok(()) + } else { + ecx.retag(kind, place) + } + } + + #[inline(always)] + fn stack_push( + ecx: &mut InterpretCx<'mir, 'tcx, Self>, + ) -> InterpResult<'tcx, stacked_borrows::CallId> { + Ok(ecx.memory().extra.stacked_borrows.borrow_mut().new_call()) + } + + #[inline(always)] + fn stack_pop( + ecx: &mut InterpretCx<'mir, 'tcx, Self>, + extra: stacked_borrows::CallId, + ) -> InterpResult<'tcx> { + Ok(ecx.memory().extra.stacked_borrows.borrow_mut().end_call(extra)) + } + + fn int_to_ptr( + int: u64, + memory: &Memory<'mir, 'tcx, Self>, + ) -> InterpResult<'tcx, Pointer> { + if int == 0 { + err!(InvalidNullPointerUsage) + } else if memory.extra.rng.is_none() { + err!(ReadBytesAsPointer) + } else { + intptrcast::GlobalState::int_to_ptr(int, memory) + } + } + + fn ptr_to_int( + ptr: Pointer, + memory: &Memory<'mir, 'tcx, Self>, + ) -> InterpResult<'tcx, u64> { + if memory.extra.rng.is_none() { + err!(ReadPointerAsBytes) + } else { + intptrcast::GlobalState::ptr_to_int(ptr, memory) + } + } +} + +impl AllocationExtra for AllocExtra { + #[inline(always)] + fn memory_read<'tcx>( + alloc: &Allocation, + ptr: Pointer, + size: Size, + ) -> InterpResult<'tcx> { + alloc.extra.stacked_borrows.memory_read(ptr, size) + } + + #[inline(always)] + fn memory_written<'tcx>( + alloc: &mut Allocation, + ptr: Pointer, + size: Size, + ) -> InterpResult<'tcx> { + alloc.extra.stacked_borrows.memory_written(ptr, size) + } + + #[inline(always)] + fn memory_deallocated<'tcx>( + alloc: &mut Allocation, + ptr: Pointer, + size: Size, + ) -> InterpResult<'tcx> { + alloc.extra.stacked_borrows.memory_deallocated(ptr, size) + } +} + +impl MayLeak for MiriMemoryKind { + #[inline(always)] + fn may_leak(self) -> bool { + use self::MiriMemoryKind::*; + match self { + Rust | C => false, + Env | Static => true, + } + } +} diff --git a/src/memory.rs b/src/memory.rs deleted file mode 100644 index ea8f01a808c04..0000000000000 --- a/src/memory.rs +++ /dev/null @@ -1,51 +0,0 @@ -use rand::rngs::StdRng; - -use rustc_mir::interpret::{Pointer, Allocation, AllocationExtra, InterpResult}; -use rustc_target::abi::Size; - -use crate::{stacked_borrows, intptrcast}; -use crate::stacked_borrows::Tag; - -#[derive(Default, Clone, Debug)] -pub struct MemoryExtra { - pub stacked_borrows: stacked_borrows::MemoryExtra, - pub intptrcast: intptrcast::MemoryExtra, - /// The random number generator to use if Miri is running in non-deterministic mode and to - /// enable intptrcast - pub(crate) rng: Option -} - -#[derive(Debug, Clone)] -pub struct AllocExtra { - pub stacked_borrows: stacked_borrows::AllocExtra, - pub intptrcast: intptrcast::AllocExtra, -} - -impl AllocationExtra for AllocExtra { - #[inline(always)] - fn memory_read<'tcx>( - alloc: &Allocation, - ptr: Pointer, - size: Size, - ) -> InterpResult<'tcx> { - alloc.extra.stacked_borrows.memory_read(ptr, size) - } - - #[inline(always)] - fn memory_written<'tcx>( - alloc: &mut Allocation, - ptr: Pointer, - size: Size, - ) -> InterpResult<'tcx> { - alloc.extra.stacked_borrows.memory_written(ptr, size) - } - - #[inline(always)] - fn memory_deallocated<'tcx>( - alloc: &mut Allocation, - ptr: Pointer, - size: Size, - ) -> InterpResult<'tcx> { - alloc.extra.stacked_borrows.memory_deallocated(ptr, size) - } -} diff --git a/src/operator.rs b/src/operator.rs index 572794a44add4..0e25de7da5a95 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -1,4 +1,4 @@ -use rustc::ty::Ty; +use rustc::ty::{Ty, layout::{Size, LayoutOf}}; use rustc::mir; use crate::*; From aa5a9bc15233960b8c375e1fa45fd11e5ae5b6cb Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 29 Jun 2019 14:15:05 +0200 Subject: [PATCH 0857/3747] some module comments --- src/eval.rs | 2 ++ src/machine.rs | 3 +++ src/range_map.rs | 5 +---- src/stacked_borrows.rs | 3 +++ src/tls.rs | 2 ++ 5 files changed, 11 insertions(+), 4 deletions(-) diff --git a/src/eval.rs b/src/eval.rs index fd5404a981d2c..616e11a51561f 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -1,3 +1,5 @@ +//! Main evaluator loop and setting up the initial stack frame. + use rand::rngs::StdRng; use rand::SeedableRng; diff --git a/src/machine.rs b/src/machine.rs index 8ef5410f395f4..9785d6a45560c 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -1,3 +1,6 @@ +//! Global machine state as well as implementation of the interpreter engine +//! `Machine` trait. + use std::rc::Rc; use std::borrow::Cow; use std::collections::HashMap; diff --git a/src/range_map.rs b/src/range_map.rs index 16e7e27241798..f2cbd89f64da6 100644 --- a/src/range_map.rs +++ b/src/range_map.rs @@ -1,5 +1,3 @@ -#![allow(unused)] - //! Implements a map from integer indices to data. //! Rather than storing data for every index, internally, this maps entire ranges to the data. //! To this end, the APIs all work on ranges, not on individual integers. Ranges are split as @@ -8,7 +6,6 @@ //! via the iteration APIs. use std::ops; -use std::num::NonZeroU64; use rustc::ty::layout::Size; @@ -158,7 +155,7 @@ impl RangeMap { let mut end_idx = first_idx; // when the loop is done, this is the first excluded element. loop { // Compute if `end` is the last element we need to look at. - let done = (self.v[end_idx].range.end >= offset+len); + let done = self.v[end_idx].range.end >= offset+len; // We definitely need to include `end`, so move the index. end_idx += 1; debug_assert!(done || end_idx < self.v.len(), "iter_mut: end-offset {} is out-of-bounds", offset+len); diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 524ad2b47af0e..6e5bbf50941bd 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -1,3 +1,6 @@ +//! Implements "Stacked Borrows". See +//! for further information. + use std::cell::RefCell; use std::collections::{HashMap, HashSet}; use std::rc::Rc; diff --git a/src/tls.rs b/src/tls.rs index ddc301447c7e3..73c778f66d25d 100644 --- a/src/tls.rs +++ b/src/tls.rs @@ -1,3 +1,5 @@ +//! Implement thread-local storage. + use std::collections::BTreeMap; use rustc_target::abi::LayoutOf; From c0b44ca98cab26289e3e6c435bab5574f30f0a09 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 28 Jun 2019 10:16:10 +0200 Subject: [PATCH 0858/3747] tweak inttoptr allocation behavior - Make `align_addr` not offset by `align` for no reason. - Add some random slack between allocations to give them the chance to not be aligned. --- src/eval.rs | 4 ++-- src/fn_call.rs | 1 + src/intptrcast.rs | 36 +++++++++++++++++++++++++++++++----- src/machine.rs | 5 +++-- 4 files changed, 37 insertions(+), 9 deletions(-) diff --git a/src/eval.rs b/src/eval.rs index 5f7d85b7445f7..ec97a77357cf8 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -10,7 +10,7 @@ use rustc::mir; use crate::{ InterpResult, InterpError, InterpretCx, StackPopCleanup, struct_error, Scalar, Tag, Pointer, - MiriMemoryKind, Evaluator, TlsEvalContextExt, + MemoryExtra, MiriMemoryKind, Evaluator, TlsEvalContextExt, }; /// Configuration needed to spawn a Miri instance. @@ -36,7 +36,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( ); // FIXME: InterpretCx::new should take an initial MemoryExtra - ecx.memory_mut().extra.rng = config.seed.map(StdRng::seed_from_u64); + ecx.memory_mut().extra = MemoryExtra::with_rng(config.seed.map(StdRng::seed_from_u64)); let main_instance = ty::Instance::mono(ecx.tcx.tcx, main_id); let main_mir = ecx.load_mir(main_instance.def)?; diff --git a/src/fn_call.rs b/src/fn_call.rs index e2a4daa6f3853..66783f3200e0d 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -982,6 +982,7 @@ fn gen_random<'mir, 'tcx>( let data = match &mut this.memory_mut().extra.rng { Some(rng) => { + let mut rng = rng.borrow_mut(); let mut data = vec![0; len]; rng.fill_bytes(&mut data); data diff --git a/src/intptrcast.rs b/src/intptrcast.rs index 176e1bc591c2e..aa2e11ac68dbe 100644 --- a/src/intptrcast.rs +++ b/src/intptrcast.rs @@ -1,5 +1,7 @@ use std::cell::{Cell, RefCell}; +use rand::Rng; + use rustc::mir::interpret::{AllocId, Pointer, InterpResult}; use rustc_mir::interpret::Memory; use rustc_target::abi::Size; @@ -73,14 +75,23 @@ impl<'mir, 'tcx> GlobalState { let mut global_state = memory.extra.intptrcast.borrow_mut(); let alloc = memory.get(ptr.alloc_id)?; + let align = alloc.align.bytes(); let base_addr = match alloc.extra.intptrcast.base_addr.get() { Some(base_addr) => base_addr, None => { // This allocation does not have a base address yet, pick one. - let base_addr = Self::align_addr(global_state.next_base_addr, alloc.align.bytes()); - global_state.next_base_addr = base_addr + alloc.bytes.len() as u64; + // Leave some space to the previous allocation, to give it some chance to be less aligned. + let slack = { + let mut rng = memory.extra.rng.as_ref().unwrap().borrow_mut(); + rng.gen_range(0, align) + }; + // From next_base_addr + slack, round up to adjust for alignment. + let base_addr = Self::align_addr(global_state.next_base_addr + slack, align); alloc.extra.intptrcast.base_addr.set(Some(base_addr)); + + // Remember next base address. + global_state.next_base_addr = base_addr + alloc.bytes.len() as u64; // Given that `next_base_addr` increases in each allocation, pushing the // corresponding tuple keeps `int_to_ptr_map` sorted global_state.int_to_ptr_map.push((base_addr, ptr.alloc_id)); @@ -89,13 +100,28 @@ impl<'mir, 'tcx> GlobalState { } }; - debug_assert_eq!(base_addr % alloc.align.bytes(), 0); // sanity check + debug_assert_eq!(base_addr % align, 0); // sanity check Ok(base_addr + ptr.offset.bytes()) } /// Shifts `addr` to make it aligned with `align` by rounding `addr` to the smallest multiple - /// of `align` that is strictly larger to `addr` + /// of `align` that is larger or equal to `addr` fn align_addr(addr: u64, align: u64) -> u64 { - addr + align - addr % align + if addr % align == 0 { + addr + } else { + addr + align - addr % align + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_align_addr() { + assert_eq!(GlobalState::align_addr(37, 4), 40); + assert_eq!(GlobalState::align_addr(44, 4), 44); } } diff --git a/src/machine.rs b/src/machine.rs index eb177fa2a1859..c956fd0f33a98 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -1,6 +1,7 @@ use std::rc::Rc; use std::borrow::Cow; use std::collections::HashMap; +use std::cell::RefCell; use rand::rngs::StdRng; @@ -46,7 +47,7 @@ pub struct MemoryExtra { pub intptrcast: intptrcast::MemoryExtra, /// The random number generator to use if Miri is running in non-deterministic mode and to /// enable intptrcast - pub(crate) rng: Option + pub(crate) rng: Option> } impl MemoryExtra { @@ -54,7 +55,7 @@ impl MemoryExtra { MemoryExtra { stacked_borrows: Default::default(), intptrcast: Default::default(), - rng, + rng: rng.map(RefCell::new), } } } From 9b66527075fafba9c058137a6943cf2e0d312000 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 28 Jun 2019 10:23:29 +0200 Subject: [PATCH 0859/3747] more sensible slack --- src/intptrcast.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/intptrcast.rs b/src/intptrcast.rs index aa2e11ac68dbe..df7217965c814 100644 --- a/src/intptrcast.rs +++ b/src/intptrcast.rs @@ -84,7 +84,8 @@ impl<'mir, 'tcx> GlobalState { // Leave some space to the previous allocation, to give it some chance to be less aligned. let slack = { let mut rng = memory.extra.rng.as_ref().unwrap().borrow_mut(); - rng.gen_range(0, align) + // This means that `(global_state.next_base_addr + slack) % 16` is uniformly distributed. + rng.gen_range(0, 16) }; // From next_base_addr + slack, round up to adjust for alignment. let base_addr = Self::align_addr(global_state.next_base_addr + slack, align); From c1645f6c6582f6017cd8e330372bbaa21d95e3f3 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 28 Jun 2019 10:24:16 +0200 Subject: [PATCH 0860/3747] don't compute residue twice --- src/intptrcast.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/intptrcast.rs b/src/intptrcast.rs index df7217965c814..a41a139062d8d 100644 --- a/src/intptrcast.rs +++ b/src/intptrcast.rs @@ -108,10 +108,9 @@ impl<'mir, 'tcx> GlobalState { /// Shifts `addr` to make it aligned with `align` by rounding `addr` to the smallest multiple /// of `align` that is larger or equal to `addr` fn align_addr(addr: u64, align: u64) -> u64 { - if addr % align == 0 { - addr - } else { - addr + align - addr % align + match addr % align { + 0 => addr, + rem => addr + align - rem } } } From 0bb50ada34b3d4fe0ad6be0041f6bd68bacb1cb0 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 28 Jun 2019 10:27:19 +0200 Subject: [PATCH 0861/3747] make sure we catch alignment problems even with intrptrcast --- .../compile-fail/intptrcast_alignment_check.rs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 tests/compile-fail/intptrcast_alignment_check.rs diff --git a/tests/compile-fail/intptrcast_alignment_check.rs b/tests/compile-fail/intptrcast_alignment_check.rs new file mode 100644 index 0000000000000..5a35844d1256d --- /dev/null +++ b/tests/compile-fail/intptrcast_alignment_check.rs @@ -0,0 +1,18 @@ +// Validation makes this fail in the wrong place +// compile-flags: -Zmiri-disable-validation -Zmiri-seed=0000000000000000 + +// Even with intptrcast and without validation, we want to be *sure* to catch bugs +// that arise from pointers being insufficiently aligned. The only way to achieve +// that is not not let programs exploit integer information for alignment, so here +// we test that this is indeed the case. +fn main() { + let x = &mut [0u8; 3]; + let base_addr = x as *mut _ as usize; + let u16_ref = unsafe { if base_addr % 2 == 0 { + &mut *(base_addr as *mut u16) + } else { + &mut *((base_addr+1) as *mut u16) + } }; + *u16_ref = 2; //~ ERROR tried to access memory with alignment 1, but alignment 2 is required + println!("{:?}", x); +} From 0fac868685020a78b056facee7fa321a02457d5f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 29 Jun 2019 13:33:47 +0200 Subject: [PATCH 0862/3747] support num_cpus and test that --- src/fn_call.rs | 19 ++++++++++++------- src/intptrcast.rs | 6 ++---- src/lib.rs | 5 +++++ test-cargo-miri/Cargo.lock | 10 ++++++++++ test-cargo-miri/Cargo.toml | 1 + test-cargo-miri/run-test.py | 6 +++--- test-cargo-miri/src/main.rs | 3 +++ test-cargo-miri/test.stdout.ref | 8 +++++--- test-cargo-miri/test.stdout.ref2 | 4 ++-- test-cargo-miri/tests/test.rs | 26 +++++++++++++++++++------- 10 files changed, 62 insertions(+), 26 deletions(-) diff --git a/src/fn_call.rs b/src/fn_call.rs index e2a4daa6f3853..559524b2fe0b8 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -622,11 +622,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let name = this.read_scalar(args[0])?.to_i32()?; trace!("sysconf() called with name {}", name); - // Cache the sysconf integers via Miri's global cache. + // TODO: Cache the sysconf integers via Miri's global cache. let paths = &[ - (&["libc", "_SC_PAGESIZE"], Scalar::from_int(4096, dest.layout.size)), + (&["libc", "_SC_PAGESIZE"], Scalar::from_int(PAGE_SIZE, dest.layout.size)), (&["libc", "_SC_GETPW_R_SIZE_MAX"], Scalar::from_int(-1, dest.layout.size)), - (&["libc", "_SC_NPROCESSORS_ONLN"], Scalar::from_int(1, dest.layout.size)), + (&["libc", "_SC_NPROCESSORS_ONLN"], Scalar::from_int(NUM_CPUS, dest.layout.size)), ]; let mut result = None; for &(path, path_value) in paths { @@ -648,6 +648,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } + "sched_getaffinity" => { + // Return an error; `num_cpus` then falls back to `sysconf`. + this.write_scalar(Scalar::from_int(-1, dest.layout.size), dest)?; + } + "isatty" => { this.write_null(dest)?; } @@ -722,14 +727,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Second argument is where we are supposed to write the stack size. let ptr = this.deref_operand(args[1])?; // Just any address. - let stack_addr = Scalar::from_int(0x80000, args[1].layout.size); + let stack_addr = Scalar::from_uint(STACK_ADDR, args[1].layout.size); this.write_scalar(stack_addr, ptr.into())?; // Return success (`0`). this.write_null(dest)?; } "pthread_get_stackaddr_np" => { // Just any address. - let stack_addr = Scalar::from_int(0x80000, dest.layout.size); + let stack_addr = Scalar::from_uint(STACK_ADDR, dest.layout.size); this.write_scalar(stack_addr, dest)?; } @@ -838,14 +843,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Initialize with `0`. this.memory_mut().get_mut(system_info_ptr.alloc_id)? .write_repeat(tcx, system_info_ptr, 0, system_info.layout.size)?; - // Set number of processors to `1`. + // Set number of processors. let dword_size = Size::from_bytes(4); let offset = 2*dword_size + 3*tcx.pointer_size(); this.memory_mut().get_mut(system_info_ptr.alloc_id)? .write_scalar( tcx, system_info_ptr.offset(offset, tcx)?, - Scalar::from_int(1, dword_size).into(), + Scalar::from_int(NUM_CPUS, dword_size).into(), dword_size, )?; } diff --git a/src/intptrcast.rs b/src/intptrcast.rs index 176e1bc591c2e..83e500ea32dd5 100644 --- a/src/intptrcast.rs +++ b/src/intptrcast.rs @@ -4,8 +4,7 @@ use rustc::mir::interpret::{AllocId, Pointer, InterpResult}; use rustc_mir::interpret::Memory; use rustc_target::abi::Size; -use crate::stacked_borrows::Tag; -use crate::Evaluator; +use crate::{Evaluator, Tag, STACK_ADDR}; pub type MemoryExtra = RefCell; @@ -25,11 +24,10 @@ pub struct GlobalState { } impl Default for GlobalState { - // FIXME: Query the page size in the future fn default() -> Self { GlobalState { int_to_ptr_map: Vec::default(), - next_base_addr: 2u64.pow(16) + next_base_addr: STACK_ADDR, } } } diff --git a/src/lib.rs b/src/lib.rs index ab9e9854c34cb..567fdae53b435 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -40,6 +40,11 @@ pub use crate::stacked_borrows::{EvalContextExt as StackedBorEvalContextExt, Tag pub use crate::machine::{MemoryExtra, AllocExtra, MiriMemoryKind, Evaluator, MiriEvalContext, MiriEvalContextExt}; pub use crate::eval::{eval_main, create_ecx, MiriConfig}; +// Some global facts about the emulated machine. +pub const PAGE_SIZE: u64 = 4*1024; +pub const STACK_ADDR: u64 = 16*PAGE_SIZE; +pub const NUM_CPUS: u64 = 1; + /// Insert rustc arguments at the beginning of the argument list that Miri wants to be /// set per default, for maximal validation power. pub fn miri_default_args() -> &'static [&'static str] { diff --git a/test-cargo-miri/Cargo.lock b/test-cargo-miri/Cargo.lock index d404872f9db6d..8343832886a6b 100644 --- a/test-cargo-miri/Cargo.lock +++ b/test-cargo-miri/Cargo.lock @@ -29,6 +29,7 @@ name = "cargo-miri-test" version = "0.1.0" dependencies = [ "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -66,6 +67,14 @@ name = "libc" version = "0.2.58" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "num_cpus" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "ppv-lite86" version = "0.2.5" @@ -148,6 +157,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum getrandom 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8d1dffef07351aafe6ef177e4dd2b8dcf503e6bc765dea3b0de9ed149a3db1ec" "checksum lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bc5729f27f159ddd61f4df6228e827e86643d4d3e7c32183cb30a1c08f604a14" "checksum libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)" = "6281b86796ba5e4366000be6e9e18bf35580adf9e63fbe2294aadb587613a319" +"checksum num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bcef43580c035376c0705c42792c294b66974abbfd2789b511784023f71f3273" "checksum ppv-lite86 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e3cbf9f658cdb5000fcf6f362b8ea2ba154b9f146a61c7a20d647034c6b6561b" "checksum rand 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d47eab0e83d9693d40f825f86948aa16eff6750ead4bdffc4ab95b8b3a7f052c" "checksum rand_chacha 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e193067942ef6f485a349a113329140d0ab9e2168ce92274499bb0e9a4190d9d" diff --git a/test-cargo-miri/Cargo.toml b/test-cargo-miri/Cargo.toml index c7fc62b79e840..3abb437049f0f 100644 --- a/test-cargo-miri/Cargo.toml +++ b/test-cargo-miri/Cargo.toml @@ -9,3 +9,4 @@ byteorder = "1.0" [dev-dependencies] rand = { version = "0.7", features = ["small_rng"] } +num_cpus = "1.10.1" diff --git a/test-cargo-miri/run-test.py b/test-cargo-miri/run-test.py index 33664737709c0..73515c74e4010 100755 --- a/test-cargo-miri/run-test.py +++ b/test-cargo-miri/run-test.py @@ -8,7 +8,7 @@ import sys, subprocess, os def fail(msg): - print("TEST FAIL: {}".format(msg)) + print("\nTEST FAIL: {}".format(msg)) sys.exit(1) def cargo_miri(cmd): @@ -57,7 +57,7 @@ def test_cargo_miri_test(): "test.stdout.ref", "test.stderr.ref" ) test("cargo miri test (with filter)", - cargo_miri("test") + ["--", "--", "impl"], + cargo_miri("test") + ["--", "--", "le1"], "test.stdout.ref2", "test.stderr.ref" ) @@ -66,5 +66,5 @@ def test_cargo_miri_test(): test_cargo_miri_run() test_cargo_miri_test() -print("TEST SUCCESSFUL!") +print("\nTEST SUCCESSFUL!") sys.exit(0) diff --git a/test-cargo-miri/src/main.rs b/test-cargo-miri/src/main.rs index c21547c29ff9c..d3663ec849d36 100644 --- a/test-cargo-miri/src/main.rs +++ b/test-cargo-miri/src/main.rs @@ -1,10 +1,13 @@ use byteorder::{BigEndian, ByteOrder}; fn main() { + // Exercise external crate, printing to stdout. let buf = &[1,2,3,4]; let n = ::read_u32(buf); assert_eq!(n, 0x01020304); println!("{:#010x}", n); + + // Access program arguments, printing to stderr. for arg in std::env::args() { eprintln!("{}", arg); } diff --git a/test-cargo-miri/test.stdout.ref b/test-cargo-miri/test.stdout.ref index 58b9b4794b902..c2257e68e256c 100644 --- a/test-cargo-miri/test.stdout.ref +++ b/test-cargo-miri/test.stdout.ref @@ -5,9 +5,11 @@ test test::rng ... ok test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out -running 2 tests +running 4 tests test entropy_rng ... ok -test simple ... ok +test num_cpus ... ok +test simple1 ... ok +test simple2 ... ok -test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out +test result: ok. 4 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out diff --git a/test-cargo-miri/test.stdout.ref2 b/test-cargo-miri/test.stdout.ref2 index ce3506709d5a0..a6f6e915e0e85 100644 --- a/test-cargo-miri/test.stdout.ref2 +++ b/test-cargo-miri/test.stdout.ref2 @@ -5,7 +5,7 @@ test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 1 filtered out running 1 test -test simple ... ok +test simple1 ... ok -test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 1 filtered out +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 3 filtered out diff --git a/test-cargo-miri/tests/test.rs b/test-cargo-miri/tests/test.rs index ac0db2778cae2..cfbe3f6d7fb66 100644 --- a/test-cargo-miri/tests/test.rs +++ b/test-cargo-miri/tests/test.rs @@ -3,13 +3,28 @@ use rand::{SeedableRng, Rng, rngs::SmallRng}; // Having more than 1 test does seem to make a difference // (i.e., this calls ptr::swap which having just one test does not). #[test] -fn simple() { +fn simple1() { assert_eq!(4, 4); } +#[test] +fn simple2() { + assert_ne!(42, 24); +} + +// A test that won't work on miri (tests disabling tests) +#[cfg(not(miri))] +#[test] +fn does_not_work_on_miri() { + let x = 0u8; + assert!(&x as *const _ as usize % 4 < 4); +} + +// We also use this to test some external crates, that we cannot depend on in the compiletest suite. + #[test] fn entropy_rng() { - // Use this opportunity to test querying the RNG (needs an external crate, hence tested here and not in the compiletest suite) + // Try seeding with "real" entropy. let mut rng = SmallRng::from_entropy(); let _val = rng.gen::(); let _val = rng.gen::(); @@ -22,10 +37,7 @@ fn entropy_rng() { let _val = rng.gen::(); } -// A test that won't work on miri -#[cfg(not(miri))] #[test] -fn does_not_work_on_miri() { - let x = 0u8; - assert!(&x as *const _ as usize % 4 < 4); +fn num_cpus() { + assert_eq!(num_cpus::get(), 1); } From c7bf9064f7028a9e43feaf699e23f1443704e448 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 29 Jun 2019 13:37:38 +0200 Subject: [PATCH 0863/3747] comment on STACK_ADDR --- src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 567fdae53b435..66b6afde3317e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -42,7 +42,7 @@ pub use crate::eval::{eval_main, create_ecx, MiriConfig}; // Some global facts about the emulated machine. pub const PAGE_SIZE: u64 = 4*1024; -pub const STACK_ADDR: u64 = 16*PAGE_SIZE; +pub const STACK_ADDR: u64 = 16*PAGE_SIZE; // not really about the "stack", but where we start assigning integer addresses to allocations pub const NUM_CPUS: u64 = 1; /// Insert rustc arguments at the beginning of the argument list that Miri wants to be From 019ad4bab456bf107cba54dc8c396fbdd6d2bae0 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 29 Jun 2019 14:37:41 +0200 Subject: [PATCH 0864/3747] move constants to machine.rs --- src/lib.rs | 10 ++++------ src/machine.rs | 5 +++++ 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 66b6afde3317e..0e4a9c4ccc37c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -37,14 +37,12 @@ pub use crate::range_map::RangeMap; pub use crate::helpers::{EvalContextExt as HelpersEvalContextExt}; pub use crate::mono_hash_map::MonoHashMap; pub use crate::stacked_borrows::{EvalContextExt as StackedBorEvalContextExt, Tag, Permission, Stack, Stacks, Item}; -pub use crate::machine::{MemoryExtra, AllocExtra, MiriMemoryKind, Evaluator, MiriEvalContext, MiriEvalContextExt}; +pub use crate::machine::{ + PAGE_SIZE, STACK_ADDR, NUM_CPUS, + MemoryExtra, AllocExtra, MiriMemoryKind, Evaluator, MiriEvalContext, MiriEvalContextExt, +}; pub use crate::eval::{eval_main, create_ecx, MiriConfig}; -// Some global facts about the emulated machine. -pub const PAGE_SIZE: u64 = 4*1024; -pub const STACK_ADDR: u64 = 16*PAGE_SIZE; // not really about the "stack", but where we start assigning integer addresses to allocations -pub const NUM_CPUS: u64 = 1; - /// Insert rustc arguments at the beginning of the argument list that Miri wants to be /// set per default, for maximal validation power. pub fn miri_default_args() -> &'static [&'static str] { diff --git a/src/machine.rs b/src/machine.rs index eb177fa2a1859..383b6aac631e7 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -12,6 +12,11 @@ use rustc::mir; use crate::*; +// Some global facts about the emulated machine. +pub const PAGE_SIZE: u64 = 4*1024; // FIXME: adjust to target architecture +pub const STACK_ADDR: u64 = 16*PAGE_SIZE; // not really about the "stack", but where we start assigning integer addresses to allocations +pub const NUM_CPUS: u64 = 1; + /// Extra memory kinds #[derive(Debug, Copy, Clone, PartialEq, Eq)] pub enum MiriMemoryKind { From 11457a4ad942ec35952682f474556f6eae2d4db3 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 30 Jun 2019 10:59:42 +0200 Subject: [PATCH 0865/3747] fix comparing function pointers with intptrcast --- src/intptrcast.rs | 39 +++++++++++++------------ src/machine.rs | 2 -- tests/run-pass/intptrcast_format.rs | 6 ++++ tests/run-pass/intptrcast_format.stdout | 2 ++ 4 files changed, 29 insertions(+), 20 deletions(-) create mode 100644 tests/run-pass/intptrcast_format.rs create mode 100644 tests/run-pass/intptrcast_format.stdout diff --git a/src/intptrcast.rs b/src/intptrcast.rs index 7fd48defda13c..f8102642bdb46 100644 --- a/src/intptrcast.rs +++ b/src/intptrcast.rs @@ -1,25 +1,26 @@ -use std::cell::{Cell, RefCell}; +use std::cell::RefCell; +use std::collections::{HashMap, hash_map::Entry}; +use std::cmp::max; use rand::Rng; -use rustc::mir::interpret::{AllocId, Pointer, InterpResult}; -use rustc_mir::interpret::Memory; +use rustc_mir::interpret::{AllocId, Pointer, InterpResult, Memory, AllocCheck}; use rustc_target::abi::Size; use crate::{Evaluator, Tag, STACK_ADDR}; pub type MemoryExtra = RefCell; -#[derive(Clone, Debug, Default)] -pub struct AllocExtra { - base_addr: Cell> -} - #[derive(Clone, Debug)] pub struct GlobalState { /// This is used as a map between the address of each allocation and its `AllocId`. /// It is always sorted pub int_to_ptr_map: Vec<(u64, AllocId)>, + /// The base address for each allocation. We cannot put that into + /// `AllocExtra` because function pointers also have a base address, and + /// they do not have an `AllocExtra`. + /// This is the inverse of `int_to_ptr_map`. + pub base_addr: HashMap, /// This is used as a memory address when a new pointer is casted to an integer. It /// is always larger than any address that was previously made part of a block. pub next_base_addr: u64, @@ -29,6 +30,7 @@ impl Default for GlobalState { fn default() -> Self { GlobalState { int_to_ptr_map: Vec::default(), + base_addr: HashMap::default(), next_base_addr: STACK_ADDR, } } @@ -71,13 +73,13 @@ impl<'mir, 'tcx> GlobalState { memory: &Memory<'mir, 'tcx, Evaluator<'tcx>>, ) -> InterpResult<'tcx, u64> { let mut global_state = memory.extra.intptrcast.borrow_mut(); + let global_state = &mut *global_state; - let alloc = memory.get(ptr.alloc_id)?; - let align = alloc.align.bytes(); + let (size, align) = memory.get_size_and_align(ptr.alloc_id, AllocCheck::Live)?; - let base_addr = match alloc.extra.intptrcast.base_addr.get() { - Some(base_addr) => base_addr, - None => { + let base_addr = match global_state.base_addr.entry(ptr.alloc_id) { + Entry::Occupied(entry) => *entry.get(), + Entry::Vacant(entry) => { // This allocation does not have a base address yet, pick one. // Leave some space to the previous allocation, to give it some chance to be less aligned. let slack = { @@ -86,11 +88,12 @@ impl<'mir, 'tcx> GlobalState { rng.gen_range(0, 16) }; // From next_base_addr + slack, round up to adjust for alignment. - let base_addr = Self::align_addr(global_state.next_base_addr + slack, align); - alloc.extra.intptrcast.base_addr.set(Some(base_addr)); + let base_addr = Self::align_addr(global_state.next_base_addr + slack, align.bytes()); + entry.insert(base_addr); - // Remember next base address. - global_state.next_base_addr = base_addr + alloc.bytes.len() as u64; + // Remember next base address. If this allocation is zero-sized, leave a gap + // of at least 1 to avoid two allocations having the same base address. + global_state.next_base_addr = base_addr + max(size.bytes(), 1); // Given that `next_base_addr` increases in each allocation, pushing the // corresponding tuple keeps `int_to_ptr_map` sorted global_state.int_to_ptr_map.push((base_addr, ptr.alloc_id)); @@ -99,7 +102,7 @@ impl<'mir, 'tcx> GlobalState { } }; - debug_assert_eq!(base_addr % align, 0); // sanity check + debug_assert_eq!(base_addr % align.bytes(), 0); // sanity check Ok(base_addr + ptr.offset.bytes()) } diff --git a/src/machine.rs b/src/machine.rs index 485286ea400dd..20fe2e055fb53 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -42,7 +42,6 @@ impl Into> for MiriMemoryKind { #[derive(Debug, Clone)] pub struct AllocExtra { pub stacked_borrows: stacked_borrows::AllocExtra, - pub intptrcast: intptrcast::AllocExtra, } /// Extra global memory data @@ -277,7 +276,6 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { mutability: alloc.mutability, extra: AllocExtra { stacked_borrows: stacks, - intptrcast: Default::default(), }, }; (Cow::Owned(alloc), base_tag) diff --git a/tests/run-pass/intptrcast_format.rs b/tests/run-pass/intptrcast_format.rs new file mode 100644 index 0000000000000..c0d3e9398dc5d --- /dev/null +++ b/tests/run-pass/intptrcast_format.rs @@ -0,0 +1,6 @@ +// compile-flags: -Zmiri-seed= + +fn main() { + println!("Hello {}", 13); + println!("{:0 Date: Sun, 30 Jun 2019 15:35:28 +0200 Subject: [PATCH 0866/3747] move shims (foreign items and intrinsics) into submodule --- src/lib.rs | 7 +++---- src/{fn_call.rs => shims/foreign_items.rs} | 0 src/{intrinsic.rs => shims/intrinsics.rs} | 0 src/shims/mod.rs | 2 ++ 4 files changed, 5 insertions(+), 4 deletions(-) rename src/{fn_call.rs => shims/foreign_items.rs} (100%) rename src/{intrinsic.rs => shims/intrinsics.rs} (100%) create mode 100644 src/shims/mod.rs diff --git a/src/lib.rs b/src/lib.rs index 0e4a9c4ccc37c..6b2de4ac08be4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -12,9 +12,8 @@ extern crate rustc_data_structures; extern crate rustc_mir; extern crate rustc_target; -mod fn_call; +mod shims; mod operator; -mod intrinsic; mod helpers; mod tls; mod range_map; @@ -29,9 +28,9 @@ pub use rustc_mir::interpret::*; // Resolve ambiguity. pub use rustc_mir::interpret::{self, AllocMap, PlaceTy}; -pub use crate::fn_call::EvalContextExt as MissingFnsEvalContextExt; +pub use crate::shims::foreign_items::EvalContextExt as ForeignItemsEvalContextExt; +pub use crate::shims::intrinsics::EvalContextExt as IntrinsicsEvalContextExt; pub use crate::operator::EvalContextExt as OperatorEvalContextExt; -pub use crate::intrinsic::EvalContextExt as IntrinsicEvalContextExt; pub use crate::tls::{EvalContextExt as TlsEvalContextExt, TlsData}; pub use crate::range_map::RangeMap; pub use crate::helpers::{EvalContextExt as HelpersEvalContextExt}; diff --git a/src/fn_call.rs b/src/shims/foreign_items.rs similarity index 100% rename from src/fn_call.rs rename to src/shims/foreign_items.rs diff --git a/src/intrinsic.rs b/src/shims/intrinsics.rs similarity index 100% rename from src/intrinsic.rs rename to src/shims/intrinsics.rs diff --git a/src/shims/mod.rs b/src/shims/mod.rs new file mode 100644 index 0000000000000..cadfc05681dad --- /dev/null +++ b/src/shims/mod.rs @@ -0,0 +1,2 @@ +pub mod foreign_items; +pub mod intrinsics; From 5d4aae8c05c6389c41b0cf5585c9dd1a645bfbd3 Mon Sep 17 00:00:00 2001 From: varkor Date: Sun, 30 Jun 2019 15:31:14 +0100 Subject: [PATCH 0867/3747] Fix `unused_must_use` inside `Box` After https://github.com/rust-lang/rust/pull/62228, this will be linted against (and causes the test to fail). --- tests/run-pass/issue-30530.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/run-pass/issue-30530.rs b/tests/run-pass/issue-30530.rs index 10dec30c64ca7..86c2d9184e016 100644 --- a/tests/run-pass/issue-30530.rs +++ b/tests/run-pass/issue-30530.rs @@ -21,7 +21,9 @@ pub enum Handler { } fn main() { - take(Handler::Default, Box::new(main)); + #[allow(unused_must_use)] { + take(Handler::Default, Box::new(main)); + } } #[inline(never)] From db6283b88447577f11e13b6eca99dfb7d0215b1b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 30 Jun 2019 16:44:25 +0200 Subject: [PATCH 0868/3747] better name for a test: threads -> sync --- tests/run-pass/{threads.rs => sync.rs} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename tests/run-pass/{threads.rs => sync.rs} (100%) diff --git a/tests/run-pass/threads.rs b/tests/run-pass/sync.rs similarity index 100% rename from tests/run-pass/threads.rs rename to tests/run-pass/sync.rs From e44d38e0511376b73e1a17588780b21c359789f6 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 30 Jun 2019 16:45:41 +0200 Subject: [PATCH 0869/3747] improve comment --- tests/run-pass/sync.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/run-pass/sync.rs b/tests/run-pass/sync.rs index dad47d85a2466..54d79566eae4b 100644 --- a/tests/run-pass/sync.rs +++ b/tests/run-pass/sync.rs @@ -8,8 +8,7 @@ fn main() { drop(m.lock()); drop(m); - // We don't provide RwLock on Windows - #[cfg(not(target_os = "windows"))] + #[cfg(not(target_os = "windows"))] // TODO: implement RwLock on Windows { let rw = sync::RwLock::new(0); drop(rw.read()); From b06731355205f0a4ffa1464137b1d55992f08b48 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 30 Jun 2019 16:56:16 +0200 Subject: [PATCH 0870/3747] use intptrcast for heap_allocator test; then it should work on Windows --- tests/run-pass/heap_allocator.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/run-pass/heap_allocator.rs b/tests/run-pass/heap_allocator.rs index b201f24e25634..457734cb602c9 100644 --- a/tests/run-pass/heap_allocator.rs +++ b/tests/run-pass/heap_allocator.rs @@ -1,3 +1,4 @@ +// compile-flag: -Zmiri-seed= #![feature(allocator_api)] use std::ptr::NonNull; @@ -75,7 +76,6 @@ fn box_to_global() { fn main() { check_alloc(System); check_alloc(Global); - #[cfg(not(target_os = "windows"))] // TODO: Inspects allocation base address on Windows; needs intptrcast model check_overalign_requests(System); check_overalign_requests(Global); global_to_box(); From 0ea4b50025ea71e11aa8b326508b4d40e998727a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 30 Jun 2019 17:02:20 +0200 Subject: [PATCH 0871/3747] Miri is not deterministic any more --- tests/run-pass/heap_allocator.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/run-pass/heap_allocator.rs b/tests/run-pass/heap_allocator.rs index 457734cb602c9..3eb0f70fd6624 100644 --- a/tests/run-pass/heap_allocator.rs +++ b/tests/run-pass/heap_allocator.rs @@ -33,8 +33,8 @@ fn check_overalign_requests(mut allocator: T) { let size = 8; // Greater than `size`. let align = 16; - // Miri is deterministic; no need to try many times. - let iterations = 1; + + let iterations = 5; unsafe { let pointers: Vec<_> = (0..iterations).map(|_| { allocator.alloc(Layout::from_size_align(size, align).unwrap()).unwrap() From 78261b788d0107efed65b4fb24e18c1a7ff5840b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 30 Jun 2019 19:10:09 +0200 Subject: [PATCH 0872/3747] fix setting rustc flags --- tests/run-pass/heap_allocator.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/run-pass/heap_allocator.rs b/tests/run-pass/heap_allocator.rs index 3eb0f70fd6624..57db5407b7af5 100644 --- a/tests/run-pass/heap_allocator.rs +++ b/tests/run-pass/heap_allocator.rs @@ -1,4 +1,4 @@ -// compile-flag: -Zmiri-seed= +// compile-flags: -Zmiri-seed= #![feature(allocator_api)] use std::ptr::NonNull; From a04890795db44682f4afd276dbb7277eee3bcc11 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 30 Jun 2019 21:03:52 +0200 Subject: [PATCH 0873/3747] move appveyor env var settings to more appropriate section --- .appveyor.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index f7d3f990ac999..4e8b8cd4b898b 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -29,8 +29,6 @@ install: - rustc --version build_script: - - set RUST_TEST_NOCAPTURE=1 - - set RUST_BACKTRACE=1 - set RUSTFLAGS=-C debug-assertions # Build and install miri - cargo build --release --all-features --all-targets @@ -40,6 +38,8 @@ build_script: - set MIRI_SYSROOT=%USERPROFILE%\AppData\Local\rust-lang\miri\cache\HOST test_script: + - set RUST_TEST_NOCAPTURE=1 + - set RUST_BACKTRACE=1 # Test miri - cargo test --release --all-features # Test cargo integration From e960270662e74aa19beee319641e12d67e45aa07 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 30 Jun 2019 21:06:32 +0200 Subject: [PATCH 0874/3747] add some tracing to intptrcast --- src/intptrcast.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/intptrcast.rs b/src/intptrcast.rs index f8102642bdb46..5480700005075 100644 --- a/src/intptrcast.rs +++ b/src/intptrcast.rs @@ -90,6 +90,10 @@ impl<'mir, 'tcx> GlobalState { // From next_base_addr + slack, round up to adjust for alignment. let base_addr = Self::align_addr(global_state.next_base_addr + slack, align.bytes()); entry.insert(base_addr); + trace!( + "Assigning base address {:#x} to allocation {:?} (slack: {}, align: {})", + base_addr, ptr.alloc_id, slack, align.bytes(), + ); // Remember next base address. If this allocation is zero-sized, leave a gap // of at least 1 to avoid two allocations having the same base address. From 709b4748599881184f4f03137d1b81ea160d5dd1 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 30 Jun 2019 21:08:17 +0200 Subject: [PATCH 0875/3747] fix minimal alignment for system allocation functions --- src/shims/foreign_items.rs | 16 ++++++++-- tests/run-pass/heap_allocator.rs | 50 ++++++++++++++++++++------------ 2 files changed, 45 insertions(+), 21 deletions(-) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 9c9e77abfed37..2e2a9062fba85 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -51,6 +51,18 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(Some(this.load_mir(instance.def)?)) } + /// Returns the minimum alignment for the target architecture. + fn min_align(&self) -> Align { + let this = self.eval_context_ref(); + // List taken from `libstd/sys_common/alloc.rs`. + let min_align = match this.tcx.tcx.sess.target.target.arch.as_str() { + "x86" | "arm" | "mips" | "powerpc" | "powerpc64" | "asmjs" | "wasm32" => 8, + "x86_64" | "aarch64" | "mips64" | "s390x" | "sparc64" => 16, + arch => bug!("Unsupported target architecture: {}", arch), + }; + Align::from_bytes(min_align).unwrap() + } + fn malloc( &mut self, size: u64, @@ -61,7 +73,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if size == 0 { Scalar::from_int(0, this.pointer_size()) } else { - let align = this.tcx.data_layout.pointer_align.abi; + let align = this.min_align(); let ptr = this.memory_mut().allocate(Size::from_bytes(size), align, MiriMemoryKind::C.into()); if zero_init { // We just allocated this, the access cannot fail @@ -94,7 +106,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx new_size: u64, ) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); - let align = this.tcx.data_layout.pointer_align.abi; + let align = this.min_align(); if old_ptr.is_null_ptr(this) { if new_size == 0 { Ok(Scalar::from_int(0, this.pointer_size())) diff --git a/tests/run-pass/heap_allocator.rs b/tests/run-pass/heap_allocator.rs index 57db5407b7af5..1ea04ec467f1c 100644 --- a/tests/run-pass/heap_allocator.rs +++ b/tests/run-pass/heap_allocator.rs @@ -6,35 +6,47 @@ use std::alloc::{Global, Alloc, Layout, System}; use std::slice; fn check_alloc(mut allocator: T) { unsafe { - let layout = Layout::from_size_align(20, 4).unwrap(); - let a = allocator.alloc(layout).unwrap(); - allocator.dealloc(a, layout); + for &align in &[4, 8, 16, 32] { + let layout = Layout::from_size_align(20, align).unwrap(); - let p1 = allocator.alloc_zeroed(layout).unwrap(); + for _ in 0..32 { + let a = allocator.alloc(layout).unwrap(); + assert_eq!(a.as_ptr() as usize % align, 0, "pointer is incorrectly aligned"); + allocator.dealloc(a, layout); + } + + let p1 = allocator.alloc_zeroed(layout).unwrap(); + assert_eq!(p1.as_ptr() as usize % align, 0, "pointer is incorrectly aligned"); - let p2 = allocator.realloc(p1, Layout::from_size_align(20, 4).unwrap(), 40).unwrap(); - let slice = slice::from_raw_parts(p2.as_ptr(), 20); - assert_eq!(&slice, &[0_u8; 20]); + let p2 = allocator.realloc(p1, layout, 40).unwrap(); + let layout = Layout::from_size_align(40, align).unwrap(); + assert_eq!(p2.as_ptr() as usize % align, 0, "pointer is incorrectly aligned"); + let slice = slice::from_raw_parts(p2.as_ptr(), 20); + assert_eq!(&slice, &[0_u8; 20]); - // old size == new size - let p3 = allocator.realloc(p2, Layout::from_size_align(40, 4).unwrap(), 40).unwrap(); - let slice = slice::from_raw_parts(p3.as_ptr(), 20); - assert_eq!(&slice, &[0_u8; 20]); + // old size == new size + let p3 = allocator.realloc(p2, layout, 40).unwrap(); + assert_eq!(p3.as_ptr() as usize % align, 0, "pointer is incorrectly aligned"); + let slice = slice::from_raw_parts(p3.as_ptr(), 20); + assert_eq!(&slice, &[0_u8; 20]); - // old size > new size - let p4 = allocator.realloc(p3, Layout::from_size_align(40, 4).unwrap(), 10).unwrap(); - let slice = slice::from_raw_parts(p4.as_ptr(), 10); - assert_eq!(&slice, &[0_u8; 10]); + // old size > new size + let p4 = allocator.realloc(p3, layout, 10).unwrap(); + let layout = Layout::from_size_align(10, align).unwrap(); + assert_eq!(p4.as_ptr() as usize % align, 0, "pointer is incorrectly aligned"); + let slice = slice::from_raw_parts(p4.as_ptr(), 10); + assert_eq!(&slice, &[0_u8; 10]); - allocator.dealloc(p4, Layout::from_size_align(10, 4).unwrap()); + allocator.dealloc(p4, layout); + } } } fn check_overalign_requests(mut allocator: T) { let size = 8; - // Greater than `size`. - let align = 16; + // Greater than `size`, and also greater than `MIN_ALIGN`. + let align = 32; - let iterations = 5; + let iterations = 32; unsafe { let pointers: Vec<_> = (0..iterations).map(|_| { allocator.alloc(Layout::from_size_align(size, align).unwrap()).unwrap() From cb6d4f0c9ab95125af236abea72661efd094f699 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 30 Jun 2019 21:23:48 +0200 Subject: [PATCH 0876/3747] test even more size-alignment combinations. found a bug in libstd! --- README.md | 1 + src/shims/foreign_items.rs | 4 ++++ tests/run-pass/heap_allocator.rs | 32 ++++++++++++++++---------------- 3 files changed, 21 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index 91dcfd7cf83b3..be104ed0b2ba3 100644 --- a/README.md +++ b/README.md @@ -333,6 +333,7 @@ Definite bugs found: * [Futures turning a shared reference into a mutable one](https://github.com/rust-lang/rust/pull/56319) * [`str` turning a shared reference into a mutable one](https://github.com/rust-lang/rust/pull/58200) * [`rand` performing unaligned reads](https://github.com/rust-random/rand/issues/779) +* [The Unix allocator calling `posix_memalign` in an invalid way](https://github.com/rust-lang/rust/issues/62251) Violations of Stacked Borrows found that are likely bugs (but Stacked Borrows is currently just an experiment): diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 2e2a9062fba85..1a39df9cce15f 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -203,12 +203,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if !align.is_power_of_two() { return err!(HeapAllocNonPowerOfTwoAlignment(align)); } + /* + FIXME: This check is disabled because rustc violates it. + See . if align < this.pointer_size().bytes() { return err!(MachineError(format!( "posix_memalign: alignment must be at least the size of a pointer, but is {}", align, ))); } + */ if size == 0 { this.write_null(ret.into())?; } else { diff --git a/tests/run-pass/heap_allocator.rs b/tests/run-pass/heap_allocator.rs index 1ea04ec467f1c..2f3a48f535ddd 100644 --- a/tests/run-pass/heap_allocator.rs +++ b/tests/run-pass/heap_allocator.rs @@ -42,23 +42,23 @@ fn check_alloc(mut allocator: T) { unsafe { } } fn check_overalign_requests(mut allocator: T) { - let size = 8; - // Greater than `size`, and also greater than `MIN_ALIGN`. - let align = 32; + for &size in &[2, 8, 64] { // size less than and bigger than alignment + for &align in &[4, 8, 16, 32] { // Be sure to cover less than and bigger than `MIN_ALIGN` for all architectures + let iterations = 32; + unsafe { + let pointers: Vec<_> = (0..iterations).map(|_| { + allocator.alloc(Layout::from_size_align(size, align).unwrap()).unwrap() + }).collect(); + for &ptr in &pointers { + assert_eq!((ptr.as_ptr() as usize) % align, 0, + "Got a pointer less aligned than requested") + } - let iterations = 32; - unsafe { - let pointers: Vec<_> = (0..iterations).map(|_| { - allocator.alloc(Layout::from_size_align(size, align).unwrap()).unwrap() - }).collect(); - for &ptr in &pointers { - assert_eq!((ptr.as_ptr() as usize) % align, 0, - "Got a pointer less aligned than requested") - } - - // Clean up. - for &ptr in &pointers { - allocator.dealloc(ptr, Layout::from_size_align(size, align).unwrap()) + // Clean up. + for &ptr in &pointers { + allocator.dealloc(ptr, Layout::from_size_align(size, align).unwrap()) + } + } } } } From 4135441137ca02168522c24c0f5a3fbbf3af8741 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 1 Jul 2019 00:12:45 +0200 Subject: [PATCH 0877/3747] don't call Memory::get without checking the pointer first; avoid Memory::get if we just need to know align/size --- src/operator.rs | 10 +++++++--- src/shims/foreign_items.rs | 32 ++++++++++++++++++++------------ 2 files changed, 27 insertions(+), 15 deletions(-) diff --git a/src/operator.rs b/src/operator.rs index 0e25de7da5a95..d3af1f0db0e02 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -206,7 +206,7 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { // on read hardware this can easily happen. Thus for comparisons we require // both pointers to be live. if self.pointer_inbounds(left).is_ok() && self.pointer_inbounds(right).is_ok() { - // Two in-bounds pointers in different allocations are different. + // Two in-bounds (and hence live) pointers in different allocations are different. false } else { return err!(InvalidPointerMath); @@ -303,7 +303,9 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { map_to_primval(left.overflowing_offset(Size::from_bytes(right as u64), self)), BitAnd if !signed => { - let ptr_base_align = self.memory().get(left.alloc_id)?.align.bytes(); + let ptr_base_align = self.memory().get_size_and_align(left.alloc_id, AllocCheck::MaybeDead) + .expect("alloc info with MaybeDead cannot fail") + .1.bytes(); let base_mask = { // FIXME: use `interpret::truncate`, once that takes a `Size` instead of a `Layout`. let shift = 128 - self.memory().pointer_size().bits(); @@ -337,7 +339,9 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { Rem if !signed => { // Doing modulo a divisor of the alignment is allowed. // (Intuition: modulo a divisor leaks less information.) - let ptr_base_align = self.memory().get(left.alloc_id)?.align.bytes(); + let ptr_base_align = self.memory().get_size_and_align(left.alloc_id, AllocCheck::MaybeDead) + .expect("alloc info with MaybeDead cannot fail") + .1.bytes(); let right = right as u64; let ptr_size = self.memory().pointer_size(); if right == 1 { diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 9c9e77abfed37..0fa857eff7574 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -252,9 +252,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Align::from_bytes(align).unwrap(), MiriMemoryKind::Rust.into() ); + // We just allocated this, the access cannot fail this.memory_mut() - .get_mut(ptr.alloc_id)? - .write_repeat(tcx, ptr, 0, Size::from_bytes(size))?; + .get_mut(ptr.alloc_id).unwrap() + .write_repeat(tcx, ptr, 0, Size::from_bytes(size)).unwrap(); this.write_scalar(Scalar::Ptr(ptr), dest)?; } "__rust_dealloc" => { @@ -494,15 +495,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Align::from_bytes(1).unwrap(), MiriMemoryKind::Env.into(), ); - { - let alloc = this.memory_mut().get_mut(value_copy.alloc_id)?; - alloc.write_bytes(tcx, value_copy, &value)?; - let trailing_zero_ptr = value_copy.offset( - Size::from_bytes(value.len() as u64), - tcx, - )?; - alloc.write_bytes(tcx, trailing_zero_ptr, &[0])?; - } + // We just allocated these, so the write cannot fail. + let alloc = this.memory_mut().get_mut(value_copy.alloc_id).unwrap(); + alloc.write_bytes(tcx, value_copy, &value).unwrap(); + let trailing_zero_ptr = value_copy.offset( + Size::from_bytes(value.len() as u64), + tcx, + ).unwrap(); + alloc.write_bytes(tcx, trailing_zero_ptr, &[0]).unwrap(); + if let Some(var) = this.machine.env_vars.insert( name.to_owned(), value_copy, @@ -839,7 +840,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx }, "GetSystemInfo" => { let system_info = this.deref_operand(args[0])?; - let system_info_ptr = system_info.ptr.to_ptr()?; + let (system_info_ptr, align) = system_info.to_scalar_ptr_align(); + let system_info_ptr = this.memory() + .check_ptr_access( + system_info_ptr, + system_info.layout.size, + align, + )? + .expect("cannot be a ZST"); // Initialize with `0`. this.memory_mut().get_mut(system_info_ptr.alloc_id)? .write_repeat(tcx, system_info_ptr, 0, system_info.layout.size)?; From 7b702b92588316adda4992e0ef247176b91a2f07 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 30 Jun 2019 23:24:08 +0200 Subject: [PATCH 0878/3747] move find_fn (which is not specific to foreign items) out of foreign_items --- src/lib.rs | 1 + src/shims/foreign_items.rs | 41 --------------------------------- src/shims/mod.rs | 47 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 48 insertions(+), 41 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 6b2de4ac08be4..50cf32f852044 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -28,6 +28,7 @@ pub use rustc_mir::interpret::*; // Resolve ambiguity. pub use rustc_mir::interpret::{self, AllocMap, PlaceTy}; +pub use crate::shims::{EvalContextExt as ShimsEvalContextExt}; pub use crate::shims::foreign_items::EvalContextExt as ForeignItemsEvalContextExt; pub use crate::shims::intrinsics::EvalContextExt as IntrinsicsEvalContextExt; pub use crate::operator::EvalContextExt as OperatorEvalContextExt; diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 1a39df9cce15f..aece4d3e1aef1 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -1,4 +1,3 @@ -use rustc::ty; use rustc::ty::layout::{Align, LayoutOf, Size}; use rustc::hir::def_id::DefId; use rustc::mir; @@ -11,46 +10,6 @@ use crate::*; impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { - fn find_fn( - &mut self, - instance: ty::Instance<'tcx>, - args: &[OpTy<'tcx, Tag>], - dest: Option>, - ret: Option, - ) -> InterpResult<'tcx, Option<&'mir mir::Body<'tcx>>> { - let this = self.eval_context_mut(); - trace!("eval_fn_call: {:#?}, {:?}", instance, dest.map(|place| *place)); - - // First, run the common hooks also supported by CTFE. - if this.hook_fn(instance, args, dest)? { - this.goto_block(ret)?; - return Ok(None); - } - // There are some more lang items we want to hook that CTFE does not hook (yet). - if this.tcx.lang_items().align_offset_fn() == Some(instance.def.def_id()) { - // FIXME: return a real value in case the target allocation has an - // alignment bigger than the one requested. - let n = u128::max_value(); - let dest = dest.unwrap(); - let n = this.truncate(n, dest.layout); - this.write_scalar(Scalar::from_uint(n, dest.layout.size), dest)?; - this.goto_block(ret)?; - return Ok(None); - } - - // Try to see if we can do something about foreign items. - if this.tcx.is_foreign_item(instance.def_id()) { - // An external function that we cannot find MIR for, but we can still run enough - // of them to make miri viable. - this.emulate_foreign_item(instance.def_id(), args, dest, ret)?; - // `goto_block` already handled. - return Ok(None); - } - - // Otherwise, load the MIR. - Ok(Some(this.load_mir(instance.def)?)) - } - /// Returns the minimum alignment for the target architecture. fn min_align(&self) -> Align { let this = self.eval_context_ref(); diff --git a/src/shims/mod.rs b/src/shims/mod.rs index cadfc05681dad..0fc23e8119375 100644 --- a/src/shims/mod.rs +++ b/src/shims/mod.rs @@ -1,2 +1,49 @@ pub mod foreign_items; pub mod intrinsics; + +use rustc::{ty, mir}; + +use crate::*; + +impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} +pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { + fn find_fn( + &mut self, + instance: ty::Instance<'tcx>, + args: &[OpTy<'tcx, Tag>], + dest: Option>, + ret: Option, + ) -> InterpResult<'tcx, Option<&'mir mir::Body<'tcx>>> { + let this = self.eval_context_mut(); + trace!("eval_fn_call: {:#?}, {:?}", instance, dest.map(|place| *place)); + + // First, run the common hooks also supported by CTFE. + if this.hook_fn(instance, args, dest)? { + this.goto_block(ret)?; + return Ok(None); + } + // There are some more lang items we want to hook that CTFE does not hook (yet). + if this.tcx.lang_items().align_offset_fn() == Some(instance.def.def_id()) { + // FIXME: return a real value in case the target allocation has an + // alignment bigger than the one requested. + let n = u128::max_value(); + let dest = dest.unwrap(); + let n = this.truncate(n, dest.layout); + this.write_scalar(Scalar::from_uint(n, dest.layout.size), dest)?; + this.goto_block(ret)?; + return Ok(None); + } + + // Try to see if we can do something about foreign items. + if this.tcx.is_foreign_item(instance.def_id()) { + // An external function that we cannot find MIR for, but we can still run enough + // of them to make miri viable. + this.emulate_foreign_item(instance.def_id(), args, dest, ret)?; + // `goto_block` already handled. + return Ok(None); + } + + // Otherwise, load the MIR. + Ok(Some(this.load_mir(instance.def)?)) + } +} From b04452223a8b4256e32306eab2f1bcb578c09c16 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 1 Jul 2019 11:05:57 +0200 Subject: [PATCH 0879/3747] be explicit about our line endings --- .gitattributes | 1 + 1 file changed, 1 insertion(+) create mode 100644 .gitattributes diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000000000..6313b56c57848 --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +* text=auto eol=lf From e8e42ab5ecead88c23dec9eab9a23019e45410fd Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 2 Jul 2019 09:51:16 +0200 Subject: [PATCH 0880/3747] add another bug we found to the list --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index be104ed0b2ba3..8c0c87ab9ebb1 100644 --- a/README.md +++ b/README.md @@ -327,6 +327,7 @@ Miri has already found a number of bugs in the Rust standard library and beyond, Definite bugs found: * [`Debug for vec_deque::Iter` accessing uninitialized memory](https://github.com/rust-lang/rust/issues/53566) +* [`Vec::into_iter` doing an unaligned ZST read](https://github.com/rust-lang/rust/pull/53804) * [`From<&[T]> for Rc` creating a not sufficiently aligned reference](https://github.com/rust-lang/rust/issues/54908) * [`BTreeMap` creating a shared reference pointing to a too small allocation](https://github.com/rust-lang/rust/issues/54957) * [`Vec::append` creating a dangling reference](https://github.com/rust-lang/rust/pull/61082) From 8d8481fed5c0417e01bfa4726e16e0181213e93f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 2 Jul 2019 13:02:48 +0200 Subject: [PATCH 0881/3747] fix outdated test name: overalign -> align --- tests/run-pass/heap_allocator.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/run-pass/heap_allocator.rs b/tests/run-pass/heap_allocator.rs index 2f3a48f535ddd..e7a609a7d98e9 100644 --- a/tests/run-pass/heap_allocator.rs +++ b/tests/run-pass/heap_allocator.rs @@ -41,7 +41,7 @@ fn check_alloc(mut allocator: T) { unsafe { } } } -fn check_overalign_requests(mut allocator: T) { +fn check_align_requests(mut allocator: T) { for &size in &[2, 8, 64] { // size less than and bigger than alignment for &align in &[4, 8, 16, 32] { // Be sure to cover less than and bigger than `MIN_ALIGN` for all architectures let iterations = 32; @@ -88,8 +88,8 @@ fn box_to_global() { fn main() { check_alloc(System); check_alloc(Global); - check_overalign_requests(System); - check_overalign_requests(Global); + check_align_requests(System); + check_align_requests(Global); global_to_box(); box_to_global(); } From ccbc035f6a57dd6315114e4de3ee89513c355bb2 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 2 Jul 2019 22:20:37 +0200 Subject: [PATCH 0882/3747] run all run-pass tests with intrptrcast. makes many of them fail! --- tests/compiletest.rs | 3 +++ tests/run-pass/intptrcast_format.rs | 6 ------ tests/run-pass/intptrcast_format.stdout | 2 -- 3 files changed, 3 insertions(+), 8 deletions(-) delete mode 100644 tests/run-pass/intptrcast_format.rs delete mode 100644 tests/run-pass/intptrcast_format.stdout diff --git a/tests/compiletest.rs b/tests/compiletest.rs index d59be08c8e003..cb61c1c01b327 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -81,6 +81,9 @@ fn miri_pass(path: &str, target: &str, opt: bool) { let mut flags = Vec::new(); if opt { flags.push("-Zmir-opt-level=3".to_owned()); + } else { + // Run with intptrcast. Avoid test matrix explosion by doing either this or opt-level=3. + flags.push("-Zmiri-seed=".to_owned()); } run_tests("ui", path, target, flags); diff --git a/tests/run-pass/intptrcast_format.rs b/tests/run-pass/intptrcast_format.rs deleted file mode 100644 index c0d3e9398dc5d..0000000000000 --- a/tests/run-pass/intptrcast_format.rs +++ /dev/null @@ -1,6 +0,0 @@ -// compile-flags: -Zmiri-seed= - -fn main() { - println!("Hello {}", 13); - println!("{:0 Date: Wed, 3 Jul 2019 09:06:35 +0200 Subject: [PATCH 0883/3747] dont add the -Zmiri-seed flag twice --- tests/compiletest.rs | 7 ++++--- tests/{run-pass => run-pass-noseed}/hashmap.rs | 0 tests/{run-pass => run-pass-noseed}/heap_allocator.rs | 0 tests/{run-pass => run-pass-noseed}/intptrcast.rs | 0 4 files changed, 4 insertions(+), 3 deletions(-) rename tests/{run-pass => run-pass-noseed}/hashmap.rs (100%) rename tests/{run-pass => run-pass-noseed}/heap_allocator.rs (100%) rename tests/{run-pass => run-pass-noseed}/intptrcast.rs (100%) diff --git a/tests/compiletest.rs b/tests/compiletest.rs index cb61c1c01b327..1d32d3a732440 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -69,7 +69,7 @@ fn compile_fail(path: &str, target: &str, opt: bool) { run_tests("compile-fail", path, target, flags); } -fn miri_pass(path: &str, target: &str, opt: bool) { +fn miri_pass(path: &str, target: &str, opt: bool, noseed: bool) { let opt_str = if opt { " with optimizations" } else { "" }; eprintln!("{}", format!( "## Running run-pass tests in {} against miri for target {}{}", @@ -81,7 +81,7 @@ fn miri_pass(path: &str, target: &str, opt: bool) { let mut flags = Vec::new(); if opt { flags.push("-Zmir-opt-level=3".to_owned()); - } else { + } else if !noseed { // Run with intptrcast. Avoid test matrix explosion by doing either this or opt-level=3. flags.push("-Zmiri-seed=".to_owned()); } @@ -107,7 +107,8 @@ fn get_target() -> String { } fn run_pass_miri(opt: bool) { - miri_pass("tests/run-pass", &get_target(), opt); + miri_pass("tests/run-pass", &get_target(), opt, false); + miri_pass("tests/run-pass-noseed", &get_target(), opt, true); } fn compile_fail_miri(opt: bool) { diff --git a/tests/run-pass/hashmap.rs b/tests/run-pass-noseed/hashmap.rs similarity index 100% rename from tests/run-pass/hashmap.rs rename to tests/run-pass-noseed/hashmap.rs diff --git a/tests/run-pass/heap_allocator.rs b/tests/run-pass-noseed/heap_allocator.rs similarity index 100% rename from tests/run-pass/heap_allocator.rs rename to tests/run-pass-noseed/heap_allocator.rs diff --git a/tests/run-pass/intptrcast.rs b/tests/run-pass-noseed/intptrcast.rs similarity index 100% rename from tests/run-pass/intptrcast.rs rename to tests/run-pass-noseed/intptrcast.rs From 457c8237652e123010555b5ecc795a5a4fd6111f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 3 Jul 2019 09:06:48 +0200 Subject: [PATCH 0884/3747] only treat integer operations as such --- src/operator.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/operator.rs b/src/operator.rs index d3af1f0db0e02..31def2fec0e03 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -56,10 +56,10 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { trace!("ptr_op: {:?} {:?} {:?}", *left, bin_op, *right); - // If intptrcast is enabled and the operation is not an offset - // we can force the cast from pointers to integer addresses and - // then dispatch to rustc binary operation method - if self.memory().extra.rng.is_some() && bin_op != Offset { + // If intptrcast is enabled, treat everything of integer *type* at integer *value*. + if self.memory().extra.rng.is_some() && left.layout.ty.is_integral() { + // This is actually an integer operation, so dispatch back to the core engine. + assert!(right.layout.ty.is_integral()); let l_bits = self.force_bits(left.imm.to_scalar()?, left.layout.size)?; let r_bits = self.force_bits(right.imm.to_scalar()?, right.layout.size)?; From c6e4f760a21f0d25215a9b5b6b01798e5d08c5ca Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 3 Jul 2019 09:23:31 +0200 Subject: [PATCH 0885/3747] allow dangling ptr-to-int casts; use force_bits for ptr comparison --- src/intptrcast.rs | 4 +++- src/operator.rs | 9 +++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/intptrcast.rs b/src/intptrcast.rs index 5480700005075..805cc2ad2a503 100644 --- a/src/intptrcast.rs +++ b/src/intptrcast.rs @@ -75,7 +75,9 @@ impl<'mir, 'tcx> GlobalState { let mut global_state = memory.extra.intptrcast.borrow_mut(); let global_state = &mut *global_state; - let (size, align) = memory.get_size_and_align(ptr.alloc_id, AllocCheck::Live)?; + // There is nothing wrong with a raw pointer being cast to an integer only after + // it became dangling. Hence `MaybeDead`. + let (size, align) = memory.get_size_and_align(ptr.alloc_id, AllocCheck::MaybeDead)?; let base_addr = match global_state.base_addr.entry(ptr.alloc_id) { Entry::Occupied(entry) => *entry.get(), diff --git a/src/operator.rs b/src/operator.rs index 31def2fec0e03..2194484316833 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -59,6 +59,8 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { // If intptrcast is enabled, treat everything of integer *type* at integer *value*. if self.memory().extra.rng.is_some() && left.layout.ty.is_integral() { // This is actually an integer operation, so dispatch back to the core engine. + // TODO: Once intptrcast is the default, librustc_mir should never even call us + // for integer types. assert!(right.layout.ty.is_integral()); let l_bits = self.force_bits(left.imm.to_scalar()?, left.layout.size)?; let r_bits = self.force_bits(right.imm.to_scalar()?, right.layout.size)?; @@ -186,6 +188,13 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { right: Scalar, ) -> InterpResult<'tcx, bool> { let size = self.pointer_size(); + if self.memory().extra.rng.is_some() { + // Just compare the integers. + // TODO: Do we really want to *always* do that, even when comparing two live in-bounds pointers? + let left = self.force_bits(left, size)?; + let right = self.force_bits(right, size)?; + return Ok(left == right); + } Ok(match (left, right) { (Scalar::Raw { .. }, Scalar::Raw { .. }) => left.to_bits(size)? == right.to_bits(size)?, From 12b8d4366cc48ed93441f4b039bc18e30b0f0baa Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 3 Jul 2019 09:32:21 +0200 Subject: [PATCH 0886/3747] avoid integer overflow in ptr-to-int cast --- src/intptrcast.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/intptrcast.rs b/src/intptrcast.rs index 805cc2ad2a503..5797895c54f80 100644 --- a/src/intptrcast.rs +++ b/src/intptrcast.rs @@ -4,7 +4,8 @@ use std::cmp::max; use rand::Rng; -use rustc_mir::interpret::{AllocId, Pointer, InterpResult, Memory, AllocCheck}; +use rustc::ty::layout::HasDataLayout; +use rustc_mir::interpret::{AllocId, Pointer, InterpResult, Memory, AllocCheck, PointerArithmetic}; use rustc_target::abi::Size; use crate::{Evaluator, Tag, STACK_ADDR}; @@ -109,7 +110,9 @@ impl<'mir, 'tcx> GlobalState { }; debug_assert_eq!(base_addr % align.bytes(), 0); // sanity check - Ok(base_addr + ptr.offset.bytes()) + // Add offset with the right kind of pointer-overflowing arithmetic. + let dl = memory.data_layout(); + Ok(dl.overflowing_offset(base_addr, ptr.offset.bytes()).0) } /// Shifts `addr` to make it aligned with `align` by rounding `addr` to the smallest multiple From c3da843ca02dab7b5f6563ffeb0d654bbe70e1f8 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 3 Jul 2019 09:42:07 +0200 Subject: [PATCH 0887/3747] we don't need zero-sized freeze-sensitive visiting --- src/helpers.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/helpers.rs b/src/helpers.rs index f65eef557c967..16451fb8726a6 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -58,6 +58,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx .map(|(size, _)| size) .unwrap_or_else(|| place.layout.size) ); + assert!(size.bytes() > 0); // Store how far we proceeded into the place so far. Everything to the left of // this offset has already been handled, in the sense that the frozen parts // have had `action` called on them. From c8450bda4fc3ed70aa019f83c58ff8ee8f9fcb09 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 3 Jul 2019 09:56:35 +0200 Subject: [PATCH 0888/3747] support integers that can be cast to pointers in in-bounds offset operation --- src/operator.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/operator.rs b/src/operator.rs index 2194484316833..2e9b8238479f3 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -397,7 +397,7 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { .checked_mul(pointee_size) .ok_or_else(|| InterpError::Overflow(mir::BinOp::Mul))?; // Now let's see what kind of pointer this is. - if let Scalar::Ptr(ptr) = ptr { + if let Ok(ptr) = self.force_ptr(ptr) { // Both old and new pointer must be in-bounds of a *live* allocation. // (Of the same allocation, but that part is trivial with our representation.) self.pointer_inbounds(ptr)?; @@ -405,7 +405,7 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { self.pointer_inbounds(ptr)?; Ok(Scalar::Ptr(ptr)) } else { - // An integer pointer. They can only be offset by 0, and we pretend there + // A "true" integer pointer. They can only be offset by 0, and we pretend there // is a little zero-sized allocation here. if offset == 0 { Ok(ptr) From eb4128fb4203f926370fdf17d6961940986728cd Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 3 Jul 2019 10:19:55 +0200 Subject: [PATCH 0889/3747] don't call Stacked Borrows hooks at all when validation is disabled --- README.md | 2 + src/eval.rs | 4 +- src/machine.rs | 78 ++++++++++++++++++++++----------- src/stacked_borrows.rs | 5 ++- tests/run-pass/transmute_fat.rs | 3 ++ 5 files changed, 62 insertions(+), 30 deletions(-) diff --git a/README.md b/README.md index 8c0c87ab9ebb1..69c66db52147e 100644 --- a/README.md +++ b/README.md @@ -279,6 +279,8 @@ Several `-Z` flags are relevant for Miri: * `-Zalways-encode-mir` makes rustc dump MIR even for completely monomorphic functions. This is needed so that Miri can execute such functions, so Miri sets this flag per default. +* `-Zmir-emit-retag` controls whether `Retag` statements are emitted. Miri + enables this per default because it is needed for validation. Moreover, Miri recognizes some environment variables: diff --git a/src/eval.rs b/src/eval.rs index ec97a77357cf8..a1157af0e39b6 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -32,11 +32,11 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( let mut ecx = InterpretCx::new( tcx.at(syntax::source_map::DUMMY_SP), ty::ParamEnv::reveal_all(), - Evaluator::new(config.validate), + Evaluator::new(), ); // FIXME: InterpretCx::new should take an initial MemoryExtra - ecx.memory_mut().extra = MemoryExtra::with_rng(config.seed.map(StdRng::seed_from_u64)); + ecx.memory_mut().extra = MemoryExtra::new(config.seed.map(StdRng::seed_from_u64), config.validate); let main_instance = ty::Instance::mono(ecx.tcx.tcx, main_id); let main_mir = ecx.load_mir(main_instance.def)?; diff --git a/src/machine.rs b/src/machine.rs index 20fe2e055fb53..0ddb2d40b8e85 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -41,7 +41,8 @@ impl Into> for MiriMemoryKind { /// Extra per-allocation data #[derive(Debug, Clone)] pub struct AllocExtra { - pub stacked_borrows: stacked_borrows::AllocExtra, + /// Stacked Borrows state is only added if validation is enabled. + pub stacked_borrows: Option, } /// Extra global memory data @@ -49,17 +50,22 @@ pub struct AllocExtra { pub struct MemoryExtra { pub stacked_borrows: stacked_borrows::MemoryExtra, pub intptrcast: intptrcast::MemoryExtra, + /// The random number generator to use if Miri is running in non-deterministic mode and to /// enable intptrcast - pub(crate) rng: Option> + pub(crate) rng: Option>, + + /// Whether to enforce the validity invariant. + pub(crate) validate: bool, } impl MemoryExtra { - pub fn with_rng(rng: Option) -> Self { + pub fn new(rng: Option, validate: bool) -> Self { MemoryExtra { stacked_borrows: Default::default(), intptrcast: Default::default(), rng: rng.map(RefCell::new), + validate, } } } @@ -82,13 +88,10 @@ pub struct Evaluator<'tcx> { /// TLS state. pub(crate) tls: TlsData<'tcx>, - - /// Whether to enforce the validity invariant. - pub(crate) validate: bool, } impl<'tcx> Evaluator<'tcx> { - pub(crate) fn new(validate: bool) -> Self { + pub(crate) fn new() -> Self { Evaluator { env_vars: HashMap::default(), argc: None, @@ -96,7 +99,6 @@ impl<'tcx> Evaluator<'tcx> { cmd_line: None, last_error: 0, tls: TlsData::default(), - validate, } } } @@ -135,7 +137,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { #[inline(always)] fn enforce_validity(ecx: &InterpretCx<'mir, 'tcx, Self>) -> bool { - ecx.machine.validate + ecx.memory().extra.validate } /// Returns `Ok()` when the function was handled; fail otherwise. @@ -251,12 +253,17 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { ) -> (Cow<'b, Allocation>, Self::PointerTag) { let kind = kind.expect("we set our STATIC_KIND so this cannot be None"); let alloc = alloc.into_owned(); - let (stacks, base_tag) = Stacks::new_allocation( - id, - Size::from_bytes(alloc.bytes.len() as u64), - Rc::clone(&memory.extra.stacked_borrows), - kind, - ); + let (stacks, base_tag) = if !memory.extra.validate { + (None, Tag::Untagged) + } else { + let (stacks, base_tag) = Stacks::new_allocation( + id, + Size::from_bytes(alloc.bytes.len() as u64), + Rc::clone(&memory.extra.stacked_borrows), + kind, + ); + (Some(stacks), base_tag) + }; if kind != MiriMemoryKind::Static.into() { assert!(alloc.relocations.is_empty(), "Only statics can come initialized with inner pointers"); // Now we can rely on the inner pointers being static, too. @@ -268,7 +275,14 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { alloc.relocations.iter() // The allocations in the relocations (pointers stored *inside* this allocation) // all get the base pointer tag. - .map(|&(offset, ((), alloc))| (offset, (memory_extra.static_base_ptr(alloc), alloc))) + .map(|&(offset, ((), alloc))| { + let tag = if !memory.extra.validate { + Tag::Untagged + } else { + memory_extra.static_base_ptr(alloc) + }; + (offset, (tag, alloc)) + }) .collect() ), undef_mask: alloc.undef_mask, @@ -286,7 +300,11 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { id: AllocId, memory: &Memory<'mir, 'tcx, Self>, ) -> Self::PointerTag { - memory.extra.stacked_borrows.borrow_mut().static_base_ptr(id) + if !memory.extra.validate { + Tag::Untagged + } else { + memory.extra.stacked_borrows.borrow_mut().static_base_ptr(id) + } } #[inline(always)] @@ -295,12 +313,8 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { kind: mir::RetagKind, place: PlaceTy<'tcx, Tag>, ) -> InterpResult<'tcx> { - if !ecx.tcx.sess.opts.debugging_opts.mir_emit_retag || !Self::enforce_validity(ecx) { - // No tracking, or no retagging. The latter is possible because a dependency of ours - // might be called with different flags than we are, so there are `Retag` - // statements but we do not want to execute them. - // Also, honor the whitelist in `enforce_validity` because otherwise we might retag - // uninitialized data. + if !Self::enforce_validity(ecx) { + // No tracking. Ok(()) } else { ecx.retag(kind, place) @@ -354,7 +368,11 @@ impl AllocationExtra for AllocExtra { ptr: Pointer, size: Size, ) -> InterpResult<'tcx> { - alloc.extra.stacked_borrows.memory_read(ptr, size) + if let Some(ref stacked_borrows) = alloc.extra.stacked_borrows { + stacked_borrows.memory_read(ptr, size) + } else { + Ok(()) + } } #[inline(always)] @@ -363,7 +381,11 @@ impl AllocationExtra for AllocExtra { ptr: Pointer, size: Size, ) -> InterpResult<'tcx> { - alloc.extra.stacked_borrows.memory_written(ptr, size) + if let Some(ref mut stacked_borrows) = alloc.extra.stacked_borrows { + stacked_borrows.memory_written(ptr, size) + } else { + Ok(()) + } } #[inline(always)] @@ -372,7 +394,11 @@ impl AllocationExtra for AllocExtra { ptr: Pointer, size: Size, ) -> InterpResult<'tcx> { - alloc.extra.stacked_borrows.memory_deallocated(ptr, size) + if let Some(ref mut stacked_borrows) = alloc.extra.stacked_borrows { + stacked_borrows.memory_deallocated(ptr, size) + } else { + Ok(()) + } } } diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 524ad2b47af0e..5c59066c475d2 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -538,6 +538,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Get the allocation. It might not be mutable, so we cannot use `get_mut`. let alloc = this.memory().get(ptr.alloc_id)?; + let stacked_borrows = alloc.extra.stacked_borrows.as_ref().expect("we should have Stacked Borrows data"); // Update the stacks. // Make sure that raw pointers and mutable shared references are reborrowed "weak": // There could be existing unique pointers reborrowed from them that should remain valid! @@ -553,14 +554,14 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // We are only ever `SharedReadOnly` inside the frozen bits. let perm = if frozen { Permission::SharedReadOnly } else { Permission::SharedReadWrite }; let item = Item { perm, tag: new_tag, protector }; - alloc.extra.stacked_borrows.for_each(cur_ptr, size, |stack, global| { + stacked_borrows.for_each(cur_ptr, size, |stack, global| { stack.grant(cur_ptr.tag, item, global) }) }); } }; let item = Item { perm, tag: new_tag, protector }; - alloc.extra.stacked_borrows.for_each(ptr, size, |stack, global| { + stacked_borrows.for_each(ptr, size, |stack, global| { stack.grant(ptr.tag, item, global) }) } diff --git a/tests/run-pass/transmute_fat.rs b/tests/run-pass/transmute_fat.rs index ec887902d0542..27da44935b106 100644 --- a/tests/run-pass/transmute_fat.rs +++ b/tests/run-pass/transmute_fat.rs @@ -1,3 +1,6 @@ +// Validation disallows this becuase the reference is never cast to a raw pointer. +// compile-flags: -Zmiri-disable-validation + fn main() { // If we are careful, we can exploit data layout... let raw = unsafe { From 8ec25066e741fd0e4a87f2eed53a777dbc64b802 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 3 Jul 2019 10:46:51 +0200 Subject: [PATCH 0890/3747] make a test noseed for now that does not work with intptrcast yet --- tests/{run-pass => run-pass-noseed}/ptr_int_casts.rs | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename tests/{run-pass => run-pass-noseed}/ptr_int_casts.rs (100%) diff --git a/tests/run-pass/ptr_int_casts.rs b/tests/run-pass-noseed/ptr_int_casts.rs similarity index 100% rename from tests/run-pass/ptr_int_casts.rs rename to tests/run-pass-noseed/ptr_int_casts.rs From b29cb7d551cece20ec0fe0b378edaeb1318d702d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 3 Jul 2019 10:54:16 +0200 Subject: [PATCH 0891/3747] avoid catching errors --- src/operator.rs | 33 ++++++++++--------- tests/compile-fail/ptr_offset_int_plus_int.rs | 2 +- 2 files changed, 19 insertions(+), 16 deletions(-) diff --git a/src/operator.rs b/src/operator.rs index 2e9b8238479f3..df60acc661ed4 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -397,21 +397,24 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { .checked_mul(pointee_size) .ok_or_else(|| InterpError::Overflow(mir::BinOp::Mul))?; // Now let's see what kind of pointer this is. - if let Ok(ptr) = self.force_ptr(ptr) { - // Both old and new pointer must be in-bounds of a *live* allocation. - // (Of the same allocation, but that part is trivial with our representation.) - self.pointer_inbounds(ptr)?; - let ptr = ptr.signed_offset(offset, self)?; - self.pointer_inbounds(ptr)?; - Ok(Scalar::Ptr(ptr)) - } else { - // A "true" integer pointer. They can only be offset by 0, and we pretend there - // is a little zero-sized allocation here. - if offset == 0 { - Ok(ptr) - } else { - err!(InvalidPointerMath) + let ptr = if offset == 0 { + match ptr { + Scalar::Ptr(ptr) => ptr, + Scalar::Raw { .. } => { + // Offset 0 on an integer. We accept that, pretending there is + // a little zero-sized allocation here. + return Ok(ptr); + } } - } + } else { + // Offset > 0. We *require* a pointer. + self.force_ptr(ptr)? + }; + // Both old and new pointer must be in-bounds of a *live* allocation. + // (Of the same allocation, but that part is trivial with our representation.) + self.pointer_inbounds(ptr)?; + let ptr = ptr.signed_offset(offset, self)?; + self.pointer_inbounds(ptr)?; + Ok(Scalar::Ptr(ptr)) } } diff --git a/tests/compile-fail/ptr_offset_int_plus_int.rs b/tests/compile-fail/ptr_offset_int_plus_int.rs index d027396108144..2d3282a0a97a0 100644 --- a/tests/compile-fail/ptr_offset_int_plus_int.rs +++ b/tests/compile-fail/ptr_offset_int_plus_int.rs @@ -1,4 +1,4 @@ -// error-pattern: invalid arithmetic on pointers +// error-pattern: tried to interpret some bytes as a pointer fn main() { // Can't offset an integer pointer by non-zero offset. From 074e20eb7b3f36846c6c3a182060a5b82da46498 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Sat, 29 Jun 2019 13:17:15 -0500 Subject: [PATCH 0892/3747] Add intptrcast test for explicit casts --- tests/run-pass-noseed/intptrcast.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tests/run-pass-noseed/intptrcast.rs b/tests/run-pass-noseed/intptrcast.rs index 40b21f9a4729e..919083f98d3df 100644 --- a/tests/run-pass-noseed/intptrcast.rs +++ b/tests/run-pass-noseed/intptrcast.rs @@ -1,4 +1,7 @@ // compile-flags: -Zmiri-seed=0000000000000000 +fn transmute_ptr_to_int(x: *const T) -> usize { + unsafe { std::mem::transmute::<*const T, usize>(x) * 1 } +} fn main() { // Some casting-to-int with arithmetic. @@ -11,4 +14,11 @@ fn main() { // Pointer string formatting! We can't check the output as it changes when libstd changes, // but we can make sure Miri does not error. format!("{:?}", &mut 13 as *mut _); + + // Check that intptrcast is triggered for explicit casts and that it is consistent with + // transmuting. + let a: *const i32 = &42; + let b = transmute_ptr_to_int(a) as u8; + let c = a as usize as u8; + assert_eq!(b, c); } From 39d383d9e729965b406009033977cb942dc899b3 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Wed, 3 Jul 2019 13:28:30 -0500 Subject: [PATCH 0893/3747] Update rust-version --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 17338728254ad..9e4ddf2acaaa8 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -7e08576e4276a97b523c25bfd196d419c39c7b87 +088b987307b91612ab164026e1dcdd0129fdb62b From 8dfb278ac5ad47f7fac3d161ebb30d9efb9246a3 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Wed, 3 Jul 2019 13:42:01 -0500 Subject: [PATCH 0894/3747] Fix explicit cast test --- tests/run-pass-noseed/intptrcast.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/tests/run-pass-noseed/intptrcast.rs b/tests/run-pass-noseed/intptrcast.rs index 919083f98d3df..1b5251c91119a 100644 --- a/tests/run-pass-noseed/intptrcast.rs +++ b/tests/run-pass-noseed/intptrcast.rs @@ -1,11 +1,13 @@ // compile-flags: -Zmiri-seed=0000000000000000 -fn transmute_ptr_to_int(x: *const T) -> usize { - unsafe { std::mem::transmute::<*const T, usize>(x) * 1 } + +// This returns a miri pointer at type usize, if the argument is a proper pointer +fn transmute_ptr_to_int(x: *const T) -> usize { + unsafe { std::mem::transmute(x) } } fn main() { // Some casting-to-int with arithmetic. - let x = &42 as *const i32 as usize; + let x = &42 as *const i32 as usize; let y = x * 2; assert_eq!(y, x + x); let z = y as u8 as usize; From 93c62a4912c7350924ec942aed37ff1cc363352f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 3 Jul 2019 23:12:44 +0200 Subject: [PATCH 0895/3747] move tls.rs into shims module --- src/lib.rs | 3 +-- src/shims/mod.rs | 1 + src/{ => shims}/tls.rs | 0 3 files changed, 2 insertions(+), 2 deletions(-) rename src/{ => shims}/tls.rs (100%) diff --git a/src/lib.rs b/src/lib.rs index 50cf32f852044..31e707077769c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -15,7 +15,6 @@ extern crate rustc_target; mod shims; mod operator; mod helpers; -mod tls; mod range_map; mod mono_hash_map; mod stacked_borrows; @@ -31,8 +30,8 @@ pub use rustc_mir::interpret::{self, AllocMap, PlaceTy}; pub use crate::shims::{EvalContextExt as ShimsEvalContextExt}; pub use crate::shims::foreign_items::EvalContextExt as ForeignItemsEvalContextExt; pub use crate::shims::intrinsics::EvalContextExt as IntrinsicsEvalContextExt; +pub use crate::shims::tls::{EvalContextExt as TlsEvalContextExt, TlsData}; pub use crate::operator::EvalContextExt as OperatorEvalContextExt; -pub use crate::tls::{EvalContextExt as TlsEvalContextExt, TlsData}; pub use crate::range_map::RangeMap; pub use crate::helpers::{EvalContextExt as HelpersEvalContextExt}; pub use crate::mono_hash_map::MonoHashMap; diff --git a/src/shims/mod.rs b/src/shims/mod.rs index 0fc23e8119375..3258cf3d9c1da 100644 --- a/src/shims/mod.rs +++ b/src/shims/mod.rs @@ -1,5 +1,6 @@ pub mod foreign_items; pub mod intrinsics; +pub mod tls; use rustc::{ty, mir}; diff --git a/src/tls.rs b/src/shims/tls.rs similarity index 100% rename from src/tls.rs rename to src/shims/tls.rs From 802dcb7f890cf1e05a98fd21466f74d9c9b5b748 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 5 Jul 2019 00:06:41 +0200 Subject: [PATCH 0896/3747] temporarily disable ptr_offset, maybe that helps --- tests/run-pass-noseed/ptr_int_casts.rs | 1 + tests/{run-pass => run-pass-noseed}/ptr_offset.rs | 2 ++ 2 files changed, 3 insertions(+) rename tests/{run-pass => run-pass-noseed}/ptr_offset.rs (85%) diff --git a/tests/run-pass-noseed/ptr_int_casts.rs b/tests/run-pass-noseed/ptr_int_casts.rs index c279024f35eab..ebf65ac3fe246 100644 --- a/tests/run-pass-noseed/ptr_int_casts.rs +++ b/tests/run-pass-noseed/ptr_int_casts.rs @@ -1,3 +1,4 @@ +// FIXME move this to run-pass, it should work with intptrcast. use std::mem; use std::ptr; diff --git a/tests/run-pass/ptr_offset.rs b/tests/run-pass-noseed/ptr_offset.rs similarity index 85% rename from tests/run-pass/ptr_offset.rs rename to tests/run-pass-noseed/ptr_offset.rs index 1c7f0eb717974..a836e02812da7 100644 --- a/tests/run-pass/ptr_offset.rs +++ b/tests/run-pass-noseed/ptr_offset.rs @@ -1,3 +1,5 @@ +// FIXME move this to run-pass, it should work with intptrcast. + fn f() -> i32 { 42 } fn main() { From 07d5e9917cb17d8c8aa2c132919e985841ed24bc Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 5 Jul 2019 09:56:42 +0200 Subject: [PATCH 0897/3747] avoid Scalar::is_null_ptr, it is going away --- src/helpers.rs | 22 ++++++++++++++++++++++ src/shims/foreign_items.rs | 35 +++++++++++++---------------------- src/shims/tls.rs | 20 +++++++++++++------- 3 files changed, 48 insertions(+), 29 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index 16451fb8726a6..3503af43690f9 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -43,6 +43,28 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx }) } + /// Write a 0 of the appropriate size to `dest`. + fn write_null(&mut self, dest: PlaceTy<'tcx, Tag>) -> InterpResult<'tcx> { + self.eval_context_mut().write_scalar(Scalar::from_int(0, dest.layout.size), dest) + } + + /// Test if this immediate equals 0. + fn is_null(&self, val: Scalar) -> InterpResult<'tcx, bool> { + let this = self.eval_context_ref(); + let null = Scalar::from_int(0, this.memory().pointer_size()); + this.ptr_eq(val, null) + } + + /// Turn a Scalar into an Option + fn test_null(&self, val: Scalar) -> InterpResult<'tcx, Option>> { + let this = self.eval_context_ref(); + Ok(if this.is_null(val)? { + None + } else { + Some(val) + }) + } + /// Visits the memory covered by `place`, sensitive to freezing: the 3rd parameter /// will be true if this is frozen, false if this is in an `UnsafeCell`. fn visit_freeze_sensitive( diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index c9b10e02c978a..d43374f1bcf89 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -49,7 +49,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ptr: Scalar, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - if !ptr.is_null_ptr(this) { + if !this.is_null(ptr)? { this.memory_mut().deallocate( ptr.to_ptr()?, None, @@ -66,7 +66,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); let align = this.min_align(); - if old_ptr.is_null_ptr(this) { + if this.is_null(old_ptr)? { if new_size == 0 { Ok(Scalar::from_int(0, this.pointer_size())) } else { @@ -427,7 +427,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let mut success = None; { let name_ptr = this.read_scalar(args[0])?.not_undef()?; - if !name_ptr.is_null_ptr(this) { + if !this.is_null(name_ptr)? { let name_ptr = name_ptr.to_ptr()?; let name = this .memory() @@ -455,7 +455,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let name_ptr = this.read_scalar(args[0])?.not_undef()?; let value_ptr = this.read_scalar(args[1])?.to_ptr()?; let value = this.memory().get(value_ptr.alloc_id)?.read_c_str(tcx, value_ptr)?; - if !name_ptr.is_null_ptr(this) { + if !this.is_null(name_ptr)? { let name_ptr = name_ptr.to_ptr()?; let name = this.memory().get(name_ptr.alloc_id)?.read_c_str(tcx, name_ptr)?; if !name.is_empty() && !name.contains(&b'=') { @@ -638,14 +638,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let key_ptr = this.read_scalar(args[0])?.not_undef()?; // Extract the function type out of the signature (that seems easier than constructing it ourselves). - let dtor = match this.read_scalar(args[1])?.not_undef()? { - Scalar::Ptr(dtor_ptr) => Some(this.memory().get_fn(dtor_ptr)?), - Scalar::Raw { data: 0, size } => { - // NULL pointer - assert_eq!(size as u64, this.memory().pointer_size().bytes()); - None - }, - Scalar::Raw { .. } => return err!(ReadBytesAsPointer), + let dtor = match this.test_null(this.read_scalar(args[1])?.not_undef()?)? { + Some(dtor_ptr) => Some(this.memory().get_fn(dtor_ptr.to_ptr()?)?), + None => None, }; // Figure out how large a pthread TLS key actually is. @@ -657,7 +652,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let key_layout = this.layout_of(key_type)?; // Create key and write it into the memory where `key_ptr` wants it. - let key = this.machine.tls.create_tls_key(dtor, tcx) as u128; + let key = this.machine.tls.create_tls_key(dtor) as u128; if key_layout.size.bits() < 128 && key >= (1u128 << key_layout.size.bits() as u128) { return err!(OutOfTls); } @@ -682,13 +677,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "pthread_getspecific" => { let key = this.read_scalar(args[0])?.to_bits(args[0].layout.size)?; - let ptr = this.machine.tls.load_tls(key)?; + let ptr = this.machine.tls.load_tls(key, tcx)?; this.write_scalar(ptr, dest)?; } "pthread_setspecific" => { let key = this.read_scalar(args[0])?.to_bits(args[0].layout.size)?; let new_ptr = this.read_scalar(args[1])?.not_undef()?; - this.machine.tls.store_tls(key, new_ptr)?; + this.machine.tls.store_tls(key, this.test_null(new_ptr)?)?; // Return success (`0`). this.write_null(dest)?; @@ -842,7 +837,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // This just creates a key; Windows does not natively support TLS destructors. // Create key and return it. - let key = this.machine.tls.create_tls_key(None, tcx) as u128; + let key = this.machine.tls.create_tls_key(None) as u128; // Figure out how large a TLS key actually is. This is `c::DWORD`. if dest.layout.size.bits() < 128 @@ -853,13 +848,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "TlsGetValue" => { let key = this.read_scalar(args[0])?.to_u32()? as u128; - let ptr = this.machine.tls.load_tls(key)?; + let ptr = this.machine.tls.load_tls(key, tcx)?; this.write_scalar(ptr, dest)?; } "TlsSetValue" => { let key = this.read_scalar(args[0])?.to_u32()? as u128; let new_ptr = this.read_scalar(args[1])?.not_undef()?; - this.machine.tls.store_tls(key, new_ptr)?; + this.machine.tls.store_tls(key, this.test_null(new_ptr)?)?; // Return success (`1`). this.write_scalar(Scalar::from_int(1, dest.layout.size), dest)?; @@ -936,10 +931,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(()) } - fn write_null(&mut self, dest: PlaceTy<'tcx, Tag>) -> InterpResult<'tcx> { - self.eval_context_mut().write_scalar(Scalar::from_int(0, dest.layout.size), dest) - } - /// Evaluates the scalar at the specified path. Returns Some(val) /// if the path could be resolved, and None otherwise fn eval_path_scalar(&mut self, path: &[&str]) -> InterpResult<'tcx, Option>> { diff --git a/src/shims/tls.rs b/src/shims/tls.rs index ddc301447c7e3..6d6a71b8eb246 100644 --- a/src/shims/tls.rs +++ b/src/shims/tls.rs @@ -12,7 +12,10 @@ pub type TlsKey = u128; #[derive(Copy, Clone, Debug)] pub struct TlsEntry<'tcx> { - pub(crate) data: Scalar, // Will eventually become a map from thread IDs to `Scalar`s, if we ever support more than one thread. + /// The data for this key. None is used to represent NULL. + /// (We normalize this early to avoid having to do a NULL-ptr-test each time we access the data.) + /// Will eventually become a map from thread IDs to `Scalar`s, if we ever support more than one thread. + pub(crate) data: Option>, pub(crate) dtor: Option>, } @@ -38,14 +41,13 @@ impl<'tcx> TlsData<'tcx> { pub fn create_tls_key( &mut self, dtor: Option>, - cx: &impl HasDataLayout, ) -> TlsKey { let new_key = self.next_key; self.next_key += 1; self.keys.insert( new_key, TlsEntry { - data: Scalar::ptr_null(cx).into(), + data: None, dtor, }, ); @@ -63,17 +65,21 @@ impl<'tcx> TlsData<'tcx> { } } - pub fn load_tls(&mut self, key: TlsKey) -> InterpResult<'tcx, Scalar> { + pub fn load_tls( + &mut self, + key: TlsKey, + cx: &impl HasDataLayout, + ) -> InterpResult<'tcx, Scalar> { match self.keys.get(&key) { Some(&TlsEntry { data, .. }) => { trace!("TLS key {} loaded: {:?}", key, data); - Ok(data) + Ok(data.unwrap_or_else(|| Scalar::ptr_null(cx).into())) } None => err!(TlsOutOfBounds), } } - pub fn store_tls(&mut self, key: TlsKey, new_data: Scalar) -> InterpResult<'tcx> { + pub fn store_tls(&mut self, key: TlsKey, new_data: Option>) -> InterpResult<'tcx> { match self.keys.get_mut(&key) { Some(&mut TlsEntry { ref mut data, .. }) => { trace!("TLS key {} stored: {:?}", key, new_data); @@ -117,7 +123,7 @@ impl<'tcx> TlsData<'tcx> { for (&key, &mut TlsEntry { ref mut data, dtor }) in thread_local.range_mut((start, Unbounded)) { - if !data.is_null_ptr(cx) { + if let Some(ref mut data) = *data { if let Some(dtor) = dtor { let ret = Some((dtor, *data, key)); *data = Scalar::ptr_null(cx); From 698b311a596b5d141b0c42f1b5400adc1f11150f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 5 Jul 2019 10:08:57 +0200 Subject: [PATCH 0898/3747] fix NULL in TLS dtors --- src/shims/tls.rs | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/shims/tls.rs b/src/shims/tls.rs index 6d6a71b8eb246..9a22c03bf2f69 100644 --- a/src/shims/tls.rs +++ b/src/shims/tls.rs @@ -6,6 +6,7 @@ use rustc::{ty, ty::layout::HasDataLayout, mir}; use crate::{ InterpResult, InterpError, StackPopCleanup, MPlaceTy, Scalar, Tag, + HelpersEvalContextExt, }; pub type TlsKey = u128; @@ -111,7 +112,6 @@ impl<'tcx> TlsData<'tcx> { fn fetch_tls_dtor( &mut self, key: Option, - cx: &impl HasDataLayout, ) -> Option<(ty::Instance<'tcx>, Scalar, TlsKey)> { use std::collections::Bound::*; @@ -123,10 +123,10 @@ impl<'tcx> TlsData<'tcx> { for (&key, &mut TlsEntry { ref mut data, dtor }) in thread_local.range_mut((start, Unbounded)) { - if let Some(ref mut data) = *data { + if let Some(data_scalar) = *data { if let Some(dtor) = dtor { - let ret = Some((dtor, *data, key)); - *data = Scalar::ptr_null(cx); + let ret = Some((dtor, data_scalar, key)); + *data = None; return ret; } } @@ -139,10 +139,11 @@ impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tc pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { fn run_tls_dtors(&mut self) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - let mut dtor = this.machine.tls.fetch_tls_dtor(None, &*this.tcx); + let mut dtor = this.machine.tls.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); + assert!(!this.is_null(ptr).unwrap(), "Data can't be NULL when dtor is called!"); // TODO: Potentially, this has to support all the other possible instances? // See eval_fn_call in interpret/terminator/mod.rs let mir = this.load_mir(instance.def)?; @@ -163,9 +164,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // step until out of stackframes this.run()?; - dtor = match this.machine.tls.fetch_tls_dtor(Some(key), &*this.tcx) { + dtor = match this.machine.tls.fetch_tls_dtor(Some(key)) { dtor @ Some(_) => dtor, - None => this.machine.tls.fetch_tls_dtor(None, &*this.tcx), + None => this.machine.tls.fetch_tls_dtor(None), }; } // FIXME: On a windows target, call `unsafe extern "system" fn on_tls_callback`. From aad5fde70316f87f023b918001f02db21d7ff0e1 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 5 Jul 2019 19:21:21 +0200 Subject: [PATCH 0899/3747] fix deallocating/reallocating with integer pointers --- src/shims/foreign_items.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index c9b10e02c978a..540e3fc964066 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -50,8 +50,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); if !ptr.is_null_ptr(this) { + let ptr = this.force_ptr(ptr)?; this.memory_mut().deallocate( - ptr.to_ptr()?, + ptr, None, MiriMemoryKind::C.into(), )?; @@ -78,7 +79,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(Scalar::Ptr(new_ptr)) } } else { - let old_ptr = old_ptr.to_ptr()?; + let old_ptr = this.force_ptr(old_ptr)?; let memory = this.memory_mut(); let old_size = Size::from_bytes(memory.get(old_ptr.alloc_id)?.bytes.len() as u64); if new_size == 0 { @@ -234,7 +235,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::Ptr(ptr), dest)?; } "__rust_dealloc" => { - let ptr = this.read_scalar(args[0])?.to_ptr()?; + let ptr = this.read_scalar(args[0])?.not_undef()?; let old_size = this.read_scalar(args[1])?.to_usize(this)?; let align = this.read_scalar(args[2])?.to_usize(this)?; if old_size == 0 { @@ -243,6 +244,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if !align.is_power_of_two() { return err!(HeapAllocNonPowerOfTwoAlignment(align)); } + let ptr = this.force_ptr(ptr)?; this.memory_mut().deallocate( ptr, Some((Size::from_bytes(old_size), Align::from_bytes(align).unwrap())), From 6c58d40a8d42650332a4c68b44ea3827263c395f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 5 Jul 2019 19:21:42 +0200 Subject: [PATCH 0900/3747] temporarily disable validation for 'cargo miri test' testing --- test-cargo-miri/run-test.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test-cargo-miri/run-test.py b/test-cargo-miri/run-test.py index 73515c74e4010..a9aba008e9a92 100755 --- a/test-cargo-miri/run-test.py +++ b/test-cargo-miri/run-test.py @@ -52,8 +52,9 @@ def test_cargo_miri_run(): ) def test_cargo_miri_test(): + # FIXME: enable validation again, once that no longer conflicts with intptrcast test("cargo miri test", - cargo_miri("test") + ["--", "-Zmiri-seed=feed"], + cargo_miri("test") + ["--", "-Zmiri-seed=feed", "-Zmiri-disable-validation"], "test.stdout.ref", "test.stderr.ref" ) test("cargo miri test (with filter)", From 9b58492df179be10cc2004ad0fe0616cdfd9b505 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 5 Jul 2019 19:22:22 +0200 Subject: [PATCH 0901/3747] temporarily disable intptrcast advanced testing on Windows --- tests/compiletest.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/compiletest.rs b/tests/compiletest.rs index 1d32d3a732440..b31be0a4f32d6 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -83,6 +83,7 @@ fn miri_pass(path: &str, target: &str, opt: bool, noseed: bool) { flags.push("-Zmir-opt-level=3".to_owned()); } else if !noseed { // Run with intptrcast. Avoid test matrix explosion by doing either this or opt-level=3. + #[cfg(not(windows))] // FIXME re-enable on Windows flags.push("-Zmiri-seed=".to_owned()); } From 4d76dd1f09db1b5a69435d3aa85c4c2f0a5887c1 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 5 Jul 2019 21:26:58 +0200 Subject: [PATCH 0902/3747] temporarily disable validation on Windows --- src/eval.rs | 10 +++++++++- tests/compiletest.rs | 5 +++-- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/src/eval.rs b/src/eval.rs index a1157af0e39b6..91a563fa56b9a 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -35,8 +35,16 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( Evaluator::new(), ); + // FIXME(https://github.com/rust-lang/miri/pull/803): no validation on Windows. + let target_os = ecx.tcx.tcx.sess.target.target.target_os.to_lowercase(); + let validate = if target_os == "windows" { + false + } else { + config.validate + }; + // FIXME: InterpretCx::new should take an initial MemoryExtra - ecx.memory_mut().extra = MemoryExtra::new(config.seed.map(StdRng::seed_from_u64), config.validate); + ecx.memory_mut().extra = MemoryExtra::new(config.seed.map(StdRng::seed_from_u64), validate); let main_instance = ty::Instance::mono(ecx.tcx.tcx, main_id); let main_mir = ecx.load_mir(main_instance.def)?; diff --git a/tests/compiletest.rs b/tests/compiletest.rs index b31be0a4f32d6..076deca6a318c 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -83,7 +83,6 @@ fn miri_pass(path: &str, target: &str, opt: bool, noseed: bool) { flags.push("-Zmir-opt-level=3".to_owned()); } else if !noseed { // Run with intptrcast. Avoid test matrix explosion by doing either this or opt-level=3. - #[cfg(not(windows))] // FIXME re-enable on Windows flags.push("-Zmiri-seed=".to_owned()); } @@ -113,7 +112,9 @@ fn run_pass_miri(opt: bool) { } fn compile_fail_miri(opt: bool) { - compile_fail("tests/compile-fail", &get_target(), opt); + if !cfg!(windows) { // FIXME re-enable on Windows + compile_fail("tests/compile-fail", &get_target(), opt); + } } fn test_runner(_tests: &[&()]) { From f23b782101c03331413870a11a787d4b605b84df Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 2 Jul 2019 09:03:45 +0200 Subject: [PATCH 0903/3747] align small malloc-allocations even less, and test that we do --- src/machine.rs | 4 +- src/shims/foreign_items.rs | 70 +++++++++++++++--------- tests/run-pass/{realloc.rs => malloc.rs} | 11 ++++ 3 files changed, 58 insertions(+), 27 deletions(-) rename tests/run-pass/{realloc.rs => malloc.rs} (70%) diff --git a/src/machine.rs b/src/machine.rs index 0ddb2d40b8e85..a58903f6d5160 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -25,6 +25,8 @@ pub enum MiriMemoryKind { Rust, /// `malloc` memory. C, + /// Windows `HeapAlloc` memory. + WinHeap, /// Part of env var emulation. Env, /// Statics. @@ -407,7 +409,7 @@ impl MayLeak for MiriMemoryKind { fn may_leak(self) -> bool { use self::MiriMemoryKind::*; match self { - Rust | C => false, + Rust | C | WinHeap => false, Env | Static => true, } } diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 2a3644e45cbf7..38fc36609e698 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -10,8 +10,8 @@ use crate::*; impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { - /// Returns the minimum alignment for the target architecture. - fn min_align(&self) -> Align { + /// Returns the minimum alignment for the target architecture for allocations of the given size. + fn min_align(&self, size: u64, kind: MiriMemoryKind) -> Align { let this = self.eval_context_ref(); // List taken from `libstd/sys_common/alloc.rs`. let min_align = match this.tcx.tcx.sess.target.target.arch.as_str() { @@ -19,21 +19,39 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "x86_64" | "aarch64" | "mips64" | "s390x" | "sparc64" => 16, arch => bug!("Unsupported target architecture: {}", arch), }; - Align::from_bytes(min_align).unwrap() + // Windows always aligns, even small allocations. + // Source: + // But jemalloc does not, so for the C heap we only align if the allocation is sufficiently big. + if kind == MiriMemoryKind::WinHeap || size >= min_align { + return Align::from_bytes(min_align).unwrap(); + } + // We have `size < min_align`. Round `size` *down* to the next power of two and use that. + fn prev_power_of_two(x: u64) -> u64 { + let next_pow2 = x.next_power_of_two(); + if next_pow2 == x { + // x *is* a power of two, just use that. + x + } else { + // x is between two powers, so next = 2*prev. + next_pow2 / 2 + } + } + Align::from_bytes(prev_power_of_two(size)).unwrap() } fn malloc( &mut self, size: u64, zero_init: bool, + kind: MiriMemoryKind, ) -> Scalar { let this = self.eval_context_mut(); let tcx = &{this.tcx.tcx}; if size == 0 { Scalar::from_int(0, this.pointer_size()) } else { - let align = this.min_align(); - let ptr = this.memory_mut().allocate(Size::from_bytes(size), align, MiriMemoryKind::C.into()); + let align = this.min_align(size, kind); + let ptr = this.memory_mut().allocate(Size::from_bytes(size), align, kind.into()); if zero_init { // We just allocated this, the access cannot fail this.memory_mut() @@ -47,6 +65,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn free( &mut self, ptr: Scalar, + kind: MiriMemoryKind, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); if !this.is_null(ptr)? { @@ -54,7 +73,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.memory_mut().deallocate( ptr, None, - MiriMemoryKind::C.into(), + kind.into(), )?; } Ok(()) @@ -64,39 +83,38 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx &mut self, old_ptr: Scalar, new_size: u64, + kind: MiriMemoryKind, ) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); - let align = this.min_align(); + let new_align = this.min_align(new_size, kind); if this.is_null(old_ptr)? { if new_size == 0 { Ok(Scalar::from_int(0, this.pointer_size())) } else { let new_ptr = this.memory_mut().allocate( Size::from_bytes(new_size), - align, - MiriMemoryKind::C.into() + new_align, + kind.into() ); Ok(Scalar::Ptr(new_ptr)) } } else { let old_ptr = this.force_ptr(old_ptr)?; let memory = this.memory_mut(); - let old_size = Size::from_bytes(memory.get(old_ptr.alloc_id)?.bytes.len() as u64); if new_size == 0 { memory.deallocate( old_ptr, - Some((old_size, align)), - MiriMemoryKind::C.into(), + None, + kind.into(), )?; Ok(Scalar::from_int(0, this.pointer_size())) } else { let new_ptr = memory.reallocate( old_ptr, - old_size, - align, + None, Size::from_bytes(new_size), - align, - MiriMemoryKind::C.into(), + new_align, + kind.into(), )?; Ok(Scalar::Ptr(new_ptr)) } @@ -145,14 +163,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx match link_name { "malloc" => { let size = this.read_scalar(args[0])?.to_usize(this)?; - let res = this.malloc(size, /*zero_init:*/ false); + let res = this.malloc(size, /*zero_init:*/ false, MiriMemoryKind::C); this.write_scalar(res, dest)?; } "calloc" => { let items = this.read_scalar(args[0])?.to_usize(this)?; let len = this.read_scalar(args[1])?.to_usize(this)?; let size = items.checked_mul(len).ok_or_else(|| InterpError::Overflow(mir::BinOp::Mul))?; - let res = this.malloc(size, /*zero_init:*/ true); + let res = this.malloc(size, /*zero_init:*/ true, MiriMemoryKind::C); this.write_scalar(res, dest)?; } "posix_memalign" => { @@ -187,12 +205,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "free" => { let ptr = this.read_scalar(args[0])?.not_undef()?; - this.free(ptr)?; + this.free(ptr, MiriMemoryKind::C)?; } "realloc" => { let old_ptr = this.read_scalar(args[0])?.not_undef()?; let new_size = this.read_scalar(args[1])?.to_usize(this)?; - let res = this.realloc(old_ptr, new_size)?; + let res = this.realloc(old_ptr, new_size, MiriMemoryKind::C)?; this.write_scalar(res, dest)?; } @@ -262,12 +280,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if !align.is_power_of_two() { return err!(HeapAllocNonPowerOfTwoAlignment(align)); } + let align = Align::from_bytes(align).unwrap(); let new_ptr = this.memory_mut().reallocate( ptr, - Size::from_bytes(old_size), - Align::from_bytes(align).unwrap(), + Some((Size::from_bytes(old_size), align)), Size::from_bytes(new_size), - Align::from_bytes(align).unwrap(), + align, MiriMemoryKind::Rust.into(), )?; this.write_scalar(Scalar::Ptr(new_ptr), dest)?; @@ -765,14 +783,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let flags = this.read_scalar(args[1])?.to_u32()?; let size = this.read_scalar(args[2])?.to_usize(this)?; let zero_init = (flags & 0x00000008) != 0; // HEAP_ZERO_MEMORY - let res = this.malloc(size, zero_init); + let res = this.malloc(size, zero_init, MiriMemoryKind::WinHeap); this.write_scalar(res, dest)?; } "HeapFree" => { let _handle = this.read_scalar(args[0])?.to_isize(this)?; let _flags = this.read_scalar(args[1])?.to_u32()?; let ptr = this.read_scalar(args[2])?.not_undef()?; - this.free(ptr)?; + this.free(ptr, MiriMemoryKind::WinHeap)?; this.write_scalar(Scalar::from_int(1, Size::from_bytes(4)), dest)?; } "HeapReAlloc" => { @@ -780,7 +798,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let _flags = this.read_scalar(args[1])?.to_u32()?; let ptr = this.read_scalar(args[2])?.not_undef()?; let size = this.read_scalar(args[3])?.to_usize(this)?; - let res = this.realloc(ptr, size)?; + let res = this.realloc(ptr, size, MiriMemoryKind::WinHeap)?; this.write_scalar(res, dest)?; } diff --git a/tests/run-pass/realloc.rs b/tests/run-pass/malloc.rs similarity index 70% rename from tests/run-pass/realloc.rs rename to tests/run-pass/malloc.rs index c23b3e645c703..a50b3f3606de3 100644 --- a/tests/run-pass/realloc.rs +++ b/tests/run-pass/malloc.rs @@ -1,4 +1,5 @@ //ignore-windows: Uses POSIX APIs +//compile-flags: -Zmiri-seed= #![feature(rustc_private)] @@ -7,6 +8,16 @@ use core::{slice, ptr}; extern crate libc; fn main() { + // Test that small allocations sometimes *are* not very aligned. + let saw_unaligned = (0..64).any(|_| unsafe { + let p = libc::malloc(3); + let addr = p as usize; + let unaligned = addr % 4 != 0; // test that this is not 4-aligned + libc::free(p); // FIXME have to free *after* test; should allow ptr-to-int of dangling ptr. + unaligned + }); + assert!(saw_unaligned); + unsafe { // Use calloc for initialized memory let p1 = libc::calloc(20, 1); From 1729965808dec239aa46f2eafaa39261f491a0b4 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 5 Jul 2019 23:47:10 +0200 Subject: [PATCH 0904/3747] rename InterpretCx -> InterpCx --- src/eval.rs | 8 ++++---- src/machine.rs | 22 +++++++++++----------- src/shims/foreign_items.rs | 2 +- 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/eval.rs b/src/eval.rs index 91a563fa56b9a..b29ce3537706b 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -8,7 +8,7 @@ use rustc::hir::def_id::DefId; use rustc::mir; use crate::{ - InterpResult, InterpError, InterpretCx, StackPopCleanup, struct_error, + InterpResult, InterpError, InterpCx, StackPopCleanup, struct_error, Scalar, Tag, Pointer, MemoryExtra, MiriMemoryKind, Evaluator, TlsEvalContextExt, }; @@ -28,8 +28,8 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig, -) -> InterpResult<'tcx, InterpretCx<'mir, 'tcx, Evaluator<'tcx>>> { - let mut ecx = InterpretCx::new( +) -> InterpResult<'tcx, InterpCx<'mir, 'tcx, Evaluator<'tcx>>> { + let mut ecx = InterpCx::new( tcx.at(syntax::source_map::DUMMY_SP), ty::ParamEnv::reveal_all(), Evaluator::new(), @@ -43,7 +43,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( config.validate }; - // FIXME: InterpretCx::new should take an initial MemoryExtra + // FIXME: InterpCx::new should take an initial MemoryExtra ecx.memory_mut().extra = MemoryExtra::new(config.seed.map(StdRng::seed_from_u64), validate); let main_instance = ty::Instance::mono(ecx.tcx.tcx, main_id); diff --git a/src/machine.rs b/src/machine.rs index a58903f6d5160..930eeee96b593 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -105,8 +105,8 @@ impl<'tcx> Evaluator<'tcx> { } } -/// A rustc InterpretCx for Miri. -pub type MiriEvalContext<'mir, 'tcx> = InterpretCx<'mir, 'tcx, Evaluator<'tcx>>; +/// A rustc InterpCx for Miri. +pub type MiriEvalContext<'mir, 'tcx> = InterpCx<'mir, 'tcx, Evaluator<'tcx>>; /// A little trait that's useful to be inherited by extension traits. pub trait MiriEvalContextExt<'mir, 'tcx> { @@ -138,14 +138,14 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { const STATIC_KIND: Option = Some(MiriMemoryKind::Static); #[inline(always)] - fn enforce_validity(ecx: &InterpretCx<'mir, 'tcx, Self>) -> bool { + fn enforce_validity(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool { ecx.memory().extra.validate } /// Returns `Ok()` when the function was handled; fail otherwise. #[inline(always)] fn find_fn( - ecx: &mut InterpretCx<'mir, 'tcx, Self>, + ecx: &mut InterpCx<'mir, 'tcx, Self>, instance: ty::Instance<'tcx>, args: &[OpTy<'tcx, Tag>], dest: Option>, @@ -156,7 +156,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { #[inline(always)] fn call_intrinsic( - ecx: &mut rustc_mir::interpret::InterpretCx<'mir, 'tcx, Self>, + ecx: &mut rustc_mir::interpret::InterpCx<'mir, 'tcx, Self>, instance: ty::Instance<'tcx>, args: &[OpTy<'tcx, Tag>], dest: PlaceTy<'tcx, Tag>, @@ -166,7 +166,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { #[inline(always)] fn ptr_op( - ecx: &rustc_mir::interpret::InterpretCx<'mir, 'tcx, Self>, + ecx: &rustc_mir::interpret::InterpCx<'mir, 'tcx, Self>, bin_op: mir::BinOp, left: ImmTy<'tcx, Tag>, right: ImmTy<'tcx, Tag>, @@ -175,7 +175,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { } fn box_alloc( - ecx: &mut InterpretCx<'mir, 'tcx, Self>, + ecx: &mut InterpCx<'mir, 'tcx, Self>, dest: PlaceTy<'tcx, Tag>, ) -> InterpResult<'tcx> { trace!("box_alloc for {:?}", dest.layout.ty); @@ -241,7 +241,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { } #[inline(always)] - fn before_terminator(_ecx: &mut InterpretCx<'mir, 'tcx, Self>) -> InterpResult<'tcx> + fn before_terminator(_ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx> { // We are not interested in detecting loops. Ok(()) @@ -311,7 +311,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { #[inline(always)] fn retag( - ecx: &mut InterpretCx<'mir, 'tcx, Self>, + ecx: &mut InterpCx<'mir, 'tcx, Self>, kind: mir::RetagKind, place: PlaceTy<'tcx, Tag>, ) -> InterpResult<'tcx> { @@ -325,14 +325,14 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { #[inline(always)] fn stack_push( - ecx: &mut InterpretCx<'mir, 'tcx, Self>, + ecx: &mut InterpCx<'mir, 'tcx, Self>, ) -> InterpResult<'tcx, stacked_borrows::CallId> { Ok(ecx.memory().extra.stacked_borrows.borrow_mut().new_call()) } #[inline(always)] fn stack_pop( - ecx: &mut InterpretCx<'mir, 'tcx, Self>, + ecx: &mut InterpCx<'mir, 'tcx, Self>, extra: stacked_borrows::CallId, ) -> InterpResult<'tcx> { Ok(ecx.memory().extra.stacked_borrows.borrow_mut().end_call(extra)) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 38fc36609e698..2fe2ecc19581a 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -345,7 +345,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx trace!("__rust_maybe_catch_panic: {:?}", f_instance); // Now we make a function call. - // TODO: consider making this reusable? `InterpretCx::step` does something similar + // TODO: consider making this reusable? `InterpCx::step` does something similar // for the TLS destructors, and of course `eval_main`. let mir = this.load_mir(f_instance.def)?; let ret_place = MPlaceTy::dangling(this.layout_of(this.tcx.mk_unit())?, this).into(); From b75e9179bf21254a198e5b7359589cd0502d135c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 5 Jul 2019 23:49:30 +0200 Subject: [PATCH 0905/3747] bump rustc --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 9e4ddf2acaaa8..cbd8e335771e3 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -088b987307b91612ab164026e1dcdd0129fdb62b +24a9bcbb7cb0d8bdc11b8252a9c13f7562c7e4ca From 029a29407acd30454fb41f340a8d108a47bef349 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 5 Jul 2019 23:51:11 +0200 Subject: [PATCH 0906/3747] dangling-ptr-to-int should work now; move to noseed --- tests/{run-pass => run-pass-noseed}/malloc.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) rename tests/{run-pass => run-pass-noseed}/malloc.rs (84%) diff --git a/tests/run-pass/malloc.rs b/tests/run-pass-noseed/malloc.rs similarity index 84% rename from tests/run-pass/malloc.rs rename to tests/run-pass-noseed/malloc.rs index a50b3f3606de3..bf51baacd35a9 100644 --- a/tests/run-pass/malloc.rs +++ b/tests/run-pass-noseed/malloc.rs @@ -11,10 +11,8 @@ fn main() { // Test that small allocations sometimes *are* not very aligned. let saw_unaligned = (0..64).any(|_| unsafe { let p = libc::malloc(3); - let addr = p as usize; - let unaligned = addr % 4 != 0; // test that this is not 4-aligned - libc::free(p); // FIXME have to free *after* test; should allow ptr-to-int of dangling ptr. - unaligned + libc::free(p); + (p as usize) % 4 != 0 // find any that this is *not* 4-aligned }); assert!(saw_unaligned); From 67882459f3ce77199f1a74180c3bccf730b5d5cb Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 6 Jul 2019 09:29:58 +0200 Subject: [PATCH 0907/3747] bump rustc --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index cbd8e335771e3..e278a80633709 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -24a9bcbb7cb0d8bdc11b8252a9c13f7562c7e4ca +481068a707679257e2a738b40987246e0420e787 From 5e022773f3e5b6a8218e94d08566a931d713bb0e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 6 Jul 2019 09:32:35 +0200 Subject: [PATCH 0908/3747] fix unused variable warning --- src/range_map.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/range_map.rs b/src/range_map.rs index f2cbd89f64da6..aa9a87887d375 100644 --- a/src/range_map.rs +++ b/src/range_map.rs @@ -281,7 +281,7 @@ mod tests { .map(|&t| t).collect::>(), vec![19, 19]); // A NOP `iter_mut` should trigger merging. - for x in map.iter_mut(Size::from_bytes(15), Size::from_bytes(5)) { } + for _ in map.iter_mut(Size::from_bytes(15), Size::from_bytes(5)) { } assert_eq!(map.v.len(), 5); assert_eq!( to_vec(&map, 10, 10), From ba8728cd8bbb9852d8884b7444a8b049a432dcd1 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 6 Jul 2019 09:33:22 +0200 Subject: [PATCH 0909/3747] fix test using mem::uninitialized --- tests/run-pass/move-undef-primval.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/run-pass/move-undef-primval.rs b/tests/run-pass/move-undef-primval.rs index 73c33943a63ac..b8bd869b48c97 100644 --- a/tests/run-pass/move-undef-primval.rs +++ b/tests/run-pass/move-undef-primval.rs @@ -1,3 +1,5 @@ +#![allow(deprecated)] + struct Foo { _inner: i32, } From fa290f1a481b0f98ed1de06206e643af8e04acd5 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 5 Jul 2019 18:44:58 +0200 Subject: [PATCH 0910/3747] uninit intrinsic is gone --- src/shims/intrinsics.rs | 30 ------------------------------ 1 file changed, 30 deletions(-) diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 3f9c4e53f09d6..d62e921695905 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -481,36 +481,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(res, dest)?; } - "uninit" => { - // Check fast path: we don't want to force an allocation in case the destination is a simple value, - // but we also do not want to create a new allocation with 0s and then copy that over. - // FIXME: We do not properly validate in case of ZSTs and when doing it in memory! - // However, this only affects direct calls of the intrinsic; calls to the stable - // functions wrapping them do get their validation. - // FIXME: should we check alignment for ZSTs? - if !dest.layout.is_zst() { - match dest.layout.abi { - layout::Abi::Scalar(..) => { - let x = ScalarMaybeUndef::Undef; - this.write_immediate(Immediate::Scalar(x), dest)?; - } - layout::Abi::ScalarPair(..) => { - let x = ScalarMaybeUndef::Undef; - this.write_immediate(Immediate::ScalarPair(x, x), dest)?; - } - _ => { - // Do it in memory - let mplace = this.force_allocation(dest)?; - assert!(mplace.meta.is_none()); - let ptr = mplace.ptr.to_ptr()?; - this.memory_mut() - .get_mut(ptr.alloc_id)? - .mark_definedness(ptr, dest.layout.size, false); - } - } - } - } - "write_bytes" => { let ty = substs.type_at(0); let ty_layout = this.layout_of(ty)?; From 2ca1b94e6d7e1a078b7fcef9a10e2ed07145e1bd Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 30 Jun 2019 16:03:13 +0200 Subject: [PATCH 0911/3747] update to FnVal changes; implement basic Dlsym support and use it for getentropy --- src/eval.rs | 4 +- src/lib.rs | 1 + src/machine.rs | 13 +++++- src/shims/dlsym.rs | 49 +++++++++++++++++++++ src/shims/foreign_items.rs | 87 ++++++++++++++++++++------------------ src/shims/mod.rs | 1 + 6 files changed, 111 insertions(+), 44 deletions(-) create mode 100644 src/shims/dlsym.rs diff --git a/src/eval.rs b/src/eval.rs index 6132c502531fa..bf99d3e61166b 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -11,7 +11,7 @@ use rustc::mir; use crate::{ InterpResult, InterpError, InterpCx, StackPopCleanup, struct_error, - Scalar, Tag, Pointer, + Scalar, Tag, Pointer, FnVal, MemoryExtra, MiriMemoryKind, Evaluator, TlsEvalContextExt, }; @@ -93,7 +93,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( let mut args = ecx.frame().body.args_iter(); // First argument: pointer to `main()`. - let main_ptr = ecx.memory_mut().create_fn_alloc(main_instance); + let main_ptr = ecx.memory_mut().create_fn_alloc(FnVal::Instance(main_instance)); let dest = ecx.eval_place(&mir::Place::Base(mir::PlaceBase::Local(args.next().unwrap())))?; ecx.write_scalar(Scalar::Ptr(main_ptr), dest)?; diff --git a/src/lib.rs b/src/lib.rs index 31e707077769c..295c8e519e13d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -31,6 +31,7 @@ pub use crate::shims::{EvalContextExt as ShimsEvalContextExt}; pub use crate::shims::foreign_items::EvalContextExt as ForeignItemsEvalContextExt; pub use crate::shims::intrinsics::EvalContextExt as IntrinsicsEvalContextExt; pub use crate::shims::tls::{EvalContextExt as TlsEvalContextExt, TlsData}; +pub use crate::shims::dlsym::{Dlsym, EvalContextExt as DlsymEvalContextExt}; pub use crate::operator::EvalContextExt as OperatorEvalContextExt; pub use crate::range_map::RangeMap; pub use crate::helpers::{EvalContextExt as HelpersEvalContextExt}; diff --git a/src/machine.rs b/src/machine.rs index 0875331131bd3..77e02dba266a2 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -135,6 +135,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { type MemoryExtra = MemoryExtra; type AllocExtra = AllocExtra; type PointerTag = Tag; + type ExtraFnVal = Dlsym; type MemoryMap = MonoHashMap, Allocation)>; @@ -145,7 +146,6 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { ecx.memory().extra.validate } - /// Returns `Ok()` when the function was handled; fail otherwise. #[inline(always)] fn find_fn( ecx: &mut InterpCx<'mir, 'tcx, Self>, @@ -157,6 +157,17 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { ecx.find_fn(instance, args, dest, ret) } + #[inline(always)] + fn call_extra_fn( + ecx: &mut InterpCx<'mir, 'tcx, Self>, + fn_val: Dlsym, + args: &[OpTy<'tcx, Tag>], + dest: Option>, + ret: Option, + ) -> InterpResult<'tcx> { + ecx.call_dlsym(fn_val, args, dest, ret) + } + #[inline(always)] fn call_intrinsic( ecx: &mut rustc_mir::interpret::InterpCx<'mir, 'tcx, Self>, diff --git a/src/shims/dlsym.rs b/src/shims/dlsym.rs new file mode 100644 index 0000000000000..1c2567b951ca0 --- /dev/null +++ b/src/shims/dlsym.rs @@ -0,0 +1,49 @@ +use rustc::mir; + +use crate::*; + +#[derive(Debug, Copy, Clone)] +pub enum Dlsym { + GetEntropy, +} + +impl Dlsym { + pub fn from_str(name: &str) -> Option { + use self::Dlsym::*; + Some(match name { + "getentropy" => GetEntropy, + _ => return None, + }) + } +} + +impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} +pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { + fn call_dlsym( + &mut self, + dlsym: Dlsym, + args: &[OpTy<'tcx, Tag>], + dest: Option>, + ret: Option, + ) -> InterpResult<'tcx> { + use self::Dlsym::*; + + let this = self.eval_context_mut(); + + let dest = dest.expect("we don't support any diverging dlsym"); + let ret = ret.expect("dest is `Some` but ret is `None`"); + + match dlsym { + GetEntropy => { + let ptr = this.read_scalar(args[0])?.not_undef()?; + let len = this.read_scalar(args[1])?.to_usize(this)?; + this.gen_random(len as usize, ptr)?; + this.write_null(dest)?; + } + } + + this.goto_block(Some(ret))?; + this.dump_place(*dest); + Ok(()) + } +} diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 2fe2ecc19581a..fb1d08d0bc201 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -307,7 +307,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // neither of which have any effect on our current PRNG let _flags = this.read_scalar(args[3])?.to_i32()?; - gen_random(this, len as usize, ptr)?; + this.gen_random(len as usize, ptr)?; this.write_scalar(Scalar::from_uint(len, dest.layout.size), dest)?; } id => { @@ -324,10 +324,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let symbol_name = this.memory().get(symbol.alloc_id)?.read_c_str(tcx, symbol)?; let err = format!("bad c unicode symbol: {:?}", symbol_name); let symbol_name = ::std::str::from_utf8(symbol_name).unwrap_or(&err); - return err!(Unimplemented(format!( - "miri does not support dynamically loading libraries (requested symbol: {})", - symbol_name - ))); + if let Some(dlsym) = Dlsym::from_str(symbol_name) { + let ptr = this.memory_mut().create_fn_alloc(FnVal::Other(dlsym)); + this.write_scalar(Scalar::from(ptr), dest)?; + } else { + return err!(Unimplemented(format!( + "Unsupported dlsym: {}", symbol_name + ))); + } } "__rust_maybe_catch_panic" => { @@ -340,7 +344,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // We abort on panic, so not much is going on here, but we still have to call the closure. let f = this.read_scalar(args[0])?.to_ptr()?; let data = this.read_scalar(args[1])?.not_undef()?; - let f_instance = this.memory().get_fn(f)?; + let f_instance = this.memory().get_fn(f)?.as_instance()?; this.write_null(dest)?; trace!("__rust_maybe_catch_panic: {:?}", f_instance); @@ -659,7 +663,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Extract the function type out of the signature (that seems easier than constructing it ourselves). let dtor = match this.test_null(this.read_scalar(args[1])?.not_undef()?)? { - Some(dtor_ptr) => Some(this.memory().get_fn(dtor_ptr.to_ptr()?)?), + Some(dtor_ptr) => Some(this.memory().get_fn(dtor_ptr)?.as_instance()?), None => None, }; @@ -766,7 +770,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "SecRandomCopyBytes" => { let len = this.read_scalar(args[1])?.to_usize(this)?; let ptr = this.read_scalar(args[2])?.not_undef()?; - gen_random(this, len as usize, ptr)?; + this.gen_random(len as usize, ptr)?; this.write_null(dest)?; } @@ -934,7 +938,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "SystemFunction036" => { let ptr = this.read_scalar(args[0])?.not_undef()?; let len = this.read_scalar(args[1])?.to_u32()?; - gen_random(this, len as usize, ptr)?; + this.gen_random(len as usize, ptr)?; this.write_scalar(Scalar::from_bool(true), dest)?; } @@ -966,36 +970,37 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } return Ok(None); } -} - -fn gen_random<'mir, 'tcx>( - this: &mut MiriEvalContext<'mir, 'tcx>, - len: usize, - dest: Scalar, -) -> InterpResult<'tcx> { - if len == 0 { - // Nothing to do - return Ok(()); - } - let ptr = dest.to_ptr()?; - - let data = match &mut this.memory_mut().extra.rng { - Some(rng) => { - let mut rng = rng.borrow_mut(); - let mut data = vec![0; len]; - rng.fill_bytes(&mut data); - data - } - None => { - return err!(Unimplemented( - "miri does not support gathering system entropy in deterministic mode! - Use '-Zmiri-seed=' to enable random number generation. - WARNING: Miri does *not* generate cryptographically secure entropy - - do not use Miri to run any program that needs secure random number generation".to_owned(), - )); + + fn gen_random( + &mut self, + len: usize, + dest: Scalar, + ) -> InterpResult<'tcx> { + if len == 0 { + // Nothing to do + return Ok(()); } - }; - let tcx = &{this.tcx.tcx}; - this.memory_mut().get_mut(ptr.alloc_id)? - .write_bytes(tcx, ptr, &data) -} + let this = self.eval_context_mut(); + let ptr = dest.to_ptr()?; + + let data = match &mut this.memory_mut().extra.rng { + Some(rng) => { + let mut rng = rng.borrow_mut(); + let mut data = vec![0; len]; + rng.fill_bytes(&mut data); + data + } + None => { + return err!(Unimplemented( + "miri does not support gathering system entropy in deterministic mode! + Use '-Zmiri-seed=' to enable random number generation. + WARNING: Miri does *not* generate cryptographically secure entropy - + do not use Miri to run any program that needs secure random number generation".to_owned(), + )); + } + }; + let tcx = &{this.tcx.tcx}; + this.memory_mut().get_mut(ptr.alloc_id)? + .write_bytes(tcx, ptr, &data) + } +} \ No newline at end of file diff --git a/src/shims/mod.rs b/src/shims/mod.rs index 3258cf3d9c1da..c06373005ff99 100644 --- a/src/shims/mod.rs +++ b/src/shims/mod.rs @@ -1,6 +1,7 @@ pub mod foreign_items; pub mod intrinsics; pub mod tls; +pub mod dlsym; use rustc::{ty, mir}; From 4f6a56f54fabf86f530527dadce624854ee4c39b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 30 Jun 2019 16:43:05 +0200 Subject: [PATCH 0912/3747] better error message when the program tries to spawn a thread --- src/lib.rs | 2 +- src/machine.rs | 3 +- src/shims/dlsym.rs | 16 ++++++---- src/shims/foreign_items.rs | 48 ++++++++++++++++++++---------- tests/compile-fail/thread-spawn.rs | 7 +++++ 5 files changed, 53 insertions(+), 23 deletions(-) create mode 100644 tests/compile-fail/thread-spawn.rs diff --git a/src/lib.rs b/src/lib.rs index 295c8e519e13d..20c24ad54fe84 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -38,7 +38,7 @@ pub use crate::helpers::{EvalContextExt as HelpersEvalContextExt}; pub use crate::mono_hash_map::MonoHashMap; pub use crate::stacked_borrows::{EvalContextExt as StackedBorEvalContextExt, Tag, Permission, Stack, Stacks, Item}; pub use crate::machine::{ - PAGE_SIZE, STACK_ADDR, NUM_CPUS, + PAGE_SIZE, STACK_ADDR, STACK_SIZE, NUM_CPUS, MemoryExtra, AllocExtra, MiriMemoryKind, Evaluator, MiriEvalContext, MiriEvalContextExt, }; pub use crate::eval::{eval_main, create_ecx, MiriConfig}; diff --git a/src/machine.rs b/src/machine.rs index 77e02dba266a2..58c1cb51ca523 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -18,7 +18,8 @@ use crate::*; // Some global facts about the emulated machine. pub const PAGE_SIZE: u64 = 4*1024; // FIXME: adjust to target architecture -pub const STACK_ADDR: u64 = 16*PAGE_SIZE; // not really about the "stack", but where we start assigning integer addresses to allocations +pub const STACK_ADDR: u64 = 32*PAGE_SIZE; // not really about the "stack", but where we start assigning integer addresses to allocations +pub const STACK_SIZE: u64 = 16*PAGE_SIZE; // whatever pub const NUM_CPUS: u64 = 1; /// Extra memory kinds diff --git a/src/shims/dlsym.rs b/src/shims/dlsym.rs index 1c2567b951ca0..602d8064e82ef 100644 --- a/src/shims/dlsym.rs +++ b/src/shims/dlsym.rs @@ -8,11 +8,17 @@ pub enum Dlsym { } impl Dlsym { - pub fn from_str(name: &str) -> Option { + // Returns an error for unsupported symbols, and None if this symbol + // should become a NULL pointer (pretend it does not exist). + pub fn from_str(name: &str) -> InterpResult<'static, Option> { use self::Dlsym::*; - Some(match name { - "getentropy" => GetEntropy, - _ => return None, + Ok(match name { + "getentropy" => Some(GetEntropy), + "__pthread_get_minstack" => None, + _ => + return err!(Unimplemented(format!( + "Unsupported dlsym: {}", name + ))), }) } } @@ -32,7 +38,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let dest = dest.expect("we don't support any diverging dlsym"); let ret = ret.expect("dest is `Some` but ret is `None`"); - + match dlsym { GetEntropy => { let ptr = this.read_scalar(args[0])?.not_undef()?; diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index fb1d08d0bc201..e31a34a601589 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -324,13 +324,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let symbol_name = this.memory().get(symbol.alloc_id)?.read_c_str(tcx, symbol)?; let err = format!("bad c unicode symbol: {:?}", symbol_name); let symbol_name = ::std::str::from_utf8(symbol_name).unwrap_or(&err); - if let Some(dlsym) = Dlsym::from_str(symbol_name) { + if let Some(dlsym) = Dlsym::from_str(symbol_name)? { let ptr = this.memory_mut().create_fn_alloc(FnVal::Other(dlsym)); this.write_scalar(Scalar::from(ptr), dest)?; } else { - return err!(Unimplemented(format!( - "Unsupported dlsym: {}", symbol_name - ))); + this.write_null(dest)?; } } @@ -713,24 +711,31 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_null(dest)?; } - // Determine stack base address. - "pthread_attr_init" | "pthread_attr_destroy" | "pthread_attr_get_np" | - "pthread_getattr_np" | "pthread_self" | "pthread_get_stacksize_np" => { + // Stack size/address stuff. + "pthread_attr_init" | "pthread_attr_destroy" | "pthread_self" | + "pthread_attr_setstacksize" => { this.write_null(dest)?; } "pthread_attr_getstack" => { - // Second argument is where we are supposed to write the stack size. - let ptr = this.deref_operand(args[1])?; - // Just any address. - let stack_addr = Scalar::from_uint(STACK_ADDR, args[1].layout.size); - this.write_scalar(stack_addr, ptr.into())?; + let addr_place = this.deref_operand(args[1])?; + let size_place = this.deref_operand(args[2])?; + + this.write_scalar( + Scalar::from_uint(STACK_ADDR, addr_place.layout.size), + addr_place.into(), + )?; + this.write_scalar( + Scalar::from_uint(STACK_SIZE, size_place.layout.size), + size_place.into(), + )?; + // Return success (`0`). this.write_null(dest)?; } - "pthread_get_stackaddr_np" => { - // Just any address. - let stack_addr = Scalar::from_uint(STACK_ADDR, dest.layout.size); - this.write_scalar(stack_addr, dest)?; + + // We don't support threading. + "pthread_create" => { + return err!(Unimplemented(format!("Miri does not support threading"))); } // Stub out calls for condvar, mutex and rwlock, to just return `0`. @@ -758,6 +763,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // macOS API stubs. + "pthread_attr_get_np" | "pthread_getattr_np" => { + this.write_null(dest)?; + } + "pthread_get_stackaddr_np" => { + let stack_addr = Scalar::from_uint(STACK_ADDR, dest.layout.size); + this.write_scalar(stack_addr, dest)?; + } + "pthread_get_stacksize_np" => { + let stack_size = Scalar::from_uint(STACK_SIZE, dest.layout.size); + this.write_scalar(stack_size, dest)?; + } "_tlv_atexit" => { // FIXME: register the destructor. }, diff --git a/tests/compile-fail/thread-spawn.rs b/tests/compile-fail/thread-spawn.rs new file mode 100644 index 0000000000000..450dea99f552f --- /dev/null +++ b/tests/compile-fail/thread-spawn.rs @@ -0,0 +1,7 @@ +use std::thread; + +// error-pattern: Miri does not support threading + +fn main() { + thread::spawn(|| {}); +} From b3c3c33ebf1f2e340e992c2f23ceaa39fc4bb365 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 30 Jun 2019 16:52:12 +0200 Subject: [PATCH 0913/3747] bump the version of getrandom that we test --- test-cargo-miri/Cargo.lock | 58 ++++++++------------------------------ 1 file changed, 11 insertions(+), 47 deletions(-) diff --git a/test-cargo-miri/Cargo.lock b/test-cargo-miri/Cargo.lock index 8343832886a6b..55e5a3dfc185d 100644 --- a/test-cargo-miri/Cargo.lock +++ b/test-cargo-miri/Cargo.lock @@ -5,11 +5,6 @@ name = "autocfg" version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "bitflags" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "byteorder" version = "1.3.2" @@ -33,34 +28,22 @@ dependencies = [ "rand 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "cloudabi" -version = "0.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "fuchsia-cprng" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "getrandom" -version = "0.1.3" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "lazy_static" version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "spin 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", +] [[package]] name = "libc" @@ -85,7 +68,7 @@ name = "rand" version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "getrandom 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "getrandom 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", "rand_chacha 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -108,7 +91,7 @@ name = "rand_core" version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "getrandom 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "getrandom 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -129,32 +112,15 @@ dependencies = [ ] [[package]] -name = "winapi" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" +name = "spin" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" [metadata] "checksum autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "0e49efa51329a5fd37e7c79db4621af617cd4e3e5bc224939808d076077077bf" -"checksum bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3d155346769a6855b86399e9bc3814ab343cd3d62c7e985113d46a0ec3c281fd" "checksum byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a7c3dd8985a7111efc5c80b44e23ecdd8c007de8ade3b96595387e812b957cf5" "checksum c2-chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7d64d04786e0f528460fc884753cf8dddcc466be308f6026f8e355c41a0e4101" -"checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" -"checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" -"checksum getrandom 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8d1dffef07351aafe6ef177e4dd2b8dcf503e6bc765dea3b0de9ed149a3db1ec" +"checksum getrandom 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "e65cce4e5084b14874c4e7097f38cab54f47ee554f9194673456ea379dcc4c55" "checksum lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bc5729f27f159ddd61f4df6228e827e86643d4d3e7c32183cb30a1c08f604a14" "checksum libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)" = "6281b86796ba5e4366000be6e9e18bf35580adf9e63fbe2294aadb587613a319" "checksum num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bcef43580c035376c0705c42792c294b66974abbfd2789b511784023f71f3273" @@ -164,6 +130,4 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum rand_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "615e683324e75af5d43d8f7a39ffe3ee4a9dc42c5c701167a71dc59c3a493aca" "checksum rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" "checksum rand_pcg 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3e196346cbbc5c70c77e7b4926147ee8e383a38ee4d15d58a08098b169e492b6" -"checksum winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "f10e386af2b13e47c89e7236a7a14a086791a2b88ebad6df9bf42040195cf770" -"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" -"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +"checksum spin 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "44363f6f51401c34e7be73db0db371c04705d35efbe9f7d6082e03a921a32c55" From 8093a59ffb0318ab315a6386cfe76e6a595a313e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 30 Jun 2019 23:28:24 +0200 Subject: [PATCH 0914/3747] move gen_random to helpers --- src/helpers.rs | 36 ++++++++++++++++++++++++++++++++++++ src/shims/foreign_items.rs | 35 ----------------------------------- 2 files changed, 36 insertions(+), 35 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index 3503af43690f9..b2be90ca999e1 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -3,6 +3,8 @@ use std::mem; use rustc::ty::{self, layout::{self, Size}}; use rustc::hir::def_id::{DefId, CRATE_DEF_INDEX}; +use rand::RngCore; + use crate::*; impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} @@ -65,6 +67,40 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx }) } + /// Generate some random bytes, and write them to `dest`. + fn gen_random( + &mut self, + len: usize, + dest: Scalar, + ) -> InterpResult<'tcx> { + if len == 0 { + // Nothing to do + return Ok(()); + } + let this = self.eval_context_mut(); + let ptr = dest.to_ptr()?; + + let data = match &mut this.memory_mut().extra.rng { + Some(rng) => { + let mut rng = rng.borrow_mut(); + let mut data = vec![0; len]; + rng.fill_bytes(&mut data); + data + } + None => { + return err!(Unimplemented( + "miri does not support gathering system entropy in deterministic mode! + Use '-Zmiri-seed=' to enable random number generation. + WARNING: Miri does *not* generate cryptographically secure entropy - + do not use Miri to run any program that needs secure random number generation".to_owned(), + )); + } + }; + let tcx = &{this.tcx.tcx}; + this.memory_mut().get_mut(ptr.alloc_id)? + .write_bytes(tcx, ptr, &data) + } + /// Visits the memory covered by `place`, sensitive to freezing: the 3rd parameter /// will be true if this is frozen, false if this is in an `UnsafeCell`. fn visit_freeze_sensitive( diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index e31a34a601589..7ab97c87e3056 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -4,8 +4,6 @@ use rustc::mir; use syntax::attr; use syntax::symbol::sym; -use rand::RngCore; - use crate::*; impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} @@ -986,37 +984,4 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } return Ok(None); } - - fn gen_random( - &mut self, - len: usize, - dest: Scalar, - ) -> InterpResult<'tcx> { - if len == 0 { - // Nothing to do - return Ok(()); - } - let this = self.eval_context_mut(); - let ptr = dest.to_ptr()?; - - let data = match &mut this.memory_mut().extra.rng { - Some(rng) => { - let mut rng = rng.borrow_mut(); - let mut data = vec![0; len]; - rng.fill_bytes(&mut data); - data - } - None => { - return err!(Unimplemented( - "miri does not support gathering system entropy in deterministic mode! - Use '-Zmiri-seed=' to enable random number generation. - WARNING: Miri does *not* generate cryptographically secure entropy - - do not use Miri to run any program that needs secure random number generation".to_owned(), - )); - } - }; - let tcx = &{this.tcx.tcx}; - this.memory_mut().get_mut(ptr.alloc_id)? - .write_bytes(tcx, ptr, &data) - } } \ No newline at end of file From 3ca934f07d2f0fcf7f5aec5f5493cdbd3dfa7480 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 30 Jun 2019 23:32:25 +0200 Subject: [PATCH 0915/3747] gen_random: use check_ptr_access --- src/helpers.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index b2be90ca999e1..b9fa7bc2a77a4 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -1,6 +1,6 @@ use std::mem; -use rustc::ty::{self, layout::{self, Size}}; +use rustc::ty::{self, layout::{self, Size, Align}}; use rustc::hir::def_id::{DefId, CRATE_DEF_INDEX}; use rand::RngCore; @@ -71,14 +71,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn gen_random( &mut self, len: usize, - dest: Scalar, + ptr: Scalar, ) -> InterpResult<'tcx> { - if len == 0 { - // Nothing to do - return Ok(()); - } let this = self.eval_context_mut(); - let ptr = dest.to_ptr()?; + + let ptr = match this.memory().check_ptr_access(ptr, Size::from_bytes(len as u64), Align::from_bytes(1).unwrap())? { + Some(ptr) => ptr, + None => return Ok(()), // zero-sized access + }; let data = match &mut this.memory_mut().extra.rng { Some(rng) => { From 4fa243be78e4be2ca8d5e79fea26fe87deb720ae Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 1 Jul 2019 23:07:40 +0200 Subject: [PATCH 0916/3747] adjust for get_fn signature change --- src/shims/foreign_items.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 7ab97c87e3056..9dbb55668ef35 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -338,7 +338,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // 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 f = this.read_scalar(args[0])?.to_ptr()?; + let f = this.read_scalar(args[0])?.not_undef()?; let data = this.read_scalar(args[1])?.not_undef()?; let f_instance = this.memory().get_fn(f)?.as_instance()?; this.write_null(dest)?; From 9e130c6c6f46532af4d210ba5e58322cd5c5cd3d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 6 Jul 2019 09:51:20 +0200 Subject: [PATCH 0917/3747] fix for changd machine trait signatures --- src/machine.rs | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/machine.rs b/src/machine.rs index 58c1cb51ca523..d1cf913a75bfd 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -11,7 +11,7 @@ use rand::rngs::StdRng; use syntax::attr; use syntax::symbol::sym; use rustc::hir::def_id::DefId; -use rustc::ty::{self, layout::{Size, LayoutOf}, query::TyCtxtAt}; +use rustc::ty::{self, layout::{Size, LayoutOf}, TyCtxt}; use rustc::mir; use crate::*; @@ -232,8 +232,8 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { } fn find_foreign_static( + tcx: TyCtxt<'tcx>, def_id: DefId, - tcx: TyCtxtAt<'tcx>, ) -> InterpResult<'tcx, Cow<'tcx, Allocation>> { let attrs = tcx.get_attrs(def_id); let link_name = match attr::first_attr_value_str_by_name(&attrs, sym::link_name) { @@ -263,20 +263,20 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { } fn tag_allocation<'b>( + memory_extra: &MemoryExtra, id: AllocId, alloc: Cow<'b, Allocation>, kind: Option>, - memory: &Memory<'mir, 'tcx, Self>, ) -> (Cow<'b, Allocation>, Self::PointerTag) { let kind = kind.expect("we set our STATIC_KIND so this cannot be None"); let alloc = alloc.into_owned(); - let (stacks, base_tag) = if !memory.extra.validate { + let (stacks, base_tag) = if !memory_extra.validate { (None, Tag::Untagged) } else { let (stacks, base_tag) = Stacks::new_allocation( id, Size::from_bytes(alloc.bytes.len() as u64), - Rc::clone(&memory.extra.stacked_borrows), + Rc::clone(&memory_extra.stacked_borrows), kind, ); (Some(stacks), base_tag) @@ -285,7 +285,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { assert!(alloc.relocations.is_empty(), "Only statics can come initialized with inner pointers"); // Now we can rely on the inner pointers being static, too. } - let mut memory_extra = memory.extra.stacked_borrows.borrow_mut(); + let mut stacked_borrows = memory_extra.stacked_borrows.borrow_mut(); let alloc: Allocation = Allocation { bytes: alloc.bytes, relocations: Relocations::from_presorted( @@ -293,10 +293,10 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { // The allocations in the relocations (pointers stored *inside* this allocation) // all get the base pointer tag. .map(|&(offset, ((), alloc))| { - let tag = if !memory.extra.validate { + let tag = if !memory_extra.validate { Tag::Untagged } else { - memory_extra.static_base_ptr(alloc) + stacked_borrows.static_base_ptr(alloc) }; (offset, (tag, alloc)) }) @@ -314,13 +314,13 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { #[inline(always)] fn tag_static_base_pointer( + memory_extra: &MemoryExtra, id: AllocId, - memory: &Memory<'mir, 'tcx, Self>, ) -> Self::PointerTag { - if !memory.extra.validate { + if !memory_extra.validate { Tag::Untagged } else { - memory.extra.stacked_borrows.borrow_mut().static_base_ptr(id) + memory_extra.stacked_borrows.borrow_mut().static_base_ptr(id) } } @@ -354,8 +354,8 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { } fn int_to_ptr( - int: u64, memory: &Memory<'mir, 'tcx, Self>, + int: u64, ) -> InterpResult<'tcx, Pointer> { if int == 0 { err!(InvalidNullPointerUsage) @@ -367,8 +367,8 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { } fn ptr_to_int( - ptr: Pointer, memory: &Memory<'mir, 'tcx, Self>, + ptr: Pointer, ) -> InterpResult<'tcx, u64> { if memory.extra.rng.is_none() { err!(ReadPointerAsBytes) From fbf3f5e0c97f1cf6fffeabb824327ab8cc9030d6 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 6 Jul 2019 09:52:28 +0200 Subject: [PATCH 0918/3747] bump rustc --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index e278a80633709..e70f05a0090dd 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -481068a707679257e2a738b40987246e0420e787 +b820c761744db080ff7a4ba3ac88d259065cb836 From 47bfc62b5be28d1861a15099787be20f83163dbc Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 5 Jul 2019 08:37:19 +0200 Subject: [PATCH 0919/3747] use Memory::read_c_str, avoid a few to_ptr --- src/shims/foreign_items.rs | 26 ++++++++++---------------- 1 file changed, 10 insertions(+), 16 deletions(-) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 9dbb55668ef35..41966c5f0d9cb 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -318,8 +318,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "dlsym" => { let _handle = this.read_scalar(args[0])?; - let symbol = this.read_scalar(args[1])?.to_ptr()?; - let symbol_name = this.memory().get(symbol.alloc_id)?.read_c_str(tcx, symbol)?; + let symbol = this.read_scalar(args[1])?.not_undef()?; + let symbol_name = this.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); if let Some(dlsym) = Dlsym::from_str(symbol_name)? { @@ -433,8 +433,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "getenv" => { let result = { - let name_ptr = this.read_scalar(args[0])?.to_ptr()?; - let name = this.memory().get(name_ptr.alloc_id)?.read_c_str(tcx, name_ptr)?; + let name_ptr = this.read_scalar(args[0])?.not_undef()?; + let name = this.memory().read_c_str(name_ptr)?; match this.machine.env_vars.get(name) { Some(&var) => Scalar::Ptr(var), None => Scalar::ptr_null(&*this.tcx), @@ -448,12 +448,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx { let name_ptr = this.read_scalar(args[0])?.not_undef()?; if !this.is_null(name_ptr)? { - let name_ptr = name_ptr.to_ptr()?; - let name = this - .memory() - .get(name_ptr.alloc_id)? - .read_c_str(tcx, name_ptr)? - .to_owned(); + let name = this.memory().read_c_str(name_ptr)?.to_owned(); if !name.is_empty() && !name.contains(&b'=') { success = Some(this.machine.env_vars.remove(&name)); } @@ -473,11 +468,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let mut new = None; { let name_ptr = this.read_scalar(args[0])?.not_undef()?; - let value_ptr = this.read_scalar(args[1])?.to_ptr()?; - let value = this.memory().get(value_ptr.alloc_id)?.read_c_str(tcx, value_ptr)?; + let value_ptr = this.read_scalar(args[1])?.not_undef()?; + let value = this.memory().read_c_str(value_ptr)?; if !this.is_null(name_ptr)? { - let name_ptr = name_ptr.to_ptr()?; - let name = this.memory().get(name_ptr.alloc_id)?.read_c_str(tcx, name_ptr)?; + let name = this.memory().read_c_str(name_ptr)?; if !name.is_empty() && !name.contains(&b'=') { new = Some((name.to_owned(), value.to_owned())); } @@ -552,8 +546,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "strlen" => { - let ptr = this.read_scalar(args[0])?.to_ptr()?; - let n = this.memory().get(ptr.alloc_id)?.read_c_str(tcx, ptr)?.len(); + let ptr = this.read_scalar(args[0])?.not_undef()?; + let n = this.memory().read_c_str(ptr)?.len(); this.write_scalar(Scalar::from_uint(n as u64, dest.layout.size), dest)?; } From 8f114e87b8ceebd034540137e57912530239e61c Mon Sep 17 00:00:00 2001 From: lzutao Date: Sat, 6 Jul 2019 16:16:34 +0700 Subject: [PATCH 0920/3747] Remove stable cargo feature `default-run` At least on beta. --- .appveyor.yml | 7 ++++--- .travis.yml | 6 +++--- Cargo.toml | 2 -- 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index 4e8b8cd4b898b..2cba0b55885ef 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -19,12 +19,13 @@ cache: install: # Install Rust - curl -sSf -o rustup-init.exe https://win.rustup.rs/ - - rustup-init.exe -y --default-host %TARGET% --default-toolchain stable + - rustup-init.exe -y --default-host %TARGET% --default-toolchain beta - set PATH=%USERPROFILE%\.cargo\bin;%PATH% + - rustup update beta # Install "master" toolchain - cargo install rustup-toolchain-install-master & exit 0 - set /p RUSTC_HASH="] description = "An experimental interpreter for Rust MIR." From 96be92401e828d52756a58fbb0579fe27dc9e616 Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Sat, 6 Jul 2019 16:35:57 +0700 Subject: [PATCH 0921/3747] build: Revert update beta toolchain --- .appveyor.yml | 7 +++---- .travis.yml | 6 +++--- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index 2cba0b55885ef..4e8b8cd4b898b 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -19,13 +19,12 @@ cache: install: # Install Rust - curl -sSf -o rustup-init.exe https://win.rustup.rs/ - - rustup-init.exe -y --default-host %TARGET% --default-toolchain beta + - rustup-init.exe -y --default-host %TARGET% --default-toolchain stable - set PATH=%USERPROFILE%\.cargo\bin;%PATH% - - rustup update beta # Install "master" toolchain - cargo install rustup-toolchain-install-master & exit 0 - set /p RUSTC_HASH= Date: Wed, 10 Jul 2019 09:55:04 +0700 Subject: [PATCH 0922/3747] Remove SliceConcatExt import --- src/shims/intrinsics.rs | 2 +- tests/compiletest.rs | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index d62e921695905..54f826db1fa83 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -5,7 +5,7 @@ use rustc::ty::layout::{self, LayoutOf, Size}; use rustc::ty; use crate::{ - PlaceTy, OpTy, ImmTy, Immediate, Scalar, ScalarMaybeUndef, Tag, + PlaceTy, OpTy, ImmTy, Immediate, Scalar, Tag, OperatorEvalContextExt }; diff --git a/tests/compiletest.rs b/tests/compiletest.rs index 076deca6a318c..4d799cdb542df 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -1,8 +1,7 @@ -#![feature(slice_concat_ext, custom_test_frameworks)] +#![feature(custom_test_frameworks)] // Custom test runner, to avoid libtest being wrapped around compiletest which wraps libtest. #![test_runner(test_runner)] -use std::slice::SliceConcatExt; use std::path::PathBuf; use std::env; From e414a5ac0e25fdd36fde06c72d1aa9f2bf983c08 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 10 Jul 2019 09:31:31 +0200 Subject: [PATCH 0923/3747] bump rustc --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index e70f05a0090dd..0a162e1928f4c 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -b820c761744db080ff7a4ba3ac88d259065cb836 +0b680cfce544ff9a59d720020e397c4bf3346650 From dd6cf30f6001339aa3d8fb1657521b772e06986a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 6 Jul 2019 11:05:51 +0200 Subject: [PATCH 0924/3747] ptr_offset works fine with intptrcast now --- tests/{run-pass-noseed => run-pass}/ptr_offset.rs | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename tests/{run-pass-noseed => run-pass}/ptr_offset.rs (100%) diff --git a/tests/run-pass-noseed/ptr_offset.rs b/tests/run-pass/ptr_offset.rs similarity index 100% rename from tests/run-pass-noseed/ptr_offset.rs rename to tests/run-pass/ptr_offset.rs From f79f31dfa18c234a3cc12c1c77fd00b045b4cd1a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 6 Jul 2019 13:14:06 +0200 Subject: [PATCH 0925/3747] adjust for rustc changes; normalize mplace before doing freeze-sensitive visit --- src/eval.rs | 2 +- src/helpers.rs | 25 +++++++++++-------------- src/shims/foreign_items.rs | 8 +------- src/shims/intrinsics.rs | 22 +++++++++++++--------- 4 files changed, 26 insertions(+), 31 deletions(-) diff --git a/src/eval.rs b/src/eval.rs index bf99d3e61166b..d40f4b3e59f64 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -136,7 +136,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( let place = ecx.mplace_field(argvs_place, idx as u64)?; ecx.write_scalar(Scalar::Ptr(arg), place.into())?; } - ecx.memory_mut().mark_immutable(argvs_place.to_ptr()?.alloc_id)?; + ecx.memory_mut().mark_immutable(argvs_place.ptr.assert_ptr().alloc_id)?; // Write a pointer to that place as the argument. let argv = argvs_place.ptr; ecx.write_scalar(argv, dest)?; diff --git a/src/helpers.rs b/src/helpers.rs index b9fa7bc2a77a4..fb4106e5db5cd 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -116,36 +116,33 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx .map(|(size, _)| size) .unwrap_or_else(|| place.layout.size) ); - assert!(size.bytes() > 0); + let place = this.normalize_mplace_ptr(place)?; // Store how far we proceeded into the place so far. Everything to the left of // this offset has already been handled, in the sense that the frozen parts // have had `action` called on them. - let mut end_ptr = place.ptr; + let mut end_ptr = place.ptr.assert_ptr(); // Called when we detected an `UnsafeCell` at the given offset and size. // Calls `action` and advances `end_ptr`. let mut unsafe_cell_action = |unsafe_cell_ptr: Scalar, unsafe_cell_size: Size| { - if unsafe_cell_size != Size::ZERO { - debug_assert_eq!(unsafe_cell_ptr.to_ptr().unwrap().alloc_id, - end_ptr.to_ptr().unwrap().alloc_id); - debug_assert_eq!(unsafe_cell_ptr.to_ptr().unwrap().tag, - end_ptr.to_ptr().unwrap().tag); - } + let unsafe_cell_ptr = unsafe_cell_ptr.assert_ptr(); + debug_assert_eq!(unsafe_cell_ptr.alloc_id, end_ptr.alloc_id); + debug_assert_eq!(unsafe_cell_ptr.tag, end_ptr.tag); // We assume that we are given the fields in increasing offset order, // and nothing else changes. - let unsafe_cell_offset = unsafe_cell_ptr.get_ptr_offset(this); - let end_offset = end_ptr.get_ptr_offset(this); + let unsafe_cell_offset = unsafe_cell_ptr.offset; + let end_offset = end_ptr.offset; assert!(unsafe_cell_offset >= end_offset); let frozen_size = unsafe_cell_offset - end_offset; // Everything between the end_ptr and this `UnsafeCell` is frozen. if frozen_size != Size::ZERO { - action(end_ptr.to_ptr()?, frozen_size, /*frozen*/true)?; + action(end_ptr, frozen_size, /*frozen*/true)?; } // This `UnsafeCell` is NOT frozen. if unsafe_cell_size != Size::ZERO { - action(unsafe_cell_ptr.to_ptr()?, unsafe_cell_size, /*frozen*/false)?; + action(unsafe_cell_ptr, unsafe_cell_size, /*frozen*/false)?; } // Update end end_ptr. - end_ptr = unsafe_cell_ptr.ptr_wrapping_offset(unsafe_cell_size, this); + end_ptr = unsafe_cell_ptr.wrapping_offset(unsafe_cell_size, this); // Done Ok(()) }; @@ -234,7 +231,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx layout::FieldPlacement::Arbitrary { .. } => { // Gather the subplaces and sort them before visiting. let mut places = fields.collect::>>>()?; - places.sort_by_key(|place| place.ptr.get_ptr_offset(self.ecx())); + places.sort_by_key(|place| place.ptr.assert_ptr().offset); self.walk_aggregate(place, places.into_iter().map(Ok)) } layout::FieldPlacement::Union { .. } => { diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 41966c5f0d9cb..fd46eaea9dab8 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -842,13 +842,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx }, "GetSystemInfo" => { let system_info = this.deref_operand(args[0])?; - let (system_info_ptr, align) = system_info.to_scalar_ptr_align(); - let system_info_ptr = this.memory() - .check_ptr_access( - system_info_ptr, - system_info.layout.size, - align, - )? + let system_info_ptr = this.check_mplace_access(system_info, None)? .expect("cannot be a ZST"); // Initialize with `0`. this.memory_mut().get_mut(system_info_ptr.alloc_id)? diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 54f826db1fa83..6038950bad9f6 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -166,17 +166,21 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let elem_size = elem_layout.size.bytes(); let count = this.read_scalar(args[2])?.to_usize(this)?; let elem_align = elem_layout.align.abi; - // erase tags: this is a raw ptr operation + + let size = Size::from_bytes(count * elem_size); let src = this.read_scalar(args[0])?.not_undef()?; + let src = this.memory().check_ptr_access(src, size, elem_align)?; let dest = this.read_scalar(args[1])?.not_undef()?; - this.memory_mut().copy( - src, - elem_align, - dest, - elem_align, - Size::from_bytes(count * elem_size), - intrinsic_name.ends_with("_nonoverlapping"), - )?; + let dest = this.memory().check_ptr_access(dest, size, elem_align)?; + + if let (Some(src), Some(dest)) = (src, dest) { + this.memory_mut().copy( + src, + dest, + size, + intrinsic_name.ends_with("_nonoverlapping"), + )?; + } } "discriminant_value" => { From a6f9bbc9e22be612849508552271e98bb0ae62bf Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 6 Jul 2019 13:16:54 +0200 Subject: [PATCH 0926/3747] now we can also enable the ptr_int_cast test again --- tests/{run-pass-noseed => run-pass}/ptr_int_casts.rs | 1 - tests/run-pass/ptr_offset.rs | 2 -- 2 files changed, 3 deletions(-) rename tests/{run-pass-noseed => run-pass}/ptr_int_casts.rs (94%) diff --git a/tests/run-pass-noseed/ptr_int_casts.rs b/tests/run-pass/ptr_int_casts.rs similarity index 94% rename from tests/run-pass-noseed/ptr_int_casts.rs rename to tests/run-pass/ptr_int_casts.rs index ebf65ac3fe246..c279024f35eab 100644 --- a/tests/run-pass-noseed/ptr_int_casts.rs +++ b/tests/run-pass/ptr_int_casts.rs @@ -1,4 +1,3 @@ -// FIXME move this to run-pass, it should work with intptrcast. use std::mem; use std::ptr; diff --git a/tests/run-pass/ptr_offset.rs b/tests/run-pass/ptr_offset.rs index a836e02812da7..1c7f0eb717974 100644 --- a/tests/run-pass/ptr_offset.rs +++ b/tests/run-pass/ptr_offset.rs @@ -1,5 +1,3 @@ -// FIXME move this to run-pass, it should work with intptrcast. - fn f() -> i32 { 42 } fn main() { From 70a5bb7dbbba69d9e2e813693063f8c2b651f66f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 6 Jul 2019 14:08:37 +0200 Subject: [PATCH 0927/3747] force pointers before reborrowing; fixes cargo miri test suite --- src/helpers.rs | 1 - src/stacked_borrows.rs | 1 + test-cargo-miri/run-test.py | 3 +-- tests/run-pass/{unique-send.rs => mpsc.rs} | 5 +++++ 4 files changed, 7 insertions(+), 3 deletions(-) rename tests/run-pass/{unique-send.rs => mpsc.rs} (57%) diff --git a/src/helpers.rs b/src/helpers.rs index fb4106e5db5cd..351a6e7e54a6f 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -116,7 +116,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx .map(|(size, _)| size) .unwrap_or_else(|| place.layout.size) ); - let place = this.normalize_mplace_ptr(place)?; // Store how far we proceeded into the place so far. Everything to the left of // this offset has already been handled, in the sense that the frozen parts // have had `action` called on them. diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index acd1aec5b770b..90656180150f1 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -587,6 +587,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Nothing to do for ZSTs. return Ok(*val); } + let place = this.force_mplace_ptr(place)?; // Compute new borrow. let new_tag = match kind { diff --git a/test-cargo-miri/run-test.py b/test-cargo-miri/run-test.py index a9aba008e9a92..73515c74e4010 100755 --- a/test-cargo-miri/run-test.py +++ b/test-cargo-miri/run-test.py @@ -52,9 +52,8 @@ def test_cargo_miri_run(): ) def test_cargo_miri_test(): - # FIXME: enable validation again, once that no longer conflicts with intptrcast test("cargo miri test", - cargo_miri("test") + ["--", "-Zmiri-seed=feed", "-Zmiri-disable-validation"], + cargo_miri("test") + ["--", "-Zmiri-seed=feed"], "test.stdout.ref", "test.stderr.ref" ) test("cargo miri test (with filter)", diff --git a/tests/run-pass/unique-send.rs b/tests/run-pass/mpsc.rs similarity index 57% rename from tests/run-pass/unique-send.rs rename to tests/run-pass/mpsc.rs index 04dbf495f8bfd..6e3c6e771ccb8 100644 --- a/tests/run-pass/unique-send.rs +++ b/tests/run-pass/mpsc.rs @@ -7,4 +7,9 @@ pub fn main() { tx.send(box 100).unwrap(); let v = rx.recv().unwrap(); assert_eq!(v, box 100); + + tx.send(box 101).unwrap(); + tx.send(box 102).unwrap(); + assert_eq!(rx.recv().unwrap(), box 101); + assert_eq!(rx.recv().unwrap(), box 102); } From 743299e7a04ee69ab00f8e92ff1c8dfec31ef1b8 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 10 Jul 2019 14:37:52 +0200 Subject: [PATCH 0928/3747] bump rustc --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 0a162e1928f4c..507fda7ac8519 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -0b680cfce544ff9a59d720020e397c4bf3346650 +d4e15655092d1bdae79619eb0ff2c3cb5468fc36 From 11686f4be23d4ee7a0490ab4d1fc593b46b1910a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 10 Jul 2019 14:38:49 +0200 Subject: [PATCH 0929/3747] we do this these days --- src/eval.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/eval.rs b/src/eval.rs index d40f4b3e59f64..dbc3282a306f8 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -108,7 +108,6 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( ecx.machine.argc = Some(argc_place.ptr.to_ptr()?); } - // FIXME: extract main source file path. // Third argument (`argv`): created from `config.args`. let dest = ecx.eval_place(&mir::Place::Base(mir::PlaceBase::Local(args.next().unwrap())))?; // For Windows, construct a command string with all the aguments. From 7dd0dd35691e0528a6f46013e61c8da4c5013cf5 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 11 Jul 2019 17:13:28 +0200 Subject: [PATCH 0930/3747] bump rust --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 507fda7ac8519..8650ea737fbee 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -d4e15655092d1bdae79619eb0ff2c3cb5468fc36 +97b1128589fdaa786a7cf65c5a6ff7ed37a1d2f3 From e7b39e382a71882546528693ea8ed8125580fcde Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 11 Jul 2019 18:41:53 +0200 Subject: [PATCH 0931/3747] reenable all tests on Windows --- src/eval.rs | 11 +---------- tests/compiletest.rs | 4 +--- 2 files changed, 2 insertions(+), 13 deletions(-) diff --git a/src/eval.rs b/src/eval.rs index dbc3282a306f8..faa50f9149168 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -31,20 +31,11 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( main_id: DefId, config: MiriConfig, ) -> InterpResult<'tcx, InterpCx<'mir, 'tcx, Evaluator<'tcx>>> { - - // FIXME(https://github.com/rust-lang/miri/pull/803): no validation on Windows. - let target_os = tcx.sess.target.target.target_os.to_lowercase(); - let validate = if target_os == "windows" { - false - } else { - config.validate - }; - let mut ecx = InterpCx::new( tcx.at(syntax::source_map::DUMMY_SP), ty::ParamEnv::reveal_all(), Evaluator::new(), - MemoryExtra::new(config.seed.map(StdRng::seed_from_u64), validate), + MemoryExtra::new(config.seed.map(StdRng::seed_from_u64), config.validate), ); let main_instance = ty::Instance::mono(ecx.tcx.tcx, main_id); diff --git a/tests/compiletest.rs b/tests/compiletest.rs index 4d799cdb542df..302c080a52eb6 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -111,9 +111,7 @@ fn run_pass_miri(opt: bool) { } fn compile_fail_miri(opt: bool) { - if !cfg!(windows) { // FIXME re-enable on Windows - compile_fail("tests/compile-fail", &get_target(), opt); - } + compile_fail("tests/compile-fail", &get_target(), opt); } fn test_runner(_tests: &[&()]) { From f8c6eb5e8c98d1ff623361d287c6e5af1943ba65 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 11 Jul 2019 18:59:11 +0200 Subject: [PATCH 0932/3747] thread creation error for Windows --- src/shims/foreign_items.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index fd46eaea9dab8..f7c6465a63637 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -725,8 +725,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_null(dest)?; } - // We don't support threading. - "pthread_create" => { + // We don't support threading. (Also for Windows.) + "pthread_create" | "CreateThread" => { return err!(Unimplemented(format!("Miri does not support threading"))); } From f1b623c31353818f8bf0abbab48249a2168e60c0 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 13 Jul 2019 10:23:40 +0200 Subject: [PATCH 0933/3747] test some const-generic-using methods --- tests/run-pass/arrays.rs | 17 +++++++++++++++++ tests/run-pass/arrays.stdout | 1 + 2 files changed, 18 insertions(+) create mode 100644 tests/run-pass/arrays.stdout diff --git a/tests/run-pass/arrays.rs b/tests/run-pass/arrays.rs index 469dde3091eb2..d374ccf25354a 100644 --- a/tests/run-pass/arrays.rs +++ b/tests/run-pass/arrays.rs @@ -33,6 +33,21 @@ fn slice_index() -> u8 { arr[5] } +fn eq() { + const N: usize = 16; + type Array = [u8; N]; + let array1: Array = [0; N]; + let array2: Array = [0; N]; + let array3: Array = [1; N]; + assert_eq!(array1, array2); + assert_ne!(array1, array3); +} + +fn debug() { + let array = [0u8, 42, 13, 71]; + println!("{:?}", array); +} + fn main() { assert_eq!(empty_array(), []); assert_eq!(index_unsafe(), 20); @@ -42,4 +57,6 @@ fn main() { assert_eq!(array_array(), [[5, 4], [3, 2], [1, 0]]); assert_eq!(array_repeat(), [42; 8]); assert_eq!(mini_array(), [42]); + eq(); + debug(); } diff --git a/tests/run-pass/arrays.stdout b/tests/run-pass/arrays.stdout new file mode 100644 index 0000000000000..6c3cefadf8035 --- /dev/null +++ b/tests/run-pass/arrays.stdout @@ -0,0 +1 @@ +[0, 42, 13, 71] From ebf65cbdab2f3d93e73f49cb0a8035d421b5c646 Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Sat, 13 Jul 2019 08:28:33 -0400 Subject: [PATCH 0934/3747] Give a useful error message if user gives invalid random seed --- src/bin/miri.rs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 5a425baf0f61f..0f28a0c5d8dca 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -17,6 +17,8 @@ extern crate syntax; use std::str::FromStr; use std::env; +use hex::FromHexError; + use rustc_interface::interface; use rustc::hir::def_id::LOCAL_CRATE; @@ -153,7 +155,14 @@ fn main() { if seed.is_some() { panic!("Cannot specify -Zmiri-seed multiple times!"); } - let seed_raw = hex::decode(arg.trim_start_matches("-Zmiri-seed=")).unwrap(); + let seed_raw = hex::decode(arg.trim_start_matches("-Zmiri-seed=")) + .unwrap_or_else(|err| match err { + FromHexError::InvalidHexCharacter { .. } => panic!( + "-Zmiri-seed should only contain valid hex digits [0-9a-fA-F]" + ), + FromHexError::OddLength => panic!("-Zmiri-seed should have an even number of digits"), + err => panic!("Unknown error decoding -Zmiri-seed as hex: {:?}", err), + }); if seed_raw.len() > 8 { panic!(format!("-Zmiri-seed must be at most 8 bytes, was {}", seed_raw.len())); } From a11d1f55ff14d7a1708f51e21771c8eb7bf44102 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 13 Jul 2019 15:18:15 +0200 Subject: [PATCH 0935/3747] avoid unnecessary allocation --- src/bin/miri.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 0f28a0c5d8dca..6e67246d2ca1d 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -184,10 +184,10 @@ fn main() { // FIXME: Ideally we'd turn a bad build env into a compile-time error, but // CTFE does not seem powerful enough for that yet. if let Some(sysroot) = compile_time_sysroot() { - let sysroot_flag = "--sysroot".to_string(); - if !rustc_args.contains(&sysroot_flag) { + let sysroot_flag = "--sysroot"; + if !rustc_args.iter().any(|e| e == sysroot_flag) { // We need to overwrite the default that librustc would compute. - rustc_args.push(sysroot_flag); + rustc_args.push(sysroot_flag.to_owned()); rustc_args.push(sysroot); } } From 4cbd31220bf710ecc917941fa7d836cad8d6eef0 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 14 Jul 2019 09:34:08 +0200 Subject: [PATCH 0936/3747] update README about what we do not support --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 69c66db52147e..9baaae568a297 100644 --- a/README.md +++ b/README.md @@ -38,8 +38,8 @@ cannot run all programs: * Miri runs the program as a platform-independent interpreter, so the program has no access to any platform-specific APIs or FFI. A few APIs have been implemented (such as printing to stdout) but most have not: for example, Miri - currently does not support concurrency, or networking, or file system access, - or gathering entropy from the system. + currently does not support concurrency, or SIMD, or networking, or file system + access. [rust]: https://www.rust-lang.org/ [mir]: https://github.com/rust-lang/rfcs/blob/master/text/1211-mir.md From 95e6e671bf2993ec51b778a0531bf393c575a7e0 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 16 Jul 2019 18:39:18 +0200 Subject: [PATCH 0937/3747] fix compile-fail tests for latest rustc --- rust-version | 2 +- tests/compile-fail/validity/dangling_ref1.rs | 2 +- tests/compile-fail/validity/dangling_ref2.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/rust-version b/rust-version index 8650ea737fbee..570ef6376272f 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -97b1128589fdaa786a7cf65c5a6ff7ed37a1d2f3 +d36b7f69448f7390fa9dfde75d58b914365acdab diff --git a/tests/compile-fail/validity/dangling_ref1.rs b/tests/compile-fail/validity/dangling_ref1.rs index 4318c7c90271f..2c1984b7159ce 100644 --- a/tests/compile-fail/validity/dangling_ref1.rs +++ b/tests/compile-fail/validity/dangling_ref1.rs @@ -1,5 +1,5 @@ use std::mem; fn main() { - let _x: &i32 = unsafe { mem::transmute(16usize) }; //~ ERROR integer pointer in non-ZST reference + let _x: &i32 = unsafe { mem::transmute(16usize) }; //~ ERROR dangling reference (created from integer) } diff --git a/tests/compile-fail/validity/dangling_ref2.rs b/tests/compile-fail/validity/dangling_ref2.rs index ef76b93d11e2d..0dc9c3a1826c3 100644 --- a/tests/compile-fail/validity/dangling_ref2.rs +++ b/tests/compile-fail/validity/dangling_ref2.rs @@ -3,5 +3,5 @@ use std::mem; fn main() { let val = 14; let ptr = (&val as *const i32).wrapping_offset(1); - let _x: &i32 = unsafe { mem::transmute(ptr) }; //~ ERROR encountered dangling (not entirely in bounds) reference + let _x: &i32 = unsafe { mem::transmute(ptr) }; //~ ERROR dangling reference (not entirely in bounds) } From 66ca0f2cc214368c1b4364a4dc941ec95a7b2d03 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 19 Jul 2019 17:36:25 +0200 Subject: [PATCH 0938/3747] fix for rustc_driver change --- benches/helpers/miri_helper.rs | 6 +++--- rust-version | 2 +- src/bin/miri.rs | 11 +++++------ 3 files changed, 9 insertions(+), 10 deletions(-) diff --git a/benches/helpers/miri_helper.rs b/benches/helpers/miri_helper.rs index 44a94cd61a0b4..203a8b1133a5c 100644 --- a/benches/helpers/miri_helper.rs +++ b/benches/helpers/miri_helper.rs @@ -8,6 +8,7 @@ extern crate test; use self::miri::eval_main; use rustc::hir::def_id::LOCAL_CRATE; use rustc_interface::interface; +use rustc_driver::Compilation; use crate::test::Bencher; struct MiriCompilerCalls<'a> { @@ -15,7 +16,7 @@ struct MiriCompilerCalls<'a> { } impl rustc_driver::Callbacks for MiriCompilerCalls<'_> { - fn after_analysis(&mut self, compiler: &interface::Compiler) -> bool { + fn after_analysis(&mut self, compiler: &interface::Compiler) -> Compilation { compiler.session().abort_if_errors(); compiler.global_ctxt().unwrap().peek_mut().enter(|tcx| { @@ -31,8 +32,7 @@ impl rustc_driver::Callbacks for MiriCompilerCalls<'_> { compiler.session().abort_if_errors(); - // Don't continue execution - false + Compilation::Stop } } diff --git a/rust-version b/rust-version index 570ef6376272f..9ee662c00cb31 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -d36b7f69448f7390fa9dfde75d58b914365acdab +527dce7137f7a3c7bf47d9a503abf25f88ea22de diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 6e67246d2ca1d..43cb19b2658ef 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -21,24 +21,24 @@ use hex::FromHexError; use rustc_interface::interface; use rustc::hir::def_id::LOCAL_CRATE; +use rustc_driver::Compilation; struct MiriCompilerCalls { miri_config: miri::MiriConfig, } impl rustc_driver::Callbacks for MiriCompilerCalls { - fn after_parsing(&mut self, compiler: &interface::Compiler) -> bool { + fn after_parsing(&mut self, compiler: &interface::Compiler) -> Compilation { let attr = ( syntax::symbol::Symbol::intern("miri"), syntax::feature_gate::AttributeType::Whitelisted, ); compiler.session().plugin_attributes.borrow_mut().push(attr); - // Continue execution - true + Compilation::Continue } - fn after_analysis(&mut self, compiler: &interface::Compiler) -> bool { + fn after_analysis(&mut self, compiler: &interface::Compiler) -> Compilation { init_late_loggers(); compiler.session().abort_if_errors(); @@ -54,8 +54,7 @@ impl rustc_driver::Callbacks for MiriCompilerCalls { compiler.session().abort_if_errors(); - // Don't continue execution - false + Compilation::Stop } } From 11d71195dd73f779cd020dd4811f1ed348f55988 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 19 Jul 2019 18:03:55 +0200 Subject: [PATCH 0939/3747] fix miri-rustc-tests --- src/bin/miri-rustc-tests.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/bin/miri-rustc-tests.rs b/src/bin/miri-rustc-tests.rs index 9b0d02f4b7e29..dae5189937a33 100644 --- a/src/bin/miri-rustc-tests.rs +++ b/src/bin/miri-rustc-tests.rs @@ -19,6 +19,7 @@ use rustc_interface::interface; use rustc::hir::{self, itemlikevisit}; use rustc::ty::TyCtxt; use rustc::hir::def_id::LOCAL_CRATE; +use rustc_driver::Compilation; use miri::MiriConfig; @@ -28,18 +29,17 @@ struct MiriCompilerCalls { } impl rustc_driver::Callbacks for MiriCompilerCalls { - fn after_parsing(&mut self, compiler: &interface::Compiler) -> bool { + fn after_parsing(&mut self, compiler: &interface::Compiler) -> Compilation { let attr = ( syntax::symbol::Symbol::intern("miri"), syntax::feature_gate::AttributeType::Whitelisted, ); compiler.session().plugin_attributes.borrow_mut().push(attr); - // Continue execution - true + Compilation::Continue } - fn after_analysis(&mut self, compiler: &interface::Compiler) -> bool { + fn after_analysis(&mut self, compiler: &interface::Compiler) -> Compilation { compiler.session().abort_if_errors(); compiler.global_ctxt().unwrap().peek_mut().enter(|tcx| { if std::env::args().any(|arg| arg == "--test") { @@ -71,7 +71,7 @@ impl rustc_driver::Callbacks for MiriCompilerCalls { }); // Continue execution on host target - self.host_target + if self.host_target { Compilation::Continue } else { Compilation::Stop } } } From 59190e85429a18a88d8155eb0e3f8c1ff1d5a123 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 20 Jul 2019 22:38:41 +0200 Subject: [PATCH 0940/3747] disable some compile-fail tests for rustc --- .../copy_nonoverlapping.rs | 0 tests/{compile-fail => compile-fail-norustc}/copy_null.rs | 0 .../copy_unaligned.rs | 0 tests/compiletest.rs | 7 +++++++ 4 files changed, 7 insertions(+) rename tests/{compile-fail => compile-fail-norustc}/copy_nonoverlapping.rs (100%) rename tests/{compile-fail => compile-fail-norustc}/copy_null.rs (100%) rename tests/{compile-fail => compile-fail-norustc}/copy_unaligned.rs (100%) diff --git a/tests/compile-fail/copy_nonoverlapping.rs b/tests/compile-fail-norustc/copy_nonoverlapping.rs similarity index 100% rename from tests/compile-fail/copy_nonoverlapping.rs rename to tests/compile-fail-norustc/copy_nonoverlapping.rs diff --git a/tests/compile-fail/copy_null.rs b/tests/compile-fail-norustc/copy_null.rs similarity index 100% rename from tests/compile-fail/copy_null.rs rename to tests/compile-fail-norustc/copy_null.rs diff --git a/tests/compile-fail/copy_unaligned.rs b/tests/compile-fail-norustc/copy_unaligned.rs similarity index 100% rename from tests/compile-fail/copy_unaligned.rs rename to tests/compile-fail-norustc/copy_unaligned.rs diff --git a/tests/compiletest.rs b/tests/compiletest.rs index 302c080a52eb6..16311d0749b3d 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -112,6 +112,13 @@ fn run_pass_miri(opt: bool) { fn compile_fail_miri(opt: bool) { compile_fail("tests/compile-fail", &get_target(), opt); + if rustc_test_suite().is_none() { + // FIXME: Some tests disabled in rustc test suite because + // they run with a debug-assertion libstd which changes the errors. + // We should build our own libstd for testing, see + // . + compile_fail("tests/compile-fail-norustc", &get_target(), opt); + } } fn test_runner(_tests: &[&()]) { From a2541aacd6b44ae2bd90cbaa0a0c4f4bcd4a62d1 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 21 Jul 2019 11:56:10 +0200 Subject: [PATCH 0941/3747] bump rust --- rust-version | 2 +- src/eval.rs | 9 ++++----- src/helpers.rs | 8 ++++++++ src/machine.rs | 4 ++-- src/shims/foreign_items.rs | 2 +- src/shims/tls.rs | 4 ++-- 6 files changed, 18 insertions(+), 11 deletions(-) diff --git a/rust-version b/rust-version index 9ee662c00cb31..b247139d09b36 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -527dce7137f7a3c7bf47d9a503abf25f88ea22de +1301422a6c2e8916560b8cc2f0564f38d8858a75 diff --git a/src/eval.rs b/src/eval.rs index faa50f9149168..cde4da833e6ca 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -7,12 +7,11 @@ use syntax::source_map::DUMMY_SP; use rustc::ty::{self, TyCtxt}; use rustc::ty::layout::{LayoutOf, Size, Align}; use rustc::hir::def_id::DefId; -use rustc::mir; use crate::{ InterpResult, InterpError, InterpCx, StackPopCleanup, struct_error, Scalar, Tag, Pointer, FnVal, - MemoryExtra, MiriMemoryKind, Evaluator, TlsEvalContextExt, + MemoryExtra, MiriMemoryKind, Evaluator, TlsEvalContextExt, HelpersEvalContextExt, }; /// Configuration needed to spawn a Miri instance. @@ -85,11 +84,11 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( // First argument: pointer to `main()`. let main_ptr = ecx.memory_mut().create_fn_alloc(FnVal::Instance(main_instance)); - let dest = ecx.eval_place(&mir::Place::Base(mir::PlaceBase::Local(args.next().unwrap())))?; + let dest = ecx.local_place(args.next().unwrap())?; ecx.write_scalar(Scalar::Ptr(main_ptr), dest)?; // Second argument (argc): `1`. - let dest = ecx.eval_place(&mir::Place::Base(mir::PlaceBase::Local(args.next().unwrap())))?; + let dest = ecx.local_place(args.next().unwrap())?; let argc = Scalar::from_uint(config.args.len() as u128, dest.layout.size); ecx.write_scalar(argc, dest)?; // Store argc for macOS's `_NSGetArgc`. @@ -100,7 +99,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( } // Third argument (`argv`): created from `config.args`. - let dest = ecx.eval_place(&mir::Place::Base(mir::PlaceBase::Local(args.next().unwrap())))?; + let dest = ecx.local_place(args.next().unwrap())?; // For Windows, construct a command string with all the aguments. let mut cmd = String::new(); for arg in config.args.iter() { diff --git a/src/helpers.rs b/src/helpers.rs index 351a6e7e54a6f..19abbd6b8193b 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -2,6 +2,7 @@ use std::mem; use rustc::ty::{self, layout::{self, Size, Align}}; use rustc::hir::def_id::{DefId, CRATE_DEF_INDEX}; +use rustc::mir; use rand::RngCore; @@ -67,6 +68,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx }) } + /// Get the `Place` for a local + fn local_place(&mut self, local: mir::Local) -> InterpResult<'tcx, PlaceTy<'tcx, Tag>> { + let this = self.eval_context_mut(); + let place = mir::Place { base: mir::PlaceBase::Local(local), projection: None }; + this.eval_place(&place) + } + /// Generate some random bytes, and write them to `dest`. fn gen_random( &mut self, diff --git a/src/machine.rs b/src/machine.rs index d1cf913a75bfd..c2e78024105da 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -214,12 +214,12 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { // First argument: `size`. // (`0` is allowed here -- this is expected to be handled by the lang item). - let arg = ecx.eval_place(&mir::Place::Base(mir::PlaceBase::Local(args.next().unwrap())))?; + let arg = ecx.local_place(args.next().unwrap())?; let size = layout.size.bytes(); ecx.write_scalar(Scalar::from_uint(size, arg.layout.size), arg)?; // Second argument: `align`. - let arg = ecx.eval_place(&mir::Place::Base(mir::PlaceBase::Local(args.next().unwrap())))?; + let arg = ecx.local_place(args.next().unwrap())?; let align = layout.align.abi.bytes(); ecx.write_scalar(Scalar::from_uint(align, arg.layout.size), arg)?; diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index f7c6465a63637..1deaf521ca66f 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -365,7 +365,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx .to_owned(), ), )?; - let arg_dest = this.eval_place(&mir::Place::Base(mir::PlaceBase::Local(arg_local)))?; + let arg_dest = this.local_place(arg_local)?; this.write_scalar(data, arg_dest)?; assert!(args.next().is_none(), "__rust_maybe_catch_panic argument has more arguments than expected"); diff --git a/src/shims/tls.rs b/src/shims/tls.rs index e2f2dab518058..abe6dd958693c 100644 --- a/src/shims/tls.rs +++ b/src/shims/tls.rs @@ -3,7 +3,7 @@ use std::collections::BTreeMap; use rustc_target::abi::LayoutOf; -use rustc::{ty, ty::layout::HasDataLayout, mir}; +use rustc::{ty, ty::layout::HasDataLayout}; use crate::{ InterpResult, InterpError, StackPopCleanup, @@ -160,7 +160,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let arg_local = this.frame().body.args_iter().next().ok_or_else( || InterpError::AbiViolation("TLS dtor does not take enough arguments.".to_owned()), )?; - let dest = this.eval_place(&mir::Place::Base(mir::PlaceBase::Local(arg_local)))?; + let dest = this.local_place(arg_local)?; this.write_scalar(ptr, dest)?; // step until out of stackframes From 068517ae66a41052dea2c86c88fc10794304622d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 23 Jul 2019 21:38:53 +0200 Subject: [PATCH 0942/3747] make sure we always have an RNG --- README.md | 8 ++-- src/eval.rs | 2 +- src/helpers.rs | 23 +++------- src/intptrcast.rs | 6 ++- src/machine.rs | 25 ++++------- src/operator.rs | 107 +++------------------------------------------- 6 files changed, 30 insertions(+), 141 deletions(-) diff --git a/README.md b/README.md index 9baaae568a297..fbd1f51c9e697 100644 --- a/README.md +++ b/README.md @@ -262,10 +262,10 @@ With this, you should now have a working development setup! See Several `-Z` flags are relevant for Miri: -* `-Zmiri-seed=` is a custom `-Z` flag added by Miri. It enables the - interpreted program to seed an RNG with system entropy. Miri will keep an RNG - on its own that is seeded with the given seed, and use that to generate the - "system entropy" that seeds the RNG(s) in the interpreted program. +* `-Zmiri-seed=` is a custom `-Z` flag added by Miri. It configures the + seed of the RNG that Miri uses to resolve non-determinism. This RNG is used + to pick base addresses for allocations, and when the interpreted program + requests system entropy. The default seed is 0. **NOTE**: This entropy is not good enough for cryptographic use! Do not generate secret keys in Miri or perform other kinds of cryptographic operations that rely on proper random numbers. diff --git a/src/eval.rs b/src/eval.rs index cde4da833e6ca..83307c99f9c59 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -34,7 +34,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( tcx.at(syntax::source_map::DUMMY_SP), ty::ParamEnv::reveal_all(), Evaluator::new(), - MemoryExtra::new(config.seed.map(StdRng::seed_from_u64), config.validate), + MemoryExtra::new(StdRng::seed_from_u64(config.seed.unwrap_or(0)), config.validate), ); let main_instance = ty::Instance::mono(ecx.tcx.tcx, main_id); diff --git a/src/helpers.rs b/src/helpers.rs index 19abbd6b8193b..3857020a71f81 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -88,25 +88,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx None => return Ok(()), // zero-sized access }; - let data = match &mut this.memory_mut().extra.rng { - Some(rng) => { - let mut rng = rng.borrow_mut(); - let mut data = vec![0; len]; - rng.fill_bytes(&mut data); - data - } - None => { - return err!(Unimplemented( - "miri does not support gathering system entropy in deterministic mode! - Use '-Zmiri-seed=' to enable random number generation. - WARNING: Miri does *not* generate cryptographically secure entropy - - do not use Miri to run any program that needs secure random number generation".to_owned(), - )); - } - }; + let rng = this.memory_mut().extra.rng.get_mut(); + let mut data = vec![0; len]; + rng.fill_bytes(&mut data); + let tcx = &{this.tcx.tcx}; - this.memory_mut().get_mut(ptr.alloc_id)? - .write_bytes(tcx, ptr, &data) + this.memory_mut().get_mut(ptr.alloc_id)?.write_bytes(tcx, ptr, &data) } /// Visits the memory covered by `place`, sensitive to freezing: the 3rd parameter diff --git a/src/intptrcast.rs b/src/intptrcast.rs index 5797895c54f80..8fbf7ed76427f 100644 --- a/src/intptrcast.rs +++ b/src/intptrcast.rs @@ -42,6 +42,10 @@ impl<'mir, 'tcx> GlobalState { int: u64, memory: &Memory<'mir, 'tcx, Evaluator<'tcx>>, ) -> InterpResult<'tcx, Pointer> { + if int == 0 { + return err!(InvalidNullPointerUsage); + } + let global_state = memory.extra.intptrcast.borrow(); match global_state.int_to_ptr_map.binary_search_by_key(&int, |(addr, _)| *addr) { @@ -86,7 +90,7 @@ impl<'mir, 'tcx> GlobalState { // This allocation does not have a base address yet, pick one. // Leave some space to the previous allocation, to give it some chance to be less aligned. let slack = { - let mut rng = memory.extra.rng.as_ref().unwrap().borrow_mut(); + let mut rng = memory.extra.rng.borrow_mut(); // This means that `(global_state.next_base_addr + slack) % 16` is uniformly distributed. rng.gen_range(0, 16) }; diff --git a/src/machine.rs b/src/machine.rs index c2e78024105da..d50afec253e80 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -57,20 +57,19 @@ pub struct MemoryExtra { pub stacked_borrows: stacked_borrows::MemoryExtra, pub intptrcast: intptrcast::MemoryExtra, - /// The random number generator to use if Miri is running in non-deterministic mode and to - /// enable intptrcast - pub(crate) rng: Option>, + /// The random number generator used for resolving non-determinism. + pub(crate) rng: RefCell, /// Whether to enforce the validity invariant. pub(crate) validate: bool, } impl MemoryExtra { - pub fn new(rng: Option, validate: bool) -> Self { + pub fn new(rng: StdRng, validate: bool) -> Self { MemoryExtra { stacked_borrows: Default::default(), intptrcast: Default::default(), - rng: rng.map(RefCell::new), + rng: RefCell::new(rng), validate, } } @@ -353,28 +352,20 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { Ok(ecx.memory().extra.stacked_borrows.borrow_mut().end_call(extra)) } + #[inline(always)] fn int_to_ptr( memory: &Memory<'mir, 'tcx, Self>, int: u64, ) -> InterpResult<'tcx, Pointer> { - if int == 0 { - err!(InvalidNullPointerUsage) - } else if memory.extra.rng.is_none() { - err!(ReadBytesAsPointer) - } else { - intptrcast::GlobalState::int_to_ptr(int, memory) - } + intptrcast::GlobalState::int_to_ptr(int, memory) } + #[inline(always)] fn ptr_to_int( memory: &Memory<'mir, 'tcx, Self>, ptr: Pointer, ) -> InterpResult<'tcx, u64> { - if memory.extra.rng.is_none() { - err!(ReadPointerAsBytes) - } else { - intptrcast::GlobalState::ptr_to_int(ptr, memory) - } + intptrcast::GlobalState::ptr_to_int(ptr, memory) } } diff --git a/src/operator.rs b/src/operator.rs index df60acc661ed4..5eeed5eac635d 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -56,8 +56,8 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { trace!("ptr_op: {:?} {:?} {:?}", *left, bin_op, *right); - // If intptrcast is enabled, treat everything of integer *type* at integer *value*. - if self.memory().extra.rng.is_some() && left.layout.ty.is_integral() { + // Treat everything of integer *type* at integer *value*. + if left.layout.ty.is_integral() { // This is actually an integer operation, so dispatch back to the core engine. // TODO: Once intptrcast is the default, librustc_mir should never even call us // for integer types. @@ -188,104 +188,11 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { right: Scalar, ) -> InterpResult<'tcx, bool> { let size = self.pointer_size(); - if self.memory().extra.rng.is_some() { - // Just compare the integers. - // TODO: Do we really want to *always* do that, even when comparing two live in-bounds pointers? - let left = self.force_bits(left, size)?; - let right = self.force_bits(right, size)?; - return Ok(left == right); - } - Ok(match (left, right) { - (Scalar::Raw { .. }, Scalar::Raw { .. }) => - left.to_bits(size)? == right.to_bits(size)?, - (Scalar::Ptr(left), Scalar::Ptr(right)) => { - // Comparison illegal if one of them is out-of-bounds, *unless* they - // are in the same allocation. - if left.alloc_id == right.alloc_id { - left.offset == right.offset - } else { - // Make sure both pointers are in-bounds. - // This accepts one-past-the end. Thus, there is still technically - // some non-determinism that we do not fully rule out when two - // allocations sit right next to each other. The C/C++ standards are - // somewhat fuzzy about this case, so pragmatically speaking I think - // for now this check is "good enough". - // FIXME: Once we support intptrcast, we could try to fix these holes. - // Dead allocations in miri cannot overlap with live allocations, but - // on read hardware this can easily happen. Thus for comparisons we require - // both pointers to be live. - if self.pointer_inbounds(left).is_ok() && self.pointer_inbounds(right).is_ok() { - // Two in-bounds (and hence live) pointers in different allocations are different. - false - } else { - return err!(InvalidPointerMath); - } - } - } - // Comparing ptr and integer. - (Scalar::Ptr(ptr), Scalar::Raw { data, size }) | - (Scalar::Raw { data, size }, Scalar::Ptr(ptr)) => { - assert_eq!(size as u64, self.pointer_size().bytes()); - let bits = data as u64; - - // Case I: Comparing real pointers with "small" integers. - // Really we should only do this for NULL, but pragmatically speaking on non-bare-metal systems, - // an allocation will never be at the very bottom of the address space. - // Such comparisons can arise when comparing empty slices, which sometimes are "fake" - // integer pointers (okay because the slice is empty) and sometimes point into a - // real allocation. - // The most common source of such integer pointers is `NonNull::dangling()`, which - // equals the type's alignment. i128 might have an alignment of 16 bytes, but few types have - // alignment 32 or higher, hence the limit of 32. - // FIXME: Once we support intptrcast, we could try to fix these holes. - if bits < 32 { - // Test if the pointer can be different from NULL or not. - // We assume that pointers that are not NULL are also not "small". - if !self.memory().ptr_may_be_null(ptr) { - return Ok(false); - } - } - - let (alloc_size, alloc_align) = self.memory() - .get_size_and_align(ptr.alloc_id, AllocCheck::MaybeDead) - .expect("alloc info with MaybeDead cannot fail"); - - // Case II: Alignment gives it away - if ptr.offset.bytes() % alloc_align.bytes() == 0 { - // The offset maintains the allocation alignment, so we know `base+offset` - // is aligned by `alloc_align`. - // FIXME: We could be even more general, e.g., offset 2 into a 4-aligned - // allocation cannot equal 3. - if bits % alloc_align.bytes() != 0 { - // The integer is *not* aligned. So they cannot be equal. - return Ok(false); - } - } - // Case III: The integer is too big, and the allocation goes on a bit - // without wrapping around the address space. - { - // Compute the highest address at which this allocation could live. - // Substract one more, because it must be possible to add the size - // to the base address without overflowing; that is, the very last address - // of the address space is never dereferencable (but it can be in-bounds, i.e., - // one-past-the-end). - let max_base_addr = - ((1u128 << self.pointer_size().bits()) - - u128::from(alloc_size.bytes()) - - 1 - ) as u64; - if let Some(max_addr) = max_base_addr.checked_add(ptr.offset.bytes()) { - if bits > max_addr { - // The integer is too big, this cannot possibly be equal. - return Ok(false) - } - } - } - - // None of the supported cases. - return err!(InvalidPointerMath); - } - }) + // Just compare the integers. + // TODO: Do we really want to *always* do that, even when comparing two live in-bounds pointers? + let left = self.force_bits(left, size)?; + let right = self.force_bits(right, size)?; + Ok(left == right) } fn ptr_int_arithmetic( From c094d42504c41ebd4e452542f3fa2cbc303fc975 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 23 Jul 2019 21:53:47 +0200 Subject: [PATCH 0943/3747] update miri-seed handling for run-pass test suite --- tests/compiletest.rs | 8 ++------ tests/{run-pass-noseed => run-pass}/hashmap.rs | 2 -- tests/{run-pass-noseed => run-pass}/heap_allocator.rs | 1 - tests/{run-pass-noseed => run-pass}/intptrcast.rs | 2 -- tests/{run-pass-noseed => run-pass}/malloc.rs | 1 - 5 files changed, 2 insertions(+), 12 deletions(-) rename tests/{run-pass-noseed => run-pass}/hashmap.rs (95%) rename tests/{run-pass-noseed => run-pass}/heap_allocator.rs (99%) rename tests/{run-pass-noseed => run-pass}/intptrcast.rs (94%) rename tests/{run-pass-noseed => run-pass}/malloc.rs (97%) diff --git a/tests/compiletest.rs b/tests/compiletest.rs index 16311d0749b3d..9394084ad34dc 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -68,7 +68,7 @@ fn compile_fail(path: &str, target: &str, opt: bool) { run_tests("compile-fail", path, target, flags); } -fn miri_pass(path: &str, target: &str, opt: bool, noseed: bool) { +fn miri_pass(path: &str, target: &str, opt: bool) { let opt_str = if opt { " with optimizations" } else { "" }; eprintln!("{}", format!( "## Running run-pass tests in {} against miri for target {}{}", @@ -80,9 +80,6 @@ fn miri_pass(path: &str, target: &str, opt: bool, noseed: bool) { let mut flags = Vec::new(); if opt { flags.push("-Zmir-opt-level=3".to_owned()); - } else if !noseed { - // Run with intptrcast. Avoid test matrix explosion by doing either this or opt-level=3. - flags.push("-Zmiri-seed=".to_owned()); } run_tests("ui", path, target, flags); @@ -106,8 +103,7 @@ fn get_target() -> String { } fn run_pass_miri(opt: bool) { - miri_pass("tests/run-pass", &get_target(), opt, false); - miri_pass("tests/run-pass-noseed", &get_target(), opt, true); + miri_pass("tests/run-pass", &get_target(), opt); } fn compile_fail_miri(opt: bool) { diff --git a/tests/run-pass-noseed/hashmap.rs b/tests/run-pass/hashmap.rs similarity index 95% rename from tests/run-pass-noseed/hashmap.rs rename to tests/run-pass/hashmap.rs index e249238d48cbf..1ff9c26ba18c7 100644 --- a/tests/run-pass-noseed/hashmap.rs +++ b/tests/run-pass/hashmap.rs @@ -1,5 +1,3 @@ -// compile-flags: -Zmiri-seed=0000000000000000 - use std::collections::{self, HashMap}; use std::hash::{BuildHasherDefault, BuildHasher}; diff --git a/tests/run-pass-noseed/heap_allocator.rs b/tests/run-pass/heap_allocator.rs similarity index 99% rename from tests/run-pass-noseed/heap_allocator.rs rename to tests/run-pass/heap_allocator.rs index e7a609a7d98e9..7bcb08058c36a 100644 --- a/tests/run-pass-noseed/heap_allocator.rs +++ b/tests/run-pass/heap_allocator.rs @@ -1,4 +1,3 @@ -// compile-flags: -Zmiri-seed= #![feature(allocator_api)] use std::ptr::NonNull; diff --git a/tests/run-pass-noseed/intptrcast.rs b/tests/run-pass/intptrcast.rs similarity index 94% rename from tests/run-pass-noseed/intptrcast.rs rename to tests/run-pass/intptrcast.rs index 1b5251c91119a..c28958b872de2 100644 --- a/tests/run-pass-noseed/intptrcast.rs +++ b/tests/run-pass/intptrcast.rs @@ -1,5 +1,3 @@ -// compile-flags: -Zmiri-seed=0000000000000000 - // This returns a miri pointer at type usize, if the argument is a proper pointer fn transmute_ptr_to_int(x: *const T) -> usize { unsafe { std::mem::transmute(x) } diff --git a/tests/run-pass-noseed/malloc.rs b/tests/run-pass/malloc.rs similarity index 97% rename from tests/run-pass-noseed/malloc.rs rename to tests/run-pass/malloc.rs index bf51baacd35a9..f66263425ee86 100644 --- a/tests/run-pass-noseed/malloc.rs +++ b/tests/run-pass/malloc.rs @@ -1,5 +1,4 @@ //ignore-windows: Uses POSIX APIs -//compile-flags: -Zmiri-seed= #![feature(rustc_private)] From 3c1ab7819698b374d833e8818e39ef011a48eb83 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 23 Jul 2019 23:25:06 +0200 Subject: [PATCH 0944/3747] review failing compile-fail tests --- tests/compile-fail/cast_box_int_to_fn_ptr.rs | 4 +- tests/compile-fail/cast_int_to_fn_ptr.rs | 2 +- tests/compile-fail/getrandom.rs | 13 ---- ...er_byte_read_2.rs => pointer_byte_read.rs} | 0 tests/compile-fail/pointer_byte_read_1.rs | 7 -- tests/compile-fail/ptr_bitops1.rs | 7 -- tests/compile-fail/ptr_bitops2.rs | 5 -- tests/compile-fail/ptr_eq_dangling.rs | 10 --- tests/compile-fail/ptr_eq_integer.rs | 6 -- tests/compile-fail/ptr_eq_out_of_bounds.rs | 9 --- .../compile-fail/ptr_eq_out_of_bounds_null.rs | 6 -- tests/compile-fail/ptr_int_cast.rs | 8 --- tests/compile-fail/ptr_offset_int_plus_int.rs | 2 +- tests/compile-fail/ptr_offset_int_plus_ptr.rs | 2 +- tests/compile-fail/ptr_rem.rs | 5 -- .../ptr_wrapping_offset_int_plus_ptr.rs | 8 --- tests/compile-fail/validity/dangling_ref1.rs | 2 +- tests/compile-fail/wild_pointer_deref.rs | 2 +- .../bitop-beyond-alignment.rs | 2 +- tests/run-pass/intptrcast.rs | 67 ++++++++++++++++++- 20 files changed, 74 insertions(+), 93 deletions(-) delete mode 100644 tests/compile-fail/getrandom.rs rename tests/compile-fail/{pointer_byte_read_2.rs => pointer_byte_read.rs} (100%) delete mode 100644 tests/compile-fail/pointer_byte_read_1.rs delete mode 100644 tests/compile-fail/ptr_bitops1.rs delete mode 100644 tests/compile-fail/ptr_bitops2.rs delete mode 100644 tests/compile-fail/ptr_eq_dangling.rs delete mode 100644 tests/compile-fail/ptr_eq_integer.rs delete mode 100644 tests/compile-fail/ptr_eq_out_of_bounds.rs delete mode 100644 tests/compile-fail/ptr_eq_out_of_bounds_null.rs delete mode 100644 tests/compile-fail/ptr_int_cast.rs delete mode 100644 tests/compile-fail/ptr_rem.rs delete mode 100644 tests/compile-fail/ptr_wrapping_offset_int_plus_ptr.rs rename tests/{compile-fail => run-pass}/bitop-beyond-alignment.rs (87%) diff --git a/tests/compile-fail/cast_box_int_to_fn_ptr.rs b/tests/compile-fail/cast_box_int_to_fn_ptr.rs index 7ee3bc62767fb..6dad2a4727306 100644 --- a/tests/compile-fail/cast_box_int_to_fn_ptr.rs +++ b/tests/compile-fail/cast_box_int_to_fn_ptr.rs @@ -4,8 +4,8 @@ fn main() { let b = Box::new(42); let g = unsafe { - std::mem::transmute::<&usize, &fn(i32)>(&b) + std::mem::transmute::<&Box, &fn(i32)>(&b) }; - (*g)(42) //~ ERROR a memory access tried to interpret some bytes as a pointer + (*g)(42) //~ ERROR tried to treat a memory pointer as a function pointer } diff --git a/tests/compile-fail/cast_int_to_fn_ptr.rs b/tests/compile-fail/cast_int_to_fn_ptr.rs index 207af4ae2cefb..4fd14751a279a 100644 --- a/tests/compile-fail/cast_int_to_fn_ptr.rs +++ b/tests/compile-fail/cast_int_to_fn_ptr.rs @@ -6,5 +6,5 @@ fn main() { std::mem::transmute::(42) }; - g(42) //~ ERROR a memory access tried to interpret some bytes as a pointer + g(42) //~ ERROR dangling pointer was dereferenced } diff --git a/tests/compile-fail/getrandom.rs b/tests/compile-fail/getrandom.rs deleted file mode 100644 index 246893a5c640f..0000000000000 --- a/tests/compile-fail/getrandom.rs +++ /dev/null @@ -1,13 +0,0 @@ -// ignore-macos: Uses Linux-only APIs -// ignore-windows: Uses Linux-only APIs - -#![feature(rustc_private)] -extern crate libc; - -fn main() { - let mut buf = [0u8; 5]; - unsafe { - libc::syscall(libc::SYS_getrandom, buf.as_mut_ptr() as *mut libc::c_void, 5 as libc::size_t, 0 as libc::c_uint); - //~^ ERROR miri does not support gathering system entropy in deterministic mode! - } -} diff --git a/tests/compile-fail/pointer_byte_read_2.rs b/tests/compile-fail/pointer_byte_read.rs similarity index 100% rename from tests/compile-fail/pointer_byte_read_2.rs rename to tests/compile-fail/pointer_byte_read.rs diff --git a/tests/compile-fail/pointer_byte_read_1.rs b/tests/compile-fail/pointer_byte_read_1.rs deleted file mode 100644 index a584863654cef..0000000000000 --- a/tests/compile-fail/pointer_byte_read_1.rs +++ /dev/null @@ -1,7 +0,0 @@ -fn main() { - let x = 13; - let y = &x; - let z = &y as *const &i32 as *const usize; - let ptr_bytes = unsafe { *z }; // the actual deref is fine, because we read the entire pointer at once - let _val = ptr_bytes / 432; //~ ERROR invalid arithmetic on pointers that would leak base addresses -} diff --git a/tests/compile-fail/ptr_bitops1.rs b/tests/compile-fail/ptr_bitops1.rs deleted file mode 100644 index 2706b0970d7d5..0000000000000 --- a/tests/compile-fail/ptr_bitops1.rs +++ /dev/null @@ -1,7 +0,0 @@ -fn main() { - let bytes = [0i8, 1, 2, 3, 4, 5, 6, 7, 8, 9]; - let one = bytes.as_ptr().wrapping_offset(1); - let three = bytes.as_ptr().wrapping_offset(3); - let res = (one as usize) | (three as usize); //~ ERROR invalid arithmetic on pointers that would leak base addresses - println!("{}", res); -} diff --git a/tests/compile-fail/ptr_bitops2.rs b/tests/compile-fail/ptr_bitops2.rs deleted file mode 100644 index 5d5eab155083b..0000000000000 --- a/tests/compile-fail/ptr_bitops2.rs +++ /dev/null @@ -1,5 +0,0 @@ -fn main() { - let val = 13usize; - let addr = &val as *const _ as usize; - let _val = addr & 13; //~ ERROR access part of a pointer value as raw bytes -} diff --git a/tests/compile-fail/ptr_eq_dangling.rs b/tests/compile-fail/ptr_eq_dangling.rs deleted file mode 100644 index 5badf099e4391..0000000000000 --- a/tests/compile-fail/ptr_eq_dangling.rs +++ /dev/null @@ -1,10 +0,0 @@ -fn main() { - let b = Box::new(0); - let x = &*b as *const i32; // soon-to-be dangling - drop(b); - let b = Box::new(0); - let y = &*b as *const i32; // different allocation - // We cannot compare these even though both are inbounds -- they *could* be - // equal if memory was reused. - assert!(x != y); //~ ERROR invalid arithmetic on pointers -} diff --git a/tests/compile-fail/ptr_eq_integer.rs b/tests/compile-fail/ptr_eq_integer.rs deleted file mode 100644 index 396abaf4493b1..0000000000000 --- a/tests/compile-fail/ptr_eq_integer.rs +++ /dev/null @@ -1,6 +0,0 @@ -fn main() { - let b = Box::new(0); - let x = &*b as *const i32; - // We cannot compare this with a non-NULL integer. After all, these *could* be equal (with the right base address). - assert!(x != 64 as *const i32); //~ ERROR invalid arithmetic on pointers -} diff --git a/tests/compile-fail/ptr_eq_out_of_bounds.rs b/tests/compile-fail/ptr_eq_out_of_bounds.rs deleted file mode 100644 index 7efa446d7fca4..0000000000000 --- a/tests/compile-fail/ptr_eq_out_of_bounds.rs +++ /dev/null @@ -1,9 +0,0 @@ -fn main() { - let b = Box::new(0); - let x = (&*b as *const i32).wrapping_sub(0x800); // out-of-bounds - let b = Box::new(0); - let y = &*b as *const i32; // different allocation - // We cannot compare these even though both allocations are live -- they *could* be - // equal (with the right base addresses). - assert!(x != y); //~ ERROR invalid arithmetic on pointers -} diff --git a/tests/compile-fail/ptr_eq_out_of_bounds_null.rs b/tests/compile-fail/ptr_eq_out_of_bounds_null.rs deleted file mode 100644 index 3b7b51fc19954..0000000000000 --- a/tests/compile-fail/ptr_eq_out_of_bounds_null.rs +++ /dev/null @@ -1,6 +0,0 @@ -fn main() { - let b = Box::new(0); - let x = (&*b as *const i32).wrapping_sub(0x800); // out-of-bounds - // We cannot compare this with NULL. After all, this *could* be NULL (with the right base address). - assert!(x != std::ptr::null()); //~ ERROR invalid arithmetic on pointers -} diff --git a/tests/compile-fail/ptr_int_cast.rs b/tests/compile-fail/ptr_int_cast.rs deleted file mode 100644 index a823a0f49b630..0000000000000 --- a/tests/compile-fail/ptr_int_cast.rs +++ /dev/null @@ -1,8 +0,0 @@ -fn main() { - let x = &1; - // Casting down to u8 and back up to a pointer loses too much precision; this must not work. - let x = x as *const i32; - let x = x as u8; //~ ERROR a raw memory access tried to access part of a pointer value as raw bytes - let x = x as *const i32; - let _val = unsafe { *x }; -} diff --git a/tests/compile-fail/ptr_offset_int_plus_int.rs b/tests/compile-fail/ptr_offset_int_plus_int.rs index 2d3282a0a97a0..051874696b116 100644 --- a/tests/compile-fail/ptr_offset_int_plus_int.rs +++ b/tests/compile-fail/ptr_offset_int_plus_int.rs @@ -1,4 +1,4 @@ -// error-pattern: tried to interpret some bytes as a pointer +// error-pattern: dangling pointer was dereferenced fn main() { // Can't offset an integer pointer by non-zero offset. diff --git a/tests/compile-fail/ptr_offset_int_plus_ptr.rs b/tests/compile-fail/ptr_offset_int_plus_ptr.rs index b49c758c72f78..bd90d06909177 100644 --- a/tests/compile-fail/ptr_offset_int_plus_ptr.rs +++ b/tests/compile-fail/ptr_offset_int_plus_ptr.rs @@ -1,4 +1,4 @@ -// error-pattern: pointer value as raw bytes +// error-pattern: dangling pointer was dereferenced fn main() { let ptr = Box::into_raw(Box::new(0u32)); diff --git a/tests/compile-fail/ptr_rem.rs b/tests/compile-fail/ptr_rem.rs deleted file mode 100644 index dfc91e9dc1b12..0000000000000 --- a/tests/compile-fail/ptr_rem.rs +++ /dev/null @@ -1,5 +0,0 @@ -fn main() { - let val = 13usize; - let addr = &val as *const _ as usize; - let _val = addr % 16; //~ ERROR access part of a pointer value as raw bytes -} diff --git a/tests/compile-fail/ptr_wrapping_offset_int_plus_ptr.rs b/tests/compile-fail/ptr_wrapping_offset_int_plus_ptr.rs deleted file mode 100644 index eacb9f07fffd7..0000000000000 --- a/tests/compile-fail/ptr_wrapping_offset_int_plus_ptr.rs +++ /dev/null @@ -1,8 +0,0 @@ -// error-pattern: pointer value as raw bytes - -fn main() { - let ptr = Box::into_raw(Box::new(0u32)); - // Can't start with an integer pointer and get to something usable - let ptr = (1 as *mut u8).wrapping_offset(ptr as isize); - let _val = unsafe { *ptr }; -} diff --git a/tests/compile-fail/validity/dangling_ref1.rs b/tests/compile-fail/validity/dangling_ref1.rs index 2c1984b7159ce..194445b1ad7e1 100644 --- a/tests/compile-fail/validity/dangling_ref1.rs +++ b/tests/compile-fail/validity/dangling_ref1.rs @@ -1,5 +1,5 @@ use std::mem; fn main() { - let _x: &i32 = unsafe { mem::transmute(16usize) }; //~ ERROR dangling reference (created from integer) + let _x: &i32 = unsafe { mem::transmute(16usize) }; //~ ERROR dangling reference (not entirely in bounds) } diff --git a/tests/compile-fail/wild_pointer_deref.rs b/tests/compile-fail/wild_pointer_deref.rs index 8eec9737546b3..ae32f7d5562bd 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 = 44 as *const i32; - let x = unsafe { *p }; //~ ERROR a memory access tried to interpret some bytes as a pointer + let x = unsafe { *p }; //~ ERROR dangling pointer was dereferenced panic!("this should never print: {}", x); } diff --git a/tests/compile-fail/bitop-beyond-alignment.rs b/tests/run-pass/bitop-beyond-alignment.rs similarity index 87% rename from tests/compile-fail/bitop-beyond-alignment.rs rename to tests/run-pass/bitop-beyond-alignment.rs index a30c054ab5d04..f7bf7f9ff58bc 100644 --- a/tests/compile-fail/bitop-beyond-alignment.rs +++ b/tests/run-pass/bitop-beyond-alignment.rs @@ -28,7 +28,7 @@ fn mk_rec() -> Rec { fn is_u64_aligned(u: &Tag) -> bool { let p: usize = unsafe { mem::transmute(u) }; let u64_align = std::mem::align_of::(); - return (p & (u64_align + 1)) == 0; //~ ERROR a raw memory access tried to access part of a pointer value as raw bytes + return (p & (u64_align + 1)) == 0; } pub fn main() { diff --git a/tests/run-pass/intptrcast.rs b/tests/run-pass/intptrcast.rs index c28958b872de2..c2711f9845d0f 100644 --- a/tests/run-pass/intptrcast.rs +++ b/tests/run-pass/intptrcast.rs @@ -3,18 +3,22 @@ fn transmute_ptr_to_int(x: *const T) -> usize { unsafe { std::mem::transmute(x) } } -fn main() { +fn cast() { // Some casting-to-int with arithmetic. let x = &42 as *const i32 as usize; let y = x * 2; assert_eq!(y, x + x); let z = y as u8 as usize; assert_eq!(z, y % 256); +} +fn format() { // Pointer string formatting! We can't check the output as it changes when libstd changes, // but we can make sure Miri does not error. format!("{:?}", &mut 13 as *mut _); +} +fn transmute() { // Check that intptrcast is triggered for explicit casts and that it is consistent with // transmuting. let a: *const i32 = &42; @@ -22,3 +26,64 @@ fn main() { let c = a as usize as u8; assert_eq!(b, c); } + +fn ptr_bitops1() { + let bytes = [0i8, 1, 2, 3, 4, 5, 6, 7, 8, 9]; + let one = bytes.as_ptr().wrapping_offset(1); + let three = bytes.as_ptr().wrapping_offset(3); + let res = (one as usize) | (three as usize); + format!("{}", res); +} + +fn ptr_bitops2() { + let val = 13usize; + let addr = &val as *const _ as usize; + let _val = addr & 13; +} + +fn ptr_eq_dangling() { + let b = Box::new(0); + let x = &*b as *const i32; // soon-to-be dangling + drop(b); + let b = Box::new(0); + let y = &*b as *const i32; // different allocation + // We cannot compare these even though both are inbounds -- they *could* be + // equal if memory was reused. + assert!(x != y); +} + +fn ptr_eq_out_of_bounds() { + let b = Box::new(0); + let x = (&*b as *const i32).wrapping_sub(0x800); // out-of-bounds + let b = Box::new(0); + let y = &*b as *const i32; // different allocation + // We cannot compare these even though both allocations are live -- they *could* be + // equal (with the right base addresses). + assert!(x != y); +} + +fn ptr_eq_out_of_bounds_null() { + let b = Box::new(0); + let x = (&*b as *const i32).wrapping_sub(0x800); // out-of-bounds + // We cannot compare this with NULL. After all, this *could* be NULL (with the right base address). + assert!(x != std::ptr::null()); +} + +fn ptr_eq_integer() { + let b = Box::new(0); + let x = &*b as *const i32; + // We cannot compare this with a non-NULL integer. After all, these *could* be equal (with the right base address). + assert!(x != 64 as *const i32); +} + +fn main() { + cast(); + format(); + transmute(); + ptr_bitops1(); + ptr_bitops2(); + ptr_eq_dangling(); + ptr_eq_out_of_bounds(); + ptr_eq_out_of_bounds_null(); + ptr_eq_integer(); +} From d5ca345c36b037c4cdfe1a9f165464e7f815e2c1 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 23 Jul 2019 23:26:25 +0200 Subject: [PATCH 0945/3747] remove redundant tests / flags --- tests/compile-fail/intptrcast_alignment_check.rs | 2 +- tests/compile-fail/intptrcast_cast_int_to_fn_ptr.rs | 10 ---------- tests/compile-fail/intptrcast_null_pointer_deref.rs | 6 ------ tests/compile-fail/intptrcast_wild_pointer_deref.rs | 7 ------- 4 files changed, 1 insertion(+), 24 deletions(-) delete mode 100644 tests/compile-fail/intptrcast_cast_int_to_fn_ptr.rs delete mode 100644 tests/compile-fail/intptrcast_null_pointer_deref.rs delete mode 100644 tests/compile-fail/intptrcast_wild_pointer_deref.rs diff --git a/tests/compile-fail/intptrcast_alignment_check.rs b/tests/compile-fail/intptrcast_alignment_check.rs index 5a35844d1256d..4e12a8a9e25e1 100644 --- a/tests/compile-fail/intptrcast_alignment_check.rs +++ b/tests/compile-fail/intptrcast_alignment_check.rs @@ -1,5 +1,5 @@ // Validation makes this fail in the wrong place -// compile-flags: -Zmiri-disable-validation -Zmiri-seed=0000000000000000 +// compile-flags: -Zmiri-disable-validation // Even with intptrcast and without validation, we want to be *sure* to catch bugs // that arise from pointers being insufficiently aligned. The only way to achieve diff --git a/tests/compile-fail/intptrcast_cast_int_to_fn_ptr.rs b/tests/compile-fail/intptrcast_cast_int_to_fn_ptr.rs deleted file mode 100644 index f4064cf92e2ca..0000000000000 --- a/tests/compile-fail/intptrcast_cast_int_to_fn_ptr.rs +++ /dev/null @@ -1,10 +0,0 @@ -// Validation makes this fail in the wrong place -// compile-flags: -Zmiri-disable-validation -Zmiri-seed=0000000000000000 - -fn main() { - let g = unsafe { - std::mem::transmute::(42) - }; - - g(42) //~ ERROR dangling pointer was dereferenced -} diff --git a/tests/compile-fail/intptrcast_null_pointer_deref.rs b/tests/compile-fail/intptrcast_null_pointer_deref.rs deleted file mode 100644 index 0c5d46609cf83..0000000000000 --- a/tests/compile-fail/intptrcast_null_pointer_deref.rs +++ /dev/null @@ -1,6 +0,0 @@ -// compile-flags: -Zmiri-seed=0000000000000000 - -fn main() { - 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/intptrcast_wild_pointer_deref.rs b/tests/compile-fail/intptrcast_wild_pointer_deref.rs deleted file mode 100644 index 2ee664eb68bd3..0000000000000 --- a/tests/compile-fail/intptrcast_wild_pointer_deref.rs +++ /dev/null @@ -1,7 +0,0 @@ -// compile-flags: -Zmiri-seed=0000000000000000 - -fn main() { - let p = 44 as *const i32; - let x = unsafe { *p }; //~ ERROR dangling pointer was dereferenced - panic!("this should never print: {}", x); -} From 724cf41eb1a4fa529a5b1fe629d077dbb217019f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 23 Jul 2019 23:43:37 +0200 Subject: [PATCH 0946/3747] use checked arithmetic in intrptrcast --- src/intptrcast.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/intptrcast.rs b/src/intptrcast.rs index 8fbf7ed76427f..1247150cc1199 100644 --- a/src/intptrcast.rs +++ b/src/intptrcast.rs @@ -95,7 +95,8 @@ impl<'mir, 'tcx> GlobalState { rng.gen_range(0, 16) }; // From next_base_addr + slack, round up to adjust for alignment. - let base_addr = Self::align_addr(global_state.next_base_addr + slack, align.bytes()); + let base_addr = global_state.next_base_addr.checked_add(slack).unwrap(); + let base_addr = Self::align_addr(base_addr, align.bytes()); entry.insert(base_addr); trace!( "Assigning base address {:#x} to allocation {:?} (slack: {}, align: {})", @@ -104,7 +105,7 @@ impl<'mir, 'tcx> GlobalState { // Remember next base address. If this allocation is zero-sized, leave a gap // of at least 1 to avoid two allocations having the same base address. - global_state.next_base_addr = base_addr + max(size.bytes(), 1); + global_state.next_base_addr = base_addr.checked_add(max(size.bytes(), 1)).unwrap(); // Given that `next_base_addr` increases in each allocation, pushing the // corresponding tuple keeps `int_to_ptr_map` sorted global_state.int_to_ptr_map.push((base_addr, ptr.alloc_id)); @@ -124,7 +125,7 @@ impl<'mir, 'tcx> GlobalState { fn align_addr(addr: u64, align: u64) -> u64 { match addr % align { 0 => addr, - rem => addr + align - rem + rem => addr.checked_add(align).unwrap() - rem } } } From 85be8ab8ebaf5487ef7e852db809751d97a36605 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 23 Jul 2019 23:48:28 +0200 Subject: [PATCH 0947/3747] fix non-deterministic test --- tests/run-pass/bitop-beyond-alignment.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/run-pass/bitop-beyond-alignment.rs b/tests/run-pass/bitop-beyond-alignment.rs index f7bf7f9ff58bc..f60982246427e 100644 --- a/tests/run-pass/bitop-beyond-alignment.rs +++ b/tests/run-pass/bitop-beyond-alignment.rs @@ -33,5 +33,5 @@ fn is_u64_aligned(u: &Tag) -> bool { pub fn main() { let x = mk_rec(); - assert!(is_u64_aligned(&x.t)); + is_u64_aligned(&x.t); // the result of this is non-deterministic } From fd71fbea0f5e9f13bf33b0b1a78f3e6d5897b542 Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Wed, 24 Jul 2019 07:30:41 +0700 Subject: [PATCH 0948/3747] build: Fix build after rust-lang/rust#60951 --- rust-version | 2 +- src/operator.rs | 7 ++++--- src/shims/foreign_items.rs | 3 ++- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/rust-version b/rust-version index b247139d09b36..973a5105980c8 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -1301422a6c2e8916560b8cc2f0564f38d8858a75 +a7f28678bbf4e16893bb6a718e427504167a9494 diff --git a/src/operator.rs b/src/operator.rs index df60acc661ed4..977d6dd56e46f 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -64,12 +64,12 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { assert!(right.layout.ty.is_integral()); let l_bits = self.force_bits(left.imm.to_scalar()?, left.layout.size)?; let r_bits = self.force_bits(right.imm.to_scalar()?, right.layout.size)?; - + let left = ImmTy::from_scalar(Scalar::from_uint(l_bits, left.layout.size), left.layout); let right = ImmTy::from_scalar(Scalar::from_uint(r_bits, left.layout.size), right.layout); return self.binary_op(bin_op, left, right); - } + } // Operations that support fat pointers match bin_op { @@ -391,11 +391,12 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { pointee_ty: Ty<'tcx>, offset: i64, ) -> InterpResult<'tcx, Scalar> { + use rustc::mir::interpret::InterpError::Panic; // FIXME: assuming here that type size is less than `i64::max_value()`. let pointee_size = self.layout_of(pointee_ty)?.size.bytes() as i64; let offset = offset .checked_mul(pointee_size) - .ok_or_else(|| InterpError::Overflow(mir::BinOp::Mul))?; + .ok_or_else(|| Panic(PanicMessage::Overflow(mir::BinOp::Mul)))?; // Now let's see what kind of pointer this is. let ptr = if offset == 0 { match ptr { diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 1deaf521ca66f..bcfcda2fd01c5 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -128,6 +128,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx dest: Option>, ret: Option, ) -> InterpResult<'tcx> { + use rustc::mir::interpret::InterpError::Panic; let this = self.eval_context_mut(); let attrs = this.tcx.get_attrs(def_id); let link_name = match attr::first_attr_value_str_by_name(&attrs, sym::link_name) { @@ -167,7 +168,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "calloc" => { let items = this.read_scalar(args[0])?.to_usize(this)?; let len = this.read_scalar(args[1])?.to_usize(this)?; - let size = items.checked_mul(len).ok_or_else(|| InterpError::Overflow(mir::BinOp::Mul))?; + let size = items.checked_mul(len).ok_or_else(|| Panic(PanicMessage::Overflow(mir::BinOp::Mul)))?; let res = this.malloc(size, /*zero_init:*/ true, MiriMemoryKind::C); this.write_scalar(res, dest)?; } From 758d88bbf96c726ca8c620068bb20f552b8bd35a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 24 Jul 2019 08:57:05 +0200 Subject: [PATCH 0949/3747] explain better what is non-deterministic here --- tests/run-pass/bitop-beyond-alignment.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/run-pass/bitop-beyond-alignment.rs b/tests/run-pass/bitop-beyond-alignment.rs index f60982246427e..a30f0fb61314a 100644 --- a/tests/run-pass/bitop-beyond-alignment.rs +++ b/tests/run-pass/bitop-beyond-alignment.rs @@ -33,5 +33,5 @@ fn is_u64_aligned(u: &Tag) -> bool { pub fn main() { let x = mk_rec(); - is_u64_aligned(&x.t); // the result of this is non-deterministic + is_u64_aligned(&x.t); // the result of this is non-deterministic (even with a fixed seed, results vary between platforms) } From 59fa7c2cf5ed072e7d9f8bc1ae2307b67dacfbdb Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 24 Jul 2019 14:18:42 +0200 Subject: [PATCH 0950/3747] readme: move flags and env vars up above dev --- README.md | 73 ++++++++++++++++++++++++++++--------------------------- 1 file changed, 37 insertions(+), 36 deletions(-) diff --git a/README.md b/README.md index fbd1f51c9e697..6b6a274f3fba6 100644 --- a/README.md +++ b/README.md @@ -136,6 +136,43 @@ should never happen when you use `cargo miri` because that takes care of setting up the sysroot. If you are using `miri` (the Miri driver) directly, see [below][testing-miri] for how to set up the sysroot. + +## Miri `-Z` flags and environment variables +[miri-flags]: #miri--z-flags-and-environment-variables + +Several `-Z` flags are relevant for Miri: + +* `-Zmiri-seed=` is a custom `-Z` flag added by Miri. It configures the + seed of the RNG that Miri uses to resolve non-determinism. This RNG is used + to pick base addresses for allocations, and when the interpreted program + requests system entropy. The default seed is 0. + **NOTE**: This entropy is not good enough for cryptographic use! Do not + generate secret keys in Miri or perform other kinds of cryptographic + operations that rely on proper random numbers. +* `-Zmiri-disable-validation` disables enforcing the validity invariant, which + is enforced by default. This is mostly useful for debugging; it means Miri + will miss bugs in your program. However, this can also help to make Miri run + faster. +* `-Zmir-opt-level` controls how many MIR optimizations are performed. Miri + overrides the default to be `0`; be advised that using any higher level can + make Miri miss bugs in your program because they got optimized away. +* `-Zalways-encode-mir` makes rustc dump MIR even for completely monomorphic + functions. This is needed so that Miri can execute such functions, so Miri + sets this flag per default. +* `-Zmir-emit-retag` controls whether `Retag` statements are emitted. Miri + enables this per default because it is needed for validation. + +Moreover, Miri recognizes some environment variables: + +* `MIRI_LOG`, `MIRI_BACKTRACE` control logging and backtrace printing during + Miri executions, also [see above][testing-miri]. +* `MIRI_SYSROOT` (recognized by `cargo miri` and the test suite) + indicates the sysroot to use. To do the same thing with `miri` + directly, use the `--sysroot` flag. +* `MIRI_TEST_TARGET` (recognized by the test suite) indicates which target + architecture to test against. `miri` and `cargo miri` accept the `--target` + flag for the same purpose. + ## Development and Debugging If you want to hack on miri yourself, great! Here are some resources you might @@ -257,42 +294,6 @@ rustup override set custom With this, you should now have a working development setup! See [above][testing-miri] for how to proceed working with the Miri driver. -### Miri `-Z` flags and environment variables -[miri-flags]: #miri--z-flags-and-environment-variables - -Several `-Z` flags are relevant for Miri: - -* `-Zmiri-seed=` is a custom `-Z` flag added by Miri. It configures the - seed of the RNG that Miri uses to resolve non-determinism. This RNG is used - to pick base addresses for allocations, and when the interpreted program - requests system entropy. The default seed is 0. - **NOTE**: This entropy is not good enough for cryptographic use! Do not - generate secret keys in Miri or perform other kinds of cryptographic - operations that rely on proper random numbers. -* `-Zmiri-disable-validation` disables enforcing the validity invariant, which - is enforced by default. This is mostly useful for debugging; it means Miri - will miss bugs in your program. However, this can also help to make Miri run - faster. -* `-Zmir-opt-level` controls how many MIR optimizations are performed. Miri - overrides the default to be `0`; be advised that using any higher level can - make Miri miss bugs in your program because they got optimized away. -* `-Zalways-encode-mir` makes rustc dump MIR even for completely monomorphic - functions. This is needed so that Miri can execute such functions, so Miri - sets this flag per default. -* `-Zmir-emit-retag` controls whether `Retag` statements are emitted. Miri - enables this per default because it is needed for validation. - -Moreover, Miri recognizes some environment variables: - -* `MIRI_LOG`, `MIRI_BACKTRACE` control logging and backtrace printing during - Miri executions, also [see above][testing-miri]. -* `MIRI_SYSROOT` (recognized by `cargo miri` and the test suite) - indicates the sysroot to use. To do the same thing with `miri` - directly, use the `--sysroot` flag. -* `MIRI_TEST_TARGET` (recognized by the test suite) indicates which target - architecture to test against. `miri` and `cargo miri` accept the `--target` - flag for the same purpose. - ## Contributing and getting help Check out the issues on this GitHub repository for some ideas. There's lots that From e6a677fe63286dac484714282da7bb873dd2dbd3 Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Wed, 24 Jul 2019 21:24:26 +0700 Subject: [PATCH 0951/3747] build: Warn if not use 2018 idioms --- src/eval.rs | 2 +- src/lib.rs | 1 + src/stacked_borrows.rs | 8 ++++---- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/eval.rs b/src/eval.rs index 83307c99f9c59..e688d35947186 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -179,7 +179,7 @@ pub fn eval_main<'tcx>( }; // Perform the main execution. - let res: InterpResult = (|| { + let res: InterpResult<'_> = (|| { ecx.run()?; ecx.run_tls_dtors() })(); diff --git a/src/lib.rs b/src/lib.rs index 20c24ad54fe84..0265fbf15cc5b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,5 +1,6 @@ #![feature(rustc_private)] +#![warn(rust_2018_idioms)] #![allow(clippy::cast_lossless)] #[macro_use] diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 90656180150f1..0fe42f7974fbd 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -28,7 +28,7 @@ pub enum Tag { } impl fmt::Debug for Tag { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { Tag::Tagged(id) => write!(f, "<{}>", id), Tag::Untagged => write!(f, ""), @@ -62,7 +62,7 @@ pub struct Item { } impl fmt::Debug for Item { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "[{:?} for {:?}", self.perm, self.tag)?; if let Some(call) = self.protector { write!(f, " (call {})", call)?; @@ -117,7 +117,7 @@ pub enum AccessKind { } impl fmt::Display for AccessKind { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { AccessKind::Read => write!(f, "read access"), AccessKind::Write => write!(f, "write access"), @@ -139,7 +139,7 @@ pub enum RefKind { } impl fmt::Display for RefKind { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { RefKind::Unique { two_phase: false } => write!(f, "unique"), RefKind::Unique { two_phase: true } => write!(f, "unique (two-phase)"), From e843077d1d673019518055c47dc39c7098993b0c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 25 Jul 2019 19:38:55 +0200 Subject: [PATCH 0952/3747] link to UB definition --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 6b6a274f3fba6..6934c453de4d0 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,8 @@ An experimental interpreter for [Rust][rust]'s [mid-level intermediate representation][mir] (MIR). It can run binaries and -test suites of cargo projects and detect certain classes of undefined behavior, +test suites of cargo projects and detect certain classes of +[undefined behavior](https://doc.rust-lang.org/reference/behavior-considered-undefined.html), for example: * Out-of-bounds memory accesses and use-after-free From 8bec925e049b74134713f4c860d1c46acc84214d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 26 Jul 2019 10:14:44 +0200 Subject: [PATCH 0953/3747] bump Rust --- rust-version | 2 +- tests/run-pass/intrinsics.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/rust-version b/rust-version index 973a5105980c8..b8ae5e6cbd56a 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -a7f28678bbf4e16893bb6a718e427504167a9494 +4268e7ee22935f086b856ef0063a9e22b49aeddb diff --git a/tests/run-pass/intrinsics.rs b/tests/run-pass/intrinsics.rs index 963265749d136..754a38f63535b 100644 --- a/tests/run-pass/intrinsics.rs +++ b/tests/run-pass/intrinsics.rs @@ -11,5 +11,5 @@ fn main() { assert_eq!(size_of_val(&[1, 2, 3] as &[i32]), 12); assert_eq!(size_of_val("foobar"), 6); - assert_eq!(unsafe { type_name::>() }, "core::option::Option"); + assert_eq!(type_name::>(), "core::option::Option"); } From faadb86159bf3c65a1e69db0432ba52c980b6324 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 26 Jul 2019 22:50:01 +0200 Subject: [PATCH 0954/3747] bump Rust --- rust-version | 2 +- src/bin/cargo-miri.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/rust-version b/rust-version index b8ae5e6cbd56a..a3ec4b911c409 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -4268e7ee22935f086b856ef0063a9e22b49aeddb +c43753f910aae000f8bcb0a502407ea332afc74b diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index cc95eeb7f3a0a..fe30e7d010bd7 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -335,7 +335,7 @@ fn main() { } fn in_cargo_miri() { - let (subcommand, skip) = match std::env::args().nth(2).deref() { + let (subcommand, skip) = match std::env::args().nth(2).as_deref() { Some("test") => (MiriCommand::Test, 3), Some("run") => (MiriCommand::Run, 3), Some("setup") => (MiriCommand::Setup, 3), From 070d1cd08d0bf7c994cc842b60d883c9f9e8ce2c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 28 Jul 2019 10:14:36 +0200 Subject: [PATCH 0955/3747] bump Rust (no changes needed) --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index a3ec4b911c409..2dc0d2bbccb65 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -c43753f910aae000f8bcb0a502407ea332afc74b +0e9b465d729d07101b29b4d096d83edf9be82df0 From 784ad6953edf5a82382e74223225382cb9ed12c4 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 29 Jul 2019 10:07:29 +0200 Subject: [PATCH 0956/3747] bump Rust --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 2dc0d2bbccb65..5178503f10412 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -0e9b465d729d07101b29b4d096d83edf9be82df0 +8b94e9e9188b65df38a5f1ae723617dc2dfb3155 From 87f20fede528a2a99c06e6aae480adac91f5ecc2 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 29 Jul 2019 10:21:59 +0200 Subject: [PATCH 0957/3747] adjust for slice pattern changes --- tests/run-pass/issue-15080.rs | 4 ++-- tests/run-pass/issue-17877.rs | 4 ++-- tests/run-pass/subslice_array.rs | 2 +- tests/run-pass/vec-matching-fold.rs | 4 ++-- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/tests/run-pass/issue-15080.rs b/tests/run-pass/issue-15080.rs index 3ef3718d52276..7f19759b910a6 100644 --- a/tests/run-pass/issue-15080.rs +++ b/tests/run-pass/issue-15080.rs @@ -6,11 +6,11 @@ fn main() { let mut result = vec!(); loop { x = match *x { - [1, n, 3, ref rest..] => { + [1, n, 3, ref rest @ ..] => { result.push(n); rest } - [n, ref rest..] => { + [n, ref rest @ ..] => { result.push(n); rest } diff --git a/tests/run-pass/issue-17877.rs b/tests/run-pass/issue-17877.rs index caad8b27766fe..9cbc459ad038e 100644 --- a/tests/run-pass/issue-17877.rs +++ b/tests/run-pass/issue-17877.rs @@ -9,8 +9,8 @@ fn main() { }, 42_usize); assert_eq!(match [0u8; 1024] { - [1, _..] => 0_usize, - [0, _..] => 1_usize, + [1, ..] => 0_usize, + [0, ..] => 1_usize, _ => 2_usize }, 1_usize); } diff --git a/tests/run-pass/subslice_array.rs b/tests/run-pass/subslice_array.rs index 5bbbffe4e60e1..df3631c647fb0 100644 --- a/tests/run-pass/subslice_array.rs +++ b/tests/run-pass/subslice_array.rs @@ -6,7 +6,7 @@ fn bar(a: &'static str, b: &'static str) -> [&'static str; 4] { fn main() { let out = bar("baz", "foo"); - let [a, xs.., d] = out; + let [a, xs @ .., d] = out; assert_eq!(a, "baz"); assert_eq!(xs, ["foo", "foo"]); assert_eq!(d, "baz"); diff --git a/tests/run-pass/vec-matching-fold.rs b/tests/run-pass/vec-matching-fold.rs index f953e04747050..54fbb702924f3 100644 --- a/tests/run-pass/vec-matching-fold.rs +++ b/tests/run-pass/vec-matching-fold.rs @@ -9,7 +9,7 @@ fn foldl(values: &[T], U: Clone+Debug, T:Debug, F: FnMut(U, &T) -> U, { match values { - &[ref head, ref tail..] => + &[ref head, ref tail @ ..] => foldl(tail, function(initial, head), function), &[] => { let res = initial.clone(); res @@ -25,7 +25,7 @@ fn foldr(values: &[T], F: FnMut(&T, U) -> U, { match values { - &[ref head.., ref tail] => + &[ref head @ .., ref tail] => foldr(head, function(tail, initial), function), &[] => { let res = initial.clone(); res From b1ba07b0ca440329068ca2fd308ccb24c31a2697 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 30 Jul 2019 11:23:56 +0200 Subject: [PATCH 0958/3747] call out more clearly what we do not test; update paragraph on intptrcast --- README.md | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 6934c453de4d0..e21ee987125e4 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ for example: * Violation of intrinsic preconditions (an [`unreachable_unchecked`] being reached, calling [`copy_nonoverlapping`] with overlapping ranges, ...) * Not sufficiently aligned memory accesses and references -* Violation of basic type invariants (a `bool` that is not 0 or 1, for example, +* Violation of *some* basic type invariants (a `bool` that is not 0 or 1, for example, or an invalid enum discriminant) * WIP: Violations of the rules governing aliasing for reference types @@ -20,22 +20,24 @@ Miri has already discovered some [real-world bugs](#bugs-found-by-miri). If you found a bug with Miri, we'd appreciate if you tell us and we'll add it to the list! -Be aware that Miri will not catch all possible errors in your program, and -cannot run all programs: +Be aware that Miri will not catch all cases of undefined behavior in your +program, and cannot run all programs: * There are still plenty of open questions around the basic invariants for some types and when these invariants even have to hold. Miri tries to avoid false positives here, so if you program runs fine in Miri right now that is by no - means a guarantee that it is UB-free when these questions get answered. In - particular, Miri does currently not check that integers are initialized or - that references point to valid data. + means a guarantee that it is UB-free when these questions get answered. + + In particular, Miri does currently not check that integers are initialized + or that references point to valid data. * If the program relies on unspecified details of how data is laid out, it will still run fine in Miri -- but might break (including causing UB) on different compiler versions or different platforms. -* Miri is fully deterministic and does not actually pick a base address in - virtual memory for the program's allocations. If program behavior depends on - the base address of an allocation, Miri will stop execution (with a few - exceptions to make some common pointer comparisons work). +* Program execution is non-deterministic when it depends, for example, on where + exactly in memory allocations end up. Miri tests one of many possible + executions of your program. If your code is sensitive to allocation base + addresses or other non-deterministic data, try running Miri with different + values for `-Zmiri-seed` to test different executions. * Miri runs the program as a platform-independent interpreter, so the program has no access to any platform-specific APIs or FFI. A few APIs have been implemented (such as printing to stdout) but most have not: for example, Miri From fcbdd2c86469b0be514b1c08075fec57e71e20a1 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 30 Jul 2019 17:04:57 +0200 Subject: [PATCH 0959/3747] move CI remark down to CI section --- README.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index e21ee987125e4..91fc72cb427bc 100644 --- a/README.md +++ b/README.md @@ -73,9 +73,7 @@ Now you can run your project in Miri: 3. If you have a binary project, you can run it through Miri using `cargo miri run`. The first time you run Miri, it will perform some extra setup and install some -dependencies. It will ask you for confirmation before installing anything. If -you run Miri on CI, run `cargo miri setup` to avoid getting interactive -questions. +dependencies. It will ask you for confirmation before installing anything. You can pass arguments to Miri after the first `--`, and pass arguments to the interpreted program or test suite after the second `--`. For example, `cargo @@ -115,6 +113,9 @@ cargo miri setup cargo miri test -- -- -Zunstable-options --exclude-should-panic ``` +We use `cargo miri setup` to avoid getting interactive questions about the extra +setup needed for Miri. + ### Common Problems When using the above instructions, you may encounter a number of confusing compiler From 6902461226ae7508e58689e80280da223462f3d0 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 30 Jul 2019 23:17:13 +0200 Subject: [PATCH 0960/3747] AppVeyor: retry download --- .appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.appveyor.yml b/.appveyor.yml index 4e8b8cd4b898b..391ff042daf41 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -18,7 +18,7 @@ cache: install: # Install Rust - - curl -sSf -o rustup-init.exe https://win.rustup.rs/ + - curl -sSf --retry 3 -o rustup-init.exe https://win.rustup.rs/ - rustup-init.exe -y --default-host %TARGET% --default-toolchain stable - set PATH=%USERPROFILE%\.cargo\bin;%PATH% # Install "master" toolchain From af7570fced59a775da78492cb20a6f22982a1268 Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Wed, 31 Jul 2019 16:42:38 +0900 Subject: [PATCH 0961/3747] Remove await_macro --- tests/run-pass/async-fn.rs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/tests/run-pass/async-fn.rs b/tests/run-pass/async-fn.rs index 8a0ac875f54d6..5c916473b5804 100644 --- a/tests/run-pass/async-fn.rs +++ b/tests/run-pass/async-fn.rs @@ -1,7 +1,4 @@ -#![feature( - async_await, - await_macro, -)] +#![feature(async_await)] use std::{future::Future, pin::Pin, task::Poll, ptr}; use std::task::{Waker, RawWaker, RawWakerVTable, Context}; @@ -11,7 +8,7 @@ pub async fn foo(x: &u32, y: u32) -> u32 { let y = &y; let z = 9; let z = &z; - let y = await!(async { *y + *z }); + let y = async { *y + *z }.await; let a = 10; let a = &a; *x + y + *a From 6dadb941013e901dd8167ee50642d6eba0c08aff Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 31 Jul 2019 13:44:55 +0200 Subject: [PATCH 0962/3747] test suite: be fine with warnings when running on rustc CI --- tests/compiletest.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tests/compiletest.rs b/tests/compiletest.rs index 9394084ad34dc..f88fb0b6b981f 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -26,7 +26,11 @@ fn rustc_lib_path() -> PathBuf { fn run_tests(mode: &str, path: &str, target: &str, mut flags: Vec) { // Some flags we always want. - flags.push("-Dwarnings -Dunused".to_owned()); // overwrite the -Aunused in compiletest-rs + if rustc_test_suite().is_none() { + // Only `-Dwarnings` on the Miri side to make the rustc toolstate management less painful. + // (We often get warnings when e.g. a feature gets stabilized or some lint gets added/improved.) + flags.push("-Dwarnings -Dunused".to_owned()); // overwrite the -Aunused in compiletest-rs + } flags.push("--edition 2018".to_owned()); if let Ok(sysroot) = std::env::var("MIRI_SYSROOT") { flags.push(format!("--sysroot {}", sysroot)); From edf7d1c30c9b53da5f9cd0fa9597d999f0aa1752 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 31 Jul 2019 13:48:15 +0200 Subject: [PATCH 0963/3747] dedup code a bit --- tests/compiletest.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/tests/compiletest.rs b/tests/compiletest.rs index f88fb0b6b981f..21366c3dbf505 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -25,8 +25,9 @@ fn rustc_lib_path() -> PathBuf { } fn run_tests(mode: &str, path: &str, target: &str, mut flags: Vec) { - // Some flags we always want. - if rustc_test_suite().is_none() { + let in_rustc_test_suite = rustc_test_suite().is_some(); + // Add some flags we always want. + if !in_rustc_test_suite { // Only `-Dwarnings` on the Miri side to make the rustc toolstate management less painful. // (We often get warnings when e.g. a feature gets stabilized or some lint gets added/improved.) flags.push("-Dwarnings -Dunused".to_owned()); // overwrite the -Aunused in compiletest-rs @@ -40,7 +41,7 @@ fn run_tests(mode: &str, path: &str, target: &str, mut flags: Vec) { let mut config = compiletest::Config::default().tempdir(); config.mode = mode.parse().expect("Invalid mode"); config.rustc_path = miri_path(); - if rustc_test_suite().is_some() { + if in_rustc_test_suite { config.run_lib_path = rustc_lib_path(); config.compile_lib_path = rustc_lib_path(); } From a414492cc736111446a11925aadba5605496624c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 31 Jul 2019 13:48:49 +0200 Subject: [PATCH 0964/3747] reorder for clarity --- tests/compiletest.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/compiletest.rs b/tests/compiletest.rs index 21366c3dbf505..eaf7f8531b8fc 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -27,12 +27,12 @@ fn rustc_lib_path() -> PathBuf { fn run_tests(mode: &str, path: &str, target: &str, mut flags: Vec) { let in_rustc_test_suite = rustc_test_suite().is_some(); // Add some flags we always want. + flags.push("--edition 2018".to_owned()); if !in_rustc_test_suite { // Only `-Dwarnings` on the Miri side to make the rustc toolstate management less painful. // (We often get warnings when e.g. a feature gets stabilized or some lint gets added/improved.) flags.push("-Dwarnings -Dunused".to_owned()); // overwrite the -Aunused in compiletest-rs } - flags.push("--edition 2018".to_owned()); if let Ok(sysroot) = std::env::var("MIRI_SYSROOT") { flags.push(format!("--sysroot {}", sysroot)); } From d213c64d8569a7422eed517b9f4a5ea867c76866 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 31 Jul 2019 15:15:14 +0200 Subject: [PATCH 0965/3747] let the user skip the sysroot consistency check --- src/bin/cargo-miri.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index fe30e7d010bd7..b46742efe72ae 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -141,6 +141,13 @@ fn test_sysroot_consistency() { .unwrap_or_else(|_| panic!("Failed to canonicalize sysroot: {}", stdout)) } + // We let the user skip this check if they really want to. + // (`bootstrap` needs this because Miri gets built by the stage1 compiler + // but run with the stage2 sysroot.) + if std::env::var("MIRI_SKIP_SYSROOT_CHECK").is_ok() { + return; + } + let rustc_sysroot = get_sysroot(Command::new("rustc")); let miri_sysroot = get_sysroot(Command::new(find_miri())); From 56630e0ff06c9f9690c4497f95a88fc64b1e5c8a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 31 Jul 2019 15:15:31 +0200 Subject: [PATCH 0966/3747] bootstrap no longer carries a copy of these flags --- src/lib.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 0265fbf15cc5b..58f572bf70112 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -47,7 +47,5 @@ pub use crate::eval::{eval_main, create_ecx, MiriConfig}; /// Insert rustc arguments at the beginning of the argument list that Miri wants to be /// set per default, for maximal validation power. pub fn miri_default_args() -> &'static [&'static str] { - // The flags here should be kept in sync with what bootstrap adds when `test-miri` is - // set, which happens in `bootstrap/bin/rustc.rs` in the rustc sources. &["-Zalways-encode-mir", "-Zmir-emit-retag", "-Zmir-opt-level=0", "--cfg=miri"] } From 6c545ba340fb50e33bf4b71672e3919a84ba4f3c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 31 Jul 2019 15:15:55 +0200 Subject: [PATCH 0967/3747] the compile-fail-norustc hack is no longer needed --- .../copy_nonoverlapping.rs | 0 tests/{compile-fail-norustc => compile-fail}/copy_null.rs | 0 .../copy_unaligned.rs | 0 tests/compiletest.rs | 7 ------- 4 files changed, 7 deletions(-) rename tests/{compile-fail-norustc => compile-fail}/copy_nonoverlapping.rs (100%) rename tests/{compile-fail-norustc => compile-fail}/copy_null.rs (100%) rename tests/{compile-fail-norustc => compile-fail}/copy_unaligned.rs (100%) diff --git a/tests/compile-fail-norustc/copy_nonoverlapping.rs b/tests/compile-fail/copy_nonoverlapping.rs similarity index 100% rename from tests/compile-fail-norustc/copy_nonoverlapping.rs rename to tests/compile-fail/copy_nonoverlapping.rs diff --git a/tests/compile-fail-norustc/copy_null.rs b/tests/compile-fail/copy_null.rs similarity index 100% rename from tests/compile-fail-norustc/copy_null.rs rename to tests/compile-fail/copy_null.rs diff --git a/tests/compile-fail-norustc/copy_unaligned.rs b/tests/compile-fail/copy_unaligned.rs similarity index 100% rename from tests/compile-fail-norustc/copy_unaligned.rs rename to tests/compile-fail/copy_unaligned.rs diff --git a/tests/compiletest.rs b/tests/compiletest.rs index 9394084ad34dc..757e8c1a64728 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -108,13 +108,6 @@ fn run_pass_miri(opt: bool) { fn compile_fail_miri(opt: bool) { compile_fail("tests/compile-fail", &get_target(), opt); - if rustc_test_suite().is_none() { - // FIXME: Some tests disabled in rustc test suite because - // they run with a debug-assertion libstd which changes the errors. - // We should build our own libstd for testing, see - // . - compile_fail("tests/compile-fail-norustc", &get_target(), opt); - } } fn test_runner(_tests: &[&()]) { From 40d647a060d4da5a3d28d92c9a782b370ab3a4f0 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 31 Jul 2019 15:28:31 +0200 Subject: [PATCH 0968/3747] test-miri is no longer a thing --- README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/README.md b/README.md index e21ee987125e4..2eae254802c82 100644 --- a/README.md +++ b/README.md @@ -282,8 +282,7 @@ The setup for a local rustc works as follows: git clone https://github.com/rust-lang/rust/ rustc cd rustc cp config.toml.example config.toml -# Now edit `config.toml` and set `debug-assertions = true` and `test-miri = true`. -# The latter is important to build libstd with the right flags for miri. +# Now edit `config.toml` and set `debug-assertions = true`. # This step can take 30 minutes and more. ./x.py build src/rustc # If you change something, you can get a faster rebuild by doing From c4c2716f4e92550d20f6bec1c21f7ee90ddb5848 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 2 Aug 2019 08:09:22 +0200 Subject: [PATCH 0969/3747] make reborrow shallow, and fix tests for that --- src/stacked_borrows.rs | 46 +------------------ .../stacked_borrows/buggy_split_at_mut.rs | 2 +- .../return_invalid_mut_option.rs | 11 +++-- .../return_invalid_mut_tuple.rs | 5 +- .../return_invalid_shr_option.rs | 8 +++- .../return_invalid_shr_tuple.rs | 5 +- 6 files changed, 23 insertions(+), 54 deletions(-) diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 0fe42f7974fbd..4e2198a8cea07 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -12,7 +12,7 @@ use rustc::hir::{MutMutable, MutImmutable}; use rustc::mir::RetagKind; use crate::{ - InterpResult, InterpError, MiriEvalContext, HelpersEvalContextExt, Evaluator, MutValueVisitor, + InterpResult, InterpError, HelpersEvalContextExt, MemoryKind, MiriMemoryKind, RangeMap, AllocId, Pointer, Immediate, ImmTy, PlaceTy, MPlaceTy, }; @@ -632,54 +632,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } - // We need a visitor to visit all references. However, that requires - // a `MemPlace`, so we have a fast path for reference types that - // avoids allocating. + // We only reborrow "bare" references/boxes. if let Some((mutbl, protector)) = qualify(place.layout.ty, kind) { // Fast path. let val = this.read_immediate(this.place_to_op(place)?)?; let val = this.retag_reference(val, mutbl, protector)?; this.write_immediate(val, place)?; - return Ok(()); - } - let place = this.force_allocation(place)?; - - let mut visitor = RetagVisitor { ecx: this, kind }; - visitor.visit_value(place)?; - - // The actual visitor. - struct RetagVisitor<'ecx, 'mir, 'tcx> { - ecx: &'ecx mut MiriEvalContext<'mir, 'tcx>, - kind: RetagKind, - } - impl<'ecx, 'mir, 'tcx> - MutValueVisitor<'mir, 'tcx, Evaluator<'tcx>> - for - RetagVisitor<'ecx, 'mir, 'tcx> - { - type V = MPlaceTy<'tcx, Tag>; - - #[inline(always)] - fn ecx(&mut self) -> &mut MiriEvalContext<'mir, 'tcx> { - &mut self.ecx - } - - // Primitives of reference type, that is the one thing we are interested in. - fn visit_primitive(&mut self, place: MPlaceTy<'tcx, Tag>) -> InterpResult<'tcx> - { - // Cannot use `builtin_deref` because that reports *immutable* for `Box`, - // making it useless. - if let Some((mutbl, protector)) = qualify(place.layout.ty, self.kind) { - let val = self.ecx.read_immediate(place.into())?; - let val = self.ecx.retag_reference( - val, - mutbl, - protector - )?; - self.ecx.write_immediate(val, place.into())?; - } - Ok(()) - } } Ok(()) diff --git a/tests/compile-fail/stacked_borrows/buggy_split_at_mut.rs b/tests/compile-fail/stacked_borrows/buggy_split_at_mut.rs index 812dd47ef1d90..798f68fa13cc9 100644 --- a/tests/compile-fail/stacked_borrows/buggy_split_at_mut.rs +++ b/tests/compile-fail/stacked_borrows/buggy_split_at_mut.rs @@ -9,7 +9,6 @@ mod safe { assert!(mid <= len); (from_raw_parts_mut(ptr, len - mid), // BUG: should be "mid" instead of "len - mid" - //~^ ERROR borrow stack from_raw_parts_mut(ptr.offset(mid as isize), len - mid)) } } @@ -18,6 +17,7 @@ mod safe { fn main() { let mut array = [1,2,3,4]; let (a, b) = safe::split_at_mut(&mut array, 0); + //~^ ERROR borrow stack a[1] = 5; b[1] = 6; } diff --git a/tests/compile-fail/stacked_borrows/return_invalid_mut_option.rs b/tests/compile-fail/stacked_borrows/return_invalid_mut_option.rs index 2eb2df81f5f16..1cb3f3f920267 100644 --- a/tests/compile-fail/stacked_borrows/return_invalid_mut_option.rs +++ b/tests/compile-fail/stacked_borrows/return_invalid_mut_option.rs @@ -1,11 +1,16 @@ // Make sure that we cannot return a `&mut` that got already invalidated, not even in an `Option`. +// Due to shallow reborrowing, the error only surfaces when we look into the `Option`. fn foo(x: &mut (i32, i32)) -> Option<&mut i32> { let xraw = x as *mut (i32, i32); - let ret = Some(unsafe { &mut (*xraw).1 }); + let ret = unsafe { &mut (*xraw).1 }; // let-bind to avoid 2phase + let ret = Some(ret); let _val = unsafe { *xraw }; // invalidate xref - ret //~ ERROR borrow stack + ret } fn main() { - foo(&mut (1, 2)); + match foo(&mut (1, 2)) { + Some(_x) => {}, //~ ERROR borrow stack + None => {}, + } } diff --git a/tests/compile-fail/stacked_borrows/return_invalid_mut_tuple.rs b/tests/compile-fail/stacked_borrows/return_invalid_mut_tuple.rs index 8b73df4bd1ac3..fbd9a6e5d2692 100644 --- a/tests/compile-fail/stacked_borrows/return_invalid_mut_tuple.rs +++ b/tests/compile-fail/stacked_borrows/return_invalid_mut_tuple.rs @@ -1,11 +1,12 @@ // Make sure that we cannot return a `&mut` that got already invalidated, not even in a tuple. +// Due to shallow reborrowing, the error only surfaces when we look into the tuple. fn foo(x: &mut (i32, i32)) -> (&mut i32,) { let xraw = x as *mut (i32, i32); let ret = (unsafe { &mut (*xraw).1 },); let _val = unsafe { *xraw }; // invalidate xref - ret //~ ERROR borrow stack + ret } fn main() { - foo(&mut (1, 2)); + foo(&mut (1, 2)).0; //~ ERROR: borrow stack } diff --git a/tests/compile-fail/stacked_borrows/return_invalid_shr_option.rs b/tests/compile-fail/stacked_borrows/return_invalid_shr_option.rs index f3a35ca266c6b..2d8527fa3fb4f 100644 --- a/tests/compile-fail/stacked_borrows/return_invalid_shr_option.rs +++ b/tests/compile-fail/stacked_borrows/return_invalid_shr_option.rs @@ -1,11 +1,15 @@ // Make sure that we cannot return a `&` that got already invalidated, not even in an `Option`. +// Due to shallow reborrowing, the error only surfaces when we look into the `Option`. fn foo(x: &mut (i32, i32)) -> Option<&i32> { let xraw = x as *mut (i32, i32); let ret = Some(unsafe { &(*xraw).1 }); unsafe { *xraw = (42, 23) }; // unfreeze - ret //~ ERROR borrow stack + ret } fn main() { - foo(&mut (1, 2)); + match foo(&mut (1, 2)) { + Some(_x) => {}, //~ ERROR borrow stack + None => {}, + } } diff --git a/tests/compile-fail/stacked_borrows/return_invalid_shr_tuple.rs b/tests/compile-fail/stacked_borrows/return_invalid_shr_tuple.rs index 82723bade27d7..d7494d6ee653b 100644 --- a/tests/compile-fail/stacked_borrows/return_invalid_shr_tuple.rs +++ b/tests/compile-fail/stacked_borrows/return_invalid_shr_tuple.rs @@ -1,11 +1,12 @@ // Make sure that we cannot return a `&` that got already invalidated, not even in a tuple. +// Due to shallow reborrowing, the error only surfaces when we look into the tuple. fn foo(x: &mut (i32, i32)) -> (&i32,) { let xraw = x as *mut (i32, i32); let ret = (unsafe { &(*xraw).1 },); unsafe { *xraw = (42, 23) }; // unfreeze - ret //~ ERROR borrow stack + ret } fn main() { - foo(&mut (1, 2)); + foo(&mut (1, 2)).0; //~ ERROR borrow stack } From 3318657eaf0b8403317883a8cd68689d8a5c7d9a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 2 Aug 2019 08:15:52 +0200 Subject: [PATCH 0970/3747] test Ref/RefMut protector interactions --- tests/run-pass/refcell.rs | 33 ----------- tests/run-pass/stacked-borrows/refcell.rs | 68 +++++++++++++++++++++++ 2 files changed, 68 insertions(+), 33 deletions(-) delete mode 100644 tests/run-pass/refcell.rs create mode 100644 tests/run-pass/stacked-borrows/refcell.rs diff --git a/tests/run-pass/refcell.rs b/tests/run-pass/refcell.rs deleted file mode 100644 index 93cef1572a3e1..0000000000000 --- a/tests/run-pass/refcell.rs +++ /dev/null @@ -1,33 +0,0 @@ -use std::cell::RefCell; - -fn main() { - let c = RefCell::new(42); - { - let s1 = c.borrow(); - let _x: i32 = *s1; - let s2 = c.borrow(); - let _x: i32 = *s1; - let _y: i32 = *s2; - let _x: i32 = *s1; - let _y: i32 = *s2; - } - { - let mut m = c.borrow_mut(); - let _z: i32 = *m; - { - let s: &i32 = &*m; - let _x = *s; - } - *m = 23; - let _z: i32 = *m; - } - { - let s1 = c.borrow(); - let _x: i32 = *s1; - let s2 = c.borrow(); - let _x: i32 = *s1; - let _y: i32 = *s2; - let _x: i32 = *s1; - let _y: i32 = *s2; - } -} diff --git a/tests/run-pass/stacked-borrows/refcell.rs b/tests/run-pass/stacked-borrows/refcell.rs new file mode 100644 index 0000000000000..0939a666193e8 --- /dev/null +++ b/tests/run-pass/stacked-borrows/refcell.rs @@ -0,0 +1,68 @@ +use std::cell::{RefCell, Ref, RefMut}; + +fn main() { + basic(); + ref_protector(); + ref_mut_protector(); +} + +fn basic() { + let c = RefCell::new(42); + { + let s1 = c.borrow(); + let _x: i32 = *s1; + let s2 = c.borrow(); + let _x: i32 = *s1; + let _y: i32 = *s2; + let _x: i32 = *s1; + let _y: i32 = *s2; + } + { + let mut m = c.borrow_mut(); + let _z: i32 = *m; + { + let s: &i32 = &*m; + let _x = *s; + } + *m = 23; + let _z: i32 = *m; + } + { + let s1 = c.borrow(); + let _x: i32 = *s1; + let s2 = c.borrow(); + let _x: i32 = *s1; + let _y: i32 = *s2; + let _x: i32 = *s1; + let _y: i32 = *s2; + } +} + +// Adding a Stacked Borrows protector for `Ref` would break this +fn ref_protector() { + fn break_it(rc: &RefCell, r: Ref<'_, i32>) { + // `r` has a shared reference, it is passed in as argument and hence + // a protector is added that marks this memory as read-only for the entire + // duration of this function. + drop(r); + // *oops* here we can mutate that memory. + *rc.borrow_mut() = 2; + } + + let rc = RefCell::new(0); + break_it(&rc, rc.borrow()) +} + +fn ref_mut_protector() { + fn break_it(rc: &RefCell, r: RefMut<'_, i32>) { + // `r` has a shared reference, it is passed in as argument and hence + // a protector is added that marks this memory as inaccessible for the entire + // duration of this function + drop(r); + // *oops* here we can mutate that memory. + *rc.borrow_mut() = 2; + } + + let rc = RefCell::new(0); + break_it(&rc, rc.borrow_mut()) +} From 30fb027f33e3c97489a7d7049d70ee876ac38c73 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 2 Aug 2019 08:38:22 +0200 Subject: [PATCH 0971/3747] comment --- src/stacked_borrows.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 4e2198a8cea07..c276f83de660e 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -633,6 +633,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // We only reborrow "bare" references/boxes. + // Not traversing into fields helps with , + // but might also cost us optimization and analyses. We will have to experiment more with this. if let Some((mutbl, protector)) = qualify(place.layout.ty, kind) { // Fast path. let val = this.read_immediate(this.place_to_op(place)?)?; From 2973063fa32155873aaeb37a7399d3c592afda5c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 2 Aug 2019 14:26:15 +0200 Subject: [PATCH 0972/3747] test dangling ZST deref --- tests/compile-fail/dangling_zst_deref.rs | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 tests/compile-fail/dangling_zst_deref.rs diff --git a/tests/compile-fail/dangling_zst_deref.rs b/tests/compile-fail/dangling_zst_deref.rs new file mode 100644 index 0000000000000..0a8480675f3d4 --- /dev/null +++ b/tests/compile-fail/dangling_zst_deref.rs @@ -0,0 +1,7 @@ +fn main() { + let p = { + let b = Box::new(42); + &*b as *const i32 as *const () + }; + let _x = unsafe { *p }; //~ ERROR dangling pointer was dereferenced +} From 0dab3d5ee167aadaebe4b32b035f6b3dc581538d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 2 Aug 2019 18:02:54 +0200 Subject: [PATCH 0973/3747] honor CARGO env var (for rustc bootstrap) --- src/bin/cargo-miri.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index b46742efe72ae..8dbb7573ba914 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -231,7 +231,14 @@ fn setup(ask_user: bool) { } else { println!("Installing xargo: `cargo install xargo -f`"); } - if !Command::new("cargo").args(&["install", "xargo", "-f"]).status().unwrap().success() { + + let mut cargo = if let Ok(val) = std::env::var("CARGO") { + // In rustc bootstrap, an env var tells us where to find cargo. + Command::new(val) + } else { + Command::new("cargo") + }; + if !cargo.args(&["install", "xargo", "-f"]).status().unwrap().success() { show_error(format!("Failed to install xargo")); } } From ff2001040f06bda894fb512684e34ea12deade6e Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Fri, 2 Aug 2019 13:42:10 -0500 Subject: [PATCH 0974/3747] Add shim for ldexp --- src/shims/foreign_items.rs | 12 ++++++++++-- tests/run-pass/intrinsics-math.rs | 4 ++++ 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index bcfcda2fd01c5..3321329478234 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -603,7 +603,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx }; this.write_scalar(Scalar::from_u64(n.to_bits()), dest)?; } - + // underscore case for windows + "_ldexp" | "ldexp" => { + // FIXME: Using host floats. + let x = f64::from_bits(this.read_scalar(args[0])?.to_u64()?); + let exp = this.read_scalar(args[1])?.to_i32()?; + // FIXME: We should use cmath if there are any imprecisions. + let n = x * 2.0f64.powi(exp); + this.write_scalar(Scalar::from_u64(n.to_bits()), dest)?; + } // Some things needed for `sys::thread` initialization to go through. "signal" | "sigaction" | "sigaltstack" => { this.write_scalar(Scalar::from_int(0, dest.layout.size), dest)?; @@ -973,4 +981,4 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } return Ok(None); } -} \ No newline at end of file +} diff --git a/tests/run-pass/intrinsics-math.rs b/tests/run-pass/intrinsics-math.rs index 20c0f67494886..9a7a70bd00925 100644 --- a/tests/run-pass/intrinsics-math.rs +++ b/tests/run-pass/intrinsics-math.rs @@ -85,4 +85,8 @@ pub fn main() { assert_approx_eq!(1.0f32.tan(), 1.557408f32); assert_approx_eq!(1.0f64.tan(), 1.557408f64); + extern { + fn ldexp(x: f64, n: i32) -> f64; + } + unsafe { assert_approx_eq!(ldexp(0.65f64, 3i32), 5.2f64); } } From 8071034b93ab1c363e45b72a5d3e53432c52f2b0 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 3 Aug 2019 10:25:55 +0200 Subject: [PATCH 0975/3747] fix for error refactoring --- src/eval.rs | 6 ++--- src/helpers.rs | 2 +- src/intptrcast.rs | 14 +++++------ src/machine.rs | 2 +- src/operator.rs | 29 +++++++++++----------- src/shims/dlsym.rs | 2 +- src/shims/foreign_items.rs | 49 +++++++++++++++++++------------------- src/shims/intrinsics.rs | 22 ++++++++--------- src/shims/tls.rs | 10 ++++---- src/stacked_borrows.rs | 18 +++++++------- 10 files changed, 77 insertions(+), 77 deletions(-) diff --git a/src/eval.rs b/src/eval.rs index e688d35947186..837757c1ad3b5 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -41,7 +41,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( let main_mir = ecx.load_mir(main_instance.def)?; if !main_mir.return_ty().is_unit() || main_mir.arg_count != 0 { - return err!(Unimplemented( + throw_unsup!(Unimplemented( "miri does not support main functions without `fn()` type signatures" .to_owned(), )); @@ -60,7 +60,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( let start_mir = ecx.load_mir(start_instance.def)?; if start_mir.arg_count != 3 { - return err!(AbiViolation(format!( + throw_unsup!(AbiViolation(format!( "'start' lang item should have three arguments, but has {}", start_mir.arg_count ))); @@ -200,7 +200,7 @@ pub fn eval_main<'tcx>( // Special treatment for some error kinds let msg = match e.kind { InterpError::Exit(code) => std::process::exit(code), - InterpError::NoMirFor(..) => + err_unsup!(NoMirFor(..)) => format!("{}. Did you set `MIRI_SYSROOT` to a Miri-enabled sysroot? You can prepare one with `cargo miri setup`.", e), _ => e.to_string() }; diff --git a/src/helpers.rs b/src/helpers.rs index 3857020a71f81..d29cc021a1b08 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -42,7 +42,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx }) .ok_or_else(|| { let path = path.iter().map(|&s| s.to_owned()).collect(); - InterpError::PathNotFound(path).into() + err_unsup!(PathNotFound(path)).into() }) } diff --git a/src/intptrcast.rs b/src/intptrcast.rs index 1247150cc1199..b1e89f3819ae2 100644 --- a/src/intptrcast.rs +++ b/src/intptrcast.rs @@ -43,19 +43,19 @@ impl<'mir, 'tcx> GlobalState { memory: &Memory<'mir, 'tcx, Evaluator<'tcx>>, ) -> InterpResult<'tcx, Pointer> { if int == 0 { - return err!(InvalidNullPointerUsage); + throw_unsup!(InvalidNullPointerUsage); } let global_state = memory.extra.intptrcast.borrow(); - match global_state.int_to_ptr_map.binary_search_by_key(&int, |(addr, _)| *addr) { + Ok(match global_state.int_to_ptr_map.binary_search_by_key(&int, |(addr, _)| *addr) { Ok(pos) => { let (_, alloc_id) = global_state.int_to_ptr_map[pos]; // `int` is equal to the starting address for an allocation, the offset should be // zero. The pointer is untagged because it was created from a cast - Ok(Pointer::new_with_tag(alloc_id, Size::from_bytes(0), Tag::Untagged)) + Pointer::new_with_tag(alloc_id, Size::from_bytes(0), Tag::Untagged) }, - Err(0) => err!(DanglingPointerDeref), + Err(0) => throw_unsup!(DanglingPointerDeref), Err(pos) => { // This is the largest of the adresses smaller than `int`, // i.e. the greatest lower bound (glb) @@ -65,12 +65,12 @@ impl<'mir, 'tcx> GlobalState { // If the offset exceeds the size of the allocation, this access is illegal if offset <= memory.get(alloc_id)?.bytes.len() as u64 { // This pointer is untagged because it was created from a cast - Ok(Pointer::new_with_tag(alloc_id, Size::from_bytes(offset), Tag::Untagged)) + Pointer::new_with_tag(alloc_id, Size::from_bytes(offset), Tag::Untagged) } else { - err!(DanglingPointerDeref) + throw_unsup!(DanglingPointerDeref) } } - } + }) } pub fn ptr_to_int( diff --git a/src/machine.rs b/src/machine.rs index d50afec253e80..cdac9fb815cc7 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -247,7 +247,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { let data = vec![0; size.bytes() as usize]; Allocation::from_bytes(&data, tcx.data_layout.pointer_align.abi) } - _ => return err!(Unimplemented( + _ => throw_unsup!(Unimplemented( format!("can't access foreign static: {}", link_name), )), }; diff --git a/src/operator.rs b/src/operator.rs index 1ce485682c770..dfe58037789c2 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -94,7 +94,7 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { let right = right.to_scalar()?; debug_assert!(left.is_ptr() || right.is_ptr() || bin_op == Offset); - match bin_op { + Ok(match bin_op { Offset => { let pointee_ty = left_layout.ty .builtin_deref(true) @@ -105,7 +105,7 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { pointee_ty, right.to_isize(self)?, )?; - Ok((ptr, false)) + (ptr, false) } // These need both to be pointer, and fail if they are not in the same location Lt | Le | Gt | Ge | Sub if left.is_ptr() && right.is_ptr() => { @@ -130,10 +130,10 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { } _ => bug!("We already established it has to be one of these operators."), }; - Ok((Scalar::from_bool(res), false)) + (Scalar::from_bool(res), false) } else { // Both are pointers, but from different allocations. - err!(InvalidPointerMath) + throw_unsup!(InvalidPointerMath) } } Gt | Ge if left.is_ptr() && right.is_bits() => { @@ -151,10 +151,10 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { }; if result { // Definitely true! - Ok((Scalar::from_bool(true), false)) + (Scalar::from_bool(true), false) } else { // Sorry, can't tell. - err!(InvalidPointerMath) + throw_unsup!(InvalidPointerMath) } } // These work if the left operand is a pointer, and the right an integer @@ -165,7 +165,7 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { left.to_ptr().expect("we checked is_ptr"), right.to_bits(self.memory().pointer_size()).expect("we checked is_bits"), right_layout.abi.is_signed(), - ) + )? } // Commutative operators also work if the integer is on the left Add | BitAnd if left.is_bits() && right.is_ptr() => { @@ -175,11 +175,11 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { right.to_ptr().expect("we checked is_ptr"), left.to_bits(self.memory().pointer_size()).expect("we checked is_bits"), left_layout.abi.is_signed(), - ) + )? } // Nothing else works - _ => err!(InvalidPointerMath), - } + _ => throw_unsup!(InvalidPointerMath), + }) } fn ptr_eq( @@ -248,7 +248,7 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { let v = Scalar::from_uint((left.offset.bytes() as u128) & right, ptr_size); (v, false) } else { - return err!(ReadPointerAsBytes); + throw_unsup!(ReadPointerAsBytes); } } @@ -271,7 +271,7 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { false, ) } else { - return err!(ReadPointerAsBytes); + throw_unsup!(ReadPointerAsBytes); } } @@ -283,7 +283,7 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { right, if signed { "signed" } else { "unsigned" } ); - return err!(Unimplemented(msg)); + throw_unsup!(Unimplemented(msg)); } }) } @@ -298,12 +298,11 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { pointee_ty: Ty<'tcx>, offset: i64, ) -> InterpResult<'tcx, Scalar> { - use rustc::mir::interpret::InterpError::Panic; // FIXME: assuming here that type size is less than `i64::max_value()`. let pointee_size = self.layout_of(pointee_ty)?.size.bytes() as i64; let offset = offset .checked_mul(pointee_size) - .ok_or_else(|| Panic(PanicMessage::Overflow(mir::BinOp::Mul)))?; + .ok_or_else(|| err_panic!(Overflow(mir::BinOp::Mul)))?; // Now let's see what kind of pointer this is. let ptr = if offset == 0 { match ptr { diff --git a/src/shims/dlsym.rs b/src/shims/dlsym.rs index 602d8064e82ef..005493096248a 100644 --- a/src/shims/dlsym.rs +++ b/src/shims/dlsym.rs @@ -16,7 +16,7 @@ impl Dlsym { "getentropy" => Some(GetEntropy), "__pthread_get_minstack" => None, _ => - return err!(Unimplemented(format!( + throw_unsup!(Unimplemented(format!( "Unsupported dlsym: {}", name ))), }) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index bcfcda2fd01c5..12baa79916ab6 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -128,7 +128,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx dest: Option>, ret: Option, ) -> InterpResult<'tcx> { - use rustc::mir::interpret::InterpError::Panic; let this = self.eval_context_mut(); let attrs = this.tcx.get_attrs(def_id); let link_name = match attr::first_attr_value_str_by_name(&attrs, sym::link_name) { @@ -142,15 +141,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // First: functions that diverge. match link_name { "__rust_start_panic" | "panic_impl" => { - return err!(MachineError("the evaluated program panicked".to_string())); + throw_unsup!(MachineError("the evaluated program panicked".to_string())); } "exit" | "ExitProcess" => { // it's really u32 for ExitProcess, but we have to put it into the `Exit` error variant anyway let code = this.read_scalar(args[0])?.to_i32()?; - return err!(Exit(code)); + return Err(InterpError::Exit(code).into()); } _ => if dest.is_none() { - return err!(Unimplemented( + throw_unsup!(Unimplemented( format!("can't call diverging foreign function: {}", link_name), )); } @@ -168,7 +167,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "calloc" => { let items = this.read_scalar(args[0])?.to_usize(this)?; let len = this.read_scalar(args[1])?.to_usize(this)?; - let size = items.checked_mul(len).ok_or_else(|| Panic(PanicMessage::Overflow(mir::BinOp::Mul)))?; + let size = items.checked_mul(len).ok_or_else(|| err_panic!(Overflow(mir::BinOp::Mul)))?; let res = this.malloc(size, /*zero_init:*/ true, MiriMemoryKind::C); this.write_scalar(res, dest)?; } @@ -178,13 +177,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let size = this.read_scalar(args[2])?.to_usize(this)?; // Align must be power of 2, and also at least ptr-sized (POSIX rules). if !align.is_power_of_two() { - return err!(HeapAllocNonPowerOfTwoAlignment(align)); + throw_unsup!(HeapAllocNonPowerOfTwoAlignment(align)); } /* FIXME: This check is disabled because rustc violates it. See . if align < this.pointer_size().bytes() { - return err!(MachineError(format!( + throw_unsup!(MachineError(format!( "posix_memalign: alignment must be at least the size of a pointer, but is {}", align, ))); @@ -217,10 +216,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let size = this.read_scalar(args[0])?.to_usize(this)?; let align = this.read_scalar(args[1])?.to_usize(this)?; if size == 0 { - return err!(HeapAllocZeroBytes); + throw_unsup!(HeapAllocZeroBytes); } if !align.is_power_of_two() { - return err!(HeapAllocNonPowerOfTwoAlignment(align)); + throw_unsup!(HeapAllocNonPowerOfTwoAlignment(align)); } let ptr = this.memory_mut() .allocate( @@ -234,10 +233,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let size = this.read_scalar(args[0])?.to_usize(this)?; let align = this.read_scalar(args[1])?.to_usize(this)?; if size == 0 { - return err!(HeapAllocZeroBytes); + throw_unsup!(HeapAllocZeroBytes); } if !align.is_power_of_two() { - return err!(HeapAllocNonPowerOfTwoAlignment(align)); + throw_unsup!(HeapAllocNonPowerOfTwoAlignment(align)); } let ptr = this.memory_mut() .allocate( @@ -256,10 +255,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let old_size = this.read_scalar(args[1])?.to_usize(this)?; let align = this.read_scalar(args[2])?.to_usize(this)?; if old_size == 0 { - return err!(HeapAllocZeroBytes); + throw_unsup!(HeapAllocZeroBytes); } if !align.is_power_of_two() { - return err!(HeapAllocNonPowerOfTwoAlignment(align)); + throw_unsup!(HeapAllocNonPowerOfTwoAlignment(align)); } let ptr = this.force_ptr(ptr)?; this.memory_mut().deallocate( @@ -274,10 +273,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let align = this.read_scalar(args[2])?.to_usize(this)?; let new_size = this.read_scalar(args[3])?.to_usize(this)?; if old_size == 0 || new_size == 0 { - return err!(HeapAllocZeroBytes); + throw_unsup!(HeapAllocZeroBytes); } if !align.is_power_of_two() { - return err!(HeapAllocNonPowerOfTwoAlignment(align)); + throw_unsup!(HeapAllocNonPowerOfTwoAlignment(align)); } let align = Align::from_bytes(align).unwrap(); let new_ptr = this.memory_mut().reallocate( @@ -310,7 +309,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_uint(len, dest.layout.size), dest)?; } id => { - return err!(Unimplemented( + throw_unsup!(Unimplemented( format!("miri does not support syscall ID {}", id), )) } @@ -361,10 +360,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let mut args = this.frame().body.args_iter(); let arg_local = args.next().ok_or_else(|| - InterpError::AbiViolation( + err_unsup!(AbiViolation( "Argument to __rust_maybe_catch_panic does not take enough arguments." .to_owned(), - ), + )), )?; let arg_dest = this.local_place(arg_local)?; this.write_scalar(data, arg_dest)?; @@ -633,7 +632,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if let Some(result) = result { this.write_scalar(result, dest)?; } else { - return err!(Unimplemented( + throw_unsup!(Unimplemented( format!("Unimplemented sysconf name: {}", name), )); } @@ -662,14 +661,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // This is `libc::pthread_key_t`. let key_type = args[0].layout.ty .builtin_deref(true) - .ok_or_else(|| InterpError::AbiViolation("wrong signature used for `pthread_key_create`: first argument must be a raw pointer.".to_owned()))? + .ok_or_else(|| err_unsup!( + AbiViolation("wrong signature used for `pthread_key_create`: first argument must be a raw pointer.".to_owned()) + ))? .ty; let key_layout = this.layout_of(key_type)?; // Create key and write it into the memory where `key_ptr` wants it. let key = this.machine.tls.create_tls_key(dtor) as u128; if key_layout.size.bits() < 128 && key >= (1u128 << key_layout.size.bits() as u128) { - return err!(OutOfTls); + throw_unsup!(OutOfTls); } let key_ptr = this.memory().check_ptr_access(key_ptr, key_layout.size, key_layout.align.abi)? @@ -728,7 +729,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // We don't support threading. (Also for Windows.) "pthread_create" | "CreateThread" => { - return err!(Unimplemented(format!("Miri does not support threading"))); + throw_unsup!(Unimplemented(format!("Miri does not support threading"))); } // Stub out calls for condvar, mutex and rwlock, to just return `0`. @@ -869,7 +870,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // 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); + throw_unsup!(OutOfTls); } this.write_scalar(Scalar::from_uint(key, dest.layout.size), dest)?; } @@ -947,7 +948,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // We can't execute anything else. _ => { - return err!(Unimplemented( + throw_unsup!(Unimplemented( format!("can't call foreign function: {}", link_name), )); } diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 6038950bad9f6..71027a65b0545 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -44,7 +44,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "assume" => { let cond = this.read_scalar(args[0])?.to_bool()?; if !cond { - return err!(AssumptionNotHeld); + throw_unsup!(AssumptionNotHeld); } } @@ -133,7 +133,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "atomic_xsub_relaxed" => { let ptr = this.deref_operand(args[0])?; if !ptr.layout.ty.is_integral() { - return err!(Unimplemented(format!("Atomic arithmetic operations only work on integer types"))); + throw_unsup!(Unimplemented(format!("Atomic arithmetic operations only work on integer types"))); } let rhs = this.read_immediate(args[1])?; let old = this.read_immediate(ptr.into())?; @@ -278,11 +278,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if this.binary_op(mir::BinOp::Rem, a, b)?.0.to_bits(dest.layout.size)? != 0 { // Check if `b` is -1, which is the "min_value / -1" case. let minus1 = Scalar::from_int(-1, dest.layout.size); - return if b.to_scalar().unwrap() == minus1 { - err!(Intrinsic(format!("exact_div: result of dividing MIN by -1 cannot be represented"))) + return Err(if b.to_scalar().unwrap() == minus1 { + err_unsup!(Intrinsic(format!("exact_div: result of dividing MIN by -1 cannot be represented"))) } else { - err!(Intrinsic(format!("exact_div: {:?} cannot be divided by {:?} without remainder", *a, *b))) - }; + err_unsup!(Intrinsic(format!("exact_div: {:?} cannot be divided by {:?} without remainder", *a, *b))) + }.into()); } this.binop_ignore_overflow(mir::BinOp::Div, a, b, dest)?; }, @@ -350,7 +350,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let ty = substs.type_at(0); let layout = this.layout_of(ty)?; if layout.abi.is_uninhabited() { - return err!(Intrinsic(format!("Trying to instantiate uninhabited type {}", ty))) + throw_unsup!(Intrinsic(format!("Trying to instantiate uninhabited type {}", ty))) } } @@ -444,7 +444,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let r = this.read_immediate(args[1])?; let rval = r.to_scalar()?.to_bits(args[1].layout.size)?; if rval == 0 { - return err!(Intrinsic(format!("Division by 0 in unchecked_div"))); + throw_unsup!(Intrinsic(format!("Division by 0 in unchecked_div"))); } this.binop_ignore_overflow( mir::BinOp::Div, @@ -459,7 +459,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let r = this.read_immediate(args[1])?; let rval = r.to_scalar()?.to_bits(args[1].layout.size)?; if rval == 0 { - return err!(Intrinsic(format!("Division by 0 in unchecked_rem"))); + throw_unsup!(Intrinsic(format!("Division by 0 in unchecked_rem"))); } this.binop_ignore_overflow( mir::BinOp::Rem, @@ -480,7 +480,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx }; let (res, overflowed) = this.binary_op(op, l, r)?; if overflowed { - return err!(Intrinsic(format!("Overflowing arithmetic in {}", intrinsic_name.get()))); + throw_unsup!(Intrinsic(format!("Overflowing arithmetic in {}", intrinsic_name.get()))); } this.write_scalar(res, dest)?; } @@ -504,7 +504,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } - name => return err!(Unimplemented(format!("unimplemented intrinsic: {}", name))), + name => throw_unsup!(Unimplemented(format!("unimplemented intrinsic: {}", name))), } Ok(()) diff --git a/src/shims/tls.rs b/src/shims/tls.rs index abe6dd958693c..145d2b3e78915 100644 --- a/src/shims/tls.rs +++ b/src/shims/tls.rs @@ -6,7 +6,7 @@ use rustc_target::abi::LayoutOf; use rustc::{ty, ty::layout::HasDataLayout}; use crate::{ - InterpResult, InterpError, StackPopCleanup, + InterpResult, StackPopCleanup, MPlaceTy, Scalar, Tag, HelpersEvalContextExt, }; @@ -64,7 +64,7 @@ impl<'tcx> TlsData<'tcx> { trace!("TLS key {} removed", key); Ok(()) } - None => err!(TlsOutOfBounds), + None => throw_unsup!(TlsOutOfBounds), } } @@ -78,7 +78,7 @@ impl<'tcx> TlsData<'tcx> { trace!("TLS key {} loaded: {:?}", key, data); Ok(data.unwrap_or_else(|| Scalar::ptr_null(cx).into())) } - None => err!(TlsOutOfBounds), + None => throw_unsup!(TlsOutOfBounds), } } @@ -89,7 +89,7 @@ impl<'tcx> TlsData<'tcx> { *data = new_data; Ok(()) } - None => err!(TlsOutOfBounds), + None => throw_unsup!(TlsOutOfBounds), } } @@ -158,7 +158,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx StackPopCleanup::None { cleanup: true }, )?; let arg_local = this.frame().body.args_iter().next().ok_or_else( - || InterpError::AbiViolation("TLS dtor does not take enough arguments.".to_owned()), + || err_unsup!(AbiViolation("TLS dtor does not take enough arguments.".to_owned())), )?; let dest = this.local_place(arg_local)?; this.write_scalar(ptr, dest)?; diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index c276f83de660e..5ef934b9922b3 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -12,7 +12,7 @@ use rustc::hir::{MutMutable, MutImmutable}; use rustc::mir::RetagKind; use crate::{ - InterpResult, InterpError, HelpersEvalContextExt, + InterpResult, HelpersEvalContextExt, MemoryKind, MiriMemoryKind, RangeMap, AllocId, Pointer, Immediate, ImmTy, PlaceTy, MPlaceTy, }; @@ -273,12 +273,12 @@ impl<'tcx> Stack { if let Some(call) = item.protector { if global.is_active(call) { if let Some(tag) = tag { - return err!(MachineError(format!( + throw_unsup!(MachineError(format!( "not granting access to tag {:?} because incompatible item is protected: {:?}", tag, item ))); } else { - return err!(MachineError(format!( + throw_unsup!(MachineError(format!( "deallocating while item is protected: {:?}", item ))); } @@ -299,10 +299,10 @@ impl<'tcx> Stack { // Step 1: Find granting item. let granting_idx = self.find_granting(access, tag) - .ok_or_else(|| InterpError::MachineError(format!( + .ok_or_else(|| err_unsup!(MachineError(format!( "no item granting {} to tag {:?} found in borrow stack", access, tag, - )))?; + ))))?; // Step 2: Remove incompatible items above them. Make sure we do not remove protected // items. Behavior differs for reads and writes. @@ -346,10 +346,10 @@ impl<'tcx> Stack { ) -> InterpResult<'tcx> { // Step 1: Find granting item. self.find_granting(AccessKind::Write, tag) - .ok_or_else(|| InterpError::MachineError(format!( + .ok_or_else(|| err_unsup!(MachineError(format!( "no item granting write access for deallocation to tag {:?} found in borrow stack", tag, - )))?; + ))))?; // Step 2: Remove all items. Also checks for protectors. for item in self.borrows.drain(..).rev() { @@ -378,9 +378,9 @@ impl<'tcx> Stack { // Now we figure out which item grants our parent (`derived_from`) this kind of access. // We use that to determine where to put the new item. let granting_idx = self.find_granting(access, derived_from) - .ok_or_else(|| InterpError::MachineError(format!( + .ok_or_else(|| err_unsup!(MachineError(format!( "trying to reborrow for {:?}, but parent tag {:?} does not have an appropriate item in the borrow stack", new.perm, derived_from, - )))?; + ))))?; // Compute where to put the new item. // Either way, we ensure that we insert the new item in a way such that between From 312b546026c59549e860cf939bc20f1117f5c93f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 3 Aug 2019 10:26:15 +0200 Subject: [PATCH 0976/3747] bump Rust --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 5178503f10412..8fbf6d7425bb1 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -8b94e9e9188b65df38a5f1ae723617dc2dfb3155 +d7270712cb446aad0817040bbca73a8d024f67b0 From e71ca965b9bfda52f6720e718a631c324c35b196 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 3 Aug 2019 13:53:02 +0200 Subject: [PATCH 0977/3747] also let bootstrap tell us where to find xargo --- src/bin/cargo-miri.rs | 35 +++++++++++++++++++++++------------ 1 file changed, 23 insertions(+), 12 deletions(-) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 8dbb7573ba914..351da554b7bfa 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -162,8 +162,26 @@ fn test_sysroot_consistency() { } } +fn cargo() -> Command { + if let Ok(val) = std::env::var("CARGO") { + // Bootstrap tells us where to find cargo + Command::new(val) + } else { + Command::new("cargo") + } +} + +fn xargo() -> Command { + if let Ok(val) = std::env::var("XARGO") { + // Bootstrap tells us where to find xargo + Command::new(val) + } else { + Command::new("xargo") + } +} + fn xargo_version() -> Option<(u32, u32, u32)> { - let out = Command::new("xargo").arg("--version").output().ok()?; + let out = xargo().arg("--version").output().ok()?; if !out.status.success() { return None; } @@ -224,21 +242,14 @@ fn setup(ask_user: bool) { } // First, we need xargo. - let xargo = xargo_version(); - if xargo.map_or(true, |v| v < (0, 3, 14)) { + if xargo_version().map_or(true, |v| v < (0, 3, 14)) { if ask_user { ask("It seems you do not have a recent enough xargo installed. I will run `cargo install xargo -f`. Proceed?"); } else { println!("Installing xargo: `cargo install xargo -f`"); } - let mut cargo = if let Ok(val) = std::env::var("CARGO") { - // In rustc bootstrap, an env var tells us where to find cargo. - Command::new(val) - } else { - Command::new("cargo") - }; - if !cargo.args(&["install", "xargo", "-f"]).status().unwrap().success() { + if !cargo().args(&["install", "xargo", "-f"]).status().unwrap().success() { show_error(format!("Failed to install xargo")); } } @@ -294,7 +305,7 @@ path = "lib.rs" // Run xargo. let target = get_arg_flag_value("--target"); let print_env = !ask_user && has_arg_flag("--env"); // whether we just print the necessary environment variable - let mut command = Command::new("xargo"); + let mut command = xargo(); command.arg("build").arg("-q") .current_dir(&dir) .env("RUSTFLAGS", miri::miri_default_args().join(" ")) @@ -383,7 +394,7 @@ fn in_cargo_miri() { // Now we run `cargo rustc $FLAGS $ARGS`, giving the user the // change to add additional arguments. `FLAGS` is set to identify // this target. The user gets to control what gets actually passed to Miri. - let mut cmd = Command::new("cargo"); + let mut cmd = cargo(); cmd.arg("rustc"); match (subcommand, kind.as_str()) { (MiriCommand::Run, "bin") => { From bb6a91dc949218c4cc4990cc6f50bbdd58df7648 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 24 Jul 2019 16:17:49 +0200 Subject: [PATCH 0978/3747] adjust for ptr_op now being called type-based --- src/machine.rs | 4 ++-- src/operator.rs | 48 ++++++++++++++++++++++-------------------------- 2 files changed, 24 insertions(+), 28 deletions(-) diff --git a/src/machine.rs b/src/machine.rs index cdac9fb815cc7..7fa79d822c35b 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -179,13 +179,13 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { } #[inline(always)] - fn ptr_op( + fn binary_ptr_op( ecx: &rustc_mir::interpret::InterpCx<'mir, 'tcx, Self>, bin_op: mir::BinOp, left: ImmTy<'tcx, Tag>, right: ImmTy<'tcx, Tag>, ) -> InterpResult<'tcx, (Scalar, bool)> { - ecx.ptr_op(bin_op, left, right) + ecx.binary_ptr_op(bin_op, left, right) } fn box_alloc( diff --git a/src/operator.rs b/src/operator.rs index dfe58037789c2..d564b5f19f95b 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -9,7 +9,7 @@ pub trait EvalContextExt<'tcx> { ptr: Pointer ) -> InterpResult<'tcx>; - fn ptr_op( + fn binary_ptr_op( &self, bin_op: mir::BinOp, left: ImmTy<'tcx, Tag>, @@ -46,7 +46,7 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { ptr.check_in_alloc(size, CheckInAllocMsg::InboundsTest) } - fn ptr_op( + fn binary_ptr_op( &self, bin_op: mir::BinOp, left: ImmTy<'tcx, Tag>, @@ -56,21 +56,6 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { trace!("ptr_op: {:?} {:?} {:?}", *left, bin_op, *right); - // Treat everything of integer *type* at integer *value*. - if left.layout.ty.is_integral() { - // This is actually an integer operation, so dispatch back to the core engine. - // TODO: Once intptrcast is the default, librustc_mir should never even call us - // for integer types. - assert!(right.layout.ty.is_integral()); - let l_bits = self.force_bits(left.imm.to_scalar()?, left.layout.size)?; - let r_bits = self.force_bits(right.imm.to_scalar()?, right.layout.size)?; - - let left = ImmTy::from_scalar(Scalar::from_uint(l_bits, left.layout.size), left.layout); - let right = ImmTy::from_scalar(Scalar::from_uint(r_bits, left.layout.size), right.layout); - - return self.binary_op(bin_op, left, right); - } - // Operations that support fat pointers match bin_op { Eq | Ne => { @@ -92,7 +77,6 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { let left = left.to_scalar()?; let right_layout = right.layout; let right = right.to_scalar()?; - debug_assert!(left.is_ptr() || right.is_ptr() || bin_op == Offset); Ok(match bin_op { Offset => { @@ -109,8 +93,8 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { } // These need both to be pointer, and fail if they are not in the same location Lt | Le | Gt | Ge | Sub if left.is_ptr() && right.is_ptr() => { - let left = left.to_ptr().expect("we checked is_ptr"); - let right = right.to_ptr().expect("we checked is_ptr"); + let left = left.assert_ptr(); + let right = right.assert_ptr(); if left.alloc_id == right.alloc_id { let res = match bin_op { Lt => left.offset < right.offset, @@ -136,10 +120,22 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { throw_unsup!(InvalidPointerMath) } } + Lt | Le | Gt | Ge if left.is_bits() && right.is_bits() => { + let left = left.assert_bits(self.memory().pointer_size()); + let right = right.assert_bits(self.memory().pointer_size()); + let res = match bin_op { + Lt => left < right, + Le => left <= right, + Gt => left > right, + Ge => left >= right, + _ => bug!("We already established it has to be one of these operators."), + }; + Ok((Scalar::from_bool(res), false)) + } Gt | Ge if left.is_ptr() && right.is_bits() => { // "ptr >[=] integer" can be tested if the integer is small enough. - let left = left.to_ptr().expect("we checked is_ptr"); - let right = right.to_bits(self.memory().pointer_size()).expect("we checked is_bits"); + let left = left.assert_ptr(); + let right = right.assert_bits(self.memory().pointer_size()); let (_alloc_size, alloc_align) = self.memory() .get_size_and_align(left.alloc_id, AllocCheck::MaybeDead) .expect("alloc info with MaybeDead cannot fail"); @@ -162,8 +158,8 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { // Cast to i128 is fine as we checked the kind to be ptr-sized self.ptr_int_arithmetic( bin_op, - left.to_ptr().expect("we checked is_ptr"), - right.to_bits(self.memory().pointer_size()).expect("we checked is_bits"), + left.assert_ptr(), + right.assert_bits(self.memory().pointer_size()), right_layout.abi.is_signed(), )? } @@ -172,8 +168,8 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { // This is a commutative operation, just swap the operands self.ptr_int_arithmetic( bin_op, - right.to_ptr().expect("we checked is_ptr"), - left.to_bits(self.memory().pointer_size()).expect("we checked is_bits"), + right.assert_ptr(), + left.assert_bits(self.memory().pointer_size()), left_layout.abi.is_signed(), )? } From 82da68c5caca6b534d77c01cbcf9d1ed0a6ef496 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 24 Jul 2019 16:22:48 +0200 Subject: [PATCH 0979/3747] implement all ptr comparisons through integer casts --- src/operator.rs | 223 +++++------------------------------------------- 1 file changed, 23 insertions(+), 200 deletions(-) diff --git a/src/operator.rs b/src/operator.rs index d564b5f19f95b..f047f4f4fad01 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -1,4 +1,4 @@ -use rustc::ty::{Ty, layout::{Size, LayoutOf}}; +use rustc::ty::{Ty, layout::LayoutOf}; use rustc::mir; use crate::*; @@ -16,14 +16,6 @@ pub trait EvalContextExt<'tcx> { right: ImmTy<'tcx, Tag>, ) -> InterpResult<'tcx, (Scalar, bool)>; - fn ptr_int_arithmetic( - &self, - bin_op: mir::BinOp, - left: Pointer, - right: u128, - signed: bool, - ) -> InterpResult<'tcx, (Scalar, bool)>; - fn ptr_eq( &self, left: Scalar, @@ -56,9 +48,9 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { trace!("ptr_op: {:?} {:?} {:?}", *left, bin_op, *right); - // Operations that support fat pointers - match bin_op { + Ok(match bin_op { Eq | Ne => { + // This supports fat pointers. let eq = match (*left, *right) { (Immediate::Scalar(left), Immediate::Scalar(right)) => self.ptr_eq(left.not_undef()?, right.not_undef()?)?, @@ -67,114 +59,38 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { self.ptr_eq(left2.not_undef()?, right2.not_undef()?)?, _ => bug!("Type system should not allow comparing Scalar with ScalarPair"), }; - return Ok((Scalar::from_bool(if bin_op == Eq { eq } else { !eq }), false)); + (Scalar::from_bool(if bin_op == Eq { eq } else { !eq }), false) } - _ => {}, - } - // Now we expect no more fat pointers. - let left_layout = left.layout; - let left = left.to_scalar()?; - let right_layout = right.layout; - let right = right.to_scalar()?; + Lt | Le | Gt | Ge => { + // Just compare the integers. + // TODO: Do we really want to *always* do that, even when comparing two live in-bounds pointers? + let left = self.force_bits(left.to_scalar()?, left.layout.size)?; + let right = self.force_bits(right.to_scalar()?, right.layout.size)?; + let res = match bin_op { + Lt => left < right, + Le => left <= right, + Gt => left > right, + Ge => left >= right, + _ => bug!("We already established it has to be one of these operators."), + }; + (Scalar::from_bool(res), false) + } - Ok(match bin_op { Offset => { - let pointee_ty = left_layout.ty + let pointee_ty = left.layout.ty .builtin_deref(true) .expect("Offset called on non-ptr type") .ty; let ptr = self.pointer_offset_inbounds( - left, + left.to_scalar()?, pointee_ty, - right.to_isize(self)?, + right.to_scalar()?.to_isize(self)?, )?; (ptr, false) } - // These need both to be pointer, and fail if they are not in the same location - Lt | Le | Gt | Ge | Sub if left.is_ptr() && right.is_ptr() => { - let left = left.assert_ptr(); - let right = right.assert_ptr(); - if left.alloc_id == right.alloc_id { - let res = match bin_op { - Lt => left.offset < right.offset, - Le => left.offset <= right.offset, - Gt => left.offset > right.offset, - Ge => left.offset >= right.offset, - Sub => { - // subtract the offsets - let left_offset = Scalar::from_uint(left.offset.bytes(), self.memory().pointer_size()); - let right_offset = Scalar::from_uint(right.offset.bytes(), self.memory().pointer_size()); - let layout = self.layout_of(self.tcx.types.usize)?; - return self.binary_op( - Sub, - ImmTy::from_scalar(left_offset, layout), - ImmTy::from_scalar(right_offset, layout), - ) - } - _ => bug!("We already established it has to be one of these operators."), - }; - (Scalar::from_bool(res), false) - } else { - // Both are pointers, but from different allocations. - throw_unsup!(InvalidPointerMath) - } - } - Lt | Le | Gt | Ge if left.is_bits() && right.is_bits() => { - let left = left.assert_bits(self.memory().pointer_size()); - let right = right.assert_bits(self.memory().pointer_size()); - let res = match bin_op { - Lt => left < right, - Le => left <= right, - Gt => left > right, - Ge => left >= right, - _ => bug!("We already established it has to be one of these operators."), - }; - Ok((Scalar::from_bool(res), false)) - } - Gt | Ge if left.is_ptr() && right.is_bits() => { - // "ptr >[=] integer" can be tested if the integer is small enough. - let left = left.assert_ptr(); - let right = right.assert_bits(self.memory().pointer_size()); - let (_alloc_size, alloc_align) = self.memory() - .get_size_and_align(left.alloc_id, AllocCheck::MaybeDead) - .expect("alloc info with MaybeDead cannot fail"); - let min_ptr_val = u128::from(alloc_align.bytes()) + u128::from(left.offset.bytes()); - let result = match bin_op { - Gt => min_ptr_val > right, - Ge => min_ptr_val >= right, - _ => bug!(), - }; - if result { - // Definitely true! - (Scalar::from_bool(true), false) - } else { - // Sorry, can't tell. - throw_unsup!(InvalidPointerMath) - } - } - // These work if the left operand is a pointer, and the right an integer - Add | BitAnd | Sub | Rem if left.is_ptr() && right.is_bits() => { - // Cast to i128 is fine as we checked the kind to be ptr-sized - self.ptr_int_arithmetic( - bin_op, - left.assert_ptr(), - right.assert_bits(self.memory().pointer_size()), - right_layout.abi.is_signed(), - )? - } - // Commutative operators also work if the integer is on the left - Add | BitAnd if left.is_bits() && right.is_ptr() => { - // This is a commutative operation, just swap the operands - self.ptr_int_arithmetic( - bin_op, - right.assert_ptr(), - left.assert_bits(self.memory().pointer_size()), - left_layout.abi.is_signed(), - )? - } - // Nothing else works - _ => throw_unsup!(InvalidPointerMath), + + _ => bug!("Invalid operator on pointers: {:?}", bin_op) }) } @@ -191,99 +107,6 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { Ok(left == right) } - fn ptr_int_arithmetic( - &self, - bin_op: mir::BinOp, - left: Pointer, - right: u128, - signed: bool, - ) -> InterpResult<'tcx, (Scalar, bool)> { - use rustc::mir::BinOp::*; - - fn map_to_primval((res, over): (Pointer, bool)) -> (Scalar, bool) { - (Scalar::Ptr(res), over) - } - - Ok(match bin_op { - Sub => - // The only way this can overflow is by underflowing, so signdeness of the right - // operands does not matter. - map_to_primval(left.overflowing_signed_offset(-(right as i128), self)), - Add if signed => - map_to_primval(left.overflowing_signed_offset(right as i128, self)), - Add if !signed => - map_to_primval(left.overflowing_offset(Size::from_bytes(right as u64), self)), - - BitAnd if !signed => { - let ptr_base_align = self.memory().get_size_and_align(left.alloc_id, AllocCheck::MaybeDead) - .expect("alloc info with MaybeDead cannot fail") - .1.bytes(); - let base_mask = { - // FIXME: use `interpret::truncate`, once that takes a `Size` instead of a `Layout`. - let shift = 128 - self.memory().pointer_size().bits(); - let value = !(ptr_base_align as u128 - 1); - // Truncate (shift left to drop out leftover values, shift right to fill with zeroes). - (value << shift) >> shift - }; - let ptr_size = self.memory().pointer_size(); - trace!("ptr BitAnd, align {}, operand {:#010x}, base_mask {:#010x}", - ptr_base_align, right, base_mask); - if right & base_mask == base_mask { - // Case 1: the base address bits are all preserved, i.e., right is all-1 there. - let offset = (left.offset.bytes() as u128 & right) as u64; - ( - Scalar::Ptr(Pointer::new_with_tag( - left.alloc_id, - Size::from_bytes(offset), - left.tag, - )), - false, - ) - } else if right & base_mask == 0 { - // Case 2: the base address bits are all taken away, i.e., right is all-0 there. - let v = Scalar::from_uint((left.offset.bytes() as u128) & right, ptr_size); - (v, false) - } else { - throw_unsup!(ReadPointerAsBytes); - } - } - - Rem if !signed => { - // Doing modulo a divisor of the alignment is allowed. - // (Intuition: modulo a divisor leaks less information.) - let ptr_base_align = self.memory().get_size_and_align(left.alloc_id, AllocCheck::MaybeDead) - .expect("alloc info with MaybeDead cannot fail") - .1.bytes(); - let right = right as u64; - let ptr_size = self.memory().pointer_size(); - if right == 1 { - // Modulo 1 is always 0. - (Scalar::from_uint(0u32, ptr_size), false) - } else if ptr_base_align % right == 0 { - // The base address would be cancelled out by the modulo operation, so we can - // just take the modulo of the offset. - ( - Scalar::from_uint((left.offset.bytes() % right) as u128, ptr_size), - false, - ) - } else { - throw_unsup!(ReadPointerAsBytes); - } - } - - _ => { - let msg = format!( - "unimplemented binary op on pointer {:?}: {:?}, {:?} ({})", - bin_op, - left, - right, - if signed { "signed" } else { "unsigned" } - ); - throw_unsup!(Unimplemented(msg)); - } - }) - } - /// Raises an error if the offset moves the pointer outside of its allocation. /// We consider ZSTs their own huge allocation that doesn't overlap with anything (and nothing /// moves in there because the size is 0). We also consider the NULL pointer its own separate From 773f6aeb4ca07711330c5ab2cdec1c50cba4b9c8 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 24 Jul 2019 16:25:12 +0200 Subject: [PATCH 0980/3747] remove some compile-fail tests that now work --- .../pointers_to_different_allocations_are_unorderable.rs | 7 ------- tests/compile-fail/ptr_ge_integer.rs | 7 ------- 2 files changed, 14 deletions(-) delete mode 100644 tests/compile-fail/pointers_to_different_allocations_are_unorderable.rs delete mode 100644 tests/compile-fail/ptr_ge_integer.rs diff --git a/tests/compile-fail/pointers_to_different_allocations_are_unorderable.rs b/tests/compile-fail/pointers_to_different_allocations_are_unorderable.rs deleted file mode 100644 index 124f84de5bf45..0000000000000 --- a/tests/compile-fail/pointers_to_different_allocations_are_unorderable.rs +++ /dev/null @@ -1,7 +0,0 @@ -fn main() { - let x: *const u8 = &1; - let y: *const u8 = &2; - if x < y { //~ ERROR attempted to do invalid arithmetic on pointers - unreachable!() - } -} diff --git a/tests/compile-fail/ptr_ge_integer.rs b/tests/compile-fail/ptr_ge_integer.rs deleted file mode 100644 index 43160249c3635..0000000000000 --- a/tests/compile-fail/ptr_ge_integer.rs +++ /dev/null @@ -1,7 +0,0 @@ -fn main() { - let b = Box::new(0); - let x = &*b as *const i32; - // We cannot test if this is >= 64. After all, depending on the base address, that - // might or might not be the case. - assert!(x >= 64 as *const i32); //~ ERROR invalid arithmetic on pointers -} From 61d8a4e101ba7822d4b86bdb548adb5bbc96e461 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 24 Jul 2019 20:42:53 +0200 Subject: [PATCH 0981/3747] simplify code --- src/shims/intrinsics.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 71027a65b0545..7a213a8059967 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -306,7 +306,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx match dest.layout.abi { layout::Abi::Scalar(ref s) => { let x = Scalar::from_int(0, s.value.size(this)); - this.write_immediate(Immediate::Scalar(x.into()), dest)?; + this.write_scalar(x, dest)?; } layout::Abi::ScalarPair(ref s1, ref s2) => { let x = Scalar::from_int(0, s1.value.size(this)); From 5efacf636baba76bec2255e3d3312f5d5c81018f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 3 Aug 2019 15:15:28 +0200 Subject: [PATCH 0982/3747] bump Rust --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 8fbf6d7425bb1..f54537d33b937 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -d7270712cb446aad0817040bbca73a8d024f67b0 +8e917f48382c6afaf50568263b89d35fba5d98e4 From ab22da8ce8b08f06e01e325c277f19072717fe9c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 3 Aug 2019 16:59:30 +0200 Subject: [PATCH 0983/3747] annotate some unwraps with better messages --- src/bin/cargo-miri.rs | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 351da554b7bfa..72bc630e7fa5e 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -249,7 +249,10 @@ fn setup(ask_user: bool) { println!("Installing xargo: `cargo install xargo -f`"); } - if !cargo().args(&["install", "xargo", "-f"]).status().unwrap().success() { + if !cargo().args(&["install", "xargo", "-f"]).status() + .expect("failed to install xargo") + .success() + { show_error(format!("Failed to install xargo")); } } @@ -257,7 +260,9 @@ fn setup(ask_user: bool) { // Then, unless `XARGO_RUST_SRC` is set, we also need rust-src. // Let's see if it is already installed. if std::env::var("XARGO_RUST_SRC").is_err() { - let sysroot = Command::new("rustc").args(&["--print", "sysroot"]).output().unwrap().stdout; + let sysroot = Command::new("rustc").args(&["--print", "sysroot"]).output() + .expect("failed to get rustc sysroot") + .stdout; let sysroot = std::str::from_utf8(&sysroot).unwrap(); let src = Path::new(sysroot.trim_end_matches('\n')).join("lib").join("rustlib").join("src"); if !src.exists() { @@ -266,7 +271,10 @@ fn setup(ask_user: bool) { } else { println!("Installing rust-src component: `rustup component add rust-src`"); } - if !Command::new("rustup").args(&["component", "add", "rust-src"]).status().unwrap().success() { + if !Command::new("rustup").args(&["component", "add", "rust-src"]).status() + .expect("failed to install rust-src component") + .success() + { show_error(format!("Failed to install rust-src component")); } } @@ -313,7 +321,9 @@ path = "lib.rs" if let Some(ref target) = target { command.arg("--target").arg(&target); } - if !command.status().unwrap().success() + if !command.status() + .expect("failed to run xargo") + .success() { show_error(format!("Failed to run xargo")); } From 10f46336af2dea648c3b2ecf999d789d33bbfdd0 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 3 Aug 2019 17:20:16 +0200 Subject: [PATCH 0984/3747] set RUSTC_DEBUG_ASSERTIONS for when we are in bootstrap --- src/bin/cargo-miri.rs | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 72bc630e7fa5e..1c0d23336e61a 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -310,17 +310,21 @@ version = "0.0.0" path = "lib.rs" "#).unwrap(); File::create(dir.join("lib.rs")).unwrap(); - // Run xargo. + // Prepare xargo invocation. let target = get_arg_flag_value("--target"); let print_env = !ask_user && has_arg_flag("--env"); // whether we just print the necessary environment variable let mut command = xargo(); - command.arg("build").arg("-q") - .current_dir(&dir) - .env("RUSTFLAGS", miri::miri_default_args().join(" ")) - .env("XARGO_HOME", dir.to_str().unwrap()); + command.arg("build").arg("-q"); + command.current_dir(&dir); + command.env("RUSTFLAGS", miri::miri_default_args().join(" ")); + command.env("XARGO_HOME", dir.to_str().unwrap()); + // In bootstrap, make sure we don't get debug assertons into our libstd. + command.env("RUSTC_DEBUG_ASSERTIONS", "false"); + // Handle target flag. if let Some(ref target) = target { command.arg("--target").arg(&target); } + // Finally run it! if !command.status() .expect("failed to run xargo") .success() From bff6b05424e9cf1a9b9afc9f5d6953ba4f1c0ea6 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 3 Aug 2019 17:27:50 +0200 Subject: [PATCH 0985/3747] more consistent test name --- .../compile-fail/{copy_nonoverlapping.rs => copy_overlapping.rs} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename tests/compile-fail/{copy_nonoverlapping.rs => copy_overlapping.rs} (100%) diff --git a/tests/compile-fail/copy_nonoverlapping.rs b/tests/compile-fail/copy_overlapping.rs similarity index 100% rename from tests/compile-fail/copy_nonoverlapping.rs rename to tests/compile-fail/copy_overlapping.rs From c4cea035e670eddc1afb0b78a6cdd37cb58c8fb7 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Sat, 3 Aug 2019 10:51:23 -0500 Subject: [PATCH 0986/3747] Formatting --- src/shims/foreign_items.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 3321329478234..3e3266b74a074 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -612,6 +612,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let n = x * 2.0f64.powi(exp); this.write_scalar(Scalar::from_u64(n.to_bits()), dest)?; } + // Some things needed for `sys::thread` initialization to go through. "signal" | "sigaction" | "sigaltstack" => { this.write_scalar(Scalar::from_int(0, dest.layout.size), dest)?; From f65e7cd2d1a99618c3225f1a6deb424e5bba7dfa Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 3 Aug 2019 20:31:33 +0200 Subject: [PATCH 0987/3747] adjust for rustc changes --- rust-version | 2 +- src/eval.rs | 9 ++++----- src/machine.rs | 4 +--- src/shims/dlsym.rs | 4 +--- src/shims/foreign_items.rs | 38 +++++++++++++------------------------- src/shims/intrinsics.rs | 16 ++++++++-------- src/shims/tls.rs | 2 +- src/stacked_borrows.rs | 14 +++++++------- 8 files changed, 36 insertions(+), 53 deletions(-) diff --git a/rust-version b/rust-version index f54537d33b937..94c6f5e4b8c97 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -8e917f48382c6afaf50568263b89d35fba5d98e4 +a45743345659c775b01484574af2818c46a2cb03 diff --git a/src/eval.rs b/src/eval.rs index 837757c1ad3b5..bc9d97b0280f1 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -41,10 +41,9 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( let main_mir = ecx.load_mir(main_instance.def)?; if !main_mir.return_ty().is_unit() || main_mir.arg_count != 0 { - throw_unsup!(Unimplemented( + throw_unsup_format!( "miri does not support main functions without `fn()` type signatures" - .to_owned(), - )); + ); } let start_id = tcx.lang_items().start_fn().unwrap(); @@ -60,10 +59,10 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( let start_mir = ecx.load_mir(start_instance.def)?; if start_mir.arg_count != 3 { - throw_unsup!(AbiViolation(format!( + bug!( "'start' lang item should have three arguments, but has {}", start_mir.arg_count - ))); + ); } // Return value (in static memory so that it does not count as leak). diff --git a/src/machine.rs b/src/machine.rs index 7fa79d822c35b..30f3231308a47 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -247,9 +247,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { let data = vec![0; size.bytes() as usize]; Allocation::from_bytes(&data, tcx.data_layout.pointer_align.abi) } - _ => throw_unsup!(Unimplemented( - format!("can't access foreign static: {}", link_name), - )), + _ => throw_unsup_format!("can't access foreign static: {}", link_name), }; Ok(Cow::Owned(alloc)) } diff --git a/src/shims/dlsym.rs b/src/shims/dlsym.rs index 005493096248a..b859a80190245 100644 --- a/src/shims/dlsym.rs +++ b/src/shims/dlsym.rs @@ -16,9 +16,7 @@ impl Dlsym { "getentropy" => Some(GetEntropy), "__pthread_get_minstack" => None, _ => - throw_unsup!(Unimplemented(format!( - "Unsupported dlsym: {}", name - ))), + throw_unsup_format!("Unsupported dlsym: {}", name), }) } } diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 12baa79916ab6..5561231edf044 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -141,7 +141,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // First: functions that diverge. match link_name { "__rust_start_panic" | "panic_impl" => { - throw_unsup!(MachineError("the evaluated program panicked".to_string())); + throw_unsup_format!("the evaluated program panicked"); } "exit" | "ExitProcess" => { // it's really u32 for ExitProcess, but we have to put it into the `Exit` error variant anyway @@ -149,9 +149,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx return Err(InterpError::Exit(code).into()); } _ => if dest.is_none() { - throw_unsup!(Unimplemented( - format!("can't call diverging foreign function: {}", link_name), - )); + throw_unsup_format!("can't call (diverging) foreign function: {}", link_name); } } @@ -183,10 +181,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx FIXME: This check is disabled because rustc violates it. See . if align < this.pointer_size().bytes() { - throw_unsup!(MachineError(format!( + throw_ub_format!( "posix_memalign: alignment must be at least the size of a pointer, but is {}", align, - ))); + ); } */ if size == 0 { @@ -309,9 +307,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_uint(len, dest.layout.size), dest)?; } id => { - throw_unsup!(Unimplemented( - format!("miri does not support syscall ID {}", id), - )) + throw_unsup_format!("miri does not support syscall ID {}", id) } } } @@ -359,12 +355,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx )?; let mut args = this.frame().body.args_iter(); - let arg_local = args.next().ok_or_else(|| - err_unsup!(AbiViolation( - "Argument to __rust_maybe_catch_panic does not take enough arguments." - .to_owned(), - )), - )?; + let arg_local = args.next() + .expect("Argument to __rust_maybe_catch_panic does not take enough arguments."); let arg_dest = this.local_place(arg_local)?; this.write_scalar(data, arg_dest)?; @@ -632,9 +624,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if let Some(result) = result { this.write_scalar(result, dest)?; } else { - throw_unsup!(Unimplemented( - format!("Unimplemented sysconf name: {}", name), - )); + throw_unsup_format!("Unimplemented sysconf name: {}", name) } } @@ -661,9 +651,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // This is `libc::pthread_key_t`. let key_type = args[0].layout.ty .builtin_deref(true) - .ok_or_else(|| err_unsup!( - AbiViolation("wrong signature used for `pthread_key_create`: first argument must be a raw pointer.".to_owned()) - ))? + .ok_or_else(|| err_ub!(Ub(format!( + "wrong signature used for `pthread_key_create`: first argument must be a raw pointer." + ))))? .ty; let key_layout = this.layout_of(key_type)?; @@ -729,7 +719,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // We don't support threading. (Also for Windows.) "pthread_create" | "CreateThread" => { - throw_unsup!(Unimplemented(format!("Miri does not support threading"))); + throw_unsup_format!("Miri does not support threading"); } // Stub out calls for condvar, mutex and rwlock, to just return `0`. @@ -948,9 +938,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // We can't execute anything else. _ => { - throw_unsup!(Unimplemented( - format!("can't call foreign function: {}", link_name), - )); + throw_unsup_format!("can't call foreign function: {}", link_name) } } diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 7a213a8059967..5c3ff139c0262 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -133,7 +133,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "atomic_xsub_relaxed" => { let ptr = this.deref_operand(args[0])?; if !ptr.layout.ty.is_integral() { - throw_unsup!(Unimplemented(format!("Atomic arithmetic operations only work on integer types"))); + bug!("Atomic arithmetic operations only work on integer types"); } let rhs = this.read_immediate(args[1])?; let old = this.read_immediate(ptr.into())?; @@ -279,9 +279,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Check if `b` is -1, which is the "min_value / -1" case. let minus1 = Scalar::from_int(-1, dest.layout.size); return Err(if b.to_scalar().unwrap() == minus1 { - err_unsup!(Intrinsic(format!("exact_div: result of dividing MIN by -1 cannot be represented"))) + err_ub!(Ub(format!("exact_div: result of dividing MIN by -1 cannot be represented"))) } else { - err_unsup!(Intrinsic(format!("exact_div: {:?} cannot be divided by {:?} without remainder", *a, *b))) + err_ub!(Ub(format!("exact_div: {:?} cannot be divided by {:?} without remainder", *a, *b))) }.into()); } this.binop_ignore_overflow(mir::BinOp::Div, a, b, dest)?; @@ -350,7 +350,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let ty = substs.type_at(0); let layout = this.layout_of(ty)?; if layout.abi.is_uninhabited() { - throw_unsup!(Intrinsic(format!("Trying to instantiate uninhabited type {}", ty))) + throw_ub_format!("Trying to instantiate uninhabited type {}", ty) } } @@ -444,7 +444,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let r = this.read_immediate(args[1])?; let rval = r.to_scalar()?.to_bits(args[1].layout.size)?; if rval == 0 { - throw_unsup!(Intrinsic(format!("Division by 0 in unchecked_div"))); + throw_ub_format!("Division by 0 in unchecked_div"); } this.binop_ignore_overflow( mir::BinOp::Div, @@ -459,7 +459,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let r = this.read_immediate(args[1])?; let rval = r.to_scalar()?.to_bits(args[1].layout.size)?; if rval == 0 { - throw_unsup!(Intrinsic(format!("Division by 0 in unchecked_rem"))); + throw_ub_format!("Division by 0 in unchecked_rem"); } this.binop_ignore_overflow( mir::BinOp::Rem, @@ -480,7 +480,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx }; let (res, overflowed) = this.binary_op(op, l, r)?; if overflowed { - throw_unsup!(Intrinsic(format!("Overflowing arithmetic in {}", intrinsic_name.get()))); + throw_ub_format!("Overflowing arithmetic in {}", intrinsic_name.get()); } this.write_scalar(res, dest)?; } @@ -504,7 +504,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } - name => throw_unsup!(Unimplemented(format!("unimplemented intrinsic: {}", name))), + name => throw_unsup_format!("unimplemented intrinsic: {}", name), } Ok(()) diff --git a/src/shims/tls.rs b/src/shims/tls.rs index 145d2b3e78915..05b8dc15da66b 100644 --- a/src/shims/tls.rs +++ b/src/shims/tls.rs @@ -158,7 +158,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx StackPopCleanup::None { cleanup: true }, )?; let arg_local = this.frame().body.args_iter().next().ok_or_else( - || err_unsup!(AbiViolation("TLS dtor does not take enough arguments.".to_owned())), + || err_ub!(Ub(format!("TLS dtor does not take enough arguments."))), )?; let dest = this.local_place(arg_local)?; this.write_scalar(ptr, dest)?; diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 5ef934b9922b3..0fbc3e1ac281d 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -273,14 +273,14 @@ impl<'tcx> Stack { if let Some(call) = item.protector { if global.is_active(call) { if let Some(tag) = tag { - throw_unsup!(MachineError(format!( + throw_ub_format!( "not granting access to tag {:?} because incompatible item is protected: {:?}", tag, item - ))); + ); } else { - throw_unsup!(MachineError(format!( + throw_ub_format!( "deallocating while item is protected: {:?}", item - ))); + ); } } } @@ -299,7 +299,7 @@ impl<'tcx> Stack { // Step 1: Find granting item. let granting_idx = self.find_granting(access, tag) - .ok_or_else(|| err_unsup!(MachineError(format!( + .ok_or_else(|| err_ub!(Ub(format!( "no item granting {} to tag {:?} found in borrow stack", access, tag, ))))?; @@ -346,7 +346,7 @@ impl<'tcx> Stack { ) -> InterpResult<'tcx> { // Step 1: Find granting item. self.find_granting(AccessKind::Write, tag) - .ok_or_else(|| err_unsup!(MachineError(format!( + .ok_or_else(|| err_ub!(Ub(format!( "no item granting write access for deallocation to tag {:?} found in borrow stack", tag, ))))?; @@ -378,7 +378,7 @@ impl<'tcx> Stack { // Now we figure out which item grants our parent (`derived_from`) this kind of access. // We use that to determine where to put the new item. let granting_idx = self.find_granting(access, derived_from) - .ok_or_else(|| err_unsup!(MachineError(format!( + .ok_or_else(|| err_ub!(Ub(format!( "trying to reborrow for {:?}, but parent tag {:?} does not have an appropriate item in the borrow stack", new.perm, derived_from, ))))?; From 8d99e42f47e4fa0d79bc544c098e7287866c9a29 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 3 Aug 2019 20:53:42 +0200 Subject: [PATCH 0988/3747] test memalign contract (rustc is fixed) --- src/shims/foreign_items.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 5561231edf044..76ee875d026bd 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -177,16 +177,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if !align.is_power_of_two() { throw_unsup!(HeapAllocNonPowerOfTwoAlignment(align)); } - /* - FIXME: This check is disabled because rustc violates it. - See . if align < this.pointer_size().bytes() { throw_ub_format!( "posix_memalign: alignment must be at least the size of a pointer, but is {}", align, ); } - */ + if size == 0 { this.write_null(ret.into())?; } else { From a41ec9aacbdc4798f9efeb8b24fc12d26e04bf7d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 3 Aug 2019 20:54:57 +0200 Subject: [PATCH 0989/3747] adjust error messages in tests --- tests/compile-fail/atomic_non_integer_arithmetic.rs | 9 --------- tests/compile-fail/ctlz_nonzero.rs | 2 +- tests/compile-fail/cttz_nonzero.rs | 2 +- tests/compile-fail/overflowing-unchecked-rsh.rs | 2 +- 4 files changed, 3 insertions(+), 12 deletions(-) delete mode 100644 tests/compile-fail/atomic_non_integer_arithmetic.rs diff --git a/tests/compile-fail/atomic_non_integer_arithmetic.rs b/tests/compile-fail/atomic_non_integer_arithmetic.rs deleted file mode 100644 index 8c2ed98b7dfab..0000000000000 --- a/tests/compile-fail/atomic_non_integer_arithmetic.rs +++ /dev/null @@ -1,9 +0,0 @@ -#![feature(core_intrinsics)] - -pub fn main() { - let mut z: f64 = 1.0; - unsafe { - ::std::intrinsics::atomic_xadd(&mut z, 2.0); - //~^ ERROR: Atomic arithmetic operations only work on integer types - } -} diff --git a/tests/compile-fail/ctlz_nonzero.rs b/tests/compile-fail/ctlz_nonzero.rs index 61f41363589ca..e82ed89da18a7 100644 --- a/tests/compile-fail/ctlz_nonzero.rs +++ b/tests/compile-fail/ctlz_nonzero.rs @@ -10,6 +10,6 @@ pub fn main() { unsafe { use crate::rusti::*; - ctlz_nonzero(0u8); //~ ERROR ctlz_nonzero called on 0 + ctlz_nonzero(0u8); //~ ERROR `ctlz_nonzero` called on 0 } } diff --git a/tests/compile-fail/cttz_nonzero.rs b/tests/compile-fail/cttz_nonzero.rs index 69d2874ce9269..205b552081148 100644 --- a/tests/compile-fail/cttz_nonzero.rs +++ b/tests/compile-fail/cttz_nonzero.rs @@ -10,6 +10,6 @@ pub fn main() { unsafe { use crate::rusti::*; - cttz_nonzero(0u8); //~ ERROR cttz_nonzero called on 0 + cttz_nonzero(0u8); //~ ERROR `cttz_nonzero` called on 0 } } diff --git a/tests/compile-fail/overflowing-unchecked-rsh.rs b/tests/compile-fail/overflowing-unchecked-rsh.rs index 0d67aef430883..f59773f7e366c 100644 --- a/tests/compile-fail/overflowing-unchecked-rsh.rs +++ b/tests/compile-fail/overflowing-unchecked-rsh.rs @@ -2,7 +2,7 @@ use std::intrinsics::*; -//error-pattern: Overflowing shift by 64 in unchecked_shr +//error-pattern: Overflowing shift by 64 in `unchecked_shr` fn main() { unsafe { From 874437d717154072a3fe6ff04887fdf42988dffc Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 4 Aug 2019 10:09:58 +0200 Subject: [PATCH 0990/3747] install xargo from git temporarily --- src/bin/cargo-miri.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 1c0d23336e61a..6baa882519b74 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -249,7 +249,8 @@ fn setup(ask_user: bool) { println!("Installing xargo: `cargo install xargo -f`"); } - if !cargo().args(&["install", "xargo", "-f"]).status() + // FIXME: Install from crates.io again once a new xargo got released. + if !cargo().args(&["install", "xargo", "-f", "--git", "https://github.com/japaric/xargo"]).status() .expect("failed to install xargo") .success() { From 162c0ffb1fc6547557f94fa0c9b316e4a785bd8a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 4 Aug 2019 10:14:51 +0200 Subject: [PATCH 0991/3747] use postfix negation instead of prefix --- src/bin/cargo-miri.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 6baa882519b74..8d7bbace0edd6 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -4,6 +4,7 @@ use std::fs::{self, File}; use std::io::{self, Write, BufRead}; use std::path::{PathBuf, Path}; use std::process::Command; +use std::ops::Not; const CARGO_MIRI_HELP: &str = r#"Interprets bin crates and tests in Miri @@ -250,9 +251,9 @@ fn setup(ask_user: bool) { } // FIXME: Install from crates.io again once a new xargo got released. - if !cargo().args(&["install", "xargo", "-f", "--git", "https://github.com/japaric/xargo"]).status() + if cargo().args(&["install", "xargo", "-f", "--git", "https://github.com/japaric/xargo"]).status() .expect("failed to install xargo") - .success() + .success().not() { show_error(format!("Failed to install xargo")); } @@ -326,9 +327,9 @@ path = "lib.rs" command.arg("--target").arg(&target); } // Finally run it! - if !command.status() + if command.status() .expect("failed to run xargo") - .success() + .success().not() { show_error(format!("Failed to run xargo")); } From ca4969d4da07faab68ab8be893602a41fca63724 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 2 Aug 2019 19:50:54 +0200 Subject: [PATCH 0992/3747] consolidate atomic tests --- tests/run-pass/atomic-access-bool.rs | 19 ------------ .../{atomic-compare_exchange.rs => atomic.rs} | 29 +++++++++++++++++-- 2 files changed, 26 insertions(+), 22 deletions(-) delete mode 100644 tests/run-pass/atomic-access-bool.rs rename tests/run-pass/{atomic-compare_exchange.rs => atomic.rs} (64%) diff --git a/tests/run-pass/atomic-access-bool.rs b/tests/run-pass/atomic-access-bool.rs deleted file mode 100644 index 68a5d7295f176..0000000000000 --- a/tests/run-pass/atomic-access-bool.rs +++ /dev/null @@ -1,19 +0,0 @@ -use std::sync::atomic::{AtomicBool, Ordering::*}; - -static mut ATOMIC: AtomicBool = AtomicBool::new(false); - -fn main() { - unsafe { - assert_eq!(*ATOMIC.get_mut(), false); - ATOMIC.store(true, SeqCst); - assert_eq!(*ATOMIC.get_mut(), true); - ATOMIC.fetch_or(false, SeqCst); - assert_eq!(*ATOMIC.get_mut(), true); - ATOMIC.fetch_and(false, SeqCst); - assert_eq!(*ATOMIC.get_mut(), false); - ATOMIC.fetch_nand(true, SeqCst); - assert_eq!(*ATOMIC.get_mut(), true); - ATOMIC.fetch_xor(true, SeqCst); - assert_eq!(*ATOMIC.get_mut(), false); - } -} diff --git a/tests/run-pass/atomic-compare_exchange.rs b/tests/run-pass/atomic.rs similarity index 64% rename from tests/run-pass/atomic-compare_exchange.rs rename to tests/run-pass/atomic.rs index 575b53fb44b0e..ed9a9f4534908 100644 --- a/tests/run-pass/atomic-compare_exchange.rs +++ b/tests/run-pass/atomic.rs @@ -1,8 +1,31 @@ -use std::sync::atomic::{AtomicIsize, Ordering::*}; - -static ATOMIC: AtomicIsize = AtomicIsize::new(0); +use std::sync::atomic::{AtomicBool, AtomicIsize, Ordering::*}; fn main() { + atomic_bool(); + atomic_isize(); +} + +fn atomic_bool() { + static mut ATOMIC: AtomicBool = AtomicBool::new(false); + + unsafe { + assert_eq!(*ATOMIC.get_mut(), false); + ATOMIC.store(true, SeqCst); + assert_eq!(*ATOMIC.get_mut(), true); + ATOMIC.fetch_or(false, SeqCst); + assert_eq!(*ATOMIC.get_mut(), true); + ATOMIC.fetch_and(false, SeqCst); + assert_eq!(*ATOMIC.get_mut(), false); + ATOMIC.fetch_nand(true, SeqCst); + assert_eq!(*ATOMIC.get_mut(), true); + ATOMIC.fetch_xor(true, SeqCst); + assert_eq!(*ATOMIC.get_mut(), false); + } +} + +fn atomic_isize() { + static ATOMIC: AtomicIsize = AtomicIsize::new(0); + // Make sure trans can emit all the intrinsics correctly assert_eq!(ATOMIC.compare_exchange(0, 1, Relaxed, Relaxed), Ok(0)); assert_eq!(ATOMIC.compare_exchange(0, 2, Acquire, Relaxed), Err(1)); From 702f63e427a17081db942ff7f964b682b2e2b663 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 2 Aug 2019 20:08:04 +0200 Subject: [PATCH 0993/3747] test AtomicU64 --- tests/run-pass/atomic.rs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/tests/run-pass/atomic.rs b/tests/run-pass/atomic.rs index ed9a9f4534908..f0b8ec06b905c 100644 --- a/tests/run-pass/atomic.rs +++ b/tests/run-pass/atomic.rs @@ -1,8 +1,9 @@ -use std::sync::atomic::{AtomicBool, AtomicIsize, Ordering::*}; +use std::sync::atomic::{AtomicBool, AtomicIsize, AtomicU64, Ordering::*}; fn main() { atomic_bool(); atomic_isize(); + atomic_u64(); } fn atomic_bool() { @@ -50,3 +51,12 @@ fn atomic_isize() { ATOMIC.compare_exchange_weak(0, 1, SeqCst, Acquire).ok(); ATOMIC.compare_exchange_weak(0, 1, SeqCst, SeqCst).ok(); } + +fn atomic_u64() { + static ATOMIC: AtomicU64 = AtomicU64::new(0); + + ATOMIC.store(1, SeqCst); + assert_eq!(ATOMIC.compare_exchange(0, 0x100, AcqRel, Acquire), Err(1)); + assert_eq!(ATOMIC.compare_exchange_weak(1, 0x100, AcqRel, Acquire), Ok(1)); + assert_eq!(ATOMIC.load(Relaxed), 0x100); +} From f47e58950bc8541a887d9e1720a5ecc9b9c346d5 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 2 Aug 2019 20:20:56 +0200 Subject: [PATCH 0994/3747] check that atomics are sufficiently aligned, and add test --- src/shims/intrinsics.rs | 57 +++++++++++++++++++++----- tests/compile-fail/atomic_unaligned.rs | 12 ++++++ 2 files changed, 58 insertions(+), 11 deletions(-) create mode 100644 tests/compile-fail/atomic_unaligned.rs diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 5c3ff139c0262..d442fcedbdb17 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -1,7 +1,7 @@ use rustc_apfloat::Float; use rustc::mir; use rustc::mir::interpret::{InterpResult, PointerArithmetic}; -use rustc::ty::layout::{self, LayoutOf, Size}; +use rustc::ty::layout::{self, LayoutOf, Size, Align}; use rustc::ty; use crate::{ @@ -48,17 +48,29 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } + "volatile_load" => { + let ptr = this.deref_operand(args[0])?; + this.copy_op(ptr.into(), dest)?; + } + + "volatile_store" => { + let ptr = this.deref_operand(args[0])?; + this.copy_op(args[1], ptr.into())?; + } + "atomic_load" | "atomic_load_relaxed" | "atomic_load_acq" => { let ptr = this.deref_operand(args[0])?; let val = this.read_scalar(ptr.into())?; // make sure it fits into a scalar; otherwise it cannot be atomic - this.write_scalar(val, dest)?; - } - "volatile_load" => { - let ptr = this.deref_operand(args[0])?; - this.copy_op(ptr.into(), dest)?; + // Check alignment requirements. Atomics must always be aligned to their size, + // even if the type they wrap would be less aligned (e.g. AtomicU64 on 32bit must + // be 8-aligned). + let align = Align::from_bytes(ptr.layout.size.bytes()).unwrap(); + this.memory().check_ptr_access(ptr.ptr, ptr.layout.size, align)?; + + this.write_scalar(val, dest)?; } "atomic_store" | @@ -66,12 +78,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "atomic_store_rel" => { let ptr = this.deref_operand(args[0])?; let val = this.read_scalar(args[1])?; // make sure it fits into a scalar; otherwise it cannot be atomic - this.write_scalar(val, ptr.into())?; - } - "volatile_store" => { - let ptr = this.deref_operand(args[0])?; - this.copy_op(args[1], ptr.into())?; + // Check alignment requirements. Atomics must always be aligned to their size, + // even if the type they wrap would be less aligned (e.g. AtomicU64 on 32bit must + // be 8-aligned). + let align = Align::from_bytes(ptr.layout.size.bytes()).unwrap(); + this.memory().check_ptr_access(ptr.ptr, ptr.layout.size, align)?; + + this.write_scalar(val, ptr.into())?; } "atomic_fence_acq" => { @@ -82,6 +96,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let ptr = this.deref_operand(args[0])?; let new = this.read_scalar(args[1])?; let old = this.read_scalar(ptr.into())?; + + // Check alignment requirements. Atomics must always be aligned to their size, + // even if the type they wrap would be less aligned (e.g. AtomicU64 on 32bit must + // be 8-aligned). + let align = Align::from_bytes(ptr.layout.size.bytes()).unwrap(); + this.memory().check_ptr_access(ptr.ptr, ptr.layout.size, align)?; + this.write_scalar(old, dest)?; // old value is returned this.write_scalar(new, ptr.into())?; } @@ -91,6 +112,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let expect_old = this.read_immediate(args[1])?; // read as immediate for the sake of `binary_op()` let new = this.read_scalar(args[2])?; let old = this.read_immediate(ptr.into())?; // read as immediate for the sake of `binary_op()` + + // Check alignment requirements. Atomics must always be aligned to their size, + // even if the type they wrap would be less aligned (e.g. AtomicU64 on 32bit must + // be 8-aligned). + let align = Align::from_bytes(ptr.layout.size.bytes()).unwrap(); + this.memory().check_ptr_access(ptr.ptr, ptr.layout.size, align)?; + // binary_op will bail if either of them is not a scalar let (eq, _) = this.binary_op(mir::BinOp::Eq, old, expect_old)?; let res = Immediate::ScalarPair(old.to_scalar_or_undef(), eq.into()); @@ -137,6 +165,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } let rhs = this.read_immediate(args[1])?; let old = this.read_immediate(ptr.into())?; + + // Check alignment requirements. Atomics must always be aligned to their size, + // even if the type they wrap would be less aligned (e.g. AtomicU64 on 32bit must + // be 8-aligned). + let align = Align::from_bytes(ptr.layout.size.bytes()).unwrap(); + this.memory().check_ptr_access(ptr.ptr, ptr.layout.size, align)?; + this.write_immediate(*old, dest)?; // old value is returned let (op, neg) = match intrinsic_name.split('_').nth(1).unwrap() { "or" => (mir::BinOp::BitOr, false), diff --git a/tests/compile-fail/atomic_unaligned.rs b/tests/compile-fail/atomic_unaligned.rs new file mode 100644 index 0000000000000..5d2347c03ffee --- /dev/null +++ b/tests/compile-fail/atomic_unaligned.rs @@ -0,0 +1,12 @@ +#![feature(core_intrinsics)] + +fn main() { + // Do a 4-aligned u64 atomic access. That should be UB on all platforms, + // even if u64 only has alignment 4. + let z = [0u32; 2]; + let zptr = &z as *const _ as *const u64; + unsafe { + ::std::intrinsics::atomic_load(zptr); + //~^ ERROR tried to access memory with alignment 4, but alignment 8 is required + } +} From 19add0bb751000dc94c28a603600f82b6e14d887 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 4 Aug 2019 10:52:09 +0200 Subject: [PATCH 0995/3747] places and pointers are not the same thing; this is a place --- src/shims/intrinsics.rs | 56 ++++++++++++++++++++--------------------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index d442fcedbdb17..b7a1761167d54 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -49,26 +49,26 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "volatile_load" => { - let ptr = this.deref_operand(args[0])?; - this.copy_op(ptr.into(), dest)?; + let place = this.deref_operand(args[0])?; + this.copy_op(place.into(), dest)?; } "volatile_store" => { - let ptr = this.deref_operand(args[0])?; - this.copy_op(args[1], ptr.into())?; + let place = this.deref_operand(args[0])?; + this.copy_op(args[1], place.into())?; } "atomic_load" | "atomic_load_relaxed" | "atomic_load_acq" => { - let ptr = this.deref_operand(args[0])?; - let val = this.read_scalar(ptr.into())?; // make sure it fits into a scalar; otherwise it cannot be atomic + let place = this.deref_operand(args[0])?; + let val = this.read_scalar(place.into())?; // make sure it fits into a scalar; otherwise it cannot be atomic // Check alignment requirements. Atomics must always be aligned to their size, // even if the type they wrap would be less aligned (e.g. AtomicU64 on 32bit must // be 8-aligned). - let align = Align::from_bytes(ptr.layout.size.bytes()).unwrap(); - this.memory().check_ptr_access(ptr.ptr, ptr.layout.size, align)?; + let align = Align::from_bytes(place.layout.size.bytes()).unwrap(); + this.memory().check_ptr_access(place.ptr, place.layout.size, align)?; this.write_scalar(val, dest)?; } @@ -76,16 +76,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "atomic_store" | "atomic_store_relaxed" | "atomic_store_rel" => { - let ptr = this.deref_operand(args[0])?; + let place = this.deref_operand(args[0])?; let val = this.read_scalar(args[1])?; // make sure it fits into a scalar; otherwise it cannot be atomic // Check alignment requirements. Atomics must always be aligned to their size, // even if the type they wrap would be less aligned (e.g. AtomicU64 on 32bit must // be 8-aligned). - let align = Align::from_bytes(ptr.layout.size.bytes()).unwrap(); - this.memory().check_ptr_access(ptr.ptr, ptr.layout.size, align)?; + let align = Align::from_bytes(place.layout.size.bytes()).unwrap(); + this.memory().check_ptr_access(place.ptr, place.layout.size, align)?; - this.write_scalar(val, ptr.into())?; + this.write_scalar(val, place.into())?; } "atomic_fence_acq" => { @@ -93,31 +93,31 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } _ if intrinsic_name.starts_with("atomic_xchg") => { - let ptr = this.deref_operand(args[0])?; + let place = this.deref_operand(args[0])?; let new = this.read_scalar(args[1])?; - let old = this.read_scalar(ptr.into())?; + let old = this.read_scalar(place.into())?; // Check alignment requirements. Atomics must always be aligned to their size, // even if the type they wrap would be less aligned (e.g. AtomicU64 on 32bit must // be 8-aligned). - let align = Align::from_bytes(ptr.layout.size.bytes()).unwrap(); - this.memory().check_ptr_access(ptr.ptr, ptr.layout.size, align)?; + let align = Align::from_bytes(place.layout.size.bytes()).unwrap(); + this.memory().check_ptr_access(place.ptr, place.layout.size, align)?; this.write_scalar(old, dest)?; // old value is returned - this.write_scalar(new, ptr.into())?; + this.write_scalar(new, place.into())?; } _ if intrinsic_name.starts_with("atomic_cxchg") => { - let ptr = this.deref_operand(args[0])?; + let place = this.deref_operand(args[0])?; let expect_old = this.read_immediate(args[1])?; // read as immediate for the sake of `binary_op()` let new = this.read_scalar(args[2])?; - let old = this.read_immediate(ptr.into())?; // read as immediate for the sake of `binary_op()` + let old = this.read_immediate(place.into())?; // read as immediate for the sake of `binary_op()` // Check alignment requirements. Atomics must always be aligned to their size, // even if the type they wrap would be less aligned (e.g. AtomicU64 on 32bit must // be 8-aligned). - let align = Align::from_bytes(ptr.layout.size.bytes()).unwrap(); - this.memory().check_ptr_access(ptr.ptr, ptr.layout.size, align)?; + let align = Align::from_bytes(place.layout.size.bytes()).unwrap(); + this.memory().check_ptr_access(place.ptr, place.layout.size, align)?; // binary_op will bail if either of them is not a scalar let (eq, _) = this.binary_op(mir::BinOp::Eq, old, expect_old)?; @@ -125,7 +125,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_immediate(res, dest)?; // old value is returned // update ptr depending on comparison if eq.to_bool()? { - this.write_scalar(new, ptr.into())?; + this.write_scalar(new, place.into())?; } } @@ -159,18 +159,18 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "atomic_xsub_rel" | "atomic_xsub_acqrel" | "atomic_xsub_relaxed" => { - let ptr = this.deref_operand(args[0])?; - if !ptr.layout.ty.is_integral() { + let place = this.deref_operand(args[0])?; + if !place.layout.ty.is_integral() { bug!("Atomic arithmetic operations only work on integer types"); } let rhs = this.read_immediate(args[1])?; - let old = this.read_immediate(ptr.into())?; + let old = this.read_immediate(place.into())?; // Check alignment requirements. Atomics must always be aligned to their size, // even if the type they wrap would be less aligned (e.g. AtomicU64 on 32bit must // be 8-aligned). - let align = Align::from_bytes(ptr.layout.size.bytes()).unwrap(); - this.memory().check_ptr_access(ptr.ptr, ptr.layout.size, align)?; + let align = Align::from_bytes(place.layout.size.bytes()).unwrap(); + this.memory().check_ptr_access(place.ptr, place.layout.size, align)?; this.write_immediate(*old, dest)?; // old value is returned let (op, neg) = match intrinsic_name.split('_').nth(1).unwrap() { @@ -189,7 +189,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } else { val }; - this.write_scalar(val, ptr.into())?; + this.write_scalar(val, place.into())?; } "breakpoint" => unimplemented!(), // halt miri From a4cc58efc6db1c8c478954ea5116e15a7add479c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 4 Aug 2019 10:54:07 +0200 Subject: [PATCH 0996/3747] one more place -> ptr rename --- src/shims/intrinsics.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index b7a1761167d54..920dc564e1546 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -370,8 +370,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "move_val_init" => { - let ptr = this.deref_operand(args[0])?; - this.copy_op(args[1], ptr.into())?; + let place = this.deref_operand(args[0])?; + this.copy_op(args[1], place.into())?; } "offset" => { From 0096a0df2a34b5818976ff40b6ec5b1a54ebf92f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 4 Aug 2019 14:49:10 +0200 Subject: [PATCH 0997/3747] gen_random helper: move ptr argument to front --- src/helpers.rs | 2 +- src/shims/dlsym.rs | 2 +- src/shims/foreign_items.rs | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index d29cc021a1b08..e9b09d8160567 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -78,8 +78,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// Generate some random bytes, and write them to `dest`. fn gen_random( &mut self, - len: usize, ptr: Scalar, + len: usize, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); diff --git a/src/shims/dlsym.rs b/src/shims/dlsym.rs index b859a80190245..307de29f22038 100644 --- a/src/shims/dlsym.rs +++ b/src/shims/dlsym.rs @@ -41,7 +41,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx GetEntropy => { let ptr = this.read_scalar(args[0])?.not_undef()?; let len = this.read_scalar(args[1])?.to_usize(this)?; - this.gen_random(len as usize, ptr)?; + this.gen_random(ptr, len as usize)?; this.write_null(dest)?; } } diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 96bc747d3efb0..4fc8b1d54cfcb 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -300,7 +300,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // neither of which have any effect on our current PRNG let _flags = this.read_scalar(args[3])?.to_i32()?; - this.gen_random(len as usize, ptr)?; + this.gen_random(ptr, len as usize)?; this.write_scalar(Scalar::from_uint(len, dest.layout.size), dest)?; } id => { @@ -776,7 +776,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "SecRandomCopyBytes" => { let len = this.read_scalar(args[1])?.to_usize(this)?; let ptr = this.read_scalar(args[2])?.not_undef()?; - this.gen_random(len as usize, ptr)?; + this.gen_random(ptr, len as usize)?; this.write_null(dest)?; } @@ -938,7 +938,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "SystemFunction036" => { let ptr = this.read_scalar(args[0])?.not_undef()?; let len = this.read_scalar(args[1])?.to_u32()?; - this.gen_random(len as usize, ptr)?; + this.gen_random(ptr, len as usize)?; this.write_scalar(Scalar::from_bool(true), dest)?; } From e8d956c4fa320675f245788701193dabd730f5a9 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 4 Aug 2019 15:09:13 +0200 Subject: [PATCH 0998/3747] add getrandom bug --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 91fc72cb427bc..8c5a29880c7cb 100644 --- a/README.md +++ b/README.md @@ -342,6 +342,7 @@ Definite bugs found: * [`str` turning a shared reference into a mutable one](https://github.com/rust-lang/rust/pull/58200) * [`rand` performing unaligned reads](https://github.com/rust-random/rand/issues/779) * [The Unix allocator calling `posix_memalign` in an invalid way](https://github.com/rust-lang/rust/issues/62251) +* [`getrandom` calling the `getrandom` syscall in an invalid way](https://github.com/rust-random/getrandom/pull/73) Violations of Stacked Borrows found that are likely bugs (but Stacked Borrows is currently just an experiment): From 0505868d18ff946da58028de20bf2d5a19bb7f40 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Sun, 4 Aug 2019 09:21:17 -0400 Subject: [PATCH 0999/3747] Do nothing when we try to generate random data of length 0 This preserves compatibility with programs that pass a null pointer and a length of zero to getrandom(), or their platform's equivalent. --- src/helpers.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/helpers.rs b/src/helpers.rs index e9b09d8160567..c543240442ec7 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -81,6 +81,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ptr: Scalar, len: usize, ) -> InterpResult<'tcx> { + // Some programs pass in a null pointer and a length of 0 + // to their platform's random-generation function (e.g. getrandom()) + // on Linux. For compatibility with these programs, we don't perform + // any additional checks - it's okay if the pointer is invalid, + // since we wouldn't actually be writing to it. + if len == 0 { + return Ok(()) + } let this = self.eval_context_mut(); let ptr = match this.memory().check_ptr_access(ptr, Size::from_bytes(len as u64), Align::from_bytes(1).unwrap())? { From c2f681f005a036568dcfe2beb171b9ab635fa486 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Sun, 4 Aug 2019 10:13:29 -0400 Subject: [PATCH 1000/3747] Add semicolon Co-Authored-By: Ralf Jung --- src/helpers.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/helpers.rs b/src/helpers.rs index c543240442ec7..569c1dbfb07ee 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -87,7 +87,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // any additional checks - it's okay if the pointer is invalid, // since we wouldn't actually be writing to it. if len == 0 { - return Ok(()) + return Ok(()); } let this = self.eval_context_mut(); From 3118b9fe4288c21dc0b81c90178cea092d0edfaf Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Sun, 4 Aug 2019 10:25:10 -0400 Subject: [PATCH 1001/3747] Add misssing 'roundf32' and 'roundf64' intrinsics --- src/shims/intrinsics.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 920dc564e1546..52a17a92c2eda 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -225,7 +225,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "sinf32" | "fabsf32" | "cosf32" | "sqrtf32" | "expf32" | "exp2f32" | "logf32" | - "log10f32" | "log2f32" | "floorf32" | "ceilf32" | "truncf32" => { + "log10f32" | "log2f32" | "floorf32" | "ceilf32" | "truncf32" | "roundf32" => { // FIXME: Using host floats. let f = f32::from_bits(this.read_scalar(args[0])?.to_u32()?); let f = match intrinsic_name.get() { @@ -241,13 +241,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "floorf32" => f.floor(), "ceilf32" => f.ceil(), "truncf32" => f.trunc(), + "roundf32" => f.round(), _ => bug!(), }; this.write_scalar(Scalar::from_u32(f.to_bits()), dest)?; } "sinf64" | "fabsf64" | "cosf64" | "sqrtf64" | "expf64" | "exp2f64" | "logf64" | - "log10f64" | "log2f64" | "floorf64" | "ceilf64" | "truncf64" => { + "log10f64" | "log2f64" | "floorf64" | "ceilf64" | "truncf64" | "roundf64" => { // FIXME: Using host floats. let f = f64::from_bits(this.read_scalar(args[0])?.to_u64()?); let f = match intrinsic_name.get() { @@ -263,6 +264,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "floorf64" => f.floor(), "ceilf64" => f.ceil(), "truncf64" => f.trunc(), + "roundf64" => f.round(), _ => bug!(), }; this.write_scalar(Scalar::from_u64(f.to_bits()), dest)?; From 4d3398fc6262a0159af7311524ade980637121ae Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Sun, 4 Aug 2019 10:17:39 -0400 Subject: [PATCH 1002/3747] Replace match with expect() --- src/helpers.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index 569c1dbfb07ee..c0e1ec2cd75bc 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -91,10 +91,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } let this = self.eval_context_mut(); - let ptr = match this.memory().check_ptr_access(ptr, Size::from_bytes(len as u64), Align::from_bytes(1).unwrap())? { - Some(ptr) => ptr, - None => return Ok(()), // zero-sized access - }; + let ptr = this.memory().check_ptr_access( + ptr, + Size::from_bytes(len as u64), + Align::from_bytes(1).unwrap() + )?.expect("we already checked for size 0"); let rng = this.memory_mut().extra.rng.get_mut(); let mut data = vec![0; len]; From 4c11c6b73729f7b573eab102efb9856b37951532 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Sun, 4 Aug 2019 15:57:00 -0400 Subject: [PATCH 1003/3747] Add test for f32::round and f64::round --- tests/run-pass/intrinsics-math.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/run-pass/intrinsics-math.rs b/tests/run-pass/intrinsics-math.rs index 9a7a70bd00925..63098f5fd3f74 100644 --- a/tests/run-pass/intrinsics-math.rs +++ b/tests/run-pass/intrinsics-math.rs @@ -85,6 +85,9 @@ pub fn main() { assert_approx_eq!(1.0f32.tan(), 1.557408f32); assert_approx_eq!(1.0f64.tan(), 1.557408f64); + assert_eq!(3.3_f32.round(), 3.0); + assert_eq!(3.3_f64.round(), 3.0); + extern { fn ldexp(x: f64, n: i32) -> f64; } From a2bdb3bb94936c45b68f91b4ffd938dd3df5f8c1 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Sun, 4 Aug 2019 10:50:38 -0400 Subject: [PATCH 1004/3747] Shim 'libc::getrandom' in addition to 'libc::syscall(libc::SYS_getrandom)' --- src/shims/foreign_items.rs | 33 ++++++++++++++++++++++++--------- 1 file changed, 24 insertions(+), 9 deletions(-) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 4fc8b1d54cfcb..6ae99c9bc15cd 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -293,15 +293,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // is called if a `HashMap` is created the regular way (e.g. HashMap). match this.read_scalar(args[0])?.to_usize(this)? { id if id == sys_getrandom => { - let ptr = this.read_scalar(args[1])?.not_undef()?; - let len = this.read_scalar(args[2])?.to_usize(this)?; - - // The only supported flags are GRND_RANDOM and GRND_NONBLOCK, - // neither of which have any effect on our current PRNG - let _flags = this.read_scalar(args[3])?.to_i32()?; - - this.gen_random(ptr, len as usize)?; - this.write_scalar(Scalar::from_uint(len, dest.layout.size), dest)?; + // The first argument is the syscall id, + // so skip over it + linux_getrandom(this, &args[1..], dest)?; } id => { throw_unsup_format!("miri does not support syscall ID {}", id) @@ -309,6 +303,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } + "getrandom" => { + linux_getrandom(this, args, dest)?; + } + "dlsym" => { let _handle = this.read_scalar(args[0])?; let symbol = this.read_scalar(args[1])?.not_undef()?; @@ -969,3 +967,20 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx return Ok(None); } } + +// Shims the linux 'getrandom()' syscall +fn linux_getrandom<'mir, 'tcx>(this: &mut MiriEvalContext<'mir, 'tcx>, + args: &[OpTy<'tcx, Tag>], + dest: PlaceTy<'tcx, Tag>) -> InterpResult<'tcx> { + let ptr = this.read_scalar(args[0])?.not_undef()?; + let len = this.read_scalar(args[1])?.to_usize(this)?; + + + // The only supported flags are GRND_RANDOM and GRND_NONBLOCK, + // neither of which have any effect on our current PRNG + let _flags = this.read_scalar(args[2])?.to_i32()?; + + this.gen_random(ptr, len as usize)?; + this.write_scalar(Scalar::from_uint(len, dest.layout.size), dest)?; + Ok(()) +} From 56a9a283e74078a3a48974a5e294bcb8f8e025c1 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Sun, 4 Aug 2019 15:53:38 -0400 Subject: [PATCH 1005/3747] Cleanup formatting --- src/shims/foreign_items.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 6ae99c9bc15cd..24bdc98fe8eb7 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -969,13 +969,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // Shims the linux 'getrandom()' syscall -fn linux_getrandom<'mir, 'tcx>(this: &mut MiriEvalContext<'mir, 'tcx>, - args: &[OpTy<'tcx, Tag>], - dest: PlaceTy<'tcx, Tag>) -> InterpResult<'tcx> { +fn linux_getrandom<'tcx>( + this: &mut MiriEvalContext<'_, 'tcx>, + args: &[OpTy<'tcx, Tag>], + dest: PlaceTy<'tcx, Tag> +) -> InterpResult<'tcx> { let ptr = this.read_scalar(args[0])?.not_undef()?; let len = this.read_scalar(args[1])?.to_usize(this)?; - // The only supported flags are GRND_RANDOM and GRND_NONBLOCK, // neither of which have any effect on our current PRNG let _flags = this.read_scalar(args[2])?.to_i32()?; From 6b087d25362a3461f76cdee5a62fb76d2d8023fd Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Sun, 4 Aug 2019 15:53:49 -0400 Subject: [PATCH 1006/3747] Add test --- tests/run-pass/linux-getrandom.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 tests/run-pass/linux-getrandom.rs diff --git a/tests/run-pass/linux-getrandom.rs b/tests/run-pass/linux-getrandom.rs new file mode 100644 index 0000000000000..ded5596d8072b --- /dev/null +++ b/tests/run-pass/linux-getrandom.rs @@ -0,0 +1,12 @@ +// only-linux: Uses Linux-only APIs + +#![feature(rustc_private)] +extern crate libc; + +fn main() { + let mut buf = [0u8; 5]; + unsafe { + assert_eq!(libc::syscall(libc::SYS_getrandom, 0 as *mut libc::c_void, 0 as libc::size_t, 0 as libc::c_uint), 0); + assert_eq!(libc::syscall(libc::SYS_getrandom, buf.as_mut_ptr() as *mut libc::c_void, 5 as libc::size_t, 0 as libc::c_uint), 5); + } +} From 8650f02bc983a34b3c7923850fca07c2ddf2d544 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Sun, 4 Aug 2019 15:59:20 -0400 Subject: [PATCH 1007/3747] Add trailing comma --- src/shims/foreign_items.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 24bdc98fe8eb7..887fb8e5d80ac 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -972,7 +972,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn linux_getrandom<'tcx>( this: &mut MiriEvalContext<'_, 'tcx>, args: &[OpTy<'tcx, Tag>], - dest: PlaceTy<'tcx, Tag> + dest: PlaceTy<'tcx, Tag>, ) -> InterpResult<'tcx> { let ptr = this.read_scalar(args[0])?.not_undef()?; let len = this.read_scalar(args[1])?.to_usize(this)?; From a74a04f35676f9061691844b2852c499d953a731 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Sun, 4 Aug 2019 16:11:52 -0400 Subject: [PATCH 1008/3747] Test 'libc::getrandom' as well --- tests/run-pass/linux-getrandom.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/run-pass/linux-getrandom.rs b/tests/run-pass/linux-getrandom.rs index ded5596d8072b..b698b54a3c0ed 100644 --- a/tests/run-pass/linux-getrandom.rs +++ b/tests/run-pass/linux-getrandom.rs @@ -8,5 +8,8 @@ fn main() { unsafe { assert_eq!(libc::syscall(libc::SYS_getrandom, 0 as *mut libc::c_void, 0 as libc::size_t, 0 as libc::c_uint), 0); assert_eq!(libc::syscall(libc::SYS_getrandom, buf.as_mut_ptr() as *mut libc::c_void, 5 as libc::size_t, 0 as libc::c_uint), 5); + + assert_eq!(libc::getrandom(0 as *mut libc::c_void, 0 as libc::size_t, 0 as libc::c_uint), 0); + assert_eq!(libc::getrandom(buf.as_mut_ptr() as *mut libc::c_void, 5 as libc::size_t, 0 as libc::c_uint), 5); } } From 8a758177073229df9c0bdcd69f3bcd7bbe5601c9 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Sun, 4 Aug 2019 16:30:33 -0400 Subject: [PATCH 1009/3747] Fix identation --- tests/run-pass/linux-getrandom.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/run-pass/linux-getrandom.rs b/tests/run-pass/linux-getrandom.rs index b698b54a3c0ed..d9d588221c974 100644 --- a/tests/run-pass/linux-getrandom.rs +++ b/tests/run-pass/linux-getrandom.rs @@ -6,7 +6,7 @@ extern crate libc; fn main() { let mut buf = [0u8; 5]; unsafe { - assert_eq!(libc::syscall(libc::SYS_getrandom, 0 as *mut libc::c_void, 0 as libc::size_t, 0 as libc::c_uint), 0); + assert_eq!(libc::syscall(libc::SYS_getrandom, 0 as *mut libc::c_void, 0 as libc::size_t, 0 as libc::c_uint), 0); assert_eq!(libc::syscall(libc::SYS_getrandom, buf.as_mut_ptr() as *mut libc::c_void, 5 as libc::size_t, 0 as libc::c_uint), 5); assert_eq!(libc::getrandom(0 as *mut libc::c_void, 0 as libc::size_t, 0 as libc::c_uint), 0); From 66d10c877d4b68d730e6aa4759a36a68dfe97152 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Sun, 4 Aug 2019 16:40:30 -0400 Subject: [PATCH 1010/3747] Ignore other platforms instead of using only-linux --- tests/run-pass/linux-getrandom.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/run-pass/linux-getrandom.rs b/tests/run-pass/linux-getrandom.rs index d9d588221c974..8da2ce46fe7d4 100644 --- a/tests/run-pass/linux-getrandom.rs +++ b/tests/run-pass/linux-getrandom.rs @@ -1,5 +1,7 @@ -// only-linux: Uses Linux-only APIs - +// Unfortunately, compiletest_rs does not support 'only-linux', +// so we need to ignore Windows and OS X instead +// ignore-macos: Uses Linux-only APIs +// ignore-windows: Uses Linux-only APIs #![feature(rustc_private)] extern crate libc; From a208f2fccf30329f148fbc1f742e4c0af2417059 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Sun, 4 Aug 2019 16:44:32 -0400 Subject: [PATCH 1011/3747] Improve formatting Co-Authored-By: Ralf Jung --- tests/run-pass/linux-getrandom.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/run-pass/linux-getrandom.rs b/tests/run-pass/linux-getrandom.rs index 8da2ce46fe7d4..f582a282c59b4 100644 --- a/tests/run-pass/linux-getrandom.rs +++ b/tests/run-pass/linux-getrandom.rs @@ -1,5 +1,5 @@ // Unfortunately, compiletest_rs does not support 'only-linux', -// so we need to ignore Windows and OS X instead +// so we need to ignore Windows and macOS instead. // ignore-macos: Uses Linux-only APIs // ignore-windows: Uses Linux-only APIs #![feature(rustc_private)] From f830a6c69ecef2e87a24be1dca68537411b04f84 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Sun, 4 Aug 2019 16:57:17 -0400 Subject: [PATCH 1012/3747] Apply more formatting fixes Co-Authored-By: Ralf Jung --- src/shims/foreign_items.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 887fb8e5d80ac..538109eceae7e 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -294,7 +294,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx match this.read_scalar(args[0])?.to_usize(this)? { id if id == sys_getrandom => { // The first argument is the syscall id, - // so skip over it + // so skip over it. linux_getrandom(this, &args[1..], dest)?; } id => { @@ -968,7 +968,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } -// Shims the linux 'getrandom()' syscall +// Shims the linux 'getrandom()' syscall. fn linux_getrandom<'tcx>( this: &mut MiriEvalContext<'_, 'tcx>, args: &[OpTy<'tcx, Tag>], @@ -978,7 +978,7 @@ fn linux_getrandom<'tcx>( let len = this.read_scalar(args[1])?.to_usize(this)?; // The only supported flags are GRND_RANDOM and GRND_NONBLOCK, - // neither of which have any effect on our current PRNG + // neither of which have any effect on our current PRNG. let _flags = this.read_scalar(args[2])?.to_i32()?; this.gen_random(ptr, len as usize)?; From d26917a9d6d6eebb37b16d896cdef9953ce34e2f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 5 Aug 2019 10:45:48 +0200 Subject: [PATCH 1013/3747] fix for latest rustc --- rust-version | 2 +- src/shims/foreign_items.rs | 4 ++-- src/shims/intrinsics.rs | 6 +++--- src/shims/tls.rs | 2 +- src/stacked_borrows.rs | 14 +++++++------- tests/compile-fail/assume.rs | 2 +- 6 files changed, 15 insertions(+), 15 deletions(-) diff --git a/rust-version b/rust-version index 94c6f5e4b8c97..0680001291b77 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -a45743345659c775b01484574af2818c46a2cb03 +11a51488f03405ea539a9fe84973ee972eaa7b96 diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 538109eceae7e..37e5fe42c3de7 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -655,9 +655,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // This is `libc::pthread_key_t`. let key_type = args[0].layout.ty .builtin_deref(true) - .ok_or_else(|| err_ub!(Ub(format!( + .ok_or_else(|| err_ub_format!( "wrong signature used for `pthread_key_create`: first argument must be a raw pointer." - ))))? + ))? .ty; let key_layout = this.layout_of(key_type)?; diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 52a17a92c2eda..c96869c80cee7 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -44,7 +44,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "assume" => { let cond = this.read_scalar(args[0])?.to_bool()?; if !cond { - throw_unsup!(AssumptionNotHeld); + throw_ub_format!("`assume` intrinsic called with `false`"); } } @@ -316,9 +316,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Check if `b` is -1, which is the "min_value / -1" case. let minus1 = Scalar::from_int(-1, dest.layout.size); return Err(if b.to_scalar().unwrap() == minus1 { - err_ub!(Ub(format!("exact_div: result of dividing MIN by -1 cannot be represented"))) + err_ub_format!("exact_div: result of dividing MIN by -1 cannot be represented") } else { - err_ub!(Ub(format!("exact_div: {:?} cannot be divided by {:?} without remainder", *a, *b))) + err_ub_format!("exact_div: {:?} cannot be divided by {:?} without remainder", *a, *b) }.into()); } this.binop_ignore_overflow(mir::BinOp::Div, a, b, dest)?; diff --git a/src/shims/tls.rs b/src/shims/tls.rs index 05b8dc15da66b..d2190bd969e3d 100644 --- a/src/shims/tls.rs +++ b/src/shims/tls.rs @@ -158,7 +158,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx StackPopCleanup::None { cleanup: true }, )?; let arg_local = this.frame().body.args_iter().next().ok_or_else( - || err_ub!(Ub(format!("TLS dtor does not take enough arguments."))), + || err_ub_format!("TLS dtor does not take enough arguments."), )?; let dest = this.local_place(arg_local)?; this.write_scalar(ptr, dest)?; diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 0fbc3e1ac281d..01ed6ec225d20 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -273,14 +273,14 @@ impl<'tcx> Stack { if let Some(call) = item.protector { if global.is_active(call) { if let Some(tag) = tag { - throw_ub_format!( + throw_ub!(UbExperimental(format!( "not granting access to tag {:?} because incompatible item is protected: {:?}", tag, item - ); + ))); } else { - throw_ub_format!( + throw_ub!(UbExperimental(format!( "deallocating while item is protected: {:?}", item - ); + ))); } } } @@ -299,7 +299,7 @@ impl<'tcx> Stack { // Step 1: Find granting item. let granting_idx = self.find_granting(access, tag) - .ok_or_else(|| err_ub!(Ub(format!( + .ok_or_else(|| err_ub!(UbExperimental(format!( "no item granting {} to tag {:?} found in borrow stack", access, tag, ))))?; @@ -346,7 +346,7 @@ impl<'tcx> Stack { ) -> InterpResult<'tcx> { // Step 1: Find granting item. self.find_granting(AccessKind::Write, tag) - .ok_or_else(|| err_ub!(Ub(format!( + .ok_or_else(|| err_ub!(UbExperimental(format!( "no item granting write access for deallocation to tag {:?} found in borrow stack", tag, ))))?; @@ -378,7 +378,7 @@ impl<'tcx> Stack { // Now we figure out which item grants our parent (`derived_from`) this kind of access. // We use that to determine where to put the new item. let granting_idx = self.find_granting(access, derived_from) - .ok_or_else(|| err_ub!(Ub(format!( + .ok_or_else(|| err_ub!(UbExperimental(format!( "trying to reborrow for {:?}, but parent tag {:?} does not have an appropriate item in the borrow stack", new.perm, derived_from, ))))?; diff --git a/tests/compile-fail/assume.rs b/tests/compile-fail/assume.rs index 3026124e1f9af..7b18cab798057 100644 --- a/tests/compile-fail/assume.rs +++ b/tests/compile-fail/assume.rs @@ -5,6 +5,6 @@ fn main() { unsafe { std::intrinsics::assume(x < 10); std::intrinsics::assume(x > 1); - std::intrinsics::assume(x > 42); //~ `assume` argument was false + std::intrinsics::assume(x > 42); //~ `assume` intrinsic called with `false` } } From b0cb603e3afa8761fcfbaaa196e1f5ff9448357b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 5 Aug 2019 15:49:19 +0200 Subject: [PATCH 1014/3747] rustup --- rust-version | 2 +- src/machine.rs | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 0680001291b77..e09b2fc7e55f4 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -11a51488f03405ea539a9fe84973ee972eaa7b96 +4be067558962c004b638e4c6f162d50f7c0c98b6 diff --git a/src/machine.rs b/src/machine.rs index 30f3231308a47..f2c81c92d3d00 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -141,6 +141,8 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { const STATIC_KIND: Option = Some(MiriMemoryKind::Static); + const CHECK_ALIGN: bool = true; + #[inline(always)] fn enforce_validity(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool { ecx.memory().extra.validate From cc8d9956054246ef78c27e58eb0a1ef1df8c1fd2 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 6 Aug 2019 08:05:32 +0200 Subject: [PATCH 1015/3747] go back to released xargo (the experiment is done) --- src/bin/cargo-miri.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 8d7bbace0edd6..2202465709d5e 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -250,8 +250,7 @@ fn setup(ask_user: bool) { println!("Installing xargo: `cargo install xargo -f`"); } - // FIXME: Install from crates.io again once a new xargo got released. - if cargo().args(&["install", "xargo", "-f", "--git", "https://github.com/japaric/xargo"]).status() + if cargo().args(&["install", "xargo", "-f"]).status() .expect("failed to install xargo") .success().not() { From c73b13fc5847f60f51a3f060fde2242bfb5cbeba Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 6 Aug 2019 12:50:22 +0200 Subject: [PATCH 1016/3747] test-cargo-miri: cargo update --- test-cargo-miri/Cargo.lock | 48 +++++++++++++++++--------------------- 1 file changed, 22 insertions(+), 26 deletions(-) diff --git a/test-cargo-miri/Cargo.lock b/test-cargo-miri/Cargo.lock index 55e5a3dfc185d..3b4dbdcf1d2e0 100644 --- a/test-cargo-miri/Cargo.lock +++ b/test-cargo-miri/Cargo.lock @@ -2,7 +2,7 @@ # It is not intended for manual editing. [[package]] name = "autocfg" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -28,26 +28,28 @@ dependencies = [ "rand 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "cfg-if" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "getrandom" -version = "0.1.6" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "lazy_static" version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "spin 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", -] [[package]] name = "libc" -version = "0.2.58" +version = "0.2.60" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -55,7 +57,7 @@ name = "num_cpus" version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -68,9 +70,9 @@ name = "rand" version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "getrandom 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_chacha 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "getrandom 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_chacha 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand_pcg 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -78,10 +80,9 @@ dependencies = [ [[package]] name = "rand_chacha" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "c2-chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -91,7 +92,7 @@ name = "rand_core" version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "getrandom 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "getrandom 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -107,27 +108,22 @@ name = "rand_pcg" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "spin" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - [metadata] -"checksum autocfg 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "0e49efa51329a5fd37e7c79db4621af617cd4e3e5bc224939808d076077077bf" +"checksum autocfg 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "22130e92352b948e7e82a49cdb0aa94f2211761117f29e052dd397c1ac33542b" "checksum byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a7c3dd8985a7111efc5c80b44e23ecdd8c007de8ade3b96595387e812b957cf5" "checksum c2-chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7d64d04786e0f528460fc884753cf8dddcc466be308f6026f8e355c41a0e4101" -"checksum getrandom 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "e65cce4e5084b14874c4e7097f38cab54f47ee554f9194673456ea379dcc4c55" +"checksum cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "b486ce3ccf7ffd79fdeb678eac06a9e6c09fc88d33836340becb8fffe87c5e33" +"checksum getrandom 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "34f33de6f0ae7c9cb5e574502a562e2b512799e32abb801cd1e79ad952b62b49" "checksum lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bc5729f27f159ddd61f4df6228e827e86643d4d3e7c32183cb30a1c08f604a14" -"checksum libc 0.2.58 (registry+https://github.com/rust-lang/crates.io-index)" = "6281b86796ba5e4366000be6e9e18bf35580adf9e63fbe2294aadb587613a319" +"checksum libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)" = "d44e80633f007889c7eff624b709ab43c92d708caad982295768a7b13ca3b5eb" "checksum num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bcef43580c035376c0705c42792c294b66974abbfd2789b511784023f71f3273" "checksum ppv-lite86 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e3cbf9f658cdb5000fcf6f362b8ea2ba154b9f146a61c7a20d647034c6b6561b" "checksum rand 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d47eab0e83d9693d40f825f86948aa16eff6750ead4bdffc4ab95b8b3a7f052c" -"checksum rand_chacha 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e193067942ef6f485a349a113329140d0ab9e2168ce92274499bb0e9a4190d9d" +"checksum rand_chacha 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "03a2a90da8c7523f554344f921aa97283eadf6ac484a6d2a7d0212fa7f8d6853" "checksum rand_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "615e683324e75af5d43d8f7a39ffe3ee4a9dc42c5c701167a71dc59c3a493aca" "checksum rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" "checksum rand_pcg 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3e196346cbbc5c70c77e7b4926147ee8e383a38ee4d15d58a08098b169e492b6" -"checksum spin 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "44363f6f51401c34e7be73db0db371c04705d35efbe9f7d6082e03a921a32c55" From 3fe4eec37a7fce551b6f3c96e67b70151bc468e2 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 6 Aug 2019 20:52:09 +0200 Subject: [PATCH 1017/3747] mention that we get the toolchain right --- src/bin/cargo-miri.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 2202465709d5e..4da039a42d9e6 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -268,7 +268,7 @@ fn setup(ask_user: bool) { let src = Path::new(sysroot.trim_end_matches('\n')).join("lib").join("rustlib").join("src"); if !src.exists() { if ask_user { - ask("It seems you do not have the rust-src component installed. I will run `rustup component add rust-src`. Proceed?"); + ask("It seems you do not have the rust-src component installed. I will run `rustup component add rust-src` for the selected toolchain. Proceed?"); } else { println!("Installing rust-src component: `rustup component add rust-src`"); } From 655f9af7fe315a9f8e881d94b7c221c965a7caae Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Tue, 6 Aug 2019 10:28:50 -0500 Subject: [PATCH 1018/3747] Add flag to enable communication --- benches/helpers/miri_helper.rs | 2 +- src/bin/miri-rustc-tests.rs | 5 +++-- src/bin/miri.rs | 6 +++++- src/eval.rs | 5 +++-- 4 files changed, 12 insertions(+), 6 deletions(-) diff --git a/benches/helpers/miri_helper.rs b/benches/helpers/miri_helper.rs index 203a8b1133a5c..003c93f7464d7 100644 --- a/benches/helpers/miri_helper.rs +++ b/benches/helpers/miri_helper.rs @@ -25,7 +25,7 @@ impl rustc_driver::Callbacks for MiriCompilerCalls<'_> { ); self.bencher.iter(|| { - let config = miri::MiriConfig { validate: true, args: vec![], seed: None }; + let config = miri::MiriConfig { validate: true, communicate: false, args: vec![], seed: None }; eval_main(tcx, entry_def_id, config); }); }); diff --git a/src/bin/miri-rustc-tests.rs b/src/bin/miri-rustc-tests.rs index dae5189937a33..a1bc53f69b800 100644 --- a/src/bin/miri-rustc-tests.rs +++ b/src/bin/miri-rustc-tests.rs @@ -48,7 +48,7 @@ impl rustc_driver::Callbacks for MiriCompilerCalls { fn visit_item(&mut self, i: &'hir hir::Item) { if let hir::ItemKind::Fn(.., body_id) = i.node { if i.attrs.iter().any(|attr| attr.check_name(syntax::symbol::sym::test)) { - let config = MiriConfig { validate: true, args: vec![], seed: None }; + let config = MiriConfig { validate: true, communicate: false, args: vec![], seed: None }; let did = self.0.hir().body_owner_def_id(body_id); println!("running test: {}", self.0.def_path_debug_str(did)); miri::eval_main(self.0, did, config); @@ -61,7 +61,8 @@ impl rustc_driver::Callbacks for MiriCompilerCalls { } tcx.hir().krate().visit_all_item_likes(&mut Visitor(tcx)); } else if let Some((entry_def_id, _)) = tcx.entry_fn(LOCAL_CRATE) { - let config = MiriConfig { validate: true, args: vec![], seed: None }; + + let config = MiriConfig { validate: true, communicate: false, args: vec![], seed: None }; miri::eval_main(tcx, entry_def_id, config); compiler.session().abort_if_errors(); diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 43cb19b2658ef..875afd42af441 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -130,6 +130,7 @@ fn main() { // Parse our arguments and split them across `rustc` and `miri`. let mut validate = true; + let mut communicate = false; let mut seed: Option = None; let mut rustc_args = vec![]; let mut miri_args = vec![]; @@ -147,6 +148,9 @@ fn main() { "-Zmiri-disable-validation" => { validate = false; }, + "-Zmiri-enable-communication" => { + communicate = true; + }, "--" => { after_dashdash = true; } @@ -196,7 +200,7 @@ fn main() { debug!("rustc arguments: {:?}", rustc_args); debug!("miri arguments: {:?}", miri_args); - let miri_config = miri::MiriConfig { validate, args: miri_args, seed }; + let miri_config = miri::MiriConfig { validate, communicate, args: miri_args, seed }; let result = rustc_driver::report_ices_to_stderr_if_any(move || { rustc_driver::run_compiler(&rustc_args, &mut MiriCompilerCalls { miri_config }, None, None) }).and_then(|result| result); diff --git a/src/eval.rs b/src/eval.rs index bc9d97b0280f1..681bad01d23cc 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -18,10 +18,11 @@ use crate::{ #[derive(Clone)] pub struct MiriConfig { pub validate: bool, + pub communicate: bool, pub args: Vec, // The seed to use when non-determinism is required (e.g. getrandom()) - pub seed: Option + pub seed: Option, } // Used by priroda. @@ -158,7 +159,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( cur_ptr = cur_ptr.offset(char_size, tcx)?; } } - + assert!(args.next().is_none(), "start lang item has more arguments than expected"); Ok(ecx) From 068c448832c466e3eb6297125a12e5a83a450e2d Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Tue, 6 Aug 2019 15:32:57 -0500 Subject: [PATCH 1019/3747] Add communicate field to evaluator and fix formatting --- benches/helpers/miri_helper.rs | 7 ++++++- src/bin/miri-rustc-tests.rs | 14 ++++++++++++-- src/eval.rs | 5 +++-- src/machine.rs | 6 +++++- 4 files changed, 26 insertions(+), 6 deletions(-) diff --git a/benches/helpers/miri_helper.rs b/benches/helpers/miri_helper.rs index 003c93f7464d7..5cb938659a6cd 100644 --- a/benches/helpers/miri_helper.rs +++ b/benches/helpers/miri_helper.rs @@ -25,7 +25,12 @@ impl rustc_driver::Callbacks for MiriCompilerCalls<'_> { ); self.bencher.iter(|| { - let config = miri::MiriConfig { validate: true, communicate: false, args: vec![], seed: None }; + let config = miri::MiriConfig { + validate: true, + communicate: false, + args: vec![], + seed: None, + }; eval_main(tcx, entry_def_id, config); }); }); diff --git a/src/bin/miri-rustc-tests.rs b/src/bin/miri-rustc-tests.rs index a1bc53f69b800..0cf171f52e7e6 100644 --- a/src/bin/miri-rustc-tests.rs +++ b/src/bin/miri-rustc-tests.rs @@ -48,7 +48,12 @@ impl rustc_driver::Callbacks for MiriCompilerCalls { fn visit_item(&mut self, i: &'hir hir::Item) { if let hir::ItemKind::Fn(.., body_id) = i.node { if i.attrs.iter().any(|attr| attr.check_name(syntax::symbol::sym::test)) { - let config = MiriConfig { validate: true, communicate: false, args: vec![], seed: None }; + let config = MiriConfig { + validate: true, + communicate: false, + args: vec![], + seed: None, + }; let did = self.0.hir().body_owner_def_id(body_id); println!("running test: {}", self.0.def_path_debug_str(did)); miri::eval_main(self.0, did, config); @@ -62,7 +67,12 @@ impl rustc_driver::Callbacks for MiriCompilerCalls { tcx.hir().krate().visit_all_item_likes(&mut Visitor(tcx)); } else if let Some((entry_def_id, _)) = tcx.entry_fn(LOCAL_CRATE) { - let config = MiriConfig { validate: true, communicate: false, args: vec![], seed: None }; + let config = MiriConfig { + validate: true, + communicate: false, + args: vec![], + seed: None + }; miri::eval_main(tcx, entry_def_id, config); compiler.session().abort_if_errors(); diff --git a/src/eval.rs b/src/eval.rs index 681bad01d23cc..e80162ec1796d 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -18,10 +18,11 @@ use crate::{ #[derive(Clone)] pub struct MiriConfig { pub validate: bool, + /// Determines if communication with the host environment is enabled. pub communicate: bool, pub args: Vec, - // The seed to use when non-determinism is required (e.g. getrandom()) + /// The seed to use when non-determinism is required (e.g. getrandom()) pub seed: Option, } @@ -34,7 +35,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( let mut ecx = InterpCx::new( tcx.at(syntax::source_map::DUMMY_SP), ty::ParamEnv::reveal_all(), - Evaluator::new(), + Evaluator::new(config.communicate), MemoryExtra::new(StdRng::seed_from_u64(config.seed.unwrap_or(0)), config.validate), ); diff --git a/src/machine.rs b/src/machine.rs index f2c81c92d3d00..ed9a8a1c46346 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -93,10 +93,13 @@ pub struct Evaluator<'tcx> { /// TLS state. pub(crate) tls: TlsData<'tcx>, + + /// If enabled, the `env_vars` field is populated with the host env vars during initialization. + pub(crate) communicate: bool, } impl<'tcx> Evaluator<'tcx> { - pub(crate) fn new() -> Self { + pub(crate) fn new(communicate: bool) -> Self { Evaluator { env_vars: HashMap::default(), argc: None, @@ -104,6 +107,7 @@ impl<'tcx> Evaluator<'tcx> { cmd_line: None, last_error: 0, tls: TlsData::default(), + communicate, } } } From 0df7a728c684606a3ee275ca32d3d56c17902c76 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Tue, 6 Aug 2019 15:47:57 -0500 Subject: [PATCH 1020/3747] Update readme --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index 8c5a29880c7cb..a9cd9ee938c59 100644 --- a/README.md +++ b/README.md @@ -157,6 +157,9 @@ Several `-Z` flags are relevant for Miri: is enforced by default. This is mostly useful for debugging; it means Miri will miss bugs in your program. However, this can also help to make Miri run faster. +* `-Zmiri-enable-communication` enables communication between the host + environment and Miri, i.e., all the host environment variables are available + during Miri runtime. * `-Zmir-opt-level` controls how many MIR optimizations are performed. Miri overrides the default to be `0`; be advised that using any higher level can make Miri miss bugs in your program because they got optimized away. From b731a6a15f3ac426ca29f5bdbe4e3d7bd68d9685 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Tue, 6 Aug 2019 17:40:07 -0500 Subject: [PATCH 1021/3747] Add support for env communication --- src/eval.rs | 8 ++++++++ src/shims/env.rs | 23 +++++++++++++++++++++++ src/shims/foreign_items.rs | 23 +++-------------------- src/shims/mod.rs | 1 + tests/run-pass/communication.rs | 6 ++++++ 5 files changed, 41 insertions(+), 20 deletions(-) create mode 100644 src/shims/env.rs create mode 100644 tests/run-pass/communication.rs diff --git a/src/eval.rs b/src/eval.rs index e80162ec1796d..b171b38a6cbd5 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -13,6 +13,7 @@ use crate::{ Scalar, Tag, Pointer, FnVal, MemoryExtra, MiriMemoryKind, Evaluator, TlsEvalContextExt, HelpersEvalContextExt, }; +use crate::shims::env::alloc_env_value; /// Configuration needed to spawn a Miri instance. #[derive(Clone)] @@ -163,6 +164,13 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( assert!(args.next().is_none(), "start lang item has more arguments than expected"); + if config.communicate { + for (name, value) in std::env::vars() { + let value = alloc_env_value(value.as_bytes(), ecx.memory_mut(), &tcx); + ecx.machine.env_vars.insert(name.into_bytes(), value); + } + } + Ok(ecx) } diff --git a/src/shims/env.rs b/src/shims/env.rs new file mode 100644 index 0000000000000..0cb8c9c370c3c --- /dev/null +++ b/src/shims/env.rs @@ -0,0 +1,23 @@ +use rustc::ty::{layout::{Size, Align}, TyCtxt}; +use rustc_mir::interpret::Memory; + +use crate::*; + +pub(crate) fn alloc_env_value<'mir, 'tcx>(bytes: &[u8], memory: &mut Memory<'mir, 'tcx, Evaluator<'tcx>>, tcx: &TyCtxt<'tcx>) -> Pointer { + let length = bytes.len() as u64; + // `+1` for the null terminator. + let ptr = memory.allocate( + Size::from_bytes(length + 1), + Align::from_bytes(1).unwrap(), + MiriMemoryKind::Env.into(), + ); + // We just allocated these, so the write cannot fail. + let alloc = memory.get_mut(ptr.alloc_id).unwrap(); + alloc.write_bytes(tcx, ptr, &bytes).unwrap(); + let trailing_zero_ptr = ptr.offset( + Size::from_bytes(length), + tcx, + ).unwrap(); + alloc.write_bytes(tcx, trailing_zero_ptr, &[0]).unwrap(); + ptr +} diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 37e5fe42c3de7..b1554395b692b 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -5,6 +5,7 @@ use syntax::attr; use syntax::symbol::sym; use crate::*; +use crate::shims::env::alloc_env_value; impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { @@ -465,26 +466,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } if let Some((name, value)) = new { - // `+1` for the null terminator. - let value_copy = this.memory_mut().allocate( - Size::from_bytes((value.len() + 1) as u64), - Align::from_bytes(1).unwrap(), - MiriMemoryKind::Env.into(), - ); - // We just allocated these, so the write cannot fail. - let alloc = this.memory_mut().get_mut(value_copy.alloc_id).unwrap(); - alloc.write_bytes(tcx, value_copy, &value).unwrap(); - let trailing_zero_ptr = value_copy.offset( - Size::from_bytes(value.len() as u64), - tcx, - ).unwrap(); - alloc.write_bytes(tcx, trailing_zero_ptr, &[0]).unwrap(); - - if let Some(var) = this.machine.env_vars.insert( - name.to_owned(), - value_copy, - ) - { + let value_copy = alloc_env_value(&value, this.memory_mut(), tcx); + if let Some(var) = this.machine.env_vars.insert(name.to_owned(), value_copy) { this.memory_mut().deallocate(var, None, MiriMemoryKind::Env.into())?; } this.write_null(dest)?; diff --git a/src/shims/mod.rs b/src/shims/mod.rs index c06373005ff99..96a1f34152b32 100644 --- a/src/shims/mod.rs +++ b/src/shims/mod.rs @@ -2,6 +2,7 @@ pub mod foreign_items; pub mod intrinsics; pub mod tls; pub mod dlsym; +pub mod env; use rustc::{ty, mir}; diff --git a/tests/run-pass/communication.rs b/tests/run-pass/communication.rs new file mode 100644 index 0000000000000..08c6bd88fd686 --- /dev/null +++ b/tests/run-pass/communication.rs @@ -0,0 +1,6 @@ +// ignore-windows: TODO env var emulation stubbed out on Windows +// compile-flags: -Zmiri-enable-communication + +fn main() { + assert!(std::env::var("PWD").is_ok()); +} From 455531c564b7c849eb505876a9810f98e2f9fca2 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 7 Aug 2019 10:24:27 +0200 Subject: [PATCH 1022/3747] Revert "uninit intrinsic is gone" This reverts commit fa290f1a481b0f98ed1de06206e643af8e04acd5. Uninit is being reinstated because it breaks some broken code. --- src/shims/intrinsics.rs | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index c96869c80cee7..4e957f792b751 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -522,6 +522,37 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(res, dest)?; } + "uninit" => { + // Check fast path: we don't want to force an allocation in case the destination is a simple value, + // but we also do not want to create a new allocation with 0s and then copy that over. + // FIXME: We do not properly validate in case of ZSTs and when doing it in memory! + // However, this only affects direct calls of the intrinsic; calls to the stable + // functions wrapping them do get their validation. + // FIXME: should we check alignment for ZSTs? + use crate::ScalarMaybeUndef; + if !dest.layout.is_zst() { + match dest.layout.abi { + layout::Abi::Scalar(..) => { + let x = ScalarMaybeUndef::Undef; + this.write_immediate(Immediate::Scalar(x), dest)?; + } + layout::Abi::ScalarPair(..) => { + let x = ScalarMaybeUndef::Undef; + this.write_immediate(Immediate::ScalarPair(x, x), dest)?; + } + _ => { + // Do it in memory + let mplace = this.force_allocation(dest)?; + assert!(mplace.meta.is_none()); + let ptr = mplace.ptr.to_ptr()?; + this.memory_mut() + .get_mut(ptr.alloc_id)? + .mark_definedness(ptr, dest.layout.size, false); + } + } + } + } + "write_bytes" => { let ty = substs.type_at(0); let ty_layout = this.layout_of(ty)?; From af623dede2437244eabe7a6833b28ec2535de82a Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Wed, 7 Aug 2019 09:09:13 -0500 Subject: [PATCH 1023/3747] Add env var test variable in compiletest --- tests/compiletest.rs | 3 +++ tests/run-pass/communication.rs | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/tests/compiletest.rs b/tests/compiletest.rs index eaf7f8531b8fc..c5fba3d46e2f3 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -37,6 +37,9 @@ fn run_tests(mode: &str, path: &str, target: &str, mut flags: Vec) { flags.push(format!("--sysroot {}", sysroot)); } + // Add a test env var to do evironment communication tests + std::env::set_var("MIRI_ENV_VAR_TEST", "0"); + // The rest of the configuration. let mut config = compiletest::Config::default().tempdir(); config.mode = mode.parse().expect("Invalid mode"); diff --git a/tests/run-pass/communication.rs b/tests/run-pass/communication.rs index 08c6bd88fd686..e3fb0c5bd5e09 100644 --- a/tests/run-pass/communication.rs +++ b/tests/run-pass/communication.rs @@ -2,5 +2,5 @@ // compile-flags: -Zmiri-enable-communication fn main() { - assert!(std::env::var("PWD").is_ok()); + assert_eq!(std::env::var("MIRI_ENV_VAR_TEST"), Ok("0".to_owned())); } From 253af9692afebc1a4b460fd2ac2cc842d007d573 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Wed, 7 Aug 2019 09:10:39 -0500 Subject: [PATCH 1024/3747] Fix formatting --- src/shims/env.rs | 6 +++++- tests/compiletest.rs | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/shims/env.rs b/src/shims/env.rs index 0cb8c9c370c3c..56d2bd4b3d3e2 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -3,7 +3,11 @@ use rustc_mir::interpret::Memory; use crate::*; -pub(crate) fn alloc_env_value<'mir, 'tcx>(bytes: &[u8], memory: &mut Memory<'mir, 'tcx, Evaluator<'tcx>>, tcx: &TyCtxt<'tcx>) -> Pointer { +pub(crate) fn alloc_env_value<'mir, 'tcx>( + bytes: &[u8], + memory: &mut Memory<'mir, 'tcx, Evaluator<'tcx>>, + tcx: &TyCtxt<'tcx>, +) -> Pointer { let length = bytes.len() as u64; // `+1` for the null terminator. let ptr = memory.allocate( diff --git a/tests/compiletest.rs b/tests/compiletest.rs index c5fba3d46e2f3..f61faa9fcc61f 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -37,7 +37,7 @@ fn run_tests(mode: &str, path: &str, target: &str, mut flags: Vec) { flags.push(format!("--sysroot {}", sysroot)); } - // Add a test env var to do evironment communication tests + // Add a test env var to do environment communication tests std::env::set_var("MIRI_ENV_VAR_TEST", "0"); // The rest of the configuration. From f544721de41b6b5e7b93dbc85840431abe195614 Mon Sep 17 00:00:00 2001 From: Tyler Mandry Date: Wed, 7 Aug 2019 16:39:54 -0700 Subject: [PATCH 1025/3747] Add generator, async tests with uninhabited saved local --- tests/run-pass/async-fn.rs | 36 ++++++++++++++++++++++++++++++++++++ tests/run-pass/generator.rs | 13 +++++++++++++ 2 files changed, 49 insertions(+) diff --git a/tests/run-pass/async-fn.rs b/tests/run-pass/async-fn.rs index 5c916473b5804..25b9b9ac5ba4b 100644 --- a/tests/run-pass/async-fn.rs +++ b/tests/run-pass/async-fn.rs @@ -14,6 +14,32 @@ pub async fn foo(x: &u32, y: u32) -> u32 { *x + y + *a } +async fn add(x: u32, y: u32) -> u32 { + async { x + y }.await +} + +async fn build_aggregate(a: u32, b: u32, c: u32, d: u32) -> u32 { + let x = (add(a, b).await, add(c, d).await); + x.0 + x.1 +} + +enum Never {} +fn never() -> Never { + panic!() +} + +async fn includes_never(crash: bool, x: u32) -> u32 { + let mut result = async { x * x }.await; + if !crash { + return result; + } + #[allow(unused)] + let bad = never(); + result *= async { x + x }.await; + drop(bad); + result +} + fn raw_waker_clone(_this: *const ()) -> RawWaker { panic!("unimplemented"); } @@ -38,4 +64,14 @@ fn main() { let waker = unsafe { Waker::from_raw(RawWaker::new(ptr::null(), &RAW_WAKER)) }; let mut context = Context::from_waker(&waker); assert_eq!(unsafe { Pin::new_unchecked(&mut fut) }.poll(&mut context), Poll::Ready(31)); + + let mut fut = build_aggregate(1, 2, 3, 4); + let waker = unsafe { Waker::from_raw(RawWaker::new(ptr::null(), &RAW_WAKER)) }; + let mut context = Context::from_waker(&waker); + assert_eq!(unsafe { Pin::new_unchecked(&mut fut) }.poll(&mut context), Poll::Ready(10)); + + let mut fut = includes_never(false, 4); + let waker = unsafe { Waker::from_raw(RawWaker::new(ptr::null(), &RAW_WAKER)) }; + let mut context = Context::from_waker(&waker); + assert_eq!(unsafe { Pin::new_unchecked(&mut fut) }.poll(&mut context), Poll::Ready(16)); } diff --git a/tests/run-pass/generator.rs b/tests/run-pass/generator.rs index 477f548a7b065..5064d8daf0f3c 100644 --- a/tests/run-pass/generator.rs +++ b/tests/run-pass/generator.rs @@ -17,7 +17,11 @@ fn finish(mut amt: usize, mut t: T) -> T::Return } } } +} +enum Never {} +fn never() -> Never { + panic!() } fn main() { @@ -67,4 +71,13 @@ fn main() { }), 10 ); + let b = true; + finish(1, || { + yield 1; + if b { return; } + #[allow(unused)] + let x = never(); + yield 2; + drop(x); + }); } From 19367fd8de5449900d9c059d84f48e8499e59b5d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 8 Aug 2019 19:34:23 +0200 Subject: [PATCH 1026/3747] bump xargo version --- src/bin/cargo-miri.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 4da039a42d9e6..b1dc306bcb1df 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -243,7 +243,7 @@ fn setup(ask_user: bool) { } // First, we need xargo. - if xargo_version().map_or(true, |v| v < (0, 3, 14)) { + if xargo_version().map_or(true, |v| v < (0, 3, 15)) { if ask_user { ask("It seems you do not have a recent enough xargo installed. I will run `cargo install xargo -f`. Proceed?"); } else { From e1d1cd191f6601b0ed2219beb7a4fb00f25b6667 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Thu, 8 Aug 2019 15:22:34 -0500 Subject: [PATCH 1027/3747] Use ldexp from cmath instead --- src/shims/foreign_items.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 37e5fe42c3de7..ba9b7ca27eb05 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -594,8 +594,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // FIXME: Using host floats. let x = f64::from_bits(this.read_scalar(args[0])?.to_u64()?); let exp = this.read_scalar(args[1])?.to_i32()?; - // FIXME: We should use cmath if there are any imprecisions. - let n = x * 2.0f64.powi(exp); + extern { + fn ldexp(x: f64, n: i32) -> f64; + } + let n = unsafe { ldexp(x, exp) }; this.write_scalar(Scalar::from_u64(n.to_bits()), dest)?; } From d5294a5bf3457c7565f1fce4ce804682a2f8fa10 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 9 Aug 2019 10:32:53 +0200 Subject: [PATCH 1028/3747] test generator that yields during initialization of struct with uninhabited field --- tests/run-pass/generator.rs | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/tests/run-pass/generator.rs b/tests/run-pass/generator.rs index 5064d8daf0f3c..c31b5b9ed3bb2 100644 --- a/tests/run-pass/generator.rs +++ b/tests/run-pass/generator.rs @@ -1,4 +1,4 @@ -#![feature(generators, generator_trait)] +#![feature(generators, generator_trait, never_type)] use std::ops::{GeneratorState, Generator}; use std::pin::Pin; @@ -26,6 +26,7 @@ fn never() -> Never { fn main() { finish(1, || yield 1); + finish(3, || { let mut x = 0; yield 1; @@ -35,23 +36,27 @@ fn main() { yield 1; assert_eq!(x, 2); }); + finish(7*8/2, || { for i in 0..8 { yield i; } }); + finish(1, || { if true { yield 1; } else { } }); + finish(1, || { if false { } else { yield 1; } }); + finish(2, || { if { yield 1; false } { yield 1; @@ -59,6 +64,7 @@ fn main() { } yield 1; }); + // also test a self-referential generator assert_eq!( finish(5, || { @@ -71,6 +77,7 @@ fn main() { }), 10 ); + let b = true; finish(1, || { yield 1; @@ -80,4 +87,10 @@ fn main() { yield 2; drop(x); }); + + finish(3, || { + yield 1; + #[allow(unreachable_code)] + let _x: (String, !) = (String::new(), { yield 2; return }); + }); } From fc06cb71bfa606ed602969868abd9623c27464e9 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 9 Aug 2019 10:26:48 +0200 Subject: [PATCH 1029/3747] simplify async-fn tests --- tests/run-pass/async-fn.rs | 53 ++++++++++++++++++-------------------- 1 file changed, 25 insertions(+), 28 deletions(-) diff --git a/tests/run-pass/async-fn.rs b/tests/run-pass/async-fn.rs index 25b9b9ac5ba4b..3f3729d708346 100644 --- a/tests/run-pass/async-fn.rs +++ b/tests/run-pass/async-fn.rs @@ -40,38 +40,35 @@ async fn includes_never(crash: bool, x: u32) -> u32 { result } -fn raw_waker_clone(_this: *const ()) -> RawWaker { - panic!("unimplemented"); -} -fn raw_waker_wake(_this: *const ()) { - panic!("unimplemented"); -} -fn raw_waker_wake_by_ref(_this: *const ()) { - panic!("unimplemented"); -} -fn raw_waker_drop(_this: *const ()) {} +fn run_fut(mut fut: impl Future, output: u32) { + fn raw_waker_clone(_this: *const ()) -> RawWaker { + panic!("unimplemented"); + } + fn raw_waker_wake(_this: *const ()) { + panic!("unimplemented"); + } + fn raw_waker_wake_by_ref(_this: *const ()) { + panic!("unimplemented"); + } + fn raw_waker_drop(_this: *const ()) {} -static RAW_WAKER: RawWakerVTable = RawWakerVTable::new( - raw_waker_clone, - raw_waker_wake, - raw_waker_wake_by_ref, - raw_waker_drop, -); + static RAW_WAKER: RawWakerVTable = RawWakerVTable::new( + raw_waker_clone, + raw_waker_wake, + raw_waker_wake_by_ref, + raw_waker_drop, + ); -fn main() { - let x = 5; - let mut fut = foo(&x, 7); let waker = unsafe { Waker::from_raw(RawWaker::new(ptr::null(), &RAW_WAKER)) }; let mut context = Context::from_waker(&waker); - assert_eq!(unsafe { Pin::new_unchecked(&mut fut) }.poll(&mut context), Poll::Ready(31)); + assert_eq!(unsafe { Pin::new_unchecked(&mut fut) }.poll(&mut context), Poll::Ready(output)); +} - let mut fut = build_aggregate(1, 2, 3, 4); - let waker = unsafe { Waker::from_raw(RawWaker::new(ptr::null(), &RAW_WAKER)) }; - let mut context = Context::from_waker(&waker); - assert_eq!(unsafe { Pin::new_unchecked(&mut fut) }.poll(&mut context), Poll::Ready(10)); +fn main() { + let x = 5; + run_fut(foo(&x, 7), 31); - let mut fut = includes_never(false, 4); - let waker = unsafe { Waker::from_raw(RawWaker::new(ptr::null(), &RAW_WAKER)) }; - let mut context = Context::from_waker(&waker); - assert_eq!(unsafe { Pin::new_unchecked(&mut fut) }.poll(&mut context), Poll::Ready(16)); + run_fut(build_aggregate(1, 2, 3, 4), 10); + + run_fut(includes_never(false, 4), 16); } From abcd2449273ebced7df695be2249f56ed4c8f331 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 9 Aug 2019 11:01:11 +0200 Subject: [PATCH 1030/3747] add async fn with partial initialization --- tests/run-pass/async-fn.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/tests/run-pass/async-fn.rs b/tests/run-pass/async-fn.rs index 3f3729d708346..91266f67aa8e4 100644 --- a/tests/run-pass/async-fn.rs +++ b/tests/run-pass/async-fn.rs @@ -1,4 +1,4 @@ -#![feature(async_await)] +#![feature(async_await, never_type)] use std::{future::Future, pin::Pin, task::Poll, ptr}; use std::task::{Waker, RawWaker, RawWakerVTable, Context}; @@ -40,6 +40,11 @@ async fn includes_never(crash: bool, x: u32) -> u32 { result } +async fn partial_init(x: u32) -> u32 { + #[allow(unreachable_code)] + let _x: (String, !) = (String::new(), return async { x + x }.await); +} + fn run_fut(mut fut: impl Future, output: u32) { fn raw_waker_clone(_this: *const ()) -> RawWaker { panic!("unimplemented"); @@ -71,4 +76,6 @@ fn main() { run_fut(build_aggregate(1, 2, 3, 4), 10); run_fut(includes_never(false, 4), 16); + + run_fut(partial_init(4), 8); } From b5ce8f410bd04b97f25b5903ca014eaf99d4dc46 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 9 Aug 2019 11:03:45 +0200 Subject: [PATCH 1031/3747] bump Rust version --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index e09b2fc7e55f4..d2d7536dcae91 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -4be067558962c004b638e4c6f162d50f7c0c98b6 +5aa3d9a7b5d3a46a7f158e8881146331a6bc9243 From 68d7e4ebb045ecd1d4ff14847d0c2cd577b0bf60 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 9 Aug 2019 11:29:10 +0200 Subject: [PATCH 1032/3747] local rustc builds now also need a sysroot built With the test-miri flag gone, the libstd of local builds isn't good enough for Miri any more. --- miri | 28 ++++++++++------------------ 1 file changed, 10 insertions(+), 18 deletions(-) diff --git a/miri b/miri index 15bfeed4da06c..1f46f04c13e8c 100755 --- a/miri +++ b/miri @@ -60,27 +60,19 @@ build_sysroot() { # Prepare and set MIRI_SYSROOT. Respects `MIRI_TEST_TARGET` and takes into account # locally built vs. distributed rustc. find_sysroot() { - # Get ourselves a sysroot if [ -n "$MIRI_SYSROOT" ]; then # Sysroot already set, use that. - true - elif echo "$SYSROOT" | egrep -q 'build/[^/]+/stage'; then - # A local rustc build. - if [ -n "$MIRI_TEST_TARGET" ]; then - # Foreign targets still need a build. Use the rustc sources. - export XARGO_RUST_SRC="$SYSROOT/../../../src" - build_sysroot --target "$MIRI_TEST_TARGET" - else - # Assume we have a proper host libstd in $SYSROOT. - MIRI_SYSROOT="$SYSROOT" - fi + return 0 + fi + # We need to build a sysroot. + if echo "$SYSROOT" | egrep -q 'build/[^/]+/stage'; then + # A local rustc build. Use its source dir. + export XARGO_RUST_SRC="$SYSROOT/../../../src" + fi + if [ -n "$MIRI_TEST_TARGET" ]; then + build_sysroot --target "$MIRI_TEST_TARGET" else - # A normal toolchain. We have to build a sysroot either way. - if [ -n "$MIRI_TEST_TARGET" ]; then - build_sysroot --target "$MIRI_TEST_TARGET" - else - build_sysroot - fi + build_sysroot fi export MIRI_SYSROOT } From b93629262dc66361387fd045e53bd01e9e45311b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 9 Aug 2019 19:21:41 +0200 Subject: [PATCH 1033/3747] test that even &Cell must be dereferencable --- ...arrier.rs => deallocate_against_barrier1.rs} | 0 .../deallocate_against_barrier2.rs | 17 +++++++++++++++++ 2 files changed, 17 insertions(+) rename tests/compile-fail/stacked_borrows/{deallocate_against_barrier.rs => deallocate_against_barrier1.rs} (100%) create mode 100644 tests/compile-fail/stacked_borrows/deallocate_against_barrier2.rs diff --git a/tests/compile-fail/stacked_borrows/deallocate_against_barrier.rs b/tests/compile-fail/stacked_borrows/deallocate_against_barrier1.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/deallocate_against_barrier.rs rename to tests/compile-fail/stacked_borrows/deallocate_against_barrier1.rs diff --git a/tests/compile-fail/stacked_borrows/deallocate_against_barrier2.rs b/tests/compile-fail/stacked_borrows/deallocate_against_barrier2.rs new file mode 100644 index 0000000000000..db4d2d998dbdf --- /dev/null +++ b/tests/compile-fail/stacked_borrows/deallocate_against_barrier2.rs @@ -0,0 +1,17 @@ +// error-pattern: deallocating while item is protected + +use std::cell::Cell; + +// Check that even `&Cell` are dereferencable. +// Also see . +fn inner(x: &Cell, f: fn(&Cell)) { + // `f` may mutate, but it may not deallocate! + f(x) +} + +fn main() { + inner(Box::leak(Box::new(Cell::new(0))), |x| { + let raw = x as *const _ as *mut Cell; + drop(unsafe { Box::from_raw(raw) }); + }); +} From 5e3035b6cbf02d29157ab5633142cf741e7b2361 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 9 Aug 2019 19:53:42 +0200 Subject: [PATCH 1034/3747] use apfloat for ldexp --- src/shims/foreign_items.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index ba9b7ca27eb05..d7c2b86c2c2de 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -1,3 +1,6 @@ +use std::convert::TryInto; + +use rustc_apfloat::Float; use rustc::ty::layout::{Align, LayoutOf, Size}; use rustc::hir::def_id::DefId; use rustc::mir; @@ -591,14 +594,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // underscore case for windows "_ldexp" | "ldexp" => { - // FIXME: Using host floats. - let x = f64::from_bits(this.read_scalar(args[0])?.to_u64()?); + let x = this.read_scalar(args[0])?.to_f64()?; let exp = this.read_scalar(args[1])?.to_i32()?; - extern { - fn ldexp(x: f64, n: i32) -> f64; - } - let n = unsafe { ldexp(x, exp) }; - this.write_scalar(Scalar::from_u64(n.to_bits()), dest)?; + // For radix-2 (binary) systems, `ldexp` and `scalbn` are the same. + let res = x.scalbn(exp.try_into().unwrap()); + this.write_scalar(Scalar::from_f64(res), dest)?; } // Some things needed for `sys::thread` initialization to go through. From 3ae01a64bcc649942cee70f6cba7e765b0850942 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 10 Aug 2019 11:22:32 +0200 Subject: [PATCH 1035/3747] also support scalbn itself --- src/shims/foreign_items.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index d7c2b86c2c2de..add6bd5bbefd6 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -580,7 +580,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx }; this.write_scalar(Scalar::from_u64(f.to_bits()), dest)?; } - // underscore case for windows + // underscore case for windows, here and below + // (see https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/floating-point-primitives?view=vs-2019) "_hypot" | "hypot" | "atan2" => { // FIXME: Using host floats. let f1 = f64::from_bits(this.read_scalar(args[0])?.to_u64()?); @@ -592,11 +593,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx }; this.write_scalar(Scalar::from_u64(n.to_bits()), dest)?; } - // underscore case for windows - "_ldexp" | "ldexp" => { + // For radix-2 (binary) systems, `ldexp` and `scalbn` are the same. + "_ldexp" | "ldexp" | "scalbn" => { let x = this.read_scalar(args[0])?.to_f64()?; let exp = this.read_scalar(args[1])?.to_i32()?; - // For radix-2 (binary) systems, `ldexp` and `scalbn` are the same. let res = x.scalbn(exp.try_into().unwrap()); this.write_scalar(Scalar::from_f64(res), dest)?; } From 0743ed631efe63ae2de96847df7b7fce629127b6 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 10 Aug 2019 11:27:27 +0200 Subject: [PATCH 1036/3747] clamp ldexp exponent to i16 --- src/shims/foreign_items.rs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index add6bd5bbefd6..4cca6b9efdd12 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -597,7 +597,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "_ldexp" | "ldexp" | "scalbn" => { let x = this.read_scalar(args[0])?.to_f64()?; let exp = this.read_scalar(args[1])?.to_i32()?; - let res = x.scalbn(exp.try_into().unwrap()); + // Saturating cast to i16. Even those are outside the valid exponent range to + // `scalbn` below will to its over/underflow handling. + let exp = if exp > i16::max_value() as i32 { + i16::max_value() + } else if exp < i16::min_value() as i32 { + i16::min_value() + } else { + exp.try_into().unwrap() + }; + let res = x.scalbn(exp); this.write_scalar(Scalar::from_f64(res), dest)?; } From 33eb5657d6b3677b000680e9fd349550143d3693 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 10 Aug 2019 11:31:20 +0200 Subject: [PATCH 1037/3747] ldexp: test overflow behavior --- tests/run-pass/intrinsics-math.rs | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/tests/run-pass/intrinsics-math.rs b/tests/run-pass/intrinsics-math.rs index 63098f5fd3f74..f435611b2b698 100644 --- a/tests/run-pass/intrinsics-math.rs +++ b/tests/run-pass/intrinsics-math.rs @@ -16,6 +16,13 @@ macro_rules! assert_approx_eq { }) } +fn ldexp(a: f64, b: i32) -> f64 { + extern { + fn ldexp(x: f64, n: i32) -> f64; + } + unsafe { ldexp(a, b) } +} + pub fn main() { use std::f32; use std::f64; @@ -88,8 +95,7 @@ pub fn main() { assert_eq!(3.3_f32.round(), 3.0); assert_eq!(3.3_f64.round(), 3.0); - extern { - fn ldexp(x: f64, n: i32) -> f64; - } - unsafe { assert_approx_eq!(ldexp(0.65f64, 3i32), 5.2f64); } + assert_eq!(ldexp(0.65f64, 3i32), 5.2f64); + assert_eq!(ldexp(1.42, 0xFFFF), f64::INFINITY); + assert_eq!(ldexp(1.42, -0xFFFF), 0f64); } From 04892d915512abe85d7a663b68dc62ef802eef30 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 10 Aug 2019 11:33:33 +0200 Subject: [PATCH 1038/3747] typo --- src/shims/foreign_items.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 4cca6b9efdd12..0288773044ac5 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -597,8 +597,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "_ldexp" | "ldexp" | "scalbn" => { let x = this.read_scalar(args[0])?.to_f64()?; let exp = this.read_scalar(args[1])?.to_i32()?; + // Saturating cast to i16. Even those are outside the valid exponent range to - // `scalbn` below will to its over/underflow handling. + // `scalbn` below will do its over/underflow handling. let exp = if exp > i16::max_value() as i32 { i16::max_value() } else if exp < i16::min_value() as i32 { @@ -606,6 +607,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } else { exp.try_into().unwrap() }; + let res = x.scalbn(exp); this.write_scalar(Scalar::from_f64(res), dest)?; } From 7a9733929b8e56d2def8bfeb8ce0dfef9e402949 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 12 Aug 2019 08:25:31 +0200 Subject: [PATCH 1039/3747] it's called RUSTC_CTFE_BACKTRACE now --- rust-version | 2 +- src/bin/miri.rs | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/rust-version b/rust-version index d2d7536dcae91..6a1f1c81bdfab 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -5aa3d9a7b5d3a46a7f158e8881146331a6bc9243 +00ee1b47f42129a0a6e33510578fbcf07c1e5382 diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 43cb19b2658ef..29076828d8141 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -92,11 +92,11 @@ fn init_late_loggers() { } } - // If `MIRI_BACKTRACE` is set and `RUST_CTFE_BACKTRACE` is not, set `RUST_CTFE_BACKTRACE`. - // Do this late, so we really only apply this to miri's errors. + // If `MIRI_BACKTRACE` is set and `RUSTC_CTFE_BACKTRACE` is not, set `RUSTC_CTFE_BACKTRACE`. + // Do this late, so we ideally only apply this to Miri's errors. if let Ok(var) = env::var("MIRI_BACKTRACE") { - if env::var("RUST_CTFE_BACKTRACE") == Err(env::VarError::NotPresent) { - env::set_var("RUST_CTFE_BACKTRACE", &var); + if env::var("RUSTC_CTFE_BACKTRACE") == Err(env::VarError::NotPresent) { + env::set_var("RUSTC_CTFE_BACKTRACE", &var); } } } From 95fb11d51fdd3523f96dca81835681274086e656 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 13 Aug 2019 09:29:01 +0200 Subject: [PATCH 1040/3747] make TLS state private to TLS module --- src/shims/tls.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/shims/tls.rs b/src/shims/tls.rs index d2190bd969e3d..e90ace948b7a0 100644 --- a/src/shims/tls.rs +++ b/src/shims/tls.rs @@ -18,17 +18,17 @@ pub struct TlsEntry<'tcx> { /// The data for this key. None is used to represent NULL. /// (We normalize this early to avoid having to do a NULL-ptr-test each time we access the data.) /// Will eventually become a map from thread IDs to `Scalar`s, if we ever support more than one thread. - pub(crate) data: Option>, - pub(crate) dtor: Option>, + data: Option>, + dtor: Option>, } #[derive(Debug)] pub struct TlsData<'tcx> { /// The Key to use for the next thread-local allocation. - pub(crate) next_key: TlsKey, + next_key: TlsKey, /// pthreads-style thread-local storage. - pub(crate) keys: BTreeMap>, + keys: BTreeMap>, } impl<'tcx> Default for TlsData<'tcx> { From 666cd22fa64ee318edc3b6292efa507442eb2554 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Tue, 13 Aug 2019 11:34:43 -0500 Subject: [PATCH 1041/3747] Wrap hashmap for env vars in its own type --- src/eval.rs | 11 ++++------- src/machine.rs | 6 +++--- src/shims/env.rs | 35 +++++++++++++++++++++++++++++++++-- src/shims/foreign_items.rs | 4 ++-- 4 files changed, 42 insertions(+), 14 deletions(-) diff --git a/src/eval.rs b/src/eval.rs index b171b38a6cbd5..5e6c8129fb310 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -13,17 +13,17 @@ use crate::{ Scalar, Tag, Pointer, FnVal, MemoryExtra, MiriMemoryKind, Evaluator, TlsEvalContextExt, HelpersEvalContextExt, }; -use crate::shims::env::alloc_env_value; +use crate::shims::env::EnvVars; /// Configuration needed to spawn a Miri instance. #[derive(Clone)] pub struct MiriConfig { + /// Determine if validity checking and Stacked Borrows are enabled. pub validate: bool, /// Determines if communication with the host environment is enabled. pub communicate: bool, pub args: Vec, - - /// The seed to use when non-determinism is required (e.g. getrandom()) + /// The seed to use when non-determinism or randomness are required (e.g. ptr-to-int cast, `getrandom()`). pub seed: Option, } @@ -165,10 +165,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( assert!(args.next().is_none(), "start lang item has more arguments than expected"); if config.communicate { - for (name, value) in std::env::vars() { - let value = alloc_env_value(value.as_bytes(), ecx.memory_mut(), &tcx); - ecx.machine.env_vars.insert(name.into_bytes(), value); - } + EnvVars::init(&mut ecx, &tcx); } Ok(ecx) diff --git a/src/machine.rs b/src/machine.rs index ed9a8a1c46346..cc0c85d6603da 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -3,7 +3,6 @@ use std::rc::Rc; use std::borrow::Cow; -use std::collections::HashMap; use std::cell::RefCell; use rand::rngs::StdRng; @@ -15,6 +14,7 @@ use rustc::ty::{self, layout::{Size, LayoutOf}, TyCtxt}; use rustc::mir; use crate::*; +use crate::shims::env::EnvVars; // Some global facts about the emulated machine. pub const PAGE_SIZE: u64 = 4*1024; // FIXME: adjust to target architecture @@ -79,7 +79,7 @@ impl MemoryExtra { pub struct Evaluator<'tcx> { /// Environment variables set by `setenv`. /// Miri does not expose env vars from the host to the emulated program. - pub(crate) env_vars: HashMap, Pointer>, + pub(crate) env_vars: EnvVars, /// Program arguments (`Option` because we can only initialize them after creating the ecx). /// These are *pointers* to argc/argv because macOS. @@ -101,7 +101,7 @@ pub struct Evaluator<'tcx> { impl<'tcx> Evaluator<'tcx> { pub(crate) fn new(communicate: bool) -> Self { Evaluator { - env_vars: HashMap::default(), + env_vars: EnvVars::default(), argc: None, argv: None, cmd_line: None, diff --git a/src/shims/env.rs b/src/shims/env.rs index 56d2bd4b3d3e2..09d87d27ebc21 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -1,8 +1,39 @@ -use rustc::ty::{layout::{Size, Align}, TyCtxt}; -use rustc_mir::interpret::Memory; +use std::collections::HashMap; +use rustc::ty::{layout::{Size, Align}, TyCtxt}; +use rustc_mir::interpret::{Pointer, Memory}; +use crate::stacked_borrows::Tag; use crate::*; +#[derive(Default)] +pub struct EnvVars { + map: HashMap, Pointer>, +} + +impl EnvVars { + pub(crate) fn init<'mir, 'tcx>( + ecx: &mut InterpCx<'mir, 'tcx, Evaluator<'tcx>>, + tcx: &TyCtxt<'tcx>, + ) { + for (name, value) in std::env::vars() { + let value = alloc_env_value(value.as_bytes(), ecx.memory_mut(), tcx); + ecx.machine.env_vars.map.insert(name.into_bytes(), value); + } + } + + pub(crate) fn get(&self, name: &[u8]) -> Option<&Pointer> { + self.map.get(name) + } + + pub(crate) fn unset(&mut self, name: &[u8]) -> Option> { + self.map.remove(name) + } + + pub(crate) fn set(&mut self, name: Vec, ptr: Pointer) -> Option>{ + self.map.insert(name, ptr) + } +} + pub(crate) fn alloc_env_value<'mir, 'tcx>( bytes: &[u8], memory: &mut Memory<'mir, 'tcx, Evaluator<'tcx>>, diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index b1554395b692b..6705183da47f9 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -438,7 +438,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if !this.is_null(name_ptr)? { let name = this.memory().read_c_str(name_ptr)?.to_owned(); if !name.is_empty() && !name.contains(&b'=') { - success = Some(this.machine.env_vars.remove(&name)); + success = Some(this.machine.env_vars.unset(&name)); } } } @@ -467,7 +467,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } if let Some((name, value)) = new { let value_copy = alloc_env_value(&value, this.memory_mut(), tcx); - if let Some(var) = this.machine.env_vars.insert(name.to_owned(), value_copy) { + if let Some(var) = this.machine.env_vars.set(name.to_owned(), value_copy) { this.memory_mut().deallocate(var, None, MiriMemoryKind::Env.into())?; } this.write_null(dest)?; From 67d13577aac2e47a0f40292c5c966469cbc610d7 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Tue, 13 Aug 2019 12:10:24 -0500 Subject: [PATCH 1042/3747] Move test env var to test_runner --- src/bin/miri-rustc-tests.rs | 1 - tests/compiletest.rs | 6 +++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/bin/miri-rustc-tests.rs b/src/bin/miri-rustc-tests.rs index 0cf171f52e7e6..9ef64c38638b7 100644 --- a/src/bin/miri-rustc-tests.rs +++ b/src/bin/miri-rustc-tests.rs @@ -66,7 +66,6 @@ impl rustc_driver::Callbacks for MiriCompilerCalls { } tcx.hir().krate().visit_all_item_likes(&mut Visitor(tcx)); } else if let Some((entry_def_id, _)) = tcx.entry_fn(LOCAL_CRATE) { - let config = MiriConfig { validate: true, communicate: false, diff --git a/tests/compiletest.rs b/tests/compiletest.rs index f61faa9fcc61f..702c6026ecedc 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -37,9 +37,6 @@ fn run_tests(mode: &str, path: &str, target: &str, mut flags: Vec) { flags.push(format!("--sysroot {}", sysroot)); } - // Add a test env var to do environment communication tests - std::env::set_var("MIRI_ENV_VAR_TEST", "0"); - // The rest of the configuration. let mut config = compiletest::Config::default().tempdir(); config.mode = mode.parse().expect("Invalid mode"); @@ -126,6 +123,9 @@ fn compile_fail_miri(opt: bool) { } fn test_runner(_tests: &[&()]) { + // Add a test env var to do environment communication tests + std::env::set_var("MIRI_ENV_VAR_TEST", "0"); + run_pass_miri(false); run_pass_miri(true); From afc6713e4178fc4c375e7acea8898534f2e6fba3 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Tue, 13 Aug 2019 16:17:41 -0500 Subject: [PATCH 1043/3747] Reorganize shims::env::EnvVars --- src/eval.rs | 8 +++----- src/lib.rs | 1 + src/machine.rs | 7 ++++--- src/shims/env.rs | 9 ++++++--- 4 files changed, 14 insertions(+), 11 deletions(-) diff --git a/src/eval.rs b/src/eval.rs index 5e6c8129fb310..936ae5b895327 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -12,8 +12,8 @@ use crate::{ InterpResult, InterpError, InterpCx, StackPopCleanup, struct_error, Scalar, Tag, Pointer, FnVal, MemoryExtra, MiriMemoryKind, Evaluator, TlsEvalContextExt, HelpersEvalContextExt, + ShimsEnvVars, }; -use crate::shims::env::EnvVars; /// Configuration needed to spawn a Miri instance. #[derive(Clone)] @@ -40,6 +40,8 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( MemoryExtra::new(StdRng::seed_from_u64(config.seed.unwrap_or(0)), config.validate), ); + ShimsEnvVars::init(config.communicate, &mut ecx, &tcx); + let main_instance = ty::Instance::mono(ecx.tcx.tcx, main_id); let main_mir = ecx.load_mir(main_instance.def)?; @@ -164,10 +166,6 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( assert!(args.next().is_none(), "start lang item has more arguments than expected"); - if config.communicate { - EnvVars::init(&mut ecx, &tcx); - } - Ok(ecx) } diff --git a/src/lib.rs b/src/lib.rs index 58f572bf70112..216e41d4f8386 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -33,6 +33,7 @@ pub use crate::shims::foreign_items::EvalContextExt as ForeignItemsEvalContextEx pub use crate::shims::intrinsics::EvalContextExt as IntrinsicsEvalContextExt; pub use crate::shims::tls::{EvalContextExt as TlsEvalContextExt, TlsData}; pub use crate::shims::dlsym::{Dlsym, EvalContextExt as DlsymEvalContextExt}; +pub use crate::shims::env::{EnvVars as ShimsEnvVars}; pub use crate::operator::EvalContextExt as OperatorEvalContextExt; pub use crate::range_map::RangeMap; pub use crate::helpers::{EvalContextExt as HelpersEvalContextExt}; diff --git a/src/machine.rs b/src/machine.rs index cc0c85d6603da..635b46bcdb048 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -14,7 +14,6 @@ use rustc::ty::{self, layout::{Size, LayoutOf}, TyCtxt}; use rustc::mir; use crate::*; -use crate::shims::env::EnvVars; // Some global facts about the emulated machine. pub const PAGE_SIZE: u64 = 4*1024; // FIXME: adjust to target architecture @@ -79,7 +78,7 @@ impl MemoryExtra { pub struct Evaluator<'tcx> { /// Environment variables set by `setenv`. /// Miri does not expose env vars from the host to the emulated program. - pub(crate) env_vars: EnvVars, + pub(crate) env_vars: ShimsEnvVars, /// Program arguments (`Option` because we can only initialize them after creating the ecx). /// These are *pointers* to argc/argv because macOS. @@ -101,7 +100,9 @@ pub struct Evaluator<'tcx> { impl<'tcx> Evaluator<'tcx> { pub(crate) fn new(communicate: bool) -> Self { Evaluator { - env_vars: EnvVars::default(), + // `env_vars` could be initialized properly here if `Memory` were available before + // calling this method. + env_vars: ShimsEnvVars::default(), argc: None, argv: None, cmd_line: None, diff --git a/src/shims/env.rs b/src/shims/env.rs index 09d87d27ebc21..4a15eb4cfb48a 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -12,12 +12,15 @@ pub struct EnvVars { impl EnvVars { pub(crate) fn init<'mir, 'tcx>( + communicate: bool, ecx: &mut InterpCx<'mir, 'tcx, Evaluator<'tcx>>, tcx: &TyCtxt<'tcx>, ) { - for (name, value) in std::env::vars() { - let value = alloc_env_value(value.as_bytes(), ecx.memory_mut(), tcx); - ecx.machine.env_vars.map.insert(name.into_bytes(), value); + if communicate { + for (name, value) in std::env::vars() { + let value = alloc_env_value(value.as_bytes(), ecx.memory_mut(), tcx); + ecx.machine.env_vars.map.insert(name.into_bytes(), value); + } } } From f451fe21bdae10709b98406544c61689e1691163 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Tue, 13 Aug 2019 16:17:53 -0500 Subject: [PATCH 1044/3747] Test env isolation --- tests/run-pass/env.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/run-pass/env.rs b/tests/run-pass/env.rs index 91e15f249d452..faf947420347d 100644 --- a/tests/run-pass/env.rs +++ b/tests/run-pass/env.rs @@ -6,4 +6,6 @@ fn main() { assert_eq!(env::var("MIRI_TEST"), Err(env::VarError::NotPresent)); env::set_var("MIRI_TEST", "the answer"); assert_eq!(env::var("MIRI_TEST"), Ok("the answer".to_owned())); + // Test that miri environment is isolated when communication is disabled. + assert!(env::var("MIRI_ENV_VAR_TEST").is_err()); } From 46f902b67dfeaeab45424dd7e24771676ef30b58 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Wed, 14 Aug 2019 10:24:35 -0500 Subject: [PATCH 1045/3747] Rename export for shims::env::EnvVars --- src/eval.rs | 8 ++++---- src/lib.rs | 2 +- src/machine.rs | 4 ++-- src/shims/env.rs | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/eval.rs b/src/eval.rs index 936ae5b895327..496bcf990adc1 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -12,7 +12,7 @@ use crate::{ InterpResult, InterpError, InterpCx, StackPopCleanup, struct_error, Scalar, Tag, Pointer, FnVal, MemoryExtra, MiriMemoryKind, Evaluator, TlsEvalContextExt, HelpersEvalContextExt, - ShimsEnvVars, + EnvVars, }; /// Configuration needed to spawn a Miri instance. @@ -39,9 +39,9 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( Evaluator::new(config.communicate), MemoryExtra::new(StdRng::seed_from_u64(config.seed.unwrap_or(0)), config.validate), ); - - ShimsEnvVars::init(config.communicate, &mut ecx, &tcx); - + // Complete initialization. + EnvVars::init(&mut ecx, &tcx, config.communicate); + // Setup first stack-frame let main_instance = ty::Instance::mono(ecx.tcx.tcx, main_id); let main_mir = ecx.load_mir(main_instance.def)?; diff --git a/src/lib.rs b/src/lib.rs index 216e41d4f8386..738419c2498b7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -33,7 +33,7 @@ pub use crate::shims::foreign_items::EvalContextExt as ForeignItemsEvalContextEx pub use crate::shims::intrinsics::EvalContextExt as IntrinsicsEvalContextExt; pub use crate::shims::tls::{EvalContextExt as TlsEvalContextExt, TlsData}; pub use crate::shims::dlsym::{Dlsym, EvalContextExt as DlsymEvalContextExt}; -pub use crate::shims::env::{EnvVars as ShimsEnvVars}; +pub use crate::shims::env::EnvVars; pub use crate::operator::EvalContextExt as OperatorEvalContextExt; pub use crate::range_map::RangeMap; pub use crate::helpers::{EvalContextExt as HelpersEvalContextExt}; diff --git a/src/machine.rs b/src/machine.rs index 635b46bcdb048..b4aac147f94fb 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -78,7 +78,7 @@ impl MemoryExtra { pub struct Evaluator<'tcx> { /// Environment variables set by `setenv`. /// Miri does not expose env vars from the host to the emulated program. - pub(crate) env_vars: ShimsEnvVars, + pub(crate) env_vars: EnvVars, /// Program arguments (`Option` because we can only initialize them after creating the ecx). /// These are *pointers* to argc/argv because macOS. @@ -102,7 +102,7 @@ impl<'tcx> Evaluator<'tcx> { Evaluator { // `env_vars` could be initialized properly here if `Memory` were available before // calling this method. - env_vars: ShimsEnvVars::default(), + env_vars: EnvVars::default(), argc: None, argv: None, cmd_line: None, diff --git a/src/shims/env.rs b/src/shims/env.rs index 4a15eb4cfb48a..d283cde8e3e9b 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -12,9 +12,9 @@ pub struct EnvVars { impl EnvVars { pub(crate) fn init<'mir, 'tcx>( - communicate: bool, ecx: &mut InterpCx<'mir, 'tcx, Evaluator<'tcx>>, tcx: &TyCtxt<'tcx>, + communicate: bool, ) { if communicate { for (name, value) in std::env::vars() { From 451a09a6857f7e7dabc918f09c78932b3de2e8f4 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Wed, 14 Aug 2019 11:22:47 -0500 Subject: [PATCH 1046/3747] Remove tcx parameter for EnvVars::alloc_env_value --- src/eval.rs | 4 +++- src/shims/env.rs | 13 ++++++------- src/shims/foreign_items.rs | 2 +- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/src/eval.rs b/src/eval.rs index 496bcf990adc1..0970edb2b75f3 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -39,8 +39,10 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( Evaluator::new(config.communicate), MemoryExtra::new(StdRng::seed_from_u64(config.seed.unwrap_or(0)), config.validate), ); + // Complete initialization. - EnvVars::init(&mut ecx, &tcx, config.communicate); + EnvVars::init(&mut ecx, config.communicate); + // Setup first stack-frame let main_instance = ty::Instance::mono(ecx.tcx.tcx, main_id); let main_mir = ecx.load_mir(main_instance.def)?; diff --git a/src/shims/env.rs b/src/shims/env.rs index d283cde8e3e9b..05c5fbb043098 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -1,6 +1,6 @@ use std::collections::HashMap; -use rustc::ty::{layout::{Size, Align}, TyCtxt}; +use rustc::ty::layout::{Size, Align}; use rustc_mir::interpret::{Pointer, Memory}; use crate::stacked_borrows::Tag; use crate::*; @@ -13,12 +13,11 @@ pub struct EnvVars { impl EnvVars { pub(crate) fn init<'mir, 'tcx>( ecx: &mut InterpCx<'mir, 'tcx, Evaluator<'tcx>>, - tcx: &TyCtxt<'tcx>, communicate: bool, ) { if communicate { for (name, value) in std::env::vars() { - let value = alloc_env_value(value.as_bytes(), ecx.memory_mut(), tcx); + let value = alloc_env_value(value.as_bytes(), ecx.memory_mut()); ecx.machine.env_vars.map.insert(name.into_bytes(), value); } } @@ -40,8 +39,8 @@ impl EnvVars { pub(crate) fn alloc_env_value<'mir, 'tcx>( bytes: &[u8], memory: &mut Memory<'mir, 'tcx, Evaluator<'tcx>>, - tcx: &TyCtxt<'tcx>, ) -> Pointer { + let tcx = {memory.tcx.tcx}; let length = bytes.len() as u64; // `+1` for the null terminator. let ptr = memory.allocate( @@ -51,11 +50,11 @@ pub(crate) fn alloc_env_value<'mir, 'tcx>( ); // We just allocated these, so the write cannot fail. let alloc = memory.get_mut(ptr.alloc_id).unwrap(); - alloc.write_bytes(tcx, ptr, &bytes).unwrap(); + alloc.write_bytes(&tcx, ptr, &bytes).unwrap(); let trailing_zero_ptr = ptr.offset( Size::from_bytes(length), - tcx, + &tcx, ).unwrap(); - alloc.write_bytes(tcx, trailing_zero_ptr, &[0]).unwrap(); + alloc.write_bytes(&tcx, trailing_zero_ptr, &[0]).unwrap(); ptr } diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 6705183da47f9..088077d5dfa2d 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -466,7 +466,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } if let Some((name, value)) = new { - let value_copy = alloc_env_value(&value, this.memory_mut(), tcx); + let value_copy = alloc_env_value(&value, this.memory_mut()); if let Some(var) = this.machine.env_vars.set(name.to_owned(), value_copy) { this.memory_mut().deallocate(var, None, MiriMemoryKind::Env.into())?; } From 41f8cfa30edc92c3c42a08059d0737d5ee4b87ac Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Wed, 14 Aug 2019 15:44:37 -0500 Subject: [PATCH 1047/3747] Move env shims to its own module --- src/eval.rs | 1 - src/lib.rs | 2 +- src/shims/env.rs | 92 ++++++++++++++++++++++++++++++++------ src/shims/foreign_items.rs | 60 ++----------------------- 4 files changed, 83 insertions(+), 72 deletions(-) diff --git a/src/eval.rs b/src/eval.rs index 0970edb2b75f3..ae57bcf98b96f 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -39,7 +39,6 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( Evaluator::new(config.communicate), MemoryExtra::new(StdRng::seed_from_u64(config.seed.unwrap_or(0)), config.validate), ); - // Complete initialization. EnvVars::init(&mut ecx, config.communicate); diff --git a/src/lib.rs b/src/lib.rs index 738419c2498b7..cea99d86eaa8a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -33,7 +33,7 @@ pub use crate::shims::foreign_items::EvalContextExt as ForeignItemsEvalContextEx pub use crate::shims::intrinsics::EvalContextExt as IntrinsicsEvalContextExt; pub use crate::shims::tls::{EvalContextExt as TlsEvalContextExt, TlsData}; pub use crate::shims::dlsym::{Dlsym, EvalContextExt as DlsymEvalContextExt}; -pub use crate::shims::env::EnvVars; +pub use crate::shims::env::{EnvVars, EvalContextExt as EnvEvalContextExt}; pub use crate::operator::EvalContextExt as OperatorEvalContextExt; pub use crate::range_map::RangeMap; pub use crate::helpers::{EvalContextExt as HelpersEvalContextExt}; diff --git a/src/shims/env.rs b/src/shims/env.rs index 05c5fbb043098..8362a02c7e80d 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -22,21 +22,9 @@ impl EnvVars { } } } - - pub(crate) fn get(&self, name: &[u8]) -> Option<&Pointer> { - self.map.get(name) - } - - pub(crate) fn unset(&mut self, name: &[u8]) -> Option> { - self.map.remove(name) - } - - pub(crate) fn set(&mut self, name: Vec, ptr: Pointer) -> Option>{ - self.map.insert(name, ptr) - } } -pub(crate) fn alloc_env_value<'mir, 'tcx>( +fn alloc_env_value<'mir, 'tcx>( bytes: &[u8], memory: &mut Memory<'mir, 'tcx, Evaluator<'tcx>>, ) -> Pointer { @@ -58,3 +46,81 @@ pub(crate) fn alloc_env_value<'mir, 'tcx>( alloc.write_bytes(&tcx, trailing_zero_ptr, &[0]).unwrap(); ptr } + +impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} +pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { + fn getenv( + &mut self, + name_op: OpTy<'tcx, Tag>, + dest: PlaceTy<'tcx, Tag> + ) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + + let result = { + let name_ptr = this.read_scalar(name_op)?.not_undef()?; + let name = this.memory().read_c_str(name_ptr)?; + match this.machine.env_vars.map.get(name) { + Some(&var) => Scalar::Ptr(var), + None => Scalar::ptr_null(&*this.tcx), + } + }; + this.write_scalar(result, dest)?; + Ok(()) + } + + fn setenv( + &mut self, + name_op: OpTy<'tcx, Tag>, + value_op: OpTy<'tcx, Tag>, + dest: PlaceTy<'tcx, Tag> + ) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + + let mut new = None; + let name_ptr = this.read_scalar(name_op)?.not_undef()?; + let value_ptr = this.read_scalar(value_op)?.not_undef()?; + let value = this.memory().read_c_str(value_ptr)?; + if !this.is_null(name_ptr)? { + let name = this.memory().read_c_str(name_ptr)?; + if !name.is_empty() && !name.contains(&b'=') { + new = Some((name.to_owned(), value.to_owned())); + } + } + if let Some((name, value)) = new { + let value_copy = alloc_env_value(&value, this.memory_mut()); + if let Some(var) = this.machine.env_vars.map.insert(name.to_owned(), value_copy) { + this.memory_mut().deallocate(var, None, MiriMemoryKind::Env.into())?; + } + this.write_null(dest)?; + } else { + this.write_scalar(Scalar::from_int(-1, dest.layout.size), dest)?; + } + Ok(()) + } + + fn unsetenv( + &mut self, + name_op: OpTy<'tcx, Tag>, + dest: PlaceTy<'tcx, Tag> + ) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + + let mut success = None; + let name_ptr = this.read_scalar(name_op)?.not_undef()?; + if !this.is_null(name_ptr)? { + let name = this.memory().read_c_str(name_ptr)?.to_owned(); + if !name.is_empty() && !name.contains(&b'=') { + success = Some(this.machine.env_vars.map.remove(&name)); + } + } + if let Some(old) = success { + if let Some(var) = old { + this.memory_mut().deallocate(var, None, MiriMemoryKind::Env.into())?; + } + this.write_null(dest)?; + } else { + this.write_scalar(Scalar::from_int(-1, dest.layout.size), dest)?; + } + Ok(()) + } +} diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 2d2b917eb2750..34b54f3290244 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -8,7 +8,6 @@ use syntax::attr; use syntax::symbol::sym; use crate::*; -use crate::shims::env::alloc_env_value; impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { @@ -422,62 +421,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } - "getenv" => { - let result = { - let name_ptr = this.read_scalar(args[0])?.not_undef()?; - let name = this.memory().read_c_str(name_ptr)?; - match this.machine.env_vars.get(name) { - Some(&var) => Scalar::Ptr(var), - None => Scalar::ptr_null(&*this.tcx), - } - }; - this.write_scalar(result, dest)?; - } - - "unsetenv" => { - let mut success = None; - { - let name_ptr = this.read_scalar(args[0])?.not_undef()?; - if !this.is_null(name_ptr)? { - let name = this.memory().read_c_str(name_ptr)?.to_owned(); - if !name.is_empty() && !name.contains(&b'=') { - success = Some(this.machine.env_vars.unset(&name)); - } - } - } - if let Some(old) = success { - if let Some(var) = old { - this.memory_mut().deallocate(var, None, MiriMemoryKind::Env.into())?; - } - this.write_null(dest)?; - } else { - this.write_scalar(Scalar::from_int(-1, dest.layout.size), dest)?; - } - } - - "setenv" => { - let mut new = None; - { - let name_ptr = this.read_scalar(args[0])?.not_undef()?; - let value_ptr = this.read_scalar(args[1])?.not_undef()?; - let value = this.memory().read_c_str(value_ptr)?; - if !this.is_null(name_ptr)? { - let name = this.memory().read_c_str(name_ptr)?; - if !name.is_empty() && !name.contains(&b'=') { - new = Some((name.to_owned(), value.to_owned())); - } - } - } - if let Some((name, value)) = new { - let value_copy = alloc_env_value(&value, this.memory_mut()); - if let Some(var) = this.machine.env_vars.set(name.to_owned(), value_copy) { - this.memory_mut().deallocate(var, None, MiriMemoryKind::Env.into())?; - } - this.write_null(dest)?; - } else { - this.write_scalar(Scalar::from_int(-1, dest.layout.size), dest)?; - } - } + "getenv" => this.getenv(args[0], dest)?, + "unsetenv" => this.unsetenv(args[0], dest)?, + "setenv" => this.setenv(args[0], args[1], dest)?, "write" => { let fd = this.read_scalar(args[0])?.to_i32()?; From aee8f173ec46d4b98cc562c6e7cad54bef764298 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Wed, 14 Aug 2019 16:48:36 -0500 Subject: [PATCH 1048/3747] Delegate writing to emulate_foreign_item --- src/shims/env.rs | 39 +++++++++++++++----------------------- src/shims/foreign_items.rs | 17 ++++++++++++++--- 2 files changed, 29 insertions(+), 27 deletions(-) diff --git a/src/shims/env.rs b/src/shims/env.rs index 8362a02c7e80d..c941bf4f50e3f 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -52,34 +52,28 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn getenv( &mut self, name_op: OpTy<'tcx, Tag>, - dest: PlaceTy<'tcx, Tag> - ) -> InterpResult<'tcx> { + ) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); - let result = { - let name_ptr = this.read_scalar(name_op)?.not_undef()?; - let name = this.memory().read_c_str(name_ptr)?; - match this.machine.env_vars.map.get(name) { - Some(&var) => Scalar::Ptr(var), - None => Scalar::ptr_null(&*this.tcx), - } - }; - this.write_scalar(result, dest)?; - Ok(()) + let name_ptr = this.read_scalar(name_op)?.not_undef()?; + let name = this.memory().read_c_str(name_ptr)?; + Ok(match this.machine.env_vars.map.get(name) { + Some(&var) => Scalar::Ptr(var), + None => Scalar::ptr_null(&*this.tcx), + }) } fn setenv( &mut self, name_op: OpTy<'tcx, Tag>, value_op: OpTy<'tcx, Tag>, - dest: PlaceTy<'tcx, Tag> - ) -> InterpResult<'tcx> { + ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - let mut new = None; let name_ptr = this.read_scalar(name_op)?.not_undef()?; let value_ptr = this.read_scalar(value_op)?.not_undef()?; let value = this.memory().read_c_str(value_ptr)?; + let mut new = None; if !this.is_null(name_ptr)? { let name = this.memory().read_c_str(name_ptr)?; if !name.is_empty() && !name.contains(&b'=') { @@ -91,22 +85,20 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if let Some(var) = this.machine.env_vars.map.insert(name.to_owned(), value_copy) { this.memory_mut().deallocate(var, None, MiriMemoryKind::Env.into())?; } - this.write_null(dest)?; + Ok(0) } else { - this.write_scalar(Scalar::from_int(-1, dest.layout.size), dest)?; + Ok(-1) } - Ok(()) } fn unsetenv( &mut self, name_op: OpTy<'tcx, Tag>, - dest: PlaceTy<'tcx, Tag> - ) -> InterpResult<'tcx> { + ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - let mut success = None; let name_ptr = this.read_scalar(name_op)?.not_undef()?; + let mut success = None; if !this.is_null(name_ptr)? { let name = this.memory().read_c_str(name_ptr)?.to_owned(); if !name.is_empty() && !name.contains(&b'=') { @@ -117,10 +109,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if let Some(var) = old { this.memory_mut().deallocate(var, None, MiriMemoryKind::Env.into())?; } - this.write_null(dest)?; + Ok(0) } else { - this.write_scalar(Scalar::from_int(-1, dest.layout.size), dest)?; + Ok(-1) } - Ok(()) } } diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 34b54f3290244..59e7673dcab5f 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -421,9 +421,20 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } - "getenv" => this.getenv(args[0], dest)?, - "unsetenv" => this.unsetenv(args[0], dest)?, - "setenv" => this.setenv(args[0], args[1], dest)?, + "getenv" => { + let result = this.getenv(args[0])?; + this.write_scalar(result, dest)?; + } + + "unsetenv" => { + let result = this.unsetenv(args[0])?; + this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + } + + "setenv" => { + let result = this.setenv(args[0], args[1])?; + this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + } "write" => { let fd = this.read_scalar(args[0])?.to_i32()?; From 60a0688185b1412147a5b5f235597bc7618b104a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 27 Jul 2019 11:03:12 +0200 Subject: [PATCH 1049/3747] adjust tests for eager pointer checks on deref --- tests/compile-fail/deref-invalid-ptr.rs | 7 +++++++ tests/compile-fail/deref-partially-dangling.rs | 8 ++++++++ tests/compile-fail/intptrcast_alignment_check.rs | 12 +++--------- tests/compile-fail/storage_dead_dangling.rs | 4 ++-- tests/run-pass/ref-invalid-ptr.rs | 12 ------------ tests/run-pass/stacked-borrows/stacked-borrows.rs | 11 ----------- 6 files changed, 20 insertions(+), 34 deletions(-) create mode 100644 tests/compile-fail/deref-invalid-ptr.rs create mode 100644 tests/compile-fail/deref-partially-dangling.rs delete mode 100644 tests/run-pass/ref-invalid-ptr.rs diff --git a/tests/compile-fail/deref-invalid-ptr.rs b/tests/compile-fail/deref-invalid-ptr.rs new file mode 100644 index 0000000000000..2a8be87e1251e --- /dev/null +++ b/tests/compile-fail/deref-invalid-ptr.rs @@ -0,0 +1,7 @@ +// This should fail even without validation. +// compile-flags: -Zmiri-disable-validation + +fn main() { + let x = 2usize as *const u32; + let _y = unsafe { &*x as *const u32 }; //~ ERROR dangling pointer was dereferenced +} diff --git a/tests/compile-fail/deref-partially-dangling.rs b/tests/compile-fail/deref-partially-dangling.rs new file mode 100644 index 0000000000000..221e585c5ff38 --- /dev/null +++ b/tests/compile-fail/deref-partially-dangling.rs @@ -0,0 +1,8 @@ +// Deref a raw ptr to access a field of a large struct, where the field +// is allocated but not the entire struct is. +fn main() { + let x = (1, 13); + let xptr = &x as *const _ as *const (i32, i32, i32); + let val = unsafe { (*xptr).1 }; //~ ERROR pointer must be in-bounds at offset 12, but is outside bounds of allocation + assert_eq!(val, 13); +} diff --git a/tests/compile-fail/intptrcast_alignment_check.rs b/tests/compile-fail/intptrcast_alignment_check.rs index 4e12a8a9e25e1..fcf613ace4627 100644 --- a/tests/compile-fail/intptrcast_alignment_check.rs +++ b/tests/compile-fail/intptrcast_alignment_check.rs @@ -1,6 +1,3 @@ -// Validation makes this fail in the wrong place -// compile-flags: -Zmiri-disable-validation - // Even with intptrcast and without validation, we want to be *sure* to catch bugs // that arise from pointers being insufficiently aligned. The only way to achieve // that is not not let programs exploit integer information for alignment, so here @@ -8,11 +5,8 @@ fn main() { let x = &mut [0u8; 3]; let base_addr = x as *mut _ as usize; - let u16_ref = unsafe { if base_addr % 2 == 0 { - &mut *(base_addr as *mut u16) - } else { - &mut *((base_addr+1) as *mut u16) - } }; - *u16_ref = 2; //~ ERROR tried to access memory with alignment 1, but alignment 2 is required + let base_addr_aligned = if base_addr % 2 == 0 { base_addr } else { base_addr+1 }; + let u16_ptr = base_addr_aligned as *mut u16; + unsafe { *u16_ptr = 2; } //~ ERROR tried to access memory with alignment 1, but alignment 2 is required println!("{:?}", x); } diff --git a/tests/compile-fail/storage_dead_dangling.rs b/tests/compile-fail/storage_dead_dangling.rs index 85c76f6f41f6e..5a5d79f1582e8 100644 --- a/tests/compile-fail/storage_dead_dangling.rs +++ b/tests/compile-fail/storage_dead_dangling.rs @@ -8,8 +8,8 @@ fn fill(v: &mut i32) { } fn evil() { - let v = unsafe { &mut *(LEAK as *mut i32) }; - let _x = *v; //~ ERROR dangling pointer was dereferenced + let v = unsafe { &mut *(LEAK as *mut i32) }; //~ ERROR dangling pointer was dereferenced + let _x = *v; } fn main() { diff --git a/tests/run-pass/ref-invalid-ptr.rs b/tests/run-pass/ref-invalid-ptr.rs deleted file mode 100644 index e0e7d2afefc52..0000000000000 --- a/tests/run-pass/ref-invalid-ptr.rs +++ /dev/null @@ -1,12 +0,0 @@ -// FIXME: validation disabled because it checks these references too eagerly. -// compile-flags: -Zmiri-disable-validation - -fn main() { - let x = 2usize as *const u32; - // This is not aligned, but we immediately cast it to a raw ptr so that must be ok. - let _y = unsafe { &*x as *const u32 }; - - let x = 0usize as *const u32; - // This is NULL, but we immediately cast it to a raw ptr so that must be ok. - let _y = unsafe { &*x as *const u32 }; -} diff --git a/tests/run-pass/stacked-borrows/stacked-borrows.rs b/tests/run-pass/stacked-borrows/stacked-borrows.rs index 7d84e33b3d6b3..afa364e856438 100644 --- a/tests/run-pass/stacked-borrows/stacked-borrows.rs +++ b/tests/run-pass/stacked-borrows/stacked-borrows.rs @@ -1,6 +1,5 @@ // Test various stacked-borrows-related things. fn main() { - deref_partially_dangling_raw(); read_does_not_invalidate1(); read_does_not_invalidate2(); ref_raw_int_raw(); @@ -14,16 +13,6 @@ fn main() { shr_and_raw(); } -// Deref a raw ptr to access a field of a large struct, where the field -// is allocated but not the entire struct is. -// For now, we want to allow this. -fn deref_partially_dangling_raw() { - let x = (1, 13); - let xptr = &x as *const _ as *const (i32, i32, i32); - let val = unsafe { (*xptr).1 }; - assert_eq!(val, 13); -} - // Make sure that reading from an `&mut` does, like reborrowing to `&`, // NOT invalidate other reborrows. fn read_does_not_invalidate1() { From a801b0ba3f8f16aa9ded9d28af4279b4b0b4509b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 28 Jul 2019 14:55:55 +0200 Subject: [PATCH 1050/3747] adjust for fn rename --- src/operator.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/operator.rs b/src/operator.rs index f047f4f4fad01..acf1db2977b79 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -35,7 +35,7 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { #[inline] fn pointer_inbounds(&self, ptr: Pointer) -> InterpResult<'tcx> { let (size, _align) = self.memory().get_size_and_align(ptr.alloc_id, AllocCheck::Live)?; - ptr.check_in_alloc(size, CheckInAllocMsg::InboundsTest) + ptr.check_inbounds_alloc(size, CheckInAllocMsg::InboundsTest) } fn binary_ptr_op( From 2f95d4d50cbf28de90d01a01e36197872f3a55f6 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 28 Jul 2019 18:08:39 +0200 Subject: [PATCH 1051/3747] remove dead code --- tests/compile-fail/storage_dead_dangling.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/compile-fail/storage_dead_dangling.rs b/tests/compile-fail/storage_dead_dangling.rs index 5a5d79f1582e8..3047f086bdf3d 100644 --- a/tests/compile-fail/storage_dead_dangling.rs +++ b/tests/compile-fail/storage_dead_dangling.rs @@ -8,8 +8,7 @@ fn fill(v: &mut i32) { } fn evil() { - let v = unsafe { &mut *(LEAK as *mut i32) }; //~ ERROR dangling pointer was dereferenced - let _x = *v; + unsafe { &mut *(LEAK as *mut i32) }; //~ ERROR dangling pointer was dereferenced } fn main() { From 8a103cfdd99b258560c1c3c88c1e49108fb87c7d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 15 Aug 2019 11:06:27 +0200 Subject: [PATCH 1052/3747] bump Rust --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 6a1f1c81bdfab..f7f2a4e20f258 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -00ee1b47f42129a0a6e33510578fbcf07c1e5382 +1cdcea920e56a5d0587307a4c9cf8fff5c77c4bc From 6ef7c0886c0e8113b038306878dbbb43a3b49535 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 15 Aug 2019 11:14:45 +0200 Subject: [PATCH 1053/3747] deny warnings on CI --- miri | 2 +- travis.sh | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/miri b/miri index 1f46f04c13e8c..6de2391137ac6 100755 --- a/miri +++ b/miri @@ -45,7 +45,7 @@ fi # We set the rpath so that Miri finds the private rustc libraries it needs. # We enable debug-assertions to get tracing. # We enable line-only debuginfo for backtraces. -export RUSTFLAGS="-C link-args=-Wl,-rpath,$LIBDIR -C debug-assertions -C debuginfo=1" +export RUSTFLAGS="-C link-args=-Wl,-rpath,$LIBDIR -C debug-assertions -C debuginfo=1 $RUSTC_EXTRA_FLAGS" ## Helper functions diff --git a/travis.sh b/travis.sh index c06dbaee3638a..6f14be44ef0ac 100755 --- a/travis.sh +++ b/travis.sh @@ -8,6 +8,7 @@ else FOREIGN_TARGET=i686-unknown-linux-gnu fi export CARGO_EXTRA_FLAGS="--all-features" +export RUSTC_EXTRA_FLAGS="-D warnings" # Prepare echo "Build and install miri" From f9241be73493f9f1e26631a5389b599557ef4f2f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 15 Aug 2019 11:24:04 +0200 Subject: [PATCH 1054/3747] fix warning --- src/eval.rs | 2 +- src/shims/env.rs | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/eval.rs b/src/eval.rs index ae57bcf98b96f..39da414de14a3 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -40,7 +40,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( MemoryExtra::new(StdRng::seed_from_u64(config.seed.unwrap_or(0)), config.validate), ); // Complete initialization. - EnvVars::init(&mut ecx, config.communicate); + EnvVars::init(&mut ecx); // Setup first stack-frame let main_instance = ty::Instance::mono(ecx.tcx.tcx, main_id); diff --git a/src/shims/env.rs b/src/shims/env.rs index c941bf4f50e3f..eb5722a5a3d82 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -13,9 +13,8 @@ pub struct EnvVars { impl EnvVars { pub(crate) fn init<'mir, 'tcx>( ecx: &mut InterpCx<'mir, 'tcx, Evaluator<'tcx>>, - communicate: bool, ) { - if communicate { + if ecx.machine.communicate { for (name, value) in std::env::vars() { let value = alloc_env_value(value.as_bytes(), ecx.memory_mut()); ecx.machine.env_vars.map.insert(name.into_bytes(), value); From 5aa60571fcbb6d44ca32c3d4b5ca3cd2f69787ac Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 26 Jul 2019 10:21:31 +0200 Subject: [PATCH 1055/3747] travis: do not install cargo from master --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 7db62bc74bd43..26645c3079517 100644 --- a/.travis.yml +++ b/.travis.yml @@ -35,7 +35,7 @@ before_script: - export PATH=$HOME/.cargo/bin:$PATH # Install "master" toolchain - cargo install rustup-toolchain-install-master || echo "rustup-toolchain-install-master already installed" -- travis_retry rustup-toolchain-install-master -f -n master $RUSTC_HASH -c cargo -c rust-src +- travis_retry rustup-toolchain-install-master -f -n master $RUSTC_HASH -c rust-src - rustup default master - rustc --version From 65541d9021904feb21a11f0a5b3fb3f7c9320a82 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 15 Aug 2019 22:30:38 +0200 Subject: [PATCH 1056/3747] rustup update --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 26645c3079517..269dc28ca021b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -33,6 +33,7 @@ before_script: # Install Rust ("stable" toolchain for better caching, it is just used to build rustup-toolchain-install-master) - curl https://build.travis-ci.org/files/rustup-init.sh -sSf | sh -s -- -y --default-toolchain stable - export PATH=$HOME/.cargo/bin:$PATH +- rustup update # Install "master" toolchain - cargo install rustup-toolchain-install-master || echo "rustup-toolchain-install-master already installed" - travis_retry rustup-toolchain-install-master -f -n master $RUSTC_HASH -c rust-src From 4f1c9bb607637cd8d6926e1b7875fb048e8a9139 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 10 Aug 2019 21:19:25 +0200 Subject: [PATCH 1057/3747] adjust for typed binary/unary_op --- src/machine.rs | 4 ++-- src/operator.rs | 10 +++++----- src/shims/intrinsics.rs | 14 +++++++------- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/machine.rs b/src/machine.rs index b4aac147f94fb..9d50c77c7c4c4 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -10,7 +10,7 @@ use rand::rngs::StdRng; use syntax::attr; use syntax::symbol::sym; use rustc::hir::def_id::DefId; -use rustc::ty::{self, layout::{Size, LayoutOf}, TyCtxt}; +use rustc::ty::{self, Ty, TyCtxt, layout::{Size, LayoutOf}}; use rustc::mir; use crate::*; @@ -191,7 +191,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { bin_op: mir::BinOp, left: ImmTy<'tcx, Tag>, right: ImmTy<'tcx, Tag>, - ) -> InterpResult<'tcx, (Scalar, bool)> { + ) -> InterpResult<'tcx, (Scalar, bool, Ty<'tcx>)> { ecx.binary_ptr_op(bin_op, left, right) } diff --git a/src/operator.rs b/src/operator.rs index acf1db2977b79..45bf1e453744c 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -14,7 +14,7 @@ pub trait EvalContextExt<'tcx> { bin_op: mir::BinOp, left: ImmTy<'tcx, Tag>, right: ImmTy<'tcx, Tag>, - ) -> InterpResult<'tcx, (Scalar, bool)>; + ) -> InterpResult<'tcx, (Scalar, bool, Ty<'tcx>)>; fn ptr_eq( &self, @@ -43,7 +43,7 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { bin_op: mir::BinOp, left: ImmTy<'tcx, Tag>, right: ImmTy<'tcx, Tag>, - ) -> InterpResult<'tcx, (Scalar, bool)> { + ) -> InterpResult<'tcx, (Scalar, bool, Ty<'tcx>)> { use rustc::mir::BinOp::*; trace!("ptr_op: {:?} {:?} {:?}", *left, bin_op, *right); @@ -59,7 +59,7 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { self.ptr_eq(left2.not_undef()?, right2.not_undef()?)?, _ => bug!("Type system should not allow comparing Scalar with ScalarPair"), }; - (Scalar::from_bool(if bin_op == Eq { eq } else { !eq }), false) + (Scalar::from_bool(if bin_op == Eq { eq } else { !eq }), false, self.tcx.types.bool) } Lt | Le | Gt | Ge => { @@ -74,7 +74,7 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { Ge => left >= right, _ => bug!("We already established it has to be one of these operators."), }; - (Scalar::from_bool(res), false) + (Scalar::from_bool(res), false, self.tcx.types.bool) } Offset => { @@ -87,7 +87,7 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { pointee_ty, right.to_scalar()?.to_isize(self)?, )?; - (ptr, false) + (ptr, false, left.layout.ty) } _ => bug!("Invalid operator on pointers: {:?}", bin_op) diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 4e957f792b751..8656962761713 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -5,7 +5,7 @@ use rustc::ty::layout::{self, LayoutOf, Size, Align}; use rustc::ty; use crate::{ - PlaceTy, OpTy, ImmTy, Immediate, Scalar, Tag, + PlaceTy, OpTy, Immediate, Scalar, Tag, OperatorEvalContextExt }; @@ -120,7 +120,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.memory().check_ptr_access(place.ptr, place.layout.size, align)?; // binary_op will bail if either of them is not a scalar - let (eq, _) = this.binary_op(mir::BinOp::Eq, old, expect_old)?; + let eq = this.overflowing_binary_op(mir::BinOp::Eq, old, expect_old)?.0; let res = Immediate::ScalarPair(old.to_scalar_or_undef(), eq.into()); this.write_immediate(res, dest)?; // old value is returned // update ptr depending on comparison @@ -183,13 +183,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx _ => bug!(), }; // Atomics wrap around on overflow. - let (val, _overflowed) = this.binary_op(op, old, rhs)?; + let val = this.binary_op(op, old, rhs)?; let val = if neg { - this.unary_op(mir::UnOp::Not, ImmTy::from_scalar(val, old.layout))? + this.unary_op(mir::UnOp::Not, val)? } else { val }; - this.write_scalar(val, place.into())?; + this.write_immediate(*val, place.into())?; } "breakpoint" => unimplemented!(), // halt miri @@ -312,7 +312,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let a = this.read_immediate(args[0])?; let b = this.read_immediate(args[1])?; // check x % y != 0 - if this.binary_op(mir::BinOp::Rem, a, b)?.0.to_bits(dest.layout.size)? != 0 { + if this.overflowing_binary_op(mir::BinOp::Rem, a, b)?.0.to_bits(dest.layout.size)? != 0 { // Check if `b` is -1, which is the "min_value / -1" case. let minus1 = Scalar::from_int(-1, dest.layout.size); return Err(if b.to_scalar().unwrap() == minus1 { @@ -515,7 +515,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "unchecked_mul" => mir::BinOp::Mul, _ => bug!(), }; - let (res, overflowed) = this.binary_op(op, l, r)?; + let (res, overflowed, _ty) = this.overflowing_binary_op(op, l, r)?; if overflowed { throw_ub_format!("Overflowing arithmetic in {}", intrinsic_name.get()); } From d7ff7ccbad89c4fe9eb84b3b22f4b994f7f169a0 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 18 Aug 2019 07:43:18 +0200 Subject: [PATCH 1058/3747] update Rust --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index f7f2a4e20f258..f90b8945180fe 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -1cdcea920e56a5d0587307a4c9cf8fff5c77c4bc +2111aed0a38c819acb140c7153e9366964a37f2f From 94cd0ce734db8f760b5a8de877684f917d0a9d90 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 18 Aug 2019 11:16:02 +0200 Subject: [PATCH 1059/3747] fix test failure due to my own lint --- rust-version | 2 +- tests/compile-fail/never_transmute_void.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/rust-version b/rust-version index f90b8945180fe..07d9d29554780 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -2111aed0a38c819acb140c7153e9366964a37f2f +ef1ecbefb8719e408150738664d443a73f757ffd diff --git a/tests/compile-fail/never_transmute_void.rs b/tests/compile-fail/never_transmute_void.rs index 5993cfad86993..a5d6795d71e79 100644 --- a/tests/compile-fail/never_transmute_void.rs +++ b/tests/compile-fail/never_transmute_void.rs @@ -2,7 +2,7 @@ // compile-flags: -Zmiri-disable-validation #![feature(never_type)] -#![allow(unused)] +#![allow(unused, invalid_value)] enum Void {} From be4108e27cf4ff452d3b667097c9e7c893063892 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 18 Aug 2019 11:31:18 +0200 Subject: [PATCH 1060/3747] test some new uninit APIs --- tests/run-pass/rc.rs | 31 +++++++++++++++++++++++++++++++ tests/run-pass/slices.rs | 18 ++++++++++++++++++ 2 files changed, 49 insertions(+) diff --git a/tests/run-pass/rc.rs b/tests/run-pass/rc.rs index d731fe8fd4c30..9ab460c961651 100644 --- a/tests/run-pass/rc.rs +++ b/tests/run-pass/rc.rs @@ -1,4 +1,6 @@ #![feature(weak_into_raw)] +#![feature(new_uninit)] +#![feature(get_mut_unchecked)] use std::cell::{Cell, RefCell}; use std::rc::{Rc, Weak}; @@ -102,6 +104,33 @@ fn weak_from_raw() { assert!(Weak::upgrade(&unsafe { Weak::from_raw(raw_2) }).is_none()); } +fn rc_uninit() { + let mut five = Rc::>::new_uninit(); + let five = unsafe { + // Deferred initialization: + Rc::get_mut_unchecked(&mut five).as_mut_ptr().write(Box::new(5)); + five.assume_init() + }; + assert_eq!(**five, 5) +} + +fn rc_uninit_slice() { + let mut values = Rc::<[Box]>::new_uninit_slice(3); + + let values = unsafe { + // Deferred initialization: + Rc::get_mut_unchecked(&mut values)[0].as_mut_ptr().write(Box::new(0)); + Rc::get_mut_unchecked(&mut values)[1].as_mut_ptr().write(Box::new(1)); + Rc::get_mut_unchecked(&mut values)[2].as_mut_ptr().write(Box::new(2)); + + values.assume_init() + }; + + for (idx, i) in values.iter().enumerate() { + assert_eq!(idx, **i); + } +} + fn main() { rc_fat_ptr_eq(); rc_refcell(); @@ -111,6 +140,8 @@ fn main() { rc_from(); weak_into_raw(); weak_from_raw(); + rc_uninit(); + rc_uninit_slice(); arc(); } diff --git a/tests/run-pass/slices.rs b/tests/run-pass/slices.rs index 4506a72e8dd02..41e7b2d36c7cf 100644 --- a/tests/run-pass/slices.rs +++ b/tests/run-pass/slices.rs @@ -1,3 +1,5 @@ +#![feature(new_uninit)] + use std::slice; fn slice_of_zst() { @@ -169,7 +171,23 @@ fn test_iter_ref_consistency() { test_mut([0u32; 0]); // ZST with alignment > 0 } +fn uninit_slice() { + let mut values = Box::<[Box]>::new_uninit_slice(3); + + let values = unsafe { + // Deferred initialization: + values[0].as_mut_ptr().write(Box::new(1)); + values[1].as_mut_ptr().write(Box::new(2)); + values[2].as_mut_ptr().write(Box::new(3)); + + values.assume_init() + }; + + assert_eq!(values.iter().map(|x| **x).collect::>(), vec![1, 2, 3]) +} + fn main() { slice_of_zst(); test_iter_ref_consistency(); + uninit_slice(); } From b44fd97af6999e032f71e9e7c265b43163cb4052 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Mon, 19 Aug 2019 10:43:09 -0500 Subject: [PATCH 1061/3747] Use host's rng when communication is enabled --- Cargo.toml | 1 + src/helpers.rs | 13 +++++++++++-- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 644a3476a6dd7..1ab0580cc6315 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -35,6 +35,7 @@ byteorder = { version = "1.1", features = ["i128"]} cargo_metadata = { version = "0.8", optional = true } directories = { version = "2.0", optional = true } rustc_version = { version = "0.2.3", optional = true } +getrandom = "0.1.10" env_logger = "0.6" log = "0.4" shell-escape = "0.1.4" diff --git a/src/helpers.rs b/src/helpers.rs index c0e1ec2cd75bc..d134a19f4c23d 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -97,9 +97,18 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Align::from_bytes(1).unwrap() )?.expect("we already checked for size 0"); - let rng = this.memory_mut().extra.rng.get_mut(); let mut data = vec![0; len]; - rng.fill_bytes(&mut data); + + if this.machine.communicate { + // Fill the buffer using the host's rng. + getrandom::getrandom(&mut data).map_err(|err| { + InterpError::Unsupported(UnsupportedOpInfo::Unsupported(err.to_string())) + })?; + } + else { + let rng = this.memory_mut().extra.rng.get_mut(); + rng.fill_bytes(&mut data); + } let tcx = &{this.tcx.tcx}; this.memory_mut().get_mut(ptr.alloc_id)?.write_bytes(tcx, ptr, &data) From a76bc3fb87b4bf470330ab2f41d0ffc6f75676e5 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 13 Jul 2019 10:27:50 +0200 Subject: [PATCH 1062/3747] test arrray try_from (interesting const generic usage) --- tests/run-pass/arrays.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/tests/run-pass/arrays.rs b/tests/run-pass/arrays.rs index d374ccf25354a..b760d515395cf 100644 --- a/tests/run-pass/arrays.rs +++ b/tests/run-pass/arrays.rs @@ -1,3 +1,5 @@ +use std::convert::TryFrom; + fn empty_array() -> [u16; 0] { [] } @@ -33,6 +35,16 @@ fn slice_index() -> u8 { arr[5] } +fn try_from() { + const N: usize = 16; + type Array = [u8; N]; + let array: Array = [0; N]; + let slice: &[u8] = &array[..]; + + let result = <&Array>::try_from(slice); + assert_eq!(&array, result.unwrap()); +} + fn eq() { const N: usize = 16; type Array = [u8; N]; @@ -57,6 +69,7 @@ fn main() { assert_eq!(array_array(), [[5, 4], [3, 2], [1, 0]]); assert_eq!(array_repeat(), [42; 8]); assert_eq!(mini_array(), [42]); + try_from(); eq(); debug(); } From 3b14567e36d4353bfa715d11387eb2e1cd1f2ae9 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 20 Aug 2019 16:11:11 +0200 Subject: [PATCH 1063/3747] bump Rust --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 07d9d29554780..853bf9bd52ee4 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -ef1ecbefb8719e408150738664d443a73f757ffd +14890954ce17c44d944eda988c5a64bb4c5ec9eb From 98129631b5a71c9a43724903499b11170b518e7a Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Tue, 20 Aug 2019 10:47:38 -0500 Subject: [PATCH 1064/3747] Use err_unsup_format instead --- src/helpers.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index d134a19f4c23d..330d6bc996b78 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -101,9 +101,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if this.machine.communicate { // Fill the buffer using the host's rng. - getrandom::getrandom(&mut data).map_err(|err| { - InterpError::Unsupported(UnsupportedOpInfo::Unsupported(err.to_string())) - })?; + getrandom::getrandom(&mut data) + .map_err(|err| err_unsup_format!("getrandom failed: {}", err))?; } else { let rng = this.memory_mut().extra.rng.get_mut(); From f53b5b0fb4cc9a716eb27929c3829f096e90b6eb Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Tue, 20 Aug 2019 10:47:57 -0500 Subject: [PATCH 1065/3747] Update -Zmiri-enable-communication docs --- README.md | 4 ++-- src/machine.rs | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index f34569d865a82..502c562d13572 100644 --- a/README.md +++ b/README.md @@ -158,8 +158,8 @@ Several `-Z` flags are relevant for Miri: will miss bugs in your program. However, this can also help to make Miri run faster. * `-Zmiri-enable-communication` enables communication between the host - environment and Miri, i.e., all the host environment variables are available - during Miri runtime. + environment and Miri, i.e., Miri uses the host's random number generator and + all the host environment variables are available during runtime. * `-Zmir-opt-level` controls how many MIR optimizations are performed. Miri overrides the default to be `0`; be advised that using any higher level can make Miri miss bugs in your program because they got optimized away. diff --git a/src/machine.rs b/src/machine.rs index b4aac147f94fb..b11ecfa441359 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -93,7 +93,8 @@ pub struct Evaluator<'tcx> { /// TLS state. pub(crate) tls: TlsData<'tcx>, - /// If enabled, the `env_vars` field is populated with the host env vars during initialization. + /// If enabled, the `env_vars` field is populated with the host env vars during initialization + /// and random number generation is delegated to the host. pub(crate) communicate: bool, } From 1be4e2ff589e14148dc71a0f4d71ff2923876415 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 21 Aug 2019 09:07:27 +0200 Subject: [PATCH 1066/3747] bump Rust --- rust-version | 2 +- tests/compiletest.rs | 10 ++++++---- tests/run-pass/async-fn.rs | 2 +- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/rust-version b/rust-version index 853bf9bd52ee4..012763c000237 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -14890954ce17c44d944eda988c5a64bb4c5ec9eb +bea0372a1a7a31b81f28cc4d9a83a2dc9a79d008 diff --git a/tests/compiletest.rs b/tests/compiletest.rs index d0705b26b7a9d..00fd039ad7e86 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -28,10 +28,12 @@ fn run_tests(mode: &str, path: &str, target: &str, mut flags: Vec) { let in_rustc_test_suite = rustc_test_suite().is_some(); // Add some flags we always want. flags.push("--edition 2018".to_owned()); - if !in_rustc_test_suite { - // Only `-Dwarnings` on the Miri side to make the rustc toolstate management less painful. - // (We often get warnings when e.g. a feature gets stabilized or some lint gets added/improved.) - flags.push("-Dwarnings -Dunused".to_owned()); // overwrite the -Aunused in compiletest-rs + if in_rustc_test_suite { + // Less aggressive warnings to make the rustc toolstate management less painful. + // (We often get warnings when e.g. a feature gets stabilized or some lint gets added/improved.) + flags.push("-Astable-features".to_owned()); + } else { + flags.push("-Dwarnings -Dunused".to_owned()); // overwrite the -Aunused in compiletest-rs } if let Ok(sysroot) = std::env::var("MIRI_SYSROOT") { flags.push(format!("--sysroot {}", sysroot)); diff --git a/tests/run-pass/async-fn.rs b/tests/run-pass/async-fn.rs index 91266f67aa8e4..dd31d901062f9 100644 --- a/tests/run-pass/async-fn.rs +++ b/tests/run-pass/async-fn.rs @@ -1,4 +1,4 @@ -#![feature(async_await, never_type)] +#![feature(never_type)] use std::{future::Future, pin::Pin, task::Poll, ptr}; use std::task::{Waker, RawWaker, RawWakerVTable, Context}; From 97f9fb1284c526f62286d3334b42481a2efe43a7 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 23 Aug 2019 23:29:11 +0200 Subject: [PATCH 1067/3747] change flag name: enable-communication -> disable-isolation --- README.md | 6 +++--- src/bin/miri.rs | 2 +- tests/run-pass/communication.rs | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 502c562d13572..d3e4adfa1785e 100644 --- a/README.md +++ b/README.md @@ -157,9 +157,9 @@ Several `-Z` flags are relevant for Miri: is enforced by default. This is mostly useful for debugging; it means Miri will miss bugs in your program. However, this can also help to make Miri run faster. -* `-Zmiri-enable-communication` enables communication between the host - environment and Miri, i.e., Miri uses the host's random number generator and - all the host environment variables are available during runtime. +* `-Zmiri-disable-isolation` disables host host isolation. As a consequence, + the program has access to host resources such as environment variables and + randomness (and, eventually, file systems and more). * `-Zmir-opt-level` controls how many MIR optimizations are performed. Miri overrides the default to be `0`; be advised that using any higher level can make Miri miss bugs in your program because they got optimized away. diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 1aa89fc5a6108..55522a52e0128 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -148,7 +148,7 @@ fn main() { "-Zmiri-disable-validation" => { validate = false; }, - "-Zmiri-enable-communication" => { + "-Zmiri-disable-isolation" => { communicate = true; }, "--" => { diff --git a/tests/run-pass/communication.rs b/tests/run-pass/communication.rs index e3fb0c5bd5e09..537e0923d20b8 100644 --- a/tests/run-pass/communication.rs +++ b/tests/run-pass/communication.rs @@ -1,5 +1,5 @@ // ignore-windows: TODO env var emulation stubbed out on Windows -// compile-flags: -Zmiri-enable-communication +// compile-flags: -Zmiri-disable-isolation fn main() { assert_eq!(std::env::var("MIRI_ENV_VAR_TEST"), Ok("0".to_owned())); From 55efee91406f17beab46273210318b7259632345 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 23 Aug 2019 23:30:23 +0200 Subject: [PATCH 1068/3747] test host randomness access --- ...mmunication.rs => env-without-isolation.rs} | 0 .../linux-getrandom-without-isolation.rs | 18 ++++++++++++++++++ 2 files changed, 18 insertions(+) rename tests/run-pass/{communication.rs => env-without-isolation.rs} (100%) create mode 100644 tests/run-pass/linux-getrandom-without-isolation.rs diff --git a/tests/run-pass/communication.rs b/tests/run-pass/env-without-isolation.rs similarity index 100% rename from tests/run-pass/communication.rs rename to tests/run-pass/env-without-isolation.rs diff --git a/tests/run-pass/linux-getrandom-without-isolation.rs b/tests/run-pass/linux-getrandom-without-isolation.rs new file mode 100644 index 0000000000000..ce9ff8b6c3f95 --- /dev/null +++ b/tests/run-pass/linux-getrandom-without-isolation.rs @@ -0,0 +1,18 @@ +// Unfortunately, compiletest_rs does not support 'only-linux', +// so we need to ignore Windows and macOS instead. +// ignore-macos: Uses Linux-only APIs +// ignore-windows: Uses Linux-only APIs +// compile-flags: -Zmiri-disable-isolation +#![feature(rustc_private)] +extern crate libc; + +fn main() { + let mut buf = [0u8; 5]; + unsafe { + assert_eq!(libc::syscall(libc::SYS_getrandom, 0 as *mut libc::c_void, 0 as libc::size_t, 0 as libc::c_uint), 0); + assert_eq!(libc::syscall(libc::SYS_getrandom, buf.as_mut_ptr() as *mut libc::c_void, 5 as libc::size_t, 0 as libc::c_uint), 5); + + assert_eq!(libc::getrandom(0 as *mut libc::c_void, 0 as libc::size_t, 0 as libc::c_uint), 0); + assert_eq!(libc::getrandom(buf.as_mut_ptr() as *mut libc::c_void, 5 as libc::size_t, 0 as libc::c_uint), 5); + } +} From 03408061270b5985d245b334fee6e5cac8c7121a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 26 Aug 2019 19:38:47 +0200 Subject: [PATCH 1069/3747] cargo update --- test-cargo-miri/Cargo.lock | 37 ++++++++++++++++++++++--------------- 1 file changed, 22 insertions(+), 15 deletions(-) diff --git a/test-cargo-miri/Cargo.lock b/test-cargo-miri/Cargo.lock index 3b4dbdcf1d2e0..2a6a32a18f045 100644 --- a/test-cargo-miri/Cargo.lock +++ b/test-cargo-miri/Cargo.lock @@ -2,7 +2,7 @@ # It is not intended for manual editing. [[package]] name = "autocfg" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -15,7 +15,7 @@ name = "c2-chacha" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "ppv-lite86 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -35,21 +35,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "getrandom" -version = "0.1.8" +version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "wasi 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "lazy_static" -version = "1.3.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "libc" -version = "0.2.60" +version = "0.2.62" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -57,7 +58,7 @@ name = "num_cpus" version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -70,8 +71,8 @@ name = "rand" version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "getrandom 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", + "getrandom 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", "rand_chacha 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -92,7 +93,7 @@ name = "rand_core" version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "getrandom 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "getrandom 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -108,18 +109,23 @@ name = "rand_pcg" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "autocfg 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "wasi" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [metadata] -"checksum autocfg 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "22130e92352b948e7e82a49cdb0aa94f2211761117f29e052dd397c1ac33542b" +"checksum autocfg 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "b671c8fb71b457dd4ae18c4ba1e59aa81793daacc361d82fcd410cef0d491875" "checksum byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a7c3dd8985a7111efc5c80b44e23ecdd8c007de8ade3b96595387e812b957cf5" "checksum c2-chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7d64d04786e0f528460fc884753cf8dddcc466be308f6026f8e355c41a0e4101" "checksum cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "b486ce3ccf7ffd79fdeb678eac06a9e6c09fc88d33836340becb8fffe87c5e33" -"checksum getrandom 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "34f33de6f0ae7c9cb5e574502a562e2b512799e32abb801cd1e79ad952b62b49" -"checksum lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bc5729f27f159ddd61f4df6228e827e86643d4d3e7c32183cb30a1c08f604a14" -"checksum libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)" = "d44e80633f007889c7eff624b709ab43c92d708caad982295768a7b13ca3b5eb" +"checksum getrandom 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "fc344b02d3868feb131e8b5fe2b9b0a1cc42942679af493061fc13b853243872" +"checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +"checksum libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)" = "34fcd2c08d2f832f376f4173a231990fa5aef4e99fb569867318a227ef4c06ba" "checksum num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bcef43580c035376c0705c42792c294b66974abbfd2789b511784023f71f3273" "checksum ppv-lite86 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e3cbf9f658cdb5000fcf6f362b8ea2ba154b9f146a61c7a20d647034c6b6561b" "checksum rand 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d47eab0e83d9693d40f825f86948aa16eff6750ead4bdffc4ab95b8b3a7f052c" @@ -127,3 +133,4 @@ dependencies = [ "checksum rand_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "615e683324e75af5d43d8f7a39ffe3ee4a9dc42c5c701167a71dc59c3a493aca" "checksum rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" "checksum rand_pcg 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3e196346cbbc5c70c77e7b4926147ee8e383a38ee4d15d58a08098b169e492b6" +"checksum wasi 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fd5442abcac6525a045cc8c795aedb60da7a2e5e89c7bf18a0d5357849bb23c7" From c6c9276d6122e4302ee42389eaf29e51ef795a57 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 26 Aug 2019 19:44:27 +0200 Subject: [PATCH 1070/3747] bump Rust and xargo --- rust-version | 2 +- src/bin/cargo-miri.rs | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/rust-version b/rust-version index 012763c000237..70f10366b9937 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -bea0372a1a7a31b81f28cc4d9a83a2dc9a79d008 +521d78407471cb78e9bbf47160f6aa23047ac499 diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index b1dc306bcb1df..8749e5b7eed93 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -243,7 +243,7 @@ fn setup(ask_user: bool) { } // First, we need xargo. - if xargo_version().map_or(true, |v| v < (0, 3, 15)) { + if xargo_version().map_or(true, |v| v < (0, 3, 16)) { if ask_user { ask("It seems you do not have a recent enough xargo installed. I will run `cargo install xargo -f`. Proceed?"); } else { @@ -297,7 +297,6 @@ default_features = false features = ["panic_unwind"] [dependencies.test] -stage = 1 "#).unwrap(); // The boring bits: a dummy project for xargo. File::create(dir.join("Cargo.toml")).unwrap() From 63ec6e6467a504e9445b9c69450a80a4dc5e6a88 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 26 Aug 2019 20:53:33 +0200 Subject: [PATCH 1071/3747] decrease getrandom version so that we dont have to bump Cargo.toml in rustc --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 1ab0580cc6315..6f45cc7a06db5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -35,7 +35,7 @@ byteorder = { version = "1.1", features = ["i128"]} cargo_metadata = { version = "0.8", optional = true } directories = { version = "2.0", optional = true } rustc_version = { version = "0.2.3", optional = true } -getrandom = "0.1.10" +getrandom = "0.1.8" env_logger = "0.6" log = "0.4" shell-escape = "0.1.4" From ace3416cf25d4214e1ebdac55459abd8edee4999 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Mon, 26 Aug 2019 15:18:11 -0500 Subject: [PATCH 1072/3747] Write name and value for each env var --- src/shims/env.rs | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/shims/env.rs b/src/shims/env.rs index eb5722a5a3d82..988ee61a0e355 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -16,17 +16,19 @@ impl EnvVars { ) { if ecx.machine.communicate { for (name, value) in std::env::vars() { - let value = alloc_env_value(value.as_bytes(), ecx.memory_mut()); - ecx.machine.env_vars.map.insert(name.into_bytes(), value); + let var_ptr = alloc_env_var(name.as_bytes(), value.as_bytes(), ecx.memory_mut()); + ecx.machine.env_vars.map.insert(name.into_bytes(), var_ptr); } } } } -fn alloc_env_value<'mir, 'tcx>( - bytes: &[u8], +fn alloc_env_var<'mir, 'tcx>( + name: &[u8], + value: &[u8], memory: &mut Memory<'mir, 'tcx, Evaluator<'tcx>>, ) -> Pointer { + let bytes = [name, b"=", value].concat(); let tcx = {memory.tcx.tcx}; let length = bytes.len() as u64; // `+1` for the null terminator. @@ -57,7 +59,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let name_ptr = this.read_scalar(name_op)?.not_undef()?; let name = this.memory().read_c_str(name_ptr)?; Ok(match this.machine.env_vars.map.get(name) { - Some(&var) => Scalar::Ptr(var), + Some(var_ptr) => Scalar::Ptr(var_ptr.offset(Size::from_bytes(name.len() as u64 + 1), this)?), None => Scalar::ptr_null(&*this.tcx), }) } @@ -80,8 +82,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } if let Some((name, value)) = new { - let value_copy = alloc_env_value(&value, this.memory_mut()); - if let Some(var) = this.machine.env_vars.map.insert(name.to_owned(), value_copy) { + let var_ptr = alloc_env_var(&name, &value, this.memory_mut()); + if let Some(var) = this.machine.env_vars.map.insert(name.to_owned(), var_ptr) { this.memory_mut().deallocate(var, None, MiriMemoryKind::Env.into())?; } Ok(0) From 3a68d943bab229271ad6d537e043d5bc3eed514d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 27 Aug 2019 08:32:31 +0200 Subject: [PATCH 1073/3747] rustup --- rust-version | 2 +- src/eval.rs | 4 ++-- src/machine.rs | 2 +- src/shims/foreign_items.rs | 2 +- src/shims/mod.rs | 2 +- src/shims/tls.rs | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/rust-version b/rust-version index 70f10366b9937..8c746ad2fff8d 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -521d78407471cb78e9bbf47160f6aa23047ac499 +0444b9f66acb5da23dc816e0d8eb59623ba9ea50 diff --git a/src/eval.rs b/src/eval.rs index 39da414de14a3..bd4d8a0bef85e 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -44,7 +44,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( // Setup first stack-frame let main_instance = ty::Instance::mono(ecx.tcx.tcx, main_id); - let main_mir = ecx.load_mir(main_instance.def)?; + let main_mir = ecx.load_mir(main_instance.def, None)?; if !main_mir.return_ty().is_unit() || main_mir.arg_count != 0 { throw_unsup_format!( @@ -62,7 +62,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( ecx.tcx.mk_substs( ::std::iter::once(ty::subst::Kind::from(main_ret_ty))) ).unwrap(); - let start_mir = ecx.load_mir(start_instance.def)?; + let start_mir = ecx.load_mir(start_instance.def, None)?; if start_mir.arg_count != 3 { bug!( diff --git a/src/machine.rs b/src/machine.rs index 8989062b513a9..3853a45fd9900 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -204,7 +204,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { // Call the `exchange_malloc` lang item. let malloc = ecx.tcx.lang_items().exchange_malloc_fn().unwrap(); let malloc = ty::Instance::mono(ecx.tcx.tcx, malloc); - let malloc_mir = ecx.load_mir(malloc.def)?; + let malloc_mir = ecx.load_mir(malloc.def, None)?; ecx.push_stack_frame( malloc, malloc_mir.span, diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 59e7673dcab5f..0b2fa64996e7e 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -341,7 +341,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Now we make a function call. // TODO: consider making this reusable? `InterpCx::step` does something similar // for the TLS destructors, and of course `eval_main`. - let mir = this.load_mir(f_instance.def)?; + let mir = this.load_mir(f_instance.def, None)?; let ret_place = MPlaceTy::dangling(this.layout_of(this.tcx.mk_unit())?, this).into(); this.push_stack_frame( f_instance, diff --git a/src/shims/mod.rs b/src/shims/mod.rs index 96a1f34152b32..5fbe6e379987b 100644 --- a/src/shims/mod.rs +++ b/src/shims/mod.rs @@ -47,6 +47,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // Otherwise, load the MIR. - Ok(Some(this.load_mir(instance.def)?)) + Ok(Some(this.load_mir(instance.def, None)?)) } } diff --git a/src/shims/tls.rs b/src/shims/tls.rs index e90ace948b7a0..44bedbd44d2d9 100644 --- a/src/shims/tls.rs +++ b/src/shims/tls.rs @@ -148,7 +148,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx assert!(!this.is_null(ptr).unwrap(), "Data can't be NULL when dtor is called!"); // TODO: Potentially, this has to support all the other possible instances? // See eval_fn_call in interpret/terminator/mod.rs - let mir = this.load_mir(instance.def)?; + let mir = this.load_mir(instance.def, None)?; let ret_place = MPlaceTy::dangling(this.layout_of(this.tcx.mk_unit())?, this).into(); this.push_stack_frame( instance, From 26afb4685d460f1153313716406bfe40011c2bf3 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 27 Aug 2019 08:42:36 +0200 Subject: [PATCH 1074/3747] hashmap ICEs with optimizations, temporarily disable --- tests/compiletest.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/compiletest.rs b/tests/compiletest.rs index 00fd039ad7e86..aa2488b1a417c 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -122,7 +122,7 @@ fn test_runner(_tests: &[&()]) { std::env::set_var("MIRI_ENV_VAR_TEST", "0"); run_pass_miri(false); - run_pass_miri(true); + // FIXME: hashmap ICEs with optimizations run_pass_miri(true); compile_fail_miri(false); compile_fail_miri(true); From 283829c5c1a13c7c1f01b4b0e0e697b967bb46f1 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 27 Aug 2019 15:12:12 +0200 Subject: [PATCH 1075/3747] explicitly enable getrandom/std feature --- Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 6f45cc7a06db5..d78ce46f0fd26 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -31,11 +31,11 @@ doctest = false # and no doc tests required-features = ["rustc_tests"] [dependencies] -byteorder = { version = "1.1", features = ["i128"]} +byteorder = { version = "1.1", features = ["i128"] } cargo_metadata = { version = "0.8", optional = true } directories = { version = "2.0", optional = true } rustc_version = { version = "0.2.3", optional = true } -getrandom = "0.1.8" +getrandom = { version = "0.1.8", features = ["std"] } env_logger = "0.6" log = "0.4" shell-escape = "0.1.4" From 7d93cc7b5efeeec001aa8071b1bc61b8cc111c95 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Tue, 27 Aug 2019 08:45:37 -0500 Subject: [PATCH 1076/3747] Add docs --- src/shims/env.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/shims/env.rs b/src/shims/env.rs index 988ee61a0e355..8f946a2b5eb10 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -7,6 +7,8 @@ use crate::*; #[derive(Default)] pub struct EnvVars { + /// Stores pointers to the environment variables. These variables must be stored as + /// null-terminated C strings with the `"{name}={value}"` format. map: HashMap, Pointer>, } @@ -59,6 +61,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let name_ptr = this.read_scalar(name_op)?.not_undef()?; let name = this.memory().read_c_str(name_ptr)?; Ok(match this.machine.env_vars.map.get(name) { + // The offset is used to strip the "{name}=" part of the string. Some(var_ptr) => Scalar::Ptr(var_ptr.offset(Size::from_bytes(name.len() as u64 + 1), this)?), None => Scalar::ptr_null(&*this.tcx), }) From 71aae4ffa5a8ee36f09953d1b85c7b5c2818e0c6 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 28 Aug 2019 09:15:31 +0200 Subject: [PATCH 1077/3747] test that build scripts do not run in Miri --- test-cargo-miri/Cargo.toml | 1 + test-cargo-miri/build.rs | 15 +++++++++++++++ 2 files changed, 16 insertions(+) create mode 100644 test-cargo-miri/build.rs diff --git a/test-cargo-miri/Cargo.toml b/test-cargo-miri/Cargo.toml index 3abb437049f0f..c2460014b6635 100644 --- a/test-cargo-miri/Cargo.toml +++ b/test-cargo-miri/Cargo.toml @@ -3,6 +3,7 @@ name = "cargo-miri-test" version = "0.1.0" authors = ["Oliver Schneider "] edition = "2018" +build = "build.rs" [dependencies] byteorder = "1.0" diff --git a/test-cargo-miri/build.rs b/test-cargo-miri/build.rs new file mode 100644 index 0000000000000..950fc3c82bb15 --- /dev/null +++ b/test-cargo-miri/build.rs @@ -0,0 +1,15 @@ +#![feature(asm)] + +fn not_in_miri() -> i32 { + // Inline assembly definitely does not work in Miri. + let dummy = 42; + unsafe { + asm!("" : : "r"(&dummy)); + } + return dummy; +} + +fn main() { + not_in_miri(); + println!("cargo:rerun-if-changed=build.rs"); +} From 7faa329f11d38da611e49c82c823a35758a713e5 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 28 Aug 2019 09:27:19 +0200 Subject: [PATCH 1078/3747] more implicit --- Cargo.toml | 1 - test-cargo-miri/Cargo.toml | 1 - 2 files changed, 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index d78ce46f0fd26..ecc8deedf3250 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,7 +5,6 @@ license = "MIT/Apache-2.0" name = "miri" repository = "https://github.com/rust-lang/miri" version = "0.1.0" -build = "build.rs" default-run = "miri" edition = "2018" diff --git a/test-cargo-miri/Cargo.toml b/test-cargo-miri/Cargo.toml index c2460014b6635..3abb437049f0f 100644 --- a/test-cargo-miri/Cargo.toml +++ b/test-cargo-miri/Cargo.toml @@ -3,7 +3,6 @@ name = "cargo-miri-test" version = "0.1.0" authors = ["Oliver Schneider "] edition = "2018" -build = "build.rs" [dependencies] byteorder = "1.0" From 79dd70fd9bd2de5a0b2dd4697905571f39012dc7 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 28 Aug 2019 18:41:30 +0200 Subject: [PATCH 1079/3747] Stacked Borrows: don't read from memory during retagging --- src/helpers.rs | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index 330d6bc996b78..e5203becd5cf3 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -222,8 +222,23 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // This is `Freeze`, there cannot be an `UnsafeCell` Ok(()) } else { - // Proceed further - self.walk_value(v) + // We want to not actually read from memory for this visit. So, before + // walking this value, we have to make sure it is not a + // `Variants::Multiple`. + match v.layout.variants { + layout::Variants::Multiple { .. } => { + // A multi-variant enum, or generator, or so. + // Treat this like a union: without reading from memory, + // we cannot determine the variant we are in. Reading from + // memory would be subject to Stacked Borrows rules, leading + // to all sorts of "funny" recursion. + self.visit_union(v) + } + layout::Variants::Single { .. } => { + // Proceed further + self.walk_value(v) + } + } } } From f3ff10005ab1bdb7c4c0d43ee54d55563911f5ea Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 28 Aug 2019 18:45:10 +0200 Subject: [PATCH 1080/3747] small optimization --- src/helpers.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index e5203becd5cf3..3eafb28b8949c 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -232,10 +232,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // we cannot determine the variant we are in. Reading from // memory would be subject to Stacked Borrows rules, leading // to all sorts of "funny" recursion. - self.visit_union(v) + // We only end up here if the type is *not* freeze, so we just call the + // `UnsafeCell` action. + (self.unsafe_cell_action)(v) } layout::Variants::Single { .. } => { - // Proceed further + // Proceed further, try to find where exactly that `UnsafeCell` + // is hiding. self.walk_value(v) } } From 1ae1d71938e2a177f3edb60fc30991ce2c8e4536 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Wed, 28 Aug 2019 17:20:50 -0500 Subject: [PATCH 1081/3747] Add -Zmiri-env-exclude flag --- README.md | 2 ++ src/bin/miri-rustc-tests.rs | 1 + src/bin/miri.rs | 12 +++++++++++- src/eval.rs | 2 ++ 4 files changed, 16 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index d3e4adfa1785e..3cc4872eb7f09 100644 --- a/README.md +++ b/README.md @@ -160,6 +160,8 @@ Several `-Z` flags are relevant for Miri: * `-Zmiri-disable-isolation` disables host host isolation. As a consequence, the program has access to host resources such as environment variables and randomness (and, eventually, file systems and more). +* `-Zmiri-env-exclude=` keeps the `var` environment variable isolated from + the host. It can be used multiple times to exclude several variables. * `-Zmir-opt-level` controls how many MIR optimizations are performed. Miri overrides the default to be `0`; be advised that using any higher level can make Miri miss bugs in your program because they got optimized away. diff --git a/src/bin/miri-rustc-tests.rs b/src/bin/miri-rustc-tests.rs index 9ef64c38638b7..f8bd92afbec7f 100644 --- a/src/bin/miri-rustc-tests.rs +++ b/src/bin/miri-rustc-tests.rs @@ -51,6 +51,7 @@ impl rustc_driver::Callbacks for MiriCompilerCalls { let config = MiriConfig { validate: true, communicate: false, + excluded_env_vars: vec![], args: vec![], seed: None, }; diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 55522a52e0128..6e4bf4a6c269e 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -135,6 +135,7 @@ fn main() { let mut rustc_args = vec![]; let mut miri_args = vec![]; let mut after_dashdash = false; + let mut excluded_env_vars = vec![]; for arg in std::env::args() { if rustc_args.is_empty() { // Very first arg: for `rustc`. @@ -175,6 +176,9 @@ fn main() { seed = Some(u64::from_be_bytes(bytes)); }, + arg if arg.starts_with("-Zmiri-env-exclude=") => { + excluded_env_vars.push(arg.trim_start_matches("-Zmiri-env-exclude=").to_owned()); + }, _ => { rustc_args.push(arg); } @@ -200,7 +204,13 @@ fn main() { debug!("rustc arguments: {:?}", rustc_args); debug!("miri arguments: {:?}", miri_args); - let miri_config = miri::MiriConfig { validate, communicate, args: miri_args, seed }; + let miri_config = miri::MiriConfig { + validate, + communicate, + excluded_env_vars, + seed, + args: miri_args, + }; let result = rustc_driver::report_ices_to_stderr_if_any(move || { rustc_driver::run_compiler(&rustc_args, &mut MiriCompilerCalls { miri_config }, None, None) }).and_then(|result| result); diff --git a/src/eval.rs b/src/eval.rs index bd4d8a0bef85e..463f21d30ec7a 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -22,6 +22,8 @@ pub struct MiriConfig { pub validate: bool, /// Determines if communication with the host environment is enabled. pub communicate: bool, + /// Environment variables that should always be isolated from the host. + pub excluded_env_vars: Vec, pub args: Vec, /// The seed to use when non-determinism or randomness are required (e.g. ptr-to-int cast, `getrandom()`). pub seed: Option, From c1cec3b247f022b9e3a88c6afe7d1fe8cc459a76 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Wed, 28 Aug 2019 17:31:57 -0500 Subject: [PATCH 1082/3747] Exclude env vars using flag --- src/eval.rs | 2 +- src/shims/env.rs | 7 +++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/eval.rs b/src/eval.rs index 463f21d30ec7a..e44fdfd141696 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -42,7 +42,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( MemoryExtra::new(StdRng::seed_from_u64(config.seed.unwrap_or(0)), config.validate), ); // Complete initialization. - EnvVars::init(&mut ecx); + EnvVars::init(&mut ecx, config.excluded_env_vars); // Setup first stack-frame let main_instance = ty::Instance::mono(ecx.tcx.tcx, main_id); diff --git a/src/shims/env.rs b/src/shims/env.rs index 8f946a2b5eb10..5a5dffa1d09b0 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -15,11 +15,14 @@ pub struct EnvVars { impl EnvVars { pub(crate) fn init<'mir, 'tcx>( ecx: &mut InterpCx<'mir, 'tcx, Evaluator<'tcx>>, + excluded_env_vars: Vec, ) { if ecx.machine.communicate { for (name, value) in std::env::vars() { - let var_ptr = alloc_env_var(name.as_bytes(), value.as_bytes(), ecx.memory_mut()); - ecx.machine.env_vars.map.insert(name.into_bytes(), var_ptr); + if !excluded_env_vars.contains(&name) { + let var_ptr = alloc_env_var(name.as_bytes(), value.as_bytes(), ecx.memory_mut()); + ecx.machine.env_vars.map.insert(name.into_bytes(), var_ptr); + } } } } From f4a25e530a773175c19ad6c50e8ce5d0f043e9c7 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Wed, 28 Aug 2019 17:34:34 -0500 Subject: [PATCH 1083/3747] Add env exclusion test --- tests/run-pass/env-exclude.rs | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 tests/run-pass/env-exclude.rs diff --git a/tests/run-pass/env-exclude.rs b/tests/run-pass/env-exclude.rs new file mode 100644 index 0000000000000..efcf7a756114c --- /dev/null +++ b/tests/run-pass/env-exclude.rs @@ -0,0 +1,6 @@ +// ignore-windows: TODO env var emulation stubbed out on Windows +// compile-flags: -Zmiri-disable-isolation -Zmiri-env-exclude=MIRI_ENV_VAR_TEST + +fn main() { + assert!(std::env::var("MIRI_ENV_VAR_TEST").is_err()); +} From abcda6dc941fb992c4293ab93d710a713ed365cc Mon Sep 17 00:00:00 2001 From: Christian Poveda <31802960+christianpoveda@users.noreply.github.com> Date: Thu, 29 Aug 2019 01:26:14 -0500 Subject: [PATCH 1084/3747] Small corrections Co-Authored-By: Ralf Jung --- README.md | 2 +- benches/helpers/miri_helper.rs | 1 + src/bin/miri-rustc-tests.rs | 1 + src/eval.rs | 1 + 4 files changed, 4 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 3cc4872eb7f09..f5b8999d1c590 100644 --- a/README.md +++ b/README.md @@ -161,7 +161,7 @@ Several `-Z` flags are relevant for Miri: the program has access to host resources such as environment variables and randomness (and, eventually, file systems and more). * `-Zmiri-env-exclude=` keeps the `var` environment variable isolated from - the host. It can be used multiple times to exclude several variables. + the host. Can be used multiple times to exclude several variables. * `-Zmir-opt-level` controls how many MIR optimizations are performed. Miri overrides the default to be `0`; be advised that using any higher level can make Miri miss bugs in your program because they got optimized away. diff --git a/benches/helpers/miri_helper.rs b/benches/helpers/miri_helper.rs index 5cb938659a6cd..a4f5599672045 100644 --- a/benches/helpers/miri_helper.rs +++ b/benches/helpers/miri_helper.rs @@ -28,6 +28,7 @@ impl rustc_driver::Callbacks for MiriCompilerCalls<'_> { let config = miri::MiriConfig { validate: true, communicate: false, + excluded_env_vars: vec![], args: vec![], seed: None, }; diff --git a/src/bin/miri-rustc-tests.rs b/src/bin/miri-rustc-tests.rs index f8bd92afbec7f..3b4ad8415917a 100644 --- a/src/bin/miri-rustc-tests.rs +++ b/src/bin/miri-rustc-tests.rs @@ -70,6 +70,7 @@ impl rustc_driver::Callbacks for MiriCompilerCalls { let config = MiriConfig { validate: true, communicate: false, + excluded_env_vars: vec![], args: vec![], seed: None }; diff --git a/src/eval.rs b/src/eval.rs index e44fdfd141696..667491f8d477e 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -24,6 +24,7 @@ pub struct MiriConfig { pub communicate: bool, /// Environment variables that should always be isolated from the host. pub excluded_env_vars: Vec, + /// Command-line arguments passed to the interpreted program. pub args: Vec, /// The seed to use when non-determinism or randomness are required (e.g. ptr-to-int cast, `getrandom()`). pub seed: Option, From 9c54368ccaf4d8a4f67c2df0efa428a6067f0ed3 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Thu, 29 Aug 2019 04:07:20 -0500 Subject: [PATCH 1085/3747] Exclude TERM env var by default --- src/shims/env.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/shims/env.rs b/src/shims/env.rs index 5a5dffa1d09b0..d0b5abbaf1819 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -15,8 +15,10 @@ pub struct EnvVars { impl EnvVars { pub(crate) fn init<'mir, 'tcx>( ecx: &mut InterpCx<'mir, 'tcx, Evaluator<'tcx>>, - excluded_env_vars: Vec, + mut excluded_env_vars: Vec, ) { + // Exclude TERM var to avoid calls to the file system + excluded_env_vars.push("TERM".to_owned()); if ecx.machine.communicate { for (name, value) in std::env::vars() { if !excluded_env_vars.contains(&name) { From 814fe9951637bc965f072c3d6b7d0386c33e90ae Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Thu, 29 Aug 2019 04:09:34 -0500 Subject: [PATCH 1086/3747] Add cargo-miri test for no isolation --- README.md | 3 ++- src/shims/env.rs | 3 ++- test-cargo-miri/run-test.py | 4 ++++ test-cargo-miri/test.stdout.ref3 | 11 +++++++++++ 4 files changed, 19 insertions(+), 2 deletions(-) create mode 100644 test-cargo-miri/test.stdout.ref3 diff --git a/README.md b/README.md index f5b8999d1c590..7ae3c84517f95 100644 --- a/README.md +++ b/README.md @@ -161,7 +161,8 @@ Several `-Z` flags are relevant for Miri: the program has access to host resources such as environment variables and randomness (and, eventually, file systems and more). * `-Zmiri-env-exclude=` keeps the `var` environment variable isolated from - the host. Can be used multiple times to exclude several variables. + the host. Can be used multiple times to exclude several variables. The `TERM` + environment variable is excluded by default. * `-Zmir-opt-level` controls how many MIR optimizations are performed. Miri overrides the default to be `0`; be advised that using any higher level can make Miri miss bugs in your program because they got optimized away. diff --git a/src/shims/env.rs b/src/shims/env.rs index d0b5abbaf1819..4b126fbfdaed1 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -17,8 +17,9 @@ impl EnvVars { ecx: &mut InterpCx<'mir, 'tcx, Evaluator<'tcx>>, mut excluded_env_vars: Vec, ) { - // Exclude TERM var to avoid calls to the file system + // Exclude `TERM` var to avoid terminfo trying to open the termcap file. excluded_env_vars.push("TERM".to_owned()); + if ecx.machine.communicate { for (name, value) in std::env::vars() { if !excluded_env_vars.contains(&name) { diff --git a/test-cargo-miri/run-test.py b/test-cargo-miri/run-test.py index 73515c74e4010..499c2e896f172 100755 --- a/test-cargo-miri/run-test.py +++ b/test-cargo-miri/run-test.py @@ -60,6 +60,10 @@ def test_cargo_miri_test(): cargo_miri("test") + ["--", "--", "le1"], "test.stdout.ref2", "test.stderr.ref" ) + test("cargo miri test (without isolation)", + cargo_miri("test") + ["--", "-Zmiri-disable-isolation", "--", "num_cpus"], + "test.stdout.ref3", "test.stderr.ref" + ) os.chdir(os.path.dirname(os.path.realpath(__file__))) diff --git a/test-cargo-miri/test.stdout.ref3 b/test-cargo-miri/test.stdout.ref3 new file mode 100644 index 0000000000000..f0d8afbd0e8e4 --- /dev/null +++ b/test-cargo-miri/test.stdout.ref3 @@ -0,0 +1,11 @@ + +running 0 tests + +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 1 filtered out + + +running 1 test +test num_cpus ... ok + +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 3 filtered out + From cecbe1611befc6bab2fa194e5cdef88f56692193 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 25 Aug 2019 14:56:38 +0200 Subject: [PATCH 1087/3747] test for invalid wide raw ptr --- tests/compile-fail/validity/invalid_wide_raw.rs | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 tests/compile-fail/validity/invalid_wide_raw.rs diff --git a/tests/compile-fail/validity/invalid_wide_raw.rs b/tests/compile-fail/validity/invalid_wide_raw.rs new file mode 100644 index 0000000000000..ec14f6988b24a --- /dev/null +++ b/tests/compile-fail/validity/invalid_wide_raw.rs @@ -0,0 +1,8 @@ +fn main() { + trait T { } + #[derive(Debug)] + struct S { + x: * mut dyn T + } + dbg!(S { x: unsafe { std::mem::transmute((0usize, 0usize)) } }); //~ ERROR: encountered dangling or unaligned vtable pointer +} From 5483531be36cc1cdc19048829c1a135ea669ab50 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 29 Aug 2019 17:20:14 +0200 Subject: [PATCH 1088/3747] bump Rust --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 8c746ad2fff8d..3520d790eca85 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -0444b9f66acb5da23dc816e0d8eb59623ba9ea50 +7445622bcb515c822a2fc6e8c57c90478c1a56bb From 4afa3bccb0a41b49037cb5b80943d58374a04cf7 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Thu, 29 Aug 2019 15:03:10 -0500 Subject: [PATCH 1089/3747] Rewrite alloc_env_var --- src/shims/env.rs | 25 ++++++------------------- 1 file changed, 6 insertions(+), 19 deletions(-) diff --git a/src/shims/env.rs b/src/shims/env.rs index 4b126fbfdaed1..1cffc60bc40a1 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -1,6 +1,6 @@ use std::collections::HashMap; -use rustc::ty::layout::{Size, Align}; +use rustc::ty::layout::{Size}; use rustc_mir::interpret::{Pointer, Memory}; use crate::stacked_borrows::Tag; use crate::*; @@ -36,24 +36,11 @@ fn alloc_env_var<'mir, 'tcx>( value: &[u8], memory: &mut Memory<'mir, 'tcx, Evaluator<'tcx>>, ) -> Pointer { - let bytes = [name, b"=", value].concat(); - let tcx = {memory.tcx.tcx}; - let length = bytes.len() as u64; - // `+1` for the null terminator. - let ptr = memory.allocate( - Size::from_bytes(length + 1), - Align::from_bytes(1).unwrap(), - MiriMemoryKind::Env.into(), - ); - // We just allocated these, so the write cannot fail. - let alloc = memory.get_mut(ptr.alloc_id).unwrap(); - alloc.write_bytes(&tcx, ptr, &bytes).unwrap(); - let trailing_zero_ptr = ptr.offset( - Size::from_bytes(length), - &tcx, - ).unwrap(); - alloc.write_bytes(&tcx, trailing_zero_ptr, &[0]).unwrap(); - ptr + let mut bytes = name.to_vec(); + bytes.push(b'='); + bytes.extend_from_slice(value); + bytes.push(0); + memory.allocate_static_bytes(bytes.as_slice(), MiriMemoryKind::Env.into()) } impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} From f67af5a1c2e6e7c785b9fc1d1edcff936992382a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 27 Aug 2019 18:36:43 +0200 Subject: [PATCH 1090/3747] test too big slice --- tests/compile-fail/slice-too-big.rs | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 tests/compile-fail/slice-too-big.rs diff --git a/tests/compile-fail/slice-too-big.rs b/tests/compile-fail/slice-too-big.rs new file mode 100644 index 0000000000000..08ab48175aedb --- /dev/null +++ b/tests/compile-fail/slice-too-big.rs @@ -0,0 +1,7 @@ +use std::mem; +use std::usize; + +fn main() { unsafe { + let ptr = Box::into_raw(Box::new(0u8)); + let _x: &[u8] = mem::transmute((ptr, usize::MAX)); //~ ERROR: invalid slice: total size is bigger than largest supported object +} } From dfca0263d0471547ccad1841076be07197c38675 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 31 Aug 2019 08:44:47 +0200 Subject: [PATCH 1091/3747] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 3520d790eca85..af5cbdfb6ca3a 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -7445622bcb515c822a2fc6e8c57c90478c1a56bb +2d851b33181b1404856cb1d8b20d261adda54ffb From a37cd856adef52451f024b44c668a8021f8236e0 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 2 Sep 2019 16:13:35 +0200 Subject: [PATCH 1092/3747] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index af5cbdfb6ca3a..28dca558cf785 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -2d851b33181b1404856cb1d8b20d261adda54ffb +fdaf594bab31eec75fb6d582cd33e5a5b43de7f4 From e479ab26406ed8a473987e5f4a1f3be3e978e5d2 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Thu, 5 Sep 2019 18:17:58 +0200 Subject: [PATCH 1093/3747] Rustup --- src/intptrcast.rs | 10 +++++----- src/machine.rs | 39 ++++++++++++-------------------------- src/shims/foreign_items.rs | 2 +- src/shims/intrinsics.rs | 18 +++++++++--------- 4 files changed, 27 insertions(+), 42 deletions(-) diff --git a/src/intptrcast.rs b/src/intptrcast.rs index b1e89f3819ae2..e08166b8c2b27 100644 --- a/src/intptrcast.rs +++ b/src/intptrcast.rs @@ -47,7 +47,7 @@ impl<'mir, 'tcx> GlobalState { } let global_state = memory.extra.intptrcast.borrow(); - + Ok(match global_state.int_to_ptr_map.binary_search_by_key(&int, |(addr, _)| *addr) { Ok(pos) => { let (_, alloc_id) = global_state.int_to_ptr_map[pos]; @@ -55,7 +55,7 @@ impl<'mir, 'tcx> GlobalState { // zero. The pointer is untagged because it was created from a cast Pointer::new_with_tag(alloc_id, Size::from_bytes(0), Tag::Untagged) }, - Err(0) => throw_unsup!(DanglingPointerDeref), + Err(0) => throw_unsup!(DanglingPointerDeref), Err(pos) => { // This is the largest of the adresses smaller than `int`, // i.e. the greatest lower bound (glb) @@ -63,12 +63,12 @@ impl<'mir, 'tcx> GlobalState { // This never overflows because `int >= glb` let offset = int - glb; // If the offset exceeds the size of the allocation, this access is illegal - if offset <= memory.get(alloc_id)?.bytes.len() as u64 { + if offset <= memory.get(alloc_id)?.size.bytes() { // This pointer is untagged because it was created from a cast Pointer::new_with_tag(alloc_id, Size::from_bytes(offset), Tag::Untagged) } else { throw_unsup!(DanglingPointerDeref) - } + } } }) } @@ -108,7 +108,7 @@ impl<'mir, 'tcx> GlobalState { global_state.next_base_addr = base_addr.checked_add(max(size.bytes(), 1)).unwrap(); // Given that `next_base_addr` increases in each allocation, pushing the // corresponding tuple keeps `int_to_ptr_map` sorted - global_state.int_to_ptr_map.push((base_addr, ptr.alloc_id)); + global_state.int_to_ptr_map.push((base_addr, ptr.alloc_id)); base_addr } diff --git a/src/machine.rs b/src/machine.rs index 3853a45fd9900..95cb31d67b8f5 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -248,7 +248,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { None => tcx.item_name(def_id).as_str(), }; - let alloc = match link_name.get() { + let alloc = match &*link_name { "__cxa_thread_atexit_impl" => { // This should be all-zero, pointer-sized. let size = tcx.data_layout.pointer_size; @@ -280,40 +280,25 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { } else { let (stacks, base_tag) = Stacks::new_allocation( id, - Size::from_bytes(alloc.bytes.len() as u64), + alloc.size, Rc::clone(&memory_extra.stacked_borrows), kind, ); (Some(stacks), base_tag) }; - if kind != MiriMemoryKind::Static.into() { - assert!(alloc.relocations.is_empty(), "Only statics can come initialized with inner pointers"); - // Now we can rely on the inner pointers being static, too. - } let mut stacked_borrows = memory_extra.stacked_borrows.borrow_mut(); - let alloc: Allocation = Allocation { - bytes: alloc.bytes, - relocations: Relocations::from_presorted( - alloc.relocations.iter() - // The allocations in the relocations (pointers stored *inside* this allocation) - // all get the base pointer tag. - .map(|&(offset, ((), alloc))| { - let tag = if !memory_extra.validate { - Tag::Untagged - } else { - stacked_borrows.static_base_ptr(alloc) - }; - (offset, (tag, alloc)) - }) - .collect() - ), - undef_mask: alloc.undef_mask, - align: alloc.align, - mutability: alloc.mutability, - extra: AllocExtra { + let alloc: Allocation = alloc.retag( + |alloc| if !memory_extra.validate { + Tag::Untagged + } else { + // Only statics may already contain pointers at this point + assert_eq!(kind, MiriMemoryKind::Static.into()); + stacked_borrows.static_base_ptr(alloc) + }, + AllocExtra { stacked_borrows: stacks, }, - }; + ); (Cow::Owned(alloc), base_tag) } diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 0b2fa64996e7e..90c18265fcf7c 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -138,7 +138,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx None => this.tcx.item_name(def_id).as_str(), }; // Strip linker suffixes (seen on 32-bit macOS). - let link_name = link_name.get().trim_end_matches("$UNIX2003"); + let link_name = link_name.trim_end_matches("$UNIX2003"); let tcx = &{this.tcx.tcx}; // First: functions that diverge. diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 8656962761713..06af6db76ae6b 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -28,8 +28,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // (as opposed to through a place), we have to remember to erase any tag // that might still hang around! - let intrinsic_name = this.tcx.item_name(instance.def_id()).as_str(); - match intrinsic_name.get() { + let intrinsic_name = &*this.tcx.item_name(instance.def_id()).as_str(); + match intrinsic_name { "arith_offset" => { let offset = this.read_scalar(args[1])?.to_isize(this)?; let ptr = this.read_scalar(args[0])?.not_undef()?; @@ -228,7 +228,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "log10f32" | "log2f32" | "floorf32" | "ceilf32" | "truncf32" | "roundf32" => { // FIXME: Using host floats. let f = f32::from_bits(this.read_scalar(args[0])?.to_u32()?); - let f = match intrinsic_name.get() { + let f = match intrinsic_name { "sinf32" => f.sin(), "fabsf32" => f.abs(), "cosf32" => f.cos(), @@ -251,7 +251,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "log10f64" | "log2f64" | "floorf64" | "ceilf64" | "truncf64" | "roundf64" => { // FIXME: Using host floats. let f = f64::from_bits(this.read_scalar(args[0])?.to_u64()?); - let f = match intrinsic_name.get() { + let f = match intrinsic_name { "sinf64" => f.sin(), "fabsf64" => f.abs(), "cosf64" => f.cos(), @@ -273,7 +273,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "fadd_fast" | "fsub_fast" | "fmul_fast" | "fdiv_fast" | "frem_fast" => { let a = this.read_immediate(args[0])?; let b = this.read_immediate(args[1])?; - let op = match intrinsic_name.get() { + let op = match intrinsic_name { "fadd_fast" => mir::BinOp::Add, "fsub_fast" => mir::BinOp::Sub, "fmul_fast" => mir::BinOp::Mul, @@ -287,7 +287,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "minnumf32" | "maxnumf32" => { let a = this.read_scalar(args[0])?.to_f32()?; let b = this.read_scalar(args[1])?.to_f32()?; - let res = if intrinsic_name.get().starts_with("min") { + let res = if intrinsic_name.starts_with("min") { a.min(b) } else { a.max(b) @@ -298,7 +298,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "minnumf64" | "maxnumf64" => { let a = this.read_scalar(args[0])?.to_f64()?; let b = this.read_scalar(args[1])?.to_f64()?; - let res = if intrinsic_name.get().starts_with("min") { + let res = if intrinsic_name.starts_with("min") { a.min(b) } else { a.max(b) @@ -509,7 +509,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "unchecked_add" | "unchecked_sub" | "unchecked_mul" => { let l = this.read_immediate(args[0])?; let r = this.read_immediate(args[1])?; - let op = match intrinsic_name.get() { + let op = match intrinsic_name { "unchecked_add" => mir::BinOp::Add, "unchecked_sub" => mir::BinOp::Sub, "unchecked_mul" => mir::BinOp::Mul, @@ -517,7 +517,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx }; let (res, overflowed, _ty) = this.overflowing_binary_op(op, l, r)?; if overflowed { - throw_ub_format!("Overflowing arithmetic in {}", intrinsic_name.get()); + throw_ub_format!("Overflowing arithmetic in {}", intrinsic_name); } this.write_scalar(res, dest)?; } From 8349ead81db9e199fa42bc7b79a90499cb63b518 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Sun, 8 Sep 2019 12:28:31 +0200 Subject: [PATCH 1094/3747] Update latest working rust version id --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 28dca558cf785..937df90718601 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -fdaf594bab31eec75fb6d582cd33e5a5b43de7f4 +4894123d21ed4b153a2e5c32c0870cb2d97f9b46 From 636439c33f392d71fe455727dc9386d264b753d0 Mon Sep 17 00:00:00 2001 From: Wesley Wiser Date: Mon, 9 Sep 2019 06:32:02 -0400 Subject: [PATCH 1095/3747] Re-enable run-pass tests with optimizations enabled --- tests/compiletest.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/compiletest.rs b/tests/compiletest.rs index aa2488b1a417c..00fd039ad7e86 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -122,7 +122,7 @@ fn test_runner(_tests: &[&()]) { std::env::set_var("MIRI_ENV_VAR_TEST", "0"); run_pass_miri(false); - // FIXME: hashmap ICEs with optimizations run_pass_miri(true); + run_pass_miri(true); compile_fail_miri(false); compile_fail_miri(true); From b952584186bcb3035c89b8382cafe57a8bfa23ec Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Mon, 9 Sep 2019 13:00:20 +0200 Subject: [PATCH 1096/3747] Rustup to 1.39.0-nightly (1e869133b 2019-09-09) --- rust-version | 2 +- tests/compile-fail/stack_free.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/rust-version b/rust-version index 937df90718601..44e4cd9cceadb 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -4894123d21ed4b153a2e5c32c0870cb2d97f9b46 +1e869133b9888dc5abde54f4f31cb797ed9c7874 diff --git a/tests/compile-fail/stack_free.rs b/tests/compile-fail/stack_free.rs index a33bca1267595..43cc17308c06f 100644 --- a/tests/compile-fail/stack_free.rs +++ b/tests/compile-fail/stack_free.rs @@ -1,7 +1,7 @@ // Validation changes why we fail // compile-flags: -Zmiri-disable-validation -// error-pattern: tried to deallocate Stack memory but gave Machine(Rust) as the kind +// error-pattern: tried to deallocate `Stack` memory but gave `Machine(Rust)` as the kind fn main() { let x = 42; From f5c35a25842d3dcec676b7a5175c90a06184b87c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 11 Sep 2019 17:13:32 +0200 Subject: [PATCH 1097/3747] fix async test --- rust-version | 2 +- tests/run-pass/async-fn.rs | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/rust-version b/rust-version index 44e4cd9cceadb..2e869d31de410 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -1e869133b9888dc5abde54f4f31cb797ed9c7874 +74d5c70b174f06843049af2d764ff57ddc81c81c diff --git a/tests/run-pass/async-fn.rs b/tests/run-pass/async-fn.rs index dd31d901062f9..90448aca17792 100644 --- a/tests/run-pass/async-fn.rs +++ b/tests/run-pass/async-fn.rs @@ -15,7 +15,8 @@ pub async fn foo(x: &u32, y: u32) -> u32 { } async fn add(x: u32, y: u32) -> u32 { - async { x + y }.await + let a = async { x + y }; + a.await } async fn build_aggregate(a: u32, b: u32, c: u32, d: u32) -> u32 { From 62280b4b1166830facf1b43d6dda13df687252c8 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Wed, 11 Sep 2019 11:09:56 -0500 Subject: [PATCH 1098/3747] Use libcore's align_offset --- src/shims/mod.rs | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/src/shims/mod.rs b/src/shims/mod.rs index 5fbe6e379987b..5b67d075a5c75 100644 --- a/src/shims/mod.rs +++ b/src/shims/mod.rs @@ -1,3 +1,4 @@ + pub mod foreign_items; pub mod intrinsics; pub mod tls; @@ -27,9 +28,25 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // There are some more lang items we want to hook that CTFE does not hook (yet). if this.tcx.lang_items().align_offset_fn() == Some(instance.def.def_id()) { - // FIXME: return a real value in case the target allocation has an - // alignment bigger than the one requested. - let n = u128::max_value(); + + let n = { + let ptr = this.read_scalar(args[0])?.not_undef()?.assert_ptr(); + let align = this.force_bits( + this.read_scalar(args[1])?.not_undef()?, + this.pointer_size() + )? as usize; + + let stride = this.memory().get(ptr.alloc_id)?.align.bytes() as usize; + // if the allocation alignment is at least the required alignment, we use the + // libcore implementation + if stride >= align { + ((stride + ptr.offset.bytes() as usize) as *const ()) + .align_offset(align) as u128 + } else { + u128::max_value() + } + }; + let dest = dest.unwrap(); let n = this.truncate(n, dest.layout); this.write_scalar(Scalar::from_uint(n, dest.layout.size), dest)?; From 138492c30b85748c3ab9d9f040f98ad9e4343e1f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 11 Sep 2019 18:33:48 +0200 Subject: [PATCH 1099/3747] bump rand dependency --- Cargo.toml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index ecc8deedf3250..7d6e9812aaf92 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -39,11 +39,13 @@ env_logger = "0.6" log = "0.4" shell-escape = "0.1.4" hex = "0.3.2" -rand = "0.6" +rand = "0.7" + # A noop dependency that changes in the Rust repository, it's a bit of a hack. # See the `src/tools/rustc-workspace-hack/README.md` file in `rust-lang/rust` # for more information. rustc-workspace-hack = "1.0.0" + # Depend on num-traits with default features to avoid having to rebuild # between "cargo build" and "cargo intall". num-traits = "*" From ed70617b9c78ab28c1c6616e112b4516b8d4a7de Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Wed, 11 Sep 2019 12:08:42 -0500 Subject: [PATCH 1100/3747] Add test for u8 align_offset --- tests/run-pass/aligned_utf8_check.rs | 13 +++++++++++++ tests/run-pass/aligned_utf8_check.stdout | 1 + 2 files changed, 14 insertions(+) create mode 100644 tests/run-pass/aligned_utf8_check.rs create mode 100644 tests/run-pass/aligned_utf8_check.stdout diff --git a/tests/run-pass/aligned_utf8_check.rs b/tests/run-pass/aligned_utf8_check.rs new file mode 100644 index 0000000000000..0d2b2bf66a97c --- /dev/null +++ b/tests/run-pass/aligned_utf8_check.rs @@ -0,0 +1,13 @@ +fn main() { + const N: usize = 10; + + let x = vec![0x4141u16; N]; + + let mut y: Vec = unsafe { std::mem::transmute(x) }; + unsafe { y.set_len(2 * N) }; + + println!("{:?}", String::from_utf8_lossy(&y)); + + let mut x: Vec = unsafe { std::mem::transmute(y) }; + unsafe { x.set_len(N) }; +} diff --git a/tests/run-pass/aligned_utf8_check.stdout b/tests/run-pass/aligned_utf8_check.stdout new file mode 100644 index 0000000000000..8d08312cac7b5 --- /dev/null +++ b/tests/run-pass/aligned_utf8_check.stdout @@ -0,0 +1 @@ +"AAAAAAAAAAAAAAAAAAAA" From 247ac227ef3ce3fe5c1886b6b5c96eee17e4779a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Miku=C5=82a?= Date: Thu, 12 Sep 2019 12:45:00 +0200 Subject: [PATCH 1101/3747] Bump byteorder and remove no-op feature --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index ecc8deedf3250..25506c963a7e1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -30,11 +30,11 @@ doctest = false # and no doc tests required-features = ["rustc_tests"] [dependencies] -byteorder = { version = "1.1", features = ["i128"] } cargo_metadata = { version = "0.8", optional = true } directories = { version = "2.0", optional = true } rustc_version = { version = "0.2.3", optional = true } getrandom = { version = "0.1.8", features = ["std"] } +byteorder = "1.3" env_logger = "0.6" log = "0.4" shell-escape = "0.1.4" From fa20338c9aa4a64d984c61ae5f4332db89c78de1 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Thu, 12 Sep 2019 09:25:39 -0500 Subject: [PATCH 1102/3747] Use str::from_utf8 instead --- src/shims/mod.rs | 1 - tests/run-pass/aligned_utf8_check.rs | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/shims/mod.rs b/src/shims/mod.rs index 5b67d075a5c75..728634a7f6f66 100644 --- a/src/shims/mod.rs +++ b/src/shims/mod.rs @@ -1,4 +1,3 @@ - pub mod foreign_items; pub mod intrinsics; pub mod tls; diff --git a/tests/run-pass/aligned_utf8_check.rs b/tests/run-pass/aligned_utf8_check.rs index 0d2b2bf66a97c..202856b3bde9a 100644 --- a/tests/run-pass/aligned_utf8_check.rs +++ b/tests/run-pass/aligned_utf8_check.rs @@ -6,7 +6,7 @@ fn main() { let mut y: Vec = unsafe { std::mem::transmute(x) }; unsafe { y.set_len(2 * N) }; - println!("{:?}", String::from_utf8_lossy(&y)); + println!("{:?}", std::str::from_utf8(&y).unwrap()); let mut x: Vec = unsafe { std::mem::transmute(y) }; unsafe { x.set_len(N) }; From b245cb616e7ef75b6a1381d3b432e4e856922bd8 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 13 Sep 2019 10:39:36 +0200 Subject: [PATCH 1103/3747] factor ask-to-run-command into helper function --- src/bin/cargo-miri.rs | 62 +++++++++++++++++++------------------------ 1 file changed, 28 insertions(+), 34 deletions(-) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 8749e5b7eed93..43e8761d48c17 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -218,17 +218,28 @@ fn xargo_version() -> Option<(u32, u32, u32)> { Some((major, minor, patch)) } -fn ask(question: &str) { - let mut buf = String::new(); - print!("{} [Y/n] ", question); - io::stdout().flush().unwrap(); - io::stdin().read_line(&mut buf).unwrap(); - match buf.trim().to_lowercase().as_ref() { - // Proceed. - "" | "y" | "yes" => {}, - "n" | "no" => show_error(format!("Aborting as per your request")), - a => show_error(format!("I do not understand `{}`", a)) - }; +fn ask_to_run(mut cmd: Command, ask: bool, text: &str) { + if ask { + let mut buf = String::new(); + print!("I will run `{:?}` to {}. Proceed? [Y/n] ", cmd, text); + io::stdout().flush().unwrap(); + io::stdin().read_line(&mut buf).unwrap(); + match buf.trim().to_lowercase().as_ref() { + // Proceed. + "" | "y" | "yes" => {}, + "n" | "no" => show_error(format!("Aborting as per your request")), + a => show_error(format!("I do not understand `{}`", a)) + }; + } else { + println!("Running `{:?}` to {}.", cmd, text); + } + + if cmd.status() + .expect(&format!("failed to execute {:?}", cmd)) + .success().not() + { + show_error(format!("Failed to {}", text)); + } } /// Performs the setup required to make `cargo miri` work: Getting a custom-built libstd. Then sets @@ -244,18 +255,9 @@ fn setup(ask_user: bool) { // First, we need xargo. if xargo_version().map_or(true, |v| v < (0, 3, 16)) { - if ask_user { - ask("It seems you do not have a recent enough xargo installed. I will run `cargo install xargo -f`. Proceed?"); - } else { - println!("Installing xargo: `cargo install xargo -f`"); - } - - if cargo().args(&["install", "xargo", "-f"]).status() - .expect("failed to install xargo") - .success().not() - { - show_error(format!("Failed to install xargo")); - } + let mut cmd = cargo(); + cmd.args(&["install", "xargo", "-f"]); + ask_to_run(cmd, ask_user, "install a recent enough xargo"); } // Then, unless `XARGO_RUST_SRC` is set, we also need rust-src. @@ -267,17 +269,9 @@ fn setup(ask_user: bool) { let sysroot = std::str::from_utf8(&sysroot).unwrap(); let src = Path::new(sysroot.trim_end_matches('\n')).join("lib").join("rustlib").join("src"); if !src.exists() { - if ask_user { - ask("It seems you do not have the rust-src component installed. I will run `rustup component add rust-src` for the selected toolchain. Proceed?"); - } else { - println!("Installing rust-src component: `rustup component add rust-src`"); - } - if !Command::new("rustup").args(&["component", "add", "rust-src"]).status() - .expect("failed to install rust-src component") - .success() - { - show_error(format!("Failed to install rust-src component")); - } + let mut cmd = Command::new("rustup"); + cmd.args(&["component", "add", "rust-src"]); + ask_to_run(cmd, ask_user, "install the rustc-src component for the selected toolchain"); } } From 78cfdcead22482c1ac5d8fa408cfc673d5735c20 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 14 Sep 2019 13:05:39 +0200 Subject: [PATCH 1104/3747] temporarily enable backtrace feature --- rust-version | 2 +- src/bin/cargo-miri.rs | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/rust-version b/rust-version index 2e869d31de410..b0af10f44a94d 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -74d5c70b174f06843049af2d764ff57ddc81c81c +eb48d6bdee6c655d71f26594d47d232adf3e4e93 diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 8749e5b7eed93..7e92c51f8e647 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -294,7 +294,9 @@ fn setup(ask_user: bool) { default_features = false # We need the `panic_unwind` feature because we use the `unwind` panic strategy. # Using `abort` works for libstd, but then libtest will not compile. -features = ["panic_unwind"] +# FIXME: Temporarily enabling backtrace feature to work around +# . +features = ["panic_unwind", "backtrace"] [dependencies.test] "#).unwrap(); From 1fb934b6cf7bf7a7b62ef65f728a397e27507f18 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 14 Sep 2019 13:40:37 +0200 Subject: [PATCH 1105/3747] add CONTRIBUTING guide --- CONTRIBUTING.md | 141 ++++++++++++++++++++++++++++++++++++++++++++++++ README.md | 129 ++------------------------------------------ 2 files changed, 146 insertions(+), 124 deletions(-) create mode 100644 CONTRIBUTING.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000000000..83e2338552e99 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,141 @@ +# Contribution Guide + +If you want to hack on miri yourself, great! Here are some resources you might +find useful. + +## Getting started + +Check out the issues on this GitHub repository for some ideas. There's lots that +needs to be done that we haven't documented in the issues yet, however. For more +ideas or help with hacking on Miri, you can contact us (`oli-obk` and `RalfJ`) +on the [Rust Zulip]. + +[Rust Zulip]: https://rust-lang.zulipchat.com + +### Fixing Miri when rustc changes + +Miri is heavily tied to rustc internals, so it is very common that rustc changes +break Miri. Fixing those is a good way to get starting working on Miri. +Usually, Miri will require changes similar to the other consumers of the changed +rustc API, so reading the rustc PR diff is a good way to get an idea for what is +needed. + +When submitting a PR against Miri after fixing it for rustc changes, make sure +you update the `rust-version` file. That file always contains the exact rustc +git commit with which Miri works, and it is the version that our CI tests Miri +against. + +## Building Miri with a nightly rustc + +Miri heavily relies on internal rustc interfaces to execute MIR. Still, some +things (like adding support for a new intrinsic or a shim for an external +function being called) can be done by working just on the Miri side. + +To prepare, make sure you are using a nightly Rust compiler. Then you should be +able to just `cargo build` Miri. + +In case this fails, your nightly might be incompatible with Miri master. The +`rust-version` file contains the commit hash of rustc that Miri is currently +tested against; you can use that to find a nightly that works or you might have +to wait for the next nightly to get released. You can also use +[`rustup-toolchain-install-master`](https://github.com/kennytm/rustup-toolchain-install-master) +to install that exact version of rustc as a toolchain: +``` +rustup-toolchain-install-master $(cat rust-version) -c rust-src +``` + +Another common problem is outdated dependencies: Miri does not come with a +lockfile (it cannot, due to how it gets embedded into the rustc build). So you +have to run `cargo update` every now and then yourself to make sure you are +using the latest versions of everything (which is what gets tested on CI). + +## Testing the Miri driver +[testing-miri]: #testing-the-miri-driver + +The Miri driver in the `miri` binary is the "heart" of Miri: it is basically a +version of `rustc` that, instead of compiling your code, runs it. It accepts +all the same flags as `rustc` (though the ones only affecting code generation +and linking obviously will have no effect) [and more][miri-flags]. + +Running the Miri driver requires some fiddling with environment variables, so +the `miri` script helps you do that. For example, you can run the driver on a +particular file by doing + +```sh +./miri run tests/run-pass/format.rs +./miri run tests/run-pass/hello.rs --target i686-unknown-linux-gnu +``` + +and you can run the test suite using: + +``` +./miri test +``` + +`./miri test FILTER` only runs those tests that contain `FILTER` in their +filename (including the base directory, e.g. `./miri test fail` will run all +compile-fail tests). + +You can get a trace of which MIR statements are being executed by setting the +`MIRI_LOG` environment variable. For example: + +```sh +MIRI_LOG=info ./miri run tests/run-pass/vecs.rs +``` + +Setting `MIRI_LOG` like this will configure logging for Miri itself as well as +the `rustc::mir::interpret` and `rustc_mir::interpret` modules in rustc. You +can also do more targeted configuration, e.g. the following helps debug the +stacked borrows implementation: + +```sh +MIRI_LOG=rustc_mir::interpret=info,miri::stacked_borrows ./miri run tests/run-pass/vecs.rs +``` + +In addition, you can set `MIRI_BACKTRACE=1` to get a backtrace of where an +evaluation error was originally raised. + +## Testing `cargo miri` + +Working with the driver directly gives you full control, but you also lose all +the convenience provided by cargo. Once your test case depends on a crate, it +is probably easier to test it with the cargo wrapper. You can install your +development version of Miri using + +``` +./miri install +``` + +and then you can use it as if it was installed by `rustup`. Make sure you use +the same toolchain when calling `cargo miri` that you used when installing Miri! + +There's a test for the cargo wrapper in the `test-cargo-miri` directory; run +`./run-test.py` in there to execute it. + +## Building Miri with a locally built rustc + +A big part of the Miri driver lives in rustc, so working on Miri will sometimes +require using a locally built rustc. The bug you want to fix may actually be on +the rustc side, or you just need to get more detailed trace of the execution +than what is possible with release builds -- in both cases, you should develop +miri against a rustc you compiled yourself, with debug assertions (and hence +tracing) enabled. + +The setup for a local rustc works as follows: +```sh +git clone https://github.com/rust-lang/rust/ rustc +cd rustc +cp config.toml.example config.toml +# Now edit `config.toml` and set `debug-assertions = true`. +# This step can take 30 minutes and more. +./x.py build src/rustc +# If you change something, you can get a faster rebuild by doing +./x.py --keep-stage 0 build src/rustc +# You may have to change the architecture in the next command +rustup toolchain link custom build/x86_64-unknown-linux-gnu/stage2 +# Now cd to your Miri directory, then configure rustup +rustup override set custom +``` + +With this, you should now have a working development setup! See +[above][testing-miri] for how to proceed working with the Miri driver. diff --git a/README.md b/README.md index 7ae3c84517f95..0187047534d48 100644 --- a/README.md +++ b/README.md @@ -50,7 +50,7 @@ program, and cannot run all programs: [`copy_nonoverlapping`]: https://doc.rust-lang.org/stable/std/ptr/fn.copy_nonoverlapping.html -## Running Miri on your own project (and its test suite) +## Using Miri Install Miri via `rustup`: @@ -183,131 +183,12 @@ Moreover, Miri recognizes some environment variables: architecture to test against. `miri` and `cargo miri` accept the `--target` flag for the same purpose. -## Development and Debugging - -If you want to hack on miri yourself, great! Here are some resources you might -find useful. - -### Using a nightly rustc - -Miri heavily relies on internal rustc interfaces to execute MIR. Still, some -things (like adding support for a new intrinsic or a shim for an external -function being called) can be done by working just on the Miri side. - -To prepare, make sure you are using a nightly Rust compiler. Then you should be -able to just `cargo build` Miri. - -In case this fails, your nightly might be incompatible with Miri master. The -`rust-version` file contains the commit hash of rustc that Miri is currently -tested against; you can use that to find a nightly that works or you might have -to wait for the next nightly to get released. You can also use -[`rustup-toolchain-install-master`](https://github.com/kennytm/rustup-toolchain-install-master) -to install that exact version of rustc as a toolchain: -``` -rustup-toolchain-install-master $(cat rust-version) -c rust-src -``` - -Another common problem is outdated dependencies: Miri does not come with a -lockfile (it cannot, due to how it gets embedded into the rustc build). So you -have to run `cargo update` every now and then yourself to make sure you are -using the latest versions of everything (which is what gets tested on CI). - -### Testing the Miri driver -[testing-miri]: #testing-the-miri-driver - -The Miri driver in the `miri` binary is the "heart" of Miri: it is basically a -version of `rustc` that, instead of compiling your code, runs it. It accepts -all the same flags as `rustc` (though the ones only affecting code generation -and linking obviously will have no effect) [and more][miri-flags]. - -Running the Miri driver requires some fiddling with environment variables, so -the `miri` script helps you do that. For example, you can run the driver on a -particular file by doing - -```sh -./miri run tests/run-pass/format.rs -./miri run tests/run-pass/hello.rs --target i686-unknown-linux-gnu -``` - -and you can run the test suite using: - -``` -./miri test -``` - -`./miri test FILTER` only runs those tests that contain `FILTER` in their -filename (including the base directory, e.g. `./miri test fail` will run all -compile-fail tests). - -You can get a trace of which MIR statements are being executed by setting the -`MIRI_LOG` environment variable. For example: - -```sh -MIRI_LOG=info ./miri run tests/run-pass/vecs.rs -``` - -Setting `MIRI_LOG` like this will configure logging for Miri itself as well as -the `rustc::mir::interpret` and `rustc_mir::interpret` modules in rustc. You -can also do more targeted configuration, e.g. the following helps debug the -stacked borrows implementation: - -```sh -MIRI_LOG=rustc_mir::interpret=info,miri::stacked_borrows ./miri run tests/run-pass/vecs.rs -``` - -In addition, you can set `MIRI_BACKTRACE=1` to get a backtrace of where an -evaluation error was originally raised. - -### Testing `cargo miri` - -Working with the driver directly gives you full control, but you also lose all -the convenience provided by cargo. Once your test case depends on a crate, it -is probably easier to test it with the cargo wrapper. You can install your -development version of Miri using - -``` -./miri install -``` - -and then you can use it as if it was installed by `rustup`. Make sure you use -the same toolchain when calling `cargo miri` that you used when installing Miri! - -There's a test for the cargo wrapper in the `test-cargo-miri` directory; run -`./run-test.py` in there to execute it. - -### Using a locally built rustc - -A big part of the Miri driver lives in rustc, so working on Miri will sometimes -require using a locally built rustc. The bug you want to fix may actually be on -the rustc side, or you just need to get more detailed trace of the execution -than what is possible with release builds -- in both cases, you should develop -miri against a rustc you compiled yourself, with debug assertions (and hence -tracing) enabled. - -The setup for a local rustc works as follows: -```sh -git clone https://github.com/rust-lang/rust/ rustc -cd rustc -cp config.toml.example config.toml -# Now edit `config.toml` and set `debug-assertions = true`. -# This step can take 30 minutes and more. -./x.py build src/rustc -# If you change something, you can get a faster rebuild by doing -./x.py --keep-stage 0 build src/rustc -# You may have to change the architecture in the next command -rustup toolchain link custom build/x86_64-unknown-linux-gnu/stage2 -# Now cd to your Miri directory, then configure rustup -rustup override set custom -``` - -With this, you should now have a working development setup! See -[above][testing-miri] for how to proceed working with the Miri driver. - ## Contributing and getting help -Check out the issues on this GitHub repository for some ideas. There's lots that -needs to be done that I haven't documented in the issues yet, however. For more -ideas or help with running or hacking on Miri, you can open an issue here on +If you want to contribute to Miri, great! Please check out our +[contribution guide](CONTRIBUTING.md). + +For help with running Miri, you can open an issue here on GitHub or contact us (`oli-obk` and `RalfJ`) on the [Rust Zulip]. [Rust Zulip]: https://rust-lang.zulipchat.com From 5ecb2d93564f5674378f348635488410aba3cff5 Mon Sep 17 00:00:00 2001 From: Santiago Pastorino Date: Sat, 14 Sep 2019 01:01:37 -0300 Subject: [PATCH 1106/3747] Place projection field is now Box<[PlaceElem<'tcx>]> --- rust-version | 2 +- src/helpers.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/rust-version b/rust-version index b0af10f44a94d..60ef1e36f7046 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -eb48d6bdee6c655d71f26594d47d232adf3e4e93 +b35ebac96102cd12406d9d87827b0838d129c278 diff --git a/src/helpers.rs b/src/helpers.rs index 3eafb28b8949c..ad30040c2ddcc 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -71,7 +71,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// Get the `Place` for a local fn local_place(&mut self, local: mir::Local) -> InterpResult<'tcx, PlaceTy<'tcx, Tag>> { let this = self.eval_context_mut(); - let place = mir::Place { base: mir::PlaceBase::Local(local), projection: None }; + let place = mir::Place { base: mir::PlaceBase::Local(local), projection: Box::new([]) }; this.eval_place(&place) } From 1ef1d581d3900e34dd6db58f20322474dad71a54 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 15 Sep 2019 23:27:58 +0200 Subject: [PATCH 1107/3747] update for rustc changes --- rust-version | 2 +- src/bin/miri.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/rust-version b/rust-version index 60ef1e36f7046..07e965d7c39e8 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -b35ebac96102cd12406d9d87827b0838d129c278 +96d07e0ac9f0c56b95a2561c6cedac0b23a5d2a3 diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 6e4bf4a6c269e..7b3dbeacc48f2 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -211,7 +211,7 @@ fn main() { seed, args: miri_args, }; - let result = rustc_driver::report_ices_to_stderr_if_any(move || { + let result = rustc_driver::catch_fatal_errors(move || { rustc_driver::run_compiler(&rustc_args, &mut MiriCompilerCalls { miri_config }, None, None) }).and_then(|result| result); std::process::exit(result.is_err() as i32); From 9e2107cef59e3ca2f2c2687ec85533177de0a337 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 16 Sep 2019 09:31:56 +0200 Subject: [PATCH 1108/3747] install ICE hook --- src/bin/miri.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 7b3dbeacc48f2..dd56f0a6e53c4 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -211,6 +211,7 @@ fn main() { seed, args: miri_args, }; + rustc_driver::install_ice_hook(); let result = rustc_driver::catch_fatal_errors(move || { rustc_driver::run_compiler(&rustc_args, &mut MiriCompilerCalls { miri_config }, None, None) }).and_then(|result| result); From 55863cb88effdaa2198a22149cfae99c2377dd76 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Mon, 16 Sep 2019 10:16:06 -0500 Subject: [PATCH 1109/3747] Use force_ptr instead of assert_ptr --- src/shims/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shims/mod.rs b/src/shims/mod.rs index 728634a7f6f66..a0da364ff0b9c 100644 --- a/src/shims/mod.rs +++ b/src/shims/mod.rs @@ -29,7 +29,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if this.tcx.lang_items().align_offset_fn() == Some(instance.def.def_id()) { let n = { - let ptr = this.read_scalar(args[0])?.not_undef()?.assert_ptr(); + let ptr = this.force_ptr(this.read_scalar(args[0])?.not_undef()?)?; let align = this.force_bits( this.read_scalar(args[1])?.not_undef()?, this.pointer_size() From 8cd215dc9733defd7f73c3955bc21c63d8b3ed7e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 16 Sep 2019 22:22:54 +0200 Subject: [PATCH 1110/3747] remove libstd backtrace work-around --- rust-version | 2 +- src/bin/cargo-miri.rs | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/rust-version b/rust-version index 07e965d7c39e8..464b061edbd0f 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -96d07e0ac9f0c56b95a2561c6cedac0b23a5d2a3 +a44881d892fb4f4a8ed93f8f392bab942fac7a41 diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index d92fc344e8ada..43e8761d48c17 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -288,9 +288,7 @@ fn setup(ask_user: bool) { default_features = false # We need the `panic_unwind` feature because we use the `unwind` panic strategy. # Using `abort` works for libstd, but then libtest will not compile. -# FIXME: Temporarily enabling backtrace feature to work around -# . -features = ["panic_unwind", "backtrace"] +features = ["panic_unwind"] [dependencies.test] "#).unwrap(); From 130f9488d3b861e02c9282b686eec717e30912cf Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 17 Sep 2019 12:30:14 +0200 Subject: [PATCH 1111/3747] rustup --- src/machine.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/machine.rs b/src/machine.rs index 95cb31d67b8f5..340dd109e1249 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -287,7 +287,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { (Some(stacks), base_tag) }; let mut stacked_borrows = memory_extra.stacked_borrows.borrow_mut(); - let alloc: Allocation = alloc.retag( + let alloc: Allocation = alloc.with_tags_and_extra( |alloc| if !memory_extra.validate { Tag::Untagged } else { From 881929f7537d6fd5b85f6c8efc1dc0f3f558591f Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Mon, 16 Sep 2019 13:46:37 -0500 Subject: [PATCH 1112/3747] Add align_offset for integers --- src/shims/mod.rs | 49 +++++++++++++++++++++++++++++------------------- 1 file changed, 30 insertions(+), 19 deletions(-) diff --git a/src/shims/mod.rs b/src/shims/mod.rs index a0da364ff0b9c..f9b89cf553a39 100644 --- a/src/shims/mod.rs +++ b/src/shims/mod.rs @@ -27,25 +27,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // There are some more lang items we want to hook that CTFE does not hook (yet). if this.tcx.lang_items().align_offset_fn() == Some(instance.def.def_id()) { - - let n = { - let ptr = this.force_ptr(this.read_scalar(args[0])?.not_undef()?)?; - let align = this.force_bits( - this.read_scalar(args[1])?.not_undef()?, - this.pointer_size() - )? as usize; - - let stride = this.memory().get(ptr.alloc_id)?.align.bytes() as usize; - // if the allocation alignment is at least the required alignment, we use the - // libcore implementation - if stride >= align { - ((stride + ptr.offset.bytes() as usize) as *const ()) - .align_offset(align) as u128 - } else { - u128::max_value() - } - }; - + let n = this.align_offset(args[0], args[1])?; let dest = dest.unwrap(); let n = this.truncate(n, dest.layout); this.write_scalar(Scalar::from_uint(n, dest.layout.size), dest)?; @@ -65,4 +47,33 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Otherwise, load the MIR. Ok(Some(this.load_mir(instance.def, None)?)) } + + fn align_offset( + &mut self, + ptr_op: OpTy<'tcx, Tag>, + align_op: OpTy<'tcx, Tag> + ) -> InterpResult<'tcx, u128> { + let this = self.eval_context_mut(); + + let req_align = this.force_bits( + this.read_scalar(align_op)?.not_undef()?, + this.pointer_size() + )? as usize; + + let ptr_scalar = this.read_scalar(ptr_op)?.not_undef()?; + + if let Scalar::Ptr(ptr) = ptr_scalar { + let cur_align = this.memory().get(ptr.alloc_id)?.align.bytes() as usize; + if cur_align < req_align { + return Ok(u128::max_value()); + } + } + + // if the allocation alignment is at least the required alignment or if the pointer is an + // integer, we use the libcore implementation + Ok( + (this.force_bits(ptr_scalar, this.pointer_size())? as *const i8) + .align_offset(req_align) as u128 + ) + } } From 497de53825728382dad498239b8dd8e871d26c45 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Tue, 17 Sep 2019 11:47:36 -0500 Subject: [PATCH 1113/3747] Update align_offset tests --- tests/run-pass/aligned_utf8_check.rs | 13 +++---------- tests/run-pass/aligned_utf8_check.stdout | 2 +- tests/run-pass/integer_align_offset.rs | 3 +++ 3 files changed, 7 insertions(+), 11 deletions(-) create mode 100644 tests/run-pass/integer_align_offset.rs diff --git a/tests/run-pass/aligned_utf8_check.rs b/tests/run-pass/aligned_utf8_check.rs index 202856b3bde9a..6c6ff6b6173cb 100644 --- a/tests/run-pass/aligned_utf8_check.rs +++ b/tests/run-pass/aligned_utf8_check.rs @@ -1,13 +1,6 @@ fn main() { const N: usize = 10; - - let x = vec![0x4141u16; N]; - - let mut y: Vec = unsafe { std::mem::transmute(x) }; - unsafe { y.set_len(2 * N) }; - - println!("{:?}", std::str::from_utf8(&y).unwrap()); - - let mut x: Vec = unsafe { std::mem::transmute(y) }; - unsafe { x.set_len(N) }; + let vec = vec![0x4141414141414141u64; N]; + let content = unsafe { std::slice::from_raw_parts(vec.as_ptr() as *const u8, 8 * N) }; + println!("{:?}", std::str::from_utf8(content).unwrap()); } diff --git a/tests/run-pass/aligned_utf8_check.stdout b/tests/run-pass/aligned_utf8_check.stdout index 8d08312cac7b5..66d4399481596 100644 --- a/tests/run-pass/aligned_utf8_check.stdout +++ b/tests/run-pass/aligned_utf8_check.stdout @@ -1 +1 @@ -"AAAAAAAAAAAAAAAAAAAA" +"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA" diff --git a/tests/run-pass/integer_align_offset.rs b/tests/run-pass/integer_align_offset.rs new file mode 100644 index 0000000000000..971c19b0576ef --- /dev/null +++ b/tests/run-pass/integer_align_offset.rs @@ -0,0 +1,3 @@ +fn main() { + assert_eq!(2, (2 as *const i8).align_offset(4)); +} From 4a0b7446cf143f1ab4f2368623de25bc563fb2e3 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Tue, 17 Sep 2019 13:26:12 -0500 Subject: [PATCH 1114/3747] Move truncation from the main branch --- src/shims/mod.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/shims/mod.rs b/src/shims/mod.rs index f9b89cf553a39..eea23b6de4e60 100644 --- a/src/shims/mod.rs +++ b/src/shims/mod.rs @@ -27,9 +27,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // There are some more lang items we want to hook that CTFE does not hook (yet). if this.tcx.lang_items().align_offset_fn() == Some(instance.def.def_id()) { - let n = this.align_offset(args[0], args[1])?; let dest = dest.unwrap(); - let n = this.truncate(n, dest.layout); + let n = this.align_offset(args[0], args[1], dest.layout)?; this.write_scalar(Scalar::from_uint(n, dest.layout.size), dest)?; this.goto_block(ret)?; return Ok(None); @@ -51,7 +50,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn align_offset( &mut self, ptr_op: OpTy<'tcx, Tag>, - align_op: OpTy<'tcx, Tag> + align_op: OpTy<'tcx, Tag>, + layout: ty::layout::TyLayout<'tcx>, ) -> InterpResult<'tcx, u128> { let this = self.eval_context_mut(); @@ -65,7 +65,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if let Scalar::Ptr(ptr) = ptr_scalar { let cur_align = this.memory().get(ptr.alloc_id)?.align.bytes() as usize; if cur_align < req_align { - return Ok(u128::max_value()); + return Ok(this.truncate(u128::max_value(), layout)); } } From d610d9de9092d3607f68bb98bee671ca08edc3ca Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 18 Sep 2019 11:22:28 +0200 Subject: [PATCH 1115/3747] bump Rust version --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 464b061edbd0f..5081720aed443 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -a44881d892fb4f4a8ed93f8f392bab942fac7a41 +64c09694a6ecc434cd3a61ade89beb1de17770c5 From 5cf90bc7866cd8f24178f2696e4fcbb7bfad0171 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Wed, 18 Sep 2019 16:10:13 -0500 Subject: [PATCH 1116/3747] Add getcwd shim --- src/shims/env.rs | 28 +++++++++++++++++++++++++++- src/shims/foreign_items.rs | 5 +++++ 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/src/shims/env.rs b/src/shims/env.rs index 1cffc60bc40a1..73627086e0b6f 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -1,4 +1,5 @@ use std::collections::HashMap; +use std::env; use rustc::ty::layout::{Size}; use rustc_mir::interpret::{Pointer, Memory}; @@ -21,7 +22,7 @@ impl EnvVars { excluded_env_vars.push("TERM".to_owned()); if ecx.machine.communicate { - for (name, value) in std::env::vars() { + for (name, value) in env::vars() { if !excluded_env_vars.contains(&name) { let var_ptr = alloc_env_var(name.as_bytes(), value.as_bytes(), ecx.memory_mut()); ecx.machine.env_vars.map.insert(name.into_bytes(), var_ptr); @@ -111,4 +112,29 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(-1) } } + + fn getcwd( + &mut self, + buf_op: OpTy<'tcx, Tag>, + size_op: OpTy<'tcx, Tag>, + ) -> InterpResult<'tcx, Scalar> { + let this = self.eval_context_mut(); + let tcx = &{this.tcx.tcx}; + + let buf = this.force_ptr(this.read_scalar(buf_op)?.not_undef()?)?; + let size = this.read_scalar(size_op)?.to_usize(&*this.tcx)?; + // If we cannot get the current directory, we return null + if let Ok(cwd) = env::current_dir() { + // It is not clear what happens with non-utf8 paths here + let mut bytes = cwd.display().to_string().into_bytes(); + // If the buffer is smaller than the path, we return null + if bytes.len() as u64 <= size { + // We need `size` bytes exactly + bytes.resize(size as usize, 0); + this.memory_mut().get_mut(buf.alloc_id)?.write_bytes(tcx, buf, &bytes)?; + return Ok(Scalar::Ptr(buf)) + } + } + Ok(Scalar::ptr_null(&*this.tcx)) + } } diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 90c18265fcf7c..45f167bea582d 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -436,6 +436,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; } + "getcwd" => { + let result = this.getcwd(args[0], args[1])?; + this.write_scalar(result, dest)?; + } + "write" => { let fd = this.read_scalar(args[0])?.to_i32()?; let buf = this.read_scalar(args[1])?.not_undef()?; From 6593563e46d025aa0eb7a12a34085b7337b62c5b Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Wed, 18 Sep 2019 16:46:41 -0500 Subject: [PATCH 1117/3747] Check that getcwd does not error --- tests/run-pass/get_current_dir.rs | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 tests/run-pass/get_current_dir.rs diff --git a/tests/run-pass/get_current_dir.rs b/tests/run-pass/get_current_dir.rs new file mode 100644 index 0000000000000..d8e6c225e9657 --- /dev/null +++ b/tests/run-pass/get_current_dir.rs @@ -0,0 +1,5 @@ +// ignore-windows: TODO the windows hook is not done yet + +fn main() { + std::env::current_dir().unwrap(); +} From 133c2b39db73843e6a5ee0bce325cca034012579 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Thu, 19 Sep 2019 10:32:18 -0500 Subject: [PATCH 1118/3747] Only use getcwd without isolation --- src/shims/env.rs | 32 +++++++++++++++++-------------- tests/run-pass/get_current_dir.rs | 1 + 2 files changed, 19 insertions(+), 14 deletions(-) diff --git a/src/shims/env.rs b/src/shims/env.rs index 73627086e0b6f..debeab894d456 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -119,22 +119,26 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx size_op: OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); - let tcx = &{this.tcx.tcx}; - let buf = this.force_ptr(this.read_scalar(buf_op)?.not_undef()?)?; - let size = this.read_scalar(size_op)?.to_usize(&*this.tcx)?; - // If we cannot get the current directory, we return null - if let Ok(cwd) = env::current_dir() { - // It is not clear what happens with non-utf8 paths here - let mut bytes = cwd.display().to_string().into_bytes(); - // If the buffer is smaller than the path, we return null - if bytes.len() as u64 <= size { - // We need `size` bytes exactly - bytes.resize(size as usize, 0); - this.memory_mut().get_mut(buf.alloc_id)?.write_bytes(tcx, buf, &bytes)?; - return Ok(Scalar::Ptr(buf)) + if this.machine.communicate { + let tcx = &{this.tcx.tcx}; + + let buf = this.force_ptr(this.read_scalar(buf_op)?.not_undef()?)?; + let size = this.read_scalar(size_op)?.to_usize(&*this.tcx)?; + // If we cannot get the current directory, we return null + if let Ok(cwd) = env::current_dir() { + // It is not clear what happens with non-utf8 paths here + let mut bytes = cwd.display().to_string().into_bytes(); + // If the buffer is smaller than the path, we return null + if bytes.len() as u64 <= size { + // We need `size` bytes exactly + bytes.resize(size as usize, 0); + this.memory_mut().get_mut(buf.alloc_id)?.write_bytes(tcx, buf, &bytes)?; + return Ok(Scalar::Ptr(buf)) + } } + return Ok(Scalar::ptr_null(&*this.tcx)); } - Ok(Scalar::ptr_null(&*this.tcx)) + throw_unsup_format!("Function not available when isolation is enabled") } } diff --git a/tests/run-pass/get_current_dir.rs b/tests/run-pass/get_current_dir.rs index d8e6c225e9657..45efd06d3f670 100644 --- a/tests/run-pass/get_current_dir.rs +++ b/tests/run-pass/get_current_dir.rs @@ -1,4 +1,5 @@ // ignore-windows: TODO the windows hook is not done yet +// compile-flags: -Zmiri-disable-isolation fn main() { std::env::current_dir().unwrap(); From 7e65c44714b3afe4ba2a1d70853c9cbbabbf74a0 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 10 Aug 2019 15:10:11 +0200 Subject: [PATCH 1119/3747] test for niche enum discriminant computation that overflows --- tests/run-pass/enums.rs | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/tests/run-pass/enums.rs b/tests/run-pass/enums.rs index 1f27292904f42..73172d6bbd2f6 100644 --- a/tests/run-pass/enums.rs +++ b/tests/run-pass/enums.rs @@ -23,6 +23,28 @@ fn test(me: MyEnum) { } } +fn discriminant_overflow() { + // Tests for https://github.com/rust-lang/rust/issues/62138. + #[repr(u8)] + #[allow(dead_code)] + enum WithWraparoundInvalidValues { + X = 1, + Y = 254, + } + + #[allow(dead_code)] + enum Foo { + A, + B, + C(WithWraparoundInvalidValues), + } + + let x = Foo::B; + if let Foo::C(_) = x { + panic!(); + } +} + fn main() { test(MyEnum::MyEmptyVariant); test(MyEnum::MyNewtypeVariant(42)); @@ -31,4 +53,6 @@ fn main() { my_first_field: 45, my_second_field: 46, }); + + discriminant_overflow(); } From d53d7f77a0edf8d74b0c2483b0aa5d65964a2889 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 10 Aug 2019 18:38:41 +0200 Subject: [PATCH 1120/3747] err on all-but-B, not just on C --- tests/run-pass/enums.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/run-pass/enums.rs b/tests/run-pass/enums.rs index 73172d6bbd2f6..dab3e873668b9 100644 --- a/tests/run-pass/enums.rs +++ b/tests/run-pass/enums.rs @@ -40,8 +40,9 @@ fn discriminant_overflow() { } let x = Foo::B; - if let Foo::C(_) = x { - panic!(); + match x { + Foo::B => {}, + _ => panic!(), } } From 0ab0e40e1b15278c34b10d23603de98c3a27f1b2 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 16 Sep 2019 15:04:42 +0200 Subject: [PATCH 1121/3747] add another test case --- tests/run-pass/enums.rs | 76 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) diff --git a/tests/run-pass/enums.rs b/tests/run-pass/enums.rs index dab3e873668b9..39bf567076c47 100644 --- a/tests/run-pass/enums.rs +++ b/tests/run-pass/enums.rs @@ -46,6 +46,81 @@ fn discriminant_overflow() { } } +fn more_discriminant_overflow() { + pub enum Infallible {} + + // The check that the `bool` field of `V1` is encoding a "niche variant" + // (i.e. not `V1`, so `V3` or `V4`) used to be mathematically incorrect, + // causing valid `V1` values to be interpreted as other variants. + #[allow(dead_code)] + pub enum E1 { + V1 { f: bool }, + V2 { f: Infallible }, + V3, + V4, + } + + // Computing the discriminant used to be done using the niche type (here `u8`, + // from the `bool` field of `V1`), overflowing for variants with large enough + // indices (`V3` and `V4`), causing them to be interpreted as other variants. + #[allow(dead_code)] + pub enum E2 { + V1 { f: bool }, + + /*_00*/ _01(X), _02(X), _03(X), _04(X), _05(X), _06(X), _07(X), + _08(X), _09(X), _0A(X), _0B(X), _0C(X), _0D(X), _0E(X), _0F(X), + _10(X), _11(X), _12(X), _13(X), _14(X), _15(X), _16(X), _17(X), + _18(X), _19(X), _1A(X), _1B(X), _1C(X), _1D(X), _1E(X), _1F(X), + _20(X), _21(X), _22(X), _23(X), _24(X), _25(X), _26(X), _27(X), + _28(X), _29(X), _2A(X), _2B(X), _2C(X), _2D(X), _2E(X), _2F(X), + _30(X), _31(X), _32(X), _33(X), _34(X), _35(X), _36(X), _37(X), + _38(X), _39(X), _3A(X), _3B(X), _3C(X), _3D(X), _3E(X), _3F(X), + _40(X), _41(X), _42(X), _43(X), _44(X), _45(X), _46(X), _47(X), + _48(X), _49(X), _4A(X), _4B(X), _4C(X), _4D(X), _4E(X), _4F(X), + _50(X), _51(X), _52(X), _53(X), _54(X), _55(X), _56(X), _57(X), + _58(X), _59(X), _5A(X), _5B(X), _5C(X), _5D(X), _5E(X), _5F(X), + _60(X), _61(X), _62(X), _63(X), _64(X), _65(X), _66(X), _67(X), + _68(X), _69(X), _6A(X), _6B(X), _6C(X), _6D(X), _6E(X), _6F(X), + _70(X), _71(X), _72(X), _73(X), _74(X), _75(X), _76(X), _77(X), + _78(X), _79(X), _7A(X), _7B(X), _7C(X), _7D(X), _7E(X), _7F(X), + _80(X), _81(X), _82(X), _83(X), _84(X), _85(X), _86(X), _87(X), + _88(X), _89(X), _8A(X), _8B(X), _8C(X), _8D(X), _8E(X), _8F(X), + _90(X), _91(X), _92(X), _93(X), _94(X), _95(X), _96(X), _97(X), + _98(X), _99(X), _9A(X), _9B(X), _9C(X), _9D(X), _9E(X), _9F(X), + _A0(X), _A1(X), _A2(X), _A3(X), _A4(X), _A5(X), _A6(X), _A7(X), + _A8(X), _A9(X), _AA(X), _AB(X), _AC(X), _AD(X), _AE(X), _AF(X), + _B0(X), _B1(X), _B2(X), _B3(X), _B4(X), _B5(X), _B6(X), _B7(X), + _B8(X), _B9(X), _BA(X), _BB(X), _BC(X), _BD(X), _BE(X), _BF(X), + _C0(X), _C1(X), _C2(X), _C3(X), _C4(X), _C5(X), _C6(X), _C7(X), + _C8(X), _C9(X), _CA(X), _CB(X), _CC(X), _CD(X), _CE(X), _CF(X), + _D0(X), _D1(X), _D2(X), _D3(X), _D4(X), _D5(X), _D6(X), _D7(X), + _D8(X), _D9(X), _DA(X), _DB(X), _DC(X), _DD(X), _DE(X), _DF(X), + _E0(X), _E1(X), _E2(X), _E3(X), _E4(X), _E5(X), _E6(X), _E7(X), + _E8(X), _E9(X), _EA(X), _EB(X), _EC(X), _ED(X), _EE(X), _EF(X), + _F0(X), _F1(X), _F2(X), _F3(X), _F4(X), _F5(X), _F6(X), _F7(X), + _F8(X), _F9(X), _FA(X), _FB(X), _FC(X), _FD(X), _FE(X), _FF(X), + + V3, + V4, + } + + if let E1::V2 { .. } = (E1::V1 { f: true }) { + unreachable!() + } + if let E1::V1 { .. } = (E1::V1 { f: true }) { + } else { + unreachable!() + } + + if let E2::V1 { .. } = E2::V3:: { + unreachable!() + } + if let E2::V3 { .. } = E2::V3:: { + } else { + unreachable!() + } +} + fn main() { test(MyEnum::MyEmptyVariant); test(MyEnum::MyNewtypeVariant(42)); @@ -56,4 +131,5 @@ fn main() { }); discriminant_overflow(); + more_discriminant_overflow(); } From a86ca2452627d19289b076ea8f1762d6d7d77cd9 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 20 Sep 2019 08:55:12 +0200 Subject: [PATCH 1122/3747] bump Rust --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 5081720aed443..60dae7291d636 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -64c09694a6ecc434cd3a61ade89beb1de17770c5 +ea3ba36f3f4b7f0168a27d23c499efeb2304e2d5 From 49275d42690318e410f65e3a38d04f2c4ccfbd0c Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Fri, 20 Sep 2019 02:13:48 -0500 Subject: [PATCH 1123/3747] Avoid writing more bytes than necessary --- src/shims/env.rs | 38 +++++++++++++++++++++----------------- 1 file changed, 21 insertions(+), 17 deletions(-) diff --git a/src/shims/env.rs b/src/shims/env.rs index debeab894d456..5e81b94e69977 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -120,25 +120,29 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); - if this.machine.communicate { - let tcx = &{this.tcx.tcx}; + if !this.machine.communicate { + throw_unsup_format!("Function not available when isolation is enabled") + } - let buf = this.force_ptr(this.read_scalar(buf_op)?.not_undef()?)?; - let size = this.read_scalar(size_op)?.to_usize(&*this.tcx)?; - // If we cannot get the current directory, we return null - if let Ok(cwd) = env::current_dir() { - // It is not clear what happens with non-utf8 paths here - let mut bytes = cwd.display().to_string().into_bytes(); - // If the buffer is smaller than the path, we return null - if bytes.len() as u64 <= size { - // We need `size` bytes exactly - bytes.resize(size as usize, 0); - this.memory_mut().get_mut(buf.alloc_id)?.write_bytes(tcx, buf, &bytes)?; - return Ok(Scalar::Ptr(buf)) - } + let tcx = &{this.tcx.tcx}; + + let buf = this.force_ptr(this.read_scalar(buf_op)?.not_undef()?)?; + let size = this.read_scalar(size_op)?.to_usize(&*this.tcx)?; + // If we cannot get the current directory, we return null + // FIXME: Technically we have to set the `errno` global too + if let Ok(cwd) = env::current_dir() { + // It is not clear what happens with non-utf8 paths here + let mut bytes = cwd.display().to_string().into_bytes(); + // If the buffer is smaller or equal than the path, we return null. + // FIXME: Technically we have to set the `errno` global too + if (bytes.len() as u64) < size { + // We add a `/0` terminator + bytes.push(0); + // This is ok because the buffer is larger than the path with the null terminator. + this.memory_mut().get_mut(buf.alloc_id)?.write_bytes(tcx, buf, &bytes)?; + return Ok(Scalar::Ptr(buf)) } - return Ok(Scalar::ptr_null(&*this.tcx)); } - throw_unsup_format!("Function not available when isolation is enabled") + Ok(Scalar::ptr_null(&*this.tcx)) } } From c0a6b5ff69580325e590d1062570be16c0a93f14 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Fri, 20 Sep 2019 03:30:55 -0500 Subject: [PATCH 1124/3747] Set errno when getcwd fails --- src/shims/env.rs | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/src/shims/env.rs b/src/shims/env.rs index 5e81b94e69977..d766d8f0c1a69 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -130,18 +130,21 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let size = this.read_scalar(size_op)?.to_usize(&*this.tcx)?; // If we cannot get the current directory, we return null // FIXME: Technically we have to set the `errno` global too - if let Ok(cwd) = env::current_dir() { - // It is not clear what happens with non-utf8 paths here - let mut bytes = cwd.display().to_string().into_bytes(); - // If the buffer is smaller or equal than the path, we return null. - // FIXME: Technically we have to set the `errno` global too - if (bytes.len() as u64) < size { - // We add a `/0` terminator - bytes.push(0); - // This is ok because the buffer is larger than the path with the null terminator. - this.memory_mut().get_mut(buf.alloc_id)?.write_bytes(tcx, buf, &bytes)?; - return Ok(Scalar::Ptr(buf)) + match env::current_dir() { + Ok(cwd) =>{ + // It is not clear what happens with non-utf8 paths here + let mut bytes = cwd.display().to_string().into_bytes(); + // If the buffer is smaller or equal than the path, we return null. + if (bytes.len() as u64) < size { + // We add a `/0` terminator + bytes.push(0); + // This is ok because the buffer is larger than the path with the null terminator. + this.memory_mut().get_mut(buf.alloc_id)?.write_bytes(tcx, buf, &bytes)?; + return Ok(Scalar::Ptr(buf)) + } + this.machine.last_error = 34; // ERANGE } + Err(e) => this.machine.last_error = e.raw_os_error().unwrap() as u32, } Ok(Scalar::ptr_null(&*this.tcx)) } From 0f58289b3d799e04aa2b0027c4a7ff571c7a7511 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Fri, 20 Sep 2019 10:25:43 -0500 Subject: [PATCH 1125/3747] fetch ERANGE value from libc --- src/shims/env.rs | 42 +++++++++++++++++++++++------------------- 1 file changed, 23 insertions(+), 19 deletions(-) diff --git a/src/shims/env.rs b/src/shims/env.rs index d766d8f0c1a69..784df0a50fb0c 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -1,10 +1,10 @@ use std::collections::HashMap; use std::env; -use rustc::ty::layout::{Size}; -use rustc_mir::interpret::{Pointer, Memory}; use crate::stacked_borrows::Tag; use crate::*; +use rustc::ty::layout::Size; +use rustc_mir::interpret::{Memory, Pointer}; #[derive(Default)] pub struct EnvVars { @@ -24,7 +24,8 @@ impl EnvVars { if ecx.machine.communicate { for (name, value) in env::vars() { if !excluded_env_vars.contains(&name) { - let var_ptr = alloc_env_var(name.as_bytes(), value.as_bytes(), ecx.memory_mut()); + let var_ptr = + alloc_env_var(name.as_bytes(), value.as_bytes(), ecx.memory_mut()); ecx.machine.env_vars.map.insert(name.into_bytes(), var_ptr); } } @@ -46,17 +47,16 @@ fn alloc_env_var<'mir, 'tcx>( impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { - fn getenv( - &mut self, - name_op: OpTy<'tcx, Tag>, - ) -> InterpResult<'tcx, Scalar> { + fn getenv(&mut self, name_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); let name_ptr = this.read_scalar(name_op)?.not_undef()?; let name = this.memory().read_c_str(name_ptr)?; Ok(match this.machine.env_vars.map.get(name) { // The offset is used to strip the "{name}=" part of the string. - Some(var_ptr) => Scalar::Ptr(var_ptr.offset(Size::from_bytes(name.len() as u64 + 1), this)?), + Some(var_ptr) => { + Scalar::Ptr(var_ptr.offset(Size::from_bytes(name.len() as u64 + 1), this)?) + } None => Scalar::ptr_null(&*this.tcx), }) } @@ -81,7 +81,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if let Some((name, value)) = new { let var_ptr = alloc_env_var(&name, &value, this.memory_mut()); if let Some(var) = this.machine.env_vars.map.insert(name.to_owned(), var_ptr) { - this.memory_mut().deallocate(var, None, MiriMemoryKind::Env.into())?; + this.memory_mut() + .deallocate(var, None, MiriMemoryKind::Env.into())?; } Ok(0) } else { @@ -89,10 +90,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } - fn unsetenv( - &mut self, - name_op: OpTy<'tcx, Tag>, - ) -> InterpResult<'tcx, i32> { + fn unsetenv(&mut self, name_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); let name_ptr = this.read_scalar(name_op)?.not_undef()?; @@ -105,7 +103,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } if let Some(old) = success { if let Some(var) = old { - this.memory_mut().deallocate(var, None, MiriMemoryKind::Env.into())?; + this.memory_mut() + .deallocate(var, None, MiriMemoryKind::Env.into())?; } Ok(0) } else { @@ -124,14 +123,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx throw_unsup_format!("Function not available when isolation is enabled") } - let tcx = &{this.tcx.tcx}; + let tcx = &{ this.tcx.tcx }; let buf = this.force_ptr(this.read_scalar(buf_op)?.not_undef()?)?; let size = this.read_scalar(size_op)?.to_usize(&*this.tcx)?; // If we cannot get the current directory, we return null // FIXME: Technically we have to set the `errno` global too match env::current_dir() { - Ok(cwd) =>{ + Ok(cwd) => { // It is not clear what happens with non-utf8 paths here let mut bytes = cwd.display().to_string().into_bytes(); // If the buffer is smaller or equal than the path, we return null. @@ -139,10 +138,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // We add a `/0` terminator bytes.push(0); // This is ok because the buffer is larger than the path with the null terminator. - this.memory_mut().get_mut(buf.alloc_id)?.write_bytes(tcx, buf, &bytes)?; - return Ok(Scalar::Ptr(buf)) + this.memory_mut() + .get_mut(buf.alloc_id)? + .write_bytes(tcx, buf, &bytes)?; + return Ok(Scalar::Ptr(buf)); } - this.machine.last_error = 34; // ERANGE + this.machine.last_error = this + .eval_path_scalar(&["libc", "ERANGE"])? + .unwrap() + .to_u32()?; } Err(e) => this.machine.last_error = e.raw_os_error().unwrap() as u32, } From f7366360383f6df430fb5dc7145f4ce8cab5f5e6 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Tue, 17 Sep 2019 13:42:04 -0500 Subject: [PATCH 1126/3747] Throw unsupported error when alignment is not a power of two --- src/shims/mod.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/shims/mod.rs b/src/shims/mod.rs index eea23b6de4e60..0b5bd7ae5cf0d 100644 --- a/src/shims/mod.rs +++ b/src/shims/mod.rs @@ -60,6 +60,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.pointer_size() )? as usize; + // FIXME: This should actually panic in the interpreted program + if !req_align.is_power_of_two() { + throw_unsup_format!("Required alignment should always be a power of two") + } + let ptr_scalar = this.read_scalar(ptr_op)?.not_undef()?; if let Scalar::Ptr(ptr) = ptr_scalar { From e2c54e64d141c8524ff9e4753f9b8acde3859351 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Sun, 22 Sep 2019 21:39:17 -0500 Subject: [PATCH 1127/3747] Ignore integers --- src/shims/mod.rs | 42 +++++++++++++++----------- tests/run-pass/integer_align_offset.rs | 3 -- 2 files changed, 24 insertions(+), 21 deletions(-) delete mode 100644 tests/run-pass/integer_align_offset.rs diff --git a/src/shims/mod.rs b/src/shims/mod.rs index 0b5bd7ae5cf0d..4ccdbdc0d7c31 100644 --- a/src/shims/mod.rs +++ b/src/shims/mod.rs @@ -1,10 +1,10 @@ +pub mod dlsym; +pub mod env; pub mod foreign_items; pub mod intrinsics; pub mod tls; -pub mod dlsym; -pub mod env; -use rustc::{ty, mir}; +use rustc::{mir, ty}; use crate::*; @@ -18,7 +18,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ret: Option, ) -> InterpResult<'tcx, Option<&'mir mir::Body<'tcx>>> { let this = self.eval_context_mut(); - trace!("eval_fn_call: {:#?}, {:?}", instance, dest.map(|place| *place)); + trace!( + "eval_fn_call: {:#?}, {:?}", + instance, + dest.map(|place| *place) + ); // First, run the common hooks also supported by CTFE. if this.hook_fn(instance, args, dest)? { @@ -28,7 +32,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // There are some more lang items we want to hook that CTFE does not hook (yet). if this.tcx.lang_items().align_offset_fn() == Some(instance.def.def_id()) { let dest = dest.unwrap(); - let n = this.align_offset(args[0], args[1], dest.layout)?; + let n = this + .align_offset(args[0], args[1])? + .unwrap_or_else(|| this.truncate(u128::max_value(), dest.layout)); this.write_scalar(Scalar::from_uint(n, dest.layout.size), dest)?; this.goto_block(ret)?; return Ok(None); @@ -51,13 +57,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx &mut self, ptr_op: OpTy<'tcx, Tag>, align_op: OpTy<'tcx, Tag>, - layout: ty::layout::TyLayout<'tcx>, - ) -> InterpResult<'tcx, u128> { + ) -> InterpResult<'tcx, Option> { let this = self.eval_context_mut(); let req_align = this.force_bits( this.read_scalar(align_op)?.not_undef()?, - this.pointer_size() + this.pointer_size(), )? as usize; // FIXME: This should actually panic in the interpreted program @@ -67,18 +72,19 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let ptr_scalar = this.read_scalar(ptr_op)?.not_undef()?; - if let Scalar::Ptr(ptr) = ptr_scalar { + if let Ok(ptr) = this.force_ptr(ptr_scalar) { let cur_align = this.memory().get(ptr.alloc_id)?.align.bytes() as usize; - if cur_align < req_align { - return Ok(this.truncate(u128::max_value(), layout)); + if cur_align >= req_align { + // if the allocation alignment is at least the required alignment we use the + // libcore implementation + return Ok(Some( + (this.force_bits(ptr_scalar, this.pointer_size())? as *const i8) + .align_offset(req_align) as u128, + )); } } - - // if the allocation alignment is at least the required alignment or if the pointer is an - // integer, we use the libcore implementation - Ok( - (this.force_bits(ptr_scalar, this.pointer_size())? as *const i8) - .align_offset(req_align) as u128 - ) + // If the allocation alignment is smaller than then required alignment or the pointer was + // actually an integer, we return `None` + Ok(None) } } diff --git a/tests/run-pass/integer_align_offset.rs b/tests/run-pass/integer_align_offset.rs deleted file mode 100644 index 971c19b0576ef..0000000000000 --- a/tests/run-pass/integer_align_offset.rs +++ /dev/null @@ -1,3 +0,0 @@ -fn main() { - assert_eq!(2, (2 as *const i8).align_offset(4)); -} From 02261e4be2c5c8d569ac98f6d7c7623c6d26fe47 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Tue, 24 Sep 2019 09:29:16 -0500 Subject: [PATCH 1128/3747] Fix comments --- src/shims/env.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/shims/env.rs b/src/shims/env.rs index 784df0a50fb0c..e2a9452045eaf 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -120,7 +120,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); if !this.machine.communicate { - throw_unsup_format!("Function not available when isolation is enabled") + throw_unsup_format!("`getcwd` not available when isolation is enabled") } let tcx = &{ this.tcx.tcx }; @@ -128,7 +128,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let buf = this.force_ptr(this.read_scalar(buf_op)?.not_undef()?)?; let size = this.read_scalar(size_op)?.to_usize(&*this.tcx)?; // If we cannot get the current directory, we return null - // FIXME: Technically we have to set the `errno` global too match env::current_dir() { Ok(cwd) => { // It is not clear what happens with non-utf8 paths here From 0eed5e64de4c7497785f5df7f2cf376d1e6afb91 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Tue, 24 Sep 2019 14:42:38 -0500 Subject: [PATCH 1129/3747] Add `chdir` shim --- src/shims/env.rs | 26 ++++++++++++++++++++++++++ src/shims/foreign_items.rs | 5 +++++ tests/run-pass/change_current_dir.rs | 14 ++++++++++++++ tests/run-pass/get_current_dir.rs | 6 ------ 4 files changed, 45 insertions(+), 6 deletions(-) create mode 100644 tests/run-pass/change_current_dir.rs delete mode 100644 tests/run-pass/get_current_dir.rs diff --git a/src/shims/env.rs b/src/shims/env.rs index e2a9452045eaf..074baa51f8263 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -1,5 +1,6 @@ use std::collections::HashMap; use std::env; +use std::path::Path; use crate::stacked_borrows::Tag; use crate::*; @@ -151,4 +152,29 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } Ok(Scalar::ptr_null(&*this.tcx)) } + + fn chdir(&mut self, path_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + let this = self.eval_context_mut(); + + if !this.machine.communicate { + throw_unsup_format!("`chdir` not available when isolation is enabled") + } + + let path_bytes = this + .memory() + .read_c_str(this.read_scalar(path_op)?.not_undef()?)?; + + let path = Path::new( + std::str::from_utf8(path_bytes) + .map_err(|_| err_unsup_format!("{:?} is not a valid utf-8 string", path_bytes))?, + ); + + match env::set_current_dir(path) { + Ok(()) => Ok(0), + Err(e) => { + this.machine.last_error = e.raw_os_error().unwrap() as u32; + Ok(-1) + } + } + } } diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 45f167bea582d..fedb6354b820a 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -441,6 +441,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(result, dest)?; } + "chdir" => { + let result = this.chdir(args[0])?; + this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + } + "write" => { let fd = this.read_scalar(args[0])?.to_i32()?; let buf = this.read_scalar(args[1])?.not_undef()?; diff --git a/tests/run-pass/change_current_dir.rs b/tests/run-pass/change_current_dir.rs new file mode 100644 index 0000000000000..fa8220339db06 --- /dev/null +++ b/tests/run-pass/change_current_dir.rs @@ -0,0 +1,14 @@ +// ignore-windows: TODO the windows hook is not done yet +// compile-flags: -Zmiri-disable-isolation +use std::env; +use std::path::Path; + +fn main() { + // test that `getcwd` is available + let cwd = env::current_dir().unwrap(); + let parent = cwd.parent().unwrap_or(&cwd); + // test that `chdir` is available + assert!(env::set_current_dir(&Path::new("..")).is_ok()); + // test that `..` goes to the parent directory + assert_eq!(env::current_dir().unwrap(), parent); +} diff --git a/tests/run-pass/get_current_dir.rs b/tests/run-pass/get_current_dir.rs deleted file mode 100644 index 45efd06d3f670..0000000000000 --- a/tests/run-pass/get_current_dir.rs +++ /dev/null @@ -1,6 +0,0 @@ -// ignore-windows: TODO the windows hook is not done yet -// compile-flags: -Zmiri-disable-isolation - -fn main() { - std::env::current_dir().unwrap(); -} From 145a5826d5cc02b15723bb9acb6739abdac28409 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Tue, 24 Sep 2019 15:53:14 -0500 Subject: [PATCH 1130/3747] Check that `chdir` fails for non-utf8 paths --- tests/compile-fail/chdir_invalid_path.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 tests/compile-fail/chdir_invalid_path.rs diff --git a/tests/compile-fail/chdir_invalid_path.rs b/tests/compile-fail/chdir_invalid_path.rs new file mode 100644 index 0000000000000..22b0d723aad8c --- /dev/null +++ b/tests/compile-fail/chdir_invalid_path.rs @@ -0,0 +1,11 @@ +// compile-flags: -Zmiri-disable-isolation + +extern { + pub fn chdir(dir: *const u8) -> i32; +} + +fn main() { + let path = vec![0xc3u8, 0x28, 0]; + // test that `chdir` errors with invalid utf-8 path + unsafe { chdir(path.as_ptr()) }; //~ ERROR is not a valid utf-8 string +} From 79b1f91f45e3883e0946846cfd82aa4273c9809a Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Tue, 24 Sep 2019 17:28:00 -0500 Subject: [PATCH 1131/3747] First version of file handling --- src/lib.rs | 1 + src/machine.rs | 3 + src/shims/foreign_items.rs | 20 ++++ src/shims/io.rs | 179 ++++++++++++++++++++++++++++++++++++ src/shims/mod.rs | 1 + tests/hello.txt | 1 + tests/run-pass/file_read.rs | 12 +++ 7 files changed, 217 insertions(+) create mode 100644 src/shims/io.rs create mode 100644 tests/hello.txt create mode 100644 tests/run-pass/file_read.rs diff --git a/src/lib.rs b/src/lib.rs index cea99d86eaa8a..9f4e605b6c941 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -34,6 +34,7 @@ pub use crate::shims::intrinsics::EvalContextExt as IntrinsicsEvalContextExt; pub use crate::shims::tls::{EvalContextExt as TlsEvalContextExt, TlsData}; pub use crate::shims::dlsym::{Dlsym, EvalContextExt as DlsymEvalContextExt}; pub use crate::shims::env::{EnvVars, EvalContextExt as EnvEvalContextExt}; +pub use crate::shims::io::{FileHandler, EvalContextExt as FileEvalContextExt}; pub use crate::operator::EvalContextExt as OperatorEvalContextExt; pub use crate::range_map::RangeMap; pub use crate::helpers::{EvalContextExt as HelpersEvalContextExt}; diff --git a/src/machine.rs b/src/machine.rs index 340dd109e1249..19be5b547ba84 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -96,6 +96,8 @@ pub struct Evaluator<'tcx> { /// If enabled, the `env_vars` field is populated with the host env vars during initialization /// and random number generation is delegated to the host. pub(crate) communicate: bool, + + pub(crate) file_handler: FileHandler, } impl<'tcx> Evaluator<'tcx> { @@ -110,6 +112,7 @@ impl<'tcx> Evaluator<'tcx> { last_error: 0, tls: TlsData::default(), communicate, + file_handler: Default::default(), } } } diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index fedb6354b820a..f717d7959f04c 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -446,6 +446,26 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; } + "open" | "open64" => { + let result = this.open(args[0], args[1])?; + this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + } + + "fcntl" => { + let result = this.fcntl(args[0], args[1], args.get(2).cloned())?; + this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + } + + "close" => { + let result = this.close(args[0])?; + this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + } + + "read" => { + let result = this.read(args[0], args[1], args[2])?; + this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + } + "write" => { let fd = this.read_scalar(args[0])?.to_i32()?; let buf = this.read_scalar(args[1])?.not_undef()?; diff --git a/src/shims/io.rs b/src/shims/io.rs new file mode 100644 index 0000000000000..02e5133c9a08c --- /dev/null +++ b/src/shims/io.rs @@ -0,0 +1,179 @@ +use std::collections::HashMap; +use std::fs::File; +use std::io::Read; + +use crate::stacked_borrows::Tag; +use crate::*; + +#[derive(Default)] +pub struct FileHandler { + files: HashMap, + flags: HashMap, + low: i32, +} + +impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} +pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { + fn open( + &mut self, + path_op: OpTy<'tcx, Tag>, + flag_op: OpTy<'tcx, Tag>, + ) -> InterpResult<'tcx, i32> { + let this = self.eval_context_mut(); + + if !this.machine.communicate { + throw_unsup_format!("`open` not available when isolation is enabled") + } + + let flag = this.read_scalar(flag_op)?.to_i32()?; + + if flag + != this + .eval_path_scalar(&["libc", "O_RDONLY"])? + .unwrap() + .to_i32()? + && flag + != this + .eval_path_scalar(&["libc", "O_CLOEXEC"])? + .unwrap() + .to_i32()? + { + throw_unsup_format!("Unsupported flag {:#x}", flag); + } + + let path_bytes = this + .memory() + .read_c_str(this.read_scalar(path_op)?.not_undef()?)?; + let path = std::str::from_utf8(path_bytes) + .map_err(|_| err_unsup_format!("{:?} is not a valid utf-8 string", path_bytes))?; + + match File::open(path) { + Ok(file) => { + let mut fh = &mut this.machine.file_handler; + fh.low += 1; + fh.files.insert(fh.low, file); + fh.flags.insert(fh.low, flag); + Ok(fh.low) + } + + Err(e) => { + this.machine.last_error = e.raw_os_error().unwrap() as u32; + Ok(-1) + } + } + } + + fn fcntl( + &mut self, + fd_op: OpTy<'tcx, Tag>, + cmd_op: OpTy<'tcx, Tag>, + arg_op: Option>, + ) -> InterpResult<'tcx, i32> { + let this = self.eval_context_mut(); + + if !this.machine.communicate { + throw_unsup_format!("`open` not available when isolation is enabled") + } + + let fd = this.read_scalar(fd_op)?.to_i32()?; + let cmd = this.read_scalar(cmd_op)?.to_i32()?; + + if cmd + == this + .eval_path_scalar(&["libc", "F_SETFD"])? + .unwrap() + .to_i32()? + { + let flag = this.read_scalar(arg_op.unwrap())?.to_i32()?; + this.machine.file_handler.flags.insert(fd, flag); + Ok(0) + } else if cmd + == this + .eval_path_scalar(&["libc", "F_GETFD"])? + .unwrap() + .to_i32()? + { + if let Some(flag) = this.machine.file_handler.flags.get(&fd) { + Ok(*flag) + } else { + this.machine.last_error = this + .eval_path_scalar(&["libc", "EBADF"])? + .unwrap() + .to_u32()?; + Ok(-1) + } + } else { + throw_unsup_format!("Unsupported command {:#x}", cmd); + } + } + + fn close(&mut self, fd_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + let this = self.eval_context_mut(); + + if !this.machine.communicate { + throw_unsup_format!("`open` not available when isolation is enabled") + } + + let fd = this.read_scalar(fd_op)?.to_i32()?; + + if let Some(file) = this.machine.file_handler.files.remove(&fd) { + match file.sync_all() { + Ok(()) => Ok(0), + Err(e) => { + this.machine.last_error = e.raw_os_error().unwrap() as u32; + Ok(-1) + } + } + } else { + this.machine.last_error = this + .eval_path_scalar(&["libc", "EBADF"])? + .unwrap() + .to_u32()?; + Ok(-1) + } + } + + fn read( + &mut self, + fd_op: OpTy<'tcx, Tag>, + buf_op: OpTy<'tcx, Tag>, + count_op: OpTy<'tcx, Tag>, + ) -> InterpResult<'tcx, i64> { + let this = self.eval_context_mut(); + + if !this.machine.communicate { + throw_unsup_format!("`open` not available when isolation is enabled") + } + + let tcx = &{ this.tcx.tcx }; + + let fd = this.read_scalar(fd_op)?.to_i32()?; + let buf = this.force_ptr(this.read_scalar(buf_op)?.not_undef()?)?; + let count = this.read_scalar(count_op)?.to_usize(&*this.tcx)?; + + if let Some(file) = this.machine.file_handler.files.get_mut(&fd) { + let mut bytes = vec![0; count as usize]; + match file.read(&mut bytes) { + Ok(read_bytes) => { + bytes.truncate(read_bytes); + + this.memory_mut() + .get_mut(buf.alloc_id)? + .write_bytes(tcx, buf, &bytes)?; + + Ok(read_bytes as i64) + } + Err(e) => { + this.machine.last_error = e.raw_os_error().unwrap() as u32; + Ok(-1) + } + } + } else { + this.machine.last_error = this + .eval_path_scalar(&["libc", "EBADF"])? + .unwrap() + .to_u32()?; + Ok(-1) + } + } +} diff --git a/src/shims/mod.rs b/src/shims/mod.rs index a0da364ff0b9c..981185d252e74 100644 --- a/src/shims/mod.rs +++ b/src/shims/mod.rs @@ -3,6 +3,7 @@ pub mod intrinsics; pub mod tls; pub mod dlsym; pub mod env; +pub mod io; use rustc::{ty, mir}; diff --git a/tests/hello.txt b/tests/hello.txt new file mode 100644 index 0000000000000..8ab686eafeb1f --- /dev/null +++ b/tests/hello.txt @@ -0,0 +1 @@ +Hello, World! diff --git a/tests/run-pass/file_read.rs b/tests/run-pass/file_read.rs new file mode 100644 index 0000000000000..93c986393b02e --- /dev/null +++ b/tests/run-pass/file_read.rs @@ -0,0 +1,12 @@ +// ignore-windows: File handling is not implemented yet +// compile-flags: -Zmiri-disable-isolation + +use std::fs::File; +use std::io::Read; + +fn main() { + let mut file = File::open("./tests/hello.txt").unwrap(); + let mut contents = String::new(); + file.read_to_string(&mut contents).unwrap(); + assert_eq!("Hello, World!\n", contents); +} From 3726081857e3759ce7b7caeb836d6dce9f515227 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Wed, 25 Sep 2019 10:49:12 -0500 Subject: [PATCH 1132/3747] Add helper function to fetch `libc` constants --- src/shims/foreign_items.rs | 8 ++++++++ src/shims/io.rs | 41 ++++++-------------------------------- 2 files changed, 14 insertions(+), 35 deletions(-) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index f717d7959f04c..2c0064976e3f3 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -949,6 +949,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } return Ok(None); } + + fn eval_libc_i32(&mut self, name: &str) -> InterpResult<'tcx, i32> { + self + .eval_context_mut() + .eval_path_scalar(&["libc", name])? + .ok_or_else(|| err_unsup_format!("Path libc::{} cannot be resolved.", name).into()) + .and_then(|scalar| scalar.to_i32()) + } } // Shims the linux 'getrandom()' syscall. diff --git a/src/shims/io.rs b/src/shims/io.rs index 02e5133c9a08c..4b9af52962e71 100644 --- a/src/shims/io.rs +++ b/src/shims/io.rs @@ -27,17 +27,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let flag = this.read_scalar(flag_op)?.to_i32()?; - if flag - != this - .eval_path_scalar(&["libc", "O_RDONLY"])? - .unwrap() - .to_i32()? - && flag - != this - .eval_path_scalar(&["libc", "O_CLOEXEC"])? - .unwrap() - .to_i32()? - { + if flag != this.eval_libc_i32("O_RDONLY")? && flag != this.eval_libc_i32("O_CLOEXEC")? { throw_unsup_format!("Unsupported flag {:#x}", flag); } @@ -78,28 +68,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let fd = this.read_scalar(fd_op)?.to_i32()?; let cmd = this.read_scalar(cmd_op)?.to_i32()?; - if cmd - == this - .eval_path_scalar(&["libc", "F_SETFD"])? - .unwrap() - .to_i32()? - { + if cmd == this.eval_libc_i32("F_SETFD")? { let flag = this.read_scalar(arg_op.unwrap())?.to_i32()?; this.machine.file_handler.flags.insert(fd, flag); Ok(0) - } else if cmd - == this - .eval_path_scalar(&["libc", "F_GETFD"])? - .unwrap() - .to_i32()? - { + } else if cmd == this.eval_libc_i32("F_GETFD")? { if let Some(flag) = this.machine.file_handler.flags.get(&fd) { Ok(*flag) } else { - this.machine.last_error = this - .eval_path_scalar(&["libc", "EBADF"])? - .unwrap() - .to_u32()?; + this.machine.last_error = this.eval_libc_i32("EBADF")? as u32; Ok(-1) } } else { @@ -125,10 +102,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } } else { - this.machine.last_error = this - .eval_path_scalar(&["libc", "EBADF"])? - .unwrap() - .to_u32()?; + this.machine.last_error = this.eval_libc_i32("EBADF")? as u32; Ok(-1) } } @@ -169,10 +143,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } } else { - this.machine.last_error = this - .eval_path_scalar(&["libc", "EBADF"])? - .unwrap() - .to_u32()?; + this.machine.last_error = this.eval_libc_i32("EBADF")? as u32; Ok(-1) } } From 01f64616adbeb6162a6aecabbdf562810f14e20f Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Wed, 25 Sep 2019 11:11:20 -0500 Subject: [PATCH 1133/3747] Check that the only flag change is done to enable `FD_CLOEXEC` --- src/shims/io.rs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/shims/io.rs b/src/shims/io.rs index 4b9af52962e71..180748a075504 100644 --- a/src/shims/io.rs +++ b/src/shims/io.rs @@ -69,8 +69,18 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let cmd = this.read_scalar(cmd_op)?.to_i32()?; if cmd == this.eval_libc_i32("F_SETFD")? { + // This does not affect the file itself. Certain flags might require changing the file + // or the way it is accessed somehow. let flag = this.read_scalar(arg_op.unwrap())?.to_i32()?; - this.machine.file_handler.flags.insert(fd, flag); + // The only usage of this in stdlib at the moment is to enable the `FD_CLOEXEC` flag. + let fd_cloexec = this.eval_libc_i32("FD_CLOEXEC")?; + if let Some(old_flag) = this.machine.file_handler.flags.get_mut(&fd) { + if flag ^ *old_flag == fd_cloexec { + *old_flag = flag; + } else { + throw_unsup_format!("Unsupported arg {:#x} for `F_SETFD`", flag); + } + } Ok(0) } else if cmd == this.eval_libc_i32("F_GETFD")? { if let Some(flag) = this.machine.file_handler.flags.get(&fd) { From bdaa90ceb20a42405f9c7fee31133e70aab1bf7d Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Wed, 25 Sep 2019 11:12:46 -0500 Subject: [PATCH 1134/3747] Add FIXME to file reading test --- tests/run-pass/file_read.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/run-pass/file_read.rs b/tests/run-pass/file_read.rs index 93c986393b02e..a60640d1b3c34 100644 --- a/tests/run-pass/file_read.rs +++ b/tests/run-pass/file_read.rs @@ -5,6 +5,7 @@ use std::fs::File; use std::io::Read; fn main() { + // FIXME: create the file and delete it when `rm` is implemented. let mut file = File::open("./tests/hello.txt").unwrap(); let mut contents = String::new(); file.read_to_string(&mut contents).unwrap(); From ca3a917a6fdc02caf40b5c466b8394be7f61f0d5 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Wed, 25 Sep 2019 11:16:11 -0500 Subject: [PATCH 1135/3747] Enable close call for macos --- src/shims/foreign_items.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 2c0064976e3f3..b8609fd2ef092 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -456,7 +456,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; } - "close" => { + "close" | "close$NOCANCEL" => { let result = this.close(args[0])?; this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; } From 20b10cc6d3419f50844a13fec2bc693b0194801d Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Thu, 26 Sep 2019 09:42:03 +0200 Subject: [PATCH 1136/3747] Update to latest nightly --- Cargo.toml | 2 +- rust-version | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 6e34d6c3d5d38..5a5c774169cff 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -59,5 +59,5 @@ cargo_miri = ["cargo_metadata", "directories", "rustc_version"] rustc_tests = [] [dev-dependencies] -compiletest_rs = { version = "0.3.22", features = ["tmp", "stable"] } +compiletest_rs = { version = "0.3.23", features = ["tmp"] } colored = "1.6" diff --git a/rust-version b/rust-version index 60dae7291d636..e4cfa76225a4f 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -ea3ba36f3f4b7f0168a27d23c499efeb2304e2d5 +a5bc0f0e3f0c58518c0537d82dee0fcfeb57115c From 9fdb347ad733dcd40eaab34ebb3143a1c6060206 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Thu, 26 Sep 2019 11:40:13 +0200 Subject: [PATCH 1137/3747] Rustup to `sty` -> `kind` changes --- rust-version | 2 +- src/helpers.rs | 2 +- src/stacked_borrows.rs | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/rust-version b/rust-version index e4cfa76225a4f..e8bca6ea63b58 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -a5bc0f0e3f0c58518c0537d82dee0fcfeb57115c +dc45735f29788924b9fc351d100e5bf3ebdca162 diff --git a/src/helpers.rs b/src/helpers.rs index ad30040c2ddcc..3bee028c5eb7a 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -211,7 +211,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn visit_value(&mut self, v: MPlaceTy<'tcx, Tag>) -> InterpResult<'tcx> { trace!("UnsafeCellVisitor: {:?} {:?}", *v, v.layout.ty); - let is_unsafe_cell = match v.layout.ty.sty { + let is_unsafe_cell = match v.layout.ty.kind { ty::Adt(adt, _) => Some(adt.did) == self.ecx.tcx.lang_items().unsafe_cell_type(), _ => false, }; diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 01ed6ec225d20..5258cbb5485b4 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -435,7 +435,7 @@ impl<'tcx> Stacks { Stacks { stacks: RefCell::new(RangeMap::new(size, stack)), - global: extra, + global: extra, } } @@ -460,7 +460,7 @@ impl Stacks { pub fn new_allocation( id: AllocId, size: Size, - extra: MemoryExtra, + extra: MemoryExtra, kind: MemoryKind, ) -> (Self, Tag) { let (tag, perm) = match kind { @@ -616,7 +616,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Cannot use `builtin_deref` because that reports *immutable* for `Box`, // making it useless. fn qualify(ty: ty::Ty<'_>, kind: RetagKind) -> Option<(RefKind, bool)> { - match ty.sty { + match ty.kind { // References are simple. ty::Ref(_, _, MutMutable) => Some((RefKind::Unique { two_phase: kind == RetagKind::TwoPhase}, kind == RetagKind::FnEntry)), From 9f6287eb0cbb0524ce503010d50a25e1e4ecb4a3 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 27 Sep 2019 10:23:26 -0400 Subject: [PATCH 1138/3747] show cargo version --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 269dc28ca021b..e053c062ff991 100644 --- a/.travis.yml +++ b/.travis.yml @@ -39,6 +39,7 @@ before_script: - travis_retry rustup-toolchain-install-master -f -n master $RUSTC_HASH -c rust-src - rustup default master - rustc --version +- cargo --version script: - ./travis.sh From c424e069932d632e08856739e2811764d4d7020c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 27 Sep 2019 10:54:39 -0400 Subject: [PATCH 1139/3747] make sure we use the stable toolchain, no matter the cache --- .travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index e053c062ff991..446fab7941105 100644 --- a/.travis.yml +++ b/.travis.yml @@ -33,6 +33,8 @@ before_script: # Install Rust ("stable" toolchain for better caching, it is just used to build rustup-toolchain-install-master) - curl https://build.travis-ci.org/files/rustup-init.sh -sSf | sh -s -- -y --default-toolchain stable - export PATH=$HOME/.cargo/bin:$PATH +- rustup default stable +- rustup uninstall beta - rustup update # Install "master" toolchain - cargo install rustup-toolchain-install-master || echo "rustup-toolchain-install-master already installed" From 28e814ab537606d3d9cd2235198c2c5f658206bf Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 28 Sep 2019 10:37:48 -0400 Subject: [PATCH 1140/3747] rustup --- rust-version | 2 +- src/eval.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/rust-version b/rust-version index e8bca6ea63b58..08d4c1dc23426 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -dc45735f29788924b9fc351d100e5bf3ebdca162 +084beb83e0e87d673d5fabc844d28e8e8ae2ab4c diff --git a/src/eval.rs b/src/eval.rs index 667491f8d477e..1b7c082ec37ba 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -63,7 +63,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( ty::ParamEnv::reveal_all(), start_id, ecx.tcx.mk_substs( - ::std::iter::once(ty::subst::Kind::from(main_ret_ty))) + ::std::iter::once(ty::subst::GenericArg::from(main_ret_ty))) ).unwrap(); let start_mir = ecx.load_mir(start_instance.def, None)?; From 63ea13ad0dc30769c674ea52172cafe4e0178bb1 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 28 Sep 2019 11:00:05 -0400 Subject: [PATCH 1141/3747] fix miri-rustc-tests --- src/bin/miri-rustc-tests.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bin/miri-rustc-tests.rs b/src/bin/miri-rustc-tests.rs index 3b4ad8415917a..5f814fd198622 100644 --- a/src/bin/miri-rustc-tests.rs +++ b/src/bin/miri-rustc-tests.rs @@ -46,7 +46,7 @@ impl rustc_driver::Callbacks for MiriCompilerCalls { struct Visitor<'tcx>(TyCtxt<'tcx>); impl<'tcx, 'hir> itemlikevisit::ItemLikeVisitor<'hir> for Visitor<'tcx> { fn visit_item(&mut self, i: &'hir hir::Item) { - if let hir::ItemKind::Fn(.., body_id) = i.node { + if let hir::ItemKind::Fn(.., body_id) = i.kind { if i.attrs.iter().any(|attr| attr.check_name(syntax::symbol::sym::test)) { let config = MiriConfig { validate: true, From 638d989629675288207fa2031a1fca531a9eaf9e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 28 Sep 2019 11:36:20 -0400 Subject: [PATCH 1142/3747] sync AppVeyor CI script with Travis --- .appveyor.yml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/.appveyor.yml b/.appveyor.yml index 391ff042daf41..c3d575403cb3d 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -17,16 +17,21 @@ cache: - '%USERPROFILE%\.rustup' install: + # Compute the rust version we use + - set /p RUSTC_HASH= Date: Sat, 28 Sep 2019 12:10:18 -0400 Subject: [PATCH 1143/3747] cargo update for test-cargo-miri --- test-cargo-miri/Cargo.lock | 38 +++++++++++++++++++------------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/test-cargo-miri/Cargo.lock b/test-cargo-miri/Cargo.lock index 2a6a32a18f045..70476fbdcb061 100644 --- a/test-cargo-miri/Cargo.lock +++ b/test-cargo-miri/Cargo.lock @@ -25,22 +25,22 @@ version = "0.1.0" dependencies = [ "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "cfg-if" -version = "0.1.9" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "getrandom" -version = "0.1.11" +version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", - "wasi 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "wasi 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -68,13 +68,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "rand" -version = "0.7.0" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "getrandom 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", + "getrandom 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", "rand_chacha 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand_pcg 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -85,15 +85,15 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "c2-chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rand_core" -version = "0.5.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "getrandom 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", + "getrandom 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -101,7 +101,7 @@ name = "rand_hc" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "rand_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -110,27 +110,27 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "autocfg 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "wasi" -version = "0.5.0" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" [metadata] "checksum autocfg 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "b671c8fb71b457dd4ae18c4ba1e59aa81793daacc361d82fcd410cef0d491875" "checksum byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a7c3dd8985a7111efc5c80b44e23ecdd8c007de8ade3b96595387e812b957cf5" "checksum c2-chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7d64d04786e0f528460fc884753cf8dddcc466be308f6026f8e355c41a0e4101" -"checksum cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "b486ce3ccf7ffd79fdeb678eac06a9e6c09fc88d33836340becb8fffe87c5e33" -"checksum getrandom 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "fc344b02d3868feb131e8b5fe2b9b0a1cc42942679af493061fc13b853243872" +"checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" +"checksum getrandom 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "473a1265acc8ff1e808cd0a1af8cee3c2ee5200916058a2ca113c29f2d903571" "checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" "checksum libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)" = "34fcd2c08d2f832f376f4173a231990fa5aef4e99fb569867318a227ef4c06ba" "checksum num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bcef43580c035376c0705c42792c294b66974abbfd2789b511784023f71f3273" "checksum ppv-lite86 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e3cbf9f658cdb5000fcf6f362b8ea2ba154b9f146a61c7a20d647034c6b6561b" -"checksum rand 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d47eab0e83d9693d40f825f86948aa16eff6750ead4bdffc4ab95b8b3a7f052c" +"checksum rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "3ae1b169243eaf61759b8475a998f0a385e42042370f3a7dbaf35246eacc8412" "checksum rand_chacha 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "03a2a90da8c7523f554344f921aa97283eadf6ac484a6d2a7d0212fa7f8d6853" -"checksum rand_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "615e683324e75af5d43d8f7a39ffe3ee4a9dc42c5c701167a71dc59c3a493aca" +"checksum rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" "checksum rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" "checksum rand_pcg 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3e196346cbbc5c70c77e7b4926147ee8e383a38ee4d15d58a08098b169e492b6" -"checksum wasi 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fd5442abcac6525a045cc8c795aedb60da7a2e5e89c7bf18a0d5357849bb23c7" +"checksum wasi 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b89c3ce4ce14bdc6fb6beaf9ec7928ca331de5df7e5ea278375642a2f478570d" From 8ecd767791a67c15b07087b060d0387f1d36ad21 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 29 Sep 2019 11:30:28 -0400 Subject: [PATCH 1144/3747] fix test failure from diagnostics change --- rust-version | 2 +- tests/compile-fail/overflowing-rsh-1.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/rust-version b/rust-version index 08d4c1dc23426..77a1658e248b7 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -084beb83e0e87d673d5fabc844d28e8e8ae2ab4c +488381ce9ef0ceabe83b73127c659e5d38137df0 diff --git a/tests/compile-fail/overflowing-rsh-1.rs b/tests/compile-fail/overflowing-rsh-1.rs index 7a4646a0ebf3a..e0d3f1904a23f 100644 --- a/tests/compile-fail/overflowing-rsh-1.rs +++ b/tests/compile-fail/overflowing-rsh-1.rs @@ -1,4 +1,4 @@ -#![allow(exceeding_bitshifts)] +#![allow(exceeding_bitshifts, const_err)] fn main() { let _n = 1i64 >> 64; //~ ERROR attempt to shift right with overflow From 9650b7868e64971f6a154c87ddd13e9cc33f1589 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 29 Sep 2019 11:43:50 -0400 Subject: [PATCH 1145/3747] more align_offset tests --- tests/run-pass/align_offset.rs | 70 +++++++++++++++++++ ..._utf8_check.stdout => align_offset.stdout} | 0 tests/run-pass/aligned_utf8_check.rs | 6 -- 3 files changed, 70 insertions(+), 6 deletions(-) create mode 100644 tests/run-pass/align_offset.rs rename tests/run-pass/{aligned_utf8_check.stdout => align_offset.stdout} (100%) delete mode 100644 tests/run-pass/aligned_utf8_check.rs diff --git a/tests/run-pass/align_offset.rs b/tests/run-pass/align_offset.rs new file mode 100644 index 0000000000000..f3464a012f027 --- /dev/null +++ b/tests/run-pass/align_offset.rs @@ -0,0 +1,70 @@ +fn test_align_offset() { + let d = Box::new([0u32; 4]); + // Get u8 pointer to base + let raw = d.as_ptr() as *const u8; + + assert_eq!(raw.align_offset(2), 0); + assert_eq!(raw.align_offset(4), 0); + assert_eq!(raw.align_offset(8), usize::max_value()); + + assert_eq!(raw.wrapping_offset(1).align_offset(2), 1); + assert_eq!(raw.wrapping_offset(1).align_offset(4), 3); + assert_eq!(raw.wrapping_offset(1).align_offset(8), usize::max_value()); + + assert_eq!(raw.wrapping_offset(2).align_offset(2), 0); + assert_eq!(raw.wrapping_offset(2).align_offset(4), 2); + assert_eq!(raw.wrapping_offset(2).align_offset(8), usize::max_value()); +} + +fn test_align_to() { + const N: usize = 4; + let d = Box::new([0u32; N]); + // Get u8 slice covering the entire thing + let s = unsafe { std::slice::from_raw_parts(d.as_ptr() as *const u8, 4 * N) }; + let raw = s.as_ptr(); + + { + let (l, m, r) = unsafe { s.align_to::() }; + assert_eq!(l.len(), 0); + assert_eq!(r.len(), 0); + assert_eq!(m.len(), N); + assert_eq!(raw, m.as_ptr() as *const u8); + } + + { + let (l, m, r) = unsafe { s[1..].align_to::() }; + assert_eq!(l.len(), 3); + assert_eq!(m.len(), N-1); + assert_eq!(r.len(), 0); + assert_eq!(raw.wrapping_offset(4), m.as_ptr() as *const u8); + } + + { + let (l, m, r) = unsafe { s[..4*N - 1].align_to::() }; + assert_eq!(l.len(), 0); + assert_eq!(m.len(), N-1); + assert_eq!(r.len(), 3); + assert_eq!(raw, m.as_ptr() as *const u8); + } + + { + let (l, m, r) = unsafe { s[1..4*N - 1].align_to::() }; + assert_eq!(l.len(), 3); + assert_eq!(m.len(), N-2); + assert_eq!(r.len(), 3); + assert_eq!(raw.wrapping_offset(4), m.as_ptr() as *const u8); + } +} + +fn test_from_utf8() { + const N: usize = 10; + let vec = vec![0x4141414141414141u64; N]; + let content = unsafe { std::slice::from_raw_parts(vec.as_ptr() as *const u8, 8 * N) }; + println!("{:?}", std::str::from_utf8(content).unwrap()); +} + +fn main() { + test_align_offset(); + test_align_to(); + test_from_utf8(); +} diff --git a/tests/run-pass/aligned_utf8_check.stdout b/tests/run-pass/align_offset.stdout similarity index 100% rename from tests/run-pass/aligned_utf8_check.stdout rename to tests/run-pass/align_offset.stdout diff --git a/tests/run-pass/aligned_utf8_check.rs b/tests/run-pass/aligned_utf8_check.rs deleted file mode 100644 index 6c6ff6b6173cb..0000000000000 --- a/tests/run-pass/aligned_utf8_check.rs +++ /dev/null @@ -1,6 +0,0 @@ -fn main() { - const N: usize = 10; - let vec = vec![0x4141414141414141u64; N]; - let content = unsafe { std::slice::from_raw_parts(vec.as_ptr() as *const u8, 8 * N) }; - println!("{:?}", std::str::from_utf8(content).unwrap()); -} From b5d449949a5833d2ea3484d840b704a731bac516 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 29 Sep 2019 11:49:04 -0400 Subject: [PATCH 1146/3747] comments and another test --- tests/run-pass/align_offset.rs | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/tests/run-pass/align_offset.rs b/tests/run-pass/align_offset.rs index f3464a012f027..8388089b8f448 100644 --- a/tests/run-pass/align_offset.rs +++ b/tests/run-pass/align_offset.rs @@ -5,15 +5,15 @@ fn test_align_offset() { assert_eq!(raw.align_offset(2), 0); assert_eq!(raw.align_offset(4), 0); - assert_eq!(raw.align_offset(8), usize::max_value()); + assert_eq!(raw.align_offset(8), usize::max_value()); // requested alignment higher than allocation alignment assert_eq!(raw.wrapping_offset(1).align_offset(2), 1); assert_eq!(raw.wrapping_offset(1).align_offset(4), 3); - assert_eq!(raw.wrapping_offset(1).align_offset(8), usize::max_value()); + assert_eq!(raw.wrapping_offset(1).align_offset(8), usize::max_value()); // requested alignment higher than allocation alignment assert_eq!(raw.wrapping_offset(2).align_offset(2), 0); assert_eq!(raw.wrapping_offset(2).align_offset(4), 2); - assert_eq!(raw.wrapping_offset(2).align_offset(8), usize::max_value()); + assert_eq!(raw.wrapping_offset(2).align_offset(8), usize::max_value()); // requested alignment higher than allocation alignment } fn test_align_to() { @@ -54,6 +54,13 @@ fn test_align_to() { assert_eq!(r.len(), 3); assert_eq!(raw.wrapping_offset(4), m.as_ptr() as *const u8); } + + { + let (l, m, r) = unsafe { s.align_to::() }; // requested alignment higher than allocation alignment + assert_eq!(l.len(), 4*N); + assert_eq!(r.len(), 0); + assert_eq!(m.len(), 0); + } } fn test_from_utf8() { From a9c207dce22340fbf2e31399bccbbafb7bfb2358 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 29 Sep 2019 12:26:13 -0400 Subject: [PATCH 1147/3747] fix tests on 32bit --- tests/run-pass/align_offset.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/run-pass/align_offset.rs b/tests/run-pass/align_offset.rs index 8388089b8f448..736889174839f 100644 --- a/tests/run-pass/align_offset.rs +++ b/tests/run-pass/align_offset.rs @@ -56,7 +56,8 @@ fn test_align_to() { } { - let (l, m, r) = unsafe { s.align_to::() }; // requested alignment higher than allocation alignment + #[repr(align(8))] struct Align8(u64); + let (l, m, r) = unsafe { s.align_to::() }; // requested alignment higher than allocation alignment assert_eq!(l.len(), 4*N); assert_eq!(r.len(), 0); assert_eq!(m.len(), 0); From 241b418125df8dee4d1524510432eea7ff50869e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 29 Sep 2019 12:31:04 -0400 Subject: [PATCH 1148/3747] bump rust even more --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 77a1658e248b7..2d311cc17704f 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -488381ce9ef0ceabe83b73127c659e5d38137df0 +d046ffddc4bd50e04ffc3ff9f766e2ac71f74d50 From 03ed4123c0b9ee265d713ba76b1b003d02c5bf3b Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Mon, 30 Sep 2019 11:51:09 -0500 Subject: [PATCH 1149/3747] Add FileHandle struct --- src/shims/io.rs | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/src/shims/io.rs b/src/shims/io.rs index 6f8785891c27a..44acf45c9a53b 100644 --- a/src/shims/io.rs +++ b/src/shims/io.rs @@ -5,17 +5,20 @@ use std::io::Read; use crate::stacked_borrows::Tag; use crate::*; +struct FileHandle { + file: File, + flag: i32, +} + pub struct FileHandler { - files: HashMap, - flags: HashMap, + handles: HashMap, low: i32, } impl Default for FileHandler { fn default() -> Self { FileHandler { - files: Default::default(), - flags: Default::default(), + handles: Default::default(), // 0, 1 and 2 are reserved for stdin, stdout and stderr low: 3, } @@ -51,8 +54,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(file) => { let mut fh = &mut this.machine.file_handler; fh.low += 1; - fh.files.insert(fh.low, file); - fh.flags.insert(fh.low, flag); + fh.handles.insert(fh.low, FileHandle{ file, flag}); Ok(fh.low) } @@ -84,7 +86,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let flag = this.read_scalar(arg_op.unwrap())?.to_i32()?; // The only usage of this in stdlib at the moment is to enable the `FD_CLOEXEC` flag. let fd_cloexec = this.eval_libc_i32("FD_CLOEXEC")?; - if let Some(old_flag) = this.machine.file_handler.flags.get_mut(&fd) { + if let Some(FileHandle{ flag: old_flag, .. }) = this.machine.file_handler.handles.get_mut(&fd) { if flag ^ *old_flag == fd_cloexec { *old_flag = flag; } else { @@ -93,8 +95,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } Ok(0) } else if cmd == this.eval_libc_i32("F_GETFD")? { - if let Some(flag) = this.machine.file_handler.flags.get(&fd) { - Ok(*flag) + if let Some(handle) = this.machine.file_handler.handles.get(&fd) { + Ok(handle.flag) } else { this.machine.last_error = this.eval_libc_i32("EBADF")? as u32; Ok(-1) @@ -113,8 +115,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let fd = this.read_scalar(fd_op)?.to_i32()?; - if let Some(file) = this.machine.file_handler.files.remove(&fd) { - match file.sync_all() { + if let Some(handle) = this.machine.file_handler.handles.remove(&fd) { + match handle.file.sync_all() { Ok(()) => Ok(0), Err(e) => { this.machine.last_error = e.raw_os_error().unwrap() as u32; @@ -145,7 +147,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let buf = this.force_ptr(this.read_scalar(buf_op)?.not_undef()?)?; let count = this.read_scalar(count_op)?.to_usize(&*this.tcx)?; - if let Some(file) = this.machine.file_handler.files.get_mut(&fd) { + if let Some(FileHandle { file, ..}) = this.machine.file_handler.handles.get_mut(&fd) { let mut bytes = vec![0; count as usize]; match file.read(&mut bytes) { Ok(read_bytes) => { From 775246e3297ef49ae361a43fc5ce469f1cc26c96 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Mon, 30 Sep 2019 14:07:08 -0500 Subject: [PATCH 1150/3747] Add method to consume std::io::Result --- src/shims/io.rs | 73 +++++++++++++++++++++++-------------------------- 1 file changed, 34 insertions(+), 39 deletions(-) diff --git a/src/shims/io.rs b/src/shims/io.rs index 44acf45c9a53b..c75d3d5ea223a 100644 --- a/src/shims/io.rs +++ b/src/shims/io.rs @@ -48,21 +48,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx .memory() .read_c_str(this.read_scalar(path_op)?.not_undef()?)?; let path = std::str::from_utf8(path_bytes) - .map_err(|_| err_unsup_format!("{:?} is not a valid utf-8 string", path_bytes))?; - - match File::open(path) { - Ok(file) => { - let mut fh = &mut this.machine.file_handler; - fh.low += 1; - fh.handles.insert(fh.low, FileHandle{ file, flag}); - Ok(fh.low) - } - - Err(e) => { - this.machine.last_error = e.raw_os_error().unwrap() as u32; - Ok(-1) - } - } + .map_err(|_| err_unsup_format!("{:?} is not a valid utf-8 string", path_bytes))? + .to_owned(); + let fd = File::open(&path).map(|file| { + let mut fh = &mut this.machine.file_handler; + fh.low += 1; + fh.handles.insert(fh.low, FileHandle{ file, flag}); + fh.low + }); + + this.consume_result::(fd, -1) } fn fcntl( @@ -116,13 +111,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let fd = this.read_scalar(fd_op)?.to_i32()?; if let Some(handle) = this.machine.file_handler.handles.remove(&fd) { - match handle.file.sync_all() { - Ok(()) => Ok(0), - Err(e) => { - this.machine.last_error = e.raw_os_error().unwrap() as u32; - Ok(-1) - } - } + this.consume_result::(handle.file.sync_all().map(|_| 0), -1) } else { this.machine.last_error = this.eval_libc_i32("EBADF")? as u32; Ok(-1) @@ -147,26 +136,32 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let buf = this.force_ptr(this.read_scalar(buf_op)?.not_undef()?)?; let count = this.read_scalar(count_op)?.to_usize(&*this.tcx)?; - if let Some(FileHandle { file, ..}) = this.machine.file_handler.handles.get_mut(&fd) { - let mut bytes = vec![0; count as usize]; - match file.read(&mut bytes) { - Ok(read_bytes) => { - bytes.truncate(read_bytes); - - this.memory_mut() - .get_mut(buf.alloc_id)? - .write_bytes(tcx, buf, &bytes)?; + let mut bytes = vec![0; count as usize]; - Ok(read_bytes as i64) - } - Err(e) => { - this.machine.last_error = e.raw_os_error().unwrap() as u32; - Ok(-1) - } - } + let read_result = if let Some(FileHandle { file, ..}) = this.machine.file_handler.handles.get_mut(&fd) { + file.read(&mut bytes).map(|bytes| bytes as i64) } else { this.machine.last_error = this.eval_libc_i32("EBADF")? as u32; - Ok(-1) + return Ok(-1); + }; + + let read_bytes = this.consume_result::(read_result, -1)?; + if read_bytes != -1 { + bytes.truncate(read_bytes as usize); + this.memory_mut() + .get_mut(buf.alloc_id)? + .write_bytes(tcx, buf, &bytes)?; + } + Ok(read_bytes) + } + + fn consume_result(&mut self, result: std::io::Result, t: T) -> InterpResult<'tcx, T> { + match result { + Ok(ok) => Ok(ok), + Err(e) => { + self.eval_context_mut().machine.last_error = e.raw_os_error().unwrap() as u32; + Ok(t) + } } } } From efbe798e626bee92cb7b2858b26ead38746b1960 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Mon, 30 Sep 2019 14:21:45 -0500 Subject: [PATCH 1151/3747] Avoid buffer allocation to read files --- src/shims/io.rs | 36 ++++++++++++++++++++---------------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/src/shims/io.rs b/src/shims/io.rs index c75d3d5ea223a..6b1952e8d66ab 100644 --- a/src/shims/io.rs +++ b/src/shims/io.rs @@ -2,6 +2,8 @@ use std::collections::HashMap; use std::fs::File; use std::io::Read; +use rustc::ty::layout::Size; + use crate::stacked_borrows::Tag; use crate::*; @@ -53,7 +55,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let fd = File::open(&path).map(|file| { let mut fh = &mut this.machine.file_handler; fh.low += 1; - fh.handles.insert(fh.low, FileHandle{ file, flag}); + fh.handles.insert(fh.low, FileHandle { file, flag }); fh.low }); @@ -81,7 +83,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let flag = this.read_scalar(arg_op.unwrap())?.to_i32()?; // The only usage of this in stdlib at the moment is to enable the `FD_CLOEXEC` flag. let fd_cloexec = this.eval_libc_i32("FD_CLOEXEC")?; - if let Some(FileHandle{ flag: old_flag, .. }) = this.machine.file_handler.handles.get_mut(&fd) { + if let Some(FileHandle { flag: old_flag, .. }) = + this.machine.file_handler.handles.get_mut(&fd) + { if flag ^ *old_flag == fd_cloexec { *old_flag = flag; } else { @@ -136,23 +140,23 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let buf = this.force_ptr(this.read_scalar(buf_op)?.not_undef()?)?; let count = this.read_scalar(count_op)?.to_usize(&*this.tcx)?; - let mut bytes = vec![0; count as usize]; - - let read_result = if let Some(FileHandle { file, ..}) = this.machine.file_handler.handles.get_mut(&fd) { - file.read(&mut bytes).map(|bytes| bytes as i64) + // Remove the file handle to avoid borrowing issues + if let Some(mut handle) = this.machine.file_handler.handles.remove(&fd) { + let bytes = handle + .file + .read(this.memory_mut().get_mut(buf.alloc_id)?.get_bytes_mut( + tcx, + buf, + Size::from_bytes(count), + )?) + .map(|bytes| bytes as i64); + // Reinsert the file handle + this.machine.file_handler.handles.insert(fd, handle); + this.consume_result::(bytes, -1) } else { this.machine.last_error = this.eval_libc_i32("EBADF")? as u32; - return Ok(-1); - }; - - let read_bytes = this.consume_result::(read_result, -1)?; - if read_bytes != -1 { - bytes.truncate(read_bytes as usize); - this.memory_mut() - .get_mut(buf.alloc_id)? - .write_bytes(tcx, buf, &bytes)?; + Ok(-1) } - Ok(read_bytes) } fn consume_result(&mut self, result: std::io::Result, t: T) -> InterpResult<'tcx, T> { From 644467c570314097f626868320bb4a9b2f769fc7 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Mon, 30 Sep 2019 15:18:23 -0500 Subject: [PATCH 1152/3747] Add methods to handle invalid fides --- src/shims/io.rs | 73 +++++++++++++++++++++++++++++++------------------ 1 file changed, 47 insertions(+), 26 deletions(-) diff --git a/src/shims/io.rs b/src/shims/io.rs index 6b1952e8d66ab..0cb2d7eeeabd4 100644 --- a/src/shims/io.rs +++ b/src/shims/io.rs @@ -7,7 +7,7 @@ use rustc::ty::layout::Size; use crate::stacked_borrows::Tag; use crate::*; -struct FileHandle { +pub struct FileHandle { file: File, flag: i32, } @@ -94,12 +94,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } Ok(0) } else if cmd == this.eval_libc_i32("F_GETFD")? { - if let Some(handle) = this.machine.file_handler.handles.get(&fd) { - Ok(handle.flag) - } else { - this.machine.last_error = this.eval_libc_i32("EBADF")? as u32; - Ok(-1) - } + this.get_handle_and(fd, |handle| Ok(handle.flag), -1) } else { throw_unsup_format!("Unsupported command {:#x}", cmd); } @@ -114,12 +109,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let fd = this.read_scalar(fd_op)?.to_i32()?; - if let Some(handle) = this.machine.file_handler.handles.remove(&fd) { - this.consume_result::(handle.file.sync_all().map(|_| 0), -1) - } else { - this.machine.last_error = this.eval_libc_i32("EBADF")? as u32; - Ok(-1) - } + this.remove_handle_and( + fd, + |handle, this| this.consume_result::(handle.file.sync_all().map(|_| 0), -1), + -1, + ) } fn read( @@ -141,21 +135,48 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let count = this.read_scalar(count_op)?.to_usize(&*this.tcx)?; // Remove the file handle to avoid borrowing issues - if let Some(mut handle) = this.machine.file_handler.handles.remove(&fd) { - let bytes = handle - .file - .read(this.memory_mut().get_mut(buf.alloc_id)?.get_bytes_mut( - tcx, - buf, - Size::from_bytes(count), - )?) - .map(|bytes| bytes as i64); - // Reinsert the file handle - this.machine.file_handler.handles.insert(fd, handle); - this.consume_result::(bytes, -1) + this.remove_handle_and( + fd, + |mut handle, this| { + let bytes = handle + .file + .read(this.memory_mut().get_mut(buf.alloc_id)?.get_bytes_mut( + tcx, + buf, + Size::from_bytes(count), + )?) + .map(|bytes| bytes as i64); + // Reinsert the file handle + this.machine.file_handler.handles.insert(fd, handle); + this.consume_result::(bytes, -1) + }, + -1, + ) + } + + fn get_handle_and(&mut self, fd: i32, f: F, t: T) -> InterpResult<'tcx, T> + where + F: Fn(&FileHandle) -> InterpResult<'tcx, T>, + { + let this = self.eval_context_mut(); + if let Some(handle) = this.machine.file_handler.handles.get(&fd) { + f(handle) + } else { + this.machine.last_error = this.eval_libc_i32("EBADF")? as u32; + Ok(t) + } + } + + fn remove_handle_and(&mut self, fd: i32, mut f: F, t: T) -> InterpResult<'tcx, T> + where + F: FnMut(FileHandle, &mut MiriEvalContext<'mir, 'tcx>) -> InterpResult<'tcx, T>, + { + let this = self.eval_context_mut(); + if let Some(handle) = this.machine.file_handler.handles.remove(&fd) { + f(handle, this) } else { this.machine.last_error = this.eval_libc_i32("EBADF")? as u32; - Ok(-1) + Ok(t) } } From 50be5a83c50528cc61d2b65a73839dbb25fc9c67 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Tue, 1 Oct 2019 09:18:55 -0500 Subject: [PATCH 1153/3747] Remove return argument when fd is not found --- src/shims/io.rs | 27 ++++++++++++--------------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/src/shims/io.rs b/src/shims/io.rs index 0cb2d7eeeabd4..c91d3a07726ed 100644 --- a/src/shims/io.rs +++ b/src/shims/io.rs @@ -50,16 +50,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx .memory() .read_c_str(this.read_scalar(path_op)?.not_undef()?)?; let path = std::str::from_utf8(path_bytes) - .map_err(|_| err_unsup_format!("{:?} is not a valid utf-8 string", path_bytes))? - .to_owned(); - let fd = File::open(&path).map(|file| { + .map_err(|_| err_unsup_format!("{:?} is not a valid utf-8 string", path_bytes))?; + let fd = File::open(path).map(|file| { let mut fh = &mut this.machine.file_handler; fh.low += 1; fh.handles.insert(fh.low, FileHandle { file, flag }); fh.low }); - this.consume_result::(fd, -1) + this.consume_result(fd) } fn fcntl( @@ -94,7 +93,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } Ok(0) } else if cmd == this.eval_libc_i32("F_GETFD")? { - this.get_handle_and(fd, |handle| Ok(handle.flag), -1) + this.get_handle_and(fd, |handle| Ok(handle.flag)) } else { throw_unsup_format!("Unsupported command {:#x}", cmd); } @@ -111,8 +110,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.remove_handle_and( fd, - |handle, this| this.consume_result::(handle.file.sync_all().map(|_| 0), -1), - -1, + |handle, this| this.consume_result(handle.file.sync_all().map(|_| 0i32)), ) } @@ -148,13 +146,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx .map(|bytes| bytes as i64); // Reinsert the file handle this.machine.file_handler.handles.insert(fd, handle); - this.consume_result::(bytes, -1) + this.consume_result(bytes) }, - -1, ) } - fn get_handle_and(&mut self, fd: i32, f: F, t: T) -> InterpResult<'tcx, T> + fn get_handle_and>(&mut self, fd: i32, f: F) -> InterpResult<'tcx, T> where F: Fn(&FileHandle) -> InterpResult<'tcx, T>, { @@ -163,11 +160,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx f(handle) } else { this.machine.last_error = this.eval_libc_i32("EBADF")? as u32; - Ok(t) + Ok((-1).into()) } } - fn remove_handle_and(&mut self, fd: i32, mut f: F, t: T) -> InterpResult<'tcx, T> + fn remove_handle_and>(&mut self, fd: i32, mut f: F) -> InterpResult<'tcx, T> where F: FnMut(FileHandle, &mut MiriEvalContext<'mir, 'tcx>) -> InterpResult<'tcx, T>, { @@ -176,16 +173,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx f(handle, this) } else { this.machine.last_error = this.eval_libc_i32("EBADF")? as u32; - Ok(t) + Ok((-1).into()) } } - fn consume_result(&mut self, result: std::io::Result, t: T) -> InterpResult<'tcx, T> { + fn consume_result>(&mut self, result: std::io::Result) -> InterpResult<'tcx, T> { match result { Ok(ok) => Ok(ok), Err(e) => { self.eval_context_mut().machine.last_error = e.raw_os_error().unwrap() as u32; - Ok(t) + Ok((-1).into()) } } } From d0509d719c27d95b5d0f8379d66f13b99b60c42e Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Tue, 1 Oct 2019 10:31:04 -0500 Subject: [PATCH 1154/3747] Add docs for helper functions --- src/shims/io.rs | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/shims/io.rs b/src/shims/io.rs index c91d3a07726ed..0d1adcce6526d 100644 --- a/src/shims/io.rs +++ b/src/shims/io.rs @@ -151,6 +151,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) } + /// Helper function that gets a `FileHandle` immutable reference and allows to manipulate it + /// using `f`. + /// + /// If the `fd` file descriptor does not corresponds to a file, this functions returns `Ok(-1)` + /// and sets `Evaluator::last_error` to `libc::EBADF` (invalid file descriptor). + /// + /// This function uses `T: From` instead of `i32` directly because some IO related + /// functions return different integer types (like `read`, that returns an `i64`) fn get_handle_and>(&mut self, fd: i32, f: F) -> InterpResult<'tcx, T> where F: Fn(&FileHandle) -> InterpResult<'tcx, T>, @@ -164,6 +172,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } + /// Helper function that removes a `FileHandle` and allows to manipulate it using the `f` + /// closure. This function is quite useful when you need to modify a `FileHandle` but you need + /// to modify `MiriEvalContext` at the same time, so you can modify the handle and reinsert it + /// using `f`. + /// + /// If the `fd` file descriptor does not corresponds to a file, this functions returns `Ok(-1)` + /// and sets `Evaluator::last_error` to `libc::EBADF` (invalid file descriptor). + /// + /// This function uses `T: From` instead of `i32` directly because some IO related + /// functions return different integer types (like `read`, that returns an `i64`) fn remove_handle_and>(&mut self, fd: i32, mut f: F) -> InterpResult<'tcx, T> where F: FnMut(FileHandle, &mut MiriEvalContext<'mir, 'tcx>) -> InterpResult<'tcx, T>, @@ -177,6 +195,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } + /// Helper function that consumes an `std::io::Result` and returns an + /// `InterpResult<'tcx,T>::Ok` instead. It is expected that the result can be converted to an + /// OS error using `std::io::Error::raw_os_error`. + /// + /// This function uses `T: From` instead of `i32` directly because some IO related + /// functions return different integer types (like `read`, that returns an `i64`) fn consume_result>(&mut self, result: std::io::Result) -> InterpResult<'tcx, T> { match result { Ok(ok) => Ok(ok), From cd495cb04f10eb2149f3a57bc0310af4c8c3ac3b Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Mon, 30 Sep 2019 11:46:07 -0500 Subject: [PATCH 1155/3747] Add file writing capabilities --- src/shims/foreign_items.rs | 4 +-- src/shims/io.rs | 62 +++++++++++++++++++++++++++++++++---- tests/hello.txt | 1 - tests/run-pass/file_read.rs | 10 ++++-- 4 files changed, 65 insertions(+), 12 deletions(-) delete mode 100644 tests/hello.txt diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index b8609fd2ef092..847169f38dca6 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -494,9 +494,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Err(_) => -1, } } else { - eprintln!("Miri: Ignored output to FD {}", fd); - // Pretend it all went well. - n as i64 + this.write(args[0], args[1], args[2])? }; // Now, `result` is the value we return back to the program. this.write_scalar( diff --git a/src/shims/io.rs b/src/shims/io.rs index 0d1adcce6526d..afb6e6311e727 100644 --- a/src/shims/io.rs +++ b/src/shims/io.rs @@ -1,6 +1,6 @@ use std::collections::HashMap; -use std::fs::File; -use std::io::Read; +use std::fs::{ File, OpenOptions }; +use std::io::{ Read, Write }; use rustc::ty::layout::Size; @@ -42,8 +42,29 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let flag = this.read_scalar(flag_op)?.to_i32()?; - if flag != this.eval_libc_i32("O_RDONLY")? && flag != this.eval_libc_i32("O_CLOEXEC")? { - throw_unsup_format!("Unsupported flag {:#x}", flag); + let mut options = OpenOptions::new(); + + // The first two bits of the flag correspond to the access mode of the file in linux. + let access_mode = flag & 0b11; + + if access_mode == this.eval_libc_i32("O_RDONLY")? { + options.read(true); + } else if access_mode == this.eval_libc_i32("O_WRONLY")? { + options.write(true); + } else if access_mode == this.eval_libc_i32("O_RDWR")? { + options.read(true).write(true); + } else { + throw_unsup_format!("Unsupported access mode {:#x}", access_mode); + } + + if flag & this.eval_libc_i32("O_APPEND")? != 0 { + options.append(true); + } + if flag & this.eval_libc_i32("O_TRUNC")? != 0 { + options.truncate(true); + } + if flag & this.eval_libc_i32("O_CREAT")? != 0 { + options.create(true); } let path_bytes = this @@ -51,7 +72,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx .read_c_str(this.read_scalar(path_op)?.not_undef()?)?; let path = std::str::from_utf8(path_bytes) .map_err(|_| err_unsup_format!("{:?} is not a valid utf-8 string", path_bytes))?; - let fd = File::open(path).map(|file| { + + let fd = options.open(path).map(|file| { let mut fh = &mut this.machine.file_handler; fh.low += 1; fh.handles.insert(fh.low, FileHandle { file, flag }); @@ -151,8 +173,36 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) } + fn write( + &mut self, + fd_op: OpTy<'tcx, Tag>, + buf_op: OpTy<'tcx, Tag>, + count_op: OpTy<'tcx, Tag>, + ) -> InterpResult<'tcx, i64> { + let this = self.eval_context_mut(); + + if !this.machine.communicate { + throw_unsup_format!("`write` not available when isolation is enabled") + } + + let tcx = &{ this.tcx.tcx }; + + let fd = this.read_scalar(fd_op)?.to_i32()?; + let buf = this.force_ptr(this.read_scalar(buf_op)?.not_undef()?)?; + let count = this.read_scalar(count_op)?.to_usize(&*this.tcx)?; + + // `to_vec` is needed to avoid borrowing issues when writing to the file. + let bytes = this.memory().get(buf.alloc_id)?.get_bytes(tcx, buf, Size::from_bytes(count))?.to_vec(); + + this.remove_handle_and(fd, |mut handle, this| { + let bytes = handle.file.write(&bytes).map(|bytes| bytes as i64); + this.machine.file_handler.handles.insert(fd, handle); + this.consume_result(bytes) + }) + } + /// Helper function that gets a `FileHandle` immutable reference and allows to manipulate it - /// using `f`. + /// using the `f` closure. /// /// If the `fd` file descriptor does not corresponds to a file, this functions returns `Ok(-1)` /// and sets `Evaluator::last_error` to `libc::EBADF` (invalid file descriptor). diff --git a/tests/hello.txt b/tests/hello.txt deleted file mode 100644 index 8ab686eafeb1f..0000000000000 --- a/tests/hello.txt +++ /dev/null @@ -1 +0,0 @@ -Hello, World! diff --git a/tests/run-pass/file_read.rs b/tests/run-pass/file_read.rs index a60640d1b3c34..b0f2618920bf8 100644 --- a/tests/run-pass/file_read.rs +++ b/tests/run-pass/file_read.rs @@ -2,10 +2,16 @@ // compile-flags: -Zmiri-disable-isolation use std::fs::File; -use std::io::Read; +use std::io::{ Read, Write }; fn main() { - // FIXME: create the file and delete it when `rm` is implemented. + // FIXME: remove the file and delete it when `rm` is implemented. + + // Test creating, writing and closing a file (closing is tested when `file` is dropped). + let mut file = File::create("./tests/hello.txt").unwrap(); + file.write(b"Hello, World!\n").unwrap(); + + // Test opening, reading and closing a file. let mut file = File::open("./tests/hello.txt").unwrap(); let mut contents = String::new(); file.read_to_string(&mut contents).unwrap(); From 5a05c04c857538a60cd006455686124162f736dc Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Tue, 1 Oct 2019 10:57:12 -0500 Subject: [PATCH 1156/3747] Correct name of each shim when erroring --- src/shims/io.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/shims/io.rs b/src/shims/io.rs index afb6e6311e727..9f08141eb3b07 100644 --- a/src/shims/io.rs +++ b/src/shims/io.rs @@ -92,7 +92,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); if !this.machine.communicate { - throw_unsup_format!("`open` not available when isolation is enabled") + throw_unsup_format!("`fcntl` not available when isolation is enabled") } let fd = this.read_scalar(fd_op)?.to_i32()?; @@ -125,7 +125,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); if !this.machine.communicate { - throw_unsup_format!("`open` not available when isolation is enabled") + throw_unsup_format!("`close` not available when isolation is enabled") } let fd = this.read_scalar(fd_op)?.to_i32()?; @@ -145,7 +145,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); if !this.machine.communicate { - throw_unsup_format!("`open` not available when isolation is enabled") + throw_unsup_format!("`read` not available when isolation is enabled") } let tcx = &{ this.tcx.tcx }; @@ -204,7 +204,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// Helper function that gets a `FileHandle` immutable reference and allows to manipulate it /// using the `f` closure. /// - /// If the `fd` file descriptor does not corresponds to a file, this functions returns `Ok(-1)` + /// If the `fd` file descriptor does not correspond to a file, this functions returns `Ok(-1)` /// and sets `Evaluator::last_error` to `libc::EBADF` (invalid file descriptor). /// /// This function uses `T: From` instead of `i32` directly because some IO related @@ -227,7 +227,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// to modify `MiriEvalContext` at the same time, so you can modify the handle and reinsert it /// using `f`. /// - /// If the `fd` file descriptor does not corresponds to a file, this functions returns `Ok(-1)` + /// If the `fd` file descriptor does not correspond to a file, this functions returns `Ok(-1)` /// and sets `Evaluator::last_error` to `libc::EBADF` (invalid file descriptor). /// /// This function uses `T: From` instead of `i32` directly because some IO related From 78e0d309efe507afab2e71a2e3a0f8bec1cd4f1a Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Tue, 1 Oct 2019 13:48:59 -0500 Subject: [PATCH 1157/3747] Avoid early return after handles are removed --- src/shims/io.rs | 55 ++++++++++++++++++++++++------------------------- 1 file changed, 27 insertions(+), 28 deletions(-) diff --git a/src/shims/io.rs b/src/shims/io.rs index 9f08141eb3b07..49ad06e0dffcd 100644 --- a/src/shims/io.rs +++ b/src/shims/io.rs @@ -1,6 +1,6 @@ use std::collections::HashMap; -use std::fs::{ File, OpenOptions }; -use std::io::{ Read, Write }; +use std::fs::{File, OpenOptions}; +use std::io::{Read, Write}; use rustc::ty::layout::Size; @@ -130,10 +130,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let fd = this.read_scalar(fd_op)?.to_i32()?; - this.remove_handle_and( - fd, - |handle, this| this.consume_result(handle.file.sync_all().map(|_| 0i32)), - ) + this.remove_handle_and(fd, |handle, this| { + this.consume_result(handle.file.sync_all().map(|_| 0i32)) + }) } fn read( @@ -155,22 +154,18 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let count = this.read_scalar(count_op)?.to_usize(&*this.tcx)?; // Remove the file handle to avoid borrowing issues - this.remove_handle_and( - fd, - |mut handle, this| { - let bytes = handle - .file - .read(this.memory_mut().get_mut(buf.alloc_id)?.get_bytes_mut( - tcx, - buf, - Size::from_bytes(count), - )?) - .map(|bytes| bytes as i64); - // Reinsert the file handle - this.machine.file_handler.handles.insert(fd, handle); - this.consume_result(bytes) - }, - ) + this.remove_handle_and(fd, |mut handle, this| { + // Don't use `?` to avoid returning before reinserting the handle + let bytes = this + .memory_mut() + .get_mut(buf.alloc_id).and_then(|alloc| + alloc.get_bytes_mut(tcx, buf, Size::from_bytes(count)) + .map(|buffer| handle.file.read(buffer).map(|bytes| bytes as i64)) + ); + // Reinsert the file handle + this.machine.file_handler.handles.insert(fd, handle); + this.consume_result(bytes?) + }) } fn write( @@ -191,13 +186,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let buf = this.force_ptr(this.read_scalar(buf_op)?.not_undef()?)?; let count = this.read_scalar(count_op)?.to_usize(&*this.tcx)?; - // `to_vec` is needed to avoid borrowing issues when writing to the file. - let bytes = this.memory().get(buf.alloc_id)?.get_bytes(tcx, buf, Size::from_bytes(count))?.to_vec(); - this.remove_handle_and(fd, |mut handle, this| { - let bytes = handle.file.write(&bytes).map(|bytes| bytes as i64); + let bytes = this.memory().get(buf.alloc_id).and_then(|alloc| { + alloc + .get_bytes(tcx, buf, Size::from_bytes(count)) + .map(|bytes| handle.file.write(bytes).map(|bytes| bytes as i64)) + }); this.machine.file_handler.handles.insert(fd, handle); - this.consume_result(bytes) + this.consume_result(bytes?) }) } @@ -251,7 +247,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// /// This function uses `T: From` instead of `i32` directly because some IO related /// functions return different integer types (like `read`, that returns an `i64`) - fn consume_result>(&mut self, result: std::io::Result) -> InterpResult<'tcx, T> { + fn consume_result>( + &mut self, + result: std::io::Result, + ) -> InterpResult<'tcx, T> { match result { Ok(ok) => Ok(ok), Err(e) => { From f5022b19d38777c72a308028663c7b6994d04648 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Wed, 2 Oct 2019 08:43:23 -0500 Subject: [PATCH 1158/3747] Fix dangling pointer bug for zero-sized reads --- src/shims/io.rs | 22 ++++++++++++++-------- tests/run-pass/file_read.rs | 20 ++++++++++++-------- 2 files changed, 26 insertions(+), 16 deletions(-) diff --git a/src/shims/io.rs b/src/shims/io.rs index 49ad06e0dffcd..9d3e3d261625b 100644 --- a/src/shims/io.rs +++ b/src/shims/io.rs @@ -150,21 +150,27 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let tcx = &{ this.tcx.tcx }; let fd = this.read_scalar(fd_op)?.to_i32()?; - let buf = this.force_ptr(this.read_scalar(buf_op)?.not_undef()?)?; + let buf_scalar = this.read_scalar(buf_op)?.not_undef()?; let count = this.read_scalar(count_op)?.to_usize(&*this.tcx)?; // Remove the file handle to avoid borrowing issues this.remove_handle_and(fd, |mut handle, this| { // Don't use `?` to avoid returning before reinserting the handle - let bytes = this - .memory_mut() - .get_mut(buf.alloc_id).and_then(|alloc| - alloc.get_bytes_mut(tcx, buf, Size::from_bytes(count)) - .map(|buffer| handle.file.read(buffer).map(|bytes| bytes as i64)) - ); + let bytes = + if count == 0 { + Ok(handle.file.read(&mut [])) + } else { + this.force_ptr(buf_scalar).and_then(|buf| this + .memory_mut() + .get_mut(buf.alloc_id).and_then(|alloc| + alloc.get_bytes_mut(tcx, buf, Size::from_bytes(count)) + .map(|buffer| handle.file.read(buffer)) + )) + + }; // Reinsert the file handle this.machine.file_handler.handles.insert(fd, handle); - this.consume_result(bytes?) + this.consume_result(bytes?.map(|bytes| bytes as i64)) }) } diff --git a/tests/run-pass/file_read.rs b/tests/run-pass/file_read.rs index b0f2618920bf8..a17f948980a93 100644 --- a/tests/run-pass/file_read.rs +++ b/tests/run-pass/file_read.rs @@ -6,14 +6,18 @@ use std::io::{ Read, Write }; fn main() { // FIXME: remove the file and delete it when `rm` is implemented. - + let path = "./tests/hello.txt"; + let bytes = b"Hello, World!\n"; // Test creating, writing and closing a file (closing is tested when `file` is dropped). - let mut file = File::create("./tests/hello.txt").unwrap(); - file.write(b"Hello, World!\n").unwrap(); - + let mut file = File::create(path).unwrap(); + file.write(bytes).unwrap(); // Test opening, reading and closing a file. - let mut file = File::open("./tests/hello.txt").unwrap(); - let mut contents = String::new(); - file.read_to_string(&mut contents).unwrap(); - assert_eq!("Hello, World!\n", contents); + let mut file = File::open(path).unwrap(); + let mut contents = Vec::new(); + // Reading 0 bytes should not fill `contents`. + file.read(&mut contents).unwrap(); + assert!(contents.is_empty()); + // Reading until EOF should get the whole text. + file.read_to_end(&mut contents).unwrap(); + assert_eq!(bytes, contents.as_slice()); } From 6c36a8c949a3e506b48481d746df85e6596d097d Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Wed, 2 Oct 2019 08:50:32 -0500 Subject: [PATCH 1159/3747] Return earlier when reading/writing 0 bytes --- src/shims/io.rs | 30 ++++++++++++++++-------------- tests/run-pass/file_read.rs | 10 ++++++---- 2 files changed, 22 insertions(+), 18 deletions(-) diff --git a/src/shims/io.rs b/src/shims/io.rs index 9d3e3d261625b..74b8dde5c7fcb 100644 --- a/src/shims/io.rs +++ b/src/shims/io.rs @@ -149,25 +149,23 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let tcx = &{ this.tcx.tcx }; + let count = this.read_scalar(count_op)?.to_usize(&*this.tcx)?; + // Reading zero bytes should not change `buf` + if count == 0 { + return Ok(0); + } let fd = this.read_scalar(fd_op)?.to_i32()?; let buf_scalar = this.read_scalar(buf_op)?.not_undef()?; - let count = this.read_scalar(count_op)?.to_usize(&*this.tcx)?; // Remove the file handle to avoid borrowing issues this.remove_handle_and(fd, |mut handle, this| { // Don't use `?` to avoid returning before reinserting the handle - let bytes = - if count == 0 { - Ok(handle.file.read(&mut [])) - } else { - this.force_ptr(buf_scalar).and_then(|buf| this - .memory_mut() - .get_mut(buf.alloc_id).and_then(|alloc| - alloc.get_bytes_mut(tcx, buf, Size::from_bytes(count)) - .map(|buffer| handle.file.read(buffer)) - )) - - }; + let bytes = this.force_ptr(buf_scalar).and_then(|buf| { + this.memory_mut() + .get_mut(buf.alloc_id)? + .get_bytes_mut(tcx, buf, Size::from_bytes(count)) + .map(|buffer| handle.file.read(buffer)) + }); // Reinsert the file handle this.machine.file_handler.handles.insert(fd, handle); this.consume_result(bytes?.map(|bytes| bytes as i64)) @@ -188,9 +186,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let tcx = &{ this.tcx.tcx }; + let count = this.read_scalar(count_op)?.to_usize(&*this.tcx)?; + // Writing zero bytes should not change `buf` + if count == 0 { + return Ok(0); + } let fd = this.read_scalar(fd_op)?.to_i32()?; let buf = this.force_ptr(this.read_scalar(buf_op)?.not_undef()?)?; - let count = this.read_scalar(count_op)?.to_usize(&*this.tcx)?; this.remove_handle_and(fd, |mut handle, this| { let bytes = this.memory().get(buf.alloc_id).and_then(|alloc| { diff --git a/tests/run-pass/file_read.rs b/tests/run-pass/file_read.rs index a17f948980a93..666abd65c12e1 100644 --- a/tests/run-pass/file_read.rs +++ b/tests/run-pass/file_read.rs @@ -2,7 +2,7 @@ // compile-flags: -Zmiri-disable-isolation use std::fs::File; -use std::io::{ Read, Write }; +use std::io::{Read, Write}; fn main() { // FIXME: remove the file and delete it when `rm` is implemented. @@ -10,13 +10,15 @@ fn main() { let bytes = b"Hello, World!\n"; // Test creating, writing and closing a file (closing is tested when `file` is dropped). let mut file = File::create(path).unwrap(); + // Writing 0 bytes should not change the file contents. + file.write(&mut []).unwrap(); + file.write(bytes).unwrap(); // Test opening, reading and closing a file. let mut file = File::open(path).unwrap(); let mut contents = Vec::new(); - // Reading 0 bytes should not fill `contents`. - file.read(&mut contents).unwrap(); - assert!(contents.is_empty()); + // Reading 0 bytes should not move the file pointer. + file.read(&mut []).unwrap(); // Reading until EOF should get the whole text. file.read_to_end(&mut contents).unwrap(); assert_eq!(bytes, contents.as_slice()); From 0c4003631d011ba569e49e6d1a63b90e92db3a49 Mon Sep 17 00:00:00 2001 From: Nicolas Date: Sat, 5 Oct 2019 06:12:37 -0300 Subject: [PATCH 1160/3747] Add missing atomic_fence intrinsics as nops Fixes #972 --- src/shims/intrinsics.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 06af6db76ae6b..875a344363a01 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -88,7 +88,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(val, place.into())?; } - "atomic_fence_acq" => { + "atomic_fence_acq" | + "atomic_fence_rel" | + "atomic_fence_acqrel" | + "atomic_fence" => { // we are inherently singlethreaded and singlecored, this is a nop } From bd4a2996d1ac30e49adfcb241cb8a436730c35ac Mon Sep 17 00:00:00 2001 From: Nicolas Date: Sat, 5 Oct 2019 08:09:23 -0300 Subject: [PATCH 1161/3747] Add test for atomic fences --- tests/run-pass/atomic.rs | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/tests/run-pass/atomic.rs b/tests/run-pass/atomic.rs index f0b8ec06b905c..5872a496dbfa4 100644 --- a/tests/run-pass/atomic.rs +++ b/tests/run-pass/atomic.rs @@ -1,9 +1,10 @@ -use std::sync::atomic::{AtomicBool, AtomicIsize, AtomicU64, Ordering::*}; +use std::sync::atomic::{fence, AtomicBool, AtomicIsize, AtomicU64, Ordering::*}; fn main() { atomic_bool(); atomic_isize(); atomic_u64(); + atomic_fences(); } fn atomic_bool() { @@ -57,6 +58,15 @@ fn atomic_u64() { ATOMIC.store(1, SeqCst); assert_eq!(ATOMIC.compare_exchange(0, 0x100, AcqRel, Acquire), Err(1)); - assert_eq!(ATOMIC.compare_exchange_weak(1, 0x100, AcqRel, Acquire), Ok(1)); + assert_eq!( + ATOMIC.compare_exchange_weak(1, 0x100, AcqRel, Acquire), + Ok(1) + ); assert_eq!(ATOMIC.load(Relaxed), 0x100); } + +fn atomic_fences() { + fence(SeqCst); + fence(Release); + fence(Acquire); +} From 2b3b865c285dc090eb49d8e5ed93165a69c6c498 Mon Sep 17 00:00:00 2001 From: YOUNGSUK_KIM Date: Sat, 5 Oct 2019 17:11:09 -0400 Subject: [PATCH 1162/3747] change cargo-miri.rs to fix issue #978 --- src/bin/cargo-miri.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 43e8761d48c17..1f1705a49ac95 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -333,7 +333,14 @@ path = "lib.rs" None => true, Some(target) => target == rustc_version::version_meta().unwrap().host, }; - let sysroot = if is_host { dir.join("HOST") } else { PathBuf::from(dir) }; + let mut sysroot = if is_host { dir.join("HOST") } else { PathBuf::from(dir) }; + if cfg!(target_os = "windows") { + // Replace backslashes in path to slashes as they cause problems. + // Win10 Powershell can work with slashes in paths. + sysroot = PathBuf::from( + String::from(sysroot.to_str().unwrap()).replace("\\", "/") + ); + } std::env::set_var("MIRI_SYSROOT", &sysroot); // pass the env var to the processes we spawn, which will turn it into "--sysroot" flags if print_env { println!("MIRI_SYSROOT={}", sysroot.display()); From 905c70cfa55a42af4f5e90a4e5cf0bebc307150c Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Mon, 7 Oct 2019 08:39:59 -0500 Subject: [PATCH 1163/3747] Rustfmt --- src/eval.rs | 64 ++++++---- src/machine.rs | 67 ++++++---- src/shims/foreign_items.rs | 246 ++++++++++++++++++++----------------- 3 files changed, 214 insertions(+), 163 deletions(-) diff --git a/src/eval.rs b/src/eval.rs index 1b7c082ec37ba..21395cb311fa3 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -3,16 +3,15 @@ use rand::rngs::StdRng; use rand::SeedableRng; -use syntax::source_map::DUMMY_SP; -use rustc::ty::{self, TyCtxt}; -use rustc::ty::layout::{LayoutOf, Size, Align}; use rustc::hir::def_id::DefId; +use rustc::ty::layout::{Align, LayoutOf, Size}; +use rustc::ty::{self, TyCtxt}; +use syntax::source_map::DUMMY_SP; use crate::{ - InterpResult, InterpError, InterpCx, StackPopCleanup, struct_error, - Scalar, Tag, Pointer, FnVal, - MemoryExtra, MiriMemoryKind, Evaluator, TlsEvalContextExt, HelpersEvalContextExt, - EnvVars, + struct_error, EnvVars, Evaluator, FnVal, HelpersEvalContextExt, InterpCx, InterpError, + InterpResult, MemoryExtra, MiriMemoryKind, Pointer, Scalar, StackPopCleanup, Tag, + TlsEvalContextExt, }; /// Configuration needed to spawn a Miri instance. @@ -40,7 +39,10 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( tcx.at(syntax::source_map::DUMMY_SP), ty::ParamEnv::reveal_all(), Evaluator::new(config.communicate), - MemoryExtra::new(StdRng::seed_from_u64(config.seed.unwrap_or(0)), config.validate), + MemoryExtra::new( + StdRng::seed_from_u64(config.seed.unwrap_or(0)), + config.validate, + ), ); // Complete initialization. EnvVars::init(&mut ecx, config.excluded_env_vars); @@ -50,9 +52,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( let main_mir = ecx.load_mir(main_instance.def, None)?; if !main_mir.return_ty().is_unit() || main_mir.arg_count != 0 { - throw_unsup_format!( - "miri does not support main functions without `fn()` type signatures" - ); + throw_unsup_format!("miri does not support main functions without `fn()` type signatures"); } let start_id = tcx.lang_items().start_fn().unwrap(); @@ -62,9 +62,10 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( ecx.tcx.tcx, ty::ParamEnv::reveal_all(), start_id, - ecx.tcx.mk_substs( - ::std::iter::once(ty::subst::GenericArg::from(main_ret_ty))) - ).unwrap(); + ecx.tcx + .mk_substs(::std::iter::once(ty::subst::GenericArg::from(main_ret_ty))), + ) + .unwrap(); let start_mir = ecx.load_mir(start_instance.def, None)?; if start_mir.arg_count != 3 { @@ -91,7 +92,9 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( let mut args = ecx.frame().body.args_iter(); // First argument: pointer to `main()`. - let main_ptr = ecx.memory_mut().create_fn_alloc(FnVal::Instance(main_instance)); + let main_ptr = ecx + .memory_mut() + .create_fn_alloc(FnVal::Instance(main_instance)); let dest = ecx.local_place(args.next().unwrap())?; ecx.write_scalar(Scalar::Ptr(main_ptr), dest)?; @@ -124,16 +127,23 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( // Add `0` terminator. let mut arg = arg.into_bytes(); arg.push(0); - argvs.push(ecx.memory_mut().allocate_static_bytes(arg.as_slice(), MiriMemoryKind::Static.into())); + argvs.push( + ecx.memory_mut() + .allocate_static_bytes(arg.as_slice(), MiriMemoryKind::Static.into()), + ); } // Make an array with all these pointers, in the Miri memory. - let argvs_layout = ecx.layout_of(ecx.tcx.mk_array(ecx.tcx.mk_imm_ptr(ecx.tcx.types.u8), argvs.len() as u64))?; + let argvs_layout = ecx.layout_of( + ecx.tcx + .mk_array(ecx.tcx.mk_imm_ptr(ecx.tcx.types.u8), argvs.len() as u64), + )?; let argvs_place = ecx.allocate(argvs_layout, MiriMemoryKind::Env.into()); for (idx, arg) in argvs.into_iter().enumerate() { let place = ecx.mplace_field(argvs_place, idx as u64)?; ecx.write_scalar(Scalar::Ptr(arg), place.into())?; } - ecx.memory_mut().mark_immutable(argvs_place.ptr.assert_ptr().alloc_id)?; + ecx.memory_mut() + .mark_immutable(argvs_place.ptr.assert_ptr().alloc_id)?; // Write a pointer to that place as the argument. let argv = argvs_place.ptr; ecx.write_scalar(argv, dest)?; @@ -145,7 +155,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( } // Store command line as UTF-16 for Windows `GetCommandLineW`. { - let tcx = &{ecx.tcx.tcx}; + let tcx = &{ ecx.tcx.tcx }; let cmd_utf16: Vec = cmd.encode_utf16().collect(); let cmd_ptr = ecx.memory_mut().allocate( Size::from_bytes(cmd_utf16.len() as u64 * 2), @@ -168,16 +178,15 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( } } - assert!(args.next().is_none(), "start lang item has more arguments than expected"); + assert!( + args.next().is_none(), + "start lang item has more arguments than expected" + ); Ok(ecx) } -pub fn eval_main<'tcx>( - tcx: TyCtxt<'tcx>, - main_id: DefId, - config: MiriConfig, -) { +pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) { let mut ecx = match create_ecx(tcx, main_id, config) { Ok(ecx) => ecx, Err(mut err) => { @@ -228,8 +237,9 @@ pub fn eval_main<'tcx>( // We iterate with indices because we need to look at the next frame (the caller). for idx in 0..frames.len() { let frame_info = &frames[idx]; - let call_site_is_local = frames.get(idx+1).map_or(false, - |caller_info| caller_info.instance.def_id().is_local()); + let call_site_is_local = frames.get(idx + 1).map_or(false, |caller_info| { + caller_info.instance.def_id().is_local() + }); if call_site_is_local { err.span_note(frame_info.call_site, &frame_info.to_string()); } else { diff --git a/src/machine.rs b/src/machine.rs index 19be5b547ba84..c8962612c658b 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -1,24 +1,28 @@ //! Global machine state as well as implementation of the interpreter engine //! `Machine` trait. -use std::rc::Rc; use std::borrow::Cow; use std::cell::RefCell; +use std::rc::Rc; use rand::rngs::StdRng; -use syntax::attr; -use syntax::symbol::sym; use rustc::hir::def_id::DefId; -use rustc::ty::{self, Ty, TyCtxt, layout::{Size, LayoutOf}}; use rustc::mir; +use rustc::ty::{ + self, + layout::{LayoutOf, Size}, + Ty, TyCtxt, +}; +use syntax::attr; +use syntax::symbol::sym; use crate::*; // Some global facts about the emulated machine. -pub const PAGE_SIZE: u64 = 4*1024; // FIXME: adjust to target architecture -pub const STACK_ADDR: u64 = 32*PAGE_SIZE; // not really about the "stack", but where we start assigning integer addresses to allocations -pub const STACK_SIZE: u64 = 16*PAGE_SIZE; // whatever +pub const PAGE_SIZE: u64 = 4 * 1024; // FIXME: adjust to target architecture +pub const STACK_ADDR: u64 = 32 * PAGE_SIZE; // not really about the "stack", but where we start assigning integer addresses to allocations +pub const STACK_SIZE: u64 = 16 * PAGE_SIZE; // whatever pub const NUM_CPUS: u64 = 1; /// Extra memory kinds @@ -146,7 +150,13 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { type PointerTag = Tag; type ExtraFnVal = Dlsym; - type MemoryMap = MonoHashMap, Allocation)>; + type MemoryMap = MonoHashMap< + AllocId, + ( + MemoryKind, + Allocation, + ), + >; const STATIC_KIND: Option = Some(MiriMemoryKind::Static); @@ -264,8 +274,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { } #[inline(always)] - fn before_terminator(_ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx> - { + fn before_terminator(_ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx> { // We are not interested in detecting loops. Ok(()) } @@ -275,7 +284,10 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { id: AllocId, alloc: Cow<'b, Allocation>, kind: Option>, - ) -> (Cow<'b, Allocation>, Self::PointerTag) { + ) -> ( + Cow<'b, Allocation>, + Self::PointerTag, + ) { let kind = kind.expect("we set our STATIC_KIND so this cannot be None"); let alloc = alloc.into_owned(); let (stacks, base_tag) = if !memory_extra.validate { @@ -291,12 +303,14 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { }; let mut stacked_borrows = memory_extra.stacked_borrows.borrow_mut(); let alloc: Allocation = alloc.with_tags_and_extra( - |alloc| if !memory_extra.validate { - Tag::Untagged - } else { - // Only statics may already contain pointers at this point - assert_eq!(kind, MiriMemoryKind::Static.into()); - stacked_borrows.static_base_ptr(alloc) + |alloc| { + if !memory_extra.validate { + Tag::Untagged + } else { + // Only statics may already contain pointers at this point + assert_eq!(kind, MiriMemoryKind::Static.into()); + stacked_borrows.static_base_ptr(alloc) + } }, AllocExtra { stacked_borrows: stacks, @@ -306,14 +320,14 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { } #[inline(always)] - fn tag_static_base_pointer( - memory_extra: &MemoryExtra, - id: AllocId, - ) -> Self::PointerTag { + fn tag_static_base_pointer(memory_extra: &MemoryExtra, id: AllocId) -> Self::PointerTag { if !memory_extra.validate { Tag::Untagged } else { - memory_extra.stacked_borrows.borrow_mut().static_base_ptr(id) + memory_extra + .stacked_borrows + .borrow_mut() + .static_base_ptr(id) } } @@ -325,7 +339,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { ) -> InterpResult<'tcx> { if !Self::enforce_validity(ecx) { // No tracking. - Ok(()) + Ok(()) } else { ecx.retag(kind, place) } @@ -343,7 +357,12 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { ecx: &mut InterpCx<'mir, 'tcx, Self>, extra: stacked_borrows::CallId, ) -> InterpResult<'tcx> { - Ok(ecx.memory().extra.stacked_borrows.borrow_mut().end_call(extra)) + Ok(ecx + .memory() + .extra + .stacked_borrows + .borrow_mut() + .end_call(extra)) } #[inline(always)] diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 847169f38dca6..985d75b03303f 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -1,9 +1,9 @@ use std::convert::TryInto; -use rustc_apfloat::Float; -use rustc::ty::layout::{Align, LayoutOf, Size}; use rustc::hir::def_id::DefId; use rustc::mir; +use rustc::ty::layout::{Align, LayoutOf, Size}; +use rustc_apfloat::Float; use syntax::attr; use syntax::symbol::sym; @@ -40,42 +40,33 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Align::from_bytes(prev_power_of_two(size)).unwrap() } - fn malloc( - &mut self, - size: u64, - zero_init: bool, - kind: MiriMemoryKind, - ) -> Scalar { + fn malloc(&mut self, size: u64, zero_init: bool, kind: MiriMemoryKind) -> Scalar { let this = self.eval_context_mut(); - let tcx = &{this.tcx.tcx}; + let tcx = &{ this.tcx.tcx }; if size == 0 { Scalar::from_int(0, this.pointer_size()) } else { let align = this.min_align(size, kind); - let ptr = this.memory_mut().allocate(Size::from_bytes(size), align, kind.into()); + let ptr = this + .memory_mut() + .allocate(Size::from_bytes(size), align, kind.into()); if zero_init { // We just allocated this, the access cannot fail this.memory_mut() - .get_mut(ptr.alloc_id).unwrap() - .write_repeat(tcx, ptr, 0, Size::from_bytes(size)).unwrap(); + .get_mut(ptr.alloc_id) + .unwrap() + .write_repeat(tcx, ptr, 0, Size::from_bytes(size)) + .unwrap(); } Scalar::Ptr(ptr) } } - fn free( - &mut self, - ptr: Scalar, - kind: MiriMemoryKind, - ) -> InterpResult<'tcx> { + fn free(&mut self, ptr: Scalar, kind: MiriMemoryKind) -> InterpResult<'tcx> { let this = self.eval_context_mut(); if !this.is_null(ptr)? { let ptr = this.force_ptr(ptr)?; - this.memory_mut().deallocate( - ptr, - None, - kind.into(), - )?; + this.memory_mut().deallocate(ptr, None, kind.into())?; } Ok(()) } @@ -92,22 +83,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if new_size == 0 { Ok(Scalar::from_int(0, this.pointer_size())) } else { - let new_ptr = this.memory_mut().allocate( - Size::from_bytes(new_size), - new_align, - kind.into() - ); + let new_ptr = + this.memory_mut() + .allocate(Size::from_bytes(new_size), new_align, kind.into()); Ok(Scalar::Ptr(new_ptr)) } } else { let old_ptr = this.force_ptr(old_ptr)?; let memory = this.memory_mut(); if new_size == 0 { - memory.deallocate( - old_ptr, - None, - kind.into(), - )?; + memory.deallocate(old_ptr, None, kind.into())?; Ok(Scalar::from_int(0, this.pointer_size())) } else { let new_ptr = memory.reallocate( @@ -139,7 +124,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx }; // Strip linker suffixes (seen on 32-bit macOS). let link_name = link_name.trim_end_matches("$UNIX2003"); - let tcx = &{this.tcx.tcx}; + let tcx = &{ this.tcx.tcx }; // First: functions that diverge. match link_name { @@ -151,8 +136,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let code = this.read_scalar(args[0])?.to_i32()?; return Err(InterpError::Exit(code).into()); } - _ => if dest.is_none() { - throw_unsup_format!("can't call (diverging) foreign function: {}", link_name); + _ => { + if dest.is_none() { + throw_unsup_format!("can't call (diverging) foreign function: {}", link_name); + } } } @@ -168,7 +155,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "calloc" => { let items = this.read_scalar(args[0])?.to_usize(this)?; let len = this.read_scalar(args[1])?.to_usize(this)?; - let size = items.checked_mul(len).ok_or_else(|| err_panic!(Overflow(mir::BinOp::Mul)))?; + let size = items + .checked_mul(len) + .ok_or_else(|| err_panic!(Overflow(mir::BinOp::Mul)))?; let res = this.malloc(size, /*zero_init:*/ true, MiriMemoryKind::C); this.write_scalar(res, dest)?; } @@ -193,7 +182,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let ptr = this.memory_mut().allocate( Size::from_bytes(size), Align::from_bytes(align).unwrap(), - MiriMemoryKind::C.into() + MiriMemoryKind::C.into(), ); this.write_scalar(Scalar::Ptr(ptr), ret.into())?; } @@ -219,12 +208,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if !align.is_power_of_two() { throw_unsup!(HeapAllocNonPowerOfTwoAlignment(align)); } - let ptr = this.memory_mut() - .allocate( - Size::from_bytes(size), - Align::from_bytes(align).unwrap(), - MiriMemoryKind::Rust.into() - ); + let ptr = this.memory_mut().allocate( + Size::from_bytes(size), + Align::from_bytes(align).unwrap(), + MiriMemoryKind::Rust.into(), + ); this.write_scalar(Scalar::Ptr(ptr), dest)?; } "__rust_alloc_zeroed" => { @@ -236,16 +224,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if !align.is_power_of_two() { throw_unsup!(HeapAllocNonPowerOfTwoAlignment(align)); } - let ptr = this.memory_mut() - .allocate( - Size::from_bytes(size), - Align::from_bytes(align).unwrap(), - MiriMemoryKind::Rust.into() - ); + let ptr = this.memory_mut().allocate( + Size::from_bytes(size), + Align::from_bytes(align).unwrap(), + MiriMemoryKind::Rust.into(), + ); // We just allocated this, the access cannot fail this.memory_mut() - .get_mut(ptr.alloc_id).unwrap() - .write_repeat(tcx, ptr, 0, Size::from_bytes(size)).unwrap(); + .get_mut(ptr.alloc_id) + .unwrap() + .write_repeat(tcx, ptr, 0, Size::from_bytes(size)) + .unwrap(); this.write_scalar(Scalar::Ptr(ptr), dest)?; } "__rust_dealloc" => { @@ -261,7 +250,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let ptr = this.force_ptr(ptr)?; this.memory_mut().deallocate( ptr, - Some((Size::from_bytes(old_size), Align::from_bytes(align).unwrap())), + Some(( + Size::from_bytes(old_size), + Align::from_bytes(align).unwrap(), + )), MiriMemoryKind::Rust.into(), )?; } @@ -288,7 +280,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "syscall" => { - let sys_getrandom = this.eval_path_scalar(&["libc", "SYS_getrandom"])? + let sys_getrandom = this + .eval_path_scalar(&["libc", "SYS_getrandom"])? .expect("Failed to get libc::SYS_getrandom") .to_usize(this)?; @@ -300,9 +293,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // so skip over it. linux_getrandom(this, &args[1..], dest)?; } - id => { - throw_unsup_format!("miri does not support syscall ID {}", id) - } + id => throw_unsup_format!("miri does not support syscall ID {}", id), } } @@ -342,7 +333,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // TODO: consider making this reusable? `InterpCx::step` does something similar // for the TLS destructors, and of course `eval_main`. let mir = this.load_mir(f_instance.def, None)?; - let ret_place = MPlaceTy::dangling(this.layout_of(this.tcx.mk_unit())?, this).into(); + let ret_place = + MPlaceTy::dangling(this.layout_of(this.tcx.mk_unit())?, this).into(); this.push_stack_frame( f_instance, mir.span, @@ -353,12 +345,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx )?; let mut args = this.frame().body.args_iter(); - let arg_local = args.next() + let arg_local = args + .next() .expect("Argument to __rust_maybe_catch_panic does not take enough arguments."); let arg_dest = this.local_place(arg_local)?; this.write_scalar(data, arg_dest)?; - assert!(args.next().is_none(), "__rust_maybe_catch_panic argument has more arguments than expected"); + assert!( + args.next().is_none(), + "__rust_maybe_catch_panic argument has more arguments than expected" + ); // We ourselves will return `0`, eventually (because we will not return if we paniced). this.write_null(dest)?; @@ -384,18 +380,19 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } }; - this.write_scalar( - Scalar::from_int(result, Size::from_bits(32)), - dest, - )?; + this.write_scalar(Scalar::from_int(result, Size::from_bits(32)), dest)?; } "memrchr" => { let ptr = this.read_scalar(args[0])?.not_undef()?; let val = this.read_scalar(args[1])?.to_i32()? as u8; let num = this.read_scalar(args[2])?.to_usize(this)?; - if let Some(idx) = this.memory().read_bytes(ptr, Size::from_bytes(num))? - .iter().rev().position(|&c| c == val) + if let Some(idx) = this + .memory() + .read_bytes(ptr, Size::from_bytes(num))? + .iter() + .rev() + .position(|&c| c == val) { let new_ptr = ptr.ptr_offset(Size::from_bytes(num - idx as u64 - 1), this)?; this.write_scalar(new_ptr, dest)?; @@ -497,10 +494,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write(args[0], args[1], args[2])? }; // Now, `result` is the value we return back to the program. - this.write_scalar( - Scalar::from_int(result, dest.layout.size), - dest, - )?; + this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; } "strlen" => { @@ -510,8 +504,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // math functions - - "cbrtf" | "coshf" | "sinhf" |"tanf" => { + "cbrtf" | "coshf" | "sinhf" | "tanf" => { // FIXME: Using host floats. let f = f32::from_bits(this.read_scalar(args[0])?.to_u32()?); let f = match link_name { @@ -591,9 +584,18 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx trace!("sysconf() called with name {}", name); // TODO: Cache the sysconf integers via Miri's global cache. let paths = &[ - (&["libc", "_SC_PAGESIZE"], Scalar::from_int(PAGE_SIZE, dest.layout.size)), - (&["libc", "_SC_GETPW_R_SIZE_MAX"], Scalar::from_int(-1, dest.layout.size)), - (&["libc", "_SC_NPROCESSORS_ONLN"], Scalar::from_int(NUM_CPUS, dest.layout.size)), + ( + &["libc", "_SC_PAGESIZE"], + Scalar::from_int(PAGE_SIZE, dest.layout.size), + ), + ( + &["libc", "_SC_GETPW_R_SIZE_MAX"], + Scalar::from_int(-1, dest.layout.size), + ), + ( + &["libc", "_SC_NPROCESSORS_ONLN"], + Scalar::from_int(NUM_CPUS, dest.layout.size), + ), ]; let mut result = None; for &(path, path_value) in paths { @@ -603,7 +605,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx result = Some(path_value); break; } - } } if let Some(result) = result { @@ -644,11 +645,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Create key and write it into the memory where `key_ptr` wants it. let key = this.machine.tls.create_tls_key(dtor) as u128; - if key_layout.size.bits() < 128 && key >= (1u128 << key_layout.size.bits() as u128) { + if key_layout.size.bits() < 128 && key >= (1u128 << key_layout.size.bits() as u128) + { throw_unsup!(OutOfTls); } - let key_ptr = this.memory().check_ptr_access(key_ptr, key_layout.size, key_layout.align.abi)? + let key_ptr = this + .memory() + .check_ptr_access(key_ptr, key_layout.size, key_layout.align.abi)? .expect("cannot be a ZST"); this.memory_mut().get_mut(key_ptr.alloc_id)?.write_scalar( tcx, @@ -681,8 +685,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // Stack size/address stuff. - "pthread_attr_init" | "pthread_attr_destroy" | "pthread_self" | - "pthread_attr_setstacksize" => { + "pthread_attr_init" + | "pthread_attr_destroy" + | "pthread_self" + | "pthread_attr_setstacksize" => { this.write_null(dest)?; } "pthread_attr_getstack" => { @@ -708,12 +714,22 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // Stub out calls for condvar, mutex and rwlock, to just return `0`. - "pthread_mutexattr_init" | "pthread_mutexattr_settype" | "pthread_mutex_init" | - "pthread_mutexattr_destroy" | "pthread_mutex_lock" | "pthread_mutex_unlock" | - "pthread_mutex_destroy" | "pthread_rwlock_rdlock" | "pthread_rwlock_unlock" | - "pthread_rwlock_wrlock" | "pthread_rwlock_destroy" | "pthread_condattr_init" | - "pthread_condattr_setclock" | "pthread_cond_init" | "pthread_condattr_destroy" | - "pthread_cond_destroy" => { + "pthread_mutexattr_init" + | "pthread_mutexattr_settype" + | "pthread_mutex_init" + | "pthread_mutexattr_destroy" + | "pthread_mutex_lock" + | "pthread_mutex_unlock" + | "pthread_mutex_destroy" + | "pthread_rwlock_rdlock" + | "pthread_rwlock_unlock" + | "pthread_rwlock_wrlock" + | "pthread_rwlock_destroy" + | "pthread_condattr_init" + | "pthread_condattr_setclock" + | "pthread_cond_init" + | "pthread_condattr_destroy" + | "pthread_cond_destroy" => { this.write_null(dest)?; } @@ -745,13 +761,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "_tlv_atexit" => { // FIXME: register the destructor. - }, + } "_NSGetArgc" => { this.write_scalar(Scalar::Ptr(this.machine.argc.unwrap()), dest)?; - }, + } "_NSGetArgv" => { this.write_scalar(Scalar::Ptr(this.machine.argv.unwrap()), dest)?; - }, + } "SecRandomCopyBytes" => { let len = this.read_scalar(args[1])?.to_usize(this)?; let ptr = this.read_scalar(args[2])?.not_undef()?; @@ -802,32 +818,35 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "AddVectoredExceptionHandler" => { // Any non zero value works for the stdlib. This is just used for stack overflows anyway. this.write_scalar(Scalar::from_int(1, dest.layout.size), dest)?; - }, - "InitializeCriticalSection" | - "EnterCriticalSection" | - "LeaveCriticalSection" | - "DeleteCriticalSection" => { + } + "InitializeCriticalSection" + | "EnterCriticalSection" + | "LeaveCriticalSection" + | "DeleteCriticalSection" => { // Nothing to do, not even a return value. - }, - "GetModuleHandleW" | - "GetProcAddress" | - "TryEnterCriticalSection" | - "GetConsoleScreenBufferInfo" | - "SetConsoleTextAttribute" => { + } + "GetModuleHandleW" + | "GetProcAddress" + | "TryEnterCriticalSection" + | "GetConsoleScreenBufferInfo" + | "SetConsoleTextAttribute" => { // Pretend these do not exist / nothing happened, by returning zero. this.write_null(dest)?; - }, + } "GetSystemInfo" => { let system_info = this.deref_operand(args[0])?; - let system_info_ptr = this.check_mplace_access(system_info, None)? + let system_info_ptr = this + .check_mplace_access(system_info, None)? .expect("cannot be a ZST"); // Initialize with `0`. - this.memory_mut().get_mut(system_info_ptr.alloc_id)? + this.memory_mut() + .get_mut(system_info_ptr.alloc_id)? .write_repeat(tcx, system_info_ptr, 0, system_info.layout.size)?; // Set number of processors. let dword_size = Size::from_bytes(4); - let offset = 2*dword_size + 3*tcx.pointer_size(); - this.memory_mut().get_mut(system_info_ptr.alloc_id)? + let offset = 2 * dword_size + 3 * tcx.pointer_size(); + this.memory_mut() + .get_mut(system_info_ptr.alloc_id)? .write_scalar( tcx, system_info_ptr.offset(offset, tcx)?, @@ -844,7 +863,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // 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) { + && key >= (1u128 << dest.layout.size.bits() as u128) + { throw_unsup!(OutOfTls); } this.write_scalar(Scalar::from_uint(key, dest.layout.size), dest)?; @@ -879,7 +899,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // stdout/stderr use std::io::{self, Write}; - let buf_cont = this.memory().read_bytes(buf, Size::from_bytes(u64::from(n)))?; + let buf_cont = this + .memory() + .read_bytes(buf, Size::from_bytes(u64::from(n)))?; let res = if handle == -11 { io::stdout().write(buf_cont) } else { @@ -922,9 +944,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // We can't execute anything else. - _ => { - throw_unsup_format!("can't call foreign function: {}", link_name) - } + _ => throw_unsup_format!("can't call foreign function: {}", link_name), } this.goto_block(Some(ret))?; @@ -934,7 +954,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// Evaluates the scalar at the specified path. Returns Some(val) /// if the path could be resolved, and None otherwise - fn eval_path_scalar(&mut self, path: &[&str]) -> InterpResult<'tcx, Option>> { + fn eval_path_scalar( + &mut self, + path: &[&str], + ) -> InterpResult<'tcx, Option>> { let this = self.eval_context_mut(); if let Ok(instance) = this.resolve_path(path) { let cid = GlobalId { @@ -949,8 +972,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } fn eval_libc_i32(&mut self, name: &str) -> InterpResult<'tcx, i32> { - self - .eval_context_mut() + self.eval_context_mut() .eval_path_scalar(&["libc", name])? .ok_or_else(|| err_unsup_format!("Path libc::{} cannot be resolved.", name).into()) .and_then(|scalar| scalar.to_i32()) From 11d7be9c6fc72c9337067e0713b06644d3574c45 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Thu, 3 Oct 2019 10:21:55 -0500 Subject: [PATCH 1164/3747] Move last_error into memory --- src/eval.rs | 7 +++++++ src/machine.rs | 4 ++-- src/shims/env.rs | 18 +++++++++++------- src/shims/foreign_items.rs | 38 ++++++++++++++++++++++++++++++++------ src/shims/io.rs | 11 ++++++++--- 5 files changed, 60 insertions(+), 18 deletions(-) diff --git a/src/eval.rs b/src/eval.rs index 21395cb311fa3..aa876d6617ce8 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -183,6 +183,13 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( "start lang item has more arguments than expected" ); + // Set the last_error to 0 + let errno_layout = ecx.layout_of(ecx.tcx.types.u32)?; + let errno_place = ecx.allocate(errno_layout, MiriMemoryKind::Static.into()); + ecx.write_scalar(Scalar::from_u32(0), errno_place.into())?; + let errno_ptr = ecx.check_mplace_access(errno_place.into(), Some(Size::from_bits(32)))?; + ecx.machine.last_error = errno_ptr; + Ok(ecx) } diff --git a/src/machine.rs b/src/machine.rs index c8962612c658b..c22b3805d46ba 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -92,7 +92,7 @@ pub struct Evaluator<'tcx> { pub(crate) cmd_line: Option>, /// Last OS error. - pub(crate) last_error: u32, + pub(crate) last_error: Option>, /// TLS state. pub(crate) tls: TlsData<'tcx>, @@ -113,7 +113,7 @@ impl<'tcx> Evaluator<'tcx> { argc: None, argv: None, cmd_line: None, - last_error: 0, + last_error: None, tls: TlsData::default(), communicate, file_handler: Default::default(), diff --git a/src/shims/env.rs b/src/shims/env.rs index 074baa51f8263..23ba8d96567d1 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -137,18 +137,19 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if (bytes.len() as u64) < size { // We add a `/0` terminator bytes.push(0); - // This is ok because the buffer is larger than the path with the null terminator. + // This is ok because the buffer is larger than the path with terminatorhe null terminator. this.memory_mut() .get_mut(buf.alloc_id)? .write_bytes(tcx, buf, &bytes)?; return Ok(Scalar::Ptr(buf)); } - this.machine.last_error = this - .eval_path_scalar(&["libc", "ERANGE"])? - .unwrap() - .to_u32()?; + let erange = this.eval_libc("ERANGE")?; + this.set_last_error(erange)?; } - Err(e) => this.machine.last_error = e.raw_os_error().unwrap() as u32, + Err(e) => this.set_last_error(Scalar::from_int( + e.raw_os_error().unwrap(), + Size::from_bits(32), + ))?, } Ok(Scalar::ptr_null(&*this.tcx)) } @@ -172,7 +173,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx match env::set_current_dir(path) { Ok(()) => Ok(0), Err(e) => { - this.machine.last_error = e.raw_os_error().unwrap() as u32; + this.set_last_error(Scalar::from_int( + e.raw_os_error().unwrap(), + Size::from_bits(32), + ))?; Ok(-1) } } diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 985d75b03303f..76430260f7ec1 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -808,11 +808,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "SetLastError" => { - let err = this.read_scalar(args[0])?.to_u32()?; - this.machine.last_error = err; + this.set_last_error(this.read_scalar(args[0])?.not_undef()?)?; } "GetLastError" => { - this.write_scalar(Scalar::from_u32(this.machine.last_error), dest)?; + let last_error = this.get_last_error()?; + this.write_scalar(last_error, dest)?; } "AddVectoredExceptionHandler" => { @@ -929,7 +929,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "GetEnvironmentVariableW" => { // This is not the env var you are looking for. - this.machine.last_error = 203; // ERROR_ENVVAR_NOT_FOUND + this.set_last_error(Scalar::from_u32(203))?; // ERROR_ENVVAR_NOT_FOUND this.write_null(dest)?; } "GetCommandLineW" => { @@ -971,11 +971,37 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx return Ok(None); } - fn eval_libc_i32(&mut self, name: &str) -> InterpResult<'tcx, i32> { + fn eval_libc(&mut self, name: &str) -> InterpResult<'tcx, Scalar> { self.eval_context_mut() .eval_path_scalar(&["libc", name])? .ok_or_else(|| err_unsup_format!("Path libc::{} cannot be resolved.", name).into()) - .and_then(|scalar| scalar.to_i32()) + .and_then(|scalar| scalar.not_undef()) + } + + fn eval_libc_i32(&mut self, name: &str) -> InterpResult<'tcx, i32> { + self.eval_libc(name).and_then(|scalar| scalar.to_i32()) + } + + fn set_last_error(&mut self, scalar: Scalar) -> InterpResult<'tcx, ()> { + let this = self.eval_context_mut(); + let tcx = &{ this.tcx.tcx }; + let errno_ptr = this.machine.last_error.unwrap(); + this.memory_mut().get_mut(errno_ptr.alloc_id)?.write_scalar( + tcx, + errno_ptr, + scalar.into(), + Size::from_bits(32), + ) + } + + fn get_last_error(&mut self) -> InterpResult<'tcx, Scalar> { + let this = self.eval_context_mut(); + let tcx = &{ this.tcx.tcx }; + let errno_ptr = this.machine.last_error.unwrap(); + this.memory() + .get(errno_ptr.alloc_id)? + .read_scalar(tcx, errno_ptr, Size::from_bits(32))? + .not_undef() } } diff --git a/src/shims/io.rs b/src/shims/io.rs index 74b8dde5c7fcb..1eaebbf0b8870 100644 --- a/src/shims/io.rs +++ b/src/shims/io.rs @@ -221,7 +221,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if let Some(handle) = this.machine.file_handler.handles.get(&fd) { f(handle) } else { - this.machine.last_error = this.eval_libc_i32("EBADF")? as u32; + let ebadf = this.eval_libc("EBADF")?; + this.set_last_error(ebadf)?; Ok((-1).into()) } } @@ -244,7 +245,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if let Some(handle) = this.machine.file_handler.handles.remove(&fd) { f(handle, this) } else { - this.machine.last_error = this.eval_libc_i32("EBADF")? as u32; + let ebadf = this.eval_libc("EBADF")?; + this.set_last_error(ebadf)?; Ok((-1).into()) } } @@ -262,7 +264,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx match result { Ok(ok) => Ok(ok), Err(e) => { - self.eval_context_mut().machine.last_error = e.raw_os_error().unwrap() as u32; + self.eval_context_mut().set_last_error(Scalar::from_int( + e.raw_os_error().unwrap(), + Size::from_bits(32), + ))?; Ok((-1).into()) } } From 887d7481148101615fc1966864a14276350dbf65 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Thu, 3 Oct 2019 10:28:38 -0500 Subject: [PATCH 1165/3747] Add __errno_location shim --- src/shims/foreign_items.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 76430260f7ec1..fecd15b39283e 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -418,6 +418,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } + "__errno_location" => { + let errno_scalar: Scalar = this.machine.last_error.unwrap().into(); + this.write_scalar(errno_scalar, dest)?; + } + "getenv" => { let result = this.getenv(args[0])?; this.write_scalar(result, dest)?; From 459c65a4f9b2e462037e600a511b785c78dd8f0e Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Mon, 7 Oct 2019 08:38:54 -0500 Subject: [PATCH 1166/3747] Add method to consume io::Error --- src/shims/env.rs | 12 +++--------- src/shims/foreign_items.rs | 9 ++++++++- src/shims/io.rs | 5 +---- 3 files changed, 12 insertions(+), 14 deletions(-) diff --git a/src/shims/env.rs b/src/shims/env.rs index 23ba8d96567d1..f4b6a7c4dbac7 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -137,7 +137,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if (bytes.len() as u64) < size { // We add a `/0` terminator bytes.push(0); - // This is ok because the buffer is larger than the path with terminatorhe null terminator. + // This is ok because the buffer is larger than the path with the null terminator. this.memory_mut() .get_mut(buf.alloc_id)? .write_bytes(tcx, buf, &bytes)?; @@ -146,10 +146,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let erange = this.eval_libc("ERANGE")?; this.set_last_error(erange)?; } - Err(e) => this.set_last_error(Scalar::from_int( - e.raw_os_error().unwrap(), - Size::from_bits(32), - ))?, + Err(e) => this.consume_io_error(e)?, } Ok(Scalar::ptr_null(&*this.tcx)) } @@ -173,10 +170,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx match env::set_current_dir(path) { Ok(()) => Ok(0), Err(e) => { - this.set_last_error(Scalar::from_int( - e.raw_os_error().unwrap(), - Size::from_bits(32), - ))?; + this.consume_io_error(e)?; Ok(-1) } } diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index fecd15b39283e..3298eef85353c 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -987,7 +987,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx self.eval_libc(name).and_then(|scalar| scalar.to_i32()) } - fn set_last_error(&mut self, scalar: Scalar) -> InterpResult<'tcx, ()> { + fn set_last_error(&mut self, scalar: Scalar) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let tcx = &{ this.tcx.tcx }; let errno_ptr = this.machine.last_error.unwrap(); @@ -1008,6 +1008,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx .read_scalar(tcx, errno_ptr, Size::from_bits(32))? .not_undef() } + + fn consume_io_error(&mut self, e: std::io::Error) -> InterpResult<'tcx> { + self.eval_context_mut().set_last_error(Scalar::from_int( + e.raw_os_error().unwrap(), + Size::from_bits(32), + )) + } } // Shims the linux 'getrandom()' syscall. diff --git a/src/shims/io.rs b/src/shims/io.rs index 1eaebbf0b8870..ca3f500f5a47f 100644 --- a/src/shims/io.rs +++ b/src/shims/io.rs @@ -264,10 +264,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx match result { Ok(ok) => Ok(ok), Err(e) => { - self.eval_context_mut().set_last_error(Scalar::from_int( - e.raw_os_error().unwrap(), - Size::from_bits(32), - ))?; + self.eval_context_mut().consume_io_error(e)?; Ok((-1).into()) } } From ffc47de1b989ea4fe15162061c835ae13524d602 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Thu, 3 Oct 2019 09:33:36 -0500 Subject: [PATCH 1167/3747] Add unlink shim to delete files --- src/shims/foreign_items.rs | 5 +++++ src/shims/io.rs | 20 ++++++++++++++++++- .../{file_read.rs => file_manipulation.rs} | 5 +++-- 3 files changed, 27 insertions(+), 3 deletions(-) rename tests/run-pass/{file_read.rs => file_manipulation.rs} (89%) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 3298eef85353c..a96ed35b67a60 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -502,6 +502,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; } + "unlink" => { + let result = this.unlink(args[0])?; + this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + } + "strlen" => { let ptr = this.read_scalar(args[0])?.not_undef()?; let n = this.memory().read_c_str(ptr)?.len(); diff --git a/src/shims/io.rs b/src/shims/io.rs index ca3f500f5a47f..0893d0b4e0e85 100644 --- a/src/shims/io.rs +++ b/src/shims/io.rs @@ -1,5 +1,5 @@ use std::collections::HashMap; -use std::fs::{File, OpenOptions}; +use std::fs::{File, OpenOptions, remove_file}; use std::io::{Read, Write}; use rustc::ty::layout::Size; @@ -205,6 +205,24 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx }) } + fn unlink( &mut self, path_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + let this = self.eval_context_mut(); + + if !this.machine.communicate { + throw_unsup_format!("`write` not available when isolation is enabled") + } + + let path_bytes = this + .memory() + .read_c_str(this.read_scalar(path_op)?.not_undef()?)?; + let path = std::str::from_utf8(path_bytes) + .map_err(|_| err_unsup_format!("{:?} is not a valid utf-8 string", path_bytes))?; + + let result = remove_file(path).map(|_| 0); + + this.consume_result(result) + } + /// Helper function that gets a `FileHandle` immutable reference and allows to manipulate it /// using the `f` closure. /// diff --git a/tests/run-pass/file_read.rs b/tests/run-pass/file_manipulation.rs similarity index 89% rename from tests/run-pass/file_read.rs rename to tests/run-pass/file_manipulation.rs index 666abd65c12e1..3980cc0f74f51 100644 --- a/tests/run-pass/file_read.rs +++ b/tests/run-pass/file_manipulation.rs @@ -1,11 +1,10 @@ // ignore-windows: File handling is not implemented yet // compile-flags: -Zmiri-disable-isolation -use std::fs::File; +use std::fs::{File, remove_file}; use std::io::{Read, Write}; fn main() { - // FIXME: remove the file and delete it when `rm` is implemented. let path = "./tests/hello.txt"; let bytes = b"Hello, World!\n"; // Test creating, writing and closing a file (closing is tested when `file` is dropped). @@ -22,4 +21,6 @@ fn main() { // Reading until EOF should get the whole text. file.read_to_end(&mut contents).unwrap(); assert_eq!(bytes, contents.as_slice()); + // Removing file should succeed + remove_file(path).unwrap(); } From 00792493ef65da150ce5d3e4cc7c15660ce1b54a Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Tue, 8 Oct 2019 08:56:36 -0500 Subject: [PATCH 1168/3747] Add tests for non-existing files --- tests/run-pass/file_manipulation.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/run-pass/file_manipulation.rs b/tests/run-pass/file_manipulation.rs index 3980cc0f74f51..fa17efd7e1799 100644 --- a/tests/run-pass/file_manipulation.rs +++ b/tests/run-pass/file_manipulation.rs @@ -23,4 +23,8 @@ fn main() { assert_eq!(bytes, contents.as_slice()); // Removing file should succeed remove_file(path).unwrap(); + // Opening non-existing file should fail + assert!(File::open(path).is_err()); + // Removing non-existing file should fail + assert!(remove_file(path).is_err()); } From 187361996f6b85edc9001cfdc0081474986ed2b1 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Tue, 8 Oct 2019 09:25:26 -0500 Subject: [PATCH 1169/3747] Add errno_location shim for MacOS --- src/shims/foreign_items.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index a96ed35b67a60..9cd84d0b887ee 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -418,7 +418,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } - "__errno_location" => { + "__errno_location" | "__error" => { let errno_scalar: Scalar = this.machine.last_error.unwrap().into(); this.write_scalar(errno_scalar, dest)?; } From 62f08eb41682e2cd44890377d422ce8268d10ca4 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 9 Oct 2019 10:29:08 +0200 Subject: [PATCH 1170/3747] also test AcqRel fence --- tests/run-pass/atomic.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/run-pass/atomic.rs b/tests/run-pass/atomic.rs index 5872a496dbfa4..a9dd29bd62bf4 100644 --- a/tests/run-pass/atomic.rs +++ b/tests/run-pass/atomic.rs @@ -69,4 +69,5 @@ fn atomic_fences() { fence(SeqCst); fence(Release); fence(Acquire); + fence(AcqRel); } From c2e4c877c5c47a20cc66de848d6eb51b0f478dd9 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 9 Oct 2019 11:11:56 +0200 Subject: [PATCH 1171/3747] bump to latest nightly --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 2d311cc17704f..db6f5ebe88c44 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -d046ffddc4bd50e04ffc3ff9f766e2ac71f74d50 +2748a9fd93dd1a00a4521f4f16de5befbf77f6cd From 610dbdd562bc327f016a326c703073cee97dc645 Mon Sep 17 00:00:00 2001 From: YOUNGSUK_KIM Date: Thu, 10 Oct 2019 11:03:20 -0400 Subject: [PATCH 1172/3747] fixed cargo-miri bug for windows users --- src/bin/cargo-miri.rs | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 1f1705a49ac95..521ac8fa065ce 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -333,17 +333,11 @@ path = "lib.rs" None => true, Some(target) => target == rustc_version::version_meta().unwrap().host, }; - let mut sysroot = if is_host { dir.join("HOST") } else { PathBuf::from(dir) }; - if cfg!(target_os = "windows") { - // Replace backslashes in path to slashes as they cause problems. - // Win10 Powershell can work with slashes in paths. - sysroot = PathBuf::from( - String::from(sysroot.to_str().unwrap()).replace("\\", "/") - ); - } + let sysroot = if is_host { dir.join("HOST") } else { PathBuf::from(dir) }; + std::env::set_var("MIRI_SYSROOT", &sysroot); // pass the env var to the processes we spawn, which will turn it into "--sysroot" flags if print_env { - println!("MIRI_SYSROOT={}", sysroot.display()); + println!("MIRI_SYSROOT={:?}", &sysroot); // for Windows users, prints path with backslashes escaped. } else if !ask_user { println!("A libstd for Miri is now available in `{}`.", sysroot.display()); } From 976c976f0948ebfb080f51c733c5bbe24c366554 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Fri, 11 Oct 2019 01:49:28 -0500 Subject: [PATCH 1173/3747] Rename shims::io to shims::fs --- src/lib.rs | 2 +- src/shims/{io.rs => fs.rs} | 0 src/shims/mod.rs | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) rename src/shims/{io.rs => fs.rs} (100%) diff --git a/src/lib.rs b/src/lib.rs index 9f4e605b6c941..baae26d91adaa 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -34,7 +34,7 @@ pub use crate::shims::intrinsics::EvalContextExt as IntrinsicsEvalContextExt; pub use crate::shims::tls::{EvalContextExt as TlsEvalContextExt, TlsData}; pub use crate::shims::dlsym::{Dlsym, EvalContextExt as DlsymEvalContextExt}; pub use crate::shims::env::{EnvVars, EvalContextExt as EnvEvalContextExt}; -pub use crate::shims::io::{FileHandler, EvalContextExt as FileEvalContextExt}; +pub use crate::shims::fs::{FileHandler, EvalContextExt as FileEvalContextExt}; pub use crate::operator::EvalContextExt as OperatorEvalContextExt; pub use crate::range_map::RangeMap; pub use crate::helpers::{EvalContextExt as HelpersEvalContextExt}; diff --git a/src/shims/io.rs b/src/shims/fs.rs similarity index 100% rename from src/shims/io.rs rename to src/shims/fs.rs diff --git a/src/shims/mod.rs b/src/shims/mod.rs index 3df5b839e5d78..6d80af46850ca 100644 --- a/src/shims/mod.rs +++ b/src/shims/mod.rs @@ -3,7 +3,7 @@ pub mod env; pub mod foreign_items; pub mod intrinsics; pub mod tls; -pub mod io; +pub mod fs; use rustc::{mir, ty}; From c8df0171e84deb4563f30f9f1c3cf61e859315fb Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Fri, 11 Oct 2019 01:53:31 -0500 Subject: [PATCH 1174/3747] Move functions to eval libc constants to helpers --- src/helpers.rs | 11 +++++++++++ src/shims/foreign_items.rs | 11 ----------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index 3bee028c5eb7a..39c7af94e0ae7 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -291,4 +291,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } } + /// Helper function to get a `libc` constant as a `Scalar`. + fn eval_libc(&mut self, name: &str) -> InterpResult<'tcx, Scalar> { + self.eval_context_mut() + .eval_path_scalar(&["libc", name])? + .ok_or_else(|| err_unsup_format!("Path libc::{} cannot be resolved.", name).into()) + .and_then(|scalar| scalar.not_undef()) + } + /// Helper function to get a `libc` constant as an `i32`. + fn eval_libc_i32(&mut self, name: &str) -> InterpResult<'tcx, i32> { + self.eval_libc(name).and_then(|scalar| scalar.to_i32()) + } } diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 9cd84d0b887ee..00160156312a8 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -981,17 +981,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx return Ok(None); } - fn eval_libc(&mut self, name: &str) -> InterpResult<'tcx, Scalar> { - self.eval_context_mut() - .eval_path_scalar(&["libc", name])? - .ok_or_else(|| err_unsup_format!("Path libc::{} cannot be resolved.", name).into()) - .and_then(|scalar| scalar.not_undef()) - } - - fn eval_libc_i32(&mut self, name: &str) -> InterpResult<'tcx, i32> { - self.eval_libc(name).and_then(|scalar| scalar.to_i32()) - } - fn set_last_error(&mut self, scalar: Scalar) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let tcx = &{ this.tcx.tcx }; From 8368d4f2b44ae1441390a2f7eee48af340c8d70c Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Fri, 11 Oct 2019 02:35:50 -0500 Subject: [PATCH 1175/3747] Add comments to explain the chdir test --- tests/run-pass/{change_current_dir.rs => current_dir.rs} | 3 +++ 1 file changed, 3 insertions(+) rename tests/run-pass/{change_current_dir.rs => current_dir.rs} (66%) diff --git a/tests/run-pass/change_current_dir.rs b/tests/run-pass/current_dir.rs similarity index 66% rename from tests/run-pass/change_current_dir.rs rename to tests/run-pass/current_dir.rs index fa8220339db06..48045187ab15e 100644 --- a/tests/run-pass/change_current_dir.rs +++ b/tests/run-pass/current_dir.rs @@ -6,6 +6,9 @@ use std::path::Path; fn main() { // test that `getcwd` is available let cwd = env::current_dir().unwrap(); + // test that changing dir to `..` actually sets the current directory to the parent of `cwd`. + // the only exception here is if `cwd` is the root directory, then changing directory must + // keep the current directory equal to `cwd`. let parent = cwd.parent().unwrap_or(&cwd); // test that `chdir` is available assert!(env::set_current_dir(&Path::new("..")).is_ok()); From 12040aae885b8df967892ea1de420b9a35b42599 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Fri, 11 Oct 2019 03:36:34 -0500 Subject: [PATCH 1176/3747] Add comment explaining why buffer isn't overflowed --- src/shims/env.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/shims/env.rs b/src/shims/env.rs index f4b6a7c4dbac7..b39bde4dedc6e 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -133,11 +133,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(cwd) => { // It is not clear what happens with non-utf8 paths here let mut bytes = cwd.display().to_string().into_bytes(); - // If the buffer is smaller or equal than the path, we return null. + // If `size` is smaller or equal than the `bytes.len()`, writing `bytes` using the + // `buf` pointer would cause an overflow, the desired behavior in this case is to + // return null. if (bytes.len() as u64) < size { // We add a `/0` terminator bytes.push(0); - // This is ok because the buffer is larger than the path with the null terminator. + // This is ok because the buffer was strictly larger than `bytes`, so after + // adding the null terminator, the buffer size is larger or equal to + // `bytes.len()`, meaning that `bytes` actually fit inside tbe buffer. this.memory_mut() .get_mut(buf.alloc_id)? .write_bytes(tcx, buf, &bytes)?; From 1c64f29811db779bb202c3450c60c227fb0234bb Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Fri, 11 Oct 2019 03:55:18 -0500 Subject: [PATCH 1177/3747] Add comment for the flag diff check --- src/shims/fs.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/shims/fs.rs b/src/shims/fs.rs index 0893d0b4e0e85..7e684489b5c9c 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -107,6 +107,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if let Some(FileHandle { flag: old_flag, .. }) = this.machine.file_handler.handles.get_mut(&fd) { + // Check that the only difference between the old flag and the current flag is + // exactly the `FD_CLOEXEC` value. if flag ^ *old_flag == fd_cloexec { *old_flag = flag; } else { From ae9f4e1e63c8dfd8f860d6b28c5a192bd22de316 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Fri, 11 Oct 2019 03:31:11 -0500 Subject: [PATCH 1178/3747] Avoid using the tests folder for the file manipualtion test --- tests/run-pass/file_manipulation.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/run-pass/file_manipulation.rs b/tests/run-pass/file_manipulation.rs index fa17efd7e1799..98f3c1089bb77 100644 --- a/tests/run-pass/file_manipulation.rs +++ b/tests/run-pass/file_manipulation.rs @@ -5,7 +5,7 @@ use std::fs::{File, remove_file}; use std::io::{Read, Write}; fn main() { - let path = "./tests/hello.txt"; + let path = "miri_test_fs.txt"; let bytes = b"Hello, World!\n"; // Test creating, writing and closing a file (closing is tested when `file` is dropped). let mut file = File::create(path).unwrap(); From e9138ab4d63019a514fe5d531776fc1ecd37c307 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Fri, 11 Oct 2019 04:01:07 -0500 Subject: [PATCH 1179/3747] Rename file manipulation test to fs --- tests/run-pass/{file_manipulation.rs => fs.rs} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename tests/run-pass/{file_manipulation.rs => fs.rs} (100%) diff --git a/tests/run-pass/file_manipulation.rs b/tests/run-pass/fs.rs similarity index 100% rename from tests/run-pass/file_manipulation.rs rename to tests/run-pass/fs.rs From 67ea4546472edace0ae1d8fc97ae85bf5953e8a5 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Fri, 11 Oct 2019 04:17:43 -0500 Subject: [PATCH 1180/3747] Correct style of comments --- src/helpers.rs | 2 ++ src/shims/env.rs | 6 +++--- tests/run-pass/current_dir.rs | 10 +++++----- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index 39c7af94e0ae7..b2a462ef90675 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -291,6 +291,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } } + /// Helper function to get a `libc` constant as a `Scalar`. fn eval_libc(&mut self, name: &str) -> InterpResult<'tcx, Scalar> { self.eval_context_mut() @@ -298,6 +299,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx .ok_or_else(|| err_unsup_format!("Path libc::{} cannot be resolved.", name).into()) .and_then(|scalar| scalar.not_undef()) } + /// Helper function to get a `libc` constant as an `i32`. fn eval_libc_i32(&mut self, name: &str) -> InterpResult<'tcx, i32> { self.eval_libc(name).and_then(|scalar| scalar.to_i32()) diff --git a/src/shims/env.rs b/src/shims/env.rs index b39bde4dedc6e..6f32783d7a767 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -133,9 +133,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(cwd) => { // It is not clear what happens with non-utf8 paths here let mut bytes = cwd.display().to_string().into_bytes(); - // If `size` is smaller or equal than the `bytes.len()`, writing `bytes` using the - // `buf` pointer would cause an overflow, the desired behavior in this case is to - // return null. + // If `size` is smaller or equal than the `bytes.len()`, writing `bytes` plus the + // required null terminator to memory using the `buf` pointer would cause an + // overflow, the desired behavior in this case is to return null. if (bytes.len() as u64) < size { // We add a `/0` terminator bytes.push(0); diff --git a/tests/run-pass/current_dir.rs b/tests/run-pass/current_dir.rs index 48045187ab15e..5e896659c85ee 100644 --- a/tests/run-pass/current_dir.rs +++ b/tests/run-pass/current_dir.rs @@ -4,14 +4,14 @@ use std::env; use std::path::Path; fn main() { - // test that `getcwd` is available + // Test that `getcwd` is available let cwd = env::current_dir().unwrap(); - // test that changing dir to `..` actually sets the current directory to the parent of `cwd`. - // the only exception here is if `cwd` is the root directory, then changing directory must + // Test that changing dir to `..` actually sets the current directory to the parent of `cwd`. + // The only exception here is if `cwd` is the root directory, then changing directory must // keep the current directory equal to `cwd`. let parent = cwd.parent().unwrap_or(&cwd); - // test that `chdir` is available + // Test that `chdir` is available assert!(env::set_current_dir(&Path::new("..")).is_ok()); - // test that `..` goes to the parent directory + // Test that `..` goes to the parent directory assert_eq!(env::current_dir().unwrap(), parent); } From 60cf06a03fa06bc1c5e2981d4ad7f5496b06c62f Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Fri, 11 Oct 2019 04:20:18 -0500 Subject: [PATCH 1181/3747] Use existing tcx instead --- src/shims/env.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/shims/env.rs b/src/shims/env.rs index 6f32783d7a767..8c1645cde738e 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -127,7 +127,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let tcx = &{ this.tcx.tcx }; let buf = this.force_ptr(this.read_scalar(buf_op)?.not_undef()?)?; - let size = this.read_scalar(size_op)?.to_usize(&*this.tcx)?; + let size = this.read_scalar(size_op)?.to_usize(&*tcx)?; // If we cannot get the current directory, we return null match env::current_dir() { Ok(cwd) => { @@ -152,7 +152,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } Err(e) => this.consume_io_error(e)?, } - Ok(Scalar::ptr_null(&*this.tcx)) + Ok(Scalar::ptr_null(&*tcx)) } fn chdir(&mut self, path_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { From 003b257f87b94921594a46b4e0ad4dc22bb4cf4d Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Fri, 11 Oct 2019 08:20:32 -0500 Subject: [PATCH 1182/3747] Change error handling style for consistency --- src/helpers.rs | 6 +++--- src/shims/env.rs | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index b2a462ef90675..c7b7853388cc5 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -296,12 +296,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn eval_libc(&mut self, name: &str) -> InterpResult<'tcx, Scalar> { self.eval_context_mut() .eval_path_scalar(&["libc", name])? - .ok_or_else(|| err_unsup_format!("Path libc::{} cannot be resolved.", name).into()) - .and_then(|scalar| scalar.not_undef()) + .ok_or_else(|| err_unsup_format!("Path libc::{} cannot be resolved.", name))? + .not_undef() } /// Helper function to get a `libc` constant as an `i32`. fn eval_libc_i32(&mut self, name: &str) -> InterpResult<'tcx, i32> { - self.eval_libc(name).and_then(|scalar| scalar.to_i32()) + self.eval_libc(name)?.to_i32() } } diff --git a/src/shims/env.rs b/src/shims/env.rs index 8c1645cde738e..2ccbc0238e5f9 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -135,7 +135,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let mut bytes = cwd.display().to_string().into_bytes(); // If `size` is smaller or equal than the `bytes.len()`, writing `bytes` plus the // required null terminator to memory using the `buf` pointer would cause an - // overflow, the desired behavior in this case is to return null. + // overflow. The desired behavior in this case is to return null. if (bytes.len() as u64) < size { // We add a `/0` terminator bytes.push(0); From aa3e9703d180648af483a4d2304a9092debf365d Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Wed, 2 Oct 2019 13:17:58 -0500 Subject: [PATCH 1183/3747] Add clock_gettime shim --- src/shims/foreign_items.rs | 55 ++++++++++++++++++++++++++++++++------ tests/run-pass/clock.rs | 7 +++++ 2 files changed, 54 insertions(+), 8 deletions(-) create mode 100644 tests/run-pass/clock.rs diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 00160156312a8..8641a7cf38627 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -507,16 +507,55 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; } - "strlen" => { - let ptr = this.read_scalar(args[0])?.not_undef()?; - let n = this.memory().read_c_str(ptr)?.len(); - this.write_scalar(Scalar::from_uint(n as u64, dest.layout.size), dest)?; + "clock_gettime" => { + if !this.machine.communicate { + throw_unsup_format!("`clock_gettime` not available when isolation is enabled") + } else { + let tcx = &{ this.tcx.tcx }; + + let clk_id = this.read_scalar(args[0])?.to_i32()?; + + if clk_id != this.eval_libc_i32("CLOCK_REALTIME")? { + let einval = this.eval_libc("EINVAL")?; + this.set_last_error(einval)?; + this.write_scalar(Scalar::from_int(-1i32, dest.layout.size), dest)?; + } else { + let tp = this.force_ptr(this.read_scalar(args[1])?.not_undef()?)?; + + let allocation = this.memory_mut().get_mut(tp.alloc_id)?; + + let duration = std::time::SystemTime::now() + .duration_since(std::time::SystemTime::UNIX_EPOCH) + .unwrap_or_else(|_| bug!("Clock went backwards")); + + allocation.write_scalar( + tcx, + tp, + Scalar::from_u64(duration.as_secs()).into(), + Size::from_bits(64), + )?; + allocation.write_scalar( + tcx, + tp.offset(Size::from_bits(64), tcx)?, + Scalar::from_u64(duration.subsec_nanos() as u64).into(), + Size::from_bits(64), + )?; + + this.write_scalar(Scalar::from_int(0i32, dest.layout.size), dest)?; + } + } } - // math functions - "cbrtf" | "coshf" | "sinhf" | "tanf" => { - // FIXME: Using host floats. - let f = f32::from_bits(this.read_scalar(args[0])?.to_u32()?); + "strlen" => { + let ptr = this.read_scalar(args[0])?.not_undef()?; + let n = this.memory().read_c_str(ptr)?.len(); + this.write_scalar(Scalar::from_uint(n as u64, dest.layout.size), dest)?; + } + + // math functions + "cbrtf" | "coshf" | "sinhf" | "tanf" => { + // FIXME: Using host floats. + let f = f32::from_bits(this.read_scalar(args[0])?.to_u32()?); let f = match link_name { "cbrtf" => f.cbrt(), "coshf" => f.cosh(), diff --git a/tests/run-pass/clock.rs b/tests/run-pass/clock.rs new file mode 100644 index 0000000000000..987a78fe1f058 --- /dev/null +++ b/tests/run-pass/clock.rs @@ -0,0 +1,7 @@ +// compile-flags: -Zmiri-disable-isolation + +use std::time::SystemTime; + +fn main() { + let _now = SystemTime::now(); +} From fcf04b5425099738c0f26994baf29a1112997bf2 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Thu, 3 Oct 2019 11:20:06 -0500 Subject: [PATCH 1184/3747] Reduce size of nanoseconds --- src/shims/foreign_items.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 8641a7cf38627..c106a296dcdef 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -537,8 +537,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx allocation.write_scalar( tcx, tp.offset(Size::from_bits(64), tcx)?, - Scalar::from_u64(duration.subsec_nanos() as u64).into(), - Size::from_bits(64), + Scalar::from_u32(duration.subsec_nanos()).into(), + Size::from_bits(32), )?; this.write_scalar(Scalar::from_int(0i32, dest.layout.size), dest)?; From adfa2eb062bf825bb100dc2cfd7ab7df075f1824 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Mon, 7 Oct 2019 16:22:53 -0500 Subject: [PATCH 1185/3747] Return negative times when the current time is before the unix epoch --- src/shims/foreign_items.rs | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index c106a296dcdef..c403afacd89b9 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -524,21 +524,30 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let allocation = this.memory_mut().get_mut(tp.alloc_id)?; + let mut sign = 1; + let duration = std::time::SystemTime::now() .duration_since(std::time::SystemTime::UNIX_EPOCH) - .unwrap_or_else(|_| bug!("Clock went backwards")); + .unwrap_or_else(|e| { + sign = -1; + e.duration() + }); + + let tv_sec_size = Size::from_bits(64); + let tv_nsec_size = Size::from_bits(64); allocation.write_scalar( tcx, tp, - Scalar::from_u64(duration.as_secs()).into(), - Size::from_bits(64), + Scalar::from_int(sign * (duration.as_secs() as i64), tv_sec_size).into(), + tv_sec_size, )?; + allocation.write_scalar( tcx, - tp.offset(Size::from_bits(64), tcx)?, - Scalar::from_u32(duration.subsec_nanos()).into(), - Size::from_bits(32), + tp.offset(tv_sec_size, tcx)?, + Scalar::from_int(duration.subsec_nanos() as i64, tv_nsec_size).into(), + tv_nsec_size, )?; this.write_scalar(Scalar::from_int(0i32, dest.layout.size), dest)?; From 7a6df8504f477faafe1c91e0c7fa83a63e31a825 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Tue, 8 Oct 2019 13:29:39 -0500 Subject: [PATCH 1186/3747] Get size of integers using libc --- src/shims/foreign_items.rs | 30 +++++++++++++++++------------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index c403afacd89b9..1e7c85c43521f 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -522,6 +522,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } else { let tp = this.force_ptr(this.read_scalar(args[1])?.not_undef()?)?; + let long = this.resolve_path(&["libc", "c_long"])?.ty(*tcx); + let time_t = this.resolve_path(&["libc", "time_t"])?.ty(*tcx); + + let tv_sec_size = this.layout_of(time_t)?.size; + let tv_nsec_size = this.layout_of(long)?.size; + let allocation = this.memory_mut().get_mut(tp.alloc_id)?; let mut sign = 1; @@ -533,13 +539,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx e.duration() }); - let tv_sec_size = Size::from_bits(64); - let tv_nsec_size = Size::from_bits(64); - allocation.write_scalar( tcx, tp, - Scalar::from_int(sign * (duration.as_secs() as i64), tv_sec_size).into(), + Scalar::from_int(sign * (duration.as_secs() as i64), tv_sec_size) + .into(), tv_sec_size, )?; @@ -555,16 +559,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } - "strlen" => { - let ptr = this.read_scalar(args[0])?.not_undef()?; - let n = this.memory().read_c_str(ptr)?.len(); - this.write_scalar(Scalar::from_uint(n as u64, dest.layout.size), dest)?; - } + "strlen" => { + let ptr = this.read_scalar(args[0])?.not_undef()?; + let n = this.memory().read_c_str(ptr)?.len(); + this.write_scalar(Scalar::from_uint(n as u64, dest.layout.size), dest)?; + } - // math functions - "cbrtf" | "coshf" | "sinhf" | "tanf" => { - // FIXME: Using host floats. - let f = f32::from_bits(this.read_scalar(args[0])?.to_u32()?); + // math functions + "cbrtf" | "coshf" | "sinhf" | "tanf" => { + // FIXME: Using host floats. + let f = f32::from_bits(this.read_scalar(args[0])?.to_u32()?); let f = match link_name { "cbrtf" => f.cbrt(), "coshf" => f.cosh(), From b7863f2509eed16f2ce79ffb52a21de5bd536a48 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Tue, 8 Oct 2019 14:04:23 -0500 Subject: [PATCH 1187/3747] Add gettimeofday shim for macOS --- src/shims/foreign_items.rs | 52 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 1e7c85c43521f..656cb01010204 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -559,6 +559,58 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } + "gettimeofday" => { + if !this.machine.communicate { + throw_unsup_format!("`gettimeofday` not available when isolation is enabled") + } else { + let tcx = &{ this.tcx.tcx }; + + let tz = this.read_scalar(args[1])?.not_undef()?; + // Using tz is obsolete and should always be null + if !this.is_null(tz)? { + let einval = this.eval_libc("EINVAL")?; + this.set_last_error(einval)?; + this.write_scalar(Scalar::from_int(-1i32, dest.layout.size), dest)?; + } else { + let tv = this.force_ptr(this.read_scalar(args[0])?.not_undef()?)?; + + let time_t = this.resolve_path(&["libc", "time_t"])?.ty(*tcx); + let suseconds_t = this.resolve_path(&["libc", "suseconds_t"])?.ty(*tcx); + + let tv_sec_size = this.layout_of(time_t)?.size; + let tv_usec_size = this.layout_of(suseconds_t)?.size; + + let allocation = this.memory_mut().get_mut(tv.alloc_id)?; + + let mut sign = 1; + + let duration = std::time::SystemTime::now() + .duration_since(std::time::SystemTime::UNIX_EPOCH) + .unwrap_or_else(|e| { + sign = -1; + e.duration() + }); + + allocation.write_scalar( + tcx, + tv, + Scalar::from_int(sign * (duration.as_secs() as i64), tv_sec_size) + .into(), + tv_sec_size, + )?; + + allocation.write_scalar( + tcx, + tv.offset(tv_sec_size, tcx)?, + Scalar::from_int(duration.subsec_micros() as i64, tv_usec_size).into(), + tv_usec_size, + )?; + + this.write_scalar(Scalar::from_int(0i32, dest.layout.size), dest)?; + } + } + } + "strlen" => { let ptr = this.read_scalar(args[0])?.not_undef()?; let n = this.memory().read_c_str(ptr)?.len(); From 9f24c126249990f337f7e940b586a1424081d9c6 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Tue, 8 Oct 2019 15:06:14 -0500 Subject: [PATCH 1188/3747] Add helper function to write structs --- src/helpers.rs | 38 +++++++++++++++++++++++++- src/shims/foreign_items.rs | 56 ++++++-------------------------------- 2 files changed, 45 insertions(+), 49 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index c7b7853388cc5..eeada36ca8335 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -1,8 +1,11 @@ use std::mem; -use rustc::ty::{self, layout::{self, Size, Align}}; use rustc::hir::def_id::{DefId, CRATE_DEF_INDEX}; use rustc::mir; +use rustc::ty::{ + self, + layout::{self, Align, Size, LayoutOf}, +}; use rand::RngCore; @@ -304,4 +307,37 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn eval_libc_i32(&mut self, name: &str) -> InterpResult<'tcx, i32> { self.eval_libc(name)?.to_i32() } + + fn write_c_ints( + &mut self, + ptr: &Pointer, + bits: &[i128], + ty_names: &[&str], + ) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + + let tcx = &{ this.tcx.tcx }; + + let mut sizes = Vec::new(); + + for name in ty_names { + let ty = this.resolve_path(&["libc", name])?.ty(*tcx); + sizes.push(this.layout_of(ty)?.size); + } + + let allocation = this.memory_mut().get_mut(ptr.alloc_id)?; + let mut offset = Size::from_bytes(0); + + for (value, size) in bits.iter().zip(sizes) { + allocation.write_scalar( + tcx, + ptr.offset(offset, tcx)?, + Scalar::from_int(*value, size).into(), + size, + )?; + offset += size; + } + + Ok(()) + } } diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 656cb01010204..edf151f44ef6a 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -511,8 +511,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if !this.machine.communicate { throw_unsup_format!("`clock_gettime` not available when isolation is enabled") } else { - let tcx = &{ this.tcx.tcx }; - let clk_id = this.read_scalar(args[0])?.to_i32()?; if clk_id != this.eval_libc_i32("CLOCK_REALTIME")? { @@ -522,14 +520,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } else { let tp = this.force_ptr(this.read_scalar(args[1])?.not_undef()?)?; - let long = this.resolve_path(&["libc", "c_long"])?.ty(*tcx); - let time_t = this.resolve_path(&["libc", "time_t"])?.ty(*tcx); - - let tv_sec_size = this.layout_of(time_t)?.size; - let tv_nsec_size = this.layout_of(long)?.size; - - let allocation = this.memory_mut().get_mut(tp.alloc_id)?; - let mut sign = 1; let duration = std::time::SystemTime::now() @@ -539,20 +529,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx e.duration() }); - allocation.write_scalar( - tcx, - tp, - Scalar::from_int(sign * (duration.as_secs() as i64), tv_sec_size) - .into(), - tv_sec_size, - )?; - - allocation.write_scalar( - tcx, - tp.offset(tv_sec_size, tcx)?, - Scalar::from_int(duration.subsec_nanos() as i64, tv_nsec_size).into(), - tv_nsec_size, - )?; + let tv_sec = sign * (duration.as_secs() as i128); + let tv_nsec = duration.subsec_nanos() as i128; + + this.write_c_ints(&tp, &[tv_sec, tv_nsec], &["time_t", "c_long"])?; this.write_scalar(Scalar::from_int(0i32, dest.layout.size), dest)?; } @@ -563,8 +543,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if !this.machine.communicate { throw_unsup_format!("`gettimeofday` not available when isolation is enabled") } else { - let tcx = &{ this.tcx.tcx }; - let tz = this.read_scalar(args[1])?.not_undef()?; // Using tz is obsolete and should always be null if !this.is_null(tz)? { @@ -574,14 +552,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } else { let tv = this.force_ptr(this.read_scalar(args[0])?.not_undef()?)?; - let time_t = this.resolve_path(&["libc", "time_t"])?.ty(*tcx); - let suseconds_t = this.resolve_path(&["libc", "suseconds_t"])?.ty(*tcx); - - let tv_sec_size = this.layout_of(time_t)?.size; - let tv_usec_size = this.layout_of(suseconds_t)?.size; - - let allocation = this.memory_mut().get_mut(tv.alloc_id)?; - let mut sign = 1; let duration = std::time::SystemTime::now() @@ -591,20 +561,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx e.duration() }); - allocation.write_scalar( - tcx, - tv, - Scalar::from_int(sign * (duration.as_secs() as i64), tv_sec_size) - .into(), - tv_sec_size, - )?; - - allocation.write_scalar( - tcx, - tv.offset(tv_sec_size, tcx)?, - Scalar::from_int(duration.subsec_micros() as i64, tv_usec_size).into(), - tv_usec_size, - )?; + let tv_sec = sign * (duration.as_secs() as i128); + let tv_usec = duration.subsec_micros() as i128; + + this.write_c_ints(&tv, &[tv_sec, tv_usec], &["time_t", "suseconds_t"])?; this.write_scalar(Scalar::from_int(0i32, dest.layout.size), dest)?; } From b8ee90d22eff95f02d78f628e4f2c3b71e265f1a Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Wed, 9 Oct 2019 10:56:47 -0500 Subject: [PATCH 1189/3747] Throw error instead of panicking for unfittable bits --- src/helpers.rs | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index eeada36ca8335..fea2307dcca5d 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -4,7 +4,7 @@ use rustc::hir::def_id::{DefId, CRATE_DEF_INDEX}; use rustc::mir; use rustc::ty::{ self, - layout::{self, Align, Size, LayoutOf}, + layout::{self, Align, LayoutOf, Size}, }; use rand::RngCore; @@ -328,11 +328,22 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let allocation = this.memory_mut().get_mut(ptr.alloc_id)?; let mut offset = Size::from_bytes(0); - for (value, size) in bits.iter().zip(sizes) { + for (&value, size) in bits.iter().zip(sizes) { + // If `value` does not fit in `size` bits, we error instead of letting + // `Scalar::from_int` panic. + let truncated = truncate(value as u128, size); + if sign_extend(truncated, size) as i128 != value { + throw_unsup_format!( + "Signed value {:#x} does not fit in {} bits", + value, + size.bits() + ) + } + allocation.write_scalar( tcx, ptr.offset(offset, tcx)?, - Scalar::from_int(*value, size).into(), + Scalar::from_int(value, size).into(), size, )?; offset += size; From 8f4d185d1b39b98846895b06d4a29525365eba4f Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Thu, 10 Oct 2019 15:41:32 -0500 Subject: [PATCH 1190/3747] Move time related functions to its own module --- src/lib.rs | 1 + src/shims/foreign_items.rs | 62 ++----------------------------- src/shims/mod.rs | 1 + src/shims/time.rs | 75 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 81 insertions(+), 58 deletions(-) create mode 100644 src/shims/time.rs diff --git a/src/lib.rs b/src/lib.rs index baae26d91adaa..06ec33a914bf7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -32,6 +32,7 @@ pub use crate::shims::{EvalContextExt as ShimsEvalContextExt}; pub use crate::shims::foreign_items::EvalContextExt as ForeignItemsEvalContextExt; pub use crate::shims::intrinsics::EvalContextExt as IntrinsicsEvalContextExt; pub use crate::shims::tls::{EvalContextExt as TlsEvalContextExt, TlsData}; +pub use crate::shims::time::{EvalContextExt as TimeEvalContextExt}; pub use crate::shims::dlsym::{Dlsym, EvalContextExt as DlsymEvalContextExt}; pub use crate::shims::env::{EnvVars, EvalContextExt as EnvEvalContextExt}; pub use crate::shims::fs::{FileHandler, EvalContextExt as FileEvalContextExt}; diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index edf151f44ef6a..f6195961ba064 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -508,67 +508,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "clock_gettime" => { - if !this.machine.communicate { - throw_unsup_format!("`clock_gettime` not available when isolation is enabled") - } else { - let clk_id = this.read_scalar(args[0])?.to_i32()?; - - if clk_id != this.eval_libc_i32("CLOCK_REALTIME")? { - let einval = this.eval_libc("EINVAL")?; - this.set_last_error(einval)?; - this.write_scalar(Scalar::from_int(-1i32, dest.layout.size), dest)?; - } else { - let tp = this.force_ptr(this.read_scalar(args[1])?.not_undef()?)?; - - let mut sign = 1; - - let duration = std::time::SystemTime::now() - .duration_since(std::time::SystemTime::UNIX_EPOCH) - .unwrap_or_else(|e| { - sign = -1; - e.duration() - }); - - let tv_sec = sign * (duration.as_secs() as i128); - let tv_nsec = duration.subsec_nanos() as i128; - - this.write_c_ints(&tp, &[tv_sec, tv_nsec], &["time_t", "c_long"])?; - - this.write_scalar(Scalar::from_int(0i32, dest.layout.size), dest)?; - } - } + let result = this.clock_gettime(args[0], args[1])?; + this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; } "gettimeofday" => { - if !this.machine.communicate { - throw_unsup_format!("`gettimeofday` not available when isolation is enabled") - } else { - let tz = this.read_scalar(args[1])?.not_undef()?; - // Using tz is obsolete and should always be null - if !this.is_null(tz)? { - let einval = this.eval_libc("EINVAL")?; - this.set_last_error(einval)?; - this.write_scalar(Scalar::from_int(-1i32, dest.layout.size), dest)?; - } else { - let tv = this.force_ptr(this.read_scalar(args[0])?.not_undef()?)?; - - let mut sign = 1; - - let duration = std::time::SystemTime::now() - .duration_since(std::time::SystemTime::UNIX_EPOCH) - .unwrap_or_else(|e| { - sign = -1; - e.duration() - }); - - let tv_sec = sign * (duration.as_secs() as i128); - let tv_usec = duration.subsec_micros() as i128; - - this.write_c_ints(&tv, &[tv_sec, tv_usec], &["time_t", "suseconds_t"])?; - - this.write_scalar(Scalar::from_int(0i32, dest.layout.size), dest)?; - } - } + let result = this.gettimeofday(args[0], args[1])?; + this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; } "strlen" => { diff --git a/src/shims/mod.rs b/src/shims/mod.rs index 6d80af46850ca..95bb8b70370f1 100644 --- a/src/shims/mod.rs +++ b/src/shims/mod.rs @@ -4,6 +4,7 @@ pub mod foreign_items; pub mod intrinsics; pub mod tls; pub mod fs; +pub mod time; use rustc::{mir, ty}; diff --git a/src/shims/time.rs b/src/shims/time.rs new file mode 100644 index 0000000000000..97b74542d8091 --- /dev/null +++ b/src/shims/time.rs @@ -0,0 +1,75 @@ +use crate::stacked_borrows::Tag; +use crate::*; + +use std::time::{Duration, SystemTime}; + +fn get_time() -> (Duration, i128) { + let mut sign = 1; + let duration = SystemTime::now() + .duration_since(SystemTime::UNIX_EPOCH) + .unwrap_or_else(|e| { + sign = -1; + e.duration() + }); + (duration, sign) +} + +impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} +pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { + fn clock_gettime( + &mut self, + clk_id_op: OpTy<'tcx, Tag>, + tp_op: OpTy<'tcx, Tag>, + ) -> InterpResult<'tcx, i32> { + let this = self.eval_context_mut(); + + if !this.machine.communicate { + throw_unsup_format!("`clock_gettime` not available when isolation is enabled") + } + + let clk_id = this.read_scalar(clk_id_op)?.to_i32()?; + if clk_id != this.eval_libc_i32("CLOCK_REALTIME")? { + let einval = this.eval_libc("EINVAL")?; + this.set_last_error(einval)?; + return Ok(-1); + } + + let tp = this.force_ptr(this.read_scalar(tp_op)?.not_undef()?)?; + + let (duration, sign) = get_time(); + let tv_sec = sign * (duration.as_secs() as i128); + let tv_nsec = duration.subsec_nanos() as i128; + this.write_c_ints(&tp, &[tv_sec, tv_nsec], &["time_t", "c_long"])?; + + Ok(0) + } + + fn gettimeofday( + &mut self, + tv_op: OpTy<'tcx, Tag>, + tz_op: OpTy<'tcx, Tag>, + ) -> InterpResult<'tcx, i32> { + let this = self.eval_context_mut(); + + if !this.machine.communicate { + throw_unsup_format!("`gettimeofday` not available when isolation is enabled") + } + // Using tz is obsolete and should always be null + let tz = this.read_scalar(tz_op)?.not_undef()?; + if !this.is_null(tz)? { + let einval = this.eval_libc("EINVAL")?; + this.set_last_error(einval)?; + return Ok(-1); + } + + let tv = this.force_ptr(this.read_scalar(tv_op)?.not_undef()?)?; + + let (duration, sign) = get_time(); + let tv_sec = sign * (duration.as_secs() as i128); + let tv_usec = duration.subsec_micros() as i128; + + this.write_c_ints(&tv, &[tv_sec, tv_usec], &["time_t", "suseconds_t"])?; + + Ok(0) + } +} From 87b210df6c4ee3cd823f3d0a4a6940084e765c82 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Fri, 11 Oct 2019 00:03:54 -0500 Subject: [PATCH 1191/3747] Fix sign when number of seconds is zero --- src/shims/time.rs | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/shims/time.rs b/src/shims/time.rs index 97b74542d8091..2995bdc434642 100644 --- a/src/shims/time.rs +++ b/src/shims/time.rs @@ -16,6 +16,7 @@ fn get_time() -> (Duration, i128) { impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { + // Foreign function used by linux fn clock_gettime( &mut self, clk_id_op: OpTy<'tcx, Tag>, @@ -38,12 +39,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let (duration, sign) = get_time(); let tv_sec = sign * (duration.as_secs() as i128); - let tv_nsec = duration.subsec_nanos() as i128; + let mut tv_nsec = duration.subsec_nanos() as i128; + // If the number of seconds is zero, we need to put the sign into the second's fraction. + if tv_sec == 0 && sign < 0 { + tv_nsec *= sign; + } + this.write_c_ints(&tp, &[tv_sec, tv_nsec], &["time_t", "c_long"])?; Ok(0) } - + // Foreign function used by generic unix fn gettimeofday( &mut self, tv_op: OpTy<'tcx, Tag>, @@ -66,7 +72,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let (duration, sign) = get_time(); let tv_sec = sign * (duration.as_secs() as i128); - let tv_usec = duration.subsec_micros() as i128; + let mut tv_usec = duration.subsec_micros() as i128; + // If the number of seconds is zero, we need to put the sign into the second's fraction. + if tv_sec == 0 && sign < 0 { + tv_usec *= sign; + } this.write_c_ints(&tv, &[tv_sec, tv_usec], &["time_t", "suseconds_t"])?; From 2cbf4afa99a1a8953ed54abdcb292b45b79a8639 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Fri, 11 Oct 2019 00:55:32 -0500 Subject: [PATCH 1192/3747] Split `write_c_ints` into less specific helper functions --- src/helpers.rs | 39 +++++++++++++++------------------------ src/shims/time.rs | 40 ++++++++++++++++++++++++++++++++++++---- 2 files changed, 51 insertions(+), 28 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index fea2307dcca5d..892ba7b2401ba 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -4,7 +4,7 @@ use rustc::hir::def_id::{DefId, CRATE_DEF_INDEX}; use rustc::mir; use rustc::ty::{ self, - layout::{self, Align, LayoutOf, Size}, + layout::{self, Align, LayoutOf, Size, TyLayout}, }; use rand::RngCore; @@ -308,42 +308,26 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx self.eval_libc(name)?.to_i32() } - fn write_c_ints( + // Writes several `ImmTy`s contiguosly into memory. This is useful when you have to pack + // different values into an struct. + fn write_immediates( &mut self, ptr: &Pointer, - bits: &[i128], - ty_names: &[&str], + imms: &[ImmTy<'tcx, Tag>], ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let tcx = &{ this.tcx.tcx }; - let mut sizes = Vec::new(); - - for name in ty_names { - let ty = this.resolve_path(&["libc", name])?.ty(*tcx); - sizes.push(this.layout_of(ty)?.size); - } - let allocation = this.memory_mut().get_mut(ptr.alloc_id)?; let mut offset = Size::from_bytes(0); - for (&value, size) in bits.iter().zip(sizes) { - // If `value` does not fit in `size` bits, we error instead of letting - // `Scalar::from_int` panic. - let truncated = truncate(value as u128, size); - if sign_extend(truncated, size) as i128 != value { - throw_unsup_format!( - "Signed value {:#x} does not fit in {} bits", - value, - size.bits() - ) - } - + for imm in imms { + let size = imm.layout.size; allocation.write_scalar( tcx, ptr.offset(offset, tcx)?, - Scalar::from_int(value, size).into(), + imm.to_scalar()?.into(), size, )?; offset += size; @@ -351,4 +335,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(()) } + + fn libc_ty_layout(&mut self, name: &str) -> InterpResult<'tcx, TyLayout<'tcx>> { + let this = self.eval_context_mut(); + let tcx = &{ this.tcx.tcx }; + let ty = this.resolve_path(&["libc", name])?.ty(*tcx); + this.layout_of(ty) + } } diff --git a/src/shims/time.rs b/src/shims/time.rs index 2995bdc434642..3acc84dbc751c 100644 --- a/src/shims/time.rs +++ b/src/shims/time.rs @@ -1,8 +1,12 @@ +use std::time::{Duration, SystemTime}; + +use rustc::ty::layout::TyLayout; + use crate::stacked_borrows::Tag; use crate::*; -use std::time::{Duration, SystemTime}; - +// Returns the time elapsed between now and the unix epoch as a `Duration` and the sign of the time +// interval fn get_time() -> (Duration, i128) { let mut sign = 1; let duration = SystemTime::now() @@ -14,6 +18,24 @@ fn get_time() -> (Duration, i128) { (duration, sign) } +fn int_to_immty_checked<'tcx>( + int: i128, + layout: TyLayout<'tcx>, +) -> InterpResult<'tcx, ImmTy<'tcx, Tag>> { + // If `int` does not fit in `size` bits, we error instead of letting + // `ImmTy::from_int` panic. + let size = layout.size; + let truncated = truncate(int as u128, size); + if sign_extend(truncated, size) as i128 != int { + throw_unsup_format!( + "Signed value {:#x} does not fit in {} bits", + int, + size.bits() + ) + } + Ok(ImmTy::from_int(int, layout)) +} + impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { // Foreign function used by linux @@ -45,7 +67,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx tv_nsec *= sign; } - this.write_c_ints(&tp, &[tv_sec, tv_nsec], &["time_t", "c_long"])?; + let imms = [ + int_to_immty_checked(tv_sec, this.libc_ty_layout("time_t")?)?, + int_to_immty_checked(tv_nsec, this.libc_ty_layout("c_long")?)?, + ]; + + this.write_immediates(&tp, &imms)?; Ok(0) } @@ -78,7 +105,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx tv_usec *= sign; } - this.write_c_ints(&tv, &[tv_sec, tv_usec], &["time_t", "suseconds_t"])?; + let imms = [ + int_to_immty_checked(tv_sec, this.libc_ty_layout("time_t")?)?, + int_to_immty_checked(tv_usec, this.libc_ty_layout("suseconds_t")?)?, + ]; + + this.write_immediates(&tv, &imms)?; Ok(0) } From a1c6797c5c145f597e37dae53031babb0aaf7735 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Fri, 11 Oct 2019 05:30:50 -0500 Subject: [PATCH 1193/3747] Error when there is an unsupported flag --- src/shims/fs.rs | 29 +++++++++++++++++++++++++---- 1 file changed, 25 insertions(+), 4 deletions(-) diff --git a/src/shims/fs.rs b/src/shims/fs.rs index 7e684489b5c9c..a6a1eb947b0bb 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -44,7 +44,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let mut options = OpenOptions::new(); - // The first two bits of the flag correspond to the access mode of the file in linux. + // The first two bits of the flag correspond to the access mode of the file in linux. This + // is done this way because `O_RDONLY` is zero in several platforms. let access_mode = flag & 0b11; if access_mode == this.eval_libc_i32("O_RDONLY")? { @@ -56,15 +57,35 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } else { throw_unsup_format!("Unsupported access mode {:#x}", access_mode); } + // We need to check that there aren't unsupported options in `flag`. For this we try to + // reproduce the content of `flag` in the `mirror` variable using only the supported + // options. + let mut mirror = access_mode; - if flag & this.eval_libc_i32("O_APPEND")? != 0 { + let o_append = this.eval_libc_i32("O_APPEND")?; + if flag & o_append != 0 { options.append(true); + mirror |= o_append; } - if flag & this.eval_libc_i32("O_TRUNC")? != 0 { + let o_trunc = this.eval_libc_i32("O_TRUNC")?; + if flag & o_trunc != 0 { options.truncate(true); + mirror |= o_trunc; } - if flag & this.eval_libc_i32("O_CREAT")? != 0 { + let o_creat = this.eval_libc_i32("O_CREAT")?; + if flag & o_creat != 0 { options.create(true); + mirror |= o_creat; + } + let o_cloexec = this.eval_libc_i32("O_CLOEXEC")?; + if flag & o_cloexec != 0 { + // This flag is a noop for now because `std` already sets it. + mirror |= o_cloexec; + } + // If `flag` is not equal to `mirror`, there is an unsupported option enabled in `flag`, + // then we throw an error. + if flag != mirror { + throw_unsup_format!("unsupported flags {:#x}", flag); } let path_bytes = this From d73fae1b28b3a12a5c22df71fc7be5fdb5f66e67 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Fri, 11 Oct 2019 12:17:54 -0500 Subject: [PATCH 1194/3747] Remove F_SETFD command --- src/shims/fs.rs | 26 ++++---------------------- 1 file changed, 4 insertions(+), 22 deletions(-) diff --git a/src/shims/fs.rs b/src/shims/fs.rs index a6a1eb947b0bb..443a61c46e9aa 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -108,7 +108,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx &mut self, fd_op: OpTy<'tcx, Tag>, cmd_op: OpTy<'tcx, Tag>, - arg_op: Option>, + _arg_op: Option>, ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); @@ -118,29 +118,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let fd = this.read_scalar(fd_op)?.to_i32()?; let cmd = this.read_scalar(cmd_op)?.to_i32()?; - - if cmd == this.eval_libc_i32("F_SETFD")? { - // This does not affect the file itself. Certain flags might require changing the file - // or the way it is accessed somehow. - let flag = this.read_scalar(arg_op.unwrap())?.to_i32()?; - // The only usage of this in stdlib at the moment is to enable the `FD_CLOEXEC` flag. - let fd_cloexec = this.eval_libc_i32("FD_CLOEXEC")?; - if let Some(FileHandle { flag: old_flag, .. }) = - this.machine.file_handler.handles.get_mut(&fd) - { - // Check that the only difference between the old flag and the current flag is - // exactly the `FD_CLOEXEC` value. - if flag ^ *old_flag == fd_cloexec { - *old_flag = flag; - } else { - throw_unsup_format!("Unsupported arg {:#x} for `F_SETFD`", flag); - } - } - Ok(0) - } else if cmd == this.eval_libc_i32("F_GETFD")? { + // We only support getting the flags for a descriptor + if cmd == this.eval_libc_i32("F_GETFD")? { this.get_handle_and(fd, |handle| Ok(handle.flag)) } else { - throw_unsup_format!("Unsupported command {:#x}", cmd); + throw_unsup_format!("The {:#x} command is not supported for `fcntl`)", cmd); } } From 9082092a71edf130aecbde147a5b27b2a50e1fd7 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 11 Oct 2019 23:02:04 +0200 Subject: [PATCH 1195/3747] use temp_dir for FS test --- tests/run-pass/fs.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/run-pass/fs.rs b/tests/run-pass/fs.rs index 98f3c1089bb77..212e5e27d8aa8 100644 --- a/tests/run-pass/fs.rs +++ b/tests/run-pass/fs.rs @@ -5,16 +5,16 @@ use std::fs::{File, remove_file}; use std::io::{Read, Write}; fn main() { - let path = "miri_test_fs.txt"; + let path = std::env::temp_dir().join("miri_test_fs.txt"); let bytes = b"Hello, World!\n"; // Test creating, writing and closing a file (closing is tested when `file` is dropped). - let mut file = File::create(path).unwrap(); + let mut file = File::create(&path).unwrap(); // Writing 0 bytes should not change the file contents. file.write(&mut []).unwrap(); file.write(bytes).unwrap(); // Test opening, reading and closing a file. - let mut file = File::open(path).unwrap(); + let mut file = File::open(&path).unwrap(); let mut contents = Vec::new(); // Reading 0 bytes should not move the file pointer. file.read(&mut []).unwrap(); @@ -22,9 +22,9 @@ fn main() { file.read_to_end(&mut contents).unwrap(); assert_eq!(bytes, contents.as_slice()); // Removing file should succeed - remove_file(path).unwrap(); + remove_file(&path).unwrap(); // Opening non-existing file should fail - assert!(File::open(path).is_err()); + assert!(File::open(&path).is_err()); // Removing non-existing file should fail - assert!(remove_file(path).is_err()); + assert!(remove_file(&path).is_err()); } From 7f28d9631e01cd39ea6e687268ba87c1f77a574b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 12 Oct 2019 17:51:10 +0200 Subject: [PATCH 1196/3747] hopefully harmless Rust bump --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index db6f5ebe88c44..fef9820f7e1a3 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -2748a9fd93dd1a00a4521f4f16de5befbf77f6cd +898f36c83cc28d7921a1d7b3605323dc5cfcf533 From 19fb53e8a3e72159c2105d497fd23d4d4f34ee3a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 12 Oct 2019 18:11:44 +0200 Subject: [PATCH 1197/3747] better debugging for sysroot check --- src/bin/cargo-miri.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 43e8761d48c17..30b1d863e0cac 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -136,8 +136,12 @@ fn test_sysroot_consistency() { .output().expect("Failed to run rustc to get sysroot info"); let stdout = String::from_utf8(out.stdout).expect("stdout is not valid UTF-8"); let stderr = String::from_utf8(out.stderr).expect("stderr is not valid UTF-8"); + assert!( + out.status.success(), + "Bad status code {} when getting sysroot info via {:?}.\nstdout:\n{}\nstderr:\n{}", + out.status, cmd, stdout, stderr, + ); let stdout = stdout.trim(); - assert!(out.status.success(), "Bad status code when getting sysroot info.\nstdout:\n{}\nstderr:\n{}", stdout, stderr); PathBuf::from(stdout).canonicalize() .unwrap_or_else(|_| panic!("Failed to canonicalize sysroot: {}", stdout)) } From 508df227e5f4820f1d600b72e626a620b2c714af Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Sat, 12 Oct 2019 19:48:18 -0500 Subject: [PATCH 1198/3747] Group libc helper functions --- src/helpers.rs | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index 892ba7b2401ba..3012b1a95541c 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -308,8 +308,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx self.eval_libc(name)?.to_i32() } + /// Helper function to get the `TyLayout` of a `libc` type + fn libc_ty_layout(&mut self, name: &str) -> InterpResult<'tcx, TyLayout<'tcx>> { + let this = self.eval_context_mut(); + let tcx = &{ this.tcx.tcx }; + let ty = this.resolve_path(&["libc", name])?.ty(*tcx); + this.layout_of(ty) + } + // Writes several `ImmTy`s contiguosly into memory. This is useful when you have to pack - // different values into an struct. + // different values into a struct. fn write_immediates( &mut self, ptr: &Pointer, @@ -335,11 +343,4 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(()) } - - fn libc_ty_layout(&mut self, name: &str) -> InterpResult<'tcx, TyLayout<'tcx>> { - let this = self.eval_context_mut(); - let tcx = &{ this.tcx.tcx }; - let ty = this.resolve_path(&["libc", name])?.ty(*tcx); - this.layout_of(ty) - } } From f76f8ce63bc160b127356c01624bbc8442844c22 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Sat, 12 Oct 2019 20:12:26 -0500 Subject: [PATCH 1199/3747] Correct fcntl behavior --- src/shims/fs.rs | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/shims/fs.rs b/src/shims/fs.rs index 443a61c46e9aa..4d93ca4fd31b7 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -9,7 +9,6 @@ use crate::*; pub struct FileHandle { file: File, - flag: i32, } pub struct FileHandler { @@ -79,13 +78,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } let o_cloexec = this.eval_libc_i32("O_CLOEXEC")?; if flag & o_cloexec != 0 { - // This flag is a noop for now because `std` already sets it. + // We do not need to do anything for this flag because `std` already sets it. + // (Technically we do not support *not* setting this flag, but we ignore that.) mirror |= o_cloexec; } // If `flag` is not equal to `mirror`, there is an unsupported option enabled in `flag`, // then we throw an error. if flag != mirror { - throw_unsup_format!("unsupported flags {:#x}", flag); + throw_unsup_format!("unsupported flags {:#x}", flag & !mirror); } let path_bytes = this @@ -97,7 +97,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let fd = options.open(path).map(|file| { let mut fh = &mut this.machine.file_handler; fh.low += 1; - fh.handles.insert(fh.low, FileHandle { file, flag }); + fh.handles.insert(fh.low, FileHandle { file }); fh.low }); @@ -108,7 +108,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx &mut self, fd_op: OpTy<'tcx, Tag>, cmd_op: OpTy<'tcx, Tag>, - _arg_op: Option>, + _arg1_op: Option>, ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); @@ -120,7 +120,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let cmd = this.read_scalar(cmd_op)?.to_i32()?; // We only support getting the flags for a descriptor if cmd == this.eval_libc_i32("F_GETFD")? { - this.get_handle_and(fd, |handle| Ok(handle.flag)) + // Currently this is the only flag that `F_GETFD` returns. It is OK to just return the + // `FD_CLOEXEC` value without checking if the flag is set for the file because `std` + // always sets this flag when opening a file. However we still need to check that the + // file itself is open. + this.get_handle_and(fd, |_| Ok(0))?; + this.eval_libc_i32("FD_CLOEXEC") } else { throw_unsup_format!("The {:#x} command is not supported for `fcntl`)", cmd); } From 50618b55cd8c2cd8da905697fe80e5f3a519fb3b Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Sun, 13 Oct 2019 16:06:37 -0500 Subject: [PATCH 1200/3747] Error on negative times --- src/shims/time.rs | 31 +++++++++---------------------- 1 file changed, 9 insertions(+), 22 deletions(-) diff --git a/src/shims/time.rs b/src/shims/time.rs index 3acc84dbc751c..1b799b1330aa1 100644 --- a/src/shims/time.rs +++ b/src/shims/time.rs @@ -7,15 +7,10 @@ use crate::*; // Returns the time elapsed between now and the unix epoch as a `Duration` and the sign of the time // interval -fn get_time() -> (Duration, i128) { - let mut sign = 1; - let duration = SystemTime::now() +fn get_time<'tcx>() -> InterpResult<'tcx, Duration> { + SystemTime::now() .duration_since(SystemTime::UNIX_EPOCH) - .unwrap_or_else(|e| { - sign = -1; - e.duration() - }); - (duration, sign) + .map_err(|_| err_unsup_format!("Time went backwards").into()) } fn int_to_immty_checked<'tcx>( @@ -59,13 +54,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let tp = this.force_ptr(this.read_scalar(tp_op)?.not_undef()?)?; - let (duration, sign) = get_time(); - let tv_sec = sign * (duration.as_secs() as i128); - let mut tv_nsec = duration.subsec_nanos() as i128; - // If the number of seconds is zero, we need to put the sign into the second's fraction. - if tv_sec == 0 && sign < 0 { - tv_nsec *= sign; - } + let duration = get_time()?; + let tv_sec = duration.as_secs() as i128; + let tv_nsec = duration.subsec_nanos() as i128; let imms = [ int_to_immty_checked(tv_sec, this.libc_ty_layout("time_t")?)?, @@ -97,13 +88,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let tv = this.force_ptr(this.read_scalar(tv_op)?.not_undef()?)?; - let (duration, sign) = get_time(); - let tv_sec = sign * (duration.as_secs() as i128); - let mut tv_usec = duration.subsec_micros() as i128; - // If the number of seconds is zero, we need to put the sign into the second's fraction. - if tv_sec == 0 && sign < 0 { - tv_usec *= sign; - } + let duration = get_time()?; + let tv_sec = duration.as_secs() as i128; + let tv_usec = duration.subsec_micros() as i128; let imms = [ int_to_immty_checked(tv_sec, this.libc_ty_layout("time_t")?)?, From d5003bc07de502267aa2588630c3345c6e05a136 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 14 Oct 2019 09:38:08 +0200 Subject: [PATCH 1201/3747] add lockfile --- .gitignore | 1 - Cargo.lock | 901 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 901 insertions(+), 1 deletion(-) create mode 100644 Cargo.lock diff --git a/.gitignore b/.gitignore index ca23de4208823..389565791c00f 100644 --- a/.gitignore +++ b/.gitignore @@ -3,4 +3,3 @@ target tex/*/out *.dot *.rs.bk -Cargo.lock diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000000000..b498f9efd9223 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,901 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "aho-corasick" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "approx" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "arrayref" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "arrayvec" +version = "0.4.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "atty" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "autocfg" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "backtrace" +version = "0.3.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "backtrace-sys 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-demangle 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "backtrace-sys" +version = "0.1.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cc 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "base64" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "bitflags" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "blake2b_simd" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "arrayref 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "arrayvec 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", + "constant_time_eq 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "byteorder" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "c2-chacha" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "ppv-lite86 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "cargo_metadata" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "cc" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "cfg-if" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "cgmath" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "approx 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "chrono" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "cloudabi" +version = "0.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "colored" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winconsole 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "compiletest_rs" +version = "0.3.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "diff 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", + "filetime 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", + "getopts 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "miow 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rustfix 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", + "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "constant_time_eq" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "crossbeam-utils" +version = "0.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "diff" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "directories" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "dirs-sys 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "dirs-sys" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_users 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "env_logger" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "atty 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)", + "humantime 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "termcolor 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "failure" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "backtrace 0.3.35 (registry+https://github.com/rust-lang/crates.io-index)", + "failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "failure_derive" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)", + "synstructure 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "filetime" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "fuchsia-cprng" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "getopts" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "unicode-width 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "getrandom" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "wasi 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "hex" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "humantime" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "itoa" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "libc" +version = "0.2.62" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "log" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "memchr" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "miow" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "socket2 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "miri" +version = "0.1.0" +dependencies = [ + "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "cargo_metadata 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", + "colored 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "compiletest_rs 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)", + "directories 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "env_logger 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", + "getrandom 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", + "hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-workspace-hack 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "shell-escape 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "vergen 3.0.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "nodrop" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "num-integer" +version = "0.1.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "autocfg 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "num-traits" +version = "0.1.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "num-traits" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "autocfg 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "ppv-lite86" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "proc-macro2" +version = "0.4.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "proc-macro2" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "quick-error" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "quote" +version = "0.6.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "quote" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "getrandom 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_chacha 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_chacha" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "c2-chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_core" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_core" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "rand_core" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "getrandom 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_hc" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rand_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_os" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rdrand" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "redox_syscall" +version = "0.1.56" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "redox_users" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", + "rust-argon2 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "regex" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "aho-corasick 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "regex-syntax 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", + "thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "regex-syntax" +version = "0.6.11" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "remove_dir_all" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rgb" +version = "0.8.14" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "rust-argon2" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", + "blake2b_simd 0.5.7 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rustc-demangle" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "rustc-workspace-hack" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "rustc_version" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rustfix" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "ryu" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "semver" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "semver-parser" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "serde" +version = "1.0.99" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "serde_derive 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "serde_derive" +version = "1.0.99" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "serde_json" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", + "ryu 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "shell-escape" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "socket2" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "syn" +version = "0.15.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "syn" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "synstructure" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "tempfile" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", + "remove_dir_all 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "termcolor" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "wincolor 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "thread_local" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "time" +version = "0.1.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "unicode-width" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "unicode-xid" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "unicode-xid" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "vergen" +version = "3.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "chrono 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", + "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "wasi" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "winapi" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "winapi-util" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "wincolor" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "winconsole" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cgmath 0.16.1 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rgb 0.8.14 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[metadata] +"checksum aho-corasick 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)" = "58fb5e95d83b38284460a5fda7d6470aa0b8844d283a0b614b8535e880800d2d" +"checksum approx 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "08abcc3b4e9339e33a3d0a5ed15d84a687350c05689d825e0f6655eef9e76a94" +"checksum arrayref 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "0d382e583f07208808f6b1249e60848879ba3543f57c32277bf52d69c2f0f0ee" +"checksum arrayvec 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)" = "b8d73f9beda665eaa98ab9e4f7442bd4e7de6652587de55b2525e52e29c1b0ba" +"checksum atty 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)" = "1803c647a3ec87095e7ae7acfca019e98de5ec9a7d01343f611cf3152ed71a90" +"checksum autocfg 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "b671c8fb71b457dd4ae18c4ba1e59aa81793daacc361d82fcd410cef0d491875" +"checksum backtrace 0.3.35 (registry+https://github.com/rust-lang/crates.io-index)" = "1371048253fa3bac6704bfd6bbfc922ee9bdcee8881330d40f308b81cc5adc55" +"checksum backtrace-sys 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)" = "82a830b4ef2d1124a711c71d263c5abdc710ef8e907bd508c88be475cebc422b" +"checksum base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0b25d992356d2eb0ed82172f5248873db5560c4721f564b13cb5193bda5e668e" +"checksum bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3d155346769a6855b86399e9bc3814ab343cd3d62c7e985113d46a0ec3c281fd" +"checksum blake2b_simd 0.5.7 (registry+https://github.com/rust-lang/crates.io-index)" = "bf775a81bb2d464e20ff170ac20316c7b08a43d11dbc72f0f82e8e8d3d6d0499" +"checksum byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a7c3dd8985a7111efc5c80b44e23ecdd8c007de8ade3b96595387e812b957cf5" +"checksum c2-chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7d64d04786e0f528460fc884753cf8dddcc466be308f6026f8e355c41a0e4101" +"checksum cargo_metadata 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "700b3731fd7d357223d0000f4dbf1808401b694609035c3c411fbc0cd375c426" +"checksum cc 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)" = "b548a4ee81fccb95919d4e22cfea83c7693ebfd78f0495493178db20b3139da7" +"checksum cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "b486ce3ccf7ffd79fdeb678eac06a9e6c09fc88d33836340becb8fffe87c5e33" +"checksum cgmath 0.16.1 (registry+https://github.com/rust-lang/crates.io-index)" = "64a4b57c8f4e3a2e9ac07e0f6abc9c24b6fc9e1b54c3478cfb598f3d0023e51c" +"checksum chrono 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "77d81f58b7301084de3b958691458a53c3f7e0b1d702f77e550b6a88e3a88abe" +"checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" +"checksum colored 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6cdb90b60f2927f8d76139c72dbde7e10c3a2bc47c8594c9c7a66529f2687c03" +"checksum compiletest_rs 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)" = "eb783fe7afb90ec3d3e49ccaf9196d29ab63c6ed61d4b0695839daa580ae3a3d" +"checksum constant_time_eq 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "995a44c877f9212528ccc74b21a232f66ad69001e40ede5bcee2ac9ef2657120" +"checksum crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)" = "04973fa96e96579258a5091af6003abde64af786b860f18622b82e026cca60e6" +"checksum diff 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "3c2b69f912779fbb121ceb775d74d51e915af17aaebc38d28a592843a2dd0a3a" +"checksum directories 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "551a778172a450d7fc12e629ca3b0428d00f6afa9a43da1b630d54604e97371c" +"checksum dirs-sys 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "afa0b23de8fd801745c471deffa6e12d248f962c9fd4b4c33787b055599bde7b" +"checksum env_logger 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "aafcde04e90a5226a6443b7aabdb016ba2f8307c847d524724bd9b346dd1a2d3" +"checksum failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "795bd83d3abeb9220f257e597aa0080a508b27533824adf336529648f6abf7e2" +"checksum failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "ea1063915fd7ef4309e222a5a07cf9c319fb9c7836b1f89b85458672dbb127e1" +"checksum filetime 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "6bd7380b54ced79dda72ecc35cc4fbbd1da6bba54afaa37e96fd1c2a308cd469" +"checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" +"checksum getopts 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)" = "14dbbfd5c71d70241ecf9e6f13737f7b5ce823821063188d7e46c41d371eebd5" +"checksum getrandom 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "fc344b02d3868feb131e8b5fe2b9b0a1cc42942679af493061fc13b853243872" +"checksum hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "805026a5d0141ffc30abb3be3173848ad46a1b1664fe632428479619a3644d77" +"checksum humantime 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3ca7e5f2e110db35f93b837c81797f3714500b81d517bf20c431b16d3ca4f114" +"checksum itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "501266b7edd0174f8530248f87f99c88fbe60ca4ef3dd486835b8d8d53136f7f" +"checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +"checksum libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)" = "34fcd2c08d2f832f376f4173a231990fa5aef4e99fb569867318a227ef4c06ba" +"checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7" +"checksum memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "88579771288728879b57485cc7d6b07d648c9f0141eb955f8ab7f9d45394468e" +"checksum miow 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "396aa0f2003d7df8395cb93e09871561ccc3e785f0acb369170e8cc74ddf9226" +"checksum nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9667ddcc6cc8a43afc9b7917599d7216aa09c463919ea32c59ed6cac8bc945" +"checksum num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)" = "b85e541ef8255f6cf42bbfe4ef361305c6c135d10919ecc26126c4e5ae94bc09" +"checksum num-traits 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)" = "92e5113e9fd4cc14ded8e499429f396a20f98c772a47cc8622a736e1ec843c31" +"checksum num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "6ba9a427cfca2be13aa6f6403b0b7e7368fe982bfa16fccc450ce74c46cd9b32" +"checksum ppv-lite86 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e3cbf9f658cdb5000fcf6f362b8ea2ba154b9f146a61c7a20d647034c6b6561b" +"checksum proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759" +"checksum proc-macro2 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4c5c2380ae88876faae57698be9e9775e3544decad214599c3a6266cca6ac802" +"checksum quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9274b940887ce9addde99c4eee6b5c44cc494b182b97e73dc8ffdcb3397fd3f0" +"checksum quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)" = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1" +"checksum quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe" +"checksum rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293" +"checksum rand 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d47eab0e83d9693d40f825f86948aa16eff6750ead4bdffc4ab95b8b3a7f052c" +"checksum rand_chacha 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "03a2a90da8c7523f554344f921aa97283eadf6ac484a6d2a7d0212fa7f8d6853" +"checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" +"checksum rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc" +"checksum rand_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "615e683324e75af5d43d8f7a39ffe3ee4a9dc42c5c701167a71dc59c3a493aca" +"checksum rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" +"checksum rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071" +"checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" +"checksum redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)" = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84" +"checksum redox_users 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4ecedbca3bf205f8d8f5c2b44d83cd0690e39ee84b951ed649e9f1841132b66d" +"checksum regex 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "88c3d9193984285d544df4a30c23a4e62ead42edf70a4452ceb76dac1ce05c26" +"checksum regex-syntax 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)" = "b143cceb2ca5e56d5671988ef8b15615733e7ee16cd348e064333b251b89343f" +"checksum remove_dir_all 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4a83fa3702a688b9359eccba92d153ac33fd2e8462f9e0e3fdf155239ea7792e" +"checksum rgb 0.8.14 (registry+https://github.com/rust-lang/crates.io-index)" = "2089e4031214d129e201f8c3c8c2fe97cd7322478a0d1cdf78e7029b0042efdb" +"checksum rust-argon2 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4ca4eaef519b494d1f2848fc602d18816fed808a981aedf4f1f00ceb7c9d32cf" +"checksum rustc-demangle 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "4c691c0e608126e00913e33f0ccf3727d5fc84573623b8d65b2df340b5201783" +"checksum rustc-workspace-hack 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc71d2faa173b74b232dedc235e3ee1696581bb132fc116fa3626d6151a1a8fb" +"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" +"checksum rustfix 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7150ac777a2931a53489f5a41eb0937b84e3092a20cd0e73ad436b65b507f607" +"checksum ryu 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c92464b447c0ee8c4fb3824ecc8383b81717b9f1e74ba2e72540aef7b9f82997" +"checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" +"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" +"checksum serde 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)" = "fec2851eb56d010dc9a21b89ca53ee75e6528bab60c11e89d38390904982da9f" +"checksum serde_derive 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)" = "cb4dc18c61206b08dc98216c98faa0232f4337e1e1b8574551d5bad29ea1b425" +"checksum serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)" = "051c49229f282f7c6f3813f8286cc1e3323e8051823fce42c7ea80fe13521704" +"checksum shell-escape 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "170a13e64f2a51b77a45702ba77287f5c6829375b04a69cf2222acd17d0cfab9" +"checksum socket2 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)" = "e8b74de517221a2cb01a53349cf54182acdc31a074727d3079068448c0676d85" +"checksum syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)" = "9ca4b3b69a77cbe1ffc9e198781b7acb0c7365a883670e8f1c1bc66fba79a5c5" +"checksum syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "66850e97125af79138385e9b88339cbcd037e3f28ceab8c5ad98e64f0f1f80bf" +"checksum synstructure 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)" = "02353edf96d6e4dc81aea2d8490a7e9db177bf8acb0e951c24940bf866cb313f" +"checksum tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9" +"checksum termcolor 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "96d6098003bde162e4277c70665bd87c326f5a0c3f3fbfb285787fa482d54e6e" +"checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b" +"checksum time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f" +"checksum unicode-width 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7007dbd421b92cc6e28410fe7362e2e0a2503394908f417b68ec8d1c364c4e20" +"checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" +"checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" +"checksum vergen 3.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "6aba5e34f93dc7051dfad05b98a18e9156f27e7b431fe1d2398cb6061c0a1dba" +"checksum wasi 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fd5442abcac6525a045cc8c795aedb60da7a2e5e89c7bf18a0d5357849bb23c7" +"checksum winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "f10e386af2b13e47c89e7236a7a14a086791a2b88ebad6df9bf42040195cf770" +"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +"checksum winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7168bab6e1daee33b4557efd0e95d5ca70a03706d39fa5f3fe7a236f584b03c9" +"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +"checksum wincolor 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "96f5016b18804d24db43cebf3c77269e7569b8954a8464501c216cc5e070eaa9" +"checksum winconsole 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3ef84b96d10db72dd980056666d7f1e7663ce93d82fa33b63e71c966f4cf5032" From 917effada1e970e964520f56431119b7f6b332c9 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 14 Oct 2019 09:40:11 +0200 Subject: [PATCH 1202/3747] CI: force using locked versions --- .appveyor.yml | 4 ++-- travis.sh | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index c3d575403cb3d..582b55f62dbb5 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -36,7 +36,7 @@ install: build_script: - set RUSTFLAGS=-C debug-assertions # Build and install miri - - cargo build --release --all-features --all-targets + - cargo build --release --all-features --all-targets --locked - cargo install --all-features --force --path . --locked --offline # Get ourselves a MIR-full libstd, and use it henceforth - cargo miri setup @@ -46,7 +46,7 @@ test_script: - set RUST_TEST_NOCAPTURE=1 - set RUST_BACKTRACE=1 # Test miri - - cargo test --release --all-features + - cargo test --release --all-features --locked # Test cargo integration - cd test-cargo-miri - '"C:\msys64\mingw64\bin\python3.exe" run-test.py' diff --git a/travis.sh b/travis.sh index 6f14be44ef0ac..af297129e8216 100755 --- a/travis.sh +++ b/travis.sh @@ -12,13 +12,13 @@ export RUSTC_EXTRA_FLAGS="-D warnings" # Prepare echo "Build and install miri" -./miri build --all-targets -./miri install +./miri build --all-targets --locked +./miri install # implicitly locked echo # Test function run_tests { - ./miri test + ./miri test --locked # "miri test" has built the sysroot for us, now this should pass without # any interactive questions. test-cargo-miri/run-test.py From d4d80cbecb592750693499717f5cd2f616b9059a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 14 Oct 2019 13:15:44 +0200 Subject: [PATCH 1203/3747] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index fef9820f7e1a3..820490edd618e 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -898f36c83cc28d7921a1d7b3605323dc5cfcf533 +d28a9c38fe14396e86ae274c7847e20ee0f78ca9 From d8f06523f26ffc5a12d347fb6934e8b7a28e8a2c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 14 Oct 2019 13:17:30 +0200 Subject: [PATCH 1204/3747] bump compiletest --- Cargo.lock | 6 +++--- Cargo.toml | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b498f9efd9223..8d80f1f11cd17 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -158,7 +158,7 @@ dependencies = [ [[package]] name = "compiletest_rs" -version = "0.3.23" +version = "0.3.24" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "diff 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", @@ -338,7 +338,7 @@ dependencies = [ "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "cargo_metadata 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", "colored 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "compiletest_rs 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)", + "compiletest_rs 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", "directories 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", "getrandom 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", @@ -822,7 +822,7 @@ dependencies = [ "checksum chrono 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "77d81f58b7301084de3b958691458a53c3f7e0b1d702f77e550b6a88e3a88abe" "checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" "checksum colored 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6cdb90b60f2927f8d76139c72dbde7e10c3a2bc47c8594c9c7a66529f2687c03" -"checksum compiletest_rs 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)" = "eb783fe7afb90ec3d3e49ccaf9196d29ab63c6ed61d4b0695839daa580ae3a3d" +"checksum compiletest_rs 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)" = "676a74b493d50ac33cacd83fd536597e6b52c0b46b9856f7b9c809d82fef4ac0" "checksum constant_time_eq 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "995a44c877f9212528ccc74b21a232f66ad69001e40ede5bcee2ac9ef2657120" "checksum crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)" = "04973fa96e96579258a5091af6003abde64af786b860f18622b82e026cca60e6" "checksum diff 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "3c2b69f912779fbb121ceb775d74d51e915af17aaebc38d28a592843a2dd0a3a" diff --git a/Cargo.toml b/Cargo.toml index 5a5c774169cff..bd345ea2b7f55 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -59,5 +59,5 @@ cargo_miri = ["cargo_metadata", "directories", "rustc_version"] rustc_tests = [] [dev-dependencies] -compiletest_rs = { version = "0.3.23", features = ["tmp"] } +compiletest_rs = { version = "0.3.24", features = ["tmp"] } colored = "1.6" From f425f445d14007d3a3dd10c7f0ca90177b9dee2e Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Sun, 13 Oct 2019 14:48:07 -0500 Subject: [PATCH 1205/3747] Check that fs errors have the proper kind --- tests/run-pass/fs.rs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/tests/run-pass/fs.rs b/tests/run-pass/fs.rs index 212e5e27d8aa8..7765e5b368e80 100644 --- a/tests/run-pass/fs.rs +++ b/tests/run-pass/fs.rs @@ -2,7 +2,7 @@ // compile-flags: -Zmiri-disable-isolation use std::fs::{File, remove_file}; -use std::io::{Read, Write}; +use std::io::{Read, Write, ErrorKind}; fn main() { let path = std::env::temp_dir().join("miri_test_fs.txt"); @@ -23,8 +23,10 @@ fn main() { assert_eq!(bytes, contents.as_slice()); // Removing file should succeed remove_file(&path).unwrap(); - // Opening non-existing file should fail - assert!(File::open(&path).is_err()); - // Removing non-existing file should fail - assert!(remove_file(&path).is_err()); + + // The two following tests also check that the `__errno_location()` shim is working properly. + // Opening a non-existing file should fail with a "not found" error. + assert_eq!(ErrorKind::NotFound, File::open(&path).unwrap_err().kind()); + // Removing a non-existing file should fail with a "not found" error. + assert_eq!(ErrorKind::NotFound, remove_file(&path).unwrap_err().kind()); } From f9c768864a7784c518b6ac1af6515950c6eff6ec Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Mon, 14 Oct 2019 09:08:39 -0500 Subject: [PATCH 1206/3747] Use places instead of ptrs to write packed immtys --- src/helpers.rs | 18 +++++++----------- src/shims/time.rs | 12 ++++++------ tests/run-pass/clock.rs | 1 + 3 files changed, 14 insertions(+), 17 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index 3012b1a95541c..9107958e010ce 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -318,27 +318,23 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Writes several `ImmTy`s contiguosly into memory. This is useful when you have to pack // different values into a struct. - fn write_immediates( + fn write_packed_immediates( &mut self, - ptr: &Pointer, + place: &MPlaceTy<'tcx, Tag>, imms: &[ImmTy<'tcx, Tag>], ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let tcx = &{ this.tcx.tcx }; - let allocation = this.memory_mut().get_mut(ptr.alloc_id)?; let mut offset = Size::from_bytes(0); - for imm in imms { - let size = imm.layout.size; - allocation.write_scalar( - tcx, - ptr.offset(offset, tcx)?, - imm.to_scalar()?.into(), - size, + for &imm in imms { + this.write_immediate_to_mplace( + *imm, + place.offset(offset, None, imm.layout, tcx)?, )?; - offset += size; + offset += imm.layout.size; } Ok(()) diff --git a/src/shims/time.rs b/src/shims/time.rs index 1b799b1330aa1..0153c1a912df5 100644 --- a/src/shims/time.rs +++ b/src/shims/time.rs @@ -10,7 +10,7 @@ use crate::*; fn get_time<'tcx>() -> InterpResult<'tcx, Duration> { SystemTime::now() .duration_since(SystemTime::UNIX_EPOCH) - .map_err(|_| err_unsup_format!("Time went backwards").into()) + .map_err(|_| err_unsup_format!("Times before the Unix epoch are not supported").into()) } fn int_to_immty_checked<'tcx>( @@ -52,7 +52,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx return Ok(-1); } - let tp = this.force_ptr(this.read_scalar(tp_op)?.not_undef()?)?; + let tp = this.deref_operand(tp_op)?; let duration = get_time()?; let tv_sec = duration.as_secs() as i128; @@ -63,11 +63,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx int_to_immty_checked(tv_nsec, this.libc_ty_layout("c_long")?)?, ]; - this.write_immediates(&tp, &imms)?; + this.write_packed_immediates(&tp, &imms)?; Ok(0) } - // Foreign function used by generic unix + // Foreign function used by generic unix (in particular macOS) fn gettimeofday( &mut self, tv_op: OpTy<'tcx, Tag>, @@ -86,7 +86,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx return Ok(-1); } - let tv = this.force_ptr(this.read_scalar(tv_op)?.not_undef()?)?; + let tv = this.deref_operand(tv_op)?; let duration = get_time()?; let tv_sec = duration.as_secs() as i128; @@ -97,7 +97,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx int_to_immty_checked(tv_usec, this.libc_ty_layout("suseconds_t")?)?, ]; - this.write_immediates(&tv, &imms)?; + this.write_packed_immediates(&tv, &imms)?; Ok(0) } diff --git a/tests/run-pass/clock.rs b/tests/run-pass/clock.rs index 987a78fe1f058..23f45f91ada14 100644 --- a/tests/run-pass/clock.rs +++ b/tests/run-pass/clock.rs @@ -1,3 +1,4 @@ +// ignore-windows: TODO clock shims are not implemented on Windows // compile-flags: -Zmiri-disable-isolation use std::time::SystemTime; From e06ce728ca49fc647ea1dfbb609116d76385446c Mon Sep 17 00:00:00 2001 From: YOUNGSUK_KIM Date: Mon, 14 Oct 2019 20:57:57 -0400 Subject: [PATCH 1207/3747] Ralf Jung's great idea! --- src/bin/cargo-miri.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 521ac8fa065ce..3af5a2b35db35 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -333,11 +333,11 @@ path = "lib.rs" None => true, Some(target) => target == rustc_version::version_meta().unwrap().host, }; - let sysroot = if is_host { dir.join("HOST") } else { PathBuf::from(dir) }; - + let sysroot = if is_host { dir.join("HOST") } else { PathBuf::from(dir) }; + std::env::set_var("MIRI_SYSROOT", &sysroot); // pass the env var to the processes we spawn, which will turn it into "--sysroot" flags if print_env { - println!("MIRI_SYSROOT={:?}", &sysroot); // for Windows users, prints path with backslashes escaped. + println!("MIRI_SYSROOT='{}'", sysroot.display().to_string().replace('\'', r#"'"'"'"#)); } else if !ask_user { println!("A libstd for Miri is now available in `{}`.", sysroot.display()); } From 65fd00665ee246a029c9b220781098277319cd6a Mon Sep 17 00:00:00 2001 From: YOUNGSUK_KIM Date: Mon, 14 Oct 2019 22:37:54 -0400 Subject: [PATCH 1208/3747] remove unnecessary line break --- src/bin/cargo-miri.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 3af5a2b35db35..479374ee47501 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -334,7 +334,6 @@ path = "lib.rs" Some(target) => target == rustc_version::version_meta().unwrap().host, }; let sysroot = if is_host { dir.join("HOST") } else { PathBuf::from(dir) }; - std::env::set_var("MIRI_SYSROOT", &sysroot); // pass the env var to the processes we spawn, which will turn it into "--sysroot" flags if print_env { println!("MIRI_SYSROOT='{}'", sysroot.display().to_string().replace('\'', r#"'"'"'"#)); From 4ba63fb0fcdc6407c284bc58935c8df7b6d79c30 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 15 Oct 2019 09:50:16 +0200 Subject: [PATCH 1209/3747] explain our shell encoding --- src/bin/cargo-miri.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 14f381a45546f..15c66f8c0dbaa 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -340,6 +340,11 @@ path = "lib.rs" let sysroot = if is_host { dir.join("HOST") } else { PathBuf::from(dir) }; std::env::set_var("MIRI_SYSROOT", &sysroot); // pass the env var to the processes we spawn, which will turn it into "--sysroot" flags if print_env { + // Escape an arbitrary string for the shell: by wrapping it in `'`, the only special + // character we have to worry about is `'` itself. Everything else is taken literally + // in these strings. `'` is encoded as `'"'"'`: the outer `'` end and being a + // `'`-quoted string, respectively; the `"'"` in the middle represents a single `'`. + // (We could use `'\''` instead of `'"'"'` if we wanted but let's avoid backslashes.) println!("MIRI_SYSROOT='{}'", sysroot.display().to_string().replace('\'', r#"'"'"'"#)); } else if !ask_user { println!("A libstd for Miri is now available in `{}`.", sysroot.display()); From 78311a713218b9923cd5ab73b62a9fe2485c7d22 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Mon, 14 Oct 2019 15:36:15 -0500 Subject: [PATCH 1210/3747] Add function to error with enabled isolation --- src/helpers.rs | 9 +++++++++ src/shims/env.rs | 8 ++------ src/shims/fs.rs | 24 ++++++------------------ src/shims/time.rs | 8 ++------ 4 files changed, 19 insertions(+), 30 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index 9107958e010ce..e3f818414da3d 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -336,7 +336,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx )?; offset += imm.layout.size; } + Ok(()) + } + /// Helper function used inside the shims of foreign functions to check that isolation is + /// disabled. It returns an error using the `name` of the foreign function if this is not the + /// case. + fn check_no_isolation(&mut self, name: &str) -> InterpResult<'tcx> { + if !self.eval_context_mut().machine.communicate { + throw_unsup_format!("`{}` not available when isolation is enabled. Pass the flag `-Zmiri-disable-isolation` to disable it.", name) + } Ok(()) } } diff --git a/src/shims/env.rs b/src/shims/env.rs index 2ccbc0238e5f9..ae800c2315fe1 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -120,9 +120,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); - if !this.machine.communicate { - throw_unsup_format!("`getcwd` not available when isolation is enabled") - } + this.check_no_isolation("getcwd")?; let tcx = &{ this.tcx.tcx }; @@ -158,9 +156,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn chdir(&mut self, path_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - if !this.machine.communicate { - throw_unsup_format!("`chdir` not available when isolation is enabled") - } + this.check_no_isolation("chdir")?; let path_bytes = this .memory() diff --git a/src/shims/fs.rs b/src/shims/fs.rs index 7e684489b5c9c..414ae35e9666f 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -36,9 +36,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - if !this.machine.communicate { - throw_unsup_format!("`open` not available when isolation is enabled") - } + this.check_no_isolation("open")?; let flag = this.read_scalar(flag_op)?.to_i32()?; @@ -91,9 +89,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - if !this.machine.communicate { - throw_unsup_format!("`fcntl` not available when isolation is enabled") - } + this.check_no_isolation("fcntl")?; let fd = this.read_scalar(fd_op)?.to_i32()?; let cmd = this.read_scalar(cmd_op)?.to_i32()?; @@ -126,9 +122,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn close(&mut self, fd_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - if !this.machine.communicate { - throw_unsup_format!("`close` not available when isolation is enabled") - } + this.check_no_isolation("close")?; let fd = this.read_scalar(fd_op)?.to_i32()?; @@ -145,9 +139,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, i64> { let this = self.eval_context_mut(); - if !this.machine.communicate { - throw_unsup_format!("`read` not available when isolation is enabled") - } + this.check_no_isolation("read")?; let tcx = &{ this.tcx.tcx }; @@ -182,9 +174,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, i64> { let this = self.eval_context_mut(); - if !this.machine.communicate { - throw_unsup_format!("`write` not available when isolation is enabled") - } + this.check_no_isolation("write")?; let tcx = &{ this.tcx.tcx }; @@ -210,9 +200,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn unlink( &mut self, path_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - if !this.machine.communicate { - throw_unsup_format!("`write` not available when isolation is enabled") - } + this.check_no_isolation("unlink")?; let path_bytes = this .memory() diff --git a/src/shims/time.rs b/src/shims/time.rs index 0153c1a912df5..d75cb7bad3845 100644 --- a/src/shims/time.rs +++ b/src/shims/time.rs @@ -41,9 +41,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - if !this.machine.communicate { - throw_unsup_format!("`clock_gettime` not available when isolation is enabled") - } + this.check_no_isolation("clock_gettime")?; let clk_id = this.read_scalar(clk_id_op)?.to_i32()?; if clk_id != this.eval_libc_i32("CLOCK_REALTIME")? { @@ -75,9 +73,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - if !this.machine.communicate { - throw_unsup_format!("`gettimeofday` not available when isolation is enabled") - } + this.check_no_isolation("gettimeofday")?; // Using tz is obsolete and should always be null let tz = this.read_scalar(tz_op)?.not_undef()?; if !this.is_null(tz)? { From 24872230dc25f40b5683549bdb1e288964744e77 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Mon, 14 Oct 2019 16:42:29 -0500 Subject: [PATCH 1211/3747] Check that access mode flags only use the first two bits --- src/shims/fs.rs | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/src/shims/fs.rs b/src/shims/fs.rs index 4d93ca4fd31b7..c3dc5e60f0b4b 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -43,15 +43,23 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let mut options = OpenOptions::new(); - // The first two bits of the flag correspond to the access mode of the file in linux. This - // is done this way because `O_RDONLY` is zero in several platforms. + let o_rdonly = this.eval_libc_i32("O_RDONLY")?; + let o_wronly = this.eval_libc_i32("O_WRONLY")?; + let o_rdwr = this.eval_libc_i32("O_RDWR")?; + // The first two bits of the flag correspond to the access mode in linux, macOS and + // windows. We need to check that in fact the access mode flags for the current platform + // only use these two bits, otherwise we are in an unsupported platform and should error. + if (o_rdonly | o_wronly | o_rdwr) & !0b11 != 0 { + throw_unsup_format!("Access mode flags on this platform are unsupported"); + } + // Now we check the access mode let access_mode = flag & 0b11; - if access_mode == this.eval_libc_i32("O_RDONLY")? { + if access_mode == o_rdonly { options.read(true); - } else if access_mode == this.eval_libc_i32("O_WRONLY")? { + } else if access_mode == o_wronly { options.write(true); - } else if access_mode == this.eval_libc_i32("O_RDWR")? { + } else if access_mode == o_rdwr { options.read(true).write(true); } else { throw_unsup_format!("Unsupported access mode {:#x}", access_mode); @@ -124,8 +132,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // `FD_CLOEXEC` value without checking if the flag is set for the file because `std` // always sets this flag when opening a file. However we still need to check that the // file itself is open. - this.get_handle_and(fd, |_| Ok(0))?; - this.eval_libc_i32("FD_CLOEXEC") + let fd_cloexec = this.eval_libc_i32("FD_CLOEXEC")?; + this.get_handle_and(fd, |_| Ok(fd_cloexec)) } else { throw_unsup_format!("The {:#x} command is not supported for `fcntl`)", cmd); } From a94d9d2c1d76f71fcf3ed5d27e5d20bec87cea62 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 16 Oct 2019 10:02:31 +0200 Subject: [PATCH 1212/3747] install minimal profile by default --- .appveyor.yml | 2 +- .travis.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index 582b55f62dbb5..d0668c72acdba 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -21,7 +21,7 @@ install: - set /p RUSTC_HASH= Date: Wed, 16 Oct 2019 10:41:50 +0200 Subject: [PATCH 1213/3747] cleanup: remove leftover rust-docs components --- .appveyor.yml | 1 + .travis.yml | 1 + 2 files changed, 2 insertions(+) diff --git a/.appveyor.yml b/.appveyor.yml index d0668c72acdba..60963438abfff 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -25,6 +25,7 @@ install: - set PATH=%USERPROFILE%\.cargo\bin;%PATH% - rustup default stable - rustup uninstall beta + - rustup component remove rust-docs & exit 0 - rustup update # Install "master" toolchain - cargo install rustup-toolchain-install-master & exit 0 diff --git a/.travis.yml b/.travis.yml index e6d5ee08892bf..51f02e76824be 100644 --- a/.travis.yml +++ b/.travis.yml @@ -35,6 +35,7 @@ before_script: - export PATH=$HOME/.cargo/bin:$PATH - rustup default stable - rustup uninstall beta +- rustup component remove rust-docs || echo "rust-docs already gone" - rustup update # Install "master" toolchain - cargo install rustup-toolchain-install-master || echo "rustup-toolchain-install-master already installed" From cb913698d28b911e4ea0b5113c3f4e102ee0285c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 16 Oct 2019 10:45:48 +0200 Subject: [PATCH 1214/3747] make sure we don't install more than we have to --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 0187047534d48..6d0173aaf04e3 100644 --- a/README.md +++ b/README.md @@ -105,6 +105,7 @@ nightly that *does* come with Miri: ```sh MIRI_NIGHTLY=nightly-$(curl -s https://rust-lang.github.io/rustup-components-history/x86_64-unknown-linux-gnu/miri) echo "Installing latest nightly with Miri: $MIRI_NIGHTLY" +rustup set profile minimal rustup default "$MIRI_NIGHTLY" rustup component add miri From 2967d0d13aa9ad536ad9532ad6eb04d3ac336346 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 16 Oct 2019 21:45:17 +0200 Subject: [PATCH 1215/3747] better error when using cargo-miri in a workspace --- src/bin/cargo-miri.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 15c66f8c0dbaa..b189dc1f808c3 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -91,7 +91,7 @@ fn list_targets() -> impl Iterator { let mut metadata = if let Ok(metadata) = cmd.exec() { metadata } else { - show_error(format!("Could not obtain Cargo metadata")); + show_error(format!("Could not obtain Cargo metadata; likely an ill-formed manifest")); }; let current_dir = std::env::current_dir(); @@ -113,7 +113,7 @@ fn list_targets() -> impl Iterator { package_manifest_directory == current_dir } }) - .expect("could not find matching package"); + .unwrap_or_else(|| show_error(format!("This seems to be a workspace, which is not supported by cargo-miri"))); let package = metadata.packages.remove(package_index); // Finally we got the list of targets to build From a353e90eedb088acf0535c62cac656c5c2621d76 Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Fri, 18 Oct 2019 11:11:50 +0900 Subject: [PATCH 1216/3747] Use memory field instead of memory() --- src/eval.rs | 12 ++++---- src/helpers.rs | 8 +++--- src/machine.rs | 6 ++-- src/operator.rs | 2 +- src/shims/env.rs | 20 +++++++------- src/shims/foreign_items.rs | 56 +++++++++++++++++++------------------- src/shims/fs.rs | 8 +++--- src/shims/intrinsics.rs | 24 ++++++++-------- src/shims/mod.rs | 2 +- src/stacked_borrows.rs | 6 ++-- 10 files changed, 72 insertions(+), 72 deletions(-) diff --git a/src/eval.rs b/src/eval.rs index aa876d6617ce8..77bc096e31983 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -93,7 +93,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( // First argument: pointer to `main()`. let main_ptr = ecx - .memory_mut() + .memory .create_fn_alloc(FnVal::Instance(main_instance)); let dest = ecx.local_place(args.next().unwrap())?; ecx.write_scalar(Scalar::Ptr(main_ptr), dest)?; @@ -128,7 +128,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( let mut arg = arg.into_bytes(); arg.push(0); argvs.push( - ecx.memory_mut() + ecx.memory .allocate_static_bytes(arg.as_slice(), MiriMemoryKind::Static.into()), ); } @@ -142,7 +142,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( let place = ecx.mplace_field(argvs_place, idx as u64)?; ecx.write_scalar(Scalar::Ptr(arg), place.into())?; } - ecx.memory_mut() + ecx.memory .mark_immutable(argvs_place.ptr.assert_ptr().alloc_id)?; // Write a pointer to that place as the argument. let argv = argvs_place.ptr; @@ -157,7 +157,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( { let tcx = &{ ecx.tcx.tcx }; let cmd_utf16: Vec = cmd.encode_utf16().collect(); - let cmd_ptr = ecx.memory_mut().allocate( + let cmd_ptr = ecx.memory.allocate( Size::from_bytes(cmd_utf16.len() as u64 * 2), Align::from_bytes(2).unwrap(), MiriMemoryKind::Env.into(), @@ -165,7 +165,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( ecx.machine.cmd_line = Some(cmd_ptr); // Store the UTF-16 string. let char_size = Size::from_bytes(2); - let cmd_alloc = ecx.memory_mut().get_mut(cmd_ptr.alloc_id)?; + let cmd_alloc = ecx.memory.get_mut(cmd_ptr.alloc_id)?; let mut cur_ptr = cmd_ptr; for &c in cmd_utf16.iter() { cmd_alloc.write_scalar( @@ -211,7 +211,7 @@ pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) { // Process the result. match res { Ok(()) => { - let leaks = ecx.memory().leak_report(); + let leaks = ecx.memory.leak_report(); // Disable the leak test on some platforms where we do not // correctly implement TLS destructors. let target_os = ecx.tcx.tcx.sess.target.target.target_os.to_lowercase(); diff --git a/src/helpers.rs b/src/helpers.rs index e3f818414da3d..08e28e909ab28 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -57,7 +57,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// Test if this immediate equals 0. fn is_null(&self, val: Scalar) -> InterpResult<'tcx, bool> { let this = self.eval_context_ref(); - let null = Scalar::from_int(0, this.memory().pointer_size()); + let null = Scalar::from_int(0, this.memory.pointer_size()); this.ptr_eq(val, null) } @@ -94,7 +94,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } let this = self.eval_context_mut(); - let ptr = this.memory().check_ptr_access( + let ptr = this.memory.check_ptr_access( ptr, Size::from_bytes(len as u64), Align::from_bytes(1).unwrap() @@ -108,12 +108,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx .map_err(|err| err_unsup_format!("getrandom failed: {}", err))?; } else { - let rng = this.memory_mut().extra.rng.get_mut(); + let rng = this.memory.extra.rng.get_mut(); rng.fill_bytes(&mut data); } let tcx = &{this.tcx.tcx}; - this.memory_mut().get_mut(ptr.alloc_id)?.write_bytes(tcx, ptr, &data) + this.memory.get_mut(ptr.alloc_id)?.write_bytes(tcx, ptr, &data) } /// Visits the memory covered by `place`, sensitive to freezing: the 3rd parameter diff --git a/src/machine.rs b/src/machine.rs index c22b3805d46ba..d20346ba468a1 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -164,7 +164,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { #[inline(always)] fn enforce_validity(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool { - ecx.memory().extra.validate + ecx.memory.extra.validate } #[inline(always)] @@ -349,7 +349,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { fn stack_push( ecx: &mut InterpCx<'mir, 'tcx, Self>, ) -> InterpResult<'tcx, stacked_borrows::CallId> { - Ok(ecx.memory().extra.stacked_borrows.borrow_mut().new_call()) + Ok(ecx.memory.extra.stacked_borrows.borrow_mut().new_call()) } #[inline(always)] @@ -358,7 +358,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { extra: stacked_borrows::CallId, ) -> InterpResult<'tcx> { Ok(ecx - .memory() + .memory .extra .stacked_borrows .borrow_mut() diff --git a/src/operator.rs b/src/operator.rs index 45bf1e453744c..9c02c56fd6a1a 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -34,7 +34,7 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { /// Test if the pointer is in-bounds of a live allocation. #[inline] fn pointer_inbounds(&self, ptr: Pointer) -> InterpResult<'tcx> { - let (size, _align) = self.memory().get_size_and_align(ptr.alloc_id, AllocCheck::Live)?; + let (size, _align) = self.memory.get_size_and_align(ptr.alloc_id, AllocCheck::Live)?; ptr.check_inbounds_alloc(size, CheckInAllocMsg::InboundsTest) } diff --git a/src/shims/env.rs b/src/shims/env.rs index ae800c2315fe1..bd9263d8bf2b7 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -26,7 +26,7 @@ impl EnvVars { for (name, value) in env::vars() { if !excluded_env_vars.contains(&name) { let var_ptr = - alloc_env_var(name.as_bytes(), value.as_bytes(), ecx.memory_mut()); + alloc_env_var(name.as_bytes(), value.as_bytes(), &mut ecx.memory); ecx.machine.env_vars.map.insert(name.into_bytes(), var_ptr); } } @@ -52,7 +52,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); let name_ptr = this.read_scalar(name_op)?.not_undef()?; - let name = this.memory().read_c_str(name_ptr)?; + let name = this.memory.read_c_str(name_ptr)?; Ok(match this.machine.env_vars.map.get(name) { // The offset is used to strip the "{name}=" part of the string. Some(var_ptr) => { @@ -71,18 +71,18 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let name_ptr = this.read_scalar(name_op)?.not_undef()?; let value_ptr = this.read_scalar(value_op)?.not_undef()?; - let value = this.memory().read_c_str(value_ptr)?; + let value = this.memory.read_c_str(value_ptr)?; let mut new = None; if !this.is_null(name_ptr)? { - let name = this.memory().read_c_str(name_ptr)?; + let name = this.memory.read_c_str(name_ptr)?; if !name.is_empty() && !name.contains(&b'=') { new = Some((name.to_owned(), value.to_owned())); } } if let Some((name, value)) = new { - let var_ptr = alloc_env_var(&name, &value, this.memory_mut()); + let var_ptr = alloc_env_var(&name, &value, &mut this.memory); if let Some(var) = this.machine.env_vars.map.insert(name.to_owned(), var_ptr) { - this.memory_mut() + this.memory .deallocate(var, None, MiriMemoryKind::Env.into())?; } Ok(0) @@ -97,14 +97,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let name_ptr = this.read_scalar(name_op)?.not_undef()?; let mut success = None; if !this.is_null(name_ptr)? { - let name = this.memory().read_c_str(name_ptr)?.to_owned(); + let name = this.memory.read_c_str(name_ptr)?.to_owned(); if !name.is_empty() && !name.contains(&b'=') { success = Some(this.machine.env_vars.map.remove(&name)); } } if let Some(old) = success { if let Some(var) = old { - this.memory_mut() + this.memory .deallocate(var, None, MiriMemoryKind::Env.into())?; } Ok(0) @@ -140,7 +140,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // This is ok because the buffer was strictly larger than `bytes`, so after // adding the null terminator, the buffer size is larger or equal to // `bytes.len()`, meaning that `bytes` actually fit inside tbe buffer. - this.memory_mut() + this.memory .get_mut(buf.alloc_id)? .write_bytes(tcx, buf, &bytes)?; return Ok(Scalar::Ptr(buf)); @@ -159,7 +159,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.check_no_isolation("chdir")?; let path_bytes = this - .memory() + .memory .read_c_str(this.read_scalar(path_op)?.not_undef()?)?; let path = Path::new( diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index f6195961ba064..563acde00e1e1 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -48,11 +48,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } else { let align = this.min_align(size, kind); let ptr = this - .memory_mut() + .memory .allocate(Size::from_bytes(size), align, kind.into()); if zero_init { // We just allocated this, the access cannot fail - this.memory_mut() + this.memory .get_mut(ptr.alloc_id) .unwrap() .write_repeat(tcx, ptr, 0, Size::from_bytes(size)) @@ -66,7 +66,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); if !this.is_null(ptr)? { let ptr = this.force_ptr(ptr)?; - this.memory_mut().deallocate(ptr, None, kind.into())?; + this.memory.deallocate(ptr, None, kind.into())?; } Ok(()) } @@ -84,13 +84,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(Scalar::from_int(0, this.pointer_size())) } else { let new_ptr = - this.memory_mut() + this.memory .allocate(Size::from_bytes(new_size), new_align, kind.into()); Ok(Scalar::Ptr(new_ptr)) } } else { let old_ptr = this.force_ptr(old_ptr)?; - let memory = this.memory_mut(); + let memory = &mut this.memory; if new_size == 0 { memory.deallocate(old_ptr, None, kind.into())?; Ok(Scalar::from_int(0, this.pointer_size())) @@ -179,7 +179,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if size == 0 { this.write_null(ret.into())?; } else { - let ptr = this.memory_mut().allocate( + let ptr = this.memory.allocate( Size::from_bytes(size), Align::from_bytes(align).unwrap(), MiriMemoryKind::C.into(), @@ -208,7 +208,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if !align.is_power_of_two() { throw_unsup!(HeapAllocNonPowerOfTwoAlignment(align)); } - let ptr = this.memory_mut().allocate( + let ptr = this.memory.allocate( Size::from_bytes(size), Align::from_bytes(align).unwrap(), MiriMemoryKind::Rust.into(), @@ -224,13 +224,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if !align.is_power_of_two() { throw_unsup!(HeapAllocNonPowerOfTwoAlignment(align)); } - let ptr = this.memory_mut().allocate( + let ptr = this.memory.allocate( Size::from_bytes(size), Align::from_bytes(align).unwrap(), MiriMemoryKind::Rust.into(), ); // We just allocated this, the access cannot fail - this.memory_mut() + this.memory .get_mut(ptr.alloc_id) .unwrap() .write_repeat(tcx, ptr, 0, Size::from_bytes(size)) @@ -248,7 +248,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx throw_unsup!(HeapAllocNonPowerOfTwoAlignment(align)); } let ptr = this.force_ptr(ptr)?; - this.memory_mut().deallocate( + this.memory.deallocate( ptr, Some(( Size::from_bytes(old_size), @@ -269,7 +269,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx throw_unsup!(HeapAllocNonPowerOfTwoAlignment(align)); } let align = Align::from_bytes(align).unwrap(); - let new_ptr = this.memory_mut().reallocate( + let new_ptr = this.memory.reallocate( ptr, Some((Size::from_bytes(old_size), align)), Size::from_bytes(new_size), @@ -304,11 +304,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "dlsym" => { let _handle = this.read_scalar(args[0])?; let symbol = this.read_scalar(args[1])?.not_undef()?; - let symbol_name = this.memory().read_c_str(symbol)?; + let symbol_name = this.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); if let Some(dlsym) = Dlsym::from_str(symbol_name)? { - let ptr = this.memory_mut().create_fn_alloc(FnVal::Other(dlsym)); + let ptr = this.memory.create_fn_alloc(FnVal::Other(dlsym)); this.write_scalar(Scalar::from(ptr), dest)?; } else { this.write_null(dest)?; @@ -325,7 +325,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // We abort on panic, so not much is going on here, but we still have to call the closure. let f = this.read_scalar(args[0])?.not_undef()?; let data = this.read_scalar(args[1])?.not_undef()?; - let f_instance = this.memory().get_fn(f)?.as_instance()?; + let f_instance = this.memory.get_fn(f)?.as_instance()?; this.write_null(dest)?; trace!("__rust_maybe_catch_panic: {:?}", f_instance); @@ -369,8 +369,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let n = Size::from_bytes(this.read_scalar(args[2])?.to_usize(this)?); let result = { - let left_bytes = this.memory().read_bytes(left, n)?; - let right_bytes = this.memory().read_bytes(right, n)?; + let left_bytes = this.memory.read_bytes(left, n)?; + let right_bytes = this.memory.read_bytes(right, n)?; use std::cmp::Ordering::*; match left_bytes.cmp(right_bytes) { @@ -388,7 +388,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let val = this.read_scalar(args[1])?.to_i32()? as u8; let num = this.read_scalar(args[2])?.to_usize(this)?; if let Some(idx) = this - .memory() + .memory .read_bytes(ptr, Size::from_bytes(num))? .iter() .rev() @@ -406,7 +406,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let val = this.read_scalar(args[1])?.to_i32()? as u8; let num = this.read_scalar(args[2])?.to_usize(this)?; let idx = this - .memory() + .memory .read_bytes(ptr, Size::from_bytes(num))? .iter() .position(|&c| c == val); @@ -477,7 +477,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // stdout/stderr use std::io::{self, Write}; - let buf_cont = this.memory().read_bytes(buf, Size::from_bytes(n))?; + let buf_cont = this.memory.read_bytes(buf, Size::from_bytes(n))?; // We need to flush to make sure this actually appears on the screen let res = if fd == 1 { // Stdout is buffered, flush to make sure it appears on the screen. @@ -519,7 +519,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "strlen" => { let ptr = this.read_scalar(args[0])?.not_undef()?; - let n = this.memory().read_c_str(ptr)?.len(); + let n = this.memory.read_c_str(ptr)?.len(); this.write_scalar(Scalar::from_uint(n as u64, dest.layout.size), dest)?; } @@ -649,7 +649,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Extract the function type out of the signature (that seems easier than constructing it ourselves). let dtor = match this.test_null(this.read_scalar(args[1])?.not_undef()?)? { - Some(dtor_ptr) => Some(this.memory().get_fn(dtor_ptr)?.as_instance()?), + Some(dtor_ptr) => Some(this.memory.get_fn(dtor_ptr)?.as_instance()?), None => None, }; @@ -671,10 +671,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } let key_ptr = this - .memory() + .memory .check_ptr_access(key_ptr, key_layout.size, key_layout.align.abi)? .expect("cannot be a ZST"); - this.memory_mut().get_mut(key_ptr.alloc_id)?.write_scalar( + this.memory.get_mut(key_ptr.alloc_id)?.write_scalar( tcx, key_ptr, Scalar::from_uint(key, key_layout.size).into(), @@ -859,13 +859,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx .check_mplace_access(system_info, None)? .expect("cannot be a ZST"); // Initialize with `0`. - this.memory_mut() + this.memory .get_mut(system_info_ptr.alloc_id)? .write_repeat(tcx, system_info_ptr, 0, system_info.layout.size)?; // Set number of processors. let dword_size = Size::from_bytes(4); let offset = 2 * dword_size + 3 * tcx.pointer_size(); - this.memory_mut() + this.memory .get_mut(system_info_ptr.alloc_id)? .write_scalar( tcx, @@ -920,7 +920,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx use std::io::{self, Write}; let buf_cont = this - .memory() + .memory .read_bytes(buf, Size::from_bytes(u64::from(n)))?; let res = if handle == -11 { io::stdout().write(buf_cont) @@ -995,7 +995,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); let tcx = &{ this.tcx.tcx }; let errno_ptr = this.machine.last_error.unwrap(); - this.memory_mut().get_mut(errno_ptr.alloc_id)?.write_scalar( + this.memory.get_mut(errno_ptr.alloc_id)?.write_scalar( tcx, errno_ptr, scalar.into(), @@ -1007,7 +1007,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); let tcx = &{ this.tcx.tcx }; let errno_ptr = this.machine.last_error.unwrap(); - this.memory() + this.memory .get(errno_ptr.alloc_id)? .read_scalar(tcx, errno_ptr, Size::from_bits(32))? .not_undef() diff --git a/src/shims/fs.rs b/src/shims/fs.rs index 445c98fd9fa4d..3a16e2868958d 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -95,7 +95,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } let path_bytes = this - .memory() + .memory .read_c_str(this.read_scalar(path_op)?.not_undef()?)?; let path = std::str::from_utf8(path_bytes) .map_err(|_| err_unsup_format!("{:?} is not a valid utf-8 string", path_bytes))?; @@ -171,7 +171,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.remove_handle_and(fd, |mut handle, this| { // Don't use `?` to avoid returning before reinserting the handle let bytes = this.force_ptr(buf_scalar).and_then(|buf| { - this.memory_mut() + this.memory .get_mut(buf.alloc_id)? .get_bytes_mut(tcx, buf, Size::from_bytes(count)) .map(|buffer| handle.file.read(buffer)) @@ -203,7 +203,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let buf = this.force_ptr(this.read_scalar(buf_op)?.not_undef()?)?; this.remove_handle_and(fd, |mut handle, this| { - let bytes = this.memory().get(buf.alloc_id).and_then(|alloc| { + let bytes = this.memory.get(buf.alloc_id).and_then(|alloc| { alloc .get_bytes(tcx, buf, Size::from_bytes(count)) .map(|bytes| handle.file.write(bytes).map(|bytes| bytes as i64)) @@ -219,7 +219,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.check_no_isolation("unlink")?; let path_bytes = this - .memory() + .memory .read_c_str(this.read_scalar(path_op)?.not_undef()?)?; let path = std::str::from_utf8(path_bytes) .map_err(|_| err_unsup_format!("{:?} is not a valid utf-8 string", path_bytes))?; diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 875a344363a01..1fa2b5a0d01fc 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -68,7 +68,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // even if the type they wrap would be less aligned (e.g. AtomicU64 on 32bit must // be 8-aligned). let align = Align::from_bytes(place.layout.size.bytes()).unwrap(); - this.memory().check_ptr_access(place.ptr, place.layout.size, align)?; + this.memory.check_ptr_access(place.ptr, place.layout.size, align)?; this.write_scalar(val, dest)?; } @@ -83,7 +83,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // even if the type they wrap would be less aligned (e.g. AtomicU64 on 32bit must // be 8-aligned). let align = Align::from_bytes(place.layout.size.bytes()).unwrap(); - this.memory().check_ptr_access(place.ptr, place.layout.size, align)?; + this.memory.check_ptr_access(place.ptr, place.layout.size, align)?; this.write_scalar(val, place.into())?; } @@ -104,7 +104,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // even if the type they wrap would be less aligned (e.g. AtomicU64 on 32bit must // be 8-aligned). let align = Align::from_bytes(place.layout.size.bytes()).unwrap(); - this.memory().check_ptr_access(place.ptr, place.layout.size, align)?; + this.memory.check_ptr_access(place.ptr, place.layout.size, align)?; this.write_scalar(old, dest)?; // old value is returned this.write_scalar(new, place.into())?; @@ -120,7 +120,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // even if the type they wrap would be less aligned (e.g. AtomicU64 on 32bit must // be 8-aligned). let align = Align::from_bytes(place.layout.size.bytes()).unwrap(); - this.memory().check_ptr_access(place.ptr, place.layout.size, align)?; + this.memory.check_ptr_access(place.ptr, place.layout.size, align)?; // binary_op will bail if either of them is not a scalar let eq = this.overflowing_binary_op(mir::BinOp::Eq, old, expect_old)?.0; @@ -173,7 +173,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // even if the type they wrap would be less aligned (e.g. AtomicU64 on 32bit must // be 8-aligned). let align = Align::from_bytes(place.layout.size.bytes()).unwrap(); - this.memory().check_ptr_access(place.ptr, place.layout.size, align)?; + this.memory.check_ptr_access(place.ptr, place.layout.size, align)?; this.write_immediate(*old, dest)?; // old value is returned let (op, neg) = match intrinsic_name.split('_').nth(1).unwrap() { @@ -207,12 +207,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let size = Size::from_bytes(count * elem_size); let src = this.read_scalar(args[0])?.not_undef()?; - let src = this.memory().check_ptr_access(src, size, elem_align)?; + let src = this.memory.check_ptr_access(src, size, elem_align)?; let dest = this.read_scalar(args[1])?.not_undef()?; - let dest = this.memory().check_ptr_access(dest, size, elem_align)?; + let dest = this.memory.check_ptr_access(dest, size, elem_align)?; if let (Some(src), Some(dest)) = (src, dest) { - this.memory_mut().copy( + this.memory.copy( src, dest, size, @@ -359,7 +359,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx assert!(mplace.meta.is_none()); // not a zst, must be valid pointer let ptr = mplace.ptr.to_ptr()?; - this.memory_mut().get_mut(ptr.alloc_id)?.write_repeat(tcx, ptr, 0, dest.layout.size)?; + this.memory.get_mut(ptr.alloc_id)?.write_repeat(tcx, ptr, 0, dest.layout.size)?; } } } @@ -548,7 +548,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let mplace = this.force_allocation(dest)?; assert!(mplace.meta.is_none()); let ptr = mplace.ptr.to_ptr()?; - this.memory_mut() + this.memory .get_mut(ptr.alloc_id)? .mark_definedness(ptr, dest.layout.size, false); } @@ -563,9 +563,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let ptr = this.read_scalar(args[0])?.not_undef()?; let count = this.read_scalar(args[2])?.to_usize(this)?; let byte_count = ty_layout.size * count; - match this.memory().check_ptr_access(ptr, byte_count, ty_layout.align.abi)? { + match this.memory.check_ptr_access(ptr, byte_count, ty_layout.align.abi)? { Some(ptr) => { - this.memory_mut() + this.memory .get_mut(ptr.alloc_id)? .write_repeat(tcx, ptr, val_byte, byte_count)?; } diff --git a/src/shims/mod.rs b/src/shims/mod.rs index 95bb8b70370f1..60974958c42ab 100644 --- a/src/shims/mod.rs +++ b/src/shims/mod.rs @@ -75,7 +75,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let ptr_scalar = this.read_scalar(ptr_op)?.not_undef()?; if let Ok(ptr) = this.force_ptr(ptr_scalar) { - let cur_align = this.memory().get(ptr.alloc_id)?.align.bytes() as usize; + let cur_align = this.memory.get(ptr.alloc_id)?.align.bytes() as usize; if cur_align >= req_align { // if the allocation alignment is at least the required alignment we use the // libcore implementation diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 5258cbb5485b4..d219c1c758345 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -533,14 +533,14 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let protector = if protect { Some(this.frame().extra) } else { None }; - let ptr = this.memory().check_ptr_access(place.ptr, size, place.align) + let ptr = this.memory.check_ptr_access(place.ptr, size, place.align) .expect("validity checks should have excluded dangling/unaligned pointer") .expect("we shouldn't get here for ZST"); trace!("reborrow: {} reference {:?} derived from {:?} (pointee {}): {:?}, size {}", kind, new_tag, ptr.tag, place.layout.ty, ptr.erase_tag(), size.bytes()); // Get the allocation. It might not be mutable, so we cannot use `get_mut`. - let alloc = this.memory().get(ptr.alloc_id)?; + let alloc = this.memory.get(ptr.alloc_id)?; let stacked_borrows = alloc.extra.stacked_borrows.as_ref().expect("we should have Stacked Borrows data"); // Update the stacks. // Make sure that raw pointers and mutable shared references are reborrowed "weak": @@ -592,7 +592,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Compute new borrow. let new_tag = match kind { RefKind::Raw { .. } => Tag::Untagged, - _ => Tag::Tagged(this.memory().extra.stacked_borrows.borrow_mut().new_ptr()), + _ => Tag::Tagged(this.memory.extra.stacked_borrows.borrow_mut().new_ptr()), }; // Reborrow. From 17449fbce6da59668987bc8527ea6f84f038dd0c Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Fri, 18 Oct 2019 11:21:20 +0900 Subject: [PATCH 1217/3747] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 820490edd618e..0f59c13723c7d 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -d28a9c38fe14396e86ae274c7847e20ee0f78ca9 +fa0f7d0080d8e7e9eb20aa9cbf8013f96c81287f From 5481afbaf64c05d5647533df0ec58492af5ef455 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 18 Oct 2019 11:33:12 +0200 Subject: [PATCH 1218/3747] cleanup now that borrow checker knows memory is a field --- src/eval.rs | 5 ++--- src/helpers.rs | 10 +++------- src/shims/env.rs | 8 +++----- src/shims/foreign_items.rs | 18 +++++++----------- src/shims/fs.rs | 8 ++------ src/shims/intrinsics.rs | 2 +- 6 files changed, 18 insertions(+), 33 deletions(-) diff --git a/src/eval.rs b/src/eval.rs index 77bc096e31983..bb0bad0ea03d7 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -155,7 +155,6 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( } // Store command line as UTF-16 for Windows `GetCommandLineW`. { - let tcx = &{ ecx.tcx.tcx }; let cmd_utf16: Vec = cmd.encode_utf16().collect(); let cmd_ptr = ecx.memory.allocate( Size::from_bytes(cmd_utf16.len() as u64 * 2), @@ -169,12 +168,12 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( let mut cur_ptr = cmd_ptr; for &c in cmd_utf16.iter() { cmd_alloc.write_scalar( - tcx, + &*ecx.tcx, cur_ptr, Scalar::from_uint(c, char_size).into(), char_size, )?; - cur_ptr = cur_ptr.offset(char_size, tcx)?; + cur_ptr = cur_ptr.offset(char_size, &*ecx.tcx)?; } } diff --git a/src/helpers.rs b/src/helpers.rs index 08e28e909ab28..c09d5c823e1bb 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -112,8 +112,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx rng.fill_bytes(&mut data); } - let tcx = &{this.tcx.tcx}; - this.memory.get_mut(ptr.alloc_id)?.write_bytes(tcx, ptr, &data) + this.memory.get_mut(ptr.alloc_id)?.write_bytes(&*this.tcx, ptr, &data) } /// Visits the memory covered by `place`, sensitive to freezing: the 3rd parameter @@ -311,8 +310,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// Helper function to get the `TyLayout` of a `libc` type fn libc_ty_layout(&mut self, name: &str) -> InterpResult<'tcx, TyLayout<'tcx>> { let this = self.eval_context_mut(); - let tcx = &{ this.tcx.tcx }; - let ty = this.resolve_path(&["libc", name])?.ty(*tcx); + let ty = this.resolve_path(&["libc", name])?.ty(*this.tcx); this.layout_of(ty) } @@ -325,14 +323,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - let tcx = &{ this.tcx.tcx }; - let mut offset = Size::from_bytes(0); for &imm in imms { this.write_immediate_to_mplace( *imm, - place.offset(offset, None, imm.layout, tcx)?, + place.offset(offset, None, imm.layout, &*this.tcx)?, )?; offset += imm.layout.size; } diff --git a/src/shims/env.rs b/src/shims/env.rs index bd9263d8bf2b7..6078ca26e269a 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -122,10 +122,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.check_no_isolation("getcwd")?; - let tcx = &{ this.tcx.tcx }; - let buf = this.force_ptr(this.read_scalar(buf_op)?.not_undef()?)?; - let size = this.read_scalar(size_op)?.to_usize(&*tcx)?; + let size = this.read_scalar(size_op)?.to_usize(&*this.tcx)?; // If we cannot get the current directory, we return null match env::current_dir() { Ok(cwd) => { @@ -142,7 +140,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // `bytes.len()`, meaning that `bytes` actually fit inside tbe buffer. this.memory .get_mut(buf.alloc_id)? - .write_bytes(tcx, buf, &bytes)?; + .write_bytes(&*this.tcx, buf, &bytes)?; return Ok(Scalar::Ptr(buf)); } let erange = this.eval_libc("ERANGE")?; @@ -150,7 +148,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } Err(e) => this.consume_io_error(e)?, } - Ok(Scalar::ptr_null(&*tcx)) + Ok(Scalar::ptr_null(&*this.tcx)) } fn chdir(&mut self, path_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 563acde00e1e1..cfbb02f608130 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -42,7 +42,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn malloc(&mut self, size: u64, zero_init: bool, kind: MiriMemoryKind) -> Scalar { let this = self.eval_context_mut(); - let tcx = &{ this.tcx.tcx }; if size == 0 { Scalar::from_int(0, this.pointer_size()) } else { @@ -55,7 +54,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.memory .get_mut(ptr.alloc_id) .unwrap() - .write_repeat(tcx, ptr, 0, Size::from_bytes(size)) + .write_repeat(&*this.tcx, ptr, 0, Size::from_bytes(size)) .unwrap(); } Scalar::Ptr(ptr) @@ -90,12 +89,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } else { let old_ptr = this.force_ptr(old_ptr)?; - let memory = &mut this.memory; if new_size == 0 { - memory.deallocate(old_ptr, None, kind.into())?; + this.memory.deallocate(old_ptr, None, kind.into())?; Ok(Scalar::from_int(0, this.pointer_size())) } else { - let new_ptr = memory.reallocate( + let new_ptr = this.memory.reallocate( old_ptr, None, Size::from_bytes(new_size), @@ -334,7 +332,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // for the TLS destructors, and of course `eval_main`. let mir = this.load_mir(f_instance.def, None)?; let ret_place = - MPlaceTy::dangling(this.layout_of(this.tcx.mk_unit())?, this).into(); + MPlaceTy::dangling(this.layout_of(tcx.mk_unit())?, this).into(); this.push_stack_frame( f_instance, mir.span, @@ -471,7 +469,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "write" => { let fd = this.read_scalar(args[0])?.to_i32()?; let buf = this.read_scalar(args[1])?.not_undef()?; - let n = this.read_scalar(args[2])?.to_usize(&*this.tcx)?; + let n = this.read_scalar(args[2])?.to_usize(tcx)?; trace!("Called write({:?}, {:?}, {:?})", fd, buf, n); let result = if fd == 1 || fd == 2 { // stdout/stderr @@ -993,10 +991,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn set_last_error(&mut self, scalar: Scalar) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - let tcx = &{ this.tcx.tcx }; let errno_ptr = this.machine.last_error.unwrap(); this.memory.get_mut(errno_ptr.alloc_id)?.write_scalar( - tcx, + &*this.tcx, errno_ptr, scalar.into(), Size::from_bits(32), @@ -1005,11 +1002,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn get_last_error(&mut self) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); - let tcx = &{ this.tcx.tcx }; let errno_ptr = this.machine.last_error.unwrap(); this.memory .get(errno_ptr.alloc_id)? - .read_scalar(tcx, errno_ptr, Size::from_bits(32))? + .read_scalar(&*this.tcx, errno_ptr, Size::from_bits(32))? .not_undef() } diff --git a/src/shims/fs.rs b/src/shims/fs.rs index 3a16e2868958d..891474bc3bdb6 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -157,8 +157,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.check_no_isolation("read")?; - let tcx = &{ this.tcx.tcx }; - let count = this.read_scalar(count_op)?.to_usize(&*this.tcx)?; // Reading zero bytes should not change `buf` if count == 0 { @@ -173,7 +171,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let bytes = this.force_ptr(buf_scalar).and_then(|buf| { this.memory .get_mut(buf.alloc_id)? - .get_bytes_mut(tcx, buf, Size::from_bytes(count)) + .get_bytes_mut(&*this.tcx, buf, Size::from_bytes(count)) .map(|buffer| handle.file.read(buffer)) }); // Reinsert the file handle @@ -192,8 +190,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.check_no_isolation("write")?; - let tcx = &{ this.tcx.tcx }; - let count = this.read_scalar(count_op)?.to_usize(&*this.tcx)?; // Writing zero bytes should not change `buf` if count == 0 { @@ -205,7 +201,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.remove_handle_and(fd, |mut handle, this| { let bytes = this.memory.get(buf.alloc_id).and_then(|alloc| { alloc - .get_bytes(tcx, buf, Size::from_bytes(count)) + .get_bytes(&*this.tcx, buf, Size::from_bytes(count)) .map(|bytes| handle.file.write(bytes).map(|bytes| bytes as i64)) }); this.machine.file_handler.handles.insert(fd, handle); diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 1fa2b5a0d01fc..4666557e200c0 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -28,7 +28,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // (as opposed to through a place), we have to remember to erase any tag // that might still hang around! - let intrinsic_name = &*this.tcx.item_name(instance.def_id()).as_str(); + let intrinsic_name = &*tcx.item_name(instance.def_id()).as_str(); match intrinsic_name { "arith_offset" => { let offset = this.read_scalar(args[1])?.to_isize(this)?; From 61da8b84282d4b44f4dd1742328867cae9e5cefc Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Sun, 13 Oct 2019 15:26:03 -0500 Subject: [PATCH 1219/3747] Add OsString from/to bytes helper functions --- src/helpers.rs | 23 +++++++++++++++++++++++ src/shims/env.rs | 16 +++++----------- src/shims/fs.rs | 5 ++--- tests/compile-fail/chdir_invalid_path.rs | 11 ----------- 4 files changed, 30 insertions(+), 25 deletions(-) delete mode 100644 tests/compile-fail/chdir_invalid_path.rs diff --git a/src/helpers.rs b/src/helpers.rs index c09d5c823e1bb..c2e4131a76d10 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -1,4 +1,5 @@ use std::mem; +use std::ffi::OsString; use rustc::hir::def_id::{DefId, CRATE_DEF_INDEX}; use rustc::mir; @@ -345,3 +346,25 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(()) } } + + +pub fn bytes_to_os_string<'tcx>(bytes: Vec) -> InterpResult<'tcx, OsString> { + if cfg!(unix) { + Ok(std::os::unix::ffi::OsStringExt::from_vec(bytes)) + } else { + std::str::from_utf8(&bytes) + .map_err(|_| err_unsup_format!("{:?} is not a valid utf-8 string", bytes).into()) + .map(OsString::from) + } + } + +pub fn os_string_to_bytes<'tcx>(os_string: OsString) -> InterpResult<'tcx, Vec> { + if cfg!(unix) { + Ok(std::os::unix::ffi::OsStringExt::into_vec(os_string)) + } else { + os_string + .into_string() + .map_err(|os_string| err_unsup_format!("{:?} is not a valid utf-8 string", os_string).into()) + .map(|s| s.into_bytes()) + } + } diff --git a/src/shims/env.rs b/src/shims/env.rs index 6078ca26e269a..1fe08aeffb7b0 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -1,9 +1,9 @@ use std::collections::HashMap; use std::env; -use std::path::Path; use crate::stacked_borrows::Tag; use crate::*; + use rustc::ty::layout::Size; use rustc_mir::interpret::{Memory, Pointer}; @@ -128,7 +128,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx match env::current_dir() { Ok(cwd) => { // It is not clear what happens with non-utf8 paths here - let mut bytes = cwd.display().to_string().into_bytes(); + let mut bytes = helpers::os_string_to_bytes(cwd.into())?; // If `size` is smaller or equal than the `bytes.len()`, writing `bytes` plus the // required null terminator to memory using the `buf` pointer would cause an // overflow. The desired behavior in this case is to return null. @@ -156,16 +156,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.check_no_isolation("chdir")?; - let path_bytes = this - .memory - .read_c_str(this.read_scalar(path_op)?.not_undef()?)?; - - let path = Path::new( - std::str::from_utf8(path_bytes) - .map_err(|_| err_unsup_format!("{:?} is not a valid utf-8 string", path_bytes))?, - ); + let bytes = this.memory.read_c_str(this.read_scalar(path_op)?.not_undef()?)?; + let path = helpers::bytes_to_os_string(bytes.to_vec()); - match env::set_current_dir(path) { + match env::set_current_dir(path?) { Ok(()) => Ok(0), Err(e) => { this.consume_io_error(e)?; diff --git a/src/shims/fs.rs b/src/shims/fs.rs index 891474bc3bdb6..cc776295bd491 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -94,11 +94,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx throw_unsup_format!("unsupported flags {:#x}", flag & !mirror); } - let path_bytes = this + let bytes = this .memory .read_c_str(this.read_scalar(path_op)?.not_undef()?)?; - let path = std::str::from_utf8(path_bytes) - .map_err(|_| err_unsup_format!("{:?} is not a valid utf-8 string", path_bytes))?; + let path: std::path::PathBuf = helpers::bytes_to_os_string(bytes.to_vec())?.into(); let fd = options.open(path).map(|file| { let mut fh = &mut this.machine.file_handler; diff --git a/tests/compile-fail/chdir_invalid_path.rs b/tests/compile-fail/chdir_invalid_path.rs deleted file mode 100644 index 22b0d723aad8c..0000000000000 --- a/tests/compile-fail/chdir_invalid_path.rs +++ /dev/null @@ -1,11 +0,0 @@ -// compile-flags: -Zmiri-disable-isolation - -extern { - pub fn chdir(dir: *const u8) -> i32; -} - -fn main() { - let path = vec![0xc3u8, 0x28, 0]; - // test that `chdir` errors with invalid utf-8 path - unsafe { chdir(path.as_ptr()) }; //~ ERROR is not a valid utf-8 string -} From 1241abbec473827acf8dbbfff8f79fe08117b967 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Thu, 17 Oct 2019 10:21:06 -0500 Subject: [PATCH 1220/3747] Change helper functions to read/write --- src/helpers.rs | 32 ++++++++++++++++++++++++-------- src/shims/env.rs | 20 +++----------------- src/shims/fs.rs | 5 +---- 3 files changed, 28 insertions(+), 29 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index c2e4131a76d10..c384b89742833 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -345,10 +345,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } Ok(()) } -} - -pub fn bytes_to_os_string<'tcx>(bytes: Vec) -> InterpResult<'tcx, OsString> { + fn read_os_string(&mut self, scalar: Scalar) -> InterpResult<'tcx, OsString> { + let bytes = self.eval_context_mut().memory.read_c_str(scalar)?.to_vec(); if cfg!(unix) { Ok(std::os::unix::ffi::OsStringExt::from_vec(bytes)) } else { @@ -358,13 +357,30 @@ pub fn bytes_to_os_string<'tcx>(bytes: Vec) -> InterpResult<'tcx, OsString> } } -pub fn os_string_to_bytes<'tcx>(os_string: OsString) -> InterpResult<'tcx, Vec> { - if cfg!(unix) { - Ok(std::os::unix::ffi::OsStringExt::into_vec(os_string)) + fn write_os_string(&mut self, os_string: OsString, ptr: Pointer, size: u64) -> InterpResult<'tcx> { + let mut bytes = if cfg!(unix) { + std::os::unix::ffi::OsStringExt::into_vec(os_string) } else { os_string .into_string() - .map_err(|os_string| err_unsup_format!("{:?} is not a valid utf-8 string", os_string).into()) - .map(|s| s.into_bytes()) + .map_err(|os_string| err_unsup_format!("{:?} is not a valid utf-8 string", os_string))? + .into_bytes() + }; + // If `size` is smaller or equal than `bytes.len()`, writing `bytes` plus the required null + // terminator to memory using the `ptr` pointer would cause an overflow. + if (bytes.len() as u64) < size { + // We add a `/0` terminator + bytes.push(0); + let this = self.eval_context_mut(); + let tcx = &{ this.tcx.tcx }; + // This is ok because the buffer was strictly larger than `bytes`, so after adding the + // null terminator, the buffer size is larger or equal to `bytes.len()`, meaning that + // `bytes` actually fit inside tbe buffer. + this.memory + .get_mut(ptr.alloc_id)? + .write_bytes(tcx, ptr, &bytes) + } else { + throw_unsup_format!("OsString is larger than destination") } } +} diff --git a/src/shims/env.rs b/src/shims/env.rs index 1fe08aeffb7b0..b344a5c549494 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -127,20 +127,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // If we cannot get the current directory, we return null match env::current_dir() { Ok(cwd) => { - // It is not clear what happens with non-utf8 paths here - let mut bytes = helpers::os_string_to_bytes(cwd.into())?; - // If `size` is smaller or equal than the `bytes.len()`, writing `bytes` plus the - // required null terminator to memory using the `buf` pointer would cause an - // overflow. The desired behavior in this case is to return null. - if (bytes.len() as u64) < size { - // We add a `/0` terminator - bytes.push(0); - // This is ok because the buffer was strictly larger than `bytes`, so after - // adding the null terminator, the buffer size is larger or equal to - // `bytes.len()`, meaning that `bytes` actually fit inside tbe buffer. - this.memory - .get_mut(buf.alloc_id)? - .write_bytes(&*this.tcx, buf, &bytes)?; + if this.write_os_string(cwd.into(), buf, size).is_ok() { return Ok(Scalar::Ptr(buf)); } let erange = this.eval_libc("ERANGE")?; @@ -156,10 +143,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.check_no_isolation("chdir")?; - let bytes = this.memory.read_c_str(this.read_scalar(path_op)?.not_undef()?)?; - let path = helpers::bytes_to_os_string(bytes.to_vec()); + let path = this.read_os_string(this.read_scalar(path_op)?.not_undef()?)?; - match env::set_current_dir(path?) { + match env::set_current_dir(path) { Ok(()) => Ok(0), Err(e) => { this.consume_io_error(e)?; diff --git a/src/shims/fs.rs b/src/shims/fs.rs index cc776295bd491..d4f9fde24e1e3 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -94,10 +94,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx throw_unsup_format!("unsupported flags {:#x}", flag & !mirror); } - let bytes = this - .memory - .read_c_str(this.read_scalar(path_op)?.not_undef()?)?; - let path: std::path::PathBuf = helpers::bytes_to_os_string(bytes.to_vec())?.into(); + let path: std::path::PathBuf = this.read_os_string(this.read_scalar(path_op)?.not_undef()?)?.into(); let fd = options.open(path).map(|file| { let mut fh = &mut this.machine.file_handler; From 68fec4b3fe3a86a01e39d31d05a8438c07845aba Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Thu, 17 Oct 2019 21:20:05 -0500 Subject: [PATCH 1221/3747] Use conditional compilation properly and work with `OsStr`s instead --- src/helpers.rs | 60 +++++++++++++++++++++++++++++++----------------- src/shims/env.rs | 3 ++- 2 files changed, 41 insertions(+), 22 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index c384b89742833..32edb107f36e1 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -1,5 +1,5 @@ use std::mem; -use std::ffi::OsString; +use std::ffi::{OsStr, OsString}; use rustc::hir::def_id::{DefId, CRATE_DEF_INDEX}; use rustc::mir; @@ -347,30 +347,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } fn read_os_string(&mut self, scalar: Scalar) -> InterpResult<'tcx, OsString> { - let bytes = self.eval_context_mut().memory.read_c_str(scalar)?.to_vec(); - if cfg!(unix) { - Ok(std::os::unix::ffi::OsStringExt::from_vec(bytes)) - } else { - std::str::from_utf8(&bytes) - .map_err(|_| err_unsup_format!("{:?} is not a valid utf-8 string", bytes).into()) - .map(OsString::from) - } + let bytes = self.eval_context_mut().memory.read_c_str(scalar)?; + Ok(bytes_to_os_str(bytes)?.into()) } - fn write_os_string(&mut self, os_string: OsString, ptr: Pointer, size: u64) -> InterpResult<'tcx> { - let mut bytes = if cfg!(unix) { - std::os::unix::ffi::OsStringExt::into_vec(os_string) - } else { - os_string - .into_string() - .map_err(|os_string| err_unsup_format!("{:?} is not a valid utf-8 string", os_string))? - .into_bytes() - }; + fn write_os_str(&mut self, os_str: &OsStr, ptr: Pointer, size: u64) -> InterpResult<'tcx> { + let bytes = os_str_to_bytes(os_str)?; // If `size` is smaller or equal than `bytes.len()`, writing `bytes` plus the required null // terminator to memory using the `ptr` pointer would cause an overflow. if (bytes.len() as u64) < size { - // We add a `/0` terminator - bytes.push(0); let this = self.eval_context_mut(); let tcx = &{ this.tcx.tcx }; // This is ok because the buffer was strictly larger than `bytes`, so after adding the @@ -378,9 +363,42 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // `bytes` actually fit inside tbe buffer. this.memory .get_mut(ptr.alloc_id)? - .write_bytes(tcx, ptr, &bytes) + .write_bytes(tcx, ptr, &bytes)?; + // We write the `/0` terminator + let tail_ptr = ptr.offset(Size::from_bytes(bytes.len() as u64 + 1), this)?; + this.memory + .get_mut(ptr.alloc_id)? + .write_bytes(tcx, tail_ptr, b"0") } else { throw_unsup_format!("OsString is larger than destination") } } } + +#[cfg(target_os = "unix")] +fn bytes_to_os_str<'tcx, 'a>(bytes: &'a[u8]) -> InterpResult<'tcx, &'a OsStr> { + Ok(std::os::unix::ffi::OsStringExt::from_bytes(bytes)) +} + +#[cfg(target_os = "unix")] +fn os_str_to_bytes<'tcx, 'a>(os_str: &'a OsStr) -> InterpResult<'tcx, &'a [u8]> { + std::os::unix::ffi::OsStringExt::into_bytes(os_str) +} + +// On non-unix platforms the best we can do to transform bytes from/to OS strings is to do the +// intermediate transformation into strings. Which invalidates non-utf8 paths that are actually +// valid. +#[cfg(not(target_os = "unix"))] +fn os_str_to_bytes<'tcx, 'a>(os_str: &'a OsStr) -> InterpResult<'tcx, &'a [u8]> { + os_str + .to_str() + .map(|s| s.as_bytes()) + .ok_or_else(|| err_unsup_format!("{:?} is not a valid utf-8 string", os_str).into()) +} + +#[cfg(not(target_os = "unix"))] +fn bytes_to_os_str<'tcx, 'a>(bytes: &'a[u8]) -> InterpResult<'tcx, &'a OsStr> { + let s = std::str::from_utf8(bytes) + .map_err(|_| err_unsup_format!("{:?} is not a valid utf-8 string", bytes))?; + Ok(&OsStr::new(s)) +} diff --git a/src/shims/env.rs b/src/shims/env.rs index b344a5c549494..b2e0709557d54 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -1,4 +1,5 @@ use std::collections::HashMap; +use std::ffi::OsString; use std::env; use crate::stacked_borrows::Tag; @@ -127,7 +128,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // If we cannot get the current directory, we return null match env::current_dir() { Ok(cwd) => { - if this.write_os_string(cwd.into(), buf, size).is_ok() { + if this.write_os_str(&OsString::from(cwd), buf, size).is_ok() { return Ok(Scalar::Ptr(buf)); } let erange = this.eval_libc("ERANGE")?; From 85941c72497e69653b847744a447ae51b433d4ba Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Fri, 18 Oct 2019 09:30:12 -0500 Subject: [PATCH 1222/3747] Rename write/read os string functions --- src/helpers.rs | 4 ++-- src/shims/env.rs | 4 ++-- src/shims/fs.rs | 8 ++------ 3 files changed, 6 insertions(+), 10 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index 32edb107f36e1..454f7d2c2f80e 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -346,12 +346,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(()) } - fn read_os_string(&mut self, scalar: Scalar) -> InterpResult<'tcx, OsString> { + fn read_os_string_from_c_string(&mut self, scalar: Scalar) -> InterpResult<'tcx, OsString> { let bytes = self.eval_context_mut().memory.read_c_str(scalar)?; Ok(bytes_to_os_str(bytes)?.into()) } - fn write_os_str(&mut self, os_str: &OsStr, ptr: Pointer, size: u64) -> InterpResult<'tcx> { + fn write_os_str_to_c_string(&mut self, os_str: &OsStr, ptr: Pointer, size: u64) -> InterpResult<'tcx> { let bytes = os_str_to_bytes(os_str)?; // If `size` is smaller or equal than `bytes.len()`, writing `bytes` plus the required null // terminator to memory using the `ptr` pointer would cause an overflow. diff --git a/src/shims/env.rs b/src/shims/env.rs index b2e0709557d54..7e2df4f985d19 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -128,7 +128,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // If we cannot get the current directory, we return null match env::current_dir() { Ok(cwd) => { - if this.write_os_str(&OsString::from(cwd), buf, size).is_ok() { + if this.write_os_str_to_c_string(&OsString::from(cwd), buf, size).is_ok() { return Ok(Scalar::Ptr(buf)); } let erange = this.eval_libc("ERANGE")?; @@ -144,7 +144,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.check_no_isolation("chdir")?; - let path = this.read_os_string(this.read_scalar(path_op)?.not_undef()?)?; + let path = this.read_os_string_from_c_string(this.read_scalar(path_op)?.not_undef()?)?; match env::set_current_dir(path) { Ok(()) => Ok(0), diff --git a/src/shims/fs.rs b/src/shims/fs.rs index d4f9fde24e1e3..7cc574f05f136 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -94,7 +94,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx throw_unsup_format!("unsupported flags {:#x}", flag & !mirror); } - let path: std::path::PathBuf = this.read_os_string(this.read_scalar(path_op)?.not_undef()?)?.into(); + let path: std::path::PathBuf = this.read_os_string_from_c_string(this.read_scalar(path_op)?.not_undef()?)?.into(); let fd = options.open(path).map(|file| { let mut fh = &mut this.machine.file_handler; @@ -210,11 +210,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.check_no_isolation("unlink")?; - let path_bytes = this - .memory - .read_c_str(this.read_scalar(path_op)?.not_undef()?)?; - let path = std::str::from_utf8(path_bytes) - .map_err(|_| err_unsup_format!("{:?} is not a valid utf-8 string", path_bytes))?; + let path = this.read_os_string_from_c_string(this.read_scalar(path_op)?.not_undef()?)?; let result = remove_file(path).map(|_| 0); From 0201cc55873dd27f0be148482ad3619083fed80b Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Fri, 18 Oct 2019 14:25:49 -0500 Subject: [PATCH 1223/3747] Fix writing errors --- src/helpers.rs | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index 454f7d2c2f80e..c975ad144e263 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -353,22 +353,19 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn write_os_str_to_c_string(&mut self, os_str: &OsStr, ptr: Pointer, size: u64) -> InterpResult<'tcx> { let bytes = os_str_to_bytes(os_str)?; + let len = bytes.len(); // If `size` is smaller or equal than `bytes.len()`, writing `bytes` plus the required null // terminator to memory using the `ptr` pointer would cause an overflow. - if (bytes.len() as u64) < size { + if (len as u64) < size { let this = self.eval_context_mut(); let tcx = &{ this.tcx.tcx }; + let buffer = this.memory.get_mut(ptr.alloc_id)?.get_bytes_mut(tcx, ptr, Size::from_bytes(len as u64 + 1))?; + buffer[..len].copy_from_slice(bytes); // This is ok because the buffer was strictly larger than `bytes`, so after adding the // null terminator, the buffer size is larger or equal to `bytes.len()`, meaning that // `bytes` actually fit inside tbe buffer. - this.memory - .get_mut(ptr.alloc_id)? - .write_bytes(tcx, ptr, &bytes)?; - // We write the `/0` terminator - let tail_ptr = ptr.offset(Size::from_bytes(bytes.len() as u64 + 1), this)?; - this.memory - .get_mut(ptr.alloc_id)? - .write_bytes(tcx, tail_ptr, b"0") + buffer[len] = 0; + Ok(()) } else { throw_unsup_format!("OsString is larger than destination") } @@ -376,13 +373,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } #[cfg(target_os = "unix")] -fn bytes_to_os_str<'tcx, 'a>(bytes: &'a[u8]) -> InterpResult<'tcx, &'a OsStr> { - Ok(std::os::unix::ffi::OsStringExt::from_bytes(bytes)) +fn os_str_to_bytes<'tcx, 'a>(os_str: &'a OsStr) -> InterpResult<'tcx, &'a [u8]> { + std::os::unix::ffi::OsStringExt::into_bytes(os_str) } #[cfg(target_os = "unix")] -fn os_str_to_bytes<'tcx, 'a>(os_str: &'a OsStr) -> InterpResult<'tcx, &'a [u8]> { - std::os::unix::ffi::OsStringExt::into_bytes(os_str) +fn bytes_to_os_str<'tcx, 'a>(bytes: &'a[u8]) -> InterpResult<'tcx, &'a OsStr> { + Ok(std::os::unix::ffi::OsStringExt::from_bytes(bytes)) } // On non-unix platforms the best we can do to transform bytes from/to OS strings is to do the From e574c77aa2292ac2a776754a60b1320058bdb071 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 19 Oct 2019 12:28:39 +0200 Subject: [PATCH 1224/3747] audit our bounds checks --- src/eval.rs | 2 +- src/helpers.rs | 1 + src/shims/foreign_items.rs | 19 ++++++------------- src/shims/intrinsics.rs | 2 ++ 4 files changed, 10 insertions(+), 14 deletions(-) diff --git a/src/eval.rs b/src/eval.rs index bb0bad0ea03d7..21a7dd35212c9 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -162,7 +162,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( MiriMemoryKind::Env.into(), ); ecx.machine.cmd_line = Some(cmd_ptr); - // Store the UTF-16 string. + // Store the UTF-16 string. We just allocated so we know the bounds are fine. let char_size = Size::from_bytes(2); let cmd_alloc = ecx.memory.get_mut(cmd_ptr.alloc_id)?; let mut cur_ptr = cmd_ptr; diff --git a/src/helpers.rs b/src/helpers.rs index c09d5c823e1bb..0c22a0f2e0653 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -94,6 +94,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } let this = self.eval_context_mut(); + // Don't forget the bounds check. let ptr = this.memory.check_ptr_access( ptr, Size::from_bytes(len as u64), diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index cfbb02f608130..cfd3743089e7d 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -50,7 +50,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx .memory .allocate(Size::from_bytes(size), align, kind.into()); if zero_init { - // We just allocated this, the access cannot fail + // We just allocated this, the access is definitely in-bounds. this.memory .get_mut(ptr.alloc_id) .unwrap() @@ -227,7 +227,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Align::from_bytes(align).unwrap(), MiriMemoryKind::Rust.into(), ); - // We just allocated this, the access cannot fail + // We just allocated this, the access is definitely in-bounds. this.memory .get_mut(ptr.alloc_id) .unwrap() @@ -643,7 +643,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Hook pthread calls that go to the thread-local storage memory subsystem. "pthread_key_create" => { - let key_ptr = this.read_scalar(args[0])?.not_undef()?; + let key_place = this.deref_operand(args[0])?; // Extract the function type out of the signature (that seems easier than constructing it ourselves). let dtor = match this.test_null(this.read_scalar(args[1])?.not_undef()?)? { @@ -668,16 +668,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx throw_unsup!(OutOfTls); } - let key_ptr = this - .memory - .check_ptr_access(key_ptr, key_layout.size, key_layout.align.abi)? - .expect("cannot be a ZST"); - this.memory.get_mut(key_ptr.alloc_id)?.write_scalar( - tcx, - key_ptr, - Scalar::from_uint(key, key_layout.size).into(), - key_layout.size, - )?; + this.write_scalar(Scalar::from_uint(key, key_layout.size), key_place.into())?; // Return success (`0`). this.write_null(dest)?; @@ -856,6 +847,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let system_info_ptr = this .check_mplace_access(system_info, None)? .expect("cannot be a ZST"); + // We rely on `deref_operand` doing bounds checks for us. // Initialize with `0`. this.memory .get_mut(system_info_ptr.alloc_id)? @@ -992,6 +984,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn set_last_error(&mut self, scalar: Scalar) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let errno_ptr = this.machine.last_error.unwrap(); + // We allocated this during machine initialziation so the bounds are fine. this.memory.get_mut(errno_ptr.alloc_id)?.write_scalar( &*this.tcx, errno_ptr, diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 4666557e200c0..cd7db09736664 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -359,6 +359,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx assert!(mplace.meta.is_none()); // not a zst, must be valid pointer let ptr = mplace.ptr.to_ptr()?; + // we know the return place is in-bounds this.memory.get_mut(ptr.alloc_id)?.write_repeat(tcx, ptr, 0, dest.layout.size)?; } } @@ -548,6 +549,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let mplace = this.force_allocation(dest)?; assert!(mplace.meta.is_none()); let ptr = mplace.ptr.to_ptr()?; + // We know the return place is in-bounds this.memory .get_mut(ptr.alloc_id)? .mark_definedness(ptr, dest.layout.size, false); From 324fed316f019a24b7a442a7759040fdd650b69f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 19 Oct 2019 16:36:45 +0200 Subject: [PATCH 1225/3747] print sysroot without any escaping --- miri | 2 +- src/bin/cargo-miri.rs | 12 ++++-------- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/miri b/miri index 6de2391137ac6..c3d7ae0280c77 100755 --- a/miri +++ b/miri @@ -54,7 +54,7 @@ build_sysroot() { # Build once, for the user to see. cargo run $CARGO_BUILD_FLAGS --bin cargo-miri -- miri setup "$@" # Call again, to just set env var. - eval $(cargo run $CARGO_BUILD_FLAGS -q --bin cargo-miri -- miri setup --env "$@") + export MIRI_SYSROOT="$(cargo run $CARGO_BUILD_FLAGS -q --bin cargo-miri -- miri setup --print-sysroot "$@")" } # Prepare and set MIRI_SYSROOT. Respects `MIRI_TEST_TARGET` and takes into account diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index b189dc1f808c3..cf513bc1d2695 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -310,7 +310,7 @@ path = "lib.rs" File::create(dir.join("lib.rs")).unwrap(); // Prepare xargo invocation. let target = get_arg_flag_value("--target"); - let print_env = !ask_user && has_arg_flag("--env"); // whether we just print the necessary environment variable + let print_sysroot = !ask_user && has_arg_flag("--print-sysroot"); // whether we just print the sysroot path let mut command = xargo(); command.arg("build").arg("-q"); command.current_dir(&dir); @@ -339,13 +339,9 @@ path = "lib.rs" }; let sysroot = if is_host { dir.join("HOST") } else { PathBuf::from(dir) }; std::env::set_var("MIRI_SYSROOT", &sysroot); // pass the env var to the processes we spawn, which will turn it into "--sysroot" flags - if print_env { - // Escape an arbitrary string for the shell: by wrapping it in `'`, the only special - // character we have to worry about is `'` itself. Everything else is taken literally - // in these strings. `'` is encoded as `'"'"'`: the outer `'` end and being a - // `'`-quoted string, respectively; the `"'"` in the middle represents a single `'`. - // (We could use `'\''` instead of `'"'"'` if we wanted but let's avoid backslashes.) - println!("MIRI_SYSROOT='{}'", sysroot.display().to_string().replace('\'', r#"'"'"'"#)); + if print_sysroot { + // Print just the sysroot and nothing else; this way we do not need any escaping. + println!("{}", sysroot.display()); } else if !ask_user { println!("A libstd for Miri is now available in `{}`.", sysroot.display()); } From ab059671cb78016bb039b3db07c62279d37ef42b Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Sat, 19 Oct 2019 14:13:49 -0500 Subject: [PATCH 1226/3747] Change comparison order for clarity --- src/helpers.rs | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index c975ad144e263..ddaf8f48a5aae 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -356,19 +356,18 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let len = bytes.len(); // If `size` is smaller or equal than `bytes.len()`, writing `bytes` plus the required null // terminator to memory using the `ptr` pointer would cause an overflow. - if (len as u64) < size { - let this = self.eval_context_mut(); - let tcx = &{ this.tcx.tcx }; - let buffer = this.memory.get_mut(ptr.alloc_id)?.get_bytes_mut(tcx, ptr, Size::from_bytes(len as u64 + 1))?; - buffer[..len].copy_from_slice(bytes); - // This is ok because the buffer was strictly larger than `bytes`, so after adding the - // null terminator, the buffer size is larger or equal to `bytes.len()`, meaning that - // `bytes` actually fit inside tbe buffer. - buffer[len] = 0; - Ok(()) - } else { - throw_unsup_format!("OsString is larger than destination") + if size <= bytes.len() as u64 { + throw_unsup_format!("OsString of length {} is too large for destination buffer of size {}", len, size) } + + let this = self.eval_context_mut(); + let buffer = this.memory.get_mut(ptr.alloc_id)?.get_bytes_mut(&*this.tcx, ptr, Size::from_bytes(len as u64 + 1))?; + buffer[..len].copy_from_slice(bytes); + // This is ok because the buffer was strictly larger than `bytes`, so after adding the + // null terminator, the buffer size is larger or equal to `bytes.len()`, meaning that + // `bytes` actually fit inside tbe buffer. + buffer[len] = 0; + Ok(()) } } From f7c6e0efbe11343562c713dce1d28e2d141dcb89 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Sat, 19 Oct 2019 15:49:00 -0500 Subject: [PATCH 1227/3747] Do additional bounds checks --- src/helpers.rs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index ddaf8f48a5aae..63380199beab4 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -356,12 +356,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let len = bytes.len(); // If `size` is smaller or equal than `bytes.len()`, writing `bytes` plus the required null // terminator to memory using the `ptr` pointer would cause an overflow. - if size <= bytes.len() as u64 { + if size <= len as u64 { throw_unsup_format!("OsString of length {} is too large for destination buffer of size {}", len, size) } - + let actual_len = (len as u64) + .checked_add(1) + .map(Size::from_bytes) + .ok_or_else(|| err_unsup_format!("OsString of length {} is too large", len))?; let this = self.eval_context_mut(); - let buffer = this.memory.get_mut(ptr.alloc_id)?.get_bytes_mut(&*this.tcx, ptr, Size::from_bytes(len as u64 + 1))?; + this.memory.check_ptr_access(ptr.into(), actual_len, Align::from_bytes(1).unwrap())?; + let buffer = this.memory.get_mut(ptr.alloc_id)?.get_bytes_mut(&*this.tcx, ptr, actual_len)?; buffer[..len].copy_from_slice(bytes); // This is ok because the buffer was strictly larger than `bytes`, so after adding the // null terminator, the buffer size is larger or equal to `bytes.len()`, meaning that From 88c88530ec5788ada08bcf23d6c7b149337f0713 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 20 Oct 2019 12:20:48 +0200 Subject: [PATCH 1228/3747] use expect_none and unwrap_none where it makes sense --- src/eval.rs | 5 +---- src/lib.rs | 1 + src/machine.rs | 5 +---- src/shims/foreign_items.rs | 5 +---- src/shims/fs.rs | 7 ++++--- src/shims/intrinsics.rs | 4 ++-- src/shims/tls.rs | 2 +- src/stacked_borrows.rs | 4 ++-- 8 files changed, 13 insertions(+), 20 deletions(-) diff --git a/src/eval.rs b/src/eval.rs index 21a7dd35212c9..6fb1cd25b159f 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -177,10 +177,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( } } - assert!( - args.next().is_none(), - "start lang item has more arguments than expected" - ); + args.next().expect_none("start lang item has more arguments than expected"); // Set the last_error to 0 let errno_layout = ecx.layout_of(ecx.tcx.types.u32)?; diff --git a/src/lib.rs b/src/lib.rs index 06ec33a914bf7..59acff358678a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,5 @@ #![feature(rustc_private)] +#![feature(option_expect_none, option_unwrap_none)] #![warn(rust_2018_idioms)] #![allow(clippy::cast_lossless)] diff --git a/src/machine.rs b/src/machine.rs index d20346ba468a1..3878a0860538f 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -244,10 +244,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { ecx.write_scalar(Scalar::from_uint(align, arg.layout.size), arg)?; // No more arguments. - assert!( - args.next().is_none(), - "`exchange_malloc` lang item has more arguments than expected" - ); + args.next().expect_none("`exchange_malloc` lang item has more arguments than expected"); Ok(()) } diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index cfd3743089e7d..b28e361b13779 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -349,10 +349,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let arg_dest = this.local_place(arg_local)?; this.write_scalar(data, arg_dest)?; - assert!( - args.next().is_none(), - "__rust_maybe_catch_panic argument has more arguments than expected" - ); + args.next().expect_none("__rust_maybe_catch_panic argument has more arguments than expected"); // We ourselves will return `0`, eventually (because we will not return if we paniced). this.write_null(dest)?; diff --git a/src/shims/fs.rs b/src/shims/fs.rs index 891474bc3bdb6..ed2465cd1f972 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -7,6 +7,7 @@ use rustc::ty::layout::Size; use crate::stacked_borrows::Tag; use crate::*; +#[derive(Debug)] pub struct FileHandle { file: File, } @@ -103,7 +104,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let fd = options.open(path).map(|file| { let mut fh = &mut this.machine.file_handler; fh.low += 1; - fh.handles.insert(fh.low, FileHandle { file }); + fh.handles.insert(fh.low, FileHandle { file }).unwrap_none(); fh.low }); @@ -175,7 +176,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx .map(|buffer| handle.file.read(buffer)) }); // Reinsert the file handle - this.machine.file_handler.handles.insert(fd, handle); + this.machine.file_handler.handles.insert(fd, handle).unwrap_none(); this.consume_result(bytes?.map(|bytes| bytes as i64)) }) } @@ -204,7 +205,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx .get_bytes(&*this.tcx, buf, Size::from_bytes(count)) .map(|bytes| handle.file.write(bytes).map(|bytes| bytes as i64)) }); - this.machine.file_handler.handles.insert(fd, handle); + this.machine.file_handler.handles.insert(fd, handle).unwrap_none(); this.consume_result(bytes?) }) } diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index cd7db09736664..46658760cc12a 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -356,7 +356,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx _ => { // Do it in memory let mplace = this.force_allocation(dest)?; - assert!(mplace.meta.is_none()); + mplace.meta.unwrap_none(); // not a zst, must be valid pointer let ptr = mplace.ptr.to_ptr()?; // we know the return place is in-bounds @@ -547,7 +547,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx _ => { // Do it in memory let mplace = this.force_allocation(dest)?; - assert!(mplace.meta.is_none()); + mplace.meta.unwrap_none(); let ptr = mplace.ptr.to_ptr()?; // We know the return place is in-bounds this.memory diff --git a/src/shims/tls.rs b/src/shims/tls.rs index 44bedbd44d2d9..b6aadd31a5be6 100644 --- a/src/shims/tls.rs +++ b/src/shims/tls.rs @@ -53,7 +53,7 @@ impl<'tcx> TlsData<'tcx> { data: None, dtor, }, - ); + ).unwrap_none(); trace!("New TLS key allocated: {} with dtor {:?}", new_key, dtor); new_key } diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index d219c1c758345..2188b9d5394a3 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -172,7 +172,7 @@ impl GlobalState { pub fn new_call(&mut self) -> CallId { let id = self.next_call_id; trace!("new_call: Assigning ID {}", id); - self.active_calls.insert(id); + assert!(self.active_calls.insert(id)); self.next_call_id = NonZeroU64::new(id.get() + 1).unwrap(); id } @@ -189,7 +189,7 @@ impl GlobalState { self.base_ptr_ids.get(&id).copied().unwrap_or_else(|| { let tag = Tag::Tagged(self.new_ptr()); trace!("New allocation {:?} has base tag {:?}", id, tag); - self.base_ptr_ids.insert(id, tag); + self.base_ptr_ids.insert(id, tag).unwrap_none(); tag }) } From 4232939319448244bacd8376049a17325225eadb Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Sat, 12 Oct 2019 20:44:45 -0500 Subject: [PATCH 1229/3747] Move last error functions to helpers --- src/helpers.rs | 35 +++++++++++++++++++++++++++++++++++ src/shims/env.rs | 4 ++-- src/shims/foreign_items.rs | 28 ---------------------------- src/shims/fs.rs | 2 +- 4 files changed, 38 insertions(+), 31 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index 0c22a0f2e0653..36091d9235550 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -345,4 +345,39 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } Ok(()) } + + /// Sets the last error variable + fn set_last_error(&mut self, scalar: Scalar) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + let tcx = &{ this.tcx.tcx }; + let errno_ptr = this.machine.last_error.unwrap(); + this.memory.get_mut(errno_ptr.alloc_id)?.write_scalar( + tcx, + errno_ptr, + scalar.into(), + Size::from_bits(32), + ) + } + + /// Gets the last error variable + fn get_last_error(&mut self) -> InterpResult<'tcx, Scalar> { + let this = self.eval_context_mut(); + let tcx = &{ this.tcx.tcx }; + let errno_ptr = this.machine.last_error.unwrap(); + this.memory + .get(errno_ptr.alloc_id)? + .read_scalar(tcx, errno_ptr, Size::from_bits(32))? + .not_undef() + } + + /// Sets the last error variable using a `std::io::Error`. It fails if the error cannot be + /// transformed to a raw os error succesfully + fn set_last_error_from_io_error(&mut self, e: std::io::Error) -> InterpResult<'tcx> { + self.eval_context_mut().set_last_error(Scalar::from_int( + e.raw_os_error().ok_or_else(|| { + err_unsup_format!("The {} error cannot be transformed into a raw os error", e) + })?, + Size::from_bits(32), + )) + } } diff --git a/src/shims/env.rs b/src/shims/env.rs index 6078ca26e269a..661e8bf209b1e 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -146,7 +146,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let erange = this.eval_libc("ERANGE")?; this.set_last_error(erange)?; } - Err(e) => this.consume_io_error(e)?, + Err(e) => this.set_last_error_from_io_error(e)?, } Ok(Scalar::ptr_null(&*this.tcx)) } @@ -168,7 +168,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx match env::set_current_dir(path) { Ok(()) => Ok(0), Err(e) => { - this.consume_io_error(e)?; + this.set_last_error_from_io_error(e)?; Ok(-1) } } diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index b28e361b13779..5d2c3648b43a5 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -977,34 +977,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } return Ok(None); } - - fn set_last_error(&mut self, scalar: Scalar) -> InterpResult<'tcx> { - let this = self.eval_context_mut(); - let errno_ptr = this.machine.last_error.unwrap(); - // We allocated this during machine initialziation so the bounds are fine. - this.memory.get_mut(errno_ptr.alloc_id)?.write_scalar( - &*this.tcx, - errno_ptr, - scalar.into(), - Size::from_bits(32), - ) - } - - fn get_last_error(&mut self) -> InterpResult<'tcx, Scalar> { - let this = self.eval_context_mut(); - let errno_ptr = this.machine.last_error.unwrap(); - this.memory - .get(errno_ptr.alloc_id)? - .read_scalar(&*this.tcx, errno_ptr, Size::from_bits(32))? - .not_undef() - } - - fn consume_io_error(&mut self, e: std::io::Error) -> InterpResult<'tcx> { - self.eval_context_mut().set_last_error(Scalar::from_int( - e.raw_os_error().unwrap(), - Size::from_bits(32), - )) - } } // Shims the linux 'getrandom()' syscall. diff --git a/src/shims/fs.rs b/src/shims/fs.rs index ed2465cd1f972..8fcd5c8b1e3e5 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -285,7 +285,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx match result { Ok(ok) => Ok(ok), Err(e) => { - self.eval_context_mut().consume_io_error(e)?; + self.eval_context_mut().set_last_error_from_io_error(e)?; Ok((-1).into()) } } From ed776f67ba73380926d987bb8ba6618fa0cc55f3 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Sat, 12 Oct 2019 20:58:02 -0500 Subject: [PATCH 1230/3747] Change last_error to a place --- src/eval.rs | 3 +-- src/helpers.rs | 18 ++++-------------- src/machine.rs | 4 ++-- src/shims/foreign_items.rs | 3 ++- 4 files changed, 9 insertions(+), 19 deletions(-) diff --git a/src/eval.rs b/src/eval.rs index 6fb1cd25b159f..f4a8d176172d4 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -183,8 +183,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( let errno_layout = ecx.layout_of(ecx.tcx.types.u32)?; let errno_place = ecx.allocate(errno_layout, MiriMemoryKind::Static.into()); ecx.write_scalar(Scalar::from_u32(0), errno_place.into())?; - let errno_ptr = ecx.check_mplace_access(errno_place.into(), Some(Size::from_bits(32)))?; - ecx.machine.last_error = errno_ptr; + ecx.machine.last_error = Some(errno_place); Ok(ecx) } diff --git a/src/helpers.rs b/src/helpers.rs index 36091d9235550..1b80166b2fe72 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -349,25 +349,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// Sets the last error variable fn set_last_error(&mut self, scalar: Scalar) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - let tcx = &{ this.tcx.tcx }; - let errno_ptr = this.machine.last_error.unwrap(); - this.memory.get_mut(errno_ptr.alloc_id)?.write_scalar( - tcx, - errno_ptr, - scalar.into(), - Size::from_bits(32), - ) + let errno_place = this.machine.last_error.unwrap(); + this.write_scalar(scalar, errno_place.into()) } /// Gets the last error variable fn get_last_error(&mut self) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); - let tcx = &{ this.tcx.tcx }; - let errno_ptr = this.machine.last_error.unwrap(); - this.memory - .get(errno_ptr.alloc_id)? - .read_scalar(tcx, errno_ptr, Size::from_bits(32))? - .not_undef() + let errno_place = this.machine.last_error.unwrap(); + this.read_scalar(errno_place.into())?.not_undef() } /// Sets the last error variable using a `std::io::Error`. It fails if the error cannot be diff --git a/src/machine.rs b/src/machine.rs index 3878a0860538f..3714aa2d799e3 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -91,8 +91,8 @@ pub struct Evaluator<'tcx> { pub(crate) argv: Option>, pub(crate) cmd_line: Option>, - /// Last OS error. - pub(crate) last_error: Option>, + /// Last OS error location in memory. It is a 32 bits integer (unsigned for Windows) + pub(crate) last_error: Option>, /// TLS state. pub(crate) tls: TlsData<'tcx>, diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 5d2c3648b43a5..51be7ea5bcd39 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -414,7 +414,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "__errno_location" | "__error" => { - let errno_scalar: Scalar = this.machine.last_error.unwrap().into(); + let errno_place = this.machine.last_error.unwrap(); + let errno_scalar: Scalar = this.check_mplace_access(errno_place.into(), Some(Size::from_bits(32)))?.unwrap().into(); this.write_scalar(errno_scalar, dest)?; } From 338e51aa48fbf9d5f3407c3872e46facfab53ca3 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Wed, 16 Oct 2019 21:37:35 -0500 Subject: [PATCH 1231/3747] Rename consume_result --- src/helpers.rs | 19 +++++++++++++++++++ src/shims/fs.rs | 29 +++++------------------------ 2 files changed, 24 insertions(+), 24 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index 1b80166b2fe72..465fca554c107 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -370,4 +370,23 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Size::from_bits(32), )) } + + /// Helper function that consumes an `std::io::Result` and returns an + /// `InterpResult<'tcx,T>::Ok` instead. It is expected that the result can be converted to an + /// OS error using `std::io::Error::raw_os_error`. + /// + /// This function uses `T: From` instead of `i32` directly because some IO related + /// functions return different integer types (like `read`, that returns an `i64`) + fn set_last_error_from_io_result>( + &mut self, + result: std::io::Result, + ) -> InterpResult<'tcx, T> { + match result { + Ok(ok) => Ok(ok), + Err(e) => { + self.eval_context_mut().set_last_error_from_io_error(e)?; + Ok((-1).into()) + } + } + } } diff --git a/src/shims/fs.rs b/src/shims/fs.rs index 8fcd5c8b1e3e5..c8d1eb29562d3 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -108,7 +108,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fh.low }); - this.consume_result(fd) + this.set_last_error_from_io_result(fd) } fn fcntl( @@ -144,7 +144,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let fd = this.read_scalar(fd_op)?.to_i32()?; this.remove_handle_and(fd, |handle, this| { - this.consume_result(handle.file.sync_all().map(|_| 0i32)) + this.set_last_error_from_io_result(handle.file.sync_all().map(|_| 0i32)) }) } @@ -177,7 +177,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx }); // Reinsert the file handle this.machine.file_handler.handles.insert(fd, handle).unwrap_none(); - this.consume_result(bytes?.map(|bytes| bytes as i64)) + this.set_last_error_from_io_result(bytes?.map(|bytes| bytes as i64)) }) } @@ -206,7 +206,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx .map(|bytes| handle.file.write(bytes).map(|bytes| bytes as i64)) }); this.machine.file_handler.handles.insert(fd, handle).unwrap_none(); - this.consume_result(bytes?) + this.set_last_error_from_io_result(bytes?) }) } @@ -223,7 +223,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let result = remove_file(path).map(|_| 0); - this.consume_result(result) + this.set_last_error_from_io_result(result) } /// Helper function that gets a `FileHandle` immutable reference and allows to manipulate it @@ -271,23 +271,4 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok((-1).into()) } } - - /// Helper function that consumes an `std::io::Result` and returns an - /// `InterpResult<'tcx,T>::Ok` instead. It is expected that the result can be converted to an - /// OS error using `std::io::Error::raw_os_error`. - /// - /// This function uses `T: From` instead of `i32` directly because some IO related - /// functions return different integer types (like `read`, that returns an `i64`) - fn consume_result>( - &mut self, - result: std::io::Result, - ) -> InterpResult<'tcx, T> { - match result { - Ok(ok) => Ok(ok), - Err(e) => { - self.eval_context_mut().set_last_error_from_io_error(e)?; - Ok((-1).into()) - } - } - } } From 5c3c738c4b82a00471cffe67e44a22173404bd4f Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Thu, 17 Oct 2019 20:29:30 -0500 Subject: [PATCH 1232/3747] Make transformation to OS error explicit --- src/helpers.rs | 34 +++++++++++++++++++++++++++------- 1 file changed, 27 insertions(+), 7 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index 465fca554c107..7d68d05cdb785 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -361,14 +361,34 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } /// Sets the last error variable using a `std::io::Error`. It fails if the error cannot be - /// transformed to a raw os error succesfully + /// transformed to a raw os error succesfully. fn set_last_error_from_io_error(&mut self, e: std::io::Error) -> InterpResult<'tcx> { - self.eval_context_mut().set_last_error(Scalar::from_int( - e.raw_os_error().ok_or_else(|| { - err_unsup_format!("The {} error cannot be transformed into a raw os error", e) - })?, - Size::from_bits(32), - )) + use std::io::ErrorKind::*; + let this = self.eval_context_mut(); + let target = &this.tcx.tcx.sess.target.target; + let last_error = if target.options.target_family == Some("unix".to_owned()) { + this.eval_libc(match e.kind() { + ConnectionRefused => "ECONNREFUSED", + ConnectionReset => "ECONNRESET", + PermissionDenied => "EPERM", + BrokenPipe => "EPIPE", + NotConnected => "ENOTCONN", + ConnectionAborted => "ECONNABORTED", + AddrNotAvailable => "EADDRNOTAVAIL", + AddrInUse => "EADDRINUSE", + NotFound => "ENOENT", + Interrupted => "EINTR", + InvalidInput => "EINVAL", + TimedOut => "ETIMEDOUT", + AlreadyExists => "EEXIST", + WouldBlock => "EWOULDBLOCK", + _ => throw_unsup_format!("The {} error cannot be transformed into a raw os error", e) + })? + } else { + // FIXME: we have to implement the windows' equivalent of this. + throw_unsup_format!("Setting the last OS error from an io::Error is unsupported for {}.", target.target_os) + }; + this.set_last_error(last_error) } /// Helper function that consumes an `std::io::Result` and returns an From 619ccf3834d18eeef1aea4030e5c2bcf673e5688 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Fri, 18 Oct 2019 14:33:25 -0500 Subject: [PATCH 1233/3747] Rename set_last_error_from_io_result --- src/helpers.rs | 10 +++++----- src/machine.rs | 2 +- src/shims/fs.rs | 11 +++++------ 3 files changed, 11 insertions(+), 12 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index 7d68d05cdb785..616de83787912 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -360,8 +360,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.read_scalar(errno_place.into())?.not_undef() } - /// Sets the last error variable using a `std::io::Error`. It fails if the error cannot be - /// transformed to a raw os error succesfully. + /// Sets the last OS error using a `std::io::Error`. This function tries to produce the most + /// similar OS error from the `std::io::ErrorKind` and sets it as the last OS error. fn set_last_error_from_io_error(&mut self, e: std::io::Error) -> InterpResult<'tcx> { use std::io::ErrorKind::*; let this = self.eval_context_mut(); @@ -392,12 +392,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } /// Helper function that consumes an `std::io::Result` and returns an - /// `InterpResult<'tcx,T>::Ok` instead. It is expected that the result can be converted to an - /// OS error using `std::io::Error::raw_os_error`. + /// `InterpResult<'tcx,T>::Ok` instead. In case the result is an error, this function returns + /// `Ok(-1)` and sets the last OS error accordingly. /// /// This function uses `T: From` instead of `i32` directly because some IO related /// functions return different integer types (like `read`, that returns an `i64`) - fn set_last_error_from_io_result>( + fn try_unwrap_io_result>( &mut self, result: std::io::Result, ) -> InterpResult<'tcx, T> { diff --git a/src/machine.rs b/src/machine.rs index 3714aa2d799e3..315e9c1a35a97 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -91,7 +91,7 @@ pub struct Evaluator<'tcx> { pub(crate) argv: Option>, pub(crate) cmd_line: Option>, - /// Last OS error location in memory. It is a 32 bits integer (unsigned for Windows) + /// Last OS error location in memory. It is a 32 bit integer (unsigned for Windows) pub(crate) last_error: Option>, /// TLS state. diff --git a/src/shims/fs.rs b/src/shims/fs.rs index c8d1eb29562d3..ffcfab10081a1 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -108,7 +108,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fh.low }); - this.set_last_error_from_io_result(fd) + this.try_unwrap_io_result(fd) } fn fcntl( @@ -144,7 +144,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let fd = this.read_scalar(fd_op)?.to_i32()?; this.remove_handle_and(fd, |handle, this| { - this.set_last_error_from_io_result(handle.file.sync_all().map(|_| 0i32)) + this.try_unwrap_io_result(handle.file.sync_all().map(|_| 0i32)) }) } @@ -175,9 +175,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx .get_bytes_mut(&*this.tcx, buf, Size::from_bytes(count)) .map(|buffer| handle.file.read(buffer)) }); - // Reinsert the file handle this.machine.file_handler.handles.insert(fd, handle).unwrap_none(); - this.set_last_error_from_io_result(bytes?.map(|bytes| bytes as i64)) + this.try_unwrap_io_result(bytes?.map(|bytes| bytes as i64)) }) } @@ -206,7 +205,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx .map(|bytes| handle.file.write(bytes).map(|bytes| bytes as i64)) }); this.machine.file_handler.handles.insert(fd, handle).unwrap_none(); - this.set_last_error_from_io_result(bytes?) + this.try_unwrap_io_result(bytes?) }) } @@ -223,7 +222,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let result = remove_file(path).map(|_| 0); - this.set_last_error_from_io_result(result) + this.try_unwrap_io_result(result) } /// Helper function that gets a `FileHandle` immutable reference and allows to manipulate it From 8a8fa53a5d28fa3e849e26e907480dd28b8f2aa3 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Fri, 18 Oct 2019 14:44:48 -0500 Subject: [PATCH 1234/3747] Transform the last error place to an immediate instead --- src/shims/foreign_items.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 51be7ea5bcd39..1933aee1151dc 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -415,8 +415,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "__errno_location" | "__error" => { let errno_place = this.machine.last_error.unwrap(); - let errno_scalar: Scalar = this.check_mplace_access(errno_place.into(), Some(Size::from_bits(32)))?.unwrap().into(); - this.write_scalar(errno_scalar, dest)?; + this.write_scalar(errno_place.to_ref().to_scalar()?, dest)?; } "getenv" => { From 9d50c5e75806bc27fc0b144be92b895c2f2a7339 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Sat, 19 Oct 2019 14:00:44 -0500 Subject: [PATCH 1235/3747] Small corrections to docs --- src/helpers.rs | 4 ++-- src/machine.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index 616de83787912..16091bb242cdd 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -346,14 +346,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(()) } - /// Sets the last error variable + /// Sets the last error variable. fn set_last_error(&mut self, scalar: Scalar) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let errno_place = this.machine.last_error.unwrap(); this.write_scalar(scalar, errno_place.into()) } - /// Gets the last error variable + /// Gets the last error variable. fn get_last_error(&mut self) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); let errno_place = this.machine.last_error.unwrap(); diff --git a/src/machine.rs b/src/machine.rs index 315e9c1a35a97..50f0ecf590936 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -91,7 +91,7 @@ pub struct Evaluator<'tcx> { pub(crate) argv: Option>, pub(crate) cmd_line: Option>, - /// Last OS error location in memory. It is a 32 bit integer (unsigned for Windows) + /// Last OS error location in memory. It is a 32-bit integer pub(crate) last_error: Option>, /// TLS state. From 283a130ddafa01537123b0650f869abc14886911 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Sun, 20 Oct 2019 17:40:21 -0500 Subject: [PATCH 1236/3747] Add docs for the new helper functions --- src/helpers.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/helpers.rs b/src/helpers.rs index 63380199beab4..4d84106dbe86f 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -346,11 +346,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(()) } + /// Helper function to read an OsString from a null-terminated sequence of bytes, which is what + /// the Unix APIs usually handle. fn read_os_string_from_c_string(&mut self, scalar: Scalar) -> InterpResult<'tcx, OsString> { let bytes = self.eval_context_mut().memory.read_c_str(scalar)?; Ok(bytes_to_os_str(bytes)?.into()) } + /// Helper function to write an OsStr as a null-terminated sequence of bytes, which is what + /// the Unix APIs usually handle. fn write_os_str_to_c_string(&mut self, os_str: &OsStr, ptr: Pointer, size: u64) -> InterpResult<'tcx> { let bytes = os_str_to_bytes(os_str)?; let len = bytes.len(); From ebdb6d4df73c244b4b6dae761c900db896263a89 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 21 Oct 2019 10:25:47 +0200 Subject: [PATCH 1237/3747] when xargo is manually specified, don't try to upgrade it --- src/bin/cargo-miri.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index cf513bc1d2695..b889ce52f386d 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -259,6 +259,10 @@ fn setup(ask_user: bool) { // First, we need xargo. if xargo_version().map_or(true, |v| v < (0, 3, 16)) { + if std::env::var("XARGO").is_ok() { + // The user manually gave us a xargo binary; don't do anything automatically. + show_error(format!("Your xargo is too old; please upgrade to the latest version")) + } let mut cmd = cargo(); cmd.args(&["install", "xargo", "-f"]); ask_to_run(cmd, ask_user, "install a recent enough xargo"); From d9aa20fb3135436706ba8b9dd387edfde9127ddb Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 21 Oct 2019 13:24:56 +0200 Subject: [PATCH 1238/3747] add some missing trailing full stops that slipped through review --- src/machine.rs | 2 +- src/shims/fs.rs | 16 ++++++++-------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/machine.rs b/src/machine.rs index 50f0ecf590936..7904e1cc123b3 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -91,7 +91,7 @@ pub struct Evaluator<'tcx> { pub(crate) argv: Option>, pub(crate) cmd_line: Option>, - /// Last OS error location in memory. It is a 32-bit integer + /// Last OS error location in memory. It is a 32-bit integer. pub(crate) last_error: Option>, /// TLS state. diff --git a/src/shims/fs.rs b/src/shims/fs.rs index ffcfab10081a1..902f5f609d18e 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -21,7 +21,7 @@ impl Default for FileHandler { fn default() -> Self { FileHandler { handles: Default::default(), - // 0, 1 and 2 are reserved for stdin, stdout and stderr + // 0, 1 and 2 are reserved for stdin, stdout and stderr. low: 3, } } @@ -123,7 +123,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let fd = this.read_scalar(fd_op)?.to_i32()?; let cmd = this.read_scalar(cmd_op)?.to_i32()?; - // We only support getting the flags for a descriptor + // We only support getting the flags for a descriptor. if cmd == this.eval_libc_i32("F_GETFD")? { // Currently this is the only flag that `F_GETFD` returns. It is OK to just return the // `FD_CLOEXEC` value without checking if the flag is set for the file because `std` @@ -159,16 +159,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.check_no_isolation("read")?; let count = this.read_scalar(count_op)?.to_usize(&*this.tcx)?; - // Reading zero bytes should not change `buf` + // Reading zero bytes should not change `buf`. if count == 0 { return Ok(0); } let fd = this.read_scalar(fd_op)?.to_i32()?; let buf_scalar = this.read_scalar(buf_op)?.not_undef()?; - // Remove the file handle to avoid borrowing issues + // Remove the file handle to avoid borrowing issues. this.remove_handle_and(fd, |mut handle, this| { - // Don't use `?` to avoid returning before reinserting the handle + // Don't use `?` to avoid returning before reinserting the handle. let bytes = this.force_ptr(buf_scalar).and_then(|buf| { this.memory .get_mut(buf.alloc_id)? @@ -191,7 +191,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.check_no_isolation("write")?; let count = this.read_scalar(count_op)?.to_usize(&*this.tcx)?; - // Writing zero bytes should not change `buf` + // Writing zero bytes should not change `buf`. if count == 0 { return Ok(0); } @@ -232,7 +232,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// and sets `Evaluator::last_error` to `libc::EBADF` (invalid file descriptor). /// /// This function uses `T: From` instead of `i32` directly because some IO related - /// functions return different integer types (like `read`, that returns an `i64`) + /// functions return different integer types (like `read`, that returns an `i64`). fn get_handle_and>(&mut self, fd: i32, f: F) -> InterpResult<'tcx, T> where F: Fn(&FileHandle) -> InterpResult<'tcx, T>, @@ -256,7 +256,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// and sets `Evaluator::last_error` to `libc::EBADF` (invalid file descriptor). /// /// This function uses `T: From` instead of `i32` directly because some IO related - /// functions return different integer types (like `read`, that returns an `i64`) + /// functions return different integer types (like `read`, that returns an `i64`). fn remove_handle_and>(&mut self, fd: i32, mut f: F) -> InterpResult<'tcx, T> where F: FnMut(FileHandle, &mut MiriEvalContext<'mir, 'tcx>) -> InterpResult<'tcx, T>, From 789eeee6a5eed7926d3ced5684b624071d9bbf5d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 21 Oct 2019 13:31:38 +0200 Subject: [PATCH 1239/3747] bump Rust (no changes needed) --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 0f59c13723c7d..8e2cace338501 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -fa0f7d0080d8e7e9eb20aa9cbf8013f96c81287f +7979016aff545f7b41cc517031026020b340989d From 2690f5948ad4746655e073fc7367df95b0eb22d2 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 22 Oct 2019 10:13:11 +0200 Subject: [PATCH 1240/3747] rustup: fix for write_bytes and new union rules --- Cargo.lock | 16 ++++++++++++++++ Cargo.toml | 1 + rust-version | 2 +- src/eval.rs | 5 +++-- src/helpers.rs | 11 ++--------- src/shims/env.rs | 8 +++----- src/shims/foreign_items.rs | 29 ++++++++--------------------- src/shims/intrinsics.rs | 18 +++--------------- tests/run-pass/union-overwrite.rs | 7 ++++--- 9 files changed, 41 insertions(+), 56 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8d80f1f11cd17..d3b6ee0bb531b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -215,6 +215,11 @@ dependencies = [ "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "either" +version = "1.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "env_logger" version = "0.6.2" @@ -294,6 +299,14 @@ dependencies = [ "quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "itertools" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "itoa" version = "0.4.4" @@ -343,6 +356,7 @@ dependencies = [ "env_logger 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", "getrandom 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", "hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -828,6 +842,7 @@ dependencies = [ "checksum diff 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "3c2b69f912779fbb121ceb775d74d51e915af17aaebc38d28a592843a2dd0a3a" "checksum directories 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "551a778172a450d7fc12e629ca3b0428d00f6afa9a43da1b630d54604e97371c" "checksum dirs-sys 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "afa0b23de8fd801745c471deffa6e12d248f962c9fd4b4c33787b055599bde7b" +"checksum either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "bb1f6b1ce1c140482ea30ddd3335fc0024ac7ee112895426e0a629a6c20adfe3" "checksum env_logger 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "aafcde04e90a5226a6443b7aabdb016ba2f8307c847d524724bd9b346dd1a2d3" "checksum failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "795bd83d3abeb9220f257e597aa0080a508b27533824adf336529648f6abf7e2" "checksum failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "ea1063915fd7ef4309e222a5a07cf9c319fb9c7836b1f89b85458672dbb127e1" @@ -837,6 +852,7 @@ dependencies = [ "checksum getrandom 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "fc344b02d3868feb131e8b5fe2b9b0a1cc42942679af493061fc13b853243872" "checksum hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "805026a5d0141ffc30abb3be3173848ad46a1b1664fe632428479619a3644d77" "checksum humantime 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3ca7e5f2e110db35f93b837c81797f3714500b81d517bf20c431b16d3ca4f114" +"checksum itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5b8467d9c1cebe26feb08c640139247fac215782d35371ade9a2136ed6085358" "checksum itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "501266b7edd0174f8530248f87f99c88fbe60ca4ef3dd486835b8d8d53136f7f" "checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" "checksum libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)" = "34fcd2c08d2f832f376f4173a231990fa5aef4e99fb569867318a227ef4c06ba" diff --git a/Cargo.toml b/Cargo.toml index bd345ea2b7f55..91da02eac8a6c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -40,6 +40,7 @@ log = "0.4" shell-escape = "0.1.4" hex = "0.3.2" rand = "0.7" +itertools = "0.8" # A noop dependency that changes in the Rust repository, it's a bit of a hack. # See the `src/tools/rustc-workspace-hack/README.md` file in `rust-lang/rust` diff --git a/rust-version b/rust-version index 8e2cace338501..b2b3a89fe9566 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -7979016aff545f7b41cc517031026020b340989d +6576f4be5af31a5e61dfc0cf50b7130e6c6dfb35 diff --git a/src/eval.rs b/src/eval.rs index f4a8d176172d4..13396e845da11 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -257,8 +257,9 @@ pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) { trace!("-------------------"); trace!("Frame {}", i); trace!(" return: {:?}", frame.return_place.map(|p| *p)); - for (i, local) in frame.locals.iter().enumerate() { - trace!(" local {}: {:?}", i, local.value); + for (_i, _local) in frame.locals.iter().enumerate() { + //trace!(" local {}: {:?}", i, local.value); + //FIXME: enable this again when the LocalValue Debug impl is back } } } diff --git a/src/helpers.rs b/src/helpers.rs index 16091bb242cdd..9e1fa34370589 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -4,7 +4,7 @@ use rustc::hir::def_id::{DefId, CRATE_DEF_INDEX}; use rustc::mir; use rustc::ty::{ self, - layout::{self, Align, LayoutOf, Size, TyLayout}, + layout::{self, LayoutOf, Size, TyLayout}, }; use rand::RngCore; @@ -94,13 +94,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } let this = self.eval_context_mut(); - // Don't forget the bounds check. - let ptr = this.memory.check_ptr_access( - ptr, - Size::from_bytes(len as u64), - Align::from_bytes(1).unwrap() - )?.expect("we already checked for size 0"); - let mut data = vec![0; len]; if this.machine.communicate { @@ -113,7 +106,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx rng.fill_bytes(&mut data); } - this.memory.get_mut(ptr.alloc_id)?.write_bytes(&*this.tcx, ptr, &data) + this.memory.write_bytes(ptr, data.iter().copied()) } /// Visits the memory covered by `place`, sensitive to freezing: the 3rd parameter diff --git a/src/shims/env.rs b/src/shims/env.rs index 661e8bf209b1e..28f1c7d2ef9ee 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -122,7 +122,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.check_no_isolation("getcwd")?; - let buf = this.force_ptr(this.read_scalar(buf_op)?.not_undef()?)?; + let buf = this.read_scalar(buf_op)?.not_undef()?; let size = this.read_scalar(size_op)?.to_usize(&*this.tcx)?; // If we cannot get the current directory, we return null match env::current_dir() { @@ -138,10 +138,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // This is ok because the buffer was strictly larger than `bytes`, so after // adding the null terminator, the buffer size is larger or equal to // `bytes.len()`, meaning that `bytes` actually fit inside tbe buffer. - this.memory - .get_mut(buf.alloc_id)? - .write_bytes(&*this.tcx, buf, &bytes)?; - return Ok(Scalar::Ptr(buf)); + this.memory.write_bytes(buf, bytes.iter().copied())?; + return Ok(buf); } let erange = this.eval_libc("ERANGE")?; this.set_last_error(erange)?; diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 1933aee1151dc..f951cf2df77ca 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -52,9 +52,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if zero_init { // We just allocated this, the access is definitely in-bounds. this.memory - .get_mut(ptr.alloc_id) - .unwrap() - .write_repeat(&*this.tcx, ptr, 0, Size::from_bytes(size)) + .write_bytes(ptr.into(), itertools::repeat_n(0u8, size as usize)) .unwrap(); } Scalar::Ptr(ptr) @@ -229,9 +227,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ); // We just allocated this, the access is definitely in-bounds. this.memory - .get_mut(ptr.alloc_id) - .unwrap() - .write_repeat(tcx, ptr, 0, Size::from_bytes(size)) + .write_bytes(ptr.into(), itertools::repeat_n(0u8, size as usize)) .unwrap(); this.write_scalar(Scalar::Ptr(ptr), dest)?; } @@ -841,25 +837,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "GetSystemInfo" => { let system_info = this.deref_operand(args[0])?; - let system_info_ptr = this - .check_mplace_access(system_info, None)? - .expect("cannot be a ZST"); - // We rely on `deref_operand` doing bounds checks for us. // Initialize with `0`. this.memory - .get_mut(system_info_ptr.alloc_id)? - .write_repeat(tcx, system_info_ptr, 0, system_info.layout.size)?; + .write_bytes(system_info.ptr, itertools::repeat_n(0, system_info.layout.size.bytes() as usize))?; // Set number of processors. let dword_size = Size::from_bytes(4); - let offset = 2 * dword_size + 3 * tcx.pointer_size(); - this.memory - .get_mut(system_info_ptr.alloc_id)? - .write_scalar( - tcx, - system_info_ptr.offset(offset, tcx)?, - Scalar::from_int(NUM_CPUS, dword_size).into(), - dword_size, - )?; + let num_cpus = this.mplace_field(system_info, 5)?; + this.write_scalar( + Scalar::from_int(NUM_CPUS, dword_size), + num_cpus.into(), + )?; } "TlsAlloc" => { diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 46658760cc12a..d39e70d8990fb 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -356,11 +356,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx _ => { // Do it in memory let mplace = this.force_allocation(dest)?; - mplace.meta.unwrap_none(); - // not a zst, must be valid pointer - let ptr = mplace.ptr.to_ptr()?; - // we know the return place is in-bounds - this.memory.get_mut(ptr.alloc_id)?.write_repeat(tcx, ptr, 0, dest.layout.size)?; + mplace.meta.unwrap_none(); // must be sized + this.memory.write_bytes(mplace.ptr, itertools::repeat_n(0, dest.layout.size.bytes() as usize))?; } } } @@ -565,16 +562,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let ptr = this.read_scalar(args[0])?.not_undef()?; let count = this.read_scalar(args[2])?.to_usize(this)?; let byte_count = ty_layout.size * count; - match this.memory.check_ptr_access(ptr, byte_count, ty_layout.align.abi)? { - Some(ptr) => { - this.memory - .get_mut(ptr.alloc_id)? - .write_repeat(tcx, ptr, val_byte, byte_count)?; - } - None => { - // Size is 0, nothing to do. - } - } + this.memory.write_bytes(ptr, itertools::repeat_n(val_byte, byte_count.bytes() as usize))?; } name => throw_unsup_format!("unimplemented intrinsic: {}", name), diff --git a/tests/run-pass/union-overwrite.rs b/tests/run-pass/union-overwrite.rs index 5c618763c0d28..d3c81834bc4b4 100644 --- a/tests/run-pass/union-overwrite.rs +++ b/tests/run-pass/union-overwrite.rs @@ -1,19 +1,20 @@ #![feature(untagged_unions)] -#![allow(unions_with_drop_fields)] #[repr(C)] +#[derive(Clone, Copy)] struct Pair(T, U); #[repr(C)] +#[derive(Clone, Copy)] struct Triple(T, T, T); #[repr(C)] -union U { +union U { a: Pair, b: B, } #[repr(C)] -union W { +union W { a: A, b: B, } From db949af8ed24e46f0d0bcc1fbe0517b2996b5f9e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 22 Oct 2019 10:43:16 +0200 Subject: [PATCH 1241/3747] fix field index --- src/shims/foreign_items.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index f951cf2df77ca..66fb53581e680 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -842,7 +842,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx .write_bytes(system_info.ptr, itertools::repeat_n(0, system_info.layout.size.bytes() as usize))?; // Set number of processors. let dword_size = Size::from_bytes(4); - let num_cpus = this.mplace_field(system_info, 5)?; + let num_cpus = this.mplace_field(system_info, 6)?; this.write_scalar( Scalar::from_int(NUM_CPUS, dword_size), num_cpus.into(), From 0ad37dd876c422829248e00e5401a9df17d7c486 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 22 Oct 2019 13:11:16 +0200 Subject: [PATCH 1242/3747] AppVeyor: abort early if a job fails --- .appveyor.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.appveyor.yml b/.appveyor.yml index 60963438abfff..2ba95c228bafb 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -12,6 +12,9 @@ branches: - auto - try +matrix: + fast_finish: true # set this flag to immediately finish build once one of the jobs fails. + cache: - '%USERPROFILE%\.cargo' - '%USERPROFILE%\.rustup' From fb4cb5bf4af633ca057a84b995bab3b08333df41 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Tue, 22 Oct 2019 16:57:07 -0500 Subject: [PATCH 1243/3747] Make size error distinguishable from other errors --- src/helpers.rs | 17 +++++++++++++---- src/shims/env.rs | 2 +- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index b31e0a2c2eb9c..79efd95eb6d74 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -412,16 +412,25 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } /// Helper function to write an OsStr as a null-terminated sequence of bytes, which is what - /// the Unix APIs usually handle. - fn write_os_str_to_c_string(&mut self, os_str: &OsStr, scalar: Scalar, size: u64) -> InterpResult<'tcx> { + /// the Unix APIs usually handle. This function returns `Ok(false)` without trying to write if + /// `size` is not large enough to fit the contents of `os_string` plus a null terminator. It + /// returns `Ok(true)` if the writing process was successful. Otherwise it returns an + /// `InterpError`. + fn write_os_str_to_c_string( + &mut self, + os_str: &OsStr, + scalar: Scalar, + size: u64 + ) -> InterpResult<'tcx, bool> { let bytes = os_str_to_bytes(os_str)?; // If `size` is smaller or equal than `bytes.len()`, writing `bytes` plus the required null // terminator to memory using the `ptr` pointer would cause an overflow. if size <= bytes.len() as u64 { - throw_unsup_format!("OsString of length {} is too large for destination buffer of size {}", bytes.len(), size) + return Ok(false); } // FIXME: We should use `Iterator::chain` instead when rust-lang/rust#65704 lands. - self.eval_context_mut().memory.write_bytes(scalar, [bytes, &[0]].concat()) + self.eval_context_mut().memory.write_bytes(scalar, [bytes, &[0]].concat())?; + Ok(true) } } diff --git a/src/shims/env.rs b/src/shims/env.rs index f88a5bbac72e9..2dc47d74ffb82 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -128,7 +128,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // If we cannot get the current directory, we return null match env::current_dir() { Ok(cwd) => { - if this.write_os_str_to_c_string(&OsString::from(cwd), buf, size).is_ok() { + if this.write_os_str_to_c_string(&OsString::from(cwd), buf, size)? { return Ok(buf); } let erange = this.eval_libc("ERANGE")?; From 47eb8549eec05117a55739c9b818d1ece1df898f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 23 Oct 2019 10:25:22 +0200 Subject: [PATCH 1244/3747] rustup + cargo update --- Cargo.lock | 338 +++++++++++++++++++++++---------------------------- rust-version | 2 +- 2 files changed, 152 insertions(+), 188 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d3b6ee0bb531b..18cef9461b268 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -20,10 +20,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "arrayvec" -version = "0.4.11" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", + "nodrop 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -31,33 +31,33 @@ name = "atty" version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "autocfg" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "backtrace" -version = "0.3.35" +version = "0.3.40" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "backtrace-sys 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)", - "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "backtrace-sys 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-demangle 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "backtrace-sys" -version = "0.1.31" +version = "0.1.32" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.46 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -70,16 +70,16 @@ dependencies = [ [[package]] name = "bitflags" -version = "1.1.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "blake2b_simd" -version = "0.5.7" +version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "arrayref 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "arrayvec 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", + "arrayvec 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", "constant_time_eq 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -90,11 +90,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "c2-chacha" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "ppv-lite86 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", + "ppv-lite86 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -103,19 +102,19 @@ version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "cc" -version = "1.0.40" +version = "1.0.46" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "cfg-if" -version = "0.1.9" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -130,10 +129,10 @@ dependencies = [ [[package]] name = "chrono" -version = "0.4.7" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", @@ -144,7 +143,7 @@ name = "cloudabi" version = "0.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -158,22 +157,22 @@ dependencies = [ [[package]] name = "compiletest_rs" -version = "0.3.24" +version = "0.3.25" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "diff 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", "filetime 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", "getopts 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "miow 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "rustfix 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -186,7 +185,7 @@ name = "crossbeam-utils" version = "0.6.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -200,7 +199,7 @@ name = "directories" version = "2.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "dirs-sys 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -209,10 +208,10 @@ name = "dirs-sys" version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "redox_users 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -226,30 +225,30 @@ version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "atty 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)", - "humantime 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "humantime 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "termcolor 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "failure" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "backtrace 0.3.35 (registry+https://github.com/rust-lang/crates.io-index)", - "failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "backtrace 0.3.40 (registry+https://github.com/rust-lang/crates.io-index)", + "failure_derive 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "failure_derive" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)", - "synstructure 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "synstructure 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -257,10 +256,10 @@ name = "filetime" version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -278,12 +277,12 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.1.11" +version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", - "wasi 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", + "wasi 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -293,7 +292,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "humantime" -version = "1.2.0" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -319,7 +318,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "libc" -version = "0.2.62" +version = "0.2.65" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -327,7 +326,7 @@ name = "log" version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -341,7 +340,7 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "socket2 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -351,15 +350,15 @@ dependencies = [ "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "cargo_metadata 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", "colored 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "compiletest_rs 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", + "compiletest_rs 0.3.25 (registry+https://github.com/rust-lang/crates.io-index)", "directories 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", - "getrandom 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", + "getrandom 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", "hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-workspace-hack 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "shell-escape 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", @@ -368,7 +367,7 @@ dependencies = [ [[package]] name = "nodrop" -version = "0.1.13" +version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -376,7 +375,7 @@ name = "num-integer" version = "0.1.41" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "autocfg 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -393,25 +392,17 @@ name = "num-traits" version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "autocfg 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "ppv-lite86" -version = "0.2.5" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "proc-macro2" -version = "0.4.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "proc-macro2" -version = "1.0.1" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -422,20 +413,12 @@ name = "quick-error" version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "quote" -version = "0.6.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "quote" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -444,21 +427,21 @@ version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rand" -version = "0.7.0" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "getrandom 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "getrandom 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "rand_chacha 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -467,8 +450,8 @@ name = "rand_chacha" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "c2-chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "c2-chacha 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -486,10 +469,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "rand_core" -version = "0.5.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "getrandom 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", + "getrandom 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -497,7 +480,7 @@ name = "rand_hc" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "rand_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -507,10 +490,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -531,7 +514,7 @@ name = "redox_users" version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", "rust-argon2 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -539,18 +522,18 @@ dependencies = [ [[package]] name = "regex" -version = "1.2.1" +version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "aho-corasick 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)", "memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "regex-syntax 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", + "regex-syntax 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", "thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "regex-syntax" -version = "0.6.11" +version = "0.6.12" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -558,7 +541,7 @@ name = "remove_dir_all" version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -572,7 +555,7 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", - "blake2b_simd 0.5.7 (registry+https://github.com/rust-lang/crates.io-index)", + "blake2b_simd 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -599,15 +582,15 @@ name = "rustfix" version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "ryu" -version = "1.0.0" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -616,7 +599,7 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -626,30 +609,30 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "serde" -version = "1.0.99" +version = "1.0.101" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde_derive 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "serde_derive" -version = "1.0.99" +version = "1.0.101" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "serde_json" -version = "1.0.40" +version = "1.0.41" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", - "ryu 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)", + "ryu 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -662,20 +645,10 @@ name = "socket2" version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "syn" -version = "0.15.44" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -683,20 +656,20 @@ name = "syn" version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "synstructure" -version = "0.10.2" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -704,12 +677,12 @@ name = "tempfile" version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", "remove_dir_all 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -733,9 +706,9 @@ name = "time" version = "0.1.42" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -743,11 +716,6 @@ name = "unicode-width" version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "unicode-xid" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "unicode-xid" version = "0.2.0" @@ -758,19 +726,19 @@ name = "vergen" version = "3.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "chrono 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", - "failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "chrono 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)", + "failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "wasi" -version = "0.5.0" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "winapi" -version = "0.3.7" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -787,7 +755,7 @@ name = "winapi-util" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -800,7 +768,7 @@ name = "wincolor" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", "winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -812,31 +780,31 @@ dependencies = [ "cgmath 0.16.1 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "rgb 0.8.14 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [metadata] "checksum aho-corasick 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)" = "58fb5e95d83b38284460a5fda7d6470aa0b8844d283a0b614b8535e880800d2d" "checksum approx 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "08abcc3b4e9339e33a3d0a5ed15d84a687350c05689d825e0f6655eef9e76a94" "checksum arrayref 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "0d382e583f07208808f6b1249e60848879ba3543f57c32277bf52d69c2f0f0ee" -"checksum arrayvec 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)" = "b8d73f9beda665eaa98ab9e4f7442bd4e7de6652587de55b2525e52e29c1b0ba" +"checksum arrayvec 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)" = "cd9fd44efafa8690358b7408d253adf110036b88f55672a933f01d616ad9b1b9" "checksum atty 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)" = "1803c647a3ec87095e7ae7acfca019e98de5ec9a7d01343f611cf3152ed71a90" -"checksum autocfg 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "b671c8fb71b457dd4ae18c4ba1e59aa81793daacc361d82fcd410cef0d491875" -"checksum backtrace 0.3.35 (registry+https://github.com/rust-lang/crates.io-index)" = "1371048253fa3bac6704bfd6bbfc922ee9bdcee8881330d40f308b81cc5adc55" -"checksum backtrace-sys 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)" = "82a830b4ef2d1124a711c71d263c5abdc710ef8e907bd508c88be475cebc422b" +"checksum autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "1d49d90015b3c36167a20fe2810c5cd875ad504b39cff3d4eae7977e6b7c1cb2" +"checksum backtrace 0.3.40 (registry+https://github.com/rust-lang/crates.io-index)" = "924c76597f0d9ca25d762c25a4d369d51267536465dc5064bdf0eb073ed477ea" +"checksum backtrace-sys 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)" = "5d6575f128516de27e3ce99689419835fce9643a9b215a14d2b5b685be018491" "checksum base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0b25d992356d2eb0ed82172f5248873db5560c4721f564b13cb5193bda5e668e" -"checksum bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3d155346769a6855b86399e9bc3814ab343cd3d62c7e985113d46a0ec3c281fd" -"checksum blake2b_simd 0.5.7 (registry+https://github.com/rust-lang/crates.io-index)" = "bf775a81bb2d464e20ff170ac20316c7b08a43d11dbc72f0f82e8e8d3d6d0499" +"checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" +"checksum blake2b_simd 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)" = "5850aeee1552f495dd0250014cf64b82b7c8879a89d83b33bbdace2cc4f63182" "checksum byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a7c3dd8985a7111efc5c80b44e23ecdd8c007de8ade3b96595387e812b957cf5" -"checksum c2-chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7d64d04786e0f528460fc884753cf8dddcc466be308f6026f8e355c41a0e4101" +"checksum c2-chacha 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "214238caa1bf3a496ec3392968969cab8549f96ff30652c9e56885329315f6bb" "checksum cargo_metadata 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "700b3731fd7d357223d0000f4dbf1808401b694609035c3c411fbc0cd375c426" -"checksum cc 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)" = "b548a4ee81fccb95919d4e22cfea83c7693ebfd78f0495493178db20b3139da7" -"checksum cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "b486ce3ccf7ffd79fdeb678eac06a9e6c09fc88d33836340becb8fffe87c5e33" +"checksum cc 1.0.46 (registry+https://github.com/rust-lang/crates.io-index)" = "0213d356d3c4ea2c18c40b037c3be23cd639825c18f25ee670ac7813beeef99c" +"checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" "checksum cgmath 0.16.1 (registry+https://github.com/rust-lang/crates.io-index)" = "64a4b57c8f4e3a2e9ac07e0f6abc9c24b6fc9e1b54c3478cfb598f3d0023e51c" -"checksum chrono 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "77d81f58b7301084de3b958691458a53c3f7e0b1d702f77e550b6a88e3a88abe" +"checksum chrono 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e8493056968583b0193c1bb04d6f7684586f3726992d6c573261941a895dbd68" "checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" "checksum colored 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6cdb90b60f2927f8d76139c72dbde7e10c3a2bc47c8594c9c7a66529f2687c03" -"checksum compiletest_rs 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)" = "676a74b493d50ac33cacd83fd536597e6b52c0b46b9856f7b9c809d82fef4ac0" +"checksum compiletest_rs 0.3.25 (registry+https://github.com/rust-lang/crates.io-index)" = "f75b10a18fb53549fdd090846eb01c7f8593914494d1faabc4d3005c436e417a" "checksum constant_time_eq 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "995a44c877f9212528ccc74b21a232f66ad69001e40ede5bcee2ac9ef2657120" "checksum crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)" = "04973fa96e96579258a5091af6003abde64af786b860f18622b82e026cca60e6" "checksum diff 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "3c2b69f912779fbb121ceb775d74d51e915af17aaebc38d28a592843a2dd0a3a" @@ -844,44 +812,42 @@ dependencies = [ "checksum dirs-sys 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "afa0b23de8fd801745c471deffa6e12d248f962c9fd4b4c33787b055599bde7b" "checksum either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "bb1f6b1ce1c140482ea30ddd3335fc0024ac7ee112895426e0a629a6c20adfe3" "checksum env_logger 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "aafcde04e90a5226a6443b7aabdb016ba2f8307c847d524724bd9b346dd1a2d3" -"checksum failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "795bd83d3abeb9220f257e597aa0080a508b27533824adf336529648f6abf7e2" -"checksum failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "ea1063915fd7ef4309e222a5a07cf9c319fb9c7836b1f89b85458672dbb127e1" +"checksum failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "f8273f13c977665c5db7eb2b99ae520952fe5ac831ae4cd09d80c4c7042b5ed9" +"checksum failure_derive 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0bc225b78e0391e4b8683440bf2e63c2deeeb2ce5189eab46e2b68c6d3725d08" "checksum filetime 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "6bd7380b54ced79dda72ecc35cc4fbbd1da6bba54afaa37e96fd1c2a308cd469" "checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" "checksum getopts 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)" = "14dbbfd5c71d70241ecf9e6f13737f7b5ce823821063188d7e46c41d371eebd5" -"checksum getrandom 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "fc344b02d3868feb131e8b5fe2b9b0a1cc42942679af493061fc13b853243872" +"checksum getrandom 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "473a1265acc8ff1e808cd0a1af8cee3c2ee5200916058a2ca113c29f2d903571" "checksum hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "805026a5d0141ffc30abb3be3173848ad46a1b1664fe632428479619a3644d77" -"checksum humantime 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3ca7e5f2e110db35f93b837c81797f3714500b81d517bf20c431b16d3ca4f114" +"checksum humantime 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f" "checksum itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5b8467d9c1cebe26feb08c640139247fac215782d35371ade9a2136ed6085358" "checksum itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "501266b7edd0174f8530248f87f99c88fbe60ca4ef3dd486835b8d8d53136f7f" "checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" -"checksum libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)" = "34fcd2c08d2f832f376f4173a231990fa5aef4e99fb569867318a227ef4c06ba" +"checksum libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)" = "1a31a0627fdf1f6a39ec0dd577e101440b7db22672c0901fe00a9a6fbb5c24e8" "checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7" "checksum memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "88579771288728879b57485cc7d6b07d648c9f0141eb955f8ab7f9d45394468e" "checksum miow 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "396aa0f2003d7df8395cb93e09871561ccc3e785f0acb369170e8cc74ddf9226" -"checksum nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9667ddcc6cc8a43afc9b7917599d7216aa09c463919ea32c59ed6cac8bc945" +"checksum nodrop 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb" "checksum num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)" = "b85e541ef8255f6cf42bbfe4ef361305c6c135d10919ecc26126c4e5ae94bc09" "checksum num-traits 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)" = "92e5113e9fd4cc14ded8e499429f396a20f98c772a47cc8622a736e1ec843c31" "checksum num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "6ba9a427cfca2be13aa6f6403b0b7e7368fe982bfa16fccc450ce74c46cd9b32" -"checksum ppv-lite86 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e3cbf9f658cdb5000fcf6f362b8ea2ba154b9f146a61c7a20d647034c6b6561b" -"checksum proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759" -"checksum proc-macro2 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4c5c2380ae88876faae57698be9e9775e3544decad214599c3a6266cca6ac802" +"checksum ppv-lite86 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "74490b50b9fbe561ac330df47c08f3f33073d2d00c150f719147d7c54522fa1b" +"checksum proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "9c9e470a8dc4aeae2dee2f335e8f533e2d4b347e1434e5671afc49b054592f27" "checksum quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9274b940887ce9addde99c4eee6b5c44cc494b182b97e73dc8ffdcb3397fd3f0" -"checksum quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)" = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1" "checksum quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe" "checksum rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293" -"checksum rand 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d47eab0e83d9693d40f825f86948aa16eff6750ead4bdffc4ab95b8b3a7f052c" +"checksum rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "3ae1b169243eaf61759b8475a998f0a385e42042370f3a7dbaf35246eacc8412" "checksum rand_chacha 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "03a2a90da8c7523f554344f921aa97283eadf6ac484a6d2a7d0212fa7f8d6853" "checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" "checksum rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc" -"checksum rand_core 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "615e683324e75af5d43d8f7a39ffe3ee4a9dc42c5c701167a71dc59c3a493aca" +"checksum rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" "checksum rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" "checksum rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071" "checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" "checksum redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)" = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84" "checksum redox_users 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4ecedbca3bf205f8d8f5c2b44d83cd0690e39ee84b951ed649e9f1841132b66d" -"checksum regex 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "88c3d9193984285d544df4a30c23a4e62ead42edf70a4452ceb76dac1ce05c26" -"checksum regex-syntax 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)" = "b143cceb2ca5e56d5671988ef8b15615733e7ee16cd348e064333b251b89343f" +"checksum regex 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dc220bd33bdce8f093101afe22a037b8eb0e5af33592e6a9caafff0d4cb81cbd" +"checksum regex-syntax 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)" = "11a7e20d1cce64ef2fed88b66d347f88bd9babb82845b2b858f3edbf59a4f716" "checksum remove_dir_all 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4a83fa3702a688b9359eccba92d153ac33fd2e8462f9e0e3fdf155239ea7792e" "checksum rgb 0.8.14 (registry+https://github.com/rust-lang/crates.io-index)" = "2089e4031214d129e201f8c3c8c2fe97cd7322478a0d1cdf78e7029b0042efdb" "checksum rust-argon2 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4ca4eaef519b494d1f2848fc602d18816fed808a981aedf4f1f00ceb7c9d32cf" @@ -889,27 +855,25 @@ dependencies = [ "checksum rustc-workspace-hack 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc71d2faa173b74b232dedc235e3ee1696581bb132fc116fa3626d6151a1a8fb" "checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" "checksum rustfix 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7150ac777a2931a53489f5a41eb0937b84e3092a20cd0e73ad436b65b507f607" -"checksum ryu 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c92464b447c0ee8c4fb3824ecc8383b81717b9f1e74ba2e72540aef7b9f82997" +"checksum ryu 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "bfa8506c1de11c9c4e4c38863ccbe02a305c8188e85a05a784c9e11e1c3910c8" "checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" "checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" -"checksum serde 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)" = "fec2851eb56d010dc9a21b89ca53ee75e6528bab60c11e89d38390904982da9f" -"checksum serde_derive 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)" = "cb4dc18c61206b08dc98216c98faa0232f4337e1e1b8574551d5bad29ea1b425" -"checksum serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)" = "051c49229f282f7c6f3813f8286cc1e3323e8051823fce42c7ea80fe13521704" +"checksum serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)" = "9796c9b7ba2ffe7a9ce53c2287dfc48080f4b2b362fcc245a259b3a7201119dd" +"checksum serde_derive 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)" = "4b133a43a1ecd55d4086bd5b4dc6c1751c68b1bfbeba7a5040442022c7e7c02e" +"checksum serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)" = "2f72eb2a68a7dc3f9a691bfda9305a1c017a6215e5a4545c258500d2099a37c2" "checksum shell-escape 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "170a13e64f2a51b77a45702ba77287f5c6829375b04a69cf2222acd17d0cfab9" "checksum socket2 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)" = "e8b74de517221a2cb01a53349cf54182acdc31a074727d3079068448c0676d85" -"checksum syn 0.15.44 (registry+https://github.com/rust-lang/crates.io-index)" = "9ca4b3b69a77cbe1ffc9e198781b7acb0c7365a883670e8f1c1bc66fba79a5c5" "checksum syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "66850e97125af79138385e9b88339cbcd037e3f28ceab8c5ad98e64f0f1f80bf" -"checksum synstructure 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)" = "02353edf96d6e4dc81aea2d8490a7e9db177bf8acb0e951c24940bf866cb313f" +"checksum synstructure 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3f085a5855930c0441ca1288cf044ea4aecf4f43a91668abdb870b4ba546a203" "checksum tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9" "checksum termcolor 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "96d6098003bde162e4277c70665bd87c326f5a0c3f3fbfb285787fa482d54e6e" "checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b" "checksum time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f" "checksum unicode-width 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7007dbd421b92cc6e28410fe7362e2e0a2503394908f417b68ec8d1c364c4e20" -"checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" "checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" "checksum vergen 3.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "6aba5e34f93dc7051dfad05b98a18e9156f27e7b431fe1d2398cb6061c0a1dba" -"checksum wasi 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fd5442abcac6525a045cc8c795aedb60da7a2e5e89c7bf18a0d5357849bb23c7" -"checksum winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "f10e386af2b13e47c89e7236a7a14a086791a2b88ebad6df9bf42040195cf770" +"checksum wasi 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b89c3ce4ce14bdc6fb6beaf9ec7928ca331de5df7e5ea278375642a2f478570d" +"checksum winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6" "checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" "checksum winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7168bab6e1daee33b4557efd0e95d5ca70a03706d39fa5f3fe7a236f584b03c9" "checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/rust-version b/rust-version index b2b3a89fe9566..71068bb941a0c 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -6576f4be5af31a5e61dfc0cf50b7130e6c6dfb35 +57bfb8096295150c06559da10adc5629e445a4ac From 6fb5e124d9299cfd52a6726caf9bd2a5bcfaf73f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 23 Oct 2019 10:31:08 +0200 Subject: [PATCH 1245/3747] use compiletest_rs for stable compiler as nightly is broken --- Cargo.lock | 44 ++++++++++++++++++++++++++++++++++++++++++++ Cargo.toml | 2 +- 2 files changed, 45 insertions(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index 18cef9461b268..0f04aa04bb454 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -172,6 +172,7 @@ dependencies = [ "serde_derive 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "tester 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -311,6 +312,15 @@ name = "itoa" version = "0.4.4" 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 = "1.4.0" @@ -685,6 +695,15 @@ dependencies = [ "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "term" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "termcolor" version = "1.0.5" @@ -693,6 +712,16 @@ dependencies = [ "wincolor 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "tester" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "getopts 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", + "term 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "thread_local" version = "0.3.6" @@ -736,6 +765,11 @@ name = "wasi" version = "0.7.0" 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" version = "0.3.8" @@ -745,6 +779,11 @@ dependencies = [ "winapi-x86_64-pc-windows-gnu 0.4.0 (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" + [[package]] name = "winapi-i686-pc-windows-gnu" version = "0.4.0" @@ -822,6 +861,7 @@ dependencies = [ "checksum humantime 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f" "checksum itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5b8467d9c1cebe26feb08c640139247fac215782d35371ade9a2136ed6085358" "checksum itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "501266b7edd0174f8530248f87f99c88fbe60ca4ef3dd486835b8d8d53136f7f" +"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" "checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" "checksum libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)" = "1a31a0627fdf1f6a39ec0dd577e101440b7db22672c0901fe00a9a6fbb5c24e8" "checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7" @@ -866,14 +906,18 @@ dependencies = [ "checksum syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "66850e97125af79138385e9b88339cbcd037e3f28ceab8c5ad98e64f0f1f80bf" "checksum synstructure 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3f085a5855930c0441ca1288cf044ea4aecf4f43a91668abdb870b4ba546a203" "checksum tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9" +"checksum term 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "fa63644f74ce96fbeb9b794f66aff2a52d601cbd5e80f4b97123e3899f4570f1" "checksum termcolor 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "96d6098003bde162e4277c70665bd87c326f5a0c3f3fbfb285787fa482d54e6e" +"checksum tester 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5e812cb26c597f86a49b26dbb58b878bd2a2b4b93fc069dc39499228fe556ff6" "checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b" "checksum time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f" "checksum unicode-width 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7007dbd421b92cc6e28410fe7362e2e0a2503394908f417b68ec8d1c364c4e20" "checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" "checksum vergen 3.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "6aba5e34f93dc7051dfad05b98a18e9156f27e7b431fe1d2398cb6061c0a1dba" "checksum wasi 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b89c3ce4ce14bdc6fb6beaf9ec7928ca331de5df7e5ea278375642a2f478570d" +"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" "checksum winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6" +"checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" "checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" "checksum winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7168bab6e1daee33b4557efd0e95d5ca70a03706d39fa5f3fe7a236f584b03c9" "checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/Cargo.toml b/Cargo.toml index 91da02eac8a6c..4c39341e10c14 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -60,5 +60,5 @@ cargo_miri = ["cargo_metadata", "directories", "rustc_version"] rustc_tests = [] [dev-dependencies] -compiletest_rs = { version = "0.3.24", features = ["tmp"] } +compiletest_rs = { version = "0.3.24", features = ["tmp", "stable"] } colored = "1.6" From 505b02fc99c49c1a3f2db4baeb989c9cb62d6605 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 23 Oct 2019 10:32:08 +0200 Subject: [PATCH 1246/3747] cargo update cargo-miri-test --- test-cargo-miri/Cargo.lock | 35 ++++++++++++++--------------------- 1 file changed, 14 insertions(+), 21 deletions(-) diff --git a/test-cargo-miri/Cargo.lock b/test-cargo-miri/Cargo.lock index 70476fbdcb061..55c7c528aa9fc 100644 --- a/test-cargo-miri/Cargo.lock +++ b/test-cargo-miri/Cargo.lock @@ -2,7 +2,7 @@ # It is not intended for manual editing. [[package]] name = "autocfg" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -12,11 +12,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "c2-chacha" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "ppv-lite86 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", + "ppv-lite86 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -39,18 +38,13 @@ version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "wasi 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "lazy_static" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "libc" -version = "0.2.62" +version = "0.2.65" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -58,12 +52,12 @@ name = "num_cpus" version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "ppv-lite86" -version = "0.2.5" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -72,7 +66,7 @@ version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "getrandom 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "rand_chacha 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -84,7 +78,7 @@ name = "rand_chacha" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "c2-chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "c2-chacha 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -109,7 +103,7 @@ name = "rand_pcg" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "autocfg 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -119,15 +113,14 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" [metadata] -"checksum autocfg 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "b671c8fb71b457dd4ae18c4ba1e59aa81793daacc361d82fcd410cef0d491875" +"checksum autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "1d49d90015b3c36167a20fe2810c5cd875ad504b39cff3d4eae7977e6b7c1cb2" "checksum byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a7c3dd8985a7111efc5c80b44e23ecdd8c007de8ade3b96595387e812b957cf5" -"checksum c2-chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7d64d04786e0f528460fc884753cf8dddcc466be308f6026f8e355c41a0e4101" +"checksum c2-chacha 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "214238caa1bf3a496ec3392968969cab8549f96ff30652c9e56885329315f6bb" "checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" "checksum getrandom 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "473a1265acc8ff1e808cd0a1af8cee3c2ee5200916058a2ca113c29f2d903571" -"checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" -"checksum libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)" = "34fcd2c08d2f832f376f4173a231990fa5aef4e99fb569867318a227ef4c06ba" +"checksum libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)" = "1a31a0627fdf1f6a39ec0dd577e101440b7db22672c0901fe00a9a6fbb5c24e8" "checksum num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bcef43580c035376c0705c42792c294b66974abbfd2789b511784023f71f3273" -"checksum ppv-lite86 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e3cbf9f658cdb5000fcf6f362b8ea2ba154b9f146a61c7a20d647034c6b6561b" +"checksum ppv-lite86 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "74490b50b9fbe561ac330df47c08f3f33073d2d00c150f719147d7c54522fa1b" "checksum rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "3ae1b169243eaf61759b8475a998f0a385e42042370f3a7dbaf35246eacc8412" "checksum rand_chacha 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "03a2a90da8c7523f554344f921aa97283eadf6ac484a6d2a7d0212fa7f8d6853" "checksum rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" From de12cbcb32a53a06e1f73e7d9cdfa11e41d79ded Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Wed, 23 Oct 2019 08:58:25 -0500 Subject: [PATCH 1247/3747] Fix documentation --- src/helpers.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index 79efd95eb6d74..0245540debbe7 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -414,8 +414,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// Helper function to write an OsStr as a null-terminated sequence of bytes, which is what /// the Unix APIs usually handle. This function returns `Ok(false)` without trying to write if /// `size` is not large enough to fit the contents of `os_string` plus a null terminator. It - /// returns `Ok(true)` if the writing process was successful. Otherwise it returns an - /// `InterpError`. + /// returns `Ok(true)` if the writing process was successful. fn write_os_str_to_c_string( &mut self, os_str: &OsStr, From 354de02c24525ee2a0cf712e5d0f44f6228ad96c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 23 Oct 2019 16:33:54 +0200 Subject: [PATCH 1248/3747] rustup; fix debugging --- rust-version | 2 +- src/eval.rs | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/rust-version b/rust-version index 71068bb941a0c..42aa6d8d76a03 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -57bfb8096295150c06559da10adc5629e445a4ac +f466f52c1bf8f2e4454e31c683a88625ad4b4033 diff --git a/src/eval.rs b/src/eval.rs index 13396e845da11..f4a8d176172d4 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -257,9 +257,8 @@ pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) { trace!("-------------------"); trace!("Frame {}", i); trace!(" return: {:?}", frame.return_place.map(|p| *p)); - for (_i, _local) in frame.locals.iter().enumerate() { - //trace!(" local {}: {:?}", i, local.value); - //FIXME: enable this again when the LocalValue Debug impl is back + for (i, local) in frame.locals.iter().enumerate() { + trace!(" local {}: {:?}", i, local.value); } } } From cf9340113efcf5c7bea4a143f42c8ea47da4550e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 24 Oct 2019 10:15:30 +0200 Subject: [PATCH 1249/3747] rustup: more flexible write_bytes avoids allocations and removes itertools dependency --- Cargo.lock | 16 ---------------- Cargo.toml | 1 - rust-version | 2 +- src/helpers.rs | 4 ++-- src/shims/foreign_items.rs | 8 ++++---- src/shims/intrinsics.rs | 6 ++++-- 6 files changed, 11 insertions(+), 26 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0f04aa04bb454..1aa15f8b6846a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -215,11 +215,6 @@ dependencies = [ "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "either" -version = "1.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "env_logger" version = "0.6.2" @@ -299,14 +294,6 @@ dependencies = [ "quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "itertools" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "itoa" version = "0.4.4" @@ -365,7 +352,6 @@ dependencies = [ "env_logger 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", "getrandom 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", "hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -849,7 +835,6 @@ dependencies = [ "checksum diff 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "3c2b69f912779fbb121ceb775d74d51e915af17aaebc38d28a592843a2dd0a3a" "checksum directories 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "551a778172a450d7fc12e629ca3b0428d00f6afa9a43da1b630d54604e97371c" "checksum dirs-sys 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "afa0b23de8fd801745c471deffa6e12d248f962c9fd4b4c33787b055599bde7b" -"checksum either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "bb1f6b1ce1c140482ea30ddd3335fc0024ac7ee112895426e0a629a6c20adfe3" "checksum env_logger 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "aafcde04e90a5226a6443b7aabdb016ba2f8307c847d524724bd9b346dd1a2d3" "checksum failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "f8273f13c977665c5db7eb2b99ae520952fe5ac831ae4cd09d80c4c7042b5ed9" "checksum failure_derive 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0bc225b78e0391e4b8683440bf2e63c2deeeb2ce5189eab46e2b68c6d3725d08" @@ -859,7 +844,6 @@ dependencies = [ "checksum getrandom 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "473a1265acc8ff1e808cd0a1af8cee3c2ee5200916058a2ca113c29f2d903571" "checksum hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "805026a5d0141ffc30abb3be3173848ad46a1b1664fe632428479619a3644d77" "checksum humantime 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f" -"checksum itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5b8467d9c1cebe26feb08c640139247fac215782d35371ade9a2136ed6085358" "checksum itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "501266b7edd0174f8530248f87f99c88fbe60ca4ef3dd486835b8d8d53136f7f" "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" "checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" diff --git a/Cargo.toml b/Cargo.toml index 4c39341e10c14..6e317ce945970 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -40,7 +40,6 @@ log = "0.4" shell-escape = "0.1.4" hex = "0.3.2" rand = "0.7" -itertools = "0.8" # A noop dependency that changes in the Rust repository, it's a bit of a hack. # See the `src/tools/rustc-workspace-hack/README.md` file in `rust-lang/rust` diff --git a/rust-version b/rust-version index 42aa6d8d76a03..543d4e269d410 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -f466f52c1bf8f2e4454e31c683a88625ad4b4033 +55e00631e5bc5b16d40232914e57deeea197a8e4 diff --git a/src/helpers.rs b/src/helpers.rs index 0245540debbe7..f7be3de8e4812 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -1,4 +1,4 @@ -use std::mem; +use std::{mem, iter}; use std::ffi::{OsStr, OsString}; use rustc::hir::def_id::{DefId, CRATE_DEF_INDEX}; @@ -428,7 +428,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx return Ok(false); } // FIXME: We should use `Iterator::chain` instead when rust-lang/rust#65704 lands. - self.eval_context_mut().memory.write_bytes(scalar, [bytes, &[0]].concat())?; + self.eval_context_mut().memory.write_bytes(scalar, bytes.iter().copied().chain(iter::once(0u8)))?; Ok(true) } } diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 66fb53581e680..dea01c63a05b9 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -1,4 +1,4 @@ -use std::convert::TryInto; +use std::{iter, convert::TryInto}; use rustc::hir::def_id::DefId; use rustc::mir; @@ -52,7 +52,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if zero_init { // We just allocated this, the access is definitely in-bounds. this.memory - .write_bytes(ptr.into(), itertools::repeat_n(0u8, size as usize)) + .write_bytes(ptr.into(), iter::repeat(0u8).take(size as usize)) .unwrap(); } Scalar::Ptr(ptr) @@ -227,7 +227,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ); // We just allocated this, the access is definitely in-bounds. this.memory - .write_bytes(ptr.into(), itertools::repeat_n(0u8, size as usize)) + .write_bytes(ptr.into(), iter::repeat(0u8).take(size as usize)) .unwrap(); this.write_scalar(Scalar::Ptr(ptr), dest)?; } @@ -839,7 +839,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let system_info = this.deref_operand(args[0])?; // Initialize with `0`. this.memory - .write_bytes(system_info.ptr, itertools::repeat_n(0, system_info.layout.size.bytes() as usize))?; + .write_bytes(system_info.ptr, iter::repeat(0u8).take(system_info.layout.size.bytes() as usize))?; // Set number of processors. let dword_size = Size::from_bytes(4); let num_cpus = this.mplace_field(system_info, 6)?; diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index d39e70d8990fb..5ef7fba7f5908 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -1,3 +1,5 @@ +use std::iter; + use rustc_apfloat::Float; use rustc::mir; use rustc::mir::interpret::{InterpResult, PointerArithmetic}; @@ -357,7 +359,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Do it in memory let mplace = this.force_allocation(dest)?; mplace.meta.unwrap_none(); // must be sized - this.memory.write_bytes(mplace.ptr, itertools::repeat_n(0, dest.layout.size.bytes() as usize))?; + this.memory.write_bytes(mplace.ptr, iter::repeat(0u8).take(dest.layout.size.bytes() as usize))?; } } } @@ -562,7 +564,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let ptr = this.read_scalar(args[0])?.not_undef()?; let count = this.read_scalar(args[2])?.to_usize(this)?; let byte_count = ty_layout.size * count; - this.memory.write_bytes(ptr, itertools::repeat_n(val_byte, byte_count.bytes() as usize))?; + this.memory.write_bytes(ptr, iter::repeat(val_byte).take(byte_count.bytes() as usize))?; } name => throw_unsup_format!("unimplemented intrinsic: {}", name), From c87f106cacf70611b37edd31c44fa133034b22ed Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 24 Oct 2019 10:23:44 +0200 Subject: [PATCH 1250/3747] update comments and some tweaks --- src/helpers.rs | 7 +++---- src/operator.rs | 5 +++-- src/shims/fs.rs | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index f7be3de8e4812..dd0530cf48b4e 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -379,7 +379,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx _ => throw_unsup_format!("The {} error cannot be transformed into a raw os error", e) })? } else { - // FIXME: we have to implement the windows' equivalent of this. + // FIXME: we have to implement the Windows equivalent of this. throw_unsup_format!("Setting the last OS error from an io::Error is unsupported for {}.", target.target_os) }; this.set_last_error(last_error) @@ -390,7 +390,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// `Ok(-1)` and sets the last OS error accordingly. /// /// This function uses `T: From` instead of `i32` directly because some IO related - /// functions return different integer types (like `read`, that returns an `i64`) + /// functions return different integer types (like `read`, that returns an `i64`). fn try_unwrap_io_result>( &mut self, result: std::io::Result, @@ -423,11 +423,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, bool> { let bytes = os_str_to_bytes(os_str)?; // If `size` is smaller or equal than `bytes.len()`, writing `bytes` plus the required null - // terminator to memory using the `ptr` pointer would cause an overflow. + // terminator to memory using the `ptr` pointer would cause an out-of-bounds access. if size <= bytes.len() as u64 { return Ok(false); } - // FIXME: We should use `Iterator::chain` instead when rust-lang/rust#65704 lands. self.eval_context_mut().memory.write_bytes(scalar, bytes.iter().copied().chain(iter::once(0u8)))?; Ok(true) } diff --git a/src/operator.rs b/src/operator.rs index 9c02c56fd6a1a..a60bc8c0b13d1 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -1,3 +1,5 @@ +use std::convert::TryFrom; + use rustc::ty::{Ty, layout::LayoutOf}; use rustc::mir; @@ -117,8 +119,7 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { pointee_ty: Ty<'tcx>, offset: i64, ) -> InterpResult<'tcx, Scalar> { - // FIXME: assuming here that type size is less than `i64::max_value()`. - let pointee_size = self.layout_of(pointee_ty)?.size.bytes() as i64; + let pointee_size = i64::try_from(self.layout_of(pointee_ty)?.size.bytes()).unwrap(); let offset = offset .checked_mul(pointee_size) .ok_or_else(|| err_panic!(Overflow(mir::BinOp::Mul)))?; diff --git a/src/shims/fs.rs b/src/shims/fs.rs index 08c9f3ec06e78..c484795d8fec7 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -95,7 +95,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx throw_unsup_format!("unsupported flags {:#x}", flag & !mirror); } - let path: std::path::PathBuf = this.read_os_string_from_c_string(this.read_scalar(path_op)?.not_undef()?)?.into(); + let path = this.read_os_string_from_c_string(this.read_scalar(path_op)?.not_undef()?)?; let fd = options.open(path).map(|file| { let mut fh = &mut this.machine.file_handler; From 1b96a822de09be7739c93f8409dbd7bbbfa3a340 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 24 Oct 2019 10:31:08 +0200 Subject: [PATCH 1251/3747] compiletest-nightly should work again --- Cargo.lock | 44 -------------------------------------------- Cargo.toml | 2 +- 2 files changed, 1 insertion(+), 45 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0f04aa04bb454..18cef9461b268 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -172,7 +172,6 @@ dependencies = [ "serde_derive 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "tester 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -312,15 +311,6 @@ name = "itoa" version = "0.4.4" 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 = "1.4.0" @@ -695,15 +685,6 @@ dependencies = [ "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "term" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "termcolor" version = "1.0.5" @@ -712,16 +693,6 @@ dependencies = [ "wincolor 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "tester" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "getopts 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", - "term 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "thread_local" version = "0.3.6" @@ -765,11 +736,6 @@ name = "wasi" version = "0.7.0" 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" version = "0.3.8" @@ -779,11 +745,6 @@ dependencies = [ "winapi-x86_64-pc-windows-gnu 0.4.0 (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" - [[package]] name = "winapi-i686-pc-windows-gnu" version = "0.4.0" @@ -861,7 +822,6 @@ dependencies = [ "checksum humantime 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f" "checksum itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5b8467d9c1cebe26feb08c640139247fac215782d35371ade9a2136ed6085358" "checksum itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "501266b7edd0174f8530248f87f99c88fbe60ca4ef3dd486835b8d8d53136f7f" -"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" "checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" "checksum libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)" = "1a31a0627fdf1f6a39ec0dd577e101440b7db22672c0901fe00a9a6fbb5c24e8" "checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7" @@ -906,18 +866,14 @@ dependencies = [ "checksum syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "66850e97125af79138385e9b88339cbcd037e3f28ceab8c5ad98e64f0f1f80bf" "checksum synstructure 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3f085a5855930c0441ca1288cf044ea4aecf4f43a91668abdb870b4ba546a203" "checksum tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9" -"checksum term 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "fa63644f74ce96fbeb9b794f66aff2a52d601cbd5e80f4b97123e3899f4570f1" "checksum termcolor 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "96d6098003bde162e4277c70665bd87c326f5a0c3f3fbfb285787fa482d54e6e" -"checksum tester 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5e812cb26c597f86a49b26dbb58b878bd2a2b4b93fc069dc39499228fe556ff6" "checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b" "checksum time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f" "checksum unicode-width 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7007dbd421b92cc6e28410fe7362e2e0a2503394908f417b68ec8d1c364c4e20" "checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" "checksum vergen 3.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "6aba5e34f93dc7051dfad05b98a18e9156f27e7b431fe1d2398cb6061c0a1dba" "checksum wasi 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b89c3ce4ce14bdc6fb6beaf9ec7928ca331de5df7e5ea278375642a2f478570d" -"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" "checksum winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6" -"checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" "checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" "checksum winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7168bab6e1daee33b4557efd0e95d5ca70a03706d39fa5f3fe7a236f584b03c9" "checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/Cargo.toml b/Cargo.toml index 4c39341e10c14..91da02eac8a6c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -60,5 +60,5 @@ cargo_miri = ["cargo_metadata", "directories", "rustc_version"] rustc_tests = [] [dev-dependencies] -compiletest_rs = { version = "0.3.24", features = ["tmp", "stable"] } +compiletest_rs = { version = "0.3.24", features = ["tmp"] } colored = "1.6" From 930c797a83669d0a6ba7797673bdb535e2979bd6 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 11 Oct 2019 10:11:01 +0200 Subject: [PATCH 1252/3747] bump rustc and adjust for rustc-dev component (also sync AppVeyor with Travis: use stable cargo) --- .appveyor.yml | 2 +- .travis.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index 2ba95c228bafb..2474657fd7776 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -32,7 +32,7 @@ install: - rustup update # Install "master" toolchain - cargo install rustup-toolchain-install-master & exit 0 - - rustup-toolchain-install-master -f -n master %RUSTC_HASH% -c cargo -c rust-src + - rustup-toolchain-install-master -f -n master %RUSTC_HASH% -c rust-src -c rustc-dev - rustup default master - rustc --version - cargo --version diff --git a/.travis.yml b/.travis.yml index 51f02e76824be..bb38510e39340 100644 --- a/.travis.yml +++ b/.travis.yml @@ -39,7 +39,7 @@ before_script: - rustup update # Install "master" toolchain - cargo install rustup-toolchain-install-master || echo "rustup-toolchain-install-master already installed" -- travis_retry rustup-toolchain-install-master -f -n master $RUSTC_HASH -c rust-src +- travis_retry rustup-toolchain-install-master -f -n master $RUSTC_HASH -c rust-src -c rustc-dev - rustup default master - rustc --version - cargo --version From 557836b83e3511e645b3484d9d2286980319fd58 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 11 Oct 2019 10:13:26 +0200 Subject: [PATCH 1253/3747] adjust README for rustc-dev --- CONTRIBUTING.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 83e2338552e99..d6436873938ed 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -31,8 +31,10 @@ Miri heavily relies on internal rustc interfaces to execute MIR. Still, some things (like adding support for a new intrinsic or a shim for an external function being called) can be done by working just on the Miri side. -To prepare, make sure you are using a nightly Rust compiler. Then you should be -able to just `cargo build` Miri. +To prepare, make sure you are using a nightly Rust compiler. You also need to +have the `rust-src` and `rustc-dev` components installed, which you can add via +`rustup component add rust-src rustc-dev`. Then you should be able to just +`cargo build` Miri. In case this fails, your nightly might be incompatible with Miri master. The `rust-version` file contains the commit hash of rustc that Miri is currently @@ -41,7 +43,7 @@ to wait for the next nightly to get released. You can also use [`rustup-toolchain-install-master`](https://github.com/kennytm/rustup-toolchain-install-master) to install that exact version of rustc as a toolchain: ``` -rustup-toolchain-install-master $(cat rust-version) -c rust-src +rustup-toolchain-install-master $(cat rust-version) -c rust-src -c rustc-dev ``` Another common problem is outdated dependencies: Miri does not come with a From 4872c5cbbe9a4f59c71a9ffde4d5e521c08e8ea0 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 12 Oct 2019 17:11:29 +0200 Subject: [PATCH 1254/3747] temporarily ignore cached rustup-toolchain-install-master --- .appveyor.yml | 2 +- .travis.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index 2474657fd7776..3fe85fe142106 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -31,7 +31,7 @@ install: - rustup component remove rust-docs & exit 0 - rustup update # Install "master" toolchain - - cargo install rustup-toolchain-install-master & exit 0 + - cargo install rustup-toolchain-install-master -f - rustup-toolchain-install-master -f -n master %RUSTC_HASH% -c rust-src -c rustc-dev - rustup default master - rustc --version diff --git a/.travis.yml b/.travis.yml index bb38510e39340..e9df794b59402 100644 --- a/.travis.yml +++ b/.travis.yml @@ -38,7 +38,7 @@ before_script: - rustup component remove rust-docs || echo "rust-docs already gone" - rustup update # Install "master" toolchain -- cargo install rustup-toolchain-install-master || echo "rustup-toolchain-install-master already installed" +- cargo install rustup-toolchain-install-master -f - travis_retry rustup-toolchain-install-master -f -n master $RUSTC_HASH -c rust-src -c rustc-dev - rustup default master - rustc --version From 55e1251886425492edac903bcbe7f7474d3a2c55 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 24 Oct 2019 13:12:26 +0200 Subject: [PATCH 1255/3747] rustc-dev landed; adjust rust version --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 543d4e269d410..61a6353bb4d90 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -55e00631e5bc5b16d40232914e57deeea197a8e4 +8e0007f829661e57d008d2e908c95f6e84b04b25 From 39cdc35dd7b5362001e5987df1e85f375f2187c4 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 24 Oct 2019 15:44:35 +0200 Subject: [PATCH 1256/3747] add back '-c cargo' --- .appveyor.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.appveyor.yml b/.appveyor.yml index 3fe85fe142106..c8ee04275c835 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -32,7 +32,9 @@ install: - rustup update # Install "master" toolchain - cargo install rustup-toolchain-install-master -f - - rustup-toolchain-install-master -f -n master %RUSTC_HASH% -c rust-src -c rustc-dev + # We need to install cargo here as well or else the DLL search path inside `cargo run` + # will be for the wrong toolchain. (On Unix, `./miri` takes care of this, but not here.) + - rustup-toolchain-install-master -f -n master %RUSTC_HASH% -c rust-src -c rustc-dev -c cargo - rustup default master - rustc --version - cargo --version From 260b463bb037809e9558421ad5e73bf89e9a08df Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Thu, 24 Oct 2019 08:44:13 -0500 Subject: [PATCH 1257/3747] Clean file handling functions --- src/shims/fs.rs | 120 +++++++++++++++++++----------------------------- 1 file changed, 46 insertions(+), 74 deletions(-) diff --git a/src/shims/fs.rs b/src/shims/fs.rs index c484795d8fec7..760fc1daff1fb 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -1,5 +1,5 @@ use std::collections::HashMap; -use std::fs::{File, OpenOptions, remove_file}; +use std::fs::{remove_file, File, OpenOptions}; use std::io::{Read, Write}; use rustc::ty::layout::Size; @@ -125,8 +125,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // `FD_CLOEXEC` value without checking if the flag is set for the file because `std` // always sets this flag when opening a file. However we still need to check that the // file itself is open. - let fd_cloexec = this.eval_libc_i32("FD_CLOEXEC")?; - this.get_handle_and(fd, |_| Ok(fd_cloexec)) + if this.machine.file_handler.handles.contains_key(&fd) { + Ok(this.eval_libc_i32("FD_CLOEXEC")?) + } else { + this.handle_not_found() + } } else { throw_unsup_format!("The {:#x} command is not supported for `fcntl`)", cmd); } @@ -139,9 +142,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let fd = this.read_scalar(fd_op)?.to_i32()?; - this.remove_handle_and(fd, |handle, this| { + if let Some(handle) = this.machine.file_handler.handles.remove(&fd) { this.try_unwrap_io_result(handle.file.sync_all().map(|_| 0i32)) - }) + } else { + this.handle_not_found() + } } fn read( @@ -160,20 +165,24 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx return Ok(0); } let fd = this.read_scalar(fd_op)?.to_i32()?; - let buf_scalar = this.read_scalar(buf_op)?.not_undef()?; - - // Remove the file handle to avoid borrowing issues. - this.remove_handle_and(fd, |mut handle, this| { - // Don't use `?` to avoid returning before reinserting the handle. - let bytes = this.force_ptr(buf_scalar).and_then(|buf| { - this.memory - .get_mut(buf.alloc_id)? - .get_bytes_mut(&*this.tcx, buf, Size::from_bytes(count)) - .map(|buffer| handle.file.read(buffer)) - }); - this.machine.file_handler.handles.insert(fd, handle).unwrap_none(); - this.try_unwrap_io_result(bytes?.map(|bytes| bytes as i64)) - }) + let buf = this.read_scalar(buf_op)?.not_undef()?; + + if let Some(handle) = this.machine.file_handler.handles.get_mut(&fd) { + // We want to read at most `count` bytes + let mut bytes = vec![0; count as usize]; + let result = handle.file.read(&mut bytes).map(|c| c as i64); + let written_count = this.try_unwrap_io_result(result)?; + // `try_unwrap_io_result` returns Ok(`-1`) if `result` is an error. There is no other + // way of returning `-1` because the `Ok` variant of `result` contains the number of + // written bytes, which is a possitive value. + if written_count != -1 { + // If reading to `bytes` did not fail, we write those bytes to the buffer. + this.memory.write_bytes(buf, bytes)?; + } + Ok(written_count) + } else { + this.handle_not_found() + } } fn write( @@ -192,20 +201,18 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx return Ok(0); } let fd = this.read_scalar(fd_op)?.to_i32()?; - let buf = this.force_ptr(this.read_scalar(buf_op)?.not_undef()?)?; - - this.remove_handle_and(fd, |mut handle, this| { - let bytes = this.memory.get(buf.alloc_id).and_then(|alloc| { - alloc - .get_bytes(&*this.tcx, buf, Size::from_bytes(count)) - .map(|bytes| handle.file.write(bytes).map(|bytes| bytes as i64)) - }); - this.machine.file_handler.handles.insert(fd, handle).unwrap_none(); - this.try_unwrap_io_result(bytes?) - }) + let buf = this.read_scalar(buf_op)?.not_undef()?; + + if let Some(handle) = this.machine.file_handler.handles.get_mut(&fd) { + let bytes = this.memory.read_bytes(buf, Size::from_bytes(count))?; + let result = handle.file.write(&bytes).map(|c| c as i64); + this.try_unwrap_io_result(result) + } else { + this.handle_not_found() + } } - fn unlink( &mut self, path_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + fn unlink(&mut self, path_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); this.check_no_isolation("unlink")?; @@ -217,49 +224,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.try_unwrap_io_result(result) } - /// Helper function that gets a `FileHandle` immutable reference and allows to manipulate it - /// using the `f` closure. - /// - /// If the `fd` file descriptor does not correspond to a file, this functions returns `Ok(-1)` - /// and sets `Evaluator::last_error` to `libc::EBADF` (invalid file descriptor). - /// - /// This function uses `T: From` instead of `i32` directly because some IO related - /// functions return different integer types (like `read`, that returns an `i64`). - fn get_handle_and>(&mut self, fd: i32, f: F) -> InterpResult<'tcx, T> - where - F: Fn(&FileHandle) -> InterpResult<'tcx, T>, - { + /// Function used when a handle is not found inside `FileHandler`. It returns `Ok(-1)`and sets + /// the last OS error to `libc::EBADF` (invalid file descriptor). This function uses + /// `T: From` instead of `i32` directly because some fs functions return different integer + /// types (like `read`, that returns an `i64`). + fn handle_not_found>(&mut self) -> InterpResult<'tcx, T> { let this = self.eval_context_mut(); - if let Some(handle) = this.machine.file_handler.handles.get(&fd) { - f(handle) - } else { - let ebadf = this.eval_libc("EBADF")?; - this.set_last_error(ebadf)?; - Ok((-1).into()) - } - } - - /// Helper function that removes a `FileHandle` and allows to manipulate it using the `f` - /// closure. This function is quite useful when you need to modify a `FileHandle` but you need - /// to modify `MiriEvalContext` at the same time, so you can modify the handle and reinsert it - /// using `f`. - /// - /// If the `fd` file descriptor does not correspond to a file, this functions returns `Ok(-1)` - /// and sets `Evaluator::last_error` to `libc::EBADF` (invalid file descriptor). - /// - /// This function uses `T: From` instead of `i32` directly because some IO related - /// functions return different integer types (like `read`, that returns an `i64`). - fn remove_handle_and>(&mut self, fd: i32, mut f: F) -> InterpResult<'tcx, T> - where - F: FnMut(FileHandle, &mut MiriEvalContext<'mir, 'tcx>) -> InterpResult<'tcx, T>, - { - let this = self.eval_context_mut(); - if let Some(handle) = this.machine.file_handler.handles.remove(&fd) { - f(handle, this) - } else { - let ebadf = this.eval_libc("EBADF")?; - this.set_last_error(ebadf)?; - Ok((-1).into()) - } + let ebadf = this.eval_libc("EBADF")?; + this.set_last_error(ebadf)?; + Ok((-1).into()) } } From 459aea8f520ef74f81863f17c4fc68bd7ef607fb Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 25 Oct 2019 20:26:01 +0200 Subject: [PATCH 1258/3747] test align_to example --- tests/run-pass/align_offset.rs | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/tests/run-pass/align_offset.rs b/tests/run-pass/align_offset.rs index 736889174839f..1202fd00be157 100644 --- a/tests/run-pass/align_offset.rs +++ b/tests/run-pass/align_offset.rs @@ -71,8 +71,31 @@ fn test_from_utf8() { println!("{:?}", std::str::from_utf8(content).unwrap()); } +fn test_u64_array() { + #[derive(Default)] + #[repr(align(8))] + struct AlignToU64(T); + + const BYTE_LEN: usize = std::mem::size_of::<[u64; 4]>(); + type Data = AlignToU64<[u8; BYTE_LEN]>; + + fn example(data: &Data) { + let (head, u64_arrays, tail) = unsafe { data.0.align_to::<[u64; 4]>() }; + + assert!(head.is_empty(), "buffer was not aligned for 64-bit numbers"); + assert_eq!(u64_arrays.len(), 1, "buffer was not long enough"); + assert!(tail.is_empty(), "buffer was too long"); + + let u64_array = &u64_arrays[0]; + let _val = u64_array[0]; // make sure we can actually load this + } + + example(&Data::default()); +} + fn main() { test_align_offset(); test_align_to(); test_from_utf8(); + test_u64_array(); } From d8a3a1f09c7d32ad4122932bf95ab5b4249eecda Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 26 Oct 2019 09:33:24 +0200 Subject: [PATCH 1259/3747] rustup for projection interning --- rust-version | 2 +- src/helpers.rs | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/rust-version b/rust-version index 61a6353bb4d90..f7618eadd9f07 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -8e0007f829661e57d008d2e908c95f6e84b04b25 +084edc426f2e7e4bbedb5c6afa7fc422a52ee379 diff --git a/src/helpers.rs b/src/helpers.rs index dd0530cf48b4e..ae117d5fb352f 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -5,6 +5,7 @@ use rustc::hir::def_id::{DefId, CRATE_DEF_INDEX}; use rustc::mir; use rustc::ty::{ self, + List, layout::{self, LayoutOf, Size, TyLayout}, }; @@ -75,7 +76,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// Get the `Place` for a local fn local_place(&mut self, local: mir::Local) -> InterpResult<'tcx, PlaceTy<'tcx, Tag>> { let this = self.eval_context_mut(); - let place = mir::Place { base: mir::PlaceBase::Local(local), projection: Box::new([]) }; + let place = mir::Place { base: mir::PlaceBase::Local(local), projection: List::empty() }; this.eval_place(&place) } From d7967f6b058b3dbf8608a76b0fbe165585a2b77c Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Sat, 26 Oct 2019 08:54:02 -0500 Subject: [PATCH 1260/3747] Drop files explicitly when closing them --- src/shims/fs.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/shims/fs.rs b/src/shims/fs.rs index 760fc1daff1fb..c57ec1a1f916b 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -143,7 +143,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let fd = this.read_scalar(fd_op)?.to_i32()?; if let Some(handle) = this.machine.file_handler.handles.remove(&fd) { - this.try_unwrap_io_result(handle.file.sync_all().map(|_| 0i32)) + // `File::sync_all` does the checks that are done when closing a file. We do this to + // to handle possible errors correctly. + let result = this.try_unwrap_io_result(handle.file.sync_all().map(|_| 0i32)); + // Now we actually drop the handle. + drop(handle); + // And return the result. + result } else { this.handle_not_found() } From 122549fd0959634d0255ba40be6c994e9e60d791 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Sat, 26 Oct 2019 09:03:45 -0500 Subject: [PATCH 1261/3747] Simplify `read` logic --- src/shims/fs.rs | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/shims/fs.rs b/src/shims/fs.rs index c57ec1a1f916b..e8c42eb9a3017 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -177,15 +177,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // We want to read at most `count` bytes let mut bytes = vec![0; count as usize]; let result = handle.file.read(&mut bytes).map(|c| c as i64); - let written_count = this.try_unwrap_io_result(result)?; - // `try_unwrap_io_result` returns Ok(`-1`) if `result` is an error. There is no other - // way of returning `-1` because the `Ok` variant of `result` contains the number of - // written bytes, which is a possitive value. - if written_count != -1 { - // If reading to `bytes` did not fail, we write those bytes to the buffer. + // If reading to `bytes` did not fail, we write those bytes to the buffer. + if result.is_ok() { this.memory.write_bytes(buf, bytes)?; } - Ok(written_count) + this.try_unwrap_io_result(result) } else { this.handle_not_found() } From b40351c53a2047114705b2efa3161687dc111c0b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Miku=C5=82a?= Date: Sun, 27 Oct 2019 23:01:01 +0100 Subject: [PATCH 1262/3747] Bump dependencies --- Cargo.lock | 18 +++++++++--------- Cargo.toml | 6 +++--- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e1444252a8171..fb7ab619281f5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -98,7 +98,7 @@ dependencies = [ [[package]] name = "cargo_metadata" -version = "0.8.2" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -216,7 +216,7 @@ dependencies = [ [[package]] name = "env_logger" -version = "0.6.2" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "atty 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)", @@ -282,7 +282,7 @@ dependencies = [ [[package]] name = "hex" -version = "0.3.2" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -335,13 +335,13 @@ name = "miri" version = "0.1.0" dependencies = [ "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "cargo_metadata 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", + "cargo_metadata 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "colored 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "compiletest_rs 0.3.25 (registry+https://github.com/rust-lang/crates.io-index)", "directories 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "env_logger 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", + "env_logger 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "getrandom 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", + "hex 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -783,7 +783,7 @@ dependencies = [ "checksum blake2b_simd 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)" = "5850aeee1552f495dd0250014cf64b82b7c8879a89d83b33bbdace2cc4f63182" "checksum byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a7c3dd8985a7111efc5c80b44e23ecdd8c007de8ade3b96595387e812b957cf5" "checksum c2-chacha 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "214238caa1bf3a496ec3392968969cab8549f96ff30652c9e56885329315f6bb" -"checksum cargo_metadata 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "700b3731fd7d357223d0000f4dbf1808401b694609035c3c411fbc0cd375c426" +"checksum cargo_metadata 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8d2d1617e838936c0d2323a65cc151e03ae19a7678dd24f72bccf27119b90a5d" "checksum cc 1.0.46 (registry+https://github.com/rust-lang/crates.io-index)" = "0213d356d3c4ea2c18c40b037c3be23cd639825c18f25ee670ac7813beeef99c" "checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" "checksum cgmath 0.16.1 (registry+https://github.com/rust-lang/crates.io-index)" = "64a4b57c8f4e3a2e9ac07e0f6abc9c24b6fc9e1b54c3478cfb598f3d0023e51c" @@ -796,14 +796,14 @@ dependencies = [ "checksum diff 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "3c2b69f912779fbb121ceb775d74d51e915af17aaebc38d28a592843a2dd0a3a" "checksum directories 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "551a778172a450d7fc12e629ca3b0428d00f6afa9a43da1b630d54604e97371c" "checksum dirs-sys 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "afa0b23de8fd801745c471deffa6e12d248f962c9fd4b4c33787b055599bde7b" -"checksum env_logger 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "aafcde04e90a5226a6443b7aabdb016ba2f8307c847d524724bd9b346dd1a2d3" +"checksum env_logger 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "44533bbbb3bb3c1fa17d9f2e4e38bbbaf8396ba82193c4cb1b6445d711445d36" "checksum failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "f8273f13c977665c5db7eb2b99ae520952fe5ac831ae4cd09d80c4c7042b5ed9" "checksum failure_derive 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0bc225b78e0391e4b8683440bf2e63c2deeeb2ce5189eab46e2b68c6d3725d08" "checksum filetime 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "6bd7380b54ced79dda72ecc35cc4fbbd1da6bba54afaa37e96fd1c2a308cd469" "checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" "checksum getopts 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)" = "14dbbfd5c71d70241ecf9e6f13737f7b5ce823821063188d7e46c41d371eebd5" "checksum getrandom 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "473a1265acc8ff1e808cd0a1af8cee3c2ee5200916058a2ca113c29f2d903571" -"checksum hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "805026a5d0141ffc30abb3be3173848ad46a1b1664fe632428479619a3644d77" +"checksum hex 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "023b39be39e3a2da62a94feb433e91e8bcd37676fbc8bea371daf52b7a769a3e" "checksum humantime 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f" "checksum itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "501266b7edd0174f8530248f87f99c88fbe60ca4ef3dd486835b8d8d53136f7f" "checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" diff --git a/Cargo.toml b/Cargo.toml index bd345ea2b7f55..ba31dd848ab41 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -30,15 +30,15 @@ doctest = false # and no doc tests required-features = ["rustc_tests"] [dependencies] -cargo_metadata = { version = "0.8", optional = true } +cargo_metadata = { version = "0.9.0", optional = true } directories = { version = "2.0", optional = true } rustc_version = { version = "0.2.3", optional = true } getrandom = { version = "0.1.8", features = ["std"] } byteorder = "1.3" -env_logger = "0.6" +env_logger = "0.7.1" log = "0.4" shell-escape = "0.1.4" -hex = "0.3.2" +hex = "0.4.0" rand = "0.7" # A noop dependency that changes in the Rust repository, it's a bit of a hack. From 06ef77bfef45b3eb01ab4c3ceb0fa30186de4ea0 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Mon, 28 Oct 2019 16:44:18 -0500 Subject: [PATCH 1263/3747] Check for usize to i64 overflows --- src/shims/fs.rs | 28 +++++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/src/shims/fs.rs b/src/shims/fs.rs index e8c42eb9a3017..2710cbacb0213 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -176,12 +176,18 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if let Some(handle) = this.machine.file_handler.handles.get_mut(&fd) { // We want to read at most `count` bytes let mut bytes = vec![0; count as usize]; - let result = handle.file.read(&mut bytes).map(|c| c as i64); - // If reading to `bytes` did not fail, we write those bytes to the buffer. - if result.is_ok() { - this.memory.write_bytes(buf, bytes)?; + let result = handle.file.read(&mut bytes); + + if let Ok(c) = result { + // Check that we read less than `i64::MAX` bytes. + if c > (i64::max_value() as usize) { + throw_unsup_format!("Number of read bytes {} is larger than the maximum value", c); + } + // If reading to `bytes` did not fail, we write those bytes to the buffer. + this.memory.write_bytes(buf, bytes)? } - this.try_unwrap_io_result(result) + + this.try_unwrap_io_result(result.map(|c| c as i64)) } else { this.handle_not_found() } @@ -207,8 +213,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if let Some(handle) = this.machine.file_handler.handles.get_mut(&fd) { let bytes = this.memory.read_bytes(buf, Size::from_bytes(count))?; - let result = handle.file.write(&bytes).map(|c| c as i64); - this.try_unwrap_io_result(result) + let result = handle.file.write(&bytes); + + if let Ok(c) = result { + // Check that we wrote less than `i64::MAX` bytes. + if c > (i64::max_value() as usize) { + throw_unsup_format!("Number of written bytes {} is larger than the maximum value", c); + } + } + + this.try_unwrap_io_result(result.map(|c| c as i64)) } else { this.handle_not_found() } From 15ae234a42bf45efeb8fae3d1c7a080a10c465cd Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 30 Oct 2019 10:16:58 +0100 Subject: [PATCH 1264/3747] rustup for span in intrinsic emulation --- rust-version | 2 +- src/machine.rs | 6 +++--- src/shims/intrinsics.rs | 4 +++- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/rust-version b/rust-version index f7618eadd9f07..8fb4c0987318a 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -084edc426f2e7e4bbedb5c6afa7fc422a52ee379 +aa69777ea2902208b24b3fd77767d577ceaf6386 diff --git a/src/machine.rs b/src/machine.rs index 7904e1cc123b3..c07fca68199ce 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -14,8 +14,7 @@ use rustc::ty::{ layout::{LayoutOf, Size}, Ty, TyCtxt, }; -use syntax::attr; -use syntax::symbol::sym; +use syntax::{attr, source_map::Span, symbol::sym}; use crate::*; @@ -192,11 +191,12 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { #[inline(always)] fn call_intrinsic( ecx: &mut rustc_mir::interpret::InterpCx<'mir, 'tcx, Self>, + span: Span, instance: ty::Instance<'tcx>, args: &[OpTy<'tcx, Tag>], dest: PlaceTy<'tcx, Tag>, ) -> InterpResult<'tcx> { - ecx.call_intrinsic(instance, args, dest) + ecx.call_intrinsic(span, instance, args, dest) } #[inline(always)] diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 5ef7fba7f5908..9e47c095d6d31 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -5,6 +5,7 @@ use rustc::mir; use rustc::mir::interpret::{InterpResult, PointerArithmetic}; use rustc::ty::layout::{self, LayoutOf, Size, Align}; use rustc::ty; +use syntax::source_map::Span; use crate::{ PlaceTy, OpTy, Immediate, Scalar, Tag, @@ -15,12 +16,13 @@ impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tc pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { fn call_intrinsic( &mut self, + span: Span, instance: ty::Instance<'tcx>, args: &[OpTy<'tcx, Tag>], dest: PlaceTy<'tcx, Tag>, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - if this.emulate_intrinsic(instance, args, dest)? { + if this.emulate_intrinsic(span, instance, args, dest)? { return Ok(()); } let tcx = &{this.tcx.tcx}; From 90634121b39ca2e15abc40ee2622b3d7e42d823c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 30 Oct 2019 15:05:44 +0100 Subject: [PATCH 1265/3747] fix typo --- src/stacked_borrows.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 2188b9d5394a3..6e63bb073c8c4 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -241,7 +241,7 @@ impl<'tcx> Stack { /// Find the first write-incompatible item above the given one -- /// i.e, find the height to which the stack will be truncated when writing to `granting`. - fn find_first_write_incompaible(&self, granting: usize) -> usize { + fn find_first_write_incompatible(&self, granting: usize) -> usize { let perm = self.borrows[granting].perm; match perm { Permission::SharedReadOnly => @@ -309,7 +309,7 @@ impl<'tcx> Stack { if access == AccessKind::Write { // Remove everything above the write-compatible items, like a proper stack. This makes sure read-only and unique // pointers become invalid on write accesses (ensures F2a, and ensures U2 for write accesses). - let first_incompatible_idx = self.find_first_write_incompaible(granting_idx); + let first_incompatible_idx = self.find_first_write_incompatible(granting_idx); for item in self.borrows.drain(first_incompatible_idx..).rev() { trace!("access: popping item {:?}", item); Stack::check_protector(&item, Some(tag), global)?; @@ -391,7 +391,7 @@ impl<'tcx> Stack { // access. Instead of popping the stack, we insert the item at the place the stack would // be popped to (i.e., we insert it above all the write-compatible items). // This ensures F2b by adding the new item below any potentially existing `SharedReadOnly`. - self.find_first_write_incompaible(granting_idx) + self.find_first_write_incompatible(granting_idx) } else { // A "safe" reborrow for a pointer that actually expects some aliasing guarantees. // Here, creating a reference actually counts as an access. From 1e0b398cb6fbfe6b2c0c029fac08f64a7e96d322 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 2 Nov 2019 11:48:28 +0100 Subject: [PATCH 1266/3747] Windows cmdline: avoid accessing allocations directly --- src/eval.rs | 36 ++++++++++++------------------------ 1 file changed, 12 insertions(+), 24 deletions(-) diff --git a/src/eval.rs b/src/eval.rs index f4a8d176172d4..2f998408b8ccb 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -4,7 +4,7 @@ use rand::rngs::StdRng; use rand::SeedableRng; use rustc::hir::def_id::DefId; -use rustc::ty::layout::{Align, LayoutOf, Size}; +use rustc::ty::layout::{LayoutOf, Size}; use rustc::ty::{self, TyCtxt}; use syntax::source_map::DUMMY_SP; @@ -48,7 +48,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( EnvVars::init(&mut ecx, config.excluded_env_vars); // Setup first stack-frame - let main_instance = ty::Instance::mono(ecx.tcx.tcx, main_id); + let main_instance = ty::Instance::mono(tcx, main_id); let main_mir = ecx.load_mir(main_instance.def, None)?; if !main_mir.return_ty().is_unit() || main_mir.arg_count != 0 { @@ -59,11 +59,10 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( let main_ret_ty = tcx.fn_sig(main_id).output(); let main_ret_ty = main_ret_ty.no_bound_vars().unwrap(); let start_instance = ty::Instance::resolve( - ecx.tcx.tcx, + tcx, ty::ParamEnv::reveal_all(), start_id, - ecx.tcx - .mk_substs(::std::iter::once(ty::subst::GenericArg::from(main_ret_ty))), + tcx.mk_substs(::std::iter::once(ty::subst::GenericArg::from(main_ret_ty))), ) .unwrap(); let start_mir = ecx.load_mir(start_instance.def, None)?; @@ -134,8 +133,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( } // Make an array with all these pointers, in the Miri memory. let argvs_layout = ecx.layout_of( - ecx.tcx - .mk_array(ecx.tcx.mk_imm_ptr(ecx.tcx.types.u8), argvs.len() as u64), + tcx.mk_array(tcx.mk_imm_ptr(tcx.types.u8), argvs.len() as u64), )?; let argvs_place = ecx.allocate(argvs_layout, MiriMemoryKind::Env.into()); for (idx, arg) in argvs.into_iter().enumerate() { @@ -156,31 +154,21 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( // Store command line as UTF-16 for Windows `GetCommandLineW`. { let cmd_utf16: Vec = cmd.encode_utf16().collect(); - let cmd_ptr = ecx.memory.allocate( - Size::from_bytes(cmd_utf16.len() as u64 * 2), - Align::from_bytes(2).unwrap(), - MiriMemoryKind::Env.into(), - ); - ecx.machine.cmd_line = Some(cmd_ptr); + let cmd_type = tcx.mk_array(tcx.types.u16, cmd_utf16.len() as u64); + let cmd_place = ecx.allocate(ecx.layout_of(cmd_type)?, MiriMemoryKind::Env.into()); + ecx.machine.cmd_line = Some(cmd_place.ptr.to_ptr()?); // Store the UTF-16 string. We just allocated so we know the bounds are fine. let char_size = Size::from_bytes(2); - let cmd_alloc = ecx.memory.get_mut(cmd_ptr.alloc_id)?; - let mut cur_ptr = cmd_ptr; - for &c in cmd_utf16.iter() { - cmd_alloc.write_scalar( - &*ecx.tcx, - cur_ptr, - Scalar::from_uint(c, char_size).into(), - char_size, - )?; - cur_ptr = cur_ptr.offset(char_size, &*ecx.tcx)?; + for (idx, &c) in cmd_utf16.iter().enumerate() { + let place = ecx.mplace_field(cmd_place, idx as u64)?; + ecx.write_scalar(Scalar::from_uint(c, char_size), place.into())?; } } args.next().expect_none("start lang item has more arguments than expected"); // Set the last_error to 0 - let errno_layout = ecx.layout_of(ecx.tcx.types.u32)?; + let errno_layout = ecx.layout_of(tcx.types.u32)?; let errno_place = ecx.allocate(errno_layout, MiriMemoryKind::Static.into()); ecx.write_scalar(Scalar::from_u32(0), errno_place.into())?; ecx.machine.last_error = Some(errno_place); From ddb1fc9205586ccd4f71bb7de583769f9fd3fa77 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 2 Nov 2019 11:50:21 +0100 Subject: [PATCH 1267/3747] store scalars where appropriate --- src/eval.rs | 6 +++--- src/machine.rs | 6 +++--- src/shims/foreign_items.rs | 6 +++--- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/eval.rs b/src/eval.rs index 2f998408b8ccb..b87d735ce525d 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -105,7 +105,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( { let argc_place = ecx.allocate(dest.layout, MiriMemoryKind::Env.into()); ecx.write_scalar(argc, argc_place.into())?; - ecx.machine.argc = Some(argc_place.ptr.to_ptr()?); + ecx.machine.argc = Some(argc_place.ptr); } // Third argument (`argv`): created from `config.args`. @@ -149,14 +149,14 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( { let argv_place = ecx.allocate(dest.layout, MiriMemoryKind::Env.into()); ecx.write_scalar(argv, argv_place.into())?; - ecx.machine.argv = Some(argv_place.ptr.to_ptr()?); + ecx.machine.argv = Some(argv_place.ptr); } // Store command line as UTF-16 for Windows `GetCommandLineW`. { let cmd_utf16: Vec = cmd.encode_utf16().collect(); let cmd_type = tcx.mk_array(tcx.types.u16, cmd_utf16.len() as u64); let cmd_place = ecx.allocate(ecx.layout_of(cmd_type)?, MiriMemoryKind::Env.into()); - ecx.machine.cmd_line = Some(cmd_place.ptr.to_ptr()?); + ecx.machine.cmd_line = Some(cmd_place.ptr); // Store the UTF-16 string. We just allocated so we know the bounds are fine. let char_size = Size::from_bytes(2); for (idx, &c) in cmd_utf16.iter().enumerate() { diff --git a/src/machine.rs b/src/machine.rs index c07fca68199ce..c76cc2e568f4f 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -86,9 +86,9 @@ pub struct Evaluator<'tcx> { /// Program arguments (`Option` because we can only initialize them after creating the ecx). /// These are *pointers* to argc/argv because macOS. /// We also need the full command line as one string because of Windows. - pub(crate) argc: Option>, - pub(crate) argv: Option>, - pub(crate) cmd_line: Option>, + pub(crate) argc: Option>, + pub(crate) argv: Option>, + pub(crate) cmd_line: Option>, /// Last OS error location in memory. It is a 32-bit integer. pub(crate) last_error: Option>, diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index dea01c63a05b9..74ce477b8e357 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -765,10 +765,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // FIXME: register the destructor. } "_NSGetArgc" => { - this.write_scalar(Scalar::Ptr(this.machine.argc.unwrap()), dest)?; + this.write_scalar(this.machine.argc.expect("machine must be initialized"), dest)?; } "_NSGetArgv" => { - this.write_scalar(Scalar::Ptr(this.machine.argv.unwrap()), dest)?; + this.write_scalar(this.machine.argv.expect("machine must be initialized"), dest)?; } "SecRandomCopyBytes" => { let len = this.read_scalar(args[1])?.to_usize(this)?; @@ -927,7 +927,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_null(dest)?; } "GetCommandLineW" => { - this.write_scalar(Scalar::Ptr(this.machine.cmd_line.unwrap()), dest)?; + this.write_scalar(this.machine.cmd_line.expect("machine must be initialized"), dest)?; } // The actual name of 'RtlGenRandom' "SystemFunction036" => { From 7a39460e2488fe654b0b6f370e652a42c600e53e Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Wed, 25 Sep 2019 01:19:41 +0200 Subject: [PATCH 1268/3747] Use the upstream `exact_div` implementation --- src/shims/intrinsics.rs | 22 +++++----------------- 1 file changed, 5 insertions(+), 17 deletions(-) diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 9e47c095d6d31..0c6e5f0af69db 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -313,23 +313,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_f64(res), dest)?; } - "exact_div" => { - // Performs an exact division, resulting in undefined behavior where - // `x % y != 0` or `y == 0` or `x == T::min_value() && y == -1` - let a = this.read_immediate(args[0])?; - let b = this.read_immediate(args[1])?; - // check x % y != 0 - if this.overflowing_binary_op(mir::BinOp::Rem, a, b)?.0.to_bits(dest.layout.size)? != 0 { - // Check if `b` is -1, which is the "min_value / -1" case. - let minus1 = Scalar::from_int(-1, dest.layout.size); - return Err(if b.to_scalar().unwrap() == minus1 { - err_ub_format!("exact_div: result of dividing MIN by -1 cannot be represented") - } else { - err_ub_format!("exact_div: {:?} cannot be divided by {:?} without remainder", *a, *b) - }.into()); - } - this.binop_ignore_overflow(mir::BinOp::Div, a, b, dest)?; - }, + "exact_div" => this.exact_div( + this.read_immediate(args[0])?, + this.read_immediate(args[1])?, + dest, + )?, "forget" => {} From 47bfd84c982b43a3e7458a38bd1c432c195f352f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 3 Nov 2019 10:02:32 +0100 Subject: [PATCH 1269/3747] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 8fb4c0987318a..1a58c80128a5a 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -aa69777ea2902208b24b3fd77767d577ceaf6386 +6c1b220fd747bf244f04b380e4d4ae005068f706 From 5a5fa1538229b0304b74ae961af157a7d4aed7d3 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 3 Nov 2019 10:03:30 +0100 Subject: [PATCH 1270/3747] style --- src/shims/intrinsics.rs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 0c6e5f0af69db..cdd31c9298c4e 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -313,11 +313,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_f64(res), dest)?; } - "exact_div" => this.exact_div( - this.read_immediate(args[0])?, - this.read_immediate(args[1])?, - dest, - )?, + "exact_div" => + this.exact_div( + this.read_immediate(args[0])?, + this.read_immediate(args[1])?, + dest, + )?, "forget" => {} From fcf0f886d46050ecbb64c068d62725b1b4ef1aca Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 3 Nov 2019 10:15:55 +0100 Subject: [PATCH 1271/3747] adjust tests --- tests/compile-fail/exact_div2.rs | 2 +- tests/compile-fail/exact_div3.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/compile-fail/exact_div2.rs b/tests/compile-fail/exact_div2.rs index 22bcf027dd05f..f4400d0d8ae22 100644 --- a/tests/compile-fail/exact_div2.rs +++ b/tests/compile-fail/exact_div2.rs @@ -1,5 +1,5 @@ #![feature(core_intrinsics)] fn main() { // divison with a remainder - unsafe { std::intrinsics::exact_div(2u16, 3); } //~ ERROR Scalar(0x0002) cannot be divided by Scalar(0x0003) without remainder + unsafe { std::intrinsics::exact_div(2u16, 3); } //~ ERROR 2 cannot be divided by 3 without remainder } diff --git a/tests/compile-fail/exact_div3.rs b/tests/compile-fail/exact_div3.rs index 2db62e0092d51..0460e412e45e2 100644 --- a/tests/compile-fail/exact_div3.rs +++ b/tests/compile-fail/exact_div3.rs @@ -1,5 +1,5 @@ #![feature(core_intrinsics)] fn main() { // signed divison with a remainder - unsafe { std::intrinsics::exact_div(-19i8, 2); } //~ ERROR Scalar(0xed) cannot be divided by Scalar(0x02) without remainder + unsafe { std::intrinsics::exact_div(-19i8, 2); } //~ ERROR 237 cannot be divided by 2 without remainder } From 955a26fb0803fa1fb46d21abcb89f3a05e5cadda Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 3 Nov 2019 15:39:03 +0100 Subject: [PATCH 1272/3747] calling panic_if_uninhabited is not actually UB --- src/shims/intrinsics.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index cdd31c9298c4e..7c8c06cbbfd54 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -381,7 +381,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let ty = substs.type_at(0); let layout = this.layout_of(ty)?; if layout.abi.is_uninhabited() { - throw_ub_format!("Trying to instantiate uninhabited type {}", ty) + // FIXME: This should throw a panic in the interpreted program instead. + throw_unsup_format!("Trying to instantiate uninhabited type {}", ty) } } From d0b4407b258acdf87a2b44b687564468b115071a Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Sun, 3 Nov 2019 10:04:00 -0600 Subject: [PATCH 1273/3747] Fix casts for `count` check --- src/shims/fs.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/shims/fs.rs b/src/shims/fs.rs index 2710cbacb0213..66e24eb8b0924 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -146,7 +146,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // `File::sync_all` does the checks that are done when closing a file. We do this to // to handle possible errors correctly. let result = this.try_unwrap_io_result(handle.file.sync_all().map(|_| 0i32)); - // Now we actually drop the handle. + // Now we actually close the file. drop(handle); // And return the result. result @@ -180,7 +180,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if let Ok(c) = result { // Check that we read less than `i64::MAX` bytes. - if c > (i64::max_value() as usize) { + if (c as u64) > (i64::max_value() as u64) { throw_unsup_format!("Number of read bytes {} is larger than the maximum value", c); } // If reading to `bytes` did not fail, we write those bytes to the buffer. @@ -217,7 +217,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if let Ok(c) = result { // Check that we wrote less than `i64::MAX` bytes. - if c > (i64::max_value() as usize) { + if (c as u64) > (i64::max_value() as u64) { throw_unsup_format!("Number of written bytes {} is larger than the maximum value", c); } } From 9b4ceec60e039433a4409ca2f89af97e1c3b581d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 4 Nov 2019 11:17:40 +0100 Subject: [PATCH 1274/3747] update comment re: not using higher mir-opt-level --- tests/compiletest.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/tests/compiletest.rs b/tests/compiletest.rs index 00fd039ad7e86..bc1ba2eda5687 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -66,9 +66,8 @@ fn compile_fail(path: &str, target: &str, opt: bool) { let mut flags = Vec::new(); if opt { - // Optimizing too aggressivley makes UB detection harder, but test at least - // the default value. - // FIXME: Opt level 3 ICEs during stack trace generation. + // FIXME: Opt level 2 ICEs during stack trace generation. + // See https://github.com/rust-lang/rust/issues/66077. flags.push("-Zmir-opt-level=1".to_owned()); } From 56c5e53553859d153009f76d2da15bf2d0e3d037 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Mon, 4 Nov 2019 09:38:21 -0500 Subject: [PATCH 1275/3747] Handle host's `usize` correctly --- src/helpers.rs | 14 ++++++++++++++ src/shims/fs.rs | 38 ++++++++++++++++++++++++-------------- 2 files changed, 38 insertions(+), 14 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index dd0530cf48b4e..c02ba3f1fab39 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -1,5 +1,6 @@ use std::{mem, iter}; use std::ffi::{OsStr, OsString}; +use std::convert::TryFrom; use rustc::hir::def_id::{DefId, CRATE_DEF_INDEX}; use rustc::mir; @@ -459,3 +460,16 @@ fn bytes_to_os_str<'tcx, 'a>(bytes: &'a[u8]) -> InterpResult<'tcx, &'a OsStr> { .map_err(|_| err_unsup_format!("{:?} is not a valid utf-8 string", bytes))?; Ok(&OsStr::new(s)) } + +pub fn try_into_host_usize(i: impl Into) -> Option { + let i: u128 = i.into(); + if i > usize::max_value() as u128 { + None + } else { + Some(i as usize) + } +} + +pub fn try_from_host_usize>(i: usize) -> Option { + T::try_from(i as u128).ok() +} diff --git a/src/shims/fs.rs b/src/shims/fs.rs index 66e24eb8b0924..910e3907695c4 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -178,16 +178,21 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let mut bytes = vec![0; count as usize]; let result = handle.file.read(&mut bytes); - if let Ok(c) = result { - // Check that we read less than `i64::MAX` bytes. - if (c as u64) > (i64::max_value() as u64) { - throw_unsup_format!("Number of read bytes {} is larger than the maximum value", c); + match result { + Ok(c) => { + if let Some(read_bytes) = helpers::try_from_host_usize::(c) { + // If reading to `bytes` did not fail, we write those bytes to the buffer. + this.memory.write_bytes(buf, bytes)?; + Ok(read_bytes) + } else { + throw_unsup_format!("Number of read bytes {} cannot be transformed to i64", c); + } + }, + Err(e) => { + this.set_last_error_from_io_error(e)?; + Ok(-1) } - // If reading to `bytes` did not fail, we write those bytes to the buffer. - this.memory.write_bytes(buf, bytes)? } - - this.try_unwrap_io_result(result.map(|c| c as i64)) } else { this.handle_not_found() } @@ -215,14 +220,19 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let bytes = this.memory.read_bytes(buf, Size::from_bytes(count))?; let result = handle.file.write(&bytes); - if let Ok(c) = result { - // Check that we wrote less than `i64::MAX` bytes. - if (c as u64) > (i64::max_value() as u64) { - throw_unsup_format!("Number of written bytes {} is larger than the maximum value", c); + match result { + Ok(c) => { + if let Some(written_bytes) = helpers::try_from_host_usize::(c) { + Ok(written_bytes) + } else { + throw_unsup_format!("Number of written bytes {} cannot be transformed to i64", c); + } + }, + Err(e) => { + this.set_last_error_from_io_error(e)?; + Ok(-1) } } - - this.try_unwrap_io_result(result.map(|c| c as i64)) } else { this.handle_not_found() } From 99282efc86974f32dd93e6504b49ed9b717caea4 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 5 Nov 2019 11:05:02 +0100 Subject: [PATCH 1276/3747] add an interesting run-pass stacked borrows example --- .../stacked-borrows/stacked-borrows.rs | 29 +++++++++++++++++++ .../stacked-borrows/stacked-borrows.stderr | 7 +++++ 2 files changed, 36 insertions(+) create mode 100644 tests/run-pass/stacked-borrows/stacked-borrows.stderr diff --git a/tests/run-pass/stacked-borrows/stacked-borrows.rs b/tests/run-pass/stacked-borrows/stacked-borrows.rs index afa364e856438..fe6a9a54d4f34 100644 --- a/tests/run-pass/stacked-borrows/stacked-borrows.rs +++ b/tests/run-pass/stacked-borrows/stacked-borrows.rs @@ -11,6 +11,7 @@ fn main() { direct_mut_to_const_raw(); two_raw(); shr_and_raw(); + disjoint_mutable_subborrows(); } // Make sure that reading from an `&mut` does, like reborrowing to `&`, @@ -138,3 +139,31 @@ fn shr_and_raw() { /* unsafe { *y2 += 1; // TODO: Once this works, add compile-fail test that tries to read from y1 again. } */ } + +fn disjoint_mutable_subborrows() { + struct Foo { + a: String, + b: Vec, + } + + unsafe fn borrow_field_a<'a>(this:*mut Foo) -> &'a mut String { + &mut (*this).a + } + + unsafe fn borrow_field_b<'a>(this:*mut Foo) -> &'a mut Vec { + &mut (*this).b + } + + let mut foo = Foo { + a: "hello".into(), + b: vec![0,1,2], + }; + + let ptr = &mut foo as *mut Foo; + + let a = unsafe{ borrow_field_a(ptr) }; + let b = unsafe{ borrow_field_b(ptr) }; + b.push(4); + a.push_str(" world"); + dbg!(a,b); +} diff --git a/tests/run-pass/stacked-borrows/stacked-borrows.stderr b/tests/run-pass/stacked-borrows/stacked-borrows.stderr new file mode 100644 index 0000000000000..4493d45ae157a --- /dev/null +++ b/tests/run-pass/stacked-borrows/stacked-borrows.stderr @@ -0,0 +1,7 @@ +[$DIR/stacked-borrows.rs:168] a = "hello world" +[$DIR/stacked-borrows.rs:168] b = [ + 0, + 1, + 2, + 4, +] From f4fb330c67f41af06ae275aafeba2a9bb69d1660 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 4 Nov 2019 13:28:18 +0100 Subject: [PATCH 1277/3747] test offset_from --- tests/run-pass/ptr_offset_from.rs | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 tests/run-pass/ptr_offset_from.rs diff --git a/tests/run-pass/ptr_offset_from.rs b/tests/run-pass/ptr_offset_from.rs new file mode 100644 index 0000000000000..92eb3f6e46e3c --- /dev/null +++ b/tests/run-pass/ptr_offset_from.rs @@ -0,0 +1,29 @@ +#![feature(ptr_offset_from)] + +fn test_raw() { unsafe { + let buf = [0u32; 4]; + + let x = buf.as_ptr() as *const u8; + let y = x.offset(12); + + assert_eq!(y.offset_from(x), 12); + assert_eq!(x.offset_from(y), -12); + assert_eq!((y as *const u32).offset_from(x as *const u32), 12/4); + assert_eq!((x as *const u32).offset_from(y as *const u32), -12/4); + + let x = (((x as usize) * 2) / 2) as *const u8; + assert_eq!(y.offset_from(x), 12); + assert_eq!(x.offset_from(y), -12); +} } + +// This also internally uses offset_from. +fn test_vec_into_iter() { + let v = Vec::::new(); + let i = v.into_iter(); + i.size_hint(); +} + +fn main() { + test_raw(); + test_vec_into_iter(); +} From 3847334e725aec9f963afa20520631bf6566a244 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 5 Nov 2019 20:17:45 +0100 Subject: [PATCH 1278/3747] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 1a58c80128a5a..5511ef0ad62f3 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -6c1b220fd747bf244f04b380e4d4ae005068f706 +3a1b3b30c6cdd674049b144a3ced7b711de962b2 From f910ea135c0cbfec4dd10adf2a79163e1b8935f3 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Tue, 5 Nov 2019 16:47:24 -0500 Subject: [PATCH 1279/3747] Avoid using `as` cast --- src/shims/fs.rs | 25 ++++++++++--------------- 1 file changed, 10 insertions(+), 15 deletions(-) diff --git a/src/shims/fs.rs b/src/shims/fs.rs index 910e3907695c4..3fccbaa33f052 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -174,19 +174,19 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let buf = this.read_scalar(buf_op)?.not_undef()?; if let Some(handle) = this.machine.file_handler.handles.get_mut(&fd) { + let count = helpers::try_into_host_usize(count) + .ok_or_else(|| err_unsup_format!("Program tries to read into buffer too big for this host platform"))?; // We want to read at most `count` bytes - let mut bytes = vec![0; count as usize]; + let mut bytes = vec![0; count]; let result = handle.file.read(&mut bytes); match result { Ok(c) => { - if let Some(read_bytes) = helpers::try_from_host_usize::(c) { - // If reading to `bytes` did not fail, we write those bytes to the buffer. - this.memory.write_bytes(buf, bytes)?; - Ok(read_bytes) - } else { - throw_unsup_format!("Number of read bytes {} cannot be transformed to i64", c); - } + let read_bytes = helpers::try_from_host_usize::(c) + .ok_or_else(|| err_unsup_format!("Number of read bytes {} cannot be transformed to i64", c))?; + // If reading to `bytes` did not fail, we write those bytes to the buffer. + this.memory.write_bytes(buf, bytes)?; + Ok(read_bytes) }, Err(e) => { this.set_last_error_from_io_error(e)?; @@ -221,13 +221,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let result = handle.file.write(&bytes); match result { - Ok(c) => { - if let Some(written_bytes) = helpers::try_from_host_usize::(c) { - Ok(written_bytes) - } else { - throw_unsup_format!("Number of written bytes {} cannot be transformed to i64", c); - } - }, + Ok(c) => helpers::try_from_host_usize::(c) + .ok_or_else(|| err_unsup_format!("Number of written bytes {} cannot be transformed to i64", c).into()), Err(e) => { this.set_last_error_from_io_error(e)?; Ok(-1) From 2661295cdffdf36f6f8593a249ed5733472391d2 Mon Sep 17 00:00:00 2001 From: YOUNGSUK KIM Date: Tue, 5 Nov 2019 21:56:18 -0500 Subject: [PATCH 1280/3747] error code E0080 is no longer printed with MIRI error message --- src/eval.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/eval.rs b/src/eval.rs index b87d735ce525d..cfe856ec3a4d4 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -9,7 +9,7 @@ use rustc::ty::{self, TyCtxt}; use syntax::source_map::DUMMY_SP; use crate::{ - struct_error, EnvVars, Evaluator, FnVal, HelpersEvalContextExt, InterpCx, InterpError, + EnvVars, Evaluator, FnVal, HelpersEvalContextExt, InterpCx, InterpError, InterpResult, MemoryExtra, MiriMemoryKind, Pointer, Scalar, StackPopCleanup, Tag, TlsEvalContextExt, }; @@ -221,7 +221,10 @@ pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) { }; let msg = format!("Miri evaluation error: {}", msg); - let mut err = struct_error(ecx.tcx.tcx.at(span), msg.as_str()); + let mut err = { + let new_tcx = ecx.tcx.tcx.at(span); + new_tcx.sess.struct_span_err(new_tcx.span, msg.as_str()) + }; let frames = ecx.generate_stacktrace(None); err.span_label(span, msg); // We iterate with indices because we need to look at the next frame (the caller). From c4f1d3f4886d1bcb144aa5b929ca76e5d2804435 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 4 Nov 2019 12:11:31 +0100 Subject: [PATCH 1281/3747] test that 0 cannot be offset-inbounds by 0 --- tests/compile-fail/ptr_offset_0_plus_0.rs | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 tests/compile-fail/ptr_offset_0_plus_0.rs diff --git a/tests/compile-fail/ptr_offset_0_plus_0.rs b/tests/compile-fail/ptr_offset_0_plus_0.rs new file mode 100644 index 0000000000000..4abcc5c1b809d --- /dev/null +++ b/tests/compile-fail/ptr_offset_0_plus_0.rs @@ -0,0 +1,7 @@ +// error-pattern: outside bounds of allocation + +fn main() { + let x = 0 as *mut i32; + let _x = x.wrapping_offset(8); // ok, this has no inbounds tag + let _x = unsafe { x.offset(0) }; // UB despite offset 0, NULL is never inbounds +} From 9eb4e00f6fe0f720d9bc7116bf89c20acd35f00b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 4 Nov 2019 12:13:51 +0100 Subject: [PATCH 1282/3747] refactor ptr_offset_inbounds: it can be reduced to check_ptr_access, after all! --- src/operator.rs | 50 ++++++++++++++----------------------------------- 1 file changed, 14 insertions(+), 36 deletions(-) diff --git a/src/operator.rs b/src/operator.rs index a60bc8c0b13d1..0c83b5bed93b7 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -1,16 +1,11 @@ use std::convert::TryFrom; -use rustc::ty::{Ty, layout::LayoutOf}; +use rustc::ty::{Ty, layout::{Size, Align, LayoutOf}}; use rustc::mir; use crate::*; pub trait EvalContextExt<'tcx> { - fn pointer_inbounds( - &self, - ptr: Pointer - ) -> InterpResult<'tcx>; - fn binary_ptr_op( &self, bin_op: mir::BinOp, @@ -33,13 +28,6 @@ pub trait EvalContextExt<'tcx> { } impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { - /// Test if the pointer is in-bounds of a live allocation. - #[inline] - fn pointer_inbounds(&self, ptr: Pointer) -> InterpResult<'tcx> { - let (size, _align) = self.memory.get_size_and_align(ptr.alloc_id, AllocCheck::Live)?; - ptr.check_inbounds_alloc(size, CheckInAllocMsg::InboundsTest) - } - fn binary_ptr_op( &self, bin_op: mir::BinOp, @@ -110,9 +98,8 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { } /// Raises an error if the offset moves the pointer outside of its allocation. - /// We consider ZSTs their own huge allocation that doesn't overlap with anything (and nothing - /// moves in there because the size is 0). We also consider the NULL pointer its own separate - /// allocation, and all the remaining integers pointers their own allocation. + /// For integers, we consider each of them their own tiny allocation of size 0, + /// so offset-by-0 is okay for them -- except for NULL, which we rule out entirely. fn pointer_offset_inbounds( &self, ptr: Scalar, @@ -123,25 +110,16 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { let offset = offset .checked_mul(pointee_size) .ok_or_else(|| err_panic!(Overflow(mir::BinOp::Mul)))?; - // Now let's see what kind of pointer this is. - let ptr = if offset == 0 { - match ptr { - Scalar::Ptr(ptr) => ptr, - Scalar::Raw { .. } => { - // Offset 0 on an integer. We accept that, pretending there is - // a little zero-sized allocation here. - return Ok(ptr); - } - } - } else { - // Offset > 0. We *require* a pointer. - self.force_ptr(ptr)? - }; - // Both old and new pointer must be in-bounds of a *live* allocation. - // (Of the same allocation, but that part is trivial with our representation.) - self.pointer_inbounds(ptr)?; - let ptr = ptr.signed_offset(offset, self)?; - self.pointer_inbounds(ptr)?; - Ok(Scalar::Ptr(ptr)) + // We do this forst, to rule out overflows. + let offset_ptr = ptr.ptr_signed_offset(offset, self)?; + // What we need to check is that starting at `ptr`, + // we could do an access of size `offset`. Alignment does not matter. + self.memory.check_ptr_access( + ptr, + Size::from_bytes(u64::try_from(offset).unwrap()), + Align::from_bytes(1).unwrap(), + )?; + // That's it! + Ok(offset_ptr) } } From 1f8cb476eabe3b809907890e69fbf3003a8bb8dc Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 4 Nov 2019 12:17:25 +0100 Subject: [PATCH 1283/3747] fix test erorr msg --- tests/compile-fail/ptr_offset_0_plus_0.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/compile-fail/ptr_offset_0_plus_0.rs b/tests/compile-fail/ptr_offset_0_plus_0.rs index 4abcc5c1b809d..96a9fb8402f68 100644 --- a/tests/compile-fail/ptr_offset_0_plus_0.rs +++ b/tests/compile-fail/ptr_offset_0_plus_0.rs @@ -1,4 +1,4 @@ -// error-pattern: outside bounds of allocation +// error-pattern: invalid use of NULL pointer fn main() { let x = 0 as *mut i32; From 4b9a7d8cffc3aefff5d660f07c90fc6f183c4357 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 4 Nov 2019 12:29:15 +0100 Subject: [PATCH 1284/3747] fix error message details --- src/operator.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/operator.rs b/src/operator.rs index 0c83b5bed93b7..dea5f1539b3e2 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -1,6 +1,6 @@ use std::convert::TryFrom; -use rustc::ty::{Ty, layout::{Size, Align, LayoutOf}}; +use rustc::ty::{Ty, layout::{Size, LayoutOf}}; use rustc::mir; use crate::*; @@ -110,14 +110,15 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { let offset = offset .checked_mul(pointee_size) .ok_or_else(|| err_panic!(Overflow(mir::BinOp::Mul)))?; - // We do this forst, to rule out overflows. + // We do this first, to rule out overflows. let offset_ptr = ptr.ptr_signed_offset(offset, self)?; // What we need to check is that starting at `ptr`, // we could do an access of size `offset`. Alignment does not matter. - self.memory.check_ptr_access( + self.memory.check_ptr_access_align( ptr, Size::from_bytes(u64::try_from(offset).unwrap()), - Align::from_bytes(1).unwrap(), + None, + CheckInAllocMsg::InboundsTest, )?; // That's it! Ok(offset_ptr) From b2a2f4dd152787cf506e75ec936c42b0b84a599f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 6 Nov 2019 09:25:02 +0100 Subject: [PATCH 1285/3747] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 5511ef0ad62f3..6b17a5dbeb5ef 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -3a1b3b30c6cdd674049b144a3ced7b711de962b2 +e4931eaaa3d95189b30e90d3af9f0db17c41bbb0 From 8b0c14f9f6ada1f042b3a734308bb60bdf4ac65e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 6 Nov 2019 10:51:06 +0100 Subject: [PATCH 1286/3747] ptr_offset: handle negative offsets --- src/operator.rs | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/operator.rs b/src/operator.rs index dea5f1539b3e2..2a90d3e12f4c0 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -112,11 +112,18 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { .ok_or_else(|| err_panic!(Overflow(mir::BinOp::Mul)))?; // We do this first, to rule out overflows. let offset_ptr = ptr.ptr_signed_offset(offset, self)?; - // What we need to check is that starting at `ptr`, - // we could do an access of size `offset`. Alignment does not matter. + // What we need to check is that starting at `min(ptr, offset_ptr)`, + // we could do an access of size `abs(offset)`. Alignment does not matter. + let (min_ptr, abs_offset) = if offset >= 0 { + (ptr, u64::try_from(offset).unwrap()) + } else { + // Negative offset. + // If the negation overflows, the result will be negative so the try_from will fail. + (offset_ptr, u64::try_from(-offset).unwrap()) + }; self.memory.check_ptr_access_align( - ptr, - Size::from_bytes(u64::try_from(offset).unwrap()), + min_ptr, + Size::from_bytes(abs_offset), None, CheckInAllocMsg::InboundsTest, )?; From e5675ab0fc03d6f2960b0ec1a8b18bdc1d42b283 Mon Sep 17 00:00:00 2001 From: YOUNGSUK KIM Date: Wed, 6 Nov 2019 08:25:00 -0500 Subject: [PATCH 1287/3747] follow-up to review --- src/eval.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/eval.rs b/src/eval.rs index cfe856ec3a4d4..b09fb5918c874 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -221,10 +221,7 @@ pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) { }; let msg = format!("Miri evaluation error: {}", msg); - let mut err = { - let new_tcx = ecx.tcx.tcx.at(span); - new_tcx.sess.struct_span_err(new_tcx.span, msg.as_str()) - }; + let mut err = ecx.tcx.sess.struct_span_err(span, msg.as_str()); let frames = ecx.generate_stacktrace(None); err.span_label(span, msg); // We iterate with indices because we need to look at the next frame (the caller). From 8b1630cb3b06d4d2d2a8a38d08afa368dcefa0c4 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 7 Nov 2019 08:55:59 +0100 Subject: [PATCH 1288/3747] tweak and slightly extend box-box-trait test --- tests/run-pass/box_box_trait.rs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/tests/run-pass/box_box_trait.rs b/tests/run-pass/box_box_trait.rs index e7620cd42f700..5ce0e8f5957be 100644 --- a/tests/run-pass/box_box_trait.rs +++ b/tests/run-pass/box_box_trait.rs @@ -1,5 +1,3 @@ -#![feature(box_syntax)] - struct DroppableStruct; static mut DROPPED: bool = false; @@ -13,7 +11,6 @@ impl Drop for DroppableStruct { trait MyTrait { fn dummy(&self) { } } impl MyTrait for Box {} -#[allow(dead_code)] struct Whatever { w: Box } impl Whatever { @@ -24,8 +21,9 @@ impl Whatever { fn main() { { - let f: Box<_> = box DroppableStruct; - let _a = Whatever::new(box f as Box); + let f = Box::new(DroppableStruct); + let a = Whatever::new(Box::new(f) as Box); + a.w.dummy(); } assert!(unsafe { DROPPED }); } From c77b2826953b126f3dfe752ef461f85d5a24d5a3 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 7 Nov 2019 08:56:11 +0100 Subject: [PATCH 1289/3747] rename call_drop_ tests to drop_ --- .../{call_drop_on_array_elements.rs => drop_on_array_elements.rs} | 0 ...at_ptr_array_elements.rs => drop_on_fat_ptr_array_elements.rs} | 0 ...rop_on_zst_array_elements.rs => drop_on_zst_array_elements.rs} | 0 ...ll_drop_through_owned_slice.rs => drop_through_owned_slice.rs} | 0 ..._drop_through_trait_object.rs => drop_through_trait_object.rs} | 0 ...through_trait_object_rc.rs => drop_through_trait_object_rc.rs} | 0 6 files changed, 0 insertions(+), 0 deletions(-) rename tests/run-pass/{call_drop_on_array_elements.rs => drop_on_array_elements.rs} (100%) rename tests/run-pass/{call_drop_on_fat_ptr_array_elements.rs => drop_on_fat_ptr_array_elements.rs} (100%) rename tests/run-pass/{call_drop_on_zst_array_elements.rs => drop_on_zst_array_elements.rs} (100%) rename tests/run-pass/{call_drop_through_owned_slice.rs => drop_through_owned_slice.rs} (100%) rename tests/run-pass/{call_drop_through_trait_object.rs => drop_through_trait_object.rs} (100%) rename tests/run-pass/{call_drop_through_trait_object_rc.rs => drop_through_trait_object_rc.rs} (100%) diff --git a/tests/run-pass/call_drop_on_array_elements.rs b/tests/run-pass/drop_on_array_elements.rs similarity index 100% rename from tests/run-pass/call_drop_on_array_elements.rs rename to tests/run-pass/drop_on_array_elements.rs diff --git a/tests/run-pass/call_drop_on_fat_ptr_array_elements.rs b/tests/run-pass/drop_on_fat_ptr_array_elements.rs similarity index 100% rename from tests/run-pass/call_drop_on_fat_ptr_array_elements.rs rename to tests/run-pass/drop_on_fat_ptr_array_elements.rs diff --git a/tests/run-pass/call_drop_on_zst_array_elements.rs b/tests/run-pass/drop_on_zst_array_elements.rs similarity index 100% rename from tests/run-pass/call_drop_on_zst_array_elements.rs rename to tests/run-pass/drop_on_zst_array_elements.rs diff --git a/tests/run-pass/call_drop_through_owned_slice.rs b/tests/run-pass/drop_through_owned_slice.rs similarity index 100% rename from tests/run-pass/call_drop_through_owned_slice.rs rename to tests/run-pass/drop_through_owned_slice.rs diff --git a/tests/run-pass/call_drop_through_trait_object.rs b/tests/run-pass/drop_through_trait_object.rs similarity index 100% rename from tests/run-pass/call_drop_through_trait_object.rs rename to tests/run-pass/drop_through_trait_object.rs diff --git a/tests/run-pass/call_drop_through_trait_object_rc.rs b/tests/run-pass/drop_through_trait_object_rc.rs similarity index 100% rename from tests/run-pass/call_drop_through_trait_object_rc.rs rename to tests/run-pass/drop_through_trait_object_rc.rs From 04c12952ca11b286536ac2826446f5f686b4af73 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 7 Nov 2019 09:05:11 +0100 Subject: [PATCH 1290/3747] centralize and expand dyn-trait (method receiver) tests --- tests/run-pass/box_box_trait.rs | 29 ------- tests/run-pass/dyn-traits.rs | 140 ++++++++++++++++++++++++++++++++ tests/run-pass/traits.rs | 30 ------- 3 files changed, 140 insertions(+), 59 deletions(-) delete mode 100644 tests/run-pass/box_box_trait.rs create mode 100644 tests/run-pass/dyn-traits.rs delete mode 100644 tests/run-pass/traits.rs diff --git a/tests/run-pass/box_box_trait.rs b/tests/run-pass/box_box_trait.rs deleted file mode 100644 index 5ce0e8f5957be..0000000000000 --- a/tests/run-pass/box_box_trait.rs +++ /dev/null @@ -1,29 +0,0 @@ -struct DroppableStruct; - -static mut DROPPED: bool = false; - -impl Drop for DroppableStruct { - fn drop(&mut self) { - unsafe { DROPPED = true; } - } -} - -trait MyTrait { fn dummy(&self) { } } -impl MyTrait for Box {} - -struct Whatever { w: Box } - -impl Whatever { - fn new(w: Box) -> Whatever { - Whatever { w: w } - } -} - -fn main() { - { - let f = Box::new(DroppableStruct); - let a = Whatever::new(Box::new(f) as Box); - a.w.dummy(); - } - assert!(unsafe { DROPPED }); -} diff --git a/tests/run-pass/dyn-traits.rs b/tests/run-pass/dyn-traits.rs new file mode 100644 index 0000000000000..bcff3e0b76dcc --- /dev/null +++ b/tests/run-pass/dyn-traits.rs @@ -0,0 +1,140 @@ +#![feature(unsized_locals)] + +fn ref_dyn() { + struct Struct(i32); + + trait Trait { + fn method(&self); + } + + impl Trait for Struct { + fn method(&self) { + assert_eq!(self.0, 42); + } + } + + struct Foo(T); + + let y: &dyn Trait = &Struct(42); + y.method(); + let x: Foo = Foo(Struct(42)); + let y: &Foo = &x; + y.0.method(); +} + +fn box_dyn() { + let x: Box i32> = Box::new(|x| x * 2); + assert_eq!(x(21), 42); + let mut i = 5; + { + let mut x: Box = Box::new(|| i *= 2); + x(); x(); + } + assert_eq!(i, 20); +} + +fn box_box_trait() { + struct DroppableStruct; + + static mut DROPPED: bool = false; + + impl Drop for DroppableStruct { + fn drop(&mut self) { + unsafe { DROPPED = true; } + } + } + + trait MyTrait { fn dummy(&self) { } } + impl MyTrait for Box {} + + struct Whatever { w: Box } + + impl Whatever { + fn new(w: Box) -> Whatever { + Whatever { w: w } + } + } + + { + let f = Box::new(DroppableStruct); + let a = Whatever::new(Box::new(f) as Box); + a.w.dummy(); + } + assert!(unsafe { DROPPED }); +} + +fn unsized_dyn() { + pub trait Foo { + fn foo(self) -> String; + } + + struct A; + + impl Foo for A { + fn foo(self) -> String { + format!("hello") + } + } + + let x = *(Box::new(A) as Box); + assert_eq!(x.foo(), format!("hello")); + + // I'm not sure whether we want this to work + let x = Box::new(A) as Box; + assert_eq!(x.foo(), format!("hello")); +} + +fn unsized_dyn_autoderef() { + pub trait Foo { + fn foo(self) -> String; + } + + impl Foo for [char] { + fn foo(self) -> String { + self.iter().collect() + } + } + + impl Foo for str { + fn foo(self) -> String { + self.to_owned() + } + } + + impl Foo for dyn FnMut() -> String { + fn foo(mut self) -> String { + self() + } + } + + let x = *(Box::new(['h', 'e', 'l', 'l', 'o']) as Box<[char]>); + assert_eq!(&x.foo() as &str, "hello"); + + let x = Box::new(['h', 'e', 'l', 'l', 'o']) as Box<[char]>; + assert_eq!(&x.foo() as &str, "hello"); + + let x = "hello".to_owned().into_boxed_str(); + assert_eq!(&x.foo() as &str, "hello"); + + let x = *("hello".to_owned().into_boxed_str()); + assert_eq!(&x.foo() as &str, "hello"); + + let x = "hello".to_owned().into_boxed_str(); + assert_eq!(&x.foo() as &str, "hello"); + + let x = *(Box::new(|| "hello".to_owned()) as Box String>); + assert_eq!(&x.foo() as &str, "hello"); + + let x = Box::new(|| "hello".to_owned()) as Box String>; + assert_eq!(&x.foo() as &str, "hello"); +} + +fn main() { + ref_dyn(); + box_dyn(); + box_box_trait(); + + // "exotic" receivers + unsized_dyn(); + unsized_dyn_autoderef(); +} diff --git a/tests/run-pass/traits.rs b/tests/run-pass/traits.rs deleted file mode 100644 index 03d2db400f013..0000000000000 --- a/tests/run-pass/traits.rs +++ /dev/null @@ -1,30 +0,0 @@ -struct Struct(i32); - -trait Trait { - fn method(&self); -} - -impl Trait for Struct { - fn method(&self) { - assert_eq!(self.0, 42); - } -} - -struct Foo(T); - -fn main() { - let y: &dyn Trait = &Struct(42); - y.method(); - let x: Foo = Foo(Struct(42)); - let y: &Foo = &x; - y.0.method(); - - let x: Box i32> = Box::new(|x| x * 2); - assert_eq!(x(21), 42); - let mut i = 5; - { - let mut x: Box = Box::new(|| i *= 2); - x(); x(); - } - assert_eq!(i, 20); -} From b7a8ce1be070c095fafc881e6deb2c1ed87943dd Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 7 Nov 2019 09:14:23 +0100 Subject: [PATCH 1291/3747] move blosure tests to closures file; test Box a bit more --- tests/run-pass/closures.rs | 16 ++++++++++++++-- tests/run-pass/dyn-traits.rs | 22 +++++++++------------- 2 files changed, 23 insertions(+), 15 deletions(-) diff --git a/tests/run-pass/closures.rs b/tests/run-pass/closures.rs index eb8d8f0d5b987..5e2e0f87bdaff 100644 --- a/tests/run-pass/closures.rs +++ b/tests/run-pass/closures.rs @@ -40,10 +40,21 @@ fn fn_once_closure_with_multiple_args() -> i64 { } } -fn boxed(f: Box i32>) -> i32 { +fn boxed_fn_once(f: Box i32>) -> i32 { f() } +fn box_dyn() { + let x: Box i32> = Box::new(|x| x * 2); + assert_eq!(x(21), 42); + let mut i = 5; + { + let mut x: Box = Box::new(|| i *= 2); + x(); x(); + } + assert_eq!(i, 20); +} + fn fn_item_as_closure_trait_object() { fn foo() {} let f: &dyn Fn() = &foo; @@ -96,8 +107,9 @@ fn main() { assert_eq!(crazy_closure(), (84, 10, 10)); assert_eq!(closure_arg_adjustment_problem(), 3); assert_eq!(fn_once_closure_with_multiple_args(), 6); - assert_eq!(boxed(Box::new({let x = 13; move || x})), 13); + assert_eq!(boxed_fn_once(Box::new({let x = 13; move || x})), 13); + box_dyn(); fn_item_as_closure_trait_object(); fn_item_with_args_as_closure_trait_object(); fn_item_with_multiple_args_as_closure_trait_object(); diff --git a/tests/run-pass/dyn-traits.rs b/tests/run-pass/dyn-traits.rs index bcff3e0b76dcc..f732c7bfaf1c9 100644 --- a/tests/run-pass/dyn-traits.rs +++ b/tests/run-pass/dyn-traits.rs @@ -1,6 +1,6 @@ #![feature(unsized_locals)] -fn ref_dyn() { +fn ref_box_dyn() { struct Struct(i32); trait Trait { @@ -17,22 +17,19 @@ fn ref_dyn() { let y: &dyn Trait = &Struct(42); y.method(); + let x: Foo = Foo(Struct(42)); let y: &Foo = &x; y.0.method(); -} -fn box_dyn() { - let x: Box i32> = Box::new(|x| x * 2); - assert_eq!(x(21), 42); - let mut i = 5; - { - let mut x: Box = Box::new(|| i *= 2); - x(); x(); - } - assert_eq!(i, 20); + let y: Box = Box::new(Struct(42)); + y.method(); + + let y = &y; + y.method(); } + fn box_box_trait() { struct DroppableStruct; @@ -130,8 +127,7 @@ fn unsized_dyn_autoderef() { } fn main() { - ref_dyn(); - box_dyn(); + ref_box_dyn(); box_box_trait(); // "exotic" receivers From 57dec5c79158a494905bfd5e6e2473783da177c8 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 7 Nov 2019 09:17:40 +0100 Subject: [PATCH 1292/3747] also test Box receiver --- tests/run-pass/dyn-traits.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tests/run-pass/dyn-traits.rs b/tests/run-pass/dyn-traits.rs index f732c7bfaf1c9..33d1f4fc1cf0c 100644 --- a/tests/run-pass/dyn-traits.rs +++ b/tests/run-pass/dyn-traits.rs @@ -5,12 +5,18 @@ fn ref_box_dyn() { trait Trait { fn method(&self); + + fn box_method(self: Box); } impl Trait for Struct { fn method(&self) { assert_eq!(self.0, 42); } + + fn box_method(self: Box) { + assert_eq!(self.0, 7); + } } struct Foo(T); @@ -27,6 +33,9 @@ fn ref_box_dyn() { let y = &y; y.method(); + + let y: Box = Box::new(Struct(7)); + y.box_method(); } From 428fc531d857937bd32e7d86757f5f033915d7b0 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 7 Nov 2019 09:44:00 +0100 Subject: [PATCH 1293/3747] silence a lint that catches the bug statically --- rust-version | 2 +- tests/compile-fail/validity/invalid_wide_raw.rs | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 6b17a5dbeb5ef..41001febbff4f 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -e4931eaaa3d95189b30e90d3af9f0db17c41bbb0 +7a76fe76f756895b8cda1e10398f2268656a2e0f diff --git a/tests/compile-fail/validity/invalid_wide_raw.rs b/tests/compile-fail/validity/invalid_wide_raw.rs index ec14f6988b24a..8f1e184ed22e5 100644 --- a/tests/compile-fail/validity/invalid_wide_raw.rs +++ b/tests/compile-fail/validity/invalid_wide_raw.rs @@ -1,3 +1,5 @@ +#![allow(invalid_value)] + fn main() { trait T { } #[derive(Debug)] From 4bbaa72dc92ca385b2595f6a072b96f36fa4a1ef Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Thu, 7 Nov 2019 20:50:16 +0100 Subject: [PATCH 1294/3747] Use TryFrom instead --- src/helpers.rs | 14 -------------- src/shims/fs.rs | 19 +++++++++++-------- 2 files changed, 11 insertions(+), 22 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index c02ba3f1fab39..dd0530cf48b4e 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -1,6 +1,5 @@ use std::{mem, iter}; use std::ffi::{OsStr, OsString}; -use std::convert::TryFrom; use rustc::hir::def_id::{DefId, CRATE_DEF_INDEX}; use rustc::mir; @@ -460,16 +459,3 @@ fn bytes_to_os_str<'tcx, 'a>(bytes: &'a[u8]) -> InterpResult<'tcx, &'a OsStr> { .map_err(|_| err_unsup_format!("{:?} is not a valid utf-8 string", bytes))?; Ok(&OsStr::new(s)) } - -pub fn try_into_host_usize(i: impl Into) -> Option { - let i: u128 = i.into(); - if i > usize::max_value() as u128 { - None - } else { - Some(i as usize) - } -} - -pub fn try_from_host_usize>(i: usize) -> Option { - T::try_from(i as u128).ok() -} diff --git a/src/shims/fs.rs b/src/shims/fs.rs index 3fccbaa33f052..8b2452d33d476 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -1,6 +1,7 @@ use std::collections::HashMap; use std::fs::{remove_file, File, OpenOptions}; use std::io::{Read, Write}; +use std::convert::TryFrom; use rustc::ty::layout::Size; @@ -174,16 +175,18 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let buf = this.read_scalar(buf_op)?.not_undef()?; if let Some(handle) = this.machine.file_handler.handles.get_mut(&fd) { - let count = helpers::try_into_host_usize(count) - .ok_or_else(|| err_unsup_format!("Program tries to read into buffer too big for this host platform"))?; - // We want to read at most `count` bytes - let mut bytes = vec![0; count]; + let count = isize::try_from(count) + .map_err(|_| err_unsup_format!("Program tries to read into buffer too big for this host platform"))?; + // We want to read at most `count` bytes. We are sure that `count` is not negative + // because it was a target's `usize`. Also we are sure that its smaller than + // `usize::max_value()` because it is a host's `isize`. + let mut bytes = vec![0; count as usize]; let result = handle.file.read(&mut bytes); match result { Ok(c) => { - let read_bytes = helpers::try_from_host_usize::(c) - .ok_or_else(|| err_unsup_format!("Number of read bytes {} cannot be transformed to i64", c))?; + let read_bytes = i64::try_from(c) + .map_err(|_| err_unsup_format!("Number of read bytes {} cannot be transformed to i64", c))?; // If reading to `bytes` did not fail, we write those bytes to the buffer. this.memory.write_bytes(buf, bytes)?; Ok(read_bytes) @@ -221,8 +224,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let result = handle.file.write(&bytes); match result { - Ok(c) => helpers::try_from_host_usize::(c) - .ok_or_else(|| err_unsup_format!("Number of written bytes {} cannot be transformed to i64", c).into()), + Ok(c) => i64::try_from(c) + .map_err(|_| err_unsup_format!("Number of written bytes {} cannot be transformed to i64", c).into()), Err(e) => { this.set_last_error_from_io_error(e)?; Ok(-1) From a90ac3b0ecc1ca315512568d2e88191e8b468b2b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 8 Nov 2019 09:16:44 +0100 Subject: [PATCH 1295/3747] disable num_cpus on Windows for now --- test-cargo-miri/tests/test.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/test-cargo-miri/tests/test.rs b/test-cargo-miri/tests/test.rs index cfbe3f6d7fb66..904bbbc6cd46b 100644 --- a/test-cargo-miri/tests/test.rs +++ b/test-cargo-miri/tests/test.rs @@ -39,5 +39,6 @@ fn entropy_rng() { #[test] fn num_cpus() { + #[cfg(not(windows))] // FIXME: enable on Windows again once https://github.com/seanmonstar/num_cpus/pull/90 gets released. assert_eq!(num_cpus::get(), 1); } From bcbc6664932437184bd33ba8cf29491bec463f34 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 8 Nov 2019 10:08:57 +0100 Subject: [PATCH 1296/3747] let's see if newer rustc helps --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 41001febbff4f..1377ee94dfc30 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -7a76fe76f756895b8cda1e10398f2268656a2e0f +c34472b77084c9f76f872871aeab121daf81fb99 From 4c25cf0a87ed605c2cc23ac74dccc56b7ea21f6b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 8 Nov 2019 12:43:26 +0100 Subject: [PATCH 1297/3747] fix into_iter usage --- tests/run-pass/iter.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/run-pass/iter.rs b/tests/run-pass/iter.rs index 1bef21d83bda3..6192dd0d37e89 100644 --- a/tests/run-pass/iter.rs +++ b/tests/run-pass/iter.rs @@ -30,7 +30,7 @@ fn iter_any() { let h = |(), (), x: &u8| { 10u8 == *x }; h((), (), &1u8); - [1, 2, 3u8].into_iter().any(|elt| 10 == *elt); + [1, 2, 3u8].iter().any(|elt| 10 == *elt); } fn main() { From 1aeecb553a79d7bf425a19f74a8b213be63773cb Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 8 Nov 2019 14:12:54 +0100 Subject: [PATCH 1298/3747] Revert "temporarily ignore cached rustup-toolchain-install-master" This reverts commit 4872c5cbbe9a4f59c71a9ffde4d5e521c08e8ea0. --- .appveyor.yml | 2 +- .travis.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index c8ee04275c835..2106ef3655032 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -31,7 +31,7 @@ install: - rustup component remove rust-docs & exit 0 - rustup update # Install "master" toolchain - - cargo install rustup-toolchain-install-master -f + - cargo install rustup-toolchain-install-master & exit 0 # We need to install cargo here as well or else the DLL search path inside `cargo run` # will be for the wrong toolchain. (On Unix, `./miri` takes care of this, but not here.) - rustup-toolchain-install-master -f -n master %RUSTC_HASH% -c rust-src -c rustc-dev -c cargo diff --git a/.travis.yml b/.travis.yml index e9df794b59402..bb38510e39340 100644 --- a/.travis.yml +++ b/.travis.yml @@ -38,7 +38,7 @@ before_script: - rustup component remove rust-docs || echo "rust-docs already gone" - rustup update # Install "master" toolchain -- cargo install rustup-toolchain-install-master -f +- cargo install rustup-toolchain-install-master || echo "rustup-toolchain-install-master already installed" - travis_retry rustup-toolchain-install-master -f -n master $RUSTC_HASH -c rust-src -c rustc-dev - rustup default master - rustc --version From d518c38219b9316d4eae2c817ec4fe3b69d4cc29 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 8 Nov 2019 14:13:23 +0100 Subject: [PATCH 1299/3747] rust-docs should be gone from all caches now --- .appveyor.yml | 1 - .travis.yml | 1 - 2 files changed, 2 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index 2106ef3655032..b9e112aa08608 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -28,7 +28,6 @@ install: - set PATH=%USERPROFILE%\.cargo\bin;%PATH% - rustup default stable - rustup uninstall beta - - rustup component remove rust-docs & exit 0 - rustup update # Install "master" toolchain - cargo install rustup-toolchain-install-master & exit 0 diff --git a/.travis.yml b/.travis.yml index bb38510e39340..a080ab55b94f2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -35,7 +35,6 @@ before_script: - export PATH=$HOME/.cargo/bin:$PATH - rustup default stable - rustup uninstall beta -- rustup component remove rust-docs || echo "rust-docs already gone" - rustup update # Install "master" toolchain - cargo install rustup-toolchain-install-master || echo "rustup-toolchain-install-master already installed" From 9ca277f2e9cface924a5afa8ccfb9c77747956d0 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 8 Nov 2019 16:36:57 +0100 Subject: [PATCH 1300/3747] bump minimal xargo version so that it honors the lockfile --- src/bin/cargo-miri.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index b889ce52f386d..36545766d101d 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -6,6 +6,8 @@ use std::path::{PathBuf, Path}; use std::process::Command; use std::ops::Not; +const XARGO_MIN_VERSION: (u32, u32, u32) = (0, 3, 17); + const CARGO_MIRI_HELP: &str = r#"Interprets bin crates and tests in Miri Usage: @@ -258,7 +260,7 @@ fn setup(ask_user: bool) { } // First, we need xargo. - if xargo_version().map_or(true, |v| v < (0, 3, 16)) { + if xargo_version().map_or(true, |v| v < XARGO_MIN_VERSION) { if std::env::var("XARGO").is_ok() { // The user manually gave us a xargo binary; don't do anything automatically. show_error(format!("Your xargo is too old; please upgrade to the latest version")) From 37b1190defc78a8d2d4139bfcb4816a1a7faf253 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 8 Nov 2019 22:07:52 +0100 Subject: [PATCH 1301/3747] rustup --- rust-version | 2 +- src/intptrcast.rs | 2 +- src/operator.rs | 2 +- src/shims/dlsym.rs | 2 +- src/shims/env.rs | 2 +- src/shims/foreign_items.rs | 58 +++++++++++++++++++------------------- src/shims/fs.rs | 10 ++++--- src/shims/intrinsics.rs | 10 +++---- src/shims/mod.rs | 2 +- src/stacked_borrows.rs | 4 +-- 10 files changed, 48 insertions(+), 46 deletions(-) diff --git a/rust-version b/rust-version index 1377ee94dfc30..ec45e1f973071 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -c34472b77084c9f76f872871aeab121daf81fb99 +9e346646e93cc243567e27bb0f4e8716d56ad1f1 diff --git a/src/intptrcast.rs b/src/intptrcast.rs index e08166b8c2b27..a55c58c13add7 100644 --- a/src/intptrcast.rs +++ b/src/intptrcast.rs @@ -63,7 +63,7 @@ impl<'mir, 'tcx> GlobalState { // This never overflows because `int >= glb` let offset = int - glb; // If the offset exceeds the size of the allocation, this access is illegal - if offset <= memory.get(alloc_id)?.size.bytes() { + if offset <= memory.get_size_and_align(alloc_id, AllocCheck::MaybeDead)?.0.bytes() { // This pointer is untagged because it was created from a cast Pointer::new_with_tag(alloc_id, Size::from_bytes(offset), Tag::Untagged) } else { diff --git a/src/operator.rs b/src/operator.rs index 2a90d3e12f4c0..6b2c12e6b0b04 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -75,7 +75,7 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { let ptr = self.pointer_offset_inbounds( left.to_scalar()?, pointee_ty, - right.to_scalar()?.to_isize(self)?, + right.to_scalar()?.to_machine_isize(self)?, )?; (ptr, false, left.layout.ty) } diff --git a/src/shims/dlsym.rs b/src/shims/dlsym.rs index 307de29f22038..ca53f5d23015a 100644 --- a/src/shims/dlsym.rs +++ b/src/shims/dlsym.rs @@ -40,7 +40,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx match dlsym { GetEntropy => { let ptr = this.read_scalar(args[0])?.not_undef()?; - let len = this.read_scalar(args[1])?.to_usize(this)?; + let len = this.read_scalar(args[1])?.to_machine_usize(this)?; this.gen_random(ptr, len as usize)?; this.write_null(dest)?; } diff --git a/src/shims/env.rs b/src/shims/env.rs index 2dc47d74ffb82..44896fd9bbd56 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -124,7 +124,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.check_no_isolation("getcwd")?; let buf = this.read_scalar(buf_op)?.not_undef()?; - let size = this.read_scalar(size_op)?.to_usize(&*this.tcx)?; + let size = this.read_scalar(size_op)?.to_machine_usize(&*this.tcx)?; // If we cannot get the current directory, we return null match env::current_dir() { Ok(cwd) => { diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 74ce477b8e357..1f43a83576f62 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -144,13 +144,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let ret = ret.expect("dest is `Some` but ret is `None`"); match link_name { "malloc" => { - let size = this.read_scalar(args[0])?.to_usize(this)?; + let size = this.read_scalar(args[0])?.to_machine_usize(this)?; let res = this.malloc(size, /*zero_init:*/ false, MiriMemoryKind::C); this.write_scalar(res, dest)?; } "calloc" => { - let items = this.read_scalar(args[0])?.to_usize(this)?; - let len = this.read_scalar(args[1])?.to_usize(this)?; + let items = this.read_scalar(args[0])?.to_machine_usize(this)?; + let len = this.read_scalar(args[1])?.to_machine_usize(this)?; let size = items .checked_mul(len) .ok_or_else(|| err_panic!(Overflow(mir::BinOp::Mul)))?; @@ -159,8 +159,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "posix_memalign" => { let ret = this.deref_operand(args[0])?; - let align = this.read_scalar(args[1])?.to_usize(this)?; - let size = this.read_scalar(args[2])?.to_usize(this)?; + let align = this.read_scalar(args[1])?.to_machine_usize(this)?; + let size = this.read_scalar(args[2])?.to_machine_usize(this)?; // Align must be power of 2, and also at least ptr-sized (POSIX rules). if !align.is_power_of_two() { throw_unsup!(HeapAllocNonPowerOfTwoAlignment(align)); @@ -190,14 +190,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "realloc" => { let old_ptr = this.read_scalar(args[0])?.not_undef()?; - let new_size = this.read_scalar(args[1])?.to_usize(this)?; + let new_size = this.read_scalar(args[1])?.to_machine_usize(this)?; let res = this.realloc(old_ptr, new_size, MiriMemoryKind::C)?; this.write_scalar(res, dest)?; } "__rust_alloc" => { - let size = this.read_scalar(args[0])?.to_usize(this)?; - let align = this.read_scalar(args[1])?.to_usize(this)?; + let size = this.read_scalar(args[0])?.to_machine_usize(this)?; + let align = this.read_scalar(args[1])?.to_machine_usize(this)?; if size == 0 { throw_unsup!(HeapAllocZeroBytes); } @@ -212,8 +212,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::Ptr(ptr), dest)?; } "__rust_alloc_zeroed" => { - let size = this.read_scalar(args[0])?.to_usize(this)?; - let align = this.read_scalar(args[1])?.to_usize(this)?; + let size = this.read_scalar(args[0])?.to_machine_usize(this)?; + let align = this.read_scalar(args[1])?.to_machine_usize(this)?; if size == 0 { throw_unsup!(HeapAllocZeroBytes); } @@ -233,8 +233,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "__rust_dealloc" => { let ptr = this.read_scalar(args[0])?.not_undef()?; - let old_size = this.read_scalar(args[1])?.to_usize(this)?; - let align = this.read_scalar(args[2])?.to_usize(this)?; + let old_size = this.read_scalar(args[1])?.to_machine_usize(this)?; + let align = this.read_scalar(args[2])?.to_machine_usize(this)?; if old_size == 0 { throw_unsup!(HeapAllocZeroBytes); } @@ -253,9 +253,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "__rust_realloc" => { let ptr = this.read_scalar(args[0])?.to_ptr()?; - let old_size = this.read_scalar(args[1])?.to_usize(this)?; - let align = this.read_scalar(args[2])?.to_usize(this)?; - let new_size = this.read_scalar(args[3])?.to_usize(this)?; + let old_size = this.read_scalar(args[1])?.to_machine_usize(this)?; + let align = this.read_scalar(args[2])?.to_machine_usize(this)?; + let new_size = this.read_scalar(args[3])?.to_machine_usize(this)?; if old_size == 0 || new_size == 0 { throw_unsup!(HeapAllocZeroBytes); } @@ -277,11 +277,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let sys_getrandom = this .eval_path_scalar(&["libc", "SYS_getrandom"])? .expect("Failed to get libc::SYS_getrandom") - .to_usize(this)?; + .to_machine_usize(this)?; // `libc::syscall(NR_GETRANDOM, buf.as_mut_ptr(), buf.len(), GRND_NONBLOCK)` // is called if a `HashMap` is created the regular way (e.g. HashMap). - match this.read_scalar(args[0])?.to_usize(this)? { + match this.read_scalar(args[0])?.to_machine_usize(this)? { id if id == sys_getrandom => { // The first argument is the syscall id, // so skip over it. @@ -357,7 +357,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "memcmp" => { let left = this.read_scalar(args[0])?.not_undef()?; let right = this.read_scalar(args[1])?.not_undef()?; - let n = Size::from_bytes(this.read_scalar(args[2])?.to_usize(this)?); + let n = Size::from_bytes(this.read_scalar(args[2])?.to_machine_usize(this)?); let result = { let left_bytes = this.memory.read_bytes(left, n)?; @@ -377,7 +377,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "memrchr" => { let ptr = this.read_scalar(args[0])?.not_undef()?; let val = this.read_scalar(args[1])?.to_i32()? as u8; - let num = this.read_scalar(args[2])?.to_usize(this)?; + let num = this.read_scalar(args[2])?.to_machine_usize(this)?; if let Some(idx) = this .memory .read_bytes(ptr, Size::from_bytes(num))? @@ -395,7 +395,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "memchr" => { let ptr = this.read_scalar(args[0])?.not_undef()?; let val = this.read_scalar(args[1])?.to_i32()? as u8; - let num = this.read_scalar(args[2])?.to_usize(this)?; + let num = this.read_scalar(args[2])?.to_machine_usize(this)?; let idx = this .memory .read_bytes(ptr, Size::from_bytes(num))? @@ -462,7 +462,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "write" => { let fd = this.read_scalar(args[0])?.to_i32()?; let buf = this.read_scalar(args[1])?.not_undef()?; - let n = this.read_scalar(args[2])?.to_usize(tcx)?; + let n = this.read_scalar(args[2])?.to_machine_usize(tcx)?; trace!("Called write({:?}, {:?}, {:?})", fd, buf, n); let result = if fd == 1 || fd == 2 { // stdout/stderr @@ -771,7 +771,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(this.machine.argv.expect("machine must be initialized"), dest)?; } "SecRandomCopyBytes" => { - let len = this.read_scalar(args[1])?.to_usize(this)?; + let len = this.read_scalar(args[1])?.to_machine_usize(this)?; let ptr = this.read_scalar(args[2])?.not_undef()?; this.gen_random(ptr, len as usize)?; this.write_null(dest)?; @@ -786,25 +786,25 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_int(1, this.pointer_size()), dest)?; } "HeapAlloc" => { - let _handle = this.read_scalar(args[0])?.to_isize(this)?; + let _handle = this.read_scalar(args[0])?.to_machine_isize(this)?; let flags = this.read_scalar(args[1])?.to_u32()?; - let size = this.read_scalar(args[2])?.to_usize(this)?; + let size = this.read_scalar(args[2])?.to_machine_usize(this)?; let zero_init = (flags & 0x00000008) != 0; // HEAP_ZERO_MEMORY let res = this.malloc(size, zero_init, MiriMemoryKind::WinHeap); this.write_scalar(res, dest)?; } "HeapFree" => { - let _handle = this.read_scalar(args[0])?.to_isize(this)?; + let _handle = this.read_scalar(args[0])?.to_machine_isize(this)?; let _flags = this.read_scalar(args[1])?.to_u32()?; let ptr = this.read_scalar(args[2])?.not_undef()?; this.free(ptr, MiriMemoryKind::WinHeap)?; this.write_scalar(Scalar::from_int(1, Size::from_bytes(4)), dest)?; } "HeapReAlloc" => { - let _handle = this.read_scalar(args[0])?.to_isize(this)?; + let _handle = this.read_scalar(args[0])?.to_machine_isize(this)?; let _flags = this.read_scalar(args[1])?.to_u32()?; let ptr = this.read_scalar(args[2])?.not_undef()?; - let size = this.read_scalar(args[3])?.to_usize(this)?; + let size = this.read_scalar(args[3])?.to_machine_usize(this)?; let res = this.realloc(ptr, size, MiriMemoryKind::WinHeap)?; this.write_scalar(res, dest)?; } @@ -883,7 +883,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_int(which, this.pointer_size()), dest)?; } "WriteFile" => { - let handle = this.read_scalar(args[0])?.to_isize(this)?; + let handle = this.read_scalar(args[0])?.to_machine_isize(this)?; let buf = this.read_scalar(args[1])?.not_undef()?; let n = this.read_scalar(args[2])?.to_u32()?; let written_place = this.deref_operand(args[3])?; @@ -973,7 +973,7 @@ fn linux_getrandom<'tcx>( dest: PlaceTy<'tcx, Tag>, ) -> InterpResult<'tcx> { let ptr = this.read_scalar(args[0])?.not_undef()?; - let len = this.read_scalar(args[1])?.to_usize(this)?; + let len = this.read_scalar(args[1])?.to_machine_usize(this)?; // The only supported flags are GRND_RANDOM and GRND_NONBLOCK, // neither of which have any effect on our current PRNG. diff --git a/src/shims/fs.rs b/src/shims/fs.rs index c484795d8fec7..764f345904fa9 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -154,7 +154,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.check_no_isolation("read")?; - let count = this.read_scalar(count_op)?.to_usize(&*this.tcx)?; + let count = this.read_scalar(count_op)?.to_machine_usize(&*this.tcx)?; // Reading zero bytes should not change `buf`. if count == 0 { return Ok(0); @@ -166,8 +166,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.remove_handle_and(fd, |mut handle, this| { // Don't use `?` to avoid returning before reinserting the handle. let bytes = this.force_ptr(buf_scalar).and_then(|buf| { + // FIXME: Don't use raw methods this.memory - .get_mut(buf.alloc_id)? + .get_raw_mut(buf.alloc_id)? .get_bytes_mut(&*this.tcx, buf, Size::from_bytes(count)) .map(|buffer| handle.file.read(buffer)) }); @@ -186,7 +187,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.check_no_isolation("write")?; - let count = this.read_scalar(count_op)?.to_usize(&*this.tcx)?; + let count = this.read_scalar(count_op)?.to_machine_usize(&*this.tcx)?; // Writing zero bytes should not change `buf`. if count == 0 { return Ok(0); @@ -195,7 +196,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let buf = this.force_ptr(this.read_scalar(buf_op)?.not_undef()?)?; this.remove_handle_and(fd, |mut handle, this| { - let bytes = this.memory.get(buf.alloc_id).and_then(|alloc| { + // FIXME: Don't use raw methods + let bytes = this.memory.get_raw(buf.alloc_id).and_then(|alloc| { alloc .get_bytes(&*this.tcx, buf, Size::from_bytes(count)) .map(|bytes| handle.file.write(bytes).map(|bytes| bytes as i64)) diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 7c8c06cbbfd54..7470090f5208f 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -35,7 +35,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let intrinsic_name = &*tcx.item_name(instance.def_id()).as_str(); match intrinsic_name { "arith_offset" => { - let offset = this.read_scalar(args[1])?.to_isize(this)?; + let offset = this.read_scalar(args[1])?.to_machine_isize(this)?; let ptr = this.read_scalar(args[0])?.not_undef()?; let pointee_ty = substs.type_at(0); @@ -206,7 +206,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let elem_ty = substs.type_at(0); let elem_layout = this.layout_of(elem_ty)?; let elem_size = elem_layout.size.bytes(); - let count = this.read_scalar(args[2])?.to_usize(this)?; + let count = this.read_scalar(args[2])?.to_machine_usize(this)?; let elem_align = elem_layout.align.abi; let size = Size::from_bytes(count * elem_size); @@ -371,7 +371,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "offset" => { - let offset = this.read_scalar(args[1])?.to_isize(this)?; + let offset = this.read_scalar(args[1])?.to_machine_isize(this)?; let ptr = this.read_scalar(args[0])?.not_undef()?; let result_ptr = this.pointer_offset_inbounds(ptr, substs.type_at(0), offset)?; this.write_scalar(result_ptr, dest)?; @@ -542,7 +542,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let ptr = mplace.ptr.to_ptr()?; // We know the return place is in-bounds this.memory - .get_mut(ptr.alloc_id)? + .get_raw_mut(ptr.alloc_id)? .mark_definedness(ptr, dest.layout.size, false); } } @@ -554,7 +554,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let ty_layout = this.layout_of(ty)?; let val_byte = this.read_scalar(args[1])?.to_u8()?; let ptr = this.read_scalar(args[0])?.not_undef()?; - let count = this.read_scalar(args[2])?.to_usize(this)?; + let count = this.read_scalar(args[2])?.to_machine_usize(this)?; let byte_count = ty_layout.size * count; this.memory.write_bytes(ptr, iter::repeat(val_byte).take(byte_count.bytes() as usize))?; } diff --git a/src/shims/mod.rs b/src/shims/mod.rs index 60974958c42ab..3302143f48cba 100644 --- a/src/shims/mod.rs +++ b/src/shims/mod.rs @@ -75,7 +75,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let ptr_scalar = this.read_scalar(ptr_op)?.not_undef()?; if let Ok(ptr) = this.force_ptr(ptr_scalar) { - let cur_align = this.memory.get(ptr.alloc_id)?.align.bytes() as usize; + let cur_align = this.memory.get_size_and_align(ptr.alloc_id, AllocCheck::MaybeDead)?.1.bytes() as usize; if cur_align >= req_align { // if the allocation alignment is at least the required alignment we use the // libcore implementation diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 6e63bb073c8c4..94e69203437bf 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -540,8 +540,8 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx kind, new_tag, ptr.tag, place.layout.ty, ptr.erase_tag(), size.bytes()); // Get the allocation. It might not be mutable, so we cannot use `get_mut`. - let alloc = this.memory.get(ptr.alloc_id)?; - let stacked_borrows = alloc.extra.stacked_borrows.as_ref().expect("we should have Stacked Borrows data"); + let extra = &this.memory.get_raw(ptr.alloc_id)?.extra; + let stacked_borrows = extra.stacked_borrows.as_ref().expect("we should have Stacked Borrows data"); // Update the stacks. // Make sure that raw pointers and mutable shared references are reborrowed "weak": // There could be existing unique pointers reborrowed from them that should remain valid! From 6e37f2f3e158c98d094b7f3c9f681ed8e5b8c4c2 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Sat, 9 Nov 2019 15:15:52 +0100 Subject: [PATCH 1302/3747] Cap `count` --- src/shims/fs.rs | 42 ++++++++++++++++++++++-------------------- 1 file changed, 22 insertions(+), 20 deletions(-) diff --git a/src/shims/fs.rs b/src/shims/fs.rs index 4d1b7fdf06c90..5e84cdee5cc4b 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -1,7 +1,7 @@ use std::collections::HashMap; +use std::convert::TryFrom; use std::fs::{remove_file, File, OpenOptions}; use std::io::{Read, Write}; -use std::convert::TryFrom; use rustc::ty::layout::Size; @@ -166,7 +166,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.check_no_isolation("read")?; - let count = this.read_scalar(count_op)?.to_machine_usize(&*this.tcx)?; + let ptr_size = this.pointer_size().bits(); + + let count = this + .read_scalar(count_op)? + .to_machine_usize(&*this.tcx)? + .min(1 << (ptr_size - 1)); // Reading zero bytes should not change `buf`. if count == 0 { return Ok(0); @@ -175,22 +180,22 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let buf = this.read_scalar(buf_op)?.not_undef()?; if let Some(handle) = this.machine.file_handler.handles.get_mut(&fd) { - let count = isize::try_from(count) - .map_err(|_| err_unsup_format!("Program tries to read into buffer too big for this host platform"))?; + let count = isize::try_from(count).unwrap(); // We want to read at most `count` bytes. We are sure that `count` is not negative // because it was a target's `usize`. Also we are sure that its smaller than // `usize::max_value()` because it is a host's `isize`. let mut bytes = vec![0; count as usize]; - let result = handle.file.read(&mut bytes); + let result = handle + .file + .read(&mut bytes) + .map(|c| i64::try_from(c).unwrap()); match result { - Ok(c) => { - let read_bytes = i64::try_from(c) - .map_err(|_| err_unsup_format!("Number of read bytes {} cannot be transformed to i64", c))?; + Ok(read_bytes) => { // If reading to `bytes` did not fail, we write those bytes to the buffer. this.memory.write_bytes(buf, bytes)?; Ok(read_bytes) - }, + } Err(e) => { this.set_last_error_from_io_error(e)?; Ok(-1) @@ -211,7 +216,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.check_no_isolation("write")?; - let count = this.read_scalar(count_op)?.to_machine_usize(&*this.tcx)?; + let ptr_size = this.pointer_size().bits(); + + let count = this + .read_scalar(count_op)? + .to_machine_usize(&*this.tcx)? + .min(1 << (ptr_size - 1)); // Writing zero bytes should not change `buf`. if count == 0 { return Ok(0); @@ -221,16 +231,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if let Some(handle) = this.machine.file_handler.handles.get_mut(&fd) { let bytes = this.memory.read_bytes(buf, Size::from_bytes(count))?; - let result = handle.file.write(&bytes); - - match result { - Ok(c) => i64::try_from(c) - .map_err(|_| err_unsup_format!("Number of written bytes {} cannot be transformed to i64", c).into()), - Err(e) => { - this.set_last_error_from_io_error(e)?; - Ok(-1) - } - } + let result = handle.file.write(&bytes).map(|c| i64::try_from(c).unwrap()); + this.try_unwrap_io_result(result) } else { this.handle_not_found() } From 2c55a508e94c4390d94a843fd52114aa7a7940a7 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 11 Nov 2019 21:25:57 +0100 Subject: [PATCH 1303/3747] rustup --- rust-version | 2 +- src/stacked_borrows.rs | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/rust-version b/rust-version index ec45e1f973071..e6d05f2ed0e2f 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -9e346646e93cc243567e27bb0f4e8716d56ad1f1 +56237d75b4271a8a2e0f47d86ea76ebf6d966152 diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 94e69203437bf..32715157a7719 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -8,7 +8,7 @@ use std::fmt; use std::num::NonZeroU64; use rustc::ty::{self, layout::Size}; -use rustc::hir::{MutMutable, MutImmutable}; +use rustc::hir::Mutability::{Mutable, Immutable}; use rustc::mir::RetagKind; use crate::{ @@ -618,13 +618,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn qualify(ty: ty::Ty<'_>, kind: RetagKind) -> Option<(RefKind, bool)> { match ty.kind { // References are simple. - ty::Ref(_, _, MutMutable) => + ty::Ref(_, _, Mutable) => Some((RefKind::Unique { two_phase: kind == RetagKind::TwoPhase}, kind == RetagKind::FnEntry)), - ty::Ref(_, _, MutImmutable) => + ty::Ref(_, _, Immutable) => Some((RefKind::Shared, kind == RetagKind::FnEntry)), // Raw pointers need to be enabled. ty::RawPtr(tym) if kind == RetagKind::Raw => - Some((RefKind::Raw { mutable: tym.mutbl == MutMutable }, false)), + Some((RefKind::Raw { mutable: tym.mutbl == Mutable }, false)), // Boxes do not get a protector: protectors reflect that references outlive the call // they were passed in to; that's just not the case for boxes. ty::Adt(..) if ty.is_box() => Some((RefKind::Unique { two_phase: false }, false)), From cf5b53e52fc0267aa9be95a6a2544eeb9761cd7f Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Tue, 12 Nov 2019 10:19:13 -0500 Subject: [PATCH 1304/3747] Rustup for panic changes This gets Miri working again, but doesn't actually implement unwinding --- src/eval.rs | 2 +- src/machine.rs | 17 +++++++++++++---- src/shims/foreign_items.rs | 2 +- src/shims/intrinsics.rs | 2 +- src/shims/mod.rs | 2 +- 5 files changed, 17 insertions(+), 8 deletions(-) diff --git a/src/eval.rs b/src/eval.rs index b09fb5918c874..65f6d5dd02718 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -213,7 +213,7 @@ pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) { }; e.print_backtrace(); if let Some(frame) = ecx.stack().last() { - let block = &frame.body.basic_blocks()[frame.block]; + let block = &frame.body.basic_blocks()[frame.block.unwrap()]; let span = if frame.stmt < block.statements.len() { block.statements[frame.stmt].source_info.span } else { diff --git a/src/machine.rs b/src/machine.rs index c76cc2e568f4f..20abfdcf54bb5 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -173,6 +173,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { args: &[OpTy<'tcx, Tag>], dest: Option>, ret: Option, + _unwind: Option, ) -> InterpResult<'tcx, Option<&'mir mir::Body<'tcx>>> { ecx.find_fn(instance, args, dest, ret) } @@ -194,8 +195,14 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { span: Span, instance: ty::Instance<'tcx>, args: &[OpTy<'tcx, Tag>], - dest: PlaceTy<'tcx, Tag>, + dest: Option>, + _ret: Option, + _unwind: Option ) -> InterpResult<'tcx> { + let dest = match dest { + Some(dest) => dest, + None => throw_ub!(Unreachable) + }; ecx.call_intrinsic(span, instance, args, dest) } @@ -353,13 +360,15 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { fn stack_pop( ecx: &mut InterpCx<'mir, 'tcx, Self>, extra: stacked_borrows::CallId, - ) -> InterpResult<'tcx> { - Ok(ecx + _unwinding: bool + ) -> InterpResult<'tcx, StackPopInfo> { + ecx .memory .extra .stacked_borrows .borrow_mut() - .end_call(extra)) + .end_call(extra); + Ok(StackPopInfo::Normal) } #[inline(always)] diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 1f43a83576f62..55ec36387f2e8 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -335,7 +335,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx mir, Some(ret_place), // Directly return to caller. - StackPopCleanup::Goto(Some(ret)), + StackPopCleanup::Goto { ret: Some(ret), unwind: None }, )?; let mut args = this.frame().body.args_iter(); diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 7470090f5208f..2e41ab1ca6700 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -22,7 +22,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx dest: PlaceTy<'tcx, Tag>, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - if this.emulate_intrinsic(span, instance, args, dest)? { + if this.emulate_intrinsic(span, instance, args, Some(dest))? { return Ok(()); } let tcx = &{this.tcx.tcx}; diff --git a/src/shims/mod.rs b/src/shims/mod.rs index 3302143f48cba..d9de27596cd0d 100644 --- a/src/shims/mod.rs +++ b/src/shims/mod.rs @@ -27,7 +27,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ); // First, run the common hooks also supported by CTFE. - if this.hook_fn(instance, args, dest)? { + if this.hook_panic_fn(instance, args, dest)? { this.goto_block(ret)?; return Ok(None); } From ca983f5f80c2e3c5cc54349276ccc8845063bf84 Mon Sep 17 00:00:00 2001 From: Steven Gu Date: Wed, 13 Nov 2019 10:14:13 +0800 Subject: [PATCH 1305/3747] Implments `intrinsics::copysignf32` and `intrinsics::copysignf64`. --- src/shims/intrinsics.rs | 22 ++++++++++++---------- tests/run-pass/floats.rs | 12 ++++++++++++ 2 files changed, 24 insertions(+), 10 deletions(-) diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 7470090f5208f..34b8c483225b6 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -291,24 +291,26 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.binop_ignore_overflow(op, a, b, dest)?; } - "minnumf32" | "maxnumf32" => { + "minnumf32" | "maxnumf32" | "copysignf32" => { let a = this.read_scalar(args[0])?.to_f32()?; let b = this.read_scalar(args[1])?.to_f32()?; - let res = if intrinsic_name.starts_with("min") { - a.min(b) - } else { - a.max(b) + let res = match intrinsic_name { + "minnumf32" => a.min(b), + "maxnumf32" => a.max(b), + "copysignf32" => a.copy_sign(b), + _ => bug!(), }; this.write_scalar(Scalar::from_f32(res), dest)?; } - "minnumf64" | "maxnumf64" => { + "minnumf64" | "maxnumf64" | "copysignf64" => { let a = this.read_scalar(args[0])?.to_f64()?; let b = this.read_scalar(args[1])?.to_f64()?; - let res = if intrinsic_name.starts_with("min") { - a.min(b) - } else { - a.max(b) + let res = match intrinsic_name { + "minnumf64" => a.min(b), + "maxnumf64" => a.max(b), + "copysignf64" => a.copy_sign(b), + _ => bug!(), }; this.write_scalar(Scalar::from_f64(res), dest)?; } diff --git a/tests/run-pass/floats.rs b/tests/run-pass/floats.rs index c1588dae249a5..7577c48c5ae38 100644 --- a/tests/run-pass/floats.rs +++ b/tests/run-pass/floats.rs @@ -25,4 +25,16 @@ fn main() { assert_eq!(std::f64::NAN.max(-9.0), -9.0); assert_eq!((9.0 as f64).min(std::f64::NAN), 9.0); assert_eq!((-9.0 as f64).max(std::f64::NAN), -9.0); + + assert_eq!(3.5_f32.copysign(0.42), 3.5_f32); + assert_eq!(3.5_f32.copysign(-0.42), -3.5_f32); + assert_eq!((-3.5_f32).copysign(0.42), 3.5_f32); + assert_eq!((-3.5_f32).copysign(-0.42), -3.5_f32); + assert!(std::f32::NAN.copysign(1.0).is_nan()); + + assert_eq!(3.5_f64.copysign(0.42), 3.5_f64); + assert_eq!(3.5_f64.copysign(-0.42), -3.5_f64); + assert_eq!((-3.5_f64).copysign(0.42), 3.5_f64); + assert_eq!((-3.5_f64).copysign(-0.42), -3.5_f64); + assert!(std::f64::NAN.copysign(1.0).is_nan()); } From edd0157069b09e3fceb8036cabbdba96972cb2f7 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Wed, 13 Nov 2019 11:57:20 -0500 Subject: [PATCH 1306/3747] Cap `count` twice --- src/shims/fs.rs | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/shims/fs.rs b/src/shims/fs.rs index 5e84cdee5cc4b..9a819cd9db4b2 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -168,10 +168,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let ptr_size = this.pointer_size().bits(); + // We cap the number of read bytes to the largest value that we are able to fit in both the + // host's and target's `isize`. let count = this .read_scalar(count_op)? .to_machine_usize(&*this.tcx)? - .min(1 << (ptr_size - 1)); + .min(1 << (ptr_size - 1)) + .min(isize::max_value() as u64); // Reading zero bytes should not change `buf`. if count == 0 { return Ok(0); @@ -180,6 +183,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let buf = this.read_scalar(buf_op)?.not_undef()?; if let Some(handle) = this.machine.file_handler.handles.get_mut(&fd) { + // This can never fail because `count` was capped to be smaller than + // `isize::max_value()`. let count = isize::try_from(count).unwrap(); // We want to read at most `count` bytes. We are sure that `count` is not negative // because it was a target's `usize`. Also we are sure that its smaller than @@ -188,6 +193,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let result = handle .file .read(&mut bytes) + // `File::read` never returns a value larger than `i64::max_value()`, so this + // unwrap cannot fail. .map(|c| i64::try_from(c).unwrap()); match result { @@ -218,10 +225,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let ptr_size = this.pointer_size().bits(); + // We cap the number of read bytes to the largest value that we are able to fit in both the + // host's and target's `isize`. let count = this .read_scalar(count_op)? .to_machine_usize(&*this.tcx)? - .min(1 << (ptr_size - 1)); + .min(1 << (ptr_size - 1)) + .min(isize::max_value() as u64); // Writing zero bytes should not change `buf`. if count == 0 { return Ok(0); From 4baef7120a934b79f87dbe5d09591d781c1c81f7 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Wed, 13 Nov 2019 14:45:00 -0500 Subject: [PATCH 1307/3747] Fix maximum `isize` value for target --- src/shims/fs.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/shims/fs.rs b/src/shims/fs.rs index 9a819cd9db4b2..4de59ad32ff59 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -173,7 +173,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let count = this .read_scalar(count_op)? .to_machine_usize(&*this.tcx)? - .min(1 << (ptr_size - 1)) + .min((1 << (ptr_size - 1)) - 1) // max value of target `isize` .min(isize::max_value() as u64); // Reading zero bytes should not change `buf`. if count == 0 { @@ -193,8 +193,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let result = handle .file .read(&mut bytes) - // `File::read` never returns a value larger than `i64::max_value()`, so this - // unwrap cannot fail. + // `File::read` never returns a value larger than `count`, so this cannot fail. .map(|c| i64::try_from(c).unwrap()); match result { @@ -230,7 +229,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let count = this .read_scalar(count_op)? .to_machine_usize(&*this.tcx)? - .min(1 << (ptr_size - 1)) + .min((1 << (ptr_size - 1)) - 1) // max value of target `isize` .min(isize::max_value() as u64); // Writing zero bytes should not change `buf`. if count == 0 { From 82ef2bb0e28884207a2c59d42d6fbf2918153ec4 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 14 Nov 2019 10:16:44 +0100 Subject: [PATCH 1308/3747] rename miri-issue to issue-miri for grouping --- tests/run-pass/{miri-issue-133.rs => issue-miri-133.rs} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename tests/run-pass/{miri-issue-133.rs => issue-miri-133.rs} (100%) diff --git a/tests/run-pass/miri-issue-133.rs b/tests/run-pass/issue-miri-133.rs similarity index 100% rename from tests/run-pass/miri-issue-133.rs rename to tests/run-pass/issue-miri-133.rs From 64244e9a18a0b6a328f8dcfe0741a160d219b429 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 14 Nov 2019 10:23:29 +0100 Subject: [PATCH 1309/3747] do full deref-check before reborrowing --- src/stacked_borrows.rs | 8 ++++---- tests/compile-fail/stacked_borrows/issue-miri-1050-1.rs | 6 ++++++ tests/compile-fail/stacked_borrows/issue-miri-1050-2.rs | 7 +++++++ 3 files changed, 17 insertions(+), 4 deletions(-) create mode 100644 tests/compile-fail/stacked_borrows/issue-miri-1050-1.rs create mode 100644 tests/compile-fail/stacked_borrows/issue-miri-1050-2.rs diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 32715157a7719..0ab9dabab9b78 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -533,9 +533,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let protector = if protect { Some(this.frame().extra) } else { None }; - let ptr = this.memory.check_ptr_access(place.ptr, size, place.align) - .expect("validity checks should have excluded dangling/unaligned pointer") - .expect("we shouldn't get here for ZST"); + let ptr = place.ptr.to_ptr().expect("we should have a proper pointer"); trace!("reborrow: {} reference {:?} derived from {:?} (pointee {}): {:?}, size {}", kind, new_tag, ptr.tag, place.layout.ty, ptr.erase_tag(), size.bytes()); @@ -583,11 +581,13 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let size = this.size_and_align_of_mplace(place)? .map(|(size, _)| size) .unwrap_or_else(|| place.layout.size); + // We can see dangling ptrs in here e.g. after a Box's `Unique` was + // updated using "self.0 = ..." (can happen in Box::from_raw); see miri#1050. + let place = this.mplace_access_checked(place)?; if size == Size::ZERO { // Nothing to do for ZSTs. return Ok(*val); } - let place = this.force_mplace_ptr(place)?; // Compute new borrow. let new_tag = match kind { diff --git a/tests/compile-fail/stacked_borrows/issue-miri-1050-1.rs b/tests/compile-fail/stacked_borrows/issue-miri-1050-1.rs new file mode 100644 index 0000000000000..24df70a8179f1 --- /dev/null +++ b/tests/compile-fail/stacked_borrows/issue-miri-1050-1.rs @@ -0,0 +1,6 @@ +// error-pattern: pointer must be in-bounds + +fn main() { unsafe { + let ptr = Box::into_raw(Box::new(0u16)); + Box::from_raw(ptr as *mut u32); +} } diff --git a/tests/compile-fail/stacked_borrows/issue-miri-1050-2.rs b/tests/compile-fail/stacked_borrows/issue-miri-1050-2.rs new file mode 100644 index 0000000000000..74aab153ea90f --- /dev/null +++ b/tests/compile-fail/stacked_borrows/issue-miri-1050-2.rs @@ -0,0 +1,7 @@ +// error-pattern: dangling pointer was dereferenced +use std::ptr::NonNull; + +fn main() { unsafe { + let ptr = NonNull::::dangling(); + Box::from_raw(ptr.as_ptr()); +} } From c790317eb95c78af1e63dc0efcd4d447aa83ffc8 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 14 Nov 2019 10:29:43 +0100 Subject: [PATCH 1310/3747] remove no-longer-needed zero checks --- src/shims/fs.rs | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/src/shims/fs.rs b/src/shims/fs.rs index 4de59ad32ff59..79e57cf2c8f5d 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -175,10 +175,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx .to_machine_usize(&*this.tcx)? .min((1 << (ptr_size - 1)) - 1) // max value of target `isize` .min(isize::max_value() as u64); - // Reading zero bytes should not change `buf`. - if count == 0 { - return Ok(0); - } + let fd = this.read_scalar(fd_op)?.to_i32()?; let buf = this.read_scalar(buf_op)?.not_undef()?; @@ -231,10 +228,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx .to_machine_usize(&*this.tcx)? .min((1 << (ptr_size - 1)) - 1) // max value of target `isize` .min(isize::max_value() as u64); - // Writing zero bytes should not change `buf`. - if count == 0 { - return Ok(0); - } + let fd = this.read_scalar(fd_op)?.to_i32()?; let buf = this.read_scalar(buf_op)?.not_undef()?; From 524624297d37f87d3bceb28cddbde82eb2e789f8 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 15 Nov 2019 15:59:19 +0100 Subject: [PATCH 1311/3747] test-cargo-miri: cargo update, re-enable windows num_cpus test --- test-cargo-miri/Cargo.lock | 37 +++++++++++++++++++---------------- test-cargo-miri/tests/test.rs | 1 - 2 files changed, 20 insertions(+), 18 deletions(-) diff --git a/test-cargo-miri/Cargo.lock b/test-cargo-miri/Cargo.lock index 55c7c528aa9fc..118afff39bd6d 100644 --- a/test-cargo-miri/Cargo.lock +++ b/test-cargo-miri/Cargo.lock @@ -1,10 +1,5 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -[[package]] -name = "autocfg" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "byteorder" version = "1.3.2" @@ -23,7 +18,7 @@ name = "cargo-miri-test" version = "0.1.0" dependencies = [ "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 1.11.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -34,7 +29,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "getrandom" -version = "0.1.12" +version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", @@ -42,6 +37,14 @@ dependencies = [ "wasi 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "hermit-abi" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "libc" version = "0.2.65" @@ -49,9 +52,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "num_cpus" -version = "1.10.1" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ + "hermit-abi 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -65,12 +69,12 @@ name = "rand" version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "getrandom 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", + "getrandom 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "rand_chacha 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_pcg 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_pcg 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -87,7 +91,7 @@ name = "rand_core" version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "getrandom 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", + "getrandom 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -100,10 +104,9 @@ dependencies = [ [[package]] name = "rand_pcg" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -113,17 +116,17 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" [metadata] -"checksum autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "1d49d90015b3c36167a20fe2810c5cd875ad504b39cff3d4eae7977e6b7c1cb2" "checksum byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a7c3dd8985a7111efc5c80b44e23ecdd8c007de8ade3b96595387e812b957cf5" "checksum c2-chacha 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "214238caa1bf3a496ec3392968969cab8549f96ff30652c9e56885329315f6bb" "checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" -"checksum getrandom 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "473a1265acc8ff1e808cd0a1af8cee3c2ee5200916058a2ca113c29f2d903571" +"checksum getrandom 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "e7db7ca94ed4cd01190ceee0d8a8052f08a247aa1b469a7f68c6a3b71afcf407" +"checksum hermit-abi 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "307c3c9f937f38e3534b1d6447ecf090cafcc9744e4a6360e8b037b2cf5af120" "checksum libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)" = "1a31a0627fdf1f6a39ec0dd577e101440b7db22672c0901fe00a9a6fbb5c24e8" -"checksum num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bcef43580c035376c0705c42792c294b66974abbfd2789b511784023f71f3273" +"checksum num_cpus 1.11.1 (registry+https://github.com/rust-lang/crates.io-index)" = "76dac5ed2a876980778b8b85f75a71b6cbf0db0b1232ee12f826bccb00d09d72" "checksum ppv-lite86 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "74490b50b9fbe561ac330df47c08f3f33073d2d00c150f719147d7c54522fa1b" "checksum rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "3ae1b169243eaf61759b8475a998f0a385e42042370f3a7dbaf35246eacc8412" "checksum rand_chacha 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "03a2a90da8c7523f554344f921aa97283eadf6ac484a6d2a7d0212fa7f8d6853" "checksum rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" "checksum rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" -"checksum rand_pcg 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3e196346cbbc5c70c77e7b4926147ee8e383a38ee4d15d58a08098b169e492b6" +"checksum rand_pcg 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "16abd0c1b639e9eb4d7c50c0b8100b0d0f849be2349829c740fe8e6eb4816429" "checksum wasi 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b89c3ce4ce14bdc6fb6beaf9ec7928ca331de5df7e5ea278375642a2f478570d" diff --git a/test-cargo-miri/tests/test.rs b/test-cargo-miri/tests/test.rs index 904bbbc6cd46b..cfbe3f6d7fb66 100644 --- a/test-cargo-miri/tests/test.rs +++ b/test-cargo-miri/tests/test.rs @@ -39,6 +39,5 @@ fn entropy_rng() { #[test] fn num_cpus() { - #[cfg(not(windows))] // FIXME: enable on Windows again once https://github.com/seanmonstar/num_cpus/pull/90 gets released. assert_eq!(num_cpus::get(), 1); } From 68bc7e077b213bc92d8511e0236d2272743aa619 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 16 Nov 2019 09:00:05 +0100 Subject: [PATCH 1312/3747] bump Rust --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index e6d05f2ed0e2f..0ddadf64c9d49 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -56237d75b4271a8a2e0f47d86ea76ebf6d966152 +1d8b6ce89e0874b5e93c9e41bfdd565c56372bb0 From 08fe5ee78c181b4b7216d4a0cdacc4a29f1ae8b6 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 16 Nov 2019 09:07:35 +0100 Subject: [PATCH 1313/3747] try the stable feature of compiletest --- Cargo.lock | 32 ++++++++++++++++++++++++++++++++ Cargo.toml | 2 +- 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index fb7ab619281f5..c930566c86a5b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -172,6 +172,7 @@ dependencies = [ "serde_derive 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "tester 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -203,6 +204,15 @@ dependencies = [ "dirs-sys 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "dirs" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "dirs-sys 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "dirs-sys" version = "0.3.4" @@ -671,6 +681,15 @@ dependencies = [ "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "term" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "dirs 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "termcolor" version = "1.0.5" @@ -679,6 +698,16 @@ dependencies = [ "wincolor 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "tester" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "getopts 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", + "term 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "thread_local" version = "0.3.6" @@ -795,6 +824,7 @@ dependencies = [ "checksum crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)" = "04973fa96e96579258a5091af6003abde64af786b860f18622b82e026cca60e6" "checksum diff 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "3c2b69f912779fbb121ceb775d74d51e915af17aaebc38d28a592843a2dd0a3a" "checksum directories 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "551a778172a450d7fc12e629ca3b0428d00f6afa9a43da1b630d54604e97371c" +"checksum dirs 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "13aea89a5c93364a98e9b37b2fa237effbb694d5cfe01c5b70941f7eb087d5e3" "checksum dirs-sys 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "afa0b23de8fd801745c471deffa6e12d248f962c9fd4b4c33787b055599bde7b" "checksum env_logger 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "44533bbbb3bb3c1fa17d9f2e4e38bbbaf8396ba82193c4cb1b6445d711445d36" "checksum failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "f8273f13c977665c5db7eb2b99ae520952fe5ac831ae4cd09d80c4c7042b5ed9" @@ -850,7 +880,9 @@ dependencies = [ "checksum syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "66850e97125af79138385e9b88339cbcd037e3f28ceab8c5ad98e64f0f1f80bf" "checksum synstructure 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3f085a5855930c0441ca1288cf044ea4aecf4f43a91668abdb870b4ba546a203" "checksum tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9" +"checksum term 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c0863a3345e70f61d613eab32ee046ccd1bcc5f9105fe402c61fcd0c13eeb8b5" "checksum termcolor 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "96d6098003bde162e4277c70665bd87c326f5a0c3f3fbfb285787fa482d54e6e" +"checksum tester 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cd0d1044cb5ca390e9c93f8c35abd2c55484397dfd786f189321aa34605ee6ab" "checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b" "checksum time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f" "checksum unicode-width 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7007dbd421b92cc6e28410fe7362e2e0a2503394908f417b68ec8d1c364c4e20" diff --git a/Cargo.toml b/Cargo.toml index ba31dd848ab41..8a09bb7ac1787 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -59,5 +59,5 @@ cargo_miri = ["cargo_metadata", "directories", "rustc_version"] rustc_tests = [] [dev-dependencies] -compiletest_rs = { version = "0.3.24", features = ["tmp"] } +compiletest_rs = { version = "0.3.24", features = ["tmp", "stable"] } colored = "1.6" From 4712ed3ff50db58e823758daca68ef33700aec00 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 17 Nov 2019 09:03:16 +0100 Subject: [PATCH 1314/3747] rustup again --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 0ddadf64c9d49..0d6f14df928cb 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -1d8b6ce89e0874b5e93c9e41bfdd565c56372bb0 +8831d766ace89bc74714918a7d9fbd3ca5ec946a From f2c0c44a098e9afda322fd9b378add202b49b637 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 17 Nov 2019 09:20:50 +0100 Subject: [PATCH 1315/3747] remove some leftovers from the miri-control-attribute days --- src/bin/miri-rustc-tests.rs | 10 ---------- src/bin/miri.rs | 10 ---------- 2 files changed, 20 deletions(-) diff --git a/src/bin/miri-rustc-tests.rs b/src/bin/miri-rustc-tests.rs index 5f814fd198622..920c925443007 100644 --- a/src/bin/miri-rustc-tests.rs +++ b/src/bin/miri-rustc-tests.rs @@ -29,16 +29,6 @@ struct MiriCompilerCalls { } impl rustc_driver::Callbacks for MiriCompilerCalls { - fn after_parsing(&mut self, compiler: &interface::Compiler) -> Compilation { - let attr = ( - syntax::symbol::Symbol::intern("miri"), - syntax::feature_gate::AttributeType::Whitelisted, - ); - compiler.session().plugin_attributes.borrow_mut().push(attr); - - Compilation::Continue - } - fn after_analysis(&mut self, compiler: &interface::Compiler) -> Compilation { compiler.session().abort_if_errors(); compiler.global_ctxt().unwrap().peek_mut().enter(|tcx| { diff --git a/src/bin/miri.rs b/src/bin/miri.rs index dd56f0a6e53c4..481491ea722f8 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -28,16 +28,6 @@ struct MiriCompilerCalls { } impl rustc_driver::Callbacks for MiriCompilerCalls { - fn after_parsing(&mut self, compiler: &interface::Compiler) -> Compilation { - let attr = ( - syntax::symbol::Symbol::intern("miri"), - syntax::feature_gate::AttributeType::Whitelisted, - ); - compiler.session().plugin_attributes.borrow_mut().push(attr); - - Compilation::Continue - } - fn after_analysis(&mut self, compiler: &interface::Compiler) -> Compilation { init_late_loggers(); compiler.session().abort_if_errors(); From 5345636f37a2934ea4c183baa2069fa50c6793cc Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 17 Nov 2019 09:30:32 +0100 Subject: [PATCH 1316/3747] use new isize_max method in FS accesses; also check full buffers for validity --- src/shims/fs.rs | 42 +++++++++++++++++++++++------------------- 1 file changed, 23 insertions(+), 19 deletions(-) diff --git a/src/shims/fs.rs b/src/shims/fs.rs index 79e57cf2c8f5d..9291f3a6e3b20 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -3,7 +3,7 @@ use std::convert::TryFrom; use std::fs::{remove_file, File, OpenOptions}; use std::io::{Read, Write}; -use rustc::ty::layout::Size; +use rustc::ty::layout::{Size, Align}; use crate::stacked_borrows::Tag; use crate::*; @@ -166,18 +166,20 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.check_no_isolation("read")?; - let ptr_size = this.pointer_size().bits(); - - // We cap the number of read bytes to the largest value that we are able to fit in both the - // host's and target's `isize`. + let fd = this.read_scalar(fd_op)?.to_i32()?; + let buf = this.read_scalar(buf_op)?.not_undef()?; let count = this .read_scalar(count_op)? - .to_machine_usize(&*this.tcx)? - .min((1 << (ptr_size - 1)) - 1) // max value of target `isize` - .min(isize::max_value() as u64); + .to_machine_usize(&*this.tcx)?; - let fd = this.read_scalar(fd_op)?.to_i32()?; - let buf = this.read_scalar(buf_op)?.not_undef()?; + // Check that the *entire* buffer is actually valid memory. + this.memory.check_ptr_access(buf, Size::from_bytes(count), Align::from_bytes(1).unwrap())?; + + // We cap the number of read bytes to the largest value that we are able to fit in both the + // host's and target's `isize`. This saves us from having to handle overflows later. + let count = count + .min(this.isize_max() as u64) + .min(isize::max_value() as u64); if let Some(handle) = this.machine.file_handler.handles.get_mut(&fd) { // This can never fail because `count` was capped to be smaller than @@ -219,18 +221,20 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.check_no_isolation("write")?; - let ptr_size = this.pointer_size().bits(); - - // We cap the number of read bytes to the largest value that we are able to fit in both the - // host's and target's `isize`. + let fd = this.read_scalar(fd_op)?.to_i32()?; + let buf = this.read_scalar(buf_op)?.not_undef()?; let count = this .read_scalar(count_op)? - .to_machine_usize(&*this.tcx)? - .min((1 << (ptr_size - 1)) - 1) // max value of target `isize` - .min(isize::max_value() as u64); + .to_machine_usize(&*this.tcx)?; - let fd = this.read_scalar(fd_op)?.to_i32()?; - let buf = this.read_scalar(buf_op)?.not_undef()?; + // Check that the *entire* buffer is actually valid memory. + this.memory.check_ptr_access(buf, Size::from_bytes(count), Align::from_bytes(1).unwrap())?; + + // We cap the number of written bytes to the largest value that we are able to fit in both the + // host's and target's `isize`. This saves us from having to handle overflows later. + let count = count + .min(this.isize_max() as u64) + .min(isize::max_value() as u64); if let Some(handle) = this.machine.file_handler.handles.get_mut(&fd) { let bytes = this.memory.read_bytes(buf, Size::from_bytes(count))?; From 08d3fbc76b72fd06cade88b2afe21b70978e8797 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Sun, 14 Apr 2019 21:02:55 -0400 Subject: [PATCH 1317/3747] Support unwinding after a panic Fixes #658 This commit adds support for unwinding after a panic. It requires a companion rustc PR to be merged, in order for the necessary hooks to work properly. Currently implemented: * Selecting between unwind/abort mode based on the rustc Session * Properly popping off stack frames, unwinding back the caller * Running 'unwind' blocks in Mir terminators Not yet implemented: * 'Abort' terminators This PR was getting fairly large, so I decided to open it for review without implementing 'Abort' terminator support. This could either be added on to this PR, or merged separately. --- src/eval.rs | 5 +- src/helpers.rs | 68 ++++++----- src/lib.rs | 1 + src/machine.rs | 59 +++++----- src/shims/foreign_items.rs | 78 +++++-------- src/shims/intrinsics.rs | 33 ++++-- src/shims/mod.rs | 20 ++-- src/shims/panic.rs | 179 +++++++++++++++++++++++++++++ src/stacked_borrows.rs | 2 +- tests/compile-fail/double_panic.rs | 11 ++ tests/compile-fail/panic1.rs | 4 +- tests/compile-fail/panic2.rs | 3 +- tests/compile-fail/panic3.rs | 1 + tests/compile-fail/panic4.rs | 1 + tests/run-pass/catch_panic.rs | 61 ++++++++++ tests/run-pass/panic1.rs | 3 + tests/run-pass/panic1.stderr | 1 + tests/run-pass/panic2.rs | 4 + tests/run-pass/panic2.stderr | 1 + 19 files changed, 404 insertions(+), 131 deletions(-) create mode 100644 src/shims/panic.rs create mode 100644 tests/compile-fail/double_panic.rs create mode 100644 tests/run-pass/catch_panic.rs create mode 100644 tests/run-pass/panic1.rs create mode 100644 tests/run-pass/panic1.stderr create mode 100644 tests/run-pass/panic2.rs create mode 100644 tests/run-pass/panic2.stderr diff --git a/src/eval.rs b/src/eval.rs index 65f6d5dd02718..7203ba6bf1db9 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -39,10 +39,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( tcx.at(syntax::source_map::DUMMY_SP), ty::ParamEnv::reveal_all(), Evaluator::new(config.communicate), - MemoryExtra::new( - StdRng::seed_from_u64(config.seed.unwrap_or(0)), - config.validate, - ), + MemoryExtra::new(StdRng::seed_from_u64(config.seed.unwrap_or(0)), config.validate), ); // Complete initialization. EnvVars::init(&mut ecx, config.excluded_env_vars); diff --git a/src/helpers.rs b/src/helpers.rs index ae117d5fb352f..cff78859df8df 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -6,6 +6,7 @@ use rustc::mir; use rustc::ty::{ self, List, + TyCtxt, layout::{self, LayoutOf, Size, TyLayout}, }; @@ -15,40 +16,45 @@ use crate::*; impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} -pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { - /// Gets an instance for a path. - fn resolve_path(&self, path: &[&str]) -> InterpResult<'tcx, ty::Instance<'tcx>> { - let this = self.eval_context_ref(); - this.tcx - .crates() - .iter() - .find(|&&krate| this.tcx.original_crate_name(krate).as_str() == path[0]) - .and_then(|krate| { - let krate = DefId { - krate: *krate, - index: CRATE_DEF_INDEX, - }; - let mut items = this.tcx.item_children(krate); - let mut path_it = path.iter().skip(1).peekable(); - - while let Some(segment) = path_it.next() { - for item in mem::replace(&mut items, Default::default()).iter() { - if item.ident.name.as_str() == *segment { - if path_it.peek().is_none() { - return Some(ty::Instance::mono(this.tcx.tcx, item.res.def_id())); - } - - items = this.tcx.item_children(item.res.def_id()); - break; +/// Gets an instance for a path. +fn resolve_did<'mir, 'tcx>(tcx: TyCtxt<'tcx>, path: &[&str]) -> InterpResult<'tcx, DefId> { + tcx + .crates() + .iter() + .find(|&&krate| tcx.original_crate_name(krate).as_str() == path[0]) + .and_then(|krate| { + let krate = DefId { + krate: *krate, + index: CRATE_DEF_INDEX, + }; + let mut items = tcx.item_children(krate); + let mut path_it = path.iter().skip(1).peekable(); + + while let Some(segment) = path_it.next() { + for item in mem::replace(&mut items, Default::default()).iter() { + if item.ident.name.as_str() == *segment { + if path_it.peek().is_none() { + return Some(item.res.def_id()) } + + items = tcx.item_children(item.res.def_id()); + break; } } - None - }) - .ok_or_else(|| { - let path = path.iter().map(|&s| s.to_owned()).collect(); - err_unsup!(PathNotFound(path)).into() - }) + } + None + }) + .ok_or_else(|| { + let path = path.iter().map(|&s| s.to_owned()).collect(); + err_unsup!(PathNotFound(path)).into() + }) +} + + +pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { + + fn resolve_path(&self, path: &[&str]) -> InterpResult<'tcx, ty::Instance<'tcx>> { + Ok(ty::Instance::mono(self.eval_context_ref().tcx.tcx, resolve_did(self.eval_context_ref().tcx.tcx, path)?)) } /// Write a 0 of the appropriate size to `dest`. diff --git a/src/lib.rs b/src/lib.rs index 59acff358678a..f29ec8f22bbae 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -37,6 +37,7 @@ pub use crate::shims::time::{EvalContextExt as TimeEvalContextExt}; pub use crate::shims::dlsym::{Dlsym, EvalContextExt as DlsymEvalContextExt}; pub use crate::shims::env::{EnvVars, EvalContextExt as EnvEvalContextExt}; pub use crate::shims::fs::{FileHandler, EvalContextExt as FileEvalContextExt}; +pub use crate::shims::panic::{CatchUnwindData, EvalContextExt as PanicEvalContextExt}; pub use crate::operator::EvalContextExt as OperatorEvalContextExt; pub use crate::range_map::RangeMap; pub use crate::helpers::{EvalContextExt as HelpersEvalContextExt}; diff --git a/src/machine.rs b/src/machine.rs index 20abfdcf54bb5..8910c589ee70e 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -8,12 +8,8 @@ use std::rc::Rc; use rand::rngs::StdRng; use rustc::hir::def_id::DefId; +use rustc::ty::{self, layout::{Size, LayoutOf}, Ty, TyCtxt}; use rustc::mir; -use rustc::ty::{ - self, - layout::{LayoutOf, Size}, - Ty, TyCtxt, -}; use syntax::{attr, source_map::Span, symbol::sym}; use crate::*; @@ -24,6 +20,19 @@ pub const STACK_ADDR: u64 = 32 * PAGE_SIZE; // not really about the "stack", but pub const STACK_SIZE: u64 = 16 * PAGE_SIZE; // whatever pub const NUM_CPUS: u64 = 1; +/// Extra data stored with each stack frame +#[derive(Debug)] +pub struct FrameData<'tcx> { + /// Extra data for Stacked Borrows. + pub call_id: stacked_borrows::CallId, + /// If this is Some(), then this is a special 'catch unwind' + /// frame. When this frame is popped during unwinding a panic, + /// we stop unwinding, and use the `CatchUnwindData` to + /// store the panic payload and continue execution in the parent frame. + pub catch_panic: Option>, +} + + /// Extra memory kinds #[derive(Debug, Copy, Clone, PartialEq, Eq)] pub enum MiriMemoryKind { @@ -101,6 +110,10 @@ pub struct Evaluator<'tcx> { pub(crate) communicate: bool, pub(crate) file_handler: FileHandler, + + /// The temporary used for storing the argument of + /// the call to `miri_start_panic` (the panic payload) when unwinding. + pub(crate) panic_payload: Option> } impl<'tcx> Evaluator<'tcx> { @@ -116,6 +129,7 @@ impl<'tcx> Evaluator<'tcx> { tls: TlsData::default(), communicate, file_handler: Default::default(), + panic_payload: None } } } @@ -143,7 +157,7 @@ impl<'mir, 'tcx> MiriEvalContextExt<'mir, 'tcx> for MiriEvalContext<'mir, 'tcx> impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { type MemoryKinds = MiriMemoryKind; - type FrameExtra = stacked_borrows::CallId; + type FrameExtra = FrameData<'tcx>; type MemoryExtra = MemoryExtra; type AllocExtra = AllocExtra; type PointerTag = Tag; @@ -173,9 +187,9 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { args: &[OpTy<'tcx, Tag>], dest: Option>, ret: Option, - _unwind: Option, + unwind: Option, ) -> InterpResult<'tcx, Option<&'mir mir::Body<'tcx>>> { - ecx.find_fn(instance, args, dest, ret) + ecx.find_fn(instance, args, dest, ret, unwind) } #[inline(always)] @@ -196,14 +210,10 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { instance: ty::Instance<'tcx>, args: &[OpTy<'tcx, Tag>], dest: Option>, - _ret: Option, - _unwind: Option + ret: Option, + unwind: Option, ) -> InterpResult<'tcx> { - let dest = match dest { - Some(dest) => dest, - None => throw_ub!(Unreachable) - }; - ecx.call_intrinsic(span, instance, args, dest) + ecx.call_intrinsic(span, instance, args, dest, ret, unwind) } #[inline(always)] @@ -352,23 +362,20 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { #[inline(always)] fn stack_push( ecx: &mut InterpCx<'mir, 'tcx, Self>, - ) -> InterpResult<'tcx, stacked_borrows::CallId> { - Ok(ecx.memory.extra.stacked_borrows.borrow_mut().new_call()) + ) -> InterpResult<'tcx, FrameData<'tcx>> { + Ok(FrameData { + call_id: ecx.memory.extra.stacked_borrows.borrow_mut().new_call(), + catch_panic: None, + }) } #[inline(always)] fn stack_pop( ecx: &mut InterpCx<'mir, 'tcx, Self>, - extra: stacked_borrows::CallId, - _unwinding: bool + extra: FrameData<'tcx>, + unwinding: bool ) -> InterpResult<'tcx, StackPopInfo> { - ecx - .memory - .extra - .stacked_borrows - .borrow_mut() - .end_call(extra); - Ok(StackPopInfo::Normal) + ecx.handle_stack_pop(extra, unwinding) } #[inline(always)] diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 55ec36387f2e8..781c5ad40f930 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -1,9 +1,10 @@ use std::{iter, convert::TryInto}; -use rustc::hir::def_id::DefId; use rustc::mir; use rustc::ty::layout::{Align, LayoutOf, Size}; +use rustc::hir::def_id::DefId; use rustc_apfloat::Float; +use rustc::ty; use syntax::attr; use syntax::symbol::sym; @@ -105,13 +106,18 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// Emulates calling a foreign item, failing if the item is not supported. /// This function will handle `goto_block` if needed. + /// Returns Ok(None) if the foreign item was completely handled + /// by this function. + /// Returns Ok(Some(body)) if processing the foreign item + /// is delegated to another function. fn emulate_foreign_item( &mut self, def_id: DefId, args: &[OpTy<'tcx, Tag>], dest: Option>, ret: Option, - ) -> InterpResult<'tcx> { + _unwind: Option + ) -> InterpResult<'tcx, Option<&'mir mir::Body<'tcx>>> { let this = self.eval_context_mut(); let attrs = this.tcx.get_attrs(def_id); let link_name = match attr::first_attr_value_str_by_name(&attrs, sym::link_name) { @@ -124,8 +130,26 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // First: functions that diverge. match link_name { - "__rust_start_panic" | "panic_impl" => { - throw_unsup_format!("the evaluated program panicked"); + // Note that this matches calls to the *foreign* item "__rust_start_panic" - + // that is, calls `extern "Rust" { fn __rust_start_panic(...) }` + // We forward this to the underlying *implementation* in "libpanic_unwind" + "__rust_start_panic" => { + let start_panic_instance = this.resolve_path(&["panic_unwind", "__rust_start_panic"])?; + return Ok(Some(this.load_mir(start_panic_instance.def, None)?)); + } + + // During a normal (non-Miri) compilation, + // this gets resolved to the '#[panic_handler]` function at link time, + // which corresponds to the function with the `#[panic_handler]` attribute. + // + // Since we're interpreting mir, we forward it to the implementation of `panic_impl` + // + // This is used by libcore to forward panics to the actual + // panic impl + "panic_impl" => { + let panic_impl_id = this.tcx.lang_items().panic_impl().unwrap(); + let panic_impl_instance = ty::Instance::mono(*this.tcx, panic_impl_id); + return Ok(Some(this.load_mir(panic_impl_instance.def, None)?)); } "exit" | "ExitProcess" => { // it's really u32 for ExitProcess, but we have to put it into the `Exit` error variant anyway @@ -310,48 +334,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "__rust_maybe_catch_panic" => { - // 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 f = this.read_scalar(args[0])?.not_undef()?; - let data = this.read_scalar(args[1])?.not_undef()?; - let f_instance = this.memory.get_fn(f)?.as_instance()?; - this.write_null(dest)?; - trace!("__rust_maybe_catch_panic: {:?}", f_instance); - - // Now we make a function call. - // TODO: consider making this reusable? `InterpCx::step` does something similar - // for the TLS destructors, and of course `eval_main`. - let mir = this.load_mir(f_instance.def, None)?; - let ret_place = - MPlaceTy::dangling(this.layout_of(tcx.mk_unit())?, this).into(); - this.push_stack_frame( - f_instance, - mir.span, - mir, - Some(ret_place), - // Directly return to caller. - StackPopCleanup::Goto { ret: Some(ret), unwind: None }, - )?; - let mut args = this.frame().body.args_iter(); - - let arg_local = args - .next() - .expect("Argument to __rust_maybe_catch_panic does not take enough arguments."); - let arg_dest = this.local_place(arg_local)?; - this.write_scalar(data, arg_dest)?; - - args.next().expect_none("__rust_maybe_catch_panic argument has more arguments than expected"); - - // We ourselves will return `0`, eventually (because we will not return if we paniced). - this.write_null(dest)?; - - // Don't fall through, we do *not* want to `goto_block`! - return Ok(()); + this.handle_catch_panic(args, dest, ret)?; + return Ok(None) } "memcmp" => { @@ -943,7 +927,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.goto_block(Some(ret))?; this.dump_place(*dest); - Ok(()) + Ok(None) } /// Evaluates the scalar at the specified path. Returns Some(val) diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 20031f837bc38..0e7314c1809f1 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -7,10 +7,7 @@ use rustc::ty::layout::{self, LayoutOf, Size, Align}; use rustc::ty; use syntax::source_map::Span; -use crate::{ - PlaceTy, OpTy, Immediate, Scalar, Tag, - OperatorEvalContextExt -}; +use crate::*; impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { @@ -19,10 +16,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx span: Span, instance: ty::Instance<'tcx>, args: &[OpTy<'tcx, Tag>], - dest: PlaceTy<'tcx, Tag>, + dest: Option>, + _ret: Option, + unwind: Option ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - if this.emulate_intrinsic(span, instance, args, Some(dest))? { + if this.emulate_intrinsic(span, instance, args, dest)? { return Ok(()); } let tcx = &{this.tcx.tcx}; @@ -31,8 +30,27 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // All these intrinsics take raw pointers, so if we access memory directly // (as opposed to through a place), we have to remember to erase any tag // that might still hang around! - let intrinsic_name = &*tcx.item_name(instance.def_id()).as_str(); + + // Handle diverging intrinsics + match intrinsic_name { + "abort" => { + // FIXME: Add a better way of indicating 'abnormal' termination, + // since this is not really an 'unsupported' behavior + throw_unsup_format!("the evaluated program aborted!"); + } + "miri_start_panic" => return this.handle_miri_start_panic(args, unwind), + _ => {} + } + + // Handle non-diverging intrinsics + // The intrinsic itself cannot diverge (otherwise, we would have handled it above), + // so if we got here without a return place... (can happen e.g., for transmute returning `!`) + let dest = match dest { + Some(dest) => dest, + None => throw_ub!(Unreachable) + }; + match intrinsic_name { "arith_offset" => { let offset = this.read_scalar(args[1])?.to_machine_isize(this)?; @@ -526,7 +544,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // However, this only affects direct calls of the intrinsic; calls to the stable // functions wrapping them do get their validation. // FIXME: should we check alignment for ZSTs? - use crate::ScalarMaybeUndef; if !dest.layout.is_zst() { match dest.layout.abi { layout::Abi::Scalar(..) => { diff --git a/src/shims/mod.rs b/src/shims/mod.rs index d9de27596cd0d..f554c19f11c27 100644 --- a/src/shims/mod.rs +++ b/src/shims/mod.rs @@ -5,9 +5,9 @@ pub mod intrinsics; pub mod tls; pub mod fs; pub mod time; +pub mod panic; use rustc::{mir, ty}; - use crate::*; impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} @@ -18,6 +18,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx args: &[OpTy<'tcx, Tag>], dest: Option>, ret: Option, + unwind: Option ) -> InterpResult<'tcx, Option<&'mir mir::Body<'tcx>>> { let this = self.eval_context_mut(); trace!( @@ -26,11 +27,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx dest.map(|place| *place) ); - // First, run the common hooks also supported by CTFE. - if this.hook_panic_fn(instance, args, dest)? { - this.goto_block(ret)?; - return Ok(None); - } // There are some more lang items we want to hook that CTFE does not hook (yet). if this.tcx.lang_items().align_offset_fn() == Some(instance.def.def_id()) { let dest = dest.unwrap(); @@ -44,11 +40,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Try to see if we can do something about foreign items. if this.tcx.is_foreign_item(instance.def_id()) { - // An external function that we cannot find MIR for, but we can still run enough - // of them to make miri viable. - this.emulate_foreign_item(instance.def_id(), args, dest, ret)?; - // `goto_block` already handled. - return Ok(None); + // An external function call that does not have a MIR body. We either find MIR elsewhere + // or emulate its effect. + // This will be Ok(None) if we're emulating the intrinsic entirely within Miri (no need + // to run extra MIR), and Ok(Some(body)) if we found MIR to run for the + // foreign function + // Any needed call to `goto_block` will be performed by `emulate_foreign_item`. + return this.emulate_foreign_item(instance.def_id(), args, dest, ret, unwind); } // Otherwise, load the MIR. diff --git a/src/shims/panic.rs b/src/shims/panic.rs new file mode 100644 index 0000000000000..3e0dd767d8231 --- /dev/null +++ b/src/shims/panic.rs @@ -0,0 +1,179 @@ +use rustc::mir; +use crate::*; +use super::machine::FrameData; +use rustc_target::spec::PanicStrategy; +use crate::rustc_target::abi::LayoutOf; + +/// Holds all of the relevant data for a call to +/// __rust_maybe_catch_panic +/// +/// If a panic occurs, we update this data with +/// the information from the panic site +#[derive(Debug)] +pub struct CatchUnwindData<'tcx> { + /// The 'data' argument passed to `__rust_maybe_catch_panic` + pub data: Pointer, + /// The `data_ptr` argument passed to `__rust_maybe_catch_panic` + pub data_place: MPlaceTy<'tcx, Tag>, + /// The `vtable_ptr` argument passed to `__rust_maybe_catch_panic` + pub vtable_place: MPlaceTy<'tcx, Tag>, + /// The `dest` from the original call to `__rust_maybe_catch_panic` + pub dest: PlaceTy<'tcx, Tag>, + /// The `ret` from the original call to `__rust_maybe_catch_panic` + pub ret: mir::BasicBlock, +} + +impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} +pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { + + /// Handles the special "miri_start_panic" intrinsic, which is called + /// by libpanic_unwind to delegate the actual unwinding process to Miri + #[inline(always)] + fn handle_miri_start_panic( + &mut self, + args: &[OpTy<'tcx, Tag>], + unwind: Option + ) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + + trace!("miri_start_panic: {:?}", this.frame().span); + + if this.tcx.tcx.sess.panic_strategy() == PanicStrategy::Abort { + // FIXME: Add a better way of indicating 'abnormal' termination, + // since this is not really an 'unsupported' behavior + throw_unsup_format!("the evaluated program panicked"); + } + + // Get the raw pointer stored in arg[0] + let scalar = this.read_immediate(args[0])?; + this.machine.panic_payload = Some(scalar); + + // Jump to the unwind block to begin unwinding + // We don't use 'goto_block' - if `unwind` is None, + // we'll end up immediately returning out of the + // function during the next step() call + let next_frame = this.frame_mut(); + next_frame.block = unwind; + next_frame.stmt = 0; + return Ok(()) + } + + #[inline(always)] + fn handle_catch_panic( + &mut self, + args: &[OpTy<'tcx, Tag>], + dest: PlaceTy<'tcx, Tag>, + ret: mir::BasicBlock, + ) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + let tcx = &{this.tcx.tcx}; + + // fn __rust_maybe_catch_panic( + // f: fn(*mut u8), + // data: *mut u8, + // data_ptr: *mut usize, + // vtable_ptr: *mut usize, + // ) -> u32 + let f = this.read_scalar(args[0])?.not_undef()?; + let data = this.read_scalar(args[1])?.not_undef()?; + let data_place = this.deref_operand(args[2])?; + let vtable_place = this.deref_operand(args[3])?; + let f_instance = this.memory.get_fn(f)?.as_instance()?; + this.write_null(dest)?; + trace!("__rust_maybe_catch_panic: {:?}", f_instance); + + + // Now we make a function call. + // TODO: consider making this reusable? `InterpCx::step` does something similar + // for the TLS destructors, and of course `eval_main`. + let mir = this.load_mir(f_instance.def, None)?; + let ret_place = + MPlaceTy::dangling(this.layout_of(tcx.mk_unit())?, this).into(); + this.push_stack_frame( + f_instance, + mir.span, + mir, + Some(ret_place), + // Directly return to caller. + StackPopCleanup::Goto { ret: Some(ret), unwind: None }, + )?; + + // In unwind mode, we tag this frame with some extra data. + // This lets `handle_stack_pop` (below) know that we should stop unwinding + // when we pop this frame. + if this.tcx.tcx.sess.panic_strategy() == PanicStrategy::Unwind { + this.frame_mut().extra.catch_panic = Some(CatchUnwindData { + data: data.to_ptr()?, + data_place, + vtable_place, + dest, + ret, + }) + } + + let mut args = this.frame().body.args_iter(); + + let arg_local = args + .next() + .expect("Argument to __rust_maybe_catch_panic does not take enough arguments."); + let arg_dest = this.local_place(arg_local)?; + this.write_scalar(data, arg_dest)?; + + args.next().expect_none("__rust_maybe_catch_panic argument has more arguments than expected"); + + // We ourselves will return `0`, eventually (because we will not return if we paniced). + this.write_null(dest)?; + + return Ok(()); + } + + #[inline(always)] + fn handle_stack_pop( + &mut self, + mut extra: FrameData<'tcx>, + unwinding: bool + ) -> InterpResult<'tcx, StackPopInfo> { + let this = self.eval_context_mut(); + + trace!("handle_stack_pop(extra = {:?}, unwinding = {})", extra, unwinding); + + // We only care about `catch_panic` if we're unwinding - if we're doing a normal + // return, then we don't need to do anything special. + let res = if let (true, Some(unwind_data)) = (unwinding, extra.catch_panic.take()) { + // We've just popped the frame that was immediately above + // the frame which originally called `__rust_maybe_catch_panic` + trace!("unwinding: found catch_panic frame: {:?}", this.frame().span); + + // `panic_payload` now holds a '*mut (dyn Any + Send)', + // provided by the `miri_start_panic` intrinsic. + // We want to split this into its consituient parts - + // the data and vtable pointers - and store them back + // into the panic handler frame + let real_ret = this.machine.panic_payload.take().unwrap(); + + let payload = this.ref_to_mplace(real_ret)?; + let payload_data_place = payload.ptr; + let payload_vtable_place = payload.meta.expect("Expected fat pointer"); + + + let data_place = unwind_data.data_place; + let vtable_place = unwind_data.vtable_place; + let dest = unwind_data.dest; + + // Here, we write to the pointers provided to the call + // to '__rust_maybe_catch_panic`. + this.write_scalar(payload_data_place, data_place.into())?; + this.write_scalar(payload_vtable_place, vtable_place.into())?; + + // We set the return value of `__rust_maybe_catch_panic` to 1, + // since there was a panic. + this.write_scalar(Scalar::from_int(1, dest.layout.size), dest)?; + + StackPopInfo::StopUnwinding + } else { + StackPopInfo::Normal + }; + this.memory.extra.stacked_borrows.borrow_mut().end_call(extra.call_id); + Ok(res) + } +} diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 0ab9dabab9b78..3b821c7155a6f 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -532,7 +532,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx protect: bool, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - let protector = if protect { Some(this.frame().extra) } else { None }; + let protector = if protect { Some(this.frame().extra.call_id) } else { None }; let ptr = place.ptr.to_ptr().expect("we should have a proper pointer"); trace!("reborrow: {} reference {:?} derived from {:?} (pointee {}): {:?}, size {}", kind, new_tag, ptr.tag, place.layout.ty, ptr.erase_tag(), size.bytes()); diff --git a/tests/compile-fail/double_panic.rs b/tests/compile-fail/double_panic.rs new file mode 100644 index 0000000000000..950d865c2a562 --- /dev/null +++ b/tests/compile-fail/double_panic.rs @@ -0,0 +1,11 @@ + //error-pattern: the evaluated program aborted +struct Foo; +impl Drop for Foo { + fn drop(&mut self) { + panic!("second"); + } +} +fn main() { + let _foo = Foo; + panic!("first"); +} diff --git a/tests/compile-fail/panic1.rs b/tests/compile-fail/panic1.rs index 1163c8708287c..ff499316920f8 100644 --- a/tests/compile-fail/panic1.rs +++ b/tests/compile-fail/panic1.rs @@ -1,5 +1,5 @@ -//error-pattern: the evaluated program panicked - +// error-pattern: the evaluated program panicked +// compile-flags: -C panic=abort fn main() { std::panic!("panicking from libstd"); } diff --git a/tests/compile-fail/panic2.rs b/tests/compile-fail/panic2.rs index e643e69224139..3b36db2d2d81d 100644 --- a/tests/compile-fail/panic2.rs +++ b/tests/compile-fail/panic2.rs @@ -1,4 +1,5 @@ -//error-pattern: the evaluated program panicked +// error-pattern: the evaluated program panicked +// compile-flags: -C panic=abort fn main() { std::panic!("{}-panicking from libstd", 42); diff --git a/tests/compile-fail/panic3.rs b/tests/compile-fail/panic3.rs index b22f95d9c69d1..6f5d6c3e1ce34 100644 --- a/tests/compile-fail/panic3.rs +++ b/tests/compile-fail/panic3.rs @@ -1,4 +1,5 @@ //error-pattern: the evaluated program panicked +// compile-flags: -C panic=abort fn main() { core::panic!("panicking from libcore"); diff --git a/tests/compile-fail/panic4.rs b/tests/compile-fail/panic4.rs index 449e716e161cf..22d675375ac42 100644 --- a/tests/compile-fail/panic4.rs +++ b/tests/compile-fail/panic4.rs @@ -1,4 +1,5 @@ //error-pattern: the evaluated program panicked +// compile-flags: -C panic=abort fn main() { core::panic!("{}-panicking from libcore", 42); diff --git a/tests/run-pass/catch_panic.rs b/tests/run-pass/catch_panic.rs new file mode 100644 index 0000000000000..8e254385d4743 --- /dev/null +++ b/tests/run-pass/catch_panic.rs @@ -0,0 +1,61 @@ +use std::panic::catch_unwind; +use std::cell::Cell; + +thread_local! { + static MY_COUNTER: Cell = Cell::new(0); + static DROPPED: Cell = Cell::new(false); + static HOOK_CALLED: Cell = Cell::new(false); +} + +struct DropTester; + +impl Drop for DropTester { + fn drop(&mut self) { + DROPPED.with(|c| { + c.set(true); + }); + } +} + +fn do_panic_counter() { + // If this gets leaked, it will be easy to spot + // in Miri's leak report + let _string = "LEAKED FROM do_panic_counter".to_string(); + + // When we panic, this should get dropped during unwinding + let _drop_tester = DropTester; + + // Check for bugs in Miri's panic implementation. + // If do_panic_counter() somehow gets called more than once, + // we'll generate a different panic message + let old_val = MY_COUNTER.with(|c| { + let val = c.get(); + c.set(val + 1); + val + }); + panic!(format!("Hello from panic: {:?}", old_val)); +} + +fn main() { + std::panic::set_hook(Box::new(|_panic_info| { + HOOK_CALLED.with(|h| h.set(true)); + })); + let res = catch_unwind(|| { + let _string = "LEAKED FROM CLOSURE".to_string(); + do_panic_counter() + }); + let expected: Box = Box::new("Hello from panic: 0".to_string()); + let actual = res.expect_err("do_panic() did not panic!") + .downcast::().expect("Failed to cast to string!"); + + assert_eq!(expected, actual); + DROPPED.with(|c| { + // This should have been set to 'true' by DropTester + assert!(c.get()); + }); + + HOOK_CALLED.with(|h| { + assert!(h.get()); + }); +} + diff --git a/tests/run-pass/panic1.rs b/tests/run-pass/panic1.rs new file mode 100644 index 0000000000000..b9bb52b95b13f --- /dev/null +++ b/tests/run-pass/panic1.rs @@ -0,0 +1,3 @@ +fn main() { + panic!("Miri panic!"); +} diff --git a/tests/run-pass/panic1.stderr b/tests/run-pass/panic1.stderr new file mode 100644 index 0000000000000..a29ba479825a7 --- /dev/null +++ b/tests/run-pass/panic1.stderr @@ -0,0 +1 @@ +thread 'main' panicked at 'Miri panic!', $DIR/panic1.rs:2:5 diff --git a/tests/run-pass/panic2.rs b/tests/run-pass/panic2.rs new file mode 100644 index 0000000000000..9a1da6656c26d --- /dev/null +++ b/tests/run-pass/panic2.rs @@ -0,0 +1,4 @@ +fn main() { + let val = "Value".to_string(); + panic!("Miri panic with value: {}", val); +} diff --git a/tests/run-pass/panic2.stderr b/tests/run-pass/panic2.stderr new file mode 100644 index 0000000000000..de70fd4d583e9 --- /dev/null +++ b/tests/run-pass/panic2.stderr @@ -0,0 +1 @@ +thread 'main' panicked at 'Miri panic with value: Value', $DIR/panic2.rs:3:5 From b06d99b8a00a2b1433b0ccaabe4b4b86bdd786b2 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Sun, 17 Nov 2019 08:40:34 -0500 Subject: [PATCH 1318/3747] Ignore '-C panic=abort' tests for now We are currently building `libpanic_abort` with the wrong panic strategy, due to Xargo missing a hack used by `bootstrap`. --- tests/compile-fail/panic1.rs | 1 + tests/compile-fail/panic2.rs | 1 + tests/compile-fail/panic3.rs | 1 + tests/compile-fail/panic4.rs | 1 + 4 files changed, 4 insertions(+) diff --git a/tests/compile-fail/panic1.rs b/tests/compile-fail/panic1.rs index ff499316920f8..4a1bb11483ca7 100644 --- a/tests/compile-fail/panic1.rs +++ b/tests/compile-fail/panic1.rs @@ -1,3 +1,4 @@ +// ignore-test: Abort panics are not yet supported // error-pattern: the evaluated program panicked // compile-flags: -C panic=abort fn main() { diff --git a/tests/compile-fail/panic2.rs b/tests/compile-fail/panic2.rs index 3b36db2d2d81d..ce4471c0effc2 100644 --- a/tests/compile-fail/panic2.rs +++ b/tests/compile-fail/panic2.rs @@ -1,3 +1,4 @@ +// ignore-test: Abort panics are not yet supported // error-pattern: the evaluated program panicked // compile-flags: -C panic=abort diff --git a/tests/compile-fail/panic3.rs b/tests/compile-fail/panic3.rs index 6f5d6c3e1ce34..842a0f5435b74 100644 --- a/tests/compile-fail/panic3.rs +++ b/tests/compile-fail/panic3.rs @@ -1,3 +1,4 @@ +// ignore-test: Abort panics are not yet supported //error-pattern: the evaluated program panicked // compile-flags: -C panic=abort diff --git a/tests/compile-fail/panic4.rs b/tests/compile-fail/panic4.rs index 22d675375ac42..816cc90cfabd8 100644 --- a/tests/compile-fail/panic4.rs +++ b/tests/compile-fail/panic4.rs @@ -1,3 +1,4 @@ +// ignore-test: Abort panics are not yet supported //error-pattern: the evaluated program panicked // compile-flags: -C panic=abort From b5235dea7f3252087569361f07ae0bab71e5ae8d Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Sun, 17 Nov 2019 11:09:16 -0500 Subject: [PATCH 1319/3747] Add #[should_panic] test --- test-cargo-miri/tests/test.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/test-cargo-miri/tests/test.rs b/test-cargo-miri/tests/test.rs index cfbe3f6d7fb66..bc00cb6a765c5 100644 --- a/test-cargo-miri/tests/test.rs +++ b/test-cargo-miri/tests/test.rs @@ -41,3 +41,9 @@ fn entropy_rng() { fn num_cpus() { assert_eq!(num_cpus::get(), 1); } + +#[test] +#[should_panic] +fn do_panic() { // In large, friendly letters :) + panic!("Explicit panic from test!"); +} From 660cd55cc74a6c391cf817d771181eeaa736967b Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Sun, 17 Nov 2019 11:49:31 -0500 Subject: [PATCH 1320/3747] Update captured test output --- test-cargo-miri/test.stdout.ref | 5 +++-- test-cargo-miri/test.stdout.ref2 | 2 +- test-cargo-miri/test.stdout.ref3 | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/test-cargo-miri/test.stdout.ref b/test-cargo-miri/test.stdout.ref index c2257e68e256c..827e2f93237bc 100644 --- a/test-cargo-miri/test.stdout.ref +++ b/test-cargo-miri/test.stdout.ref @@ -5,11 +5,12 @@ test test::rng ... ok test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out -running 4 tests +running 5 tests +test do_panic ... ok test entropy_rng ... ok test num_cpus ... ok test simple1 ... ok test simple2 ... ok -test result: ok. 4 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out +test result: ok. 5 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out diff --git a/test-cargo-miri/test.stdout.ref2 b/test-cargo-miri/test.stdout.ref2 index a6f6e915e0e85..e070941c36ec8 100644 --- a/test-cargo-miri/test.stdout.ref2 +++ b/test-cargo-miri/test.stdout.ref2 @@ -7,5 +7,5 @@ test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 1 filtered out running 1 test test simple1 ... ok -test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 3 filtered out +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 4 filtered out diff --git a/test-cargo-miri/test.stdout.ref3 b/test-cargo-miri/test.stdout.ref3 index f0d8afbd0e8e4..a4a1a7812aea8 100644 --- a/test-cargo-miri/test.stdout.ref3 +++ b/test-cargo-miri/test.stdout.ref3 @@ -7,5 +7,5 @@ test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 1 filtered out running 1 test test num_cpus ... ok -test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 3 filtered out +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 4 filtered out From 80f9484c8680e54a31916d6410a5eea2ddb1e237 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Sun, 17 Nov 2019 13:47:06 -0500 Subject: [PATCH 1321/3747] Disable panic tests on Windows Miri currently does not support `GetProcAddress` and `GetModuleHandleW`, both of which end up getting invoked by the libstd panic hook. --- tests/run-pass/catch_panic.rs | 1 + tests/run-pass/panic1.rs | 1 + tests/run-pass/panic1.stderr | 2 +- tests/run-pass/panic2.rs | 1 + tests/run-pass/panic2.stderr | 2 +- 5 files changed, 5 insertions(+), 2 deletions(-) diff --git a/tests/run-pass/catch_panic.rs b/tests/run-pass/catch_panic.rs index 8e254385d4743..228317e893695 100644 --- a/tests/run-pass/catch_panic.rs +++ b/tests/run-pass/catch_panic.rs @@ -1,3 +1,4 @@ +// ignore-windows: Unwind panicking does not currently work on Windows use std::panic::catch_unwind; use std::cell::Cell; diff --git a/tests/run-pass/panic1.rs b/tests/run-pass/panic1.rs index b9bb52b95b13f..261db018d6da0 100644 --- a/tests/run-pass/panic1.rs +++ b/tests/run-pass/panic1.rs @@ -1,3 +1,4 @@ +// ignore-windows: Unwind panicking does not currently work on Windows fn main() { panic!("Miri panic!"); } diff --git a/tests/run-pass/panic1.stderr b/tests/run-pass/panic1.stderr index a29ba479825a7..b1607dd864fb8 100644 --- a/tests/run-pass/panic1.stderr +++ b/tests/run-pass/panic1.stderr @@ -1 +1 @@ -thread 'main' panicked at 'Miri panic!', $DIR/panic1.rs:2:5 +thread 'main' panicked at 'Miri panic!', $DIR/panic1.rs:3:5 diff --git a/tests/run-pass/panic2.rs b/tests/run-pass/panic2.rs index 9a1da6656c26d..deaf606d9a2e0 100644 --- a/tests/run-pass/panic2.rs +++ b/tests/run-pass/panic2.rs @@ -1,3 +1,4 @@ +// ignore-windows: Unwind panicking does not currently work on Windows fn main() { let val = "Value".to_string(); panic!("Miri panic with value: {}", val); diff --git a/tests/run-pass/panic2.stderr b/tests/run-pass/panic2.stderr index de70fd4d583e9..bc5df83ec0f07 100644 --- a/tests/run-pass/panic2.stderr +++ b/tests/run-pass/panic2.stderr @@ -1 +1 @@ -thread 'main' panicked at 'Miri panic with value: Value', $DIR/panic2.rs:3:5 +thread 'main' panicked at 'Miri panic with value: Value', $DIR/panic2.rs:4:5 From 52b18b44f9032d0e311ca09a84956734a76ae53d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 18 Nov 2019 15:10:17 +0100 Subject: [PATCH 1322/3747] bump compiletest; remove unused feature --- Cargo.lock | 12 ++++++------ Cargo.toml | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c930566c86a5b..bc122e3debd71 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -157,7 +157,7 @@ dependencies = [ [[package]] name = "compiletest_rs" -version = "0.3.25" +version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "diff 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", @@ -172,7 +172,7 @@ dependencies = [ "serde_derive 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "tester 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "tester 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -347,7 +347,7 @@ dependencies = [ "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "cargo_metadata 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "colored 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "compiletest_rs 0.3.25 (registry+https://github.com/rust-lang/crates.io-index)", + "compiletest_rs 0.3.26 (registry+https://github.com/rust-lang/crates.io-index)", "directories 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "getrandom 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", @@ -700,7 +700,7 @@ dependencies = [ [[package]] name = "tester" -version = "0.5.1" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "getopts 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", @@ -819,7 +819,7 @@ dependencies = [ "checksum chrono 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e8493056968583b0193c1bb04d6f7684586f3726992d6c573261941a895dbd68" "checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" "checksum colored 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6cdb90b60f2927f8d76139c72dbde7e10c3a2bc47c8594c9c7a66529f2687c03" -"checksum compiletest_rs 0.3.25 (registry+https://github.com/rust-lang/crates.io-index)" = "f75b10a18fb53549fdd090846eb01c7f8593914494d1faabc4d3005c436e417a" +"checksum compiletest_rs 0.3.26 (registry+https://github.com/rust-lang/crates.io-index)" = "d7d8975604ebad8b6660796802377eb6495045c5606168fc1b8d19a4dd9bfa46" "checksum constant_time_eq 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "995a44c877f9212528ccc74b21a232f66ad69001e40ede5bcee2ac9ef2657120" "checksum crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)" = "04973fa96e96579258a5091af6003abde64af786b860f18622b82e026cca60e6" "checksum diff 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "3c2b69f912779fbb121ceb775d74d51e915af17aaebc38d28a592843a2dd0a3a" @@ -882,7 +882,7 @@ dependencies = [ "checksum tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9" "checksum term 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c0863a3345e70f61d613eab32ee046ccd1bcc5f9105fe402c61fcd0c13eeb8b5" "checksum termcolor 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "96d6098003bde162e4277c70665bd87c326f5a0c3f3fbfb285787fa482d54e6e" -"checksum tester 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cd0d1044cb5ca390e9c93f8c35abd2c55484397dfd786f189321aa34605ee6ab" +"checksum tester 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7647e6d732eb84375d8e7abda37818f81861ddbfc7235e33f4983cb254b71e4f" "checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b" "checksum time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f" "checksum unicode-width 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7007dbd421b92cc6e28410fe7362e2e0a2503394908f417b68ec8d1c364c4e20" diff --git a/Cargo.toml b/Cargo.toml index 8a09bb7ac1787..01516d3589130 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -59,5 +59,5 @@ cargo_miri = ["cargo_metadata", "directories", "rustc_version"] rustc_tests = [] [dev-dependencies] -compiletest_rs = { version = "0.3.24", features = ["tmp", "stable"] } +compiletest_rs = { version = "0.3.26", features = ["tmp"] } colored = "1.6" From 82374ad9bd73178947348206bc7ed463b5a8a982 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 19 Nov 2019 14:51:08 +0100 Subject: [PATCH 1323/3747] comments and slight refactoring --- rust-version | 2 +- src/helpers.rs | 1 + src/machine.rs | 9 ++-- src/shims/foreign_items.rs | 18 +++---- src/shims/intrinsics.rs | 2 +- src/shims/panic.rs | 106 ++++++++++++++++++------------------- 6 files changed, 67 insertions(+), 71 deletions(-) diff --git a/rust-version b/rust-version index 0d6f14df928cb..093065aab2c0a 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -8831d766ace89bc74714918a7d9fbd3ca5ec946a +3e525e3f6d9e85d54fa4c49b52df85aa0c990100 diff --git a/src/helpers.rs b/src/helpers.rs index cff78859df8df..20f21cfc255c7 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -53,6 +53,7 @@ fn resolve_did<'mir, 'tcx>(tcx: TyCtxt<'tcx>, path: &[&str]) -> InterpResult<'tc pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { + /// Gets an instance for a path. fn resolve_path(&self, path: &[&str]) -> InterpResult<'tcx, ty::Instance<'tcx>> { Ok(ty::Instance::mono(self.eval_context_ref().tcx.tcx, resolve_did(self.eval_context_ref().tcx.tcx, path)?)) } diff --git a/src/machine.rs b/src/machine.rs index 8910c589ee70e..cb65817035716 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -25,10 +25,11 @@ pub const NUM_CPUS: u64 = 1; pub struct FrameData<'tcx> { /// Extra data for Stacked Borrows. pub call_id: stacked_borrows::CallId, - /// If this is Some(), then this is a special 'catch unwind' - /// frame. When this frame is popped during unwinding a panic, - /// we stop unwinding, and use the `CatchUnwindData` to - /// store the panic payload and continue execution in the parent frame. + + /// If this is Some(), then this is a special "catch unwind" frame (the frame of the closure + /// called by `__rustc_maybe_catch_panic`). When this frame is popped during unwinding a panic, + /// we stop unwinding, use the `CatchUnwindData` to + /// store the panic payload, and continue execution in the parent frame. pub catch_panic: Option>, } diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 781c5ad40f930..3a95ffd78e31a 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -130,27 +130,21 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // First: functions that diverge. match link_name { - // Note that this matches calls to the *foreign* item "__rust_start_panic" - - // that is, calls `extern "Rust" { fn __rust_start_panic(...) }` - // We forward this to the underlying *implementation* in "libpanic_unwind" + // Note that this matches calls to the *foreign* item `__rust_start_panic* - + // that is, calls to `extern "Rust" { fn __rust_start_panic(...) }`. + // We forward this to the underlying *implementation* in "libpanic_unwind". "__rust_start_panic" => { let start_panic_instance = this.resolve_path(&["panic_unwind", "__rust_start_panic"])?; return Ok(Some(this.load_mir(start_panic_instance.def, None)?)); } - - // During a normal (non-Miri) compilation, - // this gets resolved to the '#[panic_handler]` function at link time, - // which corresponds to the function with the `#[panic_handler]` attribute. - // - // Since we're interpreting mir, we forward it to the implementation of `panic_impl` - // - // This is used by libcore to forward panics to the actual - // panic impl + // Similarly, we forward calls to the `panic_impl` foreign item to its implementation. + // The implementation is provided by the function with the `#[panic_handler]` attribute. "panic_impl" => { let panic_impl_id = this.tcx.lang_items().panic_impl().unwrap(); let panic_impl_instance = ty::Instance::mono(*this.tcx, panic_impl_id); return Ok(Some(this.load_mir(panic_impl_instance.def, None)?)); } + "exit" | "ExitProcess" => { // it's really u32 for ExitProcess, but we have to put it into the `Exit` error variant anyway let code = this.read_scalar(args[0])?.to_i32()?; diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 0e7314c1809f1..5e1f3cff1c77c 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -45,7 +45,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Handle non-diverging intrinsics // The intrinsic itself cannot diverge (otherwise, we would have handled it above), - // so if we got here without a return place... (can happen e.g., for transmute returning `!`) + // so if we got here without a return place that's UB (can happen e.g., for transmute returning `!`). let dest = match dest { Some(dest) => dest, None => throw_ub!(Unreachable) diff --git a/src/shims/panic.rs b/src/shims/panic.rs index 3e0dd767d8231..9c5c32491915b 100644 --- a/src/shims/panic.rs +++ b/src/shims/panic.rs @@ -1,3 +1,16 @@ +//! Panic runtime for Miri. +//! +//! The core pieces of the runtime are: +//! - An implementation of `__rust_maybe_catch_panic` that pushes the invoked stack frame with +//! some extra metadata derived from the panic-catching arguments of `__rust_maybe_catch_panic`. +//! - A hack in `libpanic_unwind` that calls the `miri_start_panic` intrinsic instead of the +//! target-native panic runtime. (This lives in the rustc repo.) +//! - An implementation of `miri_start_panic` that stores its argument (the panic payload), and then +//! immediately returns, but on the *unwind* edge (not the normal return edge), thus initiating unwinding. +//! - A hook executed each time a frame is popped, such that if the frame pushed by `__rust_maybe_catch_panic` +//! gets popped *during unwinding*, we take the panic payload and store it according to the extra +//! metadata we remembered when pushing said frame. + use rustc::mir; use crate::*; use super::machine::FrameData; @@ -5,29 +18,25 @@ use rustc_target::spec::PanicStrategy; use crate::rustc_target::abi::LayoutOf; /// Holds all of the relevant data for a call to -/// __rust_maybe_catch_panic +/// `__rust_maybe_catch_panic`. /// /// If a panic occurs, we update this data with -/// the information from the panic site +/// the information from the panic site. #[derive(Debug)] pub struct CatchUnwindData<'tcx> { - /// The 'data' argument passed to `__rust_maybe_catch_panic` - pub data: Pointer, - /// The `data_ptr` argument passed to `__rust_maybe_catch_panic` + /// The dereferenced `data_ptr` argument passed to `__rust_maybe_catch_panic`. pub data_place: MPlaceTy<'tcx, Tag>, - /// The `vtable_ptr` argument passed to `__rust_maybe_catch_panic` + /// The dereferenced `vtable_ptr` argument passed to `__rust_maybe_catch_panic`. pub vtable_place: MPlaceTy<'tcx, Tag>, - /// The `dest` from the original call to `__rust_maybe_catch_panic` + /// The `dest` from the original call to `__rust_maybe_catch_panic`. pub dest: PlaceTy<'tcx, Tag>, - /// The `ret` from the original call to `__rust_maybe_catch_panic` - pub ret: mir::BasicBlock, } impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { /// Handles the special "miri_start_panic" intrinsic, which is called - /// by libpanic_unwind to delegate the actual unwinding process to Miri + /// by libpanic_unwind to delegate the actual unwinding process to Miri. #[inline(always)] fn handle_miri_start_panic( &mut self, @@ -44,14 +53,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx throw_unsup_format!("the evaluated program panicked"); } - // Get the raw pointer stored in arg[0] + // Get the raw pointer stored in arg[0] (the panic payload). let scalar = this.read_immediate(args[0])?; + assert!(this.machine.panic_payload.is_none(), "the panic runtime should avoid double-panics"); this.machine.panic_payload = Some(scalar); - // Jump to the unwind block to begin unwinding - // We don't use 'goto_block' - if `unwind` is None, - // we'll end up immediately returning out of the - // function during the next step() call + // Jump to the unwind block to begin unwinding. + // We don't use `goto_block` as that is just meant for normal returns. let next_frame = this.frame_mut(); next_frame.block = unwind; next_frame.stmt = 0; @@ -74,16 +82,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // data_ptr: *mut usize, // vtable_ptr: *mut usize, // ) -> u32 + + // Get all the arguments. let f = this.read_scalar(args[0])?.not_undef()?; - let data = this.read_scalar(args[1])?.not_undef()?; + let f_arg = this.read_scalar(args[1])?.not_undef()?; let data_place = this.deref_operand(args[2])?; let vtable_place = this.deref_operand(args[3])?; + + // Now we make a function call, and pass `f_arg` as first and only argument. let f_instance = this.memory.get_fn(f)?.as_instance()?; - this.write_null(dest)?; trace!("__rust_maybe_catch_panic: {:?}", f_instance); - - - // Now we make a function call. // TODO: consider making this reusable? `InterpCx::step` does something similar // for the TLS destructors, and of course `eval_main`. let mir = this.load_mir(f_instance.def, None)?; @@ -98,32 +106,30 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx StackPopCleanup::Goto { ret: Some(ret), unwind: None }, )?; + let mut args = this.frame().body.args_iter(); + // First argument. + let arg_local = args + .next() + .expect("Argument to __rust_maybe_catch_panic does not take enough arguments."); + let arg_dest = this.local_place(arg_local)?; + this.write_scalar(f_arg, arg_dest)?; + // No more arguments. + args.next().expect_none("__rust_maybe_catch_panic argument has more arguments than expected"); + + // We ourselves will return `0`, eventually (will be overwritten if we catch a panic). + this.write_null(dest)?; + // In unwind mode, we tag this frame with some extra data. // This lets `handle_stack_pop` (below) know that we should stop unwinding // when we pop this frame. if this.tcx.tcx.sess.panic_strategy() == PanicStrategy::Unwind { this.frame_mut().extra.catch_panic = Some(CatchUnwindData { - data: data.to_ptr()?, data_place, vtable_place, dest, - ret, }) } - let mut args = this.frame().body.args_iter(); - - let arg_local = args - .next() - .expect("Argument to __rust_maybe_catch_panic does not take enough arguments."); - let arg_dest = this.local_place(arg_local)?; - this.write_scalar(data, arg_dest)?; - - args.next().expect_none("__rust_maybe_catch_panic argument has more arguments than expected"); - - // We ourselves will return `0`, eventually (because we will not return if we paniced). - this.write_null(dest)?; - return Ok(()); } @@ -140,33 +146,27 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // We only care about `catch_panic` if we're unwinding - if we're doing a normal // return, then we don't need to do anything special. let res = if let (true, Some(unwind_data)) = (unwinding, extra.catch_panic.take()) { - // We've just popped the frame that was immediately above - // the frame which originally called `__rust_maybe_catch_panic` - trace!("unwinding: found catch_panic frame: {:?}", this.frame().span); + // We've just popped a frame that was pushed by `__rust_maybe_catch_panic`, + // and we are unwinding, so we should catch that. + trace!("unwinding: found catch_panic frame during unwinding: {:?}", this.frame().span); - // `panic_payload` now holds a '*mut (dyn Any + Send)', + // `panic_payload` now holds a `*mut (dyn Any + Send)`, // provided by the `miri_start_panic` intrinsic. // We want to split this into its consituient parts - - // the data and vtable pointers - and store them back - // into the panic handler frame - let real_ret = this.machine.panic_payload.take().unwrap(); - - let payload = this.ref_to_mplace(real_ret)?; + // the data and vtable pointers - and store them according to + // `unwind_data`, i.e., we store them where `__rust_maybe_catch_panic` + // was told to put them. + let payload = this.machine.panic_payload.take().unwrap(); + let payload = this.ref_to_mplace(payload)?; let payload_data_place = payload.ptr; let payload_vtable_place = payload.meta.expect("Expected fat pointer"); - - let data_place = unwind_data.data_place; - let vtable_place = unwind_data.vtable_place; - let dest = unwind_data.dest; - - // Here, we write to the pointers provided to the call - // to '__rust_maybe_catch_panic`. - this.write_scalar(payload_data_place, data_place.into())?; - this.write_scalar(payload_vtable_place, vtable_place.into())?; + this.write_scalar(payload_data_place, unwind_data.data_place.into())?; + this.write_scalar(payload_vtable_place, unwind_data.vtable_place.into())?; // We set the return value of `__rust_maybe_catch_panic` to 1, // since there was a panic. + let dest = unwind_data.dest; this.write_scalar(Scalar::from_int(1, dest.layout.size), dest)?; StackPopInfo::StopUnwinding From 8936d67e7f7a6ab1318e6179ac3b839ffb47b430 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Tue, 19 Nov 2019 10:11:25 -0500 Subject: [PATCH 1324/3747] Delegate to the actual panic runtime crate --- src/shims/foreign_items.rs | 3 ++- src/shims/panic.rs | 7 ------- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 3a95ffd78e31a..130c5d28fff3a 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -134,7 +134,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // that is, calls to `extern "Rust" { fn __rust_start_panic(...) }`. // We forward this to the underlying *implementation* in "libpanic_unwind". "__rust_start_panic" => { - let start_panic_instance = this.resolve_path(&["panic_unwind", "__rust_start_panic"])?; + let panic_runtime = tcx.crate_name(tcx.injected_panic_runtime().expect("No panic runtime found!")); + let start_panic_instance = this.resolve_path(&[&*panic_runtime.as_str(), "__rust_start_panic"])?; return Ok(Some(this.load_mir(start_panic_instance.def, None)?)); } // Similarly, we forward calls to the `panic_impl` foreign item to its implementation. diff --git a/src/shims/panic.rs b/src/shims/panic.rs index 9c5c32491915b..ef9843056a08b 100644 --- a/src/shims/panic.rs +++ b/src/shims/panic.rs @@ -47,13 +47,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx trace!("miri_start_panic: {:?}", this.frame().span); - if this.tcx.tcx.sess.panic_strategy() == PanicStrategy::Abort { - // FIXME: Add a better way of indicating 'abnormal' termination, - // since this is not really an 'unsupported' behavior - throw_unsup_format!("the evaluated program panicked"); - } - - // Get the raw pointer stored in arg[0] (the panic payload). let scalar = this.read_immediate(args[0])?; assert!(this.machine.panic_payload.is_none(), "the panic runtime should avoid double-panics"); this.machine.panic_payload = Some(scalar); From a4eb34b3e1e93df4a5ab7645a480bbcffd8b71ef Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 19 Nov 2019 20:40:06 +0100 Subject: [PATCH 1325/3747] generalize readme --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 6d0173aaf04e3..5a85b6d478557 100644 --- a/README.md +++ b/README.md @@ -61,8 +61,8 @@ rustup component add miri If `rustup` says the `miri` component is unavailable, that's because not all nightly releases come with all tools. Check out [this website](https://rust-lang.github.io/rustup-components-history) to -determine a nightly version that comes with Miri and install that, e.g. using -`rustup install nightly-2019-03-28`. +determine a nightly version that comes with Miri and install that using +`rustup install nightly-YYYY-MM-DD`. Now you can run your project in Miri: From e02dc4af4bf3104574f5fe96f1b51cb27f65c508 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Tue, 19 Nov 2019 15:31:37 -0500 Subject: [PATCH 1326/3747] Re-add comment --- src/shims/panic.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/shims/panic.rs b/src/shims/panic.rs index ef9843056a08b..59ff1a870d105 100644 --- a/src/shims/panic.rs +++ b/src/shims/panic.rs @@ -47,6 +47,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx trace!("miri_start_panic: {:?}", this.frame().span); + // Get the raw pointer stored in arg[0] (the panic payload). let scalar = this.read_immediate(args[0])?; assert!(this.machine.panic_payload.is_none(), "the panic runtime should avoid double-panics"); this.machine.panic_payload = Some(scalar); From 2750f60d4f4c8090bd0d0230c074fc7d1e2b5a6e Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Tue, 19 Nov 2019 15:33:14 -0500 Subject: [PATCH 1327/3747] Update panic runtime comment --- src/shims/foreign_items.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 130c5d28fff3a..48d98141b8ad3 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -132,7 +132,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx match link_name { // Note that this matches calls to the *foreign* item `__rust_start_panic* - // that is, calls to `extern "Rust" { fn __rust_start_panic(...) }`. - // We forward this to the underlying *implementation* in "libpanic_unwind". + // We forward this to the underlying *implementation* in the panic runtime crate. + // Normally, this will be either `libpanic_unwind` or `libpanic_abort`, but it could + // also be a custom user-provided implementation via `#![feature(panic_runtime)]` "__rust_start_panic" => { let panic_runtime = tcx.crate_name(tcx.injected_panic_runtime().expect("No panic runtime found!")); let start_panic_instance = this.resolve_path(&[&*panic_runtime.as_str(), "__rust_start_panic"])?; From 6fe89e45f44df216911de48958aed38965b0de1c Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Tue, 19 Nov 2019 15:55:12 -0500 Subject: [PATCH 1328/3747] Disable #[should_panic] test on Windows We should re-enable this once https://github.com/rust-lang/miri/issues/1059 is fixed --- test-cargo-miri/tests/test.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/test-cargo-miri/tests/test.rs b/test-cargo-miri/tests/test.rs index bc00cb6a765c5..5d1beaec9806f 100644 --- a/test-cargo-miri/tests/test.rs +++ b/test-cargo-miri/tests/test.rs @@ -42,8 +42,13 @@ fn num_cpus() { assert_eq!(num_cpus::get(), 1); } + +// FIXME: Remove this `cfg` once we fix https://github.com/rust-lang/miri/issues/1059 +// We cfg-gate the `should_panic` attribute and the `panic!` itself, so that the test +// stdout does not depend on the platform #[test] -#[should_panic] +#[cfg_attr(not(windows), should_panic)] fn do_panic() { // In large, friendly letters :) + #[cfg(not(windows))] panic!("Explicit panic from test!"); } From 5cef4666e6bd1e2c447fb262c5a6830147a73491 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 19 Nov 2019 22:44:07 +0100 Subject: [PATCH 1329/3747] rename panic=abort tests to panic_abort --- tests/compile-fail/{panic1.rs => panic_abort1.rs} | 0 tests/compile-fail/{panic2.rs => panic_abort2.rs} | 0 tests/compile-fail/{panic3.rs => panic_abort3.rs} | 0 tests/compile-fail/{panic4.rs => panic_abort4.rs} | 0 4 files changed, 0 insertions(+), 0 deletions(-) rename tests/compile-fail/{panic1.rs => panic_abort1.rs} (100%) rename tests/compile-fail/{panic2.rs => panic_abort2.rs} (100%) rename tests/compile-fail/{panic3.rs => panic_abort3.rs} (100%) rename tests/compile-fail/{panic4.rs => panic_abort4.rs} (100%) diff --git a/tests/compile-fail/panic1.rs b/tests/compile-fail/panic_abort1.rs similarity index 100% rename from tests/compile-fail/panic1.rs rename to tests/compile-fail/panic_abort1.rs diff --git a/tests/compile-fail/panic2.rs b/tests/compile-fail/panic_abort2.rs similarity index 100% rename from tests/compile-fail/panic2.rs rename to tests/compile-fail/panic_abort2.rs diff --git a/tests/compile-fail/panic3.rs b/tests/compile-fail/panic_abort3.rs similarity index 100% rename from tests/compile-fail/panic3.rs rename to tests/compile-fail/panic_abort3.rs diff --git a/tests/compile-fail/panic4.rs b/tests/compile-fail/panic_abort4.rs similarity index 100% rename from tests/compile-fail/panic4.rs rename to tests/compile-fail/panic_abort4.rs From 2532b86a3b89acaff5c7793d69bc159de8ddd214 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Tue, 19 Nov 2019 17:25:09 -0500 Subject: [PATCH 1330/3747] Propagate the return code from the `start` lang item Fixes #1064 This ensures that we set the error code properly when a panic unwinds past `main`. I'm not sure what the best way to write a test for this is --- src/eval.rs | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/src/eval.rs b/src/eval.rs index 7203ba6bf1db9..3dad5a0d8c73e 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -11,7 +11,7 @@ use syntax::source_map::DUMMY_SP; use crate::{ EnvVars, Evaluator, FnVal, HelpersEvalContextExt, InterpCx, InterpError, InterpResult, MemoryExtra, MiriMemoryKind, Pointer, Scalar, StackPopCleanup, Tag, - TlsEvalContextExt, + TlsEvalContextExt, MPlaceTy }; /// Configuration needed to spawn a Miri instance. @@ -34,7 +34,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig, -) -> InterpResult<'tcx, InterpCx<'mir, 'tcx, Evaluator<'tcx>>> { +) -> InterpResult<'tcx, (InterpCx<'mir, 'tcx, Evaluator<'tcx>>, MPlaceTy<'tcx, Tag>)> { let mut ecx = InterpCx::new( tcx.at(syntax::source_map::DUMMY_SP), ty::ParamEnv::reveal_all(), @@ -170,12 +170,12 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( ecx.write_scalar(Scalar::from_u32(0), errno_place.into())?; ecx.machine.last_error = Some(errno_place); - Ok(ecx) + Ok((ecx, ret_ptr)) } pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) { - let mut ecx = match create_ecx(tcx, main_id, config) { - Ok(ecx) => ecx, + let (mut ecx, ret_ptr) = match create_ecx(tcx, main_id, config) { + Ok(v) => v, Err(mut err) => { err.print_backtrace(); panic!("Miri initialziation error: {}", err.kind) @@ -183,14 +183,18 @@ pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) { }; // Perform the main execution. - let res: InterpResult<'_> = (|| { + let res: InterpResult<'_, i64> = (|| { ecx.run()?; - ecx.run_tls_dtors() + // Read the return code pointer *before* we run TLS destructors, to assert + // that it was written to by the time that `start` lang item returned. + let return_code = ecx.read_scalar(ret_ptr.into())?.not_undef()?.to_machine_isize(&ecx)?; + ecx.run_tls_dtors()?; + Ok(return_code) })(); // Process the result. match res { - Ok(()) => { + Ok(return_code) => { let leaks = ecx.memory.leak_report(); // Disable the leak test on some platforms where we do not // correctly implement TLS destructors. @@ -199,6 +203,7 @@ pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) { if !ignore_leaks && leaks != 0 { tcx.sess.err("the evaluated program leaked memory"); } + std::process::exit(return_code as i32); } Err(mut e) => { // Special treatment for some error kinds From 310212931666421636286d223ca88841b26011c2 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Wed, 20 Nov 2019 12:43:10 -0500 Subject: [PATCH 1331/3747] Improve return code propagation. Don't explicitly exit if we reported an evaluation error --- src/bin/miri.rs | 5 ++++- src/eval.rs | 19 +++++++++++++++---- 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 481491ea722f8..9e95e4b0a466a 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -15,6 +15,7 @@ extern crate rustc_interface; extern crate syntax; use std::str::FromStr; +use std::convert::TryFrom; use std::env; use hex::FromHexError; @@ -39,7 +40,9 @@ impl rustc_driver::Callbacks for MiriCompilerCalls { // Add filename to `miri` arguments. config.args.insert(0, compiler.input().filestem().to_string()); - miri::eval_main(tcx, entry_def_id, config); + if let Some(return_code) = miri::eval_main(tcx, entry_def_id, config) { + std::process::exit(i32::try_from(return_code).expect("Return value was too large!")); + } }); compiler.session().abort_if_errors(); diff --git a/src/eval.rs b/src/eval.rs index 3dad5a0d8c73e..603c30feb9f46 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -29,7 +29,10 @@ pub struct MiriConfig { pub seed: Option, } -// Used by priroda. +/// Returns a freshly created `InterpCx`, along with an `MPlaceTy` representing +/// the location where the return value of the `start` lang item will be +/// written to. +/// Used by `priroda` and `miri pub fn create_ecx<'mir, 'tcx: 'mir>( tcx: TyCtxt<'tcx>, main_id: DefId, @@ -173,7 +176,10 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( Ok((ecx, ret_ptr)) } -pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) { +/// Evaluates the main function specified by `main_id`. +/// Returns `Some(return_code)` if program executed completed. +/// Returns `None` if an evaluation error occured +pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) -> Option { let (mut ecx, ret_ptr) = match create_ecx(tcx, main_id, config) { Ok(v) => v, Err(mut err) => { @@ -202,13 +208,16 @@ pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) { let ignore_leaks = target_os == "windows" || target_os == "macos"; if !ignore_leaks && leaks != 0 { tcx.sess.err("the evaluated program leaked memory"); + // Ignore the provided return code - let the reported error + // determine the return code + return None; } - std::process::exit(return_code as i32); + return Some(return_code) } Err(mut e) => { // Special treatment for some error kinds let msg = match e.kind { - InterpError::Exit(code) => std::process::exit(code), + InterpError::Exit(code) => return Some(code.into()), err_unsup!(NoMirFor(..)) => format!("{}. Did you set `MIRI_SYSROOT` to a Miri-enabled sysroot? You can prepare one with `cargo miri setup`.", e), _ => e.to_string() @@ -251,6 +260,8 @@ pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) { trace!(" local {}: {:?}", i, local.value); } } + // Let the reported error determine the return code + return None; } } } From f16f891191b3d61df3d23c49b122e12cad7e09d9 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 20 Nov 2019 19:38:41 +0100 Subject: [PATCH 1332/3747] slice matching overflow got fixed --- rust-version | 2 +- tests/run-pass/issue-17877.rs | 7 ++----- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/rust-version b/rust-version index 093065aab2c0a..cb6136f40fb6f 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -3e525e3f6d9e85d54fa4c49b52df85aa0c990100 +b9cf5417892ef242c783ef963deff5436205b0f6 diff --git a/tests/run-pass/issue-17877.rs b/tests/run-pass/issue-17877.rs index 9cbc459ad038e..d2806e5ed350b 100644 --- a/tests/run-pass/issue-17877.rs +++ b/tests/run-pass/issue-17877.rs @@ -1,14 +1,11 @@ -//ignore-windows: Causes a stack overflow?!? Likely a rustc bug: https://github.com/rust-lang/rust/issues/53820 -//FIXME: Once that bug is fixed, increase the size to 16*1024 and enable on all platforms. - #![feature(slice_patterns)] fn main() { - assert_eq!(match [0u8; 1024] { + assert_eq!(match [0u8; 16*1024] { _ => 42_usize, }, 42_usize); - assert_eq!(match [0u8; 1024] { + assert_eq!(match [0u8; 16*1024] { [1, ..] => 0_usize, [0, ..] => 1_usize, _ => 2_usize From 2176bf6cf04bea76d9a1c85a8418fb9b91d17dfa Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Wed, 20 Nov 2019 13:52:04 -0500 Subject: [PATCH 1333/3747] Fix nits Co-Authored-By: Ralf Jung --- src/eval.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/eval.rs b/src/eval.rs index 603c30feb9f46..237ef99d1fe66 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -32,7 +32,7 @@ pub struct MiriConfig { /// Returns a freshly created `InterpCx`, along with an `MPlaceTy` representing /// the location where the return value of the `start` lang item will be /// written to. -/// Used by `priroda` and `miri +/// Public because this is also used by `priroda`. pub fn create_ecx<'mir, 'tcx: 'mir>( tcx: TyCtxt<'tcx>, main_id: DefId, @@ -178,7 +178,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( /// Evaluates the main function specified by `main_id`. /// Returns `Some(return_code)` if program executed completed. -/// Returns `None` if an evaluation error occured +/// Returns `None` if an evaluation error occured. pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) -> Option { let (mut ecx, ret_ptr) = match create_ecx(tcx, main_id, config) { Ok(v) => v, @@ -209,7 +209,7 @@ pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) -> if !ignore_leaks && leaks != 0 { tcx.sess.err("the evaluated program leaked memory"); // Ignore the provided return code - let the reported error - // determine the return code + // determine the return code. return None; } return Some(return_code) @@ -260,7 +260,7 @@ pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) -> trace!(" local {}: {:?}", i, local.value); } } - // Let the reported error determine the return code + // Let the reported error determine the return code. return None; } } From a328683c4ae15137235f0b48a5d803a76343e810 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Thu, 21 Nov 2019 17:33:30 -0500 Subject: [PATCH 1334/3747] Add acos, asin, and atan foreign functions I copied the tests from the docs pages --- src/shims/foreign_items.rs | 10 ++++++++-- tests/run-pass/intrinsics-math.rs | 9 +++++++++ 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 48d98141b8ad3..5edabf2156673 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -496,7 +496,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // math functions - "cbrtf" | "coshf" | "sinhf" | "tanf" => { + "cbrtf" | "coshf" | "sinhf" | "tanf" | "acosf" | "asinf" | "atanf" => { // FIXME: Using host floats. let f = f32::from_bits(this.read_scalar(args[0])?.to_u32()?); let f = match link_name { @@ -504,6 +504,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "coshf" => f.cosh(), "sinhf" => f.sinh(), "tanf" => f.tan(), + "acosf" => f.acos(), + "asinf" => f.asin(), + "atanf" => f.atan(), _ => bug!(), }; this.write_scalar(Scalar::from_u32(f.to_bits()), dest)?; @@ -521,7 +524,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_u32(n.to_bits()), dest)?; } - "cbrt" | "cosh" | "sinh" | "tan" => { + "cbrt" | "cosh" | "sinh" | "tan" | "acos" | "asin" | "atan" => { // FIXME: Using host floats. let f = f64::from_bits(this.read_scalar(args[0])?.to_u64()?); let f = match link_name { @@ -529,6 +532,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "cosh" => f.cosh(), "sinh" => f.sinh(), "tan" => f.tan(), + "acos" => f.acos(), + "asin" => f.asin(), + "atan" => f.atan(), _ => bug!(), }; this.write_scalar(Scalar::from_u64(f.to_bits()), dest)?; diff --git a/tests/run-pass/intrinsics-math.rs b/tests/run-pass/intrinsics-math.rs index f435611b2b698..98cb87ee93422 100644 --- a/tests/run-pass/intrinsics-math.rs +++ b/tests/run-pass/intrinsics-math.rs @@ -92,6 +92,15 @@ pub fn main() { assert_approx_eq!(1.0f32.tan(), 1.557408f32); assert_approx_eq!(1.0f64.tan(), 1.557408f64); + assert_approx_eq!(f32::consts::FRAC_PI_4.cos().acos(), f32::consts::FRAC_PI_4); + assert_approx_eq!(f64::consts::FRAC_PI_4.cos().acos(), f64::consts::FRAC_PI_4); + + assert_approx_eq!(f32::consts::FRAC_PI_4.sin().asin(), f32::consts::FRAC_PI_4); + assert_approx_eq!(f64::consts::FRAC_PI_4.sin().asin(), f64::consts::FRAC_PI_4); + + assert_approx_eq!(1.0_f32, 1.0_f32.tan().atan()); + assert_approx_eq!(1.0_f64, 1.0_f64.tan().atan()); + assert_eq!(3.3_f32.round(), 3.0); assert_eq!(3.3_f64.round(), 3.0); From 6888555ca91f8e729b84da13da20d886919489b3 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 22 Nov 2019 09:50:22 +0100 Subject: [PATCH 1335/3747] rustup for never stabilization --- rust-version | 2 +- tests/compile-fail/never_say_never.rs | 1 - tests/compile-fail/never_transmute_humans.rs | 2 -- tests/compile-fail/never_transmute_void.rs | 1 - tests/run-pass/async-fn.rs | 2 -- tests/run-pass/generator.rs | 2 +- tests/run-pass/loop-break-value.rs | 1 - 7 files changed, 2 insertions(+), 9 deletions(-) diff --git a/rust-version b/rust-version index cb6136f40fb6f..09cac5bb059fa 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -b9cf5417892ef242c783ef963deff5436205b0f6 +bd816fd76f4f7a040ca7ac8ca5bc556d761f96fa diff --git a/tests/compile-fail/never_say_never.rs b/tests/compile-fail/never_say_never.rs index d7e6a8c09f64e..199ceb70fb6be 100644 --- a/tests/compile-fail/never_say_never.rs +++ b/tests/compile-fail/never_say_never.rs @@ -1,7 +1,6 @@ // This should fail even without validation // compile-flags: -Zmiri-disable-validation -#![feature(never_type)] #![allow(unreachable_code)] fn main() { diff --git a/tests/compile-fail/never_transmute_humans.rs b/tests/compile-fail/never_transmute_humans.rs index ab25b1ffc7467..f662fdcd98729 100644 --- a/tests/compile-fail/never_transmute_humans.rs +++ b/tests/compile-fail/never_transmute_humans.rs @@ -1,8 +1,6 @@ // This should fail even without validation // compile-flags: -Zmiri-disable-validation -#![feature(never_type)] - struct Human; fn main() { diff --git a/tests/compile-fail/never_transmute_void.rs b/tests/compile-fail/never_transmute_void.rs index a5d6795d71e79..933e052119564 100644 --- a/tests/compile-fail/never_transmute_void.rs +++ b/tests/compile-fail/never_transmute_void.rs @@ -1,7 +1,6 @@ // This should fail even without validation // compile-flags: -Zmiri-disable-validation -#![feature(never_type)] #![allow(unused, invalid_value)] enum Void {} diff --git a/tests/run-pass/async-fn.rs b/tests/run-pass/async-fn.rs index 90448aca17792..a4c176ad8f121 100644 --- a/tests/run-pass/async-fn.rs +++ b/tests/run-pass/async-fn.rs @@ -1,5 +1,3 @@ -#![feature(never_type)] - use std::{future::Future, pin::Pin, task::Poll, ptr}; use std::task::{Waker, RawWaker, RawWakerVTable, Context}; diff --git a/tests/run-pass/generator.rs b/tests/run-pass/generator.rs index c31b5b9ed3bb2..00ebba6344e2e 100644 --- a/tests/run-pass/generator.rs +++ b/tests/run-pass/generator.rs @@ -1,4 +1,4 @@ -#![feature(generators, generator_trait, never_type)] +#![feature(generators, generator_trait)] use std::ops::{GeneratorState, Generator}; use std::pin::Pin; diff --git a/tests/run-pass/loop-break-value.rs b/tests/run-pass/loop-break-value.rs index bd7afa7ec1a80..43acdc228202e 100644 --- a/tests/run-pass/loop-break-value.rs +++ b/tests/run-pass/loop-break-value.rs @@ -1,4 +1,3 @@ -#![feature(never_type)] #![allow(unreachable_code)] #[allow(unused)] From 6941caf1df5e38d47bfec16353c0ef6eeceb9aa8 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 22 Nov 2019 18:12:10 +0100 Subject: [PATCH 1336/3747] typo --- .../compile-fail/stacked_borrows/deallocate_against_barrier2.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/compile-fail/stacked_borrows/deallocate_against_barrier2.rs b/tests/compile-fail/stacked_borrows/deallocate_against_barrier2.rs index db4d2d998dbdf..9c0c59d364f28 100644 --- a/tests/compile-fail/stacked_borrows/deallocate_against_barrier2.rs +++ b/tests/compile-fail/stacked_borrows/deallocate_against_barrier2.rs @@ -2,7 +2,7 @@ use std::cell::Cell; -// Check that even `&Cell` are dereferencable. +// Check that even `&Cell` are dereferenceable. // Also see . fn inner(x: &Cell, f: fn(&Cell)) { // `f` may mutate, but it may not deallocate! From 5339d541efa7245a17fabe8992065ff9d444f5a4 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 23 Nov 2019 10:33:49 +0100 Subject: [PATCH 1337/3747] cargo-miri: also find Rust sources when being run in a locally built, linked toolchain --- src/bin/cargo-miri.rs | 52 ++++++++++++++++++++++++++++++++----------- 1 file changed, 39 insertions(+), 13 deletions(-) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 36545766d101d..f4fb13518e305 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -270,19 +270,44 @@ fn setup(ask_user: bool) { ask_to_run(cmd, ask_user, "install a recent enough xargo"); } - // Then, unless `XARGO_RUST_SRC` is set, we also need rust-src. - // Let's see if it is already installed. - if std::env::var("XARGO_RUST_SRC").is_err() { - let sysroot = Command::new("rustc").args(&["--print", "sysroot"]).output() - .expect("failed to get rustc sysroot") - .stdout; - let sysroot = std::str::from_utf8(&sysroot).unwrap(); - let src = Path::new(sysroot.trim_end_matches('\n')).join("lib").join("rustlib").join("src"); - if !src.exists() { - let mut cmd = Command::new("rustup"); - cmd.args(&["component", "add", "rust-src"]); - ask_to_run(cmd, ask_user, "install the rustc-src component for the selected toolchain"); + // Determine where the rust sources are located. `XARGO_RUST_SRC` env var trumps everything. + let rust_src = match std::env::var("XARGO_RUST_SRC") { + Ok(val) => PathBuf::from(val), + Err(_) => { + // Check for `rust-src` rustup component. + let sysroot = Command::new("rustc").args(&["--print", "sysroot"]).output() + .expect("failed to get rustc sysroot") + .stdout; + let sysroot = std::str::from_utf8(&sysroot).unwrap(); + let sysroot = Path::new(sysroot.trim_end_matches('\n')); + // First try: `$SYSROOT/lib/rustlib/src/rust`; test if that contains `Cargo.lock`. + let rustup_src = sysroot.join("lib").join("rustlib").join("src").join("rust"); + let base_dir = if rustup_src.join("Cargo.lock").exists() { + // Just use this. + rustup_src + } else { + // Maybe this is a local toolchain built with `x.py` and linked into `rustup`? + // Second try: `$SYSROOT/../../..`; test if that contains `x.py`. + let local_src = sysroot.parent().and_then(Path::parent).and_then(Path::parent); + match local_src { + Some(local_src) if local_src.join("x.py").exists() => { + // Use this. + PathBuf::from(local_src) + } + _ => { + // Fallback: Ask the user to install the `rust-src` component, and use that. + let mut cmd = Command::new("rustup"); + cmd.args(&["component", "add", "rust-src"]); + ask_to_run(cmd, ask_user, "install the rustc-src component for the selected toolchain"); + rustup_src + } + } + }; + base_dir.join("src") // Xargo wants the src-subdir } + }; + if !rust_src.exists() { + show_error(format!("Given Rust source directory `{}` does not exist.", rust_src.display())); } // Next, we need our own libstd. We will do this work in whatever is a good cache dir for this platform. @@ -321,7 +346,8 @@ path = "lib.rs" command.arg("build").arg("-q"); command.current_dir(&dir); command.env("RUSTFLAGS", miri::miri_default_args().join(" ")); - command.env("XARGO_HOME", dir.to_str().unwrap()); + command.env("XARGO_HOME", &dir); + command.env("XARGO_RUST_SRC", &rust_src); // In bootstrap, make sure we don't get debug assertons into our libstd. command.env("RUSTC_DEBUG_ASSERTIONS", "false"); // Handle target flag. From 274e72996eb36f815f34cf5593eaed4f314a1b2a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 23 Nov 2019 10:36:23 +0100 Subject: [PATCH 1338/3747] miri script does not need to handle locally built rustc any more --- miri | 5 ----- 1 file changed, 5 deletions(-) diff --git a/miri b/miri index c3d7ae0280c77..f1eae220e0ded 100755 --- a/miri +++ b/miri @@ -65,16 +65,11 @@ find_sysroot() { return 0 fi # We need to build a sysroot. - if echo "$SYSROOT" | egrep -q 'build/[^/]+/stage'; then - # A local rustc build. Use its source dir. - export XARGO_RUST_SRC="$SYSROOT/../../../src" - fi if [ -n "$MIRI_TEST_TARGET" ]; then build_sysroot --target "$MIRI_TEST_TARGET" else build_sysroot fi - export MIRI_SYSROOT } ## Main From ee411c2a74c9d9876c1ac5e03a300456e3caa6bb Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 24 Nov 2019 10:24:41 +0100 Subject: [PATCH 1339/3747] beef up catch_panic test --- tests/run-pass/catch_panic.rs | 67 ++++++++++++++++++++++--------- tests/run-pass/catch_panic.stderr | 7 ++++ tests/run-pass/panic1.rs | 4 -- tests/run-pass/panic1.stderr | 1 - tests/run-pass/panic2.rs | 5 --- tests/run-pass/panic2.stderr | 1 - 6 files changed, 54 insertions(+), 31 deletions(-) create mode 100644 tests/run-pass/catch_panic.stderr delete mode 100644 tests/run-pass/panic1.rs delete mode 100644 tests/run-pass/panic1.stderr delete mode 100644 tests/run-pass/panic2.rs delete mode 100644 tests/run-pass/panic2.stderr diff --git a/tests/run-pass/catch_panic.rs b/tests/run-pass/catch_panic.rs index 228317e893695..4d1f9a8504893 100644 --- a/tests/run-pass/catch_panic.rs +++ b/tests/run-pass/catch_panic.rs @@ -1,5 +1,5 @@ // ignore-windows: Unwind panicking does not currently work on Windows -use std::panic::catch_unwind; +use std::panic::{catch_unwind, AssertUnwindSafe}; use std::cell::Cell; thread_local! { @@ -18,7 +18,7 @@ impl Drop for DropTester { } } -fn do_panic_counter() { +fn do_panic_counter(do_panic: impl FnOnce(usize) -> !) { // If this gets leaked, it will be easy to spot // in Miri's leak report let _string = "LEAKED FROM do_panic_counter".to_string(); @@ -28,35 +28,62 @@ fn do_panic_counter() { // Check for bugs in Miri's panic implementation. // If do_panic_counter() somehow gets called more than once, - // we'll generate a different panic message + // we'll generate a different panic message and stderr will differ. let old_val = MY_COUNTER.with(|c| { let val = c.get(); c.set(val + 1); val }); - panic!(format!("Hello from panic: {:?}", old_val)); + do_panic(old_val); } fn main() { - std::panic::set_hook(Box::new(|_panic_info| { + let prev = std::panic::take_hook(); + std::panic::set_hook(Box::new(move |panic_info| { HOOK_CALLED.with(|h| h.set(true)); + prev(panic_info) })); - let res = catch_unwind(|| { + + test(|_old_val| panic!("Hello from panic: std")); + test(|old_val| panic!(format!("Hello from panic: {:?}", old_val))); + test(|old_val| panic!("Hello from panic: {:?}", old_val)); + // FIXME https://github.com/rust-lang/miri/issues/1071 + //test(|_old_val| core::panic!("Hello from panic: core")); + //test(|old_val| core::panic!(&format!("Hello from panic: {:?}", old_val))); + //test(|old_val| core::panic!("Hello from panic: {:?}", old_val)); + + // Cleanup: reset to default hook. + drop(std::panic::take_hook()); + + eprintln!("Success!"); // Make sure we get this in stderr +} + +fn test(do_panic: impl FnOnce(usize) -> !) { + // Reset test flags. + DROPPED.with(|c| c.set(false)); + HOOK_CALLED.with(|c| c.set(false)); + + // Cause and catch a panic. + let res = catch_unwind(AssertUnwindSafe(|| { let _string = "LEAKED FROM CLOSURE".to_string(); - do_panic_counter() - }); - let expected: Box = Box::new("Hello from panic: 0".to_string()); - let actual = res.expect_err("do_panic() did not panic!") - .downcast::().expect("Failed to cast to string!"); - - assert_eq!(expected, actual); - DROPPED.with(|c| { - // This should have been set to 'true' by DropTester - assert!(c.get()); - }); + do_panic_counter(do_panic) + })).expect_err("do_panic() did not panic!"); - HOOK_CALLED.with(|h| { - assert!(h.get()); - }); + // See if we can extract panic message. + match res.downcast::() { + Ok(s) => { + eprintln!("Caught panic message (String): {}", s); + } + Err(res) => + if let Ok(s) = res.downcast::<&str>() { + eprintln!("Caught panic message (&str): {}", s); + } else { + eprintln!("Failed get caught panic message."); + } + } + + // Test flags. + assert!(DROPPED.with(|c| c.get())); + assert!(HOOK_CALLED.with(|c| c.get())); } diff --git a/tests/run-pass/catch_panic.stderr b/tests/run-pass/catch_panic.stderr new file mode 100644 index 0000000000000..f6e5456559076 --- /dev/null +++ b/tests/run-pass/catch_panic.stderr @@ -0,0 +1,7 @@ +thread 'main' panicked at 'Hello from panic: std', $DIR/catch_panic.rs:47:21 +Caught panic message (&str): Hello from panic: std +thread 'main' panicked at 'Hello from panic: 1', $DIR/catch_panic.rs:48:20 +Caught panic message (String): Hello from panic: 1 +thread 'main' panicked at 'Hello from panic: 2', $DIR/catch_panic.rs:49:20 +Caught panic message (String): Hello from panic: 2 +Success! diff --git a/tests/run-pass/panic1.rs b/tests/run-pass/panic1.rs deleted file mode 100644 index 261db018d6da0..0000000000000 --- a/tests/run-pass/panic1.rs +++ /dev/null @@ -1,4 +0,0 @@ -// ignore-windows: Unwind panicking does not currently work on Windows -fn main() { - panic!("Miri panic!"); -} diff --git a/tests/run-pass/panic1.stderr b/tests/run-pass/panic1.stderr deleted file mode 100644 index b1607dd864fb8..0000000000000 --- a/tests/run-pass/panic1.stderr +++ /dev/null @@ -1 +0,0 @@ -thread 'main' panicked at 'Miri panic!', $DIR/panic1.rs:3:5 diff --git a/tests/run-pass/panic2.rs b/tests/run-pass/panic2.rs deleted file mode 100644 index deaf606d9a2e0..0000000000000 --- a/tests/run-pass/panic2.rs +++ /dev/null @@ -1,5 +0,0 @@ -// ignore-windows: Unwind panicking does not currently work on Windows -fn main() { - let val = "Value".to_string(); - panic!("Miri panic with value: {}", val); -} diff --git a/tests/run-pass/panic2.stderr b/tests/run-pass/panic2.stderr deleted file mode 100644 index bc5df83ec0f07..0000000000000 --- a/tests/run-pass/panic2.stderr +++ /dev/null @@ -1 +0,0 @@ -thread 'main' panicked at 'Miri panic with value: Value', $DIR/panic2.rs:4:5 From 35e1fe16652c7e7490d54fbf7f764b0676378456 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 24 Nov 2019 10:51:48 +0100 Subject: [PATCH 1340/3747] also test non-string panic payload --- tests/run-pass/catch_panic.rs | 1 + tests/run-pass/catch_panic.stderr | 2 ++ 2 files changed, 3 insertions(+) diff --git a/tests/run-pass/catch_panic.rs b/tests/run-pass/catch_panic.rs index 4d1f9a8504893..c504956db35aa 100644 --- a/tests/run-pass/catch_panic.rs +++ b/tests/run-pass/catch_panic.rs @@ -47,6 +47,7 @@ fn main() { test(|_old_val| panic!("Hello from panic: std")); test(|old_val| panic!(format!("Hello from panic: {:?}", old_val))); test(|old_val| panic!("Hello from panic: {:?}", old_val)); + test(|_old_val| panic!(1337)); // FIXME https://github.com/rust-lang/miri/issues/1071 //test(|_old_val| core::panic!("Hello from panic: core")); //test(|old_val| core::panic!(&format!("Hello from panic: {:?}", old_val))); diff --git a/tests/run-pass/catch_panic.stderr b/tests/run-pass/catch_panic.stderr index f6e5456559076..6d905da7febe6 100644 --- a/tests/run-pass/catch_panic.stderr +++ b/tests/run-pass/catch_panic.stderr @@ -4,4 +4,6 @@ thread 'main' panicked at 'Hello from panic: 1', $DIR/catch_panic.rs:48:20 Caught panic message (String): Hello from panic: 1 thread 'main' panicked at 'Hello from panic: 2', $DIR/catch_panic.rs:49:20 Caught panic message (String): Hello from panic: 2 +thread 'main' panicked at 'Box', $DIR/catch_panic.rs:50:21 +Failed get caught panic message. Success! From 51d47e8dc5a94d60ea0ef321cf81544d2908a216 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 25 Nov 2019 15:01:05 +0100 Subject: [PATCH 1341/3747] test closure-to-fn-ptr coercions a bit more --- .../run-pass/non_capture_closure_to_fn_ptr.rs | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/tests/run-pass/non_capture_closure_to_fn_ptr.rs b/tests/run-pass/non_capture_closure_to_fn_ptr.rs index e6a5017847d4d..d404daef2c7c6 100644 --- a/tests/run-pass/non_capture_closure_to_fn_ptr.rs +++ b/tests/run-pass/non_capture_closure_to_fn_ptr.rs @@ -5,7 +5,8 @@ static FOO: fn() = || { assert_ne!(42, 43) }; static BAR: fn(i32, i32) = |a, b| { assert_ne!(a, b) }; // use to first make the closure FnOnce() before making it fn() -fn magic(f: F) -> F { f } +fn magic0 R>(f: F) -> F { f } +fn magic1 R>(f: F) -> F { f } fn main() { FOO(); @@ -15,6 +16,20 @@ fn main() { let boo: &dyn Fn(i32, i32) = &BAR; boo(48, 49); - let f = magic(||{}) as fn(); + let f: fn() = ||{}; f(); + let f = magic0(||{}) as fn(); + f(); + + let g: fn(i32) = |i| assert_eq!(i, 2); + g(2); + let g = magic1(|i| assert_eq!(i, 2)) as fn(i32); + g(2); + + // FIXME: This fails with "invalid use of NULL pointer" + //let h: fn() -> ! = || std::process::exit(0); + //h(); + // FIXME: This does not even compile?!? + //let h = magic0(|| std::process::exit(0)) as fn() -> !; + //h(); } From d16e12b0a4b3b525c2aaac7af05a1494f4d3a7bc Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 25 Nov 2019 15:08:24 +0100 Subject: [PATCH 1342/3747] rename test and add some references --- ...re_to_fn_ptr.rs => coerce_non_capture_closure_to_fn_ptr.rs} | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) rename tests/run-pass/{non_capture_closure_to_fn_ptr.rs => coerce_non_capture_closure_to_fn_ptr.rs} (83%) diff --git a/tests/run-pass/non_capture_closure_to_fn_ptr.rs b/tests/run-pass/coerce_non_capture_closure_to_fn_ptr.rs similarity index 83% rename from tests/run-pass/non_capture_closure_to_fn_ptr.rs rename to tests/run-pass/coerce_non_capture_closure_to_fn_ptr.rs index d404daef2c7c6..30e1768837eb2 100644 --- a/tests/run-pass/non_capture_closure_to_fn_ptr.rs +++ b/tests/run-pass/coerce_non_capture_closure_to_fn_ptr.rs @@ -29,7 +29,8 @@ fn main() { // FIXME: This fails with "invalid use of NULL pointer" //let h: fn() -> ! = || std::process::exit(0); //h(); - // FIXME: This does not even compile?!? + // FIXME: This does not even compile?!? //let h = magic0(|| std::process::exit(0)) as fn() -> !; //h(); + // Once these tests pass, they should be in separate files as they terminate the process. } From 66dc939787d7b5df2bc4866ab69fe7cc4d980307 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 25 Nov 2019 15:08:47 +0100 Subject: [PATCH 1343/3747] rename some more tests --- tests/run-pass/{mir_coercions.rs => coercions.rs} | 0 tests/run-pass/{mir_fat_ptr.rs => fat_ptr.rs} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename tests/run-pass/{mir_coercions.rs => coercions.rs} (100%) rename tests/run-pass/{mir_fat_ptr.rs => fat_ptr.rs} (100%) diff --git a/tests/run-pass/mir_coercions.rs b/tests/run-pass/coercions.rs similarity index 100% rename from tests/run-pass/mir_coercions.rs rename to tests/run-pass/coercions.rs diff --git a/tests/run-pass/mir_fat_ptr.rs b/tests/run-pass/fat_ptr.rs similarity index 100% rename from tests/run-pass/mir_fat_ptr.rs rename to tests/run-pass/fat_ptr.rs From 2152258b04ba3eb2f7f560ff7b793fb277d29077 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 25 Nov 2019 15:10:39 +0100 Subject: [PATCH 1344/3747] and another reference --- tests/run-pass/coerce_non_capture_closure_to_fn_ptr.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/run-pass/coerce_non_capture_closure_to_fn_ptr.rs b/tests/run-pass/coerce_non_capture_closure_to_fn_ptr.rs index 30e1768837eb2..4da2c0c61b4aa 100644 --- a/tests/run-pass/coerce_non_capture_closure_to_fn_ptr.rs +++ b/tests/run-pass/coerce_non_capture_closure_to_fn_ptr.rs @@ -26,7 +26,7 @@ fn main() { let g = magic1(|i| assert_eq!(i, 2)) as fn(i32); g(2); - // FIXME: This fails with "invalid use of NULL pointer" + // FIXME: This fails with "invalid use of NULL pointer" //let h: fn() -> ! = || std::process::exit(0); //h(); // FIXME: This does not even compile?!? From e2fd9d83e202cbf54c48ab97713d8d797065f188 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 26 Nov 2019 14:28:56 +0100 Subject: [PATCH 1345/3747] cargo update --- Cargo.lock | 188 +++++++++++++++++------------------------------------ Cargo.toml | 2 +- 2 files changed, 62 insertions(+), 128 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index bc122e3debd71..0ccbaaaabec21 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8,11 +8,6 @@ dependencies = [ "memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "approx" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "arrayref" version = "0.3.5" @@ -20,11 +15,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "arrayvec" -version = "0.4.12" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "nodrop 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", -] [[package]] name = "atty" @@ -56,7 +48,7 @@ name = "backtrace-sys" version = "0.1.32" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.46 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.47 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -75,11 +67,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "blake2b_simd" -version = "0.5.8" +version = "0.5.9" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "arrayref 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "arrayvec 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)", + "arrayvec 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "constant_time_eq 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -102,14 +94,14 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.103 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.103 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.42 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "cc" -version = "1.0.46" +version = "1.0.47" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -117,24 +109,13 @@ name = "cfg-if" version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "cgmath" -version = "0.16.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "approx 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "chrono" -version = "0.4.9" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -148,31 +129,32 @@ dependencies = [ [[package]] name = "colored" -version = "1.8.0" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ + "atty 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winconsole 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "compiletest_rs" -version = "0.3.26" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "diff 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", - "filetime 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", + "filetime 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "getopts 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "miow 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "regex 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "rustfix 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.103 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.103 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.42 (registry+https://github.com/rust-lang/crates.io-index)", "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "tester 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "tester 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -252,13 +234,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", - "synstructure 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", + "synstructure 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "filetime" -version = "0.2.7" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", @@ -282,7 +264,7 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.1.12" +version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", @@ -346,14 +328,14 @@ version = "0.1.0" dependencies = [ "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "cargo_metadata 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "colored 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "compiletest_rs 0.3.26 (registry+https://github.com/rust-lang/crates.io-index)", + "colored 1.9.0 (registry+https://github.com/rust-lang/crates.io-index)", + "compiletest_rs 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "directories 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", - "getrandom 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", + "getrandom 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", "hex 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-workspace-hack 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -361,31 +343,18 @@ dependencies = [ "vergen 3.0.4 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "nodrop" -version = "0.1.14" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "num-integer" version = "0.1.41" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "num-traits" -version = "0.1.43" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "num-traits" -version = "0.2.8" +version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", @@ -417,24 +386,12 @@ dependencies = [ "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "rand" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "rand" version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "getrandom 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", + "getrandom 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", "rand_chacha 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -468,7 +425,7 @@ name = "rand_core" version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "getrandom 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", + "getrandom 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -540,18 +497,13 @@ dependencies = [ "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "rgb" -version = "0.8.14" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "rust-argon2" version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", - "blake2b_simd 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)", + "blake2b_simd 0.5.9 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -580,8 +532,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.103 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.42 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -595,7 +547,7 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.103 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -605,30 +557,30 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "serde" -version = "1.0.101" +version = "1.0.103" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde_derive 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.103 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "serde_derive" -version = "1.0.101" +version = "1.0.103" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "serde_json" -version = "1.0.41" +version = "1.0.42" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", "ryu 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.103 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -649,7 +601,7 @@ dependencies = [ [[package]] name = "syn" -version = "1.0.5" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", @@ -659,12 +611,12 @@ dependencies = [ [[package]] name = "synstructure" -version = "0.12.1" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -700,7 +652,7 @@ dependencies = [ [[package]] name = "tester" -version = "0.6.0" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "getopts 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", @@ -742,7 +694,7 @@ version = "3.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "chrono 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)", + "chrono 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", "failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -787,39 +739,26 @@ dependencies = [ "winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "winconsole" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cgmath 0.16.1 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rgb 0.8.14 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - [metadata] "checksum aho-corasick 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)" = "58fb5e95d83b38284460a5fda7d6470aa0b8844d283a0b614b8535e880800d2d" -"checksum approx 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "08abcc3b4e9339e33a3d0a5ed15d84a687350c05689d825e0f6655eef9e76a94" "checksum arrayref 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "0d382e583f07208808f6b1249e60848879ba3543f57c32277bf52d69c2f0f0ee" -"checksum arrayvec 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)" = "cd9fd44efafa8690358b7408d253adf110036b88f55672a933f01d616ad9b1b9" +"checksum arrayvec 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cff77d8686867eceff3105329d4698d96c2391c176d5d03adc90c7389162b5b8" "checksum atty 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)" = "1803c647a3ec87095e7ae7acfca019e98de5ec9a7d01343f611cf3152ed71a90" "checksum autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "1d49d90015b3c36167a20fe2810c5cd875ad504b39cff3d4eae7977e6b7c1cb2" "checksum backtrace 0.3.40 (registry+https://github.com/rust-lang/crates.io-index)" = "924c76597f0d9ca25d762c25a4d369d51267536465dc5064bdf0eb073ed477ea" "checksum backtrace-sys 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)" = "5d6575f128516de27e3ce99689419835fce9643a9b215a14d2b5b685be018491" "checksum base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0b25d992356d2eb0ed82172f5248873db5560c4721f564b13cb5193bda5e668e" "checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" -"checksum blake2b_simd 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)" = "5850aeee1552f495dd0250014cf64b82b7c8879a89d83b33bbdace2cc4f63182" +"checksum blake2b_simd 0.5.9 (registry+https://github.com/rust-lang/crates.io-index)" = "b83b7baab1e671718d78204225800d6b170e648188ac7dc992e9d6bddf87d0c0" "checksum byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a7c3dd8985a7111efc5c80b44e23ecdd8c007de8ade3b96595387e812b957cf5" "checksum c2-chacha 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "214238caa1bf3a496ec3392968969cab8549f96ff30652c9e56885329315f6bb" "checksum cargo_metadata 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8d2d1617e838936c0d2323a65cc151e03ae19a7678dd24f72bccf27119b90a5d" -"checksum cc 1.0.46 (registry+https://github.com/rust-lang/crates.io-index)" = "0213d356d3c4ea2c18c40b037c3be23cd639825c18f25ee670ac7813beeef99c" +"checksum cc 1.0.47 (registry+https://github.com/rust-lang/crates.io-index)" = "aa87058dce70a3ff5621797f1506cb837edd02ac4c0ae642b4542dce802908b8" "checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" -"checksum cgmath 0.16.1 (registry+https://github.com/rust-lang/crates.io-index)" = "64a4b57c8f4e3a2e9ac07e0f6abc9c24b6fc9e1b54c3478cfb598f3d0023e51c" -"checksum chrono 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e8493056968583b0193c1bb04d6f7684586f3726992d6c573261941a895dbd68" +"checksum chrono 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "31850b4a4d6bae316f7a09e691c944c28299298837edc0a03f755618c23cbc01" "checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" -"checksum colored 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6cdb90b60f2927f8d76139c72dbde7e10c3a2bc47c8594c9c7a66529f2687c03" -"checksum compiletest_rs 0.3.26 (registry+https://github.com/rust-lang/crates.io-index)" = "d7d8975604ebad8b6660796802377eb6495045c5606168fc1b8d19a4dd9bfa46" +"checksum colored 1.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "433e7ac7d511768127ed85b0c4947f47a254131e37864b2dc13f52aa32cd37e5" +"checksum compiletest_rs 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d7b678957210a00ba0fbeacc23d38cbfbf29895564da1616564634351e1dac5e" "checksum constant_time_eq 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "995a44c877f9212528ccc74b21a232f66ad69001e40ede5bcee2ac9ef2657120" "checksum crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)" = "04973fa96e96579258a5091af6003abde64af786b860f18622b82e026cca60e6" "checksum diff 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "3c2b69f912779fbb121ceb775d74d51e915af17aaebc38d28a592843a2dd0a3a" @@ -829,10 +768,10 @@ dependencies = [ "checksum env_logger 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "44533bbbb3bb3c1fa17d9f2e4e38bbbaf8396ba82193c4cb1b6445d711445d36" "checksum failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "f8273f13c977665c5db7eb2b99ae520952fe5ac831ae4cd09d80c4c7042b5ed9" "checksum failure_derive 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0bc225b78e0391e4b8683440bf2e63c2deeeb2ce5189eab46e2b68c6d3725d08" -"checksum filetime 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "6bd7380b54ced79dda72ecc35cc4fbbd1da6bba54afaa37e96fd1c2a308cd469" +"checksum filetime 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "1ff6d4dab0aa0c8e6346d46052e93b13a16cf847b54ed357087c35011048cc7d" "checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" "checksum getopts 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)" = "14dbbfd5c71d70241ecf9e6f13737f7b5ce823821063188d7e46c41d371eebd5" -"checksum getrandom 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "473a1265acc8ff1e808cd0a1af8cee3c2ee5200916058a2ca113c29f2d903571" +"checksum getrandom 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "e7db7ca94ed4cd01190ceee0d8a8052f08a247aa1b469a7f68c6a3b71afcf407" "checksum hex 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "023b39be39e3a2da62a94feb433e91e8bcd37676fbc8bea371daf52b7a769a3e" "checksum humantime 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f" "checksum itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "501266b7edd0174f8530248f87f99c88fbe60ca4ef3dd486835b8d8d53136f7f" @@ -841,15 +780,12 @@ dependencies = [ "checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7" "checksum memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "88579771288728879b57485cc7d6b07d648c9f0141eb955f8ab7f9d45394468e" "checksum miow 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "396aa0f2003d7df8395cb93e09871561ccc3e785f0acb369170e8cc74ddf9226" -"checksum nodrop 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb" "checksum num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)" = "b85e541ef8255f6cf42bbfe4ef361305c6c135d10919ecc26126c4e5ae94bc09" -"checksum num-traits 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)" = "92e5113e9fd4cc14ded8e499429f396a20f98c772a47cc8622a736e1ec843c31" -"checksum num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "6ba9a427cfca2be13aa6f6403b0b7e7368fe982bfa16fccc450ce74c46cd9b32" +"checksum num-traits 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "d4c81ffc11c212fa327657cb19dd85eb7419e163b5b076bede2bdb5c974c07e4" "checksum ppv-lite86 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "74490b50b9fbe561ac330df47c08f3f33073d2d00c150f719147d7c54522fa1b" "checksum proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "9c9e470a8dc4aeae2dee2f335e8f533e2d4b347e1434e5671afc49b054592f27" "checksum quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9274b940887ce9addde99c4eee6b5c44cc494b182b97e73dc8ffdcb3397fd3f0" "checksum quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe" -"checksum rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293" "checksum rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "3ae1b169243eaf61759b8475a998f0a385e42042370f3a7dbaf35246eacc8412" "checksum rand_chacha 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "03a2a90da8c7523f554344f921aa97283eadf6ac484a6d2a7d0212fa7f8d6853" "checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" @@ -863,7 +799,6 @@ dependencies = [ "checksum regex 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dc220bd33bdce8f093101afe22a037b8eb0e5af33592e6a9caafff0d4cb81cbd" "checksum regex-syntax 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)" = "11a7e20d1cce64ef2fed88b66d347f88bd9babb82845b2b858f3edbf59a4f716" "checksum remove_dir_all 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4a83fa3702a688b9359eccba92d153ac33fd2e8462f9e0e3fdf155239ea7792e" -"checksum rgb 0.8.14 (registry+https://github.com/rust-lang/crates.io-index)" = "2089e4031214d129e201f8c3c8c2fe97cd7322478a0d1cdf78e7029b0042efdb" "checksum rust-argon2 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4ca4eaef519b494d1f2848fc602d18816fed808a981aedf4f1f00ceb7c9d32cf" "checksum rustc-demangle 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "4c691c0e608126e00913e33f0ccf3727d5fc84573623b8d65b2df340b5201783" "checksum rustc-workspace-hack 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc71d2faa173b74b232dedc235e3ee1696581bb132fc116fa3626d6151a1a8fb" @@ -872,17 +807,17 @@ dependencies = [ "checksum ryu 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "bfa8506c1de11c9c4e4c38863ccbe02a305c8188e85a05a784c9e11e1c3910c8" "checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" "checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" -"checksum serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)" = "9796c9b7ba2ffe7a9ce53c2287dfc48080f4b2b362fcc245a259b3a7201119dd" -"checksum serde_derive 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)" = "4b133a43a1ecd55d4086bd5b4dc6c1751c68b1bfbeba7a5040442022c7e7c02e" -"checksum serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)" = "2f72eb2a68a7dc3f9a691bfda9305a1c017a6215e5a4545c258500d2099a37c2" +"checksum serde 1.0.103 (registry+https://github.com/rust-lang/crates.io-index)" = "1217f97ab8e8904b57dd22eb61cde455fa7446a9c1cf43966066da047c1f3702" +"checksum serde_derive 1.0.103 (registry+https://github.com/rust-lang/crates.io-index)" = "a8c6faef9a2e64b0064f48570289b4bf8823b7581f1d6157c1b52152306651d0" +"checksum serde_json 1.0.42 (registry+https://github.com/rust-lang/crates.io-index)" = "1a3351dcbc1f067e2c92ab7c3c1f288ad1a4cffc470b5aaddb4c2e0a3ae80043" "checksum shell-escape 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "170a13e64f2a51b77a45702ba77287f5c6829375b04a69cf2222acd17d0cfab9" "checksum socket2 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)" = "e8b74de517221a2cb01a53349cf54182acdc31a074727d3079068448c0676d85" -"checksum syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "66850e97125af79138385e9b88339cbcd037e3f28ceab8c5ad98e64f0f1f80bf" -"checksum synstructure 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3f085a5855930c0441ca1288cf044ea4aecf4f43a91668abdb870b4ba546a203" +"checksum syn 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)" = "661641ea2aa15845cddeb97dad000d22070bb5c1fb456b96c1cba883ec691e92" +"checksum synstructure 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)" = "67656ea1dc1b41b1451851562ea232ec2e5a80242139f7e679ceccfb5d61f545" "checksum tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9" "checksum term 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c0863a3345e70f61d613eab32ee046ccd1bcc5f9105fe402c61fcd0c13eeb8b5" "checksum termcolor 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "96d6098003bde162e4277c70665bd87c326f5a0c3f3fbfb285787fa482d54e6e" -"checksum tester 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7647e6d732eb84375d8e7abda37818f81861ddbfc7235e33f4983cb254b71e4f" +"checksum tester 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee72ec31009a42b53de9a6b7d8f462b493ab3b1e4767bda1fcdbb52127f13b6c" "checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b" "checksum time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f" "checksum unicode-width 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7007dbd421b92cc6e28410fe7362e2e0a2503394908f417b68ec8d1c364c4e20" @@ -894,4 +829,3 @@ dependencies = [ "checksum winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7168bab6e1daee33b4557efd0e95d5ca70a03706d39fa5f3fe7a236f584b03c9" "checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" "checksum wincolor 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "96f5016b18804d24db43cebf3c77269e7569b8954a8464501c216cc5e070eaa9" -"checksum winconsole 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3ef84b96d10db72dd980056666d7f1e7663ce93d82fa33b63e71c966f4cf5032" diff --git a/Cargo.toml b/Cargo.toml index 01516d3589130..ac62d29eb8fcb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -59,5 +59,5 @@ cargo_miri = ["cargo_metadata", "directories", "rustc_version"] rustc_tests = [] [dev-dependencies] -compiletest_rs = { version = "0.3.26", features = ["tmp"] } +compiletest_rs = { version = "0.4", features = ["tmp"] } colored = "1.6" From 824328c6d5d76d3db86045da7ca606789696d4f9 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 25 Nov 2019 22:48:31 +0100 Subject: [PATCH 1346/3747] adjust for goto_block refactoring --- src/machine.rs | 16 +++++++--------- src/shims/dlsym.rs | 9 +++------ src/shims/foreign_items.rs | 17 ++++++++--------- src/shims/intrinsics.rs | 27 +++++++++++++-------------- src/shims/mod.rs | 11 +++++------ src/shims/panic.rs | 5 +---- 6 files changed, 37 insertions(+), 48 deletions(-) diff --git a/src/machine.rs b/src/machine.rs index cb65817035716..c405329141985 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -186,11 +186,10 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { ecx: &mut InterpCx<'mir, 'tcx, Self>, instance: ty::Instance<'tcx>, args: &[OpTy<'tcx, Tag>], - dest: Option>, - ret: Option, + ret: Option<(PlaceTy<'tcx, Tag>, mir::BasicBlock)>, unwind: Option, ) -> InterpResult<'tcx, Option<&'mir mir::Body<'tcx>>> { - ecx.find_fn(instance, args, dest, ret, unwind) + ecx.find_fn(instance, args, ret, unwind) } #[inline(always)] @@ -198,10 +197,10 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { ecx: &mut InterpCx<'mir, 'tcx, Self>, fn_val: Dlsym, args: &[OpTy<'tcx, Tag>], - dest: Option>, - ret: Option, + ret: Option<(PlaceTy<'tcx, Tag>, mir::BasicBlock)>, + _unwind: Option, ) -> InterpResult<'tcx> { - ecx.call_dlsym(fn_val, args, dest, ret) + ecx.call_dlsym(fn_val, args, ret) } #[inline(always)] @@ -210,11 +209,10 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { span: Span, instance: ty::Instance<'tcx>, args: &[OpTy<'tcx, Tag>], - dest: Option>, - ret: Option, + ret: Option<(PlaceTy<'tcx, Tag>, mir::BasicBlock)>, unwind: Option, ) -> InterpResult<'tcx> { - ecx.call_intrinsic(span, instance, args, dest, ret, unwind) + ecx.call_intrinsic(span, instance, args, ret, unwind) } #[inline(always)] diff --git a/src/shims/dlsym.rs b/src/shims/dlsym.rs index ca53f5d23015a..dfee4066da1b0 100644 --- a/src/shims/dlsym.rs +++ b/src/shims/dlsym.rs @@ -27,15 +27,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx &mut self, dlsym: Dlsym, args: &[OpTy<'tcx, Tag>], - dest: Option>, - ret: Option, + ret: Option<(PlaceTy<'tcx, Tag>, mir::BasicBlock)>, ) -> InterpResult<'tcx> { use self::Dlsym::*; let this = self.eval_context_mut(); - - let dest = dest.expect("we don't support any diverging dlsym"); - let ret = ret.expect("dest is `Some` but ret is `None`"); + let (dest, ret) = ret.expect("we don't support any diverging dlsym"); match dlsym { GetEntropy => { @@ -46,8 +43,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } - this.goto_block(Some(ret))?; this.dump_place(*dest); + this.go_to_block(ret); Ok(()) } } diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 5edabf2156673..b136260f751ec 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -114,8 +114,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx &mut self, def_id: DefId, args: &[OpTy<'tcx, Tag>], - dest: Option>, - ret: Option, + ret: Option<(PlaceTy<'tcx, Tag>, mir::BasicBlock)>, _unwind: Option ) -> InterpResult<'tcx, Option<&'mir mir::Body<'tcx>>> { let this = self.eval_context_mut(); @@ -129,7 +128,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let tcx = &{ this.tcx.tcx }; // First: functions that diverge. - match link_name { + let (dest, ret) = match link_name { // Note that this matches calls to the *foreign* item `__rust_start_panic* - // that is, calls to `extern "Rust" { fn __rust_start_panic(...) }`. // We forward this to the underlying *implementation* in the panic runtime crate. @@ -154,15 +153,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx return Err(InterpError::Exit(code).into()); } _ => { - if dest.is_none() { + if let Some(p) = ret { + p + } else { throw_unsup_format!("can't call (diverging) foreign function: {}", link_name); } } - } + }; - // Next: functions that assume a ret and dest. - let dest = dest.expect("we already checked for a dest"); - let ret = ret.expect("dest is `Some` but ret is `None`"); + // Next: functions that return. match link_name { "malloc" => { let size = this.read_scalar(args[0])?.to_machine_usize(this)?; @@ -928,8 +927,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx _ => throw_unsup_format!("can't call foreign function: {}", link_name), } - this.goto_block(Some(ret))?; this.dump_place(*dest); + this.go_to_block(ret); Ok(None) } diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 5e1f3cff1c77c..00886328030bb 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -16,12 +16,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx span: Span, instance: ty::Instance<'tcx>, args: &[OpTy<'tcx, Tag>], - dest: Option>, - _ret: Option, + ret: Option<(PlaceTy<'tcx, Tag>, mir::BasicBlock)>, unwind: Option ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - if this.emulate_intrinsic(span, instance, args, dest)? { + if this.emulate_intrinsic(span, instance, args, ret)? { return Ok(()); } let tcx = &{this.tcx.tcx}; @@ -32,23 +31,21 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // that might still hang around! let intrinsic_name = &*tcx.item_name(instance.def_id()).as_str(); - // Handle diverging intrinsics - match intrinsic_name { + // Handle diverging intrinsics. + let (dest, ret) = match intrinsic_name { "abort" => { // FIXME: Add a better way of indicating 'abnormal' termination, // since this is not really an 'unsupported' behavior throw_unsup_format!("the evaluated program aborted!"); } "miri_start_panic" => return this.handle_miri_start_panic(args, unwind), - _ => {} - } - - // Handle non-diverging intrinsics - // The intrinsic itself cannot diverge (otherwise, we would have handled it above), - // so if we got here without a return place that's UB (can happen e.g., for transmute returning `!`). - let dest = match dest { - Some(dest) => dest, - None => throw_ub!(Unreachable) + _ => { + if let Some(p) = ret { + p + } else { + throw_unsup_format!("unimplemented (diverging) intrinsic: {}", intrinsic_name); + } + } }; match intrinsic_name { @@ -581,6 +578,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx name => throw_unsup_format!("unimplemented intrinsic: {}", name), } + this.dump_place(*dest); + this.go_to_block(ret); Ok(()) } } diff --git a/src/shims/mod.rs b/src/shims/mod.rs index f554c19f11c27..2e8aea3f86e05 100644 --- a/src/shims/mod.rs +++ b/src/shims/mod.rs @@ -16,25 +16,24 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx &mut self, instance: ty::Instance<'tcx>, args: &[OpTy<'tcx, Tag>], - dest: Option>, - ret: Option, + ret: Option<(PlaceTy<'tcx, Tag>, mir::BasicBlock)>, unwind: Option ) -> InterpResult<'tcx, Option<&'mir mir::Body<'tcx>>> { let this = self.eval_context_mut(); trace!( "eval_fn_call: {:#?}, {:?}", instance, - dest.map(|place| *place) + ret.map(|p| *p.0) ); // There are some more lang items we want to hook that CTFE does not hook (yet). if this.tcx.lang_items().align_offset_fn() == Some(instance.def.def_id()) { - let dest = dest.unwrap(); + let (dest, ret) = ret.unwrap(); let n = this .align_offset(args[0], args[1])? .unwrap_or_else(|| this.truncate(u128::max_value(), dest.layout)); this.write_scalar(Scalar::from_uint(n, dest.layout.size), dest)?; - this.goto_block(ret)?; + this.go_to_block(ret); return Ok(None); } @@ -46,7 +45,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // to run extra MIR), and Ok(Some(body)) if we found MIR to run for the // foreign function // Any needed call to `goto_block` will be performed by `emulate_foreign_item`. - return this.emulate_foreign_item(instance.def_id(), args, dest, ret, unwind); + return this.emulate_foreign_item(instance.def_id(), args, ret, unwind); } // Otherwise, load the MIR. diff --git a/src/shims/panic.rs b/src/shims/panic.rs index 59ff1a870d105..42028738822a2 100644 --- a/src/shims/panic.rs +++ b/src/shims/panic.rs @@ -53,10 +53,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.machine.panic_payload = Some(scalar); // Jump to the unwind block to begin unwinding. - // We don't use `goto_block` as that is just meant for normal returns. - let next_frame = this.frame_mut(); - next_frame.block = unwind; - next_frame.stmt = 0; + this.unwind_to_block(unwind); return Ok(()) } From fbc1fb20ac606dfcb6f91fb7823272760e583f85 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 27 Nov 2019 08:45:24 +0100 Subject: [PATCH 1347/3747] bump Rust version --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 09cac5bb059fa..b5ab3053c5cf8 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -bd816fd76f4f7a040ca7ac8ca5bc556d761f96fa +809e180a76ce97340bf4354ff357bc59e3ca40b2 From a04620eb697eb064902d5c1b5f7584fa68a1bcfd Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 27 Nov 2019 09:13:37 +0100 Subject: [PATCH 1348/3747] only run leak test on clean platforms --- src/eval.rs | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/eval.rs b/src/eval.rs index 237ef99d1fe66..3524029475a9c 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -201,16 +201,18 @@ pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) -> // Process the result. match res { Ok(return_code) => { - let leaks = ecx.memory.leak_report(); // Disable the leak test on some platforms where we do not // correctly implement TLS destructors. let target_os = ecx.tcx.tcx.sess.target.target.target_os.to_lowercase(); let ignore_leaks = target_os == "windows" || target_os == "macos"; - if !ignore_leaks && leaks != 0 { - tcx.sess.err("the evaluated program leaked memory"); - // Ignore the provided return code - let the reported error - // determine the return code. - return None; + if !ignore_leaks { + let leaks = ecx.memory.leak_report(); + if leaks != 0 { + tcx.sess.err("the evaluated program leaked memory"); + // Ignore the provided return code - let the reported error + // determine the return code. + return None; + } } return Some(return_code) } From fe76d33506f61695b54213b423efa14bbb280531 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 28 Nov 2019 23:42:10 +0100 Subject: [PATCH 1349/3747] Add and use helper function for calling a machine function and passing it some arguments --- src/eval.rs | 181 ++++++++++++++++++++------------------------- src/helpers.rs | 35 +++++++++ src/machine.rs | 31 +++----- src/shims/panic.rs | 21 +----- src/shims/tls.rs | 14 +--- 5 files changed, 131 insertions(+), 151 deletions(-) diff --git a/src/eval.rs b/src/eval.rs index 3524029475a9c..488fdc3b37b18 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -6,13 +6,8 @@ use rand::SeedableRng; use rustc::hir::def_id::DefId; use rustc::ty::layout::{LayoutOf, Size}; use rustc::ty::{self, TyCtxt}; -use syntax::source_map::DUMMY_SP; -use crate::{ - EnvVars, Evaluator, FnVal, HelpersEvalContextExt, InterpCx, InterpError, - InterpResult, MemoryExtra, MiriMemoryKind, Pointer, Scalar, StackPopCleanup, Tag, - TlsEvalContextExt, MPlaceTy -}; +use crate::*; /// Configuration needed to spawn a Miri instance. #[derive(Clone)] @@ -65,107 +60,93 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( tcx.mk_substs(::std::iter::once(ty::subst::GenericArg::from(main_ret_ty))), ) .unwrap(); - let start_mir = ecx.load_mir(start_instance.def, None)?; - - if start_mir.arg_count != 3 { - bug!( - "'start' lang item should have three arguments, but has {}", - start_mir.arg_count - ); - } - - // Return value (in static memory so that it does not count as leak). - let ret = ecx.layout_of(start_mir.return_ty())?; - let ret_ptr = ecx.allocate(ret, MiriMemoryKind::Static.into()); - - // Push our stack frame. - ecx.push_stack_frame( - start_instance, - // There is no call site. - DUMMY_SP, - start_mir, - Some(ret_ptr.into()), - StackPopCleanup::None { cleanup: true }, - )?; - - let mut args = ecx.frame().body.args_iter(); // First argument: pointer to `main()`. let main_ptr = ecx .memory .create_fn_alloc(FnVal::Instance(main_instance)); - let dest = ecx.local_place(args.next().unwrap())?; - ecx.write_scalar(Scalar::Ptr(main_ptr), dest)?; - // Second argument (argc): `1`. - let dest = ecx.local_place(args.next().unwrap())?; - let argc = Scalar::from_uint(config.args.len() as u128, dest.layout.size); - ecx.write_scalar(argc, dest)?; - // Store argc for macOS's `_NSGetArgc`. - { - let argc_place = ecx.allocate(dest.layout, MiriMemoryKind::Env.into()); - ecx.write_scalar(argc, argc_place.into())?; - ecx.machine.argc = Some(argc_place.ptr); - } - + let argc = Scalar::from_uint(config.args.len() as u128, ecx.pointer_size()); // Third argument (`argv`): created from `config.args`. - let dest = ecx.local_place(args.next().unwrap())?; - // For Windows, construct a command string with all the aguments. - let mut cmd = String::new(); - for arg in config.args.iter() { - if !cmd.is_empty() { - cmd.push(' '); + let argv = { + // For Windows, construct a command string with all the aguments (before we take apart `config.args`). + let mut cmd = String::new(); + for arg in config.args.iter() { + if !cmd.is_empty() { + cmd.push(' '); + } + cmd.push_str(&*shell_escape::windows::escape(arg.as_str().into())); } - cmd.push_str(&*shell_escape::windows::escape(arg.as_str().into())); - } - // Don't forget `0` terminator. - cmd.push(std::char::from_u32(0).unwrap()); - // Collect the pointers to the individual strings. - let mut argvs = Vec::>::new(); - for arg in config.args { - // Add `0` terminator. - let mut arg = arg.into_bytes(); - arg.push(0); - argvs.push( - ecx.memory - .allocate_static_bytes(arg.as_slice(), MiriMemoryKind::Static.into()), - ); - } - // Make an array with all these pointers, in the Miri memory. - let argvs_layout = ecx.layout_of( - tcx.mk_array(tcx.mk_imm_ptr(tcx.types.u8), argvs.len() as u64), - )?; - let argvs_place = ecx.allocate(argvs_layout, MiriMemoryKind::Env.into()); - for (idx, arg) in argvs.into_iter().enumerate() { - let place = ecx.mplace_field(argvs_place, idx as u64)?; - ecx.write_scalar(Scalar::Ptr(arg), place.into())?; - } - ecx.memory - .mark_immutable(argvs_place.ptr.assert_ptr().alloc_id)?; - // Write a pointer to that place as the argument. - let argv = argvs_place.ptr; - ecx.write_scalar(argv, dest)?; - // Store `argv` for macOS `_NSGetArgv`. - { - let argv_place = ecx.allocate(dest.layout, MiriMemoryKind::Env.into()); - ecx.write_scalar(argv, argv_place.into())?; - ecx.machine.argv = Some(argv_place.ptr); - } - // Store command line as UTF-16 for Windows `GetCommandLineW`. - { - let cmd_utf16: Vec = cmd.encode_utf16().collect(); - let cmd_type = tcx.mk_array(tcx.types.u16, cmd_utf16.len() as u64); - let cmd_place = ecx.allocate(ecx.layout_of(cmd_type)?, MiriMemoryKind::Env.into()); - ecx.machine.cmd_line = Some(cmd_place.ptr); - // Store the UTF-16 string. We just allocated so we know the bounds are fine. - let char_size = Size::from_bytes(2); - for (idx, &c) in cmd_utf16.iter().enumerate() { - let place = ecx.mplace_field(cmd_place, idx as u64)?; - ecx.write_scalar(Scalar::from_uint(c, char_size), place.into())?; + // Don't forget `0` terminator. + cmd.push(std::char::from_u32(0).unwrap()); + // Collect the pointers to the individual strings. + let mut argvs = Vec::>::new(); + for arg in config.args { + // Add `0` terminator. + let mut arg = arg.into_bytes(); + arg.push(0); + argvs.push( + ecx.memory + .allocate_static_bytes(arg.as_slice(), MiriMemoryKind::Static.into()), + ); } - } + // Make an array with all these pointers, in the Miri memory. + let argvs_layout = ecx.layout_of( + tcx.mk_array(tcx.mk_imm_ptr(tcx.types.u8), argvs.len() as u64), + )?; + let argvs_place = ecx.allocate(argvs_layout, MiriMemoryKind::Env.into()); + for (idx, arg) in argvs.into_iter().enumerate() { + let place = ecx.mplace_field(argvs_place, idx as u64)?; + ecx.write_scalar(Scalar::Ptr(arg), place.into())?; + } + ecx.memory + .mark_immutable(argvs_place.ptr.assert_ptr().alloc_id)?; + // A pointer to that place is the argument. + let argv = argvs_place.ptr; + // Store `argc` and `argv` for macOS `_NSGetArg{c,v}`. + { + let argc_place = ecx.allocate( + ecx.layout_of(tcx.types.isize)?, + MiriMemoryKind::Env.into(), + ); + ecx.write_scalar(argc, argc_place.into())?; + ecx.machine.argc = Some(argc_place.ptr); + + let argv_place = ecx.allocate( + ecx.layout_of(tcx.mk_imm_ptr(tcx.types.unit))?, + MiriMemoryKind::Env.into(), + ); + ecx.write_scalar(argv, argv_place.into())?; + ecx.machine.argv = Some(argv_place.ptr); + } + // Store command line as UTF-16 for Windows `GetCommandLineW`. + { + let cmd_utf16: Vec = cmd.encode_utf16().collect(); + let cmd_type = tcx.mk_array(tcx.types.u16, cmd_utf16.len() as u64); + let cmd_place = ecx.allocate(ecx.layout_of(cmd_type)?, MiriMemoryKind::Env.into()); + ecx.machine.cmd_line = Some(cmd_place.ptr); + // Store the UTF-16 string. We just allocated so we know the bounds are fine. + let char_size = Size::from_bytes(2); + for (idx, &c) in cmd_utf16.iter().enumerate() { + let place = ecx.mplace_field(cmd_place, idx as u64)?; + ecx.write_scalar(Scalar::from_uint(c, char_size), place.into())?; + } + } + argv + }; - args.next().expect_none("start lang item has more arguments than expected"); + // Return place (in static memory so that it does not count as leak). + let ret_place = ecx.allocate( + ecx.layout_of(tcx.types.isize)?, + MiriMemoryKind::Static.into(), + ); + // Call start function. + ecx.call_function( + start_instance, + &[main_ptr.into(), argc, argv], + Some(ret_place.into()), + StackPopCleanup::None { cleanup: true }, + )?; // Set the last_error to 0 let errno_layout = ecx.layout_of(tcx.types.u32)?; @@ -173,14 +154,14 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( ecx.write_scalar(Scalar::from_u32(0), errno_place.into())?; ecx.machine.last_error = Some(errno_place); - Ok((ecx, ret_ptr)) + Ok((ecx, ret_place)) } /// Evaluates the main function specified by `main_id`. /// Returns `Some(return_code)` if program executed completed. /// Returns `None` if an evaluation error occured. pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) -> Option { - let (mut ecx, ret_ptr) = match create_ecx(tcx, main_id, config) { + let (mut ecx, ret_place) = match create_ecx(tcx, main_id, config) { Ok(v) => v, Err(mut err) => { err.print_backtrace(); @@ -193,7 +174,7 @@ pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) -> ecx.run()?; // Read the return code pointer *before* we run TLS destructors, to assert // that it was written to by the time that `start` lang item returned. - let return_code = ecx.read_scalar(ret_ptr.into())?.not_undef()?.to_machine_isize(&ecx)?; + let return_code = ecx.read_scalar(ret_place.into())?.not_undef()?.to_machine_isize(&ecx)?; ecx.run_tls_dtors()?; Ok(return_code) })(); diff --git a/src/helpers.rs b/src/helpers.rs index 20f21cfc255c7..28c31a07ef579 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -1,6 +1,7 @@ use std::{mem, iter}; use std::ffi::{OsStr, OsString}; +use syntax::source_map::DUMMY_SP; use rustc::hir::def_id::{DefId, CRATE_DEF_INDEX}; use rustc::mir; use rustc::ty::{ @@ -118,6 +119,40 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.memory.write_bytes(ptr, data.iter().copied()) } + /// Call a function: Push the stack frame and pass the arguments. + /// For now, arguments must be scalars (so that the caller does not have to know the layout). + fn call_function( + &mut self, + f: ty::Instance<'tcx>, + args: &[Scalar], + dest: Option>, + stack_pop: StackPopCleanup, + ) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + + // Push frame. + let mir = this.load_mir(f.def, None)?; + this.push_stack_frame( + f, + DUMMY_SP, // There is no call site. + mir, + dest, + stack_pop, + )?; + + // Initialize arguments. + let mut callee_args = this.frame().body.args_iter(); + for arg in args { + let callee_arg = this.local_place( + callee_args.next().expect("callee has fewer arguments than expected") + )?; + this.write_scalar(*arg, callee_arg)?; + } + callee_args.next().expect_none("callee has more arguments than expected"); + + Ok(()) + } + /// Visits the memory covered by `place`, sensitive to freezing: the 3rd parameter /// will be true if this is frozen, false if this is in an `UnsafeCell`. fn visit_freeze_sensitive( diff --git a/src/machine.rs b/src/machine.rs index c405329141985..94ddee6fc0924 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -230,37 +230,26 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { dest: PlaceTy<'tcx, Tag>, ) -> InterpResult<'tcx> { trace!("box_alloc for {:?}", dest.layout.ty); + let layout = ecx.layout_of(dest.layout.ty.builtin_deref(false).unwrap().ty)?; + // First argument: `size`. + // (`0` is allowed here -- this is expected to be handled by the lang item). + let size = Scalar::from_uint(layout.size.bytes(), ecx.pointer_size()); + + // Second argument: `align`. + let align = Scalar::from_uint(layout.align.abi.bytes(), ecx.pointer_size()); + // Call the `exchange_malloc` lang item. let malloc = ecx.tcx.lang_items().exchange_malloc_fn().unwrap(); let malloc = ty::Instance::mono(ecx.tcx.tcx, malloc); - let malloc_mir = ecx.load_mir(malloc.def, None)?; - ecx.push_stack_frame( + ecx.call_function( malloc, - malloc_mir.span, - malloc_mir, + &[size, align], Some(dest), // Don't do anything when we are done. The `statement()` function will increment // the old stack frame's stmt counter to the next statement, which means that when // `exchange_malloc` returns, we go on evaluating exactly where we want to be. StackPopCleanup::None { cleanup: true }, )?; - - let mut args = ecx.frame().body.args_iter(); - let layout = ecx.layout_of(dest.layout.ty.builtin_deref(false).unwrap().ty)?; - - // First argument: `size`. - // (`0` is allowed here -- this is expected to be handled by the lang item). - let arg = ecx.local_place(args.next().unwrap())?; - let size = layout.size.bytes(); - ecx.write_scalar(Scalar::from_uint(size, arg.layout.size), arg)?; - - // Second argument: `align`. - let arg = ecx.local_place(args.next().unwrap())?; - let align = layout.align.abi.bytes(); - ecx.write_scalar(Scalar::from_uint(align, arg.layout.size), arg)?; - - // No more arguments. - args.next().expect_none("`exchange_malloc` lang item has more arguments than expected"); Ok(()) } diff --git a/src/shims/panic.rs b/src/shims/panic.rs index 42028738822a2..6cc9f176c8fa8 100644 --- a/src/shims/panic.rs +++ b/src/shims/panic.rs @@ -37,7 +37,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// Handles the special "miri_start_panic" intrinsic, which is called /// by libpanic_unwind to delegate the actual unwinding process to Miri. - #[inline(always)] fn handle_miri_start_panic( &mut self, args: &[OpTy<'tcx, Tag>], @@ -57,7 +56,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx return Ok(()) } - #[inline(always)] fn handle_catch_panic( &mut self, args: &[OpTy<'tcx, Tag>], @@ -83,30 +81,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Now we make a function call, and pass `f_arg` as first and only argument. let f_instance = this.memory.get_fn(f)?.as_instance()?; trace!("__rust_maybe_catch_panic: {:?}", f_instance); - // TODO: consider making this reusable? `InterpCx::step` does something similar - // for the TLS destructors, and of course `eval_main`. - let mir = this.load_mir(f_instance.def, None)?; let ret_place = MPlaceTy::dangling(this.layout_of(tcx.mk_unit())?, this).into(); - this.push_stack_frame( + this.call_function( f_instance, - mir.span, - mir, + &[f_arg], Some(ret_place), // Directly return to caller. StackPopCleanup::Goto { ret: Some(ret), unwind: None }, )?; - let mut args = this.frame().body.args_iter(); - // First argument. - let arg_local = args - .next() - .expect("Argument to __rust_maybe_catch_panic does not take enough arguments."); - let arg_dest = this.local_place(arg_local)?; - this.write_scalar(f_arg, arg_dest)?; - // No more arguments. - args.next().expect_none("__rust_maybe_catch_panic argument has more arguments than expected"); - // We ourselves will return `0`, eventually (will be overwritten if we catch a panic). this.write_null(dest)?; @@ -124,7 +108,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx return Ok(()); } - #[inline(always)] fn handle_stack_pop( &mut self, mut extra: FrameData<'tcx>, diff --git a/src/shims/tls.rs b/src/shims/tls.rs index b6aadd31a5be6..ea8b0df230f20 100644 --- a/src/shims/tls.rs +++ b/src/shims/tls.rs @@ -146,22 +146,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx while let Some((instance, ptr, key)) = dtor { trace!("Running TLS dtor {:?} on {:?}", instance, ptr); assert!(!this.is_null(ptr).unwrap(), "Data can't be NULL when dtor is called!"); - // TODO: Potentially, this has to support all the other possible instances? - // See eval_fn_call in interpret/terminator/mod.rs - let mir = this.load_mir(instance.def, None)?; + let ret_place = MPlaceTy::dangling(this.layout_of(this.tcx.mk_unit())?, this).into(); - this.push_stack_frame( + this.call_function( instance, - mir.span, - mir, + &[ptr], Some(ret_place), StackPopCleanup::None { cleanup: true }, )?; - let arg_local = this.frame().body.args_iter().next().ok_or_else( - || err_ub_format!("TLS dtor does not take enough arguments."), - )?; - let dest = this.local_place(arg_local)?; - this.write_scalar(ptr, dest)?; // step until out of stackframes this.run()?; From e5a81c6a2da299d13ab513d6328677caffc72cc4 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 29 Nov 2019 11:08:27 +0100 Subject: [PATCH 1350/3747] fix comment --- src/eval.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/eval.rs b/src/eval.rs index 488fdc3b37b18..986c6143ab4db 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -65,7 +65,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( let main_ptr = ecx .memory .create_fn_alloc(FnVal::Instance(main_instance)); - // Second argument (argc): `1`. + // Second argument (argc): length of `config.args`. let argc = Scalar::from_uint(config.args.len() as u128, ecx.pointer_size()); // Third argument (`argv`): created from `config.args`. let argv = { From 4a4886c0f07054e0367d90b461c11b1211b874ca Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 29 Nov 2019 21:37:59 +0100 Subject: [PATCH 1351/3747] avoid injected_panic_runtime which is going away --- src/shims/foreign_items.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index b136260f751ec..b9e6734613c05 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -135,7 +135,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Normally, this will be either `libpanic_unwind` or `libpanic_abort`, but it could // also be a custom user-provided implementation via `#![feature(panic_runtime)]` "__rust_start_panic" => { - let panic_runtime = tcx.crate_name(tcx.injected_panic_runtime().expect("No panic runtime found!")); + // FIXME we might want to cache this... but it's not really performance-critical. + let panic_runtime = tcx.crates().iter() + .find(|cnum| tcx.is_panic_runtime(**cnum)) + .expect("No panic runtime found!"); + let panic_runtime = tcx.crate_name(*panic_runtime); let start_panic_instance = this.resolve_path(&[&*panic_runtime.as_str(), "__rust_start_panic"])?; return Ok(Some(this.load_mir(start_panic_instance.def, None)?)); } From c9b3b688d5121d155cb29df78d83ce1b9cc19a98 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 30 Nov 2019 10:06:12 +0100 Subject: [PATCH 1352/3747] add toolchain mgmt script --- CONTRIBUTING.md | 46 +++++++++++++++++++--------------------------- toolchain | 40 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 59 insertions(+), 27 deletions(-) create mode 100755 toolchain diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index d6436873938ed..9338f0b8dd73e 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -12,6 +12,22 @@ on the [Rust Zulip]. [Rust Zulip]: https://rust-lang.zulipchat.com +## Building Miri with a pre-built rustc + +Miri heavily relies on internal rustc interfaces to execute MIR. Still, some +things (like adding support for a new intrinsic or a shim for an external +function being called) can be done by working just on the Miri side. + +The `rust-version` file contains the commit hash of rustc that Miri is currently +tested against. Other versions will likely not work. After installing +[`rustup-toolchain-install-master`], you can run the following command to +install that exact version of rustc as a toolchain: +``` +./toolchain +``` + +[`rustup-toolchain-install-master`]: https://github.com/kennytm/rustup-toolchain-install-master + ### Fixing Miri when rustc changes Miri is heavily tied to rustc internals, so it is very common that rustc changes @@ -20,36 +36,12 @@ Usually, Miri will require changes similar to the other consumers of the changed rustc API, so reading the rustc PR diff is a good way to get an idea for what is needed. -When submitting a PR against Miri after fixing it for rustc changes, make sure -you update the `rust-version` file. That file always contains the exact rustc -git commit with which Miri works, and it is the version that our CI tests Miri -against. - -## Building Miri with a nightly rustc - -Miri heavily relies on internal rustc interfaces to execute MIR. Still, some -things (like adding support for a new intrinsic or a shim for an external -function being called) can be done by working just on the Miri side. - -To prepare, make sure you are using a nightly Rust compiler. You also need to -have the `rust-src` and `rustc-dev` components installed, which you can add via -`rustup component add rust-src rustc-dev`. Then you should be able to just -`cargo build` Miri. - -In case this fails, your nightly might be incompatible with Miri master. The -`rust-version` file contains the commit hash of rustc that Miri is currently -tested against; you can use that to find a nightly that works or you might have -to wait for the next nightly to get released. You can also use -[`rustup-toolchain-install-master`](https://github.com/kennytm/rustup-toolchain-install-master) -to install that exact version of rustc as a toolchain: +To update the `rustc-version` file and install the latest rustc, you can run: ``` -rustup-toolchain-install-master $(cat rust-version) -c rust-src -c rustc-dev +./toolchain HEAD ``` -Another common problem is outdated dependencies: Miri does not come with a -lockfile (it cannot, due to how it gets embedded into the rustc build). So you -have to run `cargo update` every now and then yourself to make sure you are -using the latest versions of everything (which is what gets tested on CI). +Now try `./miri test`, and submit a PR once that works again. ## Testing the Miri driver [testing-miri]: #testing-the-miri-driver diff --git a/toolchain b/toolchain new file mode 100755 index 0000000000000..043b2ee2edd7b --- /dev/null +++ b/toolchain @@ -0,0 +1,40 @@ +#!/bin/bash +set -e +# Manages a rustup toolchain called "miri". +# +# All commands set "miri" as the override toolchain for the current directory, +# and make the `rust-version` file match that toolchain. +# +# USAGE: +# +# ./toolchain: Update "miri" toolchain to match `rust-version` (the known-good version for this commit). +# +# ./toolchain HEAD: Update "miri" toolchain and `rust-version` file to latest rustc HEAD. +# +# ./toolchain $COMMIT: Update "miri" toolchain and `rust-version` file to match that commit. + +# Determine new commit. +if [[ "$1" == "" ]]; then + NEW_COMMIT=$(cat rust-version) +elif [[ "$1" == "HEAD" ]]; then + NEW_COMMIT=$(git ls-remote https://github.com/rust-lang/rust/ HEAD | cut -f 1) +else + NEW_COMMIT="$1" +fi +echo "$NEW_COMMIT" > rust-version + +# Check if we already are at that commit. +CUR_COMMIT=$(rustc +miri --version -v | egrep "^commit-hash: " | cut -d " " -f 2) +if [[ "$CUR_COMMIT" == "$NEW_COMMIT" ]]; then + echo "miri toolchain is already at commit $CUR_COMMIT." + rustup override set miri + exit 0 +fi + +# Cleanup. +cargo +nightly clean # Use nightly cargo as miri toolchain might be broken. +rustup toolchain uninstall miri + +# Install and setup new toolchain. +rustup-toolchain-install-master -n miri -c rust-src -c rustc-dev -- "$NEW_COMMIT" +rustup override set miri From 6363bc497529dbce3000ec213a8023112eebd512 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 30 Nov 2019 10:31:53 +0100 Subject: [PATCH 1353/3747] test should_panic checking the panic string --- test-cargo-miri/tests/test.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test-cargo-miri/tests/test.rs b/test-cargo-miri/tests/test.rs index 5d1beaec9806f..ce85f929049bc 100644 --- a/test-cargo-miri/tests/test.rs +++ b/test-cargo-miri/tests/test.rs @@ -12,7 +12,7 @@ fn simple2() { assert_ne!(42, 24); } -// A test that won't work on miri (tests disabling tests) +// A test that won't work on miri (tests disabling tests). #[cfg(not(miri))] #[test] fn does_not_work_on_miri() { @@ -45,9 +45,9 @@ fn num_cpus() { // FIXME: Remove this `cfg` once we fix https://github.com/rust-lang/miri/issues/1059 // We cfg-gate the `should_panic` attribute and the `panic!` itself, so that the test -// stdout does not depend on the platform +// stdout does not depend on the platform. #[test] -#[cfg_attr(not(windows), should_panic)] +#[cfg_attr(not(windows), should_panic(expected="Explicit panic"))] fn do_panic() { // In large, friendly letters :) #[cfg(not(windows))] panic!("Explicit panic from test!"); From a971b8a2aec8cab720c51ef31f92b2246d83edd8 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 30 Nov 2019 10:19:00 +0100 Subject: [PATCH 1354/3747] fix for GlobalCtxt changes --- benches/helpers/miri_helper.rs | 6 +++--- src/bin/miri-rustc-tests.rs | 6 +++--- src/bin/miri.rs | 6 +++--- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/benches/helpers/miri_helper.rs b/benches/helpers/miri_helper.rs index a4f5599672045..95146513509bf 100644 --- a/benches/helpers/miri_helper.rs +++ b/benches/helpers/miri_helper.rs @@ -7,7 +7,7 @@ extern crate test; use self::miri::eval_main; use rustc::hir::def_id::LOCAL_CRATE; -use rustc_interface::interface; +use rustc_interface::{interface, Queries}; use rustc_driver::Compilation; use crate::test::Bencher; @@ -16,10 +16,10 @@ struct MiriCompilerCalls<'a> { } impl rustc_driver::Callbacks for MiriCompilerCalls<'_> { - fn after_analysis(&mut self, compiler: &interface::Compiler) -> Compilation { + fn after_analysis<'tcx>(&mut self, compiler: &interface::Compiler, queries: &'tcx Queries<'tcx>) -> Compilation { compiler.session().abort_if_errors(); - compiler.global_ctxt().unwrap().peek_mut().enter(|tcx| { + queries.global_ctxt().unwrap().peek_mut().enter(|tcx| { let (entry_def_id, _) = tcx.entry_fn(LOCAL_CRATE).expect( "no main or start function found", ); diff --git a/src/bin/miri-rustc-tests.rs b/src/bin/miri-rustc-tests.rs index 920c925443007..5e3f663de2e58 100644 --- a/src/bin/miri-rustc-tests.rs +++ b/src/bin/miri-rustc-tests.rs @@ -15,7 +15,7 @@ use std::sync::{Mutex, Arc}; use std::io; -use rustc_interface::interface; +use rustc_interface::{interface, Queries}; use rustc::hir::{self, itemlikevisit}; use rustc::ty::TyCtxt; use rustc::hir::def_id::LOCAL_CRATE; @@ -29,9 +29,9 @@ struct MiriCompilerCalls { } impl rustc_driver::Callbacks for MiriCompilerCalls { - fn after_analysis(&mut self, compiler: &interface::Compiler) -> Compilation { + fn after_analysis<'tcx>(&mut self, compiler: &interface::Compiler, queries: &'tcx Queries<'tcx>) -> Compilation { compiler.session().abort_if_errors(); - compiler.global_ctxt().unwrap().peek_mut().enter(|tcx| { + queries.global_ctxt().unwrap().peek_mut().enter(|tcx| { if std::env::args().any(|arg| arg == "--test") { struct Visitor<'tcx>(TyCtxt<'tcx>); impl<'tcx, 'hir> itemlikevisit::ItemLikeVisitor<'hir> for Visitor<'tcx> { diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 9e95e4b0a466a..59cb19476ac5c 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -20,7 +20,7 @@ use std::env; use hex::FromHexError; -use rustc_interface::interface; +use rustc_interface::{interface, Queries}; use rustc::hir::def_id::LOCAL_CRATE; use rustc_driver::Compilation; @@ -29,11 +29,11 @@ struct MiriCompilerCalls { } impl rustc_driver::Callbacks for MiriCompilerCalls { - fn after_analysis(&mut self, compiler: &interface::Compiler) -> Compilation { + fn after_analysis<'tcx>(&mut self, compiler: &interface::Compiler, queries: &'tcx Queries<'tcx>) -> Compilation { init_late_loggers(); compiler.session().abort_if_errors(); - compiler.global_ctxt().unwrap().peek_mut().enter(|tcx| { + queries.global_ctxt().unwrap().peek_mut().enter(|tcx| { let (entry_def_id, _) = tcx.entry_fn(LOCAL_CRATE).expect("no main function found!"); let mut config = self.miri_config.clone(); From f838410f492690e09626e9ae95f110f948235dce Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 1 Dec 2019 10:20:16 +0100 Subject: [PATCH 1355/3747] toolchain -> rustup-toolchain --- CONTRIBUTING.md | 4 ++-- toolchain => rustup-toolchain | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) rename toolchain => rustup-toolchain (76%) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 9338f0b8dd73e..c673e107d55d5 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -23,7 +23,7 @@ tested against. Other versions will likely not work. After installing [`rustup-toolchain-install-master`], you can run the following command to install that exact version of rustc as a toolchain: ``` -./toolchain +./rustup-toolchain ``` [`rustup-toolchain-install-master`]: https://github.com/kennytm/rustup-toolchain-install-master @@ -38,7 +38,7 @@ needed. To update the `rustc-version` file and install the latest rustc, you can run: ``` -./toolchain HEAD +./rustup-toolchain HEAD ``` Now try `./miri test`, and submit a PR once that works again. diff --git a/toolchain b/rustup-toolchain similarity index 76% rename from toolchain rename to rustup-toolchain index 043b2ee2edd7b..a981ec76548a5 100755 --- a/toolchain +++ b/rustup-toolchain @@ -7,11 +7,11 @@ set -e # # USAGE: # -# ./toolchain: Update "miri" toolchain to match `rust-version` (the known-good version for this commit). +# ./rustup-toolchain: Update "miri" toolchain to match `rust-version` (the known-good version for this commit). # -# ./toolchain HEAD: Update "miri" toolchain and `rust-version` file to latest rustc HEAD. +# ./rustup-toolchain HEAD: Update "miri" toolchain and `rust-version` file to latest rustc HEAD. # -# ./toolchain $COMMIT: Update "miri" toolchain and `rust-version` file to match that commit. +# ./rustup-toolchain $COMMIT: Update "miri" toolchain and `rust-version` file to match that commit. # Determine new commit. if [[ "$1" == "" ]]; then From 0a4ec5d34e542ff00ff41110b0fc42072bd1b4aa Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 1 Dec 2019 10:22:16 +0100 Subject: [PATCH 1356/3747] test for rustup-toolchain-install-master --- rustup-toolchain | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/rustup-toolchain b/rustup-toolchain index a981ec76548a5..096fa8857bab1 100755 --- a/rustup-toolchain +++ b/rustup-toolchain @@ -13,6 +13,12 @@ set -e # # ./rustup-toolchain $COMMIT: Update "miri" toolchain and `rust-version` file to match that commit. +# Make sure rustup-toolchain-install-master is installed. +if ! which rustup-toolchain-install-master >/dev/null; then + echo "Please install rustup-toolchain-install-master by running 'cargo install rustup-toolchain-install-master'" + exit 1 +fi + # Determine new commit. if [[ "$1" == "" ]]; then NEW_COMMIT=$(cat rust-version) From c39482b20341abe2b22834f2ec6b04199e4a3383 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 1 Dec 2019 10:29:19 +0100 Subject: [PATCH 1357/3747] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index b5ab3053c5cf8..43425c9afc589 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -809e180a76ce97340bf4354ff357bc59e3ca40b2 +4007d4ef26eab44bdabc2b7574d032152264d3ad From 2789e72e18938b4c676551d9b3d8f7ee955e5bbc Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 28 Nov 2019 19:17:43 +0100 Subject: [PATCH 1358/3747] test more panics --- tests/run-pass/catch_panic.rs | 16 ++++++++-------- tests/run-pass/catch_panic.stderr | 6 ++++++ 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/tests/run-pass/catch_panic.rs b/tests/run-pass/catch_panic.rs index c504956db35aa..88fc35067d012 100644 --- a/tests/run-pass/catch_panic.rs +++ b/tests/run-pass/catch_panic.rs @@ -44,14 +44,14 @@ fn main() { prev(panic_info) })); - test(|_old_val| panic!("Hello from panic: std")); - test(|old_val| panic!(format!("Hello from panic: {:?}", old_val))); - test(|old_val| panic!("Hello from panic: {:?}", old_val)); - test(|_old_val| panic!(1337)); - // FIXME https://github.com/rust-lang/miri/issues/1071 - //test(|_old_val| core::panic!("Hello from panic: core")); - //test(|old_val| core::panic!(&format!("Hello from panic: {:?}", old_val))); - //test(|old_val| core::panic!("Hello from panic: {:?}", old_val)); + test(|_old_val| std::panic!("Hello from panic: std")); + test(|old_val| std::panic!(format!("Hello from panic: {:?}", old_val))); + test(|old_val| std::panic!("Hello from panic: {:?}", old_val)); + test(|_old_val| std::panic!(1337)); + + test(|_old_val| core::panic!("Hello from panic: core")); + test(|old_val| core::panic!(&format!("Hello from panic: {:?}", old_val))); + test(|old_val| core::panic!("Hello from panic: {:?}", old_val)); // Cleanup: reset to default hook. drop(std::panic::take_hook()); diff --git a/tests/run-pass/catch_panic.stderr b/tests/run-pass/catch_panic.stderr index 6d905da7febe6..51814c7cde6e9 100644 --- a/tests/run-pass/catch_panic.stderr +++ b/tests/run-pass/catch_panic.stderr @@ -6,4 +6,10 @@ thread 'main' panicked at 'Hello from panic: 2', $DIR/catch_panic.rs:49:20 Caught panic message (String): Hello from panic: 2 thread 'main' panicked at 'Box', $DIR/catch_panic.rs:50:21 Failed get caught panic message. +thread 'main' panicked at 'Hello from panic: core', tests/run-pass/catch_panic.rs:52:21 +Caught panic message (String): Hello from panic: core +thread 'main' panicked at 'Hello from panic: 5', tests/run-pass/catch_panic.rs:53:20 +Caught panic message (String): Hello from panic: 5 +thread 'main' panicked at 'Hello from panic: 6', tests/run-pass/catch_panic.rs:54:20 +Caught panic message (String): Hello from panic: 6 Success! From f7efe238f3c999b815da3e7b736136360c973c59 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 1 Dec 2019 11:04:51 +0100 Subject: [PATCH 1359/3747] fix catch_panic.stderr --- tests/run-pass/catch_panic.stderr | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/run-pass/catch_panic.stderr b/tests/run-pass/catch_panic.stderr index 51814c7cde6e9..be729005dd56b 100644 --- a/tests/run-pass/catch_panic.stderr +++ b/tests/run-pass/catch_panic.stderr @@ -6,10 +6,10 @@ thread 'main' panicked at 'Hello from panic: 2', $DIR/catch_panic.rs:49:20 Caught panic message (String): Hello from panic: 2 thread 'main' panicked at 'Box', $DIR/catch_panic.rs:50:21 Failed get caught panic message. -thread 'main' panicked at 'Hello from panic: core', tests/run-pass/catch_panic.rs:52:21 +thread 'main' panicked at 'Hello from panic: core', $DIR/catch_panic.rs:52:21 Caught panic message (String): Hello from panic: core -thread 'main' panicked at 'Hello from panic: 5', tests/run-pass/catch_panic.rs:53:20 +thread 'main' panicked at 'Hello from panic: 5', $DIR/catch_panic.rs:53:20 Caught panic message (String): Hello from panic: 5 -thread 'main' panicked at 'Hello from panic: 6', tests/run-pass/catch_panic.rs:54:20 +thread 'main' panicked at 'Hello from panic: 6', $DIR/catch_panic.rs:54:20 Caught panic message (String): Hello from panic: 6 Success! From 3de5bd7decec2440a7696fdad72bf6f7698afa61 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 1 Dec 2019 12:57:09 +0100 Subject: [PATCH 1360/3747] run-test: make sure the sysroot building output does not distort our tests --- test-cargo-miri/run-test.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/test-cargo-miri/run-test.py b/test-cargo-miri/run-test.py index 499c2e896f172..a4086bcc8c99d 100755 --- a/test-cargo-miri/run-test.py +++ b/test-cargo-miri/run-test.py @@ -67,6 +67,10 @@ def test_cargo_miri_test(): os.chdir(os.path.dirname(os.path.realpath(__file__))) +if not 'MIRI_SYSROOT' in os.environ: + # Make sure we got a working sysroot. + # (If the sysroot gets built later when output is compared, that leads to test failures.) + subprocess.run(cargo_miri("setup"), check=True) test_cargo_miri_run() test_cargo_miri_test() From 9501d044c1afcd2c7921e48ef17930977d156dec Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 1 Dec 2019 15:16:55 +0100 Subject: [PATCH 1361/3747] don't assume a nightly toolchain is installed --- rustup-toolchain | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/rustup-toolchain b/rustup-toolchain index 096fa8857bab1..4e8e0b01ebc47 100755 --- a/rustup-toolchain +++ b/rustup-toolchain @@ -30,17 +30,17 @@ fi echo "$NEW_COMMIT" > rust-version # Check if we already are at that commit. -CUR_COMMIT=$(rustc +miri --version -v | egrep "^commit-hash: " | cut -d " " -f 2) +CUR_COMMIT=$(rustc +miri --version -v 2>/dev/null | egrep "^commit-hash: " | cut -d " " -f 2) if [[ "$CUR_COMMIT" == "$NEW_COMMIT" ]]; then echo "miri toolchain is already at commit $CUR_COMMIT." rustup override set miri exit 0 fi -# Cleanup. -cargo +nightly clean # Use nightly cargo as miri toolchain might be broken. -rustup toolchain uninstall miri - # Install and setup new toolchain. +rustup toolchain uninstall miri rustup-toolchain-install-master -n miri -c rust-src -c rustc-dev -- "$NEW_COMMIT" rustup override set miri + +# Cleanup. +cargo clean From f3c00a447c4d67053746bbfc40b41c0225f4b5dd Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 2 Dec 2019 09:05:35 +0100 Subject: [PATCH 1362/3747] use new MachineStop error variant --- rust-version | 2 +- src/eval.rs | 16 +++++++++++++++- src/lib.rs | 2 +- src/shims/foreign_items.rs | 5 +++-- 4 files changed, 20 insertions(+), 5 deletions(-) diff --git a/rust-version b/rust-version index 43425c9afc589..3a0cf96e13275 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -4007d4ef26eab44bdabc2b7574d032152264d3ad +f5c81e0a986e4285d3d0fd781a1bd475753eb12c diff --git a/src/eval.rs b/src/eval.rs index 986c6143ab4db..2c165760418f4 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -24,6 +24,12 @@ pub struct MiriConfig { pub seed: Option, } +/// Details of premature program termination. +pub enum TerminationInfo { + Exit(i64), + Abort, +} + /// Returns a freshly created `InterpCx`, along with an `MPlaceTy` representing /// the location where the return value of the `start` lang item will be /// written to. @@ -200,7 +206,15 @@ pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) -> Err(mut e) => { // Special treatment for some error kinds let msg = match e.kind { - InterpError::Exit(code) => return Some(code.into()), + InterpError::MachineStop(ref info) => { + let info = info.downcast_ref::() + .expect("invalid MachineStop payload"); + match info { + TerminationInfo::Exit(code) => return Some(*code), + TerminationInfo::Abort => + format!("The program aborted execution") + } + } err_unsup!(NoMirFor(..)) => format!("{}. Did you set `MIRI_SYSROOT` to a Miri-enabled sysroot? You can prepare one with `cargo miri setup`.", e), _ => e.to_string() diff --git a/src/lib.rs b/src/lib.rs index f29ec8f22bbae..05234e880f58c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -47,7 +47,7 @@ pub use crate::machine::{ PAGE_SIZE, STACK_ADDR, STACK_SIZE, NUM_CPUS, MemoryExtra, AllocExtra, MiriMemoryKind, Evaluator, MiriEvalContext, MiriEvalContextExt, }; -pub use crate::eval::{eval_main, create_ecx, MiriConfig}; +pub use crate::eval::{eval_main, create_ecx, MiriConfig, TerminationInfo}; /// Insert rustc arguments at the beginning of the argument list that Miri wants to be /// set per default, for maximal validation power. diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index b9e6734613c05..114931e435a4c 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -152,9 +152,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "exit" | "ExitProcess" => { - // it's really u32 for ExitProcess, but we have to put it into the `Exit` error variant anyway + // it's really u32 for ExitProcess, but we have to put it into the `Exit` variant anyway let code = this.read_scalar(args[0])?.to_i32()?; - return Err(InterpError::Exit(code).into()); + let ti = Box::new(TerminationInfo::Exit(code.into())); + return Err(InterpError::MachineStop(ti).into()); } _ => { if let Some(p) = ret { From 1c420b0b5538a9bd1d81b02e7d3d775e85fe0a4d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 2 Dec 2019 09:11:33 +0100 Subject: [PATCH 1363/3747] improve style in catch_panic test --- tests/run-pass/catch_panic.rs | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/tests/run-pass/catch_panic.rs b/tests/run-pass/catch_panic.rs index 88fc35067d012..4c8b4cba9005f 100644 --- a/tests/run-pass/catch_panic.rs +++ b/tests/run-pass/catch_panic.rs @@ -70,17 +70,13 @@ fn test(do_panic: impl FnOnce(usize) -> !) { do_panic_counter(do_panic) })).expect_err("do_panic() did not panic!"); - // See if we can extract panic message. - match res.downcast::() { - Ok(s) => { - eprintln!("Caught panic message (String): {}", s); - } - Err(res) => - if let Ok(s) = res.downcast::<&str>() { - eprintln!("Caught panic message (&str): {}", s); - } else { - eprintln!("Failed get caught panic message."); - } + // See if we can extract the panic message. + if let Some(s) = res.downcast_ref::() { + eprintln!("Caught panic message (String): {}", s); + } else if let Some(s) = res.downcast_ref::<&str>() { + eprintln!("Caught panic message (&str): {}", s); + } else { + eprintln!("Failed get caught panic message."); } // Test flags. From dcdd68b9364fb5410fccd5f66d334f6436273c4c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 2 Dec 2019 09:13:58 +0100 Subject: [PATCH 1364/3747] also indicate abort via new MachineStop variant --- src/eval.rs | 2 +- src/shims/intrinsics.rs | 5 ++--- tests/compile-fail/double_panic.rs | 2 +- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/eval.rs b/src/eval.rs index 2c165760418f4..dbb14b7bb189a 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -212,7 +212,7 @@ pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) -> match info { TerminationInfo::Exit(code) => return Some(*code), TerminationInfo::Abort => - format!("The program aborted execution") + format!("the evaluated program aborted execution") } } err_unsup!(NoMirFor(..)) => diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 00886328030bb..0cb51d593199e 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -34,9 +34,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Handle diverging intrinsics. let (dest, ret) = match intrinsic_name { "abort" => { - // FIXME: Add a better way of indicating 'abnormal' termination, - // since this is not really an 'unsupported' behavior - throw_unsup_format!("the evaluated program aborted!"); + let ti = Box::new(TerminationInfo::Abort); + return Err(InterpError::MachineStop(ti).into()); } "miri_start_panic" => return this.handle_miri_start_panic(args, unwind), _ => { diff --git a/tests/compile-fail/double_panic.rs b/tests/compile-fail/double_panic.rs index 950d865c2a562..759762196b758 100644 --- a/tests/compile-fail/double_panic.rs +++ b/tests/compile-fail/double_panic.rs @@ -1,4 +1,4 @@ - //error-pattern: the evaluated program aborted + // error-pattern: the evaluated program aborted struct Foo; impl Drop for Foo { fn drop(&mut self) { From bba9359256d5b5ffa4caef5c60237ca2b325c7f7 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 27 Nov 2019 21:50:20 +0100 Subject: [PATCH 1365/3747] expand coerce fn test --- .../coerce_non_capture_closure_to_fn_ptr.rs | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/tests/run-pass/coerce_non_capture_closure_to_fn_ptr.rs b/tests/run-pass/coerce_non_capture_closure_to_fn_ptr.rs index 4da2c0c61b4aa..71f244b2bc27a 100644 --- a/tests/run-pass/coerce_non_capture_closure_to_fn_ptr.rs +++ b/tests/run-pass/coerce_non_capture_closure_to_fn_ptr.rs @@ -5,8 +5,10 @@ static FOO: fn() = || { assert_ne!(42, 43) }; static BAR: fn(i32, i32) = |a, b| { assert_ne!(a, b) }; // use to first make the closure FnOnce() before making it fn() -fn magic0 R>(f: F) -> F { f } -fn magic1 R>(f: F) -> F { f } +fn force_once0 R>(f: F) -> F { f } +fn force_once1 R>(f: F) -> F { f } +fn force_mut0 R>(f: F) -> F { f } +fn force_mut1 R>(f: F) -> F { f } fn main() { FOO(); @@ -18,12 +20,16 @@ fn main() { let f: fn() = ||{}; f(); - let f = magic0(||{}) as fn(); + let f = force_once0(||{}) as fn(); + f(); + let f = force_mut0(||{}) as fn(); f(); let g: fn(i32) = |i| assert_eq!(i, 2); g(2); - let g = magic1(|i| assert_eq!(i, 2)) as fn(i32); + let g = force_once1(|i| assert_eq!(i, 2)) as fn(i32); + g(2); + let g = force_mut1(|i| assert_eq!(i, 2)) as fn(i32); g(2); // FIXME: This fails with "invalid use of NULL pointer" From 9f9e547d791c5031f2dde9fa5424903d52934cc1 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 27 Nov 2019 23:28:59 +0100 Subject: [PATCH 1366/3747] test diverging closure fn ptr coercion --- tests/run-pass/coerce_non_capture_closure_to_fn_ptr.rs | 8 -------- tests/run-pass/issue-miri-1075.rs | 6 ++++++ 2 files changed, 6 insertions(+), 8 deletions(-) create mode 100644 tests/run-pass/issue-miri-1075.rs diff --git a/tests/run-pass/coerce_non_capture_closure_to_fn_ptr.rs b/tests/run-pass/coerce_non_capture_closure_to_fn_ptr.rs index 71f244b2bc27a..32393a37d2ec4 100644 --- a/tests/run-pass/coerce_non_capture_closure_to_fn_ptr.rs +++ b/tests/run-pass/coerce_non_capture_closure_to_fn_ptr.rs @@ -31,12 +31,4 @@ fn main() { g(2); let g = force_mut1(|i| assert_eq!(i, 2)) as fn(i32); g(2); - - // FIXME: This fails with "invalid use of NULL pointer" - //let h: fn() -> ! = || std::process::exit(0); - //h(); - // FIXME: This does not even compile?!? - //let h = magic0(|| std::process::exit(0)) as fn() -> !; - //h(); - // Once these tests pass, they should be in separate files as they terminate the process. } diff --git a/tests/run-pass/issue-miri-1075.rs b/tests/run-pass/issue-miri-1075.rs new file mode 100644 index 0000000000000..8bacaca9c2ac2 --- /dev/null +++ b/tests/run-pass/issue-miri-1075.rs @@ -0,0 +1,6 @@ +fn main() { + let f: fn() -> ! = || std::process::exit(0); + f(); + + // FIXME: Also add a test for , once that is fixed. +} From 42732cc9bb6cec922b9cc0ef723e97dd0b83bc52 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 2 Dec 2019 15:42:38 +0100 Subject: [PATCH 1367/3747] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 3a0cf96e13275..b2b29eb527950 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -f5c81e0a986e4285d3d0fd781a1bd475753eb12c +4af3ee8ee2a2bc1286b021db7600ba990359cf3f From 8a36d12d3664ab0e882ce98bacd6f7f95000f6a2 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 29 Nov 2019 10:16:03 +0100 Subject: [PATCH 1368/3747] implement proper panicking for failed index check --- src/lib.rs | 3 ++- src/machine.rs | 10 ++++++++++ src/shims/panic.rs | 40 +++++++++++++++++++++++++++++++++++++--- 3 files changed, 49 insertions(+), 4 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 05234e880f58c..abed7ab9dfeb7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -38,6 +38,7 @@ pub use crate::shims::dlsym::{Dlsym, EvalContextExt as DlsymEvalContextExt}; pub use crate::shims::env::{EnvVars, EvalContextExt as EnvEvalContextExt}; pub use crate::shims::fs::{FileHandler, EvalContextExt as FileEvalContextExt}; pub use crate::shims::panic::{CatchUnwindData, EvalContextExt as PanicEvalContextExt}; + pub use crate::operator::EvalContextExt as OperatorEvalContextExt; pub use crate::range_map::RangeMap; pub use crate::helpers::{EvalContextExt as HelpersEvalContextExt}; @@ -45,7 +46,7 @@ pub use crate::mono_hash_map::MonoHashMap; pub use crate::stacked_borrows::{EvalContextExt as StackedBorEvalContextExt, Tag, Permission, Stack, Stacks, Item}; pub use crate::machine::{ PAGE_SIZE, STACK_ADDR, STACK_SIZE, NUM_CPUS, - MemoryExtra, AllocExtra, MiriMemoryKind, Evaluator, MiriEvalContext, MiriEvalContextExt, + MemoryExtra, AllocExtra, FrameData, MiriMemoryKind, Evaluator, MiriEvalContext, MiriEvalContextExt, }; pub use crate::eval::{eval_main, create_ecx, MiriConfig, TerminationInfo}; diff --git a/src/machine.rs b/src/machine.rs index 94ddee6fc0924..07864ac4ee468 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -215,6 +215,16 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { ecx.call_intrinsic(span, instance, args, ret, unwind) } + #[inline(always)] + fn assert_panic( + ecx: &mut InterpCx<'mir, 'tcx, Self>, + span: Span, + msg: &AssertMessage<'tcx>, + unwind: Option, + ) -> InterpResult<'tcx> { + ecx.assert_panic(span, msg, unwind) + } + #[inline(always)] fn binary_ptr_op( ecx: &rustc_mir::interpret::InterpCx<'mir, 'tcx, Self>, diff --git a/src/shims/panic.rs b/src/shims/panic.rs index 6cc9f176c8fa8..4b9cb6b41955d 100644 --- a/src/shims/panic.rs +++ b/src/shims/panic.rs @@ -11,11 +11,12 @@ //! gets popped *during unwinding*, we take the panic payload and store it according to the extra //! metadata we remembered when pushing said frame. +use syntax::source_map::Span; use rustc::mir; -use crate::*; -use super::machine::FrameData; +use rustc::ty::{self, layout::LayoutOf}; use rustc_target::spec::PanicStrategy; -use crate::rustc_target::abi::LayoutOf; + +use crate::*; /// Holds all of the relevant data for a call to /// `__rust_maybe_catch_panic`. @@ -150,4 +151,37 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.memory.extra.stacked_borrows.borrow_mut().end_call(extra.call_id); Ok(res) } + + fn assert_panic( + &mut self, + span: Span, + msg: &AssertMessage<'tcx>, + unwind: Option, + ) -> InterpResult<'tcx> { + use rustc::mir::interpret::PanicInfo::*; + let this = self.eval_context_mut(); + + match msg { + BoundsCheck { ref index, ref len } => { + // First arg: Caller location. + let location = this.alloc_caller_location_for_span(span)?; + // Second arg: index. + let index = this.read_scalar(this.eval_operand(index, None)?)?; + // Third arg: len. + let len = this.read_scalar(this.eval_operand(len, None)?)?; + + // Call the lang item. + let panic_bounds_check = this.tcx.lang_items().panic_bounds_check_fn().unwrap(); + let panic_bounds_check = ty::Instance::mono(this.tcx.tcx, panic_bounds_check); + this.call_function( + panic_bounds_check, + &[location.ptr, index.not_undef()?, len.not_undef()?], + None, + StackPopCleanup::Goto { ret: None, unwind }, + )?; + } + _ => unimplemented!() + } + Ok(()) + } } From b91383b068dcd8c7cb287858e781c80323601fa5 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 29 Nov 2019 11:17:44 +0100 Subject: [PATCH 1369/3747] implement proper panicking for other MIR assertions Requires generalizing the call_function helper to arbitrary Immediate arguments --- src/eval.rs | 4 ++-- src/helpers.rs | 4 ++-- src/machine.rs | 2 +- src/shims/env.rs | 2 +- src/shims/foreign_items.rs | 8 ++++---- src/shims/panic.rs | 27 ++++++++++++++++++++++++--- src/shims/tls.rs | 2 +- 7 files changed, 35 insertions(+), 14 deletions(-) diff --git a/src/eval.rs b/src/eval.rs index dbb14b7bb189a..f13ef89ff7fe5 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -103,7 +103,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( let argvs_place = ecx.allocate(argvs_layout, MiriMemoryKind::Env.into()); for (idx, arg) in argvs.into_iter().enumerate() { let place = ecx.mplace_field(argvs_place, idx as u64)?; - ecx.write_scalar(Scalar::Ptr(arg), place.into())?; + ecx.write_scalar(arg, place.into())?; } ecx.memory .mark_immutable(argvs_place.ptr.assert_ptr().alloc_id)?; @@ -149,7 +149,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( // Call start function. ecx.call_function( start_instance, - &[main_ptr.into(), argc, argv], + &[main_ptr.into(), argc.into(), argv.into()], Some(ret_place.into()), StackPopCleanup::None { cleanup: true }, )?; diff --git a/src/helpers.rs b/src/helpers.rs index 28c31a07ef579..68ce014c30689 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -124,7 +124,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn call_function( &mut self, f: ty::Instance<'tcx>, - args: &[Scalar], + args: &[Immediate], dest: Option>, stack_pop: StackPopCleanup, ) -> InterpResult<'tcx> { @@ -146,7 +146,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let callee_arg = this.local_place( callee_args.next().expect("callee has fewer arguments than expected") )?; - this.write_scalar(*arg, callee_arg)?; + this.write_immediate(*arg, callee_arg)?; } callee_args.next().expect_none("callee has more arguments than expected"); diff --git a/src/machine.rs b/src/machine.rs index 07864ac4ee468..980c6115e91cd 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -253,7 +253,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { let malloc = ty::Instance::mono(ecx.tcx.tcx, malloc); ecx.call_function( malloc, - &[size, align], + &[size.into(), align.into()], Some(dest), // Don't do anything when we are done. The `statement()` function will increment // the old stack frame's stmt counter to the next statement, which means that when diff --git a/src/shims/env.rs b/src/shims/env.rs index 44896fd9bbd56..ae8dae0313f1b 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -57,7 +57,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(match this.machine.env_vars.map.get(name) { // The offset is used to strip the "{name}=" part of the string. Some(var_ptr) => { - Scalar::Ptr(var_ptr.offset(Size::from_bytes(name.len() as u64 + 1), this)?) + Scalar::from(var_ptr.offset(Size::from_bytes(name.len() as u64 + 1), this)?) } None => Scalar::ptr_null(&*this.tcx), }) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 114931e435a4c..f27b4fb333527 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -205,7 +205,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Align::from_bytes(align).unwrap(), MiriMemoryKind::C.into(), ); - this.write_scalar(Scalar::Ptr(ptr), ret.into())?; + this.write_scalar(ptr, ret.into())?; } this.write_null(dest)?; } @@ -234,7 +234,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Align::from_bytes(align).unwrap(), MiriMemoryKind::Rust.into(), ); - this.write_scalar(Scalar::Ptr(ptr), dest)?; + this.write_scalar(ptr, dest)?; } "__rust_alloc_zeroed" => { let size = this.read_scalar(args[0])?.to_machine_usize(this)?; @@ -254,7 +254,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.memory .write_bytes(ptr.into(), iter::repeat(0u8).take(size as usize)) .unwrap(); - this.write_scalar(Scalar::Ptr(ptr), dest)?; + this.write_scalar(ptr, dest)?; } "__rust_dealloc" => { let ptr = this.read_scalar(args[0])?.not_undef()?; @@ -295,7 +295,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx align, MiriMemoryKind::Rust.into(), )?; - this.write_scalar(Scalar::Ptr(new_ptr), dest)?; + this.write_scalar(new_ptr, dest)?; } "syscall" => { diff --git a/src/shims/panic.rs b/src/shims/panic.rs index 4b9cb6b41955d..7cdd81d935c2e 100644 --- a/src/shims/panic.rs +++ b/src/shims/panic.rs @@ -86,7 +86,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx MPlaceTy::dangling(this.layout_of(tcx.mk_unit())?, this).into(); this.call_function( f_instance, - &[f_arg], + &[f_arg.into()], Some(ret_place), // Directly return to caller. StackPopCleanup::Goto { ret: Some(ret), unwind: None }, @@ -163,6 +163,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx match msg { BoundsCheck { ref index, ref len } => { + // Forward to `panic_bounds_check` lang item. + // First arg: Caller location. let location = this.alloc_caller_location_for_span(span)?; // Second arg: index. @@ -175,12 +177,31 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let panic_bounds_check = ty::Instance::mono(this.tcx.tcx, panic_bounds_check); this.call_function( panic_bounds_check, - &[location.ptr, index.not_undef()?, len.not_undef()?], + &[location.ptr.into(), index.into(), len.into()], + None, + StackPopCleanup::Goto { ret: None, unwind }, + )?; + } + _ => { + // Forward everything else to `panic` lang item. + + // First arg: Message. + let msg = msg.description(); + let msg = this.allocate_str(msg, MiriMemoryKind::Static.into()); + + // Second arg: Caller location. + let location = this.alloc_caller_location_for_span(span)?; + + // Call the lang item. + let panic = this.tcx.lang_items().panic_fn().unwrap(); + let panic = ty::Instance::mono(this.tcx.tcx, panic); + this.call_function( + panic, + &[msg.to_ref(), location.ptr.into()], None, StackPopCleanup::Goto { ret: None, unwind }, )?; } - _ => unimplemented!() } Ok(()) } diff --git a/src/shims/tls.rs b/src/shims/tls.rs index ea8b0df230f20..420fd63a6181e 100644 --- a/src/shims/tls.rs +++ b/src/shims/tls.rs @@ -150,7 +150,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let ret_place = MPlaceTy::dangling(this.layout_of(this.tcx.mk_unit())?, this).into(); this.call_function( instance, - &[ptr], + &[ptr.into()], Some(ret_place), StackPopCleanup::None { cleanup: true }, )?; From 4cf83433b1fb17e3d08fe68a12ee58c7960330cc Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 29 Nov 2019 11:19:15 +0100 Subject: [PATCH 1370/3747] test built-in panic catching --- tests/run-pass/catch_panic.rs | 8 ++++++++ tests/run-pass/catch_panic.stderr | 18 +++++++++++------- 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/tests/run-pass/catch_panic.rs b/tests/run-pass/catch_panic.rs index 4c8b4cba9005f..a14dd411c1c66 100644 --- a/tests/run-pass/catch_panic.rs +++ b/tests/run-pass/catch_panic.rs @@ -1,4 +1,6 @@ // ignore-windows: Unwind panicking does not currently work on Windows +#![allow(const_err)] + use std::panic::{catch_unwind, AssertUnwindSafe}; use std::cell::Cell; @@ -44,15 +46,21 @@ fn main() { prev(panic_info) })); + // Std panics test(|_old_val| std::panic!("Hello from panic: std")); test(|old_val| std::panic!(format!("Hello from panic: {:?}", old_val))); test(|old_val| std::panic!("Hello from panic: {:?}", old_val)); test(|_old_val| std::panic!(1337)); + // Core panics test(|_old_val| core::panic!("Hello from panic: core")); test(|old_val| core::panic!(&format!("Hello from panic: {:?}", old_val))); test(|old_val| core::panic!("Hello from panic: {:?}", old_val)); + // Built-in panics + test(|_old_val| { let _val = [0, 1, 2][4]; loop {} }); + test(|_old_val| { let _val = 1/0; loop {} }); + // Cleanup: reset to default hook. drop(std::panic::take_hook()); diff --git a/tests/run-pass/catch_panic.stderr b/tests/run-pass/catch_panic.stderr index be729005dd56b..fd9a2f14ec3b3 100644 --- a/tests/run-pass/catch_panic.stderr +++ b/tests/run-pass/catch_panic.stderr @@ -1,15 +1,19 @@ -thread 'main' panicked at 'Hello from panic: std', $DIR/catch_panic.rs:47:21 +thread 'main' panicked at 'Hello from panic: std', $DIR/catch_panic.rs:50:21 Caught panic message (&str): Hello from panic: std -thread 'main' panicked at 'Hello from panic: 1', $DIR/catch_panic.rs:48:20 +thread 'main' panicked at 'Hello from panic: 1', $DIR/catch_panic.rs:51:20 Caught panic message (String): Hello from panic: 1 -thread 'main' panicked at 'Hello from panic: 2', $DIR/catch_panic.rs:49:20 +thread 'main' panicked at 'Hello from panic: 2', $DIR/catch_panic.rs:52:20 Caught panic message (String): Hello from panic: 2 -thread 'main' panicked at 'Box', $DIR/catch_panic.rs:50:21 +thread 'main' panicked at 'Box', $DIR/catch_panic.rs:53:21 Failed get caught panic message. -thread 'main' panicked at 'Hello from panic: core', $DIR/catch_panic.rs:52:21 +thread 'main' panicked at 'Hello from panic: core', $DIR/catch_panic.rs:56:21 Caught panic message (String): Hello from panic: core -thread 'main' panicked at 'Hello from panic: 5', $DIR/catch_panic.rs:53:20 +thread 'main' panicked at 'Hello from panic: 5', $DIR/catch_panic.rs:57:20 Caught panic message (String): Hello from panic: 5 -thread 'main' panicked at 'Hello from panic: 6', $DIR/catch_panic.rs:54:20 +thread 'main' panicked at 'Hello from panic: 6', $DIR/catch_panic.rs:58:20 Caught panic message (String): Hello from panic: 6 +thread 'main' panicked at 'index out of bounds: the len is 3 but the index is 4', $DIR/catch_panic.rs:61:34 +Caught panic message (String): index out of bounds: the len is 3 but the index is 4 +thread 'main' panicked at 'attempt to divide by zero', $DIR/catch_panic.rs:62:34 +Caught panic message (String): attempt to divide by zero Success! From b2cddd27bd1ba25f20cb5608d73053170f2ed83b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 29 Nov 2019 11:52:53 +0100 Subject: [PATCH 1371/3747] better span for functions whose frame we push 'manually' --- src/eval.rs | 7 +------ src/helpers.rs | 6 +++++- src/shims/panic.rs | 4 ++-- 3 files changed, 8 insertions(+), 9 deletions(-) diff --git a/src/eval.rs b/src/eval.rs index f13ef89ff7fe5..33bcfcc7380e2 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -221,12 +221,7 @@ pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) -> }; e.print_backtrace(); if let Some(frame) = ecx.stack().last() { - let block = &frame.body.basic_blocks()[frame.block.unwrap()]; - let span = if frame.stmt < block.statements.len() { - block.statements[frame.stmt].source_info.span - } else { - block.terminator().source_info.span - }; + let span = frame.current_source_info().unwrap().span; let msg = format!("Miri evaluation error: {}", msg); let mut err = ecx.tcx.sess.struct_span_err(span, msg.as_str()); diff --git a/src/helpers.rs b/src/helpers.rs index 68ce014c30689..7bd29e1741946 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -132,9 +132,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Push frame. let mir = this.load_mir(f.def, None)?; + let span = this.stack().last() + .and_then(Frame::current_source_info) + .map(|si| si.span) + .unwrap_or(DUMMY_SP); this.push_stack_frame( f, - DUMMY_SP, // There is no call site. + span, mir, dest, stack_pop, diff --git a/src/shims/panic.rs b/src/shims/panic.rs index 7cdd81d935c2e..3e82519f86b14 100644 --- a/src/shims/panic.rs +++ b/src/shims/panic.rs @@ -166,7 +166,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Forward to `panic_bounds_check` lang item. // First arg: Caller location. - let location = this.alloc_caller_location_for_span(span)?; + let location = this.alloc_caller_location_for_span(span); // Second arg: index. let index = this.read_scalar(this.eval_operand(index, None)?)?; // Third arg: len. @@ -190,7 +190,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let msg = this.allocate_str(msg, MiriMemoryKind::Static.into()); // Second arg: Caller location. - let location = this.alloc_caller_location_for_span(span)?; + let location = this.alloc_caller_location_for_span(span); // Call the lang item. let panic = this.tcx.lang_items().panic_fn().unwrap(); From ae53b1222a1cbb21b057e294ea93f1283210fb1a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 29 Nov 2019 13:18:54 +0100 Subject: [PATCH 1372/3747] fix and expand panic tests --- tests/compile-fail/div-by-zero-2.rs | 5 ----- tests/compile-fail/overflowing-lsh-neg.rs | 6 ------ tests/compile-fail/overflowing-rsh-1.rs | 5 ----- tests/compile-fail/{ => panic}/panic_abort1.rs | 0 tests/compile-fail/{ => panic}/panic_abort2.rs | 0 tests/compile-fail/{ => panic}/panic_abort3.rs | 0 tests/compile-fail/{ => panic}/panic_abort4.rs | 0 tests/run-pass/{ => panic}/catch_panic.rs | 0 tests/run-pass/{ => panic}/catch_panic.stderr | 0 tests/run-pass/panic/div-by-zero-2.rs | 6 ++++++ tests/run-pass/panic/div-by-zero-2.stderr | 1 + tests/run-pass/panic/overflowing-lsh-neg.rs | 7 +++++++ tests/run-pass/panic/overflowing-lsh-neg.stderr | 1 + tests/run-pass/panic/overflowing-rsh-1.rs | 6 ++++++ tests/run-pass/panic/overflowing-rsh-1.stderr | 1 + .../{compile-fail => run-pass/panic}/overflowing-rsh-2.rs | 3 ++- tests/run-pass/panic/overflowing-rsh-2.stderr | 1 + tests/run-pass/panic/panic1.rs | 4 ++++ tests/run-pass/panic/panic1.stderr | 1 + tests/run-pass/panic/panic2.rs | 4 ++++ tests/run-pass/panic/panic2.stderr | 1 + tests/run-pass/panic/panic3.rs | 4 ++++ tests/run-pass/panic/panic3.stderr | 1 + tests/run-pass/panic/panic4.rs | 4 ++++ tests/run-pass/panic/panic4.stderr | 1 + tests/{compile-fail => run-pass/panic}/transmute_fat2.rs | 2 +- tests/run-pass/panic/transmute_fat2.stderr | 1 + 27 files changed, 47 insertions(+), 18 deletions(-) delete mode 100644 tests/compile-fail/div-by-zero-2.rs delete mode 100644 tests/compile-fail/overflowing-lsh-neg.rs delete mode 100644 tests/compile-fail/overflowing-rsh-1.rs rename tests/compile-fail/{ => panic}/panic_abort1.rs (100%) rename tests/compile-fail/{ => panic}/panic_abort2.rs (100%) rename tests/compile-fail/{ => panic}/panic_abort3.rs (100%) rename tests/compile-fail/{ => panic}/panic_abort4.rs (100%) rename tests/run-pass/{ => panic}/catch_panic.rs (100%) rename tests/run-pass/{ => panic}/catch_panic.stderr (100%) create mode 100644 tests/run-pass/panic/div-by-zero-2.rs create mode 100644 tests/run-pass/panic/div-by-zero-2.stderr create mode 100644 tests/run-pass/panic/overflowing-lsh-neg.rs create mode 100644 tests/run-pass/panic/overflowing-lsh-neg.stderr create mode 100644 tests/run-pass/panic/overflowing-rsh-1.rs create mode 100644 tests/run-pass/panic/overflowing-rsh-1.stderr rename tests/{compile-fail => run-pass/panic}/overflowing-rsh-2.rs (54%) create mode 100644 tests/run-pass/panic/overflowing-rsh-2.stderr create mode 100644 tests/run-pass/panic/panic1.rs create mode 100644 tests/run-pass/panic/panic1.stderr create mode 100644 tests/run-pass/panic/panic2.rs create mode 100644 tests/run-pass/panic/panic2.stderr create mode 100644 tests/run-pass/panic/panic3.rs create mode 100644 tests/run-pass/panic/panic3.stderr create mode 100644 tests/run-pass/panic/panic4.rs create mode 100644 tests/run-pass/panic/panic4.stderr rename tests/{compile-fail => run-pass/panic}/transmute_fat2.rs (76%) create mode 100644 tests/run-pass/panic/transmute_fat2.stderr diff --git a/tests/compile-fail/div-by-zero-2.rs b/tests/compile-fail/div-by-zero-2.rs deleted file mode 100644 index 302d26a41f369..0000000000000 --- a/tests/compile-fail/div-by-zero-2.rs +++ /dev/null @@ -1,5 +0,0 @@ -#![allow(const_err)] - -fn main() { - let _n = 1 / 0; //~ ERROR attempt to divide by zero -} diff --git a/tests/compile-fail/overflowing-lsh-neg.rs b/tests/compile-fail/overflowing-lsh-neg.rs deleted file mode 100644 index 253294d1f53b7..0000000000000 --- a/tests/compile-fail/overflowing-lsh-neg.rs +++ /dev/null @@ -1,6 +0,0 @@ -#![allow(exceeding_bitshifts)] -#![allow(const_err)] - -fn main() { - let _n = 2i64 << -1; //~ ERROR attempt to shift left with overflow -} diff --git a/tests/compile-fail/overflowing-rsh-1.rs b/tests/compile-fail/overflowing-rsh-1.rs deleted file mode 100644 index e0d3f1904a23f..0000000000000 --- a/tests/compile-fail/overflowing-rsh-1.rs +++ /dev/null @@ -1,5 +0,0 @@ -#![allow(exceeding_bitshifts, const_err)] - -fn main() { - let _n = 1i64 >> 64; //~ ERROR attempt to shift right with overflow -} diff --git a/tests/compile-fail/panic_abort1.rs b/tests/compile-fail/panic/panic_abort1.rs similarity index 100% rename from tests/compile-fail/panic_abort1.rs rename to tests/compile-fail/panic/panic_abort1.rs diff --git a/tests/compile-fail/panic_abort2.rs b/tests/compile-fail/panic/panic_abort2.rs similarity index 100% rename from tests/compile-fail/panic_abort2.rs rename to tests/compile-fail/panic/panic_abort2.rs diff --git a/tests/compile-fail/panic_abort3.rs b/tests/compile-fail/panic/panic_abort3.rs similarity index 100% rename from tests/compile-fail/panic_abort3.rs rename to tests/compile-fail/panic/panic_abort3.rs diff --git a/tests/compile-fail/panic_abort4.rs b/tests/compile-fail/panic/panic_abort4.rs similarity index 100% rename from tests/compile-fail/panic_abort4.rs rename to tests/compile-fail/panic/panic_abort4.rs diff --git a/tests/run-pass/catch_panic.rs b/tests/run-pass/panic/catch_panic.rs similarity index 100% rename from tests/run-pass/catch_panic.rs rename to tests/run-pass/panic/catch_panic.rs diff --git a/tests/run-pass/catch_panic.stderr b/tests/run-pass/panic/catch_panic.stderr similarity index 100% rename from tests/run-pass/catch_panic.stderr rename to tests/run-pass/panic/catch_panic.stderr diff --git a/tests/run-pass/panic/div-by-zero-2.rs b/tests/run-pass/panic/div-by-zero-2.rs new file mode 100644 index 0000000000000..6cc319bf0bc4b --- /dev/null +++ b/tests/run-pass/panic/div-by-zero-2.rs @@ -0,0 +1,6 @@ +// ignore-windows: Unwind panicking does not currently work on Windows +#![allow(const_err)] + +fn main() { + let _n = 1 / 0; +} diff --git a/tests/run-pass/panic/div-by-zero-2.stderr b/tests/run-pass/panic/div-by-zero-2.stderr new file mode 100644 index 0000000000000..77dca2aac1e28 --- /dev/null +++ b/tests/run-pass/panic/div-by-zero-2.stderr @@ -0,0 +1 @@ +thread 'main' panicked at 'attempt to divide by zero', $DIR/div-by-zero-2.rs:5:14 diff --git a/tests/run-pass/panic/overflowing-lsh-neg.rs b/tests/run-pass/panic/overflowing-lsh-neg.rs new file mode 100644 index 0000000000000..b214243c88f86 --- /dev/null +++ b/tests/run-pass/panic/overflowing-lsh-neg.rs @@ -0,0 +1,7 @@ +// ignore-windows: Unwind panicking does not currently work on Windows +#![allow(exceeding_bitshifts)] +#![allow(const_err)] + +fn main() { + let _n = 2i64 << -1; +} diff --git a/tests/run-pass/panic/overflowing-lsh-neg.stderr b/tests/run-pass/panic/overflowing-lsh-neg.stderr new file mode 100644 index 0000000000000..fe5a35e6b381d --- /dev/null +++ b/tests/run-pass/panic/overflowing-lsh-neg.stderr @@ -0,0 +1 @@ +thread 'main' panicked at 'attempt to shift left with overflow', $DIR/overflowing-lsh-neg.rs:6:14 diff --git a/tests/run-pass/panic/overflowing-rsh-1.rs b/tests/run-pass/panic/overflowing-rsh-1.rs new file mode 100644 index 0000000000000..68ea51d167316 --- /dev/null +++ b/tests/run-pass/panic/overflowing-rsh-1.rs @@ -0,0 +1,6 @@ +// ignore-windows: Unwind panicking does not currently work on Windows +#![allow(exceeding_bitshifts, const_err)] + +fn main() { + let _n = 1i64 >> 64; +} diff --git a/tests/run-pass/panic/overflowing-rsh-1.stderr b/tests/run-pass/panic/overflowing-rsh-1.stderr new file mode 100644 index 0000000000000..20a45739ae2e6 --- /dev/null +++ b/tests/run-pass/panic/overflowing-rsh-1.stderr @@ -0,0 +1 @@ +thread 'main' panicked at 'attempt to shift right with overflow', $DIR/overflowing-rsh-1.rs:5:14 diff --git a/tests/compile-fail/overflowing-rsh-2.rs b/tests/run-pass/panic/overflowing-rsh-2.rs similarity index 54% rename from tests/compile-fail/overflowing-rsh-2.rs rename to tests/run-pass/panic/overflowing-rsh-2.rs index 3f7f31f4c2351..4e287f20adf8f 100644 --- a/tests/compile-fail/overflowing-rsh-2.rs +++ b/tests/run-pass/panic/overflowing-rsh-2.rs @@ -1,6 +1,7 @@ +// ignore-windows: Unwind panicking does not currently work on Windows #![allow(exceeding_bitshifts, const_err)] fn main() { // Make sure we catch overflows that would be hidden by first casting the RHS to u32 - let _n = 1i64 >> (u32::max_value() as i64 + 1); //~ ERROR attempt to shift right with overflow + let _n = 1i64 >> (u32::max_value() as i64 + 1); } diff --git a/tests/run-pass/panic/overflowing-rsh-2.stderr b/tests/run-pass/panic/overflowing-rsh-2.stderr new file mode 100644 index 0000000000000..3381116ae6c85 --- /dev/null +++ b/tests/run-pass/panic/overflowing-rsh-2.stderr @@ -0,0 +1 @@ +thread 'main' panicked at 'attempt to shift right with overflow', $DIR/overflowing-rsh-2.rs:6:14 diff --git a/tests/run-pass/panic/panic1.rs b/tests/run-pass/panic/panic1.rs new file mode 100644 index 0000000000000..61321c658166f --- /dev/null +++ b/tests/run-pass/panic/panic1.rs @@ -0,0 +1,4 @@ +// ignore-windows: Unwind panicking does not currently work on Windows +fn main() { + std::panic!("panicking from libstd"); +} diff --git a/tests/run-pass/panic/panic1.stderr b/tests/run-pass/panic/panic1.stderr new file mode 100644 index 0000000000000..305fc1a1a6e66 --- /dev/null +++ b/tests/run-pass/panic/panic1.stderr @@ -0,0 +1 @@ +thread 'main' panicked at 'panicking from libstd', $DIR/panic1.rs:3:5 diff --git a/tests/run-pass/panic/panic2.rs b/tests/run-pass/panic/panic2.rs new file mode 100644 index 0000000000000..d6ab864795eaf --- /dev/null +++ b/tests/run-pass/panic/panic2.rs @@ -0,0 +1,4 @@ +// ignore-windows: Unwind panicking does not currently work on Windows +fn main() { + std::panic!("{}-panicking from libstd", 42); +} diff --git a/tests/run-pass/panic/panic2.stderr b/tests/run-pass/panic/panic2.stderr new file mode 100644 index 0000000000000..cd40559c81ef1 --- /dev/null +++ b/tests/run-pass/panic/panic2.stderr @@ -0,0 +1 @@ +thread 'main' panicked at '42-panicking from libstd', $DIR/panic2.rs:3:5 diff --git a/tests/run-pass/panic/panic3.rs b/tests/run-pass/panic/panic3.rs new file mode 100644 index 0000000000000..10a42c7e6c00f --- /dev/null +++ b/tests/run-pass/panic/panic3.rs @@ -0,0 +1,4 @@ +// ignore-windows: Unwind panicking does not currently work on Windows +fn main() { + core::panic!("panicking from libcore"); +} diff --git a/tests/run-pass/panic/panic3.stderr b/tests/run-pass/panic/panic3.stderr new file mode 100644 index 0000000000000..e3aa902f0cbc9 --- /dev/null +++ b/tests/run-pass/panic/panic3.stderr @@ -0,0 +1 @@ +thread 'main' panicked at 'panicking from libcore', $DIR/panic3.rs:3:5 diff --git a/tests/run-pass/panic/panic4.rs b/tests/run-pass/panic/panic4.rs new file mode 100644 index 0000000000000..06e2dd008fff8 --- /dev/null +++ b/tests/run-pass/panic/panic4.rs @@ -0,0 +1,4 @@ +// ignore-windows: Unwind panicking does not currently work on Windows +fn main() { + core::panic!("{}-panicking from libcore", 42); +} diff --git a/tests/run-pass/panic/panic4.stderr b/tests/run-pass/panic/panic4.stderr new file mode 100644 index 0000000000000..1a242a868cae1 --- /dev/null +++ b/tests/run-pass/panic/panic4.stderr @@ -0,0 +1 @@ +thread 'main' panicked at '42-panicking from libcore', $DIR/panic4.rs:3:5 diff --git a/tests/compile-fail/transmute_fat2.rs b/tests/run-pass/panic/transmute_fat2.rs similarity index 76% rename from tests/compile-fail/transmute_fat2.rs rename to tests/run-pass/panic/transmute_fat2.rs index 3121a139d9204..40b3bd9d10519 100644 --- a/tests/compile-fail/transmute_fat2.rs +++ b/tests/run-pass/panic/transmute_fat2.rs @@ -7,5 +7,5 @@ fn main() { let bad = unsafe { std::mem::transmute::(42) }; - bad[0]; //~ ERROR index out of bounds: the len is 0 but the index is 0 + bad[0]; } diff --git a/tests/run-pass/panic/transmute_fat2.stderr b/tests/run-pass/panic/transmute_fat2.stderr new file mode 100644 index 0000000000000..62f37877230af --- /dev/null +++ b/tests/run-pass/panic/transmute_fat2.stderr @@ -0,0 +1 @@ +thread 'main' panicked at 'index out of bounds: the len is 0 but the index is 0', $DIR/transmute_fat2.rs:10:5 From 1b3434c67d27da6cf4c758b517fe132d5295bf02 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 29 Nov 2019 19:50:37 +0100 Subject: [PATCH 1373/3747] adjust for init_allocation_extra --- src/machine.rs | 21 +++++++++------------ src/stacked_borrows.rs | 14 +++++++++++--- 2 files changed, 20 insertions(+), 15 deletions(-) diff --git a/src/machine.rs b/src/machine.rs index 980c6115e91cd..b974c956c2e9c 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -291,27 +291,24 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { Ok(()) } - fn tag_allocation<'b>( + fn init_allocation_extra<'b>( memory_extra: &MemoryExtra, id: AllocId, alloc: Cow<'b, Allocation>, kind: Option>, - ) -> ( - Cow<'b, Allocation>, - Self::PointerTag, - ) { + ) -> Cow<'b, Allocation> { let kind = kind.expect("we set our STATIC_KIND so this cannot be None"); let alloc = alloc.into_owned(); - let (stacks, base_tag) = if !memory_extra.validate { - (None, Tag::Untagged) - } else { - let (stacks, base_tag) = Stacks::new_allocation( + let stacks = if memory_extra.validate { + Some(Stacks::new_allocation( id, alloc.size, Rc::clone(&memory_extra.stacked_borrows), kind, - ); - (Some(stacks), base_tag) + )) + } else { + // No stacks. + None }; let mut stacked_borrows = memory_extra.stacked_borrows.borrow_mut(); let alloc: Allocation = alloc.with_tags_and_extra( @@ -328,7 +325,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { stacked_borrows: stacks, }, ); - (Cow::Owned(alloc), base_tag) + Cow::Owned(alloc) } #[inline(always)] diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 3b821c7155a6f..dc06f12ffeb46 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -462,7 +462,7 @@ impl Stacks { size: Size, extra: MemoryExtra, kind: MemoryKind, - ) -> (Self, Tag) { + ) -> Self { let (tag, perm) = match kind { MemoryKind::Stack => // New unique borrow. This tag is not accessible by the program, @@ -472,12 +472,15 @@ impl Stacks { // and in particular, *all* raw pointers. (Tag::Tagged(extra.borrow_mut().new_ptr()), Permission::Unique), MemoryKind::Machine(MiriMemoryKind::Static) => + // Statics are inherently shared, so we do not derive any uniqueness assumptions + // from direct accesses to a static. Thus, the base permission is `SharedReadWrite`. (extra.borrow_mut().static_base_ptr(id), Permission::SharedReadWrite), _ => + // Everything else we handle entirely untagged for now. + // FIXME: experiment with more precise tracking. (Tag::Untagged, Permission::SharedReadWrite), }; - let stack = Stacks::new(size, perm, tag, extra); - (stack, tag) + Stacks::new(size, perm, tag, extra) } #[inline(always)] @@ -591,7 +594,12 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Compute new borrow. let new_tag = match kind { + // Give up tracking for raw pointers. + // FIXME: Experiment with more precise tracking. Blocked on `&raw` + // because `Rc::into_raw` currently creates intermediate references, + // breaking `Rc::from_raw`. RefKind::Raw { .. } => Tag::Untagged, + // All other pointesr are properly tracked. _ => Tag::Tagged(this.memory.extra.stacked_borrows.borrow_mut().new_ptr()), }; From f1cde6d80b9bef9808832b5b7ea322925c04fe5b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 30 Nov 2019 10:37:14 +0100 Subject: [PATCH 1374/3747] also test built-in panics via should_panic --- test-cargo-miri/test.stdout.ref | 5 +++-- test-cargo-miri/test.stdout.ref2 | 2 +- test-cargo-miri/test.stdout.ref3 | 2 +- test-cargo-miri/tests/test.rs | 11 ++++++++++- 4 files changed, 15 insertions(+), 5 deletions(-) diff --git a/test-cargo-miri/test.stdout.ref b/test-cargo-miri/test.stdout.ref index 827e2f93237bc..0ab948893b495 100644 --- a/test-cargo-miri/test.stdout.ref +++ b/test-cargo-miri/test.stdout.ref @@ -5,12 +5,13 @@ test test::rng ... ok test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out -running 5 tests +running 6 tests test do_panic ... ok test entropy_rng ... ok +test fail_index_check ... ok test num_cpus ... ok test simple1 ... ok test simple2 ... ok -test result: ok. 5 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out +test result: ok. 6 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out diff --git a/test-cargo-miri/test.stdout.ref2 b/test-cargo-miri/test.stdout.ref2 index e070941c36ec8..1dd4f70658d50 100644 --- a/test-cargo-miri/test.stdout.ref2 +++ b/test-cargo-miri/test.stdout.ref2 @@ -7,5 +7,5 @@ test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 1 filtered out running 1 test test simple1 ... ok -test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 4 filtered out +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 5 filtered out diff --git a/test-cargo-miri/test.stdout.ref3 b/test-cargo-miri/test.stdout.ref3 index a4a1a7812aea8..af94192a12ca5 100644 --- a/test-cargo-miri/test.stdout.ref3 +++ b/test-cargo-miri/test.stdout.ref3 @@ -7,5 +7,5 @@ test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 1 filtered out running 1 test test num_cpus ... ok -test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 4 filtered out +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 5 filtered out diff --git a/test-cargo-miri/tests/test.rs b/test-cargo-miri/tests/test.rs index ce85f929049bc..76d3eeece5eb9 100644 --- a/test-cargo-miri/tests/test.rs +++ b/test-cargo-miri/tests/test.rs @@ -43,7 +43,7 @@ fn num_cpus() { } -// FIXME: Remove this `cfg` once we fix https://github.com/rust-lang/miri/issues/1059 +// FIXME: Remove this `cfg` once we fix https://github.com/rust-lang/miri/issues/1059. // We cfg-gate the `should_panic` attribute and the `panic!` itself, so that the test // stdout does not depend on the platform. #[test] @@ -52,3 +52,12 @@ fn do_panic() { // In large, friendly letters :) #[cfg(not(windows))] panic!("Explicit panic from test!"); } + +// FIXME: see above +#[test] +#[allow(const_err)] +#[cfg_attr(not(windows), should_panic(expected="the len is 0 but the index is 42"))] +fn fail_index_check() { + #[cfg(not(windows))] + [][42] +} From e77258322c71091afe23ecb64461243174e7fd49 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 30 Nov 2019 11:48:34 +0100 Subject: [PATCH 1375/3747] some error classes should be impossible --- src/eval.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/eval.rs b/src/eval.rs index 33bcfcc7380e2..17c0d52b00b9b 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -217,6 +217,8 @@ pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) -> } err_unsup!(NoMirFor(..)) => format!("{}. Did you set `MIRI_SYSROOT` to a Miri-enabled sysroot? You can prepare one with `cargo miri setup`.", e), + InterpError::Panic(_) | InterpError::InvalidProgram(_) => + bug!("This error should be impossible in Miri: {}", e), _ => e.to_string() }; e.print_backtrace(); From d43e394c4691f6ae9173001a27943d74ef6c5f97 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 1 Dec 2019 10:18:41 +0100 Subject: [PATCH 1376/3747] fix init_allocation_extra --- src/eval.rs | 6 +++--- src/machine.rs | 19 ++++++++++--------- src/shims/panic.rs | 2 +- src/stacked_borrows.rs | 10 ++++++---- 4 files changed, 20 insertions(+), 17 deletions(-) diff --git a/src/eval.rs b/src/eval.rs index 17c0d52b00b9b..2796dbd0b9b13 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -93,7 +93,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( arg.push(0); argvs.push( ecx.memory - .allocate_static_bytes(arg.as_slice(), MiriMemoryKind::Static.into()), + .allocate_static_bytes(arg.as_slice(), MiriMemoryKind::Env.into()), ); } // Make an array with all these pointers, in the Miri memory. @@ -144,7 +144,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( // Return place (in static memory so that it does not count as leak). let ret_place = ecx.allocate( ecx.layout_of(tcx.types.isize)?, - MiriMemoryKind::Static.into(), + MiriMemoryKind::Env.into(), ); // Call start function. ecx.call_function( @@ -156,7 +156,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( // Set the last_error to 0 let errno_layout = ecx.layout_of(tcx.types.u32)?; - let errno_place = ecx.allocate(errno_layout, MiriMemoryKind::Static.into()); + let errno_place = ecx.allocate(errno_layout, MiriMemoryKind::Env.into()); ecx.write_scalar(Scalar::from_u32(0), errno_place.into())?; ecx.machine.last_error = Some(errno_place); diff --git a/src/machine.rs b/src/machine.rs index b974c956c2e9c..edabc3bccbcc4 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -43,9 +43,9 @@ pub enum MiriMemoryKind { C, /// Windows `HeapAlloc` memory. WinHeap, - /// Part of env var emulation. + /// Memory for env vars and args, errno and other parts of the machine-managed environment. Env, - /// Statics. + /// Rust statics. Static, } @@ -296,19 +296,20 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { id: AllocId, alloc: Cow<'b, Allocation>, kind: Option>, - ) -> Cow<'b, Allocation> { + ) -> (Cow<'b, Allocation>, Self::PointerTag) { let kind = kind.expect("we set our STATIC_KIND so this cannot be None"); let alloc = alloc.into_owned(); - let stacks = if memory_extra.validate { - Some(Stacks::new_allocation( + let (stacks, base_tag) = if memory_extra.validate { + let (stacks, base_tag) = Stacks::new_allocation( id, alloc.size, Rc::clone(&memory_extra.stacked_borrows), kind, - )) + ); + (Some(stacks), base_tag) } else { - // No stacks. - None + // No stacks, no tag. + (None, Tag::Untagged) }; let mut stacked_borrows = memory_extra.stacked_borrows.borrow_mut(); let alloc: Allocation = alloc.with_tags_and_extra( @@ -325,7 +326,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { stacked_borrows: stacks, }, ); - Cow::Owned(alloc) + (Cow::Owned(alloc), base_tag) } #[inline(always)] diff --git a/src/shims/panic.rs b/src/shims/panic.rs index 3e82519f86b14..fc3339352a982 100644 --- a/src/shims/panic.rs +++ b/src/shims/panic.rs @@ -187,7 +187,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // First arg: Message. let msg = msg.description(); - let msg = this.allocate_str(msg, MiriMemoryKind::Static.into()); + let msg = this.allocate_str(msg, MiriMemoryKind::Env.into()); // Second arg: Caller location. let location = this.alloc_caller_location_for_span(span); diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index dc06f12ffeb46..23a32fc2ac5ca 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -462,7 +462,7 @@ impl Stacks { size: Size, extra: MemoryExtra, kind: MemoryKind, - ) -> Self { + ) -> (Self, Tag) { let (tag, perm) = match kind { MemoryKind::Stack => // New unique borrow. This tag is not accessible by the program, @@ -472,15 +472,17 @@ impl Stacks { // and in particular, *all* raw pointers. (Tag::Tagged(extra.borrow_mut().new_ptr()), Permission::Unique), MemoryKind::Machine(MiriMemoryKind::Static) => - // Statics are inherently shared, so we do not derive any uniqueness assumptions - // from direct accesses to a static. Thus, the base permission is `SharedReadWrite`. + // Static memory can be referenced by "global" pointers from `tcx`. + // Thus we call `static_base_ptr` such that the global pointers get the same tag + // as what we use here. + // The base pointer is not unique, so the base permission is `SharedReadWrite`. (extra.borrow_mut().static_base_ptr(id), Permission::SharedReadWrite), _ => // Everything else we handle entirely untagged for now. // FIXME: experiment with more precise tracking. (Tag::Untagged, Permission::SharedReadWrite), }; - Stacks::new(size, perm, tag, extra) + (Stacks::new(size, perm, tag, extra), tag) } #[inline(always)] From 8e3c3eccc46a839e81ad2806d9507ab555260556 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 1 Dec 2019 10:19:01 +0100 Subject: [PATCH 1377/3747] panic errors are actually still possible --- src/eval.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/eval.rs b/src/eval.rs index 2796dbd0b9b13..197cf87ba549b 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -217,7 +217,7 @@ pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) -> } err_unsup!(NoMirFor(..)) => format!("{}. Did you set `MIRI_SYSROOT` to a Miri-enabled sysroot? You can prepare one with `cargo miri setup`.", e), - InterpError::Panic(_) | InterpError::InvalidProgram(_) => + InterpError::InvalidProgram(_) => bug!("This error should be impossible in Miri: {}", e), _ => e.to_string() }; From 2ef5ac17cc1a6a3d2263d3a3382eba37e5252325 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 2 Dec 2019 16:04:51 +0100 Subject: [PATCH 1378/3747] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index b2b29eb527950..ebf6e5a2aca81 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -4af3ee8ee2a2bc1286b021db7600ba990359cf3f +2da942f32802c8233a09744024dfbc34431adf65 From ce7b44b048820edc6b29873a708ec12c760db64b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 2 Dec 2019 16:48:18 +0100 Subject: [PATCH 1379/3747] ignore another panicking test on Windows --- tests/run-pass/panic/transmute_fat2.rs | 1 + tests/run-pass/panic/transmute_fat2.stderr | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/run-pass/panic/transmute_fat2.rs b/tests/run-pass/panic/transmute_fat2.rs index 40b3bd9d10519..8cbe9a099bb6c 100644 --- a/tests/run-pass/panic/transmute_fat2.rs +++ b/tests/run-pass/panic/transmute_fat2.rs @@ -1,3 +1,4 @@ +// ignore-windows: Unwind panicking does not currently work on Windows fn main() { #[cfg(target_pointer_width="64")] let bad = unsafe { diff --git a/tests/run-pass/panic/transmute_fat2.stderr b/tests/run-pass/panic/transmute_fat2.stderr index 62f37877230af..08849a5b517a4 100644 --- a/tests/run-pass/panic/transmute_fat2.stderr +++ b/tests/run-pass/panic/transmute_fat2.stderr @@ -1 +1 @@ -thread 'main' panicked at 'index out of bounds: the len is 0 but the index is 0', $DIR/transmute_fat2.rs:10:5 +thread 'main' panicked at 'index out of bounds: the len is 0 but the index is 0', $DIR/transmute_fat2.rs:11:5 From a418fe9826b4b2aa0a2f9d6c26d82673262a757a Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Mon, 2 Dec 2019 20:20:11 -0500 Subject: [PATCH 1380/3747] Rustup for `BodyCache` changes --- rust-version | 2 +- src/helpers.rs | 2 +- src/shims/foreign_items.rs | 4 ++-- src/shims/mod.rs | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/rust-version b/rust-version index ebf6e5a2aca81..08289d4459e73 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -2da942f32802c8233a09744024dfbc34431adf65 +fdc0011561c6365c596dfd8fa1ef388162bc89c7 diff --git a/src/helpers.rs b/src/helpers.rs index 7bd29e1741946..e7da88f2bbfea 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -131,7 +131,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); // Push frame. - let mir = this.load_mir(f.def, None)?; + let mir = this.load_mir(f.def, None)?.body(); let span = this.stack().last() .and_then(Frame::current_source_info) .map(|si| si.span) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index f27b4fb333527..52e04aea3045c 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -141,14 +141,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx .expect("No panic runtime found!"); let panic_runtime = tcx.crate_name(*panic_runtime); let start_panic_instance = this.resolve_path(&[&*panic_runtime.as_str(), "__rust_start_panic"])?; - return Ok(Some(this.load_mir(start_panic_instance.def, None)?)); + return Ok(Some(this.load_mir(start_panic_instance.def, None)?.body())); } // Similarly, we forward calls to the `panic_impl` foreign item to its implementation. // The implementation is provided by the function with the `#[panic_handler]` attribute. "panic_impl" => { let panic_impl_id = this.tcx.lang_items().panic_impl().unwrap(); let panic_impl_instance = ty::Instance::mono(*this.tcx, panic_impl_id); - return Ok(Some(this.load_mir(panic_impl_instance.def, None)?)); + return Ok(Some(this.load_mir(panic_impl_instance.def, None)?.body())); } "exit" | "ExitProcess" => { diff --git a/src/shims/mod.rs b/src/shims/mod.rs index 2e8aea3f86e05..d7842dbcba25b 100644 --- a/src/shims/mod.rs +++ b/src/shims/mod.rs @@ -49,7 +49,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // Otherwise, load the MIR. - Ok(Some(this.load_mir(instance.def, None)?)) + Ok(Some(this.load_mir(instance.def, None)?.body())) } fn align_offset( From ebe5a51336a2b948d100863c8bd8d813a86cce0b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 3 Dec 2019 08:21:52 +0100 Subject: [PATCH 1381/3747] bump Rust to HEAD --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 08289d4459e73..e81e0579a386c 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -fdc0011561c6365c596dfd8fa1ef388162bc89c7 +4787e97475de6be9487e3d9255a9c2d3c0bf9252 From 6d8e87111ba4430ee7679232b7578257ffa015a1 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 3 Dec 2019 17:37:42 +0100 Subject: [PATCH 1382/3747] bump Rust for exact_div fix --- rust-version | 2 +- tests/compile-fail/exact_div3.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/rust-version b/rust-version index e81e0579a386c..e1047d816e228 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -4787e97475de6be9487e3d9255a9c2d3c0bf9252 +f577b0ef6e637ab7a6095cdfe0b51fa3faf97050 diff --git a/tests/compile-fail/exact_div3.rs b/tests/compile-fail/exact_div3.rs index 0460e412e45e2..0d5097a87a208 100644 --- a/tests/compile-fail/exact_div3.rs +++ b/tests/compile-fail/exact_div3.rs @@ -1,5 +1,5 @@ #![feature(core_intrinsics)] fn main() { // signed divison with a remainder - unsafe { std::intrinsics::exact_div(-19i8, 2); } //~ ERROR 237 cannot be divided by 2 without remainder + unsafe { std::intrinsics::exact_div(-19i8, 2); } //~ ERROR -19 cannot be divided by 2 without remainder } From ab000997dbc597416c151e7879bb113c56146228 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 2 Dec 2019 11:02:11 +0100 Subject: [PATCH 1383/3747] use throw_machine_stop macro --- src/shims/foreign_items.rs | 3 +-- src/shims/intrinsics.rs | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 52e04aea3045c..316cc686ad77d 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -154,8 +154,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "exit" | "ExitProcess" => { // it's really u32 for ExitProcess, but we have to put it into the `Exit` variant anyway let code = this.read_scalar(args[0])?.to_i32()?; - let ti = Box::new(TerminationInfo::Exit(code.into())); - return Err(InterpError::MachineStop(ti).into()); + throw_machine_stop!(TerminationInfo::Exit(code.into())); } _ => { if let Some(p) = ret { diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 0cb51d593199e..57b77a8b74902 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -34,8 +34,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Handle diverging intrinsics. let (dest, ret) = match intrinsic_name { "abort" => { - let ti = Box::new(TerminationInfo::Abort); - return Err(InterpError::MachineStop(ti).into()); + throw_machine_stop!(TerminationInfo::Abort); } "miri_start_panic" => return this.handle_miri_start_panic(args, unwind), _ => { From 07af5c9ffc458f34eb31fc338a3785a1c81fa04c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 3 Dec 2019 23:38:41 +0100 Subject: [PATCH 1384/3747] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index e1047d816e228..644ec5ed80721 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -f577b0ef6e637ab7a6095cdfe0b51fa3faf97050 +7afe6d9d1f48b998cc88fe6f01ba0082788ba4b9 From 808ac8f4b949d6ad4f4efc6e591e94f1321c03a3 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 4 Dec 2019 09:55:36 +0100 Subject: [PATCH 1385/3747] use write_os_str_to_c_string for unix arg passing --- src/eval.rs | 42 ++++++++++++++++++++++-------------------- 1 file changed, 22 insertions(+), 20 deletions(-) diff --git a/src/eval.rs b/src/eval.rs index 197cf87ba549b..6f7f0ba329cec 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -1,5 +1,7 @@ //! Main evaluator loop and setting up the initial stack frame. +use std::ffi::OsStr; + use rand::rngs::StdRng; use rand::SeedableRng; @@ -75,26 +77,15 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( let argc = Scalar::from_uint(config.args.len() as u128, ecx.pointer_size()); // Third argument (`argv`): created from `config.args`. let argv = { - // For Windows, construct a command string with all the aguments (before we take apart `config.args`). - let mut cmd = String::new(); + // Put each argument in memory, collect pointers. + let mut argvs = Vec::>::new(); for arg in config.args.iter() { - if !cmd.is_empty() { - cmd.push(' '); - } - cmd.push_str(&*shell_escape::windows::escape(arg.as_str().into())); - } - // Don't forget `0` terminator. - cmd.push(std::char::from_u32(0).unwrap()); - // Collect the pointers to the individual strings. - let mut argvs = Vec::>::new(); - for arg in config.args { - // Add `0` terminator. - let mut arg = arg.into_bytes(); - arg.push(0); - argvs.push( - ecx.memory - .allocate_static_bytes(arg.as_slice(), MiriMemoryKind::Env.into()), - ); + // Make space for `0` terminator. + let size = arg.len() as u64 + 1; + let arg_type = tcx.mk_array(tcx.types.u8, size); + let arg_place = ecx.allocate(ecx.layout_of(arg_type)?, MiriMemoryKind::Env.into()); + ecx.write_os_str_to_c_string(OsStr::new(arg), arg_place.ptr, size)?; + argvs.push(arg_place.ptr); } // Make an array with all these pointers, in the Miri memory. let argvs_layout = ecx.layout_of( @@ -107,7 +98,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( } ecx.memory .mark_immutable(argvs_place.ptr.assert_ptr().alloc_id)?; - // A pointer to that place is the argument. + // A pointer to that place is the 3rd argument for main. let argv = argvs_place.ptr; // Store `argc` and `argv` for macOS `_NSGetArg{c,v}`. { @@ -127,6 +118,17 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( } // Store command line as UTF-16 for Windows `GetCommandLineW`. { + // Construct a command string with all the aguments. + let mut cmd = String::new(); + for arg in config.args.iter() { + if !cmd.is_empty() { + cmd.push(' '); + } + cmd.push_str(&*shell_escape::windows::escape(arg.as_str().into())); + } + // Don't forget `0` terminator. + cmd.push(std::char::from_u32(0).unwrap()); + let cmd_utf16: Vec = cmd.encode_utf16().collect(); let cmd_type = tcx.mk_array(tcx.types.u16, cmd_utf16.len() as u64); let cmd_place = ecx.allocate(ecx.layout_of(cmd_type)?, MiriMemoryKind::Env.into()); From 01f060b6da675d800d9874e5256f4a069e58d442 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 4 Dec 2019 10:16:08 +0100 Subject: [PATCH 1386/3747] avoid allocation in read_os_string_from_c_string --- src/helpers.rs | 13 ++++++++----- src/machine.rs | 4 ++-- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index e7da88f2bbfea..9f75c9b7fbe10 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -1,5 +1,5 @@ use std::{mem, iter}; -use std::ffi::{OsStr, OsString}; +use std::ffi::OsStr; use syntax::source_map::DUMMY_SP; use rustc::hir::def_id::{DefId, CRATE_DEF_INDEX}; @@ -453,9 +453,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// Helper function to read an OsString from a null-terminated sequence of bytes, which is what /// the Unix APIs usually handle. - fn read_os_string_from_c_string(&mut self, scalar: Scalar) -> InterpResult<'tcx, OsString> { - let bytes = self.eval_context_mut().memory.read_c_str(scalar)?; - Ok(bytes_to_os_str(bytes)?.into()) + fn read_os_string_from_c_string<'a>(&'a self, scalar: Scalar) -> InterpResult<'tcx, &'a OsStr> + where 'tcx: 'a, 'mir: 'a + { + let this = self.eval_context_ref(); + let bytes = this.memory.read_c_str(scalar)?; + bytes_to_os_str(bytes) } /// Helper function to write an OsStr as a null-terminated sequence of bytes, which is what @@ -501,7 +504,7 @@ fn os_str_to_bytes<'tcx, 'a>(os_str: &'a OsStr) -> InterpResult<'tcx, &'a [u8]> } #[cfg(not(target_os = "unix"))] -fn bytes_to_os_str<'tcx, 'a>(bytes: &'a[u8]) -> InterpResult<'tcx, &'a OsStr> { +fn bytes_to_os_str<'tcx, 'a>(bytes: &'a [u8]) -> InterpResult<'tcx, &'a OsStr> { let s = std::str::from_utf8(bytes) .map_err(|_| err_unsup_format!("{:?} is not a valid utf-8 string", bytes))?; Ok(&OsStr::new(s)) diff --git a/src/machine.rs b/src/machine.rs index edabc3bccbcc4..55ac7f780fae7 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -140,8 +140,8 @@ pub type MiriEvalContext<'mir, 'tcx> = InterpCx<'mir, 'tcx, Evaluator<'tcx>>; /// A little trait that's useful to be inherited by extension traits. pub trait MiriEvalContextExt<'mir, 'tcx> { - fn eval_context_ref(&self) -> &MiriEvalContext<'mir, 'tcx>; - fn eval_context_mut(&mut self) -> &mut MiriEvalContext<'mir, 'tcx>; + fn eval_context_ref<'a>(&'a self) -> &'a MiriEvalContext<'mir, 'tcx>; + fn eval_context_mut<'a>(&'a mut self) -> &'a mut MiriEvalContext<'mir, 'tcx>; } impl<'mir, 'tcx> MiriEvalContextExt<'mir, 'tcx> for MiriEvalContext<'mir, 'tcx> { #[inline(always)] From 94732aaf7bf79fd01a4a48d11155c6586b937514 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 4 Dec 2019 10:43:36 +0100 Subject: [PATCH 1387/3747] rename helper methods a bit --- src/eval.rs | 2 +- src/helpers.rs | 4 ++-- src/shims/env.rs | 4 ++-- src/shims/fs.rs | 4 ++-- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/eval.rs b/src/eval.rs index 6f7f0ba329cec..897d395674947 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -84,7 +84,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( let size = arg.len() as u64 + 1; let arg_type = tcx.mk_array(tcx.types.u8, size); let arg_place = ecx.allocate(ecx.layout_of(arg_type)?, MiriMemoryKind::Env.into()); - ecx.write_os_str_to_c_string(OsStr::new(arg), arg_place.ptr, size)?; + ecx.write_os_str_to_c_str(OsStr::new(arg), arg_place.ptr, size)?; argvs.push(arg_place.ptr); } // Make an array with all these pointers, in the Miri memory. diff --git a/src/helpers.rs b/src/helpers.rs index 9f75c9b7fbe10..05a92164f27d8 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -453,7 +453,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// Helper function to read an OsString from a null-terminated sequence of bytes, which is what /// the Unix APIs usually handle. - fn read_os_string_from_c_string<'a>(&'a self, scalar: Scalar) -> InterpResult<'tcx, &'a OsStr> + fn read_os_str_from_c_str<'a>(&'a self, scalar: Scalar) -> InterpResult<'tcx, &'a OsStr> where 'tcx: 'a, 'mir: 'a { let this = self.eval_context_ref(); @@ -465,7 +465,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// the Unix APIs usually handle. This function returns `Ok(false)` without trying to write if /// `size` is not large enough to fit the contents of `os_string` plus a null terminator. It /// returns `Ok(true)` if the writing process was successful. - fn write_os_str_to_c_string( + fn write_os_str_to_c_str( &mut self, os_str: &OsStr, scalar: Scalar, diff --git a/src/shims/env.rs b/src/shims/env.rs index ae8dae0313f1b..8c431fd2016d5 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -128,7 +128,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // If we cannot get the current directory, we return null match env::current_dir() { Ok(cwd) => { - if this.write_os_str_to_c_string(&OsString::from(cwd), buf, size)? { + if this.write_os_str_to_c_str(&OsString::from(cwd), buf, size)? { return Ok(buf); } let erange = this.eval_libc("ERANGE")?; @@ -144,7 +144,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.check_no_isolation("chdir")?; - let path = this.read_os_string_from_c_string(this.read_scalar(path_op)?.not_undef()?)?; + let path = this.read_os_str_from_c_str(this.read_scalar(path_op)?.not_undef()?)?; match env::set_current_dir(path) { Ok(()) => Ok(0), diff --git a/src/shims/fs.rs b/src/shims/fs.rs index 9291f3a6e3b20..4d10be6264600 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -96,7 +96,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx throw_unsup_format!("unsupported flags {:#x}", flag & !mirror); } - let path = this.read_os_string_from_c_string(this.read_scalar(path_op)?.not_undef()?)?; + let path = this.read_os_str_from_c_str(this.read_scalar(path_op)?.not_undef()?)?; let fd = options.open(path).map(|file| { let mut fh = &mut this.machine.file_handler; @@ -250,7 +250,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.check_no_isolation("unlink")?; - let path = this.read_os_string_from_c_string(this.read_scalar(path_op)?.not_undef()?)?; + let path = this.read_os_str_from_c_str(this.read_scalar(path_op)?.not_undef()?)?; let result = remove_file(path).map(|_| 0); From edac086f1c9b324f97a9e0aab4c2f46b317d64e1 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 4 Dec 2019 23:31:39 +0100 Subject: [PATCH 1388/3747] rustup for find_fn rename --- rust-version | 2 +- src/machine.rs | 4 ++-- src/shims/mod.rs | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/rust-version b/rust-version index 644ec5ed80721..83d06b2f7d2ec 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -7afe6d9d1f48b998cc88fe6f01ba0082788ba4b9 +6d77e45f01079fe3d40180b3e256e414ab379f63 diff --git a/src/machine.rs b/src/machine.rs index 55ac7f780fae7..65b6bcfb2ab7f 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -182,14 +182,14 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { } #[inline(always)] - fn find_fn( + fn find_mir_or_eval_fn( ecx: &mut InterpCx<'mir, 'tcx, Self>, instance: ty::Instance<'tcx>, args: &[OpTy<'tcx, Tag>], ret: Option<(PlaceTy<'tcx, Tag>, mir::BasicBlock)>, unwind: Option, ) -> InterpResult<'tcx, Option<&'mir mir::Body<'tcx>>> { - ecx.find_fn(instance, args, ret, unwind) + ecx.find_mir_or_eval_fn(instance, args, ret, unwind) } #[inline(always)] diff --git a/src/shims/mod.rs b/src/shims/mod.rs index d7842dbcba25b..21e69dc1f0fc2 100644 --- a/src/shims/mod.rs +++ b/src/shims/mod.rs @@ -12,7 +12,7 @@ use crate::*; impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { - fn find_fn( + fn find_mir_or_eval_fn( &mut self, instance: ty::Instance<'tcx>, args: &[OpTy<'tcx, Tag>], From 87fb5db526e8602c1a34d6cb42b3a31daa83888c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 6 Dec 2019 08:25:50 +0100 Subject: [PATCH 1389/3747] avoid recompiling Miri on install --- Cargo.lock | 1 + Cargo.toml | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index 0ccbaaaabec21..9550b2bfdfe3e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -339,6 +339,7 @@ dependencies = [ "rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-workspace-hack 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.103 (registry+https://github.com/rust-lang/crates.io-index)", "shell-escape 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "vergen 3.0.4 (registry+https://github.com/rust-lang/crates.io-index)", ] diff --git a/Cargo.toml b/Cargo.toml index ac62d29eb8fcb..da9481cce5260 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -46,9 +46,10 @@ rand = "0.7" # for more information. rustc-workspace-hack = "1.0.0" -# Depend on num-traits with default features to avoid having to rebuild +# Some extra dependency for better feature control to avoid having to rebuild # between "cargo build" and "cargo intall". num-traits = "*" +serde = { version = "*", features = ["derive"] } [build-dependencies] vergen = "3" From f02643001f84f72962c01a924dd72fe5f2b00cfd Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 6 Dec 2019 09:28:46 +0100 Subject: [PATCH 1390/3747] README: Miri now supports panics and FS access --- README.md | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 5a85b6d478557..7fd94a2811a94 100644 --- a/README.md +++ b/README.md @@ -39,10 +39,9 @@ program, and cannot run all programs: addresses or other non-deterministic data, try running Miri with different values for `-Zmiri-seed` to test different executions. * Miri runs the program as a platform-independent interpreter, so the program - has no access to any platform-specific APIs or FFI. A few APIs have been + has no access to most platform-specific APIs or FFI. A few APIs have been implemented (such as printing to stdout) but most have not: for example, Miri - currently does not support concurrency, or SIMD, or networking, or file system - access. + currently does not support concurrency, or SIMD, or networking. [rust]: https://www.rust-lang.org/ [mir]: https://github.com/rust-lang/rfcs/blob/master/text/1211-mir.md @@ -78,9 +77,7 @@ dependencies. It will ask you for confirmation before installing anything. You can pass arguments to Miri after the first `--`, and pass arguments to the interpreted program or test suite after the second `--`. For example, `cargo miri run -- -Zmiri-disable-validation` runs the program without validation of -basic type invariants and references. `cargo miri test -- -- -Zunstable-options ---exclude-should-panic` skips `#[should_panic]` tests, which is a good idea -because Miri does not support unwinding or catching panics. +basic type invariants and references. When running code via `cargo miri`, the `miri` config flag is set. You can use this to exclude test cases that will fail under Miri because they do things @@ -90,8 +87,9 @@ Miri does not support: #[cfg(not(miri))] #[test] fn does_not_work_on_miri() { - let x = 0u8; - assert!(&x as *const _ as usize % 4 < 4); + std::thread::spawn(|| println!("Hello Thread!")) + .join() + .unwrap(); } ``` @@ -111,7 +109,7 @@ rustup default "$MIRI_NIGHTLY" rustup component add miri cargo miri setup -cargo miri test -- -- -Zunstable-options --exclude-should-panic +cargo miri test ``` We use `cargo miri setup` to avoid getting interactive questions about the extra From e0619b717ce2957dda6040b6996ceebb9539f30b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 6 Dec 2019 09:30:44 +0100 Subject: [PATCH 1391/3747] wording --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 7fd94a2811a94..92423c73c9ca5 100644 --- a/README.md +++ b/README.md @@ -77,7 +77,7 @@ dependencies. It will ask you for confirmation before installing anything. You can pass arguments to Miri after the first `--`, and pass arguments to the interpreted program or test suite after the second `--`. For example, `cargo miri run -- -Zmiri-disable-validation` runs the program without validation of -basic type invariants and references. +basic type invariants and without checking the aliasing of references. When running code via `cargo miri`, the `miri` config flag is set. You can use this to exclude test cases that will fail under Miri because they do things @@ -152,10 +152,10 @@ Several `-Z` flags are relevant for Miri: **NOTE**: This entropy is not good enough for cryptographic use! Do not generate secret keys in Miri or perform other kinds of cryptographic operations that rely on proper random numbers. -* `-Zmiri-disable-validation` disables enforcing the validity invariant, which - is enforced by default. This is mostly useful for debugging; it means Miri - will miss bugs in your program. However, this can also help to make Miri run - faster. +* `-Zmiri-disable-validation` disables enforcing validity invariants and + reference aliasing rules, which are enforced by default. This is mostly + useful for debugging. It means Miri will miss bugs in your program. However, + this can also help to make Miri run faster. * `-Zmiri-disable-isolation` disables host host isolation. As a consequence, the program has access to host resources such as environment variables and randomness (and, eventually, file systems and more). From 1a8755384e20e5b90e591f665f7b4849941ed58e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 7 Dec 2019 11:43:24 +0100 Subject: [PATCH 1392/3747] better way to ignore tests in Miri --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 92423c73c9ca5..3156b4fa24185 100644 --- a/README.md +++ b/README.md @@ -79,13 +79,13 @@ interpreted program or test suite after the second `--`. For example, `cargo miri run -- -Zmiri-disable-validation` runs the program without validation of basic type invariants and without checking the aliasing of references. -When running code via `cargo miri`, the `miri` config flag is set. You can -use this to exclude test cases that will fail under Miri because they do things +When compiling code via `cargo miri`, the `miri` config flag is set. You can +use this to ignore test cases that will fail under Miri because they do things Miri does not support: ```rust -#[cfg(not(miri))] #[test] +#[cfg_attr(miri, ignore)] fn does_not_work_on_miri() { std::thread::spawn(|| println!("Hello Thread!")) .join() From b883c11caa4aa3dabd245b9a91168af1d44d236e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 7 Dec 2019 11:55:19 +0100 Subject: [PATCH 1393/3747] use recommended test exclusion technique in test --- test-cargo-miri/test.stdout.ref | 5 +++-- test-cargo-miri/test.stdout.ref2 | 2 +- test-cargo-miri/test.stdout.ref3 | 2 +- test-cargo-miri/tests/test.rs | 2 +- 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/test-cargo-miri/test.stdout.ref b/test-cargo-miri/test.stdout.ref index 0ab948893b495..4260f5b3cb785 100644 --- a/test-cargo-miri/test.stdout.ref +++ b/test-cargo-miri/test.stdout.ref @@ -5,13 +5,14 @@ test test::rng ... ok test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out -running 6 tests +running 7 tests test do_panic ... ok +test does_not_work_on_miri ... ignored test entropy_rng ... ok test fail_index_check ... ok test num_cpus ... ok test simple1 ... ok test simple2 ... ok -test result: ok. 6 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out +test result: ok. 6 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out diff --git a/test-cargo-miri/test.stdout.ref2 b/test-cargo-miri/test.stdout.ref2 index 1dd4f70658d50..37efb8c3ee896 100644 --- a/test-cargo-miri/test.stdout.ref2 +++ b/test-cargo-miri/test.stdout.ref2 @@ -7,5 +7,5 @@ test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 1 filtered out running 1 test test simple1 ... ok -test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 5 filtered out +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 6 filtered out diff --git a/test-cargo-miri/test.stdout.ref3 b/test-cargo-miri/test.stdout.ref3 index af94192a12ca5..c5c39de109d2a 100644 --- a/test-cargo-miri/test.stdout.ref3 +++ b/test-cargo-miri/test.stdout.ref3 @@ -7,5 +7,5 @@ test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 1 filtered out running 1 test test num_cpus ... ok -test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 5 filtered out +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 6 filtered out diff --git a/test-cargo-miri/tests/test.rs b/test-cargo-miri/tests/test.rs index 76d3eeece5eb9..4c196ef5e0f57 100644 --- a/test-cargo-miri/tests/test.rs +++ b/test-cargo-miri/tests/test.rs @@ -13,8 +13,8 @@ fn simple2() { } // A test that won't work on miri (tests disabling tests). -#[cfg(not(miri))] #[test] +#[cfg_attr(miri, ignore)] fn does_not_work_on_miri() { let x = 0u8; assert!(&x as *const _ as usize % 4 < 4); From e92d16d9cd32fdaaf218c09e198b93c1f7c7914d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 7 Dec 2019 13:44:48 +0100 Subject: [PATCH 1394/3747] add flag to ignore memory leaks --- README.md | 1 + src/bin/miri.rs | 5 +++++ src/eval.rs | 11 +++++++---- tests/run-pass/memleak_ignored.rs | 5 +++++ 4 files changed, 18 insertions(+), 4 deletions(-) create mode 100644 tests/run-pass/memleak_ignored.rs diff --git a/README.md b/README.md index 92423c73c9ca5..01d0935be21aa 100644 --- a/README.md +++ b/README.md @@ -159,6 +159,7 @@ Several `-Z` flags are relevant for Miri: * `-Zmiri-disable-isolation` disables host host isolation. As a consequence, the program has access to host resources such as environment variables and randomness (and, eventually, file systems and more). +* `-Zmiri-ignore-leaks` disables the memory leak checker. * `-Zmiri-env-exclude=` keeps the `var` environment variable isolated from the host. Can be used multiple times to exclude several variables. The `TERM` environment variable is excluded by default. diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 59cb19476ac5c..e255afc3463d4 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -124,6 +124,7 @@ fn main() { // Parse our arguments and split them across `rustc` and `miri`. let mut validate = true; let mut communicate = false; + let mut ignore_leaks = false; let mut seed: Option = None; let mut rustc_args = vec![]; let mut miri_args = vec![]; @@ -145,6 +146,9 @@ fn main() { "-Zmiri-disable-isolation" => { communicate = true; }, + "-Zmiri-ignore-leaks" => { + ignore_leaks = true; + }, "--" => { after_dashdash = true; } @@ -200,6 +204,7 @@ fn main() { let miri_config = miri::MiriConfig { validate, communicate, + ignore_leaks, excluded_env_vars, seed, args: miri_args, diff --git a/src/eval.rs b/src/eval.rs index 897d395674947..8be42226b5ecf 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -18,6 +18,8 @@ pub struct MiriConfig { pub validate: bool, /// Determines if communication with the host environment is enabled. pub communicate: bool, + /// Determines if memory leaks should be ignored. + pub ignore_leaks: bool, /// Environment variables that should always be isolated from the host. pub excluded_env_vars: Vec, /// Command-line arguments passed to the interpreted program. @@ -169,6 +171,11 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( /// Returns `Some(return_code)` if program executed completed. /// Returns `None` if an evaluation error occured. pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) -> Option { + // FIXME: We always ignore leaks on some platforms where we do not + // correctly implement TLS destructors. + let target_os = tcx.sess.target.target.target_os.to_lowercase(); + let ignore_leaks = config.ignore_leaks || target_os == "windows" || target_os == "macos"; + let (mut ecx, ret_place) = match create_ecx(tcx, main_id, config) { Ok(v) => v, Err(mut err) => { @@ -190,10 +197,6 @@ pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) -> // Process the result. match res { Ok(return_code) => { - // Disable the leak test on some platforms where we do not - // correctly implement TLS destructors. - let target_os = ecx.tcx.tcx.sess.target.target.target_os.to_lowercase(); - let ignore_leaks = target_os == "windows" || target_os == "macos"; if !ignore_leaks { let leaks = ecx.memory.leak_report(); if leaks != 0 { diff --git a/tests/run-pass/memleak_ignored.rs b/tests/run-pass/memleak_ignored.rs new file mode 100644 index 0000000000000..fddf14121ef35 --- /dev/null +++ b/tests/run-pass/memleak_ignored.rs @@ -0,0 +1,5 @@ +// compile-flags: -Zmiri-ignore-leaks + +fn main() { + std::mem::forget(Box::new(42)); +} From 0a63637e6640cdb9ef9e0afeb4d3408cd553093f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 7 Dec 2019 18:50:07 +0100 Subject: [PATCH 1395/3747] fix all-targets build --- benches/helpers/miri_helper.rs | 1 + src/bin/miri-rustc-tests.rs | 2 ++ 2 files changed, 3 insertions(+) diff --git a/benches/helpers/miri_helper.rs b/benches/helpers/miri_helper.rs index 95146513509bf..aa0f3d9959258 100644 --- a/benches/helpers/miri_helper.rs +++ b/benches/helpers/miri_helper.rs @@ -28,6 +28,7 @@ impl rustc_driver::Callbacks for MiriCompilerCalls<'_> { let config = miri::MiriConfig { validate: true, communicate: false, + ignore_leaks: false, excluded_env_vars: vec![], args: vec![], seed: None, diff --git a/src/bin/miri-rustc-tests.rs b/src/bin/miri-rustc-tests.rs index 5e3f663de2e58..df8bb583f8e3a 100644 --- a/src/bin/miri-rustc-tests.rs +++ b/src/bin/miri-rustc-tests.rs @@ -41,6 +41,7 @@ impl rustc_driver::Callbacks for MiriCompilerCalls { let config = MiriConfig { validate: true, communicate: false, + ignore_leaks: false, excluded_env_vars: vec![], args: vec![], seed: None, @@ -60,6 +61,7 @@ impl rustc_driver::Callbacks for MiriCompilerCalls { let config = MiriConfig { validate: true, communicate: false, + ignore_leaks: false, excluded_env_vars: vec![], args: vec![], seed: None From cefc592273fbf708378273317a1485a32bbc7318 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 8 Dec 2019 01:45:41 +0100 Subject: [PATCH 1396/3747] bump Rust, fix error messages --- rust-version | 2 +- tests/compile-fail/never_say_never.rs | 2 +- tests/compile-fail/never_transmute_humans.rs | 2 +- tests/compile-fail/never_transmute_void.rs | 2 +- tests/compile-fail/out_of_bounds_ptr_2.rs | 2 +- tests/compile-fail/ptr_offset_overflow.rs | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/rust-version b/rust-version index 83d06b2f7d2ec..7266b1bd0ab0d 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -6d77e45f01079fe3d40180b3e256e414ab379f63 +5c5c8eb864e56ce905742b8e97df5506bba6aeef diff --git a/tests/compile-fail/never_say_never.rs b/tests/compile-fail/never_say_never.rs index 199ceb70fb6be..21fc16751c259 100644 --- a/tests/compile-fail/never_say_never.rs +++ b/tests/compile-fail/never_say_never.rs @@ -6,7 +6,7 @@ fn main() { let y = &5; let x: ! = unsafe { - *(y as *const _ as *const !) //~ ERROR entered unreachable code + *(y as *const _ as *const !) //~ ERROR entering unreachable code }; f(x) } diff --git a/tests/compile-fail/never_transmute_humans.rs b/tests/compile-fail/never_transmute_humans.rs index f662fdcd98729..5053be24ebf09 100644 --- a/tests/compile-fail/never_transmute_humans.rs +++ b/tests/compile-fail/never_transmute_humans.rs @@ -5,6 +5,6 @@ struct Human; fn main() { let _x: ! = unsafe { - std::mem::transmute::(Human) //~ ERROR entered unreachable code + std::mem::transmute::(Human) //~ ERROR entering unreachable code }; } diff --git a/tests/compile-fail/never_transmute_void.rs b/tests/compile-fail/never_transmute_void.rs index 933e052119564..a9cbac528d7a5 100644 --- a/tests/compile-fail/never_transmute_void.rs +++ b/tests/compile-fail/never_transmute_void.rs @@ -6,7 +6,7 @@ enum Void {} fn f(v: Void) -> ! { - match v {} //~ ERROR entered unreachable code + match v {} //~ ERROR entering unreachable code } fn main() { diff --git a/tests/compile-fail/out_of_bounds_ptr_2.rs b/tests/compile-fail/out_of_bounds_ptr_2.rs index e19a616a19165..1e4759ddc46d0 100644 --- a/tests/compile-fail/out_of_bounds_ptr_2.rs +++ b/tests/compile-fail/out_of_bounds_ptr_2.rs @@ -1,4 +1,4 @@ -// error-pattern: attempt to add with overflow +// error-pattern: overflowing in-bounds pointer arithmetic fn main() { let v = [0i8; 4]; let x = &v as *const i8; diff --git a/tests/compile-fail/ptr_offset_overflow.rs b/tests/compile-fail/ptr_offset_overflow.rs index babd0246e7e1a..e52384e919678 100644 --- a/tests/compile-fail/ptr_offset_overflow.rs +++ b/tests/compile-fail/ptr_offset_overflow.rs @@ -1,4 +1,4 @@ -//error-pattern: attempt to add with overflow +//error-pattern: overflowing in-bounds pointer arithmetic fn main() { let v = [1i8, 2]; let x = &v[1] as *const i8; From 67151a712d4e894f145454de78dcd04aa16d204a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 8 Dec 2019 10:32:50 +0100 Subject: [PATCH 1397/3747] rustup --- rust-version | 2 +- src/helpers.rs | 2 +- src/shims/foreign_items.rs | 4 ++-- src/shims/mod.rs | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/rust-version b/rust-version index 7266b1bd0ab0d..bc65b5b6751b9 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -5c5c8eb864e56ce905742b8e97df5506bba6aeef +e862c01aadb2d029864f7bb256cf6c85bbb5d7e4 diff --git a/src/helpers.rs b/src/helpers.rs index 05a92164f27d8..763ab403f192e 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -131,7 +131,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); // Push frame. - let mir = this.load_mir(f.def, None)?.body(); + let mir = &*this.load_mir(f.def, None)?; let span = this.stack().last() .and_then(Frame::current_source_info) .map(|si| si.span) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 316cc686ad77d..a983c0b11fa28 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -141,14 +141,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx .expect("No panic runtime found!"); let panic_runtime = tcx.crate_name(*panic_runtime); let start_panic_instance = this.resolve_path(&[&*panic_runtime.as_str(), "__rust_start_panic"])?; - return Ok(Some(this.load_mir(start_panic_instance.def, None)?.body())); + return Ok(Some(&*this.load_mir(start_panic_instance.def, None)?)); } // Similarly, we forward calls to the `panic_impl` foreign item to its implementation. // The implementation is provided by the function with the `#[panic_handler]` attribute. "panic_impl" => { let panic_impl_id = this.tcx.lang_items().panic_impl().unwrap(); let panic_impl_instance = ty::Instance::mono(*this.tcx, panic_impl_id); - return Ok(Some(this.load_mir(panic_impl_instance.def, None)?.body())); + return Ok(Some(&*this.load_mir(panic_impl_instance.def, None)?)); } "exit" | "ExitProcess" => { diff --git a/src/shims/mod.rs b/src/shims/mod.rs index 21e69dc1f0fc2..06ef58eaf5267 100644 --- a/src/shims/mod.rs +++ b/src/shims/mod.rs @@ -49,7 +49,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // Otherwise, load the MIR. - Ok(Some(this.load_mir(instance.def, None)?.body())) + Ok(Some(&*this.load_mir(instance.def, None)?)) } fn align_offset( From b0a205ce6ffbe5618bc280d82f261320c8421790 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 8 Dec 2019 11:06:35 +0100 Subject: [PATCH 1398/3747] add caller_location tests to Miri --- tests/run-pass/track-caller-attribute.rs | 54 ++++++++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 tests/run-pass/track-caller-attribute.rs diff --git a/tests/run-pass/track-caller-attribute.rs b/tests/run-pass/track-caller-attribute.rs new file mode 100644 index 0000000000000..68a0c95b44dba --- /dev/null +++ b/tests/run-pass/track-caller-attribute.rs @@ -0,0 +1,54 @@ +#![feature(track_caller, core_intrinsics)] + +use std::panic::Location; + +#[track_caller] +fn tracked() -> &'static Location<'static> { + Location::caller() // most importantly, we never get line 7 +} + +fn nested_intrinsic() -> &'static Location<'static> { + Location::caller() +} + +fn nested_tracked() -> &'static Location<'static> { + tracked() +} + +macro_rules! caller_location_from_macro { + () => (core::panic::Location::caller()); +} + +fn main() { + let location = Location::caller(); + assert_eq!(location.file(), file!()); + assert_eq!(location.line(), 23); + assert_eq!(location.column(), 20); + + let tracked = tracked(); + assert_eq!(tracked.file(), file!()); + assert_eq!(tracked.line(), 28); + assert_eq!(tracked.column(), 19); + + let nested = nested_intrinsic(); + assert_eq!(nested.file(), file!()); + assert_eq!(nested.line(), 11); + assert_eq!(nested.column(), 5); + + let contained = nested_tracked(); + assert_eq!(contained.file(), file!()); + assert_eq!(contained.line(), 15); + assert_eq!(contained.column(), 5); + + // `Location::caller()` in a macro should behave similarly to `file!` and `line!`, + // i.e. point to where the macro was invoked, instead of the macro itself. + let inmacro = caller_location_from_macro!(); + assert_eq!(inmacro.file(), file!()); + assert_eq!(inmacro.line(), 45); + assert_eq!(inmacro.column(), 19); + + let intrinsic = core::intrinsics::caller_location(); + assert_eq!(intrinsic.file(), file!()); + assert_eq!(intrinsic.line(), 50); + assert_eq!(intrinsic.column(), 21); +} From ef37a4c158375a29f7b4035cd3aab144fff0bb8c Mon Sep 17 00:00:00 2001 From: Markus Pettersson Date: Sun, 8 Dec 2019 11:12:25 +0100 Subject: [PATCH 1399/3747] Updated README to reflect deprecation of rustup install --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 16eae05973b2a..e505496a69a85 100644 --- a/README.md +++ b/README.md @@ -61,7 +61,7 @@ If `rustup` says the `miri` component is unavailable, that's because not all nightly releases come with all tools. Check out [this website](https://rust-lang.github.io/rustup-components-history) to determine a nightly version that comes with Miri and install that using -`rustup install nightly-YYYY-MM-DD`. +`rustup toolchain install nightly-YYYY-MM-DD`. Now you can run your project in Miri: From c9e7fe8b8cdc1b1397b8f7bcaf5b2a1aff8b830c Mon Sep 17 00:00:00 2001 From: Markus Pettersson Date: Sun, 8 Dec 2019 11:22:02 +0100 Subject: [PATCH 1400/3747] Updated CI config to reflect deprecation of rustup uninstall --- .appveyor.yml | 2 +- .travis.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index b9e112aa08608..16fd20c9da616 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -27,7 +27,7 @@ install: - rustup-init.exe -y --default-host %TARGET% --default-toolchain stable --profile minimal - set PATH=%USERPROFILE%\.cargo\bin;%PATH% - rustup default stable - - rustup uninstall beta + - rustup toolchain uninstall beta - rustup update # Install "master" toolchain - cargo install rustup-toolchain-install-master & exit 0 diff --git a/.travis.yml b/.travis.yml index a080ab55b94f2..cbb7c69db1cdf 100644 --- a/.travis.yml +++ b/.travis.yml @@ -34,7 +34,7 @@ before_script: - curl https://build.travis-ci.org/files/rustup-init.sh -sSf | sh -s -- -y --default-toolchain stable --profile minimal - export PATH=$HOME/.cargo/bin:$PATH - rustup default stable -- rustup uninstall beta +- rustup toolchain uninstall beta - rustup update # Install "master" toolchain - cargo install rustup-toolchain-install-master || echo "rustup-toolchain-install-master already installed" From d363a47fcbbdcef228acef6f8625fc09ce168c55 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Thu, 28 Nov 2019 10:36:37 +0100 Subject: [PATCH 1401/3747] Add a scheme to find the place where an id was destroyed --- benches/helpers/miri_helper.rs | 1 + src/bin/miri-rustc-tests.rs | 4 +++- src/bin/miri.rs | 13 +++++++++++++ src/eval.rs | 4 +++- src/lib.rs | 5 ++++- src/machine.rs | 4 ++-- src/stacked_borrows.rs | 14 ++++++++++---- .../compile-fail/stacked_borrows/track_id.rs | 19 +++++++++++++++++++ 8 files changed, 55 insertions(+), 9 deletions(-) create mode 100644 tests/compile-fail/stacked_borrows/track_id.rs diff --git a/benches/helpers/miri_helper.rs b/benches/helpers/miri_helper.rs index aa0f3d9959258..40683f8d74756 100644 --- a/benches/helpers/miri_helper.rs +++ b/benches/helpers/miri_helper.rs @@ -32,6 +32,7 @@ impl rustc_driver::Callbacks for MiriCompilerCalls<'_> { excluded_env_vars: vec![], args: vec![], seed: None, + tracked_id: None, }; eval_main(tcx, entry_def_id, config); }); diff --git a/src/bin/miri-rustc-tests.rs b/src/bin/miri-rustc-tests.rs index df8bb583f8e3a..8b1739f3443b5 100644 --- a/src/bin/miri-rustc-tests.rs +++ b/src/bin/miri-rustc-tests.rs @@ -45,6 +45,7 @@ impl rustc_driver::Callbacks for MiriCompilerCalls { excluded_env_vars: vec![], args: vec![], seed: None, + tracked_id: None, }; let did = self.0.hir().body_owner_def_id(body_id); println!("running test: {}", self.0.def_path_debug_str(did)); @@ -64,7 +65,8 @@ impl rustc_driver::Callbacks for MiriCompilerCalls { ignore_leaks: false, excluded_env_vars: vec![], args: vec![], - seed: None + seed: None, + tracked_id: None, }; miri::eval_main(tcx, entry_def_id, config); diff --git a/src/bin/miri.rs b/src/bin/miri.rs index e255afc3463d4..e3aa75b9e8803 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -126,6 +126,7 @@ fn main() { let mut communicate = false; let mut ignore_leaks = false; let mut seed: Option = None; + let mut tracked_id: Option = None; let mut rustc_args = vec![]; let mut miri_args = vec![]; let mut after_dashdash = false; @@ -176,6 +177,17 @@ fn main() { arg if arg.starts_with("-Zmiri-env-exclude=") => { excluded_env_vars.push(arg.trim_start_matches("-Zmiri-env-exclude=").to_owned()); }, + arg if arg.starts_with("-Zmiri-track-id=") => { + let id: u64 = match arg.trim_start_matches("-Zmiri-track-id=").parse() { + Ok(id) => id, + Err(err) => panic!("-Zmiri-track-id requires a valid `u64` as the argument: {}", err), + }; + if let Some(id) = miri::PtrId::new(id) { + tracked_id = Some(id); + } else { + panic!("-Zmiri-track-id must be a nonzero id"); + } + }, _ => { rustc_args.push(arg); } @@ -208,6 +220,7 @@ fn main() { excluded_env_vars, seed, args: miri_args, + tracked_id, }; rustc_driver::install_ice_hook(); let result = rustc_driver::catch_fatal_errors(move || { diff --git a/src/eval.rs b/src/eval.rs index 8be42226b5ecf..fb82679523e38 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -26,6 +26,8 @@ pub struct MiriConfig { pub args: Vec, /// The seed to use when non-determinism or randomness are required (e.g. ptr-to-int cast, `getrandom()`). pub seed: Option, + /// The stacked borrow id to report about + pub tracked_id: Option, } /// Details of premature program termination. @@ -47,7 +49,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( tcx.at(syntax::source_map::DUMMY_SP), ty::ParamEnv::reveal_all(), Evaluator::new(config.communicate), - MemoryExtra::new(StdRng::seed_from_u64(config.seed.unwrap_or(0)), config.validate), + MemoryExtra::new(StdRng::seed_from_u64(config.seed.unwrap_or(0)), config.validate, config.tracked_id), ); // Complete initialization. EnvVars::init(&mut ecx, config.excluded_env_vars); diff --git a/src/lib.rs b/src/lib.rs index abed7ab9dfeb7..ee13631727d2c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -43,7 +43,10 @@ pub use crate::operator::EvalContextExt as OperatorEvalContextExt; pub use crate::range_map::RangeMap; pub use crate::helpers::{EvalContextExt as HelpersEvalContextExt}; pub use crate::mono_hash_map::MonoHashMap; -pub use crate::stacked_borrows::{EvalContextExt as StackedBorEvalContextExt, Tag, Permission, Stack, Stacks, Item}; +pub use crate::stacked_borrows::{ + EvalContextExt as StackedBorEvalContextExt, Tag, Permission, Stack, Stacks, Item, PtrId, + GlobalState, +}; pub use crate::machine::{ PAGE_SIZE, STACK_ADDR, STACK_SIZE, NUM_CPUS, MemoryExtra, AllocExtra, FrameData, MiriMemoryKind, Evaluator, MiriEvalContext, MiriEvalContextExt, diff --git a/src/machine.rs b/src/machine.rs index 65b6bcfb2ab7f..3d8e724c57c37 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -77,9 +77,9 @@ pub struct MemoryExtra { } impl MemoryExtra { - pub fn new(rng: StdRng, validate: bool) -> Self { + pub fn new(rng: StdRng, validate: bool, tracked_id: Option) -> Self { MemoryExtra { - stacked_borrows: Default::default(), + stacked_borrows: Rc::new(RefCell::new(GlobalState::new(tracked_id))), intptrcast: Default::default(), rng: RefCell::new(rng), validate, diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 23a32fc2ac5ca..bd42191821b76 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -105,6 +105,8 @@ pub struct GlobalState { next_call_id: CallId, /// Those call IDs corresponding to functions that are still running. active_calls: HashSet, + /// The id to trace in this execution run + tracked_id: Option, } /// Memory extra state gives us interior mutable access to the global state. pub type MemoryExtra = Rc>; @@ -151,18 +153,17 @@ impl fmt::Display for RefKind { } /// Utilities for initialization and ID generation -impl Default for GlobalState { - fn default() -> Self { +impl GlobalState { + pub fn new(tracked_id: Option) -> Self { GlobalState { next_ptr_id: NonZeroU64::new(1).unwrap(), base_ptr_ids: HashMap::default(), next_call_id: NonZeroU64::new(1).unwrap(), active_calls: HashSet::default(), + tracked_id, } } -} -impl GlobalState { fn new_ptr(&mut self) -> PtrId { let id = self.next_ptr_id; self.next_ptr_id = NonZeroU64::new(id.get() + 1).unwrap(); @@ -312,6 +313,11 @@ impl<'tcx> Stack { let first_incompatible_idx = self.find_first_write_incompatible(granting_idx); for item in self.borrows.drain(first_incompatible_idx..).rev() { trace!("access: popping item {:?}", item); + if let Tag::Tagged(id) = item.tag { + if Some(id) == global.tracked_id { + throw_unsup!(Unsupported(format!("popped id {}", id))); + } + } Stack::check_protector(&item, Some(tag), global)?; } } else { diff --git a/tests/compile-fail/stacked_borrows/track_id.rs b/tests/compile-fail/stacked_borrows/track_id.rs new file mode 100644 index 0000000000000..67d38b119412e --- /dev/null +++ b/tests/compile-fail/stacked_borrows/track_id.rs @@ -0,0 +1,19 @@ +// compile-flags: -Zmiri-track-id=1372 +// do not run on anything but x86_64 linux, because minute changes can change the borrow stack ids +// only-x86_64 +// only-linux + +use std::mem; + +fn main() { + let mut target = 42; + // Make sure we cannot use a raw-tagged `&mut` pointing to a frozen location. + // Even just creating it unfreezes. + let raw = &mut target as *mut _; // let this leak to raw + let reference = unsafe { &*raw }; // freeze + let ptr = reference as *const _ as *mut i32; // raw ptr, with raw tag + let _mut_ref: &mut i32 = unsafe { mem::transmute(ptr) }; // &mut, with raw tag + //~^ ERROR popped id 1372 + // Now we retag, making our ref top-of-stack -- and, in particular, unfreezing. + let _val = *reference; +} From a0de213e421fa64f293d4247a2e7225104d8b6d9 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Thu, 28 Nov 2019 11:14:16 +0100 Subject: [PATCH 1402/3747] Vocabulary fix --- tests/compile-fail/stacked_borrows/track_id.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/compile-fail/stacked_borrows/track_id.rs b/tests/compile-fail/stacked_borrows/track_id.rs index 67d38b119412e..04f4f251fbaf0 100644 --- a/tests/compile-fail/stacked_borrows/track_id.rs +++ b/tests/compile-fail/stacked_borrows/track_id.rs @@ -1,5 +1,5 @@ // compile-flags: -Zmiri-track-id=1372 -// do not run on anything but x86_64 linux, because minute changes can change the borrow stack ids +// do not run on anything but x86_64 linux, because minor libstd changes can change the borrow stack ids // only-x86_64 // only-linux From 67417945d4925e0c74277df2ba38d968791aba6d Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Thu, 28 Nov 2019 14:33:35 +0100 Subject: [PATCH 1403/3747] Detect all variants of stack removals --- src/stacked_borrows.rs | 10 +++++----- tests/compile-fail/stacked_borrows/track_id.rs | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index bd42191821b76..be54b7f5ababb 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -271,6 +271,11 @@ impl<'tcx> Stack { /// Check if the given item is protected. fn check_protector(item: &Item, tag: Option, global: &GlobalState) -> InterpResult<'tcx> { + if let Tag::Tagged(id) = item.tag { + if Some(id) == global.tracked_id { + throw_unsup!(Unsupported(format!("disabling item {:?} for tag {:?}", item, tag))); + } + } if let Some(call) = item.protector { if global.is_active(call) { if let Some(tag) = tag { @@ -313,11 +318,6 @@ impl<'tcx> Stack { let first_incompatible_idx = self.find_first_write_incompatible(granting_idx); for item in self.borrows.drain(first_incompatible_idx..).rev() { trace!("access: popping item {:?}", item); - if let Tag::Tagged(id) = item.tag { - if Some(id) == global.tracked_id { - throw_unsup!(Unsupported(format!("popped id {}", id))); - } - } Stack::check_protector(&item, Some(tag), global)?; } } else { diff --git a/tests/compile-fail/stacked_borrows/track_id.rs b/tests/compile-fail/stacked_borrows/track_id.rs index 04f4f251fbaf0..e691603b53416 100644 --- a/tests/compile-fail/stacked_borrows/track_id.rs +++ b/tests/compile-fail/stacked_borrows/track_id.rs @@ -13,7 +13,7 @@ fn main() { let reference = unsafe { &*raw }; // freeze let ptr = reference as *const _ as *mut i32; // raw ptr, with raw tag let _mut_ref: &mut i32 = unsafe { mem::transmute(ptr) }; // &mut, with raw tag - //~^ ERROR popped id 1372 + //~^ ERROR disabling item [SharedReadOnly for <1372>] for tag Some() // Now we retag, making our ref top-of-stack -- and, in particular, unfreezing. let _val = *reference; } From eab25383174ec70b76395d079ad6e85dfd15f2ff Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Sun, 1 Dec 2019 00:02:58 +0100 Subject: [PATCH 1404/3747] Rename track-id to track-pointer-tag --- benches/helpers/miri_helper.rs | 2 +- src/bin/miri-rustc-tests.rs | 4 ++-- src/bin/miri.rs | 14 +++++++------- src/eval.rs | 4 ++-- src/machine.rs | 4 ++-- src/stacked_borrows.rs | 8 ++++---- tests/compile-fail/stacked_borrows/track_id.rs | 2 +- 7 files changed, 19 insertions(+), 19 deletions(-) diff --git a/benches/helpers/miri_helper.rs b/benches/helpers/miri_helper.rs index 40683f8d74756..e2951110acdf9 100644 --- a/benches/helpers/miri_helper.rs +++ b/benches/helpers/miri_helper.rs @@ -32,7 +32,7 @@ impl rustc_driver::Callbacks for MiriCompilerCalls<'_> { excluded_env_vars: vec![], args: vec![], seed: None, - tracked_id: None, + tracked_pointer_tag: None, }; eval_main(tcx, entry_def_id, config); }); diff --git a/src/bin/miri-rustc-tests.rs b/src/bin/miri-rustc-tests.rs index 8b1739f3443b5..370d2a206178e 100644 --- a/src/bin/miri-rustc-tests.rs +++ b/src/bin/miri-rustc-tests.rs @@ -45,7 +45,7 @@ impl rustc_driver::Callbacks for MiriCompilerCalls { excluded_env_vars: vec![], args: vec![], seed: None, - tracked_id: None, + tracked_pointer_tag: None, }; let did = self.0.hir().body_owner_def_id(body_id); println!("running test: {}", self.0.def_path_debug_str(did)); @@ -66,7 +66,7 @@ impl rustc_driver::Callbacks for MiriCompilerCalls { excluded_env_vars: vec![], args: vec![], seed: None, - tracked_id: None, + tracked_pointer_tag: None, }; miri::eval_main(tcx, entry_def_id, config); diff --git a/src/bin/miri.rs b/src/bin/miri.rs index e3aa75b9e8803..48af812962575 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -126,7 +126,7 @@ fn main() { let mut communicate = false; let mut ignore_leaks = false; let mut seed: Option = None; - let mut tracked_id: Option = None; + let mut tracked_pointer_tag: Option = None; let mut rustc_args = vec![]; let mut miri_args = vec![]; let mut after_dashdash = false; @@ -177,15 +177,15 @@ fn main() { arg if arg.starts_with("-Zmiri-env-exclude=") => { excluded_env_vars.push(arg.trim_start_matches("-Zmiri-env-exclude=").to_owned()); }, - arg if arg.starts_with("-Zmiri-track-id=") => { - let id: u64 = match arg.trim_start_matches("-Zmiri-track-id=").parse() { + arg if arg.starts_with("-Zmiri-track-pointer-tag=") => { + let id: u64 = match arg.trim_start_matches("-Zmiri-track-pointer-tag=").parse() { Ok(id) => id, - Err(err) => panic!("-Zmiri-track-id requires a valid `u64` as the argument: {}", err), + Err(err) => panic!("-Zmiri-track-pointer-tag requires a valid `u64` as the argument: {}", err), }; if let Some(id) = miri::PtrId::new(id) { - tracked_id = Some(id); + tracked_pointer_tag = Some(id); } else { - panic!("-Zmiri-track-id must be a nonzero id"); + panic!("-Zmiri-track-pointer-tag must be a nonzero id"); } }, _ => { @@ -220,7 +220,7 @@ fn main() { excluded_env_vars, seed, args: miri_args, - tracked_id, + tracked_pointer_tag, }; rustc_driver::install_ice_hook(); let result = rustc_driver::catch_fatal_errors(move || { diff --git a/src/eval.rs b/src/eval.rs index fb82679523e38..81de2fa882c54 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -27,7 +27,7 @@ pub struct MiriConfig { /// The seed to use when non-determinism or randomness are required (e.g. ptr-to-int cast, `getrandom()`). pub seed: Option, /// The stacked borrow id to report about - pub tracked_id: Option, + pub tracked_pointer_tag: Option, } /// Details of premature program termination. @@ -49,7 +49,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( tcx.at(syntax::source_map::DUMMY_SP), ty::ParamEnv::reveal_all(), Evaluator::new(config.communicate), - MemoryExtra::new(StdRng::seed_from_u64(config.seed.unwrap_or(0)), config.validate, config.tracked_id), + MemoryExtra::new(StdRng::seed_from_u64(config.seed.unwrap_or(0)), config.validate, config.tracked_pointer_tag), ); // Complete initialization. EnvVars::init(&mut ecx, config.excluded_env_vars); diff --git a/src/machine.rs b/src/machine.rs index 3d8e724c57c37..d5cd86d97878b 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -77,9 +77,9 @@ pub struct MemoryExtra { } impl MemoryExtra { - pub fn new(rng: StdRng, validate: bool, tracked_id: Option) -> Self { + pub fn new(rng: StdRng, validate: bool, tracked_pointer_tag: Option) -> Self { MemoryExtra { - stacked_borrows: Rc::new(RefCell::new(GlobalState::new(tracked_id))), + stacked_borrows: Rc::new(RefCell::new(GlobalState::new(tracked_pointer_tag))), intptrcast: Default::default(), rng: RefCell::new(rng), validate, diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index be54b7f5ababb..ad70b05d8abd6 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -106,7 +106,7 @@ pub struct GlobalState { /// Those call IDs corresponding to functions that are still running. active_calls: HashSet, /// The id to trace in this execution run - tracked_id: Option, + tracked_pointer_tag: Option, } /// Memory extra state gives us interior mutable access to the global state. pub type MemoryExtra = Rc>; @@ -154,13 +154,13 @@ impl fmt::Display for RefKind { /// Utilities for initialization and ID generation impl GlobalState { - pub fn new(tracked_id: Option) -> Self { + pub fn new(tracked_pointer_tag: Option) -> Self { GlobalState { next_ptr_id: NonZeroU64::new(1).unwrap(), base_ptr_ids: HashMap::default(), next_call_id: NonZeroU64::new(1).unwrap(), active_calls: HashSet::default(), - tracked_id, + tracked_pointer_tag, } } @@ -272,7 +272,7 @@ impl<'tcx> Stack { /// Check if the given item is protected. fn check_protector(item: &Item, tag: Option, global: &GlobalState) -> InterpResult<'tcx> { if let Tag::Tagged(id) = item.tag { - if Some(id) == global.tracked_id { + if Some(id) == global.tracked_pointer_tag { throw_unsup!(Unsupported(format!("disabling item {:?} for tag {:?}", item, tag))); } } diff --git a/tests/compile-fail/stacked_borrows/track_id.rs b/tests/compile-fail/stacked_borrows/track_id.rs index e691603b53416..35a0f04ee6f1c 100644 --- a/tests/compile-fail/stacked_borrows/track_id.rs +++ b/tests/compile-fail/stacked_borrows/track_id.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-track-id=1372 +// compile-flags: -Zmiri-track-pointer-tag=1372 // do not run on anything but x86_64 linux, because minor libstd changes can change the borrow stack ids // only-x86_64 // only-linux From acb43f80fdd2fb8c81192a030d9c847d27fa502d Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Sun, 1 Dec 2019 00:03:06 +0100 Subject: [PATCH 1405/3747] Document the new flag --- README.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 16eae05973b2a..176b4c4c342d6 100644 --- a/README.md +++ b/README.md @@ -160,7 +160,7 @@ Several `-Z` flags are relevant for Miri: the program has access to host resources such as environment variables and randomness (and, eventually, file systems and more). * `-Zmiri-ignore-leaks` disables the memory leak checker. -* `-Zmiri-env-exclude=` keeps the `var` environment variable isolated from +* `-Zmiri-env-exclude=` keeps the `var` environment variable isolated from the host. Can be used multiple times to exclude several variables. The `TERM` environment variable is excluded by default. * `-Zmir-opt-level` controls how many MIR optimizations are performed. Miri @@ -171,6 +171,11 @@ Several `-Z` flags are relevant for Miri: sets this flag per default. * `-Zmir-emit-retag` controls whether `Retag` statements are emitted. Miri enables this per default because it is needed for validation. +* `-Zmiri-track-pointer-tag` aborts interpretation with a backtrace when the + given pointer tag is popped from a borrow stack (which is where the tag + becomes invalid and any future use of it will error anyway). This helps you + in finding out why UB is happening and where in your code would be a good + place to look for it. Moreover, Miri recognizes some environment variables: From 7cd0d7f15266eeebada17e51881b470561c3e697 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Sun, 1 Dec 2019 00:04:24 +0100 Subject: [PATCH 1406/3747] Remove a flaky test --- .../compile-fail/stacked_borrows/track_id.rs | 19 ------------------- 1 file changed, 19 deletions(-) delete mode 100644 tests/compile-fail/stacked_borrows/track_id.rs diff --git a/tests/compile-fail/stacked_borrows/track_id.rs b/tests/compile-fail/stacked_borrows/track_id.rs deleted file mode 100644 index 35a0f04ee6f1c..0000000000000 --- a/tests/compile-fail/stacked_borrows/track_id.rs +++ /dev/null @@ -1,19 +0,0 @@ -// compile-flags: -Zmiri-track-pointer-tag=1372 -// do not run on anything but x86_64 linux, because minor libstd changes can change the borrow stack ids -// only-x86_64 -// only-linux - -use std::mem; - -fn main() { - let mut target = 42; - // Make sure we cannot use a raw-tagged `&mut` pointing to a frozen location. - // Even just creating it unfreezes. - let raw = &mut target as *mut _; // let this leak to raw - let reference = unsafe { &*raw }; // freeze - let ptr = reference as *const _ as *mut i32; // raw ptr, with raw tag - let _mut_ref: &mut i32 = unsafe { mem::transmute(ptr) }; // &mut, with raw tag - //~^ ERROR disabling item [SharedReadOnly for <1372>] for tag Some() - // Now we retag, making our ref top-of-stack -- and, in particular, unfreezing. - let _val = *reference; -} From 817f4159a2146b95fd29fb5ea1725463e8f2dfd3 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Mon, 9 Dec 2019 14:29:28 +0100 Subject: [PATCH 1407/3747] Use the machine stop error instead of abusing other error kinds --- src/eval.rs | 3 +++ src/stacked_borrows.rs | 4 ++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/eval.rs b/src/eval.rs index 81de2fa882c54..9a70663716d61 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -33,6 +33,7 @@ pub struct MiriConfig { /// Details of premature program termination. pub enum TerminationInfo { Exit(i64), + PoppedTrackedPointerTag(Item), Abort, } @@ -218,6 +219,8 @@ pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) -> .expect("invalid MachineStop payload"); match info { TerminationInfo::Exit(code) => return Some(*code), + TerminationInfo::PoppedTrackedPointerTag(item) => + format!("popped tracked tag for item {:?}", item), TerminationInfo::Abort => format!("the evaluated program aborted execution") } diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index ad70b05d8abd6..8782eb83d1835 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -12,7 +12,7 @@ use rustc::hir::Mutability::{Mutable, Immutable}; use rustc::mir::RetagKind; use crate::{ - InterpResult, HelpersEvalContextExt, + InterpResult, HelpersEvalContextExt, TerminationInfo, MemoryKind, MiriMemoryKind, RangeMap, AllocId, Pointer, Immediate, ImmTy, PlaceTy, MPlaceTy, }; @@ -273,7 +273,7 @@ impl<'tcx> Stack { fn check_protector(item: &Item, tag: Option, global: &GlobalState) -> InterpResult<'tcx> { if let Tag::Tagged(id) = item.tag { if Some(id) == global.tracked_pointer_tag { - throw_unsup!(Unsupported(format!("disabling item {:?} for tag {:?}", item, tag))); + throw_machine_stop!(TerminationInfo::PoppedTrackedPointerTag(item.clone())); } } if let Some(call) = item.protector { From 8d409a7b593b32b6b1fa1914ce352efea1bb8095 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Tue, 10 Dec 2019 14:47:28 +0100 Subject: [PATCH 1408/3747] Update README.md Co-Authored-By: Ralf Jung --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 176b4c4c342d6..5be16899a5efa 100644 --- a/README.md +++ b/README.md @@ -171,7 +171,7 @@ Several `-Z` flags are relevant for Miri: sets this flag per default. * `-Zmir-emit-retag` controls whether `Retag` statements are emitted. Miri enables this per default because it is needed for validation. -* `-Zmiri-track-pointer-tag` aborts interpretation with a backtrace when the +* `-Zmiri-track-pointer-tag=` aborts interpretation with a backtrace when the given pointer tag is popped from a borrow stack (which is where the tag becomes invalid and any future use of it will error anyway). This helps you in finding out why UB is happening and where in your code would be a good From f0d43872ad61b392d229319ae1a1478e8a558b11 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 13 Dec 2019 13:19:46 +0100 Subject: [PATCH 1409/3747] add test for sketchy vtable --- tests/compile-fail/issue-miri-1112.rs | 46 +++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 tests/compile-fail/issue-miri-1112.rs diff --git a/tests/compile-fail/issue-miri-1112.rs b/tests/compile-fail/issue-miri-1112.rs new file mode 100644 index 0000000000000..29cc5c781200d --- /dev/null +++ b/tests/compile-fail/issue-miri-1112.rs @@ -0,0 +1,46 @@ +trait Empty {} + +#[repr(transparent)] +pub struct FunnyPointer(dyn Empty); + +#[repr(C)] +pub struct Meta { + drop_fn: fn(&mut ()), + size: usize, + align: usize, +} + +impl Meta { + pub fn new() -> Self { + Meta { + drop_fn: |_| {}, + size: 0, + align: 1, + } + } +} + +#[repr(C)] +pub struct FatPointer { + pub data: *const (), + pub vtable: *const (), +} + +impl FunnyPointer { + pub unsafe fn from_data_ptr(data: &String, ptr: *const Meta) -> &Self { + let obj = FatPointer { + data: data as *const _ as *const (), + vtable: ptr as *const _ as *const (), + }; + let obj = std::mem::transmute::(obj); //~ ERROR invalid drop fn in vtable + &*obj + } +} + +fn main() { + unsafe { + let meta = Meta::new(); + let hello = "hello".to_string(); + let _raw: &FunnyPointer = FunnyPointer::from_data_ptr(&hello, &meta as *const _); + } +} From bbd512d52f5203672452a8c476775bf27fe4b110 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 14 Dec 2019 12:06:01 +0100 Subject: [PATCH 1410/3747] bump Rust --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index bc65b5b6751b9..afa5b6ae4861c 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -e862c01aadb2d029864f7bb256cf6c85bbb5d7e4 +12307b3b08edee543a78fb9d4a837fbd6d6ac0fa From 74ef63ff0aeeffc87b8d53f5fe3aadbe7cc00d3e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 15 Dec 2019 12:22:09 +0100 Subject: [PATCH 1411/3747] the never type got de-stabilized again; adjust tests --- rust-version | 2 +- tests/compile-fail/never_say_never.rs | 1 + tests/compile-fail/never_transmute_humans.rs | 2 ++ tests/compile-fail/never_transmute_void.rs | 1 + tests/run-pass/async-fn.rs | 2 ++ tests/run-pass/generator.rs | 2 +- tests/run-pass/loop-break-value.rs | 1 + tests/run-pass/panic/catch_panic.rs | 2 +- 8 files changed, 10 insertions(+), 3 deletions(-) diff --git a/rust-version b/rust-version index afa5b6ae4861c..584f9f86b985e 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -12307b3b08edee543a78fb9d4a837fbd6d6ac0fa +a605441e049f0b6d5f7715b94b8ac4662fd7fcf6 diff --git a/tests/compile-fail/never_say_never.rs b/tests/compile-fail/never_say_never.rs index 21fc16751c259..37dfe827d997b 100644 --- a/tests/compile-fail/never_say_never.rs +++ b/tests/compile-fail/never_say_never.rs @@ -1,6 +1,7 @@ // This should fail even without validation // compile-flags: -Zmiri-disable-validation +#![feature(never_type)] #![allow(unreachable_code)] fn main() { diff --git a/tests/compile-fail/never_transmute_humans.rs b/tests/compile-fail/never_transmute_humans.rs index 5053be24ebf09..2e0d4e9bdf337 100644 --- a/tests/compile-fail/never_transmute_humans.rs +++ b/tests/compile-fail/never_transmute_humans.rs @@ -1,6 +1,8 @@ // This should fail even without validation // compile-flags: -Zmiri-disable-validation +#![feature(never_type)] + struct Human; fn main() { diff --git a/tests/compile-fail/never_transmute_void.rs b/tests/compile-fail/never_transmute_void.rs index a9cbac528d7a5..2a822ab1b5150 100644 --- a/tests/compile-fail/never_transmute_void.rs +++ b/tests/compile-fail/never_transmute_void.rs @@ -1,6 +1,7 @@ // This should fail even without validation // compile-flags: -Zmiri-disable-validation +#![feature(never_type)] #![allow(unused, invalid_value)] enum Void {} diff --git a/tests/run-pass/async-fn.rs b/tests/run-pass/async-fn.rs index a4c176ad8f121..90448aca17792 100644 --- a/tests/run-pass/async-fn.rs +++ b/tests/run-pass/async-fn.rs @@ -1,3 +1,5 @@ +#![feature(never_type)] + use std::{future::Future, pin::Pin, task::Poll, ptr}; use std::task::{Waker, RawWaker, RawWakerVTable, Context}; diff --git a/tests/run-pass/generator.rs b/tests/run-pass/generator.rs index 00ebba6344e2e..c31b5b9ed3bb2 100644 --- a/tests/run-pass/generator.rs +++ b/tests/run-pass/generator.rs @@ -1,4 +1,4 @@ -#![feature(generators, generator_trait)] +#![feature(generators, generator_trait, never_type)] use std::ops::{GeneratorState, Generator}; use std::pin::Pin; diff --git a/tests/run-pass/loop-break-value.rs b/tests/run-pass/loop-break-value.rs index 43acdc228202e..bd7afa7ec1a80 100644 --- a/tests/run-pass/loop-break-value.rs +++ b/tests/run-pass/loop-break-value.rs @@ -1,3 +1,4 @@ +#![feature(never_type)] #![allow(unreachable_code)] #[allow(unused)] diff --git a/tests/run-pass/panic/catch_panic.rs b/tests/run-pass/panic/catch_panic.rs index a14dd411c1c66..722da68b70b28 100644 --- a/tests/run-pass/panic/catch_panic.rs +++ b/tests/run-pass/panic/catch_panic.rs @@ -1,6 +1,6 @@ // ignore-windows: Unwind panicking does not currently work on Windows +#![feature(never_type)] #![allow(const_err)] - use std::panic::{catch_unwind, AssertUnwindSafe}; use std::cell::Cell; From d9859c83fc416880f31f3fb8409ddb21673435f7 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Sat, 21 Dec 2019 11:45:09 +0100 Subject: [PATCH 1412/3747] Rustup to rustc 1.42.0-nightly (9ff30a781 2019-12-21) --- rust-version | 2 +- tests/compile-fail/stacked_borrows/illegal_write6.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/rust-version b/rust-version index 584f9f86b985e..f3c0b833d1a1f 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -a605441e049f0b6d5f7715b94b8ac4662fd7fcf6 +9ff30a7810c586819a78188c173a7b74adbb9730 diff --git a/tests/compile-fail/stacked_borrows/illegal_write6.rs b/tests/compile-fail/stacked_borrows/illegal_write6.rs index 86f2c0f350e3d..6985e7f0ead3b 100644 --- a/tests/compile-fail/stacked_borrows/illegal_write6.rs +++ b/tests/compile-fail/stacked_borrows/illegal_write6.rs @@ -7,6 +7,6 @@ fn main() { fn foo(a: &mut u32, y: *mut u32) -> u32 { *a = 1; let _b = &*a; - unsafe { *y = 2; } //~ ERROR: borrow stack + unsafe { *y = 2; } //~ ERROR: not granting access to tag return *a; } From b0c7625dd109197cc38710da64e5eeb401f97379 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Sat, 30 Nov 2019 15:09:52 -0500 Subject: [PATCH 1413/3747] add `statx` shim for linux --- src/helpers.rs | 42 ++++++++ src/shims/env.rs | 8 +- src/shims/foreign_items.rs | 15 ++- src/shims/fs.rs | 198 ++++++++++++++++++++++++++++++++++++- src/shims/time.rs | 39 +++----- tests/run-pass/fs.rs | 38 ++++++- 6 files changed, 303 insertions(+), 37 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index 05a92164f27d8..ac63a3a9b3a4c 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -509,3 +509,45 @@ fn bytes_to_os_str<'tcx, 'a>(bytes: &'a [u8]) -> InterpResult<'tcx, &'a OsStr> { .map_err(|_| err_unsup_format!("{:?} is not a valid utf-8 string", bytes))?; Ok(&OsStr::new(s)) } + +// FIXME: change `ImmTy::from_int` so it returns an `InterpResult` instead and remove this +// function. +pub fn immty_from_int_checked<'tcx>( + int: impl Into, + layout: TyLayout<'tcx>, +) -> InterpResult<'tcx, ImmTy<'tcx, Tag>> { + let int = int.into(); + // If `int` does not fit in `size` bits, we error instead of letting + // `ImmTy::from_int` panic. + let size = layout.size; + let truncated = truncate(int as u128, size); + if sign_extend(truncated, size) as i128 != int { + throw_unsup_format!( + "Signed value {:#x} does not fit in {} bits", + int, + size.bits() + ) + } + Ok(ImmTy::from_int(int, layout)) +} + +// FIXME: change `ImmTy::from_uint` so it returns an `InterpResult` instead and remove this +// function. +pub fn immty_from_uint_checked<'tcx>( + int: impl Into, + layout: TyLayout<'tcx>, +) -> InterpResult<'tcx, ImmTy<'tcx, Tag>> { + let int = int.into(); + // If `int` does not fit in `size` bits, we error instead of letting + // `ImmTy::from_int` panic. + let size = layout.size; + if truncate(int, size) != int { + throw_unsup_format!( + "Unsigned value {:#x} does not fit in {} bits", + int, + size.bits() + ) + } + Ok(ImmTy::from_uint(int, layout)) +} + diff --git a/src/shims/env.rs b/src/shims/env.rs index 8c431fd2016d5..3994cf78780aa 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -20,8 +20,12 @@ impl EnvVars { ecx: &mut InterpCx<'mir, 'tcx, Evaluator<'tcx>>, mut excluded_env_vars: Vec, ) { - // Exclude `TERM` var to avoid terminfo trying to open the termcap file. - excluded_env_vars.push("TERM".to_owned()); + + // FIXME: this can be removed when we have the `stat64` shim for macos. + if ecx.tcx.sess.target.target.target_os.to_lowercase() != "linux" { + // Exclude `TERM` var to avoid terminfo trying to open the termcap file. + excluded_env_vars.push("TERM".to_owned()); + } if ecx.machine.communicate { for (name, value) in env::vars() { diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 316cc686ad77d..3989f7f48a0b9 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -303,14 +303,25 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx .expect("Failed to get libc::SYS_getrandom") .to_machine_usize(this)?; - // `libc::syscall(NR_GETRANDOM, buf.as_mut_ptr(), buf.len(), GRND_NONBLOCK)` - // is called if a `HashMap` is created the regular way (e.g. HashMap). + let sys_statx = this + .eval_path_scalar(&["libc", "SYS_statx"])? + .expect("Failed to get libc::SYS_statx") + .to_machine_usize(this)?; + match this.read_scalar(args[0])?.to_machine_usize(this)? { + // `libc::syscall(NR_GETRANDOM, buf.as_mut_ptr(), buf.len(), GRND_NONBLOCK)` + // is called if a `HashMap` is created the regular way (e.g. HashMap). id if id == sys_getrandom => { // The first argument is the syscall id, // so skip over it. linux_getrandom(this, &args[1..], dest)?; } + id if id == sys_statx => { + // The first argument is the syscall id, + // so skip over it. + let result = this.statx(args[1], args[2], args[3], args[4], args[5])?; + this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + } id => throw_unsup_format!("miri does not support syscall ID {}", id), } } diff --git a/src/shims/fs.rs b/src/shims/fs.rs index 4d10be6264600..47f3f50b76aff 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -1,12 +1,16 @@ use std::collections::HashMap; -use std::convert::TryFrom; +use std::convert::{TryInto, TryFrom}; use std::fs::{remove_file, File, OpenOptions}; use std::io::{Read, Write}; +use std::path::PathBuf; +use std::time::SystemTime; -use rustc::ty::layout::{Size, Align}; +use rustc::ty::layout::{Size, Align, LayoutOf}; use crate::stacked_borrows::Tag; use crate::*; +use helpers::immty_from_uint_checked; +use shims::time::system_time_to_duration; #[derive(Debug)] pub struct FileHandle { @@ -98,7 +102,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let path = this.read_os_str_from_c_str(this.read_scalar(path_op)?.not_undef()?)?; - let fd = options.open(path).map(|file| { + let fd = options.open(&path).map(|file| { let mut fh = &mut this.machine.file_handler; fh.low += 1; fh.handles.insert(fh.low, FileHandle { file }).unwrap_none(); @@ -257,6 +261,181 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.try_unwrap_io_result(result) } + fn statx( + &mut self, + dirfd_op: OpTy<'tcx, Tag>, // Should be an `int` + pathname_op: OpTy<'tcx, Tag>, // Should be a `const char *` + flags_op: OpTy<'tcx, Tag>, // Should be an `int` + _mask_op: OpTy<'tcx, Tag>, // Should be an `unsigned int` + statxbuf_op: OpTy<'tcx, Tag> // Should be a `struct statx *` + ) -> InterpResult<'tcx, i32> { + let this = self.eval_context_mut(); + + this.check_no_isolation("statx")?; + + let statxbuf_scalar = this.read_scalar(statxbuf_op)?.not_undef()?; + let pathname_scalar = this.read_scalar(pathname_op)?.not_undef()?; + + // If the statxbuf or pathname pointers are null, the function fails with `EFAULT`. + if this.is_null(statxbuf_scalar)? || this.is_null(pathname_scalar)? { + let efault = this.eval_libc("EFAULT")?; + this.set_last_error(efault)?; + return Ok(-1); + } + + // Under normal circumstances, we would use `deref_operand(statxbuf_op)` to produce a + // proper `MemPlace` and then write the results of this function to it. However, the + // `syscall` function is untyped. This means that all the `statx` parameters are provided + // as `isize`s instead of having the proper types. Thus, we have to recover the layout of + // `statxbuf_op` by using the `libc::statx` struct type. + let statxbuf_place = { + // FIXME: This long path is required because `libc::statx` is an struct and also a + // function and `resolve_path` is returning the latter. + let statx_ty = this + .resolve_path(&["libc", "unix", "linux_like", "linux", "gnu", "statx"])? + .ty(*this.tcx); + let statxbuf_ty = this.tcx.mk_mut_ptr(statx_ty); + let statxbuf_layout = this.layout_of(statxbuf_ty)?; + let statxbuf_imm = ImmTy::from_scalar(statxbuf_scalar, statxbuf_layout); + this.ref_to_mplace(statxbuf_imm)? + }; + + let path: PathBuf = this.read_os_str_from_c_str(pathname_scalar)?.into(); + // `flags` should be a `c_int` but the `syscall` function provides an `isize`. + let flags: i32 = this + .read_scalar(flags_op)? + .to_machine_isize(&*this.tcx)? + .try_into() + .map_err(|e| err_unsup_format!( + "Failed to convert pointer sized operand to integer: {}", + e + ))?; + // `dirfd` should be a `c_int` but the `syscall` function provides an `isize`. + let dirfd: i32 = this + .read_scalar(dirfd_op)? + .to_machine_isize(&*this.tcx)? + .try_into() + .map_err(|e| err_unsup_format!( + "Failed to convert pointer sized operand to integer: {}", + e + ))?; + // we only support interpreting `path` as an absolute directory or as a directory relative + // to `dirfd` when the latter is `AT_FDCWD`. The behavior of `statx` with a relative path + // and a directory file descriptor other than `AT_FDCWD` is specified but it cannot be + // tested from `libstd`. If you found this error, please open an issue reporting it. + if !(path.is_absolute() || dirfd == this.eval_libc_i32("AT_FDCWD")?) + { + throw_unsup_format!( + "Using statx with a relative path and a file descriptor different from `AT_FDCWD` is not supported" + ) + } + + // the `_mask_op` paramter specifies the file information that the caller requested. + // However `statx` is allowed to return information that was not requested or to not + // return information that was requested. This `mask` represents the information we can + // actually provide in any host platform. + let mut mask = + this.eval_libc("STATX_TYPE")?.to_u32()? | this.eval_libc("STATX_SIZE")?.to_u32()?; + + // If the `AT_SYMLINK_NOFOLLOW` flag is set, we query the file's metadata without following + // symbolic links. + let metadata = if flags & this.eval_libc("AT_SYMLINK_NOFOLLOW")?.to_i32()? != 0 { + // FIXME: metadata for symlinks need testing. + std::fs::symlink_metadata(path) + } else { + std::fs::metadata(path) + }; + + let metadata = match metadata { + Ok(metadata) => metadata, + Err(e) => { + this.set_last_error_from_io_error(e)?; + return Ok(-1); + } + }; + + let file_type = metadata.file_type(); + + let mode_name = if file_type.is_file() { + "S_IFREG" + } else if file_type.is_dir() { + "S_IFDIR" + } else { + "S_IFLNK" + }; + + // The `mode` field specifies the type of the file and the permissions over the file for + // the owner, its group and other users. Given that we can only provide the file type + // without using platform specific methods, we only set the bits corresponding to the file + // type. This should be an `__u16` but `libc` provides its values as `u32`. + let mode: u16 = this.eval_libc(mode_name)? + .to_u32()? + .try_into() + .unwrap_or_else(|_| bug!("libc contains bad value for `{}` constant", mode_name)); + + let size = metadata.len(); + + let (access_sec, access_nsec) = extract_sec_and_nsec( + metadata.accessed(), + &mut mask, + this.eval_libc("STATX_ATIME")?.to_u32()? + )?; + + let (created_sec, created_nsec) = extract_sec_and_nsec( + metadata.created(), + &mut mask, + this.eval_libc("STATX_BTIME")?.to_u32()? + )?; + + let (modified_sec, modified_nsec) = extract_sec_and_nsec( + metadata.modified(), + &mut mask, + this.eval_libc("STATX_MTIME")?.to_u32()? + )?; + + let __u32_layout = this.libc_ty_layout("__u32")?; + let __u64_layout = this.libc_ty_layout("__u64")?; + let __u16_layout = this.libc_ty_layout("__u16")?; + + // Now we transform all this fields into `ImmTy`s and write them to `statxbuf`. We write a + // zero for the unavailable fields. + // FIXME: Provide more fields using platform specific methods. + let imms = [ + immty_from_uint_checked(mask, __u32_layout)?, // stx_mask + immty_from_uint_checked(0u128, __u32_layout)?, // stx_blksize + immty_from_uint_checked(0u128, __u64_layout)?, // stx_attributes + immty_from_uint_checked(0u128, __u32_layout)?, // stx_nlink + immty_from_uint_checked(0u128, __u32_layout)?, // stx_uid + immty_from_uint_checked(0u128, __u32_layout)?, // stx_gid + immty_from_uint_checked(mode, __u16_layout)?, // stx_mode + immty_from_uint_checked(0u128, __u16_layout)?, // statx padding + immty_from_uint_checked(0u128, __u64_layout)?, // stx_ino + immty_from_uint_checked(size, __u64_layout)?, // stx_size + immty_from_uint_checked(0u128, __u64_layout)?, // stx_blocks + immty_from_uint_checked(0u128, __u64_layout)?, // stx_attributes + immty_from_uint_checked(access_sec, __u64_layout)?, // stx_atime.tv_sec + immty_from_uint_checked(access_nsec, __u32_layout)?, // stx_atime.tv_nsec + immty_from_uint_checked(0u128, __u32_layout)?, // statx_timestamp padding + immty_from_uint_checked(created_sec, __u64_layout)?, // stx_btime.tv_sec + immty_from_uint_checked(created_nsec, __u32_layout)?, // stx_btime.tv_nsec + immty_from_uint_checked(0u128, __u32_layout)?, // statx_timestamp padding + immty_from_uint_checked(0u128, __u64_layout)?, // stx_ctime.tv_sec + immty_from_uint_checked(0u128, __u32_layout)?, // stx_ctime.tv_nsec + immty_from_uint_checked(0u128, __u32_layout)?, // statx_timestamp padding + immty_from_uint_checked(modified_sec, __u64_layout)?, // stx_mtime.tv_sec + immty_from_uint_checked(modified_nsec, __u32_layout)?, // stx_mtime.tv_nsec + immty_from_uint_checked(0u128, __u32_layout)?, // statx_timestamp padding + immty_from_uint_checked(0u128, __u64_layout)?, // stx_rdev_major + immty_from_uint_checked(0u128, __u64_layout)?, // stx_rdev_minor + immty_from_uint_checked(0u128, __u64_layout)?, // stx_dev_major + immty_from_uint_checked(0u128, __u64_layout)?, // stx_dev_minor + ]; + + this.write_packed_immediates(&statxbuf_place, &imms)?; + + Ok(0) + } + /// Function used when a handle is not found inside `FileHandler`. It returns `Ok(-1)`and sets /// the last OS error to `libc::EBADF` (invalid file descriptor). This function uses /// `T: From` instead of `i32` directly because some fs functions return different integer @@ -268,3 +447,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok((-1).into()) } } + +// Extracts the number of seconds and nanoseconds elapsed between `time` and the unix epoch, and +// then sets the `mask` bits determined by `flag` when `time` is Ok. If `time` is an error, it +// returns `(0, 0)` without setting any bits. +fn extract_sec_and_nsec<'tcx>(time: std::io::Result, mask: &mut u32, flag: u32) -> InterpResult<'tcx, (u64, u32)> { + if let Ok(time) = time { + let duration = system_time_to_duration(&time)?; + *mask |= flag; + Ok((duration.as_secs(), duration.subsec_nanos())) + } else { + Ok((0, 0)) + } +} diff --git a/src/shims/time.rs b/src/shims/time.rs index d75cb7bad3845..da9ea07c4f257 100644 --- a/src/shims/time.rs +++ b/src/shims/time.rs @@ -1,34 +1,19 @@ use std::time::{Duration, SystemTime}; -use rustc::ty::layout::TyLayout; - use crate::stacked_borrows::Tag; use crate::*; +use helpers::immty_from_int_checked; -// Returns the time elapsed between now and the unix epoch as a `Duration` and the sign of the time -// interval +// Returns the time elapsed between now and the unix epoch as a `Duration`. fn get_time<'tcx>() -> InterpResult<'tcx, Duration> { - SystemTime::now() - .duration_since(SystemTime::UNIX_EPOCH) - .map_err(|_| err_unsup_format!("Times before the Unix epoch are not supported").into()) + system_time_to_duration(&SystemTime::now()) } -fn int_to_immty_checked<'tcx>( - int: i128, - layout: TyLayout<'tcx>, -) -> InterpResult<'tcx, ImmTy<'tcx, Tag>> { - // If `int` does not fit in `size` bits, we error instead of letting - // `ImmTy::from_int` panic. - let size = layout.size; - let truncated = truncate(int as u128, size); - if sign_extend(truncated, size) as i128 != int { - throw_unsup_format!( - "Signed value {:#x} does not fit in {} bits", - int, - size.bits() - ) - } - Ok(ImmTy::from_int(int, layout)) +// Returns the time elapsed between the provided time and the unix epoch as a `Duration`. +pub fn system_time_to_duration<'tcx>(time: &SystemTime) -> InterpResult<'tcx, Duration> { + time + .duration_since(SystemTime::UNIX_EPOCH) + .map_err(|_| err_unsup_format!("Times before the Unix epoch are not supported").into()) } impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} @@ -57,8 +42,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let tv_nsec = duration.subsec_nanos() as i128; let imms = [ - int_to_immty_checked(tv_sec, this.libc_ty_layout("time_t")?)?, - int_to_immty_checked(tv_nsec, this.libc_ty_layout("c_long")?)?, + immty_from_int_checked(tv_sec, this.libc_ty_layout("time_t")?)?, + immty_from_int_checked(tv_nsec, this.libc_ty_layout("c_long")?)?, ]; this.write_packed_immediates(&tp, &imms)?; @@ -89,8 +74,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let tv_usec = duration.subsec_micros() as i128; let imms = [ - int_to_immty_checked(tv_sec, this.libc_ty_layout("time_t")?)?, - int_to_immty_checked(tv_usec, this.libc_ty_layout("suseconds_t")?)?, + immty_from_int_checked(tv_sec, this.libc_ty_layout("time_t")?)?, + immty_from_int_checked(tv_usec, this.libc_ty_layout("suseconds_t")?)?, ]; this.write_packed_immediates(&tv, &imms)?; diff --git a/tests/run-pass/fs.rs b/tests/run-pass/fs.rs index 7765e5b368e80..b8f9e3229af67 100644 --- a/tests/run-pass/fs.rs +++ b/tests/run-pass/fs.rs @@ -2,11 +2,32 @@ // compile-flags: -Zmiri-disable-isolation use std::fs::{File, remove_file}; -use std::io::{Read, Write, ErrorKind}; +use std::io::{Read, Write, ErrorKind, Result}; +use std::path::{PathBuf, Path}; + +#[cfg(target_os = "linux")] +fn test_metadata(bytes: &[u8], path: &Path) -> Result<()> { + // Test that the file metadata is correct. + let metadata = path.metadata()?; + // `path` should point to a file. + assert!(metadata.is_file()); + // The size of the file must be equal to the number of written bytes. + assert_eq!(bytes.len() as u64, metadata.len()); + Ok(()) +} + +// FIXME: Implement stat64 for macos. +#[cfg(not(target_os = "linux"))] +fn test_metadata(_bytes: &[u8], _path: &Path) -> Result<()> { + Ok(()) +} fn main() { - let path = std::env::temp_dir().join("miri_test_fs.txt"); + let tmp = std::env::temp_dir(); + let filename = PathBuf::from("miri_test_fs.txt"); + let path = tmp.join(&filename); let bytes = b"Hello, World!\n"; + // Test creating, writing and closing a file (closing is tested when `file` is dropped). let mut file = File::create(&path).unwrap(); // Writing 0 bytes should not change the file contents. @@ -21,7 +42,14 @@ fn main() { // Reading until EOF should get the whole text. file.read_to_end(&mut contents).unwrap(); assert_eq!(bytes, contents.as_slice()); - // Removing file should succeed + + // Test that metadata of an absolute path is correct. + test_metadata(bytes, &path).unwrap(); + // Test that metadata of a relative path is correct. + std::env::set_current_dir(tmp).unwrap(); + test_metadata(bytes, &filename).unwrap(); + + // Removing file should succeed. remove_file(&path).unwrap(); // The two following tests also check that the `__errno_location()` shim is working properly. @@ -29,4 +57,8 @@ fn main() { assert_eq!(ErrorKind::NotFound, File::open(&path).unwrap_err().kind()); // Removing a non-existing file should fail with a "not found" error. assert_eq!(ErrorKind::NotFound, remove_file(&path).unwrap_err().kind()); + // Reading the metadata of a non-existing file should fail with a "not found" error. + if cfg!(target_os = "linux") { // FIXME: Implement stat64 for macos. + assert_eq!(ErrorKind::NotFound, test_metadata(bytes, &path).unwrap_err().kind()); + } } From bc715cb6469015012a3d77dbd84a648c9380873e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 22 Dec 2019 18:13:13 +0100 Subject: [PATCH 1414/3747] disable sysroot checks for distributed binaries --- src/bin/cargo-miri.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index f4fb13518e305..e5c7228600914 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -148,10 +148,11 @@ fn test_sysroot_consistency() { .unwrap_or_else(|_| panic!("Failed to canonicalize sysroot: {}", stdout)) } - // We let the user skip this check if they really want to. - // (`bootstrap` needs this because Miri gets built by the stage1 compiler - // but run with the stage2 sysroot.) - if std::env::var("MIRI_SKIP_SYSROOT_CHECK").is_ok() { + // Do not check sysroots if we got built as part of a Rust distribution. + // During `bootstrap`, the sysroot does not match anyway, and then some distros + // play symlink tricks so the sysroots may be different even for the final stage + // (see ). + if option_env!("RUSTC_STAGE").is_some() { return; } From 7ead530841a7c16d2228504978a7ab34e08d0b40 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Mon, 23 Dec 2019 12:56:23 +0100 Subject: [PATCH 1415/3747] Rustfmt all the things --- benches/fibonacci.rs | 4 +- benches/helpers/miri_helper.rs | 25 ++- benches/smoke.rs | 2 +- rustfmt.toml | 3 + src/bin/cargo-miri.rs | 195 ++++++++++++----------- src/bin/miri-rustc-tests.rs | 91 +++++++---- src/bin/miri.rs | 70 +++++---- src/eval.rs | 50 +++--- src/helpers.rs | 140 ++++++++--------- src/intptrcast.rs | 19 ++- src/lib.rs | 48 +++--- src/machine.rs | 35 ++--- src/mono_hash_map.rs | 33 ++-- src/operator.rs | 38 ++--- src/range_map.rs | 206 ++++++++++++------------- src/shims/dlsym.rs | 3 +- src/shims/foreign_items.rs | 160 +++++++++++-------- src/shims/fs.rs | 94 ++++++------ src/shims/intrinsics.rs | 273 ++++++++++++++++++--------------- src/shims/mod.rs | 27 ++-- src/shims/panic.rs | 26 ++-- src/shims/time.rs | 5 +- src/shims/tls.rs | 21 +-- src/stacked_borrows.rs | 193 ++++++++++------------- tests/compiletest.rs | 34 ++-- 25 files changed, 901 insertions(+), 894 deletions(-) create mode 100644 rustfmt.toml diff --git a/benches/fibonacci.rs b/benches/fibonacci.rs index 10c119d9017ab..ebb1b5fd0b185 100644 --- a/benches/fibonacci.rs +++ b/benches/fibonacci.rs @@ -7,7 +7,7 @@ use crate::helpers::*; #[bench] fn fib(bencher: &mut Bencher) { - bencher.iter(|| { fibonacci_helper::main(); }) + bencher.iter(|| fibonacci_helper::main()) } #[bench] @@ -17,7 +17,7 @@ fn fib_miri(bencher: &mut Bencher) { #[bench] fn fib_iter(bencher: &mut Bencher) { - bencher.iter(|| { fibonacci_helper_iterative::main(); }) + bencher.iter(|| fibonacci_helper_iterative::main()) } #[bench] diff --git a/benches/helpers/miri_helper.rs b/benches/helpers/miri_helper.rs index e2951110acdf9..92aedcc4244a9 100644 --- a/benches/helpers/miri_helper.rs +++ b/benches/helpers/miri_helper.rs @@ -6,23 +6,26 @@ extern crate rustc_interface; extern crate test; use self::miri::eval_main; +use crate::test::Bencher; use rustc::hir::def_id::LOCAL_CRATE; -use rustc_interface::{interface, Queries}; use rustc_driver::Compilation; -use crate::test::Bencher; +use rustc_interface::{interface, Queries}; struct MiriCompilerCalls<'a> { bencher: &'a mut Bencher, } impl rustc_driver::Callbacks for MiriCompilerCalls<'_> { - fn after_analysis<'tcx>(&mut self, compiler: &interface::Compiler, queries: &'tcx Queries<'tcx>) -> Compilation { + fn after_analysis<'tcx>( + &mut self, + compiler: &interface::Compiler, + queries: &'tcx Queries<'tcx>, + ) -> Compilation { compiler.session().abort_if_errors(); queries.global_ctxt().unwrap().peek_mut().enter(|tcx| { - let (entry_def_id, _) = tcx.entry_fn(LOCAL_CRATE).expect( - "no main or start function found", - ); + let (entry_def_id, _) = + tcx.entry_fn(LOCAL_CRATE).expect("no main or start function found"); self.bencher.iter(|| { let config = miri::MiriConfig { @@ -50,13 +53,9 @@ fn find_sysroot() -> String { let toolchain = option_env!("RUSTUP_TOOLCHAIN").or(option_env!("MULTIRUST_TOOLCHAIN")); match (home, toolchain) { (Some(home), Some(toolchain)) => format!("{}/toolchains/{}", home, toolchain), - _ => { - option_env!("RUST_SYSROOT") - .expect( - "need to specify RUST_SYSROOT env var or use rustup or multirust", - ) - .to_owned() - } + _ => option_env!("RUST_SYSROOT") + .expect("need to specify RUST_SYSROOT env var or use rustup or multirust") + .to_owned(), } } diff --git a/benches/smoke.rs b/benches/smoke.rs index 7d614e2682988..9229e972d7f3b 100644 --- a/benches/smoke.rs +++ b/benches/smoke.rs @@ -7,7 +7,7 @@ use crate::helpers::*; #[bench] fn noop(bencher: &mut Bencher) { - bencher.iter(|| { smoke_helper::main(); }) + bencher.iter(|| smoke_helper::main()) } /* diff --git a/rustfmt.toml b/rustfmt.toml new file mode 100644 index 0000000000000..a0d494b335a88 --- /dev/null +++ b/rustfmt.toml @@ -0,0 +1,3 @@ +use_small_heuristics = "Max" +version = "Two" +match_arm_blocks = false diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index f4fb13518e305..955167bc425db 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -1,10 +1,10 @@ #![feature(inner_deref)] use std::fs::{self, File}; -use std::io::{self, Write, BufRead}; -use std::path::{PathBuf, Path}; -use std::process::Command; +use std::io::{self, BufRead, Write}; use std::ops::Not; +use std::path::{Path, PathBuf}; +use std::process::Command; const XARGO_MIN_VERSION: (u32, u32, u32) = (0, 3, 17); @@ -40,8 +40,12 @@ fn show_help() { } fn show_version() { - println!("miri {} ({} {})", - env!("CARGO_PKG_VERSION"), env!("VERGEN_SHA_SHORT"), env!("VERGEN_COMMIT_DATE")); + println!( + "miri {} ({} {})", + env!("CARGO_PKG_VERSION"), + env!("VERGEN_SHA_SHORT"), + env!("VERGEN_COMMIT_DATE") + ); } fn show_error(msg: String) -> ! { @@ -80,11 +84,10 @@ fn get_arg_flag_value(name: &str) -> Option { } } -fn list_targets() -> impl Iterator { +fn list_targets() -> impl Iterator { // We need to get the manifest, and then the metadata, to enumerate targets. - let manifest_path = get_arg_flag_value("--manifest-path").map(|m| - Path::new(&m).canonicalize().unwrap() - ); + let manifest_path = + get_arg_flag_value("--manifest-path").map(|m| Path::new(&m).canonicalize().unwrap()); let mut cmd = cargo_metadata::MetadataCommand::new(); if let Some(ref manifest_path) = manifest_path { @@ -106,16 +109,18 @@ fn list_targets() -> impl Iterator { if let Some(ref manifest_path) = manifest_path { package_manifest_path == manifest_path } else { - let current_dir = current_dir.as_ref().expect( - "could not read current directory", - ); - let package_manifest_directory = package_manifest_path.parent().expect( - "could not find parent directory of package manifest", - ); + let current_dir = current_dir.as_ref().expect("could not read current directory"); + let package_manifest_directory = package_manifest_path + .parent() + .expect("could not find parent directory of package manifest"); package_manifest_directory == current_dir } }) - .unwrap_or_else(|| show_error(format!("This seems to be a workspace, which is not supported by cargo-miri"))); + .unwrap_or_else(|| { + show_error(format!( + "This seems to be a workspace, which is not supported by cargo-miri" + )) + }); let package = metadata.packages.remove(package_index); // Finally we got the list of targets to build @@ -134,17 +139,24 @@ fn find_miri() -> PathBuf { /// toolchain than what is used when `cargo miri` is run. fn test_sysroot_consistency() { fn get_sysroot(mut cmd: Command) -> PathBuf { - let out = cmd.arg("--print").arg("sysroot") - .output().expect("Failed to run rustc to get sysroot info"); + let out = cmd + .arg("--print") + .arg("sysroot") + .output() + .expect("Failed to run rustc to get sysroot info"); let stdout = String::from_utf8(out.stdout).expect("stdout is not valid UTF-8"); let stderr = String::from_utf8(out.stderr).expect("stderr is not valid UTF-8"); assert!( out.status.success(), "Bad status code {} when getting sysroot info via {:?}.\nstdout:\n{}\nstderr:\n{}", - out.status, cmd, stdout, stderr, + out.status, + cmd, + stdout, + stderr, ); let stdout = stdout.trim(); - PathBuf::from(stdout).canonicalize() + PathBuf::from(stdout) + .canonicalize() .unwrap_or_else(|_| panic!("Failed to canonicalize sysroot: {}", stdout)) } @@ -164,7 +176,8 @@ fn test_sysroot_consistency() { Make sure you use the same toolchain to run miri that you used to build it!\n\ rustc sysroot: `{}`\n\ miri sysroot: `{}`", - rustc_sysroot.display(), miri_sysroot.display() + rustc_sysroot.display(), + miri_sysroot.display() )); } } @@ -193,28 +206,36 @@ fn xargo_version() -> Option<(u32, u32, u32)> { return None; } // Parse output. The first line looks like "xargo 0.3.12 (b004f1c 2018-12-13)". - let line = out.stderr.lines().nth(0) + let line = out + .stderr + .lines() + .nth(0) .expect("malformed `xargo --version` output: not at least one line") .expect("malformed `xargo --version` output: error reading first line"); let (name, version) = { let mut split = line.split(' '); - (split.next().expect("malformed `xargo --version` output: empty"), - split.next().expect("malformed `xargo --version` output: not at least two words")) + ( + split.next().expect("malformed `xargo --version` output: empty"), + split.next().expect("malformed `xargo --version` output: not at least two words"), + ) }; if name != "xargo" { // This is some fork of xargo return None; } let mut version_pieces = version.split('.'); - let major = version_pieces.next() + let major = version_pieces + .next() .expect("malformed `xargo --version` output: not a major version piece") .parse() .expect("malformed `xargo --version` output: major version is not an integer"); - let minor = version_pieces.next() + let minor = version_pieces + .next() .expect("malformed `xargo --version` output: not a minor version piece") .parse() .expect("malformed `xargo --version` output: minor version is not an integer"); - let patch = version_pieces.next() + let patch = version_pieces + .next() .expect("malformed `xargo --version` output: not a patch version piece") .parse() .expect("malformed `xargo --version` output: patch version is not an integer"); @@ -232,18 +253,15 @@ fn ask_to_run(mut cmd: Command, ask: bool, text: &str) { io::stdin().read_line(&mut buf).unwrap(); match buf.trim().to_lowercase().as_ref() { // Proceed. - "" | "y" | "yes" => {}, + "" | "y" | "yes" => {} "n" | "no" => show_error(format!("Aborting as per your request")), - a => show_error(format!("I do not understand `{}`", a)) + a => show_error(format!("I do not understand `{}`", a)), }; } else { println!("Running `{:?}` to {}.", cmd, text); } - if cmd.status() - .expect(&format!("failed to execute {:?}", cmd)) - .success().not() - { + if cmd.status().expect(&format!("failed to execute {:?}", cmd)).success().not() { show_error(format!("Failed to {}", text)); } } @@ -275,7 +293,9 @@ fn setup(ask_user: bool) { Ok(val) => PathBuf::from(val), Err(_) => { // Check for `rust-src` rustup component. - let sysroot = Command::new("rustc").args(&["--print", "sysroot"]).output() + let sysroot = Command::new("rustc") + .args(&["--print", "sysroot"]) + .output() .expect("failed to get rustc sysroot") .stdout; let sysroot = std::str::from_utf8(&sysroot).unwrap(); @@ -298,7 +318,11 @@ fn setup(ask_user: bool) { // Fallback: Ask the user to install the `rust-src` component, and use that. let mut cmd = Command::new("rustup"); cmd.args(&["component", "add", "rust-src"]); - ask_to_run(cmd, ask_user, "install the rustc-src component for the selected toolchain"); + ask_to_run( + cmd, + ask_user, + "install the rustc-src component for the selected toolchain", + ); rustup_src } } @@ -317,8 +341,10 @@ fn setup(ask_user: bool) { fs::create_dir_all(&dir).unwrap(); } // The interesting bit: Xargo.toml - File::create(dir.join("Xargo.toml")).unwrap() - .write_all(br#" + File::create(dir.join("Xargo.toml")) + .unwrap() + .write_all( + br#" [dependencies.std] default_features = false # We need the `panic_unwind` feature because we use the `unwind` panic strategy. @@ -326,10 +352,14 @@ default_features = false features = ["panic_unwind"] [dependencies.test] - "#).unwrap(); + "#, + ) + .unwrap(); // The boring bits: a dummy project for xargo. - File::create(dir.join("Cargo.toml")).unwrap() - .write_all(br#" + File::create(dir.join("Cargo.toml")) + .unwrap() + .write_all( + br#" [package] name = "miri-xargo" description = "A dummy project for building libstd with xargo." @@ -337,7 +367,9 @@ version = "0.0.0" [lib] path = "lib.rs" - "#).unwrap(); + "#, + ) + .unwrap(); File::create(dir.join("lib.rs")).unwrap(); // Prepare xargo invocation. let target = get_arg_flag_value("--target"); @@ -355,10 +387,7 @@ path = "lib.rs" command.arg("--target").arg(&target); } // Finally run it! - if command.status() - .expect("failed to run xargo") - .success().not() - { + if command.status().expect("failed to run xargo").success().not() { show_error(format!("Failed to run xargo")); } @@ -413,9 +442,7 @@ fn in_cargo_miri() { Some(s) if s.starts_with("-") => (MiriCommand::Run, 2), None => (MiriCommand::Run, 2), // Invalid command. - Some(s) => { - show_error(format!("Unknown command `{}`", s)) - } + Some(s) => show_error(format!("Unknown command `{}`", s)), }; let verbose = has_arg_flag("-v"); @@ -433,9 +460,10 @@ fn in_cargo_miri() { // Now run the command. for target in list_targets() { let mut args = std::env::args().skip(skip); - let kind = target.kind.get(0).expect( - "badly formatted cargo metadata: target::kind is an empty array", - ); + let kind = target + .kind + .get(0) + .expect("badly formatted cargo metadata: target::kind is an empty array"); // Now we run `cargo rustc $FLAGS $ARGS`, giving the user the // change to add additional arguments. `FLAGS` is set to identify // this target. The user gets to control what gets actually passed to Miri. @@ -470,22 +498,15 @@ fn in_cargo_miri() { // Add `--` (to end the `cargo` flags), and then the user flags. We add markers around the // user flags to be able to identify them later. "cargo rustc" adds more stuff after this, // so we have to mark both the beginning and the end. - cmd - .arg("--") - .arg("cargo-miri-marker-begin") - .args(args) - .arg("cargo-miri-marker-end"); + cmd.arg("--").arg("cargo-miri-marker-begin").args(args).arg("cargo-miri-marker-end"); let path = std::env::current_exe().expect("current executable path invalid"); cmd.env("RUSTC_WRAPPER", path); if verbose { eprintln!("+ {:?}", cmd); } - let exit_status = cmd - .spawn() - .expect("could not run cargo") - .wait() - .expect("failed to wait for cargo?"); + let exit_status = + cmd.spawn().expect("could not run cargo").wait().expect("failed to wait for cargo?"); if !exit_status.success() { std::process::exit(exit_status.code().unwrap_or(-1)) @@ -497,49 +518,43 @@ fn inside_cargo_rustc() { let sysroot = std::env::var("MIRI_SYSROOT").expect("The wrapper should have set MIRI_SYSROOT"); let rustc_args = std::env::args().skip(2); // skip `cargo rustc` - let mut args: Vec = rustc_args - .chain(Some("--sysroot".to_owned())) - .chain(Some(sysroot)) - .collect(); + let mut args: Vec = + rustc_args.chain(Some("--sysroot".to_owned())).chain(Some(sysroot)).collect(); args.splice(0..0, miri::miri_default_args().iter().map(ToString::to_string)); // See if we can find the `cargo-miri` markers. Those only get added to the binary we want to // run. They also serve to mark the user-defined arguments, which we have to move all the way // to the end (they get added somewhere in the middle). - let needs_miri = if let Some(begin) = args.iter().position(|arg| arg == "cargo-miri-marker-begin") { - let end = args - .iter() - .position(|arg| arg == "cargo-miri-marker-end") - .expect("cannot find end marker"); - // These mark the user arguments. We remove the first and last as they are the markers. - let mut user_args = args.drain(begin..=end); - assert_eq!(user_args.next().unwrap(), "cargo-miri-marker-begin"); - assert_eq!(user_args.next_back().unwrap(), "cargo-miri-marker-end"); - // Collect the rest and add it back at the end. - let mut user_args = user_args.collect::>(); - args.append(&mut user_args); - // Run this in Miri. - true - } else { - false - }; + let needs_miri = + if let Some(begin) = args.iter().position(|arg| arg == "cargo-miri-marker-begin") { + let end = args + .iter() + .position(|arg| arg == "cargo-miri-marker-end") + .expect("cannot find end marker"); + // These mark the user arguments. We remove the first and last as they are the markers. + let mut user_args = args.drain(begin..=end); + assert_eq!(user_args.next().unwrap(), "cargo-miri-marker-begin"); + assert_eq!(user_args.next_back().unwrap(), "cargo-miri-marker-end"); + // Collect the rest and add it back at the end. + let mut user_args = user_args.collect::>(); + args.append(&mut user_args); + // Run this in Miri. + true + } else { + false + }; - let mut command = if needs_miri { - Command::new(find_miri()) - } else { - Command::new("rustc") - }; + let mut command = if needs_miri { Command::new(find_miri()) } else { Command::new("rustc") }; command.args(&args); if has_arg_flag("-v") { eprintln!("+ {:?}", command); } match command.status() { - Ok(exit) => { + Ok(exit) => if !exit.success() { std::process::exit(exit.code().unwrap_or(42)); - } - } + }, Err(ref e) if needs_miri => panic!("error during miri run: {:?}", e), Err(ref e) => panic!("error during rustc call: {:?}", e), } diff --git a/src/bin/miri-rustc-tests.rs b/src/bin/miri-rustc-tests.rs index 370d2a206178e..19816fe008f5d 100644 --- a/src/bin/miri-rustc-tests.rs +++ b/src/bin/miri-rustc-tests.rs @@ -1,25 +1,24 @@ #![feature(rustc_private)] -extern crate miri; extern crate getopts; +extern crate miri; extern crate rustc; -extern crate rustc_metadata; +extern crate rustc_codegen_utils; extern crate rustc_driver; extern crate rustc_errors; -extern crate rustc_codegen_utils; extern crate rustc_interface; +extern crate rustc_metadata; extern crate syntax; -use std::path::Path; -use std::io::Write; -use std::sync::{Mutex, Arc}; use std::io; +use std::io::Write; +use std::path::Path; +use std::sync::{Arc, Mutex}; - -use rustc_interface::{interface, Queries}; +use rustc::hir::def_id::LOCAL_CRATE; use rustc::hir::{self, itemlikevisit}; use rustc::ty::TyCtxt; -use rustc::hir::def_id::LOCAL_CRATE; use rustc_driver::Compilation; +use rustc_interface::{interface, Queries}; use miri::MiriConfig; @@ -29,7 +28,11 @@ struct MiriCompilerCalls { } impl rustc_driver::Callbacks for MiriCompilerCalls { - fn after_analysis<'tcx>(&mut self, compiler: &interface::Compiler, queries: &'tcx Queries<'tcx>) -> Compilation { + fn after_analysis<'tcx>( + &mut self, + compiler: &interface::Compiler, + queries: &'tcx Queries<'tcx>, + ) -> Compilation { compiler.session().abort_if_errors(); queries.global_ctxt().unwrap().peek_mut().enter(|tcx| { if std::env::args().any(|arg| arg == "--test") { @@ -37,7 +40,8 @@ impl rustc_driver::Callbacks for MiriCompilerCalls { impl<'tcx, 'hir> itemlikevisit::ItemLikeVisitor<'hir> for Visitor<'tcx> { fn visit_item(&mut self, i: &'hir hir::Item) { if let hir::ItemKind::Fn(.., body_id) = i.kind { - if i.attrs.iter().any(|attr| attr.check_name(syntax::symbol::sym::test)) { + if i.attrs.iter().any(|attr| attr.check_name(syntax::symbol::sym::test)) + { let config = MiriConfig { validate: true, communicate: false, @@ -82,12 +86,10 @@ impl rustc_driver::Callbacks for MiriCompilerCalls { } fn main() { - let path = option_env!("MIRI_RUSTC_TEST") - .map(String::from) - .unwrap_or_else(|| { - std::env::var("MIRI_RUSTC_TEST") - .expect("need to set MIRI_RUSTC_TEST to path of rustc tests") - }); + let path = option_env!("MIRI_RUSTC_TEST").map(String::from).unwrap_or_else(|| { + std::env::var("MIRI_RUSTC_TEST") + .expect("need to set MIRI_RUSTC_TEST to path of rustc tests") + }); let mut mir_not_found = Vec::new(); let mut crate_not_found = Vec::new(); @@ -115,14 +117,16 @@ fn main() { let stderr = std::io::stderr(); write!(stderr.lock(), "test [miri-pass] {} ... ", path.display()).unwrap(); let mut host_target = false; - let mut args: Vec = 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(); + let mut args: Vec = 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(); args.splice(1..1, miri::miri_default_args().iter().map(ToString::to_string)); // file to process args.push(path.display().to_string()); @@ -130,7 +134,13 @@ fn main() { let sysroot_flag = String::from("--sysroot"); if !args.contains(&sysroot_flag) { args.push(sysroot_flag); - args.push(Path::new(&std::env::var("HOME").unwrap()).join(".xargo").join("HOST").display().to_string()); + args.push( + Path::new(&std::env::var("HOME").unwrap()) + .join(".xargo") + .join("HOST") + .display() + .to_string(), + ); } // A threadsafe buffer for writing. @@ -148,14 +158,19 @@ fn main() { let buf = BufWriter::default(); let output = buf.clone(); let result = std::panic::catch_unwind(|| { - let _ = rustc_driver::run_compiler(&args, &mut MiriCompilerCalls { host_target }, None, Some(Box::new(buf))); + let _ = rustc_driver::run_compiler( + &args, + &mut MiriCompilerCalls { host_target }, + None, + Some(Box::new(buf)), + ); }); match result { Ok(()) => { success += 1; writeln!(stderr.lock(), "ok").unwrap() - }, + } Err(_) => { let output = output.0.lock().unwrap(); let output_err = std::str::from_utf8(&output).unwrap(); @@ -178,7 +193,8 @@ fn main() { if text.starts_with(c_abi) { c_abi_fns.push(text[c_abi.len()..end].to_string()); } else if text.starts_with(unimplemented_intrinsic_s) { - unimplemented_intrinsic.push(text[unimplemented_intrinsic_s.len()..end].to_string()); + unimplemented_intrinsic + .push(text[unimplemented_intrinsic_s.len()..end].to_string()); } else if text.starts_with(unsupported_s) { unsupported.push(text[unsupported_s.len()..end].to_string()); } else if text.starts_with(abi_s) { @@ -196,10 +212,19 @@ fn main() { } let stderr = std::io::stderr(); let mut stderr = stderr.lock(); - writeln!(stderr, "{} success, {} no mir, {} crate not found, {} failed, \ - {} C fn, {} ABI, {} unsupported, {} intrinsic", - success, mir_not_found.len(), crate_not_found.len(), failed.len(), - c_abi_fns.len(), abi.len(), unsupported.len(), unimplemented_intrinsic.len()).unwrap(); + writeln!( + stderr, + "{} success, {} no mir, {} crate not found, {} failed, {} C fn, {} ABI, {} unsupported, {} intrinsic", + success, + mir_not_found.len(), + crate_not_found.len(), + failed.len(), + c_abi_fns.len(), + abi.len(), + unsupported.len(), + unimplemented_intrinsic.len() + ) + .unwrap(); writeln!(stderr, "# The \"other reasons\" errors").unwrap(); writeln!(stderr, "(sorted, deduplicated)").unwrap(); print_vec(&mut stderr, failed); diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 48af812962575..1af79b259613d 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -7,29 +7,33 @@ extern crate log; extern crate log_settings; extern crate miri; extern crate rustc; -extern crate rustc_metadata; +extern crate rustc_codegen_utils; extern crate rustc_driver; extern crate rustc_errors; -extern crate rustc_codegen_utils; extern crate rustc_interface; +extern crate rustc_metadata; extern crate syntax; -use std::str::FromStr; use std::convert::TryFrom; use std::env; +use std::str::FromStr; use hex::FromHexError; -use rustc_interface::{interface, Queries}; use rustc::hir::def_id::LOCAL_CRATE; use rustc_driver::Compilation; +use rustc_interface::{interface, Queries}; struct MiriCompilerCalls { miri_config: miri::MiriConfig, } impl rustc_driver::Callbacks for MiriCompilerCalls { - fn after_analysis<'tcx>(&mut self, compiler: &interface::Compiler, queries: &'tcx Queries<'tcx>) -> Compilation { + fn after_analysis<'tcx>( + &mut self, + compiler: &interface::Compiler, + queries: &'tcx Queries<'tcx>, + ) -> Compilation { init_late_loggers(); compiler.session().abort_if_errors(); @@ -41,7 +45,9 @@ impl rustc_driver::Callbacks for MiriCompilerCalls { config.args.insert(0, compiler.input().filestem().to_string()); if let Some(return_code) = miri::eval_main(tcx, entry_def_id, config) { - std::process::exit(i32::try_from(return_code).expect("Return value was too large!")); + std::process::exit( + i32::try_from(return_code).expect("Return value was too large!"), + ); } }); @@ -76,8 +82,10 @@ fn init_late_loggers() { // This way, if you set `MIRI_LOG=trace`, you get only the right parts of // rustc traced, but you can also do `MIRI_LOG=miri=trace,rustc_mir::interpret=debug`. if log::Level::from_str(&var).is_ok() { - env::set_var("RUSTC_LOG", - &format!("rustc::mir::interpret={0},rustc_mir::interpret={0}", var)); + env::set_var( + "RUSTC_LOG", + &format!("rustc::mir::interpret={0},rustc_mir::interpret={0}", var), + ); } else { env::set_var("RUSTC_LOG", &var); } @@ -110,11 +118,9 @@ fn compile_time_sysroot() -> Option { let toolchain = option_env!("RUSTUP_TOOLCHAIN").or(option_env!("MULTIRUST_TOOLCHAIN")); Some(match (home, toolchain) { (Some(home), Some(toolchain)) => format!("{}/toolchains/{}", home, toolchain), - _ => { - option_env!("RUST_SYSROOT") - .expect("To build Miri without rustup, set the `RUST_SYSROOT` env var at build time") - .to_owned() - } + _ => option_env!("RUST_SYSROOT") + .expect("To build Miri without rustup, set the `RUST_SYSROOT` env var at build time") + .to_owned(), }) } @@ -135,21 +141,20 @@ fn main() { if rustc_args.is_empty() { // Very first arg: for `rustc`. rustc_args.push(arg); - } - else if after_dashdash { + } else if after_dashdash { // Everything that comes after are `miri` args. miri_args.push(arg); } else { match arg.as_str() { "-Zmiri-disable-validation" => { validate = false; - }, + } "-Zmiri-disable-isolation" => { communicate = true; - }, + } "-Zmiri-ignore-leaks" => { ignore_leaks = true; - }, + } "--" => { after_dashdash = true; } @@ -162,32 +167,40 @@ fn main() { FromHexError::InvalidHexCharacter { .. } => panic!( "-Zmiri-seed should only contain valid hex digits [0-9a-fA-F]" ), - FromHexError::OddLength => panic!("-Zmiri-seed should have an even number of digits"), + FromHexError::OddLength => + panic!("-Zmiri-seed should have an even number of digits"), err => panic!("Unknown error decoding -Zmiri-seed as hex: {:?}", err), }); if seed_raw.len() > 8 { - panic!(format!("-Zmiri-seed must be at most 8 bytes, was {}", seed_raw.len())); + panic!(format!( + "-Zmiri-seed must be at most 8 bytes, was {}", + seed_raw.len() + )); } let mut bytes = [0; 8]; bytes[..seed_raw.len()].copy_from_slice(&seed_raw); seed = Some(u64::from_be_bytes(bytes)); - - }, + } arg if arg.starts_with("-Zmiri-env-exclude=") => { - excluded_env_vars.push(arg.trim_start_matches("-Zmiri-env-exclude=").to_owned()); - }, + excluded_env_vars + .push(arg.trim_start_matches("-Zmiri-env-exclude=").to_owned()); + } arg if arg.starts_with("-Zmiri-track-pointer-tag=") => { - let id: u64 = match arg.trim_start_matches("-Zmiri-track-pointer-tag=").parse() { + let id: u64 = match arg.trim_start_matches("-Zmiri-track-pointer-tag=").parse() + { Ok(id) => id, - Err(err) => panic!("-Zmiri-track-pointer-tag requires a valid `u64` as the argument: {}", err), + Err(err) => panic!( + "-Zmiri-track-pointer-tag requires a valid `u64` as the argument: {}", + err + ), }; if let Some(id) = miri::PtrId::new(id) { tracked_pointer_tag = Some(id); } else { panic!("-Zmiri-track-pointer-tag must be a nonzero id"); } - }, + } _ => { rustc_args.push(arg); } @@ -225,6 +238,7 @@ fn main() { rustc_driver::install_ice_hook(); let result = rustc_driver::catch_fatal_errors(move || { rustc_driver::run_compiler(&rustc_args, &mut MiriCompilerCalls { miri_config }, None, None) - }).and_then(|result| result); + }) + .and_then(|result| result); std::process::exit(result.is_err() as i32); } diff --git a/src/eval.rs b/src/eval.rs index 9a70663716d61..4ed1b272b2288 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -50,7 +50,11 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( tcx.at(syntax::source_map::DUMMY_SP), ty::ParamEnv::reveal_all(), Evaluator::new(config.communicate), - MemoryExtra::new(StdRng::seed_from_u64(config.seed.unwrap_or(0)), config.validate, config.tracked_pointer_tag), + MemoryExtra::new( + StdRng::seed_from_u64(config.seed.unwrap_or(0)), + config.validate, + config.tracked_pointer_tag, + ), ); // Complete initialization. EnvVars::init(&mut ecx, config.excluded_env_vars); @@ -75,9 +79,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( .unwrap(); // First argument: pointer to `main()`. - let main_ptr = ecx - .memory - .create_fn_alloc(FnVal::Instance(main_instance)); + let main_ptr = ecx.memory.create_fn_alloc(FnVal::Instance(main_instance)); // Second argument (argc): length of `config.args`. let argc = Scalar::from_uint(config.args.len() as u128, ecx.pointer_size()); // Third argument (`argv`): created from `config.args`. @@ -93,24 +95,20 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( argvs.push(arg_place.ptr); } // Make an array with all these pointers, in the Miri memory. - let argvs_layout = ecx.layout_of( - tcx.mk_array(tcx.mk_imm_ptr(tcx.types.u8), argvs.len() as u64), - )?; + let argvs_layout = + ecx.layout_of(tcx.mk_array(tcx.mk_imm_ptr(tcx.types.u8), argvs.len() as u64))?; let argvs_place = ecx.allocate(argvs_layout, MiriMemoryKind::Env.into()); for (idx, arg) in argvs.into_iter().enumerate() { let place = ecx.mplace_field(argvs_place, idx as u64)?; ecx.write_scalar(arg, place.into())?; } - ecx.memory - .mark_immutable(argvs_place.ptr.assert_ptr().alloc_id)?; + ecx.memory.mark_immutable(argvs_place.ptr.assert_ptr().alloc_id)?; // A pointer to that place is the 3rd argument for main. let argv = argvs_place.ptr; // Store `argc` and `argv` for macOS `_NSGetArg{c,v}`. { - let argc_place = ecx.allocate( - ecx.layout_of(tcx.types.isize)?, - MiriMemoryKind::Env.into(), - ); + let argc_place = + ecx.allocate(ecx.layout_of(tcx.types.isize)?, MiriMemoryKind::Env.into()); ecx.write_scalar(argc, argc_place.into())?; ecx.machine.argc = Some(argc_place.ptr); @@ -149,10 +147,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( }; // Return place (in static memory so that it does not count as leak). - let ret_place = ecx.allocate( - ecx.layout_of(tcx.types.isize)?, - MiriMemoryKind::Env.into(), - ); + let ret_place = ecx.allocate(ecx.layout_of(tcx.types.isize)?, MiriMemoryKind::Env.into()); // Call start function. ecx.call_function( start_instance, @@ -209,27 +204,30 @@ pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) -> return None; } } - return Some(return_code) + return Some(return_code); } Err(mut e) => { // Special treatment for some error kinds let msg = match e.kind { InterpError::MachineStop(ref info) => { - let info = info.downcast_ref::() + let info = info + .downcast_ref::() .expect("invalid MachineStop payload"); match info { TerminationInfo::Exit(code) => return Some(*code), TerminationInfo::PoppedTrackedPointerTag(item) => format!("popped tracked tag for item {:?}", item), TerminationInfo::Abort => - format!("the evaluated program aborted execution") + format!("the evaluated program aborted execution"), } } - err_unsup!(NoMirFor(..)) => - format!("{}. Did you set `MIRI_SYSROOT` to a Miri-enabled sysroot? You can prepare one with `cargo miri setup`.", e), + err_unsup!(NoMirFor(..)) => format!( + "{}. Did you set `MIRI_SYSROOT` to a Miri-enabled sysroot? You can prepare one with `cargo miri setup`.", + e + ), InterpError::InvalidProgram(_) => bug!("This error should be impossible in Miri: {}", e), - _ => e.to_string() + _ => e.to_string(), }; e.print_backtrace(); if let Some(frame) = ecx.stack().last() { @@ -242,9 +240,9 @@ pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) -> // We iterate with indices because we need to look at the next frame (the caller). for idx in 0..frames.len() { let frame_info = &frames[idx]; - let call_site_is_local = frames.get(idx + 1).map_or(false, |caller_info| { - caller_info.instance.def_id().is_local() - }); + let call_site_is_local = frames + .get(idx + 1) + .map_or(false, |caller_info| caller_info.instance.def_id().is_local()); if call_site_is_local { err.span_note(frame_info.call_site, &frame_info.to_string()); } else { diff --git a/src/helpers.rs b/src/helpers.rs index 5d7db0d126934..b6391ce2fde01 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -1,15 +1,14 @@ -use std::{mem, iter}; use std::ffi::OsStr; +use std::{iter, mem}; -use syntax::source_map::DUMMY_SP; use rustc::hir::def_id::{DefId, CRATE_DEF_INDEX}; use rustc::mir; use rustc::ty::{ self, - List, - TyCtxt, layout::{self, LayoutOf, Size, TyLayout}, + List, TyCtxt, }; +use syntax::source_map::DUMMY_SP; use rand::RngCore; @@ -19,15 +18,11 @@ impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tc /// Gets an instance for a path. fn resolve_did<'mir, 'tcx>(tcx: TyCtxt<'tcx>, path: &[&str]) -> InterpResult<'tcx, DefId> { - tcx - .crates() + tcx.crates() .iter() .find(|&&krate| tcx.original_crate_name(krate).as_str() == path[0]) .and_then(|krate| { - let krate = DefId { - krate: *krate, - index: CRATE_DEF_INDEX, - }; + let krate = DefId { krate: *krate, index: CRATE_DEF_INDEX }; let mut items = tcx.item_children(krate); let mut path_it = path.iter().skip(1).peekable(); @@ -35,7 +30,7 @@ fn resolve_did<'mir, 'tcx>(tcx: TyCtxt<'tcx>, path: &[&str]) -> InterpResult<'tc for item in mem::replace(&mut items, Default::default()).iter() { if item.ident.name.as_str() == *segment { if path_it.peek().is_none() { - return Some(item.res.def_id()) + return Some(item.res.def_id()); } items = tcx.item_children(item.res.def_id()); @@ -51,12 +46,13 @@ fn resolve_did<'mir, 'tcx>(tcx: TyCtxt<'tcx>, path: &[&str]) -> InterpResult<'tc }) } - pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { - /// Gets an instance for a path. fn resolve_path(&self, path: &[&str]) -> InterpResult<'tcx, ty::Instance<'tcx>> { - Ok(ty::Instance::mono(self.eval_context_ref().tcx.tcx, resolve_did(self.eval_context_ref().tcx.tcx, path)?)) + Ok(ty::Instance::mono( + self.eval_context_ref().tcx.tcx, + resolve_did(self.eval_context_ref().tcx.tcx, path)?, + )) } /// Write a 0 of the appropriate size to `dest`. @@ -74,11 +70,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// Turn a Scalar into an Option fn test_null(&self, val: Scalar) -> InterpResult<'tcx, Option>> { let this = self.eval_context_ref(); - Ok(if this.is_null(val)? { - None - } else { - Some(val) - }) + Ok(if this.is_null(val)? { None } else { Some(val) }) } /// Get the `Place` for a local @@ -89,11 +81,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } /// Generate some random bytes, and write them to `dest`. - fn gen_random( - &mut self, - ptr: Scalar, - len: usize, - ) -> InterpResult<'tcx> { + fn gen_random(&mut self, ptr: Scalar, len: usize) -> InterpResult<'tcx> { // Some programs pass in a null pointer and a length of 0 // to their platform's random-generation function (e.g. getrandom()) // on Linux. For compatibility with these programs, we don't perform @@ -110,8 +98,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Fill the buffer using the host's rng. getrandom::getrandom(&mut data) .map_err(|err| err_unsup_format!("getrandom failed: {}", err))?; - } - else { + } else { let rng = this.memory.extra.rng.get_mut(); rng.fill_bytes(&mut data); } @@ -132,23 +119,19 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Push frame. let mir = &*this.load_mir(f.def, None)?; - let span = this.stack().last() + let span = this + .stack() + .last() .and_then(Frame::current_source_info) .map(|si| si.span) .unwrap_or(DUMMY_SP); - this.push_stack_frame( - f, - span, - mir, - dest, - stack_pop, - )?; + this.push_stack_frame(f, span, mir, dest, stack_pop)?; // Initialize arguments. let mut callee_args = this.frame().body.args_iter(); for arg in args { let callee_arg = this.local_place( - callee_args.next().expect("callee has fewer arguments than expected") + callee_args.next().expect("callee has fewer arguments than expected"), )?; this.write_immediate(*arg, callee_arg)?; } @@ -167,10 +150,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx> { let this = self.eval_context_ref(); trace!("visit_frozen(place={:?}, size={:?})", *place, size); - debug_assert_eq!(size, + debug_assert_eq!( + size, this.size_and_align_of_mplace(place)? - .map(|(size, _)| size) - .unwrap_or_else(|| place.layout.size) + .map(|(size, _)| size) + .unwrap_or_else(|| place.layout.size) ); // Store how far we proceeded into the place so far. Everything to the left of // this offset has already been handled, in the sense that the frozen parts @@ -190,11 +174,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let frozen_size = unsafe_cell_offset - end_offset; // Everything between the end_ptr and this `UnsafeCell` is frozen. if frozen_size != Size::ZERO { - action(end_ptr, frozen_size, /*frozen*/true)?; + action(end_ptr, frozen_size, /*frozen*/ true)?; } // This `UnsafeCell` is NOT frozen. if unsafe_cell_size != Size::ZERO { - action(unsafe_cell_ptr, unsafe_cell_size, /*frozen*/false)?; + action(unsafe_cell_ptr, unsafe_cell_size, /*frozen*/ false)?; } // Update end end_ptr. end_ptr = unsafe_cell_ptr.wrapping_offset(unsafe_cell_size, this); @@ -208,7 +192,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx unsafe_cell_action: |place| { trace!("unsafe_cell_action on {:?}", place.ptr); // We need a size to go on. - let unsafe_cell_size = this.size_and_align_of_mplace(place)? + let unsafe_cell_size = this + .size_and_align_of_mplace(place)? .map(|(size, _)| size) // for extern types, just cover what we can .unwrap_or_else(|| place.layout.size); @@ -231,18 +216,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// Visiting the memory covered by a `MemPlace`, being aware of /// whether we are inside an `UnsafeCell` or not. struct UnsafeCellVisitor<'ecx, 'mir, 'tcx, F> - where F: FnMut(MPlaceTy<'tcx, Tag>) -> InterpResult<'tcx> + where + F: FnMut(MPlaceTy<'tcx, Tag>) -> InterpResult<'tcx>, { ecx: &'ecx MiriEvalContext<'mir, 'tcx>, unsafe_cell_action: F, } - impl<'ecx, 'mir, 'tcx, F> - ValueVisitor<'mir, 'tcx, Evaluator<'tcx>> - for - UnsafeCellVisitor<'ecx, 'mir, 'tcx, F> + impl<'ecx, 'mir, 'tcx, F> ValueVisitor<'mir, 'tcx, Evaluator<'tcx>> + for UnsafeCellVisitor<'ecx, 'mir, 'tcx, F> where - F: FnMut(MPlaceTy<'tcx, Tag>) -> InterpResult<'tcx> + F: FnMut(MPlaceTy<'tcx, Tag>) -> InterpResult<'tcx>, { type V = MPlaceTy<'tcx, Tag>; @@ -252,11 +236,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // Hook to detect `UnsafeCell`. - fn visit_value(&mut self, v: MPlaceTy<'tcx, Tag>) -> InterpResult<'tcx> - { + fn visit_value(&mut self, v: MPlaceTy<'tcx, Tag>) -> InterpResult<'tcx> { trace!("UnsafeCellVisitor: {:?} {:?}", *v, v.layout.ty); let is_unsafe_cell = match v.layout.ty.kind { - ty::Adt(adt, _) => Some(adt.did) == self.ecx.tcx.lang_items().unsafe_cell_type(), + ty::Adt(adt, _) => + Some(adt.did) == self.ecx.tcx.lang_items().unsafe_cell_type(), _ => false, }; if is_unsafe_cell { @@ -293,7 +277,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn visit_aggregate( &mut self, place: MPlaceTy<'tcx, Tag>, - fields: impl Iterator>>, + fields: impl Iterator>>, ) -> InterpResult<'tcx> { match place.layout.fields { layout::FieldPlacement::Array { .. } => { @@ -303,7 +287,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } layout::FieldPlacement::Arbitrary { .. } => { // Gather the subplaces and sort them before visiting. - let mut places = fields.collect::>>>()?; + let mut places = + fields.collect::>>>()?; places.sort_by_key(|place| place.ptr.assert_ptr().offset); self.walk_aggregate(place, places.into_iter().map(Ok)) } @@ -315,22 +300,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // We have to do *something* for unions. - fn visit_union(&mut self, v: MPlaceTy<'tcx, Tag>) -> InterpResult<'tcx> - { + fn visit_union(&mut self, v: MPlaceTy<'tcx, Tag>) -> InterpResult<'tcx> { // With unions, we fall back to whatever the type says, to hopefully be consistent // with LLVM IR. // FIXME: are we consistent, and is this really the behavior we want? let frozen = self.ecx.type_is_freeze(v.layout.ty); - if frozen { - Ok(()) - } else { - (self.unsafe_cell_action)(v) - } + if frozen { Ok(()) } else { (self.unsafe_cell_action)(v) } } // We should never get to a primitive, but always short-circuit somewhere above. - fn visit_primitive(&mut self, _v: MPlaceTy<'tcx, Tag>) -> InterpResult<'tcx> - { + fn visit_primitive(&mut self, _v: MPlaceTy<'tcx, Tag>) -> InterpResult<'tcx> { bug!("we should always short-circuit before coming to a primitive") } } @@ -382,7 +361,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// case. fn check_no_isolation(&mut self, name: &str) -> InterpResult<'tcx> { if !self.eval_context_mut().machine.communicate { - throw_unsup_format!("`{}` not available when isolation is enabled. Pass the flag `-Zmiri-disable-isolation` to disable it.", name) + throw_unsup_format!( + "`{}` not available when isolation is enabled. Pass the flag `-Zmiri-disable-isolation` to disable it.", + name + ) } Ok(()) } @@ -423,11 +405,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx TimedOut => "ETIMEDOUT", AlreadyExists => "EEXIST", WouldBlock => "EWOULDBLOCK", - _ => throw_unsup_format!("The {} error cannot be transformed into a raw os error", e) + _ => { + throw_unsup_format!("The {} error cannot be transformed into a raw os error", e) + } })? } else { // FIXME: we have to implement the Windows equivalent of this. - throw_unsup_format!("Setting the last OS error from an io::Error is unsupported for {}.", target.target_os) + throw_unsup_format!( + "Setting the last OS error from an io::Error is unsupported for {}.", + target.target_os + ) }; this.set_last_error(last_error) } @@ -454,7 +441,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// Helper function to read an OsString from a null-terminated sequence of bytes, which is what /// the Unix APIs usually handle. fn read_os_str_from_c_str<'a>(&'a self, scalar: Scalar) -> InterpResult<'tcx, &'a OsStr> - where 'tcx: 'a, 'mir: 'a + where + 'tcx: 'a, + 'mir: 'a, { let this = self.eval_context_ref(); let bytes = this.memory.read_c_str(scalar)?; @@ -469,7 +458,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx &mut self, os_str: &OsStr, scalar: Scalar, - size: u64 + size: u64, ) -> InterpResult<'tcx, bool> { let bytes = os_str_to_bytes(os_str)?; // If `size` is smaller or equal than `bytes.len()`, writing `bytes` plus the required null @@ -477,7 +466,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if size <= bytes.len() as u64 { return Ok(false); } - self.eval_context_mut().memory.write_bytes(scalar, bytes.iter().copied().chain(iter::once(0u8)))?; + self.eval_context_mut() + .memory + .write_bytes(scalar, bytes.iter().copied().chain(iter::once(0u8)))?; Ok(true) } } @@ -488,7 +479,7 @@ fn os_str_to_bytes<'tcx, 'a>(os_str: &'a OsStr) -> InterpResult<'tcx, &'a [u8]> } #[cfg(target_os = "unix")] -fn bytes_to_os_str<'tcx, 'a>(bytes: &'a[u8]) -> InterpResult<'tcx, &'a OsStr> { +fn bytes_to_os_str<'tcx, 'a>(bytes: &'a [u8]) -> InterpResult<'tcx, &'a OsStr> { Ok(std::os::unix::ffi::OsStringExt::from_bytes(bytes)) } @@ -522,11 +513,7 @@ pub fn immty_from_int_checked<'tcx>( let size = layout.size; let truncated = truncate(int as u128, size); if sign_extend(truncated, size) as i128 != int { - throw_unsup_format!( - "Signed value {:#x} does not fit in {} bits", - int, - size.bits() - ) + throw_unsup_format!("Signed value {:#x} does not fit in {} bits", int, size.bits()) } Ok(ImmTy::from_int(int, layout)) } @@ -542,12 +529,7 @@ pub fn immty_from_uint_checked<'tcx>( // `ImmTy::from_int` panic. let size = layout.size; if truncate(int, size) != int { - throw_unsup_format!( - "Unsigned value {:#x} does not fit in {} bits", - int, - size.bits() - ) + throw_unsup_format!("Unsigned value {:#x} does not fit in {} bits", int, size.bits()) } Ok(ImmTy::from_uint(int, layout)) } - diff --git a/src/intptrcast.rs b/src/intptrcast.rs index a55c58c13add7..059d8217fabb4 100644 --- a/src/intptrcast.rs +++ b/src/intptrcast.rs @@ -1,11 +1,11 @@ use std::cell::RefCell; -use std::collections::{HashMap, hash_map::Entry}; use std::cmp::max; +use std::collections::{hash_map::Entry, HashMap}; use rand::Rng; use rustc::ty::layout::HasDataLayout; -use rustc_mir::interpret::{AllocId, Pointer, InterpResult, Memory, AllocCheck, PointerArithmetic}; +use rustc_mir::interpret::{AllocCheck, AllocId, InterpResult, Memory, Pointer, PointerArithmetic}; use rustc_target::abi::Size; use crate::{Evaluator, Tag, STACK_ADDR}; @@ -47,14 +47,15 @@ impl<'mir, 'tcx> GlobalState { } let global_state = memory.extra.intptrcast.borrow(); + let pos = global_state.int_to_ptr_map.binary_search_by_key(&int, |(addr, _)| *addr); - Ok(match global_state.int_to_ptr_map.binary_search_by_key(&int, |(addr, _)| *addr) { + Ok(match pos { Ok(pos) => { let (_, alloc_id) = global_state.int_to_ptr_map[pos]; // `int` is equal to the starting address for an allocation, the offset should be // zero. The pointer is untagged because it was created from a cast Pointer::new_with_tag(alloc_id, Size::from_bytes(0), Tag::Untagged) - }, + } Err(0) => throw_unsup!(DanglingPointerDeref), Err(pos) => { // This is the largest of the adresses smaller than `int`, @@ -100,7 +101,10 @@ impl<'mir, 'tcx> GlobalState { entry.insert(base_addr); trace!( "Assigning base address {:#x} to allocation {:?} (slack: {}, align: {})", - base_addr, ptr.alloc_id, slack, align.bytes(), + base_addr, + ptr.alloc_id, + slack, + align.bytes(), ); // Remember next base address. If this allocation is zero-sized, leave a gap @@ -114,7 +118,8 @@ impl<'mir, 'tcx> GlobalState { } }; - debug_assert_eq!(base_addr % align.bytes(), 0); // sanity check + // Sanity check that the base address is aligned. + debug_assert_eq!(base_addr % align.bytes(), 0); // Add offset with the right kind of pointer-overflowing arithmetic. let dl = memory.data_layout(); Ok(dl.overflowing_offset(base_addr, ptr.offset.bytes()).0) @@ -125,7 +130,7 @@ impl<'mir, 'tcx> GlobalState { fn align_addr(addr: u64, align: u64) -> u64 { match addr % align { 0 => addr, - rem => addr.checked_add(align).unwrap() - rem + rem => addr.checked_add(align).unwrap() - rem, } } } diff --git a/src/lib.rs b/src/lib.rs index ee13631727d2c..32d2bda719ea0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,57 +1,57 @@ #![feature(rustc_private)] #![feature(option_expect_none, option_unwrap_none)] - #![warn(rust_2018_idioms)] #![allow(clippy::cast_lossless)] #[macro_use] extern crate log; // From rustc. -extern crate syntax; extern crate rustc_apfloat; -#[macro_use] extern crate rustc; +extern crate syntax; +#[macro_use] +extern crate rustc; extern crate rustc_data_structures; extern crate rustc_mir; extern crate rustc_target; -mod shims; -mod operator; +mod eval; mod helpers; -mod range_map; -mod mono_hash_map; -mod stacked_borrows; mod intptrcast; mod machine; -mod eval; +mod mono_hash_map; +mod operator; +mod range_map; +mod shims; +mod stacked_borrows; // Make all those symbols available in the same place as our own. pub use rustc_mir::interpret::*; // Resolve ambiguity. pub use rustc_mir::interpret::{self, AllocMap, PlaceTy}; -pub use crate::shims::{EvalContextExt as ShimsEvalContextExt}; -pub use crate::shims::foreign_items::EvalContextExt as ForeignItemsEvalContextExt; -pub use crate::shims::intrinsics::EvalContextExt as IntrinsicsEvalContextExt; -pub use crate::shims::tls::{EvalContextExt as TlsEvalContextExt, TlsData}; -pub use crate::shims::time::{EvalContextExt as TimeEvalContextExt}; pub use crate::shims::dlsym::{Dlsym, EvalContextExt as DlsymEvalContextExt}; pub use crate::shims::env::{EnvVars, EvalContextExt as EnvEvalContextExt}; -pub use crate::shims::fs::{FileHandler, EvalContextExt as FileEvalContextExt}; +pub use crate::shims::foreign_items::EvalContextExt as ForeignItemsEvalContextExt; +pub use crate::shims::fs::{EvalContextExt as FileEvalContextExt, FileHandler}; +pub use crate::shims::intrinsics::EvalContextExt as IntrinsicsEvalContextExt; pub use crate::shims::panic::{CatchUnwindData, EvalContextExt as PanicEvalContextExt}; +pub use crate::shims::time::EvalContextExt as TimeEvalContextExt; +pub use crate::shims::tls::{EvalContextExt as TlsEvalContextExt, TlsData}; +pub use crate::shims::EvalContextExt as ShimsEvalContextExt; +pub use crate::eval::{create_ecx, eval_main, MiriConfig, TerminationInfo}; +pub use crate::helpers::EvalContextExt as HelpersEvalContextExt; +pub use crate::machine::{ + AllocExtra, Evaluator, FrameData, MemoryExtra, MiriEvalContext, MiriEvalContextExt, + MiriMemoryKind, NUM_CPUS, PAGE_SIZE, STACK_ADDR, STACK_SIZE, +}; +pub use crate::mono_hash_map::MonoHashMap; pub use crate::operator::EvalContextExt as OperatorEvalContextExt; pub use crate::range_map::RangeMap; -pub use crate::helpers::{EvalContextExt as HelpersEvalContextExt}; -pub use crate::mono_hash_map::MonoHashMap; pub use crate::stacked_borrows::{ - EvalContextExt as StackedBorEvalContextExt, Tag, Permission, Stack, Stacks, Item, PtrId, - GlobalState, -}; -pub use crate::machine::{ - PAGE_SIZE, STACK_ADDR, STACK_SIZE, NUM_CPUS, - MemoryExtra, AllocExtra, FrameData, MiriMemoryKind, Evaluator, MiriEvalContext, MiriEvalContextExt, + EvalContextExt as StackedBorEvalContextExt, GlobalState, Item, Permission, PtrId, Stack, + Stacks, Tag, }; -pub use crate::eval::{eval_main, create_ecx, MiriConfig, TerminationInfo}; /// Insert rustc arguments at the beginning of the argument list that Miri wants to be /// set per default, for maximal validation power. diff --git a/src/machine.rs b/src/machine.rs index d5cd86d97878b..37253a260de7f 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -8,8 +8,12 @@ use std::rc::Rc; use rand::rngs::StdRng; use rustc::hir::def_id::DefId; -use rustc::ty::{self, layout::{Size, LayoutOf}, Ty, TyCtxt}; use rustc::mir; +use rustc::ty::{ + self, + layout::{LayoutOf, Size}, + Ty, TyCtxt, +}; use syntax::{attr, source_map::Span, symbol::sym}; use crate::*; @@ -33,7 +37,6 @@ pub struct FrameData<'tcx> { pub catch_panic: Option>, } - /// Extra memory kinds #[derive(Debug, Copy, Clone, PartialEq, Eq)] pub enum MiriMemoryKind { @@ -114,7 +117,7 @@ pub struct Evaluator<'tcx> { /// The temporary used for storing the argument of /// the call to `miri_start_panic` (the panic payload) when unwinding. - pub(crate) panic_payload: Option> + pub(crate) panic_payload: Option>, } impl<'tcx> Evaluator<'tcx> { @@ -130,7 +133,7 @@ impl<'tcx> Evaluator<'tcx> { tls: TlsData::default(), communicate, file_handler: Default::default(), - panic_payload: None + panic_payload: None, } } } @@ -164,13 +167,8 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { type PointerTag = Tag; type ExtraFnVal = Dlsym; - type MemoryMap = MonoHashMap< - AllocId, - ( - MemoryKind, - Allocation, - ), - >; + type MemoryMap = + MonoHashMap, Allocation)>; const STATIC_KIND: Option = Some(MiriMemoryKind::Static); @@ -322,9 +320,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { stacked_borrows.static_base_ptr(alloc) } }, - AllocExtra { - stacked_borrows: stacks, - }, + AllocExtra { stacked_borrows: stacks }, ); (Cow::Owned(alloc), base_tag) } @@ -334,10 +330,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { if !memory_extra.validate { Tag::Untagged } else { - memory_extra - .stacked_borrows - .borrow_mut() - .static_base_ptr(id) + memory_extra.stacked_borrows.borrow_mut().static_base_ptr(id) } } @@ -356,9 +349,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { } #[inline(always)] - fn stack_push( - ecx: &mut InterpCx<'mir, 'tcx, Self>, - ) -> InterpResult<'tcx, FrameData<'tcx>> { + fn stack_push(ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx, FrameData<'tcx>> { Ok(FrameData { call_id: ecx.memory.extra.stacked_borrows.borrow_mut().new_call(), catch_panic: None, @@ -369,7 +360,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { fn stack_pop( ecx: &mut InterpCx<'mir, 'tcx, Self>, extra: FrameData<'tcx>, - unwinding: bool + unwinding: bool, ) -> InterpResult<'tcx, StackPopInfo> { ecx.handle_stack_pop(extra, unwinding) } diff --git a/src/mono_hash_map.rs b/src/mono_hash_map.rs index f2abe4217306c..124ae68760260 100644 --- a/src/mono_hash_map.rs +++ b/src/mono_hash_map.rs @@ -5,10 +5,10 @@ //! The API is is completely tailored to what `memory.rs` needs. It is still in //! a separate file to minimize the amount of code that has to care about the unsafety. -use std::collections::hash_map::Entry; +use std::borrow::Borrow; use std::cell::RefCell; +use std::collections::hash_map::Entry; use std::hash::Hash; -use std::borrow::Borrow; use rustc_data_structures::fx::FxHashMap; @@ -26,7 +26,7 @@ impl MonoHashMap { /// as long as the `Ref` returned by `RefCell::borrow()` is alive. So we can't return the /// iterator, as that would drop the `Ref`. We can't return both, as it's not possible in Rust /// to have a struct/tuple with a field that refers to another field. - pub fn iter(&self, f: impl FnOnce(&mut dyn Iterator) -> T) -> T { + pub fn iter(&self, f: impl FnOnce(&mut dyn Iterator) -> T) -> T { f(&mut self.0.borrow().iter().map(|(k, v)| (k, &**v))) } } @@ -40,30 +40,28 @@ impl Default for MonoHashMap { impl AllocMap for MonoHashMap { #[inline(always)] fn contains_key(&mut self, k: &Q) -> bool - where K: Borrow + where + K: Borrow, { self.0.get_mut().contains_key(k) } #[inline(always)] - fn insert(&mut self, k: K, v: V) -> Option - { + fn insert(&mut self, k: K, v: V) -> Option { self.0.get_mut().insert(k, Box::new(v)).map(|x| *x) } #[inline(always)] fn remove(&mut self, k: &Q) -> Option - where K: Borrow + where + K: Borrow, { self.0.get_mut().remove(k).map(|x| *x) } #[inline(always)] fn filter_map_collect(&self, mut f: impl FnMut(&K, &V) -> Option) -> Vec { - self.0.borrow() - .iter() - .filter_map(move |(k, v)| f(k, &*v)) - .collect() + self.0.borrow().iter().filter_map(move |(k, v)| f(k, &*v)).collect() } /// The most interesting method: Providing a shared ref without @@ -73,11 +71,7 @@ impl AllocMap for MonoHashMap { /// if it returns a reference, that is used directly, if it /// returns owned data, that is put into the map and returned. #[inline(always)] - fn get_or( - &self, - k: K, - vacant: impl FnOnce() -> Result - ) -> Result<&V, E> { + fn get_or(&self, k: K, vacant: impl FnOnce() -> Result) -> Result<&V, E> { let val: *const V = match self.0.borrow_mut().entry(k) { Entry::Occupied(entry) => &**entry.get(), Entry::Vacant(entry) => &**entry.insert(Box::new(vacant()?)), @@ -88,12 +82,7 @@ impl AllocMap for MonoHashMap { } #[inline(always)] - fn get_mut_or( - &mut self, - k: K, - vacant: impl FnOnce() -> Result - ) -> Result<&mut V, E> - { + fn get_mut_or(&mut self, k: K, vacant: impl FnOnce() -> Result) -> Result<&mut V, E> { match self.0.get_mut().entry(k) { Entry::Occupied(e) => Ok(e.into_mut()), Entry::Vacant(e) => { diff --git a/src/operator.rs b/src/operator.rs index 6b2c12e6b0b04..7c932a907e725 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -1,7 +1,10 @@ use std::convert::TryFrom; -use rustc::ty::{Ty, layout::{Size, LayoutOf}}; use rustc::mir; +use rustc::ty::{ + layout::{LayoutOf, Size}, + Ty, +}; use crate::*; @@ -13,11 +16,7 @@ pub trait EvalContextExt<'tcx> { right: ImmTy<'tcx, Tag>, ) -> InterpResult<'tcx, (Scalar, bool, Ty<'tcx>)>; - fn ptr_eq( - &self, - left: Scalar, - right: Scalar, - ) -> InterpResult<'tcx, bool>; + fn ptr_eq(&self, left: Scalar, right: Scalar) -> InterpResult<'tcx, bool>; fn pointer_offset_inbounds( &self, @@ -41,12 +40,15 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { Ok(match bin_op { Eq | Ne => { // This supports fat pointers. + #[rustfmt::skip] let eq = match (*left, *right) { - (Immediate::Scalar(left), Immediate::Scalar(right)) => - self.ptr_eq(left.not_undef()?, right.not_undef()?)?, - (Immediate::ScalarPair(left1, left2), Immediate::ScalarPair(right1, right2)) => - self.ptr_eq(left1.not_undef()?, right1.not_undef()?)? && - self.ptr_eq(left2.not_undef()?, right2.not_undef()?)?, + (Immediate::Scalar(left), Immediate::Scalar(right)) => { + self.ptr_eq(left.not_undef()?, right.not_undef()?)? + } + (Immediate::ScalarPair(left1, left2), Immediate::ScalarPair(right1, right2)) => { + self.ptr_eq(left1.not_undef()?, right1.not_undef()?)? + && self.ptr_eq(left2.not_undef()?, right2.not_undef()?)? + } _ => bug!("Type system should not allow comparing Scalar with ScalarPair"), }; (Scalar::from_bool(if bin_op == Eq { eq } else { !eq }), false, self.tcx.types.bool) @@ -68,10 +70,8 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { } Offset => { - let pointee_ty = left.layout.ty - .builtin_deref(true) - .expect("Offset called on non-ptr type") - .ty; + let pointee_ty = + left.layout.ty.builtin_deref(true).expect("Offset called on non-ptr type").ty; let ptr = self.pointer_offset_inbounds( left.to_scalar()?, pointee_ty, @@ -80,15 +80,11 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { (ptr, false, left.layout.ty) } - _ => bug!("Invalid operator on pointers: {:?}", bin_op) + _ => bug!("Invalid operator on pointers: {:?}", bin_op), }) } - fn ptr_eq( - &self, - left: Scalar, - right: Scalar, - ) -> InterpResult<'tcx, bool> { + fn ptr_eq(&self, left: Scalar, right: Scalar) -> InterpResult<'tcx, bool> { let size = self.pointer_size(); // Just compare the integers. // TODO: Do we really want to *always* do that, even when comparing two live in-bounds pointers? diff --git a/src/range_map.rs b/src/range_map.rs index aa9a87887d375..01abaef27fd2d 100644 --- a/src/range_map.rs +++ b/src/range_map.rs @@ -29,10 +29,7 @@ impl RangeMap { let size = size.bytes(); let mut map = RangeMap { v: Vec::new() }; if size > 0 { - map.v.push(Elem { - range: 0..size, - data: init - }); + map.v.push(Elem { range: 0..size, data: init }); } map } @@ -53,7 +50,7 @@ impl RangeMap { } else if offset >= elem.range.end { // We are too far left (offset is further right). debug_assert!(candidate >= left); // we are making progress - left = candidate+1; + left = candidate + 1; } else { // This is it! return candidate; @@ -69,18 +66,16 @@ impl RangeMap { let len = len.bytes(); // Compute a slice starting with the elements we care about. let slice: &[Elem] = if len == 0 { - // We just need any empty iterator. We don't even want to - // yield the element that surrounds this position. - &[] - } else { - let first_idx = self.find_offset(offset); - &self.v[first_idx..] - }; + // We just need any empty iterator. We don't even want to + // yield the element that surrounds this position. + &[] + } else { + let first_idx = self.find_offset(offset); + &self.v[first_idx..] + }; // The first offset that is not included any more. let end = offset + len; - slice.iter() - .take_while(move |elem| elem.range.start < end) - .map(|elem| &elem.data) + slice.iter().take_while(move |elem| elem.range.start < end).map(|elem| &elem.data) } pub fn iter_mut_all<'a>(&'a mut self) -> impl Iterator + 'a { @@ -99,18 +94,17 @@ impl RangeMap { // Nothing to do. return false; } - debug_assert!(elem.range.contains(&split_offset), - "the `split_offset` is not in the element to be split"); + debug_assert!( + elem.range.contains(&split_offset), + "the `split_offset` is not in the element to be split" + ); // Now we really have to split. Reduce length of first element. let second_range = split_offset..elem.range.end; elem.range.end = split_offset; // Copy the data, and insert second element. - let second = Elem { - range: second_range, - data: elem.data.clone(), - }; - self.v.insert(index+1, second); + let second = Elem { range: second_range, data: elem.data.clone() }; + self.v.insert(index + 1, second); return true; } @@ -130,73 +124,79 @@ impl RangeMap { let len = len.bytes(); // Compute a slice containing exactly the elements we care about let slice: &mut [Elem] = if len == 0 { - // We just need any empty iterator. We don't even want to - // yield the element that surrounds this position, nor do - // any splitting. - &mut [] - } else { - // Make sure we got a clear beginning - let mut first_idx = self.find_offset(offset); - if self.split_index(first_idx, offset) { - // The newly created 2nd element is ours - first_idx += 1; - } - let first_idx = first_idx; // no more mutation - // Find our end. Linear scan, but that's ok because the iteration - // is doing the same linear scan anyway -- no increase in complexity. - // We combine this scan with a scan for duplicates that we can merge, to reduce - // the number of elements. - // We stop searching after the first "block" of size 1, to avoid spending excessive - // amounts of time on the merging. - let mut equal_since_idx = first_idx; - // Once we see too many non-mergeable blocks, we stop. - // The initial value is chosen via... magic. Benchmarking and magic. - let mut successful_merge_count = 3usize; - let mut end_idx = first_idx; // when the loop is done, this is the first excluded element. - loop { - // Compute if `end` is the last element we need to look at. - let done = self.v[end_idx].range.end >= offset+len; - // We definitely need to include `end`, so move the index. - end_idx += 1; - debug_assert!(done || end_idx < self.v.len(), "iter_mut: end-offset {} is out-of-bounds", offset+len); - // see if we want to merge everything in `equal_since..end` (exclusive at the end!) - if successful_merge_count > 0 { - if done || self.v[end_idx].data != self.v[equal_since_idx].data { - // Everything in `equal_since..end` was equal. Make them just one element covering - // the entire range. - let removed_elems = end_idx - equal_since_idx - 1; // number of elements that we would remove - if removed_elems > 0 { - // Adjust the range of the first element to cover all of them. - let equal_until = self.v[end_idx - 1].range.end; // end of range of last of the equal elements - self.v[equal_since_idx].range.end = equal_until; - // Delete the rest of them. - self.v.splice(equal_since_idx+1..end_idx, std::iter::empty()); - // Adjust `end_idx` because we made the list shorter. - end_idx -= removed_elems; - // Adjust the count for the cutoff. - successful_merge_count += removed_elems; - } else { - // Adjust the count for the cutoff. - successful_merge_count -= 1; - } - // Go on scanning for the next block starting here. - equal_since_idx = end_idx; + // We just need any empty iterator. We don't even want to + // yield the element that surrounds this position, nor do + // any splitting. + &mut [] + } else { + // Make sure we got a clear beginning + let mut first_idx = self.find_offset(offset); + if self.split_index(first_idx, offset) { + // The newly created 2nd element is ours + first_idx += 1; + } + // No more mutation. + let first_idx = first_idx; + // Find our end. Linear scan, but that's ok because the iteration + // is doing the same linear scan anyway -- no increase in complexity. + // We combine this scan with a scan for duplicates that we can merge, to reduce + // the number of elements. + // We stop searching after the first "block" of size 1, to avoid spending excessive + // amounts of time on the merging. + let mut equal_since_idx = first_idx; + // Once we see too many non-mergeable blocks, we stop. + // The initial value is chosen via... magic. Benchmarking and magic. + let mut successful_merge_count = 3usize; + // When the loop is done, this is the first excluded element. + let mut end_idx = first_idx; + loop { + // Compute if `end` is the last element we need to look at. + let done = self.v[end_idx].range.end >= offset + len; + // We definitely need to include `end`, so move the index. + end_idx += 1; + debug_assert!( + done || end_idx < self.v.len(), + "iter_mut: end-offset {} is out-of-bounds", + offset + len + ); + // see if we want to merge everything in `equal_since..end` (exclusive at the end!) + if successful_merge_count > 0 { + if done || self.v[end_idx].data != self.v[equal_since_idx].data { + // Everything in `equal_since..end` was equal. Make them just one element covering + // the entire range. + let removed_elems = end_idx - equal_since_idx - 1; // number of elements that we would remove + if removed_elems > 0 { + // Adjust the range of the first element to cover all of them. + let equal_until = self.v[end_idx - 1].range.end; // end of range of last of the equal elements + self.v[equal_since_idx].range.end = equal_until; + // Delete the rest of them. + self.v.splice(equal_since_idx + 1..end_idx, std::iter::empty()); + // Adjust `end_idx` because we made the list shorter. + end_idx -= removed_elems; + // Adjust the count for the cutoff. + successful_merge_count += removed_elems; + } else { + // Adjust the count for the cutoff. + successful_merge_count -= 1; } - } - // Leave loop if this is the last element. - if done { - break; + // Go on scanning for the next block starting here. + equal_since_idx = end_idx; } } - // Move to last included instead of first excluded index. - let end_idx = end_idx-1; - // We need to split the end as well. Even if this performs a - // split, we don't have to adjust our index as we only care about - // the first part of the split. - self.split_index(end_idx, offset+len); - // Now we yield the slice. `end` is inclusive. - &mut self.v[first_idx..=end_idx] - }; + // Leave loop if this is the last element. + if done { + break; + } + } + // Move to last included instead of first excluded index. + let end_idx = end_idx - 1; + // We need to split the end as well. Even if this performs a + // split, we don't have to adjust our index as we only care about + // the first part of the split. + self.split_index(end_idx, offset + len); + // Now we yield the slice. `end` is inclusive. + &mut self.v[first_idx..=end_idx] + }; slice.iter_mut().map(|elem| &mut elem.data) } } @@ -209,12 +209,7 @@ mod tests { fn to_vec(map: &RangeMap, offset: u64, len: u64) -> Vec { (offset..offset + len) .into_iter() - .map(|i| map - .iter(Size::from_bytes(i), Size::from_bytes(1)) - .next() - .map(|&t| t) - .unwrap() - ) + .map(|i| map.iter(Size::from_bytes(i), Size::from_bytes(1)).next().map(|&t| t).unwrap()) .collect() } @@ -250,10 +245,7 @@ mod tests { *x = 43; } assert_eq!(map.v.len(), 5); - assert_eq!( - to_vec(&map, 10, 10), - vec![-1, 42, -1, -1, -1, 43, -1, -1, -1, -1] - ); + assert_eq!(to_vec(&map, 10, 10), vec![-1, 42, -1, -1, -1, 43, -1, -1, -1, -1]); for x in map.iter_mut(Size::from_bytes(10), Size::from_bytes(10)) { if *x < 42 { @@ -261,31 +253,23 @@ mod tests { } } assert_eq!(map.v.len(), 6); - assert_eq!( - to_vec(&map, 10, 10), - vec![23, 42, 23, 23, 23, 43, 23, 23, 23, 23] - ); + assert_eq!(to_vec(&map, 10, 10), vec![23, 42, 23, 23, 23, 43, 23, 23, 23, 23]); assert_eq!(to_vec(&map, 13, 5), vec![23, 23, 43, 23, 23]); - for x in map.iter_mut(Size::from_bytes(15), Size::from_bytes(5)) { *x = 19; } assert_eq!(map.v.len(), 6); + assert_eq!(to_vec(&map, 10, 10), vec![23, 42, 23, 23, 23, 19, 19, 19, 19, 19]); + // Should be seeing two blocks with 19. assert_eq!( - to_vec(&map, 10, 10), - vec![23, 42, 23, 23, 23, 19, 19, 19, 19, 19] + map.iter(Size::from_bytes(15), Size::from_bytes(2)).map(|&t| t).collect::>(), + vec![19, 19] ); - // Should be seeing two blocks with 19. - assert_eq!(map.iter(Size::from_bytes(15), Size::from_bytes(2)) - .map(|&t| t).collect::>(), vec![19, 19]); // A NOP `iter_mut` should trigger merging. - for _ in map.iter_mut(Size::from_bytes(15), Size::from_bytes(5)) { } + for _ in map.iter_mut(Size::from_bytes(15), Size::from_bytes(5)) {} assert_eq!(map.v.len(), 5); - assert_eq!( - to_vec(&map, 10, 10), - vec![23, 42, 23, 23, 23, 19, 19, 19, 19, 19] - ); + assert_eq!(to_vec(&map, 10, 10), vec![23, 42, 23, 23, 23, 19, 19, 19, 19, 19]); } } diff --git a/src/shims/dlsym.rs b/src/shims/dlsym.rs index dfee4066da1b0..0069f8cc80870 100644 --- a/src/shims/dlsym.rs +++ b/src/shims/dlsym.rs @@ -15,8 +15,7 @@ impl Dlsym { Ok(match name { "getentropy" => Some(GetEntropy), "__pthread_get_minstack" => None, - _ => - throw_unsup_format!("Unsupported dlsym: {}", name), + _ => throw_unsup_format!("Unsupported dlsym: {}", name), }) } } diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 55742bd060b35..1a52d8721470f 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -1,10 +1,10 @@ -use std::{iter, convert::TryInto}; +use std::{convert::TryInto, iter}; +use rustc::hir::def_id::DefId; use rustc::mir; +use rustc::ty; use rustc::ty::layout::{Align, LayoutOf, Size}; -use rustc::hir::def_id::DefId; use rustc_apfloat::Float; -use rustc::ty; use syntax::attr; use syntax::symbol::sym; @@ -47,14 +47,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Scalar::from_int(0, this.pointer_size()) } else { let align = this.min_align(size, kind); - let ptr = this - .memory - .allocate(Size::from_bytes(size), align, kind.into()); + let ptr = this.memory.allocate(Size::from_bytes(size), align, kind.into()); if zero_init { // We just allocated this, the access is definitely in-bounds. - this.memory - .write_bytes(ptr.into(), iter::repeat(0u8).take(size as usize)) - .unwrap(); + this.memory.write_bytes(ptr.into(), iter::repeat(0u8).take(size as usize)).unwrap(); } Scalar::Ptr(ptr) } @@ -82,8 +78,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(Scalar::from_int(0, this.pointer_size())) } else { let new_ptr = - this.memory - .allocate(Size::from_bytes(new_size), new_align, kind.into()); + this.memory.allocate(Size::from_bytes(new_size), new_align, kind.into()); Ok(Scalar::Ptr(new_ptr)) } } else { @@ -110,12 +105,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// by this function. /// Returns Ok(Some(body)) if processing the foreign item /// is delegated to another function. + #[rustfmt::skip] fn emulate_foreign_item( &mut self, def_id: DefId, args: &[OpTy<'tcx, Tag>], ret: Option<(PlaceTy<'tcx, Tag>, mir::BasicBlock)>, - _unwind: Option + _unwind: Option, ) -> InterpResult<'tcx, Option<&'mir mir::Body<'tcx>>> { let this = self.eval_context_mut(); let attrs = this.tcx.get_attrs(def_id); @@ -136,11 +132,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // also be a custom user-provided implementation via `#![feature(panic_runtime)]` "__rust_start_panic" => { // FIXME we might want to cache this... but it's not really performance-critical. - let panic_runtime = tcx.crates().iter() + let panic_runtime = tcx + .crates() + .iter() .find(|cnum| tcx.is_panic_runtime(**cnum)) .expect("No panic runtime found!"); let panic_runtime = tcx.crate_name(*panic_runtime); - let start_panic_instance = this.resolve_path(&[&*panic_runtime.as_str(), "__rust_start_panic"])?; + let start_panic_instance = + this.resolve_path(&[&*panic_runtime.as_str(), "__rust_start_panic"])?; return Ok(Some(&*this.load_mir(start_panic_instance.def, None)?)); } // Similarly, we forward calls to the `panic_impl` foreign item to its implementation. @@ -151,7 +150,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx return Ok(Some(&*this.load_mir(panic_impl_instance.def, None)?)); } - "exit" | "ExitProcess" => { + | "exit" + | "ExitProcess" + => { // it's really u32 for ExitProcess, but we have to put it into the `Exit` variant anyway let code = this.read_scalar(args[0])?.to_i32()?; throw_machine_stop!(TerminationInfo::Exit(code.into())); @@ -175,9 +176,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "calloc" => { let items = this.read_scalar(args[0])?.to_machine_usize(this)?; let len = this.read_scalar(args[1])?.to_machine_usize(this)?; - let size = items - .checked_mul(len) - .ok_or_else(|| err_panic!(Overflow(mir::BinOp::Mul)))?; + let size = + items.checked_mul(len).ok_or_else(|| err_panic!(Overflow(mir::BinOp::Mul)))?; let res = this.malloc(size, /*zero_init:*/ true, MiriMemoryKind::C); this.write_scalar(res, dest)?; } @@ -250,9 +250,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx MiriMemoryKind::Rust.into(), ); // We just allocated this, the access is definitely in-bounds. - this.memory - .write_bytes(ptr.into(), iter::repeat(0u8).take(size as usize)) - .unwrap(); + this.memory.write_bytes(ptr.into(), iter::repeat(0u8).take(size as usize)).unwrap(); this.write_scalar(ptr, dest)?; } "__rust_dealloc" => { @@ -268,10 +266,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let ptr = this.force_ptr(ptr)?; this.memory.deallocate( ptr, - Some(( - Size::from_bytes(old_size), - Align::from_bytes(align).unwrap(), - )), + Some((Size::from_bytes(old_size), Align::from_bytes(align).unwrap())), MiriMemoryKind::Rust.into(), )?; } @@ -346,7 +341,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "__rust_maybe_catch_panic" => { this.handle_catch_panic(args, dest, ret)?; - return Ok(None) + return Ok(None); } "memcmp" => { @@ -404,7 +399,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } - "__errno_location" | "__error" => { + | "__errno_location" + | "__error" + => { let errno_place = this.machine.last_error.unwrap(); this.write_scalar(errno_place.to_ref().to_scalar()?, dest)?; } @@ -434,7 +431,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; } - "open" | "open64" => { + | "open" + | "open64" + => { let result = this.open(args[0], args[1])?; this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; } @@ -444,7 +443,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; } - "close" | "close$NOCANCEL" => { + | "close" + | "close$NOCANCEL" + => { let result = this.close(args[0])?; this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; } @@ -510,7 +511,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // math functions - "cbrtf" | "coshf" | "sinhf" | "tanf" | "acosf" | "asinf" | "atanf" => { + | "cbrtf" + | "coshf" + | "sinhf" + | "tanf" + | "acosf" + | "asinf" + | "atanf" + => { // FIXME: Using host floats. let f = f32::from_bits(this.read_scalar(args[0])?.to_u32()?); let f = match link_name { @@ -526,7 +534,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_u32(f.to_bits()), dest)?; } // underscore case for windows - "_hypotf" | "hypotf" | "atan2f" => { + | "_hypotf" + | "hypotf" + | "atan2f" + => { // FIXME: Using host floats. let f1 = f32::from_bits(this.read_scalar(args[0])?.to_u32()?); let f2 = f32::from_bits(this.read_scalar(args[1])?.to_u32()?); @@ -538,7 +549,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_u32(n.to_bits()), dest)?; } - "cbrt" | "cosh" | "sinh" | "tan" | "acos" | "asin" | "atan" => { + | "cbrt" + | "cosh" + | "sinh" + | "tan" + | "acos" + | "asin" + | "atan" + => { // FIXME: Using host floats. let f = f64::from_bits(this.read_scalar(args[0])?.to_u64()?); let f = match link_name { @@ -555,7 +573,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // underscore case for windows, here and below // (see https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/floating-point-primitives?view=vs-2019) - "_hypot" | "hypot" | "atan2" => { + | "_hypot" + | "hypot" + | "atan2" + => { // FIXME: Using host floats. let f1 = f64::from_bits(this.read_scalar(args[0])?.to_u64()?); let f2 = f64::from_bits(this.read_scalar(args[1])?.to_u64()?); @@ -567,7 +588,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_u64(n.to_bits()), dest)?; } // For radix-2 (binary) systems, `ldexp` and `scalbn` are the same. - "_ldexp" | "ldexp" | "scalbn" => { + | "_ldexp" + | "ldexp" + | "scalbn" + => { let x = this.read_scalar(args[0])?.to_f64()?; let exp = this.read_scalar(args[1])?.to_i32()?; @@ -586,7 +610,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // Some things needed for `sys::thread` initialization to go through. - "signal" | "sigaction" | "sigaltstack" => { + | "signal" + | "sigaction" + | "sigaltstack" + => { this.write_scalar(Scalar::from_int(0, dest.layout.size), dest)?; } @@ -596,14 +623,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx trace!("sysconf() called with name {}", name); // TODO: Cache the sysconf integers via Miri's global cache. let paths = &[ - ( - &["libc", "_SC_PAGESIZE"], - Scalar::from_int(PAGE_SIZE, dest.layout.size), - ), - ( - &["libc", "_SC_GETPW_R_SIZE_MAX"], - Scalar::from_int(-1, dest.layout.size), - ), + (&["libc", "_SC_PAGESIZE"], Scalar::from_int(PAGE_SIZE, dest.layout.size)), + (&["libc", "_SC_GETPW_R_SIZE_MAX"], Scalar::from_int(-1, dest.layout.size)), ( &["libc", "_SC_NPROCESSORS_ONLN"], Scalar::from_int(NUM_CPUS, dest.layout.size), @@ -688,7 +709,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // Stack size/address stuff. - "pthread_attr_init" + | "pthread_attr_init" | "pthread_attr_destroy" | "pthread_self" | "pthread_attr_setstacksize" => { @@ -712,12 +733,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // We don't support threading. (Also for Windows.) - "pthread_create" | "CreateThread" => { + | "pthread_create" + | "CreateThread" + => { throw_unsup_format!("Miri does not support threading"); } // Stub out calls for condvar, mutex and rwlock, to just return `0`. - "pthread_mutexattr_init" + | "pthread_mutexattr_init" | "pthread_mutexattr_settype" | "pthread_mutex_init" | "pthread_mutexattr_destroy" @@ -732,7 +755,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "pthread_condattr_setclock" | "pthread_cond_init" | "pthread_condattr_destroy" - | "pthread_cond_destroy" => { + | "pthread_cond_destroy" + => { this.write_null(dest)?; } @@ -751,7 +775,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // macOS API stubs. - "pthread_attr_get_np" | "pthread_getattr_np" => { + | "pthread_attr_get_np" + | "pthread_getattr_np" + => { this.write_null(dest)?; } "pthread_get_stackaddr_np" => { @@ -822,32 +848,36 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Any non zero value works for the stdlib. This is just used for stack overflows anyway. this.write_scalar(Scalar::from_int(1, dest.layout.size), dest)?; } - "InitializeCriticalSection" + + | "InitializeCriticalSection" | "EnterCriticalSection" | "LeaveCriticalSection" - | "DeleteCriticalSection" => { + | "DeleteCriticalSection" + => { // Nothing to do, not even a return value. } - "GetModuleHandleW" + + | "GetModuleHandleW" | "GetProcAddress" | "TryEnterCriticalSection" | "GetConsoleScreenBufferInfo" - | "SetConsoleTextAttribute" => { + | "SetConsoleTextAttribute" + => { // Pretend these do not exist / nothing happened, by returning zero. this.write_null(dest)?; } + "GetSystemInfo" => { let system_info = this.deref_operand(args[0])?; // Initialize with `0`. - this.memory - .write_bytes(system_info.ptr, iter::repeat(0u8).take(system_info.layout.size.bytes() as usize))?; + this.memory.write_bytes( + system_info.ptr, + iter::repeat(0u8).take(system_info.layout.size.bytes() as usize), + )?; // Set number of processors. let dword_size = Size::from_bytes(4); let num_cpus = this.mplace_field(system_info, 6)?; - this.write_scalar( - Scalar::from_int(NUM_CPUS, dword_size), - num_cpus.into(), - )?; + this.write_scalar(Scalar::from_int(NUM_CPUS, dword_size), num_cpus.into())?; } "TlsAlloc" => { @@ -894,9 +924,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // stdout/stderr use std::io::{self, Write}; - let buf_cont = this - .memory - .read_bytes(buf, Size::from_bytes(u64::from(n)))?; + let buf_cont = this.memory.read_bytes(buf, Size::from_bytes(u64::from(n)))?; let res = if handle == -11 { io::stdout().write(buf_cont) } else { @@ -928,7 +956,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_null(dest)?; } "GetCommandLineW" => { - this.write_scalar(this.machine.cmd_line.expect("machine must be initialized"), dest)?; + this.write_scalar( + this.machine.cmd_line.expect("machine must be initialized"), + dest, + )?; } // The actual name of 'RtlGenRandom' "SystemFunction036" => { @@ -955,10 +986,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, Option>> { let this = self.eval_context_mut(); if let Ok(instance) = this.resolve_path(path) { - let cid = GlobalId { - instance, - promoted: None, - }; + let cid = GlobalId { instance, promoted: None }; let const_val = this.const_eval_raw(cid)?; let const_val = this.read_scalar(const_val.into())?; return Ok(Some(const_val)); diff --git a/src/shims/fs.rs b/src/shims/fs.rs index 47f3f50b76aff..0b78111533a59 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -1,11 +1,11 @@ use std::collections::HashMap; -use std::convert::{TryInto, TryFrom}; +use std::convert::{TryFrom, TryInto}; use std::fs::{remove_file, File, OpenOptions}; use std::io::{Read, Write}; use std::path::PathBuf; use std::time::SystemTime; -use rustc::ty::layout::{Size, Align, LayoutOf}; +use rustc::ty::layout::{Align, LayoutOf, Size}; use crate::stacked_borrows::Tag; use crate::*; @@ -172,18 +172,18 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let fd = this.read_scalar(fd_op)?.to_i32()?; let buf = this.read_scalar(buf_op)?.not_undef()?; - let count = this - .read_scalar(count_op)? - .to_machine_usize(&*this.tcx)?; + let count = this.read_scalar(count_op)?.to_machine_usize(&*this.tcx)?; // Check that the *entire* buffer is actually valid memory. - this.memory.check_ptr_access(buf, Size::from_bytes(count), Align::from_bytes(1).unwrap())?; + this.memory.check_ptr_access( + buf, + Size::from_bytes(count), + Align::from_bytes(1).unwrap(), + )?; // We cap the number of read bytes to the largest value that we are able to fit in both the // host's and target's `isize`. This saves us from having to handle overflows later. - let count = count - .min(this.isize_max() as u64) - .min(isize::max_value() as u64); + let count = count.min(this.isize_max() as u64).min(isize::max_value() as u64); if let Some(handle) = this.machine.file_handler.handles.get_mut(&fd) { // This can never fail because `count` was capped to be smaller than @@ -227,18 +227,18 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let fd = this.read_scalar(fd_op)?.to_i32()?; let buf = this.read_scalar(buf_op)?.not_undef()?; - let count = this - .read_scalar(count_op)? - .to_machine_usize(&*this.tcx)?; + let count = this.read_scalar(count_op)?.to_machine_usize(&*this.tcx)?; // Check that the *entire* buffer is actually valid memory. - this.memory.check_ptr_access(buf, Size::from_bytes(count), Align::from_bytes(1).unwrap())?; + this.memory.check_ptr_access( + buf, + Size::from_bytes(count), + Align::from_bytes(1).unwrap(), + )?; // We cap the number of written bytes to the largest value that we are able to fit in both the // host's and target's `isize`. This saves us from having to handle overflows later. - let count = count - .min(this.isize_max() as u64) - .min(isize::max_value() as u64); + let count = count.min(this.isize_max() as u64).min(isize::max_value() as u64); if let Some(handle) = this.machine.file_handler.handles.get_mut(&fd) { let bytes = this.memory.read_bytes(buf, Size::from_bytes(count))?; @@ -263,11 +263,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn statx( &mut self, - dirfd_op: OpTy<'tcx, Tag>, // Should be an `int` + dirfd_op: OpTy<'tcx, Tag>, // Should be an `int` pathname_op: OpTy<'tcx, Tag>, // Should be a `const char *` - flags_op: OpTy<'tcx, Tag>, // Should be an `int` - _mask_op: OpTy<'tcx, Tag>, // Should be an `unsigned int` - statxbuf_op: OpTy<'tcx, Tag> // Should be a `struct statx *` + flags_op: OpTy<'tcx, Tag>, // Should be an `int` + _mask_op: OpTy<'tcx, Tag>, // Should be an `unsigned int` + statxbuf_op: OpTy<'tcx, Tag>, // Should be a `struct statx *` ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); @@ -302,29 +302,20 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let path: PathBuf = this.read_os_str_from_c_str(pathname_scalar)?.into(); // `flags` should be a `c_int` but the `syscall` function provides an `isize`. - let flags: i32 = this - .read_scalar(flags_op)? - .to_machine_isize(&*this.tcx)? - .try_into() - .map_err(|e| err_unsup_format!( - "Failed to convert pointer sized operand to integer: {}", - e - ))?; + let flags: i32 = + this.read_scalar(flags_op)?.to_machine_isize(&*this.tcx)?.try_into().map_err(|e| { + err_unsup_format!("Failed to convert pointer sized operand to integer: {}", e) + })?; // `dirfd` should be a `c_int` but the `syscall` function provides an `isize`. - let dirfd: i32 = this - .read_scalar(dirfd_op)? - .to_machine_isize(&*this.tcx)? - .try_into() - .map_err(|e| err_unsup_format!( - "Failed to convert pointer sized operand to integer: {}", - e - ))?; + let dirfd: i32 = + this.read_scalar(dirfd_op)?.to_machine_isize(&*this.tcx)?.try_into().map_err(|e| { + err_unsup_format!("Failed to convert pointer sized operand to integer: {}", e) + })?; // we only support interpreting `path` as an absolute directory or as a directory relative // to `dirfd` when the latter is `AT_FDCWD`. The behavior of `statx` with a relative path // and a directory file descriptor other than `AT_FDCWD` is specified but it cannot be // tested from `libstd`. If you found this error, please open an issue reporting it. - if !(path.is_absolute() || dirfd == this.eval_libc_i32("AT_FDCWD")?) - { + if !(path.is_absolute() || dirfd == this.eval_libc_i32("AT_FDCWD")?) { throw_unsup_format!( "Using statx with a relative path and a file descriptor different from `AT_FDCWD` is not supported" ) @@ -368,29 +359,30 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // the owner, its group and other users. Given that we can only provide the file type // without using platform specific methods, we only set the bits corresponding to the file // type. This should be an `__u16` but `libc` provides its values as `u32`. - let mode: u16 = this.eval_libc(mode_name)? - .to_u32()? - .try_into() - .unwrap_or_else(|_| bug!("libc contains bad value for `{}` constant", mode_name)); + let mode: u16 = this + .eval_libc(mode_name)? + .to_u32()? + .try_into() + .unwrap_or_else(|_| bug!("libc contains bad value for `{}` constant", mode_name)); let size = metadata.len(); let (access_sec, access_nsec) = extract_sec_and_nsec( metadata.accessed(), &mut mask, - this.eval_libc("STATX_ATIME")?.to_u32()? + this.eval_libc("STATX_ATIME")?.to_u32()?, )?; let (created_sec, created_nsec) = extract_sec_and_nsec( metadata.created(), &mut mask, - this.eval_libc("STATX_BTIME")?.to_u32()? + this.eval_libc("STATX_BTIME")?.to_u32()?, )?; let (modified_sec, modified_nsec) = extract_sec_and_nsec( metadata.modified(), &mut mask, - this.eval_libc("STATX_MTIME")?.to_u32()? + this.eval_libc("STATX_MTIME")?.to_u32()?, )?; let __u32_layout = this.libc_ty_layout("__u32")?; @@ -401,16 +393,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // zero for the unavailable fields. // FIXME: Provide more fields using platform specific methods. let imms = [ - immty_from_uint_checked(mask, __u32_layout)?, // stx_mask + immty_from_uint_checked(mask, __u32_layout)?, // stx_mask immty_from_uint_checked(0u128, __u32_layout)?, // stx_blksize immty_from_uint_checked(0u128, __u64_layout)?, // stx_attributes immty_from_uint_checked(0u128, __u32_layout)?, // stx_nlink immty_from_uint_checked(0u128, __u32_layout)?, // stx_uid immty_from_uint_checked(0u128, __u32_layout)?, // stx_gid - immty_from_uint_checked(mode, __u16_layout)?, // stx_mode + immty_from_uint_checked(mode, __u16_layout)?, // stx_mode immty_from_uint_checked(0u128, __u16_layout)?, // statx padding immty_from_uint_checked(0u128, __u64_layout)?, // stx_ino - immty_from_uint_checked(size, __u64_layout)?, // stx_size + immty_from_uint_checked(size, __u64_layout)?, // stx_size immty_from_uint_checked(0u128, __u64_layout)?, // stx_blocks immty_from_uint_checked(0u128, __u64_layout)?, // stx_attributes immty_from_uint_checked(access_sec, __u64_layout)?, // stx_atime.tv_sec @@ -451,7 +443,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Extracts the number of seconds and nanoseconds elapsed between `time` and the unix epoch, and // then sets the `mask` bits determined by `flag` when `time` is Ok. If `time` is an error, it // returns `(0, 0)` without setting any bits. -fn extract_sec_and_nsec<'tcx>(time: std::io::Result, mask: &mut u32, flag: u32) -> InterpResult<'tcx, (u64, u32)> { +fn extract_sec_and_nsec<'tcx>( + time: std::io::Result, + mask: &mut u32, + flag: u32, +) -> InterpResult<'tcx, (u64, u32)> { if let Ok(time) = time { let duration = system_time_to_duration(&time)?; *mask |= flag; diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 57b77a8b74902..bde2dd4655bf7 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -1,10 +1,10 @@ use std::iter; -use rustc_apfloat::Float; use rustc::mir; use rustc::mir::interpret::{InterpResult, PointerArithmetic}; -use rustc::ty::layout::{self, LayoutOf, Size, Align}; use rustc::ty; +use rustc::ty::layout::{self, Align, LayoutOf, Size}; +use rustc_apfloat::Float; use syntax::source_map::Span; use crate::*; @@ -17,13 +17,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx instance: ty::Instance<'tcx>, args: &[OpTy<'tcx, Tag>], ret: Option<(PlaceTy<'tcx, Tag>, mir::BasicBlock)>, - unwind: Option + unwind: Option, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); if this.emulate_intrinsic(span, instance, args, ret)? { return Ok(()); } - let tcx = &{this.tcx.tcx}; + let tcx = &{ this.tcx.tcx }; let substs = instance.substs; // All these intrinsics take raw pointers, so if we access memory directly @@ -37,13 +37,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx throw_machine_stop!(TerminationInfo::Abort); } "miri_start_panic" => return this.handle_miri_start_panic(args, unwind), - _ => { + _ => if let Some(p) = ret { p } else { throw_unsup_format!("unimplemented (diverging) intrinsic: {}", intrinsic_name); - } - } + }, }; match intrinsic_name { @@ -75,9 +74,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.copy_op(args[1], place.into())?; } - "atomic_load" | - "atomic_load_relaxed" | - "atomic_load_acq" => { + #[rustfmt::skip] + | "atomic_load" + | "atomic_load_relaxed" + | "atomic_load_acq" + => { let place = this.deref_operand(args[0])?; let val = this.read_scalar(place.into())?; // make sure it fits into a scalar; otherwise it cannot be atomic @@ -90,9 +91,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(val, dest)?; } - "atomic_store" | - "atomic_store_relaxed" | - "atomic_store_rel" => { + #[rustfmt::skip] + | "atomic_store" + | "atomic_store_relaxed" + | "atomic_store_rel" + => { let place = this.deref_operand(args[0])?; let val = this.read_scalar(args[1])?; // make sure it fits into a scalar; otherwise it cannot be atomic @@ -105,10 +108,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(val, place.into())?; } - "atomic_fence_acq" | - "atomic_fence_rel" | - "atomic_fence_acqrel" | - "atomic_fence" => { + #[rustfmt::skip] + | "atomic_fence_acq" + | "atomic_fence_rel" + | "atomic_fence_acqrel" + | "atomic_fence" + => { // we are inherently singlethreaded and singlecored, this is a nop } @@ -139,46 +144,49 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let align = Align::from_bytes(place.layout.size.bytes()).unwrap(); this.memory.check_ptr_access(place.ptr, place.layout.size, align)?; - // binary_op will bail if either of them is not a scalar + // `binary_op` will bail if either of them is not a scalar. let eq = this.overflowing_binary_op(mir::BinOp::Eq, old, expect_old)?.0; let res = Immediate::ScalarPair(old.to_scalar_or_undef(), eq.into()); - this.write_immediate(res, dest)?; // old value is returned - // update ptr depending on comparison + // Return old value. + this.write_immediate(res, dest)?; + // Update ptr depending on comparison. if eq.to_bool()? { this.write_scalar(new, place.into())?; } } - "atomic_or" | - "atomic_or_acq" | - "atomic_or_rel" | - "atomic_or_acqrel" | - "atomic_or_relaxed" | - "atomic_xor" | - "atomic_xor_acq" | - "atomic_xor_rel" | - "atomic_xor_acqrel" | - "atomic_xor_relaxed" | - "atomic_and" | - "atomic_and_acq" | - "atomic_and_rel" | - "atomic_and_acqrel" | - "atomic_and_relaxed" | - "atomic_nand" | - "atomic_nand_acq" | - "atomic_nand_rel" | - "atomic_nand_acqrel" | - "atomic_nand_relaxed" | - "atomic_xadd" | - "atomic_xadd_acq" | - "atomic_xadd_rel" | - "atomic_xadd_acqrel" | - "atomic_xadd_relaxed" | - "atomic_xsub" | - "atomic_xsub_acq" | - "atomic_xsub_rel" | - "atomic_xsub_acqrel" | - "atomic_xsub_relaxed" => { + #[rustfmt::skip] + | "atomic_or" + | "atomic_or_acq" + | "atomic_or_rel" + | "atomic_or_acqrel" + | "atomic_or_relaxed" + | "atomic_xor" + | "atomic_xor_acq" + | "atomic_xor_rel" + | "atomic_xor_acqrel" + | "atomic_xor_relaxed" + | "atomic_and" + | "atomic_and_acq" + | "atomic_and_rel" + | "atomic_and_acqrel" + | "atomic_and_relaxed" + | "atomic_nand" + | "atomic_nand_acq" + | "atomic_nand_rel" + | "atomic_nand_acqrel" + | "atomic_nand_relaxed" + | "atomic_xadd" + | "atomic_xadd_acq" + | "atomic_xadd_rel" + | "atomic_xadd_acqrel" + | "atomic_xadd_relaxed" + | "atomic_xsub" + | "atomic_xsub_acq" + | "atomic_xsub_rel" + | "atomic_xsub_acqrel" + | "atomic_xsub_relaxed" + => { let place = this.deref_operand(args[0])?; if !place.layout.ty.is_integral() { bug!("Atomic arithmetic operations only work on integer types"); @@ -204,18 +212,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx }; // Atomics wrap around on overflow. let val = this.binary_op(op, old, rhs)?; - let val = if neg { - this.unary_op(mir::UnOp::Not, val)? - } else { - val - }; + let val = if neg { this.unary_op(mir::UnOp::Not, val)? } else { val }; this.write_immediate(*val, place.into())?; } "breakpoint" => unimplemented!(), // halt miri - "copy" | - "copy_nonoverlapping" => { + #[rustfmt::skip] + | "copy" + | "copy_nonoverlapping" + => { let elem_ty = substs.type_at(0); let elem_layout = this.layout_of(elem_ty)?; let elem_size = elem_layout.size.bytes(); @@ -244,8 +250,21 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_uint(discr_val, dest.layout.size), dest)?; } - "sinf32" | "fabsf32" | "cosf32" | "sqrtf32" | "expf32" | "exp2f32" | "logf32" | - "log10f32" | "log2f32" | "floorf32" | "ceilf32" | "truncf32" | "roundf32" => { + #[rustfmt::skip] + | "sinf32" + | "fabsf32" + | "cosf32" + | "sqrtf32" + | "expf32" + | "exp2f32" + | "logf32" + | "log10f32" + | "log2f32" + | "floorf32" + | "ceilf32" + | "truncf32" + | "roundf32" + => { // FIXME: Using host floats. let f = f32::from_bits(this.read_scalar(args[0])?.to_u32()?); let f = match intrinsic_name { @@ -267,8 +286,21 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_u32(f.to_bits()), dest)?; } - "sinf64" | "fabsf64" | "cosf64" | "sqrtf64" | "expf64" | "exp2f64" | "logf64" | - "log10f64" | "log2f64" | "floorf64" | "ceilf64" | "truncf64" | "roundf64" => { + #[rustfmt::skip] + | "sinf64" + | "fabsf64" + | "cosf64" + | "sqrtf64" + | "expf64" + | "exp2f64" + | "logf64" + | "log10f64" + | "log2f64" + | "floorf64" + | "ceilf64" + | "truncf64" + | "roundf64" + => { // FIXME: Using host floats. let f = f64::from_bits(this.read_scalar(args[0])?.to_u64()?); let f = match intrinsic_name { @@ -290,7 +322,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_u64(f.to_bits()), dest)?; } - "fadd_fast" | "fsub_fast" | "fmul_fast" | "fdiv_fast" | "frem_fast" => { + #[rustfmt::skip] + | "fadd_fast" + | "fsub_fast" + | "fmul_fast" + | "fdiv_fast" + | "frem_fast" + => { let a = this.read_immediate(args[0])?; let b = this.read_immediate(args[1])?; let op = match intrinsic_name { @@ -304,7 +342,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.binop_ignore_overflow(op, a, b, dest)?; } - "minnumf32" | "maxnumf32" | "copysignf32" => { + #[rustfmt::skip] + | "minnumf32" + | "maxnumf32" + | "copysignf32" + => { let a = this.read_scalar(args[0])?.to_f32()?; let b = this.read_scalar(args[1])?.to_f32()?; let res = match intrinsic_name { @@ -316,7 +358,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_f32(res), dest)?; } - "minnumf64" | "maxnumf64" | "copysignf64" => { + #[rustfmt::skip] + | "minnumf64" + | "maxnumf64" + | "copysignf64" + => { let a = this.read_scalar(args[0])?.to_f64()?; let b = this.read_scalar(args[1])?.to_f64()?; let res = match intrinsic_name { @@ -329,15 +375,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "exact_div" => - this.exact_div( - this.read_immediate(args[0])?, - this.read_immediate(args[1])?, - dest, - )?, + this.exact_div(this.read_immediate(args[0])?, this.read_immediate(args[1])?, dest)?, "forget" => {} - "likely" | "unlikely" => { + #[rustfmt::skip] + | "likely" + | "unlikely" + => { // These just return their argument let b = this.read_immediate(args[0])?; this.write_immediate(*b, dest)?; @@ -365,7 +410,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Do it in memory let mplace = this.force_allocation(dest)?; mplace.meta.unwrap_none(); // must be sized - this.memory.write_bytes(mplace.ptr, iter::repeat(0u8).take(dest.layout.size.bytes() as usize))?; + this.memory.write_bytes( + mplace.ptr, + iter::repeat(0u8).take(dest.layout.size.bytes() as usize), + )?; } } } @@ -405,20 +453,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // FIXME: Using host floats. let f = f32::from_bits(this.read_scalar(args[0])?.to_u32()?); let f2 = f32::from_bits(this.read_scalar(args[1])?.to_u32()?); - this.write_scalar( - Scalar::from_u32(f.powf(f2).to_bits()), - dest, - )?; + this.write_scalar(Scalar::from_u32(f.powf(f2).to_bits()), dest)?; } "powf64" => { // FIXME: Using host floats. let f = f64::from_bits(this.read_scalar(args[0])?.to_u64()?); let f2 = f64::from_bits(this.read_scalar(args[1])?.to_u64()?); - this.write_scalar( - Scalar::from_u64(f.powf(f2).to_bits()), - dest, - )?; + this.write_scalar(Scalar::from_u64(f.powf(f2).to_bits()), dest)?; } "fmaf32" => { @@ -426,10 +468,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let b = this.read_scalar(args[1])?.to_f32()?; let c = this.read_scalar(args[2])?.to_f32()?; let res = a.mul_add(b, c).value; - this.write_scalar( - Scalar::from_f32(res), - dest, - )?; + this.write_scalar(Scalar::from_f32(res), dest)?; } "fmaf64" => { @@ -437,53 +476,42 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let b = this.read_scalar(args[1])?.to_f64()?; let c = this.read_scalar(args[2])?.to_f64()?; let res = a.mul_add(b, c).value; - this.write_scalar( - Scalar::from_f64(res), - dest, - )?; + this.write_scalar(Scalar::from_f64(res), dest)?; } "powif32" => { // FIXME: Using host floats. let f = f32::from_bits(this.read_scalar(args[0])?.to_u32()?); let i = this.read_scalar(args[1])?.to_i32()?; - this.write_scalar( - Scalar::from_u32(f.powi(i).to_bits()), - dest, - )?; + this.write_scalar(Scalar::from_u32(f.powi(i).to_bits()), dest)?; } "powif64" => { // FIXME: Using host floats. let f = f64::from_bits(this.read_scalar(args[0])?.to_u64()?); let i = this.read_scalar(args[1])?.to_i32()?; - this.write_scalar( - Scalar::from_u64(f.powi(i).to_bits()), - dest, - )?; + this.write_scalar(Scalar::from_u64(f.powi(i).to_bits()), dest)?; } "size_of_val" => { let mplace = this.deref_operand(args[0])?; - let (size, _) = this.size_and_align_of_mplace(mplace)? + let (size, _) = this + .size_and_align_of_mplace(mplace)? .expect("size_of_val called on extern type"); let ptr_size = this.pointer_size(); - this.write_scalar( - Scalar::from_uint(size.bytes() as u128, ptr_size), - dest, - )?; + this.write_scalar(Scalar::from_uint(size.bytes() as u128, ptr_size), dest)?; } - "min_align_of_val" | - "align_of_val" => { + #[rustfmt::skip] + | "min_align_of_val" + | "align_of_val" + => { let mplace = this.deref_operand(args[0])?; - let (_, align) = this.size_and_align_of_mplace(mplace)? + let (_, align) = this + .size_and_align_of_mplace(mplace)? .expect("size_of_val called on extern type"); let ptr_size = this.pointer_size(); - this.write_scalar( - Scalar::from_uint(align.bytes(), ptr_size), - dest, - )?; + this.write_scalar(Scalar::from_uint(align.bytes(), ptr_size), dest)?; } "unchecked_div" => { @@ -493,12 +521,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if rval == 0 { throw_ub_format!("Division by 0 in unchecked_div"); } - this.binop_ignore_overflow( - mir::BinOp::Div, - l, - r, - dest, - )?; + this.binop_ignore_overflow(mir::BinOp::Div, l, r, dest)?; } "unchecked_rem" => { @@ -508,15 +531,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if rval == 0 { throw_ub_format!("Division by 0 in unchecked_rem"); } - this.binop_ignore_overflow( - mir::BinOp::Rem, - l, - r, - dest, - )?; + this.binop_ignore_overflow(mir::BinOp::Rem, l, r, dest)?; } - "unchecked_add" | "unchecked_sub" | "unchecked_mul" => { + #[rustfmt::skip] + | "unchecked_add" + | "unchecked_sub" + | "unchecked_mul" + => { let l = this.read_immediate(args[0])?; let r = this.read_immediate(args[1])?; let op = match intrinsic_name { @@ -555,9 +577,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx mplace.meta.unwrap_none(); let ptr = mplace.ptr.to_ptr()?; // We know the return place is in-bounds - this.memory - .get_raw_mut(ptr.alloc_id)? - .mark_definedness(ptr, dest.layout.size, false); + this.memory.get_raw_mut(ptr.alloc_id)?.mark_definedness( + ptr, + dest.layout.size, + false, + ); } } } @@ -570,7 +594,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let ptr = this.read_scalar(args[0])?.not_undef()?; let count = this.read_scalar(args[2])?.to_machine_usize(this)?; let byte_count = ty_layout.size * count; - this.memory.write_bytes(ptr, iter::repeat(val_byte).take(byte_count.bytes() as usize))?; + this.memory + .write_bytes(ptr, iter::repeat(val_byte).take(byte_count.bytes() as usize))?; } name => throw_unsup_format!("unimplemented intrinsic: {}", name), diff --git a/src/shims/mod.rs b/src/shims/mod.rs index 06ef58eaf5267..2889807bf76aa 100644 --- a/src/shims/mod.rs +++ b/src/shims/mod.rs @@ -1,14 +1,14 @@ pub mod dlsym; pub mod env; pub mod foreign_items; -pub mod intrinsics; -pub mod tls; pub mod fs; -pub mod time; +pub mod intrinsics; pub mod panic; +pub mod time; +pub mod tls; -use rustc::{mir, ty}; use crate::*; +use rustc::{mir, ty}; impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { @@ -17,14 +17,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx instance: ty::Instance<'tcx>, args: &[OpTy<'tcx, Tag>], ret: Option<(PlaceTy<'tcx, Tag>, mir::BasicBlock)>, - unwind: Option + unwind: Option, ) -> InterpResult<'tcx, Option<&'mir mir::Body<'tcx>>> { let this = self.eval_context_mut(); - trace!( - "eval_fn_call: {:#?}, {:?}", - instance, - ret.map(|p| *p.0) - ); + trace!("eval_fn_call: {:#?}, {:?}", instance, ret.map(|p| *p.0)); // There are some more lang items we want to hook that CTFE does not hook (yet). if this.tcx.lang_items().align_offset_fn() == Some(instance.def.def_id()) { @@ -59,10 +55,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, Option> { let this = self.eval_context_mut(); - let req_align = this.force_bits( - this.read_scalar(align_op)?.not_undef()?, - this.pointer_size(), - )? as usize; + let req_align = this + .force_bits(this.read_scalar(align_op)?.not_undef()?, this.pointer_size())? + as usize; // FIXME: This should actually panic in the interpreted program if !req_align.is_power_of_two() { @@ -72,7 +67,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let ptr_scalar = this.read_scalar(ptr_op)?.not_undef()?; if let Ok(ptr) = this.force_ptr(ptr_scalar) { - let cur_align = this.memory.get_size_and_align(ptr.alloc_id, AllocCheck::MaybeDead)?.1.bytes() as usize; + let cur_align = + this.memory.get_size_and_align(ptr.alloc_id, AllocCheck::MaybeDead)?.1.bytes() + as usize; if cur_align >= req_align { // if the allocation alignment is at least the required alignment we use the // libcore implementation diff --git a/src/shims/panic.rs b/src/shims/panic.rs index fc3339352a982..f242f41f6f96f 100644 --- a/src/shims/panic.rs +++ b/src/shims/panic.rs @@ -11,10 +11,10 @@ //! gets popped *during unwinding*, we take the panic payload and store it according to the extra //! metadata we remembered when pushing said frame. -use syntax::source_map::Span; use rustc::mir; use rustc::ty::{self, layout::LayoutOf}; use rustc_target::spec::PanicStrategy; +use syntax::source_map::Span; use crate::*; @@ -35,13 +35,12 @@ pub struct CatchUnwindData<'tcx> { impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { - /// Handles the special "miri_start_panic" intrinsic, which is called /// by libpanic_unwind to delegate the actual unwinding process to Miri. fn handle_miri_start_panic( &mut self, args: &[OpTy<'tcx, Tag>], - unwind: Option + unwind: Option, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); @@ -49,12 +48,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Get the raw pointer stored in arg[0] (the panic payload). let scalar = this.read_immediate(args[0])?; - assert!(this.machine.panic_payload.is_none(), "the panic runtime should avoid double-panics"); + assert!( + this.machine.panic_payload.is_none(), + "the panic runtime should avoid double-panics" + ); this.machine.panic_payload = Some(scalar); // Jump to the unwind block to begin unwinding. this.unwind_to_block(unwind); - return Ok(()) + return Ok(()); } fn handle_catch_panic( @@ -64,7 +66,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ret: mir::BasicBlock, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - let tcx = &{this.tcx.tcx}; + let tcx = &{ this.tcx.tcx }; // fn __rust_maybe_catch_panic( // f: fn(*mut u8), @@ -82,8 +84,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Now we make a function call, and pass `f_arg` as first and only argument. let f_instance = this.memory.get_fn(f)?.as_instance()?; trace!("__rust_maybe_catch_panic: {:?}", f_instance); - let ret_place = - MPlaceTy::dangling(this.layout_of(tcx.mk_unit())?, this).into(); + let ret_place = MPlaceTy::dangling(this.layout_of(tcx.mk_unit())?, this).into(); this.call_function( f_instance, &[f_arg.into()], @@ -99,11 +100,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // This lets `handle_stack_pop` (below) know that we should stop unwinding // when we pop this frame. if this.tcx.tcx.sess.panic_strategy() == PanicStrategy::Unwind { - this.frame_mut().extra.catch_panic = Some(CatchUnwindData { - data_place, - vtable_place, - dest, - }) + this.frame_mut().extra.catch_panic = + Some(CatchUnwindData { data_place, vtable_place, dest }) } return Ok(()); @@ -112,7 +110,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn handle_stack_pop( &mut self, mut extra: FrameData<'tcx>, - unwinding: bool + unwinding: bool, ) -> InterpResult<'tcx, StackPopInfo> { let this = self.eval_context_mut(); diff --git a/src/shims/time.rs b/src/shims/time.rs index da9ea07c4f257..a7d51eaa2e0f7 100644 --- a/src/shims/time.rs +++ b/src/shims/time.rs @@ -9,10 +9,9 @@ fn get_time<'tcx>() -> InterpResult<'tcx, Duration> { system_time_to_duration(&SystemTime::now()) } -// Returns the time elapsed between the provided time and the unix epoch as a `Duration`. +/// Returns the time elapsed between the provided time and the unix epoch as a `Duration`. pub fn system_time_to_duration<'tcx>(time: &SystemTime) -> InterpResult<'tcx, Duration> { - time - .duration_since(SystemTime::UNIX_EPOCH) + time.duration_since(SystemTime::UNIX_EPOCH) .map_err(|_| err_unsup_format!("Times before the Unix epoch are not supported").into()) } diff --git a/src/shims/tls.rs b/src/shims/tls.rs index 420fd63a6181e..cdfc0bcda8b63 100644 --- a/src/shims/tls.rs +++ b/src/shims/tls.rs @@ -2,14 +2,10 @@ use std::collections::BTreeMap; -use rustc_target::abi::LayoutOf; use rustc::{ty, ty::layout::HasDataLayout}; +use rustc_target::abi::LayoutOf; -use crate::{ - InterpResult, StackPopCleanup, - MPlaceTy, Scalar, Tag, - HelpersEvalContextExt, -}; +use crate::{HelpersEvalContextExt, InterpResult, MPlaceTy, Scalar, StackPopCleanup, Tag}; pub type TlsKey = u128; @@ -41,19 +37,10 @@ impl<'tcx> Default for TlsData<'tcx> { } impl<'tcx> TlsData<'tcx> { - pub fn create_tls_key( - &mut self, - dtor: Option>, - ) -> TlsKey { + pub fn create_tls_key(&mut self, dtor: Option>) -> TlsKey { let new_key = self.next_key; self.next_key += 1; - self.keys.insert( - new_key, - TlsEntry { - data: None, - dtor, - }, - ).unwrap_none(); + self.keys.insert(new_key, TlsEntry { data: None, dtor }).unwrap_none(); trace!("New TLS key allocated: {} with dtor {:?}", new_key, dtor); new_key } diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 8782eb83d1835..fb68f46d379e1 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -3,17 +3,17 @@ use std::cell::RefCell; use std::collections::{HashMap, HashSet}; -use std::rc::Rc; use std::fmt; use std::num::NonZeroU64; +use std::rc::Rc; -use rustc::ty::{self, layout::Size}; -use rustc::hir::Mutability::{Mutable, Immutable}; +use rustc::hir::Mutability::{Immutable, Mutable}; use rustc::mir::RetagKind; +use rustc::ty::{self, layout::Size}; use crate::{ - InterpResult, HelpersEvalContextExt, TerminationInfo, - MemoryKind, MiriMemoryKind, RangeMap, AllocId, Pointer, Immediate, ImmTy, PlaceTy, MPlaceTy, + AllocId, HelpersEvalContextExt, ImmTy, Immediate, InterpResult, MPlaceTy, MemoryKind, + MiriMemoryKind, PlaceTy, Pointer, RangeMap, TerminationInfo, }; pub type PtrId = NonZeroU64; @@ -82,7 +82,6 @@ pub struct Stack { borrows: Vec, } - /// Extra per-allocation state. #[derive(Clone, Debug)] pub struct Stacks { @@ -217,7 +216,8 @@ impl Permission { /// This defines for a given permission, whether it permits the given kind of access. fn grants(self, access: AccessKind) -> bool { // Disabled grants nothing. Otherwise, all items grant read access, and except for SharedReadOnly they grant write access. - self != Permission::Disabled && (access == AccessKind::Read || self != Permission::SharedReadOnly) + self != Permission::Disabled + && (access == AccessKind::Read || self != Permission::SharedReadOnly) } } @@ -226,17 +226,16 @@ impl<'tcx> Stack { /// Find the item granting the given kind of access to the given tag, and return where /// it is on the stack. fn find_granting(&self, access: AccessKind, tag: Tag) -> Option { - self.borrows.iter() + self.borrows + .iter() .enumerate() // we also need to know *where* in the stack .rev() // search top-to-bottom // Return permission of first item that grants access. // We require a permission with the right tag, ensuring U3 and F3. - .find_map(|(idx, item)| - if tag == item.tag && item.perm.grants(access) { - Some(idx) - } else { - None - } + .find_map( + |(idx, item)| { + if tag == item.tag && item.perm.grants(access) { Some(idx) } else { None } + }, ) } @@ -245,13 +244,10 @@ impl<'tcx> Stack { fn find_first_write_incompatible(&self, granting: usize) -> usize { let perm = self.borrows[granting].perm; match perm { - Permission::SharedReadOnly => - bug!("Cannot use SharedReadOnly for writing"), - Permission::Disabled => - bug!("Cannot use Disabled for anything"), - Permission::Unique => - // On a write, everything above us is incompatible. - granting + 1, + Permission::SharedReadOnly => bug!("Cannot use SharedReadOnly for writing"), + Permission::Disabled => bug!("Cannot use Disabled for anything"), + // On a write, everything above us is incompatible. + Permission::Unique => granting + 1, Permission::SharedReadWrite => { // The SharedReadWrite *just* above us are compatible, to skip those. let mut idx = granting + 1; @@ -285,7 +281,8 @@ impl<'tcx> Stack { ))); } else { throw_ub!(UbExperimental(format!( - "deallocating while item is protected: {:?}", item + "deallocating while item is protected: {:?}", + item ))); } } @@ -295,20 +292,16 @@ impl<'tcx> Stack { /// Test if a memory `access` using pointer tagged `tag` is granted. /// If yes, return the index of the item that granted it. - fn access( - &mut self, - access: AccessKind, - tag: Tag, - global: &GlobalState, - ) -> InterpResult<'tcx> { + fn access(&mut self, access: AccessKind, tag: Tag, global: &GlobalState) -> InterpResult<'tcx> { // Two main steps: Find granting item, remove incompatible items above. // Step 1: Find granting item. - let granting_idx = self.find_granting(access, tag) - .ok_or_else(|| err_ub!(UbExperimental(format!( + let granting_idx = self.find_granting(access, tag).ok_or_else(|| { + err_ub!(UbExperimental(format!( "no item granting {} to tag {:?} found in borrow stack", access, tag, - ))))?; + ))) + })?; // Step 2: Remove incompatible items above them. Make sure we do not remove protected // items. Behavior differs for reads and writes. @@ -329,7 +322,7 @@ impl<'tcx> Stack { // This pattern occurs a lot in the standard library: create a raw pointer, then also create a shared // reference and use that. // We *disable* instead of removing `Unique` to avoid "connecting" two neighbouring blocks of SRWs. - for idx in (granting_idx+1 .. self.borrows.len()).rev() { + for idx in ((granting_idx + 1)..self.borrows.len()).rev() { let item = &mut self.borrows[idx]; if item.perm == Permission::Unique { trace!("access: disabling item {:?}", item); @@ -345,17 +338,14 @@ impl<'tcx> Stack { /// Deallocate a location: Like a write access, but also there must be no /// active protectors at all because we will remove all items. - fn dealloc( - &mut self, - tag: Tag, - global: &GlobalState, - ) -> InterpResult<'tcx> { + fn dealloc(&mut self, tag: Tag, global: &GlobalState) -> InterpResult<'tcx> { // Step 1: Find granting item. - self.find_granting(AccessKind::Write, tag) - .ok_or_else(|| err_ub!(UbExperimental(format!( + self.find_granting(AccessKind::Write, tag).ok_or_else(|| { + err_ub!(UbExperimental(format!( "no item granting write access for deallocation to tag {:?} found in borrow stack", tag, - ))))?; + ))) + })?; // Step 2: Remove all items. Also checks for protectors. for item in self.borrows.drain(..).rev() { @@ -369,18 +359,10 @@ impl<'tcx> Stack { /// `weak` controls whether this operation is weak or strong: weak granting does not act as /// an access, and they add the new item directly on top of the one it is derived /// from instead of all the way at the top of the stack. - fn grant( - &mut self, - derived_from: Tag, - new: Item, - global: &GlobalState, - ) -> InterpResult<'tcx> { + fn grant(&mut self, derived_from: Tag, new: Item, global: &GlobalState) -> InterpResult<'tcx> { // Figure out which access `perm` corresponds to. - let access = if new.perm.grants(AccessKind::Write) { - AccessKind::Write - } else { - AccessKind::Read - }; + let access = + if new.perm.grants(AccessKind::Write) { AccessKind::Write } else { AccessKind::Read }; // Now we figure out which item grants our parent (`derived_from`) this kind of access. // We use that to determine where to put the new item. let granting_idx = self.find_granting(access, derived_from) @@ -392,7 +374,10 @@ impl<'tcx> Stack { // Either way, we ensure that we insert the new item in a way such that between // `derived_from` and the new one, there are only items *compatible with* `derived_from`. let new_idx = if new.perm == Permission::SharedReadWrite { - assert!(access == AccessKind::Write, "this case only makes sense for stack-like accesses"); + assert!( + access == AccessKind::Write, + "this case only makes sense for stack-like accesses" + ); // SharedReadWrite can coexist with "existing loans", meaning they don't act like a write // access. Instead of popping the stack, we insert the item at the place the stack would // be popped to (i.e., we insert it above all the write-compatible items). @@ -412,7 +397,7 @@ impl<'tcx> Stack { }; // Put the new item there. As an optimization, deduplicate if it is equal to one of its new neighbors. - if self.borrows[new_idx-1] == new || self.borrows.get(new_idx) == Some(&new) { + if self.borrows[new_idx - 1] == new || self.borrows.get(new_idx) == Some(&new) { // Optimization applies, done. trace!("reborrow: avoiding adding redundant item {:?}", new); } else { @@ -428,21 +413,11 @@ impl<'tcx> Stack { /// Map per-stack operations to higher-level per-location-range operations. impl<'tcx> Stacks { /// Creates new stack with initial tag. - fn new( - size: Size, - perm: Permission, - tag: Tag, - extra: MemoryExtra, - ) -> Self { + fn new(size: Size, perm: Permission, tag: Tag, extra: MemoryExtra) -> Self { let item = Item { perm, tag, protector: None }; - let stack = Stack { - borrows: vec![item], - }; + let stack = Stack { borrows: vec![item] }; - Stacks { - stacks: RefCell::new(RangeMap::new(size, stack)), - global: extra, - } + Stacks { stacks: RefCell::new(RangeMap::new(size, stack)), global: extra } } /// Call `f` on every stack in the range. @@ -470,33 +445,27 @@ impl Stacks { kind: MemoryKind, ) -> (Self, Tag) { let (tag, perm) = match kind { - MemoryKind::Stack => - // New unique borrow. This tag is not accessible by the program, - // so it will only ever be used when using the local directly (i.e., - // not through a pointer). That is, whenever we directly write to a local, this will pop - // everything else off the stack, invalidating all previous pointers, - // and in particular, *all* raw pointers. - (Tag::Tagged(extra.borrow_mut().new_ptr()), Permission::Unique), + // New unique borrow. This tag is not accessible by the program, + // so it will only ever be used when using the local directly (i.e., + // not through a pointer). That is, whenever we directly write to a local, this will pop + // everything else off the stack, invalidating all previous pointers, + // and in particular, *all* raw pointers. + MemoryKind::Stack => (Tag::Tagged(extra.borrow_mut().new_ptr()), Permission::Unique), + // Static memory can be referenced by "global" pointers from `tcx`. + // Thus we call `static_base_ptr` such that the global pointers get the same tag + // as what we use here. + // The base pointer is not unique, so the base permission is `SharedReadWrite`. MemoryKind::Machine(MiriMemoryKind::Static) => - // Static memory can be referenced by "global" pointers from `tcx`. - // Thus we call `static_base_ptr` such that the global pointers get the same tag - // as what we use here. - // The base pointer is not unique, so the base permission is `SharedReadWrite`. (extra.borrow_mut().static_base_ptr(id), Permission::SharedReadWrite), - _ => - // Everything else we handle entirely untagged for now. - // FIXME: experiment with more precise tracking. - (Tag::Untagged, Permission::SharedReadWrite), + // Everything else we handle entirely untagged for now. + // FIXME: experiment with more precise tracking. + _ => (Tag::Untagged, Permission::SharedReadWrite), }; (Stacks::new(size, perm, tag, extra), tag) } #[inline(always)] - pub fn memory_read<'tcx>( - &self, - ptr: Pointer, - size: Size, - ) -> InterpResult<'tcx> { + pub fn memory_read<'tcx>(&self, ptr: Pointer, size: Size) -> InterpResult<'tcx> { trace!("read access with tag {:?}: {:?}, size {}", ptr.tag, ptr.erase_tag(), size.bytes()); self.for_each(ptr, size, |stack, global| { stack.access(AccessKind::Read, ptr.tag, global)?; @@ -505,11 +474,7 @@ impl Stacks { } #[inline(always)] - pub fn memory_written<'tcx>( - &mut self, - ptr: Pointer, - size: Size, - ) -> InterpResult<'tcx> { + pub fn memory_written<'tcx>(&mut self, ptr: Pointer, size: Size) -> InterpResult<'tcx> { trace!("write access with tag {:?}: {:?}, size {}", ptr.tag, ptr.erase_tag(), size.bytes()); self.for_each(ptr, size, |stack, global| { stack.access(AccessKind::Write, ptr.tag, global)?; @@ -524,9 +489,7 @@ impl Stacks { size: Size, ) -> InterpResult<'tcx> { trace!("deallocation with tag {:?}: {:?}, size {}", ptr.tag, ptr.erase_tag(), size.bytes()); - self.for_each(ptr, size, |stack, global| { - stack.dealloc(ptr.tag, global) - }) + self.for_each(ptr, size, |stack, global| stack.dealloc(ptr.tag, global)) } } @@ -545,12 +508,20 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); let protector = if protect { Some(this.frame().extra.call_id) } else { None }; let ptr = place.ptr.to_ptr().expect("we should have a proper pointer"); - trace!("reborrow: {} reference {:?} derived from {:?} (pointee {}): {:?}, size {}", - kind, new_tag, ptr.tag, place.layout.ty, ptr.erase_tag(), size.bytes()); + trace!( + "reborrow: {} reference {:?} derived from {:?} (pointee {}): {:?}, size {}", + kind, + new_tag, + ptr.tag, + place.layout.ty, + ptr.erase_tag(), + size.bytes() + ); // Get the allocation. It might not be mutable, so we cannot use `get_mut`. let extra = &this.memory.get_raw(ptr.alloc_id)?.extra; - let stacked_borrows = extra.stacked_borrows.as_ref().expect("we should have Stacked Borrows data"); + let stacked_borrows = + extra.stacked_borrows.as_ref().expect("we should have Stacked Borrows data"); // Update the stacks. // Make sure that raw pointers and mutable shared references are reborrowed "weak": // There could be existing unique pointers reborrowed from them that should remain valid! @@ -564,7 +535,11 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // We need a frozen-sensitive reborrow. return this.visit_freeze_sensitive(place, size, |cur_ptr, size, frozen| { // We are only ever `SharedReadOnly` inside the frozen bits. - let perm = if frozen { Permission::SharedReadOnly } else { Permission::SharedReadWrite }; + let perm = if frozen { + Permission::SharedReadOnly + } else { + Permission::SharedReadWrite + }; let item = Item { perm, tag: new_tag, protector }; stacked_borrows.for_each(cur_ptr, size, |stack, global| { stack.grant(cur_ptr.tag, item, global) @@ -573,9 +548,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } }; let item = Item { perm, tag: new_tag, protector }; - stacked_borrows.for_each(ptr, size, |stack, global| { - stack.grant(ptr.tag, item, global) - }) + stacked_borrows.for_each(ptr, size, |stack, global| stack.grant(ptr.tag, item, global)) } /// Retags an indidual pointer, returning the retagged version. @@ -589,7 +562,8 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); // We want a place for where the ptr *points to*, so we get one. let place = this.ref_to_mplace(val)?; - let size = this.size_and_align_of_mplace(place)? + let size = this + .size_and_align_of_mplace(place)? .map(|(size, _)| size) .unwrap_or_else(|| place.layout.size); // We can see dangling ptrs in here e.g. after a Box's `Unique` was @@ -622,11 +596,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { - fn retag( - &mut self, - kind: RetagKind, - place: PlaceTy<'tcx, Tag> - ) -> InterpResult<'tcx> { + fn retag(&mut self, kind: RetagKind, place: PlaceTy<'tcx, Tag>) -> InterpResult<'tcx> { let this = self.eval_context_mut(); // Determine mutability and whether to add a protector. // Cannot use `builtin_deref` because that reports *immutable* for `Box`, @@ -634,10 +604,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn qualify(ty: ty::Ty<'_>, kind: RetagKind) -> Option<(RefKind, bool)> { match ty.kind { // References are simple. - ty::Ref(_, _, Mutable) => - Some((RefKind::Unique { two_phase: kind == RetagKind::TwoPhase}, kind == RetagKind::FnEntry)), - ty::Ref(_, _, Immutable) => - Some((RefKind::Shared, kind == RetagKind::FnEntry)), + ty::Ref(_, _, Mutable) => Some(( + RefKind::Unique { two_phase: kind == RetagKind::TwoPhase }, + kind == RetagKind::FnEntry, + )), + ty::Ref(_, _, Immutable) => Some((RefKind::Shared, kind == RetagKind::FnEntry)), // Raw pointers need to be enabled. ty::RawPtr(tym) if kind == RetagKind::Raw => Some((RefKind::Raw { mutable: tym.mutbl == Mutable }, false)), diff --git a/tests/compiletest.rs b/tests/compiletest.rs index bc1ba2eda5687..eaaa87464dbf6 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -2,11 +2,11 @@ // Custom test runner, to avoid libtest being wrapped around compiletest which wraps libtest. #![test_runner(test_runner)] -use std::path::PathBuf; use std::env; +use std::path::PathBuf; -use compiletest_rs as compiletest; use colored::*; +use compiletest_rs as compiletest; fn miri_path() -> PathBuf { if rustc_test_suite().is_some() { @@ -57,12 +57,15 @@ fn run_tests(mode: &str, path: &str, target: &str, mut flags: Vec) { fn compile_fail(path: &str, target: &str, opt: bool) { let opt_str = if opt { " with optimizations" } else { "" }; - eprintln!("{}", format!( - "## Running compile-fail tests in {} against miri for target {}{}", - path, - target, - opt_str - ).green().bold()); + eprintln!( + "{}", + format!( + "## Running compile-fail tests in {} against miri for target {}{}", + path, target, opt_str + ) + .green() + .bold() + ); let mut flags = Vec::new(); if opt { @@ -76,12 +79,15 @@ fn compile_fail(path: &str, target: &str, opt: bool) { fn miri_pass(path: &str, target: &str, opt: bool) { let opt_str = if opt { " with optimizations" } else { "" }; - eprintln!("{}", format!( - "## Running run-pass tests in {} against miri for target {}{}", - path, - target, - opt_str - ).green().bold()); + eprintln!( + "{}", + format!( + "## Running run-pass tests in {} against miri for target {}{}", + path, target, opt_str + ) + .green() + .bold() + ); let mut flags = Vec::new(); if opt { From e325ad24f2ef170b2913d97a69da38ca664cb621 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 23 Dec 2019 17:44:02 +0100 Subject: [PATCH 1416/3747] support main functions with Result return type --- src/eval.rs | 5 ++--- tests/run-pass/main_result.rs | 3 +++ 2 files changed, 5 insertions(+), 3 deletions(-) create mode 100644 tests/run-pass/main_result.rs diff --git a/src/eval.rs b/src/eval.rs index 4ed1b272b2288..0cc302b967b29 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -62,9 +62,8 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( // Setup first stack-frame let main_instance = ty::Instance::mono(tcx, main_id); let main_mir = ecx.load_mir(main_instance.def, None)?; - - if !main_mir.return_ty().is_unit() || main_mir.arg_count != 0 { - throw_unsup_format!("miri does not support main functions without `fn()` type signatures"); + if main_mir.arg_count != 0 { + bug!("main function must not take any arguments"); } let start_id = tcx.lang_items().start_fn().unwrap(); diff --git a/tests/run-pass/main_result.rs b/tests/run-pass/main_result.rs new file mode 100644 index 0000000000000..078760ee6667c --- /dev/null +++ b/tests/run-pass/main_result.rs @@ -0,0 +1,3 @@ +fn main() -> Result<(), Box> { + Ok(()) +} From bac261573f3693d3cffdb6789b957bd31395997a Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Sun, 22 Dec 2019 10:05:52 +0100 Subject: [PATCH 1417/3747] Rustup to rustc 1.42.0-nightly (005cf38f7 2019-12-22) --- rust-version | 2 +- src/stacked_borrows.rs | 9 +++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/rust-version b/rust-version index f3c0b833d1a1f..999e8b0f8f730 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -9ff30a7810c586819a78188c173a7b74adbb9730 +9ae6cedb8d1e37469be1434642a3e403fce50a03 diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index fb68f46d379e1..d986a2db53837 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -7,7 +7,7 @@ use std::fmt; use std::num::NonZeroU64; use std::rc::Rc; -use rustc::hir::Mutability::{Immutable, Mutable}; +use rustc::hir::Mutability; use rustc::mir::RetagKind; use rustc::ty::{self, layout::Size}; @@ -604,14 +604,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn qualify(ty: ty::Ty<'_>, kind: RetagKind) -> Option<(RefKind, bool)> { match ty.kind { // References are simple. - ty::Ref(_, _, Mutable) => Some(( + ty::Ref(_, _, Mutability::Mut) => Some(( RefKind::Unique { two_phase: kind == RetagKind::TwoPhase }, kind == RetagKind::FnEntry, )), - ty::Ref(_, _, Immutable) => Some((RefKind::Shared, kind == RetagKind::FnEntry)), + ty::Ref(_, _, Mutability::Not) => + Some((RefKind::Shared, kind == RetagKind::FnEntry)), // Raw pointers need to be enabled. ty::RawPtr(tym) if kind == RetagKind::Raw => - Some((RefKind::Raw { mutable: tym.mutbl == Mutable }, false)), + Some((RefKind::Raw { mutable: tym.mutbl == Mutability::Mut }, false)), // Boxes do not get a protector: protectors reflect that references outlive the call // they were passed in to; that's just not the case for boxes. ty::Adt(..) if ty.is_box() => Some((RefKind::Unique { two_phase: false }, false)), From 2db6a3c04df4cdef73c5868e4fc8e5d3d766d3c7 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 24 Dec 2019 11:43:42 +0100 Subject: [PATCH 1418/3747] use new try_from methods --- src/helpers.rs | 25 ++++++------------------- 1 file changed, 6 insertions(+), 19 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index b6391ce2fde01..b631f404523f0 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -501,35 +501,22 @@ fn bytes_to_os_str<'tcx, 'a>(bytes: &'a [u8]) -> InterpResult<'tcx, &'a OsStr> { Ok(&OsStr::new(s)) } -// FIXME: change `ImmTy::from_int` so it returns an `InterpResult` instead and remove this -// function. pub fn immty_from_int_checked<'tcx>( int: impl Into, layout: TyLayout<'tcx>, ) -> InterpResult<'tcx, ImmTy<'tcx, Tag>> { let int = int.into(); - // If `int` does not fit in `size` bits, we error instead of letting - // `ImmTy::from_int` panic. - let size = layout.size; - let truncated = truncate(int as u128, size); - if sign_extend(truncated, size) as i128 != int { - throw_unsup_format!("Signed value {:#x} does not fit in {} bits", int, size.bits()) - } - Ok(ImmTy::from_int(int, layout)) + Ok(ImmTy::try_from_int(int, layout).ok_or_else(|| + err_unsup_format!("Signed value {:#x} does not fit in {} bits", int, layout.size.bits()) + )?) } -// FIXME: change `ImmTy::from_uint` so it returns an `InterpResult` instead and remove this -// function. pub fn immty_from_uint_checked<'tcx>( int: impl Into, layout: TyLayout<'tcx>, ) -> InterpResult<'tcx, ImmTy<'tcx, Tag>> { let int = int.into(); - // If `int` does not fit in `size` bits, we error instead of letting - // `ImmTy::from_int` panic. - let size = layout.size; - if truncate(int, size) != int { - throw_unsup_format!("Unsigned value {:#x} does not fit in {} bits", int, size.bits()) - } - Ok(ImmTy::from_uint(int, layout)) + Ok(ImmTy::try_from_uint(int, layout).ok_or_else(|| + err_unsup_format!("Signed value {:#x} does not fit in {} bits", int, layout.size.bits()) + )?) } From cd12f47af6e9cc107e11962230252e1d66fd9861 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 24 Dec 2019 11:46:02 +0100 Subject: [PATCH 1419/3747] make bytes conversion functions private inside read/write functions --- src/helpers.rs | 54 ++++++++++++++++++++++++-------------------------- 1 file changed, 26 insertions(+), 28 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index b631f404523f0..242e2b1d4a13d 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -445,6 +445,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx 'tcx: 'a, 'mir: 'a, { + #[cfg(target_os = "unix")] + fn bytes_to_os_str<'tcx, 'a>(bytes: &'a [u8]) -> InterpResult<'tcx, &'a OsStr> { + Ok(std::os::unix::ffi::OsStringExt::from_bytes(bytes)) + } + #[cfg(not(target_os = "unix"))] + fn bytes_to_os_str<'tcx, 'a>(bytes: &'a [u8]) -> InterpResult<'tcx, &'a OsStr> { + let s = std::str::from_utf8(bytes) + .map_err(|_| err_unsup_format!("{:?} is not a valid utf-8 string", bytes))?; + Ok(&OsStr::new(s)) + } + let this = self.eval_context_ref(); let bytes = this.memory.read_c_str(scalar)?; bytes_to_os_str(bytes) @@ -460,6 +471,21 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx scalar: Scalar, size: u64, ) -> InterpResult<'tcx, bool> { + #[cfg(target_os = "unix")] + fn os_str_to_bytes<'tcx, 'a>(os_str: &'a OsStr) -> InterpResult<'tcx, &'a [u8]> { + std::os::unix::ffi::OsStringExt::into_bytes(os_str) + } + #[cfg(not(target_os = "unix"))] + fn os_str_to_bytes<'tcx, 'a>(os_str: &'a OsStr) -> InterpResult<'tcx, &'a [u8]> { + // On non-unix platforms the best we can do to transform bytes from/to OS strings is to do the + // intermediate transformation into strings. Which invalidates non-utf8 paths that are actually + // valid. + os_str + .to_str() + .map(|s| s.as_bytes()) + .ok_or_else(|| err_unsup_format!("{:?} is not a valid utf-8 string", os_str).into()) + } + let bytes = os_str_to_bytes(os_str)?; // If `size` is smaller or equal than `bytes.len()`, writing `bytes` plus the required null // terminator to memory using the `ptr` pointer would cause an out-of-bounds access. @@ -473,34 +499,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } -#[cfg(target_os = "unix")] -fn os_str_to_bytes<'tcx, 'a>(os_str: &'a OsStr) -> InterpResult<'tcx, &'a [u8]> { - std::os::unix::ffi::OsStringExt::into_bytes(os_str) -} - -#[cfg(target_os = "unix")] -fn bytes_to_os_str<'tcx, 'a>(bytes: &'a [u8]) -> InterpResult<'tcx, &'a OsStr> { - Ok(std::os::unix::ffi::OsStringExt::from_bytes(bytes)) -} - -// On non-unix platforms the best we can do to transform bytes from/to OS strings is to do the -// intermediate transformation into strings. Which invalidates non-utf8 paths that are actually -// valid. -#[cfg(not(target_os = "unix"))] -fn os_str_to_bytes<'tcx, 'a>(os_str: &'a OsStr) -> InterpResult<'tcx, &'a [u8]> { - os_str - .to_str() - .map(|s| s.as_bytes()) - .ok_or_else(|| err_unsup_format!("{:?} is not a valid utf-8 string", os_str).into()) -} - -#[cfg(not(target_os = "unix"))] -fn bytes_to_os_str<'tcx, 'a>(bytes: &'a [u8]) -> InterpResult<'tcx, &'a OsStr> { - let s = std::str::from_utf8(bytes) - .map_err(|_| err_unsup_format!("{:?} is not a valid utf-8 string", bytes))?; - Ok(&OsStr::new(s)) -} - pub fn immty_from_int_checked<'tcx>( int: impl Into, layout: TyLayout<'tcx>, From d9ecd77adafc669854e5b74a790b243ac6f0ec5f Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Tue, 24 Dec 2019 11:01:01 -0500 Subject: [PATCH 1420/3747] add dummy stat shim --- src/shims/foreign_items.rs | 5 ++++ src/shims/fs.rs | 49 ++++++++++++++++++++++++++++++++++++++ tests/run-pass/fs.rs | 7 ------ 3 files changed, 54 insertions(+), 7 deletions(-) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 1a52d8721470f..9092828a1556b 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -494,6 +494,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; } + "stat64" => { + let result = this.stat(args[0], args[1])?; + this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + } + "clock_gettime" => { let result = this.clock_gettime(args[0], args[1])?; this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; diff --git a/src/shims/fs.rs b/src/shims/fs.rs index 0b78111533a59..d891d132f24f6 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -261,6 +261,55 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.try_unwrap_io_result(result) } + fn stat(&mut self, + _path_op: OpTy<'tcx, Tag>, + buf_op: OpTy<'tcx, Tag>, + ) -> InterpResult<'tcx, i32> { + let this = self.eval_context_mut(); + + let buf = this.deref_operand(buf_op)?; + + let dev_t_layout = this.libc_ty_layout("dev_t")?; + let mode_t_layout = this.libc_ty_layout("mode_t")?; + let nlink_t_layout = this.libc_ty_layout("nlink_t")?; + let ino_t_layout = this.libc_ty_layout("ino_t")?; + let uid_t_layout = this.libc_ty_layout("uid_t")?; + let gid_t_layout = this.libc_ty_layout("gid_t")?; + let time_t_layout = this.libc_ty_layout("time_t")?; + let long_layout = this.libc_ty_layout("c_long")?; + let off_t_layout = this.libc_ty_layout("off_t")?; + let blkcnt_t_layout = this.libc_ty_layout("blkcnt_t")?; + let blksize_t_layout = this.libc_ty_layout("blksize_t")?; + let uint32_t_layout = this.libc_ty_layout("uint32_t")?; + + let imms = [ + immty_from_uint_checked(0u128, dev_t_layout)?, // st_dev + immty_from_uint_checked(0u128, mode_t_layout)?, // st_mode + immty_from_uint_checked(0u128, nlink_t_layout)?, // st_nlink + immty_from_uint_checked(0u128, ino_t_layout)?, // st_ino + immty_from_uint_checked(0u128, uid_t_layout)?, // st_uid + immty_from_uint_checked(0u128, gid_t_layout)?, // st_gid + immty_from_uint_checked(0u128, dev_t_layout)?, // st_rdev + immty_from_uint_checked(0u128, time_t_layout)?, // st_atime + immty_from_uint_checked(0u128, long_layout)?, // st_atime_nsec + immty_from_uint_checked(0u128, time_t_layout)?, // st_mtime + immty_from_uint_checked(0u128, long_layout)?, // st_mtime_nsec + immty_from_uint_checked(0u128, time_t_layout)?, // st_ctime + immty_from_uint_checked(0u128, long_layout)?, // st_ctime_nsec + immty_from_uint_checked(0u128, time_t_layout)?, // st_birthtime + immty_from_uint_checked(0u128, long_layout)?, // st_birthtime_nsec + immty_from_uint_checked(0u128, off_t_layout)?, // st_size + immty_from_uint_checked(0u128, blkcnt_t_layout)?, // st_blocks + immty_from_uint_checked(0u128, blksize_t_layout)?, // st_blksize + immty_from_uint_checked(0u128, uint32_t_layout)?, // st_flags + immty_from_uint_checked(0u128, uint32_t_layout)?, // st_gen + ]; + + this.write_packed_immediates(&buf, &imms)?; + + Ok(0) + } + fn statx( &mut self, dirfd_op: OpTy<'tcx, Tag>, // Should be an `int` diff --git a/tests/run-pass/fs.rs b/tests/run-pass/fs.rs index b8f9e3229af67..9f000961d5a05 100644 --- a/tests/run-pass/fs.rs +++ b/tests/run-pass/fs.rs @@ -5,7 +5,6 @@ use std::fs::{File, remove_file}; use std::io::{Read, Write, ErrorKind, Result}; use std::path::{PathBuf, Path}; -#[cfg(target_os = "linux")] fn test_metadata(bytes: &[u8], path: &Path) -> Result<()> { // Test that the file metadata is correct. let metadata = path.metadata()?; @@ -16,12 +15,6 @@ fn test_metadata(bytes: &[u8], path: &Path) -> Result<()> { Ok(()) } -// FIXME: Implement stat64 for macos. -#[cfg(not(target_os = "linux"))] -fn test_metadata(_bytes: &[u8], _path: &Path) -> Result<()> { - Ok(()) -} - fn main() { let tmp = std::env::temp_dir(); let filename = PathBuf::from("miri_test_fs.txt"); From 6177e6df7e212340ad194319d698f321b44bb35a Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Tue, 24 Dec 2019 11:21:00 -0500 Subject: [PATCH 1421/3747] provide correct name for shim --- src/shims/foreign_items.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 9092828a1556b..51c43b28b68aa 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -494,7 +494,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; } - "stat64" => { + "stat$INODE64" => { let result = this.stat(args[0], args[1])?; this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; } From b2c4ff2aee08854d13b33877a4275307e27091ee Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Tue, 24 Dec 2019 11:53:03 -0500 Subject: [PATCH 1422/3747] add remanining fields to stat stuct --- src/shims/fs.rs | 64 +++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 54 insertions(+), 10 deletions(-) diff --git a/src/shims/fs.rs b/src/shims/fs.rs index d891d132f24f6..8b102bf04abf4 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -261,14 +261,58 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.try_unwrap_io_result(result) } - fn stat(&mut self, - _path_op: OpTy<'tcx, Tag>, + fn stat( + &mut self, + path_op: OpTy<'tcx, Tag>, buf_op: OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); + let path_scalar = this.read_scalar(path_op)?.not_undef()?; + let path = this.read_os_str_from_c_str(path_scalar)?; + let buf = this.deref_operand(buf_op)?; + let metadata = match std::fs::metadata(path) { + Ok(metadata) => metadata, + Err(e) => { + this.set_last_error_from_io_error(e)?; + return Ok(-1); + } + }; + + let file_type = metadata.file_type(); + + let mode_name = if file_type.is_file() { + "S_IFREG" + } else if file_type.is_dir() { + "S_IFDIR" + } else { + "S_IFLNK" + }; + + let mode = this.eval_libc(mode_name)?.to_u32()?; + + let size = metadata.len(); + + let (access_sec, access_nsec) = extract_sec_and_nsec( + metadata.accessed(), + &mut 0, + 0, + )?; + + let (created_sec, created_nsec) = extract_sec_and_nsec( + metadata.created(), + &mut 0, + 0, + )?; + + let (modified_sec, modified_nsec) = extract_sec_and_nsec( + metadata.modified(), + &mut 0, + 0, + )?; + let dev_t_layout = this.libc_ty_layout("dev_t")?; let mode_t_layout = this.libc_ty_layout("mode_t")?; let nlink_t_layout = this.libc_ty_layout("nlink_t")?; @@ -284,21 +328,21 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let imms = [ immty_from_uint_checked(0u128, dev_t_layout)?, // st_dev - immty_from_uint_checked(0u128, mode_t_layout)?, // st_mode + immty_from_uint_checked(mode, mode_t_layout)?, // st_mode immty_from_uint_checked(0u128, nlink_t_layout)?, // st_nlink immty_from_uint_checked(0u128, ino_t_layout)?, // st_ino immty_from_uint_checked(0u128, uid_t_layout)?, // st_uid immty_from_uint_checked(0u128, gid_t_layout)?, // st_gid immty_from_uint_checked(0u128, dev_t_layout)?, // st_rdev - immty_from_uint_checked(0u128, time_t_layout)?, // st_atime - immty_from_uint_checked(0u128, long_layout)?, // st_atime_nsec - immty_from_uint_checked(0u128, time_t_layout)?, // st_mtime - immty_from_uint_checked(0u128, long_layout)?, // st_mtime_nsec + immty_from_uint_checked(access_sec, time_t_layout)?, // st_atime + immty_from_uint_checked(access_nsec, long_layout)?, // st_atime_nsec + immty_from_uint_checked(modified_sec, time_t_layout)?, // st_mtime + immty_from_uint_checked(modified_nsec, long_layout)?, // st_mtime_nsec immty_from_uint_checked(0u128, time_t_layout)?, // st_ctime immty_from_uint_checked(0u128, long_layout)?, // st_ctime_nsec - immty_from_uint_checked(0u128, time_t_layout)?, // st_birthtime - immty_from_uint_checked(0u128, long_layout)?, // st_birthtime_nsec - immty_from_uint_checked(0u128, off_t_layout)?, // st_size + immty_from_uint_checked(created_sec, time_t_layout)?, // st_birthtime + immty_from_uint_checked(created_nsec, long_layout)?, // st_birthtime_nsec + immty_from_uint_checked(size, off_t_layout)?, // st_size immty_from_uint_checked(0u128, blkcnt_t_layout)?, // st_blocks immty_from_uint_checked(0u128, blksize_t_layout)?, // st_blksize immty_from_uint_checked(0u128, uint32_t_layout)?, // st_flags From 0184e10f2f1cfcdf845c680e9fd43b07c16483bd Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Tue, 24 Dec 2019 12:10:36 -0500 Subject: [PATCH 1423/3747] fix size for file mode --- src/shims/fs.rs | 22 ++++------------------ 1 file changed, 4 insertions(+), 18 deletions(-) diff --git a/src/shims/fs.rs b/src/shims/fs.rs index 8b102bf04abf4..b3d16dba6e6e2 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -291,27 +291,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "S_IFLNK" }; - let mode = this.eval_libc(mode_name)?.to_u32()?; + let mode = this.eval_libc(mode_name)?.to_bits(Size::from_bits(16))? as u16; let size = metadata.len(); - let (access_sec, access_nsec) = extract_sec_and_nsec( - metadata.accessed(), - &mut 0, - 0, - )?; - - let (created_sec, created_nsec) = extract_sec_and_nsec( - metadata.created(), - &mut 0, - 0, - )?; - - let (modified_sec, modified_nsec) = extract_sec_and_nsec( - metadata.modified(), - &mut 0, - 0, - )?; + let (access_sec, access_nsec) = extract_sec_and_nsec(metadata.accessed(), &mut 0, 0)?; + let (created_sec, created_nsec) = extract_sec_and_nsec(metadata.created(), &mut 0, 0)?; + let (modified_sec, modified_nsec) = extract_sec_and_nsec(metadata.modified(), &mut 0, 0)?; let dev_t_layout = this.libc_ty_layout("dev_t")?; let mode_t_layout = this.libc_ty_layout("mode_t")?; From dbc118919aea52645cb278d4db6d38612a448095 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Wed, 25 Dec 2019 10:32:34 -0500 Subject: [PATCH 1424/3747] add padding to immediates --- src/shims/fs.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/shims/fs.rs b/src/shims/fs.rs index b3d16dba6e6e2..d4a000305f643 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -320,6 +320,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx immty_from_uint_checked(0u128, uid_t_layout)?, // st_uid immty_from_uint_checked(0u128, gid_t_layout)?, // st_gid immty_from_uint_checked(0u128, dev_t_layout)?, // st_rdev + immty_from_uint_checked(0u128, dev_t_layout)?, // padding immty_from_uint_checked(access_sec, time_t_layout)?, // st_atime immty_from_uint_checked(access_nsec, long_layout)?, // st_atime_nsec immty_from_uint_checked(modified_sec, time_t_layout)?, // st_mtime From 75f7a118e63d6408b5cad81fe25f062405608f14 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Wed, 25 Dec 2019 11:27:25 -0500 Subject: [PATCH 1425/3747] remove restrictions due to `stat` unavailability --- src/shims/env.rs | 3 +-- tests/run-pass/fs.rs | 4 +--- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/src/shims/env.rs b/src/shims/env.rs index 3994cf78780aa..1e655ca821d81 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -20,8 +20,7 @@ impl EnvVars { ecx: &mut InterpCx<'mir, 'tcx, Evaluator<'tcx>>, mut excluded_env_vars: Vec, ) { - - // FIXME: this can be removed when we have the `stat64` shim for macos. + // FIXME: this can be removed when we fix the behavior of the `close` shim for macos. if ecx.tcx.sess.target.target.target_os.to_lowercase() != "linux" { // Exclude `TERM` var to avoid terminfo trying to open the termcap file. excluded_env_vars.push("TERM".to_owned()); diff --git a/tests/run-pass/fs.rs b/tests/run-pass/fs.rs index 9f000961d5a05..85e39bc45112b 100644 --- a/tests/run-pass/fs.rs +++ b/tests/run-pass/fs.rs @@ -51,7 +51,5 @@ fn main() { // Removing a non-existing file should fail with a "not found" error. assert_eq!(ErrorKind::NotFound, remove_file(&path).unwrap_err().kind()); // Reading the metadata of a non-existing file should fail with a "not found" error. - if cfg!(target_os = "linux") { // FIXME: Implement stat64 for macos. - assert_eq!(ErrorKind::NotFound, test_metadata(bytes, &path).unwrap_err().kind()); - } + assert_eq!(ErrorKind::NotFound, test_metadata(bytes, &path).unwrap_err().kind()); } From 6d88a4704a030b2c963abf38be481c1805b407d0 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Wed, 25 Dec 2019 11:30:01 -0500 Subject: [PATCH 1426/3747] restrict `stat` shim to macos only --- src/shims/fs.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/shims/fs.rs b/src/shims/fs.rs index d4a000305f643..78ec2169fd685 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -268,6 +268,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); + if this.tcx.sess.target.target.target_os.to_lowercase() != "macos" { + throw_unsup_format!("The `stat` shim is only only available in the `macos` platform.") + } + let path_scalar = this.read_scalar(path_op)?.not_undef()?; let path = this.read_os_str_from_c_str(path_scalar)?; From 515c11935969f6bffc42ab2e4cece862f109bb31 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Wed, 25 Dec 2019 11:39:57 -0500 Subject: [PATCH 1427/3747] Add padding on 64-bits only --- src/shims/fs.rs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/shims/fs.rs b/src/shims/fs.rs index 78ec2169fd685..adc60a52e6d17 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -295,6 +295,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "S_IFLNK" }; + // FIXME: use Scalar::to_u16 let mode = this.eval_libc(mode_name)?.to_bits(Size::from_bits(16))? as u16; let size = metadata.len(); @@ -316,6 +317,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let blksize_t_layout = this.libc_ty_layout("blksize_t")?; let uint32_t_layout = this.libc_ty_layout("uint32_t")?; + // We need to add 32 bits of padding after `st_rdev` if we are in a 64-bit platform. To do + // this, we store `st_rdev` as a `c_long` instead of a `dev_t`. + let st_rdev_layout = if this.tcx.sess.target.ptr_width == 64 { + long_layout + } else { + dev_t_layout + }; + let imms = [ immty_from_uint_checked(0u128, dev_t_layout)?, // st_dev immty_from_uint_checked(mode, mode_t_layout)?, // st_mode @@ -323,8 +332,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx immty_from_uint_checked(0u128, ino_t_layout)?, // st_ino immty_from_uint_checked(0u128, uid_t_layout)?, // st_uid immty_from_uint_checked(0u128, gid_t_layout)?, // st_gid - immty_from_uint_checked(0u128, dev_t_layout)?, // st_rdev - immty_from_uint_checked(0u128, dev_t_layout)?, // padding + immty_from_uint_checked(0u128, st_rdev_layout)?, // st_rdev immty_from_uint_checked(access_sec, time_t_layout)?, // st_atime immty_from_uint_checked(access_nsec, long_layout)?, // st_atime_nsec immty_from_uint_checked(modified_sec, time_t_layout)?, // st_mtime From d17625900234f9643180075ea44756c98a92819a Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Wed, 25 Dec 2019 16:09:54 -0500 Subject: [PATCH 1428/3747] deduplicate shared code between stat and statx --- src/shims/fs.rs | 173 +++++++++++++++++++++++++----------------------- 1 file changed, 92 insertions(+), 81 deletions(-) diff --git a/src/shims/fs.rs b/src/shims/fs.rs index adc60a52e6d17..a5bac27cc449d 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -269,40 +269,25 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); if this.tcx.sess.target.target.target_os.to_lowercase() != "macos" { - throw_unsup_format!("The `stat` shim is only only available in the `macos` platform.") + throw_unsup_format!("The `stat` shim is only only available for `macos` targets.") } let path_scalar = this.read_scalar(path_op)?.not_undef()?; - let path = this.read_os_str_from_c_str(path_scalar)?; + let path: PathBuf = this.read_os_str_from_c_str(path_scalar)?.into(); let buf = this.deref_operand(buf_op)?; - let metadata = match std::fs::metadata(path) { - Ok(metadata) => metadata, - Err(e) => { - this.set_last_error_from_io_error(e)?; - return Ok(-1); - } - }; - - let file_type = metadata.file_type(); - - let mode_name = if file_type.is_file() { - "S_IFREG" - } else if file_type.is_dir() { - "S_IFDIR" - } else { - "S_IFLNK" + let stats = match FileStatus::new(this, path, false)? { + Some(stats) => stats, + None => return Ok(-1), }; // FIXME: use Scalar::to_u16 - let mode = this.eval_libc(mode_name)?.to_bits(Size::from_bits(16))? as u16; - - let size = metadata.len(); + let mode: u16 = stats.mode.to_bits(Size::from_bits(16))? as u16; - let (access_sec, access_nsec) = extract_sec_and_nsec(metadata.accessed(), &mut 0, 0)?; - let (created_sec, created_nsec) = extract_sec_and_nsec(metadata.created(), &mut 0, 0)?; - let (modified_sec, modified_nsec) = extract_sec_and_nsec(metadata.modified(), &mut 0, 0)?; + let (access_sec, access_nsec) = stats.accessed.unwrap_or((0, 0)); + let (created_sec, created_nsec) = stats.created.unwrap_or((0, 0)); + let (modified_sec, modified_nsec) = stats.modified.unwrap_or((0, 0)); let dev_t_layout = this.libc_ty_layout("dev_t")?; let mode_t_layout = this.libc_ty_layout("mode_t")?; @@ -341,7 +326,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx immty_from_uint_checked(0u128, long_layout)?, // st_ctime_nsec immty_from_uint_checked(created_sec, time_t_layout)?, // st_birthtime immty_from_uint_checked(created_nsec, long_layout)?, // st_birthtime_nsec - immty_from_uint_checked(size, off_t_layout)?, // st_size + immty_from_uint_checked(stats.size, off_t_layout)?, // st_size immty_from_uint_checked(0u128, blkcnt_t_layout)?, // st_blocks immty_from_uint_checked(0u128, blksize_t_layout)?, // st_blksize immty_from_uint_checked(0u128, uint32_t_layout)?, // st_flags @@ -365,6 +350,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.check_no_isolation("statx")?; + if this.tcx.sess.target.target.target_os.to_lowercase() != "linux" { + throw_unsup_format!("The `statx` shim is only only available for `linux` targets.") + } + let statxbuf_scalar = this.read_scalar(statxbuf_op)?.not_undef()?; let pathname_scalar = this.read_scalar(pathname_op)?.not_undef()?; @@ -422,60 +411,43 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // If the `AT_SYMLINK_NOFOLLOW` flag is set, we query the file's metadata without following // symbolic links. - let metadata = if flags & this.eval_libc("AT_SYMLINK_NOFOLLOW")?.to_i32()? != 0 { - // FIXME: metadata for symlinks need testing. - std::fs::symlink_metadata(path) - } else { - std::fs::metadata(path) - }; - - let metadata = match metadata { - Ok(metadata) => metadata, - Err(e) => { - this.set_last_error_from_io_error(e)?; - return Ok(-1); - } - }; - - let file_type = metadata.file_type(); + let is_symlink = flags & this.eval_libc("AT_SYMLINK_NOFOLLOW")?.to_i32()? != 0; - let mode_name = if file_type.is_file() { - "S_IFREG" - } else if file_type.is_dir() { - "S_IFDIR" - } else { - "S_IFLNK" + let stats = match FileStatus::new(this, path, is_symlink)? { + Some(stats) => stats, + None => return Ok(-1), }; // The `mode` field specifies the type of the file and the permissions over the file for // the owner, its group and other users. Given that we can only provide the file type // without using platform specific methods, we only set the bits corresponding to the file // type. This should be an `__u16` but `libc` provides its values as `u32`. - let mode: u16 = this - .eval_libc(mode_name)? + let mode: u16 = stats + .mode .to_u32()? .try_into() - .unwrap_or_else(|_| bug!("libc contains bad value for `{}` constant", mode_name)); - - let size = metadata.len(); + .unwrap_or_else(|_| bug!("libc contains bad value for constant")); - let (access_sec, access_nsec) = extract_sec_and_nsec( - metadata.accessed(), - &mut mask, - this.eval_libc("STATX_ATIME")?.to_u32()?, - )?; + let (access_sec, access_nsec) = if let Some(tup) = stats.accessed { + tup + } else { + mask |= this.eval_libc("STATX_ATIME")?.to_u32()?; + (0, 0) + }; - let (created_sec, created_nsec) = extract_sec_and_nsec( - metadata.created(), - &mut mask, - this.eval_libc("STATX_BTIME")?.to_u32()?, - )?; + let (created_sec, created_nsec) = if let Some(tup) = stats.created { + tup + } else { + mask |= this.eval_libc("STATX_BTIME")?.to_u32()?; + (0, 0) + }; - let (modified_sec, modified_nsec) = extract_sec_and_nsec( - metadata.modified(), - &mut mask, - this.eval_libc("STATX_MTIME")?.to_u32()?, - )?; + let (modified_sec, modified_nsec) = if let Some(tup) = stats.modified { + tup + } else { + mask |= this.eval_libc("STATX_MTIME")?.to_u32()?; + (0, 0) + }; let __u32_layout = this.libc_ty_layout("__u32")?; let __u64_layout = this.libc_ty_layout("__u64")?; @@ -483,7 +455,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Now we transform all this fields into `ImmTy`s and write them to `statxbuf`. We write a // zero for the unavailable fields. - // FIXME: Provide more fields using platform specific methods. let imms = [ immty_from_uint_checked(mask, __u32_layout)?, // stx_mask immty_from_uint_checked(0u128, __u32_layout)?, // stx_blksize @@ -494,7 +465,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx immty_from_uint_checked(mode, __u16_layout)?, // stx_mode immty_from_uint_checked(0u128, __u16_layout)?, // statx padding immty_from_uint_checked(0u128, __u64_layout)?, // stx_ino - immty_from_uint_checked(size, __u64_layout)?, // stx_size + immty_from_uint_checked(stats.size, __u64_layout)?, // stx_size immty_from_uint_checked(0u128, __u64_layout)?, // stx_blocks immty_from_uint_checked(0u128, __u64_layout)?, // stx_attributes immty_from_uint_checked(access_sec, __u64_layout)?, // stx_atime.tv_sec @@ -532,19 +503,59 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } -// Extracts the number of seconds and nanoseconds elapsed between `time` and the unix epoch, and -// then sets the `mask` bits determined by `flag` when `time` is Ok. If `time` is an error, it -// returns `(0, 0)` without setting any bits. -fn extract_sec_and_nsec<'tcx>( - time: std::io::Result, - mask: &mut u32, - flag: u32, -) -> InterpResult<'tcx, (u64, u32)> { - if let Ok(time) = time { +// Extracts the number of seconds and nanoseconds elapsed between `time` and the unix epoch when +// `time` is Ok. If `time` is an error, it returns `None`. +fn extract_sec_and_nsec<'tcx>(time: std::io::Result) -> InterpResult<'tcx, Option<(u64, u32)>> { + time.ok().map(|time| { let duration = system_time_to_duration(&time)?; - *mask |= flag; Ok((duration.as_secs(), duration.subsec_nanos())) - } else { - Ok((0, 0)) + }).transpose() +} + +struct FileStatus { + mode: Scalar, + size: u64, + created: Option<(u64, u32)>, + accessed: Option<(u64, u32)>, + modified: Option<(u64, u32)>, +} + +impl FileStatus { + fn new<'tcx, 'mir>(ecx: &mut MiriEvalContext<'mir, 'tcx>, path: PathBuf, is_symlink: bool) -> InterpResult<'tcx, Option> { + let metadata = if is_symlink { + // FIXME: metadata for symlinks need testing. + std::fs::symlink_metadata(path) + } else { + std::fs::metadata(path) + }; + + let metadata = match metadata { + Ok(metadata) => metadata, + Err(e) => { + ecx.set_last_error_from_io_error(e)?; + return Ok(None); + } + }; + + let file_type = metadata.file_type(); + + let mode_name = if file_type.is_file() { + "S_IFREG" + } else if file_type.is_dir() { + "S_IFDIR" + } else { + "S_IFLNK" + }; + + let mode = ecx.eval_libc(mode_name)?; + + let size = metadata.len(); + + let created = extract_sec_and_nsec(metadata.created())?; + let accessed = extract_sec_and_nsec(metadata.accessed())?; + let modified = extract_sec_and_nsec(metadata.modified())?; + + // FIXME: Provide more fields using platform specific methods. + Ok(Some(FileStatus { mode, size, created, accessed, modified })) } } From 1bc362908440792123d8b8022f6e09a7401389f2 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Wed, 25 Dec 2019 18:22:33 -0500 Subject: [PATCH 1429/3747] do padding correctly --- src/shims/fs.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/shims/fs.rs b/src/shims/fs.rs index a5bac27cc449d..8cd1afd02c9f7 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -302,12 +302,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let blksize_t_layout = this.libc_ty_layout("blksize_t")?; let uint32_t_layout = this.libc_ty_layout("uint32_t")?; - // We need to add 32 bits of padding after `st_rdev` if we are in a 64-bit platform. To do - // this, we store `st_rdev` as a `c_long` instead of a `dev_t`. - let st_rdev_layout = if this.tcx.sess.target.ptr_width == 64 { - long_layout + // We need to add 32 bits of padding after `st_rdev` if we are in a 64-bit platform. + let pad_layout = if this.tcx.sess.target.ptr_width == 64 { + uint32_t_layout } else { - dev_t_layout + this.layout_of(this.tcx.mk_unit())? }; let imms = [ @@ -317,7 +316,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx immty_from_uint_checked(0u128, ino_t_layout)?, // st_ino immty_from_uint_checked(0u128, uid_t_layout)?, // st_uid immty_from_uint_checked(0u128, gid_t_layout)?, // st_gid - immty_from_uint_checked(0u128, st_rdev_layout)?, // st_rdev + immty_from_uint_checked(0u128, dev_t_layout)?, // st_rdev + immty_from_uint_checked(0u128, pad_layout)?, // padding for 64-bit targets immty_from_uint_checked(access_sec, time_t_layout)?, // st_atime immty_from_uint_checked(access_nsec, long_layout)?, // st_atime_nsec immty_from_uint_checked(modified_sec, time_t_layout)?, // st_mtime From bbbb50a09aadfc53df8ed4810d9ff67b194b2492 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Wed, 25 Dec 2019 22:22:25 -0500 Subject: [PATCH 1430/3747] set mask for statx correctly --- src/shims/fs.rs | 52 ++++++++++++++++++++++++------------------------- 1 file changed, 25 insertions(+), 27 deletions(-) diff --git a/src/shims/fs.rs b/src/shims/fs.rs index 8cd1afd02c9f7..3084d977de82a 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -277,17 +277,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let buf = this.deref_operand(buf_op)?; - let stats = match FileStatus::new(this, path, false)? { - Some(stats) => stats, + let status = match FileStatus::new(this, path, false)? { + Some(status) => status, None => return Ok(-1), }; // FIXME: use Scalar::to_u16 - let mode: u16 = stats.mode.to_bits(Size::from_bits(16))? as u16; + let mode: u16 = status.mode.to_bits(Size::from_bits(16))? as u16; - let (access_sec, access_nsec) = stats.accessed.unwrap_or((0, 0)); - let (created_sec, created_nsec) = stats.created.unwrap_or((0, 0)); - let (modified_sec, modified_nsec) = stats.modified.unwrap_or((0, 0)); + let (access_sec, access_nsec) = status.accessed.unwrap_or((0, 0)); + let (created_sec, created_nsec) = status.created.unwrap_or((0, 0)); + let (modified_sec, modified_nsec) = status.modified.unwrap_or((0, 0)); let dev_t_layout = this.libc_ty_layout("dev_t")?; let mode_t_layout = this.libc_ty_layout("mode_t")?; @@ -326,7 +326,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx immty_from_uint_checked(0u128, long_layout)?, // st_ctime_nsec immty_from_uint_checked(created_sec, time_t_layout)?, // st_birthtime immty_from_uint_checked(created_nsec, long_layout)?, // st_birthtime_nsec - immty_from_uint_checked(stats.size, off_t_layout)?, // st_size + immty_from_uint_checked(status.size, off_t_layout)?, // st_size immty_from_uint_checked(0u128, blkcnt_t_layout)?, // st_blocks immty_from_uint_checked(0u128, blksize_t_layout)?, // st_blksize immty_from_uint_checked(0u128, uint32_t_layout)?, // st_flags @@ -413,8 +413,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // symbolic links. let is_symlink = flags & this.eval_libc("AT_SYMLINK_NOFOLLOW")?.to_i32()? != 0; - let stats = match FileStatus::new(this, path, is_symlink)? { - Some(stats) => stats, + let status = match FileStatus::new(this, path, is_symlink)? { + Some(status) => status, None => return Ok(-1), }; @@ -422,32 +422,26 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // the owner, its group and other users. Given that we can only provide the file type // without using platform specific methods, we only set the bits corresponding to the file // type. This should be an `__u16` but `libc` provides its values as `u32`. - let mode: u16 = stats + let mode: u16 = status .mode .to_u32()? .try_into() .unwrap_or_else(|_| bug!("libc contains bad value for constant")); - let (access_sec, access_nsec) = if let Some(tup) = stats.accessed { - tup - } else { + let (access_sec, access_nsec) = status.accessed.map(|tup| { mask |= this.eval_libc("STATX_ATIME")?.to_u32()?; - (0, 0) - }; + InterpResult::Ok(tup) + }).unwrap_or(Ok((0, 0)))?; - let (created_sec, created_nsec) = if let Some(tup) = stats.created { - tup - } else { + let (created_sec, created_nsec) = status.created.map(|tup| { mask |= this.eval_libc("STATX_BTIME")?.to_u32()?; - (0, 0) - }; + InterpResult::Ok(tup) + }).unwrap_or(Ok((0, 0)))?; - let (modified_sec, modified_nsec) = if let Some(tup) = stats.modified { - tup - } else { + let (modified_sec, modified_nsec) = status.modified.map(|tup| { mask |= this.eval_libc("STATX_MTIME")?.to_u32()?; - (0, 0) - }; + InterpResult::Ok(tup) + }).unwrap_or(Ok((0, 0)))?; let __u32_layout = this.libc_ty_layout("__u32")?; let __u64_layout = this.libc_ty_layout("__u64")?; @@ -465,7 +459,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx immty_from_uint_checked(mode, __u16_layout)?, // stx_mode immty_from_uint_checked(0u128, __u16_layout)?, // statx padding immty_from_uint_checked(0u128, __u64_layout)?, // stx_ino - immty_from_uint_checked(stats.size, __u64_layout)?, // stx_size + immty_from_uint_checked(status.size, __u64_layout)?, // stx_size immty_from_uint_checked(0u128, __u64_layout)?, // stx_blocks immty_from_uint_checked(0u128, __u64_layout)?, // stx_attributes immty_from_uint_checked(access_sec, __u64_layout)?, // stx_atime.tv_sec @@ -521,7 +515,11 @@ struct FileStatus { } impl FileStatus { - fn new<'tcx, 'mir>(ecx: &mut MiriEvalContext<'mir, 'tcx>, path: PathBuf, is_symlink: bool) -> InterpResult<'tcx, Option> { + fn new<'tcx, 'mir>( + ecx: &mut MiriEvalContext<'mir, 'tcx>, + path: PathBuf, + is_symlink: bool + ) -> InterpResult<'tcx, Option> { let metadata = if is_symlink { // FIXME: metadata for symlinks need testing. std::fs::symlink_metadata(path) From 2151e958ceba1fcbe906eebf0b42855a0a20178f Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Thu, 26 Dec 2019 12:12:19 -0500 Subject: [PATCH 1431/3747] minor fixes and updated docs --- src/shims/fs.rs | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/src/shims/fs.rs b/src/shims/fs.rs index 3084d977de82a..f4a792a0410c6 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -411,9 +411,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // If the `AT_SYMLINK_NOFOLLOW` flag is set, we query the file's metadata without following // symbolic links. - let is_symlink = flags & this.eval_libc("AT_SYMLINK_NOFOLLOW")?.to_i32()? != 0; + let follow_symlink = flags & this.eval_libc("AT_SYMLINK_NOFOLLOW")?.to_i32()? == 0; - let status = match FileStatus::new(this, path, is_symlink)? { + let status = match FileStatus::new(this, path, follow_symlink)? { Some(status) => status, None => return Ok(-1), }; @@ -428,6 +428,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx .try_into() .unwrap_or_else(|_| bug!("libc contains bad value for constant")); + // We need to set the corresponding bits of `mask` if the access, creation and modification + // times were available. Otherwise we let them be zero. let (access_sec, access_nsec) = status.accessed.map(|tup| { mask |= this.eval_libc("STATX_ATIME")?.to_u32()?; InterpResult::Ok(tup) @@ -497,9 +499,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } -// Extracts the number of seconds and nanoseconds elapsed between `time` and the unix epoch when -// `time` is Ok. If `time` is an error, it returns `None`. -fn extract_sec_and_nsec<'tcx>(time: std::io::Result) -> InterpResult<'tcx, Option<(u64, u32)>> { +/// Extracts the number of seconds and nanoseconds elapsed between `time` and the unix epoch when +/// `time` is Ok. Returns `None` if `time` is an error. Fails if `time` happens before the unix +/// epoch. +fn extract_sec_and_nsec<'tcx>( + time: std::io::Result +) -> InterpResult<'tcx, Option<(u64, u32)>> { time.ok().map(|time| { let duration = system_time_to_duration(&time)?; Ok((duration.as_secs(), duration.subsec_nanos())) @@ -518,9 +523,9 @@ impl FileStatus { fn new<'tcx, 'mir>( ecx: &mut MiriEvalContext<'mir, 'tcx>, path: PathBuf, - is_symlink: bool + follow_symlink: bool ) -> InterpResult<'tcx, Option> { - let metadata = if is_symlink { + let metadata = if follow_symlink { // FIXME: metadata for symlinks need testing. std::fs::symlink_metadata(path) } else { From c8190e8de79b22843c4d0976def95aee120f0329 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Thu, 26 Dec 2019 13:30:04 -0500 Subject: [PATCH 1432/3747] rename metadata struct --- src/shims/fs.rs | 49 ++++++++++++++++++++++++++----------------------- 1 file changed, 26 insertions(+), 23 deletions(-) diff --git a/src/shims/fs.rs b/src/shims/fs.rs index f4a792a0410c6..63aa750bdd548 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -269,7 +269,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); if this.tcx.sess.target.target.target_os.to_lowercase() != "macos" { - throw_unsup_format!("The `stat` shim is only only available for `macos` targets.") + throw_unsup_format!("The `stat` shim is only available for `macos` targets.") } let path_scalar = this.read_scalar(path_op)?.not_undef()?; @@ -277,17 +277,18 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let buf = this.deref_operand(buf_op)?; - let status = match FileStatus::new(this, path, false)? { - Some(status) => status, + // `stat` always follows symlinks. `lstat` is used to get symlink metadata. + let metadata = match FileMetadata::new(this, path, true)? { + Some(metadata) => metadata, None => return Ok(-1), }; // FIXME: use Scalar::to_u16 - let mode: u16 = status.mode.to_bits(Size::from_bits(16))? as u16; + let mode: u16 = metadata.mode.to_bits(Size::from_bits(16))? as u16; - let (access_sec, access_nsec) = status.accessed.unwrap_or((0, 0)); - let (created_sec, created_nsec) = status.created.unwrap_or((0, 0)); - let (modified_sec, modified_nsec) = status.modified.unwrap_or((0, 0)); + let (access_sec, access_nsec) = metadata.accessed.unwrap_or((0, 0)); + let (created_sec, created_nsec) = metadata.created.unwrap_or((0, 0)); + let (modified_sec, modified_nsec) = metadata.modified.unwrap_or((0, 0)); let dev_t_layout = this.libc_ty_layout("dev_t")?; let mode_t_layout = this.libc_ty_layout("mode_t")?; @@ -302,7 +303,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let blksize_t_layout = this.libc_ty_layout("blksize_t")?; let uint32_t_layout = this.libc_ty_layout("uint32_t")?; - // We need to add 32 bits of padding after `st_rdev` if we are in a 64-bit platform. + // We need to add 32 bits of padding after `st_rdev` if we are on a 64-bit platform. let pad_layout = if this.tcx.sess.target.ptr_width == 64 { uint32_t_layout } else { @@ -326,7 +327,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx immty_from_uint_checked(0u128, long_layout)?, // st_ctime_nsec immty_from_uint_checked(created_sec, time_t_layout)?, // st_birthtime immty_from_uint_checked(created_nsec, long_layout)?, // st_birthtime_nsec - immty_from_uint_checked(status.size, off_t_layout)?, // st_size + immty_from_uint_checked(metadata.size, off_t_layout)?, // st_size immty_from_uint_checked(0u128, blkcnt_t_layout)?, // st_blocks immty_from_uint_checked(0u128, blksize_t_layout)?, // st_blksize immty_from_uint_checked(0u128, uint32_t_layout)?, // st_flags @@ -351,7 +352,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.check_no_isolation("statx")?; if this.tcx.sess.target.target.target_os.to_lowercase() != "linux" { - throw_unsup_format!("The `statx` shim is only only available for `linux` targets.") + throw_unsup_format!("The `statx` shim is only available for `linux` targets.") } let statxbuf_scalar = this.read_scalar(statxbuf_op)?.not_undef()?; @@ -413,8 +414,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // symbolic links. let follow_symlink = flags & this.eval_libc("AT_SYMLINK_NOFOLLOW")?.to_i32()? == 0; - let status = match FileStatus::new(this, path, follow_symlink)? { - Some(status) => status, + let metadata = match FileMetadata::new(this, path, follow_symlink)? { + Some(metadata) => metadata, None => return Ok(-1), }; @@ -422,7 +423,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // the owner, its group and other users. Given that we can only provide the file type // without using platform specific methods, we only set the bits corresponding to the file // type. This should be an `__u16` but `libc` provides its values as `u32`. - let mode: u16 = status + let mode: u16 = metadata .mode .to_u32()? .try_into() @@ -430,17 +431,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // We need to set the corresponding bits of `mask` if the access, creation and modification // times were available. Otherwise we let them be zero. - let (access_sec, access_nsec) = status.accessed.map(|tup| { + let (access_sec, access_nsec) = metadata.accessed.map(|tup| { mask |= this.eval_libc("STATX_ATIME")?.to_u32()?; InterpResult::Ok(tup) }).unwrap_or(Ok((0, 0)))?; - let (created_sec, created_nsec) = status.created.map(|tup| { + let (created_sec, created_nsec) = metadata.created.map(|tup| { mask |= this.eval_libc("STATX_BTIME")?.to_u32()?; InterpResult::Ok(tup) }).unwrap_or(Ok((0, 0)))?; - let (modified_sec, modified_nsec) = status.modified.map(|tup| { + let (modified_sec, modified_nsec) = metadata.modified.map(|tup| { mask |= this.eval_libc("STATX_MTIME")?.to_u32()?; InterpResult::Ok(tup) }).unwrap_or(Ok((0, 0)))?; @@ -461,7 +462,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx immty_from_uint_checked(mode, __u16_layout)?, // stx_mode immty_from_uint_checked(0u128, __u16_layout)?, // statx padding immty_from_uint_checked(0u128, __u64_layout)?, // stx_ino - immty_from_uint_checked(status.size, __u64_layout)?, // stx_size + immty_from_uint_checked(metadata.size, __u64_layout)?, // stx_size immty_from_uint_checked(0u128, __u64_layout)?, // stx_blocks immty_from_uint_checked(0u128, __u64_layout)?, // stx_attributes immty_from_uint_checked(access_sec, __u64_layout)?, // stx_atime.tv_sec @@ -511,7 +512,9 @@ fn extract_sec_and_nsec<'tcx>( }).transpose() } -struct FileStatus { +/// Stores a file's metadata in order to avoid code duplication in the different metadata related +/// shims. +struct FileMetadata { mode: Scalar, size: u64, created: Option<(u64, u32)>, @@ -519,17 +522,17 @@ struct FileStatus { modified: Option<(u64, u32)>, } -impl FileStatus { +impl FileMetadata { fn new<'tcx, 'mir>( ecx: &mut MiriEvalContext<'mir, 'tcx>, path: PathBuf, follow_symlink: bool - ) -> InterpResult<'tcx, Option> { + ) -> InterpResult<'tcx, Option> { let metadata = if follow_symlink { + std::fs::metadata(path) + } else { // FIXME: metadata for symlinks need testing. std::fs::symlink_metadata(path) - } else { - std::fs::metadata(path) }; let metadata = match metadata { @@ -559,6 +562,6 @@ impl FileStatus { let modified = extract_sec_and_nsec(metadata.modified())?; // FIXME: Provide more fields using platform specific methods. - Ok(Some(FileStatus { mode, size, created, accessed, modified })) + Ok(Some(FileMetadata { mode, size, created, accessed, modified })) } } From 4aef81eb85a47ff123db8204c59c610fa28f8693 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Fri, 27 Dec 2019 14:26:05 +0100 Subject: [PATCH 1433/3747] Remove `to_ptr` uses --- rust-version | 2 +- src/shims/foreign_items.rs | 2 +- src/shims/intrinsics.rs | 2 +- src/stacked_borrows.rs | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/rust-version b/rust-version index 999e8b0f8f730..b8bd5f9e57449 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -9ae6cedb8d1e37469be1434642a3e403fce50a03 +8f5f8f916f00f7989a4ebf7b7dbfe1afd605f828 diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 51c43b28b68aa..5bdd12b4eb1d2 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -271,7 +271,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx )?; } "__rust_realloc" => { - let ptr = this.read_scalar(args[0])?.to_ptr()?; let old_size = this.read_scalar(args[1])?.to_machine_usize(this)?; let align = this.read_scalar(args[2])?.to_machine_usize(this)?; let new_size = this.read_scalar(args[3])?.to_machine_usize(this)?; @@ -281,6 +280,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if !align.is_power_of_two() { throw_unsup!(HeapAllocNonPowerOfTwoAlignment(align)); } + let ptr = this.force_ptr(this.read_scalar(args[0])?.not_undef()?)?; let align = Align::from_bytes(align).unwrap(); let new_ptr = this.memory.reallocate( ptr, diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index bde2dd4655bf7..37aee1f5652c1 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -575,7 +575,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Do it in memory let mplace = this.force_allocation(dest)?; mplace.meta.unwrap_none(); - let ptr = mplace.ptr.to_ptr()?; + let ptr = mplace.ptr.assert_ptr(); // We know the return place is in-bounds this.memory.get_raw_mut(ptr.alloc_id)?.mark_definedness( ptr, diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index d986a2db53837..18edb603c6cf1 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -507,7 +507,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let protector = if protect { Some(this.frame().extra.call_id) } else { None }; - let ptr = place.ptr.to_ptr().expect("we should have a proper pointer"); + let ptr = place.ptr.assert_ptr(); trace!( "reborrow: {} reference {:?} derived from {:?} (pointee {}): {:?}, size {}", kind, From dc4b8ac2e65d80bbe68893fd8ab409c7e86187ec Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Fri, 27 Dec 2019 08:34:35 -0500 Subject: [PATCH 1434/3747] close file silently if the file is read only --- src/shims/fs.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/shims/fs.rs b/src/shims/fs.rs index 63aa750bdd548..c6cae22331d13 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -15,6 +15,7 @@ use shims::time::system_time_to_duration; #[derive(Debug)] pub struct FileHandle { file: File, + read_only: bool, } pub struct FileHandler { @@ -56,10 +57,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if (o_rdonly | o_wronly | o_rdwr) & !0b11 != 0 { throw_unsup_format!("Access mode flags on this platform are unsupported"); } + let mut read_only = false; + // Now we check the access mode let access_mode = flag & 0b11; if access_mode == o_rdonly { + read_only = true; options.read(true); } else if access_mode == o_wronly { options.write(true); @@ -105,7 +109,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let fd = options.open(&path).map(|file| { let mut fh = &mut this.machine.file_handler; fh.low += 1; - fh.handles.insert(fh.low, FileHandle { file }).unwrap_none(); + fh.handles.insert(fh.low, FileHandle { file, read_only }).unwrap_none(); fh.low }); @@ -148,6 +152,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let fd = this.read_scalar(fd_op)?.to_i32()?; if let Some(handle) = this.machine.file_handler.handles.remove(&fd) { + if handle.read_only { + return Ok(0); + } // `File::sync_all` does the checks that are done when closing a file. We do this to // to handle possible errors correctly. let result = this.try_unwrap_io_result(handle.file.sync_all().map(|_| 0i32)); From f00fd3990b5016bbfbbecf65d8f6bb40ca2c861a Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Fri, 27 Dec 2019 08:37:52 -0500 Subject: [PATCH 1435/3747] avoid excluding TERM env var --- src/shims/env.rs | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/shims/env.rs b/src/shims/env.rs index 1e655ca821d81..cb47e2d79fefd 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -18,14 +18,8 @@ pub struct EnvVars { impl EnvVars { pub(crate) fn init<'mir, 'tcx>( ecx: &mut InterpCx<'mir, 'tcx, Evaluator<'tcx>>, - mut excluded_env_vars: Vec, + excluded_env_vars: Vec, ) { - // FIXME: this can be removed when we fix the behavior of the `close` shim for macos. - if ecx.tcx.sess.target.target.target_os.to_lowercase() != "linux" { - // Exclude `TERM` var to avoid terminfo trying to open the termcap file. - excluded_env_vars.push("TERM".to_owned()); - } - if ecx.machine.communicate { for (name, value) in env::vars() { if !excluded_env_vars.contains(&name) { From a4bd68a45f50a9e77efde073e047beff8593e3ad Mon Sep 17 00:00:00 2001 From: JOE1994 Date: Fri, 27 Dec 2019 20:32:20 -0500 Subject: [PATCH 1436/3747] Add helper 'alloc_os_str_as_c_str' and use it in env_var emulation --- src/helpers.rs | 14 +++++++++++++ src/shims/env.rs | 43 +++++++++++++++++++------------------- src/shims/foreign_items.rs | 12 +++++++++++ 3 files changed, 47 insertions(+), 22 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index 242e2b1d4a13d..18b433a0e4a50 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -497,6 +497,20 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx .write_bytes(scalar, bytes.iter().copied().chain(iter::once(0u8)))?; Ok(true) } + + fn alloc_os_str_as_c_str( + &mut self, + os_str: &OsStr, + memkind: MemoryKind + ) -> Pointer { + let size = os_str.len() as u64 + 1; // Make space for `0` terminator. + let this = self.eval_context_mut(); + + let arg_type = this.tcx.mk_array(this.tcx.types.u8, size); + let arg_place = this.allocate(this.layout_of(arg_type).unwrap(), memkind); + self.write_os_str_to_c_str(os_str, arg_place.ptr, size).unwrap(); + arg_place.ptr.assert_ptr() + } } pub fn immty_from_int_checked<'tcx>( diff --git a/src/shims/env.rs b/src/shims/env.rs index 1e655ca821d81..1151561553f92 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -1,18 +1,18 @@ use std::collections::HashMap; -use std::ffi::OsString; +use std::ffi::{OsString, OsStr}; use std::env; use crate::stacked_borrows::Tag; use crate::*; use rustc::ty::layout::Size; -use rustc_mir::interpret::{Memory, Pointer}; +use rustc_mir::interpret::Pointer; #[derive(Default)] pub struct EnvVars { /// Stores pointers to the environment variables. These variables must be stored as /// null-terminated C strings with the `"{name}={value}"` format. - map: HashMap, Pointer>, + map: HashMap>, } impl EnvVars { @@ -30,24 +30,23 @@ impl EnvVars { for (name, value) in env::vars() { if !excluded_env_vars.contains(&name) { let var_ptr = - alloc_env_var(name.as_bytes(), value.as_bytes(), &mut ecx.memory); - ecx.machine.env_vars.map.insert(name.into_bytes(), var_ptr); + alloc_env_var_as_c_str(name.as_ref(), value.as_ref(), ecx); + ecx.machine.env_vars.map.insert(OsString::from(name), var_ptr); } } } } } -fn alloc_env_var<'mir, 'tcx>( - name: &[u8], - value: &[u8], - memory: &mut Memory<'mir, 'tcx, Evaluator<'tcx>>, +fn alloc_env_var_as_c_str<'mir, 'tcx>( + name: &OsStr, + value: &OsStr, + ecx: &mut InterpCx<'mir, 'tcx, Evaluator<'tcx>>, ) -> Pointer { - let mut bytes = name.to_vec(); - bytes.push(b'='); - bytes.extend_from_slice(value); - bytes.push(0); - memory.allocate_static_bytes(bytes.as_slice(), MiriMemoryKind::Env.into()) + let mut name_osstring = name.to_os_string(); + name_osstring.push("="); + name_osstring.push(value); + ecx.alloc_os_str_as_c_str(name_osstring.as_os_str(), MiriMemoryKind::Env.into()) } impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} @@ -56,7 +55,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); let name_ptr = this.read_scalar(name_op)?.not_undef()?; - let name = this.memory.read_c_str(name_ptr)?; + let name = this.read_os_str_from_c_str(name_ptr)?; Ok(match this.machine.env_vars.map.get(name) { // The offset is used to strip the "{name}=" part of the string. Some(var_ptr) => { @@ -71,20 +70,20 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx name_op: OpTy<'tcx, Tag>, value_op: OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, i32> { - let this = self.eval_context_mut(); + let mut this = self.eval_context_mut(); let name_ptr = this.read_scalar(name_op)?.not_undef()?; let value_ptr = this.read_scalar(value_op)?.not_undef()?; - let value = this.memory.read_c_str(value_ptr)?; + let value = this.read_os_str_from_c_str(value_ptr)?; let mut new = None; if !this.is_null(name_ptr)? { - let name = this.memory.read_c_str(name_ptr)?; - if !name.is_empty() && !name.contains(&b'=') { + let name = this.read_os_str_from_c_str(name_ptr)?; + if !name.is_empty() && !name.to_string_lossy().contains('=') { new = Some((name.to_owned(), value.to_owned())); } } if let Some((name, value)) = new { - let var_ptr = alloc_env_var(&name, &value, &mut this.memory); + let var_ptr = alloc_env_var_as_c_str(&name, &value, &mut this); if let Some(var) = this.machine.env_vars.map.insert(name.to_owned(), var_ptr) { this.memory .deallocate(var, None, MiriMemoryKind::Env.into())?; @@ -101,8 +100,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let name_ptr = this.read_scalar(name_op)?.not_undef()?; let mut success = None; if !this.is_null(name_ptr)? { - let name = this.memory.read_c_str(name_ptr)?.to_owned(); - if !name.is_empty() && !name.contains(&b'=') { + let name = this.read_os_str_from_c_str(name_ptr)?.to_owned(); + if !name.is_empty() && !name.to_string_lossy().contains('=') { success = Some(this.machine.env_vars.map.remove(&name)); } } diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 5bdd12b4eb1d2..07e3b7d758265 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -956,10 +956,22 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_null(dest)?; } "GetEnvironmentVariableW" => { + // args[0] : LPCWSTR lpName (32-bit ptr to a const string of 16-bit Unicode chars) + // args[1] : LPWSTR lpBuffer (32-bit pointer to a string of 16-bit Unicode chars) + // lpBuffer : ptr to buffer that receives contents of the env_var as a null-terminated string. + // Return `# of chars` stored in the buffer pointed to by lpBuffer, excluding null-terminator. + // Return 0 upon failure. + // This is not the env var you are looking for. this.set_last_error(Scalar::from_u32(203))?; // ERROR_ENVVAR_NOT_FOUND this.write_null(dest)?; } + "SetEnvironmentVariableW" => { + // args[0] : LPCWSTR lpName (32-bit ptr to a const string of 16-bit Unicode chars) + // args[1] : LPCWSTR lpValue (32-bit ptr to a const string of 16-bit Unicode chars) + // Return nonzero if success, else return 0. + throw_unsup_format!("can't set environment variable on Windows"); + } "GetCommandLineW" => { this.write_scalar( this.machine.cmd_line.expect("machine must be initialized"), From b7e6135d7bdd006d4f80d90e20db127ce3be0c3a Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Sat, 28 Dec 2019 08:38:31 -0500 Subject: [PATCH 1437/3747] Use Scalar::to_u16 --- src/shims/fs.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/shims/fs.rs b/src/shims/fs.rs index 63aa750bdd548..2ce002212cf37 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -283,8 +283,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx None => return Ok(-1), }; - // FIXME: use Scalar::to_u16 - let mode: u16 = metadata.mode.to_bits(Size::from_bits(16))? as u16; + let mode: u16 = metadata.mode.to_u16()?; let (access_sec, access_nsec) = metadata.accessed.unwrap_or((0, 0)); let (created_sec, created_nsec) = metadata.created.unwrap_or((0, 0)); From c60ab94d20af93161dd48525d46ef6b010a34f6c Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Sat, 28 Dec 2019 09:09:42 -0500 Subject: [PATCH 1438/3747] bump rustc version --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index b8bd5f9e57449..9f1b291f7f043 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -8f5f8f916f00f7989a4ebf7b7dbfe1afd605f828 +f564c4db0d97eabd7fdd72e589d3e415790ee2a4 From e952e37a39d7c3c54ba419c576ed34405a3d220f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 29 Dec 2019 12:38:40 +0100 Subject: [PATCH 1439/3747] compile-fail tests work with optimizations now --- tests/compile-fail/validity/nonzero.rs | 1 + tests/compiletest.rs | 4 +--- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/tests/compile-fail/validity/nonzero.rs b/tests/compile-fail/validity/nonzero.rs index f820b0e810b83..dbb31b3f17575 100644 --- a/tests/compile-fail/validity/nonzero.rs +++ b/tests/compile-fail/validity/nonzero.rs @@ -1,3 +1,4 @@ +// compile-flags: -Zmir-opt-level=1 #![feature(rustc_attrs)] #![allow(unused_attributes)] diff --git a/tests/compiletest.rs b/tests/compiletest.rs index eaaa87464dbf6..9cead530b57cd 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -69,9 +69,7 @@ fn compile_fail(path: &str, target: &str, opt: bool) { let mut flags = Vec::new(); if opt { - // FIXME: Opt level 2 ICEs during stack trace generation. - // See https://github.com/rust-lang/rust/issues/66077. - flags.push("-Zmir-opt-level=1".to_owned()); + flags.push("-Zmir-opt-level=3".to_owned()); } run_tests("compile-fail", path, target, flags); From ce4e1f9fe71234a38319c5c900f7e9b69ff8178e Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Fri, 27 Dec 2019 09:11:21 -0500 Subject: [PATCH 1440/3747] add comments --- src/shims/fs.rs | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/src/shims/fs.rs b/src/shims/fs.rs index c6cae22331d13..8829f21abd898 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -152,16 +152,24 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let fd = this.read_scalar(fd_op)?.to_i32()?; if let Some(handle) = this.machine.file_handler.handles.remove(&fd) { - if handle.read_only { - return Ok(0); + // We sync the file if it was opened in a mode different than read-only. + if !handle.read_only { + // `File::sync_all` does the checks that are done when closing a file. We do this to + // to handle possible errors correctly. + let result = this.try_unwrap_io_result(handle.file.sync_all().map(|_| 0i32)); + // Now we actually close the file. + drop(handle); + // And return the result. + result + } else { + // We drop the file, this closes it but ignores any errors produced when closing + // it. This is done because `File::sync_call` cannot be done over files like + // `/dev/urandom`. Check + // https://github.com/rust-lang/miri/issues/999#issuecomment-568920439 for a deeper + // discussion. + drop(handle); + Ok(0) } - // `File::sync_all` does the checks that are done when closing a file. We do this to - // to handle possible errors correctly. - let result = this.try_unwrap_io_result(handle.file.sync_all().map(|_| 0i32)); - // Now we actually close the file. - drop(handle); - // And return the result. - result } else { this.handle_not_found() } From a40a99d849b11f8580163d5d161221ae6f53f8d8 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Mon, 30 Dec 2019 17:26:17 -0500 Subject: [PATCH 1441/3747] avoid double negation --- src/shims/fs.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/shims/fs.rs b/src/shims/fs.rs index 8829f21abd898..1403d28673830 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -15,7 +15,7 @@ use shims::time::system_time_to_duration; #[derive(Debug)] pub struct FileHandle { file: File, - read_only: bool, + writable: bool, } pub struct FileHandler { @@ -57,13 +57,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if (o_rdonly | o_wronly | o_rdwr) & !0b11 != 0 { throw_unsup_format!("Access mode flags on this platform are unsupported"); } - let mut read_only = false; + let mut writable = true; // Now we check the access mode let access_mode = flag & 0b11; if access_mode == o_rdonly { - read_only = true; + writable = false; options.read(true); } else if access_mode == o_wronly { options.write(true); @@ -109,7 +109,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let fd = options.open(&path).map(|file| { let mut fh = &mut this.machine.file_handler; fh.low += 1; - fh.handles.insert(fh.low, FileHandle { file, read_only }).unwrap_none(); + fh.handles.insert(fh.low, FileHandle { file, writable }).unwrap_none(); fh.low }); @@ -153,7 +153,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if let Some(handle) = this.machine.file_handler.handles.remove(&fd) { // We sync the file if it was opened in a mode different than read-only. - if !handle.read_only { + if handle.writable { // `File::sync_all` does the checks that are done when closing a file. We do this to // to handle possible errors correctly. let result = this.try_unwrap_io_result(handle.file.sync_all().map(|_| 0i32)); @@ -164,7 +164,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } else { // We drop the file, this closes it but ignores any errors produced when closing // it. This is done because `File::sync_call` cannot be done over files like - // `/dev/urandom`. Check + // `/dev/urandom` which are read-only. Check // https://github.com/rust-lang/miri/issues/999#issuecomment-568920439 for a deeper // discussion. drop(handle); From e1fceafcea2b458cc44592947ef06ddf0ad39e58 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 31 Dec 2019 12:06:42 +0100 Subject: [PATCH 1442/3747] with FS access, default HashMap should work on macOS --- tests/run-pass/hashmap.rs | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/tests/run-pass/hashmap.rs b/tests/run-pass/hashmap.rs index 1ff9c26ba18c7..a63036780c998 100644 --- a/tests/run-pass/hashmap.rs +++ b/tests/run-pass/hashmap.rs @@ -1,3 +1,6 @@ +// macOS needs FS access for its HashMap: +// compile-flags: -Zmiri-disable-isolation + use std::collections::{self, HashMap}; use std::hash::{BuildHasherDefault, BuildHasher}; @@ -18,14 +21,8 @@ fn test_map(mut map: HashMap) { assert_eq!(map.values().fold(0, |x, y| x+y), num*(num-1)/2); // TODO: Test Entry API, Iterators, ... - } fn main() { - if cfg!(target_os = "macos") { // TODO: Implement libstd HashMap seeding for macOS (https://github.com/rust-lang/miri/issues/686). - // Until then, use a deterministic map. - test_map::>(HashMap::default()); - } else { - test_map(HashMap::new()); - } + test_map(HashMap::new()); } From 31fbb5a9b2553cd095144fd0a5af4c976a5a3ae5 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 31 Dec 2019 12:10:52 +0100 Subject: [PATCH 1443/3747] fix imports --- tests/run-pass/hashmap.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/run-pass/hashmap.rs b/tests/run-pass/hashmap.rs index a63036780c998..85116796d3859 100644 --- a/tests/run-pass/hashmap.rs +++ b/tests/run-pass/hashmap.rs @@ -1,8 +1,8 @@ // macOS needs FS access for its HashMap: // compile-flags: -Zmiri-disable-isolation -use std::collections::{self, HashMap}; -use std::hash::{BuildHasherDefault, BuildHasher}; +use std::collections::HashMap; +use std::hash::BuildHasher; fn test_map(mut map: HashMap) { map.insert(0, 0); From 84a43fcb6f024d00142bd61b4c7545901b9c036d Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Wed, 1 Jan 2020 03:22:06 -0500 Subject: [PATCH 1444/3747] Rustup This is mainly to see if CI can reproduce a strange issue I'm running into locally --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 9f1b291f7f043..a5ba2d9a61301 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -f564c4db0d97eabd7fdd72e589d3e415790ee2a4 +38aa6bdfd705ea0604d7d5dd9fabc5e8f853a4fc From 959033cbfb81a8b5631a1e2c1c4b308a30a12412 Mon Sep 17 00:00:00 2001 From: Wesley Wiser Date: Wed, 1 Jan 2020 21:33:51 -0500 Subject: [PATCH 1445/3747] Bump rustc version to fix miri --- rust-version | 2 +- tests/run-pass/c_enums.rs | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/rust-version b/rust-version index a5ba2d9a61301..71bc3b30f412b 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -38aa6bdfd705ea0604d7d5dd9fabc5e8f853a4fc +0ec370670220b712b042ee09aab067ec7e5878d5 diff --git a/tests/run-pass/c_enums.rs b/tests/run-pass/c_enums.rs index 16b795342eab8..5c2cecb330025 100644 --- a/tests/run-pass/c_enums.rs +++ b/tests/run-pass/c_enums.rs @@ -1,3 +1,5 @@ +#![allow(const_err)] // don't warn about truncating casts + enum Foo { Bar = 42, Baz, From c68996dda7771a404ce45690d0c1c02c268092a7 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 2 Jan 2020 15:57:33 +0100 Subject: [PATCH 1446/3747] note a FIXME --- tests/run-pass/c_enums.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/run-pass/c_enums.rs b/tests/run-pass/c_enums.rs index 5c2cecb330025..84c33ca0323f4 100644 --- a/tests/run-pass/c_enums.rs +++ b/tests/run-pass/c_enums.rs @@ -1,4 +1,4 @@ -#![allow(const_err)] // don't warn about truncating casts +#![allow(const_err)] // don't warn about truncating casts. FIXME: remove this, the error shouldn't even be shown enum Foo { Bar = 42, From 0a3f460d6966da30bc0128ab89959e17cf64fb04 Mon Sep 17 00:00:00 2001 From: Adam Perry Date: Wed, 1 Jan 2020 14:57:10 -0800 Subject: [PATCH 1447/3747] Update panic machinery to match #[track_caller] changes. This gets miri's tests passing again with https://github.com/rust-lang/rust/pull/67137. --- src/machine.rs | 1 + src/shims/panic.rs | 5 +---- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/machine.rs b/src/machine.rs index 37253a260de7f..502120d316b74 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -182,6 +182,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { #[inline(always)] fn find_mir_or_eval_fn( ecx: &mut InterpCx<'mir, 'tcx, Self>, + _span: Span, instance: ty::Instance<'tcx>, args: &[OpTy<'tcx, Tag>], ret: Option<(PlaceTy<'tcx, Tag>, mir::BasicBlock)>, diff --git a/src/shims/panic.rs b/src/shims/panic.rs index f242f41f6f96f..8f082f45c9159 100644 --- a/src/shims/panic.rs +++ b/src/shims/panic.rs @@ -187,15 +187,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let msg = msg.description(); let msg = this.allocate_str(msg, MiriMemoryKind::Env.into()); - // Second arg: Caller location. - let location = this.alloc_caller_location_for_span(span); - // Call the lang item. let panic = this.tcx.lang_items().panic_fn().unwrap(); let panic = ty::Instance::mono(this.tcx.tcx, panic); this.call_function( panic, - &[msg.to_ref(), location.ptr.into()], + &[msg.to_ref()], None, StackPopCleanup::Goto { ret: None, unwind }, )?; From ebacb8ae4ee46e72791e115a4cdce1344a5db53b Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Sun, 5 Jan 2020 17:53:45 +0900 Subject: [PATCH 1448/3747] Rustup --- rust-version | 2 +- src/eval.rs | 2 +- src/helpers.rs | 2 +- src/lib.rs | 1 + src/machine.rs | 3 ++- src/shims/foreign_items.rs | 4 ++-- src/shims/intrinsics.rs | 2 +- src/shims/panic.rs | 2 +- 8 files changed, 10 insertions(+), 8 deletions(-) diff --git a/rust-version b/rust-version index 71bc3b30f412b..44bed6b73d1a5 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -0ec370670220b712b042ee09aab067ec7e5878d5 +093241deae70ba38413aff823b31c23731debf14 diff --git a/src/eval.rs b/src/eval.rs index 0cc302b967b29..1968111307e77 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -47,7 +47,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( config: MiriConfig, ) -> InterpResult<'tcx, (InterpCx<'mir, 'tcx, Evaluator<'tcx>>, MPlaceTy<'tcx, Tag>)> { let mut ecx = InterpCx::new( - tcx.at(syntax::source_map::DUMMY_SP), + tcx.at(rustc_span::source_map::DUMMY_SP), ty::ParamEnv::reveal_all(), Evaluator::new(config.communicate), MemoryExtra::new( diff --git a/src/helpers.rs b/src/helpers.rs index 18b433a0e4a50..17d74d2ef757c 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -8,7 +8,7 @@ use rustc::ty::{ layout::{self, LayoutOf, Size, TyLayout}, List, TyCtxt, }; -use syntax::source_map::DUMMY_SP; +use rustc_span::source_map::DUMMY_SP; use rand::RngCore; diff --git a/src/lib.rs b/src/lib.rs index 32d2bda719ea0..2ddcdf8ff7776 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -10,6 +10,7 @@ extern crate rustc_apfloat; extern crate syntax; #[macro_use] extern crate rustc; +extern crate rustc_span; extern crate rustc_data_structures; extern crate rustc_mir; extern crate rustc_target; diff --git a/src/machine.rs b/src/machine.rs index 502120d316b74..4c1446c82c748 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -14,7 +14,8 @@ use rustc::ty::{ layout::{LayoutOf, Size}, Ty, TyCtxt, }; -use syntax::{attr, source_map::Span, symbol::sym}; +use rustc_span::{source_map::Span, symbol::sym}; +use syntax::attr; use crate::*; diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 07e3b7d758265..6ad16c6f67647 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -5,8 +5,8 @@ use rustc::mir; use rustc::ty; use rustc::ty::layout::{Align, LayoutOf, Size}; use rustc_apfloat::Float; +use rustc_span::symbol::sym; use syntax::attr; -use syntax::symbol::sym; use crate::*; @@ -961,7 +961,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // lpBuffer : ptr to buffer that receives contents of the env_var as a null-terminated string. // Return `# of chars` stored in the buffer pointed to by lpBuffer, excluding null-terminator. // Return 0 upon failure. - + // This is not the env var you are looking for. this.set_last_error(Scalar::from_u32(203))?; // ERROR_ENVVAR_NOT_FOUND this.write_null(dest)?; diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 37aee1f5652c1..a7aec53c37deb 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -5,7 +5,7 @@ use rustc::mir::interpret::{InterpResult, PointerArithmetic}; use rustc::ty; use rustc::ty::layout::{self, Align, LayoutOf, Size}; use rustc_apfloat::Float; -use syntax::source_map::Span; +use rustc_span::source_map::Span; use crate::*; diff --git a/src/shims/panic.rs b/src/shims/panic.rs index 8f082f45c9159..950a23aa59cac 100644 --- a/src/shims/panic.rs +++ b/src/shims/panic.rs @@ -14,7 +14,7 @@ use rustc::mir; use rustc::ty::{self, layout::LayoutOf}; use rustc_target::spec::PanicStrategy; -use syntax::source_map::Span; +use rustc_span::source_map::Span; use crate::*; From 3607dafd9b81ff2ea18861ce8bea110513e87807 Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Mon, 6 Jan 2020 13:22:24 +0900 Subject: [PATCH 1449/3747] More rustup --- src/bin/miri-rustc-tests.rs | 4 ++-- src/bin/miri.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/bin/miri-rustc-tests.rs b/src/bin/miri-rustc-tests.rs index 19816fe008f5d..f3b271c359529 100644 --- a/src/bin/miri-rustc-tests.rs +++ b/src/bin/miri-rustc-tests.rs @@ -7,7 +7,7 @@ extern crate rustc_driver; extern crate rustc_errors; extern crate rustc_interface; extern crate rustc_metadata; -extern crate syntax; +extern crate rustc_span; use std::io; use std::io::Write; @@ -40,7 +40,7 @@ impl rustc_driver::Callbacks for MiriCompilerCalls { impl<'tcx, 'hir> itemlikevisit::ItemLikeVisitor<'hir> for Visitor<'tcx> { fn visit_item(&mut self, i: &'hir hir::Item) { if let hir::ItemKind::Fn(.., body_id) = i.kind { - if i.attrs.iter().any(|attr| attr.check_name(syntax::symbol::sym::test)) + if i.attrs.iter().any(|attr| attr.check_name(rustc_span::symbol::sym::test)) { let config = MiriConfig { validate: true, diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 1af79b259613d..17c5fc20608e2 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -12,7 +12,7 @@ extern crate rustc_driver; extern crate rustc_errors; extern crate rustc_interface; extern crate rustc_metadata; -extern crate syntax; +extern crate rustc_span; use std::convert::TryFrom; use std::env; From e979589357fa3331337575a3ade04eaf48c4cccd Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 6 Jan 2020 10:43:41 +0100 Subject: [PATCH 1450/3747] no longer test 32bit macOS --- travis.sh | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/travis.sh b/travis.sh index af297129e8216..7046a3226b7dd 100755 --- a/travis.sh +++ b/travis.sh @@ -2,9 +2,7 @@ set -euo pipefail # Determine configuration -if [ "$TRAVIS_OS_NAME" == osx ]; then - FOREIGN_TARGET=i686-apple-darwin -else +if [ "$TRAVIS_OS_NAME" == linux ]; then FOREIGN_TARGET=i686-unknown-linux-gnu fi export CARGO_EXTRA_FLAGS="--all-features" @@ -28,6 +26,8 @@ echo "Test host architecture" run_tests echo -echo "Test foreign architecture ($FOREIGN_TARGET)" -MIRI_TEST_TARGET="$FOREIGN_TARGET" run_tests -echo +if [ -n "$FOREIGN_TARGET" ]; then + echo "Test foreign architecture ($FOREIGN_TARGET)" + MIRI_TEST_TARGET="$FOREIGN_TARGET" run_tests + echo +fi From 6a614708ca599cd4e2514429c167d8e045ca8128 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 6 Jan 2020 11:02:25 +0100 Subject: [PATCH 1451/3747] fix testing if a variable exists --- travis.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/travis.sh b/travis.sh index 7046a3226b7dd..3d4b8651fb839 100755 --- a/travis.sh +++ b/travis.sh @@ -26,7 +26,7 @@ echo "Test host architecture" run_tests echo -if [ -n "$FOREIGN_TARGET" ]; then +if [ -n "${FOREIGN_TARGET+exists}" ]; then echo "Test foreign architecture ($FOREIGN_TARGET)" MIRI_TEST_TARGET="$FOREIGN_TARGET" run_tests echo From 0217a25a12d87d010c3df381b0b3d1206837ad95 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 6 Jan 2020 11:38:35 +0100 Subject: [PATCH 1452/3747] remove no-longer-needed allow(const_err) --- tests/run-pass/c_enums.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/run-pass/c_enums.rs b/tests/run-pass/c_enums.rs index 84c33ca0323f4..16b795342eab8 100644 --- a/tests/run-pass/c_enums.rs +++ b/tests/run-pass/c_enums.rs @@ -1,5 +1,3 @@ -#![allow(const_err)] // don't warn about truncating casts. FIXME: remove this, the error shouldn't even be shown - enum Foo { Bar = 42, Baz, From 86ee705cd5667ff868fa00456f14b29bc3b30c88 Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Tue, 7 Jan 2020 04:53:41 +0900 Subject: [PATCH 1453/3747] Rustup --- benches/helpers/miri_helper.rs | 3 ++- rust-version | 2 +- src/bin/miri-rustc-tests.rs | 6 ++++-- src/bin/miri.rs | 3 ++- src/eval.rs | 2 +- src/helpers.rs | 4 ++-- src/lib.rs | 1 + src/machine.rs | 2 +- src/shims/foreign_items.rs | 2 +- src/shims/fs.rs | 2 +- src/stacked_borrows.rs | 2 +- 11 files changed, 17 insertions(+), 12 deletions(-) diff --git a/benches/helpers/miri_helper.rs b/benches/helpers/miri_helper.rs index 92aedcc4244a9..122d381f79272 100644 --- a/benches/helpers/miri_helper.rs +++ b/benches/helpers/miri_helper.rs @@ -2,12 +2,13 @@ extern crate getopts; extern crate miri; extern crate rustc; extern crate rustc_driver; +extern crate rustc_hir; extern crate rustc_interface; extern crate test; use self::miri::eval_main; use crate::test::Bencher; -use rustc::hir::def_id::LOCAL_CRATE; +use rustc_hir::def_id::LOCAL_CRATE; use rustc_driver::Compilation; use rustc_interface::{interface, Queries}; diff --git a/rust-version b/rust-version index 44bed6b73d1a5..d39ff0adb2683 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -093241deae70ba38413aff823b31c23731debf14 +ebbb2bf37aedaaa64dfaa52ba337ca6efb6b9093 diff --git a/src/bin/miri-rustc-tests.rs b/src/bin/miri-rustc-tests.rs index f3b271c359529..2ac0ab9ca4de1 100644 --- a/src/bin/miri-rustc-tests.rs +++ b/src/bin/miri-rustc-tests.rs @@ -5,6 +5,7 @@ extern crate rustc; extern crate rustc_codegen_utils; extern crate rustc_driver; extern crate rustc_errors; +extern crate rustc_hir; extern crate rustc_interface; extern crate rustc_metadata; extern crate rustc_span; @@ -14,8 +15,9 @@ use std::io::Write; use std::path::Path; use std::sync::{Arc, Mutex}; -use rustc::hir::def_id::LOCAL_CRATE; -use rustc::hir::{self, itemlikevisit}; +use rustc_hir as hir; +use rustc_hir::def_id::LOCAL_CRATE; +use rustc_hir::itemlikevisit; use rustc::ty::TyCtxt; use rustc_driver::Compilation; use rustc_interface::{interface, Queries}; diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 17c5fc20608e2..228c50e4a57b2 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -10,6 +10,7 @@ extern crate rustc; extern crate rustc_codegen_utils; extern crate rustc_driver; extern crate rustc_errors; +extern crate rustc_hir; extern crate rustc_interface; extern crate rustc_metadata; extern crate rustc_span; @@ -20,7 +21,7 @@ use std::str::FromStr; use hex::FromHexError; -use rustc::hir::def_id::LOCAL_CRATE; +use rustc_hir::def_id::LOCAL_CRATE; use rustc_driver::Compilation; use rustc_interface::{interface, Queries}; diff --git a/src/eval.rs b/src/eval.rs index 1968111307e77..eac9b8a83baa9 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -5,7 +5,7 @@ use std::ffi::OsStr; use rand::rngs::StdRng; use rand::SeedableRng; -use rustc::hir::def_id::DefId; +use rustc_hir::def_id::DefId; use rustc::ty::layout::{LayoutOf, Size}; use rustc::ty::{self, TyCtxt}; diff --git a/src/helpers.rs b/src/helpers.rs index 17d74d2ef757c..ff9a16a024569 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -1,7 +1,7 @@ use std::ffi::OsStr; use std::{iter, mem}; -use rustc::hir::def_id::{DefId, CRATE_DEF_INDEX}; +use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX}; use rustc::mir; use rustc::ty::{ self, @@ -331,7 +331,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// Helper function to get the `TyLayout` of a `libc` type fn libc_ty_layout(&mut self, name: &str) -> InterpResult<'tcx, TyLayout<'tcx>> { let this = self.eval_context_mut(); - let ty = this.resolve_path(&["libc", name])?.ty(*this.tcx); + let ty = this.resolve_path(&["libc", name])?.monomorphic_ty(*this.tcx); this.layout_of(ty) } diff --git a/src/lib.rs b/src/lib.rs index 2ddcdf8ff7776..19a84db3e17e3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -10,6 +10,7 @@ extern crate rustc_apfloat; extern crate syntax; #[macro_use] extern crate rustc; +extern crate rustc_hir; extern crate rustc_span; extern crate rustc_data_structures; extern crate rustc_mir; diff --git a/src/machine.rs b/src/machine.rs index 4c1446c82c748..f8c7168a5847c 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -7,7 +7,7 @@ use std::rc::Rc; use rand::rngs::StdRng; -use rustc::hir::def_id::DefId; +use rustc_hir::def_id::DefId; use rustc::mir; use rustc::ty::{ self, diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 6ad16c6f67647..2d6eafdf8f19f 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -1,6 +1,6 @@ use std::{convert::TryInto, iter}; -use rustc::hir::def_id::DefId; +use rustc_hir::def_id::DefId; use rustc::mir; use rustc::ty; use rustc::ty::layout::{Align, LayoutOf, Size}; diff --git a/src/shims/fs.rs b/src/shims/fs.rs index 8c8bd6f7bb97f..8583696828925 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -389,7 +389,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // function and `resolve_path` is returning the latter. let statx_ty = this .resolve_path(&["libc", "unix", "linux_like", "linux", "gnu", "statx"])? - .ty(*this.tcx); + .monomorphic_ty(*this.tcx); let statxbuf_ty = this.tcx.mk_mut_ptr(statx_ty); let statxbuf_layout = this.layout_of(statxbuf_ty)?; let statxbuf_imm = ImmTy::from_scalar(statxbuf_scalar, statxbuf_layout); diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 18edb603c6cf1..53a94e74cbf02 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -7,7 +7,7 @@ use std::fmt; use std::num::NonZeroU64; use std::rc::Rc; -use rustc::hir::Mutability; +use rustc_hir::Mutability; use rustc::mir::RetagKind; use rustc::ty::{self, layout::Size}; From 4a1dbc77dc9f64aebd0b16927bb71f3178376d30 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Mon, 6 Jan 2020 16:30:17 -0500 Subject: [PATCH 1454/3747] Add shim for symbolic link creation --- src/shims/foreign_items.rs | 5 +++++ src/shims/fs.rs | 31 ++++++++++++++++++++++++++++++- tests/run-pass/fs.rs | 17 ++++++++++++++++- 3 files changed, 51 insertions(+), 2 deletions(-) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 07e3b7d758265..6a2f42f832150 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -494,6 +494,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; } + "symlink" => { + let result = this.symlink(args[0], args[1])?; + this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + } + "stat$INODE64" => { let result = this.stat(args[0], args[1])?; this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; diff --git a/src/shims/fs.rs b/src/shims/fs.rs index 8c8bd6f7bb97f..c5b753f3b6a24 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -276,6 +276,36 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.try_unwrap_io_result(result) } + fn symlink( + &mut self, + target_op: OpTy<'tcx, Tag>, + linkpath_op: OpTy<'tcx, Tag> + ) -> InterpResult<'tcx, i32> { + #[cfg(target_family = "unix")] + fn create_link(src: PathBuf, dst: PathBuf) -> std::io::Result<()> { + std::os::unix::fs::symlink(src, dst) + } + + #[cfg(target_family = "windows")] + fn create_link(src: PathBuf, dst: PathBuf) -> std::io::Result<()> { + use std::os::windows::fs; + if src.is_dir() { + fs::symlink_dir(src, dst) + } else { + fs::symlink(src, dst) + } + } + + let this = self.eval_context_mut(); + + this.check_no_isolation("symlink")?; + + let target = this.read_os_str_from_c_str(this.read_scalar(target_op)?.not_undef()?)?.into(); + let linkpath = this.read_os_str_from_c_str(this.read_scalar(linkpath_op)?.not_undef()?)?.into(); + + this.try_unwrap_io_result(create_link(target, linkpath).map(|_| 0)) + } + fn stat( &mut self, path_op: OpTy<'tcx, Tag>, @@ -545,7 +575,6 @@ impl FileMetadata { let metadata = if follow_symlink { std::fs::metadata(path) } else { - // FIXME: metadata for symlinks need testing. std::fs::symlink_metadata(path) }; diff --git a/tests/run-pass/fs.rs b/tests/run-pass/fs.rs index 85e39bc45112b..9e0428fb57c27 100644 --- a/tests/run-pass/fs.rs +++ b/tests/run-pass/fs.rs @@ -39,9 +39,24 @@ fn main() { // Test that metadata of an absolute path is correct. test_metadata(bytes, &path).unwrap(); // Test that metadata of a relative path is correct. - std::env::set_current_dir(tmp).unwrap(); + std::env::set_current_dir(&tmp).unwrap(); test_metadata(bytes, &filename).unwrap(); + // Creating a symbolic link should succeed + let symlink_path = tmp.join("miri_test_fs_symlink.txt"); + std::os::unix::fs::symlink(&path, &symlink_path).unwrap(); + // Test that the symbolic link has the same contents as the file. + let mut symlink_file = File::open(&symlink_path).unwrap(); + let mut contents = Vec::new(); + symlink_file.read_to_end(&mut contents).unwrap(); + assert_eq!(bytes, contents.as_slice()); + // Test that metadata of a symbolic link is correct. + test_metadata(bytes, &symlink_path).unwrap(); + // Test that the metadata of a symbolic link is correct when not following it. + assert!(symlink_path.symlink_metadata().unwrap().file_type().is_symlink()); + // Removing symbolic link should succeed. + remove_file(&symlink_path).unwrap(); + // Removing file should succeed. remove_file(&path).unwrap(); From 329310fbd63c564df6dd76f40181668861a7ed16 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Tue, 7 Jan 2020 11:09:07 -0500 Subject: [PATCH 1455/3747] Clean paths for robustness --- tests/run-pass/fs.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/tests/run-pass/fs.rs b/tests/run-pass/fs.rs index 9e0428fb57c27..90b5dcfb5fa61 100644 --- a/tests/run-pass/fs.rs +++ b/tests/run-pass/fs.rs @@ -19,7 +19,11 @@ fn main() { let tmp = std::env::temp_dir(); let filename = PathBuf::from("miri_test_fs.txt"); let path = tmp.join(&filename); + let symlink_path = tmp.join("miri_test_fs_symlink.txt"); let bytes = b"Hello, World!\n"; + // Clean the paths for robustness. + remove_file(&path).unwrap_or(()); + remove_file(&symlink_path).unwrap_or(()); // Test creating, writing and closing a file (closing is tested when `file` is dropped). let mut file = File::create(&path).unwrap(); @@ -42,8 +46,7 @@ fn main() { std::env::set_current_dir(&tmp).unwrap(); test_metadata(bytes, &filename).unwrap(); - // Creating a symbolic link should succeed - let symlink_path = tmp.join("miri_test_fs_symlink.txt"); + // Creating a symbolic link should succeed. std::os::unix::fs::symlink(&path, &symlink_path).unwrap(); // Test that the symbolic link has the same contents as the file. let mut symlink_file = File::open(&symlink_path).unwrap(); From 91cf68fac569d0817fc8649bff28d727bbed47b2 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Tue, 7 Jan 2020 11:29:25 -0500 Subject: [PATCH 1456/3747] Add lstat shim for macos --- src/shims/foreign_items.rs | 5 +++++ src/shims/fs.rs | 26 ++++++++++++++++++++++++-- 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 6a2f42f832150..f3baebad143b3 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -504,6 +504,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; } + "lstat$INODE64" => { + let result = this.lstat(args[0], args[1])?; + this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + } + "clock_gettime" => { let result = this.clock_gettime(args[0], args[1])?; this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; diff --git a/src/shims/fs.rs b/src/shims/fs.rs index c5b753f3b6a24..3927f0e649198 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -312,6 +312,29 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx buf_op: OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); + this.check_no_isolation("stat")?; + // `stat` always follows symlinks. + this.stat_or_lstat(true, path_op, buf_op) + } + + // `lstat` is used to get symlink metadata. + fn lstat( + &mut self, + path_op: OpTy<'tcx, Tag>, + buf_op: OpTy<'tcx, Tag>, + ) -> InterpResult<'tcx, i32> { + let this = self.eval_context_mut(); + this.check_no_isolation("lstat")?; + this.stat_or_lstat(false, path_op, buf_op) + } + + fn stat_or_lstat( + &mut self, + follow_symlink: bool, + path_op: OpTy<'tcx, Tag>, + buf_op: OpTy<'tcx, Tag>, + ) -> InterpResult<'tcx, i32> { + let this = self.eval_context_mut(); if this.tcx.sess.target.target.target_os.to_lowercase() != "macos" { throw_unsup_format!("The `stat` shim is only available for `macos` targets.") @@ -322,8 +345,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let buf = this.deref_operand(buf_op)?; - // `stat` always follows symlinks. `lstat` is used to get symlink metadata. - let metadata = match FileMetadata::new(this, path, true)? { + let metadata = match FileMetadata::new(this, path, follow_symlink)? { Some(metadata) => metadata, None => return Ok(-1), }; From b9f6b9721a72abfb9f83d8b25cb41ed5c618d755 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Tue, 24 Dec 2019 00:07:55 +0100 Subject: [PATCH 1457/3747] Split error reporting from main eval function --- src/eval.rs | 110 ++++++++++++++++++++++++++-------------------------- 1 file changed, 56 insertions(+), 54 deletions(-) diff --git a/src/eval.rs b/src/eval.rs index eac9b8a83baa9..b2f290414ceea 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -8,6 +8,7 @@ use rand::SeedableRng; use rustc_hir::def_id::DefId; use rustc::ty::layout::{LayoutOf, Size}; use rustc::ty::{self, TyCtxt}; +use rustc_mir::interpret::InterpErrorInfo; use crate::*; @@ -205,64 +206,65 @@ pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) -> } return Some(return_code); } - Err(mut e) => { - // Special treatment for some error kinds - let msg = match e.kind { - InterpError::MachineStop(ref info) => { - let info = info - .downcast_ref::() - .expect("invalid MachineStop payload"); - match info { - TerminationInfo::Exit(code) => return Some(*code), - TerminationInfo::PoppedTrackedPointerTag(item) => - format!("popped tracked tag for item {:?}", item), - TerminationInfo::Abort => - format!("the evaluated program aborted execution"), - } - } - err_unsup!(NoMirFor(..)) => format!( - "{}. Did you set `MIRI_SYSROOT` to a Miri-enabled sysroot? You can prepare one with `cargo miri setup`.", - e - ), - InterpError::InvalidProgram(_) => - bug!("This error should be impossible in Miri: {}", e), - _ => e.to_string(), - }; - e.print_backtrace(); - if let Some(frame) = ecx.stack().last() { - let span = frame.current_source_info().unwrap().span; + Err(e) => report_err(&ecx, e), + } +} - let msg = format!("Miri evaluation error: {}", msg); - let mut err = ecx.tcx.sess.struct_span_err(span, msg.as_str()); - let frames = ecx.generate_stacktrace(None); - err.span_label(span, msg); - // We iterate with indices because we need to look at the next frame (the caller). - for idx in 0..frames.len() { - let frame_info = &frames[idx]; - let call_site_is_local = frames - .get(idx + 1) - .map_or(false, |caller_info| caller_info.instance.def_id().is_local()); - if call_site_is_local { - err.span_note(frame_info.call_site, &frame_info.to_string()); - } else { - err.note(&frame_info.to_string()); - } - } - err.emit(); - } else { - ecx.tcx.sess.err(&msg); +fn report_err<'tcx, 'mir>( + ecx: &InterpCx<'mir, 'tcx, Evaluator<'tcx>>, + mut e: InterpErrorInfo<'tcx>, +) -> Option { + // Special treatment for some error kinds + let msg = match e.kind { + InterpError::MachineStop(ref info) => { + let info = info.downcast_ref::().expect("invalid MachineStop payload"); + match info { + TerminationInfo::Exit(code) => return Some(*code), + TerminationInfo::PoppedTrackedPointerTag(item) => + format!("popped tracked tag for item {:?}", item), + TerminationInfo::Abort => format!("the evaluated program aborted execution"), } + } + err_unsup!(NoMirFor(..)) => format!( + "{}. Did you set `MIRI_SYSROOT` to a Miri-enabled sysroot? You can prepare one with `cargo miri setup`.", + e + ), + InterpError::InvalidProgram(_) => bug!("This error should be impossible in Miri: {}", e), + _ => e.to_string(), + }; + e.print_backtrace(); + if let Some(frame) = ecx.stack().last() { + let span = frame.current_source_info().unwrap().span; - for (i, frame) in ecx.stack().iter().enumerate() { - trace!("-------------------"); - trace!("Frame {}", i); - trace!(" return: {:?}", frame.return_place.map(|p| *p)); - for (i, local) in frame.locals.iter().enumerate() { - trace!(" local {}: {:?}", i, local.value); - } + let msg = format!("Miri evaluation error: {}", msg); + let mut err = ecx.tcx.sess.struct_span_err(span, msg.as_str()); + let frames = ecx.generate_stacktrace(None); + err.span_label(span, msg); + // We iterate with indices because we need to look at the next frame (the caller). + for idx in 0..frames.len() { + let frame_info = &frames[idx]; + let call_site_is_local = frames + .get(idx + 1) + .map_or(false, |caller_info| caller_info.instance.def_id().is_local()); + if call_site_is_local { + err.span_note(frame_info.call_site, &frame_info.to_string()); + } else { + err.note(&frame_info.to_string()); } - // Let the reported error determine the return code. - return None; + } + err.emit(); + } else { + ecx.tcx.sess.err(&msg); + } + + for (i, frame) in ecx.stack().iter().enumerate() { + trace!("-------------------"); + trace!("Frame {}", i); + trace!(" return: {:?}", frame.return_place.map(|p| *p)); + for (i, local) in frame.locals.iter().enumerate() { + trace!(" local {}: {:?}", i, local.value); } } + // Let the reported error determine the return code. + return None; } From 2673ba99fd28abc8448159a51d288ec942e7a65e Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Tue, 24 Dec 2019 00:08:47 +0100 Subject: [PATCH 1458/3747] Trailing return --- src/eval.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/eval.rs b/src/eval.rs index b2f290414ceea..9c15fedca3d0e 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -204,7 +204,7 @@ pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) -> return None; } } - return Some(return_code); + Some(return_code) } Err(e) => report_err(&ecx, e), } From 4de031b3da1c3dc8091a64daa46322ced3796c0f Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Tue, 24 Dec 2019 00:11:40 +0100 Subject: [PATCH 1459/3747] Move error reporting to its own module --- src/diagnostics.rs | 62 ++++++++++++++++++++++++++++++++++++++++++++++ src/eval.rs | 60 -------------------------------------------- src/lib.rs | 2 ++ 3 files changed, 64 insertions(+), 60 deletions(-) create mode 100644 src/diagnostics.rs diff --git a/src/diagnostics.rs b/src/diagnostics.rs new file mode 100644 index 0000000000000..30be49ff770cd --- /dev/null +++ b/src/diagnostics.rs @@ -0,0 +1,62 @@ +use rustc_mir::interpret::InterpErrorInfo; + +use crate::*; + +pub fn report_err<'tcx, 'mir>( + ecx: &InterpCx<'mir, 'tcx, Evaluator<'tcx>>, + mut e: InterpErrorInfo<'tcx>, +) -> Option { + // Special treatment for some error kinds + let msg = match e.kind { + InterpError::MachineStop(ref info) => { + let info = info.downcast_ref::().expect("invalid MachineStop payload"); + match info { + TerminationInfo::Exit(code) => return Some(*code), + TerminationInfo::PoppedTrackedPointerTag(item) => + format!("popped tracked tag for item {:?}", item), + TerminationInfo::Abort => format!("the evaluated program aborted execution"), + } + } + err_unsup!(NoMirFor(..)) => format!( + "{}. Did you set `MIRI_SYSROOT` to a Miri-enabled sysroot? You can prepare one with `cargo miri setup`.", + e + ), + InterpError::InvalidProgram(_) => bug!("This error should be impossible in Miri: {}", e), + _ => e.to_string(), + }; + e.print_backtrace(); + if let Some(frame) = ecx.stack().last() { + let span = frame.current_source_info().unwrap().span; + + let msg = format!("Miri evaluation error: {}", msg); + let mut err = ecx.tcx.sess.struct_span_err(span, msg.as_str()); + let frames = ecx.generate_stacktrace(None); + err.span_label(span, msg); + // We iterate with indices because we need to look at the next frame (the caller). + for idx in 0..frames.len() { + let frame_info = &frames[idx]; + let call_site_is_local = frames + .get(idx + 1) + .map_or(false, |caller_info| caller_info.instance.def_id().is_local()); + if call_site_is_local { + err.span_note(frame_info.call_site, &frame_info.to_string()); + } else { + err.note(&frame_info.to_string()); + } + } + err.emit(); + } else { + ecx.tcx.sess.err(&msg); + } + + for (i, frame) in ecx.stack().iter().enumerate() { + trace!("-------------------"); + trace!("Frame {}", i); + trace!(" return: {:?}", frame.return_place.map(|p| *p)); + for (i, local) in frame.locals.iter().enumerate() { + trace!(" local {}: {:?}", i, local.value); + } + } + // Let the reported error determine the return code. + return None; +} diff --git a/src/eval.rs b/src/eval.rs index 9c15fedca3d0e..e5dfbe32c12e0 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -8,7 +8,6 @@ use rand::SeedableRng; use rustc_hir::def_id::DefId; use rustc::ty::layout::{LayoutOf, Size}; use rustc::ty::{self, TyCtxt}; -use rustc_mir::interpret::InterpErrorInfo; use crate::*; @@ -209,62 +208,3 @@ pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) -> Err(e) => report_err(&ecx, e), } } - -fn report_err<'tcx, 'mir>( - ecx: &InterpCx<'mir, 'tcx, Evaluator<'tcx>>, - mut e: InterpErrorInfo<'tcx>, -) -> Option { - // Special treatment for some error kinds - let msg = match e.kind { - InterpError::MachineStop(ref info) => { - let info = info.downcast_ref::().expect("invalid MachineStop payload"); - match info { - TerminationInfo::Exit(code) => return Some(*code), - TerminationInfo::PoppedTrackedPointerTag(item) => - format!("popped tracked tag for item {:?}", item), - TerminationInfo::Abort => format!("the evaluated program aborted execution"), - } - } - err_unsup!(NoMirFor(..)) => format!( - "{}. Did you set `MIRI_SYSROOT` to a Miri-enabled sysroot? You can prepare one with `cargo miri setup`.", - e - ), - InterpError::InvalidProgram(_) => bug!("This error should be impossible in Miri: {}", e), - _ => e.to_string(), - }; - e.print_backtrace(); - if let Some(frame) = ecx.stack().last() { - let span = frame.current_source_info().unwrap().span; - - let msg = format!("Miri evaluation error: {}", msg); - let mut err = ecx.tcx.sess.struct_span_err(span, msg.as_str()); - let frames = ecx.generate_stacktrace(None); - err.span_label(span, msg); - // We iterate with indices because we need to look at the next frame (the caller). - for idx in 0..frames.len() { - let frame_info = &frames[idx]; - let call_site_is_local = frames - .get(idx + 1) - .map_or(false, |caller_info| caller_info.instance.def_id().is_local()); - if call_site_is_local { - err.span_note(frame_info.call_site, &frame_info.to_string()); - } else { - err.note(&frame_info.to_string()); - } - } - err.emit(); - } else { - ecx.tcx.sess.err(&msg); - } - - for (i, frame) in ecx.stack().iter().enumerate() { - trace!("-------------------"); - trace!("Frame {}", i); - trace!(" return: {:?}", frame.return_place.map(|p| *p)); - for (i, local) in frame.locals.iter().enumerate() { - trace!(" local {}: {:?}", i, local.value); - } - } - // Let the reported error determine the return code. - return None; -} diff --git a/src/lib.rs b/src/lib.rs index 19a84db3e17e3..b5925bb26c897 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -16,6 +16,7 @@ extern crate rustc_data_structures; extern crate rustc_mir; extern crate rustc_target; +mod diagnostics; mod eval; mod helpers; mod intptrcast; @@ -41,6 +42,7 @@ pub use crate::shims::time::EvalContextExt as TimeEvalContextExt; pub use crate::shims::tls::{EvalContextExt as TlsEvalContextExt, TlsData}; pub use crate::shims::EvalContextExt as ShimsEvalContextExt; +pub use crate::diagnostics::report_err; pub use crate::eval::{create_ecx, eval_main, MiriConfig, TerminationInfo}; pub use crate::helpers::EvalContextExt as HelpersEvalContextExt; pub use crate::machine::{ From 4411903cca01933cc98ac903b3864768b6136024 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Tue, 24 Dec 2019 00:22:32 +0100 Subject: [PATCH 1460/3747] Add a scheme for registering and obtaining errors even without access to an `InterpCx` --- src/diagnostics.rs | 17 +++++++++++++++++ src/lib.rs | 2 +- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/src/diagnostics.rs b/src/diagnostics.rs index 30be49ff770cd..2431d9230f36f 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -60,3 +60,20 @@ pub fn report_err<'tcx, 'mir>( // Let the reported error determine the return code. return None; } + +use std::cell::RefCell; +thread_local! { + static ECX: RefCell>> = RefCell::new(Vec::new()); +} + +pub fn register_err(e: InterpErrorInfo<'static>) { + ECX.with(|ecx| ecx.borrow_mut().push(e)); +} + +pub fn process_errors(mut f: impl FnMut(InterpErrorInfo<'static>)) { + ECX.with(|ecx| { + for e in ecx.borrow_mut().drain(..) { + f(e); + } + }); +} diff --git a/src/lib.rs b/src/lib.rs index b5925bb26c897..bf6b111754de9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -42,7 +42,7 @@ pub use crate::shims::time::EvalContextExt as TimeEvalContextExt; pub use crate::shims::tls::{EvalContextExt as TlsEvalContextExt, TlsData}; pub use crate::shims::EvalContextExt as ShimsEvalContextExt; -pub use crate::diagnostics::report_err; +pub use crate::diagnostics::{process_errors, register_err, report_err}; pub use crate::eval::{create_ecx, eval_main, MiriConfig, TerminationInfo}; pub use crate::helpers::EvalContextExt as HelpersEvalContextExt; pub use crate::machine::{ From 96d6efdf32f346c45f58897b2f7fff38a476cfbe Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Tue, 24 Dec 2019 02:04:07 +0100 Subject: [PATCH 1461/3747] Emit errors without halting interpretation --- src/diagnostics.rs | 16 ++++++++++------ src/lib.rs | 4 +++- src/stacked_borrows.rs | 15 ++++++++++----- 3 files changed, 23 insertions(+), 12 deletions(-) diff --git a/src/diagnostics.rs b/src/diagnostics.rs index 2431d9230f36f..504863b13427c 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -70,10 +70,14 @@ pub fn register_err(e: InterpErrorInfo<'static>) { ECX.with(|ecx| ecx.borrow_mut().push(e)); } -pub fn process_errors(mut f: impl FnMut(InterpErrorInfo<'static>)) { - ECX.with(|ecx| { - for e in ecx.borrow_mut().drain(..) { - f(e); - } - }); +impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} +pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { + fn process_errors(&self) { + let this = self.eval_context_ref(); + ECX.with(|ecx| { + for e in ecx.borrow_mut().drain(..) { + report_err(this, e); + } + }); + } } diff --git a/src/lib.rs b/src/lib.rs index bf6b111754de9..ae92a777d88e4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -42,7 +42,9 @@ pub use crate::shims::time::EvalContextExt as TimeEvalContextExt; pub use crate::shims::tls::{EvalContextExt as TlsEvalContextExt, TlsData}; pub use crate::shims::EvalContextExt as ShimsEvalContextExt; -pub use crate::diagnostics::{process_errors, register_err, report_err}; +pub use crate::diagnostics::{ + register_err, report_err, EvalContextExt as DiagnosticsEvalContextExt, +}; pub use crate::eval::{create_ecx, eval_main, MiriConfig, TerminationInfo}; pub use crate::helpers::EvalContextExt as HelpersEvalContextExt; pub use crate::machine::{ diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 53a94e74cbf02..3d446c6b468e3 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -10,11 +10,9 @@ use std::rc::Rc; use rustc_hir::Mutability; use rustc::mir::RetagKind; use rustc::ty::{self, layout::Size}; +use rustc_mir::interpret::InterpError; -use crate::{ - AllocId, HelpersEvalContextExt, ImmTy, Immediate, InterpResult, MPlaceTy, MemoryKind, - MiriMemoryKind, PlaceTy, Pointer, RangeMap, TerminationInfo, -}; +use crate::*; pub type PtrId = NonZeroU64; pub type CallId = NonZeroU64; @@ -269,7 +267,12 @@ impl<'tcx> Stack { fn check_protector(item: &Item, tag: Option, global: &GlobalState) -> InterpResult<'tcx> { if let Tag::Tagged(id) = item.tag { if Some(id) == global.tracked_pointer_tag { - throw_machine_stop!(TerminationInfo::PoppedTrackedPointerTag(item.clone())); + register_err( + InterpError::MachineStop(Box::new(TerminationInfo::PoppedTrackedPointerTag( + item.clone(), + ))) + .into(), + ); } } if let Some(call) = item.protector { @@ -630,6 +633,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_immediate(val, place)?; } + this.process_errors(); + Ok(()) } } From bb58e42da2315c30594222bccb64b8a63fb537be Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Tue, 24 Dec 2019 02:16:43 +0100 Subject: [PATCH 1462/3747] Tell the user about stacked borrow debugging flags --- src/stacked_borrows.rs | 44 +++++++++++++++++++++++++++++------------- 1 file changed, 31 insertions(+), 13 deletions(-) diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 3d446c6b468e3..77295e8dd5364 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -4,6 +4,7 @@ use std::cell::RefCell; use std::collections::{HashMap, HashSet}; use std::fmt; +use std::fmt::Write; use std::num::NonZeroU64; use std::rc::Rc; @@ -278,10 +279,13 @@ impl<'tcx> Stack { if let Some(call) = item.protector { if global.is_active(call) { if let Some(tag) = tag { - throw_ub!(UbExperimental(format!( - "not granting access to tag {:?} because incompatible item is protected: {:?}", - tag, item - ))); + return Err(err_ub_experimental( + tag, + format!( + "not granting access to tag {:?} because incompatible item is protected: {:?}", + tag, item + ), + )); } else { throw_ub!(UbExperimental(format!( "deallocating while item is protected: {:?}", @@ -300,10 +304,10 @@ impl<'tcx> Stack { // Step 1: Find granting item. let granting_idx = self.find_granting(access, tag).ok_or_else(|| { - err_ub!(UbExperimental(format!( - "no item granting {} to tag {:?} found in borrow stack", - access, tag, - ))) + err_ub_experimental( + tag, + format!("no item granting {} to tag {:?} found in borrow stack.", access, tag), + ) })?; // Step 2: Remove incompatible items above them. Make sure we do not remove protected @@ -344,10 +348,11 @@ impl<'tcx> Stack { fn dealloc(&mut self, tag: Tag, global: &GlobalState) -> InterpResult<'tcx> { // Step 1: Find granting item. self.find_granting(AccessKind::Write, tag).ok_or_else(|| { - err_ub!(UbExperimental(format!( + err_ub_experimental( + tag,format!( "no item granting write access for deallocation to tag {:?} found in borrow stack", tag, - ))) + )) })?; // Step 2: Remove all items. Also checks for protectors. @@ -369,9 +374,14 @@ impl<'tcx> Stack { // Now we figure out which item grants our parent (`derived_from`) this kind of access. // We use that to determine where to put the new item. let granting_idx = self.find_granting(access, derived_from) - .ok_or_else(|| err_ub!(UbExperimental(format!( - "trying to reborrow for {:?}, but parent tag {:?} does not have an appropriate item in the borrow stack", new.perm, derived_from, - ))))?; + .ok_or_else(|| + err_ub_experimental( + derived_from, + format!( + "trying to reborrow for {:?}, but parent tag {:?} does not have an appropriate item in the borrow stack", + new.perm, derived_from, + ), + ))?; // Compute where to put the new item. // Either way, we ensure that we insert the new item in a way such that between @@ -638,3 +648,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(()) } } + +fn err_ub_experimental(tag: Tag, mut msg: String) -> InterpErrorInfo<'static> { + if let Tag::Tagged(id) = tag { + // FIXME: do not add this message when the flag is already set + write!(msg, " Rerun with `-Zmiri-track-pointer-tag={}` for more information", id).unwrap(); + } + err_ub!(UbExperimental(msg)).into() +} From aec175e0deb39d35a9b5c0f329141c4b22930e01 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Wed, 8 Jan 2020 12:49:46 +0100 Subject: [PATCH 1463/3747] Process delayed errors on every step --- src/eval.rs | 4 +++- src/stacked_borrows.rs | 2 -- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/eval.rs b/src/eval.rs index e5dfbe32c12e0..1e9332c9a32df 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -183,7 +183,9 @@ pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) -> // Perform the main execution. let res: InterpResult<'_, i64> = (|| { - ecx.run()?; + while ecx.step()? { + ecx.process_errors(); + } // Read the return code pointer *before* we run TLS destructors, to assert // that it was written to by the time that `start` lang item returned. let return_code = ecx.read_scalar(ret_place.into())?.not_undef()?.to_machine_isize(&ecx)?; diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 77295e8dd5364..ace4fef3ce3b4 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -643,8 +643,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_immediate(val, place)?; } - this.process_errors(); - Ok(()) } } From c0a7fd56021a375478bd9e202bf5692e4e48736a Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Wed, 8 Jan 2020 12:50:15 +0100 Subject: [PATCH 1464/3747] Remove debugging hint until we can actuall use `note:` --- src/stacked_borrows.rs | 51 +++++++++++++----------------------------- 1 file changed, 15 insertions(+), 36 deletions(-) diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index ace4fef3ce3b4..7bb7dd6cec11b 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -4,7 +4,6 @@ use std::cell::RefCell; use std::collections::{HashMap, HashSet}; use std::fmt; -use std::fmt::Write; use std::num::NonZeroU64; use std::rc::Rc; @@ -279,13 +278,10 @@ impl<'tcx> Stack { if let Some(call) = item.protector { if global.is_active(call) { if let Some(tag) = tag { - return Err(err_ub_experimental( - tag, - format!( - "not granting access to tag {:?} because incompatible item is protected: {:?}", - tag, item - ), - )); + throw_ub!(UbExperimental(format!( + "not granting access to tag {:?} because incompatible item is protected: {:?}", + tag, item + ))); } else { throw_ub!(UbExperimental(format!( "deallocating while item is protected: {:?}", @@ -303,12 +299,9 @@ impl<'tcx> Stack { // Two main steps: Find granting item, remove incompatible items above. // Step 1: Find granting item. - let granting_idx = self.find_granting(access, tag).ok_or_else(|| { - err_ub_experimental( - tag, - format!("no item granting {} to tag {:?} found in borrow stack.", access, tag), - ) - })?; + let granting_idx = self.find_granting(access, tag).ok_or_else(|| err_ub!(UbExperimental( + format!("no item granting {} to tag {:?} found in borrow stack.", access, tag), + )))?; // Step 2: Remove incompatible items above them. Make sure we do not remove protected // items. Behavior differs for reads and writes. @@ -347,13 +340,10 @@ impl<'tcx> Stack { /// active protectors at all because we will remove all items. fn dealloc(&mut self, tag: Tag, global: &GlobalState) -> InterpResult<'tcx> { // Step 1: Find granting item. - self.find_granting(AccessKind::Write, tag).ok_or_else(|| { - err_ub_experimental( - tag,format!( - "no item granting write access for deallocation to tag {:?} found in borrow stack", - tag, - )) - })?; + self.find_granting(AccessKind::Write, tag).ok_or_else(|| err_ub!(UbExperimental(format!( + "no item granting write access for deallocation to tag {:?} found in borrow stack", + tag, + ))))?; // Step 2: Remove all items. Also checks for protectors. for item in self.borrows.drain(..).rev() { @@ -374,14 +364,10 @@ impl<'tcx> Stack { // Now we figure out which item grants our parent (`derived_from`) this kind of access. // We use that to determine where to put the new item. let granting_idx = self.find_granting(access, derived_from) - .ok_or_else(|| - err_ub_experimental( - derived_from, - format!( - "trying to reborrow for {:?}, but parent tag {:?} does not have an appropriate item in the borrow stack", - new.perm, derived_from, - ), - ))?; + .ok_or_else(|| err_ub!(UbExperimental(format!( + "trying to reborrow for {:?}, but parent tag {:?} does not have an appropriate item in the borrow stack", + new.perm, derived_from, + ))))?; // Compute where to put the new item. // Either way, we ensure that we insert the new item in a way such that between @@ -647,10 +633,3 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } -fn err_ub_experimental(tag: Tag, mut msg: String) -> InterpErrorInfo<'static> { - if let Tag::Tagged(id) = tag { - // FIXME: do not add this message when the flag is already set - write!(msg, " Rerun with `-Zmiri-track-pointer-tag={}` for more information", id).unwrap(); - } - err_ub!(UbExperimental(msg)).into() -} From 90a8f2f6a300505c528cf5afe8ead9c31c9bbfca Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Wed, 8 Jan 2020 13:02:55 +0100 Subject: [PATCH 1465/3747] Make the non-halting diagnostic scheme independent of `InterpError` --- src/diagnostics.rs | 34 ++++++++++++++++++++++++++-------- src/eval.rs | 1 - src/lib.rs | 2 +- src/stacked_borrows.rs | 8 +------- 4 files changed, 28 insertions(+), 17 deletions(-) diff --git a/src/diagnostics.rs b/src/diagnostics.rs index 504863b13427c..cf27a9c3762fe 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -1,7 +1,12 @@ use rustc_mir::interpret::InterpErrorInfo; +use std::cell::RefCell; use crate::*; +pub enum NonHaltingDiagnostic { + PoppedTrackedPointerTag(Item), +} + pub fn report_err<'tcx, 'mir>( ecx: &InterpCx<'mir, 'tcx, Evaluator<'tcx>>, mut e: InterpErrorInfo<'tcx>, @@ -12,8 +17,6 @@ pub fn report_err<'tcx, 'mir>( let info = info.downcast_ref::().expect("invalid MachineStop payload"); match info { TerminationInfo::Exit(code) => return Some(*code), - TerminationInfo::PoppedTrackedPointerTag(item) => - format!("popped tracked tag for item {:?}", item), TerminationInfo::Abort => format!("the evaluated program aborted execution"), } } @@ -25,11 +28,23 @@ pub fn report_err<'tcx, 'mir>( _ => e.to_string(), }; e.print_backtrace(); + report_msg(ecx, msg, true) +} + +pub fn report_msg<'tcx, 'mir>( + ecx: &InterpCx<'mir, 'tcx, Evaluator<'tcx>>, + msg: String, + error: bool, +) -> Option { if let Some(frame) = ecx.stack().last() { let span = frame.current_source_info().unwrap().span; - let msg = format!("Miri evaluation error: {}", msg); - let mut err = ecx.tcx.sess.struct_span_err(span, msg.as_str()); + let mut err = if error { + let msg = format!("Miri evaluation error: {}", msg); + ecx.tcx.sess.struct_span_err(span, msg.as_str()) + } else { + ecx.tcx.sess.diagnostic().span_note_diag(span, msg.as_str()) + }; let frames = ecx.generate_stacktrace(None); err.span_label(span, msg); // We iterate with indices because we need to look at the next frame (the caller). @@ -61,12 +76,11 @@ pub fn report_err<'tcx, 'mir>( return None; } -use std::cell::RefCell; thread_local! { - static ECX: RefCell>> = RefCell::new(Vec::new()); + static ECX: RefCell> = RefCell::new(Vec::new()); } -pub fn register_err(e: InterpErrorInfo<'static>) { +pub fn register_err(e: NonHaltingDiagnostic) { ECX.with(|ecx| ecx.borrow_mut().push(e)); } @@ -76,7 +90,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_ref(); ECX.with(|ecx| { for e in ecx.borrow_mut().drain(..) { - report_err(this, e); + let msg = match e { + NonHaltingDiagnostic::PoppedTrackedPointerTag(item) => + format!("popped tracked tag for item {:?}", item), + }; + report_msg(this, msg, false); } }); } diff --git a/src/eval.rs b/src/eval.rs index 1e9332c9a32df..171f2627ad4a7 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -33,7 +33,6 @@ pub struct MiriConfig { /// Details of premature program termination. pub enum TerminationInfo { Exit(i64), - PoppedTrackedPointerTag(Item), Abort, } diff --git a/src/lib.rs b/src/lib.rs index ae92a777d88e4..60e5217721560 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -43,7 +43,7 @@ pub use crate::shims::tls::{EvalContextExt as TlsEvalContextExt, TlsData}; pub use crate::shims::EvalContextExt as ShimsEvalContextExt; pub use crate::diagnostics::{ - register_err, report_err, EvalContextExt as DiagnosticsEvalContextExt, + register_err, report_err, EvalContextExt as DiagnosticsEvalContextExt, NonHaltingDiagnostic, }; pub use crate::eval::{create_ecx, eval_main, MiriConfig, TerminationInfo}; pub use crate::helpers::EvalContextExt as HelpersEvalContextExt; diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 7bb7dd6cec11b..a98c8e26c652d 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -10,7 +10,6 @@ use std::rc::Rc; use rustc_hir::Mutability; use rustc::mir::RetagKind; use rustc::ty::{self, layout::Size}; -use rustc_mir::interpret::InterpError; use crate::*; @@ -267,12 +266,7 @@ impl<'tcx> Stack { fn check_protector(item: &Item, tag: Option, global: &GlobalState) -> InterpResult<'tcx> { if let Tag::Tagged(id) = item.tag { if Some(id) == global.tracked_pointer_tag { - register_err( - InterpError::MachineStop(Box::new(TerminationInfo::PoppedTrackedPointerTag( - item.clone(), - ))) - .into(), - ); + register_err(NonHaltingDiagnostic::PoppedTrackedPointerTag(item.clone())); } } if let Some(call) = item.protector { From c69ebaaed229679e54b70e82824ce82c31efa7fc Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Wed, 8 Jan 2020 13:20:39 +0100 Subject: [PATCH 1466/3747] Use names that actually represent what's going on --- src/diagnostics.rs | 12 ++++++------ src/eval.rs | 2 +- src/lib.rs | 2 +- src/stacked_borrows.rs | 2 +- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/diagnostics.rs b/src/diagnostics.rs index cf27a9c3762fe..a4f40d51a3a8a 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -77,19 +77,19 @@ pub fn report_msg<'tcx, 'mir>( } thread_local! { - static ECX: RefCell> = RefCell::new(Vec::new()); + static DIAGNOSTICS: RefCell> = RefCell::new(Vec::new()); } -pub fn register_err(e: NonHaltingDiagnostic) { - ECX.with(|ecx| ecx.borrow_mut().push(e)); +pub fn register_diagnostic(e: NonHaltingDiagnostic) { + DIAGNOSTICS.with(|diagnostics| diagnostics.borrow_mut().push(e)); } impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { - fn process_errors(&self) { + fn process_diagnostics(&self) { let this = self.eval_context_ref(); - ECX.with(|ecx| { - for e in ecx.borrow_mut().drain(..) { + DIAGNOSTICS.with(|diagnostics| { + for e in diagnostics.borrow_mut().drain(..) { let msg = match e { NonHaltingDiagnostic::PoppedTrackedPointerTag(item) => format!("popped tracked tag for item {:?}", item), diff --git a/src/eval.rs b/src/eval.rs index 171f2627ad4a7..e9e74db9b7549 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -183,7 +183,7 @@ pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) -> // Perform the main execution. let res: InterpResult<'_, i64> = (|| { while ecx.step()? { - ecx.process_errors(); + ecx.process_diagnostics(); } // Read the return code pointer *before* we run TLS destructors, to assert // that it was written to by the time that `start` lang item returned. diff --git a/src/lib.rs b/src/lib.rs index 60e5217721560..4d2411a6697d0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -43,7 +43,7 @@ pub use crate::shims::tls::{EvalContextExt as TlsEvalContextExt, TlsData}; pub use crate::shims::EvalContextExt as ShimsEvalContextExt; pub use crate::diagnostics::{ - register_err, report_err, EvalContextExt as DiagnosticsEvalContextExt, NonHaltingDiagnostic, + register_diagnostic, report_err, EvalContextExt as DiagnosticsEvalContextExt, NonHaltingDiagnostic, }; pub use crate::eval::{create_ecx, eval_main, MiriConfig, TerminationInfo}; pub use crate::helpers::EvalContextExt as HelpersEvalContextExt; diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index a98c8e26c652d..60304503145fd 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -266,7 +266,7 @@ impl<'tcx> Stack { fn check_protector(item: &Item, tag: Option, global: &GlobalState) -> InterpResult<'tcx> { if let Tag::Tagged(id) = item.tag { if Some(id) == global.tracked_pointer_tag { - register_err(NonHaltingDiagnostic::PoppedTrackedPointerTag(item.clone())); + register_diagnostic(NonHaltingDiagnostic::PoppedTrackedPointerTag(item.clone())); } } if let Some(call) = item.protector { From b1676a3e894efc0728bdb3d7ef598231eaca9a41 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 9 Jan 2020 11:20:13 +0100 Subject: [PATCH 1467/3747] test that unwrap gets us the right panic location --- rust-version | 2 +- tests/run-pass/panic/std-panic-locations.rs | 38 +++++++++++++++++++++ 2 files changed, 39 insertions(+), 1 deletion(-) create mode 100644 tests/run-pass/panic/std-panic-locations.rs diff --git a/rust-version b/rust-version index d39ff0adb2683..d1b498871e87b 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -ebbb2bf37aedaaa64dfaa52ba337ca6efb6b9093 +adc65725004c8aac16392fe4052c3e347181157d diff --git a/tests/run-pass/panic/std-panic-locations.rs b/tests/run-pass/panic/std-panic-locations.rs new file mode 100644 index 0000000000000..baa1bc900f732 --- /dev/null +++ b/tests/run-pass/panic/std-panic-locations.rs @@ -0,0 +1,38 @@ +#![feature(option_expect_none, option_unwrap_none)] + +//! Test that panic locations for `#[track_caller]` functions in std have the correct +//! location reported. + +fn main() { + // inspect the `PanicInfo` we receive to ensure the right file is the source + std::panic::set_hook(Box::new(|info| { + let actual = info.location().unwrap(); + if actual.file() != file!() { + eprintln!("expected a location in the test file, found {:?}", actual); + panic!(); + } + })); + + fn assert_panicked(f: impl FnOnce() + std::panic::UnwindSafe) { + std::panic::catch_unwind(f).unwrap_err(); + } + + let nope: Option<()> = None; + assert_panicked(|| nope.unwrap()); + assert_panicked(|| nope.expect("")); + + let yep: Option<()> = Some(()); + assert_panicked(|| yep.unwrap_none()); + assert_panicked(|| yep.expect_none("")); + + let oops: Result<(), ()> = Err(()); + assert_panicked(|| oops.unwrap()); + assert_panicked(|| oops.expect("")); + + let fine: Result<(), ()> = Ok(()); + assert_panicked(|| fine.unwrap_err()); + assert_panicked(|| fine.expect_err("")); + + // Cleanup: reset to default hook. + drop(std::panic::take_hook()); +} From e9b4323048e8866871134bda9b27c8c6d4f0d844 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 9 Jan 2020 11:24:41 +0100 Subject: [PATCH 1468/3747] also make sure the hook actually gets called --- tests/run-pass/panic/std-panic-locations.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/tests/run-pass/panic/std-panic-locations.rs b/tests/run-pass/panic/std-panic-locations.rs index baa1bc900f732..ac2e8d5305dfe 100644 --- a/tests/run-pass/panic/std-panic-locations.rs +++ b/tests/run-pass/panic/std-panic-locations.rs @@ -1,11 +1,15 @@ #![feature(option_expect_none, option_unwrap_none)] - //! Test that panic locations for `#[track_caller]` functions in std have the correct //! location reported. +use std::sync::atomic::{AtomicUsize, Ordering}; + +static HOOK_COUNT: AtomicUsize = AtomicUsize::new(0); + fn main() { // inspect the `PanicInfo` we receive to ensure the right file is the source std::panic::set_hook(Box::new(|info| { + HOOK_COUNT.fetch_add(1, Ordering::Relaxed); let actual = info.location().unwrap(); if actual.file() != file!() { eprintln!("expected a location in the test file, found {:?}", actual); @@ -35,4 +39,6 @@ fn main() { // Cleanup: reset to default hook. drop(std::panic::take_hook()); + + assert_eq!(HOOK_COUNT.load(Ordering::Relaxed), 8); } From 833816dd359edd79a103a32039f8aa24f8e051d9 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 9 Jan 2020 11:41:08 +0100 Subject: [PATCH 1469/3747] Unwind panicking does not currently work on Windows --- tests/run-pass/panic/std-panic-locations.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/run-pass/panic/std-panic-locations.rs b/tests/run-pass/panic/std-panic-locations.rs index ac2e8d5305dfe..d5f38fc2672e7 100644 --- a/tests/run-pass/panic/std-panic-locations.rs +++ b/tests/run-pass/panic/std-panic-locations.rs @@ -1,3 +1,4 @@ +// ignore-windows: Unwind panicking does not currently work on Windows #![feature(option_expect_none, option_unwrap_none)] //! Test that panic locations for `#[track_caller]` functions in std have the correct //! location reported. From bfc7a7effd8836765fc8bcb28084b90b29d8906c Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Thu, 9 Jan 2020 12:38:58 +0100 Subject: [PATCH 1470/3747] Remove trailing newline --- src/stacked_borrows.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 60304503145fd..1b7a118e637d6 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -626,4 +626,3 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(()) } } - From dbffbe52148ec0ef6cf5522b4171de40c93d4d65 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Thu, 9 Jan 2020 12:42:56 +0100 Subject: [PATCH 1471/3747] Document all the things --- src/diagnostics.rs | 9 ++++++++- src/eval.rs | 2 +- src/lib.rs | 2 +- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/diagnostics.rs b/src/diagnostics.rs index a4f40d51a3a8a..e68dfad1b9fae 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -3,11 +3,13 @@ use std::cell::RefCell; use crate::*; +/// Miri specific diagnostics pub enum NonHaltingDiagnostic { PoppedTrackedPointerTag(Item), } -pub fn report_err<'tcx, 'mir>( +/// Emit a custom diagnostic without going through the miri-engine machinery +pub fn report_diagnostic<'tcx, 'mir>( ecx: &InterpCx<'mir, 'tcx, Evaluator<'tcx>>, mut e: InterpErrorInfo<'tcx>, ) -> Option { @@ -31,6 +33,8 @@ pub fn report_err<'tcx, 'mir>( report_msg(ecx, msg, true) } +/// Report an error or note (depending on the `error` argument) at the current frame's current statement. +/// Also emits a full stacktrace of the interpreter stack. pub fn report_msg<'tcx, 'mir>( ecx: &InterpCx<'mir, 'tcx, Evaluator<'tcx>>, msg: String, @@ -80,12 +84,15 @@ thread_local! { static DIAGNOSTICS: RefCell> = RefCell::new(Vec::new()); } +/// Schedule a diagnostic for emitting. This function works even if you have no `InterpCx` available. +/// The diagnostic will be emitted after the current interpreter step is finished. pub fn register_diagnostic(e: NonHaltingDiagnostic) { DIAGNOSTICS.with(|diagnostics| diagnostics.borrow_mut().push(e)); } impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { + /// Emit all diagnostics that were registed with `register_diagnostics` fn process_diagnostics(&self) { let this = self.eval_context_ref(); DIAGNOSTICS.with(|diagnostics| { diff --git a/src/eval.rs b/src/eval.rs index e9e74db9b7549..7a3945220f772 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -206,6 +206,6 @@ pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) -> } Some(return_code) } - Err(e) => report_err(&ecx, e), + Err(e) => report_diagnostic(&ecx, e), } } diff --git a/src/lib.rs b/src/lib.rs index 4d2411a6697d0..880a14b98c80e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -43,7 +43,7 @@ pub use crate::shims::tls::{EvalContextExt as TlsEvalContextExt, TlsData}; pub use crate::shims::EvalContextExt as ShimsEvalContextExt; pub use crate::diagnostics::{ - register_diagnostic, report_err, EvalContextExt as DiagnosticsEvalContextExt, NonHaltingDiagnostic, + register_diagnostic, report_diagnostic, EvalContextExt as DiagnosticsEvalContextExt, NonHaltingDiagnostic, }; pub use crate::eval::{create_ecx, eval_main, MiriConfig, TerminationInfo}; pub use crate::helpers::EvalContextExt as HelpersEvalContextExt; From 0b5a30515e6977e4a9deaefa1c0ff243afbd6ef6 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Fri, 10 Jan 2020 12:01:05 -0500 Subject: [PATCH 1472/3747] small corrections --- src/shims/fs.rs | 2 +- tests/run-pass/fs.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/shims/fs.rs b/src/shims/fs.rs index 3927f0e649198..57a88f2ccaaec 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -337,7 +337,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); if this.tcx.sess.target.target.target_os.to_lowercase() != "macos" { - throw_unsup_format!("The `stat` shim is only available for `macos` targets.") + throw_unsup_format!("The `stat` and `lstat` shims are only available for `macos` targets.") } let path_scalar = this.read_scalar(path_op)?.not_undef()?; diff --git a/tests/run-pass/fs.rs b/tests/run-pass/fs.rs index 90b5dcfb5fa61..81c56e4aafc7e 100644 --- a/tests/run-pass/fs.rs +++ b/tests/run-pass/fs.rs @@ -22,8 +22,8 @@ fn main() { let symlink_path = tmp.join("miri_test_fs_symlink.txt"); let bytes = b"Hello, World!\n"; // Clean the paths for robustness. - remove_file(&path).unwrap_or(()); - remove_file(&symlink_path).unwrap_or(()); + remove_file(&path).ok(); + remove_file(&symlink_path).ok(); // Test creating, writing and closing a file (closing is tested when `file` is dropped). let mut file = File::create(&path).unwrap(); From 5e71f2debc4df0bd25d29329cd21a7c55c5dc3ba Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Fri, 10 Jan 2020 12:18:24 -0500 Subject: [PATCH 1473/3747] fix windows symlink creation --- src/shims/fs.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shims/fs.rs b/src/shims/fs.rs index 57a88f2ccaaec..b67504261672d 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -292,7 +292,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if src.is_dir() { fs::symlink_dir(src, dst) } else { - fs::symlink(src, dst) + fs::symlink_file(src, dst) } } From 4fa2f4e10fdc05cd899f8267c4073ed8b4195845 Mon Sep 17 00:00:00 2001 From: jethrogb Date: Mon, 13 Jan 2020 20:06:58 -0800 Subject: [PATCH 1474/3747] Update .gitattributes See https://github.com/rust-lang/rust/pull/57858 --- .gitattributes | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.gitattributes b/.gitattributes index 6313b56c57848..2742e4d1d5b9b 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1 +1,6 @@ * text=auto eol=lf + +# Older git versions try to fix line endings on images, this prevents it. +*.png binary +*.jpg binary +*.ico binary From 23c74449a2793da00a41d1abf35cfe1c99f660a4 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 15 Jan 2020 19:27:21 +0100 Subject: [PATCH 1475/3747] rustup --- rust-version | 2 +- src/helpers.rs | 4 ++-- src/shims/intrinsics.rs | 4 ++-- src/shims/panic.rs | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/rust-version b/rust-version index d1b498871e87b..09255212910c4 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -adc65725004c8aac16392fe4052c3e347181157d +31dd4f4acbcbdb02b0745d2136399ed664a28050 diff --git a/src/helpers.rs b/src/helpers.rs index ff9a16a024569..fba933d278d2f 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -76,7 +76,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// Get the `Place` for a local fn local_place(&mut self, local: mir::Local) -> InterpResult<'tcx, PlaceTy<'tcx, Tag>> { let this = self.eval_context_mut(); - let place = mir::Place { base: mir::PlaceBase::Local(local), projection: List::empty() }; + let place = mir::Place { local: local, projection: List::empty() }; this.eval_place(&place) } @@ -349,7 +349,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx for &imm in imms { this.write_immediate_to_mplace( *imm, - place.offset(offset, None, imm.layout, &*this.tcx)?, + place.offset(offset, MemPlaceMeta::None, imm.layout, &*this.tcx)?, )?; offset += imm.layout.size; } diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index a7aec53c37deb..151edfda4318a 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -409,7 +409,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx _ => { // Do it in memory let mplace = this.force_allocation(dest)?; - mplace.meta.unwrap_none(); // must be sized + assert!(!mplace.layout.is_unsized()); this.memory.write_bytes( mplace.ptr, iter::repeat(0u8).take(dest.layout.size.bytes() as usize), @@ -574,7 +574,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx _ => { // Do it in memory let mplace = this.force_allocation(dest)?; - mplace.meta.unwrap_none(); + assert!(!mplace.layout.is_unsized()); let ptr = mplace.ptr.assert_ptr(); // We know the return place is in-bounds this.memory.get_raw_mut(ptr.alloc_id)?.mark_definedness( diff --git a/src/shims/panic.rs b/src/shims/panic.rs index 950a23aa59cac..d676f04646574 100644 --- a/src/shims/panic.rs +++ b/src/shims/panic.rs @@ -132,7 +132,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let payload = this.machine.panic_payload.take().unwrap(); let payload = this.ref_to_mplace(payload)?; let payload_data_place = payload.ptr; - let payload_vtable_place = payload.meta.expect("Expected fat pointer"); + let payload_vtable_place = payload.meta.unwrap_meta(); this.write_scalar(payload_data_place, unwind_data.data_place.into())?; this.write_scalar(payload_vtable_place, unwind_data.vtable_place.into())?; From 88f01027534e6dceb2b977158bd97bcad5c89a01 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 15 Jan 2020 19:35:41 +0100 Subject: [PATCH 1476/3747] rustup more --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 09255212910c4..5927df6c9519a 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -31dd4f4acbcbdb02b0745d2136399ed664a28050 +6d0bb91bcba33a70fae4b0c663fb4403ed78f071 From 0acc30956166b81c75fd2c8db250eabce6babf7d Mon Sep 17 00:00:00 2001 From: Yoshua Wuyts Date: Sat, 18 Jan 2020 16:21:30 +0100 Subject: [PATCH 1477/3747] Document miri can only be installed on nightly This updates the installation instructions to point out that miri is only available on nightly, and encodes this assumption into the installation instructions. --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index bbf26ff6f71e6..cf18e6a0670bc 100644 --- a/README.md +++ b/README.md @@ -51,10 +51,10 @@ program, and cannot run all programs: ## Using Miri -Install Miri via `rustup`: +Install Miri on Rust nightly via `rustup`: ```sh -rustup component add miri +rustup +nightly component add miri ``` If `rustup` says the `miri` component is unavailable, that's because not all From b2303a7da170f8b9a6efa0b2c9149c103cde6990 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 19 Jan 2020 10:03:18 -0600 Subject: [PATCH 1478/3747] slice_patterns is stable now --- rust-version | 2 +- tests/run-pass/issue-15080.rs | 2 -- tests/run-pass/issue-17877.rs | 2 -- tests/run-pass/subslice_array.rs | 2 -- tests/run-pass/vec-matching-fold.rs | 2 -- 5 files changed, 1 insertion(+), 9 deletions(-) diff --git a/rust-version b/rust-version index 5927df6c9519a..d6464fa872e32 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -6d0bb91bcba33a70fae4b0c663fb4403ed78f071 +6250d56355d72264ece721e8d0dc95b16a6824b1 diff --git a/tests/run-pass/issue-15080.rs b/tests/run-pass/issue-15080.rs index 7f19759b910a6..2008e6e157db8 100644 --- a/tests/run-pass/issue-15080.rs +++ b/tests/run-pass/issue-15080.rs @@ -1,5 +1,3 @@ -#![feature(slice_patterns)] - fn main() { let mut x: &[_] = &[1, 2, 3, 4]; diff --git a/tests/run-pass/issue-17877.rs b/tests/run-pass/issue-17877.rs index d2806e5ed350b..fa24ab9f4aae8 100644 --- a/tests/run-pass/issue-17877.rs +++ b/tests/run-pass/issue-17877.rs @@ -1,5 +1,3 @@ -#![feature(slice_patterns)] - fn main() { assert_eq!(match [0u8; 16*1024] { _ => 42_usize, diff --git a/tests/run-pass/subslice_array.rs b/tests/run-pass/subslice_array.rs index df3631c647fb0..9b6b12d748adb 100644 --- a/tests/run-pass/subslice_array.rs +++ b/tests/run-pass/subslice_array.rs @@ -1,5 +1,3 @@ -#![feature(slice_patterns)] - fn bar(a: &'static str, b: &'static str) -> [&'static str; 4] { [a, b, b, a] } diff --git a/tests/run-pass/vec-matching-fold.rs b/tests/run-pass/vec-matching-fold.rs index 54fbb702924f3..8fd36253b57f3 100644 --- a/tests/run-pass/vec-matching-fold.rs +++ b/tests/run-pass/vec-matching-fold.rs @@ -1,5 +1,3 @@ -#![feature(slice_patterns)] - use std::fmt::Debug; fn foldl(values: &[T], From 625fa742bca46f992c347c438658d6b747e03c51 Mon Sep 17 00:00:00 2001 From: David Cook Date: Fri, 24 Jan 2020 19:02:58 -0600 Subject: [PATCH 1479/3747] Shim intrinsics::atomic_singlethreadfence, etc. --- src/shims/intrinsics.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 151edfda4318a..04e724ff1d347 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -113,6 +113,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "atomic_fence_rel" | "atomic_fence_acqrel" | "atomic_fence" + | "atomic_singlethreadfence_acq" + | "atomic_singlethreadfence_rel" + | "atomic_singlethreadfence_acqrel" + | "atomic_singlethreadfence" => { // we are inherently singlethreaded and singlecored, this is a nop } From 9265e0cd5e4e9677ef5bdcea7a781ae7d064b4e2 Mon Sep 17 00:00:00 2001 From: David Cook Date: Sat, 25 Jan 2020 13:48:26 -0600 Subject: [PATCH 1480/3747] Add compiler fences to test --- tests/run-pass/atomic.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tests/run-pass/atomic.rs b/tests/run-pass/atomic.rs index a9dd29bd62bf4..b03a8c8901e18 100644 --- a/tests/run-pass/atomic.rs +++ b/tests/run-pass/atomic.rs @@ -1,4 +1,4 @@ -use std::sync::atomic::{fence, AtomicBool, AtomicIsize, AtomicU64, Ordering::*}; +use std::sync::atomic::{compiler_fence, fence, AtomicBool, AtomicIsize, AtomicU64, Ordering::*}; fn main() { atomic_bool(); @@ -70,4 +70,8 @@ fn atomic_fences() { fence(Release); fence(Acquire); fence(AcqRel); + compiler_fence(SeqCst); + compiler_fence(Release); + compiler_fence(Acquire); + compiler_fence(AcqRel); } From d94b88ef9837569d0efeb4725d03475e2b816e03 Mon Sep 17 00:00:00 2001 From: David Cook Date: Sat, 25 Jan 2020 22:21:33 -0600 Subject: [PATCH 1481/3747] Add support for AT_EMPTY_PATH to statx shim --- src/shims/fs.rs | 41 +++++++++++++++++++++++++++++++++++++---- tests/run-pass/fs.rs | 2 ++ 2 files changed, 39 insertions(+), 4 deletions(-) diff --git a/src/shims/fs.rs b/src/shims/fs.rs index 8a7cf9d31c0b6..0875a3314c80d 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -345,7 +345,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let buf = this.deref_operand(buf_op)?; - let metadata = match FileMetadata::new(this, path, follow_symlink)? { + let metadata = match FileMetadata::from_path(this, path, follow_symlink)? { Some(metadata) => metadata, None => return Ok(-1), }; @@ -454,6 +454,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.read_scalar(flags_op)?.to_machine_isize(&*this.tcx)?.try_into().map_err(|e| { err_unsup_format!("Failed to convert pointer sized operand to integer: {}", e) })?; + let empty_path_flag = flags & this.eval_libc("AT_EMPTY_PATH")?.to_i32()? != 0; // `dirfd` should be a `c_int` but the `syscall` function provides an `isize`. let dirfd: i32 = this.read_scalar(dirfd_op)?.to_machine_isize(&*this.tcx)?.try_into().map_err(|e| { @@ -463,7 +464,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // to `dirfd` when the latter is `AT_FDCWD`. The behavior of `statx` with a relative path // and a directory file descriptor other than `AT_FDCWD` is specified but it cannot be // tested from `libstd`. If you found this error, please open an issue reporting it. - if !(path.is_absolute() || dirfd == this.eval_libc_i32("AT_FDCWD")?) { + if !( + path.is_absolute() || + dirfd == this.eval_libc_i32("AT_FDCWD")? || + (path.as_os_str().is_empty() && empty_path_flag) + ) { throw_unsup_format!( "Using statx with a relative path and a file descriptor different from `AT_FDCWD` is not supported" ) @@ -480,7 +485,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // symbolic links. let follow_symlink = flags & this.eval_libc("AT_SYMLINK_NOFOLLOW")?.to_i32()? == 0; - let metadata = match FileMetadata::new(this, path, follow_symlink)? { + // If the path is empty, and the AT_EMPTY_PATH flag is set, we query the open file + // represented by dirfd, whether it's a directory or otherwise. + let metadata = if path.as_os_str().is_empty() && empty_path_flag { + FileMetadata::from_fd(this, dirfd)? + } else { + FileMetadata::from_path(this, path, follow_symlink)? + }; + let metadata = match metadata { Some(metadata) => metadata, None => return Ok(-1), }; @@ -589,7 +601,7 @@ struct FileMetadata { } impl FileMetadata { - fn new<'tcx, 'mir>( + fn from_path<'tcx, 'mir>( ecx: &mut MiriEvalContext<'mir, 'tcx>, path: PathBuf, follow_symlink: bool @@ -600,6 +612,27 @@ impl FileMetadata { std::fs::symlink_metadata(path) }; + FileMetadata::from_meta(ecx, metadata) + } + + fn from_fd<'tcx, 'mir>( + ecx: &mut MiriEvalContext<'mir, 'tcx>, + fd: i32, + ) -> InterpResult<'tcx, Option> { + let option = ecx.machine.file_handler.handles.get(&fd); + let handle = match option { + Some(handle) => handle, + None => return ecx.handle_not_found().map(|_: i32| None), + }; + let metadata = handle.file.metadata(); + + FileMetadata::from_meta(ecx, metadata) + } + + fn from_meta<'tcx, 'mir>( + ecx: &mut MiriEvalContext<'mir, 'tcx>, + metadata: Result, + ) -> InterpResult<'tcx, Option> { let metadata = match metadata { Ok(metadata) => metadata, Err(e) => { diff --git a/tests/run-pass/fs.rs b/tests/run-pass/fs.rs index 81c56e4aafc7e..cc8f6e01f3231 100644 --- a/tests/run-pass/fs.rs +++ b/tests/run-pass/fs.rs @@ -29,8 +29,10 @@ fn main() { let mut file = File::create(&path).unwrap(); // Writing 0 bytes should not change the file contents. file.write(&mut []).unwrap(); + assert_eq!(file.metadata().unwrap().len(), 0); file.write(bytes).unwrap(); + assert_eq!(file.metadata().unwrap().len(), bytes.len() as u64); // Test opening, reading and closing a file. let mut file = File::open(&path).unwrap(); let mut contents = Vec::new(); From c5797130d7a1766b412cc30c8346ed646ffcc2d3 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 26 Jan 2020 11:06:13 -0600 Subject: [PATCH 1482/3747] bump rustc --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index d6464fa872e32..e7e27291d5538 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -6250d56355d72264ece721e8d0dc95b16a6824b1 +698fcd38fa9548e64a2092ff48c9d15ceb57d40c From 90f3aae2dead72d502ec4e25a659efb159186f19 Mon Sep 17 00:00:00 2001 From: David Cook Date: Sun, 26 Jan 2020 11:58:08 -0600 Subject: [PATCH 1483/3747] Add fstat shim for OSX --- src/shims/foreign_items.rs | 5 ++ src/shims/fs.rs | 140 ++++++++++++++++++++++--------------- 2 files changed, 89 insertions(+), 56 deletions(-) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index deeb37da44a3f..381b43c39ec2f 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -509,6 +509,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; } + "fstat$INODE64" => { + let result = this.fstat(args[0], args[1])?; + this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + } + "clock_gettime" => { let result = this.clock_gettime(args[0], args[1])?; this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; diff --git a/src/shims/fs.rs b/src/shims/fs.rs index 0875a3314c80d..d054dd47729b1 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -328,6 +328,28 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.stat_or_lstat(false, path_op, buf_op) } + fn fstat( + &mut self, + fd_op: OpTy<'tcx, Tag>, + buf_op: OpTy<'tcx, Tag>, + ) -> InterpResult<'tcx, i32> { + let this = self.eval_context_mut(); + + this.check_no_isolation("fstat")?; + + if this.tcx.sess.target.target.target_os.to_lowercase() != "macos" { + throw_unsup_format!("The `fstat` shim is only available for `macos` targets.") + } + + let fd = this.read_scalar(fd_op)?.to_i32()?; + + let metadata = match FileMetadata::from_fd(this, fd)? { + Some(metadata) => metadata, + None => return Ok(-1), + }; + stat_write_buf(this, metadata, buf_op) + } + fn stat_or_lstat( &mut self, follow_symlink: bool, @@ -343,66 +365,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let path_scalar = this.read_scalar(path_op)?.not_undef()?; let path: PathBuf = this.read_os_str_from_c_str(path_scalar)?.into(); - let buf = this.deref_operand(buf_op)?; - let metadata = match FileMetadata::from_path(this, path, follow_symlink)? { Some(metadata) => metadata, None => return Ok(-1), }; - - let mode: u16 = metadata.mode.to_u16()?; - - let (access_sec, access_nsec) = metadata.accessed.unwrap_or((0, 0)); - let (created_sec, created_nsec) = metadata.created.unwrap_or((0, 0)); - let (modified_sec, modified_nsec) = metadata.modified.unwrap_or((0, 0)); - - let dev_t_layout = this.libc_ty_layout("dev_t")?; - let mode_t_layout = this.libc_ty_layout("mode_t")?; - let nlink_t_layout = this.libc_ty_layout("nlink_t")?; - let ino_t_layout = this.libc_ty_layout("ino_t")?; - let uid_t_layout = this.libc_ty_layout("uid_t")?; - let gid_t_layout = this.libc_ty_layout("gid_t")?; - let time_t_layout = this.libc_ty_layout("time_t")?; - let long_layout = this.libc_ty_layout("c_long")?; - let off_t_layout = this.libc_ty_layout("off_t")?; - let blkcnt_t_layout = this.libc_ty_layout("blkcnt_t")?; - let blksize_t_layout = this.libc_ty_layout("blksize_t")?; - let uint32_t_layout = this.libc_ty_layout("uint32_t")?; - - // We need to add 32 bits of padding after `st_rdev` if we are on a 64-bit platform. - let pad_layout = if this.tcx.sess.target.ptr_width == 64 { - uint32_t_layout - } else { - this.layout_of(this.tcx.mk_unit())? - }; - - let imms = [ - immty_from_uint_checked(0u128, dev_t_layout)?, // st_dev - immty_from_uint_checked(mode, mode_t_layout)?, // st_mode - immty_from_uint_checked(0u128, nlink_t_layout)?, // st_nlink - immty_from_uint_checked(0u128, ino_t_layout)?, // st_ino - immty_from_uint_checked(0u128, uid_t_layout)?, // st_uid - immty_from_uint_checked(0u128, gid_t_layout)?, // st_gid - immty_from_uint_checked(0u128, dev_t_layout)?, // st_rdev - immty_from_uint_checked(0u128, pad_layout)?, // padding for 64-bit targets - immty_from_uint_checked(access_sec, time_t_layout)?, // st_atime - immty_from_uint_checked(access_nsec, long_layout)?, // st_atime_nsec - immty_from_uint_checked(modified_sec, time_t_layout)?, // st_mtime - immty_from_uint_checked(modified_nsec, long_layout)?, // st_mtime_nsec - immty_from_uint_checked(0u128, time_t_layout)?, // st_ctime - immty_from_uint_checked(0u128, long_layout)?, // st_ctime_nsec - immty_from_uint_checked(created_sec, time_t_layout)?, // st_birthtime - immty_from_uint_checked(created_nsec, long_layout)?, // st_birthtime_nsec - immty_from_uint_checked(metadata.size, off_t_layout)?, // st_size - immty_from_uint_checked(0u128, blkcnt_t_layout)?, // st_blocks - immty_from_uint_checked(0u128, blksize_t_layout)?, // st_blksize - immty_from_uint_checked(0u128, uint32_t_layout)?, // st_flags - immty_from_uint_checked(0u128, uint32_t_layout)?, // st_gen - ]; - - this.write_packed_immediates(&buf, &imms)?; - - Ok(0) + stat_write_buf(this, metadata, buf_op) } fn statx( @@ -663,3 +630,64 @@ impl FileMetadata { Ok(Some(FileMetadata { mode, size, created, accessed, modified })) } } + +fn stat_write_buf<'tcx, 'mir>( + ecx: &mut MiriEvalContext<'mir, 'tcx>, + metadata: FileMetadata, + buf_op: OpTy<'tcx, Tag>, +) -> InterpResult<'tcx, i32> { + let mode: u16 = metadata.mode.to_u16()?; + + let (access_sec, access_nsec) = metadata.accessed.unwrap_or((0, 0)); + let (created_sec, created_nsec) = metadata.created.unwrap_or((0, 0)); + let (modified_sec, modified_nsec) = metadata.modified.unwrap_or((0, 0)); + + let dev_t_layout = ecx.libc_ty_layout("dev_t")?; + let mode_t_layout = ecx.libc_ty_layout("mode_t")?; + let nlink_t_layout = ecx.libc_ty_layout("nlink_t")?; + let ino_t_layout = ecx.libc_ty_layout("ino_t")?; + let uid_t_layout = ecx.libc_ty_layout("uid_t")?; + let gid_t_layout = ecx.libc_ty_layout("gid_t")?; + let time_t_layout = ecx.libc_ty_layout("time_t")?; + let long_layout = ecx.libc_ty_layout("c_long")?; + let off_t_layout = ecx.libc_ty_layout("off_t")?; + let blkcnt_t_layout = ecx.libc_ty_layout("blkcnt_t")?; + let blksize_t_layout = ecx.libc_ty_layout("blksize_t")?; + let uint32_t_layout = ecx.libc_ty_layout("uint32_t")?; + + // We need to add 32 bits of padding after `st_rdev` if we are on a 64-bit platform. + let pad_layout = if ecx.tcx.sess.target.ptr_width == 64 { + uint32_t_layout + } else { + ecx.layout_of(ecx.tcx.mk_unit())? + }; + + let imms = [ + immty_from_uint_checked(0u128, dev_t_layout)?, // st_dev + immty_from_uint_checked(mode, mode_t_layout)?, // st_mode + immty_from_uint_checked(0u128, nlink_t_layout)?, // st_nlink + immty_from_uint_checked(0u128, ino_t_layout)?, // st_ino + immty_from_uint_checked(0u128, uid_t_layout)?, // st_uid + immty_from_uint_checked(0u128, gid_t_layout)?, // st_gid + immty_from_uint_checked(0u128, dev_t_layout)?, // st_rdev + immty_from_uint_checked(0u128, pad_layout)?, // padding for 64-bit targets + immty_from_uint_checked(access_sec, time_t_layout)?, // st_atime + immty_from_uint_checked(access_nsec, long_layout)?, // st_atime_nsec + immty_from_uint_checked(modified_sec, time_t_layout)?, // st_mtime + immty_from_uint_checked(modified_nsec, long_layout)?, // st_mtime_nsec + immty_from_uint_checked(0u128, time_t_layout)?, // st_ctime + immty_from_uint_checked(0u128, long_layout)?, // st_ctime_nsec + immty_from_uint_checked(created_sec, time_t_layout)?, // st_birthtime + immty_from_uint_checked(created_nsec, long_layout)?, // st_birthtime_nsec + immty_from_uint_checked(metadata.size, off_t_layout)?, // st_size + immty_from_uint_checked(0u128, blkcnt_t_layout)?, // st_blocks + immty_from_uint_checked(0u128, blksize_t_layout)?, // st_blksize + immty_from_uint_checked(0u128, uint32_t_layout)?, // st_flags + immty_from_uint_checked(0u128, uint32_t_layout)?, // st_gen + ]; + + let buf = ecx.deref_operand(buf_op)?; + ecx.write_packed_immediates(&buf, &imms)?; + + Ok(0) +} From 03b5d95cffd587224fc16b4cafca25e0e52df337 Mon Sep 17 00:00:00 2001 From: David Cook Date: Sun, 26 Jan 2020 12:36:36 -0600 Subject: [PATCH 1484/3747] Add shim for lseek64 --- src/shims/foreign_items.rs | 5 +++++ src/shims/fs.rs | 34 +++++++++++++++++++++++++++++++++- tests/run-pass/fs.rs | 8 +++++++- 3 files changed, 45 insertions(+), 2 deletions(-) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index deeb37da44a3f..9d025b2b7b24d 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -489,6 +489,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; } + "lseek64" => { + let result = this.lseek64(args[0], args[1], args[2])?; + this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + } + "unlink" => { let result = this.unlink(args[0])?; this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; diff --git a/src/shims/fs.rs b/src/shims/fs.rs index 8a7cf9d31c0b6..4cfff9446b852 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -1,7 +1,7 @@ use std::collections::HashMap; use std::convert::{TryFrom, TryInto}; use std::fs::{remove_file, File, OpenOptions}; -use std::io::{Read, Write}; +use std::io::{Read, Seek, SeekFrom, Write}; use std::path::PathBuf; use std::time::SystemTime; @@ -264,6 +264,38 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } + fn lseek64( + &mut self, + fd_op: OpTy<'tcx, Tag>, + offset_op: OpTy<'tcx, Tag>, + whence_op: OpTy<'tcx, Tag>, + ) -> InterpResult<'tcx, i64> { + let this = self.eval_context_mut(); + + this.check_no_isolation("lseek64")?; + + let fd = this.read_scalar(fd_op)?.to_i32()?; + let offset = this.read_scalar(offset_op)?.to_i64()?; + let whence = this.read_scalar(whence_op)?.to_i32()?; + + let seek_from = if whence == this.eval_libc_i32("SEEK_SET")? { + SeekFrom::Start(offset as u64) + } else if whence == this.eval_libc_i32("SEEK_CUR")? { + SeekFrom::Current(offset) + } else if whence == this.eval_libc_i32("SEEK_END")? { + SeekFrom::End(offset) + } else { + throw_unsup_format!("Unsupported whence argument to lseek64: {}", whence) + }; + + if let Some(handle) = this.machine.file_handler.handles.get_mut(&fd) { + let result = handle.file.seek(seek_from).map(|offset| offset as i64); + this.try_unwrap_io_result(result) + } else { + this.handle_not_found() + } + } + fn unlink(&mut self, path_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); diff --git a/tests/run-pass/fs.rs b/tests/run-pass/fs.rs index 81c56e4aafc7e..4da67369aef84 100644 --- a/tests/run-pass/fs.rs +++ b/tests/run-pass/fs.rs @@ -2,7 +2,7 @@ // compile-flags: -Zmiri-disable-isolation use std::fs::{File, remove_file}; -use std::io::{Read, Write, ErrorKind, Result}; +use std::io::{Read, Write, ErrorKind, Result, Seek, SeekFrom}; use std::path::{PathBuf, Path}; fn test_metadata(bytes: &[u8], path: &Path) -> Result<()> { @@ -40,6 +40,12 @@ fn main() { file.read_to_end(&mut contents).unwrap(); assert_eq!(bytes, contents.as_slice()); + // Test that seeking to the beginning and reading until EOF gets the text again. + file.seek(SeekFrom::Start(0)).unwrap(); + let mut contents = Vec::new(); + file.read_to_end(&mut contents).unwrap(); + assert_eq!(bytes, contents.as_slice()); + // Test that metadata of an absolute path is correct. test_metadata(bytes, &path).unwrap(); // Test that metadata of a relative path is correct. From 01b5e8260e3a5e17ee4ce83a88fc07aeac774625 Mon Sep 17 00:00:00 2001 From: David Cook Date: Sun, 26 Jan 2020 15:10:01 -0600 Subject: [PATCH 1485/3747] Add no-op shim for posix_fadvise --- src/shims/foreign_items.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index deeb37da44a3f..7bd85a4e94d42 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -780,6 +780,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_null(dest)?; } + "posix_fadvise" => { + // fadvise is only informational, we can ignore it. + this.write_null(dest)?; + } + "mmap" => { // This is a horrible hack, but since the guard page mechanism calls mmap and expects a particular return value, we just give it that value. let addr = this.read_scalar(args[0])?.not_undef()?; From 0d0902a1e131f57995e705c362b46d59bbf63234 Mon Sep 17 00:00:00 2001 From: David Cook Date: Sun, 26 Jan 2020 18:07:31 -0600 Subject: [PATCH 1486/3747] Apply shim to lseek too (for macOS) --- src/shims/foreign_items.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 9d025b2b7b24d..a6c1a31b4feb3 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -489,7 +489,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; } - "lseek64" => { + | "lseek64" + | "lseek" + => { let result = this.lseek64(args[0], args[1], args[2])?; this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; } From 4e42e774834683570b1c0ca59ce5bb1a11119fb5 Mon Sep 17 00:00:00 2001 From: David Cook Date: Mon, 27 Jan 2020 06:28:45 -0600 Subject: [PATCH 1487/3747] Add test for posix_fadvise --- tests/run-pass/fs.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/tests/run-pass/fs.rs b/tests/run-pass/fs.rs index 81c56e4aafc7e..43f394bd32744 100644 --- a/tests/run-pass/fs.rs +++ b/tests/run-pass/fs.rs @@ -1,8 +1,13 @@ // ignore-windows: File handling is not implemented yet // compile-flags: -Zmiri-disable-isolation +#![feature(rustc_private)] + +extern crate libc; + use std::fs::{File, remove_file}; use std::io::{Read, Write, ErrorKind, Result}; +use std::os::unix::io::AsRawFd; use std::path::{PathBuf, Path}; fn test_metadata(bytes: &[u8], path: &Path) -> Result<()> { @@ -40,6 +45,16 @@ fn main() { file.read_to_end(&mut contents).unwrap(); assert_eq!(bytes, contents.as_slice()); + // Test calling posix_fadvise on the file. + unsafe { + libc::posix_fadvise( + file.as_raw_fd(), + 0, + bytes.len() as i64, + libc::POSIX_FADV_DONTNEED, + ); + } + // Test that metadata of an absolute path is correct. test_metadata(bytes, &path).unwrap(); // Test that metadata of a relative path is correct. From 9f6df672381bdb0077a91ed785c80fef78eb8def Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 28 Jan 2020 22:55:07 +0100 Subject: [PATCH 1488/3747] test track_caller with fn ptrs --- tests/run-pass/track-caller-attribute.rs | 30 ++++++++++++++++++++---- 1 file changed, 26 insertions(+), 4 deletions(-) diff --git a/tests/run-pass/track-caller-attribute.rs b/tests/run-pass/track-caller-attribute.rs index 68a0c95b44dba..f6797c24ebecf 100644 --- a/tests/run-pass/track-caller-attribute.rs +++ b/tests/run-pass/track-caller-attribute.rs @@ -19,15 +19,33 @@ macro_rules! caller_location_from_macro { () => (core::panic::Location::caller()); } +fn test_fn_ptr() { + fn pass_to_ptr_call(f: fn(T), x: T) { + f(x); + } + + #[track_caller] + fn tracked_unit(_: ()) { + let expected_line = line!() - 1; + let location = std::panic::Location::caller(); + assert_eq!(location.file(), file!()); + assert_eq!(location.line(), expected_line, "call shims report location as fn definition"); + } + + pass_to_ptr_call(tracked_unit, ()); +} + fn main() { let location = Location::caller(); + let expected_line = line!() - 1; assert_eq!(location.file(), file!()); - assert_eq!(location.line(), 23); + assert_eq!(location.line(), expected_line); assert_eq!(location.column(), 20); let tracked = tracked(); + let expected_line = line!() - 1; assert_eq!(tracked.file(), file!()); - assert_eq!(tracked.line(), 28); + assert_eq!(tracked.line(), expected_line); assert_eq!(tracked.column(), 19); let nested = nested_intrinsic(); @@ -43,12 +61,16 @@ fn main() { // `Location::caller()` in a macro should behave similarly to `file!` and `line!`, // i.e. point to where the macro was invoked, instead of the macro itself. let inmacro = caller_location_from_macro!(); + let expected_line = line!() - 1; assert_eq!(inmacro.file(), file!()); - assert_eq!(inmacro.line(), 45); + assert_eq!(inmacro.line(), expected_line); assert_eq!(inmacro.column(), 19); let intrinsic = core::intrinsics::caller_location(); + let expected_line = line!() - 1; assert_eq!(intrinsic.file(), file!()); - assert_eq!(intrinsic.line(), 50); + assert_eq!(intrinsic.line(), expected_line); assert_eq!(intrinsic.column(), 21); + + test_fn_ptr(); } From b2d404d19af4949c5159ec6353984413776b925b Mon Sep 17 00:00:00 2001 From: David Cook Date: Tue, 28 Jan 2020 18:59:49 -0600 Subject: [PATCH 1489/3747] Move posix_fadvise test to new libc test file --- tests/run-pass/fs.rs | 15 --------------- tests/run-pass/libc.rs | 35 +++++++++++++++++++++++++++++++++++ 2 files changed, 35 insertions(+), 15 deletions(-) create mode 100644 tests/run-pass/libc.rs diff --git a/tests/run-pass/fs.rs b/tests/run-pass/fs.rs index 43f394bd32744..81c56e4aafc7e 100644 --- a/tests/run-pass/fs.rs +++ b/tests/run-pass/fs.rs @@ -1,13 +1,8 @@ // ignore-windows: File handling is not implemented yet // compile-flags: -Zmiri-disable-isolation -#![feature(rustc_private)] - -extern crate libc; - use std::fs::{File, remove_file}; use std::io::{Read, Write, ErrorKind, Result}; -use std::os::unix::io::AsRawFd; use std::path::{PathBuf, Path}; fn test_metadata(bytes: &[u8], path: &Path) -> Result<()> { @@ -45,16 +40,6 @@ fn main() { file.read_to_end(&mut contents).unwrap(); assert_eq!(bytes, contents.as_slice()); - // Test calling posix_fadvise on the file. - unsafe { - libc::posix_fadvise( - file.as_raw_fd(), - 0, - bytes.len() as i64, - libc::POSIX_FADV_DONTNEED, - ); - } - // Test that metadata of an absolute path is correct. test_metadata(bytes, &path).unwrap(); // Test that metadata of a relative path is correct. diff --git a/tests/run-pass/libc.rs b/tests/run-pass/libc.rs new file mode 100644 index 0000000000000..8ba97e2e43563 --- /dev/null +++ b/tests/run-pass/libc.rs @@ -0,0 +1,35 @@ +// ignore-windows: No libc on Windows +// compile-flags: -Zmiri-disable-isolation + +#![feature(rustc_private)] + +extern crate libc; + +use std::env::temp_dir; +use std::fs::{File, remove_file}; +use std::io::Write; +use std::os::unix::io::AsRawFd; + +fn main() { + let path = temp_dir().join("miri_test_libc.txt"); + // Cleanup before test + remove_file(&path).ok(); + + // Set up an open file + let mut file = File::create(&path).unwrap(); + let bytes = b"Hello, World!\n"; + file.write(bytes).unwrap(); + + // Test calling posix_fadvise on a file. + let result = unsafe { + libc::posix_fadvise( + file.as_raw_fd(), + 0, + bytes.len() as i64, + libc::POSIX_FADV_DONTNEED, + ) + }; + drop(file); + remove_file(&path).unwrap(); + assert_eq!(result, 0); +} From 2a2dde1494cec11a885e899d737904f920bd183b Mon Sep 17 00:00:00 2001 From: David Cook Date: Tue, 28 Jan 2020 19:04:16 -0600 Subject: [PATCH 1490/3747] Try fixing test on i686-unknown-linux-gnu --- tests/run-pass/libc.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/run-pass/libc.rs b/tests/run-pass/libc.rs index 8ba97e2e43563..25f96b472b236 100644 --- a/tests/run-pass/libc.rs +++ b/tests/run-pass/libc.rs @@ -5,6 +5,7 @@ extern crate libc; +use std::convert::TryInto; use std::env::temp_dir; use std::fs::{File, remove_file}; use std::io::Write; @@ -25,7 +26,7 @@ fn main() { libc::posix_fadvise( file.as_raw_fd(), 0, - bytes.len() as i64, + bytes.len().try_into().unwrap(), libc::POSIX_FADV_DONTNEED, ) }; From d8da3968d67b7ccea4262fe1d2b296e7ed3434fa Mon Sep 17 00:00:00 2001 From: David Cook Date: Tue, 28 Jan 2020 19:43:55 -0600 Subject: [PATCH 1491/3747] Change function name, comments, and error message --- src/shims/fs.rs | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/src/shims/fs.rs b/src/shims/fs.rs index d054dd47729b1..c5017dc85bbd3 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -347,7 +347,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Some(metadata) => metadata, None => return Ok(-1), }; - stat_write_buf(this, metadata, buf_op) + stat_macos_write_buf(this, metadata, buf_op) } fn stat_or_lstat( @@ -369,7 +369,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Some(metadata) => metadata, None => return Ok(-1), }; - stat_write_buf(this, metadata, buf_op) + stat_macos_write_buf(this, metadata, buf_op) } fn statx( @@ -427,17 +427,23 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.read_scalar(dirfd_op)?.to_machine_isize(&*this.tcx)?.try_into().map_err(|e| { err_unsup_format!("Failed to convert pointer sized operand to integer: {}", e) })?; - // we only support interpreting `path` as an absolute directory or as a directory relative - // to `dirfd` when the latter is `AT_FDCWD`. The behavior of `statx` with a relative path - // and a directory file descriptor other than `AT_FDCWD` is specified but it cannot be - // tested from `libstd`. If you found this error, please open an issue reporting it. + // We only support: + // * interpreting `path` as an absolute directory, + // * interpreting `path` as a path relative to `dirfd` when the latter is `AT_FDCWD`, or + // * interpreting `dirfd` as any file descriptor when `path` is empty and AT_EMPTY_PATH is + // set. + // The behavior of `statx` with a relative path and a directory file descriptor other than + // `AT_FDCWD` is specified but it cannot be tested from `libstd`. If you found this error, + // please open an issue reporting it. if !( path.is_absolute() || dirfd == this.eval_libc_i32("AT_FDCWD")? || (path.as_os_str().is_empty() && empty_path_flag) ) { throw_unsup_format!( - "Using statx with a relative path and a file descriptor different from `AT_FDCWD` is not supported" + "Using statx is only supported with absolute paths, relative paths with the file \ + descriptor `AT_FDCWD`, and empty paths with the `AT_EMPTY_PATH` flag set and any \ + file descriptor" ) } @@ -631,7 +637,7 @@ impl FileMetadata { } } -fn stat_write_buf<'tcx, 'mir>( +fn stat_macos_write_buf<'tcx, 'mir>( ecx: &mut MiriEvalContext<'mir, 'tcx>, metadata: FileMetadata, buf_op: OpTy<'tcx, Tag>, From a39a5f8189f925bf6a3131af28801903a8143fd2 Mon Sep 17 00:00:00 2001 From: David Cook Date: Tue, 28 Jan 2020 19:57:56 -0600 Subject: [PATCH 1492/3747] Disable posix_fadvise test on macOS, not in libc --- tests/run-pass/libc.rs | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/tests/run-pass/libc.rs b/tests/run-pass/libc.rs index 25f96b472b236..eb23cd16b757c 100644 --- a/tests/run-pass/libc.rs +++ b/tests/run-pass/libc.rs @@ -5,13 +5,14 @@ extern crate libc; -use std::convert::TryInto; -use std::env::temp_dir; -use std::fs::{File, remove_file}; -use std::io::Write; -use std::os::unix::io::AsRawFd; +#[cfg(not(target_os = "macos"))] +fn test_posix_fadvise() { + use std::convert::TryInto; + use std::env::temp_dir; + use std::fs::{File, remove_file}; + use std::io::Write; + use std::os::unix::io::AsRawFd; -fn main() { let path = temp_dir().join("miri_test_libc.txt"); // Cleanup before test remove_file(&path).ok(); @@ -34,3 +35,8 @@ fn main() { remove_file(&path).unwrap(); assert_eq!(result, 0); } + +fn main() { + #[cfg(not(target_os = "macos"))] + test_posix_fadvise(); +} From a30914bcddeca1ae58e578a0aa1d49580c0cfcee Mon Sep 17 00:00:00 2001 From: David Cook Date: Tue, 28 Jan 2020 20:39:06 -0600 Subject: [PATCH 1493/3747] Conditional compilation fix --- tests/run-pass/libc.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/run-pass/libc.rs b/tests/run-pass/libc.rs index eb23cd16b757c..5b7b37db327be 100644 --- a/tests/run-pass/libc.rs +++ b/tests/run-pass/libc.rs @@ -3,6 +3,7 @@ #![feature(rustc_private)] +#[allow(unused)] // necessary on macos due to conditional compilation extern crate libc; #[cfg(not(target_os = "macos"))] From 3d8bf92a11f348d8dd2183873ca60e2e4859e5b9 Mon Sep 17 00:00:00 2001 From: Tim Diekmann Date: Sun, 26 Jan 2020 19:50:26 +0100 Subject: [PATCH 1494/3747] Rename `Alloc` to `AllocRef` Required to land https://github.com/rust-lang/rust/pull/68529. Please see that PR for details. The CI is expected to fail until the PR is landed. --- tests/compile-fail/deallocate-bad-alignment.rs | 2 +- tests/compile-fail/deallocate-bad-size.rs | 2 +- tests/compile-fail/deallocate-twice.rs | 2 +- tests/compile-fail/reallocate-bad-size.rs | 2 +- tests/compile-fail/reallocate-change-alloc.rs | 2 +- tests/compile-fail/reallocate-dangling.rs | 2 +- tests/run-pass/heap_allocator.rs | 6 +++--- 7 files changed, 9 insertions(+), 9 deletions(-) diff --git a/tests/compile-fail/deallocate-bad-alignment.rs b/tests/compile-fail/deallocate-bad-alignment.rs index d124136a96537..2ac35a450cf19 100644 --- a/tests/compile-fail/deallocate-bad-alignment.rs +++ b/tests/compile-fail/deallocate-bad-alignment.rs @@ -3,7 +3,7 @@ extern crate alloc; use alloc::alloc::Global; -use std::alloc::*; +use std::alloc::{AllocRef, Layout}; // error-pattern: incorrect alloc info: expected size 1 and align 2, got size 1 and align 1 diff --git a/tests/compile-fail/deallocate-bad-size.rs b/tests/compile-fail/deallocate-bad-size.rs index 7a95b0ac7e90a..c5b48f5ddf590 100644 --- a/tests/compile-fail/deallocate-bad-size.rs +++ b/tests/compile-fail/deallocate-bad-size.rs @@ -3,7 +3,7 @@ extern crate alloc; use alloc::alloc::Global; -use std::alloc::*; +use std::alloc::{AllocRef, Layout}; // error-pattern: incorrect alloc info: expected size 2 and align 1, got size 1 and align 1 diff --git a/tests/compile-fail/deallocate-twice.rs b/tests/compile-fail/deallocate-twice.rs index 03fab76d601b5..02c442f0ab85f 100644 --- a/tests/compile-fail/deallocate-twice.rs +++ b/tests/compile-fail/deallocate-twice.rs @@ -3,7 +3,7 @@ extern crate alloc; use alloc::alloc::Global; -use std::alloc::*; +use std::alloc::{AllocRef, Layout}; // error-pattern: tried to deallocate dangling pointer diff --git a/tests/compile-fail/reallocate-bad-size.rs b/tests/compile-fail/reallocate-bad-size.rs index 24d913205447d..905e8e0617212 100644 --- a/tests/compile-fail/reallocate-bad-size.rs +++ b/tests/compile-fail/reallocate-bad-size.rs @@ -3,7 +3,7 @@ extern crate alloc; use alloc::alloc::Global; -use std::alloc::*; +use std::alloc::{AllocRef, Layout}; // error-pattern: incorrect alloc info: expected size 2 and align 1, got size 1 and align 1 diff --git a/tests/compile-fail/reallocate-change-alloc.rs b/tests/compile-fail/reallocate-change-alloc.rs index 312edfd52b277..21468739b31c0 100644 --- a/tests/compile-fail/reallocate-change-alloc.rs +++ b/tests/compile-fail/reallocate-change-alloc.rs @@ -3,7 +3,7 @@ extern crate alloc; use alloc::alloc::Global; -use std::alloc::*; +use std::alloc::{AllocRef, Layout}; fn main() { unsafe { diff --git a/tests/compile-fail/reallocate-dangling.rs b/tests/compile-fail/reallocate-dangling.rs index 450f63cc40d35..ee73cfce8634b 100644 --- a/tests/compile-fail/reallocate-dangling.rs +++ b/tests/compile-fail/reallocate-dangling.rs @@ -3,7 +3,7 @@ extern crate alloc; use alloc::alloc::Global; -use std::alloc::*; +use std::alloc::{AllocRef, Layout}; // error-pattern: dangling pointer was dereferenced diff --git a/tests/run-pass/heap_allocator.rs b/tests/run-pass/heap_allocator.rs index 7bcb08058c36a..907fbf962df02 100644 --- a/tests/run-pass/heap_allocator.rs +++ b/tests/run-pass/heap_allocator.rs @@ -1,10 +1,10 @@ #![feature(allocator_api)] use std::ptr::NonNull; -use std::alloc::{Global, Alloc, Layout, System}; +use std::alloc::{Global, AllocRef, Layout, System}; use std::slice; -fn check_alloc(mut allocator: T) { unsafe { +fn check_alloc(mut allocator: T) { unsafe { for &align in &[4, 8, 16, 32] { let layout = Layout::from_size_align(20, align).unwrap(); @@ -40,7 +40,7 @@ fn check_alloc(mut allocator: T) { unsafe { } } } -fn check_align_requests(mut allocator: T) { +fn check_align_requests(mut allocator: T) { for &size in &[2, 8, 64] { // size less than and bigger than alignment for &align in &[4, 8, 16, 32] { // Be sure to cover less than and bigger than `MIN_ALIGN` for all architectures let iterations = 32; From 74e0482ec347d165c5629c7eeff84719cb40e524 Mon Sep 17 00:00:00 2001 From: Tim Diekmann Date: Wed, 29 Jan 2020 04:10:40 +0100 Subject: [PATCH 1495/3747] Bump rust version --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index e7e27291d5538..5ce2e4651361d 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -698fcd38fa9548e64a2092ff48c9d15ceb57d40c +3761dcd3467441f78939ccb3b341b03b6a7558d7 From 6e9abea2726462ec0901fa3d386eeee1a7771c6a Mon Sep 17 00:00:00 2001 From: David Cook Date: Tue, 28 Jan 2020 22:59:28 -0600 Subject: [PATCH 1496/3747] Update comment --- src/shims/fs.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/shims/fs.rs b/src/shims/fs.rs index c5017dc85bbd3..b5c0dead1f8f6 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -432,9 +432,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // * interpreting `path` as a path relative to `dirfd` when the latter is `AT_FDCWD`, or // * interpreting `dirfd` as any file descriptor when `path` is empty and AT_EMPTY_PATH is // set. - // The behavior of `statx` with a relative path and a directory file descriptor other than - // `AT_FDCWD` is specified but it cannot be tested from `libstd`. If you found this error, - // please open an issue reporting it. + // Other behaviors cannot be tested from `libstd` and thus are not implemented. If you + // found this error, please open an issue reporting it. if !( path.is_absolute() || dirfd == this.eval_libc_i32("AT_FDCWD")? || From 2f25e4cd17e0f97d4da9547c9b2201b5918c34b5 Mon Sep 17 00:00:00 2001 From: David Cook Date: Wed, 29 Jan 2020 19:04:18 -0600 Subject: [PATCH 1497/3747] Error with EINVAL on unsupported `whence` argument --- src/shims/fs.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/shims/fs.rs b/src/shims/fs.rs index 4cfff9446b852..388117daee6bb 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -285,7 +285,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } else if whence == this.eval_libc_i32("SEEK_END")? { SeekFrom::End(offset) } else { - throw_unsup_format!("Unsupported whence argument to lseek64: {}", whence) + let einval = this.eval_libc("EINVAL")?; + this.set_last_error(einval)?; + return Ok(-1); }; if let Some(handle) = this.machine.file_handler.handles.get_mut(&fd) { From acd156d722c6d285ad5332b7b7aeb57f3b25b09a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 30 Jan 2020 12:17:02 +0100 Subject: [PATCH 1498/3747] add test that relies on non-reborrowing-cast-to-raw --- tests/run-pass/stacked-borrows/stacked-borrows.rs | 7 +++---- tests/run-pass/stacked-borrows/stacked-borrows.stderr | 8 +------- 2 files changed, 4 insertions(+), 11 deletions(-) diff --git a/tests/run-pass/stacked-borrows/stacked-borrows.rs b/tests/run-pass/stacked-borrows/stacked-borrows.rs index fe6a9a54d4f34..208cb7e15e03d 100644 --- a/tests/run-pass/stacked-borrows/stacked-borrows.rs +++ b/tests/run-pass/stacked-borrows/stacked-borrows.rs @@ -129,16 +129,15 @@ fn two_raw() { unsafe { } } // Make sure that creating a *mut does not invalidate existing shared references. -fn shr_and_raw() { /* unsafe { +fn shr_and_raw() { unsafe { use std::mem; - // FIXME: This is currently disabled because "as *mut _" incurs a reborrow. let x = &mut 0; let y1: &i32 = mem::transmute(&*x); // launder lifetimes let y2 = x as *mut _; let _val = *y1; *y2 += 1; // TODO: Once this works, add compile-fail test that tries to read from y1 again. -} */ } +} } fn disjoint_mutable_subborrows() { struct Foo { @@ -165,5 +164,5 @@ fn disjoint_mutable_subborrows() { let b = unsafe{ borrow_field_b(ptr) }; b.push(4); a.push_str(" world"); - dbg!(a,b); + eprintln!("{:?} {:?}", a, b); } diff --git a/tests/run-pass/stacked-borrows/stacked-borrows.stderr b/tests/run-pass/stacked-borrows/stacked-borrows.stderr index 4493d45ae157a..8ee4e25dbef84 100644 --- a/tests/run-pass/stacked-borrows/stacked-borrows.stderr +++ b/tests/run-pass/stacked-borrows/stacked-borrows.stderr @@ -1,7 +1 @@ -[$DIR/stacked-borrows.rs:168] a = "hello world" -[$DIR/stacked-borrows.rs:168] b = [ - 0, - 1, - 2, - 4, -] +"hello world" [0, 1, 2, 4] From e0adfe4d459482240d0614990fcb0ea112d48cf4 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 30 Jan 2020 12:21:37 +0100 Subject: [PATCH 1499/3747] new compile-fail test involving non-reborrowing-cast-to-raw --- tests/compile-fail/stacked_borrows/illegal_read8.rs | 13 +++++++++++++ tests/run-pass/stacked-borrows/stacked-borrows.rs | 1 - 2 files changed, 13 insertions(+), 1 deletion(-) create mode 100644 tests/compile-fail/stacked_borrows/illegal_read8.rs diff --git a/tests/compile-fail/stacked_borrows/illegal_read8.rs b/tests/compile-fail/stacked_borrows/illegal_read8.rs new file mode 100644 index 0000000000000..72fca84ba19ba --- /dev/null +++ b/tests/compile-fail/stacked_borrows/illegal_read8.rs @@ -0,0 +1,13 @@ +// Make sure that creating a raw ptr next to a shared ref works +// but the shared ref still gets invalidated when the raw ptr is used for writing. + +fn main() { unsafe { + use std::mem; + let x = &mut 0; + let y1: &i32 = mem::transmute(&*x); // launder lifetimes + let y2 = x as *mut _; + let _val = *y2; + let _val = *y1; + *y2 += 1; + let _fail = *y1; //~ ERROR borrow stack +} } diff --git a/tests/run-pass/stacked-borrows/stacked-borrows.rs b/tests/run-pass/stacked-borrows/stacked-borrows.rs index 208cb7e15e03d..824437f4f1bf9 100644 --- a/tests/run-pass/stacked-borrows/stacked-borrows.rs +++ b/tests/run-pass/stacked-borrows/stacked-borrows.rs @@ -136,7 +136,6 @@ fn shr_and_raw() { unsafe { let y2 = x as *mut _; let _val = *y1; *y2 += 1; - // TODO: Once this works, add compile-fail test that tries to read from y1 again. } } fn disjoint_mutable_subborrows() { From 3cf413e4c29f4100efbf6841e2fb3876565f5638 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 30 Jan 2020 12:22:54 +0100 Subject: [PATCH 1500/3747] remove inadequate comment --- tests/run-pass/stacked-borrows/stacked-borrows.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/tests/run-pass/stacked-borrows/stacked-borrows.rs b/tests/run-pass/stacked-borrows/stacked-borrows.rs index 824437f4f1bf9..a70285d5152a7 100644 --- a/tests/run-pass/stacked-borrows/stacked-borrows.rs +++ b/tests/run-pass/stacked-borrows/stacked-borrows.rs @@ -119,9 +119,6 @@ fn direct_mut_to_const_raw() { // Make sure that we can create two raw pointers from a mutable reference and use them both. fn two_raw() { unsafe { let x = &mut 0; - // Given the implicit reborrows, the only reason this currently works is that we - // do not track raw pointers: The creation of `y2` reborrows `x` and thus pops - // `y1` off the stack. let y1 = x as *mut _; let y2 = x as *mut _; *y1 += 2; From b2c9871f7d83d9ac4c7838d4bcd2c91454620244 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 30 Jan 2020 13:29:55 +0100 Subject: [PATCH 1501/3747] update another comment --- tests/run-pass/stacked-borrows/stacked-borrows.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/run-pass/stacked-borrows/stacked-borrows.rs b/tests/run-pass/stacked-borrows/stacked-borrows.rs index a70285d5152a7..765c6188b6e17 100644 --- a/tests/run-pass/stacked-borrows/stacked-borrows.rs +++ b/tests/run-pass/stacked-borrows/stacked-borrows.rs @@ -108,7 +108,7 @@ fn drop_after_sharing() { // Make sure that coercing &mut T to *const T produces a writeable pointer. fn direct_mut_to_const_raw() { - // FIXME: This is currently disabled, waiting on a fix for + // TODO: This is currently disabled, waiting on a decision on /*let x = &mut 0; let y: *const i32 = x; unsafe { *(y as *mut i32) = 1; } From ef154df60778055f7d4cd570537c9f73ceb75b8f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 30 Jan 2020 13:38:49 +0100 Subject: [PATCH 1502/3747] pass MPlaceTy by-value, as we usually do --- src/helpers.rs | 2 +- src/shims/fs.rs | 4 ++-- src/shims/time.rs | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index fba933d278d2f..a765d58bbcf35 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -339,7 +339,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // different values into a struct. fn write_packed_immediates( &mut self, - place: &MPlaceTy<'tcx, Tag>, + place: MPlaceTy<'tcx, Tag>, imms: &[ImmTy<'tcx, Tag>], ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); diff --git a/src/shims/fs.rs b/src/shims/fs.rs index b5c0dead1f8f6..2871dcbdcb8f1 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -533,7 +533,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx immty_from_uint_checked(0u128, __u64_layout)?, // stx_dev_minor ]; - this.write_packed_immediates(&statxbuf_place, &imms)?; + this.write_packed_immediates(statxbuf_place, &imms)?; Ok(0) } @@ -692,7 +692,7 @@ fn stat_macos_write_buf<'tcx, 'mir>( ]; let buf = ecx.deref_operand(buf_op)?; - ecx.write_packed_immediates(&buf, &imms)?; + ecx.write_packed_immediates(buf, &imms)?; Ok(0) } diff --git a/src/shims/time.rs b/src/shims/time.rs index a7d51eaa2e0f7..6adea524d2d88 100644 --- a/src/shims/time.rs +++ b/src/shims/time.rs @@ -45,7 +45,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx immty_from_int_checked(tv_nsec, this.libc_ty_layout("c_long")?)?, ]; - this.write_packed_immediates(&tp, &imms)?; + this.write_packed_immediates(tp, &imms)?; Ok(0) } @@ -77,7 +77,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx immty_from_int_checked(tv_usec, this.libc_ty_layout("suseconds_t")?)?, ]; - this.write_packed_immediates(&tv, &imms)?; + this.write_packed_immediates(tv, &imms)?; Ok(0) } From 2dc309729e948eec9a20d6f05a28e73d8f0513ca Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 31 Jan 2020 11:38:07 +0100 Subject: [PATCH 1503/3747] rely on improved cargo install --- .appveyor.yml | 2 +- .travis.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index 16fd20c9da616..4281fe0180f05 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -30,7 +30,7 @@ install: - rustup toolchain uninstall beta - rustup update # Install "master" toolchain - - cargo install rustup-toolchain-install-master & exit 0 + - cargo install rustup-toolchain-install-master # We need to install cargo here as well or else the DLL search path inside `cargo run` # will be for the wrong toolchain. (On Unix, `./miri` takes care of this, but not here.) - rustup-toolchain-install-master -f -n master %RUSTC_HASH% -c rust-src -c rustc-dev -c cargo diff --git a/.travis.yml b/.travis.yml index cbb7c69db1cdf..3f0ca8a016bd2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -37,7 +37,7 @@ before_script: - rustup toolchain uninstall beta - rustup update # Install "master" toolchain -- cargo install rustup-toolchain-install-master || echo "rustup-toolchain-install-master already installed" +- cargo install rustup-toolchain-install-master - travis_retry rustup-toolchain-install-master -f -n master $RUSTC_HASH -c rust-src -c rustc-dev - rustup default master - rustc --version From 121791b9af0a5d36f619e257262f8e46189c202f Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Sun, 2 Feb 2020 18:45:53 +0900 Subject: [PATCH 1504/3747] Bump rustc --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 5ce2e4651361d..e3e82ead16d52 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -3761dcd3467441f78939ccb3b341b03b6a7558d7 +0cbcb17d3306d6e22eafc2c05ce885db97d0189c From 4b6a0d7a8ead04a5fe02caccb5608295c0bd0bc8 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 6 Feb 2020 11:20:28 +0100 Subject: [PATCH 1505/3747] bump rustc; adjust tests --- rust-version | 2 +- src/shims/intrinsics.rs | 40 ---------------------------- tests/compile-fail/div-by-zero-1.rs | 4 +-- tests/compile-fail/div-by-zero-2.rs | 9 +++++++ tests/compile-fail/div-by-zero-3.rs | 11 -------- tests/compile-fail/unchecked_add1.rs | 2 +- tests/compile-fail/unchecked_add2.rs | 2 +- tests/compile-fail/unchecked_mul1.rs | 2 +- tests/compile-fail/unchecked_mul2.rs | 2 +- tests/compile-fail/unchecked_sub1.rs | 2 +- tests/compile-fail/unchecked_sub2.rs | 2 +- 11 files changed, 17 insertions(+), 61 deletions(-) create mode 100644 tests/compile-fail/div-by-zero-2.rs delete mode 100644 tests/compile-fail/div-by-zero-3.rs diff --git a/rust-version b/rust-version index e3e82ead16d52..1ea3561cca3ac 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -0cbcb17d3306d6e22eafc2c05ce885db97d0189c +333c32a5a4a51cae562c47e0669bc5aeaf741c45 diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 04e724ff1d347..9cae97a4060cf 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -518,46 +518,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_uint(align.bytes(), ptr_size), dest)?; } - "unchecked_div" => { - let l = this.read_immediate(args[0])?; - let r = this.read_immediate(args[1])?; - let rval = r.to_scalar()?.to_bits(args[1].layout.size)?; - if rval == 0 { - throw_ub_format!("Division by 0 in unchecked_div"); - } - this.binop_ignore_overflow(mir::BinOp::Div, l, r, dest)?; - } - - "unchecked_rem" => { - let l = this.read_immediate(args[0])?; - let r = this.read_immediate(args[1])?; - let rval = r.to_scalar()?.to_bits(args[1].layout.size)?; - if rval == 0 { - throw_ub_format!("Division by 0 in unchecked_rem"); - } - this.binop_ignore_overflow(mir::BinOp::Rem, l, r, dest)?; - } - - #[rustfmt::skip] - | "unchecked_add" - | "unchecked_sub" - | "unchecked_mul" - => { - let l = this.read_immediate(args[0])?; - let r = this.read_immediate(args[1])?; - let op = match intrinsic_name { - "unchecked_add" => mir::BinOp::Add, - "unchecked_sub" => mir::BinOp::Sub, - "unchecked_mul" => mir::BinOp::Mul, - _ => bug!(), - }; - let (res, overflowed, _ty) = this.overflowing_binary_op(op, l, r)?; - if overflowed { - throw_ub_format!("Overflowing arithmetic in {}", intrinsic_name); - } - this.write_scalar(res, dest)?; - } - "uninit" => { // Check fast path: we don't want to force an allocation in case the destination is a simple value, // but we also do not want to create a new allocation with 0s and then copy that over. diff --git a/tests/compile-fail/div-by-zero-1.rs b/tests/compile-fail/div-by-zero-1.rs index 987c18e4c492a..d67d06dc1e674 100644 --- a/tests/compile-fail/div-by-zero-1.rs +++ b/tests/compile-fail/div-by-zero-1.rs @@ -2,10 +2,8 @@ use std::intrinsics::*; -//error-pattern: Division by 0 in unchecked_div - fn main() { unsafe { - let _n = unchecked_div(1i64, 0); + let _n = unchecked_div(1i64, 0); //~ERROR dividing by zero } } diff --git a/tests/compile-fail/div-by-zero-2.rs b/tests/compile-fail/div-by-zero-2.rs new file mode 100644 index 0000000000000..e904049e3b466 --- /dev/null +++ b/tests/compile-fail/div-by-zero-2.rs @@ -0,0 +1,9 @@ +#![feature(core_intrinsics)] + +use std::intrinsics::*; + +fn main() { + unsafe { + let _n = unchecked_rem(3u32, 0); //~ ERROR calculating the remainder with a divisor of zero + } +} diff --git a/tests/compile-fail/div-by-zero-3.rs b/tests/compile-fail/div-by-zero-3.rs deleted file mode 100644 index 3200504ddb6e1..0000000000000 --- a/tests/compile-fail/div-by-zero-3.rs +++ /dev/null @@ -1,11 +0,0 @@ -#![feature(core_intrinsics)] - -use std::intrinsics::*; - -//error-pattern: Division by 0 in unchecked_rem - -fn main() { - unsafe { - let _n = unchecked_rem(3u32, 0); - } -} diff --git a/tests/compile-fail/unchecked_add1.rs b/tests/compile-fail/unchecked_add1.rs index 2447c8ba4a818..eb5a41fdfaf9d 100644 --- a/tests/compile-fail/unchecked_add1.rs +++ b/tests/compile-fail/unchecked_add1.rs @@ -1,5 +1,5 @@ #![feature(core_intrinsics)] fn main() { // MAX overflow - unsafe { std::intrinsics::unchecked_add(40000u16, 30000); } //~ ERROR Overflowing arithmetic in unchecked_add + unsafe { std::intrinsics::unchecked_add(40000u16, 30000); } //~ ERROR Overflow executing `unchecked_add` } diff --git a/tests/compile-fail/unchecked_add2.rs b/tests/compile-fail/unchecked_add2.rs index e292cdf6d961e..fa6a232aedee9 100644 --- a/tests/compile-fail/unchecked_add2.rs +++ b/tests/compile-fail/unchecked_add2.rs @@ -1,5 +1,5 @@ #![feature(core_intrinsics)] fn main() { // MIN overflow - unsafe { std::intrinsics::unchecked_add(-30000i16, -8000); } //~ ERROR Overflowing arithmetic in unchecked_add + unsafe { std::intrinsics::unchecked_add(-30000i16, -8000); } //~ ERROR Overflow executing `unchecked_add` } diff --git a/tests/compile-fail/unchecked_mul1.rs b/tests/compile-fail/unchecked_mul1.rs index 57bfaf124c241..a3681a57df79d 100644 --- a/tests/compile-fail/unchecked_mul1.rs +++ b/tests/compile-fail/unchecked_mul1.rs @@ -1,5 +1,5 @@ #![feature(core_intrinsics)] fn main() { // MAX overflow - unsafe { std::intrinsics::unchecked_mul(300u16, 250u16); } //~ ERROR Overflowing arithmetic in unchecked_mul + unsafe { std::intrinsics::unchecked_mul(300u16, 250u16); } //~ ERROR Overflow executing `unchecked_mul` } diff --git a/tests/compile-fail/unchecked_mul2.rs b/tests/compile-fail/unchecked_mul2.rs index 690f2dc76284c..8fe677f8ded53 100644 --- a/tests/compile-fail/unchecked_mul2.rs +++ b/tests/compile-fail/unchecked_mul2.rs @@ -1,5 +1,5 @@ #![feature(core_intrinsics)] fn main() { // MIN overflow - unsafe { std::intrinsics::unchecked_mul(1_000_000_000i32, -4); } //~ ERROR Overflowing arithmetic in unchecked_mul + unsafe { std::intrinsics::unchecked_mul(1_000_000_000i32, -4); } //~ ERROR Overflow executing `unchecked_mul` } diff --git a/tests/compile-fail/unchecked_sub1.rs b/tests/compile-fail/unchecked_sub1.rs index 0be8afa2c34cc..230607f033058 100644 --- a/tests/compile-fail/unchecked_sub1.rs +++ b/tests/compile-fail/unchecked_sub1.rs @@ -1,5 +1,5 @@ #![feature(core_intrinsics)] fn main() { // MIN overflow - unsafe { std::intrinsics::unchecked_sub(14u32, 22); } //~ ERROR Overflowing arithmetic in unchecked_sub + unsafe { std::intrinsics::unchecked_sub(14u32, 22); } //~ ERROR Overflow executing `unchecked_sub` } diff --git a/tests/compile-fail/unchecked_sub2.rs b/tests/compile-fail/unchecked_sub2.rs index bc23fa37c3676..1ea41a3c0fb07 100644 --- a/tests/compile-fail/unchecked_sub2.rs +++ b/tests/compile-fail/unchecked_sub2.rs @@ -1,5 +1,5 @@ #![feature(core_intrinsics)] fn main() { // MAX overflow - unsafe { std::intrinsics::unchecked_sub(30000i16, -7000); } //~ ERROR Overflowing arithmetic in unchecked_sub + unsafe { std::intrinsics::unchecked_sub(30000i16, -7000); } //~ ERROR Overflow executing `unchecked_sub` } From 5d2caef3cebe97fc6cf67971064c0d5cf7bc974a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 6 Feb 2020 11:24:38 +0100 Subject: [PATCH 1506/3747] also test div-by-minus-1 --- tests/compile-fail/unchecked_div1.rs | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 tests/compile-fail/unchecked_div1.rs diff --git a/tests/compile-fail/unchecked_div1.rs b/tests/compile-fail/unchecked_div1.rs new file mode 100644 index 0000000000000..1d1bbb09aa267 --- /dev/null +++ b/tests/compile-fail/unchecked_div1.rs @@ -0,0 +1,5 @@ +#![feature(core_intrinsics)] +fn main() { + // MIN/-1 cannot be represented + unsafe { std::intrinsics::unchecked_div(i16::min_value(), -1); } //~ ERROR Overflow executing `unchecked_div` +} From 98a1cac4ef4cb766c64fb476fabf7d162dd30361 Mon Sep 17 00:00:00 2001 From: David Cook Date: Thu, 6 Feb 2020 17:50:33 -0600 Subject: [PATCH 1507/3747] Add tests to cover SEEK_CUR and SEEK_END --- tests/run-pass/fs.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/tests/run-pass/fs.rs b/tests/run-pass/fs.rs index 4da67369aef84..73e6f37453fa5 100644 --- a/tests/run-pass/fs.rs +++ b/tests/run-pass/fs.rs @@ -45,6 +45,17 @@ fn main() { let mut contents = Vec::new(); file.read_to_end(&mut contents).unwrap(); assert_eq!(bytes, contents.as_slice()); + // Test seeking relative to the end of the file. + file.seek(SeekFrom::End(-1)).unwrap(); + let mut contents = Vec::new(); + file.read_to_end(&mut contents).unwrap(); + assert_eq!(&bytes[bytes.len() - 1..], contents.as_slice()); + // Test seeking relative to the current position. + file.seek(SeekFrom::Start(5)).unwrap(); + file.seek(SeekFrom::Current(-3)).unwrap(); + let mut contents = Vec::new(); + file.read_to_end(&mut contents).unwrap(); + assert_eq!(&bytes[2..], contents.as_slice()); // Test that metadata of an absolute path is correct. test_metadata(bytes, &path).unwrap(); From d208a5fe3b16ce53764df7df610cf929b4a25d57 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 7 Feb 2020 13:47:39 +0100 Subject: [PATCH 1508/3747] rustup; fix generator test --- rust-version | 2 +- tests/compile-fail/generator-pinned-moved.rs | 2 +- tests/run-pass/generator.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/rust-version b/rust-version index 1ea3561cca3ac..edb99d8eb0d5b 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -333c32a5a4a51cae562c47e0669bc5aeaf741c45 +b5e21dbb5cabdaaadc47a4d8e3f59979dcad2871 diff --git a/tests/compile-fail/generator-pinned-moved.rs b/tests/compile-fail/generator-pinned-moved.rs index 2ae98adad7739..70ceacd8ca6fa 100644 --- a/tests/compile-fail/generator-pinned-moved.rs +++ b/tests/compile-fail/generator-pinned-moved.rs @@ -25,7 +25,7 @@ where fn next(&mut self) -> Option { let me = unsafe { Pin::new_unchecked(&mut self.0) }; - match me.resume() { + match me.resume(()) { GeneratorState::Yielded(x) => Some(x), GeneratorState::Complete(_) => None, } diff --git a/tests/run-pass/generator.rs b/tests/run-pass/generator.rs index c31b5b9ed3bb2..7f95f374ac7d8 100644 --- a/tests/run-pass/generator.rs +++ b/tests/run-pass/generator.rs @@ -9,7 +9,7 @@ fn finish(mut amt: usize, mut t: T) -> T::Return // We are not moving the `t` around until it gets dropped, so this is okay. let mut t = unsafe { Pin::new_unchecked(&mut t) }; loop { - match t.as_mut().resume() { + match t.as_mut().resume(()) { GeneratorState::Yielded(y) => amt -= y, GeneratorState::Complete(ret) => { assert_eq!(amt, 0); From 418dd641dc41e3e9edc832f9083a669836110d15 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 7 Feb 2020 14:02:36 +0100 Subject: [PATCH 1509/3747] test more generator resume things --- tests/run-pass/generator.rs | 155 ++++++++++++++++++++++++++++---- tests/run-pass/generator.stderr | 1 + 2 files changed, 138 insertions(+), 18 deletions(-) create mode 100644 tests/run-pass/generator.stderr diff --git a/tests/run-pass/generator.rs b/tests/run-pass/generator.rs index 7f95f374ac7d8..a7c72ed3530ca 100644 --- a/tests/run-pass/generator.rs +++ b/tests/run-pass/generator.rs @@ -1,30 +1,33 @@ #![feature(generators, generator_trait, never_type)] -use std::ops::{GeneratorState, Generator}; +use std::panic::{catch_unwind, AssertUnwindSafe}; +use std::ops::{GeneratorState::{self, *}, Generator}; use std::pin::Pin; +use std::sync::atomic::{AtomicUsize, Ordering}; +use std::fmt::Debug; -fn finish(mut amt: usize, mut t: T) -> T::Return - where T: Generator -{ - // We are not moving the `t` around until it gets dropped, so this is okay. - let mut t = unsafe { Pin::new_unchecked(&mut t) }; - loop { - match t.as_mut().resume(()) { - GeneratorState::Yielded(y) => amt -= y, - GeneratorState::Complete(ret) => { - assert_eq!(amt, 0); - return ret +fn basic() { + fn finish(mut amt: usize, mut t: T) -> T::Return + where T: Generator + { + // We are not moving the `t` around until it gets dropped, so this is okay. + let mut t = unsafe { Pin::new_unchecked(&mut t) }; + loop { + match t.as_mut().resume(()) { + GeneratorState::Yielded(y) => amt -= y, + GeneratorState::Complete(ret) => { + assert_eq!(amt, 0); + return ret + } } } } -} -enum Never {} -fn never() -> Never { - panic!() -} + enum Never {} + fn never() -> Never { + panic!() + } -fn main() { finish(1, || yield 1); finish(3, || { @@ -94,3 +97,119 @@ fn main() { let _x: (String, !) = (String::new(), { yield 2; return }); }); } + +fn smoke_resume_arg() { + fn drain + Unpin, R, Y>( + gen: &mut G, + inout: Vec<(R, GeneratorState)>, + ) where + Y: Debug + PartialEq, + G::Return: Debug + PartialEq, + { + let mut gen = Pin::new(gen); + + for (input, out) in inout { + assert_eq!(gen.as_mut().resume(input), out); + } + } + + static DROPS: AtomicUsize = AtomicUsize::new(0); + + #[derive(Debug, PartialEq)] + struct DropMe; + + impl Drop for DropMe { + fn drop(&mut self) { + DROPS.fetch_add(1, Ordering::SeqCst); + } + } + + fn expect_drops(expected_drops: usize, f: impl FnOnce() -> T) -> T { + DROPS.store(0, Ordering::SeqCst); + + let res = f(); + + let actual_drops = DROPS.load(Ordering::SeqCst); + assert_eq!(actual_drops, expected_drops); + res + } + + drain( + &mut |mut b| { + while b != 0 { + b = yield (b + 1); + } + -1 + }, + vec![(1, Yielded(2)), (-45, Yielded(-44)), (500, Yielded(501)), (0, Complete(-1))], + ); + + expect_drops(2, || drain(&mut |a| yield a, vec![(DropMe, Yielded(DropMe))])); + + expect_drops(6, || { + drain( + &mut |a| yield yield a, + vec![(DropMe, Yielded(DropMe)), (DropMe, Yielded(DropMe)), (DropMe, Complete(DropMe))], + ) + }); + + #[allow(unreachable_code)] + expect_drops(2, || drain(&mut |a| yield return a, vec![(DropMe, Complete(DropMe))])); + + expect_drops(2, || { + drain( + &mut |a: DropMe| { + if false { yield () } else { a } + }, + vec![(DropMe, Complete(DropMe))], + ) + }); + + expect_drops(4, || { + drain( + #[allow(unused_assignments, unused_variables)] + &mut |mut a: DropMe| { + a = yield; + a = yield; + a = yield; + }, + vec![ + (DropMe, Yielded(())), + (DropMe, Yielded(())), + (DropMe, Yielded(())), + (DropMe, Complete(())), + ], + ) + }); +} + +fn panic_drop_resume() { + static DROP: AtomicUsize = AtomicUsize::new(0); + + struct Dropper {} + + impl Drop for Dropper { + fn drop(&mut self) { + DROP.fetch_add(1, Ordering::SeqCst); + } + } + + let mut gen = |_arg| { + if true { + panic!(); + } + yield (); + }; + let mut gen = Pin::new(&mut gen); + + assert_eq!(DROP.load(Ordering::Acquire), 0); + let res = catch_unwind(AssertUnwindSafe(|| gen.as_mut().resume(Dropper {}))); + assert!(res.is_err()); + assert_eq!(DROP.load(Ordering::Acquire), 1); +} + +fn main() { + basic(); + smoke_resume_arg(); + panic_drop_resume(); +} diff --git a/tests/run-pass/generator.stderr b/tests/run-pass/generator.stderr new file mode 100644 index 0000000000000..17f385d4d6951 --- /dev/null +++ b/tests/run-pass/generator.stderr @@ -0,0 +1 @@ +thread 'main' panicked at 'explicit panic', $DIR/generator.rs:199:13 From 45f6744fdac14196378c0d2f28c48d27024d9589 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 7 Feb 2020 14:19:58 +0100 Subject: [PATCH 1510/3747] panics dont work on Windows, just the smoke test should be enough --- tests/run-pass/generator.rs | 27 --------------------------- tests/run-pass/generator.stderr | 1 - 2 files changed, 28 deletions(-) delete mode 100644 tests/run-pass/generator.stderr diff --git a/tests/run-pass/generator.rs b/tests/run-pass/generator.rs index a7c72ed3530ca..e85d2cf8f29a8 100644 --- a/tests/run-pass/generator.rs +++ b/tests/run-pass/generator.rs @@ -1,6 +1,5 @@ #![feature(generators, generator_trait, never_type)] -use std::panic::{catch_unwind, AssertUnwindSafe}; use std::ops::{GeneratorState::{self, *}, Generator}; use std::pin::Pin; use std::sync::atomic::{AtomicUsize, Ordering}; @@ -183,33 +182,7 @@ fn smoke_resume_arg() { }); } -fn panic_drop_resume() { - static DROP: AtomicUsize = AtomicUsize::new(0); - - struct Dropper {} - - impl Drop for Dropper { - fn drop(&mut self) { - DROP.fetch_add(1, Ordering::SeqCst); - } - } - - let mut gen = |_arg| { - if true { - panic!(); - } - yield (); - }; - let mut gen = Pin::new(&mut gen); - - assert_eq!(DROP.load(Ordering::Acquire), 0); - let res = catch_unwind(AssertUnwindSafe(|| gen.as_mut().resume(Dropper {}))); - assert!(res.is_err()); - assert_eq!(DROP.load(Ordering::Acquire), 1); -} - fn main() { basic(); smoke_resume_arg(); - panic_drop_resume(); } diff --git a/tests/run-pass/generator.stderr b/tests/run-pass/generator.stderr deleted file mode 100644 index 17f385d4d6951..0000000000000 --- a/tests/run-pass/generator.stderr +++ /dev/null @@ -1 +0,0 @@ -thread 'main' panicked at 'explicit panic', $DIR/generator.rs:199:13 From 38204b63211302a77bb9ff677f6b1df9f5acd734 Mon Sep 17 00:00:00 2001 From: David Cook Date: Sun, 26 Jan 2020 16:45:05 -0600 Subject: [PATCH 1511/3747] Add shim for rename --- src/shims/foreign_items.rs | 5 +++++ src/shims/fs.rs | 28 +++++++++++++++++++++++++++- tests/run-pass/fs.rs | 14 +++++++++++++- 3 files changed, 45 insertions(+), 2 deletions(-) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 5b40f3c690631..2fd886ed0e84c 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -521,6 +521,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; } + "rename" => { + let result = this.rename(args[0], args[1])?; + this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + } + "clock_gettime" => { let result = this.clock_gettime(args[0], args[1])?; this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; diff --git a/src/shims/fs.rs b/src/shims/fs.rs index f0efc073f75cb..2ae215e7204f2 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -1,6 +1,6 @@ use std::collections::HashMap; use std::convert::{TryFrom, TryInto}; -use std::fs::{remove_file, File, OpenOptions}; +use std::fs::{remove_file, rename, File, OpenOptions}; use std::io::{Read, Seek, SeekFrom, Write}; use std::path::PathBuf; use std::time::SystemTime; @@ -582,6 +582,32 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.set_last_error(ebadf)?; Ok((-1).into()) } + + fn rename( + &mut self, + oldpath_op: OpTy<'tcx, Tag>, + newpath_op: OpTy<'tcx, Tag>, + ) -> InterpResult<'tcx, i32> { + let this = self.eval_context_mut(); + + this.check_no_isolation("rename")?; + + let oldpath_scalar = this.read_scalar(oldpath_op)?.not_undef()?; + let newpath_scalar = this.read_scalar(newpath_op)?.not_undef()?; + + if this.is_null(oldpath_scalar)? || this.is_null(newpath_scalar)? { + let efault = this.eval_libc("EFAULT")?; + this.set_last_error(efault)?; + return Ok(-1); + } + + let oldpath = this.read_os_str_from_c_str(oldpath_scalar)?; + let newpath = this.read_os_str_from_c_str(newpath_scalar)?; + + let result = rename(oldpath, newpath).map(|_| 0); + + this.try_unwrap_io_result(result) + } } /// Extracts the number of seconds and nanoseconds elapsed between `time` and the unix epoch when diff --git a/tests/run-pass/fs.rs b/tests/run-pass/fs.rs index 7483bf3ec8b8a..9e1891adf34ea 100644 --- a/tests/run-pass/fs.rs +++ b/tests/run-pass/fs.rs @@ -1,7 +1,7 @@ // ignore-windows: File handling is not implemented yet // compile-flags: -Zmiri-disable-isolation -use std::fs::{File, remove_file}; +use std::fs::{File, remove_file, rename}; use std::io::{Read, Write, ErrorKind, Result, Seek, SeekFrom}; use std::path::{PathBuf, Path}; @@ -82,6 +82,18 @@ fn main() { // Removing file should succeed. remove_file(&path).unwrap(); + // Renaming a file should succeed. + let path1 = tmp.join("rename_source.txt"); + let path2 = tmp.join("rename_destination.txt"); + // Clean files for robustness. + remove_file(&path1).ok(); + remove_file(&path2).ok(); + let file = File::create(&path1).unwrap(); + drop(file); + rename(&path1, &path2).unwrap(); + assert!(path2.metadata().unwrap().is_file()); + remove_file(&path2).ok(); + // The two following tests also check that the `__errno_location()` shim is working properly. // Opening a non-existing file should fail with a "not found" error. assert_eq!(ErrorKind::NotFound, File::open(&path).unwrap_err().kind()); From f7e085764445c679bdc2694733119f2b5aeedf8e Mon Sep 17 00:00:00 2001 From: David Cook Date: Sat, 8 Feb 2020 22:40:46 -0600 Subject: [PATCH 1512/3747] Test that src path of rename is no longer a file --- tests/run-pass/fs.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/run-pass/fs.rs b/tests/run-pass/fs.rs index 9e1891adf34ea..e9132fbd61db5 100644 --- a/tests/run-pass/fs.rs +++ b/tests/run-pass/fs.rs @@ -91,6 +91,7 @@ fn main() { let file = File::create(&path1).unwrap(); drop(file); rename(&path1, &path2).unwrap(); + assert_eq!(ErrorKind::NotFound, path1.metadata().unwrap_err().kind()); assert!(path2.metadata().unwrap().is_file()); remove_file(&path2).ok(); From 87644d120fb6d0f349e003d212dd8dd5053edd49 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 12 Feb 2020 21:44:09 +0100 Subject: [PATCH 1513/3747] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index edb99d8eb0d5b..89a8a40f1b2bc 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -b5e21dbb5cabdaaadc47a4d8e3f59979dcad2871 +2d2be570970d784db5539a1d309cd22b85be910a From a843fd4e17bc88895a265136a775e73b4d44dd0a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 12 Feb 2020 21:50:54 +0100 Subject: [PATCH 1514/3747] add test for layout optimizations --- tests/run-pass/stacked-borrows/refcell.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tests/run-pass/stacked-borrows/refcell.rs b/tests/run-pass/stacked-borrows/refcell.rs index 0939a666193e8..83db10577cebf 100644 --- a/tests/run-pass/stacked-borrows/refcell.rs +++ b/tests/run-pass/stacked-borrows/refcell.rs @@ -4,6 +4,7 @@ fn main() { basic(); ref_protector(); ref_mut_protector(); + rust_issue_68303(); } fn basic() { @@ -66,3 +67,11 @@ fn ref_mut_protector() { let rc = RefCell::new(0); break_it(&rc, rc.borrow_mut()) } + +/// Make sure we do not have bad enum layout optimizations. +fn rust_issue_68303() { + let optional=Some(RefCell::new(false)); + let mut handle=optional.as_ref().unwrap().borrow_mut(); + assert!(optional.is_some()); + *handle=true; +} From 26d25220ef1e4757b167c0ddca0410d7eb20a9fa Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 13 Feb 2020 14:01:35 +0100 Subject: [PATCH 1515/3747] fix for Panic InterpError refactoring --- src/machine.rs | 2 +- src/operator.rs | 2 +- src/shims/foreign_items.rs | 2 +- src/shims/panic.rs | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/machine.rs b/src/machine.rs index f8c7168a5847c..5d933fe8a7f60 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -219,7 +219,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { fn assert_panic( ecx: &mut InterpCx<'mir, 'tcx, Self>, span: Span, - msg: &AssertMessage<'tcx>, + msg: &mir::AssertMessage<'tcx>, unwind: Option, ) -> InterpResult<'tcx> { ecx.assert_panic(span, msg, unwind) diff --git a/src/operator.rs b/src/operator.rs index 7c932a907e725..8860b949fe942 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -105,7 +105,7 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { let pointee_size = i64::try_from(self.layout_of(pointee_ty)?.size.bytes()).unwrap(); let offset = offset .checked_mul(pointee_size) - .ok_or_else(|| err_panic!(Overflow(mir::BinOp::Mul)))?; + .ok_or_else(|| err_ub_format!("overflow during offset comutation for inbounds pointer arithmetic"))?; // We do this first, to rule out overflows. let offset_ptr = ptr.ptr_signed_offset(offset, self)?; // What we need to check is that starting at `min(ptr, offset_ptr)`, diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 5b40f3c690631..4a1d62d3567e8 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -177,7 +177,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let items = this.read_scalar(args[0])?.to_machine_usize(this)?; let len = this.read_scalar(args[1])?.to_machine_usize(this)?; let size = - items.checked_mul(len).ok_or_else(|| err_panic!(Overflow(mir::BinOp::Mul)))?; + items.checked_mul(len).ok_or_else(|| err_ub_format!("overflow during calloc size computation"))?; let res = this.malloc(size, /*zero_init:*/ true, MiriMemoryKind::C); this.write_scalar(res, dest)?; } diff --git a/src/shims/panic.rs b/src/shims/panic.rs index d676f04646574..880932ae04722 100644 --- a/src/shims/panic.rs +++ b/src/shims/panic.rs @@ -153,10 +153,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn assert_panic( &mut self, span: Span, - msg: &AssertMessage<'tcx>, + msg: &mir::AssertMessage<'tcx>, unwind: Option, ) -> InterpResult<'tcx> { - use rustc::mir::interpret::PanicInfo::*; + use rustc::mir::AssertKind::*; let this = self.eval_context_mut(); match msg { From a61596d3332c9b2103404d6ee4f0b47fd6d569a5 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 14 Feb 2020 08:59:42 +0100 Subject: [PATCH 1516/3747] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 89a8a40f1b2bc..a0f512a727001 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -2d2be570970d784db5539a1d309cd22b85be910a +21ed50522ddb998f5367229984a4510af578899f From 91868125a519db341f86410590b959b10de03f11 Mon Sep 17 00:00:00 2001 From: David Cook Date: Fri, 14 Feb 2020 08:19:16 -0600 Subject: [PATCH 1517/3747] Removing file after rename must succeed Co-Authored-By: Ralf Jung --- tests/run-pass/fs.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/run-pass/fs.rs b/tests/run-pass/fs.rs index e9132fbd61db5..71c6e854f7c57 100644 --- a/tests/run-pass/fs.rs +++ b/tests/run-pass/fs.rs @@ -93,7 +93,7 @@ fn main() { rename(&path1, &path2).unwrap(); assert_eq!(ErrorKind::NotFound, path1.metadata().unwrap_err().kind()); assert!(path2.metadata().unwrap().is_file()); - remove_file(&path2).ok(); + remove_file(&path2).unwrap(); // The two following tests also check that the `__errno_location()` shim is working properly. // Opening a non-existing file should fail with a "not found" error. From e7d6e718b91d4122ee5ba8fa2ac67fb49af93f89 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Sun, 2 Feb 2020 16:21:12 -0500 Subject: [PATCH 1518/3747] reorganize shims by platform --- src/shims/foreign_items.rs | 226 ++++--------------------- src/shims/foreign_items/posix.rs | 111 ++++++++++++ src/shims/foreign_items/posix/linux.rs | 46 +++++ src/shims/foreign_items/posix/macos.rs | 62 +++++++ src/shims/foreign_items/windows.rs | 75 ++++++++ 5 files changed, 328 insertions(+), 192 deletions(-) create mode 100644 src/shims/foreign_items/posix.rs create mode 100644 src/shims/foreign_items/posix/linux.rs create mode 100644 src/shims/foreign_items/posix/macos.rs create mode 100644 src/shims/foreign_items/windows.rs diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index ff5ffb0e3ac6a..d3a8ac1b065f5 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -1,3 +1,6 @@ +mod windows; +mod posix; + use std::{convert::TryInto, iter}; use rustc_hir::def_id::DefId; @@ -167,6 +170,30 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx }; // Next: functions that return. + match link_name { + "__rust_maybe_catch_panic" => { + this.handle_catch_panic(args, dest, ret)?; + return Ok(None); + } + + _ => this.emulate_foreign_item_by_name(link_name, args, dest)?, + }; + + this.dump_place(*dest); + this.go_to_block(ret); + + Ok(None) + } + + fn emulate_foreign_item_by_name( + &mut self, + link_name: &str, + args: &[OpTy<'tcx, Tag>], + dest: PlaceTy<'tcx, Tag>, + ) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + let tcx = &{ this.tcx.tcx }; + match link_name { "malloc" => { let size = this.read_scalar(args[0])?.to_machine_usize(this)?; @@ -339,11 +366,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } - "__rust_maybe_catch_panic" => { - this.handle_catch_panic(args, dest, ret)?; - return Ok(None); - } - "memcmp" => { let left = this.read_scalar(args[0])?.not_undef()?; let right = this.read_scalar(args[1])?.not_undef()?; @@ -399,143 +421,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } - | "__errno_location" - | "__error" - => { - let errno_place = this.machine.last_error.unwrap(); - this.write_scalar(errno_place.to_ref().to_scalar()?, dest)?; - } - - "getenv" => { - let result = this.getenv(args[0])?; - this.write_scalar(result, dest)?; - } - - "unsetenv" => { - let result = this.unsetenv(args[0])?; - this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; - } - - "setenv" => { - let result = this.setenv(args[0], args[1])?; - this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; - } - - "getcwd" => { - let result = this.getcwd(args[0], args[1])?; - this.write_scalar(result, dest)?; - } - - "chdir" => { - let result = this.chdir(args[0])?; - this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; - } - - | "open" - | "open64" - => { - let result = this.open(args[0], args[1])?; - this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; - } - - "fcntl" => { - let result = this.fcntl(args[0], args[1], args.get(2).cloned())?; - this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; - } - - | "close" - | "close$NOCANCEL" - => { - let result = this.close(args[0])?; - this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; - } - - "read" => { - let result = this.read(args[0], args[1], args[2])?; - this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; - } - - "write" => { - let fd = this.read_scalar(args[0])?.to_i32()?; - let buf = this.read_scalar(args[1])?.not_undef()?; - let n = this.read_scalar(args[2])?.to_machine_usize(tcx)?; - trace!("Called write({:?}, {:?}, {:?})", fd, buf, n); - let result = if fd == 1 || fd == 2 { - // stdout/stderr - use std::io::{self, Write}; - - let buf_cont = this.memory.read_bytes(buf, Size::from_bytes(n))?; - // We need to flush to make sure this actually appears on the screen - let res = if fd == 1 { - // Stdout is buffered, flush to make sure it appears on the screen. - // This is the write() syscall of the interpreted program, we want it - // to correspond to a write() syscall on the host -- there is no good - // in adding extra buffering here. - let res = io::stdout().write(buf_cont); - io::stdout().flush().unwrap(); - res - } else { - // No need to flush, stderr is not buffered. - io::stderr().write(buf_cont) - }; - match res { - Ok(n) => n as i64, - Err(_) => -1, - } - } else { - this.write(args[0], args[1], args[2])? - }; - // Now, `result` is the value we return back to the program. - this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; - } - - | "lseek64" - | "lseek" - => { - let result = this.lseek64(args[0], args[1], args[2])?; - this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; - } - - "unlink" => { - let result = this.unlink(args[0])?; - this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; - } - - "symlink" => { - let result = this.symlink(args[0], args[1])?; - this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; - } - - "stat$INODE64" => { - let result = this.stat(args[0], args[1])?; - this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; - } - - "lstat$INODE64" => { - let result = this.lstat(args[0], args[1])?; - this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; - } - - "fstat$INODE64" => { - let result = this.fstat(args[0], args[1])?; - this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; - } "rename" => { let result = this.rename(args[0], args[1])?; this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; } - "clock_gettime" => { - let result = this.clock_gettime(args[0], args[1])?; - this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; - } - - "gettimeofday" => { - let result = this.gettimeofday(args[0], args[1])?; - this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; - } - "strlen" => { let ptr = this.read_scalar(args[0])?.not_undef()?; let n = this.memory.read_c_str(ptr)?.len(); @@ -950,60 +841,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // which one it is. this.write_scalar(Scalar::from_int(which, this.pointer_size()), dest)?; } - "WriteFile" => { - let handle = this.read_scalar(args[0])?.to_machine_isize(this)?; - let buf = this.read_scalar(args[1])?.not_undef()?; - let n = this.read_scalar(args[2])?.to_u32()?; - let written_place = this.deref_operand(args[3])?; - // Spec says to always write `0` first. - this.write_null(written_place.into())?; - let written = if handle == -11 || handle == -12 { - // stdout/stderr - use std::io::{self, Write}; - - let buf_cont = this.memory.read_bytes(buf, Size::from_bytes(u64::from(n)))?; - let res = if handle == -11 { - io::stdout().write(buf_cont) - } else { - io::stderr().write(buf_cont) - }; - res.ok().map(|n| n as u32) - } else { - eprintln!("Miri: Ignored output to handle {}", handle); - // Pretend it all went well. - Some(n) - }; - // If there was no error, write back how much was written. - if let Some(n) = written { - this.write_scalar(Scalar::from_u32(n), written_place.into())?; - } - // Return whether this was a success. - this.write_scalar( - Scalar::from_int(if written.is_some() { 1 } else { 0 }, dest.layout.size), - dest, - )?; - } "GetConsoleMode" => { // Everything is a pipe. this.write_null(dest)?; } - "GetEnvironmentVariableW" => { - // args[0] : LPCWSTR lpName (32-bit ptr to a const string of 16-bit Unicode chars) - // args[1] : LPWSTR lpBuffer (32-bit pointer to a string of 16-bit Unicode chars) - // lpBuffer : ptr to buffer that receives contents of the env_var as a null-terminated string. - // Return `# of chars` stored in the buffer pointed to by lpBuffer, excluding null-terminator. - // Return 0 upon failure. - - // This is not the env var you are looking for. - this.set_last_error(Scalar::from_u32(203))?; // ERROR_ENVVAR_NOT_FOUND - this.write_null(dest)?; - } - "SetEnvironmentVariableW" => { - // args[0] : LPCWSTR lpName (32-bit ptr to a const string of 16-bit Unicode chars) - // args[1] : LPCWSTR lpValue (32-bit ptr to a const string of 16-bit Unicode chars) - // Return nonzero if success, else return 0. - throw_unsup_format!("can't set environment variable on Windows"); - } "GetCommandLineW" => { this.write_scalar( this.machine.cmd_line.expect("machine must be initialized"), @@ -1018,13 +859,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_bool(true), dest)?; } - // We can't execute anything else. - _ => throw_unsup_format!("can't call foreign function: {}", link_name), - } + _ => match this.tcx.sess.target.target.target_os.to_lowercase().as_str() { + "linux" | "macos" => posix::EvalContextExt::emulate_foreign_item_by_name(this, link_name, args, dest)?, + "windows" => windows::EvalContextExt::emulate_foreign_item_by_name(this, link_name, args, dest)?, + target => throw_unsup_format!("The {} target platform is not supported", target), + } + }; - this.dump_place(*dest); - this.go_to_block(ret); - Ok(None) + Ok(()) } /// Evaluates the scalar at the specified path. Returns Some(val) diff --git a/src/shims/foreign_items/posix.rs b/src/shims/foreign_items/posix.rs new file mode 100644 index 0000000000000..ecdec1fb165cc --- /dev/null +++ b/src/shims/foreign_items/posix.rs @@ -0,0 +1,111 @@ +mod linux; +mod macos; + +use crate::*; +use rustc::ty::layout::Size; + +impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} +pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { + fn emulate_foreign_item_by_name( + &mut self, + link_name: &str, + args: &[OpTy<'tcx, Tag>], + dest: PlaceTy<'tcx, Tag>, + ) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + let tcx = &{ this.tcx.tcx }; + + match link_name { + // Environment related shims + "getenv" => { + let result = this.getenv(args[0])?; + this.write_scalar(result, dest)?; + } + + "unsetenv" => { + let result = this.unsetenv(args[0])?; + this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + } + + "setenv" => { + let result = this.setenv(args[0], args[1])?; + this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + } + + "getcwd" => { + let result = this.getcwd(args[0], args[1])?; + this.write_scalar(result, dest)?; + } + + "chdir" => { + let result = this.chdir(args[0])?; + this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + } + + // File related shims + "fcntl" => { + let result = this.fcntl(args[0], args[1], args.get(2).cloned())?; + this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + } + + "read" => { + let result = this.read(args[0], args[1], args[2])?; + this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + } + + "write" => { + let fd = this.read_scalar(args[0])?.to_i32()?; + let buf = this.read_scalar(args[1])?.not_undef()?; + let n = this.read_scalar(args[2])?.to_machine_usize(tcx)?; + trace!("Called write({:?}, {:?}, {:?})", fd, buf, n); + let result = if fd == 1 || fd == 2 { + // stdout/stderr + use std::io::{self, Write}; + + let buf_cont = this.memory.read_bytes(buf, Size::from_bytes(n))?; + // We need to flush to make sure this actually appears on the screen + let res = if fd == 1 { + // Stdout is buffered, flush to make sure it appears on the screen. + // This is the write() syscall of the interpreted program, we want it + // to correspond to a write() syscall on the host -- there is no good + // in adding extra buffering here. + let res = io::stdout().write(buf_cont); + io::stdout().flush().unwrap(); + res + } else { + // No need to flush, stderr is not buffered. + io::stderr().write(buf_cont) + }; + match res { + Ok(n) => n as i64, + Err(_) => -1, + } + } else { + this.write(args[0], args[1], args[2])? + }; + // Now, `result` is the value we return back to the program. + this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + } + + "unlink" => { + let result = this.unlink(args[0])?; + this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + } + + "symlink" => { + let result = this.symlink(args[0], args[1])?; + this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + } + + _ => { + match this.tcx.sess.target.target.target_os.to_lowercase().as_str() { + "linux" => linux::EvalContextExt::emulate_foreign_item_by_name(this, link_name, args, dest)?, + "macos" => macos::EvalContextExt::emulate_foreign_item_by_name(this, link_name, args, dest)?, + _ => unreachable!(), + } + } + }; + + Ok(()) + } +} diff --git a/src/shims/foreign_items/posix/linux.rs b/src/shims/foreign_items/posix/linux.rs new file mode 100644 index 0000000000000..bc61aea18c737 --- /dev/null +++ b/src/shims/foreign_items/posix/linux.rs @@ -0,0 +1,46 @@ +use crate::*; + +impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} +pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { + fn emulate_foreign_item_by_name( + &mut self, + link_name: &str, + args: &[OpTy<'tcx, Tag>], + dest: PlaceTy<'tcx, Tag>, + ) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + + match link_name { + "__errno_location" => { + let errno_place = this.machine.last_error.unwrap(); + this.write_scalar(errno_place.to_ref().to_scalar()?, dest)?; + } + + // File related shims + "open64" => { + let result = this.open(args[0], args[1])?; + this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + } + + "close" => { + let result = this.close(args[0])?; + this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + } + + "lseek64" => { + let result = this.lseek64(args[0], args[1], args[2])?; + this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + } + + // Time related shims + "clock_gettime" => { + let result = this.clock_gettime(args[0], args[1])?; + this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + } + + _ => throw_unsup_format!("can't call foreign function: {}", link_name), + }; + + Ok(()) + } +} diff --git a/src/shims/foreign_items/posix/macos.rs b/src/shims/foreign_items/posix/macos.rs new file mode 100644 index 0000000000000..e0ac92868a2c7 --- /dev/null +++ b/src/shims/foreign_items/posix/macos.rs @@ -0,0 +1,62 @@ +use crate::*; + +impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} +pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { + fn emulate_foreign_item_by_name( + &mut self, + link_name: &str, + args: &[OpTy<'tcx, Tag>], + dest: PlaceTy<'tcx, Tag>, + ) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + + match link_name { + "__error" => { + let errno_place = this.machine.last_error.unwrap(); + this.write_scalar(errno_place.to_ref().to_scalar()?, dest)?; + } + + // File related shims + "open" => { + let result = this.open(args[0], args[1])?; + this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + } + + "close$NOCANCEL" => { + let result = this.close(args[0])?; + this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + } + + "stat$INODE64" => { + let result = this.stat(args[0], args[1])?; + this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + } + + "lstat$INODE64" => { + let result = this.lstat(args[0], args[1])?; + this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + } + + "fstat$INODE64" => { + let result = this.fstat(args[0], args[1])?; + this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + } + + "lseek" => { + let result = this.lseek64(args[0], args[1], args[2])?; + this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + } + + // Time related shims + "gettimeofday" => { + let result = this.gettimeofday(args[0], args[1])?; + this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + } + + _ => throw_unsup_format!("can't call foreign function: {}", link_name), + }; + + Ok(()) + } +} + diff --git a/src/shims/foreign_items/windows.rs b/src/shims/foreign_items/windows.rs new file mode 100644 index 0000000000000..23aa8ae7deb34 --- /dev/null +++ b/src/shims/foreign_items/windows.rs @@ -0,0 +1,75 @@ +use crate::*; +use rustc::ty::layout::Size; + +impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} +pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { + fn emulate_foreign_item_by_name( + &mut self, + link_name: &str, + args: &[OpTy<'tcx, Tag>], + dest: PlaceTy<'tcx, Tag>, + ) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + + match link_name { + // Environment related shims + "GetEnvironmentVariableW" => { + // args[0] : LPCWSTR lpName (32-bit ptr to a const string of 16-bit Unicode chars) + // args[1] : LPWSTR lpBuffer (32-bit pointer to a string of 16-bit Unicode chars) + // lpBuffer : ptr to buffer that receives contents of the env_var as a null-terminated string. + // Return `# of chars` stored in the buffer pointed to by lpBuffer, excluding null-terminator. + // Return 0 upon failure. + + // This is not the env var you are looking for. + this.set_last_error(Scalar::from_u32(203))?; // ERROR_ENVVAR_NOT_FOUND + this.write_null(dest)?; + } + + "SetEnvironmentVariableW" => { + // args[0] : LPCWSTR lpName (32-bit ptr to a const string of 16-bit Unicode chars) + // args[1] : LPCWSTR lpValue (32-bit ptr to a const string of 16-bit Unicode chars) + // Return nonzero if success, else return 0. + throw_unsup_format!("can't set environment variable on Windows"); + } + + // File related shims + "WriteFile" => { + let handle = this.read_scalar(args[0])?.to_machine_isize(this)?; + let buf = this.read_scalar(args[1])?.not_undef()?; + let n = this.read_scalar(args[2])?.to_u32()?; + let written_place = this.deref_operand(args[3])?; + // Spec says to always write `0` first. + this.write_null(written_place.into())?; + let written = if handle == -11 || handle == -12 { + // stdout/stderr + use std::io::{self, Write}; + + let buf_cont = this.memory.read_bytes(buf, Size::from_bytes(u64::from(n)))?; + let res = if handle == -11 { + io::stdout().write(buf_cont) + } else { + io::stderr().write(buf_cont) + }; + res.ok().map(|n| n as u32) + } else { + eprintln!("Miri: Ignored output to handle {}", handle); + // Pretend it all went well. + Some(n) + }; + // If there was no error, write back how much was written. + if let Some(n) = written { + this.write_scalar(Scalar::from_u32(n), written_place.into())?; + } + // Return whether this was a success. + this.write_scalar( + Scalar::from_int(if written.is_some() { 1 } else { 0 }, dest.layout.size), + dest, + )?; + } + _ => throw_unsup_format!("can't call foreign function: {}", link_name), + } + + Ok(()) + } +} + From f2f8fb2c20e1a0371f43379ac13eb323f95b4f4b Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Wed, 5 Feb 2020 19:46:50 -0500 Subject: [PATCH 1519/3747] migrate more functions --- src/shims/foreign_items.rs | 157 ------------------------- src/shims/foreign_items/posix/linux.rs | 3 + src/shims/foreign_items/posix/macos.rs | 29 +++++ src/shims/foreign_items/windows.rs | 128 ++++++++++++++++++++ 4 files changed, 160 insertions(+), 157 deletions(-) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index d3a8ac1b065f5..f8a61a7c5a12a 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -702,163 +702,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_null(dest)?; } - // macOS API stubs. - | "pthread_attr_get_np" - | "pthread_getattr_np" - => { - this.write_null(dest)?; - } - "pthread_get_stackaddr_np" => { - let stack_addr = Scalar::from_uint(STACK_ADDR, dest.layout.size); - this.write_scalar(stack_addr, dest)?; - } - "pthread_get_stacksize_np" => { - let stack_size = Scalar::from_uint(STACK_SIZE, dest.layout.size); - this.write_scalar(stack_size, dest)?; - } - "_tlv_atexit" => { - // FIXME: register the destructor. - } - "_NSGetArgc" => { - this.write_scalar(this.machine.argc.expect("machine must be initialized"), dest)?; - } - "_NSGetArgv" => { - this.write_scalar(this.machine.argv.expect("machine must be initialized"), dest)?; - } - "SecRandomCopyBytes" => { - let len = this.read_scalar(args[1])?.to_machine_usize(this)?; - let ptr = this.read_scalar(args[2])?.not_undef()?; - this.gen_random(ptr, len as usize)?; - this.write_null(dest)?; - } - - // Windows API stubs. - // HANDLE = isize - // DWORD = ULONG = u32 - // BOOL = i32 - "GetProcessHeap" => { - // Just fake a HANDLE - this.write_scalar(Scalar::from_int(1, this.pointer_size()), dest)?; - } - "HeapAlloc" => { - let _handle = this.read_scalar(args[0])?.to_machine_isize(this)?; - let flags = this.read_scalar(args[1])?.to_u32()?; - let size = this.read_scalar(args[2])?.to_machine_usize(this)?; - let zero_init = (flags & 0x00000008) != 0; // HEAP_ZERO_MEMORY - let res = this.malloc(size, zero_init, MiriMemoryKind::WinHeap); - this.write_scalar(res, dest)?; - } - "HeapFree" => { - let _handle = this.read_scalar(args[0])?.to_machine_isize(this)?; - let _flags = this.read_scalar(args[1])?.to_u32()?; - let ptr = this.read_scalar(args[2])?.not_undef()?; - this.free(ptr, MiriMemoryKind::WinHeap)?; - this.write_scalar(Scalar::from_int(1, Size::from_bytes(4)), dest)?; - } - "HeapReAlloc" => { - let _handle = this.read_scalar(args[0])?.to_machine_isize(this)?; - let _flags = this.read_scalar(args[1])?.to_u32()?; - let ptr = this.read_scalar(args[2])?.not_undef()?; - let size = this.read_scalar(args[3])?.to_machine_usize(this)?; - let res = this.realloc(ptr, size, MiriMemoryKind::WinHeap)?; - this.write_scalar(res, dest)?; - } - - "SetLastError" => { - this.set_last_error(this.read_scalar(args[0])?.not_undef()?)?; - } - "GetLastError" => { - let last_error = this.get_last_error()?; - this.write_scalar(last_error, dest)?; - } - - "AddVectoredExceptionHandler" => { - // Any non zero value works for the stdlib. This is just used for stack overflows anyway. - this.write_scalar(Scalar::from_int(1, dest.layout.size), dest)?; - } - - | "InitializeCriticalSection" - | "EnterCriticalSection" - | "LeaveCriticalSection" - | "DeleteCriticalSection" - => { - // Nothing to do, not even a return value. - } - - | "GetModuleHandleW" - | "GetProcAddress" - | "TryEnterCriticalSection" - | "GetConsoleScreenBufferInfo" - | "SetConsoleTextAttribute" - => { - // Pretend these do not exist / nothing happened, by returning zero. - this.write_null(dest)?; - } - - "GetSystemInfo" => { - let system_info = this.deref_operand(args[0])?; - // Initialize with `0`. - this.memory.write_bytes( - system_info.ptr, - iter::repeat(0u8).take(system_info.layout.size.bytes() as usize), - )?; - // Set number of processors. - let dword_size = Size::from_bytes(4); - let num_cpus = this.mplace_field(system_info, 6)?; - this.write_scalar(Scalar::from_int(NUM_CPUS, dword_size), num_cpus.into())?; - } - - "TlsAlloc" => { - // This just creates a key; Windows does not natively support TLS destructors. - - // Create key and return it. - let key = this.machine.tls.create_tls_key(None) 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) - { - throw_unsup!(OutOfTls); - } - this.write_scalar(Scalar::from_uint(key, dest.layout.size), dest)?; - } - "TlsGetValue" => { - let key = this.read_scalar(args[0])?.to_u32()? as u128; - let ptr = this.machine.tls.load_tls(key, tcx)?; - this.write_scalar(ptr, dest)?; - } - "TlsSetValue" => { - let key = this.read_scalar(args[0])?.to_u32()? as u128; - let new_ptr = this.read_scalar(args[1])?.not_undef()?; - this.machine.tls.store_tls(key, this.test_null(new_ptr)?)?; - - // Return success (`1`). - this.write_scalar(Scalar::from_int(1, dest.layout.size), dest)?; - } - "GetStdHandle" => { - let which = this.read_scalar(args[0])?.to_i32()?; - // We just make this the identity function, so we know later in `WriteFile` - // which one it is. - this.write_scalar(Scalar::from_int(which, this.pointer_size()), dest)?; - } - "GetConsoleMode" => { - // Everything is a pipe. - this.write_null(dest)?; - } - "GetCommandLineW" => { - this.write_scalar( - this.machine.cmd_line.expect("machine must be initialized"), - dest, - )?; - } - // The actual name of 'RtlGenRandom' - "SystemFunction036" => { - let ptr = this.read_scalar(args[0])?.not_undef()?; - let len = this.read_scalar(args[1])?.to_u32()?; - this.gen_random(ptr, len as usize)?; - this.write_scalar(Scalar::from_bool(true), dest)?; - } - _ => match this.tcx.sess.target.target.target_os.to_lowercase().as_str() { "linux" | "macos" => posix::EvalContextExt::emulate_foreign_item_by_name(this, link_name, args, dest)?, "windows" => windows::EvalContextExt::emulate_foreign_item_by_name(this, link_name, args, dest)?, diff --git a/src/shims/foreign_items/posix/linux.rs b/src/shims/foreign_items/posix/linux.rs index bc61aea18c737..31a0a815891ec 100644 --- a/src/shims/foreign_items/posix/linux.rs +++ b/src/shims/foreign_items/posix/linux.rs @@ -38,6 +38,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; } + "pthread_getattr_np" => { + this.write_null(dest)?; + } _ => throw_unsup_format!("can't call foreign function: {}", link_name), }; diff --git a/src/shims/foreign_items/posix/macos.rs b/src/shims/foreign_items/posix/macos.rs index e0ac92868a2c7..8ed793b6c03c1 100644 --- a/src/shims/foreign_items/posix/macos.rs +++ b/src/shims/foreign_items/posix/macos.rs @@ -53,6 +53,35 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; } + // macOS API stubs. + "pthread_attr_get_np" => { + this.write_null(dest)?; + } + "pthread_get_stackaddr_np" => { + let stack_addr = Scalar::from_uint(STACK_ADDR, dest.layout.size); + this.write_scalar(stack_addr, dest)?; + } + "pthread_get_stacksize_np" => { + let stack_size = Scalar::from_uint(STACK_SIZE, dest.layout.size); + this.write_scalar(stack_size, dest)?; + } + "_tlv_atexit" => { + // FIXME: register the destructor. + } + "_NSGetArgc" => { + this.write_scalar(this.machine.argc.expect("machine must be initialized"), dest)?; + } + "_NSGetArgv" => { + this.write_scalar(this.machine.argv.expect("machine must be initialized"), dest)?; + } + "SecRandomCopyBytes" => { + let len = this.read_scalar(args[1])?.to_machine_usize(this)?; + let ptr = this.read_scalar(args[2])?.not_undef()?; + this.gen_random(ptr, len as usize)?; + this.write_null(dest)?; + } + + _ => throw_unsup_format!("can't call foreign function: {}", link_name), }; diff --git a/src/shims/foreign_items/windows.rs b/src/shims/foreign_items/windows.rs index 23aa8ae7deb34..e16a89a126fd1 100644 --- a/src/shims/foreign_items/windows.rs +++ b/src/shims/foreign_items/windows.rs @@ -1,5 +1,6 @@ use crate::*; use rustc::ty::layout::Size; +use std::iter; impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { @@ -10,6 +11,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx dest: PlaceTy<'tcx, Tag>, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); + let tcx = &{ this.tcx.tcx }; match link_name { // Environment related shims @@ -66,6 +68,132 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx dest, )?; } + // Windows API stubs. + // HANDLE = isize + // DWORD = ULONG = u32 + // BOOL = i32 + "GetProcessHeap" => { + // Just fake a HANDLE + this.write_scalar(Scalar::from_int(1, this.pointer_size()), dest)?; + } + "HeapAlloc" => { + let _handle = this.read_scalar(args[0])?.to_machine_isize(this)?; + let flags = this.read_scalar(args[1])?.to_u32()?; + let size = this.read_scalar(args[2])?.to_machine_usize(this)?; + let zero_init = (flags & 0x00000008) != 0; // HEAP_ZERO_MEMORY + let res = this.malloc(size, zero_init, MiriMemoryKind::WinHeap); + this.write_scalar(res, dest)?; + } + "HeapFree" => { + let _handle = this.read_scalar(args[0])?.to_machine_isize(this)?; + let _flags = this.read_scalar(args[1])?.to_u32()?; + let ptr = this.read_scalar(args[2])?.not_undef()?; + this.free(ptr, MiriMemoryKind::WinHeap)?; + this.write_scalar(Scalar::from_int(1, Size::from_bytes(4)), dest)?; + } + "HeapReAlloc" => { + let _handle = this.read_scalar(args[0])?.to_machine_isize(this)?; + let _flags = this.read_scalar(args[1])?.to_u32()?; + let ptr = this.read_scalar(args[2])?.not_undef()?; + let size = this.read_scalar(args[3])?.to_machine_usize(this)?; + let res = this.realloc(ptr, size, MiriMemoryKind::WinHeap)?; + this.write_scalar(res, dest)?; + } + + "SetLastError" => { + this.set_last_error(this.read_scalar(args[0])?.not_undef()?)?; + } + "GetLastError" => { + let last_error = this.get_last_error()?; + this.write_scalar(last_error, dest)?; + } + + "AddVectoredExceptionHandler" => { + // Any non zero value works for the stdlib. This is just used for stack overflows anyway. + this.write_scalar(Scalar::from_int(1, dest.layout.size), dest)?; + } + + | "InitializeCriticalSection" + | "EnterCriticalSection" + | "LeaveCriticalSection" + | "DeleteCriticalSection" + => { + // Nothing to do, not even a return value. + } + + | "GetModuleHandleW" + | "GetProcAddress" + | "TryEnterCriticalSection" + | "GetConsoleScreenBufferInfo" + | "SetConsoleTextAttribute" + => { + // Pretend these do not exist / nothing happened, by returning zero. + this.write_null(dest)?; + } + + "GetSystemInfo" => { + let system_info = this.deref_operand(args[0])?; + // Initialize with `0`. + this.memory.write_bytes( + system_info.ptr, + iter::repeat(0u8).take(system_info.layout.size.bytes() as usize), + )?; + // Set number of processors. + let dword_size = Size::from_bytes(4); + let num_cpus = this.mplace_field(system_info, 6)?; + this.write_scalar(Scalar::from_int(NUM_CPUS, dword_size), num_cpus.into())?; + } + + "TlsAlloc" => { + // This just creates a key; Windows does not natively support TLS destructors. + + // Create key and return it. + let key = this.machine.tls.create_tls_key(None) 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) + { + throw_unsup!(OutOfTls); + } + this.write_scalar(Scalar::from_uint(key, dest.layout.size), dest)?; + } + "TlsGetValue" => { + let key = this.read_scalar(args[0])?.to_u32()? as u128; + let ptr = this.machine.tls.load_tls(key, tcx)?; + this.write_scalar(ptr, dest)?; + } + "TlsSetValue" => { + let key = this.read_scalar(args[0])?.to_u32()? as u128; + let new_ptr = this.read_scalar(args[1])?.not_undef()?; + this.machine.tls.store_tls(key, this.test_null(new_ptr)?)?; + + // Return success (`1`). + this.write_scalar(Scalar::from_int(1, dest.layout.size), dest)?; + } + "GetStdHandle" => { + let which = this.read_scalar(args[0])?.to_i32()?; + // We just make this the identity function, so we know later in `WriteFile` + // which one it is. + this.write_scalar(Scalar::from_int(which, this.pointer_size()), dest)?; + } + "GetConsoleMode" => { + // Everything is a pipe. + this.write_null(dest)?; + } + "GetCommandLineW" => { + this.write_scalar( + this.machine.cmd_line.expect("machine must be initialized"), + dest, + )?; + } + // The actual name of 'RtlGenRandom' + "SystemFunction036" => { + let ptr = this.read_scalar(args[0])?.not_undef()?; + let len = this.read_scalar(args[1])?.to_u32()?; + this.gen_random(ptr, len as usize)?; + this.write_scalar(Scalar::from_bool(true), dest)?; + } _ => throw_unsup_format!("can't call foreign function: {}", link_name), } From c233c4ad9c84e138bc05db4fd5953239a9b0cd0a Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Sat, 8 Feb 2020 11:58:42 -0500 Subject: [PATCH 1520/3747] migrate more functions --- src/shims/foreign_items.rs | 110 ------------------------- src/shims/foreign_items/posix.rs | 80 +++++++++++++++++- src/shims/foreign_items/posix/linux.rs | 34 ++++++++ src/shims/foreign_items/posix/macos.rs | 23 ++++++ 4 files changed, 136 insertions(+), 111 deletions(-) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index f8a61a7c5a12a..6b4ce45f752fe 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -208,33 +208,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let res = this.malloc(size, /*zero_init:*/ true, MiriMemoryKind::C); this.write_scalar(res, dest)?; } - "posix_memalign" => { - let ret = this.deref_operand(args[0])?; - let align = this.read_scalar(args[1])?.to_machine_usize(this)?; - let size = this.read_scalar(args[2])?.to_machine_usize(this)?; - // Align must be power of 2, and also at least ptr-sized (POSIX rules). - if !align.is_power_of_two() { - throw_unsup!(HeapAllocNonPowerOfTwoAlignment(align)); - } - if align < this.pointer_size().bytes() { - throw_ub_format!( - "posix_memalign: alignment must be at least the size of a pointer, but is {}", - align, - ); - } - - if size == 0 { - this.write_null(ret.into())?; - } else { - let ptr = this.memory.allocate( - Size::from_bytes(size), - Align::from_bytes(align).unwrap(), - MiriMemoryKind::C.into(), - ); - this.write_scalar(ptr, ret.into())?; - } - this.write_null(dest)?; - } "free" => { let ptr = this.read_scalar(args[0])?.not_undef()?; this.free(ptr, MiriMemoryKind::C)?; @@ -319,53 +292,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(new_ptr, dest)?; } - "syscall" => { - let sys_getrandom = this - .eval_path_scalar(&["libc", "SYS_getrandom"])? - .expect("Failed to get libc::SYS_getrandom") - .to_machine_usize(this)?; - - let sys_statx = this - .eval_path_scalar(&["libc", "SYS_statx"])? - .expect("Failed to get libc::SYS_statx") - .to_machine_usize(this)?; - - match this.read_scalar(args[0])?.to_machine_usize(this)? { - // `libc::syscall(NR_GETRANDOM, buf.as_mut_ptr(), buf.len(), GRND_NONBLOCK)` - // is called if a `HashMap` is created the regular way (e.g. HashMap). - id if id == sys_getrandom => { - // The first argument is the syscall id, - // so skip over it. - linux_getrandom(this, &args[1..], dest)?; - } - id if id == sys_statx => { - // The first argument is the syscall id, - // so skip over it. - let result = this.statx(args[1], args[2], args[3], args[4], args[5])?; - this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; - } - id => throw_unsup_format!("miri does not support syscall ID {}", id), - } - } - - "getrandom" => { - linux_getrandom(this, args, dest)?; - } - - "dlsym" => { - let _handle = this.read_scalar(args[0])?; - let symbol = this.read_scalar(args[1])?.not_undef()?; - let symbol_name = this.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); - if let Some(dlsym) = Dlsym::from_str(symbol_name)? { - let ptr = this.memory.create_fn_alloc(FnVal::Other(dlsym)); - this.write_scalar(Scalar::from(ptr), dest)?; - } else { - this.write_null(dest)?; - } - } - "memcmp" => { let left = this.read_scalar(args[0])?.not_undef()?; let right = this.read_scalar(args[1])?.not_undef()?; @@ -386,24 +312,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_int(result, Size::from_bits(32)), dest)?; } - "memrchr" => { - let ptr = this.read_scalar(args[0])?.not_undef()?; - let val = this.read_scalar(args[1])?.to_i32()? as u8; - let num = this.read_scalar(args[2])?.to_machine_usize(this)?; - if let Some(idx) = this - .memory - .read_bytes(ptr, Size::from_bytes(num))? - .iter() - .rev() - .position(|&c| c == val) - { - let new_ptr = ptr.ptr_offset(Size::from_bytes(num - idx as u64 - 1), this)?; - this.write_scalar(new_ptr, dest)?; - } else { - this.write_null(dest)?; - } - } - "memchr" => { let ptr = this.read_scalar(args[0])?.not_undef()?; let val = this.read_scalar(args[1])?.to_i32()? as u8; @@ -728,21 +636,3 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx return Ok(None); } } - -// Shims the linux 'getrandom()' syscall. -fn linux_getrandom<'tcx>( - this: &mut MiriEvalContext<'_, 'tcx>, - args: &[OpTy<'tcx, Tag>], - dest: PlaceTy<'tcx, Tag>, -) -> InterpResult<'tcx> { - let ptr = this.read_scalar(args[0])?.not_undef()?; - let len = this.read_scalar(args[1])?.to_machine_usize(this)?; - - // The only supported flags are GRND_RANDOM and GRND_NONBLOCK, - // neither of which have any effect on our current PRNG. - let _flags = this.read_scalar(args[2])?.to_i32()?; - - this.gen_random(ptr, len as usize)?; - this.write_scalar(Scalar::from_uint(len, dest.layout.size), dest)?; - Ok(()) -} diff --git a/src/shims/foreign_items/posix.rs b/src/shims/foreign_items/posix.rs index ecdec1fb165cc..f738bdd7e6e05 100644 --- a/src/shims/foreign_items/posix.rs +++ b/src/shims/foreign_items/posix.rs @@ -2,7 +2,7 @@ mod linux; mod macos; use crate::*; -use rustc::ty::layout::Size; +use rustc::ty::layout::{Align, Size}; impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { @@ -97,6 +97,66 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; } + "posix_memalign" => { + let ret = this.deref_operand(args[0])?; + let align = this.read_scalar(args[1])?.to_machine_usize(this)?; + let size = this.read_scalar(args[2])?.to_machine_usize(this)?; + // Align must be power of 2, and also at least ptr-sized (POSIX rules). + if !align.is_power_of_two() { + throw_unsup!(HeapAllocNonPowerOfTwoAlignment(align)); + } + if align < this.pointer_size().bytes() { + throw_ub_format!( + "posix_memalign: alignment must be at least the size of a pointer, but is {}", + align, + ); + } + + if size == 0 { + this.write_null(ret.into())?; + } else { + let ptr = this.memory.allocate( + Size::from_bytes(size), + Align::from_bytes(align).unwrap(), + MiriMemoryKind::C.into(), + ); + this.write_scalar(ptr, ret.into())?; + } + this.write_null(dest)?; + } + + "dlsym" => { + let _handle = this.read_scalar(args[0])?; + let symbol = this.read_scalar(args[1])?.not_undef()?; + let symbol_name = this.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); + if let Some(dlsym) = Dlsym::from_str(symbol_name)? { + let ptr = this.memory.create_fn_alloc(FnVal::Other(dlsym)); + this.write_scalar(Scalar::from(ptr), dest)?; + } else { + this.write_null(dest)?; + } + } + + "memrchr" => { + let ptr = this.read_scalar(args[0])?.not_undef()?; + let val = this.read_scalar(args[1])?.to_i32()? as u8; + let num = this.read_scalar(args[2])?.to_machine_usize(this)?; + if let Some(idx) = this + .memory + .read_bytes(ptr, Size::from_bytes(num))? + .iter() + .rev() + .position(|&c| c == val) + { + let new_ptr = ptr.ptr_offset(Size::from_bytes(num - idx as u64 - 1), this)?; + this.write_scalar(new_ptr, dest)?; + } else { + this.write_null(dest)?; + } + } + _ => { match this.tcx.sess.target.target.target_os.to_lowercase().as_str() { "linux" => linux::EvalContextExt::emulate_foreign_item_by_name(this, link_name, args, dest)?, @@ -109,3 +169,21 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(()) } } + +// Shims the posix 'getrandom()' syscall. +fn getrandom<'tcx>( + this: &mut MiriEvalContext<'_, 'tcx>, + args: &[OpTy<'tcx, Tag>], + dest: PlaceTy<'tcx, Tag>, +) -> InterpResult<'tcx> { + let ptr = this.read_scalar(args[0])?.not_undef()?; + let len = this.read_scalar(args[1])?.to_machine_usize(this)?; + + // The only supported flags are GRND_RANDOM and GRND_NONBLOCK, + // neither of which have any effect on our current PRNG. + let _flags = this.read_scalar(args[2])?.to_i32()?; + + this.gen_random(ptr, len as usize)?; + this.write_scalar(Scalar::from_uint(len, dest.layout.size), dest)?; + Ok(()) +} diff --git a/src/shims/foreign_items/posix/linux.rs b/src/shims/foreign_items/posix/linux.rs index 31a0a815891ec..8d928b60ecbda 100644 --- a/src/shims/foreign_items/posix/linux.rs +++ b/src/shims/foreign_items/posix/linux.rs @@ -41,6 +41,40 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "pthread_getattr_np" => { this.write_null(dest)?; } + + "syscall" => { + let sys_getrandom = this + .eval_path_scalar(&["libc", "SYS_getrandom"])? + .expect("Failed to get libc::SYS_getrandom") + .to_machine_usize(this)?; + + let sys_statx = this + .eval_path_scalar(&["libc", "SYS_statx"])? + .expect("Failed to get libc::SYS_statx") + .to_machine_usize(this)?; + + match this.read_scalar(args[0])?.to_machine_usize(this)? { + // `libc::syscall(NR_GETRANDOM, buf.as_mut_ptr(), buf.len(), GRND_NONBLOCK)` + // is called if a `HashMap` is created the regular way (e.g. HashMap). + id if id == sys_getrandom => { + // The first argument is the syscall id, + // so skip over it. + super::getrandom(this, &args[1..], dest)?; + } + id if id == sys_statx => { + // The first argument is the syscall id, + // so skip over it. + let result = this.statx(args[1], args[2], args[3], args[4], args[5])?; + this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + } + id => throw_unsup_format!("miri does not support syscall ID {}", id), + } + } + + "getrandom" => { + super::getrandom(this, args, dest)?; + } + _ => throw_unsup_format!("can't call foreign function: {}", link_name), }; diff --git a/src/shims/foreign_items/posix/macos.rs b/src/shims/foreign_items/posix/macos.rs index 8ed793b6c03c1..c4bfb98562dbd 100644 --- a/src/shims/foreign_items/posix/macos.rs +++ b/src/shims/foreign_items/posix/macos.rs @@ -57,23 +57,29 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "pthread_attr_get_np" => { this.write_null(dest)?; } + "pthread_get_stackaddr_np" => { let stack_addr = Scalar::from_uint(STACK_ADDR, dest.layout.size); this.write_scalar(stack_addr, dest)?; } + "pthread_get_stacksize_np" => { let stack_size = Scalar::from_uint(STACK_SIZE, dest.layout.size); this.write_scalar(stack_size, dest)?; } + "_tlv_atexit" => { // FIXME: register the destructor. } + "_NSGetArgc" => { this.write_scalar(this.machine.argc.expect("machine must be initialized"), dest)?; } + "_NSGetArgv" => { this.write_scalar(this.machine.argv.expect("machine must be initialized"), dest)?; } + "SecRandomCopyBytes" => { let len = this.read_scalar(args[1])?.to_machine_usize(this)?; let ptr = this.read_scalar(args[2])?.not_undef()?; @@ -81,6 +87,23 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_null(dest)?; } + "syscall" => { + let sys_getrandom = this + .eval_path_scalar(&["libc", "SYS_getrandom"])? + .expect("Failed to get libc::SYS_getrandom") + .to_machine_usize(this)?; + + match this.read_scalar(args[0])?.to_machine_usize(this)? { + // `libc::syscall(NR_GETRANDOM, buf.as_mut_ptr(), buf.len(), GRND_NONBLOCK)` + // is called if a `HashMap` is created the regular way (e.g. HashMap). + id if id == sys_getrandom => { + // The first argument is the syscall id, + // so skip over it. + super::getrandom(this, &args[1..], dest)?; + } + id => throw_unsup_format!("miri does not support syscall ID {}", id), + } + } _ => throw_unsup_format!("can't call foreign function: {}", link_name), }; From 39a78f0b2490cd2e0b2b2432209d6a230ef97979 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 16 Feb 2020 13:47:31 +0100 Subject: [PATCH 1521/3747] make sure assertions and debug-assertions also panic (and can be caught) --- tests/run-pass/panic/catch_panic.rs | 4 ++++ tests/run-pass/panic/catch_panic.stderr | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/tests/run-pass/panic/catch_panic.rs b/tests/run-pass/panic/catch_panic.rs index 722da68b70b28..84d4e56431b70 100644 --- a/tests/run-pass/panic/catch_panic.rs +++ b/tests/run-pass/panic/catch_panic.rs @@ -61,6 +61,10 @@ fn main() { test(|_old_val| { let _val = [0, 1, 2][4]; loop {} }); test(|_old_val| { let _val = 1/0; loop {} }); + // Assertion and debug assertion + test(|_old_val| { assert!(false); loop {} }); + test(|_old_val| { debug_assert!(false); loop {} }); + // Cleanup: reset to default hook. drop(std::panic::take_hook()); diff --git a/tests/run-pass/panic/catch_panic.stderr b/tests/run-pass/panic/catch_panic.stderr index fd9a2f14ec3b3..d4837f555494a 100644 --- a/tests/run-pass/panic/catch_panic.stderr +++ b/tests/run-pass/panic/catch_panic.stderr @@ -16,4 +16,8 @@ thread 'main' panicked at 'index out of bounds: the len is 3 but the index is 4' Caught panic message (String): index out of bounds: the len is 3 but the index is 4 thread 'main' panicked at 'attempt to divide by zero', $DIR/catch_panic.rs:62:34 Caught panic message (String): attempt to divide by zero +thread 'main' panicked at 'assertion failed: false', $DIR/catch_panic.rs:65:23 +Caught panic message (&str): assertion failed: false +thread 'main' panicked at 'assertion failed: false', $DIR/catch_panic.rs:66:23 +Caught panic message (&str): assertion failed: false Success! From 6ff5b3fcf94e5d0e58a9b2f7432b1f564bae9f46 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 16 Feb 2020 13:55:51 +0100 Subject: [PATCH 1522/3747] make sure we also trigger debug assertions in libstd --- src/lib.rs | 2 +- tests/run-pass/panic/catch_panic.rs | 3 ++- tests/run-pass/panic/catch_panic.stderr | 2 ++ 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 880a14b98c80e..c34b90877d9d1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -62,5 +62,5 @@ pub use crate::stacked_borrows::{ /// Insert rustc arguments at the beginning of the argument list that Miri wants to be /// set per default, for maximal validation power. pub fn miri_default_args() -> &'static [&'static str] { - &["-Zalways-encode-mir", "-Zmir-emit-retag", "-Zmir-opt-level=0", "--cfg=miri"] + &["-Zalways-encode-mir", "-Zmir-emit-retag", "-Zmir-opt-level=0", "--cfg=miri", "-Cdebug-assertions=on"] } diff --git a/tests/run-pass/panic/catch_panic.rs b/tests/run-pass/panic/catch_panic.rs index 84d4e56431b70..4d4206923a5ef 100644 --- a/tests/run-pass/panic/catch_panic.rs +++ b/tests/run-pass/panic/catch_panic.rs @@ -1,4 +1,5 @@ // ignore-windows: Unwind panicking does not currently work on Windows +// normalize-stderr-test "[^ ]*libcore/macros/mod.rs[0-9:]*" -> "$$LOC" #![feature(never_type)] #![allow(const_err)] use std::panic::{catch_unwind, AssertUnwindSafe}; @@ -11,7 +12,6 @@ thread_local! { } struct DropTester; - impl Drop for DropTester { fn drop(&mut self) { DROPPED.with(|c| { @@ -64,6 +64,7 @@ fn main() { // Assertion and debug assertion test(|_old_val| { assert!(false); loop {} }); test(|_old_val| { debug_assert!(false); loop {} }); + test(|_old_val| { unsafe { (1 as *const i32).read() }; loop {} }); // trigger debug-assertion in libstd // Cleanup: reset to default hook. drop(std::panic::take_hook()); diff --git a/tests/run-pass/panic/catch_panic.stderr b/tests/run-pass/panic/catch_panic.stderr index d4837f555494a..636179beeade8 100644 --- a/tests/run-pass/panic/catch_panic.stderr +++ b/tests/run-pass/panic/catch_panic.stderr @@ -20,4 +20,6 @@ thread 'main' panicked at 'assertion failed: false', $DIR/catch_panic.rs:65:23 Caught panic message (&str): assertion failed: false thread 'main' panicked at 'assertion failed: false', $DIR/catch_panic.rs:66:23 Caught panic message (&str): assertion failed: false +thread 'main' panicked at 'attempt to copy from unaligned or null pointer', $LOC +Caught panic message (String): attempt to copy from unaligned or null pointer Success! From 8acf52b3ca5ddc464d88ea6913d66706a3b70d4b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 16 Feb 2020 14:01:00 +0100 Subject: [PATCH 1523/3747] fix compile-fail tests to avoid libstd debug assertions --- tests/compile-fail/copy_null.rs | 8 +++++++- tests/compile-fail/copy_overlapping.rs | 10 +++++++--- tests/compile-fail/copy_unaligned.rs | 8 +++++++- 3 files changed, 21 insertions(+), 5 deletions(-) diff --git a/tests/compile-fail/copy_null.rs b/tests/compile-fail/copy_null.rs index 08391b12ae1bc..ce2fbe170e45d 100644 --- a/tests/compile-fail/copy_null.rs +++ b/tests/compile-fail/copy_null.rs @@ -1,8 +1,14 @@ //error-pattern: invalid use of NULL pointer +#![feature(intrinsics)] + +// Directly call intrinsic to avoid debug assertions in libstd +extern "rust-intrinsic" { + fn copy_nonoverlapping(src: *const T, dst: *mut T, count: usize); +} fn main() { let mut data = [0u16; 4]; let ptr = &mut data[0] as *mut u16; // Even copying 0 elements from NULL should error. - unsafe { ptr.copy_from(std::ptr::null(), 0); } + unsafe { copy_nonoverlapping(std::ptr::null(), ptr, 0); } } diff --git a/tests/compile-fail/copy_overlapping.rs b/tests/compile-fail/copy_overlapping.rs index 748bccff5d3ac..76e1e20d2177f 100644 --- a/tests/compile-fail/copy_overlapping.rs +++ b/tests/compile-fail/copy_overlapping.rs @@ -1,12 +1,16 @@ -#![feature(core_intrinsics)] - //error-pattern: copy_nonoverlapping called on overlapping ranges +#![feature(intrinsics)] + +// Directly call intrinsic to avoid debug assertions in libstd +extern "rust-intrinsic" { + fn copy_nonoverlapping(src: *const T, dst: *mut T, count: usize); +} fn main() { let mut data = [0u8; 16]; unsafe { let a = data.as_mut_ptr(); let b = a.wrapping_offset(1) as *mut _; - std::ptr::copy_nonoverlapping(a, b, 2); + copy_nonoverlapping(a, b, 2); } } diff --git a/tests/compile-fail/copy_unaligned.rs b/tests/compile-fail/copy_unaligned.rs index e1f243210ade0..1a2692978f797 100644 --- a/tests/compile-fail/copy_unaligned.rs +++ b/tests/compile-fail/copy_unaligned.rs @@ -1,8 +1,14 @@ //error-pattern: tried to access memory with alignment 1, but alignment 2 is required +#![feature(intrinsics)] + +// Directly call intrinsic to avoid debug assertions in libstd +extern "rust-intrinsic" { + fn copy_nonoverlapping(src: *const T, dst: *mut T, count: usize); +} fn main() { let mut data = [0u16; 8]; let ptr = (&mut data[0] as *mut u16 as *mut u8).wrapping_add(1) as *mut u16; // Even copying 0 elements to something unaligned should error - unsafe { ptr.copy_from(&data[5], 0); } + unsafe { copy_nonoverlapping(&data[5], ptr, 0); } } From fda6104ee9bd7dee1f50a9ca2891ca27169040e0 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 16 Feb 2020 12:37:15 +0100 Subject: [PATCH 1524/3747] update README --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index cf18e6a0670bc..b5e54e64bc408 100644 --- a/README.md +++ b/README.md @@ -147,8 +147,8 @@ Several `-Z` flags are relevant for Miri: * `-Zmiri-seed=` is a custom `-Z` flag added by Miri. It configures the seed of the RNG that Miri uses to resolve non-determinism. This RNG is used - to pick base addresses for allocations, and when the interpreted program - requests system entropy. The default seed is 0. + to pick base addresses for allocations. When isolation is enabled (the default), + this is also used to emulate system entropy. The default seed is 0. **NOTE**: This entropy is not good enough for cryptographic use! Do not generate secret keys in Miri or perform other kinds of cryptographic operations that rely on proper random numbers. @@ -157,8 +157,8 @@ Several `-Z` flags are relevant for Miri: useful for debugging. It means Miri will miss bugs in your program. However, this can also help to make Miri run faster. * `-Zmiri-disable-isolation` disables host host isolation. As a consequence, - the program has access to host resources such as environment variables and - randomness (and, eventually, file systems and more). + the program has access to host resources such as environment variables, file + systems, and randomness. * `-Zmiri-ignore-leaks` disables the memory leak checker. * `-Zmiri-env-exclude=` keeps the `var` environment variable isolated from the host. Can be used multiple times to exclude several variables. The `TERM` From e449dccd3764b8adb1be4787b345eae9b0c7306e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 16 Feb 2020 12:38:00 +0100 Subject: [PATCH 1525/3747] clarify caveats --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index b5e54e64bc408..1f008e735ec2c 100644 --- a/README.md +++ b/README.md @@ -14,13 +14,13 @@ for example: * Not sufficiently aligned memory accesses and references * Violation of *some* basic type invariants (a `bool` that is not 0 or 1, for example, or an invalid enum discriminant) -* WIP: Violations of the rules governing aliasing for reference types +* **Experimental**: Violations of the rules governing aliasing for reference types Miri has already discovered some [real-world bugs](#bugs-found-by-miri). If you found a bug with Miri, we'd appreciate if you tell us and we'll add it to the list! -Be aware that Miri will not catch all cases of undefined behavior in your +Be aware that Miri will **not catch all cases of undefined behavior** in your program, and cannot run all programs: * There are still plenty of open questions around the basic invariants for some From 085874d1ffd224dfe39a1aaa82e4f286b8614c91 Mon Sep 17 00:00:00 2001 From: David Cook Date: Sun, 26 Jan 2020 11:19:06 -0600 Subject: [PATCH 1526/3747] Add F_DUPFD/F_DUPFD_CLOEXEC to fcntl shim --- src/shims/fs.rs | 21 +++++++++++++++++++-- tests/run-pass/fs.rs | 2 ++ 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/src/shims/fs.rs b/src/shims/fs.rs index 2ae215e7204f2..07390be2c8bb6 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -28,7 +28,7 @@ impl Default for FileHandler { FileHandler { handles: Default::default(), // 0, 1 and 2 are reserved for stdin, stdout and stderr. - low: 3, + low: 2, } } } @@ -120,7 +120,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx &mut self, fd_op: OpTy<'tcx, Tag>, cmd_op: OpTy<'tcx, Tag>, - _arg1_op: Option>, + arg_op: Option>, ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); @@ -139,6 +139,23 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } else { this.handle_not_found() } + } else if cmd == this.eval_libc_i32("F_DUPFD")? || cmd == this.eval_libc_i32("F_DUPFD_CLOEXEC")? { + let arg = match arg_op { + Some(arg_op) => this.read_scalar(arg_op)?.to_i32()?, + None => throw_unsup_format!("fcntl with command F_DUPFD or F_DUPFD_CLOEXEC requires a third argument"), + }; + let fh = &mut this.machine.file_handler; + let (file_result, writable) = match fh.handles.get(&fd) { + Some(original) => (original.file.try_clone(), original.writable), + None => return this.handle_not_found(), + }; + let fd_result = file_result.map(|duplicated| { + let new_fd = std::cmp::max(fh.low + 1, arg); + fh.low = new_fd; + fh.handles.insert(fh.low, FileHandle { file: duplicated, writable }).unwrap_none(); + new_fd + }); + this.try_unwrap_io_result(fd_result) } else { throw_unsup_format!("The {:#x} command is not supported for `fcntl`)", cmd); } diff --git a/tests/run-pass/fs.rs b/tests/run-pass/fs.rs index 71c6e854f7c57..632ed13f2eace 100644 --- a/tests/run-pass/fs.rs +++ b/tests/run-pass/fs.rs @@ -41,6 +41,8 @@ fn main() { // Reading until EOF should get the whole text. file.read_to_end(&mut contents).unwrap(); assert_eq!(bytes, contents.as_slice()); + // Cloning a file should be successful + file.try_clone().unwrap(); // Test that seeking to the beginning and reading until EOF gets the text again. file.seek(SeekFrom::Start(0)).unwrap(); From 3aff8038685e60c453182ec169babedeab19c606 Mon Sep 17 00:00:00 2001 From: David Cook Date: Tue, 28 Jan 2020 23:18:09 -0600 Subject: [PATCH 1527/3747] Add comment --- src/shims/fs.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/shims/fs.rs b/src/shims/fs.rs index 07390be2c8bb6..b766dd6de47aa 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -140,6 +140,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.handle_not_found() } } else if cmd == this.eval_libc_i32("F_DUPFD")? || cmd == this.eval_libc_i32("F_DUPFD_CLOEXEC")? { + // Note that we always assume the FD_CLOEXEC flag is set for every open file, in part + // because exec() isn't supported. The F_DUPFD and F_DUPFD_CLOEXEC commands only + // differ in whether the FD_CLOEXEC flag is pre-set on the duplicated file descriptor, + // thus they can share the same implementation here. let arg = match arg_op { Some(arg_op) => this.read_scalar(arg_op)?.to_i32()?, None => throw_unsup_format!("fcntl with command F_DUPFD or F_DUPFD_CLOEXEC requires a third argument"), From 1de9d107cf0e6f922fc017606a675b6a727e2bd6 Mon Sep 17 00:00:00 2001 From: David Cook Date: Thu, 30 Jan 2020 18:31:34 -0600 Subject: [PATCH 1528/3747] Style fixes --- src/shims/fs.rs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/shims/fs.rs b/src/shims/fs.rs index b766dd6de47aa..d17ef79f0eed3 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -142,12 +142,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } else if cmd == this.eval_libc_i32("F_DUPFD")? || cmd == this.eval_libc_i32("F_DUPFD_CLOEXEC")? { // Note that we always assume the FD_CLOEXEC flag is set for every open file, in part // because exec() isn't supported. The F_DUPFD and F_DUPFD_CLOEXEC commands only - // differ in whether the FD_CLOEXEC flag is pre-set on the duplicated file descriptor, + // differ in whether the FD_CLOEXEC flag is pre-set on the new file descriptor, // thus they can share the same implementation here. - let arg = match arg_op { - Some(arg_op) => this.read_scalar(arg_op)?.to_i32()?, - None => throw_unsup_format!("fcntl with command F_DUPFD or F_DUPFD_CLOEXEC requires a third argument"), - }; + let arg_op = arg_op + .ok_or_else(|| err_unsup_format!("fcntl with command F_DUPFD or F_DUPFD_CLOEXEC requires a third argument"))?; + let arg = this.read_scalar(arg_op)?.to_i32()?; let fh = &mut this.machine.file_handler; let (file_result, writable) = match fh.handles.get(&fd) { Some(original) => (original.file.try_clone(), original.writable), From eda35e153bc6f323d0707dff89a99d0034a1f39d Mon Sep 17 00:00:00 2001 From: David Cook Date: Thu, 30 Jan 2020 18:38:30 -0600 Subject: [PATCH 1529/3747] Add methods to FileHandler --- src/shims/fs.rs | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/src/shims/fs.rs b/src/shims/fs.rs index d17ef79f0eed3..792996f678d4e 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -23,6 +23,17 @@ pub struct FileHandler { low: i32, } +impl FileHandler { + fn next_fd(&self) -> i32 { + self.low + 1 + } + + fn register_fd(&mut self, fd: i32, handle: FileHandle) { + self.low = fd; + self.handles.insert(fd, handle).unwrap_none(); + } +} + impl Default for FileHandler { fn default() -> Self { FileHandler { @@ -107,10 +118,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let path = this.read_os_str_from_c_str(this.read_scalar(path_op)?.not_undef()?)?; let fd = options.open(&path).map(|file| { - let mut fh = &mut this.machine.file_handler; - fh.low += 1; - fh.handles.insert(fh.low, FileHandle { file, writable }).unwrap_none(); - fh.low + let fh = &mut this.machine.file_handler; + let fd = fh.next_fd(); + fh.register_fd(fd, FileHandle { file, writable }); + fd }); this.try_unwrap_io_result(fd) @@ -153,9 +164,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx None => return this.handle_not_found(), }; let fd_result = file_result.map(|duplicated| { - let new_fd = std::cmp::max(fh.low + 1, arg); - fh.low = new_fd; - fh.handles.insert(fh.low, FileHandle { file: duplicated, writable }).unwrap_none(); + let new_fd = std::cmp::max(fh.next_fd(), arg); + fh.register_fd(new_fd, FileHandle { file: duplicated, writable }); new_fd }); this.try_unwrap_io_result(fd_result) From 636ad629f8dc0d803b5738c78fb0ad44efb767c9 Mon Sep 17 00:00:00 2001 From: David Cook Date: Thu, 30 Jan 2020 18:43:34 -0600 Subject: [PATCH 1530/3747] Functional test of cloned file handle --- tests/run-pass/fs.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/tests/run-pass/fs.rs b/tests/run-pass/fs.rs index 632ed13f2eace..324630df1e94f 100644 --- a/tests/run-pass/fs.rs +++ b/tests/run-pass/fs.rs @@ -41,8 +41,14 @@ fn main() { // Reading until EOF should get the whole text. file.read_to_end(&mut contents).unwrap(); assert_eq!(bytes, contents.as_slice()); - // Cloning a file should be successful - file.try_clone().unwrap(); + + // Cloning a file should be successful. + let file = File::open(&path).unwrap(); + let mut cloned = file.try_clone().unwrap(); + // Reading from a cloned file should get the same text. + let mut contents = Vec::new(); + cloned.read_to_end(&mut contents).unwrap(); + assert_eq!(bytes, contents.as_slice()); // Test that seeking to the beginning and reading until EOF gets the text again. file.seek(SeekFrom::Start(0)).unwrap(); From 962a7404265ff59c13e5f548da64b45609f3065f Mon Sep 17 00:00:00 2001 From: David Cook Date: Sun, 9 Feb 2020 14:43:45 -0600 Subject: [PATCH 1531/3747] Rewrite file descriptor handling --- src/shims/fs.rs | 116 +++++++++++++++++++++++++++---------------- tests/run-pass/fs.rs | 1 + 2 files changed, 74 insertions(+), 43 deletions(-) diff --git a/src/shims/fs.rs b/src/shims/fs.rs index 792996f678d4e..26bcdbde0573c 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -1,4 +1,4 @@ -use std::collections::HashMap; +use std::collections::BTreeMap; use std::convert::{TryFrom, TryInto}; use std::fs::{remove_file, rename, File, OpenOptions}; use std::io::{Read, Seek, SeekFrom, Write}; @@ -13,34 +13,58 @@ use helpers::immty_from_uint_checked; use shims::time::system_time_to_duration; #[derive(Debug)] -pub struct FileHandle { - file: File, - writable: bool, +pub enum FileHandle { + StdInPlaceholder, + StdOutPlaceholder, + StdErrPlaceholder, + File { file: File, writable: bool }, + // In the future, could add support for dirfd() and other functions by + // adding a Directory variant here } pub struct FileHandler { - handles: HashMap, - low: i32, + handles: BTreeMap, } impl FileHandler { - fn next_fd(&self) -> i32 { - self.low + 1 + fn insert_fd(&mut self, file_handle: FileHandle) -> i32 { + self.insert_fd_with_min_fd(file_handle, 3) } - fn register_fd(&mut self, fd: i32, handle: FileHandle) { - self.low = fd; - self.handles.insert(fd, handle).unwrap_none(); + fn insert_fd_with_min_fd(&mut self, file_handle: FileHandle, min_fd: i32) -> i32 { + let min_fd = std::cmp::max(min_fd, 3); + let candidate_new_fd = self + .handles + .range(min_fd..) + .zip(min_fd..) + .find_map(|((fd, _fh), counter)| { + if *fd != counter { + // There was a gap in the fds stored, return the first unused one + // (note that this relies on BTreeMap iterating in key order) + Some(counter) + } else { + // This fd is used, keep going + None + } + }); + let new_fd = candidate_new_fd.unwrap_or_else(|| { + // find_map ran out of BTreeMap entries before finding a free fd, use one plus the + // maximum fd in the map + self.handles.keys().rev().next().map(|last_fd| last_fd + 1).unwrap_or(min_fd) + }); + self.handles.insert(new_fd, file_handle).unwrap_none(); + new_fd } } impl Default for FileHandler { fn default() -> Self { - FileHandler { - handles: Default::default(), - // 0, 1 and 2 are reserved for stdin, stdout and stderr. - low: 2, - } + let mut handles: BTreeMap = Default::default(); + // 0, 1 and 2 are reserved for stdin, stdout and stderr. + handles.insert(0, FileHandle::StdInPlaceholder); + handles.insert(1, FileHandle::StdOutPlaceholder); + handles.insert(2, FileHandle::StdErrPlaceholder); + FileHandler { handles } } } @@ -119,9 +143,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let fd = options.open(&path).map(|file| { let fh = &mut this.machine.file_handler; - let fd = fh.next_fd(); - fh.register_fd(fd, FileHandle { file, writable }); - fd + fh.insert_fd(FileHandle::File { file, writable }) }); this.try_unwrap_io_result(fd) @@ -150,23 +172,27 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } else { this.handle_not_found() } - } else if cmd == this.eval_libc_i32("F_DUPFD")? || cmd == this.eval_libc_i32("F_DUPFD_CLOEXEC")? { + } else if cmd == this.eval_libc_i32("F_DUPFD")? + || cmd == this.eval_libc_i32("F_DUPFD_CLOEXEC")? + { // Note that we always assume the FD_CLOEXEC flag is set for every open file, in part // because exec() isn't supported. The F_DUPFD and F_DUPFD_CLOEXEC commands only // differ in whether the FD_CLOEXEC flag is pre-set on the new file descriptor, // thus they can share the same implementation here. - let arg_op = arg_op - .ok_or_else(|| err_unsup_format!("fcntl with command F_DUPFD or F_DUPFD_CLOEXEC requires a third argument"))?; + let arg_op = arg_op.ok_or_else(|| { + err_unsup_format!( + "fcntl with command F_DUPFD or F_DUPFD_CLOEXEC requires a third argument" + ) + })?; let arg = this.read_scalar(arg_op)?.to_i32()?; let fh = &mut this.machine.file_handler; let (file_result, writable) = match fh.handles.get(&fd) { - Some(original) => (original.file.try_clone(), original.writable), + Some(FileHandle::File { file, writable }) => (file.try_clone(), *writable), + Some(_) => throw_unsup_format!("Duplicating file descriptors for stdin, stdout, or stderr is not supported"), None => return this.handle_not_found(), }; let fd_result = file_result.map(|duplicated| { - let new_fd = std::cmp::max(fh.next_fd(), arg); - fh.register_fd(new_fd, FileHandle { file: duplicated, writable }); - new_fd + fh.insert_fd_with_min_fd(FileHandle::File { file: duplicated, writable }, arg) }); this.try_unwrap_io_result(fd_result) } else { @@ -181,23 +207,28 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let fd = this.read_scalar(fd_op)?.to_i32()?; - if let Some(handle) = this.machine.file_handler.handles.remove(&fd) { + if fd <= 2 { + // early return to prevent removing StdInPlaceholder, etc., from the handles map + return this.handle_not_found(); + } + + if let Some(FileHandle::File { file, writable }) = this.machine.file_handler.handles.remove(&fd) { // We sync the file if it was opened in a mode different than read-only. - if handle.writable { + if writable { // `File::sync_all` does the checks that are done when closing a file. We do this to // to handle possible errors correctly. - let result = this.try_unwrap_io_result(handle.file.sync_all().map(|_| 0i32)); + let result = this.try_unwrap_io_result(file.sync_all().map(|_| 0i32)); // Now we actually close the file. - drop(handle); + drop(file); // And return the result. result } else { // We drop the file, this closes it but ignores any errors produced when closing - // it. This is done because `File::sync_call` cannot be done over files like + // it. This is done because `File::sync_all` cannot be done over files like // `/dev/urandom` which are read-only. Check // https://github.com/rust-lang/miri/issues/999#issuecomment-568920439 for a deeper // discussion. - drop(handle); + drop(file); Ok(0) } } else { @@ -230,7 +261,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // host's and target's `isize`. This saves us from having to handle overflows later. let count = count.min(this.isize_max() as u64).min(isize::max_value() as u64); - if let Some(handle) = this.machine.file_handler.handles.get_mut(&fd) { + if let Some(FileHandle::File { file, writable: _ }) = this.machine.file_handler.handles.get_mut(&fd) { // This can never fail because `count` was capped to be smaller than // `isize::max_value()`. let count = isize::try_from(count).unwrap(); @@ -238,8 +269,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // because it was a target's `usize`. Also we are sure that its smaller than // `usize::max_value()` because it is a host's `isize`. let mut bytes = vec![0; count as usize]; - let result = handle - .file + let result = file .read(&mut bytes) // `File::read` never returns a value larger than `count`, so this cannot fail. .map(|c| i64::try_from(c).unwrap()); @@ -285,9 +315,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // host's and target's `isize`. This saves us from having to handle overflows later. let count = count.min(this.isize_max() as u64).min(isize::max_value() as u64); - if let Some(handle) = this.machine.file_handler.handles.get_mut(&fd) { + if let Some(FileHandle::File { file, writable: _ }) = this.machine.file_handler.handles.get_mut(&fd) { let bytes = this.memory.read_bytes(buf, Size::from_bytes(count))?; - let result = handle.file.write(&bytes).map(|c| i64::try_from(c).unwrap()); + let result = file.write(&bytes).map(|c| i64::try_from(c).unwrap()); this.try_unwrap_io_result(result) } else { this.handle_not_found() @@ -320,8 +350,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx return Ok(-1); }; - if let Some(handle) = this.machine.file_handler.handles.get_mut(&fd) { - let result = handle.file.seek(seek_from).map(|offset| offset as i64); + if let Some(FileHandle::File { file, writable: _ }) = this.machine.file_handler.handles.get_mut(&fd) { + let result = file.seek(seek_from).map(|offset| offset as i64); this.try_unwrap_io_result(result) } else { this.handle_not_found() @@ -682,11 +712,11 @@ impl FileMetadata { fd: i32, ) -> InterpResult<'tcx, Option> { let option = ecx.machine.file_handler.handles.get(&fd); - let handle = match option { - Some(handle) => handle, - None => return ecx.handle_not_found().map(|_: i32| None), + let file = match option { + Some(FileHandle::File { file, writable: _ }) => file, + Some(_) | None => return ecx.handle_not_found().map(|_: i32| None), }; - let metadata = handle.file.metadata(); + let metadata = file.metadata(); FileMetadata::from_meta(ecx, metadata) } diff --git a/tests/run-pass/fs.rs b/tests/run-pass/fs.rs index 324630df1e94f..8fc03bcb11b88 100644 --- a/tests/run-pass/fs.rs +++ b/tests/run-pass/fs.rs @@ -50,6 +50,7 @@ fn main() { cloned.read_to_end(&mut contents).unwrap(); assert_eq!(bytes, contents.as_slice()); + let mut file = File::open(&path).unwrap(); // Test that seeking to the beginning and reading until EOF gets the text again. file.seek(SeekFrom::Start(0)).unwrap(); let mut contents = Vec::new(); From a6a8f09f1e411cc1c3edbcabb7801db8d4dadc4f Mon Sep 17 00:00:00 2001 From: David Cook Date: Sun, 16 Feb 2020 16:51:02 -0600 Subject: [PATCH 1532/3747] Address review comments --- src/lib.rs | 1 + src/shims/fs.rs | 16 +++++++++++----- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index c34b90877d9d1..85ee98aa3a123 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,5 +1,6 @@ #![feature(rustc_private)] #![feature(option_expect_none, option_unwrap_none)] +#![feature(map_first_last)] #![warn(rust_2018_idioms)] #![allow(clippy::cast_lossless)] diff --git a/src/shims/fs.rs b/src/shims/fs.rs index 26bcdbde0573c..a0df362bcee47 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -33,6 +33,11 @@ impl FileHandler { fn insert_fd_with_min_fd(&mut self, file_handle: FileHandle, min_fd: i32) -> i32 { let min_fd = std::cmp::max(min_fd, 3); + + // Find the lowest unused FD, starting from min_fd. If the first such unused FD is in + // between used FDs, the find_map combinator will return it. If the first such unused FD + // is after all other used FDs, the find_map combinator will return None, and we will use + // the FD following the greatest FD thus far. let candidate_new_fd = self .handles .range(min_fd..) @@ -50,8 +55,9 @@ impl FileHandler { let new_fd = candidate_new_fd.unwrap_or_else(|| { // find_map ran out of BTreeMap entries before finding a free fd, use one plus the // maximum fd in the map - self.handles.keys().rev().next().map(|last_fd| last_fd + 1).unwrap_or(min_fd) + self.handles.last_entry().map(|entry| entry.key() + 1).unwrap_or(min_fd) }); + self.handles.insert(new_fd, file_handle).unwrap_none(); new_fd } @@ -153,7 +159,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx &mut self, fd_op: OpTy<'tcx, Tag>, cmd_op: OpTy<'tcx, Tag>, - arg_op: Option>, + start_op: Option>, ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); @@ -179,12 +185,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // because exec() isn't supported. The F_DUPFD and F_DUPFD_CLOEXEC commands only // differ in whether the FD_CLOEXEC flag is pre-set on the new file descriptor, // thus they can share the same implementation here. - let arg_op = arg_op.ok_or_else(|| { + let start_op = start_op.ok_or_else(|| { err_unsup_format!( "fcntl with command F_DUPFD or F_DUPFD_CLOEXEC requires a third argument" ) })?; - let arg = this.read_scalar(arg_op)?.to_i32()?; + let start = this.read_scalar(start_op)?.to_i32()?; let fh = &mut this.machine.file_handler; let (file_result, writable) = match fh.handles.get(&fd) { Some(FileHandle::File { file, writable }) => (file.try_clone(), *writable), @@ -192,7 +198,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx None => return this.handle_not_found(), }; let fd_result = file_result.map(|duplicated| { - fh.insert_fd_with_min_fd(FileHandle::File { file: duplicated, writable }, arg) + fh.insert_fd_with_min_fd(FileHandle::File { file: duplicated, writable }, start) }); this.try_unwrap_io_result(fd_result) } else { From 8216f3c0f35aa948fe96d0eed17b0e5855799bd4 Mon Sep 17 00:00:00 2001 From: David Cook Date: Sun, 16 Feb 2020 16:59:54 -0600 Subject: [PATCH 1533/3747] Back out placeholder variants from FileHandle --- src/shims/fs.rs | 49 ++++++++++++++++--------------------------------- 1 file changed, 16 insertions(+), 33 deletions(-) diff --git a/src/shims/fs.rs b/src/shims/fs.rs index a0df362bcee47..a3c45101a0b70 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -13,15 +13,12 @@ use helpers::immty_from_uint_checked; use shims::time::system_time_to_duration; #[derive(Debug)] -pub enum FileHandle { - StdInPlaceholder, - StdOutPlaceholder, - StdErrPlaceholder, - File { file: File, writable: bool }, - // In the future, could add support for dirfd() and other functions by - // adding a Directory variant here +pub struct FileHandle { + file: File, + writable: bool, } +#[derive(Debug, Default)] pub struct FileHandler { handles: BTreeMap, } @@ -63,17 +60,6 @@ impl FileHandler { } } -impl Default for FileHandler { - fn default() -> Self { - let mut handles: BTreeMap = Default::default(); - // 0, 1 and 2 are reserved for stdin, stdout and stderr. - handles.insert(0, FileHandle::StdInPlaceholder); - handles.insert(1, FileHandle::StdOutPlaceholder); - handles.insert(2, FileHandle::StdErrPlaceholder); - FileHandler { handles } - } -} - impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { fn open( @@ -149,7 +135,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let fd = options.open(&path).map(|file| { let fh = &mut this.machine.file_handler; - fh.insert_fd(FileHandle::File { file, writable }) + fh.insert_fd(FileHandle { file, writable }) }); this.try_unwrap_io_result(fd) @@ -185,6 +171,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // because exec() isn't supported. The F_DUPFD and F_DUPFD_CLOEXEC commands only // differ in whether the FD_CLOEXEC flag is pre-set on the new file descriptor, // thus they can share the same implementation here. + if fd <= 2 { + throw_unsup_format!("Duplicating file descriptors for stdin, stdout, or stderr is not supported") + } let start_op = start_op.ok_or_else(|| { err_unsup_format!( "fcntl with command F_DUPFD or F_DUPFD_CLOEXEC requires a third argument" @@ -193,12 +182,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let start = this.read_scalar(start_op)?.to_i32()?; let fh = &mut this.machine.file_handler; let (file_result, writable) = match fh.handles.get(&fd) { - Some(FileHandle::File { file, writable }) => (file.try_clone(), *writable), - Some(_) => throw_unsup_format!("Duplicating file descriptors for stdin, stdout, or stderr is not supported"), + Some(FileHandle { file, writable }) => (file.try_clone(), *writable), None => return this.handle_not_found(), }; let fd_result = file_result.map(|duplicated| { - fh.insert_fd_with_min_fd(FileHandle::File { file: duplicated, writable }, start) + fh.insert_fd_with_min_fd(FileHandle { file: duplicated, writable }, start) }); this.try_unwrap_io_result(fd_result) } else { @@ -213,12 +201,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let fd = this.read_scalar(fd_op)?.to_i32()?; - if fd <= 2 { - // early return to prevent removing StdInPlaceholder, etc., from the handles map - return this.handle_not_found(); - } - - if let Some(FileHandle::File { file, writable }) = this.machine.file_handler.handles.remove(&fd) { + if let Some(FileHandle { file, writable }) = this.machine.file_handler.handles.remove(&fd) { // We sync the file if it was opened in a mode different than read-only. if writable { // `File::sync_all` does the checks that are done when closing a file. We do this to @@ -267,7 +250,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // host's and target's `isize`. This saves us from having to handle overflows later. let count = count.min(this.isize_max() as u64).min(isize::max_value() as u64); - if let Some(FileHandle::File { file, writable: _ }) = this.machine.file_handler.handles.get_mut(&fd) { + if let Some(FileHandle { file, writable: _ }) = this.machine.file_handler.handles.get_mut(&fd) { // This can never fail because `count` was capped to be smaller than // `isize::max_value()`. let count = isize::try_from(count).unwrap(); @@ -321,7 +304,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // host's and target's `isize`. This saves us from having to handle overflows later. let count = count.min(this.isize_max() as u64).min(isize::max_value() as u64); - if let Some(FileHandle::File { file, writable: _ }) = this.machine.file_handler.handles.get_mut(&fd) { + if let Some(FileHandle { file, writable: _ }) = this.machine.file_handler.handles.get_mut(&fd) { let bytes = this.memory.read_bytes(buf, Size::from_bytes(count))?; let result = file.write(&bytes).map(|c| i64::try_from(c).unwrap()); this.try_unwrap_io_result(result) @@ -356,7 +339,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx return Ok(-1); }; - if let Some(FileHandle::File { file, writable: _ }) = this.machine.file_handler.handles.get_mut(&fd) { + if let Some(FileHandle { file, writable: _ }) = this.machine.file_handler.handles.get_mut(&fd) { let result = file.seek(seek_from).map(|offset| offset as i64); this.try_unwrap_io_result(result) } else { @@ -719,8 +702,8 @@ impl FileMetadata { ) -> InterpResult<'tcx, Option> { let option = ecx.machine.file_handler.handles.get(&fd); let file = match option { - Some(FileHandle::File { file, writable: _ }) => file, - Some(_) | None => return ecx.handle_not_found().map(|_: i32| None), + Some(FileHandle { file, writable: _ }) => file, + None => return ecx.handle_not_found().map(|_: i32| None), }; let metadata = file.metadata(); From 0933314bffefdd6dcec2705a157d8228acf6fb49 Mon Sep 17 00:00:00 2001 From: David Cook Date: Mon, 17 Feb 2020 22:36:33 -0600 Subject: [PATCH 1534/3747] Rewrite file system tests --- tests/run-pass/fs.rs | 134 +++++++++++++++++++++++++++++++++++-------- 1 file changed, 109 insertions(+), 25 deletions(-) diff --git a/tests/run-pass/fs.rs b/tests/run-pass/fs.rs index 8fc03bcb11b88..3851a4d45e92b 100644 --- a/tests/run-pass/fs.rs +++ b/tests/run-pass/fs.rs @@ -5,25 +5,23 @@ use std::fs::{File, remove_file, rename}; use std::io::{Read, Write, ErrorKind, Result, Seek, SeekFrom}; use std::path::{PathBuf, Path}; -fn test_metadata(bytes: &[u8], path: &Path) -> Result<()> { - // Test that the file metadata is correct. - let metadata = path.metadata()?; - // `path` should point to a file. - assert!(metadata.is_file()); - // The size of the file must be equal to the number of written bytes. - assert_eq!(bytes.len() as u64, metadata.len()); - Ok(()) +fn main() { + test_file(); + test_file_clone(); + test_seek(); + test_metadata(); + test_symlink(); + test_errors(); + test_rename(); } -fn main() { +fn test_file() { let tmp = std::env::temp_dir(); - let filename = PathBuf::from("miri_test_fs.txt"); + let filename = PathBuf::from("miri_test_fs_file.txt"); let path = tmp.join(&filename); - let symlink_path = tmp.join("miri_test_fs_symlink.txt"); let bytes = b"Hello, World!\n"; // Clean the paths for robustness. remove_file(&path).ok(); - remove_file(&symlink_path).ok(); // Test creating, writing and closing a file (closing is tested when `file` is dropped). let mut file = File::create(&path).unwrap(); @@ -42,6 +40,21 @@ fn main() { file.read_to_end(&mut contents).unwrap(); assert_eq!(bytes, contents.as_slice()); + // Removing file should succeed. + remove_file(&path).unwrap(); +} + +fn test_file_clone() { + let tmp = std::env::temp_dir(); + let filename = PathBuf::from("miri_test_fs_file_clone.txt"); + let path = tmp.join(&filename); + let bytes = b"Hello, World!\n"; + // Clean the paths for robustness. + remove_file(&path).ok(); + + let mut file = File::create(&path).unwrap(); + file.write(bytes).unwrap(); + // Cloning a file should be successful. let file = File::open(&path).unwrap(); let mut cloned = file.try_clone().unwrap(); @@ -50,7 +63,24 @@ fn main() { cloned.read_to_end(&mut contents).unwrap(); assert_eq!(bytes, contents.as_slice()); + // Removing file should succeed. + remove_file(&path).unwrap(); +} + +fn test_seek() { + let tmp = std::env::temp_dir(); + let filename = PathBuf::from("miri_test_fs_seek.txt"); + let path = tmp.join(&filename); + let bytes = b"Hello, World!\n"; + // Clean the paths for robustness. + remove_file(&path).ok(); + + let mut file = File::create(&path).unwrap(); + file.write(bytes).unwrap(); + let mut file = File::open(&path).unwrap(); + let mut contents = Vec::new(); + file.read_to_end(&mut contents).unwrap(); // Test that seeking to the beginning and reading until EOF gets the text again. file.seek(SeekFrom::Start(0)).unwrap(); let mut contents = Vec::new(); @@ -68,11 +98,53 @@ fn main() { file.read_to_end(&mut contents).unwrap(); assert_eq!(&bytes[2..], contents.as_slice()); + // Removing file should succeed. + remove_file(&path).unwrap(); +} + +fn check_metadata(bytes: &[u8], path: &Path) -> Result<()> { + // Test that the file metadata is correct. + let metadata = path.metadata()?; + // `path` should point to a file. + assert!(metadata.is_file()); + // The size of the file must be equal to the number of written bytes. + assert_eq!(bytes.len() as u64, metadata.len()); + Ok(()) +} + +fn test_metadata() { + let tmp = std::env::temp_dir(); + let filename = PathBuf::from("miri_test_fs_metadata.txt"); + let path = tmp.join(&filename); + let bytes = b"Hello, World!\n"; + // Clean the paths for robustness. + remove_file(&path).ok(); + + let mut file = File::create(&path).unwrap(); + file.write(bytes).unwrap(); + // Test that metadata of an absolute path is correct. - test_metadata(bytes, &path).unwrap(); + check_metadata(bytes, &path).unwrap(); // Test that metadata of a relative path is correct. std::env::set_current_dir(&tmp).unwrap(); - test_metadata(bytes, &filename).unwrap(); + check_metadata(bytes, &filename).unwrap(); + + // Removing file should succeed. + remove_file(&path).unwrap(); +} + +fn test_symlink() { + let tmp = std::env::temp_dir(); + let filename = PathBuf::from("miri_test_fs_link_target.txt"); + let path = tmp.join(&filename); + let symlink_path = tmp.join("miri_test_fs_symlink.txt"); + let bytes = b"Hello, World!\n"; + // Clean the paths for robustness. + remove_file(&path).ok(); + remove_file(&symlink_path).ok(); + + let mut file = File::create(&path).unwrap(); + file.write(bytes).unwrap(); // Creating a symbolic link should succeed. std::os::unix::fs::symlink(&path, &symlink_path).unwrap(); @@ -82,7 +154,7 @@ fn main() { symlink_file.read_to_end(&mut contents).unwrap(); assert_eq!(bytes, contents.as_slice()); // Test that metadata of a symbolic link is correct. - test_metadata(bytes, &symlink_path).unwrap(); + check_metadata(bytes, &symlink_path).unwrap(); // Test that the metadata of a symbolic link is correct when not following it. assert!(symlink_path.symlink_metadata().unwrap().file_type().is_symlink()); // Removing symbolic link should succeed. @@ -90,10 +162,30 @@ fn main() { // Removing file should succeed. remove_file(&path).unwrap(); +} + +fn test_errors() { + let tmp = std::env::temp_dir(); + let filename = PathBuf::from("miri_test_fs_errors.txt"); + let path = tmp.join(&filename); + let bytes = b"Hello, World!\n"; + // Clean the paths for robustness. + remove_file(&path).ok(); + + // The following tests also check that the `__errno_location()` shim is working properly. + // Opening a non-existing file should fail with a "not found" error. + assert_eq!(ErrorKind::NotFound, File::open(&path).unwrap_err().kind()); + // Removing a non-existing file should fail with a "not found" error. + assert_eq!(ErrorKind::NotFound, remove_file(&path).unwrap_err().kind()); + // Reading the metadata of a non-existing file should fail with a "not found" error. + assert_eq!(ErrorKind::NotFound, check_metadata(bytes, &path).unwrap_err().kind()); +} +fn test_rename() { + let tmp = std::env::temp_dir(); // Renaming a file should succeed. - let path1 = tmp.join("rename_source.txt"); - let path2 = tmp.join("rename_destination.txt"); + let path1 = tmp.join("miri_test_fs_rename_source.txt"); + let path2 = tmp.join("miri_test_fs_rename_destination.txt"); // Clean files for robustness. remove_file(&path1).ok(); remove_file(&path2).ok(); @@ -103,12 +195,4 @@ fn main() { assert_eq!(ErrorKind::NotFound, path1.metadata().unwrap_err().kind()); assert!(path2.metadata().unwrap().is_file()); remove_file(&path2).unwrap(); - - // The two following tests also check that the `__errno_location()` shim is working properly. - // Opening a non-existing file should fail with a "not found" error. - assert_eq!(ErrorKind::NotFound, File::open(&path).unwrap_err().kind()); - // Removing a non-existing file should fail with a "not found" error. - assert_eq!(ErrorKind::NotFound, remove_file(&path).unwrap_err().kind()); - // Reading the metadata of a non-existing file should fail with a "not found" error. - assert_eq!(ErrorKind::NotFound, test_metadata(bytes, &path).unwrap_err().kind()); } From ae7d98b68fb34723bb0b8e18f1de71f7e0491397 Mon Sep 17 00:00:00 2001 From: David Cook Date: Tue, 18 Feb 2020 18:06:33 -0600 Subject: [PATCH 1535/3747] Extract constant for minimum fd --- src/shims/fs.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/shims/fs.rs b/src/shims/fs.rs index a3c45101a0b70..e5ed22634db9e 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -23,13 +23,16 @@ pub struct FileHandler { handles: BTreeMap, } +// fd numbers 0, 1, and 2 are reserved for stdin, stdout, and stderr +const MIN_NORMAL_FILE_FD: i32 = 3; + impl FileHandler { fn insert_fd(&mut self, file_handle: FileHandle) -> i32 { - self.insert_fd_with_min_fd(file_handle, 3) + self.insert_fd_with_min_fd(file_handle, 0) } fn insert_fd_with_min_fd(&mut self, file_handle: FileHandle, min_fd: i32) -> i32 { - let min_fd = std::cmp::max(min_fd, 3); + let min_fd = std::cmp::max(min_fd, MIN_NORMAL_FILE_FD); // Find the lowest unused FD, starting from min_fd. If the first such unused FD is in // between used FDs, the find_map combinator will return it. If the first such unused FD @@ -171,7 +174,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // because exec() isn't supported. The F_DUPFD and F_DUPFD_CLOEXEC commands only // differ in whether the FD_CLOEXEC flag is pre-set on the new file descriptor, // thus they can share the same implementation here. - if fd <= 2 { + if fd < MIN_NORMAL_FILE_FD { throw_unsup_format!("Duplicating file descriptors for stdin, stdout, or stderr is not supported") } let start_op = start_op.ok_or_else(|| { From 56f9ee2c2d04f8c9fad132a22bcfb7e76874e98b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 19 Feb 2020 09:15:12 +0100 Subject: [PATCH 1536/3747] bump Rust (no changes needed) --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index a0f512a727001..12ac7b51b9989 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -21ed50522ddb998f5367229984a4510af578899f +a2fb0c28be794f28028884650db70c17fea8e35b From 8b3176381690d01eb1cb50926ebb784bdac3ab9f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 19 Feb 2020 11:04:59 +0100 Subject: [PATCH 1537/3747] fs test: factor some common code --- tests/run-pass/fs.rs | 59 +++++++++++++++----------------------------- 1 file changed, 20 insertions(+), 39 deletions(-) diff --git a/tests/run-pass/fs.rs b/tests/run-pass/fs.rs index 3851a4d45e92b..a69f9f3b23d83 100644 --- a/tests/run-pass/fs.rs +++ b/tests/run-pass/fs.rs @@ -15,13 +15,18 @@ fn main() { test_rename(); } -fn test_file() { +/// Prepare: compute filename and make sure the file does not exist. +fn prepare(filename: &str) -> PathBuf { let tmp = std::env::temp_dir(); - let filename = PathBuf::from("miri_test_fs_file.txt"); - let path = tmp.join(&filename); - let bytes = b"Hello, World!\n"; + let path = tmp.join(filename); // Clean the paths for robustness. remove_file(&path).ok(); + path +} + +fn test_file() { + let path = prepare("miri_test_fs_file.txt"); + let bytes = b"Hello, World!\n"; // Test creating, writing and closing a file (closing is tested when `file` is dropped). let mut file = File::create(&path).unwrap(); @@ -45,12 +50,8 @@ fn test_file() { } fn test_file_clone() { - let tmp = std::env::temp_dir(); - let filename = PathBuf::from("miri_test_fs_file_clone.txt"); - let path = tmp.join(&filename); + let path = prepare("miri_test_fs_file_clone.txt"); let bytes = b"Hello, World!\n"; - // Clean the paths for robustness. - remove_file(&path).ok(); let mut file = File::create(&path).unwrap(); file.write(bytes).unwrap(); @@ -68,12 +69,8 @@ fn test_file_clone() { } fn test_seek() { - let tmp = std::env::temp_dir(); - let filename = PathBuf::from("miri_test_fs_seek.txt"); - let path = tmp.join(&filename); + let path = prepare("miri_test_fs_seek.txt"); let bytes = b"Hello, World!\n"; - // Clean the paths for robustness. - remove_file(&path).ok(); let mut file = File::create(&path).unwrap(); file.write(bytes).unwrap(); @@ -113,12 +110,8 @@ fn check_metadata(bytes: &[u8], path: &Path) -> Result<()> { } fn test_metadata() { - let tmp = std::env::temp_dir(); - let filename = PathBuf::from("miri_test_fs_metadata.txt"); - let path = tmp.join(&filename); + let path = prepare("miri_test_fs_metadata.txt"); let bytes = b"Hello, World!\n"; - // Clean the paths for robustness. - remove_file(&path).ok(); let mut file = File::create(&path).unwrap(); file.write(bytes).unwrap(); @@ -126,22 +119,17 @@ fn test_metadata() { // Test that metadata of an absolute path is correct. check_metadata(bytes, &path).unwrap(); // Test that metadata of a relative path is correct. - std::env::set_current_dir(&tmp).unwrap(); - check_metadata(bytes, &filename).unwrap(); + std::env::set_current_dir(path.parent().unwrap()).unwrap(); + check_metadata(bytes, Path::new(path.file_name().unwrap())).unwrap(); // Removing file should succeed. remove_file(&path).unwrap(); } fn test_symlink() { - let tmp = std::env::temp_dir(); - let filename = PathBuf::from("miri_test_fs_link_target.txt"); - let path = tmp.join(&filename); - let symlink_path = tmp.join("miri_test_fs_symlink.txt"); + let path = prepare("miri_test_fs_link_target.txt"); + let symlink_path = prepare("miri_test_fs_symlink.txt"); let bytes = b"Hello, World!\n"; - // Clean the paths for robustness. - remove_file(&path).ok(); - remove_file(&symlink_path).ok(); let mut file = File::create(&path).unwrap(); file.write(bytes).unwrap(); @@ -165,12 +153,8 @@ fn test_symlink() { } fn test_errors() { - let tmp = std::env::temp_dir(); - let filename = PathBuf::from("miri_test_fs_errors.txt"); - let path = tmp.join(&filename); + let path = prepare("miri_test_fs_errors.txt"); let bytes = b"Hello, World!\n"; - // Clean the paths for robustness. - remove_file(&path).ok(); // The following tests also check that the `__errno_location()` shim is working properly. // Opening a non-existing file should fail with a "not found" error. @@ -182,13 +166,10 @@ fn test_errors() { } fn test_rename() { - let tmp = std::env::temp_dir(); // Renaming a file should succeed. - let path1 = tmp.join("miri_test_fs_rename_source.txt"); - let path2 = tmp.join("miri_test_fs_rename_destination.txt"); - // Clean files for robustness. - remove_file(&path1).ok(); - remove_file(&path2).ok(); + let path1 = prepare("miri_test_fs_rename_source.txt"); + let path2 = prepare("miri_test_fs_rename_destination.txt"); + let file = File::create(&path1).unwrap(); drop(file); rename(&path1, &path2).unwrap(); From f79c453860ce113374029685b2b78b966a89559e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 19 Feb 2020 11:08:24 +0100 Subject: [PATCH 1538/3747] factor more common code --- tests/run-pass/fs.rs | 38 +++++++++++++++++--------------------- 1 file changed, 17 insertions(+), 21 deletions(-) diff --git a/tests/run-pass/fs.rs b/tests/run-pass/fs.rs index a69f9f3b23d83..ebbd0b0c57ca0 100644 --- a/tests/run-pass/fs.rs +++ b/tests/run-pass/fs.rs @@ -24,9 +24,17 @@ fn prepare(filename: &str) -> PathBuf { path } +/// Prepare like above, and also write some initial content to the file. +fn prepare_with_content(filename: &str, content: &[u8]) -> PathBuf { + let path = prepare(filename); + let mut file = File::create(&path).unwrap(); + file.write(content).unwrap(); + path +} + fn test_file() { - let path = prepare("miri_test_fs_file.txt"); let bytes = b"Hello, World!\n"; + let path = prepare("miri_test_fs_file.txt"); // Test creating, writing and closing a file (closing is tested when `file` is dropped). let mut file = File::create(&path).unwrap(); @@ -50,11 +58,8 @@ fn test_file() { } fn test_file_clone() { - let path = prepare("miri_test_fs_file_clone.txt"); let bytes = b"Hello, World!\n"; - - let mut file = File::create(&path).unwrap(); - file.write(bytes).unwrap(); + let path = prepare_with_content("miri_test_fs_file_clone.txt", bytes); // Cloning a file should be successful. let file = File::open(&path).unwrap(); @@ -69,11 +74,8 @@ fn test_file_clone() { } fn test_seek() { - let path = prepare("miri_test_fs_seek.txt"); - let bytes = b"Hello, World!\n"; - - let mut file = File::create(&path).unwrap(); - file.write(bytes).unwrap(); + let bytes = b"Hello, entire World!\n"; + let path = prepare_with_content("miri_test_fs_seek.txt", bytes); let mut file = File::open(&path).unwrap(); let mut contents = Vec::new(); @@ -110,11 +112,8 @@ fn check_metadata(bytes: &[u8], path: &Path) -> Result<()> { } fn test_metadata() { - let path = prepare("miri_test_fs_metadata.txt"); - let bytes = b"Hello, World!\n"; - - let mut file = File::create(&path).unwrap(); - file.write(bytes).unwrap(); + let bytes = b"Hello, meta-World!\n"; + let path = prepare_with_content("miri_test_fs_metadata.txt", bytes); // Test that metadata of an absolute path is correct. check_metadata(bytes, &path).unwrap(); @@ -127,12 +126,9 @@ fn test_metadata() { } fn test_symlink() { - let path = prepare("miri_test_fs_link_target.txt"); - let symlink_path = prepare("miri_test_fs_symlink.txt"); let bytes = b"Hello, World!\n"; - - let mut file = File::create(&path).unwrap(); - file.write(bytes).unwrap(); + let path = prepare_with_content("miri_test_fs_link_target.txt", bytes); + let symlink_path = prepare("miri_test_fs_symlink.txt"); // Creating a symbolic link should succeed. std::os::unix::fs::symlink(&path, &symlink_path).unwrap(); @@ -153,8 +149,8 @@ fn test_symlink() { } fn test_errors() { - let path = prepare("miri_test_fs_errors.txt"); let bytes = b"Hello, World!\n"; + let path = prepare("miri_test_fs_errors.txt"); // The following tests also check that the `__errno_location()` shim is working properly. // Opening a non-existing file should fail with a "not found" error. From 3cd13cb1746193f077766985273b144beba01480 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 19 Feb 2020 11:14:30 +0100 Subject: [PATCH 1539/3747] test a bit more --- tests/run-pass/fs.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/run-pass/fs.rs b/tests/run-pass/fs.rs index ebbd0b0c57ca0..453432f64f105 100644 --- a/tests/run-pass/fs.rs +++ b/tests/run-pass/fs.rs @@ -80,6 +80,7 @@ fn test_seek() { let mut file = File::open(&path).unwrap(); let mut contents = Vec::new(); file.read_to_end(&mut contents).unwrap(); + assert_eq!(bytes, contents.as_slice()); // Test that seeking to the beginning and reading until EOF gets the text again. file.seek(SeekFrom::Start(0)).unwrap(); let mut contents = Vec::new(); From 8fe7543191e10145ba56f676f529e9db4664dee0 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Sat, 8 Feb 2020 13:29:26 -0500 Subject: [PATCH 1540/3747] add helper function for target platform checks --- src/helpers.rs | 13 +++++++++++++ src/shims/fs.rs | 16 ++++------------ 2 files changed, 17 insertions(+), 12 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index a765d58bbcf35..c92aa6dfaa7cb 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -368,6 +368,19 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } Ok(()) } + /// Helper function used inside the shims of foreign functions to check that the target + /// platform is `platform`. It returns an error using the `name` of the foreign function if + /// this is not the case. + fn check_platform(&mut self, platform: &str, name: &str) -> InterpResult<'tcx> { + if self.eval_context_mut().tcx.sess.target.target.target_os.to_lowercase() != platform { + throw_unsup_format!( + "`{}` is only available in the `{}` platform", + name, + platform, + ) + } + Ok(()) + } /// Sets the last error variable. fn set_last_error(&mut self, scalar: Scalar) -> InterpResult<'tcx> { diff --git a/src/shims/fs.rs b/src/shims/fs.rs index 2ae215e7204f2..42a860780ff8b 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -347,6 +347,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); this.check_no_isolation("stat")?; + this.check_platform("macos", "stat")?; // `stat` always follows symlinks. this.stat_or_lstat(true, path_op, buf_op) } @@ -359,6 +360,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); this.check_no_isolation("lstat")?; + this.check_platform("macos", "lstat")?; this.stat_or_lstat(false, path_op, buf_op) } @@ -370,10 +372,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); this.check_no_isolation("fstat")?; - - if this.tcx.sess.target.target.target_os.to_lowercase() != "macos" { - throw_unsup_format!("The `fstat` shim is only available for `macos` targets.") - } + this.check_platform("macos", "fstat")?; let fd = this.read_scalar(fd_op)?.to_i32()?; @@ -392,10 +391,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - if this.tcx.sess.target.target.target_os.to_lowercase() != "macos" { - throw_unsup_format!("The `stat` and `lstat` shims are only available for `macos` targets.") - } - let path_scalar = this.read_scalar(path_op)?.not_undef()?; let path: PathBuf = this.read_os_str_from_c_str(path_scalar)?.into(); @@ -417,10 +412,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); this.check_no_isolation("statx")?; - - if this.tcx.sess.target.target.target_os.to_lowercase() != "linux" { - throw_unsup_format!("The `statx` shim is only available for `linux` targets.") - } + this.check_platform("linux", "statx")?; let statxbuf_scalar = this.read_scalar(statxbuf_op)?.not_undef()?; let pathname_scalar = this.read_scalar(pathname_op)?.not_undef()?; From 63160c66cd31c6f48a4a68ff469c4bdebc8eff2f Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Tue, 11 Feb 2020 18:32:28 -0500 Subject: [PATCH 1541/3747] move pthread related functions --- src/shims/foreign_items.rs | 112 +------------------------------ src/shims/foreign_items/posix.rs | 112 ++++++++++++++++++++++++++++++- 2 files changed, 112 insertions(+), 112 deletions(-) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 6b4ce45f752fe..9ad4a6dbaf62e 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -6,7 +6,7 @@ use std::{convert::TryInto, iter}; use rustc_hir::def_id::DefId; use rustc::mir; use rustc::ty; -use rustc::ty::layout::{Align, LayoutOf, Size}; +use rustc::ty::layout::{Align, Size}; use rustc_apfloat::Float; use rustc_span::symbol::sym; use syntax::attr; @@ -192,7 +192,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx dest: PlaceTy<'tcx, Tag>, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - let tcx = &{ this.tcx.tcx }; match link_name { "malloc" => { @@ -487,115 +486,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_null(dest)?; } - // Hook pthread calls that go to the thread-local storage memory subsystem. - "pthread_key_create" => { - let key_place = this.deref_operand(args[0])?; - - // Extract the function type out of the signature (that seems easier than constructing it ourselves). - let dtor = match this.test_null(this.read_scalar(args[1])?.not_undef()?)? { - Some(dtor_ptr) => Some(this.memory.get_fn(dtor_ptr)?.as_instance()?), - None => None, - }; - - // Figure out how large a pthread TLS key actually is. - // This is `libc::pthread_key_t`. - let key_type = args[0].layout.ty - .builtin_deref(true) - .ok_or_else(|| err_ub_format!( - "wrong signature used for `pthread_key_create`: first argument must be a raw pointer." - ))? - .ty; - let key_layout = this.layout_of(key_type)?; - - // Create key and write it into the memory where `key_ptr` wants it. - let key = this.machine.tls.create_tls_key(dtor) as u128; - if key_layout.size.bits() < 128 && key >= (1u128 << key_layout.size.bits() as u128) - { - throw_unsup!(OutOfTls); - } - - this.write_scalar(Scalar::from_uint(key, key_layout.size), key_place.into())?; - - // Return success (`0`). - this.write_null(dest)?; - } - "pthread_key_delete" => { - let key = this.read_scalar(args[0])?.to_bits(args[0].layout.size)?; - this.machine.tls.delete_tls_key(key)?; - // Return success (0) - this.write_null(dest)?; - } - "pthread_getspecific" => { - let key = this.read_scalar(args[0])?.to_bits(args[0].layout.size)?; - let ptr = this.machine.tls.load_tls(key, tcx)?; - this.write_scalar(ptr, dest)?; - } - "pthread_setspecific" => { - let key = this.read_scalar(args[0])?.to_bits(args[0].layout.size)?; - let new_ptr = this.read_scalar(args[1])?.not_undef()?; - this.machine.tls.store_tls(key, this.test_null(new_ptr)?)?; - - // Return success (`0`). - this.write_null(dest)?; - } - - // Stack size/address stuff. - | "pthread_attr_init" - | "pthread_attr_destroy" - | "pthread_self" - | "pthread_attr_setstacksize" => { - this.write_null(dest)?; - } - "pthread_attr_getstack" => { - let addr_place = this.deref_operand(args[1])?; - let size_place = this.deref_operand(args[2])?; - - this.write_scalar( - Scalar::from_uint(STACK_ADDR, addr_place.layout.size), - addr_place.into(), - )?; - this.write_scalar( - Scalar::from_uint(STACK_SIZE, size_place.layout.size), - size_place.into(), - )?; - - // Return success (`0`). - this.write_null(dest)?; - } - - // We don't support threading. (Also for Windows.) - | "pthread_create" - | "CreateThread" - => { - throw_unsup_format!("Miri does not support threading"); - } - - // Stub out calls for condvar, mutex and rwlock, to just return `0`. - | "pthread_mutexattr_init" - | "pthread_mutexattr_settype" - | "pthread_mutex_init" - | "pthread_mutexattr_destroy" - | "pthread_mutex_lock" - | "pthread_mutex_unlock" - | "pthread_mutex_destroy" - | "pthread_rwlock_rdlock" - | "pthread_rwlock_unlock" - | "pthread_rwlock_wrlock" - | "pthread_rwlock_destroy" - | "pthread_condattr_init" - | "pthread_condattr_setclock" - | "pthread_cond_init" - | "pthread_condattr_destroy" - | "pthread_cond_destroy" - => { - this.write_null(dest)?; - } - - // We don't support fork so we don't have to do anything for atfork. - "pthread_atfork" => { - this.write_null(dest)?; - } - "posix_fadvise" => { // fadvise is only informational, we can ignore it. this.write_null(dest)?; diff --git a/src/shims/foreign_items/posix.rs b/src/shims/foreign_items/posix.rs index f738bdd7e6e05..2ec8b9d7a6011 100644 --- a/src/shims/foreign_items/posix.rs +++ b/src/shims/foreign_items/posix.rs @@ -2,7 +2,7 @@ mod linux; mod macos; use crate::*; -use rustc::ty::layout::{Align, Size}; +use rustc::ty::layout::{Align, LayoutOf, Size}; impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { @@ -157,6 +157,116 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } + // Hook pthread calls that go to the thread-local storage memory subsystem. + "pthread_key_create" => { + let key_place = this.deref_operand(args[0])?; + + // Extract the function type out of the signature (that seems easier than constructing it ourselves). + let dtor = match this.test_null(this.read_scalar(args[1])?.not_undef()?)? { + Some(dtor_ptr) => Some(this.memory.get_fn(dtor_ptr)?.as_instance()?), + None => None, + }; + + // Figure out how large a pthread TLS key actually is. + // This is `libc::pthread_key_t`. + let key_type = args[0].layout.ty + .builtin_deref(true) + .ok_or_else(|| err_ub_format!( + "wrong signature used for `pthread_key_create`: first argument must be a raw pointer." + ))? + .ty; + let key_layout = this.layout_of(key_type)?; + + // Create key and write it into the memory where `key_ptr` wants it. + let key = this.machine.tls.create_tls_key(dtor) as u128; + if key_layout.size.bits() < 128 && key >= (1u128 << key_layout.size.bits() as u128) + { + throw_unsup!(OutOfTls); + } + + this.write_scalar(Scalar::from_uint(key, key_layout.size), key_place.into())?; + + // Return success (`0`). + this.write_null(dest)?; + } + "pthread_key_delete" => { + let key = this.read_scalar(args[0])?.to_bits(args[0].layout.size)?; + this.machine.tls.delete_tls_key(key)?; + // Return success (0) + this.write_null(dest)?; + } + "pthread_getspecific" => { + let key = this.read_scalar(args[0])?.to_bits(args[0].layout.size)?; + let ptr = this.machine.tls.load_tls(key, tcx)?; + this.write_scalar(ptr, dest)?; + } + "pthread_setspecific" => { + let key = this.read_scalar(args[0])?.to_bits(args[0].layout.size)?; + let new_ptr = this.read_scalar(args[1])?.not_undef()?; + this.machine.tls.store_tls(key, this.test_null(new_ptr)?)?; + + // Return success (`0`). + this.write_null(dest)?; + } + + // Stack size/address stuff. + | "pthread_attr_init" + | "pthread_attr_destroy" + | "pthread_self" + | "pthread_attr_setstacksize" => { + this.write_null(dest)?; + } + "pthread_attr_getstack" => { + let addr_place = this.deref_operand(args[1])?; + let size_place = this.deref_operand(args[2])?; + + this.write_scalar( + Scalar::from_uint(STACK_ADDR, addr_place.layout.size), + addr_place.into(), + )?; + this.write_scalar( + Scalar::from_uint(STACK_SIZE, size_place.layout.size), + size_place.into(), + )?; + + // Return success (`0`). + this.write_null(dest)?; + } + + // We don't support threading. (Also for Windows.) + | "pthread_create" + | "CreateThread" + => { + throw_unsup_format!("Miri does not support threading"); + } + + // Stub out calls for condvar, mutex and rwlock, to just return `0`. + | "pthread_mutexattr_init" + | "pthread_mutexattr_settype" + | "pthread_mutex_init" + | "pthread_mutexattr_destroy" + | "pthread_mutex_lock" + | "pthread_mutex_unlock" + | "pthread_mutex_destroy" + | "pthread_rwlock_rdlock" + | "pthread_rwlock_unlock" + | "pthread_rwlock_wrlock" + | "pthread_rwlock_destroy" + | "pthread_condattr_init" + | "pthread_condattr_setclock" + | "pthread_cond_init" + | "pthread_condattr_destroy" + | "pthread_cond_destroy" + => { + this.write_null(dest)?; + } + + // We don't support fork so we don't have to do anything for atfork. + "pthread_atfork" => { + this.write_null(dest)?; + } + + _ => { match this.tcx.sess.target.target.target_os.to_lowercase().as_str() { "linux" => linux::EvalContextExt::emulate_foreign_item_by_name(this, link_name, args, dest)?, From b81949358540fd4da759b943f8a2d7382fc2a0e3 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Tue, 11 Feb 2020 18:48:38 -0500 Subject: [PATCH 1542/3747] move remaining shims --- src/shims/foreign_items.rs | 63 +------------------------- src/shims/foreign_items/posix.rs | 56 +++++++++++++++++++++++ src/shims/foreign_items/posix/linux.rs | 5 ++ 3 files changed, 63 insertions(+), 61 deletions(-) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 9ad4a6dbaf62e..59f9a8c63a7e2 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -193,6 +193,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); + // Here we dispatch all the shims for foreign functions. If you have a platform specific + // shim, add it to the corresponding submodule. match link_name { "malloc" => { let size = this.read_scalar(args[0])?.to_machine_usize(this)?; @@ -439,67 +441,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_f64(res), dest)?; } - // Some things needed for `sys::thread` initialization to go through. - | "signal" - | "sigaction" - | "sigaltstack" - => { - this.write_scalar(Scalar::from_int(0, dest.layout.size), dest)?; - } - - "sysconf" => { - let name = this.read_scalar(args[0])?.to_i32()?; - - trace!("sysconf() called with name {}", name); - // TODO: Cache the sysconf integers via Miri's global cache. - let paths = &[ - (&["libc", "_SC_PAGESIZE"], Scalar::from_int(PAGE_SIZE, dest.layout.size)), - (&["libc", "_SC_GETPW_R_SIZE_MAX"], Scalar::from_int(-1, dest.layout.size)), - ( - &["libc", "_SC_NPROCESSORS_ONLN"], - Scalar::from_int(NUM_CPUS, dest.layout.size), - ), - ]; - let mut result = None; - for &(path, path_value) in paths { - if let Some(val) = this.eval_path_scalar(path)? { - let val = val.to_i32()?; - if val == name { - result = Some(path_value); - break; - } - } - } - if let Some(result) = result { - this.write_scalar(result, dest)?; - } else { - throw_unsup_format!("Unimplemented sysconf name: {}", name) - } - } - - "sched_getaffinity" => { - // Return an error; `num_cpus` then falls back to `sysconf`. - this.write_scalar(Scalar::from_int(-1, dest.layout.size), dest)?; - } - - "isatty" => { - this.write_null(dest)?; - } - - "posix_fadvise" => { - // fadvise is only informational, we can ignore it. - this.write_null(dest)?; - } - - "mmap" => { - // This is a horrible hack, but since the guard page mechanism calls mmap and expects a particular return value, we just give it that value. - let addr = this.read_scalar(args[0])?.not_undef()?; - this.write_scalar(addr, dest)?; - } - "mprotect" => { - this.write_null(dest)?; - } - _ => match this.tcx.sess.target.target.target_os.to_lowercase().as_str() { "linux" | "macos" => posix::EvalContextExt::emulate_foreign_item_by_name(this, link_name, args, dest)?, "windows" => windows::EvalContextExt::emulate_foreign_item_by_name(this, link_name, args, dest)?, diff --git a/src/shims/foreign_items/posix.rs b/src/shims/foreign_items/posix.rs index 2ec8b9d7a6011..f524e4df291ee 100644 --- a/src/shims/foreign_items/posix.rs +++ b/src/shims/foreign_items/posix.rs @@ -266,6 +266,62 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_null(dest)?; } + // Some things needed for `sys::thread` initialization to go through. + | "signal" + | "sigaction" + | "sigaltstack" + => { + this.write_scalar(Scalar::from_int(0, dest.layout.size), dest)?; + } + + "sysconf" => { + let name = this.read_scalar(args[0])?.to_i32()?; + + trace!("sysconf() called with name {}", name); + // TODO: Cache the sysconf integers via Miri's global cache. + let paths = &[ + (&["libc", "_SC_PAGESIZE"], Scalar::from_int(PAGE_SIZE, dest.layout.size)), + (&["libc", "_SC_GETPW_R_SIZE_MAX"], Scalar::from_int(-1, dest.layout.size)), + ( + &["libc", "_SC_NPROCESSORS_ONLN"], + Scalar::from_int(NUM_CPUS, dest.layout.size), + ), + ]; + let mut result = None; + for &(path, path_value) in paths { + if let Some(val) = this.eval_path_scalar(path)? { + let val = val.to_i32()?; + if val == name { + result = Some(path_value); + break; + } + } + } + if let Some(result) = result { + this.write_scalar(result, dest)?; + } else { + throw_unsup_format!("Unimplemented sysconf name: {}", name) + } + } + + "isatty" => { + this.write_null(dest)?; + } + + "posix_fadvise" => { + // fadvise is only informational, we can ignore it. + this.write_null(dest)?; + } + + "mmap" => { + // This is a horrible hack, but since the guard page mechanism calls mmap and expects a particular return value, we just give it that value. + let addr = this.read_scalar(args[0])?.not_undef()?; + this.write_scalar(addr, dest)?; + } + + "mprotect" => { + this.write_null(dest)?; + } _ => { match this.tcx.sess.target.target.target_os.to_lowercase().as_str() { diff --git a/src/shims/foreign_items/posix/linux.rs b/src/shims/foreign_items/posix/linux.rs index 8d928b60ecbda..7267cc1af8e5c 100644 --- a/src/shims/foreign_items/posix/linux.rs +++ b/src/shims/foreign_items/posix/linux.rs @@ -75,6 +75,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx super::getrandom(this, args, dest)?; } + "sched_getaffinity" => { + // Return an error; `num_cpus` then falls back to `sysconf`. + this.write_scalar(Scalar::from_int(-1, dest.layout.size), dest)?; + } + _ => throw_unsup_format!("can't call foreign function: {}", link_name), }; From 1dbc0c9869071df351dd40a28e0e3d78c5105bfa Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Tue, 11 Feb 2020 19:00:41 -0500 Subject: [PATCH 1543/3747] remove hack for panics --- src/shims/foreign_items.rs | 35 +++++++++++--------------- src/shims/foreign_items/posix.rs | 15 ++++++++--- src/shims/foreign_items/posix/linux.rs | 6 +++-- src/shims/foreign_items/posix/macos.rs | 6 +++-- src/shims/foreign_items/windows.rs | 6 +++-- 5 files changed, 37 insertions(+), 31 deletions(-) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 59f9a8c63a7e2..14e08f5181f52 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -170,17 +170,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx }; // Next: functions that return. - match link_name { - "__rust_maybe_catch_panic" => { - this.handle_catch_panic(args, dest, ret)?; - return Ok(None); - } - - _ => this.emulate_foreign_item_by_name(link_name, args, dest)?, - }; - - this.dump_place(*dest); - this.go_to_block(ret); + if this.emulate_foreign_item_by_name(link_name, args, dest, ret)? { + this.dump_place(*dest); + this.go_to_block(ret); + } Ok(None) } @@ -190,7 +183,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx link_name: &str, args: &[OpTy<'tcx, Tag>], dest: PlaceTy<'tcx, Tag>, - ) -> InterpResult<'tcx> { + ret: mir::BasicBlock, + ) -> InterpResult<'tcx, bool> { let this = self.eval_context_mut(); // Here we dispatch all the shims for foreign functions. If you have a platform specific @@ -293,6 +287,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(new_ptr, dest)?; } + "__rust_maybe_catch_panic" => { + this.handle_catch_panic(args, dest, ret)?; + return Ok(false); + } + "memcmp" => { let left = this.read_scalar(args[0])?.not_undef()?; let right = this.read_scalar(args[1])?.not_undef()?; @@ -330,12 +329,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } - - "rename" => { - let result = this.rename(args[0], args[1])?; - this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; - } - "strlen" => { let ptr = this.read_scalar(args[0])?.not_undef()?; let n = this.memory.read_c_str(ptr)?.len(); @@ -442,13 +435,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } _ => match this.tcx.sess.target.target.target_os.to_lowercase().as_str() { - "linux" | "macos" => posix::EvalContextExt::emulate_foreign_item_by_name(this, link_name, args, dest)?, - "windows" => windows::EvalContextExt::emulate_foreign_item_by_name(this, link_name, args, dest)?, + "linux" | "macos" => return posix::EvalContextExt::emulate_foreign_item_by_name(this, link_name, args, dest, ret), + "windows" => return windows::EvalContextExt::emulate_foreign_item_by_name(this, link_name, args, dest, ret), target => throw_unsup_format!("The {} target platform is not supported", target), } }; - Ok(()) + Ok(true) } /// Evaluates the scalar at the specified path. Returns Some(val) diff --git a/src/shims/foreign_items/posix.rs b/src/shims/foreign_items/posix.rs index f524e4df291ee..746a0f25ebb1f 100644 --- a/src/shims/foreign_items/posix.rs +++ b/src/shims/foreign_items/posix.rs @@ -2,6 +2,7 @@ mod linux; mod macos; use crate::*; +use rustc::mir; use rustc::ty::layout::{Align, LayoutOf, Size}; impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} @@ -11,7 +12,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx link_name: &str, args: &[OpTy<'tcx, Tag>], dest: PlaceTy<'tcx, Tag>, - ) -> InterpResult<'tcx> { + ret: mir::BasicBlock, + ) -> InterpResult<'tcx, bool> { let this = self.eval_context_mut(); let tcx = &{ this.tcx.tcx }; @@ -97,6 +99,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; } + "rename" => { + let result = this.rename(args[0], args[1])?; + this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + } + "posix_memalign" => { let ret = this.deref_operand(args[0])?; let align = this.read_scalar(args[1])?.to_machine_usize(this)?; @@ -325,14 +332,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx _ => { match this.tcx.sess.target.target.target_os.to_lowercase().as_str() { - "linux" => linux::EvalContextExt::emulate_foreign_item_by_name(this, link_name, args, dest)?, - "macos" => macos::EvalContextExt::emulate_foreign_item_by_name(this, link_name, args, dest)?, + "linux" => return linux::EvalContextExt::emulate_foreign_item_by_name(this, link_name, args, dest, ret), + "macos" => return macos::EvalContextExt::emulate_foreign_item_by_name(this, link_name, args, dest, ret), _ => unreachable!(), } } }; - Ok(()) + Ok(true) } } diff --git a/src/shims/foreign_items/posix/linux.rs b/src/shims/foreign_items/posix/linux.rs index 7267cc1af8e5c..27e42b0082e5a 100644 --- a/src/shims/foreign_items/posix/linux.rs +++ b/src/shims/foreign_items/posix/linux.rs @@ -1,4 +1,5 @@ use crate::*; +use rustc::mir; impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { @@ -7,7 +8,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx link_name: &str, args: &[OpTy<'tcx, Tag>], dest: PlaceTy<'tcx, Tag>, - ) -> InterpResult<'tcx> { + _ret: mir::BasicBlock, + ) -> InterpResult<'tcx, bool> { let this = self.eval_context_mut(); match link_name { @@ -83,6 +85,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx _ => throw_unsup_format!("can't call foreign function: {}", link_name), }; - Ok(()) + Ok(true) } } diff --git a/src/shims/foreign_items/posix/macos.rs b/src/shims/foreign_items/posix/macos.rs index c4bfb98562dbd..274248e8b54f7 100644 --- a/src/shims/foreign_items/posix/macos.rs +++ b/src/shims/foreign_items/posix/macos.rs @@ -1,4 +1,5 @@ use crate::*; +use rustc::mir; impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { @@ -7,7 +8,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx link_name: &str, args: &[OpTy<'tcx, Tag>], dest: PlaceTy<'tcx, Tag>, - ) -> InterpResult<'tcx> { + _ret: mir::BasicBlock, + ) -> InterpResult<'tcx, bool> { let this = self.eval_context_mut(); match link_name { @@ -108,7 +110,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx _ => throw_unsup_format!("can't call foreign function: {}", link_name), }; - Ok(()) + Ok(true) } } diff --git a/src/shims/foreign_items/windows.rs b/src/shims/foreign_items/windows.rs index e16a89a126fd1..b0d323439714a 100644 --- a/src/shims/foreign_items/windows.rs +++ b/src/shims/foreign_items/windows.rs @@ -1,4 +1,5 @@ use crate::*; +use rustc::mir; use rustc::ty::layout::Size; use std::iter; @@ -9,7 +10,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx link_name: &str, args: &[OpTy<'tcx, Tag>], dest: PlaceTy<'tcx, Tag>, - ) -> InterpResult<'tcx> { + _ret: mir::BasicBlock, + ) -> InterpResult<'tcx, bool> { let this = self.eval_context_mut(); let tcx = &{ this.tcx.tcx }; @@ -197,7 +199,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx _ => throw_unsup_format!("can't call foreign function: {}", link_name), } - Ok(()) + Ok(true) } } From bc7513bffd45c6dd52b94d29dd43e5c436c73d68 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Wed, 19 Feb 2020 16:52:34 -0500 Subject: [PATCH 1544/3747] move CreateThread to windows shims --- src/shims/foreign_items/posix.rs | 6 ++---- src/shims/foreign_items/windows.rs | 4 ++++ 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/shims/foreign_items/posix.rs b/src/shims/foreign_items/posix.rs index 746a0f25ebb1f..f50b640e17cde 100644 --- a/src/shims/foreign_items/posix.rs +++ b/src/shims/foreign_items/posix.rs @@ -240,10 +240,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_null(dest)?; } - // We don't support threading. (Also for Windows.) - | "pthread_create" - | "CreateThread" - => { + // We don't support threading. + "pthread_create" => { throw_unsup_format!("Miri does not support threading"); } diff --git a/src/shims/foreign_items/windows.rs b/src/shims/foreign_items/windows.rs index b0d323439714a..1eb84be0e3a0d 100644 --- a/src/shims/foreign_items/windows.rs +++ b/src/shims/foreign_items/windows.rs @@ -196,6 +196,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.gen_random(ptr, len as usize)?; this.write_scalar(Scalar::from_bool(true), dest)?; } + // We don't support threading. + "CreateThread" => { + throw_unsup_format!("Miri does not support threading"); + } _ => throw_unsup_format!("can't call foreign function: {}", link_name), } From 32bc015e35fb8665a77a368cc4a0b668be127f23 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Wed, 19 Feb 2020 17:03:00 -0500 Subject: [PATCH 1545/3747] reorganize comments for shim's classification --- src/shims/foreign_items/posix.rs | 1 + src/shims/foreign_items/posix/linux.rs | 1 + src/shims/foreign_items/posix/macos.rs | 2 +- src/shims/foreign_items/windows.rs | 11 +++++++---- 4 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/shims/foreign_items/posix.rs b/src/shims/foreign_items/posix.rs index f50b640e17cde..a4bc7e4726d0b 100644 --- a/src/shims/foreign_items/posix.rs +++ b/src/shims/foreign_items/posix.rs @@ -104,6 +104,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; } + // Other shims "posix_memalign" => { let ret = this.deref_operand(args[0])?; let align = this.read_scalar(args[1])?.to_machine_usize(this)?; diff --git a/src/shims/foreign_items/posix/linux.rs b/src/shims/foreign_items/posix/linux.rs index 27e42b0082e5a..cf1431c8f1170 100644 --- a/src/shims/foreign_items/posix/linux.rs +++ b/src/shims/foreign_items/posix/linux.rs @@ -40,6 +40,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; } + // Other shims "pthread_getattr_np" => { this.write_null(dest)?; } diff --git a/src/shims/foreign_items/posix/macos.rs b/src/shims/foreign_items/posix/macos.rs index 274248e8b54f7..d0bb3109424dd 100644 --- a/src/shims/foreign_items/posix/macos.rs +++ b/src/shims/foreign_items/posix/macos.rs @@ -55,7 +55,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; } - // macOS API stubs. + // Other shims "pthread_attr_get_np" => { this.write_null(dest)?; } diff --git a/src/shims/foreign_items/windows.rs b/src/shims/foreign_items/windows.rs index 1eb84be0e3a0d..29eac99e565cd 100644 --- a/src/shims/foreign_items/windows.rs +++ b/src/shims/foreign_items/windows.rs @@ -16,6 +16,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let tcx = &{ this.tcx.tcx }; match link_name { + // Windows API stubs. + // HANDLE = isize + // DWORD = ULONG = u32 + // BOOL = i32 + // Environment related shims "GetEnvironmentVariableW" => { // args[0] : LPCWSTR lpName (32-bit ptr to a const string of 16-bit Unicode chars) @@ -70,10 +75,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx dest, )?; } - // Windows API stubs. - // HANDLE = isize - // DWORD = ULONG = u32 - // BOOL = i32 + + // Other shims "GetProcessHeap" => { // Just fake a HANDLE this.write_scalar(Scalar::from_int(1, this.pointer_size()), dest)?; From dbef2340b293e1ad825c7ed2aadff24ad4991cc3 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Wed, 19 Feb 2020 17:09:12 -0500 Subject: [PATCH 1546/3747] add docs for `emulate_foreign_item_by_bame --- src/shims/foreign_items.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 14e08f5181f52..3df653d1741ab 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -178,6 +178,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(None) } + /// Emulates calling a foreign item using its name, failing if the item is not supported. + /// Returns Ok(false) if after calling this function, the call should return earlier instead of + /// going to the next block. fn emulate_foreign_item_by_name( &mut self, link_name: &str, From 9a7bc3972ceeeab709b277f0930c5becce5e9adf Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Wed, 19 Feb 2020 17:17:47 -0500 Subject: [PATCH 1547/3747] promote open and lseek shims to posix --- src/shims/foreign_items/posix.rs | 10 ++++++++++ src/shims/foreign_items/posix/linux.rs | 10 ---------- src/shims/foreign_items/posix/macos.rs | 10 ---------- 3 files changed, 10 insertions(+), 20 deletions(-) diff --git a/src/shims/foreign_items/posix.rs b/src/shims/foreign_items/posix.rs index a4bc7e4726d0b..6dc21d15b9f63 100644 --- a/src/shims/foreign_items/posix.rs +++ b/src/shims/foreign_items/posix.rs @@ -45,6 +45,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // File related shims + "open" | "open64" => { + let result = this.open(args[0], args[1])?; + this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + } + "fcntl" => { let result = this.fcntl(args[0], args[1], args.get(2).cloned())?; this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; @@ -104,6 +109,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; } + "lseek" | "lseek64" => { + let result = this.lseek64(args[0], args[1], args[2])?; + this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + } + // Other shims "posix_memalign" => { let ret = this.deref_operand(args[0])?; diff --git a/src/shims/foreign_items/posix/linux.rs b/src/shims/foreign_items/posix/linux.rs index cf1431c8f1170..1c03e3cb1cfeb 100644 --- a/src/shims/foreign_items/posix/linux.rs +++ b/src/shims/foreign_items/posix/linux.rs @@ -19,21 +19,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // File related shims - "open64" => { - let result = this.open(args[0], args[1])?; - this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; - } - "close" => { let result = this.close(args[0])?; this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; } - "lseek64" => { - let result = this.lseek64(args[0], args[1], args[2])?; - this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; - } - // Time related shims "clock_gettime" => { let result = this.clock_gettime(args[0], args[1])?; diff --git a/src/shims/foreign_items/posix/macos.rs b/src/shims/foreign_items/posix/macos.rs index d0bb3109424dd..bf7146267944f 100644 --- a/src/shims/foreign_items/posix/macos.rs +++ b/src/shims/foreign_items/posix/macos.rs @@ -19,11 +19,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // File related shims - "open" => { - let result = this.open(args[0], args[1])?; - this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; - } - "close$NOCANCEL" => { let result = this.close(args[0])?; this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; @@ -44,11 +39,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; } - "lseek" => { - let result = this.lseek64(args[0], args[1], args[2])?; - this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; - } - // Time related shims "gettimeofday" => { let result = this.gettimeofday(args[0], args[1])?; From b213f88b58b915097049d0432cbc83114f326959 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Wed, 19 Feb 2020 17:23:27 -0500 Subject: [PATCH 1548/3747] promote memrchr to work on any platform --- src/shims/foreign_items.rs | 18 ++++++++++++++++++ src/shims/foreign_items/posix.rs | 18 ------------------ 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 3df653d1741ab..59a6a41a6f39b 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -332,6 +332,24 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } + "memrchr" => { + let ptr = this.read_scalar(args[0])?.not_undef()?; + let val = this.read_scalar(args[1])?.to_i32()? as u8; + let num = this.read_scalar(args[2])?.to_machine_usize(this)?; + if let Some(idx) = this + .memory + .read_bytes(ptr, Size::from_bytes(num))? + .iter() + .rev() + .position(|&c| c == val) + { + let new_ptr = ptr.ptr_offset(Size::from_bytes(num - idx as u64 - 1), this)?; + this.write_scalar(new_ptr, dest)?; + } else { + this.write_null(dest)?; + } + } + "strlen" => { let ptr = this.read_scalar(args[0])?.not_undef()?; let n = this.memory.read_c_str(ptr)?.len(); diff --git a/src/shims/foreign_items/posix.rs b/src/shims/foreign_items/posix.rs index 6dc21d15b9f63..d82c7eddc7d7b 100644 --- a/src/shims/foreign_items/posix.rs +++ b/src/shims/foreign_items/posix.rs @@ -157,24 +157,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } - "memrchr" => { - let ptr = this.read_scalar(args[0])?.not_undef()?; - let val = this.read_scalar(args[1])?.to_i32()? as u8; - let num = this.read_scalar(args[2])?.to_machine_usize(this)?; - if let Some(idx) = this - .memory - .read_bytes(ptr, Size::from_bytes(num))? - .iter() - .rev() - .position(|&c| c == val) - { - let new_ptr = ptr.ptr_offset(Size::from_bytes(num - idx as u64 - 1), this)?; - this.write_scalar(new_ptr, dest)?; - } else { - this.write_null(dest)?; - } - } - // Hook pthread calls that go to the thread-local storage memory subsystem. "pthread_key_create" => { let key_place = this.deref_operand(args[0])?; From 3418b40dac84d124db68a10fb0e17668139751e9 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Wed, 19 Feb 2020 17:28:48 -0500 Subject: [PATCH 1549/3747] remove syscall shim from macos and move getrandom to linux module --- src/shims/foreign_items/posix.rs | 18 ------------------ src/shims/foreign_items/posix/linux.rs | 22 ++++++++++++++++++++-- src/shims/foreign_items/posix/macos.rs | 18 ------------------ 3 files changed, 20 insertions(+), 38 deletions(-) diff --git a/src/shims/foreign_items/posix.rs b/src/shims/foreign_items/posix.rs index d82c7eddc7d7b..a391baa0b22c6 100644 --- a/src/shims/foreign_items/posix.rs +++ b/src/shims/foreign_items/posix.rs @@ -333,21 +333,3 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(true) } } - -// Shims the posix 'getrandom()' syscall. -fn getrandom<'tcx>( - this: &mut MiriEvalContext<'_, 'tcx>, - args: &[OpTy<'tcx, Tag>], - dest: PlaceTy<'tcx, Tag>, -) -> InterpResult<'tcx> { - let ptr = this.read_scalar(args[0])?.not_undef()?; - let len = this.read_scalar(args[1])?.to_machine_usize(this)?; - - // The only supported flags are GRND_RANDOM and GRND_NONBLOCK, - // neither of which have any effect on our current PRNG. - let _flags = this.read_scalar(args[2])?.to_i32()?; - - this.gen_random(ptr, len as usize)?; - this.write_scalar(Scalar::from_uint(len, dest.layout.size), dest)?; - Ok(()) -} diff --git a/src/shims/foreign_items/posix/linux.rs b/src/shims/foreign_items/posix/linux.rs index 1c03e3cb1cfeb..8635455b1d7d4 100644 --- a/src/shims/foreign_items/posix/linux.rs +++ b/src/shims/foreign_items/posix/linux.rs @@ -52,7 +52,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx id if id == sys_getrandom => { // The first argument is the syscall id, // so skip over it. - super::getrandom(this, &args[1..], dest)?; + getrandom(this, &args[1..], dest)?; } id if id == sys_statx => { // The first argument is the syscall id, @@ -65,7 +65,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "getrandom" => { - super::getrandom(this, args, dest)?; + getrandom(this, args, dest)?; } "sched_getaffinity" => { @@ -79,3 +79,21 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(true) } } + +// Shims the posix 'getrandom()' syscall. +fn getrandom<'tcx>( + this: &mut MiriEvalContext<'_, 'tcx>, + args: &[OpTy<'tcx, Tag>], + dest: PlaceTy<'tcx, Tag>, +) -> InterpResult<'tcx> { + let ptr = this.read_scalar(args[0])?.not_undef()?; + let len = this.read_scalar(args[1])?.to_machine_usize(this)?; + + // The only supported flags are GRND_RANDOM and GRND_NONBLOCK, + // neither of which have any effect on our current PRNG. + let _flags = this.read_scalar(args[2])?.to_i32()?; + + this.gen_random(ptr, len as usize)?; + this.write_scalar(Scalar::from_uint(len, dest.layout.size), dest)?; + Ok(()) +} diff --git a/src/shims/foreign_items/posix/macos.rs b/src/shims/foreign_items/posix/macos.rs index bf7146267944f..8cfe959c3938f 100644 --- a/src/shims/foreign_items/posix/macos.rs +++ b/src/shims/foreign_items/posix/macos.rs @@ -79,24 +79,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_null(dest)?; } - "syscall" => { - let sys_getrandom = this - .eval_path_scalar(&["libc", "SYS_getrandom"])? - .expect("Failed to get libc::SYS_getrandom") - .to_machine_usize(this)?; - - match this.read_scalar(args[0])?.to_machine_usize(this)? { - // `libc::syscall(NR_GETRANDOM, buf.as_mut_ptr(), buf.len(), GRND_NONBLOCK)` - // is called if a `HashMap` is created the regular way (e.g. HashMap). - id if id == sys_getrandom => { - // The first argument is the syscall id, - // so skip over it. - super::getrandom(this, &args[1..], dest)?; - } - id => throw_unsup_format!("miri does not support syscall ID {}", id), - } - } - _ => throw_unsup_format!("can't call foreign function: {}", link_name), }; From bb3a711b3e28dc768c30925d78e6c2daaf00ab30 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Wed, 19 Feb 2020 17:53:33 -0500 Subject: [PATCH 1550/3747] rename platform specific shims --- src/shims/foreign_items/posix/linux.rs | 2 +- src/shims/foreign_items/posix/macos.rs | 6 +++--- src/shims/fs.rs | 20 ++++++++++---------- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/shims/foreign_items/posix/linux.rs b/src/shims/foreign_items/posix/linux.rs index 8635455b1d7d4..819da6804381d 100644 --- a/src/shims/foreign_items/posix/linux.rs +++ b/src/shims/foreign_items/posix/linux.rs @@ -57,7 +57,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx id if id == sys_statx => { // The first argument is the syscall id, // so skip over it. - let result = this.statx(args[1], args[2], args[3], args[4], args[5])?; + let result = this.linux_statx(args[1], args[2], args[3], args[4], args[5])?; this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; } id => throw_unsup_format!("miri does not support syscall ID {}", id), diff --git a/src/shims/foreign_items/posix/macos.rs b/src/shims/foreign_items/posix/macos.rs index 8cfe959c3938f..3698df95bd199 100644 --- a/src/shims/foreign_items/posix/macos.rs +++ b/src/shims/foreign_items/posix/macos.rs @@ -25,17 +25,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "stat$INODE64" => { - let result = this.stat(args[0], args[1])?; + let result = this.macos_stat(args[0], args[1])?; this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; } "lstat$INODE64" => { - let result = this.lstat(args[0], args[1])?; + let result = this.macos_lstat(args[0], args[1])?; this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; } "fstat$INODE64" => { - let result = this.fstat(args[0], args[1])?; + let result = this.macos_fstat(args[0], args[1])?; this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; } diff --git a/src/shims/fs.rs b/src/shims/fs.rs index 42a860780ff8b..afa71f654075a 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -340,7 +340,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.try_unwrap_io_result(create_link(target, linkpath).map(|_| 0)) } - fn stat( + fn macos_stat( &mut self, path_op: OpTy<'tcx, Tag>, buf_op: OpTy<'tcx, Tag>, @@ -349,11 +349,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.check_no_isolation("stat")?; this.check_platform("macos", "stat")?; // `stat` always follows symlinks. - this.stat_or_lstat(true, path_op, buf_op) + this.macos_stat_or_lstat(true, path_op, buf_op) } // `lstat` is used to get symlink metadata. - fn lstat( + fn macos_lstat( &mut self, path_op: OpTy<'tcx, Tag>, buf_op: OpTy<'tcx, Tag>, @@ -361,10 +361,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); this.check_no_isolation("lstat")?; this.check_platform("macos", "lstat")?; - this.stat_or_lstat(false, path_op, buf_op) + this.macos_stat_or_lstat(false, path_op, buf_op) } - fn fstat( + fn macos_fstat( &mut self, fd_op: OpTy<'tcx, Tag>, buf_op: OpTy<'tcx, Tag>, @@ -380,10 +380,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Some(metadata) => metadata, None => return Ok(-1), }; - stat_macos_write_buf(this, metadata, buf_op) + macos_stat_write_buf(this, metadata, buf_op) } - fn stat_or_lstat( + fn macos_stat_or_lstat( &mut self, follow_symlink: bool, path_op: OpTy<'tcx, Tag>, @@ -398,10 +398,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Some(metadata) => metadata, None => return Ok(-1), }; - stat_macos_write_buf(this, metadata, buf_op) + macos_stat_write_buf(this, metadata, buf_op) } - fn statx( + fn linux_statx( &mut self, dirfd_op: OpTy<'tcx, Tag>, // Should be an `int` pathname_op: OpTy<'tcx, Tag>, // Should be a `const char *` @@ -688,7 +688,7 @@ impl FileMetadata { } } -fn stat_macos_write_buf<'tcx, 'mir>( +fn macos_stat_write_buf<'tcx, 'mir>( ecx: &mut MiriEvalContext<'mir, 'tcx>, metadata: FileMetadata, buf_op: OpTy<'tcx, Tag>, From a60dfcf6e77e4335357a7b26de415d1e1bc21250 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 20 Feb 2020 11:09:12 +0100 Subject: [PATCH 1551/3747] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 12ac7b51b9989..00feed4764185 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -a2fb0c28be794f28028884650db70c17fea8e35b +de362d88ea17ab23ca2483cb798bc7aeb81a48f5 From 32a354efa3c089b1f47c8c72c24a6100422be5b8 Mon Sep 17 00:00:00 2001 From: David Cook Date: Thu, 20 Feb 2020 21:54:52 -0600 Subject: [PATCH 1552/3747] Test error case of std::fs::rename --- tests/run-pass/fs.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tests/run-pass/fs.rs b/tests/run-pass/fs.rs index 453432f64f105..a6ce8627cde7c 100644 --- a/tests/run-pass/fs.rs +++ b/tests/run-pass/fs.rs @@ -169,8 +169,16 @@ fn test_rename() { let file = File::create(&path1).unwrap(); drop(file); + + // Renaming should succeed rename(&path1, &path2).unwrap(); + // Check that the old file path isn't present assert_eq!(ErrorKind::NotFound, path1.metadata().unwrap_err().kind()); + // Check that the file has moved successfully assert!(path2.metadata().unwrap().is_file()); + + // Renaming a nonexistent file should fail + assert_eq!(ErrorKind::NotFound, rename(&path1, &path2).unwrap_err().kind()); + remove_file(&path2).unwrap(); } From 627d7cba644575467eb276a853acc07f7fcf2b33 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 21 Feb 2020 10:28:24 +0100 Subject: [PATCH 1553/3747] fix for const-prop lint changes --- rust-version | 2 +- tests/run-pass/panic/catch_panic.rs | 2 +- tests/run-pass/panic/div-by-zero-2.rs | 2 +- tests/run-pass/panic/overflowing-lsh-neg.rs | 3 +-- tests/run-pass/panic/overflowing-lsh-neg.stderr | 2 +- tests/run-pass/panic/overflowing-rsh-1.rs | 2 +- tests/run-pass/panic/overflowing-rsh-2.rs | 2 +- 7 files changed, 7 insertions(+), 8 deletions(-) diff --git a/rust-version b/rust-version index 00feed4764185..fe788019e0128 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -de362d88ea17ab23ca2483cb798bc7aeb81a48f5 +2851e59a52673e0242532035047009c6e121c95a diff --git a/tests/run-pass/panic/catch_panic.rs b/tests/run-pass/panic/catch_panic.rs index 4d4206923a5ef..21a6fee7c9211 100644 --- a/tests/run-pass/panic/catch_panic.rs +++ b/tests/run-pass/panic/catch_panic.rs @@ -1,7 +1,7 @@ // ignore-windows: Unwind panicking does not currently work on Windows // normalize-stderr-test "[^ ]*libcore/macros/mod.rs[0-9:]*" -> "$$LOC" #![feature(never_type)] -#![allow(const_err)] +#![allow(unconditional_panic)] use std::panic::{catch_unwind, AssertUnwindSafe}; use std::cell::Cell; diff --git a/tests/run-pass/panic/div-by-zero-2.rs b/tests/run-pass/panic/div-by-zero-2.rs index 6cc319bf0bc4b..cfacc9db0d666 100644 --- a/tests/run-pass/panic/div-by-zero-2.rs +++ b/tests/run-pass/panic/div-by-zero-2.rs @@ -1,5 +1,5 @@ // ignore-windows: Unwind panicking does not currently work on Windows -#![allow(const_err)] +#![allow(unconditional_panic)] fn main() { let _n = 1 / 0; diff --git a/tests/run-pass/panic/overflowing-lsh-neg.rs b/tests/run-pass/panic/overflowing-lsh-neg.rs index b214243c88f86..ee15ca0284ef3 100644 --- a/tests/run-pass/panic/overflowing-lsh-neg.rs +++ b/tests/run-pass/panic/overflowing-lsh-neg.rs @@ -1,6 +1,5 @@ // ignore-windows: Unwind panicking does not currently work on Windows -#![allow(exceeding_bitshifts)] -#![allow(const_err)] +#![allow(arithmetic_overflow)] fn main() { let _n = 2i64 << -1; diff --git a/tests/run-pass/panic/overflowing-lsh-neg.stderr b/tests/run-pass/panic/overflowing-lsh-neg.stderr index fe5a35e6b381d..e1e7daa119abd 100644 --- a/tests/run-pass/panic/overflowing-lsh-neg.stderr +++ b/tests/run-pass/panic/overflowing-lsh-neg.stderr @@ -1 +1 @@ -thread 'main' panicked at 'attempt to shift left with overflow', $DIR/overflowing-lsh-neg.rs:6:14 +thread 'main' panicked at 'attempt to shift left with overflow', $DIR/overflowing-lsh-neg.rs:5:14 diff --git a/tests/run-pass/panic/overflowing-rsh-1.rs b/tests/run-pass/panic/overflowing-rsh-1.rs index 68ea51d167316..36ab948a5efa0 100644 --- a/tests/run-pass/panic/overflowing-rsh-1.rs +++ b/tests/run-pass/panic/overflowing-rsh-1.rs @@ -1,5 +1,5 @@ // ignore-windows: Unwind panicking does not currently work on Windows -#![allow(exceeding_bitshifts, const_err)] +#![allow(arithmetic_overflow)] fn main() { let _n = 1i64 >> 64; diff --git a/tests/run-pass/panic/overflowing-rsh-2.rs b/tests/run-pass/panic/overflowing-rsh-2.rs index 4e287f20adf8f..da77a46a805e6 100644 --- a/tests/run-pass/panic/overflowing-rsh-2.rs +++ b/tests/run-pass/panic/overflowing-rsh-2.rs @@ -1,5 +1,5 @@ // ignore-windows: Unwind panicking does not currently work on Windows -#![allow(exceeding_bitshifts, const_err)] +#![allow(arithmetic_overflow)] fn main() { // Make sure we catch overflows that would be hidden by first casting the RHS to u32 From 0e7e5b9655cd1baab18e7ef28693cb22a94b3d0d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 21 Feb 2020 11:03:52 +0100 Subject: [PATCH 1554/3747] fix test-cargo-miri --- test-cargo-miri/tests/test.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test-cargo-miri/tests/test.rs b/test-cargo-miri/tests/test.rs index 4c196ef5e0f57..0095802a59a87 100644 --- a/test-cargo-miri/tests/test.rs +++ b/test-cargo-miri/tests/test.rs @@ -55,7 +55,7 @@ fn do_panic() { // In large, friendly letters :) // FIXME: see above #[test] -#[allow(const_err)] +#[allow(unconditional_panic)] #[cfg_attr(not(windows), should_panic(expected="the len is 0 but the index is 42"))] fn fail_index_check() { #[cfg(not(windows))] From 3e2f29a0796af501485e13cfa06302aa6e479d6a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 21 Feb 2020 11:05:56 +0100 Subject: [PATCH 1555/3747] remove some no-longer-needed allow(const_err) --- tests/run-pass/coerce_non_capture_closure_to_fn_ptr.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/tests/run-pass/coerce_non_capture_closure_to_fn_ptr.rs b/tests/run-pass/coerce_non_capture_closure_to_fn_ptr.rs index 32393a37d2ec4..bd8926aaf1ad5 100644 --- a/tests/run-pass/coerce_non_capture_closure_to_fn_ptr.rs +++ b/tests/run-pass/coerce_non_capture_closure_to_fn_ptr.rs @@ -1,7 +1,4 @@ -// allow(const_err) to work around a bug in warnings -#[allow(const_err)] static FOO: fn() = || { assert_ne!(42, 43) }; -#[allow(const_err)] static BAR: fn(i32, i32) = |a, b| { assert_ne!(a, b) }; // use to first make the closure FnOnce() before making it fn() From 08332bc73027e0dbe0601a63a82fd3917fa8531a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 21 Feb 2020 20:06:31 +0100 Subject: [PATCH 1556/3747] dont overwrite bootstrap flags --- src/bin/cargo-miri.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 9c6eab1ec7372..e990bc00277c1 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -381,8 +381,6 @@ path = "lib.rs" command.env("RUSTFLAGS", miri::miri_default_args().join(" ")); command.env("XARGO_HOME", &dir); command.env("XARGO_RUST_SRC", &rust_src); - // In bootstrap, make sure we don't get debug assertons into our libstd. - command.env("RUSTC_DEBUG_ASSERTIONS", "false"); // Handle target flag. if let Some(ref target) = target { command.arg("--target").arg(&target); From 9e9a0900261946b726137637dfbd4a70fa83f233 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Sat, 22 Feb 2020 02:18:42 -0500 Subject: [PATCH 1557/3747] minor fixes --- src/helpers.rs | 2 +- src/shims/foreign_items.rs | 26 +++++++++++++------------- src/shims/foreign_items/posix/linux.rs | 4 +++- 3 files changed, 17 insertions(+), 15 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index c92aa6dfaa7cb..2ce4ca6c91dc2 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -374,7 +374,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn check_platform(&mut self, platform: &str, name: &str) -> InterpResult<'tcx> { if self.eval_context_mut().tcx.sess.target.target.target_os.to_lowercase() != platform { throw_unsup_format!( - "`{}` is only available in the `{}` platform", + "`{}` is only available on the `{}` platform", name, platform, ) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 59a6a41a6f39b..37296132c038b 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -179,8 +179,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } /// Emulates calling a foreign item using its name, failing if the item is not supported. - /// Returns Ok(false) if after calling this function, the call should return earlier instead of - /// going to the next block. + /// Returns `true` if the caller is expected to jump to the return block, and `false` if + /// jumping has already been taken care of. fn emulate_foreign_item_by_name( &mut self, link_name: &str, @@ -315,35 +315,35 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_int(result, Size::from_bits(32)), dest)?; } - "memchr" => { + "memrchr" => { let ptr = this.read_scalar(args[0])?.not_undef()?; let val = this.read_scalar(args[1])?.to_i32()? as u8; let num = this.read_scalar(args[2])?.to_machine_usize(this)?; - let idx = this + if let Some(idx) = this .memory .read_bytes(ptr, Size::from_bytes(num))? .iter() - .position(|&c| c == val); - if let Some(idx) = idx { - let new_ptr = ptr.ptr_offset(Size::from_bytes(idx as u64), this)?; + .rev() + .position(|&c| c == val) + { + let new_ptr = ptr.ptr_offset(Size::from_bytes(num - idx as u64 - 1), this)?; this.write_scalar(new_ptr, dest)?; } else { this.write_null(dest)?; } } - "memrchr" => { + "memchr" => { let ptr = this.read_scalar(args[0])?.not_undef()?; let val = this.read_scalar(args[1])?.to_i32()? as u8; let num = this.read_scalar(args[2])?.to_machine_usize(this)?; - if let Some(idx) = this + let idx = this .memory .read_bytes(ptr, Size::from_bytes(num))? .iter() - .rev() - .position(|&c| c == val) - { - let new_ptr = ptr.ptr_offset(Size::from_bytes(num - idx as u64 - 1), this)?; + .position(|&c| c == val); + if let Some(idx) = idx { + let new_ptr = ptr.ptr_offset(Size::from_bytes(idx as u64), this)?; this.write_scalar(new_ptr, dest)?; } else { this.write_null(dest)?; diff --git a/src/shims/foreign_items/posix/linux.rs b/src/shims/foreign_items/posix/linux.rs index 819da6804381d..098d05663543e 100644 --- a/src/shims/foreign_items/posix/linux.rs +++ b/src/shims/foreign_items/posix/linux.rs @@ -25,6 +25,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // Time related shims + + // This is a POSIX function but it has only been tested on linux. "clock_gettime" => { let result = this.clock_gettime(args[0], args[1])?; this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; @@ -80,7 +82,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } -// Shims the posix 'getrandom()' syscall. +// Shims the linux 'getrandom()' syscall. fn getrandom<'tcx>( this: &mut MiriEvalContext<'_, 'tcx>, args: &[OpTy<'tcx, Tag>], From 86a4354746c81d06fc09c5c0633449a26bee442a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 21 Feb 2020 08:34:25 +0100 Subject: [PATCH 1558/3747] fix README --- README.md | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 1f008e735ec2c..f16751cd74783 100644 --- a/README.md +++ b/README.md @@ -171,11 +171,10 @@ Several `-Z` flags are relevant for Miri: sets this flag per default. * `-Zmir-emit-retag` controls whether `Retag` statements are emitted. Miri enables this per default because it is needed for validation. -* `-Zmiri-track-pointer-tag=` aborts interpretation with a backtrace when the - given pointer tag is popped from a borrow stack (which is where the tag - becomes invalid and any future use of it will error anyway). This helps you - in finding out why UB is happening and where in your code would be a good - place to look for it. +* `-Zmiri-track-pointer-tag=` shows a backtrace when the given pointer tag + is popped from a borrow stack (which is where the tag becomes invalid and any + future use of it will error). This helps you in finding out why UB is + happening and where in your code would be a good place to look for it. Moreover, Miri recognizes some environment variables: From c2bcab55b09db9adc5d33b48011a31587a8e80a1 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Sat, 22 Feb 2020 08:55:45 -0500 Subject: [PATCH 1559/3747] improve docs --- src/shims/foreign_items/posix/linux.rs | 5 +++++ src/shims/foreign_items/posix/macos.rs | 3 +++ src/shims/fs.rs | 4 ++++ 3 files changed, 12 insertions(+) diff --git a/src/shims/foreign_items/posix/linux.rs b/src/shims/foreign_items/posix/linux.rs index 098d05663543e..9da54b6d40702 100644 --- a/src/shims/foreign_items/posix/linux.rs +++ b/src/shims/foreign_items/posix/linux.rs @@ -19,6 +19,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // File related shims + + // The only reason this is not in the `posix` module is because the `macos` item has a + // different name. "close" => { let result = this.close(args[0])?; this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; @@ -56,6 +59,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // so skip over it. getrandom(this, &args[1..], dest)?; } + // `statx` is used by `libstd` to retrieve metadata information in `linux` + // instead of using `stat`,`lstat` or `fstat` as in the `macos` platform. id if id == sys_statx => { // The first argument is the syscall id, // so skip over it. diff --git a/src/shims/foreign_items/posix/macos.rs b/src/shims/foreign_items/posix/macos.rs index 3698df95bd199..25ac7e93867f2 100644 --- a/src/shims/foreign_items/posix/macos.rs +++ b/src/shims/foreign_items/posix/macos.rs @@ -19,6 +19,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // File related shims + + // The only reason this is not in the `posix` module is because the `linux` item has a + // different name. "close$NOCANCEL" => { let result = this.close(args[0])?; this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; diff --git a/src/shims/fs.rs b/src/shims/fs.rs index afa71f654075a..b3d8d6a0ac7ff 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -383,6 +383,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx macos_stat_write_buf(this, metadata, buf_op) } + /// Emulate `stat` or `lstat` on the `macos` platform. This function is not intended to be + /// called directly from `emulate_foreign_item_by_name`, so it does not check if isolation is + /// disabled or if the target platform is the correct one. Please use `macos_stat` or + /// `macos_lstat` instead. fn macos_stat_or_lstat( &mut self, follow_symlink: bool, From 208665836eef558e92925e48bf35d162dfd4d5a3 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Sat, 22 Feb 2020 09:02:25 -0500 Subject: [PATCH 1560/3747] panic if target platform is incorrect instead --- src/helpers.rs | 23 +++++++++++------------ src/shims/fs.rs | 8 ++++---- 2 files changed, 15 insertions(+), 16 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index 2ce4ca6c91dc2..2ae6910fce2dc 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -368,18 +368,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } Ok(()) } - /// Helper function used inside the shims of foreign functions to check that the target - /// platform is `platform`. It returns an error using the `name` of the foreign function if - /// this is not the case. - fn check_platform(&mut self, platform: &str, name: &str) -> InterpResult<'tcx> { - if self.eval_context_mut().tcx.sess.target.target.target_os.to_lowercase() != platform { - throw_unsup_format!( - "`{}` is only available on the `{}` platform", - name, - platform, - ) - } - Ok(()) + /// Helper function used inside the shims of foreign functions to assert that the target + /// platform is `platform`. It panics showing a message with the `name` of the foreign function + /// if this is not the case. + fn assert_platform(&mut self, platform: &str, name: &str) { + assert_eq!( + self.eval_context_mut().tcx.sess.target.target.target_os.to_lowercase(), + platform, + "`{}` is only available on the `{}` platform", + name, + platform + ) } /// Sets the last error variable. diff --git a/src/shims/fs.rs b/src/shims/fs.rs index b3d8d6a0ac7ff..f846c339defe0 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -347,7 +347,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); this.check_no_isolation("stat")?; - this.check_platform("macos", "stat")?; + this.assert_platform("macos", "stat"); // `stat` always follows symlinks. this.macos_stat_or_lstat(true, path_op, buf_op) } @@ -360,7 +360,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); this.check_no_isolation("lstat")?; - this.check_platform("macos", "lstat")?; + this.assert_platform("macos", "lstat"); this.macos_stat_or_lstat(false, path_op, buf_op) } @@ -372,7 +372,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); this.check_no_isolation("fstat")?; - this.check_platform("macos", "fstat")?; + this.assert_platform("macos", "fstat"); let fd = this.read_scalar(fd_op)?.to_i32()?; @@ -416,7 +416,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); this.check_no_isolation("statx")?; - this.check_platform("linux", "statx")?; + this.assert_platform("linux", "statx"); let statxbuf_scalar = this.read_scalar(statxbuf_op)?.not_undef()?; let pathname_scalar = this.read_scalar(pathname_op)?.not_undef()?; From 5d3554898524c01bb85a12367fc9e36f27bcfe05 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 23 Feb 2020 18:44:40 +0100 Subject: [PATCH 1561/3747] helpers.rs cleanup --- src/helpers.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index 2ae6910fce2dc..a387827650592 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -359,11 +359,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// Helper function used inside the shims of foreign functions to check that isolation is /// disabled. It returns an error using the `name` of the foreign function if this is not the /// case. - fn check_no_isolation(&mut self, name: &str) -> InterpResult<'tcx> { - if !self.eval_context_mut().machine.communicate { + fn check_no_isolation(&self, name: &str) -> InterpResult<'tcx> { + if !self.eval_context_ref().machine.communicate { throw_unsup_format!( "`{}` not available when isolation is enabled. Pass the flag `-Zmiri-disable-isolation` to disable it.", - name + name, ) } Ok(()) @@ -371,13 +371,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// Helper function used inside the shims of foreign functions to assert that the target /// platform is `platform`. It panics showing a message with the `name` of the foreign function /// if this is not the case. - fn assert_platform(&mut self, platform: &str, name: &str) { + fn assert_platform(&self, platform: &str, name: &str) { assert_eq!( - self.eval_context_mut().tcx.sess.target.target.target_os.to_lowercase(), + self.eval_context_ref().tcx.sess.target.target.target_os.to_lowercase(), platform, "`{}` is only available on the `{}` platform", name, - platform + platform, ) } @@ -389,8 +389,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } /// Gets the last error variable. - fn get_last_error(&mut self) -> InterpResult<'tcx, Scalar> { - let this = self.eval_context_mut(); + fn get_last_error(&self) -> InterpResult<'tcx, Scalar> { + let this = self.eval_context_ref(); let errno_place = this.machine.last_error.unwrap(); this.read_scalar(errno_place.into())?.not_undef() } From beb82ea4a41ba582dca6391fa622bfbb4d987226 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 23 Feb 2020 18:48:38 +0100 Subject: [PATCH 1562/3747] add private helper trait for fs shim --- src/shims/fs.rs | 195 +++++++++++++++++++++++++----------------------- 1 file changed, 100 insertions(+), 95 deletions(-) diff --git a/src/shims/fs.rs b/src/shims/fs.rs index a51a2f5250853..aa562926686dc 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -63,6 +63,105 @@ impl FileHandler { } } +impl<'mir, 'tcx> EvalContextExtPrivate<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} +trait EvalContextExtPrivate<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { + /// Emulate `stat` or `lstat` on the `macos` platform. This function is not intended to be + /// called directly from `emulate_foreign_item_by_name`, so it does not check if isolation is + /// disabled or if the target platform is the correct one. Please use `macos_stat` or + /// `macos_lstat` instead. + fn macos_stat_or_lstat( + &mut self, + follow_symlink: bool, + path_op: OpTy<'tcx, Tag>, + buf_op: OpTy<'tcx, Tag>, + ) -> InterpResult<'tcx, i32> { + let this = self.eval_context_mut(); + + let path_scalar = this.read_scalar(path_op)?.not_undef()?; + let path: PathBuf = this.read_os_str_from_c_str(path_scalar)?.into(); + + let metadata = match FileMetadata::from_path(this, path, follow_symlink)? { + Some(metadata) => metadata, + None => return Ok(-1), + }; + this.macos_stat_write_buf(metadata, buf_op) + } + + fn macos_stat_write_buf( + &mut self, + metadata: FileMetadata, + buf_op: OpTy<'tcx, Tag>, + ) -> InterpResult<'tcx, i32> { + let this = self.eval_context_mut(); + + let mode: u16 = metadata.mode.to_u16()?; + + let (access_sec, access_nsec) = metadata.accessed.unwrap_or((0, 0)); + let (created_sec, created_nsec) = metadata.created.unwrap_or((0, 0)); + let (modified_sec, modified_nsec) = metadata.modified.unwrap_or((0, 0)); + + let dev_t_layout = this.libc_ty_layout("dev_t")?; + let mode_t_layout = this.libc_ty_layout("mode_t")?; + let nlink_t_layout = this.libc_ty_layout("nlink_t")?; + let ino_t_layout = this.libc_ty_layout("ino_t")?; + let uid_t_layout = this.libc_ty_layout("uid_t")?; + let gid_t_layout = this.libc_ty_layout("gid_t")?; + let time_t_layout = this.libc_ty_layout("time_t")?; + let long_layout = this.libc_ty_layout("c_long")?; + let off_t_layout = this.libc_ty_layout("off_t")?; + let blkcnt_t_layout = this.libc_ty_layout("blkcnt_t")?; + let blksize_t_layout = this.libc_ty_layout("blksize_t")?; + let uint32_t_layout = this.libc_ty_layout("uint32_t")?; + + // We need to add 32 bits of padding after `st_rdev` if we are on a 64-bit platform. + let pad_layout = if this.tcx.sess.target.ptr_width == 64 { + uint32_t_layout + } else { + this.layout_of(this.tcx.mk_unit())? + }; + + let imms = [ + immty_from_uint_checked(0u128, dev_t_layout)?, // st_dev + immty_from_uint_checked(mode, mode_t_layout)?, // st_mode + immty_from_uint_checked(0u128, nlink_t_layout)?, // st_nlink + immty_from_uint_checked(0u128, ino_t_layout)?, // st_ino + immty_from_uint_checked(0u128, uid_t_layout)?, // st_uid + immty_from_uint_checked(0u128, gid_t_layout)?, // st_gid + immty_from_uint_checked(0u128, dev_t_layout)?, // st_rdev + immty_from_uint_checked(0u128, pad_layout)?, // padding for 64-bit targets + immty_from_uint_checked(access_sec, time_t_layout)?, // st_atime + immty_from_uint_checked(access_nsec, long_layout)?, // st_atime_nsec + immty_from_uint_checked(modified_sec, time_t_layout)?, // st_mtime + immty_from_uint_checked(modified_nsec, long_layout)?, // st_mtime_nsec + immty_from_uint_checked(0u128, time_t_layout)?, // st_ctime + immty_from_uint_checked(0u128, long_layout)?, // st_ctime_nsec + immty_from_uint_checked(created_sec, time_t_layout)?, // st_birthtime + immty_from_uint_checked(created_nsec, long_layout)?, // st_birthtime_nsec + immty_from_uint_checked(metadata.size, off_t_layout)?, // st_size + immty_from_uint_checked(0u128, blkcnt_t_layout)?, // st_blocks + immty_from_uint_checked(0u128, blksize_t_layout)?, // st_blksize + immty_from_uint_checked(0u128, uint32_t_layout)?, // st_flags + immty_from_uint_checked(0u128, uint32_t_layout)?, // st_gen + ]; + + let buf = this.deref_operand(buf_op)?; + this.write_packed_immediates(buf, &imms)?; + + Ok(0) + } + + /// Function used when a handle is not found inside `FileHandler`. It returns `Ok(-1)`and sets + /// the last OS error to `libc::EBADF` (invalid file descriptor). This function uses + /// `T: From` instead of `i32` directly because some fs functions return different integer + /// types (like `read`, that returns an `i64`). + fn handle_not_found>(&mut self) -> InterpResult<'tcx, T> { + let this = self.eval_context_mut(); + let ebadf = this.eval_libc("EBADF")?; + this.set_last_error(ebadf)?; + Ok((-1).into()) + } +} + impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { fn open( @@ -432,29 +531,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Some(metadata) => metadata, None => return Ok(-1), }; - macos_stat_write_buf(this, metadata, buf_op) - } - - /// Emulate `stat` or `lstat` on the `macos` platform. This function is not intended to be - /// called directly from `emulate_foreign_item_by_name`, so it does not check if isolation is - /// disabled or if the target platform is the correct one. Please use `macos_stat` or - /// `macos_lstat` instead. - fn macos_stat_or_lstat( - &mut self, - follow_symlink: bool, - path_op: OpTy<'tcx, Tag>, - buf_op: OpTy<'tcx, Tag>, - ) -> InterpResult<'tcx, i32> { - let this = self.eval_context_mut(); - - let path_scalar = this.read_scalar(path_op)?.not_undef()?; - let path: PathBuf = this.read_os_str_from_c_str(path_scalar)?.into(); - - let metadata = match FileMetadata::from_path(this, path, follow_symlink)? { - Some(metadata) => metadata, - None => return Ok(-1), - }; - macos_stat_write_buf(this, metadata, buf_op) + this.macos_stat_write_buf(metadata, buf_op) } fn linux_statx( @@ -620,17 +697,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(0) } - /// Function used when a handle is not found inside `FileHandler`. It returns `Ok(-1)`and sets - /// the last OS error to `libc::EBADF` (invalid file descriptor). This function uses - /// `T: From` instead of `i32` directly because some fs functions return different integer - /// types (like `read`, that returns an `i64`). - fn handle_not_found>(&mut self) -> InterpResult<'tcx, T> { - let this = self.eval_context_mut(); - let ebadf = this.eval_libc("EBADF")?; - this.set_last_error(ebadf)?; - Ok((-1).into()) - } - fn rename( &mut self, oldpath_op: OpTy<'tcx, Tag>, @@ -743,64 +809,3 @@ impl FileMetadata { Ok(Some(FileMetadata { mode, size, created, accessed, modified })) } } - -fn macos_stat_write_buf<'tcx, 'mir>( - ecx: &mut MiriEvalContext<'mir, 'tcx>, - metadata: FileMetadata, - buf_op: OpTy<'tcx, Tag>, -) -> InterpResult<'tcx, i32> { - let mode: u16 = metadata.mode.to_u16()?; - - let (access_sec, access_nsec) = metadata.accessed.unwrap_or((0, 0)); - let (created_sec, created_nsec) = metadata.created.unwrap_or((0, 0)); - let (modified_sec, modified_nsec) = metadata.modified.unwrap_or((0, 0)); - - let dev_t_layout = ecx.libc_ty_layout("dev_t")?; - let mode_t_layout = ecx.libc_ty_layout("mode_t")?; - let nlink_t_layout = ecx.libc_ty_layout("nlink_t")?; - let ino_t_layout = ecx.libc_ty_layout("ino_t")?; - let uid_t_layout = ecx.libc_ty_layout("uid_t")?; - let gid_t_layout = ecx.libc_ty_layout("gid_t")?; - let time_t_layout = ecx.libc_ty_layout("time_t")?; - let long_layout = ecx.libc_ty_layout("c_long")?; - let off_t_layout = ecx.libc_ty_layout("off_t")?; - let blkcnt_t_layout = ecx.libc_ty_layout("blkcnt_t")?; - let blksize_t_layout = ecx.libc_ty_layout("blksize_t")?; - let uint32_t_layout = ecx.libc_ty_layout("uint32_t")?; - - // We need to add 32 bits of padding after `st_rdev` if we are on a 64-bit platform. - let pad_layout = if ecx.tcx.sess.target.ptr_width == 64 { - uint32_t_layout - } else { - ecx.layout_of(ecx.tcx.mk_unit())? - }; - - let imms = [ - immty_from_uint_checked(0u128, dev_t_layout)?, // st_dev - immty_from_uint_checked(mode, mode_t_layout)?, // st_mode - immty_from_uint_checked(0u128, nlink_t_layout)?, // st_nlink - immty_from_uint_checked(0u128, ino_t_layout)?, // st_ino - immty_from_uint_checked(0u128, uid_t_layout)?, // st_uid - immty_from_uint_checked(0u128, gid_t_layout)?, // st_gid - immty_from_uint_checked(0u128, dev_t_layout)?, // st_rdev - immty_from_uint_checked(0u128, pad_layout)?, // padding for 64-bit targets - immty_from_uint_checked(access_sec, time_t_layout)?, // st_atime - immty_from_uint_checked(access_nsec, long_layout)?, // st_atime_nsec - immty_from_uint_checked(modified_sec, time_t_layout)?, // st_mtime - immty_from_uint_checked(modified_nsec, long_layout)?, // st_mtime_nsec - immty_from_uint_checked(0u128, time_t_layout)?, // st_ctime - immty_from_uint_checked(0u128, long_layout)?, // st_ctime_nsec - immty_from_uint_checked(created_sec, time_t_layout)?, // st_birthtime - immty_from_uint_checked(created_nsec, long_layout)?, // st_birthtime_nsec - immty_from_uint_checked(metadata.size, off_t_layout)?, // st_size - immty_from_uint_checked(0u128, blkcnt_t_layout)?, // st_blocks - immty_from_uint_checked(0u128, blksize_t_layout)?, // st_blksize - immty_from_uint_checked(0u128, uint32_t_layout)?, // st_flags - immty_from_uint_checked(0u128, uint32_t_layout)?, // st_gen - ]; - - let buf = ecx.deref_operand(buf_op)?; - ecx.write_packed_immediates(buf, &imms)?; - - Ok(0) -} From e575fb1f57c693efd07322cddd7e69e19da82a1c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 23 Feb 2020 18:48:44 +0100 Subject: [PATCH 1563/3747] improve comments --- src/shims/foreign_items/posix/linux.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/shims/foreign_items/posix/linux.rs b/src/shims/foreign_items/posix/linux.rs index 9da54b6d40702..4d3e1798ce148 100644 --- a/src/shims/foreign_items/posix/linux.rs +++ b/src/shims/foreign_items/posix/linux.rs @@ -18,7 +18,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(errno_place.to_ref().to_scalar()?, dest)?; } - // File related shims + // File related shims (but also see "syscall" below for statx) // The only reason this is not in the `posix` module is because the `macos` item has a // different name. @@ -59,8 +59,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // so skip over it. getrandom(this, &args[1..], dest)?; } - // `statx` is used by `libstd` to retrieve metadata information in `linux` - // instead of using `stat`,`lstat` or `fstat` as in the `macos` platform. + // `statx` is used by `libstd` to retrieve metadata information on `linux` + // instead of using `stat`,`lstat` or `fstat` as on `macos`. id if id == sys_statx => { // The first argument is the syscall id, // so skip over it. @@ -87,7 +87,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } -// Shims the linux 'getrandom()' syscall. +// Shims the linux `getrandom` syscall. fn getrandom<'tcx>( this: &mut MiriEvalContext<'_, 'tcx>, args: &[OpTy<'tcx, Tag>], From 4a9a0a9078bd57a200c1c4d83a7ebf2e3690e3c8 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 23 Feb 2020 18:54:08 +0100 Subject: [PATCH 1564/3747] avoid lowercasing platforms --- src/eval.rs | 2 +- src/helpers.rs | 2 +- src/shims/foreign_items.rs | 2 +- src/shims/foreign_items/posix.rs | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/eval.rs b/src/eval.rs index 7a3945220f772..9ce3d2b08c23e 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -169,7 +169,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) -> Option { // FIXME: We always ignore leaks on some platforms where we do not // correctly implement TLS destructors. - let target_os = tcx.sess.target.target.target_os.to_lowercase(); + let target_os = tcx.sess.target.target.target_os.as_str(); let ignore_leaks = config.ignore_leaks || target_os == "windows" || target_os == "macos"; let (mut ecx, ret_place) = match create_ecx(tcx, main_id, config) { diff --git a/src/helpers.rs b/src/helpers.rs index a387827650592..5128176acb58c 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -373,7 +373,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// if this is not the case. fn assert_platform(&self, platform: &str, name: &str) { assert_eq!( - self.eval_context_ref().tcx.sess.target.target.target_os.to_lowercase(), + self.eval_context_ref().tcx.sess.target.target.target_os, platform, "`{}` is only available on the `{}` platform", name, diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 37296132c038b..3d8d3bd52607a 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -455,7 +455,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_f64(res), dest)?; } - _ => match this.tcx.sess.target.target.target_os.to_lowercase().as_str() { + _ => match this.tcx.sess.target.target.target_os.as_str() { "linux" | "macos" => return posix::EvalContextExt::emulate_foreign_item_by_name(this, link_name, args, dest, ret), "windows" => return windows::EvalContextExt::emulate_foreign_item_by_name(this, link_name, args, dest, ret), target => throw_unsup_format!("The {} target platform is not supported", target), diff --git a/src/shims/foreign_items/posix.rs b/src/shims/foreign_items/posix.rs index a391baa0b22c6..a8b4aad8819b0 100644 --- a/src/shims/foreign_items/posix.rs +++ b/src/shims/foreign_items/posix.rs @@ -322,7 +322,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } _ => { - match this.tcx.sess.target.target.target_os.to_lowercase().as_str() { + match this.tcx.sess.target.target.target_os.as_str() { "linux" => return linux::EvalContextExt::emulate_foreign_item_by_name(this, link_name, args, dest, ret), "macos" => return macos::EvalContextExt::emulate_foreign_item_by_name(this, link_name, args, dest, ret), _ => unreachable!(), From 5b34f06bae63f9da496a907408789e17fc2ead0b Mon Sep 17 00:00:00 2001 From: David Cook Date: Fri, 24 Jan 2020 18:56:23 -0600 Subject: [PATCH 1565/3747] Add shims for mkdir and rmdir --- src/shims/foreign_items/posix.rs | 10 ++++++++ src/shims/fs.rs | 41 +++++++++++++++++++++++++++++++- tests/run-pass/fs.rs | 24 ++++++++++++++++++- 3 files changed, 73 insertions(+), 2 deletions(-) diff --git a/src/shims/foreign_items/posix.rs b/src/shims/foreign_items/posix.rs index a8b4aad8819b0..e520e23199e3c 100644 --- a/src/shims/foreign_items/posix.rs +++ b/src/shims/foreign_items/posix.rs @@ -109,6 +109,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; } + "mkdir" => { + let result = this.mkdir(args[0], args[1])?; + this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + } + + "rmdir" => { + let result = this.rmdir(args[0])?; + this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + } + "lseek" | "lseek64" => { let result = this.lseek64(args[0], args[1], args[2])?; this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; diff --git a/src/shims/fs.rs b/src/shims/fs.rs index aa562926686dc..45471a638a18e 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -1,6 +1,6 @@ use std::collections::BTreeMap; use std::convert::{TryFrom, TryInto}; -use std::fs::{remove_file, rename, File, OpenOptions}; +use std::fs::{remove_dir, remove_file, rename, DirBuilder, File, OpenOptions}; use std::io::{Read, Seek, SeekFrom, Write}; use std::path::PathBuf; use std::time::SystemTime; @@ -722,6 +722,45 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.try_unwrap_io_result(result) } + + fn mkdir( + &mut self, + path_op: OpTy<'tcx, Tag>, + mode_op: OpTy<'tcx, Tag>, + ) -> InterpResult<'tcx, i32> { + let this = self.eval_context_mut(); + + this.check_no_isolation("mkdir")?; + + let mode = this.read_scalar(mode_op)?.to_u32()?; + + let path = this.read_os_str_from_c_str(this.read_scalar(path_op)?.not_undef()?)?; + + let mut builder = DirBuilder::new(); + #[cfg(target_family = "unix")] + { + use std::os::unix::fs::DirBuilderExt; + builder.mode(mode); + } + let result = builder.create(path).map(|_| 0i32); + + this.try_unwrap_io_result(result) + } + + fn rmdir( + &mut self, + path_op: OpTy<'tcx, Tag>, + ) -> InterpResult<'tcx, i32> { + let this = self.eval_context_mut(); + + this.check_no_isolation("rmdir")?; + + let path = this.read_os_str_from_c_str(this.read_scalar(path_op)?.not_undef()?)?; + + let result = remove_dir(path).map(|_| 0i32); + + this.try_unwrap_io_result(result) + } } /// Extracts the number of seconds and nanoseconds elapsed between `time` and the unix epoch when diff --git a/tests/run-pass/fs.rs b/tests/run-pass/fs.rs index a6ce8627cde7c..7f920d8c19d8e 100644 --- a/tests/run-pass/fs.rs +++ b/tests/run-pass/fs.rs @@ -1,7 +1,7 @@ // ignore-windows: File handling is not implemented yet // compile-flags: -Zmiri-disable-isolation -use std::fs::{File, remove_file, rename}; +use std::fs::{File, create_dir, remove_dir, remove_dir_all, remove_file, rename}; use std::io::{Read, Write, ErrorKind, Result, Seek, SeekFrom}; use std::path::{PathBuf, Path}; @@ -13,6 +13,7 @@ fn main() { test_symlink(); test_errors(); test_rename(); + test_directory(); } /// Prepare: compute filename and make sure the file does not exist. @@ -24,6 +25,15 @@ fn prepare(filename: &str) -> PathBuf { path } +/// Prepare directory: compute directory name and make sure it does not exist. +fn prepare_dir(dirname: &str) -> PathBuf { + let tmp = std::env::temp_dir(); + let path = tmp.join(&dirname); + // Clean the directory for robustness. + remove_dir_all(&path).ok(); + path +} + /// Prepare like above, and also write some initial content to the file. fn prepare_with_content(filename: &str, content: &[u8]) -> PathBuf { let path = prepare(filename); @@ -182,3 +192,15 @@ fn test_rename() { remove_file(&path2).unwrap(); } + +fn test_directory() { + let dir_path = prepare_dir("miri_test_fs_dir"); + // Creating a directory should succeed. + create_dir(&dir_path).unwrap(); + // Test that the metadata of a directory is correct. + assert!(dir_path.metadata().unwrap().is_dir()); + // Deleting the directory should succeed. + remove_dir(&dir_path).unwrap(); + // Reading the metadata of a non-existent file should fail with a "not found" error. + assert_eq!(ErrorKind::NotFound, check_metadata(&[], &dir_path).unwrap_err().kind()); +} From d7c3f588eb78917952aab237c11a0edaae3c84f3 Mon Sep 17 00:00:00 2001 From: David Cook Date: Sat, 25 Jan 2020 12:57:15 -0600 Subject: [PATCH 1566/3747] Add shims for opendir and closedir --- src/lib.rs | 2 +- src/machine.rs | 2 + src/shims/foreign_items/posix.rs | 5 +++ src/shims/foreign_items/posix/linux.rs | 7 ++++ src/shims/fs.rs | 57 +++++++++++++++++++++++++- 5 files changed, 71 insertions(+), 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 85ee98aa3a123..0c4439287b329 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -36,7 +36,7 @@ pub use rustc_mir::interpret::{self, AllocMap, PlaceTy}; pub use crate::shims::dlsym::{Dlsym, EvalContextExt as DlsymEvalContextExt}; pub use crate::shims::env::{EnvVars, EvalContextExt as EnvEvalContextExt}; pub use crate::shims::foreign_items::EvalContextExt as ForeignItemsEvalContextExt; -pub use crate::shims::fs::{EvalContextExt as FileEvalContextExt, FileHandler}; +pub use crate::shims::fs::{DirHandler, EvalContextExt as FileEvalContextExt, FileHandler}; pub use crate::shims::intrinsics::EvalContextExt as IntrinsicsEvalContextExt; pub use crate::shims::panic::{CatchUnwindData, EvalContextExt as PanicEvalContextExt}; pub use crate::shims::time::EvalContextExt as TimeEvalContextExt; diff --git a/src/machine.rs b/src/machine.rs index 5d933fe8a7f60..a6bb35c811aae 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -115,6 +115,7 @@ pub struct Evaluator<'tcx> { pub(crate) communicate: bool, pub(crate) file_handler: FileHandler, + pub(crate) dir_handler: DirHandler, /// The temporary used for storing the argument of /// the call to `miri_start_panic` (the panic payload) when unwinding. @@ -134,6 +135,7 @@ impl<'tcx> Evaluator<'tcx> { tls: TlsData::default(), communicate, file_handler: Default::default(), + dir_handler: Default::default(), panic_payload: None, } } diff --git a/src/shims/foreign_items/posix.rs b/src/shims/foreign_items/posix.rs index e520e23199e3c..636137f62de05 100644 --- a/src/shims/foreign_items/posix.rs +++ b/src/shims/foreign_items/posix.rs @@ -119,6 +119,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; } + "closedir" => { + let result = this.closedir(args[0])?; + this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + } + "lseek" | "lseek64" => { let result = this.lseek64(args[0], args[1], args[2])?; this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; diff --git a/src/shims/foreign_items/posix/linux.rs b/src/shims/foreign_items/posix/linux.rs index 4d3e1798ce148..4c13624008c90 100644 --- a/src/shims/foreign_items/posix/linux.rs +++ b/src/shims/foreign_items/posix/linux.rs @@ -27,6 +27,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; } + // The only reason this is not in the `posix` module is because the `macos` item has a + // different name. + "opendir" => { + let result = this.opendir(args[0])?; + this.write_scalar(result, dest)?; + } + // Time related shims // This is a POSIX function but it has only been tested on linux. diff --git a/src/shims/fs.rs b/src/shims/fs.rs index 45471a638a18e..333b559627c1a 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -1,6 +1,7 @@ use std::collections::BTreeMap; +use std::collections::HashMap; use std::convert::{TryFrom, TryInto}; -use std::fs::{remove_dir, remove_file, rename, DirBuilder, File, OpenOptions}; +use std::fs::{read_dir, remove_dir, remove_file, rename, DirBuilder, File, OpenOptions, ReadDir}; use std::io::{Read, Seek, SeekFrom, Write}; use std::path::PathBuf; use std::time::SystemTime; @@ -162,6 +163,11 @@ trait EvalContextExtPrivate<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, ' } } +#[derive(Debug, Default)] +pub struct DirHandler { + streams: HashMap, ReadDir>, +} + impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { fn open( @@ -761,6 +767,55 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.try_unwrap_io_result(result) } + + fn opendir(&mut self, name_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, Scalar> { + let this = self.eval_context_mut(); + + this.check_no_isolation("opendir")?; + + let name = this.read_os_str_from_c_str(this.read_scalar(name_op)?.not_undef()?)?; + + let result = read_dir(name); + + match result { + Ok(dir_iter) => { + let size = 1; + let kind = MiriMemoryKind::Env; + let align = this.min_align(size, kind); + let dir_ptr = this.memory.allocate(Size::from_bytes(size), align, kind.into()); + let prev = this + .machine + .dir_handler + .streams + .insert(dir_ptr, dir_iter); + if let Some(_) = prev { + throw_unsup_format!("The pointer allocated for opendir was already registered by a previous call to opendir") + } else { + Ok(Scalar::Ptr(dir_ptr)) + } + } + Err(e) => { + this.set_last_error_from_io_error(e)?; + Ok(Scalar::from_int(0, this.memory.pointer_size())) + } + } + } + + fn closedir(&mut self, dirp_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + let this = self.eval_context_mut(); + + this.check_no_isolation("closedir")?; + + let dirp = this.force_ptr(this.read_scalar(dirp_op)?.not_undef()?)?; + + if let Some(dir_iter) = this.machine.dir_handler.streams.remove(&dirp) { + drop(dir_iter); + this.memory.deallocate(dirp, None, MiriMemoryKind::Env.into())?; + Ok(0) + } else { + this.handle_not_found() + } + } } /// Extracts the number of seconds and nanoseconds elapsed between `time` and the unix epoch when From 5d353391111c3b0b6d14c08b5813cc175780789a Mon Sep 17 00:00:00 2001 From: David Cook Date: Sat, 25 Jan 2020 17:36:51 -0600 Subject: [PATCH 1567/3747] Add shim for readdir64_r --- src/shims/foreign_items/posix/linux.rs | 7 ++ src/shims/fs.rs | 116 ++++++++++++++++++++++++- tests/run-pass/fs.rs | 20 ++++- 3 files changed, 141 insertions(+), 2 deletions(-) diff --git a/src/shims/foreign_items/posix/linux.rs b/src/shims/foreign_items/posix/linux.rs index 4c13624008c90..2872e92fa1ee1 100644 --- a/src/shims/foreign_items/posix/linux.rs +++ b/src/shims/foreign_items/posix/linux.rs @@ -34,6 +34,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(result, dest)?; } + // The `macos` module has a parallel foreign item, `readdir_r`, which uses a different + // struct layout. + "readdir64_r" => { + let result = this.readdir64_r(args[0], args[1], args[2])?; + this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + } + // Time related shims // This is a POSIX function but it has only been tested on linux. diff --git a/src/shims/fs.rs b/src/shims/fs.rs index 333b559627c1a..a5acafdaaaf04 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -1,7 +1,7 @@ use std::collections::BTreeMap; use std::collections::HashMap; use std::convert::{TryFrom, TryInto}; -use std::fs::{read_dir, remove_dir, remove_file, rename, DirBuilder, File, OpenOptions, ReadDir}; +use std::fs::{read_dir, remove_dir, remove_file, rename, DirBuilder, File, FileType, OpenOptions, ReadDir}; use std::io::{Read, Seek, SeekFrom, Write}; use std::path::PathBuf; use std::time::SystemTime; @@ -161,6 +161,43 @@ trait EvalContextExtPrivate<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, ' this.set_last_error(ebadf)?; Ok((-1).into()) } + + fn file_type_to_d_type(&mut self, file_type: std::io::Result) -> InterpResult<'tcx, i32> { + let this = self.eval_context_mut(); + match file_type { + Ok(file_type) => { + if file_type.is_dir() { + Ok(this.eval_libc("DT_DIR")?.to_u8()? as i32) + } else if file_type.is_file() { + Ok(this.eval_libc("DT_REG")?.to_u8()? as i32) + } else if file_type.is_symlink() { + Ok(this.eval_libc("DT_LNK")?.to_u8()? as i32) + } else { + #[cfg(unix)] + { + use std::os::unix::fs::FileTypeExt; + if file_type.is_block_device() { + Ok(this.eval_libc("DT_BLK")?.to_u8()? as i32) + } else if file_type.is_char_device() { + Ok(this.eval_libc("DT_CHR")?.to_u8()? as i32) + } else if file_type.is_fifo() { + Ok(this.eval_libc("DT_FIFO")?.to_u8()? as i32) + } else if file_type.is_socket() { + Ok(this.eval_libc("DT_SOCK")?.to_u8()? as i32) + } else { + Ok(this.eval_libc("DT_UNKNOWN")?.to_u8()? as i32) + } + } + #[cfg(not(unix))] + Ok(this.eval_libc("DT_UNKNOWN")?.to_u8()? as i32) + } + } + Err(e) => return match e.raw_os_error() { + Some(error) => Ok(error), + None => throw_unsup_format!("The error {} couldn't be converted to a return value", e), + } + } + } } #[derive(Debug, Default)] @@ -801,6 +838,83 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } + fn readdir64_r( + &mut self, + dirp_op: OpTy<'tcx, Tag>, + entry_op: OpTy<'tcx, Tag>, + result_op: OpTy<'tcx, Tag>, + ) -> InterpResult<'tcx, i32> { + let this = self.eval_context_mut(); + + this.check_no_isolation("readdir64_r")?; + + let dirp = this.force_ptr(this.read_scalar(dirp_op)?.not_undef()?)?; + + let entry_ptr = this.force_ptr(this.read_scalar(entry_op)?.not_undef()?)?; + let dirent64_layout = this.libc_ty_layout("dirent64")?; + this.memory.check_ptr_access( + Scalar::Ptr(entry_ptr), + dirent64_layout.size, + dirent64_layout.align.abi, + )?; + + if let Some(dir_iter) = this.machine.dir_handler.streams.get_mut(&dirp) { + match dir_iter.next() { + Some(Ok(dir_entry)) => { + // write into entry, write pointer to result, return 0 on success + let entry_place = this.deref_operand(entry_op)?; + let ino64_t_layout = this.libc_ty_layout("ino64_t")?; + let off64_t_layout = this.libc_ty_layout("off64_t")?; + let c_ushort_layout = this.libc_ty_layout("c_ushort")?; + let c_uchar_layout = this.libc_ty_layout("c_uchar")?; + + let name_offset = dirent64_layout.details.fields.offset(4); + let name_ptr = entry_ptr.offset(name_offset, this)?; + + #[cfg(unix)] + let ino = std::os::unix::fs::DirEntryExt::ino(&dir_entry); + #[cfg(not(unix))] + let ino = 0; + + #[cfg(unix)] + let file_name = dir_entry.file_name(); + #[cfg(unix)] + let file_name = std::os::unix::ffi::OsStrExt::as_bytes(file_name.as_os_str()); + #[cfg(not(unix))] + let file_name = b""; + + let file_type = this.file_type_to_d_type(dir_entry.file_type())? as u128; + + let imms = [ + immty_from_uint_checked(ino, ino64_t_layout)?, // d_ino + immty_from_uint_checked(0u128, off64_t_layout)?, // d_off + immty_from_uint_checked(0u128, c_ushort_layout)?, // d_reclen + immty_from_uint_checked(file_type, c_uchar_layout)?, // d_type + ]; + this.write_packed_immediates(entry_place, &imms)?; + this.memory.write_bytes(Scalar::Ptr(name_ptr), file_name.iter().copied())?; + + let result_place = this.deref_operand(result_op)?; + this.write_scalar(this.read_scalar(entry_op)?, result_place.into())?; + + Ok(0) + } + None => { + // end of stream: return 0, assign *result=NULL + this.write_null(this.deref_operand(result_op)?.into())?; + Ok(0) + } + Some(Err(e)) => match e.raw_os_error() { + // return positive error number on error + Some(error) => Ok(error), + None => throw_unsup_format!("The error {} couldn't be converted to a return value", e), + } + } + } else { + throw_unsup_format!("The DIR pointer passed to readdir64_r did not come from opendir") + } + } + fn closedir(&mut self, dirp_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); diff --git a/tests/run-pass/fs.rs b/tests/run-pass/fs.rs index 7f920d8c19d8e..cc450e6c01416 100644 --- a/tests/run-pass/fs.rs +++ b/tests/run-pass/fs.rs @@ -1,7 +1,7 @@ // ignore-windows: File handling is not implemented yet // compile-flags: -Zmiri-disable-isolation -use std::fs::{File, create_dir, remove_dir, remove_dir_all, remove_file, rename}; +use std::fs::{File, create_dir, read_dir, remove_dir, remove_dir_all, remove_file, rename}; use std::io::{Read, Write, ErrorKind, Result, Seek, SeekFrom}; use std::path::{PathBuf, Path}; @@ -199,6 +199,24 @@ fn test_directory() { create_dir(&dir_path).unwrap(); // Test that the metadata of a directory is correct. assert!(dir_path.metadata().unwrap().is_dir()); + + // Create some files inside the directory + let f1_path = dir_path.join("f1"); + drop(File::create(&f1_path).unwrap()); + let f2_path = dir_path.join("f2"); + drop(File::create(&f2_path).unwrap()); + // Test that the files are present inside the directory + let mut dir_iter = read_dir(&dir_path).unwrap(); + let first_dir_entry = dir_iter.next().unwrap().unwrap(); + let second_dir_entry = dir_iter.next().unwrap().unwrap(); + assert!(first_dir_entry.file_name() == "f1" || first_dir_entry.file_name() == "f2"); + assert!(second_dir_entry.file_name() == "f1" || second_dir_entry.file_name() == "f2"); + assert!(dir_iter.next().is_none()); + drop(dir_iter); + // Clean up the files in the directory + remove_file(&f1_path).unwrap(); + remove_file(&f2_path).unwrap(); + // Deleting the directory should succeed. remove_dir(&dir_path).unwrap(); // Reading the metadata of a non-existent file should fail with a "not found" error. From 974362ef6446c5ef044a29a5ce0bc2502fd9bea1 Mon Sep 17 00:00:00 2001 From: David Cook Date: Sun, 26 Jan 2020 14:13:22 -0600 Subject: [PATCH 1568/3747] Handle differing sizes of mode_t mode_t is a u32 on Linux and a u16 on macOS --- src/shims/fs.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/shims/fs.rs b/src/shims/fs.rs index a5acafdaaaf04..bedffe4b8ed13 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -775,7 +775,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.check_no_isolation("mkdir")?; + #[cfg(target_os = "linux")] let mode = this.read_scalar(mode_op)?.to_u32()?; + #[cfg(not(target_os = "linux"))] + let mode = this.read_scalar(mode_op)?.not_undef()?.to_u16()?; let path = this.read_os_str_from_c_str(this.read_scalar(path_op)?.not_undef()?)?; @@ -783,8 +786,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx #[cfg(target_family = "unix")] { use std::os::unix::fs::DirBuilderExt; - builder.mode(mode); + builder.mode(mode.into()); } + #[cfg(not(target_family = "unix"))] + let _mode = mode; let result = builder.create(path).map(|_| 0i32); this.try_unwrap_io_result(result) From ba61a9b37c6261b93e4d46b8adb44e5317456b73 Mon Sep 17 00:00:00 2001 From: David Cook Date: Sun, 26 Jan 2020 14:47:36 -0600 Subject: [PATCH 1569/3747] Add shims for macOS-specific symbols --- src/shims/foreign_items/posix/macos.rs | 14 +++++ src/shims/fs.rs | 77 ++++++++++++++++++++++++++ 2 files changed, 91 insertions(+) diff --git a/src/shims/foreign_items/posix/macos.rs b/src/shims/foreign_items/posix/macos.rs index 25ac7e93867f2..e6f4047eee47c 100644 --- a/src/shims/foreign_items/posix/macos.rs +++ b/src/shims/foreign_items/posix/macos.rs @@ -42,6 +42,20 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; } + // The only reason this is not in the `posix` module is because the `linux` item has a + // different name. + "opendir$INODE64" => { + let result = this.opendir(args[0])?; + this.write_scalar(result, dest)?; + } + + // The `linux` module has a parallel foreign item, `readdir64_r`, which uses a + // different struct layout. + "readdir_r$INODE64" => { + let result = this.readdir_r(args[0], args[1], args[2])?; + this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + } + // Time related shims "gettimeofday" => { let result = this.gettimeofday(args[0], args[1])?; diff --git a/src/shims/fs.rs b/src/shims/fs.rs index bedffe4b8ed13..12684018eec39 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -920,6 +920,83 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } + fn readdir_r( + &mut self, + dirp_op: OpTy<'tcx, Tag>, + entry_op: OpTy<'tcx, Tag>, + result_op: OpTy<'tcx, Tag>, + ) -> InterpResult<'tcx, i32> { + let this = self.eval_context_mut(); + + this.check_no_isolation("readdir_r")?; + + let dirp = this.force_ptr(this.read_scalar(dirp_op)?.not_undef()?)?; + + let entry_ptr = this.force_ptr(this.read_scalar(entry_op)?.not_undef()?)?; + let dirent_layout = this.libc_ty_layout("dirent")?; + this.memory.check_ptr_access( + Scalar::Ptr(entry_ptr), + dirent_layout.size, + dirent_layout.align.abi, + )?; + + if let Some(dir_iter) = this.machine.dir_handler.streams.get_mut(&dirp) { + match dir_iter.next() { + Some(Ok(dir_entry)) => { + // write into entry, write pointer to result, return 0 on success + let entry_place = this.deref_operand(entry_op)?; + let ino_t_layout = this.libc_ty_layout("ino_t")?; + let off_t_layout = this.libc_ty_layout("off_t")?; + let c_ushort_layout = this.libc_ty_layout("c_ushort")?; + let c_uchar_layout = this.libc_ty_layout("c_uchar")?; + + let name_offset = dirent_layout.details.fields.offset(4); + let name_ptr = entry_ptr.offset(name_offset, this)?; + + #[cfg(unix)] + let ino = std::os::unix::fs::DirEntryExt::ino(&dir_entry); + #[cfg(not(unix))] + let ino = 0; + + #[cfg(unix)] + let file_name = dir_entry.file_name(); + #[cfg(unix)] + let file_name = std::os::unix::ffi::OsStrExt::as_bytes(file_name.as_os_str()); + #[cfg(not(unix))] + let file_name = b""; + + let file_type = this.file_type_to_d_type(dir_entry.file_type())? as u128; + + let imms = [ + immty_from_uint_checked(ino, ino_t_layout)?, // d_ino + immty_from_uint_checked(0u128, off_t_layout)?, // d_off + immty_from_uint_checked(0u128, c_ushort_layout)?, // d_reclen + immty_from_uint_checked(file_type, c_uchar_layout)?, // d_type + ]; + this.write_packed_immediates(entry_place, &imms)?; + this.memory.write_bytes(Scalar::Ptr(name_ptr), file_name.iter().copied())?; + + let result_place = this.deref_operand(result_op)?; + this.write_scalar(this.read_scalar(entry_op)?, result_place.into())?; + + Ok(0) + } + None => { + // end of stream: return 0, assign *result=NULL + this.write_null(this.deref_operand(result_op)?.into())?; + Ok(0) + } + Some(Err(e)) => match e.raw_os_error() { + // return positive error number on error + Some(error) => Ok(error), + None => throw_unsup_format!("The error {} couldn't be converted to a return value", e), + } + } + } else { + throw_unsup_format!("The DIR pointer passed to readdir_r did not come from opendir") + } + } + fn closedir(&mut self, dirp_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); From d461c12c83bc9805b818b9ba9a4791ee81158d97 Mon Sep 17 00:00:00 2001 From: David Cook Date: Sun, 26 Jan 2020 15:09:24 -0600 Subject: [PATCH 1570/3747] Add more information to test asserts --- tests/run-pass/fs.rs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/tests/run-pass/fs.rs b/tests/run-pass/fs.rs index cc450e6c01416..8db755c7a7309 100644 --- a/tests/run-pass/fs.rs +++ b/tests/run-pass/fs.rs @@ -209,8 +209,16 @@ fn test_directory() { let mut dir_iter = read_dir(&dir_path).unwrap(); let first_dir_entry = dir_iter.next().unwrap().unwrap(); let second_dir_entry = dir_iter.next().unwrap().unwrap(); - assert!(first_dir_entry.file_name() == "f1" || first_dir_entry.file_name() == "f2"); - assert!(second_dir_entry.file_name() == "f1" || second_dir_entry.file_name() == "f2"); + assert!( + first_dir_entry.file_name() == "f1" || first_dir_entry.file_name() == "f2", + "File name was {:?} instead of f1 or f2", + first_dir_entry.file_name(), + ); + assert!( + second_dir_entry.file_name() == "f1" || second_dir_entry.file_name() == "f2", + "File name was {:?} instead of f1 or f2", + second_dir_entry.file_name(), + ); assert!(dir_iter.next().is_none()); drop(dir_iter); // Clean up the files in the directory From a82049587c2abbf85dc40a68c52834b068f88406 Mon Sep 17 00:00:00 2001 From: David Cook Date: Sun, 26 Jan 2020 15:45:35 -0600 Subject: [PATCH 1571/3747] Use longer file names in test --- tests/run-pass/fs.rs | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/tests/run-pass/fs.rs b/tests/run-pass/fs.rs index 8db755c7a7309..59eb4e014378e 100644 --- a/tests/run-pass/fs.rs +++ b/tests/run-pass/fs.rs @@ -201,29 +201,31 @@ fn test_directory() { assert!(dir_path.metadata().unwrap().is_dir()); // Create some files inside the directory - let f1_path = dir_path.join("f1"); - drop(File::create(&f1_path).unwrap()); - let f2_path = dir_path.join("f2"); - drop(File::create(&f2_path).unwrap()); + let path_1 = dir_path.join("test_file_1"); + drop(File::create(&path_1).unwrap()); + let path_2 = dir_path.join("test_file_2"); + drop(File::create(&path_2).unwrap()); // Test that the files are present inside the directory let mut dir_iter = read_dir(&dir_path).unwrap(); let first_dir_entry = dir_iter.next().unwrap().unwrap(); let second_dir_entry = dir_iter.next().unwrap().unwrap(); assert!( - first_dir_entry.file_name() == "f1" || first_dir_entry.file_name() == "f2", - "File name was {:?} instead of f1 or f2", + first_dir_entry.file_name() == "test_file_1" || + first_dir_entry.file_name() == "test_file_2", + "File name was {:?} instead of test_file_1 or test_file_2", first_dir_entry.file_name(), ); assert!( - second_dir_entry.file_name() == "f1" || second_dir_entry.file_name() == "f2", - "File name was {:?} instead of f1 or f2", + second_dir_entry.file_name() == "test_file_1" || + second_dir_entry.file_name() == "test_file_2", + "File name was {:?} instead of test_file_1 or test_file_2", second_dir_entry.file_name(), ); assert!(dir_iter.next().is_none()); drop(dir_iter); // Clean up the files in the directory - remove_file(&f1_path).unwrap(); - remove_file(&f2_path).unwrap(); + remove_file(&path_1).unwrap(); + remove_file(&path_2).unwrap(); // Deleting the directory should succeed. remove_dir(&dir_path).unwrap(); From 515d29aa2ccf6a7339fedab6ac827c45a8357ca5 Mon Sep 17 00:00:00 2001 From: David Cook Date: Thu, 30 Jan 2020 18:57:01 -0600 Subject: [PATCH 1572/3747] Fix dirent layout for macOS --- src/shims/fs.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/shims/fs.rs b/src/shims/fs.rs index 12684018eec39..55c66d1cf363d 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -950,7 +950,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let c_ushort_layout = this.libc_ty_layout("c_ushort")?; let c_uchar_layout = this.libc_ty_layout("c_uchar")?; - let name_offset = dirent_layout.details.fields.offset(4); + let name_offset = dirent_layout.details.fields.offset(5); let name_ptr = entry_ptr.offset(name_offset, this)?; #[cfg(unix)] @@ -969,8 +969,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let imms = [ immty_from_uint_checked(ino, ino_t_layout)?, // d_ino - immty_from_uint_checked(0u128, off_t_layout)?, // d_off + immty_from_uint_checked(0u128, off_t_layout)?, // d_seekoff immty_from_uint_checked(0u128, c_ushort_layout)?, // d_reclen + immty_from_uint_checked(file_name.len() as u128, c_ushort_layout)?, // d_namlen immty_from_uint_checked(file_type, c_uchar_layout)?, // d_type ]; this.write_packed_immediates(entry_place, &imms)?; From 9a6921a17f6a87470e6425be2d435956b54cbde0 Mon Sep 17 00:00:00 2001 From: David Cook Date: Sat, 8 Feb 2020 20:44:02 -0600 Subject: [PATCH 1573/3747] Add doc comment inside DirHandler --- src/shims/fs.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/shims/fs.rs b/src/shims/fs.rs index 55c66d1cf363d..b0ae210f55e5c 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -202,6 +202,16 @@ trait EvalContextExtPrivate<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, ' #[derive(Debug, Default)] pub struct DirHandler { + /// Directory iterators used to emulate libc "directory streams", as used in opendir, readdir, + /// and closedir. + /// + /// When opendir is called, a new allocation is made, a directory iterator is created on the + /// host for the target directory, and an entry is stored in this hash map, indexed by a + /// pointer to the allocation which represents the directory stream. When readdir is called, + /// the directory stream pointer is used to look up the corresponding ReadDir iterator from + /// this HashMap, and information from the next directory entry is returned. When closedir is + /// called, the ReadDir iterator is removed from this HashMap, and the allocation that + /// represented the directory stream is deallocated. streams: HashMap, ReadDir>, } From d4b73efa81bf031dfff846ec2a4cd0f04e462572 Mon Sep 17 00:00:00 2001 From: David Cook Date: Sat, 8 Feb 2020 20:44:35 -0600 Subject: [PATCH 1574/3747] Fix interpreted OS detection --- src/shims/fs.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/shims/fs.rs b/src/shims/fs.rs index b0ae210f55e5c..15f5237e0b57d 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -785,10 +785,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.check_no_isolation("mkdir")?; - #[cfg(target_os = "linux")] - let mode = this.read_scalar(mode_op)?.to_u32()?; - #[cfg(not(target_os = "linux"))] - let mode = this.read_scalar(mode_op)?.not_undef()?.to_u16()?; + let mode = if this.tcx.sess.target.target.target_os.to_lowercase() == "macos" { + this.read_scalar(mode_op)?.not_undef()?.to_u16()? as u32 + } else { + this.read_scalar(mode_op)?.to_u32()? + }; let path = this.read_os_str_from_c_str(this.read_scalar(path_op)?.not_undef()?)?; From 341212acd67d2409265333f2c598d446525b5468 Mon Sep 17 00:00:00 2001 From: David Cook Date: Sat, 8 Feb 2020 22:27:26 -0600 Subject: [PATCH 1575/3747] Rewrite fs tests --- tests/run-pass/fs.rs | 21 ++++----------------- 1 file changed, 4 insertions(+), 17 deletions(-) diff --git a/tests/run-pass/fs.rs b/tests/run-pass/fs.rs index 59eb4e014378e..b938fceb8d026 100644 --- a/tests/run-pass/fs.rs +++ b/tests/run-pass/fs.rs @@ -206,23 +206,10 @@ fn test_directory() { let path_2 = dir_path.join("test_file_2"); drop(File::create(&path_2).unwrap()); // Test that the files are present inside the directory - let mut dir_iter = read_dir(&dir_path).unwrap(); - let first_dir_entry = dir_iter.next().unwrap().unwrap(); - let second_dir_entry = dir_iter.next().unwrap().unwrap(); - assert!( - first_dir_entry.file_name() == "test_file_1" || - first_dir_entry.file_name() == "test_file_2", - "File name was {:?} instead of test_file_1 or test_file_2", - first_dir_entry.file_name(), - ); - assert!( - second_dir_entry.file_name() == "test_file_1" || - second_dir_entry.file_name() == "test_file_2", - "File name was {:?} instead of test_file_1 or test_file_2", - second_dir_entry.file_name(), - ); - assert!(dir_iter.next().is_none()); - drop(dir_iter); + let dir_iter = read_dir(&dir_path).unwrap(); + let mut file_names = dir_iter.map(|e| e.unwrap().file_name()).collect::>(); + file_names.sort_unstable(); + assert_eq!(file_names, vec!["test_file_1", "test_file_2"]); // Clean up the files in the directory remove_file(&path_1).unwrap(); remove_file(&path_2).unwrap(); From 947fa1fa26ca5ebc19dd8b39ee8289ce54e0c8db Mon Sep 17 00:00:00 2001 From: David Cook Date: Sun, 16 Feb 2020 12:12:20 -0600 Subject: [PATCH 1576/3747] Miscellaneous review comments --- src/shims/fs.rs | 22 +++++++--------------- 1 file changed, 7 insertions(+), 15 deletions(-) diff --git a/src/shims/fs.rs b/src/shims/fs.rs index 15f5237e0b57d..6dcdf5717c01d 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -785,7 +785,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.check_no_isolation("mkdir")?; - let mode = if this.tcx.sess.target.target.target_os.to_lowercase() == "macos" { + let _mode = if this.tcx.sess.target.target.target_os.to_lowercase() == "macos" { this.read_scalar(mode_op)?.not_undef()?.to_u16()? as u32 } else { this.read_scalar(mode_op)?.to_u32()? @@ -794,13 +794,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let path = this.read_os_str_from_c_str(this.read_scalar(path_op)?.not_undef()?)?; let mut builder = DirBuilder::new(); + + // If the host supports it, forward on the mode of the directory + // (i.e. permission bits and the sticky bit) #[cfg(target_family = "unix")] { use std::os::unix::fs::DirBuilderExt; - builder.mode(mode.into()); + builder.mode(_mode.into()); } - #[cfg(not(target_family = "unix"))] - let _mode = mode; + let result = builder.create(path).map(|_| 0i32); this.try_unwrap_io_result(result) @@ -842,7 +844,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx .streams .insert(dir_ptr, dir_iter); if let Some(_) = prev { - throw_unsup_format!("The pointer allocated for opendir was already registered by a previous call to opendir") + panic!("The pointer allocated for opendir was already registered by a previous call to opendir") } else { Ok(Scalar::Ptr(dir_ptr)) } @@ -868,11 +870,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let entry_ptr = this.force_ptr(this.read_scalar(entry_op)?.not_undef()?)?; let dirent64_layout = this.libc_ty_layout("dirent64")?; - this.memory.check_ptr_access( - Scalar::Ptr(entry_ptr), - dirent64_layout.size, - dirent64_layout.align.abi, - )?; if let Some(dir_iter) = this.machine.dir_handler.streams.get_mut(&dirp) { match dir_iter.next() { @@ -945,11 +942,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let entry_ptr = this.force_ptr(this.read_scalar(entry_op)?.not_undef()?)?; let dirent_layout = this.libc_ty_layout("dirent")?; - this.memory.check_ptr_access( - Scalar::Ptr(entry_ptr), - dirent_layout.size, - dirent_layout.align.abi, - )?; if let Some(dir_iter) = this.machine.dir_handler.streams.get_mut(&dirp) { match dir_iter.next() { From 94f611348f4484fe95c5adacac93923f3fcab9a7 Mon Sep 17 00:00:00 2001 From: David Cook Date: Sun, 16 Feb 2020 13:13:16 -0600 Subject: [PATCH 1577/3747] Use os_str_length_as_c_str in readdir[64]_r --- src/helpers.rs | 41 ++++++++++++++++++++++++++--------------- src/shims/fs.rs | 43 +++++++++++++++++++++---------------------- 2 files changed, 47 insertions(+), 37 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index 5128176acb58c..24adc72fa87b5 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -483,21 +483,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx scalar: Scalar, size: u64, ) -> InterpResult<'tcx, bool> { - #[cfg(target_os = "unix")] - fn os_str_to_bytes<'tcx, 'a>(os_str: &'a OsStr) -> InterpResult<'tcx, &'a [u8]> { - std::os::unix::ffi::OsStringExt::into_bytes(os_str) - } - #[cfg(not(target_os = "unix"))] - fn os_str_to_bytes<'tcx, 'a>(os_str: &'a OsStr) -> InterpResult<'tcx, &'a [u8]> { - // On non-unix platforms the best we can do to transform bytes from/to OS strings is to do the - // intermediate transformation into strings. Which invalidates non-utf8 paths that are actually - // valid. - os_str - .to_str() - .map(|s| s.as_bytes()) - .ok_or_else(|| err_unsup_format!("{:?} is not a valid utf-8 string", os_str).into()) - } - let bytes = os_str_to_bytes(os_str)?; // If `size` is smaller or equal than `bytes.len()`, writing `bytes` plus the required null // terminator to memory using the `ptr` pointer would cause an out-of-bounds access. @@ -510,6 +495,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(true) } + /// Helper function to determine how long an OsStr would be as a C string, not including the + /// null terminator. + fn os_str_length_as_c_str( + &mut self, + os_str: &OsStr, + ) -> InterpResult<'tcx, usize> { + let bytes = os_str_to_bytes(os_str)?; + Ok(bytes.len()) + } + fn alloc_os_str_as_c_str( &mut self, os_str: &OsStr, @@ -525,6 +520,22 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } +#[cfg(target_os = "unix")] +fn os_str_to_bytes<'tcx, 'a>(os_str: &'a OsStr) -> InterpResult<'tcx, &'a [u8]> { + std::os::unix::ffi::OsStringExt::into_bytes(os_str) +} + +#[cfg(not(target_os = "unix"))] +fn os_str_to_bytes<'tcx, 'a>(os_str: &'a OsStr) -> InterpResult<'tcx, &'a [u8]> { + // On non-unix platforms the best we can do to transform bytes from/to OS strings is to do the + // intermediate transformation into strings. Which invalidates non-utf8 paths that are actually + // valid. + os_str + .to_str() + .map(|s| s.as_bytes()) + .ok_or_else(|| err_unsup_format!("{:?} is not a valid utf-8 string", os_str).into()) +} + pub fn immty_from_int_checked<'tcx>( int: impl Into, layout: TyLayout<'tcx>, diff --git a/src/shims/fs.rs b/src/shims/fs.rs index 6dcdf5717c01d..cee9174696ffa 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -875,27 +875,26 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx match dir_iter.next() { Some(Ok(dir_entry)) => { // write into entry, write pointer to result, return 0 on success + + let name_offset = dirent64_layout.details.fields.offset(4); + let name_ptr = entry_ptr.offset(name_offset, this)?; + + let name_fits = this.write_os_str_to_c_str(&dir_entry.file_name(), Scalar::Ptr(name_ptr), 256)?; + if !name_fits { + panic!("A directory entry had a name too large to fit in libc::dirent64"); + } + let entry_place = this.deref_operand(entry_op)?; let ino64_t_layout = this.libc_ty_layout("ino64_t")?; let off64_t_layout = this.libc_ty_layout("off64_t")?; let c_ushort_layout = this.libc_ty_layout("c_ushort")?; let c_uchar_layout = this.libc_ty_layout("c_uchar")?; - let name_offset = dirent64_layout.details.fields.offset(4); - let name_ptr = entry_ptr.offset(name_offset, this)?; - #[cfg(unix)] let ino = std::os::unix::fs::DirEntryExt::ino(&dir_entry); #[cfg(not(unix))] let ino = 0; - #[cfg(unix)] - let file_name = dir_entry.file_name(); - #[cfg(unix)] - let file_name = std::os::unix::ffi::OsStrExt::as_bytes(file_name.as_os_str()); - #[cfg(not(unix))] - let file_name = b""; - let file_type = this.file_type_to_d_type(dir_entry.file_type())? as u128; let imms = [ @@ -905,7 +904,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx immty_from_uint_checked(file_type, c_uchar_layout)?, // d_type ]; this.write_packed_immediates(entry_place, &imms)?; - this.memory.write_bytes(Scalar::Ptr(name_ptr), file_name.iter().copied())?; let result_place = this.deref_operand(result_op)?; this.write_scalar(this.read_scalar(entry_op)?, result_place.into())?; @@ -947,26 +945,28 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx match dir_iter.next() { Some(Ok(dir_entry)) => { // write into entry, write pointer to result, return 0 on success + + let name_offset = dirent_layout.details.fields.offset(5); + let name_ptr = entry_ptr.offset(name_offset, this)?; + + let file_name = dir_entry.file_name(); + let name_fits = this.write_os_str_to_c_str(&file_name, Scalar::Ptr(name_ptr), 1024)?; + if !name_fits { + panic!("A directory entry had a name too large to fit in libc::dirent"); + } + let entry_place = this.deref_operand(entry_op)?; let ino_t_layout = this.libc_ty_layout("ino_t")?; let off_t_layout = this.libc_ty_layout("off_t")?; let c_ushort_layout = this.libc_ty_layout("c_ushort")?; let c_uchar_layout = this.libc_ty_layout("c_uchar")?; - let name_offset = dirent_layout.details.fields.offset(5); - let name_ptr = entry_ptr.offset(name_offset, this)?; - #[cfg(unix)] let ino = std::os::unix::fs::DirEntryExt::ino(&dir_entry); #[cfg(not(unix))] let ino = 0; - #[cfg(unix)] - let file_name = dir_entry.file_name(); - #[cfg(unix)] - let file_name = std::os::unix::ffi::OsStrExt::as_bytes(file_name.as_os_str()); - #[cfg(not(unix))] - let file_name = b""; + let file_name_len = this.os_str_length_as_c_str(&file_name)? as u128; let file_type = this.file_type_to_d_type(dir_entry.file_type())? as u128; @@ -974,11 +974,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx immty_from_uint_checked(ino, ino_t_layout)?, // d_ino immty_from_uint_checked(0u128, off_t_layout)?, // d_seekoff immty_from_uint_checked(0u128, c_ushort_layout)?, // d_reclen - immty_from_uint_checked(file_name.len() as u128, c_ushort_layout)?, // d_namlen + immty_from_uint_checked(file_name_len, c_ushort_layout)?, // d_namlen immty_from_uint_checked(file_type, c_uchar_layout)?, // d_type ]; this.write_packed_immediates(entry_place, &imms)?; - this.memory.write_bytes(Scalar::Ptr(name_ptr), file_name.iter().copied())?; let result_place = this.deref_operand(result_op)?; this.write_scalar(this.read_scalar(entry_op)?, result_place.into())?; From d6da4ab4b8c7295ad44869ff31784619086c6642 Mon Sep 17 00:00:00 2001 From: David Cook Date: Sun, 16 Feb 2020 13:22:50 -0600 Subject: [PATCH 1578/3747] Add comments --- src/shims/fs.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/shims/fs.rs b/src/shims/fs.rs index cee9174696ffa..1144425fe605d 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -874,7 +874,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if let Some(dir_iter) = this.machine.dir_handler.streams.get_mut(&dirp) { match dir_iter.next() { Some(Ok(dir_entry)) => { - // write into entry, write pointer to result, return 0 on success + // Write into entry, write pointer to result, return 0 on success. + // The name is written with write_os_str_to_c_str, while the rest of the + // dirent64 struct is written using write_packed_immediates. let name_offset = dirent64_layout.details.fields.offset(4); let name_ptr = entry_ptr.offset(name_offset, this)?; @@ -944,7 +946,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if let Some(dir_iter) = this.machine.dir_handler.streams.get_mut(&dirp) { match dir_iter.next() { Some(Ok(dir_entry)) => { - // write into entry, write pointer to result, return 0 on success + // Write into entry, write pointer to result, return 0 on success. + // The name is written with write_os_str_to_c_str, while the rest of the + // dirent struct is written using write_packed_Immediates. let name_offset = dirent_layout.details.fields.offset(5); let name_ptr = entry_ptr.offset(name_offset, this)?; From 725d6bfa9c73c70733c3511901f5ddb6296587da Mon Sep 17 00:00:00 2001 From: David Cook Date: Sun, 16 Feb 2020 13:39:06 -0600 Subject: [PATCH 1579/3747] Move error up, early return --- src/shims/fs.rs | 193 ++++++++++++++++++++++++------------------------ 1 file changed, 98 insertions(+), 95 deletions(-) diff --git a/src/shims/fs.rs b/src/shims/fs.rs index 1144425fe605d..7ae378192a219 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -871,60 +871,62 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let entry_ptr = this.force_ptr(this.read_scalar(entry_op)?.not_undef()?)?; let dirent64_layout = this.libc_ty_layout("dirent64")?; - if let Some(dir_iter) = this.machine.dir_handler.streams.get_mut(&dirp) { - match dir_iter.next() { - Some(Ok(dir_entry)) => { - // Write into entry, write pointer to result, return 0 on success. - // The name is written with write_os_str_to_c_str, while the rest of the - // dirent64 struct is written using write_packed_immediates. - - let name_offset = dirent64_layout.details.fields.offset(4); - let name_ptr = entry_ptr.offset(name_offset, this)?; - - let name_fits = this.write_os_str_to_c_str(&dir_entry.file_name(), Scalar::Ptr(name_ptr), 256)?; - if !name_fits { - panic!("A directory entry had a name too large to fit in libc::dirent64"); - } + let dir_iter = this.machine.dir_handler.streams.get_mut(&dirp).ok_or_else(|| { + err_unsup_format!("The DIR pointer passed to readdir64_r did not come from opendir") + })?; + match dir_iter.next() { + Some(Ok(dir_entry)) => { + // Write into entry, write pointer to result, return 0 on success. + // The name is written with write_os_str_to_c_str, while the rest of the + // dirent64 struct is written using write_packed_immediates. + + let name_offset = dirent64_layout.details.fields.offset(4); + let name_ptr = entry_ptr.offset(name_offset, this)?; + + let file_name = dir_entry.file_name(); + let name_fits = this.write_os_str_to_c_str(&file_name, Scalar::Ptr(name_ptr), 256)?; + if !name_fits { + panic!("A directory entry had a name too large to fit in libc::dirent64"); + } - let entry_place = this.deref_operand(entry_op)?; - let ino64_t_layout = this.libc_ty_layout("ino64_t")?; - let off64_t_layout = this.libc_ty_layout("off64_t")?; - let c_ushort_layout = this.libc_ty_layout("c_ushort")?; - let c_uchar_layout = this.libc_ty_layout("c_uchar")?; + let entry_place = this.deref_operand(entry_op)?; + let ino64_t_layout = this.libc_ty_layout("ino64_t")?; + let off64_t_layout = this.libc_ty_layout("off64_t")?; + let c_ushort_layout = this.libc_ty_layout("c_ushort")?; + let c_uchar_layout = this.libc_ty_layout("c_uchar")?; - #[cfg(unix)] - let ino = std::os::unix::fs::DirEntryExt::ino(&dir_entry); - #[cfg(not(unix))] - let ino = 0; + #[cfg(unix)] + let ino = std::os::unix::fs::DirEntryExt::ino(&dir_entry); + #[cfg(not(unix))] + let ino = 0; - let file_type = this.file_type_to_d_type(dir_entry.file_type())? as u128; + let file_type = this.file_type_to_d_type(dir_entry.file_type())? as u128; - let imms = [ - immty_from_uint_checked(ino, ino64_t_layout)?, // d_ino - immty_from_uint_checked(0u128, off64_t_layout)?, // d_off - immty_from_uint_checked(0u128, c_ushort_layout)?, // d_reclen - immty_from_uint_checked(file_type, c_uchar_layout)?, // d_type - ]; - this.write_packed_immediates(entry_place, &imms)?; + let imms = [ + immty_from_uint_checked(ino, ino64_t_layout)?, // d_ino + immty_from_uint_checked(0u128, off64_t_layout)?, // d_off + immty_from_uint_checked(0u128, c_ushort_layout)?, // d_reclen + immty_from_uint_checked(file_type, c_uchar_layout)?, // d_type + ]; + this.write_packed_immediates(entry_place, &imms)?; - let result_place = this.deref_operand(result_op)?; - this.write_scalar(this.read_scalar(entry_op)?, result_place.into())?; + let result_place = this.deref_operand(result_op)?; + this.write_scalar(this.read_scalar(entry_op)?, result_place.into())?; - Ok(0) - } + Ok(0) + } + None => { + // end of stream: return 0, assign *result=NULL + this.write_null(this.deref_operand(result_op)?.into())?; + Ok(0) + } + Some(Err(e)) => match e.raw_os_error() { + // return positive error number on error + Some(error) => Ok(error), None => { - // end of stream: return 0, assign *result=NULL - this.write_null(this.deref_operand(result_op)?.into())?; - Ok(0) - } - Some(Err(e)) => match e.raw_os_error() { - // return positive error number on error - Some(error) => Ok(error), - None => throw_unsup_format!("The error {} couldn't be converted to a return value", e), + throw_unsup_format!("The error {} couldn't be converted to a return value", e) } - } - } else { - throw_unsup_format!("The DIR pointer passed to readdir64_r did not come from opendir") + }, } } @@ -943,64 +945,65 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let entry_ptr = this.force_ptr(this.read_scalar(entry_op)?.not_undef()?)?; let dirent_layout = this.libc_ty_layout("dirent")?; - if let Some(dir_iter) = this.machine.dir_handler.streams.get_mut(&dirp) { - match dir_iter.next() { - Some(Ok(dir_entry)) => { - // Write into entry, write pointer to result, return 0 on success. - // The name is written with write_os_str_to_c_str, while the rest of the - // dirent struct is written using write_packed_Immediates. - - let name_offset = dirent_layout.details.fields.offset(5); - let name_ptr = entry_ptr.offset(name_offset, this)?; + let dir_iter = this.machine.dir_handler.streams.get_mut(&dirp).ok_or_else(|| { + err_unsup_format!("The DIR pointer passed to readdir_r did not come from opendir") + })?; + match dir_iter.next() { + Some(Ok(dir_entry)) => { + // Write into entry, write pointer to result, return 0 on success. + // The name is written with write_os_str_to_c_str, while the rest of the + // dirent struct is written using write_packed_Immediates. + + let name_offset = dirent_layout.details.fields.offset(5); + let name_ptr = entry_ptr.offset(name_offset, this)?; + + let file_name = dir_entry.file_name(); + let name_fits = this.write_os_str_to_c_str(&file_name, Scalar::Ptr(name_ptr), 1024)?; + if !name_fits { + panic!("A directory entry had a name too large to fit in libc::dirent"); + } - let file_name = dir_entry.file_name(); - let name_fits = this.write_os_str_to_c_str(&file_name, Scalar::Ptr(name_ptr), 1024)?; - if !name_fits { - panic!("A directory entry had a name too large to fit in libc::dirent"); - } + let entry_place = this.deref_operand(entry_op)?; + let ino_t_layout = this.libc_ty_layout("ino_t")?; + let off_t_layout = this.libc_ty_layout("off_t")?; + let c_ushort_layout = this.libc_ty_layout("c_ushort")?; + let c_uchar_layout = this.libc_ty_layout("c_uchar")?; - let entry_place = this.deref_operand(entry_op)?; - let ino_t_layout = this.libc_ty_layout("ino_t")?; - let off_t_layout = this.libc_ty_layout("off_t")?; - let c_ushort_layout = this.libc_ty_layout("c_ushort")?; - let c_uchar_layout = this.libc_ty_layout("c_uchar")?; + #[cfg(unix)] + let ino = std::os::unix::fs::DirEntryExt::ino(&dir_entry); + #[cfg(not(unix))] + let ino = 0; - #[cfg(unix)] - let ino = std::os::unix::fs::DirEntryExt::ino(&dir_entry); - #[cfg(not(unix))] - let ino = 0; + let file_name_len = this.os_str_length_as_c_str(&file_name)? as u128; - let file_name_len = this.os_str_length_as_c_str(&file_name)? as u128; + let file_type = this.file_type_to_d_type(dir_entry.file_type())? as u128; - let file_type = this.file_type_to_d_type(dir_entry.file_type())? as u128; + let imms = [ + immty_from_uint_checked(ino, ino_t_layout)?, // d_ino + immty_from_uint_checked(0u128, off_t_layout)?, // d_seekoff + immty_from_uint_checked(0u128, c_ushort_layout)?, // d_reclen + immty_from_uint_checked(file_name_len, c_ushort_layout)?, // d_namlen + immty_from_uint_checked(file_type, c_uchar_layout)?, // d_type + ]; + this.write_packed_immediates(entry_place, &imms)?; - let imms = [ - immty_from_uint_checked(ino, ino_t_layout)?, // d_ino - immty_from_uint_checked(0u128, off_t_layout)?, // d_seekoff - immty_from_uint_checked(0u128, c_ushort_layout)?, // d_reclen - immty_from_uint_checked(file_name_len, c_ushort_layout)?, // d_namlen - immty_from_uint_checked(file_type, c_uchar_layout)?, // d_type - ]; - this.write_packed_immediates(entry_place, &imms)?; + let result_place = this.deref_operand(result_op)?; + this.write_scalar(this.read_scalar(entry_op)?, result_place.into())?; - let result_place = this.deref_operand(result_op)?; - this.write_scalar(this.read_scalar(entry_op)?, result_place.into())?; - - Ok(0) - } + Ok(0) + } + None => { + // end of stream: return 0, assign *result=NULL + this.write_null(this.deref_operand(result_op)?.into())?; + Ok(0) + } + Some(Err(e)) => match e.raw_os_error() { + // return positive error number on error + Some(error) => Ok(error), None => { - // end of stream: return 0, assign *result=NULL - this.write_null(this.deref_operand(result_op)?.into())?; - Ok(0) + throw_unsup_format!("The error {} couldn't be converted to a return value", e) } - Some(Err(e)) => match e.raw_os_error() { - // return positive error number on error - Some(error) => Ok(error), - None => throw_unsup_format!("The error {} couldn't be converted to a return value", e), - } - } - } else { - throw_unsup_format!("The DIR pointer passed to readdir_r did not come from opendir") + }, } } From a555e1ec25389ab870009387812d07237badfbcd Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 23 Feb 2020 22:44:16 +0100 Subject: [PATCH 1580/3747] cargo update --- Cargo.lock | 373 ++++++++++++++++--------------------- test-cargo-miri/Cargo.lock | 50 ++--- 2 files changed, 184 insertions(+), 239 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9550b2bfdfe3e..7f5719b82a0cc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,15 +2,15 @@ # It is not intended for manual editing. [[package]] name = "aho-corasick" -version = "0.7.6" +version = "0.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "arrayref" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -20,26 +20,27 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "atty" -version = "0.2.13" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", + "hermit-abi 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "autocfg" -version = "0.1.7" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "backtrace" -version = "0.3.40" +version = "0.3.44" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "backtrace-sys 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)", "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-demangle 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -48,17 +49,14 @@ name = "backtrace-sys" version = "0.1.32" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "cc 1.0.47 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "base64" -version = "0.10.1" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", -] [[package]] name = "bitflags" @@ -67,17 +65,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "blake2b_simd" -version = "0.5.9" +version = "0.5.10" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "arrayref 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "arrayref 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "arrayvec 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "constant_time_eq 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "constant_time_eq 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "byteorder" -version = "1.3.2" +version = "1.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -90,18 +88,18 @@ dependencies = [ [[package]] name = "cargo_metadata" -version = "0.9.0" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.103 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.103 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.42 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.48 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "cc" -version = "1.0.47" +version = "1.0.50" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -114,25 +112,17 @@ name = "chrono" version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", + "num-integer 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "cloudabi" -version = "0.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "colored" -version = "1.9.0" +version = "1.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "atty 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)", + "atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -142,17 +132,17 @@ name = "compiletest_rs" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "diff 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", + "diff 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", "filetime 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "getopts 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "miow 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", "rustfix 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.103 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.103 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.42 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.48 (registry+https://github.com/rust-lang/crates.io-index)", "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "tester 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -160,21 +150,22 @@ dependencies = [ [[package]] name = "constant_time_eq" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "crossbeam-utils" -version = "0.6.6" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ + "autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "diff" -version = "0.1.11" +version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -201,8 +192,8 @@ version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_users 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_users 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -211,11 +202,11 @@ name = "env_logger" version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "atty 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)", + "atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", "humantime 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "termcolor 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "termcolor 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -223,7 +214,7 @@ name = "failure" version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "backtrace 0.3.40 (registry+https://github.com/rust-lang/crates.io-index)", + "backtrace 0.3.44 (registry+https://github.com/rust-lang/crates.io-index)", "failure_derive 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -232,9 +223,9 @@ name = "failure_derive" version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)", "synstructure 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -244,37 +235,40 @@ version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "fuchsia-cprng" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "getopts" version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "unicode-width 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-width 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "getrandom" -version = "0.1.13" +version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", - "wasi 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", + "wasi 0.9.0+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "hermit-abi" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "hex" -version = "0.4.0" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -282,12 +276,12 @@ name = "humantime" version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "quick-error 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "itoa" -version = "0.4.4" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -297,7 +291,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "libc" -version = "0.2.65" +version = "0.2.67" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -310,7 +304,7 @@ dependencies = [ [[package]] name = "memchr" -version = "2.2.1" +version = "2.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -326,39 +320,39 @@ dependencies = [ name = "miri" version = "0.1.0" dependencies = [ - "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "cargo_metadata 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "colored 1.9.0 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "cargo_metadata 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", + "colored 1.9.2 (registry+https://github.com/rust-lang/crates.io-index)", "compiletest_rs 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "directories 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", - "getrandom 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", - "hex 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", + "hex 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-workspace-hack 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.103 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", "shell-escape 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "vergen 3.0.4 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "num-integer" -version = "0.1.41" +version = "0.1.42" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "num-traits" -version = "0.2.10" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -368,7 +362,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "proc-macro2" -version = "1.0.6" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -376,7 +370,7 @@ dependencies = [ [[package]] name = "quick-error" -version = "1.2.2" +version = "1.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -384,16 +378,16 @@ name = "quote" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rand" -version = "0.7.2" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "getrandom 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", + "getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", "rand_chacha 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -408,25 +402,12 @@ dependencies = [ "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "rand_core" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rand_core" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "rand_core" version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "getrandom 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", + "getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -437,27 +418,6 @@ dependencies = [ "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "rand_os" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rdrand" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "redox_syscall" version = "0.1.56" @@ -465,29 +425,28 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "redox_users" -version = "0.3.1" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", - "rust-argon2 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rust-argon2 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "regex" -version = "1.3.1" +version = "1.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "aho-corasick 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)", - "memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "regex-syntax 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)", - "thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "aho-corasick 0.7.8 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "regex-syntax 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)", + "thread_local 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "regex-syntax" -version = "0.6.12" +version = "0.6.14" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -500,12 +459,13 @@ dependencies = [ [[package]] name = "rust-argon2" -version = "0.5.1" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", - "blake2b_simd 0.5.9 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", + "base64 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "blake2b_simd 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)", + "constant_time_eq 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -533,8 +493,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.103 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.42 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.48 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -548,7 +508,7 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.103 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -558,30 +518,30 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "serde" -version = "1.0.103" +version = "1.0.104" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde_derive 1.0.103 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "serde_derive" -version = "1.0.103" +version = "1.0.104" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "serde_json" -version = "1.0.42" +version = "1.0.48" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", + "itoa 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", "ryu 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.103 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -595,17 +555,17 @@ version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "syn" -version = "1.0.8" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -615,9 +575,9 @@ name = "synstructure" version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -627,8 +587,8 @@ version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", "remove_dir_all 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -645,10 +605,10 @@ dependencies = [ [[package]] name = "termcolor" -version = "1.0.5" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "wincolor 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -657,13 +617,13 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "getopts 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", "term 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "thread_local" -version = "0.3.6" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -674,14 +634,14 @@ name = "time" version = "0.1.42" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "unicode-width" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -701,7 +661,7 @@ dependencies = [ [[package]] name = "wasi" -version = "0.7.0" +version = "0.9.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -720,7 +680,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "winapi-util" -version = "0.1.2" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -731,38 +691,28 @@ name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "wincolor" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - [metadata] -"checksum aho-corasick 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)" = "58fb5e95d83b38284460a5fda7d6470aa0b8844d283a0b614b8535e880800d2d" -"checksum arrayref 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "0d382e583f07208808f6b1249e60848879ba3543f57c32277bf52d69c2f0f0ee" +"checksum aho-corasick 0.7.8 (registry+https://github.com/rust-lang/crates.io-index)" = "743ad5a418686aad3b87fd14c43badd828cf26e214a00f92a384291cf22e1811" +"checksum arrayref 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544" "checksum arrayvec 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cff77d8686867eceff3105329d4698d96c2391c176d5d03adc90c7389162b5b8" -"checksum atty 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)" = "1803c647a3ec87095e7ae7acfca019e98de5ec9a7d01343f611cf3152ed71a90" -"checksum autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "1d49d90015b3c36167a20fe2810c5cd875ad504b39cff3d4eae7977e6b7c1cb2" -"checksum backtrace 0.3.40 (registry+https://github.com/rust-lang/crates.io-index)" = "924c76597f0d9ca25d762c25a4d369d51267536465dc5064bdf0eb073ed477ea" +"checksum atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +"checksum autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d" +"checksum backtrace 0.3.44 (registry+https://github.com/rust-lang/crates.io-index)" = "e4036b9bf40f3cf16aba72a3d65e8a520fc4bafcdc7079aea8f848c58c5b5536" "checksum backtrace-sys 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)" = "5d6575f128516de27e3ce99689419835fce9643a9b215a14d2b5b685be018491" -"checksum base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0b25d992356d2eb0ed82172f5248873db5560c4721f564b13cb5193bda5e668e" +"checksum base64 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b41b7ea54a0c9d92199de89e20e58d49f02f8e699814ef3fdf266f6f748d15c7" "checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" -"checksum blake2b_simd 0.5.9 (registry+https://github.com/rust-lang/crates.io-index)" = "b83b7baab1e671718d78204225800d6b170e648188ac7dc992e9d6bddf87d0c0" -"checksum byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a7c3dd8985a7111efc5c80b44e23ecdd8c007de8ade3b96595387e812b957cf5" +"checksum blake2b_simd 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)" = "d8fb2d74254a3a0b5cac33ac9f8ed0e44aa50378d9dbb2e5d83bd21ed1dc2c8a" +"checksum byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de" "checksum c2-chacha 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "214238caa1bf3a496ec3392968969cab8549f96ff30652c9e56885329315f6bb" -"checksum cargo_metadata 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8d2d1617e838936c0d2323a65cc151e03ae19a7678dd24f72bccf27119b90a5d" -"checksum cc 1.0.47 (registry+https://github.com/rust-lang/crates.io-index)" = "aa87058dce70a3ff5621797f1506cb837edd02ac4c0ae642b4542dce802908b8" +"checksum cargo_metadata 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "46e3374c604fb39d1a2f35ed5e4a4e30e60d01fab49446e08f1b3e9a90aef202" +"checksum cc 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)" = "95e28fa049fda1c330bcf9d723be7663a899c4679724b34c81e9f5a326aab8cd" "checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" "checksum chrono 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "31850b4a4d6bae316f7a09e691c944c28299298837edc0a03f755618c23cbc01" -"checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" -"checksum colored 1.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "433e7ac7d511768127ed85b0c4947f47a254131e37864b2dc13f52aa32cd37e5" +"checksum colored 1.9.2 (registry+https://github.com/rust-lang/crates.io-index)" = "8815e2ab78f3a59928fc32e141fbeece88320a240e43f47b2fd64ea3a88a5b3d" "checksum compiletest_rs 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d7b678957210a00ba0fbeacc23d38cbfbf29895564da1616564634351e1dac5e" -"checksum constant_time_eq 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "995a44c877f9212528ccc74b21a232f66ad69001e40ede5bcee2ac9ef2657120" -"checksum crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)" = "04973fa96e96579258a5091af6003abde64af786b860f18622b82e026cca60e6" -"checksum diff 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "3c2b69f912779fbb121ceb775d74d51e915af17aaebc38d28a592843a2dd0a3a" +"checksum constant_time_eq 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" +"checksum crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8" +"checksum diff 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "0e25ea47919b1560c4e3b7fe0aaab9becf5b84a10325ddf7db0f0ba5e1026499" "checksum directories 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "551a778172a450d7fc12e629ca3b0428d00f6afa9a43da1b630d54604e97371c" "checksum dirs 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "13aea89a5c93364a98e9b37b2fa237effbb694d5cfe01c5b70941f7eb087d5e3" "checksum dirs-sys 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "afa0b23de8fd801745c471deffa6e12d248f962c9fd4b4c33787b055599bde7b" @@ -770,37 +720,33 @@ dependencies = [ "checksum failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "f8273f13c977665c5db7eb2b99ae520952fe5ac831ae4cd09d80c4c7042b5ed9" "checksum failure_derive 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0bc225b78e0391e4b8683440bf2e63c2deeeb2ce5189eab46e2b68c6d3725d08" "checksum filetime 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "1ff6d4dab0aa0c8e6346d46052e93b13a16cf847b54ed357087c35011048cc7d" -"checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" "checksum getopts 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)" = "14dbbfd5c71d70241ecf9e6f13737f7b5ce823821063188d7e46c41d371eebd5" -"checksum getrandom 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "e7db7ca94ed4cd01190ceee0d8a8052f08a247aa1b469a7f68c6a3b71afcf407" -"checksum hex 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "023b39be39e3a2da62a94feb433e91e8bcd37676fbc8bea371daf52b7a769a3e" +"checksum getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "7abc8dd8451921606d809ba32e95b6111925cd2906060d2dcc29c070220503eb" +"checksum hermit-abi 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "1010591b26bbfe835e9faeabeb11866061cc7dcebffd56ad7d0942d0e61aefd8" +"checksum hex 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "644f9158b2f133fd50f5fb3242878846d9eb792e445c893805ff0e3824006e35" "checksum humantime 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f" -"checksum itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "501266b7edd0174f8530248f87f99c88fbe60ca4ef3dd486835b8d8d53136f7f" +"checksum itoa 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "b8b7a7c0c47db5545ed3fef7468ee7bb5b74691498139e4b3f6a20685dc6dd8e" "checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" -"checksum libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)" = "1a31a0627fdf1f6a39ec0dd577e101440b7db22672c0901fe00a9a6fbb5c24e8" +"checksum libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)" = "eb147597cdf94ed43ab7a9038716637d2d1bf2bc571da995d0028dec06bd3018" "checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7" -"checksum memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "88579771288728879b57485cc7d6b07d648c9f0141eb955f8ab7f9d45394468e" +"checksum memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3728d817d99e5ac407411fa471ff9800a778d88a24685968b36824eaf4bee400" "checksum miow 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "396aa0f2003d7df8395cb93e09871561ccc3e785f0acb369170e8cc74ddf9226" -"checksum num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)" = "b85e541ef8255f6cf42bbfe4ef361305c6c135d10919ecc26126c4e5ae94bc09" -"checksum num-traits 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "d4c81ffc11c212fa327657cb19dd85eb7419e163b5b076bede2bdb5c974c07e4" +"checksum num-integer 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "3f6ea62e9d81a77cd3ee9a2a5b9b609447857f3d358704331e4ef39eb247fcba" +"checksum num-traits 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "c62be47e61d1842b9170f0fdeec8eba98e60e90e5446449a0545e5152acd7096" "checksum ppv-lite86 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "74490b50b9fbe561ac330df47c08f3f33073d2d00c150f719147d7c54522fa1b" -"checksum proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "9c9e470a8dc4aeae2dee2f335e8f533e2d4b347e1434e5671afc49b054592f27" -"checksum quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9274b940887ce9addde99c4eee6b5c44cc494b182b97e73dc8ffdcb3397fd3f0" +"checksum proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)" = "3acb317c6ff86a4e579dfa00fc5e6cca91ecbb4e7eb2df0468805b674eb88548" +"checksum quick-error 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" "checksum quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe" -"checksum rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "3ae1b169243eaf61759b8475a998f0a385e42042370f3a7dbaf35246eacc8412" +"checksum rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" "checksum rand_chacha 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "03a2a90da8c7523f554344f921aa97283eadf6ac484a6d2a7d0212fa7f8d6853" -"checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" -"checksum rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc" "checksum rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" "checksum rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" -"checksum rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071" -"checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" "checksum redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)" = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84" -"checksum redox_users 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4ecedbca3bf205f8d8f5c2b44d83cd0690e39ee84b951ed649e9f1841132b66d" -"checksum regex 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dc220bd33bdce8f093101afe22a037b8eb0e5af33592e6a9caafff0d4cb81cbd" -"checksum regex-syntax 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)" = "11a7e20d1cce64ef2fed88b66d347f88bd9babb82845b2b858f3edbf59a4f716" +"checksum redox_users 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "09b23093265f8d200fa7b4c2c76297f47e681c655f6f1285a8780d6a022f7431" +"checksum regex 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "322cf97724bea3ee221b78fe25ac9c46114ebb51747ad5babd51a2fc6a8235a8" +"checksum regex-syntax 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)" = "b28dfe3fe9badec5dbf0a79a9cccad2cfc2ab5484bdb3e44cbd1ae8b3ba2be06" "checksum remove_dir_all 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4a83fa3702a688b9359eccba92d153ac33fd2e8462f9e0e3fdf155239ea7792e" -"checksum rust-argon2 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4ca4eaef519b494d1f2848fc602d18816fed808a981aedf4f1f00ceb7c9d32cf" +"checksum rust-argon2 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2bc8af4bda8e1ff4932523b94d3dd20ee30a87232323eda55903ffd71d2fb017" "checksum rustc-demangle 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "4c691c0e608126e00913e33f0ccf3727d5fc84573623b8d65b2df340b5201783" "checksum rustc-workspace-hack 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc71d2faa173b74b232dedc235e3ee1696581bb132fc116fa3626d6151a1a8fb" "checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" @@ -808,25 +754,24 @@ dependencies = [ "checksum ryu 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "bfa8506c1de11c9c4e4c38863ccbe02a305c8188e85a05a784c9e11e1c3910c8" "checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" "checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" -"checksum serde 1.0.103 (registry+https://github.com/rust-lang/crates.io-index)" = "1217f97ab8e8904b57dd22eb61cde455fa7446a9c1cf43966066da047c1f3702" -"checksum serde_derive 1.0.103 (registry+https://github.com/rust-lang/crates.io-index)" = "a8c6faef9a2e64b0064f48570289b4bf8823b7581f1d6157c1b52152306651d0" -"checksum serde_json 1.0.42 (registry+https://github.com/rust-lang/crates.io-index)" = "1a3351dcbc1f067e2c92ab7c3c1f288ad1a4cffc470b5aaddb4c2e0a3ae80043" +"checksum serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)" = "414115f25f818d7dfccec8ee535d76949ae78584fc4f79a6f45a904bf8ab4449" +"checksum serde_derive 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)" = "128f9e303a5a29922045a830221b8f78ec74a5f544944f3d5984f8ec3895ef64" +"checksum serde_json 1.0.48 (registry+https://github.com/rust-lang/crates.io-index)" = "9371ade75d4c2d6cb154141b9752cf3781ec9c05e0e5cf35060e1e70ee7b9c25" "checksum shell-escape 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "170a13e64f2a51b77a45702ba77287f5c6829375b04a69cf2222acd17d0cfab9" "checksum socket2 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)" = "e8b74de517221a2cb01a53349cf54182acdc31a074727d3079068448c0676d85" -"checksum syn 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)" = "661641ea2aa15845cddeb97dad000d22070bb5c1fb456b96c1cba883ec691e92" +"checksum syn 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)" = "7a0294dc449adc58bb6592fff1a23d3e5e6e235afc6a0ffca2657d19e7bbffe5" "checksum synstructure 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)" = "67656ea1dc1b41b1451851562ea232ec2e5a80242139f7e679ceccfb5d61f545" "checksum tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9" "checksum term 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c0863a3345e70f61d613eab32ee046ccd1bcc5f9105fe402c61fcd0c13eeb8b5" -"checksum termcolor 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "96d6098003bde162e4277c70665bd87c326f5a0c3f3fbfb285787fa482d54e6e" +"checksum termcolor 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb6bfa289a4d7c5766392812c0a1f4c1ba45afa1ad47803c11e1f407d846d75f" "checksum tester 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee72ec31009a42b53de9a6b7d8f462b493ab3b1e4767bda1fcdbb52127f13b6c" -"checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b" +"checksum thread_local 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d40c6d1b69745a6ec6fb1ca717914848da4b44ae29d9b3080cbee91d72a69b14" "checksum time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f" -"checksum unicode-width 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7007dbd421b92cc6e28410fe7362e2e0a2503394908f417b68ec8d1c364c4e20" +"checksum unicode-width 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "caaa9d531767d1ff2150b9332433f32a24622147e5ebb1f26409d5da67afd479" "checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" "checksum vergen 3.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "6aba5e34f93dc7051dfad05b98a18e9156f27e7b431fe1d2398cb6061c0a1dba" -"checksum wasi 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b89c3ce4ce14bdc6fb6beaf9ec7928ca331de5df7e5ea278375642a2f478570d" +"checksum wasi 0.9.0+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)" = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" "checksum winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6" "checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" -"checksum winapi-util 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7168bab6e1daee33b4557efd0e95d5ca70a03706d39fa5f3fe7a236f584b03c9" +"checksum winapi-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "4ccfbf554c6ad11084fb7517daca16cfdcaccbdadba4fc336f032a8b12c2ad80" "checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" -"checksum wincolor 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "96f5016b18804d24db43cebf3c77269e7569b8954a8464501c216cc5e070eaa9" diff --git a/test-cargo-miri/Cargo.lock b/test-cargo-miri/Cargo.lock index 118afff39bd6d..f4d20ab8e1583 100644 --- a/test-cargo-miri/Cargo.lock +++ b/test-cargo-miri/Cargo.lock @@ -2,7 +2,7 @@ # It is not intended for manual editing. [[package]] name = "byteorder" -version = "1.3.2" +version = "1.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -17,9 +17,9 @@ dependencies = [ name = "cargo-miri-test" version = "0.1.0" dependencies = [ - "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.11.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 1.12.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -29,34 +29,34 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "getrandom" -version = "0.1.13" +version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", - "wasi 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", + "wasi 0.9.0+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "hermit-abi" -version = "0.1.3" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "libc" -version = "0.2.65" +version = "0.2.67" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "num_cpus" -version = "1.11.1" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "hermit-abi 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", + "hermit-abi 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -66,11 +66,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "rand" -version = "0.7.2" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "getrandom 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", + "getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", "rand_chacha 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -91,7 +91,7 @@ name = "rand_core" version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "getrandom 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", + "getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -112,21 +112,21 @@ dependencies = [ [[package]] name = "wasi" -version = "0.7.0" +version = "0.9.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" [metadata] -"checksum byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a7c3dd8985a7111efc5c80b44e23ecdd8c007de8ade3b96595387e812b957cf5" +"checksum byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de" "checksum c2-chacha 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "214238caa1bf3a496ec3392968969cab8549f96ff30652c9e56885329315f6bb" "checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" -"checksum getrandom 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "e7db7ca94ed4cd01190ceee0d8a8052f08a247aa1b469a7f68c6a3b71afcf407" -"checksum hermit-abi 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "307c3c9f937f38e3534b1d6447ecf090cafcc9744e4a6360e8b037b2cf5af120" -"checksum libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)" = "1a31a0627fdf1f6a39ec0dd577e101440b7db22672c0901fe00a9a6fbb5c24e8" -"checksum num_cpus 1.11.1 (registry+https://github.com/rust-lang/crates.io-index)" = "76dac5ed2a876980778b8b85f75a71b6cbf0db0b1232ee12f826bccb00d09d72" +"checksum getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "7abc8dd8451921606d809ba32e95b6111925cd2906060d2dcc29c070220503eb" +"checksum hermit-abi 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "1010591b26bbfe835e9faeabeb11866061cc7dcebffd56ad7d0942d0e61aefd8" +"checksum libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)" = "eb147597cdf94ed43ab7a9038716637d2d1bf2bc571da995d0028dec06bd3018" +"checksum num_cpus 1.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "46203554f085ff89c235cd12f7075f3233af9b11ed7c9e16dfe2560d03313ce6" "checksum ppv-lite86 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "74490b50b9fbe561ac330df47c08f3f33073d2d00c150f719147d7c54522fa1b" -"checksum rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "3ae1b169243eaf61759b8475a998f0a385e42042370f3a7dbaf35246eacc8412" +"checksum rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" "checksum rand_chacha 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "03a2a90da8c7523f554344f921aa97283eadf6ac484a6d2a7d0212fa7f8d6853" "checksum rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" "checksum rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" "checksum rand_pcg 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "16abd0c1b639e9eb4d7c50c0b8100b0d0f849be2349829c740fe8e6eb4816429" -"checksum wasi 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b89c3ce4ce14bdc6fb6beaf9ec7928ca331de5df7e5ea278375642a2f478570d" +"checksum wasi 0.9.0+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)" = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" From 89cbe0ae567603b416ae995f38c428445ff10159 Mon Sep 17 00:00:00 2001 From: David Cook Date: Sun, 16 Feb 2020 13:44:19 -0600 Subject: [PATCH 1581/3747] Add comments --- src/shims/fs.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/shims/fs.rs b/src/shims/fs.rs index 7ae378192a219..7ad36ed407b62 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -173,6 +173,10 @@ trait EvalContextExtPrivate<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, ' } else if file_type.is_symlink() { Ok(this.eval_libc("DT_LNK")?.to_u8()? as i32) } else { + // Certain file types are only supported when the host is a Unix system. + // (i.e. devices and sockets) If it is, check those cases, if not, fall back to + // DT_UNKNOWN sooner. + #[cfg(unix)] { use std::os::unix::fs::FileTypeExt; @@ -895,6 +899,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let c_ushort_layout = this.libc_ty_layout("c_ushort")?; let c_uchar_layout = this.libc_ty_layout("c_uchar")?; + // If the host is a Unix system, fill in the inode number with its real value. + // If not, use 0 as a fallback value. #[cfg(unix)] let ino = std::os::unix::fs::DirEntryExt::ino(&dir_entry); #[cfg(not(unix))] @@ -969,6 +975,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let c_ushort_layout = this.libc_ty_layout("c_ushort")?; let c_uchar_layout = this.libc_ty_layout("c_uchar")?; + // If the host is a Unix system, fill in the inode number with its real value. + // If not, use 0 as a fallback value. #[cfg(unix)] let ino = std::os::unix::fs::DirEntryExt::ino(&dir_entry); #[cfg(not(unix))] From dd00e5830fb40bd3afe3e41910d280353dbe75d9 Mon Sep 17 00:00:00 2001 From: David Cook Date: Sun, 16 Feb 2020 14:49:48 -0600 Subject: [PATCH 1582/3747] Use ID numbers in lieu of allocations for DIR* --- src/shims/fs.rs | 65 +++++++++++++++++++++++++++++-------------------- 1 file changed, 38 insertions(+), 27 deletions(-) diff --git a/src/shims/fs.rs b/src/shims/fs.rs index 7ad36ed407b62..f3b1cc7124c81 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -204,19 +204,39 @@ trait EvalContextExtPrivate<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, ' } } -#[derive(Debug, Default)] +#[derive(Debug)] pub struct DirHandler { /// Directory iterators used to emulate libc "directory streams", as used in opendir, readdir, /// and closedir. /// - /// When opendir is called, a new allocation is made, a directory iterator is created on the - /// host for the target directory, and an entry is stored in this hash map, indexed by a - /// pointer to the allocation which represents the directory stream. When readdir is called, - /// the directory stream pointer is used to look up the corresponding ReadDir iterator from - /// this HashMap, and information from the next directory entry is returned. When closedir is - /// called, the ReadDir iterator is removed from this HashMap, and the allocation that - /// represented the directory stream is deallocated. - streams: HashMap, ReadDir>, + /// When opendir is called, a directory iterator is created on the host for the target + /// directory, and an entry is stored in this hash map, indexed by an ID which represents + /// the directory stream. When readdir is called, the directory stream ID is used to look up + /// the corresponding ReadDir iterator from this HashMap, and information from the next + /// directory entry is returned. When closedir is called, the ReadDir iterator is removed from + /// this HashMap. + streams: HashMap, + /// ID number to be used by the next call to opendir + next_id: u64, +} + +impl DirHandler { + fn insert_new(&mut self, read_dir: ReadDir) -> u64 { + let id = self.next_id; + self.next_id += 1; + self.streams.insert(id, read_dir).unwrap_none(); + id + } +} + +impl Default for DirHandler { + fn default() -> DirHandler { + DirHandler { + streams: HashMap::new(), + // Skip 0 as an ID, because it looks like a null pointer to libc + next_id: 1, + } + } } impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} @@ -838,20 +858,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx match result { Ok(dir_iter) => { - let size = 1; - let kind = MiriMemoryKind::Env; - let align = this.min_align(size, kind); - let dir_ptr = this.memory.allocate(Size::from_bytes(size), align, kind.into()); - let prev = this - .machine - .dir_handler - .streams - .insert(dir_ptr, dir_iter); - if let Some(_) = prev { - panic!("The pointer allocated for opendir was already registered by a previous call to opendir") - } else { - Ok(Scalar::Ptr(dir_ptr)) - } + let id = this.machine.dir_handler.insert_new(dir_iter); + + // The libc API for opendir says that this method returns a pointer to an opaque + // structure, but we are returning an ID number. Thus, pass it as a scalar of + // pointer width. + Ok(Scalar::from_int(id, this.pointer_size())) } Err(e) => { this.set_last_error_from_io_error(e)?; @@ -870,7 +882,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.check_no_isolation("readdir64_r")?; - let dirp = this.force_ptr(this.read_scalar(dirp_op)?.not_undef()?)?; + let dirp = this.read_scalar(dirp_op)?.to_machine_usize(this)?; let entry_ptr = this.force_ptr(this.read_scalar(entry_op)?.not_undef()?)?; let dirent64_layout = this.libc_ty_layout("dirent64")?; @@ -946,7 +958,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.check_no_isolation("readdir_r")?; - let dirp = this.force_ptr(this.read_scalar(dirp_op)?.not_undef()?)?; + let dirp = this.read_scalar(dirp_op)?.to_machine_usize(this)?; let entry_ptr = this.force_ptr(this.read_scalar(entry_op)?.not_undef()?)?; let dirent_layout = this.libc_ty_layout("dirent")?; @@ -1020,11 +1032,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.check_no_isolation("closedir")?; - let dirp = this.force_ptr(this.read_scalar(dirp_op)?.not_undef()?)?; + let dirp = this.read_scalar(dirp_op)?.to_machine_usize(this)?; if let Some(dir_iter) = this.machine.dir_handler.streams.remove(&dirp) { drop(dir_iter); - this.memory.deallocate(dirp, None, MiriMemoryKind::Env.into())?; Ok(0) } else { this.handle_not_found() From e530829797ed2dd0cbab0309979ad5846c69b497 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Wed, 1 Jan 2020 04:12:27 -0500 Subject: [PATCH 1583/3747] Use 'cargo check' to build the sysroot and target crate Fixes #1057 Since we are no longer using "cargo rustc", we now use the rustc arguments passed by Cargo to determine whether we are building a build dependency, normal dependency, or "target" (final binary or test) crate. --- Cargo.toml | 1 + src/bin/cargo-miri.rs | 88 +++++++++++++++++++++++++++++++------------ 2 files changed, 65 insertions(+), 24 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index da9481cce5260..236905b895f8e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -50,6 +50,7 @@ rustc-workspace-hack = "1.0.0" # between "cargo build" and "cargo intall". num-traits = "*" serde = { version = "*", features = ["derive"] } +serde_json = "1.0.44" [build-dependencies] vergen = "3" diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index e990bc00277c1..55503c635dbaf 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -6,7 +6,7 @@ use std::ops::Not; use std::path::{Path, PathBuf}; use std::process::Command; -const XARGO_MIN_VERSION: (u32, u32, u32) = (0, 3, 17); +const XARGO_MIN_VERSION: (u32, u32, u32) = (0, 3, 19); const CARGO_MIRI_HELP: &str = r#"Interprets bin crates and tests in Miri @@ -84,6 +84,34 @@ fn get_arg_flag_value(name: &str) -> Option { } } + +/// Determines if we are being invoked (as rustc) to build a runnable +/// executable. We run "cargo check", so this should only happen when +/// we are trying to compile a build script or build script dependency, +/// which actually needs to be executed on the host platform. +/// +/// Currently, we detect this by checking for "--emit=link", +/// which indicates that Cargo instruced rustc to output +/// a native object. +fn is_build_dep() -> bool { + std::env::args().any(|arg| arg.starts_with("--emit=") && arg.contains("link")) +} + +/// Returns whether or not Cargo invoked the wrapper (this binary) to compile +/// the final, target crate (either a test for 'cargo test', or a binary for 'cargo run') +/// Cargo does not give us this information directly, so we need to check +/// various command-line flags. +fn is_target_crate(is_build_script: bool) -> bool { + let is_bin = get_arg_flag_value("--crate-type").as_deref() == Some("bin"); + let is_test = std::env::args().find(|arg| arg == "--test").is_some(); + + // The final runnable (under Miri) crate will either be a binary crate + // or a test crate. We make sure to exclude build scripts here, since + // they are also build with "--crate-type bin" + (is_bin || is_test) && !is_build_script +} + + fn list_targets() -> impl Iterator { // We need to get the manifest, and then the metadata, to enumerate targets. let manifest_path = @@ -197,7 +225,7 @@ fn xargo() -> Command { // Bootstrap tells us where to find xargo Command::new(val) } else { - Command::new("xargo") + Command::new("xargo-check") } } @@ -467,7 +495,7 @@ fn in_cargo_miri() { // change to add additional arguments. `FLAGS` is set to identify // this target. The user gets to control what gets actually passed to Miri. let mut cmd = cargo(); - cmd.arg("rustc"); + cmd.arg("check"); match (subcommand, kind.as_str()) { (MiriCommand::Run, "bin") => { // FIXME: we just run all the binaries here. @@ -494,10 +522,15 @@ fn in_cargo_miri() { } cmd.arg(arg); } - // Add `--` (to end the `cargo` flags), and then the user flags. We add markers around the - // user flags to be able to identify them later. "cargo rustc" adds more stuff after this, - // so we have to mark both the beginning and the end. - cmd.arg("--").arg("cargo-miri-marker-begin").args(args).arg("cargo-miri-marker-end"); + + // Serialize our actual args into a special environemt variable. + // This will be read by `inside_cargo_rustc` when we go to invoke + // our actual target crate (the binary or the test we are running). + // Since we're using "cargo check", we have no other way of passing + // these arguments. + let args_vec: Vec = args.collect(); + cmd.env("MIRI_MAGIC_ARGS", serde_json::to_string(&args_vec).expect("failed to serialize args")); + let path = std::env::current_exe().expect("current executable path invalid"); cmd.env("RUSTC_WRAPPER", path); if verbose { @@ -517,25 +550,32 @@ fn inside_cargo_rustc() { let sysroot = std::env::var("MIRI_SYSROOT").expect("The wrapper should have set MIRI_SYSROOT"); let rustc_args = std::env::args().skip(2); // skip `cargo rustc` - let mut args: Vec = - rustc_args.chain(Some("--sysroot".to_owned())).chain(Some(sysroot)).collect(); - args.splice(0..0, miri::miri_default_args().iter().map(ToString::to_string)); - // See if we can find the `cargo-miri` markers. Those only get added to the binary we want to - // run. They also serve to mark the user-defined arguments, which we have to move all the way - // to the end (they get added somewhere in the middle). + let in_build_script = is_build_dep(); + + // Build scripts need to be compiled to actual runnable executables, + // and therefore completely bypass Miri. We make sure to only specify + // our custom Xargo sysroot for non-build-script crate - that is, + // crates which are ultimately going to get interpreted by Miri. + let mut args = if in_build_script { + rustc_args.collect() + } else { + let mut args: Vec = rustc_args + .chain(Some("--sysroot".to_owned())) + .chain(Some(sysroot)) + .collect(); + args.splice(0..0, miri::miri_default_args().iter().map(ToString::to_string)); + args + }; + let needs_miri = - if let Some(begin) = args.iter().position(|arg| arg == "cargo-miri-marker-begin") { - let end = args - .iter() - .position(|arg| arg == "cargo-miri-marker-end") - .expect("cannot find end marker"); - // These mark the user arguments. We remove the first and last as they are the markers. - let mut user_args = args.drain(begin..=end); - assert_eq!(user_args.next().unwrap(), "cargo-miri-marker-begin"); - assert_eq!(user_args.next_back().unwrap(), "cargo-miri-marker-end"); - // Collect the rest and add it back at the end. - let mut user_args = user_args.collect::>(); + if is_target_crate(in_build_script) { + // This is the 'target crate '- the binary or test crate that + // we want to interpret under Miri. We deserialize the user-provided arguments + // from the special environment variable "MIRI_MAGIC_ARGS", and feed them + // to the 'miri' binary. + let magic = std::env::var("MIRI_MAGIC_ARGS").expect("missing MIRI_MAGIC_ARGS"); + let mut user_args: Vec = serde_json::from_str(&magic).expect("failed to deserialize args"); args.append(&mut user_args); // Run this in Miri. true From 443163f93071587f72014018eeb45a2225fdff79 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 24 Feb 2020 14:17:19 +0100 Subject: [PATCH 1584/3747] refactor cargo-miri a bit --- src/bin/cargo-miri.rs | 170 +++++++++++++++++++++--------------------- 1 file changed, 86 insertions(+), 84 deletions(-) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 55503c635dbaf..17063b6ff67fc 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -23,7 +23,7 @@ Common options: --features Features to compile for the package -V, --version Print version info and exit -Other [options] are the same as `cargo rustc`. Everything after the first "--" is +Other [options] are the same as `cargo check`. Everything after the first "--" is passed verbatim to Miri, which will pass everything after the second "--" verbatim to the interpreted program. "#; @@ -84,33 +84,30 @@ fn get_arg_flag_value(name: &str) -> Option { } } - -/// Determines if we are being invoked (as rustc) to build a runnable -/// executable. We run "cargo check", so this should only happen when -/// we are trying to compile a build script or build script dependency, -/// which actually needs to be executed on the host platform. -/// -/// Currently, we detect this by checking for "--emit=link", -/// which indicates that Cargo instruced rustc to output -/// a native object. -fn is_build_dep() -> bool { - std::env::args().any(|arg| arg.starts_with("--emit=") && arg.contains("link")) +/// Returns the path to the `miri` binary +fn find_miri() -> PathBuf { + let mut path = std::env::current_exe().expect("current executable path invalid"); + path.set_file_name("miri"); + path } -/// Returns whether or not Cargo invoked the wrapper (this binary) to compile -/// the final, target crate (either a test for 'cargo test', or a binary for 'cargo run') -/// Cargo does not give us this information directly, so we need to check -/// various command-line flags. -fn is_target_crate(is_build_script: bool) -> bool { - let is_bin = get_arg_flag_value("--crate-type").as_deref() == Some("bin"); - let is_test = std::env::args().find(|arg| arg == "--test").is_some(); - - // The final runnable (under Miri) crate will either be a binary crate - // or a test crate. We make sure to exclude build scripts here, since - // they are also build with "--crate-type bin" - (is_bin || is_test) && !is_build_script +fn cargo() -> Command { + if let Ok(val) = std::env::var("CARGO") { + // Bootstrap tells us where to find cargo + Command::new(val) + } else { + Command::new("cargo") + } } +fn xargo() -> Command { + if let Ok(val) = std::env::var("XARGO") { + // Bootstrap tells us where to find xargo + Command::new(val) + } else { + Command::new("xargo-check") + } +} fn list_targets() -> impl Iterator { // We need to get the manifest, and then the metadata, to enumerate targets. @@ -155,13 +152,6 @@ fn list_targets() -> impl Iterator { package.targets.into_iter() } -/// Returns the path to the `miri` binary -fn find_miri() -> PathBuf { - let mut path = std::env::current_exe().expect("current executable path invalid"); - path.set_file_name("miri"); - path -} - /// Make sure that the `miri` and `rustc` binary are from the same sysroot. /// This can be violated e.g. when miri is locally built and installed with a different /// toolchain than what is used when `cargo miri` is run. @@ -211,24 +201,6 @@ fn test_sysroot_consistency() { } } -fn cargo() -> Command { - if let Ok(val) = std::env::var("CARGO") { - // Bootstrap tells us where to find cargo - Command::new(val) - } else { - Command::new("cargo") - } -} - -fn xargo() -> Command { - if let Ok(val) = std::env::var("XARGO") { - // Bootstrap tells us where to find xargo - Command::new(val) - } else { - Command::new("xargo-check") - } -} - fn xargo_version() -> Option<(u32, u32, u32)> { let out = xargo().arg("--version").output().ok()?; if !out.status.success() { @@ -385,6 +357,7 @@ features = ["panic_unwind"] ) .unwrap(); // The boring bits: a dummy project for xargo. + // FIXME: With xargo-check, can we avoid doing this? File::create(dir.join("Cargo.toml")) .unwrap() .write_all( @@ -447,12 +420,12 @@ fn main() { } if let Some("miri") = std::env::args().nth(1).as_ref().map(AsRef::as_ref) { - // This arm is for when `cargo miri` is called. We call `cargo rustc` for each applicable target, + // This arm is for when `cargo miri` is called. We call `cargo check` for each applicable target, // but with the `RUSTC` env var set to the `cargo-miri` binary so that we come back in the other branch, // and dispatch the invocations to `rustc` and `miri`, respectively. in_cargo_miri(); } else if let Some("rustc") = std::env::args().nth(1).as_ref().map(AsRef::as_ref) { - // This arm is executed when `cargo-miri` runs `cargo rustc` with the `RUSTC_WRAPPER` env var set to itself: + // This arm is executed when `cargo-miri` runs `cargo check` with the `RUSTC_WRAPPER` env var set to itself: // dependencies get dispatched to `rustc`, the final test/binary to `miri`. inside_cargo_rustc(); } else { @@ -491,7 +464,7 @@ fn in_cargo_miri() { .kind .get(0) .expect("badly formatted cargo metadata: target::kind is an empty array"); - // Now we run `cargo rustc $FLAGS $ARGS`, giving the user the + // Now we run `cargo check $FLAGS $ARGS`, giving the user the // change to add additional arguments. `FLAGS` is set to identify // this target. The user gets to control what gets actually passed to Miri. let mut cmd = cargo(); @@ -515,7 +488,7 @@ fn in_cargo_miri() { // The remaining targets we do not even want to build. _ => continue, } - // Add user-defined args until first `--`. + // Forward user-defined `cargo` args until first `--`. while let Some(arg) = args.next() { if arg == "--" { break; @@ -523,17 +496,21 @@ fn in_cargo_miri() { cmd.arg(arg); } - // Serialize our actual args into a special environemt variable. + // Serialize the remaining args into a special environemt variable. // This will be read by `inside_cargo_rustc` when we go to invoke // our actual target crate (the binary or the test we are running). // Since we're using "cargo check", we have no other way of passing // these arguments. let args_vec: Vec = args.collect(); - cmd.env("MIRI_MAGIC_ARGS", serde_json::to_string(&args_vec).expect("failed to serialize args")); + cmd.env("MIRI_ARGS", serde_json::to_string(&args_vec).expect("failed to serialize args")); + // Set `RUSTC_WRAPPER` to ourselves. Cargo will prepend that binary to its usual invocation, + // i.e., the first argument is `rustc` -- which is what we use in `main` to distinguish + // the two codepaths. let path = std::env::current_exe().expect("current executable path invalid"); cmd.env("RUSTC_WRAPPER", path); if verbose { + cmd.env("MIRI_VERBOSE", ""); // this makes `inside_cargo_rustc` verbose. eprintln!("+ {:?}", cmd); } @@ -547,45 +524,71 @@ fn in_cargo_miri() { } fn inside_cargo_rustc() { - let sysroot = std::env::var("MIRI_SYSROOT").expect("The wrapper should have set MIRI_SYSROOT"); - - let rustc_args = std::env::args().skip(2); // skip `cargo rustc` + /// Determines if we are being invoked (as rustc) to build a runnable + /// executable. We run "cargo check", so this should only happen when + /// we are trying to compile a build script or build script dependency, + /// which actually needs to be executed on the host platform. + /// + /// Currently, we detect this by checking for "--emit=link", + /// which indicates that Cargo instruced rustc to output + /// a native object. + fn is_target_crate() -> bool { + // `--emit` is sometimes missing, e.g. cargo calls rustc for "--print". + // That is definitely not a target crate. + // If `--emit` is present, then host crates are built ("--emit=link,...), + // while the rest is only checked. + get_arg_flag_value("--emit").map_or(false, |emit| !emit.contains("link")) + } - let in_build_script = is_build_dep(); + /// Returns whether or not Cargo invoked the wrapper (this binary) to compile + /// the final, target crate (either a test for 'cargo test', or a binary for 'cargo run') + /// Cargo does not give us this information directly, so we need to check + /// various command-line flags. + fn is_runnable_crate() -> bool { + let is_bin = get_arg_flag_value("--crate-type").as_deref() == Some("bin"); + let is_test = has_arg_flag("--test"); + + // The final runnable (under Miri) crate will either be a binary crate + // or a test crate. We make sure to exclude build scripts here, since + // they are also build with "--crate-type bin" + is_bin || is_test + } - // Build scripts need to be compiled to actual runnable executables, - // and therefore completely bypass Miri. We make sure to only specify - // our custom Xargo sysroot for non-build-script crate - that is, - // crates which are ultimately going to get interpreted by Miri. - let mut args = if in_build_script { - rustc_args.collect() - } else { - let mut args: Vec = rustc_args - .chain(Some("--sysroot".to_owned())) - .chain(Some(sysroot)) - .collect(); + let verbose = std::env::var("MIRI_VERBOSE").is_ok(); + let target_crate = is_target_crate(); + + // Figure out which arguments we need to pass. + let mut args: Vec = std::env::args().skip(2).collect(); // skip `cargo-miri rustc` + // We make sure to only specify our custom Xargo sysroot and + // other args for target crates - that is, crates which are ultimately + // going to get interpreted by Miri. + if target_crate { + let sysroot = std::env::var("MIRI_SYSROOT").expect("The wrapper should have set MIRI_SYSROOT"); + args.push("--sysroot".to_owned()); + args.push(sysroot); args.splice(0..0, miri::miri_default_args().iter().map(ToString::to_string)); - args - }; + } - let needs_miri = - if is_target_crate(in_build_script) { - // This is the 'target crate '- the binary or test crate that + // Figure out the binary we need to call. If this is a runnable target crate, we want to call + // Miri to start interpretation; otherwise we want to call rustc to build the crate as usual. + let mut command = + if target_crate && is_runnable_crate() { + // This is the 'target crate' - the binary or test crate that // we want to interpret under Miri. We deserialize the user-provided arguments - // from the special environment variable "MIRI_MAGIC_ARGS", and feed them + // from the special environment variable "MIRI_ARGS", and feed them // to the 'miri' binary. - let magic = std::env::var("MIRI_MAGIC_ARGS").expect("missing MIRI_MAGIC_ARGS"); - let mut user_args: Vec = serde_json::from_str(&magic).expect("failed to deserialize args"); + let magic = std::env::var("MIRI_ARGS").expect("missing MIRI_ARGS"); + let mut user_args: Vec = serde_json::from_str(&magic).expect("failed to deserialize MIRI_ARGS"); args.append(&mut user_args); // Run this in Miri. - true + Command::new(find_miri()) } else { - false + Command::new("rustc") }; - let mut command = if needs_miri { Command::new(find_miri()) } else { Command::new("rustc") }; + // Run it. command.args(&args); - if has_arg_flag("-v") { + if verbose { eprintln!("+ {:?}", command); } @@ -594,7 +597,6 @@ fn inside_cargo_rustc() { if !exit.success() { std::process::exit(exit.code().unwrap_or(42)); }, - Err(ref e) if needs_miri => panic!("error during miri run: {:?}", e), - Err(ref e) => panic!("error during rustc call: {:?}", e), + Err(ref e) => panic!("error running {:?}:\n{:?}", command, e), } } From 47f2b127350e7d95fac67191467ecba3aed1befb Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 24 Feb 2020 14:42:45 +0100 Subject: [PATCH 1585/3747] fix Cargo.toml --- Cargo.toml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 236905b895f8e..896c726b9aa65 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -33,6 +33,8 @@ required-features = ["rustc_tests"] cargo_metadata = { version = "0.9.0", optional = true } directories = { version = "2.0", optional = true } rustc_version = { version = "0.2.3", optional = true } +serde_json = { version = "1.0.44", optional = true } + getrandom = { version = "0.1.8", features = ["std"] } byteorder = "1.3" env_logger = "0.7.1" @@ -50,14 +52,13 @@ rustc-workspace-hack = "1.0.0" # between "cargo build" and "cargo intall". num-traits = "*" serde = { version = "*", features = ["derive"] } -serde_json = "1.0.44" [build-dependencies] vergen = "3" [features] default = ["cargo_miri"] -cargo_miri = ["cargo_metadata", "directories", "rustc_version"] +cargo_miri = ["cargo_metadata", "directories", "rustc_version", "serde_json"] rustc_tests = [] [dev-dependencies] From faf7bf538d3bf61321ca0128ad039d5d13fc2a40 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 24 Feb 2020 14:45:35 +0100 Subject: [PATCH 1586/3747] update lockfile --- Cargo.lock | 1 + 1 file changed, 1 insertion(+) diff --git a/Cargo.lock b/Cargo.lock index 7f5719b82a0cc..951e91dad5b29 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -334,6 +334,7 @@ dependencies = [ "rustc-workspace-hack 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.48 (registry+https://github.com/rust-lang/crates.io-index)", "shell-escape 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "vergen 3.0.4 (registry+https://github.com/rust-lang/crates.io-index)", ] From 274ae0438fb4e942ad29fd60f0adf277cc6777d9 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 24 Feb 2020 16:22:02 +0100 Subject: [PATCH 1587/3747] add an option to disable Stacked Borrows --- README.md | 17 +++++--- src/bin/miri.rs | 5 +++ src/eval.rs | 5 ++- src/lib.rs | 2 +- src/machine.rs | 40 ++++++++++++------- src/shims/panic.rs | 4 +- src/stacked_borrows.rs | 2 +- tests/compile-fail/modifying_constants.rs | 4 +- tests/compile-fail/reference_to_packed.rs | 4 +- tests/compile-fail/stack_free.rs | 4 +- .../static_memory_modification1.rs | 4 +- .../static_memory_modification2.rs | 4 +- .../static_memory_modification3.rs | 4 +- tests/run-pass/observed_local_mut.rs | 4 +- tests/run-pass/transmute_fat.rs | 4 +- 15 files changed, 66 insertions(+), 41 deletions(-) diff --git a/README.md b/README.md index f16751cd74783..f18a5d668c392 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,8 @@ for example: * Not sufficiently aligned memory accesses and references * Violation of *some* basic type invariants (a `bool` that is not 0 or 1, for example, or an invalid enum discriminant) -* **Experimental**: Violations of the rules governing aliasing for reference types +* **Experimental**: Violations of the [Stacked Borrows] rules governing aliasing + for reference types Miri has already discovered some [real-world bugs](#bugs-found-by-miri). If you found a bug with Miri, we'd appreciate if you tell us and we'll add it to the @@ -47,6 +48,7 @@ program, and cannot run all programs: [mir]: https://github.com/rust-lang/rfcs/blob/master/text/1211-mir.md [`unreachable_unchecked`]: https://doc.rust-lang.org/stable/std/hint/fn.unreachable_unchecked.html [`copy_nonoverlapping`]: https://doc.rust-lang.org/stable/std/ptr/fn.copy_nonoverlapping.html +[Stacked Borrows]: https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md ## Using Miri @@ -152,10 +154,13 @@ Several `-Z` flags are relevant for Miri: **NOTE**: This entropy is not good enough for cryptographic use! Do not generate secret keys in Miri or perform other kinds of cryptographic operations that rely on proper random numbers. -* `-Zmiri-disable-validation` disables enforcing validity invariants and - reference aliasing rules, which are enforced by default. This is mostly - useful for debugging. It means Miri will miss bugs in your program. However, - this can also help to make Miri run faster. +* `-Zmiri-disable-validation` disables enforcing validity invariants, which are + enforced by default. This is mostly useful for debugging. It means Miri will + miss bugs in your program. However, this can also help to make Miri run + faster. +* `-Zmiri-disable-stacked-borrows` disables checking the experimental + [Stacked Borrows] aliasing rules. This can make Miri run faster, but it also + means no aliasing violations will be detected. * `-Zmiri-disable-isolation` disables host host isolation. As a consequence, the program has access to host resources such as environment variables, file systems, and randomness. @@ -234,7 +239,7 @@ Definite bugs found: * [The Unix allocator calling `posix_memalign` in an invalid way](https://github.com/rust-lang/rust/issues/62251) * [`getrandom` calling the `getrandom` syscall in an invalid way](https://github.com/rust-random/getrandom/pull/73) -Violations of Stacked Borrows found that are likely bugs (but Stacked Borrows is currently just an experiment): +Violations of [Stacked Borrows] found that are likely bugs (but Stacked Borrows is currently just an experiment): * [`VecDeque` creating overlapping mutable references](https://github.com/rust-lang/rust/pull/56161) * [`BTreeMap` creating mutable references that overlap with shared references](https://github.com/rust-lang/rust/pull/58431) diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 228c50e4a57b2..9523609889cd7 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -130,6 +130,7 @@ fn main() { // Parse our arguments and split them across `rustc` and `miri`. let mut validate = true; + let mut stacked_borrows = true; let mut communicate = false; let mut ignore_leaks = false; let mut seed: Option = None; @@ -150,6 +151,9 @@ fn main() { "-Zmiri-disable-validation" => { validate = false; } + "-Zmiri-disable-stacked-borrows" => { + stacked_borrows = false; + } "-Zmiri-disable-isolation" => { communicate = true; } @@ -229,6 +233,7 @@ fn main() { debug!("miri arguments: {:?}", miri_args); let miri_config = miri::MiriConfig { validate, + stacked_borrows, communicate, ignore_leaks, excluded_env_vars, diff --git a/src/eval.rs b/src/eval.rs index 9ce3d2b08c23e..5a0c766b5ae15 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -14,8 +14,10 @@ use crate::*; /// Configuration needed to spawn a Miri instance. #[derive(Clone)] pub struct MiriConfig { - /// Determine if validity checking and Stacked Borrows are enabled. + /// Determine if validity checking is enabled. pub validate: bool, + /// Determines if Stacked Borrows is enabled. + pub stacked_borrows: bool, /// Determines if communication with the host environment is enabled. pub communicate: bool, /// Determines if memory leaks should be ignored. @@ -52,6 +54,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( MemoryExtra::new( StdRng::seed_from_u64(config.seed.unwrap_or(0)), config.validate, + config.stacked_borrows, config.tracked_pointer_tag, ), ); diff --git a/src/lib.rs b/src/lib.rs index 85ee98aa3a123..7cea203d5e767 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -56,7 +56,7 @@ pub use crate::mono_hash_map::MonoHashMap; pub use crate::operator::EvalContextExt as OperatorEvalContextExt; pub use crate::range_map::RangeMap; pub use crate::stacked_borrows::{ - EvalContextExt as StackedBorEvalContextExt, GlobalState, Item, Permission, PtrId, Stack, + EvalContextExt as StackedBorEvalContextExt, Item, Permission, PtrId, Stack, Stacks, Tag, }; diff --git a/src/machine.rs b/src/machine.rs index 5d933fe8a7f60..7aaf97cc1236b 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -4,6 +4,7 @@ use std::borrow::Cow; use std::cell::RefCell; use std::rc::Rc; +use std::num::NonZeroU64; use rand::rngs::StdRng; @@ -63,14 +64,14 @@ impl Into> for MiriMemoryKind { /// Extra per-allocation data #[derive(Debug, Clone)] pub struct AllocExtra { - /// Stacked Borrows state is only added if validation is enabled. + /// Stacked Borrows state is only added if it is enabled. pub stacked_borrows: Option, } /// Extra global memory data #[derive(Clone, Debug)] pub struct MemoryExtra { - pub stacked_borrows: stacked_borrows::MemoryExtra, + pub stacked_borrows: Option, pub intptrcast: intptrcast::MemoryExtra, /// The random number generator used for resolving non-determinism. @@ -81,9 +82,14 @@ pub struct MemoryExtra { } impl MemoryExtra { - pub fn new(rng: StdRng, validate: bool, tracked_pointer_tag: Option) -> Self { + pub fn new(rng: StdRng, validate: bool, stacked_borrows: bool, tracked_pointer_tag: Option) -> Self { + let stacked_borrows = if stacked_borrows { + Some(Rc::new(RefCell::new(stacked_borrows::GlobalState::new(tracked_pointer_tag)))) + } else { + None + }; MemoryExtra { - stacked_borrows: Rc::new(RefCell::new(GlobalState::new(tracked_pointer_tag))), + stacked_borrows, intptrcast: Default::default(), rng: RefCell::new(rng), validate, @@ -299,11 +305,11 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { ) -> (Cow<'b, Allocation>, Self::PointerTag) { let kind = kind.expect("we set our STATIC_KIND so this cannot be None"); let alloc = alloc.into_owned(); - let (stacks, base_tag) = if memory_extra.validate { + let (stacks, base_tag) = if let Some(stacked_borrows) = memory_extra.stacked_borrows.as_ref() { let (stacks, base_tag) = Stacks::new_allocation( id, alloc.size, - Rc::clone(&memory_extra.stacked_borrows), + Rc::clone(stacked_borrows), kind, ); (Some(stacks), base_tag) @@ -311,15 +317,15 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { // No stacks, no tag. (None, Tag::Untagged) }; - let mut stacked_borrows = memory_extra.stacked_borrows.borrow_mut(); + let mut stacked_borrows = memory_extra.stacked_borrows.as_ref().map(|sb| sb.borrow_mut()); let alloc: Allocation = alloc.with_tags_and_extra( |alloc| { - if !memory_extra.validate { - Tag::Untagged - } else { + if let Some(stacked_borrows) = stacked_borrows.as_mut() { // Only statics may already contain pointers at this point assert_eq!(kind, MiriMemoryKind::Static.into()); stacked_borrows.static_base_ptr(alloc) + } else { + Tag::Untagged } }, AllocExtra { stacked_borrows: stacks }, @@ -329,10 +335,10 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { #[inline(always)] fn tag_static_base_pointer(memory_extra: &MemoryExtra, id: AllocId) -> Self::PointerTag { - if !memory_extra.validate { - Tag::Untagged + if let Some(stacked_borrows) = memory_extra.stacked_borrows.as_ref() { + stacked_borrows.borrow_mut().static_base_ptr(id) } else { - memory_extra.stacked_borrows.borrow_mut().static_base_ptr(id) + Tag::Untagged } } @@ -342,7 +348,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { kind: mir::RetagKind, place: PlaceTy<'tcx, Tag>, ) -> InterpResult<'tcx> { - if !Self::enforce_validity(ecx) { + if ecx.memory.extra.stacked_borrows.is_none() { // No tracking. Ok(()) } else { @@ -352,8 +358,12 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { #[inline(always)] fn stack_push(ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx, FrameData<'tcx>> { + let call_id = ecx.memory.extra.stacked_borrows.as_ref().map_or( + NonZeroU64::new(1).unwrap(), + |stacked_borrows| stacked_borrows.borrow_mut().new_call(), + ); Ok(FrameData { - call_id: ecx.memory.extra.stacked_borrows.borrow_mut().new_call(), + call_id, catch_panic: None, }) } diff --git a/src/shims/panic.rs b/src/shims/panic.rs index 880932ae04722..e930af7f46c5c 100644 --- a/src/shims/panic.rs +++ b/src/shims/panic.rs @@ -146,7 +146,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } else { StackPopInfo::Normal }; - this.memory.extra.stacked_borrows.borrow_mut().end_call(extra.call_id); + if let Some(stacked_borrows) = this.memory.extra.stacked_borrows.as_ref() { + stacked_borrows.borrow_mut().end_call(extra.call_id); + } Ok(res) } diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 1b7a118e637d6..9a674830c8ec2 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -575,7 +575,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // breaking `Rc::from_raw`. RefKind::Raw { .. } => Tag::Untagged, // All other pointesr are properly tracked. - _ => Tag::Tagged(this.memory.extra.stacked_borrows.borrow_mut().new_ptr()), + _ => Tag::Tagged(this.memory.extra.stacked_borrows.as_ref().unwrap().borrow_mut().new_ptr()), }; // Reborrow. diff --git a/tests/compile-fail/modifying_constants.rs b/tests/compile-fail/modifying_constants.rs index 4546e8a4d7c9b..9770917b629be 100644 --- a/tests/compile-fail/modifying_constants.rs +++ b/tests/compile-fail/modifying_constants.rs @@ -1,5 +1,5 @@ -// This should fail even without validation -// compile-flags: -Zmiri-disable-validation +// This should fail even without validation/SB +// compile-flags: -Zmiri-disable-validation -Zmiri-disable-stacked-borrows fn main() { let x = &1; // the `&1` is promoted to a constant, but it used to be that only the pointer is marked static, not the pointee diff --git a/tests/compile-fail/reference_to_packed.rs b/tests/compile-fail/reference_to_packed.rs index befe96f2b35d9..030353c2cedb3 100644 --- a/tests/compile-fail/reference_to_packed.rs +++ b/tests/compile-fail/reference_to_packed.rs @@ -1,5 +1,5 @@ -// This should fail even without validation -// compile-flags: -Zmiri-disable-validation +// This should fail even without validation/SB +// compile-flags: -Zmiri-disable-validation -Zmiri-disable-stacked-borrows #![allow(dead_code, unused_variables)] diff --git a/tests/compile-fail/stack_free.rs b/tests/compile-fail/stack_free.rs index 43cc17308c06f..b8ed2e3f1f35d 100644 --- a/tests/compile-fail/stack_free.rs +++ b/tests/compile-fail/stack_free.rs @@ -1,5 +1,5 @@ -// Validation changes why we fail -// compile-flags: -Zmiri-disable-validation +// Validation/SB changes why we fail +// compile-flags: -Zmiri-disable-validation -Zmiri-disable-stacked-borrows // error-pattern: tried to deallocate `Stack` memory but gave `Machine(Rust)` as the kind diff --git a/tests/compile-fail/static_memory_modification1.rs b/tests/compile-fail/static_memory_modification1.rs index 07a277a16f3ae..a7bb33431e721 100644 --- a/tests/compile-fail/static_memory_modification1.rs +++ b/tests/compile-fail/static_memory_modification1.rs @@ -1,5 +1,5 @@ -// Validation detects that we are casting & to &mut and so it changes why we fail -// compile-flags: -Zmiri-disable-validation +// Stacked Borrows detects that we are casting & to &mut and so it changes why we fail +// compile-flags: -Zmiri-disable-stacked-borrows static X: usize = 5; diff --git a/tests/compile-fail/static_memory_modification2.rs b/tests/compile-fail/static_memory_modification2.rs index 73928f533cb70..065206a60dbff 100644 --- a/tests/compile-fail/static_memory_modification2.rs +++ b/tests/compile-fail/static_memory_modification2.rs @@ -1,5 +1,5 @@ -// Validation detects that we are casting & to &mut and so it changes why we fail -// compile-flags: -Zmiri-disable-validation +// Stacked Borrows detects that we are casting & to &mut and so it changes why we fail +// compile-flags: -Zmiri-disable-stacked-borrows use std::mem::transmute; diff --git a/tests/compile-fail/static_memory_modification3.rs b/tests/compile-fail/static_memory_modification3.rs index 280f34a5a0213..94f88205073e2 100644 --- a/tests/compile-fail/static_memory_modification3.rs +++ b/tests/compile-fail/static_memory_modification3.rs @@ -1,5 +1,5 @@ -// Validation detects that we are casting & to &mut and so it changes why we fail -// compile-flags: -Zmiri-disable-validation +// Stacked Borrows detects that we are casting & to &mut and so it changes why we fail +// compile-flags: -Zmiri-disable-stacked-borrows use std::mem::transmute; diff --git a/tests/run-pass/observed_local_mut.rs b/tests/run-pass/observed_local_mut.rs index c58e8c84bb2e7..888b6f85e3fd5 100644 --- a/tests/run-pass/observed_local_mut.rs +++ b/tests/run-pass/observed_local_mut.rs @@ -1,5 +1,5 @@ -// Validation catches this (correctly) as UB. -// compile-flags: -Zmiri-disable-validation +// Stacked Borrows catches this (correctly) as UB. +// compile-flags: -Zmiri-disable-stacked-borrows // This test is intended to guard against the problem described in commit // 39bb1254d1eaf74f45a4e741097e33fc942168d5. diff --git a/tests/run-pass/transmute_fat.rs b/tests/run-pass/transmute_fat.rs index 27da44935b106..238122de8d4c0 100644 --- a/tests/run-pass/transmute_fat.rs +++ b/tests/run-pass/transmute_fat.rs @@ -1,5 +1,5 @@ -// Validation disallows this becuase the reference is never cast to a raw pointer. -// compile-flags: -Zmiri-disable-validation +// Stacked Borrows disallows this becuase the reference is never cast to a raw pointer. +// compile-flags: -Zmiri-disable-stacked-borrows fn main() { // If we are careful, we can exploit data layout... From 25ddc659d08061f588589c9f271c25250aa55f0d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 24 Feb 2020 16:25:29 +0100 Subject: [PATCH 1588/3747] move validate field from memory to machine --- src/eval.rs | 6 ++++-- src/machine.rs | 14 +++++++------- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/src/eval.rs b/src/eval.rs index 5a0c766b5ae15..eca634d02098c 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -50,10 +50,12 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( let mut ecx = InterpCx::new( tcx.at(rustc_span::source_map::DUMMY_SP), ty::ParamEnv::reveal_all(), - Evaluator::new(config.communicate), + Evaluator::new( + config.communicate, + config.validate, + ), MemoryExtra::new( StdRng::seed_from_u64(config.seed.unwrap_or(0)), - config.validate, config.stacked_borrows, config.tracked_pointer_tag, ), diff --git a/src/machine.rs b/src/machine.rs index 7aaf97cc1236b..8fa5268c19004 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -76,13 +76,10 @@ pub struct MemoryExtra { /// The random number generator used for resolving non-determinism. pub(crate) rng: RefCell, - - /// Whether to enforce the validity invariant. - pub(crate) validate: bool, } impl MemoryExtra { - pub fn new(rng: StdRng, validate: bool, stacked_borrows: bool, tracked_pointer_tag: Option) -> Self { + pub fn new(rng: StdRng, stacked_borrows: bool, tracked_pointer_tag: Option) -> Self { let stacked_borrows = if stacked_borrows { Some(Rc::new(RefCell::new(stacked_borrows::GlobalState::new(tracked_pointer_tag)))) } else { @@ -92,7 +89,6 @@ impl MemoryExtra { stacked_borrows, intptrcast: Default::default(), rng: RefCell::new(rng), - validate, } } } @@ -120,6 +116,9 @@ pub struct Evaluator<'tcx> { /// and random number generation is delegated to the host. pub(crate) communicate: bool, + /// Whether to enforce the validity invariant. + pub(crate) validate: bool, + pub(crate) file_handler: FileHandler, /// The temporary used for storing the argument of @@ -128,7 +127,7 @@ pub struct Evaluator<'tcx> { } impl<'tcx> Evaluator<'tcx> { - pub(crate) fn new(communicate: bool) -> Self { + pub(crate) fn new(communicate: bool, validate: bool) -> Self { Evaluator { // `env_vars` could be initialized properly here if `Memory` were available before // calling this method. @@ -139,6 +138,7 @@ impl<'tcx> Evaluator<'tcx> { last_error: None, tls: TlsData::default(), communicate, + validate, file_handler: Default::default(), panic_payload: None, } @@ -183,7 +183,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { #[inline(always)] fn enforce_validity(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool { - ecx.memory.extra.validate + ecx.machine.validate } #[inline(always)] From 9fcc8a2a9172802c30b7918c03b24ec556d5fd8e Mon Sep 17 00:00:00 2001 From: David Cook Date: Mon, 24 Feb 2020 19:16:41 -0600 Subject: [PATCH 1589/3747] Review comments --- src/shims/foreign_items/posix/linux.rs | 2 +- src/shims/foreign_items/posix/macos.rs | 2 +- src/shims/fs.rs | 42 ++++++++++++++++++-------- tests/run-pass/fs.rs | 2 ++ 4 files changed, 34 insertions(+), 14 deletions(-) diff --git a/src/shims/foreign_items/posix/linux.rs b/src/shims/foreign_items/posix/linux.rs index 2872e92fa1ee1..8a1ce5594ae46 100644 --- a/src/shims/foreign_items/posix/linux.rs +++ b/src/shims/foreign_items/posix/linux.rs @@ -37,7 +37,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // The `macos` module has a parallel foreign item, `readdir_r`, which uses a different // struct layout. "readdir64_r" => { - let result = this.readdir64_r(args[0], args[1], args[2])?; + let result = this.linux_readdir64_r(args[0], args[1], args[2])?; this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; } diff --git a/src/shims/foreign_items/posix/macos.rs b/src/shims/foreign_items/posix/macos.rs index e6f4047eee47c..cb6cd9ba44b40 100644 --- a/src/shims/foreign_items/posix/macos.rs +++ b/src/shims/foreign_items/posix/macos.rs @@ -52,7 +52,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // The `linux` module has a parallel foreign item, `readdir64_r`, which uses a // different struct layout. "readdir_r$INODE64" => { - let result = this.readdir_r(args[0], args[1], args[2])?; + let result = this.macos_readdir_r(args[0], args[1], args[2])?; this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; } diff --git a/src/shims/fs.rs b/src/shims/fs.rs index f3b1cc7124c81..d999b8066cc8b 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -809,7 +809,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.check_no_isolation("mkdir")?; - let _mode = if this.tcx.sess.target.target.target_os.to_lowercase() == "macos" { + let _mode = if this.tcx.sess.target.target.target_os.as_str() == "macos" { this.read_scalar(mode_op)?.not_undef()?.to_u16()? as u32 } else { this.read_scalar(mode_op)?.to_u32()? @@ -863,16 +863,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // The libc API for opendir says that this method returns a pointer to an opaque // structure, but we are returning an ID number. Thus, pass it as a scalar of // pointer width. - Ok(Scalar::from_int(id, this.pointer_size())) + Ok(Scalar::from_machine_usize(id, this)) } Err(e) => { this.set_last_error_from_io_error(e)?; - Ok(Scalar::from_int(0, this.memory.pointer_size())) + Ok(Scalar::from_machine_usize(0, this)) } } } - fn readdir64_r( + fn linux_readdir64_r( &mut self, dirp_op: OpTy<'tcx, Tag>, entry_op: OpTy<'tcx, Tag>, @@ -884,9 +884,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let dirp = this.read_scalar(dirp_op)?.to_machine_usize(this)?; - let entry_ptr = this.force_ptr(this.read_scalar(entry_op)?.not_undef()?)?; - let dirent64_layout = this.libc_ty_layout("dirent64")?; - let dir_iter = this.machine.dir_handler.streams.get_mut(&dirp).ok_or_else(|| { err_unsup_format!("The DIR pointer passed to readdir64_r did not come from opendir") })?; @@ -896,13 +893,24 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // The name is written with write_os_str_to_c_str, while the rest of the // dirent64 struct is written using write_packed_immediates. + // For reference: + // pub struct dirent64 { + // pub d_ino: ino64_t, + // pub d_off: off64_t, + // pub d_reclen: c_ushort, + // pub d_type: c_uchar, + // pub d_name: [c_char; 256], + // } + + let entry_ptr = this.force_ptr(this.read_scalar(entry_op)?.not_undef()?)?; + let dirent64_layout = this.libc_ty_layout("dirent64")?; let name_offset = dirent64_layout.details.fields.offset(4); let name_ptr = entry_ptr.offset(name_offset, this)?; let file_name = dir_entry.file_name(); let name_fits = this.write_os_str_to_c_str(&file_name, Scalar::Ptr(name_ptr), 256)?; if !name_fits { - panic!("A directory entry had a name too large to fit in libc::dirent64"); + throw_unsup_format!("A directory entry had a name too large to fit in libc::dirent64"); } let entry_place = this.deref_operand(entry_op)?; @@ -948,7 +956,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } - fn readdir_r( + fn macos_readdir_r( &mut self, dirp_op: OpTy<'tcx, Tag>, entry_op: OpTy<'tcx, Tag>, @@ -960,8 +968,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let dirp = this.read_scalar(dirp_op)?.to_machine_usize(this)?; - let entry_ptr = this.force_ptr(this.read_scalar(entry_op)?.not_undef()?)?; - let dirent_layout = this.libc_ty_layout("dirent")?; let dir_iter = this.machine.dir_handler.streams.get_mut(&dirp).ok_or_else(|| { err_unsup_format!("The DIR pointer passed to readdir_r did not come from opendir") @@ -972,13 +978,25 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // The name is written with write_os_str_to_c_str, while the rest of the // dirent struct is written using write_packed_Immediates. + // For reference: + // pub struct dirent { + // pub d_ino: u64, + // pub d_seekoff: u64, + // pub d_reclen: u16, + // pub d_namlen: u16, + // pub d_type: u8, + // pub d_name: [c_char; 1024], + // } + + let entry_ptr = this.force_ptr(this.read_scalar(entry_op)?.not_undef()?)?; + let dirent_layout = this.libc_ty_layout("dirent")?; let name_offset = dirent_layout.details.fields.offset(5); let name_ptr = entry_ptr.offset(name_offset, this)?; let file_name = dir_entry.file_name(); let name_fits = this.write_os_str_to_c_str(&file_name, Scalar::Ptr(name_ptr), 1024)?; if !name_fits { - panic!("A directory entry had a name too large to fit in libc::dirent"); + throw_unsup_format!("A directory entry had a name too large to fit in libc::dirent"); } let entry_place = this.deref_operand(entry_op)?; diff --git a/tests/run-pass/fs.rs b/tests/run-pass/fs.rs index b938fceb8d026..f859f934bdd1c 100644 --- a/tests/run-pass/fs.rs +++ b/tests/run-pass/fs.rs @@ -199,6 +199,8 @@ fn test_directory() { create_dir(&dir_path).unwrap(); // Test that the metadata of a directory is correct. assert!(dir_path.metadata().unwrap().is_dir()); + // Creating a directory when it already exists should fail. + assert_eq!(ErrorKind::AlreadyExists, create_dir(&dir_path).unwrap_err().kind()); // Create some files inside the directory let path_1 = dir_path.join("test_file_1"); From 9e03b4133894614b37469cde63d4f4c28341ec81 Mon Sep 17 00:00:00 2001 From: David Cook Date: Mon, 24 Feb 2020 19:38:17 -0600 Subject: [PATCH 1590/3747] Migrate readdir_r from pointers to places --- src/shims/fs.rs | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/src/shims/fs.rs b/src/shims/fs.rs index d999b8066cc8b..a3ac59bdf6e78 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -902,13 +902,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // pub d_name: [c_char; 256], // } - let entry_ptr = this.force_ptr(this.read_scalar(entry_op)?.not_undef()?)?; - let dirent64_layout = this.libc_ty_layout("dirent64")?; - let name_offset = dirent64_layout.details.fields.offset(4); - let name_ptr = entry_ptr.offset(name_offset, this)?; + let entry_place = this.deref_operand(entry_op)?; + let name_place = this.mplace_field(entry_place, 4)?; let file_name = dir_entry.file_name(); - let name_fits = this.write_os_str_to_c_str(&file_name, Scalar::Ptr(name_ptr), 256)?; + let name_fits = this.write_os_str_to_c_str(&file_name, name_place.ptr, name_place.layout.size.bytes())?; if !name_fits { throw_unsup_format!("A directory entry had a name too large to fit in libc::dirent64"); } @@ -988,13 +986,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // pub d_name: [c_char; 1024], // } - let entry_ptr = this.force_ptr(this.read_scalar(entry_op)?.not_undef()?)?; - let dirent_layout = this.libc_ty_layout("dirent")?; - let name_offset = dirent_layout.details.fields.offset(5); - let name_ptr = entry_ptr.offset(name_offset, this)?; + let entry_place = this.deref_operand(entry_op)?; + let name_place = this.mplace_field(entry_place, 5)?; let file_name = dir_entry.file_name(); - let name_fits = this.write_os_str_to_c_str(&file_name, Scalar::Ptr(name_ptr), 1024)?; + let name_fits = this.write_os_str_to_c_str(&file_name, name_place.ptr, name_place.layout.size.bytes())?; if !name_fits { throw_unsup_format!("A directory entry had a name too large to fit in libc::dirent"); } From ad8c784009bfa0934815fcf7383c1ff1e2cb8cc1 Mon Sep 17 00:00:00 2001 From: David Cook Date: Mon, 24 Feb 2020 19:50:25 -0600 Subject: [PATCH 1591/3747] Return length from write_os_str_to_c_str --- src/helpers.rs | 57 ++++++++++++++++++++---------------------------- src/shims/env.rs | 2 +- src/shims/fs.rs | 12 ++++++---- 3 files changed, 33 insertions(+), 38 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index 24adc72fa87b5..53facf89dce92 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -474,35 +474,42 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } /// Helper function to write an OsStr as a null-terminated sequence of bytes, which is what - /// the Unix APIs usually handle. This function returns `Ok(false)` without trying to write if - /// `size` is not large enough to fit the contents of `os_string` plus a null terminator. It - /// returns `Ok(true)` if the writing process was successful. + /// the Unix APIs usually handle. This function returns `Ok((false, length))` without trying + /// to write if `size` is not large enough to fit the contents of `os_string` plus a null + /// terminator. It returns `Ok((true, length))` if the writing process was successful. The + /// string length returned does not include the null terminator. fn write_os_str_to_c_str( &mut self, os_str: &OsStr, scalar: Scalar, size: u64, - ) -> InterpResult<'tcx, bool> { + ) -> InterpResult<'tcx, (bool, u64)> { + #[cfg(target_os = "unix")] + fn os_str_to_bytes<'tcx, 'a>(os_str: &'a OsStr) -> InterpResult<'tcx, &'a [u8]> { + std::os::unix::ffi::OsStringExt::into_bytes(os_str) + } + #[cfg(not(target_os = "unix"))] + fn os_str_to_bytes<'tcx, 'a>(os_str: &'a OsStr) -> InterpResult<'tcx, &'a [u8]> { + // On non-unix platforms the best we can do to transform bytes from/to OS strings is to do the + // intermediate transformation into strings. Which invalidates non-utf8 paths that are actually + // valid. + os_str + .to_str() + .map(|s| s.as_bytes()) + .ok_or_else(|| err_unsup_format!("{:?} is not a valid utf-8 string", os_str).into()) + } + let bytes = os_str_to_bytes(os_str)?; // If `size` is smaller or equal than `bytes.len()`, writing `bytes` plus the required null // terminator to memory using the `ptr` pointer would cause an out-of-bounds access. - if size <= bytes.len() as u64 { - return Ok(false); + let string_length = bytes.len() as u64; + if size <= string_length { + return Ok((false, string_length)); } self.eval_context_mut() .memory .write_bytes(scalar, bytes.iter().copied().chain(iter::once(0u8)))?; - Ok(true) - } - - /// Helper function to determine how long an OsStr would be as a C string, not including the - /// null terminator. - fn os_str_length_as_c_str( - &mut self, - os_str: &OsStr, - ) -> InterpResult<'tcx, usize> { - let bytes = os_str_to_bytes(os_str)?; - Ok(bytes.len()) + Ok((true, string_length)) } fn alloc_os_str_as_c_str( @@ -520,22 +527,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } -#[cfg(target_os = "unix")] -fn os_str_to_bytes<'tcx, 'a>(os_str: &'a OsStr) -> InterpResult<'tcx, &'a [u8]> { - std::os::unix::ffi::OsStringExt::into_bytes(os_str) -} - -#[cfg(not(target_os = "unix"))] -fn os_str_to_bytes<'tcx, 'a>(os_str: &'a OsStr) -> InterpResult<'tcx, &'a [u8]> { - // On non-unix platforms the best we can do to transform bytes from/to OS strings is to do the - // intermediate transformation into strings. Which invalidates non-utf8 paths that are actually - // valid. - os_str - .to_str() - .map(|s| s.as_bytes()) - .ok_or_else(|| err_unsup_format!("{:?} is not a valid utf-8 string", os_str).into()) -} - pub fn immty_from_int_checked<'tcx>( int: impl Into, layout: TyLayout<'tcx>, diff --git a/src/shims/env.rs b/src/shims/env.rs index 96174010441c4..3fd895576e534 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -124,7 +124,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // If we cannot get the current directory, we return null match env::current_dir() { Ok(cwd) => { - if this.write_os_str_to_c_str(&OsString::from(cwd), buf, size)? { + if this.write_os_str_to_c_str(&OsString::from(cwd), buf, size)?.0 { return Ok(buf); } let erange = this.eval_libc("ERANGE")?; diff --git a/src/shims/fs.rs b/src/shims/fs.rs index a3ac59bdf6e78..cbdaf9a65b7d0 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -906,7 +906,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let name_place = this.mplace_field(entry_place, 4)?; let file_name = dir_entry.file_name(); - let name_fits = this.write_os_str_to_c_str(&file_name, name_place.ptr, name_place.layout.size.bytes())?; + let (name_fits, _) = this.write_os_str_to_c_str( + &file_name, name_place.ptr, + name_place.layout.size.bytes(), + )?; if !name_fits { throw_unsup_format!("A directory entry had a name too large to fit in libc::dirent64"); } @@ -990,7 +993,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let name_place = this.mplace_field(entry_place, 5)?; let file_name = dir_entry.file_name(); - let name_fits = this.write_os_str_to_c_str(&file_name, name_place.ptr, name_place.layout.size.bytes())?; + let (name_fits, file_name_len) = this.write_os_str_to_c_str( + &file_name, name_place.ptr, + name_place.layout.size.bytes(), + )?; if !name_fits { throw_unsup_format!("A directory entry had a name too large to fit in libc::dirent"); } @@ -1008,8 +1014,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx #[cfg(not(unix))] let ino = 0; - let file_name_len = this.os_str_length_as_c_str(&file_name)? as u128; - let file_type = this.file_type_to_d_type(dir_entry.file_type())? as u128; let imms = [ From 739d796b0588bb7c38c2a69f17d44084d48d5010 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 25 Feb 2020 18:12:00 +0100 Subject: [PATCH 1592/3747] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index fe788019e0128..d338cf6694bb6 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -2851e59a52673e0242532035047009c6e121c95a +e3a277943e5e55a4ef169d5cc629de664db5e24e From 7e128beff92f0a3c790e18dd1c43e107629d6fa9 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 26 Feb 2020 13:50:33 +0100 Subject: [PATCH 1593/3747] fix build failures --- benches/helpers/miri_helper.rs | 1 + src/bin/miri-rustc-tests.rs | 2 ++ 2 files changed, 3 insertions(+) diff --git a/benches/helpers/miri_helper.rs b/benches/helpers/miri_helper.rs index 122d381f79272..2483f2de3a864 100644 --- a/benches/helpers/miri_helper.rs +++ b/benches/helpers/miri_helper.rs @@ -31,6 +31,7 @@ impl rustc_driver::Callbacks for MiriCompilerCalls<'_> { self.bencher.iter(|| { let config = miri::MiriConfig { validate: true, + stacked_borrows: true, communicate: false, ignore_leaks: false, excluded_env_vars: vec![], diff --git a/src/bin/miri-rustc-tests.rs b/src/bin/miri-rustc-tests.rs index 2ac0ab9ca4de1..abda47f75b1c2 100644 --- a/src/bin/miri-rustc-tests.rs +++ b/src/bin/miri-rustc-tests.rs @@ -46,6 +46,7 @@ impl rustc_driver::Callbacks for MiriCompilerCalls { { let config = MiriConfig { validate: true, + stacked_borrows: true, communicate: false, ignore_leaks: false, excluded_env_vars: vec![], @@ -67,6 +68,7 @@ impl rustc_driver::Callbacks for MiriCompilerCalls { } else if let Some((entry_def_id, _)) = tcx.entry_fn(LOCAL_CRATE) { let config = MiriConfig { validate: true, + stacked_borrows: true, communicate: false, ignore_leaks: false, excluded_env_vars: vec![], From df59d7ff749a685d6259271be9c0d6466b347f2f Mon Sep 17 00:00:00 2001 From: David Cook Date: Wed, 26 Feb 2020 07:59:11 -0600 Subject: [PATCH 1594/3747] Review comments --- src/shims/fs.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/shims/fs.rs b/src/shims/fs.rs index cbdaf9a65b7d0..880d7ddd0ae96 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -881,6 +881,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); this.check_no_isolation("readdir64_r")?; + this.assert_platform("linux", "readdir64_r"); let dirp = this.read_scalar(dirp_op)?.to_machine_usize(this)?; @@ -907,7 +908,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let file_name = dir_entry.file_name(); let (name_fits, _) = this.write_os_str_to_c_str( - &file_name, name_place.ptr, + &file_name, + name_place.ptr, name_place.layout.size.bytes(), )?; if !name_fits { @@ -966,10 +968,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); this.check_no_isolation("readdir_r")?; + this.assert_platform("macos", "readdir_r"); let dirp = this.read_scalar(dirp_op)?.to_machine_usize(this)?; - let dir_iter = this.machine.dir_handler.streams.get_mut(&dirp).ok_or_else(|| { err_unsup_format!("The DIR pointer passed to readdir_r did not come from opendir") })?; @@ -994,7 +996,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let file_name = dir_entry.file_name(); let (name_fits, file_name_len) = this.write_os_str_to_c_str( - &file_name, name_place.ptr, + &file_name, + name_place.ptr, name_place.layout.size.bytes(), )?; if !name_fits { From 62f9f4c578ab2780468ac3a25fe46d0d9a1c8146 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 26 Feb 2020 15:15:16 +0100 Subject: [PATCH 1595/3747] fix Windows build failure --- src/shims/fs.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/shims/fs.rs b/src/shims/fs.rs index 880d7ddd0ae96..cc8f18af7d618 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -927,7 +927,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx #[cfg(unix)] let ino = std::os::unix::fs::DirEntryExt::ino(&dir_entry); #[cfg(not(unix))] - let ino = 0; + let ino = 0u64; let file_type = this.file_type_to_d_type(dir_entry.file_type())? as u128; @@ -1015,7 +1015,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx #[cfg(unix)] let ino = std::os::unix::fs::DirEntryExt::ino(&dir_entry); #[cfg(not(unix))] - let ino = 0; + let ino = 0u64; let file_type = this.file_type_to_d_type(dir_entry.file_type())? as u128; From 5187e5ddd68bf0ac3d6da3302eb11ca46c83e7ce Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 28 Feb 2020 10:00:20 +0100 Subject: [PATCH 1596/3747] avoid Scalar::to_bits --- src/shims/foreign_items/posix.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/shims/foreign_items/posix.rs b/src/shims/foreign_items/posix.rs index 636137f62de05..e80908d8fa09f 100644 --- a/src/shims/foreign_items/posix.rs +++ b/src/shims/foreign_items/posix.rs @@ -205,18 +205,18 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_null(dest)?; } "pthread_key_delete" => { - let key = this.read_scalar(args[0])?.to_bits(args[0].layout.size)?; + let key = this.force_bits(this.read_scalar(args[0])?.not_undef()?, args[0].layout.size)?; this.machine.tls.delete_tls_key(key)?; // Return success (0) this.write_null(dest)?; } "pthread_getspecific" => { - let key = this.read_scalar(args[0])?.to_bits(args[0].layout.size)?; + let key = this.force_bits(this.read_scalar(args[0])?.not_undef()?, args[0].layout.size)?; let ptr = this.machine.tls.load_tls(key, tcx)?; this.write_scalar(ptr, dest)?; } "pthread_setspecific" => { - let key = this.read_scalar(args[0])?.to_bits(args[0].layout.size)?; + let key = this.force_bits(this.read_scalar(args[0])?.not_undef()?, args[0].layout.size)?; let new_ptr = this.read_scalar(args[1])?.not_undef()?; this.machine.tls.store_tls(key, this.test_null(new_ptr)?)?; From df732c863e4c7d86f23ea2e47abd7db4798bde82 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 29 Feb 2020 13:28:59 +0100 Subject: [PATCH 1597/3747] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index d338cf6694bb6..f1a0bf19e34b2 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -e3a277943e5e55a4ef169d5cc629de664db5e24e +04e7f96dd89b1f0ad615dff1c85d11d4c4c64cb4 From 2b04e3954a1aace62bd8e127f2b80c8cdfeeb5e6 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 29 Feb 2020 19:46:42 +0100 Subject: [PATCH 1598/3747] Remove incorrect try_lock from Windows critical section shim --- src/shims/foreign_items/windows.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/shims/foreign_items/windows.rs b/src/shims/foreign_items/windows.rs index 29eac99e565cd..623b0f307b911 100644 --- a/src/shims/foreign_items/windows.rs +++ b/src/shims/foreign_items/windows.rs @@ -124,11 +124,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "DeleteCriticalSection" => { // Nothing to do, not even a return value. + // (Windows locks are reentrant, and we have only 1 thread, + // so not doing any futher checks here is at least not incorrect.) } | "GetModuleHandleW" | "GetProcAddress" - | "TryEnterCriticalSection" | "GetConsoleScreenBufferInfo" | "SetConsoleTextAttribute" => { From ea5aa19487a28246c2fa29155c4f7be21b4cdfd0 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 1 Mar 2020 10:22:13 +0100 Subject: [PATCH 1599/3747] rustup --- rust-version | 2 +- src/lib.rs | 2 +- src/machine.rs | 2 +- src/shims/foreign_items.rs | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/rust-version b/rust-version index f1a0bf19e34b2..f28fce1af27c7 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -04e7f96dd89b1f0ad615dff1c85d11d4c4c64cb4 +d9051341a1c142542a3f7dab509266606c775382 diff --git a/src/lib.rs b/src/lib.rs index 10dfc32b0f781..f62f9a850d151 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -8,7 +8,7 @@ extern crate log; // From rustc. extern crate rustc_apfloat; -extern crate syntax; +extern crate rustc_ast; #[macro_use] extern crate rustc; extern crate rustc_hir; diff --git a/src/machine.rs b/src/machine.rs index ec4c69159c6ec..f90c8b82e64f7 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -16,7 +16,7 @@ use rustc::ty::{ Ty, TyCtxt, }; use rustc_span::{source_map::Span, symbol::sym}; -use syntax::attr; +use rustc_ast::attr; use crate::*; diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 3d8d3bd52607a..f8b42e5091339 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -9,7 +9,7 @@ use rustc::ty; use rustc::ty::layout::{Align, Size}; use rustc_apfloat::Float; use rustc_span::symbol::sym; -use syntax::attr; +use rustc_ast::attr; use crate::*; From cc1ebd0af62c4d0b7138a07893ee73d3e4ef05a5 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 1 Mar 2020 10:26:24 +0100 Subject: [PATCH 1600/3747] some formatting --- src/eval.rs | 7 ++----- src/helpers.rs | 12 +++++------ src/lib.rs | 18 +++++++++++------ src/machine.rs | 46 +++++++++++++++++------------------------- src/operator.rs | 6 +++--- src/stacked_borrows.rs | 25 ++++++++++++++--------- 6 files changed, 57 insertions(+), 57 deletions(-) diff --git a/src/eval.rs b/src/eval.rs index eca634d02098c..cc02100dd3b3e 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -5,9 +5,9 @@ use std::ffi::OsStr; use rand::rngs::StdRng; use rand::SeedableRng; -use rustc_hir::def_id::DefId; use rustc::ty::layout::{LayoutOf, Size}; use rustc::ty::{self, TyCtxt}; +use rustc_hir::def_id::DefId; use crate::*; @@ -50,10 +50,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( let mut ecx = InterpCx::new( tcx.at(rustc_span::source_map::DUMMY_SP), ty::ParamEnv::reveal_all(), - Evaluator::new( - config.communicate, - config.validate, - ), + Evaluator::new(config.communicate, config.validate), MemoryExtra::new( StdRng::seed_from_u64(config.seed.unwrap_or(0)), config.stacked_borrows, diff --git a/src/helpers.rs b/src/helpers.rs index 53facf89dce92..19db6852c56a7 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -1,13 +1,13 @@ use std::ffi::OsStr; use std::{iter, mem}; -use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX}; use rustc::mir; use rustc::ty::{ self, layout::{self, LayoutOf, Size, TyLayout}, List, TyCtxt, }; +use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX}; use rustc_span::source_map::DUMMY_SP; use rand::RngCore; @@ -515,7 +515,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn alloc_os_str_as_c_str( &mut self, os_str: &OsStr, - memkind: MemoryKind + memkind: MemoryKind, ) -> Pointer { let size = os_str.len() as u64 + 1; // Make space for `0` terminator. let this = self.eval_context_mut(); @@ -532,9 +532,9 @@ pub fn immty_from_int_checked<'tcx>( layout: TyLayout<'tcx>, ) -> InterpResult<'tcx, ImmTy<'tcx, Tag>> { let int = int.into(); - Ok(ImmTy::try_from_int(int, layout).ok_or_else(|| + Ok(ImmTy::try_from_int(int, layout).ok_or_else(|| { err_unsup_format!("Signed value {:#x} does not fit in {} bits", int, layout.size.bits()) - )?) + })?) } pub fn immty_from_uint_checked<'tcx>( @@ -542,7 +542,7 @@ pub fn immty_from_uint_checked<'tcx>( layout: TyLayout<'tcx>, ) -> InterpResult<'tcx, ImmTy<'tcx, Tag>> { let int = int.into(); - Ok(ImmTy::try_from_uint(int, layout).ok_or_else(|| + Ok(ImmTy::try_from_uint(int, layout).ok_or_else(|| { err_unsup_format!("Signed value {:#x} does not fit in {} bits", int, layout.size.bits()) - )?) + })?) } diff --git a/src/lib.rs b/src/lib.rs index f62f9a850d151..2a805f8555790 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -11,10 +11,10 @@ extern crate rustc_apfloat; extern crate rustc_ast; #[macro_use] extern crate rustc; -extern crate rustc_hir; -extern crate rustc_span; extern crate rustc_data_structures; +extern crate rustc_hir; extern crate rustc_mir; +extern crate rustc_span; extern crate rustc_target; mod diagnostics; @@ -44,7 +44,8 @@ pub use crate::shims::tls::{EvalContextExt as TlsEvalContextExt, TlsData}; pub use crate::shims::EvalContextExt as ShimsEvalContextExt; pub use crate::diagnostics::{ - register_diagnostic, report_diagnostic, EvalContextExt as DiagnosticsEvalContextExt, NonHaltingDiagnostic, + register_diagnostic, report_diagnostic, EvalContextExt as DiagnosticsEvalContextExt, + NonHaltingDiagnostic, }; pub use crate::eval::{create_ecx, eval_main, MiriConfig, TerminationInfo}; pub use crate::helpers::EvalContextExt as HelpersEvalContextExt; @@ -56,12 +57,17 @@ pub use crate::mono_hash_map::MonoHashMap; pub use crate::operator::EvalContextExt as OperatorEvalContextExt; pub use crate::range_map::RangeMap; pub use crate::stacked_borrows::{ - EvalContextExt as StackedBorEvalContextExt, Item, Permission, PtrId, Stack, - Stacks, Tag, + EvalContextExt as StackedBorEvalContextExt, Item, Permission, PtrId, Stack, Stacks, Tag, }; /// Insert rustc arguments at the beginning of the argument list that Miri wants to be /// set per default, for maximal validation power. pub fn miri_default_args() -> &'static [&'static str] { - &["-Zalways-encode-mir", "-Zmir-emit-retag", "-Zmir-opt-level=0", "--cfg=miri", "-Cdebug-assertions=on"] + &[ + "-Zalways-encode-mir", + "-Zmir-emit-retag", + "-Zmir-opt-level=0", + "--cfg=miri", + "-Cdebug-assertions=on", + ] } diff --git a/src/machine.rs b/src/machine.rs index f90c8b82e64f7..b5c76070ae30b 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -3,20 +3,20 @@ use std::borrow::Cow; use std::cell::RefCell; -use std::rc::Rc; use std::num::NonZeroU64; +use std::rc::Rc; use rand::rngs::StdRng; -use rustc_hir::def_id::DefId; use rustc::mir; use rustc::ty::{ self, layout::{LayoutOf, Size}, Ty, TyCtxt, }; -use rustc_span::{source_map::Span, symbol::sym}; use rustc_ast::attr; +use rustc_hir::def_id::DefId; +use rustc_span::{source_map::Span, symbol::sym}; use crate::*; @@ -85,11 +85,7 @@ impl MemoryExtra { } else { None }; - MemoryExtra { - stacked_borrows, - intptrcast: Default::default(), - rng: RefCell::new(rng), - } + MemoryExtra { stacked_borrows, intptrcast: Default::default(), rng: RefCell::new(rng) } } } @@ -307,18 +303,15 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { ) -> (Cow<'b, Allocation>, Self::PointerTag) { let kind = kind.expect("we set our STATIC_KIND so this cannot be None"); let alloc = alloc.into_owned(); - let (stacks, base_tag) = if let Some(stacked_borrows) = memory_extra.stacked_borrows.as_ref() { - let (stacks, base_tag) = Stacks::new_allocation( - id, - alloc.size, - Rc::clone(stacked_borrows), - kind, - ); - (Some(stacks), base_tag) - } else { - // No stacks, no tag. - (None, Tag::Untagged) - }; + let (stacks, base_tag) = + if let Some(stacked_borrows) = memory_extra.stacked_borrows.as_ref() { + let (stacks, base_tag) = + Stacks::new_allocation(id, alloc.size, Rc::clone(stacked_borrows), kind); + (Some(stacks), base_tag) + } else { + // No stacks, no tag. + (None, Tag::Untagged) + }; let mut stacked_borrows = memory_extra.stacked_borrows.as_ref().map(|sb| sb.borrow_mut()); let alloc: Allocation = alloc.with_tags_and_extra( |alloc| { @@ -360,14 +353,11 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { #[inline(always)] fn stack_push(ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx, FrameData<'tcx>> { - let call_id = ecx.memory.extra.stacked_borrows.as_ref().map_or( - NonZeroU64::new(1).unwrap(), - |stacked_borrows| stacked_borrows.borrow_mut().new_call(), - ); - Ok(FrameData { - call_id, - catch_panic: None, - }) + let stacked_borrows = ecx.memory.extra.stacked_borrows.as_ref(); + let call_id = stacked_borrows.map_or(NonZeroU64::new(1).unwrap(), |stacked_borrows| { + stacked_borrows.borrow_mut().new_call() + }); + Ok(FrameData { call_id, catch_panic: None }) } #[inline(always)] diff --git a/src/operator.rs b/src/operator.rs index 8860b949fe942..c494e4ff8c724 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -103,9 +103,9 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { offset: i64, ) -> InterpResult<'tcx, Scalar> { let pointee_size = i64::try_from(self.layout_of(pointee_ty)?.size.bytes()).unwrap(); - let offset = offset - .checked_mul(pointee_size) - .ok_or_else(|| err_ub_format!("overflow during offset comutation for inbounds pointer arithmetic"))?; + let offset = offset.checked_mul(pointee_size).ok_or_else(|| { + err_ub_format!("overflow during offset comutation for inbounds pointer arithmetic") + })?; // We do this first, to rule out overflows. let offset_ptr = ptr.ptr_signed_offset(offset, self)?; // What we need to check is that starting at `min(ptr, offset_ptr)`, diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 9a674830c8ec2..a51f8c457143a 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -7,9 +7,9 @@ use std::fmt; use std::num::NonZeroU64; use std::rc::Rc; -use rustc_hir::Mutability; use rustc::mir::RetagKind; use rustc::ty::{self, layout::Size}; +use rustc_hir::Mutability; use crate::*; @@ -293,9 +293,12 @@ impl<'tcx> Stack { // Two main steps: Find granting item, remove incompatible items above. // Step 1: Find granting item. - let granting_idx = self.find_granting(access, tag).ok_or_else(|| err_ub!(UbExperimental( - format!("no item granting {} to tag {:?} found in borrow stack.", access, tag), - )))?; + let granting_idx = self.find_granting(access, tag).ok_or_else(|| { + err_ub!(UbExperimental(format!( + "no item granting {} to tag {:?} found in borrow stack.", + access, tag + ),)) + })?; // Step 2: Remove incompatible items above them. Make sure we do not remove protected // items. Behavior differs for reads and writes. @@ -334,10 +337,12 @@ impl<'tcx> Stack { /// active protectors at all because we will remove all items. fn dealloc(&mut self, tag: Tag, global: &GlobalState) -> InterpResult<'tcx> { // Step 1: Find granting item. - self.find_granting(AccessKind::Write, tag).ok_or_else(|| err_ub!(UbExperimental(format!( - "no item granting write access for deallocation to tag {:?} found in borrow stack", - tag, - ))))?; + self.find_granting(AccessKind::Write, tag).ok_or_else(|| { + err_ub!(UbExperimental(format!( + "no item granting write access for deallocation to tag {:?} found in borrow stack", + tag, + ))) + })?; // Step 2: Remove all items. Also checks for protectors. for item in self.borrows.drain(..).rev() { @@ -575,7 +580,9 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // breaking `Rc::from_raw`. RefKind::Raw { .. } => Tag::Untagged, // All other pointesr are properly tracked. - _ => Tag::Tagged(this.memory.extra.stacked_borrows.as_ref().unwrap().borrow_mut().new_ptr()), + _ => Tag::Tagged( + this.memory.extra.stacked_borrows.as_ref().unwrap().borrow_mut().new_ptr(), + ), }; // Reborrow. From af98bd9a53f575bf755d172b2e64e552c59a5180 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 1 Mar 2020 11:53:34 +0100 Subject: [PATCH 1601/3747] fix trailing indent in xargo files --- src/bin/cargo-miri.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 17063b6ff67fc..88609d4dea63a 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -353,7 +353,7 @@ default_features = false features = ["panic_unwind"] [dependencies.test] - "#, +"#, ) .unwrap(); // The boring bits: a dummy project for xargo. @@ -369,7 +369,7 @@ version = "0.0.0" [lib] path = "lib.rs" - "#, +"#, ) .unwrap(); File::create(dir.join("lib.rs")).unwrap(); From 48a4e3f4d89a365dde0e0b257d7af6631d4d69aa Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 1 Mar 2020 11:54:19 +0100 Subject: [PATCH 1602/3747] format a few things --- src/bin/cargo-miri.rs | 31 ++++++++++++++++--------------- src/bin/miri-rustc-tests.rs | 8 +++++--- src/bin/miri.rs | 2 +- 3 files changed, 22 insertions(+), 19 deletions(-) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 88609d4dea63a..f8a408561b0b1 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -563,7 +563,8 @@ fn inside_cargo_rustc() { // other args for target crates - that is, crates which are ultimately // going to get interpreted by Miri. if target_crate { - let sysroot = std::env::var("MIRI_SYSROOT").expect("The wrapper should have set MIRI_SYSROOT"); + let sysroot = + std::env::var("MIRI_SYSROOT").expect("The wrapper should have set MIRI_SYSROOT"); args.push("--sysroot".to_owned()); args.push(sysroot); args.splice(0..0, miri::miri_default_args().iter().map(ToString::to_string)); @@ -571,20 +572,20 @@ fn inside_cargo_rustc() { // Figure out the binary we need to call. If this is a runnable target crate, we want to call // Miri to start interpretation; otherwise we want to call rustc to build the crate as usual. - let mut command = - if target_crate && is_runnable_crate() { - // This is the 'target crate' - the binary or test crate that - // we want to interpret under Miri. We deserialize the user-provided arguments - // from the special environment variable "MIRI_ARGS", and feed them - // to the 'miri' binary. - let magic = std::env::var("MIRI_ARGS").expect("missing MIRI_ARGS"); - let mut user_args: Vec = serde_json::from_str(&magic).expect("failed to deserialize MIRI_ARGS"); - args.append(&mut user_args); - // Run this in Miri. - Command::new(find_miri()) - } else { - Command::new("rustc") - }; + let mut command = if target_crate && is_runnable_crate() { + // This is the 'target crate' - the binary or test crate that + // we want to interpret under Miri. We deserialize the user-provided arguments + // from the special environment variable "MIRI_ARGS", and feed them + // to the 'miri' binary. + let magic = std::env::var("MIRI_ARGS").expect("missing MIRI_ARGS"); + let mut user_args: Vec = + serde_json::from_str(&magic).expect("failed to deserialize MIRI_ARGS"); + args.append(&mut user_args); + // Run this in Miri. + Command::new(find_miri()) + } else { + Command::new("rustc") + }; // Run it. command.args(&args); diff --git a/src/bin/miri-rustc-tests.rs b/src/bin/miri-rustc-tests.rs index abda47f75b1c2..9cc9901a9134a 100644 --- a/src/bin/miri-rustc-tests.rs +++ b/src/bin/miri-rustc-tests.rs @@ -15,11 +15,11 @@ use std::io::Write; use std::path::Path; use std::sync::{Arc, Mutex}; +use rustc::ty::TyCtxt; +use rustc_driver::Compilation; use rustc_hir as hir; use rustc_hir::def_id::LOCAL_CRATE; use rustc_hir::itemlikevisit; -use rustc::ty::TyCtxt; -use rustc_driver::Compilation; use rustc_interface::{interface, Queries}; use miri::MiriConfig; @@ -42,7 +42,9 @@ impl rustc_driver::Callbacks for MiriCompilerCalls { impl<'tcx, 'hir> itemlikevisit::ItemLikeVisitor<'hir> for Visitor<'tcx> { fn visit_item(&mut self, i: &'hir hir::Item) { if let hir::ItemKind::Fn(.., body_id) = i.kind { - if i.attrs.iter().any(|attr| attr.check_name(rustc_span::symbol::sym::test)) + if i.attrs + .iter() + .any(|attr| attr.check_name(rustc_span::symbol::sym::test)) { let config = MiriConfig { validate: true, diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 9523609889cd7..e69e7f7b6f50f 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -21,8 +21,8 @@ use std::str::FromStr; use hex::FromHexError; -use rustc_hir::def_id::LOCAL_CRATE; use rustc_driver::Compilation; +use rustc_hir::def_id::LOCAL_CRATE; use rustc_interface::{interface, Queries}; struct MiriCompilerCalls { From 340e14ee4204599c573e4f651e636aeaab5ce037 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 23 Feb 2020 17:45:57 +0100 Subject: [PATCH 1603/3747] tweak benchmark --- bench-cargo-miri/mse/src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bench-cargo-miri/mse/src/main.rs b/bench-cargo-miri/mse/src/main.rs index 696de93442ed1..b4ad1575104e2 100644 --- a/bench-cargo-miri/mse/src/main.rs +++ b/bench-cargo-miri/mse/src/main.rs @@ -2,7 +2,7 @@ static EXPECTED: &[u8] = &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, static PCM: &[i16] = &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, -2, 0, -2, 0, -2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 1, 0, 1, 0, 0, -2, 0, -2, 0, -2, 0, -2, -2, -2, -3, -3, -3, -3, -4, -2, -5, -2, -5, -2, -4, 0, -4, 0, -4, 0, -4, 1, -4, 1, -4, 2, -4, 2, -4, 2, -4, 2, -4, 2, -3, 1, -4, 0, -4, 0, -5, 0, -5, 0, -5, 0, -4, 2, -4, 3, -4, 4, -3, 5, -2, 5, -3, 6, -3, 6, -3, 5, -3, 5, -2, 4, -2, 3, -5, 0, -6, 0, -3, -2, -4, -4, -9, -5, -9, -4, -4, -2, -4, -2, -4, 0, -2, 1, 1, 1, 4, 2, 8, 2, 12, 1, 13, 0, 12, 0, 11, 0, 8, -2, 7, 0, 7, -3, 11, -8, 15, -9, 17, -6, 17, -5, 13, -3, 7, 0, 3, 0, -2, 0, -4, 0, -4, -2, -6, 0, -14, -2, -17, -4, -8, 0, -7, 5, -17, 7, -18, 10, -7, 18, -2, 25, -3, 27, 0, 31, 4, 34, 4, 34, 8, 36, 8, 37, 2, 36, 4, 34, 8, 28, 3, 15, 0, 11, 0, 12, -5, 8, -4, 10, 0, 23, -4, 31, -8, 30, -2, 30, 0, 26, -6, 22, -6, 20, -12, 15, -19, 10, -10, 13, -14, 6, -43, -13, -43, -16, -9, -12, -10, -29, -42, -40, -37, -28, -5, -21, 1, -24, -8, -20, 4, -18, 26, -24, 44, -26, 66, -30, 86, -37, 88, -41, 72, -46, 50, -31, 28, 23, 14, 64, 16, 51, 26, 32, 34, 39, 42, 48, 35, 58, 0, 72, -36, 69, -59, 58, -98, 54, -124, 36, -103, 12, -110, 5, -173, -19, -146, -59, -4, -42, 51, 1, -23, -6, -30, -6, 45, 46, 47, 70, 6, 55, 19, 60, 38, 62, 42, 47, 61, 46, 40, 42, -19, 22, -34, 6, -35, -50, -61, -141, -37, -171, 17, -163, 26, -180, 46, -154, 80, -63, 48, -4, 18, 20, 50, 47, 58, 53, 44, 61, 57, 85, 37, 80, 0, 86, -8, 106, -95, 49, -213, -8, -131, 47, 49, 63, 40, -39, -69, -74, -37, -20, 63, -12, 58, -14, -12, 25, -31, 41, 11, 45, 76, 47, 167, 5, 261, -37, 277, -83, 183, -172, 35, -122, -79, 138, -70, 266, 69, 124, 228, 0, 391, -29, 594, -84, 702, -78, 627, -8, 551, -13, 509, 13, 372, 120, 352, 125, 622, 127, 691, 223, 362, 126, 386, -33, 915, 198, 958, 457, 456, 298, 500, 233, 1027, 469, 1096, 426, 918, 160, 1067, 141, 1220, 189, 1245, 164, 1375, 297, 1378, 503, 1299, 702, 1550, 929, 1799, 855, 1752, 547, 1830, 602, 1928, 832, 1736, 796, 1735, 933, 1961, 1385, 1935, 1562, 2105, 1485, 2716, 1449, 2948, 1305, 2768, 1205, 2716, 1346, 2531, 1450, 2470, 1653, 3117, 2111, 3370, 2176, 2696, 1947, 2925, 2305, 3846, 2658, 2425, 2184, -877, 1981, -2261, 2623, -1645, 2908, -1876, 2732, -2704, 2953, -2484, 3116, -2120, 2954, -2442, 3216, -2466, 3499, -2192, 3234, -2392, 3361, -2497, 3869, -2078, 3772, -1858, 3915, -2066, 4438, -2285, 2934, -2294, -280, -2066, -1762, -1992, -1412, -2298, -1535, -2399, -1789, -2223, -1419, -2244, -1334, -2092, -1476, -1777, -1396, -2014, -1571, -2199, -1574, -1843, -1167, -1910, -1446, -2007, -1818]; fn main() { - for i in 0..5 { + for _ in 0..2 { mse(PCM.len(), PCM, EXPECTED); } } From 5d8fbfcb5f0a9db6c55e1953e5f9680a7e65cbda Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 23 Feb 2020 21:55:02 +0100 Subject: [PATCH 1604/3747] rename memory kind: Env -> Machine --- src/eval.rs | 14 +++++++------- src/machine.rs | 6 +++--- src/shims/env.rs | 6 +++--- src/shims/panic.rs | 2 +- 4 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/eval.rs b/src/eval.rs index cc02100dd3b3e..a46d6ce8a8ed7 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -90,14 +90,14 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( // Make space for `0` terminator. let size = arg.len() as u64 + 1; let arg_type = tcx.mk_array(tcx.types.u8, size); - let arg_place = ecx.allocate(ecx.layout_of(arg_type)?, MiriMemoryKind::Env.into()); + let arg_place = ecx.allocate(ecx.layout_of(arg_type)?, MiriMemoryKind::Machine.into()); ecx.write_os_str_to_c_str(OsStr::new(arg), arg_place.ptr, size)?; argvs.push(arg_place.ptr); } // Make an array with all these pointers, in the Miri memory. let argvs_layout = ecx.layout_of(tcx.mk_array(tcx.mk_imm_ptr(tcx.types.u8), argvs.len() as u64))?; - let argvs_place = ecx.allocate(argvs_layout, MiriMemoryKind::Env.into()); + let argvs_place = ecx.allocate(argvs_layout, MiriMemoryKind::Machine.into()); for (idx, arg) in argvs.into_iter().enumerate() { let place = ecx.mplace_field(argvs_place, idx as u64)?; ecx.write_scalar(arg, place.into())?; @@ -108,13 +108,13 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( // Store `argc` and `argv` for macOS `_NSGetArg{c,v}`. { let argc_place = - ecx.allocate(ecx.layout_of(tcx.types.isize)?, MiriMemoryKind::Env.into()); + ecx.allocate(ecx.layout_of(tcx.types.isize)?, MiriMemoryKind::Machine.into()); ecx.write_scalar(argc, argc_place.into())?; ecx.machine.argc = Some(argc_place.ptr); let argv_place = ecx.allocate( ecx.layout_of(tcx.mk_imm_ptr(tcx.types.unit))?, - MiriMemoryKind::Env.into(), + MiriMemoryKind::Machine.into(), ); ecx.write_scalar(argv, argv_place.into())?; ecx.machine.argv = Some(argv_place.ptr); @@ -134,7 +134,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( let cmd_utf16: Vec = cmd.encode_utf16().collect(); let cmd_type = tcx.mk_array(tcx.types.u16, cmd_utf16.len() as u64); - let cmd_place = ecx.allocate(ecx.layout_of(cmd_type)?, MiriMemoryKind::Env.into()); + let cmd_place = ecx.allocate(ecx.layout_of(cmd_type)?, MiriMemoryKind::Machine.into()); ecx.machine.cmd_line = Some(cmd_place.ptr); // Store the UTF-16 string. We just allocated so we know the bounds are fine. let char_size = Size::from_bytes(2); @@ -147,7 +147,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( }; // Return place (in static memory so that it does not count as leak). - let ret_place = ecx.allocate(ecx.layout_of(tcx.types.isize)?, MiriMemoryKind::Env.into()); + let ret_place = ecx.allocate(ecx.layout_of(tcx.types.isize)?, MiriMemoryKind::Machine.into()); // Call start function. ecx.call_function( start_instance, @@ -158,7 +158,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( // Set the last_error to 0 let errno_layout = ecx.layout_of(tcx.types.u32)?; - let errno_place = ecx.allocate(errno_layout, MiriMemoryKind::Env.into()); + let errno_place = ecx.allocate(errno_layout, MiriMemoryKind::Machine.into()); ecx.write_scalar(Scalar::from_u32(0), errno_place.into())?; ecx.machine.last_error = Some(errno_place); diff --git a/src/machine.rs b/src/machine.rs index b5c76070ae30b..9362ca16eac47 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -48,8 +48,8 @@ pub enum MiriMemoryKind { C, /// Windows `HeapAlloc` memory. WinHeap, - /// Memory for env vars and args, errno and other parts of the machine-managed environment. - Env, + /// Memory for env vars and args, errno, extern statics and other parts of the machine-managed environment. + Machine, /// Rust statics. Static, } @@ -433,7 +433,7 @@ impl MayLeak for MiriMemoryKind { use self::MiriMemoryKind::*; match self { Rust | C | WinHeap => false, - Env | Static => true, + Machine | Static => true, } } } diff --git a/src/shims/env.rs b/src/shims/env.rs index 3fd895576e534..10f749216541e 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -40,7 +40,7 @@ fn alloc_env_var_as_c_str<'mir, 'tcx>( let mut name_osstring = name.to_os_string(); name_osstring.push("="); name_osstring.push(value); - ecx.alloc_os_str_as_c_str(name_osstring.as_os_str(), MiriMemoryKind::Env.into()) + ecx.alloc_os_str_as_c_str(name_osstring.as_os_str(), MiriMemoryKind::Machine.into()) } impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} @@ -80,7 +80,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let var_ptr = alloc_env_var_as_c_str(&name, &value, &mut this); if let Some(var) = this.machine.env_vars.map.insert(name.to_owned(), var_ptr) { this.memory - .deallocate(var, None, MiriMemoryKind::Env.into())?; + .deallocate(var, None, MiriMemoryKind::Machine.into())?; } Ok(0) } else { @@ -102,7 +102,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if let Some(old) = success { if let Some(var) = old { this.memory - .deallocate(var, None, MiriMemoryKind::Env.into())?; + .deallocate(var, None, MiriMemoryKind::Machine.into())?; } Ok(0) } else { diff --git a/src/shims/panic.rs b/src/shims/panic.rs index e930af7f46c5c..11c5a882be9b2 100644 --- a/src/shims/panic.rs +++ b/src/shims/panic.rs @@ -187,7 +187,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // First arg: Message. let msg = msg.description(); - let msg = this.allocate_str(msg, MiriMemoryKind::Env.into()); + let msg = this.allocate_str(msg, MiriMemoryKind::Machine.into()); // Call the lang item. let panic = this.tcx.lang_items().panic_fn().unwrap(); From 8ef303cd3263c8d30db711484393455b38c8d41c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 23 Feb 2020 22:32:37 +0100 Subject: [PATCH 1605/3747] port from find_foreign_static to canonical_alloc_id --- src/eval.rs | 1 + src/machine.rs | 75 +++++++++++++++++++++++++++++------------- src/stacked_borrows.rs | 2 +- 3 files changed, 54 insertions(+), 24 deletions(-) diff --git a/src/eval.rs b/src/eval.rs index a46d6ce8a8ed7..267b79d0eba7e 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -58,6 +58,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( ), ); // Complete initialization. + MemoryExtra::init_extern_statics(&mut ecx)?; EnvVars::init(&mut ecx, config.excluded_env_vars); // Setup first stack-frame diff --git a/src/machine.rs b/src/machine.rs index 9362ca16eac47..e4e709f7e2877 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -3,6 +3,7 @@ use std::borrow::Cow; use std::cell::RefCell; +use std::collections::HashMap; use std::num::NonZeroU64; use std::rc::Rc; @@ -12,7 +13,7 @@ use rustc::mir; use rustc::ty::{ self, layout::{LayoutOf, Size}, - Ty, TyCtxt, + Ty, }; use rustc_ast::attr; use rustc_hir::def_id::DefId; @@ -74,7 +75,11 @@ pub struct MemoryExtra { pub stacked_borrows: Option, pub intptrcast: intptrcast::MemoryExtra, + /// Mapping extern static names to their canonical allocation. + pub(crate) extern_statics: HashMap<&'static str, AllocId>, + /// The random number generator used for resolving non-determinism. + /// Needs to be queried by ptr_to_int, hence needs interior mutability. pub(crate) rng: RefCell, } @@ -85,7 +90,34 @@ impl MemoryExtra { } else { None }; - MemoryExtra { stacked_borrows, intptrcast: Default::default(), rng: RefCell::new(rng) } + MemoryExtra { + stacked_borrows, + intptrcast: Default::default(), + extern_statics: HashMap::default(), + rng: RefCell::new(rng), + } + } + + /// Sets up the "extern statics" for this machine. + pub fn init_extern_statics<'mir, 'tcx>( + this: &mut MiriEvalContext<'mir, 'tcx>, + ) -> InterpResult<'tcx> { + match this.tcx.sess.target.target.target_os.as_str() { + "linux" => { + // "__cxa_thread_atexit_impl" + // This should be all-zero, pointer-sized. + let layout = this.layout_of(this.tcx.types.usize)?; + let place = this.allocate(layout, MiriMemoryKind::Machine.into()); + this.write_scalar(Scalar::from_machine_usize(0, &*this.tcx), place.into())?; + this.memory + .extra + .extern_statics + .insert("__cxa_thread_atexit_impl", place.ptr.assert_ptr().alloc_id) + .unwrap_none(); + } + _ => {} // No "extern statics" supported on this platform + } + Ok(()) } } @@ -267,32 +299,29 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { Ok(()) } - fn find_foreign_static( - tcx: TyCtxt<'tcx>, - def_id: DefId, - ) -> InterpResult<'tcx, Cow<'tcx, Allocation>> { + fn canonical_alloc_id(mem: &Memory<'mir, 'tcx, Self>, id: AllocId) -> AllocId { + let tcx = mem.tcx; + // Figure out if this is an extern static, and if yes, which one. + let def_id = match tcx.alloc_map.lock().get(id) { + Some(GlobalAlloc::Static(def_id)) if tcx.is_foreign_item(def_id) => def_id, + _ => { + // No need to canonicalize anything. + return id; + } + }; let attrs = tcx.get_attrs(def_id); let link_name = match attr::first_attr_value_str_by_name(&attrs, sym::link_name) { Some(name) => name.as_str(), None => tcx.item_name(def_id).as_str(), }; - - let alloc = match &*link_name { - "__cxa_thread_atexit_impl" => { - // This should be all-zero, pointer-sized. - let size = tcx.data_layout.pointer_size; - let data = vec![0; size.bytes() as usize]; - Allocation::from_bytes(&data, tcx.data_layout.pointer_align.abi) - } - _ => throw_unsup_format!("can't access foreign static: {}", link_name), - }; - Ok(Cow::Owned(alloc)) - } - - #[inline(always)] - fn before_terminator(_ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx> { - // We are not interested in detecting loops. - Ok(()) + // Check if we know this one. + if let Some(canonical_id) = mem.extra.extern_statics.get(&*link_name) { + trace!("canonical_alloc_id: {:?} ({}) -> {:?}", id, link_name, canonical_id); + *canonical_id + } else { + // Return original id; `Memory::get_static_alloc` will throw an error. + id + } } fn init_allocation_extra<'b>( diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index a51f8c457143a..9a511aaed577f 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -453,7 +453,7 @@ impl Stacks { // Thus we call `static_base_ptr` such that the global pointers get the same tag // as what we use here. // The base pointer is not unique, so the base permission is `SharedReadWrite`. - MemoryKind::Machine(MiriMemoryKind::Static) => + MemoryKind::Machine(MiriMemoryKind::Static) | MemoryKind::Machine(MiriMemoryKind::Machine) => (extra.borrow_mut().static_base_ptr(id), Permission::SharedReadWrite), // Everything else we handle entirely untagged for now. // FIXME: experiment with more precise tracking. From 90327335fc65c7cde6f917a898c35dcf1d019673 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 23 Feb 2020 22:35:13 +0100 Subject: [PATCH 1606/3747] canonicalize alloc ID for ptr-to-int cast --- src/intptrcast.rs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/intptrcast.rs b/src/intptrcast.rs index 059d8217fabb4..375ebf09967db 100644 --- a/src/intptrcast.rs +++ b/src/intptrcast.rs @@ -5,7 +5,7 @@ use std::collections::{hash_map::Entry, HashMap}; use rand::Rng; use rustc::ty::layout::HasDataLayout; -use rustc_mir::interpret::{AllocCheck, AllocId, InterpResult, Memory, Pointer, PointerArithmetic}; +use rustc_mir::interpret::{AllocCheck, AllocId, InterpResult, Memory, Machine, Pointer, PointerArithmetic}; use rustc_target::abi::Size; use crate::{Evaluator, Tag, STACK_ADDR}; @@ -80,12 +80,13 @@ impl<'mir, 'tcx> GlobalState { ) -> InterpResult<'tcx, u64> { let mut global_state = memory.extra.intptrcast.borrow_mut(); let global_state = &mut *global_state; + let id = Evaluator::canonical_alloc_id(memory, ptr.alloc_id); // There is nothing wrong with a raw pointer being cast to an integer only after // it became dangling. Hence `MaybeDead`. - let (size, align) = memory.get_size_and_align(ptr.alloc_id, AllocCheck::MaybeDead)?; + let (size, align) = memory.get_size_and_align(id, AllocCheck::MaybeDead)?; - let base_addr = match global_state.base_addr.entry(ptr.alloc_id) { + let base_addr = match global_state.base_addr.entry(id) { Entry::Occupied(entry) => *entry.get(), Entry::Vacant(entry) => { // This allocation does not have a base address yet, pick one. @@ -102,7 +103,7 @@ impl<'mir, 'tcx> GlobalState { trace!( "Assigning base address {:#x} to allocation {:?} (slack: {}, align: {})", base_addr, - ptr.alloc_id, + id, slack, align.bytes(), ); @@ -112,7 +113,7 @@ impl<'mir, 'tcx> GlobalState { global_state.next_base_addr = base_addr.checked_add(max(size.bytes(), 1)).unwrap(); // Given that `next_base_addr` increases in each allocation, pushing the // corresponding tuple keeps `int_to_ptr_map` sorted - global_state.int_to_ptr_map.push((base_addr, ptr.alloc_id)); + global_state.int_to_ptr_map.push((base_addr, id)); base_addr } From 21a5da99a4cc87a0053b677c68e4837a833f9941 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 2 Mar 2020 09:00:43 +0100 Subject: [PATCH 1607/3747] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index f28fce1af27c7..82d8da1d03011 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -d9051341a1c142542a3f7dab509266606c775382 +e86c9e6ef8be7ddec0360f20aae7d86c69c59a83 From 59bddba5f39ab0f61062d06d54aa12eaf18da364 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 2 Mar 2020 09:05:55 +0100 Subject: [PATCH 1608/3747] remove unused import --- src/machine.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/machine.rs b/src/machine.rs index e4e709f7e2877..331e75414a0ba 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -16,7 +16,6 @@ use rustc::ty::{ Ty, }; use rustc_ast::attr; -use rustc_hir::def_id::DefId; use rustc_span::{source_map::Span, symbol::sym}; use crate::*; From 88c45f9891ede9d5b6643783f51f722fcf817d08 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 18 Feb 2020 09:32:02 +0100 Subject: [PATCH 1609/3747] adjust for rustc changes --- rust-version | 2 +- src/helpers.rs | 9 +++------ tests/compile-fail/validity/cast_fn_ptr1.rs | 2 +- tests/compile-fail/validity/cast_fn_ptr2.rs | 2 +- tests/compile-fail/validity/fn_ptr_offset.rs | 2 +- tests/compile-fail/validity/invalid_bool.rs | 2 +- tests/compile-fail/validity/invalid_char.rs | 2 +- 7 files changed, 9 insertions(+), 12 deletions(-) diff --git a/rust-version b/rust-version index 82d8da1d03011..0b22c04d3050f 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -e86c9e6ef8be7ddec0360f20aae7d86c69c59a83 +c839a7b4c26e58319b0c40448dd423facff34cd0 diff --git a/src/helpers.rs b/src/helpers.rs index 19db6852c56a7..5ff0a5671cdb5 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -300,18 +300,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // We have to do *something* for unions. - fn visit_union(&mut self, v: MPlaceTy<'tcx, Tag>) -> InterpResult<'tcx> { + fn visit_union(&mut self, v: MPlaceTy<'tcx, Tag>, fields: usize) -> InterpResult<'tcx> { + assert!(fields > 0); // we should never reach "pseudo-unions" with 0 fields, like primitives + // With unions, we fall back to whatever the type says, to hopefully be consistent // with LLVM IR. // FIXME: are we consistent, and is this really the behavior we want? let frozen = self.ecx.type_is_freeze(v.layout.ty); if frozen { Ok(()) } else { (self.unsafe_cell_action)(v) } } - - // We should never get to a primitive, but always short-circuit somewhere above. - fn visit_primitive(&mut self, _v: MPlaceTy<'tcx, Tag>) -> InterpResult<'tcx> { - bug!("we should always short-circuit before coming to a primitive") - } } } diff --git a/tests/compile-fail/validity/cast_fn_ptr1.rs b/tests/compile-fail/validity/cast_fn_ptr1.rs index d1f6e33e45982..eb94ba256beb1 100644 --- a/tests/compile-fail/validity/cast_fn_ptr1.rs +++ b/tests/compile-fail/validity/cast_fn_ptr1.rs @@ -7,5 +7,5 @@ fn main() { let g: fn(*const i32) = unsafe { std::mem::transmute(f as fn(&i32)) }; g(0usize as *const i32) - //~^ ERROR encountered 0, but expected something greater or equal to 1 + //~^ ERROR encountered a NULL reference } diff --git a/tests/compile-fail/validity/cast_fn_ptr2.rs b/tests/compile-fail/validity/cast_fn_ptr2.rs index 809f118c1df15..a3faa84f1de0c 100644 --- a/tests/compile-fail/validity/cast_fn_ptr2.rs +++ b/tests/compile-fail/validity/cast_fn_ptr2.rs @@ -7,5 +7,5 @@ fn main() { let g: fn() -> &'static i32 = unsafe { std::mem::transmute(f as fn() -> *const i32) }; let _x = g(); - //~^ ERROR encountered 0, but expected something greater or equal to 1 + //~^ ERROR encountered a NULL reference } diff --git a/tests/compile-fail/validity/fn_ptr_offset.rs b/tests/compile-fail/validity/fn_ptr_offset.rs index 4989f4d3af7bd..5eec58b5e2347 100644 --- a/tests/compile-fail/validity/fn_ptr_offset.rs +++ b/tests/compile-fail/validity/fn_ptr_offset.rs @@ -6,5 +6,5 @@ fn main() { let x : fn() = f; let y : *mut u8 = unsafe { mem::transmute(x) }; let y = y.wrapping_offset(1); - let _x : fn() = unsafe { mem::transmute(y) }; //~ ERROR encountered a potentially NULL pointer + let _x : fn() = unsafe { mem::transmute(y) }; //~ ERROR encountered a pointer, but expected a function pointer } diff --git a/tests/compile-fail/validity/invalid_bool.rs b/tests/compile-fail/validity/invalid_bool.rs index ce464616195df..35f4d4228e70c 100644 --- a/tests/compile-fail/validity/invalid_bool.rs +++ b/tests/compile-fail/validity/invalid_bool.rs @@ -1,3 +1,3 @@ fn main() { - let _b = unsafe { std::mem::transmute::(2) }; //~ ERROR encountered 2, but expected something less or equal to 1 + let _b = unsafe { std::mem::transmute::(2) }; //~ ERROR encountered 2, but expected a boolean } diff --git a/tests/compile-fail/validity/invalid_char.rs b/tests/compile-fail/validity/invalid_char.rs index a3f9070363491..42922cdc917c8 100644 --- a/tests/compile-fail/validity/invalid_char.rs +++ b/tests/compile-fail/validity/invalid_char.rs @@ -1,6 +1,6 @@ fn main() { assert!(std::char::from_u32(-1_i32 as u32).is_none()); - let _val = match unsafe { std::mem::transmute::(-1) } { //~ ERROR encountered 4294967295, but expected something less or equal to 1114111 + let _val = match unsafe { std::mem::transmute::(-1) } { //~ ERROR encountered 4294967295, but expected a valid unicode codepoint 'a' => {true}, 'b' => {false}, _ => {true}, From 5960e8b80e96da62bf13ea72ed63dae23f8dfe96 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Mon, 2 Mar 2020 14:17:14 -0500 Subject: [PATCH 1610/3747] Rename XARGO env var to XARGO_CHECK This reflects the fact that we want bootstrap to override `xargo-check`, not `xargo --- src/bin/cargo-miri.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index f8a408561b0b1..1a99e5786ff74 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -101,7 +101,7 @@ fn cargo() -> Command { } fn xargo() -> Command { - if let Ok(val) = std::env::var("XARGO") { + if let Ok(val) = std::env::var("XARGO_CHECK") { // Bootstrap tells us where to find xargo Command::new(val) } else { @@ -280,7 +280,7 @@ fn setup(ask_user: bool) { // First, we need xargo. if xargo_version().map_or(true, |v| v < XARGO_MIN_VERSION) { - if std::env::var("XARGO").is_ok() { + if std::env::var("XARGO_CHECK").is_ok() { // The user manually gave us a xargo binary; don't do anything automatically. show_error(format!("Your xargo is too old; please upgrade to the latest version")) } From 68f70195fa562280f9e23b39bc19e05fe4239856 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 2 Mar 2020 22:10:48 +0100 Subject: [PATCH 1611/3747] rename xargo -> xargo_check --- src/bin/cargo-miri.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 1a99e5786ff74..8f26aaf4e91af 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -100,7 +100,7 @@ fn cargo() -> Command { } } -fn xargo() -> Command { +fn xargo_check() -> Command { if let Ok(val) = std::env::var("XARGO_CHECK") { // Bootstrap tells us where to find xargo Command::new(val) @@ -202,7 +202,7 @@ fn test_sysroot_consistency() { } fn xargo_version() -> Option<(u32, u32, u32)> { - let out = xargo().arg("--version").output().ok()?; + let out = xargo_check().arg("--version").output().ok()?; if !out.status.success() { return None; } @@ -376,7 +376,7 @@ path = "lib.rs" // Prepare xargo invocation. let target = get_arg_flag_value("--target"); let print_sysroot = !ask_user && has_arg_flag("--print-sysroot"); // whether we just print the sysroot path - let mut command = xargo(); + let mut command = xargo_check(); command.arg("build").arg("-q"); command.current_dir(&dir); command.env("RUSTFLAGS", miri::miri_default_args().join(" ")); From 0e021ad76cfb2fb4507e3713522707e109ee6ddd Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 2 Mar 2020 22:30:20 +0100 Subject: [PATCH 1612/3747] switch extern_statics map to symbols --- src/machine.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/machine.rs b/src/machine.rs index 331e75414a0ba..c8705eb29e8cf 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -16,7 +16,7 @@ use rustc::ty::{ Ty, }; use rustc_ast::attr; -use rustc_span::{source_map::Span, symbol::sym}; +use rustc_span::{source_map::Span, symbol::{sym, Symbol}}; use crate::*; @@ -75,7 +75,7 @@ pub struct MemoryExtra { pub intptrcast: intptrcast::MemoryExtra, /// Mapping extern static names to their canonical allocation. - pub(crate) extern_statics: HashMap<&'static str, AllocId>, + pub(crate) extern_statics: HashMap, /// The random number generator used for resolving non-determinism. /// Needs to be queried by ptr_to_int, hence needs interior mutability. @@ -111,7 +111,7 @@ impl MemoryExtra { this.memory .extra .extern_statics - .insert("__cxa_thread_atexit_impl", place.ptr.assert_ptr().alloc_id) + .insert(Symbol::intern("__cxa_thread_atexit_impl"), place.ptr.assert_ptr().alloc_id) .unwrap_none(); } _ => {} // No "extern statics" supported on this platform @@ -310,11 +310,11 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { }; let attrs = tcx.get_attrs(def_id); let link_name = match attr::first_attr_value_str_by_name(&attrs, sym::link_name) { - Some(name) => name.as_str(), - None => tcx.item_name(def_id).as_str(), + Some(name) => name, + None => tcx.item_name(def_id), }; // Check if we know this one. - if let Some(canonical_id) = mem.extra.extern_statics.get(&*link_name) { + if let Some(canonical_id) = mem.extra.extern_statics.get(&link_name) { trace!("canonical_alloc_id: {:?} ({}) -> {:?}", id, link_name, canonical_id); *canonical_id } else { From 92a28f8d8f139d0b6b0f8efa009fee0e72103d1e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 2 Mar 2020 22:36:15 +0100 Subject: [PATCH 1613/3747] HashMap -> FxHashMap --- src/intptrcast.rs | 7 ++++--- src/machine.rs | 6 +++--- src/mono_hash_map.rs | 8 ++++---- src/shims/env.rs | 4 ++-- src/shims/fs.rs | 10 +++++----- src/stacked_borrows.rs | 10 +++++----- 6 files changed, 23 insertions(+), 22 deletions(-) diff --git a/src/intptrcast.rs b/src/intptrcast.rs index 375ebf09967db..91d9f4e84ee31 100644 --- a/src/intptrcast.rs +++ b/src/intptrcast.rs @@ -1,9 +1,10 @@ use std::cell::RefCell; use std::cmp::max; -use std::collections::{hash_map::Entry, HashMap}; +use std::collections::hash_map::Entry; use rand::Rng; +use rustc_data_structures::fx::FxHashMap; use rustc::ty::layout::HasDataLayout; use rustc_mir::interpret::{AllocCheck, AllocId, InterpResult, Memory, Machine, Pointer, PointerArithmetic}; use rustc_target::abi::Size; @@ -21,7 +22,7 @@ pub struct GlobalState { /// `AllocExtra` because function pointers also have a base address, and /// they do not have an `AllocExtra`. /// This is the inverse of `int_to_ptr_map`. - pub base_addr: HashMap, + pub base_addr: FxHashMap, /// This is used as a memory address when a new pointer is casted to an integer. It /// is always larger than any address that was previously made part of a block. pub next_base_addr: u64, @@ -31,7 +32,7 @@ impl Default for GlobalState { fn default() -> Self { GlobalState { int_to_ptr_map: Vec::default(), - base_addr: HashMap::default(), + base_addr: FxHashMap::default(), next_base_addr: STACK_ADDR, } } diff --git a/src/machine.rs b/src/machine.rs index c8705eb29e8cf..0df567a2fa511 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -3,12 +3,12 @@ use std::borrow::Cow; use std::cell::RefCell; -use std::collections::HashMap; use std::num::NonZeroU64; use std::rc::Rc; use rand::rngs::StdRng; +use rustc_data_structures::fx::FxHashMap; use rustc::mir; use rustc::ty::{ self, @@ -75,7 +75,7 @@ pub struct MemoryExtra { pub intptrcast: intptrcast::MemoryExtra, /// Mapping extern static names to their canonical allocation. - pub(crate) extern_statics: HashMap, + pub(crate) extern_statics: FxHashMap, /// The random number generator used for resolving non-determinism. /// Needs to be queried by ptr_to_int, hence needs interior mutability. @@ -92,7 +92,7 @@ impl MemoryExtra { MemoryExtra { stacked_borrows, intptrcast: Default::default(), - extern_statics: HashMap::default(), + extern_statics: FxHashMap::default(), rng: RefCell::new(rng), } } diff --git a/src/mono_hash_map.rs b/src/mono_hash_map.rs index 124ae68760260..fc33126aa2e71 100644 --- a/src/mono_hash_map.rs +++ b/src/mono_hash_map.rs @@ -1,6 +1,6 @@ -//! This is a "monotonic `HashMap`": A `HashMap` that, when shared, can be pushed to but not +//! This is a "monotonic `FxHashMap`": A `FxHashMap` that, when shared, can be pushed to but not //! otherwise mutated. We also box items in the map. This means we can safely provide -//! shared references into existing items in the `HashMap`, because they will not be dropped +//! shared references into existing items in the `FxHashMap`, because they will not be dropped //! (from being removed) or moved (because they are boxed). //! The API is is completely tailored to what `memory.rs` needs. It is still in //! a separate file to minimize the amount of code that has to care about the unsafety. @@ -21,8 +21,8 @@ impl MonoHashMap { /// This function exists for priroda to be able to iterate over all evaluator memory. /// /// The function is somewhat roundabout with the closure argument because internally the - /// `MonoHashMap` uses a `RefCell`. When iterating over the `HashMap` inside the `RefCell`, - /// we need to keep a borrow to the `HashMap` inside the iterator. The borrow is only alive + /// `MonoHashMap` uses a `RefCell`. When iterating over the `FxHashMap` inside the `RefCell`, + /// we need to keep a borrow to the `FxHashMap` inside the iterator. The borrow is only alive /// as long as the `Ref` returned by `RefCell::borrow()` is alive. So we can't return the /// iterator, as that would drop the `Ref`. We can't return both, as it's not possible in Rust /// to have a struct/tuple with a field that refers to another field. diff --git a/src/shims/env.rs b/src/shims/env.rs index 10f749216541e..79f0c5b3d902a 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -1,10 +1,10 @@ -use std::collections::HashMap; use std::ffi::{OsString, OsStr}; use std::env; use crate::stacked_borrows::Tag; use crate::*; +use rustc_data_structures::fx::FxHashMap; use rustc::ty::layout::Size; use rustc_mir::interpret::Pointer; @@ -12,7 +12,7 @@ use rustc_mir::interpret::Pointer; pub struct EnvVars { /// Stores pointers to the environment variables. These variables must be stored as /// null-terminated C strings with the `"{name}={value}"` format. - map: HashMap>, + map: FxHashMap>, } impl EnvVars { diff --git a/src/shims/fs.rs b/src/shims/fs.rs index cc8f18af7d618..8a48518fa9bca 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -1,11 +1,11 @@ use std::collections::BTreeMap; -use std::collections::HashMap; use std::convert::{TryFrom, TryInto}; use std::fs::{read_dir, remove_dir, remove_file, rename, DirBuilder, File, FileType, OpenOptions, ReadDir}; use std::io::{Read, Seek, SeekFrom, Write}; use std::path::PathBuf; use std::time::SystemTime; +use rustc_data_structures::fx::FxHashMap; use rustc::ty::layout::{Align, LayoutOf, Size}; use crate::stacked_borrows::Tag; @@ -212,10 +212,10 @@ pub struct DirHandler { /// When opendir is called, a directory iterator is created on the host for the target /// directory, and an entry is stored in this hash map, indexed by an ID which represents /// the directory stream. When readdir is called, the directory stream ID is used to look up - /// the corresponding ReadDir iterator from this HashMap, and information from the next + /// the corresponding ReadDir iterator from this map, and information from the next /// directory entry is returned. When closedir is called, the ReadDir iterator is removed from - /// this HashMap. - streams: HashMap, + /// the map. + streams: FxHashMap, /// ID number to be used by the next call to opendir next_id: u64, } @@ -232,7 +232,7 @@ impl DirHandler { impl Default for DirHandler { fn default() -> DirHandler { DirHandler { - streams: HashMap::new(), + streams: FxHashMap::default(), // Skip 0 as an ID, because it looks like a null pointer to libc next_id: 1, } diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 9a511aaed577f..6188d05780cb5 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -2,11 +2,11 @@ //! for further information. use std::cell::RefCell; -use std::collections::{HashMap, HashSet}; use std::fmt; use std::num::NonZeroU64; use std::rc::Rc; +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc::mir::RetagKind; use rustc::ty::{self, layout::Size}; use rustc_hir::Mutability; @@ -96,11 +96,11 @@ pub struct GlobalState { /// Table storing the "base" tag for each allocation. /// The base tag is the one used for the initial pointer. /// We need this in a separate table to handle cyclic statics. - base_ptr_ids: HashMap, + base_ptr_ids: FxHashMap, /// Next unused call ID (for protectors). next_call_id: CallId, /// Those call IDs corresponding to functions that are still running. - active_calls: HashSet, + active_calls: FxHashSet, /// The id to trace in this execution run tracked_pointer_tag: Option, } @@ -153,9 +153,9 @@ impl GlobalState { pub fn new(tracked_pointer_tag: Option) -> Self { GlobalState { next_ptr_id: NonZeroU64::new(1).unwrap(), - base_ptr_ids: HashMap::default(), + base_ptr_ids: FxHashMap::default(), next_call_id: NonZeroU64::new(1).unwrap(), - active_calls: HashSet::default(), + active_calls: FxHashSet::default(), tracked_pointer_tag, } } From 58519a7a7930d4ac494d971a737525221c70f26a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 3 Mar 2020 15:00:19 +0100 Subject: [PATCH 1614/3747] try even harder to catch invalid generator fields --- tests/run-pass/generator.rs | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/tests/run-pass/generator.rs b/tests/run-pass/generator.rs index e85d2cf8f29a8..18eaf5e55c15d 100644 --- a/tests/run-pass/generator.rs +++ b/tests/run-pass/generator.rs @@ -4,6 +4,8 @@ use std::ops::{GeneratorState::{self, *}, Generator}; use std::pin::Pin; use std::sync::atomic::{AtomicUsize, Ordering}; use std::fmt::Debug; +use std::mem::ManuallyDrop; +use std::ptr; fn basic() { fn finish(mut amt: usize, mut t: T) -> T::Return @@ -12,8 +14,13 @@ fn basic() { // We are not moving the `t` around until it gets dropped, so this is okay. let mut t = unsafe { Pin::new_unchecked(&mut t) }; loop { - match t.as_mut().resume(()) { - GeneratorState::Yielded(y) => amt -= y, + let state = t.as_mut().resume(()); + // Test if the generator is valid (according to type invariants). + let _ = unsafe { ManuallyDrop::new(ptr::read(t.as_mut().get_unchecked_mut())) }; + match state { + GeneratorState::Yielded(y) => { + amt -= y; + } GeneratorState::Complete(ret) => { assert_eq!(amt, 0); return ret @@ -109,6 +116,8 @@ fn smoke_resume_arg() { for (input, out) in inout { assert_eq!(gen.as_mut().resume(input), out); + // Test if the generator is valid (according to type invariants). + let _ = unsafe { ManuallyDrop::new(ptr::read(gen.as_mut().get_unchecked_mut())) }; } } From ad1f0f6e65bbcdec4bba9a130105f86b56782ef7 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 4 Mar 2020 08:54:12 +0100 Subject: [PATCH 1615/3747] bump Rust --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 0b22c04d3050f..838ec0e9a7dfc 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -c839a7b4c26e58319b0c40448dd423facff34cd0 +4d71c164a89b705df6affd31a5262c832d1bc48d From db0d03229c54e3dead1cd8afde62e1ba9b1707bc Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 4 Mar 2020 09:50:26 +0100 Subject: [PATCH 1616/3747] fix allocator tests --- tests/compile-fail/deallocate-bad-alignment.rs | 2 +- tests/compile-fail/deallocate-bad-size.rs | 2 +- tests/compile-fail/deallocate-twice.rs | 2 +- tests/compile-fail/reallocate-bad-size.rs | 2 +- tests/compile-fail/reallocate-change-alloc.rs | 2 +- tests/compile-fail/reallocate-dangling.rs | 2 +- tests/run-pass/heap_allocator.rs | 14 +++++++------- 7 files changed, 13 insertions(+), 13 deletions(-) diff --git a/tests/compile-fail/deallocate-bad-alignment.rs b/tests/compile-fail/deallocate-bad-alignment.rs index 2ac35a450cf19..876339919717a 100644 --- a/tests/compile-fail/deallocate-bad-alignment.rs +++ b/tests/compile-fail/deallocate-bad-alignment.rs @@ -9,7 +9,7 @@ use std::alloc::{AllocRef, Layout}; fn main() { unsafe { - let x = Global.alloc(Layout::from_size_align_unchecked(1, 1)).unwrap(); + let x = Global.alloc(Layout::from_size_align_unchecked(1, 1)).unwrap().0; Global.dealloc(x, Layout::from_size_align_unchecked(1, 2)); } } diff --git a/tests/compile-fail/deallocate-bad-size.rs b/tests/compile-fail/deallocate-bad-size.rs index c5b48f5ddf590..3b7b3cc6a7262 100644 --- a/tests/compile-fail/deallocate-bad-size.rs +++ b/tests/compile-fail/deallocate-bad-size.rs @@ -9,7 +9,7 @@ use std::alloc::{AllocRef, Layout}; fn main() { unsafe { - let x = Global.alloc(Layout::from_size_align_unchecked(1, 1)).unwrap(); + let x = Global.alloc(Layout::from_size_align_unchecked(1, 1)).unwrap().0; Global.dealloc(x, Layout::from_size_align_unchecked(2, 1)); } } diff --git a/tests/compile-fail/deallocate-twice.rs b/tests/compile-fail/deallocate-twice.rs index 02c442f0ab85f..ee4c5dbedf90d 100644 --- a/tests/compile-fail/deallocate-twice.rs +++ b/tests/compile-fail/deallocate-twice.rs @@ -9,7 +9,7 @@ use std::alloc::{AllocRef, Layout}; fn main() { unsafe { - let x = Global.alloc(Layout::from_size_align_unchecked(1, 1)).unwrap(); + let x = Global.alloc(Layout::from_size_align_unchecked(1, 1)).unwrap().0; Global.dealloc(x, Layout::from_size_align_unchecked(1, 1)); Global.dealloc(x, Layout::from_size_align_unchecked(1, 1)); } diff --git a/tests/compile-fail/reallocate-bad-size.rs b/tests/compile-fail/reallocate-bad-size.rs index 905e8e0617212..f7117dbb646d3 100644 --- a/tests/compile-fail/reallocate-bad-size.rs +++ b/tests/compile-fail/reallocate-bad-size.rs @@ -9,7 +9,7 @@ use std::alloc::{AllocRef, Layout}; fn main() { unsafe { - let x = Global.alloc(Layout::from_size_align_unchecked(1, 1)).unwrap(); + let x = Global.alloc(Layout::from_size_align_unchecked(1, 1)).unwrap().0; Global.realloc(x, Layout::from_size_align_unchecked(2, 1), 1).unwrap(); } } diff --git a/tests/compile-fail/reallocate-change-alloc.rs b/tests/compile-fail/reallocate-change-alloc.rs index 21468739b31c0..df517f9c81f2f 100644 --- a/tests/compile-fail/reallocate-change-alloc.rs +++ b/tests/compile-fail/reallocate-change-alloc.rs @@ -7,7 +7,7 @@ use std::alloc::{AllocRef, Layout}; fn main() { unsafe { - let x = Global.alloc(Layout::from_size_align_unchecked(1, 1)).unwrap(); + let x = Global.alloc(Layout::from_size_align_unchecked(1, 1)).unwrap().0; Global.realloc(x, Layout::from_size_align_unchecked(1, 1), 1).unwrap(); let _z = *(x.as_ptr() as *mut u8); //~ ERROR dangling pointer was dereferenced } diff --git a/tests/compile-fail/reallocate-dangling.rs b/tests/compile-fail/reallocate-dangling.rs index ee73cfce8634b..19a9017e71b87 100644 --- a/tests/compile-fail/reallocate-dangling.rs +++ b/tests/compile-fail/reallocate-dangling.rs @@ -9,7 +9,7 @@ use std::alloc::{AllocRef, Layout}; fn main() { unsafe { - let x = Global.alloc(Layout::from_size_align_unchecked(1, 1)).unwrap(); + let x = Global.alloc(Layout::from_size_align_unchecked(1, 1)).unwrap().0; Global.dealloc(x, Layout::from_size_align_unchecked(1, 1)); Global.realloc(x, Layout::from_size_align_unchecked(1, 1), 1).unwrap(); } diff --git a/tests/run-pass/heap_allocator.rs b/tests/run-pass/heap_allocator.rs index 907fbf962df02..8077be405f4b2 100644 --- a/tests/run-pass/heap_allocator.rs +++ b/tests/run-pass/heap_allocator.rs @@ -9,28 +9,28 @@ fn check_alloc(mut allocator: T) { unsafe { let layout = Layout::from_size_align(20, align).unwrap(); for _ in 0..32 { - let a = allocator.alloc(layout).unwrap(); + let a = allocator.alloc(layout).unwrap().0; assert_eq!(a.as_ptr() as usize % align, 0, "pointer is incorrectly aligned"); allocator.dealloc(a, layout); } - let p1 = allocator.alloc_zeroed(layout).unwrap(); + let p1 = allocator.alloc_zeroed(layout).unwrap().0; assert_eq!(p1.as_ptr() as usize % align, 0, "pointer is incorrectly aligned"); - let p2 = allocator.realloc(p1, layout, 40).unwrap(); + let p2 = allocator.realloc(p1, layout, 40).unwrap().0; let layout = Layout::from_size_align(40, align).unwrap(); assert_eq!(p2.as_ptr() as usize % align, 0, "pointer is incorrectly aligned"); let slice = slice::from_raw_parts(p2.as_ptr(), 20); assert_eq!(&slice, &[0_u8; 20]); // old size == new size - let p3 = allocator.realloc(p2, layout, 40).unwrap(); + let p3 = allocator.realloc(p2, layout, 40).unwrap().0; assert_eq!(p3.as_ptr() as usize % align, 0, "pointer is incorrectly aligned"); let slice = slice::from_raw_parts(p3.as_ptr(), 20); assert_eq!(&slice, &[0_u8; 20]); // old size > new size - let p4 = allocator.realloc(p3, layout, 10).unwrap(); + let p4 = allocator.realloc(p3, layout, 10).unwrap().0; let layout = Layout::from_size_align(10, align).unwrap(); assert_eq!(p4.as_ptr() as usize % align, 0, "pointer is incorrectly aligned"); let slice = slice::from_raw_parts(p4.as_ptr(), 10); @@ -46,7 +46,7 @@ fn check_align_requests(mut allocator: T) { let iterations = 32; unsafe { let pointers: Vec<_> = (0..iterations).map(|_| { - allocator.alloc(Layout::from_size_align(size, align).unwrap()).unwrap() + allocator.alloc(Layout::from_size_align(size, align).unwrap()).unwrap().0 }).collect(); for &ptr in &pointers { assert_eq!((ptr.as_ptr() as usize) % align, 0, @@ -67,7 +67,7 @@ fn global_to_box() { let l = Layout::new::(); // allocate manually with global allocator, then turn into Box and free there unsafe { - let ptr = Global.alloc(l).unwrap().as_ptr() as *mut T; + let ptr = Global.alloc(l).unwrap().0.as_ptr() as *mut T; let b = Box::from_raw(ptr); drop(b); } From 5c4dc072bd6f36b6929673582a423c1be7ba485c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 4 Mar 2020 10:29:00 +0100 Subject: [PATCH 1617/3747] downgrade serde_json to match rustc workspace --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 896c726b9aa65..f71fec3c2846c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -33,7 +33,7 @@ required-features = ["rustc_tests"] cargo_metadata = { version = "0.9.0", optional = true } directories = { version = "2.0", optional = true } rustc_version = { version = "0.2.3", optional = true } -serde_json = { version = "1.0.44", optional = true } +serde_json = { version = "1.0.40", optional = true } getrandom = { version = "0.1.8", features = ["std"] } byteorder = "1.3" From 148269dd4b64c21c8dfa66d5d67a48443b1aea94 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 4 Mar 2020 13:01:06 +0100 Subject: [PATCH 1618/3747] finally stop using min/max_value and the integer modules --- rust-version | 2 +- src/shims/foreign_items.rs | 8 ++++---- src/shims/fs.rs | 8 ++++---- src/shims/mod.rs | 2 +- tests/compile-fail/exact_div4.rs | 4 ++-- tests/compile-fail/ptr_offset_overflow.rs | 2 +- tests/compile-fail/slice-too-big.rs | 1 - tests/compile-fail/unchecked_div1.rs | 2 +- tests/run-pass/align_offset.rs | 6 +++--- tests/run-pass/integer-ops.rs | 11 ++++------- tests/run-pass/ints.rs | 8 ++++---- tests/run-pass/panic/overflowing-rsh-2.rs | 2 +- tests/run-pass/pointers.rs | 2 -- tests/run-pass/ptr_arith_offset_overflow.rs | 4 ++-- tests/run-pass/ptr_int_casts.rs | 2 +- tests/run-pass/u128.rs | 4 ++-- 16 files changed, 31 insertions(+), 37 deletions(-) diff --git a/rust-version b/rust-version index 838ec0e9a7dfc..62e7b6845d518 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -4d71c164a89b705df6affd31a5262c832d1bc48d +7a3700c37132385e8e965c18e73d0a09f9146335 diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index f8b42e5091339..88ebc269cf1bd 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -443,10 +443,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Saturating cast to i16. Even those are outside the valid exponent range to // `scalbn` below will do its over/underflow handling. - let exp = if exp > i16::max_value() as i32 { - i16::max_value() - } else if exp < i16::min_value() as i32 { - i16::min_value() + let exp = if exp > i16::MAX as i32 { + i16::MAX + } else if exp < i16::MIN as i32 { + i16::MIN } else { exp.try_into().unwrap() }; diff --git a/src/shims/fs.rs b/src/shims/fs.rs index 8a48518fa9bca..0ea53b16fd191 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -427,15 +427,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // We cap the number of read bytes to the largest value that we are able to fit in both the // host's and target's `isize`. This saves us from having to handle overflows later. - let count = count.min(this.isize_max() as u64).min(isize::max_value() as u64); + let count = count.min(this.isize_max() as u64).min(isize::MAX as u64); if let Some(FileHandle { file, writable: _ }) = this.machine.file_handler.handles.get_mut(&fd) { // This can never fail because `count` was capped to be smaller than - // `isize::max_value()`. + // `isize::MAX`. let count = isize::try_from(count).unwrap(); // We want to read at most `count` bytes. We are sure that `count` is not negative // because it was a target's `usize`. Also we are sure that its smaller than - // `usize::max_value()` because it is a host's `isize`. + // `usize::MAX` because it is a host's `isize`. let mut bytes = vec![0; count as usize]; let result = file .read(&mut bytes) @@ -481,7 +481,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // We cap the number of written bytes to the largest value that we are able to fit in both the // host's and target's `isize`. This saves us from having to handle overflows later. - let count = count.min(this.isize_max() as u64).min(isize::max_value() as u64); + let count = count.min(this.isize_max() as u64).min(isize::MAX as u64); if let Some(FileHandle { file, writable: _ }) = this.machine.file_handler.handles.get_mut(&fd) { let bytes = this.memory.read_bytes(buf, Size::from_bytes(count))?; diff --git a/src/shims/mod.rs b/src/shims/mod.rs index 2889807bf76aa..04379553587da 100644 --- a/src/shims/mod.rs +++ b/src/shims/mod.rs @@ -27,7 +27,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let (dest, ret) = ret.unwrap(); let n = this .align_offset(args[0], args[1])? - .unwrap_or_else(|| this.truncate(u128::max_value(), dest.layout)); + .unwrap_or_else(|| this.truncate(u128::MAX, dest.layout)); this.write_scalar(Scalar::from_uint(n, dest.layout.size), dest)?; this.go_to_block(ret); return Ok(None); diff --git a/tests/compile-fail/exact_div4.rs b/tests/compile-fail/exact_div4.rs index 736d4f2516d2d..c241b2df660e4 100644 --- a/tests/compile-fail/exact_div4.rs +++ b/tests/compile-fail/exact_div4.rs @@ -1,5 +1,5 @@ #![feature(core_intrinsics)] fn main() { - // divison of min_value by -1 - unsafe { std::intrinsics::exact_div(i64::min_value(), -1); } //~ ERROR result of dividing MIN by -1 cannot be represented + // divison of MIN by -1 + unsafe { std::intrinsics::exact_div(i64::MIN, -1); } //~ ERROR result of dividing MIN by -1 cannot be represented } diff --git a/tests/compile-fail/ptr_offset_overflow.rs b/tests/compile-fail/ptr_offset_overflow.rs index e52384e919678..452bf341c9e20 100644 --- a/tests/compile-fail/ptr_offset_overflow.rs +++ b/tests/compile-fail/ptr_offset_overflow.rs @@ -2,5 +2,5 @@ fn main() { let v = [1i8, 2]; let x = &v[1] as *const i8; - let _val = unsafe { x.offset(isize::min_value()) }; + let _val = unsafe { x.offset(isize::MIN) }; } diff --git a/tests/compile-fail/slice-too-big.rs b/tests/compile-fail/slice-too-big.rs index 08ab48175aedb..157ea03bc932a 100644 --- a/tests/compile-fail/slice-too-big.rs +++ b/tests/compile-fail/slice-too-big.rs @@ -1,5 +1,4 @@ use std::mem; -use std::usize; fn main() { unsafe { let ptr = Box::into_raw(Box::new(0u8)); diff --git a/tests/compile-fail/unchecked_div1.rs b/tests/compile-fail/unchecked_div1.rs index 1d1bbb09aa267..b42b34ff462d4 100644 --- a/tests/compile-fail/unchecked_div1.rs +++ b/tests/compile-fail/unchecked_div1.rs @@ -1,5 +1,5 @@ #![feature(core_intrinsics)] fn main() { // MIN/-1 cannot be represented - unsafe { std::intrinsics::unchecked_div(i16::min_value(), -1); } //~ ERROR Overflow executing `unchecked_div` + unsafe { std::intrinsics::unchecked_div(i16::MIN, -1); } //~ ERROR Overflow executing `unchecked_div` } diff --git a/tests/run-pass/align_offset.rs b/tests/run-pass/align_offset.rs index 1202fd00be157..f921634647086 100644 --- a/tests/run-pass/align_offset.rs +++ b/tests/run-pass/align_offset.rs @@ -5,15 +5,15 @@ fn test_align_offset() { assert_eq!(raw.align_offset(2), 0); assert_eq!(raw.align_offset(4), 0); - assert_eq!(raw.align_offset(8), usize::max_value()); // requested alignment higher than allocation alignment + assert_eq!(raw.align_offset(8), usize::MAX); // requested alignment higher than allocation alignment assert_eq!(raw.wrapping_offset(1).align_offset(2), 1); assert_eq!(raw.wrapping_offset(1).align_offset(4), 3); - assert_eq!(raw.wrapping_offset(1).align_offset(8), usize::max_value()); // requested alignment higher than allocation alignment + assert_eq!(raw.wrapping_offset(1).align_offset(8), usize::MAX); // requested alignment higher than allocation alignment assert_eq!(raw.wrapping_offset(2).align_offset(2), 0); assert_eq!(raw.wrapping_offset(2).align_offset(4), 2); - assert_eq!(raw.wrapping_offset(2).align_offset(8), usize::max_value()); // requested alignment higher than allocation alignment + assert_eq!(raw.wrapping_offset(2).align_offset(8), usize::MAX); // requested alignment higher than allocation alignment } fn test_align_to() { diff --git a/tests/run-pass/integer-ops.rs b/tests/run-pass/integer-ops.rs index 0264099eb68dc..4ae42df592002 100644 --- a/tests/run-pass/integer-ops.rs +++ b/tests/run-pass/integer-ops.rs @@ -8,16 +8,13 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -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!(u32::MAX as i64, 4294967295); + assert_eq!(i32::MIN as i64, -2147483648); - assert_eq!(i8::max_value(), 127); + assert_eq!(i8::MAX, 127); + assert_eq!(i8::MIN, -128); assert_eq!(i32::from_str_radix("A", 16), Ok(10)); diff --git a/tests/run-pass/ints.rs b/tests/run-pass/ints.rs index 00ca2aa41dd35..5d7c383088dee 100644 --- a/tests/run-pass/ints.rs +++ b/tests/run-pass/ints.rs @@ -51,8 +51,8 @@ fn main() { assert_eq!(arith(), 5*5); assert_eq!(match_int(), 20); assert_eq!(match_int_range(), 4); - assert_eq!(i64::min_value().overflowing_mul(-1), (i64::min_value(), true)); - assert_eq!(i32::min_value().overflowing_mul(-1), (i32::min_value(), true)); - assert_eq!(i16::min_value().overflowing_mul(-1), (i16::min_value(), true)); - assert_eq!(i8::min_value().overflowing_mul(-1), (i8::min_value(), true)); + assert_eq!(i64::MIN.overflowing_mul(-1), (i64::MIN, true)); + assert_eq!(i32::MIN.overflowing_mul(-1), (i32::MIN, true)); + assert_eq!(i16::MIN.overflowing_mul(-1), (i16::MIN, true)); + assert_eq!(i8::MIN.overflowing_mul(-1), (i8::MIN, true)); } diff --git a/tests/run-pass/panic/overflowing-rsh-2.rs b/tests/run-pass/panic/overflowing-rsh-2.rs index da77a46a805e6..27cc65fa7685b 100644 --- a/tests/run-pass/panic/overflowing-rsh-2.rs +++ b/tests/run-pass/panic/overflowing-rsh-2.rs @@ -3,5 +3,5 @@ fn main() { // Make sure we catch overflows that would be hidden by first casting the RHS to u32 - let _n = 1i64 >> (u32::max_value() as i64 + 1); + let _n = 1i64 >> (u32::MAX as i64 + 1); } diff --git a/tests/run-pass/pointers.rs b/tests/run-pass/pointers.rs index e0847de97ba9c..5bf60c32541db 100644 --- a/tests/run-pass/pointers.rs +++ b/tests/run-pass/pointers.rs @@ -1,5 +1,3 @@ -use std::usize; - fn one_line_ref() -> i16 { *&1 } diff --git a/tests/run-pass/ptr_arith_offset_overflow.rs b/tests/run-pass/ptr_arith_offset_overflow.rs index 56fd448b0cc22..fdd980e2177b5 100644 --- a/tests/run-pass/ptr_arith_offset_overflow.rs +++ b/tests/run-pass/ptr_arith_offset_overflow.rs @@ -5,8 +5,8 @@ fn main() { let x = &mut ptr::null(); // going through memory as there are more sanity checks along that path *x = v.as_ptr().wrapping_offset(1); // ptr to the 2nd element // Adding 2*isize::max and then 1 is like substracting 1 - *x = x.wrapping_offset(isize::max_value()); - *x = x.wrapping_offset(isize::max_value()); + *x = x.wrapping_offset(isize::MAX); + *x = x.wrapping_offset(isize::MAX); *x = x.wrapping_offset(1); assert_eq!(unsafe { **x }, 1); } diff --git a/tests/run-pass/ptr_int_casts.rs b/tests/run-pass/ptr_int_casts.rs index c279024f35eab..468b37af5beaa 100644 --- a/tests/run-pass/ptr_int_casts.rs +++ b/tests/run-pass/ptr_int_casts.rs @@ -16,7 +16,7 @@ fn main() { // this used to trigger an ICE on 32bit) let val = &mut ptr::null(); *val = (1 as *const u8).wrapping_offset(-4); - assert_eq!(*val as usize, usize::max_value() - 2); + assert_eq!(*val as usize, usize::MAX - 2); { // ptr-int-ptr let x = 13; diff --git a/tests/run-pass/u128.rs b/tests/run-pass/u128.rs index 5a5d7c1f94421..a2ca7746b1c05 100644 --- a/tests/run-pass/u128.rs +++ b/tests/run-pass/u128.rs @@ -48,14 +48,14 @@ fn main() { assert_eq!("10000000000000000000000000000000000000000000000000000000000000000000", format!("{:b}", j)); assert_eq!("340282366920938463463374607431768211455", - format!("{}", u128::max_value())); + format!("{}", u128::MAX)); assert_eq!("147573952589676412928", format!("{:?}", j)); // common traits assert_eq!(x, b(x.clone())); // overflow checks assert_eq!((z).checked_mul(z), Some(0x734C_C2F2_A521)); assert_eq!((k).checked_mul(k), None); - let l: u128 = b(u128::max_value() - 10); + let l: u128 = b(u128::MAX - 10); let o: u128 = b(17); assert_eq!(l.checked_add(b(11)), None); assert_eq!(l.checked_sub(l), Some(0)); From d82d7013600a9f0ce6ffb74aed0a0701bdeccd79 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 6 Mar 2020 09:06:23 +0100 Subject: [PATCH 1619/3747] add option to track a particular AllocId (does nothing yet) --- benches/helpers/miri_helper.rs | 11 +---------- src/bin/miri-rustc-tests.rs | 22 ++-------------------- src/bin/miri.rs | 13 +++++++++++++ src/eval.rs | 19 +++++++++++++++++++ src/machine.rs | 9 +++++++-- 5 files changed, 42 insertions(+), 32 deletions(-) diff --git a/benches/helpers/miri_helper.rs b/benches/helpers/miri_helper.rs index 2483f2de3a864..b478a7d23eb98 100644 --- a/benches/helpers/miri_helper.rs +++ b/benches/helpers/miri_helper.rs @@ -29,16 +29,7 @@ impl rustc_driver::Callbacks for MiriCompilerCalls<'_> { tcx.entry_fn(LOCAL_CRATE).expect("no main or start function found"); self.bencher.iter(|| { - let config = miri::MiriConfig { - validate: true, - stacked_borrows: true, - communicate: false, - ignore_leaks: false, - excluded_env_vars: vec![], - args: vec![], - seed: None, - tracked_pointer_tag: None, - }; + let config = miri::MiriConfig::default(); eval_main(tcx, entry_def_id, config); }); }); diff --git a/src/bin/miri-rustc-tests.rs b/src/bin/miri-rustc-tests.rs index 9cc9901a9134a..509a1592152d0 100644 --- a/src/bin/miri-rustc-tests.rs +++ b/src/bin/miri-rustc-tests.rs @@ -46,16 +46,7 @@ impl rustc_driver::Callbacks for MiriCompilerCalls { .iter() .any(|attr| attr.check_name(rustc_span::symbol::sym::test)) { - let config = MiriConfig { - validate: true, - stacked_borrows: true, - communicate: false, - ignore_leaks: false, - excluded_env_vars: vec![], - args: vec![], - seed: None, - tracked_pointer_tag: None, - }; + let config = MiriConfig::default(); let did = self.0.hir().body_owner_def_id(body_id); println!("running test: {}", self.0.def_path_debug_str(did)); miri::eval_main(self.0, did, config); @@ -68,16 +59,7 @@ impl rustc_driver::Callbacks for MiriCompilerCalls { } tcx.hir().krate().visit_all_item_likes(&mut Visitor(tcx)); } else if let Some((entry_def_id, _)) = tcx.entry_fn(LOCAL_CRATE) { - let config = MiriConfig { - validate: true, - stacked_borrows: true, - communicate: false, - ignore_leaks: false, - excluded_env_vars: vec![], - args: vec![], - seed: None, - tracked_pointer_tag: None, - }; + let config = MiriConfig::default(); miri::eval_main(tcx, entry_def_id, config); compiler.session().abort_if_errors(); diff --git a/src/bin/miri.rs b/src/bin/miri.rs index e69e7f7b6f50f..d2709643237f1 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -135,6 +135,7 @@ fn main() { let mut ignore_leaks = false; let mut seed: Option = None; let mut tracked_pointer_tag: Option = None; + let mut tracked_alloc_id: Option = None; let mut rustc_args = vec![]; let mut miri_args = vec![]; let mut after_dashdash = false; @@ -206,6 +207,17 @@ fn main() { panic!("-Zmiri-track-pointer-tag must be a nonzero id"); } } + arg if arg.starts_with("-Zmiri-track-alloc-id=") => { + let id: u64 = match arg.trim_start_matches("-Zmiri-track-alloc-id=").parse() + { + Ok(id) => id, + Err(err) => panic!( + "-Zmiri-track-alloc-id requires a valid `u64` as the argument: {}", + err + ), + }; + tracked_alloc_id = Some(miri::AllocId(id)); + } _ => { rustc_args.push(arg); } @@ -240,6 +252,7 @@ fn main() { seed, args: miri_args, tracked_pointer_tag, + tracked_alloc_id, }; rustc_driver::install_ice_hook(); let result = rustc_driver::catch_fatal_errors(move || { diff --git a/src/eval.rs b/src/eval.rs index 267b79d0eba7e..1981a8d1e03e9 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -30,6 +30,24 @@ pub struct MiriConfig { pub seed: Option, /// The stacked borrow id to report about pub tracked_pointer_tag: Option, + /// The allocation id to report about. + pub tracked_alloc_id: Option, +} + +impl Default for MiriConfig { + fn default() -> MiriConfig { + MiriConfig { + validate: true, + stacked_borrows: true, + communicate: false, + ignore_leaks: false, + excluded_env_vars: vec![], + args: vec![], + seed: None, + tracked_pointer_tag: None, + tracked_alloc_id: None, + } + } } /// Details of premature program termination. @@ -55,6 +73,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( StdRng::seed_from_u64(config.seed.unwrap_or(0)), config.stacked_borrows, config.tracked_pointer_tag, + config.tracked_alloc_id, ), ); // Complete initialization. diff --git a/src/machine.rs b/src/machine.rs index 0df567a2fa511..07885148e1fd9 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -75,15 +75,19 @@ pub struct MemoryExtra { pub intptrcast: intptrcast::MemoryExtra, /// Mapping extern static names to their canonical allocation. - pub(crate) extern_statics: FxHashMap, + extern_statics: FxHashMap, /// The random number generator used for resolving non-determinism. /// Needs to be queried by ptr_to_int, hence needs interior mutability. pub(crate) rng: RefCell, + + /// An allocation ID to report when it is being allocated + /// (helps for debugging memory leaks). + tracked_alloc_id: Option, } impl MemoryExtra { - pub fn new(rng: StdRng, stacked_borrows: bool, tracked_pointer_tag: Option) -> Self { + pub fn new(rng: StdRng, stacked_borrows: bool, tracked_pointer_tag: Option, tracked_alloc_id: Option) -> Self { let stacked_borrows = if stacked_borrows { Some(Rc::new(RefCell::new(stacked_borrows::GlobalState::new(tracked_pointer_tag)))) } else { @@ -94,6 +98,7 @@ impl MemoryExtra { intptrcast: Default::default(), extern_statics: FxHashMap::default(), rng: RefCell::new(rng), + tracked_alloc_id, } } From ade4c4e7331fcff40643c1666ca89078b84b125a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 6 Mar 2020 09:11:41 +0100 Subject: [PATCH 1620/3747] make the new option actually do something --- README.md | 2 ++ src/diagnostics.rs | 6 +++++- src/machine.rs | 4 ++++ 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index f18a5d668c392..839facef0962f 100644 --- a/README.md +++ b/README.md @@ -180,6 +180,8 @@ Several `-Z` flags are relevant for Miri: is popped from a borrow stack (which is where the tag becomes invalid and any future use of it will error). This helps you in finding out why UB is happening and where in your code would be a good place to look for it. +* `-Zmiri-track-alloc-id=` shows a backtrace when the given allocation is + being allocated. This helps in debugging memory leaks. Moreover, Miri recognizes some environment variables: diff --git a/src/diagnostics.rs b/src/diagnostics.rs index e68dfad1b9fae..fb6598495af5e 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -6,6 +6,7 @@ use crate::*; /// Miri specific diagnostics pub enum NonHaltingDiagnostic { PoppedTrackedPointerTag(Item), + CreatedAlloc(AllocId), } /// Emit a custom diagnostic without going through the miri-engine machinery @@ -97,9 +98,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_ref(); DIAGNOSTICS.with(|diagnostics| { for e in diagnostics.borrow_mut().drain(..) { + use NonHaltingDiagnostic::*; let msg = match e { - NonHaltingDiagnostic::PoppedTrackedPointerTag(item) => + PoppedTrackedPointerTag(item) => format!("popped tracked tag for item {:?}", item), + CreatedAlloc(AllocId(id)) => + format!("created allocation with id {}", id), }; report_msg(this, msg, false); } diff --git a/src/machine.rs b/src/machine.rs index 07885148e1fd9..d15e290cbfdc9 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -334,6 +334,10 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { alloc: Cow<'b, Allocation>, kind: Option>, ) -> (Cow<'b, Allocation>, Self::PointerTag) { + if Some(id) == memory_extra.tracked_alloc_id { + register_diagnostic(NonHaltingDiagnostic::CreatedAlloc(id)); + } + let kind = kind.expect("we set our STATIC_KIND so this cannot be None"); let alloc = alloc.into_owned(); let (stacks, base_tag) = From 6670f43917db0df610401f50dc62c5d262c496b0 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 6 Mar 2020 10:46:12 +0100 Subject: [PATCH 1621/3747] README: add another bug Miri found --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index f18a5d668c392..3a7d92e906c16 100644 --- a/README.md +++ b/README.md @@ -245,6 +245,7 @@ Violations of [Stacked Borrows] found that are likely bugs (but Stacked Borrows * [`BTreeMap` creating mutable references that overlap with shared references](https://github.com/rust-lang/rust/pull/58431) * [`LinkedList` creating overlapping mutable references](https://github.com/rust-lang/rust/pull/60072) * [`Vec::push` invalidating existing references into the vector](https://github.com/rust-lang/rust/issues/60847) +* [`align_to_mut` violating uniqueness of mutable references](https://github.com/rust-lang/rust/issues/68549) ## License From d13fe01f824f9a58f94058948e57f4d8c6365866 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Wed, 4 Mar 2020 12:15:14 -0500 Subject: [PATCH 1622/3747] add working shim for environ --- src/eval.rs | 2 +- src/machine.rs | 14 ++++++++++++++ src/shims/env.rs | 15 +++++++++++++++ 3 files changed, 30 insertions(+), 1 deletion(-) diff --git a/src/eval.rs b/src/eval.rs index 1981a8d1e03e9..dacd996c4a6e0 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -77,8 +77,8 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( ), ); // Complete initialization. - MemoryExtra::init_extern_statics(&mut ecx)?; EnvVars::init(&mut ecx, config.excluded_env_vars); + MemoryExtra::init_extern_statics(&mut ecx)?; // Setup first stack-frame let main_instance = ty::Instance::mono(tcx, main_id); diff --git a/src/machine.rs b/src/machine.rs index d15e290cbfdc9..0e3cc58df736a 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -84,6 +84,9 @@ pub struct MemoryExtra { /// An allocation ID to report when it is being allocated /// (helps for debugging memory leaks). tracked_alloc_id: Option, + + /// The `AllocId` for the `environ` static. + pub(crate) environ: Option>, } impl MemoryExtra { @@ -99,6 +102,7 @@ impl MemoryExtra { extern_statics: FxHashMap::default(), rng: RefCell::new(rng), tracked_alloc_id, + environ: None, } } @@ -118,6 +122,16 @@ impl MemoryExtra { .extern_statics .insert(Symbol::intern("__cxa_thread_atexit_impl"), place.ptr.assert_ptr().alloc_id) .unwrap_none(); + + // "environ" + let layout = this.layout_of(this.tcx.types.usize)?; + let place = this.allocate(layout, MiriMemoryKind::Machine.into()); + this.write_scalar(this.memory.extra.environ.unwrap(), place.into())?; + this.memory + .extra + .extern_statics + .insert(Symbol::intern("environ"), place.ptr.assert_ptr().alloc_id) + .unwrap_none(); } _ => {} // No "extern statics" supported on this platform } diff --git a/src/shims/env.rs b/src/shims/env.rs index 79f0c5b3d902a..833fef69f28f1 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -2,6 +2,7 @@ use std::ffi::{OsString, OsStr}; use std::env; use crate::stacked_borrows::Tag; +use crate::rustc_target::abi::LayoutOf; use crate::*; use rustc_data_structures::fx::FxHashMap; @@ -20,15 +21,29 @@ impl EnvVars { ecx: &mut InterpCx<'mir, 'tcx, Evaluator<'tcx>>, excluded_env_vars: Vec, ) { + let mut vars = Vec::new(); if ecx.machine.communicate { for (name, value) in env::vars() { if !excluded_env_vars.contains(&name) { let var_ptr = alloc_env_var_as_c_str(name.as_ref(), value.as_ref(), ecx); ecx.machine.env_vars.map.insert(OsString::from(name), var_ptr); + vars.push(var_ptr.into()); } } } + // Add the trailing null pointer + vars.push(Scalar::from_int(0, ecx.pointer_size())); + // Make an array with all these pointers inside Miri. + let tcx = ecx.tcx; + let environ_layout = + ecx.layout_of(tcx.mk_array(tcx.mk_imm_ptr(tcx.types.u8), vars.len() as u64)).unwrap(); + let environ_place = ecx.allocate(environ_layout, MiriMemoryKind::Machine.into()); + for (idx, var) in vars.into_iter().enumerate() { + let place = ecx.mplace_field(environ_place, idx as u64).unwrap(); + ecx.write_scalar(var, place.into()).unwrap(); + } + ecx.memory.extra.environ = Some(environ_place.ptr.into()); } } From 4f5fdc581014ecb17a9aa14ada2a2f186c9a46a8 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Wed, 4 Mar 2020 13:24:01 -0500 Subject: [PATCH 1623/3747] update the environ shim when environment changes --- src/eval.rs | 2 +- src/machine.rs | 19 ++++++++++--------- src/shims/env.rs | 41 +++++++++++++++++++++++++++-------------- 3 files changed, 38 insertions(+), 24 deletions(-) diff --git a/src/eval.rs b/src/eval.rs index dacd996c4a6e0..1981a8d1e03e9 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -77,8 +77,8 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( ), ); // Complete initialization. - EnvVars::init(&mut ecx, config.excluded_env_vars); MemoryExtra::init_extern_statics(&mut ecx)?; + EnvVars::init(&mut ecx, config.excluded_env_vars); // Setup first stack-frame let main_instance = ty::Instance::mono(tcx, main_id); diff --git a/src/machine.rs b/src/machine.rs index 0e3cc58df736a..ece4b62d3af18 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -70,7 +70,7 @@ pub struct AllocExtra { /// Extra global memory data #[derive(Clone, Debug)] -pub struct MemoryExtra { +pub struct MemoryExtra<'tcx> { pub stacked_borrows: Option, pub intptrcast: intptrcast::MemoryExtra, @@ -85,11 +85,11 @@ pub struct MemoryExtra { /// (helps for debugging memory leaks). tracked_alloc_id: Option, - /// The `AllocId` for the `environ` static. - pub(crate) environ: Option>, + /// Place where the `environ` static is stored. + pub(crate) environ: Option>, } -impl MemoryExtra { +impl<'tcx> MemoryExtra<'tcx> { pub fn new(rng: StdRng, stacked_borrows: bool, tracked_pointer_tag: Option, tracked_alloc_id: Option) -> Self { let stacked_borrows = if stacked_borrows { Some(Rc::new(RefCell::new(stacked_borrows::GlobalState::new(tracked_pointer_tag)))) @@ -107,7 +107,7 @@ impl MemoryExtra { } /// Sets up the "extern statics" for this machine. - pub fn init_extern_statics<'mir, 'tcx>( + pub fn init_extern_statics<'mir>( this: &mut MiriEvalContext<'mir, 'tcx>, ) -> InterpResult<'tcx> { match this.tcx.sess.target.target.target_os.as_str() { @@ -126,12 +126,13 @@ impl MemoryExtra { // "environ" let layout = this.layout_of(this.tcx.types.usize)?; let place = this.allocate(layout, MiriMemoryKind::Machine.into()); - this.write_scalar(this.memory.extra.environ.unwrap(), place.into())?; + this.write_scalar(Scalar::from_machine_usize(0, &*this.tcx), place.into())?; this.memory .extra .extern_statics .insert(Symbol::intern("environ"), place.ptr.assert_ptr().alloc_id) .unwrap_none(); + this.memory.extra.environ = Some(place); } _ => {} // No "extern statics" supported on this platform } @@ -217,7 +218,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { type MemoryKinds = MiriMemoryKind; type FrameExtra = FrameData<'tcx>; - type MemoryExtra = MemoryExtra; + type MemoryExtra = MemoryExtra<'tcx>; type AllocExtra = AllocExtra; type PointerTag = Tag; type ExtraFnVal = Dlsym; @@ -343,7 +344,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { } fn init_allocation_extra<'b>( - memory_extra: &MemoryExtra, + memory_extra: &MemoryExtra<'tcx>, id: AllocId, alloc: Cow<'b, Allocation>, kind: Option>, @@ -380,7 +381,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { } #[inline(always)] - fn tag_static_base_pointer(memory_extra: &MemoryExtra, id: AllocId) -> Self::PointerTag { + fn tag_static_base_pointer(memory_extra: &MemoryExtra<'tcx>, id: AllocId) -> Self::PointerTag { if let Some(stacked_borrows) = memory_extra.stacked_borrows.as_ref() { stacked_borrows.borrow_mut().static_base_ptr(id) } else { diff --git a/src/shims/env.rs b/src/shims/env.rs index 833fef69f28f1..05c098bc4e72e 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -21,29 +21,16 @@ impl EnvVars { ecx: &mut InterpCx<'mir, 'tcx, Evaluator<'tcx>>, excluded_env_vars: Vec, ) { - let mut vars = Vec::new(); if ecx.machine.communicate { for (name, value) in env::vars() { if !excluded_env_vars.contains(&name) { let var_ptr = alloc_env_var_as_c_str(name.as_ref(), value.as_ref(), ecx); ecx.machine.env_vars.map.insert(OsString::from(name), var_ptr); - vars.push(var_ptr.into()); } } } - // Add the trailing null pointer - vars.push(Scalar::from_int(0, ecx.pointer_size())); - // Make an array with all these pointers inside Miri. - let tcx = ecx.tcx; - let environ_layout = - ecx.layout_of(tcx.mk_array(tcx.mk_imm_ptr(tcx.types.u8), vars.len() as u64)).unwrap(); - let environ_place = ecx.allocate(environ_layout, MiriMemoryKind::Machine.into()); - for (idx, var) in vars.into_iter().enumerate() { - let place = ecx.mplace_field(environ_place, idx as u64).unwrap(); - ecx.write_scalar(var, place.into()).unwrap(); - } - ecx.memory.extra.environ = Some(environ_place.ptr.into()); + ecx.update_environ().unwrap(); } } @@ -94,6 +81,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if let Some((name, value)) = new { let var_ptr = alloc_env_var_as_c_str(&name, &value, &mut this); if let Some(var) = this.machine.env_vars.map.insert(name.to_owned(), var_ptr) { + this.update_environ()?; this.memory .deallocate(var, None, MiriMemoryKind::Machine.into())?; } @@ -112,6 +100,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let name = this.read_os_str_from_c_str(name_ptr)?.to_owned(); if !name.is_empty() && !name.to_string_lossy().contains('=') { success = Some(this.machine.env_vars.map.remove(&name)); + this.update_environ()?; } } if let Some(old) = success { @@ -165,4 +154,28 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } } + + fn update_environ(&mut self) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + // Collect all the pointers to each variable in a vector. + let mut vars: Vec> = this.machine.env_vars.map.values().map(|&ptr| ptr.into()).collect(); + // Add the trailing null pointer. + vars.push(Scalar::from_int(0, this.pointer_size())); + // Make an array with all these pointers inside Miri. + let tcx = this.tcx; + let vars_layout = + this.layout_of(tcx.mk_array(tcx.types.usize, vars.len() as u64))?; + let vars_place = this.allocate(vars_layout, MiriMemoryKind::Machine.into()); + for (idx, var) in vars.into_iter().enumerate() { + let place = this.mplace_field(vars_place, idx as u64)?; + this.write_scalar(var, place.into())?; + } + + this.write_scalar( + vars_place.ptr, + this.memory.extra.environ.unwrap().into(), + )?; + + Ok(()) + } } From a28330febb07e46b5f5bc73356eb4b36b549c51e Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Thu, 5 Mar 2020 09:41:35 -0500 Subject: [PATCH 1624/3747] add testcase for `environ` shim --- tests/run-pass/env.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/run-pass/env.rs b/tests/run-pass/env.rs index faf947420347d..0b7ee8adc1a71 100644 --- a/tests/run-pass/env.rs +++ b/tests/run-pass/env.rs @@ -8,4 +8,6 @@ fn main() { assert_eq!(env::var("MIRI_TEST"), Ok("the answer".to_owned())); // Test that miri environment is isolated when communication is disabled. assert!(env::var("MIRI_ENV_VAR_TEST").is_err()); + // Test that the new variable is in the `std::env::Vars` iterator + assert!(env::vars().any(|(name, value)| name == "MIRI_TEST")) } From 7882dfb3f599df93d1e0d0a643e41072c6bf5683 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 5 Mar 2020 23:25:55 +0100 Subject: [PATCH 1625/3747] fix env update, and expand test --- src/shims/env.rs | 4 ++-- tests/run-pass/env.rs | 23 +++++++++++++++++++---- tests/run-pass/env.stdout | 14 ++++++++++++++ 3 files changed, 35 insertions(+), 6 deletions(-) create mode 100644 tests/run-pass/env.stdout diff --git a/src/shims/env.rs b/src/shims/env.rs index 05c098bc4e72e..3469beb971d68 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -81,10 +81,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if let Some((name, value)) = new { let var_ptr = alloc_env_var_as_c_str(&name, &value, &mut this); if let Some(var) = this.machine.env_vars.map.insert(name.to_owned(), var_ptr) { - this.update_environ()?; this.memory .deallocate(var, None, MiriMemoryKind::Machine.into())?; } + this.update_environ()?; Ok(0) } else { Ok(-1) @@ -100,7 +100,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let name = this.read_os_str_from_c_str(name_ptr)?.to_owned(); if !name.is_empty() && !name.to_string_lossy().contains('=') { success = Some(this.machine.env_vars.map.remove(&name)); - this.update_environ()?; } } if let Some(old) = success { @@ -108,6 +107,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.memory .deallocate(var, None, MiriMemoryKind::Machine.into())?; } + this.update_environ()?; Ok(0) } else { Ok(-1) diff --git a/tests/run-pass/env.rs b/tests/run-pass/env.rs index 0b7ee8adc1a71..c7506b23c1da0 100644 --- a/tests/run-pass/env.rs +++ b/tests/run-pass/env.rs @@ -3,11 +3,26 @@ use std::env; fn main() { + // Test that miri environment is isolated when communication is disabled. + // (`MIRI_ENV_VAR_TEST` is set by the test harness.) + assert_eq!(env::var("MIRI_ENV_VAR_TEST"), Err(env::VarError::NotPresent)); + + // Test base state. + println!("{:#?}", env::vars().collect::>()); assert_eq!(env::var("MIRI_TEST"), Err(env::VarError::NotPresent)); + + // Set the variable. env::set_var("MIRI_TEST", "the answer"); assert_eq!(env::var("MIRI_TEST"), Ok("the answer".to_owned())); - // Test that miri environment is isolated when communication is disabled. - assert!(env::var("MIRI_ENV_VAR_TEST").is_err()); - // Test that the new variable is in the `std::env::Vars` iterator - assert!(env::vars().any(|(name, value)| name == "MIRI_TEST")) + println!("{:#?}", env::vars().collect::>()); + + // Change the variable. + env::set_var("MIRI_TEST", "42"); + assert_eq!(env::var("MIRI_TEST"), Ok("42".to_owned())); + println!("{:#?}", env::vars().collect::>()); + + // Remove the variable. + env::remove_var("MIRI_TEST"); + assert_eq!(env::var("MIRI_TEST"), Err(env::VarError::NotPresent)); + println!("{:#?}", env::vars().collect::>()); } diff --git a/tests/run-pass/env.stdout b/tests/run-pass/env.stdout new file mode 100644 index 0000000000000..9a8f979598ebc --- /dev/null +++ b/tests/run-pass/env.stdout @@ -0,0 +1,14 @@ +[] +[ + ( + "MIRI_TEST", + "the answer", + ), +] +[ + ( + "MIRI_TEST", + "42", + ), +] +[] From fefa8e53440cddf4acaa592184a513b7d9b9ce2e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 6 Mar 2020 14:28:34 +0100 Subject: [PATCH 1626/3747] expand clock and fs tests a bit --- tests/run-pass/clock.rs | 8 +++++++- tests/run-pass/fs.rs | 6 +++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/tests/run-pass/clock.rs b/tests/run-pass/clock.rs index 23f45f91ada14..b4c3fa08fdc60 100644 --- a/tests/run-pass/clock.rs +++ b/tests/run-pass/clock.rs @@ -4,5 +4,11 @@ use std::time::SystemTime; fn main() { - let _now = SystemTime::now(); + let now1 = SystemTime::now(); + + // Do some work to make time pass. + for _ in 0..10 { drop(vec![42]); } + + let now2 = SystemTime::now(); + assert!(now2 > now1); } diff --git a/tests/run-pass/fs.rs b/tests/run-pass/fs.rs index f859f934bdd1c..0f3512b366050 100644 --- a/tests/run-pass/fs.rs +++ b/tests/run-pass/fs.rs @@ -215,9 +215,13 @@ fn test_directory() { // Clean up the files in the directory remove_file(&path_1).unwrap(); remove_file(&path_2).unwrap(); + // Now there should be nothing left in the directory. + let dir_iter = read_dir(&dir_path).unwrap(); + let file_names = dir_iter.map(|e| e.unwrap().file_name()).collect::>(); + assert!(file_names.is_empty()); // Deleting the directory should succeed. remove_dir(&dir_path).unwrap(); - // Reading the metadata of a non-existent file should fail with a "not found" error. + // Reading the metadata of a non-existent directory should fail with a "not found" error. assert_eq!(ErrorKind::NotFound, check_metadata(&[], &dir_path).unwrap_err().kind()); } From aedc34c6e5ee8d675212bb60d54e1394e9ee9964 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Fri, 6 Mar 2020 09:38:16 -0500 Subject: [PATCH 1627/3747] deallocate old environ --- src/machine.rs | 2 +- src/shims/env.rs | 10 +++++++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/machine.rs b/src/machine.rs index ece4b62d3af18..188001c170abf 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -85,7 +85,7 @@ pub struct MemoryExtra<'tcx> { /// (helps for debugging memory leaks). tracked_alloc_id: Option, - /// Place where the `environ` static is stored. + /// Place where the `environ` static is stored. Its value should not change after initialization. pub(crate) environ: Option>, } diff --git a/src/shims/env.rs b/src/shims/env.rs index 3469beb971d68..0408741cf2a68 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -155,8 +155,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } + /// Updates the `environ` static. It should not be called before + /// `MemoryExtra::init_extern_statics`. fn update_environ(&mut self) -> InterpResult<'tcx> { let this = self.eval_context_mut(); + // Deallocate the old environ value. + let old_vars_ptr = this.read_scalar(this.memory.extra.environ.unwrap().into())?.not_undef()?; + // The pointer itself can be null because `MemoryExtra::init_extern_statics` only + // initializes the place for the static but not the static itself. + if !this.is_null(old_vars_ptr)? { + this.memory.deallocate(this.force_ptr(old_vars_ptr)?, None, MiriMemoryKind::Machine.into())?; + } // Collect all the pointers to each variable in a vector. let mut vars: Vec> = this.machine.env_vars.map.values().map(|&ptr| ptr.into()).collect(); // Add the trailing null pointer. @@ -170,7 +179,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let place = this.mplace_field(vars_place, idx as u64)?; this.write_scalar(var, place.into())?; } - this.write_scalar( vars_place.ptr, this.memory.extra.environ.unwrap().into(), From 6eccc809f21c11f583ec237dffdbebc7e6b66038 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Sat, 7 Mar 2020 09:26:04 -0500 Subject: [PATCH 1628/3747] test that `environ` gets deallocated on changes --- tests/compile-fail/environ-gets-deallocated.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 tests/compile-fail/environ-gets-deallocated.rs diff --git a/tests/compile-fail/environ-gets-deallocated.rs b/tests/compile-fail/environ-gets-deallocated.rs new file mode 100644 index 0000000000000..014c8c431e7fb --- /dev/null +++ b/tests/compile-fail/environ-gets-deallocated.rs @@ -0,0 +1,10 @@ +extern "C" { + static environ: *const *const u8; +} + +fn main() { + let pointer = unsafe { environ }; + let _x = unsafe { *pointer }; + std::env::set_var("FOO", "BAR"); + let _y = unsafe { *pointer }; //~ ERROR dangling pointer was dereferenced +} From e31b8b3342f4fc97198609f5e7e13e484969c8b1 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Sat, 7 Mar 2020 09:39:44 -0500 Subject: [PATCH 1629/3747] add `_NSGetEnviron` foreign function for macos --- src/machine.rs | 28 ++++++++++++++------------ src/shims/foreign_items/posix/macos.rs | 5 ++++- 2 files changed, 19 insertions(+), 14 deletions(-) diff --git a/src/machine.rs b/src/machine.rs index 188001c170abf..5a50a76dfb9f8 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -110,19 +110,21 @@ impl<'tcx> MemoryExtra<'tcx> { pub fn init_extern_statics<'mir>( this: &mut MiriEvalContext<'mir, 'tcx>, ) -> InterpResult<'tcx> { - match this.tcx.sess.target.target.target_os.as_str() { - "linux" => { - // "__cxa_thread_atexit_impl" - // This should be all-zero, pointer-sized. - let layout = this.layout_of(this.tcx.types.usize)?; - let place = this.allocate(layout, MiriMemoryKind::Machine.into()); - this.write_scalar(Scalar::from_machine_usize(0, &*this.tcx), place.into())?; - this.memory - .extra - .extern_statics - .insert(Symbol::intern("__cxa_thread_atexit_impl"), place.ptr.assert_ptr().alloc_id) - .unwrap_none(); - + let target_os = this.tcx.sess.target.target.target_os.as_str(); + match target_os { + "linux" | "macos" => { + if target_os == "linux" { + // "__cxa_thread_atexit_impl" + // This should be all-zero, pointer-sized. + let layout = this.layout_of(this.tcx.types.usize)?; + let place = this.allocate(layout, MiriMemoryKind::Machine.into()); + this.write_scalar(Scalar::from_machine_usize(0, &*this.tcx), place.into())?; + this.memory + .extra + .extern_statics + .insert(Symbol::intern("__cxa_thread_atexit_impl"), place.ptr.assert_ptr().alloc_id) + .unwrap_none(); + } // "environ" let layout = this.layout_of(this.tcx.types.usize)?; let place = this.allocate(layout, MiriMemoryKind::Machine.into()); diff --git a/src/shims/foreign_items/posix/macos.rs b/src/shims/foreign_items/posix/macos.rs index cb6cd9ba44b40..d167191279ebc 100644 --- a/src/shims/foreign_items/posix/macos.rs +++ b/src/shims/foreign_items/posix/macos.rs @@ -41,7 +41,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let result = this.macos_fstat(args[0], args[1])?; this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; } - + // Environment related shims + "_NSGetEnviron" => { + this.write_scalar(this.memory.extra.environ.unwrap().ptr, dest)?; + } // The only reason this is not in the `posix` module is because the `linux` item has a // different name. "opendir$INODE64" => { From 18a71ef7b36fa8ed2031b69e414261e086fd711c Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Sat, 7 Mar 2020 11:35:00 -0500 Subject: [PATCH 1630/3747] minor corrections --- src/eval.rs | 2 +- src/machine.rs | 2 +- src/shims/env.rs | 4 ++-- tests/compile-fail/environ-gets-deallocated.rs | 18 ++++++++++++++++-- 4 files changed, 20 insertions(+), 6 deletions(-) diff --git a/src/eval.rs b/src/eval.rs index 1981a8d1e03e9..13b55a93f216c 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -78,7 +78,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( ); // Complete initialization. MemoryExtra::init_extern_statics(&mut ecx)?; - EnvVars::init(&mut ecx, config.excluded_env_vars); + EnvVars::init(&mut ecx, config.excluded_env_vars)?; // Setup first stack-frame let main_instance = ty::Instance::mono(tcx, main_id); diff --git a/src/machine.rs b/src/machine.rs index 5a50a76dfb9f8..0f0c44300108a 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -85,7 +85,7 @@ pub struct MemoryExtra<'tcx> { /// (helps for debugging memory leaks). tracked_alloc_id: Option, - /// Place where the `environ` static is stored. Its value should not change after initialization. + /// Place where the `environ` static is stored. Lazily initialized, but then never changes. pub(crate) environ: Option>, } diff --git a/src/shims/env.rs b/src/shims/env.rs index 0408741cf2a68..1962ca026ccc5 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -20,7 +20,7 @@ impl EnvVars { pub(crate) fn init<'mir, 'tcx>( ecx: &mut InterpCx<'mir, 'tcx, Evaluator<'tcx>>, excluded_env_vars: Vec, - ) { + ) -> InterpResult<'tcx> { if ecx.machine.communicate { for (name, value) in env::vars() { if !excluded_env_vars.contains(&name) { @@ -30,7 +30,7 @@ impl EnvVars { } } } - ecx.update_environ().unwrap(); + ecx.update_environ() } } diff --git a/tests/compile-fail/environ-gets-deallocated.rs b/tests/compile-fail/environ-gets-deallocated.rs index 014c8c431e7fb..a3d82a884213c 100644 --- a/tests/compile-fail/environ-gets-deallocated.rs +++ b/tests/compile-fail/environ-gets-deallocated.rs @@ -1,9 +1,23 @@ -extern "C" { +//ignore-windows: TODO env var emulation stubbed out on Windows + +#[cfg(target_os="linux")] +fn get_environ() -> *const *const u8 { + extern "C" { static environ: *const *const u8; + } + environ +} + +#[cfg(target_os="macos")] +fn get_environ() -> *const *const u8 { + extern "C" { + fn _NSGetEnviron() -> *mut *const *const u8; + } + unsafe { *_NSGetEnviron() } } fn main() { - let pointer = unsafe { environ }; + let pointer = get_environ(); let _x = unsafe { *pointer }; std::env::set_var("FOO", "BAR"); let _y = unsafe { *pointer }; //~ ERROR dangling pointer was dereferenced From 6fd3c9174c7ad518bfa7f4646477cf5606209474 Mon Sep 17 00:00:00 2001 From: Bastian Kauschke Date: Sun, 8 Mar 2020 14:31:57 +0100 Subject: [PATCH 1631/3747] rm custom `intrinsics::discriminant_value` --- src/shims/intrinsics.rs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 9cae97a4060cf..44283364a9864 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -248,12 +248,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } - "discriminant_value" => { - let place = this.deref_operand(args[0])?; - let discr_val = this.read_discriminant(place.into())?.0; - this.write_scalar(Scalar::from_uint(discr_val, dest.layout.size), dest)?; - } - #[rustfmt::skip] | "sinf32" | "fabsf32" From 8392a0c589461e998a28a52a070b5fa5a143cf77 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Sat, 7 Mar 2020 15:33:27 -0500 Subject: [PATCH 1632/3747] only expose environ on linux --- src/eval.rs | 2 +- src/machine.rs | 26 +++++++------------ src/shims/env.rs | 9 +++++-- src/shims/foreign_items/posix/macos.rs | 10 ++++--- .../compile-fail/environ-gets-deallocated.rs | 4 +-- 5 files changed, 26 insertions(+), 25 deletions(-) diff --git a/src/eval.rs b/src/eval.rs index 13b55a93f216c..a82c40a99e011 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -77,8 +77,8 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( ), ); // Complete initialization. - MemoryExtra::init_extern_statics(&mut ecx)?; EnvVars::init(&mut ecx, config.excluded_env_vars)?; + MemoryExtra::init_extern_statics(&mut ecx)?; // Setup first stack-frame let main_instance = ty::Instance::mono(tcx, main_id); diff --git a/src/machine.rs b/src/machine.rs index 0f0c44300108a..d21ff32897573 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -112,29 +112,23 @@ impl<'tcx> MemoryExtra<'tcx> { ) -> InterpResult<'tcx> { let target_os = this.tcx.sess.target.target.target_os.as_str(); match target_os { - "linux" | "macos" => { - if target_os == "linux" { - // "__cxa_thread_atexit_impl" - // This should be all-zero, pointer-sized. - let layout = this.layout_of(this.tcx.types.usize)?; - let place = this.allocate(layout, MiriMemoryKind::Machine.into()); - this.write_scalar(Scalar::from_machine_usize(0, &*this.tcx), place.into())?; - this.memory - .extra - .extern_statics - .insert(Symbol::intern("__cxa_thread_atexit_impl"), place.ptr.assert_ptr().alloc_id) - .unwrap_none(); - } - // "environ" + "linux" => { + // "__cxa_thread_atexit_impl" + // This should be all-zero, pointer-sized. let layout = this.layout_of(this.tcx.types.usize)?; let place = this.allocate(layout, MiriMemoryKind::Machine.into()); this.write_scalar(Scalar::from_machine_usize(0, &*this.tcx), place.into())?; this.memory .extra .extern_statics - .insert(Symbol::intern("environ"), place.ptr.assert_ptr().alloc_id) + .insert(Symbol::intern("__cxa_thread_atexit_impl"), place.ptr.assert_ptr().alloc_id) + .unwrap_none(); + // "environ" + this.memory + .extra + .extern_statics + .insert(Symbol::intern("environ"), this.memory.extra.environ.unwrap().ptr.assert_ptr().alloc_id) .unwrap_none(); - this.memory.extra.environ = Some(place); } _ => {} // No "extern statics" supported on this platform } diff --git a/src/shims/env.rs b/src/shims/env.rs index 1962ca026ccc5..aaecbebc36032 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -30,6 +30,11 @@ impl EnvVars { } } } + // Initialize the `environ` static + let layout = ecx.layout_of(ecx.tcx.types.usize)?; + let place = ecx.allocate(layout, MiriMemoryKind::Machine.into()); + ecx.write_scalar(Scalar::from_machine_usize(0, &*ecx.tcx), place.into())?; + ecx.memory.extra.environ = Some(place); ecx.update_environ() } } @@ -156,12 +161,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } /// Updates the `environ` static. It should not be called before - /// `MemoryExtra::init_extern_statics`. + /// `EnvVars::init`. fn update_environ(&mut self) -> InterpResult<'tcx> { let this = self.eval_context_mut(); // Deallocate the old environ value. let old_vars_ptr = this.read_scalar(this.memory.extra.environ.unwrap().into())?.not_undef()?; - // The pointer itself can be null because `MemoryExtra::init_extern_statics` only + // The pointer itself can be null because `EnvVars::init` only // initializes the place for the static but not the static itself. if !this.is_null(old_vars_ptr)? { this.memory.deallocate(this.force_ptr(old_vars_ptr)?, None, MiriMemoryKind::Machine.into())?; diff --git a/src/shims/foreign_items/posix/macos.rs b/src/shims/foreign_items/posix/macos.rs index d167191279ebc..c5c6423e8501e 100644 --- a/src/shims/foreign_items/posix/macos.rs +++ b/src/shims/foreign_items/posix/macos.rs @@ -41,10 +41,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let result = this.macos_fstat(args[0], args[1])?; this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; } - // Environment related shims - "_NSGetEnviron" => { - this.write_scalar(this.memory.extra.environ.unwrap().ptr, dest)?; - } + // The only reason this is not in the `posix` module is because the `linux` item has a // different name. "opendir$INODE64" => { @@ -59,6 +56,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; } + // Environment related shims + "_NSGetEnviron" => { + this.write_scalar(this.memory.extra.environ.unwrap().ptr, dest)?; + } + // Time related shims "gettimeofday" => { let result = this.gettimeofday(args[0], args[1])?; diff --git a/tests/compile-fail/environ-gets-deallocated.rs b/tests/compile-fail/environ-gets-deallocated.rs index a3d82a884213c..6131613fc00bb 100644 --- a/tests/compile-fail/environ-gets-deallocated.rs +++ b/tests/compile-fail/environ-gets-deallocated.rs @@ -3,9 +3,9 @@ #[cfg(target_os="linux")] fn get_environ() -> *const *const u8 { extern "C" { - static environ: *const *const u8; + static mut environ: *const *const u8; } - environ + unsafe { environ } } #[cfg(target_os="macos")] From 5c4cc2e3e0a4c8afff1bc4de718966233c7c03ee Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 8 Mar 2020 16:29:57 +0100 Subject: [PATCH 1633/3747] bump dependencies --- Cargo.lock | 104 ++++++++++++++++++++++++++++------------------------- 1 file changed, 55 insertions(+), 49 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 951e91dad5b29..b36418a1cbacf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,12 +2,17 @@ # It is not intended for manual editing. [[package]] name = "aho-corasick" -version = "0.7.8" +version = "0.7.9" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "anyhow" +version = "1.0.26" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "arrayref" version = "0.3.6" @@ -35,10 +40,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "backtrace" -version = "0.3.44" +version = "0.3.45" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "backtrace-sys 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)", + "backtrace-sys 0.1.33 (registry+https://github.com/rust-lang/crates.io-index)", "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-demangle 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", @@ -46,7 +51,7 @@ dependencies = [ [[package]] name = "backtrace-sys" -version = "0.1.32" +version = "0.1.33" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cc 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)", @@ -109,7 +114,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "chrono" -version = "0.4.10" +version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "num-integer 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", @@ -119,7 +124,7 @@ dependencies = [ [[package]] name = "colored" -version = "1.9.2" +version = "1.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", @@ -129,7 +134,7 @@ dependencies = [ [[package]] name = "compiletest_rs" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "diff 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", @@ -139,7 +144,7 @@ dependencies = [ "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "miow 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "regex 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "rustfix 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "rustfix 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.48 (registry+https://github.com/rust-lang/crates.io-index)", @@ -211,21 +216,21 @@ dependencies = [ [[package]] name = "failure" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "backtrace 0.3.44 (registry+https://github.com/rust-lang/crates.io-index)", - "failure_derive 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "backtrace 0.3.45 (registry+https://github.com/rust-lang/crates.io-index)", + "failure_derive 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "failure_derive" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.16 (registry+https://github.com/rust-lang/crates.io-index)", "synstructure 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -322,8 +327,8 @@ version = "0.1.0" dependencies = [ "byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", "cargo_metadata 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", - "colored 1.9.2 (registry+https://github.com/rust-lang/crates.io-index)", - "compiletest_rs 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "colored 1.9.3 (registry+https://github.com/rust-lang/crates.io-index)", + "compiletest_rs 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", "directories 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", @@ -363,7 +368,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "proc-macro2" -version = "1.0.8" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -376,10 +381,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "quote" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -439,15 +444,15 @@ name = "regex" version = "1.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "aho-corasick 0.7.8 (registry+https://github.com/rust-lang/crates.io-index)", + "aho-corasick 0.7.9 (registry+https://github.com/rust-lang/crates.io-index)", "memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "regex-syntax 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)", + "regex-syntax 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)", "thread_local 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "regex-syntax" -version = "0.6.14" +version = "0.6.16" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -489,10 +494,10 @@ dependencies = [ [[package]] name = "rustfix" -version = "0.4.6" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "anyhow 1.0.26 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.48 (registry+https://github.com/rust-lang/crates.io-index)", @@ -530,9 +535,9 @@ name = "serde_derive" version = "1.0.104" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.16 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -563,11 +568,11 @@ dependencies = [ [[package]] name = "syn" -version = "1.0.15" +version = "1.0.16" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -576,9 +581,9 @@ name = "synstructure" version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.16 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -656,8 +661,8 @@ version = "3.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "chrono 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", - "failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", + "chrono 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", + "failure 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -693,13 +698,14 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" [metadata] -"checksum aho-corasick 0.7.8 (registry+https://github.com/rust-lang/crates.io-index)" = "743ad5a418686aad3b87fd14c43badd828cf26e214a00f92a384291cf22e1811" +"checksum aho-corasick 0.7.9 (registry+https://github.com/rust-lang/crates.io-index)" = "d5e63fd144e18ba274ae7095c0197a870a7b9468abc801dd62f190d80817d2ec" +"checksum anyhow 1.0.26 (registry+https://github.com/rust-lang/crates.io-index)" = "7825f6833612eb2414095684fcf6c635becf3ce97fe48cf6421321e93bfbd53c" "checksum arrayref 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544" "checksum arrayvec 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cff77d8686867eceff3105329d4698d96c2391c176d5d03adc90c7389162b5b8" "checksum atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" "checksum autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d" -"checksum backtrace 0.3.44 (registry+https://github.com/rust-lang/crates.io-index)" = "e4036b9bf40f3cf16aba72a3d65e8a520fc4bafcdc7079aea8f848c58c5b5536" -"checksum backtrace-sys 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)" = "5d6575f128516de27e3ce99689419835fce9643a9b215a14d2b5b685be018491" +"checksum backtrace 0.3.45 (registry+https://github.com/rust-lang/crates.io-index)" = "ad235dabf00f36301792cfe82499880ba54c6486be094d1047b02bacb67c14e8" +"checksum backtrace-sys 0.1.33 (registry+https://github.com/rust-lang/crates.io-index)" = "e17b52e737c40a7d75abca20b29a19a0eb7ba9fc72c5a72dd282a0a3c2c0dc35" "checksum base64 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b41b7ea54a0c9d92199de89e20e58d49f02f8e699814ef3fdf266f6f748d15c7" "checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" "checksum blake2b_simd 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)" = "d8fb2d74254a3a0b5cac33ac9f8ed0e44aa50378d9dbb2e5d83bd21ed1dc2c8a" @@ -708,9 +714,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum cargo_metadata 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "46e3374c604fb39d1a2f35ed5e4a4e30e60d01fab49446e08f1b3e9a90aef202" "checksum cc 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)" = "95e28fa049fda1c330bcf9d723be7663a899c4679724b34c81e9f5a326aab8cd" "checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" -"checksum chrono 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "31850b4a4d6bae316f7a09e691c944c28299298837edc0a03f755618c23cbc01" -"checksum colored 1.9.2 (registry+https://github.com/rust-lang/crates.io-index)" = "8815e2ab78f3a59928fc32e141fbeece88320a240e43f47b2fd64ea3a88a5b3d" -"checksum compiletest_rs 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d7b678957210a00ba0fbeacc23d38cbfbf29895564da1616564634351e1dac5e" +"checksum chrono 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)" = "80094f509cf8b5ae86a4966a39b3ff66cd7e2a3e594accec3743ff3fabeab5b2" +"checksum colored 1.9.3 (registry+https://github.com/rust-lang/crates.io-index)" = "f4ffc801dacf156c5854b9df4f425a626539c3a6ef7893cc0c5084a23f0b6c59" +"checksum compiletest_rs 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "46cc00afd45129f775f8f8ee57c1ae2f7aabdf9692b2d74e36b917b91277bc7c" "checksum constant_time_eq 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" "checksum crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8" "checksum diff 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "0e25ea47919b1560c4e3b7fe0aaab9becf5b84a10325ddf7db0f0ba5e1026499" @@ -718,8 +724,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum dirs 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "13aea89a5c93364a98e9b37b2fa237effbb694d5cfe01c5b70941f7eb087d5e3" "checksum dirs-sys 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "afa0b23de8fd801745c471deffa6e12d248f962c9fd4b4c33787b055599bde7b" "checksum env_logger 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "44533bbbb3bb3c1fa17d9f2e4e38bbbaf8396ba82193c4cb1b6445d711445d36" -"checksum failure 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "f8273f13c977665c5db7eb2b99ae520952fe5ac831ae4cd09d80c4c7042b5ed9" -"checksum failure_derive 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0bc225b78e0391e4b8683440bf2e63c2deeeb2ce5189eab46e2b68c6d3725d08" +"checksum failure 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "b8529c2421efa3066a5cbd8063d2244603824daccb6936b079010bb2aa89464b" +"checksum failure_derive 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "030a733c8287d6213886dd487564ff5c8f6aae10278b3588ed177f9d18f8d231" "checksum filetime 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "1ff6d4dab0aa0c8e6346d46052e93b13a16cf847b54ed357087c35011048cc7d" "checksum getopts 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)" = "14dbbfd5c71d70241ecf9e6f13737f7b5ce823821063188d7e46c41d371eebd5" "checksum getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "7abc8dd8451921606d809ba32e95b6111925cd2906060d2dcc29c070220503eb" @@ -735,9 +741,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum num-integer 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "3f6ea62e9d81a77cd3ee9a2a5b9b609447857f3d358704331e4ef39eb247fcba" "checksum num-traits 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "c62be47e61d1842b9170f0fdeec8eba98e60e90e5446449a0545e5152acd7096" "checksum ppv-lite86 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "74490b50b9fbe561ac330df47c08f3f33073d2d00c150f719147d7c54522fa1b" -"checksum proc-macro2 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)" = "3acb317c6ff86a4e579dfa00fc5e6cca91ecbb4e7eb2df0468805b674eb88548" +"checksum proc-macro2 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)" = "6c09721c6781493a2a492a96b5a5bf19b65917fe6728884e7c44dd0c60ca3435" "checksum quick-error 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" -"checksum quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe" +"checksum quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2bdc6c187c65bca4260c9011c9e3132efe4909da44726bad24cf7572ae338d7f" "checksum rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" "checksum rand_chacha 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "03a2a90da8c7523f554344f921aa97283eadf6ac484a6d2a7d0212fa7f8d6853" "checksum rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" @@ -745,13 +751,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)" = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84" "checksum redox_users 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "09b23093265f8d200fa7b4c2c76297f47e681c655f6f1285a8780d6a022f7431" "checksum regex 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "322cf97724bea3ee221b78fe25ac9c46114ebb51747ad5babd51a2fc6a8235a8" -"checksum regex-syntax 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)" = "b28dfe3fe9badec5dbf0a79a9cccad2cfc2ab5484bdb3e44cbd1ae8b3ba2be06" +"checksum regex-syntax 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)" = "1132f845907680735a84409c3bebc64d1364a5683ffbce899550cd09d5eaefc1" "checksum remove_dir_all 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4a83fa3702a688b9359eccba92d153ac33fd2e8462f9e0e3fdf155239ea7792e" "checksum rust-argon2 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2bc8af4bda8e1ff4932523b94d3dd20ee30a87232323eda55903ffd71d2fb017" "checksum rustc-demangle 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "4c691c0e608126e00913e33f0ccf3727d5fc84573623b8d65b2df340b5201783" "checksum rustc-workspace-hack 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc71d2faa173b74b232dedc235e3ee1696581bb132fc116fa3626d6151a1a8fb" "checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" -"checksum rustfix 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7150ac777a2931a53489f5a41eb0937b84e3092a20cd0e73ad436b65b507f607" +"checksum rustfix 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "804b11883a5ce0ad0378fbf95a8dea59ee6b51c331a73b8f471b6bdaa3bd40c1" "checksum ryu 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "bfa8506c1de11c9c4e4c38863ccbe02a305c8188e85a05a784c9e11e1c3910c8" "checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" "checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" @@ -760,7 +766,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum serde_json 1.0.48 (registry+https://github.com/rust-lang/crates.io-index)" = "9371ade75d4c2d6cb154141b9752cf3781ec9c05e0e5cf35060e1e70ee7b9c25" "checksum shell-escape 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "170a13e64f2a51b77a45702ba77287f5c6829375b04a69cf2222acd17d0cfab9" "checksum socket2 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)" = "e8b74de517221a2cb01a53349cf54182acdc31a074727d3079068448c0676d85" -"checksum syn 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)" = "7a0294dc449adc58bb6592fff1a23d3e5e6e235afc6a0ffca2657d19e7bbffe5" +"checksum syn 1.0.16 (registry+https://github.com/rust-lang/crates.io-index)" = "123bd9499cfb380418d509322d7a6d52e5315f064fe4b3ad18a53d6b92c07859" "checksum synstructure 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)" = "67656ea1dc1b41b1451851562ea232ec2e5a80242139f7e679ceccfb5d61f545" "checksum tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9" "checksum term 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c0863a3345e70f61d613eab32ee046ccd1bcc5f9105fe402c61fcd0c13eeb8b5" From 69260115acbf5007277e0202b64e588dc3808d70 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 8 Mar 2020 16:50:19 +0100 Subject: [PATCH 1634/3747] readme: mention the leaks we found --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 936da469f599c..3d7003af72e4e 100644 --- a/README.md +++ b/README.md @@ -240,6 +240,7 @@ Definite bugs found: * [`rand` performing unaligned reads](https://github.com/rust-random/rand/issues/779) * [The Unix allocator calling `posix_memalign` in an invalid way](https://github.com/rust-lang/rust/issues/62251) * [`getrandom` calling the `getrandom` syscall in an invalid way](https://github.com/rust-random/getrandom/pull/73) +* [`Vec`](https://github.com/rust-lang/rust/issues/69770) and [`BTreeMap`](https://github.com/rust-lang/rust/issues/69769) leaking memory under some (panicky) conditions Violations of [Stacked Borrows] found that are likely bugs (but Stacked Borrows is currently just an experiment): From 87dbf10e84c4545c90be11325107fa0f2876f1fd Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 8 Mar 2020 17:18:53 +0100 Subject: [PATCH 1635/3747] move environ init to update_environ --- src/shims/env.rs | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/shims/env.rs b/src/shims/env.rs index aaecbebc36032..b06db5676f3e9 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -30,11 +30,6 @@ impl EnvVars { } } } - // Initialize the `environ` static - let layout = ecx.layout_of(ecx.tcx.types.usize)?; - let place = ecx.allocate(layout, MiriMemoryKind::Machine.into()); - ecx.write_scalar(Scalar::from_machine_usize(0, &*ecx.tcx), place.into())?; - ecx.memory.extra.environ = Some(place); ecx.update_environ() } } @@ -160,17 +155,22 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } - /// Updates the `environ` static. It should not be called before - /// `EnvVars::init`. + /// Updates the `environ` static. + /// The first time it gets called, also initializes `extra.environ`. fn update_environ(&mut self) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - // Deallocate the old environ value. - let old_vars_ptr = this.read_scalar(this.memory.extra.environ.unwrap().into())?.not_undef()?; - // The pointer itself can be null because `EnvVars::init` only - // initializes the place for the static but not the static itself. - if !this.is_null(old_vars_ptr)? { + // Deallocate the old environ value, if any. + if let Some(environ) = this.memory.extra.environ { + let old_vars_ptr = this.read_scalar(environ.into())?.not_undef()?; this.memory.deallocate(this.force_ptr(old_vars_ptr)?, None, MiriMemoryKind::Machine.into())?; + } else { + // No `environ` allocated yet, let's do that. + let layout = this.layout_of(this.tcx.types.usize)?; + let place = this.allocate(layout, MiriMemoryKind::Machine.into()); + this.write_scalar(Scalar::from_machine_usize(0, &*this.tcx), place.into())?; + this.memory.extra.environ = Some(place); } + // Collect all the pointers to each variable in a vector. let mut vars: Vec> = this.machine.env_vars.map.values().map(|&ptr| ptr.into()).collect(); // Add the trailing null pointer. From 5dc60d974b0a76a1f4107790ea2249993d529e80 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Sun, 8 Mar 2020 11:54:47 -0500 Subject: [PATCH 1636/3747] move environ place to EnvVars --- src/machine.rs | 20 ++++++++------------ src/shims/env.rs | 15 +++++++++------ src/shims/foreign_items/posix/macos.rs | 2 +- 3 files changed, 18 insertions(+), 19 deletions(-) diff --git a/src/machine.rs b/src/machine.rs index d21ff32897573..f69606e48f52c 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -70,7 +70,7 @@ pub struct AllocExtra { /// Extra global memory data #[derive(Clone, Debug)] -pub struct MemoryExtra<'tcx> { +pub struct MemoryExtra { pub stacked_borrows: Option, pub intptrcast: intptrcast::MemoryExtra, @@ -84,12 +84,9 @@ pub struct MemoryExtra<'tcx> { /// An allocation ID to report when it is being allocated /// (helps for debugging memory leaks). tracked_alloc_id: Option, - - /// Place where the `environ` static is stored. Lazily initialized, but then never changes. - pub(crate) environ: Option>, } -impl<'tcx> MemoryExtra<'tcx> { +impl MemoryExtra { pub fn new(rng: StdRng, stacked_borrows: bool, tracked_pointer_tag: Option, tracked_alloc_id: Option) -> Self { let stacked_borrows = if stacked_borrows { Some(Rc::new(RefCell::new(stacked_borrows::GlobalState::new(tracked_pointer_tag)))) @@ -102,12 +99,11 @@ impl<'tcx> MemoryExtra<'tcx> { extern_statics: FxHashMap::default(), rng: RefCell::new(rng), tracked_alloc_id, - environ: None, } } /// Sets up the "extern statics" for this machine. - pub fn init_extern_statics<'mir>( + pub fn init_extern_statics<'tcx, 'mir>( this: &mut MiriEvalContext<'mir, 'tcx>, ) -> InterpResult<'tcx> { let target_os = this.tcx.sess.target.target.target_os.as_str(); @@ -127,7 +123,7 @@ impl<'tcx> MemoryExtra<'tcx> { this.memory .extra .extern_statics - .insert(Symbol::intern("environ"), this.memory.extra.environ.unwrap().ptr.assert_ptr().alloc_id) + .insert(Symbol::intern("environ"), this.machine.env_vars.environ.unwrap().ptr.assert_ptr().alloc_id) .unwrap_none(); } _ => {} // No "extern statics" supported on this platform @@ -140,7 +136,7 @@ impl<'tcx> MemoryExtra<'tcx> { pub struct Evaluator<'tcx> { /// Environment variables set by `setenv`. /// Miri does not expose env vars from the host to the emulated program. - pub(crate) env_vars: EnvVars, + pub(crate) env_vars: EnvVars<'tcx>, /// Program arguments (`Option` because we can only initialize them after creating the ecx). /// These are *pointers* to argc/argv because macOS. @@ -214,7 +210,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { type MemoryKinds = MiriMemoryKind; type FrameExtra = FrameData<'tcx>; - type MemoryExtra = MemoryExtra<'tcx>; + type MemoryExtra = MemoryExtra; type AllocExtra = AllocExtra; type PointerTag = Tag; type ExtraFnVal = Dlsym; @@ -340,7 +336,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { } fn init_allocation_extra<'b>( - memory_extra: &MemoryExtra<'tcx>, + memory_extra: &MemoryExtra, id: AllocId, alloc: Cow<'b, Allocation>, kind: Option>, @@ -377,7 +373,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { } #[inline(always)] - fn tag_static_base_pointer(memory_extra: &MemoryExtra<'tcx>, id: AllocId) -> Self::PointerTag { + fn tag_static_base_pointer(memory_extra: &MemoryExtra, id: AllocId) -> Self::PointerTag { if let Some(stacked_borrows) = memory_extra.stacked_borrows.as_ref() { stacked_borrows.borrow_mut().static_base_ptr(id) } else { diff --git a/src/shims/env.rs b/src/shims/env.rs index b06db5676f3e9..7c6b6c942e5e3 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -10,14 +10,17 @@ use rustc::ty::layout::Size; use rustc_mir::interpret::Pointer; #[derive(Default)] -pub struct EnvVars { +pub struct EnvVars<'tcx> { /// Stores pointers to the environment variables. These variables must be stored as /// null-terminated C strings with the `"{name}={value}"` format. map: FxHashMap>, + + /// Place where the `environ` static is stored. Lazily initialized, but then never changes. + pub(crate) environ: Option>, } -impl EnvVars { - pub(crate) fn init<'mir, 'tcx>( +impl<'tcx> EnvVars<'tcx> { + pub(crate) fn init<'mir>( ecx: &mut InterpCx<'mir, 'tcx, Evaluator<'tcx>>, excluded_env_vars: Vec, ) -> InterpResult<'tcx> { @@ -160,7 +163,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn update_environ(&mut self) -> InterpResult<'tcx> { let this = self.eval_context_mut(); // Deallocate the old environ value, if any. - if let Some(environ) = this.memory.extra.environ { + if let Some(environ) = this.machine.env_vars.environ { let old_vars_ptr = this.read_scalar(environ.into())?.not_undef()?; this.memory.deallocate(this.force_ptr(old_vars_ptr)?, None, MiriMemoryKind::Machine.into())?; } else { @@ -168,7 +171,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let layout = this.layout_of(this.tcx.types.usize)?; let place = this.allocate(layout, MiriMemoryKind::Machine.into()); this.write_scalar(Scalar::from_machine_usize(0, &*this.tcx), place.into())?; - this.memory.extra.environ = Some(place); + this.machine.env_vars.environ = Some(place); } // Collect all the pointers to each variable in a vector. @@ -186,7 +189,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } this.write_scalar( vars_place.ptr, - this.memory.extra.environ.unwrap().into(), + this.machine.env_vars.environ.unwrap().into(), )?; Ok(()) diff --git a/src/shims/foreign_items/posix/macos.rs b/src/shims/foreign_items/posix/macos.rs index c5c6423e8501e..0d067cc04138a 100644 --- a/src/shims/foreign_items/posix/macos.rs +++ b/src/shims/foreign_items/posix/macos.rs @@ -58,7 +58,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Environment related shims "_NSGetEnviron" => { - this.write_scalar(this.memory.extra.environ.unwrap().ptr, dest)?; + this.write_scalar(this.machine.env_vars.environ.unwrap().ptr, dest)?; } // Time related shims From 83944562476ad783f8cace5d94af3490a41a256b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 8 Mar 2020 20:00:40 +0100 Subject: [PATCH 1637/3747] properly panic in panic_if_uninhabited and align_offset shims --- src/shims/intrinsics.rs | 4 +- src/shims/mod.rs | 34 +++++------ src/shims/panic.rs | 37 +++++++----- tests/run-pass/panic/catch_panic.rs | 58 +++++++++++++------ tests/run-pass/panic/catch_panic.stderr | 26 +++++---- tests/run-pass/{panic => }/transmute_fat2.rs | 0 .../{panic => }/transmute_fat2.stderr | 0 7 files changed, 97 insertions(+), 62 deletions(-) rename tests/run-pass/{panic => }/transmute_fat2.rs (100%) rename tests/run-pass/{panic => }/transmute_fat2.stderr (100%) diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 9cae97a4060cf..05047a6040c10 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -448,8 +448,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let ty = substs.type_at(0); let layout = this.layout_of(ty)?; if layout.abi.is_uninhabited() { - // FIXME: This should throw a panic in the interpreted program instead. - throw_unsup_format!("Trying to instantiate uninhabited type {}", ty) + // Return here because we paniced instead of returning normally from the intrinsic. + return this.start_panic(&format!("Attempted to instantiate uninhabited type {}", ty), unwind); } } diff --git a/src/shims/mod.rs b/src/shims/mod.rs index 04379553587da..6adf013858550 100644 --- a/src/shims/mod.rs +++ b/src/shims/mod.rs @@ -24,12 +24,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // There are some more lang items we want to hook that CTFE does not hook (yet). if this.tcx.lang_items().align_offset_fn() == Some(instance.def.def_id()) { - let (dest, ret) = ret.unwrap(); - let n = this - .align_offset(args[0], args[1])? - .unwrap_or_else(|| this.truncate(u128::MAX, dest.layout)); - this.write_scalar(Scalar::from_uint(n, dest.layout.size), dest)?; - this.go_to_block(ret); + this.align_offset(args[0], args[1], ret, unwind)?; return Ok(None); } @@ -52,35 +47,40 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx &mut self, ptr_op: OpTy<'tcx, Tag>, align_op: OpTy<'tcx, Tag>, - ) -> InterpResult<'tcx, Option> { + ret: Option<(PlaceTy<'tcx, Tag>, mir::BasicBlock)>, + unwind: Option, + ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); + let (dest, ret) = ret.unwrap(); let req_align = this .force_bits(this.read_scalar(align_op)?.not_undef()?, this.pointer_size())? as usize; - // FIXME: This should actually panic in the interpreted program + // Stop if the alignment is not a power of two. if !req_align.is_power_of_two() { - throw_unsup_format!("Required alignment should always be a power of two") + return this.start_panic("align_offset: align is not a power-of-two", unwind); } let ptr_scalar = this.read_scalar(ptr_op)?.not_undef()?; + // Default: no result. + let mut result = this.truncate(u128::MAX, dest.layout); if let Ok(ptr) = this.force_ptr(ptr_scalar) { + // Only do anything if we can identify the allocation this goes to. let cur_align = this.memory.get_size_and_align(ptr.alloc_id, AllocCheck::MaybeDead)?.1.bytes() as usize; if cur_align >= req_align { - // if the allocation alignment is at least the required alignment we use the + // If the allocation alignment is at least the required alignment we use the // libcore implementation - return Ok(Some( - (this.force_bits(ptr_scalar, this.pointer_size())? as *const i8) - .align_offset(req_align) as u128, - )); + result = (this.force_bits(ptr_scalar, this.pointer_size())? as *const i8).align_offset(req_align) as u128; } } - // If the allocation alignment is smaller than then required alignment or the pointer was - // actually an integer, we return `None` - Ok(None) + + // Return result, and jump to caller. + this.write_scalar(Scalar::from_uint(result, dest.layout.size), dest)?; + this.go_to_block(ret); + Ok(()) } } diff --git a/src/shims/panic.rs b/src/shims/panic.rs index 11c5a882be9b2..2968bd9b58d8c 100644 --- a/src/shims/panic.rs +++ b/src/shims/panic.rs @@ -152,6 +152,28 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(res) } + /// Starta a panic in the interpreter with the given message as payload. + fn start_panic( + &mut self, + msg: &str, + unwind: Option, + ) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + + // First arg: message. + let msg = this.allocate_str(msg, MiriMemoryKind::Machine.into()); + + // Call the lang item. + let panic = this.tcx.lang_items().panic_fn().unwrap(); + let panic = ty::Instance::mono(this.tcx.tcx, panic); + this.call_function( + panic, + &[msg.to_ref()], + None, + StackPopCleanup::Goto { ret: None, unwind }, + ) + } + fn assert_panic( &mut self, span: Span, @@ -184,20 +206,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } _ => { // Forward everything else to `panic` lang item. - - // First arg: Message. - let msg = msg.description(); - let msg = this.allocate_str(msg, MiriMemoryKind::Machine.into()); - - // Call the lang item. - let panic = this.tcx.lang_items().panic_fn().unwrap(); - let panic = ty::Instance::mono(this.tcx.tcx, panic); - this.call_function( - panic, - &[msg.to_ref()], - None, - StackPopCleanup::Goto { ret: None, unwind }, - )?; + this.start_panic(msg.description(), unwind)?; } } Ok(()) diff --git a/tests/run-pass/panic/catch_panic.rs b/tests/run-pass/panic/catch_panic.rs index 21a6fee7c9211..33c2beb682ae9 100644 --- a/tests/run-pass/panic/catch_panic.rs +++ b/tests/run-pass/panic/catch_panic.rs @@ -1,5 +1,5 @@ // ignore-windows: Unwind panicking does not currently work on Windows -// normalize-stderr-test "[^ ]*libcore/macros/mod.rs[0-9:]*" -> "$$LOC" +// normalize-stderr-test "[^ ]*libcore/(macros|mem)/mod.rs[0-9:]*" -> "$$LOC" #![feature(never_type)] #![allow(unconditional_panic)] use std::panic::{catch_unwind, AssertUnwindSafe}; @@ -47,24 +47,41 @@ fn main() { })); // Std panics - test(|_old_val| std::panic!("Hello from panic: std")); - test(|old_val| std::panic!(format!("Hello from panic: {:?}", old_val))); - test(|old_val| std::panic!("Hello from panic: {:?}", old_val)); - test(|_old_val| std::panic!(1337)); + test(None, |_old_val| std::panic!("Hello from panic: std")); + test(None, |old_val| std::panic!(format!("Hello from panic: {:?}", old_val))); + test(None, |old_val| std::panic!("Hello from panic: {:?}", old_val)); + test(None, |_old_val| std::panic!(1337)); // Core panics - test(|_old_val| core::panic!("Hello from panic: core")); - test(|old_val| core::panic!(&format!("Hello from panic: {:?}", old_val))); - test(|old_val| core::panic!("Hello from panic: {:?}", old_val)); - - // Built-in panics - test(|_old_val| { let _val = [0, 1, 2][4]; loop {} }); - test(|_old_val| { let _val = 1/0; loop {} }); + test(None, |_old_val| core::panic!("Hello from panic: core")); + test(None, |old_val| core::panic!(&format!("Hello from panic: {:?}", old_val))); + test(None, |old_val| core::panic!("Hello from panic: {:?}", old_val)); + + // Built-in panics; also make sure the message is right. + test( + Some("index out of bounds: the len is 3 but the index is 4"), + |_old_val| { let _val = [0, 1, 2][4]; loop {} }, + ); + test( + Some("attempt to divide by zero"), + |_old_val| { let _val = 1/0; loop {} }, + ); + + // libcore panics from shims. + #[allow(deprecated, invalid_value)] + test( + Some("Attempted to instantiate uninhabited type !"), + |_old_val| unsafe { std::mem::uninitialized::() }, + ); + test( + Some("align_offset: align is not a power-of-two"), + |_old_val| { (0usize as *const u8).align_offset(3); loop {} }, + ); // Assertion and debug assertion - test(|_old_val| { assert!(false); loop {} }); - test(|_old_val| { debug_assert!(false); loop {} }); - test(|_old_val| { unsafe { (1 as *const i32).read() }; loop {} }); // trigger debug-assertion in libstd + test(None, |_old_val| { assert!(false); loop {} }); + test(None, |_old_val| { debug_assert!(false); loop {} }); + test(None, |_old_val| { unsafe { (1 as *const i32).read() }; loop {} }); // trigger debug-assertion in libstd // Cleanup: reset to default hook. drop(std::panic::take_hook()); @@ -72,7 +89,7 @@ fn main() { eprintln!("Success!"); // Make sure we get this in stderr } -fn test(do_panic: impl FnOnce(usize) -> !) { +fn test(expect_msg: Option<&str>, do_panic: impl FnOnce(usize) -> !) { // Reset test flags. DROPPED.with(|c| c.set(false)); HOOK_CALLED.with(|c| c.set(false)); @@ -84,16 +101,21 @@ fn test(do_panic: impl FnOnce(usize) -> !) { })).expect_err("do_panic() did not panic!"); // See if we can extract the panic message. - if let Some(s) = res.downcast_ref::() { + let msg = if let Some(s) = res.downcast_ref::() { eprintln!("Caught panic message (String): {}", s); + Some(s.as_str()) } else if let Some(s) = res.downcast_ref::<&str>() { eprintln!("Caught panic message (&str): {}", s); + Some(*s) } else { eprintln!("Failed get caught panic message."); + None + }; + if let Some(expect_msg) = expect_msg { + assert_eq!(expect_msg, msg.unwrap()); } // Test flags. assert!(DROPPED.with(|c| c.get())); assert!(HOOK_CALLED.with(|c| c.get())); } - diff --git a/tests/run-pass/panic/catch_panic.stderr b/tests/run-pass/panic/catch_panic.stderr index 636179beeade8..4ff22fe2176a4 100644 --- a/tests/run-pass/panic/catch_panic.stderr +++ b/tests/run-pass/panic/catch_panic.stderr @@ -1,24 +1,28 @@ -thread 'main' panicked at 'Hello from panic: std', $DIR/catch_panic.rs:50:21 +thread 'main' panicked at 'Hello from panic: std', $DIR/catch_panic.rs:50:27 Caught panic message (&str): Hello from panic: std -thread 'main' panicked at 'Hello from panic: 1', $DIR/catch_panic.rs:51:20 +thread 'main' panicked at 'Hello from panic: 1', $DIR/catch_panic.rs:51:26 Caught panic message (String): Hello from panic: 1 -thread 'main' panicked at 'Hello from panic: 2', $DIR/catch_panic.rs:52:20 +thread 'main' panicked at 'Hello from panic: 2', $DIR/catch_panic.rs:52:26 Caught panic message (String): Hello from panic: 2 -thread 'main' panicked at 'Box', $DIR/catch_panic.rs:53:21 +thread 'main' panicked at 'Box', $DIR/catch_panic.rs:53:27 Failed get caught panic message. -thread 'main' panicked at 'Hello from panic: core', $DIR/catch_panic.rs:56:21 +thread 'main' panicked at 'Hello from panic: core', $DIR/catch_panic.rs:56:27 Caught panic message (String): Hello from panic: core -thread 'main' panicked at 'Hello from panic: 5', $DIR/catch_panic.rs:57:20 +thread 'main' panicked at 'Hello from panic: 5', $DIR/catch_panic.rs:57:26 Caught panic message (String): Hello from panic: 5 -thread 'main' panicked at 'Hello from panic: 6', $DIR/catch_panic.rs:58:20 +thread 'main' panicked at 'Hello from panic: 6', $DIR/catch_panic.rs:58:26 Caught panic message (String): Hello from panic: 6 -thread 'main' panicked at 'index out of bounds: the len is 3 but the index is 4', $DIR/catch_panic.rs:61:34 +thread 'main' panicked at 'index out of bounds: the len is 3 but the index is 4', $DIR/catch_panic.rs:63:33 Caught panic message (String): index out of bounds: the len is 3 but the index is 4 -thread 'main' panicked at 'attempt to divide by zero', $DIR/catch_panic.rs:62:34 +thread 'main' panicked at 'attempt to divide by zero', $DIR/catch_panic.rs:67:33 Caught panic message (String): attempt to divide by zero -thread 'main' panicked at 'assertion failed: false', $DIR/catch_panic.rs:65:23 +thread 'main' panicked at 'Attempted to instantiate uninhabited type !', $LOC +Caught panic message (String): Attempted to instantiate uninhabited type ! +thread 'main' panicked at 'align_offset: align is not a power-of-two', $LOC +Caught panic message (String): align_offset: align is not a power-of-two +thread 'main' panicked at 'assertion failed: false', $DIR/catch_panic.rs:82:29 Caught panic message (&str): assertion failed: false -thread 'main' panicked at 'assertion failed: false', $DIR/catch_panic.rs:66:23 +thread 'main' panicked at 'assertion failed: false', $DIR/catch_panic.rs:83:29 Caught panic message (&str): assertion failed: false thread 'main' panicked at 'attempt to copy from unaligned or null pointer', $LOC Caught panic message (String): attempt to copy from unaligned or null pointer diff --git a/tests/run-pass/panic/transmute_fat2.rs b/tests/run-pass/transmute_fat2.rs similarity index 100% rename from tests/run-pass/panic/transmute_fat2.rs rename to tests/run-pass/transmute_fat2.rs diff --git a/tests/run-pass/panic/transmute_fat2.stderr b/tests/run-pass/transmute_fat2.stderr similarity index 100% rename from tests/run-pass/panic/transmute_fat2.stderr rename to tests/run-pass/transmute_fat2.stderr From 5ef48593fb27af0194b082f7d5d9960b0d5f6320 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 4 Mar 2020 23:16:24 +0100 Subject: [PATCH 1638/3747] adjust error --- tests/compile-fail/slice-too-big.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/compile-fail/slice-too-big.rs b/tests/compile-fail/slice-too-big.rs index 157ea03bc932a..6a4c18249ee7d 100644 --- a/tests/compile-fail/slice-too-big.rs +++ b/tests/compile-fail/slice-too-big.rs @@ -2,5 +2,5 @@ use std::mem; fn main() { unsafe { let ptr = Box::into_raw(Box::new(0u8)); - let _x: &[u8] = mem::transmute((ptr, usize::MAX)); //~ ERROR: invalid slice: total size is bigger than largest supported object + let _x: &[u8] = mem::transmute((ptr, usize::MAX)); //~ ERROR: invalid reference metadata: slice is bigger than largest supported object } } From 5040cb7f81277ef6232f0f2548923b9b19fd5725 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 9 Mar 2020 17:03:45 +0100 Subject: [PATCH 1639/3747] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 62e7b6845d518..f8f856bff76ff 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -7a3700c37132385e8e965c18e73d0a09f9146335 +3dbade652ed8ebac70f903e01f51cd92c4e4302c From 881e65c01bfa5e483aa7deed3aee9771d672f231 Mon Sep 17 00:00:00 2001 From: Elichai Turkel Date: Wed, 11 Mar 2020 14:58:27 +0200 Subject: [PATCH 1640/3747] bump rust-version to latest --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index f8f856bff76ff..fb138448f9f4b 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -3dbade652ed8ebac70f903e01f51cd92c4e4302c +303d8aff6092709edd4dbd35b1c88e9aa40bf6d8 From e81ebffa59929574c8ac8fa380e27eb9e612cff9 Mon Sep 17 00:00:00 2001 From: Elichai Turkel Date: Wed, 11 Mar 2020 15:39:37 +0200 Subject: [PATCH 1641/3747] Implement panic_if_any_invalid and panic_if_zero_invalid intrinsics --- src/shims/intrinsics.rs | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 05047a6040c10..d0305c0e9fbdd 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -449,7 +449,32 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let layout = this.layout_of(ty)?; if layout.abi.is_uninhabited() { // Return here because we paniced instead of returning normally from the intrinsic. - return this.start_panic(&format!("Attempted to instantiate uninhabited type {}", ty), unwind); + return this.start_panic(&format!("attempted to instantiate uninhabited type {}", ty), unwind); + } + } + + "panic_if_zero_invalid" => { + let ty = substs.type_at(0); + let layout = this.layout_of(ty)?; + // Check if it permits zeroed raw initialization + if !layout.might_permit_raw_init(this, /*zero:*/ true).unwrap() { + // Return here because we paniced instead of returning normally from the intrinsic. + return this.start_panic(&format!("attempted to zero-initialize type `{}`, which is invalid", ty), unwind); + } + } + + "panic_if_any_invalid" => { + let ty = substs.type_at(0); + let layout = this.layout_of(ty)?; + // rustc handles all these in a single function, but we don't so we need to make sure `mem::uninitialized::()` returns the right error. + // So we check for `is_uninhabited` here too. + if layout.abi.is_uninhabited() { + return this.start_panic(&format!("attempted to instantiate uninhabited type {}", ty), unwind); + } + // Check if it permits any raw initialization + if !layout.might_permit_raw_init(this, /*zero:*/ false).unwrap() { + // Return here because we paniced instead of returning normally from the intrinsic. + return this.start_panic(&format!("attempted to leave type `{}` uninitialized, which is invalid", ty), unwind); } } From 2802c3cf0b91e18de1f37e24929a406033df0cc0 Mon Sep 17 00:00:00 2001 From: Elichai Turkel Date: Wed, 11 Mar 2020 16:02:49 +0200 Subject: [PATCH 1642/3747] Add tests for the new panic_if_any_invalid, panic_if_zero_invalid intrinsics --- tests/run-pass/panic/catch_panic.rs | 39 ++++++++++++++++++++++--- tests/run-pass/panic/catch_panic.stderr | 22 +++++++++++--- 2 files changed, 53 insertions(+), 8 deletions(-) diff --git a/tests/run-pass/panic/catch_panic.rs b/tests/run-pass/panic/catch_panic.rs index 33c2beb682ae9..a406fd434a054 100644 --- a/tests/run-pass/panic/catch_panic.rs +++ b/tests/run-pass/panic/catch_panic.rs @@ -69,10 +69,41 @@ fn main() { // libcore panics from shims. #[allow(deprecated, invalid_value)] - test( - Some("Attempted to instantiate uninhabited type !"), - |_old_val| unsafe { std::mem::uninitialized::() }, - ); + { + test( + Some("attempted to instantiate uninhabited type !"), + |_old_val| unsafe { std::mem::uninitialized::() }, + ); + test( + Some("attempted to zero-initialize type `!`, which is invalid"), + |_old_val| unsafe { std::mem::zeroed::() }, + ); + test( + Some("attempted to leave type `fn()` uninitialized, which is invalid"), + |_old_val| unsafe { std::mem::uninitialized::(); loop {} }, + ); + test( + Some("attempted to zero-initialize type `fn()`, which is invalid"), + |_old_val| unsafe { std::mem::zeroed::(); loop {} }, + ); + test( + Some("attempted to leave type `*const dyn std::marker::Sync` uninitialized, which is invalid"), + |_old_val| unsafe { std::mem::uninitialized::<*const dyn Sync>(); loop {} }, + ); + test( + Some("attempted to zero-initialize type `*mut dyn std::marker::Sync`, which is invalid"), + |_old_val| unsafe { std::mem::zeroed::<*mut dyn Sync>(); loop {} }, + ); + test( + Some("attempted to leave type `&u8` uninitialized, which is invalid"), + |_old_val| unsafe { std::mem::uninitialized::<&u8>(); loop {} }, + ); + test( + Some("attempted to zero-initialize type `&u8`, which is invalid"), + |_old_val| unsafe { std::mem::zeroed::<&u8>(); loop {} }, + ); + } + test( Some("align_offset: align is not a power-of-two"), |_old_val| { (0usize as *const u8).align_offset(3); loop {} }, diff --git a/tests/run-pass/panic/catch_panic.stderr b/tests/run-pass/panic/catch_panic.stderr index 4ff22fe2176a4..1899ea3c684a7 100644 --- a/tests/run-pass/panic/catch_panic.stderr +++ b/tests/run-pass/panic/catch_panic.stderr @@ -16,13 +16,27 @@ thread 'main' panicked at 'index out of bounds: the len is 3 but the index is 4' Caught panic message (String): index out of bounds: the len is 3 but the index is 4 thread 'main' panicked at 'attempt to divide by zero', $DIR/catch_panic.rs:67:33 Caught panic message (String): attempt to divide by zero -thread 'main' panicked at 'Attempted to instantiate uninhabited type !', $LOC -Caught panic message (String): Attempted to instantiate uninhabited type ! +thread 'main' panicked at 'attempted to instantiate uninhabited type !', $LOC +Caught panic message (String): attempted to instantiate uninhabited type ! +thread 'main' panicked at 'attempted to zero-initialize type `!`, which is invalid', $LOC +Caught panic message (String): attempted to zero-initialize type `!`, which is invalid +thread 'main' panicked at 'attempted to leave type `fn()` uninitialized, which is invalid', $LOC +Caught panic message (String): attempted to leave type `fn()` uninitialized, which is invalid +thread 'main' panicked at 'attempted to zero-initialize type `fn()`, which is invalid', $LOC +Caught panic message (String): attempted to zero-initialize type `fn()`, which is invalid +thread 'main' panicked at 'attempted to leave type `*const dyn std::marker::Sync` uninitialized, which is invalid', $LOC +Caught panic message (String): attempted to leave type `*const dyn std::marker::Sync` uninitialized, which is invalid +thread 'main' panicked at 'attempted to zero-initialize type `*mut dyn std::marker::Sync`, which is invalid', $LOC +Caught panic message (String): attempted to zero-initialize type `*mut dyn std::marker::Sync`, which is invalid +thread 'main' panicked at 'attempted to leave type `&u8` uninitialized, which is invalid', $LOC +Caught panic message (String): attempted to leave type `&u8` uninitialized, which is invalid +thread 'main' panicked at 'attempted to zero-initialize type `&u8`, which is invalid', $LOC +Caught panic message (String): attempted to zero-initialize type `&u8`, which is invalid thread 'main' panicked at 'align_offset: align is not a power-of-two', $LOC Caught panic message (String): align_offset: align is not a power-of-two -thread 'main' panicked at 'assertion failed: false', $DIR/catch_panic.rs:82:29 +thread 'main' panicked at 'assertion failed: false', $DIR/catch_panic.rs:113:29 Caught panic message (&str): assertion failed: false -thread 'main' panicked at 'assertion failed: false', $DIR/catch_panic.rs:83:29 +thread 'main' panicked at 'assertion failed: false', $DIR/catch_panic.rs:114:29 Caught panic message (&str): assertion failed: false thread 'main' panicked at 'attempt to copy from unaligned or null pointer', $LOC Caught panic message (String): attempt to copy from unaligned or null pointer From 548c90e102fe46a8348bbf7cb06c92782c66a02a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 11 Mar 2020 19:52:39 +0100 Subject: [PATCH 1643/3747] share some code between panic intrinsics, and fix the message --- src/shims/intrinsics.rs | 27 ++++++------------------- tests/run-pass/panic/catch_panic.rs | 4 ++-- tests/run-pass/panic/catch_panic.stderr | 8 ++++---- 3 files changed, 12 insertions(+), 27 deletions(-) diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index d0305c0e9fbdd..fbb0a654294f2 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -444,35 +444,20 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(result_ptr, dest)?; } - "panic_if_uninhabited" => { + "panic_if_uninhabited" | + "panic_if_zero_invalid" | + "panic_if_any_invalid" => { let ty = substs.type_at(0); let layout = this.layout_of(ty)?; if layout.abi.is_uninhabited() { // Return here because we paniced instead of returning normally from the intrinsic. - return this.start_panic(&format!("attempted to instantiate uninhabited type {}", ty), unwind); + return this.start_panic(&format!("attempted to instantiate uninhabited type `{}`", ty), unwind); } - } - - "panic_if_zero_invalid" => { - let ty = substs.type_at(0); - let layout = this.layout_of(ty)?; - // Check if it permits zeroed raw initialization - if !layout.might_permit_raw_init(this, /*zero:*/ true).unwrap() { + if intrinsic_name == "panic_if_zero_invalid" && !layout.might_permit_raw_init(this, /*zero:*/ true).unwrap() { // Return here because we paniced instead of returning normally from the intrinsic. return this.start_panic(&format!("attempted to zero-initialize type `{}`, which is invalid", ty), unwind); } - } - - "panic_if_any_invalid" => { - let ty = substs.type_at(0); - let layout = this.layout_of(ty)?; - // rustc handles all these in a single function, but we don't so we need to make sure `mem::uninitialized::()` returns the right error. - // So we check for `is_uninhabited` here too. - if layout.abi.is_uninhabited() { - return this.start_panic(&format!("attempted to instantiate uninhabited type {}", ty), unwind); - } - // Check if it permits any raw initialization - if !layout.might_permit_raw_init(this, /*zero:*/ false).unwrap() { + if intrinsic_name == "panic_if_any_invalid" && !layout.might_permit_raw_init(this, /*zero:*/ false).unwrap() { // Return here because we paniced instead of returning normally from the intrinsic. return this.start_panic(&format!("attempted to leave type `{}` uninitialized, which is invalid", ty), unwind); } diff --git a/tests/run-pass/panic/catch_panic.rs b/tests/run-pass/panic/catch_panic.rs index a406fd434a054..cc97ba5a85d29 100644 --- a/tests/run-pass/panic/catch_panic.rs +++ b/tests/run-pass/panic/catch_panic.rs @@ -71,11 +71,11 @@ fn main() { #[allow(deprecated, invalid_value)] { test( - Some("attempted to instantiate uninhabited type !"), + Some("attempted to instantiate uninhabited type `!`"), |_old_val| unsafe { std::mem::uninitialized::() }, ); test( - Some("attempted to zero-initialize type `!`, which is invalid"), + Some("attempted to instantiate uninhabited type `!`"), |_old_val| unsafe { std::mem::zeroed::() }, ); test( diff --git a/tests/run-pass/panic/catch_panic.stderr b/tests/run-pass/panic/catch_panic.stderr index 1899ea3c684a7..8d97fd6321f18 100644 --- a/tests/run-pass/panic/catch_panic.stderr +++ b/tests/run-pass/panic/catch_panic.stderr @@ -16,10 +16,10 @@ thread 'main' panicked at 'index out of bounds: the len is 3 but the index is 4' Caught panic message (String): index out of bounds: the len is 3 but the index is 4 thread 'main' panicked at 'attempt to divide by zero', $DIR/catch_panic.rs:67:33 Caught panic message (String): attempt to divide by zero -thread 'main' panicked at 'attempted to instantiate uninhabited type !', $LOC -Caught panic message (String): attempted to instantiate uninhabited type ! -thread 'main' panicked at 'attempted to zero-initialize type `!`, which is invalid', $LOC -Caught panic message (String): attempted to zero-initialize type `!`, which is invalid +thread 'main' panicked at 'attempted to instantiate uninhabited type `!`', $LOC +Caught panic message (String): attempted to instantiate uninhabited type `!` +thread 'main' panicked at 'attempted to instantiate uninhabited type `!`', $LOC +Caught panic message (String): attempted to instantiate uninhabited type `!` thread 'main' panicked at 'attempted to leave type `fn()` uninitialized, which is invalid', $LOC Caught panic message (String): attempted to leave type `fn()` uninitialized, which is invalid thread 'main' panicked at 'attempted to zero-initialize type `fn()`, which is invalid', $LOC From 45d5a37787accac8bd4276ea47872a561069109c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 11 Mar 2020 20:05:44 +0100 Subject: [PATCH 1644/3747] rustup+fix --- rust-version | 2 +- src/machine.rs | 3 +-- src/shims/panic.rs | 10 +++------- 3 files changed, 5 insertions(+), 10 deletions(-) diff --git a/rust-version b/rust-version index fb138448f9f4b..66d096c0a02b0 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -303d8aff6092709edd4dbd35b1c88e9aa40bf6d8 +c20d7eecbc0928b57da8fe30b2ef8528e2bdd5be diff --git a/src/machine.rs b/src/machine.rs index f69606e48f52c..bd5884786c0e0 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -265,11 +265,10 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { #[inline(always)] fn assert_panic( ecx: &mut InterpCx<'mir, 'tcx, Self>, - span: Span, msg: &mir::AssertMessage<'tcx>, unwind: Option, ) -> InterpResult<'tcx> { - ecx.assert_panic(span, msg, unwind) + ecx.assert_panic(msg, unwind) } #[inline(always)] diff --git a/src/shims/panic.rs b/src/shims/panic.rs index 2968bd9b58d8c..d6f563deb0f93 100644 --- a/src/shims/panic.rs +++ b/src/shims/panic.rs @@ -14,7 +14,6 @@ use rustc::mir; use rustc::ty::{self, layout::LayoutOf}; use rustc_target::spec::PanicStrategy; -use rustc_span::source_map::Span; use crate::*; @@ -176,7 +175,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn assert_panic( &mut self, - span: Span, msg: &mir::AssertMessage<'tcx>, unwind: Option, ) -> InterpResult<'tcx> { @@ -187,11 +185,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx BoundsCheck { ref index, ref len } => { // Forward to `panic_bounds_check` lang item. - // First arg: Caller location. - let location = this.alloc_caller_location_for_span(span); - // Second arg: index. + // First arg: index. let index = this.read_scalar(this.eval_operand(index, None)?)?; - // Third arg: len. + // Second arg: len. let len = this.read_scalar(this.eval_operand(len, None)?)?; // Call the lang item. @@ -199,7 +195,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let panic_bounds_check = ty::Instance::mono(this.tcx.tcx, panic_bounds_check); this.call_function( panic_bounds_check, - &[location.ptr.into(), index.into(), len.into()], + &[index.into(), len.into()], None, StackPopCleanup::Goto { ret: None, unwind }, )?; From 76ee8ff4589b5085c68c5efbebd8d3fb07b8a00d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 11 Mar 2020 20:21:44 +0100 Subject: [PATCH 1645/3747] use ctfe_backtracte variable for backtrace control --- src/bin/miri.rs | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/src/bin/miri.rs b/src/bin/miri.rs index d2709643237f1..e40bfcf6276ad 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -7,13 +7,10 @@ extern crate log; extern crate log_settings; extern crate miri; extern crate rustc; -extern crate rustc_codegen_utils; extern crate rustc_driver; -extern crate rustc_errors; extern crate rustc_hir; extern crate rustc_interface; -extern crate rustc_metadata; -extern crate rustc_span; +extern crate rustc_session; use std::convert::TryFrom; use std::env; @@ -21,9 +18,11 @@ use std::str::FromStr; use hex::FromHexError; +use rustc_session::CtfeBacktrace; use rustc_driver::Compilation; use rustc_hir::def_id::LOCAL_CRATE; use rustc_interface::{interface, Queries}; +use rustc::ty::TyCtxt; struct MiriCompilerCalls { miri_config: miri::MiriConfig, @@ -35,10 +34,10 @@ impl rustc_driver::Callbacks for MiriCompilerCalls { compiler: &interface::Compiler, queries: &'tcx Queries<'tcx>, ) -> Compilation { - init_late_loggers(); compiler.session().abort_if_errors(); queries.global_ctxt().unwrap().peek_mut().enter(|tcx| { + init_late_loggers(tcx); let (entry_def_id, _) = tcx.entry_fn(LOCAL_CRATE).expect("no main function found!"); let mut config = self.miri_config.clone(); @@ -72,7 +71,7 @@ fn init_early_loggers() { } } -fn init_late_loggers() { +fn init_late_loggers(tcx: TyCtxt<'_>) { // We initialize loggers right before we start evaluation. We overwrite the `RUSTC_LOG` // env var if it is not set, control it based on `MIRI_LOG`. if let Ok(var) = env::var("MIRI_LOG") { @@ -96,10 +95,13 @@ fn init_late_loggers() { // If `MIRI_BACKTRACE` is set and `RUSTC_CTFE_BACKTRACE` is not, set `RUSTC_CTFE_BACKTRACE`. // Do this late, so we ideally only apply this to Miri's errors. - if let Ok(var) = env::var("MIRI_BACKTRACE") { - if env::var("RUSTC_CTFE_BACKTRACE") == Err(env::VarError::NotPresent) { - env::set_var("RUSTC_CTFE_BACKTRACE", &var); - } + if let Ok(val) = env::var("MIRI_BACKTRACE") { + let ctfe_backtrace = match &*val { + "immediate" => CtfeBacktrace::Immediate, + "0" => CtfeBacktrace::Disabled, + _ => CtfeBacktrace::Capture, + }; + *tcx.sess.ctfe_backtrace.borrow_mut() = ctfe_backtrace; } } From 5531a79f4cb0b3f1bbde6c138890f41df58e657c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 12 Mar 2020 20:46:58 +0100 Subject: [PATCH 1646/3747] rustup, test Abort terminator --- rust-version | 2 +- src/lib.rs | 1 + src/machine.rs | 5 +++++ src/shims/intrinsics.rs | 1 + tests/compile-fail/abort-terminator.rs | 9 +++++++++ 5 files changed, 17 insertions(+), 1 deletion(-) create mode 100644 tests/compile-fail/abort-terminator.rs diff --git a/rust-version b/rust-version index 66d096c0a02b0..ddc3de9a54617 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -c20d7eecbc0928b57da8fe30b2ef8528e2bdd5be +54b7d21f59a363e53eb1c31d76b40af2ff99321c diff --git a/src/lib.rs b/src/lib.rs index 2a805f8555790..86fbabbd629ef 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,6 +1,7 @@ #![feature(rustc_private)] #![feature(option_expect_none, option_unwrap_none)] #![feature(map_first_last)] +#![feature(never_type)] #![warn(rust_2018_idioms)] #![allow(clippy::cast_lossless)] diff --git a/src/machine.rs b/src/machine.rs index bd5884786c0e0..8302c71e2bd15 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -271,6 +271,11 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { ecx.assert_panic(msg, unwind) } + #[inline(always)] + fn abort(_ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx, !> { + throw_machine_stop!(TerminationInfo::Abort) + } + #[inline(always)] fn binary_ptr_op( ecx: &rustc_mir::interpret::InterpCx<'mir, 'tcx, Self>, diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index e1c5fdb7c2d00..121e60c9b058d 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -34,6 +34,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Handle diverging intrinsics. let (dest, ret) = match intrinsic_name { "abort" => { + // FIXME: remove, once the intrinsic on the rustc side is fixed. throw_machine_stop!(TerminationInfo::Abort); } "miri_start_panic" => return this.handle_miri_start_panic(args, unwind), diff --git a/tests/compile-fail/abort-terminator.rs b/tests/compile-fail/abort-terminator.rs new file mode 100644 index 0000000000000..1bfa289a52b4e --- /dev/null +++ b/tests/compile-fail/abort-terminator.rs @@ -0,0 +1,9 @@ +// error-pattern: the evaluated program aborted +#![feature(unwind_attributes)] + +#[unwind(aborts)] +fn panic_abort() { panic!() } + +fn main() { + panic_abort(); +} From 13ae3147f047d7ff1488e6eabc067dacbdef58c9 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 12 Mar 2020 21:20:16 +0100 Subject: [PATCH 1647/3747] refactor handling of diverging intrinsics/foreign functions --- src/shims/foreign_items.rs | 55 +++++++++++++++++++------------------- src/shims/intrinsics.rs | 25 +++++++++-------- 2 files changed, 40 insertions(+), 40 deletions(-) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 88ebc269cf1bd..86c227121540c 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -127,9 +127,31 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let tcx = &{ this.tcx.tcx }; // First: functions that diverge. - let (dest, ret) = match link_name { - // Note that this matches calls to the *foreign* item `__rust_start_panic* - - // that is, calls to `extern "Rust" { fn __rust_start_panic(...) }`. + let (dest, ret) = match ret { + None => match link_name { + // This matches calls to the foreign item `panic_impl`. + // The implementation is provided by the function with the `#[panic_handler]` attribute. + "panic_impl" => { + let panic_impl_id = this.tcx.lang_items().panic_impl().unwrap(); + let panic_impl_instance = ty::Instance::mono(*this.tcx, panic_impl_id); + return Ok(Some(&*this.load_mir(panic_impl_instance.def, None)?)); + } + | "exit" + | "ExitProcess" + => { + // it's really u32 for ExitProcess, but we have to put it into the `Exit` variant anyway + let code = this.read_scalar(args[0])?.to_i32()?; + throw_machine_stop!(TerminationInfo::Exit(code.into())); + } + _ => throw_unsup_format!("can't call (diverging) foreign function: {}", link_name), + }, + Some(p) => p, + }; + + // Second: some functions that we forward to MIR implementations. + match link_name { + // This matches calls to the *foreign* item `__rust_start_panic*, that is, + // calls to `extern "Rust" { fn __rust_start_panic(...) }`. // We forward this to the underlying *implementation* in the panic runtime crate. // Normally, this will be either `libpanic_unwind` or `libpanic_abort`, but it could // also be a custom user-provided implementation via `#![feature(panic_runtime)]` @@ -145,31 +167,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.resolve_path(&[&*panic_runtime.as_str(), "__rust_start_panic"])?; return Ok(Some(&*this.load_mir(start_panic_instance.def, None)?)); } - // Similarly, we forward calls to the `panic_impl` foreign item to its implementation. - // The implementation is provided by the function with the `#[panic_handler]` attribute. - "panic_impl" => { - let panic_impl_id = this.tcx.lang_items().panic_impl().unwrap(); - let panic_impl_instance = ty::Instance::mono(*this.tcx, panic_impl_id); - return Ok(Some(&*this.load_mir(panic_impl_instance.def, None)?)); - } - - | "exit" - | "ExitProcess" - => { - // it's really u32 for ExitProcess, but we have to put it into the `Exit` variant anyway - let code = this.read_scalar(args[0])?.to_i32()?; - throw_machine_stop!(TerminationInfo::Exit(code.into())); - } - _ => { - if let Some(p) = ret { - p - } else { - throw_unsup_format!("can't call (diverging) foreign function: {}", link_name); - } - } - }; + _ => {} + } - // Next: functions that return. + // Third: functions that return. if this.emulate_foreign_item_by_name(link_name, args, dest, ret)? { this.dump_place(*dest); this.go_to_block(ret); diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 121e60c9b058d..cf06a647762a8 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -31,22 +31,21 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // that might still hang around! let intrinsic_name = &*tcx.item_name(instance.def_id()).as_str(); - // Handle diverging intrinsics. - let (dest, ret) = match intrinsic_name { - "abort" => { - // FIXME: remove, once the intrinsic on the rustc side is fixed. - throw_machine_stop!(TerminationInfo::Abort); - } - "miri_start_panic" => return this.handle_miri_start_panic(args, unwind), - _ => - if let Some(p) = ret { - p - } else { - throw_unsup_format!("unimplemented (diverging) intrinsic: {}", intrinsic_name); - }, + // First handle intrinsics without return place. + let (dest, ret) = match ret { + None => match intrinsic_name { + "abort" => { + // FIXME: remove, once the intrinsic on the rustc side is fixed. + throw_machine_stop!(TerminationInfo::Abort); + } + _ => throw_unsup_format!("unimplemented (diverging) intrinsic: {}", intrinsic_name), + }, + Some(p) => p, }; match intrinsic_name { + "miri_start_panic" => return this.handle_miri_start_panic(args, unwind), + "arith_offset" => { let offset = this.read_scalar(args[1])?.to_machine_isize(this)?; let ptr = this.read_scalar(args[0])?.not_undef()?; From 497fbcbf44b52d28169bf74b00ef346920cd5d26 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 14 Mar 2020 09:27:35 +0100 Subject: [PATCH 1648/3747] rustup, fix for intrinsic rename and transmute error change --- rust-version | 2 +- src/shims/intrinsics.rs | 10 +++++----- tests/compile-fail/never_transmute_humans.rs | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/rust-version b/rust-version index ddc3de9a54617..4635ed380aa49 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -54b7d21f59a363e53eb1c31d76b40af2ff99321c +1572c433eed495d0ade41511ae106b180e02851d diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index cf06a647762a8..622e237ebb0a8 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -438,20 +438,20 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(result_ptr, dest)?; } - "panic_if_uninhabited" | - "panic_if_zero_invalid" | - "panic_if_any_invalid" => { + "assert_inhabited" | + "assert_zero_valid" | + "assert_uninit_valid" => { let ty = substs.type_at(0); let layout = this.layout_of(ty)?; if layout.abi.is_uninhabited() { // Return here because we paniced instead of returning normally from the intrinsic. return this.start_panic(&format!("attempted to instantiate uninhabited type `{}`", ty), unwind); } - if intrinsic_name == "panic_if_zero_invalid" && !layout.might_permit_raw_init(this, /*zero:*/ true).unwrap() { + if intrinsic_name == "assert_zero_valid" && !layout.might_permit_raw_init(this, /*zero:*/ true).unwrap() { // Return here because we paniced instead of returning normally from the intrinsic. return this.start_panic(&format!("attempted to zero-initialize type `{}`, which is invalid", ty), unwind); } - if intrinsic_name == "panic_if_any_invalid" && !layout.might_permit_raw_init(this, /*zero:*/ false).unwrap() { + if intrinsic_name == "assert_uninit_valid" && !layout.might_permit_raw_init(this, /*zero:*/ false).unwrap() { // Return here because we paniced instead of returning normally from the intrinsic. return this.start_panic(&format!("attempted to leave type `{}` uninitialized, which is invalid", ty), unwind); } diff --git a/tests/compile-fail/never_transmute_humans.rs b/tests/compile-fail/never_transmute_humans.rs index 2e0d4e9bdf337..8a7d7bfcc682a 100644 --- a/tests/compile-fail/never_transmute_humans.rs +++ b/tests/compile-fail/never_transmute_humans.rs @@ -7,6 +7,6 @@ struct Human; fn main() { let _x: ! = unsafe { - std::mem::transmute::(Human) //~ ERROR entering unreachable code + std::mem::transmute::(Human) //~ ERROR transmuting to uninhabited }; } From a92b2274ce064cce18b7c68d66ba7c019dde487c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 14 Mar 2020 12:05:25 +0100 Subject: [PATCH 1649/3747] fix typo and deduplicate comment --- src/shims/intrinsics.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 622e237ebb0a8..3815ed5164446 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -443,16 +443,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "assert_uninit_valid" => { let ty = substs.type_at(0); let layout = this.layout_of(ty)?; + // Return here because we panicked instead of returning normally from the intrinsic. if layout.abi.is_uninhabited() { - // Return here because we paniced instead of returning normally from the intrinsic. return this.start_panic(&format!("attempted to instantiate uninhabited type `{}`", ty), unwind); } if intrinsic_name == "assert_zero_valid" && !layout.might_permit_raw_init(this, /*zero:*/ true).unwrap() { - // Return here because we paniced instead of returning normally from the intrinsic. return this.start_panic(&format!("attempted to zero-initialize type `{}`, which is invalid", ty), unwind); } if intrinsic_name == "assert_uninit_valid" && !layout.might_permit_raw_init(this, /*zero:*/ false).unwrap() { - // Return here because we paniced instead of returning normally from the intrinsic. return this.start_panic(&format!("attempted to leave type `{}` uninitialized, which is invalid", ty), unwind); } } From 1c4f27f1b2f5517c5dfa6fea0cfef8c089b2e9ec Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 14 Mar 2020 11:53:09 +0100 Subject: [PATCH 1650/3747] adjust Miri to needs of changed unwinding strategy --- src/machine.rs | 16 ++--- src/shims/foreign_items.rs | 14 ++--- src/shims/intrinsics.rs | 3 +- src/shims/panic.rs | 124 ++++++++++++++++++------------------- 4 files changed, 77 insertions(+), 80 deletions(-) diff --git a/src/machine.rs b/src/machine.rs index 8302c71e2bd15..d94c6928cfe04 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -32,11 +32,10 @@ pub struct FrameData<'tcx> { /// Extra data for Stacked Borrows. pub call_id: stacked_borrows::CallId, - /// If this is Some(), then this is a special "catch unwind" frame (the frame of the closure - /// called by `__rustc_maybe_catch_panic`). When this frame is popped during unwinding a panic, - /// we stop unwinding, use the `CatchUnwindData` to - /// store the panic payload, and continue execution in the parent frame. - pub catch_panic: Option>, + /// If this is Some(), then this is a special "catch unwind" frame (the frame of `try_fn` + /// called by `try`). When this frame is popped during unwinding a panic, + /// we stop unwinding, use the `CatchUnwindData` to handle catching. + pub catch_unwind: Option>, } /// Extra memory kinds @@ -163,7 +162,8 @@ pub struct Evaluator<'tcx> { /// The temporary used for storing the argument of /// the call to `miri_start_panic` (the panic payload) when unwinding. - pub(crate) panic_payload: Option>, + /// This is pointer-sized, and matches the `Payload` type in `src/libpanic_unwind/miri.rs`. + pub(crate) panic_payload: Option>, } impl<'tcx> Evaluator<'tcx> { @@ -405,7 +405,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { let call_id = stacked_borrows.map_or(NonZeroU64::new(1).unwrap(), |stacked_borrows| { stacked_borrows.borrow_mut().new_call() }); - Ok(FrameData { call_id, catch_panic: None }) + Ok(FrameData { call_id, catch_unwind: None }) } #[inline(always)] @@ -413,7 +413,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { ecx: &mut InterpCx<'mir, 'tcx, Self>, extra: FrameData<'tcx>, unwinding: bool, - ) -> InterpResult<'tcx, StackPopInfo> { + ) -> InterpResult<'tcx, StackPopJump> { ecx.handle_stack_pop(extra, unwinding) } diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 86c227121540c..0183757cff0ae 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -150,12 +150,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Second: some functions that we forward to MIR implementations. match link_name { - // This matches calls to the *foreign* item `__rust_start_panic*, that is, - // calls to `extern "Rust" { fn __rust_start_panic(...) }`. + // This matches calls to the foreign item `__rust_start_panic`, that is, + // calls to `extern "Rust" { fn __rust_start_panic(...) }` + // (and `__rust_panic_cleanup`, respectively). // We forward this to the underlying *implementation* in the panic runtime crate. // Normally, this will be either `libpanic_unwind` or `libpanic_abort`, but it could // also be a custom user-provided implementation via `#![feature(panic_runtime)]` - "__rust_start_panic" => { + "__rust_start_panic" | "__rust_panic_cleanup"=> { // FIXME we might want to cache this... but it's not really performance-critical. let panic_runtime = tcx .crates() @@ -164,7 +165,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx .expect("No panic runtime found!"); let panic_runtime = tcx.crate_name(*panic_runtime); let start_panic_instance = - this.resolve_path(&[&*panic_runtime.as_str(), "__rust_start_panic"])?; + this.resolve_path(&[&*panic_runtime.as_str(), link_name])?; return Ok(Some(&*this.load_mir(start_panic_instance.def, None)?)); } _ => {} @@ -291,11 +292,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(new_ptr, dest)?; } - "__rust_maybe_catch_panic" => { - this.handle_catch_panic(args, dest, ret)?; - return Ok(false); - } - "memcmp" => { let left = this.read_scalar(args[0])?.not_undef()?; let right = this.read_scalar(args[1])?.not_undef()?; diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 3815ed5164446..8d7645c81fe4f 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -34,6 +34,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // First handle intrinsics without return place. let (dest, ret) = match ret { None => match intrinsic_name { + "miri_start_panic" => return this.handle_miri_start_panic(args, unwind), "abort" => { // FIXME: remove, once the intrinsic on the rustc side is fixed. throw_machine_stop!(TerminationInfo::Abort); @@ -44,7 +45,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx }; match intrinsic_name { - "miri_start_panic" => return this.handle_miri_start_panic(args, unwind), + "try" => return this.handle_try(args, dest, ret), "arith_offset" => { let offset = this.read_scalar(args[1])?.to_machine_isize(this)?; diff --git a/src/shims/panic.rs b/src/shims/panic.rs index d6f563deb0f93..2f61ab6c39583 100644 --- a/src/shims/panic.rs +++ b/src/shims/panic.rs @@ -17,24 +17,22 @@ use rustc_target::spec::PanicStrategy; use crate::*; -/// Holds all of the relevant data for a call to -/// `__rust_maybe_catch_panic`. -/// -/// If a panic occurs, we update this data with -/// the information from the panic site. +/// Holds all of the relevant data for when unwinding hits a `try` frame. #[derive(Debug)] pub struct CatchUnwindData<'tcx> { - /// The dereferenced `data_ptr` argument passed to `__rust_maybe_catch_panic`. - pub data_place: MPlaceTy<'tcx, Tag>, - /// The dereferenced `vtable_ptr` argument passed to `__rust_maybe_catch_panic`. - pub vtable_place: MPlaceTy<'tcx, Tag>, - /// The `dest` from the original call to `__rust_maybe_catch_panic`. - pub dest: PlaceTy<'tcx, Tag>, + /// The `catch_fn` callback to call in case of a panic. + catch_fn: Scalar, + /// The `data` argument for that callback. + data: Scalar, + /// The return place from the original call to `try`. + dest: PlaceTy<'tcx, Tag>, + /// The return block from the original call to `try`. + ret: mir::BasicBlock, } impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { - /// Handles the special "miri_start_panic" intrinsic, which is called + /// Handles the special `miri_start_panic` intrinsic, which is called /// by libpanic_unwind to delegate the actual unwinding process to Miri. fn handle_miri_start_panic( &mut self, @@ -46,47 +44,50 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx trace!("miri_start_panic: {:?}", this.frame().span); // Get the raw pointer stored in arg[0] (the panic payload). - let scalar = this.read_immediate(args[0])?; + let payload = this.read_scalar(args[0])?.not_undef()?; assert!( this.machine.panic_payload.is_none(), "the panic runtime should avoid double-panics" ); - this.machine.panic_payload = Some(scalar); + this.machine.panic_payload = Some(payload); // Jump to the unwind block to begin unwinding. this.unwind_to_block(unwind); return Ok(()); } - fn handle_catch_panic( + /// Handles the `try` intrinsic, the underlying implementation of `std::panicking::try`. + fn handle_try( &mut self, args: &[OpTy<'tcx, Tag>], dest: PlaceTy<'tcx, Tag>, ret: mir::BasicBlock, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - let tcx = &{ this.tcx.tcx }; - // fn __rust_maybe_catch_panic( - // f: fn(*mut u8), - // data: *mut u8, - // data_ptr: *mut usize, - // vtable_ptr: *mut usize, - // ) -> u32 + // Signature: + // fn r#try(try_fn: fn(*mut u8), data: *mut u8, catch_fn: fn(*mut u8, *mut u8)) -> i32 + // Calls `try_fn` with `data` as argument. If that executes normally, returns 0. + // If that unwinds, calls `catch_fn` with the first argument being `data` and + // then second argument being a target-dependent `payload` (i.e. it is up to us to define + // what that is), and returns 1. + // The `payload` is passed (by libstd) to `__rust_panic_cleanup`, which is then expected to + // return a `Box`. + // In Miri, `miri_start_panic` is passed exactly that type, so we make the `payload` simply + // a pointer to `Box`. // Get all the arguments. - let f = this.read_scalar(args[0])?.not_undef()?; - let f_arg = this.read_scalar(args[1])?.not_undef()?; - let data_place = this.deref_operand(args[2])?; - let vtable_place = this.deref_operand(args[3])?; - - // Now we make a function call, and pass `f_arg` as first and only argument. - let f_instance = this.memory.get_fn(f)?.as_instance()?; - trace!("__rust_maybe_catch_panic: {:?}", f_instance); - let ret_place = MPlaceTy::dangling(this.layout_of(tcx.mk_unit())?, this).into(); + let try_fn = this.read_scalar(args[0])?.not_undef()?; + let data = this.read_scalar(args[1])?.not_undef()?; + let catch_fn = this.read_scalar(args[2])?.not_undef()?; + + // Now we make a function call, and pass `data` as first and only argument. + let f_instance = this.memory.get_fn(try_fn)?.as_instance()?; + trace!("try_fn: {:?}", f_instance); + let ret_place = MPlaceTy::dangling(this.layout_of(this.tcx.mk_unit())?, this).into(); this.call_function( f_instance, - &[f_arg.into()], + &[data.into()], Some(ret_place), // Directly return to caller. StackPopCleanup::Goto { ret: Some(ret), unwind: None }, @@ -95,12 +96,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // We ourselves will return `0`, eventually (will be overwritten if we catch a panic). this.write_null(dest)?; - // In unwind mode, we tag this frame with some extra data. + // In unwind mode, we tag this frame with the extra data needed to catch unwinding. // This lets `handle_stack_pop` (below) know that we should stop unwinding // when we pop this frame. - if this.tcx.tcx.sess.panic_strategy() == PanicStrategy::Unwind { - this.frame_mut().extra.catch_panic = - Some(CatchUnwindData { data_place, vtable_place, dest }) + if this.tcx.sess.panic_strategy() == PanicStrategy::Unwind { + this.frame_mut().extra.catch_unwind = Some(CatchUnwindData { catch_fn, data, dest, ret }); } return Ok(()); @@ -110,45 +110,45 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx &mut self, mut extra: FrameData<'tcx>, unwinding: bool, - ) -> InterpResult<'tcx, StackPopInfo> { + ) -> InterpResult<'tcx, StackPopJump> { let this = self.eval_context_mut(); trace!("handle_stack_pop(extra = {:?}, unwinding = {})", extra, unwinding); + if let Some(stacked_borrows) = this.memory.extra.stacked_borrows.as_ref() { + stacked_borrows.borrow_mut().end_call(extra.call_id); + } // We only care about `catch_panic` if we're unwinding - if we're doing a normal // return, then we don't need to do anything special. - let res = if let (true, Some(unwind_data)) = (unwinding, extra.catch_panic.take()) { - // We've just popped a frame that was pushed by `__rust_maybe_catch_panic`, + if let (true, Some(catch_unwind)) = (unwinding, extra.catch_unwind.take()) { + // We've just popped a frame that was pushed by `try`, // and we are unwinding, so we should catch that. trace!("unwinding: found catch_panic frame during unwinding: {:?}", this.frame().span); - // `panic_payload` now holds a `*mut (dyn Any + Send)`, - // provided by the `miri_start_panic` intrinsic. - // We want to split this into its consituient parts - - // the data and vtable pointers - and store them according to - // `unwind_data`, i.e., we store them where `__rust_maybe_catch_panic` - // was told to put them. - let payload = this.machine.panic_payload.take().unwrap(); - let payload = this.ref_to_mplace(payload)?; - let payload_data_place = payload.ptr; - let payload_vtable_place = payload.meta.unwrap_meta(); - - this.write_scalar(payload_data_place, unwind_data.data_place.into())?; - this.write_scalar(payload_vtable_place, unwind_data.vtable_place.into())?; + // We set the return value of `try` to 1, since there was a panic. + this.write_scalar(Scalar::from_i32(1), catch_unwind.dest)?; - // We set the return value of `__rust_maybe_catch_panic` to 1, - // since there was a panic. - let dest = unwind_data.dest; - this.write_scalar(Scalar::from_int(1, dest.layout.size), dest)?; + // `panic_payload` holds what was passed to `miri_start_panic`. + // This is exactly the second argument we need to pass to `catch_fn`. + let payload = this.machine.panic_payload.take().unwrap(); - StackPopInfo::StopUnwinding + // Push the `catch_fn` stackframe. + let f_instance = this.memory.get_fn(catch_unwind.catch_fn)?.as_instance()?; + trace!("catch_fn: {:?}", f_instance); + let ret_place = MPlaceTy::dangling(this.layout_of(this.tcx.mk_unit())?, this).into(); + this.call_function( + f_instance, + &[catch_unwind.data.into(), payload.into()], + Some(ret_place), + // Directly return to caller of `try`. + StackPopCleanup::Goto { ret: Some(catch_unwind.ret), unwind: None }, + )?; + + // We pushed a new stack frame, the engine should not do any jumping now! + Ok(StackPopJump::NoJump) } else { - StackPopInfo::Normal - }; - if let Some(stacked_borrows) = this.memory.extra.stacked_borrows.as_ref() { - stacked_borrows.borrow_mut().end_call(extra.call_id); + Ok(StackPopJump::Normal) } - Ok(res) } /// Starta a panic in the interpreter with the given message as payload. From 956692d902f708d32d5d6242955fedee9d568f02 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 15 Mar 2020 11:15:09 +0100 Subject: [PATCH 1651/3747] bump rust-version --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 4635ed380aa49..1bad03be36cbb 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -1572c433eed495d0ade41511ae106b180e02851d +7cdbc87a49b0b705a41a004a6d486b0952521ae7 From 17a677f4a9631a620e85678556d68828b6f7aa55 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 15 Mar 2020 11:17:07 +0100 Subject: [PATCH 1652/3747] abort intrinsic is handled by librustc_mir now --- src/shims/intrinsics.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 8d7645c81fe4f..b91af778d9791 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -35,10 +35,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let (dest, ret) = match ret { None => match intrinsic_name { "miri_start_panic" => return this.handle_miri_start_panic(args, unwind), - "abort" => { - // FIXME: remove, once the intrinsic on the rustc side is fixed. - throw_machine_stop!(TerminationInfo::Abort); - } _ => throw_unsup_format!("unimplemented (diverging) intrinsic: {}", intrinsic_name), }, Some(p) => p, From 92e3032941ede436d90a1c655f34ddfd3bcd9957 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 15 Mar 2020 15:15:22 +0100 Subject: [PATCH 1653/3747] Cargo.toml: group all dependencies together --- Cargo.toml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index f71fec3c2846c..e788e775972af 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -56,11 +56,11 @@ serde = { version = "*", features = ["derive"] } [build-dependencies] vergen = "3" +[dev-dependencies] +compiletest_rs = { version = "0.4", features = ["tmp"] } +colored = "1.6" + [features] default = ["cargo_miri"] cargo_miri = ["cargo_metadata", "directories", "rustc_version", "serde_json"] rustc_tests = [] - -[dev-dependencies] -compiletest_rs = { version = "0.4", features = ["tmp"] } -colored = "1.6" From a664156440916b96737c4c8317d9befca68d0440 Mon Sep 17 00:00:00 2001 From: Youngsuk Kim Date: Sun, 15 Mar 2020 18:06:21 -0400 Subject: [PATCH 1654/3747] Minor typo fix "initializiation" => "initialization" --- src/eval.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/eval.rs b/src/eval.rs index a82c40a99e011..2cf5a1dc444c2 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -198,7 +198,7 @@ pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) -> Ok(v) => v, Err(mut err) => { err.print_backtrace(); - panic!("Miri initialziation error: {}", err.kind) + panic!("Miri initialization error: {}", err.kind) } }; From bddf9e050b729d98fd64c26879a809b89593b0ec Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 16 Mar 2020 09:59:01 +0100 Subject: [PATCH 1655/3747] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 1bad03be36cbb..085e3695a1965 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -7cdbc87a49b0b705a41a004a6d486b0952521ae7 +97eda01bb79de1e0a52994f52cfb5a527687f505 From 8a26a288c2fa72e623e4c48d77216cf58c7177cc Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 16 Mar 2020 21:32:57 +0100 Subject: [PATCH 1656/3747] rustup --- rust-version | 2 +- tests/compile-fail/exact_div2.rs | 2 +- tests/compile-fail/exact_div3.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/rust-version b/rust-version index 085e3695a1965..dce708705b33a 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -97eda01bb79de1e0a52994f52cfb5a527687f505 +dd67187965e136bff1ed05e035293441c60f0790 diff --git a/tests/compile-fail/exact_div2.rs b/tests/compile-fail/exact_div2.rs index f4400d0d8ae22..9b9ae807088d7 100644 --- a/tests/compile-fail/exact_div2.rs +++ b/tests/compile-fail/exact_div2.rs @@ -1,5 +1,5 @@ #![feature(core_intrinsics)] fn main() { // divison with a remainder - unsafe { std::intrinsics::exact_div(2u16, 3); } //~ ERROR 2 cannot be divided by 3 without remainder + unsafe { std::intrinsics::exact_div(2u16, 3); } //~ ERROR 2u16 cannot be divided by 3u16 without remainder } diff --git a/tests/compile-fail/exact_div3.rs b/tests/compile-fail/exact_div3.rs index 0d5097a87a208..1cd112acfc2d5 100644 --- a/tests/compile-fail/exact_div3.rs +++ b/tests/compile-fail/exact_div3.rs @@ -1,5 +1,5 @@ #![feature(core_intrinsics)] fn main() { // signed divison with a remainder - unsafe { std::intrinsics::exact_div(-19i8, 2); } //~ ERROR -19 cannot be divided by 2 without remainder + unsafe { std::intrinsics::exact_div(-19i8, 2); } //~ ERROR -19i8 cannot be divided by 2i8 without remainder } From 8b6af3eacbeb359c2041a3b5efc12042d3c33deb Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 17 Mar 2020 15:18:53 +0100 Subject: [PATCH 1657/3747] avoid using unchecked casts or arithmetic --- src/bin/miri.rs | 3 +-- src/eval.rs | 13 +++++----- src/helpers.rs | 9 ++++--- src/shims/dlsym.rs | 2 +- src/shims/env.rs | 7 ++--- src/shims/foreign_items.rs | 10 +++---- src/shims/foreign_items/posix.rs | 4 ++- src/shims/foreign_items/posix/linux.rs | 2 +- src/shims/foreign_items/posix/macos.rs | 2 +- src/shims/foreign_items/windows.rs | 6 ++--- src/shims/fs.rs | 36 +++++++++++++------------- src/shims/intrinsics.rs | 9 ++++--- src/shims/mod.rs | 21 +++++++++------ src/shims/time.rs | 8 +++--- 14 files changed, 71 insertions(+), 61 deletions(-) diff --git a/src/bin/miri.rs b/src/bin/miri.rs index e40bfcf6276ad..4a54867c99640 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -259,7 +259,6 @@ fn main() { rustc_driver::install_ice_hook(); let result = rustc_driver::catch_fatal_errors(move || { rustc_driver::run_compiler(&rustc_args, &mut MiriCompilerCalls { miri_config }, None, None) - }) - .and_then(|result| result); + }); std::process::exit(result.is_err() as i32); } diff --git a/src/eval.rs b/src/eval.rs index 2cf5a1dc444c2..64beff6eb77fe 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -1,6 +1,7 @@ //! Main evaluator loop and setting up the initial stack frame. use std::ffi::OsStr; +use std::convert::TryFrom; use rand::rngs::StdRng; use rand::SeedableRng; @@ -101,14 +102,14 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( // First argument: pointer to `main()`. let main_ptr = ecx.memory.create_fn_alloc(FnVal::Instance(main_instance)); // Second argument (argc): length of `config.args`. - let argc = Scalar::from_uint(config.args.len() as u128, ecx.pointer_size()); + let argc = Scalar::from_uint(u64::try_from(config.args.len()).unwrap(), ecx.pointer_size()); // Third argument (`argv`): created from `config.args`. let argv = { // Put each argument in memory, collect pointers. let mut argvs = Vec::>::new(); for arg in config.args.iter() { // Make space for `0` terminator. - let size = arg.len() as u64 + 1; + let size = u64::try_from(arg.len()).unwrap().checked_add(1).unwrap(); let arg_type = tcx.mk_array(tcx.types.u8, size); let arg_place = ecx.allocate(ecx.layout_of(arg_type)?, MiriMemoryKind::Machine.into()); ecx.write_os_str_to_c_str(OsStr::new(arg), arg_place.ptr, size)?; @@ -116,10 +117,10 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( } // Make an array with all these pointers, in the Miri memory. let argvs_layout = - ecx.layout_of(tcx.mk_array(tcx.mk_imm_ptr(tcx.types.u8), argvs.len() as u64))?; + ecx.layout_of(tcx.mk_array(tcx.mk_imm_ptr(tcx.types.u8), u64::try_from(argvs.len()).unwrap()))?; let argvs_place = ecx.allocate(argvs_layout, MiriMemoryKind::Machine.into()); for (idx, arg) in argvs.into_iter().enumerate() { - let place = ecx.mplace_field(argvs_place, idx as u64)?; + let place = ecx.mplace_field(argvs_place, u64::try_from(idx).unwrap())?; ecx.write_scalar(arg, place.into())?; } ecx.memory.mark_immutable(argvs_place.ptr.assert_ptr().alloc_id)?; @@ -153,13 +154,13 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( cmd.push(std::char::from_u32(0).unwrap()); let cmd_utf16: Vec = cmd.encode_utf16().collect(); - let cmd_type = tcx.mk_array(tcx.types.u16, cmd_utf16.len() as u64); + let cmd_type = tcx.mk_array(tcx.types.u16, u64::try_from(cmd_utf16.len()).unwrap()); let cmd_place = ecx.allocate(ecx.layout_of(cmd_type)?, MiriMemoryKind::Machine.into()); ecx.machine.cmd_line = Some(cmd_place.ptr); // Store the UTF-16 string. We just allocated so we know the bounds are fine. let char_size = Size::from_bytes(2); for (idx, &c) in cmd_utf16.iter().enumerate() { - let place = ecx.mplace_field(cmd_place, idx as u64)?; + let place = ecx.mplace_field(cmd_place, u64::try_from(idx).unwrap())?; ecx.write_scalar(Scalar::from_uint(c, char_size), place.into())?; } } diff --git a/src/helpers.rs b/src/helpers.rs index 5ff0a5671cdb5..ecb3a5d8bce9c 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -1,5 +1,6 @@ use std::ffi::OsStr; use std::{iter, mem}; +use std::convert::TryFrom; use rustc::mir; use rustc::ty::{ @@ -81,7 +82,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } /// Generate some random bytes, and write them to `dest`. - fn gen_random(&mut self, ptr: Scalar, len: usize) -> InterpResult<'tcx> { + fn gen_random(&mut self, ptr: Scalar, len: u64) -> InterpResult<'tcx> { // Some programs pass in a null pointer and a length of 0 // to their platform's random-generation function (e.g. getrandom()) // on Linux. For compatibility with these programs, we don't perform @@ -92,7 +93,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } let this = self.eval_context_mut(); - let mut data = vec![0; len]; + let mut data = vec![0; usize::try_from(len).unwrap()]; if this.machine.communicate { // Fill the buffer using the host's rng. @@ -499,7 +500,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let bytes = os_str_to_bytes(os_str)?; // If `size` is smaller or equal than `bytes.len()`, writing `bytes` plus the required null // terminator to memory using the `ptr` pointer would cause an out-of-bounds access. - let string_length = bytes.len() as u64; + let string_length = u64::try_from(bytes.len()).unwrap(); if size <= string_length { return Ok((false, string_length)); } @@ -514,7 +515,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx os_str: &OsStr, memkind: MemoryKind, ) -> Pointer { - let size = os_str.len() as u64 + 1; // Make space for `0` terminator. + let size = u64::try_from(os_str.len()).unwrap().checked_add(1).unwrap(); // Make space for `0` terminator. let this = self.eval_context_mut(); let arg_type = this.tcx.mk_array(this.tcx.types.u8, size); diff --git a/src/shims/dlsym.rs b/src/shims/dlsym.rs index 0069f8cc80870..9027a97cf54e4 100644 --- a/src/shims/dlsym.rs +++ b/src/shims/dlsym.rs @@ -37,7 +37,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx GetEntropy => { let ptr = this.read_scalar(args[0])?.not_undef()?; let len = this.read_scalar(args[1])?.to_machine_usize(this)?; - this.gen_random(ptr, len as usize)?; + this.gen_random(ptr, len)?; this.write_null(dest)?; } } diff --git a/src/shims/env.rs b/src/shims/env.rs index 7c6b6c942e5e3..da634c1aeb237 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -1,5 +1,6 @@ use std::ffi::{OsString, OsStr}; use std::env; +use std::convert::TryFrom; use crate::stacked_borrows::Tag; use crate::rustc_target::abi::LayoutOf; @@ -58,7 +59,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(match this.machine.env_vars.map.get(name) { // The offset is used to strip the "{name}=" part of the string. Some(var_ptr) => { - Scalar::from(var_ptr.offset(Size::from_bytes(name.len() as u64 + 1), this)?) + Scalar::from(var_ptr.offset(Size::from_bytes(u64::try_from(name.len()).unwrap().checked_add(1).unwrap()), this)?) } None => Scalar::ptr_null(&*this.tcx), }) @@ -181,10 +182,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Make an array with all these pointers inside Miri. let tcx = this.tcx; let vars_layout = - this.layout_of(tcx.mk_array(tcx.types.usize, vars.len() as u64))?; + this.layout_of(tcx.mk_array(tcx.types.usize, u64::try_from(vars.len()).unwrap()))?; let vars_place = this.allocate(vars_layout, MiriMemoryKind::Machine.into()); for (idx, var) in vars.into_iter().enumerate() { - let place = this.mplace_field(vars_place, idx as u64)?; + let place = this.mplace_field(vars_place, u64::try_from(idx).unwrap())?; this.write_scalar(var, place.into())?; } this.write_scalar( diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 0183757cff0ae..deabbdd608193 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -1,7 +1,7 @@ mod windows; mod posix; -use std::{convert::TryInto, iter}; +use std::{convert::{TryInto, TryFrom}, iter}; use rustc_hir::def_id::DefId; use rustc::mir; @@ -250,7 +250,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx MiriMemoryKind::Rust.into(), ); // We just allocated this, the access is definitely in-bounds. - this.memory.write_bytes(ptr.into(), iter::repeat(0u8).take(size as usize)).unwrap(); + this.memory.write_bytes(ptr.into(), iter::repeat(0u8).take(usize::try_from(size).unwrap())).unwrap(); this.write_scalar(ptr, dest)?; } "__rust_dealloc" => { @@ -350,7 +350,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "strlen" => { let ptr = this.read_scalar(args[0])?.not_undef()?; let n = this.memory.read_c_str(ptr)?.len(); - this.write_scalar(Scalar::from_uint(n as u64, dest.layout.size), dest)?; + this.write_scalar(Scalar::from_uint(u64::try_from(n).unwrap(), dest.layout.size), dest)?; } // math functions @@ -440,9 +440,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Saturating cast to i16. Even those are outside the valid exponent range to // `scalbn` below will do its over/underflow handling. - let exp = if exp > i16::MAX as i32 { + let exp = if exp > i32::from(i16::MAX) { i16::MAX - } else if exp < i16::MIN as i32 { + } else if exp < i32::from(i16::MIN) { i16::MIN } else { exp.try_into().unwrap() diff --git a/src/shims/foreign_items/posix.rs b/src/shims/foreign_items/posix.rs index e80908d8fa09f..f73ec288284ab 100644 --- a/src/shims/foreign_items/posix.rs +++ b/src/shims/foreign_items/posix.rs @@ -1,6 +1,8 @@ mod linux; mod macos; +use std::convert::TryFrom; + use crate::*; use rustc::mir; use rustc::ty::layout::{Align, LayoutOf, Size}; @@ -84,7 +86,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx io::stderr().write(buf_cont) }; match res { - Ok(n) => n as i64, + Ok(n) => i64::try_from(n).unwrap(), Err(_) => -1, } } else { diff --git a/src/shims/foreign_items/posix/linux.rs b/src/shims/foreign_items/posix/linux.rs index 8a1ce5594ae46..023fee4ca7b1e 100644 --- a/src/shims/foreign_items/posix/linux.rs +++ b/src/shims/foreign_items/posix/linux.rs @@ -114,7 +114,7 @@ fn getrandom<'tcx>( // neither of which have any effect on our current PRNG. let _flags = this.read_scalar(args[2])?.to_i32()?; - this.gen_random(ptr, len as usize)?; + this.gen_random(ptr, len)?; this.write_scalar(Scalar::from_uint(len, dest.layout.size), dest)?; Ok(()) } diff --git a/src/shims/foreign_items/posix/macos.rs b/src/shims/foreign_items/posix/macos.rs index 0d067cc04138a..34661fb2383c3 100644 --- a/src/shims/foreign_items/posix/macos.rs +++ b/src/shims/foreign_items/posix/macos.rs @@ -97,7 +97,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "SecRandomCopyBytes" => { let len = this.read_scalar(args[1])?.to_machine_usize(this)?; let ptr = this.read_scalar(args[2])?.not_undef()?; - this.gen_random(ptr, len as usize)?; + this.gen_random(ptr, len)?; this.write_null(dest)?; } diff --git a/src/shims/foreign_items/windows.rs b/src/shims/foreign_items/windows.rs index 623b0f307b911..306d2f7b0e37c 100644 --- a/src/shims/foreign_items/windows.rs +++ b/src/shims/foreign_items/windows.rs @@ -165,12 +165,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_uint(key, dest.layout.size), dest)?; } "TlsGetValue" => { - let key = this.read_scalar(args[0])?.to_u32()? as u128; + let key = u128::from(this.read_scalar(args[0])?.to_u32()?); let ptr = this.machine.tls.load_tls(key, tcx)?; this.write_scalar(ptr, dest)?; } "TlsSetValue" => { - let key = this.read_scalar(args[0])?.to_u32()? as u128; + let key = u128::from(this.read_scalar(args[0])?.to_u32()?); let new_ptr = this.read_scalar(args[1])?.not_undef()?; this.machine.tls.store_tls(key, this.test_null(new_ptr)?)?; @@ -197,7 +197,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "SystemFunction036" => { let ptr = this.read_scalar(args[0])?.not_undef()?; let len = this.read_scalar(args[1])?.to_u32()?; - this.gen_random(ptr, len as usize)?; + this.gen_random(ptr, len.into())?; this.write_scalar(Scalar::from_bool(true), dest)?; } // We don't support threading. diff --git a/src/shims/fs.rs b/src/shims/fs.rs index 0ea53b16fd191..7c755143f2e81 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -10,7 +10,7 @@ use rustc::ty::layout::{Align, LayoutOf, Size}; use crate::stacked_borrows::Tag; use crate::*; -use helpers::immty_from_uint_checked; +use helpers::{immty_from_int_checked, immty_from_uint_checked}; use shims::time::system_time_to_duration; #[derive(Debug)] @@ -56,7 +56,7 @@ impl FileHandler { let new_fd = candidate_new_fd.unwrap_or_else(|| { // find_map ran out of BTreeMap entries before finding a free fd, use one plus the // maximum fd in the map - self.handles.last_entry().map(|entry| entry.key() + 1).unwrap_or(min_fd) + self.handles.last_entry().map(|entry| entry.key().checked_add(1).unwrap()).unwrap_or(min_fd) }); self.handles.insert(new_fd, file_handle).unwrap_none(); @@ -167,11 +167,11 @@ trait EvalContextExtPrivate<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, ' match file_type { Ok(file_type) => { if file_type.is_dir() { - Ok(this.eval_libc("DT_DIR")?.to_u8()? as i32) + Ok(this.eval_libc("DT_DIR")?.to_u8()?.into()) } else if file_type.is_file() { - Ok(this.eval_libc("DT_REG")?.to_u8()? as i32) + Ok(this.eval_libc("DT_REG")?.to_u8()?.into()) } else if file_type.is_symlink() { - Ok(this.eval_libc("DT_LNK")?.to_u8()? as i32) + Ok(this.eval_libc("DT_LNK")?.to_u8()?.into()) } else { // Certain file types are only supported when the host is a Unix system. // (i.e. devices and sockets) If it is, check those cases, if not, fall back to @@ -181,19 +181,19 @@ trait EvalContextExtPrivate<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, ' { use std::os::unix::fs::FileTypeExt; if file_type.is_block_device() { - Ok(this.eval_libc("DT_BLK")?.to_u8()? as i32) + Ok(this.eval_libc("DT_BLK")?.to_u8()?.into()) } else if file_type.is_char_device() { - Ok(this.eval_libc("DT_CHR")?.to_u8()? as i32) + Ok(this.eval_libc("DT_CHR")?.to_u8()?.into()) } else if file_type.is_fifo() { - Ok(this.eval_libc("DT_FIFO")?.to_u8()? as i32) + Ok(this.eval_libc("DT_FIFO")?.to_u8()?.into()) } else if file_type.is_socket() { - Ok(this.eval_libc("DT_SOCK")?.to_u8()? as i32) + Ok(this.eval_libc("DT_SOCK")?.to_u8()?.into()) } else { - Ok(this.eval_libc("DT_UNKNOWN")?.to_u8()? as i32) + Ok(this.eval_libc("DT_UNKNOWN")?.to_u8()?.into()) } } #[cfg(not(unix))] - Ok(this.eval_libc("DT_UNKNOWN")?.to_u8()? as i32) + Ok(this.eval_libc("DT_UNKNOWN")?.to_u8()?.into()) } } Err(e) => return match e.raw_os_error() { @@ -507,7 +507,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let whence = this.read_scalar(whence_op)?.to_i32()?; let seek_from = if whence == this.eval_libc_i32("SEEK_SET")? { - SeekFrom::Start(offset as u64) + SeekFrom::Start(u64::try_from(offset).unwrap()) } else if whence == this.eval_libc_i32("SEEK_CUR")? { SeekFrom::Current(offset) } else if whence == this.eval_libc_i32("SEEK_END")? { @@ -519,7 +519,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx }; if let Some(FileHandle { file, writable: _ }) = this.machine.file_handler.handles.get_mut(&fd) { - let result = file.seek(seek_from).map(|offset| offset as i64); + let result = file.seek(seek_from).map(|offset| i64::try_from(offset).unwrap()); this.try_unwrap_io_result(result) } else { this.handle_not_found() @@ -810,7 +810,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.check_no_isolation("mkdir")?; let _mode = if this.tcx.sess.target.target.target_os.as_str() == "macos" { - this.read_scalar(mode_op)?.not_undef()?.to_u16()? as u32 + u32::from(this.read_scalar(mode_op)?.not_undef()?.to_u16()?) } else { this.read_scalar(mode_op)?.to_u32()? }; @@ -929,13 +929,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx #[cfg(not(unix))] let ino = 0u64; - let file_type = this.file_type_to_d_type(dir_entry.file_type())? as u128; + let file_type = this.file_type_to_d_type(dir_entry.file_type())?; let imms = [ immty_from_uint_checked(ino, ino64_t_layout)?, // d_ino immty_from_uint_checked(0u128, off64_t_layout)?, // d_off immty_from_uint_checked(0u128, c_ushort_layout)?, // d_reclen - immty_from_uint_checked(file_type, c_uchar_layout)?, // d_type + immty_from_int_checked(file_type, c_uchar_layout)?, // d_type ]; this.write_packed_immediates(entry_place, &imms)?; @@ -1017,14 +1017,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx #[cfg(not(unix))] let ino = 0u64; - let file_type = this.file_type_to_d_type(dir_entry.file_type())? as u128; + let file_type = this.file_type_to_d_type(dir_entry.file_type())?; let imms = [ immty_from_uint_checked(ino, ino_t_layout)?, // d_ino immty_from_uint_checked(0u128, off_t_layout)?, // d_seekoff immty_from_uint_checked(0u128, c_ushort_layout)?, // d_reclen immty_from_uint_checked(file_name_len, c_ushort_layout)?, // d_namlen - immty_from_uint_checked(file_type, c_uchar_layout)?, // d_type + immty_from_int_checked(file_type, c_uchar_layout)?, // d_type ]; this.write_packed_immediates(entry_place, &imms)?; diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index b91af778d9791..6837d45158d97 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -1,4 +1,5 @@ use std::iter; +use std::convert::TryFrom; use rustc::mir; use rustc::mir::interpret::{InterpResult, PointerArithmetic}; @@ -48,7 +49,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let ptr = this.read_scalar(args[0])?.not_undef()?; let pointee_ty = substs.type_at(0); - let pointee_size = this.layout_of(pointee_ty)?.size.bytes() as i64; + let pointee_size = i64::try_from(this.layout_of(pointee_ty)?.size.bytes()).unwrap(); let offset = offset.overflowing_mul(pointee_size).0; let result_ptr = ptr.ptr_wrapping_signed_offset(offset, this); this.write_scalar(result_ptr, dest)?; @@ -229,7 +230,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let count = this.read_scalar(args[2])?.to_machine_usize(this)?; let elem_align = elem_layout.align.abi; - let size = Size::from_bytes(count * elem_size); + let size = Size::from_bytes(count) * elem_size; let src = this.read_scalar(args[0])?.not_undef()?; let src = this.memory.check_ptr_access(src, size, elem_align)?; let dest = this.read_scalar(args[1])?.not_undef()?; @@ -419,7 +420,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let layout = this.layout_of(ty)?; let align = layout.align.pref.bytes(); let ptr_size = this.pointer_size(); - let align_val = Scalar::from_uint(align as u128, ptr_size); + let align_val = Scalar::from_uint(align, ptr_size); this.write_scalar(align_val, dest)?; } @@ -502,7 +503,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx .size_and_align_of_mplace(mplace)? .expect("size_of_val called on extern type"); let ptr_size = this.pointer_size(); - this.write_scalar(Scalar::from_uint(size.bytes() as u128, ptr_size), dest)?; + this.write_scalar(Scalar::from_uint(size.bytes(), ptr_size), dest)?; } #[rustfmt::skip] diff --git a/src/shims/mod.rs b/src/shims/mod.rs index 6adf013858550..d9e4d226ecc9a 100644 --- a/src/shims/mod.rs +++ b/src/shims/mod.rs @@ -7,9 +7,12 @@ pub mod panic; pub mod time; pub mod tls; -use crate::*; +use std::convert::TryFrom; + use rustc::{mir, ty}; +use crate::*; + impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { fn find_mir_or_eval_fn( @@ -54,8 +57,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let (dest, ret) = ret.unwrap(); let req_align = this - .force_bits(this.read_scalar(align_op)?.not_undef()?, this.pointer_size())? - as usize; + .force_bits(this.read_scalar(align_op)?.not_undef()?, this.pointer_size())?; // Stop if the alignment is not a power of two. if !req_align.is_power_of_two() { @@ -69,12 +71,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if let Ok(ptr) = this.force_ptr(ptr_scalar) { // Only do anything if we can identify the allocation this goes to. let cur_align = - this.memory.get_size_and_align(ptr.alloc_id, AllocCheck::MaybeDead)?.1.bytes() - as usize; - if cur_align >= req_align { + this.memory.get_size_and_align(ptr.alloc_id, AllocCheck::MaybeDead)?.1.bytes(); + if u128::from(cur_align) >= req_align { // If the allocation alignment is at least the required alignment we use the - // libcore implementation - result = (this.force_bits(ptr_scalar, this.pointer_size())? as *const i8).align_offset(req_align) as u128; + // libcore implementation. + // FIXME: is this correct in case of truncation? + result = u128::try_from( + (this.force_bits(ptr_scalar, this.pointer_size())? as *const i8) + .align_offset(usize::try_from(req_align).unwrap()) + ).unwrap(); } } diff --git a/src/shims/time.rs b/src/shims/time.rs index 6adea524d2d88..d761698e0d278 100644 --- a/src/shims/time.rs +++ b/src/shims/time.rs @@ -37,8 +37,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let tp = this.deref_operand(tp_op)?; let duration = get_time()?; - let tv_sec = duration.as_secs() as i128; - let tv_nsec = duration.subsec_nanos() as i128; + let tv_sec = duration.as_secs(); + let tv_nsec = duration.subsec_nanos(); let imms = [ immty_from_int_checked(tv_sec, this.libc_ty_layout("time_t")?)?, @@ -69,8 +69,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let tv = this.deref_operand(tv_op)?; let duration = get_time()?; - let tv_sec = duration.as_secs() as i128; - let tv_usec = duration.subsec_micros() as i128; + let tv_sec = duration.as_secs(); + let tv_usec = duration.subsec_micros(); let imms = [ immty_from_int_checked(tv_sec, this.libc_ty_layout("time_t")?)?, From b82cf36117dc23f18e39c4136aa63e99bc48ae03 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 17 Mar 2020 20:53:34 +0100 Subject: [PATCH 1658/3747] rustup; remove no longer existing intrinsics --- rust-version | 2 +- src/shims/intrinsics.rs | 66 +---------------------------------------- 2 files changed, 2 insertions(+), 66 deletions(-) diff --git a/rust-version b/rust-version index dce708705b33a..1c3f12298f86e 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -dd67187965e136bff1ed05e035293441c60f0790 +660326e9791d5caf3186b14521498c2584a494ab diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 6837d45158d97..7f437332d9327 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -4,7 +4,7 @@ use std::convert::TryFrom; use rustc::mir; use rustc::mir::interpret::{InterpResult, PointerArithmetic}; use rustc::ty; -use rustc::ty::layout::{self, Align, LayoutOf, Size}; +use rustc::ty::layout::{Align, LayoutOf, Size}; use rustc_apfloat::Float; use rustc_span::source_map::Span; @@ -384,37 +384,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_immediate(*b, dest)?; } - "init" => { - // Check fast path: we don't want to force an allocation in case the destination is a simple value, - // but we also do not want to create a new allocation with 0s and then copy that over. - // FIXME: We do not properly validate in case of ZSTs and when doing it in memory! - // However, this only affects direct calls of the intrinsic; calls to the stable - // functions wrapping them do get their validation. - // FIXME: should we check that the destination pointer is aligned even for ZSTs? - if !dest.layout.is_zst() { - match dest.layout.abi { - layout::Abi::Scalar(ref s) => { - let x = Scalar::from_int(0, s.value.size(this)); - this.write_scalar(x, dest)?; - } - layout::Abi::ScalarPair(ref s1, ref s2) => { - let x = Scalar::from_int(0, s1.value.size(this)); - let y = Scalar::from_int(0, s2.value.size(this)); - this.write_immediate(Immediate::ScalarPair(x.into(), y.into()), dest)?; - } - _ => { - // Do it in memory - let mplace = this.force_allocation(dest)?; - assert!(!mplace.layout.is_unsized()); - this.memory.write_bytes( - mplace.ptr, - iter::repeat(0u8).take(dest.layout.size.bytes() as usize), - )?; - } - } - } - } - "pref_align_of" => { let ty = substs.type_at(0); let layout = this.layout_of(ty)?; @@ -518,39 +487,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_uint(align.bytes(), ptr_size), dest)?; } - "uninit" => { - // Check fast path: we don't want to force an allocation in case the destination is a simple value, - // but we also do not want to create a new allocation with 0s and then copy that over. - // FIXME: We do not properly validate in case of ZSTs and when doing it in memory! - // However, this only affects direct calls of the intrinsic; calls to the stable - // functions wrapping them do get their validation. - // FIXME: should we check alignment for ZSTs? - if !dest.layout.is_zst() { - match dest.layout.abi { - layout::Abi::Scalar(..) => { - let x = ScalarMaybeUndef::Undef; - this.write_immediate(Immediate::Scalar(x), dest)?; - } - layout::Abi::ScalarPair(..) => { - let x = ScalarMaybeUndef::Undef; - this.write_immediate(Immediate::ScalarPair(x, x), dest)?; - } - _ => { - // Do it in memory - let mplace = this.force_allocation(dest)?; - assert!(!mplace.layout.is_unsized()); - let ptr = mplace.ptr.assert_ptr(); - // We know the return place is in-bounds - this.memory.get_raw_mut(ptr.alloc_id)?.mark_definedness( - ptr, - dest.layout.size, - false, - ); - } - } - } - } - "write_bytes" => { let ty = substs.type_at(0); let ty_layout = this.layout_of(ty)?; From a32e25677f43d161db8fdb923cb80a7dc7c4ae48 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 18 Mar 2020 11:19:01 +0100 Subject: [PATCH 1659/3747] move repeated run of test suite (without and with MIR optimizations) out of compiletest --- README.md | 2 ++ tests/compiletest.rs | 57 ++++++++++++++++---------------------------- travis.sh | 1 + 3 files changed, 24 insertions(+), 36 deletions(-) diff --git a/README.md b/README.md index 3d7003af72e4e..a1b9783166843 100644 --- a/README.md +++ b/README.md @@ -193,6 +193,8 @@ Moreover, Miri recognizes some environment variables: * `MIRI_TEST_TARGET` (recognized by the test suite) indicates which target architecture to test against. `miri` and `cargo miri` accept the `--target` flag for the same purpose. +* `MIRI_TEST_FLAGS` (recognized by the test suite) defines extra flags to be + passed to Miri. ## Contributing and getting help diff --git a/tests/compiletest.rs b/tests/compiletest.rs index 9cead530b57cd..f43ff8ca349de 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -24,9 +24,10 @@ fn rustc_lib_path() -> PathBuf { option_env!("RUSTC_LIB_PATH").unwrap().into() } -fn run_tests(mode: &str, path: &str, target: &str, mut flags: Vec) { +fn run_tests(mode: &str, path: &str, target: &str) { let in_rustc_test_suite = rustc_test_suite().is_some(); // Add some flags we always want. + let mut flags = Vec::new(); flags.push("--edition 2018".to_owned()); if in_rustc_test_suite { // Less aggressive warnings to make the rustc toolstate management less painful. @@ -38,6 +39,12 @@ fn run_tests(mode: &str, path: &str, target: &str, mut flags: Vec) { if let Ok(sysroot) = std::env::var("MIRI_SYSROOT") { flags.push(format!("--sysroot {}", sysroot)); } + if let Ok(extra_flags) = std::env::var("MIRI_TEST_FLAGS") { + flags.push(extra_flags); + } + + let flags = flags.join(" "); + eprintln!(" Compiler flags: {}", flags); // The rest of the configuration. let mut config = compiletest::Config::default().tempdir(); @@ -51,48 +58,36 @@ fn run_tests(mode: &str, path: &str, target: &str, mut flags: Vec) { config.host = get_host(); config.src_base = PathBuf::from(path); config.target = target.to_owned(); - config.target_rustcflags = Some(flags.join(" ")); + config.target_rustcflags = Some(flags); compiletest::run_tests(&config); } -fn compile_fail(path: &str, target: &str, opt: bool) { - let opt_str = if opt { " with optimizations" } else { "" }; +fn compile_fail(path: &str, target: &str) { eprintln!( "{}", format!( - "## Running compile-fail tests in {} against miri for target {}{}", - path, target, opt_str + "## Running compile-fail tests in {} against miri for target {}", + path, target ) .green() .bold() ); - let mut flags = Vec::new(); - if opt { - flags.push("-Zmir-opt-level=3".to_owned()); - } - - run_tests("compile-fail", path, target, flags); + run_tests("compile-fail", path, target); } -fn miri_pass(path: &str, target: &str, opt: bool) { - let opt_str = if opt { " with optimizations" } else { "" }; +fn miri_pass(path: &str, target: &str) { eprintln!( "{}", format!( - "## Running run-pass tests in {} against miri for target {}{}", - path, target, opt_str + "## Running run-pass tests in {} against miri for target {}", + path, target ) .green() .bold() ); - let mut flags = Vec::new(); - if opt { - flags.push("-Zmir-opt-level=3".to_owned()); - } - - run_tests("ui", path, target, flags); + run_tests("ui", path, target); } fn get_host() -> String { @@ -112,21 +107,11 @@ fn get_target() -> String { std::env::var("MIRI_TEST_TARGET").unwrap_or_else(|_| get_host()) } -fn run_pass_miri(opt: bool) { - miri_pass("tests/run-pass", &get_target(), opt); -} - -fn compile_fail_miri(opt: bool) { - compile_fail("tests/compile-fail", &get_target(), opt); -} - fn test_runner(_tests: &[&()]) { - // Add a test env var to do environment communication tests + // Add a test env var to do environment communication tests. std::env::set_var("MIRI_ENV_VAR_TEST", "0"); - run_pass_miri(false); - run_pass_miri(true); - - compile_fail_miri(false); - compile_fail_miri(true); + let target = get_target(); + miri_pass("tests/run-pass", &target); + compile_fail("tests/compile-fail", &target); } diff --git a/travis.sh b/travis.sh index 3d4b8651fb839..fec9145ab0f7e 100755 --- a/travis.sh +++ b/travis.sh @@ -17,6 +17,7 @@ echo # Test function run_tests { ./miri test --locked + MIRI_TEST_FLAGS="-Z mir-opt-level=3" ./miri test # "miri test" has built the sysroot for us, now this should pass without # any interactive questions. test-cargo-miri/run-test.py From 1b8979c8c7fc03bd5b9a686d87b6970232099fd6 Mon Sep 17 00:00:00 2001 From: Elichai Turkel Date: Wed, 18 Mar 2020 13:16:37 +0200 Subject: [PATCH 1660/3747] Add an optional message to abort --- src/diagnostics.rs | 3 ++- src/eval.rs | 2 +- src/machine.rs | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/diagnostics.rs b/src/diagnostics.rs index fb6598495af5e..b2590a843ba96 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -20,7 +20,8 @@ pub fn report_diagnostic<'tcx, 'mir>( let info = info.downcast_ref::().expect("invalid MachineStop payload"); match info { TerminationInfo::Exit(code) => return Some(*code), - TerminationInfo::Abort => format!("the evaluated program aborted execution"), + TerminationInfo::Abort(None) => format!("the evaluated program aborted execution"), + TerminationInfo::Abort(Some(msg)) => format!("the evaluated program aborted execution: {}", msg), } } err_unsup!(NoMirFor(..)) => format!( diff --git a/src/eval.rs b/src/eval.rs index 2cf5a1dc444c2..7d42db6894328 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -53,7 +53,7 @@ impl Default for MiriConfig { /// Details of premature program termination. pub enum TerminationInfo { Exit(i64), - Abort, + Abort(Option), } /// Returns a freshly created `InterpCx`, along with an `MPlaceTy` representing diff --git a/src/machine.rs b/src/machine.rs index d94c6928cfe04..3a8e7fc902413 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -273,7 +273,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { #[inline(always)] fn abort(_ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx, !> { - throw_machine_stop!(TerminationInfo::Abort) + throw_machine_stop!(TerminationInfo::Abort(None)) } #[inline(always)] From 52e1372e038d0372c7435b50e7d6e98a15b9a02f Mon Sep 17 00:00:00 2001 From: Elichai Turkel Date: Wed, 18 Mar 2020 13:17:18 +0200 Subject: [PATCH 1661/3747] Abort instead of panic in asserting intrinsics, because they might not be panic safe --- src/shims/intrinsics.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index b91af778d9791..112b4f3c0040f 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -440,15 +440,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "assert_uninit_valid" => { let ty = substs.type_at(0); let layout = this.layout_of(ty)?; - // Return here because we panicked instead of returning normally from the intrinsic. + // Abort here because the caller might not be panic safe. if layout.abi.is_uninhabited() { - return this.start_panic(&format!("attempted to instantiate uninhabited type `{}`", ty), unwind); + throw_machine_stop!(TerminationInfo::Abort(Some(format!("attempted to instantiate uninhabited type `{}`", ty)))) } if intrinsic_name == "assert_zero_valid" && !layout.might_permit_raw_init(this, /*zero:*/ true).unwrap() { - return this.start_panic(&format!("attempted to zero-initialize type `{}`, which is invalid", ty), unwind); + throw_machine_stop!(TerminationInfo::Abort(Some(format!("attempted to zero-initialize type `{}`, which is invalid", ty)))) } if intrinsic_name == "assert_uninit_valid" && !layout.might_permit_raw_init(this, /*zero:*/ false).unwrap() { - return this.start_panic(&format!("attempted to leave type `{}` uninitialized, which is invalid", ty), unwind); + throw_machine_stop!(TerminationInfo::Abort(Some(format!("attempted to leave type `{}` uninitialized, which is invalid", ty)))) } } From 0826899ca04af6700269bde37137ab41d2f4dae5 Mon Sep 17 00:00:00 2001 From: Elichai Turkel Date: Wed, 18 Mar 2020 13:18:08 +0200 Subject: [PATCH 1662/3747] Remove uninhabit/zeroed tests to a new test file for abort checking --- tests/compile-fail/invalid_zero_init.rs | 6 +++ tests/compile-fail/uninit_uninhabited_type.rs | 7 ++++ tests/run-pass/panic/catch_panic.rs | 37 ------------------- tests/run-pass/panic/catch_panic.stderr | 20 +--------- 4 files changed, 15 insertions(+), 55 deletions(-) create mode 100644 tests/compile-fail/invalid_zero_init.rs create mode 100644 tests/compile-fail/uninit_uninhabited_type.rs diff --git a/tests/compile-fail/invalid_zero_init.rs b/tests/compile-fail/invalid_zero_init.rs new file mode 100644 index 0000000000000..78c2b0fbeeb72 --- /dev/null +++ b/tests/compile-fail/invalid_zero_init.rs @@ -0,0 +1,6 @@ + // error-pattern: the evaluated program aborted execution: attempted to zero-initialize type `fn()`, which is invalid + +#[allow(deprecated, invalid_value)] +fn main() { + unsafe { std::mem::zeroed::() }; +} diff --git a/tests/compile-fail/uninit_uninhabited_type.rs b/tests/compile-fail/uninit_uninhabited_type.rs new file mode 100644 index 0000000000000..b9048830783f8 --- /dev/null +++ b/tests/compile-fail/uninit_uninhabited_type.rs @@ -0,0 +1,7 @@ + // error-pattern: the evaluated program aborted execution: attempted to instantiate uninhabited type `!` +#![feature(never_type)] + +#[allow(deprecated, invalid_value)] +fn main() { + unsafe { std::mem::uninitialized::() }; +} diff --git a/tests/run-pass/panic/catch_panic.rs b/tests/run-pass/panic/catch_panic.rs index cc97ba5a85d29..6408c940d98a4 100644 --- a/tests/run-pass/panic/catch_panic.rs +++ b/tests/run-pass/panic/catch_panic.rs @@ -67,43 +67,6 @@ fn main() { |_old_val| { let _val = 1/0; loop {} }, ); - // libcore panics from shims. - #[allow(deprecated, invalid_value)] - { - test( - Some("attempted to instantiate uninhabited type `!`"), - |_old_val| unsafe { std::mem::uninitialized::() }, - ); - test( - Some("attempted to instantiate uninhabited type `!`"), - |_old_val| unsafe { std::mem::zeroed::() }, - ); - test( - Some("attempted to leave type `fn()` uninitialized, which is invalid"), - |_old_val| unsafe { std::mem::uninitialized::(); loop {} }, - ); - test( - Some("attempted to zero-initialize type `fn()`, which is invalid"), - |_old_val| unsafe { std::mem::zeroed::(); loop {} }, - ); - test( - Some("attempted to leave type `*const dyn std::marker::Sync` uninitialized, which is invalid"), - |_old_val| unsafe { std::mem::uninitialized::<*const dyn Sync>(); loop {} }, - ); - test( - Some("attempted to zero-initialize type `*mut dyn std::marker::Sync`, which is invalid"), - |_old_val| unsafe { std::mem::zeroed::<*mut dyn Sync>(); loop {} }, - ); - test( - Some("attempted to leave type `&u8` uninitialized, which is invalid"), - |_old_val| unsafe { std::mem::uninitialized::<&u8>(); loop {} }, - ); - test( - Some("attempted to zero-initialize type `&u8`, which is invalid"), - |_old_val| unsafe { std::mem::zeroed::<&u8>(); loop {} }, - ); - } - test( Some("align_offset: align is not a power-of-two"), |_old_val| { (0usize as *const u8).align_offset(3); loop {} }, diff --git a/tests/run-pass/panic/catch_panic.stderr b/tests/run-pass/panic/catch_panic.stderr index 8d97fd6321f18..6da9cd29963a6 100644 --- a/tests/run-pass/panic/catch_panic.stderr +++ b/tests/run-pass/panic/catch_panic.stderr @@ -16,27 +16,11 @@ thread 'main' panicked at 'index out of bounds: the len is 3 but the index is 4' Caught panic message (String): index out of bounds: the len is 3 but the index is 4 thread 'main' panicked at 'attempt to divide by zero', $DIR/catch_panic.rs:67:33 Caught panic message (String): attempt to divide by zero -thread 'main' panicked at 'attempted to instantiate uninhabited type `!`', $LOC -Caught panic message (String): attempted to instantiate uninhabited type `!` -thread 'main' panicked at 'attempted to instantiate uninhabited type `!`', $LOC -Caught panic message (String): attempted to instantiate uninhabited type `!` -thread 'main' panicked at 'attempted to leave type `fn()` uninitialized, which is invalid', $LOC -Caught panic message (String): attempted to leave type `fn()` uninitialized, which is invalid -thread 'main' panicked at 'attempted to zero-initialize type `fn()`, which is invalid', $LOC -Caught panic message (String): attempted to zero-initialize type `fn()`, which is invalid -thread 'main' panicked at 'attempted to leave type `*const dyn std::marker::Sync` uninitialized, which is invalid', $LOC -Caught panic message (String): attempted to leave type `*const dyn std::marker::Sync` uninitialized, which is invalid -thread 'main' panicked at 'attempted to zero-initialize type `*mut dyn std::marker::Sync`, which is invalid', $LOC -Caught panic message (String): attempted to zero-initialize type `*mut dyn std::marker::Sync`, which is invalid -thread 'main' panicked at 'attempted to leave type `&u8` uninitialized, which is invalid', $LOC -Caught panic message (String): attempted to leave type `&u8` uninitialized, which is invalid -thread 'main' panicked at 'attempted to zero-initialize type `&u8`, which is invalid', $LOC -Caught panic message (String): attempted to zero-initialize type `&u8`, which is invalid thread 'main' panicked at 'align_offset: align is not a power-of-two', $LOC Caught panic message (String): align_offset: align is not a power-of-two -thread 'main' panicked at 'assertion failed: false', $DIR/catch_panic.rs:113:29 +thread 'main' panicked at 'assertion failed: false', $DIR/catch_panic.rs:76:29 Caught panic message (&str): assertion failed: false -thread 'main' panicked at 'assertion failed: false', $DIR/catch_panic.rs:114:29 +thread 'main' panicked at 'assertion failed: false', $DIR/catch_panic.rs:77:29 Caught panic message (&str): assertion failed: false thread 'main' panicked at 'attempt to copy from unaligned or null pointer', $LOC Caught panic message (String): attempt to copy from unaligned or null pointer From 1103a10e2c1c9d3c6d9aeafb5154a5f5ef0495ea Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 8 Mar 2020 23:34:54 +0100 Subject: [PATCH 1663/3747] adjust for error reform --- src/helpers.rs | 3 +- src/intptrcast.rs | 8 +--- src/shims/foreign_items.rs | 41 ++++++++----------- src/shims/foreign_items/posix.rs | 11 ++--- src/shims/foreign_items/windows.rs | 9 +--- src/shims/tls.rs | 18 +++++--- tests/compile-fail/alignment.rs | 2 +- tests/compile-fail/atomic_unaligned.rs | 2 +- tests/compile-fail/cast_box_int_to_fn_ptr.rs | 2 +- tests/compile-fail/cast_fn_ptr1.rs | 2 +- tests/compile-fail/cast_fn_ptr2.rs | 2 +- tests/compile-fail/cast_fn_ptr3.rs | 2 +- tests/compile-fail/cast_fn_ptr4.rs | 2 +- tests/compile-fail/cast_fn_ptr5.rs | 2 +- tests/compile-fail/cast_int_to_fn_ptr.rs | 2 +- tests/compile-fail/copy_unaligned.rs | 2 +- tests/compile-fail/dangling_pointer_deref.rs | 2 +- tests/compile-fail/dangling_zst_deref.rs | 2 +- .../compile-fail/deallocate-bad-alignment.rs | 2 +- tests/compile-fail/deallocate-bad-size.rs | 2 +- tests/compile-fail/deallocate-twice.rs | 2 +- tests/compile-fail/deref-invalid-ptr.rs | 2 +- .../compile-fail/deref-partially-dangling.rs | 2 +- tests/compile-fail/deref_fn_ptr.rs | 2 +- .../compile-fail/environ-gets-deallocated.rs | 2 +- tests/compile-fail/execute_memory.rs | 2 +- tests/compile-fail/fn_ptr_offset.rs | 2 +- tests/compile-fail/generator-pinned-moved.rs | 2 +- .../intptrcast_alignment_check.rs | 2 +- tests/compile-fail/invalid_bool.rs | 2 +- tests/compile-fail/invalid_char.rs | 2 +- tests/compile-fail/modifying_constants.rs | 2 +- tests/compile-fail/out_of_bounds_ptr_1.rs | 2 +- tests/compile-fail/out_of_bounds_read1.rs | 2 +- tests/compile-fail/out_of_bounds_read2.rs | 2 +- ..._of_relocation_makes_the_rest_undefined.rs | 2 +- tests/compile-fail/pointer_byte_read.rs | 2 +- tests/compile-fail/ptr_offset_int_plus_int.rs | 2 +- tests/compile-fail/ptr_offset_int_plus_ptr.rs | 2 +- tests/compile-fail/ptr_offset_ptr_plus_0.rs | 2 +- tests/compile-fail/rc_as_raw.rs | 2 +- tests/compile-fail/reading_half_a_pointer.rs | 2 +- tests/compile-fail/reallocate-bad-size.rs | 2 +- tests/compile-fail/reallocate-change-alloc.rs | 2 +- tests/compile-fail/reallocate-dangling.rs | 2 +- tests/compile-fail/reference_to_packed.rs | 2 +- tests/compile-fail/stack_free.rs | 2 +- .../stacked_borrows/issue-miri-1050-2.rs | 2 +- .../static_memory_modification1.rs | 2 +- .../static_memory_modification2.rs | 2 +- .../static_memory_modification3.rs | 2 +- tests/compile-fail/storage_dead_dangling.rs | 2 +- tests/compile-fail/transmute-pair-undef.rs | 2 +- tests/compile-fail/transmute_fat1.rs | 2 +- tests/compile-fail/unaligned_ptr1.rs | 2 +- tests/compile-fail/unaligned_ptr2.rs | 2 +- tests/compile-fail/unaligned_ptr3.rs | 2 +- tests/compile-fail/unaligned_ptr_zst.rs | 2 +- tests/compile-fail/undefined_byte_read.rs | 2 +- tests/compile-fail/validity/dangling_ref1.rs | 2 +- tests/compile-fail/validity/dangling_ref2.rs | 2 +- tests/compile-fail/wild_pointer_deref.rs | 2 +- tests/compile-fail/zst2.rs | 2 +- 63 files changed, 93 insertions(+), 111 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index ecb3a5d8bce9c..ff4df42dde66a 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -42,8 +42,7 @@ fn resolve_did<'mir, 'tcx>(tcx: TyCtxt<'tcx>, path: &[&str]) -> InterpResult<'tc None }) .ok_or_else(|| { - let path = path.iter().map(|&s| s.to_owned()).collect(); - err_unsup!(PathNotFound(path)).into() + err_unsup_format!("failed to find required Rust item: {:?}", path).into() }) } diff --git a/src/intptrcast.rs b/src/intptrcast.rs index 91d9f4e84ee31..20a3b79980478 100644 --- a/src/intptrcast.rs +++ b/src/intptrcast.rs @@ -43,10 +43,6 @@ impl<'mir, 'tcx> GlobalState { int: u64, memory: &Memory<'mir, 'tcx, Evaluator<'tcx>>, ) -> InterpResult<'tcx, Pointer> { - if int == 0 { - throw_unsup!(InvalidNullPointerUsage); - } - let global_state = memory.extra.intptrcast.borrow(); let pos = global_state.int_to_ptr_map.binary_search_by_key(&int, |(addr, _)| *addr); @@ -57,7 +53,7 @@ impl<'mir, 'tcx> GlobalState { // zero. The pointer is untagged because it was created from a cast Pointer::new_with_tag(alloc_id, Size::from_bytes(0), Tag::Untagged) } - Err(0) => throw_unsup!(DanglingPointerDeref), + Err(0) => throw_ub!(InvalidIntPointerUsage(int)), Err(pos) => { // This is the largest of the adresses smaller than `int`, // i.e. the greatest lower bound (glb) @@ -69,7 +65,7 @@ impl<'mir, 'tcx> GlobalState { // This pointer is untagged because it was created from a cast Pointer::new_with_tag(alloc_id, Size::from_bytes(offset), Tag::Untagged) } else { - throw_unsup!(DanglingPointerDeref) + throw_ub!(InvalidIntPointerUsage(int)) } } }) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index deabbdd608193..4c7bcff267e16 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -222,12 +222,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "__rust_alloc" => { let size = this.read_scalar(args[0])?.to_machine_usize(this)?; let align = this.read_scalar(args[1])?.to_machine_usize(this)?; - if size == 0 { - throw_unsup!(HeapAllocZeroBytes); - } - if !align.is_power_of_two() { - throw_unsup!(HeapAllocNonPowerOfTwoAlignment(align)); - } + Self::check_alloc_request(size, align)?; let ptr = this.memory.allocate( Size::from_bytes(size), Align::from_bytes(align).unwrap(), @@ -238,12 +233,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "__rust_alloc_zeroed" => { let size = this.read_scalar(args[0])?.to_machine_usize(this)?; let align = this.read_scalar(args[1])?.to_machine_usize(this)?; - if size == 0 { - throw_unsup!(HeapAllocZeroBytes); - } - if !align.is_power_of_two() { - throw_unsup!(HeapAllocNonPowerOfTwoAlignment(align)); - } + Self::check_alloc_request(size, align)?; let ptr = this.memory.allocate( Size::from_bytes(size), Align::from_bytes(align).unwrap(), @@ -257,12 +247,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let ptr = this.read_scalar(args[0])?.not_undef()?; let old_size = this.read_scalar(args[1])?.to_machine_usize(this)?; let align = this.read_scalar(args[2])?.to_machine_usize(this)?; - if old_size == 0 { - throw_unsup!(HeapAllocZeroBytes); - } - if !align.is_power_of_two() { - throw_unsup!(HeapAllocNonPowerOfTwoAlignment(align)); - } + // No need to check old_size/align; we anyway check that they match the allocation. let ptr = this.force_ptr(ptr)?; this.memory.deallocate( ptr, @@ -274,12 +259,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let old_size = this.read_scalar(args[1])?.to_machine_usize(this)?; let align = this.read_scalar(args[2])?.to_machine_usize(this)?; let new_size = this.read_scalar(args[3])?.to_machine_usize(this)?; - if old_size == 0 || new_size == 0 { - throw_unsup!(HeapAllocZeroBytes); - } - if !align.is_power_of_two() { - throw_unsup!(HeapAllocNonPowerOfTwoAlignment(align)); - } + Self::check_alloc_request(new_size, align)?; + // No need to check old_size; we anyway check that they match the allocation. let ptr = this.force_ptr(this.read_scalar(args[0])?.not_undef()?)?; let align = Align::from_bytes(align).unwrap(); let new_ptr = this.memory.reallocate( @@ -462,6 +443,18 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(true) } + /// Check some basic requirements for this allocation request: + /// non-zero size, power-of-two alignment. + fn check_alloc_request(size: u64, align: u64) -> InterpResult<'tcx> { + if size == 0 { + throw_ub_format!("creating allocation with size 0"); + } + if !align.is_power_of_two() { + throw_ub_format!("creating allocation with non-power-of-two alignment {}", align); + } + Ok(()) + } + /// Evaluates the scalar at the specified path. Returns Some(val) /// if the path could be resolved, and None otherwise fn eval_path_scalar( diff --git a/src/shims/foreign_items/posix.rs b/src/shims/foreign_items/posix.rs index f73ec288284ab..60b9aa6efccab 100644 --- a/src/shims/foreign_items/posix.rs +++ b/src/shims/foreign_items/posix.rs @@ -138,7 +138,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let size = this.read_scalar(args[2])?.to_machine_usize(this)?; // Align must be power of 2, and also at least ptr-sized (POSIX rules). if !align.is_power_of_two() { - throw_unsup!(HeapAllocNonPowerOfTwoAlignment(align)); + throw_ub_format!("posix_memalign: alignment must be a power of two, but is {}", align); } if align < this.pointer_size().bytes() { throw_ub_format!( @@ -185,7 +185,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx }; // Figure out how large a pthread TLS key actually is. - // This is `libc::pthread_key_t`. + // To this end, deref the argument type. This is `libc::pthread_key_t`. let key_type = args[0].layout.ty .builtin_deref(true) .ok_or_else(|| err_ub_format!( @@ -195,12 +195,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let key_layout = this.layout_of(key_type)?; // Create key and write it into the memory where `key_ptr` wants it. - let key = this.machine.tls.create_tls_key(dtor) as u128; - if key_layout.size.bits() < 128 && key >= (1u128 << key_layout.size.bits() as u128) - { - throw_unsup!(OutOfTls); - } - + let key = this.machine.tls.create_tls_key(dtor, key_layout.size)?; this.write_scalar(Scalar::from_uint(key, key_layout.size), key_place.into())?; // Return success (`0`). diff --git a/src/shims/foreign_items/windows.rs b/src/shims/foreign_items/windows.rs index 306d2f7b0e37c..a35734573f296 100644 --- a/src/shims/foreign_items/windows.rs +++ b/src/shims/foreign_items/windows.rs @@ -154,14 +154,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // This just creates a key; Windows does not natively support TLS destructors. // Create key and return it. - let key = this.machine.tls.create_tls_key(None) 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) - { - throw_unsup!(OutOfTls); - } + let key = this.machine.tls.create_tls_key(None, dest.layout.size)?; this.write_scalar(Scalar::from_uint(key, dest.layout.size), dest)?; } "TlsGetValue" => { diff --git a/src/shims/tls.rs b/src/shims/tls.rs index cdfc0bcda8b63..094b58d99a287 100644 --- a/src/shims/tls.rs +++ b/src/shims/tls.rs @@ -2,7 +2,7 @@ use std::collections::BTreeMap; -use rustc::{ty, ty::layout::HasDataLayout}; +use rustc::{ty, ty::layout::{Size, HasDataLayout}}; use rustc_target::abi::LayoutOf; use crate::{HelpersEvalContextExt, InterpResult, MPlaceTy, Scalar, StackPopCleanup, Tag}; @@ -37,12 +37,18 @@ impl<'tcx> Default for TlsData<'tcx> { } impl<'tcx> TlsData<'tcx> { - pub fn create_tls_key(&mut self, dtor: Option>) -> TlsKey { + /// Generate a new TLS key with the given destructor. + /// `max_size` determines the integer size the key has to fit in. + pub fn create_tls_key(&mut self, dtor: Option>, max_size: Size) -> InterpResult<'tcx, TlsKey> { let new_key = self.next_key; self.next_key += 1; self.keys.insert(new_key, TlsEntry { data: None, dtor }).unwrap_none(); trace!("New TLS key allocated: {} with dtor {:?}", new_key, dtor); - new_key + + if max_size.bits() < 128 && new_key >= (1u128 << max_size.bits() as u128) { + throw_unsup_format!("we ran out of TLS key space"); + } + Ok(new_key) } pub fn delete_tls_key(&mut self, key: TlsKey) -> InterpResult<'tcx> { @@ -51,7 +57,7 @@ impl<'tcx> TlsData<'tcx> { trace!("TLS key {} removed", key); Ok(()) } - None => throw_unsup!(TlsOutOfBounds), + None => throw_ub_format!("removing a non-existig TLS key: {}", key), } } @@ -65,7 +71,7 @@ impl<'tcx> TlsData<'tcx> { trace!("TLS key {} loaded: {:?}", key, data); Ok(data.unwrap_or_else(|| Scalar::ptr_null(cx).into())) } - None => throw_unsup!(TlsOutOfBounds), + None => throw_ub_format!("loading from a non-existing TLS key: {}", key), } } @@ -76,7 +82,7 @@ impl<'tcx> TlsData<'tcx> { *data = new_data; Ok(()) } - None => throw_unsup!(TlsOutOfBounds), + None => throw_ub_format!("storing to a non-existing TLS key: {}", key), } } diff --git a/tests/compile-fail/alignment.rs b/tests/compile-fail/alignment.rs index 4faaa359df624..bac1b92075a76 100644 --- a/tests/compile-fail/alignment.rs +++ b/tests/compile-fail/alignment.rs @@ -5,7 +5,7 @@ fn main() { let x_ptr: *mut u8 = &mut x[0]; let y_ptr = x_ptr as *mut u64; unsafe { - *y_ptr = 42; //~ ERROR tried to access memory with alignment 1, but alignment + *y_ptr = 42; //~ ERROR accessing memory with alignment 1, but alignment } panic!("unreachable in miri"); } diff --git a/tests/compile-fail/atomic_unaligned.rs b/tests/compile-fail/atomic_unaligned.rs index 5d2347c03ffee..bdec0ff504bb6 100644 --- a/tests/compile-fail/atomic_unaligned.rs +++ b/tests/compile-fail/atomic_unaligned.rs @@ -7,6 +7,6 @@ fn main() { let zptr = &z as *const _ as *const u64; unsafe { ::std::intrinsics::atomic_load(zptr); - //~^ ERROR tried to access memory with alignment 4, but alignment 8 is required + //~^ ERROR accessing memory with alignment 4, but alignment 8 is required } } diff --git a/tests/compile-fail/cast_box_int_to_fn_ptr.rs b/tests/compile-fail/cast_box_int_to_fn_ptr.rs index 6dad2a4727306..9eea9d92dcd76 100644 --- a/tests/compile-fail/cast_box_int_to_fn_ptr.rs +++ b/tests/compile-fail/cast_box_int_to_fn_ptr.rs @@ -7,5 +7,5 @@ fn main() { std::mem::transmute::<&Box, &fn(i32)>(&b) }; - (*g)(42) //~ ERROR tried to treat a memory pointer as a function pointer + (*g)(42) //~ ERROR it does not point to a function } diff --git a/tests/compile-fail/cast_fn_ptr1.rs b/tests/compile-fail/cast_fn_ptr1.rs index 0add977bf97b4..3702ec8c94c43 100644 --- a/tests/compile-fail/cast_fn_ptr1.rs +++ b/tests/compile-fail/cast_fn_ptr1.rs @@ -5,5 +5,5 @@ fn main() { std::mem::transmute::(f) }; - g(42) //~ ERROR tried to call a function with incorrect number of arguments + g(42) //~ ERROR calling a function with more arguments than it expected } diff --git a/tests/compile-fail/cast_fn_ptr2.rs b/tests/compile-fail/cast_fn_ptr2.rs index 5af527016fb6f..39f0867489adc 100644 --- a/tests/compile-fail/cast_fn_ptr2.rs +++ b/tests/compile-fail/cast_fn_ptr2.rs @@ -5,5 +5,5 @@ fn main() { std::mem::transmute::(f) }; - g(42) //~ ERROR tried to call a function with argument of type (i32, i32) passing data of type i32 + g(42) //~ ERROR calling a function with argument of type (i32, i32) passing data of type i32 } diff --git a/tests/compile-fail/cast_fn_ptr3.rs b/tests/compile-fail/cast_fn_ptr3.rs index 29507e7c7cf54..3523db24fa320 100644 --- a/tests/compile-fail/cast_fn_ptr3.rs +++ b/tests/compile-fail/cast_fn_ptr3.rs @@ -5,6 +5,6 @@ fn main() { std::mem::transmute::(f) }; - g() //~ ERROR tried to call a function with incorrect number of arguments + g() //~ ERROR calling a function with fewer arguments than it requires } diff --git a/tests/compile-fail/cast_fn_ptr4.rs b/tests/compile-fail/cast_fn_ptr4.rs index f9a2cf9f6965e..22a36a71cef14 100644 --- a/tests/compile-fail/cast_fn_ptr4.rs +++ b/tests/compile-fail/cast_fn_ptr4.rs @@ -5,5 +5,5 @@ fn main() { std::mem::transmute::(f) }; - g(&42 as *const i32) //~ ERROR tried to call a function with argument of type *const [i32] passing data of type *const i32 + g(&42 as *const i32) //~ ERROR calling a function with argument of type *const [i32] passing data of type *const i32 } diff --git a/tests/compile-fail/cast_fn_ptr5.rs b/tests/compile-fail/cast_fn_ptr5.rs index e4ac95e676764..fb2b4403363ef 100644 --- a/tests/compile-fail/cast_fn_ptr5.rs +++ b/tests/compile-fail/cast_fn_ptr5.rs @@ -5,5 +5,5 @@ fn main() { std::mem::transmute:: u32, fn()>(f) }; - g() //~ ERROR tried to call a function with return type u32 passing return place of type () + g() //~ ERROR calling a function with return type u32 passing return place of type () } diff --git a/tests/compile-fail/cast_int_to_fn_ptr.rs b/tests/compile-fail/cast_int_to_fn_ptr.rs index 4fd14751a279a..3000779a93307 100644 --- a/tests/compile-fail/cast_int_to_fn_ptr.rs +++ b/tests/compile-fail/cast_int_to_fn_ptr.rs @@ -6,5 +6,5 @@ fn main() { std::mem::transmute::(42) }; - g(42) //~ ERROR dangling pointer was dereferenced + g(42) //~ ERROR invalid use of 42 as a pointer } diff --git a/tests/compile-fail/copy_unaligned.rs b/tests/compile-fail/copy_unaligned.rs index 1a2692978f797..a2a4762239184 100644 --- a/tests/compile-fail/copy_unaligned.rs +++ b/tests/compile-fail/copy_unaligned.rs @@ -1,4 +1,4 @@ -//error-pattern: tried to access memory with alignment 1, but alignment 2 is required +//error-pattern: accessing memory with alignment 1, but alignment 2 is required #![feature(intrinsics)] // Directly call intrinsic to avoid debug assertions in libstd diff --git a/tests/compile-fail/dangling_pointer_deref.rs b/tests/compile-fail/dangling_pointer_deref.rs index e807207730573..f2c7ec584fefb 100644 --- a/tests/compile-fail/dangling_pointer_deref.rs +++ b/tests/compile-fail/dangling_pointer_deref.rs @@ -3,6 +3,6 @@ fn main() { let b = Box::new(42); &*b as *const i32 }; - let x = unsafe { *p }; //~ ERROR dangling pointer was dereferenced + let x = unsafe { *p }; //~ ERROR dereferenced after this allocation got freed panic!("this should never print: {}", x); } diff --git a/tests/compile-fail/dangling_zst_deref.rs b/tests/compile-fail/dangling_zst_deref.rs index 0a8480675f3d4..13e5f9d321735 100644 --- a/tests/compile-fail/dangling_zst_deref.rs +++ b/tests/compile-fail/dangling_zst_deref.rs @@ -3,5 +3,5 @@ fn main() { let b = Box::new(42); &*b as *const i32 as *const () }; - let _x = unsafe { *p }; //~ ERROR dangling pointer was dereferenced + let _x = unsafe { *p }; //~ ERROR dereferenced after this allocation got freed } diff --git a/tests/compile-fail/deallocate-bad-alignment.rs b/tests/compile-fail/deallocate-bad-alignment.rs index 876339919717a..f2cd87bac6229 100644 --- a/tests/compile-fail/deallocate-bad-alignment.rs +++ b/tests/compile-fail/deallocate-bad-alignment.rs @@ -5,7 +5,7 @@ extern crate alloc; use alloc::alloc::Global; use std::alloc::{AllocRef, Layout}; -// error-pattern: incorrect alloc info: expected size 1 and align 2, got size 1 and align 1 +// error-pattern: allocation has size 1 and alignment 1, but gave size 1 and alignment 2 fn main() { unsafe { diff --git a/tests/compile-fail/deallocate-bad-size.rs b/tests/compile-fail/deallocate-bad-size.rs index 3b7b3cc6a7262..498a662518e52 100644 --- a/tests/compile-fail/deallocate-bad-size.rs +++ b/tests/compile-fail/deallocate-bad-size.rs @@ -5,7 +5,7 @@ extern crate alloc; use alloc::alloc::Global; use std::alloc::{AllocRef, Layout}; -// error-pattern: incorrect alloc info: expected size 2 and align 1, got size 1 and align 1 +// error-pattern: allocation has size 1 and alignment 1, but gave size 2 and alignment 1 fn main() { unsafe { diff --git a/tests/compile-fail/deallocate-twice.rs b/tests/compile-fail/deallocate-twice.rs index ee4c5dbedf90d..a851d75b9d5c5 100644 --- a/tests/compile-fail/deallocate-twice.rs +++ b/tests/compile-fail/deallocate-twice.rs @@ -5,7 +5,7 @@ extern crate alloc; use alloc::alloc::Global; use std::alloc::{AllocRef, Layout}; -// error-pattern: tried to deallocate dangling pointer +// error-pattern: dereferenced after this allocation got freed fn main() { unsafe { diff --git a/tests/compile-fail/deref-invalid-ptr.rs b/tests/compile-fail/deref-invalid-ptr.rs index 2a8be87e1251e..561017293a165 100644 --- a/tests/compile-fail/deref-invalid-ptr.rs +++ b/tests/compile-fail/deref-invalid-ptr.rs @@ -3,5 +3,5 @@ fn main() { let x = 2usize as *const u32; - let _y = unsafe { &*x as *const u32 }; //~ ERROR dangling pointer was dereferenced + let _y = unsafe { &*x as *const u32 }; //~ ERROR invalid use of 2 as a pointer } diff --git a/tests/compile-fail/deref-partially-dangling.rs b/tests/compile-fail/deref-partially-dangling.rs index 221e585c5ff38..a6d3aae414de0 100644 --- a/tests/compile-fail/deref-partially-dangling.rs +++ b/tests/compile-fail/deref-partially-dangling.rs @@ -3,6 +3,6 @@ fn main() { let x = (1, 13); let xptr = &x as *const _ as *const (i32, i32, i32); - let val = unsafe { (*xptr).1 }; //~ ERROR pointer must be in-bounds at offset 12, but is outside bounds of allocation + let val = unsafe { (*xptr).1 }; //~ ERROR pointer must be in-bounds at offset 12, but is outside bounds of alloc assert_eq!(val, 13); } diff --git a/tests/compile-fail/deref_fn_ptr.rs b/tests/compile-fail/deref_fn_ptr.rs index ed2ac60f43fe3..e604f96ea16f1 100644 --- a/tests/compile-fail/deref_fn_ptr.rs +++ b/tests/compile-fail/deref_fn_ptr.rs @@ -2,7 +2,7 @@ fn f() {} fn main() { let x: u8 = unsafe { - *std::mem::transmute::(f) //~ ERROR tried to dereference a function pointer + *std::mem::transmute::(f) //~ ERROR contains a function }; panic!("this should never print: {}", x); } diff --git a/tests/compile-fail/environ-gets-deallocated.rs b/tests/compile-fail/environ-gets-deallocated.rs index 6131613fc00bb..dd00aef450cd9 100644 --- a/tests/compile-fail/environ-gets-deallocated.rs +++ b/tests/compile-fail/environ-gets-deallocated.rs @@ -20,5 +20,5 @@ fn main() { let pointer = get_environ(); let _x = unsafe { *pointer }; std::env::set_var("FOO", "BAR"); - let _y = unsafe { *pointer }; //~ ERROR dangling pointer was dereferenced + let _y = unsafe { *pointer }; //~ ERROR dereferenced after this allocation got freed } diff --git a/tests/compile-fail/execute_memory.rs b/tests/compile-fail/execute_memory.rs index 295756ef0f561..2e6b58a753cd9 100644 --- a/tests/compile-fail/execute_memory.rs +++ b/tests/compile-fail/execute_memory.rs @@ -7,6 +7,6 @@ fn main() { let x = box 42; unsafe { let f = std::mem::transmute::, fn()>(x); - f() //~ ERROR tried to treat a memory pointer as a function pointer + f() //~ ERROR function pointer but it does not point to a function } } diff --git a/tests/compile-fail/fn_ptr_offset.rs b/tests/compile-fail/fn_ptr_offset.rs index 9d29316fe24fe..7e509d53c2614 100644 --- a/tests/compile-fail/fn_ptr_offset.rs +++ b/tests/compile-fail/fn_ptr_offset.rs @@ -10,5 +10,5 @@ fn main() { let y : *mut u8 = unsafe { mem::transmute(x) }; let y = y.wrapping_offset(1); let x : fn() = unsafe { mem::transmute(y) }; - x(); //~ ERROR tried to use a function pointer after offsetting it + x(); //~ ERROR function pointer but it does not point to a function } diff --git a/tests/compile-fail/generator-pinned-moved.rs b/tests/compile-fail/generator-pinned-moved.rs index 70ceacd8ca6fa..8f873f37a5f80 100644 --- a/tests/compile-fail/generator-pinned-moved.rs +++ b/tests/compile-fail/generator-pinned-moved.rs @@ -11,7 +11,7 @@ fn firstn() -> impl Generator { let num = &mut num; yield *num; - *num += 1; //~ ERROR dangling pointer was dereferenced + *num += 1; //~ ERROR dereferenced after this allocation got freed } } diff --git a/tests/compile-fail/intptrcast_alignment_check.rs b/tests/compile-fail/intptrcast_alignment_check.rs index fcf613ace4627..1a8df5eacede8 100644 --- a/tests/compile-fail/intptrcast_alignment_check.rs +++ b/tests/compile-fail/intptrcast_alignment_check.rs @@ -7,6 +7,6 @@ fn main() { let base_addr = x as *mut _ as usize; let base_addr_aligned = if base_addr % 2 == 0 { base_addr } else { base_addr+1 }; let u16_ptr = base_addr_aligned as *mut u16; - unsafe { *u16_ptr = 2; } //~ ERROR tried to access memory with alignment 1, but alignment 2 is required + unsafe { *u16_ptr = 2; } //~ ERROR memory with alignment 1, but alignment 2 is required println!("{:?}", x); } diff --git a/tests/compile-fail/invalid_bool.rs b/tests/compile-fail/invalid_bool.rs index e80dc15efaec9..6ccea35316365 100644 --- a/tests/compile-fail/invalid_bool.rs +++ b/tests/compile-fail/invalid_bool.rs @@ -3,5 +3,5 @@ fn main() { let b = unsafe { std::mem::transmute::(2) }; - let _x = b == true; //~ ERROR invalid boolean value read + let _x = b == true; //~ ERROR interpreting an invalid 8-bit value as a bool: 2 } diff --git a/tests/compile-fail/invalid_char.rs b/tests/compile-fail/invalid_char.rs index b67ed9ba520d2..ed61fcbe9d52f 100644 --- a/tests/compile-fail/invalid_char.rs +++ b/tests/compile-fail/invalid_char.rs @@ -4,5 +4,5 @@ fn main() { assert!(std::char::from_u32(-1_i32 as u32).is_none()); let c = unsafe { std::mem::transmute::(-1) }; - let _x = c == 'x'; //~ ERROR tried to interpret an invalid 32-bit value as a char + let _x = c == 'x'; //~ ERROR interpreting an invalid 32-bit value as a char } diff --git a/tests/compile-fail/modifying_constants.rs b/tests/compile-fail/modifying_constants.rs index 9770917b629be..2d18dccd319c3 100644 --- a/tests/compile-fail/modifying_constants.rs +++ b/tests/compile-fail/modifying_constants.rs @@ -4,6 +4,6 @@ fn main() { let x = &1; // the `&1` is promoted to a constant, but it used to be that only the pointer is marked static, not the pointee let y = unsafe { &mut *(x as *const i32 as *mut i32) }; - *y = 42; //~ ERROR tried to modify constant memory + *y = 42; //~ ERROR read-only assert_eq!(*x, 42); } diff --git a/tests/compile-fail/out_of_bounds_ptr_1.rs b/tests/compile-fail/out_of_bounds_ptr_1.rs index b466093053689..20bcc36f049d1 100644 --- a/tests/compile-fail/out_of_bounds_ptr_1.rs +++ b/tests/compile-fail/out_of_bounds_ptr_1.rs @@ -1,4 +1,4 @@ -// error-pattern: must be in-bounds at offset 5, but is outside bounds of allocation +// error-pattern: must be in-bounds at offset 5, but is outside bounds of alloc fn main() { let v = [0i8; 4]; let x = &v as *const i8; diff --git a/tests/compile-fail/out_of_bounds_read1.rs b/tests/compile-fail/out_of_bounds_read1.rs index 1ab2d97147792..0c175af5266b8 100644 --- a/tests/compile-fail/out_of_bounds_read1.rs +++ b/tests/compile-fail/out_of_bounds_read1.rs @@ -1,5 +1,5 @@ fn main() { let v: Vec = vec![1, 2]; - let x = unsafe { *v.as_ptr().wrapping_offset(5) }; //~ ERROR outside bounds of allocation + let x = unsafe { *v.as_ptr().wrapping_offset(5) }; //~ ERROR outside bounds of alloc panic!("this should never print: {}", x); } diff --git a/tests/compile-fail/out_of_bounds_read2.rs b/tests/compile-fail/out_of_bounds_read2.rs index 1ab2d97147792..0c175af5266b8 100644 --- a/tests/compile-fail/out_of_bounds_read2.rs +++ b/tests/compile-fail/out_of_bounds_read2.rs @@ -1,5 +1,5 @@ fn main() { let v: Vec = vec![1, 2]; - let x = unsafe { *v.as_ptr().wrapping_offset(5) }; //~ ERROR outside bounds of allocation + let x = unsafe { *v.as_ptr().wrapping_offset(5) }; //~ ERROR outside bounds of alloc panic!("this should never print: {}", x); } diff --git a/tests/compile-fail/overwriting_part_of_relocation_makes_the_rest_undefined.rs b/tests/compile-fail/overwriting_part_of_relocation_makes_the_rest_undefined.rs index 5c0d5b463d51f..d8182aaae662e 100644 --- a/tests/compile-fail/overwriting_part_of_relocation_makes_the_rest_undefined.rs +++ b/tests/compile-fail/overwriting_part_of_relocation_makes_the_rest_undefined.rs @@ -6,6 +6,6 @@ fn main() { // "attempted to interpret some raw bytes as a pointer address" instead of // "attempted to read undefined bytes" } - let x = *p; //~ ERROR attempted to read undefined bytes + let x = *p; //~ ERROR this operation requires initialized memory panic!("this should never print: {}", x); } diff --git a/tests/compile-fail/pointer_byte_read.rs b/tests/compile-fail/pointer_byte_read.rs index ddb9bc1f995f2..2ac27bf2b44da 100644 --- a/tests/compile-fail/pointer_byte_read.rs +++ b/tests/compile-fail/pointer_byte_read.rs @@ -3,5 +3,5 @@ fn main() { let y = &x; let z = &y as *const &i32 as *const u8; // the deref fails, because we are reading only a part of the pointer - let _val = unsafe { *z }; //~ ERROR tried to access part of a pointer value as raw bytes + let _val = unsafe { *z }; //~ ERROR unable to turn this pointer into raw bytes } diff --git a/tests/compile-fail/ptr_offset_int_plus_int.rs b/tests/compile-fail/ptr_offset_int_plus_int.rs index 051874696b116..f0cf00884e15b 100644 --- a/tests/compile-fail/ptr_offset_int_plus_int.rs +++ b/tests/compile-fail/ptr_offset_int_plus_int.rs @@ -1,4 +1,4 @@ -// error-pattern: dangling pointer was dereferenced +// error-pattern: invalid use of 1 as a pointer fn main() { // Can't offset an integer pointer by non-zero offset. diff --git a/tests/compile-fail/ptr_offset_int_plus_ptr.rs b/tests/compile-fail/ptr_offset_int_plus_ptr.rs index bd90d06909177..705ca68970a1a 100644 --- a/tests/compile-fail/ptr_offset_int_plus_ptr.rs +++ b/tests/compile-fail/ptr_offset_int_plus_ptr.rs @@ -1,4 +1,4 @@ -// error-pattern: dangling pointer was dereferenced +// error-pattern: invalid use of 1 as a pointer fn main() { let ptr = Box::into_raw(Box::new(0u32)); diff --git a/tests/compile-fail/ptr_offset_ptr_plus_0.rs b/tests/compile-fail/ptr_offset_ptr_plus_0.rs index a089a8b821316..d07ecc4dc7f31 100644 --- a/tests/compile-fail/ptr_offset_ptr_plus_0.rs +++ b/tests/compile-fail/ptr_offset_ptr_plus_0.rs @@ -1,4 +1,4 @@ -// error-pattern: outside bounds of allocation +// error-pattern: outside bounds of alloc fn main() { let x = Box::into_raw(Box::new(0u32)); diff --git a/tests/compile-fail/rc_as_raw.rs b/tests/compile-fail/rc_as_raw.rs index 086467eea311b..cb50ca5fcece0 100644 --- a/tests/compile-fail/rc_as_raw.rs +++ b/tests/compile-fail/rc_as_raw.rs @@ -17,5 +17,5 @@ fn main() { drop(strong); // But not any more. We can do Weak::as_raw(&weak), but accessing the pointer would lead to // undefined behaviour. - assert_eq!(42, **unsafe { &*Weak::as_raw(&weak) }); //~ ERROR dangling pointer + assert_eq!(42, **unsafe { &*Weak::as_raw(&weak) }); //~ ERROR dereferenced after this allocation got freed } diff --git a/tests/compile-fail/reading_half_a_pointer.rs b/tests/compile-fail/reading_half_a_pointer.rs index f8e9e5781e39d..5554d0c49a110 100644 --- a/tests/compile-fail/reading_half_a_pointer.rs +++ b/tests/compile-fail/reading_half_a_pointer.rs @@ -24,6 +24,6 @@ fn main() { // starts 1 byte to the right, so using it would actually be wrong! let d_alias = &mut w.data as *mut _ as *mut *const u8; unsafe { - let _x = *d_alias; //~ ERROR tried to access part of a pointer value as raw bytes + let _x = *d_alias; //~ ERROR unable to turn this pointer into raw bytes } } diff --git a/tests/compile-fail/reallocate-bad-size.rs b/tests/compile-fail/reallocate-bad-size.rs index f7117dbb646d3..a62c1adae7e64 100644 --- a/tests/compile-fail/reallocate-bad-size.rs +++ b/tests/compile-fail/reallocate-bad-size.rs @@ -5,7 +5,7 @@ extern crate alloc; use alloc::alloc::Global; use std::alloc::{AllocRef, Layout}; -// error-pattern: incorrect alloc info: expected size 2 and align 1, got size 1 and align 1 +// error-pattern: allocation has size 1 and alignment 1, but gave size 2 and alignment 1 fn main() { unsafe { diff --git a/tests/compile-fail/reallocate-change-alloc.rs b/tests/compile-fail/reallocate-change-alloc.rs index df517f9c81f2f..0d4b60e0a336f 100644 --- a/tests/compile-fail/reallocate-change-alloc.rs +++ b/tests/compile-fail/reallocate-change-alloc.rs @@ -9,6 +9,6 @@ fn main() { unsafe { let x = Global.alloc(Layout::from_size_align_unchecked(1, 1)).unwrap().0; Global.realloc(x, Layout::from_size_align_unchecked(1, 1), 1).unwrap(); - let _z = *(x.as_ptr() as *mut u8); //~ ERROR dangling pointer was dereferenced + let _z = *(x.as_ptr() as *mut u8); //~ ERROR dereferenced after this allocation got freed } } diff --git a/tests/compile-fail/reallocate-dangling.rs b/tests/compile-fail/reallocate-dangling.rs index 19a9017e71b87..9661d7e966746 100644 --- a/tests/compile-fail/reallocate-dangling.rs +++ b/tests/compile-fail/reallocate-dangling.rs @@ -5,7 +5,7 @@ extern crate alloc; use alloc::alloc::Global; use std::alloc::{AllocRef, Layout}; -// error-pattern: dangling pointer was dereferenced +// error-pattern: dereferenced after this allocation got freed fn main() { unsafe { diff --git a/tests/compile-fail/reference_to_packed.rs b/tests/compile-fail/reference_to_packed.rs index 030353c2cedb3..08104e917d212 100644 --- a/tests/compile-fail/reference_to_packed.rs +++ b/tests/compile-fail/reference_to_packed.rs @@ -15,5 +15,5 @@ fn main() { y: 99, }; let p = unsafe { &foo.x }; - let i = *p; //~ ERROR tried to access memory with alignment 1, but alignment 4 is required + let i = *p; //~ ERROR memory with alignment 1, but alignment 4 is required } diff --git a/tests/compile-fail/stack_free.rs b/tests/compile-fail/stack_free.rs index b8ed2e3f1f35d..ea09d3e2b44a6 100644 --- a/tests/compile-fail/stack_free.rs +++ b/tests/compile-fail/stack_free.rs @@ -1,7 +1,7 @@ // Validation/SB changes why we fail // compile-flags: -Zmiri-disable-validation -Zmiri-disable-stacked-borrows -// error-pattern: tried to deallocate `Stack` memory but gave `Machine(Rust)` as the kind +// error-pattern: deallocating `Stack` memory using `Machine(Rust)` deallocation operation fn main() { let x = 42; diff --git a/tests/compile-fail/stacked_borrows/issue-miri-1050-2.rs b/tests/compile-fail/stacked_borrows/issue-miri-1050-2.rs index 74aab153ea90f..69f19651e540d 100644 --- a/tests/compile-fail/stacked_borrows/issue-miri-1050-2.rs +++ b/tests/compile-fail/stacked_borrows/issue-miri-1050-2.rs @@ -1,4 +1,4 @@ -// error-pattern: dangling pointer was dereferenced +// error-pattern: invalid use of 4 as a pointer use std::ptr::NonNull; fn main() { unsafe { diff --git a/tests/compile-fail/static_memory_modification1.rs b/tests/compile-fail/static_memory_modification1.rs index a7bb33431e721..6284fec1601ad 100644 --- a/tests/compile-fail/static_memory_modification1.rs +++ b/tests/compile-fail/static_memory_modification1.rs @@ -6,7 +6,7 @@ static X: usize = 5; #[allow(mutable_transmutes)] fn main() { unsafe { - *std::mem::transmute::<&usize, &mut usize>(&X) = 6; //~ ERROR tried to modify constant memory + *std::mem::transmute::<&usize, &mut usize>(&X) = 6; //~ ERROR read-only assert_eq!(X, 6); } } diff --git a/tests/compile-fail/static_memory_modification2.rs b/tests/compile-fail/static_memory_modification2.rs index 065206a60dbff..558070d8a7917 100644 --- a/tests/compile-fail/static_memory_modification2.rs +++ b/tests/compile-fail/static_memory_modification2.rs @@ -7,6 +7,6 @@ use std::mem::transmute; fn main() { unsafe { let s = "this is a test"; - transmute::<&[u8], &mut [u8]>(s.as_bytes())[4] = 42; //~ ERROR tried to modify constant memory + transmute::<&[u8], &mut [u8]>(s.as_bytes())[4] = 42; //~ ERROR read-only } } diff --git a/tests/compile-fail/static_memory_modification3.rs b/tests/compile-fail/static_memory_modification3.rs index 94f88205073e2..93df1c5945344 100644 --- a/tests/compile-fail/static_memory_modification3.rs +++ b/tests/compile-fail/static_memory_modification3.rs @@ -7,6 +7,6 @@ use std::mem::transmute; fn main() { unsafe { let bs = b"this is a test"; - transmute::<&[u8], &mut [u8]>(bs)[4] = 42; //~ ERROR tried to modify constant memory + transmute::<&[u8], &mut [u8]>(bs)[4] = 42; //~ ERROR read-only } } diff --git a/tests/compile-fail/storage_dead_dangling.rs b/tests/compile-fail/storage_dead_dangling.rs index 3047f086bdf3d..bf2503917ccb4 100644 --- a/tests/compile-fail/storage_dead_dangling.rs +++ b/tests/compile-fail/storage_dead_dangling.rs @@ -8,7 +8,7 @@ fn fill(v: &mut i32) { } fn evil() { - unsafe { &mut *(LEAK as *mut i32) }; //~ ERROR dangling pointer was dereferenced + unsafe { &mut *(LEAK as *mut i32) }; //~ ERROR dereferenced after this allocation got freed } fn main() { diff --git a/tests/compile-fail/transmute-pair-undef.rs b/tests/compile-fail/transmute-pair-undef.rs index 43f1eed42d07a..0f02697f26152 100644 --- a/tests/compile-fail/transmute-pair-undef.rs +++ b/tests/compile-fail/transmute-pair-undef.rs @@ -18,5 +18,5 @@ fn main() { } let v = unsafe { *z.offset(first_undef) }; if v == 0 {} - //~^ ERROR attempted to read undefined bytes + //~^ ERROR this operation requires initialized memory } diff --git a/tests/compile-fail/transmute_fat1.rs b/tests/compile-fail/transmute_fat1.rs index ddc78c8bf1d4a..978edb56340e1 100644 --- a/tests/compile-fail/transmute_fat1.rs +++ b/tests/compile-fail/transmute_fat1.rs @@ -10,5 +10,5 @@ fn main() { let bad = unsafe { std::mem::transmute::<&[u8], [u8; 8]>(&[1u8]) }; - let _val = bad[0] + bad[bad.len()-1]; //~ ERROR a raw memory access tried to access part of a pointer value as raw bytes + let _val = bad[0] + bad[bad.len()-1]; //~ ERROR unable to turn this pointer into raw bytes } diff --git a/tests/compile-fail/unaligned_ptr1.rs b/tests/compile-fail/unaligned_ptr1.rs index bcc4192d7d2ae..ee1a130042317 100644 --- a/tests/compile-fail/unaligned_ptr1.rs +++ b/tests/compile-fail/unaligned_ptr1.rs @@ -5,5 +5,5 @@ fn main() { let x = [2u16, 3, 4]; // Make it big enough so we don't get an out-of-bounds error. let x = &x[0] as *const _ as *const u32; // This must fail because alignment is violated: the allocation's base is not sufficiently aligned. - let _x = unsafe { *x }; //~ ERROR tried to access memory with alignment 2, but alignment 4 is required + let _x = unsafe { *x }; //~ ERROR memory with alignment 2, but alignment 4 is required } diff --git a/tests/compile-fail/unaligned_ptr2.rs b/tests/compile-fail/unaligned_ptr2.rs index 225bd14ade619..853d890ecf07e 100644 --- a/tests/compile-fail/unaligned_ptr2.rs +++ b/tests/compile-fail/unaligned_ptr2.rs @@ -6,5 +6,5 @@ fn main() { let x = (x.as_ptr() as *const u8).wrapping_offset(3) as *const u32; // This must fail because alignment is violated: the offset is not sufficiently aligned. // Also make the offset not a power of 2, that used to ICE. - let _x = unsafe { *x }; //~ ERROR tried to access memory with alignment 1, but alignment 4 is required + let _x = unsafe { *x }; //~ ERROR memory with alignment 1, but alignment 4 is required } diff --git a/tests/compile-fail/unaligned_ptr3.rs b/tests/compile-fail/unaligned_ptr3.rs index f33a80d4588b5..43f6b472da05b 100644 --- a/tests/compile-fail/unaligned_ptr3.rs +++ b/tests/compile-fail/unaligned_ptr3.rs @@ -7,5 +7,5 @@ fn main() { // This must fail because alignment is violated. Test specifically for loading pointers, // which have special code in miri's memory. let _x = unsafe { *x }; - //~^ ERROR tried to access memory with alignment 2, but alignment + //~^ ERROR memory with alignment 2, but alignment } diff --git a/tests/compile-fail/unaligned_ptr_zst.rs b/tests/compile-fail/unaligned_ptr_zst.rs index 127ec04027d1a..31f88c838149e 100644 --- a/tests/compile-fail/unaligned_ptr_zst.rs +++ b/tests/compile-fail/unaligned_ptr_zst.rs @@ -6,5 +6,5 @@ fn main() { let x = x as *const _ as *const [u32; 0]; // This must fail because alignment is violated. Test specifically for loading ZST. let _x = unsafe { *x }; - //~^ ERROR tried to access memory with alignment 2, but alignment 4 is required + //~^ ERROR memory with alignment 2, but alignment 4 is required } diff --git a/tests/compile-fail/undefined_byte_read.rs b/tests/compile-fail/undefined_byte_read.rs index fca749ef9ccbd..36c14137bdc16 100644 --- a/tests/compile-fail/undefined_byte_read.rs +++ b/tests/compile-fail/undefined_byte_read.rs @@ -1,6 +1,6 @@ fn main() { let v: Vec = Vec::with_capacity(10); let undef = unsafe { *v.get_unchecked(5) }; - let x = undef + 1; //~ ERROR attempted to read undefined bytes + let x = undef + 1; //~ ERROR this operation requires initialized memory panic!("this should never print: {}", x); } diff --git a/tests/compile-fail/validity/dangling_ref1.rs b/tests/compile-fail/validity/dangling_ref1.rs index 194445b1ad7e1..034510f3b283a 100644 --- a/tests/compile-fail/validity/dangling_ref1.rs +++ b/tests/compile-fail/validity/dangling_ref1.rs @@ -1,5 +1,5 @@ use std::mem; fn main() { - let _x: &i32 = unsafe { mem::transmute(16usize) }; //~ ERROR dangling reference (not entirely in bounds) + let _x: &i32 = unsafe { mem::transmute(16usize) }; //~ ERROR reference to unallocated address 16 } diff --git a/tests/compile-fail/validity/dangling_ref2.rs b/tests/compile-fail/validity/dangling_ref2.rs index 0dc9c3a1826c3..4ad9b8135db44 100644 --- a/tests/compile-fail/validity/dangling_ref2.rs +++ b/tests/compile-fail/validity/dangling_ref2.rs @@ -3,5 +3,5 @@ use std::mem; fn main() { let val = 14; let ptr = (&val as *const i32).wrapping_offset(1); - let _x: &i32 = unsafe { mem::transmute(ptr) }; //~ ERROR dangling reference (not entirely in bounds) + let _x: &i32 = unsafe { mem::transmute(ptr) }; //~ ERROR dangling reference (going beyond the bounds of its allocation) } diff --git a/tests/compile-fail/wild_pointer_deref.rs b/tests/compile-fail/wild_pointer_deref.rs index ae32f7d5562bd..5780cccdb842c 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 = 44 as *const i32; - let x = unsafe { *p }; //~ ERROR dangling pointer was dereferenced + let x = unsafe { *p }; //~ ERROR invalid use of 44 as a pointer panic!("this should never print: {}", x); } diff --git a/tests/compile-fail/zst2.rs b/tests/compile-fail/zst2.rs index 950f7b3d60e6d..907337dcdb2b4 100644 --- a/tests/compile-fail/zst2.rs +++ b/tests/compile-fail/zst2.rs @@ -8,5 +8,5 @@ fn main() { let mut x_box = Box::new(1u8); let x = &mut *x_box as *mut _ as *mut [u8; 0]; drop(x_box); - unsafe { *x = zst_val; } //~ ERROR dangling pointer was dereferenced + unsafe { *x = zst_val; } //~ ERROR dereferenced after this allocation got freed } From e6e8773272a83b84b972910ca88570388ae06590 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 9 Mar 2020 09:43:20 +0100 Subject: [PATCH 1664/3747] start messages in lower-case --- src/helpers.rs | 6 +++--- src/shims/dlsym.rs | 2 +- src/shims/foreign_items.rs | 2 +- src/shims/foreign_items/posix.rs | 2 +- src/shims/fs.rs | 18 +++++++++--------- 5 files changed, 15 insertions(+), 15 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index ff4df42dde66a..43d9f1bf0b06d 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -359,7 +359,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn check_no_isolation(&self, name: &str) -> InterpResult<'tcx> { if !self.eval_context_ref().machine.communicate { throw_unsup_format!( - "`{}` not available when isolation is enabled. Pass the flag `-Zmiri-disable-isolation` to disable it.", + "`{}` not available when isolation is enabled (pass the flag `-Zmiri-disable-isolation` to disable isolation)", name, ) } @@ -415,13 +415,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx AlreadyExists => "EEXIST", WouldBlock => "EWOULDBLOCK", _ => { - throw_unsup_format!("The {} error cannot be transformed into a raw os error", e) + throw_unsup_format!("io error {} cannot be transformed into a raw os error", e) } })? } else { // FIXME: we have to implement the Windows equivalent of this. throw_unsup_format!( - "Setting the last OS error from an io::Error is unsupported for {}.", + "setting the last OS error from an io::Error is unsupported for {}.", target.target_os ) }; diff --git a/src/shims/dlsym.rs b/src/shims/dlsym.rs index 9027a97cf54e4..b0e1850ec55d0 100644 --- a/src/shims/dlsym.rs +++ b/src/shims/dlsym.rs @@ -15,7 +15,7 @@ impl Dlsym { Ok(match name { "getentropy" => Some(GetEntropy), "__pthread_get_minstack" => None, - _ => throw_unsup_format!("Unsupported dlsym: {}", name), + _ => throw_unsup_format!("unsupported dlsym: {}", name), }) } } diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 4c7bcff267e16..b4931d3600444 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -436,7 +436,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx _ => match this.tcx.sess.target.target.target_os.as_str() { "linux" | "macos" => return posix::EvalContextExt::emulate_foreign_item_by_name(this, link_name, args, dest, ret), "windows" => return windows::EvalContextExt::emulate_foreign_item_by_name(this, link_name, args, dest, ret), - target => throw_unsup_format!("The {} target platform is not supported", target), + target => throw_unsup_format!("the {} target platform is not supported", target), } }; diff --git a/src/shims/foreign_items/posix.rs b/src/shims/foreign_items/posix.rs index 60b9aa6efccab..b9449c2653d62 100644 --- a/src/shims/foreign_items/posix.rs +++ b/src/shims/foreign_items/posix.rs @@ -310,7 +310,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if let Some(result) = result { this.write_scalar(result, dest)?; } else { - throw_unsup_format!("Unimplemented sysconf name: {}", name) + throw_unsup_format!("unimplemented sysconf name: {}", name) } } diff --git a/src/shims/fs.rs b/src/shims/fs.rs index 7c755143f2e81..6894647de44da 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -198,7 +198,7 @@ trait EvalContextExtPrivate<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, ' } Err(e) => return match e.raw_os_error() { Some(error) => Ok(error), - None => throw_unsup_format!("The error {} couldn't be converted to a return value", e), + None => throw_unsup_format!("the error {} couldn't be converted to a return value", e), } } } @@ -261,7 +261,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // windows. We need to check that in fact the access mode flags for the current platform // only use these two bits, otherwise we are in an unsupported platform and should error. if (o_rdonly | o_wronly | o_rdwr) & !0b11 != 0 { - throw_unsup_format!("Access mode flags on this platform are unsupported"); + throw_unsup_format!("access mode flags on this platform are unsupported"); } let mut writable = true; @@ -276,7 +276,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } else if access_mode == o_rdwr { options.read(true).write(true); } else { - throw_unsup_format!("Unsupported access mode {:#x}", access_mode); + throw_unsup_format!("unsupported access mode {:#x}", access_mode); } // We need to check that there aren't unsupported options in `flag`. For this we try to // reproduce the content of `flag` in the `mirror` variable using only the supported @@ -351,7 +351,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // differ in whether the FD_CLOEXEC flag is pre-set on the new file descriptor, // thus they can share the same implementation here. if fd < MIN_NORMAL_FILE_FD { - throw_unsup_format!("Duplicating file descriptors for stdin, stdout, or stderr is not supported") + throw_unsup_format!("duplicating file descriptors for stdin, stdout, or stderr is not supported") } let start_op = start_op.ok_or_else(|| { err_unsup_format!( @@ -369,7 +369,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx }); this.try_unwrap_io_result(fd_result) } else { - throw_unsup_format!("The {:#x} command is not supported for `fcntl`)", cmd); + throw_unsup_format!("the {:#x} command is not supported for `fcntl`)", cmd); } } @@ -913,7 +913,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx name_place.layout.size.bytes(), )?; if !name_fits { - throw_unsup_format!("A directory entry had a name too large to fit in libc::dirent64"); + throw_unsup_format!("a directory entry had a name too large to fit in libc::dirent64"); } let entry_place = this.deref_operand(entry_op)?; @@ -953,7 +953,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // return positive error number on error Some(error) => Ok(error), None => { - throw_unsup_format!("The error {} couldn't be converted to a return value", e) + throw_unsup_format!("the error {} couldn't be converted to a return value", e) } }, } @@ -1001,7 +1001,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx name_place.layout.size.bytes(), )?; if !name_fits { - throw_unsup_format!("A directory entry had a name too large to fit in libc::dirent"); + throw_unsup_format!("a directory entry had a name too large to fit in libc::dirent"); } let entry_place = this.deref_operand(entry_op)?; @@ -1042,7 +1042,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // return positive error number on error Some(error) => Ok(error), None => { - throw_unsup_format!("The error {} couldn't be converted to a return value", e) + throw_unsup_format!("the error {} couldn't be converted to a return value", e) } }, } From 77cc0cddd9b0d90b2f7b68c6cb62d1eec33c9427 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 9 Mar 2020 10:22:30 +0100 Subject: [PATCH 1665/3747] add test for validation finding use-after-free --- tests/compile-fail/validity/dangling_ref3.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 tests/compile-fail/validity/dangling_ref3.rs diff --git a/tests/compile-fail/validity/dangling_ref3.rs b/tests/compile-fail/validity/dangling_ref3.rs new file mode 100644 index 0000000000000..46e17375a8282 --- /dev/null +++ b/tests/compile-fail/validity/dangling_ref3.rs @@ -0,0 +1,10 @@ +use std::mem; + +fn dangling() -> *const u8 { + let x = 0u8; + &x as *const _ +} + +fn main() { + let _x: &i32 = unsafe { mem::transmute(dangling()) }; //~ ERROR dangling reference (use-after-free) +} From 681819c8ad2a33923a33fc6829cfd588eb1f721f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 9 Mar 2020 09:38:33 +0100 Subject: [PATCH 1666/3747] getting a path should never fail we basically treat them as lang items --- src/helpers.rs | 73 +++++++++++++++----------- src/shims/foreign_items.rs | 18 +------ src/shims/foreign_items/posix.rs | 23 ++++---- src/shims/foreign_items/posix/linux.rs | 6 +-- src/shims/fs.rs | 12 ++--- src/shims/time.rs | 2 +- 6 files changed, 60 insertions(+), 74 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index 43d9f1bf0b06d..169bb4205649e 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -18,7 +18,7 @@ use crate::*; impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} /// Gets an instance for a path. -fn resolve_did<'mir, 'tcx>(tcx: TyCtxt<'tcx>, path: &[&str]) -> InterpResult<'tcx, DefId> { +fn try_resolve_did<'mir, 'tcx>(tcx: TyCtxt<'tcx>, path: &[&str]) -> Option { tcx.crates() .iter() .find(|&&krate| tcx.original_crate_name(krate).as_str() == path[0]) @@ -41,18 +41,47 @@ fn resolve_did<'mir, 'tcx>(tcx: TyCtxt<'tcx>, path: &[&str]) -> InterpResult<'tc } None }) - .ok_or_else(|| { - err_unsup_format!("failed to find required Rust item: {:?}", path).into() - }) } pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { /// Gets an instance for a path. - fn resolve_path(&self, path: &[&str]) -> InterpResult<'tcx, ty::Instance<'tcx>> { - Ok(ty::Instance::mono( - self.eval_context_ref().tcx.tcx, - resolve_did(self.eval_context_ref().tcx.tcx, path)?, - )) + fn resolve_path(&self, path: &[&str]) -> ty::Instance<'tcx> { + let did = try_resolve_did(self.eval_context_ref().tcx.tcx, path) + .unwrap_or_else(|| panic!("failed to find required Rust item: {:?}", path)); + ty::Instance::mono(self.eval_context_ref().tcx.tcx, did) + } + + /// Evaluates the scalar at the specified path. Returns Some(val) + /// if the path could be resolved, and None otherwise + fn eval_path_scalar( + &mut self, + path: &[&str], + ) -> InterpResult<'tcx, ScalarMaybeUndef> { + let this = self.eval_context_mut(); + let instance = this.resolve_path(path); + let cid = GlobalId { instance, promoted: None }; + let const_val = this.const_eval_raw(cid)?; + let const_val = this.read_scalar(const_val.into())?; + return Ok(const_val); + } + + /// Helper function to get a `libc` constant as a `Scalar`. + fn eval_libc(&mut self, name: &str) -> InterpResult<'tcx, Scalar> { + self.eval_context_mut() + .eval_path_scalar(&["libc", name])? + .not_undef() + } + + /// Helper function to get a `libc` constant as an `i32`. + fn eval_libc_i32(&mut self, name: &str) -> InterpResult<'tcx, i32> { + self.eval_libc(name)?.to_i32() + } + + /// Helper function to get the `TyLayout` of a `libc` type + fn libc_ty_layout(&mut self, name: &str) -> InterpResult<'tcx, TyLayout<'tcx>> { + let this = self.eval_context_mut(); + let ty = this.resolve_path(&["libc", name]).monomorphic_ty(*this.tcx); + this.layout_of(ty) } /// Write a 0 of the appropriate size to `dest`. @@ -97,7 +126,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if this.machine.communicate { // Fill the buffer using the host's rng. getrandom::getrandom(&mut data) - .map_err(|err| err_unsup_format!("getrandom failed: {}", err))?; + .map_err(|err| err_unsup_format!("host getrandom failed: {}", err))?; } else { let rng = this.memory.extra.rng.get_mut(); rng.fill_bytes(&mut data); @@ -312,26 +341,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } - /// Helper function to get a `libc` constant as a `Scalar`. - fn eval_libc(&mut self, name: &str) -> InterpResult<'tcx, Scalar> { - self.eval_context_mut() - .eval_path_scalar(&["libc", name])? - .ok_or_else(|| err_unsup_format!("Path libc::{} cannot be resolved.", name))? - .not_undef() - } - - /// Helper function to get a `libc` constant as an `i32`. - fn eval_libc_i32(&mut self, name: &str) -> InterpResult<'tcx, i32> { - self.eval_libc(name)?.to_i32() - } - - /// Helper function to get the `TyLayout` of a `libc` type - fn libc_ty_layout(&mut self, name: &str) -> InterpResult<'tcx, TyLayout<'tcx>> { - let this = self.eval_context_mut(); - let ty = this.resolve_path(&["libc", name])?.monomorphic_ty(*this.tcx); - this.layout_of(ty) - } - // Writes several `ImmTy`s contiguosly into memory. This is useful when you have to pack // different values into a struct. fn write_packed_immediates( @@ -530,7 +539,7 @@ pub fn immty_from_int_checked<'tcx>( ) -> InterpResult<'tcx, ImmTy<'tcx, Tag>> { let int = int.into(); Ok(ImmTy::try_from_int(int, layout).ok_or_else(|| { - err_unsup_format!("Signed value {:#x} does not fit in {} bits", int, layout.size.bits()) + err_unsup_format!("signed value {:#x} does not fit in {} bits", int, layout.size.bits()) })?) } @@ -540,6 +549,6 @@ pub fn immty_from_uint_checked<'tcx>( ) -> InterpResult<'tcx, ImmTy<'tcx, Tag>> { let int = int.into(); Ok(ImmTy::try_from_uint(int, layout).ok_or_else(|| { - err_unsup_format!("Signed value {:#x} does not fit in {} bits", int, layout.size.bits()) + err_unsup_format!("unsigned value {:#x} does not fit in {} bits", int, layout.size.bits()) })?) } diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index b4931d3600444..fab90e3cc5291 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -165,7 +165,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx .expect("No panic runtime found!"); let panic_runtime = tcx.crate_name(*panic_runtime); let start_panic_instance = - this.resolve_path(&[&*panic_runtime.as_str(), link_name])?; + this.resolve_path(&[&*panic_runtime.as_str(), link_name]); return Ok(Some(&*this.load_mir(start_panic_instance.def, None)?)); } _ => {} @@ -454,20 +454,4 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } Ok(()) } - - /// Evaluates the scalar at the specified path. Returns Some(val) - /// if the path could be resolved, and None otherwise - fn eval_path_scalar( - &mut self, - path: &[&str], - ) -> InterpResult<'tcx, Option>> { - let this = self.eval_context_mut(); - if let Ok(instance) = this.resolve_path(path) { - let cid = GlobalId { instance, promoted: None }; - let const_val = this.const_eval_raw(cid)?; - let const_val = this.read_scalar(const_val.into())?; - return Ok(Some(const_val)); - } - return Ok(None); - } } diff --git a/src/shims/foreign_items/posix.rs b/src/shims/foreign_items/posix.rs index b9449c2653d62..85e9b88b6ec03 100644 --- a/src/shims/foreign_items/posix.rs +++ b/src/shims/foreign_items/posix.rs @@ -289,22 +289,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx trace!("sysconf() called with name {}", name); // TODO: Cache the sysconf integers via Miri's global cache. - let paths = &[ - (&["libc", "_SC_PAGESIZE"], Scalar::from_int(PAGE_SIZE, dest.layout.size)), - (&["libc", "_SC_GETPW_R_SIZE_MAX"], Scalar::from_int(-1, dest.layout.size)), - ( - &["libc", "_SC_NPROCESSORS_ONLN"], - Scalar::from_int(NUM_CPUS, dest.layout.size), - ), + let sysconfs = &[ + ("_SC_PAGESIZE", Scalar::from_int(PAGE_SIZE, dest.layout.size)), + ("_SC_GETPW_R_SIZE_MAX", Scalar::from_int(-1, dest.layout.size)), + ("_SC_NPROCESSORS_ONLN", Scalar::from_int(NUM_CPUS, dest.layout.size)), ]; let mut result = None; - for &(path, path_value) in paths { - if let Some(val) = this.eval_path_scalar(path)? { - let val = val.to_i32()?; - if val == name { - result = Some(path_value); - break; - } + for &(sysconf_name, value) in sysconfs { + let sysconf_name = this.eval_libc_i32(sysconf_name)?; + if sysconf_name == name { + result = Some(value); + break; } } if let Some(result) = result { diff --git a/src/shims/foreign_items/posix/linux.rs b/src/shims/foreign_items/posix/linux.rs index 023fee4ca7b1e..82928c9bc17ff 100644 --- a/src/shims/foreign_items/posix/linux.rs +++ b/src/shims/foreign_items/posix/linux.rs @@ -56,13 +56,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "syscall" => { let sys_getrandom = this - .eval_path_scalar(&["libc", "SYS_getrandom"])? - .expect("Failed to get libc::SYS_getrandom") + .eval_libc("SYS_getrandom")? .to_machine_usize(this)?; let sys_statx = this - .eval_path_scalar(&["libc", "SYS_statx"])? - .expect("Failed to get libc::SYS_statx") + .eval_libc("SYS_statx")? .to_machine_usize(this)?; match this.read_scalar(args[0])?.to_machine_usize(this)? { diff --git a/src/shims/fs.rs b/src/shims/fs.rs index 6894647de44da..cb429109a4a50 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -643,7 +643,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // FIXME: This long path is required because `libc::statx` is an struct and also a // function and `resolve_path` is returning the latter. let statx_ty = this - .resolve_path(&["libc", "unix", "linux_like", "linux", "gnu", "statx"])? + .resolve_path(&["libc", "unix", "linux_like", "linux", "gnu", "statx"]) .monomorphic_ty(*this.tcx); let statxbuf_ty = this.tcx.mk_mut_ptr(statx_ty); let statxbuf_layout = this.layout_of(statxbuf_ty)?; @@ -655,13 +655,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // `flags` should be a `c_int` but the `syscall` function provides an `isize`. let flags: i32 = this.read_scalar(flags_op)?.to_machine_isize(&*this.tcx)?.try_into().map_err(|e| { - err_unsup_format!("Failed to convert pointer sized operand to integer: {}", e) + err_unsup_format!("failed to convert pointer sized operand to integer: {}", e) })?; let empty_path_flag = flags & this.eval_libc("AT_EMPTY_PATH")?.to_i32()? != 0; // `dirfd` should be a `c_int` but the `syscall` function provides an `isize`. let dirfd: i32 = this.read_scalar(dirfd_op)?.to_machine_isize(&*this.tcx)?.try_into().map_err(|e| { - err_unsup_format!("Failed to convert pointer sized operand to integer: {}", e) + err_unsup_format!("failed to convert pointer sized operand to integer: {}", e) })?; // We only support: // * interpreting `path` as an absolute directory, @@ -676,7 +676,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx (path.as_os_str().is_empty() && empty_path_flag) ) { throw_unsup_format!( - "Using statx is only supported with absolute paths, relative paths with the file \ + "using statx is only supported with absolute paths, relative paths with the file \ descriptor `AT_FDCWD`, and empty paths with the `AT_EMPTY_PATH` flag set and any \ file descriptor" ) @@ -886,7 +886,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let dirp = this.read_scalar(dirp_op)?.to_machine_usize(this)?; let dir_iter = this.machine.dir_handler.streams.get_mut(&dirp).ok_or_else(|| { - err_unsup_format!("The DIR pointer passed to readdir64_r did not come from opendir") + err_unsup_format!("the DIR pointer passed to readdir64_r did not come from opendir") })?; match dir_iter.next() { Some(Ok(dir_entry)) => { @@ -973,7 +973,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let dirp = this.read_scalar(dirp_op)?.to_machine_usize(this)?; let dir_iter = this.machine.dir_handler.streams.get_mut(&dirp).ok_or_else(|| { - err_unsup_format!("The DIR pointer passed to readdir_r did not come from opendir") + err_unsup_format!("the DIR pointer passed to readdir_r did not come from opendir") })?; match dir_iter.next() { Some(Ok(dir_entry)) => { diff --git a/src/shims/time.rs b/src/shims/time.rs index d761698e0d278..627478eaaab70 100644 --- a/src/shims/time.rs +++ b/src/shims/time.rs @@ -12,7 +12,7 @@ fn get_time<'tcx>() -> InterpResult<'tcx, Duration> { /// Returns the time elapsed between the provided time and the unix epoch as a `Duration`. pub fn system_time_to_duration<'tcx>(time: &SystemTime) -> InterpResult<'tcx, Duration> { time.duration_since(SystemTime::UNIX_EPOCH) - .map_err(|_| err_unsup_format!("Times before the Unix epoch are not supported").into()) + .map_err(|_| err_unsup_format!("times before the Unix epoch are not supported").into()) } impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} From e1e158e1037f22516a4d227abfe3bf9f7a1b8c5e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 9 Mar 2020 11:42:59 +0100 Subject: [PATCH 1667/3747] adjust error messages for lower-case start --- tests/compile-fail/overflowing-unchecked-rsh.rs | 2 +- tests/compile-fail/unchecked_add1.rs | 2 +- tests/compile-fail/unchecked_add2.rs | 2 +- tests/compile-fail/unchecked_div1.rs | 2 +- tests/compile-fail/unchecked_mul1.rs | 2 +- tests/compile-fail/unchecked_mul2.rs | 2 +- tests/compile-fail/unchecked_sub1.rs | 2 +- tests/compile-fail/unchecked_sub2.rs | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/tests/compile-fail/overflowing-unchecked-rsh.rs b/tests/compile-fail/overflowing-unchecked-rsh.rs index f59773f7e366c..730d01597f4d0 100644 --- a/tests/compile-fail/overflowing-unchecked-rsh.rs +++ b/tests/compile-fail/overflowing-unchecked-rsh.rs @@ -2,7 +2,7 @@ use std::intrinsics::*; -//error-pattern: Overflowing shift by 64 in `unchecked_shr` +//error-pattern: overflowing shift by 64 in `unchecked_shr` fn main() { unsafe { diff --git a/tests/compile-fail/unchecked_add1.rs b/tests/compile-fail/unchecked_add1.rs index eb5a41fdfaf9d..f48b91422c6e7 100644 --- a/tests/compile-fail/unchecked_add1.rs +++ b/tests/compile-fail/unchecked_add1.rs @@ -1,5 +1,5 @@ #![feature(core_intrinsics)] fn main() { // MAX overflow - unsafe { std::intrinsics::unchecked_add(40000u16, 30000); } //~ ERROR Overflow executing `unchecked_add` + unsafe { std::intrinsics::unchecked_add(40000u16, 30000); } //~ ERROR overflow executing `unchecked_add` } diff --git a/tests/compile-fail/unchecked_add2.rs b/tests/compile-fail/unchecked_add2.rs index fa6a232aedee9..150986541c3d9 100644 --- a/tests/compile-fail/unchecked_add2.rs +++ b/tests/compile-fail/unchecked_add2.rs @@ -1,5 +1,5 @@ #![feature(core_intrinsics)] fn main() { // MIN overflow - unsafe { std::intrinsics::unchecked_add(-30000i16, -8000); } //~ ERROR Overflow executing `unchecked_add` + unsafe { std::intrinsics::unchecked_add(-30000i16, -8000); } //~ ERROR overflow executing `unchecked_add` } diff --git a/tests/compile-fail/unchecked_div1.rs b/tests/compile-fail/unchecked_div1.rs index b42b34ff462d4..53d80007646de 100644 --- a/tests/compile-fail/unchecked_div1.rs +++ b/tests/compile-fail/unchecked_div1.rs @@ -1,5 +1,5 @@ #![feature(core_intrinsics)] fn main() { // MIN/-1 cannot be represented - unsafe { std::intrinsics::unchecked_div(i16::MIN, -1); } //~ ERROR Overflow executing `unchecked_div` + unsafe { std::intrinsics::unchecked_div(i16::MIN, -1); } //~ ERROR overflow executing `unchecked_div` } diff --git a/tests/compile-fail/unchecked_mul1.rs b/tests/compile-fail/unchecked_mul1.rs index a3681a57df79d..050e3ff243770 100644 --- a/tests/compile-fail/unchecked_mul1.rs +++ b/tests/compile-fail/unchecked_mul1.rs @@ -1,5 +1,5 @@ #![feature(core_intrinsics)] fn main() { // MAX overflow - unsafe { std::intrinsics::unchecked_mul(300u16, 250u16); } //~ ERROR Overflow executing `unchecked_mul` + unsafe { std::intrinsics::unchecked_mul(300u16, 250u16); } //~ ERROR overflow executing `unchecked_mul` } diff --git a/tests/compile-fail/unchecked_mul2.rs b/tests/compile-fail/unchecked_mul2.rs index 8fe677f8ded53..4fb77783b4ce7 100644 --- a/tests/compile-fail/unchecked_mul2.rs +++ b/tests/compile-fail/unchecked_mul2.rs @@ -1,5 +1,5 @@ #![feature(core_intrinsics)] fn main() { // MIN overflow - unsafe { std::intrinsics::unchecked_mul(1_000_000_000i32, -4); } //~ ERROR Overflow executing `unchecked_mul` + unsafe { std::intrinsics::unchecked_mul(1_000_000_000i32, -4); } //~ ERROR overflow executing `unchecked_mul` } diff --git a/tests/compile-fail/unchecked_sub1.rs b/tests/compile-fail/unchecked_sub1.rs index 230607f033058..69b32dd319b6f 100644 --- a/tests/compile-fail/unchecked_sub1.rs +++ b/tests/compile-fail/unchecked_sub1.rs @@ -1,5 +1,5 @@ #![feature(core_intrinsics)] fn main() { // MIN overflow - unsafe { std::intrinsics::unchecked_sub(14u32, 22); } //~ ERROR Overflow executing `unchecked_sub` + unsafe { std::intrinsics::unchecked_sub(14u32, 22); } //~ ERROR overflow executing `unchecked_sub` } diff --git a/tests/compile-fail/unchecked_sub2.rs b/tests/compile-fail/unchecked_sub2.rs index 1ea41a3c0fb07..5609ea7a3eddc 100644 --- a/tests/compile-fail/unchecked_sub2.rs +++ b/tests/compile-fail/unchecked_sub2.rs @@ -1,5 +1,5 @@ #![feature(core_intrinsics)] fn main() { // MAX overflow - unsafe { std::intrinsics::unchecked_sub(30000i16, -7000); } //~ ERROR Overflow executing `unchecked_sub` + unsafe { std::intrinsics::unchecked_sub(30000i16, -7000); } //~ ERROR overflow executing `unchecked_sub` } From 49051e05eaf91e97e106c56a4cbb0f59757494c6 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 19 Mar 2020 08:41:01 +0100 Subject: [PATCH 1668/3747] rustup, and some final message adjustments --- rust-version | 2 +- tests/compile-fail/cast_fn_ptr1.rs | 4 ++-- tests/compile-fail/cast_fn_ptr5.rs | 4 ++-- tests/compile-fail/pointer_byte_read.rs | 2 +- tests/compile-fail/reading_half_a_pointer.rs | 2 +- tests/compile-fail/transmute_fat1.rs | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/rust-version b/rust-version index 1c3f12298f86e..dd16aa7af94f6 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -660326e9791d5caf3186b14521498c2584a494ab +57e1da59cd0761330b4ea8d47b16340a78eeafa9 diff --git a/tests/compile-fail/cast_fn_ptr1.rs b/tests/compile-fail/cast_fn_ptr1.rs index 3702ec8c94c43..057cc64e9e3bc 100644 --- a/tests/compile-fail/cast_fn_ptr1.rs +++ b/tests/compile-fail/cast_fn_ptr1.rs @@ -1,9 +1,9 @@ fn main() { - fn f() {} + fn f() {} //~ ERROR calling a function with more arguments than it expected let g = unsafe { std::mem::transmute::(f) }; - g(42) //~ ERROR calling a function with more arguments than it expected + g(42) } diff --git a/tests/compile-fail/cast_fn_ptr5.rs b/tests/compile-fail/cast_fn_ptr5.rs index fb2b4403363ef..ff2a73d5a4859 100644 --- a/tests/compile-fail/cast_fn_ptr5.rs +++ b/tests/compile-fail/cast_fn_ptr5.rs @@ -1,9 +1,9 @@ fn main() { - fn f() -> u32 { 42 } + fn f() -> u32 { 42 } //~ ERROR calling a function with return type u32 passing return place of type () let g = unsafe { std::mem::transmute:: u32, fn()>(f) }; - g() //~ ERROR calling a function with return type u32 passing return place of type () + g() } diff --git a/tests/compile-fail/pointer_byte_read.rs b/tests/compile-fail/pointer_byte_read.rs index 2ac27bf2b44da..dcb0fd3fb9066 100644 --- a/tests/compile-fail/pointer_byte_read.rs +++ b/tests/compile-fail/pointer_byte_read.rs @@ -3,5 +3,5 @@ fn main() { let y = &x; let z = &y as *const &i32 as *const u8; // the deref fails, because we are reading only a part of the pointer - let _val = unsafe { *z }; //~ ERROR unable to turn this pointer into raw bytes + let _val = unsafe { *z }; //~ ERROR unable to turn pointer into raw bytes } diff --git a/tests/compile-fail/reading_half_a_pointer.rs b/tests/compile-fail/reading_half_a_pointer.rs index 5554d0c49a110..6e765a1b0ba14 100644 --- a/tests/compile-fail/reading_half_a_pointer.rs +++ b/tests/compile-fail/reading_half_a_pointer.rs @@ -24,6 +24,6 @@ fn main() { // starts 1 byte to the right, so using it would actually be wrong! let d_alias = &mut w.data as *mut _ as *mut *const u8; unsafe { - let _x = *d_alias; //~ ERROR unable to turn this pointer into raw bytes + let _x = *d_alias; //~ ERROR unable to turn pointer into raw bytes } } diff --git a/tests/compile-fail/transmute_fat1.rs b/tests/compile-fail/transmute_fat1.rs index 978edb56340e1..da45dad7b7d43 100644 --- a/tests/compile-fail/transmute_fat1.rs +++ b/tests/compile-fail/transmute_fat1.rs @@ -10,5 +10,5 @@ fn main() { let bad = unsafe { std::mem::transmute::<&[u8], [u8; 8]>(&[1u8]) }; - let _val = bad[0] + bad[bad.len()-1]; //~ ERROR unable to turn this pointer into raw bytes + let _val = bad[0] + bad[bad.len()-1]; //~ ERROR unable to turn pointer into raw bytes } From 0f1713f67cb66b2af3fd84c34a58b92f0a0c99bf Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 19 Mar 2020 15:50:02 +0100 Subject: [PATCH 1669/3747] whitelist platforms where panicking should work --- src/shims/foreign_items.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index fab90e3cc5291..af2c6d6ebb9a6 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -132,6 +132,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // This matches calls to the foreign item `panic_impl`. // The implementation is provided by the function with the `#[panic_handler]` attribute. "panic_impl" => { + // Make sure panicking actually works on this platform. + match this.tcx.sess.target.target.target_os.as_str() { + "linux" | "macos" => {}, + _ => throw_unsup_format!("panicking is not supported on this platform"), + } + let panic_impl_id = this.tcx.lang_items().panic_impl().unwrap(); let panic_impl_instance = ty::Instance::mono(*this.tcx, panic_impl_id); return Ok(Some(&*this.load_mir(panic_impl_instance.def, None)?)); From 4608b94bd89d444cbb02ed41fca2ca002cc0c5ca Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 19 Mar 2020 23:00:02 +0100 Subject: [PATCH 1670/3747] implement CLOCK_MONOTONIC on Linux --- src/machine.rs | 5 +++++ src/shims/time.rs | 24 ++++++++++++------------ tests/run-pass/clock.rs | 14 -------------- tests/run-pass/time.rs | 18 ++++++++++++++++++ 4 files changed, 35 insertions(+), 26 deletions(-) delete mode 100644 tests/run-pass/clock.rs create mode 100644 tests/run-pass/time.rs diff --git a/src/machine.rs b/src/machine.rs index 3a8e7fc902413..3cf00781338c2 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -5,6 +5,7 @@ use std::borrow::Cow; use std::cell::RefCell; use std::num::NonZeroU64; use std::rc::Rc; +use std::time::Instant; use rand::rngs::StdRng; @@ -164,6 +165,9 @@ pub struct Evaluator<'tcx> { /// the call to `miri_start_panic` (the panic payload) when unwinding. /// This is pointer-sized, and matches the `Payload` type in `src/libpanic_unwind/miri.rs`. pub(crate) panic_payload: Option>, + + /// The "time anchor" for this machine's monotone clock (for `Instant` simulation). + pub(crate) time_anchor: Instant, } impl<'tcx> Evaluator<'tcx> { @@ -182,6 +186,7 @@ impl<'tcx> Evaluator<'tcx> { file_handler: Default::default(), dir_handler: Default::default(), panic_payload: None, + time_anchor: Instant::now(), } } } diff --git a/src/shims/time.rs b/src/shims/time.rs index 627478eaaab70..c8807dd6ea846 100644 --- a/src/shims/time.rs +++ b/src/shims/time.rs @@ -1,14 +1,9 @@ -use std::time::{Duration, SystemTime}; +use std::time::{Duration, SystemTime, Instant}; use crate::stacked_borrows::Tag; use crate::*; use helpers::immty_from_int_checked; -// Returns the time elapsed between now and the unix epoch as a `Duration`. -fn get_time<'tcx>() -> InterpResult<'tcx, Duration> { - system_time_to_duration(&SystemTime::now()) -} - /// Returns the time elapsed between the provided time and the unix epoch as a `Duration`. pub fn system_time_to_duration<'tcx>(time: &SystemTime) -> InterpResult<'tcx, Duration> { time.duration_since(SystemTime::UNIX_EPOCH) @@ -28,15 +23,20 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.check_no_isolation("clock_gettime")?; let clk_id = this.read_scalar(clk_id_op)?.to_i32()?; - if clk_id != this.eval_libc_i32("CLOCK_REALTIME")? { + let tp = this.deref_operand(tp_op)?; + + let duration = if clk_id == this.eval_libc_i32("CLOCK_REALTIME")? { + system_time_to_duration(&SystemTime::now())? + } else if clk_id == this.eval_libc_i32("CLOCK_MONOTONIC")? { + // Absolute time does not matter, only relative time does, so we can just + // use our own time anchor here. + Instant::now().duration_since(this.machine.time_anchor) + } else { let einval = this.eval_libc("EINVAL")?; this.set_last_error(einval)?; return Ok(-1); - } - - let tp = this.deref_operand(tp_op)?; + }; - let duration = get_time()?; let tv_sec = duration.as_secs(); let tv_nsec = duration.subsec_nanos(); @@ -68,7 +68,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let tv = this.deref_operand(tv_op)?; - let duration = get_time()?; + let duration = system_time_to_duration(&SystemTime::now())?; let tv_sec = duration.as_secs(); let tv_usec = duration.subsec_micros(); diff --git a/tests/run-pass/clock.rs b/tests/run-pass/clock.rs deleted file mode 100644 index b4c3fa08fdc60..0000000000000 --- a/tests/run-pass/clock.rs +++ /dev/null @@ -1,14 +0,0 @@ -// ignore-windows: TODO clock shims are not implemented on Windows -// compile-flags: -Zmiri-disable-isolation - -use std::time::SystemTime; - -fn main() { - let now1 = SystemTime::now(); - - // Do some work to make time pass. - for _ in 0..10 { drop(vec![42]); } - - let now2 = SystemTime::now(); - assert!(now2 > now1); -} diff --git a/tests/run-pass/time.rs b/tests/run-pass/time.rs new file mode 100644 index 0000000000000..bbe8b4011dfa6 --- /dev/null +++ b/tests/run-pass/time.rs @@ -0,0 +1,18 @@ +// ignore-windows: TODO clock shims are not implemented on Windows +// compile-flags: -Zmiri-disable-isolation + +use std::time::{SystemTime, Instant}; + +fn main() { + let now1 = SystemTime::now(); + // Do some work to make time pass. + for _ in 0..10 { drop(vec![42]); } + let now2 = SystemTime::now(); + assert!(now2 > now1); + + let now1 = Instant::now(); + // Do some work to make time pass. + for _ in 0..10 { drop(vec![42]); } + let now2 = Instant::now(); + assert!(now2 > now1); +} From c3f6f47f7a773ad00c87cfb550006fb0906cef31 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 19 Mar 2020 23:19:17 +0100 Subject: [PATCH 1671/3747] we also do not check floats for being init'd --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index a1b9783166843..c2957416062d1 100644 --- a/README.md +++ b/README.md @@ -29,8 +29,8 @@ program, and cannot run all programs: positives here, so if you program runs fine in Miri right now that is by no means a guarantee that it is UB-free when these questions get answered. - In particular, Miri does currently not check that integers are initialized - or that references point to valid data. + In particular, Miri does currently not check that integers/floats are + initialized or that references point to valid data. * If the program relies on unspecified details of how data is laid out, it will still run fine in Miri -- but might break (including causing UB) on different compiler versions or different platforms. From e3a72be1073903dc02040163305344b845516fe0 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 20 Mar 2020 10:34:24 +0100 Subject: [PATCH 1672/3747] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index dd16aa7af94f6..ca9c782d127ae 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -57e1da59cd0761330b4ea8d47b16340a78eeafa9 +f4c675c476c18b1a11041193f2f59d695b126bc8 From 04c937e2813c5da2b003b272bff26b9d1f9ffca3 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 20 Mar 2020 15:11:54 +0100 Subject: [PATCH 1673/3747] assert platform in time shims --- src/shims/time.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/shims/time.rs b/src/shims/time.rs index c8807dd6ea846..2d812208fba11 100644 --- a/src/shims/time.rs +++ b/src/shims/time.rs @@ -21,6 +21,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); this.check_no_isolation("clock_gettime")?; + this.assert_platform("linux"); let clk_id = this.read_scalar(clk_id_op)?.to_i32()?; let tp = this.deref_operand(tp_op)?; @@ -58,6 +59,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); this.check_no_isolation("gettimeofday")?; + this.assert_platform("macos"); + // Using tz is obsolete and should always be null let tz = this.read_scalar(tz_op)?.not_undef()?; if !this.is_null(tz)? { From 3a5f601710bd14d2f924dadc5864c5b6ac0bc84c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 20 Mar 2020 15:57:11 +0100 Subject: [PATCH 1674/3747] add some more miri-detected issues --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index c2957416062d1..e0e7df24faad7 100644 --- a/README.md +++ b/README.md @@ -243,6 +243,7 @@ Definite bugs found: * [The Unix allocator calling `posix_memalign` in an invalid way](https://github.com/rust-lang/rust/issues/62251) * [`getrandom` calling the `getrandom` syscall in an invalid way](https://github.com/rust-random/getrandom/pull/73) * [`Vec`](https://github.com/rust-lang/rust/issues/69770) and [`BTreeMap`](https://github.com/rust-lang/rust/issues/69769) leaking memory under some (panicky) conditions +* [Memory leak in `beef`](https://github.com/maciejhirsz/beef/issues/12) Violations of [Stacked Borrows] found that are likely bugs (but Stacked Borrows is currently just an experiment): @@ -251,6 +252,7 @@ Violations of [Stacked Borrows] found that are likely bugs (but Stacked Borrows * [`LinkedList` creating overlapping mutable references](https://github.com/rust-lang/rust/pull/60072) * [`Vec::push` invalidating existing references into the vector](https://github.com/rust-lang/rust/issues/60847) * [`align_to_mut` violating uniqueness of mutable references](https://github.com/rust-lang/rust/issues/68549) +* [Aliasing mutable references in `sized-chunks`](https://github.com/bodil/sized-chunks/issues/8) ## License From f430e544561a430f267c9fbde20962cef4702332 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 20 Mar 2020 15:54:41 +0100 Subject: [PATCH 1675/3747] implement mach_absolute_time for macOS --- src/shims/foreign_items/posix/macos.rs | 4 ++++ src/shims/fs.rs | 12 ++++++------ src/shims/time.rs | 21 +++++++++++++++++---- 3 files changed, 27 insertions(+), 10 deletions(-) diff --git a/src/shims/foreign_items/posix/macos.rs b/src/shims/foreign_items/posix/macos.rs index 34661fb2383c3..0bb4710769d97 100644 --- a/src/shims/foreign_items/posix/macos.rs +++ b/src/shims/foreign_items/posix/macos.rs @@ -66,6 +66,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let result = this.gettimeofday(args[0], args[1])?; this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; } + "mach_absolute_time" => { + let result = this.mach_absolute_time()?; + this.write_scalar(Scalar::from_uint(result, dest.layout.size), dest)?; + } // Other shims "pthread_attr_get_np" => { diff --git a/src/shims/fs.rs b/src/shims/fs.rs index cb429109a4a50..a5aae5ed90c3a 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -574,8 +574,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx buf_op: OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - this.check_no_isolation("stat")?; this.assert_platform("macos", "stat"); + this.check_no_isolation("stat")?; // `stat` always follows symlinks. this.macos_stat_or_lstat(true, path_op, buf_op) } @@ -587,8 +587,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx buf_op: OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - this.check_no_isolation("lstat")?; this.assert_platform("macos", "lstat"); + this.check_no_isolation("lstat")?; this.macos_stat_or_lstat(false, path_op, buf_op) } @@ -599,8 +599,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - this.check_no_isolation("fstat")?; this.assert_platform("macos", "fstat"); + this.check_no_isolation("fstat")?; let fd = this.read_scalar(fd_op)?.to_i32()?; @@ -621,8 +621,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - this.check_no_isolation("statx")?; this.assert_platform("linux", "statx"); + this.check_no_isolation("statx")?; let statxbuf_scalar = this.read_scalar(statxbuf_op)?.not_undef()?; let pathname_scalar = this.read_scalar(pathname_op)?.not_undef()?; @@ -880,8 +880,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - this.check_no_isolation("readdir64_r")?; this.assert_platform("linux", "readdir64_r"); + this.check_no_isolation("readdir64_r")?; let dirp = this.read_scalar(dirp_op)?.to_machine_usize(this)?; @@ -967,8 +967,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - this.check_no_isolation("readdir_r")?; this.assert_platform("macos", "readdir_r"); + this.check_no_isolation("readdir_r")?; let dirp = this.read_scalar(dirp_op)?.to_machine_usize(this)?; diff --git a/src/shims/time.rs b/src/shims/time.rs index 2d812208fba11..b270c9770f809 100644 --- a/src/shims/time.rs +++ b/src/shims/time.rs @@ -1,4 +1,5 @@ use std::time::{Duration, SystemTime, Instant}; +use std::convert::TryFrom; use crate::stacked_borrows::Tag; use crate::*; @@ -12,7 +13,6 @@ pub fn system_time_to_duration<'tcx>(time: &SystemTime) -> InterpResult<'tcx, Du impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { - // Foreign function used by linux fn clock_gettime( &mut self, clk_id_op: OpTy<'tcx, Tag>, @@ -20,8 +20,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); + this.assert_platform("linux", "clock_gettime"); this.check_no_isolation("clock_gettime")?; - this.assert_platform("linux"); let clk_id = this.read_scalar(clk_id_op)?.to_i32()?; let tp = this.deref_operand(tp_op)?; @@ -50,7 +50,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(0) } - // Foreign function used by generic unix (in particular macOS) + fn gettimeofday( &mut self, tv_op: OpTy<'tcx, Tag>, @@ -58,8 +58,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); + this.assert_platform("macos", "gettimeofday"); this.check_no_isolation("gettimeofday")?; - this.assert_platform("macos"); // Using tz is obsolete and should always be null let tz = this.read_scalar(tz_op)?.not_undef()?; @@ -84,4 +84,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(0) } + + fn mach_absolute_time(&self) -> InterpResult<'tcx, u64> { + let this = self.eval_context_ref(); + + this.assert_platform("macos", "mach_absolute_time"); + this.check_no_isolation("mach_absolute_time")?; + + // This returns a u64, with time units determined dynamically by `mach_timebase_info`. + // We return plain nanoseconds. + let duration = Instant::now().duration_since(this.machine.time_anchor); + u64::try_from(duration.as_nanos()) + .map_err(|_| err_unsup_format!("programs running longer than 2^64 nanoseconds are not supported").into()) + } } From bde3111c61a325a2ddaf7b47975ee2758b30e969 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 21 Mar 2020 10:16:47 +0100 Subject: [PATCH 1676/3747] test windows panic message --- src/shims/foreign_items.rs | 7 +------ src/shims/mod.rs | 8 ++++++++ src/shims/panic.rs | 8 ++++++++ tests/compile-fail/panic/windows1.rs | 9 +++++++++ tests/compile-fail/panic/windows2.rs | 9 +++++++++ tests/compile-fail/panic/windows3.rs | 10 ++++++++++ 6 files changed, 45 insertions(+), 6 deletions(-) create mode 100644 tests/compile-fail/panic/windows1.rs create mode 100644 tests/compile-fail/panic/windows2.rs create mode 100644 tests/compile-fail/panic/windows3.rs diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index af2c6d6ebb9a6..60da1f1e6cc6d 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -132,12 +132,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // This matches calls to the foreign item `panic_impl`. // The implementation is provided by the function with the `#[panic_handler]` attribute. "panic_impl" => { - // Make sure panicking actually works on this platform. - match this.tcx.sess.target.target.target_os.as_str() { - "linux" | "macos" => {}, - _ => throw_unsup_format!("panicking is not supported on this platform"), - } - + this.check_panic_supported()?; let panic_impl_id = this.tcx.lang_items().panic_impl().unwrap(); let panic_impl_instance = ty::Instance::mono(*this.tcx, panic_impl_id); return Ok(Some(&*this.load_mir(panic_impl_instance.def, None)?)); diff --git a/src/shims/mod.rs b/src/shims/mod.rs index d9e4d226ecc9a..5b5a11b86b49f 100644 --- a/src/shims/mod.rs +++ b/src/shims/mod.rs @@ -42,6 +42,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx return this.emulate_foreign_item(instance.def_id(), args, ret, unwind); } + // Better error message for panics on Windows. + let def_id = instance.def_id(); + if Some(def_id) == this.tcx.lang_items().begin_panic_fn() || + Some(def_id) == this.tcx.lang_items().panic_impl() + { + this.check_panic_supported()?; + } + // Otherwise, load the MIR. Ok(Some(&*this.load_mir(instance.def, None)?)) } diff --git a/src/shims/panic.rs b/src/shims/panic.rs index 2f61ab6c39583..8dded8bf4037b 100644 --- a/src/shims/panic.rs +++ b/src/shims/panic.rs @@ -32,6 +32,14 @@ pub struct CatchUnwindData<'tcx> { impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { + /// Check if panicking is supported on this platform, and give a good error otherwise. + fn check_panic_supported(&self) -> InterpResult<'tcx> { + match self.eval_context_ref().tcx.sess.target.target.target_os.as_str() { + "linux" | "macos" => Ok(()), + _ => throw_unsup_format!("panicking is not supported on this platform"), + } + } + /// Handles the special `miri_start_panic` intrinsic, which is called /// by libpanic_unwind to delegate the actual unwinding process to Miri. fn handle_miri_start_panic( diff --git a/tests/compile-fail/panic/windows1.rs b/tests/compile-fail/panic/windows1.rs new file mode 100644 index 0000000000000..1d6faf1e751d9 --- /dev/null +++ b/tests/compile-fail/panic/windows1.rs @@ -0,0 +1,9 @@ +// ignore-linux +// ignore-macos + +// Test that panics on Windows give a reasonable error message. + +// error-pattern: panicking is not supported on this platform +fn main() { + core::panic!("this is {}", "Windows"); +} diff --git a/tests/compile-fail/panic/windows2.rs b/tests/compile-fail/panic/windows2.rs new file mode 100644 index 0000000000000..023088a692efa --- /dev/null +++ b/tests/compile-fail/panic/windows2.rs @@ -0,0 +1,9 @@ +// ignore-linux +// ignore-macos + +// Test that panics on Windows give a reasonable error message. + +// error-pattern: panicking is not supported on this platform +fn main() { + std::panic!("this is Windows"); +} diff --git a/tests/compile-fail/panic/windows3.rs b/tests/compile-fail/panic/windows3.rs new file mode 100644 index 0000000000000..b96022fc4ef5e --- /dev/null +++ b/tests/compile-fail/panic/windows3.rs @@ -0,0 +1,10 @@ +// ignore-linux +// ignore-macos + +// Test that panics on Windows give a reasonable error message. + +// error-pattern: panicking is not supported on this platform +#[allow(unconditional_panic)] +fn main() { + let _val = 1/0; +} From 5c09047411d3d1ba3a99893db64770864289d3a5 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 21 Mar 2020 10:43:59 +0100 Subject: [PATCH 1677/3747] fix tests --- tests/compile-fail/abort-terminator.rs | 1 + tests/compile-fail/{ => panic}/double_panic.rs | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) rename tests/compile-fail/{ => panic}/double_panic.rs (60%) diff --git a/tests/compile-fail/abort-terminator.rs b/tests/compile-fail/abort-terminator.rs index 1bfa289a52b4e..af1a155435fb6 100644 --- a/tests/compile-fail/abort-terminator.rs +++ b/tests/compile-fail/abort-terminator.rs @@ -1,4 +1,5 @@ // error-pattern: the evaluated program aborted +// ignore-windows (panics dont work on Windows) #![feature(unwind_attributes)] #[unwind(aborts)] diff --git a/tests/compile-fail/double_panic.rs b/tests/compile-fail/panic/double_panic.rs similarity index 60% rename from tests/compile-fail/double_panic.rs rename to tests/compile-fail/panic/double_panic.rs index 759762196b758..3085d0b006570 100644 --- a/tests/compile-fail/double_panic.rs +++ b/tests/compile-fail/panic/double_panic.rs @@ -1,4 +1,6 @@ - // error-pattern: the evaluated program aborted +// error-pattern: the evaluated program aborted +// ignore-windows (panics dont work on Windows) + struct Foo; impl Drop for Foo { fn drop(&mut self) { From e890d4d5e11c97be0769df0cb1593394e8a9f8c6 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 21 Mar 2020 12:52:23 +0100 Subject: [PATCH 1678/3747] call error location was fixed by rustup --- rust-version | 2 +- tests/compile-fail/cast_fn_ptr1.rs | 4 ++-- tests/compile-fail/cast_fn_ptr5.rs | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/rust-version b/rust-version index ca9c782d127ae..aaf176861b0db 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -f4c675c476c18b1a11041193f2f59d695b126bc8 +98803c182b2ba6ef5dccb6bf501958249295eac0 diff --git a/tests/compile-fail/cast_fn_ptr1.rs b/tests/compile-fail/cast_fn_ptr1.rs index 057cc64e9e3bc..3702ec8c94c43 100644 --- a/tests/compile-fail/cast_fn_ptr1.rs +++ b/tests/compile-fail/cast_fn_ptr1.rs @@ -1,9 +1,9 @@ fn main() { - fn f() {} //~ ERROR calling a function with more arguments than it expected + fn f() {} let g = unsafe { std::mem::transmute::(f) }; - g(42) + g(42) //~ ERROR calling a function with more arguments than it expected } diff --git a/tests/compile-fail/cast_fn_ptr5.rs b/tests/compile-fail/cast_fn_ptr5.rs index ff2a73d5a4859..fb2b4403363ef 100644 --- a/tests/compile-fail/cast_fn_ptr5.rs +++ b/tests/compile-fail/cast_fn_ptr5.rs @@ -1,9 +1,9 @@ fn main() { - fn f() -> u32 { 42 } //~ ERROR calling a function with return type u32 passing return place of type () + fn f() -> u32 { 42 } let g = unsafe { std::mem::transmute:: u32, fn()>(f) }; - g() + g() //~ ERROR calling a function with return type u32 passing return place of type () } From 6355228d4e6e44db6b16301aeed8aacdd944f07a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 21 Mar 2020 13:13:08 +0100 Subject: [PATCH 1679/3747] remove no longer needed (and sometimes broken) 'extern crate' --- src/bin/miri-rustc-tests.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/bin/miri-rustc-tests.rs b/src/bin/miri-rustc-tests.rs index 509a1592152d0..ab692e18f9097 100644 --- a/src/bin/miri-rustc-tests.rs +++ b/src/bin/miri-rustc-tests.rs @@ -1,13 +1,9 @@ #![feature(rustc_private)] -extern crate getopts; extern crate miri; extern crate rustc; -extern crate rustc_codegen_utils; extern crate rustc_driver; -extern crate rustc_errors; extern crate rustc_hir; extern crate rustc_interface; -extern crate rustc_metadata; extern crate rustc_span; use std::io; From eb3be2f97de00c0f0e2118c9372684b78496e4ca Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 21 Mar 2020 17:43:28 +0100 Subject: [PATCH 1680/3747] ./miri check --- miri | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/miri b/miri index f1eae220e0ded..47ff5024fc633 100755 --- a/miri +++ b/miri @@ -11,6 +11,9 @@ working directory. ./miri build : Just build miri. are passed to `cargo build`. +./miri check : +Just check miri. are passed to `cargo check`. + ./miri test : Build miri, set up a sysroot and then run the test suite. are passed to the final `cargo test` invocation. @@ -99,6 +102,10 @@ install|install-debug) # "--offline" to avoid querying the registry (for yanked packages). exec cargo install $CARGO_INSTALL_FLAGS --path "$(dirname "$0")" --force --locked --offline "$@" ;; +check|check-debug) + # Check, and let caller control flags. + exec cargo check $CARGO_BUILD_FLAGS "$@" + ;; build|build-debug) # Build, and let caller control flags. exec cargo build $CARGO_BUILD_FLAGS "$@" From 8acfafe186c073b047541f1aa177291850915c7d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 21 Mar 2020 17:54:18 +0100 Subject: [PATCH 1681/3747] test for zero-sized write_bytes to NULL --- tests/compile-fail/copy_null.rs | 3 +-- tests/compile-fail/write_bytes_null.rs | 10 ++++++++++ 2 files changed, 11 insertions(+), 2 deletions(-) create mode 100644 tests/compile-fail/write_bytes_null.rs diff --git a/tests/compile-fail/copy_null.rs b/tests/compile-fail/copy_null.rs index ce2fbe170e45d..b14bdc4b38632 100644 --- a/tests/compile-fail/copy_null.rs +++ b/tests/compile-fail/copy_null.rs @@ -1,4 +1,3 @@ -//error-pattern: invalid use of NULL pointer #![feature(intrinsics)] // Directly call intrinsic to avoid debug assertions in libstd @@ -10,5 +9,5 @@ fn main() { let mut data = [0u16; 4]; let ptr = &mut data[0] as *mut u16; // Even copying 0 elements from NULL should error. - unsafe { copy_nonoverlapping(std::ptr::null(), ptr, 0); } + unsafe { copy_nonoverlapping(std::ptr::null(), ptr, 0); } //~ ERROR: invalid use of NULL pointer } diff --git a/tests/compile-fail/write_bytes_null.rs b/tests/compile-fail/write_bytes_null.rs new file mode 100644 index 0000000000000..e80222162ee38 --- /dev/null +++ b/tests/compile-fail/write_bytes_null.rs @@ -0,0 +1,10 @@ +#![feature(intrinsics)] + +// Directly call intrinsic to avoid debug assertions in libstd +extern "rust-intrinsic" { + fn write_bytes(dst: *mut T, val: u8, count: usize); +} + +fn main() { + unsafe { write_bytes::(std::ptr::null_mut(), 0, 0) }; //~ ERROR invalid use of NULL pointer +} From 238ed49a07b94e0f34f39cb88198fc868b781f0c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 21 Mar 2020 17:54:33 +0100 Subject: [PATCH 1682/3747] detect UB: overflow in copy/write_bytes --- src/shims/intrinsics.rs | 9 +++++---- tests/compile-fail/copy_overflow.rs | 10 ++++++++++ tests/compile-fail/write_bytes_overflow.rs | 9 +++++++++ 3 files changed, 24 insertions(+), 4 deletions(-) create mode 100644 tests/compile-fail/copy_overflow.rs create mode 100644 tests/compile-fail/write_bytes_overflow.rs diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index a08c8a56cf2d5..9a6bd58ba42e1 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -4,7 +4,7 @@ use std::convert::TryFrom; use rustc::mir; use rustc::mir::interpret::{InterpResult, PointerArithmetic}; use rustc::ty; -use rustc::ty::layout::{Align, LayoutOf, Size}; +use rustc::ty::layout::{Align, LayoutOf}; use rustc_apfloat::Float; use rustc_span::source_map::Span; @@ -226,11 +226,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx => { let elem_ty = substs.type_at(0); let elem_layout = this.layout_of(elem_ty)?; - let elem_size = elem_layout.size.bytes(); let count = this.read_scalar(args[2])?.to_machine_usize(this)?; let elem_align = elem_layout.align.abi; - let size = Size::from_bytes(count) * elem_size; + let size = elem_layout.size.checked_mul(count, this) + .ok_or_else(|| err_ub_format!("overflow computing total size of `{}`", intrinsic_name))?; let src = this.read_scalar(args[0])?.not_undef()?; let src = this.memory.check_ptr_access(src, size, elem_align)?; let dest = this.read_scalar(args[1])?.not_undef()?; @@ -493,7 +493,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let val_byte = this.read_scalar(args[1])?.to_u8()?; let ptr = this.read_scalar(args[0])?.not_undef()?; let count = this.read_scalar(args[2])?.to_machine_usize(this)?; - let byte_count = ty_layout.size * count; + let byte_count = ty_layout.size.checked_mul(count, this) + .ok_or_else(|| err_ub_format!("overflow computing total size of `write_bytes`"))?; this.memory .write_bytes(ptr, iter::repeat(val_byte).take(byte_count.bytes() as usize))?; } diff --git a/tests/compile-fail/copy_overflow.rs b/tests/compile-fail/copy_overflow.rs new file mode 100644 index 0000000000000..c75cf6917b108 --- /dev/null +++ b/tests/compile-fail/copy_overflow.rs @@ -0,0 +1,10 @@ +// error-pattern: overflow computing total size of `copy` +use std::mem; + +fn main() { + let x = 0; + let mut y = 0; + unsafe { + (&mut y as *mut i32).copy_from(&x, 1usize << (mem::size_of::() * 8 - 1)); + } +} diff --git a/tests/compile-fail/write_bytes_overflow.rs b/tests/compile-fail/write_bytes_overflow.rs new file mode 100644 index 0000000000000..a6bf2acb16f30 --- /dev/null +++ b/tests/compile-fail/write_bytes_overflow.rs @@ -0,0 +1,9 @@ +// error-pattern: overflow computing total size of `write_bytes` +use std::mem; + +fn main() { + let mut y = 0; + unsafe { + (&mut y as *mut i32).write_bytes(0u8, 1usize << (mem::size_of::() * 8 - 1)); + } +} From 83060738354664190d4a45f7aefd5a7f5bbab609 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 21 Mar 2020 23:17:07 +0100 Subject: [PATCH 1683/3747] bump Rust --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index aaf176861b0db..29c1f3a2a83e0 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -98803c182b2ba6ef5dccb6bf501958249295eac0 +38114ff16e7856f98b2b4be7ab4cd29b38bed59a From 78fe5288d0f76ecb0993ed3be3dfc4eb731cea84 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 21 Mar 2020 23:17:18 +0100 Subject: [PATCH 1684/3747] do more cross-testing --- .travis.yml | 2 -- travis.sh | 35 +++++++++++++++++++++-------------- 2 files changed, 21 insertions(+), 16 deletions(-) diff --git a/.travis.yml b/.travis.yml index 3f0ca8a016bd2..137ae4fe66255 100644 --- a/.travis.yml +++ b/.travis.yml @@ -21,8 +21,6 @@ env: - RUST_BACKTRACE=1 before_script: -# Linux: install extra stuff for cross-compilation -- if [[ "$TRAVIS_OS_NAME" == linux ]]; then sudo apt update && sudo apt install gcc-multilib; fi # Compute the rust version we use. We do not use "language: rust" to have more control here. - | if [[ "$TRAVIS_EVENT_TYPE" == cron ]]; then diff --git a/travis.sh b/travis.sh index fec9145ab0f7e..4988c0e76ff6e 100755 --- a/travis.sh +++ b/travis.sh @@ -2,9 +2,6 @@ set -euo pipefail # Determine configuration -if [ "$TRAVIS_OS_NAME" == linux ]; then - FOREIGN_TARGET=i686-unknown-linux-gnu -fi export CARGO_EXTRA_FLAGS="--all-features" export RUSTC_EXTRA_FLAGS="-D warnings" @@ -16,19 +13,29 @@ echo # Test function run_tests { - ./miri test --locked + if [ -n "${FOREIGN_TARGET+exists}" ]; then + echo "Testing foreign architecture $FOREIGN_TARGET" + else + echo "Testing host architecture" + fi + + ./miri test --locked + if ! [ -n "${FOREIGN_TARGET+exists}" ]; then + # Only for host architecture: tests with MIR optimizations MIRI_TEST_FLAGS="-Z mir-opt-level=3" ./miri test - # "miri test" has built the sysroot for us, now this should pass without - # any interactive questions. - test-cargo-miri/run-test.py + fi + # "miri test" has built the sysroot for us, now this should pass without + # any interactive questions. + test-cargo-miri/run-test.py + + echo } -echo "Test host architecture" +# host run_tests -echo - -if [ -n "${FOREIGN_TARGET+exists}" ]; then - echo "Test foreign architecture ($FOREIGN_TARGET)" - MIRI_TEST_TARGET="$FOREIGN_TARGET" run_tests - echo +# cross-test 32bit Linux from everywhere +MIRI_TEST_TARGET=i686-unknown-linux-gnu run_tests +if [ "$TRAVIS_OS_NAME" == linux ]; then + # cross-test 64bit macOS from Linux + FOREIGN_TARGET=x86_64-apple-darwin run_tests fi From 82fe7716765c665565ff668c440303fe21345890 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 21 Mar 2020 23:26:44 +0100 Subject: [PATCH 1685/3747] also cross-test Windows from Linux, macOS --- travis.sh | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/travis.sh b/travis.sh index 4988c0e76ff6e..e9fa3b6c1aed4 100755 --- a/travis.sh +++ b/travis.sh @@ -35,7 +35,13 @@ function run_tests { run_tests # cross-test 32bit Linux from everywhere MIRI_TEST_TARGET=i686-unknown-linux-gnu run_tests + if [ "$TRAVIS_OS_NAME" == linux ]; then # cross-test 64bit macOS from Linux FOREIGN_TARGET=x86_64-apple-darwin run_tests + # cross-test 32bit Windows from Linux + FOREIGN_TARGET=i686-pc-windows-msvc run_tests +elif [ "$TRAVIS_OS_NAME" == osx ]; then + # cross-test 64bit Windows from macOS + FOREIGN_TARGET=x86_64-pc-windows-msvc run_tests fi From dece5bc4eec2fbe421cb95ca5c43e11cb6b93fc5 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 21 Mar 2020 23:28:10 +0100 Subject: [PATCH 1686/3747] fix bad use of FOREIGN_TARGET --- travis.sh | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/travis.sh b/travis.sh index e9fa3b6c1aed4..8b2453584b09a 100755 --- a/travis.sh +++ b/travis.sh @@ -13,14 +13,14 @@ echo # Test function run_tests { - if [ -n "${FOREIGN_TARGET+exists}" ]; then - echo "Testing foreign architecture $FOREIGN_TARGET" + if [ -n "${MIRI_TEST_TARGET+exists}" ]; then + echo "Testing foreign architecture $MIRI_TEST_TARGET" else echo "Testing host architecture" fi ./miri test --locked - if ! [ -n "${FOREIGN_TARGET+exists}" ]; then + if ! [ -n "${MIRI_TEST_TARGET+exists}" ]; then # Only for host architecture: tests with MIR optimizations MIRI_TEST_FLAGS="-Z mir-opt-level=3" ./miri test fi @@ -38,10 +38,10 @@ MIRI_TEST_TARGET=i686-unknown-linux-gnu run_tests if [ "$TRAVIS_OS_NAME" == linux ]; then # cross-test 64bit macOS from Linux - FOREIGN_TARGET=x86_64-apple-darwin run_tests + MIRI_TEST_TARGET=x86_64-apple-darwin run_tests # cross-test 32bit Windows from Linux - FOREIGN_TARGET=i686-pc-windows-msvc run_tests + MIRI_TEST_TARGET=i686-pc-windows-msvc run_tests elif [ "$TRAVIS_OS_NAME" == osx ]; then # cross-test 64bit Windows from macOS - FOREIGN_TARGET=x86_64-pc-windows-msvc run_tests + MIRI_TEST_TARGET=x86_64-pc-windows-msvc run_tests fi From d85f09c4e4bdee1d9698dce9a2163f46f1e1697d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 22 Mar 2020 08:51:15 +0100 Subject: [PATCH 1687/3747] platform -> target --- src/eval.rs | 2 +- src/helpers.rs | 12 +++++------ src/machine.rs | 2 +- src/shims/foreign_items.rs | 2 +- src/shims/fs.rs | 26 ++++++++++++------------ src/shims/panic.rs | 4 ++-- src/shims/time.rs | 6 +++--- test-cargo-miri/tests/test.rs | 2 +- tests/compile-fail/panic/windows1.rs | 2 +- tests/compile-fail/panic/windows2.rs | 2 +- tests/compile-fail/panic/windows3.rs | 2 +- tests/run-pass/bitop-beyond-alignment.rs | 2 +- tests/run-pass/memchr.rs | 2 +- 13 files changed, 33 insertions(+), 33 deletions(-) diff --git a/src/eval.rs b/src/eval.rs index 898e1ff6e4be4..de6c9fac1d5ee 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -190,7 +190,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( /// Returns `Some(return_code)` if program executed completed. /// Returns `None` if an evaluation error occured. pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) -> Option { - // FIXME: We always ignore leaks on some platforms where we do not + // FIXME: We always ignore leaks on some OSs where we do not // correctly implement TLS destructors. let target_os = tcx.sess.target.target.target_os.as_str(); let ignore_leaks = config.ignore_leaks || target_os == "windows" || target_os == "macos"; diff --git a/src/helpers.rs b/src/helpers.rs index 169bb4205649e..36d3181ce4e4b 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -374,16 +374,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } Ok(()) } - /// Helper function used inside the shims of foreign functions to assert that the target - /// platform is `platform`. It panics showing a message with the `name` of the foreign function + /// Helper function used inside the shims of foreign functions to assert that the target OS + /// is `target_os`. It panics showing a message with the `name` of the foreign function /// if this is not the case. - fn assert_platform(&self, platform: &str, name: &str) { + fn assert_target_os(&self, target_os: &str, name: &str) { assert_eq!( self.eval_context_ref().tcx.sess.target.target.target_os, - platform, - "`{}` is only available on the `{}` platform", + target_os, + "`{}` is only available on the `{}` target OS", name, - platform, + target_os, ) } diff --git a/src/machine.rs b/src/machine.rs index 3cf00781338c2..693c80f7deaea 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -126,7 +126,7 @@ impl MemoryExtra { .insert(Symbol::intern("environ"), this.machine.env_vars.environ.unwrap().ptr.assert_ptr().alloc_id) .unwrap_none(); } - _ => {} // No "extern statics" supported on this platform + _ => {} // No "extern statics" supported on this target } Ok(()) } diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 60da1f1e6cc6d..6827b72427fb1 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -437,7 +437,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx _ => match this.tcx.sess.target.target.target_os.as_str() { "linux" | "macos" => return posix::EvalContextExt::emulate_foreign_item_by_name(this, link_name, args, dest, ret), "windows" => return windows::EvalContextExt::emulate_foreign_item_by_name(this, link_name, args, dest, ret), - target => throw_unsup_format!("the {} target platform is not supported", target), + target => throw_unsup_format!("the target `{}` is not supported", target), } }; diff --git a/src/shims/fs.rs b/src/shims/fs.rs index a5aae5ed90c3a..d799d8ed9a8a6 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -66,9 +66,9 @@ impl FileHandler { impl<'mir, 'tcx> EvalContextExtPrivate<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} trait EvalContextExtPrivate<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { - /// Emulate `stat` or `lstat` on the `macos` platform. This function is not intended to be + /// Emulate `stat` or `lstat` on `macos`. This function is not intended to be /// called directly from `emulate_foreign_item_by_name`, so it does not check if isolation is - /// disabled or if the target platform is the correct one. Please use `macos_stat` or + /// disabled or if the target OS is the correct one. Please use `macos_stat` or /// `macos_lstat` instead. fn macos_stat_or_lstat( &mut self, @@ -114,7 +114,7 @@ trait EvalContextExtPrivate<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, ' let blksize_t_layout = this.libc_ty_layout("blksize_t")?; let uint32_t_layout = this.libc_ty_layout("uint32_t")?; - // We need to add 32 bits of padding after `st_rdev` if we are on a 64-bit platform. + // We need to add 32 bits of padding after `st_rdev` if we are on a 64-bit target. let pad_layout = if this.tcx.sess.target.ptr_width == 64 { uint32_t_layout } else { @@ -258,10 +258,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let o_wronly = this.eval_libc_i32("O_WRONLY")?; let o_rdwr = this.eval_libc_i32("O_RDWR")?; // The first two bits of the flag correspond to the access mode in linux, macOS and - // windows. We need to check that in fact the access mode flags for the current platform - // only use these two bits, otherwise we are in an unsupported platform and should error. + // windows. We need to check that in fact the access mode flags for the current target + // only use these two bits, otherwise we are in an unsupported target and should error. if (o_rdonly | o_wronly | o_rdwr) & !0b11 != 0 { - throw_unsup_format!("access mode flags on this platform are unsupported"); + throw_unsup_format!("access mode flags on this target are unsupported"); } let mut writable = true; @@ -574,7 +574,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx buf_op: OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - this.assert_platform("macos", "stat"); + this.assert_target_os("macos", "stat"); this.check_no_isolation("stat")?; // `stat` always follows symlinks. this.macos_stat_or_lstat(true, path_op, buf_op) @@ -587,7 +587,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx buf_op: OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - this.assert_platform("macos", "lstat"); + this.assert_target_os("macos", "lstat"); this.check_no_isolation("lstat")?; this.macos_stat_or_lstat(false, path_op, buf_op) } @@ -599,7 +599,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - this.assert_platform("macos", "fstat"); + this.assert_target_os("macos", "fstat"); this.check_no_isolation("fstat")?; let fd = this.read_scalar(fd_op)?.to_i32()?; @@ -621,7 +621,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - this.assert_platform("linux", "statx"); + this.assert_target_os("linux", "statx"); this.check_no_isolation("statx")?; let statxbuf_scalar = this.read_scalar(statxbuf_op)?.not_undef()?; @@ -685,7 +685,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // the `_mask_op` paramter specifies the file information that the caller requested. // However `statx` is allowed to return information that was not requested or to not // return information that was requested. This `mask` represents the information we can - // actually provide in any host platform. + // actually provide for any target. let mut mask = this.eval_libc("STATX_TYPE")?.to_u32()? | this.eval_libc("STATX_SIZE")?.to_u32()?; @@ -880,7 +880,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - this.assert_platform("linux", "readdir64_r"); + this.assert_target_os("linux", "readdir64_r"); this.check_no_isolation("readdir64_r")?; let dirp = this.read_scalar(dirp_op)?.to_machine_usize(this)?; @@ -967,7 +967,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - this.assert_platform("macos", "readdir_r"); + this.assert_target_os("macos", "readdir_r"); this.check_no_isolation("readdir_r")?; let dirp = this.read_scalar(dirp_op)?.to_machine_usize(this)?; diff --git a/src/shims/panic.rs b/src/shims/panic.rs index 8dded8bf4037b..703e711972a74 100644 --- a/src/shims/panic.rs +++ b/src/shims/panic.rs @@ -32,11 +32,11 @@ pub struct CatchUnwindData<'tcx> { impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { - /// Check if panicking is supported on this platform, and give a good error otherwise. + /// Check if panicking is supported on this target, and give a good error otherwise. fn check_panic_supported(&self) -> InterpResult<'tcx> { match self.eval_context_ref().tcx.sess.target.target.target_os.as_str() { "linux" | "macos" => Ok(()), - _ => throw_unsup_format!("panicking is not supported on this platform"), + _ => throw_unsup_format!("panicking is not supported on this target"), } } diff --git a/src/shims/time.rs b/src/shims/time.rs index b270c9770f809..58db60e516883 100644 --- a/src/shims/time.rs +++ b/src/shims/time.rs @@ -20,7 +20,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - this.assert_platform("linux", "clock_gettime"); + this.assert_target_os("linux", "clock_gettime"); this.check_no_isolation("clock_gettime")?; let clk_id = this.read_scalar(clk_id_op)?.to_i32()?; @@ -58,7 +58,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - this.assert_platform("macos", "gettimeofday"); + this.assert_target_os("macos", "gettimeofday"); this.check_no_isolation("gettimeofday")?; // Using tz is obsolete and should always be null @@ -88,7 +88,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn mach_absolute_time(&self) -> InterpResult<'tcx, u64> { let this = self.eval_context_ref(); - this.assert_platform("macos", "mach_absolute_time"); + this.assert_target_os("macos", "mach_absolute_time"); this.check_no_isolation("mach_absolute_time")?; // This returns a u64, with time units determined dynamically by `mach_timebase_info`. diff --git a/test-cargo-miri/tests/test.rs b/test-cargo-miri/tests/test.rs index 0095802a59a87..68d5426802b45 100644 --- a/test-cargo-miri/tests/test.rs +++ b/test-cargo-miri/tests/test.rs @@ -45,7 +45,7 @@ fn num_cpus() { // FIXME: Remove this `cfg` once we fix https://github.com/rust-lang/miri/issues/1059. // We cfg-gate the `should_panic` attribute and the `panic!` itself, so that the test -// stdout does not depend on the platform. +// stdout does not depend on the target. #[test] #[cfg_attr(not(windows), should_panic(expected="Explicit panic"))] fn do_panic() { // In large, friendly letters :) diff --git a/tests/compile-fail/panic/windows1.rs b/tests/compile-fail/panic/windows1.rs index 1d6faf1e751d9..142ba85c42c77 100644 --- a/tests/compile-fail/panic/windows1.rs +++ b/tests/compile-fail/panic/windows1.rs @@ -3,7 +3,7 @@ // Test that panics on Windows give a reasonable error message. -// error-pattern: panicking is not supported on this platform +// error-pattern: panicking is not supported on this target fn main() { core::panic!("this is {}", "Windows"); } diff --git a/tests/compile-fail/panic/windows2.rs b/tests/compile-fail/panic/windows2.rs index 023088a692efa..da2cfb59362ef 100644 --- a/tests/compile-fail/panic/windows2.rs +++ b/tests/compile-fail/panic/windows2.rs @@ -3,7 +3,7 @@ // Test that panics on Windows give a reasonable error message. -// error-pattern: panicking is not supported on this platform +// error-pattern: panicking is not supported on this target fn main() { std::panic!("this is Windows"); } diff --git a/tests/compile-fail/panic/windows3.rs b/tests/compile-fail/panic/windows3.rs index b96022fc4ef5e..a2e7bf5a7d438 100644 --- a/tests/compile-fail/panic/windows3.rs +++ b/tests/compile-fail/panic/windows3.rs @@ -3,7 +3,7 @@ // Test that panics on Windows give a reasonable error message. -// error-pattern: panicking is not supported on this platform +// error-pattern: panicking is not supported on this target #[allow(unconditional_panic)] fn main() { let _val = 1/0; diff --git a/tests/run-pass/bitop-beyond-alignment.rs b/tests/run-pass/bitop-beyond-alignment.rs index a30f0fb61314a..02031130b8dcc 100644 --- a/tests/run-pass/bitop-beyond-alignment.rs +++ b/tests/run-pass/bitop-beyond-alignment.rs @@ -33,5 +33,5 @@ fn is_u64_aligned(u: &Tag) -> bool { pub fn main() { let x = mk_rec(); - is_u64_aligned(&x.t); // the result of this is non-deterministic (even with a fixed seed, results vary between platforms) + is_u64_aligned(&x.t); // the result of this is non-deterministic (even with a fixed seed, results vary between targets) } diff --git a/tests/run-pass/memchr.rs b/tests/run-pass/memchr.rs index 2f5e2c4bb739e..e92c37ff2a8c7 100644 --- a/tests/run-pass/memchr.rs +++ b/tests/run-pass/memchr.rs @@ -2,7 +2,7 @@ use core::slice::memchr::{memchr, memrchr}; -// test fallback implementations on all platforms +// test fallback implementations on all targets fn matches_one() { assert_eq!(Some(0), memchr(b'a', b"a")); } From e1b654f09a6adeddb5a8b5e91cdcec656184c33f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 22 Mar 2020 08:55:53 +0100 Subject: [PATCH 1688/3747] mention cross-running in docs --- CONTRIBUTING.md | 10 ++++++---- README.md | 5 +++++ 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index c673e107d55d5..573f9f6ef6e41 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -52,18 +52,19 @@ all the same flags as `rustc` (though the ones only affecting code generation and linking obviously will have no effect) [and more][miri-flags]. Running the Miri driver requires some fiddling with environment variables, so -the `miri` script helps you do that. For example, you can run the driver on a -particular file by doing +the `miri` script helps you do that. For example, you can (cross-)run the +driver on a particular file by doing ```sh ./miri run tests/run-pass/format.rs ./miri run tests/run-pass/hello.rs --target i686-unknown-linux-gnu ``` -and you can run the test suite using: +and you can (cross-)run the test suite using: ``` ./miri test +MIRI_TEST_TARGET=i686-unknown-linux-gnu ./miri test ``` `./miri test FILTER` only runs those tests that contain `FILTER` in their @@ -104,7 +105,8 @@ and then you can use it as if it was installed by `rustup`. Make sure you use the same toolchain when calling `cargo miri` that you used when installing Miri! There's a test for the cargo wrapper in the `test-cargo-miri` directory; run -`./run-test.py` in there to execute it. +`./run-test.py` in there to execute it. Like `./miri test`, this respects the +`MIRI_TEST_TARGET` environment variable to execute the test for another target. ## Building Miri with a locally built rustc diff --git a/README.md b/README.md index e0e7df24faad7..59394830d79bc 100644 --- a/README.md +++ b/README.md @@ -76,6 +76,11 @@ Now you can run your project in Miri: The first time you run Miri, it will perform some extra setup and install some dependencies. It will ask you for confirmation before installing anything. +Miri supports cross-execution: if you want to run the program as if it was a +Linux program, you can do `cargo miri run --target x86_64-unknown-linux-gnu`. +This is particularly useful if you are using Windows, as the Linux target is +much better supported than Windows targets. + You can pass arguments to Miri after the first `--`, and pass arguments to the interpreted program or test suite after the second `--`. For example, `cargo miri run -- -Zmiri-disable-validation` runs the program without validation of From b843de6dd22f9fdfd998cd0c105cce17a31ab639 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 22 Mar 2020 09:04:10 +0100 Subject: [PATCH 1689/3747] run-test.py: also print what we are testing for --- test-cargo-miri/run-test.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/test-cargo-miri/run-test.py b/test-cargo-miri/run-test.py index a4086bcc8c99d..57b23a6a2afe2 100755 --- a/test-cargo-miri/run-test.py +++ b/test-cargo-miri/run-test.py @@ -7,6 +7,10 @@ import sys, subprocess, os +CGREEN = '\33[32m' +CBOLD = '\33[1m' +CEND = '\33[0m' + def fail(msg): print("\nTEST FAIL: {}".format(msg)) sys.exit(1) @@ -67,6 +71,9 @@ def test_cargo_miri_test(): os.chdir(os.path.dirname(os.path.realpath(__file__))) +target_str = " for target {}".format(os.environ['MIRI_TEST_TARGET']) if 'MIRI_TEST_TARGET' in os.environ else "" +print(CGREEN + CBOLD + "## Running `cargo miri` tests{}".format(target_str) + CEND) + if not 'MIRI_SYSROOT' in os.environ: # Make sure we got a working sysroot. # (If the sysroot gets built later when output is compared, that leads to test failures.) From a1b823886c072dfda3e3fdd34e5661beaf57d6d7 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 22 Mar 2020 18:50:12 +0100 Subject: [PATCH 1690/3747] give some context in error messages --- src/diagnostics.rs | 89 ++++++++++++++++++++++++++++------------------ 1 file changed, 54 insertions(+), 35 deletions(-) diff --git a/src/diagnostics.rs b/src/diagnostics.rs index b2590a843ba96..ee4084f42daf0 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -1,6 +1,7 @@ -use rustc_mir::interpret::InterpErrorInfo; use std::cell::RefCell; +use rustc_span::DUMMY_SP; + use crate::*; /// Miri specific diagnostics @@ -14,9 +15,16 @@ pub fn report_diagnostic<'tcx, 'mir>( ecx: &InterpCx<'mir, 'tcx, Evaluator<'tcx>>, mut e: InterpErrorInfo<'tcx>, ) -> Option { - // Special treatment for some error kinds + use InterpError::*; + let title = match e.kind { + Unsupported(_) => "unsupported operation", + UndefinedBehavior(_) => "Undefined Behavior", + InvalidProgram(_) => bug!("This error should be impossible in Miri: {}", e), + ResourceExhaustion(_) => "resource exhaustion", + MachineStop(_) => "program stopped", + }; let msg = match e.kind { - InterpError::MachineStop(ref info) => { + MachineStop(ref info) => { let info = info.downcast_ref::().expect("invalid MachineStop payload"); match info { TerminationInfo::Exit(code) => return Some(*code), @@ -24,52 +32,63 @@ pub fn report_diagnostic<'tcx, 'mir>( TerminationInfo::Abort(Some(msg)) => format!("the evaluated program aborted execution: {}", msg), } } - err_unsup!(NoMirFor(..)) => format!( - "{}. Did you set `MIRI_SYSROOT` to a Miri-enabled sysroot? You can prepare one with `cargo miri setup`.", - e - ), - InterpError::InvalidProgram(_) => bug!("This error should be impossible in Miri: {}", e), _ => e.to_string(), }; + let help = match e.kind { + Unsupported(UnsupportedOpInfo::NoMirFor(..)) => + Some("set `MIRI_SYSROOT` to a Miri sysroot, which you can prepare with `cargo miri setup`"), + Unsupported(_) => + Some("this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support"), + UndefinedBehavior(UndefinedBehaviorInfo::UbExperimental(_)) => + Some("this indicates a potential bug in the program: it violated *experimental* rules, and caused Undefined Behavior"), + UndefinedBehavior(_) => + Some("this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior"), + _ => None, + }; e.print_backtrace(); - report_msg(ecx, msg, true) + report_msg(ecx, &format!("{}: {}", title, msg), msg, help, true) } /// Report an error or note (depending on the `error` argument) at the current frame's current statement. /// Also emits a full stacktrace of the interpreter stack. pub fn report_msg<'tcx, 'mir>( ecx: &InterpCx<'mir, 'tcx, Evaluator<'tcx>>, - msg: String, + title: &str, + span_msg: String, + help: Option<&str>, error: bool, ) -> Option { - if let Some(frame) = ecx.stack().last() { - let span = frame.current_source_info().unwrap().span; - - let mut err = if error { - let msg = format!("Miri evaluation error: {}", msg); - ecx.tcx.sess.struct_span_err(span, msg.as_str()) + let span = if let Some(frame) = ecx.stack().last() { + frame.current_source_info().unwrap().span + } else { + DUMMY_SP + }; + let mut err = if error { + ecx.tcx.sess.struct_span_err(span, title) + } else { + ecx.tcx.sess.diagnostic().span_note_diag(span, title) + }; + err.span_label(span, span_msg); + if let Some(help) = help { + err.help(help); + } + // Add backtrace + let frames = ecx.generate_stacktrace(None); + // We iterate with indices because we need to look at the next frame (the caller). + for idx in 0..frames.len() { + let frame_info = &frames[idx]; + let call_site_is_local = frames + .get(idx + 1) + .map_or(false, |caller_info| caller_info.instance.def_id().is_local()); + if call_site_is_local { + err.span_note(frame_info.call_site, &frame_info.to_string()); } else { - ecx.tcx.sess.diagnostic().span_note_diag(span, msg.as_str()) - }; - let frames = ecx.generate_stacktrace(None); - err.span_label(span, msg); - // We iterate with indices because we need to look at the next frame (the caller). - for idx in 0..frames.len() { - let frame_info = &frames[idx]; - let call_site_is_local = frames - .get(idx + 1) - .map_or(false, |caller_info| caller_info.instance.def_id().is_local()); - if call_site_is_local { - err.span_note(frame_info.call_site, &frame_info.to_string()); - } else { - err.note(&frame_info.to_string()); - } + err.note(&frame_info.to_string()); } - err.emit(); - } else { - ecx.tcx.sess.err(&msg); } + err.emit(); + for (i, frame) in ecx.stack().iter().enumerate() { trace!("-------------------"); trace!("Frame {}", i); @@ -106,7 +125,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx CreatedAlloc(AllocId(id)) => format!("created allocation with id {}", id), }; - report_msg(this, msg, false); + report_msg(this, "tracking was triggered", msg, None, false); } }); } From 6dcca62b63135306aab50afc85075afa7427559a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 22 Mar 2020 19:48:59 +0100 Subject: [PATCH 1691/3747] move -Zmiri-disable-isolation hint to help --- src/diagnostics.rs | 82 ++++++++++++++++++++++++++++++---------------- src/eval.rs | 8 +---- src/helpers.rs | 6 ++-- src/lib.rs | 6 ++-- 4 files changed, 60 insertions(+), 42 deletions(-) diff --git a/src/diagnostics.rs b/src/diagnostics.rs index ee4084f42daf0..c46ff5354dec3 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -4,6 +4,13 @@ use rustc_span::DUMMY_SP; use crate::*; +/// Details of premature program termination. +pub enum TerminationInfo { + Exit(i64), + Abort(Option), + UnsupportedInIsolation(String), +} + /// Miri specific diagnostics pub enum NonHaltingDiagnostic { PoppedTrackedPointerTag(Item), @@ -11,47 +18,64 @@ pub enum NonHaltingDiagnostic { } /// Emit a custom diagnostic without going through the miri-engine machinery -pub fn report_diagnostic<'tcx, 'mir>( +pub fn report_error<'tcx, 'mir>( ecx: &InterpCx<'mir, 'tcx, Evaluator<'tcx>>, mut e: InterpErrorInfo<'tcx>, ) -> Option { use InterpError::*; - let title = match e.kind { - Unsupported(_) => "unsupported operation", - UndefinedBehavior(_) => "Undefined Behavior", - InvalidProgram(_) => bug!("This error should be impossible in Miri: {}", e), - ResourceExhaustion(_) => "resource exhaustion", - MachineStop(_) => "program stopped", - }; - let msg = match e.kind { - MachineStop(ref info) => { + + e.print_backtrace(); + let (title, msg, help) = match e.kind { + MachineStop(info) => { let info = info.downcast_ref::().expect("invalid MachineStop payload"); - match info { - TerminationInfo::Exit(code) => return Some(*code), - TerminationInfo::Abort(None) => format!("the evaluated program aborted execution"), - TerminationInfo::Abort(Some(msg)) => format!("the evaluated program aborted execution: {}", msg), - } + use TerminationInfo::*; + let (title, msg) = match info { + Exit(code) => return Some(*code), + Abort(None) => + ("abnormal termination", format!("the evaluated program aborted execution")), + Abort(Some(msg)) => + ("abnormal termination", format!("the evaluated program aborted execution: {}", msg)), + UnsupportedInIsolation(msg) => + ("unsupported operation", format!("{}", msg)), + }; + let help = match info { + UnsupportedInIsolation(_) => + Some("pass the flag `-Zmiri-disable-isolation` to disable isolation"), + _ => None, + }; + (title, msg, help) + } + _ => { + let (title, msg) = match e.kind { + Unsupported(_) => + ("unsupported operation", e.to_string()), + UndefinedBehavior(_) => + ("Undefined Behavior", e.to_string()), + ResourceExhaustion(_) => + ("resource exhaustion", e.to_string()), + _ => + bug!("This error should be impossible in Miri: {}", e), + }; + let help = match e.kind { + Unsupported(UnsupportedOpInfo::NoMirFor(..)) => + Some("set `MIRI_SYSROOT` to a Miri sysroot, which you can prepare with `cargo miri setup`"), + Unsupported(_) => + Some("this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support"), + UndefinedBehavior(UndefinedBehaviorInfo::UbExperimental(_)) => + Some("this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental"), + UndefinedBehavior(_) => + Some("this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior"), + _ => None, + }; + (title, msg, help) } - _ => e.to_string(), - }; - let help = match e.kind { - Unsupported(UnsupportedOpInfo::NoMirFor(..)) => - Some("set `MIRI_SYSROOT` to a Miri sysroot, which you can prepare with `cargo miri setup`"), - Unsupported(_) => - Some("this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support"), - UndefinedBehavior(UndefinedBehaviorInfo::UbExperimental(_)) => - Some("this indicates a potential bug in the program: it violated *experimental* rules, and caused Undefined Behavior"), - UndefinedBehavior(_) => - Some("this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior"), - _ => None, }; - e.print_backtrace(); report_msg(ecx, &format!("{}: {}", title, msg), msg, help, true) } /// Report an error or note (depending on the `error` argument) at the current frame's current statement. /// Also emits a full stacktrace of the interpreter stack. -pub fn report_msg<'tcx, 'mir>( +fn report_msg<'tcx, 'mir>( ecx: &InterpCx<'mir, 'tcx, Evaluator<'tcx>>, title: &str, span_msg: String, diff --git a/src/eval.rs b/src/eval.rs index de6c9fac1d5ee..d2ca57c39a792 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -51,12 +51,6 @@ impl Default for MiriConfig { } } -/// Details of premature program termination. -pub enum TerminationInfo { - Exit(i64), - Abort(Option), -} - /// Returns a freshly created `InterpCx`, along with an `MPlaceTy` representing /// the location where the return value of the `start` lang item will be /// written to. @@ -229,6 +223,6 @@ pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) -> } Some(return_code) } - Err(e) => report_diagnostic(&ecx, e), + Err(e) => report_error(&ecx, e), } } diff --git a/src/helpers.rs b/src/helpers.rs index 36d3181ce4e4b..ab6e33f231884 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -367,10 +367,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// case. fn check_no_isolation(&self, name: &str) -> InterpResult<'tcx> { if !self.eval_context_ref().machine.communicate { - throw_unsup_format!( - "`{}` not available when isolation is enabled (pass the flag `-Zmiri-disable-isolation` to disable isolation)", + throw_machine_stop!(TerminationInfo::UnsupportedInIsolation(format!( + "`{}` not available when isolation is enabled", name, - ) + ))) } Ok(()) } diff --git a/src/lib.rs b/src/lib.rs index 86fbabbd629ef..32eb5b41e5919 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -45,10 +45,10 @@ pub use crate::shims::tls::{EvalContextExt as TlsEvalContextExt, TlsData}; pub use crate::shims::EvalContextExt as ShimsEvalContextExt; pub use crate::diagnostics::{ - register_diagnostic, report_diagnostic, EvalContextExt as DiagnosticsEvalContextExt, - NonHaltingDiagnostic, + register_diagnostic, report_error, EvalContextExt as DiagnosticsEvalContextExt, + TerminationInfo, NonHaltingDiagnostic, }; -pub use crate::eval::{create_ecx, eval_main, MiriConfig, TerminationInfo}; +pub use crate::eval::{create_ecx, eval_main, MiriConfig}; pub use crate::helpers::EvalContextExt as HelpersEvalContextExt; pub use crate::machine::{ AllocExtra, Evaluator, FrameData, MemoryExtra, MiriEvalContext, MiriEvalContextExt, From dd4fef0cd95ba90ea6e1a13f054e2b66f36772ff Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 22 Mar 2020 20:09:14 +0100 Subject: [PATCH 1692/3747] fix outdated sysroot help message --- src/diagnostics.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/diagnostics.rs b/src/diagnostics.rs index c46ff5354dec3..1008c04684644 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -58,7 +58,7 @@ pub fn report_error<'tcx, 'mir>( }; let help = match e.kind { Unsupported(UnsupportedOpInfo::NoMirFor(..)) => - Some("set `MIRI_SYSROOT` to a Miri sysroot, which you can prepare with `cargo miri setup`"), + Some("make sure to use a Miri sysroot, which you can prepare with `cargo miri setup`"), Unsupported(_) => Some("this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support"), UndefinedBehavior(UndefinedBehaviorInfo::UbExperimental(_)) => From 6e302b830a8ac07efc1dca3ba1354338801bf7d4 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 22 Mar 2020 23:32:19 +0100 Subject: [PATCH 1693/3747] link to some websites for UB explanations --- src/diagnostics.rs | 43 +++++++++++++++++++++++++----------------- src/stacked_borrows.rs | 29 ++++++++++++++++++---------- 2 files changed, 45 insertions(+), 27 deletions(-) diff --git a/src/diagnostics.rs b/src/diagnostics.rs index 1008c04684644..a2cdffdf80b3d 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -9,6 +9,7 @@ pub enum TerminationInfo { Exit(i64), Abort(Option), UnsupportedInIsolation(String), + ExperimentalUb { msg: String, url: String } } /// Miri specific diagnostics @@ -25,7 +26,7 @@ pub fn report_error<'tcx, 'mir>( use InterpError::*; e.print_backtrace(); - let (title, msg, help) = match e.kind { + let (title, msg, helps) = match e.kind { MachineStop(info) => { let info = info.downcast_ref::().expect("invalid MachineStop payload"); use TerminationInfo::*; @@ -37,13 +38,20 @@ pub fn report_error<'tcx, 'mir>( ("abnormal termination", format!("the evaluated program aborted execution: {}", msg)), UnsupportedInIsolation(msg) => ("unsupported operation", format!("{}", msg)), + ExperimentalUb { msg, .. } => + ("Undefined Behavior", format!("{}", msg)), }; - let help = match info { + let helps = match info { UnsupportedInIsolation(_) => - Some("pass the flag `-Zmiri-disable-isolation` to disable isolation"), - _ => None, + vec![format!("pass the flag `-Zmiri-disable-isolation` to disable isolation")], + ExperimentalUb { url, .. } => + vec![ + format!("this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental"), + format!("see {} for further information", url), + ], + _ => vec![], }; - (title, msg, help) + (title, msg, helps) } _ => { let (title, msg) = match e.kind { @@ -56,21 +64,22 @@ pub fn report_error<'tcx, 'mir>( _ => bug!("This error should be impossible in Miri: {}", e), }; - let help = match e.kind { + let helps = match e.kind { Unsupported(UnsupportedOpInfo::NoMirFor(..)) => - Some("make sure to use a Miri sysroot, which you can prepare with `cargo miri setup`"), + vec![format!("make sure to use a Miri sysroot, which you can prepare with `cargo miri setup`")], Unsupported(_) => - Some("this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support"), - UndefinedBehavior(UndefinedBehaviorInfo::UbExperimental(_)) => - Some("this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental"), + vec![format!("this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support")], UndefinedBehavior(_) => - Some("this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior"), - _ => None, + vec![ + format!("this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior"), + format!("see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information"), + ], + _ => vec![], }; - (title, msg, help) + (title, msg, helps) } }; - report_msg(ecx, &format!("{}: {}", title, msg), msg, help, true) + report_msg(ecx, &format!("{}: {}", title, msg), msg, &helps, true) } /// Report an error or note (depending on the `error` argument) at the current frame's current statement. @@ -79,7 +88,7 @@ fn report_msg<'tcx, 'mir>( ecx: &InterpCx<'mir, 'tcx, Evaluator<'tcx>>, title: &str, span_msg: String, - help: Option<&str>, + helps: &[String], error: bool, ) -> Option { let span = if let Some(frame) = ecx.stack().last() { @@ -93,7 +102,7 @@ fn report_msg<'tcx, 'mir>( ecx.tcx.sess.diagnostic().span_note_diag(span, title) }; err.span_label(span, span_msg); - if let Some(help) = help { + for help in helps { err.help(help); } // Add backtrace @@ -149,7 +158,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx CreatedAlloc(AllocId(id)) => format!("created allocation with id {}", id), }; - report_msg(this, "tracking was triggered", msg, None, false); + report_msg(this, "tracking was triggered", msg, &[], false); } }); } diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 6188d05780cb5..05b9c478cfea3 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -192,6 +192,15 @@ impl GlobalState { } } +/// Error reporting +fn err_sb_ub(msg: String) -> InterpError<'static> { + // FIXME: use `err_machine_stop!` macro, once that exists. + InterpError::MachineStop(Box::new(TerminationInfo::ExperimentalUb { + msg, + url: format!("https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md"), + })) +} + // # Stacked Borrows Core Begin /// We need to make at least the following things true: @@ -272,15 +281,15 @@ impl<'tcx> Stack { if let Some(call) = item.protector { if global.is_active(call) { if let Some(tag) = tag { - throw_ub!(UbExperimental(format!( + Err(err_sb_ub(format!( "not granting access to tag {:?} because incompatible item is protected: {:?}", tag, item - ))); + )))? } else { - throw_ub!(UbExperimental(format!( + Err(err_sb_ub(format!( "deallocating while item is protected: {:?}", item - ))); + )))? } } } @@ -294,10 +303,10 @@ impl<'tcx> Stack { // Step 1: Find granting item. let granting_idx = self.find_granting(access, tag).ok_or_else(|| { - err_ub!(UbExperimental(format!( + err_sb_ub(format!( "no item granting {} to tag {:?} found in borrow stack.", access, tag - ),)) + )) })?; // Step 2: Remove incompatible items above them. Make sure we do not remove protected @@ -338,10 +347,10 @@ impl<'tcx> Stack { fn dealloc(&mut self, tag: Tag, global: &GlobalState) -> InterpResult<'tcx> { // Step 1: Find granting item. self.find_granting(AccessKind::Write, tag).ok_or_else(|| { - err_ub!(UbExperimental(format!( + err_sb_ub(format!( "no item granting write access for deallocation to tag {:?} found in borrow stack", tag, - ))) + )) })?; // Step 2: Remove all items. Also checks for protectors. @@ -363,10 +372,10 @@ impl<'tcx> Stack { // Now we figure out which item grants our parent (`derived_from`) this kind of access. // We use that to determine where to put the new item. let granting_idx = self.find_granting(access, derived_from) - .ok_or_else(|| err_ub!(UbExperimental(format!( + .ok_or_else(|| err_sb_ub(format!( "trying to reborrow for {:?}, but parent tag {:?} does not have an appropriate item in the borrow stack", new.perm, derived_from, - ))))?; + )))?; // Compute where to put the new item. // Either way, we ensure that we insert the new item in a way such that between From b4b8750e447058e06e8bf5ad38645ee05a81ef42 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 23 Mar 2020 10:34:15 +0100 Subject: [PATCH 1694/3747] bump Rust; HashMap should now work on macOS even with isolation --- rust-version | 2 +- src/shims/foreign_items/posix/macos.rs | 7 ------- tests/run-pass/hashmap.rs | 10 +++------- 3 files changed, 4 insertions(+), 15 deletions(-) diff --git a/rust-version b/rust-version index 29c1f3a2a83e0..70ece06e4f026 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -38114ff16e7856f98b2b4be7ab4cd29b38bed59a +8ff785011be6625e32afceee3a08e5cff7470feb diff --git a/src/shims/foreign_items/posix/macos.rs b/src/shims/foreign_items/posix/macos.rs index 0bb4710769d97..ee02effecd2c5 100644 --- a/src/shims/foreign_items/posix/macos.rs +++ b/src/shims/foreign_items/posix/macos.rs @@ -98,13 +98,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(this.machine.argv.expect("machine must be initialized"), dest)?; } - "SecRandomCopyBytes" => { - let len = this.read_scalar(args[1])?.to_machine_usize(this)?; - let ptr = this.read_scalar(args[2])?.not_undef()?; - this.gen_random(ptr, len)?; - this.write_null(dest)?; - } - _ => throw_unsup_format!("can't call foreign function: {}", link_name), }; diff --git a/tests/run-pass/hashmap.rs b/tests/run-pass/hashmap.rs index 85116796d3859..488fe6afe65e6 100644 --- a/tests/run-pass/hashmap.rs +++ b/tests/run-pass/hashmap.rs @@ -1,10 +1,7 @@ -// macOS needs FS access for its HashMap: -// compile-flags: -Zmiri-disable-isolation - use std::collections::HashMap; use std::hash::BuildHasher; -fn test_map(mut map: HashMap) { +fn smoketest_map(mut map: HashMap) { map.insert(0, 0); assert_eq!(map.values().fold(0, |x, y| x+y), 0); @@ -19,10 +16,9 @@ fn test_map(mut map: HashMap) { map.insert(i, num-1-i); } assert_eq!(map.values().fold(0, |x, y| x+y), num*(num-1)/2); - - // TODO: Test Entry API, Iterators, ... } fn main() { - test_map(HashMap::new()); + // hashbrown uses Miri on its own CI; we just do a smoketest here. + smoketest_map(HashMap::new()); } From 2f371774ef632f2dcc4548a39e8b6b98422a725b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 23 Mar 2020 19:43:03 +0100 Subject: [PATCH 1695/3747] fix conditional compilation condition for os_str <-> bytes conversion --- src/helpers.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index ab6e33f231884..b4706f04d9b87 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -463,11 +463,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx 'tcx: 'a, 'mir: 'a, { - #[cfg(target_os = "unix")] + #[cfg(unix)] fn bytes_to_os_str<'tcx, 'a>(bytes: &'a [u8]) -> InterpResult<'tcx, &'a OsStr> { - Ok(std::os::unix::ffi::OsStringExt::from_bytes(bytes)) + Ok(std::os::unix::ffi::OsStrExt::from_bytes(bytes)) } - #[cfg(not(target_os = "unix"))] + #[cfg(not(unix))] fn bytes_to_os_str<'tcx, 'a>(bytes: &'a [u8]) -> InterpResult<'tcx, &'a OsStr> { let s = std::str::from_utf8(bytes) .map_err(|_| err_unsup_format!("{:?} is not a valid utf-8 string", bytes))?; @@ -490,11 +490,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx scalar: Scalar, size: u64, ) -> InterpResult<'tcx, (bool, u64)> { - #[cfg(target_os = "unix")] + #[cfg(unix)] fn os_str_to_bytes<'tcx, 'a>(os_str: &'a OsStr) -> InterpResult<'tcx, &'a [u8]> { - std::os::unix::ffi::OsStringExt::into_bytes(os_str) + Ok(std::os::unix::ffi::OsStrExt::as_bytes(os_str)) } - #[cfg(not(target_os = "unix"))] + #[cfg(not(unix))] fn os_str_to_bytes<'tcx, 'a>(os_str: &'a OsStr) -> InterpResult<'tcx, &'a [u8]> { // On non-unix platforms the best we can do to transform bytes from/to OS strings is to do the // intermediate transformation into strings. Which invalidates non-utf8 paths that are actually From 284067cc15f5254b6b0391c1c93de8f34a8a4e8c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 23 Mar 2020 23:48:24 +0100 Subject: [PATCH 1696/3747] rustup --- rust-version | 2 +- src/stacked_borrows.rs | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/rust-version b/rust-version index 70ece06e4f026..1270131b72677 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -8ff785011be6625e32afceee3a08e5cff7470feb +1edd389cc4c7b5be7a3dd4fe4b986f6017018e54 diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 05b9c478cfea3..37f2acf4c3bce 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -194,11 +194,10 @@ impl GlobalState { /// Error reporting fn err_sb_ub(msg: String) -> InterpError<'static> { - // FIXME: use `err_machine_stop!` macro, once that exists. - InterpError::MachineStop(Box::new(TerminationInfo::ExperimentalUb { + err_machine_stop!(TerminationInfo::ExperimentalUb { msg, url: format!("https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md"), - })) + }) } // # Stacked Borrows Core Begin From 90918111474cb573a4183bb9b8eb04dfd8150275 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 23 Mar 2020 23:53:54 +0100 Subject: [PATCH 1697/3747] use Wake trait for async-fn driver --- tests/run-pass/async-fn.rs | 29 ++++++++++------------------- 1 file changed, 10 insertions(+), 19 deletions(-) diff --git a/tests/run-pass/async-fn.rs b/tests/run-pass/async-fn.rs index 90448aca17792..b0a9791233437 100644 --- a/tests/run-pass/async-fn.rs +++ b/tests/run-pass/async-fn.rs @@ -1,7 +1,9 @@ #![feature(never_type)] +#![feature(wake_trait)] -use std::{future::Future, pin::Pin, task::Poll, ptr}; -use std::task::{Waker, RawWaker, RawWakerVTable, Context}; +use std::{future::Future, pin::Pin, task::Poll}; +use std::task::{Wake, Waker, Context}; +use std::sync::Arc; // See if we can run a basic `async fn` pub async fn foo(x: &u32, y: u32) -> u32 { @@ -47,25 +49,14 @@ async fn partial_init(x: u32) -> u32 { } fn run_fut(mut fut: impl Future, output: u32) { - fn raw_waker_clone(_this: *const ()) -> RawWaker { - panic!("unimplemented"); + struct MyWaker; + impl Wake for MyWaker { + fn wake(self: Arc) { + unimplemented!() + } } - fn raw_waker_wake(_this: *const ()) { - panic!("unimplemented"); - } - fn raw_waker_wake_by_ref(_this: *const ()) { - panic!("unimplemented"); - } - fn raw_waker_drop(_this: *const ()) {} - - static RAW_WAKER: RawWakerVTable = RawWakerVTable::new( - raw_waker_clone, - raw_waker_wake, - raw_waker_wake_by_ref, - raw_waker_drop, - ); - let waker = unsafe { Waker::from_raw(RawWaker::new(ptr::null(), &RAW_WAKER)) }; + let waker = Waker::from(Arc::new(MyWaker)); let mut context = Context::from_waker(&waker); assert_eq!(unsafe { Pin::new_unchecked(&mut fut) }.poll(&mut context), Poll::Ready(output)); } From 5f9167bdaa033f568b2528881b0fe3a2cdac27dc Mon Sep 17 00:00:00 2001 From: JOE1994 Date: Mon, 23 Mar 2020 15:08:57 -0400 Subject: [PATCH 1698/3747] helper functions for env_var emulation in Windows --- src/helpers.rs | 115 +++++++++++++++++++++++++++++++++++++++++++++-- src/shims/env.rs | 20 +++++---- 2 files changed, 123 insertions(+), 12 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index b4706f04d9b87..76c5308cfd35b 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -1,4 +1,4 @@ -use std::ffi::OsStr; +use std::ffi::{OsStr, OsString}; use std::{iter, mem}; use std::convert::TryFrom; @@ -456,6 +456,18 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } + /// Dispatches to appropriate implementations for reading an OsString from Memory, + /// depending on the interpretation target. + /// FIXME: Use `Cow` to avoid copies + fn read_os_str_from_target_str(&self, scalar: Scalar) -> InterpResult<'tcx, OsString> { + let target_os = self.eval_context_ref().tcx.sess.target.target.target_os.as_str(); + match target_os { + "linux" | "macos" => self.read_os_str_from_c_str(scalar).map(|x| x.to_os_string()), + "windows" => self.read_os_str_from_wide_str(scalar), + unsupported => throw_unsup_format!("OsString support for target OS `{}` not yet available", unsupported), + } + } + /// Helper function to read an OsString from a null-terminated sequence of bytes, which is what /// the Unix APIs usually handle. fn read_os_str_from_c_str<'a>(&'a self, scalar: Scalar) -> InterpResult<'tcx, &'a OsStr> @@ -471,7 +483,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn bytes_to_os_str<'tcx, 'a>(bytes: &'a [u8]) -> InterpResult<'tcx, &'a OsStr> { let s = std::str::from_utf8(bytes) .map_err(|_| err_unsup_format!("{:?} is not a valid utf-8 string", bytes))?; - Ok(&OsStr::new(s)) + Ok(OsStr::new(s)) } let this = self.eval_context_ref(); @@ -479,6 +491,29 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx bytes_to_os_str(bytes) } + /// Helper function to read an OsString from a 0x0000-terminated sequence of u16, + /// which is what the Windows APIs usually handle. + fn read_os_str_from_wide_str<'a>(&'a self, scalar: Scalar) -> InterpResult<'tcx, OsString> + where + 'tcx: 'a, + 'mir: 'a, + { + #[cfg(windows)] + pub fn u16vec_to_osstring<'tcx, 'a>(u16_vec: Vec) -> InterpResult<'tcx, OsString> { + Ok(std::os::windows::ffi::OsStringExt::from_wide(&u16_vec[..])) + } + #[cfg(not(windows))] + pub fn u16vec_to_osstring<'tcx, 'a>(u16_vec: Vec) -> InterpResult<'tcx, OsString> { + let s = String::from_utf16(&u16_vec[..]) + .map_err(|_| err_unsup_format!("{:?} is not a valid utf-16 string", u16_vec))?; + Ok(s.into()) + } + + let u16_vec = self.eval_context_ref().memory.read_wide_str(scalar)?; + u16vec_to_osstring(u16_vec) + } + + /// Helper function to write an OsStr as a null-terminated sequence of bytes, which is what /// the Unix APIs usually handle. This function returns `Ok((false, length))` without trying /// to write if `size` is not large enough to fit the contents of `os_string` plus a null @@ -518,6 +553,66 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok((true, string_length)) } + /// Helper function to write an OsStr as a 0x0000-terminated u16-sequence, which is what + /// the Windows APIs usually handle. This function returns `Ok((false, length))` without trying + /// to write if `size` is not large enough to fit the contents of `os_string` plus a null + /// terminator. It returns `Ok((true, length))` if the writing process was successful. The + /// string length returned does not include the null terminator. + fn write_os_str_to_wide_str( + &mut self, + os_str: &OsStr, + mplace: MPlaceTy<'tcx, Tag>, + size: u64, + ) -> InterpResult<'tcx, (bool, u64)> { + #[cfg(windows)] + fn os_str_to_u16vec<'tcx>(os_str: &OsStr) -> InterpResult<'tcx, Vec> { + Ok(std::os::windows::ffi::OsStrExt::encode_wide(os_str).collect()) + } + #[cfg(not(windows))] + fn os_str_to_u16vec<'tcx>(os_str: &OsStr) -> InterpResult<'tcx, Vec> { + // On non-Windows platforms the best we can do to transform Vec from/to OS strings is to do the + // intermediate transformation into strings. Which invalidates non-utf8 paths that are actually + // valid. + os_str + .to_str() + .map(|s| s.encode_utf16().collect()) + .ok_or_else(|| err_unsup_format!("{:?} is not a valid utf-8 string", os_str).into()) + } + + let u16_vec = os_str_to_u16vec(os_str)?; + // If `size` is smaller or equal than `bytes.len()`, writing `bytes` plus the required + // 0x0000 terminator to memory would cause an out-of-bounds access. + let string_length = u64::try_from(u16_vec.len()).unwrap(); + if size <= string_length { + return Ok((false, string_length)); + } + + let this = self.eval_context_mut(); + + // Store the UTF-16 string. + let char_size = Size::from_bytes(2); + for (idx, c) in u16_vec.into_iter().chain(iter::once(0x0000)).enumerate() { + let place = this.mplace_field(mplace, idx as u64)?; + this.write_scalar(Scalar::from_uint(c, char_size), place.into())?; + } + Ok((true, string_length)) + } + + /// Dispatches to appropriate implementations for allocating & writing OsString in Memory, + /// depending on the interpretation target. + fn alloc_os_str_as_target_str( + &mut self, + os_str: &OsStr, + memkind: MemoryKind, + ) -> InterpResult<'tcx, Pointer> { + let target_os = self.eval_context_ref().tcx.sess.target.target.target_os.as_str(); + match target_os { + "linux" | "macos" => Ok(self.alloc_os_str_as_c_str(os_str, memkind)), + "windows" => Ok(self.alloc_os_str_as_wide_str(os_str, memkind)), + unsupported => throw_unsup_format!("OsString support for target OS `{}` not yet available", unsupported), + } + } + fn alloc_os_str_as_c_str( &mut self, os_str: &OsStr, @@ -528,7 +623,21 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let arg_type = this.tcx.mk_array(this.tcx.types.u8, size); let arg_place = this.allocate(this.layout_of(arg_type).unwrap(), memkind); - self.write_os_str_to_c_str(os_str, arg_place.ptr, size).unwrap(); + assert!(self.write_os_str_to_c_str(os_str, arg_place.ptr, size).unwrap().0); + arg_place.ptr.assert_ptr() + } + + fn alloc_os_str_as_wide_str( + &mut self, + os_str: &OsStr, + memkind: MemoryKind, + ) -> Pointer { + let size = u64::try_from(os_str.len()).unwrap().checked_add(1).unwrap(); // Make space for `0x0000` terminator. + let this = self.eval_context_mut(); + + let arg_type = this.tcx.mk_array(this.tcx.types.u16, size); + let arg_place = this.allocate(this.layout_of(arg_type).unwrap(), memkind); + assert!(self.write_os_str_to_wide_str(os_str, arg_place, size).unwrap().0); arg_place.ptr.assert_ptr() } } diff --git a/src/shims/env.rs b/src/shims/env.rs index da634c1aeb237..6b18cd25a1b0f 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -13,7 +13,7 @@ use rustc_mir::interpret::Pointer; #[derive(Default)] pub struct EnvVars<'tcx> { /// Stores pointers to the environment variables. These variables must be stored as - /// null-terminated C strings with the `"{name}={value}"` format. + /// null-terminated target strings (c_str or wide_str) with the `"{name}={value}"` format. map: FxHashMap>, /// Place where the `environ` static is stored. Lazily initialized, but then never changes. @@ -29,7 +29,7 @@ impl<'tcx> EnvVars<'tcx> { for (name, value) in env::vars() { if !excluded_env_vars.contains(&name) { let var_ptr = - alloc_env_var_as_c_str(name.as_ref(), value.as_ref(), ecx); + alloc_env_var_as_target_str(name.as_ref(), value.as_ref(), ecx)?; ecx.machine.env_vars.map.insert(OsString::from(name), var_ptr); } } @@ -38,21 +38,23 @@ impl<'tcx> EnvVars<'tcx> { } } -fn alloc_env_var_as_c_str<'mir, 'tcx>( +fn alloc_env_var_as_target_str<'mir, 'tcx>( name: &OsStr, value: &OsStr, ecx: &mut InterpCx<'mir, 'tcx, Evaluator<'tcx>>, -) -> Pointer { +) -> InterpResult<'tcx, Pointer> { let mut name_osstring = name.to_os_string(); name_osstring.push("="); name_osstring.push(value); - ecx.alloc_os_str_as_c_str(name_osstring.as_os_str(), MiriMemoryKind::Machine.into()) + Ok(ecx.alloc_os_str_as_target_str(name_osstring.as_os_str(), MiriMemoryKind::Machine.into())?) } impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { fn getenv(&mut self, name_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); + let target_os = this.tcx.sess.target.target.target_os.as_str(); + assert!(target_os == "linux" || target_os == "macos", "`{}` is only available for the UNIX target family"); let name_ptr = this.read_scalar(name_op)?.not_undef()?; let name = this.read_os_str_from_c_str(name_ptr)?; @@ -74,17 +76,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let name_ptr = this.read_scalar(name_op)?.not_undef()?; let value_ptr = this.read_scalar(value_op)?.not_undef()?; - let value = this.read_os_str_from_c_str(value_ptr)?; + let value = this.read_os_str_from_target_str(value_ptr)?; let mut new = None; if !this.is_null(name_ptr)? { - let name = this.read_os_str_from_c_str(name_ptr)?; + let name = this.read_os_str_from_target_str(name_ptr)?; if !name.is_empty() && !name.to_string_lossy().contains('=') { new = Some((name.to_owned(), value.to_owned())); } } if let Some((name, value)) = new { - let var_ptr = alloc_env_var_as_c_str(&name, &value, &mut this); - if let Some(var) = this.machine.env_vars.map.insert(name.to_owned(), var_ptr) { + let var_ptr = alloc_env_var_as_target_str(&name, &value, &mut this)?; + if let Some(var) = this.machine.env_vars.map.insert(name, var_ptr) { this.memory .deallocate(var, None, MiriMemoryKind::Machine.into())?; } From 80088e131b0c3b15071602254b15a01cb2f82612 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 24 Mar 2020 08:24:36 +0100 Subject: [PATCH 1699/3747] rustup for trait MachineStopType --- rust-version | 2 +- src/diagnostics.rs | 57 +++++++++++++++++++++++++++++++--------------- 2 files changed, 40 insertions(+), 19 deletions(-) diff --git a/rust-version b/rust-version index 1270131b72677..7658d0bff9d84 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -1edd389cc4c7b5be7a3dd4fe4b986f6017018e54 +342c5f33d097b2dc07a2dbc0ca45a37379d2ff60 diff --git a/src/diagnostics.rs b/src/diagnostics.rs index a2cdffdf80b3d..2e4023e0b5bf8 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -1,4 +1,5 @@ use std::cell::RefCell; +use std::fmt; use rustc_span::DUMMY_SP; @@ -12,6 +13,26 @@ pub enum TerminationInfo { ExperimentalUb { msg: String, url: String } } +impl fmt::Debug for TerminationInfo { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + use TerminationInfo::*; + match self { + Exit(code) => + write!(f, "the evaluated program completed with exit code {}", code), + Abort(None) => + write!(f, "the evaluated program aborted execution"), + Abort(Some(msg)) => + write!(f, "the evaluated program aborted execution: {}", msg), + UnsupportedInIsolation(msg) => + write!(f, "{}", msg), + ExperimentalUb { msg, .. } => + write!(f, "{}", msg), + } + } +} + +impl MachineStopType for TerminationInfo {} + /// Miri specific diagnostics pub enum NonHaltingDiagnostic { PoppedTrackedPointerTag(Item), @@ -25,21 +46,18 @@ pub fn report_error<'tcx, 'mir>( ) -> Option { use InterpError::*; - e.print_backtrace(); - let (title, msg, helps) = match e.kind { - MachineStop(info) => { + let (title, helps) = match e.kind { + MachineStop(ref info) => { let info = info.downcast_ref::().expect("invalid MachineStop payload"); use TerminationInfo::*; - let (title, msg) = match info { + let title = match info { Exit(code) => return Some(*code), - Abort(None) => - ("abnormal termination", format!("the evaluated program aborted execution")), - Abort(Some(msg)) => - ("abnormal termination", format!("the evaluated program aborted execution: {}", msg)), - UnsupportedInIsolation(msg) => - ("unsupported operation", format!("{}", msg)), - ExperimentalUb { msg, .. } => - ("Undefined Behavior", format!("{}", msg)), + Abort(_) => + "abnormal termination", + UnsupportedInIsolation(_) => + "unsupported operation", + ExperimentalUb { .. } => + "Undefined Behavior", }; let helps = match info { UnsupportedInIsolation(_) => @@ -51,16 +69,16 @@ pub fn report_error<'tcx, 'mir>( ], _ => vec![], }; - (title, msg, helps) + (title, helps) } _ => { - let (title, msg) = match e.kind { + let title = match e.kind { Unsupported(_) => - ("unsupported operation", e.to_string()), + "unsupported operation", UndefinedBehavior(_) => - ("Undefined Behavior", e.to_string()), + "Undefined Behavior", ResourceExhaustion(_) => - ("resource exhaustion", e.to_string()), + "resource exhaustion", _ => bug!("This error should be impossible in Miri: {}", e), }; @@ -76,9 +94,12 @@ pub fn report_error<'tcx, 'mir>( ], _ => vec![], }; - (title, msg, helps) + (title, helps) } }; + + e.print_backtrace(); + let msg = e.to_string(); report_msg(ecx, &format!("{}: {}", title, msg), msg, &helps, true) } From 87f549571543160626ba25b3082e16ad1b3cd6b2 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 24 Mar 2020 08:25:37 +0100 Subject: [PATCH 1700/3747] 32bit macOS is no more --- src/shims/fs.rs | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/src/shims/fs.rs b/src/shims/fs.rs index d799d8ed9a8a6..16d83188dbc27 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -114,13 +114,6 @@ trait EvalContextExtPrivate<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, ' let blksize_t_layout = this.libc_ty_layout("blksize_t")?; let uint32_t_layout = this.libc_ty_layout("uint32_t")?; - // We need to add 32 bits of padding after `st_rdev` if we are on a 64-bit target. - let pad_layout = if this.tcx.sess.target.ptr_width == 64 { - uint32_t_layout - } else { - this.layout_of(this.tcx.mk_unit())? - }; - let imms = [ immty_from_uint_checked(0u128, dev_t_layout)?, // st_dev immty_from_uint_checked(mode, mode_t_layout)?, // st_mode @@ -129,7 +122,7 @@ trait EvalContextExtPrivate<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, ' immty_from_uint_checked(0u128, uid_t_layout)?, // st_uid immty_from_uint_checked(0u128, gid_t_layout)?, // st_gid immty_from_uint_checked(0u128, dev_t_layout)?, // st_rdev - immty_from_uint_checked(0u128, pad_layout)?, // padding for 64-bit targets + immty_from_uint_checked(0u128, uint32_t_layout)?, // padding immty_from_uint_checked(access_sec, time_t_layout)?, // st_atime immty_from_uint_checked(access_nsec, long_layout)?, // st_atime_nsec immty_from_uint_checked(modified_sec, time_t_layout)?, // st_mtime From da721233d705b6f011747d75e7ada23e948b820e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 22 Mar 2020 20:08:00 +0100 Subject: [PATCH 1701/3747] cross-test on a Windows host --- .appveyor.yml | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index 4281fe0180f05..919802d12abe5 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -2,7 +2,6 @@ environment: global: PROJECT_NAME: miri matrix: - - TARGET: x86_64-pc-windows-msvc - TARGET: i686-pc-windows-msvc # branches to build @@ -43,18 +42,33 @@ build_script: # Build and install miri - cargo build --release --all-features --all-targets --locked - cargo install --all-features --force --path . --locked --offline - # Get ourselves a MIR-full libstd, and use it henceforth - - cargo miri setup - - set MIRI_SYSROOT=%USERPROFILE%\AppData\Local\rust-lang\miri\cache\HOST test_script: - set RUST_TEST_NOCAPTURE=1 - set RUST_BACKTRACE=1 - # Test miri + # Test host miri: 32bit Windows + - cargo miri setup + - set MIRI_SYSROOT=%USERPROFILE%\AppData\Local\rust-lang\miri\cache\HOST + - cargo test --release --all-features --locked + - cd test-cargo-miri + - '"C:\msys64\mingw64\bin\python3.exe" run-test.py' + - cd .. + # Test foreign miri: 64bit Linux + - cargo miri setup --target x86_64-unknown-linux-gnu + - set MIRI_SYSROOT=%USERPROFILE%\AppData\Local\rust-lang\miri\cache + - set MIRI_TEST_TARGET=x86_64-unknown-linux-gnu + - cargo test --release --all-features --locked + - cd test-cargo-miri + - '"C:\msys64\mingw64\bin\python3.exe" run-test.py' + - cd .. + # Test foreign miri: 64bit macOS + - cargo miri setup --target x86_64-apple-darwin + - set MIRI_SYSROOT=%USERPROFILE%\AppData\Local\rust-lang\miri\cache + - set MIRI_TEST_TARGET=x86_64-apple-darwin - cargo test --release --all-features --locked - # Test cargo integration - cd test-cargo-miri - '"C:\msys64\mingw64\bin\python3.exe" run-test.py' + - cd .. after_test: # Don't cache "master" toolchain, it's a waste From 3517ce66abe20263316830f13a164aff78abc5a2 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 22 Mar 2020 20:32:42 +0100 Subject: [PATCH 1702/3747] need to unset MIRI_SYSROOT before calling 'cargo miri setup' --- .appveyor.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.appveyor.yml b/.appveyor.yml index 919802d12abe5..e5c2f4fb7294a 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -53,6 +53,7 @@ test_script: - cd test-cargo-miri - '"C:\msys64\mingw64\bin\python3.exe" run-test.py' - cd .. + - ps: $env:MIRI_SYSROOT = "" # Test foreign miri: 64bit Linux - cargo miri setup --target x86_64-unknown-linux-gnu - set MIRI_SYSROOT=%USERPROFILE%\AppData\Local\rust-lang\miri\cache @@ -61,6 +62,7 @@ test_script: - cd test-cargo-miri - '"C:\msys64\mingw64\bin\python3.exe" run-test.py' - cd .. + - ps: $env:MIRI_SYSROOT = "" # Test foreign miri: 64bit macOS - cargo miri setup --target x86_64-apple-darwin - set MIRI_SYSROOT=%USERPROFILE%\AppData\Local\rust-lang\miri\cache @@ -69,6 +71,7 @@ test_script: - cd test-cargo-miri - '"C:\msys64\mingw64\bin\python3.exe" run-test.py' - cd .. + - ps: $env:MIRI_SYSROOT = "" after_test: # Don't cache "master" toolchain, it's a waste From 4ac91384ff124d5b6258a648df5176909ff1b780 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 23 Mar 2020 19:24:16 +0100 Subject: [PATCH 1703/3747] route all path reading/writing through central read/write methods --- src/helpers.rs | 24 +++++++++++++++++++++++- src/shims/env.rs | 4 ++-- src/shims/fs.rs | 42 +++++++++++++++++++++--------------------- 3 files changed, 46 insertions(+), 24 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index 76c5308cfd35b..d8731b537719b 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -1,6 +1,8 @@ use std::ffi::{OsStr, OsString}; +use std::path::Path; use std::{iter, mem}; use std::convert::TryFrom; +use std::borrow::Cow; use rustc::mir; use rustc::ty::{ @@ -491,6 +493,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx bytes_to_os_str(bytes) } + /// Read a null-terminated sequence of bytes, and perform path separator conversion if needed. + fn read_path_from_c_str<'a>(&'a self, scalar: Scalar) -> InterpResult<'tcx, Cow<'a, Path>> + where + 'tcx: 'a, + 'mir: 'a, + { + let os_str = self.read_os_str_from_c_str(scalar)?; + Ok(Cow::Borrowed(Path::new(os_str))) + } + /// Helper function to read an OsString from a 0x0000-terminated sequence of u16, /// which is what the Windows APIs usually handle. fn read_os_str_from_wide_str<'a>(&'a self, scalar: Scalar) -> InterpResult<'tcx, OsString> @@ -513,7 +525,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx u16vec_to_osstring(u16_vec) } - /// Helper function to write an OsStr as a null-terminated sequence of bytes, which is what /// the Unix APIs usually handle. This function returns `Ok((false, length))` without trying /// to write if `size` is not large enough to fit the contents of `os_string` plus a null @@ -553,6 +564,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok((true, string_length)) } + /// Write a Path to the machine memory, adjusting path separators if needed. + fn write_path_to_c_str( + &mut self, + path: &Path, + scalar: Scalar, + size: u64, + ) -> InterpResult<'tcx, (bool, u64)> { + let os_str = path.as_os_str(); + self.write_os_str_to_c_str(os_str, scalar, size) + } + /// Helper function to write an OsStr as a 0x0000-terminated u16-sequence, which is what /// the Windows APIs usually handle. This function returns `Ok((false, length))` without trying /// to write if `size` is not large enough to fit the contents of `os_string` plus a null diff --git a/src/shims/env.rs b/src/shims/env.rs index 6b18cd25a1b0f..192fc0d47abec 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -134,7 +134,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // If we cannot get the current directory, we return null match env::current_dir() { Ok(cwd) => { - if this.write_os_str_to_c_str(&OsString::from(cwd), buf, size)?.0 { + if this.write_path_to_c_str(&cwd, buf, size)?.0 { return Ok(buf); } let erange = this.eval_libc("ERANGE")?; @@ -150,7 +150,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.check_no_isolation("chdir")?; - let path = this.read_os_str_from_c_str(this.read_scalar(path_op)?.not_undef()?)?; + let path = this.read_path_from_c_str(this.read_scalar(path_op)?.not_undef()?)?; match env::set_current_dir(path) { Ok(()) => Ok(0), diff --git a/src/shims/fs.rs b/src/shims/fs.rs index 16d83188dbc27..9778775fca641 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -2,7 +2,7 @@ use std::collections::BTreeMap; use std::convert::{TryFrom, TryInto}; use std::fs::{read_dir, remove_dir, remove_file, rename, DirBuilder, File, FileType, OpenOptions, ReadDir}; use std::io::{Read, Seek, SeekFrom, Write}; -use std::path::PathBuf; +use std::path::Path; use std::time::SystemTime; use rustc_data_structures::fx::FxHashMap; @@ -79,9 +79,9 @@ trait EvalContextExtPrivate<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, ' let this = self.eval_context_mut(); let path_scalar = this.read_scalar(path_op)?.not_undef()?; - let path: PathBuf = this.read_os_str_from_c_str(path_scalar)?.into(); + let path = this.read_path_from_c_str(path_scalar)?.into_owned(); - let metadata = match FileMetadata::from_path(this, path, follow_symlink)? { + let metadata = match FileMetadata::from_path(this, &path, follow_symlink)? { Some(metadata) => metadata, None => return Ok(-1), }; @@ -303,7 +303,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx throw_unsup_format!("unsupported flags {:#x}", flag & !mirror); } - let path = this.read_os_str_from_c_str(this.read_scalar(path_op)?.not_undef()?)?; + let path = this.read_path_from_c_str(this.read_scalar(path_op)?.not_undef()?)?; let fd = options.open(&path).map(|file| { let fh = &mut this.machine.file_handler; @@ -524,10 +524,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.check_no_isolation("unlink")?; - let path = this.read_os_str_from_c_str(this.read_scalar(path_op)?.not_undef()?)?; + let path = this.read_path_from_c_str(this.read_scalar(path_op)?.not_undef()?)?; let result = remove_file(path).map(|_| 0); - this.try_unwrap_io_result(result) } @@ -537,12 +536,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx linkpath_op: OpTy<'tcx, Tag> ) -> InterpResult<'tcx, i32> { #[cfg(target_family = "unix")] - fn create_link(src: PathBuf, dst: PathBuf) -> std::io::Result<()> { + fn create_link(src: &Path, dst: &Path) -> std::io::Result<()> { std::os::unix::fs::symlink(src, dst) } #[cfg(target_family = "windows")] - fn create_link(src: PathBuf, dst: PathBuf) -> std::io::Result<()> { + fn create_link(src: &Path, dst: &Path) -> std::io::Result<()> { use std::os::windows::fs; if src.is_dir() { fs::symlink_dir(src, dst) @@ -555,10 +554,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.check_no_isolation("symlink")?; - let target = this.read_os_str_from_c_str(this.read_scalar(target_op)?.not_undef()?)?.into(); - let linkpath = this.read_os_str_from_c_str(this.read_scalar(linkpath_op)?.not_undef()?)?.into(); + let target = this.read_path_from_c_str(this.read_scalar(target_op)?.not_undef()?)?; + let linkpath = this.read_path_from_c_str(this.read_scalar(linkpath_op)?.not_undef()?)?; - this.try_unwrap_io_result(create_link(target, linkpath).map(|_| 0)) + let result = create_link(&target, &linkpath).map(|_| 0); + this.try_unwrap_io_result(result) } fn macos_stat( @@ -644,7 +644,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.ref_to_mplace(statxbuf_imm)? }; - let path: PathBuf = this.read_os_str_from_c_str(pathname_scalar)?.into(); + let path = this.read_path_from_c_str(pathname_scalar)?.into_owned(); // `flags` should be a `c_int` but the `syscall` function provides an `isize`. let flags: i32 = this.read_scalar(flags_op)?.to_machine_isize(&*this.tcx)?.try_into().map_err(|e| { @@ -691,7 +691,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let metadata = if path.as_os_str().is_empty() && empty_path_flag { FileMetadata::from_fd(this, dirfd)? } else { - FileMetadata::from_path(this, path, follow_symlink)? + FileMetadata::from_path(this, &path, follow_symlink)? }; let metadata = match metadata { Some(metadata) => metadata, @@ -785,8 +785,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx return Ok(-1); } - let oldpath = this.read_os_str_from_c_str(oldpath_scalar)?; - let newpath = this.read_os_str_from_c_str(newpath_scalar)?; + let oldpath = this.read_path_from_c_str(oldpath_scalar)?; + let newpath = this.read_path_from_c_str(newpath_scalar)?; let result = rename(oldpath, newpath).map(|_| 0); @@ -808,7 +808,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.read_scalar(mode_op)?.to_u32()? }; - let path = this.read_os_str_from_c_str(this.read_scalar(path_op)?.not_undef()?)?; + let path = this.read_path_from_c_str(this.read_scalar(path_op)?.not_undef()?)?; let mut builder = DirBuilder::new(); @@ -833,7 +833,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.check_no_isolation("rmdir")?; - let path = this.read_os_str_from_c_str(this.read_scalar(path_op)?.not_undef()?)?; + let path = this.read_path_from_c_str(this.read_scalar(path_op)?.not_undef()?)?; let result = remove_dir(path).map(|_| 0i32); @@ -845,7 +845,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.check_no_isolation("opendir")?; - let name = this.read_os_str_from_c_str(this.read_scalar(name_op)?.not_undef()?)?; + let name = this.read_path_from_c_str(this.read_scalar(name_op)?.not_undef()?)?; let result = read_dir(name); @@ -899,7 +899,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let entry_place = this.deref_operand(entry_op)?; let name_place = this.mplace_field(entry_place, 4)?; - let file_name = dir_entry.file_name(); + let file_name = dir_entry.file_name(); // not a Path as there are no separators! let (name_fits, _) = this.write_os_str_to_c_str( &file_name, name_place.ptr, @@ -987,7 +987,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let entry_place = this.deref_operand(entry_op)?; let name_place = this.mplace_field(entry_place, 5)?; - let file_name = dir_entry.file_name(); + let file_name = dir_entry.file_name(); // not a Path as there are no separators! let (name_fits, file_name_len) = this.write_os_str_to_c_str( &file_name, name_place.ptr, @@ -1082,7 +1082,7 @@ struct FileMetadata { impl FileMetadata { fn from_path<'tcx, 'mir>( ecx: &mut MiriEvalContext<'mir, 'tcx>, - path: PathBuf, + path: &Path, follow_symlink: bool ) -> InterpResult<'tcx, Option> { let metadata = if follow_symlink { From c4e29c8646e3836cec79bd17a73ac13a2b90e6e4 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 23 Mar 2020 19:57:40 +0100 Subject: [PATCH 1704/3747] convert dir separators on path load/store --- src/helpers.rs | 78 ++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 69 insertions(+), 9 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index d8731b537719b..abfe3253ce7b3 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -1,9 +1,14 @@ use std::ffi::{OsStr, OsString}; -use std::path::Path; +use std::path::{Path, PathBuf}; use std::{iter, mem}; use std::convert::TryFrom; use std::borrow::Cow; +#[cfg(unix)] +use std::os::unix::ffi::{OsStrExt, OsStringExt}; +#[cfg(windows)] +use std::os::windows::ffi::{OsStrExt, OsStringExt}; + use rustc::mir; use rustc::ty::{ self, @@ -479,7 +484,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx { #[cfg(unix)] fn bytes_to_os_str<'tcx, 'a>(bytes: &'a [u8]) -> InterpResult<'tcx, &'a OsStr> { - Ok(std::os::unix::ffi::OsStrExt::from_bytes(bytes)) + Ok(OsStr::from_bytes(bytes)) } #[cfg(not(unix))] fn bytes_to_os_str<'tcx, 'a>(bytes: &'a [u8]) -> InterpResult<'tcx, &'a OsStr> { @@ -499,8 +504,34 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx 'tcx: 'a, 'mir: 'a, { - let os_str = self.read_os_str_from_c_str(scalar)?; - Ok(Cow::Borrowed(Path::new(os_str))) + let this = self.eval_context_ref(); + let os_str = this.read_os_str_from_c_str(scalar)?; + + #[cfg(windows)] + return Ok(if this.tcx.sess.target.target.target_os == "windows" { + // Windows-on-Windows, all fine. + Cow::Borrowed(Path::new(os_str)) + } else { + // Unix target, Windows host. Need to convert target '/' to host '\'. + let converted = os_str + .encode_wide() + .map(|wchar| if wchar == '/' as u16 { '\\' as u16 } else { wchar }) + .collect::>(); + Cow::Owned(PathBuf::from(OsString::from_wide(&converted))) + }); + #[cfg(unix)] + return Ok(if this.tcx.sess.target.target.target_os == "windows" { + // Windows target, Unix host. Need to convert target '\' to host '/'. + let converted = os_str + .as_bytes() + .iter() + .map(|&wchar| if wchar == '/' as u8 { '\\' as u8 } else { wchar }) + .collect::>(); + Cow::Owned(PathBuf::from(OsString::from_vec(converted))) + } else { + // Unix-on-Unix, all is fine. + Cow::Borrowed(Path::new(os_str)) + }); } /// Helper function to read an OsString from a 0x0000-terminated sequence of u16, @@ -512,7 +543,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx { #[cfg(windows)] pub fn u16vec_to_osstring<'tcx, 'a>(u16_vec: Vec) -> InterpResult<'tcx, OsString> { - Ok(std::os::windows::ffi::OsStringExt::from_wide(&u16_vec[..])) + Ok(OsString::from_wide(&u16_vec[..])) } #[cfg(not(windows))] pub fn u16vec_to_osstring<'tcx, 'a>(u16_vec: Vec) -> InterpResult<'tcx, OsString> { @@ -538,7 +569,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, (bool, u64)> { #[cfg(unix)] fn os_str_to_bytes<'tcx, 'a>(os_str: &'a OsStr) -> InterpResult<'tcx, &'a [u8]> { - Ok(std::os::unix::ffi::OsStrExt::as_bytes(os_str)) + Ok(os_str.as_bytes()) } #[cfg(not(unix))] fn os_str_to_bytes<'tcx, 'a>(os_str: &'a OsStr) -> InterpResult<'tcx, &'a [u8]> { @@ -571,8 +602,37 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx scalar: Scalar, size: u64, ) -> InterpResult<'tcx, (bool, u64)> { - let os_str = path.as_os_str(); - self.write_os_str_to_c_str(os_str, scalar, size) + let this = self.eval_context_mut(); + + #[cfg(windows)] + let os_str = if this.tcx.sess.target.target.target_os == "windows" { + // Windows-on-Windows, all fine. + Cow::Borrowed(path.as_os_str()) + } else { + // Unix target, Windows host. Need to convert host '\\' to target '/'. + let converted = path + .as_os_str() + .encode_wide() + .map(|wchar| if wchar == '\\' as u16 { '/' as u16 } else { wchar }) + .collect::>(); + Cow::Owned(OsString::from_wide(&converted)) + }; + #[cfg(unix)] + let os_str = if this.tcx.sess.target.target.target_os == "windows" { + // Windows target, Unix host. Need to convert host '/' to target '\'. + let converted = path + .as_os_str() + .as_bytes() + .iter() + .map(|&wchar| if wchar == '/' as u8 { '\\' as u8 } else { wchar }) + .collect::>(); + Cow::Owned(OsString::from_vec(converted)) + } else { + // Unix-on-Unix, all is fine. + Cow::Borrowed(path.as_os_str()) + }; + + this.write_os_str_to_c_str(&os_str, scalar, size) } /// Helper function to write an OsStr as a 0x0000-terminated u16-sequence, which is what @@ -588,7 +648,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, (bool, u64)> { #[cfg(windows)] fn os_str_to_u16vec<'tcx>(os_str: &OsStr) -> InterpResult<'tcx, Vec> { - Ok(std::os::windows::ffi::OsStrExt::encode_wide(os_str).collect()) + Ok(os_str.encode_wide().collect()) } #[cfg(not(windows))] fn os_str_to_u16vec<'tcx>(os_str: &OsStr) -> InterpResult<'tcx, Vec> { From 3ba588db496c99eb6a9280400271af4cb1958a91 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 23 Mar 2020 23:48:12 +0100 Subject: [PATCH 1705/3747] make fs.rs at least build under Windows --- tests/run-pass/fs.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/run-pass/fs.rs b/tests/run-pass/fs.rs index 0f3512b366050..b6d460f7a981c 100644 --- a/tests/run-pass/fs.rs +++ b/tests/run-pass/fs.rs @@ -142,7 +142,10 @@ fn test_symlink() { let symlink_path = prepare("miri_test_fs_symlink.txt"); // Creating a symbolic link should succeed. + #[cfg(unix)] std::os::unix::fs::symlink(&path, &symlink_path).unwrap(); + #[cfg(windows)] + std::os::windows::fs::symlink_file(&path, &symlink_path).unwrap(); // Test that the symbolic link has the same contents as the file. let mut symlink_file = File::open(&symlink_path).unwrap(); let mut contents = Vec::new(); From 8817397828f2e4aedf4251bdc02c6299d1d1654c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 23 Mar 2020 23:42:03 +0100 Subject: [PATCH 1706/3747] test harness informs tests about suitable temp dir --- tests/compiletest.rs | 2 ++ tests/run-pass/fs.rs | 10 ++++++---- tests/run-pass/libc.rs | 11 ++++++++--- 3 files changed, 16 insertions(+), 7 deletions(-) diff --git a/tests/compiletest.rs b/tests/compiletest.rs index f43ff8ca349de..d082a2cc484bd 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -110,6 +110,8 @@ fn get_target() -> String { fn test_runner(_tests: &[&()]) { // Add a test env var to do environment communication tests. std::env::set_var("MIRI_ENV_VAR_TEST", "0"); + // Let the tests know where to store temp files (they might run for a different target, which can make this hard to find). + std::env::set_var("MIRI_TEMP", std::env::temp_dir()); let target = get_target(); miri_pass("tests/run-pass", &target); diff --git a/tests/run-pass/fs.rs b/tests/run-pass/fs.rs index b6d460f7a981c..104ba46c3e458 100644 --- a/tests/run-pass/fs.rs +++ b/tests/run-pass/fs.rs @@ -16,10 +16,13 @@ fn main() { test_directory(); } +fn tmp() -> PathBuf { + std::env::var("MIRI_TEMP").map(PathBuf::from).unwrap_or_else(|_| std::env::temp_dir()) +} + /// Prepare: compute filename and make sure the file does not exist. fn prepare(filename: &str) -> PathBuf { - let tmp = std::env::temp_dir(); - let path = tmp.join(filename); + let path = tmp().join(filename); // Clean the paths for robustness. remove_file(&path).ok(); path @@ -27,8 +30,7 @@ fn prepare(filename: &str) -> PathBuf { /// Prepare directory: compute directory name and make sure it does not exist. fn prepare_dir(dirname: &str) -> PathBuf { - let tmp = std::env::temp_dir(); - let path = tmp.join(&dirname); + let path = tmp().join(&dirname); // Clean the directory for robustness. remove_dir_all(&path).ok(); path diff --git a/tests/run-pass/libc.rs b/tests/run-pass/libc.rs index 5b7b37db327be..064c00e81bb86 100644 --- a/tests/run-pass/libc.rs +++ b/tests/run-pass/libc.rs @@ -2,19 +2,24 @@ // compile-flags: -Zmiri-disable-isolation #![feature(rustc_private)] +#![allow(unused)] // necessary on macos due to conditional compilation + +use std::path::PathBuf; -#[allow(unused)] // necessary on macos due to conditional compilation extern crate libc; +fn tmp() -> PathBuf { + std::env::var("MIRI_TEMP").map(PathBuf::from).unwrap_or_else(|_| std::env::temp_dir()) +} + #[cfg(not(target_os = "macos"))] fn test_posix_fadvise() { use std::convert::TryInto; - use std::env::temp_dir; use std::fs::{File, remove_file}; use std::io::Write; use std::os::unix::io::AsRawFd; - let path = temp_dir().join("miri_test_libc.txt"); + let path = tmp().join("miri_test_libc.txt"); // Cleanup before test remove_file(&path).ok(); From e9e04e56fc6767f63458de1c137b5231cfd77b33 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 24 Mar 2020 08:38:05 +0100 Subject: [PATCH 1707/3747] move path methods together, to the bottom of the string helpers --- src/helpers.rs | 156 +++++++++++++++++++++++++------------------------ 1 file changed, 79 insertions(+), 77 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index abfe3253ce7b3..7ca2b238218a1 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -498,42 +498,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx bytes_to_os_str(bytes) } - /// Read a null-terminated sequence of bytes, and perform path separator conversion if needed. - fn read_path_from_c_str<'a>(&'a self, scalar: Scalar) -> InterpResult<'tcx, Cow<'a, Path>> - where - 'tcx: 'a, - 'mir: 'a, - { - let this = self.eval_context_ref(); - let os_str = this.read_os_str_from_c_str(scalar)?; - - #[cfg(windows)] - return Ok(if this.tcx.sess.target.target.target_os == "windows" { - // Windows-on-Windows, all fine. - Cow::Borrowed(Path::new(os_str)) - } else { - // Unix target, Windows host. Need to convert target '/' to host '\'. - let converted = os_str - .encode_wide() - .map(|wchar| if wchar == '/' as u16 { '\\' as u16 } else { wchar }) - .collect::>(); - Cow::Owned(PathBuf::from(OsString::from_wide(&converted))) - }); - #[cfg(unix)] - return Ok(if this.tcx.sess.target.target.target_os == "windows" { - // Windows target, Unix host. Need to convert target '\' to host '/'. - let converted = os_str - .as_bytes() - .iter() - .map(|&wchar| if wchar == '/' as u8 { '\\' as u8 } else { wchar }) - .collect::>(); - Cow::Owned(PathBuf::from(OsString::from_vec(converted))) - } else { - // Unix-on-Unix, all is fine. - Cow::Borrowed(Path::new(os_str)) - }); - } - /// Helper function to read an OsString from a 0x0000-terminated sequence of u16, /// which is what the Windows APIs usually handle. fn read_os_str_from_wide_str<'a>(&'a self, scalar: Scalar) -> InterpResult<'tcx, OsString> @@ -595,46 +559,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok((true, string_length)) } - /// Write a Path to the machine memory, adjusting path separators if needed. - fn write_path_to_c_str( - &mut self, - path: &Path, - scalar: Scalar, - size: u64, - ) -> InterpResult<'tcx, (bool, u64)> { - let this = self.eval_context_mut(); - - #[cfg(windows)] - let os_str = if this.tcx.sess.target.target.target_os == "windows" { - // Windows-on-Windows, all fine. - Cow::Borrowed(path.as_os_str()) - } else { - // Unix target, Windows host. Need to convert host '\\' to target '/'. - let converted = path - .as_os_str() - .encode_wide() - .map(|wchar| if wchar == '\\' as u16 { '/' as u16 } else { wchar }) - .collect::>(); - Cow::Owned(OsString::from_wide(&converted)) - }; - #[cfg(unix)] - let os_str = if this.tcx.sess.target.target.target_os == "windows" { - // Windows target, Unix host. Need to convert host '/' to target '\'. - let converted = path - .as_os_str() - .as_bytes() - .iter() - .map(|&wchar| if wchar == '/' as u8 { '\\' as u8 } else { wchar }) - .collect::>(); - Cow::Owned(OsString::from_vec(converted)) - } else { - // Unix-on-Unix, all is fine. - Cow::Borrowed(path.as_os_str()) - }; - - this.write_os_str_to_c_str(&os_str, scalar, size) - } - /// Helper function to write an OsStr as a 0x0000-terminated u16-sequence, which is what /// the Windows APIs usually handle. This function returns `Ok((false, length))` without trying /// to write if `size` is not large enough to fit the contents of `os_string` plus a null @@ -674,7 +598,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Store the UTF-16 string. let char_size = Size::from_bytes(2); for (idx, c) in u16_vec.into_iter().chain(iter::once(0x0000)).enumerate() { - let place = this.mplace_field(mplace, idx as u64)?; + let place = this.mplace_field(mplace, u64::try_from(idx).unwrap())?; this.write_scalar(Scalar::from_uint(c, char_size), place.into())?; } Ok((true, string_length)) @@ -695,6 +619,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } + /// Allocate enough memory to store the given `OsStr` as a null-terminated sequence of bytes. fn alloc_os_str_as_c_str( &mut self, os_str: &OsStr, @@ -709,6 +634,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx arg_place.ptr.assert_ptr() } + /// Allocate enough memory to store the given `OsStr` as a null-terminated sequence of `u16`. fn alloc_os_str_as_wide_str( &mut self, os_str: &OsStr, @@ -722,6 +648,82 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx assert!(self.write_os_str_to_wide_str(os_str, arg_place, size).unwrap().0); arg_place.ptr.assert_ptr() } + + /// Read a null-terminated sequence of bytes, and perform path separator conversion if needed. + fn read_path_from_c_str<'a>(&'a self, scalar: Scalar) -> InterpResult<'tcx, Cow<'a, Path>> + where + 'tcx: 'a, + 'mir: 'a, + { + let this = self.eval_context_ref(); + let os_str = this.read_os_str_from_c_str(scalar)?; + + #[cfg(windows)] + return Ok(if this.tcx.sess.target.target.target_os == "windows" { + // Windows-on-Windows, all fine. + Cow::Borrowed(Path::new(os_str)) + } else { + // Unix target, Windows host. Need to convert target '/' to host '\'. + let converted = os_str + .encode_wide() + .map(|wchar| if wchar == '/' as u16 { '\\' as u16 } else { wchar }) + .collect::>(); + Cow::Owned(PathBuf::from(OsString::from_wide(&converted))) + }); + #[cfg(unix)] + return Ok(if this.tcx.sess.target.target.target_os == "windows" { + // Windows target, Unix host. Need to convert target '\' to host '/'. + let converted = os_str + .as_bytes() + .iter() + .map(|&wchar| if wchar == '/' as u8 { '\\' as u8 } else { wchar }) + .collect::>(); + Cow::Owned(PathBuf::from(OsString::from_vec(converted))) + } else { + // Unix-on-Unix, all is fine. + Cow::Borrowed(Path::new(os_str)) + }); + } + + /// Write a Path to the machine memory, adjusting path separators if needed. + fn write_path_to_c_str( + &mut self, + path: &Path, + scalar: Scalar, + size: u64, + ) -> InterpResult<'tcx, (bool, u64)> { + let this = self.eval_context_mut(); + + #[cfg(windows)] + let os_str = if this.tcx.sess.target.target.target_os == "windows" { + // Windows-on-Windows, all fine. + Cow::Borrowed(path.as_os_str()) + } else { + // Unix target, Windows host. Need to convert host '\\' to target '/'. + let converted = path + .as_os_str() + .encode_wide() + .map(|wchar| if wchar == '\\' as u16 { '/' as u16 } else { wchar }) + .collect::>(); + Cow::Owned(OsString::from_wide(&converted)) + }; + #[cfg(unix)] + let os_str = if this.tcx.sess.target.target.target_os == "windows" { + // Windows target, Unix host. Need to convert host '/' to target '\'. + let converted = path + .as_os_str() + .as_bytes() + .iter() + .map(|&wchar| if wchar == '/' as u8 { '\\' as u8 } else { wchar }) + .collect::>(); + Cow::Owned(OsString::from_vec(converted)) + } else { + // Unix-on-Unix, all is fine. + Cow::Borrowed(path.as_os_str()) + }; + + this.write_os_str_to_c_str(&os_str, scalar, size) + } } pub fn immty_from_int_checked<'tcx>( From 9b0e9dec49096a409d5f5e333dbf4f2a766b3c70 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 25 Mar 2020 09:05:24 +0100 Subject: [PATCH 1708/3747] rustup, adjust for renames --- rust-version | 2 +- src/machine.rs | 22 +++++++++++----------- src/stacked_borrows.rs | 10 +++++----- 3 files changed, 17 insertions(+), 17 deletions(-) diff --git a/rust-version b/rust-version index 7658d0bff9d84..3a7d316af8e9e 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -342c5f33d097b2dc07a2dbc0ca45a37379d2ff60 +02046a5d402c789c006d0da7662f800fe3c45faf diff --git a/src/machine.rs b/src/machine.rs index 693c80f7deaea..84ac8b81a0618 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -50,8 +50,8 @@ pub enum MiriMemoryKind { WinHeap, /// Memory for env vars and args, errno, extern statics and other parts of the machine-managed environment. Machine, - /// Rust statics. - Static, + /// Globals copied from `tcx`. + Global, } impl Into> for MiriMemoryKind { @@ -212,7 +212,7 @@ impl<'mir, 'tcx> MiriEvalContextExt<'mir, 'tcx> for MiriEvalContext<'mir, 'tcx> /// Machine hook implementations. impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { - type MemoryKinds = MiriMemoryKind; + type MemoryKind = MiriMemoryKind; type FrameExtra = FrameData<'tcx>; type MemoryExtra = MemoryExtra; @@ -223,7 +223,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { type MemoryMap = MonoHashMap, Allocation)>; - const STATIC_KIND: Option = Some(MiriMemoryKind::Static); + const GLOBAL_KIND: Option = Some(MiriMemoryKind::Global); const CHECK_ALIGN: bool = true; @@ -348,7 +348,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { memory_extra: &MemoryExtra, id: AllocId, alloc: Cow<'b, Allocation>, - kind: Option>, + kind: Option>, ) -> (Cow<'b, Allocation>, Self::PointerTag) { if Some(id) == memory_extra.tracked_alloc_id { register_diagnostic(NonHaltingDiagnostic::CreatedAlloc(id)); @@ -369,9 +369,9 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { let alloc: Allocation = alloc.with_tags_and_extra( |alloc| { if let Some(stacked_borrows) = stacked_borrows.as_mut() { - // Only statics may already contain pointers at this point - assert_eq!(kind, MiriMemoryKind::Static.into()); - stacked_borrows.static_base_ptr(alloc) + // Only globals may already contain pointers at this point + assert_eq!(kind, MiriMemoryKind::Global.into()); + stacked_borrows.global_base_ptr(alloc) } else { Tag::Untagged } @@ -382,9 +382,9 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { } #[inline(always)] - fn tag_static_base_pointer(memory_extra: &MemoryExtra, id: AllocId) -> Self::PointerTag { + fn tag_global_base_pointer(memory_extra: &MemoryExtra, id: AllocId) -> Self::PointerTag { if let Some(stacked_borrows) = memory_extra.stacked_borrows.as_ref() { - stacked_borrows.borrow_mut().static_base_ptr(id) + stacked_borrows.borrow_mut().global_base_ptr(id) } else { Tag::Untagged } @@ -486,7 +486,7 @@ impl MayLeak for MiriMemoryKind { use self::MiriMemoryKind::*; match self { Rust | C | WinHeap => false, - Machine | Static => true, + Machine | Global => true, } } } diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 37f2acf4c3bce..11b6cdca579af 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -182,7 +182,7 @@ impl GlobalState { self.active_calls.contains(&id) } - pub fn static_base_ptr(&mut self, id: AllocId) -> Tag { + pub fn global_base_ptr(&mut self, id: AllocId) -> Tag { self.base_ptr_ids.get(&id).copied().unwrap_or_else(|| { let tag = Tag::Tagged(self.new_ptr()); trace!("New allocation {:?} has base tag {:?}", id, tag); @@ -457,12 +457,12 @@ impl Stacks { // everything else off the stack, invalidating all previous pointers, // and in particular, *all* raw pointers. MemoryKind::Stack => (Tag::Tagged(extra.borrow_mut().new_ptr()), Permission::Unique), - // Static memory can be referenced by "global" pointers from `tcx`. - // Thus we call `static_base_ptr` such that the global pointers get the same tag + // Global memory can be referenced by global pointers from `tcx`. + // Thus we call `global_base_ptr` such that the global pointers get the same tag // as what we use here. // The base pointer is not unique, so the base permission is `SharedReadWrite`. - MemoryKind::Machine(MiriMemoryKind::Static) | MemoryKind::Machine(MiriMemoryKind::Machine) => - (extra.borrow_mut().static_base_ptr(id), Permission::SharedReadWrite), + MemoryKind::Machine(MiriMemoryKind::Global) | MemoryKind::Machine(MiriMemoryKind::Machine) => + (extra.borrow_mut().global_base_ptr(id), Permission::SharedReadWrite), // Everything else we handle entirely untagged for now. // FIXME: experiment with more precise tracking. _ => (Tag::Untagged, Permission::SharedReadWrite), From 47b91e619adffd19c60a5c20709f216c32e34c54 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 25 Mar 2020 09:12:23 +0100 Subject: [PATCH 1709/3747] test unreachable intrinsic --- src/shims/intrinsics.rs | 1 + tests/compile-fail/unreachable.rs | 4 ++++ 2 files changed, 5 insertions(+) create mode 100644 tests/compile-fail/unreachable.rs diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 9a6bd58ba42e1..91371e2c9df96 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -36,6 +36,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let (dest, ret) = match ret { None => match intrinsic_name { "miri_start_panic" => return this.handle_miri_start_panic(args, unwind), + "unreachable" => throw_ub!(Unreachable), _ => throw_unsup_format!("unimplemented (diverging) intrinsic: {}", intrinsic_name), }, Some(p) => p, diff --git a/tests/compile-fail/unreachable.rs b/tests/compile-fail/unreachable.rs new file mode 100644 index 0000000000000..245ef29cad353 --- /dev/null +++ b/tests/compile-fail/unreachable.rs @@ -0,0 +1,4 @@ +// error-pattern: entering unreachable code +fn main() { + unsafe { std::hint::unreachable_unchecked() } +} From 962e2105df2fd8d9d829bf8f7e4a7ab4b7fd1168 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 25 Mar 2020 09:15:52 +0100 Subject: [PATCH 1710/3747] remove an unnecessary as_str --- src/machine.rs | 3 +-- src/shims/fs.rs | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/machine.rs b/src/machine.rs index 84ac8b81a0618..73e7ce665b858 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -106,8 +106,7 @@ impl MemoryExtra { pub fn init_extern_statics<'tcx, 'mir>( this: &mut MiriEvalContext<'mir, 'tcx>, ) -> InterpResult<'tcx> { - let target_os = this.tcx.sess.target.target.target_os.as_str(); - match target_os { + match this.tcx.sess.target.target.target_os.as_str() { "linux" => { // "__cxa_thread_atexit_impl" // This should be all-zero, pointer-sized. diff --git a/src/shims/fs.rs b/src/shims/fs.rs index 9778775fca641..b779bf165d2b4 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -802,7 +802,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.check_no_isolation("mkdir")?; - let _mode = if this.tcx.sess.target.target.target_os.as_str() == "macos" { + let _mode = if this.tcx.sess.target.target.target_os == "macos" { u32::from(this.read_scalar(mode_op)?.not_undef()?.to_u16()?) } else { this.read_scalar(mode_op)?.to_u32()? From e19552ba414eee7cb5236bf2a65a8da8a802e8ee Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 25 Mar 2020 11:44:11 +0100 Subject: [PATCH 1711/3747] cross-running windows-gnu should now also work --- travis.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/travis.sh b/travis.sh index 8b2453584b09a..590b94b7f5db2 100755 --- a/travis.sh +++ b/travis.sh @@ -44,4 +44,6 @@ if [ "$TRAVIS_OS_NAME" == linux ]; then elif [ "$TRAVIS_OS_NAME" == osx ]; then # cross-test 64bit Windows from macOS MIRI_TEST_TARGET=x86_64-pc-windows-msvc run_tests + # cross-test 32bit GNU Windows from macOS + MIRI_TEST_TARGET=i686-pc-windows-gnu run_tests fi From 8ffbca797f8be62ac601cc1162e9605185597a00 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 25 Mar 2020 12:11:05 +0100 Subject: [PATCH 1712/3747] bump xargo version --- src/bin/cargo-miri.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 8f26aaf4e91af..9ef4996992a43 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -6,7 +6,7 @@ use std::ops::Not; use std::path::{Path, PathBuf}; use std::process::Command; -const XARGO_MIN_VERSION: (u32, u32, u32) = (0, 3, 19); +const XARGO_MIN_VERSION: (u32, u32, u32) = (0, 3, 20); const CARGO_MIRI_HELP: &str = r#"Interprets bin crates and tests in Miri From 81d505670bb7f274bd33f43ebc879eb8f610d127 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 26 Mar 2020 00:11:50 +0100 Subject: [PATCH 1713/3747] rustup; get rid of some try_from that are no longer needed --- rust-version | 2 +- src/eval.rs | 4 ++-- src/helpers.rs | 2 +- src/shims/env.rs | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/rust-version b/rust-version index 3a7d316af8e9e..538003d9fbaea 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -02046a5d402c789c006d0da7662f800fe3c45faf +a5fb9ae5b2ed3cb011ada9dc1e8633aa0927f279 diff --git a/src/eval.rs b/src/eval.rs index d2ca57c39a792..8274b52bd085e 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -114,7 +114,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( ecx.layout_of(tcx.mk_array(tcx.mk_imm_ptr(tcx.types.u8), u64::try_from(argvs.len()).unwrap()))?; let argvs_place = ecx.allocate(argvs_layout, MiriMemoryKind::Machine.into()); for (idx, arg) in argvs.into_iter().enumerate() { - let place = ecx.mplace_field(argvs_place, u64::try_from(idx).unwrap())?; + let place = ecx.mplace_field(argvs_place, idx)?; ecx.write_scalar(arg, place.into())?; } ecx.memory.mark_immutable(argvs_place.ptr.assert_ptr().alloc_id)?; @@ -154,7 +154,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( // Store the UTF-16 string. We just allocated so we know the bounds are fine. let char_size = Size::from_bytes(2); for (idx, &c) in cmd_utf16.iter().enumerate() { - let place = ecx.mplace_field(cmd_place, u64::try_from(idx).unwrap())?; + let place = ecx.mplace_field(cmd_place, idx)?; ecx.write_scalar(Scalar::from_uint(c, char_size), place.into())?; } } diff --git a/src/helpers.rs b/src/helpers.rs index 7ca2b238218a1..11f95f40b909a 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -598,7 +598,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Store the UTF-16 string. let char_size = Size::from_bytes(2); for (idx, c) in u16_vec.into_iter().chain(iter::once(0x0000)).enumerate() { - let place = this.mplace_field(mplace, u64::try_from(idx).unwrap())?; + let place = this.mplace_field(mplace, idx)?; this.write_scalar(Scalar::from_uint(c, char_size), place.into())?; } Ok((true, string_length)) diff --git a/src/shims/env.rs b/src/shims/env.rs index 192fc0d47abec..34c297248f0dd 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -61,7 +61,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(match this.machine.env_vars.map.get(name) { // The offset is used to strip the "{name}=" part of the string. Some(var_ptr) => { - Scalar::from(var_ptr.offset(Size::from_bytes(u64::try_from(name.len()).unwrap().checked_add(1).unwrap()), this)?) + Scalar::from(var_ptr.offset(Size::from_bytes(name.len()) + Size::from_bytes(1), this)?) } None => Scalar::ptr_null(&*this.tcx), }) @@ -187,7 +187,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.layout_of(tcx.mk_array(tcx.types.usize, u64::try_from(vars.len()).unwrap()))?; let vars_place = this.allocate(vars_layout, MiriMemoryKind::Machine.into()); for (idx, var) in vars.into_iter().enumerate() { - let place = this.mplace_field(vars_place, u64::try_from(idx).unwrap())?; + let place = this.mplace_field(vars_place, idx)?; this.write_scalar(var, place.into())?; } this.write_scalar( From a97ce8d94b681f8fb23b70260a219e528047e52a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 26 Mar 2020 19:25:51 +0100 Subject: [PATCH 1714/3747] test floating point casting better --- tests/run-pass/floats.rs | 47 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/tests/run-pass/floats.rs b/tests/run-pass/floats.rs index 7577c48c5ae38..39dc73ed18913 100644 --- a/tests/run-pass/floats.rs +++ b/tests/run-pass/floats.rs @@ -1,17 +1,61 @@ fn main() { + // basic arithmetic assert_eq!(6.0_f32*6.0_f32, 36.0_f32); assert_eq!(6.0_f64*6.0_f64, 36.0_f64); assert_eq!(-{5.0_f32}, -5.0_f32); + assert_eq!(-{5.0_f64}, -5.0_f64); + // infinities, NaN assert!((5.0_f32/0.0).is_infinite()); + assert!((5.0_f64/0.0).is_infinite()); assert!((-5.0_f32).sqrt().is_nan()); + assert!((-5.0_f64).sqrt().is_nan()); + // byte-level transmute let x: u64 = unsafe { std::mem::transmute(42.0_f64) }; let y: f64 = unsafe { std::mem::transmute(x) }; assert_eq!(y, 42.0_f64); + let x: u32 = unsafe { std::mem::transmute(42.0_f32) }; + let y: f32 = unsafe { std::mem::transmute(x) }; + assert_eq!(y, 42.0_f32); + // f32 casts assert_eq!(5.0f32 as u32, 5); + assert_eq!(-5.0f32 as u32, 0); assert_eq!(5.0f32 as i32, 5); assert_eq!(-5.0f32 as i32, -5); + assert_eq!(std::f32::MAX as i32, i32::MAX); + assert_eq!(std::f32::INFINITY as i32, i32::MAX); + assert_eq!(std::f32::MAX as u32, u32::MAX); + assert_eq!(std::f32::INFINITY as u32, u32::MAX); + assert_eq!(std::f32::MIN as i32, i32::MIN); + assert_eq!(std::f32::NEG_INFINITY as i32, i32::MIN); + assert_eq!(std::f32::MIN as u32, 0); + assert_eq!(std::f32::NEG_INFINITY as u32, 0); + assert_eq!(std::f32::NAN as i32, 0); + assert_eq!(std::f32::NAN as u32, 0); + assert_eq!(u128::MAX as f32, std::f32::INFINITY); + assert_eq!((u32::MAX-127) as f32 as u32, u32::MAX); // rounding loss + assert_eq!((u32::MAX-128) as f32 as u32, u32::MAX-255); // rounding loss + // f64 casts + assert_eq!(5.0f64 as u64, 5); + assert_eq!(-5.0f64 as u64, 0); + assert_eq!(5.0f64 as i64, 5); + assert_eq!(-5.0f64 as i64, -5); + assert_eq!(std::f64::MAX as i64, i64::MAX); + assert_eq!(std::f64::INFINITY as i64, i64::MAX); + assert_eq!(std::f64::MAX as u64, u64::MAX); + assert_eq!(std::f64::INFINITY as u64, u64::MAX); + assert_eq!(std::f64::MIN as i64, i64::MIN); + assert_eq!(std::f64::NEG_INFINITY as i64, i64::MIN); + assert_eq!(std::f64::MIN as u64, 0); + assert_eq!(std::f64::NEG_INFINITY as u64, 0); + assert_eq!(std::f64::NAN as i64, 0); + assert_eq!(std::f64::NAN as u64, 0); + assert_eq!(u128::MAX as f64 as u128, u128::MAX); + assert_eq!((u64::MAX-1023) as f64 as u64, u64::MAX); // rounding loss + assert_eq!((u64::MAX-1024) as f64 as u64, u64::MAX-2047); // rounding loss + + // f32 min/max assert_eq!((1.0 as f32).max(-1.0), 1.0); assert_eq!((1.0 as f32).min(-1.0), -1.0); assert_eq!(std::f32::NAN.min(9.0), 9.0); @@ -19,6 +63,7 @@ fn main() { assert_eq!((9.0 as f32).min(std::f32::NAN), 9.0); assert_eq!((-9.0 as f32).max(std::f32::NAN), -9.0); + // f64 min/max assert_eq!((1.0 as f64).max(-1.0), 1.0); assert_eq!((1.0 as f64).min(-1.0), -1.0); assert_eq!(std::f64::NAN.min(9.0), 9.0); @@ -26,12 +71,14 @@ fn main() { assert_eq!((9.0 as f64).min(std::f64::NAN), 9.0); assert_eq!((-9.0 as f64).max(std::f64::NAN), -9.0); + // f32 copysign assert_eq!(3.5_f32.copysign(0.42), 3.5_f32); assert_eq!(3.5_f32.copysign(-0.42), -3.5_f32); assert_eq!((-3.5_f32).copysign(0.42), 3.5_f32); assert_eq!((-3.5_f32).copysign(-0.42), -3.5_f32); assert!(std::f32::NAN.copysign(1.0).is_nan()); + // f64 copysign assert_eq!(3.5_f64.copysign(0.42), 3.5_f64); assert_eq!(3.5_f64.copysign(-0.42), -3.5_f64); assert_eq!((-3.5_f64).copysign(0.42), 3.5_f64); From fc8f88e04e04f83879e7d2548de5b5addac10600 Mon Sep 17 00:00:00 2001 From: JOE1994 Date: Fri, 27 Mar 2020 00:08:27 -0400 Subject: [PATCH 1715/3747] change helper fn 'write_os_str_to_wide_str' --- rust-version | 2 +- src/helpers.rs | 26 +++++--------------------- 2 files changed, 6 insertions(+), 22 deletions(-) diff --git a/rust-version b/rust-version index 538003d9fbaea..a11e231acb30e 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -a5fb9ae5b2ed3cb011ada9dc1e8633aa0927f279 +7b73d14b0b35e7b4f79f2d71dc1bbbab31698288 diff --git a/src/helpers.rs b/src/helpers.rs index 11f95f40b909a..cdad723502ebb 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -463,18 +463,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } - /// Dispatches to appropriate implementations for reading an OsString from Memory, - /// depending on the interpretation target. - /// FIXME: Use `Cow` to avoid copies - fn read_os_str_from_target_str(&self, scalar: Scalar) -> InterpResult<'tcx, OsString> { - let target_os = self.eval_context_ref().tcx.sess.target.target.target_os.as_str(); - match target_os { - "linux" | "macos" => self.read_os_str_from_c_str(scalar).map(|x| x.to_os_string()), - "windows" => self.read_os_str_from_wide_str(scalar), - unsupported => throw_unsup_format!("OsString support for target OS `{}` not yet available", unsupported), - } - } - /// Helper function to read an OsString from a null-terminated sequence of bytes, which is what /// the Unix APIs usually handle. fn read_os_str_from_c_str<'a>(&'a self, scalar: Scalar) -> InterpResult<'tcx, &'a OsStr> @@ -567,7 +555,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn write_os_str_to_wide_str( &mut self, os_str: &OsStr, - mplace: MPlaceTy<'tcx, Tag>, + scalar: Scalar, size: u64, ) -> InterpResult<'tcx, (bool, u64)> { #[cfg(windows)] @@ -593,14 +581,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx return Ok((false, string_length)); } - let this = self.eval_context_mut(); - // Store the UTF-16 string. - let char_size = Size::from_bytes(2); - for (idx, c) in u16_vec.into_iter().chain(iter::once(0x0000)).enumerate() { - let place = this.mplace_field(mplace, idx)?; - this.write_scalar(Scalar::from_uint(c, char_size), place.into())?; - } + self.eval_context_mut() + .memory + .write_u16s(scalar, u16_vec.into_iter().chain(iter::once(0x0000)))?; Ok((true, string_length)) } @@ -645,7 +629,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let arg_type = this.tcx.mk_array(this.tcx.types.u16, size); let arg_place = this.allocate(this.layout_of(arg_type).unwrap(), memkind); - assert!(self.write_os_str_to_wide_str(os_str, arg_place, size).unwrap().0); + assert!(self.write_os_str_to_wide_str(os_str, arg_place.ptr, size).unwrap().0); arg_place.ptr.assert_ptr() } From 160ebaa364bb1c7c93885765d398dcecda857664 Mon Sep 17 00:00:00 2001 From: JOE1994 Date: Fri, 27 Mar 2020 00:10:45 -0400 Subject: [PATCH 1716/3747] add OS-specific handling to src/shims/env.rs --- src/shims/env.rs | 55 ++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 46 insertions(+), 9 deletions(-) diff --git a/src/shims/env.rs b/src/shims/env.rs index 34c297248f0dd..990ccf7d69bd0 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -23,8 +23,12 @@ pub struct EnvVars<'tcx> { impl<'tcx> EnvVars<'tcx> { pub(crate) fn init<'mir>( ecx: &mut InterpCx<'mir, 'tcx, Evaluator<'tcx>>, - excluded_env_vars: Vec, + mut excluded_env_vars: Vec, ) -> InterpResult<'tcx> { + if ecx.tcx.sess.target.target.target_os == "windows" { + // Exclude `TERM` var to avoid terminfo trying to open the termcap file. + excluded_env_vars.push("TERM".to_owned()); + } if ecx.machine.communicate { for (name, value) in env::vars() { if !excluded_env_vars.contains(&name) { @@ -49,19 +53,41 @@ fn alloc_env_var_as_target_str<'mir, 'tcx>( Ok(ecx.alloc_os_str_as_target_str(name_osstring.as_os_str(), MiriMemoryKind::Machine.into())?) } +fn alloc_env_var_as_c_str<'mir, 'tcx>( + name: &OsStr, + value: &OsStr, + ecx: &mut InterpCx<'mir, 'tcx, Evaluator<'tcx>>, +) -> InterpResult<'tcx, Pointer> { + let mut name_osstring = name.to_os_string(); + name_osstring.push("="); + name_osstring.push(value); + Ok(ecx.alloc_os_str_as_c_str(name_osstring.as_os_str(), MiriMemoryKind::Machine.into())) +} + +fn alloc_env_var_as_wide_str<'mir, 'tcx>( + name: &OsStr, + value: &OsStr, + ecx: &mut InterpCx<'mir, 'tcx, Evaluator<'tcx>>, +) -> InterpResult<'tcx, Pointer> { + let mut name_osstring = name.to_os_string(); + name_osstring.push("="); + name_osstring.push(value); + Ok(ecx.alloc_os_str_as_wide_str(name_osstring.as_os_str(), MiriMemoryKind::Machine.into())) +} + impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { fn getenv(&mut self, name_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); - let target_os = this.tcx.sess.target.target.target_os.as_str(); - assert!(target_os == "linux" || target_os == "macos", "`{}` is only available for the UNIX target family"); + let target_os = &this.tcx.sess.target.target.target_os; + assert!(target_os == "linux" || target_os == "macos", "`getenv` is only available for the UNIX target family"); let name_ptr = this.read_scalar(name_op)?.not_undef()?; let name = this.read_os_str_from_c_str(name_ptr)?; Ok(match this.machine.env_vars.map.get(name) { - // The offset is used to strip the "{name}=" part of the string. Some(var_ptr) => { - Scalar::from(var_ptr.offset(Size::from_bytes(name.len()) + Size::from_bytes(1), this)?) + // The offset is used to strip the "{name}=" part of the string. + Scalar::from(var_ptr.offset(Size::from_bytes(u64::try_from(name.len()).unwrap().checked_add(1).unwrap()), this)?) } None => Scalar::ptr_null(&*this.tcx), }) @@ -73,32 +99,40 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx value_op: OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, i32> { let mut this = self.eval_context_mut(); + let target_os = &this.tcx.sess.target.target.target_os; + assert!(target_os == "linux" || target_os == "macos", "`setenv` is only available for the UNIX target family"); let name_ptr = this.read_scalar(name_op)?.not_undef()?; let value_ptr = this.read_scalar(value_op)?.not_undef()?; - let value = this.read_os_str_from_target_str(value_ptr)?; + let mut new = None; if !this.is_null(name_ptr)? { - let name = this.read_os_str_from_target_str(name_ptr)?; + let name = this.read_os_str_from_c_str(name_ptr)?; if !name.is_empty() && !name.to_string_lossy().contains('=') { + let value = this.read_os_str_from_c_str(value_ptr)?; new = Some((name.to_owned(), value.to_owned())); } } if let Some((name, value)) = new { - let var_ptr = alloc_env_var_as_target_str(&name, &value, &mut this)?; + let var_ptr = alloc_env_var_as_c_str(&name, &value, &mut this)?; if let Some(var) = this.machine.env_vars.map.insert(name, var_ptr) { this.memory .deallocate(var, None, MiriMemoryKind::Machine.into())?; } this.update_environ()?; - Ok(0) + Ok(0) // return zero on success } else { + // name argument is a null pointer, points to an empty string, or points to a string containing an '=' character. + let einval = this.eval_libc("EINVAL")?; + this.set_last_error(einval)?; Ok(-1) } } fn unsetenv(&mut self, name_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); + let target_os = &this.tcx.sess.target.target.target_os; + assert!(target_os == "linux" || target_os == "macos", "`unsetenv` is only available for the UNIX target family"); let name_ptr = this.read_scalar(name_op)?.not_undef()?; let mut success = None; @@ -116,6 +150,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.update_environ()?; Ok(0) } else { + // name argument is a null pointer, points to an empty string, or points to a string containing an '=' character. + let einval = this.eval_libc("EINVAL")?; + this.set_last_error(einval)?; Ok(-1) } } From 813d76d948cbaa8ae23fc645e1f4f02438d2ed9e Mon Sep 17 00:00:00 2001 From: JOE1994 Date: Fri, 27 Mar 2020 07:07:21 -0400 Subject: [PATCH 1717/3747] follow-up to reviews --- src/helpers.rs | 15 --------------- src/shims/env.rs | 25 +++++++------------------ 2 files changed, 7 insertions(+), 33 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index cdad723502ebb..3e89fdf6f3cce 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -588,21 +588,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok((true, string_length)) } - /// Dispatches to appropriate implementations for allocating & writing OsString in Memory, - /// depending on the interpretation target. - fn alloc_os_str_as_target_str( - &mut self, - os_str: &OsStr, - memkind: MemoryKind, - ) -> InterpResult<'tcx, Pointer> { - let target_os = self.eval_context_ref().tcx.sess.target.target.target_os.as_str(); - match target_os { - "linux" | "macos" => Ok(self.alloc_os_str_as_c_str(os_str, memkind)), - "windows" => Ok(self.alloc_os_str_as_wide_str(os_str, memkind)), - unsupported => throw_unsup_format!("OsString support for target OS `{}` not yet available", unsupported), - } - } - /// Allocate enough memory to store the given `OsStr` as a null-terminated sequence of bytes. fn alloc_os_str_as_c_str( &mut self, diff --git a/src/shims/env.rs b/src/shims/env.rs index 990ccf7d69bd0..7c126140491f3 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -23,17 +23,17 @@ pub struct EnvVars<'tcx> { impl<'tcx> EnvVars<'tcx> { pub(crate) fn init<'mir>( ecx: &mut InterpCx<'mir, 'tcx, Evaluator<'tcx>>, - mut excluded_env_vars: Vec, + excluded_env_vars: Vec, ) -> InterpResult<'tcx> { - if ecx.tcx.sess.target.target.target_os == "windows" { - // Exclude `TERM` var to avoid terminfo trying to open the termcap file. - excluded_env_vars.push("TERM".to_owned()); - } if ecx.machine.communicate { + let target_os = ecx.tcx.sess.target.target.target_os.as_str(); for (name, value) in env::vars() { if !excluded_env_vars.contains(&name) { - let var_ptr = - alloc_env_var_as_target_str(name.as_ref(), value.as_ref(), ecx)?; + let var_ptr = match target_os { + "linux" | "macos" => alloc_env_var_as_c_str(name.as_ref(), value.as_ref(), ecx)?, + "windows" => alloc_env_var_as_wide_str(name.as_ref(), value.as_ref(), ecx)?, + unsupported => throw_unsup_format!("OsString support for target OS `{}` not yet available", unsupported), + }; ecx.machine.env_vars.map.insert(OsString::from(name), var_ptr); } } @@ -42,17 +42,6 @@ impl<'tcx> EnvVars<'tcx> { } } -fn alloc_env_var_as_target_str<'mir, 'tcx>( - name: &OsStr, - value: &OsStr, - ecx: &mut InterpCx<'mir, 'tcx, Evaluator<'tcx>>, -) -> InterpResult<'tcx, Pointer> { - let mut name_osstring = name.to_os_string(); - name_osstring.push("="); - name_osstring.push(value); - Ok(ecx.alloc_os_str_as_target_str(name_osstring.as_os_str(), MiriMemoryKind::Machine.into())?) -} - fn alloc_env_var_as_c_str<'mir, 'tcx>( name: &OsStr, value: &OsStr, From 07f7083409c3cdb112249bc4f5930c3713d1bbb4 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 27 Mar 2020 12:35:08 +0100 Subject: [PATCH 1718/3747] env: more precise error --- src/shims/env.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shims/env.rs b/src/shims/env.rs index 7c126140491f3..79c386e894ecb 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -32,7 +32,7 @@ impl<'tcx> EnvVars<'tcx> { let var_ptr = match target_os { "linux" | "macos" => alloc_env_var_as_c_str(name.as_ref(), value.as_ref(), ecx)?, "windows" => alloc_env_var_as_wide_str(name.as_ref(), value.as_ref(), ecx)?, - unsupported => throw_unsup_format!("OsString support for target OS `{}` not yet available", unsupported), + unsupported => throw_unsup_format!("environment support for target OS `{}` not yet available", unsupported), }; ecx.machine.env_vars.map.insert(OsString::from(name), var_ptr); } From 2fa07009f2a27c8d77ed48539cf66db6e2b5a676 Mon Sep 17 00:00:00 2001 From: JOE1994 Date: Fri, 13 Mar 2020 12:45:02 -0400 Subject: [PATCH 1719/3747] Windows shims for env var emulation Shims for GetEnvironmentVariableW / SetEnvironmentVariableW / GetEnvironmentStringsW. Passes test 'tests/run-pass/env.rs' --- src/shims/env.rs | 120 ++++++++++++++++++++++++++++- src/shims/foreign_items/windows.rs | 30 ++++---- tests/run-pass/env.rs | 2 - 3 files changed, 136 insertions(+), 16 deletions(-) diff --git a/src/shims/env.rs b/src/shims/env.rs index 79c386e894ecb..97d74ad0e0693 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -1,6 +1,7 @@ use std::ffi::{OsString, OsStr}; use std::env; use std::convert::TryFrom; +use std::collections::hash_map::Values; use crate::stacked_borrows::Tag; use crate::rustc_target::abi::LayoutOf; @@ -40,6 +41,10 @@ impl<'tcx> EnvVars<'tcx> { } ecx.update_environ() } + + pub(super) fn values(&self) -> InterpResult<'tcx, Values<'_, OsString, Pointer>> { + Ok(self.map.values()) + } } fn alloc_env_var_as_c_str<'mir, 'tcx>( @@ -82,6 +87,79 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx }) } + fn getenvironmentvariablew( + &mut self, + name_op: OpTy<'tcx, Tag>, // LPCWSTR lpName + buf_op: OpTy<'tcx, Tag>, // LPWSTR lpBuffer + size_op: OpTy<'tcx, Tag>, // DWORD nSize + ) -> InterpResult<'tcx, u64> { + let this = self.eval_context_mut(); + this.assert_target_os("windows", "GetEnvironmentVariableW"); + + let name_ptr = this.read_scalar(name_op)?.not_undef()?; + let name = this.read_os_str_from_wide_str(name_ptr)?; + Ok(match this.machine.env_vars.map.get(&name) { + Some(var_ptr) => { + // The offset is used to strip the "{name}=" part of the string. + let name_offset_bytes = + u64::try_from(name.len()).unwrap().checked_add(1).unwrap().checked_mul(2).unwrap(); + let var_ptr = Scalar::from(var_ptr.offset(Size::from_bytes(name_offset_bytes), this)?); + + let var_size = u64::try_from(this.read_os_str_from_wide_str(var_ptr)?.len()).unwrap(); + let buf_size = u64::try_from(this.read_scalar(size_op)?.to_i32()?).unwrap(); + let return_val = if var_size.checked_add(1).unwrap() > buf_size { + // If lpBuffer is not large enough to hold the data, the return value is the buffer size, in characters, + // required to hold the string and its terminating null character and the contents of lpBuffer are undefined. + var_size + 1 + } else { + let buf_ptr = this.read_scalar(buf_op)?.not_undef()?; + for i in 0..var_size { + this.memory.copy( + this.force_ptr(var_ptr.ptr_offset(Size::from_bytes(i) * 2, this)?)?, + this.force_ptr(buf_ptr.ptr_offset(Size::from_bytes(i) * 2, this)?)?, + Size::from_bytes(2), + true, + )?; + } + // If the function succeeds, the return value is the number of characters stored in the buffer pointed to by lpBuffer, + // not including the terminating null character. + var_size + }; + return_val + } + None => { + this.set_last_error(Scalar::from_u32(203))?; // ERROR_ENVVAR_NOT_FOUND + 0 // return zero upon failure + } + }) + } + + fn getenvironmentstringsw(&mut self) -> InterpResult<'tcx, Scalar> { + let this = self.eval_context_mut(); + this.assert_target_os("windows", "GetEnvironmentStringsW"); + + // Info on layout of environment blocks in Windows: + // https://docs.microsoft.com/en-us/windows/win32/procthread/environment-variables + let mut env_vars = std::ffi::OsString::new(); + for &item in this.machine.env_vars.values()? { + let env_var = this.read_os_str_from_target_str(Scalar::from(item))?; + env_vars.push(env_var); + env_vars.push("\0"); + } + + // Allocate environment block + let tcx = this.tcx; + let env_block_size = env_vars.len().checked_add(1).unwrap(); + let env_block_type = tcx.mk_array(tcx.types.u16, u64::try_from(env_block_size).unwrap()); + let env_block_place = this.allocate(this.layout_of(env_block_type)?, MiriMemoryKind::WinHeap.into()); + + // Store environment variables to environment block + // Final null terminator(block terminator) is pushed by `write_os_str_to_wide_str` + this.write_os_str_to_wide_str(&env_vars, env_block_place, u64::try_from(env_block_size).unwrap())?; + + Ok(env_block_place.ptr) + } + fn setenv( &mut self, name_op: OpTy<'tcx, Tag>, @@ -118,6 +196,46 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } + fn setenvironmentvariablew( + &mut self, + name_op: OpTy<'tcx, Tag>, // LPCWSTR lpName, + value_op: OpTy<'tcx, Tag>, // LPCWSTR lpValue, + ) -> InterpResult<'tcx, i32> { + let mut this = self.eval_context_mut(); + this.assert_target_os("windows", "SetEnvironmentVariableW"); + + let name_ptr = this.read_scalar(name_op)?.not_undef()?; + let value_ptr = this.read_scalar(value_op)?.not_undef()?; + + let mut new = None; + if !this.is_null(name_ptr)? { + let name = this.read_os_str_from_target_str(name_ptr)?; + if this.is_null(value_ptr)? { + // Delete environment variable `{name}` + if let Some(var) = this.machine.env_vars.map.remove(&name) { + this.memory.deallocate(var, None, MiriMemoryKind::Machine.into())?; + this.update_environ()?; + } + return Ok(1); // return non-zero on success + } + if !name.is_empty() && !name.to_string_lossy().contains('=') { + let value = this.read_os_str_from_target_str(value_ptr)?; + new = Some((name.to_owned(), value.to_owned())); + } + } + if let Some((name, value)) = new { + let var_ptr = alloc_env_var_as_target_str(&name, &value, &mut this)?; + if let Some(var) = this.machine.env_vars.map.insert(name, var_ptr) { + this.memory + .deallocate(var, None, MiriMemoryKind::Machine.into())?; + } + this.update_environ()?; + Ok(1) // return non-zero on success + } else { + Ok(0) + } + } + fn unsetenv(&mut self, name_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); let target_os = &this.tcx.sess.target.target.target_os; @@ -126,7 +244,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let name_ptr = this.read_scalar(name_op)?.not_undef()?; let mut success = None; if !this.is_null(name_ptr)? { - let name = this.read_os_str_from_c_str(name_ptr)?.to_owned(); + let name = this.read_os_str_from_target_str(name_ptr)?.to_owned(); if !name.is_empty() && !name.to_string_lossy().contains('=') { success = Some(this.machine.env_vars.map.remove(&name)); } diff --git a/src/shims/foreign_items/windows.rs b/src/shims/foreign_items/windows.rs index a35734573f296..057f1c06a8505 100644 --- a/src/shims/foreign_items/windows.rs +++ b/src/shims/foreign_items/windows.rs @@ -23,22 +23,26 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Environment related shims "GetEnvironmentVariableW" => { - // args[0] : LPCWSTR lpName (32-bit ptr to a const string of 16-bit Unicode chars) - // args[1] : LPWSTR lpBuffer (32-bit pointer to a string of 16-bit Unicode chars) - // lpBuffer : ptr to buffer that receives contents of the env_var as a null-terminated string. - // Return `# of chars` stored in the buffer pointed to by lpBuffer, excluding null-terminator. - // Return 0 upon failure. - - // This is not the env var you are looking for. - this.set_last_error(Scalar::from_u32(203))?; // ERROR_ENVVAR_NOT_FOUND - this.write_null(dest)?; + let result = this.getenvironmentvariablew(args[0], args[1], args[2])?; + this.write_scalar(Scalar::from_uint(result, dest.layout.size), dest)?; } "SetEnvironmentVariableW" => { - // args[0] : LPCWSTR lpName (32-bit ptr to a const string of 16-bit Unicode chars) - // args[1] : LPCWSTR lpValue (32-bit ptr to a const string of 16-bit Unicode chars) - // Return nonzero if success, else return 0. - throw_unsup_format!("can't set environment variable on Windows"); + let result = this.setenvironmentvariablew(args[0], args[1])?; + this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + } + + "GetEnvironmentStringsW" => { + let result = this.getenvironmentstringsw()?; + // If the function succeeds, the return value is a pointer to the environment block of the current process. + this.write_scalar(result, dest)?; + } + + "FreeEnvironmentStringsW" => { + let old_vars_ptr = this.read_scalar(args[0])?.not_undef()?; + let result = this.memory.deallocate(this.force_ptr(old_vars_ptr)?, None, MiriMemoryKind::WinHeap.into()).is_ok(); + // If the function succeeds, the return value is nonzero. + this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; } // File related shims diff --git a/tests/run-pass/env.rs b/tests/run-pass/env.rs index c7506b23c1da0..23a3724ff7fd3 100644 --- a/tests/run-pass/env.rs +++ b/tests/run-pass/env.rs @@ -1,5 +1,3 @@ -//ignore-windows: TODO env var emulation stubbed out on Windows - use std::env; fn main() { From cf5822af460f342721662a4dc959713a1cd7778c Mon Sep 17 00:00:00 2001 From: JOE1994 Date: Tue, 24 Mar 2020 16:00:11 -0400 Subject: [PATCH 1720/3747] exclude 'TERM' env_var to avoid terminfo trying to open the termcap file --- README.md | 2 +- src/shims/env.rs | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 59394830d79bc..03b995aa56d3f 100644 --- a/README.md +++ b/README.md @@ -166,7 +166,7 @@ Several `-Z` flags are relevant for Miri: * `-Zmiri-disable-stacked-borrows` disables checking the experimental [Stacked Borrows] aliasing rules. This can make Miri run faster, but it also means no aliasing violations will be detected. -* `-Zmiri-disable-isolation` disables host host isolation. As a consequence, +* `-Zmiri-disable-isolation` disables host isolation. As a consequence, the program has access to host resources such as environment variables, file systems, and randomness. * `-Zmiri-ignore-leaks` disables the memory leak checker. diff --git a/src/shims/env.rs b/src/shims/env.rs index 97d74ad0e0693..32ed65b39830a 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -24,8 +24,12 @@ pub struct EnvVars<'tcx> { impl<'tcx> EnvVars<'tcx> { pub(crate) fn init<'mir>( ecx: &mut InterpCx<'mir, 'tcx, Evaluator<'tcx>>, - excluded_env_vars: Vec, + mut excluded_env_vars: Vec, ) -> InterpResult<'tcx> { + if ecx.tcx.sess.target.target.target_os.to_lowercase() == "windows" { + // Exclude `TERM` var to avoid terminfo trying to open the termcap file. + excluded_env_vars.push("TERM".to_owned()); + } if ecx.machine.communicate { let target_os = ecx.tcx.sess.target.target.target_os.as_str(); for (name, value) in env::vars() { From 2051805e957d307f7f084172b61cf0a6d69edfc9 Mon Sep 17 00:00:00 2001 From: JOE1994 Date: Wed, 25 Mar 2020 00:52:53 -0400 Subject: [PATCH 1721/3747] follow-up to reviews --- src/shims/env.rs | 110 +++++++++++++++++------------ src/shims/foreign_items/windows.rs | 9 ++- 2 files changed, 69 insertions(+), 50 deletions(-) diff --git a/src/shims/env.rs b/src/shims/env.rs index 32ed65b39830a..2e647589f4111 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -1,3 +1,5 @@ +#![allow(non_snake_case)] + use std::ffi::{OsString, OsStr}; use std::env; use std::convert::TryFrom; @@ -26,7 +28,7 @@ impl<'tcx> EnvVars<'tcx> { ecx: &mut InterpCx<'mir, 'tcx, Evaluator<'tcx>>, mut excluded_env_vars: Vec, ) -> InterpResult<'tcx> { - if ecx.tcx.sess.target.target.target_os.to_lowercase() == "windows" { + if ecx.tcx.sess.target.target.target_os == "windows" { // Exclude `TERM` var to avoid terminfo trying to open the termcap file. excluded_env_vars.push("TERM".to_owned()); } @@ -46,7 +48,7 @@ impl<'tcx> EnvVars<'tcx> { ecx.update_environ() } - pub(super) fn values(&self) -> InterpResult<'tcx, Values<'_, OsString, Pointer>> { + fn values(&self) -> InterpResult<'tcx, Values<'_, OsString, Pointer>> { Ok(self.map.values()) } } @@ -73,6 +75,28 @@ fn alloc_env_var_as_wide_str<'mir, 'tcx>( Ok(ecx.alloc_os_str_as_wide_str(name_osstring.as_os_str(), MiriMemoryKind::Machine.into())) } +fn alloc_env_var_as_c_str<'mir, 'tcx>( + name: &OsStr, + value: &OsStr, + ecx: &mut InterpCx<'mir, 'tcx, Evaluator<'tcx>>, +) -> InterpResult<'tcx, Pointer> { + let mut name_osstring = name.to_os_string(); + name_osstring.push("="); + name_osstring.push(value); + Ok(ecx.alloc_os_str_as_c_str(name_osstring.as_os_str(), MiriMemoryKind::Machine.into())) +} + +fn alloc_env_var_as_wide_str<'mir, 'tcx>( + name: &OsStr, + value: &OsStr, + ecx: &mut InterpCx<'mir, 'tcx, Evaluator<'tcx>>, +) -> InterpResult<'tcx, Pointer> { + let mut name_osstring = name.to_os_string(); + name_osstring.push("="); + name_osstring.push(value); + Ok(ecx.alloc_os_str_as_wide_str(name_osstring.as_os_str(), MiriMemoryKind::Machine.into())) +} + impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { fn getenv(&mut self, name_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, Scalar> { @@ -91,7 +115,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx }) } - fn getenvironmentvariablew( + fn GetEnvironmentVariableW( &mut self, name_op: OpTy<'tcx, Tag>, // LPCWSTR lpName buf_op: OpTy<'tcx, Tag>, // LPWSTR lpBuffer @@ -110,21 +134,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let var_ptr = Scalar::from(var_ptr.offset(Size::from_bytes(name_offset_bytes), this)?); let var_size = u64::try_from(this.read_os_str_from_wide_str(var_ptr)?.len()).unwrap(); - let buf_size = u64::try_from(this.read_scalar(size_op)?.to_i32()?).unwrap(); + // `buf_size` represent size in characters. + let buf_size = u64::try_from(this.read_scalar(size_op)?.to_u32()?).unwrap(); let return_val = if var_size.checked_add(1).unwrap() > buf_size { // If lpBuffer is not large enough to hold the data, the return value is the buffer size, in characters, // required to hold the string and its terminating null character and the contents of lpBuffer are undefined. var_size + 1 } else { let buf_ptr = this.read_scalar(buf_op)?.not_undef()?; - for i in 0..var_size { - this.memory.copy( - this.force_ptr(var_ptr.ptr_offset(Size::from_bytes(i) * 2, this)?)?, - this.force_ptr(buf_ptr.ptr_offset(Size::from_bytes(i) * 2, this)?)?, - Size::from_bytes(2), - true, - )?; - } + let bytes_to_be_copied = var_size.checked_add(1).unwrap().checked_mul(2).unwrap(); + this.memory.copy(this.force_ptr(var_ptr)?, this.force_ptr(buf_ptr)?, Size::from_bytes(bytes_to_be_copied), true)?; // If the function succeeds, the return value is the number of characters stored in the buffer pointed to by lpBuffer, // not including the terminating null character. var_size @@ -138,7 +157,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx }) } - fn getenvironmentstringsw(&mut self) -> InterpResult<'tcx, Scalar> { + fn GetEnvironmentStringsW(&mut self) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); this.assert_target_os("windows", "GetEnvironmentStringsW"); @@ -146,22 +165,23 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // https://docs.microsoft.com/en-us/windows/win32/procthread/environment-variables let mut env_vars = std::ffi::OsString::new(); for &item in this.machine.env_vars.values()? { - let env_var = this.read_os_str_from_target_str(Scalar::from(item))?; + let env_var = this.read_os_str_from_wide_str(Scalar::from(item))?; env_vars.push(env_var); env_vars.push("\0"); } + // Allocate environment block & Store environment variables to environment block. + // Final null terminator(block terminator) is added by `alloc_os_str_to_wide_str`. + let envblock_ptr = this.alloc_os_str_as_wide_str(&env_vars, MiriMemoryKind::WinHeap.into()); - // Allocate environment block - let tcx = this.tcx; - let env_block_size = env_vars.len().checked_add(1).unwrap(); - let env_block_type = tcx.mk_array(tcx.types.u16, u64::try_from(env_block_size).unwrap()); - let env_block_place = this.allocate(this.layout_of(env_block_type)?, MiriMemoryKind::WinHeap.into()); - - // Store environment variables to environment block - // Final null terminator(block terminator) is pushed by `write_os_str_to_wide_str` - this.write_os_str_to_wide_str(&env_vars, env_block_place, u64::try_from(env_block_size).unwrap())?; + Ok(envblock_ptr.into()) + } + + fn FreeEnvironmentStringsW(&mut self, env_block_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, bool> { + let this = self.eval_context_mut(); + this.assert_target_os("windows", "FreeEnvironmentStringsW"); - Ok(env_block_place.ptr) + let env_block_ptr = this.read_scalar(env_block_op)?.not_undef()?; + Ok(this.memory.deallocate(this.force_ptr(env_block_ptr)?, None, MiriMemoryKind::WinHeap.into()).is_ok()) } fn setenv( @@ -200,7 +220,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } - fn setenvironmentvariablew( + fn SetEnvironmentVariableW( &mut self, name_op: OpTy<'tcx, Tag>, // LPCWSTR lpName, value_op: OpTy<'tcx, Tag>, // LPCWSTR lpValue, @@ -211,32 +231,32 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let name_ptr = this.read_scalar(name_op)?.not_undef()?; let value_ptr = this.read_scalar(value_op)?.not_undef()?; - let mut new = None; - if !this.is_null(name_ptr)? { - let name = this.read_os_str_from_target_str(name_ptr)?; - if this.is_null(value_ptr)? { - // Delete environment variable `{name}` - if let Some(var) = this.machine.env_vars.map.remove(&name) { - this.memory.deallocate(var, None, MiriMemoryKind::Machine.into())?; - this.update_environ()?; - } - return Ok(1); // return non-zero on success - } - if !name.is_empty() && !name.to_string_lossy().contains('=') { - let value = this.read_os_str_from_target_str(value_ptr)?; - new = Some((name.to_owned(), value.to_owned())); - } + if this.is_null(name_ptr)? { + // ERROR CODE is not clearly explained in docs.. For now, throw UB instead. + throw_ub_format!("Pointer to environment variable name is NULL"); } - if let Some((name, value)) = new { - let var_ptr = alloc_env_var_as_target_str(&name, &value, &mut this)?; + + let name = this.read_os_str_from_wide_str(name_ptr)?; + if name.is_empty() { + throw_unsup_format!("Environment variable name is an empty string"); + } else if name.to_string_lossy().contains('=') { + throw_unsup_format!("Environment variable name contains '='"); + } else if this.is_null(value_ptr)? { + // Delete environment variable `{name}` + if let Some(var) = this.machine.env_vars.map.remove(&name) { + this.memory.deallocate(var, None, MiriMemoryKind::Machine.into())?; + this.update_environ()?; + } + Ok(1) // return non-zero on success + } else { + let value = this.read_os_str_from_wide_str(value_ptr)?; + let var_ptr = alloc_env_var_as_wide_str(&name, &value, &mut this)?; if let Some(var) = this.machine.env_vars.map.insert(name, var_ptr) { this.memory .deallocate(var, None, MiriMemoryKind::Machine.into())?; } this.update_environ()?; Ok(1) // return non-zero on success - } else { - Ok(0) } } @@ -248,7 +268,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let name_ptr = this.read_scalar(name_op)?.not_undef()?; let mut success = None; if !this.is_null(name_ptr)? { - let name = this.read_os_str_from_target_str(name_ptr)?.to_owned(); + let name = this.read_os_str_from_c_str(name_ptr)?.to_owned(); if !name.is_empty() && !name.to_string_lossy().contains('=') { success = Some(this.machine.env_vars.map.remove(&name)); } diff --git a/src/shims/foreign_items/windows.rs b/src/shims/foreign_items/windows.rs index 057f1c06a8505..cc64057135c11 100644 --- a/src/shims/foreign_items/windows.rs +++ b/src/shims/foreign_items/windows.rs @@ -23,24 +23,23 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Environment related shims "GetEnvironmentVariableW" => { - let result = this.getenvironmentvariablew(args[0], args[1], args[2])?; + let result = this.GetEnvironmentVariableW(args[0], args[1], args[2])?; this.write_scalar(Scalar::from_uint(result, dest.layout.size), dest)?; } "SetEnvironmentVariableW" => { - let result = this.setenvironmentvariablew(args[0], args[1])?; + let result = this.SetEnvironmentVariableW(args[0], args[1])?; this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; } "GetEnvironmentStringsW" => { - let result = this.getenvironmentstringsw()?; + let result = this.GetEnvironmentStringsW()?; // If the function succeeds, the return value is a pointer to the environment block of the current process. this.write_scalar(result, dest)?; } "FreeEnvironmentStringsW" => { - let old_vars_ptr = this.read_scalar(args[0])?.not_undef()?; - let result = this.memory.deallocate(this.force_ptr(old_vars_ptr)?, None, MiriMemoryKind::WinHeap.into()).is_ok(); + let result = this.FreeEnvironmentStringsW(args[0])?; // If the function succeeds, the return value is nonzero. this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; } From 4e38fbe6be6d5c8d67de5ca65ab763f9f314a398 Mon Sep 17 00:00:00 2001 From: JOE1994 Date: Wed, 25 Mar 2020 10:38:27 -0400 Subject: [PATCH 1722/3747] follow-up2 to review (few issues not resolved yet) --- src/shims/env.rs | 45 +++++++++++++++++------------- src/shims/foreign_items/windows.rs | 4 +-- 2 files changed, 26 insertions(+), 23 deletions(-) diff --git a/src/shims/env.rs b/src/shims/env.rs index 2e647589f4111..cc7c305596dc6 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -1,9 +1,6 @@ -#![allow(non_snake_case)] - use std::ffi::{OsString, OsStr}; use std::env; use std::convert::TryFrom; -use std::collections::hash_map::Values; use crate::stacked_borrows::Tag; use crate::rustc_target::abi::LayoutOf; @@ -47,10 +44,6 @@ impl<'tcx> EnvVars<'tcx> { } ecx.update_environ() } - - fn values(&self) -> InterpResult<'tcx, Values<'_, OsString, Pointer>> { - Ok(self.map.values()) - } } fn alloc_env_var_as_c_str<'mir, 'tcx>( @@ -115,11 +108,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx }) } + #[allow(non_snake_case)] fn GetEnvironmentVariableW( &mut self, - name_op: OpTy<'tcx, Tag>, // LPCWSTR lpName - buf_op: OpTy<'tcx, Tag>, // LPWSTR lpBuffer - size_op: OpTy<'tcx, Tag>, // DWORD nSize + name_op: OpTy<'tcx, Tag>, // LPCWSTR + buf_op: OpTy<'tcx, Tag>, // LPWSTR + size_op: OpTy<'tcx, Tag>, // DWORD ) -> InterpResult<'tcx, u64> { let this = self.eval_context_mut(); this.assert_target_os("windows", "GetEnvironmentVariableW"); @@ -134,7 +128,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let var_ptr = Scalar::from(var_ptr.offset(Size::from_bytes(name_offset_bytes), this)?); let var_size = u64::try_from(this.read_os_str_from_wide_str(var_ptr)?.len()).unwrap(); - // `buf_size` represent size in characters. + // `buf_size` represents the size in characters. let buf_size = u64::try_from(this.read_scalar(size_op)?.to_u32()?).unwrap(); let return_val = if var_size.checked_add(1).unwrap() > buf_size { // If lpBuffer is not large enough to hold the data, the return value is the buffer size, in characters, @@ -157,6 +151,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx }) } + #[allow(non_snake_case)] fn GetEnvironmentStringsW(&mut self) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); this.assert_target_os("windows", "GetEnvironmentStringsW"); @@ -164,24 +159,33 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Info on layout of environment blocks in Windows: // https://docs.microsoft.com/en-us/windows/win32/procthread/environment-variables let mut env_vars = std::ffi::OsString::new(); - for &item in this.machine.env_vars.values()? { + for &item in this.machine.env_vars.map.values() { let env_var = this.read_os_str_from_wide_str(Scalar::from(item))?; env_vars.push(env_var); env_vars.push("\0"); } // Allocate environment block & Store environment variables to environment block. // Final null terminator(block terminator) is added by `alloc_os_str_to_wide_str`. + // FIXME: MemoryKind should be `MiMemoryKind::Machine`, + // but using it results in a Stacked Borrows error when running MIRI on 'tests/run-pass/env.rs' + // For now, use `MiriMemoryKind::WinHeap` instead. let envblock_ptr = this.alloc_os_str_as_wide_str(&env_vars, MiriMemoryKind::WinHeap.into()); - + // If the function succeeds, the return value is a pointer to the environment block of the current process. Ok(envblock_ptr.into()) } - fn FreeEnvironmentStringsW(&mut self, env_block_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, bool> { + #[allow(non_snake_case)] + fn FreeEnvironmentStringsW(&mut self, env_block_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); this.assert_target_os("windows", "FreeEnvironmentStringsW"); let env_block_ptr = this.read_scalar(env_block_op)?.not_undef()?; - Ok(this.memory.deallocate(this.force_ptr(env_block_ptr)?, None, MiriMemoryKind::WinHeap.into()).is_ok()) + // FIXME: MemoryKind should be `MiMemoryKind::Machine`, + // but using it results in a Stacked Borrows error when running MIRI on 'tests/run-pass/env.rs' + // For now, use `MiriMemoryKind::WinHeap` instead. + let result = this.memory.deallocate(this.force_ptr(env_block_ptr)?, None, MiriMemoryKind::WinHeap.into()); + // If the function succeeds, the return value is nonzero. + Ok(result.is_ok() as i32) } fn setenv( @@ -220,10 +224,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } + #[allow(non_snake_case)] fn SetEnvironmentVariableW( &mut self, - name_op: OpTy<'tcx, Tag>, // LPCWSTR lpName, - value_op: OpTy<'tcx, Tag>, // LPCWSTR lpValue, + name_op: OpTy<'tcx, Tag>, // LPCWSTR + value_op: OpTy<'tcx, Tag>, // LPCWSTR ) -> InterpResult<'tcx, i32> { let mut this = self.eval_context_mut(); this.assert_target_os("windows", "SetEnvironmentVariableW"); @@ -233,14 +238,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if this.is_null(name_ptr)? { // ERROR CODE is not clearly explained in docs.. For now, throw UB instead. - throw_ub_format!("Pointer to environment variable name is NULL"); + throw_ub_format!("pointer to environment variable name is NULL"); } let name = this.read_os_str_from_wide_str(name_ptr)?; if name.is_empty() { - throw_unsup_format!("Environment variable name is an empty string"); + throw_unsup_format!("environment variable name is an empty string"); } else if name.to_string_lossy().contains('=') { - throw_unsup_format!("Environment variable name contains '='"); + throw_unsup_format!("environment variable name contains '='"); } else if this.is_null(value_ptr)? { // Delete environment variable `{name}` if let Some(var) = this.machine.env_vars.map.remove(&name) { diff --git a/src/shims/foreign_items/windows.rs b/src/shims/foreign_items/windows.rs index cc64057135c11..a64ef0f129352 100644 --- a/src/shims/foreign_items/windows.rs +++ b/src/shims/foreign_items/windows.rs @@ -34,14 +34,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "GetEnvironmentStringsW" => { let result = this.GetEnvironmentStringsW()?; - // If the function succeeds, the return value is a pointer to the environment block of the current process. this.write_scalar(result, dest)?; } "FreeEnvironmentStringsW" => { let result = this.FreeEnvironmentStringsW(args[0])?; - // If the function succeeds, the return value is nonzero. - this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + this.write_scalar(Scalar::from_i32(result), dest)?; } // File related shims From f3e3af4beec260541dbeeead0a824caee7624e77 Mon Sep 17 00:00:00 2001 From: JOE1994 Date: Fri, 27 Mar 2020 09:18:13 -0400 Subject: [PATCH 1723/3747] adjust to change of 'fn write_os_str_to_wide_str' --- src/shims/env.rs | 52 ++++++++++++++---------------------------------- 1 file changed, 15 insertions(+), 37 deletions(-) diff --git a/src/shims/env.rs b/src/shims/env.rs index cc7c305596dc6..794a1aab422a8 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -25,12 +25,12 @@ impl<'tcx> EnvVars<'tcx> { ecx: &mut InterpCx<'mir, 'tcx, Evaluator<'tcx>>, mut excluded_env_vars: Vec, ) -> InterpResult<'tcx> { - if ecx.tcx.sess.target.target.target_os == "windows" { + let target_os = ecx.tcx.sess.target.target.target_os.as_str(); + if target_os == "windows" { // Exclude `TERM` var to avoid terminfo trying to open the termcap file. excluded_env_vars.push("TERM".to_owned()); } if ecx.machine.communicate { - let target_os = ecx.tcx.sess.target.target.target_os.as_str(); for (name, value) in env::vars() { if !excluded_env_vars.contains(&name) { let var_ptr = match target_os { @@ -68,28 +68,6 @@ fn alloc_env_var_as_wide_str<'mir, 'tcx>( Ok(ecx.alloc_os_str_as_wide_str(name_osstring.as_os_str(), MiriMemoryKind::Machine.into())) } -fn alloc_env_var_as_c_str<'mir, 'tcx>( - name: &OsStr, - value: &OsStr, - ecx: &mut InterpCx<'mir, 'tcx, Evaluator<'tcx>>, -) -> InterpResult<'tcx, Pointer> { - let mut name_osstring = name.to_os_string(); - name_osstring.push("="); - name_osstring.push(value); - Ok(ecx.alloc_os_str_as_c_str(name_osstring.as_os_str(), MiriMemoryKind::Machine.into())) -} - -fn alloc_env_var_as_wide_str<'mir, 'tcx>( - name: &OsStr, - value: &OsStr, - ecx: &mut InterpCx<'mir, 'tcx, Evaluator<'tcx>>, -) -> InterpResult<'tcx, Pointer> { - let mut name_osstring = name.to_os_string(); - name_osstring.push("="); - name_osstring.push(value); - Ok(ecx.alloc_os_str_as_wide_str(name_osstring.as_os_str(), MiriMemoryKind::Machine.into())) -} - impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { fn getenv(&mut self, name_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, Scalar> { @@ -126,26 +104,26 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let name_offset_bytes = u64::try_from(name.len()).unwrap().checked_add(1).unwrap().checked_mul(2).unwrap(); let var_ptr = Scalar::from(var_ptr.offset(Size::from_bytes(name_offset_bytes), this)?); + let var = this.read_os_str_from_wide_str(var_ptr)?; - let var_size = u64::try_from(this.read_os_str_from_wide_str(var_ptr)?.len()).unwrap(); + let buf_ptr = this.read_scalar(buf_op)?.not_undef()?; // `buf_size` represents the size in characters. let buf_size = u64::try_from(this.read_scalar(size_op)?.to_u32()?).unwrap(); - let return_val = if var_size.checked_add(1).unwrap() > buf_size { - // If lpBuffer is not large enough to hold the data, the return value is the buffer size, in characters, - // required to hold the string and its terminating null character and the contents of lpBuffer are undefined. - var_size + 1 - } else { - let buf_ptr = this.read_scalar(buf_op)?.not_undef()?; - let bytes_to_be_copied = var_size.checked_add(1).unwrap().checked_mul(2).unwrap(); - this.memory.copy(this.force_ptr(var_ptr)?, this.force_ptr(buf_ptr)?, Size::from_bytes(bytes_to_be_copied), true)?; + let (success, len) = this.write_os_str_to_wide_str(&var, buf_ptr, buf_size)?; + + if success { // If the function succeeds, the return value is the number of characters stored in the buffer pointed to by lpBuffer, // not including the terminating null character. - var_size - }; - return_val + len + } else { + // If lpBuffer is not large enough to hold the data, the return value is the buffer size, in characters, + // required to hold the string and its terminating null character and the contents of lpBuffer are undefined. + len + 1 + } } None => { - this.set_last_error(Scalar::from_u32(203))?; // ERROR_ENVVAR_NOT_FOUND + let envvar_not_found = this.eval_path_scalar(&["std", "sys", "windows", "c", "ERROR_ENVVAR_NOT_FOUND"])?; + this.set_last_error(envvar_not_found.not_undef()?)?; 0 // return zero upon failure } }) From eaca17fcc31a74690bc89d6b2aa7c41b4aedb79a Mon Sep 17 00:00:00 2001 From: JOE1994 Date: Fri, 27 Mar 2020 09:59:42 -0400 Subject: [PATCH 1724/3747] add reference to issue#1013 --- src/shims/env.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/shims/env.rs b/src/shims/env.rs index 794a1aab422a8..eee9a539185cd 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -27,9 +27,11 @@ impl<'tcx> EnvVars<'tcx> { ) -> InterpResult<'tcx> { let target_os = ecx.tcx.sess.target.target.target_os.as_str(); if target_os == "windows" { - // Exclude `TERM` var to avoid terminfo trying to open the termcap file. + // Temporary hack: Exclude `TERM` var to avoid terminfo trying to open the termcap file. + // Can be removed once Issue#1013(Implement file system access for Windows) is resolved. excluded_env_vars.push("TERM".to_owned()); } + if ecx.machine.communicate { for (name, value) in env::vars() { if !excluded_env_vars.contains(&name) { From 3fe71dff5a58efaabd1686e2a25c09adb8d74092 Mon Sep 17 00:00:00 2001 From: Youngsuk Kim Date: Fri, 27 Mar 2020 10:15:35 -0400 Subject: [PATCH 1725/3747] Modify reference to issue 1013 Co-Authored-By: Ralf Jung --- src/shims/env.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shims/env.rs b/src/shims/env.rs index eee9a539185cd..b6d7010263788 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -28,7 +28,7 @@ impl<'tcx> EnvVars<'tcx> { let target_os = ecx.tcx.sess.target.target.target_os.as_str(); if target_os == "windows" { // Temporary hack: Exclude `TERM` var to avoid terminfo trying to open the termcap file. - // Can be removed once Issue#1013(Implement file system access for Windows) is resolved. + // Can be removed once https://github.com/rust-lang/miri/issues/1013 is resolved. excluded_env_vars.push("TERM".to_owned()); } From ea836eeb0d72d5f983489f283ea7fc5f6a7ad442 Mon Sep 17 00:00:00 2001 From: JOE1994 Date: Fri, 27 Mar 2020 14:18:19 -0400 Subject: [PATCH 1726/3747] remove or update 'ignore-windows' annotations in some tests --- tests/compile-fail/environ-gets-deallocated.rs | 2 +- tests/run-pass/env-exclude.rs | 1 - tests/run-pass/env-without-isolation.rs | 1 - 3 files changed, 1 insertion(+), 3 deletions(-) diff --git a/tests/compile-fail/environ-gets-deallocated.rs b/tests/compile-fail/environ-gets-deallocated.rs index dd00aef450cd9..0f374a2e3f80c 100644 --- a/tests/compile-fail/environ-gets-deallocated.rs +++ b/tests/compile-fail/environ-gets-deallocated.rs @@ -1,4 +1,4 @@ -//ignore-windows: TODO env var emulation stubbed out on Windows +//ignore-windows: Windows does not have a global environ list that the program can access directly #[cfg(target_os="linux")] fn get_environ() -> *const *const u8 { diff --git a/tests/run-pass/env-exclude.rs b/tests/run-pass/env-exclude.rs index efcf7a756114c..1e251084f0227 100644 --- a/tests/run-pass/env-exclude.rs +++ b/tests/run-pass/env-exclude.rs @@ -1,4 +1,3 @@ -// ignore-windows: TODO env var emulation stubbed out on Windows // compile-flags: -Zmiri-disable-isolation -Zmiri-env-exclude=MIRI_ENV_VAR_TEST fn main() { diff --git a/tests/run-pass/env-without-isolation.rs b/tests/run-pass/env-without-isolation.rs index 537e0923d20b8..638476209888a 100644 --- a/tests/run-pass/env-without-isolation.rs +++ b/tests/run-pass/env-without-isolation.rs @@ -1,4 +1,3 @@ -// ignore-windows: TODO env var emulation stubbed out on Windows // compile-flags: -Zmiri-disable-isolation fn main() { From da5f2f305b6ad749e01dc8d8698da0628ffd8365 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 27 Mar 2020 19:39:00 +0100 Subject: [PATCH 1727/3747] implement TLS cleanup for macOS --- src/eval.rs | 4 +-- src/shims/foreign_items/posix/macos.rs | 5 ++- src/shims/tls.rs | 44 ++++++++++++++++++++++++-- 3 files changed, 48 insertions(+), 5 deletions(-) diff --git a/src/eval.rs b/src/eval.rs index 8274b52bd085e..7f07fc1a7db6b 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -186,8 +186,8 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) -> Option { // FIXME: We always ignore leaks on some OSs where we do not // correctly implement TLS destructors. - let target_os = tcx.sess.target.target.target_os.as_str(); - let ignore_leaks = config.ignore_leaks || target_os == "windows" || target_os == "macos"; + let target_os = &tcx.sess.target.target.target_os; + let ignore_leaks = config.ignore_leaks || target_os == "windows"; let (mut ecx, ret_place) = match create_ecx(tcx, main_id, config) { Ok(v) => v, diff --git a/src/shims/foreign_items/posix/macos.rs b/src/shims/foreign_items/posix/macos.rs index ee02effecd2c5..325be877d0443 100644 --- a/src/shims/foreign_items/posix/macos.rs +++ b/src/shims/foreign_items/posix/macos.rs @@ -87,7 +87,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "_tlv_atexit" => { - // FIXME: register the destructor. + let dtor = this.read_scalar(args[0])?.not_undef()?; + let dtor = this.memory.get_fn(dtor)?.as_instance()?; + let data = this.read_scalar(args[1])?.not_undef()?; + this.machine.tls.set_global_dtor(dtor, data)?; } "_NSGetArgc" => { diff --git a/src/shims/tls.rs b/src/shims/tls.rs index 094b58d99a287..6635978cb2e37 100644 --- a/src/shims/tls.rs +++ b/src/shims/tls.rs @@ -25,6 +25,12 @@ pub struct TlsData<'tcx> { /// pthreads-style thread-local storage. keys: BTreeMap>, + + /// A single global dtor (that's how things work on macOS) with a data argument. + global_dtor: Option<(ty::Instance<'tcx>, Scalar)>, + + /// Whether we are in the "destruct" phase, during which some operations are UB. + dtors_running: bool, } impl<'tcx> Default for TlsData<'tcx> { @@ -32,6 +38,8 @@ impl<'tcx> Default for TlsData<'tcx> { TlsData { next_key: 1, // start with 1 as we must not use 0 on Windows keys: Default::default(), + global_dtor: None, + dtors_running: false, } } } @@ -86,6 +94,19 @@ impl<'tcx> TlsData<'tcx> { } } + pub fn set_global_dtor(&mut self, dtor: ty::Instance<'tcx>, data: Scalar) -> InterpResult<'tcx> { + if self.dtors_running { + // UB, according to libstd docs. + throw_ub_format!("setting global destructor while destructors are already running"); + } + if self.global_dtor.is_some() { + throw_unsup_format!("setting more than one global destructor is not supported"); + } + + self.global_dtor = Some((dtor, data)); + Ok(()) + } + /// Returns a dtor, its argument and its index, if one is supposed to run /// /// An optional destructor function may be associated with each key value. @@ -134,11 +155,30 @@ impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tc pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { fn run_tls_dtors(&mut self) -> InterpResult<'tcx> { let this = self.eval_context_mut(); + assert!(!this.machine.tls.dtors_running, "running TLS dtors twice"); + this.machine.tls.dtors_running = true; + + // The macOS global dtor runs "before any TLS slots get freed", so do that first. + if let Some((instance, data)) = this.machine.tls.global_dtor { + trace!("Running global dtor {:?} on {:?}", instance, data); + + let ret_place = MPlaceTy::dangling(this.layout_of(this.tcx.mk_unit())?, this).into(); + this.call_function( + instance, + &[data.into()], + Some(ret_place), + StackPopCleanup::None { cleanup: true }, + )?; + + // step until out of stackframes + this.run()?; + } + + // Now run the "keyed" destructors. let mut dtor = this.machine.tls.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); - assert!(!this.is_null(ptr).unwrap(), "Data can't be NULL when dtor is called!"); + assert!(!this.is_null(ptr).unwrap(), "data can't be NULL when dtor is called!"); let ret_place = MPlaceTy::dangling(this.layout_of(this.tcx.mk_unit())?, this).into(); this.call_function( From c5ef8a656fd211dd1d3c6d73cb3705dc4b301907 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 27 Mar 2020 19:39:35 +0100 Subject: [PATCH 1728/3747] enable leak tests on macOS --- tests/compile-fail/memleak.rs | 1 - tests/compile-fail/memleak_rc.rs | 1 - 2 files changed, 2 deletions(-) diff --git a/tests/compile-fail/memleak.rs b/tests/compile-fail/memleak.rs index 06e01d7aea3a5..c3b27abcdbb28 100644 --- a/tests/compile-fail/memleak.rs +++ b/tests/compile-fail/memleak.rs @@ -1,5 +1,4 @@ // ignore-windows: We do not check leaks on Windows -// ignore-macos: We do not check leaks on macOS //error-pattern: the evaluated program leaked memory diff --git a/tests/compile-fail/memleak_rc.rs b/tests/compile-fail/memleak_rc.rs index 14a85ecd8947c..446d28681b9eb 100644 --- a/tests/compile-fail/memleak_rc.rs +++ b/tests/compile-fail/memleak_rc.rs @@ -1,5 +1,4 @@ // ignore-windows: We do not check leaks on Windows -// ignore-macos: We do not check leaks on macOS //error-pattern: the evaluated program leaked memory From 579b3c49dac9def1495f7d97d4f5b2771bbeefd8 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 27 Mar 2020 20:36:18 +0100 Subject: [PATCH 1729/3747] adjust MemoryKind comment --- src/shims/env.rs | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/shims/env.rs b/src/shims/env.rs index b6d7010263788..ed689b1f4272b 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -146,9 +146,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // Allocate environment block & Store environment variables to environment block. // Final null terminator(block terminator) is added by `alloc_os_str_to_wide_str`. - // FIXME: MemoryKind should be `MiMemoryKind::Machine`, - // but using it results in a Stacked Borrows error when running MIRI on 'tests/run-pass/env.rs' - // For now, use `MiriMemoryKind::WinHeap` instead. + // FIXME: MemoryKind should be `Machine`, blocked on https://github.com/rust-lang/rust/pull/70479. let envblock_ptr = this.alloc_os_str_as_wide_str(&env_vars, MiriMemoryKind::WinHeap.into()); // If the function succeeds, the return value is a pointer to the environment block of the current process. Ok(envblock_ptr.into()) @@ -160,9 +158,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.assert_target_os("windows", "FreeEnvironmentStringsW"); let env_block_ptr = this.read_scalar(env_block_op)?.not_undef()?; - // FIXME: MemoryKind should be `MiMemoryKind::Machine`, - // but using it results in a Stacked Borrows error when running MIRI on 'tests/run-pass/env.rs' - // For now, use `MiriMemoryKind::WinHeap` instead. + // FIXME: MemoryKind should be `Machine`, blocked on https://github.com/rust-lang/rust/pull/70479. let result = this.memory.deallocate(this.force_ptr(env_block_ptr)?, None, MiriMemoryKind::WinHeap.into()); // If the function succeeds, the return value is nonzero. Ok(result.is_ok() as i32) From 032d9aa7d5160f39ab745a5da13d686ec214bb9b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 28 Mar 2020 09:10:34 +0100 Subject: [PATCH 1730/3747] also do some float-to-float cast testing --- tests/run-pass/floats.rs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/tests/run-pass/floats.rs b/tests/run-pass/floats.rs index 39dc73ed18913..990745c85d67e 100644 --- a/tests/run-pass/floats.rs +++ b/tests/run-pass/floats.rs @@ -17,7 +17,7 @@ fn main() { let y: f32 = unsafe { std::mem::transmute(x) }; assert_eq!(y, 42.0_f32); - // f32 casts + // f32-to-int casts assert_eq!(5.0f32 as u32, 5); assert_eq!(-5.0f32 as u32, 0); assert_eq!(5.0f32 as i32, 5); @@ -36,7 +36,7 @@ fn main() { assert_eq!((u32::MAX-127) as f32 as u32, u32::MAX); // rounding loss assert_eq!((u32::MAX-128) as f32 as u32, u32::MAX-255); // rounding loss - // f64 casts + // f64-to-int casts assert_eq!(5.0f64 as u64, 5); assert_eq!(-5.0f64 as u64, 0); assert_eq!(5.0f64 as i64, 5); @@ -55,6 +55,14 @@ fn main() { assert_eq!((u64::MAX-1023) as f64 as u64, u64::MAX); // rounding loss assert_eq!((u64::MAX-1024) as f64 as u64, u64::MAX-2047); // rounding loss + // f32 <-> f64 casts + assert_eq!(5.0f64 as f32, 5.0f32); + assert_eq!(5.0f32 as f64, 5.0f64); + assert_eq!(std::f64::MAX as f32, std::f32::INFINITY); + assert_eq!(std::f64::MIN as f32, std::f32::NEG_INFINITY); + assert_eq!(std::f32::INFINITY as f64, std::f64::INFINITY); + assert_eq!(std::f32::NEG_INFINITY as f64, std::f64::NEG_INFINITY); + // f32 min/max assert_eq!((1.0 as f32).max(-1.0), 1.0); assert_eq!((1.0 as f32).min(-1.0), -1.0); From b8a817fc03ada9a92df7fe916f1933f5b81f84af Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 28 Mar 2020 09:20:07 +0100 Subject: [PATCH 1731/3747] avoid promotion so this can be compared with rustc --- tests/run-pass/floats.rs | 144 +++++++++++++++++++++------------------ 1 file changed, 78 insertions(+), 66 deletions(-) diff --git a/tests/run-pass/floats.rs b/tests/run-pass/floats.rs index 990745c85d67e..5a7413e98ea81 100644 --- a/tests/run-pass/floats.rs +++ b/tests/run-pass/floats.rs @@ -1,9 +1,21 @@ +#![feature(track_caller)] +use std::fmt::Debug; + +// Helper function to avoid promotion so that this tests "run-time" casts, not CTFE. +// Doesn't make a big difference when running this in Miri, but when running this in +// rustc (with -Zmir-opt-level=0) for comparison it means we use LLVM casts. +#[track_caller] +#[inline(never)] +fn assert_eq(x: T, y: T) { + assert_eq!(x, y); +} + fn main() { // basic arithmetic - assert_eq!(6.0_f32*6.0_f32, 36.0_f32); - assert_eq!(6.0_f64*6.0_f64, 36.0_f64); - assert_eq!(-{5.0_f32}, -5.0_f32); - assert_eq!(-{5.0_f64}, -5.0_f64); + assert_eq(6.0_f32*6.0_f32, 36.0_f32); + assert_eq(6.0_f64*6.0_f64, 36.0_f64); + assert_eq(-{5.0_f32}, -5.0_f32); + assert_eq(-{5.0_f64}, -5.0_f64); // infinities, NaN assert!((5.0_f32/0.0).is_infinite()); assert!((5.0_f64/0.0).is_infinite()); @@ -12,84 +24,84 @@ fn main() { // byte-level transmute let x: u64 = unsafe { std::mem::transmute(42.0_f64) }; let y: f64 = unsafe { std::mem::transmute(x) }; - assert_eq!(y, 42.0_f64); + assert_eq(y, 42.0_f64); let x: u32 = unsafe { std::mem::transmute(42.0_f32) }; let y: f32 = unsafe { std::mem::transmute(x) }; - assert_eq!(y, 42.0_f32); + assert_eq(y, 42.0_f32); // f32-to-int casts - assert_eq!(5.0f32 as u32, 5); - assert_eq!(-5.0f32 as u32, 0); - assert_eq!(5.0f32 as i32, 5); - assert_eq!(-5.0f32 as i32, -5); - assert_eq!(std::f32::MAX as i32, i32::MAX); - assert_eq!(std::f32::INFINITY as i32, i32::MAX); - assert_eq!(std::f32::MAX as u32, u32::MAX); - assert_eq!(std::f32::INFINITY as u32, u32::MAX); - assert_eq!(std::f32::MIN as i32, i32::MIN); - assert_eq!(std::f32::NEG_INFINITY as i32, i32::MIN); - assert_eq!(std::f32::MIN as u32, 0); - assert_eq!(std::f32::NEG_INFINITY as u32, 0); - assert_eq!(std::f32::NAN as i32, 0); - assert_eq!(std::f32::NAN as u32, 0); - assert_eq!(u128::MAX as f32, std::f32::INFINITY); - assert_eq!((u32::MAX-127) as f32 as u32, u32::MAX); // rounding loss - assert_eq!((u32::MAX-128) as f32 as u32, u32::MAX-255); // rounding loss + assert_eq(5.0f32 as u32, 5); + assert_eq(-5.0f32 as u32, 0); + assert_eq(5.0f32 as i32, 5); + assert_eq(-5.0f32 as i32, -5); + assert_eq(std::f32::MAX as i32, i32::MAX); + assert_eq(std::f32::INFINITY as i32, i32::MAX); + assert_eq(std::f32::MAX as u32, u32::MAX); + assert_eq(std::f32::INFINITY as u32, u32::MAX); + assert_eq(std::f32::MIN as i32, i32::MIN); + assert_eq(std::f32::NEG_INFINITY as i32, i32::MIN); + assert_eq(std::f32::MIN as u32, 0); + assert_eq(std::f32::NEG_INFINITY as u32, 0); + assert_eq(std::f32::NAN as i32, 0); + assert_eq(std::f32::NAN as u32, 0); + assert_eq(u128::MAX as f32, std::f32::INFINITY); + assert_eq((u32::MAX-127) as f32 as u32, u32::MAX); // rounding loss + assert_eq((u32::MAX-128) as f32 as u32, u32::MAX-255); // rounding loss // f64-to-int casts - assert_eq!(5.0f64 as u64, 5); - assert_eq!(-5.0f64 as u64, 0); - assert_eq!(5.0f64 as i64, 5); - assert_eq!(-5.0f64 as i64, -5); - assert_eq!(std::f64::MAX as i64, i64::MAX); - assert_eq!(std::f64::INFINITY as i64, i64::MAX); - assert_eq!(std::f64::MAX as u64, u64::MAX); - assert_eq!(std::f64::INFINITY as u64, u64::MAX); - assert_eq!(std::f64::MIN as i64, i64::MIN); - assert_eq!(std::f64::NEG_INFINITY as i64, i64::MIN); - assert_eq!(std::f64::MIN as u64, 0); - assert_eq!(std::f64::NEG_INFINITY as u64, 0); - assert_eq!(std::f64::NAN as i64, 0); - assert_eq!(std::f64::NAN as u64, 0); - assert_eq!(u128::MAX as f64 as u128, u128::MAX); - assert_eq!((u64::MAX-1023) as f64 as u64, u64::MAX); // rounding loss - assert_eq!((u64::MAX-1024) as f64 as u64, u64::MAX-2047); // rounding loss + assert_eq(5.0f64 as u64, 5); + assert_eq(-5.0f64 as u64, 0); + assert_eq(5.0f64 as i64, 5); + assert_eq(-5.0f64 as i64, -5); + assert_eq(std::f64::MAX as i64, i64::MAX); + assert_eq(std::f64::INFINITY as i64, i64::MAX); + assert_eq(std::f64::MAX as u64, u64::MAX); + assert_eq(std::f64::INFINITY as u64, u64::MAX); + assert_eq(std::f64::MIN as i64, i64::MIN); + assert_eq(std::f64::NEG_INFINITY as i64, i64::MIN); + assert_eq(std::f64::MIN as u64, 0); + assert_eq(std::f64::NEG_INFINITY as u64, 0); + assert_eq(std::f64::NAN as i64, 0); + assert_eq(std::f64::NAN as u64, 0); + assert_eq(u128::MAX as f64 as u128, u128::MAX); + assert_eq((u64::MAX-1023) as f64 as u64, u64::MAX); // rounding loss + assert_eq((u64::MAX-1024) as f64 as u64, u64::MAX-2047); // rounding loss // f32 <-> f64 casts - assert_eq!(5.0f64 as f32, 5.0f32); - assert_eq!(5.0f32 as f64, 5.0f64); - assert_eq!(std::f64::MAX as f32, std::f32::INFINITY); - assert_eq!(std::f64::MIN as f32, std::f32::NEG_INFINITY); - assert_eq!(std::f32::INFINITY as f64, std::f64::INFINITY); - assert_eq!(std::f32::NEG_INFINITY as f64, std::f64::NEG_INFINITY); + assert_eq(5.0f64 as f32, 5.0f32); + assert_eq(5.0f32 as f64, 5.0f64); + assert_eq(std::f64::MAX as f32, std::f32::INFINITY); + assert_eq(std::f64::MIN as f32, std::f32::NEG_INFINITY); + assert_eq(std::f32::INFINITY as f64, std::f64::INFINITY); + assert_eq(std::f32::NEG_INFINITY as f64, std::f64::NEG_INFINITY); // f32 min/max - assert_eq!((1.0 as f32).max(-1.0), 1.0); - assert_eq!((1.0 as f32).min(-1.0), -1.0); - assert_eq!(std::f32::NAN.min(9.0), 9.0); - assert_eq!(std::f32::NAN.max(-9.0), -9.0); - assert_eq!((9.0 as f32).min(std::f32::NAN), 9.0); - assert_eq!((-9.0 as f32).max(std::f32::NAN), -9.0); + assert_eq((1.0 as f32).max(-1.0), 1.0); + assert_eq((1.0 as f32).min(-1.0), -1.0); + assert_eq(std::f32::NAN.min(9.0), 9.0); + assert_eq(std::f32::NAN.max(-9.0), -9.0); + assert_eq((9.0 as f32).min(std::f32::NAN), 9.0); + assert_eq((-9.0 as f32).max(std::f32::NAN), -9.0); // f64 min/max - assert_eq!((1.0 as f64).max(-1.0), 1.0); - assert_eq!((1.0 as f64).min(-1.0), -1.0); - assert_eq!(std::f64::NAN.min(9.0), 9.0); - assert_eq!(std::f64::NAN.max(-9.0), -9.0); - assert_eq!((9.0 as f64).min(std::f64::NAN), 9.0); - assert_eq!((-9.0 as f64).max(std::f64::NAN), -9.0); + assert_eq((1.0 as f64).max(-1.0), 1.0); + assert_eq((1.0 as f64).min(-1.0), -1.0); + assert_eq(std::f64::NAN.min(9.0), 9.0); + assert_eq(std::f64::NAN.max(-9.0), -9.0); + assert_eq((9.0 as f64).min(std::f64::NAN), 9.0); + assert_eq((-9.0 as f64).max(std::f64::NAN), -9.0); // f32 copysign - assert_eq!(3.5_f32.copysign(0.42), 3.5_f32); - assert_eq!(3.5_f32.copysign(-0.42), -3.5_f32); - assert_eq!((-3.5_f32).copysign(0.42), 3.5_f32); - assert_eq!((-3.5_f32).copysign(-0.42), -3.5_f32); + assert_eq(3.5_f32.copysign(0.42), 3.5_f32); + assert_eq(3.5_f32.copysign(-0.42), -3.5_f32); + assert_eq((-3.5_f32).copysign(0.42), 3.5_f32); + assert_eq((-3.5_f32).copysign(-0.42), -3.5_f32); assert!(std::f32::NAN.copysign(1.0).is_nan()); // f64 copysign - assert_eq!(3.5_f64.copysign(0.42), 3.5_f64); - assert_eq!(3.5_f64.copysign(-0.42), -3.5_f64); - assert_eq!((-3.5_f64).copysign(0.42), 3.5_f64); - assert_eq!((-3.5_f64).copysign(-0.42), -3.5_f64); + assert_eq(3.5_f64.copysign(0.42), 3.5_f64); + assert_eq(3.5_f64.copysign(-0.42), -3.5_f64); + assert_eq((-3.5_f64).copysign(0.42), 3.5_f64); + assert_eq((-3.5_f64).copysign(-0.42), -3.5_f64); assert!(std::f64::NAN.copysign(1.0).is_nan()); } From 02897e03cfe6b04d28c0f3197563d1dba3f7658d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 28 Mar 2020 09:50:24 +0100 Subject: [PATCH 1732/3747] cleanup tcx usage and a few comments --- src/shims/foreign_items.rs | 6 +++--- src/shims/foreign_items/posix.rs | 5 ++--- src/shims/foreign_items/windows.rs | 3 +-- src/shims/intrinsics.rs | 3 +-- src/shims/tls.rs | 7 +++++-- 5 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 6827b72427fb1..0bed688187b08 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -124,7 +124,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx }; // Strip linker suffixes (seen on 32-bit macOS). let link_name = link_name.trim_end_matches("$UNIX2003"); - let tcx = &{ this.tcx.tcx }; + let tcx = this.tcx.tcx; // First: functions that diverge. let (dest, ret) = match ret { @@ -133,8 +133,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // The implementation is provided by the function with the `#[panic_handler]` attribute. "panic_impl" => { this.check_panic_supported()?; - let panic_impl_id = this.tcx.lang_items().panic_impl().unwrap(); - let panic_impl_instance = ty::Instance::mono(*this.tcx, panic_impl_id); + let panic_impl_id = tcx.lang_items().panic_impl().unwrap(); + let panic_impl_instance = ty::Instance::mono(tcx, panic_impl_id); return Ok(Some(&*this.load_mir(panic_impl_instance.def, None)?)); } | "exit" diff --git a/src/shims/foreign_items/posix.rs b/src/shims/foreign_items/posix.rs index 85e9b88b6ec03..425fe4b1b479a 100644 --- a/src/shims/foreign_items/posix.rs +++ b/src/shims/foreign_items/posix.rs @@ -17,7 +17,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ret: mir::BasicBlock, ) -> InterpResult<'tcx, bool> { let this = self.eval_context_mut(); - let tcx = &{ this.tcx.tcx }; match link_name { // Environment related shims @@ -65,7 +64,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "write" => { let fd = this.read_scalar(args[0])?.to_i32()?; let buf = this.read_scalar(args[1])?.not_undef()?; - let n = this.read_scalar(args[2])?.to_machine_usize(tcx)?; + let n = this.read_scalar(args[2])?.to_machine_usize(this)?; trace!("Called write({:?}, {:?}, {:?})", fd, buf, n); let result = if fd == 1 || fd == 2 { // stdout/stderr @@ -209,7 +208,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "pthread_getspecific" => { let key = this.force_bits(this.read_scalar(args[0])?.not_undef()?, args[0].layout.size)?; - let ptr = this.machine.tls.load_tls(key, tcx)?; + let ptr = this.machine.tls.load_tls(key, this)?; this.write_scalar(ptr, dest)?; } "pthread_setspecific" => { diff --git a/src/shims/foreign_items/windows.rs b/src/shims/foreign_items/windows.rs index a64ef0f129352..9e71ba7d90741 100644 --- a/src/shims/foreign_items/windows.rs +++ b/src/shims/foreign_items/windows.rs @@ -13,7 +13,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx _ret: mir::BasicBlock, ) -> InterpResult<'tcx, bool> { let this = self.eval_context_mut(); - let tcx = &{ this.tcx.tcx }; match link_name { // Windows API stubs. @@ -160,7 +159,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "TlsGetValue" => { let key = u128::from(this.read_scalar(args[0])?.to_u32()?); - let ptr = this.machine.tls.load_tls(key, tcx)?; + let ptr = this.machine.tls.load_tls(key, this)?; this.write_scalar(ptr, dest)?; } "TlsSetValue" => { diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 91371e2c9df96..84e8cca556a1c 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -24,13 +24,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if this.emulate_intrinsic(span, instance, args, ret)? { return Ok(()); } - let tcx = &{ this.tcx.tcx }; let substs = instance.substs; // All these intrinsics take raw pointers, so if we access memory directly // (as opposed to through a place), we have to remember to erase any tag // that might still hang around! - let intrinsic_name = &*tcx.item_name(instance.def_id()).as_str(); + let intrinsic_name = &*this.tcx.item_name(instance.def_id()).as_str(); // First handle intrinsics without return place. let (dest, ret) = match ret { diff --git a/src/shims/tls.rs b/src/shims/tls.rs index 6635978cb2e37..461b5b3eed6a2 100644 --- a/src/shims/tls.rs +++ b/src/shims/tls.rs @@ -70,7 +70,7 @@ impl<'tcx> TlsData<'tcx> { } pub fn load_tls( - &mut self, + &self, key: TlsKey, cx: &impl HasDataLayout, ) -> InterpResult<'tcx, Scalar> { @@ -107,7 +107,8 @@ impl<'tcx> TlsData<'tcx> { Ok(()) } - /// Returns a dtor, its argument and its index, if one is supposed to run + /// Returns a dtor, its argument and its index, if one is supposed to run. + /// `key` is the last dtors that was run; we return the *next* one after that. /// /// An optional destructor function may be associated with each key value. /// At thread exit, if a key value has a non-NULL destructor pointer, @@ -191,8 +192,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // step until out of stackframes this.run()?; + // Fetch next dtor after `key`. dtor = match this.machine.tls.fetch_tls_dtor(Some(key)) { dtor @ Some(_) => dtor, + // We ran each dtor once, start over from the beginning. None => this.machine.tls.fetch_tls_dtor(None), }; } From f7516883968322aa03e41dfb8cdd80719ea5ea13 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 28 Mar 2020 10:29:05 +0100 Subject: [PATCH 1733/3747] miri build script: use incremental builds --- miri | 1 + 1 file changed, 1 insertion(+) diff --git a/miri b/miri index 47ff5024fc633..0cda9e80926e1 100755 --- a/miri +++ b/miri @@ -49,6 +49,7 @@ fi # We enable debug-assertions to get tracing. # We enable line-only debuginfo for backtraces. export RUSTFLAGS="-C link-args=-Wl,-rpath,$LIBDIR -C debug-assertions -C debuginfo=1 $RUSTC_EXTRA_FLAGS" +export CARGO_INCREMENTAL=1 ## Helper functions From 876bded2e8d5fe0dc3b084c3e9faa2739493d797 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 28 Mar 2020 10:07:23 +0100 Subject: [PATCH 1734/3747] run Windows TLS dtor function --- src/eval.rs | 7 +++---- src/helpers.rs | 2 +- src/machine.rs | 34 ++++++++++++++++++++++++---------- src/shims/foreign_items.rs | 2 +- src/shims/tls.rs | 27 ++++++++++++++++++++++++++- 5 files changed, 55 insertions(+), 17 deletions(-) diff --git a/src/eval.rs b/src/eval.rs index 7f07fc1a7db6b..512b4176df8b4 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -184,10 +184,9 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( /// Returns `Some(return_code)` if program executed completed. /// Returns `None` if an evaluation error occured. pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) -> Option { - // FIXME: We always ignore leaks on some OSs where we do not - // correctly implement TLS destructors. - let target_os = &tcx.sess.target.target.target_os; - let ignore_leaks = config.ignore_leaks || target_os == "windows"; + // FIXME: on Windows, locks and TLS dtor management allocate and leave that memory in `static`s. + // So we need https://github.com/rust-lang/miri/issues/940 to fix the leaks there. + let ignore_leaks = config.ignore_leaks || tcx.sess.target.target.target_os == "windows"; let (mut ecx, ret_place) = match create_ecx(tcx, main_id, config) { Ok(v) => v, diff --git a/src/helpers.rs b/src/helpers.rs index 3e89fdf6f3cce..aa327b468bf81 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -413,7 +413,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn set_last_error_from_io_error(&mut self, e: std::io::Error) -> InterpResult<'tcx> { use std::io::ErrorKind::*; let this = self.eval_context_mut(); - let target = &this.tcx.tcx.sess.target.target; + let target = &this.tcx.sess.target.target; let last_error = if target.options.target_family == Some("unix".to_owned()) { this.eval_libc(match e.kind() { ConnectionRefused => "ECONNREFUSED", diff --git a/src/machine.rs b/src/machine.rs index 73e7ce665b858..4bf3d0d7f4465 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -102,6 +102,20 @@ impl MemoryExtra { } } + fn add_extern_static<'tcx, 'mir>( + this: &mut MiriEvalContext<'mir, 'tcx>, + name: &str, + ptr: Scalar, + ) { + let ptr = ptr.assert_ptr(); + assert_eq!(ptr.offset, Size::ZERO); + this.memory + .extra + .extern_statics + .insert(Symbol::intern(name), ptr.alloc_id) + .unwrap_none(); + } + /// Sets up the "extern statics" for this machine. pub fn init_extern_statics<'tcx, 'mir>( this: &mut MiriEvalContext<'mir, 'tcx>, @@ -113,17 +127,17 @@ impl MemoryExtra { let layout = this.layout_of(this.tcx.types.usize)?; let place = this.allocate(layout, MiriMemoryKind::Machine.into()); this.write_scalar(Scalar::from_machine_usize(0, &*this.tcx), place.into())?; - this.memory - .extra - .extern_statics - .insert(Symbol::intern("__cxa_thread_atexit_impl"), place.ptr.assert_ptr().alloc_id) - .unwrap_none(); + Self::add_extern_static(this, "__cxa_thread_atexit_impl", place.ptr); // "environ" - this.memory - .extra - .extern_statics - .insert(Symbol::intern("environ"), this.machine.env_vars.environ.unwrap().ptr.assert_ptr().alloc_id) - .unwrap_none(); + Self::add_extern_static(this, "environ", this.machine.env_vars.environ.unwrap().ptr); + } + "windows" => { + // "_tls_used" + // This is some obscure hack that is part of the Windows TLS story. It's a `u8`. + let layout = this.layout_of(this.tcx.types.u8)?; + let place = this.allocate(layout, MiriMemoryKind::Machine.into()); + this.write_scalar(Scalar::from_u8(0), place.into())?; + Self::add_extern_static(this, "_tls_used", place.ptr); } _ => {} // No "extern statics" supported on this target } diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 0bed688187b08..ecf24e2f20384 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -19,7 +19,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn min_align(&self, size: u64, kind: MiriMemoryKind) -> Align { let this = self.eval_context_ref(); // List taken from `libstd/sys_common/alloc.rs`. - let min_align = match this.tcx.tcx.sess.target.target.arch.as_str() { + let min_align = match this.tcx.sess.target.target.arch.as_str() { "x86" | "arm" | "mips" | "powerpc" | "powerpc64" | "asmjs" | "wasm32" => 8, "x86_64" | "aarch64" | "mips64" | "s390x" | "sparc64" => 16, arch => bug!("Unsupported target architecture: {}", arch), diff --git a/src/shims/tls.rs b/src/shims/tls.rs index 461b5b3eed6a2..c753689f4c258 100644 --- a/src/shims/tls.rs +++ b/src/shims/tls.rs @@ -159,6 +159,32 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx assert!(!this.machine.tls.dtors_running, "running TLS dtors twice"); this.machine.tls.dtors_running = true; + if this.tcx.sess.target.target.target_os == "windows" { + // Windows has a special magic linker section that is run on certain events. + // Instead of searching for that section and supporting arbitrary hooks in there + // (that would be basically https://github.com/rust-lang/miri/issues/450), + // we specifically look up the static in libstd that we know is placed + // in that section. + let thread_callback = this.eval_path_scalar(&["std", "sys", "windows", "thread_local", "p_thread_callback"])?; + let thread_callback = this.memory.get_fn(thread_callback.not_undef()?)?.as_instance()?; + + // The signature of this function is `unsafe extern "system" fn(h: c::LPVOID, dwReason: c::DWORD, pv: c::LPVOID)`. + let reason = this.eval_path_scalar(&["std", "sys", "windows", "c", "DLL_PROCESS_DETACH"])?; + let ret_place = MPlaceTy::dangling(this.layout_of(this.tcx.mk_unit())?, this).into(); + this.call_function( + thread_callback, + &[Scalar::ptr_null(this).into(), reason.into(), Scalar::ptr_null(this).into()], + Some(ret_place), + StackPopCleanup::None { cleanup: true }, + )?; + + // step until out of stackframes + this.run()?; + + // Windows doesn't have other destructors. + return Ok(()); + } + // The macOS global dtor runs "before any TLS slots get freed", so do that first. if let Some((instance, data)) = this.machine.tls.global_dtor { trace!("Running global dtor {:?} on {:?}", instance, data); @@ -199,7 +225,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx None => this.machine.tls.fetch_tls_dtor(None), }; } - // FIXME: On a windows target, call `unsafe extern "system" fn on_tls_callback`. Ok(()) } } From 204c13b8c724b208b8e26148ba21087b543e960b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 28 Mar 2020 11:06:56 +0100 Subject: [PATCH 1735/3747] env shim: make sure we clean up all the memory we allocate --- src/eval.rs | 5 +++++ src/lib.rs | 2 ++ src/machine.rs | 8 ++++++-- src/shims/env.rs | 37 ++++++++++++++++++++++++++----------- src/stacked_borrows.rs | 4 +++- 5 files changed, 42 insertions(+), 14 deletions(-) diff --git a/src/eval.rs b/src/eval.rs index 7f07fc1a7db6b..d6e5162edaece 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -199,16 +199,21 @@ pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) -> // Perform the main execution. let res: InterpResult<'_, i64> = (|| { + // Main loop. while ecx.step()? { ecx.process_diagnostics(); } // Read the return code pointer *before* we run TLS destructors, to assert // that it was written to by the time that `start` lang item returned. let return_code = ecx.read_scalar(ret_place.into())?.not_undef()?.to_machine_isize(&ecx)?; + // Global destructors. ecx.run_tls_dtors()?; Ok(return_code) })(); + // Machine cleanup. + EnvVars::cleanup(&mut ecx).unwrap(); + // Process the result. match res { Ok(return_code) => { diff --git a/src/lib.rs b/src/lib.rs index 32eb5b41e5919..0d93becb44825 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,6 +2,8 @@ #![feature(option_expect_none, option_unwrap_none)] #![feature(map_first_last)] #![feature(never_type)] +#![feature(or_patterns)] + #![warn(rust_2018_idioms)] #![allow(clippy::cast_lossless)] diff --git a/src/machine.rs b/src/machine.rs index 73e7ce665b858..a530ef66d384e 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -48,9 +48,13 @@ pub enum MiriMemoryKind { C, /// Windows `HeapAlloc` memory. WinHeap, - /// Memory for env vars and args, errno, extern statics and other parts of the machine-managed environment. + /// Memory for args, errno, extern statics and other parts of the machine-managed environment. + /// This memory may leak. Machine, + /// Memory for env vars. Separate from `Machine` because we clean it up and leak-check it. + Env, /// Globals copied from `tcx`. + /// This memory may leak. Global, } @@ -484,7 +488,7 @@ impl MayLeak for MiriMemoryKind { fn may_leak(self) -> bool { use self::MiriMemoryKind::*; match self { - Rust | C | WinHeap => false, + Rust | C | WinHeap | Env => false, Machine | Global => true, } } diff --git a/src/shims/env.rs b/src/shims/env.rs index ed689b1f4272b..6cde82903bcce 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -46,6 +46,20 @@ impl<'tcx> EnvVars<'tcx> { } ecx.update_environ() } + + pub(crate) fn cleanup<'mir>( + ecx: &mut InterpCx<'mir, 'tcx, Evaluator<'tcx>>, + ) -> InterpResult<'tcx> { + // Deallocate individual env vars. + for (_name, ptr) in ecx.machine.env_vars.map.drain() { + ecx.memory.deallocate(ptr, None, MiriMemoryKind::Env.into())?; + } + // Deallocate environ var list. + let environ = ecx.machine.env_vars.environ.take().unwrap(); + let old_vars_ptr = ecx.read_scalar(environ.into())?.not_undef()?; + ecx.memory.deallocate(ecx.force_ptr(old_vars_ptr)?, None, MiriMemoryKind::Env.into())?; + Ok(()) + } } fn alloc_env_var_as_c_str<'mir, 'tcx>( @@ -56,7 +70,7 @@ fn alloc_env_var_as_c_str<'mir, 'tcx>( let mut name_osstring = name.to_os_string(); name_osstring.push("="); name_osstring.push(value); - Ok(ecx.alloc_os_str_as_c_str(name_osstring.as_os_str(), MiriMemoryKind::Machine.into())) + Ok(ecx.alloc_os_str_as_c_str(name_osstring.as_os_str(), MiriMemoryKind::Env.into())) } fn alloc_env_var_as_wide_str<'mir, 'tcx>( @@ -67,7 +81,7 @@ fn alloc_env_var_as_wide_str<'mir, 'tcx>( let mut name_osstring = name.to_os_string(); name_osstring.push("="); name_osstring.push(value); - Ok(ecx.alloc_os_str_as_wide_str(name_osstring.as_os_str(), MiriMemoryKind::Machine.into())) + Ok(ecx.alloc_os_str_as_wide_str(name_osstring.as_os_str(), MiriMemoryKind::Env.into())) } impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} @@ -146,7 +160,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // Allocate environment block & Store environment variables to environment block. // Final null terminator(block terminator) is added by `alloc_os_str_to_wide_str`. - // FIXME: MemoryKind should be `Machine`, blocked on https://github.com/rust-lang/rust/pull/70479. + // FIXME: MemoryKind should be `Env`, blocked on https://github.com/rust-lang/rust/pull/70479. let envblock_ptr = this.alloc_os_str_as_wide_str(&env_vars, MiriMemoryKind::WinHeap.into()); // If the function succeeds, the return value is a pointer to the environment block of the current process. Ok(envblock_ptr.into()) @@ -158,7 +172,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.assert_target_os("windows", "FreeEnvironmentStringsW"); let env_block_ptr = this.read_scalar(env_block_op)?.not_undef()?; - // FIXME: MemoryKind should be `Machine`, blocked on https://github.com/rust-lang/rust/pull/70479. + // FIXME: MemoryKind should be `Env`, blocked on https://github.com/rust-lang/rust/pull/70479. let result = this.memory.deallocate(this.force_ptr(env_block_ptr)?, None, MiriMemoryKind::WinHeap.into()); // If the function succeeds, the return value is nonzero. Ok(result.is_ok() as i32) @@ -188,7 +202,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let var_ptr = alloc_env_var_as_c_str(&name, &value, &mut this)?; if let Some(var) = this.machine.env_vars.map.insert(name, var_ptr) { this.memory - .deallocate(var, None, MiriMemoryKind::Machine.into())?; + .deallocate(var, None, MiriMemoryKind::Env.into())?; } this.update_environ()?; Ok(0) // return zero on success @@ -225,7 +239,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } else if this.is_null(value_ptr)? { // Delete environment variable `{name}` if let Some(var) = this.machine.env_vars.map.remove(&name) { - this.memory.deallocate(var, None, MiriMemoryKind::Machine.into())?; + this.memory.deallocate(var, None, MiriMemoryKind::Env.into())?; this.update_environ()?; } Ok(1) // return non-zero on success @@ -234,7 +248,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let var_ptr = alloc_env_var_as_wide_str(&name, &value, &mut this)?; if let Some(var) = this.machine.env_vars.map.insert(name, var_ptr) { this.memory - .deallocate(var, None, MiriMemoryKind::Machine.into())?; + .deallocate(var, None, MiriMemoryKind::Env.into())?; } this.update_environ()?; Ok(1) // return non-zero on success @@ -257,7 +271,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if let Some(old) = success { if let Some(var) = old { this.memory - .deallocate(var, None, MiriMemoryKind::Machine.into())?; + .deallocate(var, None, MiriMemoryKind::Env.into())?; } this.update_environ()?; Ok(0) @@ -314,12 +328,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// The first time it gets called, also initializes `extra.environ`. fn update_environ(&mut self) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - // Deallocate the old environ value, if any. + // Deallocate the old environ list, if any. if let Some(environ) = this.machine.env_vars.environ { let old_vars_ptr = this.read_scalar(environ.into())?.not_undef()?; - this.memory.deallocate(this.force_ptr(old_vars_ptr)?, None, MiriMemoryKind::Machine.into())?; + this.memory.deallocate(this.force_ptr(old_vars_ptr)?, None, MiriMemoryKind::Env.into())?; } else { // No `environ` allocated yet, let's do that. + // This is memory backing an extern static, hence `Machine`, not `Env`. let layout = this.layout_of(this.tcx.types.usize)?; let place = this.allocate(layout, MiriMemoryKind::Machine.into()); this.write_scalar(Scalar::from_machine_usize(0, &*this.tcx), place.into())?; @@ -334,7 +349,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let tcx = this.tcx; let vars_layout = this.layout_of(tcx.mk_array(tcx.types.usize, u64::try_from(vars.len()).unwrap()))?; - let vars_place = this.allocate(vars_layout, MiriMemoryKind::Machine.into()); + let vars_place = this.allocate(vars_layout, MiriMemoryKind::Env.into()); for (idx, var) in vars.into_iter().enumerate() { let place = this.mplace_field(vars_place, idx)?; this.write_scalar(var, place.into())?; diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 11b6cdca579af..c130abf0576be 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -460,8 +460,10 @@ impl Stacks { // Global memory can be referenced by global pointers from `tcx`. // Thus we call `global_base_ptr` such that the global pointers get the same tag // as what we use here. + // `Machine` is used for extern statics, and thus must also be listed here. + // `Env` we list because we can get away with precise tracking there. // The base pointer is not unique, so the base permission is `SharedReadWrite`. - MemoryKind::Machine(MiriMemoryKind::Global) | MemoryKind::Machine(MiriMemoryKind::Machine) => + MemoryKind::Machine(MiriMemoryKind::Global | MiriMemoryKind::Machine | MiriMemoryKind::Env) => (extra.borrow_mut().global_base_ptr(id), Permission::SharedReadWrite), // Everything else we handle entirely untagged for now. // FIXME: experiment with more precise tracking. From 9e39bfbbd93a98980fd2371970cc1005420d66df Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 26 Mar 2020 11:41:31 +0100 Subject: [PATCH 1736/3747] organize shims and make some only available to libstd as they are incomplete --- src/helpers.rs | 1 + src/shims/foreign_items.rs | 17 +-- src/shims/foreign_items/posix.rs | 149 ++++++++++--------------- src/shims/foreign_items/posix/linux.rs | 56 ++++++---- src/shims/foreign_items/posix/macos.rs | 51 ++++----- src/shims/foreign_items/windows.rs | 115 +++++++++++-------- 6 files changed, 193 insertions(+), 196 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index aa327b468bf81..8e379065b07eb 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -81,6 +81,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// Helper function to get a `libc` constant as an `i32`. fn eval_libc_i32(&mut self, name: &str) -> InterpResult<'tcx, i32> { + // TODO: Cache the result. self.eval_libc(name)?.to_i32() } diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index ecf24e2f20384..c92e338ef7e02 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -196,6 +196,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Here we dispatch all the shims for foreign functions. If you have a platform specific // shim, add it to the corresponding submodule. match link_name { + // Standard C allocation "malloc" => { let size = this.read_scalar(args[0])?.to_machine_usize(this)?; let res = this.malloc(size, /*zero_init:*/ false, MiriMemoryKind::C); @@ -220,6 +221,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(res, dest)?; } + // Rust allocation + // (Usually these would be forwarded to to `#[global_allocator]`; we instead implement a generic + // allocation that also checks that all conditions are met, such as not permitting zero-sized allocations.) "__rust_alloc" => { let size = this.read_scalar(args[0])?.to_machine_usize(this)?; let align = this.read_scalar(args[1])?.to_machine_usize(this)?; @@ -274,6 +278,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(new_ptr, dest)?; } + // C memory handling functions "memcmp" => { let left = this.read_scalar(args[0])?.not_undef()?; let right = this.read_scalar(args[1])?.not_undef()?; @@ -293,7 +298,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_int(result, Size::from_bits(32)), dest)?; } - "memrchr" => { let ptr = this.read_scalar(args[0])?.not_undef()?; let val = this.read_scalar(args[1])?.to_i32()? as u8; @@ -311,7 +315,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_null(dest)?; } } - "memchr" => { let ptr = this.read_scalar(args[0])?.not_undef()?; let val = this.read_scalar(args[1])?.to_i32()? as u8; @@ -328,7 +331,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_null(dest)?; } } - "strlen" => { let ptr = this.read_scalar(args[0])?.not_undef()?; let n = this.memory.read_c_str(ptr)?.len(); @@ -358,11 +360,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx }; this.write_scalar(Scalar::from_u32(f.to_bits()), dest)?; } - // underscore case for windows | "_hypotf" | "hypotf" | "atan2f" => { + // underscore case for windows, here and below + // (see https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/floating-point-primitives?view=vs-2019) // FIXME: Using host floats. let f1 = f32::from_bits(this.read_scalar(args[0])?.to_u32()?); let f2 = f32::from_bits(this.read_scalar(args[1])?.to_u32()?); @@ -373,7 +376,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx }; this.write_scalar(Scalar::from_u32(n.to_bits()), dest)?; } - | "cbrt" | "cosh" | "sinh" @@ -396,8 +398,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx }; this.write_scalar(Scalar::from_u64(f.to_bits()), dest)?; } - // underscore case for windows, here and below - // (see https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/floating-point-primitives?view=vs-2019) | "_hypot" | "hypot" | "atan2" @@ -412,11 +412,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx }; this.write_scalar(Scalar::from_u64(n.to_bits()), dest)?; } - // For radix-2 (binary) systems, `ldexp` and `scalbn` are the same. | "_ldexp" | "ldexp" | "scalbn" => { + // For radix-2 (binary) systems, `ldexp` and `scalbn` are the same. let x = this.read_scalar(args[0])?.to_f64()?; let exp = this.read_scalar(args[1])?.to_i32()?; @@ -434,6 +434,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_f64(res), dest)?; } + // Target-specific shims _ => match this.tcx.sess.target.target.target_os.as_str() { "linux" | "macos" => return posix::EvalContextExt::emulate_foreign_item_by_name(this, link_name, args, dest, ret), "windows" => return windows::EvalContextExt::emulate_foreign_item_by_name(this, link_name, args, dest, ret), diff --git a/src/shims/foreign_items/posix.rs b/src/shims/foreign_items/posix.rs index 425fe4b1b479a..9d331eece5030 100644 --- a/src/shims/foreign_items/posix.rs +++ b/src/shims/foreign_items/posix.rs @@ -24,22 +24,18 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let result = this.getenv(args[0])?; this.write_scalar(result, dest)?; } - "unsetenv" => { let result = this.unsetenv(args[0])?; this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; } - "setenv" => { let result = this.setenv(args[0], args[1])?; this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; } - "getcwd" => { let result = this.getcwd(args[0], args[1])?; this.write_scalar(result, dest)?; } - "chdir" => { let result = this.chdir(args[0])?; this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; @@ -50,17 +46,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let result = this.open(args[0], args[1])?; this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; } - "fcntl" => { let result = this.fcntl(args[0], args[1], args.get(2).cloned())?; this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; } - "read" => { let result = this.read(args[0], args[1], args[2])?; this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; } - "write" => { let fd = this.read_scalar(args[0])?.to_i32()?; let buf = this.read_scalar(args[1])?.not_undef()?; @@ -94,43 +87,40 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Now, `result` is the value we return back to the program. this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; } - "unlink" => { let result = this.unlink(args[0])?; this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; } - "symlink" => { let result = this.symlink(args[0], args[1])?; this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; } - "rename" => { let result = this.rename(args[0], args[1])?; this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; } - "mkdir" => { let result = this.mkdir(args[0], args[1])?; this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; } - "rmdir" => { let result = this.rmdir(args[0])?; this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; } - "closedir" => { let result = this.closedir(args[0])?; this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; } - "lseek" | "lseek64" => { let result = this.lseek64(args[0], args[1], args[2])?; this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; } + "posix_fadvise" => { + // fadvise is only informational, we can ignore it. + this.write_null(dest)?; + } - // Other shims + // Allocation "posix_memalign" => { let ret = this.deref_operand(args[0])?; let align = this.read_scalar(args[1])?.to_machine_usize(this)?; @@ -159,6 +149,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_null(dest)?; } + // Dynamic symbol loading "dlsym" => { let _handle = this.read_scalar(args[0])?; let symbol = this.read_scalar(args[1])?.not_undef()?; @@ -173,7 +164,30 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } - // Hook pthread calls that go to the thread-local storage memory subsystem. + // Querying system information + "sysconf" => { + let name = this.read_scalar(args[0])?.to_i32()?; + + let sysconfs = &[ + ("_SC_PAGESIZE", Scalar::from_int(PAGE_SIZE, dest.layout.size)), + ("_SC_NPROCESSORS_ONLN", Scalar::from_int(NUM_CPUS, dest.layout.size)), + ]; + let mut result = None; + for &(sysconf_name, value) in sysconfs { + let sysconf_name = this.eval_libc_i32(sysconf_name)?; + if sysconf_name == name { + result = Some(value); + break; + } + } + if let Some(result) = result { + this.write_scalar(result, dest)?; + } else { + throw_unsup_format!("unimplemented sysconf name: {}", name) + } + } + + // Thread-local storage "pthread_key_create" => { let key_place = this.deref_operand(args[0])?; @@ -220,36 +234,36 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_null(dest)?; } - // Stack size/address stuff. - | "pthread_attr_init" - | "pthread_attr_destroy" - | "pthread_self" - | "pthread_attr_setstacksize" => { - this.write_null(dest)?; + // Better error for attempts to create a thread + "pthread_create" => { + throw_unsup_format!("Miri does not support threading"); } - "pthread_attr_getstack" => { - let addr_place = this.deref_operand(args[1])?; - let size_place = this.deref_operand(args[2])?; - - this.write_scalar( - Scalar::from_uint(STACK_ADDR, addr_place.layout.size), - addr_place.into(), - )?; - this.write_scalar( - Scalar::from_uint(STACK_SIZE, size_place.layout.size), - size_place.into(), - )?; - // Return success (`0`). + // Miscellaneous + "isatty" => { + let _fd = this.read_scalar(args[0])?.to_i32()?; + // "returns 1 if fd is an open file descriptor referring to a terminal; otherwise 0 is returned, and errno is set to indicate the error" + // FIXME: we just say nothing is a terminal. + let enotty = this.eval_libc("ENOTTY")?; + this.set_last_error(enotty)?; this.write_null(dest)?; } - - // We don't support threading. - "pthread_create" => { - throw_unsup_format!("Miri does not support threading"); + "pthread_atfork" => { + let _prepare = this.read_scalar(args[0])?.not_undef()?; + let _parent = this.read_scalar(args[1])?.not_undef()?; + let _child = this.read_scalar(args[1])?.not_undef()?; + // We do not support forking, so there is nothing to do here. + this.write_null(dest)?; } - // Stub out calls for condvar, mutex and rwlock, to just return `0`. + // Incomplete shims that we "stub out" just to get pre-main initialziation code to work. + // These shims are enabled only when the caller is in the standard library. + | "pthread_attr_init" + | "pthread_attr_destroy" + | "pthread_self" + | "pthread_attr_setstacksize" if this.frame().instance.to_string().starts_with("std::sys::unix::") => { + this.write_null(dest)?; + } | "pthread_mutexattr_init" | "pthread_mutexattr_settype" | "pthread_mutex_init" @@ -265,68 +279,19 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "pthread_condattr_setclock" | "pthread_cond_init" | "pthread_condattr_destroy" - | "pthread_cond_destroy" + | "pthread_cond_destroy" if this.frame().instance.to_string().starts_with("std::sys::unix::") => { this.write_null(dest)?; } - - // We don't support fork so we don't have to do anything for atfork. - "pthread_atfork" => { - this.write_null(dest)?; - } - - // Some things needed for `sys::thread` initialization to go through. | "signal" | "sigaction" | "sigaltstack" + | "mprotect" if this.frame().instance.to_string().starts_with("std::sys::unix::") => { - this.write_scalar(Scalar::from_int(0, dest.layout.size), dest)?; - } - - "sysconf" => { - let name = this.read_scalar(args[0])?.to_i32()?; - - trace!("sysconf() called with name {}", name); - // TODO: Cache the sysconf integers via Miri's global cache. - let sysconfs = &[ - ("_SC_PAGESIZE", Scalar::from_int(PAGE_SIZE, dest.layout.size)), - ("_SC_GETPW_R_SIZE_MAX", Scalar::from_int(-1, dest.layout.size)), - ("_SC_NPROCESSORS_ONLN", Scalar::from_int(NUM_CPUS, dest.layout.size)), - ]; - let mut result = None; - for &(sysconf_name, value) in sysconfs { - let sysconf_name = this.eval_libc_i32(sysconf_name)?; - if sysconf_name == name { - result = Some(value); - break; - } - } - if let Some(result) = result { - this.write_scalar(result, dest)?; - } else { - throw_unsup_format!("unimplemented sysconf name: {}", name) - } - } - - "isatty" => { - this.write_null(dest)?; - } - - "posix_fadvise" => { - // fadvise is only informational, we can ignore it. - this.write_null(dest)?; - } - - "mmap" => { - // This is a horrible hack, but since the guard page mechanism calls mmap and expects a particular return value, we just give it that value. - let addr = this.read_scalar(args[0])?.not_undef()?; - this.write_scalar(addr, dest)?; - } - - "mprotect" => { this.write_null(dest)?; } + // Platform-specific shims _ => { match this.tcx.sess.target.target.target_os.as_str() { "linux" => return linux::EvalContextExt::emulate_foreign_item_by_name(this, link_name, args, dest, ret), diff --git a/src/shims/foreign_items/posix/linux.rs b/src/shims/foreign_items/posix/linux.rs index 82928c9bc17ff..1a8cd195ec5bc 100644 --- a/src/shims/foreign_items/posix/linux.rs +++ b/src/shims/foreign_items/posix/linux.rs @@ -13,47 +13,56 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); match link_name { + // errno "__errno_location" => { let errno_place = this.machine.last_error.unwrap(); this.write_scalar(errno_place.to_ref().to_scalar()?, dest)?; } // File related shims (but also see "syscall" below for statx) - - // The only reason this is not in the `posix` module is because the `macos` item has a - // different name. + // These symbols have different names on Linux and macOS, which is the only reason they are not + // in the `posix` module. "close" => { let result = this.close(args[0])?; this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; } - - // The only reason this is not in the `posix` module is because the `macos` item has a - // different name. "opendir" => { let result = this.opendir(args[0])?; this.write_scalar(result, dest)?; } - - // The `macos` module has a parallel foreign item, `readdir_r`, which uses a different - // struct layout. "readdir64_r" => { let result = this.linux_readdir64_r(args[0], args[1], args[2])?; this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; } // Time related shims - - // This is a POSIX function but it has only been tested on linux. "clock_gettime" => { + // This is a POSIX function but it has only been tested on linux. let result = this.clock_gettime(args[0], args[1])?; this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; } - // Other shims - "pthread_getattr_np" => { + // Querying system information + "pthread_attr_getstack" => { + // We don't support "pthread_attr_setstack", so we just pretend all stacks have the same values here. + let _attr_place = this.deref_operand(args[0])?; + let addr_place = this.deref_operand(args[1])?; + let size_place = this.deref_operand(args[2])?; + + this.write_scalar( + Scalar::from_uint(STACK_ADDR, addr_place.layout.size), + addr_place.into(), + )?; + this.write_scalar( + Scalar::from_uint(STACK_SIZE, size_place.layout.size), + size_place.into(), + )?; + + // Return success (`0`). this.write_null(dest)?; } + // Dynamically invoked syscalls "syscall" => { let sys_getrandom = this .eval_libc("SYS_getrandom")? @@ -67,15 +76,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // `libc::syscall(NR_GETRANDOM, buf.as_mut_ptr(), buf.len(), GRND_NONBLOCK)` // is called if a `HashMap` is created the regular way (e.g. HashMap). id if id == sys_getrandom => { - // The first argument is the syscall id, - // so skip over it. + // The first argument is the syscall id, so skip over it. getrandom(this, &args[1..], dest)?; } // `statx` is used by `libstd` to retrieve metadata information on `linux` // instead of using `stat`,`lstat` or `fstat` as on `macos`. id if id == sys_statx => { - // The first argument is the syscall id, - // so skip over it. + // The first argument is the syscall id, so skip over it. let result = this.linux_statx(args[1], args[2], args[3], args[4], args[5])?; this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; } @@ -83,15 +90,26 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } + // Miscelanneous "getrandom" => { getrandom(this, args, dest)?; } - "sched_getaffinity" => { - // Return an error; `num_cpus` then falls back to `sysconf`. + let _pid = this.read_scalar(args[0])?.to_i32()?; + let _cpusetsize = this.read_scalar(args[1])?.to_machine_usize(this)?; + let _mask = this.deref_operand(args[2])?; + // FIXME: we just return an error; `num_cpus` then falls back to `sysconf`. + let einval = this.eval_libc("EINVAL")?; + this.set_last_error(einval)?; this.write_scalar(Scalar::from_int(-1, dest.layout.size), dest)?; } + // Incomplete shims that we "stub out" just to get pre-main initialziation code to work. + // These shims are enabled only when the caller is in the standard library. + "pthread_getattr_np" if this.frame().instance.to_string().starts_with("std::sys::unix::") => { + this.write_null(dest)?; + } + _ => throw_unsup_format!("can't call foreign function: {}", link_name), }; diff --git a/src/shims/foreign_items/posix/macos.rs b/src/shims/foreign_items/posix/macos.rs index 325be877d0443..2261b1c4cfb97 100644 --- a/src/shims/foreign_items/posix/macos.rs +++ b/src/shims/foreign_items/posix/macos.rs @@ -13,44 +13,33 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); match link_name { + // errno "__error" => { let errno_place = this.machine.last_error.unwrap(); this.write_scalar(errno_place.to_ref().to_scalar()?, dest)?; } // File related shims - - // The only reason this is not in the `posix` module is because the `linux` item has a - // different name. "close$NOCANCEL" => { let result = this.close(args[0])?; this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; } - "stat$INODE64" => { let result = this.macos_stat(args[0], args[1])?; this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; } - "lstat$INODE64" => { let result = this.macos_lstat(args[0], args[1])?; this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; } - "fstat$INODE64" => { let result = this.macos_fstat(args[0], args[1])?; this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; } - - // The only reason this is not in the `posix` module is because the `linux` item has a - // different name. "opendir$INODE64" => { let result = this.opendir(args[0])?; this.write_scalar(result, dest)?; } - - // The `linux` module has a parallel foreign item, `readdir64_r`, which uses a - // different struct layout. "readdir_r$INODE64" => { let result = this.macos_readdir_r(args[0], args[1], args[2])?; this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; @@ -71,21 +60,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_uint(result, dest.layout.size), dest)?; } - // Other shims - "pthread_attr_get_np" => { - this.write_null(dest)?; - } - - "pthread_get_stackaddr_np" => { - let stack_addr = Scalar::from_uint(STACK_ADDR, dest.layout.size); - this.write_scalar(stack_addr, dest)?; + // Access to command-line arguments + "_NSGetArgc" => { + this.write_scalar(this.machine.argc.expect("machine must be initialized"), dest)?; } - - "pthread_get_stacksize_np" => { - let stack_size = Scalar::from_uint(STACK_SIZE, dest.layout.size); - this.write_scalar(stack_size, dest)?; + "_NSGetArgv" => { + this.write_scalar(this.machine.argv.expect("machine must be initialized"), dest)?; } + // Thread-local storage "_tlv_atexit" => { let dtor = this.read_scalar(args[0])?.not_undef()?; let dtor = this.memory.get_fn(dtor)?.as_instance()?; @@ -93,12 +76,24 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.machine.tls.set_global_dtor(dtor, data)?; } - "_NSGetArgc" => { - this.write_scalar(this.machine.argc.expect("machine must be initialized"), dest)?; + // Querying system information + "pthread_get_stackaddr_np" => { + let _thread = this.read_scalar(args[0])?.not_undef()?; + let stack_addr = Scalar::from_uint(STACK_ADDR, dest.layout.size); + this.write_scalar(stack_addr, dest)?; + } + "pthread_get_stacksize_np" => { + let _thread = this.read_scalar(args[0])?.not_undef()?; + let stack_size = Scalar::from_uint(STACK_SIZE, dest.layout.size); + this.write_scalar(stack_size, dest)?; } - "_NSGetArgv" => { - this.write_scalar(this.machine.argv.expect("machine must be initialized"), dest)?; + // Incomplete shims that we "stub out" just to get pre-main initialziation code to work. + // These shims are enabled only when the caller is in the standard library. + "mmap" if this.frame().instance.to_string().starts_with("std::sys::unix::") => { + // This is a horrible hack, but since the guard page mechanism calls mmap and expects a particular return value, we just give it that value. + let addr = this.read_scalar(args[0])?.not_undef()?; + this.write_scalar(addr, dest)?; } _ => throw_unsup_format!("can't call foreign function: {}", link_name), diff --git a/src/shims/foreign_items/windows.rs b/src/shims/foreign_items/windows.rs index 9e71ba7d90741..9a626fe75e03e 100644 --- a/src/shims/foreign_items/windows.rs +++ b/src/shims/foreign_items/windows.rs @@ -14,12 +14,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, bool> { let this = self.eval_context_mut(); + // Windows API stubs. + // HANDLE = isize + // DWORD = ULONG = u32 + // BOOL = i32 match link_name { - // Windows API stubs. - // HANDLE = isize - // DWORD = ULONG = u32 - // BOOL = i32 - // Environment related shims "GetEnvironmentVariableW" => { let result = this.GetEnvironmentVariableW(args[0], args[1], args[2])?; @@ -42,6 +41,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // File related shims + "GetStdHandle" => { + let which = this.read_scalar(args[0])?.to_i32()?; + // We just make this the identity function, so we know later in `WriteFile` + // which one it is. + this.write_scalar(Scalar::from_int(which, this.pointer_size()), dest)?; + } "WriteFile" => { let handle = this.read_scalar(args[0])?.to_machine_isize(this)?; let buf = this.read_scalar(args[1])?.not_undef()?; @@ -61,9 +66,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx }; res.ok().map(|n| n as u32) } else { - eprintln!("Miri: Ignored output to handle {}", handle); - // Pretend it all went well. - Some(n) + throw_unsup_format!("on Windows, writing to anything except stdout/stderr is not supported") }; // If there was no error, write back how much was written. if let Some(n) = written { @@ -76,11 +79,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx )?; } - // Other shims - "GetProcessHeap" => { - // Just fake a HANDLE - this.write_scalar(Scalar::from_int(1, this.pointer_size()), dest)?; - } + // Allocation "HeapAlloc" => { let _handle = this.read_scalar(args[0])?.to_machine_isize(this)?; let flags = this.read_scalar(args[1])?.to_u32()?; @@ -105,6 +104,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(res, dest)?; } + // errno "SetLastError" => { this.set_last_error(this.read_scalar(args[0])?.not_undef()?)?; } @@ -113,30 +113,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(last_error, dest)?; } - "AddVectoredExceptionHandler" => { - // Any non zero value works for the stdlib. This is just used for stack overflows anyway. - this.write_scalar(Scalar::from_int(1, dest.layout.size), dest)?; - } - - | "InitializeCriticalSection" - | "EnterCriticalSection" - | "LeaveCriticalSection" - | "DeleteCriticalSection" - => { - // Nothing to do, not even a return value. - // (Windows locks are reentrant, and we have only 1 thread, - // so not doing any futher checks here is at least not incorrect.) - } - - | "GetModuleHandleW" - | "GetProcAddress" - | "GetConsoleScreenBufferInfo" - | "SetConsoleTextAttribute" - => { - // Pretend these do not exist / nothing happened, by returning zero. - this.write_null(dest)?; - } - + // Querying system information "GetSystemInfo" => { let system_info = this.deref_operand(args[0])?; // Initialize with `0`. @@ -150,6 +127,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_int(NUM_CPUS, dword_size), num_cpus.into())?; } + // Thread-local storage "TlsAlloc" => { // This just creates a key; Windows does not natively support TLS destructors. @@ -170,33 +148,72 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Return success (`1`). this.write_scalar(Scalar::from_int(1, dest.layout.size), dest)?; } - "GetStdHandle" => { - let which = this.read_scalar(args[0])?.to_i32()?; - // We just make this the identity function, so we know later in `WriteFile` - // which one it is. - this.write_scalar(Scalar::from_int(which, this.pointer_size()), dest)?; - } - "GetConsoleMode" => { - // Everything is a pipe. - this.write_null(dest)?; - } + + // Access to command-line arguments "GetCommandLineW" => { this.write_scalar( this.machine.cmd_line.expect("machine must be initialized"), dest, )?; } - // The actual name of 'RtlGenRandom' + + // Miscellaneous "SystemFunction036" => { + // The actual name of 'RtlGenRandom' let ptr = this.read_scalar(args[0])?.not_undef()?; let len = this.read_scalar(args[1])?.to_u32()?; this.gen_random(ptr, len.into())?; this.write_scalar(Scalar::from_bool(true), dest)?; } - // We don't support threading. + "GetConsoleScreenBufferInfo" => { + // `term` needs this, so we fake it. + let _console = this.read_scalar(args[0])?.to_machine_isize(this)?; + let _buffer_info = this.deref_operand(args[1])?; + // Indicate an error. + // FIXME: we should set last_error, but to what? + this.write_null(dest)?; + } + "GetConsoleMode" => { + // Windows "isatty" (in libtest) needs this, so we fake it. + let _console = this.read_scalar(args[0])?.to_machine_isize(this)?; + let _mode = this.deref_operand(args[1])?; + // Indicate an error. + // FIXME: we should set last_error, but to what? + this.write_null(dest)?; + } + + // Better error for attempts to create a thread "CreateThread" => { throw_unsup_format!("Miri does not support threading"); } + + // Incomplete shims that we "stub out" just to get pre-main initialziation code to work. + // These shims are enabled only when the caller is in the standard library. + "GetProcessHeap" if this.frame().instance.to_string().starts_with("std::sys::windows::") => { + // Just fake a HANDLE + this.write_scalar(Scalar::from_int(1, this.pointer_size()), dest)?; + } + | "GetModuleHandleW" + | "GetProcAddress" + | "SetConsoleTextAttribute" if this.frame().instance.to_string().starts_with("std::sys::windows::") + => { + // Pretend these do not exist / nothing happened, by returning zero. + this.write_null(dest)?; + } + "AddVectoredExceptionHandler" if this.frame().instance.to_string().starts_with("std::sys::windows::") => { + // Any non zero value works for the stdlib. This is just used for stack overflows anyway. + this.write_scalar(Scalar::from_int(1, dest.layout.size), dest)?; + } + | "InitializeCriticalSection" + | "EnterCriticalSection" + | "LeaveCriticalSection" + | "DeleteCriticalSection" if this.frame().instance.to_string().starts_with("std::sys::windows::") + => { + // Nothing to do, not even a return value. + // (Windows locks are reentrant, and we have only 1 thread, + // so not doing any futher checks here is at least not incorrect.) + } + _ => throw_unsup_format!("can't call foreign function: {}", link_name), } From 6ab82f5d35d8505f2e65eebeed56d7eeb62d754e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 28 Mar 2020 11:33:56 +0100 Subject: [PATCH 1737/3747] posix_fadvise is Linux-only; also validate arguments a bit --- src/shims/foreign_items/posix.rs | 4 ---- src/shims/foreign_items/posix/linux.rs | 9 +++++++++ 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/shims/foreign_items/posix.rs b/src/shims/foreign_items/posix.rs index 9d331eece5030..ce23bc4c972f6 100644 --- a/src/shims/foreign_items/posix.rs +++ b/src/shims/foreign_items/posix.rs @@ -115,10 +115,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let result = this.lseek64(args[0], args[1], args[2])?; this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; } - "posix_fadvise" => { - // fadvise is only informational, we can ignore it. - this.write_null(dest)?; - } // Allocation "posix_memalign" => { diff --git a/src/shims/foreign_items/posix/linux.rs b/src/shims/foreign_items/posix/linux.rs index 1a8cd195ec5bc..88a18e3e75f97 100644 --- a/src/shims/foreign_items/posix/linux.rs +++ b/src/shims/foreign_items/posix/linux.rs @@ -34,6 +34,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let result = this.linux_readdir64_r(args[0], args[1], args[2])?; this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; } + // Linux-only + "posix_fadvise" => { + let _fd = this.read_scalar(args[0])?.to_i32()?; + let _offset = this.read_scalar(args[1])?.to_machine_isize(this)?; + let _len = this.read_scalar(args[2])?.to_machine_isize(this)?; + let _advice = this.read_scalar(args[3])?.to_i32()?; + // fadvise is only informational, we can ignore it. + this.write_null(dest)?; + } // Time related shims "clock_gettime" => { From a6cab24dc057f87dce7cd3134a096725fc31d556 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 28 Mar 2020 14:32:50 +0100 Subject: [PATCH 1738/3747] we don't deallocate the environ global, so leave it in the machine --- src/shims/env.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shims/env.rs b/src/shims/env.rs index 6cde82903bcce..163a8c2e51d78 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -55,7 +55,7 @@ impl<'tcx> EnvVars<'tcx> { ecx.memory.deallocate(ptr, None, MiriMemoryKind::Env.into())?; } // Deallocate environ var list. - let environ = ecx.machine.env_vars.environ.take().unwrap(); + let environ = ecx.machine.env_vars.environ.unwrap(); let old_vars_ptr = ecx.read_scalar(environ.into())?.not_undef()?; ecx.memory.deallocate(ecx.force_ptr(old_vars_ptr)?, None, MiriMemoryKind::Env.into())?; Ok(()) From 99600ba7a9820bdaaa252a9b346f87642cd24ca3 Mon Sep 17 00:00:00 2001 From: JOE1994 Date: Sat, 28 Mar 2020 10:43:47 -0400 Subject: [PATCH 1739/3747] move OsStr helpers to a separate file --- src/helpers.rs | 241 +----------------------------------------- src/lib.rs | 1 + src/shims/mod.rs | 1 + src/shims/os_str.rs | 247 ++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 250 insertions(+), 240 deletions(-) create mode 100644 src/shims/os_str.rs diff --git a/src/helpers.rs b/src/helpers.rs index 3e89fdf6f3cce..e22839d9870aa 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -1,13 +1,5 @@ -use std::ffi::{OsStr, OsString}; -use std::path::{Path, PathBuf}; -use std::{iter, mem}; use std::convert::TryFrom; -use std::borrow::Cow; - -#[cfg(unix)] -use std::os::unix::ffi::{OsStrExt, OsStringExt}; -#[cfg(windows)] -use std::os::windows::ffi::{OsStrExt, OsStringExt}; +use std::mem; use rustc::mir; use rustc::ty::{ @@ -462,237 +454,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } } - - /// Helper function to read an OsString from a null-terminated sequence of bytes, which is what - /// the Unix APIs usually handle. - fn read_os_str_from_c_str<'a>(&'a self, scalar: Scalar) -> InterpResult<'tcx, &'a OsStr> - where - 'tcx: 'a, - 'mir: 'a, - { - #[cfg(unix)] - fn bytes_to_os_str<'tcx, 'a>(bytes: &'a [u8]) -> InterpResult<'tcx, &'a OsStr> { - Ok(OsStr::from_bytes(bytes)) - } - #[cfg(not(unix))] - fn bytes_to_os_str<'tcx, 'a>(bytes: &'a [u8]) -> InterpResult<'tcx, &'a OsStr> { - let s = std::str::from_utf8(bytes) - .map_err(|_| err_unsup_format!("{:?} is not a valid utf-8 string", bytes))?; - Ok(OsStr::new(s)) - } - - let this = self.eval_context_ref(); - let bytes = this.memory.read_c_str(scalar)?; - bytes_to_os_str(bytes) - } - - /// Helper function to read an OsString from a 0x0000-terminated sequence of u16, - /// which is what the Windows APIs usually handle. - fn read_os_str_from_wide_str<'a>(&'a self, scalar: Scalar) -> InterpResult<'tcx, OsString> - where - 'tcx: 'a, - 'mir: 'a, - { - #[cfg(windows)] - pub fn u16vec_to_osstring<'tcx, 'a>(u16_vec: Vec) -> InterpResult<'tcx, OsString> { - Ok(OsString::from_wide(&u16_vec[..])) - } - #[cfg(not(windows))] - pub fn u16vec_to_osstring<'tcx, 'a>(u16_vec: Vec) -> InterpResult<'tcx, OsString> { - let s = String::from_utf16(&u16_vec[..]) - .map_err(|_| err_unsup_format!("{:?} is not a valid utf-16 string", u16_vec))?; - Ok(s.into()) - } - - let u16_vec = self.eval_context_ref().memory.read_wide_str(scalar)?; - u16vec_to_osstring(u16_vec) - } - - /// Helper function to write an OsStr as a null-terminated sequence of bytes, which is what - /// the Unix APIs usually handle. This function returns `Ok((false, length))` without trying - /// to write if `size` is not large enough to fit the contents of `os_string` plus a null - /// terminator. It returns `Ok((true, length))` if the writing process was successful. The - /// string length returned does not include the null terminator. - fn write_os_str_to_c_str( - &mut self, - os_str: &OsStr, - scalar: Scalar, - size: u64, - ) -> InterpResult<'tcx, (bool, u64)> { - #[cfg(unix)] - fn os_str_to_bytes<'tcx, 'a>(os_str: &'a OsStr) -> InterpResult<'tcx, &'a [u8]> { - Ok(os_str.as_bytes()) - } - #[cfg(not(unix))] - fn os_str_to_bytes<'tcx, 'a>(os_str: &'a OsStr) -> InterpResult<'tcx, &'a [u8]> { - // On non-unix platforms the best we can do to transform bytes from/to OS strings is to do the - // intermediate transformation into strings. Which invalidates non-utf8 paths that are actually - // valid. - os_str - .to_str() - .map(|s| s.as_bytes()) - .ok_or_else(|| err_unsup_format!("{:?} is not a valid utf-8 string", os_str).into()) - } - - let bytes = os_str_to_bytes(os_str)?; - // If `size` is smaller or equal than `bytes.len()`, writing `bytes` plus the required null - // terminator to memory using the `ptr` pointer would cause an out-of-bounds access. - let string_length = u64::try_from(bytes.len()).unwrap(); - if size <= string_length { - return Ok((false, string_length)); - } - self.eval_context_mut() - .memory - .write_bytes(scalar, bytes.iter().copied().chain(iter::once(0u8)))?; - Ok((true, string_length)) - } - - /// Helper function to write an OsStr as a 0x0000-terminated u16-sequence, which is what - /// the Windows APIs usually handle. This function returns `Ok((false, length))` without trying - /// to write if `size` is not large enough to fit the contents of `os_string` plus a null - /// terminator. It returns `Ok((true, length))` if the writing process was successful. The - /// string length returned does not include the null terminator. - fn write_os_str_to_wide_str( - &mut self, - os_str: &OsStr, - scalar: Scalar, - size: u64, - ) -> InterpResult<'tcx, (bool, u64)> { - #[cfg(windows)] - fn os_str_to_u16vec<'tcx>(os_str: &OsStr) -> InterpResult<'tcx, Vec> { - Ok(os_str.encode_wide().collect()) - } - #[cfg(not(windows))] - fn os_str_to_u16vec<'tcx>(os_str: &OsStr) -> InterpResult<'tcx, Vec> { - // On non-Windows platforms the best we can do to transform Vec from/to OS strings is to do the - // intermediate transformation into strings. Which invalidates non-utf8 paths that are actually - // valid. - os_str - .to_str() - .map(|s| s.encode_utf16().collect()) - .ok_or_else(|| err_unsup_format!("{:?} is not a valid utf-8 string", os_str).into()) - } - - let u16_vec = os_str_to_u16vec(os_str)?; - // If `size` is smaller or equal than `bytes.len()`, writing `bytes` plus the required - // 0x0000 terminator to memory would cause an out-of-bounds access. - let string_length = u64::try_from(u16_vec.len()).unwrap(); - if size <= string_length { - return Ok((false, string_length)); - } - - // Store the UTF-16 string. - self.eval_context_mut() - .memory - .write_u16s(scalar, u16_vec.into_iter().chain(iter::once(0x0000)))?; - Ok((true, string_length)) - } - - /// Allocate enough memory to store the given `OsStr` as a null-terminated sequence of bytes. - fn alloc_os_str_as_c_str( - &mut self, - os_str: &OsStr, - memkind: MemoryKind, - ) -> Pointer { - let size = u64::try_from(os_str.len()).unwrap().checked_add(1).unwrap(); // Make space for `0` terminator. - let this = self.eval_context_mut(); - - let arg_type = this.tcx.mk_array(this.tcx.types.u8, size); - let arg_place = this.allocate(this.layout_of(arg_type).unwrap(), memkind); - assert!(self.write_os_str_to_c_str(os_str, arg_place.ptr, size).unwrap().0); - arg_place.ptr.assert_ptr() - } - - /// Allocate enough memory to store the given `OsStr` as a null-terminated sequence of `u16`. - fn alloc_os_str_as_wide_str( - &mut self, - os_str: &OsStr, - memkind: MemoryKind, - ) -> Pointer { - let size = u64::try_from(os_str.len()).unwrap().checked_add(1).unwrap(); // Make space for `0x0000` terminator. - let this = self.eval_context_mut(); - - let arg_type = this.tcx.mk_array(this.tcx.types.u16, size); - let arg_place = this.allocate(this.layout_of(arg_type).unwrap(), memkind); - assert!(self.write_os_str_to_wide_str(os_str, arg_place.ptr, size).unwrap().0); - arg_place.ptr.assert_ptr() - } - - /// Read a null-terminated sequence of bytes, and perform path separator conversion if needed. - fn read_path_from_c_str<'a>(&'a self, scalar: Scalar) -> InterpResult<'tcx, Cow<'a, Path>> - where - 'tcx: 'a, - 'mir: 'a, - { - let this = self.eval_context_ref(); - let os_str = this.read_os_str_from_c_str(scalar)?; - - #[cfg(windows)] - return Ok(if this.tcx.sess.target.target.target_os == "windows" { - // Windows-on-Windows, all fine. - Cow::Borrowed(Path::new(os_str)) - } else { - // Unix target, Windows host. Need to convert target '/' to host '\'. - let converted = os_str - .encode_wide() - .map(|wchar| if wchar == '/' as u16 { '\\' as u16 } else { wchar }) - .collect::>(); - Cow::Owned(PathBuf::from(OsString::from_wide(&converted))) - }); - #[cfg(unix)] - return Ok(if this.tcx.sess.target.target.target_os == "windows" { - // Windows target, Unix host. Need to convert target '\' to host '/'. - let converted = os_str - .as_bytes() - .iter() - .map(|&wchar| if wchar == '/' as u8 { '\\' as u8 } else { wchar }) - .collect::>(); - Cow::Owned(PathBuf::from(OsString::from_vec(converted))) - } else { - // Unix-on-Unix, all is fine. - Cow::Borrowed(Path::new(os_str)) - }); - } - - /// Write a Path to the machine memory, adjusting path separators if needed. - fn write_path_to_c_str( - &mut self, - path: &Path, - scalar: Scalar, - size: u64, - ) -> InterpResult<'tcx, (bool, u64)> { - let this = self.eval_context_mut(); - - #[cfg(windows)] - let os_str = if this.tcx.sess.target.target.target_os == "windows" { - // Windows-on-Windows, all fine. - Cow::Borrowed(path.as_os_str()) - } else { - // Unix target, Windows host. Need to convert host '\\' to target '/'. - let converted = path - .as_os_str() - .encode_wide() - .map(|wchar| if wchar == '\\' as u16 { '/' as u16 } else { wchar }) - .collect::>(); - Cow::Owned(OsString::from_wide(&converted)) - }; - #[cfg(unix)] - let os_str = if this.tcx.sess.target.target.target_os == "windows" { - // Windows target, Unix host. Need to convert host '/' to target '\'. - let converted = path - .as_os_str() - .as_bytes() - .iter() - .map(|&wchar| if wchar == '/' as u8 { '\\' as u8 } else { wchar }) - .collect::>(); - Cow::Owned(OsString::from_vec(converted)) - } else { - // Unix-on-Unix, all is fine. - Cow::Borrowed(path.as_os_str()) - }; - - this.write_os_str_to_c_str(&os_str, scalar, size) - } } pub fn immty_from_int_checked<'tcx>( diff --git a/src/lib.rs b/src/lib.rs index 32eb5b41e5919..32416ccaafff3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -39,6 +39,7 @@ pub use crate::shims::env::{EnvVars, EvalContextExt as EnvEvalContextExt}; pub use crate::shims::foreign_items::EvalContextExt as ForeignItemsEvalContextExt; pub use crate::shims::fs::{DirHandler, EvalContextExt as FileEvalContextExt, FileHandler}; pub use crate::shims::intrinsics::EvalContextExt as IntrinsicsEvalContextExt; +pub use crate::shims::os_str::EvalContextExt as OsStrEvalContextExt; pub use crate::shims::panic::{CatchUnwindData, EvalContextExt as PanicEvalContextExt}; pub use crate::shims::time::EvalContextExt as TimeEvalContextExt; pub use crate::shims::tls::{EvalContextExt as TlsEvalContextExt, TlsData}; diff --git a/src/shims/mod.rs b/src/shims/mod.rs index 5b5a11b86b49f..f950c80478349 100644 --- a/src/shims/mod.rs +++ b/src/shims/mod.rs @@ -3,6 +3,7 @@ pub mod env; pub mod foreign_items; pub mod fs; pub mod intrinsics; +pub mod os_str; pub mod panic; pub mod time; pub mod tls; diff --git a/src/shims/os_str.rs b/src/shims/os_str.rs new file mode 100644 index 0000000000000..2306d01de5d96 --- /dev/null +++ b/src/shims/os_str.rs @@ -0,0 +1,247 @@ +use std::borrow::Cow; +use std::convert::TryFrom; +use std::ffi::{OsStr, OsString}; +use std::iter; +#[cfg(unix)] +use std::os::unix::ffi::{OsStrExt, OsStringExt}; +#[cfg(windows)] +use std::os::windows::ffi::{OsStrExt, OsStringExt}; +use std::path::{Path, PathBuf}; + +use rustc::ty::layout::LayoutOf; + +use crate::*; + +impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} +pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { + /// Helper function to read an OsString from a null-terminated sequence of bytes, which is what + /// the Unix APIs usually handle. + fn read_os_str_from_c_str<'a>(&'a self, scalar: Scalar) -> InterpResult<'tcx, &'a OsStr> + where + 'tcx: 'a, + 'mir: 'a, + { + #[cfg(unix)] + fn bytes_to_os_str<'tcx, 'a>(bytes: &'a [u8]) -> InterpResult<'tcx, &'a OsStr> { + Ok(OsStr::from_bytes(bytes)) + } + #[cfg(not(unix))] + fn bytes_to_os_str<'tcx, 'a>(bytes: &'a [u8]) -> InterpResult<'tcx, &'a OsStr> { + let s = std::str::from_utf8(bytes) + .map_err(|_| err_unsup_format!("{:?} is not a valid utf-8 string", bytes))?; + Ok(OsStr::new(s)) + } + + let this = self.eval_context_ref(); + let bytes = this.memory.read_c_str(scalar)?; + bytes_to_os_str(bytes) + } + + /// Helper function to read an OsString from a 0x0000-terminated sequence of u16, + /// which is what the Windows APIs usually handle. + fn read_os_str_from_wide_str<'a>(&'a self, scalar: Scalar) -> InterpResult<'tcx, OsString> + where + 'tcx: 'a, + 'mir: 'a, + { + #[cfg(windows)] + pub fn u16vec_to_osstring<'tcx, 'a>(u16_vec: Vec) -> InterpResult<'tcx, OsString> { + Ok(OsString::from_wide(&u16_vec[..])) + } + #[cfg(not(windows))] + pub fn u16vec_to_osstring<'tcx, 'a>(u16_vec: Vec) -> InterpResult<'tcx, OsString> { + let s = String::from_utf16(&u16_vec[..]) + .map_err(|_| err_unsup_format!("{:?} is not a valid utf-16 string", u16_vec))?; + Ok(s.into()) + } + + let u16_vec = self.eval_context_ref().memory.read_wide_str(scalar)?; + u16vec_to_osstring(u16_vec) + } + + /// Helper function to write an OsStr as a null-terminated sequence of bytes, which is what + /// the Unix APIs usually handle. This function returns `Ok((false, length))` without trying + /// to write if `size` is not large enough to fit the contents of `os_string` plus a null + /// terminator. It returns `Ok((true, length))` if the writing process was successful. The + /// string length returned does not include the null terminator. + fn write_os_str_to_c_str( + &mut self, + os_str: &OsStr, + scalar: Scalar, + size: u64, + ) -> InterpResult<'tcx, (bool, u64)> { + #[cfg(unix)] + fn os_str_to_bytes<'tcx, 'a>(os_str: &'a OsStr) -> InterpResult<'tcx, &'a [u8]> { + Ok(os_str.as_bytes()) + } + #[cfg(not(unix))] + fn os_str_to_bytes<'tcx, 'a>(os_str: &'a OsStr) -> InterpResult<'tcx, &'a [u8]> { + // On non-unix platforms the best we can do to transform bytes from/to OS strings is to do the + // intermediate transformation into strings. Which invalidates non-utf8 paths that are actually + // valid. + os_str + .to_str() + .map(|s| s.as_bytes()) + .ok_or_else(|| err_unsup_format!("{:?} is not a valid utf-8 string", os_str).into()) + } + + let bytes = os_str_to_bytes(os_str)?; + // If `size` is smaller or equal than `bytes.len()`, writing `bytes` plus the required null + // terminator to memory using the `ptr` pointer would cause an out-of-bounds access. + let string_length = u64::try_from(bytes.len()).unwrap(); + if size <= string_length { + return Ok((false, string_length)); + } + self.eval_context_mut() + .memory + .write_bytes(scalar, bytes.iter().copied().chain(iter::once(0u8)))?; + Ok((true, string_length)) + } + + /// Helper function to write an OsStr as a 0x0000-terminated u16-sequence, which is what + /// the Windows APIs usually handle. This function returns `Ok((false, length))` without trying + /// to write if `size` is not large enough to fit the contents of `os_string` plus a null + /// terminator. It returns `Ok((true, length))` if the writing process was successful. The + /// string length returned does not include the null terminator. + fn write_os_str_to_wide_str( + &mut self, + os_str: &OsStr, + scalar: Scalar, + size: u64, + ) -> InterpResult<'tcx, (bool, u64)> { + #[cfg(windows)] + fn os_str_to_u16vec<'tcx>(os_str: &OsStr) -> InterpResult<'tcx, Vec> { + Ok(os_str.encode_wide().collect()) + } + #[cfg(not(windows))] + fn os_str_to_u16vec<'tcx>(os_str: &OsStr) -> InterpResult<'tcx, Vec> { + // On non-Windows platforms the best we can do to transform Vec from/to OS strings is to do the + // intermediate transformation into strings. Which invalidates non-utf8 paths that are actually + // valid. + os_str + .to_str() + .map(|s| s.encode_utf16().collect()) + .ok_or_else(|| err_unsup_format!("{:?} is not a valid utf-8 string", os_str).into()) + } + + let u16_vec = os_str_to_u16vec(os_str)?; + // If `size` is smaller or equal than `bytes.len()`, writing `bytes` plus the required + // 0x0000 terminator to memory would cause an out-of-bounds access. + let string_length = u64::try_from(u16_vec.len()).unwrap(); + if size <= string_length { + return Ok((false, string_length)); + } + + // Store the UTF-16 string. + self.eval_context_mut() + .memory + .write_u16s(scalar, u16_vec.into_iter().chain(iter::once(0x0000)))?; + Ok((true, string_length)) + } + + /// Allocate enough memory to store the given `OsStr` as a null-terminated sequence of bytes. + fn alloc_os_str_as_c_str( + &mut self, + os_str: &OsStr, + memkind: MemoryKind, + ) -> Pointer { + let size = u64::try_from(os_str.len()).unwrap().checked_add(1).unwrap(); // Make space for `0` terminator. + let this = self.eval_context_mut(); + + let arg_type = this.tcx.mk_array(this.tcx.types.u8, size); + let arg_place = this.allocate(this.layout_of(arg_type).unwrap(), memkind); + assert!(self.write_os_str_to_c_str(os_str, arg_place.ptr, size).unwrap().0); + arg_place.ptr.assert_ptr() + } + + /// Allocate enough memory to store the given `OsStr` as a null-terminated sequence of `u16`. + fn alloc_os_str_as_wide_str( + &mut self, + os_str: &OsStr, + memkind: MemoryKind, + ) -> Pointer { + let size = u64::try_from(os_str.len()).unwrap().checked_add(1).unwrap(); // Make space for `0x0000` terminator. + let this = self.eval_context_mut(); + + let arg_type = this.tcx.mk_array(this.tcx.types.u16, size); + let arg_place = this.allocate(this.layout_of(arg_type).unwrap(), memkind); + assert!(self.write_os_str_to_wide_str(os_str, arg_place.ptr, size).unwrap().0); + arg_place.ptr.assert_ptr() + } + + /// Read a null-terminated sequence of bytes, and perform path separator conversion if needed. + fn read_path_from_c_str<'a>(&'a self, scalar: Scalar) -> InterpResult<'tcx, Cow<'a, Path>> + where + 'tcx: 'a, + 'mir: 'a, + { + let this = self.eval_context_ref(); + let os_str = this.read_os_str_from_c_str(scalar)?; + + #[cfg(windows)] + return Ok(if this.tcx.sess.target.target.target_os == "windows" { + // Windows-on-Windows, all fine. + Cow::Borrowed(Path::new(os_str)) + } else { + // Unix target, Windows host. Need to convert target '/' to host '\'. + let converted = os_str + .encode_wide() + .map(|wchar| if wchar == '/' as u16 { '\\' as u16 } else { wchar }) + .collect::>(); + Cow::Owned(PathBuf::from(OsString::from_wide(&converted))) + }); + #[cfg(unix)] + return Ok(if this.tcx.sess.target.target.target_os == "windows" { + // Windows target, Unix host. Need to convert target '\' to host '/'. + let converted = os_str + .as_bytes() + .iter() + .map(|&wchar| if wchar == '/' as u8 { '\\' as u8 } else { wchar }) + .collect::>(); + Cow::Owned(PathBuf::from(OsString::from_vec(converted))) + } else { + // Unix-on-Unix, all is fine. + Cow::Borrowed(Path::new(os_str)) + }); + } + + /// Write a Path to the machine memory, adjusting path separators if needed. + fn write_path_to_c_str( + &mut self, + path: &Path, + scalar: Scalar, + size: u64, + ) -> InterpResult<'tcx, (bool, u64)> { + let this = self.eval_context_mut(); + + #[cfg(windows)] + let os_str = if this.tcx.sess.target.target.target_os == "windows" { + // Windows-on-Windows, all fine. + Cow::Borrowed(path.as_os_str()) + } else { + // Unix target, Windows host. Need to convert host '\\' to target '/'. + let converted = path + .as_os_str() + .encode_wide() + .map(|wchar| if wchar == '\\' as u16 { '/' as u16 } else { wchar }) + .collect::>(); + Cow::Owned(OsString::from_wide(&converted)) + }; + #[cfg(unix)] + let os_str = if this.tcx.sess.target.target.target_os == "windows" { + // Windows target, Unix host. Need to convert host '/' to target '\'. + let converted = path + .as_os_str() + .as_bytes() + .iter() + .map(|&wchar| if wchar == '/' as u8 { '\\' as u8 } else { wchar }) + .collect::>(); + Cow::Owned(OsString::from_vec(converted)) + } else { + // Unix-on-Unix, all is fine. + Cow::Borrowed(path.as_os_str()) + }; + + this.write_os_str_to_c_str(&os_str, scalar, size) + } +} From 4e471f745f7e827a4e8986cd166f86953a0d6ab2 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 28 Mar 2020 15:45:45 +0100 Subject: [PATCH 1740/3747] fix float test comments and test a few more int->float casts --- tests/run-pass/floats.rs | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/tests/run-pass/floats.rs b/tests/run-pass/floats.rs index 5a7413e98ea81..394e91ac9c3b8 100644 --- a/tests/run-pass/floats.rs +++ b/tests/run-pass/floats.rs @@ -2,8 +2,8 @@ use std::fmt::Debug; // Helper function to avoid promotion so that this tests "run-time" casts, not CTFE. -// Doesn't make a big difference when running this in Miri, but when running this in -// rustc (with -Zmir-opt-level=0) for comparison it means we use LLVM casts. +// Doesn't make a big difference when running this in Miri, but it means we can compare this +// with the LLVM backend by running `rustc -Zmir-opt-level=0 -Zsaturating-float-casts`. #[track_caller] #[inline(never)] fn assert_eq(x: T, y: T) { @@ -29,7 +29,7 @@ fn main() { let y: f32 = unsafe { std::mem::transmute(x) }; assert_eq(y, 42.0_f32); - // f32-to-int casts + // f32 <-> int casts assert_eq(5.0f32 as u32, 5); assert_eq(-5.0f32 as u32, 0); assert_eq(5.0f32 as i32, 5); @@ -44,11 +44,13 @@ fn main() { assert_eq(std::f32::NEG_INFINITY as u32, 0); assert_eq(std::f32::NAN as i32, 0); assert_eq(std::f32::NAN as u32, 0); - assert_eq(u128::MAX as f32, std::f32::INFINITY); assert_eq((u32::MAX-127) as f32 as u32, u32::MAX); // rounding loss assert_eq((u32::MAX-128) as f32 as u32, u32::MAX-255); // rounding loss + assert_eq(127i8 as f32, 127.0f32); + assert_eq(i128::MIN as f32, -170141183460469231731687303715884105728.0f32); + assert_eq(u128::MAX as f32, std::f32::INFINITY); // saturation - // f64-to-int casts + // f64 <-> int casts assert_eq(5.0f64 as u64, 5); assert_eq(-5.0f64 as u64, 0); assert_eq(5.0f64 as i64, 5); @@ -63,9 +65,11 @@ fn main() { assert_eq(std::f64::NEG_INFINITY as u64, 0); assert_eq(std::f64::NAN as i64, 0); assert_eq(std::f64::NAN as u64, 0); - assert_eq(u128::MAX as f64 as u128, u128::MAX); assert_eq((u64::MAX-1023) as f64 as u64, u64::MAX); // rounding loss assert_eq((u64::MAX-1024) as f64 as u64, u64::MAX-2047); // rounding loss + assert_eq(u128::MAX as f64 as u128, u128::MAX); + assert_eq(i16::MIN as f64, -32768.0f64); + assert_eq(u128::MAX as f64, 340282366920938463463374607431768211455.0f64); // even that fits... // f32 <-> f64 casts assert_eq(5.0f64 as f32, 5.0f32); From 4a70ebc1f3e1d635a3ed6ec5d8e37e6618e5f05d Mon Sep 17 00:00:00 2001 From: JOE1994 Date: Sat, 28 Mar 2020 11:20:16 -0400 Subject: [PATCH 1741/3747] visually separate conditional imports in 'os_str.rs' --- src/shims/os_str.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/shims/os_str.rs b/src/shims/os_str.rs index 2306d01de5d96..316d5b0014a7e 100644 --- a/src/shims/os_str.rs +++ b/src/shims/os_str.rs @@ -2,11 +2,12 @@ use std::borrow::Cow; use std::convert::TryFrom; use std::ffi::{OsStr, OsString}; use std::iter; +use std::path::{Path, PathBuf}; + #[cfg(unix)] use std::os::unix::ffi::{OsStrExt, OsStringExt}; #[cfg(windows)] use std::os::windows::ffi::{OsStrExt, OsStringExt}; -use std::path::{Path, PathBuf}; use rustc::ty::layout::LayoutOf; From fbbca59de7873ebad6452c576fe7f9e7011c466d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 28 Mar 2020 17:35:40 +0100 Subject: [PATCH 1742/3747] avoid Scalar::from_(u)int in favor of giving the size explicitly --- src/eval.rs | 7 +++--- src/helpers.rs | 2 +- src/machine.rs | 4 ++-- src/shims/env.rs | 10 ++++---- src/shims/foreign_items.rs | 10 ++++---- src/shims/foreign_items/posix.rs | 33 +++++++++++++------------- src/shims/foreign_items/posix/linux.rs | 14 +++++------ src/shims/foreign_items/posix/macos.rs | 18 +++++++------- src/shims/foreign_items/windows.rs | 16 ++++++------- src/shims/intrinsics.rs | 9 +++---- src/shims/mod.rs | 2 +- 11 files changed, 61 insertions(+), 64 deletions(-) diff --git a/src/eval.rs b/src/eval.rs index faf7f5532ccf4..9838bd1e8cc24 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -6,7 +6,7 @@ use std::convert::TryFrom; use rand::rngs::StdRng; use rand::SeedableRng; -use rustc::ty::layout::{LayoutOf, Size}; +use rustc::ty::layout::LayoutOf; use rustc::ty::{self, TyCtxt}; use rustc_hir::def_id::DefId; @@ -96,7 +96,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( // First argument: pointer to `main()`. let main_ptr = ecx.memory.create_fn_alloc(FnVal::Instance(main_instance)); // Second argument (argc): length of `config.args`. - let argc = Scalar::from_uint(u64::try_from(config.args.len()).unwrap(), ecx.pointer_size()); + let argc = Scalar::from_machine_usize(u64::try_from(config.args.len()).unwrap(), &ecx); // Third argument (`argv`): created from `config.args`. let argv = { // Put each argument in memory, collect pointers. @@ -152,10 +152,9 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( let cmd_place = ecx.allocate(ecx.layout_of(cmd_type)?, MiriMemoryKind::Machine.into()); ecx.machine.cmd_line = Some(cmd_place.ptr); // Store the UTF-16 string. We just allocated so we know the bounds are fine. - let char_size = Size::from_bytes(2); for (idx, &c) in cmd_utf16.iter().enumerate() { let place = ecx.mplace_field(cmd_place, idx)?; - ecx.write_scalar(Scalar::from_uint(c, char_size), place.into())?; + ecx.write_scalar(Scalar::from_u16(c), place.into())?; } } argv diff --git a/src/helpers.rs b/src/helpers.rs index 8e379065b07eb..9bc0279aa455e 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -100,7 +100,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// Test if this immediate equals 0. fn is_null(&self, val: Scalar) -> InterpResult<'tcx, bool> { let this = self.eval_context_ref(); - let null = Scalar::from_int(0, this.memory.pointer_size()); + let null = Scalar::ptr_null(this); this.ptr_eq(val, null) } diff --git a/src/machine.rs b/src/machine.rs index f88210f30e8c6..ebde404769cad 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -316,10 +316,10 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { let layout = ecx.layout_of(dest.layout.ty.builtin_deref(false).unwrap().ty)?; // First argument: `size`. // (`0` is allowed here -- this is expected to be handled by the lang item). - let size = Scalar::from_uint(layout.size.bytes(), ecx.pointer_size()); + let size = Scalar::from_machine_usize(layout.size.bytes(), ecx); // Second argument: `align`. - let align = Scalar::from_uint(layout.align.abi.bytes(), ecx.pointer_size()); + let align = Scalar::from_machine_usize(layout.align.abi.bytes(), ecx); // Call the `exchange_malloc` lang item. let malloc = ecx.tcx.lang_items().exchange_malloc_fn().unwrap(); diff --git a/src/shims/env.rs b/src/shims/env.rs index 163a8c2e51d78..7aa4148fa888c 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -108,7 +108,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx name_op: OpTy<'tcx, Tag>, // LPCWSTR buf_op: OpTy<'tcx, Tag>, // LPWSTR size_op: OpTy<'tcx, Tag>, // DWORD - ) -> InterpResult<'tcx, u64> { + ) -> InterpResult<'tcx, u32> { let this = self.eval_context_mut(); this.assert_target_os("windows", "GetEnvironmentVariableW"); @@ -124,17 +124,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let buf_ptr = this.read_scalar(buf_op)?.not_undef()?; // `buf_size` represents the size in characters. - let buf_size = u64::try_from(this.read_scalar(size_op)?.to_u32()?).unwrap(); + let buf_size = u64::from(this.read_scalar(size_op)?.to_u32()?); let (success, len) = this.write_os_str_to_wide_str(&var, buf_ptr, buf_size)?; if success { // If the function succeeds, the return value is the number of characters stored in the buffer pointed to by lpBuffer, // not including the terminating null character. - len + u32::try_from(len).unwrap() } else { // If lpBuffer is not large enough to hold the data, the return value is the buffer size, in characters, // required to hold the string and its terminating null character and the contents of lpBuffer are undefined. - len + 1 + u32::try_from(len).unwrap().checked_add(1).unwrap() } } None => { @@ -344,7 +344,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Collect all the pointers to each variable in a vector. let mut vars: Vec> = this.machine.env_vars.map.values().map(|&ptr| ptr.into()).collect(); // Add the trailing null pointer. - vars.push(Scalar::from_int(0, this.pointer_size())); + vars.push(Scalar::from_machine_usize(0, this)); // Make an array with all these pointers inside Miri. let tcx = this.tcx; let vars_layout = diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index c92e338ef7e02..3e21e1d453fcf 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -47,7 +47,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn malloc(&mut self, size: u64, zero_init: bool, kind: MiriMemoryKind) -> Scalar { let this = self.eval_context_mut(); if size == 0 { - Scalar::from_int(0, this.pointer_size()) + Scalar::ptr_null(this) } else { let align = this.min_align(size, kind); let ptr = this.memory.allocate(Size::from_bytes(size), align, kind.into()); @@ -78,7 +78,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let new_align = this.min_align(new_size, kind); if this.is_null(old_ptr)? { if new_size == 0 { - Ok(Scalar::from_int(0, this.pointer_size())) + Ok(Scalar::ptr_null(this)) } else { let new_ptr = this.memory.allocate(Size::from_bytes(new_size), new_align, kind.into()); @@ -88,7 +88,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let old_ptr = this.force_ptr(old_ptr)?; if new_size == 0 { this.memory.deallocate(old_ptr, None, kind.into())?; - Ok(Scalar::from_int(0, this.pointer_size())) + Ok(Scalar::ptr_null(this)) } else { let new_ptr = this.memory.reallocate( old_ptr, @@ -296,7 +296,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } }; - this.write_scalar(Scalar::from_int(result, Size::from_bits(32)), dest)?; + this.write_scalar(Scalar::from_i32(result), dest)?; } "memrchr" => { let ptr = this.read_scalar(args[0])?.not_undef()?; @@ -334,7 +334,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "strlen" => { let ptr = this.read_scalar(args[0])?.not_undef()?; let n = this.memory.read_c_str(ptr)?.len(); - this.write_scalar(Scalar::from_uint(u64::try_from(n).unwrap(), dest.layout.size), dest)?; + this.write_scalar(Scalar::from_machine_usize(u64::try_from(n).unwrap(), this), dest)?; } // math functions diff --git a/src/shims/foreign_items/posix.rs b/src/shims/foreign_items/posix.rs index ce23bc4c972f6..1a9e91eded7fe 100644 --- a/src/shims/foreign_items/posix.rs +++ b/src/shims/foreign_items/posix.rs @@ -26,11 +26,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "unsetenv" => { let result = this.unsetenv(args[0])?; - this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + this.write_scalar(Scalar::from_i32(result), dest)?; } "setenv" => { let result = this.setenv(args[0], args[1])?; - this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + this.write_scalar(Scalar::from_i32(result), dest)?; } "getcwd" => { let result = this.getcwd(args[0], args[1])?; @@ -38,21 +38,21 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "chdir" => { let result = this.chdir(args[0])?; - this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + this.write_scalar(Scalar::from_i32(result), dest)?; } // File related shims "open" | "open64" => { let result = this.open(args[0], args[1])?; - this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + this.write_scalar(Scalar::from_i32(result), dest)?; } "fcntl" => { let result = this.fcntl(args[0], args[1], args.get(2).cloned())?; - this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + this.write_scalar(Scalar::from_i32(result), dest)?; } "read" => { let result = this.read(args[0], args[1], args[2])?; - this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + this.write_scalar(Scalar::from_machine_isize(result, this), dest)?; } "write" => { let fd = this.read_scalar(args[0])?.to_i32()?; @@ -85,35 +85,36 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write(args[0], args[1], args[2])? }; // Now, `result` is the value we return back to the program. - this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + this.write_scalar(Scalar::from_machine_isize(result, this), dest)?; } "unlink" => { let result = this.unlink(args[0])?; - this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + this.write_scalar(Scalar::from_i32(result), dest)?; } "symlink" => { let result = this.symlink(args[0], args[1])?; - this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + this.write_scalar(Scalar::from_i32(result), dest)?; } "rename" => { let result = this.rename(args[0], args[1])?; - this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + this.write_scalar(Scalar::from_i32(result), dest)?; } "mkdir" => { let result = this.mkdir(args[0], args[1])?; - this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + this.write_scalar(Scalar::from_i32(result), dest)?; } "rmdir" => { let result = this.rmdir(args[0])?; - this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + this.write_scalar(Scalar::from_i32(result), dest)?; } "closedir" => { let result = this.closedir(args[0])?; - this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + this.write_scalar(Scalar::from_i32(result), dest)?; } "lseek" | "lseek64" => { let result = this.lseek64(args[0], args[1], args[2])?; - this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + // "lseek" is only used on macOS which is 64bit-only, so `i64` always works. + this.write_scalar(Scalar::from_i64(result), dest)?; } // Allocation @@ -165,8 +166,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let name = this.read_scalar(args[0])?.to_i32()?; let sysconfs = &[ - ("_SC_PAGESIZE", Scalar::from_int(PAGE_SIZE, dest.layout.size)), - ("_SC_NPROCESSORS_ONLN", Scalar::from_int(NUM_CPUS, dest.layout.size)), + ("_SC_PAGESIZE", Scalar::from_int(PAGE_SIZE, this.pointer_size())), + ("_SC_NPROCESSORS_ONLN", Scalar::from_int(NUM_CPUS, this.pointer_size())), ]; let mut result = None; for &(sysconf_name, value) in sysconfs { diff --git a/src/shims/foreign_items/posix/linux.rs b/src/shims/foreign_items/posix/linux.rs index 88a18e3e75f97..d11d355eb3461 100644 --- a/src/shims/foreign_items/posix/linux.rs +++ b/src/shims/foreign_items/posix/linux.rs @@ -24,7 +24,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // in the `posix` module. "close" => { let result = this.close(args[0])?; - this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + this.write_scalar(Scalar::from_i32(result), dest)?; } "opendir" => { let result = this.opendir(args[0])?; @@ -32,7 +32,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "readdir64_r" => { let result = this.linux_readdir64_r(args[0], args[1], args[2])?; - this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + this.write_scalar(Scalar::from_i32(result), dest)?; } // Linux-only "posix_fadvise" => { @@ -48,7 +48,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "clock_gettime" => { // This is a POSIX function but it has only been tested on linux. let result = this.clock_gettime(args[0], args[1])?; - this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + this.write_scalar(Scalar::from_i32(result), dest)?; } // Querying system information @@ -59,11 +59,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let size_place = this.deref_operand(args[2])?; this.write_scalar( - Scalar::from_uint(STACK_ADDR, addr_place.layout.size), + Scalar::from_uint(STACK_ADDR, this.pointer_size()), addr_place.into(), )?; this.write_scalar( - Scalar::from_uint(STACK_SIZE, size_place.layout.size), + Scalar::from_uint(STACK_SIZE, this.pointer_size()), size_place.into(), )?; @@ -93,7 +93,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx id if id == sys_statx => { // The first argument is the syscall id, so skip over it. let result = this.linux_statx(args[1], args[2], args[3], args[4], args[5])?; - this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + this.write_scalar(Scalar::from_machine_isize(result.into(), this), dest)?; } id => throw_unsup_format!("miri does not support syscall ID {}", id), } @@ -110,7 +110,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // FIXME: we just return an error; `num_cpus` then falls back to `sysconf`. let einval = this.eval_libc("EINVAL")?; this.set_last_error(einval)?; - this.write_scalar(Scalar::from_int(-1, dest.layout.size), dest)?; + this.write_scalar(Scalar::from_i32(-1), dest)?; } // Incomplete shims that we "stub out" just to get pre-main initialziation code to work. diff --git a/src/shims/foreign_items/posix/macos.rs b/src/shims/foreign_items/posix/macos.rs index 2261b1c4cfb97..cc58924a54abc 100644 --- a/src/shims/foreign_items/posix/macos.rs +++ b/src/shims/foreign_items/posix/macos.rs @@ -22,19 +22,19 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // File related shims "close$NOCANCEL" => { let result = this.close(args[0])?; - this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + this.write_scalar(Scalar::from_i32(result), dest)?; } "stat$INODE64" => { let result = this.macos_stat(args[0], args[1])?; - this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + this.write_scalar(Scalar::from_i32(result), dest)?; } "lstat$INODE64" => { let result = this.macos_lstat(args[0], args[1])?; - this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + this.write_scalar(Scalar::from_i32(result), dest)?; } "fstat$INODE64" => { let result = this.macos_fstat(args[0], args[1])?; - this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + this.write_scalar(Scalar::from_i32(result), dest)?; } "opendir$INODE64" => { let result = this.opendir(args[0])?; @@ -42,7 +42,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "readdir_r$INODE64" => { let result = this.macos_readdir_r(args[0], args[1], args[2])?; - this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + this.write_scalar(Scalar::from_i32(result), dest)?; } // Environment related shims @@ -53,11 +53,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Time related shims "gettimeofday" => { let result = this.gettimeofday(args[0], args[1])?; - this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + this.write_scalar(Scalar::from_i32(result), dest)?; } "mach_absolute_time" => { let result = this.mach_absolute_time()?; - this.write_scalar(Scalar::from_uint(result, dest.layout.size), dest)?; + this.write_scalar(Scalar::from_u64(result), dest)?; } // Access to command-line arguments @@ -79,12 +79,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Querying system information "pthread_get_stackaddr_np" => { let _thread = this.read_scalar(args[0])?.not_undef()?; - let stack_addr = Scalar::from_uint(STACK_ADDR, dest.layout.size); + let stack_addr = Scalar::from_uint(STACK_ADDR, this.pointer_size()); this.write_scalar(stack_addr, dest)?; } "pthread_get_stacksize_np" => { let _thread = this.read_scalar(args[0])?.not_undef()?; - let stack_size = Scalar::from_uint(STACK_SIZE, dest.layout.size); + let stack_size = Scalar::from_uint(STACK_SIZE, this.pointer_size()); this.write_scalar(stack_size, dest)?; } diff --git a/src/shims/foreign_items/windows.rs b/src/shims/foreign_items/windows.rs index 9a626fe75e03e..7f3f1d0c2d2ec 100644 --- a/src/shims/foreign_items/windows.rs +++ b/src/shims/foreign_items/windows.rs @@ -22,12 +22,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Environment related shims "GetEnvironmentVariableW" => { let result = this.GetEnvironmentVariableW(args[0], args[1], args[2])?; - this.write_scalar(Scalar::from_uint(result, dest.layout.size), dest)?; + this.write_scalar(Scalar::from_u32(result), dest)?; } "SetEnvironmentVariableW" => { let result = this.SetEnvironmentVariableW(args[0], args[1])?; - this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + this.write_scalar(Scalar::from_i32(result), dest)?; } "GetEnvironmentStringsW" => { @@ -45,7 +45,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let which = this.read_scalar(args[0])?.to_i32()?; // We just make this the identity function, so we know later in `WriteFile` // which one it is. - this.write_scalar(Scalar::from_int(which, this.pointer_size()), dest)?; + this.write_scalar(Scalar::from_machine_isize(which.into(), this), dest)?; } "WriteFile" => { let handle = this.read_scalar(args[0])?.to_machine_isize(this)?; @@ -74,7 +74,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // Return whether this was a success. this.write_scalar( - Scalar::from_int(if written.is_some() { 1 } else { 0 }, dest.layout.size), + Scalar::from_i32(if written.is_some() { 1 } else { 0 }), dest, )?; } @@ -93,7 +93,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let _flags = this.read_scalar(args[1])?.to_u32()?; let ptr = this.read_scalar(args[2])?.not_undef()?; this.free(ptr, MiriMemoryKind::WinHeap)?; - this.write_scalar(Scalar::from_int(1, Size::from_bytes(4)), dest)?; + this.write_scalar(Scalar::from_i32(1), dest)?; } "HeapReAlloc" => { let _handle = this.read_scalar(args[0])?.to_machine_isize(this)?; @@ -146,7 +146,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.machine.tls.store_tls(key, this.test_null(new_ptr)?)?; // Return success (`1`). - this.write_scalar(Scalar::from_int(1, dest.layout.size), dest)?; + this.write_scalar(Scalar::from_i32(1), dest)?; } // Access to command-line arguments @@ -191,7 +191,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // These shims are enabled only when the caller is in the standard library. "GetProcessHeap" if this.frame().instance.to_string().starts_with("std::sys::windows::") => { // Just fake a HANDLE - this.write_scalar(Scalar::from_int(1, this.pointer_size()), dest)?; + this.write_scalar(Scalar::from_machine_isize(1, this), dest)?; } | "GetModuleHandleW" | "GetProcAddress" @@ -202,7 +202,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "AddVectoredExceptionHandler" if this.frame().instance.to_string().starts_with("std::sys::windows::") => { // Any non zero value works for the stdlib. This is just used for stack overflows anyway. - this.write_scalar(Scalar::from_int(1, dest.layout.size), dest)?; + this.write_scalar(Scalar::from_machine_usize(1, this), dest)?; } | "InitializeCriticalSection" | "EnterCriticalSection" diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 84e8cca556a1c..91d0835589f40 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -388,8 +388,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let ty = substs.type_at(0); let layout = this.layout_of(ty)?; let align = layout.align.pref.bytes(); - let ptr_size = this.pointer_size(); - let align_val = Scalar::from_uint(align, ptr_size); + let align_val = Scalar::from_machine_usize(align, this); this.write_scalar(align_val, dest)?; } @@ -471,8 +470,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let (size, _) = this .size_and_align_of_mplace(mplace)? .expect("size_of_val called on extern type"); - let ptr_size = this.pointer_size(); - this.write_scalar(Scalar::from_uint(size.bytes(), ptr_size), dest)?; + this.write_scalar(Scalar::from_machine_usize(size.bytes(), this), dest)?; } #[rustfmt::skip] @@ -483,8 +481,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let (_, align) = this .size_and_align_of_mplace(mplace)? .expect("size_of_val called on extern type"); - let ptr_size = this.pointer_size(); - this.write_scalar(Scalar::from_uint(align.bytes(), ptr_size), dest)?; + this.write_scalar(Scalar::from_machine_usize(align.bytes(), this), dest)?; } "write_bytes" => { diff --git a/src/shims/mod.rs b/src/shims/mod.rs index 5b5a11b86b49f..588f496d1f3ff 100644 --- a/src/shims/mod.rs +++ b/src/shims/mod.rs @@ -92,7 +92,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // Return result, and jump to caller. - this.write_scalar(Scalar::from_uint(result, dest.layout.size), dest)?; + this.write_scalar(Scalar::from_uint(result, this.pointer_size()), dest)?; this.go_to_block(ret); Ok(()) } From b7fec6b17f1f4cbe228c964cfb8a0f76b46f749f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 28 Mar 2020 17:38:38 +0100 Subject: [PATCH 1743/3747] use ptr_null where appropriate --- src/machine.rs | 2 +- src/shims/env.rs | 3 +-- src/shims/fs.rs | 2 +- src/shims/intrinsics.rs | 1 - 4 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/machine.rs b/src/machine.rs index ebde404769cad..84329b8fd3cd6 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -130,7 +130,7 @@ impl MemoryExtra { // This should be all-zero, pointer-sized. let layout = this.layout_of(this.tcx.types.usize)?; let place = this.allocate(layout, MiriMemoryKind::Machine.into()); - this.write_scalar(Scalar::from_machine_usize(0, &*this.tcx), place.into())?; + this.write_scalar(Scalar::from_machine_usize(0, this), place.into())?; Self::add_extern_static(this, "__cxa_thread_atexit_impl", place.ptr); // "environ" Self::add_extern_static(this, "environ", this.machine.env_vars.environ.unwrap().ptr); diff --git a/src/shims/env.rs b/src/shims/env.rs index 7aa4148fa888c..98f1e7e3cfa32 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -337,14 +337,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // This is memory backing an extern static, hence `Machine`, not `Env`. let layout = this.layout_of(this.tcx.types.usize)?; let place = this.allocate(layout, MiriMemoryKind::Machine.into()); - this.write_scalar(Scalar::from_machine_usize(0, &*this.tcx), place.into())?; this.machine.env_vars.environ = Some(place); } // Collect all the pointers to each variable in a vector. let mut vars: Vec> = this.machine.env_vars.map.values().map(|&ptr| ptr.into()).collect(); // Add the trailing null pointer. - vars.push(Scalar::from_machine_usize(0, this)); + vars.push(Scalar::ptr_null(this)); // Make an array with all these pointers inside Miri. let tcx = this.tcx; let vars_layout = diff --git a/src/shims/fs.rs b/src/shims/fs.rs index b779bf165d2b4..debf412bdd413 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -860,7 +860,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } Err(e) => { this.set_last_error_from_io_error(e)?; - Ok(Scalar::from_machine_usize(0, this)) + Ok(Scalar::ptr_null(this)) } } } diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 91d0835589f40..fda52429e515a 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -2,7 +2,6 @@ use std::iter; use std::convert::TryFrom; use rustc::mir; -use rustc::mir::interpret::{InterpResult, PointerArithmetic}; use rustc::ty; use rustc::ty::layout::{Align, LayoutOf}; use rustc_apfloat::Float; From d6795a77b4d18c96c3c967a0d05d90f20b49d0d2 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 28 Mar 2020 17:47:00 +0100 Subject: [PATCH 1744/3747] precise getrandom return type and align_offset arithmetic --- src/shims/foreign_items/posix/linux.rs | 2 +- src/shims/mod.rs | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/shims/foreign_items/posix/linux.rs b/src/shims/foreign_items/posix/linux.rs index d11d355eb3461..f56d5b3959c75 100644 --- a/src/shims/foreign_items/posix/linux.rs +++ b/src/shims/foreign_items/posix/linux.rs @@ -140,6 +140,6 @@ fn getrandom<'tcx>( let _flags = this.read_scalar(args[2])?.to_i32()?; this.gen_random(ptr, len)?; - this.write_scalar(Scalar::from_uint(len, dest.layout.size), dest)?; + this.write_scalar(Scalar::from_machine_usize(len, this), dest)?; Ok(()) } diff --git a/src/shims/mod.rs b/src/shims/mod.rs index 588f496d1f3ff..58972731fb1d8 100644 --- a/src/shims/mod.rs +++ b/src/shims/mod.rs @@ -75,7 +75,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let ptr_scalar = this.read_scalar(ptr_op)?.not_undef()?; // Default: no result. - let mut result = this.truncate(u128::MAX, dest.layout); + let mut result = this.usize_max(); if let Ok(ptr) = this.force_ptr(ptr_scalar) { // Only do anything if we can identify the allocation this goes to. let cur_align = @@ -84,7 +84,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // If the allocation alignment is at least the required alignment we use the // libcore implementation. // FIXME: is this correct in case of truncation? - result = u128::try_from( + result = u64::try_from( (this.force_bits(ptr_scalar, this.pointer_size())? as *const i8) .align_offset(usize::try_from(req_align).unwrap()) ).unwrap(); @@ -92,7 +92,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // Return result, and jump to caller. - this.write_scalar(Scalar::from_uint(result, this.pointer_size()), dest)?; + this.write_scalar(Scalar::from_machine_usize(result, this), dest)?; this.go_to_block(ret); Ok(()) } From f181e75db2722739f8b8fd0dd25ba85636c9a805 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 29 Mar 2020 10:01:31 +0200 Subject: [PATCH 1745/3747] rustup --- rust-version | 2 +- src/helpers.rs | 2 +- src/shims/env.rs | 6 +++--- src/shims/foreign_items.rs | 6 +++--- src/shims/fs.rs | 6 +++--- src/shims/mod.rs | 2 +- src/shims/tls.rs | 4 ++-- 7 files changed, 14 insertions(+), 14 deletions(-) diff --git a/rust-version b/rust-version index a11e231acb30e..0b3196a7a2806 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -7b73d14b0b35e7b4f79f2d71dc1bbbab31698288 +150322f86d441752874a8bed603d71119f190b8b diff --git a/src/helpers.rs b/src/helpers.rs index f7bc4d195caba..d0a5fc958662a 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -92,7 +92,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// Test if this immediate equals 0. fn is_null(&self, val: Scalar) -> InterpResult<'tcx, bool> { let this = self.eval_context_ref(); - let null = Scalar::ptr_null(this); + let null = Scalar::null_ptr(this); this.ptr_eq(val, null) } diff --git a/src/shims/env.rs b/src/shims/env.rs index 98f1e7e3cfa32..8a69e725abfc6 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -98,7 +98,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // The offset is used to strip the "{name}=" part of the string. Scalar::from(var_ptr.offset(Size::from_bytes(u64::try_from(name.len()).unwrap().checked_add(1).unwrap()), this)?) } - None => Scalar::ptr_null(&*this.tcx), + None => Scalar::null_ptr(&*this.tcx), }) } @@ -305,7 +305,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } Err(e) => this.set_last_error_from_io_error(e)?, } - Ok(Scalar::ptr_null(&*this.tcx)) + Ok(Scalar::null_ptr(&*this.tcx)) } fn chdir(&mut self, path_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { @@ -343,7 +343,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Collect all the pointers to each variable in a vector. let mut vars: Vec> = this.machine.env_vars.map.values().map(|&ptr| ptr.into()).collect(); // Add the trailing null pointer. - vars.push(Scalar::ptr_null(this)); + vars.push(Scalar::null_ptr(this)); // Make an array with all these pointers inside Miri. let tcx = this.tcx; let vars_layout = diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 3e21e1d453fcf..21c4b02e70852 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -47,7 +47,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn malloc(&mut self, size: u64, zero_init: bool, kind: MiriMemoryKind) -> Scalar { let this = self.eval_context_mut(); if size == 0 { - Scalar::ptr_null(this) + Scalar::null_ptr(this) } else { let align = this.min_align(size, kind); let ptr = this.memory.allocate(Size::from_bytes(size), align, kind.into()); @@ -78,7 +78,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let new_align = this.min_align(new_size, kind); if this.is_null(old_ptr)? { if new_size == 0 { - Ok(Scalar::ptr_null(this)) + Ok(Scalar::null_ptr(this)) } else { let new_ptr = this.memory.allocate(Size::from_bytes(new_size), new_align, kind.into()); @@ -88,7 +88,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let old_ptr = this.force_ptr(old_ptr)?; if new_size == 0 { this.memory.deallocate(old_ptr, None, kind.into())?; - Ok(Scalar::ptr_null(this)) + Ok(Scalar::null_ptr(this)) } else { let new_ptr = this.memory.reallocate( old_ptr, diff --git a/src/shims/fs.rs b/src/shims/fs.rs index debf412bdd413..5f8be275b2e43 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -420,7 +420,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // We cap the number of read bytes to the largest value that we are able to fit in both the // host's and target's `isize`. This saves us from having to handle overflows later. - let count = count.min(this.isize_max() as u64).min(isize::MAX as u64); + let count = count.min(this.machine_isize_max() as u64).min(isize::MAX as u64); if let Some(FileHandle { file, writable: _ }) = this.machine.file_handler.handles.get_mut(&fd) { // This can never fail because `count` was capped to be smaller than @@ -474,7 +474,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // We cap the number of written bytes to the largest value that we are able to fit in both the // host's and target's `isize`. This saves us from having to handle overflows later. - let count = count.min(this.isize_max() as u64).min(isize::MAX as u64); + let count = count.min(this.machine_isize_max() as u64).min(isize::MAX as u64); if let Some(FileHandle { file, writable: _ }) = this.machine.file_handler.handles.get_mut(&fd) { let bytes = this.memory.read_bytes(buf, Size::from_bytes(count))?; @@ -860,7 +860,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } Err(e) => { this.set_last_error_from_io_error(e)?; - Ok(Scalar::ptr_null(this)) + Ok(Scalar::null_ptr(this)) } } } diff --git a/src/shims/mod.rs b/src/shims/mod.rs index 1926cf93b6872..731dc2fedc578 100644 --- a/src/shims/mod.rs +++ b/src/shims/mod.rs @@ -76,7 +76,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let ptr_scalar = this.read_scalar(ptr_op)?.not_undef()?; // Default: no result. - let mut result = this.usize_max(); + let mut result = this.machine_usize_max(); if let Ok(ptr) = this.force_ptr(ptr_scalar) { // Only do anything if we can identify the allocation this goes to. let cur_align = diff --git a/src/shims/tls.rs b/src/shims/tls.rs index c753689f4c258..2727c32050401 100644 --- a/src/shims/tls.rs +++ b/src/shims/tls.rs @@ -77,7 +77,7 @@ impl<'tcx> TlsData<'tcx> { match self.keys.get(&key) { Some(&TlsEntry { data, .. }) => { trace!("TLS key {} loaded: {:?}", key, data); - Ok(data.unwrap_or_else(|| Scalar::ptr_null(cx).into())) + Ok(data.unwrap_or_else(|| Scalar::null_ptr(cx).into())) } None => throw_ub_format!("loading from a non-existing TLS key: {}", key), } @@ -173,7 +173,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let ret_place = MPlaceTy::dangling(this.layout_of(this.tcx.mk_unit())?, this).into(); this.call_function( thread_callback, - &[Scalar::ptr_null(this).into(), reason.into(), Scalar::ptr_null(this).into()], + &[Scalar::null_ptr(this).into(), reason.into(), Scalar::null_ptr(this).into()], Some(ret_place), StackPopCleanup::None { cleanup: true }, )?; From a481b8f261a196ec8b4107273705a750c545856b Mon Sep 17 00:00:00 2001 From: JOE1994 Date: Sat, 28 Mar 2020 14:42:22 -0400 Subject: [PATCH 1746/3747] partially implement 'set_last_error_from_io_error' for Windows --- src/helpers.rs | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index d0a5fc958662a..751d77a389783 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -71,6 +71,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx .not_undef() } + /// Helper function to get a `windows` constant as a `Scalar`. + fn eval_windows(&mut self, name: &str) -> InterpResult<'tcx, Scalar> { + self.eval_context_mut() + .eval_path_scalar(&["std", "sys", "windows", "c", name])? + .not_undef() + } + /// Helper function to get a `libc` constant as an `i32`. fn eval_libc_i32(&mut self, name: &str) -> InterpResult<'tcx, i32> { // TODO: Cache the result. @@ -428,11 +435,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } })? } else { - // FIXME: we have to implement the Windows equivalent of this. - throw_unsup_format!( - "setting the last OS error from an io::Error is unsupported for {}.", - target.target_os - ) + // FIXME: we have to finish implementing the Windows equivalent of this. + this.eval_windows(match e.kind() { + NotFound => "ERROR_FILE_NOT_FOUND", + _ => throw_unsup_format!( + "setting the last OS error from an io::Error is yet unsupported for {}.", + target.target_os + ) + })? }; this.set_last_error(last_error) } From 1141b21e50121976567cb54d6bd227bb7d5e1b61 Mon Sep 17 00:00:00 2001 From: JOE1994 Date: Sat, 28 Mar 2020 14:44:41 -0400 Subject: [PATCH 1747/3747] Windows shims for GetCurrentDirectoryW/SetCurrentDirectoryW --- src/shims/env.rs | 54 ++++++++++++- src/shims/foreign_items/windows.rs | 10 +++ src/shims/os_str.rs | 117 +++++++++++++++-------------- tests/run-pass/current_dir.rs | 7 +- 4 files changed, 127 insertions(+), 61 deletions(-) diff --git a/src/shims/env.rs b/src/shims/env.rs index 8a69e725abfc6..78e7c37d9ce75 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -138,8 +138,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } None => { - let envvar_not_found = this.eval_path_scalar(&["std", "sys", "windows", "c", "ERROR_ENVVAR_NOT_FOUND"])?; - this.set_last_error(envvar_not_found.not_undef()?)?; + let envvar_not_found = this.eval_windows("ERROR_ENVVAR_NOT_FOUND")?; + this.set_last_error(envvar_not_found)?; 0 // return zero upon failure } }) @@ -289,6 +289,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx size_op: OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); + let target_os = &this.tcx.sess.target.target.target_os; + assert!(target_os == "linux" || target_os == "macos", "`getcwd` is only available for the UNIX target family"); this.check_no_isolation("getcwd")?; @@ -308,8 +310,35 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(Scalar::null_ptr(&*this.tcx)) } + #[allow(non_snake_case)] + fn GetCurrentDirectoryW( + &mut self, + size_op: OpTy<'tcx, Tag>, // DWORD + buf_op: OpTy<'tcx, Tag>, // LPTSTR + ) -> InterpResult<'tcx, u32> { + let this = self.eval_context_mut(); + this.assert_target_os("windows", "GetCurrentDirectoryW"); + + this.check_no_isolation("GetCurrentDirectoryW")?; + + let size = u64::from(this.read_scalar(size_op)?.to_u32()?); + let buf = this.read_scalar(buf_op)?.not_undef()?; + + // If we cannot get the current directory, we return 0 + match env::current_dir() { + Ok(cwd) => { + let len = this.write_path_to_wide_str(&cwd, buf, size)?.1; + return Ok(u32::try_from(len).unwrap()) + } + Err(e) => this.set_last_error_from_io_error(e)?, + } + Ok(0) + } + fn chdir(&mut self, path_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); + let target_os = &this.tcx.sess.target.target.target_os; + assert!(target_os == "linux" || target_os == "macos", "`getcwd` is only available for the UNIX target family"); this.check_no_isolation("chdir")?; @@ -324,6 +353,27 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } + #[allow(non_snake_case)] + fn SetCurrentDirectoryW ( + &mut self, + path_op: OpTy<'tcx, Tag> // LPCTSTR + ) -> InterpResult<'tcx, i32> { // Returns BOOL(i32 in Windows) + let this = self.eval_context_mut(); + this.assert_target_os("windows", "SetCurrentDirectoryW"); + + this.check_no_isolation("SetCurrentDirectoryW")?; + + let path = this.read_path_from_wide_str(this.read_scalar(path_op)?.not_undef()?)?; + + match env::set_current_dir(path) { + Ok(()) => Ok(1), + Err(e) => { + this.set_last_error_from_io_error(e)?; + Ok(0) + } + } + } + /// Updates the `environ` static. /// The first time it gets called, also initializes `extra.environ`. fn update_environ(&mut self) -> InterpResult<'tcx> { diff --git a/src/shims/foreign_items/windows.rs b/src/shims/foreign_items/windows.rs index 7f3f1d0c2d2ec..ecd1432df0cce 100644 --- a/src/shims/foreign_items/windows.rs +++ b/src/shims/foreign_items/windows.rs @@ -40,6 +40,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_i32(result), dest)?; } + "GetCurrentDirectoryW" => { + let result = this.GetCurrentDirectoryW(args[0], args[1])?; + this.write_scalar(Scalar::from_u32(result), dest)?; + } + + "SetCurrentDirectoryW" => { + let result = this.SetCurrentDirectoryW(args[0])?; + this.write_scalar(Scalar::from_i32(result), dest)?; + } + // File related shims "GetStdHandle" => { let which = this.read_scalar(args[0])?.to_i32()?; diff --git a/src/shims/os_str.rs b/src/shims/os_str.rs index 316d5b0014a7e..c513be4a61f69 100644 --- a/src/shims/os_str.rs +++ b/src/shims/os_str.rs @@ -177,36 +177,24 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx 'mir: 'a, { let this = self.eval_context_ref(); - let os_str = this.read_os_str_from_c_str(scalar)?; + let os_str: &'a OsStr = this.read_os_str_from_c_str(scalar)?; - #[cfg(windows)] - return Ok(if this.tcx.sess.target.target.target_os == "windows" { - // Windows-on-Windows, all fine. - Cow::Borrowed(Path::new(os_str)) - } else { - // Unix target, Windows host. Need to convert target '/' to host '\'. - let converted = os_str - .encode_wide() - .map(|wchar| if wchar == '/' as u16 { '\\' as u16 } else { wchar }) - .collect::>(); - Cow::Owned(PathBuf::from(OsString::from_wide(&converted))) - }); - #[cfg(unix)] - return Ok(if this.tcx.sess.target.target.target_os == "windows" { - // Windows target, Unix host. Need to convert target '\' to host '/'. - let converted = os_str - .as_bytes() - .iter() - .map(|&wchar| if wchar == '/' as u8 { '\\' as u8 } else { wchar }) - .collect::>(); - Cow::Owned(PathBuf::from(OsString::from_vec(converted))) - } else { - // Unix-on-Unix, all is fine. - Cow::Borrowed(Path::new(os_str)) - }); + Ok(match convert_path_separator(os_str, &this.tcx.sess.target.target.target_os) { + Cow::Borrowed(x) => Cow::Borrowed(Path::new(x)), + Cow::Owned(y) => Cow::Owned(PathBuf::from(y)), + }) + } + + /// Read a null-terminated sequence of `u16`s, and perform path separator conversion if needed. + fn read_path_from_wide_str(&self, scalar: Scalar) -> InterpResult<'tcx, PathBuf> { + let this = self.eval_context_ref(); + let os_str: OsString = this.read_os_str_from_wide_str(scalar)?; + + Ok(PathBuf::from(&convert_path_separator(&os_str, &this.tcx.sess.target.target.target_os))) } - /// Write a Path to the machine memory, adjusting path separators if needed. + /// Write a Path to the machine memory (as a null-terminated sequence of bytes), + /// adjusting path separators if needed. fn write_path_to_c_str( &mut self, path: &Path, @@ -214,35 +202,52 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx size: u64, ) -> InterpResult<'tcx, (bool, u64)> { let this = self.eval_context_mut(); - - #[cfg(windows)] - let os_str = if this.tcx.sess.target.target.target_os == "windows" { - // Windows-on-Windows, all fine. - Cow::Borrowed(path.as_os_str()) - } else { - // Unix target, Windows host. Need to convert host '\\' to target '/'. - let converted = path - .as_os_str() - .encode_wide() - .map(|wchar| if wchar == '\\' as u16 { '/' as u16 } else { wchar }) - .collect::>(); - Cow::Owned(OsString::from_wide(&converted)) - }; - #[cfg(unix)] - let os_str = if this.tcx.sess.target.target.target_os == "windows" { - // Windows target, Unix host. Need to convert host '/' to target '\'. - let converted = path - .as_os_str() - .as_bytes() - .iter() - .map(|&wchar| if wchar == '/' as u8 { '\\' as u8 } else { wchar }) - .collect::>(); - Cow::Owned(OsString::from_vec(converted)) - } else { - // Unix-on-Unix, all is fine. - Cow::Borrowed(path.as_os_str()) - }; - + let os_str = convert_path_separator(path.as_os_str(), &this.tcx.sess.target.target.target_os); this.write_os_str_to_c_str(&os_str, scalar, size) } + + /// Write a Path to the machine memory (as a null-terminated sequence of `u16`s), + /// adjusting path separators if needed. + fn write_path_to_wide_str( + &mut self, + path: &Path, + scalar: Scalar, + size: u64, + ) -> InterpResult<'tcx, (bool, u64)> { + let this = self.eval_context_mut(); + let os_str = convert_path_separator(path.as_os_str(), &this.tcx.sess.target.target.target_os); + this.write_os_str_to_wide_str(&os_str, scalar, size) + } +} + +/// Perform path separator conversion if needed. +fn convert_path_separator<'a>( + os_str: &'a OsStr, + target_os: &str, +) -> Cow<'a, OsStr> { + #[cfg(windows)] + return if target_os == "windows" { + // Windows-on-Windows, all fine. + Cow::Borrowed(os_str) + } else { + // Unix target, Windows host. Need to convert host '\\' to target '/'. + let converted = os_str + .encode_wide() + .map(|wchar| if wchar == '\\' as u16 { '/' as u16 } else { wchar }) + .collect::>(); + Cow::Owned(OsString::from_wide(&converted)) + }; + #[cfg(unix)] + return if target_os == "windows" { + // Windows target, Unix host. Need to convert host '/' to target '\'. + let converted = os_str + .as_bytes() + .iter() + .map(|&wchar| if wchar == '/' as u8 { '\\' as u8 } else { wchar }) + .collect::>(); + Cow::Owned(OsString::from_vec(converted)) + } else { + // Unix-on-Unix, all is fine. + Cow::Borrowed(os_str) + }; } diff --git a/tests/run-pass/current_dir.rs b/tests/run-pass/current_dir.rs index 5e896659c85ee..a88f820951ca4 100644 --- a/tests/run-pass/current_dir.rs +++ b/tests/run-pass/current_dir.rs @@ -1,7 +1,6 @@ -// ignore-windows: TODO the windows hook is not done yet // compile-flags: -Zmiri-disable-isolation use std::env; -use std::path::Path; +use std::io::ErrorKind; fn main() { // Test that `getcwd` is available @@ -11,7 +10,9 @@ fn main() { // keep the current directory equal to `cwd`. let parent = cwd.parent().unwrap_or(&cwd); // Test that `chdir` is available - assert!(env::set_current_dir(&Path::new("..")).is_ok()); + assert!(env::set_current_dir("..").is_ok()); // Test that `..` goes to the parent directory assert_eq!(env::current_dir().unwrap(), parent); + // Test that `chdir` to a non-existing directory returns a proper error + assert_eq!(env::set_current_dir("thisdoesnotexist").unwrap_err().kind(), ErrorKind::NotFound); } From fe9ecb50d1dd1b8facd001e634449a9e8d52ad22 Mon Sep 17 00:00:00 2001 From: JOE1994 Date: Sun, 29 Mar 2020 09:46:13 -0400 Subject: [PATCH 1748/3747] Follow-up to reviews from RalfJung 1. Fix 'fn convert_path_separator' in src/shims/os_str.rs 2. Fix 'fn set_last_error_from_io_error' in src/helpers.rs 3. Minor comment fix for 'fn SetCurrentDirectoryW' in src/shims/env.rs --- src/helpers.rs | 10 +++++----- src/shims/env.rs | 2 +- src/shims/os_str.rs | 21 +++++++++++++-------- 3 files changed, 19 insertions(+), 14 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index 751d77a389783..5407eb1205179 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -414,6 +414,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx use std::io::ErrorKind::*; let this = self.eval_context_mut(); let target = &this.tcx.sess.target.target; + let target_os = &target.target_os; let last_error = if target.options.target_family == Some("unix".to_owned()) { this.eval_libc(match e.kind() { ConnectionRefused => "ECONNREFUSED", @@ -434,15 +435,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx throw_unsup_format!("io error {} cannot be transformed into a raw os error", e) } })? - } else { + } else if target_os == "windows" { // FIXME: we have to finish implementing the Windows equivalent of this. this.eval_windows(match e.kind() { NotFound => "ERROR_FILE_NOT_FOUND", - _ => throw_unsup_format!( - "setting the last OS error from an io::Error is yet unsupported for {}.", - target.target_os - ) + _ => throw_unsup_format!("io error {} cannot be transformed into a raw os error", e) })? + } else { + throw_unsup_format!("setting the last OS error from an io::Error is unsupported for {}.", target_os) }; this.set_last_error(last_error) } diff --git a/src/shims/env.rs b/src/shims/env.rs index 78e7c37d9ce75..ce1be90ce6993 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -357,7 +357,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn SetCurrentDirectoryW ( &mut self, path_op: OpTy<'tcx, Tag> // LPCTSTR - ) -> InterpResult<'tcx, i32> { // Returns BOOL(i32 in Windows) + ) -> InterpResult<'tcx, i32> { // Returns BOOL (i32 in Windows) let this = self.eval_context_mut(); this.assert_target_os("windows", "SetCurrentDirectoryW"); diff --git a/src/shims/os_str.rs b/src/shims/os_str.rs index c513be4a61f69..a182950f00655 100644 --- a/src/shims/os_str.rs +++ b/src/shims/os_str.rs @@ -179,7 +179,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_ref(); let os_str: &'a OsStr = this.read_os_str_from_c_str(scalar)?; - Ok(match convert_path_separator(os_str, &this.tcx.sess.target.target.target_os) { + Ok(match convert_path_separator(os_str, &this.tcx.sess.target.target.target_os, false) { Cow::Borrowed(x) => Cow::Borrowed(Path::new(x)), Cow::Owned(y) => Cow::Owned(PathBuf::from(y)), }) @@ -190,7 +190,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_ref(); let os_str: OsString = this.read_os_str_from_wide_str(scalar)?; - Ok(PathBuf::from(&convert_path_separator(&os_str, &this.tcx.sess.target.target.target_os))) + Ok(PathBuf::from(&convert_path_separator(&os_str, &this.tcx.sess.target.target.target_os, false))) } /// Write a Path to the machine memory (as a null-terminated sequence of bytes), @@ -202,7 +202,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx size: u64, ) -> InterpResult<'tcx, (bool, u64)> { let this = self.eval_context_mut(); - let os_str = convert_path_separator(path.as_os_str(), &this.tcx.sess.target.target.target_os); + let os_str = convert_path_separator(path.as_os_str(), &this.tcx.sess.target.target.target_os, true); this.write_os_str_to_c_str(&os_str, scalar, size) } @@ -215,35 +215,40 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx size: u64, ) -> InterpResult<'tcx, (bool, u64)> { let this = self.eval_context_mut(); - let os_str = convert_path_separator(path.as_os_str(), &this.tcx.sess.target.target.target_os); + let os_str = convert_path_separator(path.as_os_str(), &this.tcx.sess.target.target.target_os, true); this.write_os_str_to_wide_str(&os_str, scalar, size) } } /// Perform path separator conversion if needed. +/// if direction == true, Convert from 'host' to 'target'. +/// if direction == false, Convert from 'target' to 'host'. fn convert_path_separator<'a>( os_str: &'a OsStr, target_os: &str, + direction: bool, ) -> Cow<'a, OsStr> { #[cfg(windows)] return if target_os == "windows" { // Windows-on-Windows, all fine. Cow::Borrowed(os_str) } else { - // Unix target, Windows host. Need to convert host '\\' to target '/'. + // Unix target, Windows host. + let (from, to) = if direction { ('\\', '/') } else { ('/', '\\') }; let converted = os_str .encode_wide() - .map(|wchar| if wchar == '\\' as u16 { '/' as u16 } else { wchar }) + .map(|wchar| if wchar == from as u16 { to as u16 } else { wchar }) .collect::>(); Cow::Owned(OsString::from_wide(&converted)) }; #[cfg(unix)] return if target_os == "windows" { - // Windows target, Unix host. Need to convert host '/' to target '\'. + // Windows target, Unix host. + let (from, to) = if direction { ('/', '\\') } else { ('\\', '/') }; let converted = os_str .as_bytes() .iter() - .map(|&wchar| if wchar == '/' as u8 { '\\' as u8 } else { wchar }) + .map(|&wchar| if wchar == from as u8 { to as u8 } else { wchar }) .collect::>(); Cow::Owned(OsString::from_vec(converted)) } else { From 7e0cc8307e80821cdc76c379805245b256071a89 Mon Sep 17 00:00:00 2001 From: JOE1994 Date: Sun, 29 Mar 2020 10:21:02 -0400 Subject: [PATCH 1749/3747] fix 'magic boolean' to enum --- src/shims/os_str.rs | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/src/shims/os_str.rs b/src/shims/os_str.rs index a182950f00655..59cedc6e9df77 100644 --- a/src/shims/os_str.rs +++ b/src/shims/os_str.rs @@ -179,7 +179,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_ref(); let os_str: &'a OsStr = this.read_os_str_from_c_str(scalar)?; - Ok(match convert_path_separator(os_str, &this.tcx.sess.target.target.target_os, false) { + Ok(match convert_path_separator(os_str, &this.tcx.sess.target.target.target_os, PathConversionDirection::TargetToHost) { Cow::Borrowed(x) => Cow::Borrowed(Path::new(x)), Cow::Owned(y) => Cow::Owned(PathBuf::from(y)), }) @@ -190,7 +190,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_ref(); let os_str: OsString = this.read_os_str_from_wide_str(scalar)?; - Ok(PathBuf::from(&convert_path_separator(&os_str, &this.tcx.sess.target.target.target_os, false))) + Ok(PathBuf::from(&convert_path_separator(&os_str, &this.tcx.sess.target.target.target_os, PathConversionDirection::TargetToHost))) } /// Write a Path to the machine memory (as a null-terminated sequence of bytes), @@ -202,7 +202,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx size: u64, ) -> InterpResult<'tcx, (bool, u64)> { let this = self.eval_context_mut(); - let os_str = convert_path_separator(path.as_os_str(), &this.tcx.sess.target.target.target_os, true); + let os_str = convert_path_separator(path.as_os_str(), &this.tcx.sess.target.target.target_os, PathConversionDirection::HostToTarget); this.write_os_str_to_c_str(&os_str, scalar, size) } @@ -215,18 +215,21 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx size: u64, ) -> InterpResult<'tcx, (bool, u64)> { let this = self.eval_context_mut(); - let os_str = convert_path_separator(path.as_os_str(), &this.tcx.sess.target.target.target_os, true); + let os_str = convert_path_separator(path.as_os_str(), &this.tcx.sess.target.target.target_os, PathConversionDirection::HostToTarget); this.write_os_str_to_wide_str(&os_str, scalar, size) } } +enum PathConversionDirection { + HostToTarget, + TargetToHost, +} + /// Perform path separator conversion if needed. -/// if direction == true, Convert from 'host' to 'target'. -/// if direction == false, Convert from 'target' to 'host'. fn convert_path_separator<'a>( os_str: &'a OsStr, target_os: &str, - direction: bool, + direction: PathConversionDirection, ) -> Cow<'a, OsStr> { #[cfg(windows)] return if target_os == "windows" { @@ -234,7 +237,10 @@ fn convert_path_separator<'a>( Cow::Borrowed(os_str) } else { // Unix target, Windows host. - let (from, to) = if direction { ('\\', '/') } else { ('/', '\\') }; + let (from, to) = match direction { + PathConversionDirection::HostToTarget => ('\\', '/'), + PathConversionDirection::TargetToHost => ('/', '\\'), + }; let converted = os_str .encode_wide() .map(|wchar| if wchar == from as u16 { to as u16 } else { wchar }) @@ -244,7 +250,10 @@ fn convert_path_separator<'a>( #[cfg(unix)] return if target_os == "windows" { // Windows target, Unix host. - let (from, to) = if direction { ('/', '\\') } else { ('\\', '/') }; + let (from, to) = match direction { + PathConversionDirection::HostToTarget => ('/', '\\'), + PathConversionDirection::TargetToHost => ('\\', '/'), + }; let converted = os_str .as_bytes() .iter() From 1667ded0d2bc0044f84f2e56aa77f76986199058 Mon Sep 17 00:00:00 2001 From: JOE1994 Date: Sun, 29 Mar 2020 11:15:53 -0400 Subject: [PATCH 1750/3747] fix fn GetCurrentDirectoryW + clarify return types of Windows shims --- src/shims/env.rs | 40 +++++++++++++++++++++------------------- 1 file changed, 21 insertions(+), 19 deletions(-) diff --git a/src/shims/env.rs b/src/shims/env.rs index ce1be90ce6993..dfbeabf2a12bc 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -105,10 +105,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx #[allow(non_snake_case)] fn GetEnvironmentVariableW( &mut self, - name_op: OpTy<'tcx, Tag>, // LPCWSTR - buf_op: OpTy<'tcx, Tag>, // LPWSTR - size_op: OpTy<'tcx, Tag>, // DWORD - ) -> InterpResult<'tcx, u32> { + name_op: OpTy<'tcx, Tag>, // LPCWSTR + buf_op: OpTy<'tcx, Tag>, // LPWSTR + size_op: OpTy<'tcx, Tag>, // DWORD + ) -> InterpResult<'tcx, u32> { // Returns DWORD (u32 in Windows) let this = self.eval_context_mut(); this.assert_target_os("windows", "GetEnvironmentVariableW"); @@ -125,17 +125,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let buf_ptr = this.read_scalar(buf_op)?.not_undef()?; // `buf_size` represents the size in characters. let buf_size = u64::from(this.read_scalar(size_op)?.to_u32()?); - let (success, len) = this.write_os_str_to_wide_str(&var, buf_ptr, buf_size)?; - - if success { - // If the function succeeds, the return value is the number of characters stored in the buffer pointed to by lpBuffer, - // not including the terminating null character. - u32::try_from(len).unwrap() - } else { - // If lpBuffer is not large enough to hold the data, the return value is the buffer size, in characters, - // required to hold the string and its terminating null character and the contents of lpBuffer are undefined. - u32::try_from(len).unwrap().checked_add(1).unwrap() - } + HowWasBufferSize(this.write_os_str_to_wide_str(&var, buf_ptr, buf_size)?) } None => { let envvar_not_found = this.eval_windows("ERROR_ENVVAR_NOT_FOUND")?; @@ -326,10 +316,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // If we cannot get the current directory, we return 0 match env::current_dir() { - Ok(cwd) => { - let len = this.write_path_to_wide_str(&cwd, buf, size)?.1; - return Ok(u32::try_from(len).unwrap()) - } + Ok(cwd) => + return Ok(HowWasBufferSize(this.write_path_to_wide_str(&cwd, buf, size)?)), Err(e) => this.set_last_error_from_io_error(e)?, } Ok(0) @@ -411,3 +399,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(()) } } + +// Local helper function to be used in Windows shims +#[allow(non_snake_case)] +fn HowWasBufferSize((success, len): (bool, u64)) -> u32 { + if success { + // If the function succeeds, the return value is the number of characters stored in the buffer pointed to by lpBuffer, + // not including the terminating null character. + u32::try_from(len).unwrap() + } else { + // If lpBuffer is not large enough to hold the data, the return value is the buffer size, in characters, + // required to hold the string and its terminating null character and the contents of lpBuffer are undefined. + u32::try_from(len.checked_add(1).unwrap()).unwrap() + } +} From 1b0abc5797fa4e3d32a74b80ed653da1a9ab98ef Mon Sep 17 00:00:00 2001 From: JOE1994 Date: Sun, 29 Mar 2020 13:10:23 -0400 Subject: [PATCH 1751/3747] small refactorings to 'src/shims/os_str.rs' & 'src/shims/env.rs' --- src/shims/env.rs | 17 +++---- src/shims/os_str.rs | 105 ++++++++++++++++++++++---------------------- 2 files changed, 62 insertions(+), 60 deletions(-) diff --git a/src/shims/env.rs b/src/shims/env.rs index dfbeabf2a12bc..350d76bc9dacd 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -125,7 +125,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let buf_ptr = this.read_scalar(buf_op)?.not_undef()?; // `buf_size` represents the size in characters. let buf_size = u64::from(this.read_scalar(size_op)?.to_u32()?); - HowWasBufferSize(this.write_os_str_to_wide_str(&var, buf_ptr, buf_size)?) + windows_check_buffer_size(this.write_os_str_to_wide_str(&var, buf_ptr, buf_size)?) } None => { let envvar_not_found = this.eval_windows("ERROR_ENVVAR_NOT_FOUND")?; @@ -317,7 +317,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // If we cannot get the current directory, we return 0 match env::current_dir() { Ok(cwd) => - return Ok(HowWasBufferSize(this.write_path_to_wide_str(&cwd, buf, size)?)), + return Ok(windows_check_buffer_size(this.write_path_to_wide_str(&cwd, buf, size)?)), Err(e) => this.set_last_error_from_io_error(e)?, } Ok(0) @@ -400,16 +400,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } -// Local helper function to be used in Windows shims -#[allow(non_snake_case)] -fn HowWasBufferSize((success, len): (bool, u64)) -> u32 { +/// Check whether an operation that writes to a target buffer was successful. +/// Accordingly select return value. +/// Local helper function to be used in Windows shims. +fn windows_check_buffer_size((success, len): (bool, u64)) -> u32 { if success { - // If the function succeeds, the return value is the number of characters stored in the buffer pointed to by lpBuffer, + // If the function succeeds, the return value is the number of characters stored in the target buffer, // not including the terminating null character. u32::try_from(len).unwrap() } else { - // If lpBuffer is not large enough to hold the data, the return value is the buffer size, in characters, - // required to hold the string and its terminating null character and the contents of lpBuffer are undefined. + // If the target buffer was not large enough to hold the data, the return value is the buffer size, in characters, + // required to hold the string and its terminating null character. u32::try_from(len.checked_add(1).unwrap()).unwrap() } } diff --git a/src/shims/os_str.rs b/src/shims/os_str.rs index 59cedc6e9df77..74932ef6ca4ed 100644 --- a/src/shims/os_str.rs +++ b/src/shims/os_str.rs @@ -13,6 +13,53 @@ use rustc::ty::layout::LayoutOf; use crate::*; +/// Represent how path separator conversion should be done. +enum Pathconversion { + HostToTarget, + TargetToHost, +} + +/// Perform path separator conversion if needed. +fn convert_path_separator<'a>( + os_str: &'a OsStr, + target_os: &str, + direction: Pathconversion, +) -> Cow<'a, OsStr> { + #[cfg(windows)] + return if target_os == "windows" { + // Windows-on-Windows, all fine. + Cow::Borrowed(os_str) + } else { + // Unix target, Windows host. + let (from, to) = match direction { + Pathconversion::HostToTarget => ('\\', '/'), + Pathconversion::TargetToHost => ('/', '\\'), + }; + let converted = os_str + .encode_wide() + .map(|wchar| if wchar == from as u16 { to as u16 } else { wchar }) + .collect::>(); + Cow::Owned(OsString::from_wide(&converted)) + }; + #[cfg(unix)] + return if target_os == "windows" { + // Windows target, Unix host. + let (from, to) = match direction { + Pathconversion::HostToTarget => ('/', '\\'), + Pathconversion::TargetToHost => ('\\', '/'), + }; + let converted = os_str + .as_bytes() + .iter() + .map(|&wchar| if wchar == from as u8 { to as u8 } else { wchar }) + .collect::>(); + Cow::Owned(OsString::from_vec(converted)) + } else { + // Unix-on-Unix, all is fine. + Cow::Borrowed(os_str) + }; +} + impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { /// Helper function to read an OsString from a null-terminated sequence of bytes, which is what @@ -177,9 +224,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx 'mir: 'a, { let this = self.eval_context_ref(); - let os_str: &'a OsStr = this.read_os_str_from_c_str(scalar)?; + let os_str = this.read_os_str_from_c_str(scalar)?; - Ok(match convert_path_separator(os_str, &this.tcx.sess.target.target.target_os, PathConversionDirection::TargetToHost) { + Ok(match convert_path_separator(os_str, &this.tcx.sess.target.target.target_os, Pathconversion::TargetToHost) { Cow::Borrowed(x) => Cow::Borrowed(Path::new(x)), Cow::Owned(y) => Cow::Owned(PathBuf::from(y)), }) @@ -188,9 +235,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// Read a null-terminated sequence of `u16`s, and perform path separator conversion if needed. fn read_path_from_wide_str(&self, scalar: Scalar) -> InterpResult<'tcx, PathBuf> { let this = self.eval_context_ref(); - let os_str: OsString = this.read_os_str_from_wide_str(scalar)?; + let os_str = this.read_os_str_from_wide_str(scalar)?; - Ok(PathBuf::from(&convert_path_separator(&os_str, &this.tcx.sess.target.target.target_os, PathConversionDirection::TargetToHost))) + Ok(PathBuf::from(&convert_path_separator(&os_str, &this.tcx.sess.target.target.target_os, Pathconversion::TargetToHost))) } /// Write a Path to the machine memory (as a null-terminated sequence of bytes), @@ -202,7 +249,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx size: u64, ) -> InterpResult<'tcx, (bool, u64)> { let this = self.eval_context_mut(); - let os_str = convert_path_separator(path.as_os_str(), &this.tcx.sess.target.target.target_os, PathConversionDirection::HostToTarget); + let os_str = convert_path_separator(path.as_os_str(), &this.tcx.sess.target.target.target_os, Pathconversion::HostToTarget); this.write_os_str_to_c_str(&os_str, scalar, size) } @@ -215,53 +262,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx size: u64, ) -> InterpResult<'tcx, (bool, u64)> { let this = self.eval_context_mut(); - let os_str = convert_path_separator(path.as_os_str(), &this.tcx.sess.target.target.target_os, PathConversionDirection::HostToTarget); + let os_str = convert_path_separator(path.as_os_str(), &this.tcx.sess.target.target.target_os, Pathconversion::HostToTarget); this.write_os_str_to_wide_str(&os_str, scalar, size) } } - -enum PathConversionDirection { - HostToTarget, - TargetToHost, -} - -/// Perform path separator conversion if needed. -fn convert_path_separator<'a>( - os_str: &'a OsStr, - target_os: &str, - direction: PathConversionDirection, -) -> Cow<'a, OsStr> { - #[cfg(windows)] - return if target_os == "windows" { - // Windows-on-Windows, all fine. - Cow::Borrowed(os_str) - } else { - // Unix target, Windows host. - let (from, to) = match direction { - PathConversionDirection::HostToTarget => ('\\', '/'), - PathConversionDirection::TargetToHost => ('/', '\\'), - }; - let converted = os_str - .encode_wide() - .map(|wchar| if wchar == from as u16 { to as u16 } else { wchar }) - .collect::>(); - Cow::Owned(OsString::from_wide(&converted)) - }; - #[cfg(unix)] - return if target_os == "windows" { - // Windows target, Unix host. - let (from, to) = match direction { - PathConversionDirection::HostToTarget => ('/', '\\'), - PathConversionDirection::TargetToHost => ('\\', '/'), - }; - let converted = os_str - .as_bytes() - .iter() - .map(|&wchar| if wchar == from as u8 { to as u8 } else { wchar }) - .collect::>(); - Cow::Owned(OsString::from_vec(converted)) - } else { - // Unix-on-Unix, all is fine. - Cow::Borrowed(os_str) - }; -} From 9bdb4bbbbf17c2d94eece96ddc6114a3c9104f73 Mon Sep 17 00:00:00 2001 From: JOE1994 Date: Sun, 29 Mar 2020 13:13:42 -0400 Subject: [PATCH 1752/3747] Move definition of 'fn windows_check_buffer_size' to top of 'src/shims/env.rs' --- src/shims/env.rs | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/src/shims/env.rs b/src/shims/env.rs index 350d76bc9dacd..5846f51b90428 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -10,6 +10,21 @@ use rustc_data_structures::fx::FxHashMap; use rustc::ty::layout::Size; use rustc_mir::interpret::Pointer; +/// Check whether an operation that writes to a target buffer was successful. +/// Accordingly select return value. +/// Local helper function to be used in Windows shims. +fn windows_check_buffer_size((success, len): (bool, u64)) -> u32 { + if success { + // If the function succeeds, the return value is the number of characters stored in the target buffer, + // not including the terminating null character. + u32::try_from(len).unwrap() + } else { + // If the target buffer was not large enough to hold the data, the return value is the buffer size, in characters, + // required to hold the string and its terminating null character. + u32::try_from(len.checked_add(1).unwrap()).unwrap() + } +} + #[derive(Default)] pub struct EnvVars<'tcx> { /// Stores pointers to the environment variables. These variables must be stored as @@ -399,18 +414,3 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(()) } } - -/// Check whether an operation that writes to a target buffer was successful. -/// Accordingly select return value. -/// Local helper function to be used in Windows shims. -fn windows_check_buffer_size((success, len): (bool, u64)) -> u32 { - if success { - // If the function succeeds, the return value is the number of characters stored in the target buffer, - // not including the terminating null character. - u32::try_from(len).unwrap() - } else { - // If the target buffer was not large enough to hold the data, the return value is the buffer size, in characters, - // required to hold the string and its terminating null character. - u32::try_from(len.checked_add(1).unwrap()).unwrap() - } -} From a458cf3fe619764abd938eb6d5b27dd261bd8127 Mon Sep 17 00:00:00 2001 From: JOE1994 Date: Sun, 29 Mar 2020 14:19:59 -0400 Subject: [PATCH 1753/3747] make 'fn convert_path_separator' to take Cow<> (to remove unnecessary allocation) --- src/shims/os_str.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/shims/os_str.rs b/src/shims/os_str.rs index 74932ef6ca4ed..0f81c24c252f5 100644 --- a/src/shims/os_str.rs +++ b/src/shims/os_str.rs @@ -21,14 +21,14 @@ enum Pathconversion { /// Perform path separator conversion if needed. fn convert_path_separator<'a>( - os_str: &'a OsStr, + os_str: Cow<'a, OsStr>, target_os: &str, direction: Pathconversion, ) -> Cow<'a, OsStr> { #[cfg(windows)] return if target_os == "windows" { // Windows-on-Windows, all fine. - Cow::Borrowed(os_str) + os_str } else { // Unix target, Windows host. let (from, to) = match direction { @@ -56,7 +56,7 @@ fn convert_path_separator<'a>( Cow::Owned(OsString::from_vec(converted)) } else { // Unix-on-Unix, all is fine. - Cow::Borrowed(os_str) + os_str }; } @@ -226,7 +226,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_ref(); let os_str = this.read_os_str_from_c_str(scalar)?; - Ok(match convert_path_separator(os_str, &this.tcx.sess.target.target.target_os, Pathconversion::TargetToHost) { + Ok(match convert_path_separator(Cow::Borrowed(os_str), &this.tcx.sess.target.target.target_os, Pathconversion::TargetToHost) { Cow::Borrowed(x) => Cow::Borrowed(Path::new(x)), Cow::Owned(y) => Cow::Owned(PathBuf::from(y)), }) @@ -237,7 +237,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_ref(); let os_str = this.read_os_str_from_wide_str(scalar)?; - Ok(PathBuf::from(&convert_path_separator(&os_str, &this.tcx.sess.target.target.target_os, Pathconversion::TargetToHost))) + Ok(PathBuf::from(&convert_path_separator(Cow::Borrowed(&os_str), &this.tcx.sess.target.target.target_os, Pathconversion::TargetToHost))) } /// Write a Path to the machine memory (as a null-terminated sequence of bytes), @@ -249,7 +249,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx size: u64, ) -> InterpResult<'tcx, (bool, u64)> { let this = self.eval_context_mut(); - let os_str = convert_path_separator(path.as_os_str(), &this.tcx.sess.target.target.target_os, Pathconversion::HostToTarget); + let os_str = convert_path_separator(Cow::Borrowed(path.as_os_str()), &this.tcx.sess.target.target.target_os, Pathconversion::HostToTarget); this.write_os_str_to_c_str(&os_str, scalar, size) } @@ -262,7 +262,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx size: u64, ) -> InterpResult<'tcx, (bool, u64)> { let this = self.eval_context_mut(); - let os_str = convert_path_separator(path.as_os_str(), &this.tcx.sess.target.target.target_os, Pathconversion::HostToTarget); + let os_str = convert_path_separator(Cow::Borrowed(path.as_os_str()), &this.tcx.sess.target.target.target_os, Pathconversion::HostToTarget); this.write_os_str_to_wide_str(&os_str, scalar, size) } } From ed1305d986a3fff39da36de2c7ed6a3179d33c9a Mon Sep 17 00:00:00 2001 From: JOE1994 Date: Sun, 29 Mar 2020 16:01:07 -0400 Subject: [PATCH 1754/3747] fix fn read_path_from_wide_str --- src/shims/os_str.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shims/os_str.rs b/src/shims/os_str.rs index 0f81c24c252f5..49afa3bdc362f 100644 --- a/src/shims/os_str.rs +++ b/src/shims/os_str.rs @@ -237,7 +237,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_ref(); let os_str = this.read_os_str_from_wide_str(scalar)?; - Ok(PathBuf::from(&convert_path_separator(Cow::Borrowed(&os_str), &this.tcx.sess.target.target.target_os, Pathconversion::TargetToHost))) + Ok(convert_path_separator(Cow::Owned(os_str), &this.tcx.sess.target.target.target_os, Pathconversion::TargetToHost).into_owned().into()) } /// Write a Path to the machine memory (as a null-terminated sequence of bytes), From 808709c2889e11b079205fbbf830cd58d1f3711b Mon Sep 17 00:00:00 2001 From: David Cook Date: Sun, 29 Mar 2020 16:03:05 -0500 Subject: [PATCH 1755/3747] Add support for OpenOptions::create_new()/O_EXCL --- src/shims/fs.rs | 9 ++++++++- tests/run-pass/fs.rs | 19 ++++++++++++++++++- 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/src/shims/fs.rs b/src/shims/fs.rs index 5f8be275b2e43..04ca538f8b6bb 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -288,8 +288,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } let o_creat = this.eval_libc_i32("O_CREAT")?; if flag & o_creat != 0 { - options.create(true); mirror |= o_creat; + + let o_excl = this.eval_libc_i32("O_EXCL")?; + if flag & o_excl != 0 { + mirror |= o_excl; + options.create_new(true); + } else { + options.create(true); + } } let o_cloexec = this.eval_libc_i32("O_CLOEXEC")?; if flag & o_cloexec != 0 { diff --git a/tests/run-pass/fs.rs b/tests/run-pass/fs.rs index 104ba46c3e458..d8b6e5b445755 100644 --- a/tests/run-pass/fs.rs +++ b/tests/run-pass/fs.rs @@ -1,13 +1,16 @@ // ignore-windows: File handling is not implemented yet // compile-flags: -Zmiri-disable-isolation -use std::fs::{File, create_dir, read_dir, remove_dir, remove_dir_all, remove_file, rename}; +use std::fs::{ + File, create_dir, OpenOptions, read_dir, remove_dir, remove_dir_all, remove_file, rename, +}; use std::io::{Read, Write, ErrorKind, Result, Seek, SeekFrom}; use std::path::{PathBuf, Path}; fn main() { test_file(); test_file_clone(); + test_file_create_new(); test_seek(); test_metadata(); test_symlink(); @@ -85,6 +88,20 @@ fn test_file_clone() { remove_file(&path).unwrap(); } +fn test_file_create_new() { + let path = prepare("miri_test_fs_file_create_new.txt"); + + // Creating a new file that doesn't yet exist should succeed. + OpenOptions::new().write(true).create_new(true).open(&path).unwrap(); + // Creating a new file that already exists should fail. + assert_eq!(ErrorKind::AlreadyExists, OpenOptions::new().write(true).create_new(true).open(&path).unwrap_err().kind()); + // Optionally creating a new file that already exists should succeed. + OpenOptions::new().write(true).create(true).open(&path).unwrap(); + + // Clean up + remove_file(&path).unwrap(); +} + fn test_seek() { let bytes = b"Hello, entire World!\n"; let path = prepare_with_content("miri_test_fs_seek.txt", bytes); From 5ff7eef2ffbaeef58293e757b0b092ff1afdf411 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 30 Mar 2020 10:23:04 +0200 Subject: [PATCH 1756/3747] rustup; fix for TyLayout rename --- rust-version | 2 +- src/helpers.rs | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/rust-version b/rust-version index 0b3196a7a2806..42644dc121401 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -150322f86d441752874a8bed603d71119f190b8b +0afdf43dc1d9be4c8b422840166b51dd99e56a16 diff --git a/src/helpers.rs b/src/helpers.rs index 5407eb1205179..fc9bb19c882a4 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -4,7 +4,7 @@ use std::mem; use rustc::mir; use rustc::ty::{ self, - layout::{self, LayoutOf, Size, TyLayout}, + layout::{self, LayoutOf, Size, TyAndLayout}, List, TyCtxt, }; use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX}; @@ -84,8 +84,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx self.eval_libc(name)?.to_i32() } - /// Helper function to get the `TyLayout` of a `libc` type - fn libc_ty_layout(&mut self, name: &str) -> InterpResult<'tcx, TyLayout<'tcx>> { + /// Helper function to get the `TyAndLayout` of a `libc` type + fn libc_ty_layout(&mut self, name: &str) -> InterpResult<'tcx, TyAndLayout<'tcx>> { let this = self.eval_context_mut(); let ty = this.resolve_path(&["libc", name]).monomorphic_ty(*this.tcx); this.layout_of(ty) @@ -469,7 +469,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx pub fn immty_from_int_checked<'tcx>( int: impl Into, - layout: TyLayout<'tcx>, + layout: TyAndLayout<'tcx>, ) -> InterpResult<'tcx, ImmTy<'tcx, Tag>> { let int = int.into(); Ok(ImmTy::try_from_int(int, layout).ok_or_else(|| { @@ -479,7 +479,7 @@ pub fn immty_from_int_checked<'tcx>( pub fn immty_from_uint_checked<'tcx>( int: impl Into, - layout: TyLayout<'tcx>, + layout: TyAndLayout<'tcx>, ) -> InterpResult<'tcx, ImmTy<'tcx, Tag>> { let int = int.into(); Ok(ImmTy::try_from_uint(int, layout).ok_or_else(|| { From 846ce3c2616ea2fe1a3d5f040953dc5b50d2b2a0 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 30 Mar 2020 10:23:16 +0200 Subject: [PATCH 1757/3747] test const-generic Vec::from(array) --- tests/run-pass/arrays.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/tests/run-pass/arrays.rs b/tests/run-pass/arrays.rs index b760d515395cf..9589ffa1724c2 100644 --- a/tests/run-pass/arrays.rs +++ b/tests/run-pass/arrays.rs @@ -35,7 +35,7 @@ fn slice_index() -> u8 { arr[5] } -fn try_from() { +fn from() { const N: usize = 16; type Array = [u8; N]; let array: Array = [0; N]; @@ -43,6 +43,9 @@ fn try_from() { let result = <&Array>::try_from(slice); assert_eq!(&array, result.unwrap()); + + let vec = Vec::from(array); + assert_eq!(vec.len(), N); } fn eq() { @@ -69,7 +72,7 @@ fn main() { assert_eq!(array_array(), [[5, 4], [3, 2], [1, 0]]); assert_eq!(array_repeat(), [42; 8]); assert_eq!(mini_array(), [42]); - try_from(); + from(); eq(); debug(); } From 8948a29a4cb3c6940e3863886e99bacfa1f325ae Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 30 Mar 2020 11:07:32 +0200 Subject: [PATCH 1758/3747] adjust for librustc rename; reduce 'extern crate' to rustc crates --- CONTRIBUTING.md | 2 +- benches/helpers/miri_helper.rs | 10 +++------- rust-version | 2 +- src/bin/miri-rustc-tests.rs | 12 +++++------- src/bin/miri.rs | 13 ++++--------- src/diagnostics.rs | 2 ++ src/eval.rs | 4 ++-- src/helpers.rs | 6 ++++-- src/intptrcast.rs | 3 ++- src/lib.rs | 6 +----- src/machine.rs | 5 +++-- src/operator.rs | 8 +++++--- src/range_map.rs | 2 +- src/shims/dlsym.rs | 2 +- src/shims/env.rs | 2 +- src/shims/foreign_items.rs | 6 +++--- src/shims/foreign_items/posix.rs | 6 ++++-- src/shims/foreign_items/posix/linux.rs | 2 +- src/shims/foreign_items/posix/macos.rs | 2 +- src/shims/foreign_items/windows.rs | 4 ++-- src/shims/fs.rs | 2 +- src/shims/intrinsics.rs | 6 +++--- src/shims/mod.rs | 4 +++- src/shims/os_str.rs | 2 +- src/shims/panic.rs | 8 +++++--- src/shims/tls.rs | 4 +++- src/stacked_borrows.rs | 6 ++++-- 27 files changed, 67 insertions(+), 64 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 573f9f6ef6e41..c7bfe6ccf1c14 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -79,7 +79,7 @@ MIRI_LOG=info ./miri run tests/run-pass/vecs.rs ``` Setting `MIRI_LOG` like this will configure logging for Miri itself as well as -the `rustc::mir::interpret` and `rustc_mir::interpret` modules in rustc. You +the `rustc_middle::mir::interpret` and `rustc_mir::interpret` modules in rustc. You can also do more targeted configuration, e.g. the following helps debug the stacked borrows implementation: diff --git a/benches/helpers/miri_helper.rs b/benches/helpers/miri_helper.rs index b478a7d23eb98..589a95b668f37 100644 --- a/benches/helpers/miri_helper.rs +++ b/benches/helpers/miri_helper.rs @@ -1,17 +1,13 @@ -extern crate getopts; -extern crate miri; -extern crate rustc; extern crate rustc_driver; extern crate rustc_hir; extern crate rustc_interface; -extern crate test; -use self::miri::eval_main; -use crate::test::Bencher; use rustc_hir::def_id::LOCAL_CRATE; use rustc_driver::Compilation; use rustc_interface::{interface, Queries}; +use crate::test::Bencher; + struct MiriCompilerCalls<'a> { bencher: &'a mut Bencher, } @@ -30,7 +26,7 @@ impl rustc_driver::Callbacks for MiriCompilerCalls<'_> { self.bencher.iter(|| { let config = miri::MiriConfig::default(); - eval_main(tcx, entry_def_id, config); + miri::eval_main(tcx, entry_def_id, config); }); }); diff --git a/rust-version b/rust-version index 42644dc121401..4f4cff76583b2 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -0afdf43dc1d9be4c8b422840166b51dd99e56a16 +8926bb497d9b127eb318aea5aed0e745d8381591 diff --git a/src/bin/miri-rustc-tests.rs b/src/bin/miri-rustc-tests.rs index ab692e18f9097..97292cf1dbe5c 100644 --- a/src/bin/miri-rustc-tests.rs +++ b/src/bin/miri-rustc-tests.rs @@ -1,6 +1,6 @@ #![feature(rustc_private)] -extern crate miri; -extern crate rustc; + +extern crate rustc_middle; extern crate rustc_driver; extern crate rustc_hir; extern crate rustc_interface; @@ -11,15 +11,13 @@ use std::io::Write; use std::path::Path; use std::sync::{Arc, Mutex}; -use rustc::ty::TyCtxt; +use rustc_middle::ty::TyCtxt; use rustc_driver::Compilation; use rustc_hir as hir; use rustc_hir::def_id::LOCAL_CRATE; use rustc_hir::itemlikevisit; use rustc_interface::{interface, Queries}; -use miri::MiriConfig; - struct MiriCompilerCalls { /// whether we are building for the host host_target: bool, @@ -42,7 +40,7 @@ impl rustc_driver::Callbacks for MiriCompilerCalls { .iter() .any(|attr| attr.check_name(rustc_span::symbol::sym::test)) { - let config = MiriConfig::default(); + let config = miri::MiriConfig::default(); let did = self.0.hir().body_owner_def_id(body_id); println!("running test: {}", self.0.def_path_debug_str(did)); miri::eval_main(self.0, did, config); @@ -55,7 +53,7 @@ impl rustc_driver::Callbacks for MiriCompilerCalls { } tcx.hir().krate().visit_all_item_likes(&mut Visitor(tcx)); } else if let Some((entry_def_id, _)) = tcx.entry_fn(LOCAL_CRATE) { - let config = MiriConfig::default(); + let config = miri::MiriConfig::default(); miri::eval_main(tcx, entry_def_id, config); compiler.session().abort_if_errors(); diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 4a54867c99640..14d78053c0fd6 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -1,12 +1,6 @@ #![feature(rustc_private)] -extern crate env_logger; -extern crate getopts; -#[macro_use] -extern crate log; -extern crate log_settings; -extern crate miri; -extern crate rustc; +extern crate rustc_middle; extern crate rustc_driver; extern crate rustc_hir; extern crate rustc_interface; @@ -17,12 +11,13 @@ use std::env; use std::str::FromStr; use hex::FromHexError; +use log::debug; use rustc_session::CtfeBacktrace; use rustc_driver::Compilation; use rustc_hir::def_id::LOCAL_CRATE; use rustc_interface::{interface, Queries}; -use rustc::ty::TyCtxt; +use rustc_middle::ty::TyCtxt; struct MiriCompilerCalls { miri_config: miri::MiriConfig, @@ -84,7 +79,7 @@ fn init_late_loggers(tcx: TyCtxt<'_>) { if log::Level::from_str(&var).is_ok() { env::set_var( "RUSTC_LOG", - &format!("rustc::mir::interpret={0},rustc_mir::interpret={0}", var), + &format!("rustc_middle::mir::interpret={0},rustc_mir::interpret={0}", var), ); } else { env::set_var("RUSTC_LOG", &var); diff --git a/src/diagnostics.rs b/src/diagnostics.rs index 2e4023e0b5bf8..a528960cb2628 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -1,6 +1,8 @@ use std::cell::RefCell; use std::fmt; +use log::trace; + use rustc_span::DUMMY_SP; use crate::*; diff --git a/src/eval.rs b/src/eval.rs index 9838bd1e8cc24..a4867bd5de46b 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -6,8 +6,8 @@ use std::convert::TryFrom; use rand::rngs::StdRng; use rand::SeedableRng; -use rustc::ty::layout::LayoutOf; -use rustc::ty::{self, TyCtxt}; +use rustc_middle::ty::layout::LayoutOf; +use rustc_middle::ty::{self, TyCtxt}; use rustc_hir::def_id::DefId; use crate::*; diff --git a/src/helpers.rs b/src/helpers.rs index fc9bb19c882a4..15f1b286de228 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -1,8 +1,10 @@ use std::convert::TryFrom; use std::mem; -use rustc::mir; -use rustc::ty::{ +use log::trace; + +use rustc_middle::mir; +use rustc_middle::ty::{ self, layout::{self, LayoutOf, Size, TyAndLayout}, List, TyCtxt, diff --git a/src/intptrcast.rs b/src/intptrcast.rs index 20a3b79980478..8eb28e4f4700a 100644 --- a/src/intptrcast.rs +++ b/src/intptrcast.rs @@ -2,10 +2,11 @@ use std::cell::RefCell; use std::cmp::max; use std::collections::hash_map::Entry; +use log::trace; use rand::Rng; use rustc_data_structures::fx::FxHashMap; -use rustc::ty::layout::HasDataLayout; +use rustc_middle::ty::layout::HasDataLayout; use rustc_mir::interpret::{AllocCheck, AllocId, InterpResult, Memory, Machine, Pointer, PointerArithmetic}; use rustc_target::abi::Size; diff --git a/src/lib.rs b/src/lib.rs index 4fa78b7ec88eb..c04fbfeab98ca 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -7,13 +7,9 @@ #![warn(rust_2018_idioms)] #![allow(clippy::cast_lossless)] -#[macro_use] -extern crate log; -// From rustc. extern crate rustc_apfloat; extern crate rustc_ast; -#[macro_use] -extern crate rustc; +#[macro_use] extern crate rustc_middle; extern crate rustc_data_structures; extern crate rustc_hir; extern crate rustc_mir; diff --git a/src/machine.rs b/src/machine.rs index 84329b8fd3cd6..4b7f3a76569f1 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -7,11 +7,12 @@ use std::num::NonZeroU64; use std::rc::Rc; use std::time::Instant; +use log::trace; use rand::rngs::StdRng; use rustc_data_structures::fx::FxHashMap; -use rustc::mir; -use rustc::ty::{ +use rustc_middle::mir; +use rustc_middle::ty::{ self, layout::{LayoutOf, Size}, Ty, diff --git a/src/operator.rs b/src/operator.rs index c494e4ff8c724..2232be713ed58 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -1,7 +1,9 @@ use std::convert::TryFrom; -use rustc::mir; -use rustc::ty::{ +use log::trace; + +use rustc_middle::mir; +use rustc_middle::ty::{ layout::{LayoutOf, Size}, Ty, }; @@ -33,7 +35,7 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { left: ImmTy<'tcx, Tag>, right: ImmTy<'tcx, Tag>, ) -> InterpResult<'tcx, (Scalar, bool, Ty<'tcx>)> { - use rustc::mir::BinOp::*; + use rustc_middle::mir::BinOp::*; trace!("ptr_op: {:?} {:?} {:?}", *left, bin_op, *right); diff --git a/src/range_map.rs b/src/range_map.rs index 01abaef27fd2d..1d12d8a1ba652 100644 --- a/src/range_map.rs +++ b/src/range_map.rs @@ -7,7 +7,7 @@ use std::ops; -use rustc::ty::layout::Size; +use rustc_middle::ty::layout::Size; #[derive(Clone, Debug)] struct Elem { diff --git a/src/shims/dlsym.rs b/src/shims/dlsym.rs index b0e1850ec55d0..b5fe3cb7229c1 100644 --- a/src/shims/dlsym.rs +++ b/src/shims/dlsym.rs @@ -1,4 +1,4 @@ -use rustc::mir; +use rustc_middle::mir; use crate::*; diff --git a/src/shims/env.rs b/src/shims/env.rs index 5846f51b90428..76d1de5d9a649 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -7,7 +7,7 @@ use crate::rustc_target::abi::LayoutOf; use crate::*; use rustc_data_structures::fx::FxHashMap; -use rustc::ty::layout::Size; +use rustc_middle::ty::layout::Size; use rustc_mir::interpret::Pointer; /// Check whether an operation that writes to a target buffer was successful. diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 21c4b02e70852..da2f9d439c7e4 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -4,9 +4,9 @@ mod posix; use std::{convert::{TryInto, TryFrom}, iter}; use rustc_hir::def_id::DefId; -use rustc::mir; -use rustc::ty; -use rustc::ty::layout::{Align, Size}; +use rustc_middle::mir; +use rustc_middle::ty; +use rustc_middle::ty::layout::{Align, Size}; use rustc_apfloat::Float; use rustc_span::symbol::sym; use rustc_ast::attr; diff --git a/src/shims/foreign_items/posix.rs b/src/shims/foreign_items/posix.rs index 1a9e91eded7fe..28161592985ac 100644 --- a/src/shims/foreign_items/posix.rs +++ b/src/shims/foreign_items/posix.rs @@ -3,9 +3,11 @@ mod macos; use std::convert::TryFrom; +use log::trace; + use crate::*; -use rustc::mir; -use rustc::ty::layout::{Align, LayoutOf, Size}; +use rustc_middle::mir; +use rustc_middle::ty::layout::{Align, LayoutOf, Size}; impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { diff --git a/src/shims/foreign_items/posix/linux.rs b/src/shims/foreign_items/posix/linux.rs index f56d5b3959c75..286bd5798b049 100644 --- a/src/shims/foreign_items/posix/linux.rs +++ b/src/shims/foreign_items/posix/linux.rs @@ -1,5 +1,5 @@ use crate::*; -use rustc::mir; +use rustc_middle::mir; impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { diff --git a/src/shims/foreign_items/posix/macos.rs b/src/shims/foreign_items/posix/macos.rs index cc58924a54abc..44c45d90c1987 100644 --- a/src/shims/foreign_items/posix/macos.rs +++ b/src/shims/foreign_items/posix/macos.rs @@ -1,5 +1,5 @@ use crate::*; -use rustc::mir; +use rustc_middle::mir; impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { diff --git a/src/shims/foreign_items/windows.rs b/src/shims/foreign_items/windows.rs index ecd1432df0cce..f39d477f8278e 100644 --- a/src/shims/foreign_items/windows.rs +++ b/src/shims/foreign_items/windows.rs @@ -1,6 +1,6 @@ use crate::*; -use rustc::mir; -use rustc::ty::layout::Size; +use rustc_middle::mir; +use rustc_middle::ty::layout::Size; use std::iter; impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} diff --git a/src/shims/fs.rs b/src/shims/fs.rs index 5f8be275b2e43..75e90384fd568 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -6,7 +6,7 @@ use std::path::Path; use std::time::SystemTime; use rustc_data_structures::fx::FxHashMap; -use rustc::ty::layout::{Align, LayoutOf, Size}; +use rustc_middle::ty::layout::{Align, LayoutOf, Size}; use crate::stacked_borrows::Tag; use crate::*; diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index fda52429e515a..641b8b2563634 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -1,9 +1,9 @@ use std::iter; use std::convert::TryFrom; -use rustc::mir; -use rustc::ty; -use rustc::ty::layout::{Align, LayoutOf}; +use rustc_middle::mir; +use rustc_middle::ty; +use rustc_middle::ty::layout::{Align, LayoutOf}; use rustc_apfloat::Float; use rustc_span::source_map::Span; diff --git a/src/shims/mod.rs b/src/shims/mod.rs index 731dc2fedc578..e5db537cff1f7 100644 --- a/src/shims/mod.rs +++ b/src/shims/mod.rs @@ -10,7 +10,9 @@ pub mod tls; use std::convert::TryFrom; -use rustc::{mir, ty}; +use log::trace; + +use rustc_middle::{mir, ty}; use crate::*; diff --git a/src/shims/os_str.rs b/src/shims/os_str.rs index 49afa3bdc362f..704994da4bd46 100644 --- a/src/shims/os_str.rs +++ b/src/shims/os_str.rs @@ -9,7 +9,7 @@ use std::os::unix::ffi::{OsStrExt, OsStringExt}; #[cfg(windows)] use std::os::windows::ffi::{OsStrExt, OsStringExt}; -use rustc::ty::layout::LayoutOf; +use rustc_middle::ty::layout::LayoutOf; use crate::*; diff --git a/src/shims/panic.rs b/src/shims/panic.rs index 703e711972a74..77741b7cca409 100644 --- a/src/shims/panic.rs +++ b/src/shims/panic.rs @@ -11,8 +11,10 @@ //! gets popped *during unwinding*, we take the panic payload and store it according to the extra //! metadata we remembered when pushing said frame. -use rustc::mir; -use rustc::ty::{self, layout::LayoutOf}; +use log::trace; + +use rustc_middle::mir; +use rustc_middle::ty::{self, layout::LayoutOf}; use rustc_target::spec::PanicStrategy; use crate::*; @@ -186,7 +188,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx msg: &mir::AssertMessage<'tcx>, unwind: Option, ) -> InterpResult<'tcx> { - use rustc::mir::AssertKind::*; + use rustc_middle::mir::AssertKind::*; let this = self.eval_context_mut(); match msg { diff --git a/src/shims/tls.rs b/src/shims/tls.rs index 2727c32050401..76f946f724ec4 100644 --- a/src/shims/tls.rs +++ b/src/shims/tls.rs @@ -2,7 +2,9 @@ use std::collections::BTreeMap; -use rustc::{ty, ty::layout::{Size, HasDataLayout}}; +use log::trace; + +use rustc_middle::{ty, ty::layout::{Size, HasDataLayout}}; use rustc_target::abi::LayoutOf; use crate::{HelpersEvalContextExt, InterpResult, MPlaceTy, Scalar, StackPopCleanup, Tag}; diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index c130abf0576be..90920069c5eee 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -6,9 +6,11 @@ use std::fmt; use std::num::NonZeroU64; use std::rc::Rc; +use log::trace; + use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -use rustc::mir::RetagKind; -use rustc::ty::{self, layout::Size}; +use rustc_middle::mir::RetagKind; +use rustc_middle::ty::{self, layout::Size}; use rustc_hir::Mutability; use crate::*; From 1cfd80ea2d35ed0b7463c6e1e29a602c2a366db5 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 30 Mar 2020 22:13:53 +0200 Subject: [PATCH 1759/3747] rustup; fix Windows env var memory type --- rust-version | 2 +- src/shims/env.rs | 6 ++---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/rust-version b/rust-version index 4f4cff76583b2..a812b46de17f6 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -8926bb497d9b127eb318aea5aed0e745d8381591 +9a12971da5c08f9a95d54bdaef5cd83698ed4509 diff --git a/src/shims/env.rs b/src/shims/env.rs index 76d1de5d9a649..d30e953cf56a1 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -165,8 +165,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // Allocate environment block & Store environment variables to environment block. // Final null terminator(block terminator) is added by `alloc_os_str_to_wide_str`. - // FIXME: MemoryKind should be `Env`, blocked on https://github.com/rust-lang/rust/pull/70479. - let envblock_ptr = this.alloc_os_str_as_wide_str(&env_vars, MiriMemoryKind::WinHeap.into()); + let envblock_ptr = this.alloc_os_str_as_wide_str(&env_vars, MiriMemoryKind::Env.into()); // If the function succeeds, the return value is a pointer to the environment block of the current process. Ok(envblock_ptr.into()) } @@ -177,8 +176,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.assert_target_os("windows", "FreeEnvironmentStringsW"); let env_block_ptr = this.read_scalar(env_block_op)?.not_undef()?; - // FIXME: MemoryKind should be `Env`, blocked on https://github.com/rust-lang/rust/pull/70479. - let result = this.memory.deallocate(this.force_ptr(env_block_ptr)?, None, MiriMemoryKind::WinHeap.into()); + let result = this.memory.deallocate(this.force_ptr(env_block_ptr)?, None, MiriMemoryKind::Env.into()); // If the function succeeds, the return value is nonzero. Ok(result.is_ok() as i32) } From 62eaecd2aa16917e8ed02cb2ead6d23825347c29 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 31 Mar 2020 17:50:10 +0200 Subject: [PATCH 1760/3747] test subtracting SystemTime and Instant --- tests/run-pass/time.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/tests/run-pass/time.rs b/tests/run-pass/time.rs index bbe8b4011dfa6..5352630fc298c 100644 --- a/tests/run-pass/time.rs +++ b/tests/run-pass/time.rs @@ -9,10 +9,22 @@ fn main() { for _ in 0..10 { drop(vec![42]); } let now2 = SystemTime::now(); assert!(now2 > now1); + let diff = now2.duration_since(now1).unwrap(); + assert!(diff.as_micros() > 0); + assert_eq!(now1 + diff, now2); + assert_eq!(now2 - diff, now1); let now1 = Instant::now(); // Do some work to make time pass. for _ in 0..10 { drop(vec![42]); } let now2 = Instant::now(); assert!(now2 > now1); + + #[cfg(target_os = "linux")] + { + let diff = now2.duration_since(now1); + assert!(diff.as_micros() > 0); + assert_eq!(now1 + diff, now2); + assert_eq!(now2 - diff, now1); + } } From 26b5012368910fecdab844a5ee75dfdc65996654 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 31 Mar 2020 17:53:27 +0200 Subject: [PATCH 1761/3747] add TODO --- tests/run-pass/time.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/run-pass/time.rs b/tests/run-pass/time.rs index 5352630fc298c..ca16f5ed5217b 100644 --- a/tests/run-pass/time.rs +++ b/tests/run-pass/time.rs @@ -20,7 +20,7 @@ fn main() { let now2 = Instant::now(); assert!(now2 > now1); - #[cfg(target_os = "linux")] + #[cfg(target_os = "linux")] // TODO: macOS does not support Instant subtraction { let diff = now2.duration_since(now1); assert!(diff.as_micros() > 0); From b3f9e5304950c5677506fad7f2e6d44d8ef88ae3 Mon Sep 17 00:00:00 2001 From: JOE1994 Date: Tue, 31 Mar 2020 11:26:32 -0400 Subject: [PATCH 1762/3747] Implement 'GetSystemTimeAsFileTime' shim for Windows --- src/helpers.rs | 27 ++++++++++++++++++------ src/shims/env.rs | 2 +- src/shims/foreign_items/windows.rs | 5 +++++ src/shims/time.rs | 34 +++++++++++++++++++++++++++++- tests/run-pass/time.rs | 26 ++++++++++++----------- 5 files changed, 73 insertions(+), 21 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index 15f1b286de228..7d22b85b18ebf 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -73,17 +73,23 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx .not_undef() } + /// Helper function to get a `libc` constant as an `i32`. + fn eval_libc_i32(&mut self, name: &str) -> InterpResult<'tcx, i32> { + // TODO: Cache the result. + self.eval_libc(name)?.to_i32() + } + /// Helper function to get a `windows` constant as a `Scalar`. - fn eval_windows(&mut self, name: &str) -> InterpResult<'tcx, Scalar> { + fn eval_windows(&mut self, module: &str, name: &str) -> InterpResult<'tcx, Scalar> { self.eval_context_mut() - .eval_path_scalar(&["std", "sys", "windows", "c", name])? + .eval_path_scalar(&["std", "sys", "windows", module, name])? .not_undef() } - /// Helper function to get a `libc` constant as an `i32`. - fn eval_libc_i32(&mut self, name: &str) -> InterpResult<'tcx, i32> { + /// Helper function to get a `windows` constant as an `u64`. + fn eval_windows_u64(&mut self, module: &str, name: &str) -> InterpResult<'tcx, u64> { // TODO: Cache the result. - self.eval_libc(name)?.to_i32() + self.eval_windows(module, name)?.to_u64() } /// Helper function to get the `TyAndLayout` of a `libc` type @@ -93,6 +99,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.layout_of(ty) } + /// Helper function to get the `TyAndLayout` of a `windows` type + fn windows_ty_layout(&mut self, name: &str) -> InterpResult<'tcx, TyAndLayout<'tcx>> { + let this = self.eval_context_mut(); + let ty = this.resolve_path(&["std", "sys", "windows", "c", name]).monomorphic_ty(*this.tcx); + this.layout_of(ty) + } + /// Write a 0 of the appropriate size to `dest`. fn write_null(&mut self, dest: PlaceTy<'tcx, Tag>) -> InterpResult<'tcx> { self.eval_context_mut().write_scalar(Scalar::from_int(0, dest.layout.size), dest) @@ -350,7 +363,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } - // Writes several `ImmTy`s contiguosly into memory. This is useful when you have to pack + // Writes several `ImmTy`s contiguously into memory. This is useful when you have to pack // different values into a struct. fn write_packed_immediates( &mut self, @@ -439,7 +452,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx })? } else if target_os == "windows" { // FIXME: we have to finish implementing the Windows equivalent of this. - this.eval_windows(match e.kind() { + this.eval_windows("c", match e.kind() { NotFound => "ERROR_FILE_NOT_FOUND", _ => throw_unsup_format!("io error {} cannot be transformed into a raw os error", e) })? diff --git a/src/shims/env.rs b/src/shims/env.rs index d30e953cf56a1..3ffe4fc421f99 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -143,7 +143,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx windows_check_buffer_size(this.write_os_str_to_wide_str(&var, buf_ptr, buf_size)?) } None => { - let envvar_not_found = this.eval_windows("ERROR_ENVVAR_NOT_FOUND")?; + let envvar_not_found = this.eval_windows("c", "ERROR_ENVVAR_NOT_FOUND")?; this.set_last_error(envvar_not_found)?; 0 // return zero upon failure } diff --git a/src/shims/foreign_items/windows.rs b/src/shims/foreign_items/windows.rs index f39d477f8278e..ee39773d71f83 100644 --- a/src/shims/foreign_items/windows.rs +++ b/src/shims/foreign_items/windows.rs @@ -167,6 +167,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx )?; } + // Time related shims + "GetSystemTimeAsFileTime" => { + this.GetSystemTimeAsFileTime(args[0])?; + } + // Miscellaneous "SystemFunction036" => { // The actual name of 'RtlGenRandom' diff --git a/src/shims/time.rs b/src/shims/time.rs index 58db60e516883..d501fa8a0fdb8 100644 --- a/src/shims/time.rs +++ b/src/shims/time.rs @@ -3,7 +3,9 @@ use std::convert::TryFrom; use crate::stacked_borrows::Tag; use crate::*; -use helpers::immty_from_int_checked; +use helpers::{immty_from_int_checked, immty_from_uint_checked}; + +use rustc_middle::ty::layout::LayoutOf; /// Returns the time elapsed between the provided time and the unix epoch as a `Duration`. pub fn system_time_to_duration<'tcx>(time: &SystemTime) -> InterpResult<'tcx, Duration> { @@ -85,6 +87,36 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(0) } + #[allow(non_snake_case)] + fn GetSystemTimeAsFileTime(&mut self, LPFILETIME_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + + this.assert_target_os("windows", "GetSystemTimeAsFileTime"); + this.check_no_isolation("GetSystemTimeAsFileTime")?; + + let NANOS_PER_SEC = this.eval_windows_u64("time", "NANOS_PER_SEC")?; + let INTERVALS_PER_SEC = this.eval_windows_u64("time", "INTERVALS_PER_SEC")?; + let INTERVALS_TO_UNIX_EPOCH = this.eval_windows_u64("time", "INTERVALS_TO_UNIX_EPOCH")?; + let NANOS_PER_INTERVAL = NANOS_PER_SEC / INTERVALS_PER_SEC; + let SECONDS_TO_UNIX_EPOCH = INTERVALS_TO_UNIX_EPOCH / INTERVALS_PER_SEC; + + let duration = system_time_to_duration(&SystemTime::now())? + .checked_add(Duration::from_secs(SECONDS_TO_UNIX_EPOCH)) + .unwrap(); + let duration_ticks = u64::try_from(duration.as_nanos() / u128::from(NANOS_PER_INTERVAL)) + .map_err(|_| err_unsup_format!("programs running longer than 2^64 ticks are not supported"))?; + + let dwLowDateTime = u32::try_from(duration_ticks & 0x00000000FFFFFFFF).unwrap(); + let dwHighDateTime = u32::try_from((duration_ticks & 0xFFFFFFFF00000000) >> 32).unwrap(); + let DWORD_tylayout = this.layout_of(this.tcx.types.u32)?; + let imms = [ + immty_from_uint_checked(dwLowDateTime, DWORD_tylayout)?, + immty_from_uint_checked(dwHighDateTime, DWORD_tylayout)?, + ]; + this.write_packed_immediates(this.deref_operand(LPFILETIME_op)?, &imms)?; + Ok(()) + } + fn mach_absolute_time(&self) -> InterpResult<'tcx, u64> { let this = self.eval_context_ref(); diff --git a/tests/run-pass/time.rs b/tests/run-pass/time.rs index ca16f5ed5217b..fc2059fa25612 100644 --- a/tests/run-pass/time.rs +++ b/tests/run-pass/time.rs @@ -1,4 +1,3 @@ -// ignore-windows: TODO clock shims are not implemented on Windows // compile-flags: -Zmiri-disable-isolation use std::time::{SystemTime, Instant}; @@ -14,17 +13,20 @@ fn main() { assert_eq!(now1 + diff, now2); assert_eq!(now2 - diff, now1); - let now1 = Instant::now(); - // Do some work to make time pass. - for _ in 0..10 { drop(vec![42]); } - let now2 = Instant::now(); - assert!(now2 > now1); - - #[cfg(target_os = "linux")] // TODO: macOS does not support Instant subtraction + #[cfg(not(windows))] // `Instant` shims not yet implemented on Windows { - let diff = now2.duration_since(now1); - assert!(diff.as_micros() > 0); - assert_eq!(now1 + diff, now2); - assert_eq!(now2 - diff, now1); + let now1 = Instant::now(); + // Do some work to make time pass. + for _ in 0..10 { drop(vec![42]); } + let now2 = Instant::now(); + assert!(now2 > now1); + + #[cfg(target_os = "linux")] // TODO: macOS does not support Instant subtraction + { + let diff = now2.duration_since(now1); + assert!(diff.as_micros() > 0); + assert_eq!(now1 + diff, now2); + assert_eq!(now2 - diff, now1); + } } } From 3911388e06694f4ddbd7045f8684f905090e9e84 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 1 Apr 2020 19:12:22 +0200 Subject: [PATCH 1763/3747] remove ICEin intrinsic --- src/shims/intrinsics.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 641b8b2563634..e0eb0df87c481 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -217,8 +217,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_immediate(*val, place.into())?; } - "breakpoint" => unimplemented!(), // halt miri - #[rustfmt::skip] | "copy" | "copy_nonoverlapping" From 1e3800ffb1b74d51f68f6d63306ff94b4297eb73 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 1 Apr 2020 19:40:10 +0200 Subject: [PATCH 1764/3747] rustup --- rust-version | 2 +- src/helpers.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/rust-version b/rust-version index a812b46de17f6..9a662aa0c26c4 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -9a12971da5c08f9a95d54bdaef5cd83698ed4509 +235938d1acdd93d6641a741c81f64e415b786751 diff --git a/src/helpers.rs b/src/helpers.rs index 15f1b286de228..e95b0d850b68f 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -115,7 +115,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn local_place(&mut self, local: mir::Local) -> InterpResult<'tcx, PlaceTy<'tcx, Tag>> { let this = self.eval_context_mut(); let place = mir::Place { local: local, projection: List::empty() }; - this.eval_place(&place) + this.eval_place(place) } /// Generate some random bytes, and write them to `dest`. From 41d90709f25b813c33943102b0d28329de1aaf73 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 1 Apr 2020 20:12:51 +0200 Subject: [PATCH 1765/3747] sanity check time values a bit more --- tests/run-pass/time.rs | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/tests/run-pass/time.rs b/tests/run-pass/time.rs index fc2059fa25612..a9ca28161cacf 100644 --- a/tests/run-pass/time.rs +++ b/tests/run-pass/time.rs @@ -3,16 +3,22 @@ use std::time::{SystemTime, Instant}; fn main() { + // Check `SystemTime`. let now1 = SystemTime::now(); // Do some work to make time pass. for _ in 0..10 { drop(vec![42]); } let now2 = SystemTime::now(); assert!(now2 > now1); let diff = now2.duration_since(now1).unwrap(); - assert!(diff.as_micros() > 0); assert_eq!(now1 + diff, now2); assert_eq!(now2 - diff, now1); + // Sanity-check the time we got. + let seconds_since_epoch = now1.duration_since(SystemTime::UNIX_EPOCH).unwrap().as_secs(); + let years_since_epoch = seconds_since_epoch / 3600 / 24 / 365; + let year = 1970 + years_since_epoch; + assert!(2020 <= year && year < 2100); + // Check `Instant`. #[cfg(not(windows))] // `Instant` shims not yet implemented on Windows { let now1 = Instant::now(); @@ -24,9 +30,11 @@ fn main() { #[cfg(target_os = "linux")] // TODO: macOS does not support Instant subtraction { let diff = now2.duration_since(now1); - assert!(diff.as_micros() > 0); assert_eq!(now1 + diff, now2); assert_eq!(now2 - diff, now1); + // Sanity-check the difference we got. + assert!(diff.as_micros() > 1); + assert!(diff.as_micros() < 1_000_000); } } } From 94d5eb02768fc5362bbfeff9739856aa130d7397 Mon Sep 17 00:00:00 2001 From: William Brown Date: Thu, 2 Apr 2020 09:50:21 +1000 Subject: [PATCH 1766/3747] Update readme to make supported codo clearer --- README.md | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/README.md b/README.md index 03b995aa56d3f..9ca69df9607fb 100644 --- a/README.md +++ b/README.md @@ -100,6 +100,30 @@ fn does_not_work_on_miri() { } ``` +An exhaustive list of what `miri` does not support is not available, as this could be +an unbounded set with FFI and more. However `miri` will explicitly tell you when it finds +something unsupported with an error: + +``` +error: unsupported operation: can't call foreign function: mach_timebase_info + --> /home/r/.rustup/toolchains/miri/lib/rustlib/src/rust/src/libstd/sys/unix/time.rs:239:13 + | +239 | mach_timebase_info(&mut info); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't call foreign function: mach_timebase_info + | + = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support + = note: inside call to `std::sys::unix::time::inner::info` at /home/r/.rustup/toolchains/miri/lib/rustlib/src/rust/src/libstd/sys/unix/time.rs:156:24 + = note: inside call to `std::sys::unix::time::inner::Instant::checked_sub_instant` at /home/r/.rustup/toolchains/miri/lib/rustlib/src/rust/src/libstd/time.rs:263:9 +note: inside call to `std::time::Instant::duration_since` at tests/run-pass/time.rs:25:20 + --> tests/run-pass/time.rs:25:20 + | +25 | let diff = now2.duration_since(now1); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: inside call to `main` at /home/r/.rustup/toolchains/miri/lib/rustlib/src/rust/src/libstd/rt.rs:67:34 +``` + +If you do not see an error like this, you are able to keep using `miri`! + ### Running Miri on CI To run Miri on CI, make sure that you handle the case where the latest nightly From 957ec2be10e628c0d31cfa4af7b7a26eccb89dfc Mon Sep 17 00:00:00 2001 From: JOE1994 Date: Wed, 1 Apr 2020 20:35:56 -0400 Subject: [PATCH 1767/3747] Add support for 'std::time::Instant' in Windows --- src/shims/foreign_items/windows.rs | 13 +++++++----- src/shims/time.rs | 32 ++++++++++++++++++++++++++++++ tests/run-pass/time.rs | 29 ++++++++++++--------------- 3 files changed, 53 insertions(+), 21 deletions(-) diff --git a/src/shims/foreign_items/windows.rs b/src/shims/foreign_items/windows.rs index ee39773d71f83..5e1bffef8a4b9 100644 --- a/src/shims/foreign_items/windows.rs +++ b/src/shims/foreign_items/windows.rs @@ -24,27 +24,22 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let result = this.GetEnvironmentVariableW(args[0], args[1], args[2])?; this.write_scalar(Scalar::from_u32(result), dest)?; } - "SetEnvironmentVariableW" => { let result = this.SetEnvironmentVariableW(args[0], args[1])?; this.write_scalar(Scalar::from_i32(result), dest)?; } - "GetEnvironmentStringsW" => { let result = this.GetEnvironmentStringsW()?; this.write_scalar(result, dest)?; } - "FreeEnvironmentStringsW" => { let result = this.FreeEnvironmentStringsW(args[0])?; this.write_scalar(Scalar::from_i32(result), dest)?; } - "GetCurrentDirectoryW" => { let result = this.GetCurrentDirectoryW(args[0], args[1])?; this.write_scalar(Scalar::from_u32(result), dest)?; } - "SetCurrentDirectoryW" => { let result = this.SetCurrentDirectoryW(args[0])?; this.write_scalar(Scalar::from_i32(result), dest)?; @@ -171,6 +166,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "GetSystemTimeAsFileTime" => { this.GetSystemTimeAsFileTime(args[0])?; } + "QueryPerformanceCounter" => { + let result = this.QueryPerformanceCounter(args[0])?; + this.write_scalar(Scalar::from_i32(result), dest)?; + } + "QueryPerformanceFrequency" => { + let result = this.QueryPerformanceFrequency(args[0])?; + this.write_scalar(Scalar::from_i32(result), dest)?; + } // Miscellaneous "SystemFunction036" => { diff --git a/src/shims/time.rs b/src/shims/time.rs index d501fa8a0fdb8..65e83ab0af788 100644 --- a/src/shims/time.rs +++ b/src/shims/time.rs @@ -117,6 +117,38 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(()) } + #[allow(non_snake_case)] + fn QueryPerformanceCounter(&mut self, lpPerformanceCount_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + let this = self.eval_context_mut(); + + this.assert_target_os("windows", "QueryPerformanceCounter"); + this.check_no_isolation("QueryPerformanceCounter")?; + + // QPC uses a hardware counter as its basis. + // Miri will assume that the machine's hardware counter has a resolution of 1 nanosecond. + let duration = Instant::now().duration_since(this.machine.time_anchor); + let qpc = i64::try_from(duration.as_nanos()) + .map_err(|_| err_unsup_format!("programs running longer than 2^64 nanoseconds are not supported"))?; + this.write_scalar(Scalar::from_i64(qpc), this.deref_operand(lpPerformanceCount_op)?.into())?; + Ok(-1) // return non-zero on success + } + + #[allow(non_snake_case)] + fn QueryPerformanceFrequency(&mut self, lpFrequency_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + let this = self.eval_context_mut(); + + this.assert_target_os("windows", "QueryPerformanceFrequency"); + this.check_no_isolation("QueryPerformanceFrequency")?; + + // Retrieves the frequency of the hardware performance counter. + // The frequency of the performance counter is fixed at system boot and + // is consistent across all processors. + // Miri will assume that the frequency of + // the machine's hardware performance counter is 1 GHz ( = 1 x 10^9 Hz). + this.write_scalar(Scalar::from_i64(1_000_000_000), this.deref_operand(lpFrequency_op)?.into())?; + Ok(-1) // Return non-zero on success + } + fn mach_absolute_time(&self) -> InterpResult<'tcx, u64> { let this = self.eval_context_ref(); diff --git a/tests/run-pass/time.rs b/tests/run-pass/time.rs index a9ca28161cacf..264fa9de0352d 100644 --- a/tests/run-pass/time.rs +++ b/tests/run-pass/time.rs @@ -19,22 +19,19 @@ fn main() { assert!(2020 <= year && year < 2100); // Check `Instant`. - #[cfg(not(windows))] // `Instant` shims not yet implemented on Windows - { - let now1 = Instant::now(); - // Do some work to make time pass. - for _ in 0..10 { drop(vec![42]); } - let now2 = Instant::now(); - assert!(now2 > now1); + let now1 = Instant::now(); + // Do some work to make time pass. + for _ in 0..10 { drop(vec![42]); } + let now2 = Instant::now(); + assert!(now2 > now1); - #[cfg(target_os = "linux")] // TODO: macOS does not support Instant subtraction - { - let diff = now2.duration_since(now1); - assert_eq!(now1 + diff, now2); - assert_eq!(now2 - diff, now1); - // Sanity-check the difference we got. - assert!(diff.as_micros() > 1); - assert!(diff.as_micros() < 1_000_000); - } + #[cfg(target_os = "linux")] // TODO: macOS does not support Instant subtraction + { + let diff = now2.duration_since(now1); + assert_eq!(now1 + diff, now2); + assert_eq!(now2 - diff, now1); + // Sanity-check the difference we got. + assert!(diff.as_micros() > 1); + assert!(diff.as_micros() < 1_000_000); } } From ff982b1821c6b4846c7a14053ba3a00a3f97f22b Mon Sep 17 00:00:00 2001 From: JOE1994 Date: Wed, 1 Apr 2020 21:26:47 -0400 Subject: [PATCH 1768/3747] fix incorrect error message in shim 'QueryPerformanceCounter' --- src/shims/time.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shims/time.rs b/src/shims/time.rs index 65e83ab0af788..d4c88cdb614bf 100644 --- a/src/shims/time.rs +++ b/src/shims/time.rs @@ -128,7 +128,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Miri will assume that the machine's hardware counter has a resolution of 1 nanosecond. let duration = Instant::now().duration_since(this.machine.time_anchor); let qpc = i64::try_from(duration.as_nanos()) - .map_err(|_| err_unsup_format!("programs running longer than 2^64 nanoseconds are not supported"))?; + .map_err(|_| err_unsup_format!("programs running longer than 2^63 nanoseconds are not supported"))?; this.write_scalar(Scalar::from_i64(qpc), this.deref_operand(lpPerformanceCount_op)?.into())?; Ok(-1) // return non-zero on success } From 5130aa55a2d5e846b491a58a19aad8e00554d61f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 30 Mar 2020 20:15:02 +0200 Subject: [PATCH 1769/3747] adjust stacktrace printing to rustc changes --- src/diagnostics.rs | 13 +++++-------- tests/compile-fail/never_transmute_void.rs | 4 ++-- 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/src/diagnostics.rs b/src/diagnostics.rs index a528960cb2628..8595551b6cbdf 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -130,14 +130,11 @@ fn report_msg<'tcx, 'mir>( } // Add backtrace let frames = ecx.generate_stacktrace(None); - // We iterate with indices because we need to look at the next frame (the caller). - for idx in 0..frames.len() { - let frame_info = &frames[idx]; - let call_site_is_local = frames - .get(idx + 1) - .map_or(false, |caller_info| caller_info.instance.def_id().is_local()); - if call_site_is_local { - err.span_note(frame_info.call_site, &frame_info.to_string()); + for (idx, frame_info) in frames.iter().enumerate() { + let is_local = frame_info.instance.def_id().is_local(); + // No span for non-local frames and the first frame (which is the error site). + if is_local && idx > 0 { + err.span_note(frame_info.span, &frame_info.to_string()); } else { err.note(&frame_info.to_string()); } diff --git a/tests/compile-fail/never_transmute_void.rs b/tests/compile-fail/never_transmute_void.rs index 2a822ab1b5150..5e9e2ac204ea1 100644 --- a/tests/compile-fail/never_transmute_void.rs +++ b/tests/compile-fail/never_transmute_void.rs @@ -7,12 +7,12 @@ enum Void {} fn f(v: Void) -> ! { - match v {} //~ ERROR entering unreachable code + match v {} //~ ERROR entering unreachable code } fn main() { let v: Void = unsafe { std::mem::transmute::<(), Void>(()) }; - f(v); //~ inside call to `f` + f(v); //~ inside `main` } From f599687f3fdb062a8ff2fe139cbe47249c5f29a1 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 30 Mar 2020 22:54:49 +0200 Subject: [PATCH 1770/3747] adjust for span not being passed around any more --- src/diagnostics.rs | 2 +- src/helpers.rs | 9 +-------- src/machine.rs | 6 ++---- src/shims/intrinsics.rs | 4 +--- src/shims/panic.rs | 4 ++-- 5 files changed, 7 insertions(+), 18 deletions(-) diff --git a/src/diagnostics.rs b/src/diagnostics.rs index 8595551b6cbdf..9ff434021150f 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -129,7 +129,7 @@ fn report_msg<'tcx, 'mir>( err.help(help); } // Add backtrace - let frames = ecx.generate_stacktrace(None); + let frames = ecx.generate_stacktrace(); for (idx, frame_info) in frames.iter().enumerate() { let is_local = frame_info.instance.def_id().is_local(); // No span for non-local frames and the first frame (which is the error site). diff --git a/src/helpers.rs b/src/helpers.rs index 568e9c925d55a..827bf1f9dde02 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -10,7 +10,6 @@ use rustc_middle::ty::{ List, TyCtxt, }; use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX}; -use rustc_span::source_map::DUMMY_SP; use rand::RngCore; @@ -170,13 +169,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Push frame. let mir = &*this.load_mir(f.def, None)?; - let span = this - .stack() - .last() - .and_then(Frame::current_source_info) - .map(|si| si.span) - .unwrap_or(DUMMY_SP); - this.push_stack_frame(f, span, mir, dest, stack_pop)?; + this.push_stack_frame(f, mir, dest, stack_pop)?; // Initialize arguments. let mut callee_args = this.frame().body.args_iter(); diff --git a/src/machine.rs b/src/machine.rs index 4b7f3a76569f1..61c9f71407bf5 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -18,7 +18,7 @@ use rustc_middle::ty::{ Ty, }; use rustc_ast::attr; -use rustc_span::{source_map::Span, symbol::{sym, Symbol}}; +use rustc_span::symbol::{sym, Symbol}; use crate::*; @@ -253,7 +253,6 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { #[inline(always)] fn find_mir_or_eval_fn( ecx: &mut InterpCx<'mir, 'tcx, Self>, - _span: Span, instance: ty::Instance<'tcx>, args: &[OpTy<'tcx, Tag>], ret: Option<(PlaceTy<'tcx, Tag>, mir::BasicBlock)>, @@ -276,13 +275,12 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { #[inline(always)] fn call_intrinsic( ecx: &mut rustc_mir::interpret::InterpCx<'mir, 'tcx, Self>, - span: Span, instance: ty::Instance<'tcx>, args: &[OpTy<'tcx, Tag>], ret: Option<(PlaceTy<'tcx, Tag>, mir::BasicBlock)>, unwind: Option, ) -> InterpResult<'tcx> { - ecx.call_intrinsic(span, instance, args, ret, unwind) + ecx.call_intrinsic(instance, args, ret, unwind) } #[inline(always)] diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index e0eb0df87c481..b7900bfaa5d5f 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -5,7 +5,6 @@ use rustc_middle::mir; use rustc_middle::ty; use rustc_middle::ty::layout::{Align, LayoutOf}; use rustc_apfloat::Float; -use rustc_span::source_map::Span; use crate::*; @@ -13,14 +12,13 @@ impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tc pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { fn call_intrinsic( &mut self, - span: Span, instance: ty::Instance<'tcx>, args: &[OpTy<'tcx, Tag>], ret: Option<(PlaceTy<'tcx, Tag>, mir::BasicBlock)>, unwind: Option, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - if this.emulate_intrinsic(span, instance, args, ret)? { + if this.emulate_intrinsic(instance, args, ret)? { return Ok(()); } let substs = instance.substs; diff --git a/src/shims/panic.rs b/src/shims/panic.rs index 77741b7cca409..3474945980a90 100644 --- a/src/shims/panic.rs +++ b/src/shims/panic.rs @@ -51,7 +51,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - trace!("miri_start_panic: {:?}", this.frame().span); + trace!("miri_start_panic: {:?}", this.frame().instance); // Get the raw pointer stored in arg[0] (the panic payload). let payload = this.read_scalar(args[0])?.not_undef()?; @@ -133,7 +133,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if let (true, Some(catch_unwind)) = (unwinding, extra.catch_unwind.take()) { // We've just popped a frame that was pushed by `try`, // and we are unwinding, so we should catch that. - trace!("unwinding: found catch_panic frame during unwinding: {:?}", this.frame().span); + trace!("unwinding: found catch_panic frame during unwinding: {:?}", this.frame().instance); // We set the return value of `try` to 1, since there was a panic. this.write_scalar(Scalar::from_i32(1), catch_unwind.dest)?; From 165dfd78a94bb5f30e655b51cde633649107ad42 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 2 Apr 2020 09:14:23 +0200 Subject: [PATCH 1771/3747] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 9a662aa0c26c4..6ed19772cad9c 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -235938d1acdd93d6641a741c81f64e415b786751 +b793f403bdfbcc0ff3e15ed8177a81d79ba4a29b From 5ce2466892126a3ea92138df67f09243a22dcb96 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 2 Apr 2020 09:19:56 +0200 Subject: [PATCH 1772/3747] fix for FieldPlacement rename --- src/helpers.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index 827bf1f9dde02..7b1ac1aacfc8b 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -324,19 +324,19 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fields: impl Iterator>>, ) -> InterpResult<'tcx> { match place.layout.fields { - layout::FieldPlacement::Array { .. } => { + layout::FieldsShape::Array { .. } => { // For the array layout, we know the iterator will yield sorted elements so // we can avoid the allocation. self.walk_aggregate(place, fields) } - layout::FieldPlacement::Arbitrary { .. } => { + layout::FieldsShape::Arbitrary { .. } => { // Gather the subplaces and sort them before visiting. let mut places = fields.collect::>>>()?; places.sort_by_key(|place| place.ptr.assert_ptr().offset); self.walk_aggregate(place, places.into_iter().map(Ok)) } - layout::FieldPlacement::Union { .. } => { + layout::FieldsShape::Union { .. } => { // Uh, what? bug!("a union is not an aggregate we should ever visit") } From 0b07f6f5d32d6a46de21776eac714e0a04fce71d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 2 Apr 2020 09:49:48 +0200 Subject: [PATCH 1773/3747] set CARGO_INCREMENTAL=0 on CI, it's just a waste of time there --- .appveyor.yml | 1 + .travis.yml | 1 + miri | 5 ++++- 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/.appveyor.yml b/.appveyor.yml index e5c2f4fb7294a..294ef26be0bed 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -46,6 +46,7 @@ build_script: test_script: - set RUST_TEST_NOCAPTURE=1 - set RUST_BACKTRACE=1 + - set CARGO_INCREMENTAL=0 # Test host miri: 32bit Windows - cargo miri setup - set MIRI_SYSROOT=%USERPROFILE%\AppData\Local\rust-lang\miri\cache\HOST diff --git a/.travis.yml b/.travis.yml index 137ae4fe66255..a074d6b14d8da 100644 --- a/.travis.yml +++ b/.travis.yml @@ -19,6 +19,7 @@ env: global: - RUST_TEST_NOCAPTURE=1 - RUST_BACKTRACE=1 + - CARGO_INCREMENTAL=0 before_script: # Compute the rust version we use. We do not use "language: rust" to have more control here. diff --git a/miri b/miri index 0cda9e80926e1..8cd2cfc3ae0c6 100755 --- a/miri +++ b/miri @@ -49,7 +49,10 @@ fi # We enable debug-assertions to get tracing. # We enable line-only debuginfo for backtraces. export RUSTFLAGS="-C link-args=-Wl,-rpath,$LIBDIR -C debug-assertions -C debuginfo=1 $RUSTC_EXTRA_FLAGS" -export CARGO_INCREMENTAL=1 +if [ -z "$CARGO_INCREMENTAL" ]; then + # Default CARGO_INCREMENTAL to 1. + export CARGO_INCREMENTAL=1 +fi ## Helper functions From 033eae5ad73ef69648f7b794040de1cb2c4317a1 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 2 Apr 2020 11:45:17 +0200 Subject: [PATCH 1774/3747] rustup for AllocRef changes --- rust-version | 2 +- tests/run-pass/heap_allocator.rs | 17 +++++++++-------- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/rust-version b/rust-version index 6ed19772cad9c..2cb1f848a684b 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -b793f403bdfbcc0ff3e15ed8177a81d79ba4a29b +127a11a344eb59b5aea1464e98257c262dcba967 diff --git a/tests/run-pass/heap_allocator.rs b/tests/run-pass/heap_allocator.rs index 8077be405f4b2..c2fcfea58cdf5 100644 --- a/tests/run-pass/heap_allocator.rs +++ b/tests/run-pass/heap_allocator.rs @@ -1,7 +1,7 @@ #![feature(allocator_api)] use std::ptr::NonNull; -use std::alloc::{Global, AllocRef, Layout, System}; +use std::alloc::{Global, AllocRef, Layout, System, AllocInit, ReallocPlacement}; use std::slice; fn check_alloc(mut allocator: T) { unsafe { @@ -9,28 +9,29 @@ fn check_alloc(mut allocator: T) { unsafe { let layout = Layout::from_size_align(20, align).unwrap(); for _ in 0..32 { - let a = allocator.alloc(layout).unwrap().0; + let a = allocator.alloc(layout, AllocInit::Uninitialized).unwrap().ptr; assert_eq!(a.as_ptr() as usize % align, 0, "pointer is incorrectly aligned"); allocator.dealloc(a, layout); } - let p1 = allocator.alloc_zeroed(layout).unwrap().0; + let p1 = allocator.alloc(layout, AllocInit::Zeroed).unwrap().ptr; assert_eq!(p1.as_ptr() as usize % align, 0, "pointer is incorrectly aligned"); - let p2 = allocator.realloc(p1, layout, 40).unwrap().0; + // old size < new size + let p2 = allocator.grow(p1, layout, 40, ReallocPlacement::MayMove, AllocInit::Uninitialized).unwrap().ptr; let layout = Layout::from_size_align(40, align).unwrap(); assert_eq!(p2.as_ptr() as usize % align, 0, "pointer is incorrectly aligned"); let slice = slice::from_raw_parts(p2.as_ptr(), 20); assert_eq!(&slice, &[0_u8; 20]); // old size == new size - let p3 = allocator.realloc(p2, layout, 40).unwrap().0; + let p3 = allocator.grow(p2, layout, 40, ReallocPlacement::MayMove, AllocInit::Uninitialized).unwrap().ptr; assert_eq!(p3.as_ptr() as usize % align, 0, "pointer is incorrectly aligned"); let slice = slice::from_raw_parts(p3.as_ptr(), 20); assert_eq!(&slice, &[0_u8; 20]); // old size > new size - let p4 = allocator.realloc(p3, layout, 10).unwrap().0; + let p4 = allocator.shrink(p3, layout, 10, ReallocPlacement::MayMove).unwrap().ptr; let layout = Layout::from_size_align(10, align).unwrap(); assert_eq!(p4.as_ptr() as usize % align, 0, "pointer is incorrectly aligned"); let slice = slice::from_raw_parts(p4.as_ptr(), 10); @@ -46,7 +47,7 @@ fn check_align_requests(mut allocator: T) { let iterations = 32; unsafe { let pointers: Vec<_> = (0..iterations).map(|_| { - allocator.alloc(Layout::from_size_align(size, align).unwrap()).unwrap().0 + allocator.alloc(Layout::from_size_align(size, align).unwrap(), AllocInit::Uninitialized).unwrap().ptr }).collect(); for &ptr in &pointers { assert_eq!((ptr.as_ptr() as usize) % align, 0, @@ -67,7 +68,7 @@ fn global_to_box() { let l = Layout::new::(); // allocate manually with global allocator, then turn into Box and free there unsafe { - let ptr = Global.alloc(l).unwrap().0.as_ptr() as *mut T; + let ptr = Global.alloc(l, AllocInit::Uninitialized).unwrap().ptr.as_ptr() as *mut T; let b = Box::from_raw(ptr); drop(b); } From cd132f563ea5385c8dfed2b9c9032ea3e8dc3edc Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 2 Apr 2020 13:33:59 +0200 Subject: [PATCH 1775/3747] port compile-fail allocator tests to stable API --- tests/compile-fail/deallocate-bad-alignment.rs | 11 +++-------- tests/compile-fail/deallocate-bad-size.rs | 11 +++-------- tests/compile-fail/deallocate-twice.rs | 13 ++++--------- tests/compile-fail/reallocate-bad-size.rs | 11 +++-------- tests/compile-fail/reallocate-change-alloc.rs | 13 ++++--------- tests/compile-fail/reallocate-dangling.rs | 13 ++++--------- 6 files changed, 21 insertions(+), 51 deletions(-) diff --git a/tests/compile-fail/deallocate-bad-alignment.rs b/tests/compile-fail/deallocate-bad-alignment.rs index f2cd87bac6229..9b5ee9a934b0b 100644 --- a/tests/compile-fail/deallocate-bad-alignment.rs +++ b/tests/compile-fail/deallocate-bad-alignment.rs @@ -1,15 +1,10 @@ -#![feature(allocator_api)] - -extern crate alloc; - -use alloc::alloc::Global; -use std::alloc::{AllocRef, Layout}; +use std::alloc::{alloc, dealloc, realloc, Layout}; // error-pattern: allocation has size 1 and alignment 1, but gave size 1 and alignment 2 fn main() { unsafe { - let x = Global.alloc(Layout::from_size_align_unchecked(1, 1)).unwrap().0; - Global.dealloc(x, Layout::from_size_align_unchecked(1, 2)); + let x = alloc(Layout::from_size_align_unchecked(1, 1)); + dealloc(x, Layout::from_size_align_unchecked(1, 2)); } } diff --git a/tests/compile-fail/deallocate-bad-size.rs b/tests/compile-fail/deallocate-bad-size.rs index 498a662518e52..39a0d48c8b1a4 100644 --- a/tests/compile-fail/deallocate-bad-size.rs +++ b/tests/compile-fail/deallocate-bad-size.rs @@ -1,15 +1,10 @@ -#![feature(allocator_api)] - -extern crate alloc; - -use alloc::alloc::Global; -use std::alloc::{AllocRef, Layout}; +use std::alloc::{alloc, dealloc, realloc, Layout}; // error-pattern: allocation has size 1 and alignment 1, but gave size 2 and alignment 1 fn main() { unsafe { - let x = Global.alloc(Layout::from_size_align_unchecked(1, 1)).unwrap().0; - Global.dealloc(x, Layout::from_size_align_unchecked(2, 1)); + let x = alloc(Layout::from_size_align_unchecked(1, 1)); + dealloc(x, Layout::from_size_align_unchecked(2, 1)); } } diff --git a/tests/compile-fail/deallocate-twice.rs b/tests/compile-fail/deallocate-twice.rs index a851d75b9d5c5..3c5e8e96360c7 100644 --- a/tests/compile-fail/deallocate-twice.rs +++ b/tests/compile-fail/deallocate-twice.rs @@ -1,16 +1,11 @@ -#![feature(allocator_api)] - -extern crate alloc; - -use alloc::alloc::Global; -use std::alloc::{AllocRef, Layout}; +use std::alloc::{alloc, dealloc, realloc, Layout}; // error-pattern: dereferenced after this allocation got freed fn main() { unsafe { - let x = Global.alloc(Layout::from_size_align_unchecked(1, 1)).unwrap().0; - Global.dealloc(x, Layout::from_size_align_unchecked(1, 1)); - Global.dealloc(x, Layout::from_size_align_unchecked(1, 1)); + let x = alloc(Layout::from_size_align_unchecked(1, 1)); + dealloc(x, Layout::from_size_align_unchecked(1, 1)); + dealloc(x, Layout::from_size_align_unchecked(1, 1)); } } diff --git a/tests/compile-fail/reallocate-bad-size.rs b/tests/compile-fail/reallocate-bad-size.rs index a62c1adae7e64..bbdef4421b6c2 100644 --- a/tests/compile-fail/reallocate-bad-size.rs +++ b/tests/compile-fail/reallocate-bad-size.rs @@ -1,15 +1,10 @@ -#![feature(allocator_api)] - -extern crate alloc; - -use alloc::alloc::Global; -use std::alloc::{AllocRef, Layout}; +use std::alloc::{alloc, dealloc, realloc, Layout}; // error-pattern: allocation has size 1 and alignment 1, but gave size 2 and alignment 1 fn main() { unsafe { - let x = Global.alloc(Layout::from_size_align_unchecked(1, 1)).unwrap().0; - Global.realloc(x, Layout::from_size_align_unchecked(2, 1), 1).unwrap(); + let x = alloc(Layout::from_size_align_unchecked(1, 1)); + realloc(x, Layout::from_size_align_unchecked(2, 1), 1); } } diff --git a/tests/compile-fail/reallocate-change-alloc.rs b/tests/compile-fail/reallocate-change-alloc.rs index 0d4b60e0a336f..8130d72dee596 100644 --- a/tests/compile-fail/reallocate-change-alloc.rs +++ b/tests/compile-fail/reallocate-change-alloc.rs @@ -1,14 +1,9 @@ -#![feature(allocator_api)] - -extern crate alloc; - -use alloc::alloc::Global; -use std::alloc::{AllocRef, Layout}; +use std::alloc::{alloc, dealloc, realloc, Layout}; fn main() { unsafe { - let x = Global.alloc(Layout::from_size_align_unchecked(1, 1)).unwrap().0; - Global.realloc(x, Layout::from_size_align_unchecked(1, 1), 1).unwrap(); - let _z = *(x.as_ptr() as *mut u8); //~ ERROR dereferenced after this allocation got freed + let x = alloc(Layout::from_size_align_unchecked(1, 1)); + realloc(x, Layout::from_size_align_unchecked(1, 1), 1); + let _z = *x; //~ ERROR dereferenced after this allocation got freed } } diff --git a/tests/compile-fail/reallocate-dangling.rs b/tests/compile-fail/reallocate-dangling.rs index 9661d7e966746..702ddc0724a33 100644 --- a/tests/compile-fail/reallocate-dangling.rs +++ b/tests/compile-fail/reallocate-dangling.rs @@ -1,16 +1,11 @@ -#![feature(allocator_api)] - -extern crate alloc; - -use alloc::alloc::Global; -use std::alloc::{AllocRef, Layout}; +use std::alloc::{alloc, dealloc, realloc, Layout}; // error-pattern: dereferenced after this allocation got freed fn main() { unsafe { - let x = Global.alloc(Layout::from_size_align_unchecked(1, 1)).unwrap().0; - Global.dealloc(x, Layout::from_size_align_unchecked(1, 1)); - Global.realloc(x, Layout::from_size_align_unchecked(1, 1), 1).unwrap(); + let x = alloc(Layout::from_size_align_unchecked(1, 1)); + dealloc(x, Layout::from_size_align_unchecked(1, 1)); + realloc(x, Layout::from_size_align_unchecked(1, 1), 1); } } From d5beecb79c71340c36fa79d994ac5848fb1159db Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 2 Apr 2020 15:14:53 +0200 Subject: [PATCH 1776/3747] correct factual mistake in Windows message, and use "+" sugar --- src/shims/time.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/shims/time.rs b/src/shims/time.rs index d501fa8a0fdb8..735b52528fdad 100644 --- a/src/shims/time.rs +++ b/src/shims/time.rs @@ -100,11 +100,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let NANOS_PER_INTERVAL = NANOS_PER_SEC / INTERVALS_PER_SEC; let SECONDS_TO_UNIX_EPOCH = INTERVALS_TO_UNIX_EPOCH / INTERVALS_PER_SEC; - let duration = system_time_to_duration(&SystemTime::now())? - .checked_add(Duration::from_secs(SECONDS_TO_UNIX_EPOCH)) - .unwrap(); + let duration = system_time_to_duration(&SystemTime::now())? + Duration::from_secs(SECONDS_TO_UNIX_EPOCH); let duration_ticks = u64::try_from(duration.as_nanos() / u128::from(NANOS_PER_INTERVAL)) - .map_err(|_| err_unsup_format!("programs running longer than 2^64 ticks are not supported"))?; + .map_err(|_| err_unsup_format!("programs running more than 2^64 Windows ticks after the Windows epoch are not supported"))?; let dwLowDateTime = u32::try_from(duration_ticks & 0x00000000FFFFFFFF).unwrap(); let dwHighDateTime = u32::try_from((duration_ticks & 0xFFFFFFFF00000000) >> 32).unwrap(); From a494825d5aca389f5c6ff7407bd927a5faee35b8 Mon Sep 17 00:00:00 2001 From: Youngsuk Kim Date: Thu, 2 Apr 2020 16:03:56 -0400 Subject: [PATCH 1777/3747] Update comments in src/shims/time.rs Co-Authored-By: Ralf Jung --- src/shims/time.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shims/time.rs b/src/shims/time.rs index d4c88cdb614bf..07819fd56f157 100644 --- a/src/shims/time.rs +++ b/src/shims/time.rs @@ -125,7 +125,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.check_no_isolation("QueryPerformanceCounter")?; // QPC uses a hardware counter as its basis. - // Miri will assume that the machine's hardware counter has a resolution of 1 nanosecond. + // Miri will emulate a counter with a resolution of 1 nanosecond. let duration = Instant::now().duration_since(this.machine.time_anchor); let qpc = i64::try_from(duration.as_nanos()) .map_err(|_| err_unsup_format!("programs running longer than 2^63 nanoseconds are not supported"))?; From 5157b8769f6f5196e73133a4cd3ec009823e71fd Mon Sep 17 00:00:00 2001 From: Youngsuk Kim Date: Thu, 2 Apr 2020 16:04:10 -0400 Subject: [PATCH 1778/3747] Update comments in src/shims/time.rs Co-Authored-By: Ralf Jung --- src/shims/time.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shims/time.rs b/src/shims/time.rs index 07819fd56f157..769fb4cf5b332 100644 --- a/src/shims/time.rs +++ b/src/shims/time.rs @@ -124,7 +124,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.assert_target_os("windows", "QueryPerformanceCounter"); this.check_no_isolation("QueryPerformanceCounter")?; - // QPC uses a hardware counter as its basis. + // QueryPerformanceCounter uses a hardware counter as its basis. // Miri will emulate a counter with a resolution of 1 nanosecond. let duration = Instant::now().duration_since(this.machine.time_anchor); let qpc = i64::try_from(duration.as_nanos()) From f762c70b5185573112e4c897d23a29b0bf6636bd Mon Sep 17 00:00:00 2001 From: Youngsuk Kim Date: Thu, 2 Apr 2020 16:04:50 -0400 Subject: [PATCH 1779/3747] Update comments in src/shims/time.rs Co-Authored-By: Ralf Jung --- src/shims/time.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/shims/time.rs b/src/shims/time.rs index 769fb4cf5b332..d7b423fc8aae5 100644 --- a/src/shims/time.rs +++ b/src/shims/time.rs @@ -143,8 +143,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Retrieves the frequency of the hardware performance counter. // The frequency of the performance counter is fixed at system boot and // is consistent across all processors. - // Miri will assume that the frequency of - // the machine's hardware performance counter is 1 GHz ( = 1 x 10^9 Hz). + // Miri emulates a "hardware" performance counter with a resolution of 1ns, + // and thus 10^9 counts per second. this.write_scalar(Scalar::from_i64(1_000_000_000), this.deref_operand(lpFrequency_op)?.into())?; Ok(-1) // Return non-zero on success } From d5de67a5a0719daffc9e5ed6d434c9feaf093fe7 Mon Sep 17 00:00:00 2001 From: JOE1994 Date: Thu, 2 Apr 2020 16:15:23 -0400 Subject: [PATCH 1780/3747] change cfg gate to enable testing Instant subtraction in Windows --- tests/run-pass/time.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/run-pass/time.rs b/tests/run-pass/time.rs index 264fa9de0352d..aa02ac15388e5 100644 --- a/tests/run-pass/time.rs +++ b/tests/run-pass/time.rs @@ -25,7 +25,7 @@ fn main() { let now2 = Instant::now(); assert!(now2 > now1); - #[cfg(target_os = "linux")] // TODO: macOS does not support Instant subtraction + #[cfg(not(target_os = "macos"))] // TODO: macOS does not support Instant subtraction { let diff = now2.duration_since(now1); assert_eq!(now1 + diff, now2); From 9f3383d55d99635a38c5406f60d16c478534d9f6 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 3 Apr 2020 00:05:35 +0200 Subject: [PATCH 1781/3747] rustup for import changes --- rust-version | 2 +- src/eval.rs | 2 +- src/helpers.rs | 17 +++++++---------- src/intptrcast.rs | 3 +-- src/machine.rs | 10 +++------- src/operator.rs | 7 ++----- src/range_map.rs | 2 +- src/shims/env.rs | 8 +++----- src/shims/foreign_items.rs | 5 ++--- src/shims/foreign_items/posix.rs | 2 +- src/shims/foreign_items/windows.rs | 8 +++++--- src/shims/fs.rs | 2 +- src/shims/intrinsics.rs | 5 ++--- src/shims/os_str.rs | 2 +- src/shims/panic.rs | 5 ++--- src/shims/time.rs | 4 ++-- src/shims/tls.rs | 4 ++-- src/stacked_borrows.rs | 3 ++- 18 files changed, 39 insertions(+), 52 deletions(-) diff --git a/rust-version b/rust-version index 2cb1f848a684b..e3dc200835fde 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -127a11a344eb59b5aea1464e98257c262dcba967 +537ccdf3ac44c8c7a8d36cbdbe6fb224afabb7ae diff --git a/src/eval.rs b/src/eval.rs index a4867bd5de46b..46e66bc0a81e7 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -6,7 +6,7 @@ use std::convert::TryFrom; use rand::rngs::StdRng; use rand::SeedableRng; -use rustc_middle::ty::layout::LayoutOf; +use rustc_target::abi::LayoutOf; use rustc_middle::ty::{self, TyCtxt}; use rustc_hir::def_id::DefId; diff --git a/src/helpers.rs b/src/helpers.rs index 7b1ac1aacfc8b..9f46a0c1ce2d9 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -4,12 +4,9 @@ use std::mem; use log::trace; use rustc_middle::mir; -use rustc_middle::ty::{ - self, - layout::{self, LayoutOf, Size, TyAndLayout}, - List, TyCtxt, -}; +use rustc_middle::ty::{self, List, TyCtxt, layout::TyAndLayout}; use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX}; +use rustc_target::abi::{LayoutOf, Size, FieldsShape, Variants}; use rand::RngCore; @@ -298,7 +295,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // walking this value, we have to make sure it is not a // `Variants::Multiple`. match v.layout.variants { - layout::Variants::Multiple { .. } => { + Variants::Multiple { .. } => { // A multi-variant enum, or generator, or so. // Treat this like a union: without reading from memory, // we cannot determine the variant we are in. Reading from @@ -308,7 +305,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // `UnsafeCell` action. (self.unsafe_cell_action)(v) } - layout::Variants::Single { .. } => { + Variants::Single { .. } => { // Proceed further, try to find where exactly that `UnsafeCell` // is hiding. self.walk_value(v) @@ -324,19 +321,19 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fields: impl Iterator>>, ) -> InterpResult<'tcx> { match place.layout.fields { - layout::FieldsShape::Array { .. } => { + FieldsShape::Array { .. } => { // For the array layout, we know the iterator will yield sorted elements so // we can avoid the allocation. self.walk_aggregate(place, fields) } - layout::FieldsShape::Arbitrary { .. } => { + FieldsShape::Arbitrary { .. } => { // Gather the subplaces and sort them before visiting. let mut places = fields.collect::>>>()?; places.sort_by_key(|place| place.ptr.assert_ptr().offset); self.walk_aggregate(place, places.into_iter().map(Ok)) } - layout::FieldsShape::Union { .. } => { + FieldsShape::Union { .. } => { // Uh, what? bug!("a union is not an aggregate we should ever visit") } diff --git a/src/intptrcast.rs b/src/intptrcast.rs index 8eb28e4f4700a..ac27138d7630e 100644 --- a/src/intptrcast.rs +++ b/src/intptrcast.rs @@ -6,9 +6,8 @@ use log::trace; use rand::Rng; use rustc_data_structures::fx::FxHashMap; -use rustc_middle::ty::layout::HasDataLayout; use rustc_mir::interpret::{AllocCheck, AllocId, InterpResult, Memory, Machine, Pointer, PointerArithmetic}; -use rustc_target::abi::Size; +use rustc_target::abi::{Size, HasDataLayout}; use crate::{Evaluator, Tag, STACK_ADDR}; diff --git a/src/machine.rs b/src/machine.rs index 61c9f71407bf5..f794453228b84 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -11,12 +11,8 @@ use log::trace; use rand::rngs::StdRng; use rustc_data_structures::fx::FxHashMap; -use rustc_middle::mir; -use rustc_middle::ty::{ - self, - layout::{LayoutOf, Size}, - Ty, -}; +use rustc_middle::{mir, ty}; +use rustc_target::abi::{LayoutOf, Size}; use rustc_ast::attr; use rustc_span::symbol::{sym, Symbol}; @@ -303,7 +299,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { bin_op: mir::BinOp, left: ImmTy<'tcx, Tag>, right: ImmTy<'tcx, Tag>, - ) -> InterpResult<'tcx, (Scalar, bool, Ty<'tcx>)> { + ) -> InterpResult<'tcx, (Scalar, bool, ty::Ty<'tcx>)> { ecx.binary_ptr_op(bin_op, left, right) } diff --git a/src/operator.rs b/src/operator.rs index 2232be713ed58..a28a0098e92e9 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -2,11 +2,8 @@ use std::convert::TryFrom; use log::trace; -use rustc_middle::mir; -use rustc_middle::ty::{ - layout::{LayoutOf, Size}, - Ty, -}; +use rustc_middle::{mir, ty::Ty}; +use rustc_target::abi::{LayoutOf, Size}; use crate::*; diff --git a/src/range_map.rs b/src/range_map.rs index 1d12d8a1ba652..16ad5fd7c2b26 100644 --- a/src/range_map.rs +++ b/src/range_map.rs @@ -7,7 +7,7 @@ use std::ops; -use rustc_middle::ty::layout::Size; +use rustc_target::abi::Size; #[derive(Clone, Debug)] struct Elem { diff --git a/src/shims/env.rs b/src/shims/env.rs index 3ffe4fc421f99..4401682722943 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -2,14 +2,12 @@ use std::ffi::{OsString, OsStr}; use std::env; use std::convert::TryFrom; -use crate::stacked_borrows::Tag; -use crate::rustc_target::abi::LayoutOf; -use crate::*; - +use rustc_target::abi::{Size, LayoutOf}; use rustc_data_structures::fx::FxHashMap; -use rustc_middle::ty::layout::Size; use rustc_mir::interpret::Pointer; +use crate::*; + /// Check whether an operation that writes to a target buffer was successful. /// Accordingly select return value. /// Local helper function to be used in Windows shims. diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index da2f9d439c7e4..7e7f17b0dbd4a 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -4,9 +4,8 @@ mod posix; use std::{convert::{TryInto, TryFrom}, iter}; use rustc_hir::def_id::DefId; -use rustc_middle::mir; -use rustc_middle::ty; -use rustc_middle::ty::layout::{Align, Size}; +use rustc_middle::{mir, ty}; +use rustc_target::abi::{Align, Size}; use rustc_apfloat::Float; use rustc_span::symbol::sym; use rustc_ast::attr; diff --git a/src/shims/foreign_items/posix.rs b/src/shims/foreign_items/posix.rs index 28161592985ac..c9fd59c693271 100644 --- a/src/shims/foreign_items/posix.rs +++ b/src/shims/foreign_items/posix.rs @@ -7,7 +7,7 @@ use log::trace; use crate::*; use rustc_middle::mir; -use rustc_middle::ty::layout::{Align, LayoutOf, Size}; +use rustc_target::abi::{Align, LayoutOf, Size}; impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { diff --git a/src/shims/foreign_items/windows.rs b/src/shims/foreign_items/windows.rs index ee39773d71f83..276dd8fda9ff2 100644 --- a/src/shims/foreign_items/windows.rs +++ b/src/shims/foreign_items/windows.rs @@ -1,8 +1,10 @@ -use crate::*; -use rustc_middle::mir; -use rustc_middle::ty::layout::Size; use std::iter; +use rustc_middle::mir; +use rustc_target::abi::Size; + +use crate::*; + impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { fn emulate_foreign_item_by_name( diff --git a/src/shims/fs.rs b/src/shims/fs.rs index 89d067be860d2..52244dcfc847e 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -6,7 +6,7 @@ use std::path::Path; use std::time::SystemTime; use rustc_data_structures::fx::FxHashMap; -use rustc_middle::ty::layout::{Align, LayoutOf, Size}; +use rustc_target::abi::{Align, LayoutOf, Size}; use crate::stacked_borrows::Tag; use crate::*; diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index b7900bfaa5d5f..844eac398de81 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -1,10 +1,9 @@ use std::iter; use std::convert::TryFrom; -use rustc_middle::mir; -use rustc_middle::ty; -use rustc_middle::ty::layout::{Align, LayoutOf}; +use rustc_middle::{mir, ty}; use rustc_apfloat::Float; +use rustc_target::abi::{Align, LayoutOf}; use crate::*; diff --git a/src/shims/os_str.rs b/src/shims/os_str.rs index 704994da4bd46..c24d6df41e392 100644 --- a/src/shims/os_str.rs +++ b/src/shims/os_str.rs @@ -9,7 +9,7 @@ use std::os::unix::ffi::{OsStrExt, OsStringExt}; #[cfg(windows)] use std::os::windows::ffi::{OsStrExt, OsStringExt}; -use rustc_middle::ty::layout::LayoutOf; +use rustc_target::abi::LayoutOf; use crate::*; diff --git a/src/shims/panic.rs b/src/shims/panic.rs index 3474945980a90..33e47147a33ba 100644 --- a/src/shims/panic.rs +++ b/src/shims/panic.rs @@ -13,9 +13,8 @@ use log::trace; -use rustc_middle::mir; -use rustc_middle::ty::{self, layout::LayoutOf}; -use rustc_target::spec::PanicStrategy; +use rustc_middle::{mir, ty}; +use rustc_target::{spec::PanicStrategy, abi::LayoutOf}; use crate::*; diff --git a/src/shims/time.rs b/src/shims/time.rs index 735b52528fdad..a7fca5e0dde2a 100644 --- a/src/shims/time.rs +++ b/src/shims/time.rs @@ -1,12 +1,12 @@ use std::time::{Duration, SystemTime, Instant}; use std::convert::TryFrom; +use rustc_target::abi::LayoutOf; + use crate::stacked_borrows::Tag; use crate::*; use helpers::{immty_from_int_checked, immty_from_uint_checked}; -use rustc_middle::ty::layout::LayoutOf; - /// Returns the time elapsed between the provided time and the unix epoch as a `Duration`. pub fn system_time_to_duration<'tcx>(time: &SystemTime) -> InterpResult<'tcx, Duration> { time.duration_since(SystemTime::UNIX_EPOCH) diff --git a/src/shims/tls.rs b/src/shims/tls.rs index 76f946f724ec4..36ad4bd9b6916 100644 --- a/src/shims/tls.rs +++ b/src/shims/tls.rs @@ -4,8 +4,8 @@ use std::collections::BTreeMap; use log::trace; -use rustc_middle::{ty, ty::layout::{Size, HasDataLayout}}; -use rustc_target::abi::LayoutOf; +use rustc_middle::ty; +use rustc_target::abi::{LayoutOf, Size, HasDataLayout}; use crate::{HelpersEvalContextExt, InterpResult, MPlaceTy, Scalar, StackPopCleanup, Tag}; diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 90920069c5eee..89b2a8bb3e2b2 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -10,7 +10,8 @@ use log::trace; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_middle::mir::RetagKind; -use rustc_middle::ty::{self, layout::Size}; +use rustc_middle::ty; +use rustc_target::abi::Size; use rustc_hir::Mutability; use crate::*; From ef89525249614cd201aaa06d1652b693e9964c45 Mon Sep 17 00:00:00 2001 From: William Brown Date: Fri, 3 Apr 2020 09:07:57 +1000 Subject: [PATCH 1782/3747] Apply feedback --- README.md | 21 ++++----------------- 1 file changed, 4 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index 9ca69df9607fb..f755f85b601ed 100644 --- a/README.md +++ b/README.md @@ -102,28 +102,15 @@ fn does_not_work_on_miri() { An exhaustive list of what `miri` does not support is not available, as this could be an unbounded set with FFI and more. However `miri` will explicitly tell you when it finds -something unsupported with an error: +something unsupported with an error, containing a message such as: ``` error: unsupported operation: can't call foreign function: mach_timebase_info - --> /home/r/.rustup/toolchains/miri/lib/rustlib/src/rust/src/libstd/sys/unix/time.rs:239:13 - | -239 | mach_timebase_info(&mut info); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't call foreign function: mach_timebase_info - | - = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support - = note: inside call to `std::sys::unix::time::inner::info` at /home/r/.rustup/toolchains/miri/lib/rustlib/src/rust/src/libstd/sys/unix/time.rs:156:24 - = note: inside call to `std::sys::unix::time::inner::Instant::checked_sub_instant` at /home/r/.rustup/toolchains/miri/lib/rustlib/src/rust/src/libstd/time.rs:263:9 -note: inside call to `std::time::Instant::duration_since` at tests/run-pass/time.rs:25:20 - --> tests/run-pass/time.rs:25:20 - | -25 | let diff = now2.duration_since(now1); - | ^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: inside call to `main` at /home/r/.rustup/toolchains/miri/lib/rustlib/src/rust/src/libstd/rt.rs:67:34 + ... + = help: this is likely not a bug in the program; it indicates that the program \ + performed an operation that the interpreter does not support ``` -If you do not see an error like this, you are able to keep using `miri`! - ### Running Miri on CI To run Miri on CI, make sure that you handle the case where the latest nightly From bd9ec746a59eec97322eb7e7c24eb350ac94dba0 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 4 Apr 2020 12:07:22 +0200 Subject: [PATCH 1783/3747] Rust bootstrap sysroot now has src in the same place as rust-src, so remove special hack --- rust-version | 2 +- src/bin/cargo-miri.rs | 41 +++++++++++++---------------------------- 2 files changed, 14 insertions(+), 29 deletions(-) diff --git a/rust-version b/rust-version index e3dc200835fde..895cbb5fa9a01 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -537ccdf3ac44c8c7a8d36cbdbe6fb224afabb7ae +6050e523bae6de61de4e060facc43dc512adaccd diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 9ef4996992a43..083918de0f3a0 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -301,34 +301,19 @@ fn setup(ask_user: bool) { .stdout; let sysroot = std::str::from_utf8(&sysroot).unwrap(); let sysroot = Path::new(sysroot.trim_end_matches('\n')); - // First try: `$SYSROOT/lib/rustlib/src/rust`; test if that contains `Cargo.lock`. - let rustup_src = sysroot.join("lib").join("rustlib").join("src").join("rust"); - let base_dir = if rustup_src.join("Cargo.lock").exists() { - // Just use this. - rustup_src - } else { - // Maybe this is a local toolchain built with `x.py` and linked into `rustup`? - // Second try: `$SYSROOT/../../..`; test if that contains `x.py`. - let local_src = sysroot.parent().and_then(Path::parent).and_then(Path::parent); - match local_src { - Some(local_src) if local_src.join("x.py").exists() => { - // Use this. - PathBuf::from(local_src) - } - _ => { - // Fallback: Ask the user to install the `rust-src` component, and use that. - let mut cmd = Command::new("rustup"); - cmd.args(&["component", "add", "rust-src"]); - ask_to_run( - cmd, - ask_user, - "install the rustc-src component for the selected toolchain", - ); - rustup_src - } - } - }; - base_dir.join("src") // Xargo wants the src-subdir + // Check for `$SYSROOT/lib/rustlib/src/rust/src`; test if that contains `libstd/lib.rs`. + let rustup_src = sysroot.join("lib").join("rustlib").join("src").join("rust").join("src"); + if !rustup_src.join("libstd").join("lib.rs").exists() { + // Ask the user to install the `rust-src` component, and use that. + let mut cmd = Command::new("rustup"); + cmd.args(&["component", "add", "rust-src"]); + ask_to_run( + cmd, + ask_user, + "install the rustc-src component for the selected toolchain", + ); + } + rustup_src } }; if !rust_src.exists() { From 73210be73baace3006e9a63b290e2356276a1173 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 4 Apr 2020 19:35:46 +0200 Subject: [PATCH 1784/3747] tweak README --- README.md | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index f755f85b601ed..1c2c885674a5d 100644 --- a/README.md +++ b/README.md @@ -87,8 +87,8 @@ miri run -- -Zmiri-disable-validation` runs the program without validation of basic type invariants and without checking the aliasing of references. When compiling code via `cargo miri`, the `miri` config flag is set. You can -use this to ignore test cases that will fail under Miri because they do things -Miri does not support: +use this to ignore test cases that fail under Miri because they do things Miri +does not support: ```rust #[test] @@ -100,12 +100,11 @@ fn does_not_work_on_miri() { } ``` -An exhaustive list of what `miri` does not support is not available, as this could be -an unbounded set with FFI and more. However `miri` will explicitly tell you when it finds -something unsupported with an error, containing a message such as: +There is no way to list all the infinite things Miri cannot do, but the +interpreter will explicitly tell you when it finds something unsupported: ``` -error: unsupported operation: can't call foreign function: mach_timebase_info +error: unsupported operation: Miri does not support threading ... = help: this is likely not a bug in the program; it indicates that the program \ performed an operation that the interpreter does not support From 0eccf1d9aa753a04b6dd0b276c9bd11a1fd5534e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 5 Apr 2020 09:42:39 +0200 Subject: [PATCH 1785/3747] update Windows leak comment --- src/eval.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/eval.rs b/src/eval.rs index 46e66bc0a81e7..54ace889c7a9d 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -183,8 +183,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( /// Returns `Some(return_code)` if program executed completed. /// Returns `None` if an evaluation error occured. pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) -> Option { - // FIXME: on Windows, locks and TLS dtor management allocate and leave that memory in `static`s. - // So we need https://github.com/rust-lang/miri/issues/940 to fix the leaks there. + // FIXME: on Windows, we ignore leaks (https://github.com/rust-lang/miri/issues/1302). let ignore_leaks = config.ignore_leaks || tcx.sess.target.target.target_os == "windows"; let (mut ecx, ret_place) = match create_ecx(tcx, main_id, config) { From 95ea03c124d988c6c16d826c180a14447e53daa8 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 5 Apr 2020 10:20:12 +0200 Subject: [PATCH 1786/3747] add empty line before backtrace, to separate it from help text --- src/diagnostics.rs | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/diagnostics.rs b/src/diagnostics.rs index 9ff434021150f..d12b21be5a606 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -102,7 +102,7 @@ pub fn report_error<'tcx, 'mir>( e.print_backtrace(); let msg = e.to_string(); - report_msg(ecx, &format!("{}: {}", title, msg), msg, &helps, true) + report_msg(ecx, &format!("{}: {}", title, msg), msg, helps, true) } /// Report an error or note (depending on the `error` argument) at the current frame's current statement. @@ -111,7 +111,7 @@ fn report_msg<'tcx, 'mir>( ecx: &InterpCx<'mir, 'tcx, Evaluator<'tcx>>, title: &str, span_msg: String, - helps: &[String], + mut helps: Vec, error: bool, ) -> Option { let span = if let Some(frame) = ecx.stack().last() { @@ -125,8 +125,12 @@ fn report_msg<'tcx, 'mir>( ecx.tcx.sess.diagnostic().span_note_diag(span, title) }; err.span_label(span, span_msg); - for help in helps { - err.help(help); + if !helps.is_empty() { + // Add visual separator before backtrace. + helps.last_mut().unwrap().push_str("\n"); + for help in helps { + err.help(&help); + } } // Add backtrace let frames = ecx.generate_stacktrace(); @@ -178,7 +182,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx CreatedAlloc(AllocId(id)) => format!("created allocation with id {}", id), }; - report_msg(this, "tracking was triggered", msg, &[], false); + report_msg(this, "tracking was triggered", msg, vec![], false); } }); } From e7fafa190478bfbf6dfe661d8d02dc126fd86840 Mon Sep 17 00:00:00 2001 From: Stein Somers Date: Sun, 5 Apr 2020 15:21:15 +0200 Subject: [PATCH 1787/3747] Replace last_entry with last_key_value --- src/shims/fs.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shims/fs.rs b/src/shims/fs.rs index 52244dcfc847e..c70cc874164f1 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -56,7 +56,7 @@ impl FileHandler { let new_fd = candidate_new_fd.unwrap_or_else(|| { // find_map ran out of BTreeMap entries before finding a free fd, use one plus the // maximum fd in the map - self.handles.last_entry().map(|entry| entry.key().checked_add(1).unwrap()).unwrap_or(min_fd) + self.handles.last_key_value().map(|(fd, _)| fd.checked_add(1).unwrap()).unwrap_or(min_fd) }); self.handles.insert(new_fd, file_handle).unwrap_none(); From 46679bc9eff4f7f7414bc162c0e6c00e7b91cc39 Mon Sep 17 00:00:00 2001 From: David Cook Date: Sun, 26 Jan 2020 14:25:09 -0600 Subject: [PATCH 1788/3747] Add shims for RwLock::try_read/RwLock::try_write --- src/shims/foreign_items/posix.rs | 2 ++ tests/run-pass/sync.rs | 2 ++ 2 files changed, 4 insertions(+) diff --git a/src/shims/foreign_items/posix.rs b/src/shims/foreign_items/posix.rs index c9fd59c693271..4be63804a45b7 100644 --- a/src/shims/foreign_items/posix.rs +++ b/src/shims/foreign_items/posix.rs @@ -271,8 +271,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "pthread_mutex_unlock" | "pthread_mutex_destroy" | "pthread_rwlock_rdlock" + | "pthread_rwlock_tryrdlock" | "pthread_rwlock_unlock" | "pthread_rwlock_wrlock" + | "pthread_rwlock_trywrlock" | "pthread_rwlock_destroy" | "pthread_condattr_init" | "pthread_condattr_setclock" diff --git a/tests/run-pass/sync.rs b/tests/run-pass/sync.rs index 54d79566eae4b..14243349f9671 100644 --- a/tests/run-pass/sync.rs +++ b/tests/run-pass/sync.rs @@ -12,7 +12,9 @@ fn main() { { let rw = sync::RwLock::new(0); drop(rw.read()); + drop(rw.try_read()); drop(rw.write()); + drop(rw.try_write()); drop(rw); } } From 88f319fb4c0597856d62ee67eba6354b496cbe8f Mon Sep 17 00:00:00 2001 From: David Cook Date: Mon, 27 Jan 2020 21:49:06 -0600 Subject: [PATCH 1789/3747] Add failing tests for mutex and rwlock --- src/shims/foreign_items/posix.rs | 1 + tests/run-pass/sync.rs | 73 +++++++++++++++++++++++++++++--- 2 files changed, 68 insertions(+), 6 deletions(-) diff --git a/src/shims/foreign_items/posix.rs b/src/shims/foreign_items/posix.rs index 4be63804a45b7..061ae93d8f675 100644 --- a/src/shims/foreign_items/posix.rs +++ b/src/shims/foreign_items/posix.rs @@ -268,6 +268,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "pthread_mutex_init" | "pthread_mutexattr_destroy" | "pthread_mutex_lock" + | "pthread_mutex_trylock" | "pthread_mutex_unlock" | "pthread_mutex_destroy" | "pthread_rwlock_rdlock" diff --git a/tests/run-pass/sync.rs b/tests/run-pass/sync.rs index 14243349f9671..6a0b41d5f6a79 100644 --- a/tests/run-pass/sync.rs +++ b/tests/run-pass/sync.rs @@ -1,20 +1,81 @@ // Just instantiate some data structures to make sure we got all their foreign items covered. // Requires full MIR on Windows. +#![feature(rustc_private)] + use std::sync; +extern crate libc; + fn main() { let m = sync::Mutex::new(0); - drop(m.lock()); + { + let _guard = m.lock(); + let try_lock_error = m.try_lock().unwrap_err(); + if let sync::TryLockError::Poisoned(e) = try_lock_error { + panic!("{}", e); + } + } + drop(m.try_lock().unwrap()); drop(m); #[cfg(not(target_os = "windows"))] // TODO: implement RwLock on Windows { let rw = sync::RwLock::new(0); - drop(rw.read()); - drop(rw.try_read()); - drop(rw.write()); - drop(rw.try_write()); - drop(rw); + { + let _read_guard = rw.read().unwrap(); + drop(rw.read().unwrap()); + drop(rw.try_read().unwrap()); + let try_lock_error = rw.try_write().unwrap_err(); + if let sync::TryLockError::Poisoned(e) = try_lock_error { + panic!("{}", e); + } + } + + { + let _write_guard = rw.write().unwrap(); + let try_lock_error = rw.try_read().unwrap_err(); + if let sync::TryLockError::Poisoned(e) = try_lock_error { + panic!("{}", e); + } + let try_lock_error = rw.try_write().unwrap_err(); + if let sync::TryLockError::Poisoned(e) = try_lock_error { + panic!("{}", e); + } + } + + // need to go a layer deeper and test the behavior of libc functions, because + // std::sys::unix::rwlock::RWLock keeps track of write_locked and num_readers + + unsafe { + let mut mutex: libc::pthread_mutex_t = std::mem::zeroed(); + assert_eq!(libc::pthread_mutex_init(&mut mutex as *mut _, std::ptr::null_mut()), 0); + assert_eq!(libc::pthread_mutex_lock(&mut mutex as *mut _), 0); + assert_eq!(libc::pthread_mutex_trylock(&mut mutex as *mut _), libc::EBUSY); + assert_eq!(libc::pthread_mutex_unlock(&mut mutex as *mut _), 0); + assert_eq!(libc::pthread_mutex_trylock(&mut mutex as *mut _), 0); + assert_eq!(libc::pthread_mutex_unlock(&mut mutex as *mut _), 0); + assert_eq!(libc::pthread_mutex_destroy(&mut mutex as *mut _), 0); + } + + unsafe { + let mut rw: libc::pthread_rwlock_t = std::mem::zeroed(); + assert_eq!(libc::pthread_rwlock_init(&mut rw as *mut _, std::ptr::null_mut()), 0); + + assert_eq!(libc::pthread_rwlock_rdlock(&mut rw as *mut _), 0); + assert_eq!(libc::pthread_rwlock_rdlock(&mut rw as *mut _), 0); + assert_eq!(libc::pthread_rwlock_unlock(&mut rw as *mut _), 0); + assert_eq!(libc::pthread_rwlock_tryrdlock(&mut rw as *mut _), 0); + assert_eq!(libc::pthread_rwlock_unlock(&mut rw as *mut _), 0); + assert_eq!(libc::pthread_rwlock_trywrlock(&mut rw as *mut _), libc::EBUSY); + assert_eq!(libc::pthread_rwlock_unlock(&mut rw as *mut _), 0); + + assert_eq!(libc::pthread_rwlock_wrlock(&mut rw as *mut _), 0); + assert_eq!(libc::pthread_rwlock_tryrdlock(&mut rw as *mut _), libc::EBUSY); + assert_eq!(libc::pthread_rwlock_trywrlock(&mut rw as *mut _), libc::EBUSY); + assert_eq!(libc::pthread_rwlock_unlock(&mut rw as *mut _), 0); + + assert_eq!(libc::pthread_rwlock_destroy(&mut rw as *mut _), 0); + } } } From c2683dad34f6f51761661840de8164dd001bb782 Mon Sep 17 00:00:00 2001 From: David Cook Date: Tue, 28 Jan 2020 21:07:09 -0600 Subject: [PATCH 1790/3747] Clean up test case --- tests/run-pass/sync.rs | 65 +++++++++++++++++++++--------------------- 1 file changed, 32 insertions(+), 33 deletions(-) diff --git a/tests/run-pass/sync.rs b/tests/run-pass/sync.rs index 6a0b41d5f6a79..8c92b47fb276c 100644 --- a/tests/run-pass/sync.rs +++ b/tests/run-pass/sync.rs @@ -3,45 +3,33 @@ #![feature(rustc_private)] -use std::sync; +use std::sync::{Mutex, RwLock, TryLockError}; extern crate libc; fn main() { - let m = sync::Mutex::new(0); + let m = Mutex::new(0); { let _guard = m.lock(); - let try_lock_error = m.try_lock().unwrap_err(); - if let sync::TryLockError::Poisoned(e) = try_lock_error { - panic!("{}", e); - } + assert!(m.try_lock().unwrap_err().would_block()); } drop(m.try_lock().unwrap()); drop(m); #[cfg(not(target_os = "windows"))] // TODO: implement RwLock on Windows { - let rw = sync::RwLock::new(0); + let rw = RwLock::new(0); { let _read_guard = rw.read().unwrap(); drop(rw.read().unwrap()); drop(rw.try_read().unwrap()); - let try_lock_error = rw.try_write().unwrap_err(); - if let sync::TryLockError::Poisoned(e) = try_lock_error { - panic!("{}", e); - } + assert!(rw.try_write().unwrap_err().would_block()); } { let _write_guard = rw.write().unwrap(); - let try_lock_error = rw.try_read().unwrap_err(); - if let sync::TryLockError::Poisoned(e) = try_lock_error { - panic!("{}", e); - } - let try_lock_error = rw.try_write().unwrap_err(); - if let sync::TryLockError::Poisoned(e) = try_lock_error { - panic!("{}", e); - } + assert!(rw.try_read().unwrap_err().would_block()); + assert!(rw.try_write().unwrap_err().would_block()); } // need to go a layer deeper and test the behavior of libc functions, because @@ -58,24 +46,35 @@ fn main() { assert_eq!(libc::pthread_mutex_destroy(&mut mutex as *mut _), 0); } + let rw = std::cell::UnsafeCell::new(libc::PTHREAD_RWLOCK_INITIALIZER); unsafe { - let mut rw: libc::pthread_rwlock_t = std::mem::zeroed(); - assert_eq!(libc::pthread_rwlock_init(&mut rw as *mut _, std::ptr::null_mut()), 0); + assert_eq!(libc::pthread_rwlock_rdlock(rw.get()), 0); + assert_eq!(libc::pthread_rwlock_rdlock(rw.get()), 0); + assert_eq!(libc::pthread_rwlock_unlock(rw.get()), 0); + assert_eq!(libc::pthread_rwlock_tryrdlock(rw.get()), 0); + assert_eq!(libc::pthread_rwlock_unlock(rw.get()), 0); + assert_eq!(libc::pthread_rwlock_trywrlock(rw.get()), libc::EBUSY); + assert_eq!(libc::pthread_rwlock_unlock(rw.get()), 0); + + assert_eq!(libc::pthread_rwlock_wrlock(rw.get()), 0); + assert_eq!(libc::pthread_rwlock_tryrdlock(rw.get()), libc::EBUSY); + assert_eq!(libc::pthread_rwlock_trywrlock(rw.get()), libc::EBUSY); + assert_eq!(libc::pthread_rwlock_unlock(rw.get()), 0); - assert_eq!(libc::pthread_rwlock_rdlock(&mut rw as *mut _), 0); - assert_eq!(libc::pthread_rwlock_rdlock(&mut rw as *mut _), 0); - assert_eq!(libc::pthread_rwlock_unlock(&mut rw as *mut _), 0); - assert_eq!(libc::pthread_rwlock_tryrdlock(&mut rw as *mut _), 0); - assert_eq!(libc::pthread_rwlock_unlock(&mut rw as *mut _), 0); - assert_eq!(libc::pthread_rwlock_trywrlock(&mut rw as *mut _), libc::EBUSY); - assert_eq!(libc::pthread_rwlock_unlock(&mut rw as *mut _), 0); + assert_eq!(libc::pthread_rwlock_destroy(rw.get()), 0); + } + } +} - assert_eq!(libc::pthread_rwlock_wrlock(&mut rw as *mut _), 0); - assert_eq!(libc::pthread_rwlock_tryrdlock(&mut rw as *mut _), libc::EBUSY); - assert_eq!(libc::pthread_rwlock_trywrlock(&mut rw as *mut _), libc::EBUSY); - assert_eq!(libc::pthread_rwlock_unlock(&mut rw as *mut _), 0); +trait TryLockErrorExt { + fn would_block(&self) -> bool; +} - assert_eq!(libc::pthread_rwlock_destroy(&mut rw as *mut _), 0); +impl TryLockErrorExt for TryLockError { + fn would_block(&self) -> bool { + match self { + TryLockError::WouldBlock => true, + TryLockError::Poisoned(_) => false, } } } From dd9896b0f8752c71c82c5d538ec0b115ffb5cf4e Mon Sep 17 00:00:00 2001 From: David Cook Date: Mon, 17 Feb 2020 21:30:24 -0600 Subject: [PATCH 1791/3747] Implement mutex and rwlock functions --- src/lib.rs | 1 + src/shims/foreign_items/posix.rs | 91 +++++-- src/shims/mod.rs | 1 + src/shims/sync.rs | 436 +++++++++++++++++++++++++++++++ tests/run-pass/sync.rs | 97 ++++--- 5 files changed, 567 insertions(+), 59 deletions(-) create mode 100644 src/shims/sync.rs diff --git a/src/lib.rs b/src/lib.rs index c04fbfeab98ca..2f381b4a34546 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -39,6 +39,7 @@ pub use crate::shims::fs::{DirHandler, EvalContextExt as FileEvalContextExt, Fil pub use crate::shims::intrinsics::EvalContextExt as IntrinsicsEvalContextExt; pub use crate::shims::os_str::EvalContextExt as OsStrEvalContextExt; pub use crate::shims::panic::{CatchUnwindData, EvalContextExt as PanicEvalContextExt}; +pub use crate::shims::sync::{EvalContextExt as SyncEvalContextExt}; pub use crate::shims::time::EvalContextExt as TimeEvalContextExt; pub use crate::shims::tls::{EvalContextExt as TlsEvalContextExt, TlsData}; pub use crate::shims::EvalContextExt as ShimsEvalContextExt; diff --git a/src/shims/foreign_items/posix.rs b/src/shims/foreign_items/posix.rs index 061ae93d8f675..2b9e94ba11db4 100644 --- a/src/shims/foreign_items/posix.rs +++ b/src/shims/foreign_items/posix.rs @@ -255,28 +255,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_null(dest)?; } - // Incomplete shims that we "stub out" just to get pre-main initialziation code to work. + // Incomplete shims that we "stub out" just to get pre-main initialization code to work. // These shims are enabled only when the caller is in the standard library. | "pthread_attr_init" | "pthread_attr_destroy" | "pthread_self" - | "pthread_attr_setstacksize" if this.frame().instance.to_string().starts_with("std::sys::unix::") => { - this.write_null(dest)?; - } - | "pthread_mutexattr_init" - | "pthread_mutexattr_settype" - | "pthread_mutex_init" - | "pthread_mutexattr_destroy" - | "pthread_mutex_lock" - | "pthread_mutex_trylock" - | "pthread_mutex_unlock" - | "pthread_mutex_destroy" - | "pthread_rwlock_rdlock" - | "pthread_rwlock_tryrdlock" - | "pthread_rwlock_unlock" - | "pthread_rwlock_wrlock" - | "pthread_rwlock_trywrlock" - | "pthread_rwlock_destroy" + | "pthread_attr_setstacksize" | "pthread_condattr_init" | "pthread_condattr_setclock" | "pthread_cond_init" @@ -285,6 +269,77 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx => { this.write_null(dest)?; } + + "pthread_mutexattr_init" => { + let result = this.pthread_mutexattr_init(args[0])?; + this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + } + + "pthread_mutexattr_settype" => { + let result = this.pthread_mutexattr_settype(args[0], args[1])?; + this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + } + + "pthread_mutexattr_destroy" => { + let result = this.pthread_mutexattr_destroy(args[0])?; + this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + } + + "pthread_mutex_init" => { + let result = this.pthread_mutex_init(args[0], args[1])?; + this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + } + + "pthread_mutex_lock" => { + let result = this.pthread_mutex_lock(args[0])?; + this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + } + + "pthread_mutex_trylock" => { + let result = this.pthread_mutex_trylock(args[0])?; + this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + } + + "pthread_mutex_unlock" => { + let result = this.pthread_mutex_unlock(args[0])?; + this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + } + + "pthread_mutex_destroy" => { + let result = this.pthread_mutex_destroy(args[0])?; + this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + } + + "pthread_rwlock_rdlock" => { + let result = this.pthread_rwlock_rdlock(args[0])?; + this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + } + + "pthread_rwlock_tryrdlock" => { + let result = this.pthread_rwlock_tryrdlock(args[0])?; + this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + } + + "pthread_rwlock_wrlock" => { + let result = this.pthread_rwlock_wrlock(args[0])?; + this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + } + + "pthread_rwlock_trywrlock" => { + let result = this.pthread_rwlock_trywrlock(args[0])?; + this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + } + + "pthread_rwlock_unlock" => { + let result = this.pthread_rwlock_unlock(args[0])?; + this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + } + + "pthread_rwlock_destroy" => { + let result = this.pthread_rwlock_destroy(args[0])?; + this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + } + | "signal" | "sigaction" | "sigaltstack" diff --git a/src/shims/mod.rs b/src/shims/mod.rs index e5db537cff1f7..764e404141e4d 100644 --- a/src/shims/mod.rs +++ b/src/shims/mod.rs @@ -5,6 +5,7 @@ pub mod fs; pub mod intrinsics; pub mod os_str; pub mod panic; +pub mod sync; pub mod time; pub mod tls; diff --git a/src/shims/sync.rs b/src/shims/sync.rs new file mode 100644 index 0000000000000..c9329586627dd --- /dev/null +++ b/src/shims/sync.rs @@ -0,0 +1,436 @@ +use rustc_middle::ty::{TyKind, TypeAndMut}; +use rustc_target::abi::{LayoutOf, Size}; + +use crate::stacked_borrows::Tag; +use crate::*; + +impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} +pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { + // pthread_mutexattr_t is either 4 or 8 bytes, depending on the platform + // memory layout: store an i32 in the first four bytes equal to the + // corresponding libc mutex kind constant (i.e. PTHREAD_MUTEX_NORMAL) + + fn pthread_mutexattr_init(&mut self, attr_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + let this = self.eval_context_mut(); + + check_ptr_target_min_size(this, attr_op, 4)?; + + let attr = this.read_scalar(attr_op)?.not_undef()?; + if this.is_null(attr)? { + return this.eval_libc_i32("EINVAL"); + } + + let attr_place = this.deref_operand(attr_op)?; + let i32_layout = this.layout_of(this.tcx.types.i32)?; + let kind_place = attr_place.offset(Size::ZERO, MemPlaceMeta::None, i32_layout, this)?; + let default_kind = this.eval_libc("PTHREAD_MUTEX_DEFAULT")?; + this.write_scalar(default_kind, kind_place.into())?; + + Ok(0) + } + + fn pthread_mutexattr_settype( + &mut self, + attr_op: OpTy<'tcx, Tag>, + kind_op: OpTy<'tcx, Tag>, + ) -> InterpResult<'tcx, i32> { + let this = self.eval_context_mut(); + + check_ptr_target_min_size(this, attr_op, 4)?; + + let attr = this.read_scalar(attr_op)?.not_undef()?; + if this.is_null(attr)? { + return this.eval_libc_i32("EINVAL"); + } + + let kind = this.read_scalar(kind_op)?.not_undef()?; + if kind == this.eval_libc("PTHREAD_MUTEX_NORMAL")? || + kind == this.eval_libc("PTHREAD_MUTEX_ERRORCHECK")? || + kind == this.eval_libc("PTHREAD_MUTEX_RECURSIVE")? { + let attr_place = this.deref_operand(attr_op)?; + let i32_layout = this.layout_of(this.tcx.types.i32)?; + let kind_place = attr_place.offset(Size::ZERO, MemPlaceMeta::None, i32_layout, this)?; + this.write_scalar(kind, kind_place.into())?; + } else { + let einval = this.eval_libc_i32("EINVAL")?; + return Ok(einval); + } + + Ok(0) + } + + fn pthread_mutexattr_destroy(&mut self, attr_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + let this = self.eval_context_mut(); + + check_ptr_target_min_size(this, attr_op, 4)?; + + let attr = this.read_scalar(attr_op)?.not_undef()?; + if this.is_null(attr)? { + return this.eval_libc_i32("EINVAL"); + } + + let attr_place = this.deref_operand(attr_op)?; + let i32_layout = this.layout_of(this.tcx.types.i32)?; + let kind_place = attr_place.offset(Size::ZERO, MemPlaceMeta::None, i32_layout, this)?; + this.write_scalar(ScalarMaybeUndef::Undef, kind_place.into())?; + + Ok(0) + } + + // pthread_mutex_t is between 24 and 48 bytes, depending on the platform + // memory layout: + // bytes 0-3: count of how many times this mutex has been locked, as a u32 + // bytes 12-15: mutex kind, as an i32 + // (the kind should be at this offset for compatibility with the static + // initializer macro) + + fn pthread_mutex_init( + &mut self, + mutex_op: OpTy<'tcx, Tag>, + attr_op: OpTy<'tcx, Tag>, + ) -> InterpResult<'tcx, i32> { + let this = self.eval_context_mut(); + + check_ptr_target_min_size(this, mutex_op, 16)?; + check_ptr_target_min_size(this, attr_op, 4)?; + + let mutex = this.read_scalar(mutex_op)?.not_undef()?; + if this.is_null(mutex)? { + return this.eval_libc_i32("EINVAL"); + } + let mutex_place = this.deref_operand(mutex_op)?; + + let i32_layout = this.layout_of(this.tcx.types.i32)?; + + let attr = this.read_scalar(attr_op)?.not_undef()?; + let kind = if this.is_null(attr)? { + this.eval_libc("PTHREAD_MUTEX_DEFAULT")? + } else { + let attr_place = this.deref_operand(attr_op)?; + let attr_kind_place = attr_place.offset(Size::ZERO, MemPlaceMeta::None, i32_layout, this)?; + this.read_scalar(attr_kind_place.into())?.not_undef()? + }; + + let u32_layout = this.layout_of(this.tcx.types.u32)?; + let locked_count_place = mutex_place.offset(Size::ZERO, MemPlaceMeta::None, u32_layout, this)?; + this.write_scalar(Scalar::from_u32(0), locked_count_place.into())?; + + let mutex_kind_place = mutex_place.offset(Size::from_bytes(12), MemPlaceMeta::None, i32_layout, &*this.tcx)?; + this.write_scalar(kind, mutex_kind_place.into())?; + + Ok(0) + } + + fn pthread_mutex_lock(&mut self, mutex_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + let this = self.eval_context_mut(); + + check_ptr_target_min_size(this, mutex_op, 16)?; + + let mutex = this.read_scalar(mutex_op)?.not_undef()?; + if this.is_null(mutex)? { + return this.eval_libc_i32("EINVAL"); + } + let mutex_place = this.deref_operand(mutex_op)?; + + let i32_layout = this.layout_of(this.tcx.types.i32)?; + let kind_place = mutex_place.offset(Size::from_bytes(12), MemPlaceMeta::None, i32_layout, this)?; + let kind = this.read_scalar(kind_place.into())?.not_undef()?; + + let u32_layout = this.layout_of(this.tcx.types.u32)?; + let locked_count_place = mutex_place.offset(Size::ZERO, MemPlaceMeta::None, u32_layout, this)?; + let locked_count = this.read_scalar(locked_count_place.into())?.to_u32()?; + + if kind == this.eval_libc("PTHREAD_MUTEX_NORMAL")? { + if locked_count == 0 { + this.write_scalar(Scalar::from_u32(1), locked_count_place.into())?; + Ok(0) + } else { + throw_unsup_format!("Deadlock due to locking a PTHREAD_MUTEX_NORMAL mutex twice"); + } + } else if kind == this.eval_libc("PTHREAD_MUTEX_ERRORCHECK")? { + if locked_count == 0 { + this.write_scalar(Scalar::from_u32(1), locked_count_place.into())?; + Ok(0) + } else { + this.eval_libc_i32("EDEADLK") + } + } else if kind == this.eval_libc("PTHREAD_MUTEX_RECURSIVE")? { + this.write_scalar(Scalar::from_u32(locked_count + 1), locked_count_place.into())?; + Ok(0) + } else { + this.eval_libc_i32("EINVAL") + } + } + + fn pthread_mutex_trylock(&mut self, mutex_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + let this = self.eval_context_mut(); + + check_ptr_target_min_size(this, mutex_op, 16)?; + + let mutex = this.read_scalar(mutex_op)?.not_undef()?; + if this.is_null(mutex)? { + return this.eval_libc_i32("EINVAL"); + } + let mutex_place = this.deref_operand(mutex_op)?; + + let i32_layout = this.layout_of(this.tcx.types.i32)?; + let kind_place = mutex_place.offset(Size::from_bytes(12), MemPlaceMeta::None, i32_layout, this)?; + let kind = this.read_scalar(kind_place.into())?.not_undef()?; + + let u32_layout = this.layout_of(this.tcx.types.u32)?; + let locked_count_place = mutex_place.offset(Size::ZERO, MemPlaceMeta::None, u32_layout, this)?; + let locked_count = this.read_scalar(locked_count_place.into())?.to_u32()?; + + if kind == this.eval_libc("PTHREAD_MUTEX_NORMAL")? || + kind == this.eval_libc("PTHREAD_MUTEX_ERRORCHECK")? { + if locked_count == 0 { + this.write_scalar(Scalar::from_u32(1), locked_count_place.into())?; + Ok(0) + } else { + this.eval_libc_i32("EBUSY") + } + } else if kind == this.eval_libc("PTHREAD_MUTEX_RECURSIVE")? { + this.write_scalar(Scalar::from_u32(locked_count + 1), locked_count_place.into())?; + Ok(0) + } else { + this.eval_libc_i32("EINVAL") + } + } + + fn pthread_mutex_unlock(&mut self, mutex_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + let this = self.eval_context_mut(); + + check_ptr_target_min_size(this, mutex_op, 16)?; + + let mutex = this.read_scalar(mutex_op)?.not_undef()?; + if this.is_null(mutex)? { + return this.eval_libc_i32("EINVAL"); + } + let mutex_place = this.deref_operand(mutex_op)?; + + let i32_layout = this.layout_of(this.tcx.types.i32)?; + let kind_place = mutex_place.offset(Size::from_bytes(12), MemPlaceMeta::None, i32_layout, this)?; + let kind = this.read_scalar(kind_place.into())?.not_undef()?; + + let u32_layout = this.layout_of(this.tcx.types.u32)?; + let locked_count_place = mutex_place.offset(Size::ZERO, MemPlaceMeta::None, u32_layout, this)?; + let locked_count = this.read_scalar(locked_count_place.into())?.to_u32()?; + + if kind == this.eval_libc("PTHREAD_MUTEX_NORMAL")? { + if locked_count == 1 { + this.write_scalar(Scalar::from_u32(0), locked_count_place.into())?; + Ok(0) + } else { + throw_ub_format!("Attempted to unlock a PTHREAD_MUTEX_NORMAL mutex that was not locked"); + } + } else if kind == this.eval_libc("PTHREAD_MUTEX_ERRORCHECK")? { + if locked_count == 1 { + this.write_scalar(Scalar::from_u32(0), locked_count_place.into())?; + Ok(0) + } else { + this.eval_libc_i32("EPERM") + } + } else if kind == this.eval_libc("PTHREAD_MUTEX_RECURSIVE")? { + if locked_count > 0 { + this.write_scalar(Scalar::from_u32(locked_count - 1), locked_count_place.into())?; + Ok(0) + } else { + this.eval_libc_i32("EPERM") + } + } else { + this.eval_libc_i32("EINVAL") + } + } + + fn pthread_mutex_destroy(&mut self, mutex_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + let this = self.eval_context_mut(); + + check_ptr_target_min_size(this, mutex_op, 16)?; + + let mutex = this.read_scalar(mutex_op)?.not_undef()?; + if this.is_null(mutex)? { + return this.eval_libc_i32("EINVAL"); + } + let mutex_place = this.deref_operand(mutex_op)?; + + let u32_layout = this.layout_of(this.tcx.types.u32)?; + let locked_count_place = mutex_place.offset(Size::ZERO, MemPlaceMeta::None, u32_layout, this)?; + if this.read_scalar(locked_count_place.into())?.to_u32()? != 0 { + return this.eval_libc_i32("EBUSY"); + } + + let i32_layout = this.layout_of(this.tcx.types.i32)?; + let kind_place = mutex_place.offset(Size::from_bytes(12), MemPlaceMeta::None, i32_layout, this)?; + this.write_scalar(ScalarMaybeUndef::Undef, kind_place.into())?; + this.write_scalar(ScalarMaybeUndef::Undef, locked_count_place.into())?; + + Ok(0) + } + + // pthread_rwlock_t is between 32 and 56 bytes, depending on the platform + // memory layout: + // bytes 0-3: reader count, as a u32 + // bytes 4-7: writer count, as a u32 + + fn pthread_rwlock_rdlock(&mut self, rwlock_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + let this = self.eval_context_mut(); + + check_ptr_target_min_size(this, rwlock_op, 8)?; + + let rwlock = this.read_scalar(rwlock_op)?.not_undef()?; + if this.is_null(rwlock)? { + return this.eval_libc_i32("EINVAL"); + } + let rwlock_place = this.deref_operand(rwlock_op)?; + + let u32_layout = this.layout_of(this.tcx.types.u32)?; + let readers_place = rwlock_place.offset(Size::ZERO, MemPlaceMeta::None, u32_layout, this)?; + let writers_place = rwlock_place.offset(Size::from_bytes(4), MemPlaceMeta::None, u32_layout, this)?; + let readers = this.read_scalar(readers_place.into())?.to_u32()?; + let writers = this.read_scalar(writers_place.into())?.to_u32()?; + if writers != 0 { + throw_unsup_format!("Deadlock due to read-locking a pthreads read-write lock while it is already write-locked"); + } else { + this.write_scalar(Scalar::from_u32(readers + 1), readers_place.into())?; + Ok(0) + } + } + + fn pthread_rwlock_tryrdlock(&mut self, rwlock_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + let this = self.eval_context_mut(); + + check_ptr_target_min_size(this, rwlock_op, 8)?; + + let rwlock = this.read_scalar(rwlock_op)?.not_undef()?; + if this.is_null(rwlock)? { + return this.eval_libc_i32("EINVAL"); + } + let rwlock_place = this.deref_operand(rwlock_op)?; + + let u32_layout = this.layout_of(this.tcx.types.u32)?; + let readers_place = rwlock_place.offset(Size::ZERO, MemPlaceMeta::None, u32_layout, this)?; + let writers_place = rwlock_place.offset(Size::from_bytes(4), MemPlaceMeta::None, u32_layout, this)?; + let readers = this.read_scalar(readers_place.into())?.to_u32()?; + let writers = this.read_scalar(writers_place.into())?.to_u32()?; + if writers != 0 { + this.eval_libc_i32("EBUSY") + } else { + this.write_scalar(Scalar::from_u32(readers + 1), readers_place.into())?; + Ok(0) + } + } + + fn pthread_rwlock_wrlock(&mut self, rwlock_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + let this = self.eval_context_mut(); + + check_ptr_target_min_size(this, rwlock_op, 8)?; + + let rwlock = this.read_scalar(rwlock_op)?.not_undef()?; + if this.is_null(rwlock)? { + return this.eval_libc_i32("EINVAL"); + } + let rwlock_place = this.deref_operand(rwlock_op)?; + + let u32_layout = this.layout_of(this.tcx.types.u32)?; + let readers_place = rwlock_place.offset(Size::ZERO, MemPlaceMeta::None, u32_layout, this)?; + let writers_place = rwlock_place.offset(Size::from_bytes(4), MemPlaceMeta::None, u32_layout, this)?; + let readers = this.read_scalar(readers_place.into())?.to_u32()?; + let writers = this.read_scalar(writers_place.into())?.to_u32()?; + if readers != 0 { + throw_unsup_format!("Deadlock due to write-locking a pthreads read-write lock while it is already read-locked"); + } else if writers != 0 { + throw_unsup_format!("Deadlock due to write-locking a pthreads read-write lock while it is already write-locked"); + } else { + this.write_scalar(Scalar::from_u32(1), writers_place.into())?; + Ok(0) + } + } + + fn pthread_rwlock_trywrlock(&mut self, rwlock_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + let this = self.eval_context_mut(); + + check_ptr_target_min_size(this, rwlock_op, 8)?; + + let rwlock = this.read_scalar(rwlock_op)?.not_undef()?; + if this.is_null(rwlock)? { + return this.eval_libc_i32("EINVAL"); + } + let rwlock_place = this.deref_operand(rwlock_op)?; + + let u32_layout = this.layout_of(this.tcx.types.u32)?; + let readers_place = rwlock_place.offset(Size::ZERO, MemPlaceMeta::None, u32_layout, this)?; + let writers_place = rwlock_place.offset(Size::from_bytes(4), MemPlaceMeta::None, u32_layout, this)?; + let readers = this.read_scalar(readers_place.into())?.to_u32()?; + let writers = this.read_scalar(writers_place.into())?.to_u32()?; + if readers != 0 || writers != 0 { + this.eval_libc_i32("EBUSY") + } else { + this.write_scalar(Scalar::from_u32(1), writers_place.into())?; + Ok(0) + } + } + + fn pthread_rwlock_unlock(&mut self, rwlock_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + let this = self.eval_context_mut(); + + check_ptr_target_min_size(this, rwlock_op, 8)?; + + let rwlock = this.read_scalar(rwlock_op)?.not_undef()?; + if this.is_null(rwlock)? { + return this.eval_libc_i32("EINVAL"); + } + let rwlock_place = this.deref_operand(rwlock_op)?; + + let u32_layout = this.layout_of(this.tcx.types.u32)?; + let readers_place = rwlock_place.offset(Size::ZERO, MemPlaceMeta::None, u32_layout, this)?; + let writers_place = rwlock_place.offset(Size::from_bytes(4), MemPlaceMeta::None, u32_layout, this)?; + let readers = this.read_scalar(readers_place.into())?.to_u32()?; + let writers = this.read_scalar(writers_place.into())?.to_u32()?; + if readers != 0 { + this.write_scalar(Scalar::from_u32(readers - 1), readers_place.into())?; + Ok(0) + } else if writers != 0 { + this.write_scalar(Scalar::from_u32(0), writers_place.into())?; + Ok(0) + } else { + this.eval_libc_i32("EPERM") + } + } + + fn pthread_rwlock_destroy(&mut self, rwlock_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + let this = self.eval_context_mut(); + + check_ptr_target_min_size(this, rwlock_op, 8)?; + + let rwlock = this.read_scalar(rwlock_op)?.not_undef()?; + if this.is_null(rwlock)? { + return this.eval_libc_i32("EINVAL"); + } + let rwlock_place = this.deref_operand(rwlock_op)?; + + let u32_layout = this.layout_of(this.tcx.types.u32)?; + let readers_place = rwlock_place.offset(Size::ZERO, MemPlaceMeta::None, u32_layout, this)?; + if this.read_scalar(readers_place.into())?.to_u32()? != 0 { + return this.eval_libc_i32("EBUSY"); + } + let writers_place = rwlock_place.offset(Size::from_bytes(4), MemPlaceMeta::None, u32_layout, this)?; + if this.read_scalar(writers_place.into())?.to_u32()? != 0 { + return this.eval_libc_i32("EBUSY"); + } + + this.write_scalar(ScalarMaybeUndef::Undef, readers_place.into())?; + this.write_scalar(ScalarMaybeUndef::Undef, writers_place.into())?; + + Ok(0) + } +} + +fn check_ptr_target_min_size<'mir, 'tcx: 'mir>(ecx: &MiriEvalContext<'mir, 'tcx>, operand: OpTy<'tcx, Tag>, min_size: u64) -> InterpResult<'tcx, ()> { + let target_ty = match operand.layout.ty.kind { + TyKind::RawPtr(TypeAndMut{ ty, mutbl: _ }) => ty, + _ => panic!("Argument to pthread function was not a raw pointer"), + }; + let target_layout = ecx.layout_of(target_ty)?; + assert!(target_layout.size.bytes() >= min_size); + Ok(()) +} diff --git a/tests/run-pass/sync.rs b/tests/run-pass/sync.rs index 8c92b47fb276c..d6ce939c6c36c 100644 --- a/tests/run-pass/sync.rs +++ b/tests/run-pass/sync.rs @@ -1,4 +1,3 @@ -// Just instantiate some data structures to make sure we got all their foreign items covered. // Requires full MIR on Windows. #![feature(rustc_private)] @@ -8,6 +7,16 @@ use std::sync::{Mutex, RwLock, TryLockError}; extern crate libc; fn main() { + test_mutex(); + #[cfg(not(target_os = "windows"))] // TODO: implement RwLock on Windows + { + test_rwlock_stdlib(); + test_rwlock_libc_init(); + test_rwlock_libc_static_initializer(); + } +} + +fn test_mutex() { let m = Mutex::new(0); { let _guard = m.lock(); @@ -15,54 +24,60 @@ fn main() { } drop(m.try_lock().unwrap()); drop(m); +} - #[cfg(not(target_os = "windows"))] // TODO: implement RwLock on Windows +#[cfg(not(target_os = "windows"))] +fn test_rwlock_stdlib() { + let rw = RwLock::new(0); { - let rw = RwLock::new(0); - { - let _read_guard = rw.read().unwrap(); - drop(rw.read().unwrap()); - drop(rw.try_read().unwrap()); - assert!(rw.try_write().unwrap_err().would_block()); - } + let _read_guard = rw.read().unwrap(); + drop(rw.read().unwrap()); + drop(rw.try_read().unwrap()); + assert!(rw.try_write().unwrap_err().would_block()); + } - { - let _write_guard = rw.write().unwrap(); - assert!(rw.try_read().unwrap_err().would_block()); - assert!(rw.try_write().unwrap_err().would_block()); - } + { + let _write_guard = rw.write().unwrap(); + assert!(rw.try_read().unwrap_err().would_block()); + assert!(rw.try_write().unwrap_err().would_block()); + } +} - // need to go a layer deeper and test the behavior of libc functions, because - // std::sys::unix::rwlock::RWLock keeps track of write_locked and num_readers +// need to go a layer deeper and test the behavior of libc functions, because +// std::sys::unix::rwlock::RWLock keeps track of write_locked and num_readers - unsafe { - let mut mutex: libc::pthread_mutex_t = std::mem::zeroed(); - assert_eq!(libc::pthread_mutex_init(&mut mutex as *mut _, std::ptr::null_mut()), 0); - assert_eq!(libc::pthread_mutex_lock(&mut mutex as *mut _), 0); - assert_eq!(libc::pthread_mutex_trylock(&mut mutex as *mut _), libc::EBUSY); - assert_eq!(libc::pthread_mutex_unlock(&mut mutex as *mut _), 0); - assert_eq!(libc::pthread_mutex_trylock(&mut mutex as *mut _), 0); - assert_eq!(libc::pthread_mutex_unlock(&mut mutex as *mut _), 0); - assert_eq!(libc::pthread_mutex_destroy(&mut mutex as *mut _), 0); - } +#[cfg(not(target_os = "windows"))] +fn test_rwlock_libc_init() { + unsafe { + let mut mutex: libc::pthread_mutex_t = std::mem::zeroed(); + assert_eq!(libc::pthread_mutex_init(&mut mutex as *mut _, std::ptr::null_mut()), 0); + assert_eq!(libc::pthread_mutex_lock(&mut mutex as *mut _), 0); + assert_eq!(libc::pthread_mutex_trylock(&mut mutex as *mut _), libc::EBUSY); + assert_eq!(libc::pthread_mutex_unlock(&mut mutex as *mut _), 0); + assert_eq!(libc::pthread_mutex_trylock(&mut mutex as *mut _), 0); + assert_eq!(libc::pthread_mutex_unlock(&mut mutex as *mut _), 0); + assert_eq!(libc::pthread_mutex_destroy(&mut mutex as *mut _), 0); + } +} - let rw = std::cell::UnsafeCell::new(libc::PTHREAD_RWLOCK_INITIALIZER); - unsafe { - assert_eq!(libc::pthread_rwlock_rdlock(rw.get()), 0); - assert_eq!(libc::pthread_rwlock_rdlock(rw.get()), 0); - assert_eq!(libc::pthread_rwlock_unlock(rw.get()), 0); - assert_eq!(libc::pthread_rwlock_tryrdlock(rw.get()), 0); - assert_eq!(libc::pthread_rwlock_unlock(rw.get()), 0); - assert_eq!(libc::pthread_rwlock_trywrlock(rw.get()), libc::EBUSY); - assert_eq!(libc::pthread_rwlock_unlock(rw.get()), 0); +#[cfg(not(target_os = "windows"))] +fn test_rwlock_libc_static_initializer() { + let rw = std::cell::UnsafeCell::new(libc::PTHREAD_RWLOCK_INITIALIZER); + unsafe { + assert_eq!(libc::pthread_rwlock_rdlock(rw.get()), 0); + assert_eq!(libc::pthread_rwlock_rdlock(rw.get()), 0); + assert_eq!(libc::pthread_rwlock_unlock(rw.get()), 0); + assert_eq!(libc::pthread_rwlock_tryrdlock(rw.get()), 0); + assert_eq!(libc::pthread_rwlock_unlock(rw.get()), 0); + assert_eq!(libc::pthread_rwlock_trywrlock(rw.get()), libc::EBUSY); + assert_eq!(libc::pthread_rwlock_unlock(rw.get()), 0); - assert_eq!(libc::pthread_rwlock_wrlock(rw.get()), 0); - assert_eq!(libc::pthread_rwlock_tryrdlock(rw.get()), libc::EBUSY); - assert_eq!(libc::pthread_rwlock_trywrlock(rw.get()), libc::EBUSY); - assert_eq!(libc::pthread_rwlock_unlock(rw.get()), 0); + assert_eq!(libc::pthread_rwlock_wrlock(rw.get()), 0); + assert_eq!(libc::pthread_rwlock_tryrdlock(rw.get()), libc::EBUSY); + assert_eq!(libc::pthread_rwlock_trywrlock(rw.get()), libc::EBUSY); + assert_eq!(libc::pthread_rwlock_unlock(rw.get()), 0); - assert_eq!(libc::pthread_rwlock_destroy(rw.get()), 0); - } + assert_eq!(libc::pthread_rwlock_destroy(rw.get()), 0); } } From 765050f302f75a8f4c5de3ab527aec4d4f9f883e Mon Sep 17 00:00:00 2001 From: David Cook Date: Mon, 17 Feb 2020 22:52:44 -0600 Subject: [PATCH 1792/3747] Revise mutex/rwlock memory layout for macOS compat --- src/shims/sync.rs | 54 ++++++++++++++++++++++++----------------------- 1 file changed, 28 insertions(+), 26 deletions(-) diff --git a/src/shims/sync.rs b/src/shims/sync.rs index c9329586627dd..3208727730312 100644 --- a/src/shims/sync.rs +++ b/src/shims/sync.rs @@ -79,7 +79,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // pthread_mutex_t is between 24 and 48 bytes, depending on the platform // memory layout: - // bytes 0-3: count of how many times this mutex has been locked, as a u32 + // bytes 0-3: reserved for signature on macOS + // bytes 4-7: count of how many times this mutex has been locked, as a u32 // bytes 12-15: mutex kind, as an i32 // (the kind should be at this offset for compatibility with the static // initializer macro) @@ -112,7 +113,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx }; let u32_layout = this.layout_of(this.tcx.types.u32)?; - let locked_count_place = mutex_place.offset(Size::ZERO, MemPlaceMeta::None, u32_layout, this)?; + let locked_count_place = mutex_place.offset(Size::from_bytes(4), MemPlaceMeta::None, u32_layout, this)?; this.write_scalar(Scalar::from_u32(0), locked_count_place.into())?; let mutex_kind_place = mutex_place.offset(Size::from_bytes(12), MemPlaceMeta::None, i32_layout, &*this.tcx)?; @@ -137,7 +138,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let kind = this.read_scalar(kind_place.into())?.not_undef()?; let u32_layout = this.layout_of(this.tcx.types.u32)?; - let locked_count_place = mutex_place.offset(Size::ZERO, MemPlaceMeta::None, u32_layout, this)?; + let locked_count_place = mutex_place.offset(Size::from_bytes(4), MemPlaceMeta::None, u32_layout, this)?; let locked_count = this.read_scalar(locked_count_place.into())?.to_u32()?; if kind == this.eval_libc("PTHREAD_MUTEX_NORMAL")? { @@ -178,7 +179,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let kind = this.read_scalar(kind_place.into())?.not_undef()?; let u32_layout = this.layout_of(this.tcx.types.u32)?; - let locked_count_place = mutex_place.offset(Size::ZERO, MemPlaceMeta::None, u32_layout, this)?; + let locked_count_place = mutex_place.offset(Size::from_bytes(4), MemPlaceMeta::None, u32_layout, this)?; let locked_count = this.read_scalar(locked_count_place.into())?.to_u32()?; if kind == this.eval_libc("PTHREAD_MUTEX_NORMAL")? || @@ -213,7 +214,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let kind = this.read_scalar(kind_place.into())?.not_undef()?; let u32_layout = this.layout_of(this.tcx.types.u32)?; - let locked_count_place = mutex_place.offset(Size::ZERO, MemPlaceMeta::None, u32_layout, this)?; + let locked_count_place = mutex_place.offset(Size::from_bytes(4), MemPlaceMeta::None, u32_layout, this)?; let locked_count = this.read_scalar(locked_count_place.into())?.to_u32()?; if kind == this.eval_libc("PTHREAD_MUTEX_NORMAL")? { @@ -254,7 +255,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let mutex_place = this.deref_operand(mutex_op)?; let u32_layout = this.layout_of(this.tcx.types.u32)?; - let locked_count_place = mutex_place.offset(Size::ZERO, MemPlaceMeta::None, u32_layout, this)?; + let locked_count_place = mutex_place.offset(Size::from_bytes(4), MemPlaceMeta::None, u32_layout, this)?; if this.read_scalar(locked_count_place.into())?.to_u32()? != 0 { return this.eval_libc_i32("EBUSY"); } @@ -269,13 +270,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // pthread_rwlock_t is between 32 and 56 bytes, depending on the platform // memory layout: - // bytes 0-3: reader count, as a u32 - // bytes 4-7: writer count, as a u32 + // bytes 0-3: reserved for signature on macOS + // bytes 4-7: reader count, as a u32 + // bytes 8-11: writer count, as a u32 fn pthread_rwlock_rdlock(&mut self, rwlock_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - check_ptr_target_min_size(this, rwlock_op, 8)?; + check_ptr_target_min_size(this, rwlock_op, 12)?; let rwlock = this.read_scalar(rwlock_op)?.not_undef()?; if this.is_null(rwlock)? { @@ -284,8 +286,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let rwlock_place = this.deref_operand(rwlock_op)?; let u32_layout = this.layout_of(this.tcx.types.u32)?; - let readers_place = rwlock_place.offset(Size::ZERO, MemPlaceMeta::None, u32_layout, this)?; - let writers_place = rwlock_place.offset(Size::from_bytes(4), MemPlaceMeta::None, u32_layout, this)?; + let readers_place = rwlock_place.offset(Size::from_bytes(4), MemPlaceMeta::None, u32_layout, this)?; + let writers_place = rwlock_place.offset(Size::from_bytes(8), MemPlaceMeta::None, u32_layout, this)?; let readers = this.read_scalar(readers_place.into())?.to_u32()?; let writers = this.read_scalar(writers_place.into())?.to_u32()?; if writers != 0 { @@ -299,7 +301,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn pthread_rwlock_tryrdlock(&mut self, rwlock_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - check_ptr_target_min_size(this, rwlock_op, 8)?; + check_ptr_target_min_size(this, rwlock_op, 12)?; let rwlock = this.read_scalar(rwlock_op)?.not_undef()?; if this.is_null(rwlock)? { @@ -308,8 +310,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let rwlock_place = this.deref_operand(rwlock_op)?; let u32_layout = this.layout_of(this.tcx.types.u32)?; - let readers_place = rwlock_place.offset(Size::ZERO, MemPlaceMeta::None, u32_layout, this)?; - let writers_place = rwlock_place.offset(Size::from_bytes(4), MemPlaceMeta::None, u32_layout, this)?; + let readers_place = rwlock_place.offset(Size::from_bytes(4), MemPlaceMeta::None, u32_layout, this)?; + let writers_place = rwlock_place.offset(Size::from_bytes(8), MemPlaceMeta::None, u32_layout, this)?; let readers = this.read_scalar(readers_place.into())?.to_u32()?; let writers = this.read_scalar(writers_place.into())?.to_u32()?; if writers != 0 { @@ -323,7 +325,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn pthread_rwlock_wrlock(&mut self, rwlock_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - check_ptr_target_min_size(this, rwlock_op, 8)?; + check_ptr_target_min_size(this, rwlock_op, 12)?; let rwlock = this.read_scalar(rwlock_op)?.not_undef()?; if this.is_null(rwlock)? { @@ -332,8 +334,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let rwlock_place = this.deref_operand(rwlock_op)?; let u32_layout = this.layout_of(this.tcx.types.u32)?; - let readers_place = rwlock_place.offset(Size::ZERO, MemPlaceMeta::None, u32_layout, this)?; - let writers_place = rwlock_place.offset(Size::from_bytes(4), MemPlaceMeta::None, u32_layout, this)?; + let readers_place = rwlock_place.offset(Size::from_bytes(4), MemPlaceMeta::None, u32_layout, this)?; + let writers_place = rwlock_place.offset(Size::from_bytes(8), MemPlaceMeta::None, u32_layout, this)?; let readers = this.read_scalar(readers_place.into())?.to_u32()?; let writers = this.read_scalar(writers_place.into())?.to_u32()?; if readers != 0 { @@ -349,7 +351,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn pthread_rwlock_trywrlock(&mut self, rwlock_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - check_ptr_target_min_size(this, rwlock_op, 8)?; + check_ptr_target_min_size(this, rwlock_op, 12)?; let rwlock = this.read_scalar(rwlock_op)?.not_undef()?; if this.is_null(rwlock)? { @@ -358,8 +360,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let rwlock_place = this.deref_operand(rwlock_op)?; let u32_layout = this.layout_of(this.tcx.types.u32)?; - let readers_place = rwlock_place.offset(Size::ZERO, MemPlaceMeta::None, u32_layout, this)?; - let writers_place = rwlock_place.offset(Size::from_bytes(4), MemPlaceMeta::None, u32_layout, this)?; + let readers_place = rwlock_place.offset(Size::from_bytes(4), MemPlaceMeta::None, u32_layout, this)?; + let writers_place = rwlock_place.offset(Size::from_bytes(8), MemPlaceMeta::None, u32_layout, this)?; let readers = this.read_scalar(readers_place.into())?.to_u32()?; let writers = this.read_scalar(writers_place.into())?.to_u32()?; if readers != 0 || writers != 0 { @@ -373,7 +375,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn pthread_rwlock_unlock(&mut self, rwlock_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - check_ptr_target_min_size(this, rwlock_op, 8)?; + check_ptr_target_min_size(this, rwlock_op, 12)?; let rwlock = this.read_scalar(rwlock_op)?.not_undef()?; if this.is_null(rwlock)? { @@ -382,8 +384,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let rwlock_place = this.deref_operand(rwlock_op)?; let u32_layout = this.layout_of(this.tcx.types.u32)?; - let readers_place = rwlock_place.offset(Size::ZERO, MemPlaceMeta::None, u32_layout, this)?; - let writers_place = rwlock_place.offset(Size::from_bytes(4), MemPlaceMeta::None, u32_layout, this)?; + let readers_place = rwlock_place.offset(Size::from_bytes(4), MemPlaceMeta::None, u32_layout, this)?; + let writers_place = rwlock_place.offset(Size::from_bytes(8), MemPlaceMeta::None, u32_layout, this)?; let readers = this.read_scalar(readers_place.into())?.to_u32()?; let writers = this.read_scalar(writers_place.into())?.to_u32()?; if readers != 0 { @@ -400,7 +402,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn pthread_rwlock_destroy(&mut self, rwlock_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - check_ptr_target_min_size(this, rwlock_op, 8)?; + check_ptr_target_min_size(this, rwlock_op, 12)?; let rwlock = this.read_scalar(rwlock_op)?.not_undef()?; if this.is_null(rwlock)? { @@ -409,11 +411,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let rwlock_place = this.deref_operand(rwlock_op)?; let u32_layout = this.layout_of(this.tcx.types.u32)?; - let readers_place = rwlock_place.offset(Size::ZERO, MemPlaceMeta::None, u32_layout, this)?; + let readers_place = rwlock_place.offset(Size::from_bytes(4), MemPlaceMeta::None, u32_layout, this)?; if this.read_scalar(readers_place.into())?.to_u32()? != 0 { return this.eval_libc_i32("EBUSY"); } - let writers_place = rwlock_place.offset(Size::from_bytes(4), MemPlaceMeta::None, u32_layout, this)?; + let writers_place = rwlock_place.offset(Size::from_bytes(8), MemPlaceMeta::None, u32_layout, this)?; if this.read_scalar(writers_place.into())?.to_u32()? != 0 { return this.eval_libc_i32("EBUSY"); } From dca83d73cbfe847738cbd310a4da786979768dd0 Mon Sep 17 00:00:00 2001 From: David Cook Date: Thu, 20 Feb 2020 22:19:51 -0600 Subject: [PATCH 1793/3747] Add test that exercises ReentrantMutex --- tests/run-pass/reentrant-println.rs | 17 +++++++++++++++++ tests/run-pass/reentrant-println.stdout | 2 ++ 2 files changed, 19 insertions(+) create mode 100644 tests/run-pass/reentrant-println.rs create mode 100644 tests/run-pass/reentrant-println.stdout diff --git a/tests/run-pass/reentrant-println.rs b/tests/run-pass/reentrant-println.rs new file mode 100644 index 0000000000000..3703d21e0421e --- /dev/null +++ b/tests/run-pass/reentrant-println.rs @@ -0,0 +1,17 @@ +use std::fmt::{Display, Error, Formatter}; + +// This test case exercises std::sys_common::remutex::ReentrantMutex +// by calling println!() from inside fmt + +struct InterruptingCow(); + +impl Display for InterruptingCow { + fn fmt(&self, _f: &mut Formatter<'_>) -> Result<(), Error> { + println!("Moo"); + Ok(()) + } +} + +fn main() { + println!("\"Knock knock\" \"Who's {} there?\"", InterruptingCow()); +} diff --git a/tests/run-pass/reentrant-println.stdout b/tests/run-pass/reentrant-println.stdout new file mode 100644 index 0000000000000..8a57d32f84ca6 --- /dev/null +++ b/tests/run-pass/reentrant-println.stdout @@ -0,0 +1,2 @@ +"Knock knock" "Who's Moo + there?" From c773ca8614772115788fb59a8cdab49efd09e477 Mon Sep 17 00:00:00 2001 From: David Cook Date: Fri, 21 Feb 2020 19:05:24 -0600 Subject: [PATCH 1794/3747] Style fixes --- tests/run-pass/reentrant-println.rs | 4 ++-- tests/run-pass/sync.rs | 2 -- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/tests/run-pass/reentrant-println.rs b/tests/run-pass/reentrant-println.rs index 3703d21e0421e..09c4fc3f74d3e 100644 --- a/tests/run-pass/reentrant-println.rs +++ b/tests/run-pass/reentrant-println.rs @@ -3,7 +3,7 @@ use std::fmt::{Display, Error, Formatter}; // This test case exercises std::sys_common::remutex::ReentrantMutex // by calling println!() from inside fmt -struct InterruptingCow(); +struct InterruptingCow; impl Display for InterruptingCow { fn fmt(&self, _f: &mut Formatter<'_>) -> Result<(), Error> { @@ -13,5 +13,5 @@ impl Display for InterruptingCow { } fn main() { - println!("\"Knock knock\" \"Who's {} there?\"", InterruptingCow()); + println!("\"Knock knock\" \"Who's {} there?\"", InterruptingCow); } diff --git a/tests/run-pass/sync.rs b/tests/run-pass/sync.rs index d6ce939c6c36c..46cad3c162016 100644 --- a/tests/run-pass/sync.rs +++ b/tests/run-pass/sync.rs @@ -1,5 +1,3 @@ -// Requires full MIR on Windows. - #![feature(rustc_private)] use std::sync::{Mutex, RwLock, TryLockError}; From 5cc091bc6e307c4e46f94aac6cf54d0e0e2ce70a Mon Sep 17 00:00:00 2001 From: David Cook Date: Fri, 21 Feb 2020 19:10:20 -0600 Subject: [PATCH 1795/3747] Add test of recursive mutex using libc FFI --- tests/run-pass/sync.rs | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/tests/run-pass/sync.rs b/tests/run-pass/sync.rs index 46cad3c162016..b247061083798 100644 --- a/tests/run-pass/sync.rs +++ b/tests/run-pass/sync.rs @@ -8,6 +8,7 @@ fn main() { test_mutex(); #[cfg(not(target_os = "windows"))] // TODO: implement RwLock on Windows { + test_mutex_libc_recursive(); test_rwlock_stdlib(); test_rwlock_libc_init(); test_rwlock_libc_static_initializer(); @@ -24,6 +25,28 @@ fn test_mutex() { drop(m); } +#[cfg(not(target_os = "windows"))] +fn test_mutex_libc_recursive() { + unsafe { + let mut attr: libc::pthread_mutexattr_t = std::mem::zeroed(); + assert_eq!(libc::pthread_mutexattr_init(&mut attr as *mut _), 0); + assert_eq!(libc::pthread_mutexattr_settype(&mut attr as *mut _, libc::PTHREAD_MUTEX_RECURSIVE), 0); + let mut mutex: libc::pthread_mutex_t = std::mem::zeroed(); + assert_eq!(libc::pthread_mutex_init(&mut mutex as *mut _, &mut attr as *mut _), 0); + assert_eq!(libc::pthread_mutex_lock(&mut mutex as *mut _), 0); + assert_eq!(libc::pthread_mutex_trylock(&mut mutex as *mut _), 0); + assert_eq!(libc::pthread_mutex_unlock(&mut mutex as *mut _), 0); + assert_eq!(libc::pthread_mutex_unlock(&mut mutex as *mut _), 0); + assert_eq!(libc::pthread_mutex_trylock(&mut mutex as *mut _), 0); + assert_eq!(libc::pthread_mutex_lock(&mut mutex as *mut _), 0); + assert_eq!(libc::pthread_mutex_unlock(&mut mutex as *mut _), 0); + assert_eq!(libc::pthread_mutex_unlock(&mut mutex as *mut _), 0); + assert_eq!(libc::pthread_mutex_unlock(&mut mutex as *mut _), libc::EPERM); + assert_eq!(libc::pthread_mutex_destroy(&mut mutex as *mut _), 0); + assert_eq!(libc::pthread_mutexattr_destroy(&mut attr as *mut _), 0); + } +} + #[cfg(not(target_os = "windows"))] fn test_rwlock_stdlib() { let rw = RwLock::new(0); From d11315ebfb4c2d95a1ca6c52bec105237b10e933 Mon Sep 17 00:00:00 2001 From: David Cook Date: Sun, 15 Mar 2020 15:10:08 -0500 Subject: [PATCH 1796/3747] Fix misleading function names --- src/shims/sync.rs | 32 ++++++++++++++++---------------- tests/run-pass/sync.rs | 4 ++-- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/src/shims/sync.rs b/src/shims/sync.rs index 3208727730312..22e62beae2f22 100644 --- a/src/shims/sync.rs +++ b/src/shims/sync.rs @@ -13,7 +13,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn pthread_mutexattr_init(&mut self, attr_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - check_ptr_target_min_size(this, attr_op, 4)?; + assert_ptr_target_min_size(this, attr_op, 4)?; let attr = this.read_scalar(attr_op)?.not_undef()?; if this.is_null(attr)? { @@ -36,7 +36,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - check_ptr_target_min_size(this, attr_op, 4)?; + assert_ptr_target_min_size(this, attr_op, 4)?; let attr = this.read_scalar(attr_op)?.not_undef()?; if this.is_null(attr)? { @@ -62,7 +62,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn pthread_mutexattr_destroy(&mut self, attr_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - check_ptr_target_min_size(this, attr_op, 4)?; + assert_ptr_target_min_size(this, attr_op, 4)?; let attr = this.read_scalar(attr_op)?.not_undef()?; if this.is_null(attr)? { @@ -92,8 +92,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - check_ptr_target_min_size(this, mutex_op, 16)?; - check_ptr_target_min_size(this, attr_op, 4)?; + assert_ptr_target_min_size(this, mutex_op, 16)?; + assert_ptr_target_min_size(this, attr_op, 4)?; let mutex = this.read_scalar(mutex_op)?.not_undef()?; if this.is_null(mutex)? { @@ -125,7 +125,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn pthread_mutex_lock(&mut self, mutex_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - check_ptr_target_min_size(this, mutex_op, 16)?; + assert_ptr_target_min_size(this, mutex_op, 16)?; let mutex = this.read_scalar(mutex_op)?.not_undef()?; if this.is_null(mutex)? { @@ -166,7 +166,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn pthread_mutex_trylock(&mut self, mutex_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - check_ptr_target_min_size(this, mutex_op, 16)?; + assert_ptr_target_min_size(this, mutex_op, 16)?; let mutex = this.read_scalar(mutex_op)?.not_undef()?; if this.is_null(mutex)? { @@ -201,7 +201,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn pthread_mutex_unlock(&mut self, mutex_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - check_ptr_target_min_size(this, mutex_op, 16)?; + assert_ptr_target_min_size(this, mutex_op, 16)?; let mutex = this.read_scalar(mutex_op)?.not_undef()?; if this.is_null(mutex)? { @@ -246,7 +246,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn pthread_mutex_destroy(&mut self, mutex_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - check_ptr_target_min_size(this, mutex_op, 16)?; + assert_ptr_target_min_size(this, mutex_op, 16)?; let mutex = this.read_scalar(mutex_op)?.not_undef()?; if this.is_null(mutex)? { @@ -277,7 +277,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn pthread_rwlock_rdlock(&mut self, rwlock_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - check_ptr_target_min_size(this, rwlock_op, 12)?; + assert_ptr_target_min_size(this, rwlock_op, 12)?; let rwlock = this.read_scalar(rwlock_op)?.not_undef()?; if this.is_null(rwlock)? { @@ -301,7 +301,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn pthread_rwlock_tryrdlock(&mut self, rwlock_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - check_ptr_target_min_size(this, rwlock_op, 12)?; + assert_ptr_target_min_size(this, rwlock_op, 12)?; let rwlock = this.read_scalar(rwlock_op)?.not_undef()?; if this.is_null(rwlock)? { @@ -325,7 +325,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn pthread_rwlock_wrlock(&mut self, rwlock_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - check_ptr_target_min_size(this, rwlock_op, 12)?; + assert_ptr_target_min_size(this, rwlock_op, 12)?; let rwlock = this.read_scalar(rwlock_op)?.not_undef()?; if this.is_null(rwlock)? { @@ -351,7 +351,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn pthread_rwlock_trywrlock(&mut self, rwlock_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - check_ptr_target_min_size(this, rwlock_op, 12)?; + assert_ptr_target_min_size(this, rwlock_op, 12)?; let rwlock = this.read_scalar(rwlock_op)?.not_undef()?; if this.is_null(rwlock)? { @@ -375,7 +375,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn pthread_rwlock_unlock(&mut self, rwlock_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - check_ptr_target_min_size(this, rwlock_op, 12)?; + assert_ptr_target_min_size(this, rwlock_op, 12)?; let rwlock = this.read_scalar(rwlock_op)?.not_undef()?; if this.is_null(rwlock)? { @@ -402,7 +402,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn pthread_rwlock_destroy(&mut self, rwlock_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - check_ptr_target_min_size(this, rwlock_op, 12)?; + assert_ptr_target_min_size(this, rwlock_op, 12)?; let rwlock = this.read_scalar(rwlock_op)?.not_undef()?; if this.is_null(rwlock)? { @@ -427,7 +427,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } -fn check_ptr_target_min_size<'mir, 'tcx: 'mir>(ecx: &MiriEvalContext<'mir, 'tcx>, operand: OpTy<'tcx, Tag>, min_size: u64) -> InterpResult<'tcx, ()> { +fn assert_ptr_target_min_size<'mir, 'tcx: 'mir>(ecx: &MiriEvalContext<'mir, 'tcx>, operand: OpTy<'tcx, Tag>, min_size: u64) -> InterpResult<'tcx, ()> { let target_ty = match operand.layout.ty.kind { TyKind::RawPtr(TypeAndMut{ ty, mutbl: _ }) => ty, _ => panic!("Argument to pthread function was not a raw pointer"), diff --git a/tests/run-pass/sync.rs b/tests/run-pass/sync.rs index b247061083798..c1e44789aa74e 100644 --- a/tests/run-pass/sync.rs +++ b/tests/run-pass/sync.rs @@ -10,7 +10,7 @@ fn main() { { test_mutex_libc_recursive(); test_rwlock_stdlib(); - test_rwlock_libc_init(); + test_mutex_libc_init(); test_rwlock_libc_static_initializer(); } } @@ -68,7 +68,7 @@ fn test_rwlock_stdlib() { // std::sys::unix::rwlock::RWLock keeps track of write_locked and num_readers #[cfg(not(target_os = "windows"))] -fn test_rwlock_libc_init() { +fn test_mutex_libc_init() { unsafe { let mut mutex: libc::pthread_mutex_t = std::mem::zeroed(); assert_eq!(libc::pthread_mutex_init(&mut mutex as *mut _, std::ptr::null_mut()), 0); From fd94255b9d4ab69b110bb5d2acef5c288fe4a0e1 Mon Sep 17 00:00:00 2001 From: David Cook Date: Tue, 17 Mar 2020 08:19:57 -0500 Subject: [PATCH 1797/3747] Add comments explaining asserts --- src/shims/sync.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/shims/sync.rs b/src/shims/sync.rs index 22e62beae2f22..61346bfd85baa 100644 --- a/src/shims/sync.rs +++ b/src/shims/sync.rs @@ -13,6 +13,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn pthread_mutexattr_init(&mut self, attr_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); + // Ensure that the following write at an offset to the attr pointer is within bounds assert_ptr_target_min_size(this, attr_op, 4)?; let attr = this.read_scalar(attr_op)?.not_undef()?; @@ -36,6 +37,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); + // Ensure that the following write at an offset to the attr pointer is within bounds assert_ptr_target_min_size(this, attr_op, 4)?; let attr = this.read_scalar(attr_op)?.not_undef()?; @@ -62,6 +64,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn pthread_mutexattr_destroy(&mut self, attr_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); + // Ensure that the following write at an offset to the attr pointer is within bounds assert_ptr_target_min_size(this, attr_op, 4)?; let attr = this.read_scalar(attr_op)?.not_undef()?; @@ -92,7 +95,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); + // Ensure that the following writes at offsets to the mutex pointer are within bounds assert_ptr_target_min_size(this, mutex_op, 16)?; + // Ensure that the following read at an offset to the attr pointer is within bounds assert_ptr_target_min_size(this, attr_op, 4)?; let mutex = this.read_scalar(mutex_op)?.not_undef()?; @@ -125,6 +130,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn pthread_mutex_lock(&mut self, mutex_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); + // Ensure that the following reads and writes at offsets to the mutex pointer are within bounds assert_ptr_target_min_size(this, mutex_op, 16)?; let mutex = this.read_scalar(mutex_op)?.not_undef()?; @@ -166,6 +172,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn pthread_mutex_trylock(&mut self, mutex_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); + // Ensure that the following reads and writes at offsets to the mutex pointer are within bounds assert_ptr_target_min_size(this, mutex_op, 16)?; let mutex = this.read_scalar(mutex_op)?.not_undef()?; @@ -201,6 +208,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn pthread_mutex_unlock(&mut self, mutex_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); + // Ensure that the following reads and writes at offsets to the mutex pointer are within bounds assert_ptr_target_min_size(this, mutex_op, 16)?; let mutex = this.read_scalar(mutex_op)?.not_undef()?; @@ -246,6 +254,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn pthread_mutex_destroy(&mut self, mutex_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); + // Ensure that the following read and writes at offsets to the mutex pointer are within bounds assert_ptr_target_min_size(this, mutex_op, 16)?; let mutex = this.read_scalar(mutex_op)?.not_undef()?; @@ -277,6 +286,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn pthread_rwlock_rdlock(&mut self, rwlock_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); + // Ensure that the following reads and write at offsets to the rwlock pointer are within bounds assert_ptr_target_min_size(this, rwlock_op, 12)?; let rwlock = this.read_scalar(rwlock_op)?.not_undef()?; @@ -301,6 +311,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn pthread_rwlock_tryrdlock(&mut self, rwlock_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); + // Ensure that the following reads and write at offsets to the rwlock pointer are within bounds assert_ptr_target_min_size(this, rwlock_op, 12)?; let rwlock = this.read_scalar(rwlock_op)?.not_undef()?; @@ -325,6 +336,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn pthread_rwlock_wrlock(&mut self, rwlock_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); + // Ensure that the following reads and write at offsets to the rwlock pointer are within bounds assert_ptr_target_min_size(this, rwlock_op, 12)?; let rwlock = this.read_scalar(rwlock_op)?.not_undef()?; @@ -351,6 +363,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn pthread_rwlock_trywrlock(&mut self, rwlock_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); + // Ensure that the following reads and write at offsets to the rwlock pointer are within bounds assert_ptr_target_min_size(this, rwlock_op, 12)?; let rwlock = this.read_scalar(rwlock_op)?.not_undef()?; @@ -375,6 +388,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn pthread_rwlock_unlock(&mut self, rwlock_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); + // Ensure that the following reads and writes at offsets to the rwlock pointer are within bounds assert_ptr_target_min_size(this, rwlock_op, 12)?; let rwlock = this.read_scalar(rwlock_op)?.not_undef()?; @@ -402,6 +416,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn pthread_rwlock_destroy(&mut self, rwlock_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); + // Ensure that the following reads and writes at offsets to the rwlock pointer are within bounds assert_ptr_target_min_size(this, rwlock_op, 12)?; let rwlock = this.read_scalar(rwlock_op)?.not_undef()?; From 141319a412ddca4a2b16f45eed459c4a735e8f8f Mon Sep 17 00:00:00 2001 From: David Cook Date: Sun, 22 Mar 2020 15:18:02 -0500 Subject: [PATCH 1798/3747] Refactor sync shims with setters and getters --- src/shims/sync.rs | 400 +++++++++++++++++++++++++--------------------- 1 file changed, 219 insertions(+), 181 deletions(-) diff --git a/src/shims/sync.rs b/src/shims/sync.rs index 61346bfd85baa..b8d9a88865e67 100644 --- a/src/shims/sync.rs +++ b/src/shims/sync.rs @@ -6,26 +6,16 @@ use crate::*; impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { - // pthread_mutexattr_t is either 4 or 8 bytes, depending on the platform - // memory layout: store an i32 in the first four bytes equal to the - // corresponding libc mutex kind constant (i.e. PTHREAD_MUTEX_NORMAL) - fn pthread_mutexattr_init(&mut self, attr_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - // Ensure that the following write at an offset to the attr pointer is within bounds - assert_ptr_target_min_size(this, attr_op, 4)?; - let attr = this.read_scalar(attr_op)?.not_undef()?; if this.is_null(attr)? { return this.eval_libc_i32("EINVAL"); } - let attr_place = this.deref_operand(attr_op)?; - let i32_layout = this.layout_of(this.tcx.types.i32)?; - let kind_place = attr_place.offset(Size::ZERO, MemPlaceMeta::None, i32_layout, this)?; let default_kind = this.eval_libc("PTHREAD_MUTEX_DEFAULT")?; - this.write_scalar(default_kind, kind_place.into())?; + mutexattr_set_kind(this, attr_op, default_kind)?; Ok(0) } @@ -37,22 +27,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - // Ensure that the following write at an offset to the attr pointer is within bounds - assert_ptr_target_min_size(this, attr_op, 4)?; - let attr = this.read_scalar(attr_op)?.not_undef()?; if this.is_null(attr)? { return this.eval_libc_i32("EINVAL"); } let kind = this.read_scalar(kind_op)?.not_undef()?; - if kind == this.eval_libc("PTHREAD_MUTEX_NORMAL")? || - kind == this.eval_libc("PTHREAD_MUTEX_ERRORCHECK")? || - kind == this.eval_libc("PTHREAD_MUTEX_RECURSIVE")? { - let attr_place = this.deref_operand(attr_op)?; - let i32_layout = this.layout_of(this.tcx.types.i32)?; - let kind_place = attr_place.offset(Size::ZERO, MemPlaceMeta::None, i32_layout, this)?; - this.write_scalar(kind, kind_place.into())?; + if kind == this.eval_libc("PTHREAD_MUTEX_NORMAL")? + || kind == this.eval_libc("PTHREAD_MUTEX_ERRORCHECK")? + || kind == this.eval_libc("PTHREAD_MUTEX_RECURSIVE")? + { + mutexattr_set_kind(this, attr_op, kind)?; } else { let einval = this.eval_libc_i32("EINVAL")?; return Ok(einval); @@ -64,30 +49,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn pthread_mutexattr_destroy(&mut self, attr_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - // Ensure that the following write at an offset to the attr pointer is within bounds - assert_ptr_target_min_size(this, attr_op, 4)?; - let attr = this.read_scalar(attr_op)?.not_undef()?; if this.is_null(attr)? { return this.eval_libc_i32("EINVAL"); } - let attr_place = this.deref_operand(attr_op)?; - let i32_layout = this.layout_of(this.tcx.types.i32)?; - let kind_place = attr_place.offset(Size::ZERO, MemPlaceMeta::None, i32_layout, this)?; - this.write_scalar(ScalarMaybeUndef::Undef, kind_place.into())?; + mutexattr_set_kind(this, attr_op, ScalarMaybeUndef::Undef)?; Ok(0) } - // pthread_mutex_t is between 24 and 48 bytes, depending on the platform - // memory layout: - // bytes 0-3: reserved for signature on macOS - // bytes 4-7: count of how many times this mutex has been locked, as a u32 - // bytes 12-15: mutex kind, as an i32 - // (the kind should be at this offset for compatibility with the static - // initializer macro) - fn pthread_mutex_init( &mut self, mutex_op: OpTy<'tcx, Tag>, @@ -95,34 +66,20 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - // Ensure that the following writes at offsets to the mutex pointer are within bounds - assert_ptr_target_min_size(this, mutex_op, 16)?; - // Ensure that the following read at an offset to the attr pointer is within bounds - assert_ptr_target_min_size(this, attr_op, 4)?; - let mutex = this.read_scalar(mutex_op)?.not_undef()?; if this.is_null(mutex)? { return this.eval_libc_i32("EINVAL"); } - let mutex_place = this.deref_operand(mutex_op)?; - - let i32_layout = this.layout_of(this.tcx.types.i32)?; let attr = this.read_scalar(attr_op)?.not_undef()?; let kind = if this.is_null(attr)? { this.eval_libc("PTHREAD_MUTEX_DEFAULT")? } else { - let attr_place = this.deref_operand(attr_op)?; - let attr_kind_place = attr_place.offset(Size::ZERO, MemPlaceMeta::None, i32_layout, this)?; - this.read_scalar(attr_kind_place.into())?.not_undef()? + mutexattr_get_kind(this, attr_op)?.not_undef()? }; - let u32_layout = this.layout_of(this.tcx.types.u32)?; - let locked_count_place = mutex_place.offset(Size::from_bytes(4), MemPlaceMeta::None, u32_layout, this)?; - this.write_scalar(Scalar::from_u32(0), locked_count_place.into())?; - - let mutex_kind_place = mutex_place.offset(Size::from_bytes(12), MemPlaceMeta::None, i32_layout, &*this.tcx)?; - this.write_scalar(kind, mutex_kind_place.into())?; + mutex_set_locked_count(this, mutex_op, Scalar::from_u32(0))?; + mutex_set_kind(this, mutex_op, kind)?; Ok(0) } @@ -130,39 +87,30 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn pthread_mutex_lock(&mut self, mutex_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - // Ensure that the following reads and writes at offsets to the mutex pointer are within bounds - assert_ptr_target_min_size(this, mutex_op, 16)?; - let mutex = this.read_scalar(mutex_op)?.not_undef()?; if this.is_null(mutex)? { return this.eval_libc_i32("EINVAL"); } - let mutex_place = this.deref_operand(mutex_op)?; - let i32_layout = this.layout_of(this.tcx.types.i32)?; - let kind_place = mutex_place.offset(Size::from_bytes(12), MemPlaceMeta::None, i32_layout, this)?; - let kind = this.read_scalar(kind_place.into())?.not_undef()?; - - let u32_layout = this.layout_of(this.tcx.types.u32)?; - let locked_count_place = mutex_place.offset(Size::from_bytes(4), MemPlaceMeta::None, u32_layout, this)?; - let locked_count = this.read_scalar(locked_count_place.into())?.to_u32()?; + let kind = mutex_get_kind(this, mutex_op)?.not_undef()?; + let locked_count = mutex_get_locked_count(this, mutex_op)?.to_u32()?; if kind == this.eval_libc("PTHREAD_MUTEX_NORMAL")? { if locked_count == 0 { - this.write_scalar(Scalar::from_u32(1), locked_count_place.into())?; + mutex_set_locked_count(this, mutex_op, Scalar::from_u32(1))?; Ok(0) } else { throw_unsup_format!("Deadlock due to locking a PTHREAD_MUTEX_NORMAL mutex twice"); } } else if kind == this.eval_libc("PTHREAD_MUTEX_ERRORCHECK")? { if locked_count == 0 { - this.write_scalar(Scalar::from_u32(1), locked_count_place.into())?; + mutex_set_locked_count(this, mutex_op, Scalar::from_u32(1))?; Ok(0) } else { this.eval_libc_i32("EDEADLK") } } else if kind == this.eval_libc("PTHREAD_MUTEX_RECURSIVE")? { - this.write_scalar(Scalar::from_u32(locked_count + 1), locked_count_place.into())?; + mutex_set_locked_count(this, mutex_op, Scalar::from_u32(locked_count + 1))?; Ok(0) } else { this.eval_libc_i32("EINVAL") @@ -172,33 +120,25 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn pthread_mutex_trylock(&mut self, mutex_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - // Ensure that the following reads and writes at offsets to the mutex pointer are within bounds - assert_ptr_target_min_size(this, mutex_op, 16)?; - let mutex = this.read_scalar(mutex_op)?.not_undef()?; if this.is_null(mutex)? { return this.eval_libc_i32("EINVAL"); } - let mutex_place = this.deref_operand(mutex_op)?; - let i32_layout = this.layout_of(this.tcx.types.i32)?; - let kind_place = mutex_place.offset(Size::from_bytes(12), MemPlaceMeta::None, i32_layout, this)?; - let kind = this.read_scalar(kind_place.into())?.not_undef()?; + let kind = mutex_get_kind(this, mutex_op)?.not_undef()?; + let locked_count = mutex_get_locked_count(this, mutex_op)?.to_u32()?; - let u32_layout = this.layout_of(this.tcx.types.u32)?; - let locked_count_place = mutex_place.offset(Size::from_bytes(4), MemPlaceMeta::None, u32_layout, this)?; - let locked_count = this.read_scalar(locked_count_place.into())?.to_u32()?; - - if kind == this.eval_libc("PTHREAD_MUTEX_NORMAL")? || - kind == this.eval_libc("PTHREAD_MUTEX_ERRORCHECK")? { + if kind == this.eval_libc("PTHREAD_MUTEX_NORMAL")? + || kind == this.eval_libc("PTHREAD_MUTEX_ERRORCHECK")? + { if locked_count == 0 { - this.write_scalar(Scalar::from_u32(1), locked_count_place.into())?; + mutex_set_locked_count(this, mutex_op, Scalar::from_u32(1))?; Ok(0) } else { this.eval_libc_i32("EBUSY") } } else if kind == this.eval_libc("PTHREAD_MUTEX_RECURSIVE")? { - this.write_scalar(Scalar::from_u32(locked_count + 1), locked_count_place.into())?; + mutex_set_locked_count(this, mutex_op, Scalar::from_u32(locked_count + 1))?; Ok(0) } else { this.eval_libc_i32("EINVAL") @@ -208,40 +148,33 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn pthread_mutex_unlock(&mut self, mutex_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - // Ensure that the following reads and writes at offsets to the mutex pointer are within bounds - assert_ptr_target_min_size(this, mutex_op, 16)?; - let mutex = this.read_scalar(mutex_op)?.not_undef()?; if this.is_null(mutex)? { return this.eval_libc_i32("EINVAL"); } - let mutex_place = this.deref_operand(mutex_op)?; - - let i32_layout = this.layout_of(this.tcx.types.i32)?; - let kind_place = mutex_place.offset(Size::from_bytes(12), MemPlaceMeta::None, i32_layout, this)?; - let kind = this.read_scalar(kind_place.into())?.not_undef()?; - let u32_layout = this.layout_of(this.tcx.types.u32)?; - let locked_count_place = mutex_place.offset(Size::from_bytes(4), MemPlaceMeta::None, u32_layout, this)?; - let locked_count = this.read_scalar(locked_count_place.into())?.to_u32()?; + let kind = mutex_get_kind(this, mutex_op)?.not_undef()?; + let locked_count = mutex_get_locked_count(this, mutex_op)?.to_u32()?; if kind == this.eval_libc("PTHREAD_MUTEX_NORMAL")? { if locked_count == 1 { - this.write_scalar(Scalar::from_u32(0), locked_count_place.into())?; + mutex_set_locked_count(this, mutex_op, Scalar::from_u32(0))?; Ok(0) } else { - throw_ub_format!("Attempted to unlock a PTHREAD_MUTEX_NORMAL mutex that was not locked"); + throw_ub_format!( + "Attempted to unlock a PTHREAD_MUTEX_NORMAL mutex that was not locked" + ); } } else if kind == this.eval_libc("PTHREAD_MUTEX_ERRORCHECK")? { if locked_count == 1 { - this.write_scalar(Scalar::from_u32(0), locked_count_place.into())?; + mutex_set_locked_count(this, mutex_op, Scalar::from_u32(0))?; Ok(0) } else { this.eval_libc_i32("EPERM") } } else if kind == this.eval_libc("PTHREAD_MUTEX_RECURSIVE")? { if locked_count > 0 { - this.write_scalar(Scalar::from_u32(locked_count - 1), locked_count_place.into())?; + mutex_set_locked_count(this, mutex_op, Scalar::from_u32(locked_count - 1))?; Ok(0) } else { this.eval_libc_i32("EPERM") @@ -254,56 +187,37 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn pthread_mutex_destroy(&mut self, mutex_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - // Ensure that the following read and writes at offsets to the mutex pointer are within bounds - assert_ptr_target_min_size(this, mutex_op, 16)?; - let mutex = this.read_scalar(mutex_op)?.not_undef()?; if this.is_null(mutex)? { return this.eval_libc_i32("EINVAL"); } - let mutex_place = this.deref_operand(mutex_op)?; - let u32_layout = this.layout_of(this.tcx.types.u32)?; - let locked_count_place = mutex_place.offset(Size::from_bytes(4), MemPlaceMeta::None, u32_layout, this)?; - if this.read_scalar(locked_count_place.into())?.to_u32()? != 0 { + if mutex_get_locked_count(this, mutex_op)?.to_u32()? != 0 { return this.eval_libc_i32("EBUSY"); } - let i32_layout = this.layout_of(this.tcx.types.i32)?; - let kind_place = mutex_place.offset(Size::from_bytes(12), MemPlaceMeta::None, i32_layout, this)?; - this.write_scalar(ScalarMaybeUndef::Undef, kind_place.into())?; - this.write_scalar(ScalarMaybeUndef::Undef, locked_count_place.into())?; + mutex_set_kind(this, mutex_op, ScalarMaybeUndef::Undef)?; + mutex_set_locked_count(this, mutex_op, ScalarMaybeUndef::Undef)?; Ok(0) } - // pthread_rwlock_t is between 32 and 56 bytes, depending on the platform - // memory layout: - // bytes 0-3: reserved for signature on macOS - // bytes 4-7: reader count, as a u32 - // bytes 8-11: writer count, as a u32 - fn pthread_rwlock_rdlock(&mut self, rwlock_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - // Ensure that the following reads and write at offsets to the rwlock pointer are within bounds - assert_ptr_target_min_size(this, rwlock_op, 12)?; - let rwlock = this.read_scalar(rwlock_op)?.not_undef()?; if this.is_null(rwlock)? { return this.eval_libc_i32("EINVAL"); } - let rwlock_place = this.deref_operand(rwlock_op)?; - let u32_layout = this.layout_of(this.tcx.types.u32)?; - let readers_place = rwlock_place.offset(Size::from_bytes(4), MemPlaceMeta::None, u32_layout, this)?; - let writers_place = rwlock_place.offset(Size::from_bytes(8), MemPlaceMeta::None, u32_layout, this)?; - let readers = this.read_scalar(readers_place.into())?.to_u32()?; - let writers = this.read_scalar(writers_place.into())?.to_u32()?; + let readers = rwlock_get_readers(this, rwlock_op)?.to_u32()?; + let writers = rwlock_get_writers(this, rwlock_op)?.to_u32()?; if writers != 0 { - throw_unsup_format!("Deadlock due to read-locking a pthreads read-write lock while it is already write-locked"); + throw_unsup_format!( + "Deadlock due to read-locking a pthreads read-write lock while it is already write-locked" + ); } else { - this.write_scalar(Scalar::from_u32(readers + 1), readers_place.into())?; + rwlock_set_readers(this, rwlock_op, Scalar::from_u32(readers + 1))?; Ok(0) } } @@ -311,24 +225,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn pthread_rwlock_tryrdlock(&mut self, rwlock_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - // Ensure that the following reads and write at offsets to the rwlock pointer are within bounds - assert_ptr_target_min_size(this, rwlock_op, 12)?; - let rwlock = this.read_scalar(rwlock_op)?.not_undef()?; if this.is_null(rwlock)? { return this.eval_libc_i32("EINVAL"); } - let rwlock_place = this.deref_operand(rwlock_op)?; - let u32_layout = this.layout_of(this.tcx.types.u32)?; - let readers_place = rwlock_place.offset(Size::from_bytes(4), MemPlaceMeta::None, u32_layout, this)?; - let writers_place = rwlock_place.offset(Size::from_bytes(8), MemPlaceMeta::None, u32_layout, this)?; - let readers = this.read_scalar(readers_place.into())?.to_u32()?; - let writers = this.read_scalar(writers_place.into())?.to_u32()?; + let readers = rwlock_get_readers(this, rwlock_op)?.to_u32()?; + let writers = rwlock_get_writers(this, rwlock_op)?.to_u32()?; if writers != 0 { this.eval_libc_i32("EBUSY") } else { - this.write_scalar(Scalar::from_u32(readers + 1), readers_place.into())?; + rwlock_set_readers(this, rwlock_op, Scalar::from_u32(readers + 1))?; Ok(0) } } @@ -336,26 +243,23 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn pthread_rwlock_wrlock(&mut self, rwlock_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - // Ensure that the following reads and write at offsets to the rwlock pointer are within bounds - assert_ptr_target_min_size(this, rwlock_op, 12)?; - let rwlock = this.read_scalar(rwlock_op)?.not_undef()?; if this.is_null(rwlock)? { return this.eval_libc_i32("EINVAL"); } - let rwlock_place = this.deref_operand(rwlock_op)?; - let u32_layout = this.layout_of(this.tcx.types.u32)?; - let readers_place = rwlock_place.offset(Size::from_bytes(4), MemPlaceMeta::None, u32_layout, this)?; - let writers_place = rwlock_place.offset(Size::from_bytes(8), MemPlaceMeta::None, u32_layout, this)?; - let readers = this.read_scalar(readers_place.into())?.to_u32()?; - let writers = this.read_scalar(writers_place.into())?.to_u32()?; + let readers = rwlock_get_readers(this, rwlock_op)?.to_u32()?; + let writers = rwlock_get_writers(this, rwlock_op)?.to_u32()?; if readers != 0 { - throw_unsup_format!("Deadlock due to write-locking a pthreads read-write lock while it is already read-locked"); + throw_unsup_format!( + "Deadlock due to write-locking a pthreads read-write lock while it is already read-locked" + ); } else if writers != 0 { - throw_unsup_format!("Deadlock due to write-locking a pthreads read-write lock while it is already write-locked"); + throw_unsup_format!( + "Deadlock due to write-locking a pthreads read-write lock while it is already write-locked" + ); } else { - this.write_scalar(Scalar::from_u32(1), writers_place.into())?; + rwlock_set_writers(this, rwlock_op, Scalar::from_u32(1))?; Ok(0) } } @@ -363,24 +267,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn pthread_rwlock_trywrlock(&mut self, rwlock_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - // Ensure that the following reads and write at offsets to the rwlock pointer are within bounds - assert_ptr_target_min_size(this, rwlock_op, 12)?; - let rwlock = this.read_scalar(rwlock_op)?.not_undef()?; if this.is_null(rwlock)? { return this.eval_libc_i32("EINVAL"); } - let rwlock_place = this.deref_operand(rwlock_op)?; - let u32_layout = this.layout_of(this.tcx.types.u32)?; - let readers_place = rwlock_place.offset(Size::from_bytes(4), MemPlaceMeta::None, u32_layout, this)?; - let writers_place = rwlock_place.offset(Size::from_bytes(8), MemPlaceMeta::None, u32_layout, this)?; - let readers = this.read_scalar(readers_place.into())?.to_u32()?; - let writers = this.read_scalar(writers_place.into())?.to_u32()?; + let readers = rwlock_get_readers(this, rwlock_op)?.to_u32()?; + let writers = rwlock_get_writers(this, rwlock_op)?.to_u32()?; if readers != 0 || writers != 0 { this.eval_libc_i32("EBUSY") } else { - this.write_scalar(Scalar::from_u32(1), writers_place.into())?; + rwlock_set_writers(this, rwlock_op, Scalar::from_u32(1))?; Ok(0) } } @@ -388,25 +285,18 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn pthread_rwlock_unlock(&mut self, rwlock_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - // Ensure that the following reads and writes at offsets to the rwlock pointer are within bounds - assert_ptr_target_min_size(this, rwlock_op, 12)?; - let rwlock = this.read_scalar(rwlock_op)?.not_undef()?; if this.is_null(rwlock)? { return this.eval_libc_i32("EINVAL"); } - let rwlock_place = this.deref_operand(rwlock_op)?; - let u32_layout = this.layout_of(this.tcx.types.u32)?; - let readers_place = rwlock_place.offset(Size::from_bytes(4), MemPlaceMeta::None, u32_layout, this)?; - let writers_place = rwlock_place.offset(Size::from_bytes(8), MemPlaceMeta::None, u32_layout, this)?; - let readers = this.read_scalar(readers_place.into())?.to_u32()?; - let writers = this.read_scalar(writers_place.into())?.to_u32()?; + let readers = rwlock_get_readers(this, rwlock_op)?.to_u32()?; + let writers = rwlock_get_writers(this, rwlock_op)?.to_u32()?; if readers != 0 { - this.write_scalar(Scalar::from_u32(readers - 1), readers_place.into())?; + rwlock_set_readers(this, rwlock_op, Scalar::from_u32(readers - 1))?; Ok(0) } else if writers != 0 { - this.write_scalar(Scalar::from_u32(0), writers_place.into())?; + rwlock_set_writers(this, rwlock_op, Scalar::from_u32(0))?; Ok(0) } else { this.eval_libc_i32("EPERM") @@ -416,38 +306,186 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn pthread_rwlock_destroy(&mut self, rwlock_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - // Ensure that the following reads and writes at offsets to the rwlock pointer are within bounds - assert_ptr_target_min_size(this, rwlock_op, 12)?; - let rwlock = this.read_scalar(rwlock_op)?.not_undef()?; if this.is_null(rwlock)? { return this.eval_libc_i32("EINVAL"); } - let rwlock_place = this.deref_operand(rwlock_op)?; - let u32_layout = this.layout_of(this.tcx.types.u32)?; - let readers_place = rwlock_place.offset(Size::from_bytes(4), MemPlaceMeta::None, u32_layout, this)?; - if this.read_scalar(readers_place.into())?.to_u32()? != 0 { + if rwlock_get_readers(this, rwlock_op)?.to_u32()? != 0 { return this.eval_libc_i32("EBUSY"); } - let writers_place = rwlock_place.offset(Size::from_bytes(8), MemPlaceMeta::None, u32_layout, this)?; - if this.read_scalar(writers_place.into())?.to_u32()? != 0 { + if rwlock_get_writers(this, rwlock_op)?.to_u32()? != 0 { return this.eval_libc_i32("EBUSY"); } - this.write_scalar(ScalarMaybeUndef::Undef, readers_place.into())?; - this.write_scalar(ScalarMaybeUndef::Undef, writers_place.into())?; + rwlock_set_readers(this, rwlock_op, ScalarMaybeUndef::Undef)?; + rwlock_set_writers(this, rwlock_op, ScalarMaybeUndef::Undef)?; Ok(0) } } -fn assert_ptr_target_min_size<'mir, 'tcx: 'mir>(ecx: &MiriEvalContext<'mir, 'tcx>, operand: OpTy<'tcx, Tag>, min_size: u64) -> InterpResult<'tcx, ()> { +fn assert_ptr_target_min_size<'mir, 'tcx: 'mir>( + ecx: &MiriEvalContext<'mir, 'tcx>, + operand: OpTy<'tcx, Tag>, + min_size: u64, +) -> InterpResult<'tcx, ()> { let target_ty = match operand.layout.ty.kind { - TyKind::RawPtr(TypeAndMut{ ty, mutbl: _ }) => ty, + TyKind::RawPtr(TypeAndMut { ty, mutbl: _ }) => ty, _ => panic!("Argument to pthread function was not a raw pointer"), }; let target_layout = ecx.layout_of(target_ty)?; assert!(target_layout.size.bytes() >= min_size); Ok(()) } + +// pthread_mutexattr_t is either 4 or 8 bytes, depending on the platform +// memory layout: store an i32 in the first four bytes equal to the +// corresponding libc mutex kind constant (i.e. PTHREAD_MUTEX_NORMAL) + +fn mutexattr_get_kind<'mir, 'tcx: 'mir>( + ecx: &MiriEvalContext<'mir, 'tcx>, + attr_op: OpTy<'tcx, Tag>, +) -> InterpResult<'tcx, ScalarMaybeUndef> { + // Ensure that the following read at an offset to the attr pointer is within bounds + assert_ptr_target_min_size(ecx, attr_op, 4)?; + let attr_place = ecx.deref_operand(attr_op)?; + let i32_layout = ecx.layout_of(ecx.tcx.types.i32)?; + let kind_place = attr_place.offset(Size::ZERO, MemPlaceMeta::None, i32_layout, ecx)?; + ecx.read_scalar(kind_place.into()) +} + +fn mutexattr_set_kind<'mir, 'tcx: 'mir>( + ecx: &mut MiriEvalContext<'mir, 'tcx>, + attr_op: OpTy<'tcx, Tag>, + kind: impl Into>, +) -> InterpResult<'tcx, ()> { + // Ensure that the following write at an offset to the attr pointer is within bounds + assert_ptr_target_min_size(ecx, attr_op, 4)?; + let attr_place = ecx.deref_operand(attr_op)?; + let i32_layout = ecx.layout_of(ecx.tcx.types.i32)?; + let kind_place = attr_place.offset(Size::ZERO, MemPlaceMeta::None, i32_layout, ecx)?; + ecx.write_scalar(kind.into(), kind_place.into()) +} + +// pthread_mutex_t is between 24 and 48 bytes, depending on the platform +// memory layout: +// bytes 0-3: reserved for signature on macOS +// bytes 4-7: count of how many times this mutex has been locked, as a u32 +// bytes 12-15: mutex kind, as an i32 +// (the kind should be at this offset for compatibility with the static +// initializer macro) + +fn mutex_get_locked_count<'mir, 'tcx: 'mir>( + ecx: &MiriEvalContext<'mir, 'tcx>, + mutex_op: OpTy<'tcx, Tag>, +) -> InterpResult<'tcx, ScalarMaybeUndef> { + // Ensure that the following read at an offset to the mutex pointer is within bounds + assert_ptr_target_min_size(ecx, mutex_op, 16)?; + let mutex_place = ecx.deref_operand(mutex_op)?; + let u32_layout = ecx.layout_of(ecx.tcx.types.u32)?; + let locked_count_place = + mutex_place.offset(Size::from_bytes(4), MemPlaceMeta::None, u32_layout, ecx)?; + ecx.read_scalar(locked_count_place.into()) +} + +fn mutex_set_locked_count<'mir, 'tcx: 'mir>( + ecx: &mut MiriEvalContext<'mir, 'tcx>, + mutex_op: OpTy<'tcx, Tag>, + locked_count: impl Into>, +) -> InterpResult<'tcx, ()> { + // Ensure that the following write at an offset to the mutex pointer is within bounds + assert_ptr_target_min_size(ecx, mutex_op, 16)?; + let mutex_place = ecx.deref_operand(mutex_op)?; + let u32_layout = ecx.layout_of(ecx.tcx.types.u32)?; + let locked_count_place = + mutex_place.offset(Size::from_bytes(4), MemPlaceMeta::None, u32_layout, ecx)?; + ecx.write_scalar(locked_count.into(), locked_count_place.into()) +} + +fn mutex_get_kind<'mir, 'tcx: 'mir>( + ecx: &MiriEvalContext<'mir, 'tcx>, + mutex_op: OpTy<'tcx, Tag>, +) -> InterpResult<'tcx, ScalarMaybeUndef> { + // Ensure that the following read at an offset to the mutex pointer is within bounds + assert_ptr_target_min_size(ecx, mutex_op, 16)?; + let mutex_place = ecx.deref_operand(mutex_op)?; + let i32_layout = ecx.layout_of(ecx.tcx.types.i32)?; + let kind_place = + mutex_place.offset(Size::from_bytes(12), MemPlaceMeta::None, i32_layout, ecx)?; + ecx.read_scalar(kind_place.into()) +} + +fn mutex_set_kind<'mir, 'tcx: 'mir>( + ecx: &mut MiriEvalContext<'mir, 'tcx>, + mutex_op: OpTy<'tcx, Tag>, + kind: impl Into>, +) -> InterpResult<'tcx, ()> { + // Ensure that the following write at an offset to the mutex pointer is within bounds + assert_ptr_target_min_size(ecx, mutex_op, 16)?; + let mutex_place = ecx.deref_operand(mutex_op)?; + let i32_layout = ecx.layout_of(ecx.tcx.types.i32)?; + let kind_place = + mutex_place.offset(Size::from_bytes(12), MemPlaceMeta::None, i32_layout, ecx)?; + ecx.write_scalar(kind.into(), kind_place.into()) +} + +// pthread_rwlock_t is between 32 and 56 bytes, depending on the platform +// memory layout: +// bytes 0-3: reserved for signature on macOS +// bytes 4-7: reader count, as a u32 +// bytes 8-11: writer count, as a u32 + +fn rwlock_get_readers<'mir, 'tcx: 'mir>( + ecx: &MiriEvalContext<'mir, 'tcx>, + rwlock_op: OpTy<'tcx, Tag>, +) -> InterpResult<'tcx, ScalarMaybeUndef> { + // Ensure that the following read at an offset to the rwlock pointer is within bounds + assert_ptr_target_min_size(ecx, rwlock_op, 12)?; + let rwlock_place = ecx.deref_operand(rwlock_op)?; + let u32_layout = ecx.layout_of(ecx.tcx.types.u32)?; + let readers_place = + rwlock_place.offset(Size::from_bytes(4), MemPlaceMeta::None, u32_layout, ecx)?; + ecx.read_scalar(readers_place.into()) +} + +fn rwlock_set_readers<'mir, 'tcx: 'mir>( + ecx: &mut MiriEvalContext<'mir, 'tcx>, + rwlock_op: OpTy<'tcx, Tag>, + readers: impl Into>, +) -> InterpResult<'tcx, ()> { + // Ensure that the following write at an offset to the rwlock pointer is within bounds + assert_ptr_target_min_size(ecx, rwlock_op, 12)?; + let rwlock_place = ecx.deref_operand(rwlock_op)?; + let u32_layout = ecx.layout_of(ecx.tcx.types.u32)?; + let readers_place = + rwlock_place.offset(Size::from_bytes(4), MemPlaceMeta::None, u32_layout, ecx)?; + ecx.write_scalar(readers.into(), readers_place.into()) +} + +fn rwlock_get_writers<'mir, 'tcx: 'mir>( + ecx: &MiriEvalContext<'mir, 'tcx>, + rwlock_op: OpTy<'tcx, Tag>, +) -> InterpResult<'tcx, ScalarMaybeUndef> { + // Ensure that the following read at an offset to the rwlock pointer is within bounds + assert_ptr_target_min_size(ecx, rwlock_op, 12)?; + let rwlock_place = ecx.deref_operand(rwlock_op)?; + let u32_layout = ecx.layout_of(ecx.tcx.types.u32)?; + let writers_place = + rwlock_place.offset(Size::from_bytes(8), MemPlaceMeta::None, u32_layout, ecx)?; + ecx.read_scalar(writers_place.into()) +} + +fn rwlock_set_writers<'mir, 'tcx: 'mir>( + ecx: &mut MiriEvalContext<'mir, 'tcx>, + rwlock_op: OpTy<'tcx, Tag>, + writers: impl Into>, +) -> InterpResult<'tcx, ()> { + // Ensure that the following write at an offset to the rwlock pointer is within bounds + assert_ptr_target_min_size(ecx, rwlock_op, 12)?; + let rwlock_place = ecx.deref_operand(rwlock_op)?; + let u32_layout = ecx.layout_of(ecx.tcx.types.u32)?; + let writers_place = + rwlock_place.offset(Size::from_bytes(8), MemPlaceMeta::None, u32_layout, ecx)?; + ecx.write_scalar(writers.into(), writers_place.into()) +} From ba3884dae6d34370c0841d61acefe8d4a3f8d05c Mon Sep 17 00:00:00 2001 From: David Cook Date: Sun, 22 Mar 2020 16:16:02 -0500 Subject: [PATCH 1799/3747] Use checked addition/subtraction on lock counts --- src/shims/sync.rs | 54 ++++++++++++++++++++++++++++++++++------------- 1 file changed, 39 insertions(+), 15 deletions(-) diff --git a/src/shims/sync.rs b/src/shims/sync.rs index b8d9a88865e67..987513d323ecb 100644 --- a/src/shims/sync.rs +++ b/src/shims/sync.rs @@ -110,8 +110,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.eval_libc_i32("EDEADLK") } } else if kind == this.eval_libc("PTHREAD_MUTEX_RECURSIVE")? { - mutex_set_locked_count(this, mutex_op, Scalar::from_u32(locked_count + 1))?; - Ok(0) + match locked_count.checked_add(1) { + Some(new_count) => { + mutex_set_locked_count(this, mutex_op, Scalar::from_u32(new_count))?; + Ok(0) + } + None => this.eval_libc_i32("EAGAIN"), + } } else { this.eval_libc_i32("EINVAL") } @@ -138,8 +143,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.eval_libc_i32("EBUSY") } } else if kind == this.eval_libc("PTHREAD_MUTEX_RECURSIVE")? { - mutex_set_locked_count(this, mutex_op, Scalar::from_u32(locked_count + 1))?; - Ok(0) + match locked_count.checked_add(1) { + Some(new_count) => { + mutex_set_locked_count(this, mutex_op, Scalar::from_u32(new_count))?; + Ok(0) + } + None => this.eval_libc_i32("EAGAIN"), + } } else { this.eval_libc_i32("EINVAL") } @@ -173,11 +183,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.eval_libc_i32("EPERM") } } else if kind == this.eval_libc("PTHREAD_MUTEX_RECURSIVE")? { - if locked_count > 0 { - mutex_set_locked_count(this, mutex_op, Scalar::from_u32(locked_count - 1))?; - Ok(0) - } else { - this.eval_libc_i32("EPERM") + match locked_count.checked_sub(1) { + Some(new_count) => { + mutex_set_locked_count(this, mutex_op, Scalar::from_u32(new_count))?; + Ok(0) + } + None => { + // locked_count was already zero + this.eval_libc_i32("EPERM") + } } } else { this.eval_libc_i32("EINVAL") @@ -217,8 +231,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "Deadlock due to read-locking a pthreads read-write lock while it is already write-locked" ); } else { - rwlock_set_readers(this, rwlock_op, Scalar::from_u32(readers + 1))?; - Ok(0) + match readers.checked_add(1) { + Some(new_readers) => { + rwlock_set_readers(this, rwlock_op, Scalar::from_u32(new_readers))?; + Ok(0) + } + None => this.eval_libc_i32("EAGAIN"), + } } } @@ -235,8 +254,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if writers != 0 { this.eval_libc_i32("EBUSY") } else { - rwlock_set_readers(this, rwlock_op, Scalar::from_u32(readers + 1))?; - Ok(0) + match readers.checked_add(1) { + Some(new_readers) => { + rwlock_set_readers(this, rwlock_op, Scalar::from_u32(new_readers))?; + Ok(0) + } + None => this.eval_libc_i32("EAGAIN"), + } } } @@ -292,8 +316,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let readers = rwlock_get_readers(this, rwlock_op)?.to_u32()?; let writers = rwlock_get_writers(this, rwlock_op)?.to_u32()?; - if readers != 0 { - rwlock_set_readers(this, rwlock_op, Scalar::from_u32(readers - 1))?; + if let Some(new_readers) = readers.checked_sub(1) { + rwlock_set_readers(this, rwlock_op, Scalar::from_u32(new_readers))?; Ok(0) } else if writers != 0 { rwlock_set_writers(this, rwlock_op, Scalar::from_u32(0))?; From e5e3256b5942a0c2e280700fff7f33bbdc803436 Mon Sep 17 00:00:00 2001 From: David Cook Date: Thu, 26 Mar 2020 21:23:10 -0500 Subject: [PATCH 1800/3747] Address review comments --- src/shims/sync.rs | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/src/shims/sync.rs b/src/shims/sync.rs index 987513d323ecb..960eca5510a24 100644 --- a/src/shims/sync.rs +++ b/src/shims/sync.rs @@ -167,7 +167,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let locked_count = mutex_get_locked_count(this, mutex_op)?.to_u32()?; if kind == this.eval_libc("PTHREAD_MUTEX_NORMAL")? { - if locked_count == 1 { + if locked_count != 0 { mutex_set_locked_count(this, mutex_op, Scalar::from_u32(0))?; Ok(0) } else { @@ -176,7 +176,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ); } } else if kind == this.eval_libc("PTHREAD_MUTEX_ERRORCHECK")? { - if locked_count == 1 { + if locked_count != 0 { mutex_set_locked_count(this, mutex_op, Scalar::from_u32(0))?; Ok(0) } else { @@ -363,8 +363,9 @@ fn assert_ptr_target_min_size<'mir, 'tcx: 'mir>( Ok(()) } -// pthread_mutexattr_t is either 4 or 8 bytes, depending on the platform -// memory layout: store an i32 in the first four bytes equal to the +// pthread_mutexattr_t is either 4 or 8 bytes, depending on the platform. + +// Our chosen memory layout: store an i32 in the first four bytes equal to the // corresponding libc mutex kind constant (i.e. PTHREAD_MUTEX_NORMAL) fn mutexattr_get_kind<'mir, 'tcx: 'mir>( @@ -392,13 +393,14 @@ fn mutexattr_set_kind<'mir, 'tcx: 'mir>( ecx.write_scalar(kind.into(), kind_place.into()) } -// pthread_mutex_t is between 24 and 48 bytes, depending on the platform -// memory layout: +// pthread_mutex_t is between 24 and 48 bytes, depending on the platform. + +// Our chosen memory layout: // bytes 0-3: reserved for signature on macOS +// (need to avoid this because it is set by static initializer macros) // bytes 4-7: count of how many times this mutex has been locked, as a u32 // bytes 12-15: mutex kind, as an i32 -// (the kind should be at this offset for compatibility with the static -// initializer macro) +// (the kind has to be at this offset for compatibility with static initializer macros) fn mutex_get_locked_count<'mir, 'tcx: 'mir>( ecx: &MiriEvalContext<'mir, 'tcx>, @@ -454,9 +456,11 @@ fn mutex_set_kind<'mir, 'tcx: 'mir>( ecx.write_scalar(kind.into(), kind_place.into()) } -// pthread_rwlock_t is between 32 and 56 bytes, depending on the platform -// memory layout: +// pthread_rwlock_t is between 32 and 56 bytes, depending on the platform. + +// Our chosen memory layout: // bytes 0-3: reserved for signature on macOS +// (need to avoid this because it is set by static initializer macros) // bytes 4-7: reader count, as a u32 // bytes 8-11: writer count, as a u32 From 735fc12e1ad35e8789a922eb506f64756f499a32 Mon Sep 17 00:00:00 2001 From: David Cook Date: Fri, 27 Mar 2020 20:06:53 -0500 Subject: [PATCH 1801/3747] Handle variation in layout of pthread_mutex_t --- src/shims/sync.rs | 86 ++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 74 insertions(+), 12 deletions(-) diff --git a/src/shims/sync.rs b/src/shims/sync.rs index 960eca5510a24..6ce45e3ad4dd8 100644 --- a/src/shims/sync.rs +++ b/src/shims/sync.rs @@ -1,5 +1,7 @@ +use std::sync::atomic::{AtomicU64, Ordering}; + use rustc_middle::ty::{TyKind, TypeAndMut}; -use rustc_target::abi::{LayoutOf, Size}; +use rustc_target::abi::{FieldsShape, LayoutOf, Size}; use crate::stacked_borrows::Tag; use crate::*; @@ -399,15 +401,67 @@ fn mutexattr_set_kind<'mir, 'tcx: 'mir>( // bytes 0-3: reserved for signature on macOS // (need to avoid this because it is set by static initializer macros) // bytes 4-7: count of how many times this mutex has been locked, as a u32 -// bytes 12-15: mutex kind, as an i32 -// (the kind has to be at this offset for compatibility with static initializer macros) +// bytes 12-15 or 16-19 (depending on platform): mutex kind, as an i32 +// (the kind has to be at its offset for compatibility with static initializer macros) + +static LIBC_MUTEX_KIND_OFFSET_CACHE: AtomicU64 = AtomicU64::new(0); + +fn libc_mutex_kind_offset<'mir, 'tcx: 'mir>( + ecx: &mut MiriEvalContext<'mir, 'tcx>, +) -> InterpResult<'tcx, u64> { + // Check if this offset has already been found and memoized + let cached_value = LIBC_MUTEX_KIND_OFFSET_CACHE.load(Ordering::Relaxed); + if cached_value != 0 { + return Ok(cached_value); + } + + // This function infers the offset of the `kind` field of libc's pthread_mutex_t + // C struct by examining the array inside libc::PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP. + // At time of writing, it is always all zero bytes except for a one byte at one of + // four positions, depending on the target OS's C struct layout and the endianness of the + // target architecture. This offset will then be used in getters and setters below, so that + // mutexes created from static initializers can be emulated with the correct behavior. + let initializer_path = ["libc", "PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP"]; + let initializer_instance = ecx.resolve_path(&initializer_path); + let initializer_cid = GlobalId { instance: initializer_instance, promoted: None }; + let initializer_const_val = ecx.const_eval_raw(initializer_cid)?; + let array_mplacety = ecx.mplace_field(initializer_const_val, 0)?; + let array_length = match array_mplacety.layout.fields { + FieldsShape::Array { count, .. } => count, + _ => bug!("Couldn't get array length from type {:?}", array_mplacety.layout.ty), + }; + + let kind_offset = if array_length < 20 { + bug!("libc::PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP array was shorter than expected"); + } else if ecx.read_scalar(ecx.mplace_field(array_mplacety, 16)?.into())?.to_u8()? != 0 { + // for little-endian architectures + 16 + } else if ecx.read_scalar(ecx.mplace_field(array_mplacety, 19)?.into())?.to_u8()? != 0 { + // for big-endian architectures + // (note that the i32 spans bytes 16 through 19, so the offset of the kind field is 16) + 16 + } else if ecx.read_scalar(ecx.mplace_field(array_mplacety, 12)?.into())?.to_u8()? != 0 { + // for little-endian architectures + 12 + } else if ecx.read_scalar(ecx.mplace_field(array_mplacety, 15)?.into())?.to_u8()? != 0 { + // for big-endian architectures + // (note that the i32 spans bytes 12 through 15, so the offset of the kind field is 12) + 12 + } else { + bug!("Couldn't determine offset of `kind` in pthread_mutex_t"); + }; + + // Save offset to memoization cache for future calls + LIBC_MUTEX_KIND_OFFSET_CACHE.store(kind_offset, Ordering::Relaxed); + Ok(kind_offset) +} fn mutex_get_locked_count<'mir, 'tcx: 'mir>( ecx: &MiriEvalContext<'mir, 'tcx>, mutex_op: OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, ScalarMaybeUndef> { // Ensure that the following read at an offset to the mutex pointer is within bounds - assert_ptr_target_min_size(ecx, mutex_op, 16)?; + assert_ptr_target_min_size(ecx, mutex_op, 20)?; let mutex_place = ecx.deref_operand(mutex_op)?; let u32_layout = ecx.layout_of(ecx.tcx.types.u32)?; let locked_count_place = @@ -421,7 +475,7 @@ fn mutex_set_locked_count<'mir, 'tcx: 'mir>( locked_count: impl Into>, ) -> InterpResult<'tcx, ()> { // Ensure that the following write at an offset to the mutex pointer is within bounds - assert_ptr_target_min_size(ecx, mutex_op, 16)?; + assert_ptr_target_min_size(ecx, mutex_op, 20)?; let mutex_place = ecx.deref_operand(mutex_op)?; let u32_layout = ecx.layout_of(ecx.tcx.types.u32)?; let locked_count_place = @@ -430,15 +484,19 @@ fn mutex_set_locked_count<'mir, 'tcx: 'mir>( } fn mutex_get_kind<'mir, 'tcx: 'mir>( - ecx: &MiriEvalContext<'mir, 'tcx>, + ecx: &mut MiriEvalContext<'mir, 'tcx>, mutex_op: OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, ScalarMaybeUndef> { // Ensure that the following read at an offset to the mutex pointer is within bounds - assert_ptr_target_min_size(ecx, mutex_op, 16)?; + assert_ptr_target_min_size(ecx, mutex_op, 20)?; let mutex_place = ecx.deref_operand(mutex_op)?; let i32_layout = ecx.layout_of(ecx.tcx.types.i32)?; - let kind_place = - mutex_place.offset(Size::from_bytes(12), MemPlaceMeta::None, i32_layout, ecx)?; + let kind_place = mutex_place.offset( + Size::from_bytes(libc_mutex_kind_offset(ecx)?), + MemPlaceMeta::None, + i32_layout, + ecx, + )?; ecx.read_scalar(kind_place.into()) } @@ -448,11 +506,15 @@ fn mutex_set_kind<'mir, 'tcx: 'mir>( kind: impl Into>, ) -> InterpResult<'tcx, ()> { // Ensure that the following write at an offset to the mutex pointer is within bounds - assert_ptr_target_min_size(ecx, mutex_op, 16)?; + assert_ptr_target_min_size(ecx, mutex_op, 20)?; let mutex_place = ecx.deref_operand(mutex_op)?; let i32_layout = ecx.layout_of(ecx.tcx.types.i32)?; - let kind_place = - mutex_place.offset(Size::from_bytes(12), MemPlaceMeta::None, i32_layout, ecx)?; + let kind_place = mutex_place.offset( + Size::from_bytes(libc_mutex_kind_offset(ecx)?), + MemPlaceMeta::None, + i32_layout, + ecx, + )?; ecx.write_scalar(kind.into(), kind_place.into()) } From de29546414cc5a987fd3317a9c3e5415e15a133b Mon Sep 17 00:00:00 2001 From: David Cook Date: Fri, 27 Mar 2020 20:26:21 -0500 Subject: [PATCH 1802/3747] Add and rearrange mutex tests --- tests/run-pass/sync.rs | 58 ++++++++++++++++++++++++++++-------------- 1 file changed, 39 insertions(+), 19 deletions(-) diff --git a/tests/run-pass/sync.rs b/tests/run-pass/sync.rs index c1e44789aa74e..025ae81372cf8 100644 --- a/tests/run-pass/sync.rs +++ b/tests/run-pass/sync.rs @@ -5,17 +5,18 @@ use std::sync::{Mutex, RwLock, TryLockError}; extern crate libc; fn main() { - test_mutex(); + test_mutex_stdlib(); #[cfg(not(target_os = "windows"))] // TODO: implement RwLock on Windows { - test_mutex_libc_recursive(); + test_mutex_libc_init_recursive(); + test_mutex_libc_init_normal(); + test_mutex_libc_static_initializer_recursive(); test_rwlock_stdlib(); - test_mutex_libc_init(); test_rwlock_libc_static_initializer(); } } -fn test_mutex() { +fn test_mutex_stdlib() { let m = Mutex::new(0); { let _guard = m.lock(); @@ -26,7 +27,7 @@ fn test_mutex() { } #[cfg(not(target_os = "windows"))] -fn test_mutex_libc_recursive() { +fn test_mutex_libc_init_recursive() { unsafe { let mut attr: libc::pthread_mutexattr_t = std::mem::zeroed(); assert_eq!(libc::pthread_mutexattr_init(&mut attr as *mut _), 0); @@ -47,6 +48,39 @@ fn test_mutex_libc_recursive() { } } +#[cfg(not(target_os = "windows"))] +fn test_mutex_libc_init_normal() { + unsafe { + let mut mutexattr: libc::pthread_mutexattr_t = std::mem::zeroed(); + assert_eq!(libc::pthread_mutexattr_settype(&mut mutexattr as *mut _, libc::PTHREAD_MUTEX_NORMAL), 0); + let mut mutex: libc::pthread_mutex_t = std::mem::zeroed(); + assert_eq!(libc::pthread_mutex_init(&mut mutex as *mut _, &mutexattr as *const _), 0); + assert_eq!(libc::pthread_mutex_lock(&mut mutex as *mut _), 0); + assert_eq!(libc::pthread_mutex_trylock(&mut mutex as *mut _), libc::EBUSY); + assert_eq!(libc::pthread_mutex_unlock(&mut mutex as *mut _), 0); + assert_eq!(libc::pthread_mutex_trylock(&mut mutex as *mut _), 0); + assert_eq!(libc::pthread_mutex_unlock(&mut mutex as *mut _), 0); + assert_eq!(libc::pthread_mutex_destroy(&mut mutex as *mut _), 0); + } +} + +#[cfg(not(target_os = "windows"))] +fn test_mutex_libc_static_initializer_recursive() { + let mutex = std::cell::UnsafeCell::new(libc::PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP); + unsafe { + assert_eq!(libc::pthread_mutex_lock(mutex.get()), 0); + assert_eq!(libc::pthread_mutex_trylock(mutex.get()), 0); + assert_eq!(libc::pthread_mutex_unlock(mutex.get()), 0); + assert_eq!(libc::pthread_mutex_unlock(mutex.get()), 0); + assert_eq!(libc::pthread_mutex_trylock(mutex.get()), 0); + assert_eq!(libc::pthread_mutex_lock(mutex.get()), 0); + assert_eq!(libc::pthread_mutex_unlock(mutex.get()), 0); + assert_eq!(libc::pthread_mutex_unlock(mutex.get()), 0); + assert_eq!(libc::pthread_mutex_unlock(mutex.get()), libc::EPERM); + assert_eq!(libc::pthread_mutex_destroy(mutex.get()), 0); + } +} + #[cfg(not(target_os = "windows"))] fn test_rwlock_stdlib() { let rw = RwLock::new(0); @@ -67,20 +101,6 @@ fn test_rwlock_stdlib() { // need to go a layer deeper and test the behavior of libc functions, because // std::sys::unix::rwlock::RWLock keeps track of write_locked and num_readers -#[cfg(not(target_os = "windows"))] -fn test_mutex_libc_init() { - unsafe { - let mut mutex: libc::pthread_mutex_t = std::mem::zeroed(); - assert_eq!(libc::pthread_mutex_init(&mut mutex as *mut _, std::ptr::null_mut()), 0); - assert_eq!(libc::pthread_mutex_lock(&mut mutex as *mut _), 0); - assert_eq!(libc::pthread_mutex_trylock(&mut mutex as *mut _), libc::EBUSY); - assert_eq!(libc::pthread_mutex_unlock(&mut mutex as *mut _), 0); - assert_eq!(libc::pthread_mutex_trylock(&mut mutex as *mut _), 0); - assert_eq!(libc::pthread_mutex_unlock(&mut mutex as *mut _), 0); - assert_eq!(libc::pthread_mutex_destroy(&mut mutex as *mut _), 0); - } -} - #[cfg(not(target_os = "windows"))] fn test_rwlock_libc_static_initializer() { let rw = std::cell::UnsafeCell::new(libc::PTHREAD_RWLOCK_INITIALIZER); From c7466c9531c1a282380183c78001014c35dc9fac Mon Sep 17 00:00:00 2001 From: David Cook Date: Fri, 27 Mar 2020 20:40:54 -0500 Subject: [PATCH 1803/3747] Add TerminationInfo::Deadlock, use in mutex shim --- src/diagnostics.rs | 6 +++- src/shims/sync.rs | 76 +++++----------------------------------------- 2 files changed, 13 insertions(+), 69 deletions(-) diff --git a/src/diagnostics.rs b/src/diagnostics.rs index 9ff434021150f..2b53efe864e54 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -12,7 +12,8 @@ pub enum TerminationInfo { Exit(i64), Abort(Option), UnsupportedInIsolation(String), - ExperimentalUb { msg: String, url: String } + ExperimentalUb { msg: String, url: String }, + Deadlock, } impl fmt::Debug for TerminationInfo { @@ -29,6 +30,8 @@ impl fmt::Debug for TerminationInfo { write!(f, "{}", msg), ExperimentalUb { msg, .. } => write!(f, "{}", msg), + Deadlock => + write!(f, "the evaluated program deadlocked"), } } } @@ -60,6 +63,7 @@ pub fn report_error<'tcx, 'mir>( "unsupported operation", ExperimentalUb { .. } => "Undefined Behavior", + Deadlock => "deadlock", }; let helps = match info { UnsupportedInIsolation(_) => diff --git a/src/shims/sync.rs b/src/shims/sync.rs index 6ce45e3ad4dd8..94e563353b887 100644 --- a/src/shims/sync.rs +++ b/src/shims/sync.rs @@ -1,7 +1,5 @@ -use std::sync::atomic::{AtomicU64, Ordering}; - use rustc_middle::ty::{TyKind, TypeAndMut}; -use rustc_target::abi::{FieldsShape, LayoutOf, Size}; +use rustc_target::abi::{LayoutOf, Size}; use crate::stacked_borrows::Tag; use crate::*; @@ -102,7 +100,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx mutex_set_locked_count(this, mutex_op, Scalar::from_u32(1))?; Ok(0) } else { - throw_unsup_format!("Deadlock due to locking a PTHREAD_MUTEX_NORMAL mutex twice"); + throw_machine_stop!(TerminationInfo::Deadlock); } } else if kind == this.eval_libc("PTHREAD_MUTEX_ERRORCHECK")? { if locked_count == 0 { @@ -404,58 +402,6 @@ fn mutexattr_set_kind<'mir, 'tcx: 'mir>( // bytes 12-15 or 16-19 (depending on platform): mutex kind, as an i32 // (the kind has to be at its offset for compatibility with static initializer macros) -static LIBC_MUTEX_KIND_OFFSET_CACHE: AtomicU64 = AtomicU64::new(0); - -fn libc_mutex_kind_offset<'mir, 'tcx: 'mir>( - ecx: &mut MiriEvalContext<'mir, 'tcx>, -) -> InterpResult<'tcx, u64> { - // Check if this offset has already been found and memoized - let cached_value = LIBC_MUTEX_KIND_OFFSET_CACHE.load(Ordering::Relaxed); - if cached_value != 0 { - return Ok(cached_value); - } - - // This function infers the offset of the `kind` field of libc's pthread_mutex_t - // C struct by examining the array inside libc::PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP. - // At time of writing, it is always all zero bytes except for a one byte at one of - // four positions, depending on the target OS's C struct layout and the endianness of the - // target architecture. This offset will then be used in getters and setters below, so that - // mutexes created from static initializers can be emulated with the correct behavior. - let initializer_path = ["libc", "PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP"]; - let initializer_instance = ecx.resolve_path(&initializer_path); - let initializer_cid = GlobalId { instance: initializer_instance, promoted: None }; - let initializer_const_val = ecx.const_eval_raw(initializer_cid)?; - let array_mplacety = ecx.mplace_field(initializer_const_val, 0)?; - let array_length = match array_mplacety.layout.fields { - FieldsShape::Array { count, .. } => count, - _ => bug!("Couldn't get array length from type {:?}", array_mplacety.layout.ty), - }; - - let kind_offset = if array_length < 20 { - bug!("libc::PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP array was shorter than expected"); - } else if ecx.read_scalar(ecx.mplace_field(array_mplacety, 16)?.into())?.to_u8()? != 0 { - // for little-endian architectures - 16 - } else if ecx.read_scalar(ecx.mplace_field(array_mplacety, 19)?.into())?.to_u8()? != 0 { - // for big-endian architectures - // (note that the i32 spans bytes 16 through 19, so the offset of the kind field is 16) - 16 - } else if ecx.read_scalar(ecx.mplace_field(array_mplacety, 12)?.into())?.to_u8()? != 0 { - // for little-endian architectures - 12 - } else if ecx.read_scalar(ecx.mplace_field(array_mplacety, 15)?.into())?.to_u8()? != 0 { - // for big-endian architectures - // (note that the i32 spans bytes 12 through 15, so the offset of the kind field is 12) - 12 - } else { - bug!("Couldn't determine offset of `kind` in pthread_mutex_t"); - }; - - // Save offset to memoization cache for future calls - LIBC_MUTEX_KIND_OFFSET_CACHE.store(kind_offset, Ordering::Relaxed); - Ok(kind_offset) -} - fn mutex_get_locked_count<'mir, 'tcx: 'mir>( ecx: &MiriEvalContext<'mir, 'tcx>, mutex_op: OpTy<'tcx, Tag>, @@ -491,12 +437,9 @@ fn mutex_get_kind<'mir, 'tcx: 'mir>( assert_ptr_target_min_size(ecx, mutex_op, 20)?; let mutex_place = ecx.deref_operand(mutex_op)?; let i32_layout = ecx.layout_of(ecx.tcx.types.i32)?; - let kind_place = mutex_place.offset( - Size::from_bytes(libc_mutex_kind_offset(ecx)?), - MemPlaceMeta::None, - i32_layout, - ecx, - )?; + let kind_offset = if ecx.pointer_size().bytes() == 8 { 16 } else { 12 }; + let kind_place = + mutex_place.offset(Size::from_bytes(kind_offset), MemPlaceMeta::None, i32_layout, ecx)?; ecx.read_scalar(kind_place.into()) } @@ -509,12 +452,9 @@ fn mutex_set_kind<'mir, 'tcx: 'mir>( assert_ptr_target_min_size(ecx, mutex_op, 20)?; let mutex_place = ecx.deref_operand(mutex_op)?; let i32_layout = ecx.layout_of(ecx.tcx.types.i32)?; - let kind_place = mutex_place.offset( - Size::from_bytes(libc_mutex_kind_offset(ecx)?), - MemPlaceMeta::None, - i32_layout, - ecx, - )?; + let kind_offset = if ecx.pointer_size().bytes() == 8 { 16 } else { 12 }; + let kind_place = + mutex_place.offset(Size::from_bytes(kind_offset), MemPlaceMeta::None, i32_layout, ecx)?; ecx.write_scalar(kind.into(), kind_place.into()) } From 7f6df15aa2215ade35992b396bb76c8ae8fcf4df Mon Sep 17 00:00:00 2001 From: David Cook Date: Sat, 28 Mar 2020 09:25:02 -0500 Subject: [PATCH 1804/3747] Rearrange functions --- src/shims/sync.rs | 342 +++++++++++++++++++++++----------------------- 1 file changed, 171 insertions(+), 171 deletions(-) diff --git a/src/shims/sync.rs b/src/shims/sync.rs index 94e563353b887..4e4f8c112e533 100644 --- a/src/shims/sync.rs +++ b/src/shims/sync.rs @@ -4,6 +4,177 @@ use rustc_target::abi::{LayoutOf, Size}; use crate::stacked_borrows::Tag; use crate::*; +fn assert_ptr_target_min_size<'mir, 'tcx: 'mir>( + ecx: &MiriEvalContext<'mir, 'tcx>, + operand: OpTy<'tcx, Tag>, + min_size: u64, +) -> InterpResult<'tcx, ()> { + let target_ty = match operand.layout.ty.kind { + TyKind::RawPtr(TypeAndMut { ty, mutbl: _ }) => ty, + _ => panic!("Argument to pthread function was not a raw pointer"), + }; + let target_layout = ecx.layout_of(target_ty)?; + assert!(target_layout.size.bytes() >= min_size); + Ok(()) +} + +// pthread_mutexattr_t is either 4 or 8 bytes, depending on the platform. + +// Our chosen memory layout: store an i32 in the first four bytes equal to the +// corresponding libc mutex kind constant (i.e. PTHREAD_MUTEX_NORMAL) + +fn mutexattr_get_kind<'mir, 'tcx: 'mir>( + ecx: &MiriEvalContext<'mir, 'tcx>, + attr_op: OpTy<'tcx, Tag>, +) -> InterpResult<'tcx, ScalarMaybeUndef> { + // Ensure that the following read at an offset to the attr pointer is within bounds + assert_ptr_target_min_size(ecx, attr_op, 4)?; + let attr_place = ecx.deref_operand(attr_op)?; + let i32_layout = ecx.layout_of(ecx.tcx.types.i32)?; + let kind_place = attr_place.offset(Size::ZERO, MemPlaceMeta::None, i32_layout, ecx)?; + ecx.read_scalar(kind_place.into()) +} + +fn mutexattr_set_kind<'mir, 'tcx: 'mir>( + ecx: &mut MiriEvalContext<'mir, 'tcx>, + attr_op: OpTy<'tcx, Tag>, + kind: impl Into>, +) -> InterpResult<'tcx, ()> { + // Ensure that the following write at an offset to the attr pointer is within bounds + assert_ptr_target_min_size(ecx, attr_op, 4)?; + let attr_place = ecx.deref_operand(attr_op)?; + let i32_layout = ecx.layout_of(ecx.tcx.types.i32)?; + let kind_place = attr_place.offset(Size::ZERO, MemPlaceMeta::None, i32_layout, ecx)?; + ecx.write_scalar(kind.into(), kind_place.into()) +} + +// pthread_mutex_t is between 24 and 48 bytes, depending on the platform. + +// Our chosen memory layout: +// bytes 0-3: reserved for signature on macOS +// (need to avoid this because it is set by static initializer macros) +// bytes 4-7: count of how many times this mutex has been locked, as a u32 +// bytes 12-15 or 16-19 (depending on platform): mutex kind, as an i32 +// (the kind has to be at its offset for compatibility with static initializer macros) + +fn mutex_get_locked_count<'mir, 'tcx: 'mir>( + ecx: &MiriEvalContext<'mir, 'tcx>, + mutex_op: OpTy<'tcx, Tag>, +) -> InterpResult<'tcx, ScalarMaybeUndef> { + // Ensure that the following read at an offset to the mutex pointer is within bounds + assert_ptr_target_min_size(ecx, mutex_op, 20)?; + let mutex_place = ecx.deref_operand(mutex_op)?; + let u32_layout = ecx.layout_of(ecx.tcx.types.u32)?; + let locked_count_place = + mutex_place.offset(Size::from_bytes(4), MemPlaceMeta::None, u32_layout, ecx)?; + ecx.read_scalar(locked_count_place.into()) +} + +fn mutex_set_locked_count<'mir, 'tcx: 'mir>( + ecx: &mut MiriEvalContext<'mir, 'tcx>, + mutex_op: OpTy<'tcx, Tag>, + locked_count: impl Into>, +) -> InterpResult<'tcx, ()> { + // Ensure that the following write at an offset to the mutex pointer is within bounds + assert_ptr_target_min_size(ecx, mutex_op, 20)?; + let mutex_place = ecx.deref_operand(mutex_op)?; + let u32_layout = ecx.layout_of(ecx.tcx.types.u32)?; + let locked_count_place = + mutex_place.offset(Size::from_bytes(4), MemPlaceMeta::None, u32_layout, ecx)?; + ecx.write_scalar(locked_count.into(), locked_count_place.into()) +} + +fn mutex_get_kind<'mir, 'tcx: 'mir>( + ecx: &mut MiriEvalContext<'mir, 'tcx>, + mutex_op: OpTy<'tcx, Tag>, +) -> InterpResult<'tcx, ScalarMaybeUndef> { + // Ensure that the following read at an offset to the mutex pointer is within bounds + assert_ptr_target_min_size(ecx, mutex_op, 20)?; + let mutex_place = ecx.deref_operand(mutex_op)?; + let i32_layout = ecx.layout_of(ecx.tcx.types.i32)?; + let kind_offset = if ecx.pointer_size().bytes() == 8 { 16 } else { 12 }; + let kind_place = + mutex_place.offset(Size::from_bytes(kind_offset), MemPlaceMeta::None, i32_layout, ecx)?; + ecx.read_scalar(kind_place.into()) +} + +fn mutex_set_kind<'mir, 'tcx: 'mir>( + ecx: &mut MiriEvalContext<'mir, 'tcx>, + mutex_op: OpTy<'tcx, Tag>, + kind: impl Into>, +) -> InterpResult<'tcx, ()> { + // Ensure that the following write at an offset to the mutex pointer is within bounds + assert_ptr_target_min_size(ecx, mutex_op, 20)?; + let mutex_place = ecx.deref_operand(mutex_op)?; + let i32_layout = ecx.layout_of(ecx.tcx.types.i32)?; + let kind_offset = if ecx.pointer_size().bytes() == 8 { 16 } else { 12 }; + let kind_place = + mutex_place.offset(Size::from_bytes(kind_offset), MemPlaceMeta::None, i32_layout, ecx)?; + ecx.write_scalar(kind.into(), kind_place.into()) +} + +// pthread_rwlock_t is between 32 and 56 bytes, depending on the platform. + +// Our chosen memory layout: +// bytes 0-3: reserved for signature on macOS +// (need to avoid this because it is set by static initializer macros) +// bytes 4-7: reader count, as a u32 +// bytes 8-11: writer count, as a u32 + +fn rwlock_get_readers<'mir, 'tcx: 'mir>( + ecx: &MiriEvalContext<'mir, 'tcx>, + rwlock_op: OpTy<'tcx, Tag>, +) -> InterpResult<'tcx, ScalarMaybeUndef> { + // Ensure that the following read at an offset to the rwlock pointer is within bounds + assert_ptr_target_min_size(ecx, rwlock_op, 12)?; + let rwlock_place = ecx.deref_operand(rwlock_op)?; + let u32_layout = ecx.layout_of(ecx.tcx.types.u32)?; + let readers_place = + rwlock_place.offset(Size::from_bytes(4), MemPlaceMeta::None, u32_layout, ecx)?; + ecx.read_scalar(readers_place.into()) +} + +fn rwlock_set_readers<'mir, 'tcx: 'mir>( + ecx: &mut MiriEvalContext<'mir, 'tcx>, + rwlock_op: OpTy<'tcx, Tag>, + readers: impl Into>, +) -> InterpResult<'tcx, ()> { + // Ensure that the following write at an offset to the rwlock pointer is within bounds + assert_ptr_target_min_size(ecx, rwlock_op, 12)?; + let rwlock_place = ecx.deref_operand(rwlock_op)?; + let u32_layout = ecx.layout_of(ecx.tcx.types.u32)?; + let readers_place = + rwlock_place.offset(Size::from_bytes(4), MemPlaceMeta::None, u32_layout, ecx)?; + ecx.write_scalar(readers.into(), readers_place.into()) +} + +fn rwlock_get_writers<'mir, 'tcx: 'mir>( + ecx: &MiriEvalContext<'mir, 'tcx>, + rwlock_op: OpTy<'tcx, Tag>, +) -> InterpResult<'tcx, ScalarMaybeUndef> { + // Ensure that the following read at an offset to the rwlock pointer is within bounds + assert_ptr_target_min_size(ecx, rwlock_op, 12)?; + let rwlock_place = ecx.deref_operand(rwlock_op)?; + let u32_layout = ecx.layout_of(ecx.tcx.types.u32)?; + let writers_place = + rwlock_place.offset(Size::from_bytes(8), MemPlaceMeta::None, u32_layout, ecx)?; + ecx.read_scalar(writers_place.into()) +} + +fn rwlock_set_writers<'mir, 'tcx: 'mir>( + ecx: &mut MiriEvalContext<'mir, 'tcx>, + rwlock_op: OpTy<'tcx, Tag>, + writers: impl Into>, +) -> InterpResult<'tcx, ()> { + // Ensure that the following write at an offset to the rwlock pointer is within bounds + assert_ptr_target_min_size(ecx, rwlock_op, 12)?; + let rwlock_place = ecx.deref_operand(rwlock_op)?; + let u32_layout = ecx.layout_of(ecx.tcx.types.u32)?; + let writers_place = + rwlock_place.offset(Size::from_bytes(8), MemPlaceMeta::None, u32_layout, ecx)?; + ecx.write_scalar(writers.into(), writers_place.into()) +} + impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { fn pthread_mutexattr_init(&mut self, attr_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { @@ -348,174 +519,3 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(0) } } - -fn assert_ptr_target_min_size<'mir, 'tcx: 'mir>( - ecx: &MiriEvalContext<'mir, 'tcx>, - operand: OpTy<'tcx, Tag>, - min_size: u64, -) -> InterpResult<'tcx, ()> { - let target_ty = match operand.layout.ty.kind { - TyKind::RawPtr(TypeAndMut { ty, mutbl: _ }) => ty, - _ => panic!("Argument to pthread function was not a raw pointer"), - }; - let target_layout = ecx.layout_of(target_ty)?; - assert!(target_layout.size.bytes() >= min_size); - Ok(()) -} - -// pthread_mutexattr_t is either 4 or 8 bytes, depending on the platform. - -// Our chosen memory layout: store an i32 in the first four bytes equal to the -// corresponding libc mutex kind constant (i.e. PTHREAD_MUTEX_NORMAL) - -fn mutexattr_get_kind<'mir, 'tcx: 'mir>( - ecx: &MiriEvalContext<'mir, 'tcx>, - attr_op: OpTy<'tcx, Tag>, -) -> InterpResult<'tcx, ScalarMaybeUndef> { - // Ensure that the following read at an offset to the attr pointer is within bounds - assert_ptr_target_min_size(ecx, attr_op, 4)?; - let attr_place = ecx.deref_operand(attr_op)?; - let i32_layout = ecx.layout_of(ecx.tcx.types.i32)?; - let kind_place = attr_place.offset(Size::ZERO, MemPlaceMeta::None, i32_layout, ecx)?; - ecx.read_scalar(kind_place.into()) -} - -fn mutexattr_set_kind<'mir, 'tcx: 'mir>( - ecx: &mut MiriEvalContext<'mir, 'tcx>, - attr_op: OpTy<'tcx, Tag>, - kind: impl Into>, -) -> InterpResult<'tcx, ()> { - // Ensure that the following write at an offset to the attr pointer is within bounds - assert_ptr_target_min_size(ecx, attr_op, 4)?; - let attr_place = ecx.deref_operand(attr_op)?; - let i32_layout = ecx.layout_of(ecx.tcx.types.i32)?; - let kind_place = attr_place.offset(Size::ZERO, MemPlaceMeta::None, i32_layout, ecx)?; - ecx.write_scalar(kind.into(), kind_place.into()) -} - -// pthread_mutex_t is between 24 and 48 bytes, depending on the platform. - -// Our chosen memory layout: -// bytes 0-3: reserved for signature on macOS -// (need to avoid this because it is set by static initializer macros) -// bytes 4-7: count of how many times this mutex has been locked, as a u32 -// bytes 12-15 or 16-19 (depending on platform): mutex kind, as an i32 -// (the kind has to be at its offset for compatibility with static initializer macros) - -fn mutex_get_locked_count<'mir, 'tcx: 'mir>( - ecx: &MiriEvalContext<'mir, 'tcx>, - mutex_op: OpTy<'tcx, Tag>, -) -> InterpResult<'tcx, ScalarMaybeUndef> { - // Ensure that the following read at an offset to the mutex pointer is within bounds - assert_ptr_target_min_size(ecx, mutex_op, 20)?; - let mutex_place = ecx.deref_operand(mutex_op)?; - let u32_layout = ecx.layout_of(ecx.tcx.types.u32)?; - let locked_count_place = - mutex_place.offset(Size::from_bytes(4), MemPlaceMeta::None, u32_layout, ecx)?; - ecx.read_scalar(locked_count_place.into()) -} - -fn mutex_set_locked_count<'mir, 'tcx: 'mir>( - ecx: &mut MiriEvalContext<'mir, 'tcx>, - mutex_op: OpTy<'tcx, Tag>, - locked_count: impl Into>, -) -> InterpResult<'tcx, ()> { - // Ensure that the following write at an offset to the mutex pointer is within bounds - assert_ptr_target_min_size(ecx, mutex_op, 20)?; - let mutex_place = ecx.deref_operand(mutex_op)?; - let u32_layout = ecx.layout_of(ecx.tcx.types.u32)?; - let locked_count_place = - mutex_place.offset(Size::from_bytes(4), MemPlaceMeta::None, u32_layout, ecx)?; - ecx.write_scalar(locked_count.into(), locked_count_place.into()) -} - -fn mutex_get_kind<'mir, 'tcx: 'mir>( - ecx: &mut MiriEvalContext<'mir, 'tcx>, - mutex_op: OpTy<'tcx, Tag>, -) -> InterpResult<'tcx, ScalarMaybeUndef> { - // Ensure that the following read at an offset to the mutex pointer is within bounds - assert_ptr_target_min_size(ecx, mutex_op, 20)?; - let mutex_place = ecx.deref_operand(mutex_op)?; - let i32_layout = ecx.layout_of(ecx.tcx.types.i32)?; - let kind_offset = if ecx.pointer_size().bytes() == 8 { 16 } else { 12 }; - let kind_place = - mutex_place.offset(Size::from_bytes(kind_offset), MemPlaceMeta::None, i32_layout, ecx)?; - ecx.read_scalar(kind_place.into()) -} - -fn mutex_set_kind<'mir, 'tcx: 'mir>( - ecx: &mut MiriEvalContext<'mir, 'tcx>, - mutex_op: OpTy<'tcx, Tag>, - kind: impl Into>, -) -> InterpResult<'tcx, ()> { - // Ensure that the following write at an offset to the mutex pointer is within bounds - assert_ptr_target_min_size(ecx, mutex_op, 20)?; - let mutex_place = ecx.deref_operand(mutex_op)?; - let i32_layout = ecx.layout_of(ecx.tcx.types.i32)?; - let kind_offset = if ecx.pointer_size().bytes() == 8 { 16 } else { 12 }; - let kind_place = - mutex_place.offset(Size::from_bytes(kind_offset), MemPlaceMeta::None, i32_layout, ecx)?; - ecx.write_scalar(kind.into(), kind_place.into()) -} - -// pthread_rwlock_t is between 32 and 56 bytes, depending on the platform. - -// Our chosen memory layout: -// bytes 0-3: reserved for signature on macOS -// (need to avoid this because it is set by static initializer macros) -// bytes 4-7: reader count, as a u32 -// bytes 8-11: writer count, as a u32 - -fn rwlock_get_readers<'mir, 'tcx: 'mir>( - ecx: &MiriEvalContext<'mir, 'tcx>, - rwlock_op: OpTy<'tcx, Tag>, -) -> InterpResult<'tcx, ScalarMaybeUndef> { - // Ensure that the following read at an offset to the rwlock pointer is within bounds - assert_ptr_target_min_size(ecx, rwlock_op, 12)?; - let rwlock_place = ecx.deref_operand(rwlock_op)?; - let u32_layout = ecx.layout_of(ecx.tcx.types.u32)?; - let readers_place = - rwlock_place.offset(Size::from_bytes(4), MemPlaceMeta::None, u32_layout, ecx)?; - ecx.read_scalar(readers_place.into()) -} - -fn rwlock_set_readers<'mir, 'tcx: 'mir>( - ecx: &mut MiriEvalContext<'mir, 'tcx>, - rwlock_op: OpTy<'tcx, Tag>, - readers: impl Into>, -) -> InterpResult<'tcx, ()> { - // Ensure that the following write at an offset to the rwlock pointer is within bounds - assert_ptr_target_min_size(ecx, rwlock_op, 12)?; - let rwlock_place = ecx.deref_operand(rwlock_op)?; - let u32_layout = ecx.layout_of(ecx.tcx.types.u32)?; - let readers_place = - rwlock_place.offset(Size::from_bytes(4), MemPlaceMeta::None, u32_layout, ecx)?; - ecx.write_scalar(readers.into(), readers_place.into()) -} - -fn rwlock_get_writers<'mir, 'tcx: 'mir>( - ecx: &MiriEvalContext<'mir, 'tcx>, - rwlock_op: OpTy<'tcx, Tag>, -) -> InterpResult<'tcx, ScalarMaybeUndef> { - // Ensure that the following read at an offset to the rwlock pointer is within bounds - assert_ptr_target_min_size(ecx, rwlock_op, 12)?; - let rwlock_place = ecx.deref_operand(rwlock_op)?; - let u32_layout = ecx.layout_of(ecx.tcx.types.u32)?; - let writers_place = - rwlock_place.offset(Size::from_bytes(8), MemPlaceMeta::None, u32_layout, ecx)?; - ecx.read_scalar(writers_place.into()) -} - -fn rwlock_set_writers<'mir, 'tcx: 'mir>( - ecx: &mut MiriEvalContext<'mir, 'tcx>, - rwlock_op: OpTy<'tcx, Tag>, - writers: impl Into>, -) -> InterpResult<'tcx, ()> { - // Ensure that the following write at an offset to the rwlock pointer is within bounds - assert_ptr_target_min_size(ecx, rwlock_op, 12)?; - let rwlock_place = ecx.deref_operand(rwlock_op)?; - let u32_layout = ecx.layout_of(ecx.tcx.types.u32)?; - let writers_place = - rwlock_place.offset(Size::from_bytes(8), MemPlaceMeta::None, u32_layout, ecx)?; - ecx.write_scalar(writers.into(), writers_place.into()) -} From bb06a0cf0e60ef09782a41b76d5204498355193a Mon Sep 17 00:00:00 2001 From: David Cook Date: Sat, 28 Mar 2020 09:35:51 -0500 Subject: [PATCH 1805/3747] Restrict mutex static initializer test to Linux On macOS, libc does not have a static initializer for recursive mutexes --- tests/run-pass/sync.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/tests/run-pass/sync.rs b/tests/run-pass/sync.rs index 025ae81372cf8..24d7b0be53420 100644 --- a/tests/run-pass/sync.rs +++ b/tests/run-pass/sync.rs @@ -10,10 +10,13 @@ fn main() { { test_mutex_libc_init_recursive(); test_mutex_libc_init_normal(); - test_mutex_libc_static_initializer_recursive(); test_rwlock_stdlib(); test_rwlock_libc_static_initializer(); } + #[cfg(target_os = "linux")] + { + test_mutex_libc_static_initializer_recursive(); + } } fn test_mutex_stdlib() { @@ -64,7 +67,7 @@ fn test_mutex_libc_init_normal() { } } -#[cfg(not(target_os = "windows"))] +#[cfg(target_os = "linux")] fn test_mutex_libc_static_initializer_recursive() { let mutex = std::cell::UnsafeCell::new(libc::PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP); unsafe { From 37ddde9f70237a05dfdfb0aba837b8704a5dc7d0 Mon Sep 17 00:00:00 2001 From: David Cook Date: Sat, 28 Mar 2020 10:16:08 -0500 Subject: [PATCH 1806/3747] Implement TryEnterCriticalSection --- src/shims/foreign_items/windows.rs | 5 +++++ tests/run-pass/sync.rs | 3 ++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/shims/foreign_items/windows.rs b/src/shims/foreign_items/windows.rs index cfc94bfd9b71d..3c819fddc410a 100644 --- a/src/shims/foreign_items/windows.rs +++ b/src/shims/foreign_items/windows.rs @@ -233,6 +233,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // (Windows locks are reentrant, and we have only 1 thread, // so not doing any futher checks here is at least not incorrect.) } + "TryEnterCriticalSection" if this.frame().instance.to_string().starts_with("std::sys::windows::") + => { + // There is only one thread, so this always succeeds and returns TRUE + this.write_scalar(Scalar::from_int(1, dest.layout.size), dest)?; + } _ => throw_unsup_format!("can't call foreign function: {}", link_name), } diff --git a/tests/run-pass/sync.rs b/tests/run-pass/sync.rs index 24d7b0be53420..0ddf429fad9c6 100644 --- a/tests/run-pass/sync.rs +++ b/tests/run-pass/sync.rs @@ -1,6 +1,6 @@ #![feature(rustc_private)] -use std::sync::{Mutex, RwLock, TryLockError}; +use std::sync::{Mutex, TryLockError}; extern crate libc; @@ -86,6 +86,7 @@ fn test_mutex_libc_static_initializer_recursive() { #[cfg(not(target_os = "windows"))] fn test_rwlock_stdlib() { + use std::sync::RwLock; let rw = RwLock::new(0); { let _read_guard = rw.read().unwrap(); From e1a1592991e0432c1e591e92e274f9943e690e3f Mon Sep 17 00:00:00 2001 From: David Cook Date: Sat, 28 Mar 2020 10:58:36 -0500 Subject: [PATCH 1807/3747] Set some explicit return value sizes --- src/shims/foreign_items/posix.rs | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/shims/foreign_items/posix.rs b/src/shims/foreign_items/posix.rs index 2b9e94ba11db4..fbf8a3b9504fb 100644 --- a/src/shims/foreign_items/posix.rs +++ b/src/shims/foreign_items/posix.rs @@ -272,72 +272,72 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "pthread_mutexattr_init" => { let result = this.pthread_mutexattr_init(args[0])?; - this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_mutexattr_settype" => { let result = this.pthread_mutexattr_settype(args[0], args[1])?; - this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_mutexattr_destroy" => { let result = this.pthread_mutexattr_destroy(args[0])?; - this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_mutex_init" => { let result = this.pthread_mutex_init(args[0], args[1])?; - this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_mutex_lock" => { let result = this.pthread_mutex_lock(args[0])?; - this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_mutex_trylock" => { let result = this.pthread_mutex_trylock(args[0])?; - this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_mutex_unlock" => { let result = this.pthread_mutex_unlock(args[0])?; - this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_mutex_destroy" => { let result = this.pthread_mutex_destroy(args[0])?; - this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_rwlock_rdlock" => { let result = this.pthread_rwlock_rdlock(args[0])?; - this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_rwlock_tryrdlock" => { let result = this.pthread_rwlock_tryrdlock(args[0])?; - this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_rwlock_wrlock" => { let result = this.pthread_rwlock_wrlock(args[0])?; - this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_rwlock_trywrlock" => { let result = this.pthread_rwlock_trywrlock(args[0])?; - this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_rwlock_unlock" => { let result = this.pthread_rwlock_unlock(args[0])?; - this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_rwlock_destroy" => { let result = this.pthread_rwlock_destroy(args[0])?; - this.write_scalar(Scalar::from_int(result, dest.layout.size), dest)?; + this.write_scalar(Scalar::from_i32(result), dest)?; } | "signal" From 8293d80b53a60121961027c3ba8e29823b153179 Mon Sep 17 00:00:00 2001 From: David Cook Date: Sat, 28 Mar 2020 11:14:50 -0500 Subject: [PATCH 1808/3747] Set explicit return value size for windows shim --- src/shims/foreign_items/windows.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shims/foreign_items/windows.rs b/src/shims/foreign_items/windows.rs index 3c819fddc410a..443d44fae1c3a 100644 --- a/src/shims/foreign_items/windows.rs +++ b/src/shims/foreign_items/windows.rs @@ -236,7 +236,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "TryEnterCriticalSection" if this.frame().instance.to_string().starts_with("std::sys::windows::") => { // There is only one thread, so this always succeeds and returns TRUE - this.write_scalar(Scalar::from_int(1, dest.layout.size), dest)?; + this.write_scalar(Scalar::from_i32(1), dest)?; } _ => throw_unsup_format!("can't call foreign function: {}", link_name), From ac8c98da8e806a7e18dcc0cee8201085e5c7abb6 Mon Sep 17 00:00:00 2001 From: David Cook Date: Sun, 29 Mar 2020 01:38:34 -0500 Subject: [PATCH 1809/3747] Store layouts of i32 and u32 inside Evaluator --- src/lib.rs | 5 +++-- src/machine.rs | 53 ++++++++++++++++++++++++++++++++++++++++++++++- src/shims/sync.rs | 42 ++++++++++++++++++------------------- 3 files changed, 75 insertions(+), 25 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 2f381b4a34546..82ac2e8d21883 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -51,8 +51,9 @@ pub use crate::diagnostics::{ pub use crate::eval::{create_ecx, eval_main, MiriConfig}; pub use crate::helpers::EvalContextExt as HelpersEvalContextExt; pub use crate::machine::{ - AllocExtra, Evaluator, FrameData, MemoryExtra, MiriEvalContext, MiriEvalContextExt, - MiriMemoryKind, NUM_CPUS, PAGE_SIZE, STACK_ADDR, STACK_SIZE, + AllocExtra, EvalContextExt as MachineEvalContextExt, Evaluator, FrameData, MemoryExtra, + MiriEvalContext, MiriEvalContextExt, MiriMemoryKind, NUM_CPUS, PAGE_SIZE, STACK_ADDR, + STACK_SIZE, }; pub use crate::mono_hash_map::MonoHashMap; pub use crate::operator::EvalContextExt as OperatorEvalContextExt; diff --git a/src/machine.rs b/src/machine.rs index f794453228b84..a60ae8a4be21c 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -11,7 +11,7 @@ use log::trace; use rand::rngs::StdRng; use rustc_data_structures::fx::FxHashMap; -use rustc_middle::{mir, ty}; +use rustc_middle::{mir, ty::{self, layout::TyAndLayout}}; use rustc_target::abi::{LayoutOf, Size}; use rustc_ast::attr; use rustc_span::symbol::{sym, Symbol}; @@ -146,6 +146,39 @@ impl MemoryExtra { } } +/// Cached layouts of primitive types +#[derive(Default)] +struct PrimitiveLayouts<'tcx> { + i32: RefCell>>, + u32: RefCell>>, +} + +impl<'mir, 'tcx: 'mir> PrimitiveLayouts<'tcx> { + fn i32(&self, ecx: &MiriEvalContext<'mir, 'tcx>) -> InterpResult<'tcx, TyAndLayout<'tcx>> { + { + let layout_ref = self.i32.borrow(); + if layout_ref.is_some() { + return Ok(layout_ref.unwrap()); + } + } + let layout = ecx.layout_of(ecx.tcx.types.i32)?; + *self.i32.borrow_mut() = Some(layout); + Ok(layout) + } + + fn u32(&self, ecx: &MiriEvalContext<'mir, 'tcx>) -> InterpResult<'tcx, TyAndLayout<'tcx>> { + { + let layout_ref = self.u32.borrow(); + if layout_ref.is_some() { + return Ok(layout_ref.unwrap()); + } + } + let layout = ecx.layout_of(ecx.tcx.types.u32)?; + *self.u32.borrow_mut() = Some(layout); + Ok(layout) + } +} + /// The machine itself. pub struct Evaluator<'tcx> { /// Environment variables set by `setenv`. @@ -182,6 +215,9 @@ pub struct Evaluator<'tcx> { /// The "time anchor" for this machine's monotone clock (for `Instant` simulation). pub(crate) time_anchor: Instant, + + /// Cached `TyLayout`s for primitive data types that are commonly used inside Miri. + primitive_layouts: PrimitiveLayouts<'tcx>, } impl<'tcx> Evaluator<'tcx> { @@ -201,6 +237,7 @@ impl<'tcx> Evaluator<'tcx> { dir_handler: Default::default(), panic_payload: None, time_anchor: Instant::now(), + primitive_layouts: PrimitiveLayouts::default(), } } } @@ -224,6 +261,20 @@ impl<'mir, 'tcx> MiriEvalContextExt<'mir, 'tcx> for MiriEvalContext<'mir, 'tcx> } } +impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for MiriEvalContext<'mir, 'tcx> {} +/// Provides convenience methods for use elsewhere +pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { + fn i32_layout(&self) -> InterpResult<'tcx, TyAndLayout<'tcx>> { + let this = self.eval_context_ref(); + this.machine.primitive_layouts.i32(this) + } + + fn u32_layout(&self) -> InterpResult<'tcx, TyAndLayout<'tcx>> { + let this = self.eval_context_ref(); + this.machine.primitive_layouts.u32(this) + } +} + /// Machine hook implementations. impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { type MemoryKind = MiriMemoryKind; diff --git a/src/shims/sync.rs b/src/shims/sync.rs index 4e4f8c112e533..eac2053493a8c 100644 --- a/src/shims/sync.rs +++ b/src/shims/sync.rs @@ -30,8 +30,7 @@ fn mutexattr_get_kind<'mir, 'tcx: 'mir>( // Ensure that the following read at an offset to the attr pointer is within bounds assert_ptr_target_min_size(ecx, attr_op, 4)?; let attr_place = ecx.deref_operand(attr_op)?; - let i32_layout = ecx.layout_of(ecx.tcx.types.i32)?; - let kind_place = attr_place.offset(Size::ZERO, MemPlaceMeta::None, i32_layout, ecx)?; + let kind_place = attr_place.offset(Size::ZERO, MemPlaceMeta::None, ecx.i32_layout()?, ecx)?; ecx.read_scalar(kind_place.into()) } @@ -43,8 +42,7 @@ fn mutexattr_set_kind<'mir, 'tcx: 'mir>( // Ensure that the following write at an offset to the attr pointer is within bounds assert_ptr_target_min_size(ecx, attr_op, 4)?; let attr_place = ecx.deref_operand(attr_op)?; - let i32_layout = ecx.layout_of(ecx.tcx.types.i32)?; - let kind_place = attr_place.offset(Size::ZERO, MemPlaceMeta::None, i32_layout, ecx)?; + let kind_place = attr_place.offset(Size::ZERO, MemPlaceMeta::None, ecx.i32_layout()?, ecx)?; ecx.write_scalar(kind.into(), kind_place.into()) } @@ -64,9 +62,8 @@ fn mutex_get_locked_count<'mir, 'tcx: 'mir>( // Ensure that the following read at an offset to the mutex pointer is within bounds assert_ptr_target_min_size(ecx, mutex_op, 20)?; let mutex_place = ecx.deref_operand(mutex_op)?; - let u32_layout = ecx.layout_of(ecx.tcx.types.u32)?; let locked_count_place = - mutex_place.offset(Size::from_bytes(4), MemPlaceMeta::None, u32_layout, ecx)?; + mutex_place.offset(Size::from_bytes(4), MemPlaceMeta::None, ecx.u32_layout()?, ecx)?; ecx.read_scalar(locked_count_place.into()) } @@ -78,9 +75,8 @@ fn mutex_set_locked_count<'mir, 'tcx: 'mir>( // Ensure that the following write at an offset to the mutex pointer is within bounds assert_ptr_target_min_size(ecx, mutex_op, 20)?; let mutex_place = ecx.deref_operand(mutex_op)?; - let u32_layout = ecx.layout_of(ecx.tcx.types.u32)?; let locked_count_place = - mutex_place.offset(Size::from_bytes(4), MemPlaceMeta::None, u32_layout, ecx)?; + mutex_place.offset(Size::from_bytes(4), MemPlaceMeta::None, ecx.u32_layout()?, ecx)?; ecx.write_scalar(locked_count.into(), locked_count_place.into()) } @@ -91,10 +87,13 @@ fn mutex_get_kind<'mir, 'tcx: 'mir>( // Ensure that the following read at an offset to the mutex pointer is within bounds assert_ptr_target_min_size(ecx, mutex_op, 20)?; let mutex_place = ecx.deref_operand(mutex_op)?; - let i32_layout = ecx.layout_of(ecx.tcx.types.i32)?; let kind_offset = if ecx.pointer_size().bytes() == 8 { 16 } else { 12 }; - let kind_place = - mutex_place.offset(Size::from_bytes(kind_offset), MemPlaceMeta::None, i32_layout, ecx)?; + let kind_place = mutex_place.offset( + Size::from_bytes(kind_offset), + MemPlaceMeta::None, + ecx.i32_layout()?, + ecx, + )?; ecx.read_scalar(kind_place.into()) } @@ -106,10 +105,13 @@ fn mutex_set_kind<'mir, 'tcx: 'mir>( // Ensure that the following write at an offset to the mutex pointer is within bounds assert_ptr_target_min_size(ecx, mutex_op, 20)?; let mutex_place = ecx.deref_operand(mutex_op)?; - let i32_layout = ecx.layout_of(ecx.tcx.types.i32)?; let kind_offset = if ecx.pointer_size().bytes() == 8 { 16 } else { 12 }; - let kind_place = - mutex_place.offset(Size::from_bytes(kind_offset), MemPlaceMeta::None, i32_layout, ecx)?; + let kind_place = mutex_place.offset( + Size::from_bytes(kind_offset), + MemPlaceMeta::None, + ecx.i32_layout()?, + ecx, + )?; ecx.write_scalar(kind.into(), kind_place.into()) } @@ -128,9 +130,8 @@ fn rwlock_get_readers<'mir, 'tcx: 'mir>( // Ensure that the following read at an offset to the rwlock pointer is within bounds assert_ptr_target_min_size(ecx, rwlock_op, 12)?; let rwlock_place = ecx.deref_operand(rwlock_op)?; - let u32_layout = ecx.layout_of(ecx.tcx.types.u32)?; let readers_place = - rwlock_place.offset(Size::from_bytes(4), MemPlaceMeta::None, u32_layout, ecx)?; + rwlock_place.offset(Size::from_bytes(4), MemPlaceMeta::None, ecx.u32_layout()?, ecx)?; ecx.read_scalar(readers_place.into()) } @@ -142,9 +143,8 @@ fn rwlock_set_readers<'mir, 'tcx: 'mir>( // Ensure that the following write at an offset to the rwlock pointer is within bounds assert_ptr_target_min_size(ecx, rwlock_op, 12)?; let rwlock_place = ecx.deref_operand(rwlock_op)?; - let u32_layout = ecx.layout_of(ecx.tcx.types.u32)?; let readers_place = - rwlock_place.offset(Size::from_bytes(4), MemPlaceMeta::None, u32_layout, ecx)?; + rwlock_place.offset(Size::from_bytes(4), MemPlaceMeta::None, ecx.u32_layout()?, ecx)?; ecx.write_scalar(readers.into(), readers_place.into()) } @@ -155,9 +155,8 @@ fn rwlock_get_writers<'mir, 'tcx: 'mir>( // Ensure that the following read at an offset to the rwlock pointer is within bounds assert_ptr_target_min_size(ecx, rwlock_op, 12)?; let rwlock_place = ecx.deref_operand(rwlock_op)?; - let u32_layout = ecx.layout_of(ecx.tcx.types.u32)?; let writers_place = - rwlock_place.offset(Size::from_bytes(8), MemPlaceMeta::None, u32_layout, ecx)?; + rwlock_place.offset(Size::from_bytes(8), MemPlaceMeta::None, ecx.u32_layout()?, ecx)?; ecx.read_scalar(writers_place.into()) } @@ -169,9 +168,8 @@ fn rwlock_set_writers<'mir, 'tcx: 'mir>( // Ensure that the following write at an offset to the rwlock pointer is within bounds assert_ptr_target_min_size(ecx, rwlock_op, 12)?; let rwlock_place = ecx.deref_operand(rwlock_op)?; - let u32_layout = ecx.layout_of(ecx.tcx.types.u32)?; let writers_place = - rwlock_place.offset(Size::from_bytes(8), MemPlaceMeta::None, u32_layout, ecx)?; + rwlock_place.offset(Size::from_bytes(8), MemPlaceMeta::None, ecx.u32_layout()?, ecx)?; ecx.write_scalar(writers.into(), writers_place.into()) } From b8444deb64b1175152c98bd772a3fd445a77ac6e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 23 Mar 2020 13:02:02 +0100 Subject: [PATCH 1810/3747] test Vec::extend --- tests/run-pass/{vecs.rs => vec.rs} | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) rename tests/run-pass/{vecs.rs => vec.rs} (73%) diff --git a/tests/run-pass/vecs.rs b/tests/run-pass/vec.rs similarity index 73% rename from tests/run-pass/vecs.rs rename to tests/run-pass/vec.rs index 739def804975d..a2f448496fd9a 100644 --- a/tests/run-pass/vecs.rs +++ b/tests/run-pass/vec.rs @@ -71,6 +71,26 @@ fn vec_reallocate() -> Vec { v } +fn vec_push_ptr_stable() { + let mut v = Vec::with_capacity(10); + v.push(0); + let v0 = unsafe { &*(&v[0] as *const _) }; // laundering the lifetime -- we take care that `v` does not reallocate, so that's okay. + v.push(1); + let _val = *v0; +} + +fn vec_extend_ptr_stable() { + let mut v = Vec::with_capacity(10); + v.push(0); + let v0 = unsafe { &*(&v[0] as *const _) }; // laundering the lifetime -- we take care that `v` does not reallocate, so that's okay. + v.extend(&[1]); + let _val = *v0; + v.extend(vec![2]); + let _val = *v0; + v.extend(std::iter::once(3)); + let _val = *v0; +} + fn main() { assert_eq!(vec_reallocate().len(), 5); @@ -89,4 +109,7 @@ fn main() { // Test interesting empty slice comparison // (one is a real pointer, one an integer pointer). assert_eq!((200..-5).step_by(1).collect::>(), []); + + vec_push_ptr_stable(); + vec_extend_ptr_stable(); } From 9159b1eef891d35c5153b6e4027a1dd7d158e61b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 30 Mar 2020 10:41:44 +0200 Subject: [PATCH 1811/3747] test some more vec ptr invalidation --- tests/run-pass/vec.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/tests/run-pass/vec.rs b/tests/run-pass/vec.rs index a2f448496fd9a..5304e3ed71a8e 100644 --- a/tests/run-pass/vec.rs +++ b/tests/run-pass/vec.rs @@ -83,12 +83,25 @@ fn vec_extend_ptr_stable() { let mut v = Vec::with_capacity(10); v.push(0); let v0 = unsafe { &*(&v[0] as *const _) }; // laundering the lifetime -- we take care that `v` does not reallocate, so that's okay. + // `slice::Iter` (with `T: Copy`) specialization v.extend(&[1]); let _val = *v0; + // `vec::IntoIter` specialization v.extend(vec![2]); let _val = *v0; + // `TrustedLen` specialization v.extend(std::iter::once(3)); let _val = *v0; + // base case + v.extend(std::iter::once(3).filter(|_| true)); + let _val = *v0; +} + +fn vec_truncate_ptr_stable() { + let mut v = vec![0; 10]; + let v0 = unsafe { &*(&v[0] as *const _) }; // laundering the lifetime -- we take care that `v` does not reallocate, so that's okay. + v.truncate(5); + let _val = *v0; } fn main() { @@ -112,4 +125,5 @@ fn main() { vec_push_ptr_stable(); vec_extend_ptr_stable(); + vec_truncate_ptr_stable(); } From ab32084ddbe1a28c3e58ab80acdb62bb520eaf6f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 30 Mar 2020 13:27:59 +0200 Subject: [PATCH 1812/3747] use mutable reference --- tests/run-pass/vec.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/run-pass/vec.rs b/tests/run-pass/vec.rs index 5304e3ed71a8e..954cd6a1557ae 100644 --- a/tests/run-pass/vec.rs +++ b/tests/run-pass/vec.rs @@ -74,7 +74,7 @@ fn vec_reallocate() -> Vec { fn vec_push_ptr_stable() { let mut v = Vec::with_capacity(10); v.push(0); - let v0 = unsafe { &*(&v[0] as *const _) }; // laundering the lifetime -- we take care that `v` does not reallocate, so that's okay. + let v0 = unsafe { &mut *(&mut v[0] as *mut _) }; // laundering the lifetime -- we take care that `v` does not reallocate, so that's okay. v.push(1); let _val = *v0; } @@ -82,7 +82,7 @@ fn vec_push_ptr_stable() { fn vec_extend_ptr_stable() { let mut v = Vec::with_capacity(10); v.push(0); - let v0 = unsafe { &*(&v[0] as *const _) }; // laundering the lifetime -- we take care that `v` does not reallocate, so that's okay. + let v0 = unsafe { &mut *(&mut v[0] as *mut _) }; // laundering the lifetime -- we take care that `v` does not reallocate, so that's okay. // `slice::Iter` (with `T: Copy`) specialization v.extend(&[1]); let _val = *v0; @@ -99,7 +99,7 @@ fn vec_extend_ptr_stable() { fn vec_truncate_ptr_stable() { let mut v = vec![0; 10]; - let v0 = unsafe { &*(&v[0] as *const _) }; // laundering the lifetime -- we take care that `v` does not reallocate, so that's okay. + let v0 = unsafe { &mut *(&mut v[0] as *mut _) }; // laundering the lifetime -- we take care that `v` does not reallocate, so that's okay. v.truncate(5); let _val = *v0; } From 41abcdb42262ec49495838eac38dbe2e9cd0a3ba Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 30 Mar 2020 13:39:04 +0200 Subject: [PATCH 1813/3747] for consistency also rename floats.rs --- tests/run-pass/{floats.rs => float.rs} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename tests/run-pass/{floats.rs => float.rs} (100%) diff --git a/tests/run-pass/floats.rs b/tests/run-pass/float.rs similarity index 100% rename from tests/run-pass/floats.rs rename to tests/run-pass/float.rs From 3eb76f4a77d68f3f84e264fe51725e7b66256ec3 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 5 Apr 2020 18:28:05 +0200 Subject: [PATCH 1814/3747] rustup --- rust-version | 2 +- tests/run-pass/vec.rs | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 895cbb5fa9a01..6e980a4e228eb 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -6050e523bae6de61de4e060facc43dc512adaccd +e6cef0445779724b469ab7b9a8d3c05d9e848ca8 diff --git a/tests/run-pass/vec.rs b/tests/run-pass/vec.rs index 954cd6a1557ae..5c791e4db0a77 100644 --- a/tests/run-pass/vec.rs +++ b/tests/run-pass/vec.rs @@ -123,6 +123,7 @@ fn main() { // (one is a real pointer, one an integer pointer). assert_eq!((200..-5).step_by(1).collect::>(), []); + // liballoc has a more extensive test of this, but let's at least do a smoke test here. vec_push_ptr_stable(); vec_extend_ptr_stable(); vec_truncate_ptr_stable(); From 79f3307f308ac1d9304437509db0f8a4a295d63b Mon Sep 17 00:00:00 2001 From: David Cook Date: Sun, 5 Apr 2020 12:09:31 -0500 Subject: [PATCH 1815/3747] Update comments, rearrange code --- src/machine.rs | 2 + src/shims/foreign_items/posix.rs | 88 +++++++++++++---------------- src/shims/sync.rs | 9 +-- tests/run-pass/libc.rs | 85 ++++++++++++++++++++++++++++ tests/run-pass/reentrant-println.rs | 2 +- tests/run-pass/sync.rs | 88 ----------------------------- 6 files changed, 131 insertions(+), 143 deletions(-) diff --git a/src/machine.rs b/src/machine.rs index a60ae8a4be21c..bfb832085e0bf 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -217,6 +217,8 @@ pub struct Evaluator<'tcx> { pub(crate) time_anchor: Instant, /// Cached `TyLayout`s for primitive data types that are commonly used inside Miri. + /// FIXME: Search through the rest of the codebase for more layout_of() calls that + /// could be cached here. primitive_layouts: PrimitiveLayouts<'tcx>, } diff --git a/src/shims/foreign_items/posix.rs b/src/shims/foreign_items/posix.rs index fbf8a3b9504fb..3ececb9c20bbd 100644 --- a/src/shims/foreign_items/posix.rs +++ b/src/shims/foreign_items/posix.rs @@ -233,113 +233,101 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_null(dest)?; } - // Better error for attempts to create a thread - "pthread_create" => { - throw_unsup_format!("Miri does not support threading"); - } - - // Miscellaneous - "isatty" => { - let _fd = this.read_scalar(args[0])?.to_i32()?; - // "returns 1 if fd is an open file descriptor referring to a terminal; otherwise 0 is returned, and errno is set to indicate the error" - // FIXME: we just say nothing is a terminal. - let enotty = this.eval_libc("ENOTTY")?; - this.set_last_error(enotty)?; - this.write_null(dest)?; - } - "pthread_atfork" => { - let _prepare = this.read_scalar(args[0])?.not_undef()?; - let _parent = this.read_scalar(args[1])?.not_undef()?; - let _child = this.read_scalar(args[1])?.not_undef()?; - // We do not support forking, so there is nothing to do here. - this.write_null(dest)?; - } - - // Incomplete shims that we "stub out" just to get pre-main initialization code to work. - // These shims are enabled only when the caller is in the standard library. - | "pthread_attr_init" - | "pthread_attr_destroy" - | "pthread_self" - | "pthread_attr_setstacksize" - | "pthread_condattr_init" - | "pthread_condattr_setclock" - | "pthread_cond_init" - | "pthread_condattr_destroy" - | "pthread_cond_destroy" if this.frame().instance.to_string().starts_with("std::sys::unix::") - => { - this.write_null(dest)?; - } - + // Synchronization primitives "pthread_mutexattr_init" => { let result = this.pthread_mutexattr_init(args[0])?; this.write_scalar(Scalar::from_i32(result), dest)?; } - "pthread_mutexattr_settype" => { let result = this.pthread_mutexattr_settype(args[0], args[1])?; this.write_scalar(Scalar::from_i32(result), dest)?; } - "pthread_mutexattr_destroy" => { let result = this.pthread_mutexattr_destroy(args[0])?; this.write_scalar(Scalar::from_i32(result), dest)?; } - "pthread_mutex_init" => { let result = this.pthread_mutex_init(args[0], args[1])?; this.write_scalar(Scalar::from_i32(result), dest)?; } - "pthread_mutex_lock" => { let result = this.pthread_mutex_lock(args[0])?; this.write_scalar(Scalar::from_i32(result), dest)?; } - "pthread_mutex_trylock" => { let result = this.pthread_mutex_trylock(args[0])?; this.write_scalar(Scalar::from_i32(result), dest)?; } - "pthread_mutex_unlock" => { let result = this.pthread_mutex_unlock(args[0])?; this.write_scalar(Scalar::from_i32(result), dest)?; } - "pthread_mutex_destroy" => { let result = this.pthread_mutex_destroy(args[0])?; this.write_scalar(Scalar::from_i32(result), dest)?; } - "pthread_rwlock_rdlock" => { let result = this.pthread_rwlock_rdlock(args[0])?; this.write_scalar(Scalar::from_i32(result), dest)?; } - "pthread_rwlock_tryrdlock" => { let result = this.pthread_rwlock_tryrdlock(args[0])?; this.write_scalar(Scalar::from_i32(result), dest)?; } - "pthread_rwlock_wrlock" => { let result = this.pthread_rwlock_wrlock(args[0])?; this.write_scalar(Scalar::from_i32(result), dest)?; } - "pthread_rwlock_trywrlock" => { let result = this.pthread_rwlock_trywrlock(args[0])?; this.write_scalar(Scalar::from_i32(result), dest)?; } - "pthread_rwlock_unlock" => { let result = this.pthread_rwlock_unlock(args[0])?; this.write_scalar(Scalar::from_i32(result), dest)?; } - "pthread_rwlock_destroy" => { let result = this.pthread_rwlock_destroy(args[0])?; this.write_scalar(Scalar::from_i32(result), dest)?; } + // Better error for attempts to create a thread + "pthread_create" => { + throw_unsup_format!("Miri does not support threading"); + } + + // Miscellaneous + "isatty" => { + let _fd = this.read_scalar(args[0])?.to_i32()?; + // "returns 1 if fd is an open file descriptor referring to a terminal; otherwise 0 is returned, and errno is set to indicate the error" + // FIXME: we just say nothing is a terminal. + let enotty = this.eval_libc("ENOTTY")?; + this.set_last_error(enotty)?; + this.write_null(dest)?; + } + "pthread_atfork" => { + let _prepare = this.read_scalar(args[0])?.not_undef()?; + let _parent = this.read_scalar(args[1])?.not_undef()?; + let _child = this.read_scalar(args[1])?.not_undef()?; + // We do not support forking, so there is nothing to do here. + this.write_null(dest)?; + } + + // Incomplete shims that we "stub out" just to get pre-main initialization code to work. + // These shims are enabled only when the caller is in the standard library. + | "pthread_attr_init" + | "pthread_attr_destroy" + | "pthread_self" + | "pthread_attr_setstacksize" + | "pthread_condattr_init" + | "pthread_condattr_setclock" + | "pthread_cond_init" + | "pthread_condattr_destroy" + | "pthread_cond_destroy" if this.frame().instance.to_string().starts_with("std::sys::unix::") + => { + this.write_null(dest)?; + } + | "signal" | "sigaction" | "sigaltstack" diff --git a/src/shims/sync.rs b/src/shims/sync.rs index eac2053493a8c..c2ea02af5b668 100644 --- a/src/shims/sync.rs +++ b/src/shims/sync.rs @@ -20,8 +20,9 @@ fn assert_ptr_target_min_size<'mir, 'tcx: 'mir>( // pthread_mutexattr_t is either 4 or 8 bytes, depending on the platform. -// Our chosen memory layout: store an i32 in the first four bytes equal to the -// corresponding libc mutex kind constant (i.e. PTHREAD_MUTEX_NORMAL) +// Our chosen memory layout for emulation (does not have to match the platform layout!): +// store an i32 in the first four bytes equal to the corresponding libc mutex kind constant +// (e.g. PTHREAD_MUTEX_NORMAL). fn mutexattr_get_kind<'mir, 'tcx: 'mir>( ecx: &MiriEvalContext<'mir, 'tcx>, @@ -48,7 +49,7 @@ fn mutexattr_set_kind<'mir, 'tcx: 'mir>( // pthread_mutex_t is between 24 and 48 bytes, depending on the platform. -// Our chosen memory layout: +// Our chosen memory layout for the emulated mutex (does not have to match the platform layout!): // bytes 0-3: reserved for signature on macOS // (need to avoid this because it is set by static initializer macros) // bytes 4-7: count of how many times this mutex has been locked, as a u32 @@ -117,7 +118,7 @@ fn mutex_set_kind<'mir, 'tcx: 'mir>( // pthread_rwlock_t is between 32 and 56 bytes, depending on the platform. -// Our chosen memory layout: +// Our chosen memory layout for the emulated rwlock (does not have to match the platform layout!): // bytes 0-3: reserved for signature on macOS // (need to avoid this because it is set by static initializer macros) // bytes 4-7: reader count, as a u32 diff --git a/tests/run-pass/libc.rs b/tests/run-pass/libc.rs index 064c00e81bb86..7ea793089d2f2 100644 --- a/tests/run-pass/libc.rs +++ b/tests/run-pass/libc.rs @@ -42,7 +42,92 @@ fn test_posix_fadvise() { assert_eq!(result, 0); } +fn test_mutex_libc_init_recursive() { + unsafe { + let mut attr: libc::pthread_mutexattr_t = std::mem::zeroed(); + assert_eq!(libc::pthread_mutexattr_init(&mut attr as *mut _), 0); + assert_eq!(libc::pthread_mutexattr_settype(&mut attr as *mut _, libc::PTHREAD_MUTEX_RECURSIVE), 0); + let mut mutex: libc::pthread_mutex_t = std::mem::zeroed(); + assert_eq!(libc::pthread_mutex_init(&mut mutex as *mut _, &mut attr as *mut _), 0); + assert_eq!(libc::pthread_mutex_lock(&mut mutex as *mut _), 0); + assert_eq!(libc::pthread_mutex_trylock(&mut mutex as *mut _), 0); + assert_eq!(libc::pthread_mutex_unlock(&mut mutex as *mut _), 0); + assert_eq!(libc::pthread_mutex_unlock(&mut mutex as *mut _), 0); + assert_eq!(libc::pthread_mutex_trylock(&mut mutex as *mut _), 0); + assert_eq!(libc::pthread_mutex_lock(&mut mutex as *mut _), 0); + assert_eq!(libc::pthread_mutex_unlock(&mut mutex as *mut _), 0); + assert_eq!(libc::pthread_mutex_unlock(&mut mutex as *mut _), 0); + assert_eq!(libc::pthread_mutex_unlock(&mut mutex as *mut _), libc::EPERM); + assert_eq!(libc::pthread_mutex_destroy(&mut mutex as *mut _), 0); + assert_eq!(libc::pthread_mutexattr_destroy(&mut attr as *mut _), 0); + } +} + +fn test_mutex_libc_init_normal() { + unsafe { + let mut mutexattr: libc::pthread_mutexattr_t = std::mem::zeroed(); + assert_eq!(libc::pthread_mutexattr_settype(&mut mutexattr as *mut _, libc::PTHREAD_MUTEX_NORMAL), 0); + let mut mutex: libc::pthread_mutex_t = std::mem::zeroed(); + assert_eq!(libc::pthread_mutex_init(&mut mutex as *mut _, &mutexattr as *const _), 0); + assert_eq!(libc::pthread_mutex_lock(&mut mutex as *mut _), 0); + assert_eq!(libc::pthread_mutex_trylock(&mut mutex as *mut _), libc::EBUSY); + assert_eq!(libc::pthread_mutex_unlock(&mut mutex as *mut _), 0); + assert_eq!(libc::pthread_mutex_trylock(&mut mutex as *mut _), 0); + assert_eq!(libc::pthread_mutex_unlock(&mut mutex as *mut _), 0); + assert_eq!(libc::pthread_mutex_destroy(&mut mutex as *mut _), 0); + } +} + +// Only linux provides PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP, +// libc for macOS just has the default PTHREAD_MUTEX_INITIALIZER. +#[cfg(target_os = "linux")] +fn test_mutex_libc_static_initializer_recursive() { + let mutex = std::cell::UnsafeCell::new(libc::PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP); + unsafe { + assert_eq!(libc::pthread_mutex_lock(mutex.get()), 0); + assert_eq!(libc::pthread_mutex_trylock(mutex.get()), 0); + assert_eq!(libc::pthread_mutex_unlock(mutex.get()), 0); + assert_eq!(libc::pthread_mutex_unlock(mutex.get()), 0); + assert_eq!(libc::pthread_mutex_trylock(mutex.get()), 0); + assert_eq!(libc::pthread_mutex_lock(mutex.get()), 0); + assert_eq!(libc::pthread_mutex_unlock(mutex.get()), 0); + assert_eq!(libc::pthread_mutex_unlock(mutex.get()), 0); + assert_eq!(libc::pthread_mutex_unlock(mutex.get()), libc::EPERM); + assert_eq!(libc::pthread_mutex_destroy(mutex.get()), 0); + } +} + +// Testing the behavior of std::sync::RwLock does not fully exercise the pthread rwlock shims, we +// need to go a layer deeper and test the behavior of the libc functions, because +// std::sys::unix::rwlock::RWLock itself keeps track of write_locked and num_readers. +fn test_rwlock_libc_static_initializer() { + let rw = std::cell::UnsafeCell::new(libc::PTHREAD_RWLOCK_INITIALIZER); + unsafe { + assert_eq!(libc::pthread_rwlock_rdlock(rw.get()), 0); + assert_eq!(libc::pthread_rwlock_rdlock(rw.get()), 0); + assert_eq!(libc::pthread_rwlock_unlock(rw.get()), 0); + assert_eq!(libc::pthread_rwlock_tryrdlock(rw.get()), 0); + assert_eq!(libc::pthread_rwlock_unlock(rw.get()), 0); + assert_eq!(libc::pthread_rwlock_trywrlock(rw.get()), libc::EBUSY); + assert_eq!(libc::pthread_rwlock_unlock(rw.get()), 0); + + assert_eq!(libc::pthread_rwlock_wrlock(rw.get()), 0); + assert_eq!(libc::pthread_rwlock_tryrdlock(rw.get()), libc::EBUSY); + assert_eq!(libc::pthread_rwlock_trywrlock(rw.get()), libc::EBUSY); + assert_eq!(libc::pthread_rwlock_unlock(rw.get()), 0); + + assert_eq!(libc::pthread_rwlock_destroy(rw.get()), 0); + } +} + fn main() { #[cfg(not(target_os = "macos"))] test_posix_fadvise(); + + test_mutex_libc_init_recursive(); + test_mutex_libc_init_normal(); + test_rwlock_libc_static_initializer(); + + #[cfg(target_os = "linux")] + test_mutex_libc_static_initializer_recursive(); } diff --git a/tests/run-pass/reentrant-println.rs b/tests/run-pass/reentrant-println.rs index 09c4fc3f74d3e..e73e82b8ec9ed 100644 --- a/tests/run-pass/reentrant-println.rs +++ b/tests/run-pass/reentrant-println.rs @@ -1,7 +1,7 @@ use std::fmt::{Display, Error, Formatter}; // This test case exercises std::sys_common::remutex::ReentrantMutex -// by calling println!() from inside fmt +// by calling println!() from inside fmt. struct InterruptingCow; diff --git a/tests/run-pass/sync.rs b/tests/run-pass/sync.rs index 0ddf429fad9c6..1ede5d42bb4ba 100644 --- a/tests/run-pass/sync.rs +++ b/tests/run-pass/sync.rs @@ -2,20 +2,11 @@ use std::sync::{Mutex, TryLockError}; -extern crate libc; - fn main() { test_mutex_stdlib(); #[cfg(not(target_os = "windows"))] // TODO: implement RwLock on Windows { - test_mutex_libc_init_recursive(); - test_mutex_libc_init_normal(); test_rwlock_stdlib(); - test_rwlock_libc_static_initializer(); - } - #[cfg(target_os = "linux")] - { - test_mutex_libc_static_initializer_recursive(); } } @@ -29,61 +20,6 @@ fn test_mutex_stdlib() { drop(m); } -#[cfg(not(target_os = "windows"))] -fn test_mutex_libc_init_recursive() { - unsafe { - let mut attr: libc::pthread_mutexattr_t = std::mem::zeroed(); - assert_eq!(libc::pthread_mutexattr_init(&mut attr as *mut _), 0); - assert_eq!(libc::pthread_mutexattr_settype(&mut attr as *mut _, libc::PTHREAD_MUTEX_RECURSIVE), 0); - let mut mutex: libc::pthread_mutex_t = std::mem::zeroed(); - assert_eq!(libc::pthread_mutex_init(&mut mutex as *mut _, &mut attr as *mut _), 0); - assert_eq!(libc::pthread_mutex_lock(&mut mutex as *mut _), 0); - assert_eq!(libc::pthread_mutex_trylock(&mut mutex as *mut _), 0); - assert_eq!(libc::pthread_mutex_unlock(&mut mutex as *mut _), 0); - assert_eq!(libc::pthread_mutex_unlock(&mut mutex as *mut _), 0); - assert_eq!(libc::pthread_mutex_trylock(&mut mutex as *mut _), 0); - assert_eq!(libc::pthread_mutex_lock(&mut mutex as *mut _), 0); - assert_eq!(libc::pthread_mutex_unlock(&mut mutex as *mut _), 0); - assert_eq!(libc::pthread_mutex_unlock(&mut mutex as *mut _), 0); - assert_eq!(libc::pthread_mutex_unlock(&mut mutex as *mut _), libc::EPERM); - assert_eq!(libc::pthread_mutex_destroy(&mut mutex as *mut _), 0); - assert_eq!(libc::pthread_mutexattr_destroy(&mut attr as *mut _), 0); - } -} - -#[cfg(not(target_os = "windows"))] -fn test_mutex_libc_init_normal() { - unsafe { - let mut mutexattr: libc::pthread_mutexattr_t = std::mem::zeroed(); - assert_eq!(libc::pthread_mutexattr_settype(&mut mutexattr as *mut _, libc::PTHREAD_MUTEX_NORMAL), 0); - let mut mutex: libc::pthread_mutex_t = std::mem::zeroed(); - assert_eq!(libc::pthread_mutex_init(&mut mutex as *mut _, &mutexattr as *const _), 0); - assert_eq!(libc::pthread_mutex_lock(&mut mutex as *mut _), 0); - assert_eq!(libc::pthread_mutex_trylock(&mut mutex as *mut _), libc::EBUSY); - assert_eq!(libc::pthread_mutex_unlock(&mut mutex as *mut _), 0); - assert_eq!(libc::pthread_mutex_trylock(&mut mutex as *mut _), 0); - assert_eq!(libc::pthread_mutex_unlock(&mut mutex as *mut _), 0); - assert_eq!(libc::pthread_mutex_destroy(&mut mutex as *mut _), 0); - } -} - -#[cfg(target_os = "linux")] -fn test_mutex_libc_static_initializer_recursive() { - let mutex = std::cell::UnsafeCell::new(libc::PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP); - unsafe { - assert_eq!(libc::pthread_mutex_lock(mutex.get()), 0); - assert_eq!(libc::pthread_mutex_trylock(mutex.get()), 0); - assert_eq!(libc::pthread_mutex_unlock(mutex.get()), 0); - assert_eq!(libc::pthread_mutex_unlock(mutex.get()), 0); - assert_eq!(libc::pthread_mutex_trylock(mutex.get()), 0); - assert_eq!(libc::pthread_mutex_lock(mutex.get()), 0); - assert_eq!(libc::pthread_mutex_unlock(mutex.get()), 0); - assert_eq!(libc::pthread_mutex_unlock(mutex.get()), 0); - assert_eq!(libc::pthread_mutex_unlock(mutex.get()), libc::EPERM); - assert_eq!(libc::pthread_mutex_destroy(mutex.get()), 0); - } -} - #[cfg(not(target_os = "windows"))] fn test_rwlock_stdlib() { use std::sync::RwLock; @@ -102,30 +38,6 @@ fn test_rwlock_stdlib() { } } -// need to go a layer deeper and test the behavior of libc functions, because -// std::sys::unix::rwlock::RWLock keeps track of write_locked and num_readers - -#[cfg(not(target_os = "windows"))] -fn test_rwlock_libc_static_initializer() { - let rw = std::cell::UnsafeCell::new(libc::PTHREAD_RWLOCK_INITIALIZER); - unsafe { - assert_eq!(libc::pthread_rwlock_rdlock(rw.get()), 0); - assert_eq!(libc::pthread_rwlock_rdlock(rw.get()), 0); - assert_eq!(libc::pthread_rwlock_unlock(rw.get()), 0); - assert_eq!(libc::pthread_rwlock_tryrdlock(rw.get()), 0); - assert_eq!(libc::pthread_rwlock_unlock(rw.get()), 0); - assert_eq!(libc::pthread_rwlock_trywrlock(rw.get()), libc::EBUSY); - assert_eq!(libc::pthread_rwlock_unlock(rw.get()), 0); - - assert_eq!(libc::pthread_rwlock_wrlock(rw.get()), 0); - assert_eq!(libc::pthread_rwlock_tryrdlock(rw.get()), libc::EBUSY); - assert_eq!(libc::pthread_rwlock_trywrlock(rw.get()), libc::EBUSY); - assert_eq!(libc::pthread_rwlock_unlock(rw.get()), 0); - - assert_eq!(libc::pthread_rwlock_destroy(rw.get()), 0); - } -} - trait TryLockErrorExt { fn would_block(&self) -> bool; } From 177c0d3baa1d44db6ff574147a62b8b487d65f1e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 5 Apr 2020 19:13:36 +0200 Subject: [PATCH 1816/3747] also test push_str ptr stability (the original report) --- tests/run-pass/vec.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tests/run-pass/vec.rs b/tests/run-pass/vec.rs index 5c791e4db0a77..731358564b8ac 100644 --- a/tests/run-pass/vec.rs +++ b/tests/run-pass/vec.rs @@ -104,6 +104,14 @@ fn vec_truncate_ptr_stable() { let _val = *v0; } +fn push_str_ptr_stable() { + let mut buf = String::with_capacity(11); + buf.push_str("hello"); + let hello: &str = unsafe { &*(buf.as_str() as *const _) }; // laundering the lifetime -- we take care that `buf` does not reallocate, so that's okay. + buf.push_str(" world"); + assert_eq!(format!("{}", hello), "hello"); +} + fn main() { assert_eq!(vec_reallocate().len(), 5); @@ -127,4 +135,5 @@ fn main() { vec_push_ptr_stable(); vec_extend_ptr_stable(); vec_truncate_ptr_stable(); + push_str_ptr_stable(); } From 100141f57c27d0b282aec6156d60ab9d26583a47 Mon Sep 17 00:00:00 2001 From: David Cook Date: Sun, 5 Apr 2020 12:32:09 -0500 Subject: [PATCH 1817/3747] Remove null checks, fall through to UB upon deref --- src/shims/sync.rs | 70 ----------------------------------------------- 1 file changed, 70 deletions(-) diff --git a/src/shims/sync.rs b/src/shims/sync.rs index c2ea02af5b668..c9d846288a43e 100644 --- a/src/shims/sync.rs +++ b/src/shims/sync.rs @@ -179,11 +179,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn pthread_mutexattr_init(&mut self, attr_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - let attr = this.read_scalar(attr_op)?.not_undef()?; - if this.is_null(attr)? { - return this.eval_libc_i32("EINVAL"); - } - let default_kind = this.eval_libc("PTHREAD_MUTEX_DEFAULT")?; mutexattr_set_kind(this, attr_op, default_kind)?; @@ -197,11 +192,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - let attr = this.read_scalar(attr_op)?.not_undef()?; - if this.is_null(attr)? { - return this.eval_libc_i32("EINVAL"); - } - let kind = this.read_scalar(kind_op)?.not_undef()?; if kind == this.eval_libc("PTHREAD_MUTEX_NORMAL")? || kind == this.eval_libc("PTHREAD_MUTEX_ERRORCHECK")? @@ -219,11 +209,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn pthread_mutexattr_destroy(&mut self, attr_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - let attr = this.read_scalar(attr_op)?.not_undef()?; - if this.is_null(attr)? { - return this.eval_libc_i32("EINVAL"); - } - mutexattr_set_kind(this, attr_op, ScalarMaybeUndef::Undef)?; Ok(0) @@ -236,11 +221,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - let mutex = this.read_scalar(mutex_op)?.not_undef()?; - if this.is_null(mutex)? { - return this.eval_libc_i32("EINVAL"); - } - let attr = this.read_scalar(attr_op)?.not_undef()?; let kind = if this.is_null(attr)? { this.eval_libc("PTHREAD_MUTEX_DEFAULT")? @@ -257,11 +237,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn pthread_mutex_lock(&mut self, mutex_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - let mutex = this.read_scalar(mutex_op)?.not_undef()?; - if this.is_null(mutex)? { - return this.eval_libc_i32("EINVAL"); - } - let kind = mutex_get_kind(this, mutex_op)?.not_undef()?; let locked_count = mutex_get_locked_count(this, mutex_op)?.to_u32()?; @@ -295,11 +270,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn pthread_mutex_trylock(&mut self, mutex_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - let mutex = this.read_scalar(mutex_op)?.not_undef()?; - if this.is_null(mutex)? { - return this.eval_libc_i32("EINVAL"); - } - let kind = mutex_get_kind(this, mutex_op)?.not_undef()?; let locked_count = mutex_get_locked_count(this, mutex_op)?.to_u32()?; @@ -328,11 +298,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn pthread_mutex_unlock(&mut self, mutex_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - let mutex = this.read_scalar(mutex_op)?.not_undef()?; - if this.is_null(mutex)? { - return this.eval_libc_i32("EINVAL"); - } - let kind = mutex_get_kind(this, mutex_op)?.not_undef()?; let locked_count = mutex_get_locked_count(this, mutex_op)?.to_u32()?; @@ -371,11 +336,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn pthread_mutex_destroy(&mut self, mutex_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - let mutex = this.read_scalar(mutex_op)?.not_undef()?; - if this.is_null(mutex)? { - return this.eval_libc_i32("EINVAL"); - } - if mutex_get_locked_count(this, mutex_op)?.to_u32()? != 0 { return this.eval_libc_i32("EBUSY"); } @@ -389,11 +349,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn pthread_rwlock_rdlock(&mut self, rwlock_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - let rwlock = this.read_scalar(rwlock_op)?.not_undef()?; - if this.is_null(rwlock)? { - return this.eval_libc_i32("EINVAL"); - } - let readers = rwlock_get_readers(this, rwlock_op)?.to_u32()?; let writers = rwlock_get_writers(this, rwlock_op)?.to_u32()?; if writers != 0 { @@ -414,11 +369,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn pthread_rwlock_tryrdlock(&mut self, rwlock_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - let rwlock = this.read_scalar(rwlock_op)?.not_undef()?; - if this.is_null(rwlock)? { - return this.eval_libc_i32("EINVAL"); - } - let readers = rwlock_get_readers(this, rwlock_op)?.to_u32()?; let writers = rwlock_get_writers(this, rwlock_op)?.to_u32()?; if writers != 0 { @@ -437,11 +387,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn pthread_rwlock_wrlock(&mut self, rwlock_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - let rwlock = this.read_scalar(rwlock_op)?.not_undef()?; - if this.is_null(rwlock)? { - return this.eval_libc_i32("EINVAL"); - } - let readers = rwlock_get_readers(this, rwlock_op)?.to_u32()?; let writers = rwlock_get_writers(this, rwlock_op)?.to_u32()?; if readers != 0 { @@ -461,11 +406,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn pthread_rwlock_trywrlock(&mut self, rwlock_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - let rwlock = this.read_scalar(rwlock_op)?.not_undef()?; - if this.is_null(rwlock)? { - return this.eval_libc_i32("EINVAL"); - } - let readers = rwlock_get_readers(this, rwlock_op)?.to_u32()?; let writers = rwlock_get_writers(this, rwlock_op)?.to_u32()?; if readers != 0 || writers != 0 { @@ -479,11 +419,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn pthread_rwlock_unlock(&mut self, rwlock_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - let rwlock = this.read_scalar(rwlock_op)?.not_undef()?; - if this.is_null(rwlock)? { - return this.eval_libc_i32("EINVAL"); - } - let readers = rwlock_get_readers(this, rwlock_op)?.to_u32()?; let writers = rwlock_get_writers(this, rwlock_op)?.to_u32()?; if let Some(new_readers) = readers.checked_sub(1) { @@ -500,11 +435,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn pthread_rwlock_destroy(&mut self, rwlock_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - let rwlock = this.read_scalar(rwlock_op)?.not_undef()?; - if this.is_null(rwlock)? { - return this.eval_libc_i32("EINVAL"); - } - if rwlock_get_readers(this, rwlock_op)?.to_u32()? != 0 { return this.eval_libc_i32("EBUSY"); } From e7944419d4b7403c51028204ec5c4c53e776e94a Mon Sep 17 00:00:00 2001 From: David Cook Date: Sun, 5 Apr 2020 12:44:23 -0500 Subject: [PATCH 1818/3747] Use Deadlock machine stop uniformly --- src/shims/sync.rs | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/src/shims/sync.rs b/src/shims/sync.rs index c9d846288a43e..90d7104b9e7b0 100644 --- a/src/shims/sync.rs +++ b/src/shims/sync.rs @@ -352,9 +352,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let readers = rwlock_get_readers(this, rwlock_op)?.to_u32()?; let writers = rwlock_get_writers(this, rwlock_op)?.to_u32()?; if writers != 0 { - throw_unsup_format!( - "Deadlock due to read-locking a pthreads read-write lock while it is already write-locked" - ); + throw_machine_stop!(TerminationInfo::Deadlock); } else { match readers.checked_add(1) { Some(new_readers) => { @@ -390,13 +388,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let readers = rwlock_get_readers(this, rwlock_op)?.to_u32()?; let writers = rwlock_get_writers(this, rwlock_op)?.to_u32()?; if readers != 0 { - throw_unsup_format!( - "Deadlock due to write-locking a pthreads read-write lock while it is already read-locked" - ); + throw_machine_stop!(TerminationInfo::Deadlock); } else if writers != 0 { - throw_unsup_format!( - "Deadlock due to write-locking a pthreads read-write lock while it is already write-locked" - ); + throw_machine_stop!(TerminationInfo::Deadlock); } else { rwlock_set_writers(this, rwlock_op, Scalar::from_u32(1))?; Ok(0) From d5d5a569264d6ca18ff4d4648d62a81ce85114f7 Mon Sep 17 00:00:00 2001 From: David Cook Date: Sun, 5 Apr 2020 13:25:49 -0500 Subject: [PATCH 1819/3747] Add tests --- .../libc_pthread_mutex_normal_deadlock.rs | 16 ++++++++++++++++ .../libc_pthread_rwlock_read_write_deadlock.rs | 13 +++++++++++++ .../libc_pthread_rwlock_write_read_deadlock.rs | 13 +++++++++++++ ...libc_pthread_rwlock_write_write_deadlock.rs | 13 +++++++++++++ tests/run-pass/libc.rs | 18 ++++++++++++++++++ 5 files changed, 73 insertions(+) create mode 100644 tests/compile-fail/libc_pthread_mutex_normal_deadlock.rs create mode 100644 tests/compile-fail/libc_pthread_rwlock_read_write_deadlock.rs create mode 100644 tests/compile-fail/libc_pthread_rwlock_write_read_deadlock.rs create mode 100644 tests/compile-fail/libc_pthread_rwlock_write_write_deadlock.rs diff --git a/tests/compile-fail/libc_pthread_mutex_normal_deadlock.rs b/tests/compile-fail/libc_pthread_mutex_normal_deadlock.rs new file mode 100644 index 0000000000000..7034bf64ec901 --- /dev/null +++ b/tests/compile-fail/libc_pthread_mutex_normal_deadlock.rs @@ -0,0 +1,16 @@ +// ignore-windows: No libc on Windows + +#![feature(rustc_private)] + +extern crate libc; + +fn main() { + unsafe { + let mut mutexattr: libc::pthread_mutexattr_t = std::mem::zeroed(); + assert_eq!(libc::pthread_mutexattr_settype(&mut mutexattr as *mut _, libc::PTHREAD_MUTEX_NORMAL), 0); + let mut mutex: libc::pthread_mutex_t = std::mem::zeroed(); + assert_eq!(libc::pthread_mutex_init(&mut mutex as *mut _, &mutexattr as *const _), 0); + assert_eq!(libc::pthread_mutex_lock(&mut mutex as *mut _), 0); + libc::pthread_mutex_lock(&mut mutex as *mut _); //~ ERROR deadlock + } +} diff --git a/tests/compile-fail/libc_pthread_rwlock_read_write_deadlock.rs b/tests/compile-fail/libc_pthread_rwlock_read_write_deadlock.rs new file mode 100644 index 0000000000000..dd4707d60e4ca --- /dev/null +++ b/tests/compile-fail/libc_pthread_rwlock_read_write_deadlock.rs @@ -0,0 +1,13 @@ +// ignore-windows: No libc on Windows + +#![feature(rustc_private)] + +extern crate libc; + +fn main() { + let rw = std::cell::UnsafeCell::new(libc::PTHREAD_RWLOCK_INITIALIZER); + unsafe { + assert_eq!(libc::pthread_rwlock_rdlock(rw.get()), 0); + libc::pthread_rwlock_wrlock(rw.get()); //~ ERROR: deadlock + } +} diff --git a/tests/compile-fail/libc_pthread_rwlock_write_read_deadlock.rs b/tests/compile-fail/libc_pthread_rwlock_write_read_deadlock.rs new file mode 100644 index 0000000000000..1b460e7174d28 --- /dev/null +++ b/tests/compile-fail/libc_pthread_rwlock_write_read_deadlock.rs @@ -0,0 +1,13 @@ +// ignore-windows: No libc on Windows + +#![feature(rustc_private)] + +extern crate libc; + +fn main() { + let rw = std::cell::UnsafeCell::new(libc::PTHREAD_RWLOCK_INITIALIZER); + unsafe { + assert_eq!(libc::pthread_rwlock_wrlock(rw.get()), 0); + libc::pthread_rwlock_rdlock(rw.get()); //~ ERROR: deadlock + } +} diff --git a/tests/compile-fail/libc_pthread_rwlock_write_write_deadlock.rs b/tests/compile-fail/libc_pthread_rwlock_write_write_deadlock.rs new file mode 100644 index 0000000000000..cc327ec46bc29 --- /dev/null +++ b/tests/compile-fail/libc_pthread_rwlock_write_write_deadlock.rs @@ -0,0 +1,13 @@ +// ignore-windows: No libc on Windows + +#![feature(rustc_private)] + +extern crate libc; + +fn main() { + let rw = std::cell::UnsafeCell::new(libc::PTHREAD_RWLOCK_INITIALIZER); + unsafe { + assert_eq!(libc::pthread_rwlock_wrlock(rw.get()), 0); + libc::pthread_rwlock_wrlock(rw.get()); //~ ERROR: deadlock + } +} diff --git a/tests/run-pass/libc.rs b/tests/run-pass/libc.rs index 7ea793089d2f2..c930a034b130b 100644 --- a/tests/run-pass/libc.rs +++ b/tests/run-pass/libc.rs @@ -78,6 +78,23 @@ fn test_mutex_libc_init_normal() { } } +fn test_mutex_libc_init_errorcheck() { + unsafe { + let mut mutexattr: libc::pthread_mutexattr_t = std::mem::zeroed(); + assert_eq!(libc::pthread_mutexattr_settype(&mut mutexattr as *mut _, libc::PTHREAD_MUTEX_ERRORCHECK), 0); + let mut mutex: libc::pthread_mutex_t = std::mem::zeroed(); + assert_eq!(libc::pthread_mutex_init(&mut mutex as *mut _, &mutexattr as *const _), 0); + assert_eq!(libc::pthread_mutex_lock(&mut mutex as *mut _), 0); + assert_eq!(libc::pthread_mutex_trylock(&mut mutex as *mut _), libc::EBUSY); + assert_eq!(libc::pthread_mutex_lock(&mut mutex as *mut _), libc::EDEADLK); + assert_eq!(libc::pthread_mutex_unlock(&mut mutex as *mut _), 0); + assert_eq!(libc::pthread_mutex_trylock(&mut mutex as *mut _), 0); + assert_eq!(libc::pthread_mutex_unlock(&mut mutex as *mut _), 0); + assert_eq!(libc::pthread_mutex_unlock(&mut mutex as *mut _), libc::EPERM); + assert_eq!(libc::pthread_mutex_destroy(&mut mutex as *mut _), 0); + } +} + // Only linux provides PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP, // libc for macOS just has the default PTHREAD_MUTEX_INITIALIZER. #[cfg(target_os = "linux")] @@ -126,6 +143,7 @@ fn main() { test_mutex_libc_init_recursive(); test_mutex_libc_init_normal(); + test_mutex_libc_init_errorcheck(); test_rwlock_libc_static_initializer(); #[cfg(target_os = "linux")] From f9dc942cfdafc4fe86bc0ec1f0963f88eaa580c1 Mon Sep 17 00:00:00 2001 From: David Cook Date: Sun, 5 Apr 2020 13:53:03 -0500 Subject: [PATCH 1820/3747] Changes to error handling --- src/shims/sync.rs | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/src/shims/sync.rs b/src/shims/sync.rs index 90d7104b9e7b0..d7ae32daaa2ba 100644 --- a/src/shims/sync.rs +++ b/src/shims/sync.rs @@ -263,7 +263,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx None => this.eval_libc_i32("EAGAIN"), } } else { - this.eval_libc_i32("EINVAL") + throw_ub_format!("called pthread_mutex_lock on an unsupported type of mutex"); } } @@ -291,7 +291,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx None => this.eval_libc_i32("EAGAIN"), } } else { - this.eval_libc_i32("EINVAL") + throw_ub_format!("called pthread_mutex_trylock on an unsupported type of mutex"); } } @@ -306,9 +306,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx mutex_set_locked_count(this, mutex_op, Scalar::from_u32(0))?; Ok(0) } else { - throw_ub_format!( - "Attempted to unlock a PTHREAD_MUTEX_NORMAL mutex that was not locked" - ); + throw_ub_format!("unlocked a PTHREAD_MUTEX_NORMAL mutex that was not locked"); } } else if kind == this.eval_libc("PTHREAD_MUTEX_ERRORCHECK")? { if locked_count != 0 { @@ -329,7 +327,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } } else { - this.eval_libc_i32("EINVAL") + throw_ub_format!("called pthread_mutex_unlock on an unsupported type of mutex"); } } @@ -337,7 +335,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); if mutex_get_locked_count(this, mutex_op)?.to_u32()? != 0 { - return this.eval_libc_i32("EBUSY"); + throw_ub_format!("destroyed a locked mutex"); } mutex_set_kind(this, mutex_op, ScalarMaybeUndef::Undef)?; @@ -422,18 +420,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx rwlock_set_writers(this, rwlock_op, Scalar::from_u32(0))?; Ok(0) } else { - this.eval_libc_i32("EPERM") + throw_ub_format!("unlocked an rwlock that was not locked"); } } fn pthread_rwlock_destroy(&mut self, rwlock_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - if rwlock_get_readers(this, rwlock_op)?.to_u32()? != 0 { - return this.eval_libc_i32("EBUSY"); - } - if rwlock_get_writers(this, rwlock_op)?.to_u32()? != 0 { - return this.eval_libc_i32("EBUSY"); + if rwlock_get_readers(this, rwlock_op)?.to_u32()? != 0 + || rwlock_get_writers(this, rwlock_op)?.to_u32()? != 0 + { + throw_ub_format!("destroyed a locked rwlock"); } rwlock_set_readers(this, rwlock_op, ScalarMaybeUndef::Undef)?; From 134d6a2faab1801e9b3d23b6ee11ba1643eae0fe Mon Sep 17 00:00:00 2001 From: David Cook Date: Sun, 5 Apr 2020 14:55:57 -0500 Subject: [PATCH 1821/3747] Add tests, improve test coverage --- .../libc_pthread_mutex_destroy_locked.rs | 16 ++++++++++++++++ ...libc_pthread_mutex_normal_unlock_unlocked.rs | 17 +++++++++++++++++ .../libc_pthread_rwlock_destroy_read_locked.rs | 13 +++++++++++++ .../libc_pthread_rwlock_destroy_write_locked.rs | 13 +++++++++++++ .../libc_pthread_rwlock_unlock_unlocked.rs | 12 ++++++++++++ tests/run-pass/libc.rs | 8 +++++++- 6 files changed, 78 insertions(+), 1 deletion(-) create mode 100644 tests/compile-fail/libc_pthread_mutex_destroy_locked.rs create mode 100644 tests/compile-fail/libc_pthread_mutex_normal_unlock_unlocked.rs create mode 100644 tests/compile-fail/libc_pthread_rwlock_destroy_read_locked.rs create mode 100644 tests/compile-fail/libc_pthread_rwlock_destroy_write_locked.rs create mode 100644 tests/compile-fail/libc_pthread_rwlock_unlock_unlocked.rs diff --git a/tests/compile-fail/libc_pthread_mutex_destroy_locked.rs b/tests/compile-fail/libc_pthread_mutex_destroy_locked.rs new file mode 100644 index 0000000000000..e7ed8ad296211 --- /dev/null +++ b/tests/compile-fail/libc_pthread_mutex_destroy_locked.rs @@ -0,0 +1,16 @@ +// ignore-windows: No libc on Windows + +#![feature(rustc_private)] + +extern crate libc; + +fn main() { + unsafe { + let mut mutexattr: libc::pthread_mutexattr_t = std::mem::zeroed(); + assert_eq!(libc::pthread_mutexattr_settype(&mut mutexattr as *mut _, libc::PTHREAD_MUTEX_NORMAL), 0); + let mut mutex: libc::pthread_mutex_t = std::mem::zeroed(); + assert_eq!(libc::pthread_mutex_init(&mut mutex as *mut _, &mutexattr as *const _), 0); + assert_eq!(libc::pthread_mutex_lock(&mut mutex as *mut _), 0); + libc::pthread_mutex_destroy(&mut mutex as *mut _); //~ ERROR destroyed a locked mutex + } +} diff --git a/tests/compile-fail/libc_pthread_mutex_normal_unlock_unlocked.rs b/tests/compile-fail/libc_pthread_mutex_normal_unlock_unlocked.rs new file mode 100644 index 0000000000000..65de62484d5ed --- /dev/null +++ b/tests/compile-fail/libc_pthread_mutex_normal_unlock_unlocked.rs @@ -0,0 +1,17 @@ +// ignore-windows: No libc on Windows + +#![feature(rustc_private)] + +extern crate libc; + +fn main() { + unsafe { + let mut mutexattr: libc::pthread_mutexattr_t = std::mem::zeroed(); + assert_eq!(libc::pthread_mutexattr_settype(&mut mutexattr as *mut _, libc::PTHREAD_MUTEX_NORMAL), 0); + let mut mutex: libc::pthread_mutex_t = std::mem::zeroed(); + assert_eq!(libc::pthread_mutex_init(&mut mutex as *mut _, &mutexattr as *const _), 0); + assert_eq!(libc::pthread_mutex_lock(&mut mutex as *mut _), 0); + assert_eq!(libc::pthread_mutex_unlock(&mut mutex as *mut _), 0); + libc::pthread_mutex_unlock(&mut mutex as *mut _); //~ ERROR was not locked + } +} diff --git a/tests/compile-fail/libc_pthread_rwlock_destroy_read_locked.rs b/tests/compile-fail/libc_pthread_rwlock_destroy_read_locked.rs new file mode 100644 index 0000000000000..8750a7388fca2 --- /dev/null +++ b/tests/compile-fail/libc_pthread_rwlock_destroy_read_locked.rs @@ -0,0 +1,13 @@ +// ignore-windows: No libc on Windows + +#![feature(rustc_private)] + +extern crate libc; + +fn main() { + let rw = std::cell::UnsafeCell::new(libc::PTHREAD_RWLOCK_INITIALIZER); + unsafe { + assert_eq!(libc::pthread_rwlock_rdlock(rw.get()), 0); + libc::pthread_rwlock_destroy(rw.get()); //~ ERROR destroyed a locked rwlock + } +} diff --git a/tests/compile-fail/libc_pthread_rwlock_destroy_write_locked.rs b/tests/compile-fail/libc_pthread_rwlock_destroy_write_locked.rs new file mode 100644 index 0000000000000..aecccfa503103 --- /dev/null +++ b/tests/compile-fail/libc_pthread_rwlock_destroy_write_locked.rs @@ -0,0 +1,13 @@ +// ignore-windows: No libc on Windows + +#![feature(rustc_private)] + +extern crate libc; + +fn main() { + let rw = std::cell::UnsafeCell::new(libc::PTHREAD_RWLOCK_INITIALIZER); + unsafe { + assert_eq!(libc::pthread_rwlock_wrlock(rw.get()), 0); + libc::pthread_rwlock_destroy(rw.get()); //~ ERROR destroyed a locked rwlock + } +} diff --git a/tests/compile-fail/libc_pthread_rwlock_unlock_unlocked.rs b/tests/compile-fail/libc_pthread_rwlock_unlock_unlocked.rs new file mode 100644 index 0000000000000..8b3de53828df6 --- /dev/null +++ b/tests/compile-fail/libc_pthread_rwlock_unlock_unlocked.rs @@ -0,0 +1,12 @@ +// ignore-windows: No libc on Windows + +#![feature(rustc_private)] + +extern crate libc; + +fn main() { + let rw = std::cell::UnsafeCell::new(libc::PTHREAD_RWLOCK_INITIALIZER); + unsafe { + libc::pthread_rwlock_unlock(rw.get()); //~ ERROR was not locked + } +} diff --git a/tests/run-pass/libc.rs b/tests/run-pass/libc.rs index c930a034b130b..a449d9340a315 100644 --- a/tests/run-pass/libc.rs +++ b/tests/run-pass/libc.rs @@ -15,7 +15,7 @@ fn tmp() -> PathBuf { #[cfg(not(target_os = "macos"))] fn test_posix_fadvise() { use std::convert::TryInto; - use std::fs::{File, remove_file}; + use std::fs::{remove_file, File}; use std::io::Write; use std::os::unix::io::AsRawFd; @@ -66,6 +66,7 @@ fn test_mutex_libc_init_recursive() { fn test_mutex_libc_init_normal() { unsafe { let mut mutexattr: libc::pthread_mutexattr_t = std::mem::zeroed(); + assert_eq!(libc::pthread_mutexattr_settype(&mut mutexattr as *mut _, 0x12345678), libc::EINVAL); assert_eq!(libc::pthread_mutexattr_settype(&mut mutexattr as *mut _, libc::PTHREAD_MUTEX_NORMAL), 0); let mut mutex: libc::pthread_mutex_t = std::mem::zeroed(); assert_eq!(libc::pthread_mutex_init(&mut mutex as *mut _, &mutexattr as *const _), 0); @@ -133,6 +134,11 @@ fn test_rwlock_libc_static_initializer() { assert_eq!(libc::pthread_rwlock_trywrlock(rw.get()), libc::EBUSY); assert_eq!(libc::pthread_rwlock_unlock(rw.get()), 0); + assert_eq!(libc::pthread_rwlock_trywrlock(rw.get()), 0); + assert_eq!(libc::pthread_rwlock_tryrdlock(rw.get()), libc::EBUSY); + assert_eq!(libc::pthread_rwlock_trywrlock(rw.get()), libc::EBUSY); + assert_eq!(libc::pthread_rwlock_unlock(rw.get()), 0); + assert_eq!(libc::pthread_rwlock_destroy(rw.get()), 0); } } From bc54c7628dbcccc8d727abea591e9ac14ea2fed2 Mon Sep 17 00:00:00 2001 From: David Cook Date: Sun, 5 Apr 2020 16:03:44 -0500 Subject: [PATCH 1822/3747] Eagerly compute i32 and u32 layouts --- src/eval.rs | 15 +++++---- src/lib.rs | 5 ++- src/machine.rs | 79 ++++++++++++++++++----------------------------- src/shims/sync.rs | 58 ++++++++++++++++++++++++---------- 4 files changed, 83 insertions(+), 74 deletions(-) diff --git a/src/eval.rs b/src/eval.rs index 46e66bc0a81e7..c3510188e3cb2 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -1,14 +1,14 @@ //! Main evaluator loop and setting up the initial stack frame. -use std::ffi::OsStr; use std::convert::TryFrom; +use std::ffi::OsStr; use rand::rngs::StdRng; use rand::SeedableRng; -use rustc_target::abi::LayoutOf; -use rustc_middle::ty::{self, TyCtxt}; use rustc_hir::def_id::DefId; +use rustc_middle::ty::{self, layout::LayoutCx, TyCtxt}; +use rustc_target::abi::LayoutOf; use crate::*; @@ -60,10 +60,13 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( main_id: DefId, config: MiriConfig, ) -> InterpResult<'tcx, (InterpCx<'mir, 'tcx, Evaluator<'tcx>>, MPlaceTy<'tcx, Tag>)> { + let tcx_at = tcx.at(rustc_span::source_map::DUMMY_SP); + let param_env = ty::ParamEnv::reveal_all(); + let layout_cx = LayoutCx { tcx, param_env }; let mut ecx = InterpCx::new( - tcx.at(rustc_span::source_map::DUMMY_SP), - ty::ParamEnv::reveal_all(), - Evaluator::new(config.communicate, config.validate), + tcx_at, + param_env, + Evaluator::new(config.communicate, config.validate, layout_cx), MemoryExtra::new( StdRng::seed_from_u64(config.seed.unwrap_or(0)), config.stacked_borrows, diff --git a/src/lib.rs b/src/lib.rs index 82ac2e8d21883..2f381b4a34546 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -51,9 +51,8 @@ pub use crate::diagnostics::{ pub use crate::eval::{create_ecx, eval_main, MiriConfig}; pub use crate::helpers::EvalContextExt as HelpersEvalContextExt; pub use crate::machine::{ - AllocExtra, EvalContextExt as MachineEvalContextExt, Evaluator, FrameData, MemoryExtra, - MiriEvalContext, MiriEvalContextExt, MiriMemoryKind, NUM_CPUS, PAGE_SIZE, STACK_ADDR, - STACK_SIZE, + AllocExtra, Evaluator, FrameData, MemoryExtra, MiriEvalContext, MiriEvalContextExt, + MiriMemoryKind, NUM_CPUS, PAGE_SIZE, STACK_ADDR, STACK_SIZE, }; pub use crate::mono_hash_map::MonoHashMap; pub use crate::operator::EvalContextExt as OperatorEvalContextExt; diff --git a/src/machine.rs b/src/machine.rs index bfb832085e0bf..26ff23511f733 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -10,11 +10,18 @@ use std::time::Instant; use log::trace; use rand::rngs::StdRng; -use rustc_data_structures::fx::FxHashMap; -use rustc_middle::{mir, ty::{self, layout::TyAndLayout}}; -use rustc_target::abi::{LayoutOf, Size}; use rustc_ast::attr; +use rustc_data_structures::fx::FxHashMap; +use rustc_middle::{ + mir, + ty::{ + self, + layout::{LayoutCx, LayoutError, TyAndLayout}, + TyCtxt, + }, +}; use rustc_span::symbol::{sym, Symbol}; +use rustc_target::abi::{LayoutOf, Size}; use crate::*; @@ -146,36 +153,18 @@ impl MemoryExtra { } } -/// Cached layouts of primitive types -#[derive(Default)] -struct PrimitiveLayouts<'tcx> { - i32: RefCell>>, - u32: RefCell>>, +/// Precomputed layouts of primitive types +pub(crate) struct PrimitiveLayouts<'tcx> { + pub(crate) i32: TyAndLayout<'tcx>, + pub(crate) u32: TyAndLayout<'tcx>, } impl<'mir, 'tcx: 'mir> PrimitiveLayouts<'tcx> { - fn i32(&self, ecx: &MiriEvalContext<'mir, 'tcx>) -> InterpResult<'tcx, TyAndLayout<'tcx>> { - { - let layout_ref = self.i32.borrow(); - if layout_ref.is_some() { - return Ok(layout_ref.unwrap()); - } - } - let layout = ecx.layout_of(ecx.tcx.types.i32)?; - *self.i32.borrow_mut() = Some(layout); - Ok(layout) - } - - fn u32(&self, ecx: &MiriEvalContext<'mir, 'tcx>) -> InterpResult<'tcx, TyAndLayout<'tcx>> { - { - let layout_ref = self.u32.borrow(); - if layout_ref.is_some() { - return Ok(layout_ref.unwrap()); - } - } - let layout = ecx.layout_of(ecx.tcx.types.u32)?; - *self.u32.borrow_mut() = Some(layout); - Ok(layout) + fn new(layout_cx: LayoutCx<'tcx, TyCtxt<'tcx>>) -> Result> { + Ok(Self { + i32: layout_cx.layout_of(layout_cx.tcx.types.i32)?, + u32: layout_cx.layout_of(layout_cx.tcx.types.u32)?, + }) } } @@ -216,14 +205,20 @@ pub struct Evaluator<'tcx> { /// The "time anchor" for this machine's monotone clock (for `Instant` simulation). pub(crate) time_anchor: Instant, - /// Cached `TyLayout`s for primitive data types that are commonly used inside Miri. + /// Precomputed `TyLayout`s for primitive data types that are commonly used inside Miri. /// FIXME: Search through the rest of the codebase for more layout_of() calls that - /// could be cached here. - primitive_layouts: PrimitiveLayouts<'tcx>, + /// could be stored here. + pub(crate) layouts: PrimitiveLayouts<'tcx>, } impl<'tcx> Evaluator<'tcx> { - pub(crate) fn new(communicate: bool, validate: bool) -> Self { + pub(crate) fn new( + communicate: bool, + validate: bool, + layout_cx: LayoutCx<'tcx, TyCtxt<'tcx>>, + ) -> Self { + let layouts = PrimitiveLayouts::new(layout_cx) + .expect("Couldn't get layouts of primitive types"); Evaluator { // `env_vars` could be initialized properly here if `Memory` were available before // calling this method. @@ -239,7 +234,7 @@ impl<'tcx> Evaluator<'tcx> { dir_handler: Default::default(), panic_payload: None, time_anchor: Instant::now(), - primitive_layouts: PrimitiveLayouts::default(), + layouts, } } } @@ -263,20 +258,6 @@ impl<'mir, 'tcx> MiriEvalContextExt<'mir, 'tcx> for MiriEvalContext<'mir, 'tcx> } } -impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for MiriEvalContext<'mir, 'tcx> {} -/// Provides convenience methods for use elsewhere -pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { - fn i32_layout(&self) -> InterpResult<'tcx, TyAndLayout<'tcx>> { - let this = self.eval_context_ref(); - this.machine.primitive_layouts.i32(this) - } - - fn u32_layout(&self) -> InterpResult<'tcx, TyAndLayout<'tcx>> { - let this = self.eval_context_ref(); - this.machine.primitive_layouts.u32(this) - } -} - /// Machine hook implementations. impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { type MemoryKind = MiriMemoryKind; diff --git a/src/shims/sync.rs b/src/shims/sync.rs index d7ae32daaa2ba..b03dcbfd8969a 100644 --- a/src/shims/sync.rs +++ b/src/shims/sync.rs @@ -31,7 +31,8 @@ fn mutexattr_get_kind<'mir, 'tcx: 'mir>( // Ensure that the following read at an offset to the attr pointer is within bounds assert_ptr_target_min_size(ecx, attr_op, 4)?; let attr_place = ecx.deref_operand(attr_op)?; - let kind_place = attr_place.offset(Size::ZERO, MemPlaceMeta::None, ecx.i32_layout()?, ecx)?; + let kind_place = + attr_place.offset(Size::ZERO, MemPlaceMeta::None, ecx.machine.layouts.i32, ecx)?; ecx.read_scalar(kind_place.into()) } @@ -43,7 +44,8 @@ fn mutexattr_set_kind<'mir, 'tcx: 'mir>( // Ensure that the following write at an offset to the attr pointer is within bounds assert_ptr_target_min_size(ecx, attr_op, 4)?; let attr_place = ecx.deref_operand(attr_op)?; - let kind_place = attr_place.offset(Size::ZERO, MemPlaceMeta::None, ecx.i32_layout()?, ecx)?; + let kind_place = + attr_place.offset(Size::ZERO, MemPlaceMeta::None, ecx.machine.layouts.i32, ecx)?; ecx.write_scalar(kind.into(), kind_place.into()) } @@ -63,8 +65,12 @@ fn mutex_get_locked_count<'mir, 'tcx: 'mir>( // Ensure that the following read at an offset to the mutex pointer is within bounds assert_ptr_target_min_size(ecx, mutex_op, 20)?; let mutex_place = ecx.deref_operand(mutex_op)?; - let locked_count_place = - mutex_place.offset(Size::from_bytes(4), MemPlaceMeta::None, ecx.u32_layout()?, ecx)?; + let locked_count_place = mutex_place.offset( + Size::from_bytes(4), + MemPlaceMeta::None, + ecx.machine.layouts.u32, + ecx, + )?; ecx.read_scalar(locked_count_place.into()) } @@ -76,8 +82,12 @@ fn mutex_set_locked_count<'mir, 'tcx: 'mir>( // Ensure that the following write at an offset to the mutex pointer is within bounds assert_ptr_target_min_size(ecx, mutex_op, 20)?; let mutex_place = ecx.deref_operand(mutex_op)?; - let locked_count_place = - mutex_place.offset(Size::from_bytes(4), MemPlaceMeta::None, ecx.u32_layout()?, ecx)?; + let locked_count_place = mutex_place.offset( + Size::from_bytes(4), + MemPlaceMeta::None, + ecx.machine.layouts.u32, + ecx, + )?; ecx.write_scalar(locked_count.into(), locked_count_place.into()) } @@ -92,7 +102,7 @@ fn mutex_get_kind<'mir, 'tcx: 'mir>( let kind_place = mutex_place.offset( Size::from_bytes(kind_offset), MemPlaceMeta::None, - ecx.i32_layout()?, + ecx.machine.layouts.i32, ecx, )?; ecx.read_scalar(kind_place.into()) @@ -110,7 +120,7 @@ fn mutex_set_kind<'mir, 'tcx: 'mir>( let kind_place = mutex_place.offset( Size::from_bytes(kind_offset), MemPlaceMeta::None, - ecx.i32_layout()?, + ecx.machine.layouts.i32, ecx, )?; ecx.write_scalar(kind.into(), kind_place.into()) @@ -131,8 +141,12 @@ fn rwlock_get_readers<'mir, 'tcx: 'mir>( // Ensure that the following read at an offset to the rwlock pointer is within bounds assert_ptr_target_min_size(ecx, rwlock_op, 12)?; let rwlock_place = ecx.deref_operand(rwlock_op)?; - let readers_place = - rwlock_place.offset(Size::from_bytes(4), MemPlaceMeta::None, ecx.u32_layout()?, ecx)?; + let readers_place = rwlock_place.offset( + Size::from_bytes(4), + MemPlaceMeta::None, + ecx.machine.layouts.u32, + ecx, + )?; ecx.read_scalar(readers_place.into()) } @@ -144,8 +158,12 @@ fn rwlock_set_readers<'mir, 'tcx: 'mir>( // Ensure that the following write at an offset to the rwlock pointer is within bounds assert_ptr_target_min_size(ecx, rwlock_op, 12)?; let rwlock_place = ecx.deref_operand(rwlock_op)?; - let readers_place = - rwlock_place.offset(Size::from_bytes(4), MemPlaceMeta::None, ecx.u32_layout()?, ecx)?; + let readers_place = rwlock_place.offset( + Size::from_bytes(4), + MemPlaceMeta::None, + ecx.machine.layouts.u32, + ecx, + )?; ecx.write_scalar(readers.into(), readers_place.into()) } @@ -156,8 +174,12 @@ fn rwlock_get_writers<'mir, 'tcx: 'mir>( // Ensure that the following read at an offset to the rwlock pointer is within bounds assert_ptr_target_min_size(ecx, rwlock_op, 12)?; let rwlock_place = ecx.deref_operand(rwlock_op)?; - let writers_place = - rwlock_place.offset(Size::from_bytes(8), MemPlaceMeta::None, ecx.u32_layout()?, ecx)?; + let writers_place = rwlock_place.offset( + Size::from_bytes(8), + MemPlaceMeta::None, + ecx.machine.layouts.u32, + ecx, + )?; ecx.read_scalar(writers_place.into()) } @@ -169,8 +191,12 @@ fn rwlock_set_writers<'mir, 'tcx: 'mir>( // Ensure that the following write at an offset to the rwlock pointer is within bounds assert_ptr_target_min_size(ecx, rwlock_op, 12)?; let rwlock_place = ecx.deref_operand(rwlock_op)?; - let writers_place = - rwlock_place.offset(Size::from_bytes(8), MemPlaceMeta::None, ecx.u32_layout()?, ecx)?; + let writers_place = rwlock_place.offset( + Size::from_bytes(8), + MemPlaceMeta::None, + ecx.machine.layouts.u32, + ecx, + )?; ecx.write_scalar(writers.into(), writers_place.into()) } From 0f5f0e1520a4f001674478ee5b8eb7a644b2c66a Mon Sep 17 00:00:00 2001 From: David Cook Date: Sun, 5 Apr 2020 20:55:39 -0500 Subject: [PATCH 1823/3747] Fix spelling typo --- src/shims/foreign_items/posix/linux.rs | 2 +- src/shims/foreign_items/posix/macos.rs | 2 +- src/shims/foreign_items/windows.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/shims/foreign_items/posix/linux.rs b/src/shims/foreign_items/posix/linux.rs index 286bd5798b049..16c6c002b69c5 100644 --- a/src/shims/foreign_items/posix/linux.rs +++ b/src/shims/foreign_items/posix/linux.rs @@ -113,7 +113,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_i32(-1), dest)?; } - // Incomplete shims that we "stub out" just to get pre-main initialziation code to work. + // Incomplete shims that we "stub out" just to get pre-main initialization code to work. // These shims are enabled only when the caller is in the standard library. "pthread_getattr_np" if this.frame().instance.to_string().starts_with("std::sys::unix::") => { this.write_null(dest)?; diff --git a/src/shims/foreign_items/posix/macos.rs b/src/shims/foreign_items/posix/macos.rs index 44c45d90c1987..9810a77ffde18 100644 --- a/src/shims/foreign_items/posix/macos.rs +++ b/src/shims/foreign_items/posix/macos.rs @@ -88,7 +88,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(stack_size, dest)?; } - // Incomplete shims that we "stub out" just to get pre-main initialziation code to work. + // Incomplete shims that we "stub out" just to get pre-main initialization code to work. // These shims are enabled only when the caller is in the standard library. "mmap" if this.frame().instance.to_string().starts_with("std::sys::unix::") => { // This is a horrible hack, but since the guard page mechanism calls mmap and expects a particular return value, we just give it that value. diff --git a/src/shims/foreign_items/windows.rs b/src/shims/foreign_items/windows.rs index 443d44fae1c3a..1d17cbcefdeec 100644 --- a/src/shims/foreign_items/windows.rs +++ b/src/shims/foreign_items/windows.rs @@ -207,7 +207,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx throw_unsup_format!("Miri does not support threading"); } - // Incomplete shims that we "stub out" just to get pre-main initialziation code to work. + // Incomplete shims that we "stub out" just to get pre-main initialization code to work. // These shims are enabled only when the caller is in the standard library. "GetProcessHeap" if this.frame().instance.to_string().starts_with("std::sys::windows::") => { // Just fake a HANDLE From 86c57a8490ba6d06e284865adc33af7f4ebdb887 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 6 Apr 2020 09:33:36 +0200 Subject: [PATCH 1824/3747] mention ./miri build --- CONTRIBUTING.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index c7bfe6ccf1c14..3967ca05f9241 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -28,6 +28,15 @@ install that exact version of rustc as a toolchain: [`rustup-toolchain-install-master`]: https://github.com/kennytm/rustup-toolchain-install-master +Now building Miri is just one command away: + +``` +./miri build +``` + +Run `./miri` without arguments to see the other commands our build tool +supports. + ### Fixing Miri when rustc changes Miri is heavily tied to rustc internals, so it is very common that rustc changes From 3554f54173f40d96a7f81497c7955bae5bebfe1d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 6 Apr 2020 09:34:27 +0200 Subject: [PATCH 1825/3747] make just ./miri print help text without 'unknown command' --- miri | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/miri b/miri index 8cd2cfc3ae0c6..b4d205bd52c55 100755 --- a/miri +++ b/miri @@ -141,8 +141,10 @@ run|run-debug) exec cargo run $CARGO_BUILD_FLAGS -- --sysroot "$MIRI_SYSROOT" "$@" ;; *) - echo "Unknown command: $COMMAND" - echo + if [ -n "$COMMAND" ]; then + echo "Unknown command: $COMMAND" + echo + fi echo "$USAGE" exit 1 esac From ac3a24673cb242090f4b298f986f4940575483b5 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 6 Apr 2020 09:37:15 +0200 Subject: [PATCH 1826/3747] wording --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 3967ca05f9241..50cfe14a28ebf 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -69,7 +69,7 @@ driver on a particular file by doing ./miri run tests/run-pass/hello.rs --target i686-unknown-linux-gnu ``` -and you can (cross-)run the test suite using: +and you can (cross-)run the entire test suite using: ``` ./miri test From 80497e5d3c5fe08e95bcbe114fae39661a909e16 Mon Sep 17 00:00:00 2001 From: David Cook Date: Mon, 6 Apr 2020 07:23:58 -0500 Subject: [PATCH 1827/3747] Clean up conditional compilation --- tests/run-pass/libc.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/run-pass/libc.rs b/tests/run-pass/libc.rs index a449d9340a315..fc154c05c8fc3 100644 --- a/tests/run-pass/libc.rs +++ b/tests/run-pass/libc.rs @@ -12,7 +12,7 @@ fn tmp() -> PathBuf { std::env::var("MIRI_TEMP").map(PathBuf::from).unwrap_or_else(|_| std::env::temp_dir()) } -#[cfg(not(target_os = "macos"))] +#[cfg(target_os = "linux")] fn test_posix_fadvise() { use std::convert::TryInto; use std::fs::{remove_file, File}; @@ -144,7 +144,7 @@ fn test_rwlock_libc_static_initializer() { } fn main() { - #[cfg(not(target_os = "macos"))] + #[cfg(target_os = "linux")] test_posix_fadvise(); test_mutex_libc_init_recursive(); From a46f8b66c30f4eec58fd781f18583bd87a2f923a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 7 Apr 2020 16:13:19 +0200 Subject: [PATCH 1828/3747] prefer float assoc consts over std module --- tests/run-pass/float.rs | 70 ++++++++++++++++++++--------------------- 1 file changed, 35 insertions(+), 35 deletions(-) diff --git a/tests/run-pass/float.rs b/tests/run-pass/float.rs index 394e91ac9c3b8..5acaf6a2a97cd 100644 --- a/tests/run-pass/float.rs +++ b/tests/run-pass/float.rs @@ -34,37 +34,37 @@ fn main() { assert_eq(-5.0f32 as u32, 0); assert_eq(5.0f32 as i32, 5); assert_eq(-5.0f32 as i32, -5); - assert_eq(std::f32::MAX as i32, i32::MAX); - assert_eq(std::f32::INFINITY as i32, i32::MAX); - assert_eq(std::f32::MAX as u32, u32::MAX); - assert_eq(std::f32::INFINITY as u32, u32::MAX); - assert_eq(std::f32::MIN as i32, i32::MIN); - assert_eq(std::f32::NEG_INFINITY as i32, i32::MIN); - assert_eq(std::f32::MIN as u32, 0); - assert_eq(std::f32::NEG_INFINITY as u32, 0); - assert_eq(std::f32::NAN as i32, 0); - assert_eq(std::f32::NAN as u32, 0); + assert_eq(f32::MAX as i32, i32::MAX); + assert_eq(f32::INFINITY as i32, i32::MAX); + assert_eq(f32::MAX as u32, u32::MAX); + assert_eq(f32::INFINITY as u32, u32::MAX); + assert_eq(f32::MIN as i32, i32::MIN); + assert_eq(f32::NEG_INFINITY as i32, i32::MIN); + assert_eq(f32::MIN as u32, 0); + assert_eq(f32::NEG_INFINITY as u32, 0); + assert_eq(f32::NAN as i32, 0); + assert_eq(f32::NAN as u32, 0); assert_eq((u32::MAX-127) as f32 as u32, u32::MAX); // rounding loss assert_eq((u32::MAX-128) as f32 as u32, u32::MAX-255); // rounding loss assert_eq(127i8 as f32, 127.0f32); assert_eq(i128::MIN as f32, -170141183460469231731687303715884105728.0f32); - assert_eq(u128::MAX as f32, std::f32::INFINITY); // saturation + assert_eq(u128::MAX as f32, f32::INFINITY); // saturation // f64 <-> int casts assert_eq(5.0f64 as u64, 5); assert_eq(-5.0f64 as u64, 0); assert_eq(5.0f64 as i64, 5); assert_eq(-5.0f64 as i64, -5); - assert_eq(std::f64::MAX as i64, i64::MAX); - assert_eq(std::f64::INFINITY as i64, i64::MAX); - assert_eq(std::f64::MAX as u64, u64::MAX); - assert_eq(std::f64::INFINITY as u64, u64::MAX); - assert_eq(std::f64::MIN as i64, i64::MIN); - assert_eq(std::f64::NEG_INFINITY as i64, i64::MIN); - assert_eq(std::f64::MIN as u64, 0); - assert_eq(std::f64::NEG_INFINITY as u64, 0); - assert_eq(std::f64::NAN as i64, 0); - assert_eq(std::f64::NAN as u64, 0); + assert_eq(f64::MAX as i64, i64::MAX); + assert_eq(f64::INFINITY as i64, i64::MAX); + assert_eq(f64::MAX as u64, u64::MAX); + assert_eq(f64::INFINITY as u64, u64::MAX); + assert_eq(f64::MIN as i64, i64::MIN); + assert_eq(f64::NEG_INFINITY as i64, i64::MIN); + assert_eq(f64::MIN as u64, 0); + assert_eq(f64::NEG_INFINITY as u64, 0); + assert_eq(f64::NAN as i64, 0); + assert_eq(f64::NAN as u64, 0); assert_eq((u64::MAX-1023) as f64 as u64, u64::MAX); // rounding loss assert_eq((u64::MAX-1024) as f64 as u64, u64::MAX-2047); // rounding loss assert_eq(u128::MAX as f64 as u128, u128::MAX); @@ -74,38 +74,38 @@ fn main() { // f32 <-> f64 casts assert_eq(5.0f64 as f32, 5.0f32); assert_eq(5.0f32 as f64, 5.0f64); - assert_eq(std::f64::MAX as f32, std::f32::INFINITY); - assert_eq(std::f64::MIN as f32, std::f32::NEG_INFINITY); - assert_eq(std::f32::INFINITY as f64, std::f64::INFINITY); - assert_eq(std::f32::NEG_INFINITY as f64, std::f64::NEG_INFINITY); + assert_eq(f64::MAX as f32, f32::INFINITY); + assert_eq(f64::MIN as f32, f32::NEG_INFINITY); + assert_eq(f32::INFINITY as f64, f64::INFINITY); + assert_eq(f32::NEG_INFINITY as f64, f64::NEG_INFINITY); // f32 min/max assert_eq((1.0 as f32).max(-1.0), 1.0); assert_eq((1.0 as f32).min(-1.0), -1.0); - assert_eq(std::f32::NAN.min(9.0), 9.0); - assert_eq(std::f32::NAN.max(-9.0), -9.0); - assert_eq((9.0 as f32).min(std::f32::NAN), 9.0); - assert_eq((-9.0 as f32).max(std::f32::NAN), -9.0); + assert_eq(f32::NAN.min(9.0), 9.0); + assert_eq(f32::NAN.max(-9.0), -9.0); + assert_eq((9.0 as f32).min(f32::NAN), 9.0); + assert_eq((-9.0 as f32).max(f32::NAN), -9.0); // f64 min/max assert_eq((1.0 as f64).max(-1.0), 1.0); assert_eq((1.0 as f64).min(-1.0), -1.0); - assert_eq(std::f64::NAN.min(9.0), 9.0); - assert_eq(std::f64::NAN.max(-9.0), -9.0); - assert_eq((9.0 as f64).min(std::f64::NAN), 9.0); - assert_eq((-9.0 as f64).max(std::f64::NAN), -9.0); + assert_eq(f64::NAN.min(9.0), 9.0); + assert_eq(f64::NAN.max(-9.0), -9.0); + assert_eq((9.0 as f64).min(f64::NAN), 9.0); + assert_eq((-9.0 as f64).max(f64::NAN), -9.0); // f32 copysign assert_eq(3.5_f32.copysign(0.42), 3.5_f32); assert_eq(3.5_f32.copysign(-0.42), -3.5_f32); assert_eq((-3.5_f32).copysign(0.42), 3.5_f32); assert_eq((-3.5_f32).copysign(-0.42), -3.5_f32); - assert!(std::f32::NAN.copysign(1.0).is_nan()); + assert!(f32::NAN.copysign(1.0).is_nan()); // f64 copysign assert_eq(3.5_f64.copysign(0.42), 3.5_f64); assert_eq(3.5_f64.copysign(-0.42), -3.5_f64); assert_eq((-3.5_f64).copysign(0.42), 3.5_f64); assert_eq((-3.5_f64).copysign(-0.42), -3.5_f64); - assert!(std::f64::NAN.copysign(1.0).is_nan()); + assert!(f64::NAN.copysign(1.0).is_nan()); } From f462b4c25720db832b125b828bb474dd03628747 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 4 Apr 2020 13:35:30 +0200 Subject: [PATCH 1829/3747] memory reachable through globals is not a leak any more; adjust for better memory dumping --- src/machine.rs | 37 ++++++++++++++++++++--------- tests/run-pass/leak-in-static.rs | 8 +++++++ tests/run-pass/panic/catch_panic.rs | 3 --- 3 files changed, 34 insertions(+), 14 deletions(-) create mode 100644 tests/run-pass/leak-in-static.rs diff --git a/src/machine.rs b/src/machine.rs index f794453228b84..ab4fe4a2178d4 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -6,6 +6,7 @@ use std::cell::RefCell; use std::num::NonZeroU64; use std::rc::Rc; use std::time::Instant; +use std::fmt; use log::trace; use rand::rngs::StdRng; @@ -62,6 +63,31 @@ impl Into> for MiriMemoryKind { } } +impl MayLeak for MiriMemoryKind { + #[inline(always)] + fn may_leak(self) -> bool { + use self::MiriMemoryKind::*; + match self { + Rust | C | WinHeap | Env => false, + Machine | Global => true, + } + } +} + +impl fmt::Display for MiriMemoryKind { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + use self::MiriMemoryKind::*; + match self { + Rust => write!(f, "Rust heap"), + C => write!(f, "C heap"), + WinHeap => write!(f, "Windows heap"), + Machine => write!(f, "machine-managed memory"), + Env => write!(f, "environment variable"), + Global => write!(f, "global"), + } + } +} + /// Extra per-allocation data #[derive(Debug, Clone)] pub struct AllocExtra { @@ -491,14 +517,3 @@ impl AllocationExtra for AllocExtra { } } } - -impl MayLeak for MiriMemoryKind { - #[inline(always)] - fn may_leak(self) -> bool { - use self::MiriMemoryKind::*; - match self { - Rust | C | WinHeap | Env => false, - Machine | Global => true, - } - } -} diff --git a/tests/run-pass/leak-in-static.rs b/tests/run-pass/leak-in-static.rs new file mode 100644 index 0000000000000..b12cbbf6e64f7 --- /dev/null +++ b/tests/run-pass/leak-in-static.rs @@ -0,0 +1,8 @@ +static mut LEAKER: Option>> = None; + +fn main() { + // Having memory "leaked" in globals is allowed. + unsafe { + LEAKER = Some(Box::new(vec![0; 42])); + } +} diff --git a/tests/run-pass/panic/catch_panic.rs b/tests/run-pass/panic/catch_panic.rs index 6408c940d98a4..7689b85f76503 100644 --- a/tests/run-pass/panic/catch_panic.rs +++ b/tests/run-pass/panic/catch_panic.rs @@ -77,9 +77,6 @@ fn main() { test(None, |_old_val| { debug_assert!(false); loop {} }); test(None, |_old_val| { unsafe { (1 as *const i32).read() }; loop {} }); // trigger debug-assertion in libstd - // Cleanup: reset to default hook. - drop(std::panic::take_hook()); - eprintln!("Success!"); // Make sure we get this in stderr } From 7841f445932096adcf07944b707af73fc73830f1 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 7 Apr 2020 19:33:03 +0200 Subject: [PATCH 1830/3747] rustup --- rust-version | 2 +- tests/compile-fail/stack_free.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/rust-version b/rust-version index 6e980a4e228eb..b1fd330a9d665 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -e6cef0445779724b469ab7b9a8d3c05d9e848ca8 +42abbd8878d3b67238f3611b0587c704ba94f39c diff --git a/tests/compile-fail/stack_free.rs b/tests/compile-fail/stack_free.rs index ea09d3e2b44a6..50a590e448a6a 100644 --- a/tests/compile-fail/stack_free.rs +++ b/tests/compile-fail/stack_free.rs @@ -1,7 +1,7 @@ // Validation/SB changes why we fail // compile-flags: -Zmiri-disable-validation -Zmiri-disable-stacked-borrows -// error-pattern: deallocating `Stack` memory using `Machine(Rust)` deallocation operation +// error-pattern: deallocating stack variable memory using Rust heap deallocation operation fn main() { let x = 42; From 925465ebab87af43a40a32083f9db2799364c001 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 8 Apr 2020 11:39:35 +0200 Subject: [PATCH 1831/3747] more editing for CONTRIBUTING guide --- CONTRIBUTING.md | 69 ++++++++++++++++++++++++++----------------------- 1 file changed, 37 insertions(+), 32 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 50cfe14a28ebf..41dd7765145df 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -5,14 +5,14 @@ find useful. ## Getting started -Check out the issues on this GitHub repository for some ideas. There's lots that -needs to be done that we haven't documented in the issues yet, however. For more -ideas or help with hacking on Miri, you can contact us (`oli-obk` and `RalfJ`) -on the [Rust Zulip]. +Check out the issues on this GitHub repository for some ideas. In particular, +look for the green `E-*` labels which mark issues that should be rather +well-suited for onboarding. For more ideas or help with hacking on Miri, you can +contact us (`oli-obk` and `RalfJ`) on the [Rust Zulip]. [Rust Zulip]: https://rust-lang.zulipchat.com -## Building Miri with a pre-built rustc +## Preparing the build environment Miri heavily relies on internal rustc interfaces to execute MIR. Still, some things (like adding support for a new intrinsic or a shim for an external @@ -28,7 +28,11 @@ install that exact version of rustc as a toolchain: [`rustup-toolchain-install-master`]: https://github.com/kennytm/rustup-toolchain-install-master -Now building Miri is just one command away: +## Building and testing Miri + +Invoking Miri requires getting a bunch of flags right and setting up a custom +sysroot with xargo. The `miri` script takes care of that for you. With the +build environment prepared, compiling Miri is just one command away: ``` ./miri build @@ -37,32 +41,16 @@ Now building Miri is just one command away: Run `./miri` without arguments to see the other commands our build tool supports. -### Fixing Miri when rustc changes - -Miri is heavily tied to rustc internals, so it is very common that rustc changes -break Miri. Fixing those is a good way to get starting working on Miri. -Usually, Miri will require changes similar to the other consumers of the changed -rustc API, so reading the rustc PR diff is a good way to get an idea for what is -needed. - -To update the `rustc-version` file and install the latest rustc, you can run: -``` -./rustup-toolchain HEAD -``` - -Now try `./miri test`, and submit a PR once that works again. +### Testing the Miri driver -## Testing the Miri driver -[testing-miri]: #testing-the-miri-driver +The Miri driver in the `src/bin/miri.rs` binary is the "heart" of Miri: it is +basically a version of `rustc` that, instead of compiling your code, runs it. +It accepts all the same flags as `rustc` (though the ones only affecting code +generation and linking obviously will have no effect) [and more][miri-flags]. -The Miri driver in the `miri` binary is the "heart" of Miri: it is basically a -version of `rustc` that, instead of compiling your code, runs it. It accepts -all the same flags as `rustc` (though the ones only affecting code generation -and linking obviously will have no effect) [and more][miri-flags]. +[miri-flags]: README.md#miri--z-flags-and-environment-variables -Running the Miri driver requires some fiddling with environment variables, so -the `miri` script helps you do that. For example, you can (cross-)run the -driver on a particular file by doing +For example, you can (cross-)run the driver on a particular file by doing ```sh ./miri run tests/run-pass/format.rs @@ -99,7 +87,7 @@ MIRI_LOG=rustc_mir::interpret=info,miri::stacked_borrows ./miri run tests/run-pa In addition, you can set `MIRI_BACKTRACE=1` to get a backtrace of where an evaluation error was originally raised. -## Testing `cargo miri` +### Testing `cargo miri` Working with the driver directly gives you full control, but you also lose all the convenience provided by cargo. Once your test case depends on a crate, it @@ -117,7 +105,24 @@ There's a test for the cargo wrapper in the `test-cargo-miri` directory; run `./run-test.py` in there to execute it. Like `./miri test`, this respects the `MIRI_TEST_TARGET` environment variable to execute the test for another target. -## Building Miri with a locally built rustc +### Fixing Miri when rustc changes + +Miri is heavily tied to rustc internals, so it is very common that rustc changes +break Miri. Usually, Miri will require changes similar to the other consumers +of the changed rustc API, so reading the rustc PR diff is a good way to get an +idea for what is needed. + +To update the `rustc-version` file and install the latest rustc, you can run: +``` +./rustup-toolchain HEAD +``` + +Now try `./miri test`, and submit a PR once that works again. Even if you choose +not to use `./rustup-toolchain`, it is important that the `rustc-version` file +is updated, as our CI makes sure that Miri works well with that particular +version of rustc. + +## Advanced topic: Building Miri with a locally built rustc A big part of the Miri driver lives in rustc, so working on Miri will sometimes require using a locally built rustc. The bug you want to fix may actually be on @@ -143,4 +148,4 @@ rustup override set custom ``` With this, you should now have a working development setup! See -[above][testing-miri] for how to proceed working with the Miri driver. +[above](#building-and-testing-miri) for how to proceed working on Miri. From b1009c4aa5356163d91ef9b30d987e1633d04add Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 8 Apr 2020 12:30:45 +0200 Subject: [PATCH 1832/3747] more editing --- CONTRIBUTING.md | 44 ++++++++++++++++++++++++++------------------ 1 file changed, 26 insertions(+), 18 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 41dd7765145df..5862d2d402ae8 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -14,9 +14,9 @@ contact us (`oli-obk` and `RalfJ`) on the [Rust Zulip]. ## Preparing the build environment -Miri heavily relies on internal rustc interfaces to execute MIR. Still, some -things (like adding support for a new intrinsic or a shim for an external -function being called) can be done by working just on the Miri side. +Miri heavily relies on internal and unstable rustc interfaces to execute MIR, +which means it is important that you install a version of rustc that Miri +actually works with. The `rust-version` file contains the commit hash of rustc that Miri is currently tested against. Other versions will likely not work. After installing @@ -25,13 +25,15 @@ install that exact version of rustc as a toolchain: ``` ./rustup-toolchain ``` +This will set up a rustup toolchain called `miri` and set it as an override for +the current directory. [`rustup-toolchain-install-master`]: https://github.com/kennytm/rustup-toolchain-install-master ## Building and testing Miri Invoking Miri requires getting a bunch of flags right and setting up a custom -sysroot with xargo. The `miri` script takes care of that for you. With the +sysroot with xargo. The `miri` script takes care of that for you. With the build environment prepared, compiling Miri is just one command away: ``` @@ -76,7 +78,7 @@ MIRI_LOG=info ./miri run tests/run-pass/vecs.rs ``` Setting `MIRI_LOG` like this will configure logging for Miri itself as well as -the `rustc_middle::mir::interpret` and `rustc_mir::interpret` modules in rustc. You +the `rustc_middle::mir::interpret` and `rustc_mir::interpret` modules in rustc. You can also do more targeted configuration, e.g. the following helps debug the stacked borrows implementation: @@ -90,8 +92,8 @@ evaluation error was originally raised. ### Testing `cargo miri` Working with the driver directly gives you full control, but you also lose all -the convenience provided by cargo. Once your test case depends on a crate, it -is probably easier to test it with the cargo wrapper. You can install your +the convenience provided by cargo. Once your test case depends on a crate, it +is probably easier to test it with the cargo wrapper. You can install your development version of Miri using ``` @@ -105,27 +107,33 @@ There's a test for the cargo wrapper in the `test-cargo-miri` directory; run `./run-test.py` in there to execute it. Like `./miri test`, this respects the `MIRI_TEST_TARGET` environment variable to execute the test for another target. -### Fixing Miri when rustc changes +## Advanced topic: other build environments -Miri is heavily tied to rustc internals, so it is very common that rustc changes -break Miri. Usually, Miri will require changes similar to the other consumers -of the changed rustc API, so reading the rustc PR diff is a good way to get an -idea for what is needed. +We described above the simplest way to get a working build environment for Miri, +which is to use the version of rustc indicated by `rustc-version`. But +sometimes, that is not enough. + +### Updating `rustc-version` + +The `rustc-version` file is regularly updated to keep Miri close to the latest +version of rustc. Usually, new contributors do not have to worry about this. But +sometimes a newer rustc is needed for a patch, and sometimes Miri needs fixing +for changes in rustc. In both cases, `rustc-version` needs updating. To update the `rustc-version` file and install the latest rustc, you can run: ``` ./rustup-toolchain HEAD ``` -Now try `./miri test`, and submit a PR once that works again. Even if you choose -not to use `./rustup-toolchain`, it is important that the `rustc-version` file -is updated, as our CI makes sure that Miri works well with that particular -version of rustc. +Now edit Miri until `./miri test` passes, and submit a PR. Generally, it is +preferred to separate updating `rustc-version` and doing what it takes to get +Miri working again, from implementing new features that rely on the updated +rustc. This avoids blocking all Miri development on landing a big PR. -## Advanced topic: Building Miri with a locally built rustc +### Building Miri with a locally built rustc A big part of the Miri driver lives in rustc, so working on Miri will sometimes -require using a locally built rustc. The bug you want to fix may actually be on +require using a locally built rustc. The bug you want to fix may actually be on the rustc side, or you just need to get more detailed trace of the execution than what is possible with release builds -- in both cases, you should develop miri against a rustc you compiled yourself, with debug assertions (and hence From 4069302a8ce80b51c4a6ae4dcdeb4fb14a0f4e2c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 8 Apr 2020 15:17:26 +0200 Subject: [PATCH 1833/3747] add EbrCell to trophy case --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 1c2c885674a5d..efa38f8f739ed 100644 --- a/README.md +++ b/README.md @@ -259,6 +259,7 @@ Definite bugs found: * [`getrandom` calling the `getrandom` syscall in an invalid way](https://github.com/rust-random/getrandom/pull/73) * [`Vec`](https://github.com/rust-lang/rust/issues/69770) and [`BTreeMap`](https://github.com/rust-lang/rust/issues/69769) leaking memory under some (panicky) conditions * [Memory leak in `beef`](https://github.com/maciejhirsz/beef/issues/12) +* [Invalid use of undefined memory in `EbrCell`](https://github.com/Firstyear/concread/commit/b15be53b6ec076acb295a5c0483cdb4bf9be838f#diff-6282b2fc8e98bd089a1f0c86f648157cR229) Violations of [Stacked Borrows] found that are likely bugs (but Stacked Borrows is currently just an experiment): From fedca29e6979b77db1d4712dc62be041cf7f2d36 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 8 Apr 2020 15:56:59 +0200 Subject: [PATCH 1834/3747] tweak wording --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 5862d2d402ae8..a143190d5bdb7 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -45,7 +45,7 @@ supports. ### Testing the Miri driver -The Miri driver in the `src/bin/miri.rs` binary is the "heart" of Miri: it is +The Miri driver compiled from `src/bin/miri.rs` is the "heart" of Miri: it is basically a version of `rustc` that, instead of compiling your code, runs it. It accepts all the same flags as `rustc` (though the ones only affecting code generation and linking obviously will have no effect) [and more][miri-flags]. From d276d952ff448f1c1bdf9200fe1f9db00f2f1817 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 10 Apr 2020 10:27:59 +0200 Subject: [PATCH 1835/3747] fix unused warnings in tests --- tests/compile-fail/deallocate-bad-alignment.rs | 2 +- tests/compile-fail/deallocate-bad-size.rs | 2 +- tests/compile-fail/deallocate-twice.rs | 2 +- tests/compile-fail/reallocate-bad-size.rs | 2 +- tests/compile-fail/reallocate-change-alloc.rs | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/compile-fail/deallocate-bad-alignment.rs b/tests/compile-fail/deallocate-bad-alignment.rs index 9b5ee9a934b0b..621c05344b4ac 100644 --- a/tests/compile-fail/deallocate-bad-alignment.rs +++ b/tests/compile-fail/deallocate-bad-alignment.rs @@ -1,4 +1,4 @@ -use std::alloc::{alloc, dealloc, realloc, Layout}; +use std::alloc::{alloc, dealloc, Layout}; // error-pattern: allocation has size 1 and alignment 1, but gave size 1 and alignment 2 diff --git a/tests/compile-fail/deallocate-bad-size.rs b/tests/compile-fail/deallocate-bad-size.rs index 39a0d48c8b1a4..386bb56b90916 100644 --- a/tests/compile-fail/deallocate-bad-size.rs +++ b/tests/compile-fail/deallocate-bad-size.rs @@ -1,4 +1,4 @@ -use std::alloc::{alloc, dealloc, realloc, Layout}; +use std::alloc::{alloc, dealloc, Layout}; // error-pattern: allocation has size 1 and alignment 1, but gave size 2 and alignment 1 diff --git a/tests/compile-fail/deallocate-twice.rs b/tests/compile-fail/deallocate-twice.rs index 3c5e8e96360c7..67312b0d96dda 100644 --- a/tests/compile-fail/deallocate-twice.rs +++ b/tests/compile-fail/deallocate-twice.rs @@ -1,4 +1,4 @@ -use std::alloc::{alloc, dealloc, realloc, Layout}; +use std::alloc::{alloc, dealloc, Layout}; // error-pattern: dereferenced after this allocation got freed diff --git a/tests/compile-fail/reallocate-bad-size.rs b/tests/compile-fail/reallocate-bad-size.rs index bbdef4421b6c2..7826f26f9b8c6 100644 --- a/tests/compile-fail/reallocate-bad-size.rs +++ b/tests/compile-fail/reallocate-bad-size.rs @@ -1,4 +1,4 @@ -use std::alloc::{alloc, dealloc, realloc, Layout}; +use std::alloc::{alloc, realloc, Layout}; // error-pattern: allocation has size 1 and alignment 1, but gave size 2 and alignment 1 diff --git a/tests/compile-fail/reallocate-change-alloc.rs b/tests/compile-fail/reallocate-change-alloc.rs index 8130d72dee596..297029676962b 100644 --- a/tests/compile-fail/reallocate-change-alloc.rs +++ b/tests/compile-fail/reallocate-change-alloc.rs @@ -1,4 +1,4 @@ -use std::alloc::{alloc, dealloc, realloc, Layout}; +use std::alloc::{alloc, realloc, Layout}; fn main() { unsafe { From f77e0281c942f9f9df2db7ec5a52306fbaa75906 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 10 Apr 2020 10:28:07 +0200 Subject: [PATCH 1836/3747] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index b1fd330a9d665..40c0005e08067 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -42abbd8878d3b67238f3611b0587c704ba94f39c +0c835b0cca83fe21090562603e4bda77c183ace3 From 280394d366c0523f24a3a73e2e58650a5a4bfc1a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 10 Apr 2020 10:28:23 +0200 Subject: [PATCH 1837/3747] cargo update --- Cargo.lock | 234 +++++++++++++------------------------ test-cargo-miri/Cargo.lock | 35 +++--- 2 files changed, 91 insertions(+), 178 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b36418a1cbacf..f8ac5fe4b18be 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,7 +2,7 @@ # It is not intended for manual editing. [[package]] name = "aho-corasick" -version = "0.7.9" +version = "0.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -10,7 +10,7 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.26" +version = "1.0.28" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -28,8 +28,8 @@ name = "atty" version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "hermit-abi 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", + "hermit-abi 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -38,26 +38,6 @@ name = "autocfg" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "backtrace" -version = "0.3.45" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "backtrace-sys 0.1.33 (registry+https://github.com/rust-lang/crates.io-index)", - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-demangle 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "backtrace-sys" -version = "0.1.33" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cc 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "base64" version = "0.11.0" @@ -83,30 +63,17 @@ name = "byteorder" version = "1.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "c2-chacha" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "ppv-lite86 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "cargo_metadata" version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.48 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.106 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.106 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.51 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "cc" -version = "1.0.50" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "cfg-if" version = "0.1.10" @@ -138,16 +105,16 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "diff 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "filetime 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "filetime 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)", "getopts 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "miow 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "rustfix 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.48 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.3.6 (registry+https://github.com/rust-lang/crates.io-index)", + "rustfix 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.106 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.106 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.51 (registry+https://github.com/rust-lang/crates.io-index)", "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "tester 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -197,7 +164,7 @@ version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", "redox_users 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -210,37 +177,17 @@ dependencies = [ "atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", "humantime 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "termcolor 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "failure" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "backtrace 0.3.45 (registry+https://github.com/rust-lang/crates.io-index)", - "failure_derive 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "failure_derive" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "proc-macro2 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.16 (registry+https://github.com/rust-lang/crates.io-index)", - "synstructure 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "filetime" -version = "0.2.8" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -259,16 +206,16 @@ version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", "wasi 0.9.0+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "hermit-abi" -version = "0.1.8" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -296,7 +243,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "libc" -version = "0.2.67" +version = "0.2.68" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -317,7 +264,7 @@ name = "miow" version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "socket2 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)", + "socket2 0.3.12 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -338,10 +285,10 @@ dependencies = [ "rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-workspace-hack 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.48 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.106 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.51 (registry+https://github.com/rust-lang/crates.io-index)", "shell-escape 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "vergen 3.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "vergen 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -368,7 +315,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "proc-macro2" -version = "1.0.9" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -384,7 +331,7 @@ name = "quote" version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -393,18 +340,18 @@ version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_chacha 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rand_chacha" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "c2-chacha 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "ppv-lite86 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -441,18 +388,18 @@ dependencies = [ [[package]] name = "regex" -version = "1.3.4" +version = "1.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "aho-corasick 0.7.9 (registry+https://github.com/rust-lang/crates.io-index)", + "aho-corasick 0.7.10 (registry+https://github.com/rust-lang/crates.io-index)", "memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "regex-syntax 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)", + "regex-syntax 0.6.17 (registry+https://github.com/rust-lang/crates.io-index)", "thread_local 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "regex-syntax" -version = "0.6.16" +version = "0.6.17" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -474,11 +421,6 @@ dependencies = [ "crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "rustc-demangle" -version = "0.1.16" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "rustc-workspace-hack" version = "1.0.0" @@ -494,18 +436,18 @@ dependencies = [ [[package]] name = "rustfix" -version = "0.5.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "anyhow 1.0.26 (registry+https://github.com/rust-lang/crates.io-index)", + "anyhow 1.0.28 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.48 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.106 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.51 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "ryu" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -514,7 +456,7 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.106 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -524,30 +466,30 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "serde" -version = "1.0.104" +version = "1.0.106" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde_derive 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.106 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "serde_derive" -version = "1.0.104" +version = "1.0.106" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.16 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "serde_json" -version = "1.0.48" +version = "1.0.51" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "itoa 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", - "ryu 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)", + "ryu 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.106 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -557,33 +499,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "socket2" -version = "0.3.11" +version = "0.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "syn" -version = "1.0.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "proc-macro2 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "synstructure" -version = "0.12.3" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.16 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -593,7 +524,7 @@ version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", "remove_dir_all 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -614,7 +545,7 @@ name = "termcolor" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "winapi-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-util 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -623,7 +554,7 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "getopts 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", "term 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -640,7 +571,7 @@ name = "time" version = "0.1.42" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -657,12 +588,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "vergen" -version = "3.0.4" +version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "chrono 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", - "failure 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -686,7 +616,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "winapi-util" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -698,21 +628,17 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" [metadata] -"checksum aho-corasick 0.7.9 (registry+https://github.com/rust-lang/crates.io-index)" = "d5e63fd144e18ba274ae7095c0197a870a7b9468abc801dd62f190d80817d2ec" -"checksum anyhow 1.0.26 (registry+https://github.com/rust-lang/crates.io-index)" = "7825f6833612eb2414095684fcf6c635becf3ce97fe48cf6421321e93bfbd53c" +"checksum aho-corasick 0.7.10 (registry+https://github.com/rust-lang/crates.io-index)" = "8716408b8bc624ed7f65d223ddb9ac2d044c0547b6fa4b0d554f3a9540496ada" +"checksum anyhow 1.0.28 (registry+https://github.com/rust-lang/crates.io-index)" = "d9a60d744a80c30fcb657dfe2c1b22bcb3e814c1a1e3674f32bf5820b570fbff" "checksum arrayref 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544" "checksum arrayvec 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cff77d8686867eceff3105329d4698d96c2391c176d5d03adc90c7389162b5b8" "checksum atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" "checksum autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d" -"checksum backtrace 0.3.45 (registry+https://github.com/rust-lang/crates.io-index)" = "ad235dabf00f36301792cfe82499880ba54c6486be094d1047b02bacb67c14e8" -"checksum backtrace-sys 0.1.33 (registry+https://github.com/rust-lang/crates.io-index)" = "e17b52e737c40a7d75abca20b29a19a0eb7ba9fc72c5a72dd282a0a3c2c0dc35" "checksum base64 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b41b7ea54a0c9d92199de89e20e58d49f02f8e699814ef3fdf266f6f748d15c7" "checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" "checksum blake2b_simd 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)" = "d8fb2d74254a3a0b5cac33ac9f8ed0e44aa50378d9dbb2e5d83bd21ed1dc2c8a" "checksum byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de" -"checksum c2-chacha 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "214238caa1bf3a496ec3392968969cab8549f96ff30652c9e56885329315f6bb" "checksum cargo_metadata 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "46e3374c604fb39d1a2f35ed5e4a4e30e60d01fab49446e08f1b3e9a90aef202" -"checksum cc 1.0.50 (registry+https://github.com/rust-lang/crates.io-index)" = "95e28fa049fda1c330bcf9d723be7663a899c4679724b34c81e9f5a326aab8cd" "checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" "checksum chrono 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)" = "80094f509cf8b5ae86a4966a39b3ff66cd7e2a3e594accec3743ff3fabeab5b2" "checksum colored 1.9.3 (registry+https://github.com/rust-lang/crates.io-index)" = "f4ffc801dacf156c5854b9df4f425a626539c3a6ef7893cc0c5084a23f0b6c59" @@ -724,50 +650,46 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum dirs 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "13aea89a5c93364a98e9b37b2fa237effbb694d5cfe01c5b70941f7eb087d5e3" "checksum dirs-sys 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "afa0b23de8fd801745c471deffa6e12d248f962c9fd4b4c33787b055599bde7b" "checksum env_logger 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "44533bbbb3bb3c1fa17d9f2e4e38bbbaf8396ba82193c4cb1b6445d711445d36" -"checksum failure 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "b8529c2421efa3066a5cbd8063d2244603824daccb6936b079010bb2aa89464b" -"checksum failure_derive 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "030a733c8287d6213886dd487564ff5c8f6aae10278b3588ed177f9d18f8d231" -"checksum filetime 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "1ff6d4dab0aa0c8e6346d46052e93b13a16cf847b54ed357087c35011048cc7d" +"checksum filetime 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)" = "f59efc38004c988e4201d11d263b8171f49a2e7ec0bdbb71773433f271504a5e" "checksum getopts 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)" = "14dbbfd5c71d70241ecf9e6f13737f7b5ce823821063188d7e46c41d371eebd5" "checksum getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "7abc8dd8451921606d809ba32e95b6111925cd2906060d2dcc29c070220503eb" -"checksum hermit-abi 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "1010591b26bbfe835e9faeabeb11866061cc7dcebffd56ad7d0942d0e61aefd8" +"checksum hermit-abi 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "725cf19794cf90aa94e65050cb4191ff5d8fa87a498383774c47b332e3af952e" "checksum hex 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "644f9158b2f133fd50f5fb3242878846d9eb792e445c893805ff0e3824006e35" "checksum humantime 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f" "checksum itoa 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "b8b7a7c0c47db5545ed3fef7468ee7bb5b74691498139e4b3f6a20685dc6dd8e" "checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" -"checksum libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)" = "eb147597cdf94ed43ab7a9038716637d2d1bf2bc571da995d0028dec06bd3018" +"checksum libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)" = "dea0c0405123bba743ee3f91f49b1c7cfb684eef0da0a50110f758ccf24cdff0" "checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7" "checksum memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3728d817d99e5ac407411fa471ff9800a778d88a24685968b36824eaf4bee400" "checksum miow 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "396aa0f2003d7df8395cb93e09871561ccc3e785f0acb369170e8cc74ddf9226" "checksum num-integer 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "3f6ea62e9d81a77cd3ee9a2a5b9b609447857f3d358704331e4ef39eb247fcba" "checksum num-traits 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "c62be47e61d1842b9170f0fdeec8eba98e60e90e5446449a0545e5152acd7096" "checksum ppv-lite86 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "74490b50b9fbe561ac330df47c08f3f33073d2d00c150f719147d7c54522fa1b" -"checksum proc-macro2 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)" = "6c09721c6781493a2a492a96b5a5bf19b65917fe6728884e7c44dd0c60ca3435" +"checksum proc-macro2 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)" = "df246d292ff63439fea9bc8c0a270bed0e390d5ebd4db4ba15aba81111b5abe3" "checksum quick-error 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" "checksum quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2bdc6c187c65bca4260c9011c9e3132efe4909da44726bad24cf7572ae338d7f" "checksum rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" -"checksum rand_chacha 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "03a2a90da8c7523f554344f921aa97283eadf6ac484a6d2a7d0212fa7f8d6853" +"checksum rand_chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" "checksum rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" "checksum rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" "checksum redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)" = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84" "checksum redox_users 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "09b23093265f8d200fa7b4c2c76297f47e681c655f6f1285a8780d6a022f7431" -"checksum regex 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "322cf97724bea3ee221b78fe25ac9c46114ebb51747ad5babd51a2fc6a8235a8" -"checksum regex-syntax 0.6.16 (registry+https://github.com/rust-lang/crates.io-index)" = "1132f845907680735a84409c3bebc64d1364a5683ffbce899550cd09d5eaefc1" +"checksum regex 1.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7f6946991529684867e47d86474e3a6d0c0ab9b82d5821e314b1ede31fa3a4b3" +"checksum regex-syntax 0.6.17 (registry+https://github.com/rust-lang/crates.io-index)" = "7fe5bd57d1d7414c6b5ed48563a2c855d995ff777729dcd91c369ec7fea395ae" "checksum remove_dir_all 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4a83fa3702a688b9359eccba92d153ac33fd2e8462f9e0e3fdf155239ea7792e" "checksum rust-argon2 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2bc8af4bda8e1ff4932523b94d3dd20ee30a87232323eda55903ffd71d2fb017" -"checksum rustc-demangle 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "4c691c0e608126e00913e33f0ccf3727d5fc84573623b8d65b2df340b5201783" "checksum rustc-workspace-hack 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc71d2faa173b74b232dedc235e3ee1696581bb132fc116fa3626d6151a1a8fb" "checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" -"checksum rustfix 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "804b11883a5ce0ad0378fbf95a8dea59ee6b51c331a73b8f471b6bdaa3bd40c1" -"checksum ryu 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "bfa8506c1de11c9c4e4c38863ccbe02a305c8188e85a05a784c9e11e1c3910c8" +"checksum rustfix 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f2c50b74badcddeb8f7652fa8323ce440b95286f8e4b64ebfd871c609672704e" +"checksum ryu 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "535622e6be132bccd223f4bb2b8ac8d53cda3c7a6394944d3b2b33fb974f9d76" "checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" "checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" -"checksum serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)" = "414115f25f818d7dfccec8ee535d76949ae78584fc4f79a6f45a904bf8ab4449" -"checksum serde_derive 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)" = "128f9e303a5a29922045a830221b8f78ec74a5f544944f3d5984f8ec3895ef64" -"checksum serde_json 1.0.48 (registry+https://github.com/rust-lang/crates.io-index)" = "9371ade75d4c2d6cb154141b9752cf3781ec9c05e0e5cf35060e1e70ee7b9c25" +"checksum serde 1.0.106 (registry+https://github.com/rust-lang/crates.io-index)" = "36df6ac6412072f67cf767ebbde4133a5b2e88e76dc6187fa7104cd16f783399" +"checksum serde_derive 1.0.106 (registry+https://github.com/rust-lang/crates.io-index)" = "9e549e3abf4fb8621bd1609f11dfc9f5e50320802273b12f3811a67e6716ea6c" +"checksum serde_json 1.0.51 (registry+https://github.com/rust-lang/crates.io-index)" = "da07b57ee2623368351e9a0488bb0b261322a15a6e0ae53e243cbdc0f4208da9" "checksum shell-escape 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "170a13e64f2a51b77a45702ba77287f5c6829375b04a69cf2222acd17d0cfab9" -"checksum socket2 0.3.11 (registry+https://github.com/rust-lang/crates.io-index)" = "e8b74de517221a2cb01a53349cf54182acdc31a074727d3079068448c0676d85" -"checksum syn 1.0.16 (registry+https://github.com/rust-lang/crates.io-index)" = "123bd9499cfb380418d509322d7a6d52e5315f064fe4b3ad18a53d6b92c07859" -"checksum synstructure 0.12.3 (registry+https://github.com/rust-lang/crates.io-index)" = "67656ea1dc1b41b1451851562ea232ec2e5a80242139f7e679ceccfb5d61f545" +"checksum socket2 0.3.12 (registry+https://github.com/rust-lang/crates.io-index)" = "03088793f677dce356f3ccc2edb1b314ad191ab702a5de3faf49304f7e104918" +"checksum syn 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)" = "0df0eb663f387145cab623dea85b09c2c5b4b0aef44e945d928e682fce71bb03" "checksum tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9" "checksum term 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c0863a3345e70f61d613eab32ee046ccd1bcc5f9105fe402c61fcd0c13eeb8b5" "checksum termcolor 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb6bfa289a4d7c5766392812c0a1f4c1ba45afa1ad47803c11e1f407d846d75f" @@ -776,9 +698,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f" "checksum unicode-width 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "caaa9d531767d1ff2150b9332433f32a24622147e5ebb1f26409d5da67afd479" "checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" -"checksum vergen 3.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "6aba5e34f93dc7051dfad05b98a18e9156f27e7b431fe1d2398cb6061c0a1dba" +"checksum vergen 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4ce50d8996df1f85af15f2cd8d33daae6e479575123ef4314a51a70a230739cb" "checksum wasi 0.9.0+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)" = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" "checksum winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6" "checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" -"checksum winapi-util 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "4ccfbf554c6ad11084fb7517daca16cfdcaccbdadba4fc336f032a8b12c2ad80" +"checksum winapi-util 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "fa515c5163a99cc82bab70fd3bfdd36d827be85de63737b40fcef2ce084a436e" "checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/test-cargo-miri/Cargo.lock b/test-cargo-miri/Cargo.lock index f4d20ab8e1583..ecf71a5f437a9 100644 --- a/test-cargo-miri/Cargo.lock +++ b/test-cargo-miri/Cargo.lock @@ -5,14 +5,6 @@ name = "byteorder" version = "1.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "c2-chacha" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "ppv-lite86 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "cargo-miri-test" version = "0.1.0" @@ -33,21 +25,21 @@ version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", "wasi 0.9.0+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "hermit-abi" -version = "0.1.8" +version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "libc" -version = "0.2.67" +version = "0.2.68" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -55,8 +47,8 @@ name = "num_cpus" version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "hermit-abi 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", + "hermit-abi 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -70,8 +62,8 @@ version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_chacha 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand_pcg 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -79,10 +71,10 @@ dependencies = [ [[package]] name = "rand_chacha" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "c2-chacha 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "ppv-lite86 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -117,15 +109,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [metadata] "checksum byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de" -"checksum c2-chacha 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "214238caa1bf3a496ec3392968969cab8549f96ff30652c9e56885329315f6bb" "checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" "checksum getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "7abc8dd8451921606d809ba32e95b6111925cd2906060d2dcc29c070220503eb" -"checksum hermit-abi 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "1010591b26bbfe835e9faeabeb11866061cc7dcebffd56ad7d0942d0e61aefd8" -"checksum libc 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)" = "eb147597cdf94ed43ab7a9038716637d2d1bf2bc571da995d0028dec06bd3018" +"checksum hermit-abi 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "725cf19794cf90aa94e65050cb4191ff5d8fa87a498383774c47b332e3af952e" +"checksum libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)" = "dea0c0405123bba743ee3f91f49b1c7cfb684eef0da0a50110f758ccf24cdff0" "checksum num_cpus 1.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "46203554f085ff89c235cd12f7075f3233af9b11ed7c9e16dfe2560d03313ce6" "checksum ppv-lite86 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "74490b50b9fbe561ac330df47c08f3f33073d2d00c150f719147d7c54522fa1b" "checksum rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" -"checksum rand_chacha 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "03a2a90da8c7523f554344f921aa97283eadf6ac484a6d2a7d0212fa7f8d6853" +"checksum rand_chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" "checksum rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" "checksum rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" "checksum rand_pcg 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "16abd0c1b639e9eb4d7c50c0b8100b0d0f849be2349829c740fe8e6eb4816429" From 93027da5ed4ce1e98b39ec9b35ca93961ef8a723 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 10 Apr 2020 14:57:22 +0200 Subject: [PATCH 1838/3747] bump compiletest --- Cargo.lock | 6 +++--- Cargo.toml | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f8ac5fe4b18be..0dbf00e6c5665 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -101,7 +101,7 @@ dependencies = [ [[package]] name = "compiletest_rs" -version = "0.4.1" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "diff 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", @@ -275,7 +275,7 @@ dependencies = [ "byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", "cargo_metadata 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", "colored 1.9.3 (registry+https://github.com/rust-lang/crates.io-index)", - "compiletest_rs 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "compiletest_rs 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "directories 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", @@ -642,7 +642,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" "checksum chrono 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)" = "80094f509cf8b5ae86a4966a39b3ff66cd7e2a3e594accec3743ff3fabeab5b2" "checksum colored 1.9.3 (registry+https://github.com/rust-lang/crates.io-index)" = "f4ffc801dacf156c5854b9df4f425a626539c3a6ef7893cc0c5084a23f0b6c59" -"checksum compiletest_rs 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "46cc00afd45129f775f8f8ee57c1ae2f7aabdf9692b2d74e36b917b91277bc7c" +"checksum compiletest_rs 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9f737835bfbbe29ed1ff82d5137520338d7ed5bf1a1d4b9c1c7c58bb45b8fa29" "checksum constant_time_eq 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" "checksum crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8" "checksum diff 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "0e25ea47919b1560c4e3b7fe0aaab9becf5b84a10325ddf7db0f0ba5e1026499" diff --git a/Cargo.toml b/Cargo.toml index e788e775972af..8ccc9484c88b4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -57,7 +57,7 @@ serde = { version = "*", features = ["derive"] } vergen = "3" [dev-dependencies] -compiletest_rs = { version = "0.4", features = ["tmp"] } +compiletest_rs = { version = "0.5", features = ["tmp"] } colored = "1.6" [features] From ea37f580e4f521d9b1eeadea59ecc4fd579a594b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 11 Apr 2020 09:16:55 +0200 Subject: [PATCH 1839/3747] add push_str issue to trophy case --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index efa38f8f739ed..4968e66657121 100644 --- a/README.md +++ b/README.md @@ -269,6 +269,7 @@ Violations of [Stacked Borrows] found that are likely bugs (but Stacked Borrows * [`Vec::push` invalidating existing references into the vector](https://github.com/rust-lang/rust/issues/60847) * [`align_to_mut` violating uniqueness of mutable references](https://github.com/rust-lang/rust/issues/68549) * [Aliasing mutable references in `sized-chunks`](https://github.com/bodil/sized-chunks/issues/8) +* [`String::push_str` invalidating existing references into the string](https://github.com/rust-lang/rust/issues/70301) ## License From b2bf4ec2f5e6938dfcebe0690beabbef22652afb Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 11 Apr 2020 09:30:13 +0200 Subject: [PATCH 1840/3747] organize compile-fail tests in folders --- tests/compile-fail/{ => alloc}/deallocate-bad-alignment.rs | 0 tests/compile-fail/{ => alloc}/deallocate-bad-size.rs | 0 tests/compile-fail/{ => alloc}/deallocate-twice.rs | 0 tests/compile-fail/{ => alloc}/reallocate-bad-size.rs | 0 tests/compile-fail/{ => alloc}/reallocate-change-alloc.rs | 0 tests/compile-fail/{ => alloc}/reallocate-dangling.rs | 0 tests/compile-fail/{ => alloc}/stack_free.rs | 0 .../{ => dangling_pointers}/dangling_pointer_deref.rs | 0 .../{ => dangling_pointers}/dangling_zst_deref.rs | 0 .../compile-fail/{ => dangling_pointers}/deref-invalid-ptr.rs | 4 ++-- .../{ => dangling_pointers}/deref-partially-dangling.rs | 0 .../{ => dangling_pointers}/maybe_null_pointer_deref_zst.rs | 0 .../{ => dangling_pointers}/maybe_null_pointer_write_zst.rs | 0 .../{ => dangling_pointers}/out_of_bounds_read1.rs | 0 .../{ => dangling_pointers}/out_of_bounds_read2.rs | 0 .../{ => dangling_pointers}/wild_pointer_deref.rs | 0 .../{ => function_pointers}/cast_box_int_to_fn_ptr.rs | 0 tests/compile-fail/{ => function_pointers}/cast_fn_ptr1.rs | 0 tests/compile-fail/{ => function_pointers}/cast_fn_ptr2.rs | 0 tests/compile-fail/{ => function_pointers}/cast_fn_ptr3.rs | 0 tests/compile-fail/{ => function_pointers}/cast_fn_ptr4.rs | 0 tests/compile-fail/{ => function_pointers}/cast_fn_ptr5.rs | 0 .../{ => function_pointers}/cast_int_to_fn_ptr.rs | 0 tests/compile-fail/{ => function_pointers}/deref_fn_ptr.rs | 0 tests/compile-fail/{ => function_pointers}/execute_memory.rs | 0 tests/compile-fail/{ => function_pointers}/fn_ptr_offset.rs | 0 tests/compile-fail/{ => intrinsics}/assume.rs | 0 tests/compile-fail/{ => intrinsics}/copy_null.rs | 0 tests/compile-fail/{ => intrinsics}/copy_overflow.rs | 0 tests/compile-fail/{ => intrinsics}/copy_overlapping.rs | 0 tests/compile-fail/{ => intrinsics}/copy_unaligned.rs | 0 tests/compile-fail/{ => intrinsics}/ctlz_nonzero.rs | 0 tests/compile-fail/{ => intrinsics}/cttz_nonzero.rs | 0 tests/compile-fail/{ => intrinsics}/div-by-zero-1.rs | 0 tests/compile-fail/{ => intrinsics}/div-by-zero-2.rs | 0 tests/compile-fail/{ => intrinsics}/exact_div1.rs | 0 tests/compile-fail/{ => intrinsics}/exact_div2.rs | 0 tests/compile-fail/{ => intrinsics}/exact_div3.rs | 0 tests/compile-fail/{ => intrinsics}/exact_div4.rs | 0 tests/compile-fail/{ => intrinsics}/out_of_bounds_ptr_1.rs | 0 tests/compile-fail/{ => intrinsics}/out_of_bounds_ptr_2.rs | 0 .../{ => intrinsics}/overflowing-unchecked-rsh.rs | 0 tests/compile-fail/{ => intrinsics}/ptr_offset_0_plus_0.rs | 0 .../compile-fail/{ => intrinsics}/ptr_offset_int_plus_int.rs | 0 .../compile-fail/{ => intrinsics}/ptr_offset_int_plus_ptr.rs | 0 tests/compile-fail/{ => intrinsics}/ptr_offset_overflow.rs | 0 tests/compile-fail/{ => intrinsics}/ptr_offset_ptr_plus_0.rs | 0 tests/compile-fail/{ => intrinsics}/unchecked_add1.rs | 0 tests/compile-fail/{ => intrinsics}/unchecked_add2.rs | 0 tests/compile-fail/{ => intrinsics}/unchecked_div1.rs | 0 tests/compile-fail/{ => intrinsics}/unchecked_mul1.rs | 0 tests/compile-fail/{ => intrinsics}/unchecked_mul2.rs | 0 tests/compile-fail/{ => intrinsics}/unchecked_sub1.rs | 0 tests/compile-fail/{ => intrinsics}/unchecked_sub2.rs | 0 tests/compile-fail/{ => intrinsics}/write_bytes_null.rs | 0 tests/compile-fail/{ => intrinsics}/write_bytes_overflow.rs | 0 .../{ => sync}/libc_pthread_mutex_destroy_locked.rs | 0 .../{ => sync}/libc_pthread_mutex_normal_deadlock.rs | 0 .../{ => sync}/libc_pthread_mutex_normal_unlock_unlocked.rs | 0 .../{ => sync}/libc_pthread_rwlock_destroy_read_locked.rs | 0 .../{ => sync}/libc_pthread_rwlock_destroy_write_locked.rs | 0 .../{ => sync}/libc_pthread_rwlock_read_write_deadlock.rs | 0 .../{ => sync}/libc_pthread_rwlock_unlock_unlocked.rs | 0 .../{ => sync}/libc_pthread_rwlock_write_read_deadlock.rs | 0 .../{ => sync}/libc_pthread_rwlock_write_write_deadlock.rs | 0 tests/compile-fail/{ => unaligned_pointers}/alignment.rs | 0 .../compile-fail/{ => unaligned_pointers}/atomic_unaligned.rs | 0 .../{ => unaligned_pointers}/intptrcast_alignment_check.rs | 0 .../{ => unaligned_pointers}/reference_to_packed.rs | 0 tests/compile-fail/{ => unaligned_pointers}/unaligned_ptr1.rs | 0 tests/compile-fail/{ => unaligned_pointers}/unaligned_ptr2.rs | 0 tests/compile-fail/{ => unaligned_pointers}/unaligned_ptr3.rs | 0 .../{ => unaligned_pointers}/unaligned_ptr_zst.rs | 0 73 files changed, 2 insertions(+), 2 deletions(-) rename tests/compile-fail/{ => alloc}/deallocate-bad-alignment.rs (100%) rename tests/compile-fail/{ => alloc}/deallocate-bad-size.rs (100%) rename tests/compile-fail/{ => alloc}/deallocate-twice.rs (100%) rename tests/compile-fail/{ => alloc}/reallocate-bad-size.rs (100%) rename tests/compile-fail/{ => alloc}/reallocate-change-alloc.rs (100%) rename tests/compile-fail/{ => alloc}/reallocate-dangling.rs (100%) rename tests/compile-fail/{ => alloc}/stack_free.rs (100%) rename tests/compile-fail/{ => dangling_pointers}/dangling_pointer_deref.rs (100%) rename tests/compile-fail/{ => dangling_pointers}/dangling_zst_deref.rs (100%) rename tests/compile-fail/{ => dangling_pointers}/deref-invalid-ptr.rs (75%) rename tests/compile-fail/{ => dangling_pointers}/deref-partially-dangling.rs (100%) rename tests/compile-fail/{ => dangling_pointers}/maybe_null_pointer_deref_zst.rs (100%) rename tests/compile-fail/{ => dangling_pointers}/maybe_null_pointer_write_zst.rs (100%) rename tests/compile-fail/{ => dangling_pointers}/out_of_bounds_read1.rs (100%) rename tests/compile-fail/{ => dangling_pointers}/out_of_bounds_read2.rs (100%) rename tests/compile-fail/{ => dangling_pointers}/wild_pointer_deref.rs (100%) rename tests/compile-fail/{ => function_pointers}/cast_box_int_to_fn_ptr.rs (100%) rename tests/compile-fail/{ => function_pointers}/cast_fn_ptr1.rs (100%) rename tests/compile-fail/{ => function_pointers}/cast_fn_ptr2.rs (100%) rename tests/compile-fail/{ => function_pointers}/cast_fn_ptr3.rs (100%) rename tests/compile-fail/{ => function_pointers}/cast_fn_ptr4.rs (100%) rename tests/compile-fail/{ => function_pointers}/cast_fn_ptr5.rs (100%) rename tests/compile-fail/{ => function_pointers}/cast_int_to_fn_ptr.rs (100%) rename tests/compile-fail/{ => function_pointers}/deref_fn_ptr.rs (100%) rename tests/compile-fail/{ => function_pointers}/execute_memory.rs (100%) rename tests/compile-fail/{ => function_pointers}/fn_ptr_offset.rs (100%) rename tests/compile-fail/{ => intrinsics}/assume.rs (100%) rename tests/compile-fail/{ => intrinsics}/copy_null.rs (100%) rename tests/compile-fail/{ => intrinsics}/copy_overflow.rs (100%) rename tests/compile-fail/{ => intrinsics}/copy_overlapping.rs (100%) rename tests/compile-fail/{ => intrinsics}/copy_unaligned.rs (100%) rename tests/compile-fail/{ => intrinsics}/ctlz_nonzero.rs (100%) rename tests/compile-fail/{ => intrinsics}/cttz_nonzero.rs (100%) rename tests/compile-fail/{ => intrinsics}/div-by-zero-1.rs (100%) rename tests/compile-fail/{ => intrinsics}/div-by-zero-2.rs (100%) rename tests/compile-fail/{ => intrinsics}/exact_div1.rs (100%) rename tests/compile-fail/{ => intrinsics}/exact_div2.rs (100%) rename tests/compile-fail/{ => intrinsics}/exact_div3.rs (100%) rename tests/compile-fail/{ => intrinsics}/exact_div4.rs (100%) rename tests/compile-fail/{ => intrinsics}/out_of_bounds_ptr_1.rs (100%) rename tests/compile-fail/{ => intrinsics}/out_of_bounds_ptr_2.rs (100%) rename tests/compile-fail/{ => intrinsics}/overflowing-unchecked-rsh.rs (100%) rename tests/compile-fail/{ => intrinsics}/ptr_offset_0_plus_0.rs (100%) rename tests/compile-fail/{ => intrinsics}/ptr_offset_int_plus_int.rs (100%) rename tests/compile-fail/{ => intrinsics}/ptr_offset_int_plus_ptr.rs (100%) rename tests/compile-fail/{ => intrinsics}/ptr_offset_overflow.rs (100%) rename tests/compile-fail/{ => intrinsics}/ptr_offset_ptr_plus_0.rs (100%) rename tests/compile-fail/{ => intrinsics}/unchecked_add1.rs (100%) rename tests/compile-fail/{ => intrinsics}/unchecked_add2.rs (100%) rename tests/compile-fail/{ => intrinsics}/unchecked_div1.rs (100%) rename tests/compile-fail/{ => intrinsics}/unchecked_mul1.rs (100%) rename tests/compile-fail/{ => intrinsics}/unchecked_mul2.rs (100%) rename tests/compile-fail/{ => intrinsics}/unchecked_sub1.rs (100%) rename tests/compile-fail/{ => intrinsics}/unchecked_sub2.rs (100%) rename tests/compile-fail/{ => intrinsics}/write_bytes_null.rs (100%) rename tests/compile-fail/{ => intrinsics}/write_bytes_overflow.rs (100%) rename tests/compile-fail/{ => sync}/libc_pthread_mutex_destroy_locked.rs (100%) rename tests/compile-fail/{ => sync}/libc_pthread_mutex_normal_deadlock.rs (100%) rename tests/compile-fail/{ => sync}/libc_pthread_mutex_normal_unlock_unlocked.rs (100%) rename tests/compile-fail/{ => sync}/libc_pthread_rwlock_destroy_read_locked.rs (100%) rename tests/compile-fail/{ => sync}/libc_pthread_rwlock_destroy_write_locked.rs (100%) rename tests/compile-fail/{ => sync}/libc_pthread_rwlock_read_write_deadlock.rs (100%) rename tests/compile-fail/{ => sync}/libc_pthread_rwlock_unlock_unlocked.rs (100%) rename tests/compile-fail/{ => sync}/libc_pthread_rwlock_write_read_deadlock.rs (100%) rename tests/compile-fail/{ => sync}/libc_pthread_rwlock_write_write_deadlock.rs (100%) rename tests/compile-fail/{ => unaligned_pointers}/alignment.rs (100%) rename tests/compile-fail/{ => unaligned_pointers}/atomic_unaligned.rs (100%) rename tests/compile-fail/{ => unaligned_pointers}/intptrcast_alignment_check.rs (100%) rename tests/compile-fail/{ => unaligned_pointers}/reference_to_packed.rs (100%) rename tests/compile-fail/{ => unaligned_pointers}/unaligned_ptr1.rs (100%) rename tests/compile-fail/{ => unaligned_pointers}/unaligned_ptr2.rs (100%) rename tests/compile-fail/{ => unaligned_pointers}/unaligned_ptr3.rs (100%) rename tests/compile-fail/{ => unaligned_pointers}/unaligned_ptr_zst.rs (100%) diff --git a/tests/compile-fail/deallocate-bad-alignment.rs b/tests/compile-fail/alloc/deallocate-bad-alignment.rs similarity index 100% rename from tests/compile-fail/deallocate-bad-alignment.rs rename to tests/compile-fail/alloc/deallocate-bad-alignment.rs diff --git a/tests/compile-fail/deallocate-bad-size.rs b/tests/compile-fail/alloc/deallocate-bad-size.rs similarity index 100% rename from tests/compile-fail/deallocate-bad-size.rs rename to tests/compile-fail/alloc/deallocate-bad-size.rs diff --git a/tests/compile-fail/deallocate-twice.rs b/tests/compile-fail/alloc/deallocate-twice.rs similarity index 100% rename from tests/compile-fail/deallocate-twice.rs rename to tests/compile-fail/alloc/deallocate-twice.rs diff --git a/tests/compile-fail/reallocate-bad-size.rs b/tests/compile-fail/alloc/reallocate-bad-size.rs similarity index 100% rename from tests/compile-fail/reallocate-bad-size.rs rename to tests/compile-fail/alloc/reallocate-bad-size.rs diff --git a/tests/compile-fail/reallocate-change-alloc.rs b/tests/compile-fail/alloc/reallocate-change-alloc.rs similarity index 100% rename from tests/compile-fail/reallocate-change-alloc.rs rename to tests/compile-fail/alloc/reallocate-change-alloc.rs diff --git a/tests/compile-fail/reallocate-dangling.rs b/tests/compile-fail/alloc/reallocate-dangling.rs similarity index 100% rename from tests/compile-fail/reallocate-dangling.rs rename to tests/compile-fail/alloc/reallocate-dangling.rs diff --git a/tests/compile-fail/stack_free.rs b/tests/compile-fail/alloc/stack_free.rs similarity index 100% rename from tests/compile-fail/stack_free.rs rename to tests/compile-fail/alloc/stack_free.rs diff --git a/tests/compile-fail/dangling_pointer_deref.rs b/tests/compile-fail/dangling_pointers/dangling_pointer_deref.rs similarity index 100% rename from tests/compile-fail/dangling_pointer_deref.rs rename to tests/compile-fail/dangling_pointers/dangling_pointer_deref.rs diff --git a/tests/compile-fail/dangling_zst_deref.rs b/tests/compile-fail/dangling_pointers/dangling_zst_deref.rs similarity index 100% rename from tests/compile-fail/dangling_zst_deref.rs rename to tests/compile-fail/dangling_pointers/dangling_zst_deref.rs diff --git a/tests/compile-fail/deref-invalid-ptr.rs b/tests/compile-fail/dangling_pointers/deref-invalid-ptr.rs similarity index 75% rename from tests/compile-fail/deref-invalid-ptr.rs rename to tests/compile-fail/dangling_pointers/deref-invalid-ptr.rs index 561017293a165..e0bba8c7c730d 100644 --- a/tests/compile-fail/deref-invalid-ptr.rs +++ b/tests/compile-fail/dangling_pointers/deref-invalid-ptr.rs @@ -2,6 +2,6 @@ // compile-flags: -Zmiri-disable-validation fn main() { - let x = 2usize as *const u32; - let _y = unsafe { &*x as *const u32 }; //~ ERROR invalid use of 2 as a pointer + let x = 16usize as *const u32; + let _y = unsafe { &*x as *const u32 }; //~ ERROR invalid use of 16 as a pointer } diff --git a/tests/compile-fail/deref-partially-dangling.rs b/tests/compile-fail/dangling_pointers/deref-partially-dangling.rs similarity index 100% rename from tests/compile-fail/deref-partially-dangling.rs rename to tests/compile-fail/dangling_pointers/deref-partially-dangling.rs diff --git a/tests/compile-fail/maybe_null_pointer_deref_zst.rs b/tests/compile-fail/dangling_pointers/maybe_null_pointer_deref_zst.rs similarity index 100% rename from tests/compile-fail/maybe_null_pointer_deref_zst.rs rename to tests/compile-fail/dangling_pointers/maybe_null_pointer_deref_zst.rs diff --git a/tests/compile-fail/maybe_null_pointer_write_zst.rs b/tests/compile-fail/dangling_pointers/maybe_null_pointer_write_zst.rs similarity index 100% rename from tests/compile-fail/maybe_null_pointer_write_zst.rs rename to tests/compile-fail/dangling_pointers/maybe_null_pointer_write_zst.rs diff --git a/tests/compile-fail/out_of_bounds_read1.rs b/tests/compile-fail/dangling_pointers/out_of_bounds_read1.rs similarity index 100% rename from tests/compile-fail/out_of_bounds_read1.rs rename to tests/compile-fail/dangling_pointers/out_of_bounds_read1.rs diff --git a/tests/compile-fail/out_of_bounds_read2.rs b/tests/compile-fail/dangling_pointers/out_of_bounds_read2.rs similarity index 100% rename from tests/compile-fail/out_of_bounds_read2.rs rename to tests/compile-fail/dangling_pointers/out_of_bounds_read2.rs diff --git a/tests/compile-fail/wild_pointer_deref.rs b/tests/compile-fail/dangling_pointers/wild_pointer_deref.rs similarity index 100% rename from tests/compile-fail/wild_pointer_deref.rs rename to tests/compile-fail/dangling_pointers/wild_pointer_deref.rs diff --git a/tests/compile-fail/cast_box_int_to_fn_ptr.rs b/tests/compile-fail/function_pointers/cast_box_int_to_fn_ptr.rs similarity index 100% rename from tests/compile-fail/cast_box_int_to_fn_ptr.rs rename to tests/compile-fail/function_pointers/cast_box_int_to_fn_ptr.rs diff --git a/tests/compile-fail/cast_fn_ptr1.rs b/tests/compile-fail/function_pointers/cast_fn_ptr1.rs similarity index 100% rename from tests/compile-fail/cast_fn_ptr1.rs rename to tests/compile-fail/function_pointers/cast_fn_ptr1.rs diff --git a/tests/compile-fail/cast_fn_ptr2.rs b/tests/compile-fail/function_pointers/cast_fn_ptr2.rs similarity index 100% rename from tests/compile-fail/cast_fn_ptr2.rs rename to tests/compile-fail/function_pointers/cast_fn_ptr2.rs diff --git a/tests/compile-fail/cast_fn_ptr3.rs b/tests/compile-fail/function_pointers/cast_fn_ptr3.rs similarity index 100% rename from tests/compile-fail/cast_fn_ptr3.rs rename to tests/compile-fail/function_pointers/cast_fn_ptr3.rs diff --git a/tests/compile-fail/cast_fn_ptr4.rs b/tests/compile-fail/function_pointers/cast_fn_ptr4.rs similarity index 100% rename from tests/compile-fail/cast_fn_ptr4.rs rename to tests/compile-fail/function_pointers/cast_fn_ptr4.rs diff --git a/tests/compile-fail/cast_fn_ptr5.rs b/tests/compile-fail/function_pointers/cast_fn_ptr5.rs similarity index 100% rename from tests/compile-fail/cast_fn_ptr5.rs rename to tests/compile-fail/function_pointers/cast_fn_ptr5.rs diff --git a/tests/compile-fail/cast_int_to_fn_ptr.rs b/tests/compile-fail/function_pointers/cast_int_to_fn_ptr.rs similarity index 100% rename from tests/compile-fail/cast_int_to_fn_ptr.rs rename to tests/compile-fail/function_pointers/cast_int_to_fn_ptr.rs diff --git a/tests/compile-fail/deref_fn_ptr.rs b/tests/compile-fail/function_pointers/deref_fn_ptr.rs similarity index 100% rename from tests/compile-fail/deref_fn_ptr.rs rename to tests/compile-fail/function_pointers/deref_fn_ptr.rs diff --git a/tests/compile-fail/execute_memory.rs b/tests/compile-fail/function_pointers/execute_memory.rs similarity index 100% rename from tests/compile-fail/execute_memory.rs rename to tests/compile-fail/function_pointers/execute_memory.rs diff --git a/tests/compile-fail/fn_ptr_offset.rs b/tests/compile-fail/function_pointers/fn_ptr_offset.rs similarity index 100% rename from tests/compile-fail/fn_ptr_offset.rs rename to tests/compile-fail/function_pointers/fn_ptr_offset.rs diff --git a/tests/compile-fail/assume.rs b/tests/compile-fail/intrinsics/assume.rs similarity index 100% rename from tests/compile-fail/assume.rs rename to tests/compile-fail/intrinsics/assume.rs diff --git a/tests/compile-fail/copy_null.rs b/tests/compile-fail/intrinsics/copy_null.rs similarity index 100% rename from tests/compile-fail/copy_null.rs rename to tests/compile-fail/intrinsics/copy_null.rs diff --git a/tests/compile-fail/copy_overflow.rs b/tests/compile-fail/intrinsics/copy_overflow.rs similarity index 100% rename from tests/compile-fail/copy_overflow.rs rename to tests/compile-fail/intrinsics/copy_overflow.rs diff --git a/tests/compile-fail/copy_overlapping.rs b/tests/compile-fail/intrinsics/copy_overlapping.rs similarity index 100% rename from tests/compile-fail/copy_overlapping.rs rename to tests/compile-fail/intrinsics/copy_overlapping.rs diff --git a/tests/compile-fail/copy_unaligned.rs b/tests/compile-fail/intrinsics/copy_unaligned.rs similarity index 100% rename from tests/compile-fail/copy_unaligned.rs rename to tests/compile-fail/intrinsics/copy_unaligned.rs diff --git a/tests/compile-fail/ctlz_nonzero.rs b/tests/compile-fail/intrinsics/ctlz_nonzero.rs similarity index 100% rename from tests/compile-fail/ctlz_nonzero.rs rename to tests/compile-fail/intrinsics/ctlz_nonzero.rs diff --git a/tests/compile-fail/cttz_nonzero.rs b/tests/compile-fail/intrinsics/cttz_nonzero.rs similarity index 100% rename from tests/compile-fail/cttz_nonzero.rs rename to tests/compile-fail/intrinsics/cttz_nonzero.rs diff --git a/tests/compile-fail/div-by-zero-1.rs b/tests/compile-fail/intrinsics/div-by-zero-1.rs similarity index 100% rename from tests/compile-fail/div-by-zero-1.rs rename to tests/compile-fail/intrinsics/div-by-zero-1.rs diff --git a/tests/compile-fail/div-by-zero-2.rs b/tests/compile-fail/intrinsics/div-by-zero-2.rs similarity index 100% rename from tests/compile-fail/div-by-zero-2.rs rename to tests/compile-fail/intrinsics/div-by-zero-2.rs diff --git a/tests/compile-fail/exact_div1.rs b/tests/compile-fail/intrinsics/exact_div1.rs similarity index 100% rename from tests/compile-fail/exact_div1.rs rename to tests/compile-fail/intrinsics/exact_div1.rs diff --git a/tests/compile-fail/exact_div2.rs b/tests/compile-fail/intrinsics/exact_div2.rs similarity index 100% rename from tests/compile-fail/exact_div2.rs rename to tests/compile-fail/intrinsics/exact_div2.rs diff --git a/tests/compile-fail/exact_div3.rs b/tests/compile-fail/intrinsics/exact_div3.rs similarity index 100% rename from tests/compile-fail/exact_div3.rs rename to tests/compile-fail/intrinsics/exact_div3.rs diff --git a/tests/compile-fail/exact_div4.rs b/tests/compile-fail/intrinsics/exact_div4.rs similarity index 100% rename from tests/compile-fail/exact_div4.rs rename to tests/compile-fail/intrinsics/exact_div4.rs diff --git a/tests/compile-fail/out_of_bounds_ptr_1.rs b/tests/compile-fail/intrinsics/out_of_bounds_ptr_1.rs similarity index 100% rename from tests/compile-fail/out_of_bounds_ptr_1.rs rename to tests/compile-fail/intrinsics/out_of_bounds_ptr_1.rs diff --git a/tests/compile-fail/out_of_bounds_ptr_2.rs b/tests/compile-fail/intrinsics/out_of_bounds_ptr_2.rs similarity index 100% rename from tests/compile-fail/out_of_bounds_ptr_2.rs rename to tests/compile-fail/intrinsics/out_of_bounds_ptr_2.rs diff --git a/tests/compile-fail/overflowing-unchecked-rsh.rs b/tests/compile-fail/intrinsics/overflowing-unchecked-rsh.rs similarity index 100% rename from tests/compile-fail/overflowing-unchecked-rsh.rs rename to tests/compile-fail/intrinsics/overflowing-unchecked-rsh.rs diff --git a/tests/compile-fail/ptr_offset_0_plus_0.rs b/tests/compile-fail/intrinsics/ptr_offset_0_plus_0.rs similarity index 100% rename from tests/compile-fail/ptr_offset_0_plus_0.rs rename to tests/compile-fail/intrinsics/ptr_offset_0_plus_0.rs diff --git a/tests/compile-fail/ptr_offset_int_plus_int.rs b/tests/compile-fail/intrinsics/ptr_offset_int_plus_int.rs similarity index 100% rename from tests/compile-fail/ptr_offset_int_plus_int.rs rename to tests/compile-fail/intrinsics/ptr_offset_int_plus_int.rs diff --git a/tests/compile-fail/ptr_offset_int_plus_ptr.rs b/tests/compile-fail/intrinsics/ptr_offset_int_plus_ptr.rs similarity index 100% rename from tests/compile-fail/ptr_offset_int_plus_ptr.rs rename to tests/compile-fail/intrinsics/ptr_offset_int_plus_ptr.rs diff --git a/tests/compile-fail/ptr_offset_overflow.rs b/tests/compile-fail/intrinsics/ptr_offset_overflow.rs similarity index 100% rename from tests/compile-fail/ptr_offset_overflow.rs rename to tests/compile-fail/intrinsics/ptr_offset_overflow.rs diff --git a/tests/compile-fail/ptr_offset_ptr_plus_0.rs b/tests/compile-fail/intrinsics/ptr_offset_ptr_plus_0.rs similarity index 100% rename from tests/compile-fail/ptr_offset_ptr_plus_0.rs rename to tests/compile-fail/intrinsics/ptr_offset_ptr_plus_0.rs diff --git a/tests/compile-fail/unchecked_add1.rs b/tests/compile-fail/intrinsics/unchecked_add1.rs similarity index 100% rename from tests/compile-fail/unchecked_add1.rs rename to tests/compile-fail/intrinsics/unchecked_add1.rs diff --git a/tests/compile-fail/unchecked_add2.rs b/tests/compile-fail/intrinsics/unchecked_add2.rs similarity index 100% rename from tests/compile-fail/unchecked_add2.rs rename to tests/compile-fail/intrinsics/unchecked_add2.rs diff --git a/tests/compile-fail/unchecked_div1.rs b/tests/compile-fail/intrinsics/unchecked_div1.rs similarity index 100% rename from tests/compile-fail/unchecked_div1.rs rename to tests/compile-fail/intrinsics/unchecked_div1.rs diff --git a/tests/compile-fail/unchecked_mul1.rs b/tests/compile-fail/intrinsics/unchecked_mul1.rs similarity index 100% rename from tests/compile-fail/unchecked_mul1.rs rename to tests/compile-fail/intrinsics/unchecked_mul1.rs diff --git a/tests/compile-fail/unchecked_mul2.rs b/tests/compile-fail/intrinsics/unchecked_mul2.rs similarity index 100% rename from tests/compile-fail/unchecked_mul2.rs rename to tests/compile-fail/intrinsics/unchecked_mul2.rs diff --git a/tests/compile-fail/unchecked_sub1.rs b/tests/compile-fail/intrinsics/unchecked_sub1.rs similarity index 100% rename from tests/compile-fail/unchecked_sub1.rs rename to tests/compile-fail/intrinsics/unchecked_sub1.rs diff --git a/tests/compile-fail/unchecked_sub2.rs b/tests/compile-fail/intrinsics/unchecked_sub2.rs similarity index 100% rename from tests/compile-fail/unchecked_sub2.rs rename to tests/compile-fail/intrinsics/unchecked_sub2.rs diff --git a/tests/compile-fail/write_bytes_null.rs b/tests/compile-fail/intrinsics/write_bytes_null.rs similarity index 100% rename from tests/compile-fail/write_bytes_null.rs rename to tests/compile-fail/intrinsics/write_bytes_null.rs diff --git a/tests/compile-fail/write_bytes_overflow.rs b/tests/compile-fail/intrinsics/write_bytes_overflow.rs similarity index 100% rename from tests/compile-fail/write_bytes_overflow.rs rename to tests/compile-fail/intrinsics/write_bytes_overflow.rs diff --git a/tests/compile-fail/libc_pthread_mutex_destroy_locked.rs b/tests/compile-fail/sync/libc_pthread_mutex_destroy_locked.rs similarity index 100% rename from tests/compile-fail/libc_pthread_mutex_destroy_locked.rs rename to tests/compile-fail/sync/libc_pthread_mutex_destroy_locked.rs diff --git a/tests/compile-fail/libc_pthread_mutex_normal_deadlock.rs b/tests/compile-fail/sync/libc_pthread_mutex_normal_deadlock.rs similarity index 100% rename from tests/compile-fail/libc_pthread_mutex_normal_deadlock.rs rename to tests/compile-fail/sync/libc_pthread_mutex_normal_deadlock.rs diff --git a/tests/compile-fail/libc_pthread_mutex_normal_unlock_unlocked.rs b/tests/compile-fail/sync/libc_pthread_mutex_normal_unlock_unlocked.rs similarity index 100% rename from tests/compile-fail/libc_pthread_mutex_normal_unlock_unlocked.rs rename to tests/compile-fail/sync/libc_pthread_mutex_normal_unlock_unlocked.rs diff --git a/tests/compile-fail/libc_pthread_rwlock_destroy_read_locked.rs b/tests/compile-fail/sync/libc_pthread_rwlock_destroy_read_locked.rs similarity index 100% rename from tests/compile-fail/libc_pthread_rwlock_destroy_read_locked.rs rename to tests/compile-fail/sync/libc_pthread_rwlock_destroy_read_locked.rs diff --git a/tests/compile-fail/libc_pthread_rwlock_destroy_write_locked.rs b/tests/compile-fail/sync/libc_pthread_rwlock_destroy_write_locked.rs similarity index 100% rename from tests/compile-fail/libc_pthread_rwlock_destroy_write_locked.rs rename to tests/compile-fail/sync/libc_pthread_rwlock_destroy_write_locked.rs diff --git a/tests/compile-fail/libc_pthread_rwlock_read_write_deadlock.rs b/tests/compile-fail/sync/libc_pthread_rwlock_read_write_deadlock.rs similarity index 100% rename from tests/compile-fail/libc_pthread_rwlock_read_write_deadlock.rs rename to tests/compile-fail/sync/libc_pthread_rwlock_read_write_deadlock.rs diff --git a/tests/compile-fail/libc_pthread_rwlock_unlock_unlocked.rs b/tests/compile-fail/sync/libc_pthread_rwlock_unlock_unlocked.rs similarity index 100% rename from tests/compile-fail/libc_pthread_rwlock_unlock_unlocked.rs rename to tests/compile-fail/sync/libc_pthread_rwlock_unlock_unlocked.rs diff --git a/tests/compile-fail/libc_pthread_rwlock_write_read_deadlock.rs b/tests/compile-fail/sync/libc_pthread_rwlock_write_read_deadlock.rs similarity index 100% rename from tests/compile-fail/libc_pthread_rwlock_write_read_deadlock.rs rename to tests/compile-fail/sync/libc_pthread_rwlock_write_read_deadlock.rs diff --git a/tests/compile-fail/libc_pthread_rwlock_write_write_deadlock.rs b/tests/compile-fail/sync/libc_pthread_rwlock_write_write_deadlock.rs similarity index 100% rename from tests/compile-fail/libc_pthread_rwlock_write_write_deadlock.rs rename to tests/compile-fail/sync/libc_pthread_rwlock_write_write_deadlock.rs diff --git a/tests/compile-fail/alignment.rs b/tests/compile-fail/unaligned_pointers/alignment.rs similarity index 100% rename from tests/compile-fail/alignment.rs rename to tests/compile-fail/unaligned_pointers/alignment.rs diff --git a/tests/compile-fail/atomic_unaligned.rs b/tests/compile-fail/unaligned_pointers/atomic_unaligned.rs similarity index 100% rename from tests/compile-fail/atomic_unaligned.rs rename to tests/compile-fail/unaligned_pointers/atomic_unaligned.rs diff --git a/tests/compile-fail/intptrcast_alignment_check.rs b/tests/compile-fail/unaligned_pointers/intptrcast_alignment_check.rs similarity index 100% rename from tests/compile-fail/intptrcast_alignment_check.rs rename to tests/compile-fail/unaligned_pointers/intptrcast_alignment_check.rs diff --git a/tests/compile-fail/reference_to_packed.rs b/tests/compile-fail/unaligned_pointers/reference_to_packed.rs similarity index 100% rename from tests/compile-fail/reference_to_packed.rs rename to tests/compile-fail/unaligned_pointers/reference_to_packed.rs diff --git a/tests/compile-fail/unaligned_ptr1.rs b/tests/compile-fail/unaligned_pointers/unaligned_ptr1.rs similarity index 100% rename from tests/compile-fail/unaligned_ptr1.rs rename to tests/compile-fail/unaligned_pointers/unaligned_ptr1.rs diff --git a/tests/compile-fail/unaligned_ptr2.rs b/tests/compile-fail/unaligned_pointers/unaligned_ptr2.rs similarity index 100% rename from tests/compile-fail/unaligned_ptr2.rs rename to tests/compile-fail/unaligned_pointers/unaligned_ptr2.rs diff --git a/tests/compile-fail/unaligned_ptr3.rs b/tests/compile-fail/unaligned_pointers/unaligned_ptr3.rs similarity index 100% rename from tests/compile-fail/unaligned_ptr3.rs rename to tests/compile-fail/unaligned_pointers/unaligned_ptr3.rs diff --git a/tests/compile-fail/unaligned_ptr_zst.rs b/tests/compile-fail/unaligned_pointers/unaligned_ptr_zst.rs similarity index 100% rename from tests/compile-fail/unaligned_ptr_zst.rs rename to tests/compile-fail/unaligned_pointers/unaligned_ptr_zst.rs From c63c413331a14e58eb95f13494eea8d1bafa19b9 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 11 Apr 2020 09:32:34 +0200 Subject: [PATCH 1841/3747] a few more inf/nan/negz tests --- tests/run-pass/float.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/tests/run-pass/float.rs b/tests/run-pass/float.rs index 5acaf6a2a97cd..e7b59683d697e 100644 --- a/tests/run-pass/float.rs +++ b/tests/run-pass/float.rs @@ -18,9 +18,22 @@ fn main() { assert_eq(-{5.0_f64}, -5.0_f64); // infinities, NaN assert!((5.0_f32/0.0).is_infinite()); + assert_ne!({5.0_f32/0.0}, {-5.0_f32/0.0}); assert!((5.0_f64/0.0).is_infinite()); + assert_ne!({5.0_f64/0.0}, {5.0_f64/-0.0}); assert!((-5.0_f32).sqrt().is_nan()); assert!((-5.0_f64).sqrt().is_nan()); + assert_ne!(f32::NAN, f32::NAN); + assert_ne!(f64::NAN, f64::NAN); + // negative zero + let posz = 0.0f32; + let negz = -0.0f32; + assert_eq(posz, negz); + assert_ne!(posz.to_bits(), negz.to_bits()); + let posz = 0.0f64; + let negz = -0.0f64; + assert_eq(posz, negz); + assert_ne!(posz.to_bits(), negz.to_bits()); // byte-level transmute let x: u64 = unsafe { std::mem::transmute(42.0_f64) }; let y: f64 = unsafe { std::mem::transmute(x) }; From 5db01f7371ec40cd210979f29242f8c80ea2ef15 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 11 Apr 2020 10:30:55 +0200 Subject: [PATCH 1842/3747] copy lots of float-to-int cast tests from wasm test suite --- tests/run-pass/float.rs | 159 +++++++++++++++++++++++++++++++--------- 1 file changed, 123 insertions(+), 36 deletions(-) diff --git a/tests/run-pass/float.rs b/tests/run-pass/float.rs index e7b59683d697e..7eab7f1ed524b 100644 --- a/tests/run-pass/float.rs +++ b/tests/run-pass/float.rs @@ -11,6 +11,12 @@ fn assert_eq(x: T, y: T) { } fn main() { + basic(); + casts(); + ops(); +} + +fn basic() { // basic arithmetic assert_eq(6.0_f32*6.0_f32, 36.0_f32); assert_eq(6.0_f64*6.0_f64, 36.0_f64); @@ -41,57 +47,138 @@ fn main() { let x: u32 = unsafe { std::mem::transmute(42.0_f32) }; let y: f32 = unsafe { std::mem::transmute(x) }; assert_eq(y, 42.0_f32); +} + +fn casts() { + // f32 -> i32 + assert_eq::(0.0f32 as i32, 0); + assert_eq::(-0.0f32 as i32, 0); + assert_eq::(/*0x1p-149*/ f32::from_bits(0x00000001) as i32, 0); + assert_eq::(/*-0x1p-149*/ f32::from_bits(0x80000001) as i32, 0); + assert_eq::(/*0x1.19999ap+0*/ f32::from_bits(0x3f8ccccd) as i32, 1); + assert_eq::(/*-0x1.19999ap+0*/ f32::from_bits(0xbf8ccccd) as i32, -1); + assert_eq::(1.9f32 as i32, 1); + assert_eq::(-1.9f32 as i32, -1); + assert_eq::(5.0f32 as i32, 5); + assert_eq::(-5.0f32 as i32, -5); + assert_eq::(2147483520.0f32 as i32, 2147483520); + assert_eq::(-2147483648.0f32 as i32, -2147483648); + // unrepresentable casts + assert_eq::(2147483648.0f32 as i32, i32::MAX); + assert_eq::(-2147483904.0f32 as i32, i32::MIN); + assert_eq::(f32::MAX as i32, i32::MAX); + assert_eq::(f32::MIN as i32, i32::MIN); + assert_eq::(f32::INFINITY as i32, i32::MAX); + assert_eq::(f32::NEG_INFINITY as i32, i32::MIN); + assert_eq::(f32::NAN as i32, 0); + assert_eq::((-f32::NAN) as i32, 0); + + // f32 -> u32 + assert_eq::(0.0f32 as u32, 0); + assert_eq::(-0.0f32 as u32, 0); + assert_eq::(/*0x1p-149*/ f32::from_bits(0x00000001) as u32, 0); + assert_eq::(/*-0x1p-149*/ f32::from_bits(0x80000001) as u32, 0); + assert_eq::(/*0x1.19999ap+0*/ f32::from_bits(0x3f8ccccd) as u32, 1); + assert_eq::(1.9f32 as u32, 1); + assert_eq::(5.0f32 as u32, 5); + assert_eq::(2147483648.0f32 as u32, 0x8000_0000); + assert_eq::(4294967040.0f32 as u32, 0u32.wrapping_sub(256)); + assert_eq::(/*-0x1.ccccccp-1*/ f32::from_bits(0xbf666666) as u32, 0); + assert_eq::(/*-0x1.fffffep-1*/ f32::from_bits(0xbf7fffff) as u32, 0); + assert_eq::((u32::MAX-127) as f32 as u32, u32::MAX); // rounding loss + assert_eq::((u32::MAX-128) as f32 as u32, u32::MAX-255); // rounding loss + // unrepresentable casts + assert_eq::(4294967296.0f32 as u32, u32::MAX); + assert_eq::(-5.0f32 as u32, 0); + assert_eq::(f32::MAX as u32, u32::MAX); + assert_eq::(f32::MIN as u32, 0); + assert_eq::(f32::INFINITY as u32, u32::MAX); + assert_eq::(f32::NEG_INFINITY as u32, 0); + assert_eq::(f32::NAN as u32, 0); + assert_eq::((-f32::NAN) as u32, 0); - // f32 <-> int casts - assert_eq(5.0f32 as u32, 5); - assert_eq(-5.0f32 as u32, 0); - assert_eq(5.0f32 as i32, 5); - assert_eq(-5.0f32 as i32, -5); - assert_eq(f32::MAX as i32, i32::MAX); - assert_eq(f32::INFINITY as i32, i32::MAX); - assert_eq(f32::MAX as u32, u32::MAX); - assert_eq(f32::INFINITY as u32, u32::MAX); - assert_eq(f32::MIN as i32, i32::MIN); - assert_eq(f32::NEG_INFINITY as i32, i32::MIN); - assert_eq(f32::MIN as u32, 0); - assert_eq(f32::NEG_INFINITY as u32, 0); - assert_eq(f32::NAN as i32, 0); - assert_eq(f32::NAN as u32, 0); - assert_eq((u32::MAX-127) as f32 as u32, u32::MAX); // rounding loss - assert_eq((u32::MAX-128) as f32 as u32, u32::MAX-255); // rounding loss + // f32 -> i64 + assert_eq::(4294967296.0f32 as i64, 4294967296); + assert_eq::(-4294967296.0f32 as i64, -4294967296); + assert_eq::(9223371487098961920.0f32 as i64, 9223371487098961920); + assert_eq::(-9223372036854775808.0f32 as i64, -9223372036854775808); + + // f64 -> i32 + assert_eq::(0.0f64 as i32, 0); + assert_eq::(-0.0f64 as i32, 0); + assert_eq::(/*0x1.199999999999ap+0*/ f64::from_bits(0x3ff199999999999a) as i32, 1); + assert_eq::(/*-0x1.199999999999ap+0*/ f64::from_bits(0xbff199999999999a) as i32, -1); + assert_eq::(1.9f64 as i32, 1); + assert_eq::(-1.9f64 as i32, -1); + assert_eq::(1e8f64 as i32, 100_000_000); + assert_eq::(2147483647.0f64 as i32, 2147483647); + assert_eq::(-2147483648.0f64 as i32, -2147483648); + // unrepresentable casts + assert_eq::(2147483648.0f64 as i32, i32::MAX); + assert_eq::(-2147483649.0f64 as i32, i32::MIN); + + // f64 -> i64 + assert_eq::(0.0f64 as i64, 0); + assert_eq::(-0.0f64 as i64, 0); + assert_eq::(/*0x0.0000000000001p-1022*/ f64::from_bits(0x1) as i64, 0); + assert_eq::(/*-0x0.0000000000001p-1022*/ f64::from_bits(0x8000000000000001) as i64, 0); + assert_eq::(/*0x1.199999999999ap+0*/ f64::from_bits(0x3ff199999999999a) as i64, 1); + assert_eq::(/*-0x1.199999999999ap+0*/ f64::from_bits(0xbff199999999999a) as i64, -1); + assert_eq::(5.0f64 as i64, 5); + assert_eq::(5.9f64 as i64, 5); + assert_eq::(-5.0f64 as i64, -5); + assert_eq::(-5.9f64 as i64, -5); + assert_eq::(4294967296.0f64 as i64, 4294967296); + assert_eq::(-4294967296.0f64 as i64, -4294967296); + assert_eq::(9223372036854774784.0f64 as i64, 9223372036854774784); + assert_eq::(-9223372036854775808.0f64 as i64, -9223372036854775808); + // unrepresentable casts + assert_eq::(9223372036854775808.0f64 as i64, i64::MAX); + assert_eq::(-9223372036854777856.0f64 as i64, i64::MIN); + assert_eq::(f64::MAX as i64, i64::MAX); + assert_eq::(f64::MIN as i64, i64::MIN); + assert_eq::(f64::INFINITY as i64, i64::MAX); + assert_eq::(f64::NEG_INFINITY as i64, i64::MIN); + assert_eq::(f64::NAN as i64, 0); + assert_eq::((-f64::NAN) as i64, 0); + + // f64 -> u64 + assert_eq::(0.0f64 as u64, 0); + assert_eq::(-0.0f64 as u64, 0); + assert_eq::(5.0f64 as u64, 5); + assert_eq::(-5.0f64 as u64, 0); + assert_eq::(1e16f64 as u64, 10000000000000000); + assert_eq::((u64::MAX-1023) as f64 as u64, u64::MAX); // rounding loss + assert_eq::((u64::MAX-1024) as f64 as u64, u64::MAX-2047); // rounding loss + assert_eq::(9223372036854775808.0f64 as u64, 9223372036854775808); + // unrepresentable casts + assert_eq::(18446744073709551616.0f64 as u64, u64::MAX); + assert_eq::(f64::MAX as u64, u64::MAX); + assert_eq::(f64::MIN as u64, 0); + assert_eq::(f64::INFINITY as u64, u64::MAX); + assert_eq::(f64::NEG_INFINITY as u64, 0); + assert_eq::(f64::NAN as u64, 0); + assert_eq::((-f64::NAN) as u64, 0); + + // int -> f32 assert_eq(127i8 as f32, 127.0f32); assert_eq(i128::MIN as f32, -170141183460469231731687303715884105728.0f32); assert_eq(u128::MAX as f32, f32::INFINITY); // saturation - // f64 <-> int casts - assert_eq(5.0f64 as u64, 5); - assert_eq(-5.0f64 as u64, 0); - assert_eq(5.0f64 as i64, 5); - assert_eq(-5.0f64 as i64, -5); - assert_eq(f64::MAX as i64, i64::MAX); - assert_eq(f64::INFINITY as i64, i64::MAX); - assert_eq(f64::MAX as u64, u64::MAX); - assert_eq(f64::INFINITY as u64, u64::MAX); - assert_eq(f64::MIN as i64, i64::MIN); - assert_eq(f64::NEG_INFINITY as i64, i64::MIN); - assert_eq(f64::MIN as u64, 0); - assert_eq(f64::NEG_INFINITY as u64, 0); - assert_eq(f64::NAN as i64, 0); - assert_eq(f64::NAN as u64, 0); - assert_eq((u64::MAX-1023) as f64 as u64, u64::MAX); // rounding loss - assert_eq((u64::MAX-1024) as f64 as u64, u64::MAX-2047); // rounding loss - assert_eq(u128::MAX as f64 as u128, u128::MAX); + // int -> f64 assert_eq(i16::MIN as f64, -32768.0f64); assert_eq(u128::MAX as f64, 340282366920938463463374607431768211455.0f64); // even that fits... - // f32 <-> f64 casts + // f32 <-> f64 assert_eq(5.0f64 as f32, 5.0f32); assert_eq(5.0f32 as f64, 5.0f64); assert_eq(f64::MAX as f32, f32::INFINITY); assert_eq(f64::MIN as f32, f32::NEG_INFINITY); assert_eq(f32::INFINITY as f64, f64::INFINITY); assert_eq(f32::NEG_INFINITY as f64, f64::NEG_INFINITY); +} +fn ops() { // f32 min/max assert_eq((1.0 as f32).max(-1.0), 1.0); assert_eq((1.0 as f32).min(-1.0), -1.0); From faff175f3e0095d5ddabb83f290309ed0dcfcf44 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 11 Apr 2020 11:00:38 +0200 Subject: [PATCH 1843/3747] some some int-to-float and float-to-float cast tests from wasm test suite --- tests/run-pass/float.rs | 70 ++++++++++++++++++++++++++++++++--------- 1 file changed, 56 insertions(+), 14 deletions(-) diff --git a/tests/run-pass/float.rs b/tests/run-pass/float.rs index 7eab7f1ed524b..738df2f6c59e7 100644 --- a/tests/run-pass/float.rs +++ b/tests/run-pass/float.rs @@ -76,7 +76,7 @@ fn casts() { // f32 -> u32 assert_eq::(0.0f32 as u32, 0); assert_eq::(-0.0f32 as u32, 0); - assert_eq::(/*0x1p-149*/ f32::from_bits(0x00000001) as u32, 0); + assert_eq::(/*0x1p-149*/ f32::from_bits(0x1) as u32, 0); assert_eq::(/*-0x1p-149*/ f32::from_bits(0x80000001) as u32, 0); assert_eq::(/*0x1.19999ap+0*/ f32::from_bits(0x3f8ccccd) as u32, 1); assert_eq::(1.9f32 as u32, 1); @@ -161,21 +161,63 @@ fn casts() { assert_eq::((-f64::NAN) as u64, 0); // int -> f32 - assert_eq(127i8 as f32, 127.0f32); - assert_eq(i128::MIN as f32, -170141183460469231731687303715884105728.0f32); - assert_eq(u128::MAX as f32, f32::INFINITY); // saturation + assert_eq::(127i8 as f32, 127.0); + assert_eq::(2147483647i32 as f32, 2147483648.0); + assert_eq::((-2147483648i32) as f32, -2147483648.0); + assert_eq::(1234567890i32 as f32, /*0x1.26580cp+30*/ f32::from_bits(0x4e932c06)); + assert_eq::(16777217i32 as f32, 16777216.0); + assert_eq::((-16777217i32) as f32, -16777216.0); + assert_eq::(16777219i32 as f32, 16777220.0); + assert_eq::((-16777219i32) as f32, -16777220.0); + assert_eq::(0x7fffff4000000001i64 as f32, /*0x1.fffffep+62*/ f32::from_bits(0x5effffff)); + assert_eq::(0x8000004000000001u64 as i64 as f32, /*-0x1.fffffep+62*/ f32::from_bits(0xdeffffff)); + assert_eq::(0x0020000020000001i64 as f32, /*0x1.000002p+53*/ f32::from_bits(0x5a000001)); + assert_eq::(0xffdfffffdfffffffu64 as i64 as f32, /*-0x1.000002p+53*/ f32::from_bits(0xda000001)); + assert_eq::(i128::MIN as f32, -170141183460469231731687303715884105728.0f32); + assert_eq::(u128::MAX as f32, f32::INFINITY); // saturation // int -> f64 - assert_eq(i16::MIN as f64, -32768.0f64); - assert_eq(u128::MAX as f64, 340282366920938463463374607431768211455.0f64); // even that fits... - - // f32 <-> f64 - assert_eq(5.0f64 as f32, 5.0f32); - assert_eq(5.0f32 as f64, 5.0f64); - assert_eq(f64::MAX as f32, f32::INFINITY); - assert_eq(f64::MIN as f32, f32::NEG_INFINITY); - assert_eq(f32::INFINITY as f64, f64::INFINITY); - assert_eq(f32::NEG_INFINITY as f64, f64::NEG_INFINITY); + assert_eq::(127i8 as f64, 127.0); + assert_eq::(i16::MIN as f64, -32768.0f64); + assert_eq::(2147483647i32 as f64, 2147483647.0); + assert_eq::(-2147483648i32 as f64, -2147483648.0); + assert_eq::(987654321i32 as f64, 987654321.0); + assert_eq::(9223372036854775807i64 as f64, 9223372036854775807.0); + assert_eq::(-9223372036854775808i64 as f64, -9223372036854775808.0); + assert_eq::(4669201609102990i64 as f64, 4669201609102990.0); // Feigenbaum (?) + assert_eq::(9007199254740993i64 as f64, 9007199254740992.0); + assert_eq::(-9007199254740993i64 as f64, -9007199254740992.0); + assert_eq::(9007199254740995i64 as f64, 9007199254740996.0); + assert_eq::(-9007199254740995i64 as f64, -9007199254740996.0); + assert_eq::(u128::MAX as f64, 340282366920938463463374607431768211455.0f64); // even that fits... + + // f32 -> f64 + assert_eq::((0.0f32 as f64).to_bits(), 0.0f64.to_bits()); + assert_eq::(((-0.0f32) as f64).to_bits(), (-0.0f64).to_bits()); + assert_eq::(5.0f32 as f64, 5.0f64); + assert_eq::(/*0x1p-149*/ f32::from_bits(0x1) as f64, /*0x1p-149*/ f64::from_bits(0x36a0000000000000)); + assert_eq::(/*-0x1p-149*/ f32::from_bits(0x80000001) as f64, /*-0x1p-149*/ f64::from_bits(0xb6a0000000000000)); + assert_eq::(/*0x1.fffffep+127*/ f32::from_bits(0x7f7fffff) as f64, /*0x1.fffffep+127*/ f64::from_bits(0x47efffffe0000000)); + assert_eq::(/*-0x1.fffffep+127*/ (-f32::from_bits(0x7f7fffff)) as f64, /*-0x1.fffffep+127*/ -f64::from_bits(0x47efffffe0000000)); + assert_eq::(/*0x1p-119*/ f32::from_bits(0x4000000) as f64, /*0x1p-119*/ f64::from_bits(0x3880000000000000)); + assert_eq::(/*0x1.8f867ep+125*/ f32::from_bits(0x7e47c33f) as f64, 6.6382536710104395e+37); + assert_eq::(f32::INFINITY as f64, f64::INFINITY); + assert_eq::(f32::NEG_INFINITY as f64, f64::NEG_INFINITY); + + // f64 -> f32 + assert_eq::((0.0f64 as f32).to_bits(), 0.0f32.to_bits()); + assert_eq::(((-0.0f64) as f32).to_bits(), (-0.0f32).to_bits()); + assert_eq::(5.0f64 as f32, 5.0f32); + assert_eq::(/*0x0.0000000000001p-1022*/ f64::from_bits(0x1) as f32, 0.0); + assert_eq::(/*-0x0.0000000000001p-1022*/ (-f64::from_bits(0x1)) as f32, -0.0); + + assert_eq::(/*0x1.fffffe0000000p-127*/ f64::from_bits(0x380fffffe0000000) as f32, /*0x1p-149*/ f32::from_bits(0x800000)); + assert_eq::(/*0x1.4eae4f7024c7p+108*/ f64::from_bits(0x46b4eae4f7024c70) as f32, /*0x1.4eae5p+108*/ f32::from_bits(0x75a75728)); + + assert_eq::(f64::MAX as f32, f32::INFINITY); + assert_eq::(f64::MIN as f32, f32::NEG_INFINITY); + assert_eq::(f64::INFINITY as f32, f32::INFINITY); + assert_eq::(f64::NEG_INFINITY as f32, f32::NEG_INFINITY); } fn ops() { From e5e0ced87e04ee866b5064978b2d88115e03ffa3 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 11 Apr 2020 11:03:41 +0200 Subject: [PATCH 1844/3747] smoketest f32 fast-math intrinsics --- tests/run-pass/float_fast_math.rs | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/tests/run-pass/float_fast_math.rs b/tests/run-pass/float_fast_math.rs index ba7e6ac3ec063..8e5a88ff336a2 100644 --- a/tests/run-pass/float_fast_math.rs +++ b/tests/run-pass/float_fast_math.rs @@ -3,7 +3,19 @@ use std::intrinsics::{fadd_fast, fsub_fast, fmul_fast, fdiv_fast, frem_fast}; #[inline(never)] -pub fn test_operations(a: f64, b: f64) { +pub fn test_operations_f64(a: f64, b: f64) { + // make sure they all map to the correct operation + unsafe { + assert_eq!(fadd_fast(a, b), a + b); + assert_eq!(fsub_fast(a, b), a - b); + assert_eq!(fmul_fast(a, b), a * b); + assert_eq!(fdiv_fast(a, b), a / b); + assert_eq!(frem_fast(a, b), a % b); + } +} + +#[inline(never)] +pub fn test_operations_f32(a: f32, b: f32) { // make sure they all map to the correct operation unsafe { assert_eq!(fadd_fast(a, b), a + b); @@ -15,6 +27,8 @@ pub fn test_operations(a: f64, b: f64) { } fn main() { - test_operations(1., 2.); - test_operations(10., 5.); + test_operations_f64(1., 2.); + test_operations_f64(10., 5.); + test_operations_f32(11., 2.); + test_operations_f32(10., 15.); } From 97791a56da50a87a3d1c3e4290290d436f9931f7 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 12 Apr 2020 10:08:12 +0200 Subject: [PATCH 1845/3747] avoid ref in matches --- src/bin/cargo-miri.rs | 12 ++++++------ src/diagnostics.rs | 4 ++-- src/machine.rs | 6 +++--- src/mono_hash_map.rs | 2 +- src/shims/panic.rs | 2 +- src/shims/tls.rs | 6 +++--- 6 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 083918de0f3a0..dfb5a5a989125 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -115,7 +115,7 @@ fn list_targets() -> impl Iterator { get_arg_flag_value("--manifest-path").map(|m| Path::new(&m).canonicalize().unwrap()); let mut cmd = cargo_metadata::MetadataCommand::new(); - if let Some(ref manifest_path) = manifest_path { + if let Some(manifest_path) = manifest_path.as_ref() { cmd.manifest_path(manifest_path); } let mut metadata = if let Ok(metadata) = cmd.exec() { @@ -131,7 +131,7 @@ fn list_targets() -> impl Iterator { .iter() .position(|package| { let package_manifest_path = Path::new(&package.manifest_path); - if let Some(ref manifest_path) = manifest_path { + if let Some(manifest_path) = manifest_path.as_ref() { package_manifest_path == manifest_path } else { let current_dir = current_dir.as_ref().expect("could not read current directory"); @@ -368,7 +368,7 @@ path = "lib.rs" command.env("XARGO_HOME", &dir); command.env("XARGO_RUST_SRC", &rust_src); // Handle target flag. - if let Some(ref target) = target { + if let Some(target) = target.as_ref() { command.arg("--target").arg(&target); } // Finally run it! @@ -379,9 +379,9 @@ path = "lib.rs" // That should be it! But we need to figure out where xargo built stuff. // Unfortunately, it puts things into a different directory when the // architecture matches the host. - let is_host = match target { + let is_host = match target.as_ref() { None => true, - Some(target) => target == rustc_version::version_meta().unwrap().host, + Some(target) => target == &rustc_version::version_meta().unwrap().host, }; let sysroot = if is_host { dir.join("HOST") } else { PathBuf::from(dir) }; std::env::set_var("MIRI_SYSROOT", &sysroot); // pass the env var to the processes we spawn, which will turn it into "--sysroot" flags @@ -583,6 +583,6 @@ fn inside_cargo_rustc() { if !exit.success() { std::process::exit(exit.code().unwrap_or(42)); }, - Err(ref e) => panic!("error running {:?}:\n{:?}", command, e), + Err(e) => panic!("error running {:?}:\n{:?}", command, e), } } diff --git a/src/diagnostics.rs b/src/diagnostics.rs index 24e68934c66f8..90e532321e404 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -51,8 +51,8 @@ pub fn report_error<'tcx, 'mir>( ) -> Option { use InterpError::*; - let (title, helps) = match e.kind { - MachineStop(ref info) => { + let (title, helps) = match &e.kind { + MachineStop(info) => { let info = info.downcast_ref::().expect("invalid MachineStop payload"); use TerminationInfo::*; let title = match info { diff --git a/src/machine.rs b/src/machine.rs index 3c59837305066..612f1bb328cc4 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -518,7 +518,7 @@ impl AllocationExtra for AllocExtra { ptr: Pointer, size: Size, ) -> InterpResult<'tcx> { - if let Some(ref stacked_borrows) = alloc.extra.stacked_borrows { + if let Some(stacked_borrows) = alloc.extra.stacked_borrows.as_ref() { stacked_borrows.memory_read(ptr, size) } else { Ok(()) @@ -531,7 +531,7 @@ impl AllocationExtra for AllocExtra { ptr: Pointer, size: Size, ) -> InterpResult<'tcx> { - if let Some(ref mut stacked_borrows) = alloc.extra.stacked_borrows { + if let Some(stacked_borrows) = alloc.extra.stacked_borrows.as_mut() { stacked_borrows.memory_written(ptr, size) } else { Ok(()) @@ -544,7 +544,7 @@ impl AllocationExtra for AllocExtra { ptr: Pointer, size: Size, ) -> InterpResult<'tcx> { - if let Some(ref mut stacked_borrows) = alloc.extra.stacked_borrows { + if let Some(stacked_borrows) = alloc.extra.stacked_borrows.as_mut() { stacked_borrows.memory_deallocated(ptr, size) } else { Ok(()) diff --git a/src/mono_hash_map.rs b/src/mono_hash_map.rs index fc33126aa2e71..fb0169920ee28 100644 --- a/src/mono_hash_map.rs +++ b/src/mono_hash_map.rs @@ -64,7 +64,7 @@ impl AllocMap for MonoHashMap { self.0.borrow().iter().filter_map(move |(k, v)| f(k, &*v)).collect() } - /// The most interesting method: Providing a shared ref without + /// The most interesting method: Providing a shared reference without /// holding the `RefCell` open, and inserting new data if the key /// is not used yet. /// `vacant` is called if the key is not found in the map; diff --git a/src/shims/panic.rs b/src/shims/panic.rs index 33e47147a33ba..281fe1e671bb4 100644 --- a/src/shims/panic.rs +++ b/src/shims/panic.rs @@ -191,7 +191,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); match msg { - BoundsCheck { ref index, ref len } => { + BoundsCheck { index, len } => { // Forward to `panic_bounds_check` lang item. // First arg: index. diff --git a/src/shims/tls.rs b/src/shims/tls.rs index 36ad4bd9b6916..cba7dde53d81c 100644 --- a/src/shims/tls.rs +++ b/src/shims/tls.rs @@ -87,7 +87,7 @@ impl<'tcx> TlsData<'tcx> { pub fn store_tls(&mut self, key: TlsKey, new_data: Option>) -> InterpResult<'tcx> { match self.keys.get_mut(&key) { - Some(&mut TlsEntry { ref mut data, .. }) => { + Some(TlsEntry { data, .. }) => { trace!("TLS key {} stored: {:?}", key, new_data); *data = new_data; Ok(()) @@ -139,12 +139,12 @@ impl<'tcx> TlsData<'tcx> { Some(key) => Excluded(key), None => Unbounded, }; - for (&key, &mut TlsEntry { ref mut data, dtor }) in + for (&key, TlsEntry { data, dtor }) in thread_local.range_mut((start, Unbounded)) { if let Some(data_scalar) = *data { if let Some(dtor) = dtor { - let ret = Some((dtor, data_scalar, key)); + let ret = Some((*dtor, data_scalar, key)); *data = None; return ret; } From 314e7238cf5f5fa6030035814193df455d337ad7 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 12 Apr 2020 10:32:36 +0200 Subject: [PATCH 1846/3747] avoid a bunch of as_ref/as_mut --- src/bin/cargo-miri.rs | 14 +++++++------- src/machine.rs | 12 ++++++------ src/shims/panic.rs | 2 +- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index dfb5a5a989125..04020009c6943 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -115,7 +115,7 @@ fn list_targets() -> impl Iterator { get_arg_flag_value("--manifest-path").map(|m| Path::new(&m).canonicalize().unwrap()); let mut cmd = cargo_metadata::MetadataCommand::new(); - if let Some(manifest_path) = manifest_path.as_ref() { + if let Some(manifest_path) = &manifest_path { cmd.manifest_path(manifest_path); } let mut metadata = if let Ok(metadata) = cmd.exec() { @@ -131,7 +131,7 @@ fn list_targets() -> impl Iterator { .iter() .position(|package| { let package_manifest_path = Path::new(&package.manifest_path); - if let Some(manifest_path) = manifest_path.as_ref() { + if let Some(manifest_path) = &manifest_path { package_manifest_path == manifest_path } else { let current_dir = current_dir.as_ref().expect("could not read current directory"); @@ -368,8 +368,8 @@ path = "lib.rs" command.env("XARGO_HOME", &dir); command.env("XARGO_RUST_SRC", &rust_src); // Handle target flag. - if let Some(target) = target.as_ref() { - command.arg("--target").arg(&target); + if let Some(target) = &target { + command.arg("--target").arg(target); } // Finally run it! if command.status().expect("failed to run xargo").success().not() { @@ -379,7 +379,7 @@ path = "lib.rs" // That should be it! But we need to figure out where xargo built stuff. // Unfortunately, it puts things into a different directory when the // architecture matches the host. - let is_host = match target.as_ref() { + let is_host = match &target { None => true, Some(target) => target == &rustc_version::version_meta().unwrap().host, }; @@ -404,12 +404,12 @@ fn main() { return; } - if let Some("miri") = std::env::args().nth(1).as_ref().map(AsRef::as_ref) { + if let Some("miri") = std::env::args().nth(1).as_deref() { // This arm is for when `cargo miri` is called. We call `cargo check` for each applicable target, // but with the `RUSTC` env var set to the `cargo-miri` binary so that we come back in the other branch, // and dispatch the invocations to `rustc` and `miri`, respectively. in_cargo_miri(); - } else if let Some("rustc") = std::env::args().nth(1).as_ref().map(AsRef::as_ref) { + } else if let Some("rustc") = std::env::args().nth(1).as_deref() { // This arm is executed when `cargo-miri` runs `cargo check` with the `RUSTC_WRAPPER` env var set to itself: // dependencies get dispatched to `rustc`, the final test/binary to `miri`. inside_cargo_rustc(); diff --git a/src/machine.rs b/src/machine.rs index 612f1bb328cc4..72635f7bf57b0 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -429,7 +429,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { let kind = kind.expect("we set our STATIC_KIND so this cannot be None"); let alloc = alloc.into_owned(); let (stacks, base_tag) = - if let Some(stacked_borrows) = memory_extra.stacked_borrows.as_ref() { + if let Some(stacked_borrows) = &memory_extra.stacked_borrows { let (stacks, base_tag) = Stacks::new_allocation(id, alloc.size, Rc::clone(stacked_borrows), kind); (Some(stacks), base_tag) @@ -440,7 +440,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { let mut stacked_borrows = memory_extra.stacked_borrows.as_ref().map(|sb| sb.borrow_mut()); let alloc: Allocation = alloc.with_tags_and_extra( |alloc| { - if let Some(stacked_borrows) = stacked_borrows.as_mut() { + if let Some(stacked_borrows) = &mut stacked_borrows { // Only globals may already contain pointers at this point assert_eq!(kind, MiriMemoryKind::Global.into()); stacked_borrows.global_base_ptr(alloc) @@ -455,7 +455,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { #[inline(always)] fn tag_global_base_pointer(memory_extra: &MemoryExtra, id: AllocId) -> Self::PointerTag { - if let Some(stacked_borrows) = memory_extra.stacked_borrows.as_ref() { + if let Some(stacked_borrows) = &memory_extra.stacked_borrows { stacked_borrows.borrow_mut().global_base_ptr(id) } else { Tag::Untagged @@ -518,7 +518,7 @@ impl AllocationExtra for AllocExtra { ptr: Pointer, size: Size, ) -> InterpResult<'tcx> { - if let Some(stacked_borrows) = alloc.extra.stacked_borrows.as_ref() { + if let Some(stacked_borrows) = &alloc.extra.stacked_borrows { stacked_borrows.memory_read(ptr, size) } else { Ok(()) @@ -531,7 +531,7 @@ impl AllocationExtra for AllocExtra { ptr: Pointer, size: Size, ) -> InterpResult<'tcx> { - if let Some(stacked_borrows) = alloc.extra.stacked_borrows.as_mut() { + if let Some(stacked_borrows) = &mut alloc.extra.stacked_borrows { stacked_borrows.memory_written(ptr, size) } else { Ok(()) @@ -544,7 +544,7 @@ impl AllocationExtra for AllocExtra { ptr: Pointer, size: Size, ) -> InterpResult<'tcx> { - if let Some(stacked_borrows) = alloc.extra.stacked_borrows.as_mut() { + if let Some(stacked_borrows) = &mut alloc.extra.stacked_borrows { stacked_borrows.memory_deallocated(ptr, size) } else { Ok(()) diff --git a/src/shims/panic.rs b/src/shims/panic.rs index 281fe1e671bb4..1aec236a533c7 100644 --- a/src/shims/panic.rs +++ b/src/shims/panic.rs @@ -123,7 +123,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); trace!("handle_stack_pop(extra = {:?}, unwinding = {})", extra, unwinding); - if let Some(stacked_borrows) = this.memory.extra.stacked_borrows.as_ref() { + if let Some(stacked_borrows) = &this.memory.extra.stacked_borrows { stacked_borrows.borrow_mut().end_call(extra.call_id); } From 6414003ab96f30c7739a62722405f968d2d1a576 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 12 Apr 2020 11:01:59 +0200 Subject: [PATCH 1847/3747] organize intrinsics into groups --- src/shims/intrinsics.rs | 493 ++++++++++++++++++++-------------------- 1 file changed, 249 insertions(+), 244 deletions(-) diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 844eac398de81..de34f1a7b6cef 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -37,183 +37,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Some(p) => p, }; + // Then handle terminating intrinsics. match intrinsic_name { - "try" => return this.handle_try(args, dest, ret), - - "arith_offset" => { - let offset = this.read_scalar(args[1])?.to_machine_isize(this)?; - let ptr = this.read_scalar(args[0])?.not_undef()?; - - let pointee_ty = substs.type_at(0); - let pointee_size = i64::try_from(this.layout_of(pointee_ty)?.size.bytes()).unwrap(); - let offset = offset.overflowing_mul(pointee_size).0; - let result_ptr = ptr.ptr_wrapping_signed_offset(offset, this); - this.write_scalar(result_ptr, dest)?; - } - - "assume" => { - let cond = this.read_scalar(args[0])?.to_bool()?; - if !cond { - throw_ub_format!("`assume` intrinsic called with `false`"); - } - } - - "volatile_load" => { - let place = this.deref_operand(args[0])?; - this.copy_op(place.into(), dest)?; - } - - "volatile_store" => { - let place = this.deref_operand(args[0])?; - this.copy_op(args[1], place.into())?; - } - - #[rustfmt::skip] - | "atomic_load" - | "atomic_load_relaxed" - | "atomic_load_acq" - => { - let place = this.deref_operand(args[0])?; - let val = this.read_scalar(place.into())?; // make sure it fits into a scalar; otherwise it cannot be atomic - - // Check alignment requirements. Atomics must always be aligned to their size, - // even if the type they wrap would be less aligned (e.g. AtomicU64 on 32bit must - // be 8-aligned). - let align = Align::from_bytes(place.layout.size.bytes()).unwrap(); - this.memory.check_ptr_access(place.ptr, place.layout.size, align)?; - - this.write_scalar(val, dest)?; - } - - #[rustfmt::skip] - | "atomic_store" - | "atomic_store_relaxed" - | "atomic_store_rel" - => { - let place = this.deref_operand(args[0])?; - let val = this.read_scalar(args[1])?; // make sure it fits into a scalar; otherwise it cannot be atomic - - // Check alignment requirements. Atomics must always be aligned to their size, - // even if the type they wrap would be less aligned (e.g. AtomicU64 on 32bit must - // be 8-aligned). - let align = Align::from_bytes(place.layout.size.bytes()).unwrap(); - this.memory.check_ptr_access(place.ptr, place.layout.size, align)?; - - this.write_scalar(val, place.into())?; - } - - #[rustfmt::skip] - | "atomic_fence_acq" - | "atomic_fence_rel" - | "atomic_fence_acqrel" - | "atomic_fence" - | "atomic_singlethreadfence_acq" - | "atomic_singlethreadfence_rel" - | "atomic_singlethreadfence_acqrel" - | "atomic_singlethreadfence" - => { - // we are inherently singlethreaded and singlecored, this is a nop - } - - _ if intrinsic_name.starts_with("atomic_xchg") => { - let place = this.deref_operand(args[0])?; - let new = this.read_scalar(args[1])?; - let old = this.read_scalar(place.into())?; - - // Check alignment requirements. Atomics must always be aligned to their size, - // even if the type they wrap would be less aligned (e.g. AtomicU64 on 32bit must - // be 8-aligned). - let align = Align::from_bytes(place.layout.size.bytes()).unwrap(); - this.memory.check_ptr_access(place.ptr, place.layout.size, align)?; - - this.write_scalar(old, dest)?; // old value is returned - this.write_scalar(new, place.into())?; - } - - _ if intrinsic_name.starts_with("atomic_cxchg") => { - let place = this.deref_operand(args[0])?; - let expect_old = this.read_immediate(args[1])?; // read as immediate for the sake of `binary_op()` - let new = this.read_scalar(args[2])?; - let old = this.read_immediate(place.into())?; // read as immediate for the sake of `binary_op()` - - // Check alignment requirements. Atomics must always be aligned to their size, - // even if the type they wrap would be less aligned (e.g. AtomicU64 on 32bit must - // be 8-aligned). - let align = Align::from_bytes(place.layout.size.bytes()).unwrap(); - this.memory.check_ptr_access(place.ptr, place.layout.size, align)?; - - // `binary_op` will bail if either of them is not a scalar. - let eq = this.overflowing_binary_op(mir::BinOp::Eq, old, expect_old)?.0; - let res = Immediate::ScalarPair(old.to_scalar_or_undef(), eq.into()); - // Return old value. - this.write_immediate(res, dest)?; - // Update ptr depending on comparison. - if eq.to_bool()? { - this.write_scalar(new, place.into())?; - } - } - - #[rustfmt::skip] - | "atomic_or" - | "atomic_or_acq" - | "atomic_or_rel" - | "atomic_or_acqrel" - | "atomic_or_relaxed" - | "atomic_xor" - | "atomic_xor_acq" - | "atomic_xor_rel" - | "atomic_xor_acqrel" - | "atomic_xor_relaxed" - | "atomic_and" - | "atomic_and_acq" - | "atomic_and_rel" - | "atomic_and_acqrel" - | "atomic_and_relaxed" - | "atomic_nand" - | "atomic_nand_acq" - | "atomic_nand_rel" - | "atomic_nand_acqrel" - | "atomic_nand_relaxed" - | "atomic_xadd" - | "atomic_xadd_acq" - | "atomic_xadd_rel" - | "atomic_xadd_acqrel" - | "atomic_xadd_relaxed" - | "atomic_xsub" - | "atomic_xsub_acq" - | "atomic_xsub_rel" - | "atomic_xsub_acqrel" - | "atomic_xsub_relaxed" - => { - let place = this.deref_operand(args[0])?; - if !place.layout.ty.is_integral() { - bug!("Atomic arithmetic operations only work on integer types"); - } - let rhs = this.read_immediate(args[1])?; - let old = this.read_immediate(place.into())?; - - // Check alignment requirements. Atomics must always be aligned to their size, - // even if the type they wrap would be less aligned (e.g. AtomicU64 on 32bit must - // be 8-aligned). - let align = Align::from_bytes(place.layout.size.bytes()).unwrap(); - this.memory.check_ptr_access(place.ptr, place.layout.size, align)?; - - this.write_immediate(*old, dest)?; // old value is returned - let (op, neg) = match intrinsic_name.split('_').nth(1).unwrap() { - "or" => (mir::BinOp::BitOr, false), - "xor" => (mir::BinOp::BitXor, false), - "and" => (mir::BinOp::BitAnd, false), - "xadd" => (mir::BinOp::Add, false), - "xsub" => (mir::BinOp::Sub, false), - "nand" => (mir::BinOp::BitAnd, true), - _ => bug!(), - }; - // Atomics wrap around on overflow. - let val = this.binary_op(op, old, rhs)?; - let val = if neg { this.unary_op(mir::UnOp::Not, val)? } else { val }; - this.write_immediate(*val, place.into())?; - } - + // Raw memory accesses #[rustfmt::skip] | "copy" | "copy_nonoverlapping" @@ -240,6 +66,51 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } + "move_val_init" => { + let place = this.deref_operand(args[0])?; + this.copy_op(args[1], place.into())?; + } + + "volatile_load" => { + let place = this.deref_operand(args[0])?; + this.copy_op(place.into(), dest)?; + } + "volatile_store" => { + let place = this.deref_operand(args[0])?; + this.copy_op(args[1], place.into())?; + } + + "write_bytes" => { + let ty = substs.type_at(0); + let ty_layout = this.layout_of(ty)?; + let val_byte = this.read_scalar(args[1])?.to_u8()?; + let ptr = this.read_scalar(args[0])?.not_undef()?; + let count = this.read_scalar(args[2])?.to_machine_usize(this)?; + let byte_count = ty_layout.size.checked_mul(count, this) + .ok_or_else(|| err_ub_format!("overflow computing total size of `write_bytes`"))?; + this.memory + .write_bytes(ptr, iter::repeat(val_byte).take(byte_count.bytes() as usize))?; + } + + // Pointer arithmetic + "arith_offset" => { + let offset = this.read_scalar(args[1])?.to_machine_isize(this)?; + let ptr = this.read_scalar(args[0])?.not_undef()?; + + let pointee_ty = substs.type_at(0); + let pointee_size = i64::try_from(this.layout_of(pointee_ty)?.size.bytes()).unwrap(); + let offset = offset.overflowing_mul(pointee_size).0; + let result_ptr = ptr.ptr_wrapping_signed_offset(offset, this); + this.write_scalar(result_ptr, dest)?; + } + "offset" => { + let offset = this.read_scalar(args[1])?.to_machine_isize(this)?; + let ptr = this.read_scalar(args[0])?.not_undef()?; + let result_ptr = this.pointer_offset_inbounds(ptr, substs.type_at(0), offset)?; + this.write_scalar(result_ptr, dest)?; + } + + // Floating-point operations #[rustfmt::skip] | "sinf32" | "fabsf32" @@ -363,58 +234,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx }; this.write_scalar(Scalar::from_f64(res), dest)?; } - - "exact_div" => - this.exact_div(this.read_immediate(args[0])?, this.read_immediate(args[1])?, dest)?, - - "forget" => {} - - #[rustfmt::skip] - | "likely" - | "unlikely" - => { - // These just return their argument - let b = this.read_immediate(args[0])?; - this.write_immediate(*b, dest)?; - } - - "pref_align_of" => { - let ty = substs.type_at(0); - let layout = this.layout_of(ty)?; - let align = layout.align.pref.bytes(); - let align_val = Scalar::from_machine_usize(align, this); - this.write_scalar(align_val, dest)?; - } - - "move_val_init" => { - let place = this.deref_operand(args[0])?; - this.copy_op(args[1], place.into())?; - } - - "offset" => { - let offset = this.read_scalar(args[1])?.to_machine_isize(this)?; - let ptr = this.read_scalar(args[0])?.not_undef()?; - let result_ptr = this.pointer_offset_inbounds(ptr, substs.type_at(0), offset)?; - this.write_scalar(result_ptr, dest)?; - } - - "assert_inhabited" | - "assert_zero_valid" | - "assert_uninit_valid" => { - let ty = substs.type_at(0); - let layout = this.layout_of(ty)?; - // Abort here because the caller might not be panic safe. - if layout.abi.is_uninhabited() { - throw_machine_stop!(TerminationInfo::Abort(Some(format!("attempted to instantiate uninhabited type `{}`", ty)))) - } - if intrinsic_name == "assert_zero_valid" && !layout.might_permit_raw_init(this, /*zero:*/ true).unwrap() { - throw_machine_stop!(TerminationInfo::Abort(Some(format!("attempted to zero-initialize type `{}`, which is invalid", ty)))) - } - if intrinsic_name == "assert_uninit_valid" && !layout.might_permit_raw_init(this, /*zero:*/ false).unwrap() { - throw_machine_stop!(TerminationInfo::Abort(Some(format!("attempted to leave type `{}` uninitialized, which is invalid", ty)))) - } - } - + "powf32" => { // FIXME: Using host floats. let f = f32::from_bits(this.read_scalar(args[0])?.to_u32()?); @@ -459,12 +279,177 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_u64(f.powi(i).to_bits()), dest)?; } - "size_of_val" => { - let mplace = this.deref_operand(args[0])?; - let (size, _) = this - .size_and_align_of_mplace(mplace)? - .expect("size_of_val called on extern type"); - this.write_scalar(Scalar::from_machine_usize(size.bytes(), this), dest)?; + // Atomic operations + #[rustfmt::skip] + | "atomic_load" + | "atomic_load_relaxed" + | "atomic_load_acq" + => { + let place = this.deref_operand(args[0])?; + let val = this.read_scalar(place.into())?; // make sure it fits into a scalar; otherwise it cannot be atomic + + // Check alignment requirements. Atomics must always be aligned to their size, + // even if the type they wrap would be less aligned (e.g. AtomicU64 on 32bit must + // be 8-aligned). + let align = Align::from_bytes(place.layout.size.bytes()).unwrap(); + this.memory.check_ptr_access(place.ptr, place.layout.size, align)?; + + this.write_scalar(val, dest)?; + } + + #[rustfmt::skip] + | "atomic_store" + | "atomic_store_relaxed" + | "atomic_store_rel" + => { + let place = this.deref_operand(args[0])?; + let val = this.read_scalar(args[1])?; // make sure it fits into a scalar; otherwise it cannot be atomic + + // Check alignment requirements. Atomics must always be aligned to their size, + // even if the type they wrap would be less aligned (e.g. AtomicU64 on 32bit must + // be 8-aligned). + let align = Align::from_bytes(place.layout.size.bytes()).unwrap(); + this.memory.check_ptr_access(place.ptr, place.layout.size, align)?; + + this.write_scalar(val, place.into())?; + } + + #[rustfmt::skip] + | "atomic_fence_acq" + | "atomic_fence_rel" + | "atomic_fence_acqrel" + | "atomic_fence" + | "atomic_singlethreadfence_acq" + | "atomic_singlethreadfence_rel" + | "atomic_singlethreadfence_acqrel" + | "atomic_singlethreadfence" + => { + // we are inherently singlethreaded and singlecored, this is a nop + } + + _ if intrinsic_name.starts_with("atomic_xchg") => { + let place = this.deref_operand(args[0])?; + let new = this.read_scalar(args[1])?; + let old = this.read_scalar(place.into())?; + + // Check alignment requirements. Atomics must always be aligned to their size, + // even if the type they wrap would be less aligned (e.g. AtomicU64 on 32bit must + // be 8-aligned). + let align = Align::from_bytes(place.layout.size.bytes()).unwrap(); + this.memory.check_ptr_access(place.ptr, place.layout.size, align)?; + + this.write_scalar(old, dest)?; // old value is returned + this.write_scalar(new, place.into())?; + } + + _ if intrinsic_name.starts_with("atomic_cxchg") => { + let place = this.deref_operand(args[0])?; + let expect_old = this.read_immediate(args[1])?; // read as immediate for the sake of `binary_op()` + let new = this.read_scalar(args[2])?; + let old = this.read_immediate(place.into())?; // read as immediate for the sake of `binary_op()` + + // Check alignment requirements. Atomics must always be aligned to their size, + // even if the type they wrap would be less aligned (e.g. AtomicU64 on 32bit must + // be 8-aligned). + let align = Align::from_bytes(place.layout.size.bytes()).unwrap(); + this.memory.check_ptr_access(place.ptr, place.layout.size, align)?; + + // `binary_op` will bail if either of them is not a scalar. + let eq = this.overflowing_binary_op(mir::BinOp::Eq, old, expect_old)?.0; + let res = Immediate::ScalarPair(old.to_scalar_or_undef(), eq.into()); + // Return old value. + this.write_immediate(res, dest)?; + // Update ptr depending on comparison. + if eq.to_bool()? { + this.write_scalar(new, place.into())?; + } + } + + #[rustfmt::skip] + | "atomic_or" + | "atomic_or_acq" + | "atomic_or_rel" + | "atomic_or_acqrel" + | "atomic_or_relaxed" + | "atomic_xor" + | "atomic_xor_acq" + | "atomic_xor_rel" + | "atomic_xor_acqrel" + | "atomic_xor_relaxed" + | "atomic_and" + | "atomic_and_acq" + | "atomic_and_rel" + | "atomic_and_acqrel" + | "atomic_and_relaxed" + | "atomic_nand" + | "atomic_nand_acq" + | "atomic_nand_rel" + | "atomic_nand_acqrel" + | "atomic_nand_relaxed" + | "atomic_xadd" + | "atomic_xadd_acq" + | "atomic_xadd_rel" + | "atomic_xadd_acqrel" + | "atomic_xadd_relaxed" + | "atomic_xsub" + | "atomic_xsub_acq" + | "atomic_xsub_rel" + | "atomic_xsub_acqrel" + | "atomic_xsub_relaxed" + => { + let place = this.deref_operand(args[0])?; + if !place.layout.ty.is_integral() { + bug!("Atomic arithmetic operations only work on integer types"); + } + let rhs = this.read_immediate(args[1])?; + let old = this.read_immediate(place.into())?; + + // Check alignment requirements. Atomics must always be aligned to their size, + // even if the type they wrap would be less aligned (e.g. AtomicU64 on 32bit must + // be 8-aligned). + let align = Align::from_bytes(place.layout.size.bytes()).unwrap(); + this.memory.check_ptr_access(place.ptr, place.layout.size, align)?; + + this.write_immediate(*old, dest)?; // old value is returned + let (op, neg) = match intrinsic_name.split('_').nth(1).unwrap() { + "or" => (mir::BinOp::BitOr, false), + "xor" => (mir::BinOp::BitXor, false), + "and" => (mir::BinOp::BitAnd, false), + "xadd" => (mir::BinOp::Add, false), + "xsub" => (mir::BinOp::Sub, false), + "nand" => (mir::BinOp::BitAnd, true), + _ => bug!(), + }; + // Atomics wrap around on overflow. + let val = this.binary_op(op, old, rhs)?; + let val = if neg { this.unary_op(mir::UnOp::Not, val)? } else { val }; + this.write_immediate(*val, place.into())?; + } + + // Query type information + "assert_inhabited" | + "assert_zero_valid" | + "assert_uninit_valid" => { + let ty = substs.type_at(0); + let layout = this.layout_of(ty)?; + // Abort here because the caller might not be panic safe. + if layout.abi.is_uninhabited() { + throw_machine_stop!(TerminationInfo::Abort(Some(format!("attempted to instantiate uninhabited type `{}`", ty)))) + } + if intrinsic_name == "assert_zero_valid" && !layout.might_permit_raw_init(this, /*zero:*/ true).unwrap() { + throw_machine_stop!(TerminationInfo::Abort(Some(format!("attempted to zero-initialize type `{}`, which is invalid", ty)))) + } + if intrinsic_name == "assert_uninit_valid" && !layout.might_permit_raw_init(this, /*zero:*/ false).unwrap() { + throw_machine_stop!(TerminationInfo::Abort(Some(format!("attempted to leave type `{}` uninitialized, which is invalid", ty)))) + } + } + + "pref_align_of" => { + let ty = substs.type_at(0); + let layout = this.layout_of(ty)?; + let align = layout.align.pref.bytes(); + let align_val = Scalar::from_machine_usize(align, this); + this.write_scalar(align_val, dest)?; } #[rustfmt::skip] @@ -478,18 +463,38 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_machine_usize(align.bytes(), this), dest)?; } - "write_bytes" => { - let ty = substs.type_at(0); - let ty_layout = this.layout_of(ty)?; - let val_byte = this.read_scalar(args[1])?.to_u8()?; - let ptr = this.read_scalar(args[0])?.not_undef()?; - let count = this.read_scalar(args[2])?.to_machine_usize(this)?; - let byte_count = ty_layout.size.checked_mul(count, this) - .ok_or_else(|| err_ub_format!("overflow computing total size of `write_bytes`"))?; - this.memory - .write_bytes(ptr, iter::repeat(val_byte).take(byte_count.bytes() as usize))?; + "size_of_val" => { + let mplace = this.deref_operand(args[0])?; + let (size, _) = this + .size_and_align_of_mplace(mplace)? + .expect("size_of_val called on extern type"); + this.write_scalar(Scalar::from_machine_usize(size.bytes(), this), dest)?; + } + + // Other + "assume" => { + let cond = this.read_scalar(args[0])?.to_bool()?; + if !cond { + throw_ub_format!("`assume` intrinsic called with `false`"); + } + } + + "exact_div" => + this.exact_div(this.read_immediate(args[0])?, this.read_immediate(args[1])?, dest)?, + + "forget" => {} + + #[rustfmt::skip] + | "likely" + | "unlikely" + => { + // These just return their argument + let b = this.read_immediate(args[0])?; + this.write_immediate(*b, dest)?; } + "try" => return this.handle_try(args, dest, ret), + name => throw_unsup_format!("unimplemented intrinsic: {}", name), } From fd0957f5cd17e2b341c356ffc09b59eb81176eb0 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 12 Apr 2020 11:02:56 +0200 Subject: [PATCH 1848/3747] remove an intrinsic that was moved to rustc --- src/shims/intrinsics.rs | 8 -------- 1 file changed, 8 deletions(-) diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index de34f1a7b6cef..7c21ecee1d348 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -444,14 +444,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } - "pref_align_of" => { - let ty = substs.type_at(0); - let layout = this.layout_of(ty)?; - let align = layout.align.pref.bytes(); - let align_val = Scalar::from_machine_usize(align, this); - this.write_scalar(align_val, dest)?; - } - #[rustfmt::skip] | "min_align_of_val" | "align_of_val" From 2a3ce5d618d80a83ba0166e18b70a9ec69fd8f96 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 12 Apr 2020 11:04:18 +0200 Subject: [PATCH 1849/3747] there is no 'align_of_val' intrinsic --- src/shims/intrinsics.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 7c21ecee1d348..0f17bee008875 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -444,10 +444,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } - #[rustfmt::skip] - | "min_align_of_val" - | "align_of_val" - => { + "min_align_of_val" => { let mplace = this.deref_operand(args[0])?; let (_, align) = this .size_and_align_of_mplace(mplace)? From 8d1f5336c2dda92b007e8a4306315f7e81c76424 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 12 Apr 2020 11:07:37 +0200 Subject: [PATCH 1850/3747] also test unsafe cast intrinsic (happy cases) --- tests/run-pass/float.rs | 185 +++++++++++++++++++++++++++------------- 1 file changed, 125 insertions(+), 60 deletions(-) diff --git a/tests/run-pass/float.rs b/tests/run-pass/float.rs index 738df2f6c59e7..4c30cd01c4c00 100644 --- a/tests/run-pass/float.rs +++ b/tests/run-pass/float.rs @@ -10,6 +10,63 @@ fn assert_eq(x: T, y: T) { assert_eq!(x, y); } +trait FloatToInt: Copy { + fn cast(self) -> Int; + unsafe fn cast_unchecked(self) -> Int; +} + +impl FloatToInt for f32 { + fn cast(self) -> i8 { self as _ } + unsafe fn cast_unchecked(self) -> i8 { self.to_int_unchecked() } +} +impl FloatToInt for f32 { + fn cast(self) -> i32 { self as _ } + unsafe fn cast_unchecked(self) -> i32 { self.to_int_unchecked() } +} +impl FloatToInt for f32 { + fn cast(self) -> u32 { self as _ } + unsafe fn cast_unchecked(self) -> u32 { self.to_int_unchecked() } +} +impl FloatToInt for f32 { + fn cast(self) -> i64 { self as _ } + unsafe fn cast_unchecked(self) -> i64 { self.to_int_unchecked() } +} +impl FloatToInt for f32 { + fn cast(self) -> u64 { self as _ } + unsafe fn cast_unchecked(self) -> u64 { self.to_int_unchecked() } +} + +impl FloatToInt for f64 { + fn cast(self) -> i8 { self as _ } + unsafe fn cast_unchecked(self) -> i8 { self.to_int_unchecked() } +} +impl FloatToInt for f64 { + fn cast(self) -> i32 { self as _ } + unsafe fn cast_unchecked(self) -> i32 { self.to_int_unchecked() } +} +impl FloatToInt for f64 { + fn cast(self) -> u32 { self as _ } + unsafe fn cast_unchecked(self) -> u32 { self.to_int_unchecked() } +} +impl FloatToInt for f64 { + fn cast(self) -> i64 { self as _ } + unsafe fn cast_unchecked(self) -> i64 { self.to_int_unchecked() } +} +impl FloatToInt for f64 { + fn cast(self) -> u64 { self as _ } + unsafe fn cast_unchecked(self) -> u64 { self.to_int_unchecked() } +} + +/// Test this cast both via `as` and via `approx_unchecked` (i.e., it must not saturate). +#[track_caller] +#[inline(never)] +fn test_cast(x: F, y: I) + where F: FloatToInt, I: PartialEq + Debug +{ + assert_eq!(x.cast(), y); + assert_eq!(unsafe { x.cast_unchecked() }, y); +} + fn main() { basic(); casts(); @@ -50,19 +107,23 @@ fn basic() { } fn casts() { + // f32 -> i8 + test_cast::(127.99, 127); + test_cast::(-128.99, -128); + // f32 -> i32 - assert_eq::(0.0f32 as i32, 0); - assert_eq::(-0.0f32 as i32, 0); - assert_eq::(/*0x1p-149*/ f32::from_bits(0x00000001) as i32, 0); - assert_eq::(/*-0x1p-149*/ f32::from_bits(0x80000001) as i32, 0); - assert_eq::(/*0x1.19999ap+0*/ f32::from_bits(0x3f8ccccd) as i32, 1); - assert_eq::(/*-0x1.19999ap+0*/ f32::from_bits(0xbf8ccccd) as i32, -1); - assert_eq::(1.9f32 as i32, 1); - assert_eq::(-1.9f32 as i32, -1); - assert_eq::(5.0f32 as i32, 5); - assert_eq::(-5.0f32 as i32, -5); - assert_eq::(2147483520.0f32 as i32, 2147483520); - assert_eq::(-2147483648.0f32 as i32, -2147483648); + test_cast::(0.0, 0); + test_cast::(-0.0, 0); + test_cast::(/*0x1p-149*/ f32::from_bits(0x00000001), 0); + test_cast::(/*-0x1p-149*/ f32::from_bits(0x80000001), 0); + test_cast::(/*0x1.19999ap+0*/ f32::from_bits(0x3f8ccccd), 1); + test_cast::(/*-0x1.19999ap+0*/ f32::from_bits(0xbf8ccccd), -1); + test_cast::(1.9, 1); + test_cast::(-1.9, -1); + test_cast::(5.0, 5); + test_cast::(-5.0, -5); + test_cast::(2147483520.0, 2147483520); + test_cast::(-2147483648.0, -2147483648); // unrepresentable casts assert_eq::(2147483648.0f32 as i32, i32::MAX); assert_eq::(-2147483904.0f32 as i32, i32::MIN); @@ -74,19 +135,19 @@ fn casts() { assert_eq::((-f32::NAN) as i32, 0); // f32 -> u32 - assert_eq::(0.0f32 as u32, 0); - assert_eq::(-0.0f32 as u32, 0); - assert_eq::(/*0x1p-149*/ f32::from_bits(0x1) as u32, 0); - assert_eq::(/*-0x1p-149*/ f32::from_bits(0x80000001) as u32, 0); - assert_eq::(/*0x1.19999ap+0*/ f32::from_bits(0x3f8ccccd) as u32, 1); - assert_eq::(1.9f32 as u32, 1); - assert_eq::(5.0f32 as u32, 5); - assert_eq::(2147483648.0f32 as u32, 0x8000_0000); - assert_eq::(4294967040.0f32 as u32, 0u32.wrapping_sub(256)); - assert_eq::(/*-0x1.ccccccp-1*/ f32::from_bits(0xbf666666) as u32, 0); - assert_eq::(/*-0x1.fffffep-1*/ f32::from_bits(0xbf7fffff) as u32, 0); - assert_eq::((u32::MAX-127) as f32 as u32, u32::MAX); // rounding loss - assert_eq::((u32::MAX-128) as f32 as u32, u32::MAX-255); // rounding loss + test_cast::(0.0, 0); + test_cast::(-0.0, 0); + test_cast::(/*0x1p-149*/ f32::from_bits(0x1), 0); + test_cast::(/*-0x1p-149*/ f32::from_bits(0x80000001), 0); + test_cast::(/*0x1.19999ap+0*/ f32::from_bits(0x3f8ccccd), 1); + test_cast::(1.9, 1); + test_cast::(5.0, 5); + test_cast::(2147483648.0, 0x8000_0000); + test_cast::(4294967040.0, 0u32.wrapping_sub(256)); + test_cast::(/*-0x1.ccccccp-1*/ f32::from_bits(0xbf666666), 0); + test_cast::(/*-0x1.fffffep-1*/ f32::from_bits(0xbf7fffff), 0); + test_cast::((u32::MAX-127) as f32, u32::MAX); // rounding loss + test_cast::((u32::MAX-128) as f32, u32::MAX-255); // rounding loss // unrepresentable casts assert_eq::(4294967296.0f32 as u32, u32::MAX); assert_eq::(-5.0f32 as u32, 0); @@ -98,40 +159,44 @@ fn casts() { assert_eq::((-f32::NAN) as u32, 0); // f32 -> i64 - assert_eq::(4294967296.0f32 as i64, 4294967296); - assert_eq::(-4294967296.0f32 as i64, -4294967296); - assert_eq::(9223371487098961920.0f32 as i64, 9223371487098961920); - assert_eq::(-9223372036854775808.0f32 as i64, -9223372036854775808); + test_cast::(4294967296.0, 4294967296); + test_cast::(-4294967296.0, -4294967296); + test_cast::(9223371487098961920.0, 9223371487098961920); + test_cast::(-9223372036854775808.0, -9223372036854775808); + + // f64 -> i8 + test_cast::(127.99, 127); + test_cast::(-128.99, -128); // f64 -> i32 - assert_eq::(0.0f64 as i32, 0); - assert_eq::(-0.0f64 as i32, 0); - assert_eq::(/*0x1.199999999999ap+0*/ f64::from_bits(0x3ff199999999999a) as i32, 1); - assert_eq::(/*-0x1.199999999999ap+0*/ f64::from_bits(0xbff199999999999a) as i32, -1); - assert_eq::(1.9f64 as i32, 1); - assert_eq::(-1.9f64 as i32, -1); - assert_eq::(1e8f64 as i32, 100_000_000); - assert_eq::(2147483647.0f64 as i32, 2147483647); - assert_eq::(-2147483648.0f64 as i32, -2147483648); + test_cast::(0.0, 0); + test_cast::(-0.0, 0); + test_cast::(/*0x1.199999999999ap+0*/ f64::from_bits(0x3ff199999999999a), 1); + test_cast::(/*-0x1.199999999999ap+0*/ f64::from_bits(0xbff199999999999a), -1); + test_cast::(1.9, 1); + test_cast::(-1.9, -1); + test_cast::(1e8, 100_000_000); + test_cast::(2147483647.0, 2147483647); + test_cast::(-2147483648.0, -2147483648); // unrepresentable casts assert_eq::(2147483648.0f64 as i32, i32::MAX); assert_eq::(-2147483649.0f64 as i32, i32::MIN); // f64 -> i64 - assert_eq::(0.0f64 as i64, 0); - assert_eq::(-0.0f64 as i64, 0); - assert_eq::(/*0x0.0000000000001p-1022*/ f64::from_bits(0x1) as i64, 0); - assert_eq::(/*-0x0.0000000000001p-1022*/ f64::from_bits(0x8000000000000001) as i64, 0); - assert_eq::(/*0x1.199999999999ap+0*/ f64::from_bits(0x3ff199999999999a) as i64, 1); - assert_eq::(/*-0x1.199999999999ap+0*/ f64::from_bits(0xbff199999999999a) as i64, -1); - assert_eq::(5.0f64 as i64, 5); - assert_eq::(5.9f64 as i64, 5); - assert_eq::(-5.0f64 as i64, -5); - assert_eq::(-5.9f64 as i64, -5); - assert_eq::(4294967296.0f64 as i64, 4294967296); - assert_eq::(-4294967296.0f64 as i64, -4294967296); - assert_eq::(9223372036854774784.0f64 as i64, 9223372036854774784); - assert_eq::(-9223372036854775808.0f64 as i64, -9223372036854775808); + test_cast::(0.0, 0); + test_cast::(-0.0, 0); + test_cast::(/*0x0.0000000000001p-1022*/ f64::from_bits(0x1), 0); + test_cast::(/*-0x0.0000000000001p-1022*/ f64::from_bits(0x8000000000000001), 0); + test_cast::(/*0x1.199999999999ap+0*/ f64::from_bits(0x3ff199999999999a), 1); + test_cast::(/*-0x1.199999999999ap+0*/ f64::from_bits(0xbff199999999999a), -1); + test_cast::(5.0, 5); + test_cast::(5.9, 5); + test_cast::(-5.0, -5); + test_cast::(-5.9, -5); + test_cast::(4294967296.0, 4294967296); + test_cast::(-4294967296.0, -4294967296); + test_cast::(9223372036854774784.0, 9223372036854774784); + test_cast::(-9223372036854775808.0, -9223372036854775808); // unrepresentable casts assert_eq::(9223372036854775808.0f64 as i64, i64::MAX); assert_eq::(-9223372036854777856.0f64 as i64, i64::MIN); @@ -143,14 +208,14 @@ fn casts() { assert_eq::((-f64::NAN) as i64, 0); // f64 -> u64 - assert_eq::(0.0f64 as u64, 0); - assert_eq::(-0.0f64 as u64, 0); - assert_eq::(5.0f64 as u64, 5); - assert_eq::(-5.0f64 as u64, 0); - assert_eq::(1e16f64 as u64, 10000000000000000); - assert_eq::((u64::MAX-1023) as f64 as u64, u64::MAX); // rounding loss - assert_eq::((u64::MAX-1024) as f64 as u64, u64::MAX-2047); // rounding loss - assert_eq::(9223372036854775808.0f64 as u64, 9223372036854775808); + test_cast::(0.0, 0); + test_cast::(-0.0, 0); + test_cast::(5.0, 5); + test_cast::(-5.0, 0); + test_cast::(1e16, 10000000000000000); + test_cast::((u64::MAX-1023) as f64, u64::MAX); // rounding loss + test_cast::((u64::MAX-1024) as f64, u64::MAX-2047); // rounding loss + test_cast::(9223372036854775808.0, 9223372036854775808); // unrepresentable casts assert_eq::(18446744073709551616.0f64 as u64, u64::MAX); assert_eq::(f64::MAX as u64, u64::MAX); From 78ce616490c085f479fb08604f7016d8ce54a58b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 12 Apr 2020 11:35:12 +0200 Subject: [PATCH 1851/3747] implement float_to_int_unchecked --- src/shims/intrinsics.rs | 72 +++++++++++++++++++++++++++++++++++++++-- tests/run-pass/float.rs | 6 ++-- 2 files changed, 73 insertions(+), 5 deletions(-) diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 0f17bee008875..8f4bda404d72c 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -1,9 +1,10 @@ use std::iter; use std::convert::TryFrom; +use rustc_ast::ast::FloatTy; use rustc_middle::{mir, ty}; -use rustc_apfloat::Float; -use rustc_target::abi::{Align, LayoutOf}; +use rustc_apfloat::{Float, FloatConvert, Round, ieee::{Double, Single}}; +use rustc_target::abi::{Align, LayoutOf, Size}; use crate::*; @@ -279,6 +280,22 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_u64(f.powi(i).to_bits()), dest)?; } + "float_to_int_unchecked" => { + let val = this.read_immediate(args[0])?; + + let res = match val.layout.ty.kind { + ty::Float(FloatTy::F32) => { + this.float_to_int_unchecked(val.to_scalar()?.to_f32()?, dest.layout.ty)? + } + ty::Float(FloatTy::F64) => { + this.float_to_int_unchecked(val.to_scalar()?.to_f64()?, dest.layout.ty)? + } + _ => bug!("`float_to_int_unchecked` called with non-float input type {:?}", val.layout.ty), + }; + + this.write_scalar(res, dest)?; + } + // Atomic operations #[rustfmt::skip] | "atomic_load" @@ -491,4 +508,55 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.go_to_block(ret); Ok(()) } + + fn float_to_int_unchecked( + &self, + f: F, + dest_ty: ty::Ty<'tcx>, + ) -> InterpResult<'tcx, Scalar> + where + F: Float + Into> + FloatConvert + FloatConvert, + { + let this = self.eval_context_ref(); + + // Step 1: cut off the fractional part of `f`. The result of this is + // guaranteed to be precisely representable in IEEE floats. + let f = f.round_to_integral(Round::TowardZero).value; + + // Step 2: Cast the truncated float to the target integer type and see if we lose any information in this step. + Ok(match dest_ty.kind { + // Unsigned + ty::Uint(t) => { + let width = t.bit_width().unwrap_or_else(|| this.pointer_size().bits()); + let res = f.to_u128(usize::try_from(width).unwrap()); + if res.status.is_empty() { + // No status flags means there was no further rounding or other loss of precision. + Scalar::from_uint(res.value, Size::from_bits(width)) + } else { + // `f` was not representable in this integer type. + throw_ub_format!( + "`float_to_int_unchecked` intrinsic called on {} which cannot be represented in target type `{:?}`", + f, dest_ty, + ); + } + } + // Signed + ty::Int(t) => { + let width = t.bit_width().unwrap_or_else(|| this.pointer_size().bits()); + let res = f.to_i128(usize::try_from(width).unwrap()); + if res.status.is_empty() { + // No status flags means there was no further rounding or other loss of precision. + Scalar::from_int(res.value, Size::from_bits(width)) + } else { + // `f` was not representable in this integer type. + throw_ub_format!( + "`float_to_int_unchecked` intrinsic called on {} which cannot be represented in target type `{:?}`", + f, dest_ty, + ); + } + } + // Nothing else + _ => bug!("`float_to_int_unchecked` called with non-int output type {:?}", dest_ty), + }) + } } diff --git a/tests/run-pass/float.rs b/tests/run-pass/float.rs index 4c30cd01c4c00..3f86a21d18e21 100644 --- a/tests/run-pass/float.rs +++ b/tests/run-pass/float.rs @@ -146,9 +146,9 @@ fn casts() { test_cast::(4294967040.0, 0u32.wrapping_sub(256)); test_cast::(/*-0x1.ccccccp-1*/ f32::from_bits(0xbf666666), 0); test_cast::(/*-0x1.fffffep-1*/ f32::from_bits(0xbf7fffff), 0); - test_cast::((u32::MAX-127) as f32, u32::MAX); // rounding loss test_cast::((u32::MAX-128) as f32, u32::MAX-255); // rounding loss // unrepresentable casts + assert_eq::((u32::MAX-127) as f32 as u32, u32::MAX); // rounds up and then becomes unrepresentable assert_eq::(4294967296.0f32 as u32, u32::MAX); assert_eq::(-5.0f32 as u32, 0); assert_eq::(f32::MAX as u32, u32::MAX); @@ -211,12 +211,12 @@ fn casts() { test_cast::(0.0, 0); test_cast::(-0.0, 0); test_cast::(5.0, 5); - test_cast::(-5.0, 0); test_cast::(1e16, 10000000000000000); - test_cast::((u64::MAX-1023) as f64, u64::MAX); // rounding loss test_cast::((u64::MAX-1024) as f64, u64::MAX-2047); // rounding loss test_cast::(9223372036854775808.0, 9223372036854775808); // unrepresentable casts + assert_eq::(-5.0f64 as u64, 0); + assert_eq::((u64::MAX-1023) as f64 as u64, u64::MAX); // rounds up and then becomes unrepresentable assert_eq::(18446744073709551616.0f64 as u64, u64::MAX); assert_eq::(f64::MAX as u64, u64::MAX); assert_eq::(f64::MIN as u64, 0); From 30d07c861620c4c03226a9a0c693691b2e44ca58 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 12 Apr 2020 11:40:53 +0200 Subject: [PATCH 1852/3747] move error-pattern to inline annotation where possible --- tests/compile-fail/intrinsics/copy_overlapping.rs | 3 +-- tests/compile-fail/intrinsics/copy_unaligned.rs | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/tests/compile-fail/intrinsics/copy_overlapping.rs b/tests/compile-fail/intrinsics/copy_overlapping.rs index 76e1e20d2177f..8d3c68139317e 100644 --- a/tests/compile-fail/intrinsics/copy_overlapping.rs +++ b/tests/compile-fail/intrinsics/copy_overlapping.rs @@ -1,4 +1,3 @@ -//error-pattern: copy_nonoverlapping called on overlapping ranges #![feature(intrinsics)] // Directly call intrinsic to avoid debug assertions in libstd @@ -11,6 +10,6 @@ fn main() { unsafe { let a = data.as_mut_ptr(); let b = a.wrapping_offset(1) as *mut _; - copy_nonoverlapping(a, b, 2); + copy_nonoverlapping(a, b, 2); //~ ERROR copy_nonoverlapping called on overlapping ranges } } diff --git a/tests/compile-fail/intrinsics/copy_unaligned.rs b/tests/compile-fail/intrinsics/copy_unaligned.rs index a2a4762239184..84f4de93461e7 100644 --- a/tests/compile-fail/intrinsics/copy_unaligned.rs +++ b/tests/compile-fail/intrinsics/copy_unaligned.rs @@ -1,4 +1,3 @@ -//error-pattern: accessing memory with alignment 1, but alignment 2 is required #![feature(intrinsics)] // Directly call intrinsic to avoid debug assertions in libstd @@ -10,5 +9,5 @@ fn main() { let mut data = [0u16; 8]; let ptr = (&mut data[0] as *mut u16 as *mut u8).wrapping_add(1) as *mut u16; // Even copying 0 elements to something unaligned should error - unsafe { copy_nonoverlapping(&data[5], ptr, 0); } + unsafe { copy_nonoverlapping(&data[5], ptr, 0); } //~ ERROR accessing memory with alignment 1, but alignment 2 is required } From 25c71e5c0e88fb9fa9e657549658760f2e8d6bb2 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 12 Apr 2020 12:00:55 +0200 Subject: [PATCH 1853/3747] test some more corner cases in happy float casts --- tests/run-pass/float.rs | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/tests/run-pass/float.rs b/tests/run-pass/float.rs index 3f86a21d18e21..364388571f44c 100644 --- a/tests/run-pass/float.rs +++ b/tests/run-pass/float.rs @@ -56,6 +56,14 @@ impl FloatToInt for f64 { fn cast(self) -> u64 { self as _ } unsafe fn cast_unchecked(self) -> u64 { self.to_int_unchecked() } } +impl FloatToInt for f64 { + fn cast(self) -> i128 { self as _ } + unsafe fn cast_unchecked(self) -> i128 { self.to_int_unchecked() } +} +impl FloatToInt for f64 { + fn cast(self) -> u128 { self as _ } + unsafe fn cast_unchecked(self) -> u128 { self.to_int_unchecked() } +} /// Test this cast both via `as` and via `approx_unchecked` (i.e., it must not saturate). #[track_caller] @@ -137,6 +145,7 @@ fn casts() { // f32 -> u32 test_cast::(0.0, 0); test_cast::(-0.0, 0); + test_cast::(-0.9999999, 0); test_cast::(/*0x1p-149*/ f32::from_bits(0x1), 0); test_cast::(/*-0x1p-149*/ f32::from_bits(0x80000001), 0); test_cast::(/*0x1.19999ap+0*/ f32::from_bits(0x3f8ccccd), 1); @@ -210,6 +219,7 @@ fn casts() { // f64 -> u64 test_cast::(0.0, 0); test_cast::(-0.0, 0); + test_cast::(-0.99999999999, 0); test_cast::(5.0, 5); test_cast::(1e16, 10000000000000000); test_cast::((u64::MAX-1024) as f64, u64::MAX-2047); // rounding loss @@ -225,6 +235,14 @@ fn casts() { assert_eq::(f64::NAN as u64, 0); assert_eq::((-f64::NAN) as u64, 0); + // f64 -> i128 + assert_eq::(f64::MAX as i128, i128::MAX); + assert_eq::(f64::MIN as i128, i128::MIN); + + // f64 -> u128 + assert_eq::(f64::MAX as u128, u128::MAX); + assert_eq::(f64::MIN as u128, 0); + // int -> f32 assert_eq::(127i8 as f32, 127.0); assert_eq::(2147483647i32 as f32, 2147483648.0); @@ -275,10 +293,8 @@ fn casts() { assert_eq::(5.0f64 as f32, 5.0f32); assert_eq::(/*0x0.0000000000001p-1022*/ f64::from_bits(0x1) as f32, 0.0); assert_eq::(/*-0x0.0000000000001p-1022*/ (-f64::from_bits(0x1)) as f32, -0.0); - assert_eq::(/*0x1.fffffe0000000p-127*/ f64::from_bits(0x380fffffe0000000) as f32, /*0x1p-149*/ f32::from_bits(0x800000)); assert_eq::(/*0x1.4eae4f7024c7p+108*/ f64::from_bits(0x46b4eae4f7024c70) as f32, /*0x1.4eae5p+108*/ f32::from_bits(0x75a75728)); - assert_eq::(f64::MAX as f32, f32::INFINITY); assert_eq::(f64::MIN as f32, f32::NEG_INFINITY); assert_eq::(f64::INFINITY as f32, f32::INFINITY); From 17c52d47e70aff4a6ee290de5475228cdb3cc2a3 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 12 Apr 2020 12:01:07 +0200 Subject: [PATCH 1854/3747] add tests for invalid float-to-int casts --- tests/compile-fail/intrinsics/float_to_int_32_inf1.rs | 10 ++++++++++ .../compile-fail/intrinsics/float_to_int_32_infneg1.rs | 10 ++++++++++ tests/compile-fail/intrinsics/float_to_int_32_nan.rs | 10 ++++++++++ .../compile-fail/intrinsics/float_to_int_32_nanneg.rs | 10 ++++++++++ tests/compile-fail/intrinsics/float_to_int_32_neg.rs | 10 ++++++++++ .../intrinsics/float_to_int_32_too_big1.rs | 10 ++++++++++ .../intrinsics/float_to_int_32_too_big2.rs | 10 ++++++++++ .../intrinsics/float_to_int_32_too_small1.rs | 10 ++++++++++ tests/compile-fail/intrinsics/float_to_int_64_inf1.rs | 10 ++++++++++ .../compile-fail/intrinsics/float_to_int_64_infneg1.rs | 10 ++++++++++ .../compile-fail/intrinsics/float_to_int_64_infneg2.rs | 10 ++++++++++ tests/compile-fail/intrinsics/float_to_int_64_nan.rs | 10 ++++++++++ tests/compile-fail/intrinsics/float_to_int_64_neg.rs | 10 ++++++++++ .../intrinsics/float_to_int_64_too_big1.rs | 10 ++++++++++ .../intrinsics/float_to_int_64_too_big2.rs | 10 ++++++++++ .../intrinsics/float_to_int_64_too_big3.rs | 10 ++++++++++ .../intrinsics/float_to_int_64_too_big4.rs | 10 ++++++++++ .../intrinsics/float_to_int_64_too_big5.rs | 10 ++++++++++ .../intrinsics/float_to_int_64_too_small1.rs | 10 ++++++++++ .../intrinsics/float_to_int_64_too_small2.rs | 10 ++++++++++ .../intrinsics/float_to_int_64_too_small3.rs | 10 ++++++++++ 21 files changed, 210 insertions(+) create mode 100644 tests/compile-fail/intrinsics/float_to_int_32_inf1.rs create mode 100644 tests/compile-fail/intrinsics/float_to_int_32_infneg1.rs create mode 100644 tests/compile-fail/intrinsics/float_to_int_32_nan.rs create mode 100644 tests/compile-fail/intrinsics/float_to_int_32_nanneg.rs create mode 100644 tests/compile-fail/intrinsics/float_to_int_32_neg.rs create mode 100644 tests/compile-fail/intrinsics/float_to_int_32_too_big1.rs create mode 100644 tests/compile-fail/intrinsics/float_to_int_32_too_big2.rs create mode 100644 tests/compile-fail/intrinsics/float_to_int_32_too_small1.rs create mode 100644 tests/compile-fail/intrinsics/float_to_int_64_inf1.rs create mode 100644 tests/compile-fail/intrinsics/float_to_int_64_infneg1.rs create mode 100644 tests/compile-fail/intrinsics/float_to_int_64_infneg2.rs create mode 100644 tests/compile-fail/intrinsics/float_to_int_64_nan.rs create mode 100644 tests/compile-fail/intrinsics/float_to_int_64_neg.rs create mode 100644 tests/compile-fail/intrinsics/float_to_int_64_too_big1.rs create mode 100644 tests/compile-fail/intrinsics/float_to_int_64_too_big2.rs create mode 100644 tests/compile-fail/intrinsics/float_to_int_64_too_big3.rs create mode 100644 tests/compile-fail/intrinsics/float_to_int_64_too_big4.rs create mode 100644 tests/compile-fail/intrinsics/float_to_int_64_too_big5.rs create mode 100644 tests/compile-fail/intrinsics/float_to_int_64_too_small1.rs create mode 100644 tests/compile-fail/intrinsics/float_to_int_64_too_small2.rs create mode 100644 tests/compile-fail/intrinsics/float_to_int_64_too_small3.rs diff --git a/tests/compile-fail/intrinsics/float_to_int_32_inf1.rs b/tests/compile-fail/intrinsics/float_to_int_32_inf1.rs new file mode 100644 index 0000000000000..a56f4aefad3a7 --- /dev/null +++ b/tests/compile-fail/intrinsics/float_to_int_32_inf1.rs @@ -0,0 +1,10 @@ +#![feature(intrinsics)] + +// Directly call intrinsic to avoid debug assertions in libstd +extern "rust-intrinsic" { + fn float_to_int_unchecked(value: Float) -> Int; +} + +fn main() { + unsafe { float_to_int_unchecked::(f32::INFINITY); } //~ ERROR: cannot be represented in target type `i32` +} diff --git a/tests/compile-fail/intrinsics/float_to_int_32_infneg1.rs b/tests/compile-fail/intrinsics/float_to_int_32_infneg1.rs new file mode 100644 index 0000000000000..d18f75fcca8ab --- /dev/null +++ b/tests/compile-fail/intrinsics/float_to_int_32_infneg1.rs @@ -0,0 +1,10 @@ +#![feature(intrinsics)] + +// Directly call intrinsic to avoid debug assertions in libstd +extern "rust-intrinsic" { + fn float_to_int_unchecked(value: Float) -> Int; +} + +fn main() { + unsafe { float_to_int_unchecked::(f32::NEG_INFINITY); } //~ ERROR: cannot be represented in target type `i32` +} diff --git a/tests/compile-fail/intrinsics/float_to_int_32_nan.rs b/tests/compile-fail/intrinsics/float_to_int_32_nan.rs new file mode 100644 index 0000000000000..e1fe8c7cf2f74 --- /dev/null +++ b/tests/compile-fail/intrinsics/float_to_int_32_nan.rs @@ -0,0 +1,10 @@ +#![feature(intrinsics)] + +// Directly call intrinsic to avoid debug assertions in libstd +extern "rust-intrinsic" { + fn float_to_int_unchecked(value: Float) -> Int; +} + +fn main() { + unsafe { float_to_int_unchecked::(f32::NAN); } //~ ERROR: cannot be represented in target type `u32` +} diff --git a/tests/compile-fail/intrinsics/float_to_int_32_nanneg.rs b/tests/compile-fail/intrinsics/float_to_int_32_nanneg.rs new file mode 100644 index 0000000000000..38899045c92c0 --- /dev/null +++ b/tests/compile-fail/intrinsics/float_to_int_32_nanneg.rs @@ -0,0 +1,10 @@ +#![feature(intrinsics)] + +// Directly call intrinsic to avoid debug assertions in libstd +extern "rust-intrinsic" { + fn float_to_int_unchecked(value: Float) -> Int; +} + +fn main() { + unsafe { float_to_int_unchecked::(-f32::NAN); } //~ ERROR: cannot be represented in target type `u32` +} diff --git a/tests/compile-fail/intrinsics/float_to_int_32_neg.rs b/tests/compile-fail/intrinsics/float_to_int_32_neg.rs new file mode 100644 index 0000000000000..f15cf9a9cd643 --- /dev/null +++ b/tests/compile-fail/intrinsics/float_to_int_32_neg.rs @@ -0,0 +1,10 @@ +#![feature(intrinsics)] + +// Directly call intrinsic to avoid debug assertions in libstd +extern "rust-intrinsic" { + fn float_to_int_unchecked(value: Float) -> Int; +} + +fn main() { + unsafe { float_to_int_unchecked::(-1.000000001f32); } //~ ERROR: cannot be represented in target type `u32` +} diff --git a/tests/compile-fail/intrinsics/float_to_int_32_too_big1.rs b/tests/compile-fail/intrinsics/float_to_int_32_too_big1.rs new file mode 100644 index 0000000000000..ccbf917c8e89f --- /dev/null +++ b/tests/compile-fail/intrinsics/float_to_int_32_too_big1.rs @@ -0,0 +1,10 @@ +#![feature(intrinsics)] + +// Directly call intrinsic to avoid debug assertions in libstd +extern "rust-intrinsic" { + fn float_to_int_unchecked(value: Float) -> Int; +} + +fn main() { + unsafe { float_to_int_unchecked::(2147483648.0f32); } //~ ERROR: cannot be represented in target type `i32` +} diff --git a/tests/compile-fail/intrinsics/float_to_int_32_too_big2.rs b/tests/compile-fail/intrinsics/float_to_int_32_too_big2.rs new file mode 100644 index 0000000000000..6598fd36e038a --- /dev/null +++ b/tests/compile-fail/intrinsics/float_to_int_32_too_big2.rs @@ -0,0 +1,10 @@ +#![feature(intrinsics)] + +// Directly call intrinsic to avoid debug assertions in libstd +extern "rust-intrinsic" { + fn float_to_int_unchecked(value: Float) -> Int; +} + +fn main() { + unsafe { float_to_int_unchecked::((u32::MAX-127) as f32); } //~ ERROR: cannot be represented in target type `u32` +} diff --git a/tests/compile-fail/intrinsics/float_to_int_32_too_small1.rs b/tests/compile-fail/intrinsics/float_to_int_32_too_small1.rs new file mode 100644 index 0000000000000..89f09e1e3f18a --- /dev/null +++ b/tests/compile-fail/intrinsics/float_to_int_32_too_small1.rs @@ -0,0 +1,10 @@ +#![feature(intrinsics)] + +// Directly call intrinsic to avoid debug assertions in libstd +extern "rust-intrinsic" { + fn float_to_int_unchecked(value: Float) -> Int; +} + +fn main() { + unsafe { float_to_int_unchecked::(-2147483904.0f32); } //~ ERROR: cannot be represented in target type `i32` +} diff --git a/tests/compile-fail/intrinsics/float_to_int_64_inf1.rs b/tests/compile-fail/intrinsics/float_to_int_64_inf1.rs new file mode 100644 index 0000000000000..e1a7b818d8539 --- /dev/null +++ b/tests/compile-fail/intrinsics/float_to_int_64_inf1.rs @@ -0,0 +1,10 @@ +#![feature(intrinsics)] + +// Directly call intrinsic to avoid debug assertions in libstd +extern "rust-intrinsic" { + fn float_to_int_unchecked(value: Float) -> Int; +} + +fn main() { + unsafe { float_to_int_unchecked::(f64::INFINITY); } //~ ERROR: cannot be represented in target type `u128` +} diff --git a/tests/compile-fail/intrinsics/float_to_int_64_infneg1.rs b/tests/compile-fail/intrinsics/float_to_int_64_infneg1.rs new file mode 100644 index 0000000000000..a1d757b1511e6 --- /dev/null +++ b/tests/compile-fail/intrinsics/float_to_int_64_infneg1.rs @@ -0,0 +1,10 @@ +#![feature(intrinsics)] + +// Directly call intrinsic to avoid debug assertions in libstd +extern "rust-intrinsic" { + fn float_to_int_unchecked(value: Float) -> Int; +} + +fn main() { + unsafe { float_to_int_unchecked::(f64::NEG_INFINITY); } //~ ERROR: cannot be represented in target type `u128` +} diff --git a/tests/compile-fail/intrinsics/float_to_int_64_infneg2.rs b/tests/compile-fail/intrinsics/float_to_int_64_infneg2.rs new file mode 100644 index 0000000000000..e48d19f1a6a86 --- /dev/null +++ b/tests/compile-fail/intrinsics/float_to_int_64_infneg2.rs @@ -0,0 +1,10 @@ +#![feature(intrinsics)] + +// Directly call intrinsic to avoid debug assertions in libstd +extern "rust-intrinsic" { + fn float_to_int_unchecked(value: Float) -> Int; +} + +fn main() { + unsafe { float_to_int_unchecked::(f64::NEG_INFINITY); } //~ ERROR: cannot be represented in target type `i128` +} diff --git a/tests/compile-fail/intrinsics/float_to_int_64_nan.rs b/tests/compile-fail/intrinsics/float_to_int_64_nan.rs new file mode 100644 index 0000000000000..03f378f5bcb72 --- /dev/null +++ b/tests/compile-fail/intrinsics/float_to_int_64_nan.rs @@ -0,0 +1,10 @@ +#![feature(intrinsics)] + +// Directly call intrinsic to avoid debug assertions in libstd +extern "rust-intrinsic" { + fn float_to_int_unchecked(value: Float) -> Int; +} + +fn main() { + unsafe { float_to_int_unchecked::(f64::NAN); } //~ ERROR: cannot be represented in target type `u32` +} diff --git a/tests/compile-fail/intrinsics/float_to_int_64_neg.rs b/tests/compile-fail/intrinsics/float_to_int_64_neg.rs new file mode 100644 index 0000000000000..d0b5a3e21cf9e --- /dev/null +++ b/tests/compile-fail/intrinsics/float_to_int_64_neg.rs @@ -0,0 +1,10 @@ +#![feature(intrinsics)] + +// Directly call intrinsic to avoid debug assertions in libstd +extern "rust-intrinsic" { + fn float_to_int_unchecked(value: Float) -> Int; +} + +fn main() { + unsafe { float_to_int_unchecked::(-1.0000000000001f64); } //~ ERROR: cannot be represented in target type `u128` +} diff --git a/tests/compile-fail/intrinsics/float_to_int_64_too_big1.rs b/tests/compile-fail/intrinsics/float_to_int_64_too_big1.rs new file mode 100644 index 0000000000000..f928f161872e2 --- /dev/null +++ b/tests/compile-fail/intrinsics/float_to_int_64_too_big1.rs @@ -0,0 +1,10 @@ +#![feature(intrinsics)] + +// Directly call intrinsic to avoid debug assertions in libstd +extern "rust-intrinsic" { + fn float_to_int_unchecked(value: Float) -> Int; +} + +fn main() { + unsafe { float_to_int_unchecked::(2147483648.0f64); } //~ ERROR: cannot be represented in target type `i32` +} diff --git a/tests/compile-fail/intrinsics/float_to_int_64_too_big2.rs b/tests/compile-fail/intrinsics/float_to_int_64_too_big2.rs new file mode 100644 index 0000000000000..feb24c362dda7 --- /dev/null +++ b/tests/compile-fail/intrinsics/float_to_int_64_too_big2.rs @@ -0,0 +1,10 @@ +#![feature(intrinsics)] + +// Directly call intrinsic to avoid debug assertions in libstd +extern "rust-intrinsic" { + fn float_to_int_unchecked(value: Float) -> Int; +} + +fn main() { + unsafe { float_to_int_unchecked::(9223372036854775808.0f64); } //~ ERROR: cannot be represented in target type `i64` +} diff --git a/tests/compile-fail/intrinsics/float_to_int_64_too_big3.rs b/tests/compile-fail/intrinsics/float_to_int_64_too_big3.rs new file mode 100644 index 0000000000000..cd491bfed7eb9 --- /dev/null +++ b/tests/compile-fail/intrinsics/float_to_int_64_too_big3.rs @@ -0,0 +1,10 @@ +#![feature(intrinsics)] + +// Directly call intrinsic to avoid debug assertions in libstd +extern "rust-intrinsic" { + fn float_to_int_unchecked(value: Float) -> Int; +} + +fn main() { + unsafe { float_to_int_unchecked::(18446744073709551616.0f64); } //~ ERROR: cannot be represented in target type `u64` +} diff --git a/tests/compile-fail/intrinsics/float_to_int_64_too_big4.rs b/tests/compile-fail/intrinsics/float_to_int_64_too_big4.rs new file mode 100644 index 0000000000000..d5b24347b9419 --- /dev/null +++ b/tests/compile-fail/intrinsics/float_to_int_64_too_big4.rs @@ -0,0 +1,10 @@ +#![feature(intrinsics)] + +// Directly call intrinsic to avoid debug assertions in libstd +extern "rust-intrinsic" { + fn float_to_int_unchecked(value: Float) -> Int; +} + +fn main() { + unsafe { float_to_int_unchecked::(340282366920938463463374607431768211455.0f64); } //~ ERROR: cannot be represented in target type `u128` +} diff --git a/tests/compile-fail/intrinsics/float_to_int_64_too_big5.rs b/tests/compile-fail/intrinsics/float_to_int_64_too_big5.rs new file mode 100644 index 0000000000000..9c31c690b4e8a --- /dev/null +++ b/tests/compile-fail/intrinsics/float_to_int_64_too_big5.rs @@ -0,0 +1,10 @@ +#![feature(intrinsics)] + +// Directly call intrinsic to avoid debug assertions in libstd +extern "rust-intrinsic" { + fn float_to_int_unchecked(value: Float) -> Int; +} + +fn main() { + unsafe { float_to_int_unchecked::(240282366920938463463374607431768211455.0f64); } //~ ERROR: cannot be represented in target type `i128` +} diff --git a/tests/compile-fail/intrinsics/float_to_int_64_too_small1.rs b/tests/compile-fail/intrinsics/float_to_int_64_too_small1.rs new file mode 100644 index 0000000000000..08f2f9e3fd26c --- /dev/null +++ b/tests/compile-fail/intrinsics/float_to_int_64_too_small1.rs @@ -0,0 +1,10 @@ +#![feature(intrinsics)] + +// Directly call intrinsic to avoid debug assertions in libstd +extern "rust-intrinsic" { + fn float_to_int_unchecked(value: Float) -> Int; +} + +fn main() { + unsafe { float_to_int_unchecked::(-2147483649.0f64); } //~ ERROR: cannot be represented in target type `i32` +} diff --git a/tests/compile-fail/intrinsics/float_to_int_64_too_small2.rs b/tests/compile-fail/intrinsics/float_to_int_64_too_small2.rs new file mode 100644 index 0000000000000..f7b205de5346c --- /dev/null +++ b/tests/compile-fail/intrinsics/float_to_int_64_too_small2.rs @@ -0,0 +1,10 @@ +#![feature(intrinsics)] + +// Directly call intrinsic to avoid debug assertions in libstd +extern "rust-intrinsic" { + fn float_to_int_unchecked(value: Float) -> Int; +} + +fn main() { + unsafe { float_to_int_unchecked::(-9223372036854777856.0f64); } //~ ERROR: cannot be represented in target type `i64` +} diff --git a/tests/compile-fail/intrinsics/float_to_int_64_too_small3.rs b/tests/compile-fail/intrinsics/float_to_int_64_too_small3.rs new file mode 100644 index 0000000000000..779441f7448c8 --- /dev/null +++ b/tests/compile-fail/intrinsics/float_to_int_64_too_small3.rs @@ -0,0 +1,10 @@ +#![feature(intrinsics)] + +// Directly call intrinsic to avoid debug assertions in libstd +extern "rust-intrinsic" { + fn float_to_int_unchecked(value: Float) -> Int; +} + +fn main() { + unsafe { float_to_int_unchecked::(-240282366920938463463374607431768211455.0f64); } //~ ERROR: cannot be represented in target type `i128` +} From a82efce590037c9871292e34adbd4e0a6e031fc8 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 12 Apr 2020 22:01:46 +0200 Subject: [PATCH 1855/3747] remove some unnecessary trait bounds --- src/shims/intrinsics.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 8f4bda404d72c..0147d72b23868 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -3,7 +3,7 @@ use std::convert::TryFrom; use rustc_ast::ast::FloatTy; use rustc_middle::{mir, ty}; -use rustc_apfloat::{Float, FloatConvert, Round, ieee::{Double, Single}}; +use rustc_apfloat::{Float, Round}; use rustc_target::abi::{Align, LayoutOf, Size}; use crate::*; @@ -515,7 +515,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx dest_ty: ty::Ty<'tcx>, ) -> InterpResult<'tcx, Scalar> where - F: Float + Into> + FloatConvert + FloatConvert, + F: Float + Into> { let this = self.eval_context_ref(); From 91d7964513adb5aa29d1fa3f657555e110d54474 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 13 Apr 2020 00:41:39 +0200 Subject: [PATCH 1856/3747] rustup --- rust-version | 2 +- src/bin/miri-rustc-tests.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/rust-version b/rust-version index 40c0005e08067..e051ed2ecc5c1 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -0c835b0cca83fe21090562603e4bda77c183ace3 +4d1fbaccb822b6d52dc786589de7918d3c5effb1 diff --git a/src/bin/miri-rustc-tests.rs b/src/bin/miri-rustc-tests.rs index 97292cf1dbe5c..bae7356eb72c8 100644 --- a/src/bin/miri-rustc-tests.rs +++ b/src/bin/miri-rustc-tests.rs @@ -41,7 +41,7 @@ impl rustc_driver::Callbacks for MiriCompilerCalls { .any(|attr| attr.check_name(rustc_span::symbol::sym::test)) { let config = miri::MiriConfig::default(); - let did = self.0.hir().body_owner_def_id(body_id); + let did = self.0.hir().body_owner_def_id(body_id).to_def_id(); println!("running test: {}", self.0.def_path_debug_str(did)); miri::eval_main(self.0, did, config); self.0.sess.abort_if_errors(); From 75297d3536df77155b7413a9b7f453ed5dc01bb6 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 13 Apr 2020 09:18:11 +0200 Subject: [PATCH 1857/3747] for alignment errors, note that there might be false positives --- src/diagnostics.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/diagnostics.rs b/src/diagnostics.rs index 90e532321e404..c387eed5c41ca 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -93,6 +93,11 @@ pub fn report_error<'tcx, 'mir>( vec![format!("make sure to use a Miri sysroot, which you can prepare with `cargo miri setup`")], Unsupported(_) => vec![format!("this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support")], + UndefinedBehavior(UndefinedBehaviorInfo::AlignmentCheckFailed { .. }) => + vec![ + format!("this usually indicates that your program performed an invalid operation and caused Undefined Behavior"), + format!("but alignment errors can also be false positives, see https://github.com/rust-lang/miri/issues/1074"), + ], UndefinedBehavior(_) => vec![ format!("this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior"), From a6b66c31d7587254c71e60fa171827b3277f4a46 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 13 Apr 2020 11:30:02 +0200 Subject: [PATCH 1858/3747] note Miri's leak check abilities and that they are disabled on Windows --- README.md | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 4968e66657121..c3c5bba2c6f9b 100644 --- a/README.md +++ b/README.md @@ -17,12 +17,17 @@ for example: * **Experimental**: Violations of the [Stacked Borrows] rules governing aliasing for reference types +On top of that, Miri will also tell you about memory leaks: when there is memory +still allocated at the end of the execution, and that memory is not reachable +from a global `static`, Miri will raise an error. Note however that +[leak checking is currently disabled on Windows targets](https://github.com/rust-lang/miri/issues/1302). + Miri has already discovered some [real-world bugs](#bugs-found-by-miri). If you found a bug with Miri, we'd appreciate if you tell us and we'll add it to the list! -Be aware that Miri will **not catch all cases of undefined behavior** in your -program, and cannot run all programs: +However, be aware that Miri will **not catch all cases of undefined behavior** +in your program, and cannot run all programs: * There are still plenty of open questions around the basic invariants for some types and when these invariants even have to hold. Miri tries to avoid false From 5f6d250b303d839896ead366153997d0e8e013e0 Mon Sep 17 00:00:00 2001 From: Samrat Man Singh Date: Mon, 13 Apr 2020 21:18:34 +0530 Subject: [PATCH 1859/3747] [macOS] Implement `mach_timebase_info` Since we return nanoseceonds instead of ticks from `mach_absolute_time`, we don't need to scale the absolute time --- src/shims/foreign_items/posix/macos.rs | 5 +++++ src/shims/time.rs | 22 ++++++++++++++++++++++ tests/run-pass/time.rs | 15 ++++++--------- 3 files changed, 33 insertions(+), 9 deletions(-) diff --git a/src/shims/foreign_items/posix/macos.rs b/src/shims/foreign_items/posix/macos.rs index 9810a77ffde18..e7baacf7274d2 100644 --- a/src/shims/foreign_items/posix/macos.rs +++ b/src/shims/foreign_items/posix/macos.rs @@ -60,6 +60,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_u64(result), dest)?; } + "mach_timebase_info" => { + let result = this.mach_timebase_info(args[0])?; + this.write_scalar(Scalar::from_i32(result), dest)?; + }, + // Access to command-line arguments "_NSGetArgc" => { this.write_scalar(this.machine.argc.expect("machine must be initialized"), dest)?; diff --git a/src/shims/time.rs b/src/shims/time.rs index 0d7a4929e4e05..adcca21fb4c0d 100644 --- a/src/shims/time.rs +++ b/src/shims/time.rs @@ -13,6 +13,7 @@ pub fn system_time_to_duration<'tcx>(time: &SystemTime) -> InterpResult<'tcx, Du .map_err(|_| err_unsup_format!("times before the Unix epoch are not supported").into()) } + impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { fn clock_gettime( @@ -159,4 +160,25 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx u64::try_from(duration.as_nanos()) .map_err(|_| err_unsup_format!("programs running longer than 2^64 nanoseconds are not supported").into()) } + + fn mach_timebase_info(&mut self, info_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + let this = self.eval_context_mut(); + + this.assert_target_os("macos", "mach_timebase_info"); + this.check_no_isolation("mach_timebase_info")?; + + let info = this.deref_operand(info_op)?; + + // Since we return nanoseceonds instead of ticks from + // `mach_absolute_time`, we don't need to scale the absolute + // time. + let (numer, denom) = (1,1); + let imms = [ + immty_from_int_checked(numer, this.libc_ty_layout("uint32_t")?)?, + immty_from_int_checked(denom, this.libc_ty_layout("uint32_t")?)? + ]; + + this.write_packed_immediates(info, &imms)?; + Ok(0) + } } diff --git a/tests/run-pass/time.rs b/tests/run-pass/time.rs index aa02ac15388e5..9ae64fbae42a0 100644 --- a/tests/run-pass/time.rs +++ b/tests/run-pass/time.rs @@ -25,13 +25,10 @@ fn main() { let now2 = Instant::now(); assert!(now2 > now1); - #[cfg(not(target_os = "macos"))] // TODO: macOS does not support Instant subtraction - { - let diff = now2.duration_since(now1); - assert_eq!(now1 + diff, now2); - assert_eq!(now2 - diff, now1); - // Sanity-check the difference we got. - assert!(diff.as_micros() > 1); - assert!(diff.as_micros() < 1_000_000); - } + let diff = now2.duration_since(now1); + assert_eq!(now1 + diff, now2); + assert_eq!(now2 - diff, now1); + // Sanity-check the difference we got. + assert!(diff.as_micros() > 1); + assert!(diff.as_micros() < 1_000_000); } From fd8beaf5c4abac980d5730a4e19ec6c1879907b6 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 13 Apr 2020 17:51:22 +0200 Subject: [PATCH 1860/3747] add option to disable alignment checks --- src/bin/miri.rs | 5 +++++ src/eval.rs | 4 ++++ src/machine.rs | 17 +++++++++++++++-- .../unaligned_pointers/alignment.rs | 2 +- tests/run-pass/disable-alignment-check.rs | 11 +++++++++++ 5 files changed, 36 insertions(+), 3 deletions(-) create mode 100644 tests/run-pass/disable-alignment-check.rs diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 14d78053c0fd6..1ceb6e621a47b 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -128,6 +128,7 @@ fn main() { // Parse our arguments and split them across `rustc` and `miri`. let mut validate = true; let mut stacked_borrows = true; + let mut check_alignment = true; let mut communicate = false; let mut ignore_leaks = false; let mut seed: Option = None; @@ -152,6 +153,9 @@ fn main() { "-Zmiri-disable-stacked-borrows" => { stacked_borrows = false; } + "-Zmiri-disable-alignment-check" => { + check_alignment = false; + } "-Zmiri-disable-isolation" => { communicate = true; } @@ -243,6 +247,7 @@ fn main() { let miri_config = miri::MiriConfig { validate, stacked_borrows, + check_alignment, communicate, ignore_leaks, excluded_env_vars, diff --git a/src/eval.rs b/src/eval.rs index 094be194f1780..b360b1bd8bbc5 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -19,6 +19,8 @@ pub struct MiriConfig { pub validate: bool, /// Determines if Stacked Borrows is enabled. pub stacked_borrows: bool, + /// Determines if alignment checking is enabled. + pub check_alignment: bool, /// Determines if communication with the host environment is enabled. pub communicate: bool, /// Determines if memory leaks should be ignored. @@ -40,6 +42,7 @@ impl Default for MiriConfig { MiriConfig { validate: true, stacked_borrows: true, + check_alignment: true, communicate: false, ignore_leaks: false, excluded_env_vars: vec![], @@ -72,6 +75,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( config.stacked_borrows, config.tracked_pointer_tag, config.tracked_alloc_id, + config.check_alignment, ), ); // Complete initialization. diff --git a/src/machine.rs b/src/machine.rs index 72635f7bf57b0..54dfb49d798be 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -118,10 +118,19 @@ pub struct MemoryExtra { /// An allocation ID to report when it is being allocated /// (helps for debugging memory leaks). tracked_alloc_id: Option, + + /// Controls whether alignment of memory accesses is being checked. + check_alignment: bool, } impl MemoryExtra { - pub fn new(rng: StdRng, stacked_borrows: bool, tracked_pointer_tag: Option, tracked_alloc_id: Option) -> Self { + pub fn new( + rng: StdRng, + stacked_borrows: bool, + tracked_pointer_tag: Option, + tracked_alloc_id: Option, + check_alignment: bool, + ) -> Self { let stacked_borrows = if stacked_borrows { Some(Rc::new(RefCell::new(stacked_borrows::GlobalState::new(tracked_pointer_tag)))) } else { @@ -133,6 +142,7 @@ impl MemoryExtra { extern_statics: FxHashMap::default(), rng: RefCell::new(rng), tracked_alloc_id, + check_alignment, } } @@ -299,7 +309,10 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { const GLOBAL_KIND: Option = Some(MiriMemoryKind::Global); - const CHECK_ALIGN: bool = true; + #[inline(always)] + fn enforce_alignment(memory_extra: &MemoryExtra) -> bool { + memory_extra.check_alignment + } #[inline(always)] fn enforce_validity(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool { diff --git a/tests/compile-fail/unaligned_pointers/alignment.rs b/tests/compile-fail/unaligned_pointers/alignment.rs index bac1b92075a76..b732a949af876 100644 --- a/tests/compile-fail/unaligned_pointers/alignment.rs +++ b/tests/compile-fail/unaligned_pointers/alignment.rs @@ -2,7 +2,7 @@ fn main() { // miri always gives allocations the worst possible alignment, so a `u8` array is guaranteed // to be at the virtual location 1 (so one byte offset from the ultimate alignemnt location 0) let mut x = [0u8; 20]; - let x_ptr: *mut u8 = &mut x[0]; + let x_ptr: *mut u8 = x.as_mut_ptr(); let y_ptr = x_ptr as *mut u64; unsafe { *y_ptr = 42; //~ ERROR accessing memory with alignment 1, but alignment diff --git a/tests/run-pass/disable-alignment-check.rs b/tests/run-pass/disable-alignment-check.rs new file mode 100644 index 0000000000000..2fb0dd8369df7 --- /dev/null +++ b/tests/run-pass/disable-alignment-check.rs @@ -0,0 +1,11 @@ +// compile-flags: -Zmiri-disable-alignment-check + +fn main() { + let mut x = [0u8; 20]; + let x_ptr: *mut u8 = x.as_mut_ptr(); + // At least one of these is definitely unaligned. + unsafe { + *(x_ptr as *mut u64) = 42; + *(x_ptr.add(1) as *mut u64) = 42; + } +} From 0ad111415387f1e7480dd64fdf7e872045479868 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 13 Apr 2020 17:55:39 +0200 Subject: [PATCH 1861/3747] mention new option in README and diagnostics --- README.md | 2 ++ src/diagnostics.rs | 1 + 2 files changed, 3 insertions(+) diff --git a/README.md b/README.md index 4968e66657121..3df1bef7cbbbb 100644 --- a/README.md +++ b/README.md @@ -176,6 +176,8 @@ Several `-Z` flags are relevant for Miri: * `-Zmiri-disable-stacked-borrows` disables checking the experimental [Stacked Borrows] aliasing rules. This can make Miri run faster, but it also means no aliasing violations will be detected. +* `-Zmiri-disable-alignment-check` disables checking pointer alignment on memory + accesses. * `-Zmiri-disable-isolation` disables host isolation. As a consequence, the program has access to host resources such as environment variables, file systems, and randomness. diff --git a/src/diagnostics.rs b/src/diagnostics.rs index c387eed5c41ca..2359b67323d75 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -97,6 +97,7 @@ pub fn report_error<'tcx, 'mir>( vec![ format!("this usually indicates that your program performed an invalid operation and caused Undefined Behavior"), format!("but alignment errors can also be false positives, see https://github.com/rust-lang/miri/issues/1074"), + format!("you can disable the alignment check with `-Zmiri-disable-alignment-check`, but that could hide true bugs") ], UndefinedBehavior(_) => vec![ From f6bb8111f280653c86f220847bd4eb04fa9bebca Mon Sep 17 00:00:00 2001 From: Samrat Man Singh Date: Tue, 14 Apr 2020 09:40:40 +0530 Subject: [PATCH 1862/3747] Use pre-defined u32 layout Also fix typo and remove newline --- src/shims/time.rs | 7 ++++--- tests/run-pass/time.rs | 1 - 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/shims/time.rs b/src/shims/time.rs index adcca21fb4c0d..835541f9a9575 100644 --- a/src/shims/time.rs +++ b/src/shims/time.rs @@ -169,13 +169,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let info = this.deref_operand(info_op)?; - // Since we return nanoseceonds instead of ticks from + // Since we return nanoseconds instead of ticks from // `mach_absolute_time`, we don't need to scale the absolute // time. let (numer, denom) = (1,1); + let uint32_layout = this.layout_of(this.tcx.types.u32)?; let imms = [ - immty_from_int_checked(numer, this.libc_ty_layout("uint32_t")?)?, - immty_from_int_checked(denom, this.libc_ty_layout("uint32_t")?)? + immty_from_int_checked(numer, uint32_layout)?, + immty_from_int_checked(denom, uint32_layout)? ]; this.write_packed_immediates(info, &imms)?; diff --git a/tests/run-pass/time.rs b/tests/run-pass/time.rs index 9ae64fbae42a0..2c9b579f7e294 100644 --- a/tests/run-pass/time.rs +++ b/tests/run-pass/time.rs @@ -24,7 +24,6 @@ fn main() { for _ in 0..10 { drop(vec![42]); } let now2 = Instant::now(); assert!(now2 > now1); - let diff = now2.duration_since(now1); assert_eq!(now1 + diff, now2); assert_eq!(now2 - diff, now1); From 48aaf674f73add4c7d96e03a4d6cd8fa61d5ffbb Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 14 Apr 2020 09:26:42 +0200 Subject: [PATCH 1863/3747] tweak flag section in README --- README.md | 56 ++++++++++++++++++++++++++++++------------------------- 1 file changed, 31 insertions(+), 25 deletions(-) diff --git a/README.md b/README.md index 3df1bef7cbbbb..88b91d416d4df 100644 --- a/README.md +++ b/README.md @@ -160,31 +160,43 @@ up the sysroot. If you are using `miri` (the Miri driver) directly, see ## Miri `-Z` flags and environment variables [miri-flags]: #miri--z-flags-and-environment-variables -Several `-Z` flags are relevant for Miri: - -* `-Zmiri-seed=` is a custom `-Z` flag added by Miri. It configures the - seed of the RNG that Miri uses to resolve non-determinism. This RNG is used - to pick base addresses for allocations. When isolation is enabled (the default), - this is also used to emulate system entropy. The default seed is 0. - **NOTE**: This entropy is not good enough for cryptographic use! Do not - generate secret keys in Miri or perform other kinds of cryptographic - operations that rely on proper random numbers. -* `-Zmiri-disable-validation` disables enforcing validity invariants, which are - enforced by default. This is mostly useful for debugging. It means Miri will - miss bugs in your program. However, this can also help to make Miri run - faster. +Miri adds its own set of `-Z` flags: + +* `-Zmiri-disable-alignment-check` disables checking pointer alignment. This is + useful to avoid [false positives][alignment-false-positives]. However, setting + this flag means Miri could miss bugs in your program. * `-Zmiri-disable-stacked-borrows` disables checking the experimental [Stacked Borrows] aliasing rules. This can make Miri run faster, but it also means no aliasing violations will be detected. -* `-Zmiri-disable-alignment-check` disables checking pointer alignment on memory - accesses. +* `-Zmiri-disable-validation` disables enforcing validity invariants, which are + enforced by default. This is mostly useful to focus on other failures (such + as out-of-bounds accesses) first. Setting this flag means Miri will miss bugs + in your program. However, this can also help to make Miri run faster. * `-Zmiri-disable-isolation` disables host isolation. As a consequence, the program has access to host resources such as environment variables, file systems, and randomness. -* `-Zmiri-ignore-leaks` disables the memory leak checker. * `-Zmiri-env-exclude=` keeps the `var` environment variable isolated from - the host. Can be used multiple times to exclude several variables. The `TERM` - environment variable is excluded by default. + the host so that it cannot be accessed by the program. Can be used multiple + times to exclude several variables. On Windows, the `TERM` environment + variable is excluded by default. +* `-Zmiri-ignore-leaks` disables the memory leak checker. +* `-Zmiri-seed=` configures the seed of the RNG that Miri uses to resolve + non-determinism. This RNG is used to pick base addresses for allocations. + When isolation is enabled (the default), this is also used to emulate system + entropy. The default seed is 0. **NOTE**: This entropy is not good enough + for cryptographic use! Do not generate secret keys in Miri or perform other + kinds of cryptographic operations that rely on proper random numbers. +* `-Zmiri-track-alloc-id=` shows a backtrace when the given allocation is + being allocated. This helps in debugging memory leaks. +* `-Zmiri-track-pointer-tag=` shows a backtrace when the given pointer tag + is popped from a borrow stack (which is where the tag becomes invalid and any + future use of it will error). This helps you in finding out why UB is + happening and where in your code would be a good place to look for it. + +[alignment-false-positives]: https://github.com/rust-lang/miri/issues/1074 + +Some native rustc `-Z` flags are also very relevant for Miri: + * `-Zmir-opt-level` controls how many MIR optimizations are performed. Miri overrides the default to be `0`; be advised that using any higher level can make Miri miss bugs in your program because they got optimized away. @@ -192,13 +204,7 @@ Several `-Z` flags are relevant for Miri: functions. This is needed so that Miri can execute such functions, so Miri sets this flag per default. * `-Zmir-emit-retag` controls whether `Retag` statements are emitted. Miri - enables this per default because it is needed for validation. -* `-Zmiri-track-pointer-tag=` shows a backtrace when the given pointer tag - is popped from a borrow stack (which is where the tag becomes invalid and any - future use of it will error). This helps you in finding out why UB is - happening and where in your code would be a good place to look for it. -* `-Zmiri-track-alloc-id=` shows a backtrace when the given allocation is - being allocated. This helps in debugging memory leaks. + enables this per default because it is needed for [Stacked Borrows]. Moreover, Miri recognizes some environment variables: From 8e73db6510f1ca8625dc4efe3791cc9f37a7c915 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 14 Apr 2020 09:26:47 +0200 Subject: [PATCH 1864/3747] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index e051ed2ecc5c1..48247d653cdce 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -4d1fbaccb822b6d52dc786589de7918d3c5effb1 +47f49695dfb4fe9e584239fdc59c771887148a57 From f4a15444cf90452876733549731ab94517656e8b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 14 Apr 2020 09:50:20 +0200 Subject: [PATCH 1865/3747] fix comment in alignment test --- tests/compile-fail/unaligned_pointers/alignment.rs | 8 ++++---- .../unaligned_pointers/intptrcast_alignment_check.rs | 2 ++ 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/tests/compile-fail/unaligned_pointers/alignment.rs b/tests/compile-fail/unaligned_pointers/alignment.rs index b732a949af876..8532f91a5c006 100644 --- a/tests/compile-fail/unaligned_pointers/alignment.rs +++ b/tests/compile-fail/unaligned_pointers/alignment.rs @@ -1,11 +1,11 @@ fn main() { - // miri always gives allocations the worst possible alignment, so a `u8` array is guaranteed - // to be at the virtual location 1 (so one byte offset from the ultimate alignemnt location 0) let mut x = [0u8; 20]; let x_ptr: *mut u8 = x.as_mut_ptr(); - let y_ptr = x_ptr as *mut u64; + // At least one of these is definitely unaligned. + // Currently, we guarantee to complain about the first one already (https://github.com/rust-lang/miri/issues/1074). unsafe { - *y_ptr = 42; //~ ERROR accessing memory with alignment 1, but alignment + *(x_ptr as *mut u64) = 42; //~ ERROR accessing memory with alignment 1, but alignment + *(x_ptr.add(1) as *mut u64) = 42; } panic!("unreachable in miri"); } diff --git a/tests/compile-fail/unaligned_pointers/intptrcast_alignment_check.rs b/tests/compile-fail/unaligned_pointers/intptrcast_alignment_check.rs index 1a8df5eacede8..0a3b48dab5a0c 100644 --- a/tests/compile-fail/unaligned_pointers/intptrcast_alignment_check.rs +++ b/tests/compile-fail/unaligned_pointers/intptrcast_alignment_check.rs @@ -2,6 +2,8 @@ // that arise from pointers being insufficiently aligned. The only way to achieve // that is not not let programs exploit integer information for alignment, so here // we test that this is indeed the case. +// +// See https://github.com/rust-lang/miri/issues/1074. fn main() { let x = &mut [0u8; 3]; let base_addr = x as *mut _ as usize; From 90729bb0394d64ee93026410480e8155c92ab7e5 Mon Sep 17 00:00:00 2001 From: Samrat Man Singh Date: Tue, 14 Apr 2020 13:31:24 +0530 Subject: [PATCH 1866/3747] Use precomputed TyLayout from `machine.layouts` And add comment documenting successful return value from `mach_timebase_info`. --- src/shims/time.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/shims/time.rs b/src/shims/time.rs index 835541f9a9575..c22ac9ca1a509 100644 --- a/src/shims/time.rs +++ b/src/shims/time.rs @@ -173,13 +173,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // `mach_absolute_time`, we don't need to scale the absolute // time. let (numer, denom) = (1,1); - let uint32_layout = this.layout_of(this.tcx.types.u32)?; let imms = [ - immty_from_int_checked(numer, uint32_layout)?, - immty_from_int_checked(denom, uint32_layout)? + immty_from_int_checked(numer, this.machine.layouts.u32)?, + immty_from_int_checked(denom, this.machine.layouts.u32)? ]; this.write_packed_immediates(info, &imms)?; - Ok(0) + Ok(0) // KERN_SUCCESS } } From 179e78d0ad95c60689f0df4cc6e3491b53b586ad Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 14 Apr 2020 09:58:58 +0200 Subject: [PATCH 1867/3747] make sure our disable flags do not miss all bugs; move type-assert intrinsic tests to their folder --- .../dangling_pointers/dangling_pointer_deref.rs | 3 +++ .../compile-fail/dangling_pointers/dangling_zst_deref.rs | 3 +++ .../{ => intrinsics}/uninit_uninhabited_type.rs | 2 +- tests/compile-fail/intrinsics/zero_fn_ptr.rs | 6 ++++++ tests/compile-fail/invalid_bool.rs | 3 ++- tests/compile-fail/invalid_char.rs | 3 ++- tests/compile-fail/invalid_enum_discriminant.rs | 3 ++- tests/compile-fail/invalid_int.rs | 8 ++++++++ tests/compile-fail/invalid_zero_init.rs | 6 ------ ...writing_part_of_relocation_makes_the_rest_undefined.rs | 3 +++ 10 files changed, 30 insertions(+), 10 deletions(-) rename tests/compile-fail/{ => intrinsics}/uninit_uninhabited_type.rs (53%) create mode 100644 tests/compile-fail/intrinsics/zero_fn_ptr.rs create mode 100644 tests/compile-fail/invalid_int.rs delete mode 100644 tests/compile-fail/invalid_zero_init.rs diff --git a/tests/compile-fail/dangling_pointers/dangling_pointer_deref.rs b/tests/compile-fail/dangling_pointers/dangling_pointer_deref.rs index f2c7ec584fefb..e088a5532581f 100644 --- a/tests/compile-fail/dangling_pointers/dangling_pointer_deref.rs +++ b/tests/compile-fail/dangling_pointers/dangling_pointer_deref.rs @@ -1,3 +1,6 @@ +// Make sure we find these even with many checks disabled. +// compile-flags: -Zmiri-disable-alignment-check -Zmiri-disable-stacked-borrows -Zmiri-disable-validation + fn main() { let p = { let b = Box::new(42); diff --git a/tests/compile-fail/dangling_pointers/dangling_zst_deref.rs b/tests/compile-fail/dangling_pointers/dangling_zst_deref.rs index 13e5f9d321735..f1b5149dabb41 100644 --- a/tests/compile-fail/dangling_pointers/dangling_zst_deref.rs +++ b/tests/compile-fail/dangling_pointers/dangling_zst_deref.rs @@ -1,3 +1,6 @@ +// Make sure we find these even with many checks disabled. +// compile-flags: -Zmiri-disable-alignment-check -Zmiri-disable-stacked-borrows -Zmiri-disable-validation + fn main() { let p = { let b = Box::new(42); diff --git a/tests/compile-fail/uninit_uninhabited_type.rs b/tests/compile-fail/intrinsics/uninit_uninhabited_type.rs similarity index 53% rename from tests/compile-fail/uninit_uninhabited_type.rs rename to tests/compile-fail/intrinsics/uninit_uninhabited_type.rs index b9048830783f8..deb3586c781e2 100644 --- a/tests/compile-fail/uninit_uninhabited_type.rs +++ b/tests/compile-fail/intrinsics/uninit_uninhabited_type.rs @@ -1,4 +1,4 @@ - // error-pattern: the evaluated program aborted execution: attempted to instantiate uninhabited type `!` +// error-pattern: the evaluated program aborted execution: attempted to instantiate uninhabited type `!` #![feature(never_type)] #[allow(deprecated, invalid_value)] diff --git a/tests/compile-fail/intrinsics/zero_fn_ptr.rs b/tests/compile-fail/intrinsics/zero_fn_ptr.rs new file mode 100644 index 0000000000000..81dbf6c429b33 --- /dev/null +++ b/tests/compile-fail/intrinsics/zero_fn_ptr.rs @@ -0,0 +1,6 @@ +// error-pattern: the evaluated program aborted execution: attempted to zero-initialize type `fn()`, which is invalid + +#[allow(deprecated, invalid_value)] +fn main() { + unsafe { std::mem::zeroed::() }; +} diff --git a/tests/compile-fail/invalid_bool.rs b/tests/compile-fail/invalid_bool.rs index 6ccea35316365..38033146ade82 100644 --- a/tests/compile-fail/invalid_bool.rs +++ b/tests/compile-fail/invalid_bool.rs @@ -1,5 +1,6 @@ // Validation makes this fail in the wrong place -// compile-flags: -Zmiri-disable-validation +// Make sure we find these even with many checks disabled. +// compile-flags: -Zmiri-disable-alignment-check -Zmiri-disable-stacked-borrows -Zmiri-disable-validation fn main() { let b = unsafe { std::mem::transmute::(2) }; diff --git a/tests/compile-fail/invalid_char.rs b/tests/compile-fail/invalid_char.rs index ed61fcbe9d52f..ab10ab1e2173d 100644 --- a/tests/compile-fail/invalid_char.rs +++ b/tests/compile-fail/invalid_char.rs @@ -1,5 +1,6 @@ // Validation makes this fail in the wrong place -// compile-flags: -Zmiri-disable-validation +// Make sure we find these even with many checks disabled. +// compile-flags: -Zmiri-disable-alignment-check -Zmiri-disable-stacked-borrows -Zmiri-disable-validation fn main() { assert!(std::char::from_u32(-1_i32 as u32).is_none()); diff --git a/tests/compile-fail/invalid_enum_discriminant.rs b/tests/compile-fail/invalid_enum_discriminant.rs index c1b8727c129b9..cdbea6aa12234 100644 --- a/tests/compile-fail/invalid_enum_discriminant.rs +++ b/tests/compile-fail/invalid_enum_discriminant.rs @@ -1,5 +1,6 @@ // Validation makes this fail in the wrong place -// compile-flags: -Zmiri-disable-validation +// Make sure we find these even with many checks disabled. +// compile-flags: -Zmiri-disable-alignment-check -Zmiri-disable-stacked-borrows -Zmiri-disable-validation // error-pattern: invalid enum discriminant diff --git a/tests/compile-fail/invalid_int.rs b/tests/compile-fail/invalid_int.rs new file mode 100644 index 0000000000000..26a85802079b0 --- /dev/null +++ b/tests/compile-fail/invalid_int.rs @@ -0,0 +1,8 @@ +// Validation makes this fail in the wrong place +// Make sure we find these even with many checks disabled. +// compile-flags: -Zmiri-disable-alignment-check -Zmiri-disable-stacked-borrows -Zmiri-disable-validation + +fn main() { + let i = unsafe { std::mem::MaybeUninit::::uninit().assume_init() }; + let _x = i + 0; //~ ERROR this operation requires initialized memory +} diff --git a/tests/compile-fail/invalid_zero_init.rs b/tests/compile-fail/invalid_zero_init.rs deleted file mode 100644 index 78c2b0fbeeb72..0000000000000 --- a/tests/compile-fail/invalid_zero_init.rs +++ /dev/null @@ -1,6 +0,0 @@ - // error-pattern: the evaluated program aborted execution: attempted to zero-initialize type `fn()`, which is invalid - -#[allow(deprecated, invalid_value)] -fn main() { - unsafe { std::mem::zeroed::() }; -} diff --git a/tests/compile-fail/overwriting_part_of_relocation_makes_the_rest_undefined.rs b/tests/compile-fail/overwriting_part_of_relocation_makes_the_rest_undefined.rs index d8182aaae662e..3eab4c0f3d5eb 100644 --- a/tests/compile-fail/overwriting_part_of_relocation_makes_the_rest_undefined.rs +++ b/tests/compile-fail/overwriting_part_of_relocation_makes_the_rest_undefined.rs @@ -1,3 +1,6 @@ +// Make sure we find these even with many checks disabled. +// compile-flags: -Zmiri-disable-alignment-check -Zmiri-disable-stacked-borrows -Zmiri-disable-validation + fn main() { let mut p = &42; unsafe { From e6822d60b3e2cc63ff0ae4603b1021cd0fb4dae8 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 14 Apr 2020 10:03:10 +0200 Subject: [PATCH 1868/3747] make sure we find some things without validation or stacked borrows, respectively --- tests/compile-fail/stacked_borrows/load_invalid_mut.rs | 3 +++ tests/compile-fail/stacked_borrows/load_invalid_shr.rs | 3 +++ tests/compile-fail/unaligned_pointers/unaligned_ptr1.rs | 4 ++-- tests/compile-fail/unaligned_pointers/unaligned_ptr2.rs | 4 ++-- tests/compile-fail/unaligned_pointers/unaligned_ptr3.rs | 4 ++-- tests/compile-fail/validity/dangling_ref1.rs | 2 ++ tests/compile-fail/validity/dangling_ref2.rs | 2 ++ tests/compile-fail/validity/dangling_ref3.rs | 2 ++ 8 files changed, 18 insertions(+), 6 deletions(-) diff --git a/tests/compile-fail/stacked_borrows/load_invalid_mut.rs b/tests/compile-fail/stacked_borrows/load_invalid_mut.rs index 1704b7fe19b2e..c2c4ce6726dfb 100644 --- a/tests/compile-fail/stacked_borrows/load_invalid_mut.rs +++ b/tests/compile-fail/stacked_borrows/load_invalid_mut.rs @@ -1,3 +1,6 @@ +// Make sure we catch this even without validation +// compile-flags: -Zmiri-disable-validation + // Make sure that we cannot load from memory a `&mut` that got already invalidated. fn main() { let x = &mut 42; diff --git a/tests/compile-fail/stacked_borrows/load_invalid_shr.rs b/tests/compile-fail/stacked_borrows/load_invalid_shr.rs index 4757a2c1e5894..7d681f649a107 100644 --- a/tests/compile-fail/stacked_borrows/load_invalid_shr.rs +++ b/tests/compile-fail/stacked_borrows/load_invalid_shr.rs @@ -1,3 +1,6 @@ +// Make sure we catch this even without validation +// compile-flags: -Zmiri-disable-validation + // Make sure that we cannot load from memory a `&` that got already invalidated. fn main() { let x = &mut 42; diff --git a/tests/compile-fail/unaligned_pointers/unaligned_ptr1.rs b/tests/compile-fail/unaligned_pointers/unaligned_ptr1.rs index ee1a130042317..0a67cfc5a1b36 100644 --- a/tests/compile-fail/unaligned_pointers/unaligned_ptr1.rs +++ b/tests/compile-fail/unaligned_pointers/unaligned_ptr1.rs @@ -1,5 +1,5 @@ -// This should fail even without validation -// compile-flags: -Zmiri-disable-validation +// This should fail even without validation or Stacked Borrows. +// compile-flags: -Zmiri-disable-validation -Zmiri-disable-stacked-borrows fn main() { let x = [2u16, 3, 4]; // Make it big enough so we don't get an out-of-bounds error. diff --git a/tests/compile-fail/unaligned_pointers/unaligned_ptr2.rs b/tests/compile-fail/unaligned_pointers/unaligned_ptr2.rs index 853d890ecf07e..b1fb2f4aa9762 100644 --- a/tests/compile-fail/unaligned_pointers/unaligned_ptr2.rs +++ b/tests/compile-fail/unaligned_pointers/unaligned_ptr2.rs @@ -1,5 +1,5 @@ -// This should fail even without validation. -// compile-flags: -Zmiri-disable-validation +// This should fail even without validation or Stacked Borrows. +// compile-flags: -Zmiri-disable-validation -Zmiri-disable-stacked-borrows fn main() { let x = [2u32, 3]; // Make it big enough so we don't get an out-of-bounds error. diff --git a/tests/compile-fail/unaligned_pointers/unaligned_ptr3.rs b/tests/compile-fail/unaligned_pointers/unaligned_ptr3.rs index 43f6b472da05b..c5a3398384e49 100644 --- a/tests/compile-fail/unaligned_pointers/unaligned_ptr3.rs +++ b/tests/compile-fail/unaligned_pointers/unaligned_ptr3.rs @@ -1,5 +1,5 @@ -// This should fail even without validation. -// compile-flags: -Zmiri-disable-validation +// This should fail even without validation or Stacked Borrows. +// compile-flags: -Zmiri-disable-validation -Zmiri-disable-stacked-borrows fn main() { let x = [2u16, 3, 4, 5]; // Make it big enough so we don't get an out-of-bounds error. diff --git a/tests/compile-fail/validity/dangling_ref1.rs b/tests/compile-fail/validity/dangling_ref1.rs index 034510f3b283a..a83c6af21acfd 100644 --- a/tests/compile-fail/validity/dangling_ref1.rs +++ b/tests/compile-fail/validity/dangling_ref1.rs @@ -1,3 +1,5 @@ +// Make sure we catch this even without Stacked Borrows +// compile-flags: -Zmiri-disable-stacked-borrows use std::mem; fn main() { diff --git a/tests/compile-fail/validity/dangling_ref2.rs b/tests/compile-fail/validity/dangling_ref2.rs index 4ad9b8135db44..7aff1a49785cc 100644 --- a/tests/compile-fail/validity/dangling_ref2.rs +++ b/tests/compile-fail/validity/dangling_ref2.rs @@ -1,3 +1,5 @@ +// Make sure we catch this even without Stacked Borrows +// compile-flags: -Zmiri-disable-stacked-borrows use std::mem; fn main() { diff --git a/tests/compile-fail/validity/dangling_ref3.rs b/tests/compile-fail/validity/dangling_ref3.rs index 46e17375a8282..495a266a85dc6 100644 --- a/tests/compile-fail/validity/dangling_ref3.rs +++ b/tests/compile-fail/validity/dangling_ref3.rs @@ -1,3 +1,5 @@ +// Make sure we catch this even without Stacked Borrows +// compile-flags: -Zmiri-disable-stacked-borrows use std::mem; fn dangling() -> *const u8 { From fff45b77adc7a08b1ee2d3c277e74f2ec7027ea2 Mon Sep 17 00:00:00 2001 From: Samrat Man Singh Date: Tue, 14 Apr 2020 13:59:43 +0530 Subject: [PATCH 1869/3747] Reword comment in mach_timebase_info Co-Authored-By: Ralf Jung --- src/shims/time.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/shims/time.rs b/src/shims/time.rs index c22ac9ca1a509..a87db98782024 100644 --- a/src/shims/time.rs +++ b/src/shims/time.rs @@ -169,9 +169,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let info = this.deref_operand(info_op)?; - // Since we return nanoseconds instead of ticks from - // `mach_absolute_time`, we don't need to scale the absolute - // time. + // Since our emulated ticks in `mach_absolute_time` *are* nanoseconds, + // no scaling needs to happen. let (numer, denom) = (1,1); let imms = [ immty_from_int_checked(numer, this.machine.layouts.u32)?, From 90d71cd13f26c50f1d1904eb3b436c4e1faf7d2c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 13 Apr 2020 16:08:12 +0200 Subject: [PATCH 1870/3747] adjust for frame hook changes --- src/machine.rs | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/machine.rs b/src/machine.rs index 54dfb49d798be..67b847603d8a5 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -490,21 +490,25 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { } #[inline(always)] - fn stack_push(ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx, FrameData<'tcx>> { + fn init_frame_extra( + ecx: &mut InterpCx<'mir, 'tcx, Self>, + frame: Frame<'mir, 'tcx, Tag>, + ) -> InterpResult<'tcx, Frame<'mir, 'tcx, Tag, FrameData<'tcx>>> { let stacked_borrows = ecx.memory.extra.stacked_borrows.as_ref(); let call_id = stacked_borrows.map_or(NonZeroU64::new(1).unwrap(), |stacked_borrows| { stacked_borrows.borrow_mut().new_call() }); - Ok(FrameData { call_id, catch_unwind: None }) + let extra = FrameData { call_id, catch_unwind: None }; + Ok(frame.with_extra(extra)) } #[inline(always)] - fn stack_pop( + fn after_stack_pop( ecx: &mut InterpCx<'mir, 'tcx, Self>, - extra: FrameData<'tcx>, + frame: Frame<'mir, 'tcx, Tag, FrameData<'tcx>>, unwinding: bool, ) -> InterpResult<'tcx, StackPopJump> { - ecx.handle_stack_pop(extra, unwinding) + ecx.handle_stack_pop(frame.extra, unwinding) } #[inline(always)] From 0805b4bf2e6070a6e2f1026624dee87b65ee4ed7 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 13 Apr 2020 17:31:19 +0200 Subject: [PATCH 1871/3747] retag return places --- src/machine.rs | 16 ++++++++++++---- src/stacked_borrows.rs | 43 +++++++++++++++++++++++++++++++++++++----- 2 files changed, 50 insertions(+), 9 deletions(-) diff --git a/src/machine.rs b/src/machine.rs index 67b847603d8a5..94603c3dfb4d6 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -481,11 +481,10 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { kind: mir::RetagKind, place: PlaceTy<'tcx, Tag>, ) -> InterpResult<'tcx> { - if ecx.memory.extra.stacked_borrows.is_none() { - // No tracking. - Ok(()) - } else { + if ecx.memory.extra.stacked_borrows.is_some() { ecx.retag(kind, place) + } else { + Ok(()) } } @@ -502,6 +501,15 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { Ok(frame.with_extra(extra)) } + #[inline(always)] + fn after_stack_push(ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx> { + if ecx.memory.extra.stacked_borrows.is_some() { + ecx.retag_return_place() + } else { + Ok(()) + } + } + #[inline(always)] fn after_stack_pop( ecx: &mut InterpCx<'mir, 'tcx, Self>, diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 89b2a8bb3e2b2..a69948002c126 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -11,7 +11,7 @@ use log::trace; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_middle::mir::RetagKind; use rustc_middle::ty; -use rustc_target::abi::Size; +use rustc_target::abi::{LayoutOf, Size}; use rustc_hir::Mutability; use crate::*; @@ -569,7 +569,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx val: ImmTy<'tcx, Tag>, kind: RefKind, protect: bool, - ) -> InterpResult<'tcx, Immediate> { + ) -> InterpResult<'tcx, ImmTy<'tcx, Tag>> { let this = self.eval_context_mut(); // We want a place for where the ptr *points to*, so we get one. let place = this.ref_to_mplace(val)?; @@ -582,7 +582,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let place = this.mplace_access_checked(place)?; if size == Size::ZERO { // Nothing to do for ZSTs. - return Ok(*val); + return Ok(val); } // Compute new borrow. @@ -603,7 +603,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let new_place = place.replace_tag(new_tag); // Return new pointer. - Ok(new_place.to_ref()) + Ok(ImmTy::from_immediate(new_place.to_ref(), val.layout)) } } @@ -640,9 +640,42 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Fast path. let val = this.read_immediate(this.place_to_op(place)?)?; let val = this.retag_reference(val, mutbl, protector)?; - this.write_immediate(val, place)?; + this.write_immediate(*val, place)?; } Ok(()) } + + /// After a stack frame got pushed, retag the return place so that we are sure + /// it does not alias with anything. + /// + /// This is a HACK because there is nothing in MIR that would make the retag + /// explicit. Also see https://github.com/rust-lang/rust/issues/71117. + fn retag_return_place(&mut self) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + let return_place = if let Some(return_place) = this.frame_mut().return_place { + return_place + } else { + // No return place, nothing to do. + return Ok(()); + }; + if return_place.layout.is_zst() { + // There may not be any memory here, nothing to do. + return Ok(()); + } + // We need this to be in-memory to use tagged pointers. + let return_place = this.force_allocation(return_place)?; + + // We have to turn the place into a pointer to use the existing code. + // (The pointer type does not matter, so we use a raw pointer.) + let ptr_layout = this.layout_of(this.tcx.mk_mut_ptr(return_place.layout.ty))?; + let val = ImmTy::from_immediate(return_place.to_ref(), ptr_layout); + // Reborrow it. + let val = this.retag_reference(val, RefKind::Unique { two_phase: false }, /*protector*/ true)?; + // And use reborrowed pointer for return place. + let return_place = this.ref_to_mplace(val)?; + this.frame_mut().return_place = Some(return_place.into()); + + Ok(()) + } } From 3548dcf8cc3021dcfe425df90d7feb14c0bdda61 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 15 Apr 2020 12:39:28 +0200 Subject: [PATCH 1872/3747] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 48247d653cdce..937073ef4fcc3 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -47f49695dfb4fe9e584239fdc59c771887148a57 +df768c5c8fcb361c4dc94b4c776d6a78c12862e1 From a85dab42ea2f5704260232112d240b1ee51017be Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 15 Apr 2020 12:41:54 +0200 Subject: [PATCH 1873/3747] tighten Instance sanity check --- tests/run-pass/time.rs | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/tests/run-pass/time.rs b/tests/run-pass/time.rs index 2c9b579f7e294..d430062a15333 100644 --- a/tests/run-pass/time.rs +++ b/tests/run-pass/time.rs @@ -1,22 +1,29 @@ // compile-flags: -Zmiri-disable-isolation -use std::time::{SystemTime, Instant}; +use std::time::{SystemTime, Instant, Duration}; + +fn duration_sanity(diff: Duration) { + // On my laptop, I observed times around 15-40ms. Add 10x lee-way both ways. + assert!(diff.as_millis() > 1); + assert!(diff.as_millis() < 500); +} fn main() { // Check `SystemTime`. let now1 = SystemTime::now(); + let seconds_since_epoch = now1.duration_since(SystemTime::UNIX_EPOCH).unwrap().as_secs(); + let years_since_epoch = seconds_since_epoch / 3600 / 24 / 365; + let year = 1970 + years_since_epoch; + assert!(2020 <= year && year < 2100); // Do some work to make time pass. for _ in 0..10 { drop(vec![42]); } let now2 = SystemTime::now(); assert!(now2 > now1); + // Sanity-check the difference we got. let diff = now2.duration_since(now1).unwrap(); assert_eq!(now1 + diff, now2); assert_eq!(now2 - diff, now1); - // Sanity-check the time we got. - let seconds_since_epoch = now1.duration_since(SystemTime::UNIX_EPOCH).unwrap().as_secs(); - let years_since_epoch = seconds_since_epoch / 3600 / 24 / 365; - let year = 1970 + years_since_epoch; - assert!(2020 <= year && year < 2100); + duration_sanity(diff); // Check `Instant`. let now1 = Instant::now(); @@ -24,10 +31,9 @@ fn main() { for _ in 0..10 { drop(vec![42]); } let now2 = Instant::now(); assert!(now2 > now1); + // Sanity-check the difference we got. let diff = now2.duration_since(now1); assert_eq!(now1 + diff, now2); assert_eq!(now2 - diff, now1); - // Sanity-check the difference we got. - assert!(diff.as_micros() > 1); - assert!(diff.as_micros() < 1_000_000); + duration_sanity(diff); } From b77968e8bd2bc556d0bd3cfb9f7d2521a6896199 Mon Sep 17 00:00:00 2001 From: Ozaren Date: Tue, 14 Apr 2020 19:00:56 -0400 Subject: [PATCH 1874/3747] added deallocation tracking --- README.md | 3 ++- src/diagnostics.rs | 3 +++ src/machine.rs | 14 +++++++++++++- 3 files changed, 18 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 76f95ee55e802..a86de4a555190 100644 --- a/README.md +++ b/README.md @@ -192,7 +192,8 @@ Miri adds its own set of `-Z` flags: for cryptographic use! Do not generate secret keys in Miri or perform other kinds of cryptographic operations that rely on proper random numbers. * `-Zmiri-track-alloc-id=` shows a backtrace when the given allocation is - being allocated. This helps in debugging memory leaks. + being allocated or freed. This helps in debugging memory leaks and + use after free bugs. * `-Zmiri-track-pointer-tag=` shows a backtrace when the given pointer tag is popped from a borrow stack (which is where the tag becomes invalid and any future use of it will error). This helps you in finding out why UB is diff --git a/src/diagnostics.rs b/src/diagnostics.rs index 2359b67323d75..8c7bb8a47c638 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -42,6 +42,7 @@ impl MachineStopType for TerminationInfo {} pub enum NonHaltingDiagnostic { PoppedTrackedPointerTag(Item), CreatedAlloc(AllocId), + FreedAlloc(AllocId), } /// Emit a custom diagnostic without going through the miri-engine machinery @@ -191,6 +192,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx format!("popped tracked tag for item {:?}", item), CreatedAlloc(AllocId(id)) => format!("created allocation with id {}", id), + FreedAlloc(AllocId(id)) => + format!("freed allocation with id {}", id), }; report_msg(this, "tracking was triggered", msg, vec![], false); } diff --git a/src/machine.rs b/src/machine.rs index 94603c3dfb4d6..5cf42df8268b9 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -116,7 +116,7 @@ pub struct MemoryExtra { pub(crate) rng: RefCell, /// An allocation ID to report when it is being allocated - /// (helps for debugging memory leaks). + /// (helps for debugging memory leaks and use after free bugs). tracked_alloc_id: Option, /// Controls whether alignment of memory accesses is being checked. @@ -466,6 +466,18 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { (Cow::Owned(alloc), base_tag) } + #[inline(always)] + fn before_deallocation( + memory_extra: &mut Self::MemoryExtra, + id: AllocId, + ) -> InterpResult<'tcx> { + if Some(id) == memory_extra.tracked_alloc_id { + register_diagnostic(NonHaltingDiagnostic::FreedAlloc(id)); + } + + Ok(()) + } + #[inline(always)] fn tag_global_base_pointer(memory_extra: &MemoryExtra, id: AllocId) -> Self::PointerTag { if let Some(stacked_borrows) = &memory_extra.stacked_borrows { From 07c696e27e0398f4bf1b77db09fadef1591d28e4 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 15 Apr 2020 18:00:16 +0200 Subject: [PATCH 1875/3747] test some so-far untested intrinsics --- src/shims/intrinsics.rs | 4 +++- tests/run-pass/intrinsics.rs | 17 +++++++++++++++-- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 0f17bee008875..0979cd7f062d0 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -471,7 +471,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "exact_div" => this.exact_div(this.read_immediate(args[0])?, this.read_immediate(args[1])?, dest)?, - "forget" => {} + "forget" => { + // We get an argument... and forget about it. + } #[rustfmt::skip] | "likely" diff --git a/tests/run-pass/intrinsics.rs b/tests/run-pass/intrinsics.rs index 754a38f63535b..63439c996af0a 100644 --- a/tests/run-pass/intrinsics.rs +++ b/tests/run-pass/intrinsics.rs @@ -1,8 +1,16 @@ #![feature(core_intrinsics)] -use std::intrinsics::type_name; +use std::intrinsics; use std::mem::{size_of, size_of_val}; +struct Bomb; + +impl Drop for Bomb { + fn drop(&mut self) { + eprintln!("BOOM!"); + } +} + fn main() { assert_eq!(size_of::>(), 8); assert_eq!(size_of_val(&()), 0); @@ -11,5 +19,10 @@ fn main() { assert_eq!(size_of_val(&[1, 2, 3] as &[i32]), 12); assert_eq!(size_of_val("foobar"), 6); - assert_eq!(type_name::>(), "core::option::Option"); + assert_eq!(intrinsics::type_name::>(), "core::option::Option"); + + assert_eq!(intrinsics::likely(false), false); + assert_eq!(intrinsics::unlikely(true), true); + + unsafe { intrinsics::forget(Bomb); } } From b0fe99e81defb29e7e6920f5307f4d940dd718fa Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 16 Apr 2020 09:06:21 +0200 Subject: [PATCH 1876/3747] consolidate ptr tests in fewer files --- tests/run-pass/ptr_arith_offset.rs | 6 --- tests/run-pass/ptr_arith_offset_overflow.rs | 12 ----- tests/run-pass/ptr_int_casts.rs | 28 ++++++++++- tests/run-pass/ptr_int_ops.rs | 20 -------- tests/run-pass/ptr_offset.rs | 56 ++++++++++++++++++++- tests/run-pass/ptr_offset_from.rs | 29 ----------- tests/run-pass/{raw.rs => ptr_raw.rs} | 0 7 files changed, 81 insertions(+), 70 deletions(-) delete mode 100644 tests/run-pass/ptr_arith_offset.rs delete mode 100644 tests/run-pass/ptr_arith_offset_overflow.rs delete mode 100644 tests/run-pass/ptr_int_ops.rs delete mode 100644 tests/run-pass/ptr_offset_from.rs rename tests/run-pass/{raw.rs => ptr_raw.rs} (100%) diff --git a/tests/run-pass/ptr_arith_offset.rs b/tests/run-pass/ptr_arith_offset.rs deleted file mode 100644 index a6ee151e3e13b..0000000000000 --- a/tests/run-pass/ptr_arith_offset.rs +++ /dev/null @@ -1,6 +0,0 @@ -fn main() { - let v = [1i16, 2]; - let x = &v as *const [i16] as *const i16; - let x = x.wrapping_offset(1); - assert_eq!(unsafe { *x }, 2); -} diff --git a/tests/run-pass/ptr_arith_offset_overflow.rs b/tests/run-pass/ptr_arith_offset_overflow.rs deleted file mode 100644 index fdd980e2177b5..0000000000000 --- a/tests/run-pass/ptr_arith_offset_overflow.rs +++ /dev/null @@ -1,12 +0,0 @@ -use std::ptr; - -fn main() { - let v = [1i16, 2]; - let x = &mut ptr::null(); // going through memory as there are more sanity checks along that path - *x = v.as_ptr().wrapping_offset(1); // ptr to the 2nd element - // Adding 2*isize::max and then 1 is like substracting 1 - *x = x.wrapping_offset(isize::MAX); - *x = x.wrapping_offset(isize::MAX); - *x = x.wrapping_offset(1); - assert_eq!(unsafe { **x }, 1); -} diff --git a/tests/run-pass/ptr_int_casts.rs b/tests/run-pass/ptr_int_casts.rs index 468b37af5beaa..b9815126a8c79 100644 --- a/tests/run-pass/ptr_int_casts.rs +++ b/tests/run-pass/ptr_int_casts.rs @@ -7,7 +7,7 @@ fn eq_ref(x: &T, y: &T) -> bool { fn f() -> i32 { 42 } -fn main() { +fn ptr_int_casts() { // int-ptr-int assert_eq!(1 as *const i32 as usize, 1); assert_eq!((1 as *const i32).wrapping_offset(4) as usize, 1 + 4*4); @@ -40,3 +40,29 @@ fn main() { // involving types other than usize assert_eq!((-1i32) as usize as *const i32 as usize, (-1i32) as usize); } + +fn ptr_int_ops() { + let v = [1i16, 2]; + let x = &v[1] as *const i16 as usize; + // arithmetic + let _y = x + 4; + let _y = 4 + x; + let _y = x - 2; + // bit-operations, covered by alignment + assert_eq!(x & 1, 0); + assert_eq!(x & 0, 0); + assert_eq!(1 & (x+1), 1); + let _y = !1 & x; + let _y = !0 & x; + let _y = x & !1; + // remainder, covered by alignment + assert_eq!(x % 2, 0); + assert_eq!((x+1) % 2, 1); + // remainder with 1 is always 0 + assert_eq!(x % 1, 0); +} + +fn main() { + ptr_int_casts(); + ptr_int_ops(); +} diff --git a/tests/run-pass/ptr_int_ops.rs b/tests/run-pass/ptr_int_ops.rs deleted file mode 100644 index 9a29c2d30837d..0000000000000 --- a/tests/run-pass/ptr_int_ops.rs +++ /dev/null @@ -1,20 +0,0 @@ -fn main() { - let v = [1i16, 2]; - let x = &v[1] as *const i16 as usize; - // arithmetic - let _y = x + 4; - let _y = 4 + x; - let _y = x - 2; - // bit-operations, covered by alignment - assert_eq!(x & 1, 0); - assert_eq!(x & 0, 0); - assert_eq!(1 & (x+1), 1); - let _y = !1 & x; - let _y = !0 & x; - let _y = x & !1; - // remainder, covered by alignment - assert_eq!(x % 2, 0); - assert_eq!((x+1) % 2, 1); - // remainder with 1 is always 0 - assert_eq!(x % 1, 0); -} diff --git a/tests/run-pass/ptr_offset.rs b/tests/run-pass/ptr_offset.rs index 1c7f0eb717974..f83720b547c02 100644 --- a/tests/run-pass/ptr_offset.rs +++ b/tests/run-pass/ptr_offset.rs @@ -1,6 +1,58 @@ -fn f() -> i32 { 42 } +#![feature(ptr_offset_from)] +use std::{mem, ptr}; fn main() { + test_offset_from(); + test_vec_into_iter(); + ptr_arith_offset(); + ptr_arith_offset_overflow(); + ptr_offset(); +} + +fn test_offset_from() { unsafe { + let buf = [0u32; 4]; + + let x = buf.as_ptr() as *const u8; + let y = x.offset(12); + + assert_eq!(y.offset_from(x), 12); + assert_eq!(x.offset_from(y), -12); + assert_eq!((y as *const u32).offset_from(x as *const u32), 12/4); + assert_eq!((x as *const u32).offset_from(y as *const u32), -12/4); + + let x = (((x as usize) * 2) / 2) as *const u8; + assert_eq!(y.offset_from(x), 12); + assert_eq!(x.offset_from(y), -12); +} } + +// This also internally uses offset_from. +fn test_vec_into_iter() { + let v = Vec::::new(); + let i = v.into_iter(); + i.size_hint(); +} + +fn ptr_arith_offset() { + let v = [1i16, 2]; + let x = &v as *const [i16] as *const i16; + let x = x.wrapping_offset(1); + assert_eq!(unsafe { *x }, 2); +} + +fn ptr_arith_offset_overflow() { + let v = [1i16, 2]; + let x = &mut ptr::null(); // going through memory as there are more sanity checks along that path + *x = v.as_ptr().wrapping_offset(1); // ptr to the 2nd element + // Adding 2*isize::max and then 1 is like substracting 1 + *x = x.wrapping_offset(isize::MAX); + *x = x.wrapping_offset(isize::MAX); + *x = x.wrapping_offset(1); + assert_eq!(unsafe { **x }, 1); +} + +fn ptr_offset() { + fn f() -> i32 { 42 } + let v = [1i16, 2]; let x = &v as *const [i16; 2] as *const i16; let x = unsafe { x.offset(1) }; @@ -10,7 +62,7 @@ fn main() { unsafe { let p = f as fn() -> i32 as usize; let x = (p as *mut u32).offset(0) as usize; - let f: fn() -> i32 = std::mem::transmute(x); + let f: fn() -> i32 = mem::transmute(x); assert_eq!(f(), 42); } } diff --git a/tests/run-pass/ptr_offset_from.rs b/tests/run-pass/ptr_offset_from.rs deleted file mode 100644 index 92eb3f6e46e3c..0000000000000 --- a/tests/run-pass/ptr_offset_from.rs +++ /dev/null @@ -1,29 +0,0 @@ -#![feature(ptr_offset_from)] - -fn test_raw() { unsafe { - let buf = [0u32; 4]; - - let x = buf.as_ptr() as *const u8; - let y = x.offset(12); - - assert_eq!(y.offset_from(x), 12); - assert_eq!(x.offset_from(y), -12); - assert_eq!((y as *const u32).offset_from(x as *const u32), 12/4); - assert_eq!((x as *const u32).offset_from(y as *const u32), -12/4); - - let x = (((x as usize) * 2) / 2) as *const u8; - assert_eq!(y.offset_from(x), 12); - assert_eq!(x.offset_from(y), -12); -} } - -// This also internally uses offset_from. -fn test_vec_into_iter() { - let v = Vec::::new(); - let i = v.into_iter(); - i.size_hint(); -} - -fn main() { - test_raw(); - test_vec_into_iter(); -} diff --git a/tests/run-pass/raw.rs b/tests/run-pass/ptr_raw.rs similarity index 100% rename from tests/run-pass/raw.rs rename to tests/run-pass/ptr_raw.rs From 974f9c30239a550ab8ccef75dd409ebb1faacf89 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 16 Apr 2020 09:25:12 +0200 Subject: [PATCH 1877/3747] avoid test-wide allowance of unused/dead code --- tests/run-pass/bitop-beyond-alignment.rs | 3 +-- tests/run-pass/dst-field-align.rs | 4 ++-- tests/run-pass/foreign-fn-linkname.rs | 2 -- tests/run-pass/issue-15063.rs | 3 +-- tests/run-pass/issue-35815.rs | 3 +-- tests/run-pass/issue-53728.rs | 6 ++++-- tests/run-pass/libc.rs | 8 +++----- tests/run-pass/packed_struct.rs | 4 +++- tests/run-pass/regions-mock-trans.rs | 4 ++-- tests/run-pass/rfc1623.rs | 2 +- tests/run-pass/small_enum_size_bug.rs | 3 +-- tests/run-pass/static_mut.rs | 3 +-- tests/run-pass/tag-align-dyn-u64.rs | 3 +-- tests/run-pass/union.rs | 5 +++-- 14 files changed, 24 insertions(+), 29 deletions(-) diff --git a/tests/run-pass/bitop-beyond-alignment.rs b/tests/run-pass/bitop-beyond-alignment.rs index 02031130b8dcc..e540a2a4b723f 100644 --- a/tests/run-pass/bitop-beyond-alignment.rs +++ b/tests/run-pass/bitop-beyond-alignment.rs @@ -8,14 +8,13 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![allow(dead_code)] - use std::mem; enum Tag { Tag2(A) } +#[allow(dead_code)] struct Rec { c8: u8, t: Tag diff --git a/tests/run-pass/dst-field-align.rs b/tests/run-pass/dst-field-align.rs index 7cd0c851b6387..6c827d7b3beae 100644 --- a/tests/run-pass/dst-field-align.rs +++ b/tests/run-pass/dst-field-align.rs @@ -1,5 +1,4 @@ -#![allow(dead_code)] - +#[allow(dead_code)] struct Foo { a: u16, b: T @@ -17,6 +16,7 @@ struct Baz { a: T } +#[allow(dead_code)] struct HasDrop { ptr: Box, data: T diff --git a/tests/run-pass/foreign-fn-linkname.rs b/tests/run-pass/foreign-fn-linkname.rs index ebb0e5364b94e..60303c7d7c7c7 100644 --- a/tests/run-pass/foreign-fn-linkname.rs +++ b/tests/run-pass/foreign-fn-linkname.rs @@ -1,7 +1,5 @@ //ignore-windows: Uses POSIX APIs - #![feature(rustc_private)] -#![allow(unused_extern_crates)] // rustc bug https://github.com/rust-lang/rust/issues/56098 extern crate libc; diff --git a/tests/run-pass/issue-15063.rs b/tests/run-pass/issue-15063.rs index 8ccf87ee7079e..c85590bb8b4bd 100644 --- a/tests/run-pass/issue-15063.rs +++ b/tests/run-pass/issue-15063.rs @@ -1,5 +1,4 @@ -#![allow(dead_code)] - +#[allow(dead_code)] enum Two { A, B } impl Drop for Two { fn drop(&mut self) { diff --git a/tests/run-pass/issue-35815.rs b/tests/run-pass/issue-35815.rs index fb0bd8e202fff..62b3220967edd 100644 --- a/tests/run-pass/issue-35815.rs +++ b/tests/run-pass/issue-35815.rs @@ -1,7 +1,6 @@ -#![allow(dead_code)] - use std::mem; +#[allow(dead_code)] struct Foo { a: i64, b: bool, diff --git a/tests/run-pass/issue-53728.rs b/tests/run-pass/issue-53728.rs index 6d440b66b35a0..0c858d3444fb3 100644 --- a/tests/run-pass/issue-53728.rs +++ b/tests/run-pass/issue-53728.rs @@ -1,14 +1,16 @@ -#![allow(dead_code)] - #[repr(u16)] +#[allow(dead_code)] enum DeviceKind { Nil = 0, } + #[repr(packed)] +#[allow(dead_code)] struct DeviceInfo { endianness: u8, device_kind: DeviceKind, } + fn main() { let _x = None::<(DeviceInfo, u8)>; let _y = None::<(DeviceInfo, u16)>; diff --git a/tests/run-pass/libc.rs b/tests/run-pass/libc.rs index fc154c05c8fc3..14d12de0d186d 100644 --- a/tests/run-pass/libc.rs +++ b/tests/run-pass/libc.rs @@ -2,14 +2,12 @@ // compile-flags: -Zmiri-disable-isolation #![feature(rustc_private)] -#![allow(unused)] // necessary on macos due to conditional compilation - -use std::path::PathBuf; extern crate libc; -fn tmp() -> PathBuf { - std::env::var("MIRI_TEMP").map(PathBuf::from).unwrap_or_else(|_| std::env::temp_dir()) +#[cfg(target_os = "linux")] +fn tmp() -> std::path::PathBuf { + std::env::var("MIRI_TEMP").map(std::path::PathBuf::from).unwrap_or_else(|_| std::env::temp_dir()) } #[cfg(target_os = "linux")] diff --git a/tests/run-pass/packed_struct.rs b/tests/run-pass/packed_struct.rs index 303e90742fc11..52b75d1a520ae 100644 --- a/tests/run-pass/packed_struct.rs +++ b/tests/run-pass/packed_struct.rs @@ -1,4 +1,3 @@ -#![allow(dead_code)] #![feature(unsize, coerce_unsized)] #[repr(packed)] @@ -8,12 +7,14 @@ struct S { } #[repr(packed)] +#[allow(dead_code)] struct Test1<'a> { x: u8, other: &'a u32, } #[repr(packed)] +#[allow(dead_code)] struct Test2<'a> { x: u8, other: &'a Test1<'a>, @@ -26,6 +27,7 @@ fn test(t: Test2) { fn test_unsizing() { #[repr(packed)] + #[allow(dead_code)] struct UnalignedPtr<'a, T: ?Sized> where T: 'a, { diff --git a/tests/run-pass/regions-mock-trans.rs b/tests/run-pass/regions-mock-trans.rs index 020ed4927a88b..0b2433d84fa88 100644 --- a/tests/run-pass/regions-mock-trans.rs +++ b/tests/run-pass/regions-mock-trans.rs @@ -2,8 +2,6 @@ #![feature(rustc_private)] -#![allow(dead_code)] - extern crate libc; use std::mem; @@ -13,11 +11,13 @@ struct Bcx<'a> { fcx: &'a Fcx<'a> } +#[allow(dead_code)] struct Fcx<'a> { arena: &'a Arena, ccx: &'a Ccx } +#[allow(dead_code)] struct Ccx { x: isize } diff --git a/tests/run-pass/rfc1623.rs b/tests/run-pass/rfc1623.rs index 2f893d8150c94..76e2c01e74505 100644 --- a/tests/run-pass/rfc1623.rs +++ b/tests/run-pass/rfc1623.rs @@ -1,4 +1,4 @@ -#![allow(dead_code)] +#![allow(dead_code)] // tons of unused statics here... // very simple test for a 'static static with default lifetime static STATIC_STR: &str = "&'static str"; diff --git a/tests/run-pass/small_enum_size_bug.rs b/tests/run-pass/small_enum_size_bug.rs index 7576a97e36adf..bb2f597444e77 100644 --- a/tests/run-pass/small_enum_size_bug.rs +++ b/tests/run-pass/small_enum_size_bug.rs @@ -1,5 +1,4 @@ -#![allow(dead_code)] - +#[allow(dead_code)] enum E { A = 1, B = 2, diff --git a/tests/run-pass/static_mut.rs b/tests/run-pass/static_mut.rs index be5830698b211..0aa6a2e92b624 100644 --- a/tests/run-pass/static_mut.rs +++ b/tests/run-pass/static_mut.rs @@ -1,8 +1,7 @@ -#![allow(dead_code)] - static mut FOO: i32 = 42; static BAR: Foo = Foo(unsafe { &FOO as *const _} ); +#[allow(dead_code)] struct Foo(*const i32); unsafe impl Sync for Foo {} diff --git a/tests/run-pass/tag-align-dyn-u64.rs b/tests/run-pass/tag-align-dyn-u64.rs index 81c19022ab080..8a97758fbb594 100644 --- a/tests/run-pass/tag-align-dyn-u64.rs +++ b/tests/run-pass/tag-align-dyn-u64.rs @@ -8,14 +8,13 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -#![allow(dead_code)] - use std::mem; enum Tag { Tag2(A) } +#[allow(dead_code)] struct Rec { c8: u8, t: Tag diff --git a/tests/run-pass/union.rs b/tests/run-pass/union.rs index 342c94f3d4a34..c80918ee527c2 100644 --- a/tests/run-pass/union.rs +++ b/tests/run-pass/union.rs @@ -1,5 +1,4 @@ #![feature(untagged_unions)] -#![allow(dead_code, unused_variables)] fn main() { a(); @@ -9,6 +8,7 @@ fn main() { } fn a() { + #[allow(dead_code)] union U { f1: u32, f2: f32, @@ -27,6 +27,7 @@ fn b() { y: u32, } + #[allow(dead_code)] union U { s: S, both: u64, @@ -82,7 +83,7 @@ fn d() { unsafe { match u { MyUnion { f1: 10 } => { } - MyUnion { f2 } => { panic!("foo"); } + MyUnion { f2: _f2 } => { panic!("foo"); } } } } From 3e3613f2e2f8ff27499d263ae3cd95565f685dea Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 16 Apr 2020 09:27:40 +0200 Subject: [PATCH 1878/3747] merge packed_static and packed_struct --- tests/run-pass/packed_static.rs | 10 ---- tests/run-pass/packed_struct.rs | 86 +++++++++++++++++++-------------- 2 files changed, 51 insertions(+), 45 deletions(-) delete mode 100644 tests/run-pass/packed_static.rs diff --git a/tests/run-pass/packed_static.rs b/tests/run-pass/packed_static.rs deleted file mode 100644 index 1fa3a369670bb..0000000000000 --- a/tests/run-pass/packed_static.rs +++ /dev/null @@ -1,10 +0,0 @@ -#[repr(packed)] -struct Foo { - i: i32 -} - -fn main() { - assert_eq!({FOO.i}, 42); -} - -static FOO: Foo = Foo { i: 42 }; diff --git a/tests/run-pass/packed_struct.rs b/tests/run-pass/packed_struct.rs index 52b75d1a520ae..cb0bc9859345a 100644 --- a/tests/run-pass/packed_struct.rs +++ b/tests/run-pass/packed_struct.rs @@ -1,28 +1,48 @@ #![feature(unsize, coerce_unsized)] -#[repr(packed)] -struct S { - a: i32, - b: i64, -} -#[repr(packed)] -#[allow(dead_code)] -struct Test1<'a> { - x: u8, - other: &'a u32, -} +fn test_basic() { + #[repr(packed)] + struct S { + a: i32, + b: i64, + } -#[repr(packed)] -#[allow(dead_code)] -struct Test2<'a> { - x: u8, - other: &'a Test1<'a>, -} + #[repr(packed)] + #[allow(dead_code)] + struct Test1<'a> { + x: u8, + other: &'a u32, + } + + #[repr(packed)] + #[allow(dead_code)] + struct Test2<'a> { + x: u8, + other: &'a Test1<'a>, + } -fn test(t: Test2) { - let x = *t.other.other; - assert_eq!(x, 42); + fn test(t: Test2) { + let x = *t.other.other; + assert_eq!(x, 42); + } + + let mut x = S { + a: 42, + b: 99, + }; + let a = x.a; + let b = x.b; + assert_eq!(a, 42); + assert_eq!(b, 99); + // can't do `assert_eq!(x.a, 42)`, because `assert_eq!` takes a reference + assert_eq!({x.a}, 42); + assert_eq!({x.b}, 99); + + x.b = 77; + assert_eq!({x.b}, 77); + + test(Test2 { x: 0, other: &Test1 { x: 0, other: &42 }}); } fn test_unsizing() { @@ -83,25 +103,21 @@ fn test_inner_packed() { let _o2 = o.clone(); } -fn main() { - let mut x = S { - a: 42, - b: 99, - }; - let a = x.a; - let b = x.b; - assert_eq!(a, 42); - assert_eq!(b, 99); - // can't do `assert_eq!(x.a, 42)`, because `assert_eq!` takes a reference - assert_eq!({x.a}, 42); - assert_eq!({x.b}, 99); +fn test_static() { + #[repr(packed)] + struct Foo { + i: i32 + } - x.b = 77; - assert_eq!({x.b}, 77); + static FOO: Foo = Foo { i: 42 }; - test(Test2 { x: 0, other: &Test1 { x: 0, other: &42 }}); + assert_eq!({FOO.i}, 42); +} +fn main() { + test_basic(); test_unsizing(); test_drop(); test_inner_packed(); + test_static(); } From ff3b382b14a329e597fa8f714f75c40344522ebb Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 16 Apr 2020 18:35:42 +0200 Subject: [PATCH 1879/3747] ReadBytesAsPointer is always supported --- src/diagnostics.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/diagnostics.rs b/src/diagnostics.rs index 8c7bb8a47c638..ff52e2385e476 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -92,6 +92,8 @@ pub fn report_error<'tcx, 'mir>( let helps = match e.kind { Unsupported(UnsupportedOpInfo::NoMirFor(..)) => vec![format!("make sure to use a Miri sysroot, which you can prepare with `cargo miri setup`")], + Unsupported(UnsupportedOpInfo::ReadBytesAsPointer) => + panic!("`ReadBytesAsPointer` cannot be raised by Miri"), Unsupported(_) => vec![format!("this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support")], UndefinedBehavior(UndefinedBehaviorInfo::AlignmentCheckFailed { .. }) => From 57c7119315132220ef547bed0dc8d15272190291 Mon Sep 17 00:00:00 2001 From: David Cook Date: Thu, 16 Apr 2020 23:24:57 -0500 Subject: [PATCH 1880/3747] Handle std::sync::atomic::spin_loop_hint() --- src/shims/foreign_items.rs | 17 +++++++++++++---- tests/run-pass/sync.rs | 6 ++++++ 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 7e7f17b0dbd4a..e816a35253d95 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -434,10 +434,19 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // Target-specific shims - _ => match this.tcx.sess.target.target.target_os.as_str() { - "linux" | "macos" => return posix::EvalContextExt::emulate_foreign_item_by_name(this, link_name, args, dest, ret), - "windows" => return windows::EvalContextExt::emulate_foreign_item_by_name(this, link_name, args, dest, ret), - target => throw_unsup_format!("the target `{}` is not supported", target), + _ => { + match this.tcx.sess.target.target.arch.as_str() { + "x86" | "x86_64" => match link_name { + "llvm.x86.sse2.pause" => return Ok(true), + _ => {} + } + _ => {} + } + match this.tcx.sess.target.target.target_os.as_str() { + "linux" | "macos" => return posix::EvalContextExt::emulate_foreign_item_by_name(this, link_name, args, dest, ret), + "windows" => return windows::EvalContextExt::emulate_foreign_item_by_name(this, link_name, args, dest, ret), + target => throw_unsup_format!("the target `{}` is not supported", target), + } } }; diff --git a/tests/run-pass/sync.rs b/tests/run-pass/sync.rs index 1ede5d42bb4ba..90885880e681f 100644 --- a/tests/run-pass/sync.rs +++ b/tests/run-pass/sync.rs @@ -1,6 +1,7 @@ #![feature(rustc_private)] use std::sync::{Mutex, TryLockError}; +use std::sync::atomic; fn main() { test_mutex_stdlib(); @@ -8,6 +9,7 @@ fn main() { { test_rwlock_stdlib(); } + test_spin_loop_hint(); } fn test_mutex_stdlib() { @@ -50,3 +52,7 @@ impl TryLockErrorExt for TryLockError { } } } + +fn test_spin_loop_hint() { + atomic::spin_loop_hint(); +} From 6a81014ae9f169b4b6277b76052ea0a032049477 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 17 Apr 2020 11:03:20 +0200 Subject: [PATCH 1881/3747] test #[derive] on packed struct --- tests/run-pass/packed_struct.rs | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/tests/run-pass/packed_struct.rs b/tests/run-pass/packed_struct.rs index cb0bc9859345a..7aa53ef568f56 100644 --- a/tests/run-pass/packed_struct.rs +++ b/tests/run-pass/packed_struct.rs @@ -1,5 +1,7 @@ #![feature(unsize, coerce_unsized)] +use std::collections::hash_map::DefaultHasher; +use std::hash::Hash; fn test_basic() { #[repr(packed)] @@ -114,10 +116,31 @@ fn test_static() { assert_eq!({FOO.i}, 42); } +fn test_derive() { + #[repr(packed)] + #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default, Debug)] + struct P { + a: usize, + b: u8, + c: usize, + } + + let x = P {a: 1usize, b: 2u8, c: 3usize}; + let y = P {a: 1usize, b: 2u8, c: 4usize}; + + let _clone = x.clone(); + assert!(x != y); + assert_eq!(x.partial_cmp(&y).unwrap(), x.cmp(&y)); + x.hash(&mut DefaultHasher::new()); + P::default(); + format!("{:?}", x); +} + fn main() { test_basic(); test_unsizing(); test_drop(); test_inner_packed(); test_static(); + test_derive(); } From 6ad0187265dfbd9dc145042a5a809db688abbe7a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 17 Apr 2020 14:19:26 +0200 Subject: [PATCH 1882/3747] rustup for FieldsShape::Primitive --- rust-version | 2 +- src/helpers.rs | 9 ++++----- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/rust-version b/rust-version index 937073ef4fcc3..e9b00f6497768 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -df768c5c8fcb361c4dc94b4c776d6a78c12862e1 +b2c1a606feb1fbdb0ac0acba76f881ef172ed474 diff --git a/src/helpers.rs b/src/helpers.rs index 9f46a0c1ce2d9..40a33f09a83c4 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -1,5 +1,6 @@ use std::convert::TryFrom; use std::mem; +use std::num::NonZeroUsize; use log::trace; @@ -333,17 +334,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx places.sort_by_key(|place| place.ptr.assert_ptr().offset); self.walk_aggregate(place, places.into_iter().map(Ok)) } - FieldsShape::Union { .. } => { + FieldsShape::Union { .. } | FieldsShape::Primitive => { // Uh, what? - bug!("a union is not an aggregate we should ever visit") + bug!("unions/primitives are not aggregates we should ever visit") } } } // We have to do *something* for unions. - fn visit_union(&mut self, v: MPlaceTy<'tcx, Tag>, fields: usize) -> InterpResult<'tcx> { - assert!(fields > 0); // we should never reach "pseudo-unions" with 0 fields, like primitives - + fn visit_union(&mut self, v: MPlaceTy<'tcx, Tag>, _fields: NonZeroUsize) -> InterpResult<'tcx> { // With unions, we fall back to whatever the type says, to hopefully be consistent // with LLVM IR. // FIXME: are we consistent, and is this really the behavior we want? From 521e77d712a4b633701f57dc8d404827db76518a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 17 Apr 2020 20:43:54 +0200 Subject: [PATCH 1883/3747] test that we properly check dynamic alignment --- .../unaligned_pointers/dyn_alignment.rs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 tests/compile-fail/unaligned_pointers/dyn_alignment.rs diff --git a/tests/compile-fail/unaligned_pointers/dyn_alignment.rs b/tests/compile-fail/unaligned_pointers/dyn_alignment.rs new file mode 100644 index 0000000000000..a8cf54edc85fe --- /dev/null +++ b/tests/compile-fail/unaligned_pointers/dyn_alignment.rs @@ -0,0 +1,19 @@ +// should find the bug even without these +// compile-flags: -Zmiri-disable-validation -Zmiri-disable-stacked-borrows + +#[repr(align(256))] +#[derive(Debug)] +struct MuchAlign; + +fn main() { + let buf = [0u32; 256]; + // `buf` is sufficiently aligned for `layout.align` on a `dyn Debug`, but not + // for the actual alignment required by `MuchAlign`. + // We craft a wide reference `&dyn Debug` with the vtable for `MuchAlign`. That should be UB, + // as the reference is not aligned to its dynamic alignment requirements. + let mut ptr = &MuchAlign as &dyn std::fmt::Debug; + // Overwrite the data part of `ptr`. + unsafe { (&mut ptr as *mut _ as *mut *const u8).write(&buf as *const _ as *const u8); } + // Re-borrow that. This should be UB. + let _ptr = &*ptr; //~ ERROR accessing memory with alignment 4, but alignment 256 is required +} From c6ab27577b3291036788735058194e9bb05dc70c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 18 Apr 2020 02:06:36 +0200 Subject: [PATCH 1884/3747] test that we check dynamic actual size of object --- tests/compile-fail/dangling_pointers/dyn_size.rs | 13 +++++++++++++ .../unaligned_pointers/dyn_alignment.rs | 2 +- 2 files changed, 14 insertions(+), 1 deletion(-) create mode 100644 tests/compile-fail/dangling_pointers/dyn_size.rs diff --git a/tests/compile-fail/dangling_pointers/dyn_size.rs b/tests/compile-fail/dangling_pointers/dyn_size.rs new file mode 100644 index 0000000000000..c8f1ee31137a9 --- /dev/null +++ b/tests/compile-fail/dangling_pointers/dyn_size.rs @@ -0,0 +1,13 @@ +// should find the bug even without these +// compile-flags: -Zmiri-disable-validation -Zmiri-disable-stacked-borrows + +struct SliceWithHead(u8, [u8]); + +fn main() { + let buf = [0u32; 1]; + // We craft a wide pointer `*const SliceWithHead` such that the unsized tail is only partially allocated. + // That should be UB, as the reference is not fully dereferencable. + let ptr: *const SliceWithHead = unsafe { std::mem::transmute((&buf, 4usize)) }; + // Re-borrow that. This should be UB. + let _ptr = unsafe { &*ptr }; //~ ERROR pointer must be in-bounds at offset 5 +} diff --git a/tests/compile-fail/unaligned_pointers/dyn_alignment.rs b/tests/compile-fail/unaligned_pointers/dyn_alignment.rs index a8cf54edc85fe..4d0b3af0952c1 100644 --- a/tests/compile-fail/unaligned_pointers/dyn_alignment.rs +++ b/tests/compile-fail/unaligned_pointers/dyn_alignment.rs @@ -12,7 +12,7 @@ fn main() { // We craft a wide reference `&dyn Debug` with the vtable for `MuchAlign`. That should be UB, // as the reference is not aligned to its dynamic alignment requirements. let mut ptr = &MuchAlign as &dyn std::fmt::Debug; - // Overwrite the data part of `ptr`. + // Overwrite the data part of `ptr` so it points to `buf`. unsafe { (&mut ptr as *mut _ as *mut *const u8).write(&buf as *const _ as *const u8); } // Re-borrow that. This should be UB. let _ptr = &*ptr; //~ ERROR accessing memory with alignment 4, but alignment 256 is required From 0345ee42da3a206e92cecd42b0b472b82552af95 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 18 Apr 2020 09:15:59 +0200 Subject: [PATCH 1885/3747] some UB gets masked by optimizations --- tests/compile-fail/dangling_pointers/dyn_size.rs | 4 ++-- tests/compile-fail/unaligned_pointers/dyn_alignment.rs | 4 ++-- tests/compile-fail/validity/nonzero.rs | 3 ++- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/tests/compile-fail/dangling_pointers/dyn_size.rs b/tests/compile-fail/dangling_pointers/dyn_size.rs index c8f1ee31137a9..39a091387c6c2 100644 --- a/tests/compile-fail/dangling_pointers/dyn_size.rs +++ b/tests/compile-fail/dangling_pointers/dyn_size.rs @@ -1,5 +1,5 @@ -// should find the bug even without these -// compile-flags: -Zmiri-disable-validation -Zmiri-disable-stacked-borrows +// should find the bug even without these, but gets masked by optimizations +// compile-flags: -Zmiri-disable-validation -Zmiri-disable-stacked-borrows -Zmir-opt-level=0 struct SliceWithHead(u8, [u8]); diff --git a/tests/compile-fail/unaligned_pointers/dyn_alignment.rs b/tests/compile-fail/unaligned_pointers/dyn_alignment.rs index 4d0b3af0952c1..aa293a5d2167b 100644 --- a/tests/compile-fail/unaligned_pointers/dyn_alignment.rs +++ b/tests/compile-fail/unaligned_pointers/dyn_alignment.rs @@ -1,5 +1,5 @@ -// should find the bug even without these -// compile-flags: -Zmiri-disable-validation -Zmiri-disable-stacked-borrows +// should find the bug even without these, but gets masked by optimizations +// compile-flags: -Zmiri-disable-validation -Zmiri-disable-stacked-borrows -Zmir-opt-level=0 #[repr(align(256))] #[derive(Debug)] diff --git a/tests/compile-fail/validity/nonzero.rs b/tests/compile-fail/validity/nonzero.rs index dbb31b3f17575..8ff19a2b43865 100644 --- a/tests/compile-fail/validity/nonzero.rs +++ b/tests/compile-fail/validity/nonzero.rs @@ -1,4 +1,5 @@ -// compile-flags: -Zmir-opt-level=1 +// gets masked by optimizations +// compile-flags: -Zmir-opt-level=0 #![feature(rustc_attrs)] #![allow(unused_attributes)] From bb38ab4340b944cb047ea0977d4198aaa9a36dec Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 18 Apr 2020 10:11:45 +0200 Subject: [PATCH 1886/3747] use u128::MAX symbolic name --- tests/compile-fail/intrinsics/float_to_int_64_too_big4.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/compile-fail/intrinsics/float_to_int_64_too_big4.rs b/tests/compile-fail/intrinsics/float_to_int_64_too_big4.rs index d5b24347b9419..e9623dba947f3 100644 --- a/tests/compile-fail/intrinsics/float_to_int_64_too_big4.rs +++ b/tests/compile-fail/intrinsics/float_to_int_64_too_big4.rs @@ -6,5 +6,5 @@ extern "rust-intrinsic" { } fn main() { - unsafe { float_to_int_unchecked::(340282366920938463463374607431768211455.0f64); } //~ ERROR: cannot be represented in target type `u128` + unsafe { float_to_int_unchecked::(u128::MAX as f64); } //~ ERROR: cannot be represented in target type `u128` } From 699685c07cc017792eae9f7a21553e394f49d1c1 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 18 Apr 2020 13:07:50 +0200 Subject: [PATCH 1887/3747] rename test_cast -> test_both_cast to make purpose clearer --- tests/run-pass/float.rs | 128 ++++++++++++++++++++-------------------- 1 file changed, 64 insertions(+), 64 deletions(-) diff --git a/tests/run-pass/float.rs b/tests/run-pass/float.rs index 364388571f44c..c56d12a0c00e7 100644 --- a/tests/run-pass/float.rs +++ b/tests/run-pass/float.rs @@ -68,7 +68,7 @@ impl FloatToInt for f64 { /// Test this cast both via `as` and via `approx_unchecked` (i.e., it must not saturate). #[track_caller] #[inline(never)] -fn test_cast(x: F, y: I) +fn test_both_cast(x: F, y: I) where F: FloatToInt, I: PartialEq + Debug { assert_eq!(x.cast(), y); @@ -116,22 +116,22 @@ fn basic() { fn casts() { // f32 -> i8 - test_cast::(127.99, 127); - test_cast::(-128.99, -128); + test_both_cast::(127.99, 127); + test_both_cast::(-128.99, -128); // f32 -> i32 - test_cast::(0.0, 0); - test_cast::(-0.0, 0); - test_cast::(/*0x1p-149*/ f32::from_bits(0x00000001), 0); - test_cast::(/*-0x1p-149*/ f32::from_bits(0x80000001), 0); - test_cast::(/*0x1.19999ap+0*/ f32::from_bits(0x3f8ccccd), 1); - test_cast::(/*-0x1.19999ap+0*/ f32::from_bits(0xbf8ccccd), -1); - test_cast::(1.9, 1); - test_cast::(-1.9, -1); - test_cast::(5.0, 5); - test_cast::(-5.0, -5); - test_cast::(2147483520.0, 2147483520); - test_cast::(-2147483648.0, -2147483648); + test_both_cast::(0.0, 0); + test_both_cast::(-0.0, 0); + test_both_cast::(/*0x1p-149*/ f32::from_bits(0x00000001), 0); + test_both_cast::(/*-0x1p-149*/ f32::from_bits(0x80000001), 0); + test_both_cast::(/*0x1.19999ap+0*/ f32::from_bits(0x3f8ccccd), 1); + test_both_cast::(/*-0x1.19999ap+0*/ f32::from_bits(0xbf8ccccd), -1); + test_both_cast::(1.9, 1); + test_both_cast::(-1.9, -1); + test_both_cast::(5.0, 5); + test_both_cast::(-5.0, -5); + test_both_cast::(2147483520.0, 2147483520); + test_both_cast::(-2147483648.0, -2147483648); // unrepresentable casts assert_eq::(2147483648.0f32 as i32, i32::MAX); assert_eq::(-2147483904.0f32 as i32, i32::MIN); @@ -143,19 +143,19 @@ fn casts() { assert_eq::((-f32::NAN) as i32, 0); // f32 -> u32 - test_cast::(0.0, 0); - test_cast::(-0.0, 0); - test_cast::(-0.9999999, 0); - test_cast::(/*0x1p-149*/ f32::from_bits(0x1), 0); - test_cast::(/*-0x1p-149*/ f32::from_bits(0x80000001), 0); - test_cast::(/*0x1.19999ap+0*/ f32::from_bits(0x3f8ccccd), 1); - test_cast::(1.9, 1); - test_cast::(5.0, 5); - test_cast::(2147483648.0, 0x8000_0000); - test_cast::(4294967040.0, 0u32.wrapping_sub(256)); - test_cast::(/*-0x1.ccccccp-1*/ f32::from_bits(0xbf666666), 0); - test_cast::(/*-0x1.fffffep-1*/ f32::from_bits(0xbf7fffff), 0); - test_cast::((u32::MAX-128) as f32, u32::MAX-255); // rounding loss + test_both_cast::(0.0, 0); + test_both_cast::(-0.0, 0); + test_both_cast::(-0.9999999, 0); + test_both_cast::(/*0x1p-149*/ f32::from_bits(0x1), 0); + test_both_cast::(/*-0x1p-149*/ f32::from_bits(0x80000001), 0); + test_both_cast::(/*0x1.19999ap+0*/ f32::from_bits(0x3f8ccccd), 1); + test_both_cast::(1.9, 1); + test_both_cast::(5.0, 5); + test_both_cast::(2147483648.0, 0x8000_0000); + test_both_cast::(4294967040.0, 0u32.wrapping_sub(256)); + test_both_cast::(/*-0x1.ccccccp-1*/ f32::from_bits(0xbf666666), 0); + test_both_cast::(/*-0x1.fffffep-1*/ f32::from_bits(0xbf7fffff), 0); + test_both_cast::((u32::MAX-128) as f32, u32::MAX-255); // rounding loss // unrepresentable casts assert_eq::((u32::MAX-127) as f32 as u32, u32::MAX); // rounds up and then becomes unrepresentable assert_eq::(4294967296.0f32 as u32, u32::MAX); @@ -168,44 +168,44 @@ fn casts() { assert_eq::((-f32::NAN) as u32, 0); // f32 -> i64 - test_cast::(4294967296.0, 4294967296); - test_cast::(-4294967296.0, -4294967296); - test_cast::(9223371487098961920.0, 9223371487098961920); - test_cast::(-9223372036854775808.0, -9223372036854775808); + test_both_cast::(4294967296.0, 4294967296); + test_both_cast::(-4294967296.0, -4294967296); + test_both_cast::(9223371487098961920.0, 9223371487098961920); + test_both_cast::(-9223372036854775808.0, -9223372036854775808); // f64 -> i8 - test_cast::(127.99, 127); - test_cast::(-128.99, -128); + test_both_cast::(127.99, 127); + test_both_cast::(-128.99, -128); // f64 -> i32 - test_cast::(0.0, 0); - test_cast::(-0.0, 0); - test_cast::(/*0x1.199999999999ap+0*/ f64::from_bits(0x3ff199999999999a), 1); - test_cast::(/*-0x1.199999999999ap+0*/ f64::from_bits(0xbff199999999999a), -1); - test_cast::(1.9, 1); - test_cast::(-1.9, -1); - test_cast::(1e8, 100_000_000); - test_cast::(2147483647.0, 2147483647); - test_cast::(-2147483648.0, -2147483648); + test_both_cast::(0.0, 0); + test_both_cast::(-0.0, 0); + test_both_cast::(/*0x1.199999999999ap+0*/ f64::from_bits(0x3ff199999999999a), 1); + test_both_cast::(/*-0x1.199999999999ap+0*/ f64::from_bits(0xbff199999999999a), -1); + test_both_cast::(1.9, 1); + test_both_cast::(-1.9, -1); + test_both_cast::(1e8, 100_000_000); + test_both_cast::(2147483647.0, 2147483647); + test_both_cast::(-2147483648.0, -2147483648); // unrepresentable casts assert_eq::(2147483648.0f64 as i32, i32::MAX); assert_eq::(-2147483649.0f64 as i32, i32::MIN); // f64 -> i64 - test_cast::(0.0, 0); - test_cast::(-0.0, 0); - test_cast::(/*0x0.0000000000001p-1022*/ f64::from_bits(0x1), 0); - test_cast::(/*-0x0.0000000000001p-1022*/ f64::from_bits(0x8000000000000001), 0); - test_cast::(/*0x1.199999999999ap+0*/ f64::from_bits(0x3ff199999999999a), 1); - test_cast::(/*-0x1.199999999999ap+0*/ f64::from_bits(0xbff199999999999a), -1); - test_cast::(5.0, 5); - test_cast::(5.9, 5); - test_cast::(-5.0, -5); - test_cast::(-5.9, -5); - test_cast::(4294967296.0, 4294967296); - test_cast::(-4294967296.0, -4294967296); - test_cast::(9223372036854774784.0, 9223372036854774784); - test_cast::(-9223372036854775808.0, -9223372036854775808); + test_both_cast::(0.0, 0); + test_both_cast::(-0.0, 0); + test_both_cast::(/*0x0.0000000000001p-1022*/ f64::from_bits(0x1), 0); + test_both_cast::(/*-0x0.0000000000001p-1022*/ f64::from_bits(0x8000000000000001), 0); + test_both_cast::(/*0x1.199999999999ap+0*/ f64::from_bits(0x3ff199999999999a), 1); + test_both_cast::(/*-0x1.199999999999ap+0*/ f64::from_bits(0xbff199999999999a), -1); + test_both_cast::(5.0, 5); + test_both_cast::(5.9, 5); + test_both_cast::(-5.0, -5); + test_both_cast::(-5.9, -5); + test_both_cast::(4294967296.0, 4294967296); + test_both_cast::(-4294967296.0, -4294967296); + test_both_cast::(9223372036854774784.0, 9223372036854774784); + test_both_cast::(-9223372036854775808.0, -9223372036854775808); // unrepresentable casts assert_eq::(9223372036854775808.0f64 as i64, i64::MAX); assert_eq::(-9223372036854777856.0f64 as i64, i64::MIN); @@ -217,13 +217,13 @@ fn casts() { assert_eq::((-f64::NAN) as i64, 0); // f64 -> u64 - test_cast::(0.0, 0); - test_cast::(-0.0, 0); - test_cast::(-0.99999999999, 0); - test_cast::(5.0, 5); - test_cast::(1e16, 10000000000000000); - test_cast::((u64::MAX-1024) as f64, u64::MAX-2047); // rounding loss - test_cast::(9223372036854775808.0, 9223372036854775808); + test_both_cast::(0.0, 0); + test_both_cast::(-0.0, 0); + test_both_cast::(-0.99999999999, 0); + test_both_cast::(5.0, 5); + test_both_cast::(1e16, 10000000000000000); + test_both_cast::((u64::MAX-1024) as f64, u64::MAX-2047); // rounding loss + test_both_cast::(9223372036854775808.0, 9223372036854775808); // unrepresentable casts assert_eq::(-5.0f64 as u64, 0); assert_eq::((u64::MAX-1023) as f64 as u64, u64::MAX); // rounds up and then becomes unrepresentable From 14f50b34a3ee72beca54283a61e152bb088aa8e6 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 18 Apr 2020 17:53:54 +0200 Subject: [PATCH 1888/3747] use pre-computed layouts some more --- src/eval.rs | 6 +++--- src/machine.rs | 22 +++++++++++++++------- src/shims/env.rs | 2 +- src/shims/panic.rs | 6 +++--- src/shims/time.rs | 4 +--- src/shims/tls.rs | 8 ++++---- 6 files changed, 27 insertions(+), 21 deletions(-) diff --git a/src/eval.rs b/src/eval.rs index b360b1bd8bbc5..1caffe2647617 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -130,7 +130,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( // Store `argc` and `argv` for macOS `_NSGetArg{c,v}`. { let argc_place = - ecx.allocate(ecx.layout_of(tcx.types.isize)?, MiriMemoryKind::Machine.into()); + ecx.allocate(ecx.machine.layouts.isize, MiriMemoryKind::Machine.into()); ecx.write_scalar(argc, argc_place.into())?; ecx.machine.argc = Some(argc_place.ptr); @@ -168,7 +168,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( }; // Return place (in static memory so that it does not count as leak). - let ret_place = ecx.allocate(ecx.layout_of(tcx.types.isize)?, MiriMemoryKind::Machine.into()); + let ret_place = ecx.allocate(ecx.machine.layouts.isize, MiriMemoryKind::Machine.into()); // Call start function. ecx.call_function( start_instance, @@ -178,7 +178,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( )?; // Set the last_error to 0 - let errno_layout = ecx.layout_of(tcx.types.u32)?; + let errno_layout = ecx.machine.layouts.u32; let errno_place = ecx.allocate(errno_layout, MiriMemoryKind::Machine.into()); ecx.write_scalar(Scalar::from_u32(0), errno_place.into())?; ecx.machine.last_error = Some(errno_place); diff --git a/src/machine.rs b/src/machine.rs index 5cf42df8268b9..236b31ec4af54 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -168,7 +168,7 @@ impl MemoryExtra { "linux" => { // "__cxa_thread_atexit_impl" // This should be all-zero, pointer-sized. - let layout = this.layout_of(this.tcx.types.usize)?; + let layout = this.machine.layouts.usize; let place = this.allocate(layout, MiriMemoryKind::Machine.into()); this.write_scalar(Scalar::from_machine_usize(0, this), place.into())?; Self::add_extern_static(this, "__cxa_thread_atexit_impl", place.ptr); @@ -178,7 +178,7 @@ impl MemoryExtra { "windows" => { // "_tls_used" // This is some obscure hack that is part of the Windows TLS story. It's a `u8`. - let layout = this.layout_of(this.tcx.types.u8)?; + let layout = this.machine.layouts.u8; let place = this.allocate(layout, MiriMemoryKind::Machine.into()); this.write_scalar(Scalar::from_u8(0), place.into())?; Self::add_extern_static(this, "_tls_used", place.ptr); @@ -190,16 +190,26 @@ impl MemoryExtra { } /// Precomputed layouts of primitive types -pub(crate) struct PrimitiveLayouts<'tcx> { - pub(crate) i32: TyAndLayout<'tcx>, - pub(crate) u32: TyAndLayout<'tcx>, +pub struct PrimitiveLayouts<'tcx> { + pub unit: TyAndLayout<'tcx>, + pub i8: TyAndLayout<'tcx>, + pub i32: TyAndLayout<'tcx>, + pub isize: TyAndLayout<'tcx>, + pub u8: TyAndLayout<'tcx>, + pub u32: TyAndLayout<'tcx>, + pub usize: TyAndLayout<'tcx>, } impl<'mir, 'tcx: 'mir> PrimitiveLayouts<'tcx> { fn new(layout_cx: LayoutCx<'tcx, TyCtxt<'tcx>>) -> Result> { Ok(Self { + unit: layout_cx.layout_of(layout_cx.tcx.mk_unit())?, + i8: layout_cx.layout_of(layout_cx.tcx.types.i8)?, i32: layout_cx.layout_of(layout_cx.tcx.types.i32)?, + isize: layout_cx.layout_of(layout_cx.tcx.types.isize)?, + u8: layout_cx.layout_of(layout_cx.tcx.types.u8)?, u32: layout_cx.layout_of(layout_cx.tcx.types.u32)?, + usize: layout_cx.layout_of(layout_cx.tcx.types.usize)?, }) } } @@ -242,8 +252,6 @@ pub struct Evaluator<'tcx> { pub(crate) time_anchor: Instant, /// Precomputed `TyLayout`s for primitive data types that are commonly used inside Miri. - /// FIXME: Search through the rest of the codebase for more layout_of() calls that - /// could be stored here. pub(crate) layouts: PrimitiveLayouts<'tcx>, } diff --git a/src/shims/env.rs b/src/shims/env.rs index 4401682722943..8dd2a3ca302a0 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -384,7 +384,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } else { // No `environ` allocated yet, let's do that. // This is memory backing an extern static, hence `Machine`, not `Env`. - let layout = this.layout_of(this.tcx.types.usize)?; + let layout = this.machine.layouts.usize; let place = this.allocate(layout, MiriMemoryKind::Machine.into()); this.machine.env_vars.environ = Some(place); } diff --git a/src/shims/panic.rs b/src/shims/panic.rs index 1aec236a533c7..450f735ad6868 100644 --- a/src/shims/panic.rs +++ b/src/shims/panic.rs @@ -14,7 +14,7 @@ use log::trace; use rustc_middle::{mir, ty}; -use rustc_target::{spec::PanicStrategy, abi::LayoutOf}; +use rustc_target::spec::PanicStrategy; use crate::*; @@ -93,7 +93,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Now we make a function call, and pass `data` as first and only argument. let f_instance = this.memory.get_fn(try_fn)?.as_instance()?; trace!("try_fn: {:?}", f_instance); - let ret_place = MPlaceTy::dangling(this.layout_of(this.tcx.mk_unit())?, this).into(); + let ret_place = MPlaceTy::dangling(this.machine.layouts.unit, this).into(); this.call_function( f_instance, &[data.into()], @@ -144,7 +144,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Push the `catch_fn` stackframe. let f_instance = this.memory.get_fn(catch_unwind.catch_fn)?.as_instance()?; trace!("catch_fn: {:?}", f_instance); - let ret_place = MPlaceTy::dangling(this.layout_of(this.tcx.mk_unit())?, this).into(); + let ret_place = MPlaceTy::dangling(this.machine.layouts.unit, this).into(); this.call_function( f_instance, &[catch_unwind.data.into(), payload.into()], diff --git a/src/shims/time.rs b/src/shims/time.rs index a87db98782024..de9a0313b1447 100644 --- a/src/shims/time.rs +++ b/src/shims/time.rs @@ -1,8 +1,6 @@ use std::time::{Duration, SystemTime, Instant}; use std::convert::TryFrom; -use rustc_target::abi::LayoutOf; - use crate::stacked_borrows::Tag; use crate::*; use helpers::{immty_from_int_checked, immty_from_uint_checked}; @@ -107,7 +105,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let dwLowDateTime = u32::try_from(duration_ticks & 0x00000000FFFFFFFF).unwrap(); let dwHighDateTime = u32::try_from((duration_ticks & 0xFFFFFFFF00000000) >> 32).unwrap(); - let DWORD_tylayout = this.layout_of(this.tcx.types.u32)?; + let DWORD_tylayout = this.machine.layouts.u32; let imms = [ immty_from_uint_checked(dwLowDateTime, DWORD_tylayout)?, immty_from_uint_checked(dwHighDateTime, DWORD_tylayout)?, diff --git a/src/shims/tls.rs b/src/shims/tls.rs index cba7dde53d81c..ba072e8ffd5d2 100644 --- a/src/shims/tls.rs +++ b/src/shims/tls.rs @@ -5,7 +5,7 @@ use std::collections::BTreeMap; use log::trace; use rustc_middle::ty; -use rustc_target::abi::{LayoutOf, Size, HasDataLayout}; +use rustc_target::abi::{Size, HasDataLayout}; use crate::{HelpersEvalContextExt, InterpResult, MPlaceTy, Scalar, StackPopCleanup, Tag}; @@ -172,7 +172,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // The signature of this function is `unsafe extern "system" fn(h: c::LPVOID, dwReason: c::DWORD, pv: c::LPVOID)`. let reason = this.eval_path_scalar(&["std", "sys", "windows", "c", "DLL_PROCESS_DETACH"])?; - let ret_place = MPlaceTy::dangling(this.layout_of(this.tcx.mk_unit())?, this).into(); + let ret_place = MPlaceTy::dangling(this.machine.layouts.unit, this).into(); this.call_function( thread_callback, &[Scalar::null_ptr(this).into(), reason.into(), Scalar::null_ptr(this).into()], @@ -191,7 +191,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if let Some((instance, data)) = this.machine.tls.global_dtor { trace!("Running global dtor {:?} on {:?}", instance, data); - let ret_place = MPlaceTy::dangling(this.layout_of(this.tcx.mk_unit())?, this).into(); + let ret_place = MPlaceTy::dangling(this.machine.layouts.unit, this).into(); this.call_function( instance, &[data.into()], @@ -209,7 +209,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx trace!("Running TLS dtor {:?} on {:?}", instance, ptr); assert!(!this.is_null(ptr).unwrap(), "data can't be NULL when dtor is called!"); - let ret_place = MPlaceTy::dangling(this.layout_of(this.tcx.mk_unit())?, this).into(); + let ret_place = MPlaceTy::dangling(this.machine.layouts.unit, this).into(); this.call_function( instance, &[ptr.into()], From 11cd87e4572fc3ce19a19bf0dd9a2bcfd3c8e89a Mon Sep 17 00:00:00 2001 From: David Cook Date: Sat, 18 Apr 2020 19:16:52 -0500 Subject: [PATCH 1889/3747] Flip matching --- src/shims/foreign_items.rs | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index e816a35253d95..c4acbd6a1b9a9 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -433,15 +433,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_f64(res), dest)?; } + "llvm.x86.sse2.pause" if this.tcx.sess.target.target.arch == "x86" || this.tcx.sess.target.target.arch == "x86_64" => {} + // Target-specific shims _ => { - match this.tcx.sess.target.target.arch.as_str() { - "x86" | "x86_64" => match link_name { - "llvm.x86.sse2.pause" => return Ok(true), - _ => {} - } - _ => {} - } match this.tcx.sess.target.target.target_os.as_str() { "linux" | "macos" => return posix::EvalContextExt::emulate_foreign_item_by_name(this, link_name, args, dest, ret), "windows" => return windows::EvalContextExt::emulate_foreign_item_by_name(this, link_name, args, dest, ret), From 7b69a6271e3e1469da26dce61284dbcb1face302 Mon Sep 17 00:00:00 2001 From: David Cook Date: Sat, 18 Apr 2020 19:31:02 -0500 Subject: [PATCH 1890/3747] Add support for std::thread::yield_now --- src/shims/foreign_items/posix.rs | 3 +++ src/shims/foreign_items/windows.rs | 5 +++++ tests/run-pass/sync.rs | 5 +++++ 3 files changed, 13 insertions(+) diff --git a/src/shims/foreign_items/posix.rs b/src/shims/foreign_items/posix.rs index 3ececb9c20bbd..35decd6ddbf2e 100644 --- a/src/shims/foreign_items/posix.rs +++ b/src/shims/foreign_items/posix.rs @@ -312,6 +312,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // We do not support forking, so there is nothing to do here. this.write_null(dest)?; } + "sched_yield" => { + this.write_null(dest)?; + } // Incomplete shims that we "stub out" just to get pre-main initialization code to work. // These shims are enabled only when the caller is in the standard library. diff --git a/src/shims/foreign_items/windows.rs b/src/shims/foreign_items/windows.rs index 1d17cbcefdeec..0125127a9f400 100644 --- a/src/shims/foreign_items/windows.rs +++ b/src/shims/foreign_items/windows.rs @@ -201,6 +201,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // FIXME: we should set last_error, but to what? this.write_null(dest)?; } + "SwitchToThread" => { + // Note that once Miri supports concurrency, this will need to return a nonzero + // value if this call does result in switching to another thread. + this.write_null(dest)?; + } // Better error for attempts to create a thread "CreateThread" => { diff --git a/tests/run-pass/sync.rs b/tests/run-pass/sync.rs index 90885880e681f..a4fd6f584c589 100644 --- a/tests/run-pass/sync.rs +++ b/tests/run-pass/sync.rs @@ -10,6 +10,7 @@ fn main() { test_rwlock_stdlib(); } test_spin_loop_hint(); + test_thread_yield_now(); } fn test_mutex_stdlib() { @@ -56,3 +57,7 @@ impl TryLockErrorExt for TryLockError { fn test_spin_loop_hint() { atomic::spin_loop_hint(); } + +fn test_thread_yield_now() { + std::thread::yield_now(); +} From fbf47d17845cc3df5b116e45ecfea71005b61735 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 19 Apr 2020 09:21:00 +0200 Subject: [PATCH 1891/3747] note source of test values --- tests/run-pass/float.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/run-pass/float.rs b/tests/run-pass/float.rs index c56d12a0c00e7..fc513ead8dd86 100644 --- a/tests/run-pass/float.rs +++ b/tests/run-pass/float.rs @@ -114,6 +114,8 @@ fn basic() { assert_eq(y, 42.0_f32); } +/// Many of these test values are taken from +/// https://github.com/WebAssembly/testsuite/blob/master/conversions.wast. fn casts() { // f32 -> i8 test_both_cast::(127.99, 127); From 70c828b76125bc5f469e5e776f2e984708876974 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 19 Apr 2020 09:34:54 +0200 Subject: [PATCH 1892/3747] test some more extreme cast cases --- .../intrinsics/float_to_int_64_too_big6.rs | 10 ++++++++++ .../intrinsics/float_to_int_64_too_big7.rs | 10 ++++++++++ 2 files changed, 20 insertions(+) create mode 100644 tests/compile-fail/intrinsics/float_to_int_64_too_big6.rs create mode 100644 tests/compile-fail/intrinsics/float_to_int_64_too_big7.rs diff --git a/tests/compile-fail/intrinsics/float_to_int_64_too_big6.rs b/tests/compile-fail/intrinsics/float_to_int_64_too_big6.rs new file mode 100644 index 0000000000000..f008131a6e529 --- /dev/null +++ b/tests/compile-fail/intrinsics/float_to_int_64_too_big6.rs @@ -0,0 +1,10 @@ +#![feature(intrinsics)] + +// Directly call intrinsic to avoid debug assertions in libstd +extern "rust-intrinsic" { + fn float_to_int_unchecked(value: Float) -> Int; +} + +fn main() { + unsafe { float_to_int_unchecked::(f64::MAX); } //~ ERROR: cannot be represented in target type `u128` +} diff --git a/tests/compile-fail/intrinsics/float_to_int_64_too_big7.rs b/tests/compile-fail/intrinsics/float_to_int_64_too_big7.rs new file mode 100644 index 0000000000000..69922e60a6bc2 --- /dev/null +++ b/tests/compile-fail/intrinsics/float_to_int_64_too_big7.rs @@ -0,0 +1,10 @@ +#![feature(intrinsics)] + +// Directly call intrinsic to avoid debug assertions in libstd +extern "rust-intrinsic" { + fn float_to_int_unchecked(value: Float) -> Int; +} + +fn main() { + unsafe { float_to_int_unchecked::(f64::MIN); } //~ ERROR: cannot be represented in target type `i128` +} From 547a4cc9209e04c2bbbe84edcd625272e51e45b2 Mon Sep 17 00:00:00 2001 From: David Cook Date: Sun, 19 Apr 2020 09:22:40 -0500 Subject: [PATCH 1893/3747] Review comments --- src/shims/foreign_items.rs | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index c4acbd6a1b9a9..75a2475d228a6 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -433,15 +433,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_f64(res), dest)?; } + // Architecture-specific shims "llvm.x86.sse2.pause" if this.tcx.sess.target.target.arch == "x86" || this.tcx.sess.target.target.arch == "x86_64" => {} - // Target-specific shims - _ => { - match this.tcx.sess.target.target.target_os.as_str() { - "linux" | "macos" => return posix::EvalContextExt::emulate_foreign_item_by_name(this, link_name, args, dest, ret), - "windows" => return windows::EvalContextExt::emulate_foreign_item_by_name(this, link_name, args, dest, ret), - target => throw_unsup_format!("the target `{}` is not supported", target), - } + // Platform-specific shims + _ => match this.tcx.sess.target.target.target_os.as_str() { + "linux" | "macos" => return posix::EvalContextExt::emulate_foreign_item_by_name(this, link_name, args, dest, ret), + "windows" => return windows::EvalContextExt::emulate_foreign_item_by_name(this, link_name, args, dest, ret), + target => throw_unsup_format!("the target `{}` is not supported", target), } }; From 5224c72403fd4f5cbbfd574c9a18fed5678c7488 Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Wed, 1 Apr 2020 16:55:52 -0700 Subject: [PATCH 1894/3747] Move the stack to the evaluator to make Miri compile with the newest Rustc. --- src/diagnostics.rs | 10 +++++----- src/eval.rs | 2 +- src/helpers.rs | 4 ++-- src/intptrcast.rs | 4 ++-- src/machine.rs | 26 ++++++++++++++++++++++---- src/shims/dlsym.rs | 2 +- src/shims/env.rs | 10 +++++----- src/shims/foreign_items.rs | 2 +- src/shims/foreign_items/posix.rs | 2 +- src/shims/foreign_items/posix/linux.rs | 2 +- src/shims/foreign_items/posix/macos.rs | 2 +- src/shims/foreign_items/windows.rs | 2 +- src/shims/fs.rs | 4 ++-- src/shims/intrinsics.rs | 2 +- src/shims/mod.rs | 2 +- src/shims/os_str.rs | 2 +- src/shims/panic.rs | 2 +- src/shims/time.rs | 3 +-- src/shims/tls.rs | 2 +- src/stacked_borrows.rs | 4 ++-- 20 files changed, 53 insertions(+), 36 deletions(-) diff --git a/src/diagnostics.rs b/src/diagnostics.rs index ff52e2385e476..5189982b1361a 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -47,7 +47,7 @@ pub enum NonHaltingDiagnostic { /// Emit a custom diagnostic without going through the miri-engine machinery pub fn report_error<'tcx, 'mir>( - ecx: &InterpCx<'mir, 'tcx, Evaluator<'tcx>>, + ecx: &InterpCx<'mir, 'tcx, Evaluator<'mir, 'tcx>>, mut e: InterpErrorInfo<'tcx>, ) -> Option { use InterpError::*; @@ -121,13 +121,13 @@ pub fn report_error<'tcx, 'mir>( /// Report an error or note (depending on the `error` argument) at the current frame's current statement. /// Also emits a full stacktrace of the interpreter stack. fn report_msg<'tcx, 'mir>( - ecx: &InterpCx<'mir, 'tcx, Evaluator<'tcx>>, + ecx: &InterpCx<'mir, 'tcx, Evaluator<'mir, 'tcx>>, title: &str, span_msg: String, mut helps: Vec, error: bool, ) -> Option { - let span = if let Some(frame) = ecx.stack().last() { + let span = if let Some(frame) = ecx.machine.stack.last() { frame.current_source_info().unwrap().span } else { DUMMY_SP @@ -159,7 +159,7 @@ fn report_msg<'tcx, 'mir>( err.emit(); - for (i, frame) in ecx.stack().iter().enumerate() { + for (i, frame) in ecx.machine.stack.iter().enumerate() { trace!("-------------------"); trace!("Frame {}", i); trace!(" return: {:?}", frame.return_place.map(|p| *p)); @@ -181,7 +181,7 @@ pub fn register_diagnostic(e: NonHaltingDiagnostic) { DIAGNOSTICS.with(|diagnostics| diagnostics.borrow_mut().push(e)); } -impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} +impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { /// Emit all diagnostics that were registed with `register_diagnostics` fn process_diagnostics(&self) { diff --git a/src/eval.rs b/src/eval.rs index 1caffe2647617..548ecee7bc426 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -62,7 +62,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig, -) -> InterpResult<'tcx, (InterpCx<'mir, 'tcx, Evaluator<'tcx>>, MPlaceTy<'tcx, Tag>)> { +) -> InterpResult<'tcx, (InterpCx<'mir, 'tcx, Evaluator<'mir, 'tcx>>, MPlaceTy<'tcx, Tag>)> { let tcx_at = tcx.at(rustc_span::source_map::DUMMY_SP); let param_env = ty::ParamEnv::reveal_all(); let layout_cx = LayoutCx { tcx, param_env }; diff --git a/src/helpers.rs b/src/helpers.rs index 40a33f09a83c4..644ea25fbc4bf 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -13,7 +13,7 @@ use rand::RngCore; use crate::*; -impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} +impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} /// Gets an instance for a path. fn try_resolve_did<'mir, 'tcx>(tcx: TyCtxt<'tcx>, path: &[&str]) -> Option { @@ -265,7 +265,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx unsafe_cell_action: F, } - impl<'ecx, 'mir, 'tcx, F> ValueVisitor<'mir, 'tcx, Evaluator<'tcx>> + impl<'ecx, 'mir, 'tcx: 'mir, F> ValueVisitor<'mir, 'tcx, Evaluator<'mir, 'tcx>> for UnsafeCellVisitor<'ecx, 'mir, 'tcx, F> where F: FnMut(MPlaceTy<'tcx, Tag>) -> InterpResult<'tcx>, diff --git a/src/intptrcast.rs b/src/intptrcast.rs index ac27138d7630e..5413e6b935b9b 100644 --- a/src/intptrcast.rs +++ b/src/intptrcast.rs @@ -41,7 +41,7 @@ impl Default for GlobalState { impl<'mir, 'tcx> GlobalState { pub fn int_to_ptr( int: u64, - memory: &Memory<'mir, 'tcx, Evaluator<'tcx>>, + memory: &Memory<'mir, 'tcx, Evaluator<'mir, 'tcx>>, ) -> InterpResult<'tcx, Pointer> { let global_state = memory.extra.intptrcast.borrow(); let pos = global_state.int_to_ptr_map.binary_search_by_key(&int, |(addr, _)| *addr); @@ -73,7 +73,7 @@ impl<'mir, 'tcx> GlobalState { pub fn ptr_to_int( ptr: Pointer, - memory: &Memory<'mir, 'tcx, Evaluator<'tcx>>, + memory: &Memory<'mir, 'tcx, Evaluator<'mir, 'tcx>>, ) -> InterpResult<'tcx, u64> { let mut global_state = memory.extra.intptrcast.borrow_mut(); let global_state = &mut *global_state; diff --git a/src/machine.rs b/src/machine.rs index 236b31ec4af54..90e6a0e513945 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -215,7 +215,7 @@ impl<'mir, 'tcx: 'mir> PrimitiveLayouts<'tcx> { } /// The machine itself. -pub struct Evaluator<'tcx> { +pub struct Evaluator<'mir, 'tcx> { /// Environment variables set by `setenv`. /// Miri does not expose env vars from the host to the emulated program. pub(crate) env_vars: EnvVars<'tcx>, @@ -251,11 +251,14 @@ pub struct Evaluator<'tcx> { /// The "time anchor" for this machine's monotone clock (for `Instant` simulation). pub(crate) time_anchor: Instant, + /// The call stack. + pub(crate) stack: Vec>>, + /// Precomputed `TyLayout`s for primitive data types that are commonly used inside Miri. pub(crate) layouts: PrimitiveLayouts<'tcx>, } -impl<'tcx> Evaluator<'tcx> { +impl<'mir, 'tcx> Evaluator<'mir, 'tcx> { pub(crate) fn new( communicate: bool, validate: bool, @@ -279,12 +282,13 @@ impl<'tcx> Evaluator<'tcx> { panic_payload: None, time_anchor: Instant::now(), layouts, + stack: Vec::default(), } } } /// A rustc InterpCx for Miri. -pub type MiriEvalContext<'mir, 'tcx> = InterpCx<'mir, 'tcx, Evaluator<'tcx>>; +pub type MiriEvalContext<'mir, 'tcx> = InterpCx<'mir, 'tcx, Evaluator<'mir, 'tcx>>; /// A little trait that's useful to be inherited by extension traits. pub trait MiriEvalContextExt<'mir, 'tcx> { @@ -303,7 +307,7 @@ impl<'mir, 'tcx> MiriEvalContextExt<'mir, 'tcx> for MiriEvalContext<'mir, 'tcx> } /// Machine hook implementations. -impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { +impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { type MemoryKind = MiriMemoryKind; type FrameExtra = FrameData<'tcx>; @@ -322,6 +326,20 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'tcx> { memory_extra.check_alignment } + #[inline(always)] + fn stack<'a>( + ecx: &'a InterpCx<'mir, 'tcx, Self>, + ) -> &'a [Frame<'mir, 'tcx, Self::PointerTag, Self::FrameExtra>] { + &ecx.machine.stack + } + + #[inline(always)] + fn stack_mut<'a>( + ecx: &'a mut InterpCx<'mir, 'tcx, Self>, + ) -> &'a mut Vec> { + &mut ecx.machine.stack + } + #[inline(always)] fn enforce_validity(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool { ecx.machine.validate diff --git a/src/shims/dlsym.rs b/src/shims/dlsym.rs index b5fe3cb7229c1..0f6ba63e984f3 100644 --- a/src/shims/dlsym.rs +++ b/src/shims/dlsym.rs @@ -20,7 +20,7 @@ impl Dlsym { } } -impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} +impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { fn call_dlsym( &mut self, diff --git a/src/shims/env.rs b/src/shims/env.rs index 8dd2a3ca302a0..8459aa3241c8e 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -35,7 +35,7 @@ pub struct EnvVars<'tcx> { impl<'tcx> EnvVars<'tcx> { pub(crate) fn init<'mir>( - ecx: &mut InterpCx<'mir, 'tcx, Evaluator<'tcx>>, + ecx: &mut InterpCx<'mir, 'tcx, Evaluator<'mir, 'tcx>>, mut excluded_env_vars: Vec, ) -> InterpResult<'tcx> { let target_os = ecx.tcx.sess.target.target.target_os.as_str(); @@ -61,7 +61,7 @@ impl<'tcx> EnvVars<'tcx> { } pub(crate) fn cleanup<'mir>( - ecx: &mut InterpCx<'mir, 'tcx, Evaluator<'tcx>>, + ecx: &mut InterpCx<'mir, 'tcx, Evaluator<'mir, 'tcx>>, ) -> InterpResult<'tcx> { // Deallocate individual env vars. for (_name, ptr) in ecx.machine.env_vars.map.drain() { @@ -78,7 +78,7 @@ impl<'tcx> EnvVars<'tcx> { fn alloc_env_var_as_c_str<'mir, 'tcx>( name: &OsStr, value: &OsStr, - ecx: &mut InterpCx<'mir, 'tcx, Evaluator<'tcx>>, + ecx: &mut InterpCx<'mir, 'tcx, Evaluator<'mir, 'tcx>>, ) -> InterpResult<'tcx, Pointer> { let mut name_osstring = name.to_os_string(); name_osstring.push("="); @@ -89,7 +89,7 @@ fn alloc_env_var_as_c_str<'mir, 'tcx>( fn alloc_env_var_as_wide_str<'mir, 'tcx>( name: &OsStr, value: &OsStr, - ecx: &mut InterpCx<'mir, 'tcx, Evaluator<'tcx>>, + ecx: &mut InterpCx<'mir, 'tcx, Evaluator<'mir, 'tcx>>, ) -> InterpResult<'tcx, Pointer> { let mut name_osstring = name.to_os_string(); name_osstring.push("="); @@ -97,7 +97,7 @@ fn alloc_env_var_as_wide_str<'mir, 'tcx>( Ok(ecx.alloc_os_str_as_wide_str(name_osstring.as_os_str(), MiriMemoryKind::Env.into())) } -impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} +impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { fn getenv(&mut self, name_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 7e7f17b0dbd4a..c7ab8dfd8738e 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -12,7 +12,7 @@ use rustc_ast::attr; use crate::*; -impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} +impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { /// Returns the minimum alignment for the target architecture for allocations of the given size. fn min_align(&self, size: u64, kind: MiriMemoryKind) -> Align { diff --git a/src/shims/foreign_items/posix.rs b/src/shims/foreign_items/posix.rs index 3ececb9c20bbd..9fda0ad4eeed0 100644 --- a/src/shims/foreign_items/posix.rs +++ b/src/shims/foreign_items/posix.rs @@ -9,7 +9,7 @@ use crate::*; use rustc_middle::mir; use rustc_target::abi::{Align, LayoutOf, Size}; -impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} +impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { fn emulate_foreign_item_by_name( &mut self, diff --git a/src/shims/foreign_items/posix/linux.rs b/src/shims/foreign_items/posix/linux.rs index 16c6c002b69c5..b00704e47a025 100644 --- a/src/shims/foreign_items/posix/linux.rs +++ b/src/shims/foreign_items/posix/linux.rs @@ -1,7 +1,7 @@ use crate::*; use rustc_middle::mir; -impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} +impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { fn emulate_foreign_item_by_name( &mut self, diff --git a/src/shims/foreign_items/posix/macos.rs b/src/shims/foreign_items/posix/macos.rs index e7baacf7274d2..125b6b7685301 100644 --- a/src/shims/foreign_items/posix/macos.rs +++ b/src/shims/foreign_items/posix/macos.rs @@ -1,7 +1,7 @@ use crate::*; use rustc_middle::mir; -impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} +impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { fn emulate_foreign_item_by_name( &mut self, diff --git a/src/shims/foreign_items/windows.rs b/src/shims/foreign_items/windows.rs index 1d17cbcefdeec..8d564d4676bab 100644 --- a/src/shims/foreign_items/windows.rs +++ b/src/shims/foreign_items/windows.rs @@ -5,7 +5,7 @@ use rustc_target::abi::Size; use crate::*; -impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} +impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { fn emulate_foreign_item_by_name( &mut self, diff --git a/src/shims/fs.rs b/src/shims/fs.rs index c70cc874164f1..3e20f5f972889 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -64,7 +64,7 @@ impl FileHandler { } } -impl<'mir, 'tcx> EvalContextExtPrivate<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} +impl<'mir, 'tcx: 'mir> EvalContextExtPrivate<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} trait EvalContextExtPrivate<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { /// Emulate `stat` or `lstat` on `macos`. This function is not intended to be /// called directly from `emulate_foreign_item_by_name`, so it does not check if isolation is @@ -232,7 +232,7 @@ impl Default for DirHandler { } } -impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} +impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { fn open( &mut self, diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 1f9004221920f..b64aeef485ea4 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -8,7 +8,7 @@ use rustc_target::abi::{Align, LayoutOf, Size}; use crate::*; -impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} +impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { fn call_intrinsic( &mut self, diff --git a/src/shims/mod.rs b/src/shims/mod.rs index 764e404141e4d..71ff6024ec6fe 100644 --- a/src/shims/mod.rs +++ b/src/shims/mod.rs @@ -17,7 +17,7 @@ use rustc_middle::{mir, ty}; use crate::*; -impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} +impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { fn find_mir_or_eval_fn( &mut self, diff --git a/src/shims/os_str.rs b/src/shims/os_str.rs index c24d6df41e392..73dc9119a820f 100644 --- a/src/shims/os_str.rs +++ b/src/shims/os_str.rs @@ -60,7 +60,7 @@ fn convert_path_separator<'a>( }; } -impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} +impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { /// Helper function to read an OsString from a null-terminated sequence of bytes, which is what /// the Unix APIs usually handle. diff --git a/src/shims/panic.rs b/src/shims/panic.rs index 450f735ad6868..c926046a04423 100644 --- a/src/shims/panic.rs +++ b/src/shims/panic.rs @@ -31,7 +31,7 @@ pub struct CatchUnwindData<'tcx> { ret: mir::BasicBlock, } -impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} +impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { /// Check if panicking is supported on this target, and give a good error otherwise. fn check_panic_supported(&self) -> InterpResult<'tcx> { diff --git a/src/shims/time.rs b/src/shims/time.rs index de9a0313b1447..e26d2ce2e39d2 100644 --- a/src/shims/time.rs +++ b/src/shims/time.rs @@ -11,8 +11,7 @@ pub fn system_time_to_duration<'tcx>(time: &SystemTime) -> InterpResult<'tcx, Du .map_err(|_| err_unsup_format!("times before the Unix epoch are not supported").into()) } - -impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} +impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { fn clock_gettime( &mut self, diff --git a/src/shims/tls.rs b/src/shims/tls.rs index ba072e8ffd5d2..7b84468402953 100644 --- a/src/shims/tls.rs +++ b/src/shims/tls.rs @@ -154,7 +154,7 @@ impl<'tcx> TlsData<'tcx> { } } -impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} +impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { fn run_tls_dtors(&mut self) -> InterpResult<'tcx> { let this = self.eval_context_mut(); diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index a69948002c126..3412f00964b4a 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -506,7 +506,7 @@ impl Stacks { /// Retagging/reborrowing. There is some policy in here, such as which permissions /// to grant for which references, and when to add protectors. -impl<'mir, 'tcx> EvalContextPrivExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} +impl<'mir, 'tcx: 'mir> EvalContextPrivExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { fn reborrow( &mut self, @@ -607,7 +607,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } -impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} +impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { fn retag(&mut self, kind: RetagKind, place: PlaceTy<'tcx, Tag>) -> InterpResult<'tcx> { let this = self.eval_context_mut(); From 192fd3d97e9371345d82c79351da80984cd65e9a Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Thu, 16 Apr 2020 10:14:46 -0700 Subject: [PATCH 1895/3747] Move stack and stack_mut implementation in Machine to match their position in the trait. --- src/machine.rs | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/machine.rs b/src/machine.rs index 90e6a0e513945..2ab5f10af66d8 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -326,20 +326,6 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { memory_extra.check_alignment } - #[inline(always)] - fn stack<'a>( - ecx: &'a InterpCx<'mir, 'tcx, Self>, - ) -> &'a [Frame<'mir, 'tcx, Self::PointerTag, Self::FrameExtra>] { - &ecx.machine.stack - } - - #[inline(always)] - fn stack_mut<'a>( - ecx: &'a mut InterpCx<'mir, 'tcx, Self>, - ) -> &'a mut Vec> { - &mut ecx.machine.stack - } - #[inline(always)] fn enforce_validity(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool { ecx.machine.validate @@ -539,6 +525,20 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { Ok(frame.with_extra(extra)) } + #[inline(always)] + fn stack<'a>( + ecx: &'a InterpCx<'mir, 'tcx, Self>, + ) -> &'a [Frame<'mir, 'tcx, Self::PointerTag, Self::FrameExtra>] { + &ecx.machine.stack + } + + #[inline(always)] + fn stack_mut<'a>( + ecx: &'a mut InterpCx<'mir, 'tcx, Self>, + ) -> &'a mut Vec> { + &mut ecx.machine.stack + } + #[inline(always)] fn after_stack_push(ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx> { if ecx.memory.extra.stacked_borrows.is_some() { From 5d2c8358f844a943ac5318cfdbe166a6688397cb Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 20 Apr 2020 09:33:34 +0200 Subject: [PATCH 1896/3747] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index e9b00f6497768..b48a98d229f25 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -b2c1a606feb1fbdb0ac0acba76f881ef172ed474 +9b2f8dbba39dd4167f22a7026674a585c3d907d8 From 73772fede6de215faf7bf4846895cde959f82759 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 20 Apr 2020 10:04:17 +0200 Subject: [PATCH 1897/3747] adjust for Weak::as_raw -> as_ptr rename --- tests/compile-fail/{rc_as_raw.rs => rc_as_ptr.rs} | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) rename tests/compile-fail/{rc_as_raw.rs => rc_as_ptr.rs} (71%) diff --git a/tests/compile-fail/rc_as_raw.rs b/tests/compile-fail/rc_as_ptr.rs similarity index 71% rename from tests/compile-fail/rc_as_raw.rs rename to tests/compile-fail/rc_as_ptr.rs index cb50ca5fcece0..0b98c7d2bba3d 100644 --- a/tests/compile-fail/rc_as_raw.rs +++ b/tests/compile-fail/rc_as_ptr.rs @@ -5,17 +5,17 @@ use std::rc::{Rc, Weak}; use std::ptr; -/// Taken from the `Weak::as_raw` doctest. +/// Taken from the `Weak::as_ptr` doctest. fn main() { let strong = Rc::new(Box::new(42)); let weak = Rc::downgrade(&strong); // Both point to the same object - assert!(ptr::eq(&*strong, Weak::as_raw(&weak))); + assert!(ptr::eq(&*strong, Weak::as_ptr(&weak))); // The strong here keeps it alive, so we can still access the object. - assert_eq!(42, **unsafe { &*Weak::as_raw(&weak) }); + assert_eq!(42, **unsafe { &*Weak::as_ptr(&weak) }); drop(strong); // But not any more. We can do Weak::as_raw(&weak), but accessing the pointer would lead to // undefined behaviour. - assert_eq!(42, **unsafe { &*Weak::as_raw(&weak) }); //~ ERROR dereferenced after this allocation got freed + assert_eq!(42, **unsafe { &*Weak::as_ptr(&weak) }); //~ ERROR dereferenced after this allocation got freed } From 7406c1224b2dd7123ddcd6d06b809dd571fba2dd Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 20 Apr 2020 10:38:38 +0200 Subject: [PATCH 1898/3747] adjust for asm -> llvm_asm rename --- test-cargo-miri/build.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test-cargo-miri/build.rs b/test-cargo-miri/build.rs index 950fc3c82bb15..b1f5fc1726200 100644 --- a/test-cargo-miri/build.rs +++ b/test-cargo-miri/build.rs @@ -1,10 +1,10 @@ -#![feature(asm)] +#![feature(llvm_asm)] fn not_in_miri() -> i32 { // Inline assembly definitely does not work in Miri. let dummy = 42; unsafe { - asm!("" : : "r"(&dummy)); + llvm_asm!("" : : "r"(&dummy)); } return dummy; } From 54897f66f8daeec04042ab416718407b13641b86 Mon Sep 17 00:00:00 2001 From: David Cook Date: Tue, 21 Apr 2020 21:17:54 -0500 Subject: [PATCH 1899/3747] Implement ftruncate64/ftruncate for File::set_len --- src/shims/foreign_items/posix/linux.rs | 4 ++++ src/shims/foreign_items/posix/macos.rs | 4 ++++ src/shims/fs.rs | 30 ++++++++++++++++++++++++++ tests/run-pass/fs.rs | 27 +++++++++++++++++++++++ 4 files changed, 65 insertions(+) diff --git a/src/shims/foreign_items/posix/linux.rs b/src/shims/foreign_items/posix/linux.rs index b00704e47a025..a32f0fa606784 100644 --- a/src/shims/foreign_items/posix/linux.rs +++ b/src/shims/foreign_items/posix/linux.rs @@ -34,6 +34,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let result = this.linux_readdir64_r(args[0], args[1], args[2])?; this.write_scalar(Scalar::from_i32(result), dest)?; } + "ftruncate64" => { + let result = this.ftruncate64(args[0], args[1])?; + this.write_scalar(Scalar::from_i32(result), dest)?; + } // Linux-only "posix_fadvise" => { let _fd = this.read_scalar(args[0])?.to_i32()?; diff --git a/src/shims/foreign_items/posix/macos.rs b/src/shims/foreign_items/posix/macos.rs index 125b6b7685301..dd3dba6ec07cc 100644 --- a/src/shims/foreign_items/posix/macos.rs +++ b/src/shims/foreign_items/posix/macos.rs @@ -44,6 +44,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let result = this.macos_readdir_r(args[0], args[1], args[2])?; this.write_scalar(Scalar::from_i32(result), dest)?; } + "ftruncate" => { + let result = this.ftruncate64(args[0], args[1])?; + this.write_scalar(Scalar::from_i32(result), dest)?; + } // Environment related shims "_NSGetEnviron" => { diff --git a/src/shims/fs.rs b/src/shims/fs.rs index 3e20f5f972889..e7d41b36f5a6a 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -1062,6 +1062,36 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.handle_not_found() } } + + fn ftruncate64( + &mut self, fd_op: OpTy<'tcx, Tag>, + length_op: OpTy<'tcx, Tag>, + ) -> InterpResult<'tcx, i32> { + let this = self.eval_context_mut(); + + this.check_no_isolation("ftruncate64")?; + + let fd = this.read_scalar(fd_op)?.to_i32()?; + let length = this.read_scalar(length_op)?.to_i64()?; + if let Some(FileHandle { file, writable }) = this.machine.file_handler.handles.get_mut(&fd) { + if *writable { + if let Ok(length) = length.try_into() { + let result = file.set_len(length); + this.try_unwrap_io_result(result.map(|_| 0i32)) + } else { + let einval = this.eval_libc("EINVAL")?; + this.set_last_error(einval)?; + Ok(-1) + } + } else { + let einval = this.eval_libc("EINVAL")?; + this.set_last_error(einval)?; + Ok(-1) + } + } else { + this.handle_not_found() + } + } } /// Extracts the number of seconds and nanoseconds elapsed between `time` and the unix epoch when diff --git a/tests/run-pass/fs.rs b/tests/run-pass/fs.rs index d8b6e5b445755..1a139de8148ae 100644 --- a/tests/run-pass/fs.rs +++ b/tests/run-pass/fs.rs @@ -13,6 +13,7 @@ fn main() { test_file_create_new(); test_seek(); test_metadata(); + test_file_set_len(); test_symlink(); test_errors(); test_rename(); @@ -155,6 +156,32 @@ fn test_metadata() { remove_file(&path).unwrap(); } +fn test_file_set_len() { + let bytes = b"Hello, World!\n"; + let path = prepare_with_content("miri_test_fs_set_len.txt", bytes); + + // Test extending the file + let mut file = OpenOptions::new().read(true).write(true).open(&path).unwrap(); + let bytes_extended = b"Hello, World!\n\x00\x00\x00\x00\x00\x00"; + file.set_len(20).unwrap(); + let mut contents = Vec::new(); + file.read_to_end(&mut contents).unwrap(); + assert_eq!(bytes_extended, contents.as_slice()); + + // Test truncating the file + file.seek(SeekFrom::Start(0)).unwrap(); + file.set_len(10).unwrap(); + let mut contents = Vec::new(); + file.read_to_end(&mut contents).unwrap(); + assert_eq!(&bytes[..10], contents.as_slice()); + + // Can't use set_len on a file not opened for writing + let file = OpenOptions::new().read(true).open(&path).unwrap(); + assert_eq!(ErrorKind::InvalidInput, file.set_len(14).unwrap_err().kind()); + + remove_file(&path).unwrap(); +} + fn test_symlink() { let bytes = b"Hello, World!\n"; let path = prepare_with_content("miri_test_fs_link_target.txt", bytes); From e37d0e312596c06659b881c240a5afdd58395665 Mon Sep 17 00:00:00 2001 From: David Cook Date: Tue, 21 Apr 2020 21:28:22 -0500 Subject: [PATCH 1900/3747] Print hex dump of alloc on reading undef bytes --- src/diagnostics.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/diagnostics.rs b/src/diagnostics.rs index 5189982b1361a..77aaacea02400 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -114,6 +114,9 @@ pub fn report_error<'tcx, 'mir>( }; e.print_backtrace(); + if let UndefinedBehavior(UndefinedBehaviorInfo::InvalidUndefBytes(Some(ptr))) = e.kind { + ecx.memory.dump_alloc(ptr.alloc_id); + } let msg = e.to_string(); report_msg(ecx, &format!("{}: {}", title, msg), msg, helps, true) } From f49839ac30d616ceba6d46af4ecc94e80db21512 Mon Sep 17 00:00:00 2001 From: David Cook Date: Wed, 22 Apr 2020 07:09:20 -0500 Subject: [PATCH 1901/3747] Add comment --- src/shims/fs.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/shims/fs.rs b/src/shims/fs.rs index e7d41b36f5a6a..ea0b998c2e3dc 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -1084,6 +1084,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(-1) } } else { + // The file is not writable let einval = this.eval_libc("EINVAL")?; this.set_last_error(einval)?; Ok(-1) From 270adbc7c61a85ce8f4a3b636396b142e83b2f11 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 18 Apr 2020 13:56:09 +0200 Subject: [PATCH 1902/3747] Stacked Borrows: alignment does not matter --- src/stacked_borrows.rs | 10 ++++++---- tests/run-pass/packed_struct.rs | 8 +++++++- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 3412f00964b4a..03140c867b2d0 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -11,7 +11,7 @@ use log::trace; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_middle::mir::RetagKind; use rustc_middle::ty; -use rustc_target::abi::{LayoutOf, Size}; +use rustc_target::abi::{Align, LayoutOf, Size}; use rustc_hir::Mutability; use crate::*; @@ -577,11 +577,13 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx .size_and_align_of_mplace(place)? .map(|(size, _)| size) .unwrap_or_else(|| place.layout.size); + // `reborrow` relies on getting a `Pointer` and everything being in-bounds, + // so let's ensure that. However, we do not care about alignment. // We can see dangling ptrs in here e.g. after a Box's `Unique` was - // updated using "self.0 = ..." (can happen in Box::from_raw); see miri#1050. - let place = this.mplace_access_checked(place)?; + // updated using "self.0 = ..." (can happen in Box::from_raw) so we cannot ICE; see miri#1050. + let place = this.mplace_access_checked(place, Some(Align::from_bytes(1).unwrap()))?; + // Nothing to do for ZSTs. if size == Size::ZERO { - // Nothing to do for ZSTs. return Ok(val); } diff --git a/tests/run-pass/packed_struct.rs b/tests/run-pass/packed_struct.rs index 7aa53ef568f56..5582caaf37ea5 100644 --- a/tests/run-pass/packed_struct.rs +++ b/tests/run-pass/packed_struct.rs @@ -1,4 +1,4 @@ -#![feature(unsize, coerce_unsized)] +#![feature(unsize, coerce_unsized, raw_ref_op)] use std::collections::hash_map::DefaultHasher; use std::hash::Hash; @@ -6,6 +6,7 @@ use std::hash::Hash; fn test_basic() { #[repr(packed)] struct S { + fill: u8, a: i32, b: i64, } @@ -30,6 +31,7 @@ fn test_basic() { } let mut x = S { + fill: 0, a: 42, b: 99, }; @@ -37,9 +39,13 @@ fn test_basic() { let b = x.b; assert_eq!(a, 42); assert_eq!(b, 99); + assert_eq!(&x.fill, &0); // `fill` just requirs 1-byte-align, so this is fine // can't do `assert_eq!(x.a, 42)`, because `assert_eq!` takes a reference assert_eq!({x.a}, 42); assert_eq!({x.b}, 99); + // but we *can* take a raw pointer! + assert_eq!(unsafe { (&raw const x.a).read_unaligned() }, 42); + assert_eq!(unsafe { (&raw const x.b).read_unaligned() }, 99); x.b = 77; assert_eq!({x.b}, 77); From 4b9abdaa504bdf375c09afd9e994f3d066466d3c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 22 Apr 2020 23:32:28 +0200 Subject: [PATCH 1903/3747] rustup --- rust-version | 2 +- src/eval.rs | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/rust-version b/rust-version index b48a98d229f25..871e50b995be2 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -9b2f8dbba39dd4167f22a7026674a585c3d907d8 +b2e36e6c2d229126b59e892c9147fbb68115d292 diff --git a/src/eval.rs b/src/eval.rs index 548ecee7bc426..61a5b71f0bdbf 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -98,6 +98,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( start_id, tcx.mk_substs(::std::iter::once(ty::subst::GenericArg::from(main_ret_ty))), ) + .unwrap() .unwrap(); // First argument: pointer to `main()`. From 9057dae235df4d893b3051991e9794af15b32902 Mon Sep 17 00:00:00 2001 From: David Cook Date: Wed, 22 Apr 2020 17:41:06 -0500 Subject: [PATCH 1904/3747] Reorder output --- src/diagnostics.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/diagnostics.rs b/src/diagnostics.rs index 77aaacea02400..565db7b178a1d 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -114,11 +114,14 @@ pub fn report_error<'tcx, 'mir>( }; e.print_backtrace(); + let msg = e.to_string(); + let result = report_msg(ecx, &format!("{}: {}", title, msg), msg, helps, true); + if let UndefinedBehavior(UndefinedBehaviorInfo::InvalidUndefBytes(Some(ptr))) = e.kind { ecx.memory.dump_alloc(ptr.alloc_id); } - let msg = e.to_string(); - report_msg(ecx, &format!("{}: {}", title, msg), msg, helps, true) + + result } /// Report an error or note (depending on the `error` argument) at the current frame's current statement. From 5b60f0df2afba76fb6bd4cc3ae0c85ea2cfd484c Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Thu, 23 Apr 2020 02:37:58 +0000 Subject: [PATCH 1905/3747] Add ryu and tikv to trophy case --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index a86de4a555190..4d37f2c353c59 100644 --- a/README.md +++ b/README.md @@ -274,6 +274,7 @@ Definite bugs found: * [`Vec`](https://github.com/rust-lang/rust/issues/69770) and [`BTreeMap`](https://github.com/rust-lang/rust/issues/69769) leaking memory under some (panicky) conditions * [Memory leak in `beef`](https://github.com/maciejhirsz/beef/issues/12) * [Invalid use of undefined memory in `EbrCell`](https://github.com/Firstyear/concread/commit/b15be53b6ec076acb295a5c0483cdb4bf9be838f#diff-6282b2fc8e98bd089a1f0c86f648157cR229) +* [Unaligned pointer access in TiKV](https://github.com/tikv/tikv/issues/7613) Violations of [Stacked Borrows] found that are likely bugs (but Stacked Borrows is currently just an experiment): @@ -284,6 +285,7 @@ Violations of [Stacked Borrows] found that are likely bugs (but Stacked Borrows * [`align_to_mut` violating uniqueness of mutable references](https://github.com/rust-lang/rust/issues/68549) * [Aliasing mutable references in `sized-chunks`](https://github.com/bodil/sized-chunks/issues/8) * [`String::push_str` invalidating existing references into the string](https://github.com/rust-lang/rust/issues/70301) +- [`ryu` creating incorrect mutable references](https://github.com/dtolnay/ryu/issues/24) ## License From f84aa4a424221a8b3739f6232fec8f419d176fba Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Thu, 23 Apr 2020 02:46:36 -0600 Subject: [PATCH 1906/3747] Update README.md Co-Authored-By: Ralf Jung --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 4d37f2c353c59..3d88b24da6827 100644 --- a/README.md +++ b/README.md @@ -285,7 +285,7 @@ Violations of [Stacked Borrows] found that are likely bugs (but Stacked Borrows * [`align_to_mut` violating uniqueness of mutable references](https://github.com/rust-lang/rust/issues/68549) * [Aliasing mutable references in `sized-chunks`](https://github.com/bodil/sized-chunks/issues/8) * [`String::push_str` invalidating existing references into the string](https://github.com/rust-lang/rust/issues/70301) -- [`ryu` creating incorrect mutable references](https://github.com/dtolnay/ryu/issues/24) +* [`ryu` using raw pointers outside their valid memory area](https://github.com/dtolnay/ryu/issues/24) ## License From 60fa9acdf727fa98c42ed0f95b7a4cb6b4550829 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Thu, 23 Apr 2020 08:46:49 -0700 Subject: [PATCH 1907/3747] Disable interactive prompts in CI --- src/bin/cargo-miri.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 04020009c6943..ea99ee11495f0 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -1,5 +1,6 @@ #![feature(inner_deref)] +use std::env; use std::fs::{self, File}; use std::io::{self, BufRead, Write}; use std::ops::Not; @@ -435,7 +436,8 @@ fn in_cargo_miri() { test_sysroot_consistency(); // We always setup. - let ask = subcommand != MiriCommand::Setup; + // Disable interactive prompts in CI (GitHub Actions, Travis, AppVeyor, etc). + let ask = subcommand != MiriCommand::Setup && env::var_os("CI").is_none(); setup(ask); if subcommand == MiriCommand::Setup { // Stop here. From 28f4f84303076e7f537ad847e61ec1166ea62fac Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Thu, 23 Apr 2020 09:12:05 -0700 Subject: [PATCH 1908/3747] Remove unneeded setup step from CI instructions in readme --- README.md | 5 ----- 1 file changed, 5 deletions(-) diff --git a/README.md b/README.md index 3d88b24da6827..ea2aa955ba4da 100644 --- a/README.md +++ b/README.md @@ -127,16 +127,11 @@ MIRI_NIGHTLY=nightly-$(curl -s https://rust-lang.github.io/rustup-components-his echo "Installing latest nightly with Miri: $MIRI_NIGHTLY" rustup set profile minimal rustup default "$MIRI_NIGHTLY" - rustup component add miri -cargo miri setup cargo miri test ``` -We use `cargo miri setup` to avoid getting interactive questions about the extra -setup needed for Miri. - ### Common Problems When using the above instructions, you may encounter a number of confusing compiler From 2584507ce2eb9a7fc4c00213d216fc57c794e141 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Thu, 23 Apr 2020 10:12:48 -0700 Subject: [PATCH 1909/3747] Preserve consistent output whether or not CI is set --- src/bin/cargo-miri.rs | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index ea99ee11495f0..0252f22e76683 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -247,7 +247,9 @@ fn xargo_version() -> Option<(u32, u32, u32)> { Some((major, minor, patch)) } -fn ask_to_run(mut cmd: Command, ask: bool, text: &str) { +fn ask_to_run(mut cmd: Command, subcommand: MiriCommand, text: &str) { + // Disable interactive prompts in CI (GitHub Actions, Travis, AppVeyor, etc). + let ask = subcommand != MiriCommand::Setup && env::var_os("CI").is_none(); if ask { let mut buf = String::new(); print!("I will run `{:?}` to {}. Proceed? [Y/n] ", cmd, text); @@ -271,9 +273,9 @@ fn ask_to_run(mut cmd: Command, ask: bool, text: &str) { /// Performs the setup required to make `cargo miri` work: Getting a custom-built libstd. Then sets /// `MIRI_SYSROOT`. Skipped if `MIRI_SYSROOT` is already set, in which case we expect the user has /// done all this already. -fn setup(ask_user: bool) { +fn setup(subcommand: MiriCommand) { if std::env::var("MIRI_SYSROOT").is_ok() { - if !ask_user { + if subcommand == MiriCommand::Setup { println!("WARNING: MIRI_SYSROOT already set, not doing anything.") } return; @@ -287,7 +289,7 @@ fn setup(ask_user: bool) { } let mut cmd = cargo(); cmd.args(&["install", "xargo", "-f"]); - ask_to_run(cmd, ask_user, "install a recent enough xargo"); + ask_to_run(cmd, subcommand, "install a recent enough xargo"); } // Determine where the rust sources are located. `XARGO_RUST_SRC` env var trumps everything. @@ -310,7 +312,7 @@ fn setup(ask_user: bool) { cmd.args(&["component", "add", "rust-src"]); ask_to_run( cmd, - ask_user, + subcommand, "install the rustc-src component for the selected toolchain", ); } @@ -361,7 +363,8 @@ path = "lib.rs" File::create(dir.join("lib.rs")).unwrap(); // Prepare xargo invocation. let target = get_arg_flag_value("--target"); - let print_sysroot = !ask_user && has_arg_flag("--print-sysroot"); // whether we just print the sysroot path + let print_sysroot = subcommand == MiriCommand::Setup + && has_arg_flag("--print-sysroot"); // whether we just print the sysroot path let mut command = xargo_check(); command.arg("build").arg("-q"); command.current_dir(&dir); @@ -389,7 +392,7 @@ path = "lib.rs" if print_sysroot { // Print just the sysroot and nothing else; this way we do not need any escaping. println!("{}", sysroot.display()); - } else if !ask_user { + } else if subcommand == MiriCommand::Setup { println!("A libstd for Miri is now available in `{}`.", sysroot.display()); } } @@ -436,9 +439,7 @@ fn in_cargo_miri() { test_sysroot_consistency(); // We always setup. - // Disable interactive prompts in CI (GitHub Actions, Travis, AppVeyor, etc). - let ask = subcommand != MiriCommand::Setup && env::var_os("CI").is_none(); - setup(ask); + setup(subcommand); if subcommand == MiriCommand::Setup { // Stop here. return; From a5eaa5703c65c1708cdace6dfe11ebc84a9b4316 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 23 Apr 2020 19:20:09 +0200 Subject: [PATCH 1910/3747] test suite: rely on CARGO_BIN_EXE_ env vars to find Miri binary --- build.rs | 8 +------- tests/compiletest.rs | 2 +- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/build.rs b/build.rs index 97bb9358832c4..56956920e2e26 100644 --- a/build.rs +++ b/build.rs @@ -1,11 +1,5 @@ -extern crate vergen; - -use std::env; - fn main() { - // Forward the profile to the main compilation - println!("cargo:rustc-env=PROFILE={}", env::var("PROFILE").unwrap()); - // Don't rebuild miri even if nothing changed + // Don't rebuild miri when nothing changed. println!("cargo:rerun-if-changed=build.rs"); // vergen vergen::generate_cargo_keys(vergen::ConstantsFlags::all()) diff --git a/tests/compiletest.rs b/tests/compiletest.rs index d082a2cc484bd..ca18799620895 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -12,7 +12,7 @@ fn miri_path() -> PathBuf { if rustc_test_suite().is_some() { PathBuf::from(option_env!("MIRI_PATH").unwrap()) } else { - PathBuf::from(concat!("target/", env!("PROFILE"), "/miri")) + PathBuf::from(env!("CARGO_BIN_EXE_miri")) } } From a4dd463eaf548de04c55296c8ed31516fe5c5983 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Thu, 23 Apr 2020 10:27:38 -0700 Subject: [PATCH 1911/3747] Keep MiriCommand out of ask_to_run function --- src/bin/cargo-miri.rs | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 0252f22e76683..17d7ecf8c8708 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -247,10 +247,9 @@ fn xargo_version() -> Option<(u32, u32, u32)> { Some((major, minor, patch)) } -fn ask_to_run(mut cmd: Command, subcommand: MiriCommand, text: &str) { +fn ask_to_run(mut cmd: Command, ask: bool, text: &str) { // Disable interactive prompts in CI (GitHub Actions, Travis, AppVeyor, etc). - let ask = subcommand != MiriCommand::Setup && env::var_os("CI").is_none(); - if ask { + if ask && env::var_os("CI").is_none() { let mut buf = String::new(); print!("I will run `{:?}` to {}. Proceed? [Y/n] ", cmd, text); io::stdout().flush().unwrap(); @@ -281,6 +280,10 @@ fn setup(subcommand: MiriCommand) { return; } + // Subcommands other than `setup` will do a setup if necessary, but + // interactively confirm first. + let ask_user = subcommand != MiriCommand::Setup; + // First, we need xargo. if xargo_version().map_or(true, |v| v < XARGO_MIN_VERSION) { if std::env::var("XARGO_CHECK").is_ok() { @@ -289,7 +292,7 @@ fn setup(subcommand: MiriCommand) { } let mut cmd = cargo(); cmd.args(&["install", "xargo", "-f"]); - ask_to_run(cmd, subcommand, "install a recent enough xargo"); + ask_to_run(cmd, ask_user, "install a recent enough xargo"); } // Determine where the rust sources are located. `XARGO_RUST_SRC` env var trumps everything. @@ -312,7 +315,7 @@ fn setup(subcommand: MiriCommand) { cmd.args(&["component", "add", "rust-src"]); ask_to_run( cmd, - subcommand, + ask_user, "install the rustc-src component for the selected toolchain", ); } From 4dec02dd921e26524394c720895f5e18689c7e74 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 24 Apr 2020 00:52:43 +0200 Subject: [PATCH 1912/3747] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 871e50b995be2..8ed0e6ba3531a 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -b2e36e6c2d229126b59e892c9147fbb68115d292 +14b15521c52549ebbb113173b4abecd124b5a823 From d9ac84d05fc58aa82b4c4306f42231bb6aeb9226 Mon Sep 17 00:00:00 2001 From: David Cook Date: Thu, 23 Apr 2020 20:00:09 -0500 Subject: [PATCH 1913/3747] Add message before dumping alloc --- src/diagnostics.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/diagnostics.rs b/src/diagnostics.rs index 565db7b178a1d..e72232323ba28 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -118,7 +118,12 @@ pub fn report_error<'tcx, 'mir>( let result = report_msg(ecx, &format!("{}: {}", title, msg), msg, helps, true); if let UndefinedBehavior(UndefinedBehaviorInfo::InvalidUndefBytes(Some(ptr))) = e.kind { + eprintln!( + "Uninitialized read occurred at offset 0x{:x} into this allocation:", + ptr.offset.bytes(), + ); ecx.memory.dump_alloc(ptr.alloc_id); + eprintln!(); } result From 7f92eab3c477f321a55f53b6e04ac8ca2cd04ebf Mon Sep 17 00:00:00 2001 From: David Cook Date: Thu, 23 Apr 2020 20:00:25 -0500 Subject: [PATCH 1914/3747] Add test to exercise InvalidUndefBytes --- tests/compile-fail/undefined_buffer.rs | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 tests/compile-fail/undefined_buffer.rs diff --git a/tests/compile-fail/undefined_buffer.rs b/tests/compile-fail/undefined_buffer.rs new file mode 100644 index 0000000000000..dac02a8690e9e --- /dev/null +++ b/tests/compile-fail/undefined_buffer.rs @@ -0,0 +1,20 @@ +// error-pattern: reading uninitialized memory + +use std::alloc::{alloc, dealloc, Layout}; +use std::slice::from_raw_parts; + +fn main() { + let layout = Layout::from_size_align(32, 8).unwrap(); + unsafe { + let ptr = alloc(layout); + *ptr = 0x41; + *ptr.add(1) = 0x42; + *ptr.add(2) = 0x43; + *ptr.add(3) = 0x44; + *ptr.add(16) = 0x00; + let slice1 = from_raw_parts(ptr, 16); + let slice2 = from_raw_parts(ptr.add(16), 16); + drop(slice1.cmp(slice2)); + dealloc(ptr, layout); + } +} From c46668c556be7fbb5ad71b946ce0cec66372356e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 25 Apr 2020 11:12:50 +0200 Subject: [PATCH 1915/3747] fix exit code on rustc errors --- src/bin/miri.rs | 9 +++++++-- tests/compile-fail/rustc-error.rs | 4 ++++ 2 files changed, 11 insertions(+), 2 deletions(-) create mode 100644 tests/compile-fail/rustc-error.rs diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 1ceb6e621a47b..53a13bf85a5a6 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -259,6 +259,11 @@ fn main() { rustc_driver::install_ice_hook(); let result = rustc_driver::catch_fatal_errors(move || { rustc_driver::run_compiler(&rustc_args, &mut MiriCompilerCalls { miri_config }, None, None) - }); - std::process::exit(result.is_err() as i32); + }) + .and_then(|result| result); + let exit_code = match result { + Ok(_) => rustc_driver::EXIT_SUCCESS, + Err(_) => rustc_driver::EXIT_FAILURE, + }; + std::process::exit(exit_code); } diff --git a/tests/compile-fail/rustc-error.rs b/tests/compile-fail/rustc-error.rs new file mode 100644 index 0000000000000..3579a143f53b7 --- /dev/null +++ b/tests/compile-fail/rustc-error.rs @@ -0,0 +1,4 @@ +// Make sure we exit with non-0 status code when the program fails to build. +fn main() { + println("Hello, world!"); //~ ERROR expected function, found macro +} From b128879529cc3a2262965b183780166fbac0d0ef Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 25 Apr 2020 11:16:03 +0200 Subject: [PATCH 1916/3747] make sure we do not discard information on the Ok exit side --- src/bin/miri.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 53a13bf85a5a6..4e20e3a12da7e 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -262,7 +262,7 @@ fn main() { }) .and_then(|result| result); let exit_code = match result { - Ok(_) => rustc_driver::EXIT_SUCCESS, + Ok(()) => rustc_driver::EXIT_SUCCESS, Err(_) => rustc_driver::EXIT_FAILURE, }; std::process::exit(exit_code); From 72442acaff7c1f2fc805f5cbd39d1661e50cd9d3 Mon Sep 17 00:00:00 2001 From: Hero Bird Date: Sat, 25 Apr 2020 14:58:20 +0200 Subject: [PATCH 1917/3747] Add miri trophy for LazyArray::swap (ink! PR) Details to the found in https://github.com/rust-lang/miri/issues/1364. Note that this was not a found in a `master` or production release of ink!, however without analysing the code via `miri` this could have potentially happened. --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index ea2aa955ba4da..d29f1e2be259d 100644 --- a/README.md +++ b/README.md @@ -281,6 +281,7 @@ Violations of [Stacked Borrows] found that are likely bugs (but Stacked Borrows * [Aliasing mutable references in `sized-chunks`](https://github.com/bodil/sized-chunks/issues/8) * [`String::push_str` invalidating existing references into the string](https://github.com/rust-lang/rust/issues/70301) * [`ryu` using raw pointers outside their valid memory area](https://github.com/dtolnay/ryu/issues/24) +* [`LazyArray::swap` method creating overlapping mutable references (ink! PR)](https://github.com/rust-lang/miri/issues/1364) ## License From 3f43305894fc25ab55c48923a0f1987ee2e9b28b Mon Sep 17 00:00:00 2001 From: Hero Bird Date: Sat, 25 Apr 2020 19:42:48 +0200 Subject: [PATCH 1918/3747] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d29f1e2be259d..ecff779873abf 100644 --- a/README.md +++ b/README.md @@ -281,7 +281,7 @@ Violations of [Stacked Borrows] found that are likely bugs (but Stacked Borrows * [Aliasing mutable references in `sized-chunks`](https://github.com/bodil/sized-chunks/issues/8) * [`String::push_str` invalidating existing references into the string](https://github.com/rust-lang/rust/issues/70301) * [`ryu` using raw pointers outside their valid memory area](https://github.com/dtolnay/ryu/issues/24) -* [`LazyArray::swap` method creating overlapping mutable references (ink! PR)](https://github.com/rust-lang/miri/issues/1364) +* [ink! creating overlapping mutable references](https://github.com/rust-lang/miri/issues/1364) ## License From e267fb4edec86c84b6c0e415a647ba9f8b9f0c9e Mon Sep 17 00:00:00 2001 From: David Cook Date: Sun, 26 Apr 2020 22:13:36 -0500 Subject: [PATCH 1919/3747] Review comments --- src/diagnostics.rs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/diagnostics.rs b/src/diagnostics.rs index e72232323ba28..114f1d9be3623 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -115,8 +115,9 @@ pub fn report_error<'tcx, 'mir>( e.print_backtrace(); let msg = e.to_string(); - let result = report_msg(ecx, &format!("{}: {}", title, msg), msg, helps, true); + report_msg(ecx, &format!("{}: {}", title, msg), msg, helps, true); + // Extra output to help debug specific issues. if let UndefinedBehavior(UndefinedBehaviorInfo::InvalidUndefBytes(Some(ptr))) = e.kind { eprintln!( "Uninitialized read occurred at offset 0x{:x} into this allocation:", @@ -126,7 +127,7 @@ pub fn report_error<'tcx, 'mir>( eprintln!(); } - result + None } /// Report an error or note (depending on the `error` argument) at the current frame's current statement. @@ -137,7 +138,7 @@ fn report_msg<'tcx, 'mir>( span_msg: String, mut helps: Vec, error: bool, -) -> Option { +) { let span = if let Some(frame) = ecx.machine.stack.last() { frame.current_source_info().unwrap().span } else { @@ -178,8 +179,6 @@ fn report_msg<'tcx, 'mir>( trace!(" local {}: {:?}", i, local.value); } } - // Let the reported error determine the return code. - return None; } thread_local! { From da86c81e39ff27925e7052e1cc612414c7eeb244 Mon Sep 17 00:00:00 2001 From: Samrat Man Singh Date: Mon, 27 Apr 2020 09:35:19 +0530 Subject: [PATCH 1920/3747] Add test to verify arg size mismatch throws UB Also: bump up `rust-version` --- rust-version | 2 +- tests/compile-fail/shim_arg_size.rs | 15 +++++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) create mode 100644 tests/compile-fail/shim_arg_size.rs diff --git a/rust-version b/rust-version index 8ed0e6ba3531a..53979b82cf834 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -14b15521c52549ebbb113173b4abecd124b5a823 +e83f7563495dbe2629b0cbc738afb0808c4482e1 diff --git a/tests/compile-fail/shim_arg_size.rs b/tests/compile-fail/shim_arg_size.rs new file mode 100644 index 0000000000000..38b5475b9f7ea --- /dev/null +++ b/tests/compile-fail/shim_arg_size.rs @@ -0,0 +1,15 @@ +#![feature(rustc_private)] + +extern crate libc; + +// error-pattern: scalar size mismatch +fn main() { + extern "C" { + fn malloc(size: u32) -> *mut std::ffi::c_void; + } + + unsafe { + let p1 = malloc(42); + libc::free(p1); + }; +} From ae9796b9d82609e7a7325930f38fe469d676bc8b Mon Sep 17 00:00:00 2001 From: Samrat Man Singh Date: Mon, 27 Apr 2020 10:00:35 +0530 Subject: [PATCH 1921/3747] Fix shim_arg_size test for 32-bit machines --- tests/compile-fail/shim_arg_size.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/compile-fail/shim_arg_size.rs b/tests/compile-fail/shim_arg_size.rs index 38b5475b9f7ea..a31461fdbf48d 100644 --- a/tests/compile-fail/shim_arg_size.rs +++ b/tests/compile-fail/shim_arg_size.rs @@ -5,7 +5,13 @@ extern crate libc; // error-pattern: scalar size mismatch fn main() { extern "C" { + // Use the wrong type(ie. not the pointer width) for the `size` + // argument. + #[cfg(target_pointer_width="64")] fn malloc(size: u32) -> *mut std::ffi::c_void; + + #[cfg(target_pointer_width="32")] + fn malloc(size: u16) -> *mut std::ffi::c_void; } unsafe { From 73f258c451a36294587e48166f72fdae01217891 Mon Sep 17 00:00:00 2001 From: Samrat Man Singh Date: Mon, 27 Apr 2020 15:34:42 +0530 Subject: [PATCH 1922/3747] Replace error-pattern with annotation; remove unreachable line --- tests/compile-fail/shim_arg_size.rs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/tests/compile-fail/shim_arg_size.rs b/tests/compile-fail/shim_arg_size.rs index a31461fdbf48d..dd8d6dac51de8 100644 --- a/tests/compile-fail/shim_arg_size.rs +++ b/tests/compile-fail/shim_arg_size.rs @@ -1,8 +1,5 @@ #![feature(rustc_private)] -extern crate libc; - -// error-pattern: scalar size mismatch fn main() { extern "C" { // Use the wrong type(ie. not the pointer width) for the `size` @@ -15,7 +12,6 @@ fn main() { } unsafe { - let p1 = malloc(42); - libc::free(p1); + let _p1 = malloc(42); //~ ERROR Undefined Behavior: scalar size mismatch }; } From a5ddaa07eb79ff6288a686aa17b134116eab4eb8 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 27 Apr 2020 12:27:56 +0200 Subject: [PATCH 1923/3747] rename tests: undefined -> uninit --- ...rs => overwriting_part_of_relocation_makes_the_rest_uninit.rs} | 0 .../{transmute-pair-undef.rs => transmute-pair-uninit.rs} | 0 tests/compile-fail/{undefined_buffer.rs => uninit_buffer.rs} | 0 .../compile-fail/{undefined_byte_read.rs => uninit_byte_read.rs} | 0 tests/run-pass/{move-undef-primval.rs => move-uninit-primval.rs} | 0 5 files changed, 0 insertions(+), 0 deletions(-) rename tests/compile-fail/{overwriting_part_of_relocation_makes_the_rest_undefined.rs => overwriting_part_of_relocation_makes_the_rest_uninit.rs} (100%) rename tests/compile-fail/{transmute-pair-undef.rs => transmute-pair-uninit.rs} (100%) rename tests/compile-fail/{undefined_buffer.rs => uninit_buffer.rs} (100%) rename tests/compile-fail/{undefined_byte_read.rs => uninit_byte_read.rs} (100%) rename tests/run-pass/{move-undef-primval.rs => move-uninit-primval.rs} (100%) diff --git a/tests/compile-fail/overwriting_part_of_relocation_makes_the_rest_undefined.rs b/tests/compile-fail/overwriting_part_of_relocation_makes_the_rest_uninit.rs similarity index 100% rename from tests/compile-fail/overwriting_part_of_relocation_makes_the_rest_undefined.rs rename to tests/compile-fail/overwriting_part_of_relocation_makes_the_rest_uninit.rs diff --git a/tests/compile-fail/transmute-pair-undef.rs b/tests/compile-fail/transmute-pair-uninit.rs similarity index 100% rename from tests/compile-fail/transmute-pair-undef.rs rename to tests/compile-fail/transmute-pair-uninit.rs diff --git a/tests/compile-fail/undefined_buffer.rs b/tests/compile-fail/uninit_buffer.rs similarity index 100% rename from tests/compile-fail/undefined_buffer.rs rename to tests/compile-fail/uninit_buffer.rs diff --git a/tests/compile-fail/undefined_byte_read.rs b/tests/compile-fail/uninit_byte_read.rs similarity index 100% rename from tests/compile-fail/undefined_byte_read.rs rename to tests/compile-fail/uninit_byte_read.rs diff --git a/tests/run-pass/move-undef-primval.rs b/tests/run-pass/move-uninit-primval.rs similarity index 100% rename from tests/run-pass/move-undef-primval.rs rename to tests/run-pass/move-uninit-primval.rs From 82f17ab91714bcc8bd2a5591e90db690d449d38c Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Mon, 16 Mar 2020 16:48:44 -0700 Subject: [PATCH 1924/3747] Implement basic support for concurrency (Linux only). --- src/eval.rs | 3 +- src/lib.rs | 3 + src/machine.rs | 67 ++++-- src/shims/foreign_items/posix.rs | 101 ++++++++- src/shims/foreign_items/windows.rs | 6 +- src/shims/tls.rs | 98 +++++---- src/threads.rs | 303 +++++++++++++++++++++++++++ tests/compile-fail/thread-spawn.rs | 7 - tests/run-pass/concurrency/simple.rs | 59 ++++++ 9 files changed, 571 insertions(+), 76 deletions(-) create mode 100644 src/threads.rs delete mode 100644 tests/compile-fail/thread-spawn.rs create mode 100644 tests/run-pass/concurrency/simple.rs diff --git a/src/eval.rs b/src/eval.rs index 61a5b71f0bdbf..b0a59c64d1e16 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -205,7 +205,8 @@ pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) -> // Perform the main execution. let res: InterpResult<'_, i64> = (|| { // Main loop. - while ecx.step()? { + while ecx.schedule()? { + assert!(ecx.step()?); ecx.process_diagnostics(); } // Read the return code pointer *before* we run TLS destructors, to assert diff --git a/src/lib.rs b/src/lib.rs index 2f381b4a34546..c042526be64c1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -12,6 +12,7 @@ extern crate rustc_ast; #[macro_use] extern crate rustc_middle; extern crate rustc_data_structures; extern crate rustc_hir; +extern crate rustc_index; extern crate rustc_mir; extern crate rustc_span; extern crate rustc_target; @@ -26,6 +27,7 @@ mod operator; mod range_map; mod shims; mod stacked_borrows; +mod threads; // Make all those symbols available in the same place as our own. pub use rustc_mir::interpret::*; @@ -60,6 +62,7 @@ pub use crate::range_map::RangeMap; pub use crate::stacked_borrows::{ EvalContextExt as StackedBorEvalContextExt, Item, Permission, PtrId, Stack, Stacks, Tag, }; +pub use crate::threads::EvalContextExt as ThreadsEvalContextExt; /// Insert rustc arguments at the beginning of the argument list that Miri wants to be /// set per default, for maximal validation power. diff --git a/src/machine.rs b/src/machine.rs index 2ab5f10af66d8..9d1fa9b78c32d 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -26,6 +26,8 @@ use rustc_target::abi::{LayoutOf, Size}; use crate::*; +pub use crate::threads::{ThreadId, ThreadSet, ThreadLocalStorage}; + // Some global facts about the emulated machine. pub const PAGE_SIZE: u64 = 4 * 1024; // FIXME: adjust to target architecture pub const STACK_ADDR: u64 = 32 * PAGE_SIZE; // not really about the "stack", but where we start assigning integer addresses to allocations @@ -107,6 +109,7 @@ pub struct AllocExtra { pub struct MemoryExtra { pub stacked_borrows: Option, pub intptrcast: intptrcast::MemoryExtra, + pub tls: ThreadLocalStorage, /// Mapping extern static names to their canonical allocation. extern_statics: FxHashMap, @@ -143,6 +146,7 @@ impl MemoryExtra { rng: RefCell::new(rng), tracked_alloc_id, check_alignment, + tls: Default::default(), } } @@ -251,8 +255,8 @@ pub struct Evaluator<'mir, 'tcx> { /// The "time anchor" for this machine's monotone clock (for `Instant` simulation). pub(crate) time_anchor: Instant, - /// The call stack. - pub(crate) stack: Vec>>, + /// The set of threads. + pub(crate) threads: ThreadSet<'mir, 'tcx>, /// Precomputed `TyLayout`s for primitive data types that are commonly used inside Miri. pub(crate) layouts: PrimitiveLayouts<'tcx>, @@ -282,7 +286,7 @@ impl<'mir, 'tcx> Evaluator<'mir, 'tcx> { panic_payload: None, time_anchor: Instant::now(), layouts, - stack: Vec::default(), + threads: Default::default(), } } } @@ -326,6 +330,19 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { memory_extra.check_alignment } + #[inline(always)] + fn stack<'a>( + ecx: &'a InterpCx<'mir, 'tcx, Self> + ) -> &'a [Frame<'mir, 'tcx, Self::PointerTag, Self::FrameExtra>] { + ecx.active_thread_stack() + } + + fn stack_mut<'a>( + ecx: &'a mut InterpCx<'mir, 'tcx, Self> + ) -> &'a mut Vec> { + ecx.active_thread_stack_mut() + } + #[inline(always)] fn enforce_validity(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool { ecx.machine.validate @@ -418,29 +435,39 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { fn canonical_alloc_id(mem: &Memory<'mir, 'tcx, Self>, id: AllocId) -> AllocId { let tcx = mem.tcx; - // Figure out if this is an extern static, and if yes, which one. - let def_id = match tcx.alloc_map.lock().get(id) { - Some(GlobalAlloc::Static(def_id)) if tcx.is_foreign_item(def_id) => def_id, + let alloc = tcx.alloc_map.lock().get(id); + match alloc { + Some(GlobalAlloc::Static(def_id)) if tcx.is_foreign_item(def_id) => { + // Figure out if this is an extern static, and if yes, which one. + let attrs = tcx.get_attrs(def_id); + let link_name = match attr::first_attr_value_str_by_name(&attrs, sym::link_name) { + Some(name) => name, + None => tcx.item_name(def_id), + }; + // Check if we know this one. + if let Some(canonical_id) = mem.extra.extern_statics.get(&link_name) { + trace!("canonical_alloc_id: {:?} ({}) -> {:?}", id, link_name, canonical_id); + *canonical_id + } else { + // Return original id; `Memory::get_static_alloc` will throw an error. + id + } + }, + Some(GlobalAlloc::Static(def_id)) if tcx.has_attr(def_id, sym::thread_local) => { + // We have a thread local, so we need to get a unique allocation id for it. + mem.extra.tls.get_or_register_allocation(*tcx, id) + }, _ => { // No need to canonicalize anything. - return id; + id } - }; - let attrs = tcx.get_attrs(def_id); - let link_name = match attr::first_attr_value_str_by_name(&attrs, sym::link_name) { - Some(name) => name, - None => tcx.item_name(def_id), - }; - // Check if we know this one. - if let Some(canonical_id) = mem.extra.extern_statics.get(&link_name) { - trace!("canonical_alloc_id: {:?} ({}) -> {:?}", id, link_name, canonical_id); - *canonical_id - } else { - // Return original id; `Memory::get_static_alloc` will throw an error. - id } } + fn resolve_thread_local_allocation_id(extra: &Self::MemoryExtra, id: AllocId) -> AllocId { + extra.tls.resolve_allocation(id) + } + fn init_allocation_extra<'b>( memory_extra: &MemoryExtra, id: AllocId, diff --git a/src/shims/foreign_items/posix.rs b/src/shims/foreign_items/posix.rs index 70e16a65b59b3..47b661061d690 100644 --- a/src/shims/foreign_items/posix.rs +++ b/src/shims/foreign_items/posix.rs @@ -6,6 +6,7 @@ use std::convert::TryFrom; use log::trace; use crate::*; +use rustc_index::vec::Idx; use rustc_middle::mir; use rustc_target::abi::{Align, LayoutOf, Size}; @@ -221,13 +222,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "pthread_getspecific" => { let key = this.force_bits(this.read_scalar(args[0])?.not_undef()?, args[0].layout.size)?; - let ptr = this.machine.tls.load_tls(key, this)?; + let active_thread = this.get_active_thread()?; + let ptr = this.machine.tls.load_tls(key, active_thread, this)?; this.write_scalar(ptr, dest)?; } "pthread_setspecific" => { let key = this.force_bits(this.read_scalar(args[0])?.not_undef()?, args[0].layout.size)?; + let active_thread = this.get_active_thread()?; let new_ptr = this.read_scalar(args[1])?.not_undef()?; - this.machine.tls.store_tls(key, this.test_null(new_ptr)?)?; + this.machine.tls.store_tls(key, active_thread, this.test_null(new_ptr)?)?; // Return success (`0`). this.write_null(dest)?; @@ -291,11 +294,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_i32(result), dest)?; } - // Better error for attempts to create a thread - "pthread_create" => { - throw_unsup_format!("Miri does not support threading"); - } - // Miscellaneous "isatty" => { let _fd = this.read_scalar(args[0])?.to_i32()?; @@ -316,7 +314,94 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_null(dest)?; } - // Incomplete shims that we "stub out" just to get pre-main initialization code to work. + // Threading + "pthread_create" => { + assert_eq!(args.len(), 4); + let func = args[2]; + let fn_ptr = this.read_scalar(func)?.not_undef()?; + let fn_val = this.memory.get_fn(fn_ptr)?; + let instance = match fn_val { + rustc_mir::interpret::FnVal::Instance(instance) => instance, + _ => unreachable!(), + }; + let thread_info_place = this.deref_operand(args[0])?; + let thread_info_type = args[0].layout.ty + .builtin_deref(true) + .ok_or_else(|| err_ub_format!( + "wrong signature used for `pthread_create`: first argument must be a raw pointer." + ))? + .ty; + let thread_info_layout = this.layout_of(thread_info_type)?; + let func_arg = match *args[3] { + rustc_mir::interpret::Operand::Immediate(immediate) => immediate, + _ => unreachable!(), + }; + let func_args = [func_arg]; + let ret_place = + this.allocate(this.layout_of(this.tcx.types.usize)?, MiriMemoryKind::Machine.into()); + let new_thread_id = this.create_thread()?; + let old_thread_id = this.set_active_thread(new_thread_id)?; + this.call_function( + instance, + &func_args[..], + Some(ret_place.into()), + StackPopCleanup::None { cleanup: true }, + )?; + this.set_active_thread(old_thread_id)?; + this.write_scalar( + Scalar::from_uint(new_thread_id.index() as u128, thread_info_layout.size), + thread_info_place.into(), + )?; + + // Return success (`0`). + this.write_null(dest)?; + } + "pthread_join" => { + assert_eq!(args.len(), 2); + assert!( + this.is_null(this.read_scalar(args[1])?.not_undef()?)?, + "Miri supports pthread_join only with retval==NULL" + ); + let thread = this.read_scalar(args[0])?.not_undef()?.to_machine_usize(this)?; + this.join_thread(thread.into())?; + + // Return success (`0`). + this.write_null(dest)?; + } + "pthread_detach" => { + let thread = this.read_scalar(args[0])?.not_undef()?.to_machine_usize(this)?; + this.detach_thread(thread.into())?; + + // Return success (`0`). + this.write_null(dest)?; + } + + "pthread_attr_getguardsize" => { + assert_eq!(args.len(), 2); + + let guard_size = this.deref_operand(args[1])?; + let guard_size_type = args[1].layout.ty + .builtin_deref(true) + .ok_or_else(|| err_ub_format!( + "wrong signature used for `pthread_attr_getguardsize`: first argument must be a raw pointer." + ))? + .ty; + let guard_size_layout = this.layout_of(guard_size_type)?; + this.write_scalar(Scalar::from_uint(crate::PAGE_SIZE, guard_size_layout.size), guard_size.into())?; + + // Return success (`0`). + this.write_null(dest)?; + } + + "prctl" => { + let option = this.read_scalar(args[0])?.not_undef()?.to_i32()?; + assert_eq!(option, 0xf, "Miri supports only PR_SET_NAME"); + + // Return success (`0`). + this.write_null(dest)?; + } + + // Incomplete shims that we "stub out" just to get pre-main initialziation code to work. // These shims are enabled only when the caller is in the standard library. | "pthread_attr_init" | "pthread_attr_destroy" diff --git a/src/shims/foreign_items/windows.rs b/src/shims/foreign_items/windows.rs index 0950a02bf92f9..a58444b21bff1 100644 --- a/src/shims/foreign_items/windows.rs +++ b/src/shims/foreign_items/windows.rs @@ -144,13 +144,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "TlsGetValue" => { let key = u128::from(this.read_scalar(args[0])?.to_u32()?); - let ptr = this.machine.tls.load_tls(key, this)?; + let active_thread = this.get_active_thread()?; + let ptr = this.machine.tls.load_tls(key, active_thread, this)?; this.write_scalar(ptr, dest)?; } "TlsSetValue" => { let key = u128::from(this.read_scalar(args[0])?.to_u32()?); + let active_thread = this.get_active_thread()?; let new_ptr = this.read_scalar(args[1])?.not_undef()?; - this.machine.tls.store_tls(key, this.test_null(new_ptr)?)?; + this.machine.tls.store_tls(key, active_thread, this.test_null(new_ptr)?)?; // Return success (`1`). this.write_scalar(Scalar::from_i32(1), dest)?; diff --git a/src/shims/tls.rs b/src/shims/tls.rs index 7b84468402953..d16acb7500370 100644 --- a/src/shims/tls.rs +++ b/src/shims/tls.rs @@ -1,22 +1,24 @@ //! Implement thread-local storage. use std::collections::BTreeMap; +use std::collections::btree_map::Entry; use log::trace; use rustc_middle::ty; use rustc_target::abi::{Size, HasDataLayout}; -use crate::{HelpersEvalContextExt, InterpResult, MPlaceTy, Scalar, StackPopCleanup, Tag}; +use crate::{HelpersEvalContextExt, ThreadsEvalContextExt, InterpResult, MPlaceTy, Scalar, StackPopCleanup, Tag}; +use crate::machine::ThreadId; pub type TlsKey = u128; -#[derive(Copy, Clone, Debug)] +#[derive(Clone, Debug)] pub struct TlsEntry<'tcx> { /// The data for this key. None is used to represent NULL. /// (We normalize this early to avoid having to do a NULL-ptr-test each time we access the data.) /// Will eventually become a map from thread IDs to `Scalar`s, if we ever support more than one thread. - data: Option>, + data: BTreeMap>, dtor: Option>, } @@ -52,7 +54,7 @@ impl<'tcx> TlsData<'tcx> { pub fn create_tls_key(&mut self, dtor: Option>, max_size: Size) -> InterpResult<'tcx, TlsKey> { let new_key = self.next_key; self.next_key += 1; - self.keys.insert(new_key, TlsEntry { data: None, dtor }).unwrap_none(); + self.keys.insert(new_key, TlsEntry { data: Default::default(), dtor }).unwrap_none(); trace!("New TLS key allocated: {} with dtor {:?}", new_key, dtor); if max_size.bits() < 128 && new_key >= (1u128 << max_size.bits() as u128) { @@ -74,22 +76,34 @@ impl<'tcx> TlsData<'tcx> { pub fn load_tls( &self, key: TlsKey, + thread_id: ThreadId, cx: &impl HasDataLayout, ) -> InterpResult<'tcx, Scalar> { match self.keys.get(&key) { - Some(&TlsEntry { data, .. }) => { - trace!("TLS key {} loaded: {:?}", key, data); - Ok(data.unwrap_or_else(|| Scalar::null_ptr(cx).into())) + Some(TlsEntry { data, .. }) => { + let value = data.get(&thread_id).cloned(); + trace!("TLS key {} for thread {:?} loaded: {:?}", key, thread_id, value); + Ok(value.unwrap_or_else(|| Scalar::null_ptr(cx).into())) } None => throw_ub_format!("loading from a non-existing TLS key: {}", key), } } - pub fn store_tls(&mut self, key: TlsKey, new_data: Option>) -> InterpResult<'tcx> { + pub fn store_tls( + &mut self, + key: TlsKey, thread_id: ThreadId, new_data: Option>) -> InterpResult<'tcx> { match self.keys.get_mut(&key) { Some(TlsEntry { data, .. }) => { - trace!("TLS key {} stored: {:?}", key, new_data); - *data = new_data; + match new_data { + Some(ptr) => { + trace!("TLS key {} for thread {:?} stored: {:?}", key, thread_id, ptr); + data.insert(thread_id, ptr); + } + None => { + trace!("TLS key {} for thread {:?} removed", key, thread_id); + data.remove(&thread_id); + } + } Ok(()) } None => throw_ub_format!("storing to a non-existing TLS key: {}", key), @@ -131,7 +145,8 @@ impl<'tcx> TlsData<'tcx> { fn fetch_tls_dtor( &mut self, key: Option, - ) -> Option<(ty::Instance<'tcx>, Scalar, TlsKey)> { + thread_id: ThreadId, + ) -> Option<(ty::Instance<'tcx>, ThreadId, Scalar, TlsKey)> { use std::collections::Bound::*; let thread_local = &mut self.keys; @@ -142,12 +157,15 @@ impl<'tcx> TlsData<'tcx> { for (&key, TlsEntry { data, dtor }) in thread_local.range_mut((start, Unbounded)) { - if let Some(data_scalar) = *data { - if let Some(dtor) = dtor { - let ret = Some((*dtor, data_scalar, key)); - *data = None; - return ret; + match data.entry(thread_id) { + Entry::Occupied(entry) => { + let (thread_id, data_scalar) = entry.remove_entry(); + if let Some(dtor) = dtor { + let ret = Some((dtor, thread_id, data_scalar, key)); + return ret; + } } + Entry::Vacant(_) => {} } } None @@ -156,6 +174,7 @@ impl<'tcx> TlsData<'tcx> { impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { + /// Run TLS destructors for the currently active thread. fn run_tls_dtors(&mut self) -> InterpResult<'tcx> { let this = self.eval_context_mut(); assert!(!this.machine.tls.dtors_running, "running TLS dtors twice"); @@ -204,28 +223,31 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // Now run the "keyed" destructors. - let mut dtor = this.machine.tls.fetch_tls_dtor(None); - while let Some((instance, ptr, key)) = dtor { - trace!("Running TLS dtor {:?} on {:?}", instance, ptr); - assert!(!this.is_null(ptr).unwrap(), "data can't be NULL when dtor is called!"); - - let ret_place = MPlaceTy::dangling(this.machine.layouts.unit, this).into(); - this.call_function( - instance, - &[ptr.into()], - Some(ret_place), - StackPopCleanup::None { cleanup: true }, - )?; - - // step until out of stackframes - this.run()?; - - // Fetch next dtor after `key`. - dtor = match this.machine.tls.fetch_tls_dtor(Some(key)) { - dtor @ Some(_) => dtor, - // We ran each dtor once, start over from the beginning. - None => this.machine.tls.fetch_tls_dtor(None), - }; + for thread_id in this.get_all_thread_ids() { + this.set_active_thread(thread_id)?; + let mut dtor = this.machine.tls.fetch_tls_dtor(None, thread_id); + while let Some((instance, thread_id, ptr, key)) = dtor { + trace!("Running TLS dtor {:?} on {:?} at {:?}", instance, ptr, thread_id); + assert!(!this.is_null(ptr).unwrap(), "Data can't be NULL when dtor is called!"); + + let ret_place = MPlaceTy::dangling(this.layout_of(this.tcx.mk_unit())?, this).into(); + this.call_function( + instance, + &[ptr.into()], + Some(ret_place), + StackPopCleanup::None { cleanup: true }, + )?; + + // step until out of stackframes + this.run()?; + + // Fetch next dtor after `key`. + dtor = match this.machine.tls.fetch_tls_dtor(Some(key), thread_id) { + dtor @ Some(_) => dtor, + // We ran each dtor once, start over from the beginning. + None => this.machine.tls.fetch_tls_dtor(None, thread_id), + }; + } } Ok(()) } diff --git a/src/threads.rs b/src/threads.rs new file mode 100644 index 0000000000000..14ee58c2ee3e6 --- /dev/null +++ b/src/threads.rs @@ -0,0 +1,303 @@ +//! Implements threads. + +use std::cell::RefCell; +use std::collections::hash_map::Entry; + +use log::trace; + +use rustc_middle::ty; +use rustc_data_structures::fx::FxHashMap; +use rustc_index::vec::{Idx, IndexVec}; + +use crate::*; + +/// A thread identifier. +#[derive(Clone, Copy, Debug, PartialOrd, Ord, PartialEq, Eq, Hash)] +pub struct ThreadId(usize); + +impl Idx for ThreadId { + fn new(idx: usize) -> Self { + ThreadId(idx) + } + fn index(self) -> usize { + self.0 + } +} + +impl From for ThreadId { + fn from(id: u64) -> Self { + Self(id as usize) + } +} + +/// The state of a thread. +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub enum ThreadState { + /// The thread is enabled and can be executed. + Enabled, + /// The thread tried to join the specified thread and is blocked until that + /// thread terminates. + Blocked(ThreadId), + /// The thread has terminated its execution (we do not delete terminated + /// threads.) + Terminated, +} + +/// A thread. +pub struct Thread<'mir, 'tcx> { + state: ThreadState, + /// The virtual call stack. + stack: Vec>>, + /// Is the thread detached? + /// + /// A thread is detached if its join handle was destroyed and no other + /// thread can join it. + detached: bool, +} + +impl<'mir, 'tcx> Thread<'mir, 'tcx> { + /// Check if the thread terminated. If yes, change the state to terminated + /// and return `true`. + fn check_terminated(&mut self) -> bool { + if self.state == ThreadState::Enabled { + if self.stack.is_empty() { + self.state = ThreadState::Terminated; + return true; + } + } + false + } +} + +impl<'mir, 'tcx> std::fmt::Debug for Thread<'mir, 'tcx> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{:?}", self.state) + } +} + +impl<'mir, 'tcx> Default for Thread<'mir, 'tcx> { + fn default() -> Self { + Self { state: ThreadState::Enabled, stack: Vec::new(), detached: false } + } +} + +/// A set of threads. +#[derive(Debug)] +pub struct ThreadSet<'mir, 'tcx> { + /// Identifier of the currently active thread. + active_thread: ThreadId, + /// Threads used in the program. + /// + /// Note that this vector also contains terminated threads. + threads: IndexVec>, + + /// List of threads that just terminated. TODO: Cleanup. + terminated_threads: Vec, +} + +impl<'mir, 'tcx> Default for ThreadSet<'mir, 'tcx> { + fn default() -> Self { + let mut threads = IndexVec::new(); + threads.push(Default::default()); + Self { + active_thread: ThreadId::new(0), + threads: threads, + terminated_threads: Default::default(), + } + } +} + +impl<'mir, 'tcx: 'mir> ThreadSet<'mir, 'tcx> { + /// Borrow the stack of the active thread. + fn active_thread_stack(&self) -> &[Frame<'mir, 'tcx, Tag, FrameData<'tcx>>] { + &self.threads[self.active_thread].stack + } + /// Mutably borrow the stack of the active thread. + fn active_thread_stack_mut(&mut self) -> &mut Vec>> { + &mut self.threads[self.active_thread].stack + } + /// Create a new thread and returns its id. + fn create_thread(&mut self) -> ThreadId { + let new_thread_id = ThreadId::new(self.threads.len()); + self.threads.push(Default::default()); + new_thread_id + } + /// Set an active thread and return the id of the thread that was active before. + fn set_active_thread(&mut self, id: ThreadId) -> ThreadId { + let active_thread_id = self.active_thread; + self.active_thread = id; + assert!(self.active_thread.index() < self.threads.len()); + active_thread_id + } + /// Get the id of the currently active thread. + fn get_active_thread(&self) -> ThreadId { + self.active_thread + } + /// Mark the thread as detached, which means that no other thread will try + /// to join it and the thread is responsible for cleaning up. + fn detach_thread(&mut self, id: ThreadId) { + self.threads[id].detached = true; + } + /// Mark that the active thread tries to join the thread with `joined_thread_id`. + fn join_thread(&mut self, joined_thread_id: ThreadId) { + assert!(!self.threads[joined_thread_id].detached, "Bug: trying to join a detached thread."); + assert_ne!(joined_thread_id, self.active_thread, "Bug: trying to join itself"); + assert!( + self.threads + .iter() + .all(|thread| thread.state != ThreadState::Blocked(joined_thread_id)), + "Bug: multiple threads try to join the same thread." + ); + if self.threads[joined_thread_id].state != ThreadState::Terminated { + // The joined thread is still running, we need to wait for it. + self.threads[self.active_thread].state = ThreadState::Blocked(joined_thread_id); + trace!( + "{:?} blocked on {:?} when trying to join", + self.active_thread, + joined_thread_id + ); + } + } + /// Get ids of all threads ever allocated. + fn get_all_thread_ids(&mut self) -> Vec { + (0..self.threads.len()).map(ThreadId::new).collect() + } + /// Decide which thread to run next. + /// + /// Returns `false` if all threads terminated. + fn schedule(&mut self) -> InterpResult<'tcx, bool> { + if self.threads[self.active_thread].check_terminated() { + // Check if we need to unblock any threads. + for (i, thread) in self.threads.iter_enumerated_mut() { + if thread.state == ThreadState::Blocked(self.active_thread) { + trace!("unblocking {:?} because {:?} terminated", i, self.active_thread); + thread.state = ThreadState::Enabled; + } + } + } + if self.threads[self.active_thread].state == ThreadState::Enabled { + return Ok(true); + } + if let Some(enabled_thread) = + self.threads.iter().position(|thread| thread.state == ThreadState::Enabled) + { + self.active_thread = ThreadId::new(enabled_thread); + return Ok(true); + } + if self.threads.iter().all(|thread| thread.state == ThreadState::Terminated) { + Ok(false) + } else { + throw_machine_stop!(TerminationInfo::Abort(Some(format!("execution deadlocked")))) + } + } +} + +/// In Rust, a thread local variable is just a specially marked static. To +/// ensure a property that each memory allocation has a globally unique +/// allocation identifier, we create a fresh allocation id for each thread. This +/// data structure keeps the track of the created allocation identifiers and +/// their relation to the original static allocations. +#[derive(Clone, Debug, Default)] +pub struct ThreadLocalStorage { + /// A map from a thread local allocation identifier to the static from which + /// it was created. + thread_local_origin: RefCell>, + /// A map from a thread local static and thread id to the unique thread + /// local allocation. + thread_local_allocations: RefCell>, + /// The currently active thread. + active_thread: Option, +} + +impl ThreadLocalStorage { + /// For static allocation identifier `original_id` get a thread local + /// allocation identifier. If it is not allocated yet, allocate. + pub fn get_or_register_allocation(&self, tcx: ty::TyCtxt<'_>, original_id: AllocId) -> AllocId { + match self + .thread_local_allocations + .borrow_mut() + .entry((original_id, self.active_thread.unwrap())) + { + Entry::Occupied(entry) => *entry.get(), + Entry::Vacant(entry) => { + let fresh_id = tcx.alloc_map.lock().reserve(); + entry.insert(fresh_id); + self.thread_local_origin.borrow_mut().insert(fresh_id, original_id); + trace!( + "get_or_register_allocation(original_id={:?}) -> {:?}", + original_id, + fresh_id + ); + fresh_id + } + } + } + /// For thread local allocation identifier `alloc_id`, retrieve the original + /// static allocation identifier from which it was created. + pub fn resolve_allocation(&self, alloc_id: AllocId) -> AllocId { + trace!("resolve_allocation(alloc_id: {:?})", alloc_id); + if let Some(original_id) = self.thread_local_origin.borrow().get(&alloc_id) { + trace!("resolve_allocation(alloc_id: {:?}) -> {:?}", alloc_id, original_id); + *original_id + } else { + alloc_id + } + } + /// Set which thread is currently active. + fn set_active_thread(&mut self, active_thread: ThreadId) { + self.active_thread = Some(active_thread); + } +} + +impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} +pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { + fn create_thread(&mut self) -> InterpResult<'tcx, ThreadId> { + let this = self.eval_context_mut(); + Ok(this.machine.threads.create_thread()) + } + fn detach_thread(&mut self, thread_id: ThreadId) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + this.machine.threads.detach_thread(thread_id); + Ok(()) + } + fn join_thread(&mut self, joined_thread_id: ThreadId) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + this.machine.threads.join_thread(joined_thread_id); + Ok(()) + } + fn set_active_thread(&mut self, thread_id: ThreadId) -> InterpResult<'tcx, ThreadId> { + let this = self.eval_context_mut(); + this.memory.extra.tls.set_active_thread(thread_id); + Ok(this.machine.threads.set_active_thread(thread_id)) + } + fn get_active_thread(&self) -> InterpResult<'tcx, ThreadId> { + let this = self.eval_context_ref(); + Ok(this.machine.threads.get_active_thread()) + } + fn active_thread_stack(&self) -> &[Frame<'mir, 'tcx, Tag, FrameData<'tcx>>] { + let this = self.eval_context_ref(); + this.machine.threads.active_thread_stack() + } + fn active_thread_stack_mut(&mut self) -> &mut Vec>> { + let this = self.eval_context_mut(); + this.machine.threads.active_thread_stack_mut() + } + fn get_all_thread_ids(&mut self) -> Vec { + let this = self.eval_context_mut(); + this.machine.threads.get_all_thread_ids() + } + /// Decide which thread to run next. + /// + /// Returns `false` if all threads terminated. + fn schedule(&mut self) -> InterpResult<'tcx, bool> { + let this = self.eval_context_mut(); + // Find the next thread to run. + if this.machine.threads.schedule()? { + let active_thread = this.machine.threads.get_active_thread(); + this.memory.extra.tls.set_active_thread(active_thread); + Ok(true) + } else { + Ok(false) + } + } +} diff --git a/tests/compile-fail/thread-spawn.rs b/tests/compile-fail/thread-spawn.rs deleted file mode 100644 index 450dea99f552f..0000000000000 --- a/tests/compile-fail/thread-spawn.rs +++ /dev/null @@ -1,7 +0,0 @@ -use std::thread; - -// error-pattern: Miri does not support threading - -fn main() { - thread::spawn(|| {}); -} diff --git a/tests/run-pass/concurrency/simple.rs b/tests/run-pass/concurrency/simple.rs new file mode 100644 index 0000000000000..5c295d1702dd8 --- /dev/null +++ b/tests/run-pass/concurrency/simple.rs @@ -0,0 +1,59 @@ +use std::thread; + +fn create_and_detach() { + thread::spawn(|| ()); +} + +fn create_and_join() { + thread::spawn(|| ()).join().unwrap(); +} + +fn create_and_get_result() { + let nine = thread::spawn(|| 5 + 4).join().unwrap(); + assert_eq!(nine, 9); +} + +fn create_and_leak_result() { + thread::spawn(|| 7); +} + +fn create_nested_and_detach() { + thread::spawn(|| { + thread::spawn(|| ()); + }); +} + +fn create_nested_and_join() { + let handle = thread::spawn(|| thread::spawn(|| ())); + let handle_nested = handle.join().unwrap(); + handle_nested.join().unwrap(); +} + +fn create_move_in() { + let x = String::from("Hello!"); + thread::spawn(move || { + assert_eq!(x.len(), 6); + }) + .join() + .unwrap(); +} + +fn create_move_out() { + let result = thread::spawn(|| { + String::from("Hello!") + }) + .join() + .unwrap(); + assert_eq!(result.len(), 6); +} + +fn main() { + create_and_detach(); + create_and_join(); + create_and_get_result(); + create_and_leak_result(); + create_nested_and_detach(); + create_nested_and_join(); + create_move_in(); + create_move_out(); +} From 58a6a2729aa03ef8ca1c68f9c0396fafa1208f58 Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Wed, 1 Apr 2020 16:26:41 -0700 Subject: [PATCH 1925/3747] Add a warning that Miri does not check for data-races. --- README.md | 4 +++- src/shims/foreign_items/posix.rs | 2 ++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index ecff779873abf..fb981a71f0e4d 100644 --- a/README.md +++ b/README.md @@ -47,7 +47,9 @@ in your program, and cannot run all programs: * Miri runs the program as a platform-independent interpreter, so the program has no access to most platform-specific APIs or FFI. A few APIs have been implemented (such as printing to stdout) but most have not: for example, Miri - currently does not support concurrency, or SIMD, or networking. + currently does not support SIMD or networking. +* Miri currently does not check for data-races and other concurrency related + issues. [rust]: https://www.rust-lang.org/ [mir]: https://github.com/rust-lang/rfcs/blob/master/text/1211-mir.md diff --git a/src/shims/foreign_items/posix.rs b/src/shims/foreign_items/posix.rs index 47b661061d690..878ab8896ddac 100644 --- a/src/shims/foreign_items/posix.rs +++ b/src/shims/foreign_items/posix.rs @@ -316,6 +316,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Threading "pthread_create" => { + println!("WARNING: The thread support is experimental. \ + For example, Miri does not detect data races yet."); assert_eq!(args.len(), 4); let func = args[2]; let fn_ptr = this.read_scalar(func)?.not_undef()?; From 8dd8f199cab87584387ff1dbd74430e908e1f1e2 Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Wed, 1 Apr 2020 16:28:33 -0700 Subject: [PATCH 1926/3747] Update to support the updated API. --- src/machine.rs | 9 +++++++-- src/threads.rs | 13 +++++++++---- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/src/machine.rs b/src/machine.rs index 9d1fa9b78c32d..e6fea672c608c 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -464,8 +464,13 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { } } - fn resolve_thread_local_allocation_id(extra: &Self::MemoryExtra, id: AllocId) -> AllocId { - extra.tls.resolve_allocation(id) + #[inline(always)] + fn resolve_maybe_global_alloc( + tcx: ty::query::TyCtxtAt<'tcx>, + extra: &Self::MemoryExtra, + id: AllocId, + ) -> Option> { + extra.tls.resolve_allocation(*tcx, id) } fn init_allocation_extra<'b>( diff --git a/src/threads.rs b/src/threads.rs index 14ee58c2ee3e6..618713e3c3dea 100644 --- a/src/threads.rs +++ b/src/threads.rs @@ -5,9 +5,10 @@ use std::collections::hash_map::Entry; use log::trace; -use rustc_middle::ty; use rustc_data_structures::fx::FxHashMap; use rustc_index::vec::{Idx, IndexVec}; +use rustc_middle::mir; +use rustc_middle::ty; use crate::*; @@ -234,13 +235,17 @@ impl ThreadLocalStorage { } /// For thread local allocation identifier `alloc_id`, retrieve the original /// static allocation identifier from which it was created. - pub fn resolve_allocation(&self, alloc_id: AllocId) -> AllocId { + pub fn resolve_allocation<'tcx>( + &self, + tcx: ty::TyCtxt<'tcx>, + alloc_id: AllocId, + ) -> Option> { trace!("resolve_allocation(alloc_id: {:?})", alloc_id); if let Some(original_id) = self.thread_local_origin.borrow().get(&alloc_id) { trace!("resolve_allocation(alloc_id: {:?}) -> {:?}", alloc_id, original_id); - *original_id + tcx.alloc_map.lock().get(*original_id) } else { - alloc_id + tcx.alloc_map.lock().get(alloc_id) } } /// Set which thread is currently active. From 92946b5a9cc52bfef2338b2075cec85561652449 Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Wed, 1 Apr 2020 16:28:53 -0700 Subject: [PATCH 1927/3747] Add a test for thread locals. --- tests/run-pass/concurrency/thread_locals.rs | 48 +++++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 tests/run-pass/concurrency/thread_locals.rs diff --git a/tests/run-pass/concurrency/thread_locals.rs b/tests/run-pass/concurrency/thread_locals.rs new file mode 100644 index 0000000000000..d0d25ba7f70cb --- /dev/null +++ b/tests/run-pass/concurrency/thread_locals.rs @@ -0,0 +1,48 @@ +#![feature(thread_local)] + +use std::thread; + +#[thread_local] +static mut A: u8 = 0; +#[thread_local] +static mut B: u8 = 0; +static mut C: u8 = 0; + +unsafe fn get_a_ref() -> *mut u8 { + &mut A +} + +fn main() { + + unsafe { + let x = get_a_ref(); + *x = 5; + assert_eq!(A, 5); + B = 15; + C = 25; + } + + thread::spawn(|| { + unsafe { + assert_eq!(A, 0); + assert_eq!(B, 0); + assert_eq!(C, 25); + B = 14; + C = 24; + let y = get_a_ref(); + assert_eq!(*y, 0); + *y = 4; + assert_eq!(A, 4); + assert_eq!(*get_a_ref(), 4); + + } + }).join().unwrap(); + + unsafe { + assert_eq!(*get_a_ref(), 5); + assert_eq!(A, 5); + assert_eq!(B, 15); + assert_eq!(C, 24); + } + +} \ No newline at end of file From aef4c955995468d7efec81b951a1414bd3278a23 Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Fri, 3 Apr 2020 16:09:42 -0700 Subject: [PATCH 1928/3747] Fix the problem of sending pointed to thread local statics. Add a regression test. --- src/machine.rs | 23 +++++++++++++++++++ tests/run-pass/concurrency/simple.stdout | 10 ++++++++ tests/run-pass/concurrency/thread_locals.rs | 16 +++++++++---- .../run-pass/concurrency/thread_locals.stdout | 1 + 4 files changed, 46 insertions(+), 4 deletions(-) create mode 100644 tests/run-pass/concurrency/simple.stdout create mode 100644 tests/run-pass/concurrency/thread_locals.stdout diff --git a/src/machine.rs b/src/machine.rs index e6fea672c608c..7ed5f1e5539f1 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -433,6 +433,29 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { Ok(()) } + fn access_local( + ecx: &InterpCx<'mir, 'tcx, Self>, + frame: &Frame<'mir, 'tcx, Self::PointerTag, Self::FrameExtra>, + local: mir::Local, + ) -> InterpResult<'tcx, Operand> { + match frame.body.local_decls[local].local_info { + mir::LocalInfo::StaticRef { def_id, is_thread_local: true } => { + let static_alloc_id = ecx.tcx.alloc_map.lock().create_static_alloc(def_id); + let alloc_id = ecx.memory.extra.tls.get_or_register_allocation(*ecx.memory.tcx, static_alloc_id); + let tag = Self::tag_global_base_pointer(&ecx.memory.extra, alloc_id); + let pointer: Pointer = alloc_id.into(); + let pointer = pointer.with_tag(tag); + let scalar: Scalar<_> = pointer.into(); + let scalar: ScalarMaybeUndef<_> = scalar.into(); + let immediate: Immediate<_> = scalar.into(); + Ok( + Operand::Immediate(immediate) + ) + }, + _ => frame.locals[local].access(), + } + } + fn canonical_alloc_id(mem: &Memory<'mir, 'tcx, Self>, id: AllocId) -> AllocId { let tcx = mem.tcx; let alloc = tcx.alloc_map.lock().get(id); diff --git a/tests/run-pass/concurrency/simple.stdout b/tests/run-pass/concurrency/simple.stdout new file mode 100644 index 0000000000000..0506b7bdf83c0 --- /dev/null +++ b/tests/run-pass/concurrency/simple.stdout @@ -0,0 +1,10 @@ +WARNING: The thread support is experimental. For example, Miri does not detect data races yet. +WARNING: The thread support is experimental. For example, Miri does not detect data races yet. +WARNING: The thread support is experimental. For example, Miri does not detect data races yet. +WARNING: The thread support is experimental. For example, Miri does not detect data races yet. +WARNING: The thread support is experimental. For example, Miri does not detect data races yet. +WARNING: The thread support is experimental. For example, Miri does not detect data races yet. +WARNING: The thread support is experimental. For example, Miri does not detect data races yet. +WARNING: The thread support is experimental. For example, Miri does not detect data races yet. +WARNING: The thread support is experimental. For example, Miri does not detect data races yet. +WARNING: The thread support is experimental. For example, Miri does not detect data races yet. diff --git a/tests/run-pass/concurrency/thread_locals.rs b/tests/run-pass/concurrency/thread_locals.rs index d0d25ba7f70cb..1c268a4ff874a 100644 --- a/tests/run-pass/concurrency/thread_locals.rs +++ b/tests/run-pass/concurrency/thread_locals.rs @@ -12,18 +12,24 @@ unsafe fn get_a_ref() -> *mut u8 { &mut A } +struct Sender(*mut u8); + +unsafe impl Send for Sender {} + fn main() { - unsafe { + let ptr = unsafe { let x = get_a_ref(); *x = 5; assert_eq!(A, 5); B = 15; C = 25; - } + Sender(&mut A) + }; - thread::spawn(|| { + thread::spawn(move || { unsafe { + assert_eq!(*ptr.0, 5); assert_eq!(A, 0); assert_eq!(B, 0); assert_eq!(C, 25); @@ -32,6 +38,7 @@ fn main() { let y = get_a_ref(); assert_eq!(*y, 0); *y = 4; + assert_eq!(*ptr.0, 5); assert_eq!(A, 4); assert_eq!(*get_a_ref(), 4); @@ -45,4 +52,5 @@ fn main() { assert_eq!(C, 24); } -} \ No newline at end of file +} + diff --git a/tests/run-pass/concurrency/thread_locals.stdout b/tests/run-pass/concurrency/thread_locals.stdout new file mode 100644 index 0000000000000..9a53b4a5c913b --- /dev/null +++ b/tests/run-pass/concurrency/thread_locals.stdout @@ -0,0 +1 @@ +WARNING: The thread support is experimental. For example, Miri does not detect data races yet. From 1f33f04fd453a63a88cb25771466c2618b46d372 Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Mon, 6 Apr 2020 13:44:47 -0700 Subject: [PATCH 1929/3747] Move pthread_create and related shims to a separate file. --- src/lib.rs | 1 + src/shims/foreign_items/posix.rs | 62 +++-------------------- src/shims/mod.rs | 1 + src/shims/threads.rs | 84 ++++++++++++++++++++++++++++++++ src/threads.rs | 4 -- 5 files changed, 93 insertions(+), 59 deletions(-) create mode 100644 src/shims/threads.rs diff --git a/src/lib.rs b/src/lib.rs index c042526be64c1..d8b3397c8e9ba 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -42,6 +42,7 @@ pub use crate::shims::intrinsics::EvalContextExt as IntrinsicsEvalContextExt; pub use crate::shims::os_str::EvalContextExt as OsStrEvalContextExt; pub use crate::shims::panic::{CatchUnwindData, EvalContextExt as PanicEvalContextExt}; pub use crate::shims::sync::{EvalContextExt as SyncEvalContextExt}; +pub use crate::shims::threads::EvalContextExt as ThreadShimsEvalContextExt; pub use crate::shims::time::EvalContextExt as TimeEvalContextExt; pub use crate::shims::tls::{EvalContextExt as TlsEvalContextExt, TlsData}; pub use crate::shims::EvalContextExt as ShimsEvalContextExt; diff --git a/src/shims/foreign_items/posix.rs b/src/shims/foreign_items/posix.rs index 878ab8896ddac..7d2cb16afee42 100644 --- a/src/shims/foreign_items/posix.rs +++ b/src/shims/foreign_items/posix.rs @@ -6,7 +6,6 @@ use std::convert::TryFrom; use log::trace; use crate::*; -use rustc_index::vec::Idx; use rustc_middle::mir; use rustc_target::abi::{Align, LayoutOf, Size}; @@ -316,66 +315,19 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Threading "pthread_create" => { - println!("WARNING: The thread support is experimental. \ - For example, Miri does not detect data races yet."); assert_eq!(args.len(), 4); - let func = args[2]; - let fn_ptr = this.read_scalar(func)?.not_undef()?; - let fn_val = this.memory.get_fn(fn_ptr)?; - let instance = match fn_val { - rustc_mir::interpret::FnVal::Instance(instance) => instance, - _ => unreachable!(), - }; - let thread_info_place = this.deref_operand(args[0])?; - let thread_info_type = args[0].layout.ty - .builtin_deref(true) - .ok_or_else(|| err_ub_format!( - "wrong signature used for `pthread_create`: first argument must be a raw pointer." - ))? - .ty; - let thread_info_layout = this.layout_of(thread_info_type)?; - let func_arg = match *args[3] { - rustc_mir::interpret::Operand::Immediate(immediate) => immediate, - _ => unreachable!(), - }; - let func_args = [func_arg]; - let ret_place = - this.allocate(this.layout_of(this.tcx.types.usize)?, MiriMemoryKind::Machine.into()); - let new_thread_id = this.create_thread()?; - let old_thread_id = this.set_active_thread(new_thread_id)?; - this.call_function( - instance, - &func_args[..], - Some(ret_place.into()), - StackPopCleanup::None { cleanup: true }, - )?; - this.set_active_thread(old_thread_id)?; - this.write_scalar( - Scalar::from_uint(new_thread_id.index() as u128, thread_info_layout.size), - thread_info_place.into(), - )?; - - // Return success (`0`). - this.write_null(dest)?; + let result = this.pthread_create(args[0], args[1], args[2], args[3])?; + this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_join" => { assert_eq!(args.len(), 2); - assert!( - this.is_null(this.read_scalar(args[1])?.not_undef()?)?, - "Miri supports pthread_join only with retval==NULL" - ); - let thread = this.read_scalar(args[0])?.not_undef()?.to_machine_usize(this)?; - this.join_thread(thread.into())?; - - // Return success (`0`). - this.write_null(dest)?; + let result = this.pthread_join(args[0], args[1])?; + this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_detach" => { - let thread = this.read_scalar(args[0])?.not_undef()?.to_machine_usize(this)?; - this.detach_thread(thread.into())?; - - // Return success (`0`). - this.write_null(dest)?; + assert_eq!(args.len(), 1); + let result = this.pthread_detach(args[0])?; + this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_attr_getguardsize" => { diff --git a/src/shims/mod.rs b/src/shims/mod.rs index 71ff6024ec6fe..118058dd32e74 100644 --- a/src/shims/mod.rs +++ b/src/shims/mod.rs @@ -6,6 +6,7 @@ pub mod intrinsics; pub mod os_str; pub mod panic; pub mod sync; +pub mod threads; pub mod time; pub mod tls; diff --git a/src/shims/threads.rs b/src/shims/threads.rs new file mode 100644 index 0000000000000..6e1087dd81d86 --- /dev/null +++ b/src/shims/threads.rs @@ -0,0 +1,84 @@ +use crate::*; +use rustc_index::vec::Idx; +use rustc_target::abi::LayoutOf; + +impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} +pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { + fn pthread_create( + &mut self, + thread: OpTy<'tcx, Tag>, + _attr: OpTy<'tcx, Tag>, + start_routine: OpTy<'tcx, Tag>, + arg: OpTy<'tcx, Tag>, + ) -> InterpResult<'tcx, i32> { + println!( + "WARNING: The thread support is experimental. \ + For example, Miri does not detect data races yet." + ); + + let this = self.eval_context_mut(); + + let new_thread_id = this.create_thread()?; + let old_thread_id = this.set_active_thread(new_thread_id)?; + + let thread_info_place = this.deref_operand(thread)?; + let thread_info_type = thread.layout.ty + .builtin_deref(true) + .ok_or_else(|| err_ub_format!( + "wrong signature used for `pthread_create`: first argument must be a raw pointer." + ))? + .ty; + let thread_info_layout = this.layout_of(thread_info_type)?; + this.write_scalar( + Scalar::from_uint(new_thread_id.index() as u128, thread_info_layout.size), + thread_info_place.into(), + )?; + + let fn_ptr = this.read_scalar(start_routine)?.not_undef()?; + let instance = this.memory.get_fn(fn_ptr)?.as_instance()?; + + let func_arg = match *arg { + rustc_mir::interpret::Operand::Immediate(immediate) => immediate, + _ => unreachable!(), + }; + let func_args = [func_arg]; + + let ret_place = + this.allocate(this.layout_of(this.tcx.types.usize)?, MiriMemoryKind::Machine.into()); + + this.call_function( + instance, + &func_args[..], + Some(ret_place.into()), + StackPopCleanup::None { cleanup: true }, + )?; + + this.set_active_thread(old_thread_id)?; + + Ok(0) + } + fn pthread_join( + &mut self, + thread: OpTy<'tcx, Tag>, + retval: OpTy<'tcx, Tag>, + ) -> InterpResult<'tcx, i32> { + let this = self.eval_context_mut(); + + if !this.is_null(this.read_scalar(retval)?.not_undef()?)? { + throw_unsup_format!("Miri supports pthread_join only with retval==NULL"); + } + + let thread_id = this.read_scalar(thread)?.not_undef()?.to_machine_usize(this)?; + this.join_thread(thread_id.into())?; + + Ok(0) + } + fn pthread_detach(&mut self, thread: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + let this = self.eval_context_mut(); + + let thread_id = this.read_scalar(thread)?.not_undef()?.to_machine_usize(this)?; + this.detach_thread(thread_id.into())?; + + Ok(0) + } +} diff --git a/src/threads.rs b/src/threads.rs index 618713e3c3dea..9d982359bfbb1 100644 --- a/src/threads.rs +++ b/src/threads.rs @@ -91,9 +91,6 @@ pub struct ThreadSet<'mir, 'tcx> { /// /// Note that this vector also contains terminated threads. threads: IndexVec>, - - /// List of threads that just terminated. TODO: Cleanup. - terminated_threads: Vec, } impl<'mir, 'tcx> Default for ThreadSet<'mir, 'tcx> { @@ -103,7 +100,6 @@ impl<'mir, 'tcx> Default for ThreadSet<'mir, 'tcx> { Self { active_thread: ThreadId::new(0), threads: threads, - terminated_threads: Default::default(), } } } From ed9c7d168b0ded92e4bfb53acd2f71b61b54e306 Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Mon, 6 Apr 2020 14:00:45 -0700 Subject: [PATCH 1930/3747] Report that we do not support foreign thread local statics. --- src/machine.rs | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/machine.rs b/src/machine.rs index 7ed5f1e5539f1..2f0aa91575353 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -14,6 +14,7 @@ use rand::rngs::StdRng; use rustc_ast::attr; use rustc_data_structures::fx::FxHashMap; use rustc_middle::{ + middle::codegen_fn_attrs::CodegenFnAttrFlags, mir, ty::{ self, @@ -21,7 +22,7 @@ use rustc_middle::{ TyCtxt, }, }; -use rustc_span::symbol::{sym, Symbol}; +use rustc_span::{def_id::DefId, symbol::{sym, Symbol}}; use rustc_target::abi::{LayoutOf, Size}; use crate::*; @@ -459,8 +460,14 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { fn canonical_alloc_id(mem: &Memory<'mir, 'tcx, Self>, id: AllocId) -> AllocId { let tcx = mem.tcx; let alloc = tcx.alloc_map.lock().get(id); + fn is_thread_local<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> bool { + tcx.codegen_fn_attrs(def_id).flags.contains(CodegenFnAttrFlags::THREAD_LOCAL) + } match alloc { Some(GlobalAlloc::Static(def_id)) if tcx.is_foreign_item(def_id) => { + if is_thread_local(*tcx, def_id) { + unimplemented!("Foreign thread local statics are not supported yet."); + } // Figure out if this is an extern static, and if yes, which one. let attrs = tcx.get_attrs(def_id); let link_name = match attr::first_attr_value_str_by_name(&attrs, sym::link_name) { @@ -476,7 +483,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { id } }, - Some(GlobalAlloc::Static(def_id)) if tcx.has_attr(def_id, sym::thread_local) => { + Some(GlobalAlloc::Static(def_id)) if is_thread_local(*tcx, def_id) => { // We have a thread local, so we need to get a unique allocation id for it. mem.extra.tls.get_or_register_allocation(*tcx, id) }, From 52184193c363e030818a18a60123eed25b12c7c9 Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Mon, 6 Apr 2020 14:41:05 -0700 Subject: [PATCH 1931/3747] Fix comments in TLS. --- src/machine.rs | 2 +- src/shims/tls.rs | 8 +++++--- src/threads.rs | 13 +++++-------- 3 files changed, 11 insertions(+), 12 deletions(-) diff --git a/src/machine.rs b/src/machine.rs index 2f0aa91575353..a7d62897b8f01 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -27,7 +27,7 @@ use rustc_target::abi::{LayoutOf, Size}; use crate::*; -pub use crate::threads::{ThreadId, ThreadSet, ThreadLocalStorage}; +pub use crate::threads::{ThreadId, ThreadSet, ThreadState, ThreadLocalStorage}; // Some global facts about the emulated machine. pub const PAGE_SIZE: u64 = 4 * 1024; // FIXME: adjust to target architecture diff --git a/src/shims/tls.rs b/src/shims/tls.rs index d16acb7500370..ec8c31fe2c127 100644 --- a/src/shims/tls.rs +++ b/src/shims/tls.rs @@ -9,7 +9,7 @@ use rustc_middle::ty; use rustc_target::abi::{Size, HasDataLayout}; use crate::{HelpersEvalContextExt, ThreadsEvalContextExt, InterpResult, MPlaceTy, Scalar, StackPopCleanup, Tag}; -use crate::machine::ThreadId; +use crate::machine::{ThreadId, ThreadState}; pub type TlsKey = u128; @@ -174,7 +174,7 @@ impl<'tcx> TlsData<'tcx> { impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { - /// Run TLS destructors for the currently active thread. + /// Run TLS destructors for all threads. fn run_tls_dtors(&mut self) -> InterpResult<'tcx> { let this = self.eval_context_mut(); assert!(!this.machine.tls.dtors_running, "running TLS dtors twice"); @@ -223,7 +223,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // Now run the "keyed" destructors. - for thread_id in this.get_all_thread_ids() { + for (thread_id, thread_state) in this.get_all_thread_ids_with_states() { + assert!(thread_state == ThreadState::Terminated, + "TLS destructors should be executed after all threads terminated."); this.set_active_thread(thread_id)?; let mut dtor = this.machine.tls.fetch_tls_dtor(None, thread_id); while let Some((instance, thread_id, ptr, key)) = dtor { diff --git a/src/threads.rs b/src/threads.rs index 9d982359bfbb1..4458f4410e4c7 100644 --- a/src/threads.rs +++ b/src/threads.rs @@ -97,10 +97,7 @@ impl<'mir, 'tcx> Default for ThreadSet<'mir, 'tcx> { fn default() -> Self { let mut threads = IndexVec::new(); threads.push(Default::default()); - Self { - active_thread: ThreadId::new(0), - threads: threads, - } + Self { active_thread: ThreadId::new(0), threads: threads } } } @@ -156,8 +153,8 @@ impl<'mir, 'tcx: 'mir> ThreadSet<'mir, 'tcx> { } } /// Get ids of all threads ever allocated. - fn get_all_thread_ids(&mut self) -> Vec { - (0..self.threads.len()).map(ThreadId::new).collect() + fn get_all_thread_ids_with_states(&self) -> Vec<(ThreadId, ThreadState)> { + self.threads.iter_enumerated().map(|(id, thread)| (id, thread.state)).collect() } /// Decide which thread to run next. /// @@ -283,9 +280,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); this.machine.threads.active_thread_stack_mut() } - fn get_all_thread_ids(&mut self) -> Vec { + fn get_all_thread_ids_with_states(&mut self) -> Vec<(ThreadId, ThreadState)> { let this = self.eval_context_mut(); - this.machine.threads.get_all_thread_ids() + this.machine.threads.get_all_thread_ids_with_states() } /// Decide which thread to run next. /// From f21197f081048e383ff10427216db7867b746832 Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Mon, 6 Apr 2020 16:12:13 -0700 Subject: [PATCH 1932/3747] Store the thread name. --- src/shims/foreign_items/posix.rs | 13 +++++-------- src/shims/threads.rs | 20 ++++++++++++++++++++ src/threads.rs | 26 ++++++++++++++++++++------ 3 files changed, 45 insertions(+), 14 deletions(-) diff --git a/src/shims/foreign_items/posix.rs b/src/shims/foreign_items/posix.rs index 7d2cb16afee42..4e08593d61c34 100644 --- a/src/shims/foreign_items/posix.rs +++ b/src/shims/foreign_items/posix.rs @@ -329,6 +329,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let result = this.pthread_detach(args[0])?; this.write_scalar(Scalar::from_i32(result), dest)?; } + "prctl" => { + assert_eq!(args.len(), 5); + let result = this.prctl(args[0], args[1], args[2], args[3], args[4])?; + this.write_scalar(Scalar::from_i32(result), dest)?; + } "pthread_attr_getguardsize" => { assert_eq!(args.len(), 2); @@ -347,14 +352,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_null(dest)?; } - "prctl" => { - let option = this.read_scalar(args[0])?.not_undef()?.to_i32()?; - assert_eq!(option, 0xf, "Miri supports only PR_SET_NAME"); - - // Return success (`0`). - this.write_null(dest)?; - } - // Incomplete shims that we "stub out" just to get pre-main initialziation code to work. // These shims are enabled only when the caller is in the standard library. | "pthread_attr_init" diff --git a/src/shims/threads.rs b/src/shims/threads.rs index 6e1087dd81d86..3a55fb3c706c9 100644 --- a/src/shims/threads.rs +++ b/src/shims/threads.rs @@ -79,6 +79,26 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let thread_id = this.read_scalar(thread)?.not_undef()?.to_machine_usize(this)?; this.detach_thread(thread_id.into())?; + Ok(0) + } + fn prctl( + &mut self, + option: OpTy<'tcx, Tag>, + arg2: OpTy<'tcx, Tag>, + _arg3: OpTy<'tcx, Tag>, + _arg4: OpTy<'tcx, Tag>, + _arg5: OpTy<'tcx, Tag>, + ) -> InterpResult<'tcx, i32> { + let this = self.eval_context_mut(); + + let option = this.read_scalar(option)?.not_undef()?.to_i32()?; + if option != this.eval_libc_i32("PR_SET_NAME")? { + throw_unsup_format!("Miri supports only PR_SET_NAME"); + } + let address = this.read_scalar(arg2)?.not_undef()?; + let name = this.memory.read_c_str(address)?.to_owned(); + this.set_active_thread_name(name)?; + Ok(0) } } diff --git a/src/threads.rs b/src/threads.rs index 4458f4410e4c7..4ce35d50abc35 100644 --- a/src/threads.rs +++ b/src/threads.rs @@ -47,6 +47,8 @@ pub enum ThreadState { /// A thread. pub struct Thread<'mir, 'tcx> { state: ThreadState, + /// Name of the thread. + thread_name: Option>, /// The virtual call stack. stack: Vec>>, /// Is the thread detached? @@ -78,7 +80,7 @@ impl<'mir, 'tcx> std::fmt::Debug for Thread<'mir, 'tcx> { impl<'mir, 'tcx> Default for Thread<'mir, 'tcx> { fn default() -> Self { - Self { state: ThreadState::Enabled, stack: Vec::new(), detached: false } + Self { state: ThreadState::Enabled, thread_name: None, stack: Vec::new(), detached: false } } } @@ -117,16 +119,20 @@ impl<'mir, 'tcx: 'mir> ThreadSet<'mir, 'tcx> { new_thread_id } /// Set an active thread and return the id of the thread that was active before. - fn set_active_thread(&mut self, id: ThreadId) -> ThreadId { + fn set_active_thread_id(&mut self, id: ThreadId) -> ThreadId { let active_thread_id = self.active_thread; self.active_thread = id; assert!(self.active_thread.index() < self.threads.len()); active_thread_id } /// Get the id of the currently active thread. - fn get_active_thread(&self) -> ThreadId { + fn get_active_thread_id(&self) -> ThreadId { self.active_thread } + /// Get the borrow of the currently active thread. + fn active_thread_mut(&mut self) -> &mut Thread<'mir, 'tcx> { + &mut self.threads[self.active_thread] + } /// Mark the thread as detached, which means that no other thread will try /// to join it and the thread is responsible for cleaning up. fn detach_thread(&mut self, id: ThreadId) { @@ -152,6 +158,10 @@ impl<'mir, 'tcx: 'mir> ThreadSet<'mir, 'tcx> { ); } } + /// Set the name of the active thread. + fn set_thread_name(&mut self, new_thread_name: Vec) { + self.active_thread_mut().thread_name = Some(new_thread_name); + } /// Get ids of all threads ever allocated. fn get_all_thread_ids_with_states(&self) -> Vec<(ThreadId, ThreadState)> { self.threads.iter_enumerated().map(|(id, thread)| (id, thread.state)).collect() @@ -266,11 +276,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn set_active_thread(&mut self, thread_id: ThreadId) -> InterpResult<'tcx, ThreadId> { let this = self.eval_context_mut(); this.memory.extra.tls.set_active_thread(thread_id); - Ok(this.machine.threads.set_active_thread(thread_id)) + Ok(this.machine.threads.set_active_thread_id(thread_id)) } fn get_active_thread(&self) -> InterpResult<'tcx, ThreadId> { let this = self.eval_context_ref(); - Ok(this.machine.threads.get_active_thread()) + Ok(this.machine.threads.get_active_thread_id()) } fn active_thread_stack(&self) -> &[Frame<'mir, 'tcx, Tag, FrameData<'tcx>>] { let this = self.eval_context_ref(); @@ -280,6 +290,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); this.machine.threads.active_thread_stack_mut() } + fn set_active_thread_name(&mut self, new_thread_name: Vec) -> InterpResult<'tcx, ()> { + let this = self.eval_context_mut(); + Ok(this.machine.threads.set_thread_name(new_thread_name)) + } fn get_all_thread_ids_with_states(&mut self) -> Vec<(ThreadId, ThreadState)> { let this = self.eval_context_mut(); this.machine.threads.get_all_thread_ids_with_states() @@ -291,7 +305,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); // Find the next thread to run. if this.machine.threads.schedule()? { - let active_thread = this.machine.threads.get_active_thread(); + let active_thread = this.machine.threads.get_active_thread_id(); this.memory.extra.tls.set_active_thread(active_thread); Ok(true) } else { From b04bf8a51480c05fc9984476a78f07b927f2672f Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Mon, 6 Apr 2020 16:12:25 -0700 Subject: [PATCH 1933/3747] Rustfmt the test. --- tests/run-pass/concurrency/thread_locals.rs | 38 +++++++++------------ 1 file changed, 17 insertions(+), 21 deletions(-) diff --git a/tests/run-pass/concurrency/thread_locals.rs b/tests/run-pass/concurrency/thread_locals.rs index 1c268a4ff874a..50aa6fee2f876 100644 --- a/tests/run-pass/concurrency/thread_locals.rs +++ b/tests/run-pass/concurrency/thread_locals.rs @@ -17,7 +17,6 @@ struct Sender(*mut u8); unsafe impl Send for Sender {} fn main() { - let ptr = unsafe { let x = get_a_ref(); *x = 5; @@ -26,24 +25,23 @@ fn main() { C = 25; Sender(&mut A) }; - - thread::spawn(move || { - unsafe { - assert_eq!(*ptr.0, 5); - assert_eq!(A, 0); - assert_eq!(B, 0); - assert_eq!(C, 25); - B = 14; - C = 24; - let y = get_a_ref(); - assert_eq!(*y, 0); - *y = 4; - assert_eq!(*ptr.0, 5); - assert_eq!(A, 4); - assert_eq!(*get_a_ref(), 4); - - } - }).join().unwrap(); + + thread::spawn(move || unsafe { + assert_eq!(*ptr.0, 5); + assert_eq!(A, 0); + assert_eq!(B, 0); + assert_eq!(C, 25); + B = 14; + C = 24; + let y = get_a_ref(); + assert_eq!(*y, 0); + *y = 4; + assert_eq!(*ptr.0, 5); + assert_eq!(A, 4); + assert_eq!(*get_a_ref(), 4); + }) + .join() + .unwrap(); unsafe { assert_eq!(*get_a_ref(), 5); @@ -51,6 +49,4 @@ fn main() { assert_eq!(B, 15); assert_eq!(C, 24); } - } - From 2202278f6af676266034e756bd3848efe4e10ab8 Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Mon, 6 Apr 2020 16:30:30 -0700 Subject: [PATCH 1934/3747] Fix pthread_self. --- src/shims/foreign_items/posix.rs | 5 ++++- src/shims/threads.rs | 6 ++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/shims/foreign_items/posix.rs b/src/shims/foreign_items/posix.rs index 4e08593d61c34..4cd3b84991128 100644 --- a/src/shims/foreign_items/posix.rs +++ b/src/shims/foreign_items/posix.rs @@ -329,6 +329,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let result = this.pthread_detach(args[0])?; this.write_scalar(Scalar::from_i32(result), dest)?; } + "pthread_self" => { + assert_eq!(args.len(), 0); + this.pthread_self(dest)?; + } "prctl" => { assert_eq!(args.len(), 5); let result = this.prctl(args[0], args[1], args[2], args[3], args[4])?; @@ -356,7 +360,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // These shims are enabled only when the caller is in the standard library. | "pthread_attr_init" | "pthread_attr_destroy" - | "pthread_self" | "pthread_attr_setstacksize" | "pthread_condattr_init" | "pthread_condattr_setclock" diff --git a/src/shims/threads.rs b/src/shims/threads.rs index 3a55fb3c706c9..fc733d7f5c9f2 100644 --- a/src/shims/threads.rs +++ b/src/shims/threads.rs @@ -81,6 +81,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(0) } + fn pthread_self(&mut self, dest: PlaceTy<'tcx, Tag>) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + + let thread_id = this.get_active_thread()?; + this.write_scalar(Scalar::from_uint(thread_id.index() as u128, dest.layout.size), dest) + } fn prctl( &mut self, option: OpTy<'tcx, Tag>, From 1c8a59c69189b42b97db49292d0ca198a7d5977a Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Tue, 7 Apr 2020 20:20:41 -0700 Subject: [PATCH 1935/3747] Rebase on PR 1157. --- src/shims/sync.rs | 382 +++++++++++++++++++----- src/threads.rs | 81 ++++- tests/run-pass/concurrency/locks.rs | 29 ++ tests/run-pass/concurrency/locks.stdout | 3 + 4 files changed, 415 insertions(+), 80 deletions(-) create mode 100644 tests/run-pass/concurrency/locks.rs create mode 100644 tests/run-pass/concurrency/locks.stdout diff --git a/src/shims/sync.rs b/src/shims/sync.rs index b03dcbfd8969a..eb54358114348 100644 --- a/src/shims/sync.rs +++ b/src/shims/sync.rs @@ -2,6 +2,7 @@ use rustc_middle::ty::{TyKind, TypeAndMut}; use rustc_target::abi::{LayoutOf, Size}; use crate::stacked_borrows::Tag; +use crate::threads::{BlockSetId, ThreadId}; use crate::*; fn assert_ptr_target_min_size<'mir, 'tcx: 'mir>( @@ -55,15 +56,17 @@ fn mutexattr_set_kind<'mir, 'tcx: 'mir>( // bytes 0-3: reserved for signature on macOS // (need to avoid this because it is set by static initializer macros) // bytes 4-7: count of how many times this mutex has been locked, as a u32 +// bytes 8-11: when count > 0, id of the owner thread as a u32 // bytes 12-15 or 16-19 (depending on platform): mutex kind, as an i32 // (the kind has to be at its offset for compatibility with static initializer macros) +// bytes 20-23: when count > 0, id of the blockset in which the blocked threads are waiting. fn mutex_get_locked_count<'mir, 'tcx: 'mir>( ecx: &MiriEvalContext<'mir, 'tcx>, mutex_op: OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, ScalarMaybeUndef> { // Ensure that the following read at an offset to the mutex pointer is within bounds - assert_ptr_target_min_size(ecx, mutex_op, 20)?; + assert_ptr_target_min_size(ecx, mutex_op, 24)?; let mutex_place = ecx.deref_operand(mutex_op)?; let locked_count_place = mutex_place.offset( Size::from_bytes(4), @@ -80,7 +83,7 @@ fn mutex_set_locked_count<'mir, 'tcx: 'mir>( locked_count: impl Into>, ) -> InterpResult<'tcx, ()> { // Ensure that the following write at an offset to the mutex pointer is within bounds - assert_ptr_target_min_size(ecx, mutex_op, 20)?; + assert_ptr_target_min_size(ecx, mutex_op, 24)?; let mutex_place = ecx.deref_operand(mutex_op)?; let locked_count_place = mutex_place.offset( Size::from_bytes(4), @@ -91,12 +94,45 @@ fn mutex_set_locked_count<'mir, 'tcx: 'mir>( ecx.write_scalar(locked_count.into(), locked_count_place.into()) } +fn mutex_get_owner<'mir, 'tcx: 'mir>( + ecx: &MiriEvalContext<'mir, 'tcx>, + mutex_op: OpTy<'tcx, Tag>, +) -> InterpResult<'tcx, ScalarMaybeUndef> { + // Ensure that the following read at an offset to the mutex pointer is within bounds + assert_ptr_target_min_size(ecx, mutex_op, 24)?; + let mutex_place = ecx.deref_operand(mutex_op)?; + let mutex_id_place = mutex_place.offset( + Size::from_bytes(8), + MemPlaceMeta::None, + ecx.machine.layouts.u32, + ecx, + )?; + ecx.read_scalar(mutex_id_place.into()) +} + +fn mutex_set_owner<'mir, 'tcx: 'mir>( + ecx: &mut MiriEvalContext<'mir, 'tcx>, + mutex_op: OpTy<'tcx, Tag>, + mutex_id: impl Into>, +) -> InterpResult<'tcx, ()> { + // Ensure that the following write at an offset to the mutex pointer is within bounds + assert_ptr_target_min_size(ecx, mutex_op, 24)?; + let mutex_place = ecx.deref_operand(mutex_op)?; + let mutex_id_place = mutex_place.offset( + Size::from_bytes(8), + MemPlaceMeta::None, + ecx.machine.layouts.u32, + ecx, + )?; + ecx.write_scalar(mutex_id.into(), mutex_id_place.into()) +} + fn mutex_get_kind<'mir, 'tcx: 'mir>( ecx: &mut MiriEvalContext<'mir, 'tcx>, mutex_op: OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, ScalarMaybeUndef> { // Ensure that the following read at an offset to the mutex pointer is within bounds - assert_ptr_target_min_size(ecx, mutex_op, 20)?; + assert_ptr_target_min_size(ecx, mutex_op, 24)?; let mutex_place = ecx.deref_operand(mutex_op)?; let kind_offset = if ecx.pointer_size().bytes() == 8 { 16 } else { 12 }; let kind_place = mutex_place.offset( @@ -114,7 +150,7 @@ fn mutex_set_kind<'mir, 'tcx: 'mir>( kind: impl Into>, ) -> InterpResult<'tcx, ()> { // Ensure that the following write at an offset to the mutex pointer is within bounds - assert_ptr_target_min_size(ecx, mutex_op, 20)?; + assert_ptr_target_min_size(ecx, mutex_op, 24)?; let mutex_place = ecx.deref_operand(mutex_op)?; let kind_offset = if ecx.pointer_size().bytes() == 8 { 16 } else { 12 }; let kind_place = mutex_place.offset( @@ -126,6 +162,55 @@ fn mutex_set_kind<'mir, 'tcx: 'mir>( ecx.write_scalar(kind.into(), kind_place.into()) } +fn mutex_get_blockset<'mir, 'tcx: 'mir>( + ecx: &MiriEvalContext<'mir, 'tcx>, + mutex_op: OpTy<'tcx, Tag>, +) -> InterpResult<'tcx, ScalarMaybeUndef> { + // Ensure that the following read at an offset to the mutex pointer is within bounds + assert_ptr_target_min_size(ecx, mutex_op, 24)?; + let mutex_place = ecx.deref_operand(mutex_op)?; + let mutex_id_place = mutex_place.offset( + Size::from_bytes(20), + MemPlaceMeta::None, + ecx.machine.layouts.u32, + ecx, + )?; + ecx.read_scalar(mutex_id_place.into()) +} + +fn mutex_set_blockset<'mir, 'tcx: 'mir>( + ecx: &mut MiriEvalContext<'mir, 'tcx>, + mutex_op: OpTy<'tcx, Tag>, + mutex_id: impl Into>, +) -> InterpResult<'tcx, ()> { + // Ensure that the following write at an offset to the mutex pointer is within bounds + assert_ptr_target_min_size(ecx, mutex_op, 24)?; + let mutex_place = ecx.deref_operand(mutex_op)?; + let mutex_id_place = mutex_place.offset( + Size::from_bytes(20), + MemPlaceMeta::None, + ecx.machine.layouts.u32, + ecx, + )?; + ecx.write_scalar(mutex_id.into(), mutex_id_place.into()) +} + +fn mutex_get_or_create_blockset<'mir, 'tcx: 'mir>( + ecx: &mut MiriEvalContext<'mir, 'tcx>, + mutex_op: OpTy<'tcx, Tag>, +) -> InterpResult<'tcx, BlockSetId> { + let blockset = mutex_get_blockset(ecx, mutex_op)?.to_u32()?; + if blockset == 0 { + // 0 is a default value and also not a valid blockset id. Need to + // allocate a new blockset. + let blockset = ecx.create_blockset()?; + mutex_set_blockset(ecx, mutex_op, blockset.to_u32_scalar())?; + Ok(blockset) + } else { + Ok(blockset.into()) + } +} + // pthread_rwlock_t is between 32 and 56 bytes, depending on the platform. // Our chosen memory layout for the emulated rwlock (does not have to match the platform layout!): @@ -133,13 +218,17 @@ fn mutex_set_kind<'mir, 'tcx: 'mir>( // (need to avoid this because it is set by static initializer macros) // bytes 4-7: reader count, as a u32 // bytes 8-11: writer count, as a u32 +// bytes 12-15: when writer or reader count > 0, id of the blockset in which the +// blocked writers are waiting. +// bytes 16-20: when writer count > 0, id of the blockset in which the blocked +// readers are waiting. fn rwlock_get_readers<'mir, 'tcx: 'mir>( ecx: &MiriEvalContext<'mir, 'tcx>, rwlock_op: OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, ScalarMaybeUndef> { // Ensure that the following read at an offset to the rwlock pointer is within bounds - assert_ptr_target_min_size(ecx, rwlock_op, 12)?; + assert_ptr_target_min_size(ecx, rwlock_op, 20)?; let rwlock_place = ecx.deref_operand(rwlock_op)?; let readers_place = rwlock_place.offset( Size::from_bytes(4), @@ -156,7 +245,7 @@ fn rwlock_set_readers<'mir, 'tcx: 'mir>( readers: impl Into>, ) -> InterpResult<'tcx, ()> { // Ensure that the following write at an offset to the rwlock pointer is within bounds - assert_ptr_target_min_size(ecx, rwlock_op, 12)?; + assert_ptr_target_min_size(ecx, rwlock_op, 20)?; let rwlock_place = ecx.deref_operand(rwlock_op)?; let readers_place = rwlock_place.offset( Size::from_bytes(4), @@ -172,7 +261,7 @@ fn rwlock_get_writers<'mir, 'tcx: 'mir>( rwlock_op: OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, ScalarMaybeUndef> { // Ensure that the following read at an offset to the rwlock pointer is within bounds - assert_ptr_target_min_size(ecx, rwlock_op, 12)?; + assert_ptr_target_min_size(ecx, rwlock_op, 20)?; let rwlock_place = ecx.deref_operand(rwlock_op)?; let writers_place = rwlock_place.offset( Size::from_bytes(8), @@ -189,7 +278,7 @@ fn rwlock_set_writers<'mir, 'tcx: 'mir>( writers: impl Into>, ) -> InterpResult<'tcx, ()> { // Ensure that the following write at an offset to the rwlock pointer is within bounds - assert_ptr_target_min_size(ecx, rwlock_op, 12)?; + assert_ptr_target_min_size(ecx, rwlock_op, 20)?; let rwlock_place = ecx.deref_operand(rwlock_op)?; let writers_place = rwlock_place.offset( Size::from_bytes(8), @@ -200,6 +289,104 @@ fn rwlock_set_writers<'mir, 'tcx: 'mir>( ecx.write_scalar(writers.into(), writers_place.into()) } +fn rwlock_get_writer_blockset<'mir, 'tcx: 'mir>( + ecx: &MiriEvalContext<'mir, 'tcx>, + rwlock_op: OpTy<'tcx, Tag>, +) -> InterpResult<'tcx, ScalarMaybeUndef> { + // Ensure that the following read at an offset to the rwlock pointer is within bounds + assert_ptr_target_min_size(ecx, rwlock_op, 20)?; + let rwlock_place = ecx.deref_operand(rwlock_op)?; + let blockset_place = rwlock_place.offset( + Size::from_bytes(12), + MemPlaceMeta::None, + ecx.machine.layouts.u32, + ecx, + )?; + ecx.read_scalar(blockset_place.into()) +} + +fn rwlock_set_writer_blockset<'mir, 'tcx: 'mir>( + ecx: &mut MiriEvalContext<'mir, 'tcx>, + rwlock_op: OpTy<'tcx, Tag>, + blockset: impl Into>, +) -> InterpResult<'tcx, ()> { + // Ensure that the following write at an offset to the rwlock pointer is within bounds + assert_ptr_target_min_size(ecx, rwlock_op, 20)?; + let rwlock_place = ecx.deref_operand(rwlock_op)?; + let blockset_place = rwlock_place.offset( + Size::from_bytes(12), + MemPlaceMeta::None, + ecx.machine.layouts.u32, + ecx, + )?; + ecx.write_scalar(blockset.into(), blockset_place.into()) +} + +fn rwlock_get_or_create_writer_blockset<'mir, 'tcx: 'mir>( + ecx: &mut MiriEvalContext<'mir, 'tcx>, + rwlock_op: OpTy<'tcx, Tag>, +) -> InterpResult<'tcx, BlockSetId> { + let blockset = rwlock_get_writer_blockset(ecx, rwlock_op)?.to_u32()?; + if blockset == 0 { + // 0 is a default value and also not a valid blockset id. Need to + // allocate a new blockset. + let blockset = ecx.create_blockset()?; + rwlock_set_writer_blockset(ecx, rwlock_op, blockset.to_u32_scalar())?; + Ok(blockset) + } else { + Ok(blockset.into()) + } +} + +fn rwlock_get_reader_blockset<'mir, 'tcx: 'mir>( + ecx: &MiriEvalContext<'mir, 'tcx>, + rwlock_op: OpTy<'tcx, Tag>, +) -> InterpResult<'tcx, ScalarMaybeUndef> { + // Ensure that the following read at an offset to the rwlock pointer is within bounds + assert_ptr_target_min_size(ecx, rwlock_op, 20)?; + let rwlock_place = ecx.deref_operand(rwlock_op)?; + let blockset_place = rwlock_place.offset( + Size::from_bytes(16), + MemPlaceMeta::None, + ecx.machine.layouts.u32, + ecx, + )?; + ecx.read_scalar(blockset_place.into()) +} + +fn rwlock_set_reader_blockset<'mir, 'tcx: 'mir>( + ecx: &mut MiriEvalContext<'mir, 'tcx>, + rwlock_op: OpTy<'tcx, Tag>, + blockset: impl Into>, +) -> InterpResult<'tcx, ()> { + // Ensure that the following write at an offset to the rwlock pointer is within bounds + assert_ptr_target_min_size(ecx, rwlock_op, 20)?; + let rwlock_place = ecx.deref_operand(rwlock_op)?; + let blockset_place = rwlock_place.offset( + Size::from_bytes(16), + MemPlaceMeta::None, + ecx.machine.layouts.u32, + ecx, + )?; + ecx.write_scalar(blockset.into(), blockset_place.into()) +} + +fn rwlock_get_or_create_reader_blockset<'mir, 'tcx: 'mir>( + ecx: &mut MiriEvalContext<'mir, 'tcx>, + rwlock_op: OpTy<'tcx, Tag>, +) -> InterpResult<'tcx, BlockSetId> { + let blockset = rwlock_get_reader_blockset(ecx, rwlock_op)?.to_u32()?; + if blockset == 0 { + // 0 is a default value and also not a valid blockset id. Need to + // allocate a new blockset. + let blockset = ecx.create_blockset()?; + rwlock_set_reader_blockset(ecx, rwlock_op, blockset.to_u32_scalar())?; + Ok(blockset) + } else { + Ok(blockset.into()) + } +} + impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { fn pthread_mutexattr_init(&mut self, attr_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { @@ -265,31 +452,40 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let kind = mutex_get_kind(this, mutex_op)?.not_undef()?; let locked_count = mutex_get_locked_count(this, mutex_op)?.to_u32()?; + let active_thread = this.get_active_thread()?; - if kind == this.eval_libc("PTHREAD_MUTEX_NORMAL")? { - if locked_count == 0 { - mutex_set_locked_count(this, mutex_op, Scalar::from_u32(1))?; - Ok(0) - } else { - throw_machine_stop!(TerminationInfo::Deadlock); - } - } else if kind == this.eval_libc("PTHREAD_MUTEX_ERRORCHECK")? { - if locked_count == 0 { - mutex_set_locked_count(this, mutex_op, Scalar::from_u32(1))?; + if locked_count == 0 { + // The mutex is unlocked. Let's lock it. + mutex_set_locked_count(this, mutex_op, Scalar::from_u32(1))?; + mutex_set_owner(this, mutex_op, active_thread.to_u32_scalar())?; + Ok(0) + } else { + // The mutex is locked. Let's check by whom. + let owner_thread: ThreadId = + mutex_get_owner(this, mutex_op)?.not_undef()?.to_u32()?.into(); + if owner_thread != active_thread { + // Block the active thread. + let blockset = mutex_get_or_create_blockset(this, mutex_op)?; + this.block_active_thread(blockset)?; Ok(0) } else { - this.eval_libc_i32("EDEADLK") - } - } else if kind == this.eval_libc("PTHREAD_MUTEX_RECURSIVE")? { - match locked_count.checked_add(1) { - Some(new_count) => { - mutex_set_locked_count(this, mutex_op, Scalar::from_u32(new_count))?; - Ok(0) + // Trying to acquire the same mutex again. + if kind == this.eval_libc("PTHREAD_MUTEX_NORMAL")? { + throw_machine_stop!(TerminationInfo::Deadlock); + } else if kind == this.eval_libc("PTHREAD_MUTEX_ERRORCHECK")? { + this.eval_libc_i32("EDEADLK") + } else if kind == this.eval_libc("PTHREAD_MUTEX_RECURSIVE")? { + match locked_count.checked_add(1) { + Some(new_count) => { + mutex_set_locked_count(this, mutex_op, Scalar::from_u32(new_count))?; + Ok(0) + } + None => this.eval_libc_i32("EAGAIN"), + } + } else { + throw_ub_format!("called pthread_mutex_lock on an unsupported type of mutex"); } - None => this.eval_libc_i32("EAGAIN"), } - } else { - throw_ub_format!("called pthread_mutex_lock on an unsupported type of mutex"); } } @@ -298,26 +494,36 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let kind = mutex_get_kind(this, mutex_op)?.not_undef()?; let locked_count = mutex_get_locked_count(this, mutex_op)?.to_u32()?; + let active_thread = this.get_active_thread()?; - if kind == this.eval_libc("PTHREAD_MUTEX_NORMAL")? - || kind == this.eval_libc("PTHREAD_MUTEX_ERRORCHECK")? - { - if locked_count == 0 { - mutex_set_locked_count(this, mutex_op, Scalar::from_u32(1))?; - Ok(0) - } else { + if locked_count == 0 { + // The mutex is unlocked. Let's lock it. + mutex_set_locked_count(this, mutex_op, Scalar::from_u32(1))?; + mutex_set_owner(this, mutex_op, active_thread.to_u32_scalar())?; + Ok(0) + } else { + let owner_thread: ThreadId = mutex_get_owner(this, mutex_op)?.to_u32()?.into(); + if owner_thread != active_thread { this.eval_libc_i32("EBUSY") - } - } else if kind == this.eval_libc("PTHREAD_MUTEX_RECURSIVE")? { - match locked_count.checked_add(1) { - Some(new_count) => { - mutex_set_locked_count(this, mutex_op, Scalar::from_u32(new_count))?; - Ok(0) + } else { + if kind == this.eval_libc("PTHREAD_MUTEX_NORMAL")? + || kind == this.eval_libc("PTHREAD_MUTEX_ERRORCHECK")? + { + this.eval_libc_i32("EBUSY") + } else if kind == this.eval_libc("PTHREAD_MUTEX_RECURSIVE")? { + match locked_count.checked_add(1) { + Some(new_count) => { + mutex_set_locked_count(this, mutex_op, Scalar::from_u32(new_count))?; + Ok(0) + } + None => this.eval_libc_i32("EAGAIN"), + } + } else { + throw_ub_format!( + "called pthread_mutex_trylock on an unsupported type of mutex" + ); } - None => this.eval_libc_i32("EAGAIN"), } - } else { - throw_ub_format!("called pthread_mutex_trylock on an unsupported type of mutex"); } } @@ -326,34 +532,40 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let kind = mutex_get_kind(this, mutex_op)?.not_undef()?; let locked_count = mutex_get_locked_count(this, mutex_op)?.to_u32()?; - - if kind == this.eval_libc("PTHREAD_MUTEX_NORMAL")? { - if locked_count != 0 { - mutex_set_locked_count(this, mutex_op, Scalar::from_u32(0))?; - Ok(0) + let owner_thread: ThreadId = mutex_get_owner(this, mutex_op)?.to_u32()?.into(); + + if owner_thread != this.get_active_thread()? { + throw_ub_format!("called pthread_mutex_unlock on a mutex owned by another thread"); + } else if locked_count == 1 { + let blockset = mutex_get_or_create_blockset(this, mutex_op)?; + if let Some(new_owner) = this.unblock_random_thread(blockset)? { + // We have at least one thread waiting on this mutex. Transfer + // ownership to it. + mutex_set_owner(this, mutex_op, new_owner.to_u32_scalar())?; } else { - throw_ub_format!("unlocked a PTHREAD_MUTEX_NORMAL mutex that was not locked"); - } - } else if kind == this.eval_libc("PTHREAD_MUTEX_ERRORCHECK")? { - if locked_count != 0 { + // No thread is waiting on this mutex. mutex_set_locked_count(this, mutex_op, Scalar::from_u32(0))?; - Ok(0) - } else { - this.eval_libc_i32("EPERM") } - } else if kind == this.eval_libc("PTHREAD_MUTEX_RECURSIVE")? { - match locked_count.checked_sub(1) { - Some(new_count) => { - mutex_set_locked_count(this, mutex_op, Scalar::from_u32(new_count))?; - Ok(0) - } - None => { - // locked_count was already zero - this.eval_libc_i32("EPERM") + Ok(0) + } else { + if kind == this.eval_libc("PTHREAD_MUTEX_NORMAL")? { + throw_ub_format!("unlocked a PTHREAD_MUTEX_NORMAL mutex that was not locked"); + } else if kind == this.eval_libc("PTHREAD_MUTEX_ERRORCHECK")? { + this.eval_libc_i32("EPERM") + } else if kind == this.eval_libc("PTHREAD_MUTEX_RECURSIVE")? { + match locked_count.checked_sub(1) { + Some(new_count) => { + mutex_set_locked_count(this, mutex_op, Scalar::from_u32(new_count))?; + Ok(0) + } + None => { + // locked_count was already zero + this.eval_libc_i32("EPERM") + } } + } else { + throw_ub_format!("called pthread_mutex_unlock on an unsupported type of mutex"); } - } else { - throw_ub_format!("called pthread_mutex_unlock on an unsupported type of mutex"); } } @@ -366,6 +578,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx mutex_set_kind(this, mutex_op, ScalarMaybeUndef::Undef)?; mutex_set_locked_count(this, mutex_op, ScalarMaybeUndef::Undef)?; + mutex_set_blockset(this, mutex_op, ScalarMaybeUndef::Undef)?; Ok(0) } @@ -375,8 +588,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let readers = rwlock_get_readers(this, rwlock_op)?.to_u32()?; let writers = rwlock_get_writers(this, rwlock_op)?.to_u32()?; + if writers != 0 { - throw_machine_stop!(TerminationInfo::Deadlock); + // The lock is locked by a writer. + assert_eq!(writers, 1); + let reader_blockset = rwlock_get_or_create_reader_blockset(this, rwlock_op)?; + this.block_active_thread(reader_blockset)?; + Ok(0) } else { match readers.checked_add(1) { Some(new_readers) => { @@ -411,14 +629,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let readers = rwlock_get_readers(this, rwlock_op)?.to_u32()?; let writers = rwlock_get_writers(this, rwlock_op)?.to_u32()?; - if readers != 0 { - throw_machine_stop!(TerminationInfo::Deadlock); - } else if writers != 0 { - throw_machine_stop!(TerminationInfo::Deadlock); + let writer_blockset = rwlock_get_or_create_writer_blockset(this, rwlock_op)?; + if readers != 0 || writers != 0 { + this.block_active_thread(writer_blockset)?; } else { rwlock_set_writers(this, rwlock_op, Scalar::from_u32(1))?; - Ok(0) } + Ok(0) } fn pthread_rwlock_trywrlock(&mut self, rwlock_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { @@ -439,11 +656,28 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let readers = rwlock_get_readers(this, rwlock_op)?.to_u32()?; let writers = rwlock_get_writers(this, rwlock_op)?.to_u32()?; + let writer_blockset = rwlock_get_or_create_writer_blockset(this, rwlock_op)?; if let Some(new_readers) = readers.checked_sub(1) { + assert_eq!(writers, 0); rwlock_set_readers(this, rwlock_op, Scalar::from_u32(new_readers))?; + if new_readers == 0 { + if let Some(_writer) = this.unblock_random_thread(writer_blockset)? { + rwlock_set_writers(this, rwlock_op, Scalar::from_u32(1))?; + } + } Ok(0) } else if writers != 0 { + let reader_blockset = rwlock_get_or_create_reader_blockset(this, rwlock_op)?; rwlock_set_writers(this, rwlock_op, Scalar::from_u32(0))?; + if let Some(_writer) = this.unblock_random_thread(writer_blockset)? { + rwlock_set_writers(this, rwlock_op, Scalar::from_u32(1))?; + } else { + let mut readers = 0; + while let Some(_reader) = this.unblock_random_thread(reader_blockset)? { + readers += 1; + } + rwlock_set_readers(this, rwlock_op, Scalar::from_u32(readers))? + } Ok(0) } else { throw_ub_format!("unlocked an rwlock that was not locked"); @@ -461,6 +695,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx rwlock_set_readers(this, rwlock_op, ScalarMaybeUndef::Undef)?; rwlock_set_writers(this, rwlock_op, ScalarMaybeUndef::Undef)?; + rwlock_set_reader_blockset(this, rwlock_op, ScalarMaybeUndef::Undef)?; + rwlock_set_writer_blockset(this, rwlock_op, ScalarMaybeUndef::Undef)?; Ok(0) } diff --git a/src/threads.rs b/src/threads.rs index 4ce35d50abc35..5991ba4ed1f63 100644 --- a/src/threads.rs +++ b/src/threads.rs @@ -2,6 +2,7 @@ use std::cell::RefCell; use std::collections::hash_map::Entry; +use std::convert::TryFrom; use log::trace; @@ -31,6 +32,37 @@ impl From for ThreadId { } } +impl From for ThreadId { + fn from(id: u32) -> Self { + Self(id as usize) + } +} + +impl ThreadId { + pub fn to_u32_scalar<'tcx>(&self) -> Scalar { + Scalar::from_u32(u32::try_from(self.0).unwrap()) + } +} + +/// An identifier of a set of blocked threads. +/// +/// Note: 0 is not a valid identifier. +#[derive(Clone, Copy, Debug, PartialOrd, Ord, PartialEq, Eq, Hash)] +pub struct BlockSetId(u32); + +impl From for BlockSetId { + fn from(id: u32) -> Self { + assert_ne!(id, 0, "0 is not a valid blockset id"); + Self(id) + } +} + +impl BlockSetId { + pub fn to_u32_scalar<'tcx>(&self) -> Scalar { + Scalar::from_u32(self.0) + } +} + /// The state of a thread. #[derive(Debug, Copy, Clone, PartialEq, Eq)] pub enum ThreadState { @@ -38,7 +70,9 @@ pub enum ThreadState { Enabled, /// The thread tried to join the specified thread and is blocked until that /// thread terminates. - Blocked(ThreadId), + BlockedOnJoin(ThreadId), + /// The thread is blocked and belongs to the given blockset.. + Blocked(BlockSetId), /// The thread has terminated its execution (we do not delete terminated /// threads.) Terminated, @@ -93,13 +127,15 @@ pub struct ThreadSet<'mir, 'tcx> { /// /// Note that this vector also contains terminated threads. threads: IndexVec>, + /// A counter used to generate unique identifiers for blocksets. + blockset_counter: u32, } impl<'mir, 'tcx> Default for ThreadSet<'mir, 'tcx> { fn default() -> Self { let mut threads = IndexVec::new(); threads.push(Default::default()); - Self { active_thread: ThreadId::new(0), threads: threads } + Self { active_thread: ThreadId::new(0), threads: threads, blockset_counter: 0 } } } @@ -145,12 +181,12 @@ impl<'mir, 'tcx: 'mir> ThreadSet<'mir, 'tcx> { assert!( self.threads .iter() - .all(|thread| thread.state != ThreadState::Blocked(joined_thread_id)), + .all(|thread| thread.state != ThreadState::BlockedOnJoin(joined_thread_id)), "Bug: multiple threads try to join the same thread." ); if self.threads[joined_thread_id].state != ThreadState::Terminated { // The joined thread is still running, we need to wait for it. - self.threads[self.active_thread].state = ThreadState::Blocked(joined_thread_id); + self.active_thread_mut().state = ThreadState::BlockedOnJoin(joined_thread_id); trace!( "{:?} blocked on {:?} when trying to join", self.active_thread, @@ -162,10 +198,29 @@ impl<'mir, 'tcx: 'mir> ThreadSet<'mir, 'tcx> { fn set_thread_name(&mut self, new_thread_name: Vec) { self.active_thread_mut().thread_name = Some(new_thread_name); } - /// Get ids of all threads ever allocated. + /// Get ids and states of all threads ever allocated. fn get_all_thread_ids_with_states(&self) -> Vec<(ThreadId, ThreadState)> { self.threads.iter_enumerated().map(|(id, thread)| (id, thread.state)).collect() } + fn create_blockset(&mut self) -> BlockSetId { + self.blockset_counter = self.blockset_counter.checked_add(1).unwrap(); + self.blockset_counter.into() + } + fn block_active_thread(&mut self, set: BlockSetId) { + let state = &mut self.active_thread_mut().state; + assert_eq!(*state, ThreadState::Enabled); + *state = ThreadState::Blocked(set); + } + fn unblock_random_thread(&mut self, set: BlockSetId) -> Option { + for (id, thread) in self.threads.iter_enumerated_mut() { + if thread.state == ThreadState::Blocked(set) { + trace!("unblocking {:?} in blockset {:?}", id, set); + thread.state = ThreadState::Enabled; + return Some(id); + } + } + None + } /// Decide which thread to run next. /// /// Returns `false` if all threads terminated. @@ -173,7 +228,7 @@ impl<'mir, 'tcx: 'mir> ThreadSet<'mir, 'tcx> { if self.threads[self.active_thread].check_terminated() { // Check if we need to unblock any threads. for (i, thread) in self.threads.iter_enumerated_mut() { - if thread.state == ThreadState::Blocked(self.active_thread) { + if thread.state == ThreadState::BlockedOnJoin(self.active_thread) { trace!("unblocking {:?} because {:?} terminated", i, self.active_thread); thread.state = ThreadState::Enabled; } @@ -191,7 +246,7 @@ impl<'mir, 'tcx: 'mir> ThreadSet<'mir, 'tcx> { if self.threads.iter().all(|thread| thread.state == ThreadState::Terminated) { Ok(false) } else { - throw_machine_stop!(TerminationInfo::Abort(Some(format!("execution deadlocked")))) + throw_machine_stop!(TerminationInfo::Deadlock); } } } @@ -298,6 +353,18 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); this.machine.threads.get_all_thread_ids_with_states() } + fn create_blockset(&mut self) -> InterpResult<'tcx, BlockSetId> { + let this = self.eval_context_mut(); + Ok(this.machine.threads.create_blockset()) + } + fn block_active_thread(&mut self, set: BlockSetId) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + Ok(this.machine.threads.block_active_thread(set)) + } + fn unblock_random_thread(&mut self, set: BlockSetId) -> InterpResult<'tcx, Option> { + let this = self.eval_context_mut(); + Ok(this.machine.threads.unblock_random_thread(set)) + } /// Decide which thread to run next. /// /// Returns `false` if all threads terminated. diff --git a/tests/run-pass/concurrency/locks.rs b/tests/run-pass/concurrency/locks.rs new file mode 100644 index 0000000000000..575aeadd7fedf --- /dev/null +++ b/tests/run-pass/concurrency/locks.rs @@ -0,0 +1,29 @@ +//! This test just calls the relevant APIs to check if Miri crashes. + +use std::sync::{Arc, Mutex}; +use std::thread; + +fn main() { + + let data = Arc::new(Mutex::new(0)); + let mut threads = Vec::new(); + + for _ in 0..3 { + let data = Arc::clone(&data); + let thread = thread::spawn(move || { + let mut data = data.lock().unwrap(); + *data += 1; + }); + threads.push(thread); + } + + for thread in threads { + thread.join().unwrap(); + } + + assert!(data.try_lock().is_ok()); + + let data = Arc::try_unwrap(data).unwrap().into_inner().unwrap(); + assert_eq!(data, 3); + +} \ No newline at end of file diff --git a/tests/run-pass/concurrency/locks.stdout b/tests/run-pass/concurrency/locks.stdout new file mode 100644 index 0000000000000..2486b320db18f --- /dev/null +++ b/tests/run-pass/concurrency/locks.stdout @@ -0,0 +1,3 @@ +WARNING: The thread support is experimental. For example, Miri does not detect data races yet. +WARNING: The thread support is experimental. For example, Miri does not detect data races yet. +WARNING: The thread support is experimental. For example, Miri does not detect data races yet. From d907fb50215c2f79e4fd312447a67439620bb2ab Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Thu, 9 Apr 2020 12:06:33 -0700 Subject: [PATCH 1936/3747] Rename ThreadSet to ThreadManager. --- src/machine.rs | 4 ++-- src/threads.rs | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/machine.rs b/src/machine.rs index a7d62897b8f01..b56755083f4d0 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -27,7 +27,7 @@ use rustc_target::abi::{LayoutOf, Size}; use crate::*; -pub use crate::threads::{ThreadId, ThreadSet, ThreadState, ThreadLocalStorage}; +pub use crate::threads::{ThreadId, ThreadManager, ThreadState, ThreadLocalStorage}; // Some global facts about the emulated machine. pub const PAGE_SIZE: u64 = 4 * 1024; // FIXME: adjust to target architecture @@ -257,7 +257,7 @@ pub struct Evaluator<'mir, 'tcx> { pub(crate) time_anchor: Instant, /// The set of threads. - pub(crate) threads: ThreadSet<'mir, 'tcx>, + pub(crate) threads: ThreadManager<'mir, 'tcx>, /// Precomputed `TyLayout`s for primitive data types that are commonly used inside Miri. pub(crate) layouts: PrimitiveLayouts<'tcx>, diff --git a/src/threads.rs b/src/threads.rs index 5991ba4ed1f63..2352f26ebeef9 100644 --- a/src/threads.rs +++ b/src/threads.rs @@ -120,7 +120,7 @@ impl<'mir, 'tcx> Default for Thread<'mir, 'tcx> { /// A set of threads. #[derive(Debug)] -pub struct ThreadSet<'mir, 'tcx> { +pub struct ThreadManager<'mir, 'tcx> { /// Identifier of the currently active thread. active_thread: ThreadId, /// Threads used in the program. @@ -131,7 +131,7 @@ pub struct ThreadSet<'mir, 'tcx> { blockset_counter: u32, } -impl<'mir, 'tcx> Default for ThreadSet<'mir, 'tcx> { +impl<'mir, 'tcx> Default for ThreadManager<'mir, 'tcx> { fn default() -> Self { let mut threads = IndexVec::new(); threads.push(Default::default()); @@ -139,7 +139,7 @@ impl<'mir, 'tcx> Default for ThreadSet<'mir, 'tcx> { } } -impl<'mir, 'tcx: 'mir> ThreadSet<'mir, 'tcx> { +impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { /// Borrow the stack of the active thread. fn active_thread_stack(&self) -> &[Frame<'mir, 'tcx, Tag, FrameData<'tcx>>] { &self.threads[self.active_thread].stack From 0c4303cd7f903d2c05e70c05800dddefd7ccb7c6 Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Thu, 9 Apr 2020 13:37:38 -0700 Subject: [PATCH 1937/3747] Small refactoring in pthread sync: extract common functionallity to separate functions. --- src/shims/sync.rs | 235 ++++++++++++---------------------------------- 1 file changed, 58 insertions(+), 177 deletions(-) diff --git a/src/shims/sync.rs b/src/shims/sync.rs index eb54358114348..76f97aab23916 100644 --- a/src/shims/sync.rs +++ b/src/shims/sync.rs @@ -1,4 +1,4 @@ -use rustc_middle::ty::{TyKind, TypeAndMut}; +use rustc_middle::ty::{layout::TyAndLayout, TyKind, TypeAndMut}; use rustc_target::abi::{LayoutOf, Size}; use crate::stacked_borrows::Tag; @@ -19,22 +19,48 @@ fn assert_ptr_target_min_size<'mir, 'tcx: 'mir>( Ok(()) } +fn get_at_offset<'mir, 'tcx: 'mir>( + ecx: &MiriEvalContext<'mir, 'tcx>, + op: OpTy<'tcx, Tag>, + offset: u64, + layout: TyAndLayout<'tcx>, + min_size: u64, +) -> InterpResult<'tcx, ScalarMaybeUndef> { + // Ensure that the following read at an offset to the attr pointer is within bounds + assert_ptr_target_min_size(ecx, op, min_size)?; + let op_place = ecx.deref_operand(op)?; + let value_place = op_place.offset(Size::from_bytes(offset), MemPlaceMeta::None, layout, ecx)?; + ecx.read_scalar(value_place.into()) +} + +fn set_at_offset<'mir, 'tcx: 'mir>( + ecx: &mut MiriEvalContext<'mir, 'tcx>, + op: OpTy<'tcx, Tag>, + offset: u64, + value: impl Into>, + layout: TyAndLayout<'tcx>, + min_size: u64, +) -> InterpResult<'tcx, ()> { + // Ensure that the following write at an offset to the attr pointer is within bounds + assert_ptr_target_min_size(ecx, op, min_size)?; + let op_place = ecx.deref_operand(op)?; + let value_place = op_place.offset(Size::from_bytes(offset), MemPlaceMeta::None, layout, ecx)?; + ecx.write_scalar(value.into(), value_place.into()) +} + // pthread_mutexattr_t is either 4 or 8 bytes, depending on the platform. // Our chosen memory layout for emulation (does not have to match the platform layout!): // store an i32 in the first four bytes equal to the corresponding libc mutex kind constant // (e.g. PTHREAD_MUTEX_NORMAL). +const PTHREAD_MUTEXATTR_T_MIN_SIZE: u64 = 4; + fn mutexattr_get_kind<'mir, 'tcx: 'mir>( ecx: &MiriEvalContext<'mir, 'tcx>, attr_op: OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, ScalarMaybeUndef> { - // Ensure that the following read at an offset to the attr pointer is within bounds - assert_ptr_target_min_size(ecx, attr_op, 4)?; - let attr_place = ecx.deref_operand(attr_op)?; - let kind_place = - attr_place.offset(Size::ZERO, MemPlaceMeta::None, ecx.machine.layouts.i32, ecx)?; - ecx.read_scalar(kind_place.into()) + get_at_offset(ecx, attr_op, 0, ecx.machine.layouts.i32, PTHREAD_MUTEXATTR_T_MIN_SIZE) } fn mutexattr_set_kind<'mir, 'tcx: 'mir>( @@ -42,12 +68,7 @@ fn mutexattr_set_kind<'mir, 'tcx: 'mir>( attr_op: OpTy<'tcx, Tag>, kind: impl Into>, ) -> InterpResult<'tcx, ()> { - // Ensure that the following write at an offset to the attr pointer is within bounds - assert_ptr_target_min_size(ecx, attr_op, 4)?; - let attr_place = ecx.deref_operand(attr_op)?; - let kind_place = - attr_place.offset(Size::ZERO, MemPlaceMeta::None, ecx.machine.layouts.i32, ecx)?; - ecx.write_scalar(kind.into(), kind_place.into()) + set_at_offset(ecx, attr_op, 0, kind, ecx.machine.layouts.i32, PTHREAD_MUTEXATTR_T_MIN_SIZE) } // pthread_mutex_t is between 24 and 48 bytes, depending on the platform. @@ -61,20 +82,13 @@ fn mutexattr_set_kind<'mir, 'tcx: 'mir>( // (the kind has to be at its offset for compatibility with static initializer macros) // bytes 20-23: when count > 0, id of the blockset in which the blocked threads are waiting. +const PTHREAD_MUTEX_T_MIN_SIZE: u64 = 24; + fn mutex_get_locked_count<'mir, 'tcx: 'mir>( ecx: &MiriEvalContext<'mir, 'tcx>, mutex_op: OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, ScalarMaybeUndef> { - // Ensure that the following read at an offset to the mutex pointer is within bounds - assert_ptr_target_min_size(ecx, mutex_op, 24)?; - let mutex_place = ecx.deref_operand(mutex_op)?; - let locked_count_place = mutex_place.offset( - Size::from_bytes(4), - MemPlaceMeta::None, - ecx.machine.layouts.u32, - ecx, - )?; - ecx.read_scalar(locked_count_place.into()) + get_at_offset(ecx, mutex_op, 4, ecx.machine.layouts.u32, PTHREAD_MUTEX_T_MIN_SIZE) } fn mutex_set_locked_count<'mir, 'tcx: 'mir>( @@ -82,66 +96,30 @@ fn mutex_set_locked_count<'mir, 'tcx: 'mir>( mutex_op: OpTy<'tcx, Tag>, locked_count: impl Into>, ) -> InterpResult<'tcx, ()> { - // Ensure that the following write at an offset to the mutex pointer is within bounds - assert_ptr_target_min_size(ecx, mutex_op, 24)?; - let mutex_place = ecx.deref_operand(mutex_op)?; - let locked_count_place = mutex_place.offset( - Size::from_bytes(4), - MemPlaceMeta::None, - ecx.machine.layouts.u32, - ecx, - )?; - ecx.write_scalar(locked_count.into(), locked_count_place.into()) + set_at_offset(ecx, mutex_op, 4, locked_count, ecx.machine.layouts.u32, PTHREAD_MUTEX_T_MIN_SIZE) } fn mutex_get_owner<'mir, 'tcx: 'mir>( ecx: &MiriEvalContext<'mir, 'tcx>, mutex_op: OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, ScalarMaybeUndef> { - // Ensure that the following read at an offset to the mutex pointer is within bounds - assert_ptr_target_min_size(ecx, mutex_op, 24)?; - let mutex_place = ecx.deref_operand(mutex_op)?; - let mutex_id_place = mutex_place.offset( - Size::from_bytes(8), - MemPlaceMeta::None, - ecx.machine.layouts.u32, - ecx, - )?; - ecx.read_scalar(mutex_id_place.into()) + get_at_offset(ecx, mutex_op, 8, ecx.machine.layouts.u32, PTHREAD_MUTEX_T_MIN_SIZE) } fn mutex_set_owner<'mir, 'tcx: 'mir>( ecx: &mut MiriEvalContext<'mir, 'tcx>, mutex_op: OpTy<'tcx, Tag>, - mutex_id: impl Into>, + owner: impl Into>, ) -> InterpResult<'tcx, ()> { - // Ensure that the following write at an offset to the mutex pointer is within bounds - assert_ptr_target_min_size(ecx, mutex_op, 24)?; - let mutex_place = ecx.deref_operand(mutex_op)?; - let mutex_id_place = mutex_place.offset( - Size::from_bytes(8), - MemPlaceMeta::None, - ecx.machine.layouts.u32, - ecx, - )?; - ecx.write_scalar(mutex_id.into(), mutex_id_place.into()) + set_at_offset(ecx, mutex_op, 8, owner, ecx.machine.layouts.u32, PTHREAD_MUTEX_T_MIN_SIZE) } fn mutex_get_kind<'mir, 'tcx: 'mir>( ecx: &mut MiriEvalContext<'mir, 'tcx>, mutex_op: OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, ScalarMaybeUndef> { - // Ensure that the following read at an offset to the mutex pointer is within bounds - assert_ptr_target_min_size(ecx, mutex_op, 24)?; - let mutex_place = ecx.deref_operand(mutex_op)?; - let kind_offset = if ecx.pointer_size().bytes() == 8 { 16 } else { 12 }; - let kind_place = mutex_place.offset( - Size::from_bytes(kind_offset), - MemPlaceMeta::None, - ecx.machine.layouts.i32, - ecx, - )?; - ecx.read_scalar(kind_place.into()) + let offset = if ecx.pointer_size().bytes() == 8 { 16 } else { 12 }; + get_at_offset(ecx, mutex_op, offset, ecx.machine.layouts.i32, PTHREAD_MUTEX_T_MIN_SIZE) } fn mutex_set_kind<'mir, 'tcx: 'mir>( @@ -149,50 +127,23 @@ fn mutex_set_kind<'mir, 'tcx: 'mir>( mutex_op: OpTy<'tcx, Tag>, kind: impl Into>, ) -> InterpResult<'tcx, ()> { - // Ensure that the following write at an offset to the mutex pointer is within bounds - assert_ptr_target_min_size(ecx, mutex_op, 24)?; - let mutex_place = ecx.deref_operand(mutex_op)?; - let kind_offset = if ecx.pointer_size().bytes() == 8 { 16 } else { 12 }; - let kind_place = mutex_place.offset( - Size::from_bytes(kind_offset), - MemPlaceMeta::None, - ecx.machine.layouts.i32, - ecx, - )?; - ecx.write_scalar(kind.into(), kind_place.into()) + let offset = if ecx.pointer_size().bytes() == 8 { 16 } else { 12 }; + set_at_offset(ecx, mutex_op, offset, kind, ecx.machine.layouts.i32, PTHREAD_MUTEX_T_MIN_SIZE) } fn mutex_get_blockset<'mir, 'tcx: 'mir>( ecx: &MiriEvalContext<'mir, 'tcx>, mutex_op: OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, ScalarMaybeUndef> { - // Ensure that the following read at an offset to the mutex pointer is within bounds - assert_ptr_target_min_size(ecx, mutex_op, 24)?; - let mutex_place = ecx.deref_operand(mutex_op)?; - let mutex_id_place = mutex_place.offset( - Size::from_bytes(20), - MemPlaceMeta::None, - ecx.machine.layouts.u32, - ecx, - )?; - ecx.read_scalar(mutex_id_place.into()) + get_at_offset(ecx, mutex_op, 20, ecx.machine.layouts.u32, PTHREAD_MUTEX_T_MIN_SIZE) } fn mutex_set_blockset<'mir, 'tcx: 'mir>( ecx: &mut MiriEvalContext<'mir, 'tcx>, mutex_op: OpTy<'tcx, Tag>, - mutex_id: impl Into>, + blockset: impl Into>, ) -> InterpResult<'tcx, ()> { - // Ensure that the following write at an offset to the mutex pointer is within bounds - assert_ptr_target_min_size(ecx, mutex_op, 24)?; - let mutex_place = ecx.deref_operand(mutex_op)?; - let mutex_id_place = mutex_place.offset( - Size::from_bytes(20), - MemPlaceMeta::None, - ecx.machine.layouts.u32, - ecx, - )?; - ecx.write_scalar(mutex_id.into(), mutex_id_place.into()) + set_at_offset(ecx, mutex_op, 20, blockset, ecx.machine.layouts.u32, PTHREAD_MUTEX_T_MIN_SIZE) } fn mutex_get_or_create_blockset<'mir, 'tcx: 'mir>( @@ -223,20 +174,13 @@ fn mutex_get_or_create_blockset<'mir, 'tcx: 'mir>( // bytes 16-20: when writer count > 0, id of the blockset in which the blocked // readers are waiting. +const PTHREAD_RWLOCK_T_MIN_SIZE: u64 = 20; + fn rwlock_get_readers<'mir, 'tcx: 'mir>( ecx: &MiriEvalContext<'mir, 'tcx>, rwlock_op: OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, ScalarMaybeUndef> { - // Ensure that the following read at an offset to the rwlock pointer is within bounds - assert_ptr_target_min_size(ecx, rwlock_op, 20)?; - let rwlock_place = ecx.deref_operand(rwlock_op)?; - let readers_place = rwlock_place.offset( - Size::from_bytes(4), - MemPlaceMeta::None, - ecx.machine.layouts.u32, - ecx, - )?; - ecx.read_scalar(readers_place.into()) + get_at_offset(ecx, rwlock_op, 4, ecx.machine.layouts.u32, PTHREAD_RWLOCK_T_MIN_SIZE) } fn rwlock_set_readers<'mir, 'tcx: 'mir>( @@ -244,32 +188,14 @@ fn rwlock_set_readers<'mir, 'tcx: 'mir>( rwlock_op: OpTy<'tcx, Tag>, readers: impl Into>, ) -> InterpResult<'tcx, ()> { - // Ensure that the following write at an offset to the rwlock pointer is within bounds - assert_ptr_target_min_size(ecx, rwlock_op, 20)?; - let rwlock_place = ecx.deref_operand(rwlock_op)?; - let readers_place = rwlock_place.offset( - Size::from_bytes(4), - MemPlaceMeta::None, - ecx.machine.layouts.u32, - ecx, - )?; - ecx.write_scalar(readers.into(), readers_place.into()) + set_at_offset(ecx, rwlock_op, 4, readers, ecx.machine.layouts.u32, PTHREAD_RWLOCK_T_MIN_SIZE) } fn rwlock_get_writers<'mir, 'tcx: 'mir>( ecx: &MiriEvalContext<'mir, 'tcx>, rwlock_op: OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, ScalarMaybeUndef> { - // Ensure that the following read at an offset to the rwlock pointer is within bounds - assert_ptr_target_min_size(ecx, rwlock_op, 20)?; - let rwlock_place = ecx.deref_operand(rwlock_op)?; - let writers_place = rwlock_place.offset( - Size::from_bytes(8), - MemPlaceMeta::None, - ecx.machine.layouts.u32, - ecx, - )?; - ecx.read_scalar(writers_place.into()) + get_at_offset(ecx, rwlock_op, 8, ecx.machine.layouts.u32, PTHREAD_RWLOCK_T_MIN_SIZE) } fn rwlock_set_writers<'mir, 'tcx: 'mir>( @@ -277,32 +203,14 @@ fn rwlock_set_writers<'mir, 'tcx: 'mir>( rwlock_op: OpTy<'tcx, Tag>, writers: impl Into>, ) -> InterpResult<'tcx, ()> { - // Ensure that the following write at an offset to the rwlock pointer is within bounds - assert_ptr_target_min_size(ecx, rwlock_op, 20)?; - let rwlock_place = ecx.deref_operand(rwlock_op)?; - let writers_place = rwlock_place.offset( - Size::from_bytes(8), - MemPlaceMeta::None, - ecx.machine.layouts.u32, - ecx, - )?; - ecx.write_scalar(writers.into(), writers_place.into()) + set_at_offset(ecx, rwlock_op, 8, writers, ecx.machine.layouts.u32, PTHREAD_RWLOCK_T_MIN_SIZE) } fn rwlock_get_writer_blockset<'mir, 'tcx: 'mir>( ecx: &MiriEvalContext<'mir, 'tcx>, rwlock_op: OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, ScalarMaybeUndef> { - // Ensure that the following read at an offset to the rwlock pointer is within bounds - assert_ptr_target_min_size(ecx, rwlock_op, 20)?; - let rwlock_place = ecx.deref_operand(rwlock_op)?; - let blockset_place = rwlock_place.offset( - Size::from_bytes(12), - MemPlaceMeta::None, - ecx.machine.layouts.u32, - ecx, - )?; - ecx.read_scalar(blockset_place.into()) + get_at_offset(ecx, rwlock_op, 12, ecx.machine.layouts.u32, PTHREAD_RWLOCK_T_MIN_SIZE) } fn rwlock_set_writer_blockset<'mir, 'tcx: 'mir>( @@ -310,16 +218,7 @@ fn rwlock_set_writer_blockset<'mir, 'tcx: 'mir>( rwlock_op: OpTy<'tcx, Tag>, blockset: impl Into>, ) -> InterpResult<'tcx, ()> { - // Ensure that the following write at an offset to the rwlock pointer is within bounds - assert_ptr_target_min_size(ecx, rwlock_op, 20)?; - let rwlock_place = ecx.deref_operand(rwlock_op)?; - let blockset_place = rwlock_place.offset( - Size::from_bytes(12), - MemPlaceMeta::None, - ecx.machine.layouts.u32, - ecx, - )?; - ecx.write_scalar(blockset.into(), blockset_place.into()) + set_at_offset(ecx, rwlock_op, 12, blockset, ecx.machine.layouts.u32, PTHREAD_RWLOCK_T_MIN_SIZE) } fn rwlock_get_or_create_writer_blockset<'mir, 'tcx: 'mir>( @@ -342,16 +241,7 @@ fn rwlock_get_reader_blockset<'mir, 'tcx: 'mir>( ecx: &MiriEvalContext<'mir, 'tcx>, rwlock_op: OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, ScalarMaybeUndef> { - // Ensure that the following read at an offset to the rwlock pointer is within bounds - assert_ptr_target_min_size(ecx, rwlock_op, 20)?; - let rwlock_place = ecx.deref_operand(rwlock_op)?; - let blockset_place = rwlock_place.offset( - Size::from_bytes(16), - MemPlaceMeta::None, - ecx.machine.layouts.u32, - ecx, - )?; - ecx.read_scalar(blockset_place.into()) + get_at_offset(ecx, rwlock_op, 16, ecx.machine.layouts.u32, PTHREAD_RWLOCK_T_MIN_SIZE) } fn rwlock_set_reader_blockset<'mir, 'tcx: 'mir>( @@ -359,16 +249,7 @@ fn rwlock_set_reader_blockset<'mir, 'tcx: 'mir>( rwlock_op: OpTy<'tcx, Tag>, blockset: impl Into>, ) -> InterpResult<'tcx, ()> { - // Ensure that the following write at an offset to the rwlock pointer is within bounds - assert_ptr_target_min_size(ecx, rwlock_op, 20)?; - let rwlock_place = ecx.deref_operand(rwlock_op)?; - let blockset_place = rwlock_place.offset( - Size::from_bytes(16), - MemPlaceMeta::None, - ecx.machine.layouts.u32, - ecx, - )?; - ecx.write_scalar(blockset.into(), blockset_place.into()) + set_at_offset(ecx, rwlock_op, 16, blockset, ecx.machine.layouts.u32, PTHREAD_RWLOCK_T_MIN_SIZE) } fn rwlock_get_or_create_reader_blockset<'mir, 'tcx: 'mir>( From 963e9698f9ab959de06f42047ef1979bde0aac84 Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Tue, 14 Apr 2020 17:21:52 -0700 Subject: [PATCH 1938/3747] Generate fresh allocation ids for thread locals in eval_maybe_thread_local_static_const. --- src/diagnostics.rs | 4 +- src/machine.rs | 112 ++++++++++++++++++++------------------------- src/shims/tls.rs | 2 +- 3 files changed, 53 insertions(+), 65 deletions(-) diff --git a/src/diagnostics.rs b/src/diagnostics.rs index 114f1d9be3623..b7c96dd7e98aa 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -139,7 +139,7 @@ fn report_msg<'tcx, 'mir>( mut helps: Vec, error: bool, ) { - let span = if let Some(frame) = ecx.machine.stack.last() { + let span = if let Some(frame) = ecx.active_thread_stack().last() { frame.current_source_info().unwrap().span } else { DUMMY_SP @@ -171,7 +171,7 @@ fn report_msg<'tcx, 'mir>( err.emit(); - for (i, frame) in ecx.machine.stack.iter().enumerate() { + for (i, frame) in ecx.active_thread_stack().iter().enumerate() { trace!("-------------------"); trace!("Frame {}", i); trace!(" return: {:?}", frame.return_place.map(|p| *p)); diff --git a/src/machine.rs b/src/machine.rs index b56755083f4d0..a9582f595ff63 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -22,7 +22,7 @@ use rustc_middle::{ TyCtxt, }, }; -use rustc_span::{def_id::DefId, symbol::{sym, Symbol}}; +use rustc_span::symbol::{sym, Symbol}; use rustc_target::abi::{LayoutOf, Size}; use crate::*; @@ -331,19 +331,6 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { memory_extra.check_alignment } - #[inline(always)] - fn stack<'a>( - ecx: &'a InterpCx<'mir, 'tcx, Self> - ) -> &'a [Frame<'mir, 'tcx, Self::PointerTag, Self::FrameExtra>] { - ecx.active_thread_stack() - } - - fn stack_mut<'a>( - ecx: &'a mut InterpCx<'mir, 'tcx, Self> - ) -> &'a mut Vec> { - ecx.active_thread_stack_mut() - } - #[inline(always)] fn enforce_validity(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool { ecx.machine.validate @@ -434,63 +421,52 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { Ok(()) } - fn access_local( + fn eval_maybe_thread_local_static_const( ecx: &InterpCx<'mir, 'tcx, Self>, - frame: &Frame<'mir, 'tcx, Self::PointerTag, Self::FrameExtra>, - local: mir::Local, - ) -> InterpResult<'tcx, Operand> { - match frame.body.local_decls[local].local_info { - mir::LocalInfo::StaticRef { def_id, is_thread_local: true } => { - let static_alloc_id = ecx.tcx.alloc_map.lock().create_static_alloc(def_id); - let alloc_id = ecx.memory.extra.tls.get_or_register_allocation(*ecx.memory.tcx, static_alloc_id); - let tag = Self::tag_global_base_pointer(&ecx.memory.extra, alloc_id); - let pointer: Pointer = alloc_id.into(); - let pointer = pointer.with_tag(tag); - let scalar: Scalar<_> = pointer.into(); - let scalar: ScalarMaybeUndef<_> = scalar.into(); - let immediate: Immediate<_> = scalar.into(); - Ok( - Operand::Immediate(immediate) - ) - }, - _ => frame.locals[local].access(), + mut val: mir::interpret::ConstValue<'tcx> + )-> InterpResult<'tcx, mir::interpret::ConstValue<'tcx>> { + match &mut val { + mir::interpret::ConstValue::Scalar(Scalar::Ptr(ptr)) => { + let alloc_id = ptr.alloc_id; + let alloc = ecx.tcx.alloc_map.lock().get(alloc_id); + match alloc { + Some(GlobalAlloc::Static(def_id)) + if ecx.tcx.codegen_fn_attrs(def_id).flags.contains(CodegenFnAttrFlags::THREAD_LOCAL) => { + // We have a thread-local static. + let new_alloc_id = ecx.memory.extra.tls.get_or_register_allocation( + *ecx.memory.tcx, alloc_id); + ptr.alloc_id = new_alloc_id; + }, + _ => {}, + } + } + _ => {}, } + Ok(val) } fn canonical_alloc_id(mem: &Memory<'mir, 'tcx, Self>, id: AllocId) -> AllocId { let tcx = mem.tcx; - let alloc = tcx.alloc_map.lock().get(id); - fn is_thread_local<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> bool { - tcx.codegen_fn_attrs(def_id).flags.contains(CodegenFnAttrFlags::THREAD_LOCAL) - } - match alloc { - Some(GlobalAlloc::Static(def_id)) if tcx.is_foreign_item(def_id) => { - if is_thread_local(*tcx, def_id) { - unimplemented!("Foreign thread local statics are not supported yet."); - } - // Figure out if this is an extern static, and if yes, which one. - let attrs = tcx.get_attrs(def_id); - let link_name = match attr::first_attr_value_str_by_name(&attrs, sym::link_name) { - Some(name) => name, - None => tcx.item_name(def_id), - }; - // Check if we know this one. - if let Some(canonical_id) = mem.extra.extern_statics.get(&link_name) { - trace!("canonical_alloc_id: {:?} ({}) -> {:?}", id, link_name, canonical_id); - *canonical_id - } else { - // Return original id; `Memory::get_static_alloc` will throw an error. - id - } - }, - Some(GlobalAlloc::Static(def_id)) if is_thread_local(*tcx, def_id) => { - // We have a thread local, so we need to get a unique allocation id for it. - mem.extra.tls.get_or_register_allocation(*tcx, id) - }, + // Figure out if this is an extern static, and if yes, which one. + let def_id = match tcx.alloc_map.lock().get(id) { + Some(GlobalAlloc::Static(def_id)) if tcx.is_foreign_item(def_id) => def_id, _ => { // No need to canonicalize anything. - id + return id; } + }; + let attrs = tcx.get_attrs(def_id); + let link_name = match attr::first_attr_value_str_by_name(&attrs, sym::link_name) { + Some(name) => name, + None => tcx.item_name(def_id), + }; + // Check if we know this one. + if let Some(canonical_id) = mem.extra.extern_statics.get(&link_name) { + trace!("canonical_alloc_id: {:?} ({}) -> {:?}", id, link_name, canonical_id); + *canonical_id + } else { + // Return original id; `Memory::get_static_alloc` will throw an error. + id } } @@ -587,6 +563,18 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { Ok(frame.with_extra(extra)) } + fn stack<'a>( + ecx: &'a InterpCx<'mir, 'tcx, Self> + ) -> &'a [Frame<'mir, 'tcx, Self::PointerTag, Self::FrameExtra>] { + ecx.active_thread_stack() + } + + fn stack_mut<'a>( + ecx: &'a mut InterpCx<'mir, 'tcx, Self> + ) -> &'a mut Vec> { + ecx.active_thread_stack_mut() + } + #[inline(always)] fn stack<'a>( ecx: &'a InterpCx<'mir, 'tcx, Self>, diff --git a/src/shims/tls.rs b/src/shims/tls.rs index ec8c31fe2c127..5cef3871c033f 100644 --- a/src/shims/tls.rs +++ b/src/shims/tls.rs @@ -161,7 +161,7 @@ impl<'tcx> TlsData<'tcx> { Entry::Occupied(entry) => { let (thread_id, data_scalar) = entry.remove_entry(); if let Some(dtor) = dtor { - let ret = Some((dtor, thread_id, data_scalar, key)); + let ret = Some((*dtor, thread_id, data_scalar, key)); return ret; } } From 51b16e56cd297afd308aea5b258a677901c7b45e Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Wed, 15 Apr 2020 14:34:34 -0700 Subject: [PATCH 1939/3747] Generate thread local allocations in eval_maybe_thread_local_static_const. --- src/machine.rs | 64 ++++++++++++++++++++--------- src/threads.rs | 108 ++++++++++++++++--------------------------------- 2 files changed, 78 insertions(+), 94 deletions(-) diff --git a/src/machine.rs b/src/machine.rs index a9582f595ff63..a5183d3e8166a 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -18,6 +18,7 @@ use rustc_middle::{ mir, ty::{ self, + Instance, layout::{LayoutCx, LayoutError, TyAndLayout}, TyCtxt, }, @@ -27,7 +28,7 @@ use rustc_target::abi::{LayoutOf, Size}; use crate::*; -pub use crate::threads::{ThreadId, ThreadManager, ThreadState, ThreadLocalStorage}; +pub use crate::threads::{ThreadId, ThreadManager, ThreadState}; // Some global facts about the emulated machine. pub const PAGE_SIZE: u64 = 4 * 1024; // FIXME: adjust to target architecture @@ -110,7 +111,6 @@ pub struct AllocExtra { pub struct MemoryExtra { pub stacked_borrows: Option, pub intptrcast: intptrcast::MemoryExtra, - pub tls: ThreadLocalStorage, /// Mapping extern static names to their canonical allocation. extern_statics: FxHashMap, @@ -147,7 +147,6 @@ impl MemoryExtra { rng: RefCell::new(rng), tracked_alloc_id, check_alignment, - tls: Default::default(), } } @@ -423,24 +422,58 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { fn eval_maybe_thread_local_static_const( ecx: &InterpCx<'mir, 'tcx, Self>, - mut val: mir::interpret::ConstValue<'tcx> - )-> InterpResult<'tcx, mir::interpret::ConstValue<'tcx>> { + mut val: mir::interpret::ConstValue<'tcx>, + ) -> InterpResult<'tcx, mir::interpret::ConstValue<'tcx>> { match &mut val { mir::interpret::ConstValue::Scalar(Scalar::Ptr(ptr)) => { let alloc_id = ptr.alloc_id; let alloc = ecx.tcx.alloc_map.lock().get(alloc_id); match alloc { Some(GlobalAlloc::Static(def_id)) - if ecx.tcx.codegen_fn_attrs(def_id).flags.contains(CodegenFnAttrFlags::THREAD_LOCAL) => { + if ecx + .tcx + .codegen_fn_attrs(def_id) + .flags + .contains(CodegenFnAttrFlags::THREAD_LOCAL) => + { // We have a thread-local static. - let new_alloc_id = ecx.memory.extra.tls.get_or_register_allocation( - *ecx.memory.tcx, alloc_id); + let new_alloc_id = if let Some(new_alloc_id) = + ecx.get_thread_local_alloc_id(alloc_id) + { + new_alloc_id + } else { + if ecx.tcx.is_foreign_item(def_id) { + throw_unsup_format!( + "Foreign thread-local statics are not supported." + ) + } + let instance = Instance::mono(ecx.tcx.tcx, def_id); + let gid = GlobalId { instance, promoted: None }; + let raw_const = ecx + .tcx + .const_eval_raw(ty::ParamEnv::reveal_all().and(gid)) + .map_err(|err| { + // no need to report anything, the const_eval call takes care of that + // for statics + assert!(ecx.tcx.is_static(def_id)); + match err { + ErrorHandled::Reported => err_inval!(ReferencedConstant), + ErrorHandled::TooGeneric => err_inval!(TooGeneric), + } + })?; + let id = raw_const.alloc_id; + let mut alloc_map = ecx.tcx.alloc_map.lock(); + let allocation = alloc_map.unwrap_memory(id); + let new_alloc_id = alloc_map.create_memory_alloc(allocation); + ecx.set_thread_local_alloc_id(alloc_id, new_alloc_id); + new_alloc_id + }; ptr.alloc_id = new_alloc_id; - }, - _ => {}, + } + _ => {} } } - _ => {}, + _ => {} } Ok(val) } @@ -470,15 +503,6 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { } } - #[inline(always)] - fn resolve_maybe_global_alloc( - tcx: ty::query::TyCtxtAt<'tcx>, - extra: &Self::MemoryExtra, - id: AllocId, - ) -> Option> { - extra.tls.resolve_allocation(*tcx, id) - } - fn init_allocation_extra<'b>( memory_extra: &MemoryExtra, id: AllocId, diff --git a/src/threads.rs b/src/threads.rs index 2352f26ebeef9..170fb0c4767ef 100644 --- a/src/threads.rs +++ b/src/threads.rs @@ -1,15 +1,12 @@ //! Implements threads. use std::cell::RefCell; -use std::collections::hash_map::Entry; use std::convert::TryFrom; use log::trace; use rustc_data_structures::fx::FxHashMap; use rustc_index::vec::{Idx, IndexVec}; -use rustc_middle::mir; -use rustc_middle::ty; use crate::*; @@ -129,17 +126,41 @@ pub struct ThreadManager<'mir, 'tcx> { threads: IndexVec>, /// A counter used to generate unique identifiers for blocksets. blockset_counter: u32, + /// A mapping from an allocation id of a thread-local static to an + /// allocation id of a thread specific allocation. + thread_local_alloc_ids: RefCell>, } impl<'mir, 'tcx> Default for ThreadManager<'mir, 'tcx> { fn default() -> Self { let mut threads = IndexVec::new(); threads.push(Default::default()); - Self { active_thread: ThreadId::new(0), threads: threads, blockset_counter: 0 } + Self { + active_thread: ThreadId::new(0), + threads: threads, + blockset_counter: 0, + thread_local_alloc_ids: Default::default(), + } } } impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { + /// Check if we have an allocation for the given thread local static for the + /// active thread. + pub fn get_thread_local_alloc_id(&self, static_alloc_id: AllocId) -> Option { + self.thread_local_alloc_ids.borrow().get(&(static_alloc_id, self.active_thread)).cloned() + } + /// Set the allocation id as the allocation id of the given thread local + /// static for the active thread. + pub fn set_thread_local_alloc_id(&self, static_alloc_id: AllocId, new_alloc_id: AllocId) { + assert!( + self.thread_local_alloc_ids + .borrow_mut() + .insert((static_alloc_id, self.active_thread), new_alloc_id) + .is_none(), + "Bug: a thread local initialized twice for the same thread." + ); + } /// Borrow the stack of the active thread. fn active_thread_stack(&self) -> &[Frame<'mir, 'tcx, Tag, FrameData<'tcx>>] { &self.threads[self.active_thread].stack @@ -251,69 +272,16 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { } } -/// In Rust, a thread local variable is just a specially marked static. To -/// ensure a property that each memory allocation has a globally unique -/// allocation identifier, we create a fresh allocation id for each thread. This -/// data structure keeps the track of the created allocation identifiers and -/// their relation to the original static allocations. -#[derive(Clone, Debug, Default)] -pub struct ThreadLocalStorage { - /// A map from a thread local allocation identifier to the static from which - /// it was created. - thread_local_origin: RefCell>, - /// A map from a thread local static and thread id to the unique thread - /// local allocation. - thread_local_allocations: RefCell>, - /// The currently active thread. - active_thread: Option, -} - -impl ThreadLocalStorage { - /// For static allocation identifier `original_id` get a thread local - /// allocation identifier. If it is not allocated yet, allocate. - pub fn get_or_register_allocation(&self, tcx: ty::TyCtxt<'_>, original_id: AllocId) -> AllocId { - match self - .thread_local_allocations - .borrow_mut() - .entry((original_id, self.active_thread.unwrap())) - { - Entry::Occupied(entry) => *entry.get(), - Entry::Vacant(entry) => { - let fresh_id = tcx.alloc_map.lock().reserve(); - entry.insert(fresh_id); - self.thread_local_origin.borrow_mut().insert(fresh_id, original_id); - trace!( - "get_or_register_allocation(original_id={:?}) -> {:?}", - original_id, - fresh_id - ); - fresh_id - } - } - } - /// For thread local allocation identifier `alloc_id`, retrieve the original - /// static allocation identifier from which it was created. - pub fn resolve_allocation<'tcx>( - &self, - tcx: ty::TyCtxt<'tcx>, - alloc_id: AllocId, - ) -> Option> { - trace!("resolve_allocation(alloc_id: {:?})", alloc_id); - if let Some(original_id) = self.thread_local_origin.borrow().get(&alloc_id) { - trace!("resolve_allocation(alloc_id: {:?}) -> {:?}", alloc_id, original_id); - tcx.alloc_map.lock().get(*original_id) - } else { - tcx.alloc_map.lock().get(alloc_id) - } - } - /// Set which thread is currently active. - fn set_active_thread(&mut self, active_thread: ThreadId) { - self.active_thread = Some(active_thread); - } -} - impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { + fn get_thread_local_alloc_id(&self, static_alloc_id: AllocId) -> Option { + let this = self.eval_context_ref(); + this.machine.threads.get_thread_local_alloc_id(static_alloc_id) + } + fn set_thread_local_alloc_id(&self, static_alloc_id: AllocId, thread_local_alloc_id: AllocId) { + let this = self.eval_context_ref(); + this.machine.threads.set_thread_local_alloc_id(static_alloc_id, thread_local_alloc_id) + } fn create_thread(&mut self) -> InterpResult<'tcx, ThreadId> { let this = self.eval_context_mut(); Ok(this.machine.threads.create_thread()) @@ -330,7 +298,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } fn set_active_thread(&mut self, thread_id: ThreadId) -> InterpResult<'tcx, ThreadId> { let this = self.eval_context_mut(); - this.memory.extra.tls.set_active_thread(thread_id); Ok(this.machine.threads.set_active_thread_id(thread_id)) } fn get_active_thread(&self) -> InterpResult<'tcx, ThreadId> { @@ -370,13 +337,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// Returns `false` if all threads terminated. fn schedule(&mut self) -> InterpResult<'tcx, bool> { let this = self.eval_context_mut(); - // Find the next thread to run. - if this.machine.threads.schedule()? { - let active_thread = this.machine.threads.get_active_thread_id(); - this.memory.extra.tls.set_active_thread(active_thread); - Ok(true) - } else { - Ok(false) - } + this.machine.threads.schedule() } } From 325c31e578210d0c72d8d5f1612074ddcbe514bb Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Wed, 15 Apr 2020 21:25:12 -0700 Subject: [PATCH 1940/3747] Address some of the reviewers comments. --- src/eval.rs | 2 +- src/machine.rs | 24 ++++---- src/shims/foreign_items/posix.rs | 57 ++++++++----------- src/shims/threads.rs | 14 +++-- src/threads.rs | 43 ++++++++++++-- tests/compile-fail/thread-spawn.rs | 9 +++ tests/run-pass/concurrency/locks.rs | 2 + tests/run-pass/concurrency/locks.stderr | 2 + tests/run-pass/concurrency/locks.stdout | 3 - tests/run-pass/concurrency/simple.rs | 2 + tests/run-pass/concurrency/simple.stderr | 2 + tests/run-pass/concurrency/simple.stdout | 10 ---- tests/run-pass/concurrency/thread_locals.rs | 2 + .../run-pass/concurrency/thread_locals.stderr | 2 + .../run-pass/concurrency/thread_locals.stdout | 1 - 15 files changed, 101 insertions(+), 74 deletions(-) create mode 100644 tests/compile-fail/thread-spawn.rs create mode 100644 tests/run-pass/concurrency/locks.stderr delete mode 100644 tests/run-pass/concurrency/locks.stdout create mode 100644 tests/run-pass/concurrency/simple.stderr delete mode 100644 tests/run-pass/concurrency/simple.stdout create mode 100644 tests/run-pass/concurrency/thread_locals.stderr delete mode 100644 tests/run-pass/concurrency/thread_locals.stdout diff --git a/src/eval.rs b/src/eval.rs index b0a59c64d1e16..d83039e475684 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -206,7 +206,7 @@ pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) -> let res: InterpResult<'_, i64> = (|| { // Main loop. while ecx.schedule()? { - assert!(ecx.step()?); + assert!(ecx.step()?, "Bug: a terminated thread was scheduled for execution."); ecx.process_diagnostics(); } // Read the return code pointer *before* we run TLS destructors, to assert diff --git a/src/machine.rs b/src/machine.rs index a5183d3e8166a..0920364a44a8e 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -428,41 +428,37 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { mir::interpret::ConstValue::Scalar(Scalar::Ptr(ptr)) => { let alloc_id = ptr.alloc_id; let alloc = ecx.tcx.alloc_map.lock().get(alloc_id); + let tcx = ecx.tcx; + let is_thread_local = |def_id| { + tcx.codegen_fn_attrs(def_id).flags.contains(CodegenFnAttrFlags::THREAD_LOCAL) + }; match alloc { - Some(GlobalAlloc::Static(def_id)) - if ecx - .tcx - .codegen_fn_attrs(def_id) - .flags - .contains(CodegenFnAttrFlags::THREAD_LOCAL) => - { - // We have a thread-local static. + Some(GlobalAlloc::Static(def_id)) if is_thread_local(def_id) => { let new_alloc_id = if let Some(new_alloc_id) = ecx.get_thread_local_alloc_id(alloc_id) { new_alloc_id } else { - if ecx.tcx.is_foreign_item(def_id) { + if tcx.is_foreign_item(def_id) { throw_unsup_format!( "Foreign thread-local statics are not supported." ) } - let instance = Instance::mono(ecx.tcx.tcx, def_id); + let instance = Instance::mono(tcx.tcx, def_id); let gid = GlobalId { instance, promoted: None }; - let raw_const = ecx - .tcx + let raw_const = tcx .const_eval_raw(ty::ParamEnv::reveal_all().and(gid)) .map_err(|err| { // no need to report anything, the const_eval call takes care of that // for statics - assert!(ecx.tcx.is_static(def_id)); + assert!(tcx.is_static(def_id)); match err { ErrorHandled::Reported => err_inval!(ReferencedConstant), ErrorHandled::TooGeneric => err_inval!(TooGeneric), } })?; let id = raw_const.alloc_id; - let mut alloc_map = ecx.tcx.alloc_map.lock(); + let mut alloc_map = tcx.alloc_map.lock(); let allocation = alloc_map.unwrap_memory(id); let new_alloc_id = alloc_map.create_memory_alloc(allocation); ecx.set_thread_local_alloc_id(alloc_id, new_alloc_id); diff --git a/src/shims/foreign_items/posix.rs b/src/shims/foreign_items/posix.rs index 4cd3b84991128..5bb556aaa50b0 100644 --- a/src/shims/foreign_items/posix.rs +++ b/src/shims/foreign_items/posix.rs @@ -293,26 +293,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_i32(result), dest)?; } - // Miscellaneous - "isatty" => { - let _fd = this.read_scalar(args[0])?.to_i32()?; - // "returns 1 if fd is an open file descriptor referring to a terminal; otherwise 0 is returned, and errno is set to indicate the error" - // FIXME: we just say nothing is a terminal. - let enotty = this.eval_libc("ENOTTY")?; - this.set_last_error(enotty)?; - this.write_null(dest)?; - } - "pthread_atfork" => { - let _prepare = this.read_scalar(args[0])?.not_undef()?; - let _parent = this.read_scalar(args[1])?.not_undef()?; - let _child = this.read_scalar(args[1])?.not_undef()?; - // We do not support forking, so there is nothing to do here. - this.write_null(dest)?; - } - "sched_yield" => { - this.write_null(dest)?; - } - // Threading "pthread_create" => { assert_eq!(args.len(), 4); @@ -339,20 +319,20 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_i32(result), dest)?; } - "pthread_attr_getguardsize" => { - assert_eq!(args.len(), 2); - - let guard_size = this.deref_operand(args[1])?; - let guard_size_type = args[1].layout.ty - .builtin_deref(true) - .ok_or_else(|| err_ub_format!( - "wrong signature used for `pthread_attr_getguardsize`: first argument must be a raw pointer." - ))? - .ty; - let guard_size_layout = this.layout_of(guard_size_type)?; - this.write_scalar(Scalar::from_uint(crate::PAGE_SIZE, guard_size_layout.size), guard_size.into())?; - - // Return success (`0`). + // Miscellaneous + "isatty" => { + let _fd = this.read_scalar(args[0])?.to_i32()?; + // "returns 1 if fd is an open file descriptor referring to a terminal; otherwise 0 is returned, and errno is set to indicate the error" + // FIXME: we just say nothing is a terminal. + let enotty = this.eval_libc("ENOTTY")?; + this.set_last_error(enotty)?; + this.write_null(dest)?; + } + "pthread_atfork" => { + let _prepare = this.read_scalar(args[0])?.not_undef()?; + let _parent = this.read_scalar(args[1])?.not_undef()?; + let _child = this.read_scalar(args[1])?.not_undef()?; + // We do not support forking, so there is nothing to do here. this.write_null(dest)?; } @@ -369,6 +349,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx => { this.write_null(dest)?; } + "pthread_attr_getguardsize" if this.frame().instance.to_string().starts_with("std::sys::unix::") + => { + let guard_size = this.deref_operand(args[1])?; + let guard_size_layout = this.libc_ty_layout("size_t")?; + this.write_scalar(Scalar::from_uint(crate::PAGE_SIZE, guard_size_layout.size), guard_size.into())?; + + // Return success (`0`). + this.write_null(dest)?; + } | "signal" | "sigaction" diff --git a/src/shims/threads.rs b/src/shims/threads.rs index fc733d7f5c9f2..d8ba11d267f39 100644 --- a/src/shims/threads.rs +++ b/src/shims/threads.rs @@ -11,13 +11,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx start_routine: OpTy<'tcx, Tag>, arg: OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, i32> { - println!( - "WARNING: The thread support is experimental. \ - For example, Miri does not detect data races yet." - ); - let this = self.eval_context_mut(); + this.tcx.sess.warn( + "The thread support is experimental. \ + For example, Miri does not detect data races yet.", + ); + let new_thread_id = this.create_thread()?; let old_thread_id = this.set_active_thread(new_thread_id)?; @@ -57,6 +57,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(0) } + fn pthread_join( &mut self, thread: OpTy<'tcx, Tag>, @@ -73,6 +74,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(0) } + fn pthread_detach(&mut self, thread: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); @@ -81,12 +83,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(0) } + fn pthread_self(&mut self, dest: PlaceTy<'tcx, Tag>) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let thread_id = this.get_active_thread()?; this.write_scalar(Scalar::from_uint(thread_id.index() as u128, dest.layout.size), dest) } + fn prctl( &mut self, option: OpTy<'tcx, Tag>, diff --git a/src/threads.rs b/src/threads.rs index 170fb0c4767ef..c623fcae817dd 100644 --- a/src/threads.rs +++ b/src/threads.rs @@ -2,6 +2,7 @@ use std::cell::RefCell; use std::convert::TryFrom; +use std::num::NonZeroU32; use log::trace; @@ -42,21 +43,18 @@ impl ThreadId { } /// An identifier of a set of blocked threads. -/// -/// Note: 0 is not a valid identifier. #[derive(Clone, Copy, Debug, PartialOrd, Ord, PartialEq, Eq, Hash)] -pub struct BlockSetId(u32); +pub struct BlockSetId(NonZeroU32); impl From for BlockSetId { fn from(id: u32) -> Self { - assert_ne!(id, 0, "0 is not a valid blockset id"); - Self(id) + Self(NonZeroU32::new(id).expect("0 is not a valid blockset id")) } } impl BlockSetId { pub fn to_u32_scalar<'tcx>(&self) -> Scalar { - Scalar::from_u32(self.0) + Scalar::from_u32(self.0.get()) } } @@ -150,6 +148,7 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { pub fn get_thread_local_alloc_id(&self, static_alloc_id: AllocId) -> Option { self.thread_local_alloc_ids.borrow().get(&(static_alloc_id, self.active_thread)).cloned() } + /// Set the allocation id as the allocation id of the given thread local /// static for the active thread. pub fn set_thread_local_alloc_id(&self, static_alloc_id: AllocId, new_alloc_id: AllocId) { @@ -161,20 +160,24 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { "Bug: a thread local initialized twice for the same thread." ); } + /// Borrow the stack of the active thread. fn active_thread_stack(&self) -> &[Frame<'mir, 'tcx, Tag, FrameData<'tcx>>] { &self.threads[self.active_thread].stack } + /// Mutably borrow the stack of the active thread. fn active_thread_stack_mut(&mut self) -> &mut Vec>> { &mut self.threads[self.active_thread].stack } + /// Create a new thread and returns its id. fn create_thread(&mut self) -> ThreadId { let new_thread_id = ThreadId::new(self.threads.len()); self.threads.push(Default::default()); new_thread_id } + /// Set an active thread and return the id of the thread that was active before. fn set_active_thread_id(&mut self, id: ThreadId) -> ThreadId { let active_thread_id = self.active_thread; @@ -182,19 +185,23 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { assert!(self.active_thread.index() < self.threads.len()); active_thread_id } + /// Get the id of the currently active thread. fn get_active_thread_id(&self) -> ThreadId { self.active_thread } + /// Get the borrow of the currently active thread. fn active_thread_mut(&mut self) -> &mut Thread<'mir, 'tcx> { &mut self.threads[self.active_thread] } + /// Mark the thread as detached, which means that no other thread will try /// to join it and the thread is responsible for cleaning up. fn detach_thread(&mut self, id: ThreadId) { self.threads[id].detached = true; } + /// Mark that the active thread tries to join the thread with `joined_thread_id`. fn join_thread(&mut self, joined_thread_id: ThreadId) { assert!(!self.threads[joined_thread_id].detached, "Bug: trying to join a detached thread."); @@ -215,23 +222,32 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { ); } } + /// Set the name of the active thread. fn set_thread_name(&mut self, new_thread_name: Vec) { self.active_thread_mut().thread_name = Some(new_thread_name); } + /// Get ids and states of all threads ever allocated. fn get_all_thread_ids_with_states(&self) -> Vec<(ThreadId, ThreadState)> { self.threads.iter_enumerated().map(|(id, thread)| (id, thread.state)).collect() } + + /// Allocate a new blockset id. fn create_blockset(&mut self) -> BlockSetId { self.blockset_counter = self.blockset_counter.checked_add(1).unwrap(); self.blockset_counter.into() } + + /// Block the currently active thread and put it into the given blockset. fn block_active_thread(&mut self, set: BlockSetId) { let state = &mut self.active_thread_mut().state; assert_eq!(*state, ThreadState::Enabled); *state = ThreadState::Blocked(set); } + + /// Unblock any one thread from the given blockset if it contains at least + /// one. Return the id of the unblocked thread. fn unblock_random_thread(&mut self, set: BlockSetId) -> Option { for (id, thread) in self.threads.iter_enumerated_mut() { if thread.state == ThreadState::Blocked(set) { @@ -242,6 +258,7 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { } None } + /// Decide which thread to run next. /// /// Returns `false` if all threads terminated. @@ -278,60 +295,74 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_ref(); this.machine.threads.get_thread_local_alloc_id(static_alloc_id) } + fn set_thread_local_alloc_id(&self, static_alloc_id: AllocId, thread_local_alloc_id: AllocId) { let this = self.eval_context_ref(); this.machine.threads.set_thread_local_alloc_id(static_alloc_id, thread_local_alloc_id) } + fn create_thread(&mut self) -> InterpResult<'tcx, ThreadId> { let this = self.eval_context_mut(); Ok(this.machine.threads.create_thread()) } + fn detach_thread(&mut self, thread_id: ThreadId) -> InterpResult<'tcx> { let this = self.eval_context_mut(); this.machine.threads.detach_thread(thread_id); Ok(()) } + fn join_thread(&mut self, joined_thread_id: ThreadId) -> InterpResult<'tcx> { let this = self.eval_context_mut(); this.machine.threads.join_thread(joined_thread_id); Ok(()) } + fn set_active_thread(&mut self, thread_id: ThreadId) -> InterpResult<'tcx, ThreadId> { let this = self.eval_context_mut(); Ok(this.machine.threads.set_active_thread_id(thread_id)) } + fn get_active_thread(&self) -> InterpResult<'tcx, ThreadId> { let this = self.eval_context_ref(); Ok(this.machine.threads.get_active_thread_id()) } + fn active_thread_stack(&self) -> &[Frame<'mir, 'tcx, Tag, FrameData<'tcx>>] { let this = self.eval_context_ref(); this.machine.threads.active_thread_stack() } + fn active_thread_stack_mut(&mut self) -> &mut Vec>> { let this = self.eval_context_mut(); this.machine.threads.active_thread_stack_mut() } + fn set_active_thread_name(&mut self, new_thread_name: Vec) -> InterpResult<'tcx, ()> { let this = self.eval_context_mut(); Ok(this.machine.threads.set_thread_name(new_thread_name)) } + fn get_all_thread_ids_with_states(&mut self) -> Vec<(ThreadId, ThreadState)> { let this = self.eval_context_mut(); this.machine.threads.get_all_thread_ids_with_states() } + fn create_blockset(&mut self) -> InterpResult<'tcx, BlockSetId> { let this = self.eval_context_mut(); Ok(this.machine.threads.create_blockset()) } + fn block_active_thread(&mut self, set: BlockSetId) -> InterpResult<'tcx> { let this = self.eval_context_mut(); Ok(this.machine.threads.block_active_thread(set)) } + fn unblock_random_thread(&mut self, set: BlockSetId) -> InterpResult<'tcx, Option> { let this = self.eval_context_mut(); Ok(this.machine.threads.unblock_random_thread(set)) } + /// Decide which thread to run next. /// /// Returns `false` if all threads terminated. diff --git a/tests/compile-fail/thread-spawn.rs b/tests/compile-fail/thread-spawn.rs new file mode 100644 index 0000000000000..4b9073f3a73ee --- /dev/null +++ b/tests/compile-fail/thread-spawn.rs @@ -0,0 +1,9 @@ +// ignore-linux +// ignore-macos +use std::thread; + +// error-pattern: Miri does not support threading + +fn main() { + thread::spawn(|| {}); +} diff --git a/tests/run-pass/concurrency/locks.rs b/tests/run-pass/concurrency/locks.rs index 575aeadd7fedf..49935db91bd94 100644 --- a/tests/run-pass/concurrency/locks.rs +++ b/tests/run-pass/concurrency/locks.rs @@ -1,3 +1,5 @@ +// ignore-windows + //! This test just calls the relevant APIs to check if Miri crashes. use std::sync::{Arc, Mutex}; diff --git a/tests/run-pass/concurrency/locks.stderr b/tests/run-pass/concurrency/locks.stderr new file mode 100644 index 0000000000000..20a2bf3eeb878 --- /dev/null +++ b/tests/run-pass/concurrency/locks.stderr @@ -0,0 +1,2 @@ +warning: The thread support is experimental. For example, Miri does not detect data races yet. + diff --git a/tests/run-pass/concurrency/locks.stdout b/tests/run-pass/concurrency/locks.stdout deleted file mode 100644 index 2486b320db18f..0000000000000 --- a/tests/run-pass/concurrency/locks.stdout +++ /dev/null @@ -1,3 +0,0 @@ -WARNING: The thread support is experimental. For example, Miri does not detect data races yet. -WARNING: The thread support is experimental. For example, Miri does not detect data races yet. -WARNING: The thread support is experimental. For example, Miri does not detect data races yet. diff --git a/tests/run-pass/concurrency/simple.rs b/tests/run-pass/concurrency/simple.rs index 5c295d1702dd8..5adc521f59c22 100644 --- a/tests/run-pass/concurrency/simple.rs +++ b/tests/run-pass/concurrency/simple.rs @@ -1,3 +1,5 @@ +// ignore-windows + use std::thread; fn create_and_detach() { diff --git a/tests/run-pass/concurrency/simple.stderr b/tests/run-pass/concurrency/simple.stderr new file mode 100644 index 0000000000000..20a2bf3eeb878 --- /dev/null +++ b/tests/run-pass/concurrency/simple.stderr @@ -0,0 +1,2 @@ +warning: The thread support is experimental. For example, Miri does not detect data races yet. + diff --git a/tests/run-pass/concurrency/simple.stdout b/tests/run-pass/concurrency/simple.stdout deleted file mode 100644 index 0506b7bdf83c0..0000000000000 --- a/tests/run-pass/concurrency/simple.stdout +++ /dev/null @@ -1,10 +0,0 @@ -WARNING: The thread support is experimental. For example, Miri does not detect data races yet. -WARNING: The thread support is experimental. For example, Miri does not detect data races yet. -WARNING: The thread support is experimental. For example, Miri does not detect data races yet. -WARNING: The thread support is experimental. For example, Miri does not detect data races yet. -WARNING: The thread support is experimental. For example, Miri does not detect data races yet. -WARNING: The thread support is experimental. For example, Miri does not detect data races yet. -WARNING: The thread support is experimental. For example, Miri does not detect data races yet. -WARNING: The thread support is experimental. For example, Miri does not detect data races yet. -WARNING: The thread support is experimental. For example, Miri does not detect data races yet. -WARNING: The thread support is experimental. For example, Miri does not detect data races yet. diff --git a/tests/run-pass/concurrency/thread_locals.rs b/tests/run-pass/concurrency/thread_locals.rs index 50aa6fee2f876..1805a1da3d0bf 100644 --- a/tests/run-pass/concurrency/thread_locals.rs +++ b/tests/run-pass/concurrency/thread_locals.rs @@ -1,3 +1,5 @@ +// ignore-windows + #![feature(thread_local)] use std::thread; diff --git a/tests/run-pass/concurrency/thread_locals.stderr b/tests/run-pass/concurrency/thread_locals.stderr new file mode 100644 index 0000000000000..20a2bf3eeb878 --- /dev/null +++ b/tests/run-pass/concurrency/thread_locals.stderr @@ -0,0 +1,2 @@ +warning: The thread support is experimental. For example, Miri does not detect data races yet. + diff --git a/tests/run-pass/concurrency/thread_locals.stdout b/tests/run-pass/concurrency/thread_locals.stdout deleted file mode 100644 index 9a53b4a5c913b..0000000000000 --- a/tests/run-pass/concurrency/thread_locals.stdout +++ /dev/null @@ -1 +0,0 @@ -WARNING: The thread support is experimental. For example, Miri does not detect data races yet. From 4609c3c520f8b9b4d014f4a0a8ee12528fba6211 Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Thu, 16 Apr 2020 08:34:30 -0700 Subject: [PATCH 1941/3747] Rename eval_maybe_thread_local_static_const to adjust_global_const. --- src/machine.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/machine.rs b/src/machine.rs index 0920364a44a8e..d79e0255f0250 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -420,7 +420,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { Ok(()) } - fn eval_maybe_thread_local_static_const( + fn adjust_global_const( ecx: &InterpCx<'mir, 'tcx, Self>, mut val: mir::interpret::ConstValue<'tcx>, ) -> InterpResult<'tcx, mir::interpret::ConstValue<'tcx>> { From d9ec0f2b36cc53e770193fa5a409f51cc3a7cc5a Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Thu, 16 Apr 2020 12:21:01 -0700 Subject: [PATCH 1942/3747] Add a missing newline in the test. --- tests/run-pass/concurrency/locks.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/tests/run-pass/concurrency/locks.rs b/tests/run-pass/concurrency/locks.rs index 49935db91bd94..3c8373691b842 100644 --- a/tests/run-pass/concurrency/locks.rs +++ b/tests/run-pass/concurrency/locks.rs @@ -6,7 +6,6 @@ use std::sync::{Arc, Mutex}; use std::thread; fn main() { - let data = Arc::new(Mutex::new(0)); let mut threads = Vec::new(); @@ -27,5 +26,4 @@ fn main() { let data = Arc::try_unwrap(data).unwrap().into_inner().unwrap(); assert_eq!(data, 3); - -} \ No newline at end of file +} From 552080a5b7c4ec01d3ed74b411bfefaaebf70feb Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Thu, 16 Apr 2020 12:22:30 -0700 Subject: [PATCH 1943/3747] Fix imports. --- src/lib.rs | 4 +++- src/machine.rs | 2 -- src/shims/tls.rs | 6 ++++-- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index d8b3397c8e9ba..bedacf705ac48 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -63,7 +63,9 @@ pub use crate::range_map::RangeMap; pub use crate::stacked_borrows::{ EvalContextExt as StackedBorEvalContextExt, Item, Permission, PtrId, Stack, Stacks, Tag, }; -pub use crate::threads::EvalContextExt as ThreadsEvalContextExt; +pub use crate::threads::{ + EvalContextExt as ThreadsEvalContextExt, ThreadId, ThreadManager, ThreadState, +}; /// Insert rustc arguments at the beginning of the argument list that Miri wants to be /// set per default, for maximal validation power. diff --git a/src/machine.rs b/src/machine.rs index d79e0255f0250..23d4e37c66d17 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -28,8 +28,6 @@ use rustc_target::abi::{LayoutOf, Size}; use crate::*; -pub use crate::threads::{ThreadId, ThreadManager, ThreadState}; - // Some global facts about the emulated machine. pub const PAGE_SIZE: u64 = 4 * 1024; // FIXME: adjust to target architecture pub const STACK_ADDR: u64 = 32 * PAGE_SIZE; // not really about the "stack", but where we start assigning integer addresses to allocations diff --git a/src/shims/tls.rs b/src/shims/tls.rs index 5cef3871c033f..da0c585958a3c 100644 --- a/src/shims/tls.rs +++ b/src/shims/tls.rs @@ -8,8 +8,10 @@ use log::trace; use rustc_middle::ty; use rustc_target::abi::{Size, HasDataLayout}; -use crate::{HelpersEvalContextExt, ThreadsEvalContextExt, InterpResult, MPlaceTy, Scalar, StackPopCleanup, Tag}; -use crate::machine::{ThreadId, ThreadState}; +use crate::{ + HelpersEvalContextExt, InterpResult, MPlaceTy, Scalar, StackPopCleanup, Tag, ThreadId, + ThreadState, ThreadsEvalContextExt, +}; pub type TlsKey = u128; From 94118d4d9ad4bbce3533638ca5fc540275d14a69 Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Thu, 16 Apr 2020 12:22:58 -0700 Subject: [PATCH 1944/3747] Make an assert message consistent with other asserts. --- src/eval.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/eval.rs b/src/eval.rs index d83039e475684..085a53862fd44 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -206,7 +206,7 @@ pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) -> let res: InterpResult<'_, i64> = (|| { // Main loop. while ecx.schedule()? { - assert!(ecx.step()?, "Bug: a terminated thread was scheduled for execution."); + assert!(ecx.step()?, "a terminated thread was scheduled for execution"); ecx.process_diagnostics(); } // Read the return code pointer *before* we run TLS destructors, to assert From 1d0eb93ebddd35126cc22f938ff9247ff0e27b0b Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Thu, 16 Apr 2020 12:26:32 -0700 Subject: [PATCH 1945/3747] Fix typo in a comment. --- src/shims/foreign_items/posix.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shims/foreign_items/posix.rs b/src/shims/foreign_items/posix.rs index 5bb556aaa50b0..9e85bcc66bb2a 100644 --- a/src/shims/foreign_items/posix.rs +++ b/src/shims/foreign_items/posix.rs @@ -336,7 +336,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_null(dest)?; } - // Incomplete shims that we "stub out" just to get pre-main initialziation code to work. + // Incomplete shims that we "stub out" just to get pre-main initialization code to work. // These shims are enabled only when the caller is in the standard library. | "pthread_attr_init" | "pthread_attr_destroy" From 688cacbdd73427ec5bd86300cc75a07fa89ec310 Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Thu, 16 Apr 2020 13:32:40 -0700 Subject: [PATCH 1946/3747] Cleanup the implementation of adjust_global_const. --- src/machine.rs | 50 +---------------------- src/threads.rs | 106 +++++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 94 insertions(+), 62 deletions(-) diff --git a/src/machine.rs b/src/machine.rs index 23d4e37c66d17..a81273960d09f 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -14,11 +14,9 @@ use rand::rngs::StdRng; use rustc_ast::attr; use rustc_data_structures::fx::FxHashMap; use rustc_middle::{ - middle::codegen_fn_attrs::CodegenFnAttrFlags, mir, ty::{ self, - Instance, layout::{LayoutCx, LayoutError, TyAndLayout}, TyCtxt, }, @@ -422,53 +420,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { ecx: &InterpCx<'mir, 'tcx, Self>, mut val: mir::interpret::ConstValue<'tcx>, ) -> InterpResult<'tcx, mir::interpret::ConstValue<'tcx>> { - match &mut val { - mir::interpret::ConstValue::Scalar(Scalar::Ptr(ptr)) => { - let alloc_id = ptr.alloc_id; - let alloc = ecx.tcx.alloc_map.lock().get(alloc_id); - let tcx = ecx.tcx; - let is_thread_local = |def_id| { - tcx.codegen_fn_attrs(def_id).flags.contains(CodegenFnAttrFlags::THREAD_LOCAL) - }; - match alloc { - Some(GlobalAlloc::Static(def_id)) if is_thread_local(def_id) => { - let new_alloc_id = if let Some(new_alloc_id) = - ecx.get_thread_local_alloc_id(alloc_id) - { - new_alloc_id - } else { - if tcx.is_foreign_item(def_id) { - throw_unsup_format!( - "Foreign thread-local statics are not supported." - ) - } - let instance = Instance::mono(tcx.tcx, def_id); - let gid = GlobalId { instance, promoted: None }; - let raw_const = tcx - .const_eval_raw(ty::ParamEnv::reveal_all().and(gid)) - .map_err(|err| { - // no need to report anything, the const_eval call takes care of that - // for statics - assert!(tcx.is_static(def_id)); - match err { - ErrorHandled::Reported => err_inval!(ReferencedConstant), - ErrorHandled::TooGeneric => err_inval!(TooGeneric), - } - })?; - let id = raw_const.alloc_id; - let mut alloc_map = tcx.alloc_map.lock(); - let allocation = alloc_map.unwrap_memory(id); - let new_alloc_id = alloc_map.create_memory_alloc(allocation); - ecx.set_thread_local_alloc_id(alloc_id, new_alloc_id); - new_alloc_id - }; - ptr.alloc_id = new_alloc_id; - } - _ => {} - } - } - _ => {} - } + ecx.remap_thread_local_alloc_ids(&mut val)?; Ok(val) } diff --git a/src/threads.rs b/src/threads.rs index c623fcae817dd..c8348e262696a 100644 --- a/src/threads.rs +++ b/src/threads.rs @@ -7,7 +7,13 @@ use std::num::NonZeroU32; use log::trace; use rustc_data_structures::fx::FxHashMap; +use rustc_hir::def_id::DefId; use rustc_index::vec::{Idx, IndexVec}; +use rustc_middle::{ + middle::codegen_fn_attrs::CodegenFnAttrFlags, + mir, + ty::{self, Instance}, +}; use crate::*; @@ -124,9 +130,9 @@ pub struct ThreadManager<'mir, 'tcx> { threads: IndexVec>, /// A counter used to generate unique identifiers for blocksets. blockset_counter: u32, - /// A mapping from an allocation id of a thread-local static to an - /// allocation id of a thread specific allocation. - thread_local_alloc_ids: RefCell>, + /// A mapping from a thread-local static to an allocation id of a thread + /// specific allocation. + thread_local_alloc_ids: RefCell>, } impl<'mir, 'tcx> Default for ThreadManager<'mir, 'tcx> { @@ -145,19 +151,19 @@ impl<'mir, 'tcx> Default for ThreadManager<'mir, 'tcx> { impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { /// Check if we have an allocation for the given thread local static for the /// active thread. - pub fn get_thread_local_alloc_id(&self, static_alloc_id: AllocId) -> Option { - self.thread_local_alloc_ids.borrow().get(&(static_alloc_id, self.active_thread)).cloned() + pub fn get_thread_local_alloc_id(&self, def_id: DefId) -> Option { + self.thread_local_alloc_ids.borrow().get(&(def_id, self.active_thread)).cloned() } /// Set the allocation id as the allocation id of the given thread local /// static for the active thread. - pub fn set_thread_local_alloc_id(&self, static_alloc_id: AllocId, new_alloc_id: AllocId) { + pub fn set_thread_local_alloc_id(&self, def_id: DefId, new_alloc_id: AllocId) { assert!( self.thread_local_alloc_ids .borrow_mut() - .insert((static_alloc_id, self.active_thread), new_alloc_id) + .insert((def_id, self.active_thread), new_alloc_id) .is_none(), - "Bug: a thread local initialized twice for the same thread." + "a thread local initialized twice for the same thread" ); } @@ -291,14 +297,88 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { - fn get_thread_local_alloc_id(&self, static_alloc_id: AllocId) -> Option { + /// A workaround for thread-local statics until + /// https://github.com/rust-lang/rust/issues/70685 is fixed: change the + /// thread-local allocation id with a freshly generated allocation id for + /// the currently active thread. + fn remap_thread_local_alloc_ids( + &self, + val: &mut mir::interpret::ConstValue<'tcx>, + ) -> InterpResult<'tcx> { let this = self.eval_context_ref(); - this.machine.threads.get_thread_local_alloc_id(static_alloc_id) + match val { + mir::interpret::ConstValue::Scalar(Scalar::Ptr(ptr)) => { + let alloc_id = ptr.alloc_id; + let alloc = this.tcx.alloc_map.lock().get(alloc_id); + let tcx = this.tcx; + let is_thread_local = |def_id| { + tcx.codegen_fn_attrs(def_id).flags.contains(CodegenFnAttrFlags::THREAD_LOCAL) + }; + match alloc { + Some(GlobalAlloc::Static(def_id)) if is_thread_local(def_id) => { + ptr.alloc_id = this.get_or_create_thread_local_alloc_id(def_id)?; + } + _ => {} + } + } + _ => { + // FIXME: Handling only `Scalar` seems to work for now, but at + // least in principle thread-locals could be in any constant, so + // we should also consider other cases. However, once + // https://github.com/rust-lang/rust/issues/70685 gets fixed, + // this code will have to be rewritten anyway. + } + } + Ok(()) } - - fn set_thread_local_alloc_id(&self, static_alloc_id: AllocId, thread_local_alloc_id: AllocId) { + /// Get a thread-specific allocation id for the given thread-local static. + /// If needed, allocate a new one. + /// + /// FIXME: This method should be replaced as soon as + /// https://github.com/rust-lang/rust/issues/70685 gets fixed. + fn get_or_create_thread_local_alloc_id(&self, def_id: DefId) -> InterpResult<'tcx, AllocId> { let this = self.eval_context_ref(); - this.machine.threads.set_thread_local_alloc_id(static_alloc_id, thread_local_alloc_id) + let tcx = this.tcx; + if let Some(new_alloc_id) = this.machine.threads.get_thread_local_alloc_id(def_id) { + // We already have a thread-specific allocation id for this + // thread-local static. + Ok(new_alloc_id) + } else { + // We need to allocate a thread-specific allocation id for this + // thread-local static. + // + // At first, we invoke the `const_eval_raw` query and extract the + // allocation from it. Unfortunately, we have to duplicate the code + // from `Memory::get_global_alloc` that does this. + // + // Then we store the retrieved allocation back into the `alloc_map` + // to get a fresh allocation id, which we can use as a + // thread-specific allocation id for the thread-local static. + if tcx.is_foreign_item(def_id) { + throw_unsup_format!("foreign thread-local statics are not supported"); + } + // Invoke the `const_eval_raw` query. + let instance = Instance::mono(tcx.tcx, def_id); + let gid = GlobalId { instance, promoted: None }; + let raw_const = + tcx.const_eval_raw(ty::ParamEnv::reveal_all().and(gid)).map_err(|err| { + // no need to report anything, the const_eval call takes care of that + // for statics + assert!(tcx.is_static(def_id)); + err + })?; + let id = raw_const.alloc_id; + // Extract the allocation from the query result. + let mut alloc_map = tcx.alloc_map.lock(); + let allocation = alloc_map.unwrap_memory(id); + // Create a new allocation id for the same allocation in this hacky + // way. Internally, `alloc_map` deduplicates allocations, but this + // is fine because Miri will make a copy before a first mutable + // access. + let new_alloc_id = alloc_map.create_memory_alloc(allocation); + this.machine.threads.set_thread_local_alloc_id(def_id, new_alloc_id); + Ok(new_alloc_id) + } } fn create_thread(&mut self) -> InterpResult<'tcx, ThreadId> { From a585dc8289120aa4ee232c1f8317a21eb5ae2c1a Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Thu, 16 Apr 2020 13:39:21 -0700 Subject: [PATCH 1947/3747] Add a missing newline. --- src/threads.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/threads.rs b/src/threads.rs index c8348e262696a..72584b7265577 100644 --- a/src/threads.rs +++ b/src/threads.rs @@ -331,6 +331,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } Ok(()) } + /// Get a thread-specific allocation id for the given thread-local static. /// If needed, allocate a new one. /// From 44e930559917968d4513e5915f5957f2fe1f3e11 Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Thu, 16 Apr 2020 13:52:14 -0700 Subject: [PATCH 1948/3747] Rename threads to thread to match the Rust standard library. --- src/lib.rs | 6 +++--- src/shims/mod.rs | 2 +- src/shims/sync.rs | 2 +- src/shims/{threads.rs => thread.rs} | 0 src/{threads.rs => thread.rs} | 0 5 files changed, 5 insertions(+), 5 deletions(-) rename src/shims/{threads.rs => thread.rs} (100%) rename src/{threads.rs => thread.rs} (100%) diff --git a/src/lib.rs b/src/lib.rs index bedacf705ac48..96e6f7d63e69f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -27,7 +27,7 @@ mod operator; mod range_map; mod shims; mod stacked_borrows; -mod threads; +mod thread; // Make all those symbols available in the same place as our own. pub use rustc_mir::interpret::*; @@ -42,7 +42,7 @@ pub use crate::shims::intrinsics::EvalContextExt as IntrinsicsEvalContextExt; pub use crate::shims::os_str::EvalContextExt as OsStrEvalContextExt; pub use crate::shims::panic::{CatchUnwindData, EvalContextExt as PanicEvalContextExt}; pub use crate::shims::sync::{EvalContextExt as SyncEvalContextExt}; -pub use crate::shims::threads::EvalContextExt as ThreadShimsEvalContextExt; +pub use crate::shims::thread::EvalContextExt as ThreadShimsEvalContextExt; pub use crate::shims::time::EvalContextExt as TimeEvalContextExt; pub use crate::shims::tls::{EvalContextExt as TlsEvalContextExt, TlsData}; pub use crate::shims::EvalContextExt as ShimsEvalContextExt; @@ -63,7 +63,7 @@ pub use crate::range_map::RangeMap; pub use crate::stacked_borrows::{ EvalContextExt as StackedBorEvalContextExt, Item, Permission, PtrId, Stack, Stacks, Tag, }; -pub use crate::threads::{ +pub use crate::thread::{ EvalContextExt as ThreadsEvalContextExt, ThreadId, ThreadManager, ThreadState, }; diff --git a/src/shims/mod.rs b/src/shims/mod.rs index 118058dd32e74..166d1a5456df1 100644 --- a/src/shims/mod.rs +++ b/src/shims/mod.rs @@ -6,7 +6,7 @@ pub mod intrinsics; pub mod os_str; pub mod panic; pub mod sync; -pub mod threads; +pub mod thread; pub mod time; pub mod tls; diff --git a/src/shims/sync.rs b/src/shims/sync.rs index 76f97aab23916..d8a00156384c3 100644 --- a/src/shims/sync.rs +++ b/src/shims/sync.rs @@ -2,7 +2,7 @@ use rustc_middle::ty::{layout::TyAndLayout, TyKind, TypeAndMut}; use rustc_target::abi::{LayoutOf, Size}; use crate::stacked_borrows::Tag; -use crate::threads::{BlockSetId, ThreadId}; +use crate::thread::BlockSetId; use crate::*; fn assert_ptr_target_min_size<'mir, 'tcx: 'mir>( diff --git a/src/shims/threads.rs b/src/shims/thread.rs similarity index 100% rename from src/shims/threads.rs rename to src/shims/thread.rs diff --git a/src/threads.rs b/src/thread.rs similarity index 100% rename from src/threads.rs rename to src/thread.rs From d062f63519bfe7e366f0cadfdb15073434558351 Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Thu, 16 Apr 2020 19:40:02 -0700 Subject: [PATCH 1949/3747] Fix support for MacOS. --- src/eval.rs | 16 ++- src/lib.rs | 2 +- src/shims/foreign_items/posix/macos.rs | 3 +- src/shims/tls.rs | 151 ++++++++++++++----------- src/thread.rs | 49 ++++---- 5 files changed, 128 insertions(+), 93 deletions(-) diff --git a/src/eval.rs b/src/eval.rs index 085a53862fd44..ab82c39836b2e 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -205,15 +205,25 @@ pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) -> // Perform the main execution. let res: InterpResult<'_, i64> = (|| { // Main loop. - while ecx.schedule()? { - assert!(ecx.step()?, "a terminated thread was scheduled for execution"); + loop { + match ecx.schedule()? { + SchedulingAction::ExecuteStep => { + assert!(ecx.step()?, "a terminated thread was scheduled for execution"); + } + SchedulingAction::ExecuteDtors => { + ecx.run_tls_dtors_for_active_thread()?; + } + SchedulingAction::Stop => { + break; + } + } ecx.process_diagnostics(); } // Read the return code pointer *before* we run TLS destructors, to assert // that it was written to by the time that `start` lang item returned. let return_code = ecx.read_scalar(ret_place.into())?.not_undef()?.to_machine_isize(&ecx)?; // Global destructors. - ecx.run_tls_dtors()?; + ecx.run_windows_tls_dtors()?; Ok(return_code) })(); diff --git a/src/lib.rs b/src/lib.rs index 96e6f7d63e69f..beee94b918b56 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -64,7 +64,7 @@ pub use crate::stacked_borrows::{ EvalContextExt as StackedBorEvalContextExt, Item, Permission, PtrId, Stack, Stacks, Tag, }; pub use crate::thread::{ - EvalContextExt as ThreadsEvalContextExt, ThreadId, ThreadManager, ThreadState, + EvalContextExt as ThreadsEvalContextExt, SchedulingAction, ThreadId, ThreadManager, ThreadState, }; /// Insert rustc arguments at the beginning of the argument list that Miri wants to be diff --git a/src/shims/foreign_items/posix/macos.rs b/src/shims/foreign_items/posix/macos.rs index dd3dba6ec07cc..9f65d0f9c47d7 100644 --- a/src/shims/foreign_items/posix/macos.rs +++ b/src/shims/foreign_items/posix/macos.rs @@ -82,7 +82,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let dtor = this.read_scalar(args[0])?.not_undef()?; let dtor = this.memory.get_fn(dtor)?.as_instance()?; let data = this.read_scalar(args[1])?.not_undef()?; - this.machine.tls.set_global_dtor(dtor, data)?; + let active_thread = this.get_active_thread()?; + this.machine.tls.set_global_dtor(active_thread, dtor, data)?; } // Querying system information diff --git a/src/shims/tls.rs b/src/shims/tls.rs index da0c585958a3c..6dc3025acd5ae 100644 --- a/src/shims/tls.rs +++ b/src/shims/tls.rs @@ -2,15 +2,17 @@ use std::collections::BTreeMap; use std::collections::btree_map::Entry; +use std::collections::HashSet; use log::trace; +use rustc_index::vec::Idx; use rustc_middle::ty; use rustc_target::abi::{Size, HasDataLayout}; use crate::{ HelpersEvalContextExt, InterpResult, MPlaceTy, Scalar, StackPopCleanup, Tag, ThreadId, - ThreadState, ThreadsEvalContextExt, + ThreadsEvalContextExt, }; pub type TlsKey = u128; @@ -32,11 +34,11 @@ pub struct TlsData<'tcx> { /// pthreads-style thread-local storage. keys: BTreeMap>, - /// A single global dtor (that's how things work on macOS) with a data argument. - global_dtor: Option<(ty::Instance<'tcx>, Scalar)>, + /// A single global per thread dtor (that's how things work on macOS) with a data argument. + global_dtors: BTreeMap, Scalar)>, /// Whether we are in the "destruct" phase, during which some operations are UB. - dtors_running: bool, + dtors_running: HashSet, } impl<'tcx> Default for TlsData<'tcx> { @@ -44,8 +46,8 @@ impl<'tcx> Default for TlsData<'tcx> { TlsData { next_key: 1, // start with 1 as we must not use 0 on Windows keys: Default::default(), - global_dtor: None, - dtors_running: false, + global_dtors: Default::default(), + dtors_running: Default::default(), } } } @@ -112,16 +114,15 @@ impl<'tcx> TlsData<'tcx> { } } - pub fn set_global_dtor(&mut self, dtor: ty::Instance<'tcx>, data: Scalar) -> InterpResult<'tcx> { - if self.dtors_running { + /// Set global dtor for the given thread. + pub fn set_global_dtor(&mut self, thread: ThreadId, dtor: ty::Instance<'tcx>, data: Scalar) -> InterpResult<'tcx> { + if self.dtors_running.contains(&thread) { // UB, according to libstd docs. throw_ub_format!("setting global destructor while destructors are already running"); } - if self.global_dtor.is_some() { - throw_unsup_format!("setting more than one global destructor is not supported"); + if self.global_dtors.insert(thread, (dtor, data)).is_some() { + throw_unsup_format!("setting more than one global destructor for the same thread is not supported"); } - - self.global_dtor = Some((dtor, data)); Ok(()) } @@ -148,7 +149,7 @@ impl<'tcx> TlsData<'tcx> { &mut self, key: Option, thread_id: ThreadId, - ) -> Option<(ty::Instance<'tcx>, ThreadId, Scalar, TlsKey)> { + ) -> Option<(ty::Instance<'tcx>, Scalar, TlsKey)> { use std::collections::Bound::*; let thread_local = &mut self.keys; @@ -161,9 +162,9 @@ impl<'tcx> TlsData<'tcx> { { match data.entry(thread_id) { Entry::Occupied(entry) => { - let (thread_id, data_scalar) = entry.remove_entry(); + let data_scalar = entry.remove(); if let Some(dtor) = dtor { - let ret = Some((*dtor, thread_id, data_scalar, key)); + let ret = Some((*dtor, data_scalar, key)); return ret; } } @@ -176,83 +177,99 @@ impl<'tcx> TlsData<'tcx> { impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { - /// Run TLS destructors for all threads. - fn run_tls_dtors(&mut self) -> InterpResult<'tcx> { + + /// Run TLS destructors for the main thread on Windows. The implementation + /// assumes that we do not support concurrency on Windows yet. + /// + /// Note: on non-Windows OS this function is a no-op. + fn run_windows_tls_dtors(&mut self) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - assert!(!this.machine.tls.dtors_running, "running TLS dtors twice"); - this.machine.tls.dtors_running = true; + if this.tcx.sess.target.target.target_os != "windows" { + return Ok(()); + } + let active_thread = this.get_active_thread()?; + assert_eq!(active_thread.index(), 0, "concurrency on Windows not supported"); + assert!(!this.machine.tls.dtors_running.contains(&active_thread), "running TLS dtors twice"); + this.machine.tls.dtors_running.insert(active_thread); + // Windows has a special magic linker section that is run on certain events. + // Instead of searching for that section and supporting arbitrary hooks in there + // (that would be basically https://github.com/rust-lang/miri/issues/450), + // we specifically look up the static in libstd that we know is placed + // in that section. + let thread_callback = this.eval_path_scalar(&["std", "sys", "windows", "thread_local", "p_thread_callback"])?; + let thread_callback = this.memory.get_fn(thread_callback.not_undef()?)?.as_instance()?; + + // The signature of this function is `unsafe extern "system" fn(h: c::LPVOID, dwReason: c::DWORD, pv: c::LPVOID)`. + let reason = this.eval_path_scalar(&["std", "sys", "windows", "c", "DLL_PROCESS_DETACH"])?; + let ret_place = MPlaceTy::dangling(this.machine.layouts.unit, this).into(); + this.call_function( + thread_callback, + &[Scalar::null_ptr(this).into(), reason.into(), Scalar::null_ptr(this).into()], + Some(ret_place), + StackPopCleanup::None { cleanup: true }, + )?; + + // step until out of stackframes + this.run()?; + + // Windows doesn't have other destructors. + Ok(()) + } + /// Run TLS destructors for the active thread. + /// + /// Note: on Windows OS this function is a no-op because we do not support + /// concurrency on Windows yet. + fn run_tls_dtors_for_active_thread(&mut self) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); if this.tcx.sess.target.target.target_os == "windows" { - // Windows has a special magic linker section that is run on certain events. - // Instead of searching for that section and supporting arbitrary hooks in there - // (that would be basically https://github.com/rust-lang/miri/issues/450), - // we specifically look up the static in libstd that we know is placed - // in that section. - let thread_callback = this.eval_path_scalar(&["std", "sys", "windows", "thread_local", "p_thread_callback"])?; - let thread_callback = this.memory.get_fn(thread_callback.not_undef()?)?.as_instance()?; - - // The signature of this function is `unsafe extern "system" fn(h: c::LPVOID, dwReason: c::DWORD, pv: c::LPVOID)`. - let reason = this.eval_path_scalar(&["std", "sys", "windows", "c", "DLL_PROCESS_DETACH"])?; + return Ok(()); + } + let thread_id = this.get_active_thread()?; + assert!(!this.machine.tls.dtors_running.contains(&thread_id), "running TLS dtors twice"); + this.machine.tls.dtors_running.insert(thread_id); + + // The macOS global dtor runs "before any TLS slots get freed", so do that first. + if let Some(&(instance, data)) = this.machine.tls.global_dtors.get(&thread_id) { + trace!("Running global dtor {:?} on {:?} at {:?}", instance, data, thread_id); + let ret_place = MPlaceTy::dangling(this.machine.layouts.unit, this).into(); this.call_function( - thread_callback, - &[Scalar::null_ptr(this).into(), reason.into(), Scalar::null_ptr(this).into()], + instance, + &[data.into()], Some(ret_place), StackPopCleanup::None { cleanup: true }, )?; // step until out of stackframes this.run()?; - - // Windows doesn't have other destructors. - return Ok(()); } - // The macOS global dtor runs "before any TLS slots get freed", so do that first. - if let Some((instance, data)) = this.machine.tls.global_dtor { - trace!("Running global dtor {:?} on {:?}", instance, data); + assert!(this.has_terminated(thread_id)?, "running TLS dtors for non-terminated thread"); + let mut dtor = this.machine.tls.fetch_tls_dtor(None, thread_id); + while let Some((instance, ptr, key)) = dtor { + trace!("Running TLS dtor {:?} on {:?} at {:?}", instance, ptr, thread_id); + assert!(!this.is_null(ptr).unwrap(), "Data can't be NULL when dtor is called!"); let ret_place = MPlaceTy::dangling(this.machine.layouts.unit, this).into(); this.call_function( instance, - &[data.into()], + &[ptr.into()], Some(ret_place), StackPopCleanup::None { cleanup: true }, )?; // step until out of stackframes this.run()?; - } - // Now run the "keyed" destructors. - for (thread_id, thread_state) in this.get_all_thread_ids_with_states() { - assert!(thread_state == ThreadState::Terminated, - "TLS destructors should be executed after all threads terminated."); - this.set_active_thread(thread_id)?; - let mut dtor = this.machine.tls.fetch_tls_dtor(None, thread_id); - while let Some((instance, thread_id, ptr, key)) = dtor { - trace!("Running TLS dtor {:?} on {:?} at {:?}", instance, ptr, thread_id); - assert!(!this.is_null(ptr).unwrap(), "Data can't be NULL when dtor is called!"); - - let ret_place = MPlaceTy::dangling(this.layout_of(this.tcx.mk_unit())?, this).into(); - this.call_function( - instance, - &[ptr.into()], - Some(ret_place), - StackPopCleanup::None { cleanup: true }, - )?; - - // step until out of stackframes - this.run()?; - - // Fetch next dtor after `key`. - dtor = match this.machine.tls.fetch_tls_dtor(Some(key), thread_id) { - dtor @ Some(_) => dtor, - // We ran each dtor once, start over from the beginning. - None => this.machine.tls.fetch_tls_dtor(None, thread_id), - }; - } + // Fetch next dtor after `key`. + dtor = match this.machine.tls.fetch_tls_dtor(Some(key), thread_id) { + dtor @ Some(_) => dtor, + // We ran each dtor once, start over from the beginning. + None => this.machine.tls.fetch_tls_dtor(None, thread_id), + }; } + Ok(()) } } diff --git a/src/thread.rs b/src/thread.rs index 72584b7265577..d40b2a176e73f 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -17,6 +17,16 @@ use rustc_middle::{ use crate::*; +#[derive(Clone, Copy, Debug, PartialEq, Eq)] +pub enum SchedulingAction { + /// Execute step on the active thread. + ExecuteStep, + /// Execute destructors of the active thread. + ExecuteDtors, + /// Stop the program. + Stop, +} + /// A thread identifier. #[derive(Clone, Copy, Debug, PartialOrd, Ord, PartialEq, Eq, Hash)] pub struct ThreadId(usize); @@ -197,6 +207,11 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { self.active_thread } + /// Has the given thread terminated? + fn has_terminated(&self, thread_id: ThreadId) -> bool { + self.threads[thread_id].state == ThreadState::Terminated + } + /// Get the borrow of the currently active thread. fn active_thread_mut(&mut self) -> &mut Thread<'mir, 'tcx> { &mut self.threads[self.active_thread] @@ -234,11 +249,6 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { self.active_thread_mut().thread_name = Some(new_thread_name); } - /// Get ids and states of all threads ever allocated. - fn get_all_thread_ids_with_states(&self) -> Vec<(ThreadId, ThreadState)> { - self.threads.iter_enumerated().map(|(id, thread)| (id, thread.state)).collect() - } - /// Allocate a new blockset id. fn create_blockset(&mut self) -> BlockSetId { self.blockset_counter = self.blockset_counter.checked_add(1).unwrap(); @@ -265,10 +275,8 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { None } - /// Decide which thread to run next. - /// - /// Returns `false` if all threads terminated. - fn schedule(&mut self) -> InterpResult<'tcx, bool> { + /// Decide which action to take next and on which thread. + fn schedule(&mut self) -> InterpResult<'tcx, SchedulingAction> { if self.threads[self.active_thread].check_terminated() { // Check if we need to unblock any threads. for (i, thread) in self.threads.iter_enumerated_mut() { @@ -277,18 +285,19 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { thread.state = ThreadState::Enabled; } } + return Ok(SchedulingAction::ExecuteDtors); } if self.threads[self.active_thread].state == ThreadState::Enabled { - return Ok(true); + return Ok(SchedulingAction::ExecuteStep); } if let Some(enabled_thread) = self.threads.iter().position(|thread| thread.state == ThreadState::Enabled) { self.active_thread = ThreadId::new(enabled_thread); - return Ok(true); + return Ok(SchedulingAction::ExecuteStep); } if self.threads.iter().all(|thread| thread.state == ThreadState::Terminated) { - Ok(false) + Ok(SchedulingAction::Stop) } else { throw_machine_stop!(TerminationInfo::Deadlock); } @@ -409,6 +418,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(this.machine.threads.get_active_thread_id()) } + fn has_terminated(&self, thread_id: ThreadId) -> InterpResult<'tcx, bool> { + let this = self.eval_context_ref(); + Ok(this.machine.threads.has_terminated(thread_id)) + } + fn active_thread_stack(&self) -> &[Frame<'mir, 'tcx, Tag, FrameData<'tcx>>] { let this = self.eval_context_ref(); this.machine.threads.active_thread_stack() @@ -424,11 +438,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(this.machine.threads.set_thread_name(new_thread_name)) } - fn get_all_thread_ids_with_states(&mut self) -> Vec<(ThreadId, ThreadState)> { - let this = self.eval_context_mut(); - this.machine.threads.get_all_thread_ids_with_states() - } - fn create_blockset(&mut self) -> InterpResult<'tcx, BlockSetId> { let this = self.eval_context_mut(); Ok(this.machine.threads.create_blockset()) @@ -444,10 +453,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(this.machine.threads.unblock_random_thread(set)) } - /// Decide which thread to run next. - /// - /// Returns `false` if all threads terminated. - fn schedule(&mut self) -> InterpResult<'tcx, bool> { + /// Decide which action to take next and on which thread. + fn schedule(&mut self) -> InterpResult<'tcx, SchedulingAction> { let this = self.eval_context_mut(); this.machine.threads.schedule() } From 134533d066a4ab57d1a3e7ed9590052db313b5e6 Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Fri, 17 Apr 2020 15:38:23 -0700 Subject: [PATCH 1950/3747] Add a comment explaining global destructors on MacOS. --- src/shims/tls.rs | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/src/shims/tls.rs b/src/shims/tls.rs index 6dc3025acd5ae..722b24d747525 100644 --- a/src/shims/tls.rs +++ b/src/shims/tls.rs @@ -114,8 +114,21 @@ impl<'tcx> TlsData<'tcx> { } } - /// Set global dtor for the given thread. - pub fn set_global_dtor(&mut self, thread: ThreadId, dtor: ty::Instance<'tcx>, data: Scalar) -> InterpResult<'tcx> { + /// Set global dtor for the given thread. This function is used to implement + /// `_tlv_atexit` shim on MacOS. + /// + /// Global destructors are available only on MacOS and (potentially + /// confusingly) they seem to be still per thread as can be guessed from the + /// following comment in the [`_tlv_atexit` + /// implementation](https://github.com/opensource-apple/dyld/blob/195030646877261f0c8c7ad8b001f52d6a26f514/src/threadLocalVariables.c#L389): + /// + /// // NOTE: this does not need locks because it only operates on current thread data + pub fn set_global_dtor( + &mut self, + thread: ThreadId, + dtor: ty::Instance<'tcx>, + data: Scalar + ) -> InterpResult<'tcx> { if self.dtors_running.contains(&thread) { // UB, according to libstd docs. throw_ub_format!("setting global destructor while destructors are already running"); From 46fd333daa8dc71f1c61aa87ecbf9881fae920c6 Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Sat, 18 Apr 2020 15:39:53 -0700 Subject: [PATCH 1951/3747] Implement thread::yield_now. --- src/shims/foreign_items/posix.rs | 5 +++++ src/shims/thread.rs | 8 ++++++++ src/thread.rs | 32 +++++++++++++++++++++++++++----- 3 files changed, 40 insertions(+), 5 deletions(-) diff --git a/src/shims/foreign_items/posix.rs b/src/shims/foreign_items/posix.rs index 9e85bcc66bb2a..4574d203efb79 100644 --- a/src/shims/foreign_items/posix.rs +++ b/src/shims/foreign_items/posix.rs @@ -318,6 +318,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let result = this.prctl(args[0], args[1], args[2], args[3], args[4])?; this.write_scalar(Scalar::from_i32(result), dest)?; } + "sched_yield" => { + assert_eq!(args.len(), 0); + let result = this.sched_yield()?; + this.write_scalar(Scalar::from_i32(result), dest)?; + } // Miscellaneous "isatty" => { diff --git a/src/shims/thread.rs b/src/shims/thread.rs index d8ba11d267f39..ccdf6df3f9d6f 100644 --- a/src/shims/thread.rs +++ b/src/shims/thread.rs @@ -111,4 +111,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(0) } + + fn sched_yield(&mut self) -> InterpResult<'tcx, i32> { + let this = self.eval_context_mut(); + + this.yield_active_thread()?; + + Ok(0) + } } diff --git a/src/thread.rs b/src/thread.rs index d40b2a176e73f..31296ad96ff0f 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -143,6 +143,8 @@ pub struct ThreadManager<'mir, 'tcx> { /// A mapping from a thread-local static to an allocation id of a thread /// specific allocation. thread_local_alloc_ids: RefCell>, + /// A flag that indicates that we should change the active thread. + yield_active_thread: bool, } impl<'mir, 'tcx> Default for ThreadManager<'mir, 'tcx> { @@ -154,6 +156,7 @@ impl<'mir, 'tcx> Default for ThreadManager<'mir, 'tcx> { threads: threads, blockset_counter: 0, thread_local_alloc_ids: Default::default(), + yield_active_thread: false, } } } @@ -275,6 +278,11 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { None } + /// Change the active thread to some enabled thread. + fn yield_active_thread(&mut self) { + self.yield_active_thread = true; + } + /// Decide which action to take next and on which thread. fn schedule(&mut self) -> InterpResult<'tcx, SchedulingAction> { if self.threads[self.active_thread].check_terminated() { @@ -287,13 +295,21 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { } return Ok(SchedulingAction::ExecuteDtors); } - if self.threads[self.active_thread].state == ThreadState::Enabled { + if self.threads[self.active_thread].state == ThreadState::Enabled + && !self.yield_active_thread + { return Ok(SchedulingAction::ExecuteStep); } - if let Some(enabled_thread) = - self.threads.iter().position(|thread| thread.state == ThreadState::Enabled) - { - self.active_thread = ThreadId::new(enabled_thread); + for (id, thread) in self.threads.iter_enumerated() { + if thread.state == ThreadState::Enabled { + if !(self.yield_active_thread && id == self.active_thread) { + self.active_thread = id; + break; + } + } + } + self.yield_active_thread = false; + if self.threads[self.active_thread].state == ThreadState::Enabled { return Ok(SchedulingAction::ExecuteStep); } if self.threads.iter().all(|thread| thread.state == ThreadState::Terminated) { @@ -453,6 +469,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(this.machine.threads.unblock_random_thread(set)) } + fn yield_active_thread(&mut self) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + this.machine.threads.yield_active_thread(); + Ok(()) + } + /// Decide which action to take next and on which thread. fn schedule(&mut self) -> InterpResult<'tcx, SchedulingAction> { let this = self.eval_context_mut(); From 421be273cc389a5d426063f71cba82bf1c364f00 Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Sat, 18 Apr 2020 12:25:11 -0700 Subject: [PATCH 1952/3747] Add concurrency tests. --- src/shims/sync.rs | 1 + src/shims/tls.rs | 2 + src/thread.rs | 4 +- .../concurrency/dangling_tls_lib.rs | 46 ++++++++++++++++ .../libc_pthread_mutex_deadlock.rs | 32 ++++++++++++ .../libc_pthread_mutex_wrong_owner.rs | 32 ++++++++++++ ...libc_pthread_rwlock_write_read_deadlock.rs | 32 ++++++++++++ ...ibc_pthread_rwlock_write_write_deadlock.rs | 32 ++++++++++++ tests/run-pass/concurrency/locks.rs | 52 +++++++++++++++++-- 9 files changed, 227 insertions(+), 6 deletions(-) create mode 100644 tests/compile-fail/concurrency/dangling_tls_lib.rs create mode 100644 tests/compile-fail/concurrency/libc_pthread_mutex_deadlock.rs create mode 100644 tests/compile-fail/concurrency/libc_pthread_mutex_wrong_owner.rs create mode 100644 tests/compile-fail/concurrency/libc_pthread_rwlock_write_read_deadlock.rs create mode 100644 tests/compile-fail/concurrency/libc_pthread_rwlock_write_write_deadlock.rs diff --git a/src/shims/sync.rs b/src/shims/sync.rs index d8a00156384c3..6a1ea108dbb06 100644 --- a/src/shims/sync.rs +++ b/src/shims/sync.rs @@ -532,6 +532,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } + // FIXME: We should check that this lock was locked by the active thread. fn pthread_rwlock_unlock(&mut self, rwlock_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); diff --git a/src/shims/tls.rs b/src/shims/tls.rs index 722b24d747525..89ec16596599e 100644 --- a/src/shims/tls.rs +++ b/src/shims/tls.rs @@ -233,6 +233,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// /// Note: on Windows OS this function is a no-op because we do not support /// concurrency on Windows yet. + /// + /// FIXME: we do not support yet deallocation of thread local statics. fn run_tls_dtors_for_active_thread(&mut self) -> InterpResult<'tcx> { let this = self.eval_context_mut(); if this.tcx.sess.target.target.target_os == "windows" { diff --git a/src/thread.rs b/src/thread.rs index 31296ad96ff0f..ab6a4c94db831 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -164,13 +164,13 @@ impl<'mir, 'tcx> Default for ThreadManager<'mir, 'tcx> { impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { /// Check if we have an allocation for the given thread local static for the /// active thread. - pub fn get_thread_local_alloc_id(&self, def_id: DefId) -> Option { + fn get_thread_local_alloc_id(&self, def_id: DefId) -> Option { self.thread_local_alloc_ids.borrow().get(&(def_id, self.active_thread)).cloned() } /// Set the allocation id as the allocation id of the given thread local /// static for the active thread. - pub fn set_thread_local_alloc_id(&self, def_id: DefId, new_alloc_id: AllocId) { + fn set_thread_local_alloc_id(&self, def_id: DefId, new_alloc_id: AllocId) { assert!( self.thread_local_alloc_ids .borrow_mut() diff --git a/tests/compile-fail/concurrency/dangling_tls_lib.rs b/tests/compile-fail/concurrency/dangling_tls_lib.rs new file mode 100644 index 0000000000000..ad12c107bffb0 --- /dev/null +++ b/tests/compile-fail/concurrency/dangling_tls_lib.rs @@ -0,0 +1,46 @@ +// ignore-windows + +#![feature(thread_local_internals)] + +use std::cell::RefCell; +use std::thread; + +static A: std::thread::LocalKey> = { + #[inline] + fn __init() -> RefCell { + RefCell::new(0) + } + + unsafe fn __getit() -> Option<&'static RefCell> { + static __KEY: std::thread::__OsLocalKeyInner> = + std::thread::__OsLocalKeyInner::new(); + __KEY.get(__init) + } + + unsafe { std::thread::LocalKey::new(__getit) } +}; + +struct Sender(*mut u8); + +unsafe impl Send for Sender {} + +fn main() { + A.with(|f| { + assert_eq!(*f.borrow(), 0); + *f.borrow_mut() = 4; + }); + + let handle = thread::spawn(|| { + let ptr = A.with(|f| { + assert_eq!(*f.borrow(), 0); + *f.borrow_mut() = 5; + &mut *f.borrow_mut() as *mut u8 + }); + Sender(ptr) + }); + let ptr = handle.join().unwrap().0; + A.with(|f| { + assert_eq!(*f.borrow(), 4); + }); + let _x = unsafe { *ptr }; //~ ERROR Undefined Behavior +} diff --git a/tests/compile-fail/concurrency/libc_pthread_mutex_deadlock.rs b/tests/compile-fail/concurrency/libc_pthread_mutex_deadlock.rs new file mode 100644 index 0000000000000..5d04635a36c88 --- /dev/null +++ b/tests/compile-fail/concurrency/libc_pthread_mutex_deadlock.rs @@ -0,0 +1,32 @@ +// ignore-windows: No libc on Windows + +#![feature(rustc_private)] + +extern crate libc; + +use std::cell::UnsafeCell; +use std::sync::Arc; +use std::thread; + +struct Mutex(UnsafeCell); + +unsafe impl Send for Mutex {} +unsafe impl Sync for Mutex {} + +fn new_lock() -> Arc { + Arc::new(Mutex(UnsafeCell::new(libc::PTHREAD_MUTEX_INITIALIZER))) +} + +fn main() { + unsafe { + let lock = new_lock(); + assert_eq!(libc::pthread_mutex_lock(lock.0.get() as *mut _), 0); + + let lock_copy = lock.clone(); + thread::spawn(move || { + assert_eq!(libc::pthread_mutex_lock(lock_copy.0.get() as *mut _), 0); //~ ERROR: deadlock + }) + .join() + .unwrap(); + } +} diff --git a/tests/compile-fail/concurrency/libc_pthread_mutex_wrong_owner.rs b/tests/compile-fail/concurrency/libc_pthread_mutex_wrong_owner.rs new file mode 100644 index 0000000000000..3009721abe2e1 --- /dev/null +++ b/tests/compile-fail/concurrency/libc_pthread_mutex_wrong_owner.rs @@ -0,0 +1,32 @@ +// ignore-windows: No libc on Windows + +#![feature(rustc_private)] + +extern crate libc; + +use std::cell::UnsafeCell; +use std::sync::Arc; +use std::thread; + +struct Mutex(UnsafeCell); + +unsafe impl Send for Mutex {} +unsafe impl Sync for Mutex {} + +fn new_lock() -> Arc { + Arc::new(Mutex(UnsafeCell::new(libc::PTHREAD_MUTEX_INITIALIZER))) +} + +fn main() { + unsafe { + let lock = new_lock(); + assert_eq!(libc::pthread_mutex_lock(lock.0.get() as *mut _), 0); + + let lock_copy = lock.clone(); + thread::spawn(move || { + assert_eq!(libc::pthread_mutex_unlock(lock_copy.0.get() as *mut _), 0); //~ ERROR: Undefined Behavior: called pthread_mutex_unlock on a mutex owned by another thread + }) + .join() + .unwrap(); + } +} diff --git a/tests/compile-fail/concurrency/libc_pthread_rwlock_write_read_deadlock.rs b/tests/compile-fail/concurrency/libc_pthread_rwlock_write_read_deadlock.rs new file mode 100644 index 0000000000000..19dce431c8b1c --- /dev/null +++ b/tests/compile-fail/concurrency/libc_pthread_rwlock_write_read_deadlock.rs @@ -0,0 +1,32 @@ +// ignore-windows: No libc on Windows + +#![feature(rustc_private)] + +extern crate libc; + +use std::cell::UnsafeCell; +use std::sync::Arc; +use std::thread; + +struct RwLock(UnsafeCell); + +unsafe impl Send for RwLock {} +unsafe impl Sync for RwLock {} + +fn new_lock() -> Arc { + Arc::new(RwLock(UnsafeCell::new(libc::PTHREAD_RWLOCK_INITIALIZER))) +} + +fn main() { + unsafe { + let lock = new_lock(); + assert_eq!(libc::pthread_rwlock_rdlock(lock.0.get() as *mut _), 0); + + let lock_copy = lock.clone(); + thread::spawn(move || { + assert_eq!(libc::pthread_rwlock_wrlock(lock_copy.0.get() as *mut _), 0); //~ ERROR: deadlock + }) + .join() + .unwrap(); + } +} diff --git a/tests/compile-fail/concurrency/libc_pthread_rwlock_write_write_deadlock.rs b/tests/compile-fail/concurrency/libc_pthread_rwlock_write_write_deadlock.rs new file mode 100644 index 0000000000000..098c1c2fe26cc --- /dev/null +++ b/tests/compile-fail/concurrency/libc_pthread_rwlock_write_write_deadlock.rs @@ -0,0 +1,32 @@ +// ignore-windows: No libc on Windows + +#![feature(rustc_private)] + +extern crate libc; + +use std::cell::UnsafeCell; +use std::sync::Arc; +use std::thread; + +struct RwLock(UnsafeCell); + +unsafe impl Send for RwLock {} +unsafe impl Sync for RwLock {} + +fn new_lock() -> Arc { + Arc::new(RwLock(UnsafeCell::new(libc::PTHREAD_RWLOCK_INITIALIZER))) +} + +fn main() { + unsafe { + let lock = new_lock(); + assert_eq!(libc::pthread_rwlock_wrlock(lock.0.get() as *mut _), 0); + + let lock_copy = lock.clone(); + thread::spawn(move || { + assert_eq!(libc::pthread_rwlock_wrlock(lock_copy.0.get() as *mut _), 0); //~ ERROR: deadlock + }) + .join() + .unwrap(); + } +} diff --git a/tests/run-pass/concurrency/locks.rs b/tests/run-pass/concurrency/locks.rs index 3c8373691b842..90c10b8ffe247 100644 --- a/tests/run-pass/concurrency/locks.rs +++ b/tests/run-pass/concurrency/locks.rs @@ -1,11 +1,9 @@ // ignore-windows -//! This test just calls the relevant APIs to check if Miri crashes. - -use std::sync::{Arc, Mutex}; +use std::sync::{Arc, Mutex, RwLock}; use std::thread; -fn main() { +fn check_mutex() { let data = Arc::new(Mutex::new(0)); let mut threads = Vec::new(); @@ -27,3 +25,49 @@ fn main() { let data = Arc::try_unwrap(data).unwrap().into_inner().unwrap(); assert_eq!(data, 3); } + +fn check_rwlock_write() { + let data = Arc::new(RwLock::new(0)); + let mut threads = Vec::new(); + + for _ in 0..3 { + let data = Arc::clone(&data); + let thread = thread::spawn(move || { + let mut data = data.write().unwrap(); + *data += 1; + }); + threads.push(thread); + } + + for thread in threads { + thread.join().unwrap(); + } + + assert!(data.try_write().is_ok()); + + let data = Arc::try_unwrap(data).unwrap().into_inner().unwrap(); + assert_eq!(data, 3); +} + +fn check_rwlock_read_no_deadlock() { + let l1 = Arc::new(RwLock::new(0)); + let l2 = Arc::new(RwLock::new(0)); + + let l1_copy = Arc::clone(&l1); + let l2_copy = Arc::clone(&l2); + let _guard1 = l1.read().unwrap(); + let handle = thread::spawn(move || { + let _guard2 = l2_copy.read().unwrap(); + thread::yield_now(); + let _guard1 = l1_copy.read().unwrap(); + }); + thread::yield_now(); + let _guard2 = l2.read().unwrap(); + handle.join().unwrap(); +} + +fn main() { + check_mutex(); + check_rwlock_write(); + check_rwlock_read_no_deadlock(); +} From c84b2890adb6b67712c6cff565eed2521dc9ba65 Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Sun, 19 Apr 2020 12:22:33 -0700 Subject: [PATCH 1953/3747] Update a comment in README about what concurrency checks we support. --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index fb981a71f0e4d..cf50049daedf3 100644 --- a/README.md +++ b/README.md @@ -48,8 +48,8 @@ in your program, and cannot run all programs: has no access to most platform-specific APIs or FFI. A few APIs have been implemented (such as printing to stdout) but most have not: for example, Miri currently does not support SIMD or networking. -* Miri currently does not check for data-races and other concurrency related - issues. +* Miri currently does not check for data-races and most other concurrency + related issues. [rust]: https://www.rust-lang.org/ [mir]: https://github.com/rust-lang/rfcs/blob/master/text/1211-mir.md From d6c03926ab8aff457a3e9b607bdcca654bfe17fe Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Sun, 19 Apr 2020 12:24:46 -0700 Subject: [PATCH 1954/3747] Rename MacOS set global dtor function. --- src/shims/foreign_items/posix/macos.rs | 2 +- src/shims/tls.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/shims/foreign_items/posix/macos.rs b/src/shims/foreign_items/posix/macos.rs index 9f65d0f9c47d7..9f6ea00b03132 100644 --- a/src/shims/foreign_items/posix/macos.rs +++ b/src/shims/foreign_items/posix/macos.rs @@ -83,7 +83,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let dtor = this.memory.get_fn(dtor)?.as_instance()?; let data = this.read_scalar(args[1])?.not_undef()?; let active_thread = this.get_active_thread()?; - this.machine.tls.set_global_dtor(active_thread, dtor, data)?; + this.machine.tls.set_thread_global_dtor(active_thread, dtor, data)?; } // Querying system information diff --git a/src/shims/tls.rs b/src/shims/tls.rs index 89ec16596599e..c08ec78c136da 100644 --- a/src/shims/tls.rs +++ b/src/shims/tls.rs @@ -123,7 +123,7 @@ impl<'tcx> TlsData<'tcx> { /// implementation](https://github.com/opensource-apple/dyld/blob/195030646877261f0c8c7ad8b001f52d6a26f514/src/threadLocalVariables.c#L389): /// /// // NOTE: this does not need locks because it only operates on current thread data - pub fn set_global_dtor( + pub fn set_thread_global_dtor( &mut self, thread: ThreadId, dtor: ty::Instance<'tcx>, From 69df2e19de4bf49df6e250cd367c553737dd6d0c Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Sun, 19 Apr 2020 14:01:12 -0700 Subject: [PATCH 1955/3747] Move prctl to Linux specific shims. --- src/shims/foreign_items/posix.rs | 5 ----- src/shims/foreign_items/posix/linux.rs | 7 +++++++ 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/shims/foreign_items/posix.rs b/src/shims/foreign_items/posix.rs index 4574d203efb79..6e2a7a9fcb4fa 100644 --- a/src/shims/foreign_items/posix.rs +++ b/src/shims/foreign_items/posix.rs @@ -313,11 +313,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx assert_eq!(args.len(), 0); this.pthread_self(dest)?; } - "prctl" => { - assert_eq!(args.len(), 5); - let result = this.prctl(args[0], args[1], args[2], args[3], args[4])?; - this.write_scalar(Scalar::from_i32(result), dest)?; - } "sched_yield" => { assert_eq!(args.len(), 0); let result = this.sched_yield()?; diff --git a/src/shims/foreign_items/posix/linux.rs b/src/shims/foreign_items/posix/linux.rs index a32f0fa606784..eb58f7466089b 100644 --- a/src/shims/foreign_items/posix/linux.rs +++ b/src/shims/foreign_items/posix/linux.rs @@ -75,6 +75,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_null(dest)?; } + // Threading + "prctl" => { + assert_eq!(args.len(), 5); + let result = this.prctl(args[0], args[1], args[2], args[3], args[4])?; + this.write_scalar(Scalar::from_i32(result), dest)?; + } + // Dynamically invoked syscalls "syscall" => { let sys_getrandom = this From eab38dfe00d99bca183b7744823f8614d04e5304 Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Sun, 19 Apr 2020 14:01:56 -0700 Subject: [PATCH 1956/3747] Change the warning message. --- src/shims/thread.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shims/thread.rs b/src/shims/thread.rs index ccdf6df3f9d6f..077da0b1a19d1 100644 --- a/src/shims/thread.rs +++ b/src/shims/thread.rs @@ -14,7 +14,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); this.tcx.sess.warn( - "The thread support is experimental. \ + "thread support is experimental. \ For example, Miri does not detect data races yet.", ); From 75e6549c119cd0d30f764c3d8c2a742c63bc495f Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Sun, 19 Apr 2020 14:18:30 -0700 Subject: [PATCH 1957/3747] Improve prctl, add a test. --- src/shims/thread.rs | 15 ++++++++++----- .../concurrency/libc_prctl_thread_name.rs | 17 +++++++++++++++++ 2 files changed, 27 insertions(+), 5 deletions(-) create mode 100644 tests/run-pass/concurrency/libc_prctl_thread_name.rs diff --git a/src/shims/thread.rs b/src/shims/thread.rs index 077da0b1a19d1..ab3b436b86655 100644 --- a/src/shims/thread.rs +++ b/src/shims/thread.rs @@ -102,12 +102,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); let option = this.read_scalar(option)?.not_undef()?.to_i32()?; - if option != this.eval_libc_i32("PR_SET_NAME")? { - throw_unsup_format!("Miri supports only PR_SET_NAME"); + if option == this.eval_libc_i32("PR_SET_NAME")? { + let address = this.read_scalar(arg2)?.not_undef()?; + let name = this.memory.read_c_str(address)?.to_owned(); + this.set_active_thread_name(name)?; + } else if option == this.eval_libc_i32("PR_GET_NAME")? { + let address = this.read_scalar(arg2)?.not_undef()?; + let name = this.get_active_thread_name()?; + this.memory.write_bytes(address, name)?; + } else { + throw_unsup_format!("Unsupported prctl option."); } - let address = this.read_scalar(arg2)?.not_undef()?; - let name = this.memory.read_c_str(address)?.to_owned(); - this.set_active_thread_name(name)?; Ok(0) } diff --git a/tests/run-pass/concurrency/libc_prctl_thread_name.rs b/tests/run-pass/concurrency/libc_prctl_thread_name.rs new file mode 100644 index 0000000000000..235ac27e0a59f --- /dev/null +++ b/tests/run-pass/concurrency/libc_prctl_thread_name.rs @@ -0,0 +1,17 @@ +// ignore-windows: No libc on Windows + +#![feature(rustc_private)] + +extern crate libc; + +use std::ffi::CString; + +fn main() { + unsafe { + let thread_name = CString::new("hello").expect("CString::new failed"); + assert_eq!(libc::prctl(libc::PR_SET_NAME, thread_name.as_ptr() as u64, 0, 0, 0), 0); + let mut buf = [0; 6]; + assert_eq!(libc::prctl(libc::PR_GET_NAME, buf.as_mut_ptr() as u64, 0, 0, 0), 0); + assert_eq!(thread_name.as_bytes_with_nul(), buf); + } +} From 94cbe88e8073381dbf7aeed2f0cf720b08f05785 Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Sun, 19 Apr 2020 14:21:18 -0700 Subject: [PATCH 1958/3747] Many small changes to thread management. --- src/shims/sync.rs | 8 ++-- src/thread.rs | 112 ++++++++++++++++++++++++++++++++++------------ 2 files changed, 87 insertions(+), 33 deletions(-) diff --git a/src/shims/sync.rs b/src/shims/sync.rs index 6a1ea108dbb06..97afbbe98f6a0 100644 --- a/src/shims/sync.rs +++ b/src/shims/sync.rs @@ -419,7 +419,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx throw_ub_format!("called pthread_mutex_unlock on a mutex owned by another thread"); } else if locked_count == 1 { let blockset = mutex_get_or_create_blockset(this, mutex_op)?; - if let Some(new_owner) = this.unblock_random_thread(blockset)? { + if let Some(new_owner) = this.unblock_some_thread(blockset)? { // We have at least one thread waiting on this mutex. Transfer // ownership to it. mutex_set_owner(this, mutex_op, new_owner.to_u32_scalar())?; @@ -543,7 +543,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx assert_eq!(writers, 0); rwlock_set_readers(this, rwlock_op, Scalar::from_u32(new_readers))?; if new_readers == 0 { - if let Some(_writer) = this.unblock_random_thread(writer_blockset)? { + if let Some(_writer) = this.unblock_some_thread(writer_blockset)? { rwlock_set_writers(this, rwlock_op, Scalar::from_u32(1))?; } } @@ -551,11 +551,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } else if writers != 0 { let reader_blockset = rwlock_get_or_create_reader_blockset(this, rwlock_op)?; rwlock_set_writers(this, rwlock_op, Scalar::from_u32(0))?; - if let Some(_writer) = this.unblock_random_thread(writer_blockset)? { + if let Some(_writer) = this.unblock_some_thread(writer_blockset)? { rwlock_set_writers(this, rwlock_op, Scalar::from_u32(1))?; } else { let mut readers = 0; - while let Some(_reader) = this.unblock_random_thread(reader_blockset)? { + while let Some(_reader) = this.unblock_some_thread(reader_blockset)? { readers += 1; } rwlock_set_readers(this, rwlock_op, Scalar::from_u32(readers))? diff --git a/src/thread.rs b/src/thread.rs index ab6a4c94db831..5eb6560a09e64 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -31,6 +31,9 @@ pub enum SchedulingAction { #[derive(Clone, Copy, Debug, PartialOrd, Ord, PartialEq, Eq, Hash)] pub struct ThreadId(usize); +/// The main thread. When it terminates, the whole application terminates. +const MAIN_THREAD: ThreadId = ThreadId(0); + impl Idx for ThreadId { fn new(idx: usize) -> Self { ThreadId(idx) @@ -42,13 +45,13 @@ impl Idx for ThreadId { impl From for ThreadId { fn from(id: u64) -> Self { - Self(id as usize) + Self(usize::try_from(id).unwrap()) } } impl From for ThreadId { fn from(id: u32) -> Self { - Self(id as usize) + Self(usize::try_from(id).unwrap()) } } @@ -82,10 +85,10 @@ pub enum ThreadState { /// The thread tried to join the specified thread and is blocked until that /// thread terminates. BlockedOnJoin(ThreadId), - /// The thread is blocked and belongs to the given blockset.. + /// The thread is blocked and belongs to the given blockset. Blocked(BlockSetId), /// The thread has terminated its execution (we do not delete terminated - /// threads.) + /// threads). Terminated, } @@ -150,6 +153,7 @@ pub struct ThreadManager<'mir, 'tcx> { impl<'mir, 'tcx> Default for ThreadManager<'mir, 'tcx> { fn default() -> Self { let mut threads = IndexVec::new(); + // Create the main thread and add it to the list of threads. threads.push(Default::default()); Self { active_thread: ThreadId::new(0), @@ -170,14 +174,13 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { /// Set the allocation id as the allocation id of the given thread local /// static for the active thread. + /// + /// Panics if a thread local is initialized twice for the same thread. fn set_thread_local_alloc_id(&self, def_id: DefId, new_alloc_id: AllocId) { - assert!( - self.thread_local_alloc_ids - .borrow_mut() - .insert((def_id, self.active_thread), new_alloc_id) - .is_none(), - "a thread local initialized twice for the same thread" - ); + self.thread_local_alloc_ids + .borrow_mut() + .insert((def_id, self.active_thread), new_alloc_id) + .unwrap_none(); } /// Borrow the stack of the active thread. @@ -227,15 +230,20 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { } /// Mark that the active thread tries to join the thread with `joined_thread_id`. - fn join_thread(&mut self, joined_thread_id: ThreadId) { - assert!(!self.threads[joined_thread_id].detached, "Bug: trying to join a detached thread."); - assert_ne!(joined_thread_id, self.active_thread, "Bug: trying to join itself"); - assert!( - self.threads - .iter() - .all(|thread| thread.state != ThreadState::BlockedOnJoin(joined_thread_id)), - "Bug: multiple threads try to join the same thread." - ); + fn join_thread(&mut self, joined_thread_id: ThreadId) -> InterpResult<'tcx> { + if self.threads[joined_thread_id].detached { + throw_ub_format!("trying to join a detached thread"); + } + if joined_thread_id == self.active_thread { + throw_ub_format!("trying to join itself"); + } + if self + .threads + .iter() + .any(|thread| thread.state == ThreadState::BlockedOnJoin(joined_thread_id)) + { + throw_ub_format!("multiple threads try to join the same thread"); + } if self.threads[joined_thread_id].state != ThreadState::Terminated { // The joined thread is still running, we need to wait for it. self.active_thread_mut().state = ThreadState::BlockedOnJoin(joined_thread_id); @@ -245,6 +253,7 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { joined_thread_id ); } + Ok(()) } /// Set the name of the active thread. @@ -252,6 +261,15 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { self.active_thread_mut().thread_name = Some(new_thread_name); } + /// Get the name of the active thread. + fn get_thread_name(&mut self) -> InterpResult<'tcx, Vec> { + if let Some(ref thread_name) = self.active_thread_mut().thread_name { + Ok(thread_name.clone()) + } else { + throw_ub_format!("thread {:?} has no name set", self.active_thread) + } + } + /// Allocate a new blockset id. fn create_blockset(&mut self) -> BlockSetId { self.blockset_counter = self.blockset_counter.checked_add(1).unwrap(); @@ -267,7 +285,7 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { /// Unblock any one thread from the given blockset if it contains at least /// one. Return the id of the unblocked thread. - fn unblock_random_thread(&mut self, set: BlockSetId) -> Option { + fn unblock_some_thread(&mut self, set: BlockSetId) -> Option { for (id, thread) in self.threads.iter_enumerated_mut() { if thread.state == ThreadState::Blocked(set) { trace!("unblocking {:?} in blockset {:?}", id, set); @@ -284,6 +302,11 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { } /// Decide which action to take next and on which thread. + /// + /// The currently implemented scheduling policy is the one that is commonly + /// used in stateless model checkers such as Loom: run the active thread as + /// long as we can and switch only when we have to (the active thread was + /// blocked, terminated, or was explicitly asked to be preempted). fn schedule(&mut self) -> InterpResult<'tcx, SchedulingAction> { if self.threads[self.active_thread].check_terminated() { // Check if we need to unblock any threads. @@ -295,14 +318,24 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { } return Ok(SchedulingAction::ExecuteDtors); } + if self.threads[MAIN_THREAD].state == ThreadState::Terminated { + // The main thread terminated; stop the program. + if self.threads.iter().any(|thread| thread.state != ThreadState::Terminated) { + // FIXME: This check should be either configurable or just emit a warning. + throw_unsup_format!("the main thread terminated without waiting for other threads"); + } + return Ok(SchedulingAction::Stop); + } if self.threads[self.active_thread].state == ThreadState::Enabled && !self.yield_active_thread { + // The currently active thread is still enabled, just continue with it. return Ok(SchedulingAction::ExecuteStep); } + // We need to pick a new thread for execution. for (id, thread) in self.threads.iter_enumerated() { if thread.state == ThreadState::Enabled { - if !(self.yield_active_thread && id == self.active_thread) { + if !self.yield_active_thread || id != self.active_thread { self.active_thread = id; break; } @@ -312,14 +345,16 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { if self.threads[self.active_thread].state == ThreadState::Enabled { return Ok(SchedulingAction::ExecuteStep); } + // We have not found a thread to execute. if self.threads.iter().all(|thread| thread.state == ThreadState::Terminated) { - Ok(SchedulingAction::Stop) + unreachable!(); } else { throw_machine_stop!(TerminationInfo::Deadlock); } } } +// Public interface to thread management. impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { /// A workaround for thread-local statics until @@ -331,8 +366,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx val: &mut mir::interpret::ConstValue<'tcx>, ) -> InterpResult<'tcx> { let this = self.eval_context_ref(); - match val { - mir::interpret::ConstValue::Scalar(Scalar::Ptr(ptr)) => { + match *val { + mir::interpret::ConstValue::Scalar(Scalar::Ptr(ref mut ptr)) => { let alloc_id = ptr.alloc_id; let alloc = this.tcx.alloc_map.lock().get(alloc_id); let tcx = this.tcx; @@ -407,68 +442,86 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } + #[inline] fn create_thread(&mut self) -> InterpResult<'tcx, ThreadId> { let this = self.eval_context_mut(); Ok(this.machine.threads.create_thread()) } + #[inline] fn detach_thread(&mut self, thread_id: ThreadId) -> InterpResult<'tcx> { let this = self.eval_context_mut(); this.machine.threads.detach_thread(thread_id); Ok(()) } + #[inline] fn join_thread(&mut self, joined_thread_id: ThreadId) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - this.machine.threads.join_thread(joined_thread_id); - Ok(()) + this.machine.threads.join_thread(joined_thread_id) } + #[inline] fn set_active_thread(&mut self, thread_id: ThreadId) -> InterpResult<'tcx, ThreadId> { let this = self.eval_context_mut(); Ok(this.machine.threads.set_active_thread_id(thread_id)) } + #[inline] fn get_active_thread(&self) -> InterpResult<'tcx, ThreadId> { let this = self.eval_context_ref(); Ok(this.machine.threads.get_active_thread_id()) } + #[inline] fn has_terminated(&self, thread_id: ThreadId) -> InterpResult<'tcx, bool> { let this = self.eval_context_ref(); Ok(this.machine.threads.has_terminated(thread_id)) } + #[inline] fn active_thread_stack(&self) -> &[Frame<'mir, 'tcx, Tag, FrameData<'tcx>>] { let this = self.eval_context_ref(); this.machine.threads.active_thread_stack() } + #[inline] fn active_thread_stack_mut(&mut self) -> &mut Vec>> { let this = self.eval_context_mut(); this.machine.threads.active_thread_stack_mut() } + #[inline] fn set_active_thread_name(&mut self, new_thread_name: Vec) -> InterpResult<'tcx, ()> { let this = self.eval_context_mut(); Ok(this.machine.threads.set_thread_name(new_thread_name)) } + #[inline] + fn get_active_thread_name(&mut self) -> InterpResult<'tcx, Vec> { + let this = self.eval_context_mut(); + this.machine.threads.get_thread_name() + } + + #[inline] fn create_blockset(&mut self) -> InterpResult<'tcx, BlockSetId> { let this = self.eval_context_mut(); Ok(this.machine.threads.create_blockset()) } + #[inline] fn block_active_thread(&mut self, set: BlockSetId) -> InterpResult<'tcx> { let this = self.eval_context_mut(); Ok(this.machine.threads.block_active_thread(set)) } - fn unblock_random_thread(&mut self, set: BlockSetId) -> InterpResult<'tcx, Option> { + #[inline] + fn unblock_some_thread(&mut self, set: BlockSetId) -> InterpResult<'tcx, Option> { let this = self.eval_context_mut(); - Ok(this.machine.threads.unblock_random_thread(set)) + Ok(this.machine.threads.unblock_some_thread(set)) } + #[inline] fn yield_active_thread(&mut self) -> InterpResult<'tcx> { let this = self.eval_context_mut(); this.machine.threads.yield_active_thread(); @@ -476,6 +529,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } /// Decide which action to take next and on which thread. + #[inline] fn schedule(&mut self) -> InterpResult<'tcx, SchedulingAction> { let this = self.eval_context_mut(); this.machine.threads.schedule() From 80459bbf774f6238936837ace61fa6c1c95051ec Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Sun, 19 Apr 2020 14:22:55 -0700 Subject: [PATCH 1959/3747] Improve concurrency tests. --- .../concurrency/dangling_tls_lib.rs | 2 +- ...libc_pthread_rwlock_write_read_deadlock.rs | 32 ------------------- ...ibc_pthread_rwlock_write_write_deadlock.rs | 32 ------------------- .../{ => concurrency}/thread-spawn.rs | 5 +-- .../libc_pthread_mutex_deadlock.rs | 0 .../libc_pthread_mutex_wrong_owner.rs | 0 ...libc_pthread_rwlock_write_read_deadlock.rs | 25 +++++++++++++-- ...wlock_write_read_deadlock_single_thread.rs | 13 ++++++++ ...ibc_pthread_rwlock_write_write_deadlock.rs | 25 +++++++++++++-- ...lock_write_write_deadlock_single_thread.rs | 13 ++++++++ tests/run-pass/concurrency/locks.rs | 4 ++- tests/run-pass/concurrency/locks.stderr | 2 +- tests/run-pass/concurrency/simple.rs | 2 +- tests/run-pass/concurrency/simple.stderr | 2 +- tests/run-pass/concurrency/thread_locals.rs | 7 +++- .../run-pass/concurrency/thread_locals.stderr | 2 +- 16 files changed, 87 insertions(+), 79 deletions(-) delete mode 100644 tests/compile-fail/concurrency/libc_pthread_rwlock_write_read_deadlock.rs delete mode 100644 tests/compile-fail/concurrency/libc_pthread_rwlock_write_write_deadlock.rs rename tests/compile-fail/{ => concurrency}/thread-spawn.rs (52%) rename tests/compile-fail/{concurrency => sync}/libc_pthread_mutex_deadlock.rs (100%) rename tests/compile-fail/{concurrency => sync}/libc_pthread_mutex_wrong_owner.rs (100%) create mode 100644 tests/compile-fail/sync/libc_pthread_rwlock_write_read_deadlock_single_thread.rs create mode 100644 tests/compile-fail/sync/libc_pthread_rwlock_write_write_deadlock_single_thread.rs diff --git a/tests/compile-fail/concurrency/dangling_tls_lib.rs b/tests/compile-fail/concurrency/dangling_tls_lib.rs index ad12c107bffb0..684dd0e86f608 100644 --- a/tests/compile-fail/concurrency/dangling_tls_lib.rs +++ b/tests/compile-fail/concurrency/dangling_tls_lib.rs @@ -1,4 +1,4 @@ -// ignore-windows +// ignore-windows: Concurrency on Windows is not supported yet. #![feature(thread_local_internals)] diff --git a/tests/compile-fail/concurrency/libc_pthread_rwlock_write_read_deadlock.rs b/tests/compile-fail/concurrency/libc_pthread_rwlock_write_read_deadlock.rs deleted file mode 100644 index 19dce431c8b1c..0000000000000 --- a/tests/compile-fail/concurrency/libc_pthread_rwlock_write_read_deadlock.rs +++ /dev/null @@ -1,32 +0,0 @@ -// ignore-windows: No libc on Windows - -#![feature(rustc_private)] - -extern crate libc; - -use std::cell::UnsafeCell; -use std::sync::Arc; -use std::thread; - -struct RwLock(UnsafeCell); - -unsafe impl Send for RwLock {} -unsafe impl Sync for RwLock {} - -fn new_lock() -> Arc { - Arc::new(RwLock(UnsafeCell::new(libc::PTHREAD_RWLOCK_INITIALIZER))) -} - -fn main() { - unsafe { - let lock = new_lock(); - assert_eq!(libc::pthread_rwlock_rdlock(lock.0.get() as *mut _), 0); - - let lock_copy = lock.clone(); - thread::spawn(move || { - assert_eq!(libc::pthread_rwlock_wrlock(lock_copy.0.get() as *mut _), 0); //~ ERROR: deadlock - }) - .join() - .unwrap(); - } -} diff --git a/tests/compile-fail/concurrency/libc_pthread_rwlock_write_write_deadlock.rs b/tests/compile-fail/concurrency/libc_pthread_rwlock_write_write_deadlock.rs deleted file mode 100644 index 098c1c2fe26cc..0000000000000 --- a/tests/compile-fail/concurrency/libc_pthread_rwlock_write_write_deadlock.rs +++ /dev/null @@ -1,32 +0,0 @@ -// ignore-windows: No libc on Windows - -#![feature(rustc_private)] - -extern crate libc; - -use std::cell::UnsafeCell; -use std::sync::Arc; -use std::thread; - -struct RwLock(UnsafeCell); - -unsafe impl Send for RwLock {} -unsafe impl Sync for RwLock {} - -fn new_lock() -> Arc { - Arc::new(RwLock(UnsafeCell::new(libc::PTHREAD_RWLOCK_INITIALIZER))) -} - -fn main() { - unsafe { - let lock = new_lock(); - assert_eq!(libc::pthread_rwlock_wrlock(lock.0.get() as *mut _), 0); - - let lock_copy = lock.clone(); - thread::spawn(move || { - assert_eq!(libc::pthread_rwlock_wrlock(lock_copy.0.get() as *mut _), 0); //~ ERROR: deadlock - }) - .join() - .unwrap(); - } -} diff --git a/tests/compile-fail/thread-spawn.rs b/tests/compile-fail/concurrency/thread-spawn.rs similarity index 52% rename from tests/compile-fail/thread-spawn.rs rename to tests/compile-fail/concurrency/thread-spawn.rs index 4b9073f3a73ee..f0e4ab3817d34 100644 --- a/tests/compile-fail/thread-spawn.rs +++ b/tests/compile-fail/concurrency/thread-spawn.rs @@ -1,5 +1,6 @@ -// ignore-linux -// ignore-macos +// ignore-linux: Only Windows is not supported. +// ignore-macos: Only Windows is not supported. + use std::thread; // error-pattern: Miri does not support threading diff --git a/tests/compile-fail/concurrency/libc_pthread_mutex_deadlock.rs b/tests/compile-fail/sync/libc_pthread_mutex_deadlock.rs similarity index 100% rename from tests/compile-fail/concurrency/libc_pthread_mutex_deadlock.rs rename to tests/compile-fail/sync/libc_pthread_mutex_deadlock.rs diff --git a/tests/compile-fail/concurrency/libc_pthread_mutex_wrong_owner.rs b/tests/compile-fail/sync/libc_pthread_mutex_wrong_owner.rs similarity index 100% rename from tests/compile-fail/concurrency/libc_pthread_mutex_wrong_owner.rs rename to tests/compile-fail/sync/libc_pthread_mutex_wrong_owner.rs diff --git a/tests/compile-fail/sync/libc_pthread_rwlock_write_read_deadlock.rs b/tests/compile-fail/sync/libc_pthread_rwlock_write_read_deadlock.rs index 1b460e7174d28..19dce431c8b1c 100644 --- a/tests/compile-fail/sync/libc_pthread_rwlock_write_read_deadlock.rs +++ b/tests/compile-fail/sync/libc_pthread_rwlock_write_read_deadlock.rs @@ -4,10 +4,29 @@ extern crate libc; +use std::cell::UnsafeCell; +use std::sync::Arc; +use std::thread; + +struct RwLock(UnsafeCell); + +unsafe impl Send for RwLock {} +unsafe impl Sync for RwLock {} + +fn new_lock() -> Arc { + Arc::new(RwLock(UnsafeCell::new(libc::PTHREAD_RWLOCK_INITIALIZER))) +} + fn main() { - let rw = std::cell::UnsafeCell::new(libc::PTHREAD_RWLOCK_INITIALIZER); unsafe { - assert_eq!(libc::pthread_rwlock_wrlock(rw.get()), 0); - libc::pthread_rwlock_rdlock(rw.get()); //~ ERROR: deadlock + let lock = new_lock(); + assert_eq!(libc::pthread_rwlock_rdlock(lock.0.get() as *mut _), 0); + + let lock_copy = lock.clone(); + thread::spawn(move || { + assert_eq!(libc::pthread_rwlock_wrlock(lock_copy.0.get() as *mut _), 0); //~ ERROR: deadlock + }) + .join() + .unwrap(); } } diff --git a/tests/compile-fail/sync/libc_pthread_rwlock_write_read_deadlock_single_thread.rs b/tests/compile-fail/sync/libc_pthread_rwlock_write_read_deadlock_single_thread.rs new file mode 100644 index 0000000000000..1b460e7174d28 --- /dev/null +++ b/tests/compile-fail/sync/libc_pthread_rwlock_write_read_deadlock_single_thread.rs @@ -0,0 +1,13 @@ +// ignore-windows: No libc on Windows + +#![feature(rustc_private)] + +extern crate libc; + +fn main() { + let rw = std::cell::UnsafeCell::new(libc::PTHREAD_RWLOCK_INITIALIZER); + unsafe { + assert_eq!(libc::pthread_rwlock_wrlock(rw.get()), 0); + libc::pthread_rwlock_rdlock(rw.get()); //~ ERROR: deadlock + } +} diff --git a/tests/compile-fail/sync/libc_pthread_rwlock_write_write_deadlock.rs b/tests/compile-fail/sync/libc_pthread_rwlock_write_write_deadlock.rs index cc327ec46bc29..098c1c2fe26cc 100644 --- a/tests/compile-fail/sync/libc_pthread_rwlock_write_write_deadlock.rs +++ b/tests/compile-fail/sync/libc_pthread_rwlock_write_write_deadlock.rs @@ -4,10 +4,29 @@ extern crate libc; +use std::cell::UnsafeCell; +use std::sync::Arc; +use std::thread; + +struct RwLock(UnsafeCell); + +unsafe impl Send for RwLock {} +unsafe impl Sync for RwLock {} + +fn new_lock() -> Arc { + Arc::new(RwLock(UnsafeCell::new(libc::PTHREAD_RWLOCK_INITIALIZER))) +} + fn main() { - let rw = std::cell::UnsafeCell::new(libc::PTHREAD_RWLOCK_INITIALIZER); unsafe { - assert_eq!(libc::pthread_rwlock_wrlock(rw.get()), 0); - libc::pthread_rwlock_wrlock(rw.get()); //~ ERROR: deadlock + let lock = new_lock(); + assert_eq!(libc::pthread_rwlock_wrlock(lock.0.get() as *mut _), 0); + + let lock_copy = lock.clone(); + thread::spawn(move || { + assert_eq!(libc::pthread_rwlock_wrlock(lock_copy.0.get() as *mut _), 0); //~ ERROR: deadlock + }) + .join() + .unwrap(); } } diff --git a/tests/compile-fail/sync/libc_pthread_rwlock_write_write_deadlock_single_thread.rs b/tests/compile-fail/sync/libc_pthread_rwlock_write_write_deadlock_single_thread.rs new file mode 100644 index 0000000000000..cc327ec46bc29 --- /dev/null +++ b/tests/compile-fail/sync/libc_pthread_rwlock_write_write_deadlock_single_thread.rs @@ -0,0 +1,13 @@ +// ignore-windows: No libc on Windows + +#![feature(rustc_private)] + +extern crate libc; + +fn main() { + let rw = std::cell::UnsafeCell::new(libc::PTHREAD_RWLOCK_INITIALIZER); + unsafe { + assert_eq!(libc::pthread_rwlock_wrlock(rw.get()), 0); + libc::pthread_rwlock_wrlock(rw.get()); //~ ERROR: deadlock + } +} diff --git a/tests/run-pass/concurrency/locks.rs b/tests/run-pass/concurrency/locks.rs index 90c10b8ffe247..f5469712c5f55 100644 --- a/tests/run-pass/concurrency/locks.rs +++ b/tests/run-pass/concurrency/locks.rs @@ -1,4 +1,4 @@ -// ignore-windows +// ignore-windows: Concurrency on Windows is not supported yet. use std::sync::{Arc, Mutex, RwLock}; use std::thread; @@ -11,6 +11,7 @@ fn check_mutex() { let data = Arc::clone(&data); let thread = thread::spawn(move || { let mut data = data.lock().unwrap(); + thread::yield_now(); *data += 1; }); threads.push(thread); @@ -34,6 +35,7 @@ fn check_rwlock_write() { let data = Arc::clone(&data); let thread = thread::spawn(move || { let mut data = data.write().unwrap(); + thread::yield_now(); *data += 1; }); threads.push(thread); diff --git a/tests/run-pass/concurrency/locks.stderr b/tests/run-pass/concurrency/locks.stderr index 20a2bf3eeb878..2dbfb7721d368 100644 --- a/tests/run-pass/concurrency/locks.stderr +++ b/tests/run-pass/concurrency/locks.stderr @@ -1,2 +1,2 @@ -warning: The thread support is experimental. For example, Miri does not detect data races yet. +warning: thread support is experimental. For example, Miri does not detect data races yet. diff --git a/tests/run-pass/concurrency/simple.rs b/tests/run-pass/concurrency/simple.rs index 5adc521f59c22..ad47bb144b58d 100644 --- a/tests/run-pass/concurrency/simple.rs +++ b/tests/run-pass/concurrency/simple.rs @@ -1,4 +1,4 @@ -// ignore-windows +// ignore-windows: Concurrency on Windows is not supported yet. use std::thread; diff --git a/tests/run-pass/concurrency/simple.stderr b/tests/run-pass/concurrency/simple.stderr index 20a2bf3eeb878..2dbfb7721d368 100644 --- a/tests/run-pass/concurrency/simple.stderr +++ b/tests/run-pass/concurrency/simple.stderr @@ -1,2 +1,2 @@ -warning: The thread support is experimental. For example, Miri does not detect data races yet. +warning: thread support is experimental. For example, Miri does not detect data races yet. diff --git a/tests/run-pass/concurrency/thread_locals.rs b/tests/run-pass/concurrency/thread_locals.rs index 1805a1da3d0bf..384c2ac9155b2 100644 --- a/tests/run-pass/concurrency/thread_locals.rs +++ b/tests/run-pass/concurrency/thread_locals.rs @@ -1,4 +1,9 @@ -// ignore-windows +// ignore-windows: Concurrency on Windows is not supported yet. + +//! The main purpose of this test is to check that if we take a pointer to +//! thread's `t1` thread-local `A` and send it to another thread `t2`, +//! dereferencing the pointer on `t2` resolves to `t1`'s thread-local. In this +//! test, we also check that thread-locals act as per-thread statics. #![feature(thread_local)] diff --git a/tests/run-pass/concurrency/thread_locals.stderr b/tests/run-pass/concurrency/thread_locals.stderr index 20a2bf3eeb878..2dbfb7721d368 100644 --- a/tests/run-pass/concurrency/thread_locals.stderr +++ b/tests/run-pass/concurrency/thread_locals.stderr @@ -1,2 +1,2 @@ -warning: The thread support is experimental. For example, Miri does not detect data races yet. +warning: thread support is experimental. For example, Miri does not detect data races yet. From 17f7bc86ae4bf5d160ae13552387afb922f75cdc Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Sun, 19 Apr 2020 15:23:30 -0700 Subject: [PATCH 1960/3747] Fix how a pthread_create function argument is constructed. --- src/shims/thread.rs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/shims/thread.rs b/src/shims/thread.rs index ab3b436b86655..ee4369cb412e7 100644 --- a/src/shims/thread.rs +++ b/src/shims/thread.rs @@ -37,11 +37,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let fn_ptr = this.read_scalar(start_routine)?.not_undef()?; let instance = this.memory.get_fn(fn_ptr)?.as_instance()?; - let func_arg = match *arg { - rustc_mir::interpret::Operand::Immediate(immediate) => immediate, - _ => unreachable!(), - }; - let func_args = [func_arg]; + let func_arg = this.read_immediate(arg)?; + let func_args = [*func_arg]; let ret_place = this.allocate(this.layout_of(this.tcx.types.usize)?, MiriMemoryKind::Machine.into()); From 5b55e0706c3fff3fd015e5396422a2a1eda19779 Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Sun, 19 Apr 2020 16:42:58 -0700 Subject: [PATCH 1961/3747] Add more concurrency tests. --- .../libc_pthread_create_main_terminate.rs | 24 +++++++++++++++ .../concurrency/libc_pthread_join_detached.rs | 24 +++++++++++++++ .../concurrency/libc_pthread_join_joined.rs | 24 +++++++++++++++ .../concurrency/libc_pthread_join_multiple.rs | 30 +++++++++++++++++++ .../concurrency/libc_pthread_join_self.rs | 16 ++++++++++ 5 files changed, 118 insertions(+) create mode 100644 tests/compile-fail/concurrency/libc_pthread_create_main_terminate.rs create mode 100644 tests/compile-fail/concurrency/libc_pthread_join_detached.rs create mode 100644 tests/compile-fail/concurrency/libc_pthread_join_joined.rs create mode 100644 tests/compile-fail/concurrency/libc_pthread_join_multiple.rs create mode 100644 tests/compile-fail/concurrency/libc_pthread_join_self.rs diff --git a/tests/compile-fail/concurrency/libc_pthread_create_main_terminate.rs b/tests/compile-fail/concurrency/libc_pthread_create_main_terminate.rs new file mode 100644 index 0000000000000..e34d3f5c93bce --- /dev/null +++ b/tests/compile-fail/concurrency/libc_pthread_create_main_terminate.rs @@ -0,0 +1,24 @@ +// ignore-windows: Concurrency on Windows is not supported yet. + +// Check that we terminate the program when the main thread terminates. + +//~^^^^ ERROR: unsupported operation: the main thread terminated without waiting for other threads + +#![feature(rustc_private)] + +extern crate libc; + +use std::{mem, ptr}; + +extern "C" fn thread_start(_null: *mut libc::c_void) -> *mut libc::c_void { + ptr::null_mut() +} + +fn main() { + unsafe { + let mut native: libc::pthread_t = mem::zeroed(); + let attr: libc::pthread_attr_t = mem::zeroed(); + // assert_eq!(libc::pthread_attr_init(&mut attr), 0); FIXME: this function is not yet implemented. + assert_eq!(libc::pthread_create(&mut native, &attr, thread_start, ptr::null_mut()), 0); + } +} diff --git a/tests/compile-fail/concurrency/libc_pthread_join_detached.rs b/tests/compile-fail/concurrency/libc_pthread_join_detached.rs new file mode 100644 index 0000000000000..ad83fb2efef3d --- /dev/null +++ b/tests/compile-fail/concurrency/libc_pthread_join_detached.rs @@ -0,0 +1,24 @@ +// ignore-windows: Concurrency on Windows is not supported yet. + +// Joining a detached thread is undefined behavior. + +#![feature(rustc_private)] + +extern crate libc; + +use std::{mem, ptr}; + +extern "C" fn thread_start(_null: *mut libc::c_void) -> *mut libc::c_void { + ptr::null_mut() +} + +fn main() { + unsafe { + let mut native: libc::pthread_t = mem::zeroed(); + let attr: libc::pthread_attr_t = mem::zeroed(); + // assert_eq!(libc::pthread_attr_init(&mut attr), 0); FIXME: this function is not yet implemented. + assert_eq!(libc::pthread_create(&mut native, &attr, thread_start, ptr::null_mut()), 0); + assert_eq!(libc::pthread_detach(native), 0); + assert_eq!(libc::pthread_join(native, ptr::null_mut()), 0); //~ ERROR: Undefined Behavior: trying to join a detached or already joined thread + } +} diff --git a/tests/compile-fail/concurrency/libc_pthread_join_joined.rs b/tests/compile-fail/concurrency/libc_pthread_join_joined.rs new file mode 100644 index 0000000000000..3ca0424496904 --- /dev/null +++ b/tests/compile-fail/concurrency/libc_pthread_join_joined.rs @@ -0,0 +1,24 @@ +// ignore-windows: Concurrency on Windows is not supported yet. + +// Joining an already joined thread is undefined behavior. + +#![feature(rustc_private)] + +extern crate libc; + +use std::{mem, ptr}; + +extern "C" fn thread_start(_null: *mut libc::c_void) -> *mut libc::c_void { + ptr::null_mut() +} + +fn main() { + unsafe { + let mut native: libc::pthread_t = mem::zeroed(); + let attr: libc::pthread_attr_t = mem::zeroed(); + // assert_eq!(libc::pthread_attr_init(&mut attr), 0); FIXME: this function is not yet implemented. + assert_eq!(libc::pthread_create(&mut native, &attr, thread_start, ptr::null_mut()), 0); + assert_eq!(libc::pthread_join(native, ptr::null_mut()), 0); + assert_eq!(libc::pthread_join(native, ptr::null_mut()), 0); //~ ERROR: Undefined Behavior: trying to join a detached or already joined thread + } +} diff --git a/tests/compile-fail/concurrency/libc_pthread_join_multiple.rs b/tests/compile-fail/concurrency/libc_pthread_join_multiple.rs new file mode 100644 index 0000000000000..08ce94022c6f1 --- /dev/null +++ b/tests/compile-fail/concurrency/libc_pthread_join_multiple.rs @@ -0,0 +1,30 @@ +// ignore-windows: Concurrency on Windows is not supported yet. + +// Joining the same thread multiple times is undefined behavior. + +#![feature(rustc_private)] + +extern crate libc; + +use std::thread; +use std::{mem, ptr}; + +extern "C" fn thread_start(_null: *mut libc::c_void) -> *mut libc::c_void { + ptr::null_mut() +} + +fn main() { + unsafe { + let mut native: libc::pthread_t = mem::zeroed(); + let attr: libc::pthread_attr_t = mem::zeroed(); + // assert_eq!(libc::pthread_attr_init(&mut attr), 0); FIXME: this function is not yet implemented. + assert_eq!(libc::pthread_create(&mut native, &attr, thread_start, ptr::null_mut()), 0); + let mut native_copy: libc::pthread_t = mem::zeroed(); + ptr::copy_nonoverlapping(&native, &mut native_copy, 1); + let handle = thread::spawn(move || { + assert_eq!(libc::pthread_join(native_copy, ptr::null_mut()), 0); //~ ERROR: Undefined Behavior: trying to join a detached or already joined thread + }); + assert_eq!(libc::pthread_join(native, ptr::null_mut()), 0); + handle.join().unwrap(); + } +} diff --git a/tests/compile-fail/concurrency/libc_pthread_join_self.rs b/tests/compile-fail/concurrency/libc_pthread_join_self.rs new file mode 100644 index 0000000000000..1aeb274dcd1db --- /dev/null +++ b/tests/compile-fail/concurrency/libc_pthread_join_self.rs @@ -0,0 +1,16 @@ +// ignore-windows: Concurrency on Windows is not supported yet. + +// Joining itself is undefined behavior. + +#![feature(rustc_private)] + +extern crate libc; + +use std::ptr; + +fn main() { + unsafe { + let native: libc::pthread_t = libc::pthread_self(); + assert_eq!(libc::pthread_join(native, ptr::null_mut()), 0); //~ ERROR: Undefined Behavior: trying to join itself + } +} From e4dc3567f8bb2b5b50230aa31d4ad57b631ac8db Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Sun, 19 Apr 2020 16:43:40 -0700 Subject: [PATCH 1962/3747] Track if a thread was already joined. --- src/thread.rs | 57 ++++++++++++++++++++++++++++++++++----------------- 1 file changed, 38 insertions(+), 19 deletions(-) diff --git a/src/thread.rs b/src/thread.rs index 5eb6560a09e64..657792bd2c676 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -92,6 +92,18 @@ pub enum ThreadState { Terminated, } +/// The join status of a thread. +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +enum ThreadJoinStatus { + /// The thread can be joined. + Joinable, + /// A thread is detached if its join handle was destroyed and no other + /// thread can join it. + Detached, + /// The thread was already joined by some thread and cannot be joined again. + Joined, +} + /// A thread. pub struct Thread<'mir, 'tcx> { state: ThreadState, @@ -99,11 +111,8 @@ pub struct Thread<'mir, 'tcx> { thread_name: Option>, /// The virtual call stack. stack: Vec>>, - /// Is the thread detached? - /// - /// A thread is detached if its join handle was destroyed and no other - /// thread can join it. - detached: bool, + /// The join status. + join_status: ThreadJoinStatus, } impl<'mir, 'tcx> Thread<'mir, 'tcx> { @@ -128,7 +137,12 @@ impl<'mir, 'tcx> std::fmt::Debug for Thread<'mir, 'tcx> { impl<'mir, 'tcx> Default for Thread<'mir, 'tcx> { fn default() -> Self { - Self { state: ThreadState::Enabled, thread_name: None, stack: Vec::new(), detached: false } + Self { + state: ThreadState::Enabled, + thread_name: None, + stack: Vec::new(), + join_status: ThreadJoinStatus::Joinable, + } } } @@ -225,25 +239,31 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { /// Mark the thread as detached, which means that no other thread will try /// to join it and the thread is responsible for cleaning up. - fn detach_thread(&mut self, id: ThreadId) { - self.threads[id].detached = true; + fn detach_thread(&mut self, id: ThreadId) -> InterpResult<'tcx> { + if self.threads[id].join_status != ThreadJoinStatus::Joinable { + throw_ub_format!("trying to detach thread that was already detached or joined"); + } + self.threads[id].join_status = ThreadJoinStatus::Detached; + Ok(()) } /// Mark that the active thread tries to join the thread with `joined_thread_id`. fn join_thread(&mut self, joined_thread_id: ThreadId) -> InterpResult<'tcx> { - if self.threads[joined_thread_id].detached { - throw_ub_format!("trying to join a detached thread"); + if self.threads[joined_thread_id].join_status != ThreadJoinStatus::Joinable { + throw_ub_format!("trying to join a detached or already joined thread"); } if joined_thread_id == self.active_thread { throw_ub_format!("trying to join itself"); } - if self - .threads - .iter() - .any(|thread| thread.state == ThreadState::BlockedOnJoin(joined_thread_id)) - { - throw_ub_format!("multiple threads try to join the same thread"); - } + assert!( + self.threads + .iter() + .all(|thread| thread.state != ThreadState::BlockedOnJoin(joined_thread_id)), + "a joinable thread has threads waiting for its termination" + ); + // Mark the joined thread as being joined so that we detect if other + // threads try to join it. + self.threads[joined_thread_id].join_status = ThreadJoinStatus::Joined; if self.threads[joined_thread_id].state != ThreadState::Terminated { // The joined thread is still running, we need to wait for it. self.active_thread_mut().state = ThreadState::BlockedOnJoin(joined_thread_id); @@ -451,8 +471,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx #[inline] fn detach_thread(&mut self, thread_id: ThreadId) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - this.machine.threads.detach_thread(thread_id); - Ok(()) + this.machine.threads.detach_thread(thread_id) } #[inline] From 9a01c3fa3e294cfb22fb259da05e54f7ec2a6320 Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Sun, 19 Apr 2020 20:52:53 -0700 Subject: [PATCH 1963/3747] Clarify comments about TLS destructor handling in Windows, add a test for TLS destructors. --- src/eval.rs | 3 +- src/shims/tls.rs | 3 +- src/thread.rs | 11 +++++ .../concurrency/dangling_tls_lib.rs | 3 ++ tests/run-pass/concurrency/tls_lib_drop.rs | 46 +++++++++++++++++++ .../run-pass/concurrency/tls_lib_drop.stderr | 2 + .../run-pass/concurrency/tls_lib_drop.stdout | 2 + 7 files changed, 67 insertions(+), 3 deletions(-) create mode 100644 tests/run-pass/concurrency/tls_lib_drop.rs create mode 100644 tests/run-pass/concurrency/tls_lib_drop.stderr create mode 100644 tests/run-pass/concurrency/tls_lib_drop.stdout diff --git a/src/eval.rs b/src/eval.rs index ab82c39836b2e..c5a04d75858cd 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -222,7 +222,8 @@ pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) -> // Read the return code pointer *before* we run TLS destructors, to assert // that it was written to by the time that `start` lang item returned. let return_code = ecx.read_scalar(ret_place.into())?.not_undef()?.to_machine_isize(&ecx)?; - // Global destructors. + // Run Windows destructors. (We do not support concurrency on Windows + // yet, so we run the destructor of the main thread separately.) ecx.run_windows_tls_dtors()?; Ok(return_code) })(); diff --git a/src/shims/tls.rs b/src/shims/tls.rs index c08ec78c136da..31a9ee3c94251 100644 --- a/src/shims/tls.rs +++ b/src/shims/tls.rs @@ -6,7 +6,6 @@ use std::collections::HashSet; use log::trace; -use rustc_index::vec::Idx; use rustc_middle::ty; use rustc_target::abi::{Size, HasDataLayout}; @@ -201,7 +200,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx return Ok(()); } let active_thread = this.get_active_thread()?; - assert_eq!(active_thread.index(), 0, "concurrency on Windows not supported"); + assert_eq!(this.get_total_thread_count()?, 1, "concurrency on Windows not supported"); assert!(!this.machine.tls.dtors_running.contains(&active_thread), "running TLS dtors twice"); this.machine.tls.dtors_running.insert(active_thread); // Windows has a special magic linker section that is run on certain events. diff --git a/src/thread.rs b/src/thread.rs index 657792bd2c676..8c353d6a8853c 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -227,6 +227,11 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { self.active_thread } + /// Get the total number of threads that were ever spawn by this program. + fn get_total_thread_count(&self) -> usize { + self.threads.len() + } + /// Has the given thread terminated? fn has_terminated(&self, thread_id: ThreadId) -> bool { self.threads[thread_id].state == ThreadState::Terminated @@ -492,6 +497,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(this.machine.threads.get_active_thread_id()) } + #[inline] + fn get_total_thread_count(&self) -> InterpResult<'tcx, usize> { + let this = self.eval_context_ref(); + Ok(this.machine.threads.get_total_thread_count()) + } + #[inline] fn has_terminated(&self, thread_id: ThreadId) -> InterpResult<'tcx, bool> { let this = self.eval_context_ref(); diff --git a/tests/compile-fail/concurrency/dangling_tls_lib.rs b/tests/compile-fail/concurrency/dangling_tls_lib.rs index 684dd0e86f608..6be5538bb444d 100644 --- a/tests/compile-fail/concurrency/dangling_tls_lib.rs +++ b/tests/compile-fail/concurrency/dangling_tls_lib.rs @@ -1,5 +1,8 @@ // ignore-windows: Concurrency on Windows is not supported yet. +//! Check that we catch if a thread local is accessed after the thread has +//! terminated. + #![feature(thread_local_internals)] use std::cell::RefCell; diff --git a/tests/run-pass/concurrency/tls_lib_drop.rs b/tests/run-pass/concurrency/tls_lib_drop.rs new file mode 100644 index 0000000000000..c9b04a728258b --- /dev/null +++ b/tests/run-pass/concurrency/tls_lib_drop.rs @@ -0,0 +1,46 @@ +// ignore-windows: Concurrency on Windows is not supported yet. + +//! Check that destructors of the library thread locals are executed immediately +//! after a thread terminates. + +#![feature(thread_local_internals)] + +use std::cell::RefCell; +use std::thread; + +struct TestCell { + value: RefCell, +} + +impl Drop for TestCell { + fn drop(&mut self) { + println!("Dropping: {}", self.value.borrow()) + } +} + +static A: std::thread::LocalKey = { + #[inline] + fn __init() -> TestCell { + TestCell { value: RefCell::new(0) } + } + + unsafe fn __getit() -> Option<&'static TestCell> { + static __KEY: std::thread::__OsLocalKeyInner = + std::thread::__OsLocalKeyInner::new(); + __KEY.get(__init) + } + + unsafe { std::thread::LocalKey::new(__getit) } +}; + +fn main() { + thread::spawn(|| { + A.with(|f| { + assert_eq!(*f.value.borrow(), 0); + *f.value.borrow_mut() = 5; + }); + }) + .join() + .unwrap(); + println!("Continue main.") +} diff --git a/tests/run-pass/concurrency/tls_lib_drop.stderr b/tests/run-pass/concurrency/tls_lib_drop.stderr new file mode 100644 index 0000000000000..2dbfb7721d368 --- /dev/null +++ b/tests/run-pass/concurrency/tls_lib_drop.stderr @@ -0,0 +1,2 @@ +warning: thread support is experimental. For example, Miri does not detect data races yet. + diff --git a/tests/run-pass/concurrency/tls_lib_drop.stdout b/tests/run-pass/concurrency/tls_lib_drop.stdout new file mode 100644 index 0000000000000..d2bbb866b77ea --- /dev/null +++ b/tests/run-pass/concurrency/tls_lib_drop.stdout @@ -0,0 +1,2 @@ +Dropping: 5 +Continue main. From 3bb16574486ecabd702587c6811ae5154cb3b12c Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Sun, 19 Apr 2020 21:03:23 -0700 Subject: [PATCH 1964/3747] Small style fix. --- src/machine.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/machine.rs b/src/machine.rs index a81273960d09f..4032a399e3eb0 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -282,7 +282,7 @@ impl<'mir, 'tcx> Evaluator<'mir, 'tcx> { panic_payload: None, time_anchor: Instant::now(), layouts, - threads: Default::default(), + threads: ThreadManager::default(), } } } From 452e36efb3840f4b44c70c3939e3a88f27e47710 Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Sun, 19 Apr 2020 21:21:22 -0700 Subject: [PATCH 1965/3747] Print the thread name in Debug. --- src/thread.rs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/thread.rs b/src/thread.rs index 8c353d6a8853c..76f1e20cb13a1 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -131,7 +131,16 @@ impl<'mir, 'tcx> Thread<'mir, 'tcx> { impl<'mir, 'tcx> std::fmt::Debug for Thread<'mir, 'tcx> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{:?}", self.state) + if let Some(ref name) = self.thread_name { + if let Ok(name_str) = std::str::from_utf8(name) { + write!(f, "{}", name_str)?; + } else { + write!(f, "")?; + } + } else { + write!(f, "unnamed")?; + } + write!(f, "({:?}, {:?})", self.state, self.join_status) } } From 69eaaadc28e027fd749c2f6e500daa48f8c2aba3 Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Mon, 20 Apr 2020 11:53:19 -0700 Subject: [PATCH 1966/3747] Fix merge error. --- src/machine.rs | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/src/machine.rs b/src/machine.rs index 4032a399e3eb0..3853f65599596 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -545,20 +545,6 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { ecx.active_thread_stack_mut() } - #[inline(always)] - fn stack<'a>( - ecx: &'a InterpCx<'mir, 'tcx, Self>, - ) -> &'a [Frame<'mir, 'tcx, Self::PointerTag, Self::FrameExtra>] { - &ecx.machine.stack - } - - #[inline(always)] - fn stack_mut<'a>( - ecx: &'a mut InterpCx<'mir, 'tcx, Self>, - ) -> &'a mut Vec> { - &mut ecx.machine.stack - } - #[inline(always)] fn after_stack_push(ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx> { if ecx.memory.extra.stacked_borrows.is_some() { From e7c2694b8b93ad44256d7ce3d179f172a4c6a9b0 Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Mon, 20 Apr 2020 13:22:28 -0700 Subject: [PATCH 1967/3747] Make the main thread detached. --- src/thread.rs | 4 +++- .../concurrency/libc_pthread_join_self.rs | 14 +++++++++----- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/src/thread.rs b/src/thread.rs index 76f1e20cb13a1..80c9965aa1d8e 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -177,7 +177,9 @@ impl<'mir, 'tcx> Default for ThreadManager<'mir, 'tcx> { fn default() -> Self { let mut threads = IndexVec::new(); // Create the main thread and add it to the list of threads. - threads.push(Default::default()); + let mut main_thread = Thread::default(); + main_thread.join_status = ThreadJoinStatus::Detached; + threads.push(main_thread); Self { active_thread: ThreadId::new(0), threads: threads, diff --git a/tests/compile-fail/concurrency/libc_pthread_join_self.rs b/tests/compile-fail/concurrency/libc_pthread_join_self.rs index 1aeb274dcd1db..d765a95d8be7a 100644 --- a/tests/compile-fail/concurrency/libc_pthread_join_self.rs +++ b/tests/compile-fail/concurrency/libc_pthread_join_self.rs @@ -6,11 +6,15 @@ extern crate libc; -use std::ptr; +use std::{ptr, thread}; fn main() { - unsafe { - let native: libc::pthread_t = libc::pthread_self(); - assert_eq!(libc::pthread_join(native, ptr::null_mut()), 0); //~ ERROR: Undefined Behavior: trying to join itself - } + let handle = thread::spawn(|| { + unsafe { + let native: libc::pthread_t = libc::pthread_self(); + assert_eq!(libc::pthread_join(native, ptr::null_mut()), 0); //~ ERROR: Undefined Behavior: trying to join itself + } + }); + thread::yield_now(); + handle.join().unwrap(); } From e7b82fde4a06ec7a75511a900379017d37d991fd Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Mon, 20 Apr 2020 13:22:51 -0700 Subject: [PATCH 1968/3747] Fix the test annotation. --- .../concurrency/libc_pthread_create_main_terminate.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/compile-fail/concurrency/libc_pthread_create_main_terminate.rs b/tests/compile-fail/concurrency/libc_pthread_create_main_terminate.rs index e34d3f5c93bce..ea11691955ce7 100644 --- a/tests/compile-fail/concurrency/libc_pthread_create_main_terminate.rs +++ b/tests/compile-fail/concurrency/libc_pthread_create_main_terminate.rs @@ -1,9 +1,8 @@ // ignore-windows: Concurrency on Windows is not supported yet. +// error-pattern: unsupported operation: the main thread terminated without waiting for other threads // Check that we terminate the program when the main thread terminates. -//~^^^^ ERROR: unsupported operation: the main thread terminated without waiting for other threads - #![feature(rustc_private)] extern crate libc; From 40e50bf58bd82482026bb1e1f0766bdf909fe9cb Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Mon, 20 Apr 2020 13:23:11 -0700 Subject: [PATCH 1969/3747] Clarify test comments. --- tests/compile-fail/concurrency/libc_pthread_join_multiple.rs | 2 +- tests/run-pass/concurrency/tls_lib_drop.rs | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/tests/compile-fail/concurrency/libc_pthread_join_multiple.rs b/tests/compile-fail/concurrency/libc_pthread_join_multiple.rs index 08ce94022c6f1..949fcc282f0f6 100644 --- a/tests/compile-fail/concurrency/libc_pthread_join_multiple.rs +++ b/tests/compile-fail/concurrency/libc_pthread_join_multiple.rs @@ -1,6 +1,6 @@ // ignore-windows: Concurrency on Windows is not supported yet. -// Joining the same thread multiple times is undefined behavior. +// Joining the same thread from multiple threads is undefined behavior. #![feature(rustc_private)] diff --git a/tests/run-pass/concurrency/tls_lib_drop.rs b/tests/run-pass/concurrency/tls_lib_drop.rs index c9b04a728258b..d39528cfefe37 100644 --- a/tests/run-pass/concurrency/tls_lib_drop.rs +++ b/tests/run-pass/concurrency/tls_lib_drop.rs @@ -2,6 +2,9 @@ //! Check that destructors of the library thread locals are executed immediately //! after a thread terminates. +//! +//! FIXME: We should have a similar test for thread-local statics (statics +//! annotated with `#[thread_local]`) once they support destructors. #![feature(thread_local_internals)] From 8a7dbde372388c0f4125f3aad0f697f8af138026 Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Mon, 20 Apr 2020 16:49:27 -0700 Subject: [PATCH 1970/3747] Check prctl argument types and fix the test. --- src/shims/thread.rs | 20 ++++++++++++++++--- .../concurrency/libc_prctl_thread_name.rs | 4 ++-- 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/src/shims/thread.rs b/src/shims/thread.rs index ee4369cb412e7..65187326223cd 100644 --- a/src/shims/thread.rs +++ b/src/shims/thread.rs @@ -92,12 +92,26 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx &mut self, option: OpTy<'tcx, Tag>, arg2: OpTy<'tcx, Tag>, - _arg3: OpTy<'tcx, Tag>, - _arg4: OpTy<'tcx, Tag>, - _arg5: OpTy<'tcx, Tag>, + arg3: OpTy<'tcx, Tag>, + arg4: OpTy<'tcx, Tag>, + arg5: OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); + // prctl last 5 arguments are declared as variadic. Therefore, we need + // to check their types manually. + let c_long_size = this.libc_ty_layout("c_long")?.size.bytes(); + let check_arg = |arg: OpTy<'tcx, Tag>| -> InterpResult<'tcx> { + match this.read_scalar(arg)?.not_undef()? { + Scalar::Raw { size, .. } if u64::from(size) == c_long_size => Ok(()), + _ => throw_ub_format!("an argument of unsupported type was passed to prctl"), + } + }; + check_arg(arg2)?; + check_arg(arg3)?; + check_arg(arg4)?; + check_arg(arg5)?; + let option = this.read_scalar(option)?.not_undef()?.to_i32()?; if option == this.eval_libc_i32("PR_SET_NAME")? { let address = this.read_scalar(arg2)?.not_undef()?; diff --git a/tests/run-pass/concurrency/libc_prctl_thread_name.rs b/tests/run-pass/concurrency/libc_prctl_thread_name.rs index 235ac27e0a59f..aa3f62f03d77a 100644 --- a/tests/run-pass/concurrency/libc_prctl_thread_name.rs +++ b/tests/run-pass/concurrency/libc_prctl_thread_name.rs @@ -9,9 +9,9 @@ use std::ffi::CString; fn main() { unsafe { let thread_name = CString::new("hello").expect("CString::new failed"); - assert_eq!(libc::prctl(libc::PR_SET_NAME, thread_name.as_ptr() as u64, 0, 0, 0), 0); + assert_eq!(libc::prctl(libc::PR_SET_NAME, thread_name.as_ptr() as libc::c_long, 0 as libc::c_long, 0 as libc::c_long, 0 as libc::c_long), 0); let mut buf = [0; 6]; - assert_eq!(libc::prctl(libc::PR_GET_NAME, buf.as_mut_ptr() as u64, 0, 0, 0), 0); + assert_eq!(libc::prctl(libc::PR_GET_NAME, buf.as_mut_ptr() as libc::c_long, 0 as libc::c_long, 0 as libc::c_long, 0 as libc::c_long), 0); assert_eq!(thread_name.as_bytes_with_nul(), buf); } } From d45e985669d1bc532862ed3a50dce9cfdf08d7ff Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Mon, 20 Apr 2020 16:57:30 -0700 Subject: [PATCH 1971/3747] Clarify FIXME. --- src/thread.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/thread.rs b/src/thread.rs index 80c9965aa1d8e..aee9b8a6f56d3 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -357,7 +357,12 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { if self.threads[MAIN_THREAD].state == ThreadState::Terminated { // The main thread terminated; stop the program. if self.threads.iter().any(|thread| thread.state != ThreadState::Terminated) { - // FIXME: This check should be either configurable or just emit a warning. + // FIXME: This check should be either configurable or just emit + // a warning. For example, it seems normal for a program to + // terminate without waiting for its detached threads to + // terminate. However, this case is not trivial to support + // because we also probably do not want to consider the memory + // owned by these threads as leaked. throw_unsup_format!("the main thread terminated without waiting for other threads"); } return Ok(SchedulingAction::Stop); From eaa63266d8456ac8c3d1b82f4e1078fcd271e95c Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Mon, 20 Apr 2020 17:02:43 -0700 Subject: [PATCH 1972/3747] Make multiple threads to try to join a thread while it is still running. --- tests/compile-fail/concurrency/libc_pthread_join_multiple.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/compile-fail/concurrency/libc_pthread_join_multiple.rs b/tests/compile-fail/concurrency/libc_pthread_join_multiple.rs index 949fcc282f0f6..0d99b69ed9147 100644 --- a/tests/compile-fail/concurrency/libc_pthread_join_multiple.rs +++ b/tests/compile-fail/concurrency/libc_pthread_join_multiple.rs @@ -10,6 +10,8 @@ use std::thread; use std::{mem, ptr}; extern "C" fn thread_start(_null: *mut libc::c_void) -> *mut libc::c_void { + thread::yield_now(); + thread::yield_now(); ptr::null_mut() } From cc9248a7c891614cf79e7ec708de2ff99d4eb06c Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Mon, 20 Apr 2020 17:10:25 -0700 Subject: [PATCH 1973/3747] Ignore prctl test on MacOS because it does not support it. --- tests/run-pass/concurrency/libc_prctl_thread_name.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/run-pass/concurrency/libc_prctl_thread_name.rs b/tests/run-pass/concurrency/libc_prctl_thread_name.rs index aa3f62f03d77a..b8ba27b3a8954 100644 --- a/tests/run-pass/concurrency/libc_prctl_thread_name.rs +++ b/tests/run-pass/concurrency/libc_prctl_thread_name.rs @@ -1,4 +1,5 @@ // ignore-windows: No libc on Windows +// ignore-macos: No prctl on MacOS #![feature(rustc_private)] From 90e9a87fa79f541efecadde6daa53299b9350e07 Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Mon, 20 Apr 2020 17:13:22 -0700 Subject: [PATCH 1974/3747] Add an explanatory comment to the test. --- tests/compile-fail/concurrency/libc_pthread_join_multiple.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/compile-fail/concurrency/libc_pthread_join_multiple.rs b/tests/compile-fail/concurrency/libc_pthread_join_multiple.rs index 0d99b69ed9147..f8a43cfcde647 100644 --- a/tests/compile-fail/concurrency/libc_pthread_join_multiple.rs +++ b/tests/compile-fail/concurrency/libc_pthread_join_multiple.rs @@ -10,6 +10,7 @@ use std::thread; use std::{mem, ptr}; extern "C" fn thread_start(_null: *mut libc::c_void) -> *mut libc::c_void { + // Yield the thread several times so that other threads can join it. thread::yield_now(); thread::yield_now(); ptr::null_mut() From 8240ed26a97a6d1642546e56144870305ff4676c Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Mon, 20 Apr 2020 17:23:51 -0700 Subject: [PATCH 1975/3747] Change the test not to rely on internals. --- tests/run-pass/concurrency/tls_lib_drop.rs | 22 +++------------------- 1 file changed, 3 insertions(+), 19 deletions(-) diff --git a/tests/run-pass/concurrency/tls_lib_drop.rs b/tests/run-pass/concurrency/tls_lib_drop.rs index d39528cfefe37..0d1808cbe0fa4 100644 --- a/tests/run-pass/concurrency/tls_lib_drop.rs +++ b/tests/run-pass/concurrency/tls_lib_drop.rs @@ -2,11 +2,6 @@ //! Check that destructors of the library thread locals are executed immediately //! after a thread terminates. -//! -//! FIXME: We should have a similar test for thread-local statics (statics -//! annotated with `#[thread_local]`) once they support destructors. - -#![feature(thread_local_internals)] use std::cell::RefCell; use std::thread; @@ -21,20 +16,9 @@ impl Drop for TestCell { } } -static A: std::thread::LocalKey = { - #[inline] - fn __init() -> TestCell { - TestCell { value: RefCell::new(0) } - } - - unsafe fn __getit() -> Option<&'static TestCell> { - static __KEY: std::thread::__OsLocalKeyInner = - std::thread::__OsLocalKeyInner::new(); - __KEY.get(__init) - } - - unsafe { std::thread::LocalKey::new(__getit) } -}; +thread_local! { + static A: TestCell = TestCell { value: RefCell::new(0) }; +} fn main() { thread::spawn(|| { From feb188360ee5ff6ae4cdc8e6a20ec29f9cd385ba Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Fri, 24 Apr 2020 15:16:24 -0700 Subject: [PATCH 1976/3747] Unify TLS dtors; move stepping outside. --- src/eval.rs | 7 +- src/shims/tls.rs | 112 +++++++++++------- src/thread.rs | 13 ++ .../concurrency/tls_lib_drop_single_thread.rs | 25 ++++ .../tls_lib_drop_single_thread.stderr | 2 + 5 files changed, 110 insertions(+), 49 deletions(-) create mode 100644 tests/run-pass/concurrency/tls_lib_drop_single_thread.rs create mode 100644 tests/run-pass/concurrency/tls_lib_drop_single_thread.stderr diff --git a/src/eval.rs b/src/eval.rs index c5a04d75858cd..9131946f8dc16 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -211,7 +211,7 @@ pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) -> assert!(ecx.step()?, "a terminated thread was scheduled for execution"); } SchedulingAction::ExecuteDtors => { - ecx.run_tls_dtors_for_active_thread()?; + ecx.schedule_tls_dtors_for_active_thread()?; } SchedulingAction::Stop => { break; @@ -219,12 +219,7 @@ pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) -> } ecx.process_diagnostics(); } - // Read the return code pointer *before* we run TLS destructors, to assert - // that it was written to by the time that `start` lang item returned. let return_code = ecx.read_scalar(ret_place.into())?.not_undef()?.to_machine_isize(&ecx)?; - // Run Windows destructors. (We do not support concurrency on Windows - // yet, so we run the destructor of the main thread separately.) - ecx.run_windows_tls_dtors()?; Ok(return_code) })(); diff --git a/src/shims/tls.rs b/src/shims/tls.rs index 31a9ee3c94251..615950621a247 100644 --- a/src/shims/tls.rs +++ b/src/shims/tls.rs @@ -38,6 +38,9 @@ pub struct TlsData<'tcx> { /// Whether we are in the "destruct" phase, during which some operations are UB. dtors_running: HashSet, + + /// The last TlsKey used to retrieve a TLS destructor. + last_dtor_key: BTreeMap, } impl<'tcx> Default for TlsData<'tcx> { @@ -47,6 +50,7 @@ impl<'tcx> Default for TlsData<'tcx> { keys: Default::default(), global_dtors: Default::default(), dtors_running: Default::default(), + last_dtor_key: Default::default(), } } } @@ -187,21 +191,15 @@ impl<'tcx> TlsData<'tcx> { } } -impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} -pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { - - /// Run TLS destructors for the main thread on Windows. The implementation - /// assumes that we do not support concurrency on Windows yet. - /// - /// Note: on non-Windows OS this function is a no-op. - fn run_windows_tls_dtors(&mut self) -> InterpResult<'tcx> { +impl<'mir, 'tcx: 'mir> EvalContextPrivExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} +trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { + /// Schedule TLS destructors for the main thread on Windows. The + /// implementation assumes that we do not support concurrency on Windows + /// yet. + fn schedule_windows_tls_dtors(&mut self) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - if this.tcx.sess.target.target.target_os != "windows" { - return Ok(()); - } let active_thread = this.get_active_thread()?; assert_eq!(this.get_total_thread_count()?, 1, "concurrency on Windows not supported"); - assert!(!this.machine.tls.dtors_running.contains(&active_thread), "running TLS dtors twice"); this.machine.tls.dtors_running.insert(active_thread); // Windows has a special magic linker section that is run on certain events. // Instead of searching for that section and supporting arbitrary hooks in there @@ -221,30 +219,18 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx StackPopCleanup::None { cleanup: true }, )?; - // step until out of stackframes - this.run()?; - - // Windows doesn't have other destructors. + this.enable_thread(active_thread)?; Ok(()) } - /// Run TLS destructors for the active thread. + /// Schedule the MacOS global dtor to be executed. /// - /// Note: on Windows OS this function is a no-op because we do not support - /// concurrency on Windows yet. - /// - /// FIXME: we do not support yet deallocation of thread local statics. - fn run_tls_dtors_for_active_thread(&mut self) -> InterpResult<'tcx> { + /// Note: It is safe to call this function also on other Unixes. + fn schedule_macos_global_tls_dtors(&mut self) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - if this.tcx.sess.target.target.target_os == "windows" { - return Ok(()); - } let thread_id = this.get_active_thread()?; - assert!(!this.machine.tls.dtors_running.contains(&thread_id), "running TLS dtors twice"); - this.machine.tls.dtors_running.insert(thread_id); - // The macOS global dtor runs "before any TLS slots get freed", so do that first. - if let Some(&(instance, data)) = this.machine.tls.global_dtors.get(&thread_id) { + if let Some((instance, data)) = this.machine.tls.global_dtors.remove(&thread_id) { trace!("Running global dtor {:?} on {:?} at {:?}", instance, data, thread_id); let ret_place = MPlaceTy::dangling(this.machine.layouts.unit, this).into(); @@ -255,14 +241,33 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx StackPopCleanup::None { cleanup: true }, )?; - // step until out of stackframes - this.run()?; + // Enable the thread so that it steps through the destructor which + // we just scheduled. Since we deleted the destructor, it is + // guaranteed that we will schedule it again. The `dtors_running` + // flag will prevent the code from adding the destructor again. + this.enable_thread(thread_id)?; } + Ok(()) + } + + /// Schedule a pthread TLS destructor. + fn schedule_pthread_tls_dtors(&mut self) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + let active_thread = this.get_active_thread()?; - assert!(this.has_terminated(thread_id)?, "running TLS dtors for non-terminated thread"); - let mut dtor = this.machine.tls.fetch_tls_dtor(None, thread_id); - while let Some((instance, ptr, key)) = dtor { - trace!("Running TLS dtor {:?} on {:?} at {:?}", instance, ptr, thread_id); + assert!(this.has_terminated(active_thread)?, "running TLS dtors for non-terminated thread"); + // Fetch next dtor after `key`. + let last_key = this.machine.tls.last_dtor_key.get(&active_thread).cloned(); + let dtor = match this.machine.tls.fetch_tls_dtor(last_key, active_thread) { + dtor @ Some(_) => dtor, + // We ran each dtor once, start over from the beginning. + None => { + this.machine.tls.fetch_tls_dtor(None, active_thread) + } + }; + if let Some((instance, ptr, key)) = dtor { + this.machine.tls.last_dtor_key.insert(active_thread, key); + trace!("Running TLS dtor {:?} on {:?} at {:?}", instance, ptr, active_thread); assert!(!this.is_null(ptr).unwrap(), "Data can't be NULL when dtor is called!"); let ret_place = MPlaceTy::dangling(this.machine.layouts.unit, this).into(); @@ -273,15 +278,36 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx StackPopCleanup::None { cleanup: true }, )?; - // step until out of stackframes - this.run()?; + this.enable_thread(active_thread)?; + return Ok(()); + } + this.machine.tls.last_dtor_key.remove(&active_thread); + + Ok(()) + } +} + +impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} +pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { - // Fetch next dtor after `key`. - dtor = match this.machine.tls.fetch_tls_dtor(Some(key), thread_id) { - dtor @ Some(_) => dtor, - // We ran each dtor once, start over from the beginning. - None => this.machine.tls.fetch_tls_dtor(None, thread_id), - }; + /// Schedule an active thread's TLS destructor to run on the active thread. + /// Note that this function does not run the destructors itself, it just + /// schedules them one by one each time it is called. + /// + /// FIXME: we do not support yet deallocation of thread local statics. + fn schedule_tls_dtors_for_active_thread(&mut self) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + let active_thread = this.get_active_thread()?; + + if this.tcx.sess.target.target.target_os == "windows" { + if !this.machine.tls.dtors_running.contains(&active_thread) { + this.machine.tls.dtors_running.insert(active_thread); + this.schedule_windows_tls_dtors()?; + } + } else { + this.machine.tls.dtors_running.insert(active_thread); + this.schedule_macos_global_tls_dtors()?; + this.schedule_pthread_tls_dtors()?; } Ok(()) diff --git a/src/thread.rs b/src/thread.rs index aee9b8a6f56d3..c4e0f9be1877b 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -248,6 +248,12 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { self.threads[thread_id].state == ThreadState::Terminated } + /// Enable the thread for execution. The thread must be terminated. + fn enable_thread(&mut self, thread_id: ThreadId) { + assert!(self.has_terminated(thread_id)); + self.threads[thread_id].state = ThreadState::Enabled; + } + /// Get the borrow of the currently active thread. fn active_thread_mut(&mut self) -> &mut Thread<'mir, 'tcx> { &mut self.threads[self.active_thread] @@ -525,6 +531,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(this.machine.threads.has_terminated(thread_id)) } + #[inline] + fn enable_thread(&mut self, thread_id: ThreadId) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + this.machine.threads.enable_thread(thread_id); + Ok(()) + } + #[inline] fn active_thread_stack(&self) -> &[Frame<'mir, 'tcx, Tag, FrameData<'tcx>>] { let this = self.eval_context_ref(); diff --git a/tests/run-pass/concurrency/tls_lib_drop_single_thread.rs b/tests/run-pass/concurrency/tls_lib_drop_single_thread.rs new file mode 100644 index 0000000000000..f232cee5bdd10 --- /dev/null +++ b/tests/run-pass/concurrency/tls_lib_drop_single_thread.rs @@ -0,0 +1,25 @@ +//! Check that destructors of the thread locals are executed on all OSes. + +use std::cell::RefCell; + +struct TestCell { + value: RefCell, +} + +impl Drop for TestCell { + fn drop(&mut self) { + eprintln!("Dropping: {}", self.value.borrow()) + } +} + +thread_local! { + static A: TestCell = TestCell { value: RefCell::new(0) }; +} + +fn main() { + A.with(|f| { + assert_eq!(*f.value.borrow(), 0); + *f.value.borrow_mut() = 5; + }); + eprintln!("Continue main.") +} diff --git a/tests/run-pass/concurrency/tls_lib_drop_single_thread.stderr b/tests/run-pass/concurrency/tls_lib_drop_single_thread.stderr new file mode 100644 index 0000000000000..a9d705e5b9a22 --- /dev/null +++ b/tests/run-pass/concurrency/tls_lib_drop_single_thread.stderr @@ -0,0 +1,2 @@ +Continue main. +Dropping: 5 From 04abf066f15c2ce2d1a788a1021bb14dcb9ac045 Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Fri, 24 Apr 2020 16:46:51 -0700 Subject: [PATCH 1977/3747] Move copying of the thread name to the client side. --- src/shims/thread.rs | 2 +- src/thread.rs | 20 ++++++++++++++------ 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/src/shims/thread.rs b/src/shims/thread.rs index 65187326223cd..67e833f222e4b 100644 --- a/src/shims/thread.rs +++ b/src/shims/thread.rs @@ -119,7 +119,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.set_active_thread_name(name)?; } else if option == this.eval_libc_i32("PR_GET_NAME")? { let address = this.read_scalar(arg2)?.not_undef()?; - let name = this.get_active_thread_name()?; + let name = this.get_active_thread_name()?.to_vec(); this.memory.write_bytes(address, name)?; } else { throw_unsup_format!("Unsupported prctl option."); diff --git a/src/thread.rs b/src/thread.rs index c4e0f9be1877b..eb7af536cf119 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -254,11 +254,16 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { self.threads[thread_id].state = ThreadState::Enabled; } - /// Get the borrow of the currently active thread. + /// Get a mutable borrow of the currently active thread. fn active_thread_mut(&mut self) -> &mut Thread<'mir, 'tcx> { &mut self.threads[self.active_thread] } + /// Get a shared borrow of the currently active thread. + fn active_thread_ref(&self) -> &Thread<'mir, 'tcx> { + &self.threads[self.active_thread] + } + /// Mark the thread as detached, which means that no other thread will try /// to join it and the thread is responsible for cleaning up. fn detach_thread(&mut self, id: ThreadId) -> InterpResult<'tcx> { @@ -304,9 +309,9 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { } /// Get the name of the active thread. - fn get_thread_name(&mut self) -> InterpResult<'tcx, Vec> { - if let Some(ref thread_name) = self.active_thread_mut().thread_name { - Ok(thread_name.clone()) + fn get_thread_name(&self) -> InterpResult<'tcx, &[u8]> { + if let Some(ref thread_name) = self.active_thread_ref().thread_name { + Ok(thread_name) } else { throw_ub_format!("thread {:?} has no name set", self.active_thread) } @@ -557,8 +562,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } #[inline] - fn get_active_thread_name(&mut self) -> InterpResult<'tcx, Vec> { - let this = self.eval_context_mut(); + fn get_active_thread_name<'c>(&'c self) -> InterpResult<'tcx, &'c [u8]> + where + 'mir: 'c, + { + let this = self.eval_context_ref(); this.machine.threads.get_thread_name() } From bc9d007e3eccae1bbb7b90bbfd2c2d583e44166f Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Fri, 24 Apr 2020 16:47:18 -0700 Subject: [PATCH 1978/3747] Improve Debug formatting of the thread name. --- src/thread.rs | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/thread.rs b/src/thread.rs index eb7af536cf119..ecdaced3f8c5d 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -132,13 +132,9 @@ impl<'mir, 'tcx> Thread<'mir, 'tcx> { impl<'mir, 'tcx> std::fmt::Debug for Thread<'mir, 'tcx> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { if let Some(ref name) = self.thread_name { - if let Ok(name_str) = std::str::from_utf8(name) { - write!(f, "{}", name_str)?; - } else { - write!(f, "")?; - } + write!(f, "{}", String::from_utf8_lossy(name))?; } else { - write!(f, "unnamed")?; + write!(f, "")?; } write!(f, "({:?}, {:?})", self.state, self.join_status) } From ff5e35b90a7717bffb4bf2f1ae898e2c73920281 Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Sun, 26 Apr 2020 14:24:48 -0700 Subject: [PATCH 1979/3747] Added a test that joining main is UB. --- .../concurrency/libc_pthread_join_main.rs | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 tests/compile-fail/concurrency/libc_pthread_join_main.rs diff --git a/tests/compile-fail/concurrency/libc_pthread_join_main.rs b/tests/compile-fail/concurrency/libc_pthread_join_main.rs new file mode 100644 index 0000000000000..69e1a68ef97ae --- /dev/null +++ b/tests/compile-fail/concurrency/libc_pthread_join_main.rs @@ -0,0 +1,20 @@ +// ignore-windows: Concurrency on Windows is not supported yet. + +// Joining the main thread is undefined behavior. + +#![feature(rustc_private)] + +extern crate libc; + +use std::{ptr, thread}; + +fn main() { + let thread_id: libc::pthread_t = unsafe { libc::pthread_self() }; + let handle = thread::spawn(move || { + unsafe { + assert_eq!(libc::pthread_join(thread_id, ptr::null_mut()), 0); //~ ERROR: Undefined Behavior: trying to join a detached or already joined thread + } + }); + thread::yield_now(); + handle.join().unwrap(); +} From 64164b10e8b321745284bf7da7656e464b4ec9f4 Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Sun, 26 Apr 2020 14:42:07 -0700 Subject: [PATCH 1980/3747] Improve comments. --- src/thread.rs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/thread.rs b/src/thread.rs index ecdaced3f8c5d..9a332a0dcf2c0 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -61,7 +61,8 @@ impl ThreadId { } } -/// An identifier of a set of blocked threads. +/// An identifier of a set of blocked threads. 0 is used to indicate the absence +/// of a blockset identifier and, therefore, is not a valid identifier. #[derive(Clone, Copy, Debug, PartialOrd, Ord, PartialEq, Eq, Hash)] pub struct BlockSetId(NonZeroU32); @@ -116,8 +117,8 @@ pub struct Thread<'mir, 'tcx> { } impl<'mir, 'tcx> Thread<'mir, 'tcx> { - /// Check if the thread terminated. If yes, change the state to terminated - /// and return `true`. + /// Check if the thread is done executing (no more stack frames). If yes, + /// change the state to terminated and return `true`. fn check_terminated(&mut self) -> bool { if self.state == ThreadState::Enabled { if self.stack.is_empty() { @@ -174,6 +175,7 @@ impl<'mir, 'tcx> Default for ThreadManager<'mir, 'tcx> { let mut threads = IndexVec::new(); // Create the main thread and add it to the list of threads. let mut main_thread = Thread::default(); + // The main thread can *not* be joined on. main_thread.join_status = ThreadJoinStatus::Detached; threads.push(main_thread); Self { @@ -282,7 +284,7 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { self.threads .iter() .all(|thread| thread.state != ThreadState::BlockedOnJoin(joined_thread_id)), - "a joinable thread has threads waiting for its termination" + "a joinable thread already has threads waiting for its termination" ); // Mark the joined thread as being joined so that we detect if other // threads try to join it. @@ -349,7 +351,7 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { /// The currently implemented scheduling policy is the one that is commonly /// used in stateless model checkers such as Loom: run the active thread as /// long as we can and switch only when we have to (the active thread was - /// blocked, terminated, or was explicitly asked to be preempted). + /// blocked, terminated, or has explicitly asked to be preempted). fn schedule(&mut self) -> InterpResult<'tcx, SchedulingAction> { if self.threads[self.active_thread].check_terminated() { // Check if we need to unblock any threads. From 60cd8aa4b0dadaf5e32bcf86ee6cbddb93c69c01 Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Sun, 26 Apr 2020 14:44:59 -0700 Subject: [PATCH 1981/3747] Delete a duplicate test. --- .../concurrency/dangling_tls_lib.rs | 49 ------------------- 1 file changed, 49 deletions(-) delete mode 100644 tests/compile-fail/concurrency/dangling_tls_lib.rs diff --git a/tests/compile-fail/concurrency/dangling_tls_lib.rs b/tests/compile-fail/concurrency/dangling_tls_lib.rs deleted file mode 100644 index 6be5538bb444d..0000000000000 --- a/tests/compile-fail/concurrency/dangling_tls_lib.rs +++ /dev/null @@ -1,49 +0,0 @@ -// ignore-windows: Concurrency on Windows is not supported yet. - -//! Check that we catch if a thread local is accessed after the thread has -//! terminated. - -#![feature(thread_local_internals)] - -use std::cell::RefCell; -use std::thread; - -static A: std::thread::LocalKey> = { - #[inline] - fn __init() -> RefCell { - RefCell::new(0) - } - - unsafe fn __getit() -> Option<&'static RefCell> { - static __KEY: std::thread::__OsLocalKeyInner> = - std::thread::__OsLocalKeyInner::new(); - __KEY.get(__init) - } - - unsafe { std::thread::LocalKey::new(__getit) } -}; - -struct Sender(*mut u8); - -unsafe impl Send for Sender {} - -fn main() { - A.with(|f| { - assert_eq!(*f.borrow(), 0); - *f.borrow_mut() = 4; - }); - - let handle = thread::spawn(|| { - let ptr = A.with(|f| { - assert_eq!(*f.borrow(), 0); - *f.borrow_mut() = 5; - &mut *f.borrow_mut() as *mut u8 - }); - Sender(ptr) - }); - let ptr = handle.join().unwrap().0; - A.with(|f| { - assert_eq!(*f.borrow(), 4); - }); - let _x = unsafe { *ptr }; //~ ERROR Undefined Behavior -} From 39efdf31cf4f69ac0e33f79efe83243c6cdb4d35 Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Sun, 26 Apr 2020 14:56:31 -0700 Subject: [PATCH 1982/3747] Move prctl test to the same file as other libc tests. --- .../concurrency/libc_prctl_thread_name.rs | 18 ------------------ tests/run-pass/libc.rs | 17 +++++++++++++++++ 2 files changed, 17 insertions(+), 18 deletions(-) delete mode 100644 tests/run-pass/concurrency/libc_prctl_thread_name.rs diff --git a/tests/run-pass/concurrency/libc_prctl_thread_name.rs b/tests/run-pass/concurrency/libc_prctl_thread_name.rs deleted file mode 100644 index b8ba27b3a8954..0000000000000 --- a/tests/run-pass/concurrency/libc_prctl_thread_name.rs +++ /dev/null @@ -1,18 +0,0 @@ -// ignore-windows: No libc on Windows -// ignore-macos: No prctl on MacOS - -#![feature(rustc_private)] - -extern crate libc; - -use std::ffi::CString; - -fn main() { - unsafe { - let thread_name = CString::new("hello").expect("CString::new failed"); - assert_eq!(libc::prctl(libc::PR_SET_NAME, thread_name.as_ptr() as libc::c_long, 0 as libc::c_long, 0 as libc::c_long, 0 as libc::c_long), 0); - let mut buf = [0; 6]; - assert_eq!(libc::prctl(libc::PR_GET_NAME, buf.as_mut_ptr() as libc::c_long, 0 as libc::c_long, 0 as libc::c_long, 0 as libc::c_long), 0); - assert_eq!(thread_name.as_bytes_with_nul(), buf); - } -} diff --git a/tests/run-pass/libc.rs b/tests/run-pass/libc.rs index 14d12de0d186d..5873d42969500 100644 --- a/tests/run-pass/libc.rs +++ b/tests/run-pass/libc.rs @@ -141,6 +141,20 @@ fn test_rwlock_libc_static_initializer() { } } +/// Test whether the `prctl` shim correctly sets the thread name. +/// +/// Note: `prctl` exists only on Linux. +fn test_prctl_thread_name() { + use std::ffi::CString; + unsafe { + let thread_name = CString::new("hello").expect("CString::new failed"); + assert_eq!(libc::prctl(libc::PR_SET_NAME, thread_name.as_ptr() as libc::c_long, 0 as libc::c_long, 0 as libc::c_long, 0 as libc::c_long), 0); + let mut buf = [0; 6]; + assert_eq!(libc::prctl(libc::PR_GET_NAME, buf.as_mut_ptr() as libc::c_long, 0 as libc::c_long, 0 as libc::c_long, 0 as libc::c_long), 0); + assert_eq!(thread_name.as_bytes_with_nul(), buf); + } +} + fn main() { #[cfg(target_os = "linux")] test_posix_fadvise(); @@ -152,4 +166,7 @@ fn main() { #[cfg(target_os = "linux")] test_mutex_libc_static_initializer_recursive(); + + #[cfg(target_os = "linux")] + test_prctl_thread_name(); } From 6842eb2b84337ff01158ca7c0eee669b0d1e061f Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Sun, 26 Apr 2020 15:52:01 -0700 Subject: [PATCH 1983/3747] Rename global tls dtor to thread dtor. --- src/shims/foreign_items/posix/macos.rs | 2 +- src/shims/tls.rs | 39 ++++++++++++++------------ 2 files changed, 22 insertions(+), 19 deletions(-) diff --git a/src/shims/foreign_items/posix/macos.rs b/src/shims/foreign_items/posix/macos.rs index 9f6ea00b03132..200b88f29c8f8 100644 --- a/src/shims/foreign_items/posix/macos.rs +++ b/src/shims/foreign_items/posix/macos.rs @@ -83,7 +83,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let dtor = this.memory.get_fn(dtor)?.as_instance()?; let data = this.read_scalar(args[1])?.not_undef()?; let active_thread = this.get_active_thread()?; - this.machine.tls.set_thread_global_dtor(active_thread, dtor, data)?; + this.machine.tls.set_thread_dtor(active_thread, dtor, data)?; } // Querying system information diff --git a/src/shims/tls.rs b/src/shims/tls.rs index 615950621a247..d3d50977320b0 100644 --- a/src/shims/tls.rs +++ b/src/shims/tls.rs @@ -33,8 +33,9 @@ pub struct TlsData<'tcx> { /// pthreads-style thread-local storage. keys: BTreeMap>, - /// A single global per thread dtor (that's how things work on macOS) with a data argument. - global_dtors: BTreeMap, Scalar)>, + /// A single per thread destructor of the thread local storage (that's how + /// things work on macOS) with a data argument. + thread_dtors: BTreeMap, Scalar)>, /// Whether we are in the "destruct" phase, during which some operations are UB. dtors_running: HashSet, @@ -48,7 +49,7 @@ impl<'tcx> Default for TlsData<'tcx> { TlsData { next_key: 1, // start with 1 as we must not use 0 on Windows keys: Default::default(), - global_dtors: Default::default(), + thread_dtors: Default::default(), dtors_running: Default::default(), last_dtor_key: Default::default(), } @@ -117,16 +118,16 @@ impl<'tcx> TlsData<'tcx> { } } - /// Set global dtor for the given thread. This function is used to implement - /// `_tlv_atexit` shim on MacOS. + /// Set the thread wide destructor of the thread local storage for the given + /// thread. This function is used to implement `_tlv_atexit` shim on MacOS. /// - /// Global destructors are available only on MacOS and (potentially - /// confusingly) they seem to be still per thread as can be guessed from the - /// following comment in the [`_tlv_atexit` + /// Thread wide dtors are available only on MacOS. There is one destructor + /// per thread as can be guessed from the following comment in the + /// [`_tlv_atexit` /// implementation](https://github.com/opensource-apple/dyld/blob/195030646877261f0c8c7ad8b001f52d6a26f514/src/threadLocalVariables.c#L389): /// /// // NOTE: this does not need locks because it only operates on current thread data - pub fn set_thread_global_dtor( + pub fn set_thread_dtor( &mut self, thread: ThreadId, dtor: ty::Instance<'tcx>, @@ -134,10 +135,10 @@ impl<'tcx> TlsData<'tcx> { ) -> InterpResult<'tcx> { if self.dtors_running.contains(&thread) { // UB, according to libstd docs. - throw_ub_format!("setting global destructor while destructors are already running"); + throw_ub_format!("setting thread's local storage destructor while destructors are already running"); } - if self.global_dtors.insert(thread, (dtor, data)).is_some() { - throw_unsup_format!("setting more than one global destructor for the same thread is not supported"); + if self.thread_dtors.insert(thread, (dtor, data)).is_some() { + throw_unsup_format!("setting more than one thread local storage destructor for the same thread is not supported"); } Ok(()) } @@ -223,15 +224,15 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(()) } - /// Schedule the MacOS global dtor to be executed. + /// Schedule the MacOS thread destructor of the thread local storage to be + /// executed. /// /// Note: It is safe to call this function also on other Unixes. - fn schedule_macos_global_tls_dtors(&mut self) -> InterpResult<'tcx> { + fn schedule_macos_tls_dtor(&mut self) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let thread_id = this.get_active_thread()?; - // The macOS global dtor runs "before any TLS slots get freed", so do that first. - if let Some((instance, data)) = this.machine.tls.global_dtors.remove(&thread_id) { - trace!("Running global dtor {:?} on {:?} at {:?}", instance, data, thread_id); + if let Some((instance, data)) = this.machine.tls.thread_dtors.remove(&thread_id) { + trace!("Running macos dtor {:?} on {:?} at {:?}", instance, data, thread_id); let ret_place = MPlaceTy::dangling(this.machine.layouts.unit, this).into(); this.call_function( @@ -306,7 +307,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } else { this.machine.tls.dtors_running.insert(active_thread); - this.schedule_macos_global_tls_dtors()?; + // The macOS thread wide destructor runs "before any TLS slots get + // freed", so do that first. + this.schedule_macos_tls_dtor()?; this.schedule_pthread_tls_dtors()?; } From c4574dde8dbd3f996418927a3edc8a83e9709f9c Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Sun, 26 Apr 2020 15:52:45 -0700 Subject: [PATCH 1984/3747] Many small changes to clean up code. --- src/shims/thread.rs | 44 +++++++++++--------------------------------- src/shims/tls.rs | 8 +++++--- src/thread.rs | 7 +++++++ 3 files changed, 23 insertions(+), 36 deletions(-) diff --git a/src/shims/thread.rs b/src/shims/thread.rs index 67e833f222e4b..c2ef272237808 100644 --- a/src/shims/thread.rs +++ b/src/shims/thread.rs @@ -1,5 +1,4 @@ use crate::*; -use rustc_index::vec::Idx; use rustc_target::abi::LayoutOf; impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} @@ -19,18 +18,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ); let new_thread_id = this.create_thread()?; + // Also switch to new thread so that we can push the first stackframe. let old_thread_id = this.set_active_thread(new_thread_id)?; let thread_info_place = this.deref_operand(thread)?; - let thread_info_type = thread.layout.ty - .builtin_deref(true) - .ok_or_else(|| err_ub_format!( - "wrong signature used for `pthread_create`: first argument must be a raw pointer." - ))? - .ty; - let thread_info_layout = this.layout_of(thread_info_type)?; this.write_scalar( - Scalar::from_uint(new_thread_id.index() as u128, thread_info_layout.size), + Scalar::from_uint(new_thread_id.to_u128(), thread_info_place.layout.size), thread_info_place.into(), )?; @@ -38,14 +31,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let instance = this.memory.get_fn(fn_ptr)?.as_instance()?; let func_arg = this.read_immediate(arg)?; - let func_args = [*func_arg]; let ret_place = this.allocate(this.layout_of(this.tcx.types.usize)?, MiriMemoryKind::Machine.into()); this.call_function( instance, - &func_args[..], + &[*func_arg], Some(ret_place.into()), StackPopCleanup::None { cleanup: true }, )?; @@ -66,7 +58,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx throw_unsup_format!("Miri supports pthread_join only with retval==NULL"); } - let thread_id = this.read_scalar(thread)?.not_undef()?.to_machine_usize(this)?; + let thread_id = this.read_scalar(thread)?.to_machine_usize(this)?; this.join_thread(thread_id.into())?; Ok(0) @@ -75,7 +67,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn pthread_detach(&mut self, thread: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - let thread_id = this.read_scalar(thread)?.not_undef()?.to_machine_usize(this)?; + let thread_id = this.read_scalar(thread)?.to_machine_usize(this)?; this.detach_thread(thread_id.into())?; Ok(0) @@ -85,34 +77,20 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); let thread_id = this.get_active_thread()?; - this.write_scalar(Scalar::from_uint(thread_id.index() as u128, dest.layout.size), dest) + this.write_scalar(Scalar::from_uint(thread_id.to_u128(), dest.layout.size), dest) } fn prctl( &mut self, option: OpTy<'tcx, Tag>, arg2: OpTy<'tcx, Tag>, - arg3: OpTy<'tcx, Tag>, - arg4: OpTy<'tcx, Tag>, - arg5: OpTy<'tcx, Tag>, + _arg3: OpTy<'tcx, Tag>, + _arg4: OpTy<'tcx, Tag>, + _arg5: OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - // prctl last 5 arguments are declared as variadic. Therefore, we need - // to check their types manually. - let c_long_size = this.libc_ty_layout("c_long")?.size.bytes(); - let check_arg = |arg: OpTy<'tcx, Tag>| -> InterpResult<'tcx> { - match this.read_scalar(arg)?.not_undef()? { - Scalar::Raw { size, .. } if u64::from(size) == c_long_size => Ok(()), - _ => throw_ub_format!("an argument of unsupported type was passed to prctl"), - } - }; - check_arg(arg2)?; - check_arg(arg3)?; - check_arg(arg4)?; - check_arg(arg5)?; - - let option = this.read_scalar(option)?.not_undef()?.to_i32()?; + let option = this.read_scalar(option)?.to_i32()?; if option == this.eval_libc_i32("PR_SET_NAME")? { let address = this.read_scalar(arg2)?.not_undef()?; let name = this.memory.read_c_str(address)?.to_owned(); @@ -122,7 +100,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let name = this.get_active_thread_name()?.to_vec(); this.memory.write_bytes(address, name)?; } else { - throw_unsup_format!("Unsupported prctl option."); + throw_unsup_format!("unsupported prctl option {}", option); } Ok(0) diff --git a/src/shims/tls.rs b/src/shims/tls.rs index d3d50977320b0..087b44af2f58f 100644 --- a/src/shims/tls.rs +++ b/src/shims/tls.rs @@ -20,7 +20,6 @@ pub type TlsKey = u128; pub struct TlsEntry<'tcx> { /// The data for this key. None is used to represent NULL. /// (We normalize this early to avoid having to do a NULL-ptr-test each time we access the data.) - /// Will eventually become a map from thread IDs to `Scalar`s, if we ever support more than one thread. data: BTreeMap>, dtor: Option>, } @@ -89,7 +88,7 @@ impl<'tcx> TlsData<'tcx> { ) -> InterpResult<'tcx, Scalar> { match self.keys.get(&key) { Some(TlsEntry { data, .. }) => { - let value = data.get(&thread_id).cloned(); + let value = data.get(&thread_id).copied(); trace!("TLS key {} for thread {:?} loaded: {:?}", key, thread_id, value); Ok(value.unwrap_or_else(|| Scalar::null_ptr(cx).into())) } @@ -99,7 +98,10 @@ impl<'tcx> TlsData<'tcx> { pub fn store_tls( &mut self, - key: TlsKey, thread_id: ThreadId, new_data: Option>) -> InterpResult<'tcx> { + key: TlsKey, + thread_id: ThreadId, + new_data: Option> + ) -> InterpResult<'tcx> { match self.keys.get_mut(&key) { Some(TlsEntry { data, .. }) => { match new_data { diff --git a/src/thread.rs b/src/thread.rs index 9a332a0dcf2c0..f9094d771e6dd 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -1,5 +1,6 @@ //! Implements threads. +use std::convert::TryInto; use std::cell::RefCell; use std::convert::TryFrom; use std::num::NonZeroU32; @@ -34,6 +35,12 @@ pub struct ThreadId(usize); /// The main thread. When it terminates, the whole application terminates. const MAIN_THREAD: ThreadId = ThreadId(0); +impl ThreadId { + pub fn to_u128(self) -> u128 { + self.0.try_into().unwrap() + } +} + impl Idx for ThreadId { fn new(idx: usize) -> Self { ThreadId(idx) From 911ff7eade22e7bd15e79167a22845005f29b3fb Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Sun, 26 Apr 2020 20:49:53 -0700 Subject: [PATCH 1985/3747] Improve style and comments. --- src/eval.rs | 2 +- src/shims/tls.rs | 14 ++++++++------ 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/eval.rs b/src/eval.rs index 9131946f8dc16..89d61d141a23b 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -211,7 +211,7 @@ pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) -> assert!(ecx.step()?, "a terminated thread was scheduled for execution"); } SchedulingAction::ExecuteDtors => { - ecx.schedule_tls_dtors_for_active_thread()?; + ecx.schedule_next_tls_dtor_for_active_thread()?; } SchedulingAction::Stop => { break; diff --git a/src/shims/tls.rs b/src/shims/tls.rs index 087b44af2f58f..54850de82c87c 100644 --- a/src/shims/tls.rs +++ b/src/shims/tls.rs @@ -105,9 +105,9 @@ impl<'tcx> TlsData<'tcx> { match self.keys.get_mut(&key) { Some(TlsEntry { data, .. }) => { match new_data { - Some(ptr) => { - trace!("TLS key {} for thread {:?} stored: {:?}", key, thread_id, ptr); - data.insert(thread_id, ptr); + Some(scalar) => { + trace!("TLS key {} for thread {:?} stored: {:?}", key, thread_id, scalar); + data.insert(thread_id, scalar); } None => { trace!("TLS key {} for thread {:?} removed", key, thread_id); @@ -271,7 +271,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if let Some((instance, ptr, key)) = dtor { this.machine.tls.last_dtor_key.insert(active_thread, key); trace!("Running TLS dtor {:?} on {:?} at {:?}", instance, ptr, active_thread); - assert!(!this.is_null(ptr).unwrap(), "Data can't be NULL when dtor is called!"); + assert!(!this.is_null(ptr).unwrap(), "data can't be NULL when dtor is called!"); let ret_place = MPlaceTy::dangling(this.machine.layouts.unit, this).into(); this.call_function( @@ -295,10 +295,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// Schedule an active thread's TLS destructor to run on the active thread. /// Note that this function does not run the destructors itself, it just - /// schedules them one by one each time it is called. + /// schedules them one by one each time it is called and reenables the + /// thread so that it can be executed normally by the main execution loop. /// /// FIXME: we do not support yet deallocation of thread local statics. - fn schedule_tls_dtors_for_active_thread(&mut self) -> InterpResult<'tcx> { + /// Issue: https://github.com/rust-lang/miri/issues/1369 + fn schedule_next_tls_dtor_for_active_thread(&mut self) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let active_thread = this.get_active_thread()?; From d9e18ada39b52518c70df7801be564e58f4e8a66 Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Sun, 26 Apr 2020 20:50:58 -0700 Subject: [PATCH 1986/3747] Make sure to remove thread local data only if we have destructor. --- src/shims/tls.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shims/tls.rs b/src/shims/tls.rs index 54850de82c87c..7d4aae3670829 100644 --- a/src/shims/tls.rs +++ b/src/shims/tls.rs @@ -181,8 +181,8 @@ impl<'tcx> TlsData<'tcx> { { match data.entry(thread_id) { Entry::Occupied(entry) => { - let data_scalar = entry.remove(); if let Some(dtor) = dtor { + let data_scalar = entry.remove(); let ret = Some((*dtor, data_scalar, key)); return ret; } From 174adad2b34ddacc129232c6127a260270d1f52a Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Sun, 26 Apr 2020 20:51:21 -0700 Subject: [PATCH 1987/3747] Use DLL_THREAD_DETACH when calling windows TLS destructor. --- src/shims/tls.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shims/tls.rs b/src/shims/tls.rs index 7d4aae3670829..eb8c99b72f6f1 100644 --- a/src/shims/tls.rs +++ b/src/shims/tls.rs @@ -213,7 +213,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let thread_callback = this.memory.get_fn(thread_callback.not_undef()?)?.as_instance()?; // The signature of this function is `unsafe extern "system" fn(h: c::LPVOID, dwReason: c::DWORD, pv: c::LPVOID)`. - let reason = this.eval_path_scalar(&["std", "sys", "windows", "c", "DLL_PROCESS_DETACH"])?; + let reason = this.eval_path_scalar(&["std", "sys", "windows", "c", "DLL_THREAD_DETACH"])?; let ret_place = MPlaceTy::dangling(this.machine.layouts.unit, this).into(); this.call_function( thread_callback, From 9ba3ef2a44118fb2692a65a04500cdef4f6036d5 Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Sun, 26 Apr 2020 21:01:03 -0700 Subject: [PATCH 1988/3747] Change representation and conversion of ThreadId and BlockSetId. --- src/shims/sync.rs | 6 +++--- src/thread.rs | 20 +++++++++----------- 2 files changed, 12 insertions(+), 14 deletions(-) diff --git a/src/shims/sync.rs b/src/shims/sync.rs index 97afbbe98f6a0..b0605b4e8146b 100644 --- a/src/shims/sync.rs +++ b/src/shims/sync.rs @@ -158,7 +158,7 @@ fn mutex_get_or_create_blockset<'mir, 'tcx: 'mir>( mutex_set_blockset(ecx, mutex_op, blockset.to_u32_scalar())?; Ok(blockset) } else { - Ok(blockset.into()) + Ok(BlockSetId::new(blockset)) } } @@ -233,7 +233,7 @@ fn rwlock_get_or_create_writer_blockset<'mir, 'tcx: 'mir>( rwlock_set_writer_blockset(ecx, rwlock_op, blockset.to_u32_scalar())?; Ok(blockset) } else { - Ok(blockset.into()) + Ok(BlockSetId::new(blockset)) } } @@ -264,7 +264,7 @@ fn rwlock_get_or_create_reader_blockset<'mir, 'tcx: 'mir>( rwlock_set_reader_blockset(ecx, rwlock_op, blockset.to_u32_scalar())?; Ok(blockset) } else { - Ok(blockset.into()) + Ok(BlockSetId::new(blockset)) } } diff --git a/src/thread.rs b/src/thread.rs index f9094d771e6dd..749d6bf955f27 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -30,7 +30,7 @@ pub enum SchedulingAction { /// A thread identifier. #[derive(Clone, Copy, Debug, PartialOrd, Ord, PartialEq, Eq, Hash)] -pub struct ThreadId(usize); +pub struct ThreadId(u32); /// The main thread. When it terminates, the whole application terminates. const MAIN_THREAD: ThreadId = ThreadId(0); @@ -43,22 +43,22 @@ impl ThreadId { impl Idx for ThreadId { fn new(idx: usize) -> Self { - ThreadId(idx) + ThreadId(u32::try_from(idx).unwrap()) } fn index(self) -> usize { - self.0 + usize::try_from(self.0).unwrap() } } impl From for ThreadId { fn from(id: u64) -> Self { - Self(usize::try_from(id).unwrap()) + Self(u32::try_from(id).unwrap()) } } impl From for ThreadId { fn from(id: u32) -> Self { - Self(usize::try_from(id).unwrap()) + Self(u32::try_from(id).unwrap()) } } @@ -73,13 +73,11 @@ impl ThreadId { #[derive(Clone, Copy, Debug, PartialOrd, Ord, PartialEq, Eq, Hash)] pub struct BlockSetId(NonZeroU32); -impl From for BlockSetId { - fn from(id: u32) -> Self { +impl BlockSetId { + /// Panics if `id` is 0. + pub fn new(id: u32) -> Self { Self(NonZeroU32::new(id).expect("0 is not a valid blockset id")) } -} - -impl BlockSetId { pub fn to_u32_scalar<'tcx>(&self) -> Scalar { Scalar::from_u32(self.0.get()) } @@ -325,7 +323,7 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { /// Allocate a new blockset id. fn create_blockset(&mut self) -> BlockSetId { self.blockset_counter = self.blockset_counter.checked_add(1).unwrap(); - self.blockset_counter.into() + BlockSetId::new(self.blockset_counter) } /// Block the currently active thread and put it into the given blockset. From 207c6e7fa74758a64104c2d77218e263d92cf1c6 Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Sun, 26 Apr 2020 21:13:33 -0700 Subject: [PATCH 1989/3747] Improve comments and code clarity. --- src/shims/sync.rs | 16 ++++++++++------ src/thread.rs | 2 +- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/shims/sync.rs b/src/shims/sync.rs index b0605b4e8146b..9dad302706c27 100644 --- a/src/shims/sync.rs +++ b/src/shims/sync.rs @@ -80,7 +80,8 @@ fn mutexattr_set_kind<'mir, 'tcx: 'mir>( // bytes 8-11: when count > 0, id of the owner thread as a u32 // bytes 12-15 or 16-19 (depending on platform): mutex kind, as an i32 // (the kind has to be at its offset for compatibility with static initializer macros) -// bytes 20-23: when count > 0, id of the blockset in which the blocked threads are waiting. +// bytes 20-23: when count > 0, id of the blockset in which the blocked threads +// are waiting or 0 if blockset is not yet assigned. const PTHREAD_MUTEX_T_MIN_SIZE: u64 = 24; @@ -170,9 +171,9 @@ fn mutex_get_or_create_blockset<'mir, 'tcx: 'mir>( // bytes 4-7: reader count, as a u32 // bytes 8-11: writer count, as a u32 // bytes 12-15: when writer or reader count > 0, id of the blockset in which the -// blocked writers are waiting. +// blocked writers are waiting or 0 if blockset is not yet assigned. // bytes 16-20: when writer count > 0, id of the blockset in which the blocked -// readers are waiting. +// readers are waiting or 0 if blockset is not yet assigned. const PTHREAD_RWLOCK_T_MIN_SIZE: u64 = 20; @@ -342,8 +343,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(0) } else { // The mutex is locked. Let's check by whom. - let owner_thread: ThreadId = - mutex_get_owner(this, mutex_op)?.not_undef()?.to_u32()?.into(); + let owner_thread: ThreadId = mutex_get_owner(this, mutex_op)?.to_u32()?.into(); if owner_thread != active_thread { // Block the active thread. let blockset = mutex_get_or_create_blockset(this, mutex_op)?; @@ -425,6 +425,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx mutex_set_owner(this, mutex_op, new_owner.to_u32_scalar())?; } else { // No thread is waiting on this mutex. + mutex_set_owner(this, mutex_op, Scalar::from_u32(0))?; mutex_set_locked_count(this, mutex_op, Scalar::from_u32(0))?; } Ok(0) @@ -550,10 +551,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(0) } else if writers != 0 { let reader_blockset = rwlock_get_or_create_reader_blockset(this, rwlock_op)?; - rwlock_set_writers(this, rwlock_op, Scalar::from_u32(0))?; + // We are prioritizing writers here against the readers. As a + // result, not only readers can starve writers, but also writers can + // starve readers. if let Some(_writer) = this.unblock_some_thread(writer_blockset)? { rwlock_set_writers(this, rwlock_op, Scalar::from_u32(1))?; } else { + rwlock_set_writers(this, rwlock_op, Scalar::from_u32(0))?; let mut readers = 0; while let Some(_reader) = this.unblock_some_thread(reader_blockset)? { readers += 1; diff --git a/src/thread.rs b/src/thread.rs index 749d6bf955f27..9408dbe56cd91 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -1,8 +1,8 @@ //! Implements threads. -use std::convert::TryInto; use std::cell::RefCell; use std::convert::TryFrom; +use std::convert::TryInto; use std::num::NonZeroU32; use log::trace; From 356aecce7f3c438db6804a72a5022a2537d35104 Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Sun, 26 Apr 2020 21:25:46 -0700 Subject: [PATCH 1990/3747] Add a FIXME. --- src/shims/thread.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/shims/thread.rs b/src/shims/thread.rs index c2ef272237808..27e9980852904 100644 --- a/src/shims/thread.rs +++ b/src/shims/thread.rs @@ -55,6 +55,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); if !this.is_null(this.read_scalar(retval)?.not_undef()?)? { + // FIXME: implement reading the thread function's return place. throw_unsup_format!("Miri supports pthread_join only with retval==NULL"); } From f204b67b0f5ae6f498d29938790cd989e58f5bec Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Sun, 26 Apr 2020 21:49:36 -0700 Subject: [PATCH 1991/3747] Merge dtors_running and last_dtor_key fields. --- src/shims/tls.rs | 47 ++++++++++++++++++++++++++++++++--------------- 1 file changed, 32 insertions(+), 15 deletions(-) diff --git a/src/shims/tls.rs b/src/shims/tls.rs index eb8c99b72f6f1..a98a80256414e 100644 --- a/src/shims/tls.rs +++ b/src/shims/tls.rs @@ -2,10 +2,10 @@ use std::collections::BTreeMap; use std::collections::btree_map::Entry; -use std::collections::HashSet; use log::trace; +use rustc_data_structures::fx::FxHashMap; use rustc_middle::ty; use rustc_target::abi::{Size, HasDataLayout}; @@ -24,6 +24,12 @@ pub struct TlsEntry<'tcx> { dtor: Option>, } +#[derive(Clone, Debug)] +struct RunningDtorsState { + /// The last TlsKey used to retrieve a TLS destructor. + last_dtor_key: Option, +} + #[derive(Debug)] pub struct TlsData<'tcx> { /// The Key to use for the next thread-local allocation. @@ -36,11 +42,10 @@ pub struct TlsData<'tcx> { /// things work on macOS) with a data argument. thread_dtors: BTreeMap, Scalar)>, - /// Whether we are in the "destruct" phase, during which some operations are UB. - dtors_running: HashSet, - - /// The last TlsKey used to retrieve a TLS destructor. - last_dtor_key: BTreeMap, + /// State for currently running TLS dtors. If this map contains a key for a + /// specific thread, it means that we are in the "destruct" phase, during + /// which some operations are UB. + dtors_running: FxHashMap, } impl<'tcx> Default for TlsData<'tcx> { @@ -50,7 +55,6 @@ impl<'tcx> Default for TlsData<'tcx> { keys: Default::default(), thread_dtors: Default::default(), dtors_running: Default::default(), - last_dtor_key: Default::default(), } } } @@ -135,7 +139,7 @@ impl<'tcx> TlsData<'tcx> { dtor: ty::Instance<'tcx>, data: Scalar ) -> InterpResult<'tcx> { - if self.dtors_running.contains(&thread) { + if self.dtors_running.contains_key(&thread) { // UB, according to libstd docs. throw_ub_format!("setting thread's local storage destructor while destructors are already running"); } @@ -192,6 +196,21 @@ impl<'tcx> TlsData<'tcx> { } None } + + /// Set that dtors are running for `thread`. It is guaranteed not to change + /// the existing values stored in `dtors_running` for this thread. Returns + /// `true` if dtors for `thread` are already running. + fn set_dtors_running_for_thread(&mut self, thread: ThreadId) -> bool { + if self.dtors_running.contains_key(&thread) { + true + } else { + self.dtors_running.insert( + thread, + RunningDtorsState { last_dtor_key: None } + ); + false + } + } } impl<'mir, 'tcx: 'mir> EvalContextPrivExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} @@ -203,7 +222,6 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); let active_thread = this.get_active_thread()?; assert_eq!(this.get_total_thread_count()?, 1, "concurrency on Windows not supported"); - this.machine.tls.dtors_running.insert(active_thread); // Windows has a special magic linker section that is run on certain events. // Instead of searching for that section and supporting arbitrary hooks in there // (that would be basically https://github.com/rust-lang/miri/issues/450), @@ -260,7 +278,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx assert!(this.has_terminated(active_thread)?, "running TLS dtors for non-terminated thread"); // Fetch next dtor after `key`. - let last_key = this.machine.tls.last_dtor_key.get(&active_thread).cloned(); + let last_key = this.machine.tls.dtors_running[&active_thread].last_dtor_key.clone(); let dtor = match this.machine.tls.fetch_tls_dtor(last_key, active_thread) { dtor @ Some(_) => dtor, // We ran each dtor once, start over from the beginning. @@ -269,7 +287,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } }; if let Some((instance, ptr, key)) = dtor { - this.machine.tls.last_dtor_key.insert(active_thread, key); + this.machine.tls.dtors_running.get_mut(&active_thread).unwrap().last_dtor_key = Some(key); trace!("Running TLS dtor {:?} on {:?} at {:?}", instance, ptr, active_thread); assert!(!this.is_null(ptr).unwrap(), "data can't be NULL when dtor is called!"); @@ -284,7 +302,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.enable_thread(active_thread)?; return Ok(()); } - this.machine.tls.last_dtor_key.remove(&active_thread); + this.machine.tls.dtors_running.get_mut(&active_thread).unwrap().last_dtor_key = None; Ok(()) } @@ -305,12 +323,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let active_thread = this.get_active_thread()?; if this.tcx.sess.target.target.target_os == "windows" { - if !this.machine.tls.dtors_running.contains(&active_thread) { - this.machine.tls.dtors_running.insert(active_thread); + if !this.machine.tls.set_dtors_running_for_thread(active_thread) { this.schedule_windows_tls_dtors()?; } } else { - this.machine.tls.dtors_running.insert(active_thread); + this.machine.tls.set_dtors_running_for_thread(active_thread); // The macOS thread wide destructor runs "before any TLS slots get // freed", so do that first. this.schedule_macos_tls_dtor()?; From 331dbd1469abb9ee7959684305732b0613f0bf15 Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Sun, 26 Apr 2020 22:05:09 -0700 Subject: [PATCH 1992/3747] Add a test for joining in a destructor. --- tests/run-pass/concurrency/tls_lib_drop.rs | 45 +++++++++++++++++-- .../run-pass/concurrency/tls_lib_drop.stdout | 2 + 2 files changed, 43 insertions(+), 4 deletions(-) diff --git a/tests/run-pass/concurrency/tls_lib_drop.rs b/tests/run-pass/concurrency/tls_lib_drop.rs index 0d1808cbe0fa4..de2566de85c6a 100644 --- a/tests/run-pass/concurrency/tls_lib_drop.rs +++ b/tests/run-pass/concurrency/tls_lib_drop.rs @@ -1,8 +1,5 @@ // ignore-windows: Concurrency on Windows is not supported yet. -//! Check that destructors of the library thread locals are executed immediately -//! after a thread terminates. - use std::cell::RefCell; use std::thread; @@ -20,7 +17,9 @@ thread_local! { static A: TestCell = TestCell { value: RefCell::new(0) }; } -fn main() { +/// Check that destructors of the library thread locals are executed immediately +/// after a thread terminates. +fn check_destructors() { thread::spawn(|| { A.with(|f| { assert_eq!(*f.value.borrow(), 0); @@ -31,3 +30,41 @@ fn main() { .unwrap(); println!("Continue main.") } + +struct JoinCell { + value: RefCell>>, +} + +impl Drop for JoinCell { + fn drop(&mut self) { + let join_handle = self.value.borrow_mut().take().unwrap(); + println!("Joining: {}", join_handle.join().unwrap()); + } +} + +thread_local! { + static B: JoinCell = JoinCell { value: RefCell::new(None) }; +} + +/// Check that the destructor can be blocked joining another thread. +fn check_blocking() { + thread::spawn(|| { + B.with(|f| { + assert!(f.value.borrow().is_none()); + let handle = thread::spawn(|| 7); + *f.value.borrow_mut() = Some(handle); + }); + }) + .join() + .unwrap(); + println!("Continue main 2."); + // Preempt the main thread so that the destructor gets executed and can join + // the thread. + thread::yield_now(); + thread::yield_now(); +} + +fn main() { + check_destructors(); + check_blocking(); +} diff --git a/tests/run-pass/concurrency/tls_lib_drop.stdout b/tests/run-pass/concurrency/tls_lib_drop.stdout index d2bbb866b77ea..d622c0ccce882 100644 --- a/tests/run-pass/concurrency/tls_lib_drop.stdout +++ b/tests/run-pass/concurrency/tls_lib_drop.stdout @@ -1,2 +1,4 @@ Dropping: 5 Continue main. +Continue main 2. +Joining: 7 From c56ef31780c63e03ada0a8282e5d95ba1f082d92 Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Mon, 27 Apr 2020 11:01:35 -0700 Subject: [PATCH 1993/3747] Improve comments. --- src/shims/thread.rs | 3 +++ src/thread.rs | 3 +++ 2 files changed, 6 insertions(+) diff --git a/src/shims/thread.rs b/src/shims/thread.rs index 27e9980852904..d11853d534523 100644 --- a/src/shims/thread.rs +++ b/src/shims/thread.rs @@ -32,6 +32,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let func_arg = this.read_immediate(arg)?; + // Note: the returned value is currently ignored (see the FIXME in + // pthread_join below) because the Rust standard library does not use + // it. let ret_place = this.allocate(this.layout_of(this.tcx.types.usize)?, MiriMemoryKind::Machine.into()); diff --git a/src/thread.rs b/src/thread.rs index 9408dbe56cd91..715107530cefb 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -358,6 +358,9 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { /// long as we can and switch only when we have to (the active thread was /// blocked, terminated, or has explicitly asked to be preempted). fn schedule(&mut self) -> InterpResult<'tcx, SchedulingAction> { + // Check whether the thread has **just** terminated (`check_terminated` + // checks whether the thread has popped all its stack and if yes, sets + // the thread state to terminated.) if self.threads[self.active_thread].check_terminated() { // Check if we need to unblock any threads. for (i, thread) in self.threads.iter_enumerated_mut() { From df2ca53b6978c7ac2ec6e271a5ee73fba70877c5 Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Mon, 27 Apr 2020 12:32:57 -0700 Subject: [PATCH 1994/3747] Make From implementations non-failing. --- src/shims/thread.rs | 6 ++++-- src/thread.rs | 12 +++++++----- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/shims/thread.rs b/src/shims/thread.rs index d11853d534523..29a4ed3676879 100644 --- a/src/shims/thread.rs +++ b/src/shims/thread.rs @@ -1,3 +1,5 @@ +use std::convert::TryInto; + use crate::*; use rustc_target::abi::LayoutOf; @@ -63,7 +65,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } let thread_id = this.read_scalar(thread)?.to_machine_usize(this)?; - this.join_thread(thread_id.into())?; + this.join_thread(thread_id.try_into().expect("thread ID should fit in u32"))?; Ok(0) } @@ -72,7 +74,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); let thread_id = this.read_scalar(thread)?.to_machine_usize(this)?; - this.detach_thread(thread_id.into())?; + this.detach_thread(thread_id.try_into().expect("thread ID should fit in u32"))?; Ok(0) } diff --git a/src/thread.rs b/src/thread.rs index 715107530cefb..69e7bcdb298c1 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -3,7 +3,7 @@ use std::cell::RefCell; use std::convert::TryFrom; use std::convert::TryInto; -use std::num::NonZeroU32; +use std::num::{NonZeroU32, TryFromIntError}; use log::trace; @@ -45,20 +45,22 @@ impl Idx for ThreadId { fn new(idx: usize) -> Self { ThreadId(u32::try_from(idx).unwrap()) } + fn index(self) -> usize { usize::try_from(self.0).unwrap() } } -impl From for ThreadId { - fn from(id: u64) -> Self { - Self(u32::try_from(id).unwrap()) +impl TryFrom for ThreadId { + type Error = TryFromIntError; + fn try_from(id: u64) -> Result { + u32::try_from(id).map(|id_u32| Self(id_u32)) } } impl From for ThreadId { fn from(id: u32) -> Self { - Self(u32::try_from(id).unwrap()) + Self(id) } } From 1355574bebb5f7cb572bb7399964f91101e8852e Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Mon, 27 Apr 2020 14:00:39 -0700 Subject: [PATCH 1995/3747] Delete remaining tls entries after all destructors completed. --- src/shims/tls.rs | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/src/shims/tls.rs b/src/shims/tls.rs index a98a80256414e..d5ea430dd2768 100644 --- a/src/shims/tls.rs +++ b/src/shims/tls.rs @@ -211,6 +211,14 @@ impl<'tcx> TlsData<'tcx> { false } } + + /// Delete all TLS entries for the given thread. This function should be + /// called after all TLS destructors have already finished. + fn delete_all_thread_tls(&mut self, thread_id: ThreadId) { + for TlsEntry { data, .. } in self.keys.values_mut() { + data.remove(&thread_id); + } + } } impl<'mir, 'tcx: 'mir> EvalContextPrivExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} @@ -271,8 +279,9 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(()) } - /// Schedule a pthread TLS destructor. - fn schedule_pthread_tls_dtors(&mut self) -> InterpResult<'tcx> { + /// Schedule a pthread TLS destructor. Returns `true` if found + /// a destructor to schedule, and `false` otherwise. + fn schedule_pthread_tls_dtors(&mut self) -> InterpResult<'tcx, bool> { let this = self.eval_context_mut(); let active_thread = this.get_active_thread()?; @@ -300,11 +309,11 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx )?; this.enable_thread(active_thread)?; - return Ok(()); + return Ok(true); } this.machine.tls.dtors_running.get_mut(&active_thread).unwrap().last_dtor_key = None; - Ok(()) + Ok(false) } } @@ -322,16 +331,21 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); let active_thread = this.get_active_thread()?; - if this.tcx.sess.target.target.target_os == "windows" { + let finished = if this.tcx.sess.target.target.target_os == "windows" { if !this.machine.tls.set_dtors_running_for_thread(active_thread) { this.schedule_windows_tls_dtors()?; } + true } else { this.machine.tls.set_dtors_running_for_thread(active_thread); // The macOS thread wide destructor runs "before any TLS slots get // freed", so do that first. this.schedule_macos_tls_dtor()?; - this.schedule_pthread_tls_dtors()?; + this.schedule_pthread_tls_dtors()? + }; + + if finished { + this.machine.tls.delete_all_thread_tls(active_thread); } Ok(()) From 3b5854191c35107a50ff83dd1e8b46f58d964224 Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Mon, 27 Apr 2020 15:21:01 -0700 Subject: [PATCH 1996/3747] Fix MacOS and Windows builds. --- src/shims/tls.rs | 25 +++++++++++++++++-------- tests/run-pass/libc.rs | 1 + 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/src/shims/tls.rs b/src/shims/tls.rs index d5ea430dd2768..f13d9e6dfee82 100644 --- a/src/shims/tls.rs +++ b/src/shims/tls.rs @@ -253,10 +253,10 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } /// Schedule the MacOS thread destructor of the thread local storage to be - /// executed. + /// executed. Returns `true` if scheduled. /// /// Note: It is safe to call this function also on other Unixes. - fn schedule_macos_tls_dtor(&mut self) -> InterpResult<'tcx> { + fn schedule_macos_tls_dtor(&mut self) -> InterpResult<'tcx, bool> { let this = self.eval_context_mut(); let thread_id = this.get_active_thread()?; if let Some((instance, data)) = this.machine.tls.thread_dtors.remove(&thread_id) { @@ -275,8 +275,10 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // guaranteed that we will schedule it again. The `dtors_running` // flag will prevent the code from adding the destructor again. this.enable_thread(thread_id)?; + Ok(true) + } else { + Ok(false) } - Ok(()) } /// Schedule a pthread TLS destructor. Returns `true` if found @@ -331,20 +333,27 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); let active_thread = this.get_active_thread()?; - let finished = if this.tcx.sess.target.target.target_os == "windows" { + let scheduled_next = if this.tcx.sess.target.target.target_os == "windows" { if !this.machine.tls.set_dtors_running_for_thread(active_thread) { this.schedule_windows_tls_dtors()?; + true + } else { + false } - true } else { this.machine.tls.set_dtors_running_for_thread(active_thread); // The macOS thread wide destructor runs "before any TLS slots get // freed", so do that first. - this.schedule_macos_tls_dtor()?; - this.schedule_pthread_tls_dtors()? + if this.schedule_macos_tls_dtor()? { + true + } else { + this.schedule_pthread_tls_dtors()? + } }; - if finished { + if !scheduled_next { + // No dtors scheduled means that we are finished. Delete the + // remaining TLS entries. this.machine.tls.delete_all_thread_tls(active_thread); } diff --git a/tests/run-pass/libc.rs b/tests/run-pass/libc.rs index 5873d42969500..36805fc83e30c 100644 --- a/tests/run-pass/libc.rs +++ b/tests/run-pass/libc.rs @@ -144,6 +144,7 @@ fn test_rwlock_libc_static_initializer() { /// Test whether the `prctl` shim correctly sets the thread name. /// /// Note: `prctl` exists only on Linux. +#[cfg(target_os = "linux")] fn test_prctl_thread_name() { use std::ffi::CString; unsafe { From a5445e0230c7e15357099bcda9e34dc8aa77bc9c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 28 Apr 2020 10:30:21 +0200 Subject: [PATCH 1997/3747] rustup for more LocalDefId changes --- benches/helpers/miri_helper.rs | 2 +- rust-version | 2 +- src/bin/miri-rustc-tests.rs | 2 +- src/bin/miri.rs | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/benches/helpers/miri_helper.rs b/benches/helpers/miri_helper.rs index 589a95b668f37..2e71c7eb8b1d5 100644 --- a/benches/helpers/miri_helper.rs +++ b/benches/helpers/miri_helper.rs @@ -26,7 +26,7 @@ impl rustc_driver::Callbacks for MiriCompilerCalls<'_> { self.bencher.iter(|| { let config = miri::MiriConfig::default(); - miri::eval_main(tcx, entry_def_id, config); + miri::eval_main(tcx, entry_def_id.to_def_id(), config); }); }); diff --git a/rust-version b/rust-version index 53979b82cf834..173566bdf616a 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -e83f7563495dbe2629b0cbc738afb0808c4482e1 +fb5615a4771ea3d54256f969dc84d2dfd38d812c diff --git a/src/bin/miri-rustc-tests.rs b/src/bin/miri-rustc-tests.rs index bae7356eb72c8..add9cfe897fb1 100644 --- a/src/bin/miri-rustc-tests.rs +++ b/src/bin/miri-rustc-tests.rs @@ -54,7 +54,7 @@ impl rustc_driver::Callbacks for MiriCompilerCalls { tcx.hir().krate().visit_all_item_likes(&mut Visitor(tcx)); } else if let Some((entry_def_id, _)) = tcx.entry_fn(LOCAL_CRATE) { let config = miri::MiriConfig::default(); - miri::eval_main(tcx, entry_def_id, config); + miri::eval_main(tcx, entry_def_id.to_def_id(), config); compiler.session().abort_if_errors(); } else { diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 4e20e3a12da7e..06101fe24e2d8 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -39,7 +39,7 @@ impl rustc_driver::Callbacks for MiriCompilerCalls { // Add filename to `miri` arguments. config.args.insert(0, compiler.input().filestem().to_string()); - if let Some(return_code) = miri::eval_main(tcx, entry_def_id, config) { + if let Some(return_code) = miri::eval_main(tcx, entry_def_id.to_def_id(), config) { std::process::exit( i32::try_from(return_code).expect("Return value was too large!"), ); From 46b03174d02c06fe062747e732733a39a1971817 Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Wed, 29 Apr 2020 13:16:22 -0700 Subject: [PATCH 1998/3747] Improve code readability and comments. --- src/eval.rs | 3 ++ src/shims/sync.rs | 2 +- src/shims/thread.rs | 4 +-- src/shims/tls.rs | 67 +++++++++++++++++++++++++++------------------ src/thread.rs | 7 ++--- 5 files changed, 50 insertions(+), 33 deletions(-) diff --git a/src/eval.rs b/src/eval.rs index 89d61d141a23b..6352d06268654 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -211,6 +211,9 @@ pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) -> assert!(ecx.step()?, "a terminated thread was scheduled for execution"); } SchedulingAction::ExecuteDtors => { + // This will either enable the thread again (so we go back + // to `ExecuteStep`), or determine that this thread is done + // for good. ecx.schedule_next_tls_dtor_for_active_thread()?; } SchedulingAction::Stop => { diff --git a/src/shims/sync.rs b/src/shims/sync.rs index 9dad302706c27..bc64b1e97a50e 100644 --- a/src/shims/sync.rs +++ b/src/shims/sync.rs @@ -555,7 +555,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // result, not only readers can starve writers, but also writers can // starve readers. if let Some(_writer) = this.unblock_some_thread(writer_blockset)? { - rwlock_set_writers(this, rwlock_op, Scalar::from_u32(1))?; + assert_eq!(writers, 1); } else { rwlock_set_writers(this, rwlock_op, Scalar::from_u32(0))?; let mut readers = 0; diff --git a/src/shims/thread.rs b/src/shims/thread.rs index 29a4ed3676879..3aca9520f6718 100644 --- a/src/shims/thread.rs +++ b/src/shims/thread.rs @@ -25,7 +25,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let thread_info_place = this.deref_operand(thread)?; this.write_scalar( - Scalar::from_uint(new_thread_id.to_u128(), thread_info_place.layout.size), + Scalar::from_uint(new_thread_id.to_u32(), thread_info_place.layout.size), thread_info_place.into(), )?; @@ -83,7 +83,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); let thread_id = this.get_active_thread()?; - this.write_scalar(Scalar::from_uint(thread_id.to_u128(), dest.layout.size), dest) + this.write_scalar(Scalar::from_uint(thread_id.to_u32(), dest.layout.size), dest) } fn prctl( diff --git a/src/shims/tls.rs b/src/shims/tls.rs index f13d9e6dfee82..8a5bb7b42c5d2 100644 --- a/src/shims/tls.rs +++ b/src/shims/tls.rs @@ -26,7 +26,9 @@ pub struct TlsEntry<'tcx> { #[derive(Clone, Debug)] struct RunningDtorsState { - /// The last TlsKey used to retrieve a TLS destructor. + /// The last TlsKey used to retrieve a TLS destructor. `None` means that we + /// have not tried to retrieve a TLS destructor yet or that we already tried + /// all keys. last_dtor_key: Option, } @@ -40,7 +42,7 @@ pub struct TlsData<'tcx> { /// A single per thread destructor of the thread local storage (that's how /// things work on macOS) with a data argument. - thread_dtors: BTreeMap, Scalar)>, + macos_thread_dtors: BTreeMap, Scalar)>, /// State for currently running TLS dtors. If this map contains a key for a /// specific thread, it means that we are in the "destruct" phase, during @@ -53,7 +55,7 @@ impl<'tcx> Default for TlsData<'tcx> { TlsData { next_key: 1, // start with 1 as we must not use 0 on Windows keys: Default::default(), - thread_dtors: Default::default(), + macos_thread_dtors: Default::default(), dtors_running: Default::default(), } } @@ -143,7 +145,7 @@ impl<'tcx> TlsData<'tcx> { // UB, according to libstd docs. throw_ub_format!("setting thread's local storage destructor while destructors are already running"); } - if self.thread_dtors.insert(thread, (dtor, data)).is_some() { + if self.macos_thread_dtors.insert(thread, (dtor, data)).is_some() { throw_unsup_format!("setting more than one thread local storage destructor for the same thread is not supported"); } Ok(()) @@ -186,6 +188,7 @@ impl<'tcx> TlsData<'tcx> { match data.entry(thread_id) { Entry::Occupied(entry) => { if let Some(dtor) = dtor { + // Set TLS data to NULL, and call dtor with old value. let data_scalar = entry.remove(); let ret = Some((*dtor, data_scalar, key)); return ret; @@ -204,6 +207,8 @@ impl<'tcx> TlsData<'tcx> { if self.dtors_running.contains_key(&thread) { true } else { + // We need to guard this `insert` with a check because otherwise we + // would risk to overwrite `last_dtor_key` with `None`. self.dtors_running.insert( thread, RunningDtorsState { last_dtor_key: None } @@ -259,7 +264,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn schedule_macos_tls_dtor(&mut self) -> InterpResult<'tcx, bool> { let this = self.eval_context_mut(); let thread_id = this.get_active_thread()?; - if let Some((instance, data)) = this.machine.tls.thread_dtors.remove(&thread_id) { + if let Some((instance, data)) = this.machine.tls.macos_thread_dtors.remove(&thread_id) { trace!("Running macos dtor {:?} on {:?} at {:?}", instance, data, thread_id); let ret_place = MPlaceTy::dangling(this.machine.layouts.unit, this).into(); @@ -283,7 +288,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// Schedule a pthread TLS destructor. Returns `true` if found /// a destructor to schedule, and `false` otherwise. - fn schedule_pthread_tls_dtors(&mut self) -> InterpResult<'tcx, bool> { + fn schedule_next_pthread_tls_dtor(&mut self) -> InterpResult<'tcx, bool> { let this = self.eval_context_mut(); let active_thread = this.get_active_thread()?; @@ -329,33 +334,43 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// /// FIXME: we do not support yet deallocation of thread local statics. /// Issue: https://github.com/rust-lang/miri/issues/1369 + /// + /// Note: we consistently run TLS destructors for all threads, including the + /// main thread. However, it is not clear that we should run the TLS + /// destructors for the main thread. See issue: + /// https://github.com/rust-lang/rust/issues/28129. fn schedule_next_tls_dtor_for_active_thread(&mut self) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let active_thread = this.get_active_thread()?; - let scheduled_next = if this.tcx.sess.target.target.target_os == "windows" { - if !this.machine.tls.set_dtors_running_for_thread(active_thread) { + if this.machine.tls.set_dtors_running_for_thread(active_thread) { + // This is the first time we got asked to schedule a destructor. The + // Windows schedule destructor function must be called exactly once, + // this is why it is in this block. + if this.tcx.sess.target.target.target_os == "windows" { + // On Windows, we signal that the thread quit by starting the + // relevant function, reenabling the thread, and going back to + // the scheduler. this.schedule_windows_tls_dtors()?; - true - } else { - false - } - } else { - this.machine.tls.set_dtors_running_for_thread(active_thread); - // The macOS thread wide destructor runs "before any TLS slots get - // freed", so do that first. - if this.schedule_macos_tls_dtor()? { - true - } else { - this.schedule_pthread_tls_dtors()? + return Ok(()) } - }; - - if !scheduled_next { - // No dtors scheduled means that we are finished. Delete the - // remaining TLS entries. - this.machine.tls.delete_all_thread_tls(active_thread); } + // The macOS thread wide destructor runs "before any TLS slots get + // freed", so do that first. + if this.schedule_macos_tls_dtor()? { + // We have scheduled a MacOS dtor to run on the thread. Execute it + // to completion and come back here. Scheduling a destructor + // destroys it, so we will not enter this branch again. + return Ok(()) + } + if this.schedule_next_pthread_tls_dtor()? { + // We have scheduled a pthread destructor and removed it from the + // destructors list. Run it to completion and come back here. + return Ok(()) + } + + // All dtors done! + this.machine.tls.delete_all_thread_tls(active_thread); Ok(()) } diff --git a/src/thread.rs b/src/thread.rs index 69e7bcdb298c1..7d394c900274f 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -2,7 +2,6 @@ use std::cell::RefCell; use std::convert::TryFrom; -use std::convert::TryInto; use std::num::{NonZeroU32, TryFromIntError}; use log::trace; @@ -36,8 +35,8 @@ pub struct ThreadId(u32); const MAIN_THREAD: ThreadId = ThreadId(0); impl ThreadId { - pub fn to_u128(self) -> u128 { - self.0.try_into().unwrap() + pub fn to_u32(self) -> u32 { + self.0 } } @@ -362,7 +361,7 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { fn schedule(&mut self) -> InterpResult<'tcx, SchedulingAction> { // Check whether the thread has **just** terminated (`check_terminated` // checks whether the thread has popped all its stack and if yes, sets - // the thread state to terminated.) + // the thread state to terminated). if self.threads[self.active_thread].check_terminated() { // Check if we need to unblock any threads. for (i, thread) in self.threads.iter_enumerated_mut() { From 0e052ab8970777e8f418c4ccf495845804aeae90 Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Wed, 29 Apr 2020 15:12:09 -0700 Subject: [PATCH 1999/3747] Use Entry API in set_dtors_running. --- src/shims/tls.rs | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/src/shims/tls.rs b/src/shims/tls.rs index 8a5bb7b42c5d2..57b041e685f7f 100644 --- a/src/shims/tls.rs +++ b/src/shims/tls.rs @@ -1,7 +1,8 @@ //! Implement thread-local storage. use std::collections::BTreeMap; -use std::collections::btree_map::Entry; +use std::collections::btree_map::Entry as BTreeEntry; +use std::collections::hash_map::Entry as HashMapEntry; use log::trace; @@ -186,7 +187,7 @@ impl<'tcx> TlsData<'tcx> { thread_local.range_mut((start, Unbounded)) { match data.entry(thread_id) { - Entry::Occupied(entry) => { + BTreeEntry::Occupied(entry) => { if let Some(dtor) = dtor { // Set TLS data to NULL, and call dtor with old value. let data_scalar = entry.remove(); @@ -194,7 +195,7 @@ impl<'tcx> TlsData<'tcx> { return ret; } } - Entry::Vacant(_) => {} + BTreeEntry::Vacant(_) => {} } } None @@ -204,16 +205,14 @@ impl<'tcx> TlsData<'tcx> { /// the existing values stored in `dtors_running` for this thread. Returns /// `true` if dtors for `thread` are already running. fn set_dtors_running_for_thread(&mut self, thread: ThreadId) -> bool { - if self.dtors_running.contains_key(&thread) { - true - } else { - // We need to guard this `insert` with a check because otherwise we - // would risk to overwrite `last_dtor_key` with `None`. - self.dtors_running.insert( - thread, - RunningDtorsState { last_dtor_key: None } - ); - false + match self.dtors_running.entry(thread) { + HashMapEntry::Occupied(_) => true, + HashMapEntry::Vacant(entry) => { + // We cannot just do `self.dtors_running.insert` because that + // would overwrite `last_dtor_key` with `None`. + entry.insert(RunningDtorsState { last_dtor_key: None }); + false + } } } From 603ec0b3d848f4f0f63f4842231ac13e0fa0ce8c Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Wed, 29 Apr 2020 15:20:26 -0700 Subject: [PATCH 2000/3747] Fix a regression in Windows dtors. --- src/shims/tls.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shims/tls.rs b/src/shims/tls.rs index 57b041e685f7f..f78b46ec3e7f0 100644 --- a/src/shims/tls.rs +++ b/src/shims/tls.rs @@ -342,7 +342,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); let active_thread = this.get_active_thread()?; - if this.machine.tls.set_dtors_running_for_thread(active_thread) { + if !this.machine.tls.set_dtors_running_for_thread(active_thread) { // This is the first time we got asked to schedule a destructor. The // Windows schedule destructor function must be called exactly once, // this is why it is in this block. From 488f3801e2a22afb093d03cf176169d91212374c Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Thu, 30 Apr 2020 00:03:43 +0000 Subject: [PATCH 2001/3747] Add servo_arc to trophy case --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index ecff779873abf..82a047e3ff1bf 100644 --- a/README.md +++ b/README.md @@ -270,6 +270,7 @@ Definite bugs found: * [Memory leak in `beef`](https://github.com/maciejhirsz/beef/issues/12) * [Invalid use of undefined memory in `EbrCell`](https://github.com/Firstyear/concread/commit/b15be53b6ec076acb295a5c0483cdb4bf9be838f#diff-6282b2fc8e98bd089a1f0c86f648157cR229) * [Unaligned pointer access in TiKV](https://github.com/tikv/tikv/issues/7613) +* [Invalid use of integer as pointer in `servo_arc`](https://github.com/servo/servo/issues/26357) Violations of [Stacked Borrows] found that are likely bugs (but Stacked Borrows is currently just an experiment): From e9212d14ac1083515d79ace2ced6f5846598983f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 30 Apr 2020 10:19:34 +0200 Subject: [PATCH 2002/3747] more helpful error on workspaces --- src/bin/cargo-miri.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 17d7ecf8c8708..1d93654e33e98 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -144,7 +144,8 @@ fn list_targets() -> impl Iterator { }) .unwrap_or_else(|| { show_error(format!( - "This seems to be a workspace, which is not supported by cargo-miri" + "this seems to be a workspace, which is not supported by `cargo miri`.\n\ + Try to `cd` into the crate you want to test, and re-run `cargo miri` there." )) }); let package = metadata.packages.remove(package_index); From 1aabd6da7509cd67ec2b23f3499686ebf4d73704 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 30 Apr 2020 10:24:57 +0200 Subject: [PATCH 2003/3747] Tweak error wording --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 82a047e3ff1bf..0df6665323418 100644 --- a/README.md +++ b/README.md @@ -270,7 +270,7 @@ Definite bugs found: * [Memory leak in `beef`](https://github.com/maciejhirsz/beef/issues/12) * [Invalid use of undefined memory in `EbrCell`](https://github.com/Firstyear/concread/commit/b15be53b6ec076acb295a5c0483cdb4bf9be838f#diff-6282b2fc8e98bd089a1f0c86f648157cR229) * [Unaligned pointer access in TiKV](https://github.com/tikv/tikv/issues/7613) -* [Invalid use of integer as pointer in `servo_arc`](https://github.com/servo/servo/issues/26357) +* [Dangling shared reference in `servo_arc`](https://github.com/servo/servo/issues/26357) Violations of [Stacked Borrows] found that are likely bugs (but Stacked Borrows is currently just an experiment): From 48da0cf489c1cbbb309692db4049632d83740a8e Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Thu, 30 Apr 2020 08:35:59 -0700 Subject: [PATCH 2004/3747] Fix prctl SET_NAME and GET_NAME behaviour. --- src/shims/thread.rs | 10 ++++++++-- src/thread.rs | 8 ++++---- tests/run-pass/libc.rs | 17 +++++++++++++---- 3 files changed, 25 insertions(+), 10 deletions(-) diff --git a/src/shims/thread.rs b/src/shims/thread.rs index 3aca9520f6718..2f553c1c729e8 100644 --- a/src/shims/thread.rs +++ b/src/shims/thread.rs @@ -99,11 +99,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let option = this.read_scalar(option)?.to_i32()?; if option == this.eval_libc_i32("PR_SET_NAME")? { let address = this.read_scalar(arg2)?.not_undef()?; - let name = this.memory.read_c_str(address)?.to_owned(); + let mut name = this.memory.read_c_str(address)?.to_owned(); + // The name should be no more than 16 bytes, including the null + // byte. Since `read_c_str` returns the string without the null + // byte, we need to truncate to 15. + name.truncate(15); this.set_active_thread_name(name)?; } else if option == this.eval_libc_i32("PR_GET_NAME")? { let address = this.read_scalar(arg2)?.not_undef()?; - let name = this.get_active_thread_name()?.to_vec(); + let mut name = this.get_active_thread_name()?.to_vec(); + name.push(0u8); + assert!(name.len() <= 16); this.memory.write_bytes(address, name)?; } else { throw_unsup_format!("unsupported prctl option {}", option); diff --git a/src/thread.rs b/src/thread.rs index 7d394c900274f..376920e225ba7 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -313,11 +313,11 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { } /// Get the name of the active thread. - fn get_thread_name(&self) -> InterpResult<'tcx, &[u8]> { + fn get_thread_name(&self) -> &[u8] { if let Some(ref thread_name) = self.active_thread_ref().thread_name { - Ok(thread_name) + thread_name } else { - throw_ub_format!("thread {:?} has no name set", self.active_thread) + b"" } } @@ -574,7 +574,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx 'mir: 'c, { let this = self.eval_context_ref(); - this.machine.threads.get_thread_name() + Ok(this.machine.threads.get_thread_name()) } #[inline] diff --git a/tests/run-pass/libc.rs b/tests/run-pass/libc.rs index 36805fc83e30c..04ca5c0b3b1a9 100644 --- a/tests/run-pass/libc.rs +++ b/tests/run-pass/libc.rs @@ -147,12 +147,21 @@ fn test_rwlock_libc_static_initializer() { #[cfg(target_os = "linux")] fn test_prctl_thread_name() { use std::ffi::CString; + use libc::c_long; unsafe { + let mut buf = [255; 10]; + assert_eq!(libc::prctl(libc::PR_GET_NAME, buf.as_mut_ptr() as c_long, 0 as c_long, 0 as c_long, 0 as c_long), 0); + assert_eq!(b"\0", &buf); let thread_name = CString::new("hello").expect("CString::new failed"); - assert_eq!(libc::prctl(libc::PR_SET_NAME, thread_name.as_ptr() as libc::c_long, 0 as libc::c_long, 0 as libc::c_long, 0 as libc::c_long), 0); - let mut buf = [0; 6]; - assert_eq!(libc::prctl(libc::PR_GET_NAME, buf.as_mut_ptr() as libc::c_long, 0 as libc::c_long, 0 as libc::c_long, 0 as libc::c_long), 0); - assert_eq!(thread_name.as_bytes_with_nul(), buf); + assert_eq!(libc::prctl(libc::PR_SET_NAME, thread_name.as_ptr() as c_long, 0 as c_long, 0 as c_long, 0 as c_long), 0); + let mut buf = [255; 6]; + assert_eq!(libc::prctl(libc::PR_GET_NAME, buf.as_mut_ptr() as c_long, 0 as c_long, 0 as c_long, 0 as c_long), 0); + assert_eq!(b"hello\0", &buf); + let long_thread_name = CString::new("01234567890123456789").expect("CString::new failed"); + assert_eq!(libc::prctl(libc::PR_SET_NAME, long_thread_name.as_ptr() as c_long, 0 as c_long, 0 as c_long, 0 as c_long), 0); + let mut buf = [255; 16]; + assert_eq!(libc::prctl(libc::PR_GET_NAME, buf.as_mut_ptr() as c_long, 0 as c_long, 0 as c_long, 0 as c_long), 0); + assert_eq!(b"012345678901234\0", &buf); } } From ba670d69701acd444019c296a0699f7549439e33 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 30 Apr 2020 19:38:17 +0200 Subject: [PATCH 2005/3747] make sure macos function has 'macos' in its name --- src/shims/foreign_items/posix/macos.rs | 2 +- src/shims/tls.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/shims/foreign_items/posix/macos.rs b/src/shims/foreign_items/posix/macos.rs index 200b88f29c8f8..0e3019ce33a39 100644 --- a/src/shims/foreign_items/posix/macos.rs +++ b/src/shims/foreign_items/posix/macos.rs @@ -83,7 +83,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let dtor = this.memory.get_fn(dtor)?.as_instance()?; let data = this.read_scalar(args[1])?.not_undef()?; let active_thread = this.get_active_thread()?; - this.machine.tls.set_thread_dtor(active_thread, dtor, data)?; + this.machine.tls.set_macos_thread_dtor(active_thread, dtor, data)?; } // Querying system information diff --git a/src/shims/tls.rs b/src/shims/tls.rs index f78b46ec3e7f0..1ef4728faf076 100644 --- a/src/shims/tls.rs +++ b/src/shims/tls.rs @@ -136,7 +136,7 @@ impl<'tcx> TlsData<'tcx> { /// implementation](https://github.com/opensource-apple/dyld/blob/195030646877261f0c8c7ad8b001f52d6a26f514/src/threadLocalVariables.c#L389): /// /// // NOTE: this does not need locks because it only operates on current thread data - pub fn set_thread_dtor( + pub fn set_macos_thread_dtor( &mut self, thread: ThreadId, dtor: ty::Instance<'tcx>, From 580c1194d96d08bc2efaba4fbd86e916b849a194 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 30 Apr 2020 19:39:56 +0200 Subject: [PATCH 2006/3747] README tweak --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index a64161809e642..ee23df5ed17e6 100644 --- a/README.md +++ b/README.md @@ -48,8 +48,8 @@ in your program, and cannot run all programs: has no access to most platform-specific APIs or FFI. A few APIs have been implemented (such as printing to stdout) but most have not: for example, Miri currently does not support SIMD or networking. -* Miri currently does not check for data-races and most other concurrency - related issues. +* Miri currently does not check for data-races and most other concurrency-related + issues. [rust]: https://www.rust-lang.org/ [mir]: https://github.com/rust-lang/rfcs/blob/master/text/1211-mir.md From 1a704a517a46c84ca6d347b863ea12173f55b8ec Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 1 May 2020 10:29:39 +0200 Subject: [PATCH 2007/3747] rustup, adjust error messages --- rust-version | 2 +- tests/compile-fail/validity/execute_memory.rs | 2 +- tests/compile-fail/validity/fn_ptr_offset.rs | 2 +- tests/compile-fail/validity/invalid_bool.rs | 2 +- tests/compile-fail/validity/invalid_char.rs | 2 +- tests/compile-fail/validity/invalid_enum_discriminant.rs | 2 +- tests/compile-fail/validity/transmute_through_ptr.rs | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/rust-version b/rust-version index 173566bdf616a..1070924d744d7 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -fb5615a4771ea3d54256f969dc84d2dfd38d812c +e94eaa6dce468928b4e1326b2f0054f3075681ff diff --git a/tests/compile-fail/validity/execute_memory.rs b/tests/compile-fail/validity/execute_memory.rs index 426a51faf8a37..5230e7fdf5297 100644 --- a/tests/compile-fail/validity/execute_memory.rs +++ b/tests/compile-fail/validity/execute_memory.rs @@ -3,6 +3,6 @@ fn main() { let x = box 42; unsafe { - let _f = std::mem::transmute::, fn()>(x); //~ ERROR encountered a pointer, but expected a function pointer + let _f = std::mem::transmute::, fn()>(x); //~ ERROR expected a function pointer } } diff --git a/tests/compile-fail/validity/fn_ptr_offset.rs b/tests/compile-fail/validity/fn_ptr_offset.rs index 5eec58b5e2347..c651fbe070fba 100644 --- a/tests/compile-fail/validity/fn_ptr_offset.rs +++ b/tests/compile-fail/validity/fn_ptr_offset.rs @@ -6,5 +6,5 @@ fn main() { let x : fn() = f; let y : *mut u8 = unsafe { mem::transmute(x) }; let y = y.wrapping_offset(1); - let _x : fn() = unsafe { mem::transmute(y) }; //~ ERROR encountered a pointer, but expected a function pointer + let _x : fn() = unsafe { mem::transmute(y) }; //~ ERROR expected a function pointer } diff --git a/tests/compile-fail/validity/invalid_bool.rs b/tests/compile-fail/validity/invalid_bool.rs index 35f4d4228e70c..0b2d648d02adc 100644 --- a/tests/compile-fail/validity/invalid_bool.rs +++ b/tests/compile-fail/validity/invalid_bool.rs @@ -1,3 +1,3 @@ fn main() { - let _b = unsafe { std::mem::transmute::(2) }; //~ ERROR encountered 2, but expected a boolean + let _b = unsafe { std::mem::transmute::(2) }; //~ ERROR encountered 0x02, but expected a boolean } diff --git a/tests/compile-fail/validity/invalid_char.rs b/tests/compile-fail/validity/invalid_char.rs index 42922cdc917c8..2801f32971569 100644 --- a/tests/compile-fail/validity/invalid_char.rs +++ b/tests/compile-fail/validity/invalid_char.rs @@ -1,6 +1,6 @@ fn main() { assert!(std::char::from_u32(-1_i32 as u32).is_none()); - let _val = match unsafe { std::mem::transmute::(-1) } { //~ ERROR encountered 4294967295, but expected a valid unicode codepoint + let _val = match unsafe { std::mem::transmute::(-1) } { //~ ERROR encountered 0xffffffff, but expected a valid unicode codepoint 'a' => {true}, 'b' => {false}, _ => {true}, diff --git a/tests/compile-fail/validity/invalid_enum_discriminant.rs b/tests/compile-fail/validity/invalid_enum_discriminant.rs index 13be4e7dcea81..a3234ba0920c3 100644 --- a/tests/compile-fail/validity/invalid_enum_discriminant.rs +++ b/tests/compile-fail/validity/invalid_enum_discriminant.rs @@ -4,5 +4,5 @@ pub enum Foo { } fn main() { - let _f = unsafe { std::mem::transmute::(42) }; //~ ERROR encountered 42, but expected a valid enum discriminant + let _f = unsafe { std::mem::transmute::(42) }; //~ ERROR encountered 0x0000002a, but expected a valid enum discriminant } diff --git a/tests/compile-fail/validity/transmute_through_ptr.rs b/tests/compile-fail/validity/transmute_through_ptr.rs index 4b6a3c95928ae..617781c127514 100644 --- a/tests/compile-fail/validity/transmute_through_ptr.rs +++ b/tests/compile-fail/validity/transmute_through_ptr.rs @@ -10,5 +10,5 @@ fn main() { let mut x = Bool::True; evil(&mut x); let _y = x; // reading this ought to be enough to trigger validation - //~^ ERROR encountered 44, but expected a valid enum discriminant + //~^ ERROR encountered 0x0000002c, but expected a valid enum discriminant } From 393165f859c9722494b62da232be332f5428be6c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 1 May 2020 14:43:59 +0200 Subject: [PATCH 2008/3747] rustup; fix for changed error messages --- rust-version | 2 +- src/diagnostics.rs | 2 +- src/intptrcast.rs | 8 +++++--- tests/compile-fail/dangling_pointers/deref-invalid-ptr.rs | 2 +- .../compile-fail/dangling_pointers/wild_pointer_deref.rs | 2 +- .../compile-fail/function_pointers/cast_int_to_fn_ptr.rs | 2 +- tests/compile-fail/intrinsics/copy_null.rs | 2 +- tests/compile-fail/intrinsics/ptr_offset_0_plus_0.rs | 2 +- tests/compile-fail/intrinsics/ptr_offset_int_plus_int.rs | 2 +- tests/compile-fail/intrinsics/ptr_offset_int_plus_ptr.rs | 2 +- tests/compile-fail/intrinsics/write_bytes_null.rs | 2 +- tests/compile-fail/invalid_bool.rs | 2 +- tests/compile-fail/invalid_enum_discriminant.rs | 2 +- tests/compile-fail/null_pointer_deref.rs | 2 +- tests/compile-fail/null_pointer_deref_zst.rs | 2 +- tests/compile-fail/null_pointer_write.rs | 2 +- tests/compile-fail/null_pointer_write_zst.rs | 2 +- tests/compile-fail/stacked_borrows/issue-miri-1050-2.rs | 2 +- 18 files changed, 22 insertions(+), 20 deletions(-) diff --git a/rust-version b/rust-version index 1070924d744d7..7e957fa4257da 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -e94eaa6dce468928b4e1326b2f0054f3075681ff +fd61d06772d17c6242265d860fbfb5eafd282caa diff --git a/src/diagnostics.rs b/src/diagnostics.rs index b7c96dd7e98aa..06d12b99c1ea0 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -16,7 +16,7 @@ pub enum TerminationInfo { Deadlock, } -impl fmt::Debug for TerminationInfo { +impl fmt::Display for TerminationInfo { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { use TerminationInfo::*; match self { diff --git a/src/intptrcast.rs b/src/intptrcast.rs index 5413e6b935b9b..f51c8a7ce7439 100644 --- a/src/intptrcast.rs +++ b/src/intptrcast.rs @@ -9,7 +9,7 @@ use rustc_data_structures::fx::FxHashMap; use rustc_mir::interpret::{AllocCheck, AllocId, InterpResult, Memory, Machine, Pointer, PointerArithmetic}; use rustc_target::abi::{Size, HasDataLayout}; -use crate::{Evaluator, Tag, STACK_ADDR}; +use crate::{Evaluator, Tag, STACK_ADDR, CheckInAllocMsg}; pub type MemoryExtra = RefCell; @@ -46,6 +46,8 @@ impl<'mir, 'tcx> GlobalState { let global_state = memory.extra.intptrcast.borrow(); let pos = global_state.int_to_ptr_map.binary_search_by_key(&int, |(addr, _)| *addr); + // The int must be in-bounds after being cast to a pointer, so we error + // with `CheckInAllocMsg::InboundsTest`. Ok(match pos { Ok(pos) => { let (_, alloc_id) = global_state.int_to_ptr_map[pos]; @@ -53,7 +55,7 @@ impl<'mir, 'tcx> GlobalState { // zero. The pointer is untagged because it was created from a cast Pointer::new_with_tag(alloc_id, Size::from_bytes(0), Tag::Untagged) } - Err(0) => throw_ub!(InvalidIntPointerUsage(int)), + Err(0) => throw_ub!(DanglingIntPointer(int, CheckInAllocMsg::InboundsTest)), Err(pos) => { // This is the largest of the adresses smaller than `int`, // i.e. the greatest lower bound (glb) @@ -65,7 +67,7 @@ impl<'mir, 'tcx> GlobalState { // This pointer is untagged because it was created from a cast Pointer::new_with_tag(alloc_id, Size::from_bytes(offset), Tag::Untagged) } else { - throw_ub!(InvalidIntPointerUsage(int)) + throw_ub!(DanglingIntPointer(int, CheckInAllocMsg::InboundsTest)) } } }) diff --git a/tests/compile-fail/dangling_pointers/deref-invalid-ptr.rs b/tests/compile-fail/dangling_pointers/deref-invalid-ptr.rs index e0bba8c7c730d..6aa93e714721a 100644 --- a/tests/compile-fail/dangling_pointers/deref-invalid-ptr.rs +++ b/tests/compile-fail/dangling_pointers/deref-invalid-ptr.rs @@ -3,5 +3,5 @@ fn main() { let x = 16usize as *const u32; - let _y = unsafe { &*x as *const u32 }; //~ ERROR invalid use of 16 as a pointer + let _y = unsafe { &*x as *const u32 }; //~ ERROR inbounds test failed: 0x10 is not a valid pointer } diff --git a/tests/compile-fail/dangling_pointers/wild_pointer_deref.rs b/tests/compile-fail/dangling_pointers/wild_pointer_deref.rs index 5780cccdb842c..371e72d2822d0 100644 --- a/tests/compile-fail/dangling_pointers/wild_pointer_deref.rs +++ b/tests/compile-fail/dangling_pointers/wild_pointer_deref.rs @@ -1,5 +1,5 @@ fn main() { let p = 44 as *const i32; - let x = unsafe { *p }; //~ ERROR invalid use of 44 as a pointer + let x = unsafe { *p }; //~ ERROR inbounds test failed: 0x2c is not a valid pointer panic!("this should never print: {}", x); } diff --git a/tests/compile-fail/function_pointers/cast_int_to_fn_ptr.rs b/tests/compile-fail/function_pointers/cast_int_to_fn_ptr.rs index 3000779a93307..94ff3327123b4 100644 --- a/tests/compile-fail/function_pointers/cast_int_to_fn_ptr.rs +++ b/tests/compile-fail/function_pointers/cast_int_to_fn_ptr.rs @@ -6,5 +6,5 @@ fn main() { std::mem::transmute::(42) }; - g(42) //~ ERROR invalid use of 42 as a pointer + g(42) //~ ERROR inbounds test failed: 0x2a is not a valid pointer } diff --git a/tests/compile-fail/intrinsics/copy_null.rs b/tests/compile-fail/intrinsics/copy_null.rs index b14bdc4b38632..60cb7e4eff513 100644 --- a/tests/compile-fail/intrinsics/copy_null.rs +++ b/tests/compile-fail/intrinsics/copy_null.rs @@ -9,5 +9,5 @@ fn main() { let mut data = [0u16; 4]; let ptr = &mut data[0] as *mut u16; // Even copying 0 elements from NULL should error. - unsafe { copy_nonoverlapping(std::ptr::null(), ptr, 0); } //~ ERROR: invalid use of NULL pointer + unsafe { copy_nonoverlapping(std::ptr::null(), ptr, 0); } //~ ERROR: memory access failed: 0x0 is not a valid pointer } diff --git a/tests/compile-fail/intrinsics/ptr_offset_0_plus_0.rs b/tests/compile-fail/intrinsics/ptr_offset_0_plus_0.rs index 96a9fb8402f68..d6cf3d65f296d 100644 --- a/tests/compile-fail/intrinsics/ptr_offset_0_plus_0.rs +++ b/tests/compile-fail/intrinsics/ptr_offset_0_plus_0.rs @@ -1,4 +1,4 @@ -// error-pattern: invalid use of NULL pointer +// error-pattern: inbounds test failed: 0x0 is not a valid pointer fn main() { let x = 0 as *mut i32; diff --git a/tests/compile-fail/intrinsics/ptr_offset_int_plus_int.rs b/tests/compile-fail/intrinsics/ptr_offset_int_plus_int.rs index f0cf00884e15b..4bee2fec6b7b0 100644 --- a/tests/compile-fail/intrinsics/ptr_offset_int_plus_int.rs +++ b/tests/compile-fail/intrinsics/ptr_offset_int_plus_int.rs @@ -1,4 +1,4 @@ -// error-pattern: invalid use of 1 as a pointer +// error-pattern: inbounds test failed: 0x1 is not a valid pointer fn main() { // Can't offset an integer pointer by non-zero offset. diff --git a/tests/compile-fail/intrinsics/ptr_offset_int_plus_ptr.rs b/tests/compile-fail/intrinsics/ptr_offset_int_plus_ptr.rs index 705ca68970a1a..892dbca1128fc 100644 --- a/tests/compile-fail/intrinsics/ptr_offset_int_plus_ptr.rs +++ b/tests/compile-fail/intrinsics/ptr_offset_int_plus_ptr.rs @@ -1,4 +1,4 @@ -// error-pattern: invalid use of 1 as a pointer +// error-pattern: inbounds test failed: 0x1 is not a valid pointer fn main() { let ptr = Box::into_raw(Box::new(0u32)); diff --git a/tests/compile-fail/intrinsics/write_bytes_null.rs b/tests/compile-fail/intrinsics/write_bytes_null.rs index e80222162ee38..c3f77b27b4ff0 100644 --- a/tests/compile-fail/intrinsics/write_bytes_null.rs +++ b/tests/compile-fail/intrinsics/write_bytes_null.rs @@ -6,5 +6,5 @@ extern "rust-intrinsic" { } fn main() { - unsafe { write_bytes::(std::ptr::null_mut(), 0, 0) }; //~ ERROR invalid use of NULL pointer + unsafe { write_bytes::(std::ptr::null_mut(), 0, 0) }; //~ ERROR memory access failed: 0x0 is not a valid pointer } diff --git a/tests/compile-fail/invalid_bool.rs b/tests/compile-fail/invalid_bool.rs index 38033146ade82..23441ea7d4aad 100644 --- a/tests/compile-fail/invalid_bool.rs +++ b/tests/compile-fail/invalid_bool.rs @@ -4,5 +4,5 @@ fn main() { let b = unsafe { std::mem::transmute::(2) }; - let _x = b == true; //~ ERROR interpreting an invalid 8-bit value as a bool: 2 + let _x = b == true; //~ ERROR interpreting an invalid 8-bit value as a bool } diff --git a/tests/compile-fail/invalid_enum_discriminant.rs b/tests/compile-fail/invalid_enum_discriminant.rs index cdbea6aa12234..893dd03c64e67 100644 --- a/tests/compile-fail/invalid_enum_discriminant.rs +++ b/tests/compile-fail/invalid_enum_discriminant.rs @@ -2,7 +2,7 @@ // Make sure we find these even with many checks disabled. // compile-flags: -Zmiri-disable-alignment-check -Zmiri-disable-stacked-borrows -Zmiri-disable-validation -// error-pattern: invalid enum discriminant +// error-pattern: enum value has invalid discriminant: 0x0000002a use std::mem; diff --git a/tests/compile-fail/null_pointer_deref.rs b/tests/compile-fail/null_pointer_deref.rs index 8bf0392b8903b..bd4758f737e71 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 invalid use of NULL pointer + let x: i32 = unsafe { *std::ptr::null() }; //~ ERROR inbounds test failed: 0x0 is not a valid pointer panic!("this should never print: {}", x); } diff --git a/tests/compile-fail/null_pointer_deref_zst.rs b/tests/compile-fail/null_pointer_deref_zst.rs index b2800e96292d7..cfd3a75e3b8cf 100644 --- a/tests/compile-fail/null_pointer_deref_zst.rs +++ b/tests/compile-fail/null_pointer_deref_zst.rs @@ -1,4 +1,4 @@ fn main() { - let x: () = unsafe { *std::ptr::null() }; //~ ERROR invalid use of NULL pointer + let x: () = unsafe { *std::ptr::null() }; //~ ERROR memory access failed: 0x0 is not a valid pointer panic!("this should never print: {:?}", x); } diff --git a/tests/compile-fail/null_pointer_write.rs b/tests/compile-fail/null_pointer_write.rs index 1577b2a1b13bc..97c9ee8b1f52d 100644 --- a/tests/compile-fail/null_pointer_write.rs +++ b/tests/compile-fail/null_pointer_write.rs @@ -1,3 +1,3 @@ fn main() { - unsafe { *std::ptr::null_mut() = 0i32 }; //~ ERROR invalid use of NULL pointer + unsafe { *std::ptr::null_mut() = 0i32 }; //~ ERROR inbounds test failed: 0x0 is not a valid pointer } diff --git a/tests/compile-fail/null_pointer_write_zst.rs b/tests/compile-fail/null_pointer_write_zst.rs index 7e91d736bd295..0f7244ba25ccf 100644 --- a/tests/compile-fail/null_pointer_write_zst.rs +++ b/tests/compile-fail/null_pointer_write_zst.rs @@ -2,5 +2,5 @@ fn main() { // Not using the () type here, as writes of that type do not even have MIR generated. // Also not assigning directly as that's array initialization, not assignment. let zst_val = [1u8; 0]; - unsafe { *std::ptr::null_mut() = zst_val }; //~ ERROR invalid use of NULL pointer + unsafe { *std::ptr::null_mut() = zst_val }; //~ ERROR memory access failed: 0x0 is not a valid pointer } diff --git a/tests/compile-fail/stacked_borrows/issue-miri-1050-2.rs b/tests/compile-fail/stacked_borrows/issue-miri-1050-2.rs index 69f19651e540d..c40d8de21dd7f 100644 --- a/tests/compile-fail/stacked_borrows/issue-miri-1050-2.rs +++ b/tests/compile-fail/stacked_borrows/issue-miri-1050-2.rs @@ -1,4 +1,4 @@ -// error-pattern: invalid use of 4 as a pointer +// error-pattern: inbounds test failed: 0x4 is not a valid pointer use std::ptr::NonNull; fn main() { unsafe { From 5e25dfaef83d1a2855cc4e4a1aecca77ba0dc47a Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Fri, 1 May 2020 21:34:16 +0000 Subject: [PATCH 2009/3747] Add another tikv stacked borrowing error to trophy case --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index ee23df5ed17e6..08e30b5f77dd5 100644 --- a/README.md +++ b/README.md @@ -285,6 +285,7 @@ Violations of [Stacked Borrows] found that are likely bugs (but Stacked Borrows * [`String::push_str` invalidating existing references into the string](https://github.com/rust-lang/rust/issues/70301) * [`ryu` using raw pointers outside their valid memory area](https://github.com/dtolnay/ryu/issues/24) * [ink! creating overlapping mutable references](https://github.com/rust-lang/miri/issues/1364) +* [Stacked borrowing violation in TiKV](https://github.com/tikv/tikv/pull/7709) ## License From dbd6403955a4d7ebb589a1b40c1b55d1cf04cfe2 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 2 May 2020 02:13:48 +0200 Subject: [PATCH 2010/3747] rustup for fixed error messages --- rust-version | 2 +- tests/compile-fail/invalid_bool.rs | 2 +- tests/compile-fail/invalid_char.rs | 7 ++++--- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/rust-version b/rust-version index 7e957fa4257da..853c4ff103357 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -fd61d06772d17c6242265d860fbfb5eafd282caa +7f65393b9abf5e70d0b9a8080558f17c5625bd40 diff --git a/tests/compile-fail/invalid_bool.rs b/tests/compile-fail/invalid_bool.rs index 23441ea7d4aad..6dee9ec3c91a8 100644 --- a/tests/compile-fail/invalid_bool.rs +++ b/tests/compile-fail/invalid_bool.rs @@ -4,5 +4,5 @@ fn main() { let b = unsafe { std::mem::transmute::(2) }; - let _x = b == true; //~ ERROR interpreting an invalid 8-bit value as a bool + let _x = b == true; //~ ERROR interpreting an invalid 8-bit value as a bool: 0x02 } diff --git a/tests/compile-fail/invalid_char.rs b/tests/compile-fail/invalid_char.rs index ab10ab1e2173d..b240cb22ebe93 100644 --- a/tests/compile-fail/invalid_char.rs +++ b/tests/compile-fail/invalid_char.rs @@ -3,7 +3,8 @@ // compile-flags: -Zmiri-disable-alignment-check -Zmiri-disable-stacked-borrows -Zmiri-disable-validation fn main() { - assert!(std::char::from_u32(-1_i32 as u32).is_none()); - let c = unsafe { std::mem::transmute::(-1) }; - let _x = c == 'x'; //~ ERROR interpreting an invalid 32-bit value as a char + let c = 0xFFFFFFu32; + assert!(std::char::from_u32(c).is_none()); + let c = unsafe { std::mem::transmute::(c) }; + let _x = c == 'x'; //~ ERROR interpreting an invalid 32-bit value as a char: 0x00ffffff } From ee6460e7639832f87f4c6f077cce932cd804301e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 2 May 2020 11:00:37 +0200 Subject: [PATCH 2011/3747] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 853c4ff103357..7affb621bc70e 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -7f65393b9abf5e70d0b9a8080558f17c5625bd40 +dae90c195989b09475b6c0225a3018cbd7afa587 From 15c299e6570d2f96c364b41cff5e937b8825501e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 2 May 2020 11:04:45 +0200 Subject: [PATCH 2012/3747] Adjust wording --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 08e30b5f77dd5..4ca4840714a88 100644 --- a/README.md +++ b/README.md @@ -285,7 +285,7 @@ Violations of [Stacked Borrows] found that are likely bugs (but Stacked Borrows * [`String::push_str` invalidating existing references into the string](https://github.com/rust-lang/rust/issues/70301) * [`ryu` using raw pointers outside their valid memory area](https://github.com/dtolnay/ryu/issues/24) * [ink! creating overlapping mutable references](https://github.com/rust-lang/miri/issues/1364) -* [Stacked borrowing violation in TiKV](https://github.com/tikv/tikv/pull/7709) +* [TiKV creating overlapping mutable reference and raw pointer](https://github.com/tikv/tikv/pull/7709) ## License From df4623e5d8518db4ca845f3db6b36e57f87c3d81 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 2 May 2020 11:08:20 +0200 Subject: [PATCH 2013/3747] trophy case: consistent wording (X doing Y) --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index ee23df5ed17e6..1e271f7a2c1fb 100644 --- a/README.md +++ b/README.md @@ -269,10 +269,10 @@ Definite bugs found: * [The Unix allocator calling `posix_memalign` in an invalid way](https://github.com/rust-lang/rust/issues/62251) * [`getrandom` calling the `getrandom` syscall in an invalid way](https://github.com/rust-random/getrandom/pull/73) * [`Vec`](https://github.com/rust-lang/rust/issues/69770) and [`BTreeMap`](https://github.com/rust-lang/rust/issues/69769) leaking memory under some (panicky) conditions -* [Memory leak in `beef`](https://github.com/maciejhirsz/beef/issues/12) -* [Invalid use of undefined memory in `EbrCell`](https://github.com/Firstyear/concread/commit/b15be53b6ec076acb295a5c0483cdb4bf9be838f#diff-6282b2fc8e98bd089a1f0c86f648157cR229) -* [Unaligned pointer access in TiKV](https://github.com/tikv/tikv/issues/7613) -* [Dangling shared reference in `servo_arc`](https://github.com/servo/servo/issues/26357) +* [`beef` leaking memory](https://github.com/maciejhirsz/beef/issues/12) +* [`EbrCell` using uninitialized memory incorrectly](https://github.com/Firstyear/concread/commit/b15be53b6ec076acb295a5c0483cdb4bf9be838f#diff-6282b2fc8e98bd089a1f0c86f648157cR229) +* [TiKV performing an unaligned pointer access](https://github.com/tikv/tikv/issues/7613) +* [`servo_arc` creating a dangling shared reference](https://github.com/servo/servo/issues/26357) Violations of [Stacked Borrows] found that are likely bugs (but Stacked Borrows is currently just an experiment): @@ -281,7 +281,7 @@ Violations of [Stacked Borrows] found that are likely bugs (but Stacked Borrows * [`LinkedList` creating overlapping mutable references](https://github.com/rust-lang/rust/pull/60072) * [`Vec::push` invalidating existing references into the vector](https://github.com/rust-lang/rust/issues/60847) * [`align_to_mut` violating uniqueness of mutable references](https://github.com/rust-lang/rust/issues/68549) -* [Aliasing mutable references in `sized-chunks`](https://github.com/bodil/sized-chunks/issues/8) +* [`sized-chunks` creating aliasing mutable references](https://github.com/bodil/sized-chunks/issues/8) * [`String::push_str` invalidating existing references into the string](https://github.com/rust-lang/rust/issues/70301) * [`ryu` using raw pointers outside their valid memory area](https://github.com/dtolnay/ryu/issues/24) * [ink! creating overlapping mutable references](https://github.com/rust-lang/miri/issues/1364) From 157854095957cee97962921b87cdda14d2131787 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 3 May 2020 12:10:24 +0200 Subject: [PATCH 2014/3747] bump Rust, fix warnings --- rust-version | 2 +- src/diagnostics.rs | 2 +- src/eval.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/rust-version b/rust-version index 7affb621bc70e..81fe678f1172a 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -dae90c195989b09475b6c0225a3018cbd7afa587 +0a675c5e02e6ecfda7d4e04aabd23a9935e0c4bf diff --git a/src/diagnostics.rs b/src/diagnostics.rs index 06d12b99c1ea0..e5e7f0c904754 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -48,7 +48,7 @@ pub enum NonHaltingDiagnostic { /// Emit a custom diagnostic without going through the miri-engine machinery pub fn report_error<'tcx, 'mir>( ecx: &InterpCx<'mir, 'tcx, Evaluator<'mir, 'tcx>>, - mut e: InterpErrorInfo<'tcx>, + e: InterpErrorInfo<'tcx>, ) -> Option { use InterpError::*; diff --git a/src/eval.rs b/src/eval.rs index 6352d06268654..5daad7cc068b8 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -196,7 +196,7 @@ pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) -> let (mut ecx, ret_place) = match create_ecx(tcx, main_id, config) { Ok(v) => v, - Err(mut err) => { + Err(err) => { err.print_backtrace(); panic!("Miri initialization error: {}", err.kind) } From ff1f0b06cca7697db480087820640115946fb7f7 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 3 May 2020 12:24:40 +0200 Subject: [PATCH 2015/3747] explain what happens in a test --- tests/run-pass/transmute_fat2.rs | 1 + tests/run-pass/transmute_fat2.stderr | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/run-pass/transmute_fat2.rs b/tests/run-pass/transmute_fat2.rs index 8cbe9a099bb6c..c667aab6bb5fd 100644 --- a/tests/run-pass/transmute_fat2.rs +++ b/tests/run-pass/transmute_fat2.rs @@ -8,5 +8,6 @@ fn main() { let bad = unsafe { std::mem::transmute::(42) }; + // This created a slice with length 0, so the following will fail the bounds check. bad[0]; } diff --git a/tests/run-pass/transmute_fat2.stderr b/tests/run-pass/transmute_fat2.stderr index 08849a5b517a4..2539e58814d6b 100644 --- a/tests/run-pass/transmute_fat2.stderr +++ b/tests/run-pass/transmute_fat2.stderr @@ -1 +1 @@ -thread 'main' panicked at 'index out of bounds: the len is 0 but the index is 0', $DIR/transmute_fat2.rs:11:5 +thread 'main' panicked at 'index out of bounds: the len is 0 but the index is 0', $DIR/transmute_fat2.rs:12:5 From 994b13eaee64ac87fbdee4cc0efd7cae0d3f9c2a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 3 May 2020 12:24:57 +0200 Subject: [PATCH 2016/3747] yield on x86 'pause' hint --- src/shims/foreign_items.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 9e531accd06a8..25aece5989b92 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -434,7 +434,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // Architecture-specific shims - "llvm.x86.sse2.pause" if this.tcx.sess.target.target.arch == "x86" || this.tcx.sess.target.target.arch == "x86_64" => {} + "llvm.x86.sse2.pause" if this.tcx.sess.target.target.arch == "x86" || this.tcx.sess.target.target.arch == "x86_64" => { + this.sched_yield()?; + } // Platform-specific shims _ => match this.tcx.sess.target.target.target_os.as_str() { From 2b591b849f6654da993304e6b3c14472e8b4d205 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 3 May 2020 12:25:07 +0200 Subject: [PATCH 2017/3747] test panics in threads --- tests/run-pass/concurrency/simple.rs | 11 +++++++++++ tests/run-pass/concurrency/simple.stderr | 1 + 2 files changed, 12 insertions(+) diff --git a/tests/run-pass/concurrency/simple.rs b/tests/run-pass/concurrency/simple.rs index ad47bb144b58d..a065813490579 100644 --- a/tests/run-pass/concurrency/simple.rs +++ b/tests/run-pass/concurrency/simple.rs @@ -49,6 +49,16 @@ fn create_move_out() { assert_eq!(result.len(), 6); } +fn panic() { + let result = thread::spawn(|| { + panic!("Hello!") + }) + .join() + .unwrap_err(); + let msg = result.downcast_ref::<&'static str>().unwrap(); + assert_eq!(*msg, "Hello!"); +} + fn main() { create_and_detach(); create_and_join(); @@ -58,4 +68,5 @@ fn main() { create_nested_and_join(); create_move_in(); create_move_out(); + panic(); } diff --git a/tests/run-pass/concurrency/simple.stderr b/tests/run-pass/concurrency/simple.stderr index 2dbfb7721d368..dff33c6531c4c 100644 --- a/tests/run-pass/concurrency/simple.stderr +++ b/tests/run-pass/concurrency/simple.stderr @@ -1,2 +1,3 @@ warning: thread support is experimental. For example, Miri does not detect data races yet. +thread '' panicked at 'Hello!', $DIR/simple.rs:54:9 From c26fb591fa562268d8eb47599717f8d6c96f1d3b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 3 May 2020 12:40:15 +0200 Subject: [PATCH 2018/3747] also test std::hint::spin_loop --- tests/run-pass/sync.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/run-pass/sync.rs b/tests/run-pass/sync.rs index a4fd6f584c589..8b8594d4df69d 100644 --- a/tests/run-pass/sync.rs +++ b/tests/run-pass/sync.rs @@ -1,7 +1,8 @@ -#![feature(rustc_private)] +#![feature(rustc_private, renamed_spin_loop)] use std::sync::{Mutex, TryLockError}; use std::sync::atomic; +use std::hint; fn main() { test_mutex_stdlib(); @@ -56,6 +57,7 @@ impl TryLockErrorExt for TryLockError { fn test_spin_loop_hint() { atomic::spin_loop_hint(); + hint::spin_loop(); } fn test_thread_yield_now() { From f2f4e6fc65f15d593dacb79f6558d66618705415 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 3 May 2020 12:51:48 +0200 Subject: [PATCH 2019/3747] also test panic from thread with name --- tests/run-pass/concurrency/simple.rs | 10 ++++++++++ tests/run-pass/concurrency/simple.stderr | 1 + 2 files changed, 11 insertions(+) diff --git a/tests/run-pass/concurrency/simple.rs b/tests/run-pass/concurrency/simple.rs index a065813490579..c22506821f548 100644 --- a/tests/run-pass/concurrency/simple.rs +++ b/tests/run-pass/concurrency/simple.rs @@ -59,6 +59,15 @@ fn panic() { assert_eq!(*msg, "Hello!"); } +fn panic_named() { + thread::Builder::new().name("childthread".to_string()).spawn(move || { + panic!("Hello, world!"); + }) + .unwrap() + .join() + .unwrap_err(); +} + fn main() { create_and_detach(); create_and_join(); @@ -69,4 +78,5 @@ fn main() { create_move_in(); create_move_out(); panic(); + panic_named(); } diff --git a/tests/run-pass/concurrency/simple.stderr b/tests/run-pass/concurrency/simple.stderr index dff33c6531c4c..e52d07cdc73f7 100644 --- a/tests/run-pass/concurrency/simple.stderr +++ b/tests/run-pass/concurrency/simple.stderr @@ -1,3 +1,4 @@ warning: thread support is experimental. For example, Miri does not detect data races yet. thread '' panicked at 'Hello!', $DIR/simple.rs:54:9 +thread 'childthread' panicked at 'Hello, world!', $DIR/simple.rs:64:9 From 6680118588f4ba52683b9fffbb7ac88a50b4f971 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 3 May 2020 12:56:38 +0200 Subject: [PATCH 2020/3747] de-duplicate default thread name --- src/thread.rs | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/thread.rs b/src/thread.rs index 376920e225ba7..2119175e12cc9 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -134,16 +134,20 @@ impl<'mir, 'tcx> Thread<'mir, 'tcx> { } false } + + /// Get the name of the current thread, or `` if it was not set. + fn thread_name(&self) -> &[u8] { + if let Some(ref thread_name) = self.thread_name { + thread_name + } else { + b"" + } + } } impl<'mir, 'tcx> std::fmt::Debug for Thread<'mir, 'tcx> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - if let Some(ref name) = self.thread_name { - write!(f, "{}", String::from_utf8_lossy(name))?; - } else { - write!(f, "")?; - } - write!(f, "({:?}, {:?})", self.state, self.join_status) + write!(f, "{}({:?}, {:?})", String::from_utf8_lossy(self.thread_name()), self.state, self.join_status) } } @@ -314,11 +318,7 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { /// Get the name of the active thread. fn get_thread_name(&self) -> &[u8] { - if let Some(ref thread_name) = self.active_thread_ref().thread_name { - thread_name - } else { - b"" - } + self.active_thread_ref().thread_name() } /// Allocate a new blockset id. From 6b18f6e10602b5ea08fbd94c5e10396f984d8174 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 3 May 2020 13:22:56 +0200 Subject: [PATCH 2021/3747] fix setting thread name on macOS --- src/shims/foreign_items/posix/macos.rs | 6 ++++++ src/shims/thread.rs | 14 ++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/src/shims/foreign_items/posix/macos.rs b/src/shims/foreign_items/posix/macos.rs index 0e3019ce33a39..3677960fd8777 100644 --- a/src/shims/foreign_items/posix/macos.rs +++ b/src/shims/foreign_items/posix/macos.rs @@ -98,6 +98,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(stack_size, dest)?; } + // Threading + "pthread_setname_np" => { + let ptr = this.read_scalar(args[0])?.not_undef()?; + this.pthread_setname_np(ptr)?; + } + // Incomplete shims that we "stub out" just to get pre-main initialization code to work. // These shims are enabled only when the caller is in the standard library. "mmap" if this.frame().instance.to_string().starts_with("std::sys::unix::") => { diff --git a/src/shims/thread.rs b/src/shims/thread.rs index 2f553c1c729e8..ac1bb39a69828 100644 --- a/src/shims/thread.rs +++ b/src/shims/thread.rs @@ -95,6 +95,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx _arg5: OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); + this.assert_target_os("linux", "prctl"); let option = this.read_scalar(option)?.to_i32()?; if option == this.eval_libc_i32("PR_SET_NAME")? { @@ -118,6 +119,19 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(0) } + fn pthread_setname_np( + &mut self, + ptr: Scalar, + ) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + this.assert_target_os("macos", "pthread_setname_np"); + + let name = this.memory.read_c_str(ptr)?.to_owned(); + this.set_active_thread_name(name)?; + + Ok(()) + } + fn sched_yield(&mut self) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); From 61a86e1ffea5bbda721ab2d2702807f085e2a3a4 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 4 May 2020 09:37:40 +0200 Subject: [PATCH 2022/3747] Windows lock primitives: check that we are truly sinle-threaded --- src/shims/foreign_items/windows.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/shims/foreign_items/windows.rs b/src/shims/foreign_items/windows.rs index a58444b21bff1..f55b5b8450e04 100644 --- a/src/shims/foreign_items/windows.rs +++ b/src/shims/foreign_items/windows.rs @@ -236,12 +236,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "LeaveCriticalSection" | "DeleteCriticalSection" if this.frame().instance.to_string().starts_with("std::sys::windows::") => { + assert_eq!(this.get_total_thread_count()?, 1, "concurrency on Windows not supported"); // Nothing to do, not even a return value. // (Windows locks are reentrant, and we have only 1 thread, // so not doing any futher checks here is at least not incorrect.) } "TryEnterCriticalSection" if this.frame().instance.to_string().starts_with("std::sys::windows::") => { + assert_eq!(this.get_total_thread_count()?, 1, "concurrency on Windows not supported"); // There is only one thread, so this always succeeds and returns TRUE this.write_scalar(Scalar::from_i32(1), dest)?; } From 65c3914a29b250081b4dd659657d612929fdaef2 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 4 May 2020 09:43:09 +0200 Subject: [PATCH 2023/3747] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 81fe678f1172a..be7b603f9054a 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -0a675c5e02e6ecfda7d4e04aabd23a9935e0c4bf +ff4df04799c406c8149a041c3163321758aac924 From ec95ed4556e63e93fb5abb453bfb9db41c4c5a76 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 4 May 2020 09:45:15 +0200 Subject: [PATCH 2024/3747] rename single-threaded sync test --- tests/run-pass/{sync.rs => sync_singlethread.rs} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename tests/run-pass/{sync.rs => sync_singlethread.rs} (100%) diff --git a/tests/run-pass/sync.rs b/tests/run-pass/sync_singlethread.rs similarity index 100% rename from tests/run-pass/sync.rs rename to tests/run-pass/sync_singlethread.rs From 78f329513af3e5f34cfd4d9a09fe3a9a4427194f Mon Sep 17 00:00:00 2001 From: Chase Albert Date: Thu, 2 Apr 2020 17:09:20 -0400 Subject: [PATCH 2025/3747] Check that shims are called with the correct number of arguments --- src/helpers.rs | 11 +- src/lib.rs | 3 + src/shims/dlsym.rs | 6 +- src/shims/foreign_items.rs | 91 ++++++++------ src/shims/foreign_items/posix.rs | 160 ++++++++++++++++--------- src/shims/foreign_items/posix/linux.rs | 57 +++++---- src/shims/foreign_items/posix/macos.rs | 47 +++++--- src/shims/foreign_items/windows.rs | 127 ++++++++++++++------ src/shims/fs.rs | 25 ++-- src/shims/intrinsics.rs | 143 +++++++++++++--------- src/shims/mod.rs | 4 +- src/shims/panic.rs | 11 +- 12 files changed, 445 insertions(+), 240 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index 644ea25fbc4bf..43a20d290c80f 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -1,4 +1,4 @@ -use std::convert::TryFrom; +use std::convert::{TryFrom, TryInto}; use std::mem; use std::num::NonZeroUsize; @@ -471,6 +471,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } +/// Check that the number of args is what we expect. +pub fn check_arg_count<'a, 'tcx, const N: usize>(args: &'a [OpTy<'tcx, Tag>]) -> InterpResult<'tcx, &'a [OpTy<'tcx, Tag>; N]> + where &'a [OpTy<'tcx, Tag>; N]: TryFrom<&'a [OpTy<'tcx, Tag>]> { + if let Ok(ops) = args.try_into() { + return Ok(ops); + } + throw_ub_format!("incorrect number of arguments, got {}, needed {}", args.len(), N) +} + pub fn immty_from_int_checked<'tcx>( int: impl Into, layout: TyAndLayout<'tcx>, diff --git a/src/lib.rs b/src/lib.rs index beee94b918b56..e8cf507d35a0a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -7,6 +7,9 @@ #![warn(rust_2018_idioms)] #![allow(clippy::cast_lossless)] +#![allow(incomplete_features)] +#![feature(const_generics)] + extern crate rustc_apfloat; extern crate rustc_ast; #[macro_use] extern crate rustc_middle; diff --git a/src/shims/dlsym.rs b/src/shims/dlsym.rs index 0f6ba63e984f3..3c4a942b596fb 100644 --- a/src/shims/dlsym.rs +++ b/src/shims/dlsym.rs @@ -1,6 +1,7 @@ use rustc_middle::mir; use crate::*; +use helpers::check_arg_count; #[derive(Debug, Copy, Clone)] pub enum Dlsym { @@ -35,8 +36,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx match dlsym { GetEntropy => { - let ptr = this.read_scalar(args[0])?.not_undef()?; - let len = this.read_scalar(args[1])?.to_machine_usize(this)?; + let &[ptr, len] = check_arg_count(args)?; + let ptr = this.read_scalar(ptr)?.not_undef()?; + let len = this.read_scalar(len)?.to_machine_usize(this)?; this.gen_random(ptr, len)?; this.write_null(dest)?; } diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 25aece5989b92..643f76bfe37a1 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -11,6 +11,7 @@ use rustc_span::symbol::sym; use rustc_ast::attr; use crate::*; +use helpers::check_arg_count; impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { @@ -139,8 +140,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "exit" | "ExitProcess" => { + let &[code] = check_arg_count(args)?; // it's really u32 for ExitProcess, but we have to put it into the `Exit` variant anyway - let code = this.read_scalar(args[0])?.to_i32()?; + let code = this.read_scalar(code)?.to_i32()?; throw_machine_stop!(TerminationInfo::Exit(code.into())); } _ => throw_unsup_format!("can't call (diverging) foreign function: {}", link_name), @@ -197,25 +199,29 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx match link_name { // Standard C allocation "malloc" => { - let size = this.read_scalar(args[0])?.to_machine_usize(this)?; + let &[size] = check_arg_count(args)?; + let size = this.read_scalar(size)?.to_machine_usize(this)?; let res = this.malloc(size, /*zero_init:*/ false, MiriMemoryKind::C); this.write_scalar(res, dest)?; } "calloc" => { - let items = this.read_scalar(args[0])?.to_machine_usize(this)?; - let len = this.read_scalar(args[1])?.to_machine_usize(this)?; + let &[items, len] = check_arg_count(args)?; + let items = this.read_scalar(items)?.to_machine_usize(this)?; + let len = this.read_scalar(len)?.to_machine_usize(this)?; let size = items.checked_mul(len).ok_or_else(|| err_ub_format!("overflow during calloc size computation"))?; let res = this.malloc(size, /*zero_init:*/ true, MiriMemoryKind::C); this.write_scalar(res, dest)?; } "free" => { - let ptr = this.read_scalar(args[0])?.not_undef()?; + let &[ptr] = check_arg_count(args)?; + let ptr = this.read_scalar(ptr)?.not_undef()?; this.free(ptr, MiriMemoryKind::C)?; } "realloc" => { - let old_ptr = this.read_scalar(args[0])?.not_undef()?; - let new_size = this.read_scalar(args[1])?.to_machine_usize(this)?; + let &[old_ptr, new_size] = check_arg_count(args)?; + let old_ptr = this.read_scalar(old_ptr)?.not_undef()?; + let new_size = this.read_scalar(new_size)?.to_machine_usize(this)?; let res = this.realloc(old_ptr, new_size, MiriMemoryKind::C)?; this.write_scalar(res, dest)?; } @@ -224,8 +230,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // (Usually these would be forwarded to to `#[global_allocator]`; we instead implement a generic // allocation that also checks that all conditions are met, such as not permitting zero-sized allocations.) "__rust_alloc" => { - let size = this.read_scalar(args[0])?.to_machine_usize(this)?; - let align = this.read_scalar(args[1])?.to_machine_usize(this)?; + let &[size, align] = check_arg_count(args)?; + let size = this.read_scalar(size)?.to_machine_usize(this)?; + let align = this.read_scalar(align)?.to_machine_usize(this)?; Self::check_alloc_request(size, align)?; let ptr = this.memory.allocate( Size::from_bytes(size), @@ -235,8 +242,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(ptr, dest)?; } "__rust_alloc_zeroed" => { - let size = this.read_scalar(args[0])?.to_machine_usize(this)?; - let align = this.read_scalar(args[1])?.to_machine_usize(this)?; + let &[size, align] = check_arg_count(args)?; + let size = this.read_scalar(size)?.to_machine_usize(this)?; + let align = this.read_scalar(align)?.to_machine_usize(this)?; Self::check_alloc_request(size, align)?; let ptr = this.memory.allocate( Size::from_bytes(size), @@ -248,9 +256,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(ptr, dest)?; } "__rust_dealloc" => { - let ptr = this.read_scalar(args[0])?.not_undef()?; - let old_size = this.read_scalar(args[1])?.to_machine_usize(this)?; - let align = this.read_scalar(args[2])?.to_machine_usize(this)?; + let &[ptr, old_size, align] = check_arg_count(args)?; + let ptr = this.read_scalar(ptr)?.not_undef()?; + let old_size = this.read_scalar(old_size)?.to_machine_usize(this)?; + let align = this.read_scalar(align)?.to_machine_usize(this)?; // No need to check old_size/align; we anyway check that they match the allocation. let ptr = this.force_ptr(ptr)?; this.memory.deallocate( @@ -260,12 +269,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx )?; } "__rust_realloc" => { - let old_size = this.read_scalar(args[1])?.to_machine_usize(this)?; - let align = this.read_scalar(args[2])?.to_machine_usize(this)?; - let new_size = this.read_scalar(args[3])?.to_machine_usize(this)?; + let &[ptr, old_size, align, new_size] = check_arg_count(args)?; + let ptr = this.force_ptr(this.read_scalar(ptr)?.not_undef()?)?; + let old_size = this.read_scalar(old_size)?.to_machine_usize(this)?; + let align = this.read_scalar(align)?.to_machine_usize(this)?; + let new_size = this.read_scalar(new_size)?.to_machine_usize(this)?; Self::check_alloc_request(new_size, align)?; // No need to check old_size; we anyway check that they match the allocation. - let ptr = this.force_ptr(this.read_scalar(args[0])?.not_undef()?)?; let align = Align::from_bytes(align).unwrap(); let new_ptr = this.memory.reallocate( ptr, @@ -279,9 +289,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // C memory handling functions "memcmp" => { - let left = this.read_scalar(args[0])?.not_undef()?; - let right = this.read_scalar(args[1])?.not_undef()?; - let n = Size::from_bytes(this.read_scalar(args[2])?.to_machine_usize(this)?); + let &[left, right, n] = check_arg_count(args)?; + let left = this.read_scalar(left)?.not_undef()?; + let right = this.read_scalar(right)?.not_undef()?; + let n = Size::from_bytes(this.read_scalar(n)?.to_machine_usize(this)?); let result = { let left_bytes = this.memory.read_bytes(left, n)?; @@ -298,9 +309,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_i32(result), dest)?; } "memrchr" => { - let ptr = this.read_scalar(args[0])?.not_undef()?; - let val = this.read_scalar(args[1])?.to_i32()? as u8; - let num = this.read_scalar(args[2])?.to_machine_usize(this)?; + let &[ptr, val, num] = check_arg_count(args)?; + let ptr = this.read_scalar(ptr)?.not_undef()?; + let val = this.read_scalar(val)?.to_i32()? as u8; + let num = this.read_scalar(num)?.to_machine_usize(this)?; if let Some(idx) = this .memory .read_bytes(ptr, Size::from_bytes(num))? @@ -315,9 +327,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } "memchr" => { - let ptr = this.read_scalar(args[0])?.not_undef()?; - let val = this.read_scalar(args[1])?.to_i32()? as u8; - let num = this.read_scalar(args[2])?.to_machine_usize(this)?; + let &[ptr, val, num] = check_arg_count(args)?; + let ptr = this.read_scalar(ptr)?.not_undef()?; + let val = this.read_scalar(val)?.to_i32()? as u8; + let num = this.read_scalar(num)?.to_machine_usize(this)?; let idx = this .memory .read_bytes(ptr, Size::from_bytes(num))? @@ -331,7 +344,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } "strlen" => { - let ptr = this.read_scalar(args[0])?.not_undef()?; + let &[ptr] = check_arg_count(args)?; + let ptr = this.read_scalar(ptr)?.not_undef()?; let n = this.memory.read_c_str(ptr)?.len(); this.write_scalar(Scalar::from_machine_usize(u64::try_from(n).unwrap(), this), dest)?; } @@ -345,8 +359,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "asinf" | "atanf" => { + let &[f] = check_arg_count(args)?; // FIXME: Using host floats. - let f = f32::from_bits(this.read_scalar(args[0])?.to_u32()?); + let f = f32::from_bits(this.read_scalar(f)?.to_u32()?); let f = match link_name { "cbrtf" => f.cbrt(), "coshf" => f.cosh(), @@ -363,11 +378,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "hypotf" | "atan2f" => { + let &[f1, f2] = check_arg_count(args)?; // underscore case for windows, here and below // (see https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/floating-point-primitives?view=vs-2019) // FIXME: Using host floats. - let f1 = f32::from_bits(this.read_scalar(args[0])?.to_u32()?); - let f2 = f32::from_bits(this.read_scalar(args[1])?.to_u32()?); + let f1 = f32::from_bits(this.read_scalar(f1)?.to_u32()?); + let f2 = f32::from_bits(this.read_scalar(f2)?.to_u32()?); let n = match link_name { "_hypotf" | "hypotf" => f1.hypot(f2), "atan2f" => f1.atan2(f2), @@ -383,8 +399,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "asin" | "atan" => { + let &[f] = check_arg_count(args)?; // FIXME: Using host floats. - let f = f64::from_bits(this.read_scalar(args[0])?.to_u64()?); + let f = f64::from_bits(this.read_scalar(f)?.to_u64()?); let f = match link_name { "cbrt" => f.cbrt(), "cosh" => f.cosh(), @@ -401,9 +418,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "hypot" | "atan2" => { + let &[f1, f2] = check_arg_count(args)?; // FIXME: Using host floats. - let f1 = f64::from_bits(this.read_scalar(args[0])?.to_u64()?); - let f2 = f64::from_bits(this.read_scalar(args[1])?.to_u64()?); + let f1 = f64::from_bits(this.read_scalar(f1)?.to_u64()?); + let f2 = f64::from_bits(this.read_scalar(f2)?.to_u64()?); let n = match link_name { "_hypot" | "hypot" => f1.hypot(f2), "atan2" => f1.atan2(f2), @@ -415,9 +433,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "ldexp" | "scalbn" => { + let &[x, exp] = check_arg_count(args)?; // For radix-2 (binary) systems, `ldexp` and `scalbn` are the same. - let x = this.read_scalar(args[0])?.to_f64()?; - let exp = this.read_scalar(args[1])?.to_i32()?; + let x = this.read_scalar(x)?.to_f64()?; + let exp = this.read_scalar(exp)?.to_i32()?; // Saturating cast to i16. Even those are outside the valid exponent range to // `scalbn` below will do its over/underflow handling. diff --git a/src/shims/foreign_items/posix.rs b/src/shims/foreign_items/posix.rs index 6e2a7a9fcb4fa..4c50d5ddc5b8c 100644 --- a/src/shims/foreign_items/posix.rs +++ b/src/shims/foreign_items/posix.rs @@ -6,6 +6,7 @@ use std::convert::TryFrom; use log::trace; use crate::*; +use helpers::check_arg_count; use rustc_middle::mir; use rustc_target::abi::{Align, LayoutOf, Size}; @@ -23,43 +24,51 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx match link_name { // Environment related shims "getenv" => { - let result = this.getenv(args[0])?; + let &[name] = check_arg_count(args)?; + let result = this.getenv(name)?; this.write_scalar(result, dest)?; } "unsetenv" => { - let result = this.unsetenv(args[0])?; + let &[name] = check_arg_count(args)?; + let result = this.unsetenv(name)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "setenv" => { - let result = this.setenv(args[0], args[1])?; + let &[name, value, _overwrite] = check_arg_count(args)?; + let result = this.setenv(name, value)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "getcwd" => { - let result = this.getcwd(args[0], args[1])?; + let &[buf, size] = check_arg_count(args)?; + let result = this.getcwd(buf, size)?; this.write_scalar(result, dest)?; } "chdir" => { - let result = this.chdir(args[0])?; + let &[path] = check_arg_count(args)?; + let result = this.chdir(path)?; this.write_scalar(Scalar::from_i32(result), dest)?; } // File related shims "open" | "open64" => { - let result = this.open(args[0], args[1])?; + let &[path, flag, _mode] = check_arg_count(args)?; + let result = this.open(path, flag)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "fcntl" => { - let result = this.fcntl(args[0], args[1], args.get(2).cloned())?; + let result = this.fcntl(args); this.write_scalar(Scalar::from_i32(result), dest)?; } "read" => { - let result = this.read(args[0], args[1], args[2])?; + let &[fd, buf, count] = check_arg_count(args)?; + let result = this.read(fd, buf, count)?; this.write_scalar(Scalar::from_machine_isize(result, this), dest)?; } "write" => { - let fd = this.read_scalar(args[0])?.to_i32()?; - let buf = this.read_scalar(args[1])?.not_undef()?; - let n = this.read_scalar(args[2])?.to_machine_usize(this)?; + let &[fd, buf, n] = check_arg_count(args)?; + let fd = this.read_scalar(fd)?.to_i32()?; + let buf = this.read_scalar(buf)?.not_undef()?; + let n = this.read_scalar(n)?.to_machine_usize(this)?; trace!("Called write({:?}, {:?}, {:?})", fd, buf, n); let result = if fd == 1 || fd == 2 { // stdout/stderr @@ -84,46 +93,55 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Err(_) => -1, } } else { - this.write(args[0], args[1], args[2])? + let &[fd, buf, count] = check_arg_count(args)?; + this.write(fd, buf, count)? }; // Now, `result` is the value we return back to the program. this.write_scalar(Scalar::from_machine_isize(result, this), dest)?; } "unlink" => { - let result = this.unlink(args[0])?; + let &[path] = check_arg_count(args)?; + let result = this.unlink(path)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "symlink" => { - let result = this.symlink(args[0], args[1])?; + let &[target, linkpath] = check_arg_count(args)?; + let result = this.symlink(target, linkpath)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "rename" => { - let result = this.rename(args[0], args[1])?; + let &[oldpath, newpath] = check_arg_count(args)?; + let result = this.rename(oldpath, newpath)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "mkdir" => { - let result = this.mkdir(args[0], args[1])?; + let &[path, mode] = check_arg_count(args)?; + let result = this.mkdir(path, mode)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "rmdir" => { - let result = this.rmdir(args[0])?; + let &[path] = check_arg_count(args)?; + let result = this.rmdir(path)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "closedir" => { - let result = this.closedir(args[0])?; + let &[dirp] = check_arg_count(args)?; + let result = this.closedir(dirp)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "lseek" | "lseek64" => { - let result = this.lseek64(args[0], args[1], args[2])?; + let &[fd, offset, whence] = check_arg_count(args)?; + let result = this.lseek64(fd, offset, whence)?; // "lseek" is only used on macOS which is 64bit-only, so `i64` always works. this.write_scalar(Scalar::from_i64(result), dest)?; } // Allocation "posix_memalign" => { - let ret = this.deref_operand(args[0])?; - let align = this.read_scalar(args[1])?.to_machine_usize(this)?; - let size = this.read_scalar(args[2])?.to_machine_usize(this)?; + let &[ret, align, size] = check_arg_count(args)?; + let ret = this.deref_operand(ret)?; + let align = this.read_scalar(align)?.to_machine_usize(this)?; + let size = this.read_scalar(size)?.to_machine_usize(this)?; // Align must be power of 2, and also at least ptr-sized (POSIX rules). if !align.is_power_of_two() { throw_ub_format!("posix_memalign: alignment must be a power of two, but is {}", align); @@ -150,8 +168,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Dynamic symbol loading "dlsym" => { - let _handle = this.read_scalar(args[0])?; - let symbol = this.read_scalar(args[1])?.not_undef()?; + let &[_handle, symbol] = check_arg_count(args)?; + let _handle = this.read_scalar(_handle)?.not_undef()?; + let symbol = this.read_scalar(symbol)?.not_undef()?; let symbol_name = this.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); @@ -165,7 +184,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Querying system information "sysconf" => { - let name = this.read_scalar(args[0])?.to_i32()?; + let &[name] = check_arg_count(args)?; + let name = this.read_scalar(name)?.to_i32()?; let sysconfs = &[ ("_SC_PAGESIZE", Scalar::from_int(PAGE_SIZE, this.pointer_size())), @@ -188,17 +208,19 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Thread-local storage "pthread_key_create" => { - let key_place = this.deref_operand(args[0])?; + let &[key, dtor] = check_arg_count(args)?; + let key_place = this.deref_operand(key)?; + let dtor = this.read_scalar(dtor)?.not_undef()?; // Extract the function type out of the signature (that seems easier than constructing it ourselves). - let dtor = match this.test_null(this.read_scalar(args[1])?.not_undef()?)? { + let dtor = match this.test_null(dtor)? { Some(dtor_ptr) => Some(this.memory.get_fn(dtor_ptr)?.as_instance()?), None => None, }; // Figure out how large a pthread TLS key actually is. // To this end, deref the argument type. This is `libc::pthread_key_t`. - let key_type = args[0].layout.ty + let key_type = key.layout.ty .builtin_deref(true) .ok_or_else(|| err_ub_format!( "wrong signature used for `pthread_key_create`: first argument must be a raw pointer." @@ -214,21 +236,24 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_null(dest)?; } "pthread_key_delete" => { - let key = this.force_bits(this.read_scalar(args[0])?.not_undef()?, args[0].layout.size)?; + let &[key] = check_arg_count(args)?; + let key = this.force_bits(this.read_scalar(key)?.not_undef()?, key.layout.size)?; this.machine.tls.delete_tls_key(key)?; // Return success (0) this.write_null(dest)?; } "pthread_getspecific" => { - let key = this.force_bits(this.read_scalar(args[0])?.not_undef()?, args[0].layout.size)?; + let &[key] = check_arg_count(args)?; + let key = this.force_bits(this.read_scalar(key)?.not_undef()?, key.layout.size)?; let active_thread = this.get_active_thread()?; let ptr = this.machine.tls.load_tls(key, active_thread, this)?; this.write_scalar(ptr, dest)?; } "pthread_setspecific" => { - let key = this.force_bits(this.read_scalar(args[0])?.not_undef()?, args[0].layout.size)?; + let &[key, new_ptr] = check_arg_count(args)?; + let key = this.force_bits(this.read_scalar(key)?.not_undef()?, key.layout.size)?; let active_thread = this.get_active_thread()?; - let new_ptr = this.read_scalar(args[1])?.not_undef()?; + let new_ptr = this.read_scalar(new_ptr)?.not_undef()?; this.machine.tls.store_tls(key, active_thread, this.test_null(new_ptr)?)?; // Return success (`0`). @@ -237,91 +262,106 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Synchronization primitives "pthread_mutexattr_init" => { - let result = this.pthread_mutexattr_init(args[0])?; + let &[attr] = check_arg_count(args)?; + let result = this.pthread_mutexattr_init(attr)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_mutexattr_settype" => { - let result = this.pthread_mutexattr_settype(args[0], args[1])?; + let &[attr, kind] = check_arg_count(args)?; + let result = this.pthread_mutexattr_settype(attr, kind)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_mutexattr_destroy" => { - let result = this.pthread_mutexattr_destroy(args[0])?; + let &[attr] = check_arg_count(args)?; + let result = this.pthread_mutexattr_destroy(attr)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_mutex_init" => { - let result = this.pthread_mutex_init(args[0], args[1])?; + let &[mutex, attr] = check_arg_count(args)?; + let result = this.pthread_mutex_init(mutex, attr)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_mutex_lock" => { - let result = this.pthread_mutex_lock(args[0])?; + let &[mutex] = check_arg_count(args)?; + let result = this.pthread_mutex_lock(mutex)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_mutex_trylock" => { - let result = this.pthread_mutex_trylock(args[0])?; + let &[mutex] = check_arg_count(args)?; + let result = this.pthread_mutex_trylock(mutex)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_mutex_unlock" => { - let result = this.pthread_mutex_unlock(args[0])?; + let &[mutex] = check_arg_count(args)?; + let result = this.pthread_mutex_unlock(mutex)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_mutex_destroy" => { - let result = this.pthread_mutex_destroy(args[0])?; + let &[mutex] = check_arg_count(args)?; + let result = this.pthread_mutex_destroy(mutex)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_rwlock_rdlock" => { - let result = this.pthread_rwlock_rdlock(args[0])?; + let &[rwlock] = check_arg_count(args)?; + let result = this.pthread_rwlock_rdlock(rwlock)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_rwlock_tryrdlock" => { - let result = this.pthread_rwlock_tryrdlock(args[0])?; + let &[rwlock] = check_arg_count(args)?; + let result = this.pthread_rwlock_tryrdlock(rwlock)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_rwlock_wrlock" => { - let result = this.pthread_rwlock_wrlock(args[0])?; + let &[rwlock] = check_arg_count(args)?; + let result = this.pthread_rwlock_wrlock(rwlock)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_rwlock_trywrlock" => { - let result = this.pthread_rwlock_trywrlock(args[0])?; + let &[rwlock] = check_arg_count(args)?; + let result = this.pthread_rwlock_trywrlock(rwlock)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_rwlock_unlock" => { - let result = this.pthread_rwlock_unlock(args[0])?; + let &[rwlock] = check_arg_count(args)?; + let result = this.pthread_rwlock_unlock(rwlock)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_rwlock_destroy" => { - let result = this.pthread_rwlock_destroy(args[0])?; + let &[rwlock] = check_arg_count(args)?; + let result = this.pthread_rwlock_destroy(rwlock)?; this.write_scalar(Scalar::from_i32(result), dest)?; } // Threading "pthread_create" => { - assert_eq!(args.len(), 4); - let result = this.pthread_create(args[0], args[1], args[2], args[3])?; + let &[thread, attr, start, arg] = check_arg_count(args)?; + let result = this.pthread_create(thread, attr, start, arg)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_join" => { - assert_eq!(args.len(), 2); - let result = this.pthread_join(args[0], args[1])?; + let &[thread, retval] = check_arg_count(args)?; + let result = this.pthread_join(thread, retval)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_detach" => { - assert_eq!(args.len(), 1); - let result = this.pthread_detach(args[0])?; + let &[thread] = check_arg_count(args)?; + let result = this.pthread_detach(thread)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_self" => { - assert_eq!(args.len(), 0); + let &[] = check_arg_count(args)?; this.pthread_self(dest)?; } "sched_yield" => { - assert_eq!(args.len(), 0); + let &[] = check_arg_count(args)?; let result = this.sched_yield()?; this.write_scalar(Scalar::from_i32(result), dest)?; } // Miscellaneous "isatty" => { - let _fd = this.read_scalar(args[0])?.to_i32()?; + let &[_fd] = check_arg_count(args)?; + let _fd = this.read_scalar(_fd)?.to_i32()?; // "returns 1 if fd is an open file descriptor referring to a terminal; otherwise 0 is returned, and errno is set to indicate the error" // FIXME: we just say nothing is a terminal. let enotty = this.eval_libc("ENOTTY")?; @@ -329,9 +369,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_null(dest)?; } "pthread_atfork" => { - let _prepare = this.read_scalar(args[0])?.not_undef()?; - let _parent = this.read_scalar(args[1])?.not_undef()?; - let _child = this.read_scalar(args[1])?.not_undef()?; + let &[_prepare, _parent, _child] = check_arg_count(args)?; + let _prepare = this.read_scalar(_prepare)?.not_undef()?; + let _parent = this.read_scalar(_parent)?.not_undef()?; + let _child = this.read_scalar(_child)?.not_undef()?; // We do not support forking, so there is nothing to do here. this.write_null(dest)?; } @@ -351,7 +392,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "pthread_attr_getguardsize" if this.frame().instance.to_string().starts_with("std::sys::unix::") => { - let guard_size = this.deref_operand(args[1])?; + let &[_attr, guard_size] = check_arg_count(args)?; + let guard_size = this.deref_operand(guard_size)?; let guard_size_layout = this.libc_ty_layout("size_t")?; this.write_scalar(Scalar::from_uint(crate::PAGE_SIZE, guard_size_layout.size), guard_size.into())?; diff --git a/src/shims/foreign_items/posix/linux.rs b/src/shims/foreign_items/posix/linux.rs index eb58f7466089b..b0f4a45f1c011 100644 --- a/src/shims/foreign_items/posix/linux.rs +++ b/src/shims/foreign_items/posix/linux.rs @@ -1,4 +1,5 @@ use crate::*; +use helpers::check_arg_count; use rustc_middle::mir; impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} @@ -15,6 +16,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx match link_name { // errno "__errno_location" => { + let &[] = check_arg_count(args)?; let errno_place = this.machine.last_error.unwrap(); this.write_scalar(errno_place.to_ref().to_scalar()?, dest)?; } @@ -23,27 +25,32 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // These symbols have different names on Linux and macOS, which is the only reason they are not // in the `posix` module. "close" => { - let result = this.close(args[0])?; + let &[fd] = check_arg_count(args)?; + let result = this.close(fd)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "opendir" => { - let result = this.opendir(args[0])?; + let &[name] = check_arg_count(args)?; + let result = this.opendir(name)?; this.write_scalar(result, dest)?; } "readdir64_r" => { - let result = this.linux_readdir64_r(args[0], args[1], args[2])?; + let &[dirp, entry, result] = check_arg_count(args)?; + let result = this.linux_readdir64_r(dirp, entry, result)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "ftruncate64" => { - let result = this.ftruncate64(args[0], args[1])?; + let &[fd, length] = check_arg_count(args)?; + let result = this.ftruncate64(fd, length)?; this.write_scalar(Scalar::from_i32(result), dest)?; } // Linux-only "posix_fadvise" => { - let _fd = this.read_scalar(args[0])?.to_i32()?; - let _offset = this.read_scalar(args[1])?.to_machine_isize(this)?; - let _len = this.read_scalar(args[2])?.to_machine_isize(this)?; - let _advice = this.read_scalar(args[3])?.to_i32()?; + let &[_fd, _offset, _len, _advice] = check_arg_count(args)?; + let _fd = this.read_scalar(_fd)?.to_i32()?; + let _offset = this.read_scalar(_offset)?.to_machine_isize(this)?; + let _len = this.read_scalar(_len)?.to_machine_isize(this)?; + let _advice = this.read_scalar(_advice)?.to_i32()?; // fadvise is only informational, we can ignore it. this.write_null(dest)?; } @@ -51,16 +58,18 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Time related shims "clock_gettime" => { // This is a POSIX function but it has only been tested on linux. - let result = this.clock_gettime(args[0], args[1])?; + let &[clk_id, tp] = check_arg_count(args)?; + let result = this.clock_gettime(clk_id, tp)?; this.write_scalar(Scalar::from_i32(result), dest)?; } // Querying system information "pthread_attr_getstack" => { // We don't support "pthread_attr_setstack", so we just pretend all stacks have the same values here. - let _attr_place = this.deref_operand(args[0])?; - let addr_place = this.deref_operand(args[1])?; - let size_place = this.deref_operand(args[2])?; + let &[_attr_place, addr_place, size_place] = check_arg_count(args)?; + let _attr_place = this.deref_operand(_attr_place)?; + let addr_place = this.deref_operand(addr_place)?; + let size_place = this.deref_operand(size_place)?; this.write_scalar( Scalar::from_uint(STACK_ADDR, this.pointer_size()), @@ -77,8 +86,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Threading "prctl" => { - assert_eq!(args.len(), 5); - let result = this.prctl(args[0], args[1], args[2], args[3], args[4])?; + let &[option, arg2, arg3, arg4, arg5] = check_arg_count(args)?; + let result = this.prctl(option, arg2, arg3, arg4, arg5)?; this.write_scalar(Scalar::from_i32(result), dest)?; } @@ -92,6 +101,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx .eval_libc("SYS_statx")? .to_machine_usize(this)?; + if args.is_empty() { + throw_ub_format!("incorrect number of arguments, needed at least 1"); + } match this.read_scalar(args[0])?.to_machine_usize(this)? { // `libc::syscall(NR_GETRANDOM, buf.as_mut_ptr(), buf.len(), GRND_NONBLOCK)` // is called if a `HashMap` is created the regular way (e.g. HashMap). @@ -103,7 +115,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // instead of using `stat`,`lstat` or `fstat` as on `macos`. id if id == sys_statx => { // The first argument is the syscall id, so skip over it. - let result = this.linux_statx(args[1], args[2], args[3], args[4], args[5])?; + let &[_, dirfd, pathname, flags, mask, statxbuf] = check_arg_count(args)?; + let result = this.linux_statx(dirfd, pathname, flags, mask, statxbuf)?; this.write_scalar(Scalar::from_machine_isize(result.into(), this), dest)?; } id => throw_unsup_format!("miri does not support syscall ID {}", id), @@ -115,9 +128,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx getrandom(this, args, dest)?; } "sched_getaffinity" => { - let _pid = this.read_scalar(args[0])?.to_i32()?; - let _cpusetsize = this.read_scalar(args[1])?.to_machine_usize(this)?; - let _mask = this.deref_operand(args[2])?; + let &[_pid, _cpusetsize, _mask] = check_arg_count(args)?; + let _pid = this.read_scalar(_pid)?.to_i32()?; + let _cpusetsize = this.read_scalar(_cpusetsize)?.to_machine_usize(this)?; + let _mask = this.deref_operand(_mask)?; // FIXME: we just return an error; `num_cpus` then falls back to `sysconf`. let einval = this.eval_libc("EINVAL")?; this.set_last_error(einval)?; @@ -143,12 +157,13 @@ fn getrandom<'tcx>( args: &[OpTy<'tcx, Tag>], dest: PlaceTy<'tcx, Tag>, ) -> InterpResult<'tcx> { - let ptr = this.read_scalar(args[0])?.not_undef()?; - let len = this.read_scalar(args[1])?.to_machine_usize(this)?; + let &[ptr, len, _flags] = check_arg_count(args)?; + let ptr = this.read_scalar(ptr)?.not_undef()?; + let len = this.read_scalar(len)?.to_machine_usize(this)?; // The only supported flags are GRND_RANDOM and GRND_NONBLOCK, // neither of which have any effect on our current PRNG. - let _flags = this.read_scalar(args[2])?.to_i32()?; + let _flags = this.read_scalar(_flags)?.to_i32()?; this.gen_random(ptr, len)?; this.write_scalar(Scalar::from_machine_usize(len, this), dest)?; diff --git a/src/shims/foreign_items/posix/macos.rs b/src/shims/foreign_items/posix/macos.rs index 3677960fd8777..e9fd3aa8ac81e 100644 --- a/src/shims/foreign_items/posix/macos.rs +++ b/src/shims/foreign_items/posix/macos.rs @@ -1,4 +1,5 @@ use crate::*; +use helpers::check_arg_count; use rustc_middle::mir; impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} @@ -15,85 +16,102 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx match link_name { // errno "__error" => { + let &[] = check_arg_count(args)?; let errno_place = this.machine.last_error.unwrap(); this.write_scalar(errno_place.to_ref().to_scalar()?, dest)?; } // File related shims "close$NOCANCEL" => { - let result = this.close(args[0])?; + let &[result] = check_arg_count(args)?; + let result = this.close(result)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "stat$INODE64" => { - let result = this.macos_stat(args[0], args[1])?; + let &[path, buf] = check_arg_count(args)?; + let result = this.macos_stat(path, buf)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "lstat$INODE64" => { - let result = this.macos_lstat(args[0], args[1])?; + let &[path, buf] = check_arg_count(args)?; + let result = this.macos_lstat(path, buf)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "fstat$INODE64" => { - let result = this.macos_fstat(args[0], args[1])?; + let &[fd, buf] = check_arg_count(args)?; + let result = this.macos_fstat(fd, buf)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "opendir$INODE64" => { - let result = this.opendir(args[0])?; + let &[name] = check_arg_count(args)?; + let result = this.opendir(name)?; this.write_scalar(result, dest)?; } "readdir_r$INODE64" => { - let result = this.macos_readdir_r(args[0], args[1], args[2])?; + let &[dirp, entry, result] = check_arg_count(args)?; + let result = this.macos_readdir_r(dirp, entry, result)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "ftruncate" => { - let result = this.ftruncate64(args[0], args[1])?; + let &[fd, length] = check_arg_count(args)?; + let result = this.ftruncate64(fd, length)?; this.write_scalar(Scalar::from_i32(result), dest)?; } // Environment related shims "_NSGetEnviron" => { + let &[] = check_arg_count(args)?; this.write_scalar(this.machine.env_vars.environ.unwrap().ptr, dest)?; } // Time related shims "gettimeofday" => { - let result = this.gettimeofday(args[0], args[1])?; + let &[tv, tz] = check_arg_count(args)?; + let result = this.gettimeofday(tv, tz)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "mach_absolute_time" => { + let &[] = check_arg_count(args)?; let result = this.mach_absolute_time()?; this.write_scalar(Scalar::from_u64(result), dest)?; } "mach_timebase_info" => { - let result = this.mach_timebase_info(args[0])?; + let &[info] = check_arg_count(args)?; + let result = this.mach_timebase_info(info)?; this.write_scalar(Scalar::from_i32(result), dest)?; }, // Access to command-line arguments "_NSGetArgc" => { + let &[] = check_arg_count(args)?; this.write_scalar(this.machine.argc.expect("machine must be initialized"), dest)?; } "_NSGetArgv" => { + let &[] = check_arg_count(args)?; this.write_scalar(this.machine.argv.expect("machine must be initialized"), dest)?; } // Thread-local storage "_tlv_atexit" => { - let dtor = this.read_scalar(args[0])?.not_undef()?; + let &[dtor, data] = check_arg_count(args)?; + let dtor = this.read_scalar(dtor)?.not_undef()?; let dtor = this.memory.get_fn(dtor)?.as_instance()?; - let data = this.read_scalar(args[1])?.not_undef()?; + let data = this.read_scalar(data)?.not_undef()?; let active_thread = this.get_active_thread()?; this.machine.tls.set_macos_thread_dtor(active_thread, dtor, data)?; } // Querying system information "pthread_get_stackaddr_np" => { - let _thread = this.read_scalar(args[0])?.not_undef()?; + let &[_thread] = check_arg_count(args)?; + let _thread = this.read_scalar(_thread)?.not_undef()?; let stack_addr = Scalar::from_uint(STACK_ADDR, this.pointer_size()); this.write_scalar(stack_addr, dest)?; } "pthread_get_stacksize_np" => { - let _thread = this.read_scalar(args[0])?.not_undef()?; + let &[_thread] = check_arg_count(args)?; + let _thread = this.read_scalar(_thread)?.not_undef()?; let stack_size = Scalar::from_uint(STACK_SIZE, this.pointer_size()); this.write_scalar(stack_size, dest)?; } @@ -108,7 +126,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // These shims are enabled only when the caller is in the standard library. "mmap" if this.frame().instance.to_string().starts_with("std::sys::unix::") => { // This is a horrible hack, but since the guard page mechanism calls mmap and expects a particular return value, we just give it that value. - let addr = this.read_scalar(args[0])?.not_undef()?; + let &[addr, _, _, _, _, _] = check_arg_count(args)?; + let addr = this.read_scalar(addr)?.not_undef()?; this.write_scalar(addr, dest)?; } diff --git a/src/shims/foreign_items/windows.rs b/src/shims/foreign_items/windows.rs index f55b5b8450e04..9edd20ddcab19 100644 --- a/src/shims/foreign_items/windows.rs +++ b/src/shims/foreign_items/windows.rs @@ -4,6 +4,7 @@ use rustc_middle::mir; use rustc_target::abi::Size; use crate::*; +use helpers::check_arg_count; impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { @@ -23,42 +24,50 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx match link_name { // Environment related shims "GetEnvironmentVariableW" => { - let result = this.GetEnvironmentVariableW(args[0], args[1], args[2])?; + let &[name, buf, size] = check_arg_count(args)?; + let result = this.GetEnvironmentVariableW(name, buf, size)?; this.write_scalar(Scalar::from_u32(result), dest)?; } "SetEnvironmentVariableW" => { - let result = this.SetEnvironmentVariableW(args[0], args[1])?; + let &[name, value] = check_arg_count(args)?; + let result = this.SetEnvironmentVariableW(name, value)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "GetEnvironmentStringsW" => { + let &[] = check_arg_count(args)?; let result = this.GetEnvironmentStringsW()?; this.write_scalar(result, dest)?; } "FreeEnvironmentStringsW" => { - let result = this.FreeEnvironmentStringsW(args[0])?; + let &[env_block] = check_arg_count(args)?; + let result = this.FreeEnvironmentStringsW(env_block)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "GetCurrentDirectoryW" => { - let result = this.GetCurrentDirectoryW(args[0], args[1])?; + let &[size, buf] = check_arg_count(args)?; + let result = this.GetCurrentDirectoryW(size, buf)?; this.write_scalar(Scalar::from_u32(result), dest)?; } "SetCurrentDirectoryW" => { - let result = this.SetCurrentDirectoryW(args[0])?; + let &[path] = check_arg_count(args)?; + let result = this.SetCurrentDirectoryW(path)?; this.write_scalar(Scalar::from_i32(result), dest)?; } // File related shims "GetStdHandle" => { - let which = this.read_scalar(args[0])?.to_i32()?; + let &[which] = check_arg_count(args)?; + let which = this.read_scalar(which)?.to_i32()?; // We just make this the identity function, so we know later in `WriteFile` // which one it is. this.write_scalar(Scalar::from_machine_isize(which.into(), this), dest)?; } "WriteFile" => { - let handle = this.read_scalar(args[0])?.to_machine_isize(this)?; - let buf = this.read_scalar(args[1])?.not_undef()?; - let n = this.read_scalar(args[2])?.to_u32()?; - let written_place = this.deref_operand(args[3])?; + let &[handle, buf, n, written_ptr, _overlapped] = check_arg_count(args)?; + let handle = this.read_scalar(handle)?.to_machine_isize(this)?; + let buf = this.read_scalar(buf)?.not_undef()?; + let n = this.read_scalar(n)?.to_u32()?; + let written_place = this.deref_operand(written_ptr)?; // Spec says to always write `0` first. this.write_null(written_place.into())?; let written = if handle == -11 || handle == -12 { @@ -88,41 +97,48 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Allocation "HeapAlloc" => { - let _handle = this.read_scalar(args[0])?.to_machine_isize(this)?; - let flags = this.read_scalar(args[1])?.to_u32()?; - let size = this.read_scalar(args[2])?.to_machine_usize(this)?; + let &[_handle, flags, size] = check_arg_count(args)?; + let _handle = this.read_scalar(_handle)?.to_machine_isize(this)?; + let flags = this.read_scalar(flags)?.to_u32()?; + let size = this.read_scalar(size)?.to_machine_usize(this)?; let zero_init = (flags & 0x00000008) != 0; // HEAP_ZERO_MEMORY let res = this.malloc(size, zero_init, MiriMemoryKind::WinHeap); this.write_scalar(res, dest)?; } "HeapFree" => { - let _handle = this.read_scalar(args[0])?.to_machine_isize(this)?; - let _flags = this.read_scalar(args[1])?.to_u32()?; - let ptr = this.read_scalar(args[2])?.not_undef()?; + let &[_handle, _flags, ptr] = check_arg_count(args)?; + let _handle = this.read_scalar(_handle)?.to_machine_isize(this)?; + let _flags = this.read_scalar(_flags)?.to_u32()?; + let ptr = this.read_scalar(ptr)?.not_undef()?; this.free(ptr, MiriMemoryKind::WinHeap)?; this.write_scalar(Scalar::from_i32(1), dest)?; } "HeapReAlloc" => { - let _handle = this.read_scalar(args[0])?.to_machine_isize(this)?; - let _flags = this.read_scalar(args[1])?.to_u32()?; - let ptr = this.read_scalar(args[2])?.not_undef()?; - let size = this.read_scalar(args[3])?.to_machine_usize(this)?; + let &[_handle, _flags, ptr, size] = check_arg_count(args)?; + let _handle = this.read_scalar(_handle)?.to_machine_isize(this)?; + let _flags = this.read_scalar(_flags)?.to_u32()?; + let ptr = this.read_scalar(ptr)?.not_undef()?; + let size = this.read_scalar(size)?.to_machine_usize(this)?; let res = this.realloc(ptr, size, MiriMemoryKind::WinHeap)?; this.write_scalar(res, dest)?; } // errno "SetLastError" => { - this.set_last_error(this.read_scalar(args[0])?.not_undef()?)?; + let &[error] = check_arg_count(args)?; + let error = this.read_scalar(error)?.not_undef()?; + this.set_last_error(error)?; } "GetLastError" => { + let &[] = check_arg_count(args)?; let last_error = this.get_last_error()?; this.write_scalar(last_error, dest)?; } // Querying system information "GetSystemInfo" => { - let system_info = this.deref_operand(args[0])?; + let &[system_info] = check_arg_count(args)?; + let system_info = this.deref_operand(system_info)?; // Initialize with `0`. this.memory.write_bytes( system_info.ptr, @@ -139,19 +155,22 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // This just creates a key; Windows does not natively support TLS destructors. // Create key and return it. + let &[] = check_arg_count(args)?; let key = this.machine.tls.create_tls_key(None, dest.layout.size)?; this.write_scalar(Scalar::from_uint(key, dest.layout.size), dest)?; } "TlsGetValue" => { - let key = u128::from(this.read_scalar(args[0])?.to_u32()?); + let &[key] = check_arg_count(args)?; + let key = u128::from(this.read_scalar(key)?.to_u32()?); let active_thread = this.get_active_thread()?; let ptr = this.machine.tls.load_tls(key, active_thread, this)?; this.write_scalar(ptr, dest)?; } "TlsSetValue" => { - let key = u128::from(this.read_scalar(args[0])?.to_u32()?); + let &[key, new_ptr] = check_arg_count(args)?; + let key = u128::from(this.read_scalar(key)?.to_u32()?); let active_thread = this.get_active_thread()?; - let new_ptr = this.read_scalar(args[1])?.not_undef()?; + let new_ptr = this.read_scalar(new_ptr)?.not_undef()?; this.machine.tls.store_tls(key, active_thread, this.test_null(new_ptr)?)?; // Return success (`1`). @@ -160,6 +179,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Access to command-line arguments "GetCommandLineW" => { + let &[] = check_arg_count(args)?; this.write_scalar( this.machine.cmd_line.expect("machine must be initialized"), dest, @@ -168,42 +188,52 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Time related shims "GetSystemTimeAsFileTime" => { - this.GetSystemTimeAsFileTime(args[0])?; + #[allow(non_snake_case)] + let &[LPFILETIME] = check_arg_count(args)?; + this.GetSystemTimeAsFileTime(LPFILETIME)?; } "QueryPerformanceCounter" => { - let result = this.QueryPerformanceCounter(args[0])?; + #[allow(non_snake_case)] + let &[lpPerformanceCount] = check_arg_count(args)?; + let result = this.QueryPerformanceCounter(lpPerformanceCount)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "QueryPerformanceFrequency" => { - let result = this.QueryPerformanceFrequency(args[0])?; + #[allow(non_snake_case)] + let &[lpFrequency] = check_arg_count(args)?; + let result = this.QueryPerformanceFrequency(lpFrequency)?; this.write_scalar(Scalar::from_i32(result), dest)?; } // Miscellaneous "SystemFunction036" => { // The actual name of 'RtlGenRandom' - let ptr = this.read_scalar(args[0])?.not_undef()?; - let len = this.read_scalar(args[1])?.to_u32()?; + let &[ptr, len] = check_arg_count(args)?; + let ptr = this.read_scalar(ptr)?.not_undef()?; + let len = this.read_scalar(len)?.to_u32()?; this.gen_random(ptr, len.into())?; this.write_scalar(Scalar::from_bool(true), dest)?; } "GetConsoleScreenBufferInfo" => { // `term` needs this, so we fake it. - let _console = this.read_scalar(args[0])?.to_machine_isize(this)?; - let _buffer_info = this.deref_operand(args[1])?; + let &[_console, _buffer_info] = check_arg_count(args)?; + let _console = this.read_scalar(_console)?.to_machine_isize(this)?; + let _buffer_info = this.deref_operand(_buffer_info)?; // Indicate an error. // FIXME: we should set last_error, but to what? this.write_null(dest)?; } "GetConsoleMode" => { // Windows "isatty" (in libtest) needs this, so we fake it. - let _console = this.read_scalar(args[0])?.to_machine_isize(this)?; - let _mode = this.deref_operand(args[1])?; + let &[_console, _mode] = check_arg_count(args)?; + let _console = this.read_scalar(_console)?.to_machine_isize(this)?; + let _mode = this.deref_operand(_mode)?; // Indicate an error. // FIXME: we should set last_error, but to what? this.write_null(dest)?; } "SwitchToThread" => { + let &[] = check_arg_count(args)?; // Note that once Miri supports concurrency, this will need to return a nonzero // value if this call does result in switching to another thread. this.write_null(dest)?; @@ -217,17 +247,34 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Incomplete shims that we "stub out" just to get pre-main initialization code to work. // These shims are enabled only when the caller is in the standard library. "GetProcessHeap" if this.frame().instance.to_string().starts_with("std::sys::windows::") => { + let &[] = check_arg_count(args)?; // Just fake a HANDLE this.write_scalar(Scalar::from_machine_isize(1, this), dest)?; } - | "GetModuleHandleW" - | "GetProcAddress" - | "SetConsoleTextAttribute" if this.frame().instance.to_string().starts_with("std::sys::windows::") + "GetModuleHandleW" if this.frame().instance.to_string().starts_with("std::sys::windows::") => { - // Pretend these do not exist / nothing happened, by returning zero. + #[allow(non_snake_case)] + let &[_lpModuleName] = check_arg_count(args)?; + // Pretend this does not exist / nothing happened, by returning zero. + this.write_null(dest)?; + } + "GetProcAddress" if this.frame().instance.to_string().starts_with("std::sys::windows::") + => { + #[allow(non_snake_case)] + let &[_hModule, _lpProcName] = check_arg_count(args)?; + // Pretend this does not exist / nothing happened, by returning zero. + this.write_null(dest)?; + } + "SetConsoleTextAttribute" if this.frame().instance.to_string().starts_with("std::sys::windows::") + => { + #[allow(non_snake_case)] + let &[_hConsoleOutput, _wAttribute] = check_arg_count(args)?; + // Pretend these does not exist / nothing happened, by returning zero. this.write_null(dest)?; } "AddVectoredExceptionHandler" if this.frame().instance.to_string().starts_with("std::sys::windows::") => { + #[allow(non_snake_case)] + let &[_First, _Handler] = check_arg_count(args)?; // Any non zero value works for the stdlib. This is just used for stack overflows anyway. this.write_scalar(Scalar::from_machine_usize(1, this), dest)?; } @@ -236,6 +283,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "LeaveCriticalSection" | "DeleteCriticalSection" if this.frame().instance.to_string().starts_with("std::sys::windows::") => { + #[allow(non_snake_case)] + let &[_lpCriticalSection] = check_arg_count(args)?; assert_eq!(this.get_total_thread_count()?, 1, "concurrency on Windows not supported"); // Nothing to do, not even a return value. // (Windows locks are reentrant, and we have only 1 thread, @@ -243,6 +292,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "TryEnterCriticalSection" if this.frame().instance.to_string().starts_with("std::sys::windows::") => { + #[allow(non_snake_case)] + let &[_lpCriticalSection] = check_arg_count(args)?; assert_eq!(this.get_total_thread_count()?, 1, "concurrency on Windows not supported"); // There is only one thread, so this always succeeds and returns TRUE this.write_scalar(Scalar::from_i32(1), dest)?; diff --git a/src/shims/fs.rs b/src/shims/fs.rs index ea0b998c2e3dc..b9bb0fadf1a4b 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -10,7 +10,7 @@ use rustc_target::abi::{Align, LayoutOf, Size}; use crate::stacked_borrows::Tag; use crate::*; -use helpers::{immty_from_int_checked, immty_from_uint_checked}; +use helpers::{check_arg_count, immty_from_int_checked, immty_from_uint_checked}; use shims::time::system_time_to_duration; #[derive(Debug)] @@ -322,16 +322,22 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn fcntl( &mut self, - fd_op: OpTy<'tcx, Tag>, - cmd_op: OpTy<'tcx, Tag>, - start_op: Option>, + args: &[OpTy<'tcx, Tag>], ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); this.check_no_isolation("fcntl")?; - let fd = this.read_scalar(fd_op)?.to_i32()?; - let cmd = this.read_scalar(cmd_op)?.to_i32()?; + let (fd, cmd, start) = if args.len() == 2 { + let &[fd, cmd] = check_arg_count(args)?; + (fd, cmd, None) + } else { + // If args.len() isn't 2 or 3 this will error appropriately. + let &[fd, cmd, start] = check_arg_count(args)?; + (fd, cmd, Some(start)) + }; + let fd = this.read_scalar(fd)?.to_i32()?; + let cmd = this.read_scalar(cmd)?.to_i32()?; // We only support getting the flags for a descriptor. if cmd == this.eval_libc_i32("F_GETFD")? { // Currently this is the only flag that `F_GETFD` returns. It is OK to just return the @@ -353,12 +359,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if fd < MIN_NORMAL_FILE_FD { throw_unsup_format!("duplicating file descriptors for stdin, stdout, or stderr is not supported") } - let start_op = start_op.ok_or_else(|| { + let start = start.ok_or_else(|| { err_unsup_format!( "fcntl with command F_DUPFD or F_DUPFD_CLOEXEC requires a third argument" ) })?; - let start = this.read_scalar(start_op)?.to_i32()?; + let start = this.read_scalar(start)?.to_i32()?; let fh = &mut this.machine.file_handler; let (file_result, writable) = match fh.handles.get(&fd) { Some(FileHandle { file, writable }) => (file.try_clone(), *writable), @@ -1064,7 +1070,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } fn ftruncate64( - &mut self, fd_op: OpTy<'tcx, Tag>, + &mut self, + fd_op: OpTy<'tcx, Tag>, length_op: OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index b64aeef485ea4..a77443ef52247 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -7,6 +7,7 @@ use rustc_apfloat::{Float, Round}; use rustc_target::abi::{Align, LayoutOf, Size}; use crate::*; +use helpers::check_arg_count; impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { @@ -45,16 +46,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "copy" | "copy_nonoverlapping" => { + let &[src, dest, count] = check_arg_count(args)?; let elem_ty = substs.type_at(0); let elem_layout = this.layout_of(elem_ty)?; - let count = this.read_scalar(args[2])?.to_machine_usize(this)?; + let count = this.read_scalar(count)?.to_machine_usize(this)?; let elem_align = elem_layout.align.abi; let size = elem_layout.size.checked_mul(count, this) .ok_or_else(|| err_ub_format!("overflow computing total size of `{}`", intrinsic_name))?; - let src = this.read_scalar(args[0])?.not_undef()?; + let src = this.read_scalar(src)?.not_undef()?; let src = this.memory.check_ptr_access(src, size, elem_align)?; - let dest = this.read_scalar(args[1])?.not_undef()?; + let dest = this.read_scalar(dest)?.not_undef()?; let dest = this.memory.check_ptr_access(dest, size, elem_align)?; if let (Some(src), Some(dest)) = (src, dest) { @@ -68,25 +70,29 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "move_val_init" => { - let place = this.deref_operand(args[0])?; - this.copy_op(args[1], place.into())?; + let &[place, dest] = check_arg_count(args)?; + let place = this.deref_operand(place)?; + this.copy_op(dest, place.into())?; } "volatile_load" => { - let place = this.deref_operand(args[0])?; + let &[place] = check_arg_count(args)?; + let place = this.deref_operand(place)?; this.copy_op(place.into(), dest)?; } "volatile_store" => { - let place = this.deref_operand(args[0])?; - this.copy_op(args[1], place.into())?; + let &[place, dest] = check_arg_count(args)?; + let place = this.deref_operand(place)?; + this.copy_op(dest, place.into())?; } "write_bytes" => { + let &[ptr, val_byte, count] = check_arg_count(args)?; let ty = substs.type_at(0); let ty_layout = this.layout_of(ty)?; - let val_byte = this.read_scalar(args[1])?.to_u8()?; - let ptr = this.read_scalar(args[0])?.not_undef()?; - let count = this.read_scalar(args[2])?.to_machine_usize(this)?; + let val_byte = this.read_scalar(val_byte)?.to_u8()?; + let ptr = this.read_scalar(ptr)?.not_undef()?; + let count = this.read_scalar(count)?.to_machine_usize(this)?; let byte_count = ty_layout.size.checked_mul(count, this) .ok_or_else(|| err_ub_format!("overflow computing total size of `write_bytes`"))?; this.memory @@ -95,8 +101,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Pointer arithmetic "arith_offset" => { - let offset = this.read_scalar(args[1])?.to_machine_isize(this)?; - let ptr = this.read_scalar(args[0])?.not_undef()?; + let &[ptr, offset] = check_arg_count(args)?; + let ptr = this.read_scalar(ptr)?.not_undef()?; + let offset = this.read_scalar(offset)?.to_machine_isize(this)?; let pointee_ty = substs.type_at(0); let pointee_size = i64::try_from(this.layout_of(pointee_ty)?.size.bytes()).unwrap(); @@ -105,8 +112,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(result_ptr, dest)?; } "offset" => { - let offset = this.read_scalar(args[1])?.to_machine_isize(this)?; - let ptr = this.read_scalar(args[0])?.not_undef()?; + let &[ptr, offset] = check_arg_count(args)?; + let ptr = this.read_scalar(ptr)?.not_undef()?; + let offset = this.read_scalar(offset)?.to_machine_isize(this)?; let result_ptr = this.pointer_offset_inbounds(ptr, substs.type_at(0), offset)?; this.write_scalar(result_ptr, dest)?; } @@ -127,8 +135,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "truncf32" | "roundf32" => { + let &[f] = check_arg_count(args)?; // FIXME: Using host floats. - let f = f32::from_bits(this.read_scalar(args[0])?.to_u32()?); + let f = f32::from_bits(this.read_scalar(f)?.to_u32()?); let f = match intrinsic_name { "sinf32" => f.sin(), "fabsf32" => f.abs(), @@ -163,8 +172,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "truncf64" | "roundf64" => { + let &[f] = check_arg_count(args)?; // FIXME: Using host floats. - let f = f64::from_bits(this.read_scalar(args[0])?.to_u64()?); + let f = f64::from_bits(this.read_scalar(f)?.to_u64()?); let f = match intrinsic_name { "sinf64" => f.sin(), "fabsf64" => f.abs(), @@ -191,8 +201,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "fdiv_fast" | "frem_fast" => { - let a = this.read_immediate(args[0])?; - let b = this.read_immediate(args[1])?; + let &[a, b] = check_arg_count(args)?; + let a = this.read_immediate(a)?; + let b = this.read_immediate(b)?; let op = match intrinsic_name { "fadd_fast" => mir::BinOp::Add, "fsub_fast" => mir::BinOp::Sub, @@ -209,8 +220,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "maxnumf32" | "copysignf32" => { - let a = this.read_scalar(args[0])?.to_f32()?; - let b = this.read_scalar(args[1])?.to_f32()?; + let &[a, b] = check_arg_count(args)?; + let a = this.read_scalar(a)?.to_f32()?; + let b = this.read_scalar(b)?.to_f32()?; let res = match intrinsic_name { "minnumf32" => a.min(b), "maxnumf32" => a.max(b), @@ -225,8 +237,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "maxnumf64" | "copysignf64" => { - let a = this.read_scalar(args[0])?.to_f64()?; - let b = this.read_scalar(args[1])?.to_f64()?; + let &[a, b] = check_arg_count(args)?; + let a = this.read_scalar(a)?.to_f64()?; + let b = this.read_scalar(b)?.to_f64()?; let res = match intrinsic_name { "minnumf64" => a.min(b), "maxnumf64" => a.max(b), @@ -235,53 +248,60 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx }; this.write_scalar(Scalar::from_f64(res), dest)?; } - + "powf32" => { + let &[f, f2] = check_arg_count(args)?; // FIXME: Using host floats. - let f = f32::from_bits(this.read_scalar(args[0])?.to_u32()?); - let f2 = f32::from_bits(this.read_scalar(args[1])?.to_u32()?); + let f = f32::from_bits(this.read_scalar(f)?.to_u32()?); + let f2 = f32::from_bits(this.read_scalar(f2)?.to_u32()?); this.write_scalar(Scalar::from_u32(f.powf(f2).to_bits()), dest)?; } "powf64" => { + let &[f, f2] = check_arg_count(args)?; // FIXME: Using host floats. - let f = f64::from_bits(this.read_scalar(args[0])?.to_u64()?); - let f2 = f64::from_bits(this.read_scalar(args[1])?.to_u64()?); + let f = f64::from_bits(this.read_scalar(f)?.to_u64()?); + let f2 = f64::from_bits(this.read_scalar(f2)?.to_u64()?); this.write_scalar(Scalar::from_u64(f.powf(f2).to_bits()), dest)?; } "fmaf32" => { - let a = this.read_scalar(args[0])?.to_f32()?; - let b = this.read_scalar(args[1])?.to_f32()?; - let c = this.read_scalar(args[2])?.to_f32()?; + let &[a, b, c] = check_arg_count(args)?; + let a = this.read_scalar(a)?.to_f32()?; + let b = this.read_scalar(b)?.to_f32()?; + let c = this.read_scalar(c)?.to_f32()?; let res = a.mul_add(b, c).value; this.write_scalar(Scalar::from_f32(res), dest)?; } "fmaf64" => { - let a = this.read_scalar(args[0])?.to_f64()?; - let b = this.read_scalar(args[1])?.to_f64()?; - let c = this.read_scalar(args[2])?.to_f64()?; + let &[a, b, c] = check_arg_count(args)?; + let a = this.read_scalar(a)?.to_f64()?; + let b = this.read_scalar(b)?.to_f64()?; + let c = this.read_scalar(c)?.to_f64()?; let res = a.mul_add(b, c).value; this.write_scalar(Scalar::from_f64(res), dest)?; } "powif32" => { + let &[f, i] = check_arg_count(args)?; // FIXME: Using host floats. - let f = f32::from_bits(this.read_scalar(args[0])?.to_u32()?); - let i = this.read_scalar(args[1])?.to_i32()?; + let f = f32::from_bits(this.read_scalar(f)?.to_u32()?); + let i = this.read_scalar(i)?.to_i32()?; this.write_scalar(Scalar::from_u32(f.powi(i).to_bits()), dest)?; } "powif64" => { + let &[f, i] = check_arg_count(args)?; // FIXME: Using host floats. - let f = f64::from_bits(this.read_scalar(args[0])?.to_u64()?); - let i = this.read_scalar(args[1])?.to_i32()?; + let f = f64::from_bits(this.read_scalar(f)?.to_u64()?); + let i = this.read_scalar(i)?.to_i32()?; this.write_scalar(Scalar::from_u64(f.powi(i).to_bits()), dest)?; } "float_to_int_unchecked" => { - let val = this.read_immediate(args[0])?; + let &[val] = check_arg_count(args)?; + let val = this.read_immediate(val)?; let res = match val.layout.ty.kind { ty::Float(FloatTy::F32) => { @@ -302,7 +322,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "atomic_load_relaxed" | "atomic_load_acq" => { - let place = this.deref_operand(args[0])?; + let &[place] = check_arg_count(args)?; + let place = this.deref_operand(place)?; let val = this.read_scalar(place.into())?; // make sure it fits into a scalar; otherwise it cannot be atomic // Check alignment requirements. Atomics must always be aligned to their size, @@ -319,8 +340,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "atomic_store_relaxed" | "atomic_store_rel" => { - let place = this.deref_operand(args[0])?; - let val = this.read_scalar(args[1])?; // make sure it fits into a scalar; otherwise it cannot be atomic + let &[place, val] = check_arg_count(args)?; + let place = this.deref_operand(place)?; + let val = this.read_scalar(val)?; // make sure it fits into a scalar; otherwise it cannot be atomic // Check alignment requirements. Atomics must always be aligned to their size, // even if the type they wrap would be less aligned (e.g. AtomicU64 on 32bit must @@ -345,8 +367,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } _ if intrinsic_name.starts_with("atomic_xchg") => { - let place = this.deref_operand(args[0])?; - let new = this.read_scalar(args[1])?; + let &[place, new] = check_arg_count(args)?; + let place = this.deref_operand(place)?; + let new = this.read_scalar(new)?; let old = this.read_scalar(place.into())?; // Check alignment requirements. Atomics must always be aligned to their size, @@ -360,9 +383,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } _ if intrinsic_name.starts_with("atomic_cxchg") => { - let place = this.deref_operand(args[0])?; - let expect_old = this.read_immediate(args[1])?; // read as immediate for the sake of `binary_op()` - let new = this.read_scalar(args[2])?; + let &[place, expect_old, new] = check_arg_count(args)?; + let place = this.deref_operand(place)?; + let expect_old = this.read_immediate(expect_old)?; // read as immediate for the sake of `binary_op()` + let new = this.read_scalar(new)?; let old = this.read_immediate(place.into())?; // read as immediate for the sake of `binary_op()` // Check alignment requirements. Atomics must always be aligned to their size, @@ -414,11 +438,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "atomic_xsub_acqrel" | "atomic_xsub_relaxed" => { - let place = this.deref_operand(args[0])?; + let &[place, rhs] = check_arg_count(args)?; + let place = this.deref_operand(place)?; if !place.layout.ty.is_integral() { bug!("Atomic arithmetic operations only work on integer types"); } - let rhs = this.read_immediate(args[1])?; + let rhs = this.read_immediate(rhs)?; let old = this.read_immediate(place.into())?; // Check alignment requirements. Atomics must always be aligned to their size, @@ -447,6 +472,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "assert_inhabited" | "assert_zero_valid" | "assert_uninit_valid" => { + let &[] = check_arg_count(args)?; let ty = substs.type_at(0); let layout = this.layout_of(ty)?; // Abort here because the caller might not be panic safe. @@ -462,7 +488,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "min_align_of_val" => { - let mplace = this.deref_operand(args[0])?; + let &[mplace] = check_arg_count(args)?; + let mplace = this.deref_operand(mplace)?; let (_, align) = this .size_and_align_of_mplace(mplace)? .expect("size_of_val called on extern type"); @@ -470,7 +497,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "size_of_val" => { - let mplace = this.deref_operand(args[0])?; + let &[mplace] = check_arg_count(args)?; + let mplace = this.deref_operand(mplace)?; let (size, _) = this .size_and_align_of_mplace(mplace)? .expect("size_of_val called on extern type"); @@ -479,17 +507,21 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Other "assume" => { - let cond = this.read_scalar(args[0])?.to_bool()?; + let &[cond] = check_arg_count(args)?; + let cond = this.read_scalar(cond)?.not_undef()?.to_bool()?; if !cond { throw_ub_format!("`assume` intrinsic called with `false`"); } } - "exact_div" => - this.exact_div(this.read_immediate(args[0])?, this.read_immediate(args[1])?, dest)?, + "exact_div" => { + let &[num, denom] = check_arg_count(args)?; + this.exact_div(this.read_immediate(num)?, this.read_immediate(denom)?, dest)?; + } "forget" => { // We get an argument... and forget about it. + let &[_] = check_arg_count(args)?; } #[rustfmt::skip] @@ -497,7 +529,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "unlikely" => { // These just return their argument - let b = this.read_immediate(args[0])?; + let &[b] = check_arg_count(args)?; + let b = this.read_immediate(b)?; this.write_immediate(*b, dest)?; } diff --git a/src/shims/mod.rs b/src/shims/mod.rs index 166d1a5456df1..cd525e173ed70 100644 --- a/src/shims/mod.rs +++ b/src/shims/mod.rs @@ -17,6 +17,7 @@ use log::trace; use rustc_middle::{mir, ty}; use crate::*; +use helpers::check_arg_count; impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { @@ -32,7 +33,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // There are some more lang items we want to hook that CTFE does not hook (yet). if this.tcx.lang_items().align_offset_fn() == Some(instance.def.def_id()) { - this.align_offset(args[0], args[1], ret, unwind)?; + let &[ptr, align] = check_arg_count(args)?; + this.align_offset(ptr, align, ret, unwind)?; return Ok(None); } diff --git a/src/shims/panic.rs b/src/shims/panic.rs index c926046a04423..43f90f1b04f73 100644 --- a/src/shims/panic.rs +++ b/src/shims/panic.rs @@ -17,6 +17,7 @@ use rustc_middle::{mir, ty}; use rustc_target::spec::PanicStrategy; use crate::*; +use helpers::check_arg_count; /// Holds all of the relevant data for when unwinding hits a `try` frame. #[derive(Debug)] @@ -53,7 +54,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx trace!("miri_start_panic: {:?}", this.frame().instance); // Get the raw pointer stored in arg[0] (the panic payload). - let payload = this.read_scalar(args[0])?.not_undef()?; + let &[payload] = check_arg_count(args)?; + let payload = this.read_scalar(payload)?.not_undef()?; assert!( this.machine.panic_payload.is_none(), "the panic runtime should avoid double-panics" @@ -86,9 +88,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // a pointer to `Box`. // Get all the arguments. - let try_fn = this.read_scalar(args[0])?.not_undef()?; - let data = this.read_scalar(args[1])?.not_undef()?; - let catch_fn = this.read_scalar(args[2])?.not_undef()?; + let &[try_fn, data, catch_fn] = check_arg_count(args)?; + let try_fn = this.read_scalar(try_fn)?.not_undef()?; + let data = this.read_scalar(data)?.not_undef()?; + let catch_fn = this.read_scalar(catch_fn)?.not_undef()?; // Now we make a function call, and pass `data` as first and only argument. let f_instance = this.memory.get_fn(try_fn)?.as_instance()?; From 46aaab30fec9ba85ac086137109e66bf5557dd7e Mon Sep 17 00:00:00 2001 From: Chase Albert Date: Thu, 30 Apr 2020 17:30:21 -0400 Subject: [PATCH 2026/3747] Add a test for check_arg_count. --- tests/compile-fail/check_arg_count.rs | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 tests/compile-fail/check_arg_count.rs diff --git a/tests/compile-fail/check_arg_count.rs b/tests/compile-fail/check_arg_count.rs new file mode 100644 index 0000000000000..663fa60f72d7a --- /dev/null +++ b/tests/compile-fail/check_arg_count.rs @@ -0,0 +1,7 @@ +#![feature(core_intrinsics)] + +use std::intrinsics; + +fn main() { + unsafe { intrinsics::forget(); } //~ ERROR this function takes 1 argument but 0 arguments were supplied +} From 4d3dff2addc479d54e03bf41ff3fe6f6f0302fdc Mon Sep 17 00:00:00 2001 From: Chase Albert Date: Thu, 30 Apr 2020 17:30:27 -0400 Subject: [PATCH 2027/3747] Address consistency of naming for unused/merely validated arguments. --- src/shims/foreign_items/posix.rs | 18 ++++++------- src/shims/foreign_items/posix/linux.rs | 37 ++++++++++++++------------ src/shims/foreign_items/posix/macos.rs | 8 +++--- src/shims/foreign_items/windows.rs | 24 ++++++++--------- 4 files changed, 45 insertions(+), 42 deletions(-) diff --git a/src/shims/foreign_items/posix.rs b/src/shims/foreign_items/posix.rs index 4c50d5ddc5b8c..6b28e7070165b 100644 --- a/src/shims/foreign_items/posix.rs +++ b/src/shims/foreign_items/posix.rs @@ -56,7 +56,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_i32(result), dest)?; } "fcntl" => { - let result = this.fcntl(args); + let result = this.fcntl(args)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "read" => { @@ -168,8 +168,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Dynamic symbol loading "dlsym" => { - let &[_handle, symbol] = check_arg_count(args)?; - let _handle = this.read_scalar(_handle)?.not_undef()?; + let &[handle, symbol] = check_arg_count(args)?; + this.read_scalar(handle)?.not_undef()?; let symbol = this.read_scalar(symbol)?.not_undef()?; let symbol_name = this.memory.read_c_str(symbol)?; let err = format!("bad c unicode symbol: {:?}", symbol_name); @@ -360,8 +360,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Miscellaneous "isatty" => { - let &[_fd] = check_arg_count(args)?; - let _fd = this.read_scalar(_fd)?.to_i32()?; + let &[fd] = check_arg_count(args)?; + this.read_scalar(fd)?.to_i32()?; // "returns 1 if fd is an open file descriptor referring to a terminal; otherwise 0 is returned, and errno is set to indicate the error" // FIXME: we just say nothing is a terminal. let enotty = this.eval_libc("ENOTTY")?; @@ -369,10 +369,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_null(dest)?; } "pthread_atfork" => { - let &[_prepare, _parent, _child] = check_arg_count(args)?; - let _prepare = this.read_scalar(_prepare)?.not_undef()?; - let _parent = this.read_scalar(_parent)?.not_undef()?; - let _child = this.read_scalar(_child)?.not_undef()?; + let &[prepare, parent, child] = check_arg_count(args)?; + this.read_scalar(prepare)?.not_undef()?; + this.read_scalar(parent)?.not_undef()?; + this.read_scalar(child)?.not_undef()?; // We do not support forking, so there is nothing to do here. this.write_null(dest)?; } diff --git a/src/shims/foreign_items/posix/linux.rs b/src/shims/foreign_items/posix/linux.rs index b0f4a45f1c011..3f9d1b259a86a 100644 --- a/src/shims/foreign_items/posix/linux.rs +++ b/src/shims/foreign_items/posix/linux.rs @@ -46,11 +46,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // Linux-only "posix_fadvise" => { - let &[_fd, _offset, _len, _advice] = check_arg_count(args)?; - let _fd = this.read_scalar(_fd)?.to_i32()?; - let _offset = this.read_scalar(_offset)?.to_machine_isize(this)?; - let _len = this.read_scalar(_len)?.to_machine_isize(this)?; - let _advice = this.read_scalar(_advice)?.to_i32()?; + let &[fd, offset, len, advice] = check_arg_count(args)?; + this.read_scalar(fd)?.to_i32()?; + this.read_scalar(offset)?.to_machine_isize(this)?; + this.read_scalar(len)?.to_machine_isize(this)?; + this.read_scalar(advice)?.to_i32()?; // fadvise is only informational, we can ignore it. this.write_null(dest)?; } @@ -66,8 +66,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Querying system information "pthread_attr_getstack" => { // We don't support "pthread_attr_setstack", so we just pretend all stacks have the same values here. - let &[_attr_place, addr_place, size_place] = check_arg_count(args)?; - let _attr_place = this.deref_operand(_attr_place)?; + let &[attr_place, addr_place, size_place] = check_arg_count(args)?; + this.deref_operand(attr_place)?; let addr_place = this.deref_operand(addr_place)?; let size_place = this.deref_operand(size_place)?; @@ -102,14 +102,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx .to_machine_usize(this)?; if args.is_empty() { - throw_ub_format!("incorrect number of arguments, needed at least 1"); + throw_ub_format!("incorrect number of arguments for syscall, needed at least 1"); } match this.read_scalar(args[0])?.to_machine_usize(this)? { // `libc::syscall(NR_GETRANDOM, buf.as_mut_ptr(), buf.len(), GRND_NONBLOCK)` // is called if a `HashMap` is created the regular way (e.g. HashMap). id if id == sys_getrandom => { // The first argument is the syscall id, so skip over it. - getrandom(this, &args[1..], dest)?; + let &[_, ptr, len, flags] = check_arg_count(args)?; + getrandom(this, ptr, len, flags, dest)?; } // `statx` is used by `libstd` to retrieve metadata information on `linux` // instead of using `stat`,`lstat` or `fstat` as on `macos`. @@ -125,13 +126,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Miscelanneous "getrandom" => { - getrandom(this, args, dest)?; + let &[ptr, len, flags] = check_arg_count(args)?; + getrandom(this, ptr, len, flags, dest)?; } "sched_getaffinity" => { - let &[_pid, _cpusetsize, _mask] = check_arg_count(args)?; - let _pid = this.read_scalar(_pid)?.to_i32()?; - let _cpusetsize = this.read_scalar(_cpusetsize)?.to_machine_usize(this)?; - let _mask = this.deref_operand(_mask)?; + let &[pid, cpusetsize, mask] = check_arg_count(args)?; + this.read_scalar(pid)?.to_i32()?; + this.read_scalar(cpusetsize)?.to_machine_usize(this)?; + this.deref_operand(mask)?; // FIXME: we just return an error; `num_cpus` then falls back to `sysconf`. let einval = this.eval_libc("EINVAL")?; this.set_last_error(einval)?; @@ -154,16 +156,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Shims the linux `getrandom` syscall. fn getrandom<'tcx>( this: &mut MiriEvalContext<'_, 'tcx>, - args: &[OpTy<'tcx, Tag>], + ptr: OpTy<'tcx, Tag>, + len: OpTy<'tcx, Tag>, + flags: OpTy<'tcx, Tag>, dest: PlaceTy<'tcx, Tag>, ) -> InterpResult<'tcx> { - let &[ptr, len, _flags] = check_arg_count(args)?; let ptr = this.read_scalar(ptr)?.not_undef()?; let len = this.read_scalar(len)?.to_machine_usize(this)?; // The only supported flags are GRND_RANDOM and GRND_NONBLOCK, // neither of which have any effect on our current PRNG. - let _flags = this.read_scalar(_flags)?.to_i32()?; + this.read_scalar(flags)?.to_i32()?; this.gen_random(ptr, len)?; this.write_scalar(Scalar::from_machine_usize(len, this), dest)?; diff --git a/src/shims/foreign_items/posix/macos.rs b/src/shims/foreign_items/posix/macos.rs index e9fd3aa8ac81e..685f66d443d4f 100644 --- a/src/shims/foreign_items/posix/macos.rs +++ b/src/shims/foreign_items/posix/macos.rs @@ -104,14 +104,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Querying system information "pthread_get_stackaddr_np" => { - let &[_thread] = check_arg_count(args)?; - let _thread = this.read_scalar(_thread)?.not_undef()?; + let &[thread] = check_arg_count(args)?; + this.read_scalar(thread)?.not_undef()?; let stack_addr = Scalar::from_uint(STACK_ADDR, this.pointer_size()); this.write_scalar(stack_addr, dest)?; } "pthread_get_stacksize_np" => { - let &[_thread] = check_arg_count(args)?; - let _thread = this.read_scalar(_thread)?.not_undef()?; + let &[thread] = check_arg_count(args)?; + this.read_scalar(thread)?.not_undef()?; let stack_size = Scalar::from_uint(STACK_SIZE, this.pointer_size()); this.write_scalar(stack_size, dest)?; } diff --git a/src/shims/foreign_items/windows.rs b/src/shims/foreign_items/windows.rs index 9edd20ddcab19..3d7afc616e8ed 100644 --- a/src/shims/foreign_items/windows.rs +++ b/src/shims/foreign_items/windows.rs @@ -97,8 +97,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Allocation "HeapAlloc" => { - let &[_handle, flags, size] = check_arg_count(args)?; - let _handle = this.read_scalar(_handle)?.to_machine_isize(this)?; + let &[handle, flags, size] = check_arg_count(args)?; + this.read_scalar(handle)?.to_machine_isize(this)?; let flags = this.read_scalar(flags)?.to_u32()?; let size = this.read_scalar(size)?.to_machine_usize(this)?; let zero_init = (flags & 0x00000008) != 0; // HEAP_ZERO_MEMORY @@ -106,16 +106,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(res, dest)?; } "HeapFree" => { - let &[_handle, _flags, ptr] = check_arg_count(args)?; - let _handle = this.read_scalar(_handle)?.to_machine_isize(this)?; + let &[handle, _flags, ptr] = check_arg_count(args)?; + this.read_scalar(handle)?.to_machine_isize(this)?; let _flags = this.read_scalar(_flags)?.to_u32()?; let ptr = this.read_scalar(ptr)?.not_undef()?; this.free(ptr, MiriMemoryKind::WinHeap)?; this.write_scalar(Scalar::from_i32(1), dest)?; } "HeapReAlloc" => { - let &[_handle, _flags, ptr, size] = check_arg_count(args)?; - let _handle = this.read_scalar(_handle)?.to_machine_isize(this)?; + let &[handle, _flags, ptr, size] = check_arg_count(args)?; + this.read_scalar(handle)?.to_machine_isize(this)?; let _flags = this.read_scalar(_flags)?.to_u32()?; let ptr = this.read_scalar(ptr)?.not_undef()?; let size = this.read_scalar(size)?.to_machine_usize(this)?; @@ -216,18 +216,18 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "GetConsoleScreenBufferInfo" => { // `term` needs this, so we fake it. - let &[_console, _buffer_info] = check_arg_count(args)?; - let _console = this.read_scalar(_console)?.to_machine_isize(this)?; - let _buffer_info = this.deref_operand(_buffer_info)?; + let &[console, buffer_info] = check_arg_count(args)?; + this.read_scalar(console)?.to_machine_isize(this)?; + this.deref_operand(buffer_info)?; // Indicate an error. // FIXME: we should set last_error, but to what? this.write_null(dest)?; } "GetConsoleMode" => { // Windows "isatty" (in libtest) needs this, so we fake it. - let &[_console, _mode] = check_arg_count(args)?; - let _console = this.read_scalar(_console)?.to_machine_isize(this)?; - let _mode = this.deref_operand(_mode)?; + let &[console, mode] = check_arg_count(args)?; + this.read_scalar(console)?.to_machine_isize(this)?; + this.deref_operand(mode)?; // Indicate an error. // FIXME: we should set last_error, but to what? this.write_null(dest)?; From f46d1974313c83886508088ff1beac3a107c3790 Mon Sep 17 00:00:00 2001 From: Chase Albert Date: Thu, 30 Apr 2020 18:16:56 -0400 Subject: [PATCH 2028/3747] Test for too many args. --- tests/compile-fail/check_arg_count.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/compile-fail/check_arg_count.rs b/tests/compile-fail/check_arg_count.rs index 663fa60f72d7a..0cc6dcb9a98d0 100644 --- a/tests/compile-fail/check_arg_count.rs +++ b/tests/compile-fail/check_arg_count.rs @@ -4,4 +4,5 @@ use std::intrinsics; fn main() { unsafe { intrinsics::forget(); } //~ ERROR this function takes 1 argument but 0 arguments were supplied + unsafe { intrinsics::forget(1, 2); } //~ ERROR this function takes 1 argument but 2 arguments were supplied } From 4e3d1fee51a3a326c4146cb0986820ed129fce95 Mon Sep 17 00:00:00 2001 From: Chase Albert Date: Mon, 4 May 2020 14:24:22 -0400 Subject: [PATCH 2029/3747] Address comments. --- src/helpers.rs | 2 +- src/shims/foreign_items.rs | 1 + src/shims/foreign_items/posix/linux.rs | 3 ++- src/shims/foreign_items/posix/macos.rs | 5 +++-- src/shims/foreign_items/windows.rs | 8 ++++---- src/shims/fs.rs | 25 +++++++++---------------- src/shims/thread.rs | 4 ++-- 7 files changed, 22 insertions(+), 26 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index 43a20d290c80f..510efe4660880 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -477,7 +477,7 @@ pub fn check_arg_count<'a, 'tcx, const N: usize>(args: &'a [OpTy<'tcx, Tag>]) -> if let Ok(ops) = args.try_into() { return Ok(ops); } - throw_ub_format!("incorrect number of arguments, got {}, needed {}", args.len(), N) + throw_ub_format!("incorrect number of arguments: got {}, expected {}", args.len(), N) } pub fn immty_from_int_checked<'tcx>( diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 643f76bfe37a1..8a75fb03a53c0 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -454,6 +454,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Architecture-specific shims "llvm.x86.sse2.pause" if this.tcx.sess.target.target.arch == "x86" || this.tcx.sess.target.target.arch == "x86_64" => { + let &[] = check_arg_count(args)?; this.sched_yield()?; } diff --git a/src/shims/foreign_items/posix/linux.rs b/src/shims/foreign_items/posix/linux.rs index 3f9d1b259a86a..e0f54cac1570a 100644 --- a/src/shims/foreign_items/posix/linux.rs +++ b/src/shims/foreign_items/posix/linux.rs @@ -102,7 +102,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx .to_machine_usize(this)?; if args.is_empty() { - throw_ub_format!("incorrect number of arguments for syscall, needed at least 1"); + throw_ub_format!("incorrect number of arguments for syscall: got 0, expected at least 1"); } match this.read_scalar(args[0])?.to_machine_usize(this)? { // `libc::syscall(NR_GETRANDOM, buf.as_mut_ptr(), buf.len(), GRND_NONBLOCK)` @@ -143,6 +143,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Incomplete shims that we "stub out" just to get pre-main initialization code to work. // These shims are enabled only when the caller is in the standard library. "pthread_getattr_np" if this.frame().instance.to_string().starts_with("std::sys::unix::") => { + let &[_thread, _attr] = check_arg_count(args)?; this.write_null(dest)?; } diff --git a/src/shims/foreign_items/posix/macos.rs b/src/shims/foreign_items/posix/macos.rs index 685f66d443d4f..1cfecbc93461f 100644 --- a/src/shims/foreign_items/posix/macos.rs +++ b/src/shims/foreign_items/posix/macos.rs @@ -118,8 +118,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Threading "pthread_setname_np" => { - let ptr = this.read_scalar(args[0])?.not_undef()?; - this.pthread_setname_np(ptr)?; + let &[name] = check_arg_count(args)?; + let name = this.read_scalar(name)?.not_undef()?; + this.pthread_setname_np(name)?; } // Incomplete shims that we "stub out" just to get pre-main initialization code to work. diff --git a/src/shims/foreign_items/windows.rs b/src/shims/foreign_items/windows.rs index 3d7afc616e8ed..ab912476f6a93 100644 --- a/src/shims/foreign_items/windows.rs +++ b/src/shims/foreign_items/windows.rs @@ -106,17 +106,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(res, dest)?; } "HeapFree" => { - let &[handle, _flags, ptr] = check_arg_count(args)?; + let &[handle, flags, ptr] = check_arg_count(args)?; this.read_scalar(handle)?.to_machine_isize(this)?; - let _flags = this.read_scalar(_flags)?.to_u32()?; + this.read_scalar(flags)?.to_u32()?; let ptr = this.read_scalar(ptr)?.not_undef()?; this.free(ptr, MiriMemoryKind::WinHeap)?; this.write_scalar(Scalar::from_i32(1), dest)?; } "HeapReAlloc" => { - let &[handle, _flags, ptr, size] = check_arg_count(args)?; + let &[handle, flags, ptr, size] = check_arg_count(args)?; this.read_scalar(handle)?.to_machine_isize(this)?; - let _flags = this.read_scalar(_flags)?.to_u32()?; + this.read_scalar(flags)?.to_u32()?; let ptr = this.read_scalar(ptr)?.not_undef()?; let size = this.read_scalar(size)?.to_machine_usize(this)?; let res = this.realloc(ptr, size, MiriMemoryKind::WinHeap)?; diff --git a/src/shims/fs.rs b/src/shims/fs.rs index b9bb0fadf1a4b..ecb906f158e32 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -328,22 +328,18 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.check_no_isolation("fcntl")?; - let (fd, cmd, start) = if args.len() == 2 { - let &[fd, cmd] = check_arg_count(args)?; - (fd, cmd, None) - } else { - // If args.len() isn't 2 or 3 this will error appropriately. - let &[fd, cmd, start] = check_arg_count(args)?; - (fd, cmd, Some(start)) - }; - let fd = this.read_scalar(fd)?.to_i32()?; - let cmd = this.read_scalar(cmd)?.to_i32()?; + if args.len() < 2 { + throw_ub_format!("incorrect number of arguments for fcntl: got {}, expected at least 2", args.len()); + } + let cmd = this.read_scalar(args[1])?.to_i32()?; // We only support getting the flags for a descriptor. if cmd == this.eval_libc_i32("F_GETFD")? { // Currently this is the only flag that `F_GETFD` returns. It is OK to just return the // `FD_CLOEXEC` value without checking if the flag is set for the file because `std` // always sets this flag when opening a file. However we still need to check that the // file itself is open. + let &[fd, _] = check_arg_count(args)?; + let fd = this.read_scalar(fd)?.to_i32()?; if this.machine.file_handler.handles.contains_key(&fd) { Ok(this.eval_libc_i32("FD_CLOEXEC")?) } else { @@ -356,15 +352,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // because exec() isn't supported. The F_DUPFD and F_DUPFD_CLOEXEC commands only // differ in whether the FD_CLOEXEC flag is pre-set on the new file descriptor, // thus they can share the same implementation here. + let &[fd, _, start] = check_arg_count(args)?; + let fd = this.read_scalar(fd)?.to_i32()?; + let start = this.read_scalar(start)?.to_i32()?; if fd < MIN_NORMAL_FILE_FD { throw_unsup_format!("duplicating file descriptors for stdin, stdout, or stderr is not supported") } - let start = start.ok_or_else(|| { - err_unsup_format!( - "fcntl with command F_DUPFD or F_DUPFD_CLOEXEC requires a third argument" - ) - })?; - let start = this.read_scalar(start)?.to_i32()?; let fh = &mut this.machine.file_handler; let (file_result, writable) = match fh.handles.get(&fd) { Some(FileHandle { file, writable }) => (file.try_clone(), *writable), diff --git a/src/shims/thread.rs b/src/shims/thread.rs index ac1bb39a69828..3ea1ee0aa17d2 100644 --- a/src/shims/thread.rs +++ b/src/shims/thread.rs @@ -121,12 +121,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn pthread_setname_np( &mut self, - ptr: Scalar, + name: Scalar, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); this.assert_target_os("macos", "pthread_setname_np"); - let name = this.memory.read_c_str(ptr)?.to_owned(); + let name = this.memory.read_c_str(name)?.to_owned(); this.set_active_thread_name(name)?; Ok(()) From f741f2cc714b90a224f0b8739c6d57107bf372cc Mon Sep 17 00:00:00 2001 From: Chase Albert Date: Mon, 4 May 2020 23:22:00 -0400 Subject: [PATCH 2030/3747] Correct the test. --- tests/compile-fail/check_arg_count.rs | 8 -------- tests/compile-fail/check_arg_count_too_few_args.rs | 12 ++++++++++++ tests/compile-fail/check_arg_count_too_many_args.rs | 12 ++++++++++++ 3 files changed, 24 insertions(+), 8 deletions(-) delete mode 100644 tests/compile-fail/check_arg_count.rs create mode 100644 tests/compile-fail/check_arg_count_too_few_args.rs create mode 100644 tests/compile-fail/check_arg_count_too_many_args.rs diff --git a/tests/compile-fail/check_arg_count.rs b/tests/compile-fail/check_arg_count.rs deleted file mode 100644 index 0cc6dcb9a98d0..0000000000000 --- a/tests/compile-fail/check_arg_count.rs +++ /dev/null @@ -1,8 +0,0 @@ -#![feature(core_intrinsics)] - -use std::intrinsics; - -fn main() { - unsafe { intrinsics::forget(); } //~ ERROR this function takes 1 argument but 0 arguments were supplied - unsafe { intrinsics::forget(1, 2); } //~ ERROR this function takes 1 argument but 2 arguments were supplied -} diff --git a/tests/compile-fail/check_arg_count_too_few_args.rs b/tests/compile-fail/check_arg_count_too_few_args.rs new file mode 100644 index 0000000000000..c6c19e042dd48 --- /dev/null +++ b/tests/compile-fail/check_arg_count_too_few_args.rs @@ -0,0 +1,12 @@ +#![feature(core_intrinsics)] +#![feature(rustc_private)] + +fn main() { + extern "C" { + fn malloc() -> *mut std::ffi::c_void; + } + + unsafe { + let _ = malloc(); //~ ERROR Undefined Behavior: incorrect number of arguments: got 0, expected 1 + }; +} diff --git a/tests/compile-fail/check_arg_count_too_many_args.rs b/tests/compile-fail/check_arg_count_too_many_args.rs new file mode 100644 index 0000000000000..cca03e53ec10e --- /dev/null +++ b/tests/compile-fail/check_arg_count_too_many_args.rs @@ -0,0 +1,12 @@ +#![feature(core_intrinsics)] +#![feature(rustc_private)] + +fn main() { + extern "C" { + fn malloc(_: i32, _: i32) -> *mut std::ffi::c_void; + } + + unsafe { + let _ = malloc(1, 2); //~ ERROR Undefined Behavior: incorrect number of arguments: got 2, expected 1 + }; +} From 5566e3901c5dffe55cf093e05d8a9bf097958122 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 5 May 2020 11:44:33 +0200 Subject: [PATCH 2031/3747] deduplicate FD extraction --- src/shims/fs.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/shims/fs.rs b/src/shims/fs.rs index ecb906f158e32..ba4611373c8a0 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -331,6 +331,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if args.len() < 2 { throw_ub_format!("incorrect number of arguments for fcntl: got {}, expected at least 2", args.len()); } + let fd = this.read_scalar(args[0])?.to_i32()?; let cmd = this.read_scalar(args[1])?.to_i32()?; // We only support getting the flags for a descriptor. if cmd == this.eval_libc_i32("F_GETFD")? { @@ -338,8 +339,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // `FD_CLOEXEC` value without checking if the flag is set for the file because `std` // always sets this flag when opening a file. However we still need to check that the // file itself is open. - let &[fd, _] = check_arg_count(args)?; - let fd = this.read_scalar(fd)?.to_i32()?; + let &[_, _] = check_arg_count(args)?; if this.machine.file_handler.handles.contains_key(&fd) { Ok(this.eval_libc_i32("FD_CLOEXEC")?) } else { @@ -352,8 +352,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // because exec() isn't supported. The F_DUPFD and F_DUPFD_CLOEXEC commands only // differ in whether the FD_CLOEXEC flag is pre-set on the new file descriptor, // thus they can share the same implementation here. - let &[fd, _, start] = check_arg_count(args)?; - let fd = this.read_scalar(fd)?.to_i32()?; + let &[_, _, start] = check_arg_count(args)?; let start = this.read_scalar(start)?.to_i32()?; if fd < MIN_NORMAL_FILE_FD { throw_unsup_format!("duplicating file descriptors for stdin, stdout, or stderr is not supported") From cd6be9885217d409dc23572714a7b499784e921f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 5 May 2020 11:57:08 +0200 Subject: [PATCH 2032/3747] make sure we check argument count everywhere --- src/shims/foreign_items/posix.rs | 43 +++++++++++++++++++----------- src/shims/foreign_items/windows.rs | 17 +++++------- src/shims/intrinsics.rs | 1 + 3 files changed, 35 insertions(+), 26 deletions(-) diff --git a/src/shims/foreign_items/posix.rs b/src/shims/foreign_items/posix.rs index 6b28e7070165b..a68414ddbc2fe 100644 --- a/src/shims/foreign_items/posix.rs +++ b/src/shims/foreign_items/posix.rs @@ -379,19 +379,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Incomplete shims that we "stub out" just to get pre-main initialization code to work. // These shims are enabled only when the caller is in the standard library. - | "pthread_attr_init" - | "pthread_attr_destroy" - | "pthread_attr_setstacksize" - | "pthread_condattr_init" - | "pthread_condattr_setclock" - | "pthread_cond_init" - | "pthread_condattr_destroy" - | "pthread_cond_destroy" if this.frame().instance.to_string().starts_with("std::sys::unix::") - => { - this.write_null(dest)?; - } - "pthread_attr_getguardsize" if this.frame().instance.to_string().starts_with("std::sys::unix::") - => { + "pthread_attr_getguardsize" + if this.frame().instance.to_string().starts_with("std::sys::unix::") => { let &[_attr, guard_size] = check_arg_count(args)?; let guard_size = this.deref_operand(guard_size)?; let guard_size_layout = this.libc_ty_layout("size_t")?; @@ -401,11 +390,33 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_null(dest)?; } + | "pthread_attr_init" + | "pthread_attr_destroy" + | "pthread_condattr_init" + | "pthread_condattr_destroy" + | "pthread_cond_destroy" + if this.frame().instance.to_string().starts_with("std::sys::unix::") => { + let &[_] = check_arg_count(args)?; + this.write_null(dest)?; + } + | "pthread_cond_init" + | "pthread_attr_setstacksize" + | "pthread_condattr_setclock" + if this.frame().instance.to_string().starts_with("std::sys::unix::") => { + let &[_, _] = check_arg_count(args)?; + this.write_null(dest)?; + } + | "signal" - | "sigaction" | "sigaltstack" - | "mprotect" if this.frame().instance.to_string().starts_with("std::sys::unix::") - => { + if this.frame().instance.to_string().starts_with("std::sys::unix::") => { + let &[_, _] = check_arg_count(args)?; + this.write_null(dest)?; + } + | "sigaction" + | "mprotect" + if this.frame().instance.to_string().starts_with("std::sys::unix::") => { + let &[_, _, _] = check_arg_count(args)?; this.write_null(dest)?; } diff --git a/src/shims/foreign_items/windows.rs b/src/shims/foreign_items/windows.rs index ab912476f6a93..cff1887ff8b54 100644 --- a/src/shims/foreign_items/windows.rs +++ b/src/shims/foreign_items/windows.rs @@ -251,22 +251,19 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Just fake a HANDLE this.write_scalar(Scalar::from_machine_isize(1, this), dest)?; } - "GetModuleHandleW" if this.frame().instance.to_string().starts_with("std::sys::windows::") - => { + "GetModuleHandleW" if this.frame().instance.to_string().starts_with("std::sys::windows::") => { #[allow(non_snake_case)] let &[_lpModuleName] = check_arg_count(args)?; // Pretend this does not exist / nothing happened, by returning zero. this.write_null(dest)?; } - "GetProcAddress" if this.frame().instance.to_string().starts_with("std::sys::windows::") - => { + "GetProcAddress" if this.frame().instance.to_string().starts_with("std::sys::windows::") => { #[allow(non_snake_case)] let &[_hModule, _lpProcName] = check_arg_count(args)?; // Pretend this does not exist / nothing happened, by returning zero. this.write_null(dest)?; } - "SetConsoleTextAttribute" if this.frame().instance.to_string().starts_with("std::sys::windows::") - => { + "SetConsoleTextAttribute" if this.frame().instance.to_string().starts_with("std::sys::windows::") => { #[allow(non_snake_case)] let &[_hConsoleOutput, _wAttribute] = check_arg_count(args)?; // Pretend these does not exist / nothing happened, by returning zero. @@ -281,8 +278,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "InitializeCriticalSection" | "EnterCriticalSection" | "LeaveCriticalSection" - | "DeleteCriticalSection" if this.frame().instance.to_string().starts_with("std::sys::windows::") - => { + | "DeleteCriticalSection" + if this.frame().instance.to_string().starts_with("std::sys::windows::") => { #[allow(non_snake_case)] let &[_lpCriticalSection] = check_arg_count(args)?; assert_eq!(this.get_total_thread_count()?, 1, "concurrency on Windows not supported"); @@ -290,8 +287,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // (Windows locks are reentrant, and we have only 1 thread, // so not doing any futher checks here is at least not incorrect.) } - "TryEnterCriticalSection" if this.frame().instance.to_string().starts_with("std::sys::windows::") - => { + "TryEnterCriticalSection" + if this.frame().instance.to_string().starts_with("std::sys::windows::") => { #[allow(non_snake_case)] let &[_lpCriticalSection] = check_arg_count(args)?; assert_eq!(this.get_total_thread_count()?, 1, "concurrency on Windows not supported"); diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index a77443ef52247..cf485b5477468 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -363,6 +363,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "atomic_singlethreadfence_acqrel" | "atomic_singlethreadfence" => { + let &[] = check_arg_count(args)?; // we are inherently singlethreaded and singlecored, this is a nop } From 5656cb73d45c6403c3e3ba2be0283b1779365ecb Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 5 May 2020 11:57:39 +0200 Subject: [PATCH 2033/3747] fix a comment now that we have concurrency --- src/shims/intrinsics.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index cf485b5477468..08087b0350d9c 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -364,7 +364,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "atomic_singlethreadfence" => { let &[] = check_arg_count(args)?; - // we are inherently singlethreaded and singlecored, this is a nop + // FIXME: this will become relevant once we try to detect data races. } _ if intrinsic_name.starts_with("atomic_xchg") => { From 40800cfa197100f45419586fbdc622d17ea47b7f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 5 May 2020 12:19:54 +0200 Subject: [PATCH 2034/3747] make sure we check the size of all arguments --- src/shims/foreign_items/posix.rs | 7 ++++--- src/shims/foreign_items/windows.rs | 3 ++- src/shims/fs.rs | 14 ++++++++++++++ 3 files changed, 20 insertions(+), 4 deletions(-) diff --git a/src/shims/foreign_items/posix.rs b/src/shims/foreign_items/posix.rs index a68414ddbc2fe..951a40293b72d 100644 --- a/src/shims/foreign_items/posix.rs +++ b/src/shims/foreign_items/posix.rs @@ -34,7 +34,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_i32(result), dest)?; } "setenv" => { - let &[name, value, _overwrite] = check_arg_count(args)?; + let &[name, value, overwrite] = check_arg_count(args)?; + this.read_scalar(overwrite)?.to_i32()?; let result = this.setenv(name, value)?; this.write_scalar(Scalar::from_i32(result), dest)?; } @@ -51,8 +52,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // File related shims "open" | "open64" => { - let &[path, flag, _mode] = check_arg_count(args)?; - let result = this.open(path, flag)?; + let &[path, flag, mode] = check_arg_count(args)?; + let result = this.open(path, flag, mode)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "fcntl" => { diff --git a/src/shims/foreign_items/windows.rs b/src/shims/foreign_items/windows.rs index cff1887ff8b54..7f3cd03cd2d36 100644 --- a/src/shims/foreign_items/windows.rs +++ b/src/shims/foreign_items/windows.rs @@ -63,7 +63,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_machine_isize(which.into(), this), dest)?; } "WriteFile" => { - let &[handle, buf, n, written_ptr, _overlapped] = check_arg_count(args)?; + let &[handle, buf, n, written_ptr, overlapped] = check_arg_count(args)?; + this.read_scalar(overlapped)?.to_machine_usize(this)?; // this is a poiner, that we ignore let handle = this.read_scalar(handle)?.to_machine_isize(this)?; let buf = this.read_scalar(buf)?.not_undef()?; let n = this.read_scalar(n)?.to_u32()?; diff --git a/src/shims/fs.rs b/src/shims/fs.rs index ba4611373c8a0..58abf748dd5a8 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -238,6 +238,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx &mut self, path_op: OpTy<'tcx, Tag>, flag_op: OpTy<'tcx, Tag>, + mode_op: OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); @@ -245,6 +246,19 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let flag = this.read_scalar(flag_op)?.to_i32()?; + // Check mode (size depends on platform). + // FIXME: should we do something with the mode? + match this.tcx.sess.target.target.target_os.as_str() { + "macos" => { + // FIXME: I think `mode` should be `u16` on macOS, but see + // . + // For now, just don't check on macos. + } + _ => { + this.read_scalar(mode_op)?.to_u32()?; + } + }; + let mut options = OpenOptions::new(); let o_rdonly = this.eval_libc_i32("O_RDONLY")?; From 45ef97535ff64b22cf281c087c6bf1f603208985 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 5 May 2020 16:49:01 +0200 Subject: [PATCH 2035/3747] fs shim: check that mode is default --- src/shims/fs.rs | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/src/shims/fs.rs b/src/shims/fs.rs index 58abf748dd5a8..0de0b33fb2e29 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -246,18 +246,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let flag = this.read_scalar(flag_op)?.to_i32()?; - // Check mode (size depends on platform). - // FIXME: should we do something with the mode? - match this.tcx.sess.target.target.target_os.as_str() { - "macos" => { - // FIXME: I think `mode` should be `u16` on macOS, but see - // . - // For now, just don't check on macos. - } - _ => { - this.read_scalar(mode_op)?.to_u32()?; - } - }; + // Get the mode. On macOS, the argument type `mode_t` is actually `u16`, but + // C integer promotion rules mean that on the ABI level, it gets passed as `u32` + // (see https://github.com/rust-lang/rust/issues/71915). + let mode = this.read_scalar(mode_op)?.to_u32()?; + if mode != 0o666 { + throw_unsup_format!("non-default mode 0o{:o} is not supported", mode); + } let mut options = OpenOptions::new(); From da6846c8a953c065ec868d91d4e40d0b4dda4659 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 6 May 2020 22:46:42 +0200 Subject: [PATCH 2036/3747] copy some float cast tests from rustc --- tests/run-pass/float.rs | 113 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 112 insertions(+), 1 deletion(-) diff --git a/tests/run-pass/float.rs b/tests/run-pass/float.rs index fc513ead8dd86..3347b0a07c26a 100644 --- a/tests/run-pass/float.rs +++ b/tests/run-pass/float.rs @@ -1,4 +1,4 @@ -#![feature(track_caller)] +#![feature(track_caller, stmt_expr_attributes)] use std::fmt::Debug; // Helper function to avoid promotion so that this tests "run-time" casts, not CTFE. @@ -78,6 +78,7 @@ fn test_both_cast(x: F, y: I) fn main() { basic(); casts(); + more_casts(); ops(); } @@ -334,3 +335,113 @@ fn ops() { assert_eq((-3.5_f64).copysign(-0.42), -3.5_f64); assert!(f64::NAN.copysign(1.0).is_nan()); } + +/// Tests taken from rustc test suite. +/// + +// Poor-man's black-box +#[inline(never)] +fn black_box(x: T) -> T { x } + +macro_rules! test { + ($val:expr, $src_ty:ident -> $dest_ty:ident, $expected:expr) => ( + // black_box disables constant evaluation to test run-time conversions: + assert_eq!(black_box::<$src_ty>($val) as $dest_ty, $expected, + "run-time {} -> {}", stringify!($src_ty), stringify!($dest_ty)); + + { + const X: $src_ty = $val; + const Y: $dest_ty = X as $dest_ty; + assert_eq!(Y, $expected, + "const eval {} -> {}", stringify!($src_ty), stringify!($dest_ty)); + } + ); + + ($fval:expr, f* -> $ity:ident, $ival:expr) => ( + test!($fval, f32 -> $ity, $ival); + test!($fval, f64 -> $ity, $ival); + ) +} + +macro_rules! common_fptoi_tests { + ($fty:ident -> $($ity:ident)+) => ({ $( + test!($fty::NAN, $fty -> $ity, 0); + test!($fty::INFINITY, $fty -> $ity, $ity::MAX); + test!($fty::NEG_INFINITY, $fty -> $ity, $ity::MIN); + // These two tests are not solely float->int tests, in particular the latter relies on + // `u128::MAX as f32` not being UB. But that's okay, since this file tests int->float + // as well, the test is just slightly misplaced. + test!($ity::MIN as $fty, $fty -> $ity, $ity::MIN); + test!($ity::MAX as $fty, $fty -> $ity, $ity::MAX); + test!(0., $fty -> $ity, 0); + test!($fty::MIN_POSITIVE, $fty -> $ity, 0); + test!(-0.9, $fty -> $ity, 0); + test!(1., $fty -> $ity, 1); + test!(42., $fty -> $ity, 42); + )+ }); + + (f* -> $($ity:ident)+) => ({ + common_fptoi_tests!(f32 -> $($ity)+); + common_fptoi_tests!(f64 -> $($ity)+); + }) +} + +macro_rules! fptoui_tests { + ($fty: ident -> $($ity: ident)+) => ({ $( + test!(-0., $fty -> $ity, 0); + test!(-$fty::MIN_POSITIVE, $fty -> $ity, 0); + test!(-0.99999994, $fty -> $ity, 0); + test!(-1., $fty -> $ity, 0); + test!(-100., $fty -> $ity, 0); + test!(#[allow(overflowing_literals)] -1e50, $fty -> $ity, 0); + test!(#[allow(overflowing_literals)] -1e130, $fty -> $ity, 0); + )+ }); + + (f* -> $($ity:ident)+) => ({ + fptoui_tests!(f32 -> $($ity)+); + fptoui_tests!(f64 -> $($ity)+); + }) +} + +fn more_casts() { + common_fptoi_tests!(f* -> i8 i16 i32 i64 u8 u16 u32 u64); + fptoui_tests!(f* -> u8 u16 u32 u64); + common_fptoi_tests!(f* -> i128 u128); + fptoui_tests!(f* -> u128); + + // The following tests cover edge cases for some integer types. + + // # u8 + test!(254., f* -> u8, 254); + test!(256., f* -> u8, 255); + + // # i8 + test!(-127., f* -> i8, -127); + test!(-129., f* -> i8, -128); + test!(126., f* -> i8, 126); + test!(128., f* -> i8, 127); + + // # i32 + // -2147483648. is i32::MIN (exactly) + test!(-2147483648., f* -> i32, i32::MIN); + // 2147483648. is i32::MAX rounded up + test!(2147483648., f32 -> i32, 2147483647); + // With 24 significand bits, floats with magnitude in [2^30 + 1, 2^31] are rounded to + // multiples of 2^7. Therefore, nextDown(round(i32::MAX)) is 2^31 - 128: + test!(2147483520., f32 -> i32, 2147483520); + // Similarly, nextUp(i32::MIN) is i32::MIN + 2^8 and nextDown(i32::MIN) is i32::MIN - 2^7 + test!(-2147483904., f* -> i32, i32::MIN); + test!(-2147483520., f* -> i32, -2147483520); + + // # u32 + // round(MAX) and nextUp(round(MAX)) + test!(4294967040., f* -> u32, 4294967040); + test!(4294967296., f* -> u32, 4294967295); + + // # u128 + // float->int: + test!(f32::MAX, f32 -> u128, 0xffffff00000000000000000000000000); + // nextDown(f32::MAX) = 2^128 - 2 * 2^104 + const SECOND_LARGEST_F32: f32 = 340282326356119256160033759537265639424.; + test!(SECOND_LARGEST_F32, f32 -> u128, 0xfffffe00000000000000000000000000); +} From 356848c9b9a3bd8226bbabd08611b1e519acc9c7 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Thu, 7 May 2020 02:42:12 +0000 Subject: [PATCH 2037/3747] Add two more TiKV bugs to trophy case --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 5a520385fd17a..bfabc12659ac3 100644 --- a/README.md +++ b/README.md @@ -273,6 +273,7 @@ Definite bugs found: * [`EbrCell` using uninitialized memory incorrectly](https://github.com/Firstyear/concread/commit/b15be53b6ec076acb295a5c0483cdb4bf9be838f#diff-6282b2fc8e98bd089a1f0c86f648157cR229) * [TiKV performing an unaligned pointer access](https://github.com/tikv/tikv/issues/7613) * [`servo_arc` creating a dangling shared reference](https://github.com/servo/servo/issues/26357) +* [TiKV constructing out-of-bounds pointers and overlapping mutable references](https://github.com/tikv/tikv/pull/7751) Violations of [Stacked Borrows] found that are likely bugs (but Stacked Borrows is currently just an experiment): From fb3a067ac6af5ed2d0f393a4dce0c92d437f1fc1 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 7 May 2020 08:38:52 +0200 Subject: [PATCH 2038/3747] rustup; fix error messages --- rust-version | 2 +- tests/compile-fail/issue-miri-1112.rs | 2 +- tests/compile-fail/validity/dangling_ref1.rs | 2 +- tests/compile-fail/validity/invalid_wide_raw.rs | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/rust-version b/rust-version index be7b603f9054a..33dc39f869135 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -ff4df04799c406c8149a041c3163321758aac924 +97f3eeec8216d7155c24674b9be55e7c672bcae3 diff --git a/tests/compile-fail/issue-miri-1112.rs b/tests/compile-fail/issue-miri-1112.rs index 29cc5c781200d..a00bed190e605 100644 --- a/tests/compile-fail/issue-miri-1112.rs +++ b/tests/compile-fail/issue-miri-1112.rs @@ -32,7 +32,7 @@ impl FunnyPointer { data: data as *const _ as *const (), vtable: ptr as *const _ as *const (), }; - let obj = std::mem::transmute::(obj); //~ ERROR invalid drop fn in vtable + let obj = std::mem::transmute::(obj); //~ ERROR invalid drop function pointer in vtable &*obj } } diff --git a/tests/compile-fail/validity/dangling_ref1.rs b/tests/compile-fail/validity/dangling_ref1.rs index a83c6af21acfd..5097135f02d39 100644 --- a/tests/compile-fail/validity/dangling_ref1.rs +++ b/tests/compile-fail/validity/dangling_ref1.rs @@ -3,5 +3,5 @@ use std::mem; fn main() { - let _x: &i32 = unsafe { mem::transmute(16usize) }; //~ ERROR reference to unallocated address 16 + let _x: &i32 = unsafe { mem::transmute(16usize) }; //~ ERROR encountered a dangling reference (address 16 is unallocated) } diff --git a/tests/compile-fail/validity/invalid_wide_raw.rs b/tests/compile-fail/validity/invalid_wide_raw.rs index 8f1e184ed22e5..c232672132227 100644 --- a/tests/compile-fail/validity/invalid_wide_raw.rs +++ b/tests/compile-fail/validity/invalid_wide_raw.rs @@ -6,5 +6,5 @@ fn main() { struct S { x: * mut dyn T } - dbg!(S { x: unsafe { std::mem::transmute((0usize, 0usize)) } }); //~ ERROR: encountered dangling or unaligned vtable pointer + dbg!(S { x: unsafe { std::mem::transmute((0usize, 0usize)) } }); //~ ERROR: encountered dangling vtable pointer } From 132feb88db9bf49efdbbe27d09ed68f1c6b6eb67 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 7 May 2020 11:21:31 +0200 Subject: [PATCH 2039/3747] adjust wording --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index bfabc12659ac3..35d15d59ee4db 100644 --- a/README.md +++ b/README.md @@ -273,7 +273,7 @@ Definite bugs found: * [`EbrCell` using uninitialized memory incorrectly](https://github.com/Firstyear/concread/commit/b15be53b6ec076acb295a5c0483cdb4bf9be838f#diff-6282b2fc8e98bd089a1f0c86f648157cR229) * [TiKV performing an unaligned pointer access](https://github.com/tikv/tikv/issues/7613) * [`servo_arc` creating a dangling shared reference](https://github.com/servo/servo/issues/26357) -* [TiKV constructing out-of-bounds pointers and overlapping mutable references](https://github.com/tikv/tikv/pull/7751) +* [TiKV constructing out-of-bounds pointers (and overlapping mutable references)](https://github.com/tikv/tikv/pull/7751) Violations of [Stacked Borrows] found that are likely bugs (but Stacked Borrows is currently just an experiment): From b4ad90669b7e51e50d87f893b6bcbe39410b9db0 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 7 May 2020 23:59:26 +0200 Subject: [PATCH 2040/3747] rustup --- rust-version | 2 +- tests/compile-fail/validity/dangling_ref1.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/rust-version b/rust-version index 33dc39f869135..050d500e53f9c 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -97f3eeec8216d7155c24674b9be55e7c672bcae3 +a08c47310c7d49cbdc5d7afb38408ba519967ecd diff --git a/tests/compile-fail/validity/dangling_ref1.rs b/tests/compile-fail/validity/dangling_ref1.rs index 5097135f02d39..78425cde4a8aa 100644 --- a/tests/compile-fail/validity/dangling_ref1.rs +++ b/tests/compile-fail/validity/dangling_ref1.rs @@ -3,5 +3,5 @@ use std::mem; fn main() { - let _x: &i32 = unsafe { mem::transmute(16usize) }; //~ ERROR encountered a dangling reference (address 16 is unallocated) + let _x: &i32 = unsafe { mem::transmute(16usize) }; //~ ERROR encountered a dangling reference (address 0x10 is unallocated) } From 914e483c89c9b1619001e2c9dcc75a53968da3e7 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 8 May 2020 09:55:28 +0200 Subject: [PATCH 2041/3747] fix cargo-miri intercepting --help/--version arguments --- src/bin/cargo-miri.rs | 50 +++++++++++++++++++++---------------------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 1d93654e33e98..4392cb93ddb44 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -401,31 +401,6 @@ path = "lib.rs" } } -fn main() { - // Check for version and help flags even when invoked as `cargo-miri`. - if std::env::args().any(|a| a == "--help" || a == "-h") { - show_help(); - return; - } - if std::env::args().any(|a| a == "--version" || a == "-V") { - show_version(); - return; - } - - if let Some("miri") = std::env::args().nth(1).as_deref() { - // This arm is for when `cargo miri` is called. We call `cargo check` for each applicable target, - // but with the `RUSTC` env var set to the `cargo-miri` binary so that we come back in the other branch, - // and dispatch the invocations to `rustc` and `miri`, respectively. - in_cargo_miri(); - } else if let Some("rustc") = std::env::args().nth(1).as_deref() { - // This arm is executed when `cargo-miri` runs `cargo check` with the `RUSTC_WRAPPER` env var set to itself: - // dependencies get dispatched to `rustc`, the final test/binary to `miri`. - inside_cargo_rustc(); - } else { - show_error(format!("must be called with either `miri` or `rustc` as first argument.")) - } -} - fn in_cargo_miri() { let (subcommand, skip) = match std::env::args().nth(2).as_deref() { Some("test") => (MiriCommand::Test, 3), @@ -593,3 +568,28 @@ fn inside_cargo_rustc() { Err(e) => panic!("error running {:?}:\n{:?}", command, e), } } + +fn main() { + // Check for version and help flags even when invoked as `cargo-miri`. + if has_arg_flag("--help") || has_arg_flag("-h") { + show_help(); + return; + } + if has_arg_flag("--version") || has_arg_flag("-V") { + show_version(); + return; + } + + if let Some("miri") = std::env::args().nth(1).as_deref() { + // This arm is for when `cargo miri` is called. We call `cargo check` for each applicable target, + // but with the `RUSTC` env var set to the `cargo-miri` binary so that we come back in the other branch, + // and dispatch the invocations to `rustc` and `miri`, respectively. + in_cargo_miri(); + } else if let Some("rustc") = std::env::args().nth(1).as_deref() { + // This arm is executed when `cargo-miri` runs `cargo check` with the `RUSTC_WRAPPER` env var set to itself: + // dependencies get dispatched to `rustc`, the final test/binary to `miri`. + inside_cargo_rustc(); + } else { + show_error(format!("must be called with either `miri` or `rustc` as first argument.")) + } +} From 379ac82a1c1d7530070e6676f03c8ca5eb9f7894 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 9 May 2020 10:15:09 +0200 Subject: [PATCH 2042/3747] bump Rust, fix for renames --- rust-version | 2 +- src/diagnostics.rs | 2 +- src/helpers.rs | 2 +- src/shims/sync.rs | 56 +++++++++++++++++++++++----------------------- 4 files changed, 31 insertions(+), 31 deletions(-) diff --git a/rust-version b/rust-version index 050d500e53f9c..d53d4d68e486a 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -a08c47310c7d49cbdc5d7afb38408ba519967ecd +0f9088f9610618e724cfc0cf2ba3721918be5ec9 diff --git a/src/diagnostics.rs b/src/diagnostics.rs index e5e7f0c904754..8296f71773c2a 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -118,7 +118,7 @@ pub fn report_error<'tcx, 'mir>( report_msg(ecx, &format!("{}: {}", title, msg), msg, helps, true); // Extra output to help debug specific issues. - if let UndefinedBehavior(UndefinedBehaviorInfo::InvalidUndefBytes(Some(ptr))) = e.kind { + if let UndefinedBehavior(UndefinedBehaviorInfo::InvalidUninitBytes(Some(ptr))) = e.kind { eprintln!( "Uninitialized read occurred at offset 0x{:x} into this allocation:", ptr.offset.bytes(), diff --git a/src/helpers.rs b/src/helpers.rs index 510efe4660880..8b20ee2f0d835 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -54,7 +54,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn eval_path_scalar( &mut self, path: &[&str], - ) -> InterpResult<'tcx, ScalarMaybeUndef> { + ) -> InterpResult<'tcx, ScalarMaybeUninit> { let this = self.eval_context_mut(); let instance = this.resolve_path(path); let cid = GlobalId { instance, promoted: None }; diff --git a/src/shims/sync.rs b/src/shims/sync.rs index bc64b1e97a50e..c205c5c8dddb1 100644 --- a/src/shims/sync.rs +++ b/src/shims/sync.rs @@ -25,7 +25,7 @@ fn get_at_offset<'mir, 'tcx: 'mir>( offset: u64, layout: TyAndLayout<'tcx>, min_size: u64, -) -> InterpResult<'tcx, ScalarMaybeUndef> { +) -> InterpResult<'tcx, ScalarMaybeUninit> { // Ensure that the following read at an offset to the attr pointer is within bounds assert_ptr_target_min_size(ecx, op, min_size)?; let op_place = ecx.deref_operand(op)?; @@ -37,7 +37,7 @@ fn set_at_offset<'mir, 'tcx: 'mir>( ecx: &mut MiriEvalContext<'mir, 'tcx>, op: OpTy<'tcx, Tag>, offset: u64, - value: impl Into>, + value: impl Into>, layout: TyAndLayout<'tcx>, min_size: u64, ) -> InterpResult<'tcx, ()> { @@ -59,14 +59,14 @@ const PTHREAD_MUTEXATTR_T_MIN_SIZE: u64 = 4; fn mutexattr_get_kind<'mir, 'tcx: 'mir>( ecx: &MiriEvalContext<'mir, 'tcx>, attr_op: OpTy<'tcx, Tag>, -) -> InterpResult<'tcx, ScalarMaybeUndef> { +) -> InterpResult<'tcx, ScalarMaybeUninit> { get_at_offset(ecx, attr_op, 0, ecx.machine.layouts.i32, PTHREAD_MUTEXATTR_T_MIN_SIZE) } fn mutexattr_set_kind<'mir, 'tcx: 'mir>( ecx: &mut MiriEvalContext<'mir, 'tcx>, attr_op: OpTy<'tcx, Tag>, - kind: impl Into>, + kind: impl Into>, ) -> InterpResult<'tcx, ()> { set_at_offset(ecx, attr_op, 0, kind, ecx.machine.layouts.i32, PTHREAD_MUTEXATTR_T_MIN_SIZE) } @@ -88,14 +88,14 @@ const PTHREAD_MUTEX_T_MIN_SIZE: u64 = 24; fn mutex_get_locked_count<'mir, 'tcx: 'mir>( ecx: &MiriEvalContext<'mir, 'tcx>, mutex_op: OpTy<'tcx, Tag>, -) -> InterpResult<'tcx, ScalarMaybeUndef> { +) -> InterpResult<'tcx, ScalarMaybeUninit> { get_at_offset(ecx, mutex_op, 4, ecx.machine.layouts.u32, PTHREAD_MUTEX_T_MIN_SIZE) } fn mutex_set_locked_count<'mir, 'tcx: 'mir>( ecx: &mut MiriEvalContext<'mir, 'tcx>, mutex_op: OpTy<'tcx, Tag>, - locked_count: impl Into>, + locked_count: impl Into>, ) -> InterpResult<'tcx, ()> { set_at_offset(ecx, mutex_op, 4, locked_count, ecx.machine.layouts.u32, PTHREAD_MUTEX_T_MIN_SIZE) } @@ -103,14 +103,14 @@ fn mutex_set_locked_count<'mir, 'tcx: 'mir>( fn mutex_get_owner<'mir, 'tcx: 'mir>( ecx: &MiriEvalContext<'mir, 'tcx>, mutex_op: OpTy<'tcx, Tag>, -) -> InterpResult<'tcx, ScalarMaybeUndef> { +) -> InterpResult<'tcx, ScalarMaybeUninit> { get_at_offset(ecx, mutex_op, 8, ecx.machine.layouts.u32, PTHREAD_MUTEX_T_MIN_SIZE) } fn mutex_set_owner<'mir, 'tcx: 'mir>( ecx: &mut MiriEvalContext<'mir, 'tcx>, mutex_op: OpTy<'tcx, Tag>, - owner: impl Into>, + owner: impl Into>, ) -> InterpResult<'tcx, ()> { set_at_offset(ecx, mutex_op, 8, owner, ecx.machine.layouts.u32, PTHREAD_MUTEX_T_MIN_SIZE) } @@ -118,7 +118,7 @@ fn mutex_set_owner<'mir, 'tcx: 'mir>( fn mutex_get_kind<'mir, 'tcx: 'mir>( ecx: &mut MiriEvalContext<'mir, 'tcx>, mutex_op: OpTy<'tcx, Tag>, -) -> InterpResult<'tcx, ScalarMaybeUndef> { +) -> InterpResult<'tcx, ScalarMaybeUninit> { let offset = if ecx.pointer_size().bytes() == 8 { 16 } else { 12 }; get_at_offset(ecx, mutex_op, offset, ecx.machine.layouts.i32, PTHREAD_MUTEX_T_MIN_SIZE) } @@ -126,7 +126,7 @@ fn mutex_get_kind<'mir, 'tcx: 'mir>( fn mutex_set_kind<'mir, 'tcx: 'mir>( ecx: &mut MiriEvalContext<'mir, 'tcx>, mutex_op: OpTy<'tcx, Tag>, - kind: impl Into>, + kind: impl Into>, ) -> InterpResult<'tcx, ()> { let offset = if ecx.pointer_size().bytes() == 8 { 16 } else { 12 }; set_at_offset(ecx, mutex_op, offset, kind, ecx.machine.layouts.i32, PTHREAD_MUTEX_T_MIN_SIZE) @@ -135,14 +135,14 @@ fn mutex_set_kind<'mir, 'tcx: 'mir>( fn mutex_get_blockset<'mir, 'tcx: 'mir>( ecx: &MiriEvalContext<'mir, 'tcx>, mutex_op: OpTy<'tcx, Tag>, -) -> InterpResult<'tcx, ScalarMaybeUndef> { +) -> InterpResult<'tcx, ScalarMaybeUninit> { get_at_offset(ecx, mutex_op, 20, ecx.machine.layouts.u32, PTHREAD_MUTEX_T_MIN_SIZE) } fn mutex_set_blockset<'mir, 'tcx: 'mir>( ecx: &mut MiriEvalContext<'mir, 'tcx>, mutex_op: OpTy<'tcx, Tag>, - blockset: impl Into>, + blockset: impl Into>, ) -> InterpResult<'tcx, ()> { set_at_offset(ecx, mutex_op, 20, blockset, ecx.machine.layouts.u32, PTHREAD_MUTEX_T_MIN_SIZE) } @@ -180,14 +180,14 @@ const PTHREAD_RWLOCK_T_MIN_SIZE: u64 = 20; fn rwlock_get_readers<'mir, 'tcx: 'mir>( ecx: &MiriEvalContext<'mir, 'tcx>, rwlock_op: OpTy<'tcx, Tag>, -) -> InterpResult<'tcx, ScalarMaybeUndef> { +) -> InterpResult<'tcx, ScalarMaybeUninit> { get_at_offset(ecx, rwlock_op, 4, ecx.machine.layouts.u32, PTHREAD_RWLOCK_T_MIN_SIZE) } fn rwlock_set_readers<'mir, 'tcx: 'mir>( ecx: &mut MiriEvalContext<'mir, 'tcx>, rwlock_op: OpTy<'tcx, Tag>, - readers: impl Into>, + readers: impl Into>, ) -> InterpResult<'tcx, ()> { set_at_offset(ecx, rwlock_op, 4, readers, ecx.machine.layouts.u32, PTHREAD_RWLOCK_T_MIN_SIZE) } @@ -195,14 +195,14 @@ fn rwlock_set_readers<'mir, 'tcx: 'mir>( fn rwlock_get_writers<'mir, 'tcx: 'mir>( ecx: &MiriEvalContext<'mir, 'tcx>, rwlock_op: OpTy<'tcx, Tag>, -) -> InterpResult<'tcx, ScalarMaybeUndef> { +) -> InterpResult<'tcx, ScalarMaybeUninit> { get_at_offset(ecx, rwlock_op, 8, ecx.machine.layouts.u32, PTHREAD_RWLOCK_T_MIN_SIZE) } fn rwlock_set_writers<'mir, 'tcx: 'mir>( ecx: &mut MiriEvalContext<'mir, 'tcx>, rwlock_op: OpTy<'tcx, Tag>, - writers: impl Into>, + writers: impl Into>, ) -> InterpResult<'tcx, ()> { set_at_offset(ecx, rwlock_op, 8, writers, ecx.machine.layouts.u32, PTHREAD_RWLOCK_T_MIN_SIZE) } @@ -210,14 +210,14 @@ fn rwlock_set_writers<'mir, 'tcx: 'mir>( fn rwlock_get_writer_blockset<'mir, 'tcx: 'mir>( ecx: &MiriEvalContext<'mir, 'tcx>, rwlock_op: OpTy<'tcx, Tag>, -) -> InterpResult<'tcx, ScalarMaybeUndef> { +) -> InterpResult<'tcx, ScalarMaybeUninit> { get_at_offset(ecx, rwlock_op, 12, ecx.machine.layouts.u32, PTHREAD_RWLOCK_T_MIN_SIZE) } fn rwlock_set_writer_blockset<'mir, 'tcx: 'mir>( ecx: &mut MiriEvalContext<'mir, 'tcx>, rwlock_op: OpTy<'tcx, Tag>, - blockset: impl Into>, + blockset: impl Into>, ) -> InterpResult<'tcx, ()> { set_at_offset(ecx, rwlock_op, 12, blockset, ecx.machine.layouts.u32, PTHREAD_RWLOCK_T_MIN_SIZE) } @@ -241,14 +241,14 @@ fn rwlock_get_or_create_writer_blockset<'mir, 'tcx: 'mir>( fn rwlock_get_reader_blockset<'mir, 'tcx: 'mir>( ecx: &MiriEvalContext<'mir, 'tcx>, rwlock_op: OpTy<'tcx, Tag>, -) -> InterpResult<'tcx, ScalarMaybeUndef> { +) -> InterpResult<'tcx, ScalarMaybeUninit> { get_at_offset(ecx, rwlock_op, 16, ecx.machine.layouts.u32, PTHREAD_RWLOCK_T_MIN_SIZE) } fn rwlock_set_reader_blockset<'mir, 'tcx: 'mir>( ecx: &mut MiriEvalContext<'mir, 'tcx>, rwlock_op: OpTy<'tcx, Tag>, - blockset: impl Into>, + blockset: impl Into>, ) -> InterpResult<'tcx, ()> { set_at_offset(ecx, rwlock_op, 16, blockset, ecx.machine.layouts.u32, PTHREAD_RWLOCK_T_MIN_SIZE) } @@ -304,7 +304,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn pthread_mutexattr_destroy(&mut self, attr_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - mutexattr_set_kind(this, attr_op, ScalarMaybeUndef::Undef)?; + mutexattr_set_kind(this, attr_op, ScalarMaybeUninit::Uninit)?; Ok(0) } @@ -458,9 +458,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx throw_ub_format!("destroyed a locked mutex"); } - mutex_set_kind(this, mutex_op, ScalarMaybeUndef::Undef)?; - mutex_set_locked_count(this, mutex_op, ScalarMaybeUndef::Undef)?; - mutex_set_blockset(this, mutex_op, ScalarMaybeUndef::Undef)?; + mutex_set_kind(this, mutex_op, ScalarMaybeUninit::Uninit)?; + mutex_set_locked_count(this, mutex_op, ScalarMaybeUninit::Uninit)?; + mutex_set_blockset(this, mutex_op, ScalarMaybeUninit::Uninit)?; Ok(0) } @@ -579,10 +579,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx throw_ub_format!("destroyed a locked rwlock"); } - rwlock_set_readers(this, rwlock_op, ScalarMaybeUndef::Undef)?; - rwlock_set_writers(this, rwlock_op, ScalarMaybeUndef::Undef)?; - rwlock_set_reader_blockset(this, rwlock_op, ScalarMaybeUndef::Undef)?; - rwlock_set_writer_blockset(this, rwlock_op, ScalarMaybeUndef::Undef)?; + rwlock_set_readers(this, rwlock_op, ScalarMaybeUninit::Uninit)?; + rwlock_set_writers(this, rwlock_op, ScalarMaybeUninit::Uninit)?; + rwlock_set_reader_blockset(this, rwlock_op, ScalarMaybeUninit::Uninit)?; + rwlock_set_writer_blockset(this, rwlock_op, ScalarMaybeUninit::Uninit)?; Ok(0) } From 70f83a342c43da584a029d60f79547b175f28947 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 9 May 2020 11:45:43 +0200 Subject: [PATCH 2043/3747] re-do cargo-miri host/target detection logic to match rustbuild --- src/bin/cargo-miri.rs | 31 ++++++++++++++++++------------- 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 4392cb93ddb44..0d73c7cf853a4 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -462,6 +462,14 @@ fn in_cargo_miri() { } cmd.arg(arg); } + // We want to always run `cargo` with `--target`. This later helps us detect + // which crates are proc-macro/build-script (host crates) and which crates are + // needed for the program itself. + if get_arg_flag_value("--target").is_none() { + // When no `--target` is given, default to the host. + cmd.arg("--target"); + cmd.arg(rustc_version::version_meta().unwrap().host); + } // Serialize the remaining args into a special environemt variable. // This will be read by `inside_cargo_rustc` when we go to invoke @@ -491,24 +499,21 @@ fn in_cargo_miri() { } fn inside_cargo_rustc() { - /// Determines if we are being invoked (as rustc) to build a runnable - /// executable. We run "cargo check", so this should only happen when - /// we are trying to compile a build script or build script dependency, - /// which actually needs to be executed on the host platform. + /// Determines if we are being invoked (as rustc) to build a crate for + /// the "target" architecture, in contrast to the "host" architecture. + /// Host crates are for build scripts and proc macros and still need to + /// be built like normal; target crates need to be built for or interpreted + /// by Miri. /// - /// Currently, we detect this by checking for "--emit=link", - /// which indicates that Cargo instruced rustc to output - /// a native object. + /// Currently, we detect this by checking for "--target=", which flag is + /// never set for host crates. This matches what rustc bootstrap does, + /// which hopefully makes it "reliable enough". fn is_target_crate() -> bool { - // `--emit` is sometimes missing, e.g. cargo calls rustc for "--print". - // That is definitely not a target crate. - // If `--emit` is present, then host crates are built ("--emit=link,...), - // while the rest is only checked. - get_arg_flag_value("--emit").map_or(false, |emit| !emit.contains("link")) + get_arg_flag_value("--target").is_some() } /// Returns whether or not Cargo invoked the wrapper (this binary) to compile - /// the final, target crate (either a test for 'cargo test', or a binary for 'cargo run') + /// the final, binary crate (either a test for 'cargo test', or a binary for 'cargo run') /// Cargo does not give us this information directly, so we need to check /// various command-line flags. fn is_runnable_crate() -> bool { From e73fc97f0b9b7db87e977c3051699d959c603a6e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 9 May 2020 11:52:26 +0200 Subject: [PATCH 2044/3747] cargo-miri: honor RUSTC env var --- src/bin/cargo-miri.rs | 35 +++++++++++++++-------------------- 1 file changed, 15 insertions(+), 20 deletions(-) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 0d73c7cf853a4..44106955e0f4c 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -6,6 +6,7 @@ use std::io::{self, BufRead, Write}; use std::ops::Not; use std::path::{Path, PathBuf}; use std::process::Command; +use std::ffi::OsString; const XARGO_MIN_VERSION: (u32, u32, u32) = (0, 3, 20); @@ -85,29 +86,23 @@ fn get_arg_flag_value(name: &str) -> Option { } } -/// Returns the path to the `miri` binary -fn find_miri() -> PathBuf { +/// Returns a command for the right `miri` binary. +fn miri() -> Command { let mut path = std::env::current_exe().expect("current executable path invalid"); path.set_file_name("miri"); - path + Command::new(path) } fn cargo() -> Command { - if let Ok(val) = std::env::var("CARGO") { - // Bootstrap tells us where to find cargo - Command::new(val) - } else { - Command::new("cargo") - } + Command::new(env::var_os("CARGO").unwrap_or_else(|| OsString::from("cargo"))) } fn xargo_check() -> Command { - if let Ok(val) = std::env::var("XARGO_CHECK") { - // Bootstrap tells us where to find xargo - Command::new(val) - } else { - Command::new("xargo-check") - } + Command::new(env::var_os("XARGO_CHECK").unwrap_or_else(|| OsString::from("xargo-check"))) +} + +fn rustc() -> Command { + Command::new(env::var_os("RUSTC").unwrap_or_else(|| OsString::from("rustc"))) } fn list_targets() -> impl Iterator { @@ -188,8 +183,8 @@ fn test_sysroot_consistency() { return; } - let rustc_sysroot = get_sysroot(Command::new("rustc")); - let miri_sysroot = get_sysroot(Command::new(find_miri())); + let rustc_sysroot = get_sysroot(rustc()); + let miri_sysroot = get_sysroot(miri()); if rustc_sysroot != miri_sysroot { show_error(format!( @@ -301,7 +296,7 @@ fn setup(subcommand: MiriCommand) { Ok(val) => PathBuf::from(val), Err(_) => { // Check for `rust-src` rustup component. - let sysroot = Command::new("rustc") + let sysroot = rustc() .args(&["--print", "sysroot"]) .output() .expect("failed to get rustc sysroot") @@ -554,9 +549,9 @@ fn inside_cargo_rustc() { serde_json::from_str(&magic).expect("failed to deserialize MIRI_ARGS"); args.append(&mut user_args); // Run this in Miri. - Command::new(find_miri()) + miri() } else { - Command::new("rustc") + rustc() }; // Run it. From 1ba42b9f55b11a13a507534e9b832b4d754d6435 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 9 May 2020 11:53:24 +0200 Subject: [PATCH 2045/3747] Wording Co-authored-by: Oliver Scherer --- src/bin/cargo-miri.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 44106955e0f4c..8b238a7f79729 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -500,7 +500,7 @@ fn inside_cargo_rustc() { /// be built like normal; target crates need to be built for or interpreted /// by Miri. /// - /// Currently, we detect this by checking for "--target=", which flag is + /// Currently, we detect this by checking for "--target=", which is /// never set for host crates. This matches what rustc bootstrap does, /// which hopefully makes it "reliable enough". fn is_target_crate() -> bool { From 20097be2feaaa92c3a2843fb1c57c6a28d3dcf29 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 9 May 2020 11:54:35 +0200 Subject: [PATCH 2046/3747] more comment --- src/bin/cargo-miri.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 8b238a7f79729..8bd9947092a78 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -502,7 +502,8 @@ fn inside_cargo_rustc() { /// /// Currently, we detect this by checking for "--target=", which is /// never set for host crates. This matches what rustc bootstrap does, - /// which hopefully makes it "reliable enough". + /// which hopefully makes it "reliable enough". This relies on us always + /// invoking cargo itself with `--target`, which `in_cargo_miri` ensures. fn is_target_crate() -> bool { get_arg_flag_value("--target").is_some() } From 024cc435f4e19e2d34f8e2099f8da1fb2bf1b952 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 9 May 2020 11:58:18 +0200 Subject: [PATCH 2047/3747] avoid env::var which requires valid UTF-8 --- src/bin/cargo-miri.rs | 15 +++++++++------ src/bin/miri.rs | 9 +++++---- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 8bd9947092a78..37ab41b317db5 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -269,7 +269,7 @@ fn ask_to_run(mut cmd: Command, ask: bool, text: &str) { /// `MIRI_SYSROOT`. Skipped if `MIRI_SYSROOT` is already set, in which case we expect the user has /// done all this already. fn setup(subcommand: MiriCommand) { - if std::env::var("MIRI_SYSROOT").is_ok() { + if std::env::var_os("MIRI_SYSROOT").is_some() { if subcommand == MiriCommand::Setup { println!("WARNING: MIRI_SYSROOT already set, not doing anything.") } @@ -282,7 +282,7 @@ fn setup(subcommand: MiriCommand) { // First, we need xargo. if xargo_version().map_or(true, |v| v < XARGO_MIN_VERSION) { - if std::env::var("XARGO_CHECK").is_ok() { + if std::env::var_os("XARGO_CHECK").is_some() { // The user manually gave us a xargo binary; don't do anything automatically. show_error(format!("Your xargo is too old; please upgrade to the latest version")) } @@ -292,9 +292,9 @@ fn setup(subcommand: MiriCommand) { } // Determine where the rust sources are located. `XARGO_RUST_SRC` env var trumps everything. - let rust_src = match std::env::var("XARGO_RUST_SRC") { - Ok(val) => PathBuf::from(val), - Err(_) => { + let rust_src = match std::env::var_os("XARGO_RUST_SRC") { + Some(val) => PathBuf::from(val), + None => { // Check for `rust-src` rustup component. let sysroot = rustc() .args(&["--print", "sysroot"]) @@ -522,7 +522,7 @@ fn inside_cargo_rustc() { is_bin || is_test } - let verbose = std::env::var("MIRI_VERBOSE").is_ok(); + let verbose = std::env::var_os("MIRI_VERBOSE").is_some(); let target_crate = is_target_crate(); // Figure out which arguments we need to pass. @@ -531,6 +531,7 @@ fn inside_cargo_rustc() { // other args for target crates - that is, crates which are ultimately // going to get interpreted by Miri. if target_crate { + // FIXME: breaks for non-UTF-8 sysroots (use `var_os` instead). let sysroot = std::env::var("MIRI_SYSROOT").expect("The wrapper should have set MIRI_SYSROOT"); args.push("--sysroot".to_owned()); @@ -545,6 +546,8 @@ fn inside_cargo_rustc() { // we want to interpret under Miri. We deserialize the user-provided arguments // from the special environment variable "MIRI_ARGS", and feed them // to the 'miri' binary. + // + // `env::var` is okay here, well-formed JSON is always UTF-8. let magic = std::env::var("MIRI_ARGS").expect("missing MIRI_ARGS"); let mut user_args: Vec = serde_json::from_str(&magic).expect("failed to deserialize MIRI_ARGS"); diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 06101fe24e2d8..31f78aa9895af 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -61,7 +61,7 @@ fn init_early_loggers() { // If it is not set, we avoid initializing now so that we can initialize // later with our custom settings, and *not* log anything for what happens before // `miri` gets started. - if env::var("RUSTC_LOG").is_ok() { + if env::var_os("RUSTC_LOG").is_some() { rustc_driver::init_rustc_env_logger(); } } @@ -69,8 +69,9 @@ fn init_early_loggers() { fn init_late_loggers(tcx: TyCtxt<'_>) { // We initialize loggers right before we start evaluation. We overwrite the `RUSTC_LOG` // env var if it is not set, control it based on `MIRI_LOG`. + // (FIXE: use `var_os`, but then we need to manually concatenate instead of `format!`.) if let Ok(var) = env::var("MIRI_LOG") { - if env::var("RUSTC_LOG").is_err() { + if env::var_os("RUSTC_LOG").is_none() { // We try to be a bit clever here: if `MIRI_LOG` is just a single level // used for everything, we only apply it to the parts of rustc that are // CTFE-related. Otherwise, we use it verbatim for `RUSTC_LOG`. @@ -90,8 +91,8 @@ fn init_late_loggers(tcx: TyCtxt<'_>) { // If `MIRI_BACKTRACE` is set and `RUSTC_CTFE_BACKTRACE` is not, set `RUSTC_CTFE_BACKTRACE`. // Do this late, so we ideally only apply this to Miri's errors. - if let Ok(val) = env::var("MIRI_BACKTRACE") { - let ctfe_backtrace = match &*val { + if let Some(val) = env::var_os("MIRI_BACKTRACE") { + let ctfe_backtrace = match &*val.to_string_lossy() { "immediate" => CtfeBacktrace::Immediate, "0" => CtfeBacktrace::Disabled, _ => CtfeBacktrace::Capture, From ba801a45dbbc9075f4bf13ee4b6b57c311e331ff Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 9 May 2020 12:24:30 +0200 Subject: [PATCH 2048/3747] make Miri work in rustc bootstrap stage 0 --- README.md | 7 +++++++ src/bin/cargo-miri.rs | 49 ++++++++++++++++++++++++++++--------------- src/bin/miri.rs | 6 ++++++ 3 files changed, 45 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index 35d15d59ee4db..1dd4a91e822fd 100644 --- a/README.md +++ b/README.md @@ -222,6 +222,13 @@ Moreover, Miri recognizes some environment variables: * `MIRI_TEST_FLAGS` (recognized by the test suite) defines extra flags to be passed to Miri. +The following environment variables are internal, but used to communicate between +different Miri binaries, and as such worht documenting: + +* `MIRI_BE_RUSTC` when set to any value tells the Miri driver to actually not + interpret the code but compile it like rustc would. This is useful to be sure + that the compiled `rlib`s are compatible with Miri. + ## Contributing and getting help If you want to contribute to Miri, great! Please check out our diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 37ab41b317db5..a1f502ab262fb 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -86,11 +86,15 @@ fn get_arg_flag_value(name: &str) -> Option { } } -/// Returns a command for the right `miri` binary. -fn miri() -> Command { +/// Returns the path to the `miri` binary +fn find_miri() -> PathBuf { let mut path = std::env::current_exe().expect("current executable path invalid"); path.set_file_name("miri"); - Command::new(path) + path +} + +fn miri() -> Command { + Command::new(find_miri()) } fn cargo() -> Command { @@ -322,7 +326,8 @@ fn setup(subcommand: MiriCommand) { show_error(format!("Given Rust source directory `{}` does not exist.", rust_src.display())); } - // Next, we need our own libstd. We will do this work in whatever is a good cache dir for this platform. + // Next, we need our own libstd. Prepare a xargo project for that purpose. + // We will do this work in whatever is a good cache dir for this platform. let dirs = directories::ProjectDirs::from("org", "rust-lang", "miri").unwrap(); let dir = dirs.cache_dir(); if !dir.exists() { @@ -360,20 +365,31 @@ path = "lib.rs" ) .unwrap(); File::create(dir.join("lib.rs")).unwrap(); - // Prepare xargo invocation. + + // Determine architectures. + // We always need to set a target so rustc bootstrap can tell apart host from target crates. + let host = rustc_version::version_meta().unwrap().host; let target = get_arg_flag_value("--target"); - let print_sysroot = subcommand == MiriCommand::Setup - && has_arg_flag("--print-sysroot"); // whether we just print the sysroot path + let target = target.as_ref().unwrap_or(&host); + // Now invoke xargo. let mut command = xargo_check(); command.arg("build").arg("-q"); + command.arg("--target").arg(target); command.current_dir(&dir); - command.env("RUSTFLAGS", miri::miri_default_args().join(" ")); command.env("XARGO_HOME", &dir); command.env("XARGO_RUST_SRC", &rust_src); - // Handle target flag. - if let Some(target) = &target { - command.arg("--target").arg(target); + // Use Miri as rustc to build a libstd compatible with us (and use the right flags). + // However, when we are running in bootstrap, we cannot just overwrite `RUSTC`, + // because we still need bootstrap to distinguish between host and target crates. + // In that case we overwrite `RUSTC_REAL` instead which determines the rustc used + // for target crates. + if env::var_os("RUSTC_STAGE").is_some() { + command.env("RUSTC_REAL", find_miri()); + } else { + command.env("RUSTC", find_miri()); } + command.env("MIRI_BE_RUSTC", "1"); + command.env("RUSTFLAGS", miri::miri_default_args().join(" ")); // Finally run it! if command.status().expect("failed to run xargo").success().not() { show_error(format!("Failed to run xargo")); @@ -382,12 +398,11 @@ path = "lib.rs" // That should be it! But we need to figure out where xargo built stuff. // Unfortunately, it puts things into a different directory when the // architecture matches the host. - let is_host = match &target { - None => true, - Some(target) => target == &rustc_version::version_meta().unwrap().host, - }; - let sysroot = if is_host { dir.join("HOST") } else { PathBuf::from(dir) }; + let sysroot = if target == &host { dir.join("HOST") } else { PathBuf::from(dir) }; std::env::set_var("MIRI_SYSROOT", &sysroot); // pass the env var to the processes we spawn, which will turn it into "--sysroot" flags + // Figure out what to print. + let print_sysroot = subcommand == MiriCommand::Setup + && has_arg_flag("--print-sysroot"); // whether we just print the sysroot path if print_sysroot { // Print just the sysroot and nothing else; this way we do not need any escaping. println!("{}", sysroot.display()); @@ -476,7 +491,7 @@ fn in_cargo_miri() { // Set `RUSTC_WRAPPER` to ourselves. Cargo will prepend that binary to its usual invocation, // i.e., the first argument is `rustc` -- which is what we use in `main` to distinguish - // the two codepaths. + // the two codepaths. (That extra argument is why we prefer this over setting `RUSTC`.) let path = std::env::current_exe().expect("current executable path invalid"); cmd.env("RUSTC_WRAPPER", path); if verbose { diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 31f78aa9895af..1e382a5a9bea2 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -124,6 +124,12 @@ fn compile_time_sysroot() -> Option { } fn main() { + // If the environment asks us to actually be rustc, then do that. + if env::var_os("MIRI_BE_RUSTC").is_some() { + eprintln!("miri-as-rustc called with args: {:?}", env::args()); + return rustc_driver::main(); + } + init_early_loggers(); // Parse our arguments and split them across `rustc` and `miri`. From ac65350789d7f6be1b1b4942d6a3e0b54e9bca3c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 9 May 2020 13:20:34 +0200 Subject: [PATCH 2049/3747] adjust default sysroot when being rustc Also while at it, refactor how we pass the default Miri flags --- src/bin/miri.rs | 95 ++++++++++++++++++++++++++++--------------------- 1 file changed, 54 insertions(+), 41 deletions(-) diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 1e382a5a9bea2..c9391cec66f0f 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -16,7 +16,6 @@ use log::debug; use rustc_session::CtfeBacktrace; use rustc_driver::Compilation; use rustc_hir::def_id::LOCAL_CRATE; -use rustc_interface::{interface, Queries}; use rustc_middle::ty::TyCtxt; struct MiriCompilerCalls { @@ -26,8 +25,8 @@ struct MiriCompilerCalls { impl rustc_driver::Callbacks for MiriCompilerCalls { fn after_analysis<'tcx>( &mut self, - compiler: &interface::Compiler, - queries: &'tcx Queries<'tcx>, + compiler: &rustc_interface::interface::Compiler, + queries: &'tcx rustc_interface::Queries<'tcx>, ) -> Compilation { compiler.session().abort_if_errors(); @@ -106,12 +105,12 @@ fn init_late_loggers(tcx: TyCtxt<'_>) { fn compile_time_sysroot() -> Option { if option_env!("RUSTC_STAGE").is_some() { // This is being built as part of rustc, and gets shipped with rustup. - // We can rely on the sysroot computation in librustc. + // We can rely on the sysroot computation in librustc_session. return None; } // For builds outside rustc, we need to ensure that we got a sysroot - // that gets used as a default. The sysroot computation in librustc would - // end up somewhere in the build dir. + // that gets used as a default. The sysroot computation in librustc_session would + // end up somewhere in the build dir (see `get_or_default_sysroot`). // Taken from PR . let home = option_env!("RUSTUP_HOME").or(option_env!("MULTIRUST_HOME")); let toolchain = option_env!("RUSTUP_TOOLCHAIN").or(option_env!("MULTIRUST_TOOLCHAIN")); @@ -123,13 +122,47 @@ fn compile_time_sysroot() -> Option { }) } +/// Execute a compiler with the given CLI arguments and callbacks. +fn run_compiler(mut args: Vec, callbacks: &mut (dyn rustc_driver::Callbacks + Send)) { + // Make sure we use the right default sysroot. The default sysroot is wrong, + // because `get_or_default_sysroot` in `librustc_session` bases that on `current_exe`. + // + // Make sure we always call `compile_time_sysroot` as that also does some sanity-checks + // of the environment we were built in. + // FIXME: Ideally we'd turn a bad build env into a compile-time error via CTFE or so. + if let Some(sysroot) = compile_time_sysroot() { + let sysroot_flag = "--sysroot"; + if !args.iter().any(|e| e == sysroot_flag) { + // We need to overwrite the default that librustc_session would compute. + args.push(sysroot_flag.to_owned()); + args.push(sysroot); + } + } + + // Invoke compiler, and handle return code. + let result = rustc_driver::catch_fatal_errors(move || { + rustc_driver::run_compiler(&args, callbacks, None, None) + }) + .and_then(|result| result); + let exit_code = match result { + Ok(()) => rustc_driver::EXIT_SUCCESS, + Err(_) => rustc_driver::EXIT_FAILURE, + }; + std::process::exit(exit_code); +} + fn main() { + rustc_driver::install_ice_hook(); + // If the environment asks us to actually be rustc, then do that. if env::var_os("MIRI_BE_RUSTC").is_some() { - eprintln!("miri-as-rustc called with args: {:?}", env::args()); - return rustc_driver::main(); + rustc_driver::init_rustc_env_logger(); + // We cannot use `rustc_driver::main` as we need to adjust the CLI arguments. + let mut callbacks = rustc_driver::TimePassesCallbacks::default(); + return run_compiler(env::args().collect(), &mut callbacks); } + // Init loggers the Miri way. init_early_loggers(); // Parse our arguments and split them across `rustc` and `miri`. @@ -142,16 +175,20 @@ fn main() { let mut tracked_pointer_tag: Option = None; let mut tracked_alloc_id: Option = None; let mut rustc_args = vec![]; - let mut miri_args = vec![]; + let mut crate_args = vec![]; let mut after_dashdash = false; let mut excluded_env_vars = vec![]; - for arg in std::env::args() { + for arg in env::args() { if rustc_args.is_empty() { - // Very first arg: for `rustc`. + // Very first arg: binary name. rustc_args.push(arg); + // After this, push Miri default args (before everything else so they can be overwritten). + for arg in miri::miri_default_args().iter() { + rustc_args.push(arg.to_string()); + } } else if after_dashdash { - // Everything that comes after are `miri` args. - miri_args.push(arg); + // Everything that comes after `--` is forwarded to the interpreted crate. + crate_args.push(arg); } else { match arg.as_str() { "-Zmiri-disable-validation" => { @@ -227,30 +264,15 @@ fn main() { tracked_alloc_id = Some(miri::AllocId(id)); } _ => { + // Forward to rustc. rustc_args.push(arg); } } } } - // Determine sysroot if needed. Make sure we always call `compile_time_sysroot` - // as that also does some sanity-checks of the environment we were built in. - // FIXME: Ideally we'd turn a bad build env into a compile-time error, but - // CTFE does not seem powerful enough for that yet. - if let Some(sysroot) = compile_time_sysroot() { - let sysroot_flag = "--sysroot"; - if !rustc_args.iter().any(|e| e == sysroot_flag) { - // We need to overwrite the default that librustc would compute. - rustc_args.push(sysroot_flag.to_owned()); - rustc_args.push(sysroot); - } - } - - // Finally, add the default flags all the way in the beginning, but after the binary name. - rustc_args.splice(1..1, miri::miri_default_args().iter().map(ToString::to_string)); - debug!("rustc arguments: {:?}", rustc_args); - debug!("miri arguments: {:?}", miri_args); + debug!("crate arguments: {:?}", crate_args); let miri_config = miri::MiriConfig { validate, stacked_borrows, @@ -259,18 +281,9 @@ fn main() { ignore_leaks, excluded_env_vars, seed, - args: miri_args, + args: crate_args, tracked_pointer_tag, tracked_alloc_id, }; - rustc_driver::install_ice_hook(); - let result = rustc_driver::catch_fatal_errors(move || { - rustc_driver::run_compiler(&rustc_args, &mut MiriCompilerCalls { miri_config }, None, None) - }) - .and_then(|result| result); - let exit_code = match result { - Ok(()) => rustc_driver::EXIT_SUCCESS, - Err(_) => rustc_driver::EXIT_FAILURE, - }; - std::process::exit(exit_code); + return run_compiler(rustc_args, &mut MiriCompilerCalls { miri_config }); } From e65d87b110dd6890a3bd5b52198a535d8b91d355 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 9 May 2020 14:08:58 +0200 Subject: [PATCH 2050/3747] Typo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 1dd4a91e822fd..057ff5e7ce841 100644 --- a/README.md +++ b/README.md @@ -223,7 +223,7 @@ Moreover, Miri recognizes some environment variables: passed to Miri. The following environment variables are internal, but used to communicate between -different Miri binaries, and as such worht documenting: +different Miri binaries, and as such worth documenting: * `MIRI_BE_RUSTC` when set to any value tells the Miri driver to actually not interpret the code but compile it like rustc would. This is useful to be sure From 3fdab9c44681247a94b8d09e4396b6058751ffcb Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Fri, 8 May 2020 13:56:10 +0200 Subject: [PATCH 2051/3747] Update to rustc changes --- src/machine.rs | 4 ++-- src/thread.rs | 7 +++---- tests/compile-fail/validity/invalid_wide_raw.rs | 2 +- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/machine.rs b/src/machine.rs index 3853f65599596..51aa7ae31047a 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -427,7 +427,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { fn canonical_alloc_id(mem: &Memory<'mir, 'tcx, Self>, id: AllocId) -> AllocId { let tcx = mem.tcx; // Figure out if this is an extern static, and if yes, which one. - let def_id = match tcx.alloc_map.lock().get(id) { + let def_id = match tcx.get_global_alloc(id) { Some(GlobalAlloc::Static(def_id)) if tcx.is_foreign_item(def_id) => def_id, _ => { // No need to canonicalize anything. @@ -494,7 +494,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { if Some(id) == memory_extra.tracked_alloc_id { register_diagnostic(NonHaltingDiagnostic::FreedAlloc(id)); } - + Ok(()) } diff --git a/src/thread.rs b/src/thread.rs index 2119175e12cc9..d78beed28cfb7 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -428,7 +428,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx match *val { mir::interpret::ConstValue::Scalar(Scalar::Ptr(ref mut ptr)) => { let alloc_id = ptr.alloc_id; - let alloc = this.tcx.alloc_map.lock().get(alloc_id); + let alloc = this.tcx.get_global_alloc(alloc_id); let tcx = this.tcx; let is_thread_local = |def_id| { tcx.codegen_fn_attrs(def_id).flags.contains(CodegenFnAttrFlags::THREAD_LOCAL) @@ -489,13 +489,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx })?; let id = raw_const.alloc_id; // Extract the allocation from the query result. - let mut alloc_map = tcx.alloc_map.lock(); - let allocation = alloc_map.unwrap_memory(id); + let allocation = tcx.global_alloc(id).unwrap_memory(); // Create a new allocation id for the same allocation in this hacky // way. Internally, `alloc_map` deduplicates allocations, but this // is fine because Miri will make a copy before a first mutable // access. - let new_alloc_id = alloc_map.create_memory_alloc(allocation); + let new_alloc_id = tcx.create_memory_alloc(allocation); this.machine.threads.set_thread_local_alloc_id(def_id, new_alloc_id); Ok(new_alloc_id) } diff --git a/tests/compile-fail/validity/invalid_wide_raw.rs b/tests/compile-fail/validity/invalid_wide_raw.rs index c232672132227..6e0809b15ca43 100644 --- a/tests/compile-fail/validity/invalid_wide_raw.rs +++ b/tests/compile-fail/validity/invalid_wide_raw.rs @@ -6,5 +6,5 @@ fn main() { struct S { x: * mut dyn T } - dbg!(S { x: unsafe { std::mem::transmute((0usize, 0usize)) } }); //~ ERROR: encountered dangling vtable pointer + dbg!(S { x: unsafe { std::mem::transmute((0usize, 0usize)) } }); //~ ERROR: encountered dangling vtable pointer in wide pointer } From 4f06197aff96b84905d973ce5a46d43b9a3062f8 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 10 May 2020 10:32:29 +0200 Subject: [PATCH 2052/3747] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index d53d4d68e486a..aafee80cbe02d 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -0f9088f9610618e724cfc0cf2ba3721918be5ec9 +6f5c7827b71d1e1e4831fa7522e49acaf2a9e44e From 81046fa5e5d8780449c5afd2ce3ec505563a5f76 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 10 May 2020 18:41:03 +0200 Subject: [PATCH 2053/3747] cargo-miri: never invoke rustc, always go through 'MIRI_BE_RUSTC=1 miri' instead --- src/bin/cargo-miri.rs | 123 ++++++++++++------------------------------ src/bin/miri.rs | 8 +-- 2 files changed, 38 insertions(+), 93 deletions(-) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index a1f502ab262fb..2e1609e1edff5 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -8,6 +8,8 @@ use std::path::{Path, PathBuf}; use std::process::Command; use std::ffi::OsString; +use rustc_version::VersionMeta; + const XARGO_MIN_VERSION: (u32, u32, u32) = (0, 3, 20); const CARGO_MIRI_HELP: &str = r#"Interprets bin crates and tests in Miri @@ -97,6 +99,10 @@ fn miri() -> Command { Command::new(find_miri()) } +fn version_info() -> VersionMeta { + VersionMeta::for_command(miri()).expect("failed to determine underlying rustc version of Miri") +} + fn cargo() -> Command { Command::new(env::var_os("CARGO").unwrap_or_else(|| OsString::from("cargo"))) } @@ -105,10 +111,6 @@ fn xargo_check() -> Command { Command::new(env::var_os("XARGO_CHECK").unwrap_or_else(|| OsString::from("xargo-check"))) } -fn rustc() -> Command { - Command::new(env::var_os("RUSTC").unwrap_or_else(|| OsString::from("rustc"))) -} - fn list_targets() -> impl Iterator { // We need to get the manifest, and then the metadata, to enumerate targets. let manifest_path = @@ -153,55 +155,6 @@ fn list_targets() -> impl Iterator { package.targets.into_iter() } -/// Make sure that the `miri` and `rustc` binary are from the same sysroot. -/// This can be violated e.g. when miri is locally built and installed with a different -/// toolchain than what is used when `cargo miri` is run. -fn test_sysroot_consistency() { - fn get_sysroot(mut cmd: Command) -> PathBuf { - let out = cmd - .arg("--print") - .arg("sysroot") - .output() - .expect("Failed to run rustc to get sysroot info"); - let stdout = String::from_utf8(out.stdout).expect("stdout is not valid UTF-8"); - let stderr = String::from_utf8(out.stderr).expect("stderr is not valid UTF-8"); - assert!( - out.status.success(), - "Bad status code {} when getting sysroot info via {:?}.\nstdout:\n{}\nstderr:\n{}", - out.status, - cmd, - stdout, - stderr, - ); - let stdout = stdout.trim(); - PathBuf::from(stdout) - .canonicalize() - .unwrap_or_else(|_| panic!("Failed to canonicalize sysroot: {}", stdout)) - } - - // Do not check sysroots if we got built as part of a Rust distribution. - // During `bootstrap`, the sysroot does not match anyway, and then some distros - // play symlink tricks so the sysroots may be different even for the final stage - // (see ). - if option_env!("RUSTC_STAGE").is_some() { - return; - } - - let rustc_sysroot = get_sysroot(rustc()); - let miri_sysroot = get_sysroot(miri()); - - if rustc_sysroot != miri_sysroot { - show_error(format!( - "miri was built for a different sysroot than the rustc in your current toolchain.\n\ - Make sure you use the same toolchain to run miri that you used to build it!\n\ - rustc sysroot: `{}`\n\ - miri sysroot: `{}`", - rustc_sysroot.display(), - miri_sysroot.display() - )); - } -} - fn xargo_version() -> Option<(u32, u32, u32)> { let out = xargo_check().arg("--version").output().ok()?; if !out.status.success() { @@ -300,10 +253,10 @@ fn setup(subcommand: MiriCommand) { Some(val) => PathBuf::from(val), None => { // Check for `rust-src` rustup component. - let sysroot = rustc() + let sysroot = miri() .args(&["--print", "sysroot"]) .output() - .expect("failed to get rustc sysroot") + .expect("failed to determine sysroot") .stdout; let sysroot = std::str::from_utf8(&sysroot).unwrap(); let sysroot = Path::new(sysroot.trim_end_matches('\n')); @@ -316,7 +269,7 @@ fn setup(subcommand: MiriCommand) { ask_to_run( cmd, ask_user, - "install the rustc-src component for the selected toolchain", + "install the `rust-src` component for the selected toolchain", ); } rustup_src @@ -368,7 +321,7 @@ path = "lib.rs" // Determine architectures. // We always need to set a target so rustc bootstrap can tell apart host from target crates. - let host = rustc_version::version_meta().unwrap().host; + let host = version_info().host; let target = get_arg_flag_value("--target"); let target = target.as_ref().unwrap_or(&host); // Now invoke xargo. @@ -424,9 +377,6 @@ fn in_cargo_miri() { }; let verbose = has_arg_flag("-v"); - // Some basic sanity checks - test_sysroot_consistency(); - // We always setup. setup(subcommand); if subcommand == MiriCommand::Setup { @@ -478,7 +428,7 @@ fn in_cargo_miri() { if get_arg_flag_value("--target").is_none() { // When no `--target` is given, default to the host. cmd.arg("--target"); - cmd.arg(rustc_version::version_meta().unwrap().host); + cmd.arg(version_info().host); } // Serialize the remaining args into a special environemt variable. @@ -540,51 +490,46 @@ fn inside_cargo_rustc() { let verbose = std::env::var_os("MIRI_VERBOSE").is_some(); let target_crate = is_target_crate(); - // Figure out which arguments we need to pass. - let mut args: Vec = std::env::args().skip(2).collect(); // skip `cargo-miri rustc` - // We make sure to only specify our custom Xargo sysroot and - // other args for target crates - that is, crates which are ultimately - // going to get interpreted by Miri. + let mut cmd = miri(); + // Forward arguments. + cmd.args(std::env::args().skip(2)); // skip `cargo-miri rustc` + + // We make sure to only specify our custom Xargo sysroot for target crates - that is, + // crates which are ultimately going to get interpreted by Miri. if target_crate { - // FIXME: breaks for non-UTF-8 sysroots (use `var_os` instead). let sysroot = - std::env::var("MIRI_SYSROOT").expect("The wrapper should have set MIRI_SYSROOT"); - args.push("--sysroot".to_owned()); - args.push(sysroot); - args.splice(0..0, miri::miri_default_args().iter().map(ToString::to_string)); + env::var_os("MIRI_SYSROOT").expect("The wrapper should have set MIRI_SYSROOT"); + cmd.arg("--sysroot"); + cmd.arg(sysroot); } - // Figure out the binary we need to call. If this is a runnable target crate, we want to call - // Miri to start interpretation; otherwise we want to call rustc to build the crate as usual. - let mut command = if target_crate && is_runnable_crate() { - // This is the 'target crate' - the binary or test crate that - // we want to interpret under Miri. We deserialize the user-provided arguments - // from the special environment variable "MIRI_ARGS", and feed them - // to the 'miri' binary. + // If this is a runnable target crate, we want Miri to start interpretation; + // otherwise we want Miri to behave like rustc and build the crate as usual. + if target_crate && is_runnable_crate() { + // This is the binary or test crate that we want to interpret under Miri. + // We deserialize the arguments that are meant for Miri from the special environment + // variable "MIRI_ARGS", and feed them to the 'miri' binary. // // `env::var` is okay here, well-formed JSON is always UTF-8. let magic = std::env::var("MIRI_ARGS").expect("missing MIRI_ARGS"); - let mut user_args: Vec = + let miri_args: Vec = serde_json::from_str(&magic).expect("failed to deserialize MIRI_ARGS"); - args.append(&mut user_args); - // Run this in Miri. - miri() + cmd.args(miri_args); } else { - rustc() + // We want to compile, not interpret. + cmd.env("MIRI_BE_RUSTC", "1"); }; // Run it. - command.args(&args); if verbose { - eprintln!("+ {:?}", command); + eprintln!("+ {:?}", cmd); } - - match command.status() { + match cmd.status() { Ok(exit) => if !exit.success() { std::process::exit(exit.code().unwrap_or(42)); }, - Err(e) => panic!("error running {:?}:\n{:?}", command, e), + Err(e) => panic!("error running {:?}:\n{:?}", cmd, e), } } @@ -609,6 +554,6 @@ fn main() { // dependencies get dispatched to `rustc`, the final test/binary to `miri`. inside_cargo_rustc(); } else { - show_error(format!("must be called with either `miri` or `rustc` as first argument.")) + show_error(format!("`cargo-miri` must be called with either `miri` or `rustc` as first argument.")) } } diff --git a/src/bin/miri.rs b/src/bin/miri.rs index c9391cec66f0f..ff3872f2fd02c 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -139,6 +139,10 @@ fn run_compiler(mut args: Vec, callbacks: &mut (dyn rustc_driver::Callba } } + // Some options have different defaults in Miri than in plain rustc; apply those by making + // them the first arguments after the binary name (but later arguments can overwrite them). + args.splice(1..1, miri::miri_default_args().iter().map(ToString::to_string)); + // Invoke compiler, and handle return code. let result = rustc_driver::catch_fatal_errors(move || { rustc_driver::run_compiler(&args, callbacks, None, None) @@ -182,10 +186,6 @@ fn main() { if rustc_args.is_empty() { // Very first arg: binary name. rustc_args.push(arg); - // After this, push Miri default args (before everything else so they can be overwritten). - for arg in miri::miri_default_args().iter() { - rustc_args.push(arg.to_string()); - } } else if after_dashdash { // Everything that comes after `--` is forwarded to the interpreted crate. crate_args.push(arg); From 12114c5137682cb99673d2757ed2af9b2dfc2113 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 10 May 2020 18:52:21 +0200 Subject: [PATCH 2054/3747] fix dead link in README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 057ff5e7ce841..26d9b39fdd8e9 100644 --- a/README.md +++ b/README.md @@ -156,7 +156,7 @@ Try deleting `~/.cache/miri`. This means the sysroot you are using was not compiled with Miri in mind. This should never happen when you use `cargo miri` because that takes care of setting up the sysroot. If you are using `miri` (the Miri driver) directly, see -[below][testing-miri] for how to set up the sysroot. +[CONTRIBUTING.md](CONTRIBUTING.md) for how to use `./miri`. ## Miri `-Z` flags and environment variables From 845b89c23607516b5cae90cc3c925c9ab32059c7 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 10 May 2020 18:56:38 +0200 Subject: [PATCH 2055/3747] we do not need to set RUSTFLAGS for xargo any more as miri-as-rustc already uses these flags --- src/bin/cargo-miri.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 2e1609e1edff5..ca7fafd3d9c2d 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -342,7 +342,6 @@ path = "lib.rs" command.env("RUSTC", find_miri()); } command.env("MIRI_BE_RUSTC", "1"); - command.env("RUSTFLAGS", miri::miri_default_args().join(" ")); // Finally run it! if command.status().expect("failed to run xargo").success().not() { show_error(format!("Failed to run xargo")); From 938fe00f0246afe007850a362aa2050151772baa Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 11 May 2020 00:07:59 +0200 Subject: [PATCH 2056/3747] fix some comments, and run_compiler return type --- README.md | 4 ++-- src/bin/cargo-miri.rs | 8 +++----- src/bin/miri.rs | 10 +++++----- 3 files changed, 10 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 26d9b39fdd8e9..02fbd6cdfacfa 100644 --- a/README.md +++ b/README.md @@ -155,8 +155,8 @@ Try deleting `~/.cache/miri`. This means the sysroot you are using was not compiled with Miri in mind. This should never happen when you use `cargo miri` because that takes care of setting -up the sysroot. If you are using `miri` (the Miri driver) directly, see -[CONTRIBUTING.md](CONTRIBUTING.md) for how to use `./miri`. +up the sysroot. If you are using `miri` (the Miri driver) directly, see the +[contributors' guide](CONTRIBUTING.md) for how to use `./miri` to best do that. ## Miri `-Z` flags and environment variables diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index ca7fafd3d9c2d..b2e5238489f2f 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -479,10 +479,6 @@ fn inside_cargo_rustc() { fn is_runnable_crate() -> bool { let is_bin = get_arg_flag_value("--crate-type").as_deref() == Some("bin"); let is_test = has_arg_flag("--test"); - - // The final runnable (under Miri) crate will either be a binary crate - // or a test crate. We make sure to exclude build scripts here, since - // they are also build with "--crate-type bin" is_bin || is_test } @@ -494,7 +490,8 @@ fn inside_cargo_rustc() { cmd.args(std::env::args().skip(2)); // skip `cargo-miri rustc` // We make sure to only specify our custom Xargo sysroot for target crates - that is, - // crates which are ultimately going to get interpreted by Miri. + // crates which are needed for interpretation by Miri. proc-macros and build scripts + // should use the default sysroot. if target_crate { let sysroot = env::var_os("MIRI_SYSROOT").expect("The wrapper should have set MIRI_SYSROOT"); @@ -506,6 +503,7 @@ fn inside_cargo_rustc() { // otherwise we want Miri to behave like rustc and build the crate as usual. if target_crate && is_runnable_crate() { // This is the binary or test crate that we want to interpret under Miri. + // (Testing `target_crate` is needed to exclude build scripts.) // We deserialize the arguments that are meant for Miri from the special environment // variable "MIRI_ARGS", and feed them to the 'miri' binary. // diff --git a/src/bin/miri.rs b/src/bin/miri.rs index ff3872f2fd02c..96de81b624307 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -68,7 +68,7 @@ fn init_early_loggers() { fn init_late_loggers(tcx: TyCtxt<'_>) { // We initialize loggers right before we start evaluation. We overwrite the `RUSTC_LOG` // env var if it is not set, control it based on `MIRI_LOG`. - // (FIXE: use `var_os`, but then we need to manually concatenate instead of `format!`.) + // (FIXME: use `var_os`, but then we need to manually concatenate instead of `format!`.) if let Ok(var) = env::var("MIRI_LOG") { if env::var_os("RUSTC_LOG").is_none() { // We try to be a bit clever here: if `MIRI_LOG` is just a single level @@ -123,7 +123,7 @@ fn compile_time_sysroot() -> Option { } /// Execute a compiler with the given CLI arguments and callbacks. -fn run_compiler(mut args: Vec, callbacks: &mut (dyn rustc_driver::Callbacks + Send)) { +fn run_compiler(mut args: Vec, callbacks: &mut (dyn rustc_driver::Callbacks + Send)) -> ! { // Make sure we use the right default sysroot. The default sysroot is wrong, // because `get_or_default_sysroot` in `librustc_session` bases that on `current_exe`. // @@ -152,7 +152,7 @@ fn run_compiler(mut args: Vec, callbacks: &mut (dyn rustc_driver::Callba Ok(()) => rustc_driver::EXIT_SUCCESS, Err(_) => rustc_driver::EXIT_FAILURE, }; - std::process::exit(exit_code); + std::process::exit(exit_code) } fn main() { @@ -163,7 +163,7 @@ fn main() { rustc_driver::init_rustc_env_logger(); // We cannot use `rustc_driver::main` as we need to adjust the CLI arguments. let mut callbacks = rustc_driver::TimePassesCallbacks::default(); - return run_compiler(env::args().collect(), &mut callbacks); + run_compiler(env::args().collect(), &mut callbacks) } // Init loggers the Miri way. @@ -285,5 +285,5 @@ fn main() { tracked_pointer_tag, tracked_alloc_id, }; - return run_compiler(rustc_args, &mut MiriCompilerCalls { miri_config }); + run_compiler(rustc_args, &mut MiriCompilerCalls { miri_config }) } From 88fc42bbc8f9589bdbcca9d86026e4673b54deee Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 11 May 2020 10:37:35 +0200 Subject: [PATCH 2057/3747] compiletest: no need to call rustc here --- tests/compiletest.rs | 34 ++++++++-------------------------- 1 file changed, 8 insertions(+), 26 deletions(-) diff --git a/tests/compiletest.rs b/tests/compiletest.rs index ca18799620895..17125de9f55fb 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -9,23 +9,11 @@ use colored::*; use compiletest_rs as compiletest; fn miri_path() -> PathBuf { - if rustc_test_suite().is_some() { - PathBuf::from(option_env!("MIRI_PATH").unwrap()) - } else { - PathBuf::from(env!("CARGO_BIN_EXE_miri")) - } -} - -fn rustc_test_suite() -> Option { - option_env!("RUSTC_TEST_SUITE").map(PathBuf::from) -} - -fn rustc_lib_path() -> PathBuf { - option_env!("RUSTC_LIB_PATH").unwrap().into() + PathBuf::from(option_env!("MIRI_PATH").unwrap_or(env!("CARGO_BIN_EXE_miri"))) } fn run_tests(mode: &str, path: &str, target: &str) { - let in_rustc_test_suite = rustc_test_suite().is_some(); + let in_rustc_test_suite = option_env!("RUSTC_STAGE").is_some(); // Add some flags we always want. let mut flags = Vec::new(); flags.push("--edition 2018".to_owned()); @@ -50,9 +38,9 @@ fn run_tests(mode: &str, path: &str, target: &str) { let mut config = compiletest::Config::default().tempdir(); config.mode = mode.parse().expect("Invalid mode"); config.rustc_path = miri_path(); - if in_rustc_test_suite { - config.run_lib_path = rustc_lib_path(); - config.compile_lib_path = rustc_lib_path(); + if let Some(lib_path) = option_env!("RUSTC_LIB_PATH") { + config.run_lib_path = PathBuf::from(lib_path); + config.compile_lib_path = PathBuf::from(lib_path); } config.filter = env::args().nth(1); config.host = get_host(); @@ -91,15 +79,9 @@ fn miri_pass(path: &str, target: &str) { } fn get_host() -> String { - let rustc = rustc_test_suite().unwrap_or(PathBuf::from("rustc")); - let rustc_version = std::process::Command::new(rustc) - .arg("-vV") - .output() - .expect("rustc not found for -vV") - .stdout; - let rustc_version = std::str::from_utf8(&rustc_version).expect("rustc -vV is not utf8"); - let version_meta = rustc_version::version_meta_for(&rustc_version) - .expect("failed to parse rustc version info"); + let version_meta = rustc_version::VersionMeta::for_command( + std::process::Command::new(miri_path()) + ).expect("failed to parse rustc version info"); version_meta.host } From 791ec8fef740ecbf3ad63ae1c5a3001e1ec45598 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 11 May 2020 10:54:21 +0200 Subject: [PATCH 2058/3747] fmt --- tests/compiletest.rs | 24 +++++++++--------------- 1 file changed, 9 insertions(+), 15 deletions(-) diff --git a/tests/compiletest.rs b/tests/compiletest.rs index 17125de9f55fb..2be0661b93ee0 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -53,12 +53,9 @@ fn run_tests(mode: &str, path: &str, target: &str) { fn compile_fail(path: &str, target: &str) { eprintln!( "{}", - format!( - "## Running compile-fail tests in {} against miri for target {}", - path, target - ) - .green() - .bold() + format!("## Running compile-fail tests in {} against miri for target {}", path, target) + .green() + .bold() ); run_tests("compile-fail", path, target); @@ -67,21 +64,18 @@ fn compile_fail(path: &str, target: &str) { fn miri_pass(path: &str, target: &str) { eprintln!( "{}", - format!( - "## Running run-pass tests in {} against miri for target {}", - path, target - ) - .green() - .bold() + format!("## Running run-pass tests in {} against miri for target {}", path, target) + .green() + .bold() ); run_tests("ui", path, target); } fn get_host() -> String { - let version_meta = rustc_version::VersionMeta::for_command( - std::process::Command::new(miri_path()) - ).expect("failed to parse rustc version info"); + let version_meta = + rustc_version::VersionMeta::for_command(std::process::Command::new(miri_path())) + .expect("failed to parse rustc version info"); version_meta.host } From 880e6847cfb895459a183346f62767f4a9f31660 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 10 May 2020 23:49:10 +0200 Subject: [PATCH 2059/3747] play with bash on AppVeyor Also consistently order and format our two CI files --- .appveyor.yml | 106 +++++++++++++++------------------------------ .travis.yml | 48 +++++++++----------- travis.sh => ci.sh | 19 ++++---- 3 files changed, 67 insertions(+), 106 deletions(-) rename travis.sh => ci.sh (73%) diff --git a/.appveyor.yml b/.appveyor.yml index 294ef26be0bed..209e38dc532a3 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -1,84 +1,50 @@ +build: off # No Visual Studio auto-build. environment: - global: - PROJECT_NAME: miri - matrix: - - TARGET: i686-pc-windows-msvc + global: + PROJECT_NAME: miri + matrix: + - TARGET: i686-pc-windows-msvc +matrix: + fast_finish: true # Immediately finish build once one of the jobs fails. +cache: +- '%USERPROFILE%\.cargo' +- '%USERPROFILE%\.rustup' # branches to build branches: # whitelist only: - - auto - - try - -matrix: - fast_finish: true # set this flag to immediately finish build once one of the jobs fails. - -cache: - - '%USERPROFILE%\.cargo' - - '%USERPROFILE%\.rustup' + - auto + - try install: - # Compute the rust version we use - - set /p RUSTC_HASH= Date: Mon, 11 May 2020 10:13:17 +0200 Subject: [PATCH 2060/3747] fix warnings for non-Unix builds --- src/shims/fs.rs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/shims/fs.rs b/src/shims/fs.rs index 0de0b33fb2e29..8613f6bb0994e 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -549,12 +549,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx target_op: OpTy<'tcx, Tag>, linkpath_op: OpTy<'tcx, Tag> ) -> InterpResult<'tcx, i32> { - #[cfg(target_family = "unix")] + #[cfg(unix)] fn create_link(src: &Path, dst: &Path) -> std::io::Result<()> { std::os::unix::fs::symlink(src, dst) } - #[cfg(target_family = "windows")] + #[cfg(windows)] fn create_link(src: &Path, dst: &Path) -> std::io::Result<()> { use std::os::windows::fs; if src.is_dir() { @@ -816,7 +816,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.check_no_isolation("mkdir")?; - let _mode = if this.tcx.sess.target.target.target_os == "macos" { + #[cfg_attr(not(unix), allow(unused_variables))] + let mode = if this.tcx.sess.target.target.target_os == "macos" { u32::from(this.read_scalar(mode_op)?.not_undef()?.to_u16()?) } else { this.read_scalar(mode_op)?.to_u32()? @@ -824,14 +825,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let path = this.read_path_from_c_str(this.read_scalar(path_op)?.not_undef()?)?; + #[cfg_attr(not(unix), allow(unused_mut))] let mut builder = DirBuilder::new(); // If the host supports it, forward on the mode of the directory // (i.e. permission bits and the sticky bit) - #[cfg(target_family = "unix")] + #[cfg(unix)] { use std::os::unix::fs::DirBuilderExt; - builder.mode(_mode.into()); + builder.mode(mode.into()); } let result = builder.create(path).map(|_| 0i32); From fdebecbb086a6f1a4606d50a53231ae69eb1a47a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 11 May 2020 10:40:25 +0200 Subject: [PATCH 2061/3747] fix python interpreter on Windows --- .appveyor.yml | 1 + ci.sh | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.appveyor.yml b/.appveyor.yml index 209e38dc532a3..741a1de11a80a 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -38,6 +38,7 @@ install: - cargo --version test_script: +- set PYTHON=C:\msys64\mingw64\bin\python3.exe - bash ci.sh after_test: diff --git a/ci.sh b/ci.sh index 4bc039e607ba8..ecc881919deeb 100755 --- a/ci.sh +++ b/ci.sh @@ -29,7 +29,7 @@ function run_tests { fi # "miri test" has built the sysroot for us, now this should pass without # any interactive questions. - test-cargo-miri/run-test.py + ${PYTHON:-python3} test-cargo-miri/run-test.py echo } From dec0bf15f67d5181917d02a469756d91059ebace Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 11 May 2020 10:59:01 +0200 Subject: [PATCH 2062/3747] Windows CI: rely on stable cargo --- .appveyor.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index 741a1de11a80a..34887459f6d93 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -29,10 +29,8 @@ install: - rustup toolchain uninstall beta nightly - rustup update # Install "master" toolchain. -# We need to install cargo here as well or else the DLL search path inside `cargo run` -# will be for the wrong toolchain. (On Unix, `./miri` takes care of this, but not here.) - cargo install rustup-toolchain-install-master -- rustup-toolchain-install-master -f -n master %RUSTC_HASH% -c rust-src -c rustc-dev -c cargo +- rustup-toolchain-install-master -f -n master %RUSTC_HASH% -c rust-src -c rustc-dev - rustup default master - rustc --version - cargo --version From 131bdf88a759e3737d1eb28801e7816340f236b5 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 11 May 2020 11:19:26 +0200 Subject: [PATCH 2063/3747] always lock on CI --- ci.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci.sh b/ci.sh index ecc881919deeb..a7254f2958a0a 100755 --- a/ci.sh +++ b/ci.sh @@ -25,7 +25,7 @@ function run_tests { ./miri test --locked if ! [ -n "${MIRI_TEST_TARGET+exists}" ]; then # Only for host architecture: tests with MIR optimizations - MIRI_TEST_FLAGS="-Z mir-opt-level=3" ./miri test + MIRI_TEST_FLAGS="-Z mir-opt-level=3" ./miri test --locked fi # "miri test" has built the sysroot for us, now this should pass without # any interactive questions. From aaa3208432ac25739f38c81b0646234afa62fafa Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 14 May 2020 19:21:04 +0200 Subject: [PATCH 2064/3747] test Linux on macOS host --- ci.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/ci.sh b/ci.sh index a7254f2958a0a..922469aeca542 100755 --- a/ci.sh +++ b/ci.sh @@ -42,6 +42,7 @@ if [ "${TRAVIS_OS_NAME:-}" == linux ]; then MIRI_TEST_TARGET=x86_64-apple-darwin run_tests MIRI_TEST_TARGET=i686-pc-windows-msvc run_tests elif [ "${TRAVIS_OS_NAME:-}" == osx ]; then + MIRI_TEST_TARGET=i686-unknown-linux-gnu run_tests MIRI_TEST_TARGET=x86_64-pc-windows-msvc run_tests MIRI_TEST_TARGET=i686-pc-windows-gnu run_tests elif [ "${CI_WINDOWS:-}" == True ]; then From e0f9081c5cdcf21d3e02c1e31bac5a5d95a4c581 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 16 May 2020 11:30:11 +0200 Subject: [PATCH 2065/3747] use new rustc_driver::catch_with_exit_code --- rust-version | 2 +- src/bin/miri.rs | 9 ++------- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/rust-version b/rust-version index aafee80cbe02d..b1b25c4bcab68 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -6f5c7827b71d1e1e4831fa7522e49acaf2a9e44e +84539360498cab3c70a7c9114c0b8106c8e1b06b diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 96de81b624307..48e4a60c71f94 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -144,14 +144,9 @@ fn run_compiler(mut args: Vec, callbacks: &mut (dyn rustc_driver::Callba args.splice(1..1, miri::miri_default_args().iter().map(ToString::to_string)); // Invoke compiler, and handle return code. - let result = rustc_driver::catch_fatal_errors(move || { + let exit_code = rustc_driver::catch_with_exit_code(move || { rustc_driver::run_compiler(&args, callbacks, None, None) - }) - .and_then(|result| result); - let exit_code = match result { - Ok(()) => rustc_driver::EXIT_SUCCESS, - Err(_) => rustc_driver::EXIT_FAILURE, - }; + }); std::process::exit(exit_code) } From e22baedb1f1099488cdfcc49f561ec24ea457395 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 17 May 2020 10:08:45 +0200 Subject: [PATCH 2066/3747] add test suite filter example to README and 'cargo miri --help' --- README.md | 11 ++++++----- src/bin/cargo-miri.rs | 6 +++++- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 02fbd6cdfacfa..12fc6d22cf85d 100644 --- a/README.md +++ b/README.md @@ -83,16 +83,17 @@ Now you can run your project in Miri: The first time you run Miri, it will perform some extra setup and install some dependencies. It will ask you for confirmation before installing anything. +You can pass arguments to Miri after the first `--`, and pass arguments to the +interpreted program or test suite after the second `--`. For example, `cargo +miri run -- -Zmiri-disable-stacked-borrows` runs the program without checking +the aliasing of references. To filter the tests being run, use `cargo miri test +-- -- filter`. + Miri supports cross-execution: if you want to run the program as if it was a Linux program, you can do `cargo miri run --target x86_64-unknown-linux-gnu`. This is particularly useful if you are using Windows, as the Linux target is much better supported than Windows targets. -You can pass arguments to Miri after the first `--`, and pass arguments to the -interpreted program or test suite after the second `--`. For example, `cargo -miri run -- -Zmiri-disable-validation` runs the program without validation of -basic type invariants and without checking the aliasing of references. - When compiling code via `cargo miri`, the `miri` config flag is set. You can use this to ignore test cases that fail under Miri because they do things Miri does not support: diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index b2e5238489f2f..5dadd3f931db2 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -15,7 +15,7 @@ const XARGO_MIN_VERSION: (u32, u32, u32) = (0, 3, 20); const CARGO_MIRI_HELP: &str = r#"Interprets bin crates and tests in Miri Usage: - cargo miri [subcommand] [options] [--] [...] [--] [...] + cargo miri [subcommand] [...] [--] [...] [--] [...] Subcommands: run Run binaries (default) @@ -30,6 +30,10 @@ Common options: Other [options] are the same as `cargo check`. Everything after the first "--" is passed verbatim to Miri, which will pass everything after the second "--" verbatim to the interpreted program. + +Examples: + cargo miri run -- -Zmiri-disable-stacked-borrows + cargo miri test -- -- test-suite-filter "#; #[derive(Copy, Clone, Debug, PartialEq, Eq)] From d90a087df9830e08db88f83fc7da3c1b2609c10c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 17 May 2020 11:20:05 +0200 Subject: [PATCH 2067/3747] fix libstd rebuilds due to RUSTFLAGS changes --- src/bin/cargo-miri.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 5dadd3f931db2..12f59c05b0a94 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -335,6 +335,7 @@ path = "lib.rs" command.current_dir(&dir); command.env("XARGO_HOME", &dir); command.env("XARGO_RUST_SRC", &rust_src); + command.env_remove("RUSTFLAGS"); // Make sure external `RUSTFLAGS` do not influence the build. // Use Miri as rustc to build a libstd compatible with us (and use the right flags). // However, when we are running in bootstrap, we cannot just overwrite `RUSTC`, // because we still need bootstrap to distinguish between host and target crates. From 87c46944482a8cc5a7256fc0d5dcd9fd015b51d6 Mon Sep 17 00:00:00 2001 From: David Cook Date: Tue, 21 Apr 2020 22:01:40 -0500 Subject: [PATCH 2068/3747] Add file sync shims Adds implementations for fsync, fdatasync, and sync_file_range --- src/shims/foreign_items/posix.rs | 8 ++++ src/shims/foreign_items/posix/linux.rs | 5 +++ src/shims/fs.rs | 62 ++++++++++++++++++++++++++ tests/run-pass/fs.rs | 24 ++++++++++ tests/run-pass/libc.rs | 36 ++++++++++++++- 5 files changed, 134 insertions(+), 1 deletion(-) diff --git a/src/shims/foreign_items/posix.rs b/src/shims/foreign_items/posix.rs index 951a40293b72d..6311f0a4a9fc4 100644 --- a/src/shims/foreign_items/posix.rs +++ b/src/shims/foreign_items/posix.rs @@ -136,6 +136,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // "lseek" is only used on macOS which is 64bit-only, so `i64` always works. this.write_scalar(Scalar::from_i64(result), dest)?; } + "fsync" => { + let result = this.fsync(args[0])?; + this.write_scalar(Scalar::from_i32(result), dest)?; + } + "fdatasync" => { + let result = this.fdatasync(args[0])?; + this.write_scalar(Scalar::from_i32(result), dest)?; + } // Allocation "posix_memalign" => { diff --git a/src/shims/foreign_items/posix/linux.rs b/src/shims/foreign_items/posix/linux.rs index e0f54cac1570a..16d7d059e73b2 100644 --- a/src/shims/foreign_items/posix/linux.rs +++ b/src/shims/foreign_items/posix/linux.rs @@ -54,6 +54,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // fadvise is only informational, we can ignore it. this.write_null(dest)?; } + // Linux-only + "sync_file_range" => { + let result = this.sync_file_range(args[0], args[1], args[2], args[3])?; + this.write_scalar(Scalar::from_i32(result), dest)?; + } // Time related shims "clock_gettime" => { diff --git a/src/shims/fs.rs b/src/shims/fs.rs index 8613f6bb0994e..b7579f6cb732e 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -375,6 +375,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fh.insert_fd_with_min_fd(FileHandle { file: duplicated, writable }, start) }); this.try_unwrap_io_result(fd_result) + } else if this.tcx.sess.target.target.target_os == "macos" + && cmd == this.eval_libc_i32("F_FULLFSYNC")? + { + if let Some(FileHandle { file, writable: _ }) = this.machine.file_handler.handles.get_mut(&fd) { + let result = file.sync_all(); + this.try_unwrap_io_result(result.map(|_| 0i32)) + } else { + this.handle_not_found() + } } else { throw_unsup_format!("the {:#x} command is not supported for `fcntl`)", cmd); } @@ -1103,6 +1112,59 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.handle_not_found() } } + + fn fsync(&mut self, fd_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + let this = self.eval_context_mut(); + + this.check_no_isolation("fsync")?; + + let fd = this.read_scalar(fd_op)?.to_i32()?; + if let Some(FileHandle { file, writable: _ }) = this.machine.file_handler.handles.get_mut(&fd) { + let result = file.sync_all(); + this.try_unwrap_io_result(result.map(|_| 0i32)) + } else { + this.handle_not_found() + } + } + + fn fdatasync(&mut self, fd_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + let this = self.eval_context_mut(); + + this.check_no_isolation("fdatasync")?; + + let fd = this.read_scalar(fd_op)?.to_i32()?; + if let Some(FileHandle { file, writable: _ }) = this.machine.file_handler.handles.get_mut(&fd) { + let result = file.sync_data(); + this.try_unwrap_io_result(result.map(|_| 0i32)) + } else { + this.handle_not_found() + } + } + + fn sync_file_range( + &mut self, + fd_op: OpTy<'tcx, Tag>, + offset_op: OpTy<'tcx, Tag>, + nbytes_op: OpTy<'tcx, Tag>, + flags_op: OpTy<'tcx, Tag>, + ) -> InterpResult<'tcx, i32> { + let this = self.eval_context_mut(); + + this.check_no_isolation("sync_file_range")?; + + let fd = this.read_scalar(fd_op)?.to_i32()?; + let _offset = this.read_scalar(offset_op)?.to_i64()?; + let _nbytes = this.read_scalar(nbytes_op)?.to_i64()?; + let _flags = this.read_scalar(flags_op)?.to_u32()?; + if let Some(FileHandle { file, writable: _ }) = this.machine.file_handler.handles.get_mut(&fd) { + // In the interest of host compatibility, we conservatively ignore + // offset, nbytes, and flags, and sync the entire file. + let result = file.sync_data(); + this.try_unwrap_io_result(result.map(|_| 0i32)) + } else { + this.handle_not_found() + } + } } /// Extracts the number of seconds and nanoseconds elapsed between `time` and the unix epoch when diff --git a/tests/run-pass/fs.rs b/tests/run-pass/fs.rs index 1a139de8148ae..df022a7c70d8e 100644 --- a/tests/run-pass/fs.rs +++ b/tests/run-pass/fs.rs @@ -14,6 +14,8 @@ fn main() { test_seek(); test_metadata(); test_file_set_len(); + test_file_sync_all(); + test_file_sync_data(); test_symlink(); test_errors(); test_rename(); @@ -182,6 +184,28 @@ fn test_file_set_len() { remove_file(&path).unwrap(); } +fn test_file_sync_all() { + let bytes = b"Hello, World!\n"; + let path = prepare_with_content("miri_test_fs_sync_all.txt", bytes); + + // Test that we can call sync_all (can't readily test effects of this operation) + let file = File::open(&path).unwrap(); + file.sync_all().unwrap(); + + remove_file(&path).unwrap(); +} + +fn test_file_sync_data() { + let bytes = b"Hello, World!\n"; + let path = prepare_with_content("miri_test_fs_sync_data.txt", bytes); + + // Test that we can call sync_data (can't readily test effects of this operation) + let file = File::open(&path).unwrap(); + file.sync_data().unwrap(); + + remove_file(&path).unwrap(); +} + fn test_symlink() { let bytes = b"Hello, World!\n"; let path = prepare_with_content("miri_test_fs_link_target.txt", bytes); diff --git a/tests/run-pass/libc.rs b/tests/run-pass/libc.rs index 04ca5c0b3b1a9..5897c46f63755 100644 --- a/tests/run-pass/libc.rs +++ b/tests/run-pass/libc.rs @@ -17,7 +17,7 @@ fn test_posix_fadvise() { use std::io::Write; use std::os::unix::io::AsRawFd; - let path = tmp().join("miri_test_libc.txt"); + let path = tmp().join("miri_test_libc_posix_fadvise.txt"); // Cleanup before test remove_file(&path).ok(); @@ -40,6 +40,37 @@ fn test_posix_fadvise() { assert_eq!(result, 0); } +#[cfg(target_os = "linux")] +fn test_sync_file_range() { + use std::fs::{remove_file, File}; + use std::io::Write; + use std::os::unix::io::AsRawFd; + + let path = tmp().join("miri_test_libc_sync_file_range.txt"); + // Cleanup before test + remove_file(&path).ok(); + + // Write to a file + let mut file = File::create(&path).unwrap(); + let bytes = b"Hello, World!\n"; + file.write(bytes).unwrap(); + + // Test calling sync_file_range on a file. + let result = unsafe { + libc::sync_file_range( + file.as_raw_fd(), + 0, + 0, + libc::SYNC_FILE_RANGE_WAIT_BEFORE + | libc::SYNC_FILE_RANGE_WRITE + | libc::SYNC_FILE_RANGE_WAIT_AFTER, + ) + }; + drop(file); + remove_file(&path).unwrap(); + assert_eq!(result, 0); +} + fn test_mutex_libc_init_recursive() { unsafe { let mut attr: libc::pthread_mutexattr_t = std::mem::zeroed(); @@ -169,6 +200,9 @@ fn main() { #[cfg(target_os = "linux")] test_posix_fadvise(); + #[cfg(target_os = "linux")] + test_sync_file_range(); + test_mutex_libc_init_recursive(); test_mutex_libc_init_normal(); test_mutex_libc_init_errorcheck(); From 0b060c73648169ef6ff261ff323880a240619475 Mon Sep 17 00:00:00 2001 From: David Cook Date: Tue, 19 May 2020 08:57:31 -0500 Subject: [PATCH 2069/3747] Review comments --- src/shims/foreign_items/posix.rs | 6 ++++-- src/shims/foreign_items/posix/linux.rs | 4 ++-- src/shims/fs.rs | 25 ++++++++++++++++++++++--- tests/run-pass/fs.rs | 21 +++++---------------- 4 files changed, 33 insertions(+), 23 deletions(-) diff --git a/src/shims/foreign_items/posix.rs b/src/shims/foreign_items/posix.rs index 6311f0a4a9fc4..14d072d8e3c08 100644 --- a/src/shims/foreign_items/posix.rs +++ b/src/shims/foreign_items/posix.rs @@ -137,11 +137,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_i64(result), dest)?; } "fsync" => { - let result = this.fsync(args[0])?; + let &[fd] = check_arg_count(args)?; + let result = this.fsync(fd)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "fdatasync" => { - let result = this.fdatasync(args[0])?; + let &[fd] = check_arg_count(args)?; + let result = this.fdatasync(fd)?; this.write_scalar(Scalar::from_i32(result), dest)?; } diff --git a/src/shims/foreign_items/posix/linux.rs b/src/shims/foreign_items/posix/linux.rs index 16d7d059e73b2..bc6ae89966d7c 100644 --- a/src/shims/foreign_items/posix/linux.rs +++ b/src/shims/foreign_items/posix/linux.rs @@ -54,9 +54,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // fadvise is only informational, we can ignore it. this.write_null(dest)?; } - // Linux-only "sync_file_range" => { - let result = this.sync_file_range(args[0], args[1], args[2], args[3])?; + let &[fd, offset, nbytes, flags] = check_arg_count(args)?; + let result = this.sync_file_range(fd, offset, nbytes, flags)?; this.write_scalar(Scalar::from_i32(result), dest)?; } diff --git a/src/shims/fs.rs b/src/shims/fs.rs index b7579f6cb732e..ac405138f5244 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -378,6 +378,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } else if this.tcx.sess.target.target.target_os == "macos" && cmd == this.eval_libc_i32("F_FULLFSYNC")? { + // On macOS, fsync does not wait for the underlying disk to finish writing, while this + // F_FULLFSYNC operation does. The standard library uses F_FULLFSYNC for both + // File::sync_data() and File::sync_all(). + let &[_, _] = check_arg_count(args)?; if let Some(FileHandle { file, writable: _ }) = this.machine.file_handler.handles.get_mut(&fd) { let result = file.sync_all(); this.try_unwrap_io_result(result.map(|_| 0i32)) @@ -1153,9 +1157,24 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.check_no_isolation("sync_file_range")?; let fd = this.read_scalar(fd_op)?.to_i32()?; - let _offset = this.read_scalar(offset_op)?.to_i64()?; - let _nbytes = this.read_scalar(nbytes_op)?.to_i64()?; - let _flags = this.read_scalar(flags_op)?.to_u32()?; + let offset = this.read_scalar(offset_op)?.to_i64()?; + let nbytes = this.read_scalar(nbytes_op)?.to_i64()?; + let flags = this.read_scalar(flags_op)?.to_i32()?; + + if offset < 0 || nbytes < 0 { + let einval = this.eval_libc("EINVAL")?; + this.set_last_error(einval)?; + return Ok(-1); + } + let allowed_flags = this.eval_libc_i32("SYNC_FILE_RANGE_WAIT_BEFORE")? + | this.eval_libc_i32("SYNC_FILE_RANGE_WRITE")? + | this.eval_libc_i32("SYNC_FILE_RANGE_WAIT_AFTER")?; + if flags & allowed_flags != flags { + let einval = this.eval_libc("EINVAL")?; + this.set_last_error(einval)?; + return Ok(-1); + } + if let Some(FileHandle { file, writable: _ }) = this.machine.file_handler.handles.get_mut(&fd) { // In the interest of host compatibility, we conservatively ignore // offset, nbytes, and flags, and sync the entire file. diff --git a/tests/run-pass/fs.rs b/tests/run-pass/fs.rs index df022a7c70d8e..d831129dc80fb 100644 --- a/tests/run-pass/fs.rs +++ b/tests/run-pass/fs.rs @@ -14,8 +14,7 @@ fn main() { test_seek(); test_metadata(); test_file_set_len(); - test_file_sync_all(); - test_file_sync_data(); + test_file_sync(); test_symlink(); test_errors(); test_rename(); @@ -184,24 +183,14 @@ fn test_file_set_len() { remove_file(&path).unwrap(); } -fn test_file_sync_all() { +fn test_file_sync() { let bytes = b"Hello, World!\n"; - let path = prepare_with_content("miri_test_fs_sync_all.txt", bytes); + let path = prepare_with_content("miri_test_fs_sync.txt", bytes); - // Test that we can call sync_all (can't readily test effects of this operation) - let file = File::open(&path).unwrap(); - file.sync_all().unwrap(); - - remove_file(&path).unwrap(); -} - -fn test_file_sync_data() { - let bytes = b"Hello, World!\n"; - let path = prepare_with_content("miri_test_fs_sync_data.txt", bytes); - - // Test that we can call sync_data (can't readily test effects of this operation) + // Test that we can call sync_data and sync_all (can't readily test effects of this operation) let file = File::open(&path).unwrap(); file.sync_data().unwrap(); + file.sync_all().unwrap(); remove_file(&path).unwrap(); } From cc1a2119f68ae05f625e150c15521bc006db60f9 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 20 May 2020 00:00:35 +0200 Subject: [PATCH 2070/3747] adjust for changed allocation strategy --- rust-version | 2 +- tests/run-pass/heap.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/rust-version b/rust-version index b1b25c4bcab68..7b8f0d43c89e7 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -84539360498cab3c70a7c9114c0b8106c8e1b06b +672b272077561ca7b5027a8aff9ea2957c7d4c21 diff --git a/tests/run-pass/heap.rs b/tests/run-pass/heap.rs index b533f91646988..44537e74b5a44 100644 --- a/tests/run-pass/heap.rs +++ b/tests/run-pass/heap.rs @@ -14,12 +14,12 @@ fn allocate_reallocate() { // 6 byte heap alloc (__rust_allocate) s.push_str("foobar"); assert_eq!(s.len(), 6); - assert_eq!(s.capacity(), 6); + assert_eq!(s.capacity(), 8); // heap size doubled to 12 (__rust_reallocate) s.push_str("baz"); assert_eq!(s.len(), 9); - assert_eq!(s.capacity(), 12); + assert_eq!(s.capacity(), 16); // heap size reduced to 9 (__rust_reallocate) s.shrink_to_fit(); From 00a4421573fd420990167ec5ea2358cb19928846 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 21 May 2020 15:43:26 +0200 Subject: [PATCH 2071/3747] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 7b8f0d43c89e7..1465f2b175c2c 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -672b272077561ca7b5027a8aff9ea2957c7d4c21 +82911b3bba76e73afe2881b732fe6b0edb35d5d3 From 08ddbd6ce024e1bee9a11d61f52dc0e3b753c616 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 21 May 2020 22:38:06 +0200 Subject: [PATCH 2072/3747] prepare Dlsym system for dynamic symbols on Windows --- src/shims/dlsym.rs | 19 ++++++++++++++----- src/shims/foreign_items/posix.rs | 4 +--- src/shims/foreign_items/windows.rs | 11 ++++++++--- 3 files changed, 23 insertions(+), 11 deletions(-) diff --git a/src/shims/dlsym.rs b/src/shims/dlsym.rs index 3c4a942b596fb..1416db346cd03 100644 --- a/src/shims/dlsym.rs +++ b/src/shims/dlsym.rs @@ -11,12 +11,21 @@ pub enum Dlsym { impl Dlsym { // Returns an error for unsupported symbols, and None if this symbol // should become a NULL pointer (pretend it does not exist). - pub fn from_str(name: &str) -> InterpResult<'static, Option> { + pub fn from_str(name: &[u8], target_os: &str) -> InterpResult<'static, Option> { use self::Dlsym::*; - Ok(match name { - "getentropy" => Some(GetEntropy), - "__pthread_get_minstack" => None, - _ => throw_unsup_format!("unsupported dlsym: {}", name), + let name = String::from_utf8_lossy(name); + Ok(match target_os { + "linux" | "macos" => match &*name { + "getentropy" => Some(GetEntropy), + "__pthread_get_minstack" => None, + _ => throw_unsup_format!("unsupported dlsym: {}", name), + } + "windows" => match &*name { + "SetThreadStackGuarantee" => None, + "AcquireSRWLockExclusive" => None, + _ => throw_unsup_format!("unsupported dlsym: {}", name), + } + os => bug!("dlsym not implemented for target_os {}", os), }) } } diff --git a/src/shims/foreign_items/posix.rs b/src/shims/foreign_items/posix.rs index 951a40293b72d..39b00feec1943 100644 --- a/src/shims/foreign_items/posix.rs +++ b/src/shims/foreign_items/posix.rs @@ -173,9 +173,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.read_scalar(handle)?.not_undef()?; let symbol = this.read_scalar(symbol)?.not_undef()?; let symbol_name = this.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); - if let Some(dlsym) = Dlsym::from_str(symbol_name)? { + if let Some(dlsym) = Dlsym::from_str(symbol_name, &this.tcx.sess.target.target.target_os)? { let ptr = this.memory.create_fn_alloc(FnVal::Other(dlsym)); this.write_scalar(Scalar::from(ptr), dest)?; } else { diff --git a/src/shims/foreign_items/windows.rs b/src/shims/foreign_items/windows.rs index 7f3cd03cd2d36..a11e3b8aa6a01 100644 --- a/src/shims/foreign_items/windows.rs +++ b/src/shims/foreign_items/windows.rs @@ -260,9 +260,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "GetProcAddress" if this.frame().instance.to_string().starts_with("std::sys::windows::") => { #[allow(non_snake_case)] - let &[_hModule, _lpProcName] = check_arg_count(args)?; - // Pretend this does not exist / nothing happened, by returning zero. - this.write_null(dest)?; + let &[_hModule, lpProcName] = check_arg_count(args)?; + let name = this.memory.read_c_str(this.read_scalar(lpProcName)?.not_undef()?)?; + if let Some(dlsym) = Dlsym::from_str(name, &this.tcx.sess.target.target.target_os)? { + let ptr = this.memory.create_fn_alloc(FnVal::Other(dlsym)); + this.write_scalar(Scalar::from(ptr), dest)?; + } else { + this.write_null(dest)?; + } } "SetConsoleTextAttribute" if this.frame().instance.to_string().starts_with("std::sys::windows::") => { #[allow(non_snake_case)] From f09decb398f86ebfb7938b5aca39202acb50d45e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 21 May 2020 23:00:59 +0200 Subject: [PATCH 2073/3747] disentangle macos and linux dlsyms --- src/shims/dlsym.rs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/shims/dlsym.rs b/src/shims/dlsym.rs index 1416db346cd03..301687092813b 100644 --- a/src/shims/dlsym.rs +++ b/src/shims/dlsym.rs @@ -15,15 +15,18 @@ impl Dlsym { use self::Dlsym::*; let name = String::from_utf8_lossy(name); Ok(match target_os { - "linux" | "macos" => match &*name { - "getentropy" => Some(GetEntropy), + "linux" => match &*name { "__pthread_get_minstack" => None, - _ => throw_unsup_format!("unsupported dlsym: {}", name), + _ => throw_unsup_format!("unsupported Linux dlsym: {}", name), + } + "macos" => match &*name { + "getentropy" => Some(GetEntropy), + _ => throw_unsup_format!("unsupported macOS dlsym: {}", name), } "windows" => match &*name { "SetThreadStackGuarantee" => None, "AcquireSRWLockExclusive" => None, - _ => throw_unsup_format!("unsupported dlsym: {}", name), + _ => throw_unsup_format!("unsupported Windows dlsym: {}", name), } os => bug!("dlsym not implemented for target_os {}", os), }) From 526fae75413392dcfd05256145c5503011d9c89a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 21 May 2020 23:06:31 +0200 Subject: [PATCH 2074/3747] GetProcAddress: basic validation for hModule argument --- src/shims/foreign_items/windows.rs | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/src/shims/foreign_items/windows.rs b/src/shims/foreign_items/windows.rs index a11e3b8aa6a01..60448406a67de 100644 --- a/src/shims/foreign_items/windows.rs +++ b/src/shims/foreign_items/windows.rs @@ -206,6 +206,20 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_i32(result), dest)?; } + // Dynamic symbol loading + "GetProcAddress" => { + #[allow(non_snake_case)] + let &[hModule, lpProcName] = check_arg_count(args)?; + this.read_scalar(hModule)?.not_undef()?; + let name = this.memory.read_c_str(this.read_scalar(lpProcName)?.not_undef()?)?; + if let Some(dlsym) = Dlsym::from_str(name, &this.tcx.sess.target.target.target_os)? { + let ptr = this.memory.create_fn_alloc(FnVal::Other(dlsym)); + this.write_scalar(Scalar::from(ptr), dest)?; + } else { + this.write_null(dest)?; + } + } + // Miscellaneous "SystemFunction036" => { // The actual name of 'RtlGenRandom' @@ -258,17 +272,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Pretend this does not exist / nothing happened, by returning zero. this.write_null(dest)?; } - "GetProcAddress" if this.frame().instance.to_string().starts_with("std::sys::windows::") => { - #[allow(non_snake_case)] - let &[_hModule, lpProcName] = check_arg_count(args)?; - let name = this.memory.read_c_str(this.read_scalar(lpProcName)?.not_undef()?)?; - if let Some(dlsym) = Dlsym::from_str(name, &this.tcx.sess.target.target.target_os)? { - let ptr = this.memory.create_fn_alloc(FnVal::Other(dlsym)); - this.write_scalar(Scalar::from(ptr), dest)?; - } else { - this.write_null(dest)?; - } - } "SetConsoleTextAttribute" if this.frame().instance.to_string().starts_with("std::sys::windows::") => { #[allow(non_snake_case)] let &[_hConsoleOutput, _wAttribute] = check_arg_count(args)?; From 402535ef8639b4ba42ad4c1be7ff50542f8104d1 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 21 May 2020 23:24:37 +0200 Subject: [PATCH 2075/3747] also pretend GetSystemTimePreciseAsFileTime does not exist --- src/shims/dlsym.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/shims/dlsym.rs b/src/shims/dlsym.rs index 301687092813b..87c7f447ac03c 100644 --- a/src/shims/dlsym.rs +++ b/src/shims/dlsym.rs @@ -26,6 +26,7 @@ impl Dlsym { "windows" => match &*name { "SetThreadStackGuarantee" => None, "AcquireSRWLockExclusive" => None, + "GetSystemTimePreciseAsFileTime" => None, _ => throw_unsup_format!("unsupported Windows dlsym: {}", name), } os => bug!("dlsym not implemented for target_os {}", os), From 11d9409e82e68876dd292c364d4bfaf66220de36 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 22 May 2020 09:00:32 +0200 Subject: [PATCH 2076/3747] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 1465f2b175c2c..0b9281beeb4f4 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -82911b3bba76e73afe2881b732fe6b0edb35d5d3 +458a3e76294fd859fb037f425404180c91e14767 From 42a3e8783861e82a58a769df8e2e718b38cd25cd Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 22 May 2020 10:29:47 +0200 Subject: [PATCH 2077/3747] rustup, and now we also need to install llvm-tools --- .appveyor.yml | 2 +- .travis.yml | 2 +- rust-version | 2 +- rustup-toolchain | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index 34887459f6d93..5cb5267a6da54 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -30,7 +30,7 @@ install: - rustup update # Install "master" toolchain. - cargo install rustup-toolchain-install-master -- rustup-toolchain-install-master -f -n master %RUSTC_HASH% -c rust-src -c rustc-dev +- rustup-toolchain-install-master -f -n master %RUSTC_HASH% -c rust-src -c rustc-dev -c llvm-tools - rustup default master - rustc --version - cargo --version diff --git a/.travis.yml b/.travis.yml index 1605737a7b09c..fcef17b124ddd 100644 --- a/.travis.yml +++ b/.travis.yml @@ -36,7 +36,7 @@ before_script: - rustup update # Install "master" toolchain. - cargo install rustup-toolchain-install-master -- travis_retry rustup-toolchain-install-master -f -n master $RUSTC_HASH -c rust-src -c rustc-dev +- travis_retry rustup-toolchain-install-master -f -n master $RUSTC_HASH -c rust-src -c rustc-dev -c llvm-tools - rustup default master - rustc --version - cargo --version diff --git a/rust-version b/rust-version index 0b9281beeb4f4..a4414470549d0 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -458a3e76294fd859fb037f425404180c91e14767 +c60b675e280fedded8d8487acd051cd342e486f2 diff --git a/rustup-toolchain b/rustup-toolchain index 4e8e0b01ebc47..3fbebe1565f7e 100755 --- a/rustup-toolchain +++ b/rustup-toolchain @@ -39,7 +39,7 @@ fi # Install and setup new toolchain. rustup toolchain uninstall miri -rustup-toolchain-install-master -n miri -c rust-src -c rustc-dev -- "$NEW_COMMIT" +rustup-toolchain-install-master -n miri -c rust-src -c rustc-dev -c llvm-tools -- "$NEW_COMMIT" rustup override set miri # Cleanup. From fbb8c1526ae55f479bdfaf7c00341cb4d36ad597 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 22 May 2020 11:56:18 +0200 Subject: [PATCH 2078/3747] verify the size of all shim arguments --- src/shims/foreign_items/posix.rs | 8 ++++---- src/shims/foreign_items/posix/macos.rs | 4 ++-- src/shims/foreign_items/windows.rs | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/shims/foreign_items/posix.rs b/src/shims/foreign_items/posix.rs index 39b00feec1943..09191011a4a89 100644 --- a/src/shims/foreign_items/posix.rs +++ b/src/shims/foreign_items/posix.rs @@ -170,7 +170,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Dynamic symbol loading "dlsym" => { let &[handle, symbol] = check_arg_count(args)?; - this.read_scalar(handle)?.not_undef()?; + this.read_scalar(handle)?.to_machine_usize(this)?; let symbol = this.read_scalar(symbol)?.not_undef()?; let symbol_name = this.memory.read_c_str(symbol)?; if let Some(dlsym) = Dlsym::from_str(symbol_name, &this.tcx.sess.target.target.target_os)? { @@ -369,9 +369,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "pthread_atfork" => { let &[prepare, parent, child] = check_arg_count(args)?; - this.read_scalar(prepare)?.not_undef()?; - this.read_scalar(parent)?.not_undef()?; - this.read_scalar(child)?.not_undef()?; + this.force_bits(this.read_scalar(prepare)?.not_undef()?, this.memory.pointer_size())?; + this.force_bits(this.read_scalar(parent)?.not_undef()?, this.memory.pointer_size())?; + this.force_bits(this.read_scalar(child)?.not_undef()?, this.memory.pointer_size())?; // We do not support forking, so there is nothing to do here. this.write_null(dest)?; } diff --git a/src/shims/foreign_items/posix/macos.rs b/src/shims/foreign_items/posix/macos.rs index 1cfecbc93461f..e6d39af453958 100644 --- a/src/shims/foreign_items/posix/macos.rs +++ b/src/shims/foreign_items/posix/macos.rs @@ -105,13 +105,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Querying system information "pthread_get_stackaddr_np" => { let &[thread] = check_arg_count(args)?; - this.read_scalar(thread)?.not_undef()?; + this.read_scalar(thread)?.to_machine_usize(this)?; let stack_addr = Scalar::from_uint(STACK_ADDR, this.pointer_size()); this.write_scalar(stack_addr, dest)?; } "pthread_get_stacksize_np" => { let &[thread] = check_arg_count(args)?; - this.read_scalar(thread)?.not_undef()?; + this.read_scalar(thread)?.to_machine_usize(this)?; let stack_size = Scalar::from_uint(STACK_SIZE, this.pointer_size()); this.write_scalar(stack_size, dest)?; } diff --git a/src/shims/foreign_items/windows.rs b/src/shims/foreign_items/windows.rs index 60448406a67de..c24824153ca24 100644 --- a/src/shims/foreign_items/windows.rs +++ b/src/shims/foreign_items/windows.rs @@ -210,7 +210,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "GetProcAddress" => { #[allow(non_snake_case)] let &[hModule, lpProcName] = check_arg_count(args)?; - this.read_scalar(hModule)?.not_undef()?; + this.read_scalar(hModule)?.to_machine_isize(this)?; let name = this.memory.read_c_str(this.read_scalar(lpProcName)?.not_undef()?)?; if let Some(dlsym) = Dlsym::from_str(name, &this.tcx.sess.target.target.target_os)? { let ptr = this.memory.create_fn_alloc(FnVal::Other(dlsym)); From 87a846f2d672547fa86508120584f494c05f0de6 Mon Sep 17 00:00:00 2001 From: David Cook Date: Thu, 14 May 2020 08:03:49 -0500 Subject: [PATCH 2079/3747] Update to match rustc changes --- src/diagnostics.rs | 18 +++++++++++------- tests/compile-fail/uninit_buffer.rs | 2 +- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/src/diagnostics.rs b/src/diagnostics.rs index 8296f71773c2a..2d8b1248dcf4d 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -118,13 +118,17 @@ pub fn report_error<'tcx, 'mir>( report_msg(ecx, &format!("{}: {}", title, msg), msg, helps, true); // Extra output to help debug specific issues. - if let UndefinedBehavior(UndefinedBehaviorInfo::InvalidUninitBytes(Some(ptr))) = e.kind { - eprintln!( - "Uninitialized read occurred at offset 0x{:x} into this allocation:", - ptr.offset.bytes(), - ); - ecx.memory.dump_alloc(ptr.alloc_id); - eprintln!(); + match e.kind { + UndefinedBehavior(UndefinedBehaviorInfo::InvalidUninitBytes(Some(access))) => { + eprintln!( + "Uninitialized read occurred at offsets 0x{:x}..0x{:x} into this allocation:", + access.uninit_ptr.offset.bytes(), + access.uninit_ptr.offset.bytes() + access.uninit_size.bytes(), + ); + ecx.memory.dump_alloc(access.uninit_ptr.alloc_id); + eprintln!(); + } + _ => {} } None diff --git a/tests/compile-fail/uninit_buffer.rs b/tests/compile-fail/uninit_buffer.rs index dac02a8690e9e..351181016e4bf 100644 --- a/tests/compile-fail/uninit_buffer.rs +++ b/tests/compile-fail/uninit_buffer.rs @@ -1,4 +1,4 @@ -// error-pattern: reading uninitialized memory +// error-pattern: 12 bytes are uninitialized use std::alloc::{alloc, dealloc, Layout}; use std::slice::from_raw_parts; From 58bc2185e13adc3875b7d9f15d5660858bc194e9 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 22 May 2020 17:03:37 +0200 Subject: [PATCH 2080/3747] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index a4414470549d0..adf285ab17ba0 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -c60b675e280fedded8d8487acd051cd342e486f2 +a9ca1ec9280ca1e5020edd699917c3367a30a798 From 404c37999be2b0f5a8769870f985fd6677ee3905 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 23 May 2020 16:30:50 +0200 Subject: [PATCH 2081/3747] test discriminant_value intrinsic --- tests/run-pass/intrinsics.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tests/run-pass/intrinsics.rs b/tests/run-pass/intrinsics.rs index 63439c996af0a..ffa7f080aa4e4 100644 --- a/tests/run-pass/intrinsics.rs +++ b/tests/run-pass/intrinsics.rs @@ -25,4 +25,9 @@ fn main() { assert_eq!(intrinsics::unlikely(true), true); unsafe { intrinsics::forget(Bomb); } + + let _v = intrinsics::discriminant_value(&Some(())); + let _v = intrinsics::discriminant_value(&0); + let _v = intrinsics::discriminant_value(&true); + let _v = intrinsics::discriminant_value(&vec![1,2,3]); } From e6ced2f9c45ee73f092d36035e4ba70300ca5516 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 24 May 2020 11:58:19 +0200 Subject: [PATCH 2082/3747] add interesting unsizing test --- tests/run-pass/dyn-lcsit.rs | 68 +++++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) create mode 100644 tests/run-pass/dyn-lcsit.rs diff --git a/tests/run-pass/dyn-lcsit.rs b/tests/run-pass/dyn-lcsit.rs new file mode 100644 index 0000000000000..fa11e9a2a318e --- /dev/null +++ b/tests/run-pass/dyn-lcsit.rs @@ -0,0 +1,68 @@ +// Taken from the rustc test suite; this triggers an interesting case in unsizing. + +#![allow(non_upper_case_globals, incomplete_features)] +#![feature(associated_type_bounds)] +#![feature(impl_trait_in_bindings)] + +use std::ops::Add; + +trait Tr1 { type As1; fn mk(&self) -> Self::As1; } +trait Tr2<'a> { fn tr2(self) -> &'a Self; } + +fn assert_copy(x: T) { let _x = x; let _x = x; } +fn assert_static(_: T) {} +fn assert_forall_tr2 Tr2<'a>>(_: T) {} + +#[derive(Copy, Clone)] +struct S1; +#[derive(Copy, Clone)] +struct S2; +impl Tr1 for S1 { type As1 = S2; fn mk(&self) -> Self::As1 { S2 } } + +const cdef_et1: &dyn Tr1 = &S1; +const sdef_et1: &dyn Tr1 = &S1; +pub fn use_et1() { assert_copy(cdef_et1.mk()); assert_copy(sdef_et1.mk()); } + +const cdef_et2: &(dyn Tr1 + Sync) = &S1; +static sdef_et2: &(dyn Tr1 + Sync) = &S1; +pub fn use_et2() { assert_static(cdef_et2.mk()); assert_static(sdef_et2.mk()); } + +const cdef_et3: &dyn Tr1>>> = { + struct A; + impl Tr1 for A { + type As1 = core::ops::Range; + fn mk(&self) -> Self::As1 { 0..10 } + }; + &A +}; +pub fn use_et3() { + let _0 = cdef_et3.mk().clone(); + let mut s = 0u8; + for _1 in _0 { + let _2 = _1 + 1u8; + s += _2.into(); + } + assert_eq!(s, (0..10).map(|x| x + 1).sum()); +} + +const cdef_et4: &(dyn Tr1 Tr2<'a>> + Sync) = { + #[derive(Copy, Clone)] + struct A; + impl Tr1 for A { + type As1 = A; + fn mk(&self) -> A { A } + } + impl<'a> Tr2<'a> for A { + fn tr2(self) -> &'a Self { &A } + } + &A +}; +static sdef_et4: &(dyn Tr1 Tr2<'a>> + Sync) = cdef_et4; +pub fn use_et4() { assert_forall_tr2(cdef_et4.mk()); assert_forall_tr2(sdef_et4.mk()); } + +fn main() { + let _ = use_et1(); + let _ = use_et2(); + let _ = use_et3(); + let _ = use_et4(); +} From 7a3ccb1b5711eb6ed563953e988652fbacc7f312 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 24 May 2020 14:00:32 +0200 Subject: [PATCH 2083/3747] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index adf285ab17ba0..4275de5f8cbbb 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -a9ca1ec9280ca1e5020edd699917c3367a30a798 +7726070fa755f660b5da3f82f46e07d9c6866f69 From cf7d88fd91046f1f851a3d0687188d9cd283a162 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 22 May 2020 10:12:32 +0200 Subject: [PATCH 2084/3747] unset RUSTC_WRAPPER for xargo invocation --- src/bin/cargo-miri.rs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/bin/cargo-miri.rs b/src/bin/cargo-miri.rs index 12f59c05b0a94..2e2d4ce956b13 100644 --- a/src/bin/cargo-miri.rs +++ b/src/bin/cargo-miri.rs @@ -335,7 +335,6 @@ path = "lib.rs" command.current_dir(&dir); command.env("XARGO_HOME", &dir); command.env("XARGO_RUST_SRC", &rust_src); - command.env_remove("RUSTFLAGS"); // Make sure external `RUSTFLAGS` do not influence the build. // Use Miri as rustc to build a libstd compatible with us (and use the right flags). // However, when we are running in bootstrap, we cannot just overwrite `RUSTC`, // because we still need bootstrap to distinguish between host and target crates. @@ -347,6 +346,12 @@ path = "lib.rs" command.env("RUSTC", find_miri()); } command.env("MIRI_BE_RUSTC", "1"); + // Make sure there are no other wrappers or flags getting in our way + // (Cc https://github.com/rust-lang/miri/issues/1421). + // This is consistent with normal `cargo build` that does not apply `RUSTFLAGS` + // to the sysroot either. + command.env_remove("RUSTC_WRAPPER"); + command.env_remove("RUSTFLAGS"); // Finally run it! if command.status().expect("failed to run xargo").success().not() { show_error(format!("Failed to run xargo")); @@ -446,6 +451,9 @@ fn in_cargo_miri() { // Set `RUSTC_WRAPPER` to ourselves. Cargo will prepend that binary to its usual invocation, // i.e., the first argument is `rustc` -- which is what we use in `main` to distinguish // the two codepaths. (That extra argument is why we prefer this over setting `RUSTC`.) + if env::var_os("RUSTC_WRAPPER").is_some() { + println!("WARNING: Ignoring existing `RUSTC_WRAPPER` environment variable, Miri does not support wrapping."); + } let path = std::env::current_exe().expect("current executable path invalid"); cmd.env("RUSTC_WRAPPER", path); if verbose { From 2c94ad08d8cbd065a3673cee5d894963c33236c0 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 24 May 2020 19:20:44 +0200 Subject: [PATCH 2085/3747] use helper method to compute size of int type --- src/lib.rs | 1 + src/shims/intrinsics.rs | 16 +++++++++------- 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index e8cf507d35a0a..0ea0d57caccc0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -10,6 +10,7 @@ #![allow(incomplete_features)] #![feature(const_generics)] +extern crate rustc_attr; extern crate rustc_apfloat; extern crate rustc_ast; #[macro_use] extern crate rustc_middle; diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 08087b0350d9c..1a8c9163211a8 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -1,10 +1,12 @@ use std::iter; use std::convert::TryFrom; +use rustc_attr as attr; use rustc_ast::ast::FloatTy; use rustc_middle::{mir, ty}; +use rustc_middle::ty::layout::IntegerExt; use rustc_apfloat::{Float, Round}; -use rustc_target::abi::{Align, LayoutOf, Size}; +use rustc_target::abi::{Align, Integer, LayoutOf}; use crate::*; use helpers::check_arg_count; @@ -563,11 +565,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(match dest_ty.kind { // Unsigned ty::Uint(t) => { - let width = t.bit_width().unwrap_or_else(|| this.pointer_size().bits()); - let res = f.to_u128(usize::try_from(width).unwrap()); + let size = Integer::from_attr(this, attr::IntType::UnsignedInt(t)).size(); + let res = f.to_u128(size.bits_usize()); if res.status.is_empty() { // No status flags means there was no further rounding or other loss of precision. - Scalar::from_uint(res.value, Size::from_bits(width)) + Scalar::from_uint(res.value, size) } else { // `f` was not representable in this integer type. throw_ub_format!( @@ -578,11 +580,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // Signed ty::Int(t) => { - let width = t.bit_width().unwrap_or_else(|| this.pointer_size().bits()); - let res = f.to_i128(usize::try_from(width).unwrap()); + let size = Integer::from_attr(this, attr::IntType::SignedInt(t)).size(); + let res = f.to_i128(size.bits_usize()); if res.status.is_empty() { // No status flags means there was no further rounding or other loss of precision. - Scalar::from_int(res.value, Size::from_bits(width)) + Scalar::from_int(res.value, size) } else { // `f` was not representable in this integer type. throw_ub_format!( From 679245769b6984ec5a7edf70fb4744d8411468b8 Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Tue, 21 Apr 2020 16:38:14 -0700 Subject: [PATCH 2086/3747] Implement support for synchronization primitives. --- src/eval.rs | 6 + src/lib.rs | 6 +- src/machine.rs | 8 +- src/shims/foreign_items/posix.rs | 48 +- src/shims/sync.rs | 650 +++++++++++------- src/sync.rs | 299 ++++++++ src/thread.rs | 147 +++- tests/run-pass/concurrency/barrier.rs | 27 + tests/run-pass/concurrency/barrier.stderr | 2 + tests/run-pass/concurrency/barrier.stdout | 20 + tests/run-pass/concurrency/condvar.rs | 28 + tests/run-pass/concurrency/condvar.stderr | 2 + .../run-pass/concurrency/libc_pthread_cond.rs | 199 ++++++ .../concurrency/libc_pthread_cond.stderr | 2 + tests/run-pass/concurrency/mpsc.rs | 56 ++ tests/run-pass/concurrency/mpsc.stderr | 2 + tests/run-pass/concurrency/once.rs | 44 ++ tests/run-pass/concurrency/once.stderr | 2 + 18 files changed, 1276 insertions(+), 272 deletions(-) create mode 100644 src/sync.rs create mode 100644 tests/run-pass/concurrency/barrier.rs create mode 100644 tests/run-pass/concurrency/barrier.stderr create mode 100644 tests/run-pass/concurrency/barrier.stdout create mode 100644 tests/run-pass/concurrency/condvar.rs create mode 100644 tests/run-pass/concurrency/condvar.stderr create mode 100644 tests/run-pass/concurrency/libc_pthread_cond.rs create mode 100644 tests/run-pass/concurrency/libc_pthread_cond.stderr create mode 100644 tests/run-pass/concurrency/mpsc.rs create mode 100644 tests/run-pass/concurrency/mpsc.stderr create mode 100644 tests/run-pass/concurrency/once.rs create mode 100644 tests/run-pass/concurrency/once.stderr diff --git a/src/eval.rs b/src/eval.rs index 5daad7cc068b8..30901a8f127f4 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -210,6 +210,12 @@ pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) -> SchedulingAction::ExecuteStep => { assert!(ecx.step()?, "a terminated thread was scheduled for execution"); } + SchedulingAction::ExecuteCallback => { + assert!(ecx.machine.communicate, + "scheduler callbacks require disabled isolation, but the code \ + that created the callback did not check it"); + ecx.run_scheduler_callback()?; + } SchedulingAction::ExecuteDtors => { // This will either enable the thread again (so we go back // to `ExecuteStep`), or determine that this thread is done diff --git a/src/lib.rs b/src/lib.rs index 0ea0d57caccc0..e79fc2add39e1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -31,6 +31,7 @@ mod operator; mod range_map; mod shims; mod stacked_borrows; +mod sync; mod thread; // Make all those symbols available in the same place as our own. @@ -45,7 +46,7 @@ pub use crate::shims::fs::{DirHandler, EvalContextExt as FileEvalContextExt, Fil pub use crate::shims::intrinsics::EvalContextExt as IntrinsicsEvalContextExt; pub use crate::shims::os_str::EvalContextExt as OsStrEvalContextExt; pub use crate::shims::panic::{CatchUnwindData, EvalContextExt as PanicEvalContextExt}; -pub use crate::shims::sync::{EvalContextExt as SyncEvalContextExt}; +pub use crate::shims::sync::{EvalContextExt as SyncShimsEvalContextExt}; pub use crate::shims::thread::EvalContextExt as ThreadShimsEvalContextExt; pub use crate::shims::time::EvalContextExt as TimeEvalContextExt; pub use crate::shims::tls::{EvalContextExt as TlsEvalContextExt, TlsData}; @@ -70,6 +71,9 @@ pub use crate::stacked_borrows::{ pub use crate::thread::{ EvalContextExt as ThreadsEvalContextExt, SchedulingAction, ThreadId, ThreadManager, ThreadState, }; +pub use crate::sync::{ + EvalContextExt as SyncEvalContextExt, CondvarId, MutexId, RwLockId +}; /// Insert rustc arguments at the beginning of the argument list that Miri wants to be /// set per default, for maximal validation power. diff --git a/src/machine.rs b/src/machine.rs index 51aa7ae31047a..4fb08cd259b67 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -5,7 +5,7 @@ use std::borrow::Cow; use std::cell::RefCell; use std::num::NonZeroU64; use std::rc::Rc; -use std::time::Instant; +use std::time::{Instant, SystemTime}; use std::fmt; use log::trace; @@ -251,6 +251,11 @@ pub struct Evaluator<'mir, 'tcx> { /// The "time anchor" for this machine's monotone clock (for `Instant` simulation). pub(crate) time_anchor: Instant, + /// The approximate system time when "time anchor" was created. This is used + /// for converting system time to monotone time so that we can simplify the + /// thread scheduler to deal only with a single representation of time. + pub(crate) time_anchor_timestamp: SystemTime, + /// The set of threads. pub(crate) threads: ThreadManager<'mir, 'tcx>, @@ -281,6 +286,7 @@ impl<'mir, 'tcx> Evaluator<'mir, 'tcx> { dir_handler: Default::default(), panic_payload: None, time_anchor: Instant::now(), + time_anchor_timestamp: SystemTime::now(), layouts, threads: ThreadManager::default(), } diff --git a/src/shims/foreign_items/posix.rs b/src/shims/foreign_items/posix.rs index 09191011a4a89..352e38113abbe 100644 --- a/src/shims/foreign_items/posix.rs +++ b/src/shims/foreign_items/posix.rs @@ -330,6 +330,45 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let result = this.pthread_rwlock_destroy(rwlock)?; this.write_scalar(Scalar::from_i32(result), dest)?; } + "pthread_condattr_init" => { + let result = this.pthread_condattr_init(args[0])?; + this.write_scalar(Scalar::from_i32(result), dest)?; + } + "pthread_condattr_setclock" => { + let result = this.pthread_condattr_setclock(args[0], args[1])?; + this.write_scalar(Scalar::from_i32(result), dest)?; + } + "pthread_condattr_getclock" => { + let result = this.pthread_condattr_getclock(args[0], args[1])?; + this.write_scalar(Scalar::from_i32(result), dest)?; + } + "pthread_condattr_destroy" => { + let result = this.pthread_condattr_destroy(args[0])?; + this.write_scalar(Scalar::from_i32(result), dest)?; + } + "pthread_cond_init" => { + let result = this.pthread_cond_init(args[0], args[1])?; + this.write_scalar(Scalar::from_i32(result), dest)?; + } + "pthread_cond_signal" => { + let result = this.pthread_cond_signal(args[0])?; + this.write_scalar(Scalar::from_i32(result), dest)?; + } + "pthread_cond_broadcast" => { + let result = this.pthread_cond_broadcast(args[0])?; + this.write_scalar(Scalar::from_i32(result), dest)?; + } + "pthread_cond_wait" => { + let result = this.pthread_cond_wait(args[0], args[1])?; + this.write_scalar(Scalar::from_i32(result), dest)?; + } + "pthread_cond_timedwait" => { + this.pthread_cond_timedwait(args[0], args[1], args[2], dest)?; + } + "pthread_cond_destroy" => { + let result = this.pthread_cond_destroy(args[0])?; + this.write_scalar(Scalar::from_i32(result), dest)?; + } // Threading "pthread_create" => { @@ -391,16 +430,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "pthread_attr_init" | "pthread_attr_destroy" - | "pthread_condattr_init" - | "pthread_condattr_destroy" - | "pthread_cond_destroy" - if this.frame().instance.to_string().starts_with("std::sys::unix::") => { - let &[_] = check_arg_count(args)?; - this.write_null(dest)?; - } - | "pthread_cond_init" | "pthread_attr_setstacksize" - | "pthread_condattr_setclock" if this.frame().instance.to_string().starts_with("std::sys::unix::") => { let &[_, _] = check_arg_count(args)?; this.write_null(dest)?; diff --git a/src/shims/sync.rs b/src/shims/sync.rs index c205c5c8dddb1..dfd7999457eb9 100644 --- a/src/shims/sync.rs +++ b/src/shims/sync.rs @@ -1,8 +1,10 @@ +use std::time::{Duration, SystemTime}; + use rustc_middle::ty::{layout::TyAndLayout, TyKind, TypeAndMut}; use rustc_target::abi::{LayoutOf, Size}; use crate::stacked_borrows::Tag; -use crate::thread::BlockSetId; + use crate::*; fn assert_ptr_target_min_size<'mir, 'tcx: 'mir>( @@ -76,45 +78,12 @@ fn mutexattr_set_kind<'mir, 'tcx: 'mir>( // Our chosen memory layout for the emulated mutex (does not have to match the platform layout!): // bytes 0-3: reserved for signature on macOS // (need to avoid this because it is set by static initializer macros) -// bytes 4-7: count of how many times this mutex has been locked, as a u32 -// bytes 8-11: when count > 0, id of the owner thread as a u32 +// bytes 4-7: mutex id as u32 or 0 if id is not assigned yet. // bytes 12-15 or 16-19 (depending on platform): mutex kind, as an i32 // (the kind has to be at its offset for compatibility with static initializer macros) -// bytes 20-23: when count > 0, id of the blockset in which the blocked threads -// are waiting or 0 if blockset is not yet assigned. const PTHREAD_MUTEX_T_MIN_SIZE: u64 = 24; -fn mutex_get_locked_count<'mir, 'tcx: 'mir>( - ecx: &MiriEvalContext<'mir, 'tcx>, - mutex_op: OpTy<'tcx, Tag>, -) -> InterpResult<'tcx, ScalarMaybeUninit> { - get_at_offset(ecx, mutex_op, 4, ecx.machine.layouts.u32, PTHREAD_MUTEX_T_MIN_SIZE) -} - -fn mutex_set_locked_count<'mir, 'tcx: 'mir>( - ecx: &mut MiriEvalContext<'mir, 'tcx>, - mutex_op: OpTy<'tcx, Tag>, - locked_count: impl Into>, -) -> InterpResult<'tcx, ()> { - set_at_offset(ecx, mutex_op, 4, locked_count, ecx.machine.layouts.u32, PTHREAD_MUTEX_T_MIN_SIZE) -} - -fn mutex_get_owner<'mir, 'tcx: 'mir>( - ecx: &MiriEvalContext<'mir, 'tcx>, - mutex_op: OpTy<'tcx, Tag>, -) -> InterpResult<'tcx, ScalarMaybeUninit> { - get_at_offset(ecx, mutex_op, 8, ecx.machine.layouts.u32, PTHREAD_MUTEX_T_MIN_SIZE) -} - -fn mutex_set_owner<'mir, 'tcx: 'mir>( - ecx: &mut MiriEvalContext<'mir, 'tcx>, - mutex_op: OpTy<'tcx, Tag>, - owner: impl Into>, -) -> InterpResult<'tcx, ()> { - set_at_offset(ecx, mutex_op, 8, owner, ecx.machine.layouts.u32, PTHREAD_MUTEX_T_MIN_SIZE) -} - fn mutex_get_kind<'mir, 'tcx: 'mir>( ecx: &mut MiriEvalContext<'mir, 'tcx>, mutex_op: OpTy<'tcx, Tag>, @@ -132,34 +101,34 @@ fn mutex_set_kind<'mir, 'tcx: 'mir>( set_at_offset(ecx, mutex_op, offset, kind, ecx.machine.layouts.i32, PTHREAD_MUTEX_T_MIN_SIZE) } -fn mutex_get_blockset<'mir, 'tcx: 'mir>( +fn mutex_get_id<'mir, 'tcx: 'mir>( ecx: &MiriEvalContext<'mir, 'tcx>, mutex_op: OpTy<'tcx, Tag>, -) -> InterpResult<'tcx, ScalarMaybeUninit> { - get_at_offset(ecx, mutex_op, 20, ecx.machine.layouts.u32, PTHREAD_MUTEX_T_MIN_SIZE) +) -> InterpResult<'tcx, ScalarMaybeUndef> { + get_at_offset(ecx, mutex_op, 4, ecx.machine.layouts.u32, PTHREAD_MUTEX_T_MIN_SIZE) } -fn mutex_set_blockset<'mir, 'tcx: 'mir>( +fn mutex_set_id<'mir, 'tcx: 'mir>( ecx: &mut MiriEvalContext<'mir, 'tcx>, mutex_op: OpTy<'tcx, Tag>, - blockset: impl Into>, + id: impl Into>, ) -> InterpResult<'tcx, ()> { - set_at_offset(ecx, mutex_op, 20, blockset, ecx.machine.layouts.u32, PTHREAD_MUTEX_T_MIN_SIZE) + set_at_offset(ecx, mutex_op, 4, id, ecx.machine.layouts.u32, PTHREAD_MUTEX_T_MIN_SIZE) } -fn mutex_get_or_create_blockset<'mir, 'tcx: 'mir>( +fn mutex_get_or_create_id<'mir, 'tcx: 'mir>( ecx: &mut MiriEvalContext<'mir, 'tcx>, mutex_op: OpTy<'tcx, Tag>, -) -> InterpResult<'tcx, BlockSetId> { - let blockset = mutex_get_blockset(ecx, mutex_op)?.to_u32()?; - if blockset == 0 { - // 0 is a default value and also not a valid blockset id. Need to - // allocate a new blockset. - let blockset = ecx.create_blockset()?; - mutex_set_blockset(ecx, mutex_op, blockset.to_u32_scalar())?; - Ok(blockset) +) -> InterpResult<'tcx, MutexId> { + let id = mutex_get_id(ecx, mutex_op)?.to_u32()?; + if id == 0 { + // 0 is a default value and also not a valid mutex id. Need to allocate + // a new mutex. + let id = ecx.mutex_create(); + mutex_set_id(ecx, mutex_op, id.to_u32_scalar())?; + Ok(id) } else { - Ok(BlockSetId::new(blockset)) + Ok(id.into()) } } @@ -168,105 +137,160 @@ fn mutex_get_or_create_blockset<'mir, 'tcx: 'mir>( // Our chosen memory layout for the emulated rwlock (does not have to match the platform layout!): // bytes 0-3: reserved for signature on macOS // (need to avoid this because it is set by static initializer macros) -// bytes 4-7: reader count, as a u32 -// bytes 8-11: writer count, as a u32 -// bytes 12-15: when writer or reader count > 0, id of the blockset in which the -// blocked writers are waiting or 0 if blockset is not yet assigned. -// bytes 16-20: when writer count > 0, id of the blockset in which the blocked -// readers are waiting or 0 if blockset is not yet assigned. +// bytes 4-7: rwlock id as u32 or 0 if id is not assigned yet. -const PTHREAD_RWLOCK_T_MIN_SIZE: u64 = 20; +const PTHREAD_RWLOCK_T_MIN_SIZE: u64 = 32; -fn rwlock_get_readers<'mir, 'tcx: 'mir>( +fn rwlock_get_id<'mir, 'tcx: 'mir>( ecx: &MiriEvalContext<'mir, 'tcx>, rwlock_op: OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, ScalarMaybeUninit> { get_at_offset(ecx, rwlock_op, 4, ecx.machine.layouts.u32, PTHREAD_RWLOCK_T_MIN_SIZE) } -fn rwlock_set_readers<'mir, 'tcx: 'mir>( +fn rwlock_set_id<'mir, 'tcx: 'mir>( ecx: &mut MiriEvalContext<'mir, 'tcx>, rwlock_op: OpTy<'tcx, Tag>, - readers: impl Into>, + id: impl Into>, ) -> InterpResult<'tcx, ()> { - set_at_offset(ecx, rwlock_op, 4, readers, ecx.machine.layouts.u32, PTHREAD_RWLOCK_T_MIN_SIZE) + set_at_offset(ecx, rwlock_op, 4, id, ecx.machine.layouts.u32, PTHREAD_RWLOCK_T_MIN_SIZE) } -fn rwlock_get_writers<'mir, 'tcx: 'mir>( - ecx: &MiriEvalContext<'mir, 'tcx>, +fn rwlock_get_or_create_id<'mir, 'tcx: 'mir>( + ecx: &mut MiriEvalContext<'mir, 'tcx>, rwlock_op: OpTy<'tcx, Tag>, -) -> InterpResult<'tcx, ScalarMaybeUninit> { - get_at_offset(ecx, rwlock_op, 8, ecx.machine.layouts.u32, PTHREAD_RWLOCK_T_MIN_SIZE) +) -> InterpResult<'tcx, RwLockId> { + let id = rwlock_get_id(ecx, rwlock_op)?.to_u32()?; + if id == 0 { + // 0 is a default value and also not a valid rwlock id. Need to allocate + // a new read-write lock. + let id = ecx.rwlock_create(); + rwlock_set_id(ecx, rwlock_op, id.to_u32_scalar())?; + Ok(id) + } else { + Ok(id.into()) + } +} + +// pthread_condattr_t + +// Our chosen memory layout for emulation (does not have to match the platform layout!): +// store an i32 in the first four bytes equal to the corresponding libc clock id constant +// (e.g. CLOCK_REALTIME). + +const PTHREAD_CONDATTR_T_MIN_SIZE: u64 = 4; + +fn condattr_get_clock_id<'mir, 'tcx: 'mir>( + ecx: &MiriEvalContext<'mir, 'tcx>, + attr_op: OpTy<'tcx, Tag>, +) -> InterpResult<'tcx, ScalarMaybeUndef> { + get_at_offset(ecx, attr_op, 0, ecx.machine.layouts.i32, PTHREAD_CONDATTR_T_MIN_SIZE) } -fn rwlock_set_writers<'mir, 'tcx: 'mir>( +fn condattr_set_clock_id<'mir, 'tcx: 'mir>( ecx: &mut MiriEvalContext<'mir, 'tcx>, - rwlock_op: OpTy<'tcx, Tag>, - writers: impl Into>, + attr_op: OpTy<'tcx, Tag>, + clock_id: impl Into>, ) -> InterpResult<'tcx, ()> { - set_at_offset(ecx, rwlock_op, 8, writers, ecx.machine.layouts.u32, PTHREAD_RWLOCK_T_MIN_SIZE) + set_at_offset(ecx, attr_op, 0, clock_id, ecx.machine.layouts.i32, PTHREAD_CONDATTR_T_MIN_SIZE) } -fn rwlock_get_writer_blockset<'mir, 'tcx: 'mir>( +// pthread_cond_t + +// Our chosen memory layout for the emulated conditional variable (does not have +// to match the platform layout!): + +// bytes 4-7: the conditional variable id as u32 or 0 if id is not assigned yet. +// bytes 8-11: the clock id constant as i32 + +const PTHREAD_COND_T_MIN_SIZE: u64 = 12; + +fn cond_get_id<'mir, 'tcx: 'mir>( ecx: &MiriEvalContext<'mir, 'tcx>, - rwlock_op: OpTy<'tcx, Tag>, -) -> InterpResult<'tcx, ScalarMaybeUninit> { - get_at_offset(ecx, rwlock_op, 12, ecx.machine.layouts.u32, PTHREAD_RWLOCK_T_MIN_SIZE) + cond_op: OpTy<'tcx, Tag>, +) -> InterpResult<'tcx, ScalarMaybeUndef> { + get_at_offset(ecx, cond_op, 4, ecx.machine.layouts.u32, PTHREAD_COND_T_MIN_SIZE) } -fn rwlock_set_writer_blockset<'mir, 'tcx: 'mir>( +fn cond_set_id<'mir, 'tcx: 'mir>( ecx: &mut MiriEvalContext<'mir, 'tcx>, - rwlock_op: OpTy<'tcx, Tag>, - blockset: impl Into>, + cond_op: OpTy<'tcx, Tag>, + id: impl Into>, ) -> InterpResult<'tcx, ()> { - set_at_offset(ecx, rwlock_op, 12, blockset, ecx.machine.layouts.u32, PTHREAD_RWLOCK_T_MIN_SIZE) + set_at_offset(ecx, cond_op, 4, id, ecx.machine.layouts.u32, PTHREAD_COND_T_MIN_SIZE) } -fn rwlock_get_or_create_writer_blockset<'mir, 'tcx: 'mir>( +fn cond_get_or_create_id<'mir, 'tcx: 'mir>( ecx: &mut MiriEvalContext<'mir, 'tcx>, - rwlock_op: OpTy<'tcx, Tag>, -) -> InterpResult<'tcx, BlockSetId> { - let blockset = rwlock_get_writer_blockset(ecx, rwlock_op)?.to_u32()?; - if blockset == 0 { - // 0 is a default value and also not a valid blockset id. Need to - // allocate a new blockset. - let blockset = ecx.create_blockset()?; - rwlock_set_writer_blockset(ecx, rwlock_op, blockset.to_u32_scalar())?; - Ok(blockset) + cond_op: OpTy<'tcx, Tag>, +) -> InterpResult<'tcx, CondvarId> { + let id = cond_get_id(ecx, cond_op)?.to_u32()?; + if id == 0 { + // 0 is a default value and also not a valid conditional variable id. + // Need to allocate a new id. + let id = ecx.condvar_create(); + cond_set_id(ecx, cond_op, id.to_u32_scalar())?; + Ok(id) } else { - Ok(BlockSetId::new(blockset)) + Ok(id.into()) } } -fn rwlock_get_reader_blockset<'mir, 'tcx: 'mir>( +fn cond_get_clock_id<'mir, 'tcx: 'mir>( ecx: &MiriEvalContext<'mir, 'tcx>, - rwlock_op: OpTy<'tcx, Tag>, -) -> InterpResult<'tcx, ScalarMaybeUninit> { - get_at_offset(ecx, rwlock_op, 16, ecx.machine.layouts.u32, PTHREAD_RWLOCK_T_MIN_SIZE) + cond_op: OpTy<'tcx, Tag>, +) -> InterpResult<'tcx, ScalarMaybeUndef> { + get_at_offset(ecx, cond_op, 8, ecx.machine.layouts.i32, PTHREAD_COND_T_MIN_SIZE) } -fn rwlock_set_reader_blockset<'mir, 'tcx: 'mir>( +fn cond_set_clock_id<'mir, 'tcx: 'mir>( ecx: &mut MiriEvalContext<'mir, 'tcx>, - rwlock_op: OpTy<'tcx, Tag>, - blockset: impl Into>, + cond_op: OpTy<'tcx, Tag>, + clock_id: impl Into>, ) -> InterpResult<'tcx, ()> { - set_at_offset(ecx, rwlock_op, 16, blockset, ecx.machine.layouts.u32, PTHREAD_RWLOCK_T_MIN_SIZE) + set_at_offset(ecx, cond_op, 8, clock_id, ecx.machine.layouts.i32, PTHREAD_COND_T_MIN_SIZE) } -fn rwlock_get_or_create_reader_blockset<'mir, 'tcx: 'mir>( +/// Try to reacquire the mutex associated with the condition variable after we were signaled. +fn reacquire_cond_mutex<'mir, 'tcx: 'mir>( ecx: &mut MiriEvalContext<'mir, 'tcx>, - rwlock_op: OpTy<'tcx, Tag>, -) -> InterpResult<'tcx, BlockSetId> { - let blockset = rwlock_get_reader_blockset(ecx, rwlock_op)?.to_u32()?; - if blockset == 0 { - // 0 is a default value and also not a valid blockset id. Need to - // allocate a new blockset. - let blockset = ecx.create_blockset()?; - rwlock_set_reader_blockset(ecx, rwlock_op, blockset.to_u32_scalar())?; - Ok(blockset) + thread: ThreadId, + mutex: MutexId, +) -> InterpResult<'tcx> { + if ecx.mutex_is_locked(mutex) { + ecx.mutex_enqueue(mutex, thread); } else { - Ok(BlockSetId::new(blockset)) + ecx.mutex_lock(mutex, thread); + ecx.unblock_thread(thread)?; } + Ok(()) +} + +/// Release the mutex associated with the condition variable because we are +/// entering the waiting state. +fn release_cond_mutex<'mir, 'tcx: 'mir>( + ecx: &mut MiriEvalContext<'mir, 'tcx>, + active_thread: ThreadId, + mutex: MutexId, +) -> InterpResult<'tcx> { + if let Some((owner_thread, current_locked_count)) = ecx.mutex_unlock(mutex) { + if current_locked_count != 0 { + throw_unsup_format!("awaiting on multiple times acquired lock is not supported"); + } + if owner_thread != active_thread { + throw_ub_format!("awaiting on a mutex owned by a different thread"); + } + if let Some(thread) = ecx.mutex_dequeue(mutex) { + // We have at least one thread waiting on this mutex. Transfer + // ownership to it. + ecx.mutex_lock(mutex, thread); + ecx.unblock_thread(thread)?; + } + } else { + throw_ub_format!("awaiting on unlocked mutex"); + } + ecx.block_thread(active_thread)?; + Ok(()) } impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} @@ -323,7 +347,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx mutexattr_get_kind(this, attr_op)?.not_undef()? }; - mutex_set_locked_count(this, mutex_op, Scalar::from_u32(0))?; + let _ = mutex_get_or_create_id(this, mutex_op)?; mutex_set_kind(this, mutex_op, kind)?; Ok(0) @@ -333,21 +357,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); let kind = mutex_get_kind(this, mutex_op)?.not_undef()?; - let locked_count = mutex_get_locked_count(this, mutex_op)?.to_u32()?; + let id = mutex_get_or_create_id(this, mutex_op)?; let active_thread = this.get_active_thread()?; - if locked_count == 0 { - // The mutex is unlocked. Let's lock it. - mutex_set_locked_count(this, mutex_op, Scalar::from_u32(1))?; - mutex_set_owner(this, mutex_op, active_thread.to_u32_scalar())?; - Ok(0) - } else { - // The mutex is locked. Let's check by whom. - let owner_thread: ThreadId = mutex_get_owner(this, mutex_op)?.to_u32()?.into(); + if this.mutex_is_locked(id) { + let owner_thread = this.mutex_get_owner(id); if owner_thread != active_thread { // Block the active thread. - let blockset = mutex_get_or_create_blockset(this, mutex_op)?; - this.block_active_thread(blockset)?; + this.block_thread(active_thread)?; + this.mutex_enqueue(id, active_thread); Ok(0) } else { // Trying to acquire the same mutex again. @@ -356,17 +374,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } else if kind == this.eval_libc("PTHREAD_MUTEX_ERRORCHECK")? { this.eval_libc_i32("EDEADLK") } else if kind == this.eval_libc("PTHREAD_MUTEX_RECURSIVE")? { - match locked_count.checked_add(1) { - Some(new_count) => { - mutex_set_locked_count(this, mutex_op, Scalar::from_u32(new_count))?; - Ok(0) - } - None => this.eval_libc_i32("EAGAIN"), - } + this.mutex_lock(id, active_thread); + Ok(0) } else { throw_ub_format!("called pthread_mutex_lock on an unsupported type of mutex"); } } + } else { + // The mutex is unlocked. Let's lock it. + this.mutex_lock(id, active_thread); + Ok(0) } } @@ -374,16 +391,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); let kind = mutex_get_kind(this, mutex_op)?.not_undef()?; - let locked_count = mutex_get_locked_count(this, mutex_op)?.to_u32()?; + let id = mutex_get_or_create_id(this, mutex_op)?; let active_thread = this.get_active_thread()?; - if locked_count == 0 { - // The mutex is unlocked. Let's lock it. - mutex_set_locked_count(this, mutex_op, Scalar::from_u32(1))?; - mutex_set_owner(this, mutex_op, active_thread.to_u32_scalar())?; - Ok(0) - } else { - let owner_thread: ThreadId = mutex_get_owner(this, mutex_op)?.to_u32()?.into(); + if this.mutex_is_locked(id) { + let owner_thread = this.mutex_get_owner(id); if owner_thread != active_thread { this.eval_libc_i32("EBUSY") } else { @@ -392,19 +404,18 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx { this.eval_libc_i32("EBUSY") } else if kind == this.eval_libc("PTHREAD_MUTEX_RECURSIVE")? { - match locked_count.checked_add(1) { - Some(new_count) => { - mutex_set_locked_count(this, mutex_op, Scalar::from_u32(new_count))?; - Ok(0) - } - None => this.eval_libc_i32("EAGAIN"), - } + this.mutex_lock(id, active_thread); + Ok(0) } else { throw_ub_format!( "called pthread_mutex_trylock on an unsupported type of mutex" ); } } + } else { + // The mutex is unlocked. Let's lock it. + this.mutex_lock(id, active_thread); + Ok(0) } } @@ -412,21 +423,20 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); let kind = mutex_get_kind(this, mutex_op)?.not_undef()?; - let locked_count = mutex_get_locked_count(this, mutex_op)?.to_u32()?; - let owner_thread: ThreadId = mutex_get_owner(this, mutex_op)?.to_u32()?.into(); - - if owner_thread != this.get_active_thread()? { - throw_ub_format!("called pthread_mutex_unlock on a mutex owned by another thread"); - } else if locked_count == 1 { - let blockset = mutex_get_or_create_blockset(this, mutex_op)?; - if let Some(new_owner) = this.unblock_some_thread(blockset)? { - // We have at least one thread waiting on this mutex. Transfer - // ownership to it. - mutex_set_owner(this, mutex_op, new_owner.to_u32_scalar())?; - } else { - // No thread is waiting on this mutex. - mutex_set_owner(this, mutex_op, Scalar::from_u32(0))?; - mutex_set_locked_count(this, mutex_op, Scalar::from_u32(0))?; + let id = mutex_get_or_create_id(this, mutex_op)?; + + if let Some((owner_thread, current_locked_count)) = this.mutex_unlock(id) { + if owner_thread != this.get_active_thread()? { + throw_ub_format!("called pthread_mutex_unlock on a mutex owned by another thread"); + } + if current_locked_count == 0 { + // The mutex is unlocked. + if let Some(thread) = this.mutex_dequeue(id) { + // We have at least one thread waiting on this mutex. Transfer + // ownership to it. + this.mutex_lock(id, thread); + this.unblock_thread(thread)?; + } } Ok(0) } else { @@ -435,16 +445,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } else if kind == this.eval_libc("PTHREAD_MUTEX_ERRORCHECK")? { this.eval_libc_i32("EPERM") } else if kind == this.eval_libc("PTHREAD_MUTEX_RECURSIVE")? { - match locked_count.checked_sub(1) { - Some(new_count) => { - mutex_set_locked_count(this, mutex_op, Scalar::from_u32(new_count))?; - Ok(0) - } - None => { - // locked_count was already zero - this.eval_libc_i32("EPERM") - } - } + this.eval_libc_i32("EPERM") } else { throw_ub_format!("called pthread_mutex_unlock on an unsupported type of mutex"); } @@ -454,13 +455,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn pthread_mutex_destroy(&mut self, mutex_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - if mutex_get_locked_count(this, mutex_op)?.to_u32()? != 0 { + let id = mutex_get_or_create_id(this, mutex_op)?; + + if this.mutex_is_locked(id) { throw_ub_format!("destroyed a locked mutex"); } - mutex_set_kind(this, mutex_op, ScalarMaybeUninit::Uninit)?; - mutex_set_locked_count(this, mutex_op, ScalarMaybeUninit::Uninit)?; - mutex_set_blockset(this, mutex_op, ScalarMaybeUninit::Uninit)?; + mutex_set_kind(this, mutex_op, ScalarMaybeUndef::Undef)?; + mutex_set_id(this, mutex_op, ScalarMaybeUndef::Undef)?; Ok(0) } @@ -468,121 +470,305 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn pthread_rwlock_rdlock(&mut self, rwlock_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - let readers = rwlock_get_readers(this, rwlock_op)?.to_u32()?; - let writers = rwlock_get_writers(this, rwlock_op)?.to_u32()?; + let id = rwlock_get_or_create_id(this, rwlock_op)?; + let active_thread = this.get_active_thread()?; - if writers != 0 { - // The lock is locked by a writer. - assert_eq!(writers, 1); - let reader_blockset = rwlock_get_or_create_reader_blockset(this, rwlock_op)?; - this.block_active_thread(reader_blockset)?; + if this.rwlock_is_write_locked(id) { + this.rwlock_enqueue_reader(id, active_thread); + this.block_thread(active_thread)?; Ok(0) } else { - match readers.checked_add(1) { - Some(new_readers) => { - rwlock_set_readers(this, rwlock_op, Scalar::from_u32(new_readers))?; - Ok(0) - } - None => this.eval_libc_i32("EAGAIN"), - } + this.rwlock_reader_add(id, active_thread); + Ok(0) } } fn pthread_rwlock_tryrdlock(&mut self, rwlock_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - let readers = rwlock_get_readers(this, rwlock_op)?.to_u32()?; - let writers = rwlock_get_writers(this, rwlock_op)?.to_u32()?; - if writers != 0 { + let id = rwlock_get_or_create_id(this, rwlock_op)?; + let active_thread = this.get_active_thread()?; + + if this.rwlock_is_write_locked(id) { this.eval_libc_i32("EBUSY") } else { - match readers.checked_add(1) { - Some(new_readers) => { - rwlock_set_readers(this, rwlock_op, Scalar::from_u32(new_readers))?; - Ok(0) - } - None => this.eval_libc_i32("EAGAIN"), - } + this.rwlock_reader_add(id, active_thread); + Ok(0) } } fn pthread_rwlock_wrlock(&mut self, rwlock_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - let readers = rwlock_get_readers(this, rwlock_op)?.to_u32()?; - let writers = rwlock_get_writers(this, rwlock_op)?.to_u32()?; - let writer_blockset = rwlock_get_or_create_writer_blockset(this, rwlock_op)?; - if readers != 0 || writers != 0 { - this.block_active_thread(writer_blockset)?; + let id = rwlock_get_or_create_id(this, rwlock_op)?; + let active_thread = this.get_active_thread()?; + + if this.rwlock_is_locked(id) { + this.block_thread(active_thread)?; + this.rwlock_enqueue_writer(id, active_thread); } else { - rwlock_set_writers(this, rwlock_op, Scalar::from_u32(1))?; + this.rwlock_writer_set(id, active_thread); } + Ok(0) } fn pthread_rwlock_trywrlock(&mut self, rwlock_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - let readers = rwlock_get_readers(this, rwlock_op)?.to_u32()?; - let writers = rwlock_get_writers(this, rwlock_op)?.to_u32()?; - if readers != 0 || writers != 0 { + let id = rwlock_get_or_create_id(this, rwlock_op)?; + let active_thread = this.get_active_thread()?; + + if this.rwlock_is_locked(id) { this.eval_libc_i32("EBUSY") } else { - rwlock_set_writers(this, rwlock_op, Scalar::from_u32(1))?; + this.rwlock_writer_set(id, active_thread); Ok(0) } } - // FIXME: We should check that this lock was locked by the active thread. fn pthread_rwlock_unlock(&mut self, rwlock_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - let readers = rwlock_get_readers(this, rwlock_op)?.to_u32()?; - let writers = rwlock_get_writers(this, rwlock_op)?.to_u32()?; - let writer_blockset = rwlock_get_or_create_writer_blockset(this, rwlock_op)?; - if let Some(new_readers) = readers.checked_sub(1) { - assert_eq!(writers, 0); - rwlock_set_readers(this, rwlock_op, Scalar::from_u32(new_readers))?; - if new_readers == 0 { - if let Some(_writer) = this.unblock_some_thread(writer_blockset)? { - rwlock_set_writers(this, rwlock_op, Scalar::from_u32(1))?; + let id = rwlock_get_or_create_id(this, rwlock_op)?; + let active_thread = this.get_active_thread()?; + + if this.rwlock_reader_remove(id, active_thread) { + // The thread was a reader. + if this.rwlock_is_locked(id) { + // No more readers owning the lock. Give it to a writer if there + // is any. + if let Some(writer) = this.rwlock_dequeue_writer(id) { + this.unblock_thread(writer)?; + this.rwlock_writer_set(id, writer); } } Ok(0) - } else if writers != 0 { - let reader_blockset = rwlock_get_or_create_reader_blockset(this, rwlock_op)?; + } else if Some(active_thread) == this.rwlock_writer_remove(id) { + // The thread was a writer. + // // We are prioritizing writers here against the readers. As a // result, not only readers can starve writers, but also writers can // starve readers. - if let Some(_writer) = this.unblock_some_thread(writer_blockset)? { - assert_eq!(writers, 1); + if let Some(writer) = this.rwlock_dequeue_writer(id) { + // Give the lock to another writer. + this.unblock_thread(writer)?; + this.rwlock_writer_set(id, writer); } else { - rwlock_set_writers(this, rwlock_op, Scalar::from_u32(0))?; - let mut readers = 0; - while let Some(_reader) = this.unblock_some_thread(reader_blockset)? { - readers += 1; + // Give the lock to all readers. + while let Some(reader) = this.rwlock_dequeue_reader(id) { + this.unblock_thread(reader)?; + this.rwlock_reader_add(id, reader); } - rwlock_set_readers(this, rwlock_op, Scalar::from_u32(readers))? } Ok(0) } else { - throw_ub_format!("unlocked an rwlock that was not locked"); + throw_ub_format!("unlocked an rwlock that was not locked by the active thread"); } } fn pthread_rwlock_destroy(&mut self, rwlock_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - if rwlock_get_readers(this, rwlock_op)?.to_u32()? != 0 - || rwlock_get_writers(this, rwlock_op)?.to_u32()? != 0 - { + let id = rwlock_get_or_create_id(this, rwlock_op)?; + + if this.rwlock_is_locked(id) { throw_ub_format!("destroyed a locked rwlock"); } - rwlock_set_readers(this, rwlock_op, ScalarMaybeUninit::Uninit)?; - rwlock_set_writers(this, rwlock_op, ScalarMaybeUninit::Uninit)?; - rwlock_set_reader_blockset(this, rwlock_op, ScalarMaybeUninit::Uninit)?; - rwlock_set_writer_blockset(this, rwlock_op, ScalarMaybeUninit::Uninit)?; + rwlock_set_id(this, rwlock_op, ScalarMaybeUndef::Undef)?; + + Ok(0) + } + + fn pthread_condattr_init(&mut self, attr_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + let this = self.eval_context_mut(); + + let default_clock_id = this.eval_libc("CLOCK_REALTIME")?; + condattr_set_clock_id(this, attr_op, default_clock_id)?; + + Ok(0) + } + + fn pthread_condattr_setclock( + &mut self, + attr_op: OpTy<'tcx, Tag>, + clock_id_op: OpTy<'tcx, Tag>, + ) -> InterpResult<'tcx, i32> { + let this = self.eval_context_mut(); + + let clock_id = this.read_scalar(clock_id_op)?.not_undef()?; + if clock_id == this.eval_libc("CLOCK_REALTIME")? + || clock_id == this.eval_libc("CLOCK_MONOTONIC")? + { + condattr_set_clock_id(this, attr_op, clock_id)?; + } else { + let einval = this.eval_libc_i32("EINVAL")?; + return Ok(einval); + } + + Ok(0) + } + + fn pthread_condattr_getclock( + &mut self, + attr_op: OpTy<'tcx, Tag>, + clk_id_op: OpTy<'tcx, Tag>, + ) -> InterpResult<'tcx, i32> { + let this = self.eval_context_mut(); + + let clock_id = condattr_get_clock_id(this, attr_op)?; + this.write_scalar(clock_id, this.deref_operand(clk_id_op)?.into())?; + + Ok(0) + } + + fn pthread_condattr_destroy(&mut self, attr_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + let this = self.eval_context_mut(); + + condattr_set_clock_id(this, attr_op, ScalarMaybeUndef::Undef)?; + + Ok(0) + } + + fn pthread_cond_init( + &mut self, + cond_op: OpTy<'tcx, Tag>, + attr_op: OpTy<'tcx, Tag>, + ) -> InterpResult<'tcx, i32> { + let this = self.eval_context_mut(); + + let attr = this.read_scalar(attr_op)?.not_undef()?; + let clock_id = if this.is_null(attr)? { + this.eval_libc("CLOCK_REALTIME")? + } else { + condattr_get_clock_id(this, attr_op)?.not_undef()? + }; + + let _ = cond_get_or_create_id(this, cond_op)?; + cond_set_clock_id(this, cond_op, clock_id)?; + + Ok(0) + } + + fn pthread_cond_signal(&mut self, cond_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + let this = self.eval_context_mut(); + let id = cond_get_or_create_id(this, cond_op)?; + if let Some((thread, mutex)) = this.condvar_signal(id) { + reacquire_cond_mutex(this, thread, mutex)?; + this.unregister_callback_if_exists(thread)?; + } + + Ok(0) + } + + fn pthread_cond_broadcast(&mut self, cond_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + let this = self.eval_context_mut(); + let id = cond_get_or_create_id(this, cond_op)?; + + while let Some((thread, mutex)) = this.condvar_signal(id) { + reacquire_cond_mutex(this, thread, mutex)?; + this.unregister_callback_if_exists(thread)?; + } + + Ok(0) + } + + fn pthread_cond_wait( + &mut self, + cond_op: OpTy<'tcx, Tag>, + mutex_op: OpTy<'tcx, Tag>, + ) -> InterpResult<'tcx, i32> { + let this = self.eval_context_mut(); + + let id = cond_get_or_create_id(this, cond_op)?; + let mutex_id = mutex_get_or_create_id(this, mutex_op)?; + let active_thread = this.get_active_thread()?; + + release_cond_mutex(this, active_thread, mutex_id)?; + this.condvar_wait(id, active_thread, mutex_id); + + Ok(0) + } + + fn pthread_cond_timedwait( + &mut self, + cond_op: OpTy<'tcx, Tag>, + mutex_op: OpTy<'tcx, Tag>, + abstime_op: OpTy<'tcx, Tag>, + dest: PlaceTy<'tcx, Tag>, + ) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + + this.check_no_isolation("pthread_cond_timedwait")?; + + let id = cond_get_or_create_id(this, cond_op)?; + let mutex_id = mutex_get_or_create_id(this, mutex_op)?; + let active_thread = this.get_active_thread()?; + + release_cond_mutex(this, active_thread, mutex_id)?; + this.condvar_wait(id, active_thread, mutex_id); + + // We return success for now and override it in the timeout callback. + this.write_scalar(Scalar::from_i32(0), dest)?; + + // Extract the timeout. + let clock_id = cond_get_clock_id(this, cond_op)?.to_i32()?; + let duration = { + let tp = this.deref_operand(abstime_op)?; + let mut offset = Size::from_bytes(0); + let layout = this.libc_ty_layout("time_t")?; + let seconds_place = tp.offset(offset, MemPlaceMeta::None, layout, this)?; + let seconds = this.read_scalar(seconds_place.into())?.to_u64()?; + offset += layout.size; + let layout = this.libc_ty_layout("c_long")?; + let nanoseconds_place = tp.offset(offset, MemPlaceMeta::None, layout, this)?; + let nanoseconds = this.read_scalar(nanoseconds_place.into())?.to_u64()?; + Duration::new(seconds, nanoseconds as u32) + }; + + let timeout_time = if clock_id == this.eval_libc_i32("CLOCK_REALTIME")? { + let time_anchor_since_epoch = + this.machine.time_anchor_timestamp.duration_since(SystemTime::UNIX_EPOCH).unwrap(); + let duration_since_time_anchor = duration.checked_sub(time_anchor_since_epoch).unwrap(); + this.machine.time_anchor.checked_add(duration_since_time_anchor).unwrap() + } else if clock_id == this.eval_libc_i32("CLOCK_MONOTONIC")? { + this.machine.time_anchor.checked_add(duration).unwrap() + } else { + throw_ub_format!("Unsupported clock id."); + }; + + // Register the timeout callback. + this.register_callback( + active_thread, + timeout_time, + Box::new(move |ecx| { + // Try to reacquire the mutex. + reacquire_cond_mutex(ecx, active_thread, mutex_id)?; + + // Remove the thread from the conditional variable. + ecx.condvar_remove_waiter(id, active_thread); + + // Set the timeout value. + let timeout = ecx.eval_libc_i32("ETIMEDOUT")?; + ecx.write_scalar(Scalar::from_i32(timeout), dest)?; + + Ok(()) + }), + )?; + + Ok(()) + } + + fn pthread_cond_destroy(&mut self, cond_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + let this = self.eval_context_mut(); + + let id = cond_get_or_create_id(this, cond_op)?; + if this.condvar_is_awaited(id) { + throw_ub_format!("destroyed an awaited conditional variable"); + } + cond_set_id(this, cond_op, ScalarMaybeUndef::Undef)?; + cond_set_clock_id(this, cond_op, ScalarMaybeUndef::Undef)?; Ok(0) } diff --git a/src/sync.rs b/src/sync.rs new file mode 100644 index 0000000000000..5d181692fb2a3 --- /dev/null +++ b/src/sync.rs @@ -0,0 +1,299 @@ +use std::collections::{hash_map::Entry, HashMap, VecDeque}; +use std::convert::TryFrom; +use std::num::NonZeroU32; +use std::time::Instant; + +use rustc_index::vec::{Idx, IndexVec}; + +use crate::*; + +macro_rules! declare_id { + ($name: ident) => { + #[derive(Clone, Copy, Debug, PartialOrd, Ord, PartialEq, Eq, Hash)] + pub struct $name(NonZeroU32); + + impl Idx for $name { + fn new(idx: usize) -> Self { + $name(NonZeroU32::new(u32::try_from(idx).unwrap() + 1).unwrap()) + } + fn index(self) -> usize { + usize::try_from(self.0.get() - 1).unwrap() + } + } + + impl From for $name { + fn from(id: u32) -> Self { + Self(NonZeroU32::new(id).unwrap()) + } + } + + impl $name { + pub fn to_u32_scalar<'tcx>(&self) -> Scalar { + Scalar::from_u32(self.0.get()) + } + } + }; +} + +declare_id!(MutexId); + +/// The mutex state. +#[derive(Default, Debug)] +struct Mutex { + /// The thread that currently owns the lock. + owner: Option, + /// How many times the mutex was locked by the owner. + lock_count: usize, + /// The queue of threads waiting for this mutex. + queue: VecDeque, +} + +declare_id!(RwLockId); + +/// The read-write lock state. +#[derive(Default, Debug)] +struct RwLock { + /// The writer thread that currently owns the lock. + writer: Option, + /// The readers that currently own the lock and how many times they acquired + /// the lock. + readers: HashMap, + /// The queue of writer threads waiting for this lock. + writer_queue: VecDeque, + /// The queue of reader threads waiting for this lock. + reader_queue: VecDeque, +} + +declare_id!(CondvarId); + +/// A thread waiting on a conditional variable. +#[derive(Debug)] +struct CondvarWaiter { + /// The thread that is waiting on this variable. + thread: ThreadId, + /// The mutex on which the thread is waiting. + mutex: MutexId, + /// The moment in time when the waiter should time out. + timeout: Option, +} + +/// The conditional variable state. +#[derive(Default, Debug)] +struct Condvar { + waiters: VecDeque, +} + +/// The state of all synchronization variables. +#[derive(Default, Debug)] +pub(super) struct SynchronizationState { + mutexes: IndexVec, + rwlocks: IndexVec, + condvars: IndexVec, +} + +// Public interface to synchronization primitives. Please note that in most +// cases, the function calls are infallible and it is the client's (shim +// implementation's) responsibility to detect and deal with erroneous +// situations. +impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} +pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { + #[inline] + /// Create state for a new mutex. + fn mutex_create(&mut self) -> MutexId { + let this = self.eval_context_mut(); + this.machine.threads.sync.mutexes.push(Default::default()) + } + + #[inline] + /// Get the id of the thread that currently owns this lock. + fn mutex_get_owner(&mut self, id: MutexId) -> ThreadId { + let this = self.eval_context_ref(); + this.machine.threads.sync.mutexes[id].owner.unwrap() + } + + #[inline] + /// Check if locked. + fn mutex_is_locked(&mut self, id: MutexId) -> bool { + let this = self.eval_context_mut(); + this.machine.threads.sync.mutexes[id].owner.is_some() + } + + /// Lock by setting the mutex owner and increasing the lock count. + fn mutex_lock(&mut self, id: MutexId, thread: ThreadId) { + let this = self.eval_context_mut(); + let mutex = &mut this.machine.threads.sync.mutexes[id]; + if let Some(current_owner) = mutex.owner { + assert_eq!(thread, current_owner, "mutex already locked by another thread"); + assert!( + mutex.lock_count > 0, + "invariant violation: lock_count == 0 iff the thread is unlocked" + ); + } else { + mutex.owner = Some(thread); + } + mutex.lock_count = mutex.lock_count.checked_add(1).unwrap(); + } + + /// Unlock by decreasing the lock count. If the lock count reaches 0, unset + /// the owner. + fn mutex_unlock(&mut self, id: MutexId) -> Option<(ThreadId, usize)> { + let this = self.eval_context_mut(); + let mutex = &mut this.machine.threads.sync.mutexes[id]; + if let Some(current_owner) = mutex.owner { + mutex.lock_count = mutex + .lock_count + .checked_sub(1) + .expect("invariant violation: lock_count == 0 iff the thread is unlocked"); + if mutex.lock_count == 0 { + mutex.owner = None; + } + Some((current_owner, mutex.lock_count)) + } else { + None + } + } + + #[inline] + /// Take a thread out the queue waiting for the lock. + fn mutex_enqueue(&mut self, id: MutexId, thread: ThreadId) { + let this = self.eval_context_mut(); + this.machine.threads.sync.mutexes[id].queue.push_back(thread); + } + + #[inline] + /// Take a thread out the queue waiting for the lock. + fn mutex_dequeue(&mut self, id: MutexId) -> Option { + let this = self.eval_context_mut(); + this.machine.threads.sync.mutexes[id].queue.pop_front() + } + + #[inline] + /// Create state for a new read write lock. + fn rwlock_create(&mut self) -> RwLockId { + let this = self.eval_context_mut(); + this.machine.threads.sync.rwlocks.push(Default::default()) + } + + #[inline] + /// Check if locked. + fn rwlock_is_locked(&mut self, id: RwLockId) -> bool { + let this = self.eval_context_mut(); + this.machine.threads.sync.rwlocks[id].writer.is_some() + || !this.machine.threads.sync.rwlocks[id].readers.is_empty() + } + + #[inline] + /// Check if write locked. + fn rwlock_is_write_locked(&mut self, id: RwLockId) -> bool { + let this = self.eval_context_mut(); + this.machine.threads.sync.rwlocks[id].writer.is_some() + } + + /// Add a reader that collectively with other readers owns the lock. + fn rwlock_reader_add(&mut self, id: RwLockId, reader: ThreadId) { + let this = self.eval_context_mut(); + assert!(!this.rwlock_is_write_locked(id), "the lock is write locked"); + let count = this.machine.threads.sync.rwlocks[id].readers.entry(reader).or_insert(0); + *count += 1; + } + + /// Try removing the reader. Returns `true` if succeeded. + fn rwlock_reader_remove(&mut self, id: RwLockId, reader: ThreadId) -> bool { + let this = self.eval_context_mut(); + match this.machine.threads.sync.rwlocks[id].readers.entry(reader) { + Entry::Occupied(mut entry) => { + let count = entry.get_mut(); + *count -= 1; + if *count == 0 { + entry.remove(); + } + true + } + Entry::Vacant(_) => false, + } + } + + #[inline] + /// Put the reader in the queue waiting for the lock. + fn rwlock_enqueue_reader(&mut self, id: RwLockId, reader: ThreadId) { + let this = self.eval_context_mut(); + assert!(this.rwlock_is_write_locked(id), "queueing on not write locked lock"); + this.machine.threads.sync.rwlocks[id].reader_queue.push_back(reader); + } + + #[inline] + /// Take the reader out the queue waiting for the lock. + fn rwlock_dequeue_reader(&mut self, id: RwLockId) -> Option { + let this = self.eval_context_mut(); + this.machine.threads.sync.rwlocks[id].reader_queue.pop_front() + } + + #[inline] + /// Lock by setting the writer that owns the lock. + fn rwlock_writer_set(&mut self, id: RwLockId, writer: ThreadId) { + let this = self.eval_context_mut(); + assert!(!this.rwlock_is_locked(id), "the lock is already locked"); + this.machine.threads.sync.rwlocks[id].writer = Some(writer); + } + + #[inline] + /// Try removing the writer. + fn rwlock_writer_remove(&mut self, id: RwLockId) -> Option { + let this = self.eval_context_mut(); + this.machine.threads.sync.rwlocks[id].writer.take() + } + + #[inline] + /// Put the writer in the queue waiting for the lock. + fn rwlock_enqueue_writer(&mut self, id: RwLockId, writer: ThreadId) { + let this = self.eval_context_mut(); + assert!(this.rwlock_is_locked(id), "queueing on unlocked lock"); + this.machine.threads.sync.rwlocks[id].writer_queue.push_back(writer); + } + + #[inline] + /// Take the writer out the queue waiting for the lock. + fn rwlock_dequeue_writer(&mut self, id: RwLockId) -> Option { + let this = self.eval_context_mut(); + this.machine.threads.sync.rwlocks[id].writer_queue.pop_front() + } + + #[inline] + /// Create state for a new conditional variable. + fn condvar_create(&mut self) -> CondvarId { + let this = self.eval_context_mut(); + this.machine.threads.sync.condvars.push(Default::default()) + } + + #[inline] + /// Is the conditional variable awaited? + fn condvar_is_awaited(&mut self, id: CondvarId) -> bool { + let this = self.eval_context_mut(); + !this.machine.threads.sync.condvars[id].waiters.is_empty() + } + + /// Mark that the thread is waiting on the conditional variable. + fn condvar_wait(&mut self, id: CondvarId, thread: ThreadId, mutex: MutexId) { + let this = self.eval_context_mut(); + let waiters = &mut this.machine.threads.sync.condvars[id].waiters; + assert!(waiters.iter().all(|waiter| waiter.thread != thread), "thread is already waiting"); + waiters.push_back(CondvarWaiter { thread, mutex, timeout: None }); + } + + /// Wake up some thread (if there is any) sleeping on the conditional + /// variable. + fn condvar_signal(&mut self, id: CondvarId) -> Option<(ThreadId, MutexId)> { + let this = self.eval_context_mut(); + this.machine.threads.sync.condvars[id] + .waiters + .pop_front() + .map(|waiter| (waiter.thread, waiter.mutex)) + } + + #[inline] + /// Remove the thread from the queue of threads waiting on this conditional variable. + fn condvar_remove_waiter(&mut self, id: CondvarId, thread: ThreadId) { + let this = self.eval_context_mut(); + this.machine.threads.sync.condvars[id].waiters.retain(|waiter| waiter.thread != thread); + } +} diff --git a/src/thread.rs b/src/thread.rs index d78beed28cfb7..6ebf35a6527f5 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -1,8 +1,10 @@ //! Implements threads. use std::cell::RefCell; +use std::collections::hash_map::Entry; use std::convert::TryFrom; use std::num::{NonZeroU32, TryFromIntError}; +use std::time::Instant; use log::trace; @@ -15,18 +17,24 @@ use rustc_middle::{ ty::{self, Instance}, }; +use crate::sync::SynchronizationState; use crate::*; #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum SchedulingAction { /// Execute step on the active thread. ExecuteStep, + /// Execute a scheduler's callback. + ExecuteCallback, /// Execute destructors of the active thread. ExecuteDtors, /// Stop the program. Stop, } +type EventCallback<'mir, 'tcx> = + Box>) -> InterpResult<'tcx> + 'tcx>; + /// A thread identifier. #[derive(Clone, Copy, Debug, PartialOrd, Ord, PartialEq, Eq, Hash)] pub struct ThreadId(u32); @@ -94,6 +102,7 @@ pub enum ThreadState { BlockedOnJoin(ThreadId), /// The thread is blocked and belongs to the given blockset. Blocked(BlockSetId), + BlockedThread, /// The thread has terminated its execution (we do not delete terminated /// threads). Terminated, @@ -162,6 +171,23 @@ impl<'mir, 'tcx> Default for Thread<'mir, 'tcx> { } } +/// Callbacks are used to implement timeouts. For example, waiting on a +/// conditional variable with a timeout creates a callback that is called after +/// the specified time and unblocks the thread. If another thread signals on the +/// conditional variable, the signal handler deletes the callback. +struct CallBackInfo<'mir, 'tcx> { + /// The callback should be called no earlier than this time. + call_time: Instant, + /// The called function. + callback: EventCallback<'mir, 'tcx>, +} + +impl<'mir, 'tcx> std::fmt::Debug for CallBackInfo<'mir, 'tcx> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "CallBack({:?})", self.call_time) + } +} + /// A set of threads. #[derive(Debug)] pub struct ThreadManager<'mir, 'tcx> { @@ -171,6 +197,8 @@ pub struct ThreadManager<'mir, 'tcx> { /// /// Note that this vector also contains terminated threads. threads: IndexVec>, + /// FIXME: make private. + pub(crate) sync: SynchronizationState, /// A counter used to generate unique identifiers for blocksets. blockset_counter: u32, /// A mapping from a thread-local static to an allocation id of a thread @@ -178,6 +206,8 @@ pub struct ThreadManager<'mir, 'tcx> { thread_local_alloc_ids: RefCell>, /// A flag that indicates that we should change the active thread. yield_active_thread: bool, + /// Callbacks that are called once the specified time passes. + callbacks: FxHashMap>, } impl<'mir, 'tcx> Default for ThreadManager<'mir, 'tcx> { @@ -191,9 +221,11 @@ impl<'mir, 'tcx> Default for ThreadManager<'mir, 'tcx> { Self { active_thread: ThreadId::new(0), threads: threads, + sync: SynchronizationState::default(), blockset_counter: 0, thread_local_alloc_ids: Default::default(), yield_active_thread: false, + callbacks: FxHashMap::default(), } } } @@ -321,30 +353,18 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { self.active_thread_ref().thread_name() } - /// Allocate a new blockset id. - fn create_blockset(&mut self) -> BlockSetId { - self.blockset_counter = self.blockset_counter.checked_add(1).unwrap(); - BlockSetId::new(self.blockset_counter) - } - - /// Block the currently active thread and put it into the given blockset. - fn block_active_thread(&mut self, set: BlockSetId) { - let state = &mut self.active_thread_mut().state; + /// Put the thread into the blocked state. + fn block_thread(&mut self, thread: ThreadId) { + let state = &mut self.threads[thread].state; assert_eq!(*state, ThreadState::Enabled); - *state = ThreadState::Blocked(set); + *state = ThreadState::BlockedThread; } - /// Unblock any one thread from the given blockset if it contains at least - /// one. Return the id of the unblocked thread. - fn unblock_some_thread(&mut self, set: BlockSetId) -> Option { - for (id, thread) in self.threads.iter_enumerated_mut() { - if thread.state == ThreadState::Blocked(set) { - trace!("unblocking {:?} in blockset {:?}", id, set); - thread.state = ThreadState::Enabled; - return Some(id); - } - } - None + /// Put the blocked thread into the enabled state. + fn unblock_thread(&mut self, thread: ThreadId) { + let state = &mut self.threads[thread].state; + assert_eq!(*state, ThreadState::BlockedThread); + *state = ThreadState::Enabled; } /// Change the active thread to some enabled thread. @@ -352,6 +372,39 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { self.yield_active_thread = true; } + /// Register the given `callback` to be called once the `call_time` passes. + fn register_callback( + &mut self, + thread: ThreadId, + call_time: Instant, + callback: EventCallback<'mir, 'tcx>, + ) { + self.callbacks + .insert(thread, CallBackInfo { call_time: call_time, callback: callback }) + .unwrap_none(); + } + + /// Unregister the callback for the `thread`. + fn unregister_callback_if_exists(&mut self, thread: ThreadId) { + self.callbacks.remove(&thread); + } + + /// Get a callback that is ready to be called. + fn get_callback(&mut self) -> Option<(ThreadId, EventCallback<'mir, 'tcx>)> { + let current_time = Instant::now(); + // We use a for loop here to make the scheduler more deterministic. + for thread in self.threads.indices() { + match self.callbacks.entry(thread) { + Entry::Occupied(entry) => + if current_time >= entry.get().call_time { + return Some((thread, entry.remove().callback)); + }, + Entry::Vacant(_) => {} + } + } + None + } + /// Decide which action to take next and on which thread. /// /// The currently implemented scheduling policy is the one that is commonly @@ -407,6 +460,18 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { // We have not found a thread to execute. if self.threads.iter().all(|thread| thread.state == ThreadState::Terminated) { unreachable!(); + } else if let Some(next_call_time) = + self.callbacks.values().min_by_key(|info| info.call_time) + { + // All threads are currently blocked, but we have unexecuted + // callbacks, which may unblock some of the threads. Hence, + // sleep until the first callback. + if let Some(sleep_time) = + next_call_time.call_time.checked_duration_since(Instant::now()) + { + std::thread::sleep(sleep_time); + } + Ok(SchedulingAction::ExecuteCallback) } else { throw_machine_stop!(TerminationInfo::Deadlock); } @@ -577,27 +642,51 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } #[inline] - fn create_blockset(&mut self) -> InterpResult<'tcx, BlockSetId> { + fn block_thread(&mut self, thread: ThreadId) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - Ok(this.machine.threads.create_blockset()) + Ok(this.machine.threads.block_thread(thread)) } #[inline] - fn block_active_thread(&mut self, set: BlockSetId) -> InterpResult<'tcx> { + fn unblock_thread(&mut self, thread: ThreadId) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - Ok(this.machine.threads.block_active_thread(set)) + Ok(this.machine.threads.unblock_thread(thread)) } #[inline] - fn unblock_some_thread(&mut self, set: BlockSetId) -> InterpResult<'tcx, Option> { + fn yield_active_thread(&mut self) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - Ok(this.machine.threads.unblock_some_thread(set)) + this.machine.threads.yield_active_thread(); + Ok(()) } #[inline] - fn yield_active_thread(&mut self) -> InterpResult<'tcx> { + fn register_callback( + &mut self, + thread: ThreadId, + call_time: Instant, + callback: EventCallback<'mir, 'tcx>, + ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - this.machine.threads.yield_active_thread(); + this.machine.threads.register_callback(thread, call_time, callback); + Ok(()) + } + + #[inline] + fn unregister_callback_if_exists(&mut self, thread: ThreadId) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + this.machine.threads.unregister_callback_if_exists(thread); + Ok(()) + } + + /// Execute the callback on the callback's thread. + #[inline] + fn run_scheduler_callback(&mut self) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + let (thread, callback) = this.machine.threads.get_callback().expect("no callback found"); + let old_thread = this.set_active_thread(thread)?; + callback(this)?; + this.set_active_thread(old_thread)?; Ok(()) } diff --git a/tests/run-pass/concurrency/barrier.rs b/tests/run-pass/concurrency/barrier.rs new file mode 100644 index 0000000000000..1e976a63453db --- /dev/null +++ b/tests/run-pass/concurrency/barrier.rs @@ -0,0 +1,27 @@ +// ignore-windows: Concurrency on Windows is not supported yet. + +//! Check if Rust barriers are working. + +use std::sync::{Arc, Barrier}; +use std::thread; + + +/// This test is taken from the Rust documentation. +fn main() { + let mut handles = Vec::with_capacity(10); + let barrier = Arc::new(Barrier::new(10)); + for _ in 0..10 { + let c = barrier.clone(); + // The same messages will be printed together. + // You will NOT see any interleaving. + handles.push(thread::spawn(move|| { + println!("before wait"); + c.wait(); + println!("after wait"); + })); + } + // Wait for other threads to finish. + for handle in handles { + handle.join().unwrap(); + } +} \ No newline at end of file diff --git a/tests/run-pass/concurrency/barrier.stderr b/tests/run-pass/concurrency/barrier.stderr new file mode 100644 index 0000000000000..2dbfb7721d368 --- /dev/null +++ b/tests/run-pass/concurrency/barrier.stderr @@ -0,0 +1,2 @@ +warning: thread support is experimental. For example, Miri does not detect data races yet. + diff --git a/tests/run-pass/concurrency/barrier.stdout b/tests/run-pass/concurrency/barrier.stdout new file mode 100644 index 0000000000000..f2c036a1735ed --- /dev/null +++ b/tests/run-pass/concurrency/barrier.stdout @@ -0,0 +1,20 @@ +before wait +before wait +before wait +before wait +before wait +before wait +before wait +before wait +before wait +before wait +after wait +after wait +after wait +after wait +after wait +after wait +after wait +after wait +after wait +after wait diff --git a/tests/run-pass/concurrency/condvar.rs b/tests/run-pass/concurrency/condvar.rs new file mode 100644 index 0000000000000..ab971ee6e8c63 --- /dev/null +++ b/tests/run-pass/concurrency/condvar.rs @@ -0,0 +1,28 @@ +// ignore-windows: Concurrency on Windows is not supported yet. + +//! Check if Rust conditional variables are working. + +use std::sync::{Arc, Condvar, Mutex}; +use std::thread; + +/// The test taken from the Rust documentation. +fn main() { + let pair = Arc::new((Mutex::new(false), Condvar::new())); + let pair2 = pair.clone(); + + // Inside of our lock, spawn a new thread, and then wait for it to start. + thread::spawn(move || { + let (lock, cvar) = &*pair2; + let mut started = lock.lock().unwrap(); + *started = true; + // We notify the condvar that the value has changed. + cvar.notify_one(); + }); + + // Wait for the thread to start up. + let (lock, cvar) = &*pair; + let mut started = lock.lock().unwrap(); + while !*started { + started = cvar.wait(started).unwrap(); + } +} diff --git a/tests/run-pass/concurrency/condvar.stderr b/tests/run-pass/concurrency/condvar.stderr new file mode 100644 index 0000000000000..2dbfb7721d368 --- /dev/null +++ b/tests/run-pass/concurrency/condvar.stderr @@ -0,0 +1,2 @@ +warning: thread support is experimental. For example, Miri does not detect data races yet. + diff --git a/tests/run-pass/concurrency/libc_pthread_cond.rs b/tests/run-pass/concurrency/libc_pthread_cond.rs new file mode 100644 index 0000000000000..83a651e6f04a7 --- /dev/null +++ b/tests/run-pass/concurrency/libc_pthread_cond.rs @@ -0,0 +1,199 @@ +// ignore-windows: No libc on Windows +// compile-flags: -Zmiri-disable-isolation + +#![feature(rustc_private)] + +extern crate libc; + +use std::cell::UnsafeCell; +use std::mem::{self, MaybeUninit}; +use std::sync::Arc; +use std::thread; + +struct Mutex { + inner: UnsafeCell, +} + +unsafe impl Sync for Mutex {} + +impl std::fmt::Debug for Mutex { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "Mutex") + } +} + +struct Cond { + inner: UnsafeCell, +} + +unsafe impl Sync for Cond {} + +impl std::fmt::Debug for Cond { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "Cond") + } +} + +unsafe fn create_cond_attr_monotonic() -> libc::pthread_condattr_t { + let mut attr = MaybeUninit::::uninit(); + assert_eq!(libc::pthread_condattr_init(attr.as_mut_ptr()), 0); + assert_eq!(libc::pthread_condattr_setclock(attr.as_mut_ptr(), libc::CLOCK_MONOTONIC), 0); + attr.assume_init() +} + +unsafe fn create_cond(attr: Option) -> Cond { + let cond: Cond = mem::zeroed(); + if let Some(mut attr) = attr { + assert_eq!(libc::pthread_cond_init(cond.inner.get() as *mut _, &attr as *const _), 0); + assert_eq!(libc::pthread_condattr_destroy(&mut attr as *mut _), 0); + } else { + assert_eq!(libc::pthread_cond_init(cond.inner.get() as *mut _, 0 as *const _), 0); + } + cond +} + +unsafe fn create_mutex() -> Mutex { + mem::zeroed() +} + +unsafe fn create_timeout(seconds: i64) -> libc::timespec { + let mut now: libc::timespec = mem::zeroed(); + assert_eq!(libc::clock_gettime(libc::CLOCK_MONOTONIC, &mut now), 0); + libc::timespec { tv_sec: now.tv_sec + seconds, tv_nsec: now.tv_nsec } +} + +fn test_pthread_condattr_t() { + unsafe { + let mut attr = create_cond_attr_monotonic(); + let mut clock_id = MaybeUninit::::uninit(); + assert_eq!(libc::pthread_condattr_getclock(&attr as *const _, clock_id.as_mut_ptr()), 0); + assert_eq!(clock_id.assume_init(), libc::CLOCK_MONOTONIC); + assert_eq!(libc::pthread_condattr_destroy(&mut attr as *mut _), 0); + } +} + +fn test_signal() { + unsafe { + let cond = Arc::new(create_cond(None)); + let mutex = Arc::new(create_mutex()); + + assert_eq!(libc::pthread_mutex_lock(mutex.inner.get() as *mut _), 0); + + let spawn_mutex = Arc::clone(&mutex); + let spawn_cond = Arc::clone(&cond); + let handle = thread::spawn(move || { + assert_eq!(libc::pthread_mutex_lock(spawn_mutex.inner.get() as *mut _), 0); + assert_eq!(libc::pthread_cond_signal(spawn_cond.inner.get() as *mut _), 0); + assert_eq!(libc::pthread_mutex_unlock(spawn_mutex.inner.get() as *mut _), 0); + }); + + assert_eq!( + libc::pthread_cond_wait(cond.inner.get() as *mut _, mutex.inner.get() as *mut _), + 0 + ); + assert_eq!(libc::pthread_mutex_unlock(mutex.inner.get() as *mut _), 0); + + handle.join().unwrap(); + + let mutex = Arc::try_unwrap(mutex).unwrap(); + assert_eq!(libc::pthread_mutex_destroy(mutex.inner.get() as *mut _), 0); + let cond = Arc::try_unwrap(cond).unwrap(); + assert_eq!(libc::pthread_cond_destroy(cond.inner.get() as *mut _), 0); + } +} + +fn test_broadcast() { + unsafe { + let cond = Arc::new(create_cond(None)); + let mutex = Arc::new(create_mutex()); + + assert_eq!(libc::pthread_mutex_lock(mutex.inner.get() as *mut _), 0); + + let spawn_mutex = Arc::clone(&mutex); + let spawn_cond = Arc::clone(&cond); + let handle = thread::spawn(move || { + assert_eq!(libc::pthread_mutex_lock(spawn_mutex.inner.get() as *mut _), 0); + assert_eq!(libc::pthread_cond_broadcast(spawn_cond.inner.get() as *mut _), 0); + assert_eq!(libc::pthread_mutex_unlock(spawn_mutex.inner.get() as *mut _), 0); + }); + + assert_eq!( + libc::pthread_cond_wait(cond.inner.get() as *mut _, mutex.inner.get() as *mut _), + 0 + ); + assert_eq!(libc::pthread_mutex_unlock(mutex.inner.get() as *mut _), 0); + + handle.join().unwrap(); + + let mutex = Arc::try_unwrap(mutex).unwrap(); + assert_eq!(libc::pthread_mutex_destroy(mutex.inner.get() as *mut _), 0); + let cond = Arc::try_unwrap(cond).unwrap(); + assert_eq!(libc::pthread_cond_destroy(cond.inner.get() as *mut _), 0); + } +} + +fn test_timed_wait_timeout() { + unsafe { + let attr = create_cond_attr_monotonic(); + let cond = create_cond(Some(attr)); + let mutex = create_mutex(); + let timeout = create_timeout(1); + + assert_eq!(libc::pthread_mutex_lock(mutex.inner.get() as *mut _), 0); + assert_eq!( + libc::pthread_cond_timedwait( + cond.inner.get() as *mut _, + mutex.inner.get() as *mut _, + &timeout + ), + libc::ETIMEDOUT + ); + assert_eq!(libc::pthread_mutex_unlock(mutex.inner.get() as *mut _), 0); + assert_eq!(libc::pthread_mutex_destroy(mutex.inner.get() as *mut _), 0); + assert_eq!(libc::pthread_cond_destroy(cond.inner.get() as *mut _), 0); + } +} + +fn test_timed_wait_notimeout() { + unsafe { + let attr = create_cond_attr_monotonic(); + let cond = Arc::new(create_cond(Some(attr))); + let mutex = Arc::new(create_mutex()); + let timeout = create_timeout(100); + + assert_eq!(libc::pthread_mutex_lock(mutex.inner.get() as *mut _), 0); + + let spawn_mutex = Arc::clone(&mutex); + let spawn_cond = Arc::clone(&cond); + let handle = thread::spawn(move || { + assert_eq!(libc::pthread_mutex_lock(spawn_mutex.inner.get() as *mut _), 0); + assert_eq!(libc::pthread_cond_signal(spawn_cond.inner.get() as *mut _), 0); + assert_eq!(libc::pthread_mutex_unlock(spawn_mutex.inner.get() as *mut _), 0); + }); + + assert_eq!( + libc::pthread_cond_timedwait( + cond.inner.get() as *mut _, + mutex.inner.get() as *mut _, + &timeout + ), + 0 + ); + assert_eq!(libc::pthread_mutex_unlock(mutex.inner.get() as *mut _), 0); + + handle.join().unwrap(); + + let mutex = Arc::try_unwrap(mutex).unwrap(); + assert_eq!(libc::pthread_mutex_destroy(mutex.inner.get() as *mut _), 0); + let cond = Arc::try_unwrap(cond).unwrap(); + assert_eq!(libc::pthread_cond_destroy(cond.inner.get() as *mut _), 0); + } +} + +fn main() { + test_pthread_condattr_t(); + test_signal(); + test_broadcast(); + test_timed_wait_timeout(); + test_timed_wait_notimeout(); +} diff --git a/tests/run-pass/concurrency/libc_pthread_cond.stderr b/tests/run-pass/concurrency/libc_pthread_cond.stderr new file mode 100644 index 0000000000000..2dbfb7721d368 --- /dev/null +++ b/tests/run-pass/concurrency/libc_pthread_cond.stderr @@ -0,0 +1,2 @@ +warning: thread support is experimental. For example, Miri does not detect data races yet. + diff --git a/tests/run-pass/concurrency/mpsc.rs b/tests/run-pass/concurrency/mpsc.rs new file mode 100644 index 0000000000000..3558f5415d071 --- /dev/null +++ b/tests/run-pass/concurrency/mpsc.rs @@ -0,0 +1,56 @@ +// ignore-windows: Concurrency on Windows is not supported yet. + +//! Check if Rust channels are working. + +use std::sync::mpsc::{channel, sync_channel}; +use std::thread; + +/// The test taken from the Rust documentation. +fn simple_send() { + let (tx, rx) = channel(); + thread::spawn(move || { + tx.send(10).unwrap(); + }); + assert_eq!(rx.recv().unwrap(), 10); +} + +/// The test taken from the Rust documentation. +fn multiple_send() { + let (tx, rx) = channel(); + for i in 0..10 { + let tx = tx.clone(); + thread::spawn(move || { + tx.send(i).unwrap(); + }); + } + + let mut sum = 0; + for _ in 0..10 { + let j = rx.recv().unwrap(); + assert!(0 <= j && j < 10); + sum += j; + } + assert_eq!(sum, 45); +} + +/// The test taken from the Rust documentation. +fn send_on_sync() { + let (sender, receiver) = sync_channel(1); + + // this returns immediately + sender.send(1).unwrap(); + + thread::spawn(move || { + // this will block until the previous message has been received + sender.send(2).unwrap(); + }); + + assert_eq!(receiver.recv().unwrap(), 1); + assert_eq!(receiver.recv().unwrap(), 2); +} + +fn main() { + simple_send(); + multiple_send(); + send_on_sync(); +} diff --git a/tests/run-pass/concurrency/mpsc.stderr b/tests/run-pass/concurrency/mpsc.stderr new file mode 100644 index 0000000000000..2dbfb7721d368 --- /dev/null +++ b/tests/run-pass/concurrency/mpsc.stderr @@ -0,0 +1,2 @@ +warning: thread support is experimental. For example, Miri does not detect data races yet. + diff --git a/tests/run-pass/concurrency/once.rs b/tests/run-pass/concurrency/once.rs new file mode 100644 index 0000000000000..499ceacfa8c40 --- /dev/null +++ b/tests/run-pass/concurrency/once.rs @@ -0,0 +1,44 @@ +// ignore-windows: Concurrency on Windows is not supported yet. + +//! Check if Rust once statics are working. The test taken from the Rust +//! documentation. + +use std::sync::Once; +use std::thread; + +static mut VAL: usize = 0; +static INIT: Once = Once::new(); + +fn get_cached_val() -> usize { + unsafe { + INIT.call_once(|| { + VAL = expensive_computation(); + }); + VAL + } +} + +fn expensive_computation() -> usize { + let mut i = 1; + let mut c = 1; + while i < 10000 { + i *= c; + c += 1; + } + i +} + +fn main() { + let handles: Vec<_> = (0..10) + .map(|_| { + thread::spawn(|| { + thread::yield_now(); + let val = get_cached_val(); + assert_eq!(val, 40320); + }) + }) + .collect(); + for handle in handles { + handle.join().unwrap(); + } +} diff --git a/tests/run-pass/concurrency/once.stderr b/tests/run-pass/concurrency/once.stderr new file mode 100644 index 0000000000000..2dbfb7721d368 --- /dev/null +++ b/tests/run-pass/concurrency/once.stderr @@ -0,0 +1,2 @@ +warning: thread support is experimental. For example, Miri does not detect data races yet. + From d0de439ac8366afce491250a64b78702fa5d7dd6 Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Thu, 30 Apr 2020 13:47:12 -0700 Subject: [PATCH 2087/3747] Cleanup. --- src/thread.rs | 28 +++++++--------------------- 1 file changed, 7 insertions(+), 21 deletions(-) diff --git a/src/thread.rs b/src/thread.rs index 6ebf35a6527f5..856468705d307 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -3,7 +3,7 @@ use std::cell::RefCell; use std::collections::hash_map::Entry; use std::convert::TryFrom; -use std::num::{NonZeroU32, TryFromIntError}; +use std::num::TryFromIntError; use std::time::Instant; use log::trace; @@ -77,21 +77,6 @@ impl ThreadId { } } -/// An identifier of a set of blocked threads. 0 is used to indicate the absence -/// of a blockset identifier and, therefore, is not a valid identifier. -#[derive(Clone, Copy, Debug, PartialOrd, Ord, PartialEq, Eq, Hash)] -pub struct BlockSetId(NonZeroU32); - -impl BlockSetId { - /// Panics if `id` is 0. - pub fn new(id: u32) -> Self { - Self(NonZeroU32::new(id).expect("0 is not a valid blockset id")) - } - pub fn to_u32_scalar<'tcx>(&self) -> Scalar { - Scalar::from_u32(self.0.get()) - } -} - /// The state of a thread. #[derive(Debug, Copy, Clone, PartialEq, Eq)] pub enum ThreadState { @@ -100,9 +85,10 @@ pub enum ThreadState { /// The thread tried to join the specified thread and is blocked until that /// thread terminates. BlockedOnJoin(ThreadId), - /// The thread is blocked and belongs to the given blockset. - Blocked(BlockSetId), - BlockedThread, + /// The thread is blocked on some synchronization primitive. It is the + /// responsibility of the synchronization primitives to track threads that + /// are blocked by them. + BlockedOnSync, /// The thread has terminated its execution (we do not delete terminated /// threads). Terminated, @@ -357,13 +343,13 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { fn block_thread(&mut self, thread: ThreadId) { let state = &mut self.threads[thread].state; assert_eq!(*state, ThreadState::Enabled); - *state = ThreadState::BlockedThread; + *state = ThreadState::BlockedOnSync; } /// Put the blocked thread into the enabled state. fn unblock_thread(&mut self, thread: ThreadId) { let state = &mut self.threads[thread].state; - assert_eq!(*state, ThreadState::BlockedThread); + assert_eq!(*state, ThreadState::BlockedOnSync); *state = ThreadState::Enabled; } From 044a068c672cf8edae2cd9d5032995f37f1c3718 Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Thu, 30 Apr 2020 14:07:07 -0700 Subject: [PATCH 2088/3747] Improve code readability and comments. --- src/eval.rs | 4 ++-- src/shims/sync.rs | 12 +++++----- src/sync.rs | 15 +++++++----- src/thread.rs | 60 +++++++++++++++++++++++------------------------ 4 files changed, 47 insertions(+), 44 deletions(-) diff --git a/src/eval.rs b/src/eval.rs index 30901a8f127f4..7a6c562e7ca07 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -210,11 +210,11 @@ pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) -> SchedulingAction::ExecuteStep => { assert!(ecx.step()?, "a terminated thread was scheduled for execution"); } - SchedulingAction::ExecuteCallback => { + SchedulingAction::ExecuteTimeoutCallback => { assert!(ecx.machine.communicate, "scheduler callbacks require disabled isolation, but the code \ that created the callback did not check it"); - ecx.run_scheduler_callback()?; + ecx.run_timeout_callback()?; } SchedulingAction::ExecuteDtors => { // This will either enable the thread again (so we go back diff --git a/src/shims/sync.rs b/src/shims/sync.rs index dfd7999457eb9..f31efe18e1c17 100644 --- a/src/shims/sync.rs +++ b/src/shims/sync.rs @@ -128,7 +128,7 @@ fn mutex_get_or_create_id<'mir, 'tcx: 'mir>( mutex_set_id(ecx, mutex_op, id.to_u32_scalar())?; Ok(id) } else { - Ok(id.into()) + Ok(MutexId::from_u32(id)) } } @@ -168,7 +168,7 @@ fn rwlock_get_or_create_id<'mir, 'tcx: 'mir>( rwlock_set_id(ecx, rwlock_op, id.to_u32_scalar())?; Ok(id) } else { - Ok(id.into()) + Ok(RwLockId::from_u32(id)) } } @@ -232,7 +232,7 @@ fn cond_get_or_create_id<'mir, 'tcx: 'mir>( cond_set_id(ecx, cond_op, id.to_u32_scalar())?; Ok(id) } else { - Ok(id.into()) + Ok(CondvarId::from_u32(id)) } } @@ -656,7 +656,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let id = cond_get_or_create_id(this, cond_op)?; if let Some((thread, mutex)) = this.condvar_signal(id) { reacquire_cond_mutex(this, thread, mutex)?; - this.unregister_callback_if_exists(thread)?; + this.unregister_timeout_callback_if_exists(thread)?; } Ok(0) @@ -668,7 +668,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx while let Some((thread, mutex)) = this.condvar_signal(id) { reacquire_cond_mutex(this, thread, mutex)?; - this.unregister_callback_if_exists(thread)?; + this.unregister_timeout_callback_if_exists(thread)?; } Ok(0) @@ -739,7 +739,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx }; // Register the timeout callback. - this.register_callback( + this.register_timeout_callback( active_thread, timeout_time, Box::new(move |ecx| { diff --git a/src/sync.rs b/src/sync.rs index 5d181692fb2a3..88b5d6c060ddc 100644 --- a/src/sync.rs +++ b/src/sync.rs @@ -9,9 +9,18 @@ use crate::*; macro_rules! declare_id { ($name: ident) => { + /// 0 is used to indicate that the id was not yet assigned and, + /// therefore, is not a valid identifier. #[derive(Clone, Copy, Debug, PartialOrd, Ord, PartialEq, Eq, Hash)] pub struct $name(NonZeroU32); + impl $name { + // Panics if `id == 0`. + pub fn from_u32(id: u32) -> Self { + Self(NonZeroU32::new(id).unwrap()) + } + } + impl Idx for $name { fn new(idx: usize) -> Self { $name(NonZeroU32::new(u32::try_from(idx).unwrap() + 1).unwrap()) @@ -21,12 +30,6 @@ macro_rules! declare_id { } } - impl From for $name { - fn from(id: u32) -> Self { - Self(NonZeroU32::new(id).unwrap()) - } - } - impl $name { pub fn to_u32_scalar<'tcx>(&self) -> Scalar { Scalar::from_u32(self.0.get()) diff --git a/src/thread.rs b/src/thread.rs index 856468705d307..f67de48b710db 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -24,15 +24,17 @@ use crate::*; pub enum SchedulingAction { /// Execute step on the active thread. ExecuteStep, - /// Execute a scheduler's callback. - ExecuteCallback, + /// Execute a timeout callback. + ExecuteTimeoutCallback, /// Execute destructors of the active thread. ExecuteDtors, /// Stop the program. Stop, } -type EventCallback<'mir, 'tcx> = +/// Timeout timeout_callbacks can be created by synchronization primitives to tell the +/// scheduler that they should be called once some period of time passes. +type TimeoutCallback<'mir, 'tcx> = Box>) -> InterpResult<'tcx> + 'tcx>; /// A thread identifier. @@ -161,14 +163,14 @@ impl<'mir, 'tcx> Default for Thread<'mir, 'tcx> { /// conditional variable with a timeout creates a callback that is called after /// the specified time and unblocks the thread. If another thread signals on the /// conditional variable, the signal handler deletes the callback. -struct CallBackInfo<'mir, 'tcx> { +struct TimeoutCallbackInfo<'mir, 'tcx> { /// The callback should be called no earlier than this time. call_time: Instant, /// The called function. - callback: EventCallback<'mir, 'tcx>, + callback: TimeoutCallback<'mir, 'tcx>, } -impl<'mir, 'tcx> std::fmt::Debug for CallBackInfo<'mir, 'tcx> { +impl<'mir, 'tcx> std::fmt::Debug for TimeoutCallbackInfo<'mir, 'tcx> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "CallBack({:?})", self.call_time) } @@ -183,17 +185,16 @@ pub struct ThreadManager<'mir, 'tcx> { /// /// Note that this vector also contains terminated threads. threads: IndexVec>, - /// FIXME: make private. + /// This field is pub(crate) because the synchronization primitives + /// (`crate::sync`) need a way to access it. pub(crate) sync: SynchronizationState, - /// A counter used to generate unique identifiers for blocksets. - blockset_counter: u32, /// A mapping from a thread-local static to an allocation id of a thread /// specific allocation. thread_local_alloc_ids: RefCell>, /// A flag that indicates that we should change the active thread. yield_active_thread: bool, /// Callbacks that are called once the specified time passes. - callbacks: FxHashMap>, + timeout_callbacks: FxHashMap>, } impl<'mir, 'tcx> Default for ThreadManager<'mir, 'tcx> { @@ -208,10 +209,9 @@ impl<'mir, 'tcx> Default for ThreadManager<'mir, 'tcx> { active_thread: ThreadId::new(0), threads: threads, sync: SynchronizationState::default(), - blockset_counter: 0, thread_local_alloc_ids: Default::default(), yield_active_thread: false, - callbacks: FxHashMap::default(), + timeout_callbacks: FxHashMap::default(), } } } @@ -359,28 +359,28 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { } /// Register the given `callback` to be called once the `call_time` passes. - fn register_callback( + fn register_timeout_callback( &mut self, thread: ThreadId, call_time: Instant, - callback: EventCallback<'mir, 'tcx>, + callback: TimeoutCallback<'mir, 'tcx>, ) { - self.callbacks - .insert(thread, CallBackInfo { call_time: call_time, callback: callback }) + self.timeout_callbacks + .insert(thread, TimeoutCallbackInfo { call_time: call_time, callback: callback }) .unwrap_none(); } /// Unregister the callback for the `thread`. - fn unregister_callback_if_exists(&mut self, thread: ThreadId) { - self.callbacks.remove(&thread); + fn unregister_timeout_callback_if_exists(&mut self, thread: ThreadId) { + self.timeout_callbacks.remove(&thread); } /// Get a callback that is ready to be called. - fn get_callback(&mut self) -> Option<(ThreadId, EventCallback<'mir, 'tcx>)> { + fn get_callback(&mut self) -> Option<(ThreadId, TimeoutCallback<'mir, 'tcx>)> { let current_time = Instant::now(); // We use a for loop here to make the scheduler more deterministic. for thread in self.threads.indices() { - match self.callbacks.entry(thread) { + match self.timeout_callbacks.entry(thread) { Entry::Occupied(entry) => if current_time >= entry.get().call_time { return Some((thread, entry.remove().callback)); @@ -447,17 +447,17 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { if self.threads.iter().all(|thread| thread.state == ThreadState::Terminated) { unreachable!(); } else if let Some(next_call_time) = - self.callbacks.values().min_by_key(|info| info.call_time) + self.timeout_callbacks.values().min_by_key(|info| info.call_time) { // All threads are currently blocked, but we have unexecuted - // callbacks, which may unblock some of the threads. Hence, + // timeout_callbacks, which may unblock some of the threads. Hence, // sleep until the first callback. if let Some(sleep_time) = next_call_time.call_time.checked_duration_since(Instant::now()) { std::thread::sleep(sleep_time); } - Ok(SchedulingAction::ExecuteCallback) + Ok(SchedulingAction::ExecuteTimeoutCallback) } else { throw_machine_stop!(TerminationInfo::Deadlock); } @@ -647,27 +647,27 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } #[inline] - fn register_callback( + fn register_timeout_callback( &mut self, thread: ThreadId, call_time: Instant, - callback: EventCallback<'mir, 'tcx>, + callback: TimeoutCallback<'mir, 'tcx>, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - this.machine.threads.register_callback(thread, call_time, callback); + this.machine.threads.register_timeout_callback(thread, call_time, callback); Ok(()) } #[inline] - fn unregister_callback_if_exists(&mut self, thread: ThreadId) -> InterpResult<'tcx> { + fn unregister_timeout_callback_if_exists(&mut self, thread: ThreadId) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - this.machine.threads.unregister_callback_if_exists(thread); + this.machine.threads.unregister_timeout_callback_if_exists(thread); Ok(()) } - /// Execute the callback on the callback's thread. + /// Execute a timeout callback on the callback's thread. #[inline] - fn run_scheduler_callback(&mut self) -> InterpResult<'tcx> { + fn run_timeout_callback(&mut self) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let (thread, callback) = this.machine.threads.get_callback().expect("no callback found"); let old_thread = this.set_active_thread(thread)?; From 6e774dec86daeda8aa6ae2fa20c2334cd8841db6 Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Thu, 30 Apr 2020 14:48:09 -0700 Subject: [PATCH 2089/3747] Move all run-pass synchronization primitive tests to sync.rs. --- tests/run-pass/concurrency/barrier.rs | 27 --- tests/run-pass/concurrency/condvar.rs | 28 --- tests/run-pass/concurrency/condvar.stderr | 2 - tests/run-pass/concurrency/locks.rs | 75 ------ tests/run-pass/concurrency/locks.stderr | 2 - tests/run-pass/concurrency/mpsc.rs | 56 ----- tests/run-pass/concurrency/mpsc.stderr | 2 - tests/run-pass/concurrency/once.rs | 44 ---- tests/run-pass/concurrency/once.stderr | 2 - tests/run-pass/concurrency/sync.rs | 216 ++++++++++++++++++ .../{barrier.stderr => sync.stderr} | 0 .../{barrier.stdout => sync.stdout} | 0 12 files changed, 216 insertions(+), 238 deletions(-) delete mode 100644 tests/run-pass/concurrency/barrier.rs delete mode 100644 tests/run-pass/concurrency/condvar.rs delete mode 100644 tests/run-pass/concurrency/condvar.stderr delete mode 100644 tests/run-pass/concurrency/locks.rs delete mode 100644 tests/run-pass/concurrency/locks.stderr delete mode 100644 tests/run-pass/concurrency/mpsc.rs delete mode 100644 tests/run-pass/concurrency/mpsc.stderr delete mode 100644 tests/run-pass/concurrency/once.rs delete mode 100644 tests/run-pass/concurrency/once.stderr create mode 100644 tests/run-pass/concurrency/sync.rs rename tests/run-pass/concurrency/{barrier.stderr => sync.stderr} (100%) rename tests/run-pass/concurrency/{barrier.stdout => sync.stdout} (100%) diff --git a/tests/run-pass/concurrency/barrier.rs b/tests/run-pass/concurrency/barrier.rs deleted file mode 100644 index 1e976a63453db..0000000000000 --- a/tests/run-pass/concurrency/barrier.rs +++ /dev/null @@ -1,27 +0,0 @@ -// ignore-windows: Concurrency on Windows is not supported yet. - -//! Check if Rust barriers are working. - -use std::sync::{Arc, Barrier}; -use std::thread; - - -/// This test is taken from the Rust documentation. -fn main() { - let mut handles = Vec::with_capacity(10); - let barrier = Arc::new(Barrier::new(10)); - for _ in 0..10 { - let c = barrier.clone(); - // The same messages will be printed together. - // You will NOT see any interleaving. - handles.push(thread::spawn(move|| { - println!("before wait"); - c.wait(); - println!("after wait"); - })); - } - // Wait for other threads to finish. - for handle in handles { - handle.join().unwrap(); - } -} \ No newline at end of file diff --git a/tests/run-pass/concurrency/condvar.rs b/tests/run-pass/concurrency/condvar.rs deleted file mode 100644 index ab971ee6e8c63..0000000000000 --- a/tests/run-pass/concurrency/condvar.rs +++ /dev/null @@ -1,28 +0,0 @@ -// ignore-windows: Concurrency on Windows is not supported yet. - -//! Check if Rust conditional variables are working. - -use std::sync::{Arc, Condvar, Mutex}; -use std::thread; - -/// The test taken from the Rust documentation. -fn main() { - let pair = Arc::new((Mutex::new(false), Condvar::new())); - let pair2 = pair.clone(); - - // Inside of our lock, spawn a new thread, and then wait for it to start. - thread::spawn(move || { - let (lock, cvar) = &*pair2; - let mut started = lock.lock().unwrap(); - *started = true; - // We notify the condvar that the value has changed. - cvar.notify_one(); - }); - - // Wait for the thread to start up. - let (lock, cvar) = &*pair; - let mut started = lock.lock().unwrap(); - while !*started { - started = cvar.wait(started).unwrap(); - } -} diff --git a/tests/run-pass/concurrency/condvar.stderr b/tests/run-pass/concurrency/condvar.stderr deleted file mode 100644 index 2dbfb7721d368..0000000000000 --- a/tests/run-pass/concurrency/condvar.stderr +++ /dev/null @@ -1,2 +0,0 @@ -warning: thread support is experimental. For example, Miri does not detect data races yet. - diff --git a/tests/run-pass/concurrency/locks.rs b/tests/run-pass/concurrency/locks.rs deleted file mode 100644 index f5469712c5f55..0000000000000 --- a/tests/run-pass/concurrency/locks.rs +++ /dev/null @@ -1,75 +0,0 @@ -// ignore-windows: Concurrency on Windows is not supported yet. - -use std::sync::{Arc, Mutex, RwLock}; -use std::thread; - -fn check_mutex() { - let data = Arc::new(Mutex::new(0)); - let mut threads = Vec::new(); - - for _ in 0..3 { - let data = Arc::clone(&data); - let thread = thread::spawn(move || { - let mut data = data.lock().unwrap(); - thread::yield_now(); - *data += 1; - }); - threads.push(thread); - } - - for thread in threads { - thread.join().unwrap(); - } - - assert!(data.try_lock().is_ok()); - - let data = Arc::try_unwrap(data).unwrap().into_inner().unwrap(); - assert_eq!(data, 3); -} - -fn check_rwlock_write() { - let data = Arc::new(RwLock::new(0)); - let mut threads = Vec::new(); - - for _ in 0..3 { - let data = Arc::clone(&data); - let thread = thread::spawn(move || { - let mut data = data.write().unwrap(); - thread::yield_now(); - *data += 1; - }); - threads.push(thread); - } - - for thread in threads { - thread.join().unwrap(); - } - - assert!(data.try_write().is_ok()); - - let data = Arc::try_unwrap(data).unwrap().into_inner().unwrap(); - assert_eq!(data, 3); -} - -fn check_rwlock_read_no_deadlock() { - let l1 = Arc::new(RwLock::new(0)); - let l2 = Arc::new(RwLock::new(0)); - - let l1_copy = Arc::clone(&l1); - let l2_copy = Arc::clone(&l2); - let _guard1 = l1.read().unwrap(); - let handle = thread::spawn(move || { - let _guard2 = l2_copy.read().unwrap(); - thread::yield_now(); - let _guard1 = l1_copy.read().unwrap(); - }); - thread::yield_now(); - let _guard2 = l2.read().unwrap(); - handle.join().unwrap(); -} - -fn main() { - check_mutex(); - check_rwlock_write(); - check_rwlock_read_no_deadlock(); -} diff --git a/tests/run-pass/concurrency/locks.stderr b/tests/run-pass/concurrency/locks.stderr deleted file mode 100644 index 2dbfb7721d368..0000000000000 --- a/tests/run-pass/concurrency/locks.stderr +++ /dev/null @@ -1,2 +0,0 @@ -warning: thread support is experimental. For example, Miri does not detect data races yet. - diff --git a/tests/run-pass/concurrency/mpsc.rs b/tests/run-pass/concurrency/mpsc.rs deleted file mode 100644 index 3558f5415d071..0000000000000 --- a/tests/run-pass/concurrency/mpsc.rs +++ /dev/null @@ -1,56 +0,0 @@ -// ignore-windows: Concurrency on Windows is not supported yet. - -//! Check if Rust channels are working. - -use std::sync::mpsc::{channel, sync_channel}; -use std::thread; - -/// The test taken from the Rust documentation. -fn simple_send() { - let (tx, rx) = channel(); - thread::spawn(move || { - tx.send(10).unwrap(); - }); - assert_eq!(rx.recv().unwrap(), 10); -} - -/// The test taken from the Rust documentation. -fn multiple_send() { - let (tx, rx) = channel(); - for i in 0..10 { - let tx = tx.clone(); - thread::spawn(move || { - tx.send(i).unwrap(); - }); - } - - let mut sum = 0; - for _ in 0..10 { - let j = rx.recv().unwrap(); - assert!(0 <= j && j < 10); - sum += j; - } - assert_eq!(sum, 45); -} - -/// The test taken from the Rust documentation. -fn send_on_sync() { - let (sender, receiver) = sync_channel(1); - - // this returns immediately - sender.send(1).unwrap(); - - thread::spawn(move || { - // this will block until the previous message has been received - sender.send(2).unwrap(); - }); - - assert_eq!(receiver.recv().unwrap(), 1); - assert_eq!(receiver.recv().unwrap(), 2); -} - -fn main() { - simple_send(); - multiple_send(); - send_on_sync(); -} diff --git a/tests/run-pass/concurrency/mpsc.stderr b/tests/run-pass/concurrency/mpsc.stderr deleted file mode 100644 index 2dbfb7721d368..0000000000000 --- a/tests/run-pass/concurrency/mpsc.stderr +++ /dev/null @@ -1,2 +0,0 @@ -warning: thread support is experimental. For example, Miri does not detect data races yet. - diff --git a/tests/run-pass/concurrency/once.rs b/tests/run-pass/concurrency/once.rs deleted file mode 100644 index 499ceacfa8c40..0000000000000 --- a/tests/run-pass/concurrency/once.rs +++ /dev/null @@ -1,44 +0,0 @@ -// ignore-windows: Concurrency on Windows is not supported yet. - -//! Check if Rust once statics are working. The test taken from the Rust -//! documentation. - -use std::sync::Once; -use std::thread; - -static mut VAL: usize = 0; -static INIT: Once = Once::new(); - -fn get_cached_val() -> usize { - unsafe { - INIT.call_once(|| { - VAL = expensive_computation(); - }); - VAL - } -} - -fn expensive_computation() -> usize { - let mut i = 1; - let mut c = 1; - while i < 10000 { - i *= c; - c += 1; - } - i -} - -fn main() { - let handles: Vec<_> = (0..10) - .map(|_| { - thread::spawn(|| { - thread::yield_now(); - let val = get_cached_val(); - assert_eq!(val, 40320); - }) - }) - .collect(); - for handle in handles { - handle.join().unwrap(); - } -} diff --git a/tests/run-pass/concurrency/once.stderr b/tests/run-pass/concurrency/once.stderr deleted file mode 100644 index 2dbfb7721d368..0000000000000 --- a/tests/run-pass/concurrency/once.stderr +++ /dev/null @@ -1,2 +0,0 @@ -warning: thread support is experimental. For example, Miri does not detect data races yet. - diff --git a/tests/run-pass/concurrency/sync.rs b/tests/run-pass/concurrency/sync.rs new file mode 100644 index 0000000000000..b09bfe9e0c868 --- /dev/null +++ b/tests/run-pass/concurrency/sync.rs @@ -0,0 +1,216 @@ +// ignore-windows: Concurrency on Windows is not supported yet. + +use std::sync::mpsc::{channel, sync_channel}; +use std::sync::{Arc, Barrier, Condvar, Mutex, Once, RwLock}; +use std::thread; + +// Check if Rust barriers are working. + +/// This test is taken from the Rust documentation. +fn check_barriers() { + let mut handles = Vec::with_capacity(10); + let barrier = Arc::new(Barrier::new(10)); + for _ in 0..10 { + let c = barrier.clone(); + // The same messages will be printed together. + // You will NOT see any interleaving. + handles.push(thread::spawn(move || { + println!("before wait"); + c.wait(); + println!("after wait"); + })); + } + // Wait for other threads to finish. + for handle in handles { + handle.join().unwrap(); + } +} + +// Check if Rust conditional variables are working. + +/// The test taken from the Rust documentation. +fn check_conditional_variables() { + let pair = Arc::new((Mutex::new(false), Condvar::new())); + let pair2 = pair.clone(); + + // Inside of our lock, spawn a new thread, and then wait for it to start. + thread::spawn(move || { + let (lock, cvar) = &*pair2; + let mut started = lock.lock().unwrap(); + *started = true; + // We notify the condvar that the value has changed. + cvar.notify_one(); + }); + + // Wait for the thread to start up. + let (lock, cvar) = &*pair; + let mut started = lock.lock().unwrap(); + while !*started { + started = cvar.wait(started).unwrap(); + } +} + +// Check if locks are working. + +fn check_mutex() { + let data = Arc::new(Mutex::new(0)); + let mut threads = Vec::new(); + + for _ in 0..3 { + let data = Arc::clone(&data); + let thread = thread::spawn(move || { + let mut data = data.lock().unwrap(); + thread::yield_now(); + *data += 1; + }); + threads.push(thread); + } + + for thread in threads { + thread.join().unwrap(); + } + + assert!(data.try_lock().is_ok()); + + let data = Arc::try_unwrap(data).unwrap().into_inner().unwrap(); + assert_eq!(data, 3); +} + +fn check_rwlock_write() { + let data = Arc::new(RwLock::new(0)); + let mut threads = Vec::new(); + + for _ in 0..3 { + let data = Arc::clone(&data); + let thread = thread::spawn(move || { + let mut data = data.write().unwrap(); + thread::yield_now(); + *data += 1; + }); + threads.push(thread); + } + + for thread in threads { + thread.join().unwrap(); + } + + assert!(data.try_write().is_ok()); + + let data = Arc::try_unwrap(data).unwrap().into_inner().unwrap(); + assert_eq!(data, 3); +} + +fn check_rwlock_read_no_deadlock() { + let l1 = Arc::new(RwLock::new(0)); + let l2 = Arc::new(RwLock::new(0)); + + let l1_copy = Arc::clone(&l1); + let l2_copy = Arc::clone(&l2); + let _guard1 = l1.read().unwrap(); + let handle = thread::spawn(move || { + let _guard2 = l2_copy.read().unwrap(); + thread::yield_now(); + let _guard1 = l1_copy.read().unwrap(); + }); + thread::yield_now(); + let _guard2 = l2.read().unwrap(); + handle.join().unwrap(); +} + +// Check if channels are working. + +/// The test taken from the Rust documentation. +fn simple_send() { + let (tx, rx) = channel(); + thread::spawn(move || { + tx.send(10).unwrap(); + }); + assert_eq!(rx.recv().unwrap(), 10); +} + +/// The test taken from the Rust documentation. +fn multiple_send() { + let (tx, rx) = channel(); + for i in 0..10 { + let tx = tx.clone(); + thread::spawn(move || { + tx.send(i).unwrap(); + }); + } + + let mut sum = 0; + for _ in 0..10 { + let j = rx.recv().unwrap(); + assert!(0 <= j && j < 10); + sum += j; + } + assert_eq!(sum, 45); +} + +/// The test taken from the Rust documentation. +fn send_on_sync() { + let (sender, receiver) = sync_channel(1); + + // this returns immediately + sender.send(1).unwrap(); + + thread::spawn(move || { + // this will block until the previous message has been received + sender.send(2).unwrap(); + }); + + assert_eq!(receiver.recv().unwrap(), 1); + assert_eq!(receiver.recv().unwrap(), 2); +} + +// Check if Rust once statics are working. + +static mut VAL: usize = 0; +static INIT: Once = Once::new(); + +fn get_cached_val() -> usize { + unsafe { + INIT.call_once(|| { + VAL = expensive_computation(); + }); + VAL + } +} + +fn expensive_computation() -> usize { + let mut i = 1; + let mut c = 1; + while i < 10000 { + i *= c; + c += 1; + } + i +} + +/// The test taken from the Rust documentation. +fn check_once() { + let handles: Vec<_> = (0..10) + .map(|_| { + thread::spawn(|| { + thread::yield_now(); + let val = get_cached_val(); + assert_eq!(val, 40320); + }) + }) + .collect(); + for handle in handles { + handle.join().unwrap(); + } +} + +fn main() { + check_barriers(); + check_conditional_variables(); + check_mutex(); + check_rwlock_write(); + check_rwlock_read_no_deadlock(); + simple_send(); + multiple_send(); + send_on_sync(); + check_once(); +} diff --git a/tests/run-pass/concurrency/barrier.stderr b/tests/run-pass/concurrency/sync.stderr similarity index 100% rename from tests/run-pass/concurrency/barrier.stderr rename to tests/run-pass/concurrency/sync.stderr diff --git a/tests/run-pass/concurrency/barrier.stdout b/tests/run-pass/concurrency/sync.stdout similarity index 100% rename from tests/run-pass/concurrency/barrier.stdout rename to tests/run-pass/concurrency/sync.stdout From 4a303b13095122c2007bf8751bdbc0e89b8708d3 Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Thu, 30 Apr 2020 14:59:35 -0700 Subject: [PATCH 2090/3747] Add a timeout test for conditional variables. --- tests/run-pass/concurrency/sync.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/tests/run-pass/concurrency/sync.rs b/tests/run-pass/concurrency/sync.rs index b09bfe9e0c868..e422a7fbdbc5b 100644 --- a/tests/run-pass/concurrency/sync.rs +++ b/tests/run-pass/concurrency/sync.rs @@ -1,8 +1,10 @@ // ignore-windows: Concurrency on Windows is not supported yet. +// compile-flags: -Zmiri-disable-isolation use std::sync::mpsc::{channel, sync_channel}; use std::sync::{Arc, Barrier, Condvar, Mutex, Once, RwLock}; use std::thread; +use std::time::{Duration, Instant}; // Check if Rust barriers are working. @@ -50,6 +52,17 @@ fn check_conditional_variables() { } } +/// Test that waiting on a conditional variable with a timeout does not +/// deadlock. +fn check_conditional_variables_timeout() { + let lock = Mutex::new(()); + let cvar = Condvar::new(); + let guard = lock.lock().unwrap(); + let now = Instant::now(); + let _guard = cvar.wait_timeout(guard, Duration::from_millis(100)).unwrap().0; + assert!(now.elapsed().as_millis() >= 100); +} + // Check if locks are working. fn check_mutex() { @@ -206,6 +219,7 @@ fn check_once() { fn main() { check_barriers(); check_conditional_variables(); + check_conditional_variables_timeout(); check_mutex(); check_rwlock_write(); check_rwlock_read_no_deadlock(); From 86eb262e8a2d270cc8195185b217710f815761b3 Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Thu, 30 Apr 2020 15:37:27 -0700 Subject: [PATCH 2091/3747] Cleanup Condvar tests. --- src/shims/sync.rs | 12 +- .../run-pass/concurrency/libc_pthread_cond.rs | 212 ++++-------------- .../concurrency/libc_pthread_cond.stderr | 2 - tests/run-pass/concurrency/sync.rs | 54 ++++- 4 files changed, 102 insertions(+), 178 deletions(-) delete mode 100644 tests/run-pass/concurrency/libc_pthread_cond.stderr diff --git a/src/shims/sync.rs b/src/shims/sync.rs index f31efe18e1c17..a586be8139ba5 100644 --- a/src/shims/sync.rs +++ b/src/shims/sync.rs @@ -1,4 +1,5 @@ use std::time::{Duration, SystemTime}; +use std::convert::TryInto; use rustc_middle::ty::{layout::TyAndLayout, TyKind, TypeAndMut}; use rustc_target::abi::{LayoutOf, Size}; @@ -719,12 +720,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let mut offset = Size::from_bytes(0); let layout = this.libc_ty_layout("time_t")?; let seconds_place = tp.offset(offset, MemPlaceMeta::None, layout, this)?; - let seconds = this.read_scalar(seconds_place.into())?.to_u64()?; + let seconds = this.read_scalar(seconds_place.into())?; offset += layout.size; let layout = this.libc_ty_layout("c_long")?; let nanoseconds_place = tp.offset(offset, MemPlaceMeta::None, layout, this)?; - let nanoseconds = this.read_scalar(nanoseconds_place.into())?.to_u64()?; - Duration::new(seconds, nanoseconds as u32) + let nanoseconds = this.read_scalar(nanoseconds_place.into())?; + let (seconds, nanoseconds) = if this.pointer_size().bytes() == 8 { + (seconds.to_u64()?, nanoseconds.to_u64()?.try_into().unwrap()) + } else { + (seconds.to_u32()?.into(), nanoseconds.to_u32()?) + }; + Duration::new(seconds, nanoseconds) }; let timeout_time = if clock_id == this.eval_libc_i32("CLOCK_REALTIME")? { diff --git a/tests/run-pass/concurrency/libc_pthread_cond.rs b/tests/run-pass/concurrency/libc_pthread_cond.rs index 83a651e6f04a7..9b7a06b431c04 100644 --- a/tests/run-pass/concurrency/libc_pthread_cond.rs +++ b/tests/run-pass/concurrency/libc_pthread_cond.rs @@ -1,199 +1,75 @@ // ignore-windows: No libc on Windows +// ignore-macos: pthread_condattr_setclock is not supported on MacOS. // compile-flags: -Zmiri-disable-isolation #![feature(rustc_private)] +/// Test that conditional variable timeouts are working properly with both +/// monotonic and system clocks. extern crate libc; -use std::cell::UnsafeCell; -use std::mem::{self, MaybeUninit}; -use std::sync::Arc; -use std::thread; +use std::mem; +use std::time::Instant; -struct Mutex { - inner: UnsafeCell, -} - -unsafe impl Sync for Mutex {} - -impl std::fmt::Debug for Mutex { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "Mutex") - } -} - -struct Cond { - inner: UnsafeCell, -} - -unsafe impl Sync for Cond {} - -impl std::fmt::Debug for Cond { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "Cond") - } -} - -unsafe fn create_cond_attr_monotonic() -> libc::pthread_condattr_t { - let mut attr = MaybeUninit::::uninit(); - assert_eq!(libc::pthread_condattr_init(attr.as_mut_ptr()), 0); - assert_eq!(libc::pthread_condattr_setclock(attr.as_mut_ptr(), libc::CLOCK_MONOTONIC), 0); - attr.assume_init() -} - -unsafe fn create_cond(attr: Option) -> Cond { - let cond: Cond = mem::zeroed(); - if let Some(mut attr) = attr { - assert_eq!(libc::pthread_cond_init(cond.inner.get() as *mut _, &attr as *const _), 0); - assert_eq!(libc::pthread_condattr_destroy(&mut attr as *mut _), 0); - } else { - assert_eq!(libc::pthread_cond_init(cond.inner.get() as *mut _, 0 as *const _), 0); - } - cond -} - -unsafe fn create_mutex() -> Mutex { - mem::zeroed() -} - -unsafe fn create_timeout(seconds: i64) -> libc::timespec { - let mut now: libc::timespec = mem::zeroed(); - assert_eq!(libc::clock_gettime(libc::CLOCK_MONOTONIC, &mut now), 0); - libc::timespec { tv_sec: now.tv_sec + seconds, tv_nsec: now.tv_nsec } -} - -fn test_pthread_condattr_t() { +fn test_timed_wait_timeout_monotonic() { unsafe { - let mut attr = create_cond_attr_monotonic(); - let mut clock_id = MaybeUninit::::uninit(); - assert_eq!(libc::pthread_condattr_getclock(&attr as *const _, clock_id.as_mut_ptr()), 0); - assert_eq!(clock_id.assume_init(), libc::CLOCK_MONOTONIC); - assert_eq!(libc::pthread_condattr_destroy(&mut attr as *mut _), 0); - } -} + let mut attr: libc::pthread_condattr_t = mem::zeroed(); + assert_eq!(libc::pthread_condattr_init(&mut attr as *mut _), 0); + assert_eq!(libc::pthread_condattr_setclock(&mut attr as *mut _, libc::CLOCK_MONOTONIC), 0); -fn test_signal() { - unsafe { - let cond = Arc::new(create_cond(None)); - let mutex = Arc::new(create_mutex()); + let mut cond: libc::pthread_cond_t = mem::zeroed(); + assert_eq!(libc::pthread_cond_init(&mut cond as *mut _, &attr as *const _), 0); + assert_eq!(libc::pthread_condattr_destroy(&mut attr as *mut _), 0); - assert_eq!(libc::pthread_mutex_lock(mutex.inner.get() as *mut _), 0); + let mut mutex: libc::pthread_mutex_t = mem::zeroed(); - let spawn_mutex = Arc::clone(&mutex); - let spawn_cond = Arc::clone(&cond); - let handle = thread::spawn(move || { - assert_eq!(libc::pthread_mutex_lock(spawn_mutex.inner.get() as *mut _), 0); - assert_eq!(libc::pthread_cond_signal(spawn_cond.inner.get() as *mut _), 0); - assert_eq!(libc::pthread_mutex_unlock(spawn_mutex.inner.get() as *mut _), 0); - }); + let mut now: libc::timespec = mem::zeroed(); + assert_eq!(libc::clock_gettime(libc::CLOCK_MONOTONIC, &mut now), 0); + let timeout = libc::timespec { tv_sec: now.tv_sec + 1, tv_nsec: now.tv_nsec }; + assert_eq!(libc::pthread_mutex_lock(&mut mutex as *mut _), 0); + let current_time = Instant::now(); assert_eq!( - libc::pthread_cond_wait(cond.inner.get() as *mut _, mutex.inner.get() as *mut _), - 0 + libc::pthread_cond_timedwait(&mut cond as *mut _, &mut mutex as *mut _, &timeout), + libc::ETIMEDOUT ); - assert_eq!(libc::pthread_mutex_unlock(mutex.inner.get() as *mut _), 0); - - handle.join().unwrap(); - - let mutex = Arc::try_unwrap(mutex).unwrap(); - assert_eq!(libc::pthread_mutex_destroy(mutex.inner.get() as *mut _), 0); - let cond = Arc::try_unwrap(cond).unwrap(); - assert_eq!(libc::pthread_cond_destroy(cond.inner.get() as *mut _), 0); + assert!(current_time.elapsed().as_millis() >= 900); + assert_eq!(libc::pthread_mutex_unlock(&mut mutex as *mut _), 0); + assert_eq!(libc::pthread_mutex_destroy(&mut mutex as *mut _), 0); + assert_eq!(libc::pthread_cond_destroy(&mut cond as *mut _), 0); } } -fn test_broadcast() { +fn test_timed_wait_timeout_realtime() { unsafe { - let cond = Arc::new(create_cond(None)); - let mutex = Arc::new(create_mutex()); - - assert_eq!(libc::pthread_mutex_lock(mutex.inner.get() as *mut _), 0); - - let spawn_mutex = Arc::clone(&mutex); - let spawn_cond = Arc::clone(&cond); - let handle = thread::spawn(move || { - assert_eq!(libc::pthread_mutex_lock(spawn_mutex.inner.get() as *mut _), 0); - assert_eq!(libc::pthread_cond_broadcast(spawn_cond.inner.get() as *mut _), 0); - assert_eq!(libc::pthread_mutex_unlock(spawn_mutex.inner.get() as *mut _), 0); - }); + let mut attr: libc::pthread_condattr_t = mem::zeroed(); + assert_eq!(libc::pthread_condattr_init(&mut attr as *mut _), 0); + assert_eq!(libc::pthread_condattr_setclock(&mut attr as *mut _, libc::CLOCK_REALTIME), 0); - assert_eq!( - libc::pthread_cond_wait(cond.inner.get() as *mut _, mutex.inner.get() as *mut _), - 0 - ); - assert_eq!(libc::pthread_mutex_unlock(mutex.inner.get() as *mut _), 0); + let mut cond: libc::pthread_cond_t = mem::zeroed(); + assert_eq!(libc::pthread_cond_init(&mut cond as *mut _, &attr as *const _), 0); + assert_eq!(libc::pthread_condattr_destroy(&mut attr as *mut _), 0); - handle.join().unwrap(); + let mut mutex: libc::pthread_mutex_t = mem::zeroed(); - let mutex = Arc::try_unwrap(mutex).unwrap(); - assert_eq!(libc::pthread_mutex_destroy(mutex.inner.get() as *mut _), 0); - let cond = Arc::try_unwrap(cond).unwrap(); - assert_eq!(libc::pthread_cond_destroy(cond.inner.get() as *mut _), 0); - } -} + let mut now: libc::timespec = mem::zeroed(); + assert_eq!(libc::clock_gettime(libc::CLOCK_REALTIME, &mut now), 0); + let timeout = libc::timespec { tv_sec: now.tv_sec + 1, tv_nsec: now.tv_nsec }; -fn test_timed_wait_timeout() { - unsafe { - let attr = create_cond_attr_monotonic(); - let cond = create_cond(Some(attr)); - let mutex = create_mutex(); - let timeout = create_timeout(1); - - assert_eq!(libc::pthread_mutex_lock(mutex.inner.get() as *mut _), 0); + assert_eq!(libc::pthread_mutex_lock(&mut mutex as *mut _), 0); + let current_time = Instant::now(); assert_eq!( - libc::pthread_cond_timedwait( - cond.inner.get() as *mut _, - mutex.inner.get() as *mut _, - &timeout - ), + libc::pthread_cond_timedwait(&mut cond as *mut _, &mut mutex as *mut _, &timeout), libc::ETIMEDOUT ); - assert_eq!(libc::pthread_mutex_unlock(mutex.inner.get() as *mut _), 0); - assert_eq!(libc::pthread_mutex_destroy(mutex.inner.get() as *mut _), 0); - assert_eq!(libc::pthread_cond_destroy(cond.inner.get() as *mut _), 0); - } -} - -fn test_timed_wait_notimeout() { - unsafe { - let attr = create_cond_attr_monotonic(); - let cond = Arc::new(create_cond(Some(attr))); - let mutex = Arc::new(create_mutex()); - let timeout = create_timeout(100); - - assert_eq!(libc::pthread_mutex_lock(mutex.inner.get() as *mut _), 0); - - let spawn_mutex = Arc::clone(&mutex); - let spawn_cond = Arc::clone(&cond); - let handle = thread::spawn(move || { - assert_eq!(libc::pthread_mutex_lock(spawn_mutex.inner.get() as *mut _), 0); - assert_eq!(libc::pthread_cond_signal(spawn_cond.inner.get() as *mut _), 0); - assert_eq!(libc::pthread_mutex_unlock(spawn_mutex.inner.get() as *mut _), 0); - }); - - assert_eq!( - libc::pthread_cond_timedwait( - cond.inner.get() as *mut _, - mutex.inner.get() as *mut _, - &timeout - ), - 0 - ); - assert_eq!(libc::pthread_mutex_unlock(mutex.inner.get() as *mut _), 0); - - handle.join().unwrap(); - - let mutex = Arc::try_unwrap(mutex).unwrap(); - assert_eq!(libc::pthread_mutex_destroy(mutex.inner.get() as *mut _), 0); - let cond = Arc::try_unwrap(cond).unwrap(); - assert_eq!(libc::pthread_cond_destroy(cond.inner.get() as *mut _), 0); + assert!(current_time.elapsed().as_millis() >= 900); + assert_eq!(libc::pthread_mutex_unlock(&mut mutex as *mut _), 0); + assert_eq!(libc::pthread_mutex_destroy(&mut mutex as *mut _), 0); + assert_eq!(libc::pthread_cond_destroy(&mut cond as *mut _), 0); } } fn main() { - test_pthread_condattr_t(); - test_signal(); - test_broadcast(); - test_timed_wait_timeout(); - test_timed_wait_notimeout(); + test_timed_wait_timeout_monotonic(); + test_timed_wait_timeout_realtime(); } diff --git a/tests/run-pass/concurrency/libc_pthread_cond.stderr b/tests/run-pass/concurrency/libc_pthread_cond.stderr deleted file mode 100644 index 2dbfb7721d368..0000000000000 --- a/tests/run-pass/concurrency/libc_pthread_cond.stderr +++ /dev/null @@ -1,2 +0,0 @@ -warning: thread support is experimental. For example, Miri does not detect data races yet. - diff --git a/tests/run-pass/concurrency/sync.rs b/tests/run-pass/concurrency/sync.rs index e422a7fbdbc5b..e3f3a03b11ae3 100644 --- a/tests/run-pass/concurrency/sync.rs +++ b/tests/run-pass/concurrency/sync.rs @@ -31,7 +31,7 @@ fn check_barriers() { // Check if Rust conditional variables are working. /// The test taken from the Rust documentation. -fn check_conditional_variables() { +fn check_conditional_variables_notify_one() { let pair = Arc::new((Mutex::new(false), Condvar::new())); let pair2 = pair.clone(); @@ -52,17 +52,59 @@ fn check_conditional_variables() { } } +/// The test taken from the Rust documentation. +fn check_conditional_variables_notify_all() { + let pair = Arc::new((Mutex::new(false), Condvar::new())); + let pair2 = pair.clone(); + + thread::spawn(move || { + let (lock, cvar) = &*pair2; + let mut started = lock.lock().unwrap(); + *started = true; + // We notify the condvar that the value has changed. + cvar.notify_all(); + }); + + // Wait for the thread to start up. + let (lock, cvar) = &*pair; + let mut started = lock.lock().unwrap(); + // As long as the value inside the `Mutex` is `false`, we wait. + while !*started { + started = cvar.wait(started).unwrap(); + } +} + /// Test that waiting on a conditional variable with a timeout does not /// deadlock. -fn check_conditional_variables_timeout() { +fn check_conditional_variables_timed_wait_timeout() { let lock = Mutex::new(()); let cvar = Condvar::new(); let guard = lock.lock().unwrap(); let now = Instant::now(); - let _guard = cvar.wait_timeout(guard, Duration::from_millis(100)).unwrap().0; + let (_guard, timeout) = cvar.wait_timeout(guard, Duration::from_millis(100)).unwrap(); + assert!(timeout.timed_out()); assert!(now.elapsed().as_millis() >= 100); } +/// Test that signaling a conditional variable when waiting with a timeout works +/// as expected. +fn check_conditional_variables_timed_wait_notimeout() { + let pair = Arc::new((Mutex::new(()), Condvar::new())); + let pair2 = pair.clone(); + + let (lock, cvar) = &*pair; + let guard = lock.lock().unwrap(); + + let handle = thread::spawn(move || { + let (_lock, cvar) = &*pair2; + cvar.notify_one(); + }); + + let (_guard, timeout) = cvar.wait_timeout(guard, Duration::from_millis(100)).unwrap(); + assert!(!timeout.timed_out()); + handle.join().unwrap(); +} + // Check if locks are working. fn check_mutex() { @@ -218,8 +260,10 @@ fn check_once() { fn main() { check_barriers(); - check_conditional_variables(); - check_conditional_variables_timeout(); + check_conditional_variables_notify_one(); + check_conditional_variables_notify_all(); + check_conditional_variables_timed_wait_timeout(); + check_conditional_variables_timed_wait_notimeout(); check_mutex(); check_rwlock_write(); check_rwlock_read_no_deadlock(); From 0bbac1275177176c6bb1a8640b5ef34dbb5c5074 Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Mon, 18 May 2020 16:28:19 +0200 Subject: [PATCH 2092/3747] Change how the time is handled. --- src/machine.rs | 8 +------- src/shims/sync.rs | 10 ++++------ src/sync.rs | 5 +---- src/thread.rs | 47 ++++++++++++++++++++++++++++++----------------- 4 files changed, 36 insertions(+), 34 deletions(-) diff --git a/src/machine.rs b/src/machine.rs index 4fb08cd259b67..51aa7ae31047a 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -5,7 +5,7 @@ use std::borrow::Cow; use std::cell::RefCell; use std::num::NonZeroU64; use std::rc::Rc; -use std::time::{Instant, SystemTime}; +use std::time::Instant; use std::fmt; use log::trace; @@ -251,11 +251,6 @@ pub struct Evaluator<'mir, 'tcx> { /// The "time anchor" for this machine's monotone clock (for `Instant` simulation). pub(crate) time_anchor: Instant, - /// The approximate system time when "time anchor" was created. This is used - /// for converting system time to monotone time so that we can simplify the - /// thread scheduler to deal only with a single representation of time. - pub(crate) time_anchor_timestamp: SystemTime, - /// The set of threads. pub(crate) threads: ThreadManager<'mir, 'tcx>, @@ -286,7 +281,6 @@ impl<'mir, 'tcx> Evaluator<'mir, 'tcx> { dir_handler: Default::default(), panic_payload: None, time_anchor: Instant::now(), - time_anchor_timestamp: SystemTime::now(), layouts, threads: ThreadManager::default(), } diff --git a/src/shims/sync.rs b/src/shims/sync.rs index a586be8139ba5..5432c76dfe719 100644 --- a/src/shims/sync.rs +++ b/src/shims/sync.rs @@ -1,10 +1,11 @@ -use std::time::{Duration, SystemTime}; use std::convert::TryInto; +use std::time::{Duration, SystemTime}; use rustc_middle::ty::{layout::TyAndLayout, TyKind, TypeAndMut}; use rustc_target::abi::{LayoutOf, Size}; use crate::stacked_borrows::Tag; +use crate::thread::Time; use crate::*; @@ -734,12 +735,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx }; let timeout_time = if clock_id == this.eval_libc_i32("CLOCK_REALTIME")? { - let time_anchor_since_epoch = - this.machine.time_anchor_timestamp.duration_since(SystemTime::UNIX_EPOCH).unwrap(); - let duration_since_time_anchor = duration.checked_sub(time_anchor_since_epoch).unwrap(); - this.machine.time_anchor.checked_add(duration_since_time_anchor).unwrap() + Time::RealTime(SystemTime::UNIX_EPOCH.checked_add(duration).unwrap()) } else if clock_id == this.eval_libc_i32("CLOCK_MONOTONIC")? { - this.machine.time_anchor.checked_add(duration).unwrap() + Time::Monotonic(this.machine.time_anchor.checked_add(duration).unwrap()) } else { throw_ub_format!("Unsupported clock id."); }; diff --git a/src/sync.rs b/src/sync.rs index 88b5d6c060ddc..e05d111cb2839 100644 --- a/src/sync.rs +++ b/src/sync.rs @@ -1,7 +1,6 @@ use std::collections::{hash_map::Entry, HashMap, VecDeque}; use std::convert::TryFrom; use std::num::NonZeroU32; -use std::time::Instant; use rustc_index::vec::{Idx, IndexVec}; @@ -76,8 +75,6 @@ struct CondvarWaiter { thread: ThreadId, /// The mutex on which the thread is waiting. mutex: MutexId, - /// The moment in time when the waiter should time out. - timeout: Option, } /// The conditional variable state. @@ -280,7 +277,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); let waiters = &mut this.machine.threads.sync.condvars[id].waiters; assert!(waiters.iter().all(|waiter| waiter.thread != thread), "thread is already waiting"); - waiters.push_back(CondvarWaiter { thread, mutex, timeout: None }); + waiters.push_back(CondvarWaiter { thread, mutex }); } /// Wake up some thread (if there is any) sleeping on the conditional diff --git a/src/thread.rs b/src/thread.rs index f67de48b710db..69b31b541ae5e 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -4,7 +4,7 @@ use std::cell::RefCell; use std::collections::hash_map::Entry; use std::convert::TryFrom; use std::num::TryFromIntError; -use std::time::Instant; +use std::time::{Duration, Instant, SystemTime}; use log::trace; @@ -159,13 +159,30 @@ impl<'mir, 'tcx> Default for Thread<'mir, 'tcx> { } } +#[derive(Debug)] +pub enum Time { + Monotonic(Instant), + RealTime(SystemTime), +} + +impl Time { + /// How long do we have to wait from now until the specified time? + fn get_wait_time(&self) -> Duration { + match self { + Time::Monotonic(instant) => instant.saturating_duration_since(Instant::now()), + Time::RealTime(time) => + time.duration_since(SystemTime::now()).unwrap_or(Duration::new(0, 0)), + } + } +} + /// Callbacks are used to implement timeouts. For example, waiting on a /// conditional variable with a timeout creates a callback that is called after /// the specified time and unblocks the thread. If another thread signals on the /// conditional variable, the signal handler deletes the callback. struct TimeoutCallbackInfo<'mir, 'tcx> { /// The callback should be called no earlier than this time. - call_time: Instant, + call_time: Time, /// The called function. callback: TimeoutCallback<'mir, 'tcx>, } @@ -362,11 +379,11 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { fn register_timeout_callback( &mut self, thread: ThreadId, - call_time: Instant, + call_time: Time, callback: TimeoutCallback<'mir, 'tcx>, ) { self.timeout_callbacks - .insert(thread, TimeoutCallbackInfo { call_time: call_time, callback: callback }) + .insert(thread, TimeoutCallbackInfo { call_time, callback }) .unwrap_none(); } @@ -376,13 +393,12 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { } /// Get a callback that is ready to be called. - fn get_callback(&mut self) -> Option<(ThreadId, TimeoutCallback<'mir, 'tcx>)> { - let current_time = Instant::now(); + fn get_ready_callback(&mut self) -> Option<(ThreadId, TimeoutCallback<'mir, 'tcx>)> { // We use a for loop here to make the scheduler more deterministic. for thread in self.threads.indices() { match self.timeout_callbacks.entry(thread) { Entry::Occupied(entry) => - if current_time >= entry.get().call_time { + if entry.get().call_time.get_wait_time() == Duration::new(0, 0) { return Some((thread, entry.remove().callback)); }, Entry::Vacant(_) => {} @@ -445,18 +461,14 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { } // We have not found a thread to execute. if self.threads.iter().all(|thread| thread.state == ThreadState::Terminated) { - unreachable!(); - } else if let Some(next_call_time) = - self.timeout_callbacks.values().min_by_key(|info| info.call_time) + unreachable!("all threads terminated without the main thread terminating?!"); + } else if let Some(sleep_time) = + self.timeout_callbacks.values().map(|info| info.call_time.get_wait_time()).min() { // All threads are currently blocked, but we have unexecuted // timeout_callbacks, which may unblock some of the threads. Hence, // sleep until the first callback. - if let Some(sleep_time) = - next_call_time.call_time.checked_duration_since(Instant::now()) - { - std::thread::sleep(sleep_time); - } + std::thread::sleep(sleep_time); Ok(SchedulingAction::ExecuteTimeoutCallback) } else { throw_machine_stop!(TerminationInfo::Deadlock); @@ -650,7 +662,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn register_timeout_callback( &mut self, thread: ThreadId, - call_time: Instant, + call_time: Time, callback: TimeoutCallback<'mir, 'tcx>, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); @@ -669,7 +681,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx #[inline] fn run_timeout_callback(&mut self) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - let (thread, callback) = this.machine.threads.get_callback().expect("no callback found"); + let (thread, callback) = + this.machine.threads.get_ready_callback().expect("no callback found"); let old_thread = this.set_active_thread(thread)?; callback(this)?; this.set_active_thread(old_thread)?; From 3da61fa4274b370dc2c72ce8b7bdbbfeb836110a Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Mon, 18 May 2020 16:39:19 +0200 Subject: [PATCH 2093/3747] Add comments explaining the declare_id macro. --- src/sync.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/sync.rs b/src/sync.rs index e05d111cb2839..7957faeb7e3d7 100644 --- a/src/sync.rs +++ b/src/sync.rs @@ -6,6 +6,10 @@ use rustc_index::vec::{Idx, IndexVec}; use crate::*; +/// We cannot use the `newtype_index!` macro because we have to use 0 as a +/// sentinel value meaning that the identifier is not assigned. This is because +/// the pthreads static initializers initialize memory with zeros (see the +/// `src/shims/sync.rs` file). macro_rules! declare_id { ($name: ident) => { /// 0 is used to indicate that the id was not yet assigned and, @@ -22,9 +26,13 @@ macro_rules! declare_id { impl Idx for $name { fn new(idx: usize) -> Self { + // We use 0 as a sentinel value (see the comment above) and, + // therefore, need to shift by one when converting from an index + // into a vector. $name(NonZeroU32::new(u32::try_from(idx).unwrap() + 1).unwrap()) } fn index(self) -> usize { + // See the comment in `Self::new`. usize::try_from(self.0.get() - 1).unwrap() } } From fdfd56b75b2aefefe6545eed704550ff5de3bdd7 Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Mon, 18 May 2020 17:18:15 +0200 Subject: [PATCH 2094/3747] Small changes. --- src/shims/sync.rs | 63 +++++++---------- src/sync.rs | 70 +++++++++++++------ src/thread.rs | 7 +- .../libc_pthread_rwlock_read_wrong_owner.rs | 32 +++++++++ .../libc_pthread_rwlock_write_wrong_owner.rs | 32 +++++++++ 5 files changed, 143 insertions(+), 61 deletions(-) create mode 100644 tests/compile-fail/sync/libc_pthread_rwlock_read_wrong_owner.rs create mode 100644 tests/compile-fail/sync/libc_pthread_rwlock_write_wrong_owner.rs diff --git a/src/shims/sync.rs b/src/shims/sync.rs index 5432c76dfe719..ee2579c22f179 100644 --- a/src/shims/sync.rs +++ b/src/shims/sync.rs @@ -202,6 +202,7 @@ fn condattr_set_clock_id<'mir, 'tcx: 'mir>( // Our chosen memory layout for the emulated conditional variable (does not have // to match the platform layout!): +// bytes 0-3: reserved for signature on macOS // bytes 4-7: the conditional variable id as u32 or 0 if id is not assigned yet. // bytes 8-11: the clock id constant as i32 @@ -275,19 +276,13 @@ fn release_cond_mutex<'mir, 'tcx: 'mir>( active_thread: ThreadId, mutex: MutexId, ) -> InterpResult<'tcx> { - if let Some((owner_thread, current_locked_count)) = ecx.mutex_unlock(mutex) { - if current_locked_count != 0 { - throw_unsup_format!("awaiting on multiple times acquired lock is not supported"); + if let Some((old_owner_thread, old_locked_count)) = ecx.mutex_unlock(mutex)? { + if old_locked_count != 1 { + throw_unsup_format!("awaiting on a lock acquired multiple times is not supported"); } - if owner_thread != active_thread { + if old_owner_thread != active_thread { throw_ub_format!("awaiting on a mutex owned by a different thread"); } - if let Some(thread) = ecx.mutex_dequeue(mutex) { - // We have at least one thread waiting on this mutex. Transfer - // ownership to it. - ecx.mutex_lock(mutex, thread); - ecx.unblock_thread(thread)?; - } } else { throw_ub_format!("awaiting on unlocked mutex"); } @@ -349,7 +344,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx mutexattr_get_kind(this, attr_op)?.not_undef()? }; - let _ = mutex_get_or_create_id(this, mutex_op)?; + // Write 0 to use the same code path as the static initializers. + mutex_set_id(this, mutex_op, Scalar::from_i32(0))?; + mutex_set_kind(this, mutex_op, kind)?; Ok(0) @@ -427,19 +424,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let kind = mutex_get_kind(this, mutex_op)?.not_undef()?; let id = mutex_get_or_create_id(this, mutex_op)?; - if let Some((owner_thread, current_locked_count)) = this.mutex_unlock(id) { - if owner_thread != this.get_active_thread()? { + if let Some((old_owner_thread, _old_locked_count)) = this.mutex_unlock(id)? { + if old_owner_thread != this.get_active_thread()? { throw_ub_format!("called pthread_mutex_unlock on a mutex owned by another thread"); } - if current_locked_count == 0 { - // The mutex is unlocked. - if let Some(thread) = this.mutex_dequeue(id) { - // We have at least one thread waiting on this mutex. Transfer - // ownership to it. - this.mutex_lock(id, thread); - this.unblock_thread(thread)?; - } - } Ok(0) } else { if kind == this.eval_libc("PTHREAD_MUTEX_NORMAL")? { @@ -476,11 +464,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let active_thread = this.get_active_thread()?; if this.rwlock_is_write_locked(id) { - this.rwlock_enqueue_reader(id, active_thread); - this.block_thread(active_thread)?; + this.rwlock_enqueue_and_block_reader(id, active_thread)?; Ok(0) } else { - this.rwlock_reader_add(id, active_thread); + this.rwlock_reader_lock(id, active_thread); Ok(0) } } @@ -494,7 +481,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if this.rwlock_is_write_locked(id) { this.eval_libc_i32("EBUSY") } else { - this.rwlock_reader_add(id, active_thread); + this.rwlock_reader_lock(id, active_thread); Ok(0) } } @@ -506,10 +493,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let active_thread = this.get_active_thread()?; if this.rwlock_is_locked(id) { - this.block_thread(active_thread)?; - this.rwlock_enqueue_writer(id, active_thread); + this.rwlock_enqueue_and_block_writer(id, active_thread)?; } else { - this.rwlock_writer_set(id, active_thread); + this.rwlock_writer_lock(id, active_thread); } Ok(0) @@ -524,7 +510,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if this.rwlock_is_locked(id) { this.eval_libc_i32("EBUSY") } else { - this.rwlock_writer_set(id, active_thread); + this.rwlock_writer_lock(id, active_thread); Ok(0) } } @@ -535,18 +521,18 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let id = rwlock_get_or_create_id(this, rwlock_op)?; let active_thread = this.get_active_thread()?; - if this.rwlock_reader_remove(id, active_thread) { + if this.rwlock_reader_unlock(id, active_thread) { // The thread was a reader. if this.rwlock_is_locked(id) { // No more readers owning the lock. Give it to a writer if there // is any. if let Some(writer) = this.rwlock_dequeue_writer(id) { this.unblock_thread(writer)?; - this.rwlock_writer_set(id, writer); + this.rwlock_writer_lock(id, writer); } } Ok(0) - } else if Some(active_thread) == this.rwlock_writer_remove(id) { + } else if Some(active_thread) == this.rwlock_writer_unlock(id) { // The thread was a writer. // // We are prioritizing writers here against the readers. As a @@ -555,12 +541,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if let Some(writer) = this.rwlock_dequeue_writer(id) { // Give the lock to another writer. this.unblock_thread(writer)?; - this.rwlock_writer_set(id, writer); + this.rwlock_writer_lock(id, writer); } else { // Give the lock to all readers. while let Some(reader) = this.rwlock_dequeue_reader(id) { this.unblock_thread(reader)?; - this.rwlock_reader_add(id, reader); + this.rwlock_reader_lock(id, reader); } } Ok(0) @@ -586,6 +572,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn pthread_condattr_init(&mut self, attr_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); + // The default value of the clock attribute shall refer to the system + // clock. + // https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_condattr_setclock.html let default_clock_id = this.eval_libc("CLOCK_REALTIME")?; condattr_set_clock_id(this, attr_op, default_clock_id)?; @@ -647,7 +636,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx condattr_get_clock_id(this, attr_op)?.not_undef()? }; - let _ = cond_get_or_create_id(this, cond_op)?; + // Write 0 to use the same code path as the static initializers. + cond_set_id(this, cond_op, Scalar::from_i32(0))?; + cond_set_clock_id(this, cond_op, clock_id)?; Ok(0) diff --git a/src/sync.rs b/src/sync.rs index 7957faeb7e3d7..a71d4597c6697 100644 --- a/src/sync.rs +++ b/src/sync.rs @@ -1,6 +1,7 @@ use std::collections::{hash_map::Entry, HashMap, VecDeque}; use std::convert::TryFrom; use std::num::NonZeroU32; +use std::ops::Not; use rustc_index::vec::{Idx, IndexVec}; @@ -142,34 +143,47 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx mutex.lock_count = mutex.lock_count.checked_add(1).unwrap(); } - /// Unlock by decreasing the lock count. If the lock count reaches 0, unset - /// the owner. - fn mutex_unlock(&mut self, id: MutexId) -> Option<(ThreadId, usize)> { + /// Try unlocking by decreasing the lock count and returning the old owner + /// and the old lock count. If the lock count reaches 0, release the lock + /// and potentially give to a new owner. If the lock was not locked, return + /// `None`. + /// + /// Note: It is the caller's responsibility to check that the thread that + /// unlocked the lock actually is the same one, which owned it. + fn mutex_unlock(&mut self, id: MutexId) -> InterpResult<'tcx, Option<(ThreadId, usize)>> { let this = self.eval_context_mut(); let mutex = &mut this.machine.threads.sync.mutexes[id]; if let Some(current_owner) = mutex.owner { - mutex.lock_count = mutex - .lock_count + // Mutex is locked. + let old_lock_count = mutex.lock_count; + mutex.lock_count = old_lock_count .checked_sub(1) .expect("invariant violation: lock_count == 0 iff the thread is unlocked"); if mutex.lock_count == 0 { mutex.owner = None; + // The mutex is completely unlocked. Try transfering ownership + // to another thread. + if let Some(new_owner) = this.mutex_dequeue(id) { + this.mutex_lock(id, new_owner); + this.unblock_thread(new_owner)?; + } } - Some((current_owner, mutex.lock_count)) + Ok(Some((current_owner, old_lock_count))) } else { - None + // Mutex is unlocked. + Ok(None) } } #[inline] - /// Take a thread out the queue waiting for the lock. + /// Put the thread into the queue waiting for the lock. fn mutex_enqueue(&mut self, id: MutexId, thread: ThreadId) { let this = self.eval_context_mut(); this.machine.threads.sync.mutexes[id].queue.push_back(thread); } #[inline] - /// Take a thread out the queue waiting for the lock. + /// Take a thread out of the queue waiting for the lock. fn mutex_dequeue(&mut self, id: MutexId) -> Option { let this = self.eval_context_mut(); this.machine.threads.sync.mutexes[id].queue.pop_front() @@ -187,7 +201,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn rwlock_is_locked(&mut self, id: RwLockId) -> bool { let this = self.eval_context_mut(); this.machine.threads.sync.rwlocks[id].writer.is_some() - || !this.machine.threads.sync.rwlocks[id].readers.is_empty() + || this.machine.threads.sync.rwlocks[id].readers.is_empty().not() } #[inline] @@ -197,16 +211,18 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.machine.threads.sync.rwlocks[id].writer.is_some() } - /// Add a reader that collectively with other readers owns the lock. - fn rwlock_reader_add(&mut self, id: RwLockId, reader: ThreadId) { + /// Read-lock the lock by adding the `reader` the list of threads that own + /// this lock. + fn rwlock_reader_lock(&mut self, id: RwLockId, reader: ThreadId) { let this = self.eval_context_mut(); assert!(!this.rwlock_is_write_locked(id), "the lock is write locked"); let count = this.machine.threads.sync.rwlocks[id].readers.entry(reader).or_insert(0); - *count += 1; + *count = count.checked_add(1).expect("the reader counter overflowed"); } - /// Try removing the reader. Returns `true` if succeeded. - fn rwlock_reader_remove(&mut self, id: RwLockId, reader: ThreadId) -> bool { + /// Try read-unlock the lock for `reader`. Returns `true` if succeeded, + /// `false` if this `reader` did not hold the lock. + fn rwlock_reader_unlock(&mut self, id: RwLockId, reader: ThreadId) -> bool { let this = self.eval_context_mut(); match this.machine.threads.sync.rwlocks[id].readers.entry(reader) { Entry::Occupied(mut entry) => { @@ -222,15 +238,20 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } #[inline] - /// Put the reader in the queue waiting for the lock. - fn rwlock_enqueue_reader(&mut self, id: RwLockId, reader: ThreadId) { + /// Put the reader in the queue waiting for the lock and block it. + fn rwlock_enqueue_and_block_reader( + &mut self, + id: RwLockId, + reader: ThreadId, + ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); assert!(this.rwlock_is_write_locked(id), "queueing on not write locked lock"); this.machine.threads.sync.rwlocks[id].reader_queue.push_back(reader); + this.block_thread(reader) } #[inline] - /// Take the reader out the queue waiting for the lock. + /// Take a reader out the queue waiting for the lock. fn rwlock_dequeue_reader(&mut self, id: RwLockId) -> Option { let this = self.eval_context_mut(); this.machine.threads.sync.rwlocks[id].reader_queue.pop_front() @@ -238,25 +259,30 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx #[inline] /// Lock by setting the writer that owns the lock. - fn rwlock_writer_set(&mut self, id: RwLockId, writer: ThreadId) { + fn rwlock_writer_lock(&mut self, id: RwLockId, writer: ThreadId) { let this = self.eval_context_mut(); assert!(!this.rwlock_is_locked(id), "the lock is already locked"); this.machine.threads.sync.rwlocks[id].writer = Some(writer); } #[inline] - /// Try removing the writer. - fn rwlock_writer_remove(&mut self, id: RwLockId) -> Option { + /// Try to unlock by removing the writer. + fn rwlock_writer_unlock(&mut self, id: RwLockId) -> Option { let this = self.eval_context_mut(); this.machine.threads.sync.rwlocks[id].writer.take() } #[inline] /// Put the writer in the queue waiting for the lock. - fn rwlock_enqueue_writer(&mut self, id: RwLockId, writer: ThreadId) { + fn rwlock_enqueue_and_block_writer( + &mut self, + id: RwLockId, + writer: ThreadId, + ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); assert!(this.rwlock_is_locked(id), "queueing on unlocked lock"); this.machine.threads.sync.rwlocks[id].writer_queue.push_back(writer); + this.block_thread(writer) } #[inline] diff --git a/src/thread.rs b/src/thread.rs index 69b31b541ae5e..e61761e599cd8 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -32,7 +32,7 @@ pub enum SchedulingAction { Stop, } -/// Timeout timeout_callbacks can be created by synchronization primitives to tell the +/// Timeout callbacks can be created by synchronization primitives to tell the /// scheduler that they should be called once some period of time passes. type TimeoutCallback<'mir, 'tcx> = Box>) -> InterpResult<'tcx> + 'tcx>; @@ -189,7 +189,7 @@ struct TimeoutCallbackInfo<'mir, 'tcx> { impl<'mir, 'tcx> std::fmt::Debug for TimeoutCallbackInfo<'mir, 'tcx> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "CallBack({:?})", self.call_time) + write!(f, "TimeoutCallback({:?})", self.call_time) } } @@ -394,7 +394,8 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { /// Get a callback that is ready to be called. fn get_ready_callback(&mut self) -> Option<(ThreadId, TimeoutCallback<'mir, 'tcx>)> { - // We use a for loop here to make the scheduler more deterministic. + // We iterate over all threads in the order of their indices because + // this allows us to have a deterministic scheduler. for thread in self.threads.indices() { match self.timeout_callbacks.entry(thread) { Entry::Occupied(entry) => diff --git a/tests/compile-fail/sync/libc_pthread_rwlock_read_wrong_owner.rs b/tests/compile-fail/sync/libc_pthread_rwlock_read_wrong_owner.rs new file mode 100644 index 0000000000000..a73a8496a3296 --- /dev/null +++ b/tests/compile-fail/sync/libc_pthread_rwlock_read_wrong_owner.rs @@ -0,0 +1,32 @@ +// ignore-windows: No libc on Windows + +#![feature(rustc_private)] + +extern crate libc; + +use std::cell::UnsafeCell; +use std::sync::Arc; +use std::thread; + +struct RwLock(UnsafeCell); + +unsafe impl Send for RwLock {} +unsafe impl Sync for RwLock {} + +fn new_lock() -> Arc { + Arc::new(RwLock(UnsafeCell::new(libc::PTHREAD_RWLOCK_INITIALIZER))) +} + +fn main() { + unsafe { + let lock = new_lock(); + assert_eq!(libc::pthread_rwlock_rdlock(lock.0.get() as *mut _), 0); + + let lock_copy = lock.clone(); + thread::spawn(move || { + assert_eq!(libc::pthread_rwlock_unlock(lock_copy.0.get() as *mut _), 0); //~ ERROR: Undefined Behavior: unlocked an rwlock that was not locked by the active thread + }) + .join() + .unwrap(); + } +} diff --git a/tests/compile-fail/sync/libc_pthread_rwlock_write_wrong_owner.rs b/tests/compile-fail/sync/libc_pthread_rwlock_write_wrong_owner.rs new file mode 100644 index 0000000000000..663dedb6f6fca --- /dev/null +++ b/tests/compile-fail/sync/libc_pthread_rwlock_write_wrong_owner.rs @@ -0,0 +1,32 @@ +// ignore-windows: No libc on Windows + +#![feature(rustc_private)] + +extern crate libc; + +use std::cell::UnsafeCell; +use std::sync::Arc; +use std::thread; + +struct RwLock(UnsafeCell); + +unsafe impl Send for RwLock {} +unsafe impl Sync for RwLock {} + +fn new_lock() -> Arc { + Arc::new(RwLock(UnsafeCell::new(libc::PTHREAD_RWLOCK_INITIALIZER))) +} + +fn main() { + unsafe { + let lock = new_lock(); + assert_eq!(libc::pthread_rwlock_wrlock(lock.0.get() as *mut _), 0); + + let lock_copy = lock.clone(); + thread::spawn(move || { + assert_eq!(libc::pthread_rwlock_unlock(lock_copy.0.get() as *mut _), 0); //~ ERROR: Undefined Behavior: unlocked an rwlock that was not locked by the active thread + }) + .join() + .unwrap(); + } +} From 0838347d8f77091ffb5a30606010d0bbedda22a4 Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Tue, 19 May 2020 16:26:42 +0200 Subject: [PATCH 2095/3747] Change the scheduling to execute timeout callbacks first. --- src/thread.rs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/thread.rs b/src/thread.rs index e61761e599cd8..70c2419c4d490 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -441,6 +441,22 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { } return Ok(SchedulingAction::Stop); } + // At least for `pthread_cond_timedwait` we need to report timeout when + // the function is called already after the specified time even if a + // signal is received before the thread gets scheduled. Therefore, we + // need to schedule all timeout callbacks before we continue regular + // execution. + // + // Documentation: + // https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_cond_timedwait.html# + if let Some(sleep_time) = + self.timeout_callbacks.values().map(|info| info.call_time.get_wait_time()).min() + { + if sleep_time == Duration::new(0, 0) { + return Ok(SchedulingAction::ExecuteTimeoutCallback); + } + } + // No callbacks scheduled, pick a regular thread to execute. if self.threads[self.active_thread].state == ThreadState::Enabled && !self.yield_active_thread { From 8b5a9836be5b115f27f48406f68bf64d931ceabc Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Tue, 19 May 2020 16:47:25 +0200 Subject: [PATCH 2096/3747] Small changes. --- src/shims/sync.rs | 27 ++++++++---- src/sync.rs | 1 + .../run-pass/concurrency/libc_pthread_cond.rs | 42 ++++--------------- tests/run-pass/concurrency/sync.rs | 5 ++- 4 files changed, 30 insertions(+), 45 deletions(-) diff --git a/src/shims/sync.rs b/src/shims/sync.rs index ee2579c22f179..f34799f74251f 100644 --- a/src/shims/sync.rs +++ b/src/shims/sync.rs @@ -254,7 +254,8 @@ fn cond_set_clock_id<'mir, 'tcx: 'mir>( set_at_offset(ecx, cond_op, 8, clock_id, ecx.machine.layouts.i32, PTHREAD_COND_T_MIN_SIZE) } -/// Try to reacquire the mutex associated with the condition variable after we were signaled. +/// Try to reacquire the mutex associated with the condition variable after we +/// were signaled. fn reacquire_cond_mutex<'mir, 'tcx: 'mir>( ecx: &mut MiriEvalContext<'mir, 'tcx>, thread: ThreadId, @@ -269,6 +270,17 @@ fn reacquire_cond_mutex<'mir, 'tcx: 'mir>( Ok(()) } +/// Reacquire the conditional variable and remove the timeout callback if any +/// was registered. +fn post_cond_signal<'mir, 'tcx: 'mir>( + ecx: &mut MiriEvalContext<'mir, 'tcx>, + thread: ThreadId, + mutex: MutexId, +) -> InterpResult<'tcx> { + reacquire_cond_mutex(ecx, thread, mutex)?; + ecx.unregister_timeout_callback_if_exists(thread) +} + /// Release the mutex associated with the condition variable because we are /// entering the waiting state. fn release_cond_mutex<'mir, 'tcx: 'mir>( @@ -648,8 +660,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); let id = cond_get_or_create_id(this, cond_op)?; if let Some((thread, mutex)) = this.condvar_signal(id) { - reacquire_cond_mutex(this, thread, mutex)?; - this.unregister_timeout_callback_if_exists(thread)?; + post_cond_signal(this, thread, mutex)?; } Ok(0) @@ -660,8 +671,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let id = cond_get_or_create_id(this, cond_op)?; while let Some((thread, mutex)) = this.condvar_signal(id) { - reacquire_cond_mutex(this, thread, mutex)?; - this.unregister_timeout_callback_if_exists(thread)?; + post_cond_signal(this, thread, mutex)?; } Ok(0) @@ -730,7 +740,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } else if clock_id == this.eval_libc_i32("CLOCK_MONOTONIC")? { Time::Monotonic(this.machine.time_anchor.checked_add(duration).unwrap()) } else { - throw_ub_format!("Unsupported clock id."); + throw_unsup_format!("Unsupported clock id."); }; // Register the timeout callback. @@ -738,13 +748,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx active_thread, timeout_time, Box::new(move |ecx| { - // Try to reacquire the mutex. + // We are not waiting for the condvar any more, wait for the + // mutex instead. reacquire_cond_mutex(ecx, active_thread, mutex_id)?; // Remove the thread from the conditional variable. ecx.condvar_remove_waiter(id, active_thread); - // Set the timeout value. + // Set the return value: we timed out. let timeout = ecx.eval_libc_i32("ETIMEDOUT")?; ecx.write_scalar(Scalar::from_i32(timeout), dest)?; diff --git a/src/sync.rs b/src/sync.rs index a71d4597c6697..cbae29bdbb367 100644 --- a/src/sync.rs +++ b/src/sync.rs @@ -179,6 +179,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// Put the thread into the queue waiting for the lock. fn mutex_enqueue(&mut self, id: MutexId, thread: ThreadId) { let this = self.eval_context_mut(); + assert!(this.mutex_is_locked(id), "queing on unlocked mutex"); this.machine.threads.sync.mutexes[id].queue.push_back(thread); } diff --git a/tests/run-pass/concurrency/libc_pthread_cond.rs b/tests/run-pass/concurrency/libc_pthread_cond.rs index 9b7a06b431c04..39b6a7e4ef803 100644 --- a/tests/run-pass/concurrency/libc_pthread_cond.rs +++ b/tests/run-pass/concurrency/libc_pthread_cond.rs @@ -11,11 +11,11 @@ extern crate libc; use std::mem; use std::time::Instant; -fn test_timed_wait_timeout_monotonic() { +fn test_timed_wait_timeout(clock_id: i32) { unsafe { let mut attr: libc::pthread_condattr_t = mem::zeroed(); assert_eq!(libc::pthread_condattr_init(&mut attr as *mut _), 0); - assert_eq!(libc::pthread_condattr_setclock(&mut attr as *mut _, libc::CLOCK_MONOTONIC), 0); + assert_eq!(libc::pthread_condattr_setclock(&mut attr as *mut _, clock_id), 0); let mut cond: libc::pthread_cond_t = mem::zeroed(); assert_eq!(libc::pthread_cond_init(&mut cond as *mut _, &attr as *const _), 0); @@ -24,7 +24,7 @@ fn test_timed_wait_timeout_monotonic() { let mut mutex: libc::pthread_mutex_t = mem::zeroed(); let mut now: libc::timespec = mem::zeroed(); - assert_eq!(libc::clock_gettime(libc::CLOCK_MONOTONIC, &mut now), 0); + assert_eq!(libc::clock_gettime(clock_id, &mut now), 0); let timeout = libc::timespec { tv_sec: now.tv_sec + 1, tv_nsec: now.tv_nsec }; assert_eq!(libc::pthread_mutex_lock(&mut mutex as *mut _), 0); @@ -33,36 +33,8 @@ fn test_timed_wait_timeout_monotonic() { libc::pthread_cond_timedwait(&mut cond as *mut _, &mut mutex as *mut _, &timeout), libc::ETIMEDOUT ); - assert!(current_time.elapsed().as_millis() >= 900); - assert_eq!(libc::pthread_mutex_unlock(&mut mutex as *mut _), 0); - assert_eq!(libc::pthread_mutex_destroy(&mut mutex as *mut _), 0); - assert_eq!(libc::pthread_cond_destroy(&mut cond as *mut _), 0); - } -} - -fn test_timed_wait_timeout_realtime() { - unsafe { - let mut attr: libc::pthread_condattr_t = mem::zeroed(); - assert_eq!(libc::pthread_condattr_init(&mut attr as *mut _), 0); - assert_eq!(libc::pthread_condattr_setclock(&mut attr as *mut _, libc::CLOCK_REALTIME), 0); - - let mut cond: libc::pthread_cond_t = mem::zeroed(); - assert_eq!(libc::pthread_cond_init(&mut cond as *mut _, &attr as *const _), 0); - assert_eq!(libc::pthread_condattr_destroy(&mut attr as *mut _), 0); - - let mut mutex: libc::pthread_mutex_t = mem::zeroed(); - - let mut now: libc::timespec = mem::zeroed(); - assert_eq!(libc::clock_gettime(libc::CLOCK_REALTIME, &mut now), 0); - let timeout = libc::timespec { tv_sec: now.tv_sec + 1, tv_nsec: now.tv_nsec }; - - assert_eq!(libc::pthread_mutex_lock(&mut mutex as *mut _), 0); - let current_time = Instant::now(); - assert_eq!( - libc::pthread_cond_timedwait(&mut cond as *mut _, &mut mutex as *mut _, &timeout), - libc::ETIMEDOUT - ); - assert!(current_time.elapsed().as_millis() >= 900); + let elapsed_time = current_time.elapsed().as_millis(); + assert!(900 <= elapsed_time && elapsed_time <= 1100); assert_eq!(libc::pthread_mutex_unlock(&mut mutex as *mut _), 0); assert_eq!(libc::pthread_mutex_destroy(&mut mutex as *mut _), 0); assert_eq!(libc::pthread_cond_destroy(&mut cond as *mut _), 0); @@ -70,6 +42,6 @@ fn test_timed_wait_timeout_realtime() { } fn main() { - test_timed_wait_timeout_monotonic(); - test_timed_wait_timeout_realtime(); + test_timed_wait_timeout(libc::CLOCK_MONOTONIC); + test_timed_wait_timeout(libc::CLOCK_REALTIME); } diff --git a/tests/run-pass/concurrency/sync.rs b/tests/run-pass/concurrency/sync.rs index e3f3a03b11ae3..5c19eee342f11 100644 --- a/tests/run-pass/concurrency/sync.rs +++ b/tests/run-pass/concurrency/sync.rs @@ -35,8 +35,9 @@ fn check_conditional_variables_notify_one() { let pair = Arc::new((Mutex::new(false), Condvar::new())); let pair2 = pair.clone(); - // Inside of our lock, spawn a new thread, and then wait for it to start. + // Spawn a new thread. thread::spawn(move || { + thread::yield_now(); let (lock, cvar) = &*pair2; let mut started = lock.lock().unwrap(); *started = true; @@ -44,7 +45,7 @@ fn check_conditional_variables_notify_one() { cvar.notify_one(); }); - // Wait for the thread to start up. + // Wait for the thread to fully start up. let (lock, cvar) = &*pair; let mut started = lock.lock().unwrap(); while !*started { From babedc938e2c9a681737b3468b9124a58b2ec677 Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Tue, 19 May 2020 18:33:26 +0200 Subject: [PATCH 2097/3747] Rewrite notify all test. --- tests/run-pass/concurrency/sync.rs | 39 ++++++++++++++++++------------ 1 file changed, 23 insertions(+), 16 deletions(-) diff --git a/tests/run-pass/concurrency/sync.rs b/tests/run-pass/concurrency/sync.rs index 5c19eee342f11..faf47851bd01f 100644 --- a/tests/run-pass/concurrency/sync.rs +++ b/tests/run-pass/concurrency/sync.rs @@ -53,25 +53,32 @@ fn check_conditional_variables_notify_one() { } } -/// The test taken from the Rust documentation. fn check_conditional_variables_notify_all() { - let pair = Arc::new((Mutex::new(false), Condvar::new())); - let pair2 = pair.clone(); + let pair = Arc::new(((Mutex::new(())), Condvar::new())); - thread::spawn(move || { - let (lock, cvar) = &*pair2; - let mut started = lock.lock().unwrap(); - *started = true; - // We notify the condvar that the value has changed. - cvar.notify_all(); - }); + // Spawn threads and block them on the conditional variable. + let handles: Vec<_> = (0..5) + .map(|_| { + let pair2 = pair.clone(); + thread::spawn(move || { + let (lock, cvar) = &*pair2; + let guard = lock.lock().unwrap(); + // Block waiting on the conditional variable. + let _ = cvar.wait(guard).unwrap(); + }) + }) + .inspect(|_| { + thread::yield_now(); + thread::yield_now(); + }) + .collect(); - // Wait for the thread to start up. - let (lock, cvar) = &*pair; - let mut started = lock.lock().unwrap(); - // As long as the value inside the `Mutex` is `false`, we wait. - while !*started { - started = cvar.wait(started).unwrap(); + let (_, cvar) = &*pair; + // Unblock all threads. + cvar.notify_all(); + + for handle in handles { + handle.join().unwrap(); } } From bd97074517c6ba334247b70f33199e40374c223a Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Tue, 19 May 2020 18:44:32 +0200 Subject: [PATCH 2098/3747] Small changes. --- src/shims/sync.rs | 79 ++++++++++++------- src/sync.rs | 16 +++- src/thread.rs | 11 ++- .../libc_pthread_mutex_normal_deadlock.rs | 4 +- .../sync/libc_pthread_mutex_wrong_owner.rs | 2 +- tests/run-pass/concurrency/sync.rs | 7 +- 6 files changed, 77 insertions(+), 42 deletions(-) diff --git a/src/shims/sync.rs b/src/shims/sync.rs index f34799f74251f..4fe3534739811 100644 --- a/src/shims/sync.rs +++ b/src/shims/sync.rs @@ -288,15 +288,12 @@ fn release_cond_mutex<'mir, 'tcx: 'mir>( active_thread: ThreadId, mutex: MutexId, ) -> InterpResult<'tcx> { - if let Some((old_owner_thread, old_locked_count)) = ecx.mutex_unlock(mutex)? { + if let Some(old_locked_count) = ecx.mutex_unlock(mutex, active_thread)? { if old_locked_count != 1 { throw_unsup_format!("awaiting on a lock acquired multiple times is not supported"); } - if old_owner_thread != active_thread { - throw_ub_format!("awaiting on a mutex owned by a different thread"); - } } else { - throw_ub_format!("awaiting on unlocked mutex"); + throw_ub_format!("awaiting on unlocked or owned by a different thread mutex"); } ecx.block_thread(active_thread)?; Ok(()) @@ -321,7 +318,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); let kind = this.read_scalar(kind_op)?.not_undef()?; - if kind == this.eval_libc("PTHREAD_MUTEX_NORMAL")? + if kind == this.eval_libc("PTHREAD_MUTEX_DEFAULT")? + || kind == this.eval_libc("PTHREAD_MUTEX_NORMAL")? || kind == this.eval_libc("PTHREAD_MUTEX_ERRORCHECK")? || kind == this.eval_libc("PTHREAD_MUTEX_RECURSIVE")? { @@ -380,6 +378,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(0) } else { // Trying to acquire the same mutex again. + if kind == this.eval_libc("PTHREAD_MUTEX_DEFAULT")? { + // FIXME: Sometimes this is actually a Deadlock. + // https://github.com/rust-lang/miri/issues/1419 + throw_ub_format!( + "trying to acquire already locked PTHREAD_MUTEX_DEFAULT (see #1419)" + ); + } if kind == this.eval_libc("PTHREAD_MUTEX_NORMAL")? { throw_machine_stop!(TerminationInfo::Deadlock); } else if kind == this.eval_libc("PTHREAD_MUTEX_ERRORCHECK")? { @@ -388,7 +393,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.mutex_lock(id, active_thread); Ok(0) } else { - throw_ub_format!("called pthread_mutex_lock on an unsupported type of mutex"); + throw_unsup_format!( + "called pthread_mutex_lock on an unsupported type of mutex" + ); } } } else { @@ -410,7 +417,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if owner_thread != active_thread { this.eval_libc_i32("EBUSY") } else { - if kind == this.eval_libc("PTHREAD_MUTEX_NORMAL")? + if kind == this.eval_libc("PTHREAD_MUTEX_DEFAULT")? + || kind == this.eval_libc("PTHREAD_MUTEX_NORMAL")? || kind == this.eval_libc("PTHREAD_MUTEX_ERRORCHECK")? { this.eval_libc_i32("EBUSY") @@ -418,7 +426,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.mutex_lock(id, active_thread); Ok(0) } else { - throw_ub_format!( + throw_unsup_format!( "called pthread_mutex_trylock on an unsupported type of mutex" ); } @@ -435,21 +443,29 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let kind = mutex_get_kind(this, mutex_op)?.not_undef()?; let id = mutex_get_or_create_id(this, mutex_op)?; + let active_thread = this.get_active_thread()?; - if let Some((old_owner_thread, _old_locked_count)) = this.mutex_unlock(id)? { - if old_owner_thread != this.get_active_thread()? { - throw_ub_format!("called pthread_mutex_unlock on a mutex owned by another thread"); - } + if let Some(_old_locked_count) = this.mutex_unlock(id, active_thread)? { + // The mutex was locked by the current thread. Ok(0) } else { - if kind == this.eval_libc("PTHREAD_MUTEX_NORMAL")? { - throw_ub_format!("unlocked a PTHREAD_MUTEX_NORMAL mutex that was not locked"); + // The mutex was locked by another thread or not locked at all. See + // the “Unlock When Not Owner” column in + // https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_mutex_unlock.html. + if kind == this.eval_libc("PTHREAD_MUTEX_DEFAULT")? { + throw_ub_format!( + "unlocked a PTHREAD_MUTEX_DEFAULT mutex that was not locked by the current thread" + ); + } else if kind == this.eval_libc("PTHREAD_MUTEX_NORMAL")? { + throw_ub_format!( + "unlocked a PTHREAD_MUTEX_NORMAL mutex that was not locked by the current thread" + ); } else if kind == this.eval_libc("PTHREAD_MUTEX_ERRORCHECK")? { this.eval_libc_i32("EPERM") } else if kind == this.eval_libc("PTHREAD_MUTEX_RECURSIVE")? { this.eval_libc_i32("EPERM") } else { - throw_ub_format!("called pthread_mutex_unlock on an unsupported type of mutex"); + throw_unsup_format!("called pthread_mutex_unlock on an unsupported type of mutex"); } } } @@ -505,6 +521,18 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let active_thread = this.get_active_thread()?; if this.rwlock_is_locked(id) { + // Note: this will deadlock if the lock is already locked by this + // thread in any way. + // + // Relevant documentation: + // https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_rwlock_wrlock.html + // An in depth discussion on this topic: + // https://github.com/rust-lang/rust/issues/53127 + // + // FIXME: Detect and report the deadlock proactively. (We currently + // report the deadlock only when no thread can continue execution, + // but we could detect that this lock is already locked and report + // an error.) this.rwlock_enqueue_and_block_writer(id, active_thread)?; } else { this.rwlock_writer_lock(id, active_thread); @@ -719,19 +747,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let clock_id = cond_get_clock_id(this, cond_op)?.to_i32()?; let duration = { let tp = this.deref_operand(abstime_op)?; - let mut offset = Size::from_bytes(0); - let layout = this.libc_ty_layout("time_t")?; - let seconds_place = tp.offset(offset, MemPlaceMeta::None, layout, this)?; + let seconds_place = this.mplace_field(tp, 0)?; let seconds = this.read_scalar(seconds_place.into())?; - offset += layout.size; - let layout = this.libc_ty_layout("c_long")?; - let nanoseconds_place = tp.offset(offset, MemPlaceMeta::None, layout, this)?; + let nanoseconds_place = this.mplace_field(tp, 1)?; let nanoseconds = this.read_scalar(nanoseconds_place.into())?; - let (seconds, nanoseconds) = if this.pointer_size().bytes() == 8 { - (seconds.to_u64()?, nanoseconds.to_u64()?.try_into().unwrap()) - } else { - (seconds.to_u32()?.into(), nanoseconds.to_u32()?) - }; + let (seconds, nanoseconds) = ( + seconds.to_machine_usize(this)?, + nanoseconds.to_machine_usize(this)?.try_into().unwrap(), + ); Duration::new(seconds, nanoseconds) }; @@ -740,7 +763,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } else if clock_id == this.eval_libc_i32("CLOCK_MONOTONIC")? { Time::Monotonic(this.machine.time_anchor.checked_add(duration).unwrap()) } else { - throw_unsup_format!("Unsupported clock id."); + throw_unsup_format!("unsupported clock id: {}", clock_id); }; // Register the timeout callback. diff --git a/src/sync.rs b/src/sync.rs index cbae29bdbb367..026542926ed84 100644 --- a/src/sync.rs +++ b/src/sync.rs @@ -30,10 +30,12 @@ macro_rules! declare_id { // We use 0 as a sentinel value (see the comment above) and, // therefore, need to shift by one when converting from an index // into a vector. - $name(NonZeroU32::new(u32::try_from(idx).unwrap() + 1).unwrap()) + let shifted_idx = u32::try_from(idx).unwrap().checked_add(1).unwrap(); + $name(NonZeroU32::new(shifted_idx).unwrap()) } fn index(self) -> usize { // See the comment in `Self::new`. + // (This cannot underflow because self is NonZeroU32.) usize::try_from(self.0.get() - 1).unwrap() } } @@ -150,11 +152,19 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// /// Note: It is the caller's responsibility to check that the thread that /// unlocked the lock actually is the same one, which owned it. - fn mutex_unlock(&mut self, id: MutexId) -> InterpResult<'tcx, Option<(ThreadId, usize)>> { + fn mutex_unlock( + &mut self, + id: MutexId, + expected_owner: ThreadId, + ) -> InterpResult<'tcx, Option> { let this = self.eval_context_mut(); let mutex = &mut this.machine.threads.sync.mutexes[id]; if let Some(current_owner) = mutex.owner { // Mutex is locked. + if current_owner != expected_owner { + // Only the owner can unlock the mutex. + return Ok(None); + } let old_lock_count = mutex.lock_count; mutex.lock_count = old_lock_count .checked_sub(1) @@ -168,7 +178,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.unblock_thread(new_owner)?; } } - Ok(Some((current_owner, old_lock_count))) + Ok(Some(old_lock_count)) } else { // Mutex is unlocked. Ok(None) diff --git a/src/thread.rs b/src/thread.rs index 70c2419c4d490..45b07477fa239 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -159,6 +159,7 @@ impl<'mir, 'tcx> Default for Thread<'mir, 'tcx> { } } +/// A specific moment in time. #[derive(Debug)] pub enum Time { Monotonic(Instant), @@ -449,9 +450,9 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { // // Documentation: // https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_cond_timedwait.html# - if let Some(sleep_time) = - self.timeout_callbacks.values().map(|info| info.call_time.get_wait_time()).min() - { + let potential_sleep_time = + self.timeout_callbacks.values().map(|info| info.call_time.get_wait_time()).min(); + if let Some(sleep_time) = potential_sleep_time { if sleep_time == Duration::new(0, 0) { return Ok(SchedulingAction::ExecuteTimeoutCallback); } @@ -479,9 +480,7 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { // We have not found a thread to execute. if self.threads.iter().all(|thread| thread.state == ThreadState::Terminated) { unreachable!("all threads terminated without the main thread terminating?!"); - } else if let Some(sleep_time) = - self.timeout_callbacks.values().map(|info| info.call_time.get_wait_time()).min() - { + } else if let Some(sleep_time) = potential_sleep_time { // All threads are currently blocked, but we have unexecuted // timeout_callbacks, which may unblock some of the threads. Hence, // sleep until the first callback. diff --git a/tests/compile-fail/sync/libc_pthread_mutex_normal_deadlock.rs b/tests/compile-fail/sync/libc_pthread_mutex_normal_deadlock.rs index 7034bf64ec901..4af8ee5df4b7f 100644 --- a/tests/compile-fail/sync/libc_pthread_mutex_normal_deadlock.rs +++ b/tests/compile-fail/sync/libc_pthread_mutex_normal_deadlock.rs @@ -11,6 +11,8 @@ fn main() { let mut mutex: libc::pthread_mutex_t = std::mem::zeroed(); assert_eq!(libc::pthread_mutex_init(&mut mutex as *mut _, &mutexattr as *const _), 0); assert_eq!(libc::pthread_mutex_lock(&mut mutex as *mut _), 0); - libc::pthread_mutex_lock(&mut mutex as *mut _); //~ ERROR deadlock + // FIXME: The error should be deadlock. See issue + // https://github.com/rust-lang/miri/issues/1419. + libc::pthread_mutex_lock(&mut mutex as *mut _); //~ ERROR Undefined Behavior } } diff --git a/tests/compile-fail/sync/libc_pthread_mutex_wrong_owner.rs b/tests/compile-fail/sync/libc_pthread_mutex_wrong_owner.rs index 3009721abe2e1..e67e8d366ebf8 100644 --- a/tests/compile-fail/sync/libc_pthread_mutex_wrong_owner.rs +++ b/tests/compile-fail/sync/libc_pthread_mutex_wrong_owner.rs @@ -24,7 +24,7 @@ fn main() { let lock_copy = lock.clone(); thread::spawn(move || { - assert_eq!(libc::pthread_mutex_unlock(lock_copy.0.get() as *mut _), 0); //~ ERROR: Undefined Behavior: called pthread_mutex_unlock on a mutex owned by another thread + assert_eq!(libc::pthread_mutex_unlock(lock_copy.0.get() as *mut _), 0); //~ ERROR: Undefined Behavior: unlocked a PTHREAD_MUTEX_DEFAULT mutex that was not locked }) .join() .unwrap(); diff --git a/tests/run-pass/concurrency/sync.rs b/tests/run-pass/concurrency/sync.rs index faf47851bd01f..2009c01ce9f95 100644 --- a/tests/run-pass/concurrency/sync.rs +++ b/tests/run-pass/concurrency/sync.rs @@ -91,7 +91,8 @@ fn check_conditional_variables_timed_wait_timeout() { let now = Instant::now(); let (_guard, timeout) = cvar.wait_timeout(guard, Duration::from_millis(100)).unwrap(); assert!(timeout.timed_out()); - assert!(now.elapsed().as_millis() >= 100); + let elapsed_time = now.elapsed().as_millis(); + assert!(100 <= elapsed_time && elapsed_time <= 300); } /// Test that signaling a conditional variable when waiting with a timeout works @@ -243,7 +244,7 @@ fn get_cached_val() -> usize { fn expensive_computation() -> usize { let mut i = 1; let mut c = 1; - while i < 10000 { + while i < 1000 { i *= c; c += 1; } @@ -257,7 +258,7 @@ fn check_once() { thread::spawn(|| { thread::yield_now(); let val = get_cached_val(); - assert_eq!(val, 40320); + assert_eq!(val, 5040); }) }) .collect(); From 6ff0af3adf6aa9d1dac07d45cd40bdc8b123d229 Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Sun, 24 May 2020 20:20:28 +0200 Subject: [PATCH 2099/3747] Fix #1419. --- src/shims/sync.rs | 58 ++++++++++++++----- .../libc_pthread_mutex_normal_deadlock.rs | 4 +- 2 files changed, 45 insertions(+), 17 deletions(-) diff --git a/src/shims/sync.rs b/src/shims/sync.rs index 4fe3534739811..ee139b057914d 100644 --- a/src/shims/sync.rs +++ b/src/shims/sync.rs @@ -58,8 +58,31 @@ fn set_at_offset<'mir, 'tcx: 'mir>( // store an i32 in the first four bytes equal to the corresponding libc mutex kind constant // (e.g. PTHREAD_MUTEX_NORMAL). +/// A flag that allows to distinguish `PTHREAD_MUTEX_NORMAL` from +/// `PTHREAD_MUTEX_DEFAULT`. Since in `glibc` they have the same numeric values, +/// but different behaviour, we need a way to distinguish them. We do this by +/// setting this bit flag to the `PTHREAD_MUTEX_NORMAL` mutexes. See the comment +/// in `pthread_mutexattr_settype` function. +const PTHREAD_MUTEX_NORMAL_FLAG: i32 = 0x8000000; + const PTHREAD_MUTEXATTR_T_MIN_SIZE: u64 = 4; +fn is_mutex_kind_default<'mir, 'tcx: 'mir>( + ecx: &mut MiriEvalContext<'mir, 'tcx>, + kind: Scalar, +) -> InterpResult<'tcx, bool> { + Ok(kind == ecx.eval_libc("PTHREAD_MUTEX_DEFAULT")?) +} + +fn is_mutex_kind_normal<'mir, 'tcx: 'mir>( + ecx: &mut MiriEvalContext<'mir, 'tcx>, + kind: Scalar, +) -> InterpResult<'tcx, bool> { + let kind = kind.to_i32()?; + let mutex_normal_kind = ecx.eval_libc("PTHREAD_MUTEX_NORMAL")?.to_i32()?; + Ok(kind == (mutex_normal_kind | PTHREAD_MUTEX_NORMAL_FLAG)) +} + fn mutexattr_get_kind<'mir, 'tcx: 'mir>( ecx: &MiriEvalContext<'mir, 'tcx>, attr_op: OpTy<'tcx, Tag>, @@ -318,8 +341,20 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); let kind = this.read_scalar(kind_op)?.not_undef()?; - if kind == this.eval_libc("PTHREAD_MUTEX_DEFAULT")? - || kind == this.eval_libc("PTHREAD_MUTEX_NORMAL")? + if kind == this.eval_libc("PTHREAD_MUTEX_NORMAL")? { + // In `glibc` implementation, the numeric values of + // `PTHREAD_MUTEX_NORMAL` and `PTHREAD_MUTEX_DEFAULT` are equal, but + // they have different behaviour in some cases. Therefore, we add + // this flag to ensure that we can distinguish + // `PTHREAD_MUTEX_NORMAL` from `PTHREAD_MUTEX_DEFAULT`. + let normal_kind = kind.to_i32()? | PTHREAD_MUTEX_NORMAL_FLAG; + // Check that after setting the flag, the kind is distinguishable + // from all other kinds. + assert_ne!(normal_kind, this.eval_libc("PTHREAD_MUTEX_DEFAULT")?.to_i32()?); + assert_ne!(normal_kind, this.eval_libc("PTHREAD_MUTEX_ERRORCHECK")?.to_i32()?); + assert_ne!(normal_kind, this.eval_libc("PTHREAD_MUTEX_RECURSIVE")?.to_i32()?); + mutexattr_set_kind(this, attr_op, Scalar::from_i32(normal_kind))?; + } else if kind == this.eval_libc("PTHREAD_MUTEX_DEFAULT")? || kind == this.eval_libc("PTHREAD_MUTEX_ERRORCHECK")? || kind == this.eval_libc("PTHREAD_MUTEX_RECURSIVE")? { @@ -378,14 +413,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(0) } else { // Trying to acquire the same mutex again. - if kind == this.eval_libc("PTHREAD_MUTEX_DEFAULT")? { - // FIXME: Sometimes this is actually a Deadlock. - // https://github.com/rust-lang/miri/issues/1419 - throw_ub_format!( - "trying to acquire already locked PTHREAD_MUTEX_DEFAULT (see #1419)" - ); - } - if kind == this.eval_libc("PTHREAD_MUTEX_NORMAL")? { + if is_mutex_kind_default(this, kind)? { + throw_ub_format!("trying to acquire already locked PTHREAD_MUTEX_DEFAULT"); + } else if is_mutex_kind_normal(this, kind)? { throw_machine_stop!(TerminationInfo::Deadlock); } else if kind == this.eval_libc("PTHREAD_MUTEX_ERRORCHECK")? { this.eval_libc_i32("EDEADLK") @@ -417,8 +447,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if owner_thread != active_thread { this.eval_libc_i32("EBUSY") } else { - if kind == this.eval_libc("PTHREAD_MUTEX_DEFAULT")? - || kind == this.eval_libc("PTHREAD_MUTEX_NORMAL")? + if is_mutex_kind_default(this, kind)? + || is_mutex_kind_normal(this, kind)? || kind == this.eval_libc("PTHREAD_MUTEX_ERRORCHECK")? { this.eval_libc_i32("EBUSY") @@ -452,11 +482,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // The mutex was locked by another thread or not locked at all. See // the “Unlock When Not Owner” column in // https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_mutex_unlock.html. - if kind == this.eval_libc("PTHREAD_MUTEX_DEFAULT")? { + if is_mutex_kind_default(this, kind)? { throw_ub_format!( "unlocked a PTHREAD_MUTEX_DEFAULT mutex that was not locked by the current thread" ); - } else if kind == this.eval_libc("PTHREAD_MUTEX_NORMAL")? { + } else if is_mutex_kind_normal(this, kind)? { throw_ub_format!( "unlocked a PTHREAD_MUTEX_NORMAL mutex that was not locked by the current thread" ); diff --git a/tests/compile-fail/sync/libc_pthread_mutex_normal_deadlock.rs b/tests/compile-fail/sync/libc_pthread_mutex_normal_deadlock.rs index 4af8ee5df4b7f..96e0ff3bfff72 100644 --- a/tests/compile-fail/sync/libc_pthread_mutex_normal_deadlock.rs +++ b/tests/compile-fail/sync/libc_pthread_mutex_normal_deadlock.rs @@ -11,8 +11,6 @@ fn main() { let mut mutex: libc::pthread_mutex_t = std::mem::zeroed(); assert_eq!(libc::pthread_mutex_init(&mut mutex as *mut _, &mutexattr as *const _), 0); assert_eq!(libc::pthread_mutex_lock(&mut mutex as *mut _), 0); - // FIXME: The error should be deadlock. See issue - // https://github.com/rust-lang/miri/issues/1419. - libc::pthread_mutex_lock(&mut mutex as *mut _); //~ ERROR Undefined Behavior + libc::pthread_mutex_lock(&mut mutex as *mut _); //~ ERROR deadlock: the evaluated program deadlocked } } From 90590a399d326641a9132bb4a33f4645c08b73d8 Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Sun, 24 May 2020 20:29:56 +0200 Subject: [PATCH 2100/3747] Small fixes. --- src/shims/sync.rs | 21 +++++++++++++------ src/thread.rs | 15 +++++++++---- .../sync/libc_pthread_mutex_NULL_deadlock.rs | 16 ++++++++++++++ .../libc_pthread_mutex_default_deadlock.rs | 17 +++++++++++++++ .../sync/libc_pthread_mutex_wrong_owner.rs | 2 +- 5 files changed, 60 insertions(+), 11 deletions(-) create mode 100644 tests/compile-fail/sync/libc_pthread_mutex_NULL_deadlock.rs create mode 100644 tests/compile-fail/sync/libc_pthread_mutex_default_deadlock.rs diff --git a/src/shims/sync.rs b/src/shims/sync.rs index ee139b057914d..95092a042d34a 100644 --- a/src/shims/sync.rs +++ b/src/shims/sync.rs @@ -301,6 +301,8 @@ fn post_cond_signal<'mir, 'tcx: 'mir>( mutex: MutexId, ) -> InterpResult<'tcx> { reacquire_cond_mutex(ecx, thread, mutex)?; + // Waiting for the mutex is not included in the waiting time because we need + // to acquire the mutex always even if we get a timeout. ecx.unregister_timeout_callback_if_exists(thread) } @@ -343,10 +345,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let kind = this.read_scalar(kind_op)?.not_undef()?; if kind == this.eval_libc("PTHREAD_MUTEX_NORMAL")? { // In `glibc` implementation, the numeric values of - // `PTHREAD_MUTEX_NORMAL` and `PTHREAD_MUTEX_DEFAULT` are equal, but - // they have different behaviour in some cases. Therefore, we add - // this flag to ensure that we can distinguish - // `PTHREAD_MUTEX_NORMAL` from `PTHREAD_MUTEX_DEFAULT`. + // `PTHREAD_MUTEX_NORMAL` and `PTHREAD_MUTEX_DEFAULT` are equal. + // However, a mutex created by explicitly passing + // `PTHREAD_MUTEX_NORMAL` type has in some cases different behaviour + // from the default mutex for which the type was not explicitly + // specified. For a more detailed discussion, please see + // https://github.com/rust-lang/miri/issues/1419. + // + // To distinguish these two cases in already constructed mutexes, we + // use the same trick as glibc: for the case when + // `pthread_mutexattr_settype` is caled explicitly, we set the + // `PTHREAD_MUTEX_NORMAL_FLAG` flag. let normal_kind = kind.to_i32()? | PTHREAD_MUTEX_NORMAL_FLAG; // Check that after setting the flag, the kind is distinguishable // from all other kinds. @@ -414,7 +423,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } else { // Trying to acquire the same mutex again. if is_mutex_kind_default(this, kind)? { - throw_ub_format!("trying to acquire already locked PTHREAD_MUTEX_DEFAULT"); + throw_ub_format!("trying to acquire already locked default mutex"); } else if is_mutex_kind_normal(this, kind)? { throw_machine_stop!(TerminationInfo::Deadlock); } else if kind == this.eval_libc("PTHREAD_MUTEX_ERRORCHECK")? { @@ -484,7 +493,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_mutex_unlock.html. if is_mutex_kind_default(this, kind)? { throw_ub_format!( - "unlocked a PTHREAD_MUTEX_DEFAULT mutex that was not locked by the current thread" + "unlocked a default mutex that was not locked by the current thread" ); } else if is_mutex_kind_normal(this, kind)? { throw_ub_format!( diff --git a/src/thread.rs b/src/thread.rs index 45b07477fa239..59f08eec1649b 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -377,6 +377,9 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { } /// Register the given `callback` to be called once the `call_time` passes. + /// + /// The callback will be called with `thread` being the active thread, and + /// the callback may not change the active thread. fn register_timeout_callback( &mut self, thread: ThreadId, @@ -452,10 +455,8 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { // https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_cond_timedwait.html# let potential_sleep_time = self.timeout_callbacks.values().map(|info| info.call_time.get_wait_time()).min(); - if let Some(sleep_time) = potential_sleep_time { - if sleep_time == Duration::new(0, 0) { - return Ok(SchedulingAction::ExecuteTimeoutCallback); - } + if potential_sleep_time == Some(Duration::new(0, 0)) { + return Ok(SchedulingAction::ExecuteTimeoutCallback); } // No callbacks scheduled, pick a regular thread to execute. if self.threads[self.active_thread].state == ThreadState::Enabled @@ -699,6 +700,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); let (thread, callback) = this.machine.threads.get_ready_callback().expect("no callback found"); + // This back-and-forth with `set_active_thread` is here because of two + // design decisions: + // 1. Make the caller and not the callback responsible for changing + // thread. + // 2. Make the scheduler the only place that can change the active + // thread. let old_thread = this.set_active_thread(thread)?; callback(this)?; this.set_active_thread(old_thread)?; diff --git a/tests/compile-fail/sync/libc_pthread_mutex_NULL_deadlock.rs b/tests/compile-fail/sync/libc_pthread_mutex_NULL_deadlock.rs new file mode 100644 index 0000000000000..3a737b2e3e155 --- /dev/null +++ b/tests/compile-fail/sync/libc_pthread_mutex_NULL_deadlock.rs @@ -0,0 +1,16 @@ +// ignore-windows: No libc on Windows +// +// Check that if we pass NULL attribute, then we get the default mutex type. + +#![feature(rustc_private)] + +extern crate libc; + +fn main() { + unsafe { + let mut mutex: libc::pthread_mutex_t = std::mem::zeroed(); + assert_eq!(libc::pthread_mutex_init(&mut mutex as *mut _, std::ptr::null() as *const _), 0); + assert_eq!(libc::pthread_mutex_lock(&mut mutex as *mut _), 0); + libc::pthread_mutex_lock(&mut mutex as *mut _); //~ ERROR Undefined Behavior: trying to acquire already locked default mutex + } +} diff --git a/tests/compile-fail/sync/libc_pthread_mutex_default_deadlock.rs b/tests/compile-fail/sync/libc_pthread_mutex_default_deadlock.rs new file mode 100644 index 0000000000000..0f6f570d70b02 --- /dev/null +++ b/tests/compile-fail/sync/libc_pthread_mutex_default_deadlock.rs @@ -0,0 +1,17 @@ +// ignore-windows: No libc on Windows +// +// Check that if we do not set the mutex type, it is the default. + +#![feature(rustc_private)] + +extern crate libc; + +fn main() { + unsafe { + let mutexattr: libc::pthread_mutexattr_t = std::mem::zeroed(); + let mut mutex: libc::pthread_mutex_t = std::mem::zeroed(); + assert_eq!(libc::pthread_mutex_init(&mut mutex as *mut _, &mutexattr as *const _), 0); + assert_eq!(libc::pthread_mutex_lock(&mut mutex as *mut _), 0); + libc::pthread_mutex_lock(&mut mutex as *mut _); //~ ERROR Undefined Behavior: trying to acquire already locked default mutex + } +} diff --git a/tests/compile-fail/sync/libc_pthread_mutex_wrong_owner.rs b/tests/compile-fail/sync/libc_pthread_mutex_wrong_owner.rs index e67e8d366ebf8..d69929d4ed465 100644 --- a/tests/compile-fail/sync/libc_pthread_mutex_wrong_owner.rs +++ b/tests/compile-fail/sync/libc_pthread_mutex_wrong_owner.rs @@ -24,7 +24,7 @@ fn main() { let lock_copy = lock.clone(); thread::spawn(move || { - assert_eq!(libc::pthread_mutex_unlock(lock_copy.0.get() as *mut _), 0); //~ ERROR: Undefined Behavior: unlocked a PTHREAD_MUTEX_DEFAULT mutex that was not locked + assert_eq!(libc::pthread_mutex_unlock(lock_copy.0.get() as *mut _), 0); //~ ERROR: Undefined Behavior: unlocked a default mutex that was not locked by the current thread }) .join() .unwrap(); From dec205757ae2e370e631729c96f1d8e4a0ab1936 Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Mon, 25 May 2020 00:28:01 +0200 Subject: [PATCH 2101/3747] Fix compilation errors after rebase. --- src/shims/foreign_items/posix.rs | 34 ++++++++++++++++++++++---------- src/shims/sync.rs | 30 ++++++++++++++-------------- 2 files changed, 39 insertions(+), 25 deletions(-) diff --git a/src/shims/foreign_items/posix.rs b/src/shims/foreign_items/posix.rs index 352e38113abbe..db2fab526c1f7 100644 --- a/src/shims/foreign_items/posix.rs +++ b/src/shims/foreign_items/posix.rs @@ -331,42 +331,52 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_condattr_init" => { - let result = this.pthread_condattr_init(args[0])?; + let &[attr] = check_arg_count(args)?; + let result = this.pthread_condattr_init(attr)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_condattr_setclock" => { - let result = this.pthread_condattr_setclock(args[0], args[1])?; + let &[attr, clock_id] = check_arg_count(args)?; + let result = this.pthread_condattr_setclock(attr, clock_id)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_condattr_getclock" => { - let result = this.pthread_condattr_getclock(args[0], args[1])?; + let &[attr, clock_id] = check_arg_count(args)?; + let result = this.pthread_condattr_getclock(attr, clock_id)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_condattr_destroy" => { - let result = this.pthread_condattr_destroy(args[0])?; + let &[attr] = check_arg_count(args)?; + let result = this.pthread_condattr_destroy(attr)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_cond_init" => { - let result = this.pthread_cond_init(args[0], args[1])?; + let &[cond, attr] = check_arg_count(args)?; + let result = this.pthread_cond_init(cond, attr)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_cond_signal" => { - let result = this.pthread_cond_signal(args[0])?; + let &[cond] = check_arg_count(args)?; + let result = this.pthread_cond_signal(cond)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_cond_broadcast" => { - let result = this.pthread_cond_broadcast(args[0])?; + let &[cond] = check_arg_count(args)?; + let result = this.pthread_cond_broadcast(cond)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_cond_wait" => { - let result = this.pthread_cond_wait(args[0], args[1])?; + let &[cond, mutex] = check_arg_count(args)?; + let result = this.pthread_cond_wait(cond, mutex)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_cond_timedwait" => { - this.pthread_cond_timedwait(args[0], args[1], args[2], dest)?; + let &[cond, mutex, abstime] = check_arg_count(args)?; + this.pthread_cond_timedwait(cond, mutex, abstime, dest)?; } "pthread_cond_destroy" => { - let result = this.pthread_cond_destroy(args[0])?; + let &[cond] = check_arg_count(args)?; + let result = this.pthread_cond_destroy(cond)?; this.write_scalar(Scalar::from_i32(result), dest)?; } @@ -430,6 +440,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "pthread_attr_init" | "pthread_attr_destroy" + if this.frame().instance.to_string().starts_with("std::sys::unix::") => { + let &[_] = check_arg_count(args)?; + this.write_null(dest)?; + } | "pthread_attr_setstacksize" if this.frame().instance.to_string().starts_with("std::sys::unix::") => { let &[_, _] = check_arg_count(args)?; diff --git a/src/shims/sync.rs b/src/shims/sync.rs index 95092a042d34a..5b0de43e54669 100644 --- a/src/shims/sync.rs +++ b/src/shims/sync.rs @@ -129,14 +129,14 @@ fn mutex_set_kind<'mir, 'tcx: 'mir>( fn mutex_get_id<'mir, 'tcx: 'mir>( ecx: &MiriEvalContext<'mir, 'tcx>, mutex_op: OpTy<'tcx, Tag>, -) -> InterpResult<'tcx, ScalarMaybeUndef> { +) -> InterpResult<'tcx, ScalarMaybeUninit> { get_at_offset(ecx, mutex_op, 4, ecx.machine.layouts.u32, PTHREAD_MUTEX_T_MIN_SIZE) } fn mutex_set_id<'mir, 'tcx: 'mir>( ecx: &mut MiriEvalContext<'mir, 'tcx>, mutex_op: OpTy<'tcx, Tag>, - id: impl Into>, + id: impl Into>, ) -> InterpResult<'tcx, ()> { set_at_offset(ecx, mutex_op, 4, id, ecx.machine.layouts.u32, PTHREAD_MUTEX_T_MIN_SIZE) } @@ -176,7 +176,7 @@ fn rwlock_get_id<'mir, 'tcx: 'mir>( fn rwlock_set_id<'mir, 'tcx: 'mir>( ecx: &mut MiriEvalContext<'mir, 'tcx>, rwlock_op: OpTy<'tcx, Tag>, - id: impl Into>, + id: impl Into>, ) -> InterpResult<'tcx, ()> { set_at_offset(ecx, rwlock_op, 4, id, ecx.machine.layouts.u32, PTHREAD_RWLOCK_T_MIN_SIZE) } @@ -208,14 +208,14 @@ const PTHREAD_CONDATTR_T_MIN_SIZE: u64 = 4; fn condattr_get_clock_id<'mir, 'tcx: 'mir>( ecx: &MiriEvalContext<'mir, 'tcx>, attr_op: OpTy<'tcx, Tag>, -) -> InterpResult<'tcx, ScalarMaybeUndef> { +) -> InterpResult<'tcx, ScalarMaybeUninit> { get_at_offset(ecx, attr_op, 0, ecx.machine.layouts.i32, PTHREAD_CONDATTR_T_MIN_SIZE) } fn condattr_set_clock_id<'mir, 'tcx: 'mir>( ecx: &mut MiriEvalContext<'mir, 'tcx>, attr_op: OpTy<'tcx, Tag>, - clock_id: impl Into>, + clock_id: impl Into>, ) -> InterpResult<'tcx, ()> { set_at_offset(ecx, attr_op, 0, clock_id, ecx.machine.layouts.i32, PTHREAD_CONDATTR_T_MIN_SIZE) } @@ -234,14 +234,14 @@ const PTHREAD_COND_T_MIN_SIZE: u64 = 12; fn cond_get_id<'mir, 'tcx: 'mir>( ecx: &MiriEvalContext<'mir, 'tcx>, cond_op: OpTy<'tcx, Tag>, -) -> InterpResult<'tcx, ScalarMaybeUndef> { +) -> InterpResult<'tcx, ScalarMaybeUninit> { get_at_offset(ecx, cond_op, 4, ecx.machine.layouts.u32, PTHREAD_COND_T_MIN_SIZE) } fn cond_set_id<'mir, 'tcx: 'mir>( ecx: &mut MiriEvalContext<'mir, 'tcx>, cond_op: OpTy<'tcx, Tag>, - id: impl Into>, + id: impl Into>, ) -> InterpResult<'tcx, ()> { set_at_offset(ecx, cond_op, 4, id, ecx.machine.layouts.u32, PTHREAD_COND_T_MIN_SIZE) } @@ -265,14 +265,14 @@ fn cond_get_or_create_id<'mir, 'tcx: 'mir>( fn cond_get_clock_id<'mir, 'tcx: 'mir>( ecx: &MiriEvalContext<'mir, 'tcx>, cond_op: OpTy<'tcx, Tag>, -) -> InterpResult<'tcx, ScalarMaybeUndef> { +) -> InterpResult<'tcx, ScalarMaybeUninit> { get_at_offset(ecx, cond_op, 8, ecx.machine.layouts.i32, PTHREAD_COND_T_MIN_SIZE) } fn cond_set_clock_id<'mir, 'tcx: 'mir>( ecx: &mut MiriEvalContext<'mir, 'tcx>, cond_op: OpTy<'tcx, Tag>, - clock_id: impl Into>, + clock_id: impl Into>, ) -> InterpResult<'tcx, ()> { set_at_offset(ecx, cond_op, 8, clock_id, ecx.machine.layouts.i32, PTHREAD_COND_T_MIN_SIZE) } @@ -518,8 +518,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx throw_ub_format!("destroyed a locked mutex"); } - mutex_set_kind(this, mutex_op, ScalarMaybeUndef::Undef)?; - mutex_set_id(this, mutex_op, ScalarMaybeUndef::Undef)?; + mutex_set_kind(this, mutex_op, ScalarMaybeUninit::Uninit)?; + mutex_set_id(this, mutex_op, ScalarMaybeUninit::Uninit)?; Ok(0) } @@ -643,7 +643,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx throw_ub_format!("destroyed a locked rwlock"); } - rwlock_set_id(this, rwlock_op, ScalarMaybeUndef::Undef)?; + rwlock_set_id(this, rwlock_op, ScalarMaybeUninit::Uninit)?; Ok(0) } @@ -696,7 +696,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn pthread_condattr_destroy(&mut self, attr_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - condattr_set_clock_id(this, attr_op, ScalarMaybeUndef::Undef)?; + condattr_set_clock_id(this, attr_op, ScalarMaybeUninit::Uninit)?; Ok(0) } @@ -835,8 +835,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if this.condvar_is_awaited(id) { throw_ub_format!("destroyed an awaited conditional variable"); } - cond_set_id(this, cond_op, ScalarMaybeUndef::Undef)?; - cond_set_clock_id(this, cond_op, ScalarMaybeUndef::Undef)?; + cond_set_id(this, cond_op, ScalarMaybeUninit::Uninit)?; + cond_set_clock_id(this, cond_op, ScalarMaybeUninit::Uninit)?; Ok(0) } From 34ddd775e8352c4905b56f183421902cdda9d100 Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Mon, 25 May 2020 08:07:07 +0200 Subject: [PATCH 2102/3747] Increase the elapsed time window. --- tests/run-pass/concurrency/libc_pthread_cond.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/run-pass/concurrency/libc_pthread_cond.rs b/tests/run-pass/concurrency/libc_pthread_cond.rs index 39b6a7e4ef803..27f5ead450fab 100644 --- a/tests/run-pass/concurrency/libc_pthread_cond.rs +++ b/tests/run-pass/concurrency/libc_pthread_cond.rs @@ -34,7 +34,7 @@ fn test_timed_wait_timeout(clock_id: i32) { libc::ETIMEDOUT ); let elapsed_time = current_time.elapsed().as_millis(); - assert!(900 <= elapsed_time && elapsed_time <= 1100); + assert!(900 <= elapsed_time && elapsed_time <= 1300); assert_eq!(libc::pthread_mutex_unlock(&mut mutex as *mut _), 0); assert_eq!(libc::pthread_mutex_destroy(&mut mutex as *mut _), 0); assert_eq!(libc::pthread_cond_destroy(&mut cond as *mut _), 0); From 1fecbd8a87238330ad5f8f3c211ba03b19d0c2e8 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 25 May 2020 09:42:08 +0200 Subject: [PATCH 2103/3747] macos does not have pthread_condattr_setclock/getclock --- src/shims/foreign_items/posix.rs | 10 ---------- src/shims/foreign_items/posix/linux.rs | 10 ++++++++++ 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/shims/foreign_items/posix.rs b/src/shims/foreign_items/posix.rs index db2fab526c1f7..1652a3a1b5454 100644 --- a/src/shims/foreign_items/posix.rs +++ b/src/shims/foreign_items/posix.rs @@ -335,16 +335,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let result = this.pthread_condattr_init(attr)?; this.write_scalar(Scalar::from_i32(result), dest)?; } - "pthread_condattr_setclock" => { - let &[attr, clock_id] = check_arg_count(args)?; - let result = this.pthread_condattr_setclock(attr, clock_id)?; - this.write_scalar(Scalar::from_i32(result), dest)?; - } - "pthread_condattr_getclock" => { - let &[attr, clock_id] = check_arg_count(args)?; - let result = this.pthread_condattr_getclock(attr, clock_id)?; - this.write_scalar(Scalar::from_i32(result), dest)?; - } "pthread_condattr_destroy" => { let &[attr] = check_arg_count(args)?; let result = this.pthread_condattr_destroy(attr)?; diff --git a/src/shims/foreign_items/posix/linux.rs b/src/shims/foreign_items/posix/linux.rs index e0f54cac1570a..323418f39ba02 100644 --- a/src/shims/foreign_items/posix/linux.rs +++ b/src/shims/foreign_items/posix/linux.rs @@ -90,6 +90,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let result = this.prctl(option, arg2, arg3, arg4, arg5)?; this.write_scalar(Scalar::from_i32(result), dest)?; } + "pthread_condattr_setclock" => { + let &[attr, clock_id] = check_arg_count(args)?; + let result = this.pthread_condattr_setclock(attr, clock_id)?; + this.write_scalar(Scalar::from_i32(result), dest)?; + } + "pthread_condattr_getclock" => { + let &[attr, clock_id] = check_arg_count(args)?; + let result = this.pthread_condattr_getclock(attr, clock_id)?; + this.write_scalar(Scalar::from_i32(result), dest)?; + } // Dynamically invoked syscalls "syscall" => { From 9ff77f6cb36993026626a6463a6d22bca699a528 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 25 May 2020 09:45:42 +0200 Subject: [PATCH 2104/3747] add an assertion --- src/sync.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/sync.rs b/src/sync.rs index 026542926ed84..107ad5ace1723 100644 --- a/src/sync.rs +++ b/src/sync.rs @@ -238,6 +238,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx match this.machine.threads.sync.rwlocks[id].readers.entry(reader) { Entry::Occupied(mut entry) => { let count = entry.get_mut(); + assert!(*count > 0, "rwlock locked with count == 0"); *count -= 1; if *count == 0 { entry.remove(); From a95f754a9cdd729b525cee2501c98636db6e9c39 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 25 May 2020 10:39:37 +0200 Subject: [PATCH 2105/3747] better error when reading from stdin --- src/shims/foreign_items/posix.rs | 22 ++++++++++++++++------ src/shims/fs.rs | 26 +++++++++++++------------- 2 files changed, 29 insertions(+), 19 deletions(-) diff --git a/src/shims/foreign_items/posix.rs b/src/shims/foreign_items/posix.rs index 1652a3a1b5454..651b619e163d4 100644 --- a/src/shims/foreign_items/posix.rs +++ b/src/shims/foreign_items/posix.rs @@ -62,20 +62,31 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "read" => { let &[fd, buf, count] = check_arg_count(args)?; - let result = this.read(fd, buf, count)?; + let fd = this.read_scalar(fd)?.to_i32()?; + let buf = this.read_scalar(buf)?.not_undef()?; + let count = this.read_scalar(count)?.to_machine_usize(this)?; + let result = if fd == 0 { + throw_unsup_format!("reading from stdin is not implemented") + } else if fd == 1 || fd == 2 { + throw_unsup_format!("cannot read from stdout/stderr") + } else { + this.read(fd, buf, count)? + }; this.write_scalar(Scalar::from_machine_isize(result, this), dest)?; } "write" => { let &[fd, buf, n] = check_arg_count(args)?; let fd = this.read_scalar(fd)?.to_i32()?; let buf = this.read_scalar(buf)?.not_undef()?; - let n = this.read_scalar(n)?.to_machine_usize(this)?; - trace!("Called write({:?}, {:?}, {:?})", fd, buf, n); - let result = if fd == 1 || fd == 2 { + let count = this.read_scalar(n)?.to_machine_usize(this)?; + trace!("Called write({:?}, {:?}, {:?})", fd, buf, count); + let result = if fd == 0 { + throw_unsup_format!("cannot write to stdin") + } else if fd == 1 || fd == 2 { // stdout/stderr use std::io::{self, Write}; - let buf_cont = this.memory.read_bytes(buf, Size::from_bytes(n))?; + let buf_cont = this.memory.read_bytes(buf, Size::from_bytes(count))?; // We need to flush to make sure this actually appears on the screen let res = if fd == 1 { // Stdout is buffered, flush to make sure it appears on the screen. @@ -94,7 +105,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Err(_) => -1, } } else { - let &[fd, buf, count] = check_arg_count(args)?; this.write(fd, buf, count)? }; // Now, `result` is the value we return back to the program. diff --git a/src/shims/fs.rs b/src/shims/fs.rs index 8613f6bb0994e..07360636280f9 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -5,6 +5,8 @@ use std::io::{Read, Seek, SeekFrom, Write}; use std::path::Path; use std::time::SystemTime; +use log::trace; + use rustc_data_structures::fx::FxHashMap; use rustc_target::abi::{Align, LayoutOf, Size}; @@ -413,17 +415,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn read( &mut self, - fd_op: OpTy<'tcx, Tag>, - buf_op: OpTy<'tcx, Tag>, - count_op: OpTy<'tcx, Tag>, + fd: i32, + buf: Scalar, + count: u64, ) -> InterpResult<'tcx, i64> { let this = self.eval_context_mut(); this.check_no_isolation("read")?; + assert!(fd >= 3); - let fd = this.read_scalar(fd_op)?.to_i32()?; - let buf = this.read_scalar(buf_op)?.not_undef()?; - let count = this.read_scalar(count_op)?.to_machine_usize(&*this.tcx)?; + trace!("Reading from FD {}, size {}", fd, count); // Check that the *entire* buffer is actually valid memory. this.memory.check_ptr_access( @@ -437,6 +438,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let count = count.min(this.machine_isize_max() as u64).min(isize::MAX as u64); if let Some(FileHandle { file, writable: _ }) = this.machine.file_handler.handles.get_mut(&fd) { + trace!("read: FD mapped to {:?}", file); // This can never fail because `count` was capped to be smaller than // `isize::MAX`. let count = isize::try_from(count).unwrap(); @@ -461,23 +463,21 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } } else { + trace!("read: FD not found"); this.handle_not_found() } } fn write( &mut self, - fd_op: OpTy<'tcx, Tag>, - buf_op: OpTy<'tcx, Tag>, - count_op: OpTy<'tcx, Tag>, + fd: i32, + buf: Scalar, + count: u64, ) -> InterpResult<'tcx, i64> { let this = self.eval_context_mut(); this.check_no_isolation("write")?; - - let fd = this.read_scalar(fd_op)?.to_i32()?; - let buf = this.read_scalar(buf_op)?.not_undef()?; - let count = this.read_scalar(count_op)?.to_machine_usize(&*this.tcx)?; + assert!(fd >= 3); // Check that the *entire* buffer is actually valid memory. this.memory.check_ptr_access( From 7ba8bbc49fa245f02dbca25fea446a75a4c19150 Mon Sep 17 00:00:00 2001 From: David Cook Date: Sun, 24 May 2020 13:17:16 -0500 Subject: [PATCH 2106/3747] Update comments --- src/shims/fs.rs | 8 +++++--- tests/run-pass/libc.rs | 4 ++-- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/shims/fs.rs b/src/shims/fs.rs index ac405138f5244..66e191e3ed4a1 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -378,9 +378,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } else if this.tcx.sess.target.target.target_os == "macos" && cmd == this.eval_libc_i32("F_FULLFSYNC")? { - // On macOS, fsync does not wait for the underlying disk to finish writing, while this - // F_FULLFSYNC operation does. The standard library uses F_FULLFSYNC for both - // File::sync_data() and File::sync_all(). let &[_, _] = check_arg_count(args)?; if let Some(FileHandle { file, writable: _ }) = this.machine.file_handler.handles.get_mut(&fd) { let result = file.sync_all(); @@ -1118,6 +1115,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } fn fsync(&mut self, fd_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + // On macOS, `fsync` (unlike `fcntl(F_FULLFSYNC)`) does not wait for the + // underlying disk to finish writing. In the interest of host compatibility, + // we conservatively implement this with `sync_all`, which + // *does* wait for the disk. + let this = self.eval_context_mut(); this.check_no_isolation("fsync")?; diff --git a/tests/run-pass/libc.rs b/tests/run-pass/libc.rs index 5897c46f63755..08199c1452d34 100644 --- a/tests/run-pass/libc.rs +++ b/tests/run-pass/libc.rs @@ -47,10 +47,10 @@ fn test_sync_file_range() { use std::os::unix::io::AsRawFd; let path = tmp().join("miri_test_libc_sync_file_range.txt"); - // Cleanup before test + // Cleanup before test. remove_file(&path).ok(); - // Write to a file + // Write to a file. let mut file = File::create(&path).unwrap(); let bytes = b"Hello, World!\n"; file.write(bytes).unwrap(); From 325208247428723f45f2db36c7a1f14f9d558a2b Mon Sep 17 00:00:00 2001 From: David Cook Date: Mon, 25 May 2020 13:20:29 -0500 Subject: [PATCH 2107/3747] Fix test on Windows hosts FlushFileBuffers requires that a file be opened for writing --- tests/run-pass/fs.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/run-pass/fs.rs b/tests/run-pass/fs.rs index d831129dc80fb..a031233d581ab 100644 --- a/tests/run-pass/fs.rs +++ b/tests/run-pass/fs.rs @@ -188,7 +188,7 @@ fn test_file_sync() { let path = prepare_with_content("miri_test_fs_sync.txt", bytes); // Test that we can call sync_data and sync_all (can't readily test effects of this operation) - let file = File::open(&path).unwrap(); + let file = OpenOptions::new().write(true).open(&path).unwrap(); file.sync_data().unwrap(); file.sync_all().unwrap(); From c01bc142194ae294356ac3b5b8666c3c351f14d5 Mon Sep 17 00:00:00 2001 From: David Cook Date: Mon, 25 May 2020 19:50:06 -0500 Subject: [PATCH 2108/3747] Fix fsync shim for Windows hosts with RO files --- src/shims/fs.rs | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/src/shims/fs.rs b/src/shims/fs.rs index 66e191e3ed4a1..7f1c5caaf6427 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -1125,9 +1125,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.check_no_isolation("fsync")?; let fd = this.read_scalar(fd_op)?.to_i32()?; - if let Some(FileHandle { file, writable: _ }) = this.machine.file_handler.handles.get_mut(&fd) { - let result = file.sync_all(); - this.try_unwrap_io_result(result.map(|_| 0i32)) + if let Some(FileHandle { file, writable }) = this.machine.file_handler.handles.get_mut(&fd) { + if !*writable && cfg!(windows) { + // sync_all() will return an error on Windows hosts if the file is not opened for writing. + Ok(0i32) + } else { + let result = file.sync_all(); + this.try_unwrap_io_result(result.map(|_| 0i32)) + } } else { this.handle_not_found() } @@ -1139,9 +1144,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.check_no_isolation("fdatasync")?; let fd = this.read_scalar(fd_op)?.to_i32()?; - if let Some(FileHandle { file, writable: _ }) = this.machine.file_handler.handles.get_mut(&fd) { - let result = file.sync_data(); - this.try_unwrap_io_result(result.map(|_| 0i32)) + if let Some(FileHandle { file, writable }) = this.machine.file_handler.handles.get_mut(&fd) { + if !*writable && cfg!(windows) { + // sync_data() will return an error on Windows hosts if the file is not opened for writing. + Ok(0i32) + } else { + let result = file.sync_data(); + this.try_unwrap_io_result(result.map(|_| 0i32)) + } } else { this.handle_not_found() } From 60f466d6ad235dee5524bb56283fd0d477bf5c89 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 28 May 2020 08:51:38 +0200 Subject: [PATCH 2109/3747] use strip_prefix where it makes sense --- src/bin/miri.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 48e4a60c71f94..ecd232cac5621 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -1,4 +1,5 @@ #![feature(rustc_private)] +#![feature(str_strip)] extern crate rustc_middle; extern crate rustc_driver; @@ -208,7 +209,7 @@ fn main() { if seed.is_some() { panic!("Cannot specify -Zmiri-seed multiple times!"); } - let seed_raw = hex::decode(arg.trim_start_matches("-Zmiri-seed=")) + let seed_raw = hex::decode(arg.strip_prefix("-Zmiri-seed=").unwrap()) .unwrap_or_else(|err| match err { FromHexError::InvalidHexCharacter { .. } => panic!( "-Zmiri-seed should only contain valid hex digits [0-9a-fA-F]" @@ -230,10 +231,10 @@ fn main() { } arg if arg.starts_with("-Zmiri-env-exclude=") => { excluded_env_vars - .push(arg.trim_start_matches("-Zmiri-env-exclude=").to_owned()); + .push(arg.strip_prefix("-Zmiri-env-exclude=").unwrap().to_owned()); } arg if arg.starts_with("-Zmiri-track-pointer-tag=") => { - let id: u64 = match arg.trim_start_matches("-Zmiri-track-pointer-tag=").parse() + let id: u64 = match arg.strip_prefix("-Zmiri-track-pointer-tag=").unwrap().parse() { Ok(id) => id, Err(err) => panic!( @@ -248,7 +249,7 @@ fn main() { } } arg if arg.starts_with("-Zmiri-track-alloc-id=") => { - let id: u64 = match arg.trim_start_matches("-Zmiri-track-alloc-id=").parse() + let id: u64 = match arg.strip_prefix("-Zmiri-track-alloc-id=").unwrap().parse() { Ok(id) => id, Err(err) => panic!( From 0790f75ae4892772583ef637b2fcde31039d8999 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 21 May 2020 11:00:06 +0200 Subject: [PATCH 2110/3747] make cargo-miri a separate crate in a workspace --- Cargo.lock | 18 +++++++++----- Cargo.toml | 29 +++++----------------- cargo-miri/Cargo.toml | 28 +++++++++++++++++++++ src/bin/cargo-miri.rs => cargo-miri/bin.rs | 0 build.rs => cargo-miri/build.rs | 0 miri | 12 +++++---- 6 files changed, 53 insertions(+), 34 deletions(-) create mode 100644 cargo-miri/Cargo.toml rename src/bin/cargo-miri.rs => cargo-miri/bin.rs (100%) rename build.rs => cargo-miri/build.rs (100%) diff --git a/Cargo.lock b/Cargo.lock index 0dbf00e6c5665..23eafaaa6e4ad 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -63,6 +63,18 @@ name = "byteorder" version = "1.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "cargo-miri" +version = "0.1.0" +dependencies = [ + "cargo_metadata 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", + "directories 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-workspace-hack 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.51 (registry+https://github.com/rust-lang/crates.io-index)", + "vergen 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "cargo_metadata" version = "0.9.1" @@ -273,22 +285,16 @@ name = "miri" version = "0.1.0" dependencies = [ "byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "cargo_metadata 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", "colored 1.9.3 (registry+https://github.com/rust-lang/crates.io-index)", "compiletest_rs 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "directories 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", "hex 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-workspace-hack 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.106 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.51 (registry+https://github.com/rust-lang/crates.io-index)", "shell-escape 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "vergen 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 8ccc9484c88b4..6eede5ef464bc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] -authors = ["Scott Olson "] -description = "An experimental interpreter for Rust MIR." +authors = ["Miri Team"] +description = "An experimental interpreter for Rust MIR (core driver)." license = "MIT/Apache-2.0" name = "miri" repository = "https://github.com/rust-lang/miri" @@ -8,6 +8,9 @@ version = "0.1.0" default-run = "miri" edition = "2018" +[workspace] +members = ["cargo-miri"] + [lib] test = true # we have unit tests doctest = false # but no doc tests @@ -17,12 +20,6 @@ name = "miri" test = false # we have no unit tests doctest = false # and no doc tests -[[bin]] -name = "cargo-miri" -test = false # we have no unit tests -doctest = false # and no doc tests -required-features = ["cargo_miri"] - [[bin]] name = "miri-rustc-tests" test = false # we have no unit tests @@ -30,11 +27,6 @@ doctest = false # and no doc tests required-features = ["rustc_tests"] [dependencies] -cargo_metadata = { version = "0.9.0", optional = true } -directories = { version = "2.0", optional = true } -rustc_version = { version = "0.2.3", optional = true } -serde_json = { version = "1.0.40", optional = true } - getrandom = { version = "0.1.8", features = ["std"] } byteorder = "1.3" env_logger = "0.7.1" @@ -48,19 +40,10 @@ rand = "0.7" # for more information. rustc-workspace-hack = "1.0.0" -# Some extra dependency for better feature control to avoid having to rebuild -# between "cargo build" and "cargo intall". -num-traits = "*" -serde = { version = "*", features = ["derive"] } - -[build-dependencies] -vergen = "3" - [dev-dependencies] compiletest_rs = { version = "0.5", features = ["tmp"] } +rustc_version = "0.2.3" colored = "1.6" [features] -default = ["cargo_miri"] -cargo_miri = ["cargo_metadata", "directories", "rustc_version", "serde_json"] rustc_tests = [] diff --git a/cargo-miri/Cargo.toml b/cargo-miri/Cargo.toml new file mode 100644 index 0000000000000..86b2576273d22 --- /dev/null +++ b/cargo-miri/Cargo.toml @@ -0,0 +1,28 @@ +[package] +authors = ["Miri Team"] +description = "An experimental interpreter for Rust MIR (cargo wrapper)." +license = "MIT/Apache-2.0" +name = "cargo-miri" +repository = "https://github.com/rust-lang/miri" +version = "0.1.0" +edition = "2018" + +[[bin]] +name = "cargo-miri" +path = "bin.rs" +test = false # we have no unit tests +doctest = false # and no doc tests + +[dependencies] +cargo_metadata = "0.9.0" +directories = "2.0" +rustc_version = "0.2.3" +serde_json = "1.0.40" + +# A noop dependency that changes in the Rust repository, it's a bit of a hack. +# See the `src/tools/rustc-workspace-hack/README.md` file in `rust-lang/rust` +# for more information. +rustc-workspace-hack = "1.0.0" + +[build-dependencies] +vergen = "3" diff --git a/src/bin/cargo-miri.rs b/cargo-miri/bin.rs similarity index 100% rename from src/bin/cargo-miri.rs rename to cargo-miri/bin.rs diff --git a/build.rs b/cargo-miri/build.rs similarity index 100% rename from build.rs rename to cargo-miri/build.rs diff --git a/miri b/miri index b4d205bd52c55..948a839ef7271 100755 --- a/miri +++ b/miri @@ -59,9 +59,9 @@ fi # Build a sysroot and set MIRI_SYSROOT to use it. Arguments are passed to `cargo miri setup`. build_sysroot() { # Build once, for the user to see. - cargo run $CARGO_BUILD_FLAGS --bin cargo-miri -- miri setup "$@" + cargo run $CARGO_BUILD_FLAGS -p cargo-miri -- miri setup "$@" # Call again, to just set env var. - export MIRI_SYSROOT="$(cargo run $CARGO_BUILD_FLAGS -q --bin cargo-miri -- miri setup --print-sysroot "$@")" + export MIRI_SYSROOT="$(cargo run $CARGO_BUILD_FLAGS -q -p cargo-miri -- miri setup --print-sysroot "$@")" } # Prepare and set MIRI_SYSROOT. Respects `MIRI_TEST_TARGET` and takes into account @@ -104,21 +104,23 @@ case "$COMMAND" in install|install-debug) # "--locked" to respect the Cargo.lock file if it exists, # "--offline" to avoid querying the registry (for yanked packages). - exec cargo install $CARGO_INSTALL_FLAGS --path "$(dirname "$0")" --force --locked --offline "$@" + cargo install $CARGO_INSTALL_FLAGS --path "$(dirname "$0")" --force --locked --offline "$@" + cargo install $CARGO_INSTALL_FLAGS --path "$(dirname "$0")"/cargo-miri --force --locked --offline "$@" ;; check|check-debug) # Check, and let caller control flags. - exec cargo check $CARGO_BUILD_FLAGS "$@" + exec cargo check $CARGO_BUILD_FLAGS --all "$@" ;; build|build-debug) # Build, and let caller control flags. - exec cargo build $CARGO_BUILD_FLAGS "$@" + exec cargo build $CARGO_BUILD_FLAGS --all "$@" ;; test|test-debug) # First build and get a sysroot. cargo build $CARGO_BUILD_FLAGS find_sysroot # Then test, and let caller control flags. + # No `--all` as `cargo-miri` has no tests. exec cargo test $CARGO_BUILD_FLAGS "$@" ;; run|run-debug) From b71fea710cd8be5e34ac0b91ceb4aed6ceaad836 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 21 May 2020 11:23:04 +0200 Subject: [PATCH 2111/3747] just respect existing RUSTFLAGS instead of providing another override --- ci.sh | 2 +- miri | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/ci.sh b/ci.sh index 922469aeca542..8c3fcebe94db9 100755 --- a/ci.sh +++ b/ci.sh @@ -4,7 +4,7 @@ set -euo pipefail # Determine configuration export RUST_TEST_NOCAPTURE=1 export RUST_BACKTRACE=1 -export RUSTC_EXTRA_FLAGS="-D warnings" +export RUSTFLAGS="-D warnings" export CARGO_INCREMENTAL=0 export CARGO_EXTRA_FLAGS="--all-features" diff --git a/miri b/miri index 948a839ef7271..4b6426adb1dc7 100755 --- a/miri +++ b/miri @@ -45,14 +45,14 @@ if ! test -d "$LIBDIR"; then echo "Please report a bug at https://github.com/rust-lang/miri/issues." exit 2 fi -# We set the rpath so that Miri finds the private rustc libraries it needs. -# We enable debug-assertions to get tracing. -# We enable line-only debuginfo for backtraces. -export RUSTFLAGS="-C link-args=-Wl,-rpath,$LIBDIR -C debug-assertions -C debuginfo=1 $RUSTC_EXTRA_FLAGS" if [ -z "$CARGO_INCREMENTAL" ]; then # Default CARGO_INCREMENTAL to 1. export CARGO_INCREMENTAL=1 fi +# We set the rpath so that Miri finds the private rustc libraries it needs. +# We enable debug-assertions to get tracing. +# We enable line-only debuginfo for backtraces. +export RUSTFLAGS="-C link-args=-Wl,-rpath,$LIBDIR -C debug-assertions -C debuginfo=1 $RUSTFLAGS" ## Helper functions From c4c7463aa5af77915041baf0acce4bd29f88029c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 21 May 2020 11:30:37 +0200 Subject: [PATCH 2112/3747] make sure CI fails when we do not recognize the platform --- ci.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ci.sh b/ci.sh index 8c3fcebe94db9..785d7aa5520c0 100755 --- a/ci.sh +++ b/ci.sh @@ -48,4 +48,7 @@ elif [ "${TRAVIS_OS_NAME:-}" == osx ]; then elif [ "${CI_WINDOWS:-}" == True ]; then MIRI_TEST_TARGET=x86_64-unknown-linux-gnu run_tests MIRI_TEST_TARGET=x86_64-apple-darwin run_tests +else + echo "FATAL: unknown CI platform" + exit 1 fi From 254fc50bc14d83c54283220ed39e33ce06241eef Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 21 May 2020 11:32:12 +0200 Subject: [PATCH 2113/3747] fmt --- cargo-miri/bin.rs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index 2e2d4ce956b13..4974ef63f5db6 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -1,12 +1,12 @@ #![feature(inner_deref)] use std::env; +use std::ffi::OsString; use std::fs::{self, File}; use std::io::{self, BufRead, Write}; use std::ops::Not; use std::path::{Path, PathBuf}; use std::process::Command; -use std::ffi::OsString; use rustc_version::VersionMeta; @@ -265,7 +265,8 @@ fn setup(subcommand: MiriCommand) { let sysroot = std::str::from_utf8(&sysroot).unwrap(); let sysroot = Path::new(sysroot.trim_end_matches('\n')); // Check for `$SYSROOT/lib/rustlib/src/rust/src`; test if that contains `libstd/lib.rs`. - let rustup_src = sysroot.join("lib").join("rustlib").join("src").join("rust").join("src"); + let rustup_src = + sysroot.join("lib").join("rustlib").join("src").join("rust").join("src"); if !rustup_src.join("libstd").join("lib.rs").exists() { // Ask the user to install the `rust-src` component, and use that. let mut cmd = Command::new("rustup"); @@ -363,8 +364,7 @@ path = "lib.rs" let sysroot = if target == &host { dir.join("HOST") } else { PathBuf::from(dir) }; std::env::set_var("MIRI_SYSROOT", &sysroot); // pass the env var to the processes we spawn, which will turn it into "--sysroot" flags // Figure out what to print. - let print_sysroot = subcommand == MiriCommand::Setup - && has_arg_flag("--print-sysroot"); // whether we just print the sysroot path + let print_sysroot = subcommand == MiriCommand::Setup && has_arg_flag("--print-sysroot"); // whether we just print the sysroot path if print_sysroot { // Print just the sysroot and nothing else; this way we do not need any escaping. println!("{}", sysroot.display()); @@ -564,6 +564,8 @@ fn main() { // dependencies get dispatched to `rustc`, the final test/binary to `miri`. inside_cargo_rustc(); } else { - show_error(format!("`cargo-miri` must be called with either `miri` or `rustc` as first argument.")) + show_error(format!( + "`cargo-miri` must be called with either `miri` or `rustc` as first argument." + )) } } From 7fcf92dfea6c5ba7cec44fbae5e41ca2f181dcd8 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 21 May 2020 11:21:03 +0200 Subject: [PATCH 2114/3747] re-add some fake dependencies to avoid rebuilds --- Cargo.lock | 2 ++ Cargo.toml | 5 +++++ cargo-miri/Cargo.toml | 4 ++++ 3 files changed, 11 insertions(+) diff --git a/Cargo.lock b/Cargo.lock index 23eafaaa6e4ad..182216b9ec32a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -71,6 +71,7 @@ dependencies = [ "directories 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-workspace-hack 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.106 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 1.0.51 (registry+https://github.com/rust-lang/crates.io-index)", "vergen 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -290,6 +291,7 @@ dependencies = [ "env_logger 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", "getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", "hex 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-workspace-hack 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/Cargo.toml b/Cargo.toml index 6eede5ef464bc..375cb0aa35b07 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -40,6 +40,11 @@ rand = "0.7" # for more information. rustc-workspace-hack = "1.0.0" +# Enable some feature flags that dev-dependencies need but dependencies +# do not. This makes `./miri install` after `./miri build` faster. +[target."cfg(unix)".dependencies] +libc = "0.2" + [dev-dependencies] compiletest_rs = { version = "0.5", features = ["tmp"] } rustc_version = "0.2.3" diff --git a/cargo-miri/Cargo.toml b/cargo-miri/Cargo.toml index 86b2576273d22..d6a98be2bbdfa 100644 --- a/cargo-miri/Cargo.toml +++ b/cargo-miri/Cargo.toml @@ -24,5 +24,9 @@ serde_json = "1.0.40" # for more information. rustc-workspace-hack = "1.0.0" +# Enable some feature flags that dev-dependencies need but dependencies +# do not. This makes `./miri install` after `./miri build` faster. +serde = { version = "*", features = ["derive"] } + [build-dependencies] vergen = "3" From 35964b10b0d4fadfdb921cc8a3f24a90ba8b50b3 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 21 May 2020 14:18:18 +0200 Subject: [PATCH 2115/3747] no workspace as that is incompatible with the rustc submodule --- Cargo.lock | 93 ----------- Cargo.toml | 3 - cargo-miri/Cargo.lock | 351 ++++++++++++++++++++++++++++++++++++++++++ miri | 16 +- 4 files changed, 362 insertions(+), 101 deletions(-) create mode 100644 cargo-miri/Cargo.lock diff --git a/Cargo.lock b/Cargo.lock index 182216b9ec32a..f68a6133be57e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -43,11 +43,6 @@ name = "base64" version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "bitflags" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "blake2b_simd" version = "0.5.10" @@ -63,45 +58,11 @@ name = "byteorder" version = "1.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "cargo-miri" -version = "0.1.0" -dependencies = [ - "cargo_metadata 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", - "directories 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-workspace-hack 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.106 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.51 (registry+https://github.com/rust-lang/crates.io-index)", - "vergen 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "cargo_metadata" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.106 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.106 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.51 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "cfg-if" version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "chrono" -version = "0.4.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "num-integer 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", - "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "colored" version = "1.9.3" @@ -153,15 +114,6 @@ name = "diff" version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "directories" -version = "2.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "dirs-sys 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "dirs" version = "2.0.2" @@ -299,23 +251,6 @@ dependencies = [ "shell-escape 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "num-integer" -version = "0.1.42" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "num-traits 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "num-traits" -version = "0.2.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "ppv-lite86" version = "0.2.6" @@ -464,7 +399,6 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.106 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -574,16 +508,6 @@ dependencies = [ "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "time" -version = "0.1.42" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "unicode-width" version = "0.1.7" @@ -594,15 +518,6 @@ name = "unicode-xid" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "vergen" -version = "3.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "chrono 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "wasi" version = "0.9.0+wasi-snapshot-preview1" @@ -643,18 +558,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" "checksum autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d" "checksum base64 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b41b7ea54a0c9d92199de89e20e58d49f02f8e699814ef3fdf266f6f748d15c7" -"checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" "checksum blake2b_simd 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)" = "d8fb2d74254a3a0b5cac33ac9f8ed0e44aa50378d9dbb2e5d83bd21ed1dc2c8a" "checksum byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de" -"checksum cargo_metadata 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "46e3374c604fb39d1a2f35ed5e4a4e30e60d01fab49446e08f1b3e9a90aef202" "checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" -"checksum chrono 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)" = "80094f509cf8b5ae86a4966a39b3ff66cd7e2a3e594accec3743ff3fabeab5b2" "checksum colored 1.9.3 (registry+https://github.com/rust-lang/crates.io-index)" = "f4ffc801dacf156c5854b9df4f425a626539c3a6ef7893cc0c5084a23f0b6c59" "checksum compiletest_rs 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9f737835bfbbe29ed1ff82d5137520338d7ed5bf1a1d4b9c1c7c58bb45b8fa29" "checksum constant_time_eq 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" "checksum crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8" "checksum diff 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "0e25ea47919b1560c4e3b7fe0aaab9becf5b84a10325ddf7db0f0ba5e1026499" -"checksum directories 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "551a778172a450d7fc12e629ca3b0428d00f6afa9a43da1b630d54604e97371c" "checksum dirs 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "13aea89a5c93364a98e9b37b2fa237effbb694d5cfe01c5b70941f7eb087d5e3" "checksum dirs-sys 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "afa0b23de8fd801745c471deffa6e12d248f962c9fd4b4c33787b055599bde7b" "checksum env_logger 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "44533bbbb3bb3c1fa17d9f2e4e38bbbaf8396ba82193c4cb1b6445d711445d36" @@ -670,8 +581,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7" "checksum memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3728d817d99e5ac407411fa471ff9800a778d88a24685968b36824eaf4bee400" "checksum miow 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "396aa0f2003d7df8395cb93e09871561ccc3e785f0acb369170e8cc74ddf9226" -"checksum num-integer 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "3f6ea62e9d81a77cd3ee9a2a5b9b609447857f3d358704331e4ef39eb247fcba" -"checksum num-traits 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "c62be47e61d1842b9170f0fdeec8eba98e60e90e5446449a0545e5152acd7096" "checksum ppv-lite86 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "74490b50b9fbe561ac330df47c08f3f33073d2d00c150f719147d7c54522fa1b" "checksum proc-macro2 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)" = "df246d292ff63439fea9bc8c0a270bed0e390d5ebd4db4ba15aba81111b5abe3" "checksum quick-error 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" @@ -703,10 +612,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum termcolor 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb6bfa289a4d7c5766392812c0a1f4c1ba45afa1ad47803c11e1f407d846d75f" "checksum tester 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee72ec31009a42b53de9a6b7d8f462b493ab3b1e4767bda1fcdbb52127f13b6c" "checksum thread_local 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d40c6d1b69745a6ec6fb1ca717914848da4b44ae29d9b3080cbee91d72a69b14" -"checksum time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f" "checksum unicode-width 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "caaa9d531767d1ff2150b9332433f32a24622147e5ebb1f26409d5da67afd479" "checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" -"checksum vergen 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4ce50d8996df1f85af15f2cd8d33daae6e479575123ef4314a51a70a230739cb" "checksum wasi 0.9.0+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)" = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" "checksum winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6" "checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" diff --git a/Cargo.toml b/Cargo.toml index 375cb0aa35b07..c33008e48a790 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,9 +8,6 @@ version = "0.1.0" default-run = "miri" edition = "2018" -[workspace] -members = ["cargo-miri"] - [lib] test = true # we have unit tests doctest = false # but no doc tests diff --git a/cargo-miri/Cargo.lock b/cargo-miri/Cargo.lock new file mode 100644 index 0000000000000..c6d80add07878 --- /dev/null +++ b/cargo-miri/Cargo.lock @@ -0,0 +1,351 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "arrayref" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544" + +[[package]] +name = "arrayvec" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cff77d8686867eceff3105329d4698d96c2391c176d5d03adc90c7389162b5b8" + +[[package]] +name = "autocfg" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d" + +[[package]] +name = "base64" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b41b7ea54a0c9d92199de89e20e58d49f02f8e699814ef3fdf266f6f748d15c7" + +[[package]] +name = "bitflags" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" + +[[package]] +name = "blake2b_simd" +version = "0.5.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8fb2d74254a3a0b5cac33ac9f8ed0e44aa50378d9dbb2e5d83bd21ed1dc2c8a" +dependencies = [ + "arrayref", + "arrayvec", + "constant_time_eq", +] + +[[package]] +name = "cargo-miri" +version = "0.1.0" +dependencies = [ + "cargo_metadata", + "directories", + "rustc-workspace-hack", + "rustc_version", + "serde", + "serde_json", + "vergen", +] + +[[package]] +name = "cargo_metadata" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46e3374c604fb39d1a2f35ed5e4a4e30e60d01fab49446e08f1b3e9a90aef202" +dependencies = [ + "semver", + "serde", + "serde_derive", + "serde_json", +] + +[[package]] +name = "cfg-if" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" + +[[package]] +name = "chrono" +version = "0.4.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80094f509cf8b5ae86a4966a39b3ff66cd7e2a3e594accec3743ff3fabeab5b2" +dependencies = [ + "num-integer", + "num-traits", + "time", +] + +[[package]] +name = "constant_time_eq" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" + +[[package]] +name = "crossbeam-utils" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8" +dependencies = [ + "autocfg", + "cfg-if", + "lazy_static", +] + +[[package]] +name = "directories" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "551a778172a450d7fc12e629ca3b0428d00f6afa9a43da1b630d54604e97371c" +dependencies = [ + "cfg-if", + "dirs-sys", +] + +[[package]] +name = "dirs-sys" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "afa0b23de8fd801745c471deffa6e12d248f962c9fd4b4c33787b055599bde7b" +dependencies = [ + "cfg-if", + "libc", + "redox_users", + "winapi", +] + +[[package]] +name = "getrandom" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7abc8dd8451921606d809ba32e95b6111925cd2906060d2dcc29c070220503eb" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "itoa" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8b7a7c0c47db5545ed3fef7468ee7bb5b74691498139e4b3f6a20685dc6dd8e" + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "libc" +version = "0.2.70" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3baa92041a6fec78c687fa0cc2b3fae8884f743d672cf551bed1d6dac6988d0f" + +[[package]] +name = "num-integer" +version = "0.1.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f6ea62e9d81a77cd3ee9a2a5b9b609447857f3d358704331e4ef39eb247fcba" +dependencies = [ + "autocfg", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c62be47e61d1842b9170f0fdeec8eba98e60e90e5446449a0545e5152acd7096" +dependencies = [ + "autocfg", +] + +[[package]] +name = "proc-macro2" +version = "1.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53f5ffe53a6b28e37c9c1ce74893477864d64f74778a93a4beb43c8fa167f639" +dependencies = [ + "unicode-xid", +] + +[[package]] +name = "quote" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54a21852a652ad6f610c9510194f398ff6f8692e334fd1145fed931f7fbe44ea" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "redox_syscall" +version = "0.1.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84" + +[[package]] +name = "redox_users" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09b23093265f8d200fa7b4c2c76297f47e681c655f6f1285a8780d6a022f7431" +dependencies = [ + "getrandom", + "redox_syscall", + "rust-argon2", +] + +[[package]] +name = "rust-argon2" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bc8af4bda8e1ff4932523b94d3dd20ee30a87232323eda55903ffd71d2fb017" +dependencies = [ + "base64", + "blake2b_simd", + "constant_time_eq", + "crossbeam-utils", +] + +[[package]] +name = "rustc-workspace-hack" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc71d2faa173b74b232dedc235e3ee1696581bb132fc116fa3626d6151a1a8fb" + +[[package]] +name = "rustc_version" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" +dependencies = [ + "semver", +] + +[[package]] +name = "ryu" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed3d612bc64430efeb3f7ee6ef26d590dce0c43249217bddc62112540c7941e1" + +[[package]] +name = "semver" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" +dependencies = [ + "semver-parser", + "serde", +] + +[[package]] +name = "semver-parser" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" + +[[package]] +name = "serde" +version = "1.0.110" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99e7b308464d16b56eba9964e4972a3eee817760ab60d88c3f86e1fecb08204c" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.110" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "818fbf6bfa9a42d3bfcaca148547aa00c7b915bec71d1757aa2d44ca68771984" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.53" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "993948e75b189211a9b31a7528f950c6adc21f9720b6438ff80a7fa2f864cea2" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "syn" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95b5f192649e48a5302a13f2feb224df883b98933222369e4b3b0fe2a5447269" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + +[[package]] +name = "time" +version = "0.1.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca8a50ef2360fbd1eeb0ecd46795a87a19024eb4b53c5dc916ca1fd95fe62438" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "unicode-xid" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" + +[[package]] +name = "vergen" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ce50d8996df1f85af15f2cd8d33daae6e479575123ef4314a51a70a230739cb" +dependencies = [ + "bitflags", + "chrono", +] + +[[package]] +name = "wasi" +version = "0.9.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" + +[[package]] +name = "winapi" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/miri b/miri index 4b6426adb1dc7..237a53efb1ad1 100755 --- a/miri +++ b/miri @@ -49,6 +49,10 @@ if [ -z "$CARGO_INCREMENTAL" ]; then # Default CARGO_INCREMENTAL to 1. export CARGO_INCREMENTAL=1 fi +if [ -z "$CARGO_TARGET_DIR" ]; then + # Share target dir between `miri` and `cargo-miri`. + export CARGO_TARGET_DIR="$(dirname "$0")"/target +fi # We set the rpath so that Miri finds the private rustc libraries it needs. # We enable debug-assertions to get tracing. # We enable line-only debuginfo for backtraces. @@ -59,9 +63,9 @@ export RUSTFLAGS="-C link-args=-Wl,-rpath,$LIBDIR -C debug-assertions -C debugin # Build a sysroot and set MIRI_SYSROOT to use it. Arguments are passed to `cargo miri setup`. build_sysroot() { # Build once, for the user to see. - cargo run $CARGO_BUILD_FLAGS -p cargo-miri -- miri setup "$@" + cargo run $CARGO_BUILD_FLAGS --manifest-path "$(dirname "$0")"/cargo-miri/Cargo.toml -- miri setup "$@" # Call again, to just set env var. - export MIRI_SYSROOT="$(cargo run $CARGO_BUILD_FLAGS -q -p cargo-miri -- miri setup --print-sysroot "$@")" + export MIRI_SYSROOT="$(cargo run $CARGO_BUILD_FLAGS --manifest-path "$(dirname "$0")"/cargo-miri/Cargo.toml -q -- miri setup --print-sysroot "$@")" } # Prepare and set MIRI_SYSROOT. Respects `MIRI_TEST_TARGET` and takes into account @@ -109,18 +113,20 @@ install|install-debug) ;; check|check-debug) # Check, and let caller control flags. - exec cargo check $CARGO_BUILD_FLAGS --all "$@" + cargo check $CARGO_BUILD_FLAGS --manifest-path "$(dirname "$0")"/Cargo.toml "$@" + cargo check $CARGO_BUILD_FLAGS --manifest-path "$(dirname "$0")"/cargo-miri/Cargo.toml "$@" ;; build|build-debug) # Build, and let caller control flags. - exec cargo build $CARGO_BUILD_FLAGS --all "$@" + cargo build $CARGO_BUILD_FLAGS --manifest-path "$(dirname "$0")"/Cargo.toml "$@" + cargo build $CARGO_BUILD_FLAGS --manifest-path "$(dirname "$0")"/cargo-miri/Cargo.toml "$@" ;; test|test-debug) # First build and get a sysroot. cargo build $CARGO_BUILD_FLAGS find_sysroot # Then test, and let caller control flags. - # No `--all` as `cargo-miri` has no tests. + # Only in root project as `cargo-miri` has no tests. exec cargo test $CARGO_BUILD_FLAGS "$@" ;; run|run-debug) From ac454a248524b8b273b17337e3d59a45772f357f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 21 May 2020 14:24:41 +0200 Subject: [PATCH 2116/3747] cargo-miri: allow overwriting miri command, and make that consistent with compiletest --- cargo-miri/bin.rs | 3 +++ tests/compiletest.rs | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index 4974ef63f5db6..197552a4b1266 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -94,6 +94,9 @@ fn get_arg_flag_value(name: &str) -> Option { /// Returns the path to the `miri` binary fn find_miri() -> PathBuf { + if let Some(path) = env::var_os("MIRI") { + return path.into(); + } let mut path = std::env::current_exe().expect("current executable path invalid"); path.set_file_name("miri"); path diff --git a/tests/compiletest.rs b/tests/compiletest.rs index 2be0661b93ee0..a64f0edb94645 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -9,7 +9,7 @@ use colored::*; use compiletest_rs as compiletest; fn miri_path() -> PathBuf { - PathBuf::from(option_env!("MIRI_PATH").unwrap_or(env!("CARGO_BIN_EXE_miri"))) + PathBuf::from(option_env!("MIRI").unwrap_or(env!("CARGO_BIN_EXE_miri"))) } fn run_tests(mode: &str, path: &str, target: &str) { From 229784ba624f6d018abb7c1fcb18d5b4387f72a3 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 28 May 2020 09:19:01 +0200 Subject: [PATCH 2117/3747] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 4275de5f8cbbb..a2f999a91cafe 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -7726070fa755f660b5da3f82f46e07d9c6866f69 +45127211566c53bac386b66909a830649182ab7a From f55c0153f1f259032fe6eda8bce036993da3a932 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 29 May 2020 10:01:07 +0200 Subject: [PATCH 2118/3747] str_strip is stable --- rust-version | 2 +- src/bin/miri.rs | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/rust-version b/rust-version index a2f999a91cafe..73f017b8d2c62 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -45127211566c53bac386b66909a830649182ab7a +255c0338dc0b02f833fb1a816d76febd50c399c4 diff --git a/src/bin/miri.rs b/src/bin/miri.rs index ecd232cac5621..41490531a78bf 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -1,5 +1,4 @@ #![feature(rustc_private)] -#![feature(str_strip)] extern crate rustc_middle; extern crate rustc_driver; From 394a57fc22d061c943985c741cca6cb5694586c5 Mon Sep 17 00:00:00 2001 From: Joe Richey Date: Fri, 15 May 2020 01:44:41 -0700 Subject: [PATCH 2119/3747] Remove pointer arithmetic intrinsics These are now implemented in rustc's mir interpreter Signed-off-by: Joe Richey --- src/operator.rs | 46 +---------------------------------------- src/shims/intrinsics.rs | 20 ------------------ 2 files changed, 1 insertion(+), 65 deletions(-) diff --git a/src/operator.rs b/src/operator.rs index a28a0098e92e9..bfc8e908dc15b 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -1,9 +1,6 @@ -use std::convert::TryFrom; - use log::trace; use rustc_middle::{mir, ty::Ty}; -use rustc_target::abi::{LayoutOf, Size}; use crate::*; @@ -16,13 +13,6 @@ pub trait EvalContextExt<'tcx> { ) -> InterpResult<'tcx, (Scalar, bool, Ty<'tcx>)>; fn ptr_eq(&self, left: Scalar, right: Scalar) -> InterpResult<'tcx, bool>; - - fn pointer_offset_inbounds( - &self, - ptr: Scalar, - pointee_ty: Ty<'tcx>, - offset: i64, - ) -> InterpResult<'tcx, Scalar>; } impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { @@ -71,7 +61,7 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { Offset => { let pointee_ty = left.layout.ty.builtin_deref(true).expect("Offset called on non-ptr type").ty; - let ptr = self.pointer_offset_inbounds( + let ptr = self.ptr_offset_inbounds( left.to_scalar()?, pointee_ty, right.to_scalar()?.to_machine_isize(self)?, @@ -91,38 +81,4 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { let right = self.force_bits(right, size)?; Ok(left == right) } - - /// Raises an error if the offset moves the pointer outside of its allocation. - /// For integers, we consider each of them their own tiny allocation of size 0, - /// so offset-by-0 is okay for them -- except for NULL, which we rule out entirely. - fn pointer_offset_inbounds( - &self, - ptr: Scalar, - pointee_ty: Ty<'tcx>, - offset: i64, - ) -> InterpResult<'tcx, Scalar> { - let pointee_size = i64::try_from(self.layout_of(pointee_ty)?.size.bytes()).unwrap(); - let offset = offset.checked_mul(pointee_size).ok_or_else(|| { - err_ub_format!("overflow during offset comutation for inbounds pointer arithmetic") - })?; - // We do this first, to rule out overflows. - let offset_ptr = ptr.ptr_signed_offset(offset, self)?; - // What we need to check is that starting at `min(ptr, offset_ptr)`, - // we could do an access of size `abs(offset)`. Alignment does not matter. - let (min_ptr, abs_offset) = if offset >= 0 { - (ptr, u64::try_from(offset).unwrap()) - } else { - // Negative offset. - // If the negation overflows, the result will be negative so the try_from will fail. - (offset_ptr, u64::try_from(-offset).unwrap()) - }; - self.memory.check_ptr_access_align( - min_ptr, - Size::from_bytes(abs_offset), - None, - CheckInAllocMsg::InboundsTest, - )?; - // That's it! - Ok(offset_ptr) - } } diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 1a8c9163211a8..ec86e878ec607 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -101,26 +101,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx .write_bytes(ptr, iter::repeat(val_byte).take(byte_count.bytes() as usize))?; } - // Pointer arithmetic - "arith_offset" => { - let &[ptr, offset] = check_arg_count(args)?; - let ptr = this.read_scalar(ptr)?.not_undef()?; - let offset = this.read_scalar(offset)?.to_machine_isize(this)?; - - let pointee_ty = substs.type_at(0); - let pointee_size = i64::try_from(this.layout_of(pointee_ty)?.size.bytes()).unwrap(); - let offset = offset.overflowing_mul(pointee_size).0; - let result_ptr = ptr.ptr_wrapping_signed_offset(offset, this); - this.write_scalar(result_ptr, dest)?; - } - "offset" => { - let &[ptr, offset] = check_arg_count(args)?; - let ptr = this.read_scalar(ptr)?.not_undef()?; - let offset = this.read_scalar(offset)?.to_machine_isize(this)?; - let result_ptr = this.pointer_offset_inbounds(ptr, substs.type_at(0), offset)?; - this.write_scalar(result_ptr, dest)?; - } - // Floating-point operations #[rustfmt::skip] | "sinf32" From c77e9022d5d75a2d273b39f0539bfbf52d0ba6e6 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 30 May 2020 09:14:56 +0200 Subject: [PATCH 2120/3747] rustup (and account for stabilization) --- rust-version | 2 +- src/shims/intrinsics.rs | 1 - tests/compile-fail/rc_as_ptr.rs | 1 - tests/run-pass/rc.rs | 1 - 4 files changed, 1 insertion(+), 4 deletions(-) diff --git a/rust-version b/rust-version index 73f017b8d2c62..0124f254ec1ea 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -255c0338dc0b02f833fb1a816d76febd50c399c4 +0e9e4083100aa3ebf09b8f1ace0348cb37475eb9 diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index ec86e878ec607..c16fbc278c8d8 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -1,5 +1,4 @@ use std::iter; -use std::convert::TryFrom; use rustc_attr as attr; use rustc_ast::ast::FloatTy; diff --git a/tests/compile-fail/rc_as_ptr.rs b/tests/compile-fail/rc_as_ptr.rs index 0b98c7d2bba3d..1a9c322ac8d06 100644 --- a/tests/compile-fail/rc_as_ptr.rs +++ b/tests/compile-fail/rc_as_ptr.rs @@ -1,6 +1,5 @@ // This should fail even without validation // compile-flags: -Zmiri-disable-validation -#![feature(weak_into_raw)] use std::rc::{Rc, Weak}; use std::ptr; diff --git a/tests/run-pass/rc.rs b/tests/run-pass/rc.rs index 9ab460c961651..3dc61fe1f00d5 100644 --- a/tests/run-pass/rc.rs +++ b/tests/run-pass/rc.rs @@ -1,4 +1,3 @@ -#![feature(weak_into_raw)] #![feature(new_uninit)] #![feature(get_mut_unchecked)] From 7589bc7ba92df64cbf3cab214724a6d500a0e2b3 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 30 May 2020 22:29:27 +0200 Subject: [PATCH 2121/3747] sync cleanup: mark infallible ops as such; consistent combine en/dequeue with (un)block; comments --- src/shims/foreign_items/posix.rs | 4 +- src/shims/foreign_items/posix/macos.rs | 2 +- src/shims/foreign_items/windows.rs | 8 ++-- src/shims/sync.rs | 60 +++++++++++++------------- src/shims/thread.rs | 16 +++---- src/shims/tls.rs | 18 ++++---- src/sync.rs | 54 ++++++++++++++--------- src/thread.rs | 52 +++++++++++----------- 8 files changed, 110 insertions(+), 104 deletions(-) diff --git a/src/shims/foreign_items/posix.rs b/src/shims/foreign_items/posix.rs index 651b619e163d4..77f0c5b9fbd61 100644 --- a/src/shims/foreign_items/posix.rs +++ b/src/shims/foreign_items/posix.rs @@ -254,14 +254,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "pthread_getspecific" => { let &[key] = check_arg_count(args)?; let key = this.force_bits(this.read_scalar(key)?.not_undef()?, key.layout.size)?; - let active_thread = this.get_active_thread()?; + let active_thread = this.get_active_thread(); let ptr = this.machine.tls.load_tls(key, active_thread, this)?; this.write_scalar(ptr, dest)?; } "pthread_setspecific" => { let &[key, new_ptr] = check_arg_count(args)?; let key = this.force_bits(this.read_scalar(key)?.not_undef()?, key.layout.size)?; - let active_thread = this.get_active_thread()?; + let active_thread = this.get_active_thread(); let new_ptr = this.read_scalar(new_ptr)?.not_undef()?; this.machine.tls.store_tls(key, active_thread, this.test_null(new_ptr)?)?; diff --git a/src/shims/foreign_items/posix/macos.rs b/src/shims/foreign_items/posix/macos.rs index e6d39af453958..fb50e4d918173 100644 --- a/src/shims/foreign_items/posix/macos.rs +++ b/src/shims/foreign_items/posix/macos.rs @@ -98,7 +98,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let dtor = this.read_scalar(dtor)?.not_undef()?; let dtor = this.memory.get_fn(dtor)?.as_instance()?; let data = this.read_scalar(data)?.not_undef()?; - let active_thread = this.get_active_thread()?; + let active_thread = this.get_active_thread(); this.machine.tls.set_macos_thread_dtor(active_thread, dtor, data)?; } diff --git a/src/shims/foreign_items/windows.rs b/src/shims/foreign_items/windows.rs index c24824153ca24..2a30a23489970 100644 --- a/src/shims/foreign_items/windows.rs +++ b/src/shims/foreign_items/windows.rs @@ -163,14 +163,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "TlsGetValue" => { let &[key] = check_arg_count(args)?; let key = u128::from(this.read_scalar(key)?.to_u32()?); - let active_thread = this.get_active_thread()?; + let active_thread = this.get_active_thread(); let ptr = this.machine.tls.load_tls(key, active_thread, this)?; this.write_scalar(ptr, dest)?; } "TlsSetValue" => { let &[key, new_ptr] = check_arg_count(args)?; let key = u128::from(this.read_scalar(key)?.to_u32()?); - let active_thread = this.get_active_thread()?; + let active_thread = this.get_active_thread(); let new_ptr = this.read_scalar(new_ptr)?.not_undef()?; this.machine.tls.store_tls(key, active_thread, this.test_null(new_ptr)?)?; @@ -291,7 +291,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if this.frame().instance.to_string().starts_with("std::sys::windows::") => { #[allow(non_snake_case)] let &[_lpCriticalSection] = check_arg_count(args)?; - assert_eq!(this.get_total_thread_count()?, 1, "concurrency on Windows not supported"); + assert_eq!(this.get_total_thread_count(), 1, "concurrency on Windows not supported"); // Nothing to do, not even a return value. // (Windows locks are reentrant, and we have only 1 thread, // so not doing any futher checks here is at least not incorrect.) @@ -300,7 +300,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if this.frame().instance.to_string().starts_with("std::sys::windows::") => { #[allow(non_snake_case)] let &[_lpCriticalSection] = check_arg_count(args)?; - assert_eq!(this.get_total_thread_count()?, 1, "concurrency on Windows not supported"); + assert_eq!(this.get_total_thread_count(), 1, "concurrency on Windows not supported"); // There is only one thread, so this always succeeds and returns TRUE this.write_scalar(Scalar::from_i32(1), dest)?; } diff --git a/src/shims/sync.rs b/src/shims/sync.rs index 5b0de43e54669..01c7b4a1eb4fa 100644 --- a/src/shims/sync.rs +++ b/src/shims/sync.rs @@ -284,15 +284,16 @@ fn reacquire_cond_mutex<'mir, 'tcx: 'mir>( thread: ThreadId, mutex: MutexId, ) -> InterpResult<'tcx> { + ecx.unblock_thread(thread); if ecx.mutex_is_locked(mutex) { - ecx.mutex_enqueue(mutex, thread); + ecx.mutex_enqueue_and_block(mutex, thread); } else { ecx.mutex_lock(mutex, thread); - ecx.unblock_thread(thread)?; } Ok(()) } +/// After a thread waiting on a condvar was signalled: /// Reacquire the conditional variable and remove the timeout callback if any /// was registered. fn post_cond_signal<'mir, 'tcx: 'mir>( @@ -303,12 +304,13 @@ fn post_cond_signal<'mir, 'tcx: 'mir>( reacquire_cond_mutex(ecx, thread, mutex)?; // Waiting for the mutex is not included in the waiting time because we need // to acquire the mutex always even if we get a timeout. - ecx.unregister_timeout_callback_if_exists(thread) + ecx.unregister_timeout_callback_if_exists(thread); + Ok(()) } /// Release the mutex associated with the condition variable because we are /// entering the waiting state. -fn release_cond_mutex<'mir, 'tcx: 'mir>( +fn release_cond_mutex_and_block<'mir, 'tcx: 'mir>( ecx: &mut MiriEvalContext<'mir, 'tcx>, active_thread: ThreadId, mutex: MutexId, @@ -320,7 +322,7 @@ fn release_cond_mutex<'mir, 'tcx: 'mir>( } else { throw_ub_format!("awaiting on unlocked or owned by a different thread mutex"); } - ecx.block_thread(active_thread)?; + ecx.block_thread(active_thread); Ok(()) } @@ -411,14 +413,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let kind = mutex_get_kind(this, mutex_op)?.not_undef()?; let id = mutex_get_or_create_id(this, mutex_op)?; - let active_thread = this.get_active_thread()?; + let active_thread = this.get_active_thread(); if this.mutex_is_locked(id) { let owner_thread = this.mutex_get_owner(id); if owner_thread != active_thread { - // Block the active thread. - this.block_thread(active_thread)?; - this.mutex_enqueue(id, active_thread); + // Enqueue the active thread. + this.mutex_enqueue_and_block(id, active_thread); Ok(0) } else { // Trying to acquire the same mutex again. @@ -449,7 +450,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let kind = mutex_get_kind(this, mutex_op)?.not_undef()?; let id = mutex_get_or_create_id(this, mutex_op)?; - let active_thread = this.get_active_thread()?; + let active_thread = this.get_active_thread(); if this.mutex_is_locked(id) { let owner_thread = this.mutex_get_owner(id); @@ -482,7 +483,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let kind = mutex_get_kind(this, mutex_op)?.not_undef()?; let id = mutex_get_or_create_id(this, mutex_op)?; - let active_thread = this.get_active_thread()?; + let active_thread = this.get_active_thread(); if let Some(_old_locked_count) = this.mutex_unlock(id, active_thread)? { // The mutex was locked by the current thread. @@ -528,10 +529,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); let id = rwlock_get_or_create_id(this, rwlock_op)?; - let active_thread = this.get_active_thread()?; + let active_thread = this.get_active_thread(); if this.rwlock_is_write_locked(id) { - this.rwlock_enqueue_and_block_reader(id, active_thread)?; + this.rwlock_enqueue_and_block_reader(id, active_thread); Ok(0) } else { this.rwlock_reader_lock(id, active_thread); @@ -543,7 +544,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); let id = rwlock_get_or_create_id(this, rwlock_op)?; - let active_thread = this.get_active_thread()?; + let active_thread = this.get_active_thread(); if this.rwlock_is_write_locked(id) { this.eval_libc_i32("EBUSY") @@ -557,7 +558,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); let id = rwlock_get_or_create_id(this, rwlock_op)?; - let active_thread = this.get_active_thread()?; + let active_thread = this.get_active_thread(); if this.rwlock_is_locked(id) { // Note: this will deadlock if the lock is already locked by this @@ -565,14 +566,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // // Relevant documentation: // https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_rwlock_wrlock.html - // An in depth discussion on this topic: + // An in-depth discussion on this topic: // https://github.com/rust-lang/rust/issues/53127 // // FIXME: Detect and report the deadlock proactively. (We currently // report the deadlock only when no thread can continue execution, // but we could detect that this lock is already locked and report // an error.) - this.rwlock_enqueue_and_block_writer(id, active_thread)?; + this.rwlock_enqueue_and_block_writer(id, active_thread); } else { this.rwlock_writer_lock(id, active_thread); } @@ -584,7 +585,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); let id = rwlock_get_or_create_id(this, rwlock_op)?; - let active_thread = this.get_active_thread()?; + let active_thread = this.get_active_thread(); if this.rwlock_is_locked(id) { this.eval_libc_i32("EBUSY") @@ -598,15 +599,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); let id = rwlock_get_or_create_id(this, rwlock_op)?; - let active_thread = this.get_active_thread()?; + let active_thread = this.get_active_thread(); if this.rwlock_reader_unlock(id, active_thread) { // The thread was a reader. if this.rwlock_is_locked(id) { // No more readers owning the lock. Give it to a writer if there // is any. - if let Some(writer) = this.rwlock_dequeue_writer(id) { - this.unblock_thread(writer)?; + if let Some(writer) = this.rwlock_dequeue_and_unblock_writer(id) { this.rwlock_writer_lock(id, writer); } } @@ -617,14 +617,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // We are prioritizing writers here against the readers. As a // result, not only readers can starve writers, but also writers can // starve readers. - if let Some(writer) = this.rwlock_dequeue_writer(id) { + if let Some(writer) = this.rwlock_dequeue_and_unblock_writer(id) { // Give the lock to another writer. - this.unblock_thread(writer)?; this.rwlock_writer_lock(id, writer); } else { // Give the lock to all readers. - while let Some(reader) = this.rwlock_dequeue_reader(id) { - this.unblock_thread(reader)?; + while let Some(reader) = this.rwlock_dequeue_and_unblock_reader(id) { this.rwlock_reader_lock(id, reader); } } @@ -753,9 +751,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let id = cond_get_or_create_id(this, cond_op)?; let mutex_id = mutex_get_or_create_id(this, mutex_op)?; - let active_thread = this.get_active_thread()?; + let active_thread = this.get_active_thread(); - release_cond_mutex(this, active_thread, mutex_id)?; + release_cond_mutex_and_block(this, active_thread, mutex_id)?; this.condvar_wait(id, active_thread, mutex_id); Ok(0) @@ -774,9 +772,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let id = cond_get_or_create_id(this, cond_op)?; let mutex_id = mutex_get_or_create_id(this, mutex_op)?; - let active_thread = this.get_active_thread()?; + let active_thread = this.get_active_thread(); - release_cond_mutex(this, active_thread, mutex_id)?; + release_cond_mutex_and_block(this, active_thread, mutex_id)?; this.condvar_wait(id, active_thread, mutex_id); // We return success for now and override it in the timeout callback. @@ -823,7 +821,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(()) }), - )?; + ); Ok(()) } @@ -833,7 +831,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let id = cond_get_or_create_id(this, cond_op)?; if this.condvar_is_awaited(id) { - throw_ub_format!("destroyed an awaited conditional variable"); + throw_ub_format!("destroying an awaited conditional variable"); } cond_set_id(this, cond_op, ScalarMaybeUninit::Uninit)?; cond_set_clock_id(this, cond_op, ScalarMaybeUninit::Uninit)?; diff --git a/src/shims/thread.rs b/src/shims/thread.rs index 3ea1ee0aa17d2..e5d3a9f0d6f87 100644 --- a/src/shims/thread.rs +++ b/src/shims/thread.rs @@ -19,9 +19,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx For example, Miri does not detect data races yet.", ); - let new_thread_id = this.create_thread()?; + let new_thread_id = this.create_thread(); // Also switch to new thread so that we can push the first stackframe. - let old_thread_id = this.set_active_thread(new_thread_id)?; + let old_thread_id = this.set_active_thread(new_thread_id); let thread_info_place = this.deref_operand(thread)?; this.write_scalar( @@ -47,7 +47,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx StackPopCleanup::None { cleanup: true }, )?; - this.set_active_thread(old_thread_id)?; + this.set_active_thread(old_thread_id); Ok(0) } @@ -82,7 +82,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn pthread_self(&mut self, dest: PlaceTy<'tcx, Tag>) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - let thread_id = this.get_active_thread()?; + let thread_id = this.get_active_thread(); this.write_scalar(Scalar::from_uint(thread_id.to_u32(), dest.layout.size), dest) } @@ -105,10 +105,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // byte. Since `read_c_str` returns the string without the null // byte, we need to truncate to 15. name.truncate(15); - this.set_active_thread_name(name)?; + this.set_active_thread_name(name); } else if option == this.eval_libc_i32("PR_GET_NAME")? { let address = this.read_scalar(arg2)?.not_undef()?; - let mut name = this.get_active_thread_name()?.to_vec(); + let mut name = this.get_active_thread_name().to_vec(); name.push(0u8); assert!(name.len() <= 16); this.memory.write_bytes(address, name)?; @@ -127,7 +127,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.assert_target_os("macos", "pthread_setname_np"); let name = this.memory.read_c_str(name)?.to_owned(); - this.set_active_thread_name(name)?; + this.set_active_thread_name(name); Ok(()) } @@ -135,7 +135,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn sched_yield(&mut self) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - this.yield_active_thread()?; + this.yield_active_thread(); Ok(0) } diff --git a/src/shims/tls.rs b/src/shims/tls.rs index 1ef4728faf076..695614633682a 100644 --- a/src/shims/tls.rs +++ b/src/shims/tls.rs @@ -232,8 +232,8 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// yet. fn schedule_windows_tls_dtors(&mut self) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - let active_thread = this.get_active_thread()?; - assert_eq!(this.get_total_thread_count()?, 1, "concurrency on Windows not supported"); + let active_thread = this.get_active_thread(); + assert_eq!(this.get_total_thread_count(), 1, "concurrency on Windows not supported"); // Windows has a special magic linker section that is run on certain events. // Instead of searching for that section and supporting arbitrary hooks in there // (that would be basically https://github.com/rust-lang/miri/issues/450), @@ -252,7 +252,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx StackPopCleanup::None { cleanup: true }, )?; - this.enable_thread(active_thread)?; + this.enable_thread(active_thread); Ok(()) } @@ -262,7 +262,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// Note: It is safe to call this function also on other Unixes. fn schedule_macos_tls_dtor(&mut self) -> InterpResult<'tcx, bool> { let this = self.eval_context_mut(); - let thread_id = this.get_active_thread()?; + let thread_id = this.get_active_thread(); if let Some((instance, data)) = this.machine.tls.macos_thread_dtors.remove(&thread_id) { trace!("Running macos dtor {:?} on {:?} at {:?}", instance, data, thread_id); @@ -278,7 +278,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // we just scheduled. Since we deleted the destructor, it is // guaranteed that we will schedule it again. The `dtors_running` // flag will prevent the code from adding the destructor again. - this.enable_thread(thread_id)?; + this.enable_thread(thread_id); Ok(true) } else { Ok(false) @@ -289,9 +289,9 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// a destructor to schedule, and `false` otherwise. fn schedule_next_pthread_tls_dtor(&mut self) -> InterpResult<'tcx, bool> { let this = self.eval_context_mut(); - let active_thread = this.get_active_thread()?; + let active_thread = this.get_active_thread(); - assert!(this.has_terminated(active_thread)?, "running TLS dtors for non-terminated thread"); + assert!(this.has_terminated(active_thread), "running TLS dtors for non-terminated thread"); // Fetch next dtor after `key`. let last_key = this.machine.tls.dtors_running[&active_thread].last_dtor_key.clone(); let dtor = match this.machine.tls.fetch_tls_dtor(last_key, active_thread) { @@ -314,7 +314,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx StackPopCleanup::None { cleanup: true }, )?; - this.enable_thread(active_thread)?; + this.enable_thread(active_thread); return Ok(true); } this.machine.tls.dtors_running.get_mut(&active_thread).unwrap().last_dtor_key = None; @@ -340,7 +340,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// https://github.com/rust-lang/rust/issues/28129. fn schedule_next_tls_dtor_for_active_thread(&mut self) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - let active_thread = this.get_active_thread()?; + let active_thread = this.get_active_thread(); if !this.machine.tls.set_dtors_running_for_thread(active_thread) { // This is the first time we got asked to schedule a destructor. The diff --git a/src/sync.rs b/src/sync.rs index 107ad5ace1723..8418bd429515e 100644 --- a/src/sync.rs +++ b/src/sync.rs @@ -145,13 +145,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx mutex.lock_count = mutex.lock_count.checked_add(1).unwrap(); } - /// Try unlocking by decreasing the lock count and returning the old owner - /// and the old lock count. If the lock count reaches 0, release the lock - /// and potentially give to a new owner. If the lock was not locked, return - /// `None`. - /// - /// Note: It is the caller's responsibility to check that the thread that - /// unlocked the lock actually is the same one, which owned it. + /// Try unlocking by decreasing the lock count and returning the old lock + /// count. If the lock count reaches 0, release the lock and potentially + /// give to a new owner. If the lock was not locked by `expected_owner`, + /// return `None`. fn mutex_unlock( &mut self, id: MutexId, @@ -173,9 +170,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx mutex.owner = None; // The mutex is completely unlocked. Try transfering ownership // to another thread. - if let Some(new_owner) = this.mutex_dequeue(id) { + if let Some(new_owner) = this.mutex_dequeue_and_unblock(id) { this.mutex_lock(id, new_owner); - this.unblock_thread(new_owner)?; } } Ok(Some(old_lock_count)) @@ -187,17 +183,23 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx #[inline] /// Put the thread into the queue waiting for the lock. - fn mutex_enqueue(&mut self, id: MutexId, thread: ThreadId) { + fn mutex_enqueue_and_block(&mut self, id: MutexId, thread: ThreadId) { let this = self.eval_context_mut(); assert!(this.mutex_is_locked(id), "queing on unlocked mutex"); this.machine.threads.sync.mutexes[id].queue.push_back(thread); + this.block_thread(thread); } #[inline] /// Take a thread out of the queue waiting for the lock. - fn mutex_dequeue(&mut self, id: MutexId) -> Option { + fn mutex_dequeue_and_unblock(&mut self, id: MutexId) -> Option { let this = self.eval_context_mut(); - this.machine.threads.sync.mutexes[id].queue.pop_front() + if let Some(thread) = this.machine.threads.sync.mutexes[id].queue.pop_front() { + this.unblock_thread(thread); + Some(thread) + } else { + None + } } #[inline] @@ -255,25 +257,30 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx &mut self, id: RwLockId, reader: ThreadId, - ) -> InterpResult<'tcx> { + ) { let this = self.eval_context_mut(); assert!(this.rwlock_is_write_locked(id), "queueing on not write locked lock"); this.machine.threads.sync.rwlocks[id].reader_queue.push_back(reader); - this.block_thread(reader) + this.block_thread(reader); } #[inline] /// Take a reader out the queue waiting for the lock. - fn rwlock_dequeue_reader(&mut self, id: RwLockId) -> Option { + fn rwlock_dequeue_and_unblock_reader(&mut self, id: RwLockId) -> Option { let this = self.eval_context_mut(); - this.machine.threads.sync.rwlocks[id].reader_queue.pop_front() + if let Some(reader) = this.machine.threads.sync.rwlocks[id].reader_queue.pop_front() { + this.unblock_thread(reader); + Some(reader) + } else { + None + } } #[inline] /// Lock by setting the writer that owns the lock. fn rwlock_writer_lock(&mut self, id: RwLockId, writer: ThreadId) { let this = self.eval_context_mut(); - assert!(!this.rwlock_is_locked(id), "the lock is already locked"); + assert!(!this.rwlock_is_locked(id), "the relock is already locked"); this.machine.threads.sync.rwlocks[id].writer = Some(writer); } @@ -290,18 +297,23 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx &mut self, id: RwLockId, writer: ThreadId, - ) -> InterpResult<'tcx> { + ) { let this = self.eval_context_mut(); assert!(this.rwlock_is_locked(id), "queueing on unlocked lock"); this.machine.threads.sync.rwlocks[id].writer_queue.push_back(writer); - this.block_thread(writer) + this.block_thread(writer); } #[inline] /// Take the writer out the queue waiting for the lock. - fn rwlock_dequeue_writer(&mut self, id: RwLockId) -> Option { + fn rwlock_dequeue_and_unblock_writer(&mut self, id: RwLockId) -> Option { let this = self.eval_context_mut(); - this.machine.threads.sync.rwlocks[id].writer_queue.pop_front() + if let Some(writer) = this.machine.threads.sync.rwlocks[id].writer_queue.pop_front() { + this.unblock_thread(writer); + Some(writer) + } else { + None + } } #[inline] diff --git a/src/thread.rs b/src/thread.rs index 59f08eec1649b..246a383d178b0 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -581,9 +581,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } #[inline] - fn create_thread(&mut self) -> InterpResult<'tcx, ThreadId> { + fn create_thread(&mut self) -> ThreadId { let this = self.eval_context_mut(); - Ok(this.machine.threads.create_thread()) + this.machine.threads.create_thread() } #[inline] @@ -599,34 +599,33 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } #[inline] - fn set_active_thread(&mut self, thread_id: ThreadId) -> InterpResult<'tcx, ThreadId> { + fn set_active_thread(&mut self, thread_id: ThreadId) -> ThreadId { let this = self.eval_context_mut(); - Ok(this.machine.threads.set_active_thread_id(thread_id)) + this.machine.threads.set_active_thread_id(thread_id) } #[inline] - fn get_active_thread(&self) -> InterpResult<'tcx, ThreadId> { + fn get_active_thread(&self) -> ThreadId { let this = self.eval_context_ref(); - Ok(this.machine.threads.get_active_thread_id()) + this.machine.threads.get_active_thread_id() } #[inline] - fn get_total_thread_count(&self) -> InterpResult<'tcx, usize> { + fn get_total_thread_count(&self) -> usize { let this = self.eval_context_ref(); - Ok(this.machine.threads.get_total_thread_count()) + this.machine.threads.get_total_thread_count() } #[inline] - fn has_terminated(&self, thread_id: ThreadId) -> InterpResult<'tcx, bool> { + fn has_terminated(&self, thread_id: ThreadId) -> bool { let this = self.eval_context_ref(); - Ok(this.machine.threads.has_terminated(thread_id)) + this.machine.threads.has_terminated(thread_id) } #[inline] - fn enable_thread(&mut self, thread_id: ThreadId) -> InterpResult<'tcx> { + fn enable_thread(&mut self, thread_id: ThreadId) { let this = self.eval_context_mut(); this.machine.threads.enable_thread(thread_id); - Ok(()) } #[inline] @@ -642,37 +641,36 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } #[inline] - fn set_active_thread_name(&mut self, new_thread_name: Vec) -> InterpResult<'tcx, ()> { + fn set_active_thread_name(&mut self, new_thread_name: Vec) { let this = self.eval_context_mut(); - Ok(this.machine.threads.set_thread_name(new_thread_name)) + this.machine.threads.set_thread_name(new_thread_name); } #[inline] - fn get_active_thread_name<'c>(&'c self) -> InterpResult<'tcx, &'c [u8]> + fn get_active_thread_name<'c>(&'c self) -> &'c [u8] where 'mir: 'c, { let this = self.eval_context_ref(); - Ok(this.machine.threads.get_thread_name()) + this.machine.threads.get_thread_name() } #[inline] - fn block_thread(&mut self, thread: ThreadId) -> InterpResult<'tcx> { + fn block_thread(&mut self, thread: ThreadId) { let this = self.eval_context_mut(); - Ok(this.machine.threads.block_thread(thread)) + this.machine.threads.block_thread(thread); } #[inline] - fn unblock_thread(&mut self, thread: ThreadId) -> InterpResult<'tcx> { + fn unblock_thread(&mut self, thread: ThreadId) { let this = self.eval_context_mut(); - Ok(this.machine.threads.unblock_thread(thread)) + this.machine.threads.unblock_thread(thread); } #[inline] - fn yield_active_thread(&mut self) -> InterpResult<'tcx> { + fn yield_active_thread(&mut self) { let this = self.eval_context_mut(); this.machine.threads.yield_active_thread(); - Ok(()) } #[inline] @@ -681,17 +679,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx thread: ThreadId, call_time: Time, callback: TimeoutCallback<'mir, 'tcx>, - ) -> InterpResult<'tcx> { + ) { let this = self.eval_context_mut(); this.machine.threads.register_timeout_callback(thread, call_time, callback); - Ok(()) } #[inline] - fn unregister_timeout_callback_if_exists(&mut self, thread: ThreadId) -> InterpResult<'tcx> { + fn unregister_timeout_callback_if_exists(&mut self, thread: ThreadId) { let this = self.eval_context_mut(); this.machine.threads.unregister_timeout_callback_if_exists(thread); - Ok(()) } /// Execute a timeout callback on the callback's thread. @@ -706,9 +702,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // thread. // 2. Make the scheduler the only place that can change the active // thread. - let old_thread = this.set_active_thread(thread)?; + let old_thread = this.set_active_thread(thread); callback(this)?; - this.set_active_thread(old_thread)?; + this.set_active_thread(old_thread); Ok(()) } From a80821e046c75878f4b63eac35c642b48c5825c3 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 30 May 2020 22:35:58 +0200 Subject: [PATCH 2122/3747] also combine re-locking into the dequeue-and-unblock operation --- src/shims/sync.rs | 13 +++++-------- src/sync.rs | 32 ++++++++++++++++++-------------- 2 files changed, 23 insertions(+), 22 deletions(-) diff --git a/src/shims/sync.rs b/src/shims/sync.rs index 01c7b4a1eb4fa..2669776db5bad 100644 --- a/src/shims/sync.rs +++ b/src/shims/sync.rs @@ -606,9 +606,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if this.rwlock_is_locked(id) { // No more readers owning the lock. Give it to a writer if there // is any. - if let Some(writer) = this.rwlock_dequeue_and_unblock_writer(id) { - this.rwlock_writer_lock(id, writer); - } + this.rwlock_dequeue_and_lock_writer(id); } Ok(0) } else if Some(active_thread) == this.rwlock_writer_unlock(id) { @@ -617,13 +615,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // We are prioritizing writers here against the readers. As a // result, not only readers can starve writers, but also writers can // starve readers. - if let Some(writer) = this.rwlock_dequeue_and_unblock_writer(id) { - // Give the lock to another writer. - this.rwlock_writer_lock(id, writer); + if this.rwlock_dequeue_and_lock_writer(id) { + // Someone got the write lock, nice. } else { // Give the lock to all readers. - while let Some(reader) = this.rwlock_dequeue_and_unblock_reader(id) { - this.rwlock_reader_lock(id, reader); + while this.rwlock_dequeue_and_lock_reader(id) { + // Rinse and repeat. } } Ok(0) diff --git a/src/sync.rs b/src/sync.rs index 8418bd429515e..723815dbf226e 100644 --- a/src/sync.rs +++ b/src/sync.rs @@ -170,9 +170,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx mutex.owner = None; // The mutex is completely unlocked. Try transfering ownership // to another thread. - if let Some(new_owner) = this.mutex_dequeue_and_unblock(id) { - this.mutex_lock(id, new_owner); - } + this.mutex_dequeue_and_lock(id); } Ok(Some(old_lock_count)) } else { @@ -182,7 +180,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } #[inline] - /// Put the thread into the queue waiting for the lock. + /// Put the thread into the queue waiting for the mutex. fn mutex_enqueue_and_block(&mut self, id: MutexId, thread: ThreadId) { let this = self.eval_context_mut(); assert!(this.mutex_is_locked(id), "queing on unlocked mutex"); @@ -191,14 +189,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } #[inline] - /// Take a thread out of the queue waiting for the lock. - fn mutex_dequeue_and_unblock(&mut self, id: MutexId) -> Option { + /// Take a thread out of the queue waiting for the mutex, and lock + /// the mutex for it. Returns `true` if some thread has the mutex now. + fn mutex_dequeue_and_lock(&mut self, id: MutexId) -> bool { let this = self.eval_context_mut(); if let Some(thread) = this.machine.threads.sync.mutexes[id].queue.pop_front() { this.unblock_thread(thread); - Some(thread) + this.mutex_lock(id, thread); + true } else { - None + false } } @@ -266,13 +266,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx #[inline] /// Take a reader out the queue waiting for the lock. - fn rwlock_dequeue_and_unblock_reader(&mut self, id: RwLockId) -> Option { + /// Returns `true` if some thread got the rwlock. + fn rwlock_dequeue_and_lock_reader(&mut self, id: RwLockId) -> bool { let this = self.eval_context_mut(); if let Some(reader) = this.machine.threads.sync.rwlocks[id].reader_queue.pop_front() { this.unblock_thread(reader); - Some(reader) + this.rwlock_reader_lock(id, reader); + true } else { - None + false } } @@ -306,13 +308,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx #[inline] /// Take the writer out the queue waiting for the lock. - fn rwlock_dequeue_and_unblock_writer(&mut self, id: RwLockId) -> Option { + /// Returns `true` if some thread got the rwlock. + fn rwlock_dequeue_and_lock_writer(&mut self, id: RwLockId) -> bool { let this = self.eval_context_mut(); if let Some(writer) = this.machine.threads.sync.rwlocks[id].writer_queue.pop_front() { this.unblock_thread(writer); - Some(writer) + this.rwlock_writer_lock(id, writer); + true } else { - None + false } } From acb3ec0866ab9abad7772ce0c1e6eeb267e111cd Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 30 May 2020 22:48:43 +0200 Subject: [PATCH 2123/3747] test and fix for rwlock unlock bug --- src/shims/sync.rs | 3 +- src/sync.rs | 2 +- tests/run-pass/concurrency/sync.rs | 47 ++++++++++++++++++++++++++++++ 3 files changed, 50 insertions(+), 2 deletions(-) diff --git a/src/shims/sync.rs b/src/shims/sync.rs index 2669776db5bad..39a087dc9ac2c 100644 --- a/src/shims/sync.rs +++ b/src/shims/sync.rs @@ -1,5 +1,6 @@ use std::convert::TryInto; use std::time::{Duration, SystemTime}; +use std::ops::Not; use rustc_middle::ty::{layout::TyAndLayout, TyKind, TypeAndMut}; use rustc_target::abi::{LayoutOf, Size}; @@ -603,7 +604,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if this.rwlock_reader_unlock(id, active_thread) { // The thread was a reader. - if this.rwlock_is_locked(id) { + if this.rwlock_is_locked(id).not() { // No more readers owning the lock. Give it to a writer if there // is any. this.rwlock_dequeue_and_lock_writer(id); diff --git a/src/sync.rs b/src/sync.rs index 723815dbf226e..5ba29b5afa252 100644 --- a/src/sync.rs +++ b/src/sync.rs @@ -282,7 +282,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// Lock by setting the writer that owns the lock. fn rwlock_writer_lock(&mut self, id: RwLockId, writer: ThreadId) { let this = self.eval_context_mut(); - assert!(!this.rwlock_is_locked(id), "the relock is already locked"); + assert!(!this.rwlock_is_locked(id), "the rwlock is already locked"); this.machine.threads.sync.rwlocks[id].writer = Some(writer); } diff --git a/tests/run-pass/concurrency/sync.rs b/tests/run-pass/concurrency/sync.rs index 2009c01ce9f95..e36c79491f91e 100644 --- a/tests/run-pass/concurrency/sync.rs +++ b/tests/run-pass/concurrency/sync.rs @@ -267,6 +267,51 @@ fn check_once() { } } +fn check_rwlock_unlock_bug1() { + // There was a bug where when un-read-locking an rwlock that still has other + // readers waiting, we'd accidentally also let a writer in. + // That caused an ICE. + let l = Arc::new(RwLock::new(0)); + + let r1 = l.read().unwrap(); + let r2 = l.read().unwrap(); + + // Make a waiting writer. + let l2 = l.clone(); + thread::spawn(move || { + let mut w = l2.write().unwrap(); + *w += 1; + }); + thread::yield_now(); + + drop(r1); + assert_eq!(*r2, 0); + thread::yield_now(); + thread::yield_now(); + thread::yield_now(); + assert_eq!(*r2, 0); + drop(r2); +} + +fn check_rwlock_unlock_bug2() { + // There was a bug where when un-read-locking an rwlock by letting the last reader leaver, + // we'd forget to wake up a writer. + // That meant the writer thread could never run again. + let l = Arc::new(RwLock::new(0)); + + let r = l.read().unwrap(); + + // Make a waiting writer. + let l2 = l.clone(); + let h = thread::spawn(move || { + let _w = l2.write().unwrap(); + }); + thread::yield_now(); + + drop(r); + h.join().unwrap(); +} + fn main() { check_barriers(); check_conditional_variables_notify_one(); @@ -280,4 +325,6 @@ fn main() { multiple_send(); send_on_sync(); check_once(); + check_rwlock_unlock_bug1(); + check_rwlock_unlock_bug2(); } From 67ad3041409ba87187c7c72e6f19ae79e1a7715f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 30 May 2020 22:50:49 +0200 Subject: [PATCH 2124/3747] update unsupported example in README (now that threading is supported on some platforms) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 12fc6d22cf85d..b2738bb062aa2 100644 --- a/README.md +++ b/README.md @@ -112,7 +112,7 @@ There is no way to list all the infinite things Miri cannot do, but the interpreter will explicitly tell you when it finds something unsupported: ``` -error: unsupported operation: Miri does not support threading +error: unsupported operation: can't call foreign function: bind ... = help: this is likely not a bug in the program; it indicates that the program \ performed an operation that the interpreter does not support From 0b6ec575b9d0c683b854ba4ea3da726620c209b9 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 30 May 2020 22:54:37 +0200 Subject: [PATCH 2125/3747] make mutex_unlock infallible --- src/shims/sync.rs | 4 ++-- src/sync.rs | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/shims/sync.rs b/src/shims/sync.rs index 39a087dc9ac2c..8986455a14fcd 100644 --- a/src/shims/sync.rs +++ b/src/shims/sync.rs @@ -316,7 +316,7 @@ fn release_cond_mutex_and_block<'mir, 'tcx: 'mir>( active_thread: ThreadId, mutex: MutexId, ) -> InterpResult<'tcx> { - if let Some(old_locked_count) = ecx.mutex_unlock(mutex, active_thread)? { + if let Some(old_locked_count) = ecx.mutex_unlock(mutex, active_thread) { if old_locked_count != 1 { throw_unsup_format!("awaiting on a lock acquired multiple times is not supported"); } @@ -486,7 +486,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let id = mutex_get_or_create_id(this, mutex_op)?; let active_thread = this.get_active_thread(); - if let Some(_old_locked_count) = this.mutex_unlock(id, active_thread)? { + if let Some(_old_locked_count) = this.mutex_unlock(id, active_thread) { // The mutex was locked by the current thread. Ok(0) } else { diff --git a/src/sync.rs b/src/sync.rs index 5ba29b5afa252..0d4b4d6b7c1cb 100644 --- a/src/sync.rs +++ b/src/sync.rs @@ -153,14 +153,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx &mut self, id: MutexId, expected_owner: ThreadId, - ) -> InterpResult<'tcx, Option> { + ) -> Option { let this = self.eval_context_mut(); let mutex = &mut this.machine.threads.sync.mutexes[id]; if let Some(current_owner) = mutex.owner { // Mutex is locked. if current_owner != expected_owner { // Only the owner can unlock the mutex. - return Ok(None); + return None; } let old_lock_count = mutex.lock_count; mutex.lock_count = old_lock_count @@ -172,10 +172,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // to another thread. this.mutex_dequeue_and_lock(id); } - Ok(Some(old_lock_count)) + Some(old_lock_count) } else { // Mutex is unlocked. - Ok(None) + None } } From 3032224d19394551580a402744ff85b8de5ae99a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 31 May 2020 10:30:25 +0200 Subject: [PATCH 2126/3747] rustup, adjust error message --- rust-version | 2 +- tests/compile-fail/validity/invalid_char.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/rust-version b/rust-version index 0124f254ec1ea..dd0af02836c75 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -0e9e4083100aa3ebf09b8f1ace0348cb37475eb9 +b6fa392238a459c29a47e2cf824d79a49a8ba039 diff --git a/tests/compile-fail/validity/invalid_char.rs b/tests/compile-fail/validity/invalid_char.rs index 2801f32971569..079823f894a86 100644 --- a/tests/compile-fail/validity/invalid_char.rs +++ b/tests/compile-fail/validity/invalid_char.rs @@ -1,6 +1,6 @@ fn main() { assert!(std::char::from_u32(-1_i32 as u32).is_none()); - let _val = match unsafe { std::mem::transmute::(-1) } { //~ ERROR encountered 0xffffffff, but expected a valid unicode codepoint + let _val = match unsafe { std::mem::transmute::(-1) } { //~ ERROR encountered 0xffffffff, but expected a valid unicode scalar value 'a' => {true}, 'b' => {false}, _ => {true}, From 7d406b152ada9c2af9af66724462710da014ff1a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 30 May 2020 18:46:26 +0200 Subject: [PATCH 2127/3747] test WTF8 encoding corner cases --- tests/run-pass/wtf8.rs | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 tests/run-pass/wtf8.rs diff --git a/tests/run-pass/wtf8.rs b/tests/run-pass/wtf8.rs new file mode 100644 index 0000000000000..2b4da785f2ee3 --- /dev/null +++ b/tests/run-pass/wtf8.rs @@ -0,0 +1,23 @@ +// ignore-linux: tests Windows-only APIs +// ignore-macos: tests Windows-only APIs + +use std::os::windows::ffi::{OsStrExt, OsStringExt}; +use std::ffi::{OsStr, OsString}; + +fn test1() { + let base = "a\té \u{7f}💩\r"; + let mut base: Vec = OsStr::new(base).encode_wide().collect(); + base.push(0xD800); + let _res = OsString::from_wide(&base); +} + +fn test2() { + let mut base: Vec = OsStr::new("aé ").encode_wide().collect(); + base.push(0xD83D); + let mut _res: Vec = OsString::from_wide(&base).encode_wide().collect(); +} + +fn main() { + test1(); + test2(); +} From 7cd68eb11b08571e75d882510dea7ce95f2d439f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 1 Jun 2020 01:15:00 +0200 Subject: [PATCH 2128/3747] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index dd0af02836c75..c5327e4d2bbcd 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -b6fa392238a459c29a47e2cf824d79a49a8ba039 +5fd2f06e99a985dd896684cb2c9f8c7090eca1ab From 17dd44ee92a0fc08fd6bc04c10ecd880d7a225a9 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 1 Jun 2020 19:23:54 +0200 Subject: [PATCH 2129/3747] rustup --- rust-version | 2 +- src/machine.rs | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/rust-version b/rust-version index c5327e4d2bbcd..daae7a34d0482 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -5fd2f06e99a985dd896684cb2c9f8c7090eca1ab +d3cba254e464303a6495942f3a831c2bbd7f1768 diff --git a/src/machine.rs b/src/machine.rs index 51aa7ae31047a..4f45b4f93f180 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -22,6 +22,7 @@ use rustc_middle::{ }, }; use rustc_span::symbol::{sym, Symbol}; +use rustc_span::def_id::DefId; use rustc_target::abi::{LayoutOf, Size}; use crate::*; @@ -416,10 +417,18 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { Ok(()) } + fn thread_local_alloc_id( + ecx: &mut InterpCx<'mir, 'tcx, Self>, + def_id: DefId, + ) -> InterpResult<'tcx, AllocId> { + ecx.get_or_create_thread_local_alloc_id(def_id) + } + fn adjust_global_const( ecx: &InterpCx<'mir, 'tcx, Self>, mut val: mir::interpret::ConstValue<'tcx>, ) -> InterpResult<'tcx, mir::interpret::ConstValue<'tcx>> { + // FIXME: Remove this, do The Right Thing in `thread_local_alloc_id` instead. ecx.remap_thread_local_alloc_ids(&mut val)?; Ok(val) } From dcb2b30982352362a0f10cbd45be298b31306eff Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 3 Jun 2020 09:40:21 +0200 Subject: [PATCH 2130/3747] rustup, and adjust timing tests --- rust-version | 2 +- tests/run-pass/concurrency/libc_pthread_cond.rs | 2 ++ tests/run-pass/concurrency/sync.rs | 2 +- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/rust-version b/rust-version index daae7a34d0482..d163c31622820 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -d3cba254e464303a6495942f3a831c2bbd7f1768 +680a4b2fbdca0dc6c5ceec826a8dbeabe28f305d diff --git a/tests/run-pass/concurrency/libc_pthread_cond.rs b/tests/run-pass/concurrency/libc_pthread_cond.rs index 27f5ead450fab..8aa3b210f4b0f 100644 --- a/tests/run-pass/concurrency/libc_pthread_cond.rs +++ b/tests/run-pass/concurrency/libc_pthread_cond.rs @@ -25,6 +25,8 @@ fn test_timed_wait_timeout(clock_id: i32) { let mut now: libc::timespec = mem::zeroed(); assert_eq!(libc::clock_gettime(clock_id, &mut now), 0); + // Waiting for a second... mostly because waiting less requires mich more tricky arithmetic. + // FIXME: wait less. let timeout = libc::timespec { tv_sec: now.tv_sec + 1, tv_nsec: now.tv_nsec }; assert_eq!(libc::pthread_mutex_lock(&mut mutex as *mut _), 0); diff --git a/tests/run-pass/concurrency/sync.rs b/tests/run-pass/concurrency/sync.rs index e36c79491f91e..b36ad27ebe198 100644 --- a/tests/run-pass/concurrency/sync.rs +++ b/tests/run-pass/concurrency/sync.rs @@ -109,7 +109,7 @@ fn check_conditional_variables_timed_wait_notimeout() { cvar.notify_one(); }); - let (_guard, timeout) = cvar.wait_timeout(guard, Duration::from_millis(100)).unwrap(); + let (_guard, timeout) = cvar.wait_timeout(guard, Duration::from_millis(200)).unwrap(); assert!(!timeout.timed_out()); handle.join().unwrap(); } From e352d4fbb7bc46b66debd642967f18b9c7ecea2f Mon Sep 17 00:00:00 2001 From: David Cook Date: Sat, 6 Jun 2020 16:54:13 +0000 Subject: [PATCH 2131/3747] Finish fixing Windows host support --- src/shims/fs.rs | 32 ++++++++++++++++++++++++-------- tests/run-pass/fs.rs | 5 +++++ tests/run-pass/libc.rs | 22 +++++++++++++++++++--- 3 files changed, 48 insertions(+), 11 deletions(-) diff --git a/src/shims/fs.rs b/src/shims/fs.rs index 7f1c5caaf6427..ece4d236ba0d9 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -379,9 +379,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx && cmd == this.eval_libc_i32("F_FULLFSYNC")? { let &[_, _] = check_arg_count(args)?; - if let Some(FileHandle { file, writable: _ }) = this.machine.file_handler.handles.get_mut(&fd) { - let result = file.sync_all(); - this.try_unwrap_io_result(result.map(|_| 0i32)) + if let Some(FileHandle { file, writable }) = this.machine.file_handler.handles.get_mut(&fd) { + if !*writable && cfg!(windows) { + // sync_all() will return an error on Windows hosts if the file is not opened + // for writing. (FlushFileBuffers requires that the file handle have the + // GENERIC_WRITE right) + Ok(0i32) + } else { + let result = file.sync_all(); + this.try_unwrap_io_result(result.map(|_| 0i32)) + } } else { this.handle_not_found() } @@ -1128,6 +1135,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if let Some(FileHandle { file, writable }) = this.machine.file_handler.handles.get_mut(&fd) { if !*writable && cfg!(windows) { // sync_all() will return an error on Windows hosts if the file is not opened for writing. + // (FlushFileBuffers requires that the file handle have the GENERIC_WRITE right) Ok(0i32) } else { let result = file.sync_all(); @@ -1147,6 +1155,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if let Some(FileHandle { file, writable }) = this.machine.file_handler.handles.get_mut(&fd) { if !*writable && cfg!(windows) { // sync_data() will return an error on Windows hosts if the file is not opened for writing. + // (FlushFileBuffers requires that the file handle have the GENERIC_WRITE right) Ok(0i32) } else { let result = file.sync_data(); @@ -1187,11 +1196,18 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx return Ok(-1); } - if let Some(FileHandle { file, writable: _ }) = this.machine.file_handler.handles.get_mut(&fd) { - // In the interest of host compatibility, we conservatively ignore - // offset, nbytes, and flags, and sync the entire file. - let result = file.sync_data(); - this.try_unwrap_io_result(result.map(|_| 0i32)) + if let Some(FileHandle { file, writable }) = this.machine.file_handler.handles.get_mut(&fd) { + if !*writable && cfg!(windows) { + // sync_data() will return an error on Windows hosts if the file is not opened for + // writing. (FlushFileBuffers requires that the file handle have the GENERIC_WRITE + // right) + Ok(0i32) + } else { + // In the interest of host compatibility, we conservatively ignore + // offset, nbytes, and flags, and sync the entire file. + let result = file.sync_data(); + this.try_unwrap_io_result(result.map(|_| 0i32)) + } } else { this.handle_not_found() } diff --git a/tests/run-pass/fs.rs b/tests/run-pass/fs.rs index a031233d581ab..caa9bffc2bc86 100644 --- a/tests/run-pass/fs.rs +++ b/tests/run-pass/fs.rs @@ -192,6 +192,11 @@ fn test_file_sync() { file.sync_data().unwrap(); file.sync_all().unwrap(); + // Test that we can call sync_data and sync_all on a file opened for reading. + let file = File::open(&path).unwrap(); + file.sync_data().unwrap(); + file.sync_all().unwrap(); + remove_file(&path).unwrap(); } diff --git a/tests/run-pass/libc.rs b/tests/run-pass/libc.rs index 08199c1452d34..6f30cb5a9150f 100644 --- a/tests/run-pass/libc.rs +++ b/tests/run-pass/libc.rs @@ -55,8 +55,22 @@ fn test_sync_file_range() { let bytes = b"Hello, World!\n"; file.write(bytes).unwrap(); - // Test calling sync_file_range on a file. - let result = unsafe { + // Test calling sync_file_range on the file. + let result_1 = unsafe { + libc::sync_file_range( + file.as_raw_fd(), + 0, + 0, + libc::SYNC_FILE_RANGE_WAIT_BEFORE + | libc::SYNC_FILE_RANGE_WRITE + | libc::SYNC_FILE_RANGE_WAIT_AFTER, + ) + }; + drop(file); + + // Test calling sync_file_range on a file opened for reading. + let file = File::open(&path).unwrap(); + let result_2 = unsafe { libc::sync_file_range( file.as_raw_fd(), 0, @@ -67,8 +81,10 @@ fn test_sync_file_range() { ) }; drop(file); + remove_file(&path).unwrap(); - assert_eq!(result, 0); + assert_eq!(result_1, 0); + assert_eq!(result_2, 0); } fn test_mutex_libc_init_recursive() { From ea4a5587ca230b9f485085fb5c5891de9452bf13 Mon Sep 17 00:00:00 2001 From: Youngsuk Kim Date: Mon, 8 Jun 2020 17:30:43 -0400 Subject: [PATCH 2132/3747] Add a case to list of 'StackedBorrows violations' A small fix was made to libstd in rust-lang/rust#70479 (back in March). (Miri reported UB due to Stacked Borrows violation - [link to Miri error log](https://github.com/rust-lang/miri/pull/1225#discussion_r397830221)) Thank you for reviewing :+1: --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index b2738bb062aa2..6b2b36d18c32f 100644 --- a/README.md +++ b/README.md @@ -295,6 +295,7 @@ Violations of [Stacked Borrows] found that are likely bugs (but Stacked Borrows * [`ryu` using raw pointers outside their valid memory area](https://github.com/dtolnay/ryu/issues/24) * [ink! creating overlapping mutable references](https://github.com/rust-lang/miri/issues/1364) * [TiKV creating overlapping mutable reference and raw pointer](https://github.com/tikv/tikv/pull/7709) +* [Windows `Env` iterator creating `*const T` from `&T` to read memory outside of `T`](https://github.com/rust-lang/rust/pull/70479) ## License From a60c130b0d4e1caecd525682c320224023bdf4a5 Mon Sep 17 00:00:00 2001 From: David Cook Date: Mon, 8 Jun 2020 23:34:02 +0000 Subject: [PATCH 2133/3747] Extract common logic for Windows host workaround --- src/shims/fs.rs | 64 +++++++++++++++++++------------------------------ 1 file changed, 24 insertions(+), 40 deletions(-) diff --git a/src/shims/fs.rs b/src/shims/fs.rs index ece4d236ba0d9..c789263ebea76 100644 --- a/src/shims/fs.rs +++ b/src/shims/fs.rs @@ -232,6 +232,18 @@ impl Default for DirHandler { } } +fn maybe_sync_file(file: &File, writable: bool, operation: fn(&File) -> std::io::Result<()>) -> std::io::Result { + if !writable && cfg!(windows) { + // sync_all() and sync_data() will return an error on Windows hosts if the file is not opened + // for writing. (FlushFileBuffers requires that the file handle have the + // GENERIC_WRITE right) + Ok(0i32) + } else { + let result = operation(file); + result.map(|_| 0i32) + } +} + impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { fn open( @@ -379,16 +391,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx && cmd == this.eval_libc_i32("F_FULLFSYNC")? { let &[_, _] = check_arg_count(args)?; - if let Some(FileHandle { file, writable }) = this.machine.file_handler.handles.get_mut(&fd) { - if !*writable && cfg!(windows) { - // sync_all() will return an error on Windows hosts if the file is not opened - // for writing. (FlushFileBuffers requires that the file handle have the - // GENERIC_WRITE right) - Ok(0i32) - } else { - let result = file.sync_all(); - this.try_unwrap_io_result(result.map(|_| 0i32)) - } + if let Some(FileHandle { file, writable }) = this.machine.file_handler.handles.get(&fd) { + let io_result = maybe_sync_file(file, *writable, File::sync_all); + this.try_unwrap_io_result(io_result) } else { this.handle_not_found() } @@ -1132,15 +1137,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.check_no_isolation("fsync")?; let fd = this.read_scalar(fd_op)?.to_i32()?; - if let Some(FileHandle { file, writable }) = this.machine.file_handler.handles.get_mut(&fd) { - if !*writable && cfg!(windows) { - // sync_all() will return an error on Windows hosts if the file is not opened for writing. - // (FlushFileBuffers requires that the file handle have the GENERIC_WRITE right) - Ok(0i32) - } else { - let result = file.sync_all(); - this.try_unwrap_io_result(result.map(|_| 0i32)) - } + if let Some(FileHandle { file, writable }) = this.machine.file_handler.handles.get(&fd) { + let io_result = maybe_sync_file(file, *writable, File::sync_all); + this.try_unwrap_io_result(io_result) } else { this.handle_not_found() } @@ -1152,15 +1151,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.check_no_isolation("fdatasync")?; let fd = this.read_scalar(fd_op)?.to_i32()?; - if let Some(FileHandle { file, writable }) = this.machine.file_handler.handles.get_mut(&fd) { - if !*writable && cfg!(windows) { - // sync_data() will return an error on Windows hosts if the file is not opened for writing. - // (FlushFileBuffers requires that the file handle have the GENERIC_WRITE right) - Ok(0i32) - } else { - let result = file.sync_data(); - this.try_unwrap_io_result(result.map(|_| 0i32)) - } + if let Some(FileHandle { file, writable }) = this.machine.file_handler.handles.get(&fd) { + let io_result = maybe_sync_file(file, *writable, File::sync_data); + this.try_unwrap_io_result(io_result) } else { this.handle_not_found() } @@ -1196,18 +1189,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx return Ok(-1); } - if let Some(FileHandle { file, writable }) = this.machine.file_handler.handles.get_mut(&fd) { - if !*writable && cfg!(windows) { - // sync_data() will return an error on Windows hosts if the file is not opened for - // writing. (FlushFileBuffers requires that the file handle have the GENERIC_WRITE - // right) - Ok(0i32) - } else { - // In the interest of host compatibility, we conservatively ignore - // offset, nbytes, and flags, and sync the entire file. - let result = file.sync_data(); - this.try_unwrap_io_result(result.map(|_| 0i32)) - } + if let Some(FileHandle { file, writable }) = this.machine.file_handler.handles.get(&fd) { + let io_result = maybe_sync_file(file, *writable, File::sync_data); + this.try_unwrap_io_result(io_result) } else { this.handle_not_found() } From 34f495a99438f8af3ba6c60ba97acc094d58ac65 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 10 Jun 2020 10:55:48 +0200 Subject: [PATCH 2134/3747] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index d163c31622820..177b6ada73401 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -680a4b2fbdca0dc6c5ceec826a8dbeabe28f305d +bb8674837a9cc5225020e07fc3f164762bb4c11c From 399435240550ade667e3315e22e8c72458e31e2f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 12 Jun 2020 10:00:46 +0200 Subject: [PATCH 2135/3747] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 177b6ada73401..adb8991d4ad8c 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -bb8674837a9cc5225020e07fc3f164762bb4c11c +50c0192c64241d723066add22c53d472e2b9cba9 From e063ce27370e217f37905620edaaec73e1bbc618 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 13 Jun 2020 11:30:31 +0200 Subject: [PATCH 2136/3747] rustup; and a bit of UnsafeCell detection refactoring --- rust-version | 2 +- src/helpers.rs | 12 +++++------- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/rust-version b/rust-version index adb8991d4ad8c..017196c1669d3 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -50c0192c64241d723066add22c53d472e2b9cba9 +1fb612bd15bb3ef098fd24c20d0727de573b4410 diff --git a/src/helpers.rs b/src/helpers.rs index 8b20ee2f0d835..4e5e0dcfca256 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -291,6 +291,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } else if self.ecx.type_is_freeze(v.layout.ty) { // This is `Freeze`, there cannot be an `UnsafeCell` Ok(()) + } else if matches!(v.layout.fields, FieldsShape::Union(..)) { + // A (non-frozen) union. We fall back to whatever the type says. + (self.unsafe_cell_action)(v) } else { // We want to not actually read from memory for this visit. So, before // walking this value, we have to make sure it is not a @@ -341,13 +344,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } - // We have to do *something* for unions. - fn visit_union(&mut self, v: MPlaceTy<'tcx, Tag>, _fields: NonZeroUsize) -> InterpResult<'tcx> { - // With unions, we fall back to whatever the type says, to hopefully be consistent - // with LLVM IR. - // FIXME: are we consistent, and is this really the behavior we want? - let frozen = self.ecx.type_is_freeze(v.layout.ty); - if frozen { Ok(()) } else { (self.unsafe_cell_action)(v) } + fn visit_union(&mut self, _v: MPlaceTy<'tcx, Tag>, _fields: NonZeroUsize) -> InterpResult<'tcx> { + bug!("we should have already handled unions in `visit_value`") } } } From 9df8d588eaa87f79b6a7bdc139621d240c198962 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 15 Jun 2020 10:58:20 +0200 Subject: [PATCH 2137/3747] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 017196c1669d3..4ecda8a5f4f5c 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -1fb612bd15bb3ef098fd24c20d0727de573b4410 +4fb54ed484e2239a3e9eff3be17df00d2a162be3 From 5c5b61ffb0810e4aa318fd5f20a49f016f3a1e36 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 15 Jun 2020 17:38:27 +0200 Subject: [PATCH 2138/3747] rustup --- rust-version | 2 +- src/eval.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/rust-version b/rust-version index 4ecda8a5f4f5c..342ec7486e678 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -4fb54ed484e2239a3e9eff3be17df00d2a162be3 +ff4a2533a0720f9cdd86e02eafa3725f07aa7752 diff --git a/src/eval.rs b/src/eval.rs index 7a6c562e7ca07..56d6f3ed3c5b9 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -63,11 +63,11 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( main_id: DefId, config: MiriConfig, ) -> InterpResult<'tcx, (InterpCx<'mir, 'tcx, Evaluator<'mir, 'tcx>>, MPlaceTy<'tcx, Tag>)> { - let tcx_at = tcx.at(rustc_span::source_map::DUMMY_SP); let param_env = ty::ParamEnv::reveal_all(); let layout_cx = LayoutCx { tcx, param_env }; let mut ecx = InterpCx::new( - tcx_at, + tcx, + rustc_span::source_map::DUMMY_SP, param_env, Evaluator::new(config.communicate, config.validate, layout_cx), MemoryExtra::new( From 2940da9d1f22982b237cf7c64d7e9e5829397f88 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 20 Jun 2020 11:48:42 +0200 Subject: [PATCH 2139/3747] bump Rust --- rust-version | 2 +- .../{invalid_enum_discriminant.rs => invalid_enum_tag.rs} | 2 +- .../{invalid_enum_discriminant.rs => invalid_enum_tag.rs} | 2 +- tests/compile-fail/validity/transmute_through_ptr.rs | 4 ++-- tests/run-pass/panic/catch_panic.rs | 4 ++-- tests/run-pass/panic/catch_panic.stderr | 4 ++-- tests/run-pass/specialization.rs | 1 + 7 files changed, 10 insertions(+), 9 deletions(-) rename tests/compile-fail/{invalid_enum_discriminant.rs => invalid_enum_tag.rs} (85%) rename tests/compile-fail/validity/{invalid_enum_discriminant.rs => invalid_enum_tag.rs} (63%) diff --git a/rust-version b/rust-version index 342ec7486e678..f001577e7f0cb 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -ff4a2533a0720f9cdd86e02eafa3725f07aa7752 +033013cab3a861224fd55f494c8be1cb0349eb49 diff --git a/tests/compile-fail/invalid_enum_discriminant.rs b/tests/compile-fail/invalid_enum_tag.rs similarity index 85% rename from tests/compile-fail/invalid_enum_discriminant.rs rename to tests/compile-fail/invalid_enum_tag.rs index 893dd03c64e67..762a70d803a41 100644 --- a/tests/compile-fail/invalid_enum_discriminant.rs +++ b/tests/compile-fail/invalid_enum_tag.rs @@ -2,7 +2,7 @@ // Make sure we find these even with many checks disabled. // compile-flags: -Zmiri-disable-alignment-check -Zmiri-disable-stacked-borrows -Zmiri-disable-validation -// error-pattern: enum value has invalid discriminant: 0x0000002a +// error-pattern: enum value has invalid tag: 0x0000002a use std::mem; diff --git a/tests/compile-fail/validity/invalid_enum_discriminant.rs b/tests/compile-fail/validity/invalid_enum_tag.rs similarity index 63% rename from tests/compile-fail/validity/invalid_enum_discriminant.rs rename to tests/compile-fail/validity/invalid_enum_tag.rs index a3234ba0920c3..897bfa90a7029 100644 --- a/tests/compile-fail/validity/invalid_enum_discriminant.rs +++ b/tests/compile-fail/validity/invalid_enum_tag.rs @@ -4,5 +4,5 @@ pub enum Foo { } fn main() { - let _f = unsafe { std::mem::transmute::(42) }; //~ ERROR encountered 0x0000002a, but expected a valid enum discriminant + let _f = unsafe { std::mem::transmute::(42) }; //~ ERROR encountered 0x0000002a, but expected a valid enum tag } diff --git a/tests/compile-fail/validity/transmute_through_ptr.rs b/tests/compile-fail/validity/transmute_through_ptr.rs index 617781c127514..1d5cf16aa5ea4 100644 --- a/tests/compile-fail/validity/transmute_through_ptr.rs +++ b/tests/compile-fail/validity/transmute_through_ptr.rs @@ -3,12 +3,12 @@ enum Bool { True } fn evil(x: &mut Bool) { let x = x as *mut _ as *mut u32; - unsafe { *x = 44; } // out-of-bounds enum discriminant + unsafe { *x = 44; } // out-of-bounds enum tag } fn main() { let mut x = Bool::True; evil(&mut x); let _y = x; // reading this ought to be enough to trigger validation - //~^ ERROR encountered 0x0000002c, but expected a valid enum discriminant + //~^ ERROR encountered 0x0000002c, but expected a valid enum tag } diff --git a/tests/run-pass/panic/catch_panic.rs b/tests/run-pass/panic/catch_panic.rs index 7689b85f76503..288ae1965a69d 100644 --- a/tests/run-pass/panic/catch_panic.rs +++ b/tests/run-pass/panic/catch_panic.rs @@ -1,5 +1,5 @@ // ignore-windows: Unwind panicking does not currently work on Windows -// normalize-stderr-test "[^ ]*libcore/(macros|mem)/mod.rs[0-9:]*" -> "$$LOC" +// normalize-stderr-test "[^ ]*libcore/[a-z/]+.rs[0-9:]*" -> "$$LOC" #![feature(never_type)] #![allow(unconditional_panic)] use std::panic::{catch_unwind, AssertUnwindSafe}; @@ -75,7 +75,7 @@ fn main() { // Assertion and debug assertion test(None, |_old_val| { assert!(false); loop {} }); test(None, |_old_val| { debug_assert!(false); loop {} }); - test(None, |_old_val| { unsafe { (1 as *const i32).read() }; loop {} }); // trigger debug-assertion in libstd + test(None, |_old_val| { unsafe { std::char::from_u32_unchecked(0xFD10000); } loop {} }); // trigger debug-assertion in libstd eprintln!("Success!"); // Make sure we get this in stderr } diff --git a/tests/run-pass/panic/catch_panic.stderr b/tests/run-pass/panic/catch_panic.stderr index 6da9cd29963a6..f64ff1186619e 100644 --- a/tests/run-pass/panic/catch_panic.stderr +++ b/tests/run-pass/panic/catch_panic.stderr @@ -22,6 +22,6 @@ thread 'main' panicked at 'assertion failed: false', $DIR/catch_panic.rs:76:29 Caught panic message (&str): assertion failed: false thread 'main' panicked at 'assertion failed: false', $DIR/catch_panic.rs:77:29 Caught panic message (&str): assertion failed: false -thread 'main' panicked at 'attempt to copy from unaligned or null pointer', $LOC -Caught panic message (String): attempt to copy from unaligned or null pointer +thread 'main' panicked at 'called `Option::unwrap()` on a `None` value', $LOC +Caught panic message (String): called `Option::unwrap()` on a `None` value Success! diff --git a/tests/run-pass/specialization.rs b/tests/run-pass/specialization.rs index 13894926d36db..44cef00a22c36 100644 --- a/tests/run-pass/specialization.rs +++ b/tests/run-pass/specialization.rs @@ -1,3 +1,4 @@ +#![allow(incomplete_features)] #![feature(specialization)] trait IsUnit { From a29f86b512a0a6a353c11f44af768da6bdc5c782 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 20 Jun 2020 14:28:55 +0200 Subject: [PATCH 2140/3747] make sure '&raw *' on a dangling raw ptr is UB --- .../dangling_pointers/dangling_pointer_addr_of.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 tests/compile-fail/dangling_pointers/dangling_pointer_addr_of.rs diff --git a/tests/compile-fail/dangling_pointers/dangling_pointer_addr_of.rs b/tests/compile-fail/dangling_pointers/dangling_pointer_addr_of.rs new file mode 100644 index 0000000000000..5df5b324f4579 --- /dev/null +++ b/tests/compile-fail/dangling_pointers/dangling_pointer_addr_of.rs @@ -0,0 +1,13 @@ +// Make sure we find these even with many checks disabled. +// compile-flags: -Zmiri-disable-alignment-check -Zmiri-disable-stacked-borrows -Zmiri-disable-validation +#![feature(raw_ref_macros)] +use std::ptr; + +fn main() { + let p = { + let b = Box::new(42); + &*b as *const i32 + }; + let x = unsafe { ptr::raw_const!(*p) }; //~ ERROR dereferenced after this allocation got freed + panic!("this should never print: {:?}", x); +} From 03fe3772a8a6859b2aa890f5a002e7cc3707e326 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 20 Jun 2020 14:31:47 +0200 Subject: [PATCH 2141/3747] make sure the raw_ptr macros also avoid UB --- tests/run-pass/packed_struct.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tests/run-pass/packed_struct.rs b/tests/run-pass/packed_struct.rs index 5582caaf37ea5..43419695ba044 100644 --- a/tests/run-pass/packed_struct.rs +++ b/tests/run-pass/packed_struct.rs @@ -1,7 +1,8 @@ -#![feature(unsize, coerce_unsized, raw_ref_op)] +#![feature(unsize, coerce_unsized, raw_ref_op, raw_ref_macros)] use std::collections::hash_map::DefaultHasher; use std::hash::Hash; +use std::ptr; fn test_basic() { #[repr(packed)] @@ -45,7 +46,9 @@ fn test_basic() { assert_eq!({x.b}, 99); // but we *can* take a raw pointer! assert_eq!(unsafe { (&raw const x.a).read_unaligned() }, 42); + assert_eq!(unsafe { ptr::raw_const!(x.a).read_unaligned() }, 42); assert_eq!(unsafe { (&raw const x.b).read_unaligned() }, 99); + assert_eq!(unsafe { ptr::raw_const!(x.b).read_unaligned() }, 99); x.b = 77; assert_eq!({x.b}, 77); From 8d1d5724727ee5a6862881bc97da86b9c90f9b21 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 20 Jun 2020 14:34:57 +0200 Subject: [PATCH 2142/3747] unaligned-raw-deref is always UB --- .../unaligned_pointers/unaligned_ptr_addr_of.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 tests/compile-fail/unaligned_pointers/unaligned_ptr_addr_of.rs diff --git a/tests/compile-fail/unaligned_pointers/unaligned_ptr_addr_of.rs b/tests/compile-fail/unaligned_pointers/unaligned_ptr_addr_of.rs new file mode 100644 index 0000000000000..cd52cd44c2b2c --- /dev/null +++ b/tests/compile-fail/unaligned_pointers/unaligned_ptr_addr_of.rs @@ -0,0 +1,12 @@ +// This should fail even without validation or Stacked Borrows. +// compile-flags: -Zmiri-disable-validation -Zmiri-disable-stacked-borrows +#![feature(raw_ref_macros)] +use std::ptr; + +fn main() { + let x = [2u16, 3, 4]; // Make it big enough so we don't get an out-of-bounds error. + let x = &x[0] as *const _ as *const u32; + // This must fail because alignment is violated: the allocation's base is not sufficiently aligned. + // The deref is UB even if we just put the result into a raw pointer. + let _x = unsafe { ptr::raw_const!(*x) }; //~ ERROR memory with alignment 2, but alignment 4 is required +} From 2e5a0dc172916bef6f8506d5e8b08b8653d98360 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 22 Jun 2020 11:32:01 +0200 Subject: [PATCH 2143/3747] add a miscompilation test --- tests/run-pass/issue-73223.rs | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 tests/run-pass/issue-73223.rs diff --git a/tests/run-pass/issue-73223.rs b/tests/run-pass/issue-73223.rs new file mode 100644 index 0000000000000..3a32d970d637a --- /dev/null +++ b/tests/run-pass/issue-73223.rs @@ -0,0 +1,22 @@ +fn main() { + let mut state = State { prev: None, next: Some(8) }; + let path = "/nested/some/more"; + assert_eq!(state.rest(path), "some/more"); +} + +struct State { + prev: Option, + next: Option, +} + +impl State { + fn rest<'r>(&mut self, path: &'r str) -> &'r str { + let start = match self.next.take() { + Some(v) => v, + None => return "", + }; + + self.prev = Some(start); + &path[start..] + } +} From 4788f775f85e1a40aef5893dac5b97e0c7a314ae Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 22 Jun 2020 11:38:34 +0200 Subject: [PATCH 2144/3747] rustup; stop testing with mir opts as they are currently broken --- ci.sh | 7 ++++--- rust-version | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/ci.sh b/ci.sh index 785d7aa5520c0..0625c25575726 100755 --- a/ci.sh +++ b/ci.sh @@ -23,10 +23,11 @@ function run_tests { fi ./miri test --locked - if ! [ -n "${MIRI_TEST_TARGET+exists}" ]; then + #if ! [ -n "${MIRI_TEST_TARGET+exists}" ]; then # Only for host architecture: tests with MIR optimizations - MIRI_TEST_FLAGS="-Z mir-opt-level=3" ./miri test --locked - fi + # FIXME: disabled because of . + #MIRI_TEST_FLAGS="-Z mir-opt-level=3" ./miri test --locked + #fi # "miri test" has built the sysroot for us, now this should pass without # any interactive questions. ${PYTHON:-python3} test-cargo-miri/run-test.py diff --git a/rust-version b/rust-version index f001577e7f0cb..9f71640a53f1d 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -033013cab3a861224fd55f494c8be1cb0349eb49 +1a4e2b6f9c75a0e21722c88a0e3b610d6ffc3ae3 From 9d41e4c899e81b25b20ee92a542be4982197b9c8 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 25 Jun 2020 11:34:52 +0200 Subject: [PATCH 2145/3747] rustup --- ci.sh | 8 ++++---- rust-version | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/ci.sh b/ci.sh index 0625c25575726..ac0d080a48391 100755 --- a/ci.sh +++ b/ci.sh @@ -23,11 +23,11 @@ function run_tests { fi ./miri test --locked - #if ! [ -n "${MIRI_TEST_TARGET+exists}" ]; then + if ! [ -n "${MIRI_TEST_TARGET+exists}" ]; then # Only for host architecture: tests with MIR optimizations - # FIXME: disabled because of . - #MIRI_TEST_FLAGS="-Z mir-opt-level=3" ./miri test --locked - #fi + # FIXME:only testing level 1 because of . + MIRI_TEST_FLAGS="-Z mir-opt-level=1" ./miri test --locked + fi # "miri test" has built the sysroot for us, now this should pass without # any interactive questions. ${PYTHON:-python3} test-cargo-miri/run-test.py diff --git a/rust-version b/rust-version index 9f71640a53f1d..8a53046ddfbf4 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -1a4e2b6f9c75a0e21722c88a0e3b610d6ffc3ae3 +67100f61e62a86f2bf9e38552ee138e231eddc74 From 3ea8c5fa33d9385d1c01c28b0cbc4796611cb52e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 26 Jun 2020 20:36:08 +0200 Subject: [PATCH 2146/3747] bump Rust --- rust-version | 2 +- tests/compile-fail/intrinsics/exact_div2.rs | 2 +- tests/compile-fail/intrinsics/exact_div3.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/rust-version b/rust-version index 8a53046ddfbf4..159f752cc0df3 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -67100f61e62a86f2bf9e38552ee138e231eddc74 +7750c3d46bc19784adb1ee6e37a5ec7e4cd7e772 diff --git a/tests/compile-fail/intrinsics/exact_div2.rs b/tests/compile-fail/intrinsics/exact_div2.rs index 9b9ae807088d7..1327046920d26 100644 --- a/tests/compile-fail/intrinsics/exact_div2.rs +++ b/tests/compile-fail/intrinsics/exact_div2.rs @@ -1,5 +1,5 @@ #![feature(core_intrinsics)] fn main() { // divison with a remainder - unsafe { std::intrinsics::exact_div(2u16, 3); } //~ ERROR 2u16 cannot be divided by 3u16 without remainder + unsafe { std::intrinsics::exact_div(2u16, 3); } //~ ERROR 2_u16 cannot be divided by 3_u16 without remainder } diff --git a/tests/compile-fail/intrinsics/exact_div3.rs b/tests/compile-fail/intrinsics/exact_div3.rs index 1cd112acfc2d5..6a309442749b1 100644 --- a/tests/compile-fail/intrinsics/exact_div3.rs +++ b/tests/compile-fail/intrinsics/exact_div3.rs @@ -1,5 +1,5 @@ #![feature(core_intrinsics)] fn main() { // signed divison with a remainder - unsafe { std::intrinsics::exact_div(-19i8, 2); } //~ ERROR -19i8 cannot be divided by 2i8 without remainder + unsafe { std::intrinsics::exact_div(-19i8, 2); } //~ ERROR -19_i8 cannot be divided by 2_i8 without remainder } From b46f946c81477e22c14d92ab93609ade18dc86d6 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 27 Jun 2020 11:57:43 +0200 Subject: [PATCH 2147/3747] supply our own implementation of the CTFE pointer comparison intrinsics --- src/shims/intrinsics.rs | 37 ++++++++++++++++++++++++++---------- tests/run-pass/intrinsics.rs | 7 ++++++- 2 files changed, 33 insertions(+), 11 deletions(-) diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index c16fbc278c8d8..015d9edc11b70 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -6,6 +6,7 @@ use rustc_middle::{mir, ty}; use rustc_middle::ty::layout::IntegerExt; use rustc_apfloat::{Float, Round}; use rustc_target::abi::{Align, Integer, LayoutOf}; +use rustc_span::symbol::sym; use crate::*; use helpers::check_arg_count; @@ -20,17 +21,19 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx unwind: Option, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - if this.emulate_intrinsic(instance, args, ret)? { + let intrinsic_name = this.tcx.item_name(instance.def_id()); + // We want to overwrite some of the intrinsic implementations that CTFE uses. + let prefer_miri_intrinsic = match intrinsic_name { + sym::ptr_guaranteed_eq | sym::ptr_guaranteed_ne => true, + _ => false, + }; + + if !prefer_miri_intrinsic && this.emulate_intrinsic(instance, args, ret)? { return Ok(()); } - let substs = instance.substs; - - // All these intrinsics take raw pointers, so if we access memory directly - // (as opposed to through a place), we have to remember to erase any tag - // that might still hang around! - let intrinsic_name = &*this.tcx.item_name(instance.def_id()).as_str(); // First handle intrinsics without return place. + let intrinsic_name = &*intrinsic_name.as_str(); let (dest, ret) = match ret { None => match intrinsic_name { "miri_start_panic" => return this.handle_miri_start_panic(args, unwind), @@ -42,13 +45,27 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Then handle terminating intrinsics. match intrinsic_name { + // Miri overwriting CTFE intrinsics. + "ptr_guaranteed_eq" => { + let &[left, right] = check_arg_count(args)?; + let left = this.read_immediate(left)?; + let right = this.read_immediate(right)?; + this.binop_ignore_overflow(mir::BinOp::Eq, left, right, dest)?; + } + "ptr_guaranteed_ne" => { + let &[left, right] = check_arg_count(args)?; + let left = this.read_immediate(left)?; + let right = this.read_immediate(right)?; + this.binop_ignore_overflow(mir::BinOp::Ne, left, right, dest)?; + } + // Raw memory accesses #[rustfmt::skip] | "copy" | "copy_nonoverlapping" => { let &[src, dest, count] = check_arg_count(args)?; - let elem_ty = substs.type_at(0); + let elem_ty = instance.substs.type_at(0); let elem_layout = this.layout_of(elem_ty)?; let count = this.read_scalar(count)?.to_machine_usize(this)?; let elem_align = elem_layout.align.abi; @@ -89,7 +106,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "write_bytes" => { let &[ptr, val_byte, count] = check_arg_count(args)?; - let ty = substs.type_at(0); + let ty = instance.substs.type_at(0); let ty_layout = this.layout_of(ty)?; let val_byte = this.read_scalar(val_byte)?.to_u8()?; let ptr = this.read_scalar(ptr)?.not_undef()?; @@ -455,7 +472,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "assert_zero_valid" | "assert_uninit_valid" => { let &[] = check_arg_count(args)?; - let ty = substs.type_at(0); + let ty = instance.substs.type_at(0); let layout = this.layout_of(ty)?; // Abort here because the caller might not be panic safe. if layout.abi.is_uninhabited() { diff --git a/tests/run-pass/intrinsics.rs b/tests/run-pass/intrinsics.rs index ffa7f080aa4e4..8f7dbac670646 100644 --- a/tests/run-pass/intrinsics.rs +++ b/tests/run-pass/intrinsics.rs @@ -1,4 +1,4 @@ -#![feature(core_intrinsics)] +#![feature(core_intrinsics, const_raw_ptr_comparison)] use std::intrinsics; use std::mem::{size_of, size_of_val}; @@ -30,4 +30,9 @@ fn main() { let _v = intrinsics::discriminant_value(&0); let _v = intrinsics::discriminant_value(&true); let _v = intrinsics::discriminant_value(&vec![1,2,3]); + + let addr = &13 as *const i32; + let addr2 = (addr as usize).wrapping_add(usize::MAX).wrapping_add(1); + assert!(addr.guaranteed_eq(addr2 as *const _)); + assert!(addr.guaranteed_ne(0x100 as *const _)); } From 395f5d40dcd50b3e83c3cd0a15f1927c141bf48c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 27 Jun 2020 12:36:20 +0200 Subject: [PATCH 2148/3747] Rename shims::{sync -> posic_sync} and move sync_singlethread test to other sync test --- src/lib.rs | 24 +++++++++---------- src/shims/{sync.rs => posix_sync.rs} | 3 +++ src/thread.rs | 4 ++-- .../{ => concurrency}/sync_singlethread.rs | 0 4 files changed, 17 insertions(+), 14 deletions(-) rename src/shims/{sync.rs => posix_sync.rs} (99%) rename tests/run-pass/{ => concurrency}/sync_singlethread.rs (100%) diff --git a/src/lib.rs b/src/lib.rs index e79fc2add39e1..e0da83840edd3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -39,18 +39,18 @@ pub use rustc_mir::interpret::*; // Resolve ambiguity. pub use rustc_mir::interpret::{self, AllocMap, PlaceTy}; -pub use crate::shims::dlsym::{Dlsym, EvalContextExt as DlsymEvalContextExt}; -pub use crate::shims::env::{EnvVars, EvalContextExt as EnvEvalContextExt}; -pub use crate::shims::foreign_items::EvalContextExt as ForeignItemsEvalContextExt; -pub use crate::shims::fs::{DirHandler, EvalContextExt as FileEvalContextExt, FileHandler}; -pub use crate::shims::intrinsics::EvalContextExt as IntrinsicsEvalContextExt; -pub use crate::shims::os_str::EvalContextExt as OsStrEvalContextExt; -pub use crate::shims::panic::{CatchUnwindData, EvalContextExt as PanicEvalContextExt}; -pub use crate::shims::sync::{EvalContextExt as SyncShimsEvalContextExt}; -pub use crate::shims::thread::EvalContextExt as ThreadShimsEvalContextExt; -pub use crate::shims::time::EvalContextExt as TimeEvalContextExt; -pub use crate::shims::tls::{EvalContextExt as TlsEvalContextExt, TlsData}; -pub use crate::shims::EvalContextExt as ShimsEvalContextExt; +pub use crate::shims::dlsym::{Dlsym, EvalContextExt as _}; +pub use crate::shims::env::{EnvVars, EvalContextExt as _}; +pub use crate::shims::foreign_items::EvalContextExt as _; +pub use crate::shims::fs::{DirHandler, EvalContextExt as _, FileHandler}; +pub use crate::shims::intrinsics::EvalContextExt as _; +pub use crate::shims::os_str::EvalContextExt as _; +pub use crate::shims::panic::{CatchUnwindData, EvalContextExt as _}; +pub use crate::shims::posix_sync::{EvalContextExt as _}; +pub use crate::shims::thread::EvalContextExt as _; +pub use crate::shims::time::EvalContextExt as _; +pub use crate::shims::tls::{EvalContextExt as _, TlsData}; +pub use crate::shims::EvalContextExt as _; pub use crate::diagnostics::{ register_diagnostic, report_error, EvalContextExt as DiagnosticsEvalContextExt, diff --git a/src/shims/sync.rs b/src/shims/posix_sync.rs similarity index 99% rename from src/shims/sync.rs rename to src/shims/posix_sync.rs index 8986455a14fcd..cdc1f8cc763ab 100644 --- a/src/shims/sync.rs +++ b/src/shims/posix_sync.rs @@ -522,6 +522,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx mutex_set_kind(this, mutex_op, ScalarMaybeUninit::Uninit)?; mutex_set_id(this, mutex_op, ScalarMaybeUninit::Uninit)?; + // FIXME: delete interpreter state associated with this mutex. Ok(0) } @@ -640,6 +641,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } rwlock_set_id(this, rwlock_op, ScalarMaybeUninit::Uninit)?; + // FIXME: delete interpreter state associated with this rwlock. Ok(0) } @@ -833,6 +835,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } cond_set_id(this, cond_op, ScalarMaybeUninit::Uninit)?; cond_set_clock_id(this, cond_op, ScalarMaybeUninit::Uninit)?; + // FIXME: delete interpreter state associated with this condvar. Ok(0) } diff --git a/src/thread.rs b/src/thread.rs index 246a383d178b0..896f93ef1a3a1 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -91,8 +91,8 @@ pub enum ThreadState { /// responsibility of the synchronization primitives to track threads that /// are blocked by them. BlockedOnSync, - /// The thread has terminated its execution (we do not delete terminated - /// threads). + /// The thread has terminated its execution. We do not delete terminated + /// threads (FIXME: why?). Terminated, } diff --git a/tests/run-pass/sync_singlethread.rs b/tests/run-pass/concurrency/sync_singlethread.rs similarity index 100% rename from tests/run-pass/sync_singlethread.rs rename to tests/run-pass/concurrency/sync_singlethread.rs From af5887e869c91df9920856e2ba2ee3e85cea6a78 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 27 Jun 2020 13:19:35 +0200 Subject: [PATCH 2149/3747] module organization: move platform-specific code to shims::{posix::{linux, macos}, windows} --- src/intptrcast.rs | 2 +- src/lib.rs | 7 +++---- src/machine.rs | 4 ++-- src/shims/foreign_items.rs | 9 +++------ src/shims/mod.rs | 13 ++++++++----- .../posix.rs => posix/foreign_items.rs} | 15 ++++++++------- src/shims/{ => posix}/fs.rs | 4 ++-- .../linux.rs => posix/linux/foreign_items.rs} | 8 ++++++-- src/shims/posix/linux/mod.rs | 1 + .../macos.rs => posix/macos/foreign_items.rs} | 5 ++++- src/shims/posix/macos/mod.rs | 1 + src/shims/posix/mod.rs | 10 ++++++++++ src/shims/{posix_sync.rs => posix/sync.rs} | 6 +++--- src/shims/{ => posix}/thread.rs | 0 src/shims/tls.rs | 5 +---- .../windows.rs => windows/foreign_items.rs} | 0 src/shims/windows/mod.rs | 1 + 17 files changed, 54 insertions(+), 37 deletions(-) rename src/shims/{foreign_items/posix.rs => posix/foreign_items.rs} (98%) rename src/shims/{ => posix}/fs.rs (99%) rename src/shims/{foreign_items/posix/linux.rs => posix/linux/foreign_items.rs} (97%) create mode 100644 src/shims/posix/linux/mod.rs rename src/shims/{foreign_items/posix/macos.rs => posix/macos/foreign_items.rs} (98%) create mode 100644 src/shims/posix/macos/mod.rs create mode 100644 src/shims/posix/mod.rs rename src/shims/{posix_sync.rs => posix/sync.rs} (99%) rename src/shims/{ => posix}/thread.rs (100%) rename src/shims/{foreign_items/windows.rs => windows/foreign_items.rs} (100%) create mode 100644 src/shims/windows/mod.rs diff --git a/src/intptrcast.rs b/src/intptrcast.rs index f51c8a7ce7439..c908bdf24ebac 100644 --- a/src/intptrcast.rs +++ b/src/intptrcast.rs @@ -9,7 +9,7 @@ use rustc_data_structures::fx::FxHashMap; use rustc_mir::interpret::{AllocCheck, AllocId, InterpResult, Memory, Machine, Pointer, PointerArithmetic}; use rustc_target::abi::{Size, HasDataLayout}; -use crate::{Evaluator, Tag, STACK_ADDR, CheckInAllocMsg}; +use crate::*; pub type MemoryExtra = RefCell; diff --git a/src/lib.rs b/src/lib.rs index e0da83840edd3..fa357eb9b1341 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -34,6 +34,8 @@ mod stacked_borrows; mod sync; mod thread; +// Establish a "crate-wide prelude": we often import `crate::*`. + // Make all those symbols available in the same place as our own. pub use rustc_mir::interpret::*; // Resolve ambiguity. @@ -42,13 +44,10 @@ pub use rustc_mir::interpret::{self, AllocMap, PlaceTy}; pub use crate::shims::dlsym::{Dlsym, EvalContextExt as _}; pub use crate::shims::env::{EnvVars, EvalContextExt as _}; pub use crate::shims::foreign_items::EvalContextExt as _; -pub use crate::shims::fs::{DirHandler, EvalContextExt as _, FileHandler}; pub use crate::shims::intrinsics::EvalContextExt as _; pub use crate::shims::os_str::EvalContextExt as _; -pub use crate::shims::panic::{CatchUnwindData, EvalContextExt as _}; -pub use crate::shims::posix_sync::{EvalContextExt as _}; -pub use crate::shims::thread::EvalContextExt as _; pub use crate::shims::time::EvalContextExt as _; +pub use crate::shims::panic::{CatchUnwindData, EvalContextExt as _}; pub use crate::shims::tls::{EvalContextExt as _, TlsData}; pub use crate::shims::EvalContextExt as _; diff --git a/src/machine.rs b/src/machine.rs index 4f45b4f93f180..6233222c004d1 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -241,8 +241,8 @@ pub struct Evaluator<'mir, 'tcx> { /// Whether to enforce the validity invariant. pub(crate) validate: bool, - pub(crate) file_handler: FileHandler, - pub(crate) dir_handler: DirHandler, + pub(crate) file_handler: shims::posix::FileHandler, + pub(crate) dir_handler: shims::posix::DirHandler, /// The temporary used for storing the argument of /// the call to `miri_start_panic` (the panic payload) when unwinding. diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 8a75fb03a53c0..14c5aac4899a7 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -1,6 +1,3 @@ -mod windows; -mod posix; - use std::{convert::{TryInto, TryFrom}, iter}; use rustc_hir::def_id::DefId; @@ -455,13 +452,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Architecture-specific shims "llvm.x86.sse2.pause" if this.tcx.sess.target.target.arch == "x86" || this.tcx.sess.target.target.arch == "x86_64" => { let &[] = check_arg_count(args)?; - this.sched_yield()?; + this.yield_active_thread(); } // Platform-specific shims _ => match this.tcx.sess.target.target.target_os.as_str() { - "linux" | "macos" => return posix::EvalContextExt::emulate_foreign_item_by_name(this, link_name, args, dest, ret), - "windows" => return windows::EvalContextExt::emulate_foreign_item_by_name(this, link_name, args, dest, ret), + "linux" | "macos" => return shims::posix::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, args, dest, ret), + "windows" => return shims::windows::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, args, dest, ret), target => throw_unsup_format!("the target `{}` is not supported", target), } }; diff --git a/src/shims/mod.rs b/src/shims/mod.rs index cd525e173ed70..37e7b8c40462e 100644 --- a/src/shims/mod.rs +++ b/src/shims/mod.rs @@ -1,15 +1,18 @@ -pub mod dlsym; -pub mod env; + pub mod foreign_items; -pub mod fs; pub mod intrinsics; +pub mod posix; +pub mod windows; + +pub mod dlsym; +pub mod env; pub mod os_str; pub mod panic; -pub mod sync; -pub mod thread; pub mod time; pub mod tls; +// End module management, begin local code + use std::convert::TryFrom; use log::trace; diff --git a/src/shims/foreign_items/posix.rs b/src/shims/posix/foreign_items.rs similarity index 98% rename from src/shims/foreign_items/posix.rs rename to src/shims/posix/foreign_items.rs index 8e4d140b06cb2..bbda40def620e 100644 --- a/src/shims/foreign_items/posix.rs +++ b/src/shims/posix/foreign_items.rs @@ -1,15 +1,16 @@ -mod linux; -mod macos; - use std::convert::TryFrom; use log::trace; -use crate::*; -use helpers::check_arg_count; use rustc_middle::mir; use rustc_target::abi::{Align, LayoutOf, Size}; +use crate::*; +use helpers::check_arg_count; +use shims::posix::fs::EvalContextExt as _; +use shims::posix::sync::EvalContextExt as _; +use shims::posix::thread::EvalContextExt as _; + impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { fn emulate_foreign_item_by_name( @@ -476,8 +477,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Platform-specific shims _ => { match this.tcx.sess.target.target.target_os.as_str() { - "linux" => return linux::EvalContextExt::emulate_foreign_item_by_name(this, link_name, args, dest, ret), - "macos" => return macos::EvalContextExt::emulate_foreign_item_by_name(this, link_name, args, dest, ret), + "linux" => return shims::posix::linux::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, args, dest, ret), + "macos" => return shims::posix::macos::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, args, dest, ret), _ => unreachable!(), } } diff --git a/src/shims/fs.rs b/src/shims/posix/fs.rs similarity index 99% rename from src/shims/fs.rs rename to src/shims/posix/fs.rs index 29e0da14ff1eb..87aa28120c28e 100644 --- a/src/shims/fs.rs +++ b/src/shims/posix/fs.rs @@ -10,13 +10,13 @@ use log::trace; use rustc_data_structures::fx::FxHashMap; use rustc_target::abi::{Align, LayoutOf, Size}; -use crate::stacked_borrows::Tag; use crate::*; +use stacked_borrows::Tag; use helpers::{check_arg_count, immty_from_int_checked, immty_from_uint_checked}; use shims::time::system_time_to_duration; #[derive(Debug)] -pub struct FileHandle { +struct FileHandle { file: File, writable: bool, } diff --git a/src/shims/foreign_items/posix/linux.rs b/src/shims/posix/linux/foreign_items.rs similarity index 97% rename from src/shims/foreign_items/posix/linux.rs rename to src/shims/posix/linux/foreign_items.rs index 2d124f9d8c6c0..ff30609d9ab27 100644 --- a/src/shims/foreign_items/posix/linux.rs +++ b/src/shims/posix/linux/foreign_items.rs @@ -1,7 +1,11 @@ -use crate::*; -use helpers::check_arg_count; use rustc_middle::mir; +use crate::*; +use crate::helpers::check_arg_count; +use shims::posix::fs::EvalContextExt as _; +use shims::posix::sync::EvalContextExt as _; +use shims::posix::thread::EvalContextExt as _; + impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { fn emulate_foreign_item_by_name( diff --git a/src/shims/posix/linux/mod.rs b/src/shims/posix/linux/mod.rs new file mode 100644 index 0000000000000..09c6507b24f84 --- /dev/null +++ b/src/shims/posix/linux/mod.rs @@ -0,0 +1 @@ +pub mod foreign_items; diff --git a/src/shims/foreign_items/posix/macos.rs b/src/shims/posix/macos/foreign_items.rs similarity index 98% rename from src/shims/foreign_items/posix/macos.rs rename to src/shims/posix/macos/foreign_items.rs index fb50e4d918173..ef649c3e84069 100644 --- a/src/shims/foreign_items/posix/macos.rs +++ b/src/shims/posix/macos/foreign_items.rs @@ -1,6 +1,9 @@ +use rustc_middle::mir; + use crate::*; use helpers::check_arg_count; -use rustc_middle::mir; +use shims::posix::fs::EvalContextExt as _; +use shims::posix::thread::EvalContextExt as _; impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { diff --git a/src/shims/posix/macos/mod.rs b/src/shims/posix/macos/mod.rs new file mode 100644 index 0000000000000..09c6507b24f84 --- /dev/null +++ b/src/shims/posix/macos/mod.rs @@ -0,0 +1 @@ +pub mod foreign_items; diff --git a/src/shims/posix/mod.rs b/src/shims/posix/mod.rs new file mode 100644 index 0000000000000..2f505cfb9c0b5 --- /dev/null +++ b/src/shims/posix/mod.rs @@ -0,0 +1,10 @@ +pub mod foreign_items; + +mod fs; +mod sync; +mod thread; + +mod linux; +mod macos; + +pub use fs::{DirHandler, FileHandler}; diff --git a/src/shims/posix_sync.rs b/src/shims/posix/sync.rs similarity index 99% rename from src/shims/posix_sync.rs rename to src/shims/posix/sync.rs index cdc1f8cc763ab..a61c80d5118c4 100644 --- a/src/shims/posix_sync.rs +++ b/src/shims/posix/sync.rs @@ -5,10 +5,10 @@ use std::ops::Not; use rustc_middle::ty::{layout::TyAndLayout, TyKind, TypeAndMut}; use rustc_target::abi::{LayoutOf, Size}; -use crate::stacked_borrows::Tag; -use crate::thread::Time; - use crate::*; +use stacked_borrows::Tag; +use thread::Time; + fn assert_ptr_target_min_size<'mir, 'tcx: 'mir>( ecx: &MiriEvalContext<'mir, 'tcx>, diff --git a/src/shims/thread.rs b/src/shims/posix/thread.rs similarity index 100% rename from src/shims/thread.rs rename to src/shims/posix/thread.rs diff --git a/src/shims/tls.rs b/src/shims/tls.rs index 695614633682a..704598ef2c6c0 100644 --- a/src/shims/tls.rs +++ b/src/shims/tls.rs @@ -10,10 +10,7 @@ use rustc_data_structures::fx::FxHashMap; use rustc_middle::ty; use rustc_target::abi::{Size, HasDataLayout}; -use crate::{ - HelpersEvalContextExt, InterpResult, MPlaceTy, Scalar, StackPopCleanup, Tag, ThreadId, - ThreadsEvalContextExt, -}; +use crate::*; pub type TlsKey = u128; diff --git a/src/shims/foreign_items/windows.rs b/src/shims/windows/foreign_items.rs similarity index 100% rename from src/shims/foreign_items/windows.rs rename to src/shims/windows/foreign_items.rs diff --git a/src/shims/windows/mod.rs b/src/shims/windows/mod.rs new file mode 100644 index 0000000000000..09c6507b24f84 --- /dev/null +++ b/src/shims/windows/mod.rs @@ -0,0 +1 @@ +pub mod foreign_items; From dca00ab85ec970432ebaf1cf59b0e795db2d65cd Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 27 Jun 2020 13:50:52 +0200 Subject: [PATCH 2150/3747] introduce platform-specific module hierarchy for dlsym (similar to foreign_items) --- src/shims/dlsym.rs | 43 ++++----------- src/shims/posix/dlsym.rs | 39 +++++++++++++ src/shims/posix/linux/dlsym.rs | 34 ++++++++++++ src/shims/posix/linux/mod.rs | 1 + src/shims/posix/macos/dlsym.rs | 49 +++++++++++++++++ src/shims/posix/macos/mod.rs | 1 + src/shims/posix/mod.rs | 1 + src/shims/windows/dlsym.rs | 55 +++++++++++++++++++ src/shims/windows/mod.rs | 3 + src/shims/windows/sync.rs | 0 .../run-pass/concurrency/sync_singlethread.rs | 6 +- 11 files changed, 194 insertions(+), 38 deletions(-) create mode 100644 src/shims/posix/dlsym.rs create mode 100644 src/shims/posix/linux/dlsym.rs create mode 100644 src/shims/posix/macos/dlsym.rs create mode 100644 src/shims/windows/dlsym.rs create mode 100644 src/shims/windows/sync.rs diff --git a/src/shims/dlsym.rs b/src/shims/dlsym.rs index 87c7f447ac03c..9b15cb9ac9a31 100644 --- a/src/shims/dlsym.rs +++ b/src/shims/dlsym.rs @@ -1,34 +1,24 @@ use rustc_middle::mir; use crate::*; -use helpers::check_arg_count; +use shims::posix::dlsym as posix; +use shims::windows::dlsym as windows; #[derive(Debug, Copy, Clone)] +#[allow(non_camel_case_types)] pub enum Dlsym { - GetEntropy, + Posix(posix::Dlsym), + Windows(windows::Dlsym), } impl Dlsym { // Returns an error for unsupported symbols, and None if this symbol // should become a NULL pointer (pretend it does not exist). pub fn from_str(name: &[u8], target_os: &str) -> InterpResult<'static, Option> { - use self::Dlsym::*; - let name = String::from_utf8_lossy(name); + let name = &*String::from_utf8_lossy(name); Ok(match target_os { - "linux" => match &*name { - "__pthread_get_minstack" => None, - _ => throw_unsup_format!("unsupported Linux dlsym: {}", name), - } - "macos" => match &*name { - "getentropy" => Some(GetEntropy), - _ => throw_unsup_format!("unsupported macOS dlsym: {}", name), - } - "windows" => match &*name { - "SetThreadStackGuarantee" => None, - "AcquireSRWLockExclusive" => None, - "GetSystemTimePreciseAsFileTime" => None, - _ => throw_unsup_format!("unsupported Windows dlsym: {}", name), - } + "linux" | "macos" => posix::Dlsym::from_str(name, target_os)?.map(Dlsym::Posix), + "windows" => windows::Dlsym::from_str(name)?.map(Dlsym::Windows), os => bug!("dlsym not implemented for target_os {}", os), }) } @@ -42,23 +32,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx args: &[OpTy<'tcx, Tag>], ret: Option<(PlaceTy<'tcx, Tag>, mir::BasicBlock)>, ) -> InterpResult<'tcx> { - use self::Dlsym::*; - let this = self.eval_context_mut(); - let (dest, ret) = ret.expect("we don't support any diverging dlsym"); - match dlsym { - GetEntropy => { - let &[ptr, len] = check_arg_count(args)?; - let ptr = this.read_scalar(ptr)?.not_undef()?; - let len = this.read_scalar(len)?.to_machine_usize(this)?; - this.gen_random(ptr, len)?; - this.write_null(dest)?; - } + Dlsym::Posix(dlsym) => posix::EvalContextExt::call_dlsym(this, dlsym, args, ret), + Dlsym::Windows(dlsym) => windows::EvalContextExt::call_dlsym(this, dlsym, args, ret), } - - this.dump_place(*dest); - this.go_to_block(ret); - Ok(()) } } diff --git a/src/shims/posix/dlsym.rs b/src/shims/posix/dlsym.rs new file mode 100644 index 0000000000000..52d9844bed511 --- /dev/null +++ b/src/shims/posix/dlsym.rs @@ -0,0 +1,39 @@ +use rustc_middle::mir; + +use crate::*; +use shims::posix::linux::dlsym as linux; +use shims::posix::macos::dlsym as macos; + +#[derive(Debug, Copy, Clone)] +pub enum Dlsym { + Linux(linux::Dlsym), + MacOs(macos::Dlsym), +} + +impl Dlsym { + // Returns an error for unsupported symbols, and None if this symbol + // should become a NULL pointer (pretend it does not exist). + pub fn from_str(name: &str, target_os: &str) -> InterpResult<'static, Option> { + Ok(match target_os { + "linux" => linux::Dlsym::from_str(name)?.map(Dlsym::Linux), + "macos" => macos::Dlsym::from_str(name)?.map(Dlsym::MacOs), + _ => unreachable!(), + }) + } +} + +impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} +pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { + fn call_dlsym( + &mut self, + dlsym: Dlsym, + args: &[OpTy<'tcx, Tag>], + ret: Option<(PlaceTy<'tcx, Tag>, mir::BasicBlock)>, + ) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + match dlsym { + Dlsym::Linux(dlsym) => linux::EvalContextExt::call_dlsym(this, dlsym, args, ret), + Dlsym::MacOs(dlsym) => macos::EvalContextExt::call_dlsym(this, dlsym, args, ret), + } + } +} diff --git a/src/shims/posix/linux/dlsym.rs b/src/shims/posix/linux/dlsym.rs new file mode 100644 index 0000000000000..9be300edf495a --- /dev/null +++ b/src/shims/posix/linux/dlsym.rs @@ -0,0 +1,34 @@ +use rustc_middle::mir; + +use crate::*; + +#[derive(Debug, Copy, Clone)] +pub enum Dlsym { +} + +impl Dlsym { + // Returns an error for unsupported symbols, and None if this symbol + // should become a NULL pointer (pretend it does not exist). + pub fn from_str(name: &str) -> InterpResult<'static, Option> { + Ok(match &*name { + "__pthread_get_minstack" => None, + _ => throw_unsup_format!("unsupported Linux dlsym: {}", name), + }) + } +} + +impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} +pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { + fn call_dlsym( + &mut self, + dlsym: Dlsym, + _args: &[OpTy<'tcx, Tag>], + ret: Option<(PlaceTy<'tcx, Tag>, mir::BasicBlock)>, + ) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + let (_dest, _ret) = ret.expect("we don't support any diverging dlsym"); + assert!(this.tcx.sess.target.target.target_os == "linux"); + + match dlsym {} + } +} diff --git a/src/shims/posix/linux/mod.rs b/src/shims/posix/linux/mod.rs index 09c6507b24f84..cadd6a8ea384e 100644 --- a/src/shims/posix/linux/mod.rs +++ b/src/shims/posix/linux/mod.rs @@ -1 +1,2 @@ pub mod foreign_items; +pub mod dlsym; diff --git a/src/shims/posix/macos/dlsym.rs b/src/shims/posix/macos/dlsym.rs new file mode 100644 index 0000000000000..8256c10b0d397 --- /dev/null +++ b/src/shims/posix/macos/dlsym.rs @@ -0,0 +1,49 @@ +use rustc_middle::mir; + +use crate::*; +use helpers::check_arg_count; + +#[derive(Debug, Copy, Clone)] +#[allow(non_camel_case_types)] +pub enum Dlsym { + getentropy, +} + +impl Dlsym { + // Returns an error for unsupported symbols, and None if this symbol + // should become a NULL pointer (pretend it does not exist). + pub fn from_str(name: &str) -> InterpResult<'static, Option> { + Ok(match name { + "getentropy" => Some(Dlsym::getentropy), + _ => throw_unsup_format!("unsupported macOS dlsym: {}", name), + }) + } +} + +impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} +pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { + fn call_dlsym( + &mut self, + dlsym: Dlsym, + args: &[OpTy<'tcx, Tag>], + ret: Option<(PlaceTy<'tcx, Tag>, mir::BasicBlock)>, + ) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + let (dest, ret) = ret.expect("we don't support any diverging dlsym"); + assert!(this.tcx.sess.target.target.target_os == "macos"); + + match dlsym { + Dlsym::getentropy => { + let &[ptr, len] = check_arg_count(args)?; + let ptr = this.read_scalar(ptr)?.not_undef()?; + let len = this.read_scalar(len)?.to_machine_usize(this)?; + this.gen_random(ptr, len)?; + this.write_null(dest)?; + } + } + + this.dump_place(*dest); + this.go_to_block(ret); + Ok(()) + } +} diff --git a/src/shims/posix/macos/mod.rs b/src/shims/posix/macos/mod.rs index 09c6507b24f84..cadd6a8ea384e 100644 --- a/src/shims/posix/macos/mod.rs +++ b/src/shims/posix/macos/mod.rs @@ -1 +1,2 @@ pub mod foreign_items; +pub mod dlsym; diff --git a/src/shims/posix/mod.rs b/src/shims/posix/mod.rs index 2f505cfb9c0b5..9916c65be0fb8 100644 --- a/src/shims/posix/mod.rs +++ b/src/shims/posix/mod.rs @@ -1,4 +1,5 @@ pub mod foreign_items; +pub mod dlsym; mod fs; mod sync; diff --git a/src/shims/windows/dlsym.rs b/src/shims/windows/dlsym.rs new file mode 100644 index 0000000000000..34ed6ca150e01 --- /dev/null +++ b/src/shims/windows/dlsym.rs @@ -0,0 +1,55 @@ +use rustc_middle::mir; + +use crate::*; +use helpers::check_arg_count; + +#[derive(Debug, Copy, Clone)] +pub enum Dlsym { + AcquireSRWLockExclusive, + AcquireSRWLockShared, +} + +impl Dlsym { + // Returns an error for unsupported symbols, and None if this symbol + // should become a NULL pointer (pretend it does not exist). + pub fn from_str(name: &str) -> InterpResult<'static, Option> { + Ok(match name { + "AcquireSRWLockExclusive" => Some(Dlsym::AcquireSRWLockExclusive), + "AcquireSRWLockShared" => Some(Dlsym::AcquireSRWLockShared), + "SetThreadStackGuarantee" => None, + "GetSystemTimePreciseAsFileTime" => None, + _ => throw_unsup_format!("unsupported Windows dlsym: {}", name), + }) + } +} + +impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} +pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { + fn call_dlsym( + &mut self, + dlsym: Dlsym, + args: &[OpTy<'tcx, Tag>], + ret: Option<(PlaceTy<'tcx, Tag>, mir::BasicBlock)>, + ) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + let (dest, ret) = ret.expect("we don't support any diverging dlsym"); + assert!(this.tcx.sess.target.target.target_os == "windows"); + + match dlsym { + Dlsym::AcquireSRWLockExclusive => { + let &[ptr] = check_arg_count(args)?; + let lock = this.deref_operand(ptr)?; // points to ptr-sized data + throw_unsup_format!("AcquireSRWLockExclusive is not actually implemented"); + } + Dlsym::AcquireSRWLockShared => { + let &[ptr] = check_arg_count(args)?; + let lock = this.deref_operand(ptr)?; // points to ptr-sized data + throw_unsup_format!("AcquireSRWLockExclusive is not actually implemented"); + } + } + + this.dump_place(*dest); + this.go_to_block(ret); + Ok(()) + } +} diff --git a/src/shims/windows/mod.rs b/src/shims/windows/mod.rs index 09c6507b24f84..04f9ace8e799b 100644 --- a/src/shims/windows/mod.rs +++ b/src/shims/windows/mod.rs @@ -1 +1,4 @@ pub mod foreign_items; +pub mod dlsym; + +mod sync; diff --git a/src/shims/windows/sync.rs b/src/shims/windows/sync.rs new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/tests/run-pass/concurrency/sync_singlethread.rs b/tests/run-pass/concurrency/sync_singlethread.rs index 8b8594d4df69d..749db855e296f 100644 --- a/tests/run-pass/concurrency/sync_singlethread.rs +++ b/tests/run-pass/concurrency/sync_singlethread.rs @@ -6,10 +6,7 @@ use std::hint; fn main() { test_mutex_stdlib(); - #[cfg(not(target_os = "windows"))] // TODO: implement RwLock on Windows - { - test_rwlock_stdlib(); - } + test_rwlock_stdlib(); test_spin_loop_hint(); test_thread_yield_now(); } @@ -24,7 +21,6 @@ fn test_mutex_stdlib() { drop(m); } -#[cfg(not(target_os = "windows"))] fn test_rwlock_stdlib() { use std::sync::RwLock; let rw = RwLock::new(0); From 8e9296994837c82c39b2c4cee7623d9181e4bc80 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 27 Jun 2020 14:35:58 +0200 Subject: [PATCH 2151/3747] implement Windows SRWLock shims --- src/shims/tls.rs | 2 +- src/shims/windows/dlsym.rs | 33 +++++- src/shims/windows/foreign_items.rs | 3 +- src/shims/windows/sync.rs | 161 +++++++++++++++++++++++++++++ 4 files changed, 193 insertions(+), 6 deletions(-) diff --git a/src/shims/tls.rs b/src/shims/tls.rs index 704598ef2c6c0..0cd9ef0565058 100644 --- a/src/shims/tls.rs +++ b/src/shims/tls.rs @@ -230,7 +230,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn schedule_windows_tls_dtors(&mut self) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let active_thread = this.get_active_thread(); - assert_eq!(this.get_total_thread_count(), 1, "concurrency on Windows not supported"); + assert_eq!(this.get_total_thread_count(), 1, "concurrency on Windows is not supported"); // Windows has a special magic linker section that is run on certain events. // Instead of searching for that section and supporting arbitrary hooks in there // (that would be basically https://github.com/rust-lang/miri/issues/450), diff --git a/src/shims/windows/dlsym.rs b/src/shims/windows/dlsym.rs index 34ed6ca150e01..737fd4314f632 100644 --- a/src/shims/windows/dlsym.rs +++ b/src/shims/windows/dlsym.rs @@ -2,11 +2,16 @@ use rustc_middle::mir; use crate::*; use helpers::check_arg_count; +use shims::windows::sync::EvalContextExt as _; #[derive(Debug, Copy, Clone)] pub enum Dlsym { AcquireSRWLockExclusive, + ReleaseSRWLockExclusive, + TryAcquireSRWLockExclusive, AcquireSRWLockShared, + ReleaseSRWLockShared, + TryAcquireSRWLockShared, } impl Dlsym { @@ -15,7 +20,11 @@ impl Dlsym { pub fn from_str(name: &str) -> InterpResult<'static, Option> { Ok(match name { "AcquireSRWLockExclusive" => Some(Dlsym::AcquireSRWLockExclusive), + "ReleaseSRWLockExclusive" => Some(Dlsym::ReleaseSRWLockExclusive), + "TryAcquireSRWLockExclusive" => Some(Dlsym::TryAcquireSRWLockExclusive), "AcquireSRWLockShared" => Some(Dlsym::AcquireSRWLockShared), + "ReleaseSRWLockShared" => Some(Dlsym::ReleaseSRWLockShared), + "TryAcquireSRWLockShared" => Some(Dlsym::TryAcquireSRWLockShared), "SetThreadStackGuarantee" => None, "GetSystemTimePreciseAsFileTime" => None, _ => throw_unsup_format!("unsupported Windows dlsym: {}", name), @@ -38,13 +47,29 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx match dlsym { Dlsym::AcquireSRWLockExclusive => { let &[ptr] = check_arg_count(args)?; - let lock = this.deref_operand(ptr)?; // points to ptr-sized data - throw_unsup_format!("AcquireSRWLockExclusive is not actually implemented"); + this.AcquireSRWLockExclusive(ptr)?; + } + Dlsym::ReleaseSRWLockExclusive => { + let &[ptr] = check_arg_count(args)?; + this.ReleaseSRWLockExclusive(ptr)?; + } + Dlsym::TryAcquireSRWLockExclusive => { + let &[ptr] = check_arg_count(args)?; + let ret = this.TryAcquireSRWLockExclusive(ptr)?; + this.write_scalar(Scalar::from_u8(ret), dest)?; } Dlsym::AcquireSRWLockShared => { let &[ptr] = check_arg_count(args)?; - let lock = this.deref_operand(ptr)?; // points to ptr-sized data - throw_unsup_format!("AcquireSRWLockExclusive is not actually implemented"); + this.AcquireSRWLockShared(ptr)?; + } + Dlsym::ReleaseSRWLockShared => { + let &[ptr] = check_arg_count(args)?; + this.ReleaseSRWLockShared(ptr)?; + } + Dlsym::TryAcquireSRWLockShared => { + let &[ptr] = check_arg_count(args)?; + let ret = this.TryAcquireSRWLockShared(ptr)?; + this.write_scalar(Scalar::from_u8(ret), dest)?; } } diff --git a/src/shims/windows/foreign_items.rs b/src/shims/windows/foreign_items.rs index 2a30a23489970..ddb70b752e794 100644 --- a/src/shims/windows/foreign_items.rs +++ b/src/shims/windows/foreign_items.rs @@ -21,6 +21,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // HANDLE = isize // DWORD = ULONG = u32 // BOOL = i32 + // BOOLEAN = u8 match link_name { // Environment related shims "GetEnvironmentVariableW" => { @@ -301,7 +302,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx #[allow(non_snake_case)] let &[_lpCriticalSection] = check_arg_count(args)?; assert_eq!(this.get_total_thread_count(), 1, "concurrency on Windows not supported"); - // There is only one thread, so this always succeeds and returns TRUE + // There is only one thread, so this always succeeds and returns TRUE. this.write_scalar(Scalar::from_i32(1), dest)?; } diff --git a/src/shims/windows/sync.rs b/src/shims/windows/sync.rs index e69de29bb2d1d..ef40eb0891104 100644 --- a/src/shims/windows/sync.rs +++ b/src/shims/windows/sync.rs @@ -0,0 +1,161 @@ +use rustc_target::abi::Size; + +use crate::*; + +// Locks are pointer-sized pieces of data, initialized to 0. +// We use them to count readers, with usize::MAX representing the write-locked state. + +fn deref_lock<'mir, 'tcx: 'mir>( + ecx: &mut MiriEvalContext<'mir, 'tcx>, + lock_op: OpTy<'tcx, Tag>, +) -> InterpResult<'tcx, MPlaceTy<'tcx, Tag>> { + // `lock` is a pointer to `void*`; cast it to a pointer to `usize`. + let lock = ecx.deref_operand(lock_op)?; + let usize = ecx.machine.layouts.usize; + assert_eq!(lock.layout.size, usize.size); + Ok(lock.offset(Size::ZERO, MemPlaceMeta::None, usize, ecx)?) +} + +impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} +pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { + #[allow(non_snake_case)] + fn AcquireSRWLockExclusive( + &mut self, + lock_op: OpTy<'tcx, Tag>, + ) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + assert_eq!(this.get_total_thread_count(), 1, "concurrency on Windows is not supported"); + + let lock = deref_lock(this, lock_op)?; + let lock_val = this.read_scalar(lock.into())?.to_machine_usize(this)?; + if lock_val == 0 { + // Currently not locked. Lock it. + let new_val = Scalar::from_machine_usize(this.machine_usize_max(), this); + this.write_scalar(new_val, lock.into())?; + } else { + // Lock is already held. This is a deadlock. + throw_machine_stop!(TerminationInfo::Deadlock); + } + + Ok(()) + } + + #[allow(non_snake_case)] + fn TryAcquireSRWLockExclusive( + &mut self, + lock_op: OpTy<'tcx, Tag>, + ) -> InterpResult<'tcx, u8> { + let this = self.eval_context_mut(); + assert_eq!(this.get_total_thread_count(), 1, "concurrency on Windows is not supported"); + + let lock = deref_lock(this, lock_op)?; + let lock_val = this.read_scalar(lock.into())?.to_machine_usize(this)?; + if lock_val == 0 { + // Currently not locked. Lock it. + let new_val = this.machine_usize_max(); + this.write_scalar(Scalar::from_machine_usize(new_val, this), lock.into())?; + Ok(1) + } else { + // Lock is already held. + Ok(0) + } + } + + #[allow(non_snake_case)] + fn ReleaseSRWLockExclusive( + &mut self, + lock_op: OpTy<'tcx, Tag>, + ) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + assert_eq!(this.get_total_thread_count(), 1, "concurrency on Windows is not supported"); + + let lock = deref_lock(this, lock_op)?; + let lock_val = this.read_scalar(lock.into())?.to_machine_usize(this)?; + if lock_val == this.machine_usize_max() { + // Currently locked. Unlock it. + let new_val = 0; + this.write_scalar(Scalar::from_machine_usize(new_val, this), lock.into())?; + } else { + // Lock is not locked. + throw_ub_format!("calling ReleaseSRWLockExclusive on an SRWLock that is not exclusively locked"); + } + + Ok(()) + } + + #[allow(non_snake_case)] + fn AcquireSRWLockShared( + &mut self, + lock_op: OpTy<'tcx, Tag>, + ) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + assert_eq!(this.get_total_thread_count(), 1, "concurrency on Windows is not supported"); + + let lock = deref_lock(this, lock_op)?; + let lock_val = this.read_scalar(lock.into())?.to_machine_usize(this)?; + if lock_val == this.machine_usize_max() { + // Currently write locked. This is a deadlock. + throw_machine_stop!(TerminationInfo::Deadlock); + } else { + // Bump up read counter (cannot overflow as we just checkd against usize::MAX); + let new_val = lock_val+1; + // Make sure this does not reach the "write locked" flag. + if new_val == this.machine_usize_max() { + throw_unsup_format!("SRWLock read-acquired too many times"); + } + this.write_scalar(Scalar::from_machine_usize(new_val, this), lock.into())?; + } + + Ok(()) + } + + #[allow(non_snake_case)] + fn TryAcquireSRWLockShared( + &mut self, + lock_op: OpTy<'tcx, Tag>, + ) -> InterpResult<'tcx, u8> { + let this = self.eval_context_mut(); + assert_eq!(this.get_total_thread_count(), 1, "concurrency on Windows is not supported"); + + let lock = deref_lock(this, lock_op)?; + let lock_val = this.read_scalar(lock.into())?.to_machine_usize(this)?; + if lock_val == this.machine_usize_max() { + // Currently write locked. + Ok(0) + } else { + // Bump up read counter (cannot overflow as we just checkd against usize::MAX); + let new_val = lock_val+1; + // Make sure this does not reach the "write locked" flag. + if new_val == this.machine_usize_max() { + throw_unsup_format!("SRWLock read-acquired too many times"); + } + this.write_scalar(Scalar::from_machine_usize(new_val, this), lock.into())?; + Ok(1) + } + } + + #[allow(non_snake_case)] + fn ReleaseSRWLockShared( + &mut self, + lock_op: OpTy<'tcx, Tag>, + ) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + assert_eq!(this.get_total_thread_count(), 1, "concurrency on Windows is not supported"); + + let lock = deref_lock(this, lock_op)?; + let lock_val = this.read_scalar(lock.into())?.to_machine_usize(this)?; + if lock_val == this.machine_usize_max() { + // Currently write locked. This is a UB. + throw_ub_format!("calling ReleaseSRWLockShared on write-locked SRWLock"); + } else if lock_val == 0 { + // Currently not locked at all. + throw_ub_format!("calling ReleaseSRWLockShared on unlocked SRWLock"); + } else { + // Decrement read counter (cannot overflow as we just checkd against 0); + let new_val = lock_val-1; + this.write_scalar(Scalar::from_machine_usize(new_val, this), lock.into())?; + } + + Ok(()) + } +} From e54619b5e18ce9781faed975f5101db621608ea0 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 27 Jun 2020 14:43:37 +0200 Subject: [PATCH 2152/3747] with this, we support panics on Windows --- src/shims/foreign_items.rs | 1 - src/shims/mod.rs | 8 -------- src/shims/panic.rs | 8 -------- tests/compile-fail/abort-terminator.rs | 1 - tests/compile-fail/panic/double_panic.rs | 1 - tests/compile-fail/panic/windows1.rs | 9 --------- tests/compile-fail/panic/windows2.rs | 9 --------- tests/compile-fail/panic/windows3.rs | 10 ---------- tests/run-pass/panic/catch_panic.rs | 2 +- tests/run-pass/panic/div-by-zero-2.rs | 1 - tests/run-pass/panic/div-by-zero-2.stderr | 2 +- tests/run-pass/panic/overflowing-lsh-neg.rs | 1 - tests/run-pass/panic/overflowing-lsh-neg.stderr | 2 +- tests/run-pass/panic/overflowing-rsh-1.rs | 1 - tests/run-pass/panic/overflowing-rsh-1.stderr | 2 +- tests/run-pass/panic/overflowing-rsh-2.rs | 1 - tests/run-pass/panic/overflowing-rsh-2.stderr | 2 +- tests/run-pass/panic/panic1.rs | 1 - tests/run-pass/panic/panic1.stderr | 2 +- tests/run-pass/panic/panic2.rs | 1 - tests/run-pass/panic/panic2.stderr | 2 +- tests/run-pass/panic/panic3.rs | 1 - tests/run-pass/panic/panic3.stderr | 2 +- tests/run-pass/panic/panic4.rs | 1 - tests/run-pass/panic/panic4.stderr | 2 +- tests/run-pass/panic/std-panic-locations.rs | 1 - tests/run-pass/transmute_fat2.rs | 1 - tests/run-pass/transmute_fat2.stderr | 2 +- 28 files changed, 10 insertions(+), 67 deletions(-) delete mode 100644 tests/compile-fail/panic/windows1.rs delete mode 100644 tests/compile-fail/panic/windows2.rs delete mode 100644 tests/compile-fail/panic/windows3.rs diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 14c5aac4899a7..a7495beef72ee 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -129,7 +129,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // This matches calls to the foreign item `panic_impl`. // The implementation is provided by the function with the `#[panic_handler]` attribute. "panic_impl" => { - this.check_panic_supported()?; let panic_impl_id = tcx.lang_items().panic_impl().unwrap(); let panic_impl_instance = ty::Instance::mono(tcx, panic_impl_id); return Ok(Some(&*this.load_mir(panic_impl_instance.def, None)?)); diff --git a/src/shims/mod.rs b/src/shims/mod.rs index 37e7b8c40462e..56754a9ebde55 100644 --- a/src/shims/mod.rs +++ b/src/shims/mod.rs @@ -52,14 +52,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx return this.emulate_foreign_item(instance.def_id(), args, ret, unwind); } - // Better error message for panics on Windows. - let def_id = instance.def_id(); - if Some(def_id) == this.tcx.lang_items().begin_panic_fn() || - Some(def_id) == this.tcx.lang_items().panic_impl() - { - this.check_panic_supported()?; - } - // Otherwise, load the MIR. Ok(Some(&*this.load_mir(instance.def, None)?)) } diff --git a/src/shims/panic.rs b/src/shims/panic.rs index 43f90f1b04f73..8e291c2012152 100644 --- a/src/shims/panic.rs +++ b/src/shims/panic.rs @@ -34,14 +34,6 @@ pub struct CatchUnwindData<'tcx> { impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { - /// Check if panicking is supported on this target, and give a good error otherwise. - fn check_panic_supported(&self) -> InterpResult<'tcx> { - match self.eval_context_ref().tcx.sess.target.target.target_os.as_str() { - "linux" | "macos" => Ok(()), - _ => throw_unsup_format!("panicking is not supported on this target"), - } - } - /// Handles the special `miri_start_panic` intrinsic, which is called /// by libpanic_unwind to delegate the actual unwinding process to Miri. fn handle_miri_start_panic( diff --git a/tests/compile-fail/abort-terminator.rs b/tests/compile-fail/abort-terminator.rs index af1a155435fb6..1bfa289a52b4e 100644 --- a/tests/compile-fail/abort-terminator.rs +++ b/tests/compile-fail/abort-terminator.rs @@ -1,5 +1,4 @@ // error-pattern: the evaluated program aborted -// ignore-windows (panics dont work on Windows) #![feature(unwind_attributes)] #[unwind(aborts)] diff --git a/tests/compile-fail/panic/double_panic.rs b/tests/compile-fail/panic/double_panic.rs index 3085d0b006570..80d74f026232e 100644 --- a/tests/compile-fail/panic/double_panic.rs +++ b/tests/compile-fail/panic/double_panic.rs @@ -1,5 +1,4 @@ // error-pattern: the evaluated program aborted -// ignore-windows (panics dont work on Windows) struct Foo; impl Drop for Foo { diff --git a/tests/compile-fail/panic/windows1.rs b/tests/compile-fail/panic/windows1.rs deleted file mode 100644 index 142ba85c42c77..0000000000000 --- a/tests/compile-fail/panic/windows1.rs +++ /dev/null @@ -1,9 +0,0 @@ -// ignore-linux -// ignore-macos - -// Test that panics on Windows give a reasonable error message. - -// error-pattern: panicking is not supported on this target -fn main() { - core::panic!("this is {}", "Windows"); -} diff --git a/tests/compile-fail/panic/windows2.rs b/tests/compile-fail/panic/windows2.rs deleted file mode 100644 index da2cfb59362ef..0000000000000 --- a/tests/compile-fail/panic/windows2.rs +++ /dev/null @@ -1,9 +0,0 @@ -// ignore-linux -// ignore-macos - -// Test that panics on Windows give a reasonable error message. - -// error-pattern: panicking is not supported on this target -fn main() { - std::panic!("this is Windows"); -} diff --git a/tests/compile-fail/panic/windows3.rs b/tests/compile-fail/panic/windows3.rs deleted file mode 100644 index a2e7bf5a7d438..0000000000000 --- a/tests/compile-fail/panic/windows3.rs +++ /dev/null @@ -1,10 +0,0 @@ -// ignore-linux -// ignore-macos - -// Test that panics on Windows give a reasonable error message. - -// error-pattern: panicking is not supported on this target -#[allow(unconditional_panic)] -fn main() { - let _val = 1/0; -} diff --git a/tests/run-pass/panic/catch_panic.rs b/tests/run-pass/panic/catch_panic.rs index 288ae1965a69d..ac41de586e8a7 100644 --- a/tests/run-pass/panic/catch_panic.rs +++ b/tests/run-pass/panic/catch_panic.rs @@ -1,7 +1,7 @@ -// ignore-windows: Unwind panicking does not currently work on Windows // normalize-stderr-test "[^ ]*libcore/[a-z/]+.rs[0-9:]*" -> "$$LOC" #![feature(never_type)] #![allow(unconditional_panic)] + use std::panic::{catch_unwind, AssertUnwindSafe}; use std::cell::Cell; diff --git a/tests/run-pass/panic/div-by-zero-2.rs b/tests/run-pass/panic/div-by-zero-2.rs index cfacc9db0d666..fac5415696fc6 100644 --- a/tests/run-pass/panic/div-by-zero-2.rs +++ b/tests/run-pass/panic/div-by-zero-2.rs @@ -1,4 +1,3 @@ -// ignore-windows: Unwind panicking does not currently work on Windows #![allow(unconditional_panic)] fn main() { diff --git a/tests/run-pass/panic/div-by-zero-2.stderr b/tests/run-pass/panic/div-by-zero-2.stderr index 77dca2aac1e28..d255811be2a94 100644 --- a/tests/run-pass/panic/div-by-zero-2.stderr +++ b/tests/run-pass/panic/div-by-zero-2.stderr @@ -1 +1 @@ -thread 'main' panicked at 'attempt to divide by zero', $DIR/div-by-zero-2.rs:5:14 +thread 'main' panicked at 'attempt to divide by zero', $DIR/div-by-zero-2.rs:4:14 diff --git a/tests/run-pass/panic/overflowing-lsh-neg.rs b/tests/run-pass/panic/overflowing-lsh-neg.rs index ee15ca0284ef3..bf5eed1c550f1 100644 --- a/tests/run-pass/panic/overflowing-lsh-neg.rs +++ b/tests/run-pass/panic/overflowing-lsh-neg.rs @@ -1,4 +1,3 @@ -// ignore-windows: Unwind panicking does not currently work on Windows #![allow(arithmetic_overflow)] fn main() { diff --git a/tests/run-pass/panic/overflowing-lsh-neg.stderr b/tests/run-pass/panic/overflowing-lsh-neg.stderr index e1e7daa119abd..04d98a0a2f155 100644 --- a/tests/run-pass/panic/overflowing-lsh-neg.stderr +++ b/tests/run-pass/panic/overflowing-lsh-neg.stderr @@ -1 +1 @@ -thread 'main' panicked at 'attempt to shift left with overflow', $DIR/overflowing-lsh-neg.rs:5:14 +thread 'main' panicked at 'attempt to shift left with overflow', $DIR/overflowing-lsh-neg.rs:4:14 diff --git a/tests/run-pass/panic/overflowing-rsh-1.rs b/tests/run-pass/panic/overflowing-rsh-1.rs index 36ab948a5efa0..4c0106f0fb1fd 100644 --- a/tests/run-pass/panic/overflowing-rsh-1.rs +++ b/tests/run-pass/panic/overflowing-rsh-1.rs @@ -1,4 +1,3 @@ -// ignore-windows: Unwind panicking does not currently work on Windows #![allow(arithmetic_overflow)] fn main() { diff --git a/tests/run-pass/panic/overflowing-rsh-1.stderr b/tests/run-pass/panic/overflowing-rsh-1.stderr index 20a45739ae2e6..a9a72f46222df 100644 --- a/tests/run-pass/panic/overflowing-rsh-1.stderr +++ b/tests/run-pass/panic/overflowing-rsh-1.stderr @@ -1 +1 @@ -thread 'main' panicked at 'attempt to shift right with overflow', $DIR/overflowing-rsh-1.rs:5:14 +thread 'main' panicked at 'attempt to shift right with overflow', $DIR/overflowing-rsh-1.rs:4:14 diff --git a/tests/run-pass/panic/overflowing-rsh-2.rs b/tests/run-pass/panic/overflowing-rsh-2.rs index 27cc65fa7685b..19d16e7bc84a2 100644 --- a/tests/run-pass/panic/overflowing-rsh-2.rs +++ b/tests/run-pass/panic/overflowing-rsh-2.rs @@ -1,4 +1,3 @@ -// ignore-windows: Unwind panicking does not currently work on Windows #![allow(arithmetic_overflow)] fn main() { diff --git a/tests/run-pass/panic/overflowing-rsh-2.stderr b/tests/run-pass/panic/overflowing-rsh-2.stderr index 3381116ae6c85..24b61194565dd 100644 --- a/tests/run-pass/panic/overflowing-rsh-2.stderr +++ b/tests/run-pass/panic/overflowing-rsh-2.stderr @@ -1 +1 @@ -thread 'main' panicked at 'attempt to shift right with overflow', $DIR/overflowing-rsh-2.rs:6:14 +thread 'main' panicked at 'attempt to shift right with overflow', $DIR/overflowing-rsh-2.rs:5:14 diff --git a/tests/run-pass/panic/panic1.rs b/tests/run-pass/panic/panic1.rs index 61321c658166f..9d9ad28df5a71 100644 --- a/tests/run-pass/panic/panic1.rs +++ b/tests/run-pass/panic/panic1.rs @@ -1,4 +1,3 @@ -// ignore-windows: Unwind panicking does not currently work on Windows fn main() { std::panic!("panicking from libstd"); } diff --git a/tests/run-pass/panic/panic1.stderr b/tests/run-pass/panic/panic1.stderr index 305fc1a1a6e66..954b8799a0823 100644 --- a/tests/run-pass/panic/panic1.stderr +++ b/tests/run-pass/panic/panic1.stderr @@ -1 +1 @@ -thread 'main' panicked at 'panicking from libstd', $DIR/panic1.rs:3:5 +thread 'main' panicked at 'panicking from libstd', $DIR/panic1.rs:2:5 diff --git a/tests/run-pass/panic/panic2.rs b/tests/run-pass/panic/panic2.rs index d6ab864795eaf..d90e3f2e0ac13 100644 --- a/tests/run-pass/panic/panic2.rs +++ b/tests/run-pass/panic/panic2.rs @@ -1,4 +1,3 @@ -// ignore-windows: Unwind panicking does not currently work on Windows fn main() { std::panic!("{}-panicking from libstd", 42); } diff --git a/tests/run-pass/panic/panic2.stderr b/tests/run-pass/panic/panic2.stderr index cd40559c81ef1..e90e3502cbfbf 100644 --- a/tests/run-pass/panic/panic2.stderr +++ b/tests/run-pass/panic/panic2.stderr @@ -1 +1 @@ -thread 'main' panicked at '42-panicking from libstd', $DIR/panic2.rs:3:5 +thread 'main' panicked at '42-panicking from libstd', $DIR/panic2.rs:2:5 diff --git a/tests/run-pass/panic/panic3.rs b/tests/run-pass/panic/panic3.rs index 10a42c7e6c00f..418ee4f8411eb 100644 --- a/tests/run-pass/panic/panic3.rs +++ b/tests/run-pass/panic/panic3.rs @@ -1,4 +1,3 @@ -// ignore-windows: Unwind panicking does not currently work on Windows fn main() { core::panic!("panicking from libcore"); } diff --git a/tests/run-pass/panic/panic3.stderr b/tests/run-pass/panic/panic3.stderr index e3aa902f0cbc9..0a3c191b282ec 100644 --- a/tests/run-pass/panic/panic3.stderr +++ b/tests/run-pass/panic/panic3.stderr @@ -1 +1 @@ -thread 'main' panicked at 'panicking from libcore', $DIR/panic3.rs:3:5 +thread 'main' panicked at 'panicking from libcore', $DIR/panic3.rs:2:5 diff --git a/tests/run-pass/panic/panic4.rs b/tests/run-pass/panic/panic4.rs index 06e2dd008fff8..0fcc53813b5d7 100644 --- a/tests/run-pass/panic/panic4.rs +++ b/tests/run-pass/panic/panic4.rs @@ -1,4 +1,3 @@ -// ignore-windows: Unwind panicking does not currently work on Windows fn main() { core::panic!("{}-panicking from libcore", 42); } diff --git a/tests/run-pass/panic/panic4.stderr b/tests/run-pass/panic/panic4.stderr index 1a242a868cae1..946059b1e49fc 100644 --- a/tests/run-pass/panic/panic4.stderr +++ b/tests/run-pass/panic/panic4.stderr @@ -1 +1 @@ -thread 'main' panicked at '42-panicking from libcore', $DIR/panic4.rs:3:5 +thread 'main' panicked at '42-panicking from libcore', $DIR/panic4.rs:2:5 diff --git a/tests/run-pass/panic/std-panic-locations.rs b/tests/run-pass/panic/std-panic-locations.rs index d5f38fc2672e7..ac2e8d5305dfe 100644 --- a/tests/run-pass/panic/std-panic-locations.rs +++ b/tests/run-pass/panic/std-panic-locations.rs @@ -1,4 +1,3 @@ -// ignore-windows: Unwind panicking does not currently work on Windows #![feature(option_expect_none, option_unwrap_none)] //! Test that panic locations for `#[track_caller]` functions in std have the correct //! location reported. diff --git a/tests/run-pass/transmute_fat2.rs b/tests/run-pass/transmute_fat2.rs index c667aab6bb5fd..3dff2cc1e0c93 100644 --- a/tests/run-pass/transmute_fat2.rs +++ b/tests/run-pass/transmute_fat2.rs @@ -1,4 +1,3 @@ -// ignore-windows: Unwind panicking does not currently work on Windows fn main() { #[cfg(target_pointer_width="64")] let bad = unsafe { diff --git a/tests/run-pass/transmute_fat2.stderr b/tests/run-pass/transmute_fat2.stderr index 2539e58814d6b..08849a5b517a4 100644 --- a/tests/run-pass/transmute_fat2.stderr +++ b/tests/run-pass/transmute_fat2.stderr @@ -1 +1 @@ -thread 'main' panicked at 'index out of bounds: the len is 0 but the index is 0', $DIR/transmute_fat2.rs:12:5 +thread 'main' panicked at 'index out of bounds: the len is 0 but the index is 0', $DIR/transmute_fat2.rs:11:5 From a9dc2796cac8d49f67f6055d3fe3561a13f604b7 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 28 Jun 2020 09:23:01 +0200 Subject: [PATCH 2153/3747] Move get/set_at_offset helpers to global helpers file --- src/helpers.rs | 31 +++++++++++++++ src/shims/posix/sync.rs | 84 +++++++---------------------------------- 2 files changed, 45 insertions(+), 70 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index 4e5e0dcfca256..c1eaf4eb4865d 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -467,6 +467,37 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } } + + fn read_scalar_at_offset( + &self, + op: OpTy<'tcx, Tag>, + offset: u64, + layout: TyAndLayout<'tcx>, + ) -> InterpResult<'tcx, ScalarMaybeUninit> { + let this = self.eval_context_ref(); + let op_place = this.deref_operand(op)?; + let offset = Size::from_bytes(offset); + // Ensure that the following read at an offset is within bounds + assert!(op_place.layout.size >= offset + layout.size); + let value_place = op_place.offset(offset, MemPlaceMeta::None, layout, this)?; + this.read_scalar(value_place.into()) + } + + fn write_scalar_at_offset( + &mut self, + op: OpTy<'tcx, Tag>, + offset: u64, + value: impl Into>, + layout: TyAndLayout<'tcx>, + ) -> InterpResult<'tcx, ()> { + let this = self.eval_context_mut(); + let op_place = this.deref_operand(op)?; + let offset = Size::from_bytes(offset); + // Ensure that the following read at an offset is within bounds + assert!(op_place.layout.size >= offset + layout.size); + let value_place = op_place.offset(offset, MemPlaceMeta::None, layout, this)?; + this.write_scalar(value, value_place.into()) + } } /// Check that the number of args is what we expect. diff --git a/src/shims/posix/sync.rs b/src/shims/posix/sync.rs index a61c80d5118c4..bc4be56557a49 100644 --- a/src/shims/posix/sync.rs +++ b/src/shims/posix/sync.rs @@ -2,57 +2,11 @@ use std::convert::TryInto; use std::time::{Duration, SystemTime}; use std::ops::Not; -use rustc_middle::ty::{layout::TyAndLayout, TyKind, TypeAndMut}; -use rustc_target::abi::{LayoutOf, Size}; - use crate::*; use stacked_borrows::Tag; use thread::Time; -fn assert_ptr_target_min_size<'mir, 'tcx: 'mir>( - ecx: &MiriEvalContext<'mir, 'tcx>, - operand: OpTy<'tcx, Tag>, - min_size: u64, -) -> InterpResult<'tcx, ()> { - let target_ty = match operand.layout.ty.kind { - TyKind::RawPtr(TypeAndMut { ty, mutbl: _ }) => ty, - _ => panic!("Argument to pthread function was not a raw pointer"), - }; - let target_layout = ecx.layout_of(target_ty)?; - assert!(target_layout.size.bytes() >= min_size); - Ok(()) -} - -fn get_at_offset<'mir, 'tcx: 'mir>( - ecx: &MiriEvalContext<'mir, 'tcx>, - op: OpTy<'tcx, Tag>, - offset: u64, - layout: TyAndLayout<'tcx>, - min_size: u64, -) -> InterpResult<'tcx, ScalarMaybeUninit> { - // Ensure that the following read at an offset to the attr pointer is within bounds - assert_ptr_target_min_size(ecx, op, min_size)?; - let op_place = ecx.deref_operand(op)?; - let value_place = op_place.offset(Size::from_bytes(offset), MemPlaceMeta::None, layout, ecx)?; - ecx.read_scalar(value_place.into()) -} - -fn set_at_offset<'mir, 'tcx: 'mir>( - ecx: &mut MiriEvalContext<'mir, 'tcx>, - op: OpTy<'tcx, Tag>, - offset: u64, - value: impl Into>, - layout: TyAndLayout<'tcx>, - min_size: u64, -) -> InterpResult<'tcx, ()> { - // Ensure that the following write at an offset to the attr pointer is within bounds - assert_ptr_target_min_size(ecx, op, min_size)?; - let op_place = ecx.deref_operand(op)?; - let value_place = op_place.offset(Size::from_bytes(offset), MemPlaceMeta::None, layout, ecx)?; - ecx.write_scalar(value.into(), value_place.into()) -} - // pthread_mutexattr_t is either 4 or 8 bytes, depending on the platform. // Our chosen memory layout for emulation (does not have to match the platform layout!): @@ -66,8 +20,6 @@ fn set_at_offset<'mir, 'tcx: 'mir>( /// in `pthread_mutexattr_settype` function. const PTHREAD_MUTEX_NORMAL_FLAG: i32 = 0x8000000; -const PTHREAD_MUTEXATTR_T_MIN_SIZE: u64 = 4; - fn is_mutex_kind_default<'mir, 'tcx: 'mir>( ecx: &mut MiriEvalContext<'mir, 'tcx>, kind: Scalar, @@ -88,7 +40,7 @@ fn mutexattr_get_kind<'mir, 'tcx: 'mir>( ecx: &MiriEvalContext<'mir, 'tcx>, attr_op: OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, ScalarMaybeUninit> { - get_at_offset(ecx, attr_op, 0, ecx.machine.layouts.i32, PTHREAD_MUTEXATTR_T_MIN_SIZE) + ecx.read_scalar_at_offset(attr_op, 0, ecx.machine.layouts.i32) } fn mutexattr_set_kind<'mir, 'tcx: 'mir>( @@ -96,7 +48,7 @@ fn mutexattr_set_kind<'mir, 'tcx: 'mir>( attr_op: OpTy<'tcx, Tag>, kind: impl Into>, ) -> InterpResult<'tcx, ()> { - set_at_offset(ecx, attr_op, 0, kind, ecx.machine.layouts.i32, PTHREAD_MUTEXATTR_T_MIN_SIZE) + ecx.write_scalar_at_offset(attr_op, 0, kind, ecx.machine.layouts.i32) } // pthread_mutex_t is between 24 and 48 bytes, depending on the platform. @@ -108,14 +60,12 @@ fn mutexattr_set_kind<'mir, 'tcx: 'mir>( // bytes 12-15 or 16-19 (depending on platform): mutex kind, as an i32 // (the kind has to be at its offset for compatibility with static initializer macros) -const PTHREAD_MUTEX_T_MIN_SIZE: u64 = 24; - fn mutex_get_kind<'mir, 'tcx: 'mir>( ecx: &mut MiriEvalContext<'mir, 'tcx>, mutex_op: OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, ScalarMaybeUninit> { let offset = if ecx.pointer_size().bytes() == 8 { 16 } else { 12 }; - get_at_offset(ecx, mutex_op, offset, ecx.machine.layouts.i32, PTHREAD_MUTEX_T_MIN_SIZE) + ecx.read_scalar_at_offset(mutex_op, offset, ecx.machine.layouts.i32) } fn mutex_set_kind<'mir, 'tcx: 'mir>( @@ -124,14 +74,14 @@ fn mutex_set_kind<'mir, 'tcx: 'mir>( kind: impl Into>, ) -> InterpResult<'tcx, ()> { let offset = if ecx.pointer_size().bytes() == 8 { 16 } else { 12 }; - set_at_offset(ecx, mutex_op, offset, kind, ecx.machine.layouts.i32, PTHREAD_MUTEX_T_MIN_SIZE) + ecx.write_scalar_at_offset(mutex_op, offset, kind, ecx.machine.layouts.i32) } fn mutex_get_id<'mir, 'tcx: 'mir>( ecx: &MiriEvalContext<'mir, 'tcx>, mutex_op: OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, ScalarMaybeUninit> { - get_at_offset(ecx, mutex_op, 4, ecx.machine.layouts.u32, PTHREAD_MUTEX_T_MIN_SIZE) + ecx.read_scalar_at_offset(mutex_op, 4, ecx.machine.layouts.u32) } fn mutex_set_id<'mir, 'tcx: 'mir>( @@ -139,7 +89,7 @@ fn mutex_set_id<'mir, 'tcx: 'mir>( mutex_op: OpTy<'tcx, Tag>, id: impl Into>, ) -> InterpResult<'tcx, ()> { - set_at_offset(ecx, mutex_op, 4, id, ecx.machine.layouts.u32, PTHREAD_MUTEX_T_MIN_SIZE) + ecx.write_scalar_at_offset(mutex_op, 4, id, ecx.machine.layouts.u32) } fn mutex_get_or_create_id<'mir, 'tcx: 'mir>( @@ -165,13 +115,11 @@ fn mutex_get_or_create_id<'mir, 'tcx: 'mir>( // (need to avoid this because it is set by static initializer macros) // bytes 4-7: rwlock id as u32 or 0 if id is not assigned yet. -const PTHREAD_RWLOCK_T_MIN_SIZE: u64 = 32; - fn rwlock_get_id<'mir, 'tcx: 'mir>( ecx: &MiriEvalContext<'mir, 'tcx>, rwlock_op: OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, ScalarMaybeUninit> { - get_at_offset(ecx, rwlock_op, 4, ecx.machine.layouts.u32, PTHREAD_RWLOCK_T_MIN_SIZE) + ecx.read_scalar_at_offset(rwlock_op, 4, ecx.machine.layouts.u32) } fn rwlock_set_id<'mir, 'tcx: 'mir>( @@ -179,7 +127,7 @@ fn rwlock_set_id<'mir, 'tcx: 'mir>( rwlock_op: OpTy<'tcx, Tag>, id: impl Into>, ) -> InterpResult<'tcx, ()> { - set_at_offset(ecx, rwlock_op, 4, id, ecx.machine.layouts.u32, PTHREAD_RWLOCK_T_MIN_SIZE) + ecx.write_scalar_at_offset(rwlock_op, 4, id, ecx.machine.layouts.u32) } fn rwlock_get_or_create_id<'mir, 'tcx: 'mir>( @@ -204,13 +152,11 @@ fn rwlock_get_or_create_id<'mir, 'tcx: 'mir>( // store an i32 in the first four bytes equal to the corresponding libc clock id constant // (e.g. CLOCK_REALTIME). -const PTHREAD_CONDATTR_T_MIN_SIZE: u64 = 4; - fn condattr_get_clock_id<'mir, 'tcx: 'mir>( ecx: &MiriEvalContext<'mir, 'tcx>, attr_op: OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, ScalarMaybeUninit> { - get_at_offset(ecx, attr_op, 0, ecx.machine.layouts.i32, PTHREAD_CONDATTR_T_MIN_SIZE) + ecx.read_scalar_at_offset(attr_op, 0, ecx.machine.layouts.i32) } fn condattr_set_clock_id<'mir, 'tcx: 'mir>( @@ -218,7 +164,7 @@ fn condattr_set_clock_id<'mir, 'tcx: 'mir>( attr_op: OpTy<'tcx, Tag>, clock_id: impl Into>, ) -> InterpResult<'tcx, ()> { - set_at_offset(ecx, attr_op, 0, clock_id, ecx.machine.layouts.i32, PTHREAD_CONDATTR_T_MIN_SIZE) + ecx.write_scalar_at_offset(attr_op, 0, clock_id, ecx.machine.layouts.i32) } // pthread_cond_t @@ -230,13 +176,11 @@ fn condattr_set_clock_id<'mir, 'tcx: 'mir>( // bytes 4-7: the conditional variable id as u32 or 0 if id is not assigned yet. // bytes 8-11: the clock id constant as i32 -const PTHREAD_COND_T_MIN_SIZE: u64 = 12; - fn cond_get_id<'mir, 'tcx: 'mir>( ecx: &MiriEvalContext<'mir, 'tcx>, cond_op: OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, ScalarMaybeUninit> { - get_at_offset(ecx, cond_op, 4, ecx.machine.layouts.u32, PTHREAD_COND_T_MIN_SIZE) + ecx.read_scalar_at_offset(cond_op, 4, ecx.machine.layouts.u32) } fn cond_set_id<'mir, 'tcx: 'mir>( @@ -244,7 +188,7 @@ fn cond_set_id<'mir, 'tcx: 'mir>( cond_op: OpTy<'tcx, Tag>, id: impl Into>, ) -> InterpResult<'tcx, ()> { - set_at_offset(ecx, cond_op, 4, id, ecx.machine.layouts.u32, PTHREAD_COND_T_MIN_SIZE) + ecx.write_scalar_at_offset(cond_op, 4, id, ecx.machine.layouts.u32) } fn cond_get_or_create_id<'mir, 'tcx: 'mir>( @@ -267,7 +211,7 @@ fn cond_get_clock_id<'mir, 'tcx: 'mir>( ecx: &MiriEvalContext<'mir, 'tcx>, cond_op: OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, ScalarMaybeUninit> { - get_at_offset(ecx, cond_op, 8, ecx.machine.layouts.i32, PTHREAD_COND_T_MIN_SIZE) + ecx.read_scalar_at_offset(cond_op, 8, ecx.machine.layouts.i32) } fn cond_set_clock_id<'mir, 'tcx: 'mir>( @@ -275,7 +219,7 @@ fn cond_set_clock_id<'mir, 'tcx: 'mir>( cond_op: OpTy<'tcx, Tag>, clock_id: impl Into>, ) -> InterpResult<'tcx, ()> { - set_at_offset(ecx, cond_op, 8, clock_id, ecx.machine.layouts.i32, PTHREAD_COND_T_MIN_SIZE) + ecx.write_scalar_at_offset(cond_op, 8, clock_id, ecx.machine.layouts.i32) } /// Try to reacquire the mutex associated with the condition variable after we From 3a5bcb97edd5bab769341aacde18a05c015aa396 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 28 Jun 2020 09:47:20 +0200 Subject: [PATCH 2154/3747] move rwlock dequeuing to shared code, and use that code for Windows rwlocks --- src/shims/posix/sync.rs | 22 +-- src/shims/windows/foreign_items.rs | 6 +- src/shims/windows/sync.rs | 134 ++++++-------- src/sync.rs | 165 +++++++++++------- .../compile-fail/concurrency/thread-spawn.rs | 2 +- 5 files changed, 164 insertions(+), 165 deletions(-) diff --git a/src/shims/posix/sync.rs b/src/shims/posix/sync.rs index bc4be56557a49..cce0ddc930df0 100644 --- a/src/shims/posix/sync.rs +++ b/src/shims/posix/sync.rs @@ -1,6 +1,5 @@ use std::convert::TryInto; use std::time::{Duration, SystemTime}; -use std::ops::Not; use crate::*; use stacked_borrows::Tag; @@ -548,27 +547,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let active_thread = this.get_active_thread(); if this.rwlock_reader_unlock(id, active_thread) { - // The thread was a reader. - if this.rwlock_is_locked(id).not() { - // No more readers owning the lock. Give it to a writer if there - // is any. - this.rwlock_dequeue_and_lock_writer(id); - } Ok(0) - } else if Some(active_thread) == this.rwlock_writer_unlock(id) { - // The thread was a writer. - // - // We are prioritizing writers here against the readers. As a - // result, not only readers can starve writers, but also writers can - // starve readers. - if this.rwlock_dequeue_and_lock_writer(id) { - // Someone got the write lock, nice. - } else { - // Give the lock to all readers. - while this.rwlock_dequeue_and_lock_reader(id) { - // Rinse and repeat. - } - } + } else if this.rwlock_writer_unlock(id, active_thread) { Ok(0) } else { throw_ub_format!("unlocked an rwlock that was not locked by the active thread"); diff --git a/src/shims/windows/foreign_items.rs b/src/shims/windows/foreign_items.rs index ddb70b752e794..e8937bbb30855 100644 --- a/src/shims/windows/foreign_items.rs +++ b/src/shims/windows/foreign_items.rs @@ -257,7 +257,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Better error for attempts to create a thread "CreateThread" => { - throw_unsup_format!("Miri does not support threading"); + throw_unsup_format!("Miri does not support concurrency on Windows"); } // Incomplete shims that we "stub out" just to get pre-main initialization code to work. @@ -292,7 +292,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if this.frame().instance.to_string().starts_with("std::sys::windows::") => { #[allow(non_snake_case)] let &[_lpCriticalSection] = check_arg_count(args)?; - assert_eq!(this.get_total_thread_count(), 1, "concurrency on Windows not supported"); + assert_eq!(this.get_total_thread_count(), 1, "concurrency on Windows is not supported"); // Nothing to do, not even a return value. // (Windows locks are reentrant, and we have only 1 thread, // so not doing any futher checks here is at least not incorrect.) @@ -301,7 +301,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if this.frame().instance.to_string().starts_with("std::sys::windows::") => { #[allow(non_snake_case)] let &[_lpCriticalSection] = check_arg_count(args)?; - assert_eq!(this.get_total_thread_count(), 1, "concurrency on Windows not supported"); + assert_eq!(this.get_total_thread_count(), 1, "concurrency on Windows is not supported"); // There is only one thread, so this always succeeds and returns TRUE. this.write_scalar(Scalar::from_i32(1), dest)?; } diff --git a/src/shims/windows/sync.rs b/src/shims/windows/sync.rs index ef40eb0891104..7bad3c08a598f 100644 --- a/src/shims/windows/sync.rs +++ b/src/shims/windows/sync.rs @@ -1,19 +1,22 @@ -use rustc_target::abi::Size; - use crate::*; // Locks are pointer-sized pieces of data, initialized to 0. -// We use them to count readers, with usize::MAX representing the write-locked state. +// We use the first 4 bytes to store the RwLockId. -fn deref_lock<'mir, 'tcx: 'mir>( +fn srwlock_get_or_create_id<'mir, 'tcx: 'mir>( ecx: &mut MiriEvalContext<'mir, 'tcx>, lock_op: OpTy<'tcx, Tag>, -) -> InterpResult<'tcx, MPlaceTy<'tcx, Tag>> { - // `lock` is a pointer to `void*`; cast it to a pointer to `usize`. - let lock = ecx.deref_operand(lock_op)?; - let usize = ecx.machine.layouts.usize; - assert_eq!(lock.layout.size, usize.size); - Ok(lock.offset(Size::ZERO, MemPlaceMeta::None, usize, ecx)?) +) -> InterpResult<'tcx, RwLockId> { + let id = ecx.read_scalar_at_offset(lock_op, 0, ecx.machine.layouts.u32)?.to_u32()?; + if id == 0 { + // 0 is a default value and also not a valid rwlock id. Need to allocate + // a new rwlock. + let id = ecx.rwlock_create(); + ecx.write_scalar_at_offset(lock_op, 0, id.to_u32_scalar(), ecx.machine.layouts.u32)?; + Ok(id) + } else { + Ok(RwLockId::from_u32(id)) + } } impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} @@ -24,17 +27,20 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx lock_op: OpTy<'tcx, Tag>, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - assert_eq!(this.get_total_thread_count(), 1, "concurrency on Windows is not supported"); - - let lock = deref_lock(this, lock_op)?; - let lock_val = this.read_scalar(lock.into())?.to_machine_usize(this)?; - if lock_val == 0 { - // Currently not locked. Lock it. - let new_val = Scalar::from_machine_usize(this.machine_usize_max(), this); - this.write_scalar(new_val, lock.into())?; + let id = srwlock_get_or_create_id(this, lock_op)?; + let active_thread = this.get_active_thread(); + + if this.rwlock_is_locked(id) { + // Note: this will deadlock if the lock is already locked by this + // thread in any way. + // + // FIXME: Detect and report the deadlock proactively. (We currently + // report the deadlock only when no thread can continue execution, + // but we could detect that this lock is already locked and report + // an error.) + this.rwlock_enqueue_and_block_writer(id, active_thread); } else { - // Lock is already held. This is a deadlock. - throw_machine_stop!(TerminationInfo::Deadlock); + this.rwlock_writer_lock(id, active_thread); } Ok(()) @@ -46,18 +52,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx lock_op: OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, u8> { let this = self.eval_context_mut(); - assert_eq!(this.get_total_thread_count(), 1, "concurrency on Windows is not supported"); - - let lock = deref_lock(this, lock_op)?; - let lock_val = this.read_scalar(lock.into())?.to_machine_usize(this)?; - if lock_val == 0 { - // Currently not locked. Lock it. - let new_val = this.machine_usize_max(); - this.write_scalar(Scalar::from_machine_usize(new_val, this), lock.into())?; - Ok(1) - } else { + let id = srwlock_get_or_create_id(this, lock_op)?; + let active_thread = this.get_active_thread(); + + if this.rwlock_is_locked(id) { // Lock is already held. Ok(0) + } else { + this.rwlock_writer_lock(id, active_thread); + Ok(1) } } @@ -67,17 +70,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx lock_op: OpTy<'tcx, Tag>, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - assert_eq!(this.get_total_thread_count(), 1, "concurrency on Windows is not supported"); - - let lock = deref_lock(this, lock_op)?; - let lock_val = this.read_scalar(lock.into())?.to_machine_usize(this)?; - if lock_val == this.machine_usize_max() { - // Currently locked. Unlock it. - let new_val = 0; - this.write_scalar(Scalar::from_machine_usize(new_val, this), lock.into())?; - } else { - // Lock is not locked. - throw_ub_format!("calling ReleaseSRWLockExclusive on an SRWLock that is not exclusively locked"); + let id = srwlock_get_or_create_id(this, lock_op)?; + let active_thread = this.get_active_thread(); + + if !this.rwlock_writer_unlock(id, active_thread) { + // The docs do not say anything about this case, but it seems better to not allow it. + throw_ub_format!("calling ReleaseSRWLockExclusive on an SRWLock that is not exclusively locked by the current thread"); } Ok(()) @@ -89,21 +87,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx lock_op: OpTy<'tcx, Tag>, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - assert_eq!(this.get_total_thread_count(), 1, "concurrency on Windows is not supported"); + let id = srwlock_get_or_create_id(this, lock_op)?; + let active_thread = this.get_active_thread(); - let lock = deref_lock(this, lock_op)?; - let lock_val = this.read_scalar(lock.into())?.to_machine_usize(this)?; - if lock_val == this.machine_usize_max() { - // Currently write locked. This is a deadlock. - throw_machine_stop!(TerminationInfo::Deadlock); + if this.rwlock_is_write_locked(id) { + this.rwlock_enqueue_and_block_reader(id, active_thread); } else { - // Bump up read counter (cannot overflow as we just checkd against usize::MAX); - let new_val = lock_val+1; - // Make sure this does not reach the "write locked" flag. - if new_val == this.machine_usize_max() { - throw_unsup_format!("SRWLock read-acquired too many times"); - } - this.write_scalar(Scalar::from_machine_usize(new_val, this), lock.into())?; + this.rwlock_reader_lock(id, active_thread); } Ok(()) @@ -115,21 +105,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx lock_op: OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, u8> { let this = self.eval_context_mut(); - assert_eq!(this.get_total_thread_count(), 1, "concurrency on Windows is not supported"); + let id = srwlock_get_or_create_id(this, lock_op)?; + let active_thread = this.get_active_thread(); - let lock = deref_lock(this, lock_op)?; - let lock_val = this.read_scalar(lock.into())?.to_machine_usize(this)?; - if lock_val == this.machine_usize_max() { - // Currently write locked. + if this.rwlock_is_write_locked(id) { Ok(0) } else { - // Bump up read counter (cannot overflow as we just checkd against usize::MAX); - let new_val = lock_val+1; - // Make sure this does not reach the "write locked" flag. - if new_val == this.machine_usize_max() { - throw_unsup_format!("SRWLock read-acquired too many times"); - } - this.write_scalar(Scalar::from_machine_usize(new_val, this), lock.into())?; + this.rwlock_reader_lock(id, active_thread); Ok(1) } } @@ -140,20 +122,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx lock_op: OpTy<'tcx, Tag>, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - assert_eq!(this.get_total_thread_count(), 1, "concurrency on Windows is not supported"); - - let lock = deref_lock(this, lock_op)?; - let lock_val = this.read_scalar(lock.into())?.to_machine_usize(this)?; - if lock_val == this.machine_usize_max() { - // Currently write locked. This is a UB. - throw_ub_format!("calling ReleaseSRWLockShared on write-locked SRWLock"); - } else if lock_val == 0 { - // Currently not locked at all. - throw_ub_format!("calling ReleaseSRWLockShared on unlocked SRWLock"); - } else { - // Decrement read counter (cannot overflow as we just checkd against 0); - let new_val = lock_val-1; - this.write_scalar(Scalar::from_machine_usize(new_val, this), lock.into())?; + let id = srwlock_get_or_create_id(this, lock_op)?; + let active_thread = this.get_active_thread(); + + if !this.rwlock_reader_unlock(id, active_thread) { + // The docs do not say anything about this case, but it seems better to not allow it. + throw_ub_format!("calling ReleaseSRWLockShared on an SRWLock that is not locked by the current thread"); } Ok(()) diff --git a/src/sync.rs b/src/sync.rs index 0d4b4d6b7c1cb..7e3c27b386dfe 100644 --- a/src/sync.rs +++ b/src/sync.rs @@ -3,6 +3,8 @@ use std::convert::TryFrom; use std::num::NonZeroU32; use std::ops::Not; +use log::trace; + use rustc_index::vec::{Idx, IndexVec}; use crate::*; @@ -102,6 +104,52 @@ pub(super) struct SynchronizationState { condvars: IndexVec, } +// Private extension trait for local helper methods +impl<'mir, 'tcx: 'mir> EvalContextExtPriv<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} +trait EvalContextExtPriv<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { + /// Take a reader out of the queue waiting for the lock. + /// Returns `true` if some thread got the rwlock. + #[inline] + fn rwlock_dequeue_and_lock_reader(&mut self, id: RwLockId) -> bool { + let this = self.eval_context_mut(); + if let Some(reader) = this.machine.threads.sync.rwlocks[id].reader_queue.pop_front() { + this.unblock_thread(reader); + this.rwlock_reader_lock(id, reader); + true + } else { + false + } + } + + /// Take the writer out of the queue waiting for the lock. + /// Returns `true` if some thread got the rwlock. + #[inline] + fn rwlock_dequeue_and_lock_writer(&mut self, id: RwLockId) -> bool { + let this = self.eval_context_mut(); + if let Some(writer) = this.machine.threads.sync.rwlocks[id].writer_queue.pop_front() { + this.unblock_thread(writer); + this.rwlock_writer_lock(id, writer); + true + } else { + false + } + } + + /// Take a thread out of the queue waiting for the mutex, and lock + /// the mutex for it. Returns `true` if some thread has the mutex now. + #[inline] + fn mutex_dequeue_and_lock(&mut self, id: MutexId) -> bool { + let this = self.eval_context_mut(); + if let Some(thread) = this.machine.threads.sync.mutexes[id].queue.pop_front() { + this.unblock_thread(thread); + this.mutex_lock(id, thread); + true + } else { + false + } + } +} + // Public interface to synchronization primitives. Please note that in most // cases, the function calls are infallible and it is the client's (shim // implementation's) responsibility to detect and deal with erroneous @@ -124,8 +172,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx #[inline] /// Check if locked. - fn mutex_is_locked(&mut self, id: MutexId) -> bool { - let this = self.eval_context_mut(); + fn mutex_is_locked(&self, id: MutexId) -> bool { + let this = self.eval_context_ref(); this.machine.threads.sync.mutexes[id].owner.is_some() } @@ -174,7 +222,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } Some(old_lock_count) } else { - // Mutex is unlocked. + // Mutex is not locked. None } } @@ -188,20 +236,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.block_thread(thread); } - #[inline] - /// Take a thread out of the queue waiting for the mutex, and lock - /// the mutex for it. Returns `true` if some thread has the mutex now. - fn mutex_dequeue_and_lock(&mut self, id: MutexId) -> bool { - let this = self.eval_context_mut(); - if let Some(thread) = this.machine.threads.sync.mutexes[id].queue.pop_front() { - this.unblock_thread(thread); - this.mutex_lock(id, thread); - true - } else { - false - } - } - #[inline] /// Create state for a new read write lock. fn rwlock_create(&mut self) -> RwLockId { @@ -211,17 +245,23 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx #[inline] /// Check if locked. - fn rwlock_is_locked(&mut self, id: RwLockId) -> bool { - let this = self.eval_context_mut(); - this.machine.threads.sync.rwlocks[id].writer.is_some() - || this.machine.threads.sync.rwlocks[id].readers.is_empty().not() + fn rwlock_is_locked(&self, id: RwLockId) -> bool { + let this = self.eval_context_ref(); + let rwlock = &this.machine.threads.sync.rwlocks[id]; + trace!( + "rwlock_is_locked: {:?} writer is {:?} and there are {} reader threads (some of which could hold multiple read locks)", + id, rwlock.writer, rwlock.readers.len(), + ); + rwlock.writer.is_some()|| rwlock.readers.is_empty().not() } #[inline] /// Check if write locked. - fn rwlock_is_write_locked(&mut self, id: RwLockId) -> bool { - let this = self.eval_context_mut(); - this.machine.threads.sync.rwlocks[id].writer.is_some() + fn rwlock_is_write_locked(&self, id: RwLockId) -> bool { + let this = self.eval_context_ref(); + let rwlock = &this.machine.threads.sync.rwlocks[id]; + trace!("rwlock_is_write_locked: {:?} writer is {:?}", id, rwlock.writer); + rwlock.writer.is_some() } /// Read-lock the lock by adding the `reader` the list of threads that own @@ -229,12 +269,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn rwlock_reader_lock(&mut self, id: RwLockId, reader: ThreadId) { let this = self.eval_context_mut(); assert!(!this.rwlock_is_write_locked(id), "the lock is write locked"); + trace!("rwlock_reader_lock: {:?} now also held (one more time) by {:?}", id, reader); let count = this.machine.threads.sync.rwlocks[id].readers.entry(reader).or_insert(0); *count = count.checked_add(1).expect("the reader counter overflowed"); } - /// Try read-unlock the lock for `reader`. Returns `true` if succeeded, - /// `false` if this `reader` did not hold the lock. + /// Try read-unlock the lock for `reader` and potentially give the lock to a new owner. + /// Returns `true` if succeeded, `false` if this `reader` did not hold the lock. fn rwlock_reader_unlock(&mut self, id: RwLockId, reader: ThreadId) -> bool { let this = self.eval_context_mut(); match this.machine.threads.sync.rwlocks[id].readers.entry(reader) { @@ -243,12 +284,19 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx assert!(*count > 0, "rwlock locked with count == 0"); *count -= 1; if *count == 0 { + trace!("rwlock_reader_unlock: {:?} no longer held by {:?}", id, reader); entry.remove(); + } else { + trace!("rwlock_reader_unlock: {:?} held one less time by {:?}", id, reader); } - true } - Entry::Vacant(_) => false, + Entry::Vacant(_) => return false, // we did not even own this lock + } + // The thread was a reader. If the lock is not held any more, give it to a writer. + if this.rwlock_is_locked(id).not() { + this.rwlock_dequeue_and_lock_writer(id); } + true } #[inline] @@ -259,38 +307,49 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx reader: ThreadId, ) { let this = self.eval_context_mut(); - assert!(this.rwlock_is_write_locked(id), "queueing on not write locked lock"); + assert!(this.rwlock_is_write_locked(id), "read-queueing on not write locked rwlock"); this.machine.threads.sync.rwlocks[id].reader_queue.push_back(reader); this.block_thread(reader); } - #[inline] - /// Take a reader out the queue waiting for the lock. - /// Returns `true` if some thread got the rwlock. - fn rwlock_dequeue_and_lock_reader(&mut self, id: RwLockId) -> bool { - let this = self.eval_context_mut(); - if let Some(reader) = this.machine.threads.sync.rwlocks[id].reader_queue.pop_front() { - this.unblock_thread(reader); - this.rwlock_reader_lock(id, reader); - true - } else { - false - } - } - #[inline] /// Lock by setting the writer that owns the lock. fn rwlock_writer_lock(&mut self, id: RwLockId, writer: ThreadId) { let this = self.eval_context_mut(); assert!(!this.rwlock_is_locked(id), "the rwlock is already locked"); + trace!("rwlock_writer_lock: {:?} now held by {:?}", id, writer); this.machine.threads.sync.rwlocks[id].writer = Some(writer); } #[inline] /// Try to unlock by removing the writer. - fn rwlock_writer_unlock(&mut self, id: RwLockId) -> Option { + fn rwlock_writer_unlock(&mut self, id: RwLockId, expected_writer: ThreadId) -> bool { let this = self.eval_context_mut(); - this.machine.threads.sync.rwlocks[id].writer.take() + let rwlock = &mut this.machine.threads.sync.rwlocks[id]; + if let Some(current_writer) = rwlock.writer { + if current_writer != expected_writer { + // Only the owner can unlock the rwlock. + return false; + } + rwlock.writer = None; + trace!("rwlock_writer_unlock: {:?} unlocked by {:?}", id, expected_writer); + // The thread was a writer. + // + // We are prioritizing writers here against the readers. As a + // result, not only readers can starve writers, but also writers can + // starve readers. + if this.rwlock_dequeue_and_lock_writer(id) { + // Someone got the write lock, nice. + } else { + // Give the lock to all readers. + while this.rwlock_dequeue_and_lock_reader(id) { + // Rinse and repeat. + } + } + true + } else { + false + } } #[inline] @@ -301,25 +360,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx writer: ThreadId, ) { let this = self.eval_context_mut(); - assert!(this.rwlock_is_locked(id), "queueing on unlocked lock"); + assert!(this.rwlock_is_locked(id), "write-queueing on unlocked rwlock"); this.machine.threads.sync.rwlocks[id].writer_queue.push_back(writer); this.block_thread(writer); } - #[inline] - /// Take the writer out the queue waiting for the lock. - /// Returns `true` if some thread got the rwlock. - fn rwlock_dequeue_and_lock_writer(&mut self, id: RwLockId) -> bool { - let this = self.eval_context_mut(); - if let Some(writer) = this.machine.threads.sync.rwlocks[id].writer_queue.pop_front() { - this.unblock_thread(writer); - this.rwlock_writer_lock(id, writer); - true - } else { - false - } - } - #[inline] /// Create state for a new conditional variable. fn condvar_create(&mut self) -> CondvarId { diff --git a/tests/compile-fail/concurrency/thread-spawn.rs b/tests/compile-fail/concurrency/thread-spawn.rs index f0e4ab3817d34..27760eed8dba9 100644 --- a/tests/compile-fail/concurrency/thread-spawn.rs +++ b/tests/compile-fail/concurrency/thread-spawn.rs @@ -3,7 +3,7 @@ use std::thread; -// error-pattern: Miri does not support threading +// error-pattern: Miri does not support concurrency on Windows fn main() { thread::spawn(|| {}); From fcdacce4b1638bb00aa4f9e0b8c5c5707c5ab969 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 28 Jun 2020 11:31:34 +0200 Subject: [PATCH 2155/3747] fix some ignore-windows comments --- .../concurrency/libc_pthread_create_main_terminate.rs | 2 +- tests/compile-fail/concurrency/libc_pthread_join_detached.rs | 2 +- tests/compile-fail/concurrency/libc_pthread_join_joined.rs | 2 +- tests/compile-fail/concurrency/libc_pthread_join_main.rs | 2 +- tests/compile-fail/concurrency/libc_pthread_join_multiple.rs | 2 +- tests/compile-fail/concurrency/libc_pthread_join_self.rs | 2 +- tests/compile-fail/environ-gets-deallocated.rs | 2 +- tests/run-pass/calloc.rs | 2 +- tests/run-pass/malloc.rs | 2 +- tests/run-pass/thread-local.rs | 2 +- 10 files changed, 10 insertions(+), 10 deletions(-) diff --git a/tests/compile-fail/concurrency/libc_pthread_create_main_terminate.rs b/tests/compile-fail/concurrency/libc_pthread_create_main_terminate.rs index ea11691955ce7..35ee03242d116 100644 --- a/tests/compile-fail/concurrency/libc_pthread_create_main_terminate.rs +++ b/tests/compile-fail/concurrency/libc_pthread_create_main_terminate.rs @@ -1,4 +1,4 @@ -// ignore-windows: Concurrency on Windows is not supported yet. +// ignore-windows: No libc on Windows // error-pattern: unsupported operation: the main thread terminated without waiting for other threads // Check that we terminate the program when the main thread terminates. diff --git a/tests/compile-fail/concurrency/libc_pthread_join_detached.rs b/tests/compile-fail/concurrency/libc_pthread_join_detached.rs index ad83fb2efef3d..dcd06596de130 100644 --- a/tests/compile-fail/concurrency/libc_pthread_join_detached.rs +++ b/tests/compile-fail/concurrency/libc_pthread_join_detached.rs @@ -1,4 +1,4 @@ -// ignore-windows: Concurrency on Windows is not supported yet. +// ignore-windows: No libc on Windows // Joining a detached thread is undefined behavior. diff --git a/tests/compile-fail/concurrency/libc_pthread_join_joined.rs b/tests/compile-fail/concurrency/libc_pthread_join_joined.rs index 3ca0424496904..26f33f1f5f949 100644 --- a/tests/compile-fail/concurrency/libc_pthread_join_joined.rs +++ b/tests/compile-fail/concurrency/libc_pthread_join_joined.rs @@ -1,4 +1,4 @@ -// ignore-windows: Concurrency on Windows is not supported yet. +// ignore-windows: No libc on Windows // Joining an already joined thread is undefined behavior. diff --git a/tests/compile-fail/concurrency/libc_pthread_join_main.rs b/tests/compile-fail/concurrency/libc_pthread_join_main.rs index 69e1a68ef97ae..15e43776ab828 100644 --- a/tests/compile-fail/concurrency/libc_pthread_join_main.rs +++ b/tests/compile-fail/concurrency/libc_pthread_join_main.rs @@ -1,4 +1,4 @@ -// ignore-windows: Concurrency on Windows is not supported yet. +// ignore-windows: No libc on Windows // Joining the main thread is undefined behavior. diff --git a/tests/compile-fail/concurrency/libc_pthread_join_multiple.rs b/tests/compile-fail/concurrency/libc_pthread_join_multiple.rs index f8a43cfcde647..d86233a67643b 100644 --- a/tests/compile-fail/concurrency/libc_pthread_join_multiple.rs +++ b/tests/compile-fail/concurrency/libc_pthread_join_multiple.rs @@ -1,4 +1,4 @@ -// ignore-windows: Concurrency on Windows is not supported yet. +// ignore-windows: No libc on Windows // Joining the same thread from multiple threads is undefined behavior. diff --git a/tests/compile-fail/concurrency/libc_pthread_join_self.rs b/tests/compile-fail/concurrency/libc_pthread_join_self.rs index d765a95d8be7a..2a8fe12eafd62 100644 --- a/tests/compile-fail/concurrency/libc_pthread_join_self.rs +++ b/tests/compile-fail/concurrency/libc_pthread_join_self.rs @@ -1,4 +1,4 @@ -// ignore-windows: Concurrency on Windows is not supported yet. +// ignore-windows: No libc on Windows // Joining itself is undefined behavior. diff --git a/tests/compile-fail/environ-gets-deallocated.rs b/tests/compile-fail/environ-gets-deallocated.rs index 0f374a2e3f80c..b5a4441d2f9bd 100644 --- a/tests/compile-fail/environ-gets-deallocated.rs +++ b/tests/compile-fail/environ-gets-deallocated.rs @@ -1,4 +1,4 @@ -//ignore-windows: Windows does not have a global environ list that the program can access directly +// ignore-windows: Windows does not have a global environ list that the program can access directly #[cfg(target_os="linux")] fn get_environ() -> *const *const u8 { diff --git a/tests/run-pass/calloc.rs b/tests/run-pass/calloc.rs index 4c520da85e876..6793f86c116cb 100644 --- a/tests/run-pass/calloc.rs +++ b/tests/run-pass/calloc.rs @@ -1,4 +1,4 @@ -//ignore-windows: Uses POSIX APIs +// ignore-windows: No libc on Windows #![feature(rustc_private)] diff --git a/tests/run-pass/malloc.rs b/tests/run-pass/malloc.rs index f66263425ee86..8e0d9ac629328 100644 --- a/tests/run-pass/malloc.rs +++ b/tests/run-pass/malloc.rs @@ -1,4 +1,4 @@ -//ignore-windows: Uses POSIX APIs +// ignore-windows: No libc on Windows #![feature(rustc_private)] diff --git a/tests/run-pass/thread-local.rs b/tests/run-pass/thread-local.rs index 8de45811be443..1aa442edad3b2 100644 --- a/tests/run-pass/thread-local.rs +++ b/tests/run-pass/thread-local.rs @@ -1,4 +1,4 @@ -//ignore-windows: Uses POSIX APIs +// ignore-windows: No libc on Windows #![feature(rustc_private)] extern crate libc; From c379793cdee2ef6e777fce7e4f19993d29e77f9d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 2 Jul 2020 09:50:52 +0200 Subject: [PATCH 2156/3747] add option to track call IDs --- README.md | 3 +++ src/bin/miri.rs | 28 +++++++++++++++++++++------- src/diagnostics.rs | 7 +++++-- src/eval.rs | 6 +++++- src/lib.rs | 2 +- src/machine.rs | 3 ++- src/stacked_borrows.rs | 12 +++++++++--- 7 files changed, 46 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index 6b2b36d18c32f..ab4d4c02db1ed 100644 --- a/README.md +++ b/README.md @@ -196,6 +196,9 @@ Miri adds its own set of `-Z` flags: is popped from a borrow stack (which is where the tag becomes invalid and any future use of it will error). This helps you in finding out why UB is happening and where in your code would be a good place to look for it. +* `-Zmiri-track-call-id=` shows a backtrace when the given call id is + assigned to a stack frame. This helps in debugging UB related to Stacked + Borrows "protectors". [alignment-false-positives]: https://github.com/rust-lang/miri/issues/1074 diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 41490531a78bf..f22f19845c6c9 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -172,6 +172,7 @@ fn main() { let mut ignore_leaks = false; let mut seed: Option = None; let mut tracked_pointer_tag: Option = None; + let mut tracked_call_id: Option = None; let mut tracked_alloc_id: Option = None; let mut rustc_args = vec![]; let mut crate_args = vec![]; @@ -233,26 +234,38 @@ fn main() { .push(arg.strip_prefix("-Zmiri-env-exclude=").unwrap().to_owned()); } arg if arg.starts_with("-Zmiri-track-pointer-tag=") => { - let id: u64 = match arg.strip_prefix("-Zmiri-track-pointer-tag=").unwrap().parse() - { + let id: u64 = match arg.strip_prefix("-Zmiri-track-pointer-tag=").unwrap().parse() { Ok(id) => id, Err(err) => panic!( - "-Zmiri-track-pointer-tag requires a valid `u64` as the argument: {}", + "-Zmiri-track-pointer-tag requires a valid `u64` argument: {}", err ), }; if let Some(id) = miri::PtrId::new(id) { tracked_pointer_tag = Some(id); } else { - panic!("-Zmiri-track-pointer-tag must be a nonzero id"); + panic!("-Zmiri-track-pointer-tag requires a nonzero argument"); + } + } + arg if arg.starts_with("-Zmiri-track-call-id=") => { + let id: u64 = match arg.strip_prefix("-Zmiri-track-call-id=").unwrap().parse() { + Ok(id) => id, + Err(err) => panic!( + "-Zmiri-track-call-id requires a valid `u64` argument: {}", + err + ), + }; + if let Some(id) = miri::CallId::new(id) { + tracked_call_id = Some(id); + } else { + panic!("-Zmiri-track-call-id requires a nonzero argument"); } } arg if arg.starts_with("-Zmiri-track-alloc-id=") => { - let id: u64 = match arg.strip_prefix("-Zmiri-track-alloc-id=").unwrap().parse() - { + let id: u64 = match arg.strip_prefix("-Zmiri-track-alloc-id=").unwrap().parse() { Ok(id) => id, Err(err) => panic!( - "-Zmiri-track-alloc-id requires a valid `u64` as the argument: {}", + "-Zmiri-track-alloc-id requires a valid `u64` argument: {}", err ), }; @@ -278,6 +291,7 @@ fn main() { seed, args: crate_args, tracked_pointer_tag, + tracked_call_id, tracked_alloc_id, }; run_compiler(rustc_args, &mut MiriCompilerCalls { miri_config }) diff --git a/src/diagnostics.rs b/src/diagnostics.rs index 2d8b1248dcf4d..8fdf039ce8e6c 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -40,7 +40,8 @@ impl MachineStopType for TerminationInfo {} /// Miri specific diagnostics pub enum NonHaltingDiagnostic { - PoppedTrackedPointerTag(Item), + PoppedPointerTag(Item), + CreatedCallId(CallId), CreatedAlloc(AllocId), FreedAlloc(AllocId), } @@ -204,8 +205,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx for e in diagnostics.borrow_mut().drain(..) { use NonHaltingDiagnostic::*; let msg = match e { - PoppedTrackedPointerTag(item) => + PoppedPointerTag(item) => format!("popped tracked tag for item {:?}", item), + CreatedCallId(id) => + format!("function call with id {}", id), CreatedAlloc(AllocId(id)) => format!("created allocation with id {}", id), FreedAlloc(AllocId(id)) => diff --git a/src/eval.rs b/src/eval.rs index 56d6f3ed3c5b9..ee429dd3143ed 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -31,8 +31,10 @@ pub struct MiriConfig { pub args: Vec, /// The seed to use when non-determinism or randomness are required (e.g. ptr-to-int cast, `getrandom()`). pub seed: Option, - /// The stacked borrow id to report about + /// The stacked borrows pointer id to report about pub tracked_pointer_tag: Option, + /// The stacked borrows call ID to report about + pub tracked_call_id: Option, /// The allocation id to report about. pub tracked_alloc_id: Option, } @@ -49,6 +51,7 @@ impl Default for MiriConfig { args: vec![], seed: None, tracked_pointer_tag: None, + tracked_call_id: None, tracked_alloc_id: None, } } @@ -74,6 +77,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( StdRng::seed_from_u64(config.seed.unwrap_or(0)), config.stacked_borrows, config.tracked_pointer_tag, + config.tracked_call_id, config.tracked_alloc_id, config.check_alignment, ), diff --git a/src/lib.rs b/src/lib.rs index fa357eb9b1341..816917081a8ce 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -65,7 +65,7 @@ pub use crate::mono_hash_map::MonoHashMap; pub use crate::operator::EvalContextExt as OperatorEvalContextExt; pub use crate::range_map::RangeMap; pub use crate::stacked_borrows::{ - EvalContextExt as StackedBorEvalContextExt, Item, Permission, PtrId, Stack, Stacks, Tag, + EvalContextExt as StackedBorEvalContextExt, Item, Permission, CallId, PtrId, Stack, Stacks, Tag, }; pub use crate::thread::{ EvalContextExt as ThreadsEvalContextExt, SchedulingAction, ThreadId, ThreadManager, ThreadState, diff --git a/src/machine.rs b/src/machine.rs index 6233222c004d1..f23d8833bd82b 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -129,11 +129,12 @@ impl MemoryExtra { rng: StdRng, stacked_borrows: bool, tracked_pointer_tag: Option, + tracked_call_id: Option, tracked_alloc_id: Option, check_alignment: bool, ) -> Self { let stacked_borrows = if stacked_borrows { - Some(Rc::new(RefCell::new(stacked_borrows::GlobalState::new(tracked_pointer_tag)))) + Some(Rc::new(RefCell::new(stacked_borrows::GlobalState::new(tracked_pointer_tag, tracked_call_id)))) } else { None }; diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 03140c867b2d0..3c263670bc7fb 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -104,8 +104,10 @@ pub struct GlobalState { next_call_id: CallId, /// Those call IDs corresponding to functions that are still running. active_calls: FxHashSet, - /// The id to trace in this execution run + /// The pointer id to trace tracked_pointer_tag: Option, + /// The call id to trace + tracked_call_id: Option, } /// Memory extra state gives us interior mutable access to the global state. pub type MemoryExtra = Rc>; @@ -153,13 +155,14 @@ impl fmt::Display for RefKind { /// Utilities for initialization and ID generation impl GlobalState { - pub fn new(tracked_pointer_tag: Option) -> Self { + pub fn new(tracked_pointer_tag: Option, tracked_call_id: Option) -> Self { GlobalState { next_ptr_id: NonZeroU64::new(1).unwrap(), base_ptr_ids: FxHashMap::default(), next_call_id: NonZeroU64::new(1).unwrap(), active_calls: FxHashSet::default(), tracked_pointer_tag, + tracked_call_id, } } @@ -172,6 +175,9 @@ impl GlobalState { pub fn new_call(&mut self) -> CallId { let id = self.next_call_id; trace!("new_call: Assigning ID {}", id); + if Some(id) == self.tracked_call_id { + register_diagnostic(NonHaltingDiagnostic::CreatedCallId(id)); + } assert!(self.active_calls.insert(id)); self.next_call_id = NonZeroU64::new(id.get() + 1).unwrap(); id @@ -277,7 +283,7 @@ impl<'tcx> Stack { fn check_protector(item: &Item, tag: Option, global: &GlobalState) -> InterpResult<'tcx> { if let Tag::Tagged(id) = item.tag { if Some(id) == global.tracked_pointer_tag { - register_diagnostic(NonHaltingDiagnostic::PoppedTrackedPointerTag(item.clone())); + register_diagnostic(NonHaltingDiagnostic::PoppedPointerTag(item.clone())); } } if let Some(call) = item.protector { From 6ca67a346bcbef6e996d9ea1b313bd4363d57adc Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 2 Jul 2020 10:37:29 +0200 Subject: [PATCH 2157/3747] rustup --- rust-version | 2 +- tests/run-pass/float.rs | 2 +- tests/run-pass/track-caller-attribute.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/rust-version b/rust-version index 159f752cc0df3..e14dd73c70fe7 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -7750c3d46bc19784adb1ee6e37a5ec7e4cd7e772 +9491f18c5de3ff1c4bf9c3fdacf52d9859e26f7c diff --git a/tests/run-pass/float.rs b/tests/run-pass/float.rs index 3347b0a07c26a..0b89f11b0609b 100644 --- a/tests/run-pass/float.rs +++ b/tests/run-pass/float.rs @@ -1,4 +1,4 @@ -#![feature(track_caller, stmt_expr_attributes)] +#![feature(stmt_expr_attributes)] use std::fmt::Debug; // Helper function to avoid promotion so that this tests "run-time" casts, not CTFE. diff --git a/tests/run-pass/track-caller-attribute.rs b/tests/run-pass/track-caller-attribute.rs index f6797c24ebecf..be655703daa06 100644 --- a/tests/run-pass/track-caller-attribute.rs +++ b/tests/run-pass/track-caller-attribute.rs @@ -1,4 +1,4 @@ -#![feature(track_caller, core_intrinsics)] +#![feature(core_intrinsics)] use std::panic::Location; From c5b324b031c1152c558737928cb345d07a1e5b82 Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Thu, 2 Jul 2020 20:00:27 +0100 Subject: [PATCH 2158/3747] Remove likely and unlikely from intrinsics shim They are now implemented in MIR interpreter by rust-lang/rust#73778 --- src/shims/intrinsics.rs | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 015d9edc11b70..68f67a1ed98d4 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -523,16 +523,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let &[_] = check_arg_count(args)?; } - #[rustfmt::skip] - | "likely" - | "unlikely" - => { - // These just return their argument - let &[b] = check_arg_count(args)?; - let b = this.read_immediate(b)?; - this.write_immediate(*b, dest)?; - } - "try" => return this.handle_try(args, dest, ret), name => throw_unsup_format!("unimplemented intrinsic: {}", name), From e310e2f0b925f24572b188eee18935767480517a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 3 Jul 2020 11:18:44 +0200 Subject: [PATCH 2159/3747] set --target when building miri This helps cargo tell apart `./miri` builds and `cargo check` (e.g. through rust-analyzer). See https://github.com/rust-lang/cargo/issues/8440. --- miri | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/miri b/miri index 237a53efb1ad1..37e87ec79861d 100755 --- a/miri +++ b/miri @@ -94,12 +94,12 @@ COMMAND="$1" # . case "$COMMAND" in *-debug) - CARGO_INSTALL_FLAGS="--debug $CARGO_EXTRA_FLAGS" - CARGO_BUILD_FLAGS="$CARGO_EXTRA_FLAGS" + CARGO_INSTALL_FLAGS="--target $TARGET --debug $CARGO_EXTRA_FLAGS" + CARGO_BUILD_FLAGS="--target $TARGET $CARGO_EXTRA_FLAGS" ;; *) - CARGO_INSTALL_FLAGS="$CARGO_EXTRA_FLAGS" - CARGO_BUILD_FLAGS="--release $CARGO_EXTRA_FLAGS" + CARGO_INSTALL_FLAGS="--target $TARGET $CARGO_EXTRA_FLAGS" + CARGO_BUILD_FLAGS="--target $TARGET --release $CARGO_EXTRA_FLAGS" ;; esac From ab65cb3c6779f1d59ea2022c4d9d6effca2c614d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 5 Jul 2020 20:01:12 +0200 Subject: [PATCH 2160/3747] support relative XARGO_RUST_SRC --- cargo-miri/bin.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index 197552a4b1266..68f25b411a9d9 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -257,7 +257,10 @@ fn setup(subcommand: MiriCommand) { // Determine where the rust sources are located. `XARGO_RUST_SRC` env var trumps everything. let rust_src = match std::env::var_os("XARGO_RUST_SRC") { - Some(val) => PathBuf::from(val), + Some(val) => { + let val = PathBuf::from(val); + val.canonicalize().unwrap_or(val) + } None => { // Check for `rust-src` rustup component. let sysroot = miri() From 28b44d970c0b58a7e4d683580ecee4bf9c8cb073 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 5 Jul 2020 12:53:00 +0200 Subject: [PATCH 2161/3747] test validation of uninit memory (used to ICE) --- .../validity/invalid_bool_uninit.rs | 10 + .../validity/invalid_char_uninit.rs | 10 + .../invalid_enum_tag_256variants_uninit.rs | 270 ++++++++++++++++++ .../validity/invalid_fnptr_uninit.rs | 10 + 4 files changed, 300 insertions(+) create mode 100644 tests/compile-fail/validity/invalid_bool_uninit.rs create mode 100644 tests/compile-fail/validity/invalid_char_uninit.rs create mode 100644 tests/compile-fail/validity/invalid_enum_tag_256variants_uninit.rs create mode 100644 tests/compile-fail/validity/invalid_fnptr_uninit.rs diff --git a/tests/compile-fail/validity/invalid_bool_uninit.rs b/tests/compile-fail/validity/invalid_bool_uninit.rs new file mode 100644 index 0000000000000..89b57b2d50d10 --- /dev/null +++ b/tests/compile-fail/validity/invalid_bool_uninit.rs @@ -0,0 +1,10 @@ +#![allow(invalid_value)] + +union MyUninit { + init: (), + uninit: bool, +} + +fn main() { + let _b = unsafe { MyUninit { init: () }.uninit }; //~ ERROR encountered uninitialized bytes, but expected a boolean +} diff --git a/tests/compile-fail/validity/invalid_char_uninit.rs b/tests/compile-fail/validity/invalid_char_uninit.rs new file mode 100644 index 0000000000000..34798dfbc6595 --- /dev/null +++ b/tests/compile-fail/validity/invalid_char_uninit.rs @@ -0,0 +1,10 @@ +#![allow(invalid_value)] + +union MyUninit { + init: (), + uninit: char, +} + +fn main() { + let _b = unsafe { MyUninit { init: () }.uninit }; //~ ERROR encountered uninitialized bytes, but expected a valid unicode scalar value (in `0..=0x10FFFF` but not in `0xD800..=0xDFFF`) +} diff --git a/tests/compile-fail/validity/invalid_enum_tag_256variants_uninit.rs b/tests/compile-fail/validity/invalid_enum_tag_256variants_uninit.rs new file mode 100644 index 0000000000000..c0f53d72a2950 --- /dev/null +++ b/tests/compile-fail/validity/invalid_enum_tag_256variants_uninit.rs @@ -0,0 +1,270 @@ +#![allow(unused, deprecated, invalid_value)] + +#[derive(Copy, Clone)] +enum A { + A0, + A1, + A2, + A3, + A4, + A5, + A6, + A7, + A8, + A9, + A10, + A11, + A12, + A13, + A14, + A15, + A16, + A17, + A18, + A19, + A20, + A21, + A22, + A23, + A24, + A25, + A26, + A27, + A28, + A29, + A30, + A31, + A32, + A33, + A34, + A35, + A36, + A37, + A38, + A39, + A40, + A41, + A42, + A43, + A44, + A45, + A46, + A47, + A48, + A49, + A50, + A51, + A52, + A53, + A54, + A55, + A56, + A57, + A58, + A59, + A60, + A61, + A62, + A63, + A64, + A65, + A66, + A67, + A68, + A69, + A70, + A71, + A72, + A73, + A74, + A75, + A76, + A77, + A78, + A79, + A80, + A81, + A82, + A83, + A84, + A85, + A86, + A87, + A88, + A89, + A90, + A91, + A92, + A93, + A94, + A95, + A96, + A97, + A98, + A99, + A100, + A101, + A102, + A103, + A104, + A105, + A106, + A107, + A108, + A109, + A110, + A111, + A112, + A113, + A114, + A115, + A116, + A117, + A118, + A119, + A120, + A121, + A122, + A123, + A124, + A125, + A126, + A127, + A128, + A129, + A130, + A131, + A132, + A133, + A134, + A135, + A136, + A137, + A138, + A139, + A140, + A141, + A142, + A143, + A144, + A145, + A146, + A147, + A148, + A149, + A150, + A151, + A152, + A153, + A154, + A155, + A156, + A157, + A158, + A159, + A160, + A161, + A162, + A163, + A164, + A165, + A166, + A167, + A168, + A169, + A170, + A171, + A172, + A173, + A174, + A175, + A176, + A177, + A178, + A179, + A180, + A181, + A182, + A183, + A184, + A185, + A186, + A187, + A188, + A189, + A190, + A191, + A192, + A193, + A194, + A195, + A196, + A197, + A198, + A199, + A200, + A201, + A202, + A203, + A204, + A205, + A206, + A207, + A208, + A209, + A210, + A211, + A212, + A213, + A214, + A215, + A216, + A217, + A218, + A219, + A220, + A221, + A222, + A223, + A224, + A225, + A226, + A227, + A228, + A229, + A230, + A231, + A232, + A233, + A234, + A235, + A236, + A237, + A238, + A239, + A240, + A241, + A242, + A243, + A244, + A245, + A246, + A247, + A248, + A249, + A250, + A251, + A252, + A253, + A254, + A255, +} + +union MyUninit { + init: (), + uninit: A, +} + +fn main() { + let _a = unsafe { MyUninit { init: () }.uninit }; //~ ERROR encountered uninitialized bytes, but expected a valid enum tag +} diff --git a/tests/compile-fail/validity/invalid_fnptr_uninit.rs b/tests/compile-fail/validity/invalid_fnptr_uninit.rs new file mode 100644 index 0000000000000..dbd6711dc65a4 --- /dev/null +++ b/tests/compile-fail/validity/invalid_fnptr_uninit.rs @@ -0,0 +1,10 @@ +#![allow(invalid_value)] + +union MyUninit { + init: (), + uninit: fn(), +} + +fn main() { + let _b = unsafe { MyUninit { init: () }.uninit }; //~ ERROR encountered uninitialized bytes, but expected a function pointer +} From 6c2521f54f22254fe7fdfea4d22b7abbf243e2cf Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 5 Jul 2020 13:43:20 +0200 Subject: [PATCH 2162/3747] adjust error messages --- tests/compile-fail/validity/invalid_enum_tag.rs | 2 +- .../validity/invalid_enum_tag_256variants_uninit.rs | 2 +- tests/compile-fail/validity/transmute_through_ptr.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/compile-fail/validity/invalid_enum_tag.rs b/tests/compile-fail/validity/invalid_enum_tag.rs index 897bfa90a7029..39e8eed683a3b 100644 --- a/tests/compile-fail/validity/invalid_enum_tag.rs +++ b/tests/compile-fail/validity/invalid_enum_tag.rs @@ -4,5 +4,5 @@ pub enum Foo { } fn main() { - let _f = unsafe { std::mem::transmute::(42) }; //~ ERROR encountered 0x0000002a, but expected a valid enum tag + let _f = unsafe { std::mem::transmute::(42) }; //~ ERROR encountered 0x0000002a at ., but expected a valid enum tag } diff --git a/tests/compile-fail/validity/invalid_enum_tag_256variants_uninit.rs b/tests/compile-fail/validity/invalid_enum_tag_256variants_uninit.rs index c0f53d72a2950..74e24491e6108 100644 --- a/tests/compile-fail/validity/invalid_enum_tag_256variants_uninit.rs +++ b/tests/compile-fail/validity/invalid_enum_tag_256variants_uninit.rs @@ -266,5 +266,5 @@ union MyUninit { } fn main() { - let _a = unsafe { MyUninit { init: () }.uninit }; //~ ERROR encountered uninitialized bytes, but expected a valid enum tag + let _a = unsafe { MyUninit { init: () }.uninit }; //~ ERROR encountered uninitialized bytes at ., but expected a valid enum tag } diff --git a/tests/compile-fail/validity/transmute_through_ptr.rs b/tests/compile-fail/validity/transmute_through_ptr.rs index 1d5cf16aa5ea4..6a88fdaea1ee4 100644 --- a/tests/compile-fail/validity/transmute_through_ptr.rs +++ b/tests/compile-fail/validity/transmute_through_ptr.rs @@ -10,5 +10,5 @@ fn main() { let mut x = Bool::True; evil(&mut x); let _y = x; // reading this ought to be enough to trigger validation - //~^ ERROR encountered 0x0000002c, but expected a valid enum tag + //~^ ERROR encountered 0x0000002c at ., but expected a valid enum tag } From 04019eec3cc17684fff1790b0d15a5df89a9aa79 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 7 Jul 2020 22:57:58 +0200 Subject: [PATCH 2163/3747] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index e14dd73c70fe7..e339c77f1ac32 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -9491f18c5de3ff1c4bf9c3fdacf52d9859e26f7c +e1beee4992ad4b235fc700bf7af1ee86f894ea53 From dcb0f6309e93fd302952c1e8a7fb890fd32a5548 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 8 Jul 2020 11:05:22 +0200 Subject: [PATCH 2164/3747] we cannot track all machine memory any more due to int-ptr-casts --- rust-version | 2 +- src/machine.rs | 12 ++++++++---- src/shims/env.rs | 4 ++-- src/stacked_borrows.rs | 6 +++--- 4 files changed, 14 insertions(+), 10 deletions(-) diff --git a/rust-version b/rust-version index e339c77f1ac32..f1a465c7d6240 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -e1beee4992ad4b235fc700bf7af1ee86f894ea53 +8ac1525e091d3db28e67adcbbd6db1e1deaa37fb diff --git a/src/machine.rs b/src/machine.rs index f23d8833bd82b..49d647838c9e1 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -54,7 +54,7 @@ pub enum MiriMemoryKind { C, /// Windows `HeapAlloc` memory. WinHeap, - /// Memory for args, errno, extern statics and other parts of the machine-managed environment. + /// Memory for args, errno, and other parts of the machine-managed environment. /// This memory may leak. Machine, /// Memory for env vars. Separate from `Machine` because we clean it up and leak-check it. @@ -62,6 +62,9 @@ pub enum MiriMemoryKind { /// Globals copied from `tcx`. /// This memory may leak. Global, + /// Memory for extern statics. + /// This memory may leak. + ExternGlobal, } impl Into> for MiriMemoryKind { @@ -77,7 +80,7 @@ impl MayLeak for MiriMemoryKind { use self::MiriMemoryKind::*; match self { Rust | C | WinHeap | Env => false, - Machine | Global => true, + Machine | Global | ExternGlobal => true, } } } @@ -92,6 +95,7 @@ impl fmt::Display for MiriMemoryKind { Machine => write!(f, "machine-managed memory"), Env => write!(f, "environment variable"), Global => write!(f, "global"), + ExternGlobal => write!(f, "extern global"), } } } @@ -171,7 +175,7 @@ impl MemoryExtra { // "__cxa_thread_atexit_impl" // This should be all-zero, pointer-sized. let layout = this.machine.layouts.usize; - let place = this.allocate(layout, MiriMemoryKind::Machine.into()); + let place = this.allocate(layout, MiriMemoryKind::ExternGlobal.into()); this.write_scalar(Scalar::from_machine_usize(0, this), place.into())?; Self::add_extern_static(this, "__cxa_thread_atexit_impl", place.ptr); // "environ" @@ -181,7 +185,7 @@ impl MemoryExtra { // "_tls_used" // This is some obscure hack that is part of the Windows TLS story. It's a `u8`. let layout = this.machine.layouts.u8; - let place = this.allocate(layout, MiriMemoryKind::Machine.into()); + let place = this.allocate(layout, MiriMemoryKind::ExternGlobal.into()); this.write_scalar(Scalar::from_u8(0), place.into())?; Self::add_extern_static(this, "_tls_used", place.ptr); } diff --git a/src/shims/env.rs b/src/shims/env.rs index 8459aa3241c8e..4a2bec28bd17c 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -383,9 +383,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.memory.deallocate(this.force_ptr(old_vars_ptr)?, None, MiriMemoryKind::Env.into())?; } else { // No `environ` allocated yet, let's do that. - // This is memory backing an extern static, hence `Machine`, not `Env`. + // This is memory backing an extern static, hence `ExternGlobal`, not `Env`. let layout = this.machine.layouts.usize; - let place = this.allocate(layout, MiriMemoryKind::Machine.into()); + let place = this.allocate(layout, MiriMemoryKind::ExternGlobal.into()); this.machine.env_vars.environ = Some(place); } diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 3c263670bc7fb..6942acc5e2b07 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -466,13 +466,13 @@ impl Stacks { // everything else off the stack, invalidating all previous pointers, // and in particular, *all* raw pointers. MemoryKind::Stack => (Tag::Tagged(extra.borrow_mut().new_ptr()), Permission::Unique), - // Global memory can be referenced by global pointers from `tcx`. + // `Global` memory can be referenced by global pointers from `tcx`. // Thus we call `global_base_ptr` such that the global pointers get the same tag // as what we use here. - // `Machine` is used for extern statics, and thus must also be listed here. + // `ExternGlobal` is used for extern statics, and thus must also be listed here. // `Env` we list because we can get away with precise tracking there. // The base pointer is not unique, so the base permission is `SharedReadWrite`. - MemoryKind::Machine(MiriMemoryKind::Global | MiriMemoryKind::Machine | MiriMemoryKind::Env) => + MemoryKind::Machine(MiriMemoryKind::Global | MiriMemoryKind::ExternGlobal | MiriMemoryKind::Env) => (extra.borrow_mut().global_base_ptr(id), Permission::SharedReadWrite), // Everything else we handle entirely untagged for now. // FIXME: experiment with more precise tracking. From 7d9d74e06505b48d2894a24ccbe716ffa931bd2b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 9 Jul 2020 08:59:28 +0200 Subject: [PATCH 2165/3747] on Windows, strip the '\\?\' prefix from the canonical path --- cargo-miri/bin.rs | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index 68f25b411a9d9..e2f32cb0a5384 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -258,8 +258,20 @@ fn setup(subcommand: MiriCommand) { // Determine where the rust sources are located. `XARGO_RUST_SRC` env var trumps everything. let rust_src = match std::env::var_os("XARGO_RUST_SRC") { Some(val) => { - let val = PathBuf::from(val); - val.canonicalize().unwrap_or(val) + let path = PathBuf::from(val); + let path = path.canonicalize().unwrap_or(path); + + // On Windows, this produces a path starting with `\\?\`, which xargo cannot deal with. + // Strip that prefix; the resulting path should still be valid. + #[cfg(windows)] + let path = { + let str = path.into_os_string().into_string() + .expect("non-unicode paths are currently not supported"); + let str = str.strip_prefix(r"\\?\").map(String::from).unwrap_or(str); + PathBuf::from(str) + }; + + path } None => { // Check for `rust-src` rustup component. From ee056ccf7b2341ae72af4d6be7acad6e80155301 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 9 Jul 2020 12:45:35 +0200 Subject: [PATCH 2166/3747] better way to get an absolute path --- cargo-miri/bin.rs | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index e2f32cb0a5384..852dbd7d3ea21 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -259,19 +259,8 @@ fn setup(subcommand: MiriCommand) { let rust_src = match std::env::var_os("XARGO_RUST_SRC") { Some(val) => { let path = PathBuf::from(val); - let path = path.canonicalize().unwrap_or(path); - - // On Windows, this produces a path starting with `\\?\`, which xargo cannot deal with. - // Strip that prefix; the resulting path should still be valid. - #[cfg(windows)] - let path = { - let str = path.into_os_string().into_string() - .expect("non-unicode paths are currently not supported"); - let str = str.strip_prefix(r"\\?\").map(String::from).unwrap_or(str); - PathBuf::from(str) - }; - - path + // Make path absolute, but not via `canonicalize` (which does not work very well on Windows). + env::current_dir().unwrap().join(path) } None => { // Check for `rust-src` rustup component. From 2fbc4aa7ca8d53cc4613db954886e04b79d6804e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 9 Jul 2020 13:02:42 +0200 Subject: [PATCH 2167/3747] Cleanup code Co-authored-by: Aleksey Kladov --- cargo-miri/bin.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index 852dbd7d3ea21..6d4c51256febd 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -257,8 +257,7 @@ fn setup(subcommand: MiriCommand) { // Determine where the rust sources are located. `XARGO_RUST_SRC` env var trumps everything. let rust_src = match std::env::var_os("XARGO_RUST_SRC") { - Some(val) => { - let path = PathBuf::from(val); + Some(path) => { // Make path absolute, but not via `canonicalize` (which does not work very well on Windows). env::current_dir().unwrap().join(path) } From 22e7a6263b457aa6b3402aaebbf98f47da92c03d Mon Sep 17 00:00:00 2001 From: Justus K Date: Thu, 9 Jul 2020 13:16:38 +0200 Subject: [PATCH 2168/3747] Early exit if program doesn't contain a main fn --- src/bin/miri.rs | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/bin/miri.rs b/src/bin/miri.rs index f22f19845c6c9..73e52af4ec51d 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -5,6 +5,7 @@ extern crate rustc_driver; extern crate rustc_hir; extern crate rustc_interface; extern crate rustc_session; +extern crate rustc_errors; use std::convert::TryFrom; use std::env; @@ -13,7 +14,8 @@ use std::str::FromStr; use hex::FromHexError; use log::debug; -use rustc_session::CtfeBacktrace; +use rustc_session::{CtfeBacktrace, config::ErrorOutputType}; +use rustc_errors::emitter::{HumanReadableErrorType, ColorConfig}; use rustc_driver::Compilation; use rustc_hir::def_id::LOCAL_CRATE; use rustc_middle::ty::TyCtxt; @@ -32,7 +34,12 @@ impl rustc_driver::Callbacks for MiriCompilerCalls { queries.global_ctxt().unwrap().peek_mut().enter(|tcx| { init_late_loggers(tcx); - let (entry_def_id, _) = tcx.entry_fn(LOCAL_CRATE).expect("no main function found!"); + let (entry_def_id, _) = if let Some((entry_def, x)) = tcx.entry_fn(LOCAL_CRATE) { + (entry_def, x) + } else { + let output_ty = ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(ColorConfig::Auto)); + rustc_session::early_error(output_ty, "miri can only run programs that have a main function"); + }; let mut config = self.miri_config.clone(); // Add filename to `miri` arguments. From c93fc933bd54be1f5237c5411bc70cbc0176cf39 Mon Sep 17 00:00:00 2001 From: Justus K Date: Thu, 9 Jul 2020 14:08:45 +0200 Subject: [PATCH 2169/3747] Add ui test for early exiting if no main --- tests/run-pass/no_main.rs | 1 + tests/run-pass/no_main.stderr | 2 ++ 2 files changed, 3 insertions(+) create mode 100644 tests/run-pass/no_main.rs create mode 100644 tests/run-pass/no_main.stderr diff --git a/tests/run-pass/no_main.rs b/tests/run-pass/no_main.rs new file mode 100644 index 0000000000000..1ae9a6a35c250 --- /dev/null +++ b/tests/run-pass/no_main.rs @@ -0,0 +1 @@ +#![no_main] diff --git a/tests/run-pass/no_main.stderr b/tests/run-pass/no_main.stderr new file mode 100644 index 0000000000000..52591a8d6da31 --- /dev/null +++ b/tests/run-pass/no_main.stderr @@ -0,0 +1,2 @@ +error: miri can only run programs that have a main function + From d23e245f38f556e833ca7fc4f616b78e791b923b Mon Sep 17 00:00:00 2001 From: Justus K Date: Thu, 9 Jul 2020 17:21:09 +0200 Subject: [PATCH 2170/3747] Move no_main test to compile-fail --- tests/compile-fail/no_main.rs | 2 ++ tests/run-pass/no_main.rs | 1 - tests/run-pass/no_main.stderr | 2 -- 3 files changed, 2 insertions(+), 3 deletions(-) create mode 100644 tests/compile-fail/no_main.rs delete mode 100644 tests/run-pass/no_main.rs delete mode 100644 tests/run-pass/no_main.stderr diff --git a/tests/compile-fail/no_main.rs b/tests/compile-fail/no_main.rs new file mode 100644 index 0000000000000..a9e8e816828c0 --- /dev/null +++ b/tests/compile-fail/no_main.rs @@ -0,0 +1,2 @@ +// error-pattern: miri can only run programs that have a main function +#![no_main] diff --git a/tests/run-pass/no_main.rs b/tests/run-pass/no_main.rs deleted file mode 100644 index 1ae9a6a35c250..0000000000000 --- a/tests/run-pass/no_main.rs +++ /dev/null @@ -1 +0,0 @@ -#![no_main] diff --git a/tests/run-pass/no_main.stderr b/tests/run-pass/no_main.stderr deleted file mode 100644 index 52591a8d6da31..0000000000000 --- a/tests/run-pass/no_main.stderr +++ /dev/null @@ -1,2 +0,0 @@ -error: miri can only run programs that have a main function - From 2602e951c0301e6502e835b1842e3e144d10c306 Mon Sep 17 00:00:00 2001 From: Samrat Man Singh Date: Thu, 28 May 2020 11:24:47 +0530 Subject: [PATCH 2171/3747] Handle `read`s on STDIN --- src/shims/posix/foreign_items.rs | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/shims/posix/foreign_items.rs b/src/shims/posix/foreign_items.rs index bbda40def620e..8efe8f0ed3fd1 100644 --- a/src/shims/posix/foreign_items.rs +++ b/src/shims/posix/foreign_items.rs @@ -67,7 +67,18 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let buf = this.read_scalar(buf)?.not_undef()?; let count = this.read_scalar(count)?.to_machine_usize(this)?; let result = if fd == 0 { - throw_unsup_format!("reading from stdin is not implemented") + use std::io::{self, Read}; + + let mut buffer = String::new(); + let res = io::stdin().read_to_string(&mut buffer); + + match res { + Ok(bytes) => { + this.memory.write_bytes(buf, buffer.bytes())?; + i64::try_from(bytes).unwrap() + }, + Err(_) => -1, + } } else if fd == 1 || fd == 2 { throw_unsup_format!("cannot read from stdout/stderr") } else { From 15466e00b05c9167687e75582568c3d699e22e62 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 11 Jul 2020 11:07:17 +0200 Subject: [PATCH 2172/3747] go back to using canonicalize() --- cargo-miri/bin.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index 6d4c51256febd..33a1124aaba09 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -10,7 +10,7 @@ use std::process::Command; use rustc_version::VersionMeta; -const XARGO_MIN_VERSION: (u32, u32, u32) = (0, 3, 20); +const XARGO_MIN_VERSION: (u32, u32, u32) = (0, 3, 21); const CARGO_MIRI_HELP: &str = r#"Interprets bin crates and tests in Miri @@ -258,8 +258,9 @@ fn setup(subcommand: MiriCommand) { // Determine where the rust sources are located. `XARGO_RUST_SRC` env var trumps everything. let rust_src = match std::env::var_os("XARGO_RUST_SRC") { Some(path) => { - // Make path absolute, but not via `canonicalize` (which does not work very well on Windows). - env::current_dir().unwrap().join(path) + let path = PathBuf::from(path); + // Make path absolute if possible. + path.canonicalize().unwrap_or(path) } None => { // Check for `rust-src` rustup component. From f68bba9906c85a508531daaa1f64da723185b6c4 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 11 Jul 2020 20:56:47 +0200 Subject: [PATCH 2173/3747] test casting a dangling ptr back from an int --- tests/run-pass/intptrcast.rs | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/tests/run-pass/intptrcast.rs b/tests/run-pass/intptrcast.rs index c2711f9845d0f..6e72d30d41235 100644 --- a/tests/run-pass/intptrcast.rs +++ b/tests/run-pass/intptrcast.rs @@ -12,6 +12,20 @@ fn cast() { assert_eq!(z, y % 256); } +/// Test usize->ptr cast for dangling and OOB address. +/// That is safe, and thus has to work. +fn cast_dangling() { + let b = Box::new(0); + let x = &*b as *const i32 as usize; + drop(b); + let _val = x as *const i32; + + let b = Box::new(0); + let mut x = &*b as *const i32 as usize; + x += 0x100; + let _val = x as *const i32; +} + fn format() { // Pointer string formatting! We can't check the output as it changes when libstd changes, // but we can make sure Miri does not error. @@ -47,8 +61,7 @@ fn ptr_eq_dangling() { drop(b); let b = Box::new(0); let y = &*b as *const i32; // different allocation - // We cannot compare these even though both are inbounds -- they *could* be - // equal if memory was reused. + // They *could* be equal if memory was reused, but probably are not. assert!(x != y); } @@ -57,27 +70,27 @@ fn ptr_eq_out_of_bounds() { let x = (&*b as *const i32).wrapping_sub(0x800); // out-of-bounds let b = Box::new(0); let y = &*b as *const i32; // different allocation - // We cannot compare these even though both allocations are live -- they *could* be - // equal (with the right base addresses). + // They *could* be equal (with the right base addresses), but probably are not. assert!(x != y); } fn ptr_eq_out_of_bounds_null() { let b = Box::new(0); let x = (&*b as *const i32).wrapping_sub(0x800); // out-of-bounds - // We cannot compare this with NULL. After all, this *could* be NULL (with the right base address). + // This *could* be NULL (with the right base address), but probably is not. assert!(x != std::ptr::null()); } fn ptr_eq_integer() { let b = Box::new(0); let x = &*b as *const i32; - // We cannot compare this with a non-NULL integer. After all, these *could* be equal (with the right base address). + // These *could* be equal (with the right base address), but probably are not. assert!(x != 64 as *const i32); } fn main() { cast(); + cast_dangling(); format(); transmute(); ptr_bitops1(); From 74ff4f805a2f6f8f098f1e3323bc57277cfeb2fa Mon Sep 17 00:00:00 2001 From: Samrat Man Singh Date: Sun, 12 Jul 2020 20:27:19 +0530 Subject: [PATCH 2174/3747] Read into buffer of fixed size for `read`s to STDIN Also: - Check isolation is disabled. - Add FIXMEs to set error numbers in `read` and `write`. --- src/shims/posix/foreign_items.rs | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/shims/posix/foreign_items.rs b/src/shims/posix/foreign_items.rs index 8efe8f0ed3fd1..200d50433b3ee 100644 --- a/src/shims/posix/foreign_items.rs +++ b/src/shims/posix/foreign_items.rs @@ -69,14 +69,21 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let result = if fd == 0 { use std::io::{self, Read}; - let mut buffer = String::new(); - let res = io::stdin().read_to_string(&mut buffer); + this.check_no_isolation("read")?; + + let mut buffer = vec![0; count as usize]; + let res = io::stdin() + .read(&mut buffer) + // `Stdin::read` never returns a value larger + // than `count`, so this cannot fail. + .map(|c| i64::try_from(c).unwrap()); match res { Ok(bytes) => { - this.memory.write_bytes(buf, buffer.bytes())?; + this.memory.write_bytes(buf, buffer)?; i64::try_from(bytes).unwrap() }, + // FIXME: set errno to appropriate value Err(_) => -1, } } else if fd == 1 || fd == 2 { @@ -114,6 +121,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx }; match res { Ok(n) => i64::try_from(n).unwrap(), + // FIXME: set errno to appropriate value Err(_) => -1, } } else { From ce5ed69eac64dc581debf39c0ec4322126ff55f0 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 15 Jul 2020 08:42:15 +0200 Subject: [PATCH 2175/3747] rustup; fix Windows TLS --- rust-version | 2 +- src/shims/tls.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/rust-version b/rust-version index f1a465c7d6240..c8c4d489e1d6f 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -8ac1525e091d3db28e67adcbbd6db1e1deaa37fb +567ad7455d5f25f6b38d2fded1cb621e0c34a48b diff --git a/src/shims/tls.rs b/src/shims/tls.rs index 0cd9ef0565058..d2d5522c40232 100644 --- a/src/shims/tls.rs +++ b/src/shims/tls.rs @@ -236,7 +236,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // (that would be basically https://github.com/rust-lang/miri/issues/450), // we specifically look up the static in libstd that we know is placed // in that section. - let thread_callback = this.eval_path_scalar(&["std", "sys", "windows", "thread_local", "p_thread_callback"])?; + let thread_callback = this.eval_path_scalar(&["std", "sys", "windows", "thread_local_key", "p_thread_callback"])?; let thread_callback = this.memory.get_fn(thread_callback.not_undef()?)?.as_instance()?; // The signature of this function is `unsafe extern "system" fn(h: c::LPVOID, dwReason: c::DWORD, pv: c::LPVOID)`. From 6dbfb2d9dee84b29612527044fc308e6304cfbf2 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 15 Jul 2020 10:09:28 +0200 Subject: [PATCH 2176/3747] make cfg(miri) greppable --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index ab4d4c02db1ed..e20c53b68dc5e 100644 --- a/README.md +++ b/README.md @@ -94,9 +94,9 @@ Linux program, you can do `cargo miri run --target x86_64-unknown-linux-gnu`. This is particularly useful if you are using Windows, as the Linux target is much better supported than Windows targets. -When compiling code via `cargo miri`, the `miri` config flag is set. You can -use this to ignore test cases that fail under Miri because they do things Miri -does not support: +When compiling code via `cargo miri`, the `cfg(miri)` config flag is set. You +can use this to ignore test cases that fail under Miri because they do things +Miri does not support: ```rust #[test] From c28786d320048b81d2433689fac7ce5429292b46 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 16 Jul 2020 12:16:43 +0200 Subject: [PATCH 2177/3747] remove an unnecessary intermediate cast --- src/shims/posix/fs.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/shims/posix/fs.rs b/src/shims/posix/fs.rs index 87aa28120c28e..7754c02744e6f 100644 --- a/src/shims/posix/fs.rs +++ b/src/shims/posix/fs.rs @@ -461,9 +461,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if let Some(FileHandle { file, writable: _ }) = this.machine.file_handler.handles.get_mut(&fd) { trace!("read: FD mapped to {:?}", file); - // This can never fail because `count` was capped to be smaller than - // `isize::MAX`. - let count = isize::try_from(count).unwrap(); // We want to read at most `count` bytes. We are sure that `count` is not negative // because it was a target's `usize`. Also we are sure that its smaller than // `usize::MAX` because it is a host's `isize`. From d617d615e4f310eadde6e3be1c1e970e9608bb81 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 17 Jul 2020 12:54:38 +0200 Subject: [PATCH 2178/3747] fix non-fatal diagnostics stacktraces --- src/diagnostics.rs | 101 +++++++++++++++++++++++++++++++++------------ src/eval.rs | 3 +- src/thread.rs | 3 ++ 3 files changed, 79 insertions(+), 28 deletions(-) diff --git a/src/diagnostics.rs b/src/diagnostics.rs index 8fdf039ce8e6c..009f8aa29cecf 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -3,7 +3,8 @@ use std::fmt; use log::trace; -use rustc_span::DUMMY_SP; +use rustc_middle::ty::{self, TyCtxt}; +use rustc_span::{source_map::DUMMY_SP, Span}; use crate::*; @@ -116,7 +117,17 @@ pub fn report_error<'tcx, 'mir>( e.print_backtrace(); let msg = e.to_string(); - report_msg(ecx, &format!("{}: {}", title, msg), msg, helps, true); + report_msg(*ecx.tcx, /*error*/true, &format!("{}: {}", title, msg), msg, helps, &ecx.generate_stacktrace()); + + // Debug-dump all locals. + for (i, frame) in ecx.active_thread_stack().iter().enumerate() { + trace!("-------------------"); + trace!("Frame {}", i); + trace!(" return: {:?}", frame.return_place.map(|p| *p)); + for (i, local) in frame.locals.iter().enumerate() { + trace!(" local {}: {:?}", i, local.value); + } + } // Extra output to help debug specific issues. match e.kind { @@ -135,24 +146,21 @@ pub fn report_error<'tcx, 'mir>( None } -/// Report an error or note (depending on the `error` argument) at the current frame's current statement. +/// Report an error or note (depending on the `error` argument) with the given stacktrace. /// Also emits a full stacktrace of the interpreter stack. -fn report_msg<'tcx, 'mir>( - ecx: &InterpCx<'mir, 'tcx, Evaluator<'mir, 'tcx>>, +fn report_msg<'tcx>( + tcx: TyCtxt<'tcx>, + error: bool, title: &str, span_msg: String, mut helps: Vec, - error: bool, + stacktrace: &[FrameInfo<'tcx>], ) { - let span = if let Some(frame) = ecx.active_thread_stack().last() { - frame.current_source_info().unwrap().span - } else { - DUMMY_SP - }; + let span = stacktrace.first().map_or(DUMMY_SP, |fi| fi.span); let mut err = if error { - ecx.tcx.sess.struct_span_err(span, title) + tcx.sess.struct_span_err(span, title) } else { - ecx.tcx.sess.diagnostic().span_note_diag(span, title) + tcx.sess.diagnostic().span_note_diag(span, title) }; err.span_label(span, span_msg); if !helps.is_empty() { @@ -163,8 +171,7 @@ fn report_msg<'tcx, 'mir>( } } // Add backtrace - let frames = ecx.generate_stacktrace(); - for (idx, frame_info) in frames.iter().enumerate() { + for (idx, frame_info) in stacktrace.iter().enumerate() { let is_local = frame_info.instance.def_id().is_local(); // No span for non-local frames and the first frame (which is the error site). if is_local && idx > 0 { @@ -175,15 +182,6 @@ fn report_msg<'tcx, 'mir>( } err.emit(); - - for (i, frame) in ecx.active_thread_stack().iter().enumerate() { - trace!("-------------------"); - trace!("Frame {}", i); - trace!(" return: {:?}", frame.return_place.map(|p| *p)); - for (i, local) in frame.locals.iter().enumerate() { - trace!(" local {}: {:?}", i, local.value); - } - } } thread_local! { @@ -196,13 +194,62 @@ pub fn register_diagnostic(e: NonHaltingDiagnostic) { DIAGNOSTICS.with(|diagnostics| diagnostics.borrow_mut().push(e)); } +/// Remember enough about the topmost frame so that we can restore the stack +/// after a step was taken. +pub struct TopFrameInfo<'tcx> { + stack_size: usize, + instance: ty::Instance<'tcx>, + span: Span, +} + impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { + fn preprocess_diagnostics(&self) -> TopFrameInfo<'tcx> { + // Ensure we have no lingering diagnostics. + DIAGNOSTICS.with(|diagnostics| assert!(diagnostics.borrow().is_empty())); + + let this = self.eval_context_ref(); + let frame = this.frame(); + + TopFrameInfo { + stack_size: this.active_thread_stack().len(), + instance: frame.instance, + span: frame.current_source_info().map_or(DUMMY_SP, |si| si.span), + } + } + /// Emit all diagnostics that were registed with `register_diagnostics` - fn process_diagnostics(&self) { + fn process_diagnostics(&self, info: TopFrameInfo<'tcx>) { let this = self.eval_context_ref(); DIAGNOSTICS.with(|diagnostics| { - for e in diagnostics.borrow_mut().drain(..) { + let mut diagnostics = diagnostics.borrow_mut(); + if diagnostics.is_empty() { + return; + } + // We need to fix up the stack trace, because the machine has already + // stepped to the next statement. + let mut stacktrace = this.generate_stacktrace(); + // Remove newly pushed frames. + while stacktrace.len() > info.stack_size { + stacktrace.remove(0); + } + // Add popped frame back. + if stacktrace.len() < info.stack_size { + assert!(stacktrace.len() == info.stack_size-1, "we should never pop more than one frame at once"); + let frame_info = FrameInfo { + instance: info.instance, + span: info.span, + lint_root: None, + }; + stacktrace.insert(0, frame_info); + } else { + // Adjust topmost frame. + stacktrace[0].span = info.span; + assert_eq!(stacktrace[0].instance, info.instance, "we should not pop and push a frame in one step"); + } + + // Show diagnostics. + for e in diagnostics.drain(..) { use NonHaltingDiagnostic::*; let msg = match e { PoppedPointerTag(item) => @@ -214,7 +261,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx FreedAlloc(AllocId(id)) => format!("freed allocation with id {}", id), }; - report_msg(this, "tracking was triggered", msg, vec![], false); + report_msg(*this.tcx, /*error*/false, "tracking was triggered", msg, vec![], &stacktrace); } }); } diff --git a/src/eval.rs b/src/eval.rs index ee429dd3143ed..79ceb6be806e2 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -212,7 +212,9 @@ pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) -> loop { match ecx.schedule()? { SchedulingAction::ExecuteStep => { + let info = ecx.preprocess_diagnostics(); assert!(ecx.step()?, "a terminated thread was scheduled for execution"); + ecx.process_diagnostics(info); } SchedulingAction::ExecuteTimeoutCallback => { assert!(ecx.machine.communicate, @@ -230,7 +232,6 @@ pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) -> break; } } - ecx.process_diagnostics(); } let return_code = ecx.read_scalar(ret_place.into())?.not_undef()?.to_machine_isize(&ecx)?; Ok(return_code) diff --git a/src/thread.rs b/src/thread.rs index 896f93ef1a3a1..aee7d395ddfcf 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -373,6 +373,9 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { /// Change the active thread to some enabled thread. fn yield_active_thread(&mut self) { + // We do not immediately, as swapping out the current stack while execution a MIR statement + // could lead to all sorts of confusion. + // We should only switch stacks between steps. self.yield_active_thread = true; } From 545aa6019557ae2777233e1d8f6cbd8b6f7b3180 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 17 Jul 2020 13:39:25 +0200 Subject: [PATCH 2179/3747] fix typo Co-authored-by: Oliver Scherer --- src/thread.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/thread.rs b/src/thread.rs index aee7d395ddfcf..42a4dbded58f4 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -373,7 +373,7 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { /// Change the active thread to some enabled thread. fn yield_active_thread(&mut self) { - // We do not immediately, as swapping out the current stack while execution a MIR statement + // We do not yield immediately, as swapping out the current stack while executing a MIR statement // could lead to all sorts of confusion. // We should only switch stacks between steps. self.yield_active_thread = true; From 4c1beb2e453cdd8f3678e399aaa60c2c02980348 Mon Sep 17 00:00:00 2001 From: Samrat Man Singh Date: Fri, 17 Jul 2020 00:03:56 +0530 Subject: [PATCH 2180/3747] Ensure buffer for reading from Stdin is smaller than machine usize Also, set appropriate error code on failure --- src/shims/posix/foreign_items.rs | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/src/shims/posix/foreign_items.rs b/src/shims/posix/foreign_items.rs index 200d50433b3ee..81708e61b1ab5 100644 --- a/src/shims/posix/foreign_items.rs +++ b/src/shims/posix/foreign_items.rs @@ -1,4 +1,5 @@ use std::convert::TryFrom; +use std::io::{self, Read, Write}; use log::trace; @@ -11,6 +12,7 @@ use shims::posix::fs::EvalContextExt as _; use shims::posix::sync::EvalContextExt as _; use shims::posix::thread::EvalContextExt as _; + impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { fn emulate_foreign_item_by_name( @@ -67,10 +69,23 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let buf = this.read_scalar(buf)?.not_undef()?; let count = this.read_scalar(count)?.to_machine_usize(this)?; let result = if fd == 0 { - use std::io::{self, Read}; this.check_no_isolation("read")?; + // We cap the number of read bytes to the largest + // value that we are able to fit in both the + // host's and target's `isize`. This saves us from + // having to handle overflows later. + let count = count.min(this.machine_isize_max() as u64).min(isize::MAX as u64); + // This can never fail because `count` was capped + // to be smaller than `isize::MAX`. + let count = isize::try_from(count).unwrap(); + + // We want to read at most `count` bytes. We are + // sure that `count` is not negative because it + // was a target's `usize`. Also we are sure that + // its smaller than `usize::MAX` because it is a + // host's `isize`. let mut buffer = vec![0; count as usize]; let res = io::stdin() .read(&mut buffer) @@ -83,8 +98,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.memory.write_bytes(buf, buffer)?; i64::try_from(bytes).unwrap() }, - // FIXME: set errno to appropriate value - Err(_) => -1, + Err(e) => { + this.set_last_error_from_io_error(e)?; + -1 + }, } } else if fd == 1 || fd == 2 { throw_unsup_format!("cannot read from stdout/stderr") @@ -103,7 +120,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx throw_unsup_format!("cannot write to stdin") } else if fd == 1 || fd == 2 { // stdout/stderr - use std::io::{self, Write}; let buf_cont = this.memory.read_bytes(buf, Size::from_bytes(count))?; // We need to flush to make sure this actually appears on the screen From f4d1841811c260c96c71a41774d3cb61b62dad7f Mon Sep 17 00:00:00 2001 From: Samrat Man Singh Date: Sat, 18 Jul 2020 10:45:06 +0530 Subject: [PATCH 2181/3747] Remove unnecessary cast --- src/shims/posix/foreign_items.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/shims/posix/foreign_items.rs b/src/shims/posix/foreign_items.rs index 81708e61b1ab5..e0ad0d8d4112e 100644 --- a/src/shims/posix/foreign_items.rs +++ b/src/shims/posix/foreign_items.rs @@ -12,7 +12,6 @@ use shims::posix::fs::EvalContextExt as _; use shims::posix::sync::EvalContextExt as _; use shims::posix::thread::EvalContextExt as _; - impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { fn emulate_foreign_item_by_name( @@ -77,9 +76,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // host's and target's `isize`. This saves us from // having to handle overflows later. let count = count.min(this.machine_isize_max() as u64).min(isize::MAX as u64); - // This can never fail because `count` was capped - // to be smaller than `isize::MAX`. - let count = isize::try_from(count).unwrap(); // We want to read at most `count` bytes. We are // sure that `count` is not negative because it From d1aee6965bca6d31d1d414e7174b40e89a326483 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Naz=C4=B1m=20Can=20Alt=C4=B1nova?= Date: Sat, 18 Jul 2020 12:48:26 +0200 Subject: [PATCH 2182/3747] Remove unreachable intrinsic --- src/shims/intrinsics.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 68f67a1ed98d4..c44caed34f65a 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -37,7 +37,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let (dest, ret) = match ret { None => match intrinsic_name { "miri_start_panic" => return this.handle_miri_start_panic(args, unwind), - "unreachable" => throw_ub!(Unreachable), _ => throw_unsup_format!("unimplemented (diverging) intrinsic: {}", intrinsic_name), }, Some(p) => p, From cded9b7142b3b8d0e986d85e93ea502bd7a0d668 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 18 Jul 2020 17:58:16 +0200 Subject: [PATCH 2183/3747] set errno on stdout write failure --- src/shims/posix/foreign_items.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/shims/posix/foreign_items.rs b/src/shims/posix/foreign_items.rs index e0ad0d8d4112e..80611a18e4fc7 100644 --- a/src/shims/posix/foreign_items.rs +++ b/src/shims/posix/foreign_items.rs @@ -133,8 +133,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx }; match res { Ok(n) => i64::try_from(n).unwrap(), - // FIXME: set errno to appropriate value - Err(_) => -1, + Err(e) => { + this.set_last_error_from_io_error(e)?; + -1 + } } } else { this.write(fd, buf, count)? From 7d6aec68878ae15044ec8f075a5bede15ae421d3 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 23 Jul 2020 10:40:13 +0200 Subject: [PATCH 2184/3747] rustup --- rust-version | 2 +- src/helpers.rs | 4 ++-- src/shims/posix/fs.rs | 3 ++- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/rust-version b/rust-version index c8c4d489e1d6f..bfbf6b81b2e2e 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -567ad7455d5f25f6b38d2fded1cb621e0c34a48b +4825e12fc9c79954aa0fe18f5521efa6c19c7539 diff --git a/src/helpers.rs b/src/helpers.rs index c1eaf4eb4865d..473da84aeea35 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -92,14 +92,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// Helper function to get the `TyAndLayout` of a `libc` type fn libc_ty_layout(&mut self, name: &str) -> InterpResult<'tcx, TyAndLayout<'tcx>> { let this = self.eval_context_mut(); - let ty = this.resolve_path(&["libc", name]).monomorphic_ty(*this.tcx); + let ty = this.resolve_path(&["libc", name]).ty(*this.tcx, ty::ParamEnv::reveal_all()); this.layout_of(ty) } /// Helper function to get the `TyAndLayout` of a `windows` type fn windows_ty_layout(&mut self, name: &str) -> InterpResult<'tcx, TyAndLayout<'tcx>> { let this = self.eval_context_mut(); - let ty = this.resolve_path(&["std", "sys", "windows", "c", name]).monomorphic_ty(*this.tcx); + let ty = this.resolve_path(&["std", "sys", "windows", "c", name]).ty(*this.tcx, ty::ParamEnv::reveal_all()); this.layout_of(ty) } diff --git a/src/shims/posix/fs.rs b/src/shims/posix/fs.rs index 7754c02744e6f..a43e86dcc5b5b 100644 --- a/src/shims/posix/fs.rs +++ b/src/shims/posix/fs.rs @@ -9,6 +9,7 @@ use log::trace; use rustc_data_structures::fx::FxHashMap; use rustc_target::abi::{Align, LayoutOf, Size}; +use rustc_middle::ty; use crate::*; use stacked_borrows::Tag; @@ -670,7 +671,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // function and `resolve_path` is returning the latter. let statx_ty = this .resolve_path(&["libc", "unix", "linux_like", "linux", "gnu", "statx"]) - .monomorphic_ty(*this.tcx); + .ty(*this.tcx, ty::ParamEnv::reveal_all()); let statxbuf_ty = this.tcx.mk_mut_ptr(statx_ty); let statxbuf_layout = this.layout_of(statxbuf_ty)?; let statxbuf_imm = ImmTy::from_scalar(statxbuf_scalar, statxbuf_layout); From 4033358956eaca6ccd7fe6d905b572c243673a62 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 23 Jul 2020 15:20:36 +0200 Subject: [PATCH 2185/3747] make miri_start_panic intrinsic an FFI function --- src/shims/foreign_items.rs | 6 +++++- src/shims/intrinsics.rs | 9 +++------ 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index a7495beef72ee..cf85636b57bf2 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -111,7 +111,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx def_id: DefId, args: &[OpTy<'tcx, Tag>], ret: Option<(PlaceTy<'tcx, Tag>, mir::BasicBlock)>, - _unwind: Option, + unwind: Option, ) -> InterpResult<'tcx, Option<&'mir mir::Body<'tcx>>> { let this = self.eval_context_mut(); let attrs = this.tcx.get_attrs(def_id); @@ -126,6 +126,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // First: functions that diverge. let (dest, ret) = match ret { None => match link_name { + "miri_start_panic" => { + this.handle_miri_start_panic(args, unwind)?; + return Ok(None); + } // This matches calls to the foreign item `panic_impl`. // The implementation is provided by the function with the `#[panic_handler]` attribute. "panic_impl" => { diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index c44caed34f65a..f542bebd82ad1 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -18,7 +18,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx instance: ty::Instance<'tcx>, args: &[OpTy<'tcx, Tag>], ret: Option<(PlaceTy<'tcx, Tag>, mir::BasicBlock)>, - unwind: Option, + _unwind: Option, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let intrinsic_name = this.tcx.item_name(instance.def_id()); @@ -32,13 +32,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx return Ok(()); } - // First handle intrinsics without return place. + // All supported intrinsics have a return place. let intrinsic_name = &*intrinsic_name.as_str(); let (dest, ret) = match ret { - None => match intrinsic_name { - "miri_start_panic" => return this.handle_miri_start_panic(args, unwind), - _ => throw_unsup_format!("unimplemented (diverging) intrinsic: {}", intrinsic_name), - }, + None => throw_unsup_format!("unimplemented (diverging) intrinsic: {}", intrinsic_name), Some(p) => p, }; From fef5fa2ae160118d7165a6394ff9d5447da17729 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 23 Jul 2020 15:47:33 +0200 Subject: [PATCH 2186/3747] add a Miri extern fn to mark an allocation as being a static root for leak checking --- src/eval.rs | 8 +++++--- src/machine.rs | 4 ++++ src/shims/foreign_items.rs | 11 +++++++++++ 3 files changed, 20 insertions(+), 3 deletions(-) diff --git a/src/eval.rs b/src/eval.rs index 79ceb6be806e2..24cf0cbf06be0 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -5,6 +5,7 @@ use std::ffi::OsStr; use rand::rngs::StdRng; use rand::SeedableRng; +use log::info; use rustc_hir::def_id::DefId; use rustc_middle::ty::{self, layout::LayoutCx, TyCtxt}; @@ -195,8 +196,8 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( /// Returns `Some(return_code)` if program executed completed. /// Returns `None` if an evaluation error occured. pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) -> Option { - // FIXME: on Windows, we ignore leaks (https://github.com/rust-lang/miri/issues/1302). - let ignore_leaks = config.ignore_leaks || tcx.sess.target.target.target_os == "windows"; + // Copy setting before we move `config`. + let ignore_leaks = config.ignore_leaks; let (mut ecx, ret_place) = match create_ecx(tcx, main_id, config) { Ok(v) => v, @@ -244,7 +245,8 @@ pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) -> match res { Ok(return_code) => { if !ignore_leaks { - let leaks = ecx.memory.leak_report(); + info!("Additonal static roots: {:?}", ecx.machine.static_roots); + let leaks = ecx.memory.leak_report(&ecx.machine.static_roots); if leaks != 0 { tcx.sess.err("the evaluated program leaked memory"); // Ignore the provided return code - let the reported error diff --git a/src/machine.rs b/src/machine.rs index 49d647838c9e1..e9217896ef6eb 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -262,6 +262,9 @@ pub struct Evaluator<'mir, 'tcx> { /// Precomputed `TyLayout`s for primitive data types that are commonly used inside Miri. pub(crate) layouts: PrimitiveLayouts<'tcx>, + + /// Allocations that are considered roots of static memory (that may leak). + pub(crate) static_roots: Vec, } impl<'mir, 'tcx> Evaluator<'mir, 'tcx> { @@ -289,6 +292,7 @@ impl<'mir, 'tcx> Evaluator<'mir, 'tcx> { time_anchor: Instant::now(), layouts, threads: ThreadManager::default(), + static_roots: Vec::new(), } } } diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index cf85636b57bf2..f1b04afe0a620 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -197,6 +197,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Here we dispatch all the shims for foreign functions. If you have a platform specific // shim, add it to the corresponding submodule. match link_name { + // Miri-specific extern functions + "miri_static_root" => { + let &[ptr] = check_arg_count(args)?; + let ptr = this.read_scalar(ptr)?.not_undef()?; + let ptr = this.force_ptr(ptr)?; + if ptr.offset != Size::ZERO { + throw_unsup_format!("Pointer passed to miri_static_root must point to beginning of an allocated block"); + } + this.machine.static_roots.push(ptr.alloc_id); + } + // Standard C allocation "malloc" => { let &[size] = check_arg_count(args)?; From bc0569253f6e8ab98232dd8020bd44b7262c91ec Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 23 Jul 2020 15:49:22 +0200 Subject: [PATCH 2187/3747] enable leak check tests on Windows --- src/shims/foreign_items.rs | 2 +- tests/compile-fail/memleak.rs | 2 -- tests/compile-fail/memleak_rc.rs | 2 -- 3 files changed, 1 insertion(+), 5 deletions(-) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index f1b04afe0a620..7323a664bda8d 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -203,7 +203,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let ptr = this.read_scalar(ptr)?.not_undef()?; let ptr = this.force_ptr(ptr)?; if ptr.offset != Size::ZERO { - throw_unsup_format!("Pointer passed to miri_static_root must point to beginning of an allocated block"); + throw_unsup_format!("pointer passed to miri_static_root must point to beginning of an allocated block"); } this.machine.static_roots.push(ptr.alloc_id); } diff --git a/tests/compile-fail/memleak.rs b/tests/compile-fail/memleak.rs index c3b27abcdbb28..71b4e2f442f31 100644 --- a/tests/compile-fail/memleak.rs +++ b/tests/compile-fail/memleak.rs @@ -1,5 +1,3 @@ -// ignore-windows: We do not check leaks on Windows - //error-pattern: the evaluated program leaked memory fn main() { diff --git a/tests/compile-fail/memleak_rc.rs b/tests/compile-fail/memleak_rc.rs index 446d28681b9eb..b2bc6722afb04 100644 --- a/tests/compile-fail/memleak_rc.rs +++ b/tests/compile-fail/memleak_rc.rs @@ -1,5 +1,3 @@ -// ignore-windows: We do not check leaks on Windows - //error-pattern: the evaluated program leaked memory use std::rc::Rc; From 06f8bf6afa887a04ecdce0e5d8c7b4c66e2736d2 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 23 Jul 2020 17:14:25 +0200 Subject: [PATCH 2188/3747] document Miri extern functions --- README.md | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/README.md b/README.md index e20c53b68dc5e..f97639ea5bdfd 100644 --- a/README.md +++ b/README.md @@ -233,6 +233,29 @@ different Miri binaries, and as such worth documenting: interpret the code but compile it like rustc would. This is useful to be sure that the compiled `rlib`s are compatible with Miri. +## Miri `extern` functions + +Miri provides some `extern` functions that programs can import to access +Miri-specific functionality: + +```rust +#[cfg(miri)] +extern "Rust" { + /// Miri-provided extern function to mark the block `ptr` points to as a "root" + /// for some static memory. This memory and everything reachable by it is not + /// considered leaking even if it still exists when the program terminates. + /// + /// `ptr` has to point to the beginning of an allocated block. + fn miri_static_root(ptr: *const u8); + + /// Miri-provided extern function to begin unwinding with the given payload. + /// + /// This is internal and unstable and should not be used; we give it here + /// just to be complete. + fn miri_start_panic(payload: *mut u8) -> !; +} +``` + ## Contributing and getting help If you want to contribute to Miri, great! Please check out our From c641fbde0223cde9fae67de3cc4892998a21cec0 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 25 Jul 2020 10:02:25 +0200 Subject: [PATCH 2189/3747] update rust-version --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index bfbf6b81b2e2e..d0c938c53fafd 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -4825e12fc9c79954aa0fe18f5521efa6c19c7539 +0e11fc8053d32c44e7152865852acc5c3c54efb3 From 5161ba346c646914b4992aa9cc97d0e4309128b6 Mon Sep 17 00:00:00 2001 From: Philippe Nadon Date: Thu, 23 Jul 2020 09:50:45 -0600 Subject: [PATCH 2190/3747] renamed ScalarMaybeUninit::not_undef to check_init Related to PR https://github.com/rust-lang/rust/pull/74664 --- src/eval.rs | 2 +- src/helpers.rs | 8 +++--- src/operator.rs | 6 ++--- src/shims/env.rs | 34 +++++++++++++------------- src/shims/foreign_items.rs | 18 +++++++------- src/shims/intrinsics.rs | 8 +++--- src/shims/mod.rs | 4 +-- src/shims/panic.rs | 8 +++--- src/shims/posix/foreign_items.rs | 22 ++++++++--------- src/shims/posix/fs.rs | 26 ++++++++++---------- src/shims/posix/linux/foreign_items.rs | 2 +- src/shims/posix/macos/dlsym.rs | 2 +- src/shims/posix/macos/foreign_items.rs | 8 +++--- src/shims/posix/sync.rs | 18 +++++++------- src/shims/posix/thread.rs | 8 +++--- src/shims/time.rs | 2 +- src/shims/tls.rs | 2 +- src/shims/windows/foreign_items.rs | 14 +++++------ 18 files changed, 96 insertions(+), 96 deletions(-) diff --git a/src/eval.rs b/src/eval.rs index 24cf0cbf06be0..8561edcc05b9c 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -234,7 +234,7 @@ pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) -> } } } - let return_code = ecx.read_scalar(ret_place.into())?.not_undef()?.to_machine_isize(&ecx)?; + let return_code = ecx.read_scalar(ret_place.into())?.check_init()?.to_machine_isize(&ecx)?; Ok(return_code) })(); diff --git a/src/helpers.rs b/src/helpers.rs index 473da84aeea35..d271b845c2151 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -67,7 +67,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn eval_libc(&mut self, name: &str) -> InterpResult<'tcx, Scalar> { self.eval_context_mut() .eval_path_scalar(&["libc", name])? - .not_undef() + .check_init() } /// Helper function to get a `libc` constant as an `i32`. @@ -80,7 +80,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn eval_windows(&mut self, module: &str, name: &str) -> InterpResult<'tcx, Scalar> { self.eval_context_mut() .eval_path_scalar(&["std", "sys", "windows", module, name])? - .not_undef() + .check_init() } /// Helper function to get a `windows` constant as an `u64`. @@ -407,7 +407,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn get_last_error(&self) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_ref(); let errno_place = this.machine.last_error.unwrap(); - this.read_scalar(errno_place.into())?.not_undef() + this.read_scalar(errno_place.into())?.check_init() } /// Sets the last OS error using a `std::io::Error`. This function tries to produce the most @@ -467,7 +467,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } } - + fn read_scalar_at_offset( &self, op: OpTy<'tcx, Tag>, diff --git a/src/operator.rs b/src/operator.rs index bfc8e908dc15b..5b86b9a76f6b4 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -32,11 +32,11 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { #[rustfmt::skip] let eq = match (*left, *right) { (Immediate::Scalar(left), Immediate::Scalar(right)) => { - self.ptr_eq(left.not_undef()?, right.not_undef()?)? + self.ptr_eq(left.check_init()?, right.check_init()?)? } (Immediate::ScalarPair(left1, left2), Immediate::ScalarPair(right1, right2)) => { - self.ptr_eq(left1.not_undef()?, right1.not_undef()?)? - && self.ptr_eq(left2.not_undef()?, right2.not_undef()?)? + self.ptr_eq(left1.check_init()?, right1.check_init()?)? + && self.ptr_eq(left2.check_init()?, right2.check_init()?)? } _ => bug!("Type system should not allow comparing Scalar with ScalarPair"), }; diff --git a/src/shims/env.rs b/src/shims/env.rs index 4a2bec28bd17c..86a7a58ac4aab 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -69,7 +69,7 @@ impl<'tcx> EnvVars<'tcx> { } // Deallocate environ var list. let environ = ecx.machine.env_vars.environ.unwrap(); - let old_vars_ptr = ecx.read_scalar(environ.into())?.not_undef()?; + let old_vars_ptr = ecx.read_scalar(environ.into())?.check_init()?; ecx.memory.deallocate(ecx.force_ptr(old_vars_ptr)?, None, MiriMemoryKind::Env.into())?; Ok(()) } @@ -104,7 +104,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let target_os = &this.tcx.sess.target.target.target_os; assert!(target_os == "linux" || target_os == "macos", "`getenv` is only available for the UNIX target family"); - let name_ptr = this.read_scalar(name_op)?.not_undef()?; + let name_ptr = this.read_scalar(name_op)?.check_init()?; let name = this.read_os_str_from_c_str(name_ptr)?; Ok(match this.machine.env_vars.map.get(name) { Some(var_ptr) => { @@ -125,7 +125,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); this.assert_target_os("windows", "GetEnvironmentVariableW"); - let name_ptr = this.read_scalar(name_op)?.not_undef()?; + let name_ptr = this.read_scalar(name_op)?.check_init()?; let name = this.read_os_str_from_wide_str(name_ptr)?; Ok(match this.machine.env_vars.map.get(&name) { Some(var_ptr) => { @@ -135,7 +135,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let var_ptr = Scalar::from(var_ptr.offset(Size::from_bytes(name_offset_bytes), this)?); let var = this.read_os_str_from_wide_str(var_ptr)?; - let buf_ptr = this.read_scalar(buf_op)?.not_undef()?; + let buf_ptr = this.read_scalar(buf_op)?.check_init()?; // `buf_size` represents the size in characters. let buf_size = u64::from(this.read_scalar(size_op)?.to_u32()?); windows_check_buffer_size(this.write_os_str_to_wide_str(&var, buf_ptr, buf_size)?) @@ -153,7 +153,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); this.assert_target_os("windows", "GetEnvironmentStringsW"); - // Info on layout of environment blocks in Windows: + // Info on layout of environment blocks in Windows: // https://docs.microsoft.com/en-us/windows/win32/procthread/environment-variables let mut env_vars = std::ffi::OsString::new(); for &item in this.machine.env_vars.map.values() { @@ -173,7 +173,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); this.assert_target_os("windows", "FreeEnvironmentStringsW"); - let env_block_ptr = this.read_scalar(env_block_op)?.not_undef()?; + let env_block_ptr = this.read_scalar(env_block_op)?.check_init()?; let result = this.memory.deallocate(this.force_ptr(env_block_ptr)?, None, MiriMemoryKind::Env.into()); // If the function succeeds, the return value is nonzero. Ok(result.is_ok() as i32) @@ -188,8 +188,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let target_os = &this.tcx.sess.target.target.target_os; assert!(target_os == "linux" || target_os == "macos", "`setenv` is only available for the UNIX target family"); - let name_ptr = this.read_scalar(name_op)?.not_undef()?; - let value_ptr = this.read_scalar(value_op)?.not_undef()?; + let name_ptr = this.read_scalar(name_op)?.check_init()?; + let value_ptr = this.read_scalar(value_op)?.check_init()?; let mut new = None; if !this.is_null(name_ptr)? { @@ -224,14 +224,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let mut this = self.eval_context_mut(); this.assert_target_os("windows", "SetEnvironmentVariableW"); - let name_ptr = this.read_scalar(name_op)?.not_undef()?; - let value_ptr = this.read_scalar(value_op)?.not_undef()?; + let name_ptr = this.read_scalar(name_op)?.check_init()?; + let value_ptr = this.read_scalar(value_op)?.check_init()?; if this.is_null(name_ptr)? { // ERROR CODE is not clearly explained in docs.. For now, throw UB instead. throw_ub_format!("pointer to environment variable name is NULL"); } - + let name = this.read_os_str_from_wide_str(name_ptr)?; if name.is_empty() { throw_unsup_format!("environment variable name is an empty string"); @@ -261,7 +261,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let target_os = &this.tcx.sess.target.target.target_os; assert!(target_os == "linux" || target_os == "macos", "`unsetenv` is only available for the UNIX target family"); - let name_ptr = this.read_scalar(name_op)?.not_undef()?; + let name_ptr = this.read_scalar(name_op)?.check_init()?; let mut success = None; if !this.is_null(name_ptr)? { let name = this.read_os_str_from_c_str(name_ptr)?.to_owned(); @@ -295,7 +295,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.check_no_isolation("getcwd")?; - let buf = this.read_scalar(buf_op)?.not_undef()?; + let buf = this.read_scalar(buf_op)?.check_init()?; let size = this.read_scalar(size_op)?.to_machine_usize(&*this.tcx)?; // If we cannot get the current directory, we return null match env::current_dir() { @@ -323,7 +323,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.check_no_isolation("GetCurrentDirectoryW")?; let size = u64::from(this.read_scalar(size_op)?.to_u32()?); - let buf = this.read_scalar(buf_op)?.not_undef()?; + let buf = this.read_scalar(buf_op)?.check_init()?; // If we cannot get the current directory, we return 0 match env::current_dir() { @@ -341,7 +341,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.check_no_isolation("chdir")?; - let path = this.read_path_from_c_str(this.read_scalar(path_op)?.not_undef()?)?; + let path = this.read_path_from_c_str(this.read_scalar(path_op)?.check_init()?)?; match env::set_current_dir(path) { Ok(()) => Ok(0), @@ -362,7 +362,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.check_no_isolation("SetCurrentDirectoryW")?; - let path = this.read_path_from_wide_str(this.read_scalar(path_op)?.not_undef()?)?; + let path = this.read_path_from_wide_str(this.read_scalar(path_op)?.check_init()?)?; match env::set_current_dir(path) { Ok(()) => Ok(1), @@ -379,7 +379,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); // Deallocate the old environ list, if any. if let Some(environ) = this.machine.env_vars.environ { - let old_vars_ptr = this.read_scalar(environ.into())?.not_undef()?; + let old_vars_ptr = this.read_scalar(environ.into())?.check_init()?; this.memory.deallocate(this.force_ptr(old_vars_ptr)?, None, MiriMemoryKind::Env.into())?; } else { // No `environ` allocated yet, let's do that. diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 7323a664bda8d..d4f248f0329dc 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -226,12 +226,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "free" => { let &[ptr] = check_arg_count(args)?; - let ptr = this.read_scalar(ptr)?.not_undef()?; + let ptr = this.read_scalar(ptr)?.check_init()?; this.free(ptr, MiriMemoryKind::C)?; } "realloc" => { let &[old_ptr, new_size] = check_arg_count(args)?; - let old_ptr = this.read_scalar(old_ptr)?.not_undef()?; + let old_ptr = this.read_scalar(old_ptr)?.check_init()?; let new_size = this.read_scalar(new_size)?.to_machine_usize(this)?; let res = this.realloc(old_ptr, new_size, MiriMemoryKind::C)?; this.write_scalar(res, dest)?; @@ -268,7 +268,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "__rust_dealloc" => { let &[ptr, old_size, align] = check_arg_count(args)?; - let ptr = this.read_scalar(ptr)?.not_undef()?; + let ptr = this.read_scalar(ptr)?.check_init()?; let old_size = this.read_scalar(old_size)?.to_machine_usize(this)?; let align = this.read_scalar(align)?.to_machine_usize(this)?; // No need to check old_size/align; we anyway check that they match the allocation. @@ -281,7 +281,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "__rust_realloc" => { let &[ptr, old_size, align, new_size] = check_arg_count(args)?; - let ptr = this.force_ptr(this.read_scalar(ptr)?.not_undef()?)?; + let ptr = this.force_ptr(this.read_scalar(ptr)?.check_init()?)?; let old_size = this.read_scalar(old_size)?.to_machine_usize(this)?; let align = this.read_scalar(align)?.to_machine_usize(this)?; let new_size = this.read_scalar(new_size)?.to_machine_usize(this)?; @@ -301,8 +301,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // C memory handling functions "memcmp" => { let &[left, right, n] = check_arg_count(args)?; - let left = this.read_scalar(left)?.not_undef()?; - let right = this.read_scalar(right)?.not_undef()?; + let left = this.read_scalar(left)?.check_init()?; + let right = this.read_scalar(right)?.check_init()?; let n = Size::from_bytes(this.read_scalar(n)?.to_machine_usize(this)?); let result = { @@ -321,7 +321,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "memrchr" => { let &[ptr, val, num] = check_arg_count(args)?; - let ptr = this.read_scalar(ptr)?.not_undef()?; + let ptr = this.read_scalar(ptr)?.check_init()?; let val = this.read_scalar(val)?.to_i32()? as u8; let num = this.read_scalar(num)?.to_machine_usize(this)?; if let Some(idx) = this @@ -339,7 +339,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "memchr" => { let &[ptr, val, num] = check_arg_count(args)?; - let ptr = this.read_scalar(ptr)?.not_undef()?; + let ptr = this.read_scalar(ptr)?.check_init()?; let val = this.read_scalar(val)?.to_i32()? as u8; let num = this.read_scalar(num)?.to_machine_usize(this)?; let idx = this @@ -356,7 +356,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "strlen" => { let &[ptr] = check_arg_count(args)?; - let ptr = this.read_scalar(ptr)?.not_undef()?; + let ptr = this.read_scalar(ptr)?.check_init()?; let n = this.memory.read_c_str(ptr)?.len(); this.write_scalar(Scalar::from_machine_usize(u64::try_from(n).unwrap(), this), dest)?; } diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index f542bebd82ad1..ce0368b4a0829 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -68,9 +68,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let size = elem_layout.size.checked_mul(count, this) .ok_or_else(|| err_ub_format!("overflow computing total size of `{}`", intrinsic_name))?; - let src = this.read_scalar(src)?.not_undef()?; + let src = this.read_scalar(src)?.check_init()?; let src = this.memory.check_ptr_access(src, size, elem_align)?; - let dest = this.read_scalar(dest)?.not_undef()?; + let dest = this.read_scalar(dest)?.check_init()?; let dest = this.memory.check_ptr_access(dest, size, elem_align)?; if let (Some(src), Some(dest)) = (src, dest) { @@ -105,7 +105,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let ty = instance.substs.type_at(0); let ty_layout = this.layout_of(ty)?; let val_byte = this.read_scalar(val_byte)?.to_u8()?; - let ptr = this.read_scalar(ptr)?.not_undef()?; + let ptr = this.read_scalar(ptr)?.check_init()?; let count = this.read_scalar(count)?.to_machine_usize(this)?; let byte_count = ty_layout.size.checked_mul(count, this) .ok_or_else(|| err_ub_format!("overflow computing total size of `write_bytes`"))?; @@ -503,7 +503,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Other "assume" => { let &[cond] = check_arg_count(args)?; - let cond = this.read_scalar(cond)?.not_undef()?.to_bool()?; + let cond = this.read_scalar(cond)?.check_init()?.to_bool()?; if !cond { throw_ub_format!("`assume` intrinsic called with `false`"); } diff --git a/src/shims/mod.rs b/src/shims/mod.rs index 56754a9ebde55..05dd4059eb1bc 100644 --- a/src/shims/mod.rs +++ b/src/shims/mod.rs @@ -67,14 +67,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let (dest, ret) = ret.unwrap(); let req_align = this - .force_bits(this.read_scalar(align_op)?.not_undef()?, this.pointer_size())?; + .force_bits(this.read_scalar(align_op)?.check_init()?, this.pointer_size())?; // Stop if the alignment is not a power of two. if !req_align.is_power_of_two() { return this.start_panic("align_offset: align is not a power-of-two", unwind); } - let ptr_scalar = this.read_scalar(ptr_op)?.not_undef()?; + let ptr_scalar = this.read_scalar(ptr_op)?.check_init()?; // Default: no result. let mut result = this.machine_usize_max(); diff --git a/src/shims/panic.rs b/src/shims/panic.rs index 8e291c2012152..45a41b9b7be06 100644 --- a/src/shims/panic.rs +++ b/src/shims/panic.rs @@ -47,7 +47,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Get the raw pointer stored in arg[0] (the panic payload). let &[payload] = check_arg_count(args)?; - let payload = this.read_scalar(payload)?.not_undef()?; + let payload = this.read_scalar(payload)?.check_init()?; assert!( this.machine.panic_payload.is_none(), "the panic runtime should avoid double-panics" @@ -81,9 +81,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Get all the arguments. let &[try_fn, data, catch_fn] = check_arg_count(args)?; - let try_fn = this.read_scalar(try_fn)?.not_undef()?; - let data = this.read_scalar(data)?.not_undef()?; - let catch_fn = this.read_scalar(catch_fn)?.not_undef()?; + let try_fn = this.read_scalar(try_fn)?.check_init()?; + let data = this.read_scalar(data)?.check_init()?; + let catch_fn = this.read_scalar(catch_fn)?.check_init()?; // Now we make a function call, and pass `data` as first and only argument. let f_instance = this.memory.get_fn(try_fn)?.as_instance()?; diff --git a/src/shims/posix/foreign_items.rs b/src/shims/posix/foreign_items.rs index 80611a18e4fc7..4bb94ae89449a 100644 --- a/src/shims/posix/foreign_items.rs +++ b/src/shims/posix/foreign_items.rs @@ -65,7 +65,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "read" => { let &[fd, buf, count] = check_arg_count(args)?; let fd = this.read_scalar(fd)?.to_i32()?; - let buf = this.read_scalar(buf)?.not_undef()?; + let buf = this.read_scalar(buf)?.check_init()?; let count = this.read_scalar(count)?.to_machine_usize(this)?; let result = if fd == 0 { @@ -109,7 +109,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "write" => { let &[fd, buf, n] = check_arg_count(args)?; let fd = this.read_scalar(fd)?.to_i32()?; - let buf = this.read_scalar(buf)?.not_undef()?; + let buf = this.read_scalar(buf)?.check_init()?; let count = this.read_scalar(n)?.to_machine_usize(this)?; trace!("Called write({:?}, {:?}, {:?})", fd, buf, count); let result = if fd == 0 { @@ -225,7 +225,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "dlsym" => { let &[handle, symbol] = check_arg_count(args)?; this.read_scalar(handle)?.to_machine_usize(this)?; - let symbol = this.read_scalar(symbol)?.not_undef()?; + let symbol = this.read_scalar(symbol)?.check_init()?; let symbol_name = this.memory.read_c_str(symbol)?; if let Some(dlsym) = Dlsym::from_str(symbol_name, &this.tcx.sess.target.target.target_os)? { let ptr = this.memory.create_fn_alloc(FnVal::Other(dlsym)); @@ -263,7 +263,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "pthread_key_create" => { let &[key, dtor] = check_arg_count(args)?; let key_place = this.deref_operand(key)?; - let dtor = this.read_scalar(dtor)?.not_undef()?; + let dtor = this.read_scalar(dtor)?.check_init()?; // Extract the function type out of the signature (that seems easier than constructing it ourselves). let dtor = match this.test_null(dtor)? { @@ -290,23 +290,23 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "pthread_key_delete" => { let &[key] = check_arg_count(args)?; - let key = this.force_bits(this.read_scalar(key)?.not_undef()?, key.layout.size)?; + let key = this.force_bits(this.read_scalar(key)?.check_init()?, key.layout.size)?; this.machine.tls.delete_tls_key(key)?; // Return success (0) this.write_null(dest)?; } "pthread_getspecific" => { let &[key] = check_arg_count(args)?; - let key = this.force_bits(this.read_scalar(key)?.not_undef()?, key.layout.size)?; + let key = this.force_bits(this.read_scalar(key)?.check_init()?, key.layout.size)?; let active_thread = this.get_active_thread(); let ptr = this.machine.tls.load_tls(key, active_thread, this)?; this.write_scalar(ptr, dest)?; } "pthread_setspecific" => { let &[key, new_ptr] = check_arg_count(args)?; - let key = this.force_bits(this.read_scalar(key)?.not_undef()?, key.layout.size)?; + let key = this.force_bits(this.read_scalar(key)?.check_init()?, key.layout.size)?; let active_thread = this.get_active_thread(); - let new_ptr = this.read_scalar(new_ptr)?.not_undef()?; + let new_ptr = this.read_scalar(new_ptr)?.check_init()?; this.machine.tls.store_tls(key, active_thread, this.test_null(new_ptr)?)?; // Return success (`0`). @@ -462,9 +462,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "pthread_atfork" => { let &[prepare, parent, child] = check_arg_count(args)?; - this.force_bits(this.read_scalar(prepare)?.not_undef()?, this.memory.pointer_size())?; - this.force_bits(this.read_scalar(parent)?.not_undef()?, this.memory.pointer_size())?; - this.force_bits(this.read_scalar(child)?.not_undef()?, this.memory.pointer_size())?; + this.force_bits(this.read_scalar(prepare)?.check_init()?, this.memory.pointer_size())?; + this.force_bits(this.read_scalar(parent)?.check_init()?, this.memory.pointer_size())?; + this.force_bits(this.read_scalar(child)?.check_init()?, this.memory.pointer_size())?; // We do not support forking, so there is nothing to do here. this.write_null(dest)?; } diff --git a/src/shims/posix/fs.rs b/src/shims/posix/fs.rs index a43e86dcc5b5b..a50228a4847c6 100644 --- a/src/shims/posix/fs.rs +++ b/src/shims/posix/fs.rs @@ -81,7 +81,7 @@ trait EvalContextExtPrivate<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, ' ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - let path_scalar = this.read_scalar(path_op)?.not_undef()?; + let path_scalar = this.read_scalar(path_op)?.check_init()?; let path = this.read_path_from_c_str(path_scalar)?.into_owned(); let metadata = match FileMetadata::from_path(this, &path, follow_symlink)? { @@ -334,7 +334,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx throw_unsup_format!("unsupported flags {:#x}", flag & !mirror); } - let path = this.read_path_from_c_str(this.read_scalar(path_op)?.not_undef()?)?; + let path = this.read_path_from_c_str(this.read_scalar(path_op)?.check_init()?)?; let fd = options.open(&path).map(|file| { let fh = &mut this.machine.file_handler; @@ -558,7 +558,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.check_no_isolation("unlink")?; - let path = this.read_path_from_c_str(this.read_scalar(path_op)?.not_undef()?)?; + let path = this.read_path_from_c_str(this.read_scalar(path_op)?.check_init()?)?; let result = remove_file(path).map(|_| 0); this.try_unwrap_io_result(result) @@ -588,8 +588,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.check_no_isolation("symlink")?; - let target = this.read_path_from_c_str(this.read_scalar(target_op)?.not_undef()?)?; - let linkpath = this.read_path_from_c_str(this.read_scalar(linkpath_op)?.not_undef()?)?; + let target = this.read_path_from_c_str(this.read_scalar(target_op)?.check_init()?)?; + let linkpath = this.read_path_from_c_str(this.read_scalar(linkpath_op)?.check_init()?)?; let result = create_link(&target, &linkpath).map(|_| 0); this.try_unwrap_io_result(result) @@ -651,8 +651,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.assert_target_os("linux", "statx"); this.check_no_isolation("statx")?; - let statxbuf_scalar = this.read_scalar(statxbuf_op)?.not_undef()?; - let pathname_scalar = this.read_scalar(pathname_op)?.not_undef()?; + let statxbuf_scalar = this.read_scalar(statxbuf_op)?.check_init()?; + let pathname_scalar = this.read_scalar(pathname_op)?.check_init()?; // If the statxbuf or pathname pointers are null, the function fails with `EFAULT`. if this.is_null(statxbuf_scalar)? || this.is_null(pathname_scalar)? { @@ -810,8 +810,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.check_no_isolation("rename")?; - let oldpath_scalar = this.read_scalar(oldpath_op)?.not_undef()?; - let newpath_scalar = this.read_scalar(newpath_op)?.not_undef()?; + let oldpath_scalar = this.read_scalar(oldpath_op)?.check_init()?; + let newpath_scalar = this.read_scalar(newpath_op)?.check_init()?; if this.is_null(oldpath_scalar)? || this.is_null(newpath_scalar)? { let efault = this.eval_libc("EFAULT")?; @@ -838,12 +838,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx #[cfg_attr(not(unix), allow(unused_variables))] let mode = if this.tcx.sess.target.target.target_os == "macos" { - u32::from(this.read_scalar(mode_op)?.not_undef()?.to_u16()?) + u32::from(this.read_scalar(mode_op)?.check_init()?.to_u16()?) } else { this.read_scalar(mode_op)?.to_u32()? }; - let path = this.read_path_from_c_str(this.read_scalar(path_op)?.not_undef()?)?; + let path = this.read_path_from_c_str(this.read_scalar(path_op)?.check_init()?)?; #[cfg_attr(not(unix), allow(unused_mut))] let mut builder = DirBuilder::new(); @@ -869,7 +869,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.check_no_isolation("rmdir")?; - let path = this.read_path_from_c_str(this.read_scalar(path_op)?.not_undef()?)?; + let path = this.read_path_from_c_str(this.read_scalar(path_op)?.check_init()?)?; let result = remove_dir(path).map(|_| 0i32); @@ -881,7 +881,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.check_no_isolation("opendir")?; - let name = this.read_path_from_c_str(this.read_scalar(name_op)?.not_undef()?)?; + let name = this.read_path_from_c_str(this.read_scalar(name_op)?.check_init()?)?; let result = read_dir(name); diff --git a/src/shims/posix/linux/foreign_items.rs b/src/shims/posix/linux/foreign_items.rs index ff30609d9ab27..ccb0ef8226e6f 100644 --- a/src/shims/posix/linux/foreign_items.rs +++ b/src/shims/posix/linux/foreign_items.rs @@ -181,7 +181,7 @@ fn getrandom<'tcx>( flags: OpTy<'tcx, Tag>, dest: PlaceTy<'tcx, Tag>, ) -> InterpResult<'tcx> { - let ptr = this.read_scalar(ptr)?.not_undef()?; + let ptr = this.read_scalar(ptr)?.check_init()?; let len = this.read_scalar(len)?.to_machine_usize(this)?; // The only supported flags are GRND_RANDOM and GRND_NONBLOCK, diff --git a/src/shims/posix/macos/dlsym.rs b/src/shims/posix/macos/dlsym.rs index 8256c10b0d397..0236b10e5fc8e 100644 --- a/src/shims/posix/macos/dlsym.rs +++ b/src/shims/posix/macos/dlsym.rs @@ -35,7 +35,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx match dlsym { Dlsym::getentropy => { let &[ptr, len] = check_arg_count(args)?; - let ptr = this.read_scalar(ptr)?.not_undef()?; + let ptr = this.read_scalar(ptr)?.check_init()?; let len = this.read_scalar(len)?.to_machine_usize(this)?; this.gen_random(ptr, len)?; this.write_null(dest)?; diff --git a/src/shims/posix/macos/foreign_items.rs b/src/shims/posix/macos/foreign_items.rs index ef649c3e84069..2e7258c800ac3 100644 --- a/src/shims/posix/macos/foreign_items.rs +++ b/src/shims/posix/macos/foreign_items.rs @@ -98,9 +98,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Thread-local storage "_tlv_atexit" => { let &[dtor, data] = check_arg_count(args)?; - let dtor = this.read_scalar(dtor)?.not_undef()?; + let dtor = this.read_scalar(dtor)?.check_init()?; let dtor = this.memory.get_fn(dtor)?.as_instance()?; - let data = this.read_scalar(data)?.not_undef()?; + let data = this.read_scalar(data)?.check_init()?; let active_thread = this.get_active_thread(); this.machine.tls.set_macos_thread_dtor(active_thread, dtor, data)?; } @@ -122,7 +122,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Threading "pthread_setname_np" => { let &[name] = check_arg_count(args)?; - let name = this.read_scalar(name)?.not_undef()?; + let name = this.read_scalar(name)?.check_init()?; this.pthread_setname_np(name)?; } @@ -131,7 +131,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "mmap" if this.frame().instance.to_string().starts_with("std::sys::unix::") => { // This is a horrible hack, but since the guard page mechanism calls mmap and expects a particular return value, we just give it that value. let &[addr, _, _, _, _, _] = check_arg_count(args)?; - let addr = this.read_scalar(addr)?.not_undef()?; + let addr = this.read_scalar(addr)?.check_init()?; this.write_scalar(addr, dest)?; } diff --git a/src/shims/posix/sync.rs b/src/shims/posix/sync.rs index cce0ddc930df0..28a45b194771e 100644 --- a/src/shims/posix/sync.rs +++ b/src/shims/posix/sync.rs @@ -288,7 +288,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - let kind = this.read_scalar(kind_op)?.not_undef()?; + let kind = this.read_scalar(kind_op)?.check_init()?; if kind == this.eval_libc("PTHREAD_MUTEX_NORMAL")? { // In `glibc` implementation, the numeric values of // `PTHREAD_MUTEX_NORMAL` and `PTHREAD_MUTEX_DEFAULT` are equal. @@ -337,11 +337,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - let attr = this.read_scalar(attr_op)?.not_undef()?; + let attr = this.read_scalar(attr_op)?.check_init()?; let kind = if this.is_null(attr)? { this.eval_libc("PTHREAD_MUTEX_DEFAULT")? } else { - mutexattr_get_kind(this, attr_op)?.not_undef()? + mutexattr_get_kind(this, attr_op)?.check_init()? }; // Write 0 to use the same code path as the static initializers. @@ -355,7 +355,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn pthread_mutex_lock(&mut self, mutex_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - let kind = mutex_get_kind(this, mutex_op)?.not_undef()?; + let kind = mutex_get_kind(this, mutex_op)?.check_init()?; let id = mutex_get_or_create_id(this, mutex_op)?; let active_thread = this.get_active_thread(); @@ -392,7 +392,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn pthread_mutex_trylock(&mut self, mutex_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - let kind = mutex_get_kind(this, mutex_op)?.not_undef()?; + let kind = mutex_get_kind(this, mutex_op)?.check_init()?; let id = mutex_get_or_create_id(this, mutex_op)?; let active_thread = this.get_active_thread(); @@ -425,7 +425,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn pthread_mutex_unlock(&mut self, mutex_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - let kind = mutex_get_kind(this, mutex_op)?.not_undef()?; + let kind = mutex_get_kind(this, mutex_op)?.check_init()?; let id = mutex_get_or_create_id(this, mutex_op)?; let active_thread = this.get_active_thread(); @@ -589,7 +589,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - let clock_id = this.read_scalar(clock_id_op)?.not_undef()?; + let clock_id = this.read_scalar(clock_id_op)?.check_init()?; if clock_id == this.eval_libc("CLOCK_REALTIME")? || clock_id == this.eval_libc("CLOCK_MONOTONIC")? { @@ -630,11 +630,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - let attr = this.read_scalar(attr_op)?.not_undef()?; + let attr = this.read_scalar(attr_op)?.check_init()?; let clock_id = if this.is_null(attr)? { this.eval_libc("CLOCK_REALTIME")? } else { - condattr_get_clock_id(this, attr_op)?.not_undef()? + condattr_get_clock_id(this, attr_op)?.check_init()? }; // Write 0 to use the same code path as the static initializers. diff --git a/src/shims/posix/thread.rs b/src/shims/posix/thread.rs index e5d3a9f0d6f87..7c9c489e6fb4c 100644 --- a/src/shims/posix/thread.rs +++ b/src/shims/posix/thread.rs @@ -29,7 +29,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx thread_info_place.into(), )?; - let fn_ptr = this.read_scalar(start_routine)?.not_undef()?; + let fn_ptr = this.read_scalar(start_routine)?.check_init()?; let instance = this.memory.get_fn(fn_ptr)?.as_instance()?; let func_arg = this.read_immediate(arg)?; @@ -59,7 +59,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - if !this.is_null(this.read_scalar(retval)?.not_undef()?)? { + if !this.is_null(this.read_scalar(retval)?.check_init()?)? { // FIXME: implement reading the thread function's return place. throw_unsup_format!("Miri supports pthread_join only with retval==NULL"); } @@ -99,7 +99,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let option = this.read_scalar(option)?.to_i32()?; if option == this.eval_libc_i32("PR_SET_NAME")? { - let address = this.read_scalar(arg2)?.not_undef()?; + let address = this.read_scalar(arg2)?.check_init()?; let mut name = this.memory.read_c_str(address)?.to_owned(); // The name should be no more than 16 bytes, including the null // byte. Since `read_c_str` returns the string without the null @@ -107,7 +107,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx name.truncate(15); this.set_active_thread_name(name); } else if option == this.eval_libc_i32("PR_GET_NAME")? { - let address = this.read_scalar(arg2)?.not_undef()?; + let address = this.read_scalar(arg2)?.check_init()?; let mut name = this.get_active_thread_name().to_vec(); name.push(0u8); assert!(name.len() <= 16); diff --git a/src/shims/time.rs b/src/shims/time.rs index e26d2ce2e39d2..193c87f7f099a 100644 --- a/src/shims/time.rs +++ b/src/shims/time.rs @@ -62,7 +62,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.check_no_isolation("gettimeofday")?; // Using tz is obsolete and should always be null - let tz = this.read_scalar(tz_op)?.not_undef()?; + let tz = this.read_scalar(tz_op)?.check_init()?; if !this.is_null(tz)? { let einval = this.eval_libc("EINVAL")?; this.set_last_error(einval)?; diff --git a/src/shims/tls.rs b/src/shims/tls.rs index d2d5522c40232..8d05442ad6bc0 100644 --- a/src/shims/tls.rs +++ b/src/shims/tls.rs @@ -237,7 +237,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // we specifically look up the static in libstd that we know is placed // in that section. let thread_callback = this.eval_path_scalar(&["std", "sys", "windows", "thread_local_key", "p_thread_callback"])?; - let thread_callback = this.memory.get_fn(thread_callback.not_undef()?)?.as_instance()?; + let thread_callback = this.memory.get_fn(thread_callback.check_init()?)?.as_instance()?; // The signature of this function is `unsafe extern "system" fn(h: c::LPVOID, dwReason: c::DWORD, pv: c::LPVOID)`. let reason = this.eval_path_scalar(&["std", "sys", "windows", "c", "DLL_THREAD_DETACH"])?; diff --git a/src/shims/windows/foreign_items.rs b/src/shims/windows/foreign_items.rs index e8937bbb30855..fc1093b64fb4b 100644 --- a/src/shims/windows/foreign_items.rs +++ b/src/shims/windows/foreign_items.rs @@ -67,7 +67,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let &[handle, buf, n, written_ptr, overlapped] = check_arg_count(args)?; this.read_scalar(overlapped)?.to_machine_usize(this)?; // this is a poiner, that we ignore let handle = this.read_scalar(handle)?.to_machine_isize(this)?; - let buf = this.read_scalar(buf)?.not_undef()?; + let buf = this.read_scalar(buf)?.check_init()?; let n = this.read_scalar(n)?.to_u32()?; let written_place = this.deref_operand(written_ptr)?; // Spec says to always write `0` first. @@ -111,7 +111,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let &[handle, flags, ptr] = check_arg_count(args)?; this.read_scalar(handle)?.to_machine_isize(this)?; this.read_scalar(flags)?.to_u32()?; - let ptr = this.read_scalar(ptr)?.not_undef()?; + let ptr = this.read_scalar(ptr)?.check_init()?; this.free(ptr, MiriMemoryKind::WinHeap)?; this.write_scalar(Scalar::from_i32(1), dest)?; } @@ -119,7 +119,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let &[handle, flags, ptr, size] = check_arg_count(args)?; this.read_scalar(handle)?.to_machine_isize(this)?; this.read_scalar(flags)?.to_u32()?; - let ptr = this.read_scalar(ptr)?.not_undef()?; + let ptr = this.read_scalar(ptr)?.check_init()?; let size = this.read_scalar(size)?.to_machine_usize(this)?; let res = this.realloc(ptr, size, MiriMemoryKind::WinHeap)?; this.write_scalar(res, dest)?; @@ -128,7 +128,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // errno "SetLastError" => { let &[error] = check_arg_count(args)?; - let error = this.read_scalar(error)?.not_undef()?; + let error = this.read_scalar(error)?.check_init()?; this.set_last_error(error)?; } "GetLastError" => { @@ -172,7 +172,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let &[key, new_ptr] = check_arg_count(args)?; let key = u128::from(this.read_scalar(key)?.to_u32()?); let active_thread = this.get_active_thread(); - let new_ptr = this.read_scalar(new_ptr)?.not_undef()?; + let new_ptr = this.read_scalar(new_ptr)?.check_init()?; this.machine.tls.store_tls(key, active_thread, this.test_null(new_ptr)?)?; // Return success (`1`). @@ -212,7 +212,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx #[allow(non_snake_case)] let &[hModule, lpProcName] = check_arg_count(args)?; this.read_scalar(hModule)?.to_machine_isize(this)?; - let name = this.memory.read_c_str(this.read_scalar(lpProcName)?.not_undef()?)?; + let name = this.memory.read_c_str(this.read_scalar(lpProcName)?.check_init()?)?; if let Some(dlsym) = Dlsym::from_str(name, &this.tcx.sess.target.target.target_os)? { let ptr = this.memory.create_fn_alloc(FnVal::Other(dlsym)); this.write_scalar(Scalar::from(ptr), dest)?; @@ -225,7 +225,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "SystemFunction036" => { // The actual name of 'RtlGenRandom' let &[ptr, len] = check_arg_count(args)?; - let ptr = this.read_scalar(ptr)?.not_undef()?; + let ptr = this.read_scalar(ptr)?.check_init()?; let len = this.read_scalar(len)?.to_u32()?; this.gen_random(ptr, len.into())?; this.write_scalar(Scalar::from_bool(true), dest)?; From 21268157ff89c13ee5d079e322bb692bb9216802 Mon Sep 17 00:00:00 2001 From: Philippe Nadon Date: Thu, 23 Jul 2020 10:28:00 -0600 Subject: [PATCH 2191/3747] renamed Immediate::to_scalar_or_undef to Immediate::to_scalar_or_uninit in src/shims/intrinsics.rs related issue #71193 --- src/shims/intrinsics.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index ce0368b4a0829..ee64b1ffca44b 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -392,7 +392,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // `binary_op` will bail if either of them is not a scalar. let eq = this.overflowing_binary_op(mir::BinOp::Eq, old, expect_old)?.0; - let res = Immediate::ScalarPair(old.to_scalar_or_undef(), eq.into()); + let res = Immediate::ScalarPair(old.to_scalar_or_uninit(), eq.into()); // Return old value. this.write_immediate(res, dest)?; // Update ptr depending on comparison. From 6282e927740b4e054e90879171fdb3f6feb9deff Mon Sep 17 00:00:00 2001 From: Phil Nadon Date: Sun, 26 Jul 2020 07:54:24 -0600 Subject: [PATCH 2192/3747] Updated Rust version to latest master Updated Rust version since the latest version contains changes which allow this version of Miri to build. --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index d0c938c53fafd..211af60b88aae 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -0e11fc8053d32c44e7152865852acc5c3c54efb3 +13f9aa190957b993a268fd4a046fce76ca8814ee From 6dd700fd177e22ab24b97c175ea9ce8611c07932 Mon Sep 17 00:00:00 2001 From: Philippe Nadon Date: Mon, 27 Jul 2020 13:07:25 -0600 Subject: [PATCH 2193/3747] Changed not_undef to check_init in foreign_items.rs Due to changes from upstream, a commit using not_undef was inserted, which had to be updated to use check_init. related issue #71193 --- src/shims/foreign_items.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index d4f248f0329dc..98e66db92da3c 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -200,7 +200,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Miri-specific extern functions "miri_static_root" => { let &[ptr] = check_arg_count(args)?; - let ptr = this.read_scalar(ptr)?.not_undef()?; + let ptr = this.read_scalar(ptr)?.check_init()?; let ptr = this.force_ptr(ptr)?; if ptr.offset != Size::ZERO { throw_unsup_format!("pointer passed to miri_static_root must point to beginning of an allocated block"); From 0a4e8caa8c303e8a8b5459bb79c7474eb53619ae Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 26 Jul 2020 11:15:01 +0200 Subject: [PATCH 2194/3747] adjust to canonical_alloc_id removal --- src/diagnostics.rs | 4 ++-- src/intptrcast.rs | 3 +-- src/machine.rs | 38 ++++++++++---------------------------- src/thread.rs | 41 +---------------------------------------- 4 files changed, 14 insertions(+), 72 deletions(-) diff --git a/src/diagnostics.rs b/src/diagnostics.rs index 009f8aa29cecf..3c6486244591e 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -94,8 +94,8 @@ pub fn report_error<'tcx, 'mir>( let helps = match e.kind { Unsupported(UnsupportedOpInfo::NoMirFor(..)) => vec![format!("make sure to use a Miri sysroot, which you can prepare with `cargo miri setup`")], - Unsupported(UnsupportedOpInfo::ReadBytesAsPointer) => - panic!("`ReadBytesAsPointer` cannot be raised by Miri"), + Unsupported(UnsupportedOpInfo::ReadBytesAsPointer | UnsupportedOpInfo::ThreadLocalStatic(_) | UnsupportedOpInfo::ReadExternStatic(_)) => + panic!("Error should never be raised by Miri: {:?}", e.kind), Unsupported(_) => vec![format!("this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support")], UndefinedBehavior(UndefinedBehaviorInfo::AlignmentCheckFailed { .. }) => diff --git a/src/intptrcast.rs b/src/intptrcast.rs index c908bdf24ebac..188ff94861bdd 100644 --- a/src/intptrcast.rs +++ b/src/intptrcast.rs @@ -6,7 +6,6 @@ use log::trace; use rand::Rng; use rustc_data_structures::fx::FxHashMap; -use rustc_mir::interpret::{AllocCheck, AllocId, InterpResult, Memory, Machine, Pointer, PointerArithmetic}; use rustc_target::abi::{Size, HasDataLayout}; use crate::*; @@ -79,7 +78,7 @@ impl<'mir, 'tcx> GlobalState { ) -> InterpResult<'tcx, u64> { let mut global_state = memory.extra.intptrcast.borrow_mut(); let global_state = &mut *global_state; - let id = Evaluator::canonical_alloc_id(memory, ptr.alloc_id); + let id = ptr.alloc_id; // There is nothing wrong with a raw pointer being cast to an integer only after // it became dangling. Hence `MaybeDead`. diff --git a/src/machine.rs b/src/machine.rs index e9217896ef6eb..d418409df0674 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -426,44 +426,26 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { Ok(()) } - fn thread_local_alloc_id( + fn thread_local_static_alloc_id( ecx: &mut InterpCx<'mir, 'tcx, Self>, def_id: DefId, ) -> InterpResult<'tcx, AllocId> { ecx.get_or_create_thread_local_alloc_id(def_id) } - fn adjust_global_const( - ecx: &InterpCx<'mir, 'tcx, Self>, - mut val: mir::interpret::ConstValue<'tcx>, - ) -> InterpResult<'tcx, mir::interpret::ConstValue<'tcx>> { - // FIXME: Remove this, do The Right Thing in `thread_local_alloc_id` instead. - ecx.remap_thread_local_alloc_ids(&mut val)?; - Ok(val) - } - - fn canonical_alloc_id(mem: &Memory<'mir, 'tcx, Self>, id: AllocId) -> AllocId { - let tcx = mem.tcx; - // Figure out if this is an extern static, and if yes, which one. - let def_id = match tcx.get_global_alloc(id) { - Some(GlobalAlloc::Static(def_id)) if tcx.is_foreign_item(def_id) => def_id, - _ => { - // No need to canonicalize anything. - return id; - } - }; - let attrs = tcx.get_attrs(def_id); + fn extern_static_alloc_id( + memory: &Memory<'mir, 'tcx, Self>, + def_id: DefId, + ) -> InterpResult<'tcx, AllocId> { + let attrs = memory.tcx.get_attrs(def_id); let link_name = match attr::first_attr_value_str_by_name(&attrs, sym::link_name) { Some(name) => name, - None => tcx.item_name(def_id), + None => memory.tcx.item_name(def_id), }; - // Check if we know this one. - if let Some(canonical_id) = mem.extra.extern_statics.get(&link_name) { - trace!("canonical_alloc_id: {:?} ({}) -> {:?}", id, link_name, canonical_id); - *canonical_id + if let Some(&id) = memory.extra.extern_statics.get(&link_name) { + Ok(id) } else { - // Return original id; `Memory::get_static_alloc` will throw an error. - id + throw_unsup_format!("`extern` static {:?} is not supported by Miri", def_id) } } diff --git a/src/thread.rs b/src/thread.rs index 42a4dbded58f4..0a83b71665c5c 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -11,11 +11,7 @@ use log::trace; use rustc_data_structures::fx::FxHashMap; use rustc_hir::def_id::DefId; use rustc_index::vec::{Idx, IndexVec}; -use rustc_middle::{ - middle::codegen_fn_attrs::CodegenFnAttrFlags, - mir, - ty::{self, Instance}, -}; +use rustc_middle::ty::{self, Instance}; use crate::sync::SynchronizationState; use crate::*; @@ -499,41 +495,6 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { // Public interface to thread management. impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { - /// A workaround for thread-local statics until - /// https://github.com/rust-lang/rust/issues/70685 is fixed: change the - /// thread-local allocation id with a freshly generated allocation id for - /// the currently active thread. - fn remap_thread_local_alloc_ids( - &self, - val: &mut mir::interpret::ConstValue<'tcx>, - ) -> InterpResult<'tcx> { - let this = self.eval_context_ref(); - match *val { - mir::interpret::ConstValue::Scalar(Scalar::Ptr(ref mut ptr)) => { - let alloc_id = ptr.alloc_id; - let alloc = this.tcx.get_global_alloc(alloc_id); - let tcx = this.tcx; - let is_thread_local = |def_id| { - tcx.codegen_fn_attrs(def_id).flags.contains(CodegenFnAttrFlags::THREAD_LOCAL) - }; - match alloc { - Some(GlobalAlloc::Static(def_id)) if is_thread_local(def_id) => { - ptr.alloc_id = this.get_or_create_thread_local_alloc_id(def_id)?; - } - _ => {} - } - } - _ => { - // FIXME: Handling only `Scalar` seems to work for now, but at - // least in principle thread-locals could be in any constant, so - // we should also consider other cases. However, once - // https://github.com/rust-lang/rust/issues/70685 gets fixed, - // this code will have to be rewritten anyway. - } - } - Ok(()) - } - /// Get a thread-specific allocation id for the given thread-local static. /// If needed, allocate a new one. /// From 7b07fc385c1b9e61f8388c5540d344ecf25bb932 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 26 Jul 2020 12:11:27 +0200 Subject: [PATCH 2195/3747] get_or_create_thread_local_alloc_id: share code with Memory::get_global_alloc --- src/thread.rs | 24 +++--------------------- 1 file changed, 3 insertions(+), 21 deletions(-) diff --git a/src/thread.rs b/src/thread.rs index 0a83b71665c5c..8d493ac8f3bde 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -11,7 +11,6 @@ use log::trace; use rustc_data_structures::fx::FxHashMap; use rustc_hir::def_id::DefId; use rustc_index::vec::{Idx, IndexVec}; -use rustc_middle::ty::{self, Instance}; use crate::sync::SynchronizationState; use crate::*; @@ -497,9 +496,6 @@ impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mi pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { /// Get a thread-specific allocation id for the given thread-local static. /// If needed, allocate a new one. - /// - /// FIXME: This method should be replaced as soon as - /// https://github.com/rust-lang/rust/issues/70685 gets fixed. fn get_or_create_thread_local_alloc_id(&self, def_id: DefId) -> InterpResult<'tcx, AllocId> { let this = self.eval_context_ref(); let tcx = this.tcx; @@ -511,29 +507,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // We need to allocate a thread-specific allocation id for this // thread-local static. // - // At first, we invoke the `const_eval_raw` query and extract the - // allocation from it. Unfortunately, we have to duplicate the code - // from `Memory::get_global_alloc` that does this. - // + // At first, we compute the initial value for this static. // Then we store the retrieved allocation back into the `alloc_map` // to get a fresh allocation id, which we can use as a // thread-specific allocation id for the thread-local static. + // On first access to that allocation, it will be copied over to the machine memory. if tcx.is_foreign_item(def_id) { throw_unsup_format!("foreign thread-local statics are not supported"); } - // Invoke the `const_eval_raw` query. - let instance = Instance::mono(tcx.tcx, def_id); - let gid = GlobalId { instance, promoted: None }; - let raw_const = - tcx.const_eval_raw(ty::ParamEnv::reveal_all().and(gid)).map_err(|err| { - // no need to report anything, the const_eval call takes care of that - // for statics - assert!(tcx.is_static(def_id)); - err - })?; - let id = raw_const.alloc_id; - // Extract the allocation from the query result. - let allocation = tcx.global_alloc(id).unwrap_memory(); + let allocation = interpret::get_static(*tcx, def_id)?; // Create a new allocation id for the same allocation in this hacky // way. Internally, `alloc_map` deduplicates allocations, but this // is fine because Miri will make a copy before a first mutable From 390899e8b9c9b3b415a630e663418f1ad7e10c4d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 26 Jul 2020 15:55:15 +0200 Subject: [PATCH 2196/3747] test referencing unsupported extern static --- tests/compile-fail/extern_static.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 tests/compile-fail/extern_static.rs diff --git a/tests/compile-fail/extern_static.rs b/tests/compile-fail/extern_static.rs new file mode 100644 index 0000000000000..650dfd0ac7878 --- /dev/null +++ b/tests/compile-fail/extern_static.rs @@ -0,0 +1,10 @@ +#![feature(raw_ref_op)] +//! Even referencing an unknown `extern static` already triggers an error. + +extern "C" { + static mut FOO: i32; +} + +fn main() { + let _val = unsafe { &raw const FOO }; //~ ERROR is not supported by Miri +} From 2a42f8e93c3be903cbfd940cbee3299506e184c7 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 26 Jul 2020 15:53:02 +0200 Subject: [PATCH 2197/3747] fix and test order of TLS dtors and thread joining --- src/shims/tls.rs | 4 +-- src/thread.rs | 26 ++++++++++++++----- tests/run-pass/concurrency/tls_lib_drop.rs | 8 +++--- .../run-pass/concurrency/tls_lib_drop.stdout | 6 ++--- 4 files changed, 28 insertions(+), 16 deletions(-) diff --git a/src/shims/tls.rs b/src/shims/tls.rs index 8d05442ad6bc0..4a0d5fc22ad61 100644 --- a/src/shims/tls.rs +++ b/src/shims/tls.rs @@ -328,9 +328,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// schedules them one by one each time it is called and reenables the /// thread so that it can be executed normally by the main execution loop. /// - /// FIXME: we do not support yet deallocation of thread local statics. - /// Issue: https://github.com/rust-lang/miri/issues/1369 - /// /// Note: we consistently run TLS destructors for all threads, including the /// main thread. However, it is not clear that we should run the TLS /// destructors for the main thread. See issue: @@ -367,6 +364,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // All dtors done! this.machine.tls.delete_all_thread_tls(active_thread); + this.thread_terminated(); Ok(()) } diff --git a/src/thread.rs b/src/thread.rs index 8d493ac8f3bde..8520dcd073a75 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -410,6 +410,20 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { None } + /// Handles thread termination of the active thread: wakes up threads joining on this one, + /// and deallocated thread-local statics. + /// + /// This is called from `tls.rs` after handling the TLS dtors. + fn thread_terminated(&mut self) { + for (i, thread) in self.threads.iter_enumerated_mut() { + // Check if we need to unblock any threads. + if thread.state == ThreadState::BlockedOnJoin(self.active_thread) { + trace!("unblocking {:?} because {:?} terminated", i, self.active_thread); + thread.state = ThreadState::Enabled; + } + } + } + /// Decide which action to take next and on which thread. /// /// The currently implemented scheduling policy is the one that is commonly @@ -421,13 +435,6 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { // checks whether the thread has popped all its stack and if yes, sets // the thread state to terminated). if self.threads[self.active_thread].check_terminated() { - // Check if we need to unblock any threads. - for (i, thread) in self.threads.iter_enumerated_mut() { - if thread.state == ThreadState::BlockedOnJoin(self.active_thread) { - trace!("unblocking {:?} because {:?} terminated", i, self.active_thread); - thread.state = ThreadState::Enabled; - } - } return Ok(SchedulingAction::ExecuteDtors); } if self.threads[MAIN_THREAD].state == ThreadState::Terminated { @@ -660,4 +667,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); this.machine.threads.schedule() } + + #[inline] + fn thread_terminated(&mut self) { + self.eval_context_mut().machine.threads.thread_terminated() + } } diff --git a/tests/run-pass/concurrency/tls_lib_drop.rs b/tests/run-pass/concurrency/tls_lib_drop.rs index de2566de85c6a..46f59ef6204f7 100644 --- a/tests/run-pass/concurrency/tls_lib_drop.rs +++ b/tests/run-pass/concurrency/tls_lib_drop.rs @@ -9,7 +9,8 @@ struct TestCell { impl Drop for TestCell { fn drop(&mut self) { - println!("Dropping: {}", self.value.borrow()) + for _ in 0..10 { thread::yield_now(); } + println!("Dropping: {} (should be before 'Continue main 1').", self.value.borrow()) } } @@ -28,7 +29,7 @@ fn check_destructors() { }) .join() .unwrap(); - println!("Continue main.") + println!("Continue main 1.") } struct JoinCell { @@ -37,8 +38,9 @@ struct JoinCell { impl Drop for JoinCell { fn drop(&mut self) { + for _ in 0..10 { thread::yield_now(); } let join_handle = self.value.borrow_mut().take().unwrap(); - println!("Joining: {}", join_handle.join().unwrap()); + println!("Joining: {} (should be before 'Continue main 2').", join_handle.join().unwrap()); } } diff --git a/tests/run-pass/concurrency/tls_lib_drop.stdout b/tests/run-pass/concurrency/tls_lib_drop.stdout index d622c0ccce882..484979b04ca77 100644 --- a/tests/run-pass/concurrency/tls_lib_drop.stdout +++ b/tests/run-pass/concurrency/tls_lib_drop.stdout @@ -1,4 +1,4 @@ -Dropping: 5 -Continue main. +Dropping: 5 (should be before 'Continue main 1'). +Continue main 1. +Joining: 7 (should be before 'Continue main 2'). Continue main 2. -Joining: 7 From c77540ce13890ba5f16f276967e86f8d7fb8f78e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 27 Jul 2020 12:53:39 +0200 Subject: [PATCH 2198/3747] deallocate thread-local statics when the thread dies --- src/machine.rs | 16 ++++-- src/shims/env.rs | 4 +- src/shims/tls.rs | 2 +- src/stacked_borrows.rs | 4 +- src/thread.rs | 56 ++++++++++++------- .../thread_local_static_dealloc.rs | 13 +++++ 6 files changed, 63 insertions(+), 32 deletions(-) create mode 100644 tests/compile-fail/concurrency/thread_local_static_dealloc.rs diff --git a/src/machine.rs b/src/machine.rs index d418409df0674..5dfe99627437d 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -64,7 +64,10 @@ pub enum MiriMemoryKind { Global, /// Memory for extern statics. /// This memory may leak. - ExternGlobal, + ExternStatic, + /// Memory for thread-local statics. + /// This memory may leak. + Tls, } impl Into> for MiriMemoryKind { @@ -80,7 +83,7 @@ impl MayLeak for MiriMemoryKind { use self::MiriMemoryKind::*; match self { Rust | C | WinHeap | Env => false, - Machine | Global | ExternGlobal => true, + Machine | Global | ExternStatic | Tls => true, } } } @@ -94,8 +97,9 @@ impl fmt::Display for MiriMemoryKind { WinHeap => write!(f, "Windows heap"), Machine => write!(f, "machine-managed memory"), Env => write!(f, "environment variable"), - Global => write!(f, "global"), - ExternGlobal => write!(f, "extern global"), + Global => write!(f, "global (static or const)"), + ExternStatic => write!(f, "extern static"), + Tls => write!(f, "thread-local static"), } } } @@ -175,7 +179,7 @@ impl MemoryExtra { // "__cxa_thread_atexit_impl" // This should be all-zero, pointer-sized. let layout = this.machine.layouts.usize; - let place = this.allocate(layout, MiriMemoryKind::ExternGlobal.into()); + let place = this.allocate(layout, MiriMemoryKind::ExternStatic.into()); this.write_scalar(Scalar::from_machine_usize(0, this), place.into())?; Self::add_extern_static(this, "__cxa_thread_atexit_impl", place.ptr); // "environ" @@ -185,7 +189,7 @@ impl MemoryExtra { // "_tls_used" // This is some obscure hack that is part of the Windows TLS story. It's a `u8`. let layout = this.machine.layouts.u8; - let place = this.allocate(layout, MiriMemoryKind::ExternGlobal.into()); + let place = this.allocate(layout, MiriMemoryKind::ExternStatic.into()); this.write_scalar(Scalar::from_u8(0), place.into())?; Self::add_extern_static(this, "_tls_used", place.ptr); } diff --git a/src/shims/env.rs b/src/shims/env.rs index 86a7a58ac4aab..d7474dbf87efc 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -383,9 +383,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.memory.deallocate(this.force_ptr(old_vars_ptr)?, None, MiriMemoryKind::Env.into())?; } else { // No `environ` allocated yet, let's do that. - // This is memory backing an extern static, hence `ExternGlobal`, not `Env`. + // This is memory backing an extern static, hence `ExternStatic`, not `Env`. let layout = this.machine.layouts.usize; - let place = this.allocate(layout, MiriMemoryKind::ExternGlobal.into()); + let place = this.allocate(layout, MiriMemoryKind::ExternStatic.into()); this.machine.env_vars.environ = Some(place); } diff --git a/src/shims/tls.rs b/src/shims/tls.rs index 4a0d5fc22ad61..d929459740072 100644 --- a/src/shims/tls.rs +++ b/src/shims/tls.rs @@ -364,7 +364,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // All dtors done! this.machine.tls.delete_all_thread_tls(active_thread); - this.thread_terminated(); + this.thread_terminated()?; Ok(()) } diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 6942acc5e2b07..cefe334574b44 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -469,10 +469,10 @@ impl Stacks { // `Global` memory can be referenced by global pointers from `tcx`. // Thus we call `global_base_ptr` such that the global pointers get the same tag // as what we use here. - // `ExternGlobal` is used for extern statics, and thus must also be listed here. + // `ExternStatic` is used for extern statics, and thus must also be listed here. // `Env` we list because we can get away with precise tracking there. // The base pointer is not unique, so the base permission is `SharedReadWrite`. - MemoryKind::Machine(MiriMemoryKind::Global | MiriMemoryKind::ExternGlobal | MiriMemoryKind::Env) => + MemoryKind::Machine(MiriMemoryKind::Global | MiriMemoryKind::ExternStatic | MiriMemoryKind::Tls | MiriMemoryKind::Env) => (extra.borrow_mut().global_base_ptr(id), Permission::SharedReadWrite), // Everything else we handle entirely untagged for now. // FIXME: experiment with more precise tracking. diff --git a/src/thread.rs b/src/thread.rs index 8520dcd073a75..1e710a25edc99 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -410,18 +410,31 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { None } - /// Handles thread termination of the active thread: wakes up threads joining on this one, - /// and deallocated thread-local statics. - /// - /// This is called from `tls.rs` after handling the TLS dtors. - fn thread_terminated(&mut self) { + /// Wakes up threads joining on the active one and deallocates thread-local statics. + /// The `AllocId` that can now be freed is returned. + fn thread_terminated(&mut self) -> Vec { + let mut free_tls_statics = Vec::new(); + { + let mut thread_local_statics = self.thread_local_alloc_ids.borrow_mut(); + thread_local_statics.retain(|&(_def_id, thread), &mut alloc_id| { + if thread != self.active_thread { + // Keep this static around. + return true; + } + // Delete this static from the map and from memory. + // We cannot free directly here as we cannot use `?` in this context. + free_tls_statics.push(alloc_id); + return false; + }); + } + // Check if we need to unblock any threads. for (i, thread) in self.threads.iter_enumerated_mut() { - // Check if we need to unblock any threads. if thread.state == ThreadState::BlockedOnJoin(self.active_thread) { trace!("unblocking {:?} because {:?} terminated", i, self.active_thread); thread.state = ThreadState::Enabled; } } + return free_tls_statics; } /// Decide which action to take next and on which thread. @@ -503,8 +516,8 @@ impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mi pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { /// Get a thread-specific allocation id for the given thread-local static. /// If needed, allocate a new one. - fn get_or_create_thread_local_alloc_id(&self, def_id: DefId) -> InterpResult<'tcx, AllocId> { - let this = self.eval_context_ref(); + fn get_or_create_thread_local_alloc_id(&mut self, def_id: DefId) -> InterpResult<'tcx, AllocId> { + let this = self.eval_context_mut(); let tcx = this.tcx; if let Some(new_alloc_id) = this.machine.threads.get_thread_local_alloc_id(def_id) { // We already have a thread-specific allocation id for this @@ -513,21 +526,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } else { // We need to allocate a thread-specific allocation id for this // thread-local static. - // - // At first, we compute the initial value for this static. - // Then we store the retrieved allocation back into the `alloc_map` - // to get a fresh allocation id, which we can use as a - // thread-specific allocation id for the thread-local static. - // On first access to that allocation, it will be copied over to the machine memory. + // First, we compute the initial value for this static. if tcx.is_foreign_item(def_id) { throw_unsup_format!("foreign thread-local statics are not supported"); } let allocation = interpret::get_static(*tcx, def_id)?; - // Create a new allocation id for the same allocation in this hacky - // way. Internally, `alloc_map` deduplicates allocations, but this - // is fine because Miri will make a copy before a first mutable - // access. - let new_alloc_id = tcx.create_memory_alloc(allocation); + // Create a fresh allocation with this content. + let new_alloc_id = this.memory.allocate_with(allocation.clone(), MiriMemoryKind::Tls.into()).alloc_id; this.machine.threads.set_thread_local_alloc_id(def_id, new_alloc_id); Ok(new_alloc_id) } @@ -668,8 +673,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.machine.threads.schedule() } + /// Handles thread termination of the active thread: wakes up threads joining on this one, + /// and deallocated thread-local statics. + /// + /// This is called from `tls.rs` after handling the TLS dtors. #[inline] - fn thread_terminated(&mut self) { - self.eval_context_mut().machine.threads.thread_terminated() + fn thread_terminated(&mut self) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + for alloc_id in this.machine.threads.thread_terminated() { + let ptr = this.memory.global_base_pointer(alloc_id.into())?; + this.memory.deallocate(ptr, None, MiriMemoryKind::Tls.into())?; + } + Ok(()) } } diff --git a/tests/compile-fail/concurrency/thread_local_static_dealloc.rs b/tests/compile-fail/concurrency/thread_local_static_dealloc.rs new file mode 100644 index 0000000000000..1b20ce8bfb380 --- /dev/null +++ b/tests/compile-fail/concurrency/thread_local_static_dealloc.rs @@ -0,0 +1,13 @@ +// ignore-windows: Concurrency on Windows is not supported yet. + +//! Ensure that thread-local statics get deallocated when the thread dies. + +#![feature(thread_local)] + +#[thread_local] +static mut TLS: u8 = 0; + +fn main() { unsafe { + let dangling_ptr = std::thread::spawn(|| &TLS as *const u8 as usize).join().unwrap(); + let _val = *(dangling_ptr as *const u8); +} } From 6fbaa72642dacf92746c695046c8dfe6834ef18f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 27 Jul 2020 13:10:11 +0200 Subject: [PATCH 2199/3747] fix diagnostics printing when triggered during TLS dtor scheduling --- src/diagnostics.rs | 24 ++++++++++++++++++------ src/eval.rs | 4 ++-- src/shims/tls.rs | 3 +++ 3 files changed, 23 insertions(+), 8 deletions(-) diff --git a/src/diagnostics.rs b/src/diagnostics.rs index 3c6486244591e..2e8809cd73611 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -162,7 +162,15 @@ fn report_msg<'tcx>( } else { tcx.sess.diagnostic().span_note_diag(span, title) }; - err.span_label(span, span_msg); + // Show main message. + if span != DUMMY_SP { + err.span_label(span, span_msg); + } else { + // Make sure we show the message even when it is a dummy span. + err.note(&span_msg); + err.note("(no span available)"); + } + // Show help messages. if !helps.is_empty() { // Add visual separator before backtrace. helps.last_mut().unwrap().push_str("\n"); @@ -198,7 +206,7 @@ pub fn register_diagnostic(e: NonHaltingDiagnostic) { /// after a step was taken. pub struct TopFrameInfo<'tcx> { stack_size: usize, - instance: ty::Instance<'tcx>, + instance: Option>, span: Span, } @@ -209,11 +217,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx DIAGNOSTICS.with(|diagnostics| assert!(diagnostics.borrow().is_empty())); let this = self.eval_context_ref(); + if this.active_thread_stack().is_empty() { + // Diagnostics can happen even with the emoty stack (e.g. deallocation thread-local statics). + return TopFrameInfo { stack_size: 0, instance: None, span: DUMMY_SP }; + } let frame = this.frame(); TopFrameInfo { stack_size: this.active_thread_stack().len(), - instance: frame.instance, + instance: Some(frame.instance), span: frame.current_source_info().map_or(DUMMY_SP, |si| si.span), } } @@ -237,15 +249,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if stacktrace.len() < info.stack_size { assert!(stacktrace.len() == info.stack_size-1, "we should never pop more than one frame at once"); let frame_info = FrameInfo { - instance: info.instance, + instance: info.instance.unwrap(), span: info.span, lint_root: None, }; stacktrace.insert(0, frame_info); - } else { + } else if let Some(instance) = info.instance { // Adjust topmost frame. stacktrace[0].span = info.span; - assert_eq!(stacktrace[0].instance, info.instance, "we should not pop and push a frame in one step"); + assert_eq!(stacktrace[0].instance, instance, "we should not pop and push a frame in one step"); } // Show diagnostics. diff --git a/src/eval.rs b/src/eval.rs index 8561edcc05b9c..cc5a6eb21faba 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -211,11 +211,10 @@ pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) -> let res: InterpResult<'_, i64> = (|| { // Main loop. loop { + let info = ecx.preprocess_diagnostics(); match ecx.schedule()? { SchedulingAction::ExecuteStep => { - let info = ecx.preprocess_diagnostics(); assert!(ecx.step()?, "a terminated thread was scheduled for execution"); - ecx.process_diagnostics(info); } SchedulingAction::ExecuteTimeoutCallback => { assert!(ecx.machine.communicate, @@ -233,6 +232,7 @@ pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) -> break; } } + ecx.process_diagnostics(info); } let return_code = ecx.read_scalar(ret_place.into())?.check_init()?.to_machine_isize(&ecx)?; Ok(return_code) diff --git a/src/shims/tls.rs b/src/shims/tls.rs index d929459740072..2ba0782f7054f 100644 --- a/src/shims/tls.rs +++ b/src/shims/tls.rs @@ -348,6 +348,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx return Ok(()) } } + // The remaining dtors make some progress each time around the scheduler loop, + // until they return `false` to indicate that they are done. + // The macOS thread wide destructor runs "before any TLS slots get // freed", so do that first. if this.schedule_macos_tls_dtor()? { From bec7aab7fd089d89e940029038669f851d497caa Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 27 Jul 2020 14:10:31 +0200 Subject: [PATCH 2200/3747] Typos Co-authored-by: Oliver Scherer --- src/diagnostics.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/diagnostics.rs b/src/diagnostics.rs index 2e8809cd73611..1b41ba4418377 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -218,7 +218,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_ref(); if this.active_thread_stack().is_empty() { - // Diagnostics can happen even with the emoty stack (e.g. deallocation thread-local statics). + // Diagnostics can happen even with the empty stack (e.g. deallocation of thread-local statics). return TopFrameInfo { stack_size: 0, instance: None, span: DUMMY_SP }; } let frame = this.frame(); From cae90b6d293dc0e9bb3275457a94323bd14d51a1 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 27 Jul 2020 23:40:27 +0200 Subject: [PATCH 2201/3747] rustup and test fixes --- rust-version | 2 +- tests/compile-fail/concurrency/thread_local_static_dealloc.rs | 2 +- tests/run-pass/panic/catch_panic.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/rust-version b/rust-version index 211af60b88aae..3f188639fa3d4 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -13f9aa190957b993a268fd4a046fce76ca8814ee +efc02b03d18b0cbaa55b1e421d792f70a39230b2 diff --git a/tests/compile-fail/concurrency/thread_local_static_dealloc.rs b/tests/compile-fail/concurrency/thread_local_static_dealloc.rs index 1b20ce8bfb380..73e4ab596585d 100644 --- a/tests/compile-fail/concurrency/thread_local_static_dealloc.rs +++ b/tests/compile-fail/concurrency/thread_local_static_dealloc.rs @@ -9,5 +9,5 @@ static mut TLS: u8 = 0; fn main() { unsafe { let dangling_ptr = std::thread::spawn(|| &TLS as *const u8 as usize).join().unwrap(); - let _val = *(dangling_ptr as *const u8); + let _val = *(dangling_ptr as *const u8); //~ ERROR dereferenced after this allocation got freed } } diff --git a/tests/run-pass/panic/catch_panic.rs b/tests/run-pass/panic/catch_panic.rs index ac41de586e8a7..811c370d812fe 100644 --- a/tests/run-pass/panic/catch_panic.rs +++ b/tests/run-pass/panic/catch_panic.rs @@ -1,4 +1,4 @@ -// normalize-stderr-test "[^ ]*libcore/[a-z/]+.rs[0-9:]*" -> "$$LOC" +// normalize-stderr-test "[^ ]*libcore/[a-z_/]+.rs[0-9:]*" -> "$$LOC" #![feature(never_type)] #![allow(unconditional_panic)] From ee39ac9840519e7b5a90d9f0f506a092f4177cd9 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 28 Jul 2020 14:00:33 +0200 Subject: [PATCH 2202/3747] rustup for new folder layout --- cargo-miri/bin.rs | 8 ++++---- rust-version | 2 +- tests/run-pass/panic/catch_panic.rs | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index 33a1124aaba09..000a4d41cc5da 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -10,7 +10,7 @@ use std::process::Command; use rustc_version::VersionMeta; -const XARGO_MIN_VERSION: (u32, u32, u32) = (0, 3, 21); +const XARGO_MIN_VERSION: (u32, u32, u32) = (0, 3, 22); const CARGO_MIRI_HELP: &str = r#"Interprets bin crates and tests in Miri @@ -271,10 +271,10 @@ fn setup(subcommand: MiriCommand) { .stdout; let sysroot = std::str::from_utf8(&sysroot).unwrap(); let sysroot = Path::new(sysroot.trim_end_matches('\n')); - // Check for `$SYSROOT/lib/rustlib/src/rust/src`; test if that contains `libstd/lib.rs`. + // Check for `$SYSROOT/lib/rustlib/src/rust/library`; test if that contains `std/Cargo.toml`. let rustup_src = - sysroot.join("lib").join("rustlib").join("src").join("rust").join("src"); - if !rustup_src.join("libstd").join("lib.rs").exists() { + sysroot.join("lib").join("rustlib").join("src").join("rust").join("library"); + if !rustup_src.join("std").join("Cargo.toml").exists() { // Ask the user to install the `rust-src` component, and use that. let mut cmd = Command::new("rustup"); cmd.args(&["component", "add", "rust-src"]); diff --git a/rust-version b/rust-version index 3f188639fa3d4..1ba022ac96940 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -efc02b03d18b0cbaa55b1e421d792f70a39230b2 +1454bbd4fdac9b7272b93fe82860613dccc0afad diff --git a/tests/run-pass/panic/catch_panic.rs b/tests/run-pass/panic/catch_panic.rs index 811c370d812fe..6dc47f2f591ac 100644 --- a/tests/run-pass/panic/catch_panic.rs +++ b/tests/run-pass/panic/catch_panic.rs @@ -1,4 +1,4 @@ -// normalize-stderr-test "[^ ]*libcore/[a-z_/]+.rs[0-9:]*" -> "$$LOC" +// normalize-stderr-test "[^ ]*core/[a-z_/]+.rs[0-9:]*" -> "$$LOC" #![feature(never_type)] #![allow(unconditional_panic)] From 797436cefb8dcc0c54a0712874602fe2900f5c00 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 29 Jul 2020 18:21:32 +0200 Subject: [PATCH 2203/3747] only check-build the dummy xargo project --- cargo-miri/bin.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index 000a4d41cc5da..85d72daadbdf3 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -338,7 +338,7 @@ path = "lib.rs" let target = target.as_ref().unwrap_or(&host); // Now invoke xargo. let mut command = xargo_check(); - command.arg("build").arg("-q"); + command.arg("check").arg("-q"); command.arg("--target").arg(target); command.current_dir(&dir); command.env("XARGO_HOME", &dir); From d340933112da9e5dcca01f6f9e6e024c31a9e4b8 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 30 Jul 2020 18:31:19 +0200 Subject: [PATCH 2204/3747] rustup --- rust-version | 2 +- src/diagnostics.rs | 3 +-- src/shims/foreign_items.rs | 4 +++- src/shims/intrinsics.rs | 4 +++- src/shims/posix/macos/dlsym.rs | 4 +++- src/shims/windows/dlsym.rs | 4 +++- 6 files changed, 14 insertions(+), 7 deletions(-) diff --git a/rust-version b/rust-version index 1ba022ac96940..0765203ccbc3f 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -1454bbd4fdac9b7272b93fe82860613dccc0afad +21867225a74d3b07c2b65e32c67f45197db36896 diff --git a/src/diagnostics.rs b/src/diagnostics.rs index 1b41ba4418377..a20e8126c13ae 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -137,8 +137,7 @@ pub fn report_error<'tcx, 'mir>( access.uninit_ptr.offset.bytes(), access.uninit_ptr.offset.bytes() + access.uninit_size.bytes(), ); - ecx.memory.dump_alloc(access.uninit_ptr.alloc_id); - eprintln!(); + eprintln!("{:?}", ecx.memory.dump_alloc(access.uninit_ptr.alloc_id)); } _ => {} } diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 98e66db92da3c..0379ec0c07787 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -1,5 +1,7 @@ use std::{convert::{TryInto, TryFrom}, iter}; +use log::trace; + use rustc_hir::def_id::DefId; use rustc_middle::{mir, ty}; use rustc_target::abi::{Align, Size}; @@ -175,7 +177,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Third: functions that return. if this.emulate_foreign_item_by_name(link_name, args, dest, ret)? { - this.dump_place(*dest); + trace!("{:?}", this.dump_place(*dest)); this.go_to_block(ret); } diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index ee64b1ffca44b..105026c70d837 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -1,5 +1,7 @@ use std::iter; +use log::trace; + use rustc_attr as attr; use rustc_ast::ast::FloatTy; use rustc_middle::{mir, ty}; @@ -524,7 +526,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx name => throw_unsup_format!("unimplemented intrinsic: {}", name), } - this.dump_place(*dest); + trace!("{:?}", this.dump_place(*dest)); this.go_to_block(ret); Ok(()) } diff --git a/src/shims/posix/macos/dlsym.rs b/src/shims/posix/macos/dlsym.rs index 0236b10e5fc8e..c9f57090ff8a2 100644 --- a/src/shims/posix/macos/dlsym.rs +++ b/src/shims/posix/macos/dlsym.rs @@ -1,5 +1,7 @@ use rustc_middle::mir; +use log::trace; + use crate::*; use helpers::check_arg_count; @@ -42,7 +44,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } - this.dump_place(*dest); + trace!("{:?}", this.dump_place(*dest)); this.go_to_block(ret); Ok(()) } diff --git a/src/shims/windows/dlsym.rs b/src/shims/windows/dlsym.rs index 737fd4314f632..91bfedff8db68 100644 --- a/src/shims/windows/dlsym.rs +++ b/src/shims/windows/dlsym.rs @@ -1,5 +1,7 @@ use rustc_middle::mir; +use log::trace; + use crate::*; use helpers::check_arg_count; use shims::windows::sync::EvalContextExt as _; @@ -73,7 +75,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } - this.dump_place(*dest); + trace!("{:?}", this.dump_place(*dest)); this.go_to_block(ret); Ok(()) } From 2dfde5b696b4f84907da50f151aafc322c975d94 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 30 Jul 2020 18:31:40 +0200 Subject: [PATCH 2205/3747] remove upstreamed intrinsic impls --- src/shims/intrinsics.rs | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 105026c70d837..53d4d08eba0dc 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -484,24 +484,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } - "min_align_of_val" => { - let &[mplace] = check_arg_count(args)?; - let mplace = this.deref_operand(mplace)?; - let (_, align) = this - .size_and_align_of_mplace(mplace)? - .expect("size_of_val called on extern type"); - this.write_scalar(Scalar::from_machine_usize(align.bytes(), this), dest)?; - } - - "size_of_val" => { - let &[mplace] = check_arg_count(args)?; - let mplace = this.deref_operand(mplace)?; - let (size, _) = this - .size_and_align_of_mplace(mplace)? - .expect("size_of_val called on extern type"); - this.write_scalar(Scalar::from_machine_usize(size.bytes(), this), dest)?; - } - // Other "assume" => { let &[cond] = check_arg_count(args)?; From 729ccbc65e6d1e0004fba28aaa7a3c9c9408c15c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 31 Jul 2020 18:30:07 +0200 Subject: [PATCH 2206/3747] test track_caller on trait objects --- tests/run-pass/track-caller-attribute.rs | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/tests/run-pass/track-caller-attribute.rs b/tests/run-pass/track-caller-attribute.rs index be655703daa06..a9cfd2e0ebded 100644 --- a/tests/run-pass/track-caller-attribute.rs +++ b/tests/run-pass/track-caller-attribute.rs @@ -35,6 +35,28 @@ fn test_fn_ptr() { pass_to_ptr_call(tracked_unit, ()); } +fn test_trait_obj() { + trait Tracked { + #[track_caller] + fn handle(&self) { // `fn` here is what the `location` should point at. + let location = std::panic::Location::caller(); + assert_eq!(location.file(), file!()); + // we only call this via trait object, so the def site should *always* be returned + assert_eq!(location.line(), line!() - 4); + assert_eq!(location.column(), 9); + } + } + + impl Tracked for () {} + impl Tracked for u8 {} + + let tracked: &dyn Tracked = &5u8; + tracked.handle(); + + const TRACKED: &dyn Tracked = &(); + TRACKED.handle(); +} + fn main() { let location = Location::caller(); let expected_line = line!() - 1; @@ -73,4 +95,5 @@ fn main() { assert_eq!(intrinsic.column(), 21); test_fn_ptr(); + test_trait_obj(); } From 35309a200ba880b2c5203e16a115ab14d0088e12 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 1 Aug 2020 14:18:52 +0200 Subject: [PATCH 2207/3747] rustup; fix linked_list test --- rust-version | 2 +- tests/run-pass/linked-list.rs | 22 ++++++++++++---------- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/rust-version b/rust-version index 0765203ccbc3f..7c4b8a50cc287 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -21867225a74d3b07c2b65e32c67f45197db36896 +dfe1e3b641abbede6230e3931d14f0d43e5b8e54 diff --git a/tests/run-pass/linked-list.rs b/tests/run-pass/linked-list.rs index f1d21728b2f00..976a35da6061d 100644 --- a/tests/run-pass/linked-list.rs +++ b/tests/run-pass/linked-list.rs @@ -1,4 +1,4 @@ -#![feature(linked_list_extras)] +#![feature(linked_list_cursors)] use std::collections::LinkedList; fn list_from(v: &[T]) -> LinkedList { @@ -9,25 +9,27 @@ fn main() { let mut m = list_from(&[0, 2, 4, 6, 8]); let len = m.len(); { - let mut it = m.iter_mut(); - it.insert_next(-2); + let mut it = m.cursor_front_mut(); + it.insert_before(-2); loop { - match it.next() { + match it.current().copied() { None => break, Some(elt) => { - it.insert_next(*elt + 1); match it.peek_next() { - Some(x) => assert_eq!(*x, *elt + 2), - None => assert_eq!(8, *elt), + Some(x) => assert_eq!(*x, elt + 2), + None => assert_eq!(8, elt), } + it.insert_after(elt + 1); + it.move_next(); // Move by 2 to skip the one we inserted. + it.move_next(); } } } - it.insert_next(0); - it.insert_next(1); + it.insert_before(99); + it.insert_after(-10); } assert_eq!(m.len(), 3 + len * 2); assert_eq!(m.into_iter().collect::>(), - [-2, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1]); + [-10, -2, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 99]); } From 5d221450690cc0a31da829563042762dff3139df Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 31 Jul 2020 19:28:59 +0200 Subject: [PATCH 2208/3747] test unwinding past topmost frame of a stack --- .../concurrency/unwind_top_of_stack.rs | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 tests/compile-fail/concurrency/unwind_top_of_stack.rs diff --git a/tests/compile-fail/concurrency/unwind_top_of_stack.rs b/tests/compile-fail/concurrency/unwind_top_of_stack.rs new file mode 100644 index 0000000000000..93b15202fc385 --- /dev/null +++ b/tests/compile-fail/concurrency/unwind_top_of_stack.rs @@ -0,0 +1,24 @@ +// ignore-windows: Concurrency on Windows is not supported yet. +// error-pattern: unwinding past the topmost frame of the stack + +//! Unwinding past the top frame of a stack is Undefined Behavior. + +#![feature(rustc_private)] + +extern crate libc; + +use std::{mem, ptr}; + +extern "C" fn thread_start(_null: *mut libc::c_void) -> *mut libc::c_void { + panic!() +} + +fn main() { + unsafe { + let mut native: libc::pthread_t = mem::zeroed(); + let attr: libc::pthread_attr_t = mem::zeroed(); + // assert_eq!(libc::pthread_attr_init(&mut attr), 0); FIXME: this function is not yet implemented. + assert_eq!(libc::pthread_create(&mut native, &attr, thread_start, ptr::null_mut()), 0); + assert_eq!(libc::pthread_join(native, ptr::null_mut()), 0); + } +} From e3956f4200184c88f0f6100f15669b1e6639804f Mon Sep 17 00:00:00 2001 From: Samrat Man Singh Date: Fri, 31 Jul 2020 22:53:35 +0530 Subject: [PATCH 2209/3747] Add FileDescriptor trait to abstract fn's on File's and Std{in,out,err} --- src/machine.rs | 2 +- src/shims/posix/fs.rs | 188 ++++++++++++++++++++++++++++-------------- 2 files changed, 129 insertions(+), 61 deletions(-) diff --git a/src/machine.rs b/src/machine.rs index e9217896ef6eb..bcdd92070942b 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -246,7 +246,7 @@ pub struct Evaluator<'mir, 'tcx> { /// Whether to enforce the validity invariant. pub(crate) validate: bool, - pub(crate) file_handler: shims::posix::FileHandler, + pub(crate) file_handler: shims::posix::FileHandler<'tcx>, pub(crate) dir_handler: shims::posix::DirHandler, /// The temporary used for storing the argument of diff --git a/src/shims/posix/fs.rs b/src/shims/posix/fs.rs index a43e86dcc5b5b..5415e9e1f77cb 100644 --- a/src/shims/posix/fs.rs +++ b/src/shims/posix/fs.rs @@ -1,7 +1,7 @@ use std::collections::BTreeMap; use std::convert::{TryFrom, TryInto}; use std::fs::{read_dir, remove_dir, remove_file, rename, DirBuilder, File, FileType, OpenOptions, ReadDir}; -use std::io::{Read, Seek, SeekFrom, Write}; +use std::io::{self, Read, Seek, SeekFrom, Write}; use std::path::Path; use std::time::SystemTime; @@ -22,15 +22,42 @@ struct FileHandle { writable: bool, } +trait FileDescriptor<'tcx> : std::fmt::Debug { + fn as_file_handle(&self) -> InterpResult<'tcx, &FileHandle>; + + fn read(&mut self, bytes: &mut [u8]) -> Result; + fn write(&mut self, bytes: &[u8]) -> Result; + fn seek(&mut self, offset: SeekFrom) -> Result; +} + +impl<'tcx> FileDescriptor<'tcx> for FileHandle { + fn as_file_handle(&self) -> InterpResult<'tcx, &FileHandle> { + Ok(&self) + } + + fn read(&mut self, bytes: &mut [u8]) -> Result { + self.file.read(bytes) + } + + fn write(&mut self, bytes: &[u8]) -> Result { + self.file.write(bytes) + } + + fn seek(&mut self, offset: SeekFrom) -> Result { + self.file.seek(offset) + } +} + #[derive(Debug, Default)] -pub struct FileHandler { - handles: BTreeMap, +pub struct FileHandler<'tcx> { + handles: BTreeMap>>, } + // fd numbers 0, 1, and 2 are reserved for stdin, stdout, and stderr const MIN_NORMAL_FILE_FD: i32 = 3; -impl FileHandler { +impl<'tcx> FileHandler<'tcx> { fn insert_fd(&mut self, file_handle: FileHandle) -> i32 { self.insert_fd_with_min_fd(file_handle, 0) } @@ -62,7 +89,7 @@ impl FileHandler { self.handles.last_key_value().map(|(fd, _)| fd.checked_add(1).unwrap()).unwrap_or(min_fd) }); - self.handles.insert(new_fd, file_handle).unwrap_none(); + self.handles.insert(new_fd, Box::new(file_handle)).unwrap_none(); new_fd } } @@ -383,20 +410,28 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } let fh = &mut this.machine.file_handler; let (file_result, writable) = match fh.handles.get(&fd) { - Some(FileHandle { file, writable }) => (file.try_clone(), *writable), + Some(file_descriptor) => match file_descriptor.as_file_handle() { + Ok(FileHandle { file, writable }) => (file.try_clone(), writable.clone()), + Err(_) => return this.handle_not_found(), + }, None => return this.handle_not_found(), }; let fd_result = file_result.map(|duplicated| { - fh.insert_fd_with_min_fd(FileHandle { file: duplicated, writable }, start) + fh.insert_fd_with_min_fd(FileHandle { file: duplicated, writable: writable }, start) }); this.try_unwrap_io_result(fd_result) } else if this.tcx.sess.target.target.target_os == "macos" && cmd == this.eval_libc_i32("F_FULLFSYNC")? { let &[_, _] = check_arg_count(args)?; - if let Some(FileHandle { file, writable }) = this.machine.file_handler.handles.get(&fd) { - let io_result = maybe_sync_file(file, *writable, File::sync_all); - this.try_unwrap_io_result(io_result) + if let Some(file_descriptor) = this.machine.file_handler.handles.get(&fd) { + match file_descriptor.as_file_handle() { + Ok(FileHandle { file, writable }) => { + let io_result = maybe_sync_file(&file, *writable, File::sync_all); + this.try_unwrap_io_result(io_result) + }, + Err(_) => this.handle_not_found(), + } } else { this.handle_not_found() } @@ -412,24 +447,29 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let fd = this.read_scalar(fd_op)?.to_i32()?; - if let Some(FileHandle { file, writable }) = this.machine.file_handler.handles.remove(&fd) { - // We sync the file if it was opened in a mode different than read-only. - if writable { - // `File::sync_all` does the checks that are done when closing a file. We do this to - // to handle possible errors correctly. - let result = this.try_unwrap_io_result(file.sync_all().map(|_| 0i32)); - // Now we actually close the file. - drop(file); - // And return the result. - result - } else { - // We drop the file, this closes it but ignores any errors produced when closing - // it. This is done because `File::sync_all` cannot be done over files like - // `/dev/urandom` which are read-only. Check - // https://github.com/rust-lang/miri/issues/999#issuecomment-568920439 for a deeper - // discussion. - drop(file); - Ok(0) + if let Some(file_descriptor) = this.machine.file_handler.handles.remove(&fd) { + match file_descriptor.as_file_handle() { + Ok(FileHandle { file, writable }) => { + // We sync the file if it was opened in a mode different than read-only. + if *writable { + // `File::sync_all` does the checks that are done when closing a file. We do this to + // to handle possible errors correctly. + let result = this.try_unwrap_io_result(file.sync_all().map(|_| 0i32)); + // Now we actually close the file. + drop(file); + // And return the result. + result + } else { + // We drop the file, this closes it but ignores any errors produced when closing + // it. This is done because `File::sync_all` cannot be done over files like + // `/dev/urandom` which are read-only. Check + // https://github.com/rust-lang/miri/issues/999#issuecomment-568920439 for a deeper + // discussion. + drop(file); + Ok(0) + } + }, + Err(_) => this.handle_not_found() } } else { this.handle_not_found() @@ -460,15 +500,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // host's and target's `isize`. This saves us from having to handle overflows later. let count = count.min(this.machine_isize_max() as u64).min(isize::MAX as u64); - if let Some(FileHandle { file, writable: _ }) = this.machine.file_handler.handles.get_mut(&fd) { - trace!("read: FD mapped to {:?}", file); + if let Some(file_descriptor) = this.machine.file_handler.handles.get_mut(&fd) { + trace!("read: FD mapped to {:?}", file_descriptor); // We want to read at most `count` bytes. We are sure that `count` is not negative // because it was a target's `usize`. Also we are sure that its smaller than // `usize::MAX` because it is a host's `isize`. let mut bytes = vec![0; count as usize]; - let result = file + // `File::read` never returns a value larger than `count`, + // so this cannot fail. + let result = file_descriptor .read(&mut bytes) - // `File::read` never returns a value larger than `count`, so this cannot fail. .map(|c| i64::try_from(c).unwrap()); match result { @@ -510,9 +551,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // host's and target's `isize`. This saves us from having to handle overflows later. let count = count.min(this.machine_isize_max() as u64).min(isize::MAX as u64); - if let Some(FileHandle { file, writable: _ }) = this.machine.file_handler.handles.get_mut(&fd) { + if let Some(file_descriptor) = this.machine.file_handler.handles.get_mut(&fd) { let bytes = this.memory.read_bytes(buf, Size::from_bytes(count))?; - let result = file.write(&bytes).map(|c| i64::try_from(c).unwrap()); + let result = file_descriptor + .write(&bytes) + .map(|c| i64::try_from(c).unwrap()); this.try_unwrap_io_result(result) } else { this.handle_not_found() @@ -545,8 +588,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx return Ok(-1); }; - if let Some(FileHandle { file, writable: _ }) = this.machine.file_handler.handles.get_mut(&fd) { - let result = file.seek(seek_from).map(|offset| i64::try_from(offset).unwrap()); + if let Some(file_descriptor) = this.machine.file_handler.handles.get_mut(&fd) { + let result = file_descriptor + .seek(seek_from) + .map(|offset| i64::try_from(offset).unwrap()); this.try_unwrap_io_result(result) } else { this.handle_not_found() @@ -1103,21 +1148,26 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let fd = this.read_scalar(fd_op)?.to_i32()?; let length = this.read_scalar(length_op)?.to_i64()?; - if let Some(FileHandle { file, writable }) = this.machine.file_handler.handles.get_mut(&fd) { - if *writable { - if let Ok(length) = length.try_into() { - let result = file.set_len(length); - this.try_unwrap_io_result(result.map(|_| 0i32)) - } else { - let einval = this.eval_libc("EINVAL")?; - this.set_last_error(einval)?; - Ok(-1) + if let Some(file_descriptor) = this.machine.file_handler.handles.get_mut(&fd) { + match file_descriptor.as_file_handle() { + Ok(FileHandle { file, writable }) => { + if *writable { + if let Ok(length) = length.try_into() { + let result = file.set_len(length); + this.try_unwrap_io_result(result.map(|_| 0i32)) + } else { + let einval = this.eval_libc("EINVAL")?; + this.set_last_error(einval)?; + Ok(-1) + } + } else { + // The file is not writable + let einval = this.eval_libc("EINVAL")?; + this.set_last_error(einval)?; + Ok(-1) + } } - } else { - // The file is not writable - let einval = this.eval_libc("EINVAL")?; - this.set_last_error(einval)?; - Ok(-1) + Err(_) => this.handle_not_found() } } else { this.handle_not_found() @@ -1135,9 +1185,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.check_no_isolation("fsync")?; let fd = this.read_scalar(fd_op)?.to_i32()?; - if let Some(FileHandle { file, writable }) = this.machine.file_handler.handles.get(&fd) { - let io_result = maybe_sync_file(file, *writable, File::sync_all); - this.try_unwrap_io_result(io_result) + if let Some(file_descriptor) = this.machine.file_handler.handles.get(&fd) { + match file_descriptor.as_file_handle() { + Ok(FileHandle { file, writable }) => { + let io_result = maybe_sync_file(&file, *writable, File::sync_all); + this.try_unwrap_io_result(io_result) + } + Err(_) => this.handle_not_found() + } } else { this.handle_not_found() } @@ -1149,9 +1204,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.check_no_isolation("fdatasync")?; let fd = this.read_scalar(fd_op)?.to_i32()?; - if let Some(FileHandle { file, writable }) = this.machine.file_handler.handles.get(&fd) { - let io_result = maybe_sync_file(file, *writable, File::sync_data); - this.try_unwrap_io_result(io_result) + if let Some(file_descriptor) = this.machine.file_handler.handles.get(&fd) { + match file_descriptor.as_file_handle() { + Ok(FileHandle { file, writable }) => { + let io_result = maybe_sync_file(&file, *writable, File::sync_data); + this.try_unwrap_io_result(io_result) + } + Err(_) => this.handle_not_found() + } } else { this.handle_not_found() } @@ -1187,9 +1247,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx return Ok(-1); } - if let Some(FileHandle { file, writable }) = this.machine.file_handler.handles.get(&fd) { - let io_result = maybe_sync_file(file, *writable, File::sync_data); - this.try_unwrap_io_result(io_result) + if let Some(file_descriptor) = this.machine.file_handler.handles.get(&fd) { + match file_descriptor.as_file_handle() { + Ok(FileHandle { file, writable }) => { + let io_result = maybe_sync_file(&file, *writable, File::sync_data); + this.try_unwrap_io_result(io_result) + }, + Err(_) => this.handle_not_found() + } } else { this.handle_not_found() } @@ -1239,7 +1304,10 @@ impl FileMetadata { ) -> InterpResult<'tcx, Option> { let option = ecx.machine.file_handler.handles.get(&fd); let file = match option { - Some(FileHandle { file, writable: _ }) => file, + Some(file_descriptor) => match file_descriptor.as_file_handle() { + Ok(FileHandle { file, writable: _ }) => file, + Err(_) => return ecx.handle_not_found().map(|_: i32| None), + }, None => return ecx.handle_not_found().map(|_: i32| None), }; let metadata = file.metadata(); From 3386f12eca5db75ee679c5d08fecec88ae99e6a0 Mon Sep 17 00:00:00 2001 From: Samrat Man Singh Date: Mon, 3 Aug 2020 11:01:42 +0530 Subject: [PATCH 2210/3747] Wrap io::Result from `FileDescriptor::{read,write,seek}` in InterpResult The outer InterpResult will be used to indicate that a fn is not implemented for a struct(eg. `write` for Stdin). The inner io::Result is just the result from the read/write/seek. --- src/shims/posix/fs.rs | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/shims/posix/fs.rs b/src/shims/posix/fs.rs index 5415e9e1f77cb..6f46401ece657 100644 --- a/src/shims/posix/fs.rs +++ b/src/shims/posix/fs.rs @@ -25,9 +25,9 @@ struct FileHandle { trait FileDescriptor<'tcx> : std::fmt::Debug { fn as_file_handle(&self) -> InterpResult<'tcx, &FileHandle>; - fn read(&mut self, bytes: &mut [u8]) -> Result; - fn write(&mut self, bytes: &[u8]) -> Result; - fn seek(&mut self, offset: SeekFrom) -> Result; + fn read(&mut self, bytes: &mut [u8]) -> InterpResult<'tcx, io::Result>; + fn write(&mut self, bytes: &[u8]) -> InterpResult<'tcx, io::Result>; + fn seek(&mut self, offset: SeekFrom) -> InterpResult<'tcx, io::Result>; } impl<'tcx> FileDescriptor<'tcx> for FileHandle { @@ -35,16 +35,16 @@ impl<'tcx> FileDescriptor<'tcx> for FileHandle { Ok(&self) } - fn read(&mut self, bytes: &mut [u8]) -> Result { - self.file.read(bytes) + fn read(&mut self, bytes: &mut [u8]) -> InterpResult<'tcx, io::Result> { + Ok(self.file.read(bytes)) } - fn write(&mut self, bytes: &[u8]) -> Result { - self.file.write(bytes) + fn write(&mut self, bytes: &[u8]) -> InterpResult<'tcx, io::Result> { + Ok(self.file.write(bytes)) } - fn seek(&mut self, offset: SeekFrom) -> Result { - self.file.seek(offset) + fn seek(&mut self, offset: SeekFrom) -> InterpResult<'tcx, io::Result> { + Ok(self.file.seek(offset)) } } @@ -509,7 +509,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // `File::read` never returns a value larger than `count`, // so this cannot fail. let result = file_descriptor - .read(&mut bytes) + .read(&mut bytes)? .map(|c| i64::try_from(c).unwrap()); match result { @@ -554,7 +554,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if let Some(file_descriptor) = this.machine.file_handler.handles.get_mut(&fd) { let bytes = this.memory.read_bytes(buf, Size::from_bytes(count))?; let result = file_descriptor - .write(&bytes) + .write(&bytes)? .map(|c| i64::try_from(c).unwrap()); this.try_unwrap_io_result(result) } else { @@ -590,7 +590,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if let Some(file_descriptor) = this.machine.file_handler.handles.get_mut(&fd) { let result = file_descriptor - .seek(seek_from) + .seek(seek_from)? .map(|offset| i64::try_from(offset).unwrap()); this.try_unwrap_io_result(result) } else { From cda255cfb4f240639493e76190db9708fc08a590 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 3 Aug 2020 14:20:46 +0200 Subject: [PATCH 2211/3747] rustup; inner_deref has been stabilized --- cargo-miri/bin.rs | 2 -- rust-version | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index 85d72daadbdf3..a2d6c3fc5b71a 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -1,5 +1,3 @@ -#![feature(inner_deref)] - use std::env; use std::ffi::OsString; use std::fs::{self, File}; diff --git a/rust-version b/rust-version index 7c4b8a50cc287..807d4e85591da 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -dfe1e3b641abbede6230e3931d14f0d43e5b8e54 +dbc2ef25fb5e15445de38f19ba75547a6cf35cae From 79e066fc95c036e64716a4222c580782a9c932c2 Mon Sep 17 00:00:00 2001 From: Samrat Man Singh Date: Mon, 3 Aug 2020 20:39:09 +0530 Subject: [PATCH 2212/3747] Remove unnecessary `clone()` on `writable` --- src/shims/posix/fs.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/shims/posix/fs.rs b/src/shims/posix/fs.rs index 6f46401ece657..1bba30a1ea0ff 100644 --- a/src/shims/posix/fs.rs +++ b/src/shims/posix/fs.rs @@ -411,13 +411,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let fh = &mut this.machine.file_handler; let (file_result, writable) = match fh.handles.get(&fd) { Some(file_descriptor) => match file_descriptor.as_file_handle() { - Ok(FileHandle { file, writable }) => (file.try_clone(), writable.clone()), + Ok(FileHandle { file, writable }) => (file.try_clone(), *writable), Err(_) => return this.handle_not_found(), }, None => return this.handle_not_found(), }; let fd_result = file_result.map(|duplicated| { - fh.insert_fd_with_min_fd(FileHandle { file: duplicated, writable: writable }, start) + fh.insert_fd_with_min_fd(FileHandle { file: duplicated, writable }, start) }); this.try_unwrap_io_result(fd_result) } else if this.tcx.sess.target.target.target_os == "macos" From bea7113eb8b3ce63b95a9c6a4f8d39c7f912d9e1 Mon Sep 17 00:00:00 2001 From: Samrat Man Singh Date: Sat, 1 Aug 2020 17:08:28 +0530 Subject: [PATCH 2213/3747] Add `impl FileDescriptor` for stdin, stdout, stderr - Use `FileDescriptor::read` for stdin reads - Use `FileDescriptor::write` for stdout/err writes - Handle stdout/err reads in `FileDescriptor::read` --- src/shims/posix/foreign_items.rs | 74 ++--------------------- src/shims/posix/fs.rs | 74 +++++++++++++++++++++-- tests/compile-fail/fs/read_from_stdout.rs | 14 +++++ tests/compile-fail/fs/write_to_stdin.rs | 14 +++++ 4 files changed, 104 insertions(+), 72 deletions(-) create mode 100644 tests/compile-fail/fs/read_from_stdout.rs create mode 100644 tests/compile-fail/fs/write_to_stdin.rs diff --git a/src/shims/posix/foreign_items.rs b/src/shims/posix/foreign_items.rs index 4bb94ae89449a..594f58d26461f 100644 --- a/src/shims/posix/foreign_items.rs +++ b/src/shims/posix/foreign_items.rs @@ -1,5 +1,4 @@ -use std::convert::TryFrom; -use std::io::{self, Read, Write}; +use std::io::{self, Write}; use log::trace; @@ -67,43 +66,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let fd = this.read_scalar(fd)?.to_i32()?; let buf = this.read_scalar(buf)?.check_init()?; let count = this.read_scalar(count)?.to_machine_usize(this)?; - let result = if fd == 0 { - - this.check_no_isolation("read")?; - - // We cap the number of read bytes to the largest - // value that we are able to fit in both the - // host's and target's `isize`. This saves us from - // having to handle overflows later. - let count = count.min(this.machine_isize_max() as u64).min(isize::MAX as u64); - - // We want to read at most `count` bytes. We are - // sure that `count` is not negative because it - // was a target's `usize`. Also we are sure that - // its smaller than `usize::MAX` because it is a - // host's `isize`. - let mut buffer = vec![0; count as usize]; - let res = io::stdin() - .read(&mut buffer) - // `Stdin::read` never returns a value larger - // than `count`, so this cannot fail. - .map(|c| i64::try_from(c).unwrap()); - - match res { - Ok(bytes) => { - this.memory.write_bytes(buf, buffer)?; - i64::try_from(bytes).unwrap() - }, - Err(e) => { - this.set_last_error_from_io_error(e)?; - -1 - }, - } - } else if fd == 1 || fd == 2 { - throw_unsup_format!("cannot read from stdout/stderr") - } else { - this.read(fd, buf, count)? - }; + let result = this.read(fd, buf, count)?; this.write_scalar(Scalar::from_machine_isize(result, this), dest)?; } "write" => { @@ -112,35 +75,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let buf = this.read_scalar(buf)?.check_init()?; let count = this.read_scalar(n)?.to_machine_usize(this)?; trace!("Called write({:?}, {:?}, {:?})", fd, buf, count); - let result = if fd == 0 { - throw_unsup_format!("cannot write to stdin") - } else if fd == 1 || fd == 2 { - // stdout/stderr - - let buf_cont = this.memory.read_bytes(buf, Size::from_bytes(count))?; - // We need to flush to make sure this actually appears on the screen - let res = if fd == 1 { - // Stdout is buffered, flush to make sure it appears on the screen. - // This is the write() syscall of the interpreted program, we want it - // to correspond to a write() syscall on the host -- there is no good - // in adding extra buffering here. - let res = io::stdout().write(buf_cont); - io::stdout().flush().unwrap(); - res - } else { - // No need to flush, stderr is not buffered. - io::stderr().write(buf_cont) - }; - match res { - Ok(n) => i64::try_from(n).unwrap(), - Err(e) => { - this.set_last_error_from_io_error(e)?; - -1 - } - } - } else { - this.write(fd, buf, count)? - }; + let result = this.write(fd, buf, count)?; + if fd == 1 { + io::stdout().flush().unwrap(); + } // Now, `result` is the value we return back to the program. this.write_scalar(Scalar::from_machine_isize(result, this), dest)?; } diff --git a/src/shims/posix/fs.rs b/src/shims/posix/fs.rs index 2d784490656c9..65d50aa504d3d 100644 --- a/src/shims/posix/fs.rs +++ b/src/shims/posix/fs.rs @@ -48,11 +48,77 @@ impl<'tcx> FileDescriptor<'tcx> for FileHandle { } } -#[derive(Debug, Default)] +impl<'tcx> FileDescriptor<'tcx> for io::Stdin { + fn as_file_handle(&self) -> InterpResult<'tcx, &FileHandle> { + throw_unsup_format!("stdin cannot be used as FileHandle"); + } + + fn read(&mut self, bytes: &mut [u8]) -> InterpResult<'tcx, io::Result> { + Ok(Read::read(self, bytes)) + } + + fn write(&mut self, _bytes: &[u8]) -> InterpResult<'tcx, io::Result> { + throw_unsup_format!("cannot write to stdin"); + } + + fn seek(&mut self, _offset: SeekFrom) -> InterpResult<'tcx, io::Result> { + throw_unsup_format!("cannot seek on stdin"); + } +} + +impl<'tcx> FileDescriptor<'tcx> for io::Stdout { + fn as_file_handle(&self) -> InterpResult<'tcx, &FileHandle> { + throw_unsup_format!("stdout cannot be used as FileHandle"); + } + + fn read(&mut self, _bytes: &mut [u8]) -> InterpResult<'tcx, io::Result> { + throw_unsup_format!("cannot read from stdout"); + } + + fn write(&mut self, bytes: &[u8]) -> InterpResult<'tcx, io::Result> { + Ok(Write::write(self, bytes)) + } + + fn seek(&mut self, _offset: SeekFrom) -> InterpResult<'tcx, io::Result> { + throw_unsup_format!("cannot seek on stdout"); + } +} + +impl<'tcx> FileDescriptor<'tcx> for io::Stderr { + fn as_file_handle(&self) -> InterpResult<'tcx, &FileHandle> { + throw_unsup_format!("stdout cannot be used as FileHandle"); + } + + fn read(&mut self, _bytes: &mut [u8]) -> InterpResult<'tcx, io::Result> { + throw_unsup_format!("cannot read from stderr"); + } + + fn write(&mut self, bytes: &[u8]) -> InterpResult<'tcx, io::Result> { + Ok(Write::write(self, bytes)) + } + + fn seek(&mut self, _offset: SeekFrom) -> InterpResult<'tcx, io::Result> { + throw_unsup_format!("cannot seek on stderr"); + } +} + +#[derive(Debug)] pub struct FileHandler<'tcx> { handles: BTreeMap>>, } +impl<'tcx> Default for FileHandler<'tcx> { + fn default() -> Self { + let mut handles = BTreeMap::new(); + handles.insert(0i32, Box::new(io::stdin()) as Box>); + handles.insert(1i32, Box::new(io::stdout()) as Box>); + handles.insert(2i32, Box::new(io::stderr()) as Box>); + FileHandler { + handles + } + } +} + // fd numbers 0, 1, and 2 are reserved for stdin, stdout, and stderr const MIN_NORMAL_FILE_FD: i32 = 3; @@ -485,7 +551,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); this.check_no_isolation("read")?; - assert!(fd >= 3); trace!("Reading from FD {}, size {}", fd, count); @@ -537,8 +602,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, i64> { let this = self.eval_context_mut(); - this.check_no_isolation("write")?; - assert!(fd >= 3); + if fd >= 3 { + this.check_no_isolation("write")?; + } // Check that the *entire* buffer is actually valid memory. this.memory.check_ptr_access( diff --git a/tests/compile-fail/fs/read_from_stdout.rs b/tests/compile-fail/fs/read_from_stdout.rs new file mode 100644 index 0000000000000..17f1735f6aded --- /dev/null +++ b/tests/compile-fail/fs/read_from_stdout.rs @@ -0,0 +1,14 @@ +// compile-flags: -Zmiri-disable-isolation +// ignore-windows: No libc on Windows + +#![feature(rustc_private)] + +extern crate libc; + +fn main() -> std::io::Result<()> { + let mut bytes = [0u8; 512]; + unsafe { + libc::read(1, bytes.as_mut_ptr() as *mut libc::c_void, 512); //~ ERROR cannot read from stdout + } + Ok(()) +} diff --git a/tests/compile-fail/fs/write_to_stdin.rs b/tests/compile-fail/fs/write_to_stdin.rs new file mode 100644 index 0000000000000..30d24b5dc4443 --- /dev/null +++ b/tests/compile-fail/fs/write_to_stdin.rs @@ -0,0 +1,14 @@ +// compile-flags: -Zmiri-disable-isolation +// ignore-windows: No libc on Windows + +#![feature(rustc_private)] + +extern crate libc; + +fn main() -> std::io::Result<()> { + let bytes = b"hello"; + unsafe { + libc::write(0, bytes.as_ptr() as *const libc::c_void, 5); //~ ERROR cannot write to stdin + } + Ok(()) +} From bdef57ea45594752f904983effc81fe938fbdfe9 Mon Sep 17 00:00:00 2001 From: Samrat Man Singh Date: Tue, 4 Aug 2020 20:40:48 +0530 Subject: [PATCH 2214/3747] Flush to stdout from FileDescriptor::write for `Stdout` Also, remove unnecessary `-Zmiri-disable-isolation` in test --- src/shims/posix/foreign_items.rs | 5 ----- src/shims/posix/fs.rs | 10 +++++++++- tests/compile-fail/fs/write_to_stdin.rs | 1 - 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/shims/posix/foreign_items.rs b/src/shims/posix/foreign_items.rs index 594f58d26461f..151ab95f1e3c4 100644 --- a/src/shims/posix/foreign_items.rs +++ b/src/shims/posix/foreign_items.rs @@ -1,5 +1,3 @@ -use std::io::{self, Write}; - use log::trace; use rustc_middle::mir; @@ -76,9 +74,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let count = this.read_scalar(n)?.to_machine_usize(this)?; trace!("Called write({:?}, {:?}, {:?})", fd, buf, count); let result = this.write(fd, buf, count)?; - if fd == 1 { - io::stdout().flush().unwrap(); - } // Now, `result` is the value we return back to the program. this.write_scalar(Scalar::from_machine_isize(result, this), dest)?; } diff --git a/src/shims/posix/fs.rs b/src/shims/posix/fs.rs index 65d50aa504d3d..3e1ba3976f776 100644 --- a/src/shims/posix/fs.rs +++ b/src/shims/posix/fs.rs @@ -76,7 +76,15 @@ impl<'tcx> FileDescriptor<'tcx> for io::Stdout { } fn write(&mut self, bytes: &[u8]) -> InterpResult<'tcx, io::Result> { - Ok(Write::write(self, bytes)) + let result = Write::write(self, bytes); + // Stdout is buffered, flush to make sure it appears on the + // screen. This is the write() syscall of the interpreted + // program, we want it to correspond to a write() syscall on + // the host -- there is no good in adding extra buffering + // here. + io::stdout().flush().unwrap(); + + Ok(result) } fn seek(&mut self, _offset: SeekFrom) -> InterpResult<'tcx, io::Result> { diff --git a/tests/compile-fail/fs/write_to_stdin.rs b/tests/compile-fail/fs/write_to_stdin.rs index 30d24b5dc4443..c2754636c860c 100644 --- a/tests/compile-fail/fs/write_to_stdin.rs +++ b/tests/compile-fail/fs/write_to_stdin.rs @@ -1,4 +1,3 @@ -// compile-flags: -Zmiri-disable-isolation // ignore-windows: No libc on Windows #![feature(rustc_private)] From 422113a49188f6c4e1e625f6efbe78da87441f09 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 5 Aug 2020 13:38:15 +0200 Subject: [PATCH 2215/3747] rustup --- rust-version | 2 +- tests/run-pass/heap_allocator.rs | 19 ++++++++++--------- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/rust-version b/rust-version index 807d4e85591da..4fb52f22fa0a7 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -dbc2ef25fb5e15445de38f19ba75547a6cf35cae +1d69e3b1d753951bc7df0f02d6fd4719065d98c3 diff --git a/tests/run-pass/heap_allocator.rs b/tests/run-pass/heap_allocator.rs index c2fcfea58cdf5..557550d6f4331 100644 --- a/tests/run-pass/heap_allocator.rs +++ b/tests/run-pass/heap_allocator.rs @@ -1,7 +1,7 @@ -#![feature(allocator_api)] +#![feature(allocator_api, slice_ptr_get)] use std::ptr::NonNull; -use std::alloc::{Global, AllocRef, Layout, System, AllocInit, ReallocPlacement}; +use std::alloc::{Global, AllocRef, Layout, System}; use std::slice; fn check_alloc(mut allocator: T) { unsafe { @@ -9,29 +9,30 @@ fn check_alloc(mut allocator: T) { unsafe { let layout = Layout::from_size_align(20, align).unwrap(); for _ in 0..32 { - let a = allocator.alloc(layout, AllocInit::Uninitialized).unwrap().ptr; + let a = allocator.alloc(layout).unwrap().as_non_null_ptr(); assert_eq!(a.as_ptr() as usize % align, 0, "pointer is incorrectly aligned"); allocator.dealloc(a, layout); } - let p1 = allocator.alloc(layout, AllocInit::Zeroed).unwrap().ptr; + let p1 = allocator.alloc_zeroed(layout).unwrap().as_non_null_ptr(); assert_eq!(p1.as_ptr() as usize % align, 0, "pointer is incorrectly aligned"); + assert_eq!(*p1.as_ptr(), 0); // old size < new size - let p2 = allocator.grow(p1, layout, 40, ReallocPlacement::MayMove, AllocInit::Uninitialized).unwrap().ptr; + let p2 = allocator.grow(p1, layout, 40).unwrap().as_non_null_ptr(); let layout = Layout::from_size_align(40, align).unwrap(); assert_eq!(p2.as_ptr() as usize % align, 0, "pointer is incorrectly aligned"); let slice = slice::from_raw_parts(p2.as_ptr(), 20); assert_eq!(&slice, &[0_u8; 20]); // old size == new size - let p3 = allocator.grow(p2, layout, 40, ReallocPlacement::MayMove, AllocInit::Uninitialized).unwrap().ptr; + let p3 = allocator.grow(p2, layout, 40).unwrap().as_non_null_ptr(); assert_eq!(p3.as_ptr() as usize % align, 0, "pointer is incorrectly aligned"); let slice = slice::from_raw_parts(p3.as_ptr(), 20); assert_eq!(&slice, &[0_u8; 20]); // old size > new size - let p4 = allocator.shrink(p3, layout, 10, ReallocPlacement::MayMove).unwrap().ptr; + let p4 = allocator.shrink(p3, layout, 10).unwrap().as_non_null_ptr(); let layout = Layout::from_size_align(10, align).unwrap(); assert_eq!(p4.as_ptr() as usize % align, 0, "pointer is incorrectly aligned"); let slice = slice::from_raw_parts(p4.as_ptr(), 10); @@ -47,7 +48,7 @@ fn check_align_requests(mut allocator: T) { let iterations = 32; unsafe { let pointers: Vec<_> = (0..iterations).map(|_| { - allocator.alloc(Layout::from_size_align(size, align).unwrap(), AllocInit::Uninitialized).unwrap().ptr + allocator.alloc(Layout::from_size_align(size, align).unwrap()).unwrap().as_non_null_ptr() }).collect(); for &ptr in &pointers { assert_eq!((ptr.as_ptr() as usize) % align, 0, @@ -68,7 +69,7 @@ fn global_to_box() { let l = Layout::new::(); // allocate manually with global allocator, then turn into Box and free there unsafe { - let ptr = Global.alloc(l, AllocInit::Uninitialized).unwrap().ptr.as_ptr() as *mut T; + let ptr = Global.alloc(l).unwrap().as_non_null_ptr().as_ptr() as *mut T; let b = Box::from_raw(ptr); drop(b); } From 773dfb31f0c35ec992892b4677ea5764068f8092 Mon Sep 17 00:00:00 2001 From: Samrat Man Singh Date: Sat, 8 Aug 2020 14:42:50 +0530 Subject: [PATCH 2216/3747] Bubble up error from FileDescriptor::as_file_handle ...instead of handle_not_found --- src/shims/posix/fs.rs | 114 +++++++++++++++++------------------------- 1 file changed, 47 insertions(+), 67 deletions(-) diff --git a/src/shims/posix/fs.rs b/src/shims/posix/fs.rs index 3e1ba3976f776..13c7827f88794 100644 --- a/src/shims/posix/fs.rs +++ b/src/shims/posix/fs.rs @@ -484,9 +484,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } let fh = &mut this.machine.file_handler; let (file_result, writable) = match fh.handles.get(&fd) { - Some(file_descriptor) => match file_descriptor.as_file_handle() { - Ok(FileHandle { file, writable }) => (file.try_clone(), *writable), - Err(_) => return this.handle_not_found(), + Some(file_descriptor) => { + let FileHandle { file, writable } = file_descriptor.as_file_handle()?; + (file.try_clone(), *writable) }, None => return this.handle_not_found(), }; @@ -522,28 +522,24 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let fd = this.read_scalar(fd_op)?.to_i32()?; if let Some(file_descriptor) = this.machine.file_handler.handles.remove(&fd) { - match file_descriptor.as_file_handle() { - Ok(FileHandle { file, writable }) => { - // We sync the file if it was opened in a mode different than read-only. - if *writable { - // `File::sync_all` does the checks that are done when closing a file. We do this to - // to handle possible errors correctly. - let result = this.try_unwrap_io_result(file.sync_all().map(|_| 0i32)); - // Now we actually close the file. - drop(file); - // And return the result. - result - } else { - // We drop the file, this closes it but ignores any errors produced when closing - // it. This is done because `File::sync_all` cannot be done over files like - // `/dev/urandom` which are read-only. Check - // https://github.com/rust-lang/miri/issues/999#issuecomment-568920439 for a deeper - // discussion. - drop(file); - Ok(0) - } - }, - Err(_) => this.handle_not_found() + let FileHandle { file, writable } = file_descriptor.as_file_handle()?; + // We sync the file if it was opened in a mode different than read-only. + if *writable { + // `File::sync_all` does the checks that are done when closing a file. We do this to + // to handle possible errors correctly. + let result = this.try_unwrap_io_result(file.sync_all().map(|_| 0i32)); + // Now we actually close the file. + drop(file); + // And return the result. + result + } else { + // We drop the file, this closes it but ignores any errors produced when closing + // it. This is done because `File::sync_all` cannot be done over files like + // `/dev/urandom` which are read-only. Check + // https://github.com/rust-lang/miri/issues/999#issuecomment-568920439 for a deeper + // discussion. + drop(file); + Ok(0) } } else { this.handle_not_found() @@ -1223,25 +1219,21 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let fd = this.read_scalar(fd_op)?.to_i32()?; let length = this.read_scalar(length_op)?.to_i64()?; if let Some(file_descriptor) = this.machine.file_handler.handles.get_mut(&fd) { - match file_descriptor.as_file_handle() { - Ok(FileHandle { file, writable }) => { - if *writable { - if let Ok(length) = length.try_into() { - let result = file.set_len(length); - this.try_unwrap_io_result(result.map(|_| 0i32)) - } else { - let einval = this.eval_libc("EINVAL")?; - this.set_last_error(einval)?; - Ok(-1) - } - } else { - // The file is not writable - let einval = this.eval_libc("EINVAL")?; - this.set_last_error(einval)?; - Ok(-1) - } + let FileHandle { file, writable } = file_descriptor.as_file_handle()?; + if *writable { + if let Ok(length) = length.try_into() { + let result = file.set_len(length); + this.try_unwrap_io_result(result.map(|_| 0i32)) + } else { + let einval = this.eval_libc("EINVAL")?; + this.set_last_error(einval)?; + Ok(-1) } - Err(_) => this.handle_not_found() + } else { + // The file is not writable + let einval = this.eval_libc("EINVAL")?; + this.set_last_error(einval)?; + Ok(-1) } } else { this.handle_not_found() @@ -1260,13 +1252,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let fd = this.read_scalar(fd_op)?.to_i32()?; if let Some(file_descriptor) = this.machine.file_handler.handles.get(&fd) { - match file_descriptor.as_file_handle() { - Ok(FileHandle { file, writable }) => { - let io_result = maybe_sync_file(&file, *writable, File::sync_all); - this.try_unwrap_io_result(io_result) - } - Err(_) => this.handle_not_found() - } + let FileHandle { file, writable } = file_descriptor.as_file_handle()?; + let io_result = maybe_sync_file(&file, *writable, File::sync_all); + this.try_unwrap_io_result(io_result) } else { this.handle_not_found() } @@ -1279,13 +1267,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let fd = this.read_scalar(fd_op)?.to_i32()?; if let Some(file_descriptor) = this.machine.file_handler.handles.get(&fd) { - match file_descriptor.as_file_handle() { - Ok(FileHandle { file, writable }) => { - let io_result = maybe_sync_file(&file, *writable, File::sync_data); - this.try_unwrap_io_result(io_result) - } - Err(_) => this.handle_not_found() - } + let FileHandle { file, writable } = file_descriptor.as_file_handle()?; + let io_result = maybe_sync_file(&file, *writable, File::sync_data); + this.try_unwrap_io_result(io_result) } else { this.handle_not_found() } @@ -1322,13 +1306,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } if let Some(file_descriptor) = this.machine.file_handler.handles.get(&fd) { - match file_descriptor.as_file_handle() { - Ok(FileHandle { file, writable }) => { - let io_result = maybe_sync_file(&file, *writable, File::sync_data); - this.try_unwrap_io_result(io_result) - }, - Err(_) => this.handle_not_found() - } + let FileHandle { file, writable } = file_descriptor.as_file_handle()?; + let io_result = maybe_sync_file(&file, *writable, File::sync_data); + this.try_unwrap_io_result(io_result) } else { this.handle_not_found() } @@ -1378,9 +1358,9 @@ impl FileMetadata { ) -> InterpResult<'tcx, Option> { let option = ecx.machine.file_handler.handles.get(&fd); let file = match option { - Some(file_descriptor) => match file_descriptor.as_file_handle() { - Ok(FileHandle { file, writable: _ }) => file, - Err(_) => return ecx.handle_not_found().map(|_: i32| None), + Some(file_descriptor) => { + let FileHandle { file, writable: _ } = file_descriptor.as_file_handle()?; + file }, None => return ecx.handle_not_found().map(|_: i32| None), }; From 045bcab1eb9a0d0efbed0ae6d2e3dd30270284e6 Mon Sep 17 00:00:00 2001 From: Samrat Man Singh Date: Sat, 8 Aug 2020 15:08:29 +0530 Subject: [PATCH 2217/3747] Add FIXME's for `dup` and other syscalls to support stdin/out/err --- src/shims/posix/fs.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/shims/posix/fs.rs b/src/shims/posix/fs.rs index 13c7827f88794..ec6fb7c537356 100644 --- a/src/shims/posix/fs.rs +++ b/src/shims/posix/fs.rs @@ -485,6 +485,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let fh = &mut this.machine.file_handler; let (file_result, writable) = match fh.handles.get(&fd) { Some(file_descriptor) => { + // FIXME: Support "dup" for all FDs(stdin, etc) let FileHandle { file, writable } = file_descriptor.as_file_handle()?; (file.try_clone(), *writable) }, @@ -499,6 +500,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx { let &[_, _] = check_arg_count(args)?; if let Some(file_descriptor) = this.machine.file_handler.handles.get(&fd) { + // FIXME: Support fullfsync for all FDs match file_descriptor.as_file_handle() { Ok(FileHandle { file, writable }) => { let io_result = maybe_sync_file(&file, *writable, File::sync_all); @@ -522,6 +524,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let fd = this.read_scalar(fd_op)?.to_i32()?; if let Some(file_descriptor) = this.machine.file_handler.handles.remove(&fd) { + // FIXME: Support `close` for all FDs(stdin, etc) let FileHandle { file, writable } = file_descriptor.as_file_handle()?; // We sync the file if it was opened in a mode different than read-only. if *writable { @@ -1219,6 +1222,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let fd = this.read_scalar(fd_op)?.to_i32()?; let length = this.read_scalar(length_op)?.to_i64()?; if let Some(file_descriptor) = this.machine.file_handler.handles.get_mut(&fd) { + // FIXME: Support ftruncate64 for all FDs let FileHandle { file, writable } = file_descriptor.as_file_handle()?; if *writable { if let Ok(length) = length.try_into() { @@ -1252,6 +1256,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let fd = this.read_scalar(fd_op)?.to_i32()?; if let Some(file_descriptor) = this.machine.file_handler.handles.get(&fd) { + // FIXME: Support fsync for all FDs let FileHandle { file, writable } = file_descriptor.as_file_handle()?; let io_result = maybe_sync_file(&file, *writable, File::sync_all); this.try_unwrap_io_result(io_result) @@ -1267,6 +1272,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let fd = this.read_scalar(fd_op)?.to_i32()?; if let Some(file_descriptor) = this.machine.file_handler.handles.get(&fd) { + // FIXME: Support fdatasync for all FDs let FileHandle { file, writable } = file_descriptor.as_file_handle()?; let io_result = maybe_sync_file(&file, *writable, File::sync_data); this.try_unwrap_io_result(io_result) @@ -1306,6 +1312,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } if let Some(file_descriptor) = this.machine.file_handler.handles.get(&fd) { + // FIXME: Support sync_data_range for all FDs let FileHandle { file, writable } = file_descriptor.as_file_handle()?; let io_result = maybe_sync_file(&file, *writable, File::sync_data); this.try_unwrap_io_result(io_result) From 1069f6b17468a48af5a8ab441bf355ac955f4596 Mon Sep 17 00:00:00 2001 From: Samrat Man Singh Date: Sat, 8 Aug 2020 17:28:41 +0530 Subject: [PATCH 2218/3747] Fix handling of as_file_handle error for `fullfsync` --- src/shims/posix/fs.rs | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/src/shims/posix/fs.rs b/src/shims/posix/fs.rs index ec6fb7c537356..e0b2837cae908 100644 --- a/src/shims/posix/fs.rs +++ b/src/shims/posix/fs.rs @@ -501,13 +501,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let &[_, _] = check_arg_count(args)?; if let Some(file_descriptor) = this.machine.file_handler.handles.get(&fd) { // FIXME: Support fullfsync for all FDs - match file_descriptor.as_file_handle() { - Ok(FileHandle { file, writable }) => { - let io_result = maybe_sync_file(&file, *writable, File::sync_all); - this.try_unwrap_io_result(io_result) - }, - Err(_) => this.handle_not_found(), - } + let FileHandle { file, writable } = file_descriptor.as_file_handle()?; + let io_result = maybe_sync_file(&file, *writable, File::sync_all); + this.try_unwrap_io_result(io_result) } else { this.handle_not_found() } @@ -1365,10 +1361,7 @@ impl FileMetadata { ) -> InterpResult<'tcx, Option> { let option = ecx.machine.file_handler.handles.get(&fd); let file = match option { - Some(file_descriptor) => { - let FileHandle { file, writable: _ } = file_descriptor.as_file_handle()?; - file - }, + Some(file_descriptor) => &file_descriptor.as_file_handle()?.file, None => return ecx.handle_not_found().map(|_: i32| None), }; let metadata = file.metadata(); From 07a4383ac8930d3d1a243f3e44f6cbc33e42696b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 8 Aug 2020 10:27:23 +0200 Subject: [PATCH 2219/3747] rustup --- rust-version | 2 +- src/bin/miri-rustc-tests.rs | 2 +- src/machine.rs | 3 +-- src/shims/foreign_items.rs | 3 +-- 4 files changed, 4 insertions(+), 6 deletions(-) diff --git a/rust-version b/rust-version index 4fb52f22fa0a7..75cd757fcc4c5 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -1d69e3b1d753951bc7df0f02d6fd4719065d98c3 +c92fc8db8b009b7661cff31fa59a7c0348653bd0 diff --git a/src/bin/miri-rustc-tests.rs b/src/bin/miri-rustc-tests.rs index add9cfe897fb1..56d19e62749ea 100644 --- a/src/bin/miri-rustc-tests.rs +++ b/src/bin/miri-rustc-tests.rs @@ -38,7 +38,7 @@ impl rustc_driver::Callbacks for MiriCompilerCalls { if let hir::ItemKind::Fn(.., body_id) = i.kind { if i.attrs .iter() - .any(|attr| attr.check_name(rustc_span::symbol::sym::test)) + .any(|attr| self.0.sess.check_name(attr, rustc_span::symbol::sym::test)) { let config = miri::MiriConfig::default(); let did = self.0.hir().body_owner_def_id(body_id).to_def_id(); diff --git a/src/machine.rs b/src/machine.rs index f9dd48fdbae2a..9e22825ccac4b 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -11,7 +11,6 @@ use std::fmt; use log::trace; use rand::rngs::StdRng; -use rustc_ast::attr; use rustc_data_structures::fx::FxHashMap; use rustc_middle::{ mir, @@ -442,7 +441,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { def_id: DefId, ) -> InterpResult<'tcx, AllocId> { let attrs = memory.tcx.get_attrs(def_id); - let link_name = match attr::first_attr_value_str_by_name(&attrs, sym::link_name) { + let link_name = match memory.tcx.sess.first_attr_value_str_by_name(&attrs, sym::link_name) { Some(name) => name, None => memory.tcx.item_name(def_id), }; diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 0379ec0c07787..355801eb8ffb2 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -7,7 +7,6 @@ use rustc_middle::{mir, ty}; use rustc_target::abi::{Align, Size}; use rustc_apfloat::Float; use rustc_span::symbol::sym; -use rustc_ast::attr; use crate::*; use helpers::check_arg_count; @@ -117,7 +116,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, Option<&'mir mir::Body<'tcx>>> { let this = self.eval_context_mut(); let attrs = this.tcx.get_attrs(def_id); - let link_name = match attr::first_attr_value_str_by_name(&attrs, sym::link_name) { + let link_name = match this.tcx.sess.first_attr_value_str_by_name(&attrs, sym::link_name) { Some(name) => name.as_str(), None => this.tcx.item_name(def_id).as_str(), }; From 5657f08bea978ddd9114c5a25a07e115ee609425 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 8 Aug 2020 15:21:04 +0200 Subject: [PATCH 2220/3747] fs: move isolation handling to inside trait --- src/helpers.rs | 13 ++++-- src/shims/posix/fs.rs | 53 ++++++++++++++----------- tests/compile-fail/fs/isolated_stdin.rs | 13 ++++++ 3 files changed, 52 insertions(+), 27 deletions(-) create mode 100644 tests/compile-fail/fs/isolated_stdin.rs diff --git a/src/helpers.rs b/src/helpers.rs index d271b845c2151..0426115773d9e 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -376,13 +376,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// case. fn check_no_isolation(&self, name: &str) -> InterpResult<'tcx> { if !self.eval_context_ref().machine.communicate { - throw_machine_stop!(TerminationInfo::UnsupportedInIsolation(format!( - "`{}` not available when isolation is enabled", - name, - ))) + isolation_error(name)?; } Ok(()) } + /// Helper function used inside the shims of foreign functions to assert that the target OS /// is `target_os`. It panics showing a message with the `name` of the foreign function /// if this is not the case. @@ -509,6 +507,13 @@ pub fn check_arg_count<'a, 'tcx, const N: usize>(args: &'a [OpTy<'tcx, Tag>]) -> throw_ub_format!("incorrect number of arguments: got {}, expected {}", args.len(), N) } +pub fn isolation_error(name: &str) -> InterpResult<'static> { + throw_machine_stop!(TerminationInfo::UnsupportedInIsolation(format!( + "`{}` not available when isolation is enabled", + name, + ))) +} + pub fn immty_from_int_checked<'tcx>( int: impl Into, layout: TyAndLayout<'tcx>, diff --git a/src/shims/posix/fs.rs b/src/shims/posix/fs.rs index e0b2837cae908..cf050b7086945 100644 --- a/src/shims/posix/fs.rs +++ b/src/shims/posix/fs.rs @@ -25,9 +25,9 @@ struct FileHandle { trait FileDescriptor<'tcx> : std::fmt::Debug { fn as_file_handle(&self) -> InterpResult<'tcx, &FileHandle>; - fn read(&mut self, bytes: &mut [u8]) -> InterpResult<'tcx, io::Result>; - fn write(&mut self, bytes: &[u8]) -> InterpResult<'tcx, io::Result>; - fn seek(&mut self, offset: SeekFrom) -> InterpResult<'tcx, io::Result>; + fn read(&mut self, communicate_allowed: bool, bytes: &mut [u8]) -> InterpResult<'tcx, io::Result>; + fn write(&mut self, communicate_allowed: bool, bytes: &[u8]) -> InterpResult<'tcx, io::Result>; + fn seek(&mut self, communicate_allowed: bool, offset: SeekFrom) -> InterpResult<'tcx, io::Result>; } impl<'tcx> FileDescriptor<'tcx> for FileHandle { @@ -35,15 +35,18 @@ impl<'tcx> FileDescriptor<'tcx> for FileHandle { Ok(&self) } - fn read(&mut self, bytes: &mut [u8]) -> InterpResult<'tcx, io::Result> { + fn read(&mut self, communicate_allowed: bool, bytes: &mut [u8]) -> InterpResult<'tcx, io::Result> { + assert!(communicate_allowed, "isolation should have prevented even opening a file"); Ok(self.file.read(bytes)) } - fn write(&mut self, bytes: &[u8]) -> InterpResult<'tcx, io::Result> { + fn write(&mut self, communicate_allowed: bool, bytes: &[u8]) -> InterpResult<'tcx, io::Result> { + assert!(communicate_allowed, "isolation should have prevented even opening a file"); Ok(self.file.write(bytes)) } - fn seek(&mut self, offset: SeekFrom) -> InterpResult<'tcx, io::Result> { + fn seek(&mut self, communicate_allowed: bool, offset: SeekFrom) -> InterpResult<'tcx, io::Result> { + assert!(communicate_allowed, "isolation should have prevented even opening a file"); Ok(self.file.seek(offset)) } } @@ -53,15 +56,19 @@ impl<'tcx> FileDescriptor<'tcx> for io::Stdin { throw_unsup_format!("stdin cannot be used as FileHandle"); } - fn read(&mut self, bytes: &mut [u8]) -> InterpResult<'tcx, io::Result> { + fn read(&mut self, communicate_allowed: bool, bytes: &mut [u8]) -> InterpResult<'tcx, io::Result> { + if !communicate_allowed { + // We want isolation mode to be deterministic, so we have to disallow all reads, even stdin. + helpers::isolation_error("read")?; + } Ok(Read::read(self, bytes)) } - fn write(&mut self, _bytes: &[u8]) -> InterpResult<'tcx, io::Result> { + fn write(&mut self, _communicate_allowed: bool, _bytes: &[u8]) -> InterpResult<'tcx, io::Result> { throw_unsup_format!("cannot write to stdin"); } - fn seek(&mut self, _offset: SeekFrom) -> InterpResult<'tcx, io::Result> { + fn seek(&mut self, _communicate_allowed: bool, _offset: SeekFrom) -> InterpResult<'tcx, io::Result> { throw_unsup_format!("cannot seek on stdin"); } } @@ -71,11 +78,12 @@ impl<'tcx> FileDescriptor<'tcx> for io::Stdout { throw_unsup_format!("stdout cannot be used as FileHandle"); } - fn read(&mut self, _bytes: &mut [u8]) -> InterpResult<'tcx, io::Result> { + fn read(&mut self, _communicate_allowed: bool, _bytes: &mut [u8]) -> InterpResult<'tcx, io::Result> { throw_unsup_format!("cannot read from stdout"); } - fn write(&mut self, bytes: &[u8]) -> InterpResult<'tcx, io::Result> { + fn write(&mut self, _communicate_allowed: bool, bytes: &[u8]) -> InterpResult<'tcx, io::Result> { + // We allow writing to stderr even with isolation enabled. let result = Write::write(self, bytes); // Stdout is buffered, flush to make sure it appears on the // screen. This is the write() syscall of the interpreted @@ -87,7 +95,7 @@ impl<'tcx> FileDescriptor<'tcx> for io::Stdout { Ok(result) } - fn seek(&mut self, _offset: SeekFrom) -> InterpResult<'tcx, io::Result> { + fn seek(&mut self, _communicate_allowed: bool, _offset: SeekFrom) -> InterpResult<'tcx, io::Result> { throw_unsup_format!("cannot seek on stdout"); } } @@ -97,15 +105,16 @@ impl<'tcx> FileDescriptor<'tcx> for io::Stderr { throw_unsup_format!("stdout cannot be used as FileHandle"); } - fn read(&mut self, _bytes: &mut [u8]) -> InterpResult<'tcx, io::Result> { + fn read(&mut self, _communicate_allowed: bool, _bytes: &mut [u8]) -> InterpResult<'tcx, io::Result> { throw_unsup_format!("cannot read from stderr"); } - fn write(&mut self, bytes: &[u8]) -> InterpResult<'tcx, io::Result> { + fn write(&mut self, _communicate_allowed: bool, bytes: &[u8]) -> InterpResult<'tcx, io::Result> { + // We allow writing to stderr even with isolation enabled. Ok(Write::write(self, bytes)) } - fn seek(&mut self, _offset: SeekFrom) -> InterpResult<'tcx, io::Result> { + fn seek(&mut self, _communicate_allowed: bool, _offset: SeekFrom) -> InterpResult<'tcx, io::Result> { throw_unsup_format!("cannot seek on stderr"); } } @@ -553,7 +562,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, i64> { let this = self.eval_context_mut(); - this.check_no_isolation("read")?; + // Isolation check is done via `FileDescriptor` trait. trace!("Reading from FD {}, size {}", fd, count); @@ -577,7 +586,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // `File::read` never returns a value larger than `count`, // so this cannot fail. let result = file_descriptor - .read(&mut bytes)? + .read(this.machine.communicate, &mut bytes)? .map(|c| i64::try_from(c).unwrap()); match result { @@ -605,9 +614,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, i64> { let this = self.eval_context_mut(); - if fd >= 3 { - this.check_no_isolation("write")?; - } + // Isolation check is done via `FileDescriptor` trait. // Check that the *entire* buffer is actually valid memory. this.memory.check_ptr_access( @@ -623,7 +630,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if let Some(file_descriptor) = this.machine.file_handler.handles.get_mut(&fd) { let bytes = this.memory.read_bytes(buf, Size::from_bytes(count))?; let result = file_descriptor - .write(&bytes)? + .write(this.machine.communicate, &bytes)? .map(|c| i64::try_from(c).unwrap()); this.try_unwrap_io_result(result) } else { @@ -639,7 +646,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, i64> { let this = self.eval_context_mut(); - this.check_no_isolation("lseek64")?; + // Isolation check is done via `FileDescriptor` trait. let fd = this.read_scalar(fd_op)?.to_i32()?; let offset = this.read_scalar(offset_op)?.to_i64()?; @@ -659,7 +666,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if let Some(file_descriptor) = this.machine.file_handler.handles.get_mut(&fd) { let result = file_descriptor - .seek(seek_from)? + .seek(this.machine.communicate, seek_from)? .map(|offset| i64::try_from(offset).unwrap()); this.try_unwrap_io_result(result) } else { diff --git a/tests/compile-fail/fs/isolated_stdin.rs b/tests/compile-fail/fs/isolated_stdin.rs new file mode 100644 index 0000000000000..6c467a2d1f141 --- /dev/null +++ b/tests/compile-fail/fs/isolated_stdin.rs @@ -0,0 +1,13 @@ +// ignore-windows: No libc on Windows + +#![feature(rustc_private)] + +extern crate libc; + +fn main() -> std::io::Result<()> { + let mut bytes = [0u8; 512]; + unsafe { + libc::read(0, bytes.as_mut_ptr() as *mut libc::c_void, 512); //~ ERROR `read` not available when isolation is enabled + } + Ok(()) +} From 5ea5e9fc2c0848d1d670f02644ea953e0800a123 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 10 Aug 2020 09:02:45 +0200 Subject: [PATCH 2221/3747] accept ReferencedConstant errors in Miri (can happen post-monomorphization) --- src/diagnostics.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/diagnostics.rs b/src/diagnostics.rs index a20e8126c13ae..ca3dd4dd66f23 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -88,6 +88,8 @@ pub fn report_error<'tcx, 'mir>( "Undefined Behavior", ResourceExhaustion(_) => "resource exhaustion", + InvalidProgram(InvalidProgramInfo::ReferencedConstant) => + "post-monomorphization error", _ => bug!("This error should be impossible in Miri: {}", e), }; From da2260db441503ba9d93b55db3ca49710eff23b2 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 10 Aug 2020 10:10:08 +0200 Subject: [PATCH 2222/3747] make sure opening a file fails with isolation enabled --- tests/compile-fail/fs/isolated_file.rs | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 tests/compile-fail/fs/isolated_file.rs diff --git a/tests/compile-fail/fs/isolated_file.rs b/tests/compile-fail/fs/isolated_file.rs new file mode 100644 index 0000000000000..5b7270f18931c --- /dev/null +++ b/tests/compile-fail/fs/isolated_file.rs @@ -0,0 +1,6 @@ +// ignore-windows: File handling is not implemented yet +// error-pattern: `open` not available when isolation is enabled + +fn main() { + let _file = std::fs::File::open("file.txt").unwrap(); +} From 94f13efefda1f891905913d088869bc1589a45c9 Mon Sep 17 00:00:00 2001 From: Oliver Scherer Date: Tue, 11 Aug 2020 11:37:29 +0200 Subject: [PATCH 2223/3747] Bump for rustc changes --- src/thread.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/thread.rs b/src/thread.rs index 1e710a25edc99..cffbec93c5cab 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -530,7 +530,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if tcx.is_foreign_item(def_id) { throw_unsup_format!("foreign thread-local statics are not supported"); } - let allocation = interpret::get_static(*tcx, def_id)?; + let allocation = tcx.eval_static_initializer(def_id)?; // Create a fresh allocation with this content. let new_alloc_id = this.memory.allocate_with(allocation.clone(), MiriMemoryKind::Tls.into()).alloc_id; this.machine.threads.set_thread_local_alloc_id(def_id, new_alloc_id); From 2f68a1f5b53acbd263f224666ff524be5e0e2c24 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 12 Aug 2020 09:19:40 +0200 Subject: [PATCH 2224/3747] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 75cd757fcc4c5..c8fd55f4c3b2c 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -c92fc8db8b009b7661cff31fa59a7c0348653bd0 +c94ed5ca91f1363b66970ce2cbd6e2773e3cb1d3 From 80929e17ae4806a1d2fb5cf282f430c5e34f7796 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 10 Aug 2020 09:04:37 +0200 Subject: [PATCH 2225/3747] add test for unused ill-formed constant also use better span in TopFrameInfo --- src/diagnostics.rs | 2 +- tests/compile-fail/erroneous_const.rs | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) create mode 100644 tests/compile-fail/erroneous_const.rs diff --git a/src/diagnostics.rs b/src/diagnostics.rs index ca3dd4dd66f23..eed60c2696e12 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -227,7 +227,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx TopFrameInfo { stack_size: this.active_thread_stack().len(), instance: Some(frame.instance), - span: frame.current_source_info().map_or(DUMMY_SP, |si| si.span), + span: frame.current_span(), } } diff --git a/tests/compile-fail/erroneous_const.rs b/tests/compile-fail/erroneous_const.rs new file mode 100644 index 0000000000000..287e073581416 --- /dev/null +++ b/tests/compile-fail/erroneous_const.rs @@ -0,0 +1,19 @@ +//! Make sure we detect erroneous constants post-monomorphization even when they are unused. +//! (https://github.com/rust-lang/miri/issues/1382) +#![feature(const_panic)] +#![feature(never_type)] +#![warn(warnings, const_err)] + +struct PrintName(T); +impl PrintName { + const VOID: ! = panic!(); //~WARN any use of this value will cause an error +} + +fn no_codegen() { + if false { + let _ = PrintName::::VOID; //~ERROR referenced constant has errors + } +} +fn main() { + no_codegen::(); +} From 925d60760eb953af3ffd288fa5a8e9546f60311e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 13 Aug 2020 08:43:28 +0200 Subject: [PATCH 2226/3747] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index c8fd55f4c3b2c..198b3970e0d16 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -c94ed5ca91f1363b66970ce2cbd6e2773e3cb1d3 +814bc4fe9364865bfaa94d7825b8eabc11245c7c From 46852d736e896ed9328308115dc06d8fbf84a3ac Mon Sep 17 00:00:00 2001 From: Samrat Man Singh Date: Thu, 13 Aug 2020 15:01:52 +0530 Subject: [PATCH 2227/3747] Remove lifetime from FileDescriptor trait Also: - Remove type annotate `handles` declaration instead of every insert. - Add note about flush being unnecessary when writing to stderr --- src/machine.rs | 2 +- src/shims/posix/fs.rs | 67 ++++++++++++++++++++++--------------------- 2 files changed, 35 insertions(+), 34 deletions(-) diff --git a/src/machine.rs b/src/machine.rs index 9e22825ccac4b..04bba6c33cdb6 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -249,7 +249,7 @@ pub struct Evaluator<'mir, 'tcx> { /// Whether to enforce the validity invariant. pub(crate) validate: bool, - pub(crate) file_handler: shims::posix::FileHandler<'tcx>, + pub(crate) file_handler: shims::posix::FileHandler, pub(crate) dir_handler: shims::posix::DirHandler, /// The temporary used for storing the argument of diff --git a/src/shims/posix/fs.rs b/src/shims/posix/fs.rs index cf050b7086945..5f31a6375cb7e 100644 --- a/src/shims/posix/fs.rs +++ b/src/shims/posix/fs.rs @@ -22,41 +22,41 @@ struct FileHandle { writable: bool, } -trait FileDescriptor<'tcx> : std::fmt::Debug { - fn as_file_handle(&self) -> InterpResult<'tcx, &FileHandle>; +trait FileDescriptor : std::fmt::Debug { + fn as_file_handle<'tcx>(&self) -> InterpResult<'tcx, &FileHandle>; - fn read(&mut self, communicate_allowed: bool, bytes: &mut [u8]) -> InterpResult<'tcx, io::Result>; - fn write(&mut self, communicate_allowed: bool, bytes: &[u8]) -> InterpResult<'tcx, io::Result>; - fn seek(&mut self, communicate_allowed: bool, offset: SeekFrom) -> InterpResult<'tcx, io::Result>; + fn read<'tcx>(&mut self, communicate_allowed: bool, bytes: &mut [u8]) -> InterpResult<'tcx, io::Result>; + fn write<'tcx>(&mut self, communicate_allowed: bool, bytes: &[u8]) -> InterpResult<'tcx, io::Result>; + fn seek<'tcx>(&mut self, communicate_allowed: bool, offset: SeekFrom) -> InterpResult<'tcx, io::Result>; } -impl<'tcx> FileDescriptor<'tcx> for FileHandle { - fn as_file_handle(&self) -> InterpResult<'tcx, &FileHandle> { +impl FileDescriptor for FileHandle { + fn as_file_handle<'tcx>(&self) -> InterpResult<'tcx, &FileHandle> { Ok(&self) } - fn read(&mut self, communicate_allowed: bool, bytes: &mut [u8]) -> InterpResult<'tcx, io::Result> { + fn read<'tcx>(&mut self, communicate_allowed: bool, bytes: &mut [u8]) -> InterpResult<'tcx, io::Result> { assert!(communicate_allowed, "isolation should have prevented even opening a file"); Ok(self.file.read(bytes)) } - fn write(&mut self, communicate_allowed: bool, bytes: &[u8]) -> InterpResult<'tcx, io::Result> { + fn write<'tcx>(&mut self, communicate_allowed: bool, bytes: &[u8]) -> InterpResult<'tcx, io::Result> { assert!(communicate_allowed, "isolation should have prevented even opening a file"); Ok(self.file.write(bytes)) } - fn seek(&mut self, communicate_allowed: bool, offset: SeekFrom) -> InterpResult<'tcx, io::Result> { + fn seek<'tcx>(&mut self, communicate_allowed: bool, offset: SeekFrom) -> InterpResult<'tcx, io::Result> { assert!(communicate_allowed, "isolation should have prevented even opening a file"); Ok(self.file.seek(offset)) } } -impl<'tcx> FileDescriptor<'tcx> for io::Stdin { - fn as_file_handle(&self) -> InterpResult<'tcx, &FileHandle> { +impl FileDescriptor for io::Stdin { + fn as_file_handle<'tcx>(&self) -> InterpResult<'tcx, &FileHandle> { throw_unsup_format!("stdin cannot be used as FileHandle"); } - fn read(&mut self, communicate_allowed: bool, bytes: &mut [u8]) -> InterpResult<'tcx, io::Result> { + fn read<'tcx>(&mut self, communicate_allowed: bool, bytes: &mut [u8]) -> InterpResult<'tcx, io::Result> { if !communicate_allowed { // We want isolation mode to be deterministic, so we have to disallow all reads, even stdin. helpers::isolation_error("read")?; @@ -64,25 +64,25 @@ impl<'tcx> FileDescriptor<'tcx> for io::Stdin { Ok(Read::read(self, bytes)) } - fn write(&mut self, _communicate_allowed: bool, _bytes: &[u8]) -> InterpResult<'tcx, io::Result> { + fn write<'tcx>(&mut self, _communicate_allowed: bool, _bytes: &[u8]) -> InterpResult<'tcx, io::Result> { throw_unsup_format!("cannot write to stdin"); } - fn seek(&mut self, _communicate_allowed: bool, _offset: SeekFrom) -> InterpResult<'tcx, io::Result> { + fn seek<'tcx>(&mut self, _communicate_allowed: bool, _offset: SeekFrom) -> InterpResult<'tcx, io::Result> { throw_unsup_format!("cannot seek on stdin"); } } -impl<'tcx> FileDescriptor<'tcx> for io::Stdout { - fn as_file_handle(&self) -> InterpResult<'tcx, &FileHandle> { +impl FileDescriptor for io::Stdout { + fn as_file_handle<'tcx>(&self) -> InterpResult<'tcx, &FileHandle> { throw_unsup_format!("stdout cannot be used as FileHandle"); } - fn read(&mut self, _communicate_allowed: bool, _bytes: &mut [u8]) -> InterpResult<'tcx, io::Result> { + fn read<'tcx>(&mut self, _communicate_allowed: bool, _bytes: &mut [u8]) -> InterpResult<'tcx, io::Result> { throw_unsup_format!("cannot read from stdout"); } - fn write(&mut self, _communicate_allowed: bool, bytes: &[u8]) -> InterpResult<'tcx, io::Result> { + fn write<'tcx>(&mut self, _communicate_allowed: bool, bytes: &[u8]) -> InterpResult<'tcx, io::Result> { // We allow writing to stderr even with isolation enabled. let result = Write::write(self, bytes); // Stdout is buffered, flush to make sure it appears on the @@ -95,41 +95,42 @@ impl<'tcx> FileDescriptor<'tcx> for io::Stdout { Ok(result) } - fn seek(&mut self, _communicate_allowed: bool, _offset: SeekFrom) -> InterpResult<'tcx, io::Result> { + fn seek<'tcx>(&mut self, _communicate_allowed: bool, _offset: SeekFrom) -> InterpResult<'tcx, io::Result> { throw_unsup_format!("cannot seek on stdout"); } } -impl<'tcx> FileDescriptor<'tcx> for io::Stderr { - fn as_file_handle(&self) -> InterpResult<'tcx, &FileHandle> { +impl FileDescriptor for io::Stderr { + fn as_file_handle<'tcx>(&self) -> InterpResult<'tcx, &FileHandle> { throw_unsup_format!("stdout cannot be used as FileHandle"); } - fn read(&mut self, _communicate_allowed: bool, _bytes: &mut [u8]) -> InterpResult<'tcx, io::Result> { + fn read<'tcx>(&mut self, _communicate_allowed: bool, _bytes: &mut [u8]) -> InterpResult<'tcx, io::Result> { throw_unsup_format!("cannot read from stderr"); } - fn write(&mut self, _communicate_allowed: bool, bytes: &[u8]) -> InterpResult<'tcx, io::Result> { + fn write<'tcx>(&mut self, _communicate_allowed: bool, bytes: &[u8]) -> InterpResult<'tcx, io::Result> { // We allow writing to stderr even with isolation enabled. + // No need to flush, stderr is not buffered. Ok(Write::write(self, bytes)) } - fn seek(&mut self, _communicate_allowed: bool, _offset: SeekFrom) -> InterpResult<'tcx, io::Result> { + fn seek<'tcx>(&mut self, _communicate_allowed: bool, _offset: SeekFrom) -> InterpResult<'tcx, io::Result> { throw_unsup_format!("cannot seek on stderr"); } } #[derive(Debug)] -pub struct FileHandler<'tcx> { - handles: BTreeMap>>, +pub struct FileHandler { + handles: BTreeMap>, } -impl<'tcx> Default for FileHandler<'tcx> { +impl<'tcx> Default for FileHandler { fn default() -> Self { - let mut handles = BTreeMap::new(); - handles.insert(0i32, Box::new(io::stdin()) as Box>); - handles.insert(1i32, Box::new(io::stdout()) as Box>); - handles.insert(2i32, Box::new(io::stderr()) as Box>); + let mut handles : BTreeMap<_, Box> = BTreeMap::new(); + handles.insert(0i32, Box::new(io::stdin())); + handles.insert(1i32, Box::new(io::stdout())); + handles.insert(2i32, Box::new(io::stderr())); FileHandler { handles } @@ -140,7 +141,7 @@ impl<'tcx> Default for FileHandler<'tcx> { // fd numbers 0, 1, and 2 are reserved for stdin, stdout, and stderr const MIN_NORMAL_FILE_FD: i32 = 3; -impl<'tcx> FileHandler<'tcx> { +impl<'tcx> FileHandler { fn insert_fd(&mut self, file_handle: FileHandle) -> i32 { self.insert_fd_with_min_fd(file_handle, 0) } From 0c2506411700591f218c03dca19b47388bd80f60 Mon Sep 17 00:00:00 2001 From: Samrat Man Singh Date: Thu, 13 Aug 2020 16:18:08 +0530 Subject: [PATCH 2228/3747] Remove unnecessary whitespace Co-authored-by: Ralf Jung --- src/shims/posix/fs.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shims/posix/fs.rs b/src/shims/posix/fs.rs index 5f31a6375cb7e..06a8bf1cb0206 100644 --- a/src/shims/posix/fs.rs +++ b/src/shims/posix/fs.rs @@ -127,7 +127,7 @@ pub struct FileHandler { impl<'tcx> Default for FileHandler { fn default() -> Self { - let mut handles : BTreeMap<_, Box> = BTreeMap::new(); + let mut handles: BTreeMap<_, Box> = BTreeMap::new(); handles.insert(0i32, Box::new(io::stdin())); handles.insert(1i32, Box::new(io::stdout())); handles.insert(2i32, Box::new(io::stderr())); From df311293e2a4a413020840494cc310a3d1d1541f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 13 Aug 2020 14:00:10 +0200 Subject: [PATCH 2229/3747] fix Stderr::as_file_handle error message --- src/shims/posix/fs.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shims/posix/fs.rs b/src/shims/posix/fs.rs index 06a8bf1cb0206..b4719c25baee4 100644 --- a/src/shims/posix/fs.rs +++ b/src/shims/posix/fs.rs @@ -102,7 +102,7 @@ impl FileDescriptor for io::Stdout { impl FileDescriptor for io::Stderr { fn as_file_handle<'tcx>(&self) -> InterpResult<'tcx, &FileHandle> { - throw_unsup_format!("stdout cannot be used as FileHandle"); + throw_unsup_format!("stderr cannot be used as FileHandle"); } fn read<'tcx>(&mut self, _communicate_allowed: bool, _bytes: &mut [u8]) -> InterpResult<'tcx, io::Result> { From cb985670c1997534a0cd1cfee606e81e4fa136dc Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 16 Aug 2020 17:08:34 +0200 Subject: [PATCH 2230/3747] make alignment check integer-based by default, and add an option to make it symbolic --- src/bin/miri.rs | 54 ++++++------------- src/eval.rs | 16 ++++-- src/lib.rs | 2 +- src/machine.rs | 11 ++-- .../unaligned_pointers/atomic_unaligned.rs | 1 + .../unaligned_pointers/dyn_alignment.rs | 4 +- .../intptrcast_alignment_check.rs | 10 ++-- .../unaligned_pointers/reference_to_packed.rs | 2 +- .../unaligned_pointers/unaligned_ptr_zst.rs | 4 +- tests/run-pass/align.rs | 11 ++++ 10 files changed, 62 insertions(+), 53 deletions(-) create mode 100644 tests/run-pass/align.rs diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 73e52af4ec51d..134702047522d 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -172,48 +172,41 @@ fn main() { init_early_loggers(); // Parse our arguments and split them across `rustc` and `miri`. - let mut validate = true; - let mut stacked_borrows = true; - let mut check_alignment = true; - let mut communicate = false; - let mut ignore_leaks = false; - let mut seed: Option = None; - let mut tracked_pointer_tag: Option = None; - let mut tracked_call_id: Option = None; - let mut tracked_alloc_id: Option = None; + let mut miri_config = miri::MiriConfig::default(); let mut rustc_args = vec![]; - let mut crate_args = vec![]; let mut after_dashdash = false; - let mut excluded_env_vars = vec![]; for arg in env::args() { if rustc_args.is_empty() { // Very first arg: binary name. rustc_args.push(arg); } else if after_dashdash { // Everything that comes after `--` is forwarded to the interpreted crate. - crate_args.push(arg); + miri_config.args.push(arg); } else { match arg.as_str() { "-Zmiri-disable-validation" => { - validate = false; + miri_config.validate = false; } "-Zmiri-disable-stacked-borrows" => { - stacked_borrows = false; + miri_config.stacked_borrows = false; } "-Zmiri-disable-alignment-check" => { - check_alignment = false; + miri_config.check_alignment = miri::AlignmentCheck::None; + } + "-Zmiri-symbolic-alignment-check" => { + miri_config.check_alignment = miri::AlignmentCheck::Symbolic; } "-Zmiri-disable-isolation" => { - communicate = true; + miri_config.communicate = true; } "-Zmiri-ignore-leaks" => { - ignore_leaks = true; + miri_config.ignore_leaks = true; } "--" => { after_dashdash = true; } arg if arg.starts_with("-Zmiri-seed=") => { - if seed.is_some() { + if miri_config.seed.is_some() { panic!("Cannot specify -Zmiri-seed multiple times!"); } let seed_raw = hex::decode(arg.strip_prefix("-Zmiri-seed=").unwrap()) @@ -234,10 +227,10 @@ fn main() { let mut bytes = [0; 8]; bytes[..seed_raw.len()].copy_from_slice(&seed_raw); - seed = Some(u64::from_be_bytes(bytes)); + miri_config.seed = Some(u64::from_be_bytes(bytes)); } arg if arg.starts_with("-Zmiri-env-exclude=") => { - excluded_env_vars + miri_config.excluded_env_vars .push(arg.strip_prefix("-Zmiri-env-exclude=").unwrap().to_owned()); } arg if arg.starts_with("-Zmiri-track-pointer-tag=") => { @@ -249,7 +242,7 @@ fn main() { ), }; if let Some(id) = miri::PtrId::new(id) { - tracked_pointer_tag = Some(id); + miri_config.tracked_pointer_tag = Some(id); } else { panic!("-Zmiri-track-pointer-tag requires a nonzero argument"); } @@ -263,7 +256,7 @@ fn main() { ), }; if let Some(id) = miri::CallId::new(id) { - tracked_call_id = Some(id); + miri_config.tracked_call_id = Some(id); } else { panic!("-Zmiri-track-call-id requires a nonzero argument"); } @@ -276,7 +269,7 @@ fn main() { err ), }; - tracked_alloc_id = Some(miri::AllocId(id)); + miri_config.tracked_alloc_id = Some(miri::AllocId(id)); } _ => { // Forward to rustc. @@ -287,19 +280,6 @@ fn main() { } debug!("rustc arguments: {:?}", rustc_args); - debug!("crate arguments: {:?}", crate_args); - let miri_config = miri::MiriConfig { - validate, - stacked_borrows, - check_alignment, - communicate, - ignore_leaks, - excluded_env_vars, - seed, - args: crate_args, - tracked_pointer_tag, - tracked_call_id, - tracked_alloc_id, - }; + debug!("crate arguments: {:?}", miri_config.args); run_compiler(rustc_args, &mut MiriCompilerCalls { miri_config }) } diff --git a/src/eval.rs b/src/eval.rs index cc5a6eb21faba..8e4604c3360a6 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -13,6 +13,16 @@ use rustc_target::abi::LayoutOf; use crate::*; +#[derive(Copy, Clone, Debug, PartialEq)] +pub enum AlignmentCheck { + /// Do not check alignment. + None, + /// Check alignment "symbolically", i.e., using only the requested alignment for an allocation and not its real base address. + Symbolic, + /// Check alignment on the actual physical integer address. + Int, +} + /// Configuration needed to spawn a Miri instance. #[derive(Clone)] pub struct MiriConfig { @@ -20,8 +30,8 @@ pub struct MiriConfig { pub validate: bool, /// Determines if Stacked Borrows is enabled. pub stacked_borrows: bool, - /// Determines if alignment checking is enabled. - pub check_alignment: bool, + /// Controls alignment checking. + pub check_alignment: AlignmentCheck, /// Determines if communication with the host environment is enabled. pub communicate: bool, /// Determines if memory leaks should be ignored. @@ -45,7 +55,7 @@ impl Default for MiriConfig { MiriConfig { validate: true, stacked_borrows: true, - check_alignment: true, + check_alignment: AlignmentCheck::Int, communicate: false, ignore_leaks: false, excluded_env_vars: vec![], diff --git a/src/lib.rs b/src/lib.rs index 816917081a8ce..1b66d5ff6f31d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -55,7 +55,7 @@ pub use crate::diagnostics::{ register_diagnostic, report_error, EvalContextExt as DiagnosticsEvalContextExt, TerminationInfo, NonHaltingDiagnostic, }; -pub use crate::eval::{create_ecx, eval_main, MiriConfig}; +pub use crate::eval::{create_ecx, eval_main, AlignmentCheck, MiriConfig}; pub use crate::helpers::EvalContextExt as HelpersEvalContextExt; pub use crate::machine::{ AllocExtra, Evaluator, FrameData, MemoryExtra, MiriEvalContext, MiriEvalContextExt, diff --git a/src/machine.rs b/src/machine.rs index 04bba6c33cdb6..f2abb2ae0e7e6 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -128,7 +128,7 @@ pub struct MemoryExtra { tracked_alloc_id: Option, /// Controls whether alignment of memory accesses is being checked. - check_alignment: bool, + check_alignment: AlignmentCheck, } impl MemoryExtra { @@ -138,7 +138,7 @@ impl MemoryExtra { tracked_pointer_tag: Option, tracked_call_id: Option, tracked_alloc_id: Option, - check_alignment: bool, + check_alignment: AlignmentCheck, ) -> Self { let stacked_borrows = if stacked_borrows { Some(Rc::new(RefCell::new(stacked_borrows::GlobalState::new(tracked_pointer_tag, tracked_call_id)))) @@ -336,7 +336,12 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { #[inline(always)] fn enforce_alignment(memory_extra: &MemoryExtra) -> bool { - memory_extra.check_alignment + memory_extra.check_alignment != AlignmentCheck::None + } + + #[inline(always)] + fn force_int_for_alignment_check(memory_extra: &Self::MemoryExtra) -> bool { + memory_extra.check_alignment == AlignmentCheck::Int } #[inline(always)] diff --git a/tests/compile-fail/unaligned_pointers/atomic_unaligned.rs b/tests/compile-fail/unaligned_pointers/atomic_unaligned.rs index bdec0ff504bb6..77eff5087dac5 100644 --- a/tests/compile-fail/unaligned_pointers/atomic_unaligned.rs +++ b/tests/compile-fail/unaligned_pointers/atomic_unaligned.rs @@ -1,3 +1,4 @@ +// compile-flags: -Zmiri-symbolic-alignment-check #![feature(core_intrinsics)] fn main() { diff --git a/tests/compile-fail/unaligned_pointers/dyn_alignment.rs b/tests/compile-fail/unaligned_pointers/dyn_alignment.rs index aa293a5d2167b..a40db99a72a6c 100644 --- a/tests/compile-fail/unaligned_pointers/dyn_alignment.rs +++ b/tests/compile-fail/unaligned_pointers/dyn_alignment.rs @@ -1,4 +1,4 @@ -// should find the bug even without these, but gets masked by optimizations +// should find the bug even without validation and stacked borrows, but gets masked by optimizations // compile-flags: -Zmiri-disable-validation -Zmiri-disable-stacked-borrows -Zmir-opt-level=0 #[repr(align(256))] @@ -15,5 +15,5 @@ fn main() { // Overwrite the data part of `ptr` so it points to `buf`. unsafe { (&mut ptr as *mut _ as *mut *const u8).write(&buf as *const _ as *const u8); } // Re-borrow that. This should be UB. - let _ptr = &*ptr; //~ ERROR accessing memory with alignment 4, but alignment 256 is required + let _ptr = &*ptr; //~ ERROR alignment 256 is required } diff --git a/tests/compile-fail/unaligned_pointers/intptrcast_alignment_check.rs b/tests/compile-fail/unaligned_pointers/intptrcast_alignment_check.rs index 0a3b48dab5a0c..3865d45786374 100644 --- a/tests/compile-fail/unaligned_pointers/intptrcast_alignment_check.rs +++ b/tests/compile-fail/unaligned_pointers/intptrcast_alignment_check.rs @@ -1,7 +1,9 @@ -// Even with intptrcast and without validation, we want to be *sure* to catch bugs -// that arise from pointers being insufficiently aligned. The only way to achieve -// that is not not let programs exploit integer information for alignment, so here -// we test that this is indeed the case. +// compile-flags: -Zmiri-symbolic-alignment-check +// With the symbolic alignment check, even with intptrcast and without +// validation, we want to be *sure* to catch bugs that arise from pointers being +// insufficiently aligned. The only way to achieve that is not not let programs +// exploit integer information for alignment, so here we test that this is +// indeed the case. // // See https://github.com/rust-lang/miri/issues/1074. fn main() { diff --git a/tests/compile-fail/unaligned_pointers/reference_to_packed.rs b/tests/compile-fail/unaligned_pointers/reference_to_packed.rs index 08104e917d212..a1240c90182aa 100644 --- a/tests/compile-fail/unaligned_pointers/reference_to_packed.rs +++ b/tests/compile-fail/unaligned_pointers/reference_to_packed.rs @@ -15,5 +15,5 @@ fn main() { y: 99, }; let p = unsafe { &foo.x }; - let i = *p; //~ ERROR memory with alignment 1, but alignment 4 is required + let i = *p; //~ ERROR alignment 4 is required } diff --git a/tests/compile-fail/unaligned_pointers/unaligned_ptr_zst.rs b/tests/compile-fail/unaligned_pointers/unaligned_ptr_zst.rs index 31f88c838149e..beba47359b551 100644 --- a/tests/compile-fail/unaligned_pointers/unaligned_ptr_zst.rs +++ b/tests/compile-fail/unaligned_pointers/unaligned_ptr_zst.rs @@ -2,9 +2,9 @@ // compile-flags: -Zmiri-disable-validation fn main() { - let x = &2u16; + let x = &2u8; let x = x as *const _ as *const [u32; 0]; // This must fail because alignment is violated. Test specifically for loading ZST. let _x = unsafe { *x }; - //~^ ERROR memory with alignment 2, but alignment 4 is required + //~^ ERROR alignment 4 is required } diff --git a/tests/run-pass/align.rs b/tests/run-pass/align.rs new file mode 100644 index 0000000000000..b3d268f45e4bb --- /dev/null +++ b/tests/run-pass/align.rs @@ -0,0 +1,11 @@ +// This manually makes sure that we have a pointer with the proper alignment. +// Do this a couple times in a loop because it may work "by chance". +fn main() { + for _ in 0..10 { + let x = &mut [0u8; 3]; + let base_addr = x as *mut _ as usize; + let base_addr_aligned = if base_addr % 2 == 0 { base_addr } else { base_addr+1 }; + let u16_ptr = base_addr_aligned as *mut u16; + unsafe { *u16_ptr = 2; } + } +} From 5a579f281d913d7d838413564272fafc23c6c336 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 16 Aug 2020 17:12:32 +0200 Subject: [PATCH 2231/3747] document -Zmiri-symbolic-alignment-check --- README.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/README.md b/README.md index f97639ea5bdfd..a189fd233f588 100644 --- a/README.md +++ b/README.md @@ -189,6 +189,17 @@ Miri adds its own set of `-Z` flags: entropy. The default seed is 0. **NOTE**: This entropy is not good enough for cryptographic use! Do not generate secret keys in Miri or perform other kinds of cryptographic operations that rely on proper random numbers. +* `-Zmiri-symbolic-alignment-check` makes the alignment check more strict. By + default, alignment is checked by casting the pointer to an integer, and making + sure that is a multiple of the alignment. This can lead to cases where a + program passes the alignment check by pure chance, because things "happened to + be" sufficiently aligned. To avoid such cases, the symbolic alignment check + only takes into account the requested alignment of the relevant allocation, + and the offset into that allocation. This avoids such false negatives, but it + also incurs some false positives when the code does manual integer arithmetic + to ensure alignment. (The standard library `align_to` method works fine in + both modes; under symbolic alignment it only fills the middle slice when the + allocation guarantees sufficient alignment.) * `-Zmiri-track-alloc-id=` shows a backtrace when the given allocation is being allocated or freed. This helps in debugging memory leaks and use after free bugs. From 664706662ff1221e88e70dd5c6ceef391e2528a6 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 16 Aug 2020 17:16:53 +0200 Subject: [PATCH 2232/3747] adjust diagnostics to alignment check mode --- src/diagnostics.rs | 7 ++++--- src/machine.rs | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/diagnostics.rs b/src/diagnostics.rs index eed60c2696e12..81cd049217227 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -100,11 +100,12 @@ pub fn report_error<'tcx, 'mir>( panic!("Error should never be raised by Miri: {:?}", e.kind), Unsupported(_) => vec![format!("this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support")], - UndefinedBehavior(UndefinedBehaviorInfo::AlignmentCheckFailed { .. }) => + UndefinedBehavior(UndefinedBehaviorInfo::AlignmentCheckFailed { .. }) + if ecx.memory.extra.check_alignment == AlignmentCheck::Symbolic + => vec![ format!("this usually indicates that your program performed an invalid operation and caused Undefined Behavior"), - format!("but alignment errors can also be false positives, see https://github.com/rust-lang/miri/issues/1074"), - format!("you can disable the alignment check with `-Zmiri-disable-alignment-check`, but that could hide true bugs") + format!("but due to `-Zmiri-symbolic-alignment-check`, alignment errors can also be false positives"), ], UndefinedBehavior(_) => vec![ diff --git a/src/machine.rs b/src/machine.rs index f2abb2ae0e7e6..b76159694d822 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -128,7 +128,7 @@ pub struct MemoryExtra { tracked_alloc_id: Option, /// Controls whether alignment of memory accesses is being checked. - check_alignment: AlignmentCheck, + pub(crate) check_alignment: AlignmentCheck, } impl MemoryExtra { From d4e5943259de7573556711ed6496c409dd754ea3 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 16 Aug 2020 18:16:34 +0200 Subject: [PATCH 2233/3747] use real align_offset unless we symbolic alignment check is enabled --- src/shims/mod.rs | 35 ++++++++++--------- tests/run-pass/align.rs | 28 +++++++++++---- ...ign_offset.rs => align_offset_symbolic.rs} | 2 ++ ...et.stdout => align_offset_symbolic.stdout} | 0 4 files changed, 41 insertions(+), 24 deletions(-) rename tests/run-pass/{align_offset.rs => align_offset_symbolic.rs} (98%) rename tests/run-pass/{align_offset.stdout => align_offset_symbolic.stdout} (100%) diff --git a/src/shims/mod.rs b/src/shims/mod.rs index 05dd4059eb1bc..eab27496cb286 100644 --- a/src/shims/mod.rs +++ b/src/shims/mod.rs @@ -13,8 +13,6 @@ pub mod tls; // End module management, begin local code -use std::convert::TryFrom; - use log::trace; use rustc_middle::{mir, ty}; @@ -37,8 +35,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // There are some more lang items we want to hook that CTFE does not hook (yet). if this.tcx.lang_items().align_offset_fn() == Some(instance.def.def_id()) { let &[ptr, align] = check_arg_count(args)?; - this.align_offset(ptr, align, ret, unwind)?; - return Ok(None); + if this.align_offset(ptr, align, ret, unwind)? { + return Ok(None); + } } // Try to see if we can do something about foreign items. @@ -56,46 +55,48 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(Some(&*this.load_mir(instance.def, None)?)) } + /// Returns `true` if the computation was performed, and `false` if we should just evaluate + /// the actual MIR of `align_offset`. fn align_offset( &mut self, ptr_op: OpTy<'tcx, Tag>, align_op: OpTy<'tcx, Tag>, ret: Option<(PlaceTy<'tcx, Tag>, mir::BasicBlock)>, unwind: Option, - ) -> InterpResult<'tcx> { + ) -> InterpResult<'tcx, bool> { let this = self.eval_context_mut(); let (dest, ret) = ret.unwrap(); + if this.memory.extra.check_alignment != AlignmentCheck::Symbolic { + // Just use actual implementation. + return Ok(false); + } + let req_align = this .force_bits(this.read_scalar(align_op)?.check_init()?, this.pointer_size())?; // Stop if the alignment is not a power of two. if !req_align.is_power_of_two() { - return this.start_panic("align_offset: align is not a power-of-two", unwind); + this.start_panic("align_offset: align is not a power-of-two", unwind)?; + return Ok(true); // nothing left to do } let ptr_scalar = this.read_scalar(ptr_op)?.check_init()?; - // Default: no result. - let mut result = this.machine_usize_max(); if let Ok(ptr) = this.force_ptr(ptr_scalar) { // Only do anything if we can identify the allocation this goes to. let cur_align = this.memory.get_size_and_align(ptr.alloc_id, AllocCheck::MaybeDead)?.1.bytes(); if u128::from(cur_align) >= req_align { // If the allocation alignment is at least the required alignment we use the - // libcore implementation. - // FIXME: is this correct in case of truncation? - result = u64::try_from( - (this.force_bits(ptr_scalar, this.pointer_size())? as *const i8) - .align_offset(usize::try_from(req_align).unwrap()) - ).unwrap(); + // real implementation. + return Ok(false); } } - // Return result, and jump to caller. - this.write_scalar(Scalar::from_machine_usize(result, this), dest)?; + // Return error result (usize::MAX), and jump to caller. + this.write_scalar(Scalar::from_machine_usize(this.machine_usize_max(), this), dest)?; this.go_to_block(ret); - Ok(()) + Ok(true) } } diff --git a/tests/run-pass/align.rs b/tests/run-pass/align.rs index b3d268f45e4bb..81e7e8c7ccac3 100644 --- a/tests/run-pass/align.rs +++ b/tests/run-pass/align.rs @@ -1,11 +1,25 @@ -// This manually makes sure that we have a pointer with the proper alignment. -// Do this a couple times in a loop because it may work "by chance". +/// This manually makes sure that we have a pointer with the proper alignment. +fn manual_alignment() { + let x = &mut [0u8; 3]; + let base_addr = x as *mut _ as usize; + let base_addr_aligned = if base_addr % 2 == 0 { base_addr } else { base_addr+1 }; + let u16_ptr = base_addr_aligned as *mut u16; + unsafe { *u16_ptr = 2; } +} + +/// Test standard library `align_to`. +fn align_to() { + const LEN: usize = 128; + let buf = &[0u8; LEN]; + let (l, m, r) = unsafe { buf.align_to::() }; + assert!(m.len()*4 >= LEN-4); + assert!(l.len() + r.len() <= 4); +} + fn main() { + // Do this a couple times in a loop because it may work "by chance". for _ in 0..10 { - let x = &mut [0u8; 3]; - let base_addr = x as *mut _ as usize; - let base_addr_aligned = if base_addr % 2 == 0 { base_addr } else { base_addr+1 }; - let u16_ptr = base_addr_aligned as *mut u16; - unsafe { *u16_ptr = 2; } + manual_alignment(); + align_to(); } } diff --git a/tests/run-pass/align_offset.rs b/tests/run-pass/align_offset_symbolic.rs similarity index 98% rename from tests/run-pass/align_offset.rs rename to tests/run-pass/align_offset_symbolic.rs index f921634647086..70b2e00896dc0 100644 --- a/tests/run-pass/align_offset.rs +++ b/tests/run-pass/align_offset_symbolic.rs @@ -1,3 +1,5 @@ +// compile-flags: -Zmiri-symbolic-alignment-check + fn test_align_offset() { let d = Box::new([0u32; 4]); // Get u8 pointer to base diff --git a/tests/run-pass/align_offset.stdout b/tests/run-pass/align_offset_symbolic.stdout similarity index 100% rename from tests/run-pass/align_offset.stdout rename to tests/run-pass/align_offset_symbolic.stdout From 0913653e065896cbbacf164c36673fec48f947d1 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 16 Aug 2020 18:31:48 +0200 Subject: [PATCH 2234/3747] make sure we test panic of interpreter-impelemted align_offset --- tests/run-pass/panic/catch_panic.rs | 5 ++++- tests/run-pass/panic/catch_panic.stderr | 24 ++++++++++++------------ 2 files changed, 16 insertions(+), 13 deletions(-) diff --git a/tests/run-pass/panic/catch_panic.rs b/tests/run-pass/panic/catch_panic.rs index 6dc47f2f591ac..3afff1d36d36e 100644 --- a/tests/run-pass/panic/catch_panic.rs +++ b/tests/run-pass/panic/catch_panic.rs @@ -1,4 +1,7 @@ // normalize-stderr-test "[^ ]*core/[a-z_/]+.rs[0-9:]*" -> "$$LOC" +// normalize-stderr-test "catch_panic\.rs:[0-9]{2}" -> "catch_panic.rs:LL" +// We test the `align_offset` panic below, make sure we test the interpreter impl and not the "real" one. +// compile-flags: -Zmiri-symbolic-alignment-check #![feature(never_type)] #![allow(unconditional_panic)] @@ -99,7 +102,7 @@ fn test(expect_msg: Option<&str>, do_panic: impl FnOnce(usize) -> !) { eprintln!("Caught panic message (&str): {}", s); Some(*s) } else { - eprintln!("Failed get caught panic message."); + eprintln!("Failed to get caught panic message."); None }; if let Some(expect_msg) = expect_msg { diff --git a/tests/run-pass/panic/catch_panic.stderr b/tests/run-pass/panic/catch_panic.stderr index f64ff1186619e..c31f54aac729a 100644 --- a/tests/run-pass/panic/catch_panic.stderr +++ b/tests/run-pass/panic/catch_panic.stderr @@ -1,26 +1,26 @@ -thread 'main' panicked at 'Hello from panic: std', $DIR/catch_panic.rs:50:27 +thread 'main' panicked at 'Hello from panic: std', $DIR/catch_panic.rs:LL:27 Caught panic message (&str): Hello from panic: std -thread 'main' panicked at 'Hello from panic: 1', $DIR/catch_panic.rs:51:26 +thread 'main' panicked at 'Hello from panic: 1', $DIR/catch_panic.rs:LL:26 Caught panic message (String): Hello from panic: 1 -thread 'main' panicked at 'Hello from panic: 2', $DIR/catch_panic.rs:52:26 +thread 'main' panicked at 'Hello from panic: 2', $DIR/catch_panic.rs:LL:26 Caught panic message (String): Hello from panic: 2 -thread 'main' panicked at 'Box', $DIR/catch_panic.rs:53:27 -Failed get caught panic message. -thread 'main' panicked at 'Hello from panic: core', $DIR/catch_panic.rs:56:27 +thread 'main' panicked at 'Box', $DIR/catch_panic.rs:LL:27 +Failed to get caught panic message. +thread 'main' panicked at 'Hello from panic: core', $DIR/catch_panic.rs:LL:27 Caught panic message (String): Hello from panic: core -thread 'main' panicked at 'Hello from panic: 5', $DIR/catch_panic.rs:57:26 +thread 'main' panicked at 'Hello from panic: 5', $DIR/catch_panic.rs:LL:26 Caught panic message (String): Hello from panic: 5 -thread 'main' panicked at 'Hello from panic: 6', $DIR/catch_panic.rs:58:26 +thread 'main' panicked at 'Hello from panic: 6', $DIR/catch_panic.rs:LL:26 Caught panic message (String): Hello from panic: 6 -thread 'main' panicked at 'index out of bounds: the len is 3 but the index is 4', $DIR/catch_panic.rs:63:33 +thread 'main' panicked at 'index out of bounds: the len is 3 but the index is 4', $DIR/catch_panic.rs:LL:33 Caught panic message (String): index out of bounds: the len is 3 but the index is 4 -thread 'main' panicked at 'attempt to divide by zero', $DIR/catch_panic.rs:67:33 +thread 'main' panicked at 'attempt to divide by zero', $DIR/catch_panic.rs:LL:33 Caught panic message (String): attempt to divide by zero thread 'main' panicked at 'align_offset: align is not a power-of-two', $LOC Caught panic message (String): align_offset: align is not a power-of-two -thread 'main' panicked at 'assertion failed: false', $DIR/catch_panic.rs:76:29 +thread 'main' panicked at 'assertion failed: false', $DIR/catch_panic.rs:LL:29 Caught panic message (&str): assertion failed: false -thread 'main' panicked at 'assertion failed: false', $DIR/catch_panic.rs:77:29 +thread 'main' panicked at 'assertion failed: false', $DIR/catch_panic.rs:LL:29 Caught panic message (&str): assertion failed: false thread 'main' panicked at 'called `Option::unwrap()` on a `None` value', $LOC Caught panic message (String): called `Option::unwrap()` on a `None` value From f691e573b242a046b9c411eb8e362b8a0715f07e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 17 Aug 2020 11:51:18 +0200 Subject: [PATCH 2235/3747] tweak alignment check docs --- README.md | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index a189fd233f588..37ed718a1a2b8 100644 --- a/README.md +++ b/README.md @@ -165,9 +165,8 @@ up the sysroot. If you are using `miri` (the Miri driver) directly, see the Miri adds its own set of `-Z` flags: -* `-Zmiri-disable-alignment-check` disables checking pointer alignment. This is - useful to avoid [false positives][alignment-false-positives]. However, setting - this flag means Miri could miss bugs in your program. +* `-Zmiri-disable-alignment-check` disables checking pointer alignment, so you + can focus on other failures. * `-Zmiri-disable-stacked-borrows` disables checking the experimental [Stacked Borrows] aliasing rules. This can make Miri run faster, but it also means no aliasing violations will be detected. @@ -193,12 +192,13 @@ Miri adds its own set of `-Z` flags: default, alignment is checked by casting the pointer to an integer, and making sure that is a multiple of the alignment. This can lead to cases where a program passes the alignment check by pure chance, because things "happened to - be" sufficiently aligned. To avoid such cases, the symbolic alignment check - only takes into account the requested alignment of the relevant allocation, - and the offset into that allocation. This avoids such false negatives, but it - also incurs some false positives when the code does manual integer arithmetic - to ensure alignment. (The standard library `align_to` method works fine in - both modes; under symbolic alignment it only fills the middle slice when the + be" sufficiently aligned -- there is no UB in this execution but there would + be UB in others. To avoid such cases, the symbolic alignment check only takes + into account the requested alignment of the relevant allocation, and the + offset into that allocation. This avoids missing such bugs, but it also + incurs some false positives when the code does manual integer arithmetic to + ensure alignment. (The standard library `align_to` method works fine in both + modes; under symbolic alignment it only fills the middle slice when the allocation guarantees sufficient alignment.) * `-Zmiri-track-alloc-id=` shows a backtrace when the given allocation is being allocated or freed. This helps in debugging memory leaks and @@ -211,8 +211,6 @@ Miri adds its own set of `-Z` flags: assigned to a stack frame. This helps in debugging UB related to Stacked Borrows "protectors". -[alignment-false-positives]: https://github.com/rust-lang/miri/issues/1074 - Some native rustc `-Z` flags are also very relevant for Miri: * `-Zmir-opt-level` controls how many MIR optimizations are performed. Miri From db159b8709dac1cb8adeac91c3257906e55319ec Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 17 Aug 2020 16:51:48 +0200 Subject: [PATCH 2236/3747] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 198b3970e0d16..e322ff61d1bda 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -814bc4fe9364865bfaa94d7825b8eabc11245c7c +8cdc94e84040ce797fd33d0a7cfda4ec4f2f2421 From 5b1bc4ba94cdbb403388cd7c5b45f5ecf4ccd922 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 17 Aug 2020 17:09:09 +0200 Subject: [PATCH 2237/3747] make another test more robust against random alignment --- tests/compile-fail/unaligned_pointers/alignment.rs | 8 ++++---- .../unaligned_pointers/reference_to_packed.rs | 14 ++++++++------ .../unaligned_pointers/unaligned_ptr1.rs | 10 ++++++---- .../unaligned_pointers/unaligned_ptr2.rs | 12 +++++++----- .../unaligned_pointers/unaligned_ptr3.rs | 14 ++++++++------ .../unaligned_pointers/unaligned_ptr_addr_of.rs | 12 +++++++----- 6 files changed, 40 insertions(+), 30 deletions(-) diff --git a/tests/compile-fail/unaligned_pointers/alignment.rs b/tests/compile-fail/unaligned_pointers/alignment.rs index 8532f91a5c006..e4d7621b8b125 100644 --- a/tests/compile-fail/unaligned_pointers/alignment.rs +++ b/tests/compile-fail/unaligned_pointers/alignment.rs @@ -1,11 +1,11 @@ +// error-pattern: but alignment 4 is required + fn main() { let mut x = [0u8; 20]; let x_ptr: *mut u8 = x.as_mut_ptr(); // At least one of these is definitely unaligned. - // Currently, we guarantee to complain about the first one already (https://github.com/rust-lang/miri/issues/1074). unsafe { - *(x_ptr as *mut u64) = 42; //~ ERROR accessing memory with alignment 1, but alignment - *(x_ptr.add(1) as *mut u64) = 42; + *(x_ptr as *mut u32) = 42; + *(x_ptr.add(1) as *mut u32) = 42; } - panic!("unreachable in miri"); } diff --git a/tests/compile-fail/unaligned_pointers/reference_to_packed.rs b/tests/compile-fail/unaligned_pointers/reference_to_packed.rs index a1240c90182aa..998394c6c70cc 100644 --- a/tests/compile-fail/unaligned_pointers/reference_to_packed.rs +++ b/tests/compile-fail/unaligned_pointers/reference_to_packed.rs @@ -10,10 +10,12 @@ struct Foo { } fn main() { - let foo = Foo { - x: 42, - y: 99, - }; - let p = unsafe { &foo.x }; - let i = *p; //~ ERROR alignment 4 is required + for _ in 0..10 { // Try many times as this might work by chance. + let foo = Foo { + x: 42, + y: 99, + }; + let p = unsafe { &foo.x }; + let i = *p; //~ ERROR alignment 4 is required + } } diff --git a/tests/compile-fail/unaligned_pointers/unaligned_ptr1.rs b/tests/compile-fail/unaligned_pointers/unaligned_ptr1.rs index 0a67cfc5a1b36..43e6fd67d2460 100644 --- a/tests/compile-fail/unaligned_pointers/unaligned_ptr1.rs +++ b/tests/compile-fail/unaligned_pointers/unaligned_ptr1.rs @@ -2,8 +2,10 @@ // compile-flags: -Zmiri-disable-validation -Zmiri-disable-stacked-borrows fn main() { - let x = [2u16, 3, 4]; // Make it big enough so we don't get an out-of-bounds error. - let x = &x[0] as *const _ as *const u32; - // This must fail because alignment is violated: the allocation's base is not sufficiently aligned. - let _x = unsafe { *x }; //~ ERROR memory with alignment 2, but alignment 4 is required + for _ in 0..10 { // Try many times as this might work by chance. + let x = [2u16, 3, 4]; // Make it big enough so we don't get an out-of-bounds error. + let x = &x[0] as *const _ as *const u32; + // This must fail because alignment is violated: the allocation's base is not sufficiently aligned. + let _x = unsafe { *x }; //~ ERROR memory with alignment 2, but alignment 4 is required + } } diff --git a/tests/compile-fail/unaligned_pointers/unaligned_ptr2.rs b/tests/compile-fail/unaligned_pointers/unaligned_ptr2.rs index b1fb2f4aa9762..f4ed8d47b53f1 100644 --- a/tests/compile-fail/unaligned_pointers/unaligned_ptr2.rs +++ b/tests/compile-fail/unaligned_pointers/unaligned_ptr2.rs @@ -2,9 +2,11 @@ // compile-flags: -Zmiri-disable-validation -Zmiri-disable-stacked-borrows fn main() { - let x = [2u32, 3]; // Make it big enough so we don't get an out-of-bounds error. - let x = (x.as_ptr() as *const u8).wrapping_offset(3) as *const u32; - // This must fail because alignment is violated: the offset is not sufficiently aligned. - // Also make the offset not a power of 2, that used to ICE. - let _x = unsafe { *x }; //~ ERROR memory with alignment 1, but alignment 4 is required + for _ in 0..10 { // Try many times as this might work by chance. + let x = [2u32, 3]; // Make it big enough so we don't get an out-of-bounds error. + let x = (x.as_ptr() as *const u8).wrapping_offset(3) as *const u32; + // This must fail because alignment is violated: the offset is not sufficiently aligned. + // Also make the offset not a power of 2, that used to ICE. + let _x = unsafe { *x }; //~ ERROR memory with alignment 1, but alignment 4 is required + } } diff --git a/tests/compile-fail/unaligned_pointers/unaligned_ptr3.rs b/tests/compile-fail/unaligned_pointers/unaligned_ptr3.rs index c5a3398384e49..61c2a3cde8948 100644 --- a/tests/compile-fail/unaligned_pointers/unaligned_ptr3.rs +++ b/tests/compile-fail/unaligned_pointers/unaligned_ptr3.rs @@ -2,10 +2,12 @@ // compile-flags: -Zmiri-disable-validation -Zmiri-disable-stacked-borrows fn main() { - let x = [2u16, 3, 4, 5]; // Make it big enough so we don't get an out-of-bounds error. - let x = &x[0] as *const _ as *const *const u8; // cast to ptr-to-ptr, so that we load a ptr - // This must fail because alignment is violated. Test specifically for loading pointers, - // which have special code in miri's memory. - let _x = unsafe { *x }; - //~^ ERROR memory with alignment 2, but alignment + for _ in 0..10 { // Try many times as this might work by chance. + let x = [2u16, 3, 4, 5]; // Make it big enough so we don't get an out-of-bounds error. + let x = &x[0] as *const _ as *const *const u8; // cast to ptr-to-ptr, so that we load a ptr + // This must fail because alignment is violated. Test specifically for loading pointers, + // which have special code in miri's memory. + let _x = unsafe { *x }; + //~^ ERROR but alignment + } } diff --git a/tests/compile-fail/unaligned_pointers/unaligned_ptr_addr_of.rs b/tests/compile-fail/unaligned_pointers/unaligned_ptr_addr_of.rs index cd52cd44c2b2c..88e2634efaf61 100644 --- a/tests/compile-fail/unaligned_pointers/unaligned_ptr_addr_of.rs +++ b/tests/compile-fail/unaligned_pointers/unaligned_ptr_addr_of.rs @@ -4,9 +4,11 @@ use std::ptr; fn main() { - let x = [2u16, 3, 4]; // Make it big enough so we don't get an out-of-bounds error. - let x = &x[0] as *const _ as *const u32; - // This must fail because alignment is violated: the allocation's base is not sufficiently aligned. - // The deref is UB even if we just put the result into a raw pointer. - let _x = unsafe { ptr::raw_const!(*x) }; //~ ERROR memory with alignment 2, but alignment 4 is required + for _ in 0..10 { // Try many times as this might work by chance. + let x = [2u16, 3, 4]; // Make it big enough so we don't get an out-of-bounds error. + let x = &x[0] as *const _ as *const u32; + // This must fail because alignment is violated: the allocation's base is not sufficiently aligned. + // The deref is UB even if we just put the result into a raw pointer. + let _x = unsafe { ptr::raw_const!(*x) }; //~ ERROR memory with alignment 2, but alignment 4 is required + } } From d5b15297acc5f585b308700d27c0f1420154a14e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 18 Aug 2020 10:11:54 +0200 Subject: [PATCH 2238/3747] forgot to add alignment test loop in one test --- rust-version | 2 +- .../unaligned_pointers/alignment.rs | 2 ++ .../unaligned_pointers/atomic_unaligned.rs | 2 +- .../unaligned_pointers/dyn_alignment.rs | 22 ++++++++++--------- .../intptrcast_alignment_check.rs | 3 ++- .../unaligned_pointers/reference_to_packed.rs | 2 +- .../unaligned_pointers/unaligned_ptr1.rs | 2 +- .../unaligned_pointers/unaligned_ptr2.rs | 14 ++++++------ .../unaligned_pointers/unaligned_ptr3.rs | 3 +-- .../unaligned_pointers/unaligned_ptr_zst.rs | 11 +++++----- 10 files changed, 34 insertions(+), 29 deletions(-) diff --git a/rust-version b/rust-version index e322ff61d1bda..6d85c7fb38887 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -8cdc94e84040ce797fd33d0a7cfda4ec4f2f2421 +515c9fa505e18a65d7f61bc3e9eb833b79a68618 diff --git a/tests/compile-fail/unaligned_pointers/alignment.rs b/tests/compile-fail/unaligned_pointers/alignment.rs index e4d7621b8b125..ff31fc6c293e9 100644 --- a/tests/compile-fail/unaligned_pointers/alignment.rs +++ b/tests/compile-fail/unaligned_pointers/alignment.rs @@ -1,6 +1,8 @@ // error-pattern: but alignment 4 is required fn main() { + // No retry needed, this fails reliably. + let mut x = [0u8; 20]; let x_ptr: *mut u8 = x.as_mut_ptr(); // At least one of these is definitely unaligned. diff --git a/tests/compile-fail/unaligned_pointers/atomic_unaligned.rs b/tests/compile-fail/unaligned_pointers/atomic_unaligned.rs index 77eff5087dac5..7e0704ac6fc06 100644 --- a/tests/compile-fail/unaligned_pointers/atomic_unaligned.rs +++ b/tests/compile-fail/unaligned_pointers/atomic_unaligned.rs @@ -8,6 +8,6 @@ fn main() { let zptr = &z as *const _ as *const u64; unsafe { ::std::intrinsics::atomic_load(zptr); - //~^ ERROR accessing memory with alignment 4, but alignment 8 is required + //~^ERROR accessing memory with alignment 4, but alignment 8 is required } } diff --git a/tests/compile-fail/unaligned_pointers/dyn_alignment.rs b/tests/compile-fail/unaligned_pointers/dyn_alignment.rs index a40db99a72a6c..91d9ec475b1fe 100644 --- a/tests/compile-fail/unaligned_pointers/dyn_alignment.rs +++ b/tests/compile-fail/unaligned_pointers/dyn_alignment.rs @@ -6,14 +6,16 @@ struct MuchAlign; fn main() { - let buf = [0u32; 256]; - // `buf` is sufficiently aligned for `layout.align` on a `dyn Debug`, but not - // for the actual alignment required by `MuchAlign`. - // We craft a wide reference `&dyn Debug` with the vtable for `MuchAlign`. That should be UB, - // as the reference is not aligned to its dynamic alignment requirements. - let mut ptr = &MuchAlign as &dyn std::fmt::Debug; - // Overwrite the data part of `ptr` so it points to `buf`. - unsafe { (&mut ptr as *mut _ as *mut *const u8).write(&buf as *const _ as *const u8); } - // Re-borrow that. This should be UB. - let _ptr = &*ptr; //~ ERROR alignment 256 is required + for _ in 0..10 { // Try many times as this might work by chance. + let buf = [0u32; 256]; + // `buf` is sufficiently aligned for `layout.align` on a `dyn Debug`, but not + // for the actual alignment required by `MuchAlign`. + // We craft a wide reference `&dyn Debug` with the vtable for `MuchAlign`. That should be UB, + // as the reference is not aligned to its dynamic alignment requirements. + let mut ptr = &MuchAlign as &dyn std::fmt::Debug; + // Overwrite the data part of `ptr` so it points to `buf`. + unsafe { (&mut ptr as *mut _ as *mut *const u8).write(&buf as *const _ as *const u8); } + // Re-borrow that. This should be UB. + let _ptr = &*ptr; //~ERROR alignment 256 is required + } } diff --git a/tests/compile-fail/unaligned_pointers/intptrcast_alignment_check.rs b/tests/compile-fail/unaligned_pointers/intptrcast_alignment_check.rs index 3865d45786374..9872a493c02a9 100644 --- a/tests/compile-fail/unaligned_pointers/intptrcast_alignment_check.rs +++ b/tests/compile-fail/unaligned_pointers/intptrcast_alignment_check.rs @@ -9,8 +9,9 @@ fn main() { let x = &mut [0u8; 3]; let base_addr = x as *mut _ as usize; + // Manually make sure the pointer is properly aligned. let base_addr_aligned = if base_addr % 2 == 0 { base_addr } else { base_addr+1 }; let u16_ptr = base_addr_aligned as *mut u16; - unsafe { *u16_ptr = 2; } //~ ERROR memory with alignment 1, but alignment 2 is required + unsafe { *u16_ptr = 2; } //~ERROR memory with alignment 1, but alignment 2 is required println!("{:?}", x); } diff --git a/tests/compile-fail/unaligned_pointers/reference_to_packed.rs b/tests/compile-fail/unaligned_pointers/reference_to_packed.rs index 998394c6c70cc..6fa9521185352 100644 --- a/tests/compile-fail/unaligned_pointers/reference_to_packed.rs +++ b/tests/compile-fail/unaligned_pointers/reference_to_packed.rs @@ -16,6 +16,6 @@ fn main() { y: 99, }; let p = unsafe { &foo.x }; - let i = *p; //~ ERROR alignment 4 is required + let i = *p; //~ERROR alignment 4 is required } } diff --git a/tests/compile-fail/unaligned_pointers/unaligned_ptr1.rs b/tests/compile-fail/unaligned_pointers/unaligned_ptr1.rs index 43e6fd67d2460..1d72e5170b7c2 100644 --- a/tests/compile-fail/unaligned_pointers/unaligned_ptr1.rs +++ b/tests/compile-fail/unaligned_pointers/unaligned_ptr1.rs @@ -6,6 +6,6 @@ fn main() { let x = [2u16, 3, 4]; // Make it big enough so we don't get an out-of-bounds error. let x = &x[0] as *const _ as *const u32; // This must fail because alignment is violated: the allocation's base is not sufficiently aligned. - let _x = unsafe { *x }; //~ ERROR memory with alignment 2, but alignment 4 is required + let _x = unsafe { *x }; //~ERROR memory with alignment 2, but alignment 4 is required } } diff --git a/tests/compile-fail/unaligned_pointers/unaligned_ptr2.rs b/tests/compile-fail/unaligned_pointers/unaligned_ptr2.rs index f4ed8d47b53f1..49612e2b8a096 100644 --- a/tests/compile-fail/unaligned_pointers/unaligned_ptr2.rs +++ b/tests/compile-fail/unaligned_pointers/unaligned_ptr2.rs @@ -2,11 +2,11 @@ // compile-flags: -Zmiri-disable-validation -Zmiri-disable-stacked-borrows fn main() { - for _ in 0..10 { // Try many times as this might work by chance. - let x = [2u32, 3]; // Make it big enough so we don't get an out-of-bounds error. - let x = (x.as_ptr() as *const u8).wrapping_offset(3) as *const u32; - // This must fail because alignment is violated: the offset is not sufficiently aligned. - // Also make the offset not a power of 2, that used to ICE. - let _x = unsafe { *x }; //~ ERROR memory with alignment 1, but alignment 4 is required - } + // No retry needed, this fails reliably. + + let x = [2u32, 3]; // Make it big enough so we don't get an out-of-bounds error. + let x = (x.as_ptr() as *const u8).wrapping_offset(3) as *const u32; + // This must fail because alignment is violated: the offset is not sufficiently aligned. + // Also make the offset not a power of 2, that used to ICE. + let _x = unsafe { *x }; //~ERROR memory with alignment 1, but alignment 4 is required } diff --git a/tests/compile-fail/unaligned_pointers/unaligned_ptr3.rs b/tests/compile-fail/unaligned_pointers/unaligned_ptr3.rs index 61c2a3cde8948..ecab83b05a09f 100644 --- a/tests/compile-fail/unaligned_pointers/unaligned_ptr3.rs +++ b/tests/compile-fail/unaligned_pointers/unaligned_ptr3.rs @@ -7,7 +7,6 @@ fn main() { let x = &x[0] as *const _ as *const *const u8; // cast to ptr-to-ptr, so that we load a ptr // This must fail because alignment is violated. Test specifically for loading pointers, // which have special code in miri's memory. - let _x = unsafe { *x }; - //~^ ERROR but alignment + let _x = unsafe { *x }; //~ERROR but alignment } } diff --git a/tests/compile-fail/unaligned_pointers/unaligned_ptr_zst.rs b/tests/compile-fail/unaligned_pointers/unaligned_ptr_zst.rs index beba47359b551..2b6ff3f71c60f 100644 --- a/tests/compile-fail/unaligned_pointers/unaligned_ptr_zst.rs +++ b/tests/compile-fail/unaligned_pointers/unaligned_ptr_zst.rs @@ -2,9 +2,10 @@ // compile-flags: -Zmiri-disable-validation fn main() { - let x = &2u8; - let x = x as *const _ as *const [u32; 0]; - // This must fail because alignment is violated. Test specifically for loading ZST. - let _x = unsafe { *x }; - //~^ ERROR alignment 4 is required + for _ in 0..10 { // Try many times as this might work by chance. + let x = &2u8; + let x = x as *const _ as *const [u32; 0]; + // This must fail because alignment is violated. Test specifically for loading ZST. + let _x = unsafe { *x }; //~ERROR alignment 4 is required + } } From 20942fb3a72b30a69f2ad5775b58b358dabab002 Mon Sep 17 00:00:00 2001 From: Jubilee Young Date: Wed, 19 Aug 2020 22:19:22 -0700 Subject: [PATCH 2239/3747] Remove byteorder dependency miri hasn't actually depended on byteorder directly for a while. Let's remove this dependency so Rust also depends less on it. --- Cargo.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index c33008e48a790..89f568146e07c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,7 +25,6 @@ required-features = ["rustc_tests"] [dependencies] getrandom = { version = "0.1.8", features = ["std"] } -byteorder = "1.3" env_logger = "0.7.1" log = "0.4" shell-escape = "0.1.4" From 237bea2c179adac24e12c190add9d8366192b32d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 20 Aug 2020 10:13:21 +0200 Subject: [PATCH 2240/3747] avoid promotion in alignment test to get different alignment on each try --- rust-version | 2 +- tests/compile-fail/unaligned_pointers/unaligned_ptr_zst.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/rust-version b/rust-version index 6d85c7fb38887..e00eb00ee556d 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -515c9fa505e18a65d7f61bc3e9eb833b79a68618 +1a22a0ff93d63f738151f096434e732466b4a42e diff --git a/tests/compile-fail/unaligned_pointers/unaligned_ptr_zst.rs b/tests/compile-fail/unaligned_pointers/unaligned_ptr_zst.rs index 2b6ff3f71c60f..169e98abf311a 100644 --- a/tests/compile-fail/unaligned_pointers/unaligned_ptr_zst.rs +++ b/tests/compile-fail/unaligned_pointers/unaligned_ptr_zst.rs @@ -3,8 +3,8 @@ fn main() { for _ in 0..10 { // Try many times as this might work by chance. - let x = &2u8; - let x = x as *const _ as *const [u32; 0]; + let x = 2u8; + let x = &x as *const _ as *const [u32; 0]; // This must fail because alignment is violated. Test specifically for loading ZST. let _x = unsafe { *x }; //~ERROR alignment 4 is required } From f3747b635e90faa5ee02e4207c5ed2bca64be274 Mon Sep 17 00:00:00 2001 From: Jubilee Young Date: Thu, 20 Aug 2020 16:48:35 -0700 Subject: [PATCH 2241/3747] Update lockfile --- Cargo.lock | 385 ++++++++++++++++++++++++++--------------------------- 1 file changed, 188 insertions(+), 197 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f68a6133be57e..d09ec19af6524 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,618 +4,609 @@ name = "aho-corasick" version = "0.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8716408b8bc624ed7f65d223ddb9ac2d044c0547b6fa4b0d554f3a9540496ada" dependencies = [ - "memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr", ] [[package]] name = "anyhow" version = "1.0.28" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9a60d744a80c30fcb657dfe2c1b22bcb3e814c1a1e3674f32bf5820b570fbff" [[package]] name = "arrayref" version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544" [[package]] name = "arrayvec" version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cff77d8686867eceff3105329d4698d96c2391c176d5d03adc90c7389162b5b8" [[package]] name = "atty" version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" dependencies = [ - "hermit-abi 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "hermit-abi", + "libc", + "winapi", ] [[package]] name = "autocfg" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d" [[package]] name = "base64" version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b41b7ea54a0c9d92199de89e20e58d49f02f8e699814ef3fdf266f6f748d15c7" [[package]] name = "blake2b_simd" version = "0.5.10" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8fb2d74254a3a0b5cac33ac9f8ed0e44aa50378d9dbb2e5d83bd21ed1dc2c8a" dependencies = [ - "arrayref 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", - "arrayvec 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "constant_time_eq 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "arrayref", + "arrayvec", + "constant_time_eq", ] -[[package]] -name = "byteorder" -version = "1.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "cfg-if" version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" [[package]] name = "colored" version = "1.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4ffc801dacf156c5854b9df4f425a626539c3a6ef7893cc0c5084a23f0b6c59" dependencies = [ - "atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "atty", + "lazy_static", + "winapi", ] [[package]] name = "compiletest_rs" version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f737835bfbbe29ed1ff82d5137520338d7ed5bf1a1d4b9c1c7c58bb45b8fa29" dependencies = [ - "diff 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", - "filetime 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)", - "getopts 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "miow 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.3.6 (registry+https://github.com/rust-lang/crates.io-index)", - "rustfix 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.106 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.106 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.51 (registry+https://github.com/rust-lang/crates.io-index)", - "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "tester 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "diff", + "filetime", + "getopts", + "libc", + "log", + "miow", + "regex", + "rustfix", + "serde", + "serde_derive", + "serde_json", + "tempfile", + "tester", + "winapi", ] [[package]] name = "constant_time_eq" version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" [[package]] name = "crossbeam-utils" version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8" dependencies = [ - "autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg", + "cfg-if", + "lazy_static", ] [[package]] name = "diff" version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e25ea47919b1560c4e3b7fe0aaab9becf5b84a10325ddf7db0f0ba5e1026499" [[package]] name = "dirs" version = "2.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13aea89a5c93364a98e9b37b2fa237effbb694d5cfe01c5b70941f7eb087d5e3" dependencies = [ - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "dirs-sys 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if", + "dirs-sys", ] [[package]] name = "dirs-sys" version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "afa0b23de8fd801745c471deffa6e12d248f962c9fd4b4c33787b055599bde7b" dependencies = [ - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_users 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if", + "libc", + "redox_users", + "winapi", ] [[package]] name = "env_logger" version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44533bbbb3bb3c1fa17d9f2e4e38bbbaf8396ba82193c4cb1b6445d711445d36" dependencies = [ - "atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", - "humantime 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "regex 1.3.6 (registry+https://github.com/rust-lang/crates.io-index)", - "termcolor 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "atty", + "humantime", + "log", + "regex", + "termcolor", ] [[package]] name = "filetime" version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f59efc38004c988e4201d11d263b8171f49a2e7ec0bdbb71773433f271504a5e" dependencies = [ - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if", + "libc", + "redox_syscall", + "winapi", ] [[package]] name = "getopts" version = "0.2.21" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14dbbfd5c71d70241ecf9e6f13737f7b5ce823821063188d7e46c41d371eebd5" dependencies = [ - "unicode-width 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-width", ] [[package]] name = "getrandom" version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7abc8dd8451921606d809ba32e95b6111925cd2906060d2dcc29c070220503eb" dependencies = [ - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", - "wasi 0.9.0+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if", + "libc", + "wasi", ] [[package]] name = "hermit-abi" version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "725cf19794cf90aa94e65050cb4191ff5d8fa87a498383774c47b332e3af952e" dependencies = [ - "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", + "libc", ] [[package]] name = "hex" version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "644f9158b2f133fd50f5fb3242878846d9eb792e445c893805ff0e3824006e35" [[package]] name = "humantime" version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f" dependencies = [ - "quick-error 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "quick-error", ] [[package]] name = "itoa" version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8b7a7c0c47db5545ed3fef7468ee7bb5b74691498139e4b3f6a20685dc6dd8e" [[package]] name = "lazy_static" version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" version = "0.2.68" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dea0c0405123bba743ee3f91f49b1c7cfb684eef0da0a50110f758ccf24cdff0" [[package]] name = "log" version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7" dependencies = [ - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if", ] [[package]] name = "memchr" version = "2.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3728d817d99e5ac407411fa471ff9800a778d88a24685968b36824eaf4bee400" [[package]] name = "miow" version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "396aa0f2003d7df8395cb93e09871561ccc3e785f0acb369170e8cc74ddf9226" dependencies = [ - "socket2 0.3.12 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "socket2", + "winapi", ] [[package]] name = "miri" version = "0.1.0" dependencies = [ - "byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "colored 1.9.3 (registry+https://github.com/rust-lang/crates.io-index)", - "compiletest_rs 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", - "env_logger 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", - "getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", - "hex 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc-workspace-hack 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "shell-escape 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "colored", + "compiletest_rs", + "env_logger", + "getrandom", + "hex", + "libc", + "log", + "rand", + "rustc-workspace-hack", + "rustc_version", + "shell-escape", ] [[package]] name = "ppv-lite86" version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74490b50b9fbe561ac330df47c08f3f33073d2d00c150f719147d7c54522fa1b" [[package]] name = "proc-macro2" version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df246d292ff63439fea9bc8c0a270bed0e390d5ebd4db4ba15aba81111b5abe3" dependencies = [ - "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-xid", ] [[package]] name = "quick-error" version = "1.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" [[package]] name = "quote" version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bdc6c187c65bca4260c9011c9e3132efe4909da44726bad24cf7572ae338d7f" dependencies = [ - "proc-macro2 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2", ] [[package]] name = "rand" version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" dependencies = [ - "getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "getrandom", + "libc", + "rand_chacha", + "rand_core", + "rand_hc", ] [[package]] name = "rand_chacha" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" dependencies = [ - "ppv-lite86 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "ppv-lite86", + "rand_core", ] [[package]] name = "rand_core" version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" dependencies = [ - "getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", + "getrandom", ] [[package]] name = "rand_hc" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" dependencies = [ - "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core", ] [[package]] name = "redox_syscall" version = "0.1.56" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84" [[package]] name = "redox_users" version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09b23093265f8d200fa7b4c2c76297f47e681c655f6f1285a8780d6a022f7431" dependencies = [ - "getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", - "rust-argon2 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "getrandom", + "redox_syscall", + "rust-argon2", ] [[package]] name = "regex" version = "1.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f6946991529684867e47d86474e3a6d0c0ab9b82d5821e314b1ede31fa3a4b3" dependencies = [ - "aho-corasick 0.7.10 (registry+https://github.com/rust-lang/crates.io-index)", - "memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "regex-syntax 0.6.17 (registry+https://github.com/rust-lang/crates.io-index)", - "thread_local 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "aho-corasick", + "memchr", + "regex-syntax", + "thread_local", ] [[package]] name = "regex-syntax" version = "0.6.17" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fe5bd57d1d7414c6b5ed48563a2c855d995ff777729dcd91c369ec7fea395ae" [[package]] name = "remove_dir_all" version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a83fa3702a688b9359eccba92d153ac33fd2e8462f9e0e3fdf155239ea7792e" dependencies = [ - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi", ] [[package]] name = "rust-argon2" version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bc8af4bda8e1ff4932523b94d3dd20ee30a87232323eda55903ffd71d2fb017" dependencies = [ - "base64 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", - "blake2b_simd 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)", - "constant_time_eq 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", + "base64", + "blake2b_simd", + "constant_time_eq", + "crossbeam-utils", ] [[package]] name = "rustc-workspace-hack" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc71d2faa173b74b232dedc235e3ee1696581bb132fc116fa3626d6151a1a8fb" [[package]] name = "rustc_version" version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" dependencies = [ - "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", + "semver", ] [[package]] name = "rustfix" version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2c50b74badcddeb8f7652fa8323ce440b95286f8e4b64ebfd871c609672704e" dependencies = [ - "anyhow 1.0.28 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.106 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.51 (registry+https://github.com/rust-lang/crates.io-index)", + "anyhow", + "log", + "serde", + "serde_json", ] [[package]] name = "ryu" version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "535622e6be132bccd223f4bb2b8ac8d53cda3c7a6394944d3b2b33fb974f9d76" [[package]] name = "semver" version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" dependencies = [ - "semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "semver-parser", ] [[package]] name = "semver-parser" version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" [[package]] name = "serde" version = "1.0.106" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36df6ac6412072f67cf767ebbde4133a5b2e88e76dc6187fa7104cd16f783399" dependencies = [ - "serde_derive 1.0.106 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive", ] [[package]] name = "serde_derive" version = "1.0.106" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e549e3abf4fb8621bd1609f11dfc9f5e50320802273b12f3811a67e6716ea6c" dependencies = [ - "proc-macro2 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2", + "quote", + "syn", ] [[package]] name = "serde_json" version = "1.0.51" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da07b57ee2623368351e9a0488bb0b261322a15a6e0ae53e243cbdc0f4208da9" dependencies = [ - "itoa 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)", - "ryu 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.106 (registry+https://github.com/rust-lang/crates.io-index)", + "itoa", + "ryu", + "serde", ] [[package]] name = "shell-escape" version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "170a13e64f2a51b77a45702ba77287f5c6829375b04a69cf2222acd17d0cfab9" [[package]] name = "socket2" version = "0.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03088793f677dce356f3ccc2edb1b314ad191ab702a5de3faf49304f7e104918" dependencies = [ - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if", + "libc", + "redox_syscall", + "winapi", ] [[package]] name = "syn" version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0df0eb663f387145cab623dea85b09c2c5b4b0aef44e945d928e682fce71bb03" dependencies = [ - "proc-macro2 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2", + "quote", + "unicode-xid", ] [[package]] name = "tempfile" version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9" dependencies = [ - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", - "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", - "remove_dir_all 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if", + "libc", + "rand", + "redox_syscall", + "remove_dir_all", + "winapi", ] [[package]] name = "term" version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0863a3345e70f61d613eab32ee046ccd1bcc5f9105fe402c61fcd0c13eeb8b5" dependencies = [ - "dirs 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "dirs", + "winapi", ] [[package]] name = "termcolor" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb6bfa289a4d7c5766392812c0a1f4c1ba45afa1ad47803c11e1f407d846d75f" dependencies = [ - "winapi-util 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-util", ] [[package]] name = "tester" version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee72ec31009a42b53de9a6b7d8f462b493ab3b1e4767bda1fcdbb52127f13b6c" dependencies = [ - "getopts 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", - "term 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", + "getopts", + "libc", + "term", ] [[package]] name = "thread_local" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d40c6d1b69745a6ec6fb1ca717914848da4b44ae29d9b3080cbee91d72a69b14" dependencies = [ - "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static", ] [[package]] name = "unicode-width" version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "caaa9d531767d1ff2150b9332433f32a24622147e5ebb1f26409d5da67afd479" [[package]] name = "unicode-xid" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" [[package]] name = "wasi" version = "0.9.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" [[package]] name = "winapi" version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6" dependencies = [ - "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", ] [[package]] name = "winapi-i686-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-util" version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa515c5163a99cc82bab70fd3bfdd36d827be85de63737b40fcef2ce084a436e" dependencies = [ - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi", ] [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" - -[metadata] -"checksum aho-corasick 0.7.10 (registry+https://github.com/rust-lang/crates.io-index)" = "8716408b8bc624ed7f65d223ddb9ac2d044c0547b6fa4b0d554f3a9540496ada" -"checksum anyhow 1.0.28 (registry+https://github.com/rust-lang/crates.io-index)" = "d9a60d744a80c30fcb657dfe2c1b22bcb3e814c1a1e3674f32bf5820b570fbff" -"checksum arrayref 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544" -"checksum arrayvec 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cff77d8686867eceff3105329d4698d96c2391c176d5d03adc90c7389162b5b8" -"checksum atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" -"checksum autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d" -"checksum base64 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b41b7ea54a0c9d92199de89e20e58d49f02f8e699814ef3fdf266f6f748d15c7" -"checksum blake2b_simd 0.5.10 (registry+https://github.com/rust-lang/crates.io-index)" = "d8fb2d74254a3a0b5cac33ac9f8ed0e44aa50378d9dbb2e5d83bd21ed1dc2c8a" -"checksum byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de" -"checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" -"checksum colored 1.9.3 (registry+https://github.com/rust-lang/crates.io-index)" = "f4ffc801dacf156c5854b9df4f425a626539c3a6ef7893cc0c5084a23f0b6c59" -"checksum compiletest_rs 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9f737835bfbbe29ed1ff82d5137520338d7ed5bf1a1d4b9c1c7c58bb45b8fa29" -"checksum constant_time_eq 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" -"checksum crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8" -"checksum diff 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)" = "0e25ea47919b1560c4e3b7fe0aaab9becf5b84a10325ddf7db0f0ba5e1026499" -"checksum dirs 2.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "13aea89a5c93364a98e9b37b2fa237effbb694d5cfe01c5b70941f7eb087d5e3" -"checksum dirs-sys 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "afa0b23de8fd801745c471deffa6e12d248f962c9fd4b4c33787b055599bde7b" -"checksum env_logger 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "44533bbbb3bb3c1fa17d9f2e4e38bbbaf8396ba82193c4cb1b6445d711445d36" -"checksum filetime 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)" = "f59efc38004c988e4201d11d263b8171f49a2e7ec0bdbb71773433f271504a5e" -"checksum getopts 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)" = "14dbbfd5c71d70241ecf9e6f13737f7b5ce823821063188d7e46c41d371eebd5" -"checksum getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "7abc8dd8451921606d809ba32e95b6111925cd2906060d2dcc29c070220503eb" -"checksum hermit-abi 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "725cf19794cf90aa94e65050cb4191ff5d8fa87a498383774c47b332e3af952e" -"checksum hex 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "644f9158b2f133fd50f5fb3242878846d9eb792e445c893805ff0e3824006e35" -"checksum humantime 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f" -"checksum itoa 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "b8b7a7c0c47db5545ed3fef7468ee7bb5b74691498139e4b3f6a20685dc6dd8e" -"checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" -"checksum libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)" = "dea0c0405123bba743ee3f91f49b1c7cfb684eef0da0a50110f758ccf24cdff0" -"checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7" -"checksum memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3728d817d99e5ac407411fa471ff9800a778d88a24685968b36824eaf4bee400" -"checksum miow 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "396aa0f2003d7df8395cb93e09871561ccc3e785f0acb369170e8cc74ddf9226" -"checksum ppv-lite86 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "74490b50b9fbe561ac330df47c08f3f33073d2d00c150f719147d7c54522fa1b" -"checksum proc-macro2 1.0.10 (registry+https://github.com/rust-lang/crates.io-index)" = "df246d292ff63439fea9bc8c0a270bed0e390d5ebd4db4ba15aba81111b5abe3" -"checksum quick-error 1.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" -"checksum quote 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2bdc6c187c65bca4260c9011c9e3132efe4909da44726bad24cf7572ae338d7f" -"checksum rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" -"checksum rand_chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" -"checksum rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" -"checksum rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" -"checksum redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)" = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84" -"checksum redox_users 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "09b23093265f8d200fa7b4c2c76297f47e681c655f6f1285a8780d6a022f7431" -"checksum regex 1.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7f6946991529684867e47d86474e3a6d0c0ab9b82d5821e314b1ede31fa3a4b3" -"checksum regex-syntax 0.6.17 (registry+https://github.com/rust-lang/crates.io-index)" = "7fe5bd57d1d7414c6b5ed48563a2c855d995ff777729dcd91c369ec7fea395ae" -"checksum remove_dir_all 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4a83fa3702a688b9359eccba92d153ac33fd2e8462f9e0e3fdf155239ea7792e" -"checksum rust-argon2 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2bc8af4bda8e1ff4932523b94d3dd20ee30a87232323eda55903ffd71d2fb017" -"checksum rustc-workspace-hack 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc71d2faa173b74b232dedc235e3ee1696581bb132fc116fa3626d6151a1a8fb" -"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" -"checksum rustfix 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f2c50b74badcddeb8f7652fa8323ce440b95286f8e4b64ebfd871c609672704e" -"checksum ryu 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "535622e6be132bccd223f4bb2b8ac8d53cda3c7a6394944d3b2b33fb974f9d76" -"checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" -"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" -"checksum serde 1.0.106 (registry+https://github.com/rust-lang/crates.io-index)" = "36df6ac6412072f67cf767ebbde4133a5b2e88e76dc6187fa7104cd16f783399" -"checksum serde_derive 1.0.106 (registry+https://github.com/rust-lang/crates.io-index)" = "9e549e3abf4fb8621bd1609f11dfc9f5e50320802273b12f3811a67e6716ea6c" -"checksum serde_json 1.0.51 (registry+https://github.com/rust-lang/crates.io-index)" = "da07b57ee2623368351e9a0488bb0b261322a15a6e0ae53e243cbdc0f4208da9" -"checksum shell-escape 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "170a13e64f2a51b77a45702ba77287f5c6829375b04a69cf2222acd17d0cfab9" -"checksum socket2 0.3.12 (registry+https://github.com/rust-lang/crates.io-index)" = "03088793f677dce356f3ccc2edb1b314ad191ab702a5de3faf49304f7e104918" -"checksum syn 1.0.17 (registry+https://github.com/rust-lang/crates.io-index)" = "0df0eb663f387145cab623dea85b09c2c5b4b0aef44e945d928e682fce71bb03" -"checksum tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9" -"checksum term 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c0863a3345e70f61d613eab32ee046ccd1bcc5f9105fe402c61fcd0c13eeb8b5" -"checksum termcolor 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb6bfa289a4d7c5766392812c0a1f4c1ba45afa1ad47803c11e1f407d846d75f" -"checksum tester 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee72ec31009a42b53de9a6b7d8f462b493ab3b1e4767bda1fcdbb52127f13b6c" -"checksum thread_local 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d40c6d1b69745a6ec6fb1ca717914848da4b44ae29d9b3080cbee91d72a69b14" -"checksum unicode-width 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "caaa9d531767d1ff2150b9332433f32a24622147e5ebb1f26409d5da67afd479" -"checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" -"checksum wasi 0.9.0+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)" = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" -"checksum winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6" -"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" -"checksum winapi-util 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "fa515c5163a99cc82bab70fd3bfdd36d827be85de63737b40fcef2ce084a436e" -"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" From 2619b4fa1883b324f56798e37b79efe98e66e642 Mon Sep 17 00:00:00 2001 From: Jubilee Young Date: Fri, 21 Aug 2020 01:37:56 -0700 Subject: [PATCH 2242/3747] Bump cargo_metadata to 0.11 --- cargo-miri/Cargo.lock | 18 +++++++++++++----- cargo-miri/Cargo.toml | 2 +- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/cargo-miri/Cargo.lock b/cargo-miri/Cargo.lock index c6d80add07878..0052bfa183d06 100644 --- a/cargo-miri/Cargo.lock +++ b/cargo-miri/Cargo.lock @@ -56,13 +56,12 @@ dependencies = [ [[package]] name = "cargo_metadata" -version = "0.9.1" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46e3374c604fb39d1a2f35ed5e4a4e30e60d01fab49446e08f1b3e9a90aef202" +checksum = "89fec17b16f1ac67908af82e47d0a90a7afd0e1827b181cd77504323d3263d35" dependencies = [ - "semver", + "semver 0.10.0", "serde", - "serde_derive", "serde_json", ] @@ -229,7 +228,7 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" dependencies = [ - "semver", + "semver 0.9.0", ] [[package]] @@ -243,6 +242,15 @@ name = "semver" version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" +dependencies = [ + "semver-parser", +] + +[[package]] +name = "semver" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "394cec28fa623e00903caf7ba4fa6fb9a0e260280bb8cdbbba029611108a0190" dependencies = [ "semver-parser", "serde", diff --git a/cargo-miri/Cargo.toml b/cargo-miri/Cargo.toml index d6a98be2bbdfa..91c4783694844 100644 --- a/cargo-miri/Cargo.toml +++ b/cargo-miri/Cargo.toml @@ -14,7 +14,7 @@ test = false # we have no unit tests doctest = false # and no doc tests [dependencies] -cargo_metadata = "0.9.0" +cargo_metadata = "0.11" directories = "2.0" rustc_version = "0.2.3" serde_json = "1.0.40" From 3b7f36ef8d9ce4419c643b774b58831ba86b8a8f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 22 Aug 2020 14:31:46 +0200 Subject: [PATCH 2243/3747] emphasize that some flags are unsound to use --- README.md | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 37ed718a1a2b8..f47ee09690404 100644 --- a/README.md +++ b/README.md @@ -166,14 +166,17 @@ up the sysroot. If you are using `miri` (the Miri driver) directly, see the Miri adds its own set of `-Z` flags: * `-Zmiri-disable-alignment-check` disables checking pointer alignment, so you - can focus on other failures. + can focus on other failures, but it means Miri can miss bugs in your program. + Using this flag is **unsound**. * `-Zmiri-disable-stacked-borrows` disables checking the experimental [Stacked Borrows] aliasing rules. This can make Miri run faster, but it also - means no aliasing violations will be detected. + means no aliasing violations will be detected. Using this flag is **unsound** + (but the affected soundness rules are experimental). * `-Zmiri-disable-validation` disables enforcing validity invariants, which are enforced by default. This is mostly useful to focus on other failures (such - as out-of-bounds accesses) first. Setting this flag means Miri will miss bugs - in your program. However, this can also help to make Miri run faster. + as out-of-bounds accesses) first. Setting this flag means Miri can miss bugs + in your program. However, this can also help to make Miri run faster. Using + this flag is **unsound**. * `-Zmiri-disable-isolation` disables host isolation. As a consequence, the program has access to host resources such as environment variables, file systems, and randomness. From 8da9d23e5e7a509e8bee4e0a4b12b9e694a6f225 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 22 Aug 2020 18:03:34 +0200 Subject: [PATCH 2244/3747] tweak test matrix: test big-endian, and test less on macOS host (it is slow) --- ci.sh | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/ci.sh b/ci.sh index ac0d080a48391..c2c36e1efc1fe 100755 --- a/ci.sh +++ b/ci.sh @@ -43,9 +43,8 @@ if [ "${TRAVIS_OS_NAME:-}" == linux ]; then MIRI_TEST_TARGET=x86_64-apple-darwin run_tests MIRI_TEST_TARGET=i686-pc-windows-msvc run_tests elif [ "${TRAVIS_OS_NAME:-}" == osx ]; then - MIRI_TEST_TARGET=i686-unknown-linux-gnu run_tests + MIRI_TEST_TARGET=mips64-unknown-linux-gnuabi64 run_tests # big-endian architecture MIRI_TEST_TARGET=x86_64-pc-windows-msvc run_tests - MIRI_TEST_TARGET=i686-pc-windows-gnu run_tests elif [ "${CI_WINDOWS:-}" == True ]; then MIRI_TEST_TARGET=x86_64-unknown-linux-gnu run_tests MIRI_TEST_TARGET=x86_64-apple-darwin run_tests From df9b2127ce5c8ac567f0dc60e3b7b828e10d5613 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 22 Aug 2020 18:07:43 +0200 Subject: [PATCH 2245/3747] fix a test for big-endian targets --- tests/run-pass/transmute_fat2.rs | 8 ++++++-- tests/run-pass/transmute_fat2.stderr | 2 +- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/tests/run-pass/transmute_fat2.rs b/tests/run-pass/transmute_fat2.rs index 3dff2cc1e0c93..2f0271d5813f5 100644 --- a/tests/run-pass/transmute_fat2.rs +++ b/tests/run-pass/transmute_fat2.rs @@ -1,9 +1,13 @@ fn main() { - #[cfg(target_pointer_width="64")] + #[cfg(all(target_endian="little", target_pointer_width="64"))] let bad = unsafe { std::mem::transmute::(42) }; - #[cfg(target_pointer_width="32")] + #[cfg(all(target_endian="big", target_pointer_width="64"))] + let bad = unsafe { + std::mem::transmute::(42 << 64) + }; + #[cfg(all(target_endian="little", target_pointer_width="32"))] let bad = unsafe { std::mem::transmute::(42) }; diff --git a/tests/run-pass/transmute_fat2.stderr b/tests/run-pass/transmute_fat2.stderr index 08849a5b517a4..c8298a6c23c66 100644 --- a/tests/run-pass/transmute_fat2.stderr +++ b/tests/run-pass/transmute_fat2.stderr @@ -1 +1 @@ -thread 'main' panicked at 'index out of bounds: the len is 0 but the index is 0', $DIR/transmute_fat2.rs:11:5 +thread 'main' panicked at 'index out of bounds: the len is 0 but the index is 0', $DIR/transmute_fat2.rs:15:5 From 2f9de18f8870e4265478b2d98d6c3dac6a62336d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 24 Aug 2020 10:06:44 +0200 Subject: [PATCH 2246/3747] rustup; account for ptr_offset_from stabilization --- rust-version | 2 +- tests/run-pass/ptr_offset.rs | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/rust-version b/rust-version index e00eb00ee556d..15fcdfa88c366 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -1a22a0ff93d63f738151f096434e732466b4a42e +c4b6d9411f939c1ad7b3521b907fa101f3360462 diff --git a/tests/run-pass/ptr_offset.rs b/tests/run-pass/ptr_offset.rs index f83720b547c02..71d057b8c9ced 100644 --- a/tests/run-pass/ptr_offset.rs +++ b/tests/run-pass/ptr_offset.rs @@ -1,4 +1,3 @@ -#![feature(ptr_offset_from)] use std::{mem, ptr}; fn main() { From 3bc8302a54653f3f92b015106a5322f7ce8e29a0 Mon Sep 17 00:00:00 2001 From: David Cook Date: Tue, 25 Aug 2020 19:00:46 -0500 Subject: [PATCH 2247/3747] Support --test/--bin/--lib in cargo-miri --- cargo-miri/bin.rs | 80 +++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 71 insertions(+), 9 deletions(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index a2d6c3fc5b71a..029c5e5610c2c 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -378,6 +378,69 @@ path = "lib.rs" } } +enum CargoTargets { + All, + Filtered { lib: bool, bin: Vec, test: Vec }, +} + +impl CargoTargets { + fn matches(&self, kind: &str, name: &str) -> bool { + match self { + CargoTargets::All => true, + CargoTargets::Filtered { lib, bin, test } => match kind { + "lib" => *lib, + "bin" => bin.iter().any(|n| n == name), + "test" => test.iter().any(|n| n == name), + _ => false, + }, + } + } +} + +fn parse_cargo_miri_args( + mut args: impl Iterator, +) -> (CargoTargets, Vec, Vec) { + let mut lib_present = false; + let mut bin_targets = Vec::new(); + let mut test_targets = Vec::new(); + let mut additional_args = Vec::new(); + while let Some(arg) = args.next() { + match arg { + arg if arg == "--" => break, + arg if arg == "--lib" => lib_present = true, + arg if arg == "--bin" => { + if let Some(binary) = args.next() { + if binary == "--" { + show_error(format!("\"--bin\" takes one argument.")); + } else { + bin_targets.push(binary) + } + } else { + show_error(format!("\"--bin\" takes one argument.")); + } + } + arg if arg == "--test" => { + if let Some(test) = args.next() { + if test == "--" { + show_error(format!("\"--test\" takes one argument.")); + } else { + test_targets.push(test) + } + } else { + show_error(format!("\"--test\" takes one argument.")); + } + } + other => additional_args.push(other), + } + } + let targets = if !lib_present && bin_targets.len() == 0 && test_targets.len() == 0 { + CargoTargets::All + } else { + CargoTargets::Filtered { lib: lib_present, bin: bin_targets, test: test_targets } + }; + (targets, additional_args, args.collect()) +} + fn in_cargo_miri() { let (subcommand, skip) = match std::env::args().nth(2).as_deref() { Some("test") => (MiriCommand::Test, 3), @@ -398,13 +461,18 @@ fn in_cargo_miri() { return; } + let (target_filters, cargo_args, miri_args) = + parse_cargo_miri_args(std::env::args().skip(skip)); + // Now run the command. for target in list_targets() { - let mut args = std::env::args().skip(skip); let kind = target .kind .get(0) .expect("badly formatted cargo metadata: target::kind is an empty array"); + if !target_filters.matches(kind, &target.name) { + continue; + } // Now we run `cargo check $FLAGS $ARGS`, giving the user the // change to add additional arguments. `FLAGS` is set to identify // this target. The user gets to control what gets actually passed to Miri. @@ -412,8 +480,6 @@ fn in_cargo_miri() { cmd.arg("check"); match (subcommand, kind.as_str()) { (MiriCommand::Run, "bin") => { - // FIXME: we just run all the binaries here. - // We should instead support `cargo miri --bin foo`. cmd.arg("--bin").arg(target.name); } (MiriCommand::Test, "test") => { @@ -430,10 +496,7 @@ fn in_cargo_miri() { _ => continue, } // Forward user-defined `cargo` args until first `--`. - while let Some(arg) = args.next() { - if arg == "--" { - break; - } + for arg in cargo_args.iter() { cmd.arg(arg); } // We want to always run `cargo` with `--target`. This later helps us detect @@ -450,8 +513,7 @@ fn in_cargo_miri() { // our actual target crate (the binary or the test we are running). // Since we're using "cargo check", we have no other way of passing // these arguments. - let args_vec: Vec = args.collect(); - cmd.env("MIRI_ARGS", serde_json::to_string(&args_vec).expect("failed to serialize args")); + cmd.env("MIRI_ARGS", serde_json::to_string(&miri_args).expect("failed to serialize args")); // Set `RUSTC_WRAPPER` to ourselves. Cargo will prepend that binary to its usual invocation, // i.e., the first argument is `rustc` -- which is what we use in `main` to distinguish From 40847abd5f2da77bce75ee12564a49b01c3588e7 Mon Sep 17 00:00:00 2001 From: David Cook Date: Wed, 26 Aug 2020 18:41:01 -0500 Subject: [PATCH 2248/3747] Review comments --- cargo-miri/bin.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index 029c5e5610c2c..9ac1f3e4c2d4a 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -406,7 +406,10 @@ fn parse_cargo_miri_args( let mut additional_args = Vec::new(); while let Some(arg) = args.next() { match arg { - arg if arg == "--" => break, + arg if arg == "--" => { + // Miri arguments begin after the first "--". + break; + } arg if arg == "--lib" => lib_present = true, arg if arg == "--bin" => { if let Some(binary) = args.next() { @@ -419,6 +422,7 @@ fn parse_cargo_miri_args( show_error(format!("\"--bin\" takes one argument.")); } } + arg if arg.starts_with("--bin=") => bin_targets.push((&arg[6..]).to_string()), arg if arg == "--test" => { if let Some(test) = args.next() { if test == "--" { @@ -430,6 +434,7 @@ fn parse_cargo_miri_args( show_error(format!("\"--test\" takes one argument.")); } } + arg if arg.starts_with("--test=") => test_targets.push((&arg[7..]).to_string()), other => additional_args.push(other), } } @@ -480,6 +485,7 @@ fn in_cargo_miri() { cmd.arg("check"); match (subcommand, kind.as_str()) { (MiriCommand::Run, "bin") => { + // FIXME: we default to running all binaries here. cmd.arg("--bin").arg(target.name); } (MiriCommand::Test, "test") => { @@ -495,7 +501,7 @@ fn in_cargo_miri() { // The remaining targets we do not even want to build. _ => continue, } - // Forward user-defined `cargo` args until first `--`. + // Forward further `cargo` args. for arg in cargo_args.iter() { cmd.arg(arg); } From 4608341ca071634b9aae2ea967f25b5cfe970e7e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 27 Aug 2020 08:37:11 +0200 Subject: [PATCH 2249/3747] add encoding_rs OOB arithmetic --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index f47ee09690404..d8474868703d6 100644 --- a/README.md +++ b/README.md @@ -320,6 +320,7 @@ Definite bugs found: * [TiKV performing an unaligned pointer access](https://github.com/tikv/tikv/issues/7613) * [`servo_arc` creating a dangling shared reference](https://github.com/servo/servo/issues/26357) * [TiKV constructing out-of-bounds pointers (and overlapping mutable references)](https://github.com/tikv/tikv/pull/7751) +* [`encoding_rs` doing out-of-bounds pointer arithmetic](https://github.com/hsivonen/encoding_rs/pull/53) Violations of [Stacked Borrows] found that are likely bugs (but Stacked Borrows is currently just an experiment): From 39e6baeb91fc720494ae8ebd6f7c2cd29a19130f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 27 Aug 2020 09:27:58 +0200 Subject: [PATCH 2250/3747] rustup --- rust-version | 2 +- tests/run-pass/heap_allocator.rs | 30 +++++++++++++++--------------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/rust-version b/rust-version index 15fcdfa88c366..f5fb708740208 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -c4b6d9411f939c1ad7b3521b907fa101f3360462 +18b0585b52741ca158dfebef7968326e2704352e diff --git a/tests/run-pass/heap_allocator.rs b/tests/run-pass/heap_allocator.rs index 557550d6f4331..cf9a2f4b6925f 100644 --- a/tests/run-pass/heap_allocator.rs +++ b/tests/run-pass/heap_allocator.rs @@ -6,39 +6,39 @@ use std::slice; fn check_alloc(mut allocator: T) { unsafe { for &align in &[4, 8, 16, 32] { - let layout = Layout::from_size_align(20, align).unwrap(); + let layout_20 = Layout::from_size_align(20, align).unwrap(); + let layout_40 = Layout::from_size_align(40, 4*align).unwrap(); + let layout_10 = Layout::from_size_align(10, align/2).unwrap(); for _ in 0..32 { - let a = allocator.alloc(layout).unwrap().as_non_null_ptr(); - assert_eq!(a.as_ptr() as usize % align, 0, "pointer is incorrectly aligned"); - allocator.dealloc(a, layout); + let a = allocator.alloc(layout_20).unwrap().as_non_null_ptr(); + assert_eq!(a.as_ptr() as usize % layout_20.align(), 0, "pointer is incorrectly aligned"); + allocator.dealloc(a, layout_20); } - let p1 = allocator.alloc_zeroed(layout).unwrap().as_non_null_ptr(); - assert_eq!(p1.as_ptr() as usize % align, 0, "pointer is incorrectly aligned"); + let p1 = allocator.alloc_zeroed(layout_20).unwrap().as_non_null_ptr(); + assert_eq!(p1.as_ptr() as usize % layout_20.align(), 0, "pointer is incorrectly aligned"); assert_eq!(*p1.as_ptr(), 0); // old size < new size - let p2 = allocator.grow(p1, layout, 40).unwrap().as_non_null_ptr(); - let layout = Layout::from_size_align(40, align).unwrap(); - assert_eq!(p2.as_ptr() as usize % align, 0, "pointer is incorrectly aligned"); + let p2 = allocator.grow(p1, layout_20, layout_40).unwrap().as_non_null_ptr(); + assert_eq!(p2.as_ptr() as usize % layout_40.align(), 0, "pointer is incorrectly aligned"); let slice = slice::from_raw_parts(p2.as_ptr(), 20); assert_eq!(&slice, &[0_u8; 20]); // old size == new size - let p3 = allocator.grow(p2, layout, 40).unwrap().as_non_null_ptr(); - assert_eq!(p3.as_ptr() as usize % align, 0, "pointer is incorrectly aligned"); + let p3 = allocator.grow(p2, layout_40, layout_40).unwrap().as_non_null_ptr(); + assert_eq!(p3.as_ptr() as usize % layout_40.align(), 0, "pointer is incorrectly aligned"); let slice = slice::from_raw_parts(p3.as_ptr(), 20); assert_eq!(&slice, &[0_u8; 20]); // old size > new size - let p4 = allocator.shrink(p3, layout, 10).unwrap().as_non_null_ptr(); - let layout = Layout::from_size_align(10, align).unwrap(); - assert_eq!(p4.as_ptr() as usize % align, 0, "pointer is incorrectly aligned"); + let p4 = allocator.shrink(p3, layout_40, layout_10).unwrap().as_non_null_ptr(); + assert_eq!(p4.as_ptr() as usize % layout_10.align(), 0, "pointer is incorrectly aligned"); let slice = slice::from_raw_parts(p4.as_ptr(), 10); assert_eq!(&slice, &[0_u8; 10]); - allocator.dealloc(p4, layout); + allocator.dealloc(p4, layout_10); } } } From 64e2d3e2d0d8de0f750381ba8786fdd398c538a4 Mon Sep 17 00:00:00 2001 From: David Cook Date: Thu, 27 Aug 2020 05:00:56 -0500 Subject: [PATCH 2251/3747] Review comments --- cargo-miri/bin.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index 9ac1f3e4c2d4a..98304d247f98f 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -422,7 +422,7 @@ fn parse_cargo_miri_args( show_error(format!("\"--bin\" takes one argument.")); } } - arg if arg.starts_with("--bin=") => bin_targets.push((&arg[6..]).to_string()), + arg if arg.starts_with("--bin=") => bin_targets.push((&arg["--bin=".len()..]).to_string()), arg if arg == "--test" => { if let Some(test) = args.next() { if test == "--" { @@ -434,7 +434,7 @@ fn parse_cargo_miri_args( show_error(format!("\"--test\" takes one argument.")); } } - arg if arg.starts_with("--test=") => test_targets.push((&arg[7..]).to_string()), + arg if arg.starts_with("--test=") => test_targets.push((&arg["--test=".len()..]).to_string()), other => additional_args.push(other), } } @@ -466,6 +466,7 @@ fn in_cargo_miri() { return; } + // FIXME: this accepts --test, --lib, and multiple --bin for `cargo miri run`. let (target_filters, cargo_args, miri_args) = parse_cargo_miri_args(std::env::args().skip(skip)); From 5d9d75fc1f2fc87f419913db7bf8a073b04f955d Mon Sep 17 00:00:00 2001 From: David Cook Date: Fri, 28 Aug 2020 23:12:11 -0500 Subject: [PATCH 2252/3747] Test cargo miri target selection --- test-cargo-miri/run-test.py | 12 ++++++++++++ test-cargo-miri/test.stdout.ref4 | 12 ++++++++++++ test-cargo-miri/test.stdout.ref5 | 6 ++++++ 3 files changed, 30 insertions(+) create mode 100644 test-cargo-miri/test.stdout.ref4 create mode 100644 test-cargo-miri/test.stdout.ref5 diff --git a/test-cargo-miri/run-test.py b/test-cargo-miri/run-test.py index 57b23a6a2afe2..a258c7f73c2d9 100755 --- a/test-cargo-miri/run-test.py +++ b/test-cargo-miri/run-test.py @@ -50,6 +50,10 @@ def test_cargo_miri_run(): cargo_miri("run"), "stdout.ref", "stderr.ref" ) + test("cargo miri run (with target)", + cargo_miri("run") + ["--bin", "cargo-miri-test"], + "stdout.ref", "stderr.ref" + ) test("cargo miri run (with arguments)", cargo_miri("run") + ["--", "--", "hello world", '"hello world"'], "stdout.ref", "stderr.ref2" @@ -68,6 +72,14 @@ def test_cargo_miri_test(): cargo_miri("test") + ["--", "-Zmiri-disable-isolation", "--", "num_cpus"], "test.stdout.ref3", "test.stderr.ref" ) + test("cargo miri test (test target)", + cargo_miri("test") + ["--test", "test"], + "test.stdout.ref4", "test.stderr.ref" + ) + test("cargo miri test (bin target)", + cargo_miri("test") + ["--bin", "cargo-miri-test"], + "test.stdout.ref5", "test.stderr.ref" + ) os.chdir(os.path.dirname(os.path.realpath(__file__))) diff --git a/test-cargo-miri/test.stdout.ref4 b/test-cargo-miri/test.stdout.ref4 new file mode 100644 index 0000000000000..b6403bf6c0916 --- /dev/null +++ b/test-cargo-miri/test.stdout.ref4 @@ -0,0 +1,12 @@ + +running 7 tests +test do_panic ... ok +test does_not_work_on_miri ... ignored +test entropy_rng ... ok +test fail_index_check ... ok +test num_cpus ... ok +test simple1 ... ok +test simple2 ... ok + +test result: ok. 6 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out + diff --git a/test-cargo-miri/test.stdout.ref5 b/test-cargo-miri/test.stdout.ref5 new file mode 100644 index 0000000000000..4caa30a7f0e50 --- /dev/null +++ b/test-cargo-miri/test.stdout.ref5 @@ -0,0 +1,6 @@ + +running 1 test +test test::rng ... ok + +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out + From 3ba7f46058db2baa7e03cbca5570a4a4c1ac832b Mon Sep 17 00:00:00 2001 From: David Cook Date: Sat, 29 Aug 2020 21:38:37 -0500 Subject: [PATCH 2253/3747] Move panic payload state from Machine to Thread --- src/machine.rs | 6 -- src/shims/panic.rs | 10 +-- src/thread.rs | 37 +++++++++ tests/run-pass/panic/concurrent-panic.rs | 80 ++++++++++++++++++++ tests/run-pass/panic/concurrent-panic.stderr | 4 + 5 files changed, 124 insertions(+), 13 deletions(-) create mode 100644 tests/run-pass/panic/concurrent-panic.rs create mode 100644 tests/run-pass/panic/concurrent-panic.stderr diff --git a/src/machine.rs b/src/machine.rs index b76159694d822..ebe3c509ad874 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -252,11 +252,6 @@ pub struct Evaluator<'mir, 'tcx> { pub(crate) file_handler: shims::posix::FileHandler, pub(crate) dir_handler: shims::posix::DirHandler, - /// The temporary used for storing the argument of - /// the call to `miri_start_panic` (the panic payload) when unwinding. - /// This is pointer-sized, and matches the `Payload` type in `src/libpanic_unwind/miri.rs`. - pub(crate) panic_payload: Option>, - /// The "time anchor" for this machine's monotone clock (for `Instant` simulation). pub(crate) time_anchor: Instant, @@ -291,7 +286,6 @@ impl<'mir, 'tcx> Evaluator<'mir, 'tcx> { validate, file_handler: Default::default(), dir_handler: Default::default(), - panic_payload: None, time_anchor: Instant::now(), layouts, threads: ThreadManager::default(), diff --git a/src/shims/panic.rs b/src/shims/panic.rs index 45a41b9b7be06..b9d8ceb1dfb58 100644 --- a/src/shims/panic.rs +++ b/src/shims/panic.rs @@ -48,11 +48,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Get the raw pointer stored in arg[0] (the panic payload). let &[payload] = check_arg_count(args)?; let payload = this.read_scalar(payload)?.check_init()?; - assert!( - this.machine.panic_payload.is_none(), - "the panic runtime should avoid double-panics" - ); - this.machine.panic_payload = Some(payload); + this.set_panic_payload(payload); // Jump to the unwind block to begin unwinding. this.unwind_to_block(unwind); @@ -132,9 +128,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // We set the return value of `try` to 1, since there was a panic. this.write_scalar(Scalar::from_i32(1), catch_unwind.dest)?; - // `panic_payload` holds what was passed to `miri_start_panic`. + // The Thread's `panic_payload` holds what was passed to `miri_start_panic`. // This is exactly the second argument we need to pass to `catch_fn`. - let payload = this.machine.panic_payload.take().unwrap(); + let payload = this.take_panic_payload(); // Push the `catch_fn` stackframe. let f_instance = this.memory.get_fn(catch_unwind.catch_fn)?.as_instance()?; diff --git a/src/thread.rs b/src/thread.rs index cffbec93c5cab..dd5358bfb5e06 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -106,12 +106,21 @@ enum ThreadJoinStatus { /// A thread. pub struct Thread<'mir, 'tcx> { state: ThreadState, + /// Name of the thread. thread_name: Option>, + /// The virtual call stack. stack: Vec>>, + /// The join status. join_status: ThreadJoinStatus, + + /// The temporary used for storing the argument of + /// the call to `miri_start_panic` (the panic payload) when unwinding. + /// This is pointer-sized, and matches the `Payload` type in `src/libpanic_unwind/miri.rs`. + panic_payload: Option>, + } impl<'mir, 'tcx> Thread<'mir, 'tcx> { @@ -150,6 +159,7 @@ impl<'mir, 'tcx> Default for Thread<'mir, 'tcx> { thread_name: None, stack: Vec::new(), join_status: ThreadJoinStatus::Joinable, + panic_payload: None, } } } @@ -509,6 +519,21 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { throw_machine_stop!(TerminationInfo::Deadlock); } } + + /// Store the panic payload when beginning unwinding. + fn set_panic_payload(&mut self, payload: Scalar) { + let thread = self.active_thread_mut(); + assert!( + thread.panic_payload.is_none(), + "the panic runtime should avoid double-panics" + ); + thread.panic_payload = Some(payload); + } + + /// Retrieve the panic payload, for use in `catch_unwind`. + fn take_panic_payload(&mut self) -> Scalar { + self.active_thread_mut().panic_payload.take().unwrap() + } } // Public interface to thread management. @@ -686,4 +711,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } Ok(()) } + + /// Store the panic payload when beginning unwinding. + fn set_panic_payload(&mut self, payload: Scalar) { + let this = self.eval_context_mut(); + this.machine.threads.set_panic_payload(payload); + } + + /// Retrieve the panic payload, for use in `catch_unwind`. + fn take_panic_payload(&mut self) -> Scalar { + let this = self.eval_context_mut(); + this.machine.threads.take_panic_payload() + } } diff --git a/tests/run-pass/panic/concurrent-panic.rs b/tests/run-pass/panic/concurrent-panic.rs new file mode 100644 index 0000000000000..e798f514711f8 --- /dev/null +++ b/tests/run-pass/panic/concurrent-panic.rs @@ -0,0 +1,80 @@ +// ignore-windows: Concurrency on Windows is not supported yet. +use std::sync::{Arc, Condvar, Mutex}; +use std::thread::{spawn, JoinHandle}; + +struct BlockOnDrop(Option>); + +impl BlockOnDrop { + fn new(handle: JoinHandle<()>) -> BlockOnDrop { + BlockOnDrop(Some(handle)) + } +} + +impl Drop for BlockOnDrop { + fn drop(&mut self) { + let _ = self.0.take().unwrap().join(); + } +} + +/// Cause a panic in one thread while another thread is unwinding. +fn main() { + let t1_started_pair = Arc::new((Mutex::new(false), Condvar::new())); + let t2_started_pair = Arc::new((Mutex::new(false), Condvar::new())); + + let t1_continue_mutex = Arc::new(Mutex::new(())); + let t1_continue_guard = t1_continue_mutex.lock(); + + let t1 = { + let t1_started_pair = t1_started_pair.clone(); + let t1_continue_mutex = t1_continue_mutex.clone(); + spawn(move || { + let (mutex, condvar) = &*t1_started_pair; + *mutex.lock().unwrap() = true; + condvar.notify_one(); + + drop(t1_continue_mutex.lock()); + panic!("panic in thread 1"); + }) + }; + let t2 = { + let t2_started_pair = t2_started_pair.clone(); + let block_on_drop = BlockOnDrop::new(t1); + spawn(move || { + let _ = block_on_drop; + + let (mutex, condvar) = &*t2_started_pair; + *mutex.lock().unwrap() = true; + condvar.notify_one(); + + panic!("panic in thread 2"); + }) + }; + + // Wait for thread 1 to signal it has started. + let (t1_started_mutex, t1_started_condvar) = &*t1_started_pair; + let mut t1_started_guard = t1_started_mutex.lock().unwrap(); + while !*t1_started_guard { + t1_started_guard = t1_started_condvar.wait(t1_started_guard).unwrap(); + } + // Thread 1 should now be blocked waiting on t1_continue_mutex. + + // Wait for thread 2 to signal it has started. + let (t2_started_mutex, t2_started_condvar) = &*t2_started_pair; + let mut t2_started_guard = t2_started_mutex.lock().unwrap(); + while !*t2_started_guard { + t2_started_guard = t2_started_condvar.wait(t2_started_guard).unwrap(); + } + // Thread 2 should now have already panicked and be in the middle of + // unwinding. It should now be blocked on joining thread 1. + + // Unlock t1_continue_mutex, and allow thread 1 to proceed. + drop(t1_continue_guard); + // Thread 1 will panic the next time it is scheduled. This will test the + // behavior of interest to this test, whether Miri properly handles + // concurrent panics in two different threads. + + // Block the main thread on waiting to join thread 2. Thread 2 should + // already be blocked on joining thread 1, so thread 1 will be scheduled + // to run next, as it is the only ready thread. + assert!(t2.join().is_err()); +} diff --git a/tests/run-pass/panic/concurrent-panic.stderr b/tests/run-pass/panic/concurrent-panic.stderr new file mode 100644 index 0000000000000..6652137c9659e --- /dev/null +++ b/tests/run-pass/panic/concurrent-panic.stderr @@ -0,0 +1,4 @@ +warning: thread support is experimental. For example, Miri does not detect data races yet. + +thread '' panicked at 'panic in thread 2', $DIR/concurrent-panic.rs:49:13 +thread '' panicked at 'panic in thread 1', $DIR/concurrent-panic.rs:36:13 From da2f268443bcaf889896dd3ca4e6635b9e5cc4b5 Mon Sep 17 00:00:00 2001 From: David Cook Date: Mon, 31 Aug 2020 19:32:14 -0500 Subject: [PATCH 2254/3747] Review comments --- src/shims/panic.rs | 9 +++-- src/thread.rs | 36 ++++---------------- tests/run-pass/panic/concurrent-panic.rs | 29 +++++++++++----- tests/run-pass/panic/concurrent-panic.stderr | 11 ++++-- 4 files changed, 43 insertions(+), 42 deletions(-) diff --git a/src/shims/panic.rs b/src/shims/panic.rs index b9d8ceb1dfb58..f907b76b679c4 100644 --- a/src/shims/panic.rs +++ b/src/shims/panic.rs @@ -48,7 +48,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Get the raw pointer stored in arg[0] (the panic payload). let &[payload] = check_arg_count(args)?; let payload = this.read_scalar(payload)?.check_init()?; - this.set_panic_payload(payload); + let thread = this.active_thread_mut(); + assert!( + thread.panic_payload.is_none(), + "the panic runtime should avoid double-panics" + ); + thread.panic_payload = Some(payload); // Jump to the unwind block to begin unwinding. this.unwind_to_block(unwind); @@ -130,7 +135,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // The Thread's `panic_payload` holds what was passed to `miri_start_panic`. // This is exactly the second argument we need to pass to `catch_fn`. - let payload = this.take_panic_payload(); + let payload = this.active_thread_mut().panic_payload.take().unwrap(); // Push the `catch_fn` stackframe. let f_instance = this.memory.get_fn(catch_unwind.catch_fn)?.as_instance()?; diff --git a/src/thread.rs b/src/thread.rs index dd5358bfb5e06..a542d0895b251 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -119,8 +119,7 @@ pub struct Thread<'mir, 'tcx> { /// The temporary used for storing the argument of /// the call to `miri_start_panic` (the panic payload) when unwinding. /// This is pointer-sized, and matches the `Payload` type in `src/libpanic_unwind/miri.rs`. - panic_payload: Option>, - + pub(crate) panic_payload: Option>, } impl<'mir, 'tcx> Thread<'mir, 'tcx> { @@ -519,21 +518,6 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { throw_machine_stop!(TerminationInfo::Deadlock); } } - - /// Store the panic payload when beginning unwinding. - fn set_panic_payload(&mut self, payload: Scalar) { - let thread = self.active_thread_mut(); - assert!( - thread.panic_payload.is_none(), - "the panic runtime should avoid double-panics" - ); - thread.panic_payload = Some(payload); - } - - /// Retrieve the panic payload, for use in `catch_unwind`. - fn take_panic_payload(&mut self) -> Scalar { - self.active_thread_mut().panic_payload.take().unwrap() - } } // Public interface to thread management. @@ -593,6 +577,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.machine.threads.get_active_thread_id() } + #[inline] + fn active_thread_mut(&mut self) -> &mut Thread<'mir, 'tcx> { + let this = self.eval_context_mut(); + this.machine.threads.active_thread_mut() + } + #[inline] fn get_total_thread_count(&self) -> usize { let this = self.eval_context_ref(); @@ -711,16 +701,4 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } Ok(()) } - - /// Store the panic payload when beginning unwinding. - fn set_panic_payload(&mut self, payload: Scalar) { - let this = self.eval_context_mut(); - this.machine.threads.set_panic_payload(payload); - } - - /// Retrieve the panic payload, for use in `catch_unwind`. - fn take_panic_payload(&mut self) -> Scalar { - let this = self.eval_context_mut(); - this.machine.threads.take_panic_payload() - } } diff --git a/tests/run-pass/panic/concurrent-panic.rs b/tests/run-pass/panic/concurrent-panic.rs index e798f514711f8..0ff5788e204d1 100644 --- a/tests/run-pass/panic/concurrent-panic.rs +++ b/tests/run-pass/panic/concurrent-panic.rs @@ -1,4 +1,8 @@ // ignore-windows: Concurrency on Windows is not supported yet. + +//! Cause a panic in one thread while another thread is unwinding. This checks +//! that separate threads have their own panicking state. + use std::sync::{Arc, Condvar, Mutex}; use std::thread::{spawn, JoinHandle}; @@ -12,11 +16,12 @@ impl BlockOnDrop { impl Drop for BlockOnDrop { fn drop(&mut self) { + eprintln!("Thread 2 blocking on thread 1"); let _ = self.0.take().unwrap().join(); + eprintln!("Thread 1 has exited"); } } -/// Cause a panic in one thread while another thread is unwinding. fn main() { let t1_started_pair = Arc::new((Mutex::new(false), Condvar::new())); let t2_started_pair = Arc::new((Mutex::new(false), Condvar::new())); @@ -28,6 +33,7 @@ fn main() { let t1_started_pair = t1_started_pair.clone(); let t1_continue_mutex = t1_continue_mutex.clone(); spawn(move || { + eprintln!("Thread 1 starting, will block on mutex"); let (mutex, condvar) = &*t1_started_pair; *mutex.lock().unwrap() = true; condvar.notify_one(); @@ -36,6 +42,16 @@ fn main() { panic!("panic in thread 1"); }) }; + + // Wait for thread 1 to signal it has started. + let (t1_started_mutex, t1_started_condvar) = &*t1_started_pair; + let mut t1_started_guard = t1_started_mutex.lock().unwrap(); + while !*t1_started_guard { + t1_started_guard = t1_started_condvar.wait(t1_started_guard).unwrap(); + } + eprintln!("Thread 1 reported it has started"); + // Thread 1 should now be blocked waiting on t1_continue_mutex. + let t2 = { let t2_started_pair = t2_started_pair.clone(); let block_on_drop = BlockOnDrop::new(t1); @@ -50,24 +66,18 @@ fn main() { }) }; - // Wait for thread 1 to signal it has started. - let (t1_started_mutex, t1_started_condvar) = &*t1_started_pair; - let mut t1_started_guard = t1_started_mutex.lock().unwrap(); - while !*t1_started_guard { - t1_started_guard = t1_started_condvar.wait(t1_started_guard).unwrap(); - } - // Thread 1 should now be blocked waiting on t1_continue_mutex. - // Wait for thread 2 to signal it has started. let (t2_started_mutex, t2_started_condvar) = &*t2_started_pair; let mut t2_started_guard = t2_started_mutex.lock().unwrap(); while !*t2_started_guard { t2_started_guard = t2_started_condvar.wait(t2_started_guard).unwrap(); } + eprintln!("Thread 2 reported it has started"); // Thread 2 should now have already panicked and be in the middle of // unwinding. It should now be blocked on joining thread 1. // Unlock t1_continue_mutex, and allow thread 1 to proceed. + eprintln!("Unlocking mutex"); drop(t1_continue_guard); // Thread 1 will panic the next time it is scheduled. This will test the // behavior of interest to this test, whether Miri properly handles @@ -77,4 +87,5 @@ fn main() { // already be blocked on joining thread 1, so thread 1 will be scheduled // to run next, as it is the only ready thread. assert!(t2.join().is_err()); + eprintln!("Thread 2 has exited"); } diff --git a/tests/run-pass/panic/concurrent-panic.stderr b/tests/run-pass/panic/concurrent-panic.stderr index 6652137c9659e..d538efdb0e88f 100644 --- a/tests/run-pass/panic/concurrent-panic.stderr +++ b/tests/run-pass/panic/concurrent-panic.stderr @@ -1,4 +1,11 @@ warning: thread support is experimental. For example, Miri does not detect data races yet. -thread '' panicked at 'panic in thread 2', $DIR/concurrent-panic.rs:49:13 -thread '' panicked at 'panic in thread 1', $DIR/concurrent-panic.rs:36:13 +Thread 1 starting, will block on mutex +Thread 1 reported it has started +thread '' panicked at 'panic in thread 2', $DIR/concurrent-panic.rs:65:13 +Thread 2 blocking on thread 1 +Thread 2 reported it has started +Unlocking mutex +thread '' panicked at 'panic in thread 1', $DIR/concurrent-panic.rs:42:13 +Thread 1 has exited +Thread 2 has exited From 34664623066a762235004c08d0b9a188c0d65d2a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 1 Sep 2020 10:55:09 +0200 Subject: [PATCH 2255/3747] rustup, fix test --- rust-version | 2 +- tests/run-pass/stacked-borrows/interior_mutability.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/rust-version b/rust-version index f5fb708740208..6e9f26cbe4103 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -18b0585b52741ca158dfebef7968326e2704352e +d9cd4a33f53689bc0847775669a14f666a138fd7 diff --git a/tests/run-pass/stacked-borrows/interior_mutability.rs b/tests/run-pass/stacked-borrows/interior_mutability.rs index bd19f153deeb4..17e628a09f23e 100644 --- a/tests/run-pass/stacked-borrows/interior_mutability.rs +++ b/tests/run-pass/stacked-borrows/interior_mutability.rs @@ -54,7 +54,7 @@ fn into_interior_mutability() { let mut x: MaybeUninit<(Cell, u32)> = MaybeUninit::uninit(); x.as_ptr(); x.write((Cell::new(0), 1)); - let ptr = unsafe { x.get_ref() }; + let ptr = unsafe { x.assume_init_ref() }; assert_eq!(ptr.1, 1); } From 7a2c6812b94f5a96fa3a3b16ee4fbc885fc8676c Mon Sep 17 00:00:00 2001 From: David Cook Date: Mon, 31 Aug 2020 21:29:09 -0500 Subject: [PATCH 2256/3747] Per-thread errno storage --- src/eval.rs | 6 ------ src/helpers.rs | 23 +++++++++++++++++++---- src/machine.rs | 4 ---- src/shims/posix/linux/foreign_items.rs | 2 +- src/shims/posix/macos/foreign_items.rs | 2 +- src/thread.rs | 10 ++++++++++ tests/run-pass/libc.rs | 20 ++++++++++++++++++++ tests/run-pass/libc.stderr | 2 ++ 8 files changed, 53 insertions(+), 16 deletions(-) create mode 100644 tests/run-pass/libc.stderr diff --git a/src/eval.rs b/src/eval.rs index 8e4604c3360a6..e36a0019cdcb2 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -193,12 +193,6 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( StackPopCleanup::None { cleanup: true }, )?; - // Set the last_error to 0 - let errno_layout = ecx.machine.layouts.u32; - let errno_place = ecx.allocate(errno_layout, MiriMemoryKind::Machine.into()); - ecx.write_scalar(Scalar::from_u32(0), errno_place.into())?; - ecx.machine.last_error = Some(errno_place); - Ok((ecx, ret_place)) } diff --git a/src/helpers.rs b/src/helpers.rs index 0426115773d9e..f56818726235d 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -394,17 +394,32 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) } + /// Get last error variable as a place, lazily allocating thread-local storage for it if + /// necessary. + fn last_error_place(&mut self) -> InterpResult<'tcx, MPlaceTy<'tcx, Tag>> { + let this = self.eval_context_mut(); + if let Some(errno_place) = this.active_thread_ref().last_error { + Ok(errno_place) + } else { + let errno_layout = this.machine.layouts.u32; + let errno_place = this.allocate(errno_layout, MiriMemoryKind::Machine.into()); + this.write_scalar(Scalar::from_u32(0), errno_place.into())?; + this.active_thread_mut().last_error = Some(errno_place); + Ok(errno_place) + } + } + /// Sets the last error variable. fn set_last_error(&mut self, scalar: Scalar) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - let errno_place = this.machine.last_error.unwrap(); + let errno_place = this.last_error_place()?; this.write_scalar(scalar, errno_place.into()) } /// Gets the last error variable. - fn get_last_error(&self) -> InterpResult<'tcx, Scalar> { - let this = self.eval_context_ref(); - let errno_place = this.machine.last_error.unwrap(); + fn get_last_error(&mut self) -> InterpResult<'tcx, Scalar> { + let this = self.eval_context_mut(); + let errno_place = this.last_error_place()?; this.read_scalar(errno_place.into())?.check_init() } diff --git a/src/machine.rs b/src/machine.rs index ebe3c509ad874..6defb2d053aa7 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -236,9 +236,6 @@ pub struct Evaluator<'mir, 'tcx> { pub(crate) argv: Option>, pub(crate) cmd_line: Option>, - /// Last OS error location in memory. It is a 32-bit integer. - pub(crate) last_error: Option>, - /// TLS state. pub(crate) tls: TlsData<'tcx>, @@ -280,7 +277,6 @@ impl<'mir, 'tcx> Evaluator<'mir, 'tcx> { argc: None, argv: None, cmd_line: None, - last_error: None, tls: TlsData::default(), communicate, validate, diff --git a/src/shims/posix/linux/foreign_items.rs b/src/shims/posix/linux/foreign_items.rs index ccb0ef8226e6f..357c55c926f13 100644 --- a/src/shims/posix/linux/foreign_items.rs +++ b/src/shims/posix/linux/foreign_items.rs @@ -21,7 +21,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // errno "__errno_location" => { let &[] = check_arg_count(args)?; - let errno_place = this.machine.last_error.unwrap(); + let errno_place = this.last_error_place()?; this.write_scalar(errno_place.to_ref().to_scalar()?, dest)?; } diff --git a/src/shims/posix/macos/foreign_items.rs b/src/shims/posix/macos/foreign_items.rs index 2e7258c800ac3..72ec7a5d97022 100644 --- a/src/shims/posix/macos/foreign_items.rs +++ b/src/shims/posix/macos/foreign_items.rs @@ -20,7 +20,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // errno "__error" => { let &[] = check_arg_count(args)?; - let errno_place = this.machine.last_error.unwrap(); + let errno_place = this.last_error_place()?; this.write_scalar(errno_place.to_ref().to_scalar()?, dest)?; } diff --git a/src/thread.rs b/src/thread.rs index a542d0895b251..eeaee7dc44d5d 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -120,6 +120,9 @@ pub struct Thread<'mir, 'tcx> { /// the call to `miri_start_panic` (the panic payload) when unwinding. /// This is pointer-sized, and matches the `Payload` type in `src/libpanic_unwind/miri.rs`. pub(crate) panic_payload: Option>, + + /// Last OS error location in memory. It is a 32-bit integer. + pub(crate) last_error: Option>, } impl<'mir, 'tcx> Thread<'mir, 'tcx> { @@ -159,6 +162,7 @@ impl<'mir, 'tcx> Default for Thread<'mir, 'tcx> { stack: Vec::new(), join_status: ThreadJoinStatus::Joinable, panic_payload: None, + last_error: None, } } } @@ -583,6 +587,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.machine.threads.active_thread_mut() } + #[inline] + fn active_thread_ref(&self) -> &Thread<'mir, 'tcx> { + let this = self.eval_context_ref(); + this.machine.threads.active_thread_ref() + } + #[inline] fn get_total_thread_count(&self) -> usize { let this = self.eval_context_ref(); diff --git a/tests/run-pass/libc.rs b/tests/run-pass/libc.rs index 6f30cb5a9150f..ab9a690fe1d77 100644 --- a/tests/run-pass/libc.rs +++ b/tests/run-pass/libc.rs @@ -212,6 +212,24 @@ fn test_prctl_thread_name() { } } +/// Tests whether each thread has its own `__errno_location`. +fn test_thread_local_errno() { + #[cfg(not(target_os = "macos"))] + use libc::__errno_location; + #[cfg(target_os = "macos")] + use libc::__error as __errno_location; + + unsafe { + *__errno_location() = 0xBEEF; + std::thread::spawn(|| { + assert_eq!(*__errno_location(), 0); + *__errno_location() = 0xBAD1DEA; + assert_eq!(*__errno_location(), 0xBAD1DEA); + }).join().unwrap(); + assert_eq!(*__errno_location(), 0xBEEF); + } +} + fn main() { #[cfg(target_os = "linux")] test_posix_fadvise(); @@ -229,4 +247,6 @@ fn main() { #[cfg(target_os = "linux")] test_prctl_thread_name(); + + test_thread_local_errno(); } diff --git a/tests/run-pass/libc.stderr b/tests/run-pass/libc.stderr new file mode 100644 index 0000000000000..2dbfb7721d368 --- /dev/null +++ b/tests/run-pass/libc.stderr @@ -0,0 +1,2 @@ +warning: thread support is experimental. For example, Miri does not detect data races yet. + From a6746ad893c7f6cbcb367276534e329110e75d83 Mon Sep 17 00:00:00 2001 From: David Cook Date: Wed, 2 Sep 2020 20:58:41 -0500 Subject: [PATCH 2257/3747] Add comment --- src/helpers.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/helpers.rs b/src/helpers.rs index f56818726235d..39af9d3143aaf 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -401,6 +401,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if let Some(errno_place) = this.active_thread_ref().last_error { Ok(errno_place) } else { + // Allocate new place, set initial value to 0. let errno_layout = this.machine.layouts.u32; let errno_place = this.allocate(errno_layout, MiriMemoryKind::Machine.into()); this.write_scalar(Scalar::from_u32(0), errno_place.into())?; From 4f2f87b2dff5b586d3130737716fcbb3d3086d57 Mon Sep 17 00:00:00 2001 From: LeSeulArtichaut Date: Fri, 4 Sep 2020 22:03:45 +0200 Subject: [PATCH 2258/3747] Change `ty.kind` -> `ty.kind()` --- rust-version | 2 +- src/helpers.rs | 2 +- src/shims/intrinsics.rs | 8 ++++---- src/stacked_borrows.rs | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/rust-version b/rust-version index 6e9f26cbe4103..797f6e825a742 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -d9cd4a33f53689bc0847775669a14f666a138fd7 +d2454643e137bde519786ee9e650c455d7ad6f34 diff --git a/src/helpers.rs b/src/helpers.rs index 39af9d3143aaf..d3fcb1c53dba1 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -280,7 +280,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Hook to detect `UnsafeCell`. fn visit_value(&mut self, v: MPlaceTy<'tcx, Tag>) -> InterpResult<'tcx> { trace!("UnsafeCellVisitor: {:?} {:?}", *v, v.layout.ty); - let is_unsafe_cell = match v.layout.ty.kind { + let is_unsafe_cell = match v.layout.ty.kind() { ty::Adt(adt, _) => Some(adt.did) == self.ecx.tcx.lang_items().unsafe_cell_type(), _ => false, diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 53d4d08eba0dc..4d8801f178874 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -299,7 +299,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let &[val] = check_arg_count(args)?; let val = this.read_immediate(val)?; - let res = match val.layout.ty.kind { + let res = match val.layout.ty.kind() { ty::Float(FloatTy::F32) => { this.float_to_int_unchecked(val.to_scalar()?.to_f32()?, dest.layout.ty)? } @@ -528,10 +528,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let f = f.round_to_integral(Round::TowardZero).value; // Step 2: Cast the truncated float to the target integer type and see if we lose any information in this step. - Ok(match dest_ty.kind { + Ok(match dest_ty.kind() { // Unsigned ty::Uint(t) => { - let size = Integer::from_attr(this, attr::IntType::UnsignedInt(t)).size(); + let size = Integer::from_attr(this, attr::IntType::UnsignedInt(*t)).size(); let res = f.to_u128(size.bits_usize()); if res.status.is_empty() { // No status flags means there was no further rounding or other loss of precision. @@ -546,7 +546,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // Signed ty::Int(t) => { - let size = Integer::from_attr(this, attr::IntType::SignedInt(t)).size(); + let size = Integer::from_attr(this, attr::IntType::SignedInt(*t)).size(); let res = f.to_i128(size.bits_usize()); if res.status.is_empty() { // No status flags means there was no further rounding or other loss of precision. diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index cefe334574b44..817ed99d2bb27 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -623,7 +623,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Cannot use `builtin_deref` because that reports *immutable* for `Box`, // making it useless. fn qualify(ty: ty::Ty<'_>, kind: RetagKind) -> Option<(RefKind, bool)> { - match ty.kind { + match ty.kind() { // References are simple. ty::Ref(_, _, Mutability::Mut) => Some(( RefKind::Unique { two_phase: kind == RetagKind::TwoPhase }, From 6d323e10324298a8fc7c268079c7999794525a7a Mon Sep 17 00:00:00 2001 From: David Cook Date: Sun, 6 Sep 2020 17:08:41 -0500 Subject: [PATCH 2259/3747] Refactor timespec parsing, improve error handling --- src/helpers.rs | 37 ++++++++++++++++++ src/shims/posix/sync.rs | 39 ++++++++----------- .../run-pass/concurrency/libc_pthread_cond.rs | 20 ++++++++++ 3 files changed, 74 insertions(+), 22 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index d3fcb1c53dba1..f8bf9598c14f7 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -1,6 +1,7 @@ use std::convert::{TryFrom, TryInto}; use std::mem; use std::num::NonZeroUsize; +use std::time::Duration; use log::trace; @@ -41,6 +42,9 @@ fn try_resolve_did<'mir, 'tcx>(tcx: TyCtxt<'tcx>, path: &[&str]) -> Option: crate::MiriEvalContextExt<'mir, 'tcx> { /// Gets an instance for a path. fn resolve_path(&self, path: &[&str]) -> ty::Instance<'tcx> { @@ -512,6 +516,39 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let value_place = op_place.offset(offset, MemPlaceMeta::None, layout, this)?; this.write_scalar(value, value_place.into()) } + + /// Parse a `timespec` struct and return it as a `std::time::Duration`. The outer `Result` is + /// for interpreter errors encountered while reading memory, and the inner `Result` indicates + /// whether the value in the `timespec` struct is invalid. Some libc functions will return + /// `EINVAL` if the struct's value is invalid. + fn read_timespec( + &mut self, + timespec_ptr_op: OpTy<'tcx, Tag>, + ) -> InterpResult<'tcx, Result> { + let this = self.eval_context_mut(); + let tp = this.deref_operand(timespec_ptr_op)?; + let seconds_place = this.mplace_field(tp, 0)?; + let seconds_scalar = this.read_scalar(seconds_place.into())?; + let seconds = seconds_scalar.to_machine_isize(this)?; + let nanoseconds_place = this.mplace_field(tp, 1)?; + let nanoseconds_scalar = this.read_scalar(nanoseconds_place.into())?; + let nanoseconds = nanoseconds_scalar.to_machine_isize(this)?; + + let seconds: u64 = if let Ok(s) = seconds.try_into() { + s + } else { + return Ok(Err(TimespecError)); + }; + let nanoseconds: u32 = if let Ok(ns) = nanoseconds.try_into() { + if ns >= 1_000_000_000 { + return Ok(Err(TimespecError)); + } + ns + } else { + return Ok(Err(TimespecError)); + }; + Ok(Ok(Duration::new(seconds, nanoseconds))) + } } /// Check that the number of args is what we expect. diff --git a/src/shims/posix/sync.rs b/src/shims/posix/sync.rs index 28a45b194771e..94704bff32acf 100644 --- a/src/shims/posix/sync.rs +++ b/src/shims/posix/sync.rs @@ -1,11 +1,10 @@ -use std::convert::TryInto; -use std::time::{Duration, SystemTime}; +use std::time::SystemTime; use crate::*; +use helpers::TimespecError; use stacked_borrows::Tag; use thread::Time; - // pthread_mutexattr_t is either 4 or 8 bytes, depending on the platform. // Our chosen memory layout for emulation (does not have to match the platform layout!): @@ -698,25 +697,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let mutex_id = mutex_get_or_create_id(this, mutex_op)?; let active_thread = this.get_active_thread(); - release_cond_mutex_and_block(this, active_thread, mutex_id)?; - this.condvar_wait(id, active_thread, mutex_id); - - // We return success for now and override it in the timeout callback. - this.write_scalar(Scalar::from_i32(0), dest)?; - // Extract the timeout. let clock_id = cond_get_clock_id(this, cond_op)?.to_i32()?; - let duration = { - let tp = this.deref_operand(abstime_op)?; - let seconds_place = this.mplace_field(tp, 0)?; - let seconds = this.read_scalar(seconds_place.into())?; - let nanoseconds_place = this.mplace_field(tp, 1)?; - let nanoseconds = this.read_scalar(nanoseconds_place.into())?; - let (seconds, nanoseconds) = ( - seconds.to_machine_usize(this)?, - nanoseconds.to_machine_usize(this)?.try_into().unwrap(), - ); - Duration::new(seconds, nanoseconds) + let duration = match this.read_timespec(abstime_op)? { + Ok(duration) => duration, + Err(TimespecError) => { + let einval = this.eval_libc("EINVAL")?; + this.write_scalar(einval, dest)?; + return Ok(()); + } }; let timeout_time = if clock_id == this.eval_libc_i32("CLOCK_REALTIME")? { @@ -727,6 +716,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx throw_unsup_format!("unsupported clock id: {}", clock_id); }; + release_cond_mutex_and_block(this, active_thread, mutex_id)?; + this.condvar_wait(id, active_thread, mutex_id); + + // We return success for now and override it in the timeout callback. + this.write_scalar(Scalar::from_i32(0), dest)?; + // Register the timeout callback. this.register_timeout_callback( active_thread, @@ -740,8 +735,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ecx.condvar_remove_waiter(id, active_thread); // Set the return value: we timed out. - let timeout = ecx.eval_libc_i32("ETIMEDOUT")?; - ecx.write_scalar(Scalar::from_i32(timeout), dest)?; + let etimedout = ecx.eval_libc("ETIMEDOUT")?; + ecx.write_scalar(etimedout, dest)?; Ok(()) }), diff --git a/tests/run-pass/concurrency/libc_pthread_cond.rs b/tests/run-pass/concurrency/libc_pthread_cond.rs index 8aa3b210f4b0f..e1ca63f9ca437 100644 --- a/tests/run-pass/concurrency/libc_pthread_cond.rs +++ b/tests/run-pass/concurrency/libc_pthread_cond.rs @@ -37,6 +37,26 @@ fn test_timed_wait_timeout(clock_id: i32) { ); let elapsed_time = current_time.elapsed().as_millis(); assert!(900 <= elapsed_time && elapsed_time <= 1300); + + let invalid_timeout_1 = libc::timespec { tv_sec: now.tv_sec + 1, tv_nsec: 1_000_000_000 }; + assert_eq!( + libc::pthread_cond_timedwait( + &mut cond as *mut _, + &mut mutex as *mut _, + &invalid_timeout_1 + ), + libc::EINVAL + ); + let invalid_timeout_2 = libc::timespec { tv_sec: now.tv_sec + 1, tv_nsec: -1 }; + assert_eq!( + libc::pthread_cond_timedwait( + &mut cond as *mut _, + &mut mutex as *mut _, + &invalid_timeout_2 + ), + libc::EINVAL + ); + assert_eq!(libc::pthread_mutex_unlock(&mut mutex as *mut _), 0); assert_eq!(libc::pthread_mutex_destroy(&mut mutex as *mut _), 0); assert_eq!(libc::pthread_cond_destroy(&mut cond as *mut _), 0); From 417ac2939a87b84c70f4c8b3c2a343c253a5c5d1 Mon Sep 17 00:00:00 2001 From: David Cook Date: Sun, 6 Sep 2020 17:09:24 -0500 Subject: [PATCH 2260/3747] Implement libc::nanosleep shim --- src/shims/posix/foreign_items.rs | 5 ++++ src/shims/time.rs | 39 +++++++++++++++++++++++++++++++- tests/run-pass/time.rs | 11 +++++++++ 3 files changed, 54 insertions(+), 1 deletion(-) diff --git a/src/shims/posix/foreign_items.rs b/src/shims/posix/foreign_items.rs index 151ab95f1e3c4..26c743b360e06 100644 --- a/src/shims/posix/foreign_items.rs +++ b/src/shims/posix/foreign_items.rs @@ -382,6 +382,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let result = this.sched_yield()?; this.write_scalar(Scalar::from_i32(result), dest)?; } + "nanosleep" => { + let &[req, rem] = check_arg_count(args)?; + let result = this.nanosleep(req, rem)?; + this.write_scalar(Scalar::from_i32(result), dest)?; + } // Miscellaneous "isatty" => { diff --git a/src/shims/time.rs b/src/shims/time.rs index 193c87f7f099a..32c1ce888ed0e 100644 --- a/src/shims/time.rs +++ b/src/shims/time.rs @@ -3,7 +3,8 @@ use std::convert::TryFrom; use crate::stacked_borrows::Tag; use crate::*; -use helpers::{immty_from_int_checked, immty_from_uint_checked}; +use helpers::{immty_from_int_checked, immty_from_uint_checked, TimespecError}; +use thread::Time; /// Returns the time elapsed between the provided time and the unix epoch as a `Duration`. pub fn system_time_to_duration<'tcx>(time: &SystemTime) -> InterpResult<'tcx, Duration> { @@ -177,4 +178,40 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_packed_immediates(info, &imms)?; Ok(0) // KERN_SUCCESS } + + fn nanosleep( + &mut self, + req_op: OpTy<'tcx, Tag>, + _rem: OpTy<'tcx, Tag>, + ) -> InterpResult<'tcx, i32> { + // Signal handlers are not supported, so rem will never be written to. + + let this = self.eval_context_mut(); + + this.check_no_isolation("nanosleep")?; + + let duration = match this.read_timespec(req_op)? { + Ok(duration) => duration, + Err(TimespecError) => { + let einval = this.eval_libc("EINVAL")?; + this.set_last_error(einval)?; + return Ok(-1); + } + }; + let timeout_time = Time::RealTime(SystemTime::now().checked_add(duration).unwrap()); + + let active_thread = this.get_active_thread(); + this.block_thread(active_thread); + + this.register_timeout_callback( + active_thread, + timeout_time, + Box::new(move |ecx| { + ecx.unblock_thread(active_thread); + Ok(()) + }), + ); + + Ok(0) + } } diff --git a/tests/run-pass/time.rs b/tests/run-pass/time.rs index d430062a15333..ae287234d1774 100644 --- a/tests/run-pass/time.rs +++ b/tests/run-pass/time.rs @@ -8,6 +8,14 @@ fn duration_sanity(diff: Duration) { assert!(diff.as_millis() < 500); } +#[cfg(unix)] +fn test_sleep() { + let before = Instant::now(); + std::thread::sleep(Duration::from_millis(100)); + let after = Instant::now(); + assert!((after - before).as_millis() >= 100); +} + fn main() { // Check `SystemTime`. let now1 = SystemTime::now(); @@ -36,4 +44,7 @@ fn main() { assert_eq!(now1 + diff, now2); assert_eq!(now2 - diff, now1); duration_sanity(diff); + + #[cfg(unix)] + test_sleep(); } From 210f18d6c7962ae5125947e89d38cac34c65b6a8 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 7 Sep 2020 10:24:04 +0200 Subject: [PATCH 2261/3747] work around rustc optimizations becoming too smart --- ci.sh | 2 +- rust-version | 2 +- tests/compile-fail/invalid_bool.rs | 4 +++- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/ci.sh b/ci.sh index c2c36e1efc1fe..a1d0a38c4fb8c 100755 --- a/ci.sh +++ b/ci.sh @@ -25,7 +25,7 @@ function run_tests { ./miri test --locked if ! [ -n "${MIRI_TEST_TARGET+exists}" ]; then # Only for host architecture: tests with MIR optimizations - # FIXME:only testing level 1 because of . + # FIXME: only testing level 1 because of . MIRI_TEST_FLAGS="-Z mir-opt-level=1" ./miri test --locked fi # "miri test" has built the sysroot for us, now this should pass without diff --git a/rust-version b/rust-version index 797f6e825a742..d2cf18f80f171 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -d2454643e137bde519786ee9e650c455d7ad6f34 +e114d6228b948ce056de0bcdec2603c8e89d3727 diff --git a/tests/compile-fail/invalid_bool.rs b/tests/compile-fail/invalid_bool.rs index 6dee9ec3c91a8..933ee91c7d4d4 100644 --- a/tests/compile-fail/invalid_bool.rs +++ b/tests/compile-fail/invalid_bool.rs @@ -2,7 +2,9 @@ // Make sure we find these even with many checks disabled. // compile-flags: -Zmiri-disable-alignment-check -Zmiri-disable-stacked-borrows -Zmiri-disable-validation +fn dont_optimize(x: T) -> T { x } + fn main() { let b = unsafe { std::mem::transmute::(2) }; - let _x = b == true; //~ ERROR interpreting an invalid 8-bit value as a bool: 0x02 + let _x = b == dont_optimize(true); //~ ERROR interpreting an invalid 8-bit value as a bool: 0x02 } From d9bc19a7b078e75052167496fff3c4d91c7bbd66 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 7 Sep 2020 10:35:39 +0200 Subject: [PATCH 2262/3747] test opt-level 2 --- ci.sh | 4 ++-- tests/run-pass/float.rs | 2 ++ 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/ci.sh b/ci.sh index a1d0a38c4fb8c..915a4cf2fd3d1 100755 --- a/ci.sh +++ b/ci.sh @@ -25,8 +25,8 @@ function run_tests { ./miri test --locked if ! [ -n "${MIRI_TEST_TARGET+exists}" ]; then # Only for host architecture: tests with MIR optimizations - # FIXME: only testing level 1 because of . - MIRI_TEST_FLAGS="-Z mir-opt-level=1" ./miri test --locked + # FIXME: only testing level 2 because of . + MIRI_TEST_FLAGS="-Z mir-opt-level=2" ./miri test --locked fi # "miri test" has built the sysroot for us, now this should pass without # any interactive questions. diff --git a/tests/run-pass/float.rs b/tests/run-pass/float.rs index 0b89f11b0609b..ea6269c22fb98 100644 --- a/tests/run-pass/float.rs +++ b/tests/run-pass/float.rs @@ -1,3 +1,5 @@ +// compile-flags: -Zmir-opt-level=0 +// FIXME: Using opt-level 2 here makes the test take forever (https://github.com/rust-lang/rust/issues/76433). #![feature(stmt_expr_attributes)] use std::fmt::Debug; From 088af66f85ef5e885202ad258670936f8edc3c53 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 7 Sep 2020 11:16:16 +0200 Subject: [PATCH 2263/3747] better optimization suppression Co-authored-by: bjorn3 --- tests/compile-fail/invalid_bool.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/compile-fail/invalid_bool.rs b/tests/compile-fail/invalid_bool.rs index 933ee91c7d4d4..8d8cce1c7e50e 100644 --- a/tests/compile-fail/invalid_bool.rs +++ b/tests/compile-fail/invalid_bool.rs @@ -2,6 +2,7 @@ // Make sure we find these even with many checks disabled. // compile-flags: -Zmiri-disable-alignment-check -Zmiri-disable-stacked-borrows -Zmiri-disable-validation +#[inline(never)] fn dont_optimize(x: T) -> T { x } fn main() { From 029c851d7c0eee03178c96c890ec974262b2ee21 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 7 Sep 2020 11:22:49 +0200 Subject: [PATCH 2264/3747] another optimization work-around --- tests/compile-fail/unaligned_pointers/unaligned_ptr_zst.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/compile-fail/unaligned_pointers/unaligned_ptr_zst.rs b/tests/compile-fail/unaligned_pointers/unaligned_ptr_zst.rs index 169e98abf311a..a9db5ff7df39e 100644 --- a/tests/compile-fail/unaligned_pointers/unaligned_ptr_zst.rs +++ b/tests/compile-fail/unaligned_pointers/unaligned_ptr_zst.rs @@ -2,8 +2,8 @@ // compile-flags: -Zmiri-disable-validation fn main() { - for _ in 0..10 { // Try many times as this might work by chance. - let x = 2u8; + for i in 0..10 { // Try many times as this might work by chance. + let x = i as u8; let x = &x as *const _ as *const [u32; 0]; // This must fail because alignment is violated. Test specifically for loading ZST. let _x = unsafe { *x }; //~ERROR alignment 4 is required From 3ba1035d279e0acfc3aaf68e8bd055f2d1ffb205 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 7 Sep 2020 11:26:24 +0200 Subject: [PATCH 2265/3747] use standard black_box function --- tests/compile-fail/invalid_bool.rs | 6 ++---- tests/run-pass/float.rs | 7 ++----- tests/run-pass/u128.rs | 3 ++- 3 files changed, 6 insertions(+), 10 deletions(-) diff --git a/tests/compile-fail/invalid_bool.rs b/tests/compile-fail/invalid_bool.rs index 8d8cce1c7e50e..796d8220dc196 100644 --- a/tests/compile-fail/invalid_bool.rs +++ b/tests/compile-fail/invalid_bool.rs @@ -1,11 +1,9 @@ // Validation makes this fail in the wrong place // Make sure we find these even with many checks disabled. // compile-flags: -Zmiri-disable-alignment-check -Zmiri-disable-stacked-borrows -Zmiri-disable-validation - -#[inline(never)] -fn dont_optimize(x: T) -> T { x } +#![feature(test)] fn main() { let b = unsafe { std::mem::transmute::(2) }; - let _x = b == dont_optimize(true); //~ ERROR interpreting an invalid 8-bit value as a bool: 0x02 + let _x = b == std::hint::black_box(true); //~ ERROR interpreting an invalid 8-bit value as a bool: 0x02 } diff --git a/tests/run-pass/float.rs b/tests/run-pass/float.rs index ea6269c22fb98..327ea17731a8d 100644 --- a/tests/run-pass/float.rs +++ b/tests/run-pass/float.rs @@ -1,7 +1,8 @@ // compile-flags: -Zmir-opt-level=0 // FIXME: Using opt-level 2 here makes the test take forever (https://github.com/rust-lang/rust/issues/76433). -#![feature(stmt_expr_attributes)] +#![feature(stmt_expr_attributes, test)] use std::fmt::Debug; +use std::hint::black_box; // Helper function to avoid promotion so that this tests "run-time" casts, not CTFE. // Doesn't make a big difference when running this in Miri, but it means we can compare this @@ -341,10 +342,6 @@ fn ops() { /// Tests taken from rustc test suite. /// -// Poor-man's black-box -#[inline(never)] -fn black_box(x: T) -> T { x } - macro_rules! test { ($val:expr, $src_ty:ident -> $dest_ty:ident, $expected:expr) => ( // black_box disables constant evaluation to test run-time conversions: diff --git a/tests/run-pass/u128.rs b/tests/run-pass/u128.rs index a2ca7746b1c05..bbc667c5ddebb 100644 --- a/tests/run-pass/u128.rs +++ b/tests/run-pass/u128.rs @@ -1,4 +1,5 @@ -fn b(t: T) -> T { t } +#![feature(test)] +use std::hint::black_box as b; fn main() { let x: u128 = 0xFFFF_FFFF_FFFF_FFFF__FFFF_FFFF_FFFF_FFFF; From 3fdbc0fd3f4e0117d708cac58b35fa841eed19af Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 7 Sep 2020 13:10:31 +0200 Subject: [PATCH 2266/3747] fix referenced issue --- tests/run-pass/float.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/run-pass/float.rs b/tests/run-pass/float.rs index 327ea17731a8d..88f841eae74d9 100644 --- a/tests/run-pass/float.rs +++ b/tests/run-pass/float.rs @@ -1,5 +1,5 @@ // compile-flags: -Zmir-opt-level=0 -// FIXME: Using opt-level 2 here makes the test take forever (https://github.com/rust-lang/rust/issues/76433). +// FIXME: Using opt-level 2 here makes the test take forever (https://github.com/rust-lang/rust/issues/73717). #![feature(stmt_expr_attributes, test)] use std::fmt::Debug; use std::hint::black_box; From 33e928c9ca456f36ac662657333d6ca046be17bd Mon Sep 17 00:00:00 2001 From: David Cook Date: Mon, 7 Sep 2020 10:54:39 -0500 Subject: [PATCH 2267/3747] Review comments --- src/helpers.rs | 23 +++++++++---------- src/shims/posix/sync.rs | 5 ++-- src/shims/time.rs | 8 +++---- .../run-pass/concurrency/libc_pthread_cond.rs | 12 ++++++++++ tests/run-pass/time.rs | 1 + 5 files changed, 30 insertions(+), 19 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index f8bf9598c14f7..f5094b169f9ed 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -42,9 +42,6 @@ fn try_resolve_did<'mir, 'tcx>(tcx: TyCtxt<'tcx>, path: &[&str]) -> Option: crate::MiriEvalContextExt<'mir, 'tcx> { /// Gets an instance for a path. fn resolve_path(&self, path: &[&str]) -> ty::Instance<'tcx> { @@ -517,14 +514,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(value, value_place.into()) } - /// Parse a `timespec` struct and return it as a `std::time::Duration`. The outer `Result` is - /// for interpreter errors encountered while reading memory, and the inner `Result` indicates - /// whether the value in the `timespec` struct is invalid. Some libc functions will return - /// `EINVAL` if the struct's value is invalid. + /// Parse a `timespec` struct and return it as a `std::time::Duration`. It returns `None` + /// if the value in the `timespec` struct is invalid. Some libc functions will return + /// `EINVAL` in this case. fn read_timespec( &mut self, timespec_ptr_op: OpTy<'tcx, Tag>, - ) -> InterpResult<'tcx, Result> { + ) -> InterpResult<'tcx, Option> { let this = self.eval_context_mut(); let tp = this.deref_operand(timespec_ptr_op)?; let seconds_place = this.mplace_field(tp, 0)?; @@ -537,17 +533,20 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let seconds: u64 = if let Ok(s) = seconds.try_into() { s } else { - return Ok(Err(TimespecError)); + // tv_sec must be non-negative. + return Ok(None); }; let nanoseconds: u32 = if let Ok(ns) = nanoseconds.try_into() { if ns >= 1_000_000_000 { - return Ok(Err(TimespecError)); + // tv_nsec must not be greater than 999,999,999. + return Ok(None); } ns } else { - return Ok(Err(TimespecError)); + // tv_nsec must be non-negative. + return Ok(None); }; - Ok(Ok(Duration::new(seconds, nanoseconds))) + Ok(Some(Duration::new(seconds, nanoseconds))) } } diff --git a/src/shims/posix/sync.rs b/src/shims/posix/sync.rs index 94704bff32acf..6918fb7fd7eca 100644 --- a/src/shims/posix/sync.rs +++ b/src/shims/posix/sync.rs @@ -1,7 +1,6 @@ use std::time::SystemTime; use crate::*; -use helpers::TimespecError; use stacked_borrows::Tag; use thread::Time; @@ -700,8 +699,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Extract the timeout. let clock_id = cond_get_clock_id(this, cond_op)?.to_i32()?; let duration = match this.read_timespec(abstime_op)? { - Ok(duration) => duration, - Err(TimespecError) => { + Some(duration) => duration, + None => { let einval = this.eval_libc("EINVAL")?; this.write_scalar(einval, dest)?; return Ok(()); diff --git a/src/shims/time.rs b/src/shims/time.rs index 32c1ce888ed0e..9d6d6ed38daab 100644 --- a/src/shims/time.rs +++ b/src/shims/time.rs @@ -3,7 +3,7 @@ use std::convert::TryFrom; use crate::stacked_borrows::Tag; use crate::*; -use helpers::{immty_from_int_checked, immty_from_uint_checked, TimespecError}; +use helpers::{immty_from_int_checked, immty_from_uint_checked}; use thread::Time; /// Returns the time elapsed between the provided time and the unix epoch as a `Duration`. @@ -191,14 +191,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.check_no_isolation("nanosleep")?; let duration = match this.read_timespec(req_op)? { - Ok(duration) => duration, - Err(TimespecError) => { + Some(duration) => duration, + None => { let einval = this.eval_libc("EINVAL")?; this.set_last_error(einval)?; return Ok(-1); } }; - let timeout_time = Time::RealTime(SystemTime::now().checked_add(duration).unwrap()); + let timeout_time = Time::Monotonic(Instant::now().checked_add(duration).unwrap()); let active_thread = this.get_active_thread(); this.block_thread(active_thread); diff --git a/tests/run-pass/concurrency/libc_pthread_cond.rs b/tests/run-pass/concurrency/libc_pthread_cond.rs index e1ca63f9ca437..d4e52bb3a97b0 100644 --- a/tests/run-pass/concurrency/libc_pthread_cond.rs +++ b/tests/run-pass/concurrency/libc_pthread_cond.rs @@ -38,6 +38,8 @@ fn test_timed_wait_timeout(clock_id: i32) { let elapsed_time = current_time.elapsed().as_millis(); assert!(900 <= elapsed_time && elapsed_time <= 1300); + // Test that invalid nanosecond values (above 10^9 or negative) are rejected with the + // correct error code. let invalid_timeout_1 = libc::timespec { tv_sec: now.tv_sec + 1, tv_nsec: 1_000_000_000 }; assert_eq!( libc::pthread_cond_timedwait( @@ -56,6 +58,16 @@ fn test_timed_wait_timeout(clock_id: i32) { ), libc::EINVAL ); + // Test that invalid second values (negative) are rejected with the correct error code. + let invalid_timeout_3 = libc::timespec { tv_sec: -1, tv_nsec: 0 }; + assert_eq!( + libc::pthread_cond_timedwait( + &mut cond as *mut _, + &mut mutex as *mut _, + &invalid_timeout_3 + ), + libc::EINVAL + ); assert_eq!(libc::pthread_mutex_unlock(&mut mutex as *mut _), 0); assert_eq!(libc::pthread_mutex_destroy(&mut mutex as *mut _), 0); diff --git a/tests/run-pass/time.rs b/tests/run-pass/time.rs index ae287234d1774..e76c8573c5162 100644 --- a/tests/run-pass/time.rs +++ b/tests/run-pass/time.rs @@ -8,6 +8,7 @@ fn duration_sanity(diff: Duration) { assert!(diff.as_millis() < 500); } +// Thus far, only `libc::nanosleep`, is implemented, not `c::Sleep`. #[cfg(unix)] fn test_sleep() { let before = Instant::now(); From 597360f49995c3c79f955ff7d61a52082382a412 Mon Sep 17 00:00:00 2001 From: David Cook Date: Mon, 7 Sep 2020 11:31:28 -0500 Subject: [PATCH 2268/3747] Simplify read_timespec error handling --- src/helpers.rs | 22 ++++++++-------------- 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index f5094b169f9ed..9e4bc21ab1b38 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -530,23 +530,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let nanoseconds_scalar = this.read_scalar(nanoseconds_place.into())?; let nanoseconds = nanoseconds_scalar.to_machine_isize(this)?; - let seconds: u64 = if let Ok(s) = seconds.try_into() { - s - } else { + Ok((move || { // tv_sec must be non-negative. - return Ok(None); - }; - let nanoseconds: u32 = if let Ok(ns) = nanoseconds.try_into() { - if ns >= 1_000_000_000 { + let seconds: u64 = seconds.try_into().ok()?; + // tv_nsec must be non-negative. + let nanoseconds: u32 = nanoseconds.try_into().ok()?; + if nanoseconds >= 1_000_000_000 { // tv_nsec must not be greater than 999,999,999. - return Ok(None); + return None; } - ns - } else { - // tv_nsec must be non-negative. - return Ok(None); - }; - Ok(Some(Duration::new(seconds, nanoseconds))) + Some(Duration::new(seconds, nanoseconds)) + })()) } } From 06aaea1d6bd94bb715e558c9a5c9c8af27be8895 Mon Sep 17 00:00:00 2001 From: David Cook Date: Mon, 7 Sep 2020 15:05:26 -0500 Subject: [PATCH 2269/3747] Update comment --- tests/run-pass/time.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/run-pass/time.rs b/tests/run-pass/time.rs index e76c8573c5162..cce29003e5676 100644 --- a/tests/run-pass/time.rs +++ b/tests/run-pass/time.rs @@ -8,7 +8,7 @@ fn duration_sanity(diff: Duration) { assert!(diff.as_millis() < 500); } -// Thus far, only `libc::nanosleep`, is implemented, not `c::Sleep`. +// Sleeping on Windows is not supported yet. #[cfg(unix)] fn test_sleep() { let before = Instant::now(); From b06f0d16a9dc66654b4e41f4e57be26e6ef4e302 Mon Sep 17 00:00:00 2001 From: David Cook Date: Mon, 7 Sep 2020 15:09:34 -0500 Subject: [PATCH 2270/3747] Use try block instead of closure --- src/helpers.rs | 8 ++++---- src/lib.rs | 1 + 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index 9e4bc21ab1b38..5bb620b563d3c 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -530,17 +530,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let nanoseconds_scalar = this.read_scalar(nanoseconds_place.into())?; let nanoseconds = nanoseconds_scalar.to_machine_isize(this)?; - Ok((move || { + Ok(try { // tv_sec must be non-negative. let seconds: u64 = seconds.try_into().ok()?; // tv_nsec must be non-negative. let nanoseconds: u32 = nanoseconds.try_into().ok()?; if nanoseconds >= 1_000_000_000 { // tv_nsec must not be greater than 999,999,999. - return None; + None? } - Some(Duration::new(seconds, nanoseconds)) - })()) + Duration::new(seconds, nanoseconds) + }) } } diff --git a/src/lib.rs b/src/lib.rs index 1b66d5ff6f31d..77eac9a6324a4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,6 +3,7 @@ #![feature(map_first_last)] #![feature(never_type)] #![feature(or_patterns)] +#![feature(try_blocks)] #![warn(rust_2018_idioms)] #![allow(clippy::cast_lossless)] From 563fb8e43d4c236faeeb9b611294a82ecff93712 Mon Sep 17 00:00:00 2001 From: Samrat Man Singh Date: Sat, 15 Aug 2020 14:15:31 +0530 Subject: [PATCH 2271/3747] Implement dup and close for stdin/stdout/stderr Support F_DUPFD on stdin/stdout/stderr Enable `close`-ing stdin/stdout/stderr For `dup`, check if FD is `File` first If not, clone the appropriate standard IO stream Merge POSIX `close` and `dup` tests into same module Also, add assertion that `write` on a closed FD returns an error. Add `dup` as FileDescriptor trait fn Also: - Fix `close` so it drops `self` instead of reference to it - Remove FD clamping in insert_fd_with_min_fd, since FDs 0-2 can be closed Fix fs_libc tests Make error message when closing stdin/out/err more specific Return io::Result from `FileDescriptor::dup` Change error message when closing stdin/out/err Refactor `FileDescriptor::dup` impl for `FileHandle` Remove empty line --- src/shims/posix/fs.rs | 115 ++++++++++++++++---------- tests/compile-fail/fs/close_stdout.rs | 14 ++++ tests/run-pass/fs_libc.rs | 20 +++++ tests/run-pass/fs_libc.stderr | 1 + tests/run-pass/fs_libc.stdout | 1 + 5 files changed, 109 insertions(+), 42 deletions(-) create mode 100644 tests/compile-fail/fs/close_stdout.rs create mode 100644 tests/run-pass/fs_libc.rs create mode 100644 tests/run-pass/fs_libc.stderr create mode 100644 tests/run-pass/fs_libc.stdout diff --git a/src/shims/posix/fs.rs b/src/shims/posix/fs.rs index b4719c25baee4..c50b41b75ef9e 100644 --- a/src/shims/posix/fs.rs +++ b/src/shims/posix/fs.rs @@ -28,6 +28,9 @@ trait FileDescriptor : std::fmt::Debug { fn read<'tcx>(&mut self, communicate_allowed: bool, bytes: &mut [u8]) -> InterpResult<'tcx, io::Result>; fn write<'tcx>(&mut self, communicate_allowed: bool, bytes: &[u8]) -> InterpResult<'tcx, io::Result>; fn seek<'tcx>(&mut self, communicate_allowed: bool, offset: SeekFrom) -> InterpResult<'tcx, io::Result>; + fn close<'tcx>(self: Box, _communicate_allowed: bool) -> InterpResult<'tcx, io::Result>; + + fn dup<'tcx>(&mut self) -> io::Result>; } impl FileDescriptor for FileHandle { @@ -49,6 +52,34 @@ impl FileDescriptor for FileHandle { assert!(communicate_allowed, "isolation should have prevented even opening a file"); Ok(self.file.seek(offset)) } + + fn close<'tcx>(self: Box, communicate_allowed: bool) -> InterpResult<'tcx, io::Result> { + assert!(communicate_allowed, "isolation should have prevented even opening a file"); + // We sync the file if it was opened in a mode different than read-only. + if self.writable { + // `File::sync_all` does the checks that are done when closing a file. We do this to + // to handle possible errors correctly. + let result = self.file.sync_all().map(|_| 0i32); + // Now we actually close the file. + drop(self); + // And return the result. + Ok(result) + } else { + // We drop the file, this closes it but ignores any errors + // produced when closing it. This is done because + // `File::sync_all` cannot be done over files like + // `/dev/urandom` which are read-only. Check + // https://github.com/rust-lang/miri/issues/999#issuecomment-568920439 + // for a deeper discussion. + drop(self); + Ok(Ok(0)) + } + } + + fn dup<'tcx>(&mut self) -> io::Result> { + let duplicated = self.file.try_clone()?; + Ok(Box::new(FileHandle { file: duplicated, writable: self.writable })) + } } impl FileDescriptor for io::Stdin { @@ -71,6 +102,14 @@ impl FileDescriptor for io::Stdin { fn seek<'tcx>(&mut self, _communicate_allowed: bool, _offset: SeekFrom) -> InterpResult<'tcx, io::Result> { throw_unsup_format!("cannot seek on stdin"); } + + fn close<'tcx>(self: Box, _communicate_allowed: bool) -> InterpResult<'tcx, io::Result> { + throw_unsup_format!("stdin cannot be closed"); + } + + fn dup<'tcx>(&mut self) -> io::Result> { + Ok(Box::new(io::stdin())) + } } impl FileDescriptor for io::Stdout { @@ -98,6 +137,14 @@ impl FileDescriptor for io::Stdout { fn seek<'tcx>(&mut self, _communicate_allowed: bool, _offset: SeekFrom) -> InterpResult<'tcx, io::Result> { throw_unsup_format!("cannot seek on stdout"); } + + fn close<'tcx>(self: Box, _communicate_allowed: bool) -> InterpResult<'tcx, io::Result> { + throw_unsup_format!("stdout cannot be closed"); + } + + fn dup<'tcx>(&mut self) -> io::Result> { + Ok(Box::new(io::stdout())) + } } impl FileDescriptor for io::Stderr { @@ -118,6 +165,14 @@ impl FileDescriptor for io::Stderr { fn seek<'tcx>(&mut self, _communicate_allowed: bool, _offset: SeekFrom) -> InterpResult<'tcx, io::Result> { throw_unsup_format!("cannot seek on stderr"); } + + fn close<'tcx>(self: Box, _communicate_allowed: bool) -> InterpResult<'tcx, io::Result> { + throw_unsup_format!("stderr cannot be closed"); + } + + fn dup<'tcx>(&mut self) -> io::Result> { + Ok(Box::new(io::stderr())) + } } #[derive(Debug)] @@ -137,18 +192,12 @@ impl<'tcx> Default for FileHandler { } } - -// fd numbers 0, 1, and 2 are reserved for stdin, stdout, and stderr -const MIN_NORMAL_FILE_FD: i32 = 3; - impl<'tcx> FileHandler { - fn insert_fd(&mut self, file_handle: FileHandle) -> i32 { + fn insert_fd(&mut self, file_handle: Box) -> i32 { self.insert_fd_with_min_fd(file_handle, 0) } - fn insert_fd_with_min_fd(&mut self, file_handle: FileHandle, min_fd: i32) -> i32 { - let min_fd = std::cmp::max(min_fd, MIN_NORMAL_FILE_FD); - + fn insert_fd_with_min_fd(&mut self, file_handle: Box, min_fd: i32) -> i32 { // Find the lowest unused FD, starting from min_fd. If the first such unused FD is in // between used FDs, the find_map combinator will return it. If the first such unused FD // is after all other used FDs, the find_map combinator will return None, and we will use @@ -173,7 +222,7 @@ impl<'tcx> FileHandler { self.handles.last_key_value().map(|(fd, _)| fd.checked_add(1).unwrap()).unwrap_or(min_fd) }); - self.handles.insert(new_fd, Box::new(file_handle)).unwrap_none(); + self.handles.insert(new_fd, file_handle).unwrap_none(); new_fd } } @@ -449,7 +498,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let fd = options.open(&path).map(|file| { let fh = &mut this.machine.file_handler; - fh.insert_fd(FileHandle { file, writable }) + fh.insert_fd(Box::new(FileHandle { file, writable })) }); this.try_unwrap_io_result(fd) @@ -489,22 +538,22 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // thus they can share the same implementation here. let &[_, _, start] = check_arg_count(args)?; let start = this.read_scalar(start)?.to_i32()?; - if fd < MIN_NORMAL_FILE_FD { - throw_unsup_format!("duplicating file descriptors for stdin, stdout, or stderr is not supported") - } + let fh = &mut this.machine.file_handler; - let (file_result, writable) = match fh.handles.get(&fd) { + + match fh.handles.get_mut(&fd) { Some(file_descriptor) => { - // FIXME: Support "dup" for all FDs(stdin, etc) - let FileHandle { file, writable } = file_descriptor.as_file_handle()?; - (file.try_clone(), *writable) + let dup_result = file_descriptor.dup(); + match dup_result { + Ok(dup_fd) => Ok(fh.insert_fd_with_min_fd(dup_fd, start)), + Err(e) => { + this.set_last_error_from_io_error(e)?; + Ok(-1) + } + } }, None => return this.handle_not_found(), - }; - let fd_result = file_result.map(|duplicated| { - fh.insert_fd_with_min_fd(FileHandle { file: duplicated, writable }, start) - }); - this.try_unwrap_io_result(fd_result) + } } else if this.tcx.sess.target.target.target_os == "macos" && cmd == this.eval_libc_i32("F_FULLFSYNC")? { @@ -530,26 +579,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let fd = this.read_scalar(fd_op)?.to_i32()?; if let Some(file_descriptor) = this.machine.file_handler.handles.remove(&fd) { - // FIXME: Support `close` for all FDs(stdin, etc) - let FileHandle { file, writable } = file_descriptor.as_file_handle()?; - // We sync the file if it was opened in a mode different than read-only. - if *writable { - // `File::sync_all` does the checks that are done when closing a file. We do this to - // to handle possible errors correctly. - let result = this.try_unwrap_io_result(file.sync_all().map(|_| 0i32)); - // Now we actually close the file. - drop(file); - // And return the result. - result - } else { - // We drop the file, this closes it but ignores any errors produced when closing - // it. This is done because `File::sync_all` cannot be done over files like - // `/dev/urandom` which are read-only. Check - // https://github.com/rust-lang/miri/issues/999#issuecomment-568920439 for a deeper - // discussion. - drop(file); - Ok(0) - } + let result = file_descriptor.close(this.machine.communicate)?; + this.try_unwrap_io_result(result) } else { this.handle_not_found() } diff --git a/tests/compile-fail/fs/close_stdout.rs b/tests/compile-fail/fs/close_stdout.rs new file mode 100644 index 0000000000000..4f10d5e0c990d --- /dev/null +++ b/tests/compile-fail/fs/close_stdout.rs @@ -0,0 +1,14 @@ +// ignore-windows: No libc on Windows +// compile-flags: -Zmiri-disable-isolation + +// FIXME: standard handles cannot be closed (https://github.com/rust-lang/rust/issues/40032) + +#![feature(rustc_private)] + +extern crate libc; + +fn main() { + unsafe { + libc::close(1); //~ ERROR stdout cannot be closed + } +} diff --git a/tests/run-pass/fs_libc.rs b/tests/run-pass/fs_libc.rs new file mode 100644 index 0000000000000..e3deb7a5bcd8a --- /dev/null +++ b/tests/run-pass/fs_libc.rs @@ -0,0 +1,20 @@ +// ignore-windows +// compile-flags: -Zmiri-disable-isolation + +#![feature(rustc_private)] + +extern crate libc; + +fn main() { + dup_stdout_stderr_test(); +} + +fn dup_stdout_stderr_test() { + let bytes = b"hello dup fd\n"; + unsafe { + let new_stdout = libc::fcntl(1, libc::F_DUPFD, 0); + let new_stderr = libc::fcntl(2, libc::F_DUPFD, 0); + libc::write(new_stdout, bytes.as_ptr() as *const libc::c_void, bytes.len()); + libc::write(new_stderr, bytes.as_ptr() as *const libc::c_void, bytes.len()); + } +} diff --git a/tests/run-pass/fs_libc.stderr b/tests/run-pass/fs_libc.stderr new file mode 100644 index 0000000000000..b6fa69e3d5d2e --- /dev/null +++ b/tests/run-pass/fs_libc.stderr @@ -0,0 +1 @@ +hello dup fd diff --git a/tests/run-pass/fs_libc.stdout b/tests/run-pass/fs_libc.stdout new file mode 100644 index 0000000000000..b6fa69e3d5d2e --- /dev/null +++ b/tests/run-pass/fs_libc.stdout @@ -0,0 +1 @@ +hello dup fd From bea2d7bb55775a9eb81a32d72938eeaaf90f279f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 10 Sep 2020 08:38:30 +0200 Subject: [PATCH 2272/3747] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index d2cf18f80f171..8e33b80ff68f5 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -e114d6228b948ce056de0bcdec2603c8e89d3727 +a1894e4afe1a39f718cc27232a5a2f0d02b501f6 From e61be0b8b8c0409ea2c7afac50bfd6afc09cf811 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 10 Sep 2020 08:38:43 +0200 Subject: [PATCH 2273/3747] expand collection tests --- ...zed-binary-heap-push.rs => binary-heap.rs} | 21 ++++++++++++++- tests/run-pass/btreemap.rs | 27 +++++++++++++++---- tests/run-pass/hashmap.rs | 16 +++++++++++ tests/run-pass/linked-list.rs | 19 ++++++++++++- tests/run-pass/vec.rs | 16 +++++++++++ 5 files changed, 92 insertions(+), 7 deletions(-) rename tests/run-pass/{zero-sized-binary-heap-push.rs => binary-heap.rs} (58%) diff --git a/tests/run-pass/zero-sized-binary-heap-push.rs b/tests/run-pass/binary-heap.rs similarity index 58% rename from tests/run-pass/zero-sized-binary-heap-push.rs rename to tests/run-pass/binary-heap.rs index c9312d79bfda0..8b8fa6458e650 100644 --- a/tests/run-pass/zero-sized-binary-heap-push.rs +++ b/tests/run-pass/binary-heap.rs @@ -1,7 +1,7 @@ use std::collections::BinaryHeap; use std::iter::Iterator; -fn main() { +fn zero_sized_push() { const N: usize = 8; for len in 0..N { @@ -16,3 +16,22 @@ fn main() { tester.clear(); } } + +fn drain() { + let mut heap = (0..128i32).collect::>(); + + assert!(!heap.is_empty()); + + let mut sum = 0; + for x in heap.drain() { + sum += x; + } + assert_eq!(sum, 127*128/2); + + assert!(heap.is_empty()); +} + +fn main() { + zero_sized_push(); + drain(); +} diff --git a/tests/run-pass/btreemap.rs b/tests/run-pass/btreemap.rs index e2049d9480322..603674cc4503d 100644 --- a/tests/run-pass/btreemap.rs +++ b/tests/run-pass/btreemap.rs @@ -7,6 +7,20 @@ pub enum Foo { _C, } +// Gather all references from a mutable iterator and make sure Miri notices if +// using them is dangerous. +fn test_all_refs<'a, T: 'a>(dummy: &mut T, iter: impl Iterator) { + // Gather all those references. + let mut refs: Vec<&mut T> = iter.collect(); + // Use them all. Twice, to be sure we got all interleavings. + for r in refs.iter_mut() { + std::mem::swap(dummy, r); + } + for r in refs { + std::mem::swap(dummy, r); + } +} + pub fn main() { let mut b = BTreeSet::new(); b.insert(Foo::A("\'")); @@ -19,11 +33,14 @@ pub fn main() { // Also test a lower-alignment type, where the NodeHeader overlaps with // the keys. let mut b = BTreeSet::new(); - b.insert(1024); - b.insert(7); + b.insert(1024u16); + b.insert(7u16); let mut b = BTreeMap::new(); - b.insert("bar", 1024); - b.insert("baz", 7); - for _val in b.iter_mut() {} + b.insert(format!("bar"), 1024); + b.insert(format!("baz"), 7); + for i in 0..60 { + b.insert(format!("key{}", i), i); + } + test_all_refs(&mut 13, b.values_mut()); } diff --git a/tests/run-pass/hashmap.rs b/tests/run-pass/hashmap.rs index 488fe6afe65e6..215f762efcc98 100644 --- a/tests/run-pass/hashmap.rs +++ b/tests/run-pass/hashmap.rs @@ -1,6 +1,20 @@ use std::collections::HashMap; use std::hash::BuildHasher; +// Gather all references from a mutable iterator and make sure Miri notices if +// using them is dangerous. +fn test_all_refs<'a, T: 'a>(dummy: &mut T, iter: impl Iterator) { + // Gather all those references. + let mut refs: Vec<&mut T> = iter.collect(); + // Use them all. Twice, to be sure we got all interleavings. + for r in refs.iter_mut() { + std::mem::swap(dummy, r); + } + for r in refs { + std::mem::swap(dummy, r); + } +} + fn smoketest_map(mut map: HashMap) { map.insert(0, 0); assert_eq!(map.values().fold(0, |x, y| x+y), 0); @@ -16,6 +30,8 @@ fn smoketest_map(mut map: HashMap) { map.insert(i, num-1-i); } assert_eq!(map.values().fold(0, |x, y| x+y), num*(num-1)/2); + + test_all_refs(&mut 13, map.values_mut()); } fn main() { diff --git a/tests/run-pass/linked-list.rs b/tests/run-pass/linked-list.rs index 976a35da6061d..0ed9d6032d0e5 100644 --- a/tests/run-pass/linked-list.rs +++ b/tests/run-pass/linked-list.rs @@ -4,7 +4,21 @@ use std::collections::LinkedList; fn list_from(v: &[T]) -> LinkedList { v.iter().cloned().collect() } - + +// Gather all references from a mutable iterator and make sure Miri notices if +// using them is dangerous. +fn test_all_refs<'a, T: 'a>(dummy: &mut T, iter: impl Iterator) { + // Gather all those references. + let mut refs: Vec<&mut T> = iter.collect(); + // Use them all. Twice, to be sure we got all interleavings. + for r in refs.iter_mut() { + std::mem::swap(dummy, r); + } + for r in refs { + std::mem::swap(dummy, r); + } +} + fn main() { let mut m = list_from(&[0, 2, 4, 6, 8]); let len = m.len(); @@ -30,6 +44,9 @@ fn main() { } assert_eq!(m.len(), 3 + len * 2); + let mut m2 = m.clone(); assert_eq!(m.into_iter().collect::>(), [-10, -2, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 99]); + + test_all_refs(&mut 13, m2.iter_mut()); } diff --git a/tests/run-pass/vec.rs b/tests/run-pass/vec.rs index 731358564b8ac..5fea4a9147a0b 100644 --- a/tests/run-pass/vec.rs +++ b/tests/run-pass/vec.rs @@ -1,3 +1,17 @@ +// Gather all references from a mutable iterator and make sure Miri notices if +// using them is dangerous. +fn test_all_refs<'a, T: 'a>(dummy: &mut T, iter: impl Iterator) { + // Gather all those references. + let mut refs: Vec<&mut T> = iter.collect(); + // Use them all. Twice, to be sure we got all interleavings. + for r in refs.iter_mut() { + std::mem::swap(dummy, r); + } + for r in refs { + std::mem::swap(dummy, r); + } +} + fn make_vec() -> Vec { let mut v = Vec::with_capacity(4); v.push(1); @@ -53,6 +67,8 @@ fn vec_iter_and_mut() { *i += 1; } assert_eq!(v.iter().sum::(), 2+3+4+5); + + test_all_refs(&mut 13, v.iter_mut()); } fn vec_iter_and_mut_rev() { From bc548d30041a3ac247d264d6b49904b25f232f7a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 11 Sep 2020 12:20:08 +0200 Subject: [PATCH 2274/3747] test BTreeMap::drain_filter for leaks --- tests/run-pass/btreemap.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tests/run-pass/btreemap.rs b/tests/run-pass/btreemap.rs index 603674cc4503d..e639ba6225ca3 100644 --- a/tests/run-pass/btreemap.rs +++ b/tests/run-pass/btreemap.rs @@ -1,4 +1,6 @@ +#![feature(btree_drain_filter)] use std::collections::{BTreeMap, BTreeSet}; +use std::mem; #[derive(PartialEq, Eq, PartialOrd, Ord)] pub enum Foo { @@ -43,4 +45,9 @@ pub fn main() { b.insert(format!("key{}", i), i); } test_all_refs(&mut 13, b.values_mut()); + + // Test forgetting the drain. + let mut d = b.drain_filter(|_, i| *i < 30); + d.next().unwrap(); + mem::forget(d); } From ebc3b718818c27a5061c2f2da31f9ef7e4d6851d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 13 Sep 2020 21:10:29 +0200 Subject: [PATCH 2275/3747] also detect Azure CI environments --- cargo-miri/bin.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index 98304d247f98f..12c5d1c325539 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -207,7 +207,10 @@ fn xargo_version() -> Option<(u32, u32, u32)> { fn ask_to_run(mut cmd: Command, ask: bool, text: &str) { // Disable interactive prompts in CI (GitHub Actions, Travis, AppVeyor, etc). - if ask && env::var_os("CI").is_none() { + // Azure doesn't set `CI` though (nothing to see here, just Microsoft being Microsoft), + // so we also check their `TF_BUILD`. + let is_ci = env::var_os("CI").is_some() || env::var_os("TF_BUILD").is_some(); + if ask && !is_ci { let mut buf = String::new(); print!("I will run `{:?}` to {}. Proceed? [Y/n] ", cmd, text); io::stdout().flush().unwrap(); From 93c31e7790368ba062da93189c241d996a9ae172 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Thu, 17 Sep 2020 09:39:52 -0400 Subject: [PATCH 2276/3747] Enable some panic tests on Windows --- test-cargo-miri/tests/test.rs | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/test-cargo-miri/tests/test.rs b/test-cargo-miri/tests/test.rs index 68d5426802b45..e38dc7a926c9e 100644 --- a/test-cargo-miri/tests/test.rs +++ b/test-cargo-miri/tests/test.rs @@ -42,22 +42,15 @@ fn num_cpus() { assert_eq!(num_cpus::get(), 1); } - -// FIXME: Remove this `cfg` once we fix https://github.com/rust-lang/miri/issues/1059. -// We cfg-gate the `should_panic` attribute and the `panic!` itself, so that the test -// stdout does not depend on the target. #[test] -#[cfg_attr(not(windows), should_panic(expected="Explicit panic"))] +#[should_panic(expected="Explicit panic")] fn do_panic() { // In large, friendly letters :) - #[cfg(not(windows))] panic!("Explicit panic from test!"); } -// FIXME: see above #[test] #[allow(unconditional_panic)] -#[cfg_attr(not(windows), should_panic(expected="the len is 0 but the index is 42"))] +#[should_panic(expected="the len is 0 but the index is 42")] fn fail_index_check() { - #[cfg(not(windows))] [][42] } From 2b3b83eb2c01d82cd1fce9285e50bae1c2cb9b54 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 6 Sep 2020 19:28:29 +0200 Subject: [PATCH 2277/3747] canonicalize miri's directory --- miri | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/miri b/miri index 37e87ec79861d..f53c21ff115cf 100755 --- a/miri +++ b/miri @@ -39,6 +39,7 @@ EOF TARGET=$(rustc --version --verbose | grep "^host:" | cut -d ' ' -f 2) SYSROOT=$(rustc --print sysroot) LIBDIR=$SYSROOT/lib/rustlib/$TARGET/lib +MIRIDIR=$(readlink -e "$(dirname "$0")") if ! test -d "$LIBDIR"; then echo "Something went wrong determining the library dir." echo "I got $LIBDIR but that does not exist." @@ -51,7 +52,7 @@ if [ -z "$CARGO_INCREMENTAL" ]; then fi if [ -z "$CARGO_TARGET_DIR" ]; then # Share target dir between `miri` and `cargo-miri`. - export CARGO_TARGET_DIR="$(dirname "$0")"/target + export CARGO_TARGET_DIR="$MIRIDIR/target" fi # We set the rpath so that Miri finds the private rustc libraries it needs. # We enable debug-assertions to get tracing. @@ -63,9 +64,9 @@ export RUSTFLAGS="-C link-args=-Wl,-rpath,$LIBDIR -C debug-assertions -C debugin # Build a sysroot and set MIRI_SYSROOT to use it. Arguments are passed to `cargo miri setup`. build_sysroot() { # Build once, for the user to see. - cargo run $CARGO_BUILD_FLAGS --manifest-path "$(dirname "$0")"/cargo-miri/Cargo.toml -- miri setup "$@" + cargo run $CARGO_BUILD_FLAGS --manifest-path "$MIRIDIR"/cargo-miri/Cargo.toml -- miri setup "$@" # Call again, to just set env var. - export MIRI_SYSROOT="$(cargo run $CARGO_BUILD_FLAGS --manifest-path "$(dirname "$0")"/cargo-miri/Cargo.toml -q -- miri setup --print-sysroot "$@")" + export MIRI_SYSROOT="$(cargo run $CARGO_BUILD_FLAGS --manifest-path "$MIRIDIR"/cargo-miri/Cargo.toml -q -- miri setup --print-sysroot "$@")" } # Prepare and set MIRI_SYSROOT. Respects `MIRI_TEST_TARGET` and takes into account @@ -108,18 +109,18 @@ case "$COMMAND" in install|install-debug) # "--locked" to respect the Cargo.lock file if it exists, # "--offline" to avoid querying the registry (for yanked packages). - cargo install $CARGO_INSTALL_FLAGS --path "$(dirname "$0")" --force --locked --offline "$@" - cargo install $CARGO_INSTALL_FLAGS --path "$(dirname "$0")"/cargo-miri --force --locked --offline "$@" + cargo install $CARGO_INSTALL_FLAGS --path "$MIRIDIR" --force --locked --offline "$@" + cargo install $CARGO_INSTALL_FLAGS --path "$MIRIDIR"/cargo-miri --force --locked --offline "$@" ;; check|check-debug) # Check, and let caller control flags. - cargo check $CARGO_BUILD_FLAGS --manifest-path "$(dirname "$0")"/Cargo.toml "$@" - cargo check $CARGO_BUILD_FLAGS --manifest-path "$(dirname "$0")"/cargo-miri/Cargo.toml "$@" + cargo check $CARGO_BUILD_FLAGS --manifest-path "$MIRIDIR"/Cargo.toml "$@" + cargo check $CARGO_BUILD_FLAGS --manifest-path "$MIRIDIR"/cargo-miri/Cargo.toml "$@" ;; build|build-debug) # Build, and let caller control flags. - cargo build $CARGO_BUILD_FLAGS --manifest-path "$(dirname "$0")"/Cargo.toml "$@" - cargo build $CARGO_BUILD_FLAGS --manifest-path "$(dirname "$0")"/cargo-miri/Cargo.toml "$@" + cargo build $CARGO_BUILD_FLAGS --manifest-path "$MIRIDIR"/Cargo.toml "$@" + cargo build $CARGO_BUILD_FLAGS --manifest-path "$MIRIDIR"/cargo-miri/Cargo.toml "$@" ;; test|test-debug) # First build and get a sysroot. From 16afe1a2343de58c29480ab0d90490b58eee00d8 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 6 Sep 2020 19:28:58 +0200 Subject: [PATCH 2278/3747] towards letting cargo do binary selection: wrappers and runners set up --- cargo-miri/Cargo.lock | 24 +-- cargo-miri/Cargo.toml | 1 - cargo-miri/bin.rs | 332 +++++++++++++----------------------------- 3 files changed, 103 insertions(+), 254 deletions(-) diff --git a/cargo-miri/Cargo.lock b/cargo-miri/Cargo.lock index 0052bfa183d06..bb3b05db03a41 100644 --- a/cargo-miri/Cargo.lock +++ b/cargo-miri/Cargo.lock @@ -45,7 +45,6 @@ dependencies = [ name = "cargo-miri" version = "0.1.0" dependencies = [ - "cargo_metadata", "directories", "rustc-workspace-hack", "rustc_version", @@ -54,17 +53,6 @@ dependencies = [ "vergen", ] -[[package]] -name = "cargo_metadata" -version = "0.11.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89fec17b16f1ac67908af82e47d0a90a7afd0e1827b181cd77504323d3263d35" -dependencies = [ - "semver 0.10.0", - "serde", - "serde_json", -] - [[package]] name = "cfg-if" version = "0.1.10" @@ -228,7 +216,7 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" dependencies = [ - "semver 0.9.0", + "semver", ] [[package]] @@ -246,16 +234,6 @@ dependencies = [ "semver-parser", ] -[[package]] -name = "semver" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "394cec28fa623e00903caf7ba4fa6fb9a0e260280bb8cdbbba029611108a0190" -dependencies = [ - "semver-parser", - "serde", -] - [[package]] name = "semver-parser" version = "0.7.0" diff --git a/cargo-miri/Cargo.toml b/cargo-miri/Cargo.toml index 91c4783694844..2de581c1c2e26 100644 --- a/cargo-miri/Cargo.toml +++ b/cargo-miri/Cargo.toml @@ -14,7 +14,6 @@ test = false # we have no unit tests doctest = false # and no doc tests [dependencies] -cargo_metadata = "0.11" directories = "2.0" rustc_version = "0.2.3" serde_json = "1.0.40" diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index 12c5d1c325539..f3a2a511517f4 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -116,50 +116,6 @@ fn xargo_check() -> Command { Command::new(env::var_os("XARGO_CHECK").unwrap_or_else(|| OsString::from("xargo-check"))) } -fn list_targets() -> impl Iterator { - // We need to get the manifest, and then the metadata, to enumerate targets. - let manifest_path = - get_arg_flag_value("--manifest-path").map(|m| Path::new(&m).canonicalize().unwrap()); - - let mut cmd = cargo_metadata::MetadataCommand::new(); - if let Some(manifest_path) = &manifest_path { - cmd.manifest_path(manifest_path); - } - let mut metadata = if let Ok(metadata) = cmd.exec() { - metadata - } else { - show_error(format!("Could not obtain Cargo metadata; likely an ill-formed manifest")); - }; - - let current_dir = std::env::current_dir(); - - let package_index = metadata - .packages - .iter() - .position(|package| { - let package_manifest_path = Path::new(&package.manifest_path); - if let Some(manifest_path) = &manifest_path { - package_manifest_path == manifest_path - } else { - let current_dir = current_dir.as_ref().expect("could not read current directory"); - let package_manifest_directory = package_manifest_path - .parent() - .expect("could not find parent directory of package manifest"); - package_manifest_directory == current_dir - } - }) - .unwrap_or_else(|| { - show_error(format!( - "this seems to be a workspace, which is not supported by `cargo miri`.\n\ - Try to `cd` into the crate you want to test, and re-run `cargo miri` there." - )) - }); - let package = metadata.packages.remove(package_index); - - // Finally we got the list of targets to build - package.targets.into_iter() -} - fn xargo_version() -> Option<(u32, u32, u32)> { let out = xargo_check().arg("--version").output().ok()?; if !out.status.success() { @@ -381,173 +337,77 @@ path = "lib.rs" } } -enum CargoTargets { - All, - Filtered { lib: bool, bin: Vec, test: Vec }, -} - -impl CargoTargets { - fn matches(&self, kind: &str, name: &str) -> bool { - match self { - CargoTargets::All => true, - CargoTargets::Filtered { lib, bin, test } => match kind { - "lib" => *lib, - "bin" => bin.iter().any(|n| n == name), - "test" => test.iter().any(|n| n == name), - _ => false, - }, - } - } -} - -fn parse_cargo_miri_args( - mut args: impl Iterator, -) -> (CargoTargets, Vec, Vec) { - let mut lib_present = false; - let mut bin_targets = Vec::new(); - let mut test_targets = Vec::new(); - let mut additional_args = Vec::new(); - while let Some(arg) = args.next() { - match arg { - arg if arg == "--" => { - // Miri arguments begin after the first "--". - break; - } - arg if arg == "--lib" => lib_present = true, - arg if arg == "--bin" => { - if let Some(binary) = args.next() { - if binary == "--" { - show_error(format!("\"--bin\" takes one argument.")); - } else { - bin_targets.push(binary) - } - } else { - show_error(format!("\"--bin\" takes one argument.")); - } - } - arg if arg.starts_with("--bin=") => bin_targets.push((&arg["--bin=".len()..]).to_string()), - arg if arg == "--test" => { - if let Some(test) = args.next() { - if test == "--" { - show_error(format!("\"--test\" takes one argument.")); - } else { - test_targets.push(test) - } - } else { - show_error(format!("\"--test\" takes one argument.")); - } - } - arg if arg.starts_with("--test=") => test_targets.push((&arg["--test=".len()..]).to_string()), - other => additional_args.push(other), - } - } - let targets = if !lib_present && bin_targets.len() == 0 && test_targets.len() == 0 { - CargoTargets::All - } else { - CargoTargets::Filtered { lib: lib_present, bin: bin_targets, test: test_targets } - }; - (targets, additional_args, args.collect()) -} - -fn in_cargo_miri() { - let (subcommand, skip) = match std::env::args().nth(2).as_deref() { - Some("test") => (MiriCommand::Test, 3), - Some("run") => (MiriCommand::Run, 3), - Some("setup") => (MiriCommand::Setup, 3), - // Default command, if there is an option or nothing. - Some(s) if s.starts_with("-") => (MiriCommand::Run, 2), - None => (MiriCommand::Run, 2), +fn phase_cargo_miri(mut args: env::Args) { + // Require a subcommand before any flags. + // We cannot know which of those flags take arguments and which do not, + // so we cannot detect subcommands later. + let subcommand = match args.next().as_deref() { + Some("test") => MiriCommand::Test, + Some("run") => MiriCommand::Run, + Some("setup") => MiriCommand::Setup, // Invalid command. - Some(s) => show_error(format!("Unknown command `{}`", s)), + None => show_error(format!("`cargo miri` must be immediately followed by `test`, `run`, or `setup`.")), + Some(s) => show_error(format!("unknown command `{}`", s)), }; let verbose = has_arg_flag("-v"); // We always setup. setup(subcommand); - if subcommand == MiriCommand::Setup { - // Stop here. - return; - } - // FIXME: this accepts --test, --lib, and multiple --bin for `cargo miri run`. - let (target_filters, cargo_args, miri_args) = - parse_cargo_miri_args(std::env::args().skip(skip)); - - // Now run the command. - for target in list_targets() { - let kind = target - .kind - .get(0) - .expect("badly formatted cargo metadata: target::kind is an empty array"); - if !target_filters.matches(kind, &target.name) { - continue; - } - // Now we run `cargo check $FLAGS $ARGS`, giving the user the - // change to add additional arguments. `FLAGS` is set to identify - // this target. The user gets to control what gets actually passed to Miri. - let mut cmd = cargo(); - cmd.arg("check"); - match (subcommand, kind.as_str()) { - (MiriCommand::Run, "bin") => { - // FIXME: we default to running all binaries here. - cmd.arg("--bin").arg(target.name); - } - (MiriCommand::Test, "test") => { - cmd.arg("--test").arg(target.name); - } - (MiriCommand::Test, "lib") => { - // There can be only one lib. - cmd.arg("--lib").arg("--profile").arg("test"); - } - (MiriCommand::Test, "bin") => { - cmd.arg("--bin").arg(target.name).arg("--profile").arg("test"); - } - // The remaining targets we do not even want to build. - _ => continue, - } - // Forward further `cargo` args. - for arg in cargo_args.iter() { - cmd.arg(arg); - } - // We want to always run `cargo` with `--target`. This later helps us detect - // which crates are proc-macro/build-script (host crates) and which crates are - // needed for the program itself. - if get_arg_flag_value("--target").is_none() { - // When no `--target` is given, default to the host. - cmd.arg("--target"); - cmd.arg(version_info().host); - } + // Invoke actual cargo for the job, but with different flags. + let miri_path = std::env::current_exe().expect("current executable path invalid"); + let cargo_cmd = match subcommand { + MiriCommand::Test => "test", + MiriCommand::Run => "run", + MiriCommand::Setup => return, // `cargo miri setup` stops here. + }; + let mut cmd = cargo(); + cmd.arg(cargo_cmd); + + // Make sure we know the build target, and cargo does, too. + // This is needed to make the `CARGO_TARGET_*_RUNNER` env var do something, + // and it later helps us detect which crates are proc-macro/build-script + // (host crates) and which crates are needed for the program itself. + let target = if let Some(target) = get_arg_flag_value("--target") { + target + } else { + // No target given. Pick default and tell cargo about it. + let host = version_info().host; + cmd.arg("--target"); + cmd.arg(&host); + host + }; - // Serialize the remaining args into a special environemt variable. - // This will be read by `inside_cargo_rustc` when we go to invoke - // our actual target crate (the binary or the test we are running). - // Since we're using "cargo check", we have no other way of passing - // these arguments. - cmd.env("MIRI_ARGS", serde_json::to_string(&miri_args).expect("failed to serialize args")); - - // Set `RUSTC_WRAPPER` to ourselves. Cargo will prepend that binary to its usual invocation, - // i.e., the first argument is `rustc` -- which is what we use in `main` to distinguish - // the two codepaths. (That extra argument is why we prefer this over setting `RUSTC`.) - if env::var_os("RUSTC_WRAPPER").is_some() { - println!("WARNING: Ignoring existing `RUSTC_WRAPPER` environment variable, Miri does not support wrapping."); - } - let path = std::env::current_exe().expect("current executable path invalid"); - cmd.env("RUSTC_WRAPPER", path); - if verbose { - cmd.env("MIRI_VERBOSE", ""); // this makes `inside_cargo_rustc` verbose. - eprintln!("+ {:?}", cmd); - } + // Forward all further arguments. + cmd.args(args); - let exit_status = - cmd.spawn().expect("could not run cargo").wait().expect("failed to wait for cargo?"); + // Set `RUSTC_WRAPPER` to ourselves. Cargo will prepend that binary to its usual invocation, + // i.e., the first argument is `rustc` -- which is what we use in `main` to distinguish + // the two codepaths. (That extra argument is why we prefer this over setting `RUSTC`.) + if env::var_os("RUSTC_WRAPPER").is_some() { + println!("WARNING: Ignoring `RUSTC_WRAPPER` environment variable, Miri does not support wrapping."); + } + cmd.env("RUSTC_WRAPPER", &miri_path); + if verbose { + eprintln!("+ RUSTC_WRAPPER={:?}", miri_path); + } - if !exit_status.success() { - std::process::exit(exit_status.code().unwrap_or(-1)) - } + // Set the runner for the current target to us as well, so we can interpret the binaries. + let runner_env_name = format!("CARGO_TARGET_{}_RUNNER", target.to_uppercase().replace('-', "_")); + cmd.env(runner_env_name, &miri_path); + + // Run cargo. + if verbose { + cmd.env("MIRI_VERBOSE", ""); // this makes `inside_cargo_rustc` verbose. + eprintln!("+ {:?}", cmd); } + let exit_status = + cmd.spawn().expect("could not run cargo").wait().expect("failed to wait for cargo?"); + + std::process::exit(exit_status.code().unwrap_or(-1)) } -fn inside_cargo_rustc() { +fn phase_cargo_rustc(mut args: env::Args) { /// Determines if we are being invoked (as rustc) to build a crate for /// the "target" architecture, in contrast to the "host" architecture. /// Host crates are for build scripts and proc macros and still need to @@ -569,15 +429,35 @@ fn inside_cargo_rustc() { fn is_runnable_crate() -> bool { let is_bin = get_arg_flag_value("--crate-type").as_deref() == Some("bin"); let is_test = has_arg_flag("--test"); - is_bin || is_test + let print = get_arg_flag_value("--print").is_some(); + (is_bin || is_test) && !print } let verbose = std::env::var_os("MIRI_VERBOSE").is_some(); let target_crate = is_target_crate(); + if target_crate && is_runnable_crate() { + // This is the binary or test crate that we want to interpret under Miri. + // But we cannot run it here, as cargo invoked us as a compiler -- our stdin and stdout are not + // like we want them. + // Instead of compiling, we write JSON into the output file with all the relevant command-line flags + // and environment variables; this is sued alter when cargo calls us again in the CARGO_TARGET_RUNNER phase. + let filename = format!( + "{}/{}{}", + get_arg_flag_value("--out-dir").unwrap(), + get_arg_flag_value("--crate-name").unwrap(), + // This is technically a `-C` flag but the prefix seems unique enough... + // (and cargo passes this before the filename so it should be unique) + get_arg_flag_value("extra-filename").unwrap_or(String::new()), + ); + eprintln!("Miri is supposed to run {}", filename); + return; + } + let mut cmd = miri(); // Forward arguments. - cmd.args(std::env::args().skip(2)); // skip `cargo-miri rustc` + cmd.args(args); + // FIXME: Make the build check-only! // We make sure to only specify our custom Xargo sysroot for target crates - that is, // crates which are needed for interpretation by Miri. proc-macros and build scripts @@ -589,23 +469,9 @@ fn inside_cargo_rustc() { cmd.arg(sysroot); } - // If this is a runnable target crate, we want Miri to start interpretation; - // otherwise we want Miri to behave like rustc and build the crate as usual. - if target_crate && is_runnable_crate() { - // This is the binary or test crate that we want to interpret under Miri. - // (Testing `target_crate` is needed to exclude build scripts.) - // We deserialize the arguments that are meant for Miri from the special environment - // variable "MIRI_ARGS", and feed them to the 'miri' binary. - // - // `env::var` is okay here, well-formed JSON is always UTF-8. - let magic = std::env::var("MIRI_ARGS").expect("missing MIRI_ARGS"); - let miri_args: Vec = - serde_json::from_str(&magic).expect("failed to deserialize MIRI_ARGS"); - cmd.args(miri_args); - } else { - // We want to compile, not interpret. - cmd.env("MIRI_BE_RUSTC", "1"); - }; + // We want to compile, not interpret. We still use Miri to make sure the compiler version etc + // are the exact same as what is used for interpretation. + cmd.env("MIRI_BE_RUSTC", "1"); // Run it. if verbose { @@ -620,6 +486,10 @@ fn inside_cargo_rustc() { } } +fn phase_cargo_runner(binary: &str, args: env::Args) { + eprintln!("Asked to execute {}, args: {:?}", binary, args.collect::>()); +} + fn main() { // Check for version and help flags even when invoked as `cargo-miri`. if has_arg_flag("--help") || has_arg_flag("-h") { @@ -631,18 +501,20 @@ fn main() { return; } - if let Some("miri") = std::env::args().nth(1).as_deref() { - // This arm is for when `cargo miri` is called. We call `cargo check` for each applicable target, - // but with the `RUSTC` env var set to the `cargo-miri` binary so that we come back in the other branch, - // and dispatch the invocations to `rustc` and `miri`, respectively. - in_cargo_miri(); - } else if let Some("rustc") = std::env::args().nth(1).as_deref() { - // This arm is executed when `cargo-miri` runs `cargo check` with the `RUSTC_WRAPPER` env var set to itself: - // dependencies get dispatched to `rustc`, the final test/binary to `miri`. - inside_cargo_rustc(); - } else { - show_error(format!( - "`cargo-miri` must be called with either `miri` or `rustc` as first argument." - )) + let mut args = std::env::args(); + // Skip binary name. + args.next().unwrap(); + + // Dispatch to `cargo-miri` phase. There are three phases: + // - When we are called via `cargo miri`, we run as the frontend and invoke the underlying + // cargo. We set RUSTC_WRAPPER and CARGO_TARGET_RUNNER to ourselves. + // - When we are executed due to RUSTC_WRAPPER, we build crates or store the flags of + // binary crates for later interpretation. + // - When we are executed due to CARGO_TARGET_RUNNER, we start interpretation based on the + // flags that were stored earlier. + match &*args.next().unwrap() { + "miri" => phase_cargo_miri(args), + "rustc" => phase_cargo_rustc(args), + binary => phase_cargo_runner(binary, args), } } From e2119dc94dee5afe4a0ccd30530f9d4b824a3504 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 7 Sep 2020 20:19:45 +0200 Subject: [PATCH 2279/3747] stub JSON information flow from cargo-build-time to run-time --- cargo-miri/bin.rs | 40 ++++++++++++++++++++++++++++++++++------ 1 file changed, 34 insertions(+), 6 deletions(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index f3a2a511517f4..fee485ec9044c 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -1,10 +1,13 @@ use std::env; use std::ffi::OsString; use std::fs::{self, File}; -use std::io::{self, BufRead, Write}; +use std::io::{self, BufRead, BufReader, BufWriter, Write}; use std::ops::Not; use std::path::{Path, PathBuf}; use std::process::Command; +use std::collections::HashMap; + +use serde::{Deserialize, Serialize}; use rustc_version::VersionMeta; @@ -41,6 +44,15 @@ enum MiriCommand { Setup, } +/// The inforamtion Miri needs to run a crate. Stored as JSON when the crate is "compiled". +#[derive(Serialize, Deserialize)] +struct CrateRunInfo { + /// The command-line arguments. + args: Vec, + /// The environment. + env: HashMap, +} + fn show_help() { println!("{}", CARGO_MIRI_HELP); } @@ -442,15 +454,24 @@ fn phase_cargo_rustc(mut args: env::Args) { // like we want them. // Instead of compiling, we write JSON into the output file with all the relevant command-line flags // and environment variables; this is sued alter when cargo calls us again in the CARGO_TARGET_RUNNER phase. - let filename = format!( - "{}/{}{}", - get_arg_flag_value("--out-dir").unwrap(), + let info = CrateRunInfo { args: Vec::new(), env: HashMap::new() }; + + let mut path = PathBuf::from(get_arg_flag_value("--out-dir").unwrap()); + path.push(format!( + "{}{}", get_arg_flag_value("--crate-name").unwrap(), // This is technically a `-C` flag but the prefix seems unique enough... // (and cargo passes this before the filename so it should be unique) get_arg_flag_value("extra-filename").unwrap_or(String::new()), - ); - eprintln!("Miri is supposed to run {}", filename); + )); + eprintln!("Miri is supposed to run {}", path.display()); + + let file = File::create(&path) + .unwrap_or_else(|_| show_error(format!("Cannot create {}", path.display()))); + let file = BufWriter::new(file); + serde_json::ser::to_writer(file, &info) + .unwrap_or_else(|_| show_error(format!("Cannot write to {}", path.display()))); + return; } @@ -488,6 +509,13 @@ fn phase_cargo_rustc(mut args: env::Args) { fn phase_cargo_runner(binary: &str, args: env::Args) { eprintln!("Asked to execute {}, args: {:?}", binary, args.collect::>()); + + let file = File::open(binary) + .unwrap_or_else(|_| show_error(format!("File {:?} not found, or cargo-miri invoked incorrectly", binary))); + let file = BufReader::new(file); + let info: CrateRunInfo = serde_json::from_reader(file) + .unwrap_or_else(|_| show_error(format!("File {:?} does not contain valid JSON", binary))); + // FIXME: remove the file. } fn main() { From 7ee2729824f1922d361c54a8d43e04190b513fc5 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 7 Sep 2020 21:12:51 +0200 Subject: [PATCH 2280/3747] it actually runs tests now! --- cargo-miri/bin.rs | 70 ++++++++++++++++++++++++++++++----------------- 1 file changed, 45 insertions(+), 25 deletions(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index fee485ec9044c..57c0ec985ab8f 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -5,7 +5,6 @@ use std::io::{self, BufRead, BufReader, BufWriter, Write}; use std::ops::Not; use std::path::{Path, PathBuf}; use std::process::Command; -use std::collections::HashMap; use serde::{Deserialize, Serialize}; @@ -50,7 +49,16 @@ struct CrateRunInfo { /// The command-line arguments. args: Vec, /// The environment. - env: HashMap, + env: Vec<(OsString, OsString)>, +} + +impl CrateRunInfo { + /// Gather all the information we need. + fn collect(args: env::ArgsOs) -> Self { + let args = args.collect(); + let env = env::vars_os().collect(); + CrateRunInfo { args, env } + } } fn show_help() { @@ -128,6 +136,11 @@ fn xargo_check() -> Command { Command::new(env::var_os("XARGO_CHECK").unwrap_or_else(|| OsString::from("xargo-check"))) } +fn exec(mut cmd: Command) -> ! { + let exit_status = cmd.status().expect("failed to run command"); + std::process::exit(exit_status.code().unwrap_or(-1)) +} + fn xargo_version() -> Option<(u32, u32, u32)> { let out = xargo_check().arg("--version").output().ok()?; if !out.status.success() { @@ -349,17 +362,16 @@ path = "lib.rs" } } -fn phase_cargo_miri(mut args: env::Args) { +fn phase_cargo_miri(mut args: env::ArgsOs) { // Require a subcommand before any flags. // We cannot know which of those flags take arguments and which do not, // so we cannot detect subcommands later. - let subcommand = match args.next().as_deref() { + let subcommand = match args.next().as_deref().and_then(|s| s.to_str()) { Some("test") => MiriCommand::Test, Some("run") => MiriCommand::Run, Some("setup") => MiriCommand::Setup, // Invalid command. - None => show_error(format!("`cargo miri` must be immediately followed by `test`, `run`, or `setup`.")), - Some(s) => show_error(format!("unknown command `{}`", s)), + _ => show_error(format!("`cargo miri` must be immediately followed by `test`, `run`, or `setup`.")), }; let verbose = has_arg_flag("-v"); @@ -413,13 +425,10 @@ fn phase_cargo_miri(mut args: env::Args) { cmd.env("MIRI_VERBOSE", ""); // this makes `inside_cargo_rustc` verbose. eprintln!("+ {:?}", cmd); } - let exit_status = - cmd.spawn().expect("could not run cargo").wait().expect("failed to wait for cargo?"); - - std::process::exit(exit_status.code().unwrap_or(-1)) + exec(cmd) } -fn phase_cargo_rustc(mut args: env::Args) { +fn phase_cargo_rustc(args: env::ArgsOs) { /// Determines if we are being invoked (as rustc) to build a crate for /// the "target" architecture, in contrast to the "host" architecture. /// Host crates are for build scripts and proc macros and still need to @@ -454,7 +463,7 @@ fn phase_cargo_rustc(mut args: env::Args) { // like we want them. // Instead of compiling, we write JSON into the output file with all the relevant command-line flags // and environment variables; this is sued alter when cargo calls us again in the CARGO_TARGET_RUNNER phase. - let info = CrateRunInfo { args: Vec::new(), env: HashMap::new() }; + let info = CrateRunInfo::collect(args); let mut path = PathBuf::from(get_arg_flag_value("--out-dir").unwrap()); path.push(format!( @@ -464,14 +473,12 @@ fn phase_cargo_rustc(mut args: env::Args) { // (and cargo passes this before the filename so it should be unique) get_arg_flag_value("extra-filename").unwrap_or(String::new()), )); - eprintln!("Miri is supposed to run {}", path.display()); let file = File::create(&path) .unwrap_or_else(|_| show_error(format!("Cannot create {}", path.display()))); let file = BufWriter::new(file); serde_json::ser::to_writer(file, &info) .unwrap_or_else(|_| show_error(format!("Cannot write to {}", path.display()))); - return; } @@ -498,17 +505,11 @@ fn phase_cargo_rustc(mut args: env::Args) { if verbose { eprintln!("+ {:?}", cmd); } - match cmd.status() { - Ok(exit) => - if !exit.success() { - std::process::exit(exit.code().unwrap_or(42)); - }, - Err(e) => panic!("error running {:?}:\n{:?}", cmd, e), - } + exec(cmd) } -fn phase_cargo_runner(binary: &str, args: env::Args) { - eprintln!("Asked to execute {}, args: {:?}", binary, args.collect::>()); +fn phase_cargo_runner(binary: &str, args: env::ArgsOs) { + let verbose = std::env::var_os("MIRI_VERBOSE").is_some(); let file = File::open(binary) .unwrap_or_else(|_| show_error(format!("File {:?} not found, or cargo-miri invoked incorrectly", binary))); @@ -516,6 +517,24 @@ fn phase_cargo_runner(binary: &str, args: env::Args) { let info: CrateRunInfo = serde_json::from_reader(file) .unwrap_or_else(|_| show_error(format!("File {:?} does not contain valid JSON", binary))); // FIXME: remove the file. + + let mut cmd = miri(); + // Forward rustc arguments,with our sysroot. + cmd.args(info.args); + let sysroot = + env::var_os("MIRI_SYSROOT").expect("The wrapper should have set MIRI_SYSROOT"); + cmd.arg("--sysroot"); + cmd.arg(sysroot); + + // Then pass binary arguments. + cmd.arg("--"); + cmd.args(args); + + // Run it. + if verbose { + eprintln!("+ {:?}", cmd); + } + exec(cmd) } fn main() { @@ -529,7 +548,7 @@ fn main() { return; } - let mut args = std::env::args(); + let mut args = std::env::args_os(); // Skip binary name. args.next().unwrap(); @@ -540,7 +559,8 @@ fn main() { // binary crates for later interpretation. // - When we are executed due to CARGO_TARGET_RUNNER, we start interpretation based on the // flags that were stored earlier. - match &*args.next().unwrap() { + // FIXME: report errors for these unwraps. + match &*args.next().unwrap().to_str().unwrap() { "miri" => phase_cargo_miri(args), "rustc" => phase_cargo_rustc(args), binary => phase_cargo_runner(binary, args), From c41a039c56de183468fc5b428e61e2522991fd35 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 9 Sep 2020 08:58:29 +0200 Subject: [PATCH 2281/3747] patch --extern and --emit; test suite passes now! --- cargo-miri/bin.rs | 98 ++++++++++++++++++++++++--------- test-cargo-miri/run-test.py | 25 +++++---- test-cargo-miri/test.stdout.ref | 12 +--- 3 files changed, 90 insertions(+), 45 deletions(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index 57c0ec985ab8f..bf27195d5392f 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -47,14 +47,14 @@ enum MiriCommand { #[derive(Serialize, Deserialize)] struct CrateRunInfo { /// The command-line arguments. - args: Vec, + args: Vec, /// The environment. env: Vec<(OsString, OsString)>, } impl CrateRunInfo { /// Gather all the information we need. - fn collect(args: env::ArgsOs) -> Self { + fn collect(args: env::Args) -> Self { let args = args.collect(); let env = env::vars_os().collect(); CrateRunInfo { args, env } @@ -362,11 +362,11 @@ path = "lib.rs" } } -fn phase_cargo_miri(mut args: env::ArgsOs) { +fn phase_cargo_miri(mut args: env::Args) { // Require a subcommand before any flags. // We cannot know which of those flags take arguments and which do not, // so we cannot detect subcommands later. - let subcommand = match args.next().as_deref().and_then(|s| s.to_str()) { + let subcommand = match args.next().as_deref() { Some("test") => MiriCommand::Test, Some("run") => MiriCommand::Run, Some("setup") => MiriCommand::Setup, @@ -423,12 +423,12 @@ fn phase_cargo_miri(mut args: env::ArgsOs) { // Run cargo. if verbose { cmd.env("MIRI_VERBOSE", ""); // this makes `inside_cargo_rustc` verbose. - eprintln!("+ {:?}", cmd); + eprintln!("[cargo-miri miri] {:?}", cmd); } exec(cmd) } -fn phase_cargo_rustc(args: env::ArgsOs) { +fn phase_cargo_rustc(args: env::Args) { /// Determines if we are being invoked (as rustc) to build a crate for /// the "target" architecture, in contrast to the "host" architecture. /// Host crates are for build scripts and proc macros and still need to @@ -473,19 +473,41 @@ fn phase_cargo_rustc(args: env::ArgsOs) { // (and cargo passes this before the filename so it should be unique) get_arg_flag_value("extra-filename").unwrap_or(String::new()), )); + if verbose { + eprintln!("[cargo-miri rustc] writing run info to {:?}", path.display()); + } let file = File::create(&path) - .unwrap_or_else(|_| show_error(format!("Cannot create {}", path.display()))); + .unwrap_or_else(|_| show_error(format!("Cannot create {:?}", path.display()))); let file = BufWriter::new(file); serde_json::ser::to_writer(file, &info) - .unwrap_or_else(|_| show_error(format!("Cannot write to {}", path.display()))); + .unwrap_or_else(|_| show_error(format!("Cannot write to {:?}", path.display()))); return; } let mut cmd = miri(); - // Forward arguments. - cmd.args(args); - // FIXME: Make the build check-only! + // Forward arguments, but (only for target crates!) remove "link" from "--emit" to make this a check-only build. + let emit_flag = "--emit"; + for arg in args { + if target_crate && arg.starts_with(emit_flag) { + // Patch this argument. First, extract its value. + let val = &arg[emit_flag.len()..]; + assert!(val.starts_with("="), "`cargo` should pass `--emit=X` as one argument"); + let val = &val[1..]; + let mut val: Vec<_> = val.split(',').collect(); + // Now make sure "link" is not in there, but "metadata" is. + if let Some(i) = val.iter().position(|&s| s == "link") { + val.remove(i); + if !val.iter().any(|&s| s == "metadata") { + val.push("metadata"); + } + } + cmd.arg(format!("{}={}", emit_flag, val.join(","))); + // FIXME: due to this, the `.rlib` file does not get created and cargo re-triggers the build each time. + } else { + cmd.arg(arg); + } + } // We make sure to only specify our custom Xargo sysroot for target crates - that is, // crates which are needed for interpretation by Miri. proc-macros and build scripts @@ -503,36 +525,60 @@ fn phase_cargo_rustc(args: env::ArgsOs) { // Run it. if verbose { - eprintln!("+ {:?}", cmd); + eprintln!("[cargo-miri rustc] {:?}", cmd); } exec(cmd) } -fn phase_cargo_runner(binary: &str, args: env::ArgsOs) { +fn phase_cargo_runner(binary: &str, binary_args: env::Args) { let verbose = std::env::var_os("MIRI_VERBOSE").is_some(); let file = File::open(binary) - .unwrap_or_else(|_| show_error(format!("File {:?} not found, or cargo-miri invoked incorrectly", binary))); + .unwrap_or_else(|_| show_error(format!("File {:?} not found or `cargo-miri` invoked incorrectly; please only invoke this binary through `cargo miri`", binary))); let file = BufReader::new(file); let info: CrateRunInfo = serde_json::from_reader(file) .unwrap_or_else(|_| show_error(format!("File {:?} does not contain valid JSON", binary))); - // FIXME: remove the file. + fs::remove_file(binary) + .unwrap_or_else(|_| show_error(format!("Unable to remove file {:?}", binary))); let mut cmd = miri(); - // Forward rustc arguments,with our sysroot. - cmd.args(info.args); + // Forward rustc arguments. We need to patch "--extern" filenames because + // we forced a check-only build without cargo knowing about that: replace `.rlib` suffix by `.rmeta`. + let mut args = info.args.into_iter(); + let extern_flag = "--extern"; + while let Some(arg) = args.next() { + if arg == extern_flag { + let next_arg = args.next().expect("`--extern` should be followed by a filename"); + let next_arg = next_arg.strip_suffix(".rlib").expect("all extern filenames should end in `.rlib`"); + cmd.arg(extern_flag); + cmd.arg(format!("{}.rmeta", next_arg)); + } else { + cmd.arg(arg); + } + } + // Set sysroot. let sysroot = env::var_os("MIRI_SYSROOT").expect("The wrapper should have set MIRI_SYSROOT"); cmd.arg("--sysroot"); cmd.arg(sysroot); + // Respect `MIRIFLAGS`. + if let Ok(a) = env::var("MIRIFLAGS") { + // This code is taken from `RUSTFLAGS` handling in cargo. + let args = a + .split(' ') + .map(str::trim) + .filter(|s| !s.is_empty()) + .map(str::to_string); + cmd.args(args); + } // Then pass binary arguments. cmd.arg("--"); - cmd.args(args); + cmd.args(binary_args); // Run it. if verbose { - eprintln!("+ {:?}", cmd); + eprintln!("[cargo-miri runner] {:?}", cmd); } exec(cmd) } @@ -548,7 +594,9 @@ fn main() { return; } - let mut args = std::env::args_os(); + // Rustc does not support non-UTF-8 arguments so we make no attempt either. + // (We do support non-UTF-8 environment variables though.) + let mut args = std::env::args(); // Skip binary name. args.next().unwrap(); @@ -559,10 +607,10 @@ fn main() { // binary crates for later interpretation. // - When we are executed due to CARGO_TARGET_RUNNER, we start interpretation based on the // flags that were stored earlier. - // FIXME: report errors for these unwraps. - match &*args.next().unwrap().to_str().unwrap() { - "miri" => phase_cargo_miri(args), - "rustc" => phase_cargo_rustc(args), - binary => phase_cargo_runner(binary, args), + match args.next().as_deref() { + Some("miri") => phase_cargo_miri(args), + Some("rustc") => phase_cargo_rustc(args), + Some(binary) => phase_cargo_runner(binary, args), + _ => show_error(format!("`cargo-miri` called without first argument; please only invoke this binary through `cargo miri`")), } } diff --git a/test-cargo-miri/run-test.py b/test-cargo-miri/run-test.py index a258c7f73c2d9..6a28f1b403e8f 100755 --- a/test-cargo-miri/run-test.py +++ b/test-cargo-miri/run-test.py @@ -21,13 +21,16 @@ def cargo_miri(cmd): args += ["--target", os.environ['MIRI_TEST_TARGET']] return args -def test(name, cmd, stdout_ref, stderr_ref): +def test(name, cmd, stdout_ref, stderr_ref, env={}): print("==> Testing `{}` <==".format(name)) ## Call `cargo miri`, capture all output + p_env = os.environ.copy() + p_env.update(env) p = subprocess.Popen( cmd, stdout=subprocess.PIPE, - stderr=subprocess.PIPE + stderr=subprocess.PIPE, + env=p_env, ) (stdout, stderr) = p.communicate() stdout = stdout.decode("UTF-8") @@ -55,29 +58,31 @@ def test_cargo_miri_run(): "stdout.ref", "stderr.ref" ) test("cargo miri run (with arguments)", - cargo_miri("run") + ["--", "--", "hello world", '"hello world"'], + cargo_miri("run") + ["--", "hello world", '"hello world"'], "stdout.ref", "stderr.ref2" ) def test_cargo_miri_test(): test("cargo miri test", - cargo_miri("test") + ["--", "-Zmiri-seed=feed"], - "test.stdout.ref", "test.stderr.ref" + cargo_miri("test"), + "test.stdout.ref", "test.stderr.ref", + env={'MIRIFLAGS': "-Zmiri-seed=feed"}, ) test("cargo miri test (with filter)", - cargo_miri("test") + ["--", "--", "le1"], + cargo_miri("test") + ["--", "--format=pretty", "le1"], "test.stdout.ref2", "test.stderr.ref" ) test("cargo miri test (without isolation)", - cargo_miri("test") + ["--", "-Zmiri-disable-isolation", "--", "num_cpus"], - "test.stdout.ref3", "test.stderr.ref" + cargo_miri("test") + ["--", "--format=pretty", "num_cpus"], + "test.stdout.ref3", "test.stderr.ref", + env={'MIRIFLAGS': "-Zmiri-disable-isolation"}, ) test("cargo miri test (test target)", - cargo_miri("test") + ["--test", "test"], + cargo_miri("test") + ["--test", "test", "--", "--format=pretty"], "test.stdout.ref4", "test.stderr.ref" ) test("cargo miri test (bin target)", - cargo_miri("test") + ["--bin", "cargo-miri-test"], + cargo_miri("test") + ["--bin", "cargo-miri-test", "--", "--format=pretty"], "test.stdout.ref5", "test.stderr.ref" ) diff --git a/test-cargo-miri/test.stdout.ref b/test-cargo-miri/test.stdout.ref index 4260f5b3cb785..fa78cd3548783 100644 --- a/test-cargo-miri/test.stdout.ref +++ b/test-cargo-miri/test.stdout.ref @@ -1,18 +1,10 @@ running 1 test -test test::rng ... ok - +. test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out running 7 tests -test do_panic ... ok -test does_not_work_on_miri ... ignored -test entropy_rng ... ok -test fail_index_check ... ok -test num_cpus ... ok -test simple1 ... ok -test simple2 ... ok - +.i..... test result: ok. 6 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out From ee7d5895302d621fdef40590f072cbed940d204e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 8 Sep 2020 09:56:21 +0200 Subject: [PATCH 2282/3747] test respecting 'test=false', and what happens with doctests --- test-cargo-miri/Cargo.toml | 4 ++++ test-cargo-miri/src/lib.rs | 7 +++++++ 2 files changed, 11 insertions(+) create mode 100644 test-cargo-miri/src/lib.rs diff --git a/test-cargo-miri/Cargo.toml b/test-cargo-miri/Cargo.toml index 3abb437049f0f..68970d7d1662b 100644 --- a/test-cargo-miri/Cargo.toml +++ b/test-cargo-miri/Cargo.toml @@ -10,3 +10,7 @@ byteorder = "1.0" [dev-dependencies] rand = { version = "0.7", features = ["small_rng"] } num_cpus = "1.10.1" + +[lib] +test = false +doctest = false # FIXME: doctests should be skipped automatically until we can run them... diff --git a/test-cargo-miri/src/lib.rs b/test-cargo-miri/src/lib.rs new file mode 100644 index 0000000000000..064954ba98003 --- /dev/null +++ b/test-cargo-miri/src/lib.rs @@ -0,0 +1,7 @@ +/// Doc-test test +/// ```rust +/// assert!(true); +/// ``` +pub fn make_true() -> bool { + true +} From 9a9988a4b04622805ae5060dcafc123964da2c3d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 8 Sep 2020 10:01:18 +0200 Subject: [PATCH 2283/3747] update docs, and also use MIRIFLAGS for the test suite --- README.md | 16 ++++++++-------- ci.sh | 2 +- tests/compiletest.rs | 2 +- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index d8474868703d6..67161974b1843 100644 --- a/README.md +++ b/README.md @@ -83,11 +83,10 @@ Now you can run your project in Miri: The first time you run Miri, it will perform some extra setup and install some dependencies. It will ask you for confirmation before installing anything. -You can pass arguments to Miri after the first `--`, and pass arguments to the -interpreted program or test suite after the second `--`. For example, `cargo -miri run -- -Zmiri-disable-stacked-borrows` runs the program without checking -the aliasing of references. To filter the tests being run, use `cargo miri test --- -- filter`. +`cargo miri run/test` supports the exact same flags as `cargo run/test`. You +can pass arguments to Miri via `MIRIFLAGS`. For example, +`MIRIFLAGS="-Zmiri-disable-stacked-borrows" cargo miri run` runs the program +without checking the aliasing of references. Miri supports cross-execution: if you want to run the program as if it was a Linux program, you can do `cargo miri run --target x86_64-unknown-linux-gnu`. @@ -163,7 +162,8 @@ up the sysroot. If you are using `miri` (the Miri driver) directly, see the ## Miri `-Z` flags and environment variables [miri-flags]: #miri--z-flags-and-environment-variables -Miri adds its own set of `-Z` flags: +Miri adds its own set of `-Z` flags, which are usually set via the `MIRIFLAGS` +environment variable: * `-Zmiri-disable-alignment-check` disables checking pointer alignment, so you can focus on other failures, but it means Miri can miss bugs in your program. @@ -229,14 +229,14 @@ Moreover, Miri recognizes some environment variables: * `MIRI_LOG`, `MIRI_BACKTRACE` control logging and backtrace printing during Miri executions, also [see above][testing-miri]. +* `MIRIFLAGS` (recognized by `cargo miri` and the test suite) defines extra + flags to be passed to Miri. * `MIRI_SYSROOT` (recognized by `cargo miri` and the test suite) indicates the sysroot to use. To do the same thing with `miri` directly, use the `--sysroot` flag. * `MIRI_TEST_TARGET` (recognized by the test suite) indicates which target architecture to test against. `miri` and `cargo miri` accept the `--target` flag for the same purpose. -* `MIRI_TEST_FLAGS` (recognized by the test suite) defines extra flags to be - passed to Miri. The following environment variables are internal, but used to communicate between different Miri binaries, and as such worth documenting: diff --git a/ci.sh b/ci.sh index 915a4cf2fd3d1..12683a2fccbec 100755 --- a/ci.sh +++ b/ci.sh @@ -26,7 +26,7 @@ function run_tests { if ! [ -n "${MIRI_TEST_TARGET+exists}" ]; then # Only for host architecture: tests with MIR optimizations # FIXME: only testing level 2 because of . - MIRI_TEST_FLAGS="-Z mir-opt-level=2" ./miri test --locked + MIRIFLAGS="-Z mir-opt-level=2" ./miri test --locked fi # "miri test" has built the sysroot for us, now this should pass without # any interactive questions. diff --git a/tests/compiletest.rs b/tests/compiletest.rs index a64f0edb94645..35c1de3399c02 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -27,7 +27,7 @@ fn run_tests(mode: &str, path: &str, target: &str) { if let Ok(sysroot) = std::env::var("MIRI_SYSROOT") { flags.push(format!("--sysroot {}", sysroot)); } - if let Ok(extra_flags) = std::env::var("MIRI_TEST_FLAGS") { + if let Ok(extra_flags) = std::env::var("MIRIFLAGS") { flags.push(extra_flags); } From 0019fe2459eb353688c8578459eded7d17359d22 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 8 Sep 2020 11:08:46 +0200 Subject: [PATCH 2284/3747] fix typo Co-authored-by: Oli Scherer --- cargo-miri/bin.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index bf27195d5392f..f5c402de72766 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -462,7 +462,7 @@ fn phase_cargo_rustc(args: env::Args) { // But we cannot run it here, as cargo invoked us as a compiler -- our stdin and stdout are not // like we want them. // Instead of compiling, we write JSON into the output file with all the relevant command-line flags - // and environment variables; this is sued alter when cargo calls us again in the CARGO_TARGET_RUNNER phase. + // and environment variables; this is used when cargo calls us again in the CARGO_TARGET_RUNNER phase. let info = CrateRunInfo::collect(args); let mut path = PathBuf::from(get_arg_flag_value("--out-dir").unwrap()); From 147330cc3603260d17085f3abcf7e62ca01b44ef Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 8 Sep 2020 20:08:11 +0200 Subject: [PATCH 2285/3747] even when not linking, create stub .rlib files to fool cargo --- cargo-miri/bin.rs | 99 +++++++++++++++++++++++++++++------------------ 1 file changed, 61 insertions(+), 38 deletions(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index f5c402de72766..1aa1d4d87e447 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -136,9 +136,13 @@ fn xargo_check() -> Command { Command::new(env::var_os("XARGO_CHECK").unwrap_or_else(|| OsString::from("xargo-check"))) } -fn exec(mut cmd: Command) -> ! { +/// Execute the command if it fails, fail this process with the same exit code. +/// Otherwise, continue. +fn exec(mut cmd: Command) { let exit_status = cmd.status().expect("failed to run command"); - std::process::exit(exit_status.code().unwrap_or(-1)) + if exit_status.success().not() { + std::process::exit(exit_status.code().unwrap_or(-1)) + } } fn xargo_version() -> Option<(u32, u32, u32)> { @@ -454,6 +458,20 @@ fn phase_cargo_rustc(args: env::Args) { (is_bin || is_test) && !print } + fn out_filename(prefix: &str, suffix: &str) -> PathBuf { + let mut path = PathBuf::from(get_arg_flag_value("--out-dir").unwrap()); + path.push(format!( + "{}{}{}{}", + prefix, + get_arg_flag_value("--crate-name").unwrap(), + // This is technically a `-C` flag but the prefix seems unique enough... + // (and cargo passes this before the filename so it should be unique) + get_arg_flag_value("extra-filename").unwrap_or(String::new()), + suffix, + )); + path + } + let verbose = std::env::var_os("MIRI_VERBOSE").is_some(); let target_crate = is_target_crate(); @@ -464,59 +482,57 @@ fn phase_cargo_rustc(args: env::Args) { // Instead of compiling, we write JSON into the output file with all the relevant command-line flags // and environment variables; this is used when cargo calls us again in the CARGO_TARGET_RUNNER phase. let info = CrateRunInfo::collect(args); + // FIXME: Windows might need a ".exe" suffix. + let filename = out_filename("", ""); - let mut path = PathBuf::from(get_arg_flag_value("--out-dir").unwrap()); - path.push(format!( - "{}{}", - get_arg_flag_value("--crate-name").unwrap(), - // This is technically a `-C` flag but the prefix seems unique enough... - // (and cargo passes this before the filename so it should be unique) - get_arg_flag_value("extra-filename").unwrap_or(String::new()), - )); if verbose { - eprintln!("[cargo-miri rustc] writing run info to {:?}", path.display()); + eprintln!("[cargo-miri rustc] writing run info to {:?}", filename.display()); } - let file = File::create(&path) - .unwrap_or_else(|_| show_error(format!("Cannot create {:?}", path.display()))); + let file = File::create(&filename) + .unwrap_or_else(|_| show_error(format!("Cannot create {:?}", filename.display()))); let file = BufWriter::new(file); serde_json::ser::to_writer(file, &info) - .unwrap_or_else(|_| show_error(format!("Cannot write to {:?}", path.display()))); + .unwrap_or_else(|_| show_error(format!("Cannot write to {:?}", filename.display()))); return; } let mut cmd = miri(); - // Forward arguments, but (only for target crates!) remove "link" from "--emit" to make this a check-only build. - let emit_flag = "--emit"; - for arg in args { - if target_crate && arg.starts_with(emit_flag) { - // Patch this argument. First, extract its value. - let val = &arg[emit_flag.len()..]; - assert!(val.starts_with("="), "`cargo` should pass `--emit=X` as one argument"); - let val = &val[1..]; - let mut val: Vec<_> = val.split(',').collect(); - // Now make sure "link" is not in there, but "metadata" is. - if let Some(i) = val.iter().position(|&s| s == "link") { - val.remove(i); - if !val.iter().any(|&s| s == "metadata") { - val.push("metadata"); + let mut emit_link_hack = false; + // Arguments are treated very differently depending on whether this crate is + // for interpretation by Miri, or for use by a build script / proc macro. + if target_crate { + // Forward arguments, butremove "link" from "--emit" to make this a check-only build. + let emit_flag = "--emit"; + for arg in args { + if arg.starts_with(emit_flag) { + // Patch this argument. First, extract its value. + let val = &arg[emit_flag.len()..]; + assert!(val.starts_with("="), "`cargo` should pass `--emit=X` as one argument"); + let val = &val[1..]; + let mut val: Vec<_> = val.split(',').collect(); + // Now make sure "link" is not in there, but "metadata" is. + if let Some(i) = val.iter().position(|&s| s == "link") { + emit_link_hack = true; + val.remove(i); + if !val.iter().any(|&s| s == "metadata") { + val.push("metadata"); + } } + cmd.arg(format!("{}={}", emit_flag, val.join(","))); + } else { + cmd.arg(arg); } - cmd.arg(format!("{}={}", emit_flag, val.join(","))); - // FIXME: due to this, the `.rlib` file does not get created and cargo re-triggers the build each time. - } else { - cmd.arg(arg); } - } - // We make sure to only specify our custom Xargo sysroot for target crates - that is, - // crates which are needed for interpretation by Miri. proc-macros and build scripts - // should use the default sysroot. - if target_crate { + // Use our custom sysroot. let sysroot = env::var_os("MIRI_SYSROOT").expect("The wrapper should have set MIRI_SYSROOT"); cmd.arg("--sysroot"); cmd.arg(sysroot); + } else { + // For host crates, just forward everything. + cmd.args(args); } // We want to compile, not interpret. We still use Miri to make sure the compiler version etc @@ -527,7 +543,14 @@ fn phase_cargo_rustc(args: env::Args) { if verbose { eprintln!("[cargo-miri rustc] {:?}", cmd); } - exec(cmd) + exec(cmd); + + // Create a stub .rlib file if "link" was requested by cargo. + if emit_link_hack { + // FIXME: is "lib" always right? + let filename = out_filename("lib", ".rlib"); + File::create(filename).expect("Failed to create rlib file"); + } } fn phase_cargo_runner(binary: &str, binary_args: env::Args) { From 53eab7195a8b4c68e3b51e928ffed4b4580c9cf2 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 8 Sep 2020 20:18:08 +0200 Subject: [PATCH 2286/3747] make our filename handling work better across platforms --- cargo-miri/bin.rs | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index 1aa1d4d87e447..3e42cf1f77229 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -486,14 +486,14 @@ fn phase_cargo_rustc(args: env::Args) { let filename = out_filename("", ""); if verbose { - eprintln!("[cargo-miri rustc] writing run info to {:?}", filename.display()); + eprintln!("[cargo-miri rustc] writing run info to `{}`", filename.display()); } let file = File::create(&filename) - .unwrap_or_else(|_| show_error(format!("Cannot create {:?}", filename.display()))); + .unwrap_or_else(|_| show_error(format!("Cannot create `{}`", filename.display()))); let file = BufWriter::new(file); serde_json::ser::to_writer(file, &info) - .unwrap_or_else(|_| show_error(format!("Cannot write to {:?}", filename.display()))); + .unwrap_or_else(|_| show_error(format!("Cannot write to `{}`", filename.display()))); return; } @@ -502,7 +502,7 @@ fn phase_cargo_rustc(args: env::Args) { // Arguments are treated very differently depending on whether this crate is // for interpretation by Miri, or for use by a build script / proc macro. if target_crate { - // Forward arguments, butremove "link" from "--emit" to make this a check-only build. + // Forward arguments, but remove "link" from "--emit" to make this a check-only build. let emit_flag = "--emit"; for arg in args { if arg.starts_with(emit_flag) { @@ -547,21 +547,26 @@ fn phase_cargo_rustc(args: env::Args) { // Create a stub .rlib file if "link" was requested by cargo. if emit_link_hack { - // FIXME: is "lib" always right? + // Some platforms prepend "lib", some do not... let's just create both files. let filename = out_filename("lib", ".rlib"); File::create(filename).expect("Failed to create rlib file"); + let filename = out_filename("", ".rlib"); + File::create(filename).expect("Failed to create rlib file"); } } fn phase_cargo_runner(binary: &str, binary_args: env::Args) { let verbose = std::env::var_os("MIRI_VERBOSE").is_some(); - let file = File::open(binary) + // Strip extension from binary name (Windows adds ".exe"). + let mut filename = PathBuf::from(binary); + filename.set_extension(""); + let file = File::open(&filename) .unwrap_or_else(|_| show_error(format!("File {:?} not found or `cargo-miri` invoked incorrectly; please only invoke this binary through `cargo miri`", binary))); let file = BufReader::new(file); let info: CrateRunInfo = serde_json::from_reader(file) .unwrap_or_else(|_| show_error(format!("File {:?} does not contain valid JSON", binary))); - fs::remove_file(binary) + fs::remove_file(&filename) .unwrap_or_else(|_| show_error(format!("Unable to remove file {:?}", binary))); let mut cmd = miri(); From c793d6036a33eb6df5d523aeb6f5fbe375d8b3c7 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 9 Sep 2020 01:00:09 +0200 Subject: [PATCH 2287/3747] handle binary suffices (for Windows); stop deleting fake binary --- cargo-miri/bin.rs | 35 ++++++++++++++++++----------------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index 3e42cf1f77229..537f071c9d463 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -59,6 +59,14 @@ impl CrateRunInfo { let env = env::vars_os().collect(); CrateRunInfo { args, env } } + + fn store(&self, filename: &Path) { + let file = File::create(filename) + .unwrap_or_else(|_| show_error(format!("Cannot create `{}`", filename.display()))); + let file = BufWriter::new(file); + serde_json::ser::to_writer(file, self) + .unwrap_or_else(|_| show_error(format!("Cannot write to `{}`", filename.display()))); + } } fn show_help() { @@ -482,18 +490,16 @@ fn phase_cargo_rustc(args: env::Args) { // Instead of compiling, we write JSON into the output file with all the relevant command-line flags // and environment variables; this is used when cargo calls us again in the CARGO_TARGET_RUNNER phase. let info = CrateRunInfo::collect(args); - // FIXME: Windows might need a ".exe" suffix. let filename = out_filename("", ""); - if verbose { eprintln!("[cargo-miri rustc] writing run info to `{}`", filename.display()); } - let file = File::create(&filename) - .unwrap_or_else(|_| show_error(format!("Cannot create `{}`", filename.display()))); - let file = BufWriter::new(file); - serde_json::ser::to_writer(file, &info) - .unwrap_or_else(|_| show_error(format!("Cannot write to `{}`", filename.display()))); + info.store(&filename); + // For Windows, do the same thing again with `.exe` appended to the filename. + // (Need to do this here as cargo moves that "binary" to a different place before running it.) + info.store(&out_filename("", ".exe")); + return; } @@ -558,16 +564,11 @@ fn phase_cargo_rustc(args: env::Args) { fn phase_cargo_runner(binary: &str, binary_args: env::Args) { let verbose = std::env::var_os("MIRI_VERBOSE").is_some(); - // Strip extension from binary name (Windows adds ".exe"). - let mut filename = PathBuf::from(binary); - filename.set_extension(""); - let file = File::open(&filename) + let file = File::open(&binary) .unwrap_or_else(|_| show_error(format!("File {:?} not found or `cargo-miri` invoked incorrectly; please only invoke this binary through `cargo miri`", binary))); let file = BufReader::new(file); let info: CrateRunInfo = serde_json::from_reader(file) .unwrap_or_else(|_| show_error(format!("File {:?} does not contain valid JSON", binary))); - fs::remove_file(&filename) - .unwrap_or_else(|_| show_error(format!("Unable to remove file {:?}", binary))); let mut cmd = miri(); // Forward rustc arguments. We need to patch "--extern" filenames because @@ -593,10 +594,10 @@ fn phase_cargo_runner(binary: &str, binary_args: env::Args) { if let Ok(a) = env::var("MIRIFLAGS") { // This code is taken from `RUSTFLAGS` handling in cargo. let args = a - .split(' ') - .map(str::trim) - .filter(|s| !s.is_empty()) - .map(str::to_string); + .split(' ') + .map(str::trim) + .filter(|s| !s.is_empty()) + .map(str::to_string); cmd.args(args); } From 10f58b3eabf641151c7a02aadf8a2911ad24f281 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 9 Sep 2020 08:40:06 +0200 Subject: [PATCH 2288/3747] fix Miri script on macOS --- miri | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/miri b/miri index f53c21ff115cf..aef61b6dd68d3 100755 --- a/miri +++ b/miri @@ -39,7 +39,11 @@ EOF TARGET=$(rustc --version --verbose | grep "^host:" | cut -d ' ' -f 2) SYSROOT=$(rustc --print sysroot) LIBDIR=$SYSROOT/lib/rustlib/$TARGET/lib -MIRIDIR=$(readlink -e "$(dirname "$0")") +MIRIDIR=$(dirname "$0") +if readlink -e . >/dev/null; then + # This platform supports `readlink -e`. + MIRIDIR=$(readlink -e "$MIRIDIR") +fi if ! test -d "$LIBDIR"; then echo "Something went wrong determining the library dir." echo "I got $LIBDIR but that does not exist." From 119bf4d6073e0675714c1ee1f3f4f9b655b83544 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 9 Sep 2020 08:51:41 +0200 Subject: [PATCH 2289/3747] forward build-time env vars to binary, and test that we do --- cargo-miri/bin.rs | 27 +++++++++++++++++---------- test-cargo-miri/test.stdout.ref | 6 +++--- test-cargo-miri/test.stdout.ref2 | 2 +- test-cargo-miri/test.stdout.ref3 | 2 +- test-cargo-miri/test.stdout.ref4 | 5 +++-- test-cargo-miri/tests/test.rs | 6 ++++++ 6 files changed, 31 insertions(+), 17 deletions(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index 537f071c9d463..7ae3c7fe6cfde 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -375,6 +375,16 @@ path = "lib.rs" } fn phase_cargo_miri(mut args: env::Args) { + // Check for version and help flags even when invoked as `cargo-miri`. + if has_arg_flag("--help") || has_arg_flag("-h") { + show_help(); + return; + } + if has_arg_flag("--version") || has_arg_flag("-V") { + show_version(); + return; + } + // Require a subcommand before any flags. // We cannot know which of those flags take arguments and which do not, // so we cannot detect subcommands later. @@ -570,6 +580,13 @@ fn phase_cargo_runner(binary: &str, binary_args: env::Args) { let info: CrateRunInfo = serde_json::from_reader(file) .unwrap_or_else(|_| show_error(format!("File {:?} does not contain valid JSON", binary))); + // Set missing env vars. + for (name, val) in info.env { + if env::var_os(&name).is_none() { + env::set_var(name, val); + } + } + let mut cmd = miri(); // Forward rustc arguments. We need to patch "--extern" filenames because // we forced a check-only build without cargo knowing about that: replace `.rlib` suffix by `.rmeta`. @@ -613,16 +630,6 @@ fn phase_cargo_runner(binary: &str, binary_args: env::Args) { } fn main() { - // Check for version and help flags even when invoked as `cargo-miri`. - if has_arg_flag("--help") || has_arg_flag("-h") { - show_help(); - return; - } - if has_arg_flag("--version") || has_arg_flag("-V") { - show_version(); - return; - } - // Rustc does not support non-UTF-8 arguments so we make no attempt either. // (We do support non-UTF-8 environment variables though.) let mut args = std::env::args(); diff --git a/test-cargo-miri/test.stdout.ref b/test-cargo-miri/test.stdout.ref index fa78cd3548783..1eb18fe88768a 100644 --- a/test-cargo-miri/test.stdout.ref +++ b/test-cargo-miri/test.stdout.ref @@ -4,7 +4,7 @@ running 1 test test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out -running 7 tests -.i..... -test result: ok. 6 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out +running 8 tests +..i..... +test result: ok. 7 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out diff --git a/test-cargo-miri/test.stdout.ref2 b/test-cargo-miri/test.stdout.ref2 index 37efb8c3ee896..d426bdf6db632 100644 --- a/test-cargo-miri/test.stdout.ref2 +++ b/test-cargo-miri/test.stdout.ref2 @@ -7,5 +7,5 @@ test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 1 filtered out running 1 test test simple1 ... ok -test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 6 filtered out +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 7 filtered out diff --git a/test-cargo-miri/test.stdout.ref3 b/test-cargo-miri/test.stdout.ref3 index c5c39de109d2a..bc4a7c47e9f51 100644 --- a/test-cargo-miri/test.stdout.ref3 +++ b/test-cargo-miri/test.stdout.ref3 @@ -7,5 +7,5 @@ test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 1 filtered out running 1 test test num_cpus ... ok -test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 6 filtered out +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 7 filtered out diff --git a/test-cargo-miri/test.stdout.ref4 b/test-cargo-miri/test.stdout.ref4 index b6403bf6c0916..32bbcf9bf275b 100644 --- a/test-cargo-miri/test.stdout.ref4 +++ b/test-cargo-miri/test.stdout.ref4 @@ -1,5 +1,6 @@ -running 7 tests +running 8 tests +test cargo_env ... ok test do_panic ... ok test does_not_work_on_miri ... ignored test entropy_rng ... ok @@ -8,5 +9,5 @@ test num_cpus ... ok test simple1 ... ok test simple2 ... ok -test result: ok. 6 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out +test result: ok. 7 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out diff --git a/test-cargo-miri/tests/test.rs b/test-cargo-miri/tests/test.rs index e38dc7a926c9e..35e05368803a6 100644 --- a/test-cargo-miri/tests/test.rs +++ b/test-cargo-miri/tests/test.rs @@ -42,6 +42,12 @@ fn num_cpus() { assert_eq!(num_cpus::get(), 1); } +#[test] +fn cargo_env() { + assert_eq!(env!("CARGO_PKG_NAME"), "cargo-miri-test"); + env!("CARGO_BIN_EXE_cargo-miri-test"); // Asserts that this exists. +} + #[test] #[should_panic(expected="Explicit panic")] fn do_panic() { // In large, friendly letters :) From 74fdb5cf2cbd069ad2890ee642d66fc59b3ddc0e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 9 Sep 2020 09:12:26 +0200 Subject: [PATCH 2290/3747] patch away --error-format and --json so that errors are rendered properly --- cargo-miri/bin.rs | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index 7ae3c7fe6cfde..bac38e3c80188 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -588,16 +588,32 @@ fn phase_cargo_runner(binary: &str, binary_args: env::Args) { } let mut cmd = miri(); - // Forward rustc arguments. We need to patch "--extern" filenames because - // we forced a check-only build without cargo knowing about that: replace `.rlib` suffix by `.rmeta`. + // Forward rustc arguments. + // We need to patch "--extern" filenames because we forced a check-only + // build without cargo knowing about that: replace `.rlib` suffix by + // `.rmeta`. + // We also need to remove `--error-format` as cargo specifies that to be JSON, + // but when we run here, cargo does not interpret the JSON any more. `--json` + // then also nees to be dropped. let mut args = info.args.into_iter(); let extern_flag = "--extern"; + let error_format_flag = "--error-format"; + let json_flag = "--json"; while let Some(arg) = args.next() { if arg == extern_flag { + // `--extern` is always passed as a separate argument by cargo. let next_arg = args.next().expect("`--extern` should be followed by a filename"); let next_arg = next_arg.strip_suffix(".rlib").expect("all extern filenames should end in `.rlib`"); cmd.arg(extern_flag); cmd.arg(format!("{}.rmeta", next_arg)); + } else if arg.starts_with(error_format_flag) { + let suffix = &arg[error_format_flag.len()..]; + assert!(suffix.starts_with('=')); + // Drop this argument. + } else if arg.starts_with(json_flag) { + let suffix = &arg[json_flag.len()..]; + assert!(suffix.starts_with('=')); + // Drop this argument. } else { cmd.arg(arg); } From 504c617cd4d1f67e8f472b559d32ab081b9c804e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 9 Sep 2020 09:18:10 +0200 Subject: [PATCH 2291/3747] test reading from stdin --- test-cargo-miri/run-test.py | 19 +++++++++---------- test-cargo-miri/src/main.rs | 18 ++++++++++++++++++ test-cargo-miri/stdout.ref | 2 ++ test-cargo-miri/stdout.ref2 | 1 + 4 files changed, 30 insertions(+), 10 deletions(-) create mode 100644 test-cargo-miri/stdout.ref2 diff --git a/test-cargo-miri/run-test.py b/test-cargo-miri/run-test.py index 6a28f1b403e8f..877a2a5706196 100755 --- a/test-cargo-miri/run-test.py +++ b/test-cargo-miri/run-test.py @@ -21,18 +21,19 @@ def cargo_miri(cmd): args += ["--target", os.environ['MIRI_TEST_TARGET']] return args -def test(name, cmd, stdout_ref, stderr_ref, env={}): +def test(name, cmd, stdout_ref, stderr_ref, stdin=b'', env={}): print("==> Testing `{}` <==".format(name)) ## Call `cargo miri`, capture all output p_env = os.environ.copy() p_env.update(env) p = subprocess.Popen( cmd, + stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=p_env, ) - (stdout, stderr) = p.communicate() + (stdout, stderr) = p.communicate(input=stdin) stdout = stdout.decode("UTF-8") stderr = stderr.decode("UTF-8") # Show output @@ -51,15 +52,13 @@ def test(name, cmd, stdout_ref, stderr_ref, env={}): def test_cargo_miri_run(): test("cargo miri run", cargo_miri("run"), - "stdout.ref", "stderr.ref" - ) - test("cargo miri run (with target)", - cargo_miri("run") + ["--bin", "cargo-miri-test"], - "stdout.ref", "stderr.ref" + "stdout.ref", "stderr.ref", + stdin=b'12\n21\n', + env={'MIRIFLAGS': "-Zmiri-disable-isolation"}, ) - test("cargo miri run (with arguments)", - cargo_miri("run") + ["--", "hello world", '"hello world"'], - "stdout.ref", "stderr.ref2" + test("cargo miri run (with arguments and target)", + cargo_miri("run") + ["--bin", "cargo-miri-test", "--", "hello world", '"hello world"'], + "stdout.ref2", "stderr.ref2" ) def test_cargo_miri_test(): diff --git a/test-cargo-miri/src/main.rs b/test-cargo-miri/src/main.rs index d3663ec849d36..0079328ff6059 100644 --- a/test-cargo-miri/src/main.rs +++ b/test-cargo-miri/src/main.rs @@ -1,4 +1,6 @@ use byteorder::{BigEndian, ByteOrder}; +#[cfg(unix)] +use std::io::{self, BufRead}; fn main() { // Exercise external crate, printing to stdout. @@ -11,6 +13,22 @@ fn main() { for arg in std::env::args() { eprintln!("{}", arg); } + + // If there were no arguments, access stdin. + if std::env::args().len() <= 1 { + #[cfg(unix)] + for line in io::stdin().lock().lines() { + let num: i32 = line.unwrap().parse().unwrap(); + println!("{}", 2*num); + } + // On non-Unix, reading from stdin is not support. So we hard-code the right answer. + #[cfg(not(unix))] + { + println!("24"); + println!("42"); + } + } + } #[cfg(test)] diff --git a/test-cargo-miri/stdout.ref b/test-cargo-miri/stdout.ref index 6710f307cb26d..2eab8df967d5f 100644 --- a/test-cargo-miri/stdout.ref +++ b/test-cargo-miri/stdout.ref @@ -1 +1,3 @@ 0x01020304 +24 +42 diff --git a/test-cargo-miri/stdout.ref2 b/test-cargo-miri/stdout.ref2 new file mode 100644 index 0000000000000..6710f307cb26d --- /dev/null +++ b/test-cargo-miri/stdout.ref2 @@ -0,0 +1 @@ +0x01020304 From ba3b354af98e07805168398f28d62f526b0471ad Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 9 Sep 2020 11:48:44 +0200 Subject: [PATCH 2292/3747] update comment Co-authored-by: Oli Scherer --- cargo-miri/bin.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index bac38e3c80188..70f8888676f39 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -444,7 +444,7 @@ fn phase_cargo_miri(mut args: env::Args) { // Run cargo. if verbose { - cmd.env("MIRI_VERBOSE", ""); // this makes `inside_cargo_rustc` verbose. + cmd.env("MIRI_VERBOSE", ""); // This makes the other phases verbose. eprintln!("[cargo-miri miri] {:?}", cmd); } exec(cmd) From 2205ed5bbb2fb8fb6c3b6a619815513f9d4c8038 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 11 Sep 2020 15:05:05 +0200 Subject: [PATCH 2293/3747] show proper warning about not running doctests --- cargo-miri/bin.rs | 22 ++++++++++++++++++++-- test-cargo-miri/Cargo.toml | 3 +-- test-cargo-miri/run-test.py | 4 ++-- test-cargo-miri/test.stderr.ref | 1 + test-cargo-miri/test.stderr.ref2 | 0 5 files changed, 24 insertions(+), 6 deletions(-) create mode 100644 test-cargo-miri/test.stderr.ref2 diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index 70f8888676f39..6dbaa9791df45 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -442,6 +442,9 @@ fn phase_cargo_miri(mut args: env::Args) { let runner_env_name = format!("CARGO_TARGET_{}_RUNNER", target.to_uppercase().replace('-', "_")); cmd.env(runner_env_name, &miri_path); + // Set rustdoc to us as well, so we can make it do nothing (see issue #584). + cmd.env("RUSTDOC", &miri_path); + // Run cargo. if verbose { cmd.env("MIRI_VERBOSE", ""); // This makes the other phases verbose. @@ -571,7 +574,7 @@ fn phase_cargo_rustc(args: env::Args) { } } -fn phase_cargo_runner(binary: &str, binary_args: env::Args) { +fn phase_cargo_runner(binary: &Path, binary_args: env::Args) { let verbose = std::env::var_os("MIRI_VERBOSE").is_some(); let file = File::open(&binary) @@ -659,10 +662,25 @@ fn main() { // binary crates for later interpretation. // - When we are executed due to CARGO_TARGET_RUNNER, we start interpretation based on the // flags that were stored earlier. + // On top of that, we are also called as RUSTDOC, but that is just a stub currently. match args.next().as_deref() { Some("miri") => phase_cargo_miri(args), Some("rustc") => phase_cargo_rustc(args), - Some(binary) => phase_cargo_runner(binary, args), + Some(arg) => { + // We have to distinguish the "runner" and "rustfmt" cases. + // As runner, the first argument is the binary (a file that should exist, with an absolute path); + // as rustfmt, the first argument is a flag (`--something`). + let binary = Path::new(arg); + if binary.exists() { + assert!(!arg.starts_with("--")); // not a flag + phase_cargo_runner(binary, args); + } else if arg.starts_with("--") { + // We are rustdoc. + eprintln!("Running doctests is not currently supported by Miri.") + } else { + show_error(format!("`cargo-miri` called with unexpected first argument `{}`; please only invoke this binary through `cargo miri`", arg)); + } + } _ => show_error(format!("`cargo-miri` called without first argument; please only invoke this binary through `cargo miri`")), } } diff --git a/test-cargo-miri/Cargo.toml b/test-cargo-miri/Cargo.toml index 68970d7d1662b..6bc11ef0cc5ad 100644 --- a/test-cargo-miri/Cargo.toml +++ b/test-cargo-miri/Cargo.toml @@ -12,5 +12,4 @@ rand = { version = "0.7", features = ["small_rng"] } num_cpus = "1.10.1" [lib] -test = false -doctest = false # FIXME: doctests should be skipped automatically until we can run them... +test = false # test that this is respected (will show in the output) diff --git a/test-cargo-miri/run-test.py b/test-cargo-miri/run-test.py index 877a2a5706196..82b3b88a63320 100755 --- a/test-cargo-miri/run-test.py +++ b/test-cargo-miri/run-test.py @@ -78,11 +78,11 @@ def test_cargo_miri_test(): ) test("cargo miri test (test target)", cargo_miri("test") + ["--test", "test", "--", "--format=pretty"], - "test.stdout.ref4", "test.stderr.ref" + "test.stdout.ref4", "test.stderr.ref2" ) test("cargo miri test (bin target)", cargo_miri("test") + ["--bin", "cargo-miri-test", "--", "--format=pretty"], - "test.stdout.ref5", "test.stderr.ref" + "test.stdout.ref5", "test.stderr.ref2" ) os.chdir(os.path.dirname(os.path.realpath(__file__))) diff --git a/test-cargo-miri/test.stderr.ref b/test-cargo-miri/test.stderr.ref index e69de29bb2d1d..a310169e305ee 100644 --- a/test-cargo-miri/test.stderr.ref +++ b/test-cargo-miri/test.stderr.ref @@ -0,0 +1 @@ +Running doctests is not currently supported by Miri. diff --git a/test-cargo-miri/test.stderr.ref2 b/test-cargo-miri/test.stderr.ref2 new file mode 100644 index 0000000000000..e69de29bb2d1d From 93bedd0a0920be8c26704a27ea0b0c754e438a4f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 11 Sep 2020 18:20:41 +0200 Subject: [PATCH 2294/3747] fix cargo-miri-test for cross-runs --- test-cargo-miri/run-test.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/test-cargo-miri/run-test.py b/test-cargo-miri/run-test.py index 82b3b88a63320..c7694f3854c87 100755 --- a/test-cargo-miri/run-test.py +++ b/test-cargo-miri/run-test.py @@ -62,18 +62,22 @@ def test_cargo_miri_run(): ) def test_cargo_miri_test(): + # rustdoc is not run on foreign targets + is_foreign = 'MIRI_TEST_TARGET' in os.environ + rustdoc_ref = "test.stderr.ref2" if is_foreign else "test.stderr.ref" + test("cargo miri test", cargo_miri("test"), - "test.stdout.ref", "test.stderr.ref", + "test.stdout.ref",rustdoc_ref, env={'MIRIFLAGS': "-Zmiri-seed=feed"}, ) test("cargo miri test (with filter)", cargo_miri("test") + ["--", "--format=pretty", "le1"], - "test.stdout.ref2", "test.stderr.ref" + "test.stdout.ref2", rustdoc_ref ) test("cargo miri test (without isolation)", cargo_miri("test") + ["--", "--format=pretty", "num_cpus"], - "test.stdout.ref3", "test.stderr.ref", + "test.stdout.ref3", rustdoc_ref, env={'MIRIFLAGS': "-Zmiri-disable-isolation"}, ) test("cargo miri test (test target)", From 174a92c39ae67243a775953781ad60044054b12f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 12 Sep 2020 12:41:23 +0200 Subject: [PATCH 2295/3747] detect when the user passes Miri's flags the old way, and support this for now --- cargo-miri/bin.rs | 61 ++++++++++++++++++++++++++++++++++------------- 1 file changed, 45 insertions(+), 16 deletions(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index 6dbaa9791df45..deb5733485d73 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -12,28 +12,21 @@ use rustc_version::VersionMeta; const XARGO_MIN_VERSION: (u32, u32, u32) = (0, 3, 22); -const CARGO_MIRI_HELP: &str = r#"Interprets bin crates and tests in Miri +const CARGO_MIRI_HELP: &str = r#"Runs binary crates and tests in Miri Usage: - cargo miri [subcommand] [...] [--] [...] [--] [...] + cargo miri [subcommand] [...] [--] [...] Subcommands: - run Run binaries (default) + run Run binaries test Run tests setup Only perform automatic setup, but without asking questions (for getting a proper libstd) -Common options: - -h, --help Print this message - --features Features to compile for the package - -V, --version Print version info and exit - -Other [options] are the same as `cargo check`. Everything after the first "--" is -passed verbatim to Miri, which will pass everything after the second "--" verbatim -to the interpreted program. +The cargo options are exactly the same as for `cargo run` and `cargo test`, respectively. Examples: - cargo miri run -- -Zmiri-disable-stacked-borrows - cargo miri test -- -- test-suite-filter + cargo miri run + cargo miri test -- test-suite-filter "#; #[derive(Copy, Clone, Debug, PartialEq, Eq)] @@ -393,7 +386,7 @@ fn phase_cargo_miri(mut args: env::Args) { Some("run") => MiriCommand::Run, Some("setup") => MiriCommand::Setup, // Invalid command. - _ => show_error(format!("`cargo miri` must be immediately followed by `test`, `run`, or `setup`.")), + _ => show_error(format!("`cargo miri` supports the following subcommands: `run`, `test`, and `setup`.")), }; let verbose = has_arg_flag("-v"); @@ -424,8 +417,44 @@ fn phase_cargo_miri(mut args: env::Args) { host }; - // Forward all further arguments. - cmd.args(args); + // Forward all further arguments. We do some processing here because we want to + // detect people still using the old way of passing flags to Miri + // (`cargo miri -- -Zmiri-foo`). + while let Some(arg) = args.next() { + cmd.arg(&arg); + if arg == "--" { + // Check if the next argument starts with `-Zmiri`. If yes, we assume + // this is an old-style invocation. + if let Some(next_arg) = args.next() { + if next_arg.starts_with("-Zmiri") { + eprintln!( + "WARNING: it seems like you are setting Miri's flags in `cargo miri` the old way,\n\ + i.e., by passing them after the first `--`. This style is deprecated; please set\n\ + the MIRIFLAGS environment variable instead. `cargo miri run/test` now interprets\n\ + arguments the exact same way as `cargo run/test`." + ); + // Old-style invocation. Turn these into MIRIFLAGS. + let mut miriflags = env::var("MIRIFLAGS").unwrap_or_default(); + miriflags.push(' '); + miriflags.push_str(&next_arg); + while let Some(further_arg) = args.next() { + if further_arg == "--" { + // End of the Miri flags! + break; + } + miriflags.push(' '); + miriflags.push_str(&further_arg); + } + env::set_var("MIRIFLAGS", miriflags); + // Pass the remaining flags to cargo. + cmd.args(args); + break; + } + // Not a Miri argument after all, make sure we pass it to cargo. + cmd.arg(next_arg); + } + } + } // Set `RUSTC_WRAPPER` to ourselves. Cargo will prepend that binary to its usual invocation, // i.e., the first argument is `rustc` -- which is what we use in `main` to distinguish From 33c669679efdeec9f9a6e6bbb7404fdb1d2d5fd6 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 12 Sep 2020 12:52:14 +0200 Subject: [PATCH 2296/3747] test 'harness=false' tests --- cargo-miri/bin.rs | 2 +- test-cargo-miri/Cargo.toml | 4 ++++ test-cargo-miri/run-test.py | 22 +++++++++---------- test-cargo-miri/src/main.rs | 1 - test-cargo-miri/{stderr.ref => stderr.ref1} | 0 test-cargo-miri/{stdout.ref => stdout.ref1} | 0 .../{test.stderr.ref => test.stderr.ref1} | 0 .../{test.stdout.ref => test.stdout.ref1} | 1 + test-cargo-miri/test.stdout.ref2 | 1 + test-cargo-miri/test.stdout.ref3 | 1 + test-cargo-miri/tests/no-harness.rs | 3 +++ 11 files changed, 22 insertions(+), 13 deletions(-) rename test-cargo-miri/{stderr.ref => stderr.ref1} (100%) rename test-cargo-miri/{stdout.ref => stdout.ref1} (100%) rename test-cargo-miri/{test.stderr.ref => test.stderr.ref1} (100%) rename test-cargo-miri/{test.stdout.ref => test.stdout.ref1} (92%) create mode 100644 test-cargo-miri/tests/no-harness.rs diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index deb5733485d73..f514f4e3e5c37 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -502,7 +502,7 @@ fn phase_cargo_rustc(args: env::Args) { /// Cargo does not give us this information directly, so we need to check /// various command-line flags. fn is_runnable_crate() -> bool { - let is_bin = get_arg_flag_value("--crate-type").as_deref() == Some("bin"); + let is_bin = get_arg_flag_value("--crate-type").as_deref().unwrap_or("bin") == "bin"; let is_test = has_arg_flag("--test"); let print = get_arg_flag_value("--print").is_some(); (is_bin || is_test) && !print diff --git a/test-cargo-miri/Cargo.toml b/test-cargo-miri/Cargo.toml index 6bc11ef0cc5ad..f4847270ba409 100644 --- a/test-cargo-miri/Cargo.toml +++ b/test-cargo-miri/Cargo.toml @@ -13,3 +13,7 @@ num_cpus = "1.10.1" [lib] test = false # test that this is respected (will show in the output) + +[[test]] +name = "no-harness" +harness = false diff --git a/test-cargo-miri/run-test.py b/test-cargo-miri/run-test.py index c7694f3854c87..665e9834e8e56 100755 --- a/test-cargo-miri/run-test.py +++ b/test-cargo-miri/run-test.py @@ -22,7 +22,7 @@ def cargo_miri(cmd): return args def test(name, cmd, stdout_ref, stderr_ref, stdin=b'', env={}): - print("==> Testing `{}` <==".format(name)) + print("==> Testing {} <==".format(name)) ## Call `cargo miri`, capture all output p_env = os.environ.copy() p_env.update(env) @@ -50,13 +50,13 @@ def test(name, cmd, stdout_ref, stderr_ref, stdin=b'', env={}): fail("stderr does not match reference") def test_cargo_miri_run(): - test("cargo miri run", + test("`cargo miri run`", cargo_miri("run"), - "stdout.ref", "stderr.ref", + "stdout.ref1", "stderr.ref1", stdin=b'12\n21\n', env={'MIRIFLAGS': "-Zmiri-disable-isolation"}, ) - test("cargo miri run (with arguments and target)", + test("`cargo miri run` (with arguments and target)", cargo_miri("run") + ["--bin", "cargo-miri-test", "--", "hello world", '"hello world"'], "stdout.ref2", "stderr.ref2" ) @@ -64,27 +64,27 @@ def test_cargo_miri_run(): def test_cargo_miri_test(): # rustdoc is not run on foreign targets is_foreign = 'MIRI_TEST_TARGET' in os.environ - rustdoc_ref = "test.stderr.ref2" if is_foreign else "test.stderr.ref" + rustdoc_ref = "test.stderr.ref2" if is_foreign else "test.stderr.ref1" - test("cargo miri test", + test("`cargo miri test`", cargo_miri("test"), - "test.stdout.ref",rustdoc_ref, + "test.stdout.ref1",rustdoc_ref, env={'MIRIFLAGS': "-Zmiri-seed=feed"}, ) - test("cargo miri test (with filter)", + test("`cargo miri test` (with filter)", cargo_miri("test") + ["--", "--format=pretty", "le1"], "test.stdout.ref2", rustdoc_ref ) - test("cargo miri test (without isolation)", + test("`cargo miri test` (without isolation)", cargo_miri("test") + ["--", "--format=pretty", "num_cpus"], "test.stdout.ref3", rustdoc_ref, env={'MIRIFLAGS': "-Zmiri-disable-isolation"}, ) - test("cargo miri test (test target)", + test("`cargo miri test` (test target)", cargo_miri("test") + ["--test", "test", "--", "--format=pretty"], "test.stdout.ref4", "test.stderr.ref2" ) - test("cargo miri test (bin target)", + test("`cargo miri test` (bin target)", cargo_miri("test") + ["--bin", "cargo-miri-test", "--", "--format=pretty"], "test.stdout.ref5", "test.stderr.ref2" ) diff --git a/test-cargo-miri/src/main.rs b/test-cargo-miri/src/main.rs index 0079328ff6059..17808f57061ef 100644 --- a/test-cargo-miri/src/main.rs +++ b/test-cargo-miri/src/main.rs @@ -28,7 +28,6 @@ fn main() { println!("42"); } } - } #[cfg(test)] diff --git a/test-cargo-miri/stderr.ref b/test-cargo-miri/stderr.ref1 similarity index 100% rename from test-cargo-miri/stderr.ref rename to test-cargo-miri/stderr.ref1 diff --git a/test-cargo-miri/stdout.ref b/test-cargo-miri/stdout.ref1 similarity index 100% rename from test-cargo-miri/stdout.ref rename to test-cargo-miri/stdout.ref1 diff --git a/test-cargo-miri/test.stderr.ref b/test-cargo-miri/test.stderr.ref1 similarity index 100% rename from test-cargo-miri/test.stderr.ref rename to test-cargo-miri/test.stderr.ref1 diff --git a/test-cargo-miri/test.stdout.ref b/test-cargo-miri/test.stdout.ref1 similarity index 92% rename from test-cargo-miri/test.stdout.ref rename to test-cargo-miri/test.stdout.ref1 index 1eb18fe88768a..76144513c5489 100644 --- a/test-cargo-miri/test.stdout.ref +++ b/test-cargo-miri/test.stdout.ref1 @@ -3,6 +3,7 @@ running 1 test . test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out +no-harness test running 8 tests ..i..... diff --git a/test-cargo-miri/test.stdout.ref2 b/test-cargo-miri/test.stdout.ref2 index d426bdf6db632..1264c6da7ff8c 100644 --- a/test-cargo-miri/test.stdout.ref2 +++ b/test-cargo-miri/test.stdout.ref2 @@ -3,6 +3,7 @@ running 0 tests test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 1 filtered out +no-harness test running 1 test test simple1 ... ok diff --git a/test-cargo-miri/test.stdout.ref3 b/test-cargo-miri/test.stdout.ref3 index bc4a7c47e9f51..a5edee2c5f13b 100644 --- a/test-cargo-miri/test.stdout.ref3 +++ b/test-cargo-miri/test.stdout.ref3 @@ -3,6 +3,7 @@ running 0 tests test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 1 filtered out +no-harness test running 1 test test num_cpus ... ok diff --git a/test-cargo-miri/tests/no-harness.rs b/test-cargo-miri/tests/no-harness.rs new file mode 100644 index 0000000000000..8d1c5c3462660 --- /dev/null +++ b/test-cargo-miri/tests/no-harness.rs @@ -0,0 +1,3 @@ +fn main() { + println!("no-harness test"); +} From 113a335c3eae30c0e7e2d691ccbba66bd1d1e75e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 12 Sep 2020 13:10:23 +0200 Subject: [PATCH 2297/3747] test propagating env vars from build.rs to binary --- cargo-miri/bin.rs | 4 +++- test-cargo-miri/build.rs | 2 ++ test-cargo-miri/run-test.py | 7 +++++-- test-cargo-miri/src/main.rs | 3 +++ 4 files changed, 13 insertions(+), 3 deletions(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index f514f4e3e5c37..d35940897191f 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -612,7 +612,9 @@ fn phase_cargo_runner(binary: &Path, binary_args: env::Args) { let info: CrateRunInfo = serde_json::from_reader(file) .unwrap_or_else(|_| show_error(format!("File {:?} does not contain valid JSON", binary))); - // Set missing env vars. + // Set missing env vars. Looks like `build.rs` vars are still set at run-time, but + // `CARGO_BIN_EXE_*` are not. This means we can give the run-time environment precedence, + // to rather do too little than too much. for (name, val) in info.env { if env::var_os(&name).is_none() { env::set_var(name, val); diff --git a/test-cargo-miri/build.rs b/test-cargo-miri/build.rs index b1f5fc1726200..9851ccf39f3ff 100644 --- a/test-cargo-miri/build.rs +++ b/test-cargo-miri/build.rs @@ -12,4 +12,6 @@ fn not_in_miri() -> i32 { fn main() { not_in_miri(); println!("cargo:rerun-if-changed=build.rs"); + println!("cargo:rerun-if-env-changed=MIRITESTVAR"); + println!("cargo:rustc-env=MIRITESTVAR=testval"); } diff --git a/test-cargo-miri/run-test.py b/test-cargo-miri/run-test.py index 665e9834e8e56..2250835c9998c 100755 --- a/test-cargo-miri/run-test.py +++ b/test-cargo-miri/run-test.py @@ -50,11 +50,14 @@ def test(name, cmd, stdout_ref, stderr_ref, stdin=b'', env={}): fail("stderr does not match reference") def test_cargo_miri_run(): - test("`cargo miri run`", + test("`cargo miri run` (without isolation)", cargo_miri("run"), "stdout.ref1", "stderr.ref1", stdin=b'12\n21\n', - env={'MIRIFLAGS': "-Zmiri-disable-isolation"}, + env={ + 'MIRIFLAGS': "-Zmiri-disable-isolation", + 'MIRITESTVAR': "wrongval", # make sure the build.rs value takes precedence + }, ) test("`cargo miri run` (with arguments and target)", cargo_miri("run") + ["--bin", "cargo-miri-test", "--", "hello world", '"hello world"'], diff --git a/test-cargo-miri/src/main.rs b/test-cargo-miri/src/main.rs index 17808f57061ef..b36b0c725f85e 100644 --- a/test-cargo-miri/src/main.rs +++ b/test-cargo-miri/src/main.rs @@ -3,6 +3,9 @@ use byteorder::{BigEndian, ByteOrder}; use std::io::{self, BufRead}; fn main() { + // Check env var set by `build.rs`. + assert_eq!(env!("MIRITESTVAR"), "testval"); + // Exercise external crate, printing to stdout. let buf = &[1,2,3,4]; let n = ::read_u32(buf); From c99fb102b8db55c09400c46d097d8fbb9dcde580 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 12 Sep 2020 13:33:30 +0200 Subject: [PATCH 2298/3747] test 'cargo miri run' CWD, also for subcrate in a workspace --- test-cargo-miri/Cargo.lock | 72 +++++++++++++++-------------- test-cargo-miri/Cargo.toml | 5 +- test-cargo-miri/run-test.py | 5 ++ test-cargo-miri/src/main.rs | 8 +++- test-cargo-miri/stderr.ref3 | 0 test-cargo-miri/stdout.ref3 | 1 + test-cargo-miri/subcrate/Cargo.toml | 9 ++++ test-cargo-miri/subcrate/main.rs | 11 +++++ 8 files changed, 74 insertions(+), 37 deletions(-) create mode 100644 test-cargo-miri/stderr.ref3 create mode 100644 test-cargo-miri/stdout.ref3 create mode 100644 test-cargo-miri/subcrate/Cargo.toml create mode 100644 test-cargo-miri/subcrate/main.rs diff --git a/test-cargo-miri/Cargo.lock b/test-cargo-miri/Cargo.lock index ecf71a5f437a9..6bc70135a898a 100644 --- a/test-cargo-miri/Cargo.lock +++ b/test-cargo-miri/Cargo.lock @@ -4,120 +4,122 @@ name = "byteorder" version = "1.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de" [[package]] name = "cargo-miri-test" version = "0.1.0" dependencies = [ - "byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", - "num_cpus 1.12.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", + "byteorder", + "num_cpus", + "rand", ] [[package]] name = "cfg-if" version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" [[package]] name = "getrandom" version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7abc8dd8451921606d809ba32e95b6111925cd2906060d2dcc29c070220503eb" dependencies = [ - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", - "wasi 0.9.0+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if", + "libc", + "wasi", ] [[package]] name = "hermit-abi" version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "725cf19794cf90aa94e65050cb4191ff5d8fa87a498383774c47b332e3af952e" dependencies = [ - "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", + "libc", ] [[package]] name = "libc" version = "0.2.68" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dea0c0405123bba743ee3f91f49b1c7cfb684eef0da0a50110f758ccf24cdff0" [[package]] name = "num_cpus" version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46203554f085ff89c235cd12f7075f3233af9b11ed7c9e16dfe2560d03313ce6" dependencies = [ - "hermit-abi 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", + "hermit-abi", + "libc", ] [[package]] name = "ppv-lite86" version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74490b50b9fbe561ac330df47c08f3f33073d2d00c150f719147d7c54522fa1b" [[package]] name = "rand" version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" dependencies = [ - "getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_pcg 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "getrandom", + "libc", + "rand_chacha", + "rand_core", + "rand_hc", + "rand_pcg", ] [[package]] name = "rand_chacha" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" dependencies = [ - "ppv-lite86 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "ppv-lite86", + "rand_core", ] [[package]] name = "rand_core" version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" dependencies = [ - "getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", + "getrandom", ] [[package]] name = "rand_hc" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" dependencies = [ - "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core", ] [[package]] name = "rand_pcg" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16abd0c1b639e9eb4d7c50c0b8100b0d0f849be2349829c740fe8e6eb4816429" dependencies = [ - "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core", ] +[[package]] +name = "subcrate" +version = "0.1.0" + [[package]] name = "wasi" version = "0.9.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" - -[metadata] -"checksum byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de" -"checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" -"checksum getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "7abc8dd8451921606d809ba32e95b6111925cd2906060d2dcc29c070220503eb" -"checksum hermit-abi 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "725cf19794cf90aa94e65050cb4191ff5d8fa87a498383774c47b332e3af952e" -"checksum libc 0.2.68 (registry+https://github.com/rust-lang/crates.io-index)" = "dea0c0405123bba743ee3f91f49b1c7cfb684eef0da0a50110f758ccf24cdff0" -"checksum num_cpus 1.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "46203554f085ff89c235cd12f7075f3233af9b11ed7c9e16dfe2560d03313ce6" -"checksum ppv-lite86 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "74490b50b9fbe561ac330df47c08f3f33073d2d00c150f719147d7c54522fa1b" -"checksum rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" -"checksum rand_chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" -"checksum rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" -"checksum rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" -"checksum rand_pcg 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "16abd0c1b639e9eb4d7c50c0b8100b0d0f849be2349829c740fe8e6eb4816429" -"checksum wasi 0.9.0+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)" = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" +checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" diff --git a/test-cargo-miri/Cargo.toml b/test-cargo-miri/Cargo.toml index f4847270ba409..131e18498539d 100644 --- a/test-cargo-miri/Cargo.toml +++ b/test-cargo-miri/Cargo.toml @@ -1,7 +1,10 @@ +[workspace] +members = ["subcrate"] + [package] name = "cargo-miri-test" version = "0.1.0" -authors = ["Oliver Schneider "] +authors = ["Miri Team"] edition = "2018" [dependencies] diff --git a/test-cargo-miri/run-test.py b/test-cargo-miri/run-test.py index 2250835c9998c..430c8a75830da 100755 --- a/test-cargo-miri/run-test.py +++ b/test-cargo-miri/run-test.py @@ -63,6 +63,11 @@ def test_cargo_miri_run(): cargo_miri("run") + ["--bin", "cargo-miri-test", "--", "hello world", '"hello world"'], "stdout.ref2", "stderr.ref2" ) + test("`cargo miri run` (subcrate)", + cargo_miri("run") + ["-p", "subcrate"], + "stdout.ref3", "stderr.ref3", + env={'MIRIFLAGS': "-Zmiri-disable-isolation"}, + ) def test_cargo_miri_test(): # rustdoc is not run on foreign targets diff --git a/test-cargo-miri/src/main.rs b/test-cargo-miri/src/main.rs index b36b0c725f85e..5f311441bfaf5 100644 --- a/test-cargo-miri/src/main.rs +++ b/test-cargo-miri/src/main.rs @@ -1,4 +1,6 @@ use byteorder::{BigEndian, ByteOrder}; +use std::env; +use std::path::PathBuf; #[cfg(unix)] use std::io::{self, BufRead}; @@ -17,8 +19,12 @@ fn main() { eprintln!("{}", arg); } - // If there were no arguments, access stdin. + // If there were no arguments, access stdin and test working dir. if std::env::args().len() <= 1 { + let env_dir = env::current_dir().unwrap(); + let crate_dir = PathBuf::from(env::var_os("CARGO_MANIFEST_DIR").unwrap()); + assert_eq!(env_dir, crate_dir); + #[cfg(unix)] for line in io::stdin().lock().lines() { let num: i32 = line.unwrap().parse().unwrap(); diff --git a/test-cargo-miri/stderr.ref3 b/test-cargo-miri/stderr.ref3 new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/test-cargo-miri/stdout.ref3 b/test-cargo-miri/stdout.ref3 new file mode 100644 index 0000000000000..53340a502381d --- /dev/null +++ b/test-cargo-miri/stdout.ref3 @@ -0,0 +1 @@ +subcrate running diff --git a/test-cargo-miri/subcrate/Cargo.toml b/test-cargo-miri/subcrate/Cargo.toml new file mode 100644 index 0000000000000..13e9aa4c1af20 --- /dev/null +++ b/test-cargo-miri/subcrate/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "subcrate" +version = "0.1.0" +authors = ["Miri Team"] +edition = "2018" + +[[bin]] +name = "subcrate" +path = "main.rs" diff --git a/test-cargo-miri/subcrate/main.rs b/test-cargo-miri/subcrate/main.rs new file mode 100644 index 0000000000000..db8ea7eb18557 --- /dev/null +++ b/test-cargo-miri/subcrate/main.rs @@ -0,0 +1,11 @@ +use std::env; +use std::path::PathBuf; + +fn main() { + println!("subcrate running"); + + let env_dir = env::current_dir().unwrap(); + let crate_dir = PathBuf::from(env::var_os("CARGO_MANIFEST_DIR").unwrap()); + // CWD should be workspace root, i.e., one level up from crate root. + assert_eq!(env_dir, crate_dir.parent().unwrap()); +} From b244a2ddaa5bbc7eb0b50c018e0e578c0b230283 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 12 Sep 2020 13:52:05 +0200 Subject: [PATCH 2299/3747] make sure subcrate tests have the right cwd --- README.md | 4 ++++ cargo-miri/bin.rs | 10 +++++++++- src/bin/miri.rs | 5 +++++ test-cargo-miri/Cargo.toml | 4 ---- test-cargo-miri/run-test.py | 29 +++++++++++++++++------------ test-cargo-miri/subcrate/Cargo.toml | 5 +++++ test-cargo-miri/subcrate/test.rs | 11 +++++++++++ test-cargo-miri/test.stdout.ref1 | 1 - test-cargo-miri/test.stdout.ref2 | 1 - test-cargo-miri/test.stdout.ref3 | 17 +++++++++-------- test-cargo-miri/test.stdout.ref4 | 13 +++---------- test-cargo-miri/test.stdout.ref5 | 6 +++--- test-cargo-miri/tests/no-harness.rs | 3 --- 13 files changed, 66 insertions(+), 43 deletions(-) create mode 100644 test-cargo-miri/subcrate/test.rs delete mode 100644 test-cargo-miri/tests/no-harness.rs diff --git a/README.md b/README.md index 67161974b1843..6654de10abfff 100644 --- a/README.md +++ b/README.md @@ -244,6 +244,10 @@ different Miri binaries, and as such worth documenting: * `MIRI_BE_RUSTC` when set to any value tells the Miri driver to actually not interpret the code but compile it like rustc would. This is useful to be sure that the compiled `rlib`s are compatible with Miri. +* `MIRI_CWD` when set to any value tells the Miri driver to change to the given + directory after loading all the source files, but before commencing + interpretation. This is useful if the interpreted program wants a different + working directory at run-time than at build-time. ## Miri `extern` functions diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index d35940897191f..a4898e1a2cffb 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -43,6 +43,8 @@ struct CrateRunInfo { args: Vec, /// The environment. env: Vec<(OsString, OsString)>, + /// The current working directory. + current_dir: OsString, } impl CrateRunInfo { @@ -50,7 +52,8 @@ impl CrateRunInfo { fn collect(args: env::Args) -> Self { let args = args.collect(); let env = env::vars_os().collect(); - CrateRunInfo { args, env } + let current_dir = env::current_dir().unwrap().into_os_string(); + CrateRunInfo { args, env, current_dir } } fn store(&self, filename: &Path) { @@ -672,6 +675,11 @@ fn phase_cargo_runner(binary: &Path, binary_args: env::Args) { cmd.arg("--"); cmd.args(binary_args); + // Make sure we use the build-time working directory for interpreting Miri/rustc arguments. + // But then we need to switch to the run-time one, which we instruct Miri do do by setting `MIRI_CWD`. + cmd.current_dir(info.current_dir); + cmd.env("MIRI_CWD", env::current_dir().unwrap()); + // Run it. if verbose { eprintln!("[cargo-miri runner] {:?}", cmd); diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 134702047522d..4363f9a150a78 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -45,6 +45,11 @@ impl rustc_driver::Callbacks for MiriCompilerCalls { // Add filename to `miri` arguments. config.args.insert(0, compiler.input().filestem().to_string()); + // Adjust working directory for interpretation. + if let Some(cwd) = env::var_os("MIRI_CWD") { + env::set_current_dir(cwd).unwrap(); + } + if let Some(return_code) = miri::eval_main(tcx, entry_def_id.to_def_id(), config) { std::process::exit( i32::try_from(return_code).expect("Return value was too large!"), diff --git a/test-cargo-miri/Cargo.toml b/test-cargo-miri/Cargo.toml index 131e18498539d..4900ce9675d6f 100644 --- a/test-cargo-miri/Cargo.toml +++ b/test-cargo-miri/Cargo.toml @@ -16,7 +16,3 @@ num_cpus = "1.10.1" [lib] test = false # test that this is respected (will show in the output) - -[[test]] -name = "no-harness" -harness = false diff --git a/test-cargo-miri/run-test.py b/test-cargo-miri/run-test.py index 430c8a75830da..78b10d1f2bfbb 100755 --- a/test-cargo-miri/run-test.py +++ b/test-cargo-miri/run-test.py @@ -50,7 +50,7 @@ def test(name, cmd, stdout_ref, stderr_ref, stdin=b'', env={}): fail("stderr does not match reference") def test_cargo_miri_run(): - test("`cargo miri run` (without isolation)", + test("`cargo miri run` (no isolation)", cargo_miri("run"), "stdout.ref1", "stderr.ref1", stdin=b'12\n21\n', @@ -61,9 +61,9 @@ def test_cargo_miri_run(): ) test("`cargo miri run` (with arguments and target)", cargo_miri("run") + ["--bin", "cargo-miri-test", "--", "hello world", '"hello world"'], - "stdout.ref2", "stderr.ref2" + "stdout.ref2", "stderr.ref2", ) - test("`cargo miri run` (subcrate)", + test("`cargo miri run` (subcrate, no ioslation)", cargo_miri("run") + ["-p", "subcrate"], "stdout.ref3", "stderr.ref3", env={'MIRIFLAGS': "-Zmiri-disable-isolation"}, @@ -76,25 +76,30 @@ def test_cargo_miri_test(): test("`cargo miri test`", cargo_miri("test"), - "test.stdout.ref1",rustdoc_ref, + "test.stdout.ref1", rustdoc_ref, env={'MIRIFLAGS': "-Zmiri-seed=feed"}, ) + test("`cargo miri test` (no isolation)", + cargo_miri("test"), + "test.stdout.ref1", rustdoc_ref, + env={'MIRIFLAGS': "-Zmiri-disable-isolation"}, + ) test("`cargo miri test` (with filter)", cargo_miri("test") + ["--", "--format=pretty", "le1"], - "test.stdout.ref2", rustdoc_ref - ) - test("`cargo miri test` (without isolation)", - cargo_miri("test") + ["--", "--format=pretty", "num_cpus"], - "test.stdout.ref3", rustdoc_ref, - env={'MIRIFLAGS': "-Zmiri-disable-isolation"}, + "test.stdout.ref2", rustdoc_ref, ) test("`cargo miri test` (test target)", cargo_miri("test") + ["--test", "test", "--", "--format=pretty"], - "test.stdout.ref4", "test.stderr.ref2" + "test.stdout.ref3", "test.stderr.ref2", ) test("`cargo miri test` (bin target)", cargo_miri("test") + ["--bin", "cargo-miri-test", "--", "--format=pretty"], - "test.stdout.ref5", "test.stderr.ref2" + "test.stdout.ref4", "test.stderr.ref2", + ) + test("`cargo miri test` (subcrate)", + cargo_miri("test") + ["-p", "subcrate"], + "test.stdout.ref5", "test.stderr.ref2", + env={'MIRIFLAGS': "-Zmiri-disable-isolation"}, ) os.chdir(os.path.dirname(os.path.realpath(__file__))) diff --git a/test-cargo-miri/subcrate/Cargo.toml b/test-cargo-miri/subcrate/Cargo.toml index 13e9aa4c1af20..78552e6aedf07 100644 --- a/test-cargo-miri/subcrate/Cargo.toml +++ b/test-cargo-miri/subcrate/Cargo.toml @@ -7,3 +7,8 @@ edition = "2018" [[bin]] name = "subcrate" path = "main.rs" + +[[test]] +name = "subtest" +path = "test.rs" +harness = false diff --git a/test-cargo-miri/subcrate/test.rs b/test-cargo-miri/subcrate/test.rs new file mode 100644 index 0000000000000..16c63411ce84e --- /dev/null +++ b/test-cargo-miri/subcrate/test.rs @@ -0,0 +1,11 @@ +use std::env; +use std::path::PathBuf; + +fn main() { + println!("subcrate testing"); + + let env_dir = env::current_dir().unwrap(); + let crate_dir = PathBuf::from(env::var_os("CARGO_MANIFEST_DIR").unwrap()); + // CWD should be crate root. + assert_eq!(env_dir, crate_dir); +} diff --git a/test-cargo-miri/test.stdout.ref1 b/test-cargo-miri/test.stdout.ref1 index 76144513c5489..1eb18fe88768a 100644 --- a/test-cargo-miri/test.stdout.ref1 +++ b/test-cargo-miri/test.stdout.ref1 @@ -3,7 +3,6 @@ running 1 test . test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out -no-harness test running 8 tests ..i..... diff --git a/test-cargo-miri/test.stdout.ref2 b/test-cargo-miri/test.stdout.ref2 index 1264c6da7ff8c..d426bdf6db632 100644 --- a/test-cargo-miri/test.stdout.ref2 +++ b/test-cargo-miri/test.stdout.ref2 @@ -3,7 +3,6 @@ running 0 tests test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 1 filtered out -no-harness test running 1 test test simple1 ... ok diff --git a/test-cargo-miri/test.stdout.ref3 b/test-cargo-miri/test.stdout.ref3 index a5edee2c5f13b..32bbcf9bf275b 100644 --- a/test-cargo-miri/test.stdout.ref3 +++ b/test-cargo-miri/test.stdout.ref3 @@ -1,12 +1,13 @@ -running 0 tests - -test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 1 filtered out - -no-harness test - -running 1 test +running 8 tests +test cargo_env ... ok +test do_panic ... ok +test does_not_work_on_miri ... ignored +test entropy_rng ... ok +test fail_index_check ... ok test num_cpus ... ok +test simple1 ... ok +test simple2 ... ok -test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 7 filtered out +test result: ok. 7 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out diff --git a/test-cargo-miri/test.stdout.ref4 b/test-cargo-miri/test.stdout.ref4 index 32bbcf9bf275b..4caa30a7f0e50 100644 --- a/test-cargo-miri/test.stdout.ref4 +++ b/test-cargo-miri/test.stdout.ref4 @@ -1,13 +1,6 @@ -running 8 tests -test cargo_env ... ok -test do_panic ... ok -test does_not_work_on_miri ... ignored -test entropy_rng ... ok -test fail_index_check ... ok -test num_cpus ... ok -test simple1 ... ok -test simple2 ... ok +running 1 test +test test::rng ... ok -test result: ok. 7 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out diff --git a/test-cargo-miri/test.stdout.ref5 b/test-cargo-miri/test.stdout.ref5 index 4caa30a7f0e50..67e5c7f8e920c 100644 --- a/test-cargo-miri/test.stdout.ref5 +++ b/test-cargo-miri/test.stdout.ref5 @@ -1,6 +1,6 @@ -running 1 test -test test::rng ... ok +running 0 tests -test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out +subcrate testing diff --git a/test-cargo-miri/tests/no-harness.rs b/test-cargo-miri/tests/no-harness.rs deleted file mode 100644 index 8d1c5c3462660..0000000000000 --- a/test-cargo-miri/tests/no-harness.rs +++ /dev/null @@ -1,3 +0,0 @@ -fn main() { - println!("no-harness test"); -} From 192b535adc32d96795ad4e39cc199ab68a28a60b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 12 Sep 2020 13:57:49 +0200 Subject: [PATCH 2300/3747] cleaner output for cargo-miri-test harness --- test-cargo-miri/run-test.py | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/test-cargo-miri/run-test.py b/test-cargo-miri/run-test.py index 78b10d1f2bfbb..bbb8df9059acb 100755 --- a/test-cargo-miri/run-test.py +++ b/test-cargo-miri/run-test.py @@ -22,7 +22,7 @@ def cargo_miri(cmd): return args def test(name, cmd, stdout_ref, stderr_ref, stdin=b'', env={}): - print("==> Testing {} <==".format(name)) + print("Testing {}...".format(name)) ## Call `cargo miri`, capture all output p_env = os.environ.copy() p_env.update(env) @@ -36,18 +36,17 @@ def test(name, cmd, stdout_ref, stderr_ref, stdin=b'', env={}): (stdout, stderr) = p.communicate(input=stdin) stdout = stdout.decode("UTF-8") stderr = stderr.decode("UTF-8") + if p.returncode == 0 and stdout == open(stdout_ref).read() and stderr == open(stderr_ref).read(): + # All good! + return # Show output - print("=> captured stdout <=") + print("--- BEGIN stdout ---") print(stdout, end="") - print("=> captured stderr <=") + print("--- END stdout ---") + print("--- BEGIN stderr ---") print(stderr, end="") - # Test for failures - if p.returncode != 0: - fail("Non-zero exit status") - if stdout != open(stdout_ref).read(): - fail("stdout does not match reference") - if stderr != open(stderr_ref).read(): - fail("stderr does not match reference") + print("--- END stderr ---") + fail("exit code was {}".format(p.returncode)) def test_cargo_miri_run(): test("`cargo miri run` (no isolation)", @@ -96,7 +95,7 @@ def test_cargo_miri_test(): cargo_miri("test") + ["--bin", "cargo-miri-test", "--", "--format=pretty"], "test.stdout.ref4", "test.stderr.ref2", ) - test("`cargo miri test` (subcrate)", + test("`cargo miri test` (subcrate, no isolation)", cargo_miri("test") + ["-p", "subcrate"], "test.stdout.ref5", "test.stderr.ref2", env={'MIRIFLAGS': "-Zmiri-disable-isolation"}, From f7612f71bcc10ceab30623850098a5c03459be28 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 12 Sep 2020 14:02:08 +0200 Subject: [PATCH 2301/3747] more consistent error capitalization --- cargo-miri/bin.rs | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index a4898e1a2cffb..ab0c70fc86d1a 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -58,10 +58,10 @@ impl CrateRunInfo { fn store(&self, filename: &Path) { let file = File::create(filename) - .unwrap_or_else(|_| show_error(format!("Cannot create `{}`", filename.display()))); + .unwrap_or_else(|_| show_error(format!("cannot create `{}`", filename.display()))); let file = BufWriter::new(file); serde_json::ser::to_writer(file, self) - .unwrap_or_else(|_| show_error(format!("Cannot write to `{}`", filename.display()))); + .unwrap_or_else(|_| show_error(format!("cannot write to `{}`", filename.display()))); } } @@ -207,15 +207,15 @@ fn ask_to_run(mut cmd: Command, ask: bool, text: &str) { match buf.trim().to_lowercase().as_ref() { // Proceed. "" | "y" | "yes" => {} - "n" | "no" => show_error(format!("Aborting as per your request")), - a => show_error(format!("I do not understand `{}`", a)), + "n" | "no" => show_error(format!("aborting as per your request")), + a => show_error(format!("invalid answer `{}`", a)), }; } else { println!("Running `{:?}` to {}.", cmd, text); } if cmd.status().expect(&format!("failed to execute {:?}", cmd)).success().not() { - show_error(format!("Failed to {}", text)); + show_error(format!("failed to {}", text)); } } @@ -238,7 +238,7 @@ fn setup(subcommand: MiriCommand) { if xargo_version().map_or(true, |v| v < XARGO_MIN_VERSION) { if std::env::var_os("XARGO_CHECK").is_some() { // The user manually gave us a xargo binary; don't do anything automatically. - show_error(format!("Your xargo is too old; please upgrade to the latest version")) + show_error(format!("xargo is too old; please upgrade to the latest version")) } let mut cmd = cargo(); cmd.args(&["install", "xargo", "-f"]); @@ -278,7 +278,7 @@ fn setup(subcommand: MiriCommand) { } }; if !rust_src.exists() { - show_error(format!("Given Rust source directory `{}` does not exist.", rust_src.display())); + show_error(format!("given Rust source directory `{}` does not exist.", rust_src.display())); } // Next, we need our own libstd. Prepare a xargo project for that purpose. @@ -352,7 +352,7 @@ path = "lib.rs" command.env_remove("RUSTFLAGS"); // Finally run it! if command.status().expect("failed to run xargo").success().not() { - show_error(format!("Failed to run xargo")); + show_error(format!("failed to run xargo")); } // That should be it! But we need to figure out where xargo built stuff. @@ -578,7 +578,7 @@ fn phase_cargo_rustc(args: env::Args) { // Use our custom sysroot. let sysroot = - env::var_os("MIRI_SYSROOT").expect("The wrapper should have set MIRI_SYSROOT"); + env::var_os("MIRI_SYSROOT").expect("the wrapper should have set MIRI_SYSROOT"); cmd.arg("--sysroot"); cmd.arg(sysroot); } else { @@ -600,9 +600,9 @@ fn phase_cargo_rustc(args: env::Args) { if emit_link_hack { // Some platforms prepend "lib", some do not... let's just create both files. let filename = out_filename("lib", ".rlib"); - File::create(filename).expect("Failed to create rlib file"); + File::create(filename).expect("failed to create rlib file"); let filename = out_filename("", ".rlib"); - File::create(filename).expect("Failed to create rlib file"); + File::create(filename).expect("failed to create rlib file"); } } @@ -610,10 +610,10 @@ fn phase_cargo_runner(binary: &Path, binary_args: env::Args) { let verbose = std::env::var_os("MIRI_VERBOSE").is_some(); let file = File::open(&binary) - .unwrap_or_else(|_| show_error(format!("File {:?} not found or `cargo-miri` invoked incorrectly; please only invoke this binary through `cargo miri`", binary))); + .unwrap_or_else(|_| show_error(format!("file {:?} not found or `cargo-miri` invoked incorrectly; please only invoke this binary through `cargo miri`", binary))); let file = BufReader::new(file); let info: CrateRunInfo = serde_json::from_reader(file) - .unwrap_or_else(|_| show_error(format!("File {:?} does not contain valid JSON", binary))); + .unwrap_or_else(|_| show_error(format!("file {:?} contains outdated or invalid JSON; try `cargo clean`", binary))); // Set missing env vars. Looks like `build.rs` vars are still set at run-time, but // `CARGO_BIN_EXE_*` are not. This means we can give the run-time environment precedence, @@ -657,7 +657,7 @@ fn phase_cargo_runner(binary: &Path, binary_args: env::Args) { } // Set sysroot. let sysroot = - env::var_os("MIRI_SYSROOT").expect("The wrapper should have set MIRI_SYSROOT"); + env::var_os("MIRI_SYSROOT").expect("the wrapper should have set MIRI_SYSROOT"); cmd.arg("--sysroot"); cmd.arg(sysroot); // Respect `MIRIFLAGS`. From 18483b4d5e36237f1939903e008ec2c7bb4e8035 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 12 Sep 2020 14:09:43 +0200 Subject: [PATCH 2302/3747] make (not yet actually used) doctest actually use the crate, and fix a comment --- cargo-miri/bin.rs | 2 +- test-cargo-miri/src/lib.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index ab0c70fc86d1a..871478d330ccb 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -140,7 +140,7 @@ fn xargo_check() -> Command { Command::new(env::var_os("XARGO_CHECK").unwrap_or_else(|| OsString::from("xargo-check"))) } -/// Execute the command if it fails, fail this process with the same exit code. +/// Execute the command. If it fails, fail this process with the same exit code. /// Otherwise, continue. fn exec(mut cmd: Command) { let exit_status = cmd.status().expect("failed to run command"); diff --git a/test-cargo-miri/src/lib.rs b/test-cargo-miri/src/lib.rs index 064954ba98003..4e2c8b572c777 100644 --- a/test-cargo-miri/src/lib.rs +++ b/test-cargo-miri/src/lib.rs @@ -1,6 +1,6 @@ /// Doc-test test /// ```rust -/// assert!(true); +/// assert!(cargo_miri_test::make_true()); /// ``` pub fn make_true() -> bool { true From 05f5c3d0783cfda72562373599eb1976f384e14e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 12 Sep 2020 14:24:56 +0200 Subject: [PATCH 2303/3747] make sure tests pass even with RUST_TEST_NOCAPTURE set --- test-cargo-miri/run-test.py | 1 + 1 file changed, 1 insertion(+) diff --git a/test-cargo-miri/run-test.py b/test-cargo-miri/run-test.py index bbb8df9059acb..e7c341a1f0408 100755 --- a/test-cargo-miri/run-test.py +++ b/test-cargo-miri/run-test.py @@ -102,6 +102,7 @@ def test_cargo_miri_test(): ) os.chdir(os.path.dirname(os.path.realpath(__file__))) +os.environ["RUST_TEST_NOCAPTURE"] = "0" # this affects test output, so make sure it is not set target_str = " for target {}".format(os.environ['MIRI_TEST_TARGET']) if 'MIRI_TEST_TARGET' in os.environ else "" print(CGREEN + CBOLD + "## Running `cargo miri` tests{}".format(target_str) + CEND) From db067f4a3e611002b3b2b9cea9b2b65a2edb7385 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 12 Sep 2020 16:01:33 +0200 Subject: [PATCH 2304/3747] test-cargo-miri: normalize slashes before comparing paths --- test-cargo-miri/src/main.rs | 7 +++++-- test-cargo-miri/subcrate/main.rs | 11 ++++++++--- test-cargo-miri/subcrate/test.rs | 8 +++++--- 3 files changed, 18 insertions(+), 8 deletions(-) diff --git a/test-cargo-miri/src/main.rs b/test-cargo-miri/src/main.rs index 5f311441bfaf5..43b507e9c9aa5 100644 --- a/test-cargo-miri/src/main.rs +++ b/test-cargo-miri/src/main.rs @@ -1,6 +1,5 @@ use byteorder::{BigEndian, ByteOrder}; use std::env; -use std::path::PathBuf; #[cfg(unix)] use std::io::{self, BufRead}; @@ -21,8 +20,12 @@ fn main() { // If there were no arguments, access stdin and test working dir. if std::env::args().len() <= 1 { + // CWD should be crate root. + // We have to normalize slashes, as the env var might be set for a different target's conventions. let env_dir = env::current_dir().unwrap(); - let crate_dir = PathBuf::from(env::var_os("CARGO_MANIFEST_DIR").unwrap()); + let env_dir = env_dir.to_string_lossy().replace("\\", "/"); + let crate_dir = env::var_os("CARGO_MANIFEST_DIR").unwrap(); + let crate_dir = crate_dir.to_string_lossy().replace("\\", "/"); assert_eq!(env_dir, crate_dir); #[cfg(unix)] diff --git a/test-cargo-miri/subcrate/main.rs b/test-cargo-miri/subcrate/main.rs index db8ea7eb18557..4ce80b3707226 100644 --- a/test-cargo-miri/subcrate/main.rs +++ b/test-cargo-miri/subcrate/main.rs @@ -4,8 +4,13 @@ use std::path::PathBuf; fn main() { println!("subcrate running"); - let env_dir = env::current_dir().unwrap(); - let crate_dir = PathBuf::from(env::var_os("CARGO_MANIFEST_DIR").unwrap()); // CWD should be workspace root, i.e., one level up from crate root. - assert_eq!(env_dir, crate_dir.parent().unwrap()); + // We have to normalize slashes, as the env var might be set for a different target's conventions. + let env_dir = env::current_dir().unwrap(); + let env_dir = env_dir.to_string_lossy().replace("\\", "/"); + let crate_dir = env::var_os("CARGO_MANIFEST_DIR").unwrap(); + let crate_dir = crate_dir.to_string_lossy().replace("\\", "/"); + let crate_dir = PathBuf::from(crate_dir); + let crate_dir = crate_dir.parent().unwrap().to_string_lossy(); + assert_eq!(env_dir, crate_dir); } diff --git a/test-cargo-miri/subcrate/test.rs b/test-cargo-miri/subcrate/test.rs index 16c63411ce84e..0fd26059a1d37 100644 --- a/test-cargo-miri/subcrate/test.rs +++ b/test-cargo-miri/subcrate/test.rs @@ -1,11 +1,13 @@ use std::env; -use std::path::PathBuf; fn main() { println!("subcrate testing"); - let env_dir = env::current_dir().unwrap(); - let crate_dir = PathBuf::from(env::var_os("CARGO_MANIFEST_DIR").unwrap()); // CWD should be crate root. + // We have to normalize slashes, as the env var might be set for a different target's conventions. + let env_dir = env::current_dir().unwrap(); + let env_dir = env_dir.to_string_lossy().replace("\\", "/"); + let crate_dir = env::var_os("CARGO_MANIFEST_DIR").unwrap(); + let crate_dir = crate_dir.to_string_lossy().replace("\\", "/"); assert_eq!(env_dir, crate_dir); } From ae859c3f7be2fe63ebb96dc5cba3c635b81da65b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 16 Sep 2020 19:54:52 +0200 Subject: [PATCH 2305/3747] add comment mentioning alternative approach --- cargo-miri/bin.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index 871478d330ccb..522570626d094 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -397,6 +397,11 @@ fn phase_cargo_miri(mut args: env::Args) { setup(subcommand); // Invoke actual cargo for the job, but with different flags. + // We re-use `cargo test` and `cargo run`, which makes target and binary handling very easy but + // requires some extra work to make the build check-only (see all the `--emit` hacks below). + // describes an alternative + // approach that uses `cargo check`, making that part easier but target and binary handling + // harder. let miri_path = std::env::current_exe().expect("current executable path invalid"); let cargo_cmd = match subcommand { MiriCommand::Test => "test", From 3163242ff1eb5c827cc92ad90211869273bed4bd Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 17 Sep 2020 17:42:52 +0200 Subject: [PATCH 2306/3747] rustup; no need to special-case the guaranteed_eq/ne intrinsics any more --- rust-version | 2 +- src/shims/intrinsics.rs | 11 ++--------- 2 files changed, 3 insertions(+), 10 deletions(-) diff --git a/rust-version b/rust-version index 8e33b80ff68f5..d8673b9211643 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -a1894e4afe1a39f718cc27232a5a2f0d02b501f6 +7bdb5dee7bac15458b10b148e9e24968e633053e diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 4d8801f178874..6051ad482e519 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -8,7 +8,6 @@ use rustc_middle::{mir, ty}; use rustc_middle::ty::layout::IntegerExt; use rustc_apfloat::{Float, Round}; use rustc_target::abi::{Align, Integer, LayoutOf}; -use rustc_span::symbol::sym; use crate::*; use helpers::check_arg_count; @@ -23,19 +22,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx _unwind: Option, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - let intrinsic_name = this.tcx.item_name(instance.def_id()); - // We want to overwrite some of the intrinsic implementations that CTFE uses. - let prefer_miri_intrinsic = match intrinsic_name { - sym::ptr_guaranteed_eq | sym::ptr_guaranteed_ne => true, - _ => false, - }; - if !prefer_miri_intrinsic && this.emulate_intrinsic(instance, args, ret)? { + if this.emulate_intrinsic(instance, args, ret)? { return Ok(()); } // All supported intrinsics have a return place. - let intrinsic_name = &*intrinsic_name.as_str(); + let intrinsic_name = &*this.tcx.item_name(instance.def_id()).as_str(); let (dest, ret) = match ret { None => throw_unsup_format!("unimplemented (diverging) intrinsic: {}", intrinsic_name), Some(p) => p, From e9e67c97cc7b8d242042051d81e97eea6482ce48 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 17 Sep 2020 20:08:18 +0200 Subject: [PATCH 2307/3747] cargo update main crates --- Cargo.lock | 129 +++++++++++++++++++++--------------------- cargo-miri/Cargo.lock | 98 +++++++++++++++++--------------- 2 files changed, 116 insertions(+), 111 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d09ec19af6524..4cf2b62006f88 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,18 +2,18 @@ # It is not intended for manual editing. [[package]] name = "aho-corasick" -version = "0.7.10" +version = "0.7.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8716408b8bc624ed7f65d223ddb9ac2d044c0547b6fa4b0d554f3a9540496ada" +checksum = "043164d8ba5c4c3035fec9bbee8647c0261d788f3474306f93bb65901cae0e86" dependencies = [ "memchr", ] [[package]] name = "anyhow" -version = "1.0.28" +version = "1.0.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9a60d744a80c30fcb657dfe2c1b22bcb3e814c1a1e3674f32bf5820b570fbff" +checksum = "6b602bfe940d21c130f3895acd65221e8a61270debe89d628b9cb4e3ccb8569b" [[package]] name = "arrayref" @@ -40,15 +40,15 @@ dependencies = [ [[package]] name = "autocfg" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d" +checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" [[package]] name = "base64" -version = "0.11.0" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b41b7ea54a0c9d92199de89e20e58d49f02f8e699814ef3fdf266f6f748d15c7" +checksum = "3441f0f7b02788e948e47f457ca01f1d7e6d92c693bc132c22b087d3141c03ff" [[package]] name = "blake2b_simd" @@ -135,11 +135,10 @@ dependencies = [ [[package]] name = "dirs-sys" -version = "0.3.4" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afa0b23de8fd801745c471deffa6e12d248f962c9fd4b4c33787b055599bde7b" +checksum = "8e93d7f5705de3e49895a2b5e0b8855a1c27f080192ae9c32a6432d50741a57a" dependencies = [ - "cfg-if", "libc", "redox_users", "winapi", @@ -160,9 +159,9 @@ dependencies = [ [[package]] name = "filetime" -version = "0.2.9" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f59efc38004c988e4201d11d263b8171f49a2e7ec0bdbb71773433f271504a5e" +checksum = "3ed85775dcc68644b5c950ac06a2b23768d3bc9390464151aaf27136998dcf9e" dependencies = [ "cfg-if", "libc", @@ -181,9 +180,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.1.14" +version = "0.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7abc8dd8451921606d809ba32e95b6111925cd2906060d2dcc29c070220503eb" +checksum = "fc587bc0ec293155d5bfa6b9891ec18a1e330c234f896ea47fbada4cadbe47e6" dependencies = [ "cfg-if", "libc", @@ -192,9 +191,9 @@ dependencies = [ [[package]] name = "hermit-abi" -version = "0.1.10" +version = "0.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "725cf19794cf90aa94e65050cb4191ff5d8fa87a498383774c47b332e3af952e" +checksum = "3deed196b6e7f9e44a2ae8d94225d80302d81208b1bb673fd21fe634645c85a9" dependencies = [ "libc", ] @@ -216,9 +215,9 @@ dependencies = [ [[package]] name = "itoa" -version = "0.4.5" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8b7a7c0c47db5545ed3fef7468ee7bb5b74691498139e4b3f6a20685dc6dd8e" +checksum = "dc6f3ad7b9d11a0c00842ff8de1b60ee58661048eb8049ed33c73594f359d7e6" [[package]] name = "lazy_static" @@ -228,15 +227,15 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.68" +version = "0.2.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dea0c0405123bba743ee3f91f49b1c7cfb684eef0da0a50110f758ccf24cdff0" +checksum = "f2f96b10ec2560088a8e76961b00d47107b3a625fecb76dedb29ee7ccbf98235" [[package]] name = "log" -version = "0.4.8" +version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7" +checksum = "4fabed175da42fed1fa0746b0ea71f412aa9d35e76e95e59b192c64b9dc2bf8b" dependencies = [ "cfg-if", ] @@ -249,9 +248,9 @@ checksum = "3728d817d99e5ac407411fa471ff9800a778d88a24685968b36824eaf4bee400" [[package]] name = "miow" -version = "0.3.3" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "396aa0f2003d7df8395cb93e09871561ccc3e785f0acb369170e8cc74ddf9226" +checksum = "07b88fb9795d4d36d62a012dfbf49a8f5cf12751f36d31a9dbe66d528e58979e" dependencies = [ "socket2", "winapi", @@ -276,15 +275,15 @@ dependencies = [ [[package]] name = "ppv-lite86" -version = "0.2.6" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74490b50b9fbe561ac330df47c08f3f33073d2d00c150f719147d7c54522fa1b" +checksum = "c36fa947111f5c62a733b652544dd0016a43ce89619538a8ef92724a6f501a20" [[package]] name = "proc-macro2" -version = "1.0.10" +version = "1.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df246d292ff63439fea9bc8c0a270bed0e390d5ebd4db4ba15aba81111b5abe3" +checksum = "36e28516df94f3dd551a587da5357459d9b36d945a7c37c3557928c1c2ff2a2c" dependencies = [ "unicode-xid", ] @@ -297,9 +296,9 @@ checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" [[package]] name = "quote" -version = "1.0.3" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bdc6c187c65bca4260c9011c9e3132efe4909da44726bad24cf7572ae338d7f" +checksum = "aa563d17ecb180e500da1cfd2b028310ac758de548efdd203e18f283af693f37" dependencies = [ "proc-macro2", ] @@ -347,15 +346,15 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.1.56" +version = "0.1.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84" +checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce" [[package]] name = "redox_users" -version = "0.3.4" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09b23093265f8d200fa7b4c2c76297f47e681c655f6f1285a8780d6a022f7431" +checksum = "de0737333e7a9502c789a36d7c7fa6092a49895d4faa31ca5df163857ded2e9d" dependencies = [ "getrandom", "redox_syscall", @@ -364,9 +363,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.3.6" +version = "1.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f6946991529684867e47d86474e3a6d0c0ab9b82d5821e314b1ede31fa3a4b3" +checksum = "9c3780fcf44b193bc4d09f36d2a3c87b251da4a046c87795a0d35f4f927ad8e6" dependencies = [ "aho-corasick", "memchr", @@ -376,24 +375,24 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.6.17" +version = "0.6.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fe5bd57d1d7414c6b5ed48563a2c855d995ff777729dcd91c369ec7fea395ae" +checksum = "26412eb97c6b088a6997e05f69403a802a92d520de2f8e63c2b65f9e0f47c4e8" [[package]] name = "remove_dir_all" -version = "0.5.2" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a83fa3702a688b9359eccba92d153ac33fd2e8462f9e0e3fdf155239ea7792e" +checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" dependencies = [ "winapi", ] [[package]] name = "rust-argon2" -version = "0.7.0" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bc8af4bda8e1ff4932523b94d3dd20ee30a87232323eda55903ffd71d2fb017" +checksum = "9dab61250775933275e84053ac235621dfb739556d5c54a2f2e9313b7cf43a19" dependencies = [ "base64", "blake2b_simd", @@ -430,9 +429,9 @@ dependencies = [ [[package]] name = "ryu" -version = "1.0.3" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "535622e6be132bccd223f4bb2b8ac8d53cda3c7a6394944d3b2b33fb974f9d76" +checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" [[package]] name = "semver" @@ -451,18 +450,18 @@ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" [[package]] name = "serde" -version = "1.0.106" +version = "1.0.116" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36df6ac6412072f67cf767ebbde4133a5b2e88e76dc6187fa7104cd16f783399" +checksum = "96fe57af81d28386a513cbc6858332abc6117cfdb5999647c6444b8f43a370a5" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.106" +version = "1.0.116" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e549e3abf4fb8621bd1609f11dfc9f5e50320802273b12f3811a67e6716ea6c" +checksum = "f630a6370fd8e457873b4bd2ffdae75408bc291ba72be773772a4c2a065d9ae8" dependencies = [ "proc-macro2", "quote", @@ -471,9 +470,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.51" +version = "1.0.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da07b57ee2623368351e9a0488bb0b261322a15a6e0ae53e243cbdc0f4208da9" +checksum = "164eacbdb13512ec2745fb09d51fd5b22b0d65ed294a1dcf7285a360c80a675c" dependencies = [ "itoa", "ryu", @@ -482,15 +481,15 @@ dependencies = [ [[package]] name = "shell-escape" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "170a13e64f2a51b77a45702ba77287f5c6829375b04a69cf2222acd17d0cfab9" +checksum = "45bb67a18fa91266cc7807181f62f9178a6873bfad7dc788c42e6430db40184f" [[package]] name = "socket2" -version = "0.3.12" +version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03088793f677dce356f3ccc2edb1b314ad191ab702a5de3faf49304f7e104918" +checksum = "b1fa70dc5c8104ec096f4fe7ede7a221d35ae13dcd19ba1ad9a81d2cab9a1c44" dependencies = [ "cfg-if", "libc", @@ -500,9 +499,9 @@ dependencies = [ [[package]] name = "syn" -version = "1.0.17" +version = "1.0.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0df0eb663f387145cab623dea85b09c2c5b4b0aef44e945d928e682fce71bb03" +checksum = "6690e3e9f692504b941dc6c3b188fd28df054f7fb8469ab40680df52fdcc842b" dependencies = [ "proc-macro2", "quote", @@ -564,15 +563,15 @@ dependencies = [ [[package]] name = "unicode-width" -version = "0.1.7" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "caaa9d531767d1ff2150b9332433f32a24622147e5ebb1f26409d5da67afd479" +checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3" [[package]] name = "unicode-xid" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" +checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" [[package]] name = "wasi" @@ -582,9 +581,9 @@ checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" [[package]] name = "winapi" -version = "0.3.8" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" dependencies = [ "winapi-i686-pc-windows-gnu", "winapi-x86_64-pc-windows-gnu", @@ -598,9 +597,9 @@ checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-util" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa515c5163a99cc82bab70fd3bfdd36d827be85de63737b40fcef2ce084a436e" +checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" dependencies = [ "winapi", ] diff --git a/cargo-miri/Cargo.lock b/cargo-miri/Cargo.lock index bb3b05db03a41..4053bfbcc46ee 100644 --- a/cargo-miri/Cargo.lock +++ b/cargo-miri/Cargo.lock @@ -14,15 +14,15 @@ checksum = "cff77d8686867eceff3105329d4698d96c2391c176d5d03adc90c7389162b5b8" [[package]] name = "autocfg" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d" +checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" [[package]] name = "base64" -version = "0.11.0" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b41b7ea54a0c9d92199de89e20e58d49f02f8e699814ef3fdf266f6f748d15c7" +checksum = "3441f0f7b02788e948e47f457ca01f1d7e6d92c693bc132c22b087d3141c03ff" [[package]] name = "bitflags" @@ -61,9 +61,9 @@ checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" [[package]] name = "chrono" -version = "0.4.11" +version = "0.4.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80094f509cf8b5ae86a4966a39b3ff66cd7e2a3e594accec3743ff3fabeab5b2" +checksum = "942f72db697d8767c22d46a598e01f2d3b475501ea43d0db4f16d90259182d0b" dependencies = [ "num-integer", "num-traits", @@ -99,11 +99,10 @@ dependencies = [ [[package]] name = "dirs-sys" -version = "0.3.4" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afa0b23de8fd801745c471deffa6e12d248f962c9fd4b4c33787b055599bde7b" +checksum = "8e93d7f5705de3e49895a2b5e0b8855a1c27f080192ae9c32a6432d50741a57a" dependencies = [ - "cfg-if", "libc", "redox_users", "winapi", @@ -111,20 +110,20 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.1.14" +version = "0.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7abc8dd8451921606d809ba32e95b6111925cd2906060d2dcc29c070220503eb" +checksum = "fc587bc0ec293155d5bfa6b9891ec18a1e330c234f896ea47fbada4cadbe47e6" dependencies = [ "cfg-if", "libc", - "wasi", + "wasi 0.9.0+wasi-snapshot-preview1", ] [[package]] name = "itoa" -version = "0.4.5" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8b7a7c0c47db5545ed3fef7468ee7bb5b74691498139e4b3f6a20685dc6dd8e" +checksum = "dc6f3ad7b9d11a0c00842ff8de1b60ee58661048eb8049ed33c73594f359d7e6" [[package]] name = "lazy_static" @@ -134,15 +133,15 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.70" +version = "0.2.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3baa92041a6fec78c687fa0cc2b3fae8884f743d672cf551bed1d6dac6988d0f" +checksum = "f2f96b10ec2560088a8e76961b00d47107b3a625fecb76dedb29ee7ccbf98235" [[package]] name = "num-integer" -version = "0.1.42" +version = "0.1.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f6ea62e9d81a77cd3ee9a2a5b9b609447857f3d358704331e4ef39eb247fcba" +checksum = "8d59457e662d541ba17869cf51cf177c0b5f0cbf476c66bdc90bf1edac4f875b" dependencies = [ "autocfg", "num-traits", @@ -150,42 +149,42 @@ dependencies = [ [[package]] name = "num-traits" -version = "0.2.11" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c62be47e61d1842b9170f0fdeec8eba98e60e90e5446449a0545e5152acd7096" +checksum = "ac267bcc07f48ee5f8935ab0d24f316fb722d7a1292e2913f0cc196b29ffd611" dependencies = [ "autocfg", ] [[package]] name = "proc-macro2" -version = "1.0.13" +version = "1.0.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53f5ffe53a6b28e37c9c1ce74893477864d64f74778a93a4beb43c8fa167f639" +checksum = "36e28516df94f3dd551a587da5357459d9b36d945a7c37c3557928c1c2ff2a2c" dependencies = [ "unicode-xid", ] [[package]] name = "quote" -version = "1.0.6" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54a21852a652ad6f610c9510194f398ff6f8692e334fd1145fed931f7fbe44ea" +checksum = "aa563d17ecb180e500da1cfd2b028310ac758de548efdd203e18f283af693f37" dependencies = [ "proc-macro2", ] [[package]] name = "redox_syscall" -version = "0.1.56" +version = "0.1.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84" +checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce" [[package]] name = "redox_users" -version = "0.3.4" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09b23093265f8d200fa7b4c2c76297f47e681c655f6f1285a8780d6a022f7431" +checksum = "de0737333e7a9502c789a36d7c7fa6092a49895d4faa31ca5df163857ded2e9d" dependencies = [ "getrandom", "redox_syscall", @@ -194,9 +193,9 @@ dependencies = [ [[package]] name = "rust-argon2" -version = "0.7.0" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bc8af4bda8e1ff4932523b94d3dd20ee30a87232323eda55903ffd71d2fb017" +checksum = "9dab61250775933275e84053ac235621dfb739556d5c54a2f2e9313b7cf43a19" dependencies = [ "base64", "blake2b_simd", @@ -221,9 +220,9 @@ dependencies = [ [[package]] name = "ryu" -version = "1.0.4" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed3d612bc64430efeb3f7ee6ef26d590dce0c43249217bddc62112540c7941e1" +checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" [[package]] name = "semver" @@ -242,18 +241,18 @@ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" [[package]] name = "serde" -version = "1.0.110" +version = "1.0.116" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99e7b308464d16b56eba9964e4972a3eee817760ab60d88c3f86e1fecb08204c" +checksum = "96fe57af81d28386a513cbc6858332abc6117cfdb5999647c6444b8f43a370a5" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.110" +version = "1.0.116" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "818fbf6bfa9a42d3bfcaca148547aa00c7b915bec71d1757aa2d44ca68771984" +checksum = "f630a6370fd8e457873b4bd2ffdae75408bc291ba72be773772a4c2a065d9ae8" dependencies = [ "proc-macro2", "quote", @@ -262,9 +261,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.53" +version = "1.0.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "993948e75b189211a9b31a7528f950c6adc21f9720b6438ff80a7fa2f864cea2" +checksum = "164eacbdb13512ec2745fb09d51fd5b22b0d65ed294a1dcf7285a360c80a675c" dependencies = [ "itoa", "ryu", @@ -273,9 +272,9 @@ dependencies = [ [[package]] name = "syn" -version = "1.0.23" +version = "1.0.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95b5f192649e48a5302a13f2feb224df883b98933222369e4b3b0fe2a5447269" +checksum = "6690e3e9f692504b941dc6c3b188fd28df054f7fb8469ab40680df52fdcc842b" dependencies = [ "proc-macro2", "quote", @@ -284,19 +283,20 @@ dependencies = [ [[package]] name = "time" -version = "0.1.43" +version = "0.1.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca8a50ef2360fbd1eeb0ecd46795a87a19024eb4b53c5dc916ca1fd95fe62438" +checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255" dependencies = [ "libc", + "wasi 0.10.0+wasi-snapshot-preview1", "winapi", ] [[package]] name = "unicode-xid" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" +checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" [[package]] name = "vergen" @@ -314,11 +314,17 @@ version = "0.9.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" +[[package]] +name = "wasi" +version = "0.10.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" + [[package]] name = "winapi" -version = "0.3.8" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" dependencies = [ "winapi-i686-pc-windows-gnu", "winapi-x86_64-pc-windows-gnu", From 055e90dd6f912ebb7746c23da56f139c958aaac1 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 18 Sep 2020 12:12:02 +0200 Subject: [PATCH 2308/3747] 'cargo update' test-cargo-miri --- test-cargo-miri/Cargo.lock | 24 +++++++++++++----------- test-cargo-miri/Cargo.toml | 1 - test-cargo-miri/src/main.rs | 3 ++- test-cargo-miri/subcrate/Cargo.toml | 3 +++ test-cargo-miri/subcrate/test.rs | 3 +++ test-cargo-miri/test.stdout.ref1 | 6 +++--- test-cargo-miri/test.stdout.ref2 | 2 +- test-cargo-miri/test.stdout.ref3 | 5 ++--- test-cargo-miri/tests/test.rs | 5 ----- 9 files changed, 27 insertions(+), 25 deletions(-) diff --git a/test-cargo-miri/Cargo.lock b/test-cargo-miri/Cargo.lock index 6bc70135a898a..8ea88fbb828d8 100644 --- a/test-cargo-miri/Cargo.lock +++ b/test-cargo-miri/Cargo.lock @@ -11,7 +11,6 @@ name = "cargo-miri-test" version = "0.1.0" dependencies = [ "byteorder", - "num_cpus", "rand", ] @@ -23,9 +22,9 @@ checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" [[package]] name = "getrandom" -version = "0.1.14" +version = "0.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7abc8dd8451921606d809ba32e95b6111925cd2906060d2dcc29c070220503eb" +checksum = "fc587bc0ec293155d5bfa6b9891ec18a1e330c234f896ea47fbada4cadbe47e6" dependencies = [ "cfg-if", "libc", @@ -34,24 +33,24 @@ dependencies = [ [[package]] name = "hermit-abi" -version = "0.1.10" +version = "0.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "725cf19794cf90aa94e65050cb4191ff5d8fa87a498383774c47b332e3af952e" +checksum = "3deed196b6e7f9e44a2ae8d94225d80302d81208b1bb673fd21fe634645c85a9" dependencies = [ "libc", ] [[package]] name = "libc" -version = "0.2.68" +version = "0.2.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dea0c0405123bba743ee3f91f49b1c7cfb684eef0da0a50110f758ccf24cdff0" +checksum = "f2f96b10ec2560088a8e76961b00d47107b3a625fecb76dedb29ee7ccbf98235" [[package]] name = "num_cpus" -version = "1.12.0" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46203554f085ff89c235cd12f7075f3233af9b11ed7c9e16dfe2560d03313ce6" +checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3" dependencies = [ "hermit-abi", "libc", @@ -59,9 +58,9 @@ dependencies = [ [[package]] name = "ppv-lite86" -version = "0.2.6" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74490b50b9fbe561ac330df47c08f3f33073d2d00c150f719147d7c54522fa1b" +checksum = "c36fa947111f5c62a733b652544dd0016a43ce89619538a8ef92724a6f501a20" [[package]] name = "rand" @@ -117,6 +116,9 @@ dependencies = [ [[package]] name = "subcrate" version = "0.1.0" +dependencies = [ + "num_cpus", +] [[package]] name = "wasi" diff --git a/test-cargo-miri/Cargo.toml b/test-cargo-miri/Cargo.toml index 4900ce9675d6f..b2a1612ffadfe 100644 --- a/test-cargo-miri/Cargo.toml +++ b/test-cargo-miri/Cargo.toml @@ -12,7 +12,6 @@ byteorder = "1.0" [dev-dependencies] rand = { version = "0.7", features = ["small_rng"] } -num_cpus = "1.10.1" [lib] test = false # test that this is respected (will show in the output) diff --git a/test-cargo-miri/src/main.rs b/test-cargo-miri/src/main.rs index 43b507e9c9aa5..16b173b287cae 100644 --- a/test-cargo-miri/src/main.rs +++ b/test-cargo-miri/src/main.rs @@ -19,6 +19,7 @@ fn main() { } // If there were no arguments, access stdin and test working dir. + // (We rely on the test runner to always disable isolation when passing no arguments.) if std::env::args().len() <= 1 { // CWD should be crate root. // We have to normalize slashes, as the env var might be set for a different target's conventions. @@ -33,7 +34,7 @@ fn main() { let num: i32 = line.unwrap().parse().unwrap(); println!("{}", 2*num); } - // On non-Unix, reading from stdin is not support. So we hard-code the right answer. + // On non-Unix, reading from stdin is not supported. So we hard-code the right answer. #[cfg(not(unix))] { println!("24"); diff --git a/test-cargo-miri/subcrate/Cargo.toml b/test-cargo-miri/subcrate/Cargo.toml index 78552e6aedf07..be27f88ad9a1c 100644 --- a/test-cargo-miri/subcrate/Cargo.toml +++ b/test-cargo-miri/subcrate/Cargo.toml @@ -12,3 +12,6 @@ path = "main.rs" name = "subtest" path = "test.rs" harness = false + +[dev-dependencies] +num_cpus = "1.10.1" diff --git a/test-cargo-miri/subcrate/test.rs b/test-cargo-miri/subcrate/test.rs index 0fd26059a1d37..fdab9402813be 100644 --- a/test-cargo-miri/subcrate/test.rs +++ b/test-cargo-miri/subcrate/test.rs @@ -10,4 +10,7 @@ fn main() { let crate_dir = env::var_os("CARGO_MANIFEST_DIR").unwrap(); let crate_dir = crate_dir.to_string_lossy().replace("\\", "/"); assert_eq!(env_dir, crate_dir); + + // Make sure we can call `num_cpus`. + num_cpus::get(); } diff --git a/test-cargo-miri/test.stdout.ref1 b/test-cargo-miri/test.stdout.ref1 index 1eb18fe88768a..7079798e42feb 100644 --- a/test-cargo-miri/test.stdout.ref1 +++ b/test-cargo-miri/test.stdout.ref1 @@ -4,7 +4,7 @@ running 1 test test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out -running 8 tests -..i..... -test result: ok. 7 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out +running 7 tests +..i.... +test result: ok. 6 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out diff --git a/test-cargo-miri/test.stdout.ref2 b/test-cargo-miri/test.stdout.ref2 index d426bdf6db632..37efb8c3ee896 100644 --- a/test-cargo-miri/test.stdout.ref2 +++ b/test-cargo-miri/test.stdout.ref2 @@ -7,5 +7,5 @@ test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 1 filtered out running 1 test test simple1 ... ok -test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 7 filtered out +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 6 filtered out diff --git a/test-cargo-miri/test.stdout.ref3 b/test-cargo-miri/test.stdout.ref3 index 32bbcf9bf275b..893e52e87774d 100644 --- a/test-cargo-miri/test.stdout.ref3 +++ b/test-cargo-miri/test.stdout.ref3 @@ -1,13 +1,12 @@ -running 8 tests +running 7 tests test cargo_env ... ok test do_panic ... ok test does_not_work_on_miri ... ignored test entropy_rng ... ok test fail_index_check ... ok -test num_cpus ... ok test simple1 ... ok test simple2 ... ok -test result: ok. 7 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out +test result: ok. 6 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out diff --git a/test-cargo-miri/tests/test.rs b/test-cargo-miri/tests/test.rs index 35e05368803a6..436e919e050d9 100644 --- a/test-cargo-miri/tests/test.rs +++ b/test-cargo-miri/tests/test.rs @@ -37,11 +37,6 @@ fn entropy_rng() { let _val = rng.gen::(); } -#[test] -fn num_cpus() { - assert_eq!(num_cpus::get(), 1); -} - #[test] fn cargo_env() { assert_eq!(env!("CARGO_PKG_NAME"), "cargo-miri-test"); From 6be8761e4717ae9b3810cf6a9ce70afa952142e3 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 18 Sep 2020 12:17:09 +0200 Subject: [PATCH 2309/3747] update for major version bumps --- Cargo.lock | 23 +++++++++++++++++------ Cargo.toml | 4 ++-- cargo-miri/Cargo.lock | 5 ++--- cargo-miri/Cargo.toml | 2 +- 4 files changed, 22 insertions(+), 12 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4cf2b62006f88..8c73cb05535c9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -69,9 +69,9 @@ checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" [[package]] name = "colored" -version = "1.9.3" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4ffc801dacf156c5854b9df4f425a626539c3a6ef7893cc0c5084a23f0b6c59" +checksum = "b3616f750b84d8f0de8a58bda93e08e2a81ad3f523089b05f1dffecab48c6cbd" dependencies = [ "atty", "lazy_static", @@ -189,6 +189,17 @@ dependencies = [ "wasi", ] +[[package]] +name = "getrandom" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee8025cf36f917e6a52cce185b7c7177689b838b7ec138364e50cc2277a56cf4" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + [[package]] name = "hermit-abi" version = "0.1.15" @@ -263,7 +274,7 @@ dependencies = [ "colored", "compiletest_rs", "env_logger", - "getrandom", + "getrandom 0.2.0", "hex", "libc", "log", @@ -309,7 +320,7 @@ version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" dependencies = [ - "getrandom", + "getrandom 0.1.15", "libc", "rand_chacha", "rand_core", @@ -332,7 +343,7 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" dependencies = [ - "getrandom", + "getrandom 0.1.15", ] [[package]] @@ -356,7 +367,7 @@ version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "de0737333e7a9502c789a36d7c7fa6092a49895d4faa31ca5df163857ded2e9d" dependencies = [ - "getrandom", + "getrandom 0.1.15", "redox_syscall", "rust-argon2", ] diff --git a/Cargo.toml b/Cargo.toml index 89f568146e07c..c36a97bb0a1ae 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,7 +24,7 @@ doctest = false # and no doc tests required-features = ["rustc_tests"] [dependencies] -getrandom = { version = "0.1.8", features = ["std"] } +getrandom = { version = "0.2", features = ["std"] } env_logger = "0.7.1" log = "0.4" shell-escape = "0.1.4" @@ -44,7 +44,7 @@ libc = "0.2" [dev-dependencies] compiletest_rs = { version = "0.5", features = ["tmp"] } rustc_version = "0.2.3" -colored = "1.6" +colored = "2" [features] rustc_tests = [] diff --git a/cargo-miri/Cargo.lock b/cargo-miri/Cargo.lock index 4053bfbcc46ee..54472947b691d 100644 --- a/cargo-miri/Cargo.lock +++ b/cargo-miri/Cargo.lock @@ -89,11 +89,10 @@ dependencies = [ [[package]] name = "directories" -version = "2.0.2" +version = "3.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "551a778172a450d7fc12e629ca3b0428d00f6afa9a43da1b630d54604e97371c" +checksum = "f8fed639d60b58d0f53498ab13d26f621fd77569cc6edb031f4cc36a2ad9da0f" dependencies = [ - "cfg-if", "dirs-sys", ] diff --git a/cargo-miri/Cargo.toml b/cargo-miri/Cargo.toml index 2de581c1c2e26..8233c5c24f83a 100644 --- a/cargo-miri/Cargo.toml +++ b/cargo-miri/Cargo.toml @@ -14,7 +14,7 @@ test = false # we have no unit tests doctest = false # and no doc tests [dependencies] -directories = "2.0" +directories = "3" rustc_version = "0.2.3" serde_json = "1.0.40" From 32cdb7131b275c00f6a711e2c0f71d5ae76b67d5 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 18 Sep 2020 13:10:18 +0200 Subject: [PATCH 2310/3747] support panic=abort --- README.md | 2 + cargo-miri/bin.rs | 48 ++++++++++++++++++------ src/shims/foreign_items.rs | 18 +++++---- src/shims/panic.rs | 2 + tests/compile-fail/panic/panic_abort1.rs | 5 ++- tests/compile-fail/panic/panic_abort2.rs | 4 +- tests/compile-fail/panic/panic_abort3.rs | 4 +- tests/compile-fail/panic/panic_abort4.rs | 4 +- 8 files changed, 59 insertions(+), 28 deletions(-) diff --git a/README.md b/README.md index 6654de10abfff..22823f5bf8bf8 100644 --- a/README.md +++ b/README.md @@ -244,6 +244,8 @@ different Miri binaries, and as such worth documenting: * `MIRI_BE_RUSTC` when set to any value tells the Miri driver to actually not interpret the code but compile it like rustc would. This is useful to be sure that the compiled `rlib`s are compatible with Miri. + When set while running `cargo-miri`, it indicates that we are part of a sysroot + build (for which some crates need special treatment). * `MIRI_CWD` when set to any value tells the Miri driver to change to the given directory after loading all the source files, but before commencing interpretation. This is useful if the interpreted program wants a different diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index 522570626d094..2eefc105abb78 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -295,8 +295,7 @@ fn setup(subcommand: MiriCommand) { br#" [dependencies.std] default_features = false -# We need the `panic_unwind` feature because we use the `unwind` panic strategy. -# Using `abort` works for libstd, but then libtest will not compile. +# We support unwinding, so enable that panic runtime. features = ["panic_unwind"] [dependencies.test] @@ -338,10 +337,14 @@ path = "lib.rs" // because we still need bootstrap to distinguish between host and target crates. // In that case we overwrite `RUSTC_REAL` instead which determines the rustc used // for target crates. + // We set ourselves (`cargo-miri`) instead of Miri directly to be able to patch the flags + // for `libpanic_abort` (usually this is done by bootstrap but we have to do it ourselves). + // The `MIRI_BE_RUSTC` will mean we dispatch to `phase_setup_rustc`. + let cargo_miri_path = std::env::current_exe().expect("current executable path invalid"); if env::var_os("RUSTC_STAGE").is_some() { - command.env("RUSTC_REAL", find_miri()); + command.env("RUSTC_REAL", &cargo_miri_path); } else { - command.env("RUSTC", find_miri()); + command.env("RUSTC", &cargo_miri_path); } command.env("MIRI_BE_RUSTC", "1"); // Make sure there are no other wrappers or flags getting in our way @@ -370,6 +373,21 @@ path = "lib.rs" } } +fn phase_setup_rustc(args: env::Args) { + // Mostly we just forward everything. + // `MIRI_BE_RUST` is already set. + let mut cmd = miri(); + cmd.args(args); + + // Patch the panic runtime for `libpanic_abort` (mirroring what bootstrap usually does). + if get_arg_flag_value("--crate-name").as_deref() == Some("panic_abort") { + cmd.arg("-C").arg("panic=abort"); + } + + // Run it! + exec(cmd); +} + fn phase_cargo_miri(mut args: env::Args) { // Check for version and help flags even when invoked as `cargo-miri`. if has_arg_flag("--help") || has_arg_flag("-h") { @@ -402,7 +420,7 @@ fn phase_cargo_miri(mut args: env::Args) { // describes an alternative // approach that uses `cargo check`, making that part easier but target and binary handling // harder. - let miri_path = std::env::current_exe().expect("current executable path invalid"); + let cargo_miri_path = std::env::current_exe().expect("current executable path invalid"); let cargo_cmd = match subcommand { MiriCommand::Test => "test", MiriCommand::Run => "run", @@ -470,22 +488,22 @@ fn phase_cargo_miri(mut args: env::Args) { if env::var_os("RUSTC_WRAPPER").is_some() { println!("WARNING: Ignoring `RUSTC_WRAPPER` environment variable, Miri does not support wrapping."); } - cmd.env("RUSTC_WRAPPER", &miri_path); - if verbose { - eprintln!("+ RUSTC_WRAPPER={:?}", miri_path); - } + cmd.env("RUSTC_WRAPPER", &cargo_miri_path); // Set the runner for the current target to us as well, so we can interpret the binaries. let runner_env_name = format!("CARGO_TARGET_{}_RUNNER", target.to_uppercase().replace('-', "_")); - cmd.env(runner_env_name, &miri_path); + cmd.env(&runner_env_name, &cargo_miri_path); // Set rustdoc to us as well, so we can make it do nothing (see issue #584). - cmd.env("RUSTDOC", &miri_path); + cmd.env("RUSTDOC", &cargo_miri_path); // Run cargo. if verbose { - cmd.env("MIRI_VERBOSE", ""); // This makes the other phases verbose. + eprintln!("[cargo-miri miri] RUSTC_WRAPPER={:?}", cargo_miri_path); + eprintln!("[cargo-miri miri] {}={:?}", runner_env_name, cargo_miri_path); + eprintln!("[cargo-miri miri] RUSTDOC={:?}", cargo_miri_path); eprintln!("[cargo-miri miri] {:?}", cmd); + cmd.env("MIRI_VERBOSE", ""); // This makes the other phases verbose. } exec(cmd) } @@ -699,6 +717,12 @@ fn main() { // Skip binary name. args.next().unwrap(); + // Dispatch running as part of sysroot compilation. + if env::var_os("MIRI_BE_RUSTC").is_some() { + phase_setup_rustc(args); + return; + } + // Dispatch to `cargo-miri` phase. There are three phases: // - When we are called via `cargo miri`, we run as the frontend and invoke the underlying // cargo. We set RUSTC_WRAPPER and CARGO_TARGET_RUNNER to ourselves. diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 355801eb8ffb2..a2ff39d0b4e9c 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -4,7 +4,7 @@ use log::trace; use rustc_hir::def_id::DefId; use rustc_middle::{mir, ty}; -use rustc_target::abi::{Align, Size}; +use rustc_target::{abi::{Align, Size}, spec::PanicStrategy}; use rustc_apfloat::Float; use rustc_span::symbol::sym; @@ -146,6 +146,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let code = this.read_scalar(code)?.to_i32()?; throw_machine_stop!(TerminationInfo::Exit(code.into())); } + "abort" => { + throw_machine_stop!(TerminationInfo::Abort(None)) + } _ => throw_unsup_format!("can't call (diverging) foreign function: {}", link_name), }, Some(p) => p, @@ -160,13 +163,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Normally, this will be either `libpanic_unwind` or `libpanic_abort`, but it could // also be a custom user-provided implementation via `#![feature(panic_runtime)]` "__rust_start_panic" | "__rust_panic_cleanup"=> { - // FIXME we might want to cache this... but it's not really performance-critical. - let panic_runtime = tcx - .crates() - .iter() - .find(|cnum| tcx.is_panic_runtime(**cnum)) - .expect("No panic runtime found!"); - let panic_runtime = tcx.crate_name(*panic_runtime); + // This replicates some of the logic in `inject_panic_runtime`. + // FIXME: is there a way to reuse that logic? + let panic_runtime = match this.tcx.sess.panic_strategy() { + PanicStrategy::Unwind => sym::panic_unwind, + PanicStrategy::Abort => sym::panic_abort, + }; let start_panic_instance = this.resolve_path(&[&*panic_runtime.as_str(), link_name]); return Ok(Some(&*this.load_mir(start_panic_instance.def, None)?)); diff --git a/src/shims/panic.rs b/src/shims/panic.rs index f907b76b679c4..52d27a1bb5c2d 100644 --- a/src/shims/panic.rs +++ b/src/shims/panic.rs @@ -44,6 +44,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); trace!("miri_start_panic: {:?}", this.frame().instance); + // Make sure we only start unwinding when this matches our panic strategy. + assert_eq!(this.tcx.sess.panic_strategy(), PanicStrategy::Unwind); // Get the raw pointer stored in arg[0] (the panic payload). let &[payload] = check_arg_count(args)?; diff --git a/tests/compile-fail/panic/panic_abort1.rs b/tests/compile-fail/panic/panic_abort1.rs index 4a1bb11483ca7..ee1d5b312d547 100644 --- a/tests/compile-fail/panic/panic_abort1.rs +++ b/tests/compile-fail/panic/panic_abort1.rs @@ -1,6 +1,7 @@ -// ignore-test: Abort panics are not yet supported -// error-pattern: the evaluated program panicked +// error-pattern: the evaluated program aborted execution // compile-flags: -C panic=abort +// ignore-windows: windows panics via inline assembly (FIXME) + fn main() { std::panic!("panicking from libstd"); } diff --git a/tests/compile-fail/panic/panic_abort2.rs b/tests/compile-fail/panic/panic_abort2.rs index ce4471c0effc2..4c08ab4ddcb71 100644 --- a/tests/compile-fail/panic/panic_abort2.rs +++ b/tests/compile-fail/panic/panic_abort2.rs @@ -1,6 +1,6 @@ -// ignore-test: Abort panics are not yet supported -// error-pattern: the evaluated program panicked +// error-pattern: the evaluated program aborted execution // compile-flags: -C panic=abort +// ignore-windows: windows panics via inline assembly (FIXME) fn main() { std::panic!("{}-panicking from libstd", 42); diff --git a/tests/compile-fail/panic/panic_abort3.rs b/tests/compile-fail/panic/panic_abort3.rs index 842a0f5435b74..81a603d5e3690 100644 --- a/tests/compile-fail/panic/panic_abort3.rs +++ b/tests/compile-fail/panic/panic_abort3.rs @@ -1,6 +1,6 @@ -// ignore-test: Abort panics are not yet supported -//error-pattern: the evaluated program panicked +// error-pattern: the evaluated program aborted execution // compile-flags: -C panic=abort +// ignore-windows: windows panics via inline assembly (FIXME) fn main() { core::panic!("panicking from libcore"); diff --git a/tests/compile-fail/panic/panic_abort4.rs b/tests/compile-fail/panic/panic_abort4.rs index 816cc90cfabd8..d015316ef2633 100644 --- a/tests/compile-fail/panic/panic_abort4.rs +++ b/tests/compile-fail/panic/panic_abort4.rs @@ -1,6 +1,6 @@ -// ignore-test: Abort panics are not yet supported -//error-pattern: the evaluated program panicked +// error-pattern: the evaluated program aborted execution // compile-flags: -C panic=abort +// ignore-windows: windows panics via inline assembly (FIXME) fn main() { core::panic!("{}-panicking from libcore", 42); From 97a71c0c777fa5873aca866a9a8f4adfab48feef Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 18 Sep 2020 13:34:25 +0200 Subject: [PATCH 2311/3747] fmt Co-authored-by: Oli Scherer --- src/shims/foreign_items.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index a2ff39d0b4e9c..5bcbd797ca3c9 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -162,7 +162,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // We forward this to the underlying *implementation* in the panic runtime crate. // Normally, this will be either `libpanic_unwind` or `libpanic_abort`, but it could // also be a custom user-provided implementation via `#![feature(panic_runtime)]` - "__rust_start_panic" | "__rust_panic_cleanup"=> { + "__rust_start_panic" | "__rust_panic_cleanup" => { // This replicates some of the logic in `inject_panic_runtime`. // FIXME: is there a way to reuse that logic? let panic_runtime = match this.tcx.sess.panic_strategy() { From 5652052e23d16a0c56d5d95a2b2f42ecd48c042f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 19 Sep 2020 11:37:56 +0200 Subject: [PATCH 2312/3747] list two more aliasing problems we found in BTreeMap and VecDeque --- README.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 22823f5bf8bf8..657ea096e6c8a 100644 --- a/README.md +++ b/README.md @@ -330,9 +330,9 @@ Definite bugs found: Violations of [Stacked Borrows] found that are likely bugs (but Stacked Borrows is currently just an experiment): -* [`VecDeque` creating overlapping mutable references](https://github.com/rust-lang/rust/pull/56161) -* [`BTreeMap` creating mutable references that overlap with shared references](https://github.com/rust-lang/rust/pull/58431) -* [`LinkedList` creating overlapping mutable references](https://github.com/rust-lang/rust/pull/60072) +* [`VecDeque::drain` creating overlapping mutable references](https://github.com/rust-lang/rust/pull/56161) +* [`BTreeMap` iterators creating mutable references that overlap with shared references](https://github.com/rust-lang/rust/pull/58431) +* [`LinkedList` cursor insertion creating overlapping mutable references](https://github.com/rust-lang/rust/pull/60072) * [`Vec::push` invalidating existing references into the vector](https://github.com/rust-lang/rust/issues/60847) * [`align_to_mut` violating uniqueness of mutable references](https://github.com/rust-lang/rust/issues/68549) * [`sized-chunks` creating aliasing mutable references](https://github.com/bodil/sized-chunks/issues/8) @@ -341,6 +341,8 @@ Violations of [Stacked Borrows] found that are likely bugs (but Stacked Borrows * [ink! creating overlapping mutable references](https://github.com/rust-lang/miri/issues/1364) * [TiKV creating overlapping mutable reference and raw pointer](https://github.com/tikv/tikv/pull/7709) * [Windows `Env` iterator creating `*const T` from `&T` to read memory outside of `T`](https://github.com/rust-lang/rust/pull/70479) +* [`BTreeMap::iter_mut` creating overlapping mutable references](https://github.com/rust-lang/rust/issues/73915) +* [`VecDeque::iter_mut` creating overlapping mutable references](https://github.com/rust-lang/rust/issues/74029) ## License From 83a339e5a9cdb9efce75e6c0ed90d630fd4eaf85 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 20 Sep 2020 10:26:22 +0200 Subject: [PATCH 2313/3747] rustup; make sure the iterator moves even with smarter optimizations --- rust-version | 2 +- tests/compile-fail/generator-pinned-moved.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/rust-version b/rust-version index d8673b9211643..37be5591da6e3 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -7bdb5dee7bac15458b10b148e9e24968e633053e +a3bc0e752fad96f537b73f4e9bc805a73d404f7b diff --git a/tests/compile-fail/generator-pinned-moved.rs b/tests/compile-fail/generator-pinned-moved.rs index 8f873f37a5f80..e0ce5cb7333a2 100644 --- a/tests/compile-fail/generator-pinned-moved.rs +++ b/tests/compile-fail/generator-pinned-moved.rs @@ -34,10 +34,10 @@ where fn main() { let mut generator_iterator_2 = { - let mut generator_iterator = GeneratorIteratorAdapter(firstn()); + let mut generator_iterator = Box::new(GeneratorIteratorAdapter(firstn())); generator_iterator.next(); // pin it - generator_iterator // move it + Box::new(*generator_iterator) // move it }; // *deallocate* generator_iterator generator_iterator_2.next(); // and use moved value From 08e076c658f0c42071c278bf35695e30273bed93 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 20 Sep 2020 12:02:04 +0200 Subject: [PATCH 2314/3747] account for mir-opts masking more errors --- tests/compile-fail/storage_dead_dangling.rs | 4 ++-- tests/compile-fail/validity/transmute_through_ptr.rs | 4 +++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/tests/compile-fail/storage_dead_dangling.rs b/tests/compile-fail/storage_dead_dangling.rs index bf2503917ccb4..ad8e05537e1af 100644 --- a/tests/compile-fail/storage_dead_dangling.rs +++ b/tests/compile-fail/storage_dead_dangling.rs @@ -1,5 +1,5 @@ -// This should fail even without validation -// compile-flags: -Zmiri-disable-validation +// This should fail even without validation, but some MIR opts mask the error +// compile-flags: -Zmiri-disable-validation -Zmir-opt-level=0 static mut LEAK: usize = 0; diff --git a/tests/compile-fail/validity/transmute_through_ptr.rs b/tests/compile-fail/validity/transmute_through_ptr.rs index 6a88fdaea1ee4..0ef69efb86e61 100644 --- a/tests/compile-fail/validity/transmute_through_ptr.rs +++ b/tests/compile-fail/validity/transmute_through_ptr.rs @@ -1,4 +1,5 @@ #[repr(u32)] +#[derive(Debug)] enum Bool { True } fn evil(x: &mut Bool) { @@ -9,6 +10,7 @@ fn evil(x: &mut Bool) { fn main() { let mut x = Bool::True; evil(&mut x); - let _y = x; // reading this ought to be enough to trigger validation + let y = x; // reading this ought to be enough to trigger validation //~^ ERROR encountered 0x0000002c at ., but expected a valid enum tag + println!("{:?}", y); // make sure it is used (and not optimized away) } From b0baa151b29d59b7bc6d7917503774a2416a5b4c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 20 Sep 2020 13:13:57 +0200 Subject: [PATCH 2315/3747] rustup --- rust-version | 2 +- src/helpers.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/rust-version b/rust-version index 37be5591da6e3..3126a8a9128d4 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -a3bc0e752fad96f537b73f4e9bc805a73d404f7b +5e449b9adff463455743291b0c1f76feec092992 diff --git a/src/helpers.rs b/src/helpers.rs index 5bb620b563d3c..abf128ff3e2da 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -59,7 +59,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); let instance = this.resolve_path(path); let cid = GlobalId { instance, promoted: None }; - let const_val = this.const_eval_raw(cid)?; + let const_val = this.eval_to_allocation(cid)?; let const_val = this.read_scalar(const_val.into())?; return Ok(const_val); } From 4b5e78052a030783a609ea0d9c5ad401261fc44d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 20 Sep 2020 15:55:36 +0200 Subject: [PATCH 2316/3747] rustup; support panic=abort on Windows --- rust-version | 2 +- tests/compile-fail/panic/panic_abort1.rs | 1 - tests/compile-fail/panic/panic_abort2.rs | 1 - tests/compile-fail/panic/panic_abort3.rs | 1 - tests/compile-fail/panic/panic_abort4.rs | 1 - 5 files changed, 1 insertion(+), 5 deletions(-) diff --git a/rust-version b/rust-version index 3126a8a9128d4..92bdd16b2be60 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -5e449b9adff463455743291b0c1f76feec092992 +41507ed0d57eba71adc20a021a19b64322162f04 diff --git a/tests/compile-fail/panic/panic_abort1.rs b/tests/compile-fail/panic/panic_abort1.rs index ee1d5b312d547..02f8f25880f3d 100644 --- a/tests/compile-fail/panic/panic_abort1.rs +++ b/tests/compile-fail/panic/panic_abort1.rs @@ -1,6 +1,5 @@ // error-pattern: the evaluated program aborted execution // compile-flags: -C panic=abort -// ignore-windows: windows panics via inline assembly (FIXME) fn main() { std::panic!("panicking from libstd"); diff --git a/tests/compile-fail/panic/panic_abort2.rs b/tests/compile-fail/panic/panic_abort2.rs index 4c08ab4ddcb71..0d6808dd22e04 100644 --- a/tests/compile-fail/panic/panic_abort2.rs +++ b/tests/compile-fail/panic/panic_abort2.rs @@ -1,6 +1,5 @@ // error-pattern: the evaluated program aborted execution // compile-flags: -C panic=abort -// ignore-windows: windows panics via inline assembly (FIXME) fn main() { std::panic!("{}-panicking from libstd", 42); diff --git a/tests/compile-fail/panic/panic_abort3.rs b/tests/compile-fail/panic/panic_abort3.rs index 81a603d5e3690..6640a56c0be28 100644 --- a/tests/compile-fail/panic/panic_abort3.rs +++ b/tests/compile-fail/panic/panic_abort3.rs @@ -1,6 +1,5 @@ // error-pattern: the evaluated program aborted execution // compile-flags: -C panic=abort -// ignore-windows: windows panics via inline assembly (FIXME) fn main() { core::panic!("panicking from libcore"); diff --git a/tests/compile-fail/panic/panic_abort4.rs b/tests/compile-fail/panic/panic_abort4.rs index d015316ef2633..d39b1794e676a 100644 --- a/tests/compile-fail/panic/panic_abort4.rs +++ b/tests/compile-fail/panic/panic_abort4.rs @@ -1,6 +1,5 @@ // error-pattern: the evaluated program aborted execution // compile-flags: -C panic=abort -// ignore-windows: windows panics via inline assembly (FIXME) fn main() { core::panic!("{}-panicking from libcore", 42); From 88b9c2173e71a02731b1e79e7b7a64783784e0ed Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 21 Sep 2020 09:10:04 +0200 Subject: [PATCH 2317/3747] also support old 'cargo miri run -- -- args' style --- cargo-miri/bin.rs | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index 2eefc105abb78..bc5738f01d150 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -452,26 +452,28 @@ fn phase_cargo_miri(mut args: env::Args) { // Check if the next argument starts with `-Zmiri`. If yes, we assume // this is an old-style invocation. if let Some(next_arg) = args.next() { - if next_arg.starts_with("-Zmiri") { + if next_arg.starts_with("-Zmiri") || next_arg == "--" { eprintln!( "WARNING: it seems like you are setting Miri's flags in `cargo miri` the old way,\n\ i.e., by passing them after the first `--`. This style is deprecated; please set\n\ the MIRIFLAGS environment variable instead. `cargo miri run/test` now interprets\n\ arguments the exact same way as `cargo run/test`." ); - // Old-style invocation. Turn these into MIRIFLAGS. - let mut miriflags = env::var("MIRIFLAGS").unwrap_or_default(); - miriflags.push(' '); - miriflags.push_str(&next_arg); - while let Some(further_arg) = args.next() { - if further_arg == "--" { - // End of the Miri flags! - break; - } + // Old-style invocation. Turn these into MIRIFLAGS, if there are any. + if next_arg != "--" { + let mut miriflags = env::var("MIRIFLAGS").unwrap_or_default(); miriflags.push(' '); - miriflags.push_str(&further_arg); + miriflags.push_str(&next_arg); + while let Some(further_arg) = args.next() { + if further_arg == "--" { + // End of the Miri flags! + break; + } + miriflags.push(' '); + miriflags.push_str(&further_arg); + } + env::set_var("MIRIFLAGS", miriflags); } - env::set_var("MIRIFLAGS", miriflags); // Pass the remaining flags to cargo. cmd.args(args); break; From 4dda2ad5b49cb64d2413c3a0b5f19e1b66e5db69 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 21 Sep 2020 12:46:18 +0200 Subject: [PATCH 2318/3747] support non-rlib extern files --- cargo-miri/bin.rs | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index bc5738f01d150..5731a9a591f9a 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -663,11 +663,16 @@ fn phase_cargo_runner(binary: &Path, binary_args: env::Args) { let json_flag = "--json"; while let Some(arg) = args.next() { if arg == extern_flag { + cmd.arg(extern_flag); // always forward flag, but adjust filename // `--extern` is always passed as a separate argument by cargo. let next_arg = args.next().expect("`--extern` should be followed by a filename"); - let next_arg = next_arg.strip_suffix(".rlib").expect("all extern filenames should end in `.rlib`"); - cmd.arg(extern_flag); - cmd.arg(format!("{}.rmeta", next_arg)); + if let Some(next_lib) = next_arg.strip_suffix(".rlib") { + // If this is an rlib, make it an rmeta. + cmd.arg(format!("{}.rmeta", next_lib)); + } else { + // Some other extern file (e.g., a `.so`). Forward unchanged. + cmd.arg(next_arg); + } } else if arg.starts_with(error_format_flag) { let suffix = &arg[error_format_flag.len()..]; assert!(suffix.starts_with('=')); From 0c67ec205723561fe9f7442185e4d62aed0adb10 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 21 Sep 2020 15:47:09 +0200 Subject: [PATCH 2319/3747] test formerly broken serde_derive dependency --- test-cargo-miri/Cargo.lock | 47 ++++++++++++++++++++++++++++++++++++++ test-cargo-miri/Cargo.toml | 1 + 2 files changed, 48 insertions(+) diff --git a/test-cargo-miri/Cargo.lock b/test-cargo-miri/Cargo.lock index 8ea88fbb828d8..b03347d9f0dec 100644 --- a/test-cargo-miri/Cargo.lock +++ b/test-cargo-miri/Cargo.lock @@ -12,6 +12,7 @@ version = "0.1.0" dependencies = [ "byteorder", "rand", + "serde_derive", ] [[package]] @@ -62,6 +63,24 @@ version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c36fa947111f5c62a733b652544dd0016a43ce89619538a8ef92724a6f501a20" +[[package]] +name = "proc-macro2" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36e28516df94f3dd551a587da5357459d9b36d945a7c37c3557928c1c2ff2a2c" +dependencies = [ + "unicode-xid", +] + +[[package]] +name = "quote" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa563d17ecb180e500da1cfd2b028310ac758de548efdd203e18f283af693f37" +dependencies = [ + "proc-macro2", +] + [[package]] name = "rand" version = "0.7.3" @@ -113,6 +132,17 @@ dependencies = [ "rand_core", ] +[[package]] +name = "serde_derive" +version = "1.0.116" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f630a6370fd8e457873b4bd2ffdae75408bc291ba72be773772a4c2a065d9ae8" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "subcrate" version = "0.1.0" @@ -120,6 +150,23 @@ dependencies = [ "num_cpus", ] +[[package]] +name = "syn" +version = "1.0.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6690e3e9f692504b941dc6c3b188fd28df054f7fb8469ab40680df52fdcc842b" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + +[[package]] +name = "unicode-xid" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" + [[package]] name = "wasi" version = "0.9.0+wasi-snapshot-preview1" diff --git a/test-cargo-miri/Cargo.toml b/test-cargo-miri/Cargo.toml index b2a1612ffadfe..54a03f5f5ded1 100644 --- a/test-cargo-miri/Cargo.toml +++ b/test-cargo-miri/Cargo.toml @@ -12,6 +12,7 @@ byteorder = "1.0" [dev-dependencies] rand = { version = "0.7", features = ["small_rng"] } +serde_derive = "1.0" # not actually used, but exercises some unique code path (`--extern` .so file) [lib] test = false # test that this is respected (will show in the output) From dae575c38f0d46e6a3b9144fa223384beddc8cc2 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 23 Sep 2020 22:13:13 +0200 Subject: [PATCH 2320/3747] opt-level 3 is clean again :) --- ci.sh | 3 +-- rust-version | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/ci.sh b/ci.sh index 12683a2fccbec..56a6f1228ab59 100755 --- a/ci.sh +++ b/ci.sh @@ -25,8 +25,7 @@ function run_tests { ./miri test --locked if ! [ -n "${MIRI_TEST_TARGET+exists}" ]; then # Only for host architecture: tests with MIR optimizations - # FIXME: only testing level 2 because of . - MIRIFLAGS="-Z mir-opt-level=2" ./miri test --locked + MIRIFLAGS="-Z mir-opt-level=3" ./miri test --locked fi # "miri test" has built the sysroot for us, now this should pass without # any interactive questions. diff --git a/rust-version b/rust-version index 92bdd16b2be60..16a773193d14d 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -41507ed0d57eba71adc20a021a19b64322162f04 +a6008fac97f81a3fc51668b0c7fa0e2e6f2a599b From 67c5067a2fa80ce5609ec4dbb833460efeacd30a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 24 Sep 2020 09:19:03 +0200 Subject: [PATCH 2321/3747] rustup; fix tests --- rust-version | 2 +- tests/compile-fail/alloc/deallocate-bad-alignment.rs | 2 +- tests/compile-fail/alloc/deallocate-bad-size.rs | 2 +- tests/compile-fail/alloc/reallocate-bad-size.rs | 2 +- tests/compile-fail/alloc/stack_free.rs | 2 +- tests/run-pass/heap_allocator.rs | 4 ++-- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/rust-version b/rust-version index 16a773193d14d..835708a42baa8 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -a6008fac97f81a3fc51668b0c7fa0e2e6f2a599b +78a089487b5f6d5e4205ac4500410b442857bced diff --git a/tests/compile-fail/alloc/deallocate-bad-alignment.rs b/tests/compile-fail/alloc/deallocate-bad-alignment.rs index 621c05344b4ac..852a0660217ee 100644 --- a/tests/compile-fail/alloc/deallocate-bad-alignment.rs +++ b/tests/compile-fail/alloc/deallocate-bad-alignment.rs @@ -1,6 +1,6 @@ use std::alloc::{alloc, dealloc, Layout}; -// error-pattern: allocation has size 1 and alignment 1, but gave size 1 and alignment 2 +// error-pattern: has size 1 and alignment 1, but gave size 1 and alignment 2 fn main() { unsafe { diff --git a/tests/compile-fail/alloc/deallocate-bad-size.rs b/tests/compile-fail/alloc/deallocate-bad-size.rs index 386bb56b90916..167cc015c2da9 100644 --- a/tests/compile-fail/alloc/deallocate-bad-size.rs +++ b/tests/compile-fail/alloc/deallocate-bad-size.rs @@ -1,6 +1,6 @@ use std::alloc::{alloc, dealloc, Layout}; -// error-pattern: allocation has size 1 and alignment 1, but gave size 2 and alignment 1 +// error-pattern: has size 1 and alignment 1, but gave size 2 and alignment 1 fn main() { unsafe { diff --git a/tests/compile-fail/alloc/reallocate-bad-size.rs b/tests/compile-fail/alloc/reallocate-bad-size.rs index 7826f26f9b8c6..80239015dc1d0 100644 --- a/tests/compile-fail/alloc/reallocate-bad-size.rs +++ b/tests/compile-fail/alloc/reallocate-bad-size.rs @@ -1,6 +1,6 @@ use std::alloc::{alloc, realloc, Layout}; -// error-pattern: allocation has size 1 and alignment 1, but gave size 2 and alignment 1 +// error-pattern: has size 1 and alignment 1, but gave size 2 and alignment 1 fn main() { unsafe { diff --git a/tests/compile-fail/alloc/stack_free.rs b/tests/compile-fail/alloc/stack_free.rs index 50a590e448a6a..d854fa993a79f 100644 --- a/tests/compile-fail/alloc/stack_free.rs +++ b/tests/compile-fail/alloc/stack_free.rs @@ -1,7 +1,7 @@ // Validation/SB changes why we fail // compile-flags: -Zmiri-disable-validation -Zmiri-disable-stacked-borrows -// error-pattern: deallocating stack variable memory using Rust heap deallocation operation +// error-pattern: which is stack variable memory, using Rust heap deallocation operation fn main() { let x = 42; diff --git a/tests/run-pass/heap_allocator.rs b/tests/run-pass/heap_allocator.rs index cf9a2f4b6925f..5d89243b86a93 100644 --- a/tests/run-pass/heap_allocator.rs +++ b/tests/run-pass/heap_allocator.rs @@ -4,7 +4,7 @@ use std::ptr::NonNull; use std::alloc::{Global, AllocRef, Layout, System}; use std::slice; -fn check_alloc(mut allocator: T) { unsafe { +fn check_alloc(allocator: T) { unsafe { for &align in &[4, 8, 16, 32] { let layout_20 = Layout::from_size_align(20, align).unwrap(); let layout_40 = Layout::from_size_align(40, 4*align).unwrap(); @@ -42,7 +42,7 @@ fn check_alloc(mut allocator: T) { unsafe { } } } -fn check_align_requests(mut allocator: T) { +fn check_align_requests(allocator: T) { for &size in &[2, 8, 64] { // size less than and bigger than alignment for &align in &[4, 8, 16, 32] { // Be sure to cover less than and bigger than `MIN_ALIGN` for all architectures let iterations = 32; From 56ea94dfa36e853ad7bf3b3d94718dc4c30f1596 Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Sun, 27 Sep 2020 10:00:06 +0700 Subject: [PATCH 2322/3747] Remove assume intrinsic from EvalContextExt It has been moved to rustc_mir. --- rust-version | 2 +- src/shims/intrinsics.rs | 8 -------- 2 files changed, 1 insertion(+), 9 deletions(-) diff --git a/rust-version b/rust-version index 835708a42baa8..362f89b5d1fee 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -78a089487b5f6d5e4205ac4500410b442857bced +1ec980d225fff2346a1a631a7ffc88b37e9e18af diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 6051ad482e519..b401bd8adaee4 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -478,14 +478,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // Other - "assume" => { - let &[cond] = check_arg_count(args)?; - let cond = this.read_scalar(cond)?.check_init()?.to_bool()?; - if !cond { - throw_ub_format!("`assume` intrinsic called with `false`"); - } - } - "exact_div" => { let &[num, denom] = check_arg_count(args)?; this.exact_div(this.read_immediate(num)?, this.read_immediate(denom)?, dest)?; From 22f1eb01ee42c8dcfe5e7d7c981bba82aad1bbea Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Mon, 2 Dec 2019 21:15:58 -0500 Subject: [PATCH 2323/3747] Add API for capturing backtrace This PR adds two new Miri-defined extern functions: `miri_get_backtrace` and `miri_resolve_frame`, which are documented in the README. Together, they allow obtaining a backtrace for the currently executing program. I've added a test showing how these APIs are used. I've also prepared a companion PR `backtrace-rs`, which will allow `backtrace::Backtrace::new()` to work automatically under Miri. Once these two PRs are merged, we will be able to print backtraces from the normal Rust panic hook (since libstd is now using backtrace-rs). A few notes: * Resolving the backtrace frames is *very* slow - you can actually see each line being printed out one at a time. Some local testing showed that this is not (primrary) caused by resolving a `Span` - it seems to be just Miri being slow. * For the first time, we now interact directly with a user-defined struct (instead of just executing the user-provided MIR that manipulates the struct). To allow for future changes, I've added a 'version' parameter (currently required to be 0). This should allow us to change the `MiriFrame` struct should the need ever arise. * I used the approach suggested by @oli-obk - a returned backtrace pointer consists of a base function allocation, with the 'offset' used to encode the `Span.lo`. This allows losslessly reconstructing the location information in `miri_resolve_frame`. * There are a few quirks on the `backtrace-rs` side: * `backtrace-rs` calls `getcwd()` by default to try to simplify the filename. This results in an isolation error by default, which could be annoying when printing a backtrace from libstd. * `backtrace-rs` tries to remove 'internal' frames (everything between the call to `Backtrace::new()` and the internal API call made by backtrace-rs) by comparing the returned frame pointer value to a Rust function pointer. This doesn't work due to the way we construct the frame pointers passed to the caller. We could attempt to support this kind of comparison, or just add a `#[cfg(miri)]` and ignore the frames ourselves. --- README.md | 26 ++++++ src/shims/foreign_items.rs | 88 ++++++++++++++++++- .../backtrace/bad-backtrace-decl.rs | 13 +++ .../backtrace/bad-backtrace-ptr.rs | 9 ++ .../backtrace/bad-backtrace-version.rs | 9 ++ tests/run-pass/backtrace-api.rs | 24 +++++ tests/run-pass/backtrace-api.stderr | 10 +++ 7 files changed, 178 insertions(+), 1 deletion(-) create mode 100644 tests/compile-fail/backtrace/bad-backtrace-decl.rs create mode 100644 tests/compile-fail/backtrace/bad-backtrace-ptr.rs create mode 100644 tests/compile-fail/backtrace/bad-backtrace-version.rs create mode 100644 tests/run-pass/backtrace-api.rs create mode 100644 tests/run-pass/backtrace-api.stderr diff --git a/README.md b/README.md index 657ea096e6c8a..524c8e10cf365 100644 --- a/README.md +++ b/README.md @@ -266,6 +266,32 @@ extern "Rust" { /// `ptr` has to point to the beginning of an allocated block. fn miri_static_root(ptr: *const u8); + /// Miri-provided extern function to obtain a backtrace of the current call stack. + /// This returns a boxed slice of pointers - each pointer is an opaque value + /// that is only useful when passed to `miri_resolve_frame` + fn miri_get_backtrace() -> Box<[*mut ()]>; + + /// Miri-provided extern function to resolve a frame pointer obtained + /// from `miri_get_backtrace`. The `version` argument must be `0`, + /// and `MiriFrame` should be declared as follows: + /// + /// ```rust + /// struct MiriFrame { + /// // The name of the function being executed, encoded in UTF-8 + /// name: Box<[u8]>, + /// // The filename of the function being executed, encoded in UTF-8 + /// filename: Box<[u8]>, + /// // The line number currently being executed in `filename`, starting from '1'. + /// lineno: u32, + /// // The column number currently being executed in `filename`, starting from '1'. + /// colno: u32, + /// } + /// ``` + /// + /// The fields must be declared in exactly the same order as they appear in `MiriFrame` above. + /// This function can be called on any thread (not just the one which obtained `frame`) + fn miri_resolve_frame(version: u8, frame: *mut ()) -> MiriFrame; + /// Miri-provided extern function to begin unwinding with the given payload. /// /// This is internal and unstable and should not be used; we give it here diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 5bcbd797ca3c9..4d1ead8f0f82f 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -3,10 +3,13 @@ use std::{convert::{TryInto, TryFrom}, iter}; use log::trace; use rustc_hir::def_id::DefId; -use rustc_middle::{mir, ty}; +use rustc_middle::mir; use rustc_target::{abi::{Align, Size}, spec::PanicStrategy}; +use rustc_middle::ty::{self, ParamEnv, TypeAndMut}; +use rustc_ast::ast::Mutability; use rustc_apfloat::Float; use rustc_span::symbol::sym; +use rustc_span::BytePos; use crate::*; use helpers::check_arg_count; @@ -211,6 +214,89 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.machine.static_roots.push(ptr.alloc_id); } + // Obtains a Miri backtrace. See the README for details. + "miri_get_backtrace" => { + let tcx = this.tcx; + let mut data = Vec::new(); + for frame in this.active_thread_stack().iter().rev() { + data.push((frame.instance, frame.current_span().lo())); + } + + let ptrs: Vec<_> = data.into_iter().map(|(instance, pos)| { + let mut fn_ptr = this.memory.create_fn_alloc(FnVal::Instance(instance)); + fn_ptr.offset = Size::from_bytes(pos.0); + Scalar::Ptr(fn_ptr) + }).collect(); + + let len = ptrs.len(); + + let ptr_ty = tcx.mk_ptr(TypeAndMut { + ty: tcx.types.unit, + mutbl: Mutability::Mut + }); + + let array_ty = tcx.mk_array(ptr_ty, ptrs.len().try_into().unwrap()); + let array_ty_and_env = ParamEnv::empty().and(array_ty); + + // Write pointers into array + let alloc = this.allocate(tcx.layout_of(array_ty_and_env).unwrap(), MiriMemoryKind::Rust.into()); + for (i, ptr) in ptrs.into_iter().enumerate() { + let place = this.mplace_index(alloc, i as u64)?; + this.write_immediate_to_mplace(ptr.into(), place)?; + } + + this.write_immediate(Immediate::new_slice(alloc.ptr.into(), len.try_into().unwrap(), this), dest)?; + } + + // Resolves a Miri backtrace frame. See the README for details. + "miri_resolve_frame" => { + let tcx = this.tcx; + let &[version, ptr] = check_arg_count(args)?; + + let version = this.read_scalar(version)?.to_u8()?; + if version != 0 { + throw_ub_format!("Unknown `miri_resolve_frame` version {}", version); + } + + let ptr = match this.read_scalar(ptr)?.check_init()? { + Scalar::Ptr(ptr) => ptr, + Scalar::Raw { .. } => throw_ub_format!("Expected a pointer in `rust_miri_resolve_frame`, found {:?}", ptr) + }; + + let fn_instance = if let Some(GlobalAlloc::Function(instance)) = this.tcx.get_global_alloc(ptr.alloc_id) { + instance + } else { + throw_ub_format!("Expect function pointer, found {:?}", ptr); + }; + + if dest.layout.layout.fields.count() != 4 { + throw_ub_format!("Bad declaration of miri_resolve_frame - should return a struct with 4 fields"); + } + + let pos = BytePos(ptr.offset.bytes().try_into().unwrap()); + let name = fn_instance.to_string(); + + let lo = tcx.sess.source_map().lookup_char_pos(pos); + + let filename = lo.file.name.to_string(); + let lineno: u32 = lo.line as u32; + // `lo.col` is 0-based - add 1 to make it 1-based for the caller. + let colno: u32 = lo.col.0 as u32 + 1; + + let name_alloc = this.allocate_str(&name, MiriMemoryKind::Rust.into()); + let filename_alloc = this.allocate_str(&filename, MiriMemoryKind::Rust.into()); + let lineno_alloc = Scalar::from_u32(lineno); + let colno_alloc = Scalar::from_u32(colno); + + let dest = this.force_allocation_maybe_sized(dest, MemPlaceMeta::None)?.0; + + this.write_immediate(name_alloc.to_ref(), this.mplace_field(dest, 0)?.into())?; + this.write_immediate(filename_alloc.to_ref(), this.mplace_field(dest, 1)?.into())?; + this.write_scalar(lineno_alloc, this.mplace_field(dest, 2)?.into())?; + this.write_scalar(colno_alloc, this.mplace_field(dest, 3)?.into())?; + } + + // Standard C allocation "malloc" => { let &[size] = check_arg_count(args)?; diff --git a/tests/compile-fail/backtrace/bad-backtrace-decl.rs b/tests/compile-fail/backtrace/bad-backtrace-decl.rs new file mode 100644 index 0000000000000..7c250fbbe3a4d --- /dev/null +++ b/tests/compile-fail/backtrace/bad-backtrace-decl.rs @@ -0,0 +1,13 @@ +extern "Rust" { + fn miri_get_backtrace() -> Box<[*mut ()]>; + fn miri_resolve_frame(version: u8, ptr: *mut ()); +} + +fn main() { + let frames = unsafe { miri_get_backtrace() }; + for frame in frames.into_iter() { + unsafe { + miri_resolve_frame(0, *frame); //~ ERROR Undefined Behavior: Bad declaration of miri_resolve_frame - should return a struct with 4 fields + } + } +} diff --git a/tests/compile-fail/backtrace/bad-backtrace-ptr.rs b/tests/compile-fail/backtrace/bad-backtrace-ptr.rs new file mode 100644 index 0000000000000..49b8ac88494dc --- /dev/null +++ b/tests/compile-fail/backtrace/bad-backtrace-ptr.rs @@ -0,0 +1,9 @@ +extern "Rust" { + fn miri_resolve_frame(version: u8, ptr: *mut ()); +} + +fn main() { + unsafe { + miri_resolve_frame(0, 0 as *mut _); //~ ERROR Undefined Behavior: Expected a pointer + } +} diff --git a/tests/compile-fail/backtrace/bad-backtrace-version.rs b/tests/compile-fail/backtrace/bad-backtrace-version.rs new file mode 100644 index 0000000000000..b0183ca99e942 --- /dev/null +++ b/tests/compile-fail/backtrace/bad-backtrace-version.rs @@ -0,0 +1,9 @@ +extern "Rust" { + fn miri_resolve_frame(version: u8, ptr: *mut ()); +} + +fn main() { + unsafe { + miri_resolve_frame(1, 0 as *mut _); //~ ERROR Undefined Behavior: Unknown `miri_resolve_frame` version 1 + } +} diff --git a/tests/run-pass/backtrace-api.rs b/tests/run-pass/backtrace-api.rs new file mode 100644 index 0000000000000..fa86debf17d5e --- /dev/null +++ b/tests/run-pass/backtrace-api.rs @@ -0,0 +1,24 @@ +// normalize-stderr-test ".*rustlib" -> "RUSTLIB" + +extern "Rust" { + fn miri_get_backtrace() -> Box<[*mut ()]>; + fn miri_resolve_frame(version: u8, ptr: *mut ()) -> MiriFrame; +} + +#[derive(Debug)] +struct MiriFrame { + name: Box<[u8]>, + filename: Box<[u8]>, + lineno: u32, + colno: u32 +} + +fn main() { + let frames = unsafe { miri_get_backtrace() }; + for frame in frames.into_iter() { + let miri_frame = unsafe { miri_resolve_frame(0, *frame) }; + let name = String::from_utf8(miri_frame.name.into()).unwrap(); + let filename = String::from_utf8(miri_frame.filename.into()).unwrap(); + eprintln!("{}:{}:{} ({})", filename, miri_frame.lineno, miri_frame.colno, name); + } +} diff --git a/tests/run-pass/backtrace-api.stderr b/tests/run-pass/backtrace-api.stderr new file mode 100644 index 0000000000000..91a99070eb647 --- /dev/null +++ b/tests/run-pass/backtrace-api.stderr @@ -0,0 +1,10 @@ +$DIR/backtrace-api.rs:17:27 (main) +RUSTLIB/src/rust/library/core/src/ops/function.rs:227:5 (>::call_once - shim(fn())) +RUSTLIB/src/rust/library/std/src/sys_common/backtrace.rs:137:18 (std::sys_common::backtrace::__rust_begin_short_backtrace::) +RUSTLIB/src/rust/library/std/src/rt.rs:66:18 (std::rt::lang_start::<()>::{{closure}}#0) +RUSTLIB/src/rust/library/core/src/ops/function.rs:259:13 (std::ops::function::impls:: for &dyn std::ops::Fn() -> i32 + std::marker::Sync + std::panic::RefUnwindSafe>::call_once) +RUSTLIB/src/rust/library/std/src/panicking.rs:381:40 (std::panicking::r#try::do_call::<&dyn std::ops::Fn() -> i32 + std::marker::Sync + std::panic::RefUnwindSafe, i32>) +RUSTLIB/src/rust/library/std/src/panicking.rs:345:19 (std::panicking::r#try:: i32 + std::marker::Sync + std::panic::RefUnwindSafe>) +RUSTLIB/src/rust/library/std/src/panic.rs:382:14 (std::panic::catch_unwind::<&dyn std::ops::Fn() -> i32 + std::marker::Sync + std::panic::RefUnwindSafe, i32>) +RUSTLIB/src/rust/library/std/src/rt.rs:51:25 (std::rt::lang_start_internal) +RUSTLIB/src/rust/library/std/src/rt.rs:65:5 (std::rt::lang_start::<()>) From ae18659d52821d95bf028f424b57f87a3465bf57 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Tue, 22 Sep 2020 10:58:18 -0400 Subject: [PATCH 2324/3747] Normalize line and column numbers from the sysroot --- tests/run-pass/backtrace-api.rs | 1 + tests/run-pass/backtrace-api.stderr | 20 ++++++++++---------- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/tests/run-pass/backtrace-api.rs b/tests/run-pass/backtrace-api.rs index fa86debf17d5e..51da6cf9c4dc5 100644 --- a/tests/run-pass/backtrace-api.rs +++ b/tests/run-pass/backtrace-api.rs @@ -1,4 +1,5 @@ // normalize-stderr-test ".*rustlib" -> "RUSTLIB" +// normalize-stderr-test "RUSTLIB/(.*):\d+:\d+ "-> "RUSTLIB/$1:LL:COL " extern "Rust" { fn miri_get_backtrace() -> Box<[*mut ()]>; diff --git a/tests/run-pass/backtrace-api.stderr b/tests/run-pass/backtrace-api.stderr index 91a99070eb647..042ca843d0e12 100644 --- a/tests/run-pass/backtrace-api.stderr +++ b/tests/run-pass/backtrace-api.stderr @@ -1,10 +1,10 @@ -$DIR/backtrace-api.rs:17:27 (main) -RUSTLIB/src/rust/library/core/src/ops/function.rs:227:5 (>::call_once - shim(fn())) -RUSTLIB/src/rust/library/std/src/sys_common/backtrace.rs:137:18 (std::sys_common::backtrace::__rust_begin_short_backtrace::) -RUSTLIB/src/rust/library/std/src/rt.rs:66:18 (std::rt::lang_start::<()>::{{closure}}#0) -RUSTLIB/src/rust/library/core/src/ops/function.rs:259:13 (std::ops::function::impls:: for &dyn std::ops::Fn() -> i32 + std::marker::Sync + std::panic::RefUnwindSafe>::call_once) -RUSTLIB/src/rust/library/std/src/panicking.rs:381:40 (std::panicking::r#try::do_call::<&dyn std::ops::Fn() -> i32 + std::marker::Sync + std::panic::RefUnwindSafe, i32>) -RUSTLIB/src/rust/library/std/src/panicking.rs:345:19 (std::panicking::r#try:: i32 + std::marker::Sync + std::panic::RefUnwindSafe>) -RUSTLIB/src/rust/library/std/src/panic.rs:382:14 (std::panic::catch_unwind::<&dyn std::ops::Fn() -> i32 + std::marker::Sync + std::panic::RefUnwindSafe, i32>) -RUSTLIB/src/rust/library/std/src/rt.rs:51:25 (std::rt::lang_start_internal) -RUSTLIB/src/rust/library/std/src/rt.rs:65:5 (std::rt::lang_start::<()>) +$DIR/backtrace-api.rs:18:27 (main) +RUSTLIB/src/rust/library/core/src/ops/function.rs:LL:COL (>::call_once - shim(fn())) +RUSTLIB/src/rust/library/std/src/sys_common/backtrace.rs:LL:COL (std::sys_common::backtrace::__rust_begin_short_backtrace::) +RUSTLIB/src/rust/library/std/src/rt.rs:LL:COL (std::rt::lang_start::<()>::{{closure}}#0) +RUSTLIB/src/rust/library/core/src/ops/function.rs:LL:COL (std::ops::function::impls:: for &dyn std::ops::Fn() -> i32 + std::marker::Sync + std::panic::RefUnwindSafe>::call_once) +RUSTLIB/src/rust/library/std/src/panicking.rs:LL:COL (std::panicking::r#try::do_call::<&dyn std::ops::Fn() -> i32 + std::marker::Sync + std::panic::RefUnwindSafe, i32>) +RUSTLIB/src/rust/library/std/src/panicking.rs:LL:COL (std::panicking::r#try:: i32 + std::marker::Sync + std::panic::RefUnwindSafe>) +RUSTLIB/src/rust/library/std/src/panic.rs:LL:COL (std::panic::catch_unwind::<&dyn std::ops::Fn() -> i32 + std::marker::Sync + std::panic::RefUnwindSafe, i32>) +RUSTLIB/src/rust/library/std/src/rt.rs:LL:COL (std::rt::lang_start_internal) +RUSTLIB/src/rust/library/std/src/rt.rs:LL:COL (std::rt::lang_start::<()>) From ef43c5a614fe1b9556e4291f7f11cbe0e3d9a125 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Thu, 24 Sep 2020 14:18:47 -0400 Subject: [PATCH 2325/3747] Use a 'flags' parameter instead of 'version' --- README.md | 2 +- src/shims/foreign_items.rs | 8 ++++---- tests/compile-fail/backtrace/bad-backtrace-decl.rs | 4 ++-- tests/compile-fail/backtrace/bad-backtrace-ptr.rs | 4 ++-- tests/compile-fail/backtrace/bad-backtrace-version.rs | 4 ++-- tests/run-pass/backtrace-api.rs | 4 ++-- 6 files changed, 13 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 524c8e10cf365..55d3bef727f32 100644 --- a/README.md +++ b/README.md @@ -290,7 +290,7 @@ extern "Rust" { /// /// The fields must be declared in exactly the same order as they appear in `MiriFrame` above. /// This function can be called on any thread (not just the one which obtained `frame`) - fn miri_resolve_frame(version: u8, frame: *mut ()) -> MiriFrame; + fn miri_resolve_frame(frame: *mut (), flags: u64) -> MiriFrame; /// Miri-provided extern function to begin unwinding with the given payload. /// diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 4d1ead8f0f82f..b1a02a8eb65b8 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -251,11 +251,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Resolves a Miri backtrace frame. See the README for details. "miri_resolve_frame" => { let tcx = this.tcx; - let &[version, ptr] = check_arg_count(args)?; + let &[ptr, flags] = check_arg_count(args)?; - let version = this.read_scalar(version)?.to_u8()?; - if version != 0 { - throw_ub_format!("Unknown `miri_resolve_frame` version {}", version); + let flags = this.read_scalar(flags)?.to_u64()?; + if flags != 0 { + throw_ub_format!("Unknown `miri_resolve_frame` flags {}", flags); } let ptr = match this.read_scalar(ptr)?.check_init()? { diff --git a/tests/compile-fail/backtrace/bad-backtrace-decl.rs b/tests/compile-fail/backtrace/bad-backtrace-decl.rs index 7c250fbbe3a4d..c55a1c6d38085 100644 --- a/tests/compile-fail/backtrace/bad-backtrace-decl.rs +++ b/tests/compile-fail/backtrace/bad-backtrace-decl.rs @@ -1,13 +1,13 @@ extern "Rust" { fn miri_get_backtrace() -> Box<[*mut ()]>; - fn miri_resolve_frame(version: u8, ptr: *mut ()); + fn miri_resolve_frame(ptr: *mut (), flags: u64); } fn main() { let frames = unsafe { miri_get_backtrace() }; for frame in frames.into_iter() { unsafe { - miri_resolve_frame(0, *frame); //~ ERROR Undefined Behavior: Bad declaration of miri_resolve_frame - should return a struct with 4 fields + miri_resolve_frame(*frame, 0); //~ ERROR Undefined Behavior: Bad declaration of miri_resolve_frame - should return a struct with 4 fields } } } diff --git a/tests/compile-fail/backtrace/bad-backtrace-ptr.rs b/tests/compile-fail/backtrace/bad-backtrace-ptr.rs index 49b8ac88494dc..3f672eb2dcadc 100644 --- a/tests/compile-fail/backtrace/bad-backtrace-ptr.rs +++ b/tests/compile-fail/backtrace/bad-backtrace-ptr.rs @@ -1,9 +1,9 @@ extern "Rust" { - fn miri_resolve_frame(version: u8, ptr: *mut ()); + fn miri_resolve_frame(ptr: *mut (), flags: u64); } fn main() { unsafe { - miri_resolve_frame(0, 0 as *mut _); //~ ERROR Undefined Behavior: Expected a pointer + miri_resolve_frame(0 as *mut _, 0); //~ ERROR Undefined Behavior: Expected a pointer } } diff --git a/tests/compile-fail/backtrace/bad-backtrace-version.rs b/tests/compile-fail/backtrace/bad-backtrace-version.rs index b0183ca99e942..d6743ae8fff93 100644 --- a/tests/compile-fail/backtrace/bad-backtrace-version.rs +++ b/tests/compile-fail/backtrace/bad-backtrace-version.rs @@ -1,9 +1,9 @@ extern "Rust" { - fn miri_resolve_frame(version: u8, ptr: *mut ()); + fn miri_resolve_frame(ptr: *mut (), flags: u64); } fn main() { unsafe { - miri_resolve_frame(1, 0 as *mut _); //~ ERROR Undefined Behavior: Unknown `miri_resolve_frame` version 1 + miri_resolve_frame(0 as *mut _, 1); //~ ERROR Undefined Behavior: Unknown `miri_resolve_frame` flags 1 } } diff --git a/tests/run-pass/backtrace-api.rs b/tests/run-pass/backtrace-api.rs index 51da6cf9c4dc5..231b718cd3eb9 100644 --- a/tests/run-pass/backtrace-api.rs +++ b/tests/run-pass/backtrace-api.rs @@ -3,7 +3,7 @@ extern "Rust" { fn miri_get_backtrace() -> Box<[*mut ()]>; - fn miri_resolve_frame(version: u8, ptr: *mut ()) -> MiriFrame; + fn miri_resolve_frame(ptr: *mut (), flags: u64) -> MiriFrame; } #[derive(Debug)] @@ -17,7 +17,7 @@ struct MiriFrame { fn main() { let frames = unsafe { miri_get_backtrace() }; for frame in frames.into_iter() { - let miri_frame = unsafe { miri_resolve_frame(0, *frame) }; + let miri_frame = unsafe { miri_resolve_frame(*frame, 0) }; let name = String::from_utf8(miri_frame.name.into()).unwrap(); let filename = String::from_utf8(miri_frame.filename.into()).unwrap(); eprintln!("{}:{}:{} ({})", filename, miri_frame.lineno, miri_frame.colno, name); From 9fc384fcf9e8d028aec1dd11da15c702667e4205 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Thu, 24 Sep 2020 15:05:50 -0400 Subject: [PATCH 2326/3747] Print non-std frames to stdout in `backtrace-api` test --- tests/run-pass/backtrace-api.rs | 18 ++++++++++++++++-- tests/run-pass/backtrace-api.stderr | 5 ++++- tests/run-pass/backtrace-api.stdout | 4 ++++ 3 files changed, 24 insertions(+), 3 deletions(-) create mode 100644 tests/run-pass/backtrace-api.stdout diff --git a/tests/run-pass/backtrace-api.rs b/tests/run-pass/backtrace-api.rs index 231b718cd3eb9..73a3f6242d5b8 100644 --- a/tests/run-pass/backtrace-api.rs +++ b/tests/run-pass/backtrace-api.rs @@ -14,12 +14,26 @@ struct MiriFrame { colno: u32 } +fn func_a() -> Box<[*mut ()]> { func_b::() } +fn func_b() -> Box<[*mut ()]> { func_c() } +fn func_c() -> Box<[*mut ()]> { unsafe { miri_get_backtrace() } } + fn main() { - let frames = unsafe { miri_get_backtrace() }; + let mut seen_main = false; + let frames = func_a(); for frame in frames.into_iter() { let miri_frame = unsafe { miri_resolve_frame(*frame, 0) }; let name = String::from_utf8(miri_frame.name.into()).unwrap(); let filename = String::from_utf8(miri_frame.filename.into()).unwrap(); - eprintln!("{}:{}:{} ({})", filename, miri_frame.lineno, miri_frame.colno, name); + + // Print every frame to stderr. + let out = format!("{}:{}:{} ({})", filename, miri_frame.lineno, miri_frame.colno, name); + eprintln!("{}", out); + // Print the 'main' frame (and everything before it) to stdout, skipping + // the printing of internal (and possibly fragile) libstd frames. + if !seen_main { + println!("{}", out); + seen_main = name == "main"; + } } } diff --git a/tests/run-pass/backtrace-api.stderr b/tests/run-pass/backtrace-api.stderr index 042ca843d0e12..b96def8093a44 100644 --- a/tests/run-pass/backtrace-api.stderr +++ b/tests/run-pass/backtrace-api.stderr @@ -1,4 +1,7 @@ -$DIR/backtrace-api.rs:18:27 (main) +$DIR/backtrace-api.rs:19:42 (func_c) +$DIR/backtrace-api.rs:18:36 (func_b::) +$DIR/backtrace-api.rs:17:33 (func_a) +$DIR/backtrace-api.rs:23:18 (main) RUSTLIB/src/rust/library/core/src/ops/function.rs:LL:COL (>::call_once - shim(fn())) RUSTLIB/src/rust/library/std/src/sys_common/backtrace.rs:LL:COL (std::sys_common::backtrace::__rust_begin_short_backtrace::) RUSTLIB/src/rust/library/std/src/rt.rs:LL:COL (std::rt::lang_start::<()>::{{closure}}#0) diff --git a/tests/run-pass/backtrace-api.stdout b/tests/run-pass/backtrace-api.stdout new file mode 100644 index 0000000000000..0d8aaa7a3261c --- /dev/null +++ b/tests/run-pass/backtrace-api.stdout @@ -0,0 +1,4 @@ +$DIR/backtrace-api.rs:19:42 (func_c) +$DIR/backtrace-api.rs:18:36 (func_b::) +$DIR/backtrace-api.rs:17:33 (func_a) +$DIR/backtrace-api.rs:23:18 (main) From b89f6561e52d458522e640ef5777126c410fd4ca Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Thu, 24 Sep 2020 18:52:17 -0400 Subject: [PATCH 2327/3747] Move things around --- src/shims/backtrace.rs | 110 ++++++++++++++++++ src/shims/foreign_items.rs | 81 +------------ src/shims/mod.rs | 2 +- .../backtrace/bad-backtrace-decl.rs | 4 +- .../backtrace/bad-backtrace-version.rs | 2 +- tests/run-pass/backtrace-api.rs | 4 +- 6 files changed, 120 insertions(+), 83 deletions(-) create mode 100644 src/shims/backtrace.rs diff --git a/src/shims/backtrace.rs b/src/shims/backtrace.rs new file mode 100644 index 0000000000000..2b360cb85a6eb --- /dev/null +++ b/src/shims/backtrace.rs @@ -0,0 +1,110 @@ +use crate::*; +use helpers::check_arg_count; +use rustc_middle::ty::TypeAndMut; +use rustc_ast::ast::Mutability; +use rustc_span::BytePos; +use rustc_target::abi::Size; +use std::convert::TryInto as _; +use crate::rustc_target::abi::LayoutOf as _; + +impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} +pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { + + fn handle_miri_get_backtrace( + &mut self, + args: &[OpTy<'tcx, Tag>], + dest: PlaceTy<'tcx, Tag> + ) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + let tcx = this.tcx; + let &[flags] = check_arg_count(args)?; + + let flags = this.read_scalar(flags)?.to_u64()?; + if flags != 0 { + throw_unsup_format!("unknown `miri_get_backtrace` flags {}", flags); + } + + let mut data = Vec::new(); + for frame in this.active_thread_stack().iter().rev() { + data.push((frame.instance, frame.current_span().lo())); + } + + let ptrs: Vec<_> = data.into_iter().map(|(instance, pos)| { + let mut fn_ptr = this.memory.create_fn_alloc(FnVal::Instance(instance)); + fn_ptr.offset = Size::from_bytes(pos.0); + Scalar::Ptr(fn_ptr) + }).collect(); + + let len = ptrs.len(); + + let ptr_ty = tcx.mk_ptr(TypeAndMut { + ty: tcx.types.unit, + mutbl: Mutability::Mut + }); + + let array_ty = tcx.mk_array(ptr_ty, ptrs.len().try_into().unwrap()); + + // Write pointers into array + let alloc = this.allocate(this.layout_of(array_ty).unwrap(), MiriMemoryKind::Rust.into()); + for (i, ptr) in ptrs.into_iter().enumerate() { + let place = this.mplace_index(alloc, i as u64)?; + this.write_immediate_to_mplace(ptr.into(), place)?; + } + + this.write_immediate(Immediate::new_slice(alloc.ptr.into(), len.try_into().unwrap(), this), dest)?; + Ok(()) + } + + fn handle_miri_resolve_frame( + &mut self, + args: &[OpTy<'tcx, Tag>], + dest: PlaceTy<'tcx, Tag> + ) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + let tcx = this.tcx; + let &[ptr, flags] = check_arg_count(args)?; + + let flags = this.read_scalar(flags)?.to_u64()?; + if flags != 0 { + throw_unsup_format!("unknown `miri_resolve_frame` flags {}", flags); + } + + let ptr = match this.read_scalar(ptr)?.check_init()? { + Scalar::Ptr(ptr) => ptr, + Scalar::Raw { .. } => throw_ub_format!("Expected a pointer in `rust_miri_resolve_frame`, found {:?}", ptr) + }; + + let fn_instance = if let Some(GlobalAlloc::Function(instance)) = this.tcx.get_global_alloc(ptr.alloc_id) { + instance + } else { + throw_ub_format!("expected function pointer, found {:?}", ptr); + }; + + if dest.layout.layout.fields.count() != 4 { + throw_ub_format!("Bad declaration of miri_resolve_frame - should return a struct with 4 fields"); + } + + let pos = BytePos(ptr.offset.bytes().try_into().unwrap()); + let name = fn_instance.to_string(); + + let lo = tcx.sess.source_map().lookup_char_pos(pos); + + let filename = lo.file.name.to_string(); + let lineno: u32 = lo.line as u32; + // `lo.col` is 0-based - add 1 to make it 1-based for the caller. + let colno: u32 = lo.col.0 as u32 + 1; + + let name_alloc = this.allocate_str(&name, MiriMemoryKind::Rust.into()); + let filename_alloc = this.allocate_str(&filename, MiriMemoryKind::Rust.into()); + let lineno_alloc = Scalar::from_u32(lineno); + let colno_alloc = Scalar::from_u32(colno); + + let dest = this.force_allocation_maybe_sized(dest, MemPlaceMeta::None)?.0; + + this.write_immediate(name_alloc.to_ref(), this.mplace_field(dest, 0)?.into())?; + this.write_immediate(filename_alloc.to_ref(), this.mplace_field(dest, 1)?.into())?; + this.write_scalar(lineno_alloc, this.mplace_field(dest, 2)?.into())?; + this.write_scalar(colno_alloc, this.mplace_field(dest, 3)?.into())?; + Ok(()) + } +} diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index b1a02a8eb65b8..7118fbda2403a 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -5,13 +5,12 @@ use log::trace; use rustc_hir::def_id::DefId; use rustc_middle::mir; use rustc_target::{abi::{Align, Size}, spec::PanicStrategy}; -use rustc_middle::ty::{self, ParamEnv, TypeAndMut}; -use rustc_ast::ast::Mutability; +use rustc_middle::ty; use rustc_apfloat::Float; use rustc_span::symbol::sym; -use rustc_span::BytePos; use crate::*; +use super::backtrace::EvalContextExt as _; use helpers::check_arg_count; impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} @@ -216,84 +215,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Obtains a Miri backtrace. See the README for details. "miri_get_backtrace" => { - let tcx = this.tcx; - let mut data = Vec::new(); - for frame in this.active_thread_stack().iter().rev() { - data.push((frame.instance, frame.current_span().lo())); - } - - let ptrs: Vec<_> = data.into_iter().map(|(instance, pos)| { - let mut fn_ptr = this.memory.create_fn_alloc(FnVal::Instance(instance)); - fn_ptr.offset = Size::from_bytes(pos.0); - Scalar::Ptr(fn_ptr) - }).collect(); - - let len = ptrs.len(); - - let ptr_ty = tcx.mk_ptr(TypeAndMut { - ty: tcx.types.unit, - mutbl: Mutability::Mut - }); - - let array_ty = tcx.mk_array(ptr_ty, ptrs.len().try_into().unwrap()); - let array_ty_and_env = ParamEnv::empty().and(array_ty); - - // Write pointers into array - let alloc = this.allocate(tcx.layout_of(array_ty_and_env).unwrap(), MiriMemoryKind::Rust.into()); - for (i, ptr) in ptrs.into_iter().enumerate() { - let place = this.mplace_index(alloc, i as u64)?; - this.write_immediate_to_mplace(ptr.into(), place)?; - } - - this.write_immediate(Immediate::new_slice(alloc.ptr.into(), len.try_into().unwrap(), this), dest)?; + this.handle_miri_get_backtrace(args, dest)?; } // Resolves a Miri backtrace frame. See the README for details. "miri_resolve_frame" => { - let tcx = this.tcx; - let &[ptr, flags] = check_arg_count(args)?; - - let flags = this.read_scalar(flags)?.to_u64()?; - if flags != 0 { - throw_ub_format!("Unknown `miri_resolve_frame` flags {}", flags); - } - - let ptr = match this.read_scalar(ptr)?.check_init()? { - Scalar::Ptr(ptr) => ptr, - Scalar::Raw { .. } => throw_ub_format!("Expected a pointer in `rust_miri_resolve_frame`, found {:?}", ptr) - }; - - let fn_instance = if let Some(GlobalAlloc::Function(instance)) = this.tcx.get_global_alloc(ptr.alloc_id) { - instance - } else { - throw_ub_format!("Expect function pointer, found {:?}", ptr); - }; - - if dest.layout.layout.fields.count() != 4 { - throw_ub_format!("Bad declaration of miri_resolve_frame - should return a struct with 4 fields"); - } - - let pos = BytePos(ptr.offset.bytes().try_into().unwrap()); - let name = fn_instance.to_string(); - - let lo = tcx.sess.source_map().lookup_char_pos(pos); - - let filename = lo.file.name.to_string(); - let lineno: u32 = lo.line as u32; - // `lo.col` is 0-based - add 1 to make it 1-based for the caller. - let colno: u32 = lo.col.0 as u32 + 1; - - let name_alloc = this.allocate_str(&name, MiriMemoryKind::Rust.into()); - let filename_alloc = this.allocate_str(&filename, MiriMemoryKind::Rust.into()); - let lineno_alloc = Scalar::from_u32(lineno); - let colno_alloc = Scalar::from_u32(colno); - - let dest = this.force_allocation_maybe_sized(dest, MemPlaceMeta::None)?.0; - - this.write_immediate(name_alloc.to_ref(), this.mplace_field(dest, 0)?.into())?; - this.write_immediate(filename_alloc.to_ref(), this.mplace_field(dest, 1)?.into())?; - this.write_scalar(lineno_alloc, this.mplace_field(dest, 2)?.into())?; - this.write_scalar(colno_alloc, this.mplace_field(dest, 3)?.into())?; + this.handle_miri_resolve_frame(args, dest)?; } diff --git a/src/shims/mod.rs b/src/shims/mod.rs index eab27496cb286..90dcc4d8ff1e4 100644 --- a/src/shims/mod.rs +++ b/src/shims/mod.rs @@ -1,4 +1,4 @@ - +mod backtrace; pub mod foreign_items; pub mod intrinsics; pub mod posix; diff --git a/tests/compile-fail/backtrace/bad-backtrace-decl.rs b/tests/compile-fail/backtrace/bad-backtrace-decl.rs index c55a1c6d38085..bccc7063af719 100644 --- a/tests/compile-fail/backtrace/bad-backtrace-decl.rs +++ b/tests/compile-fail/backtrace/bad-backtrace-decl.rs @@ -1,10 +1,10 @@ extern "Rust" { - fn miri_get_backtrace() -> Box<[*mut ()]>; + fn miri_get_backtrace(flags: u64) -> Box<[*mut ()]>; fn miri_resolve_frame(ptr: *mut (), flags: u64); } fn main() { - let frames = unsafe { miri_get_backtrace() }; + let frames = unsafe { miri_get_backtrace(0) }; for frame in frames.into_iter() { unsafe { miri_resolve_frame(*frame, 0); //~ ERROR Undefined Behavior: Bad declaration of miri_resolve_frame - should return a struct with 4 fields diff --git a/tests/compile-fail/backtrace/bad-backtrace-version.rs b/tests/compile-fail/backtrace/bad-backtrace-version.rs index d6743ae8fff93..4579b5d0ade89 100644 --- a/tests/compile-fail/backtrace/bad-backtrace-version.rs +++ b/tests/compile-fail/backtrace/bad-backtrace-version.rs @@ -4,6 +4,6 @@ extern "Rust" { fn main() { unsafe { - miri_resolve_frame(0 as *mut _, 1); //~ ERROR Undefined Behavior: Unknown `miri_resolve_frame` flags 1 + miri_resolve_frame(0 as *mut _, 1); //~ ERROR unsupported operation: unknown `miri_resolve_frame` flags 1 } } diff --git a/tests/run-pass/backtrace-api.rs b/tests/run-pass/backtrace-api.rs index 73a3f6242d5b8..655a52c7fc7d0 100644 --- a/tests/run-pass/backtrace-api.rs +++ b/tests/run-pass/backtrace-api.rs @@ -2,7 +2,7 @@ // normalize-stderr-test "RUSTLIB/(.*):\d+:\d+ "-> "RUSTLIB/$1:LL:COL " extern "Rust" { - fn miri_get_backtrace() -> Box<[*mut ()]>; + fn miri_get_backtrace(flags: u64) -> Box<[*mut ()]>; fn miri_resolve_frame(ptr: *mut (), flags: u64) -> MiriFrame; } @@ -16,7 +16,7 @@ struct MiriFrame { fn func_a() -> Box<[*mut ()]> { func_b::() } fn func_b() -> Box<[*mut ()]> { func_c() } -fn func_c() -> Box<[*mut ()]> { unsafe { miri_get_backtrace() } } +fn func_c() -> Box<[*mut ()]> { unsafe { miri_get_backtrace(0) } } fn main() { let mut seen_main = false; From f756e3a93f53d72eceb2367a36f91b7f809752d6 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Thu, 24 Sep 2020 19:06:39 -0400 Subject: [PATCH 2328/3747] Explain encoding scheme --- src/shims/backtrace.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/shims/backtrace.rs b/src/shims/backtrace.rs index 2b360cb85a6eb..2c031f179d08e 100644 --- a/src/shims/backtrace.rs +++ b/src/shims/backtrace.rs @@ -30,6 +30,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } let ptrs: Vec<_> = data.into_iter().map(|(instance, pos)| { + // We represent a frame pointer by using the `span.lo` value + // as an offset into the function's allocation. This gives us an + // opaque pointer that we can return to user code, and allows us + // to reconstruct the needed frame information in `handle_miri_resolve_frame`. + // Note that we never actually read or write anything from/to this pointer - + // all of the data is represented by the pointer value itself. let mut fn_ptr = this.memory.create_fn_alloc(FnVal::Instance(instance)); fn_ptr.offset = Size::from_bytes(pos.0); Scalar::Ptr(fn_ptr) From e1bce19ca953873dc9ff90d2fede9e35449dc2ea Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Thu, 24 Sep 2020 19:10:02 -0400 Subject: [PATCH 2329/3747] Make some error messages lowercase --- src/shims/backtrace.rs | 4 ++-- tests/compile-fail/backtrace/bad-backtrace-decl.rs | 2 +- tests/compile-fail/backtrace/bad-backtrace-ptr.rs | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/shims/backtrace.rs b/src/shims/backtrace.rs index 2c031f179d08e..57d59dd4c098b 100644 --- a/src/shims/backtrace.rs +++ b/src/shims/backtrace.rs @@ -77,7 +77,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let ptr = match this.read_scalar(ptr)?.check_init()? { Scalar::Ptr(ptr) => ptr, - Scalar::Raw { .. } => throw_ub_format!("Expected a pointer in `rust_miri_resolve_frame`, found {:?}", ptr) + Scalar::Raw { .. } => throw_ub_format!("expected a pointer in `rust_miri_resolve_frame`, found {:?}", ptr) }; let fn_instance = if let Some(GlobalAlloc::Function(instance)) = this.tcx.get_global_alloc(ptr.alloc_id) { @@ -87,7 +87,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx }; if dest.layout.layout.fields.count() != 4 { - throw_ub_format!("Bad declaration of miri_resolve_frame - should return a struct with 4 fields"); + throw_ub_format!("bad declaration of miri_resolve_frame - should return a struct with 4 fields"); } let pos = BytePos(ptr.offset.bytes().try_into().unwrap()); diff --git a/tests/compile-fail/backtrace/bad-backtrace-decl.rs b/tests/compile-fail/backtrace/bad-backtrace-decl.rs index bccc7063af719..b9f1c779ae232 100644 --- a/tests/compile-fail/backtrace/bad-backtrace-decl.rs +++ b/tests/compile-fail/backtrace/bad-backtrace-decl.rs @@ -7,7 +7,7 @@ fn main() { let frames = unsafe { miri_get_backtrace(0) }; for frame in frames.into_iter() { unsafe { - miri_resolve_frame(*frame, 0); //~ ERROR Undefined Behavior: Bad declaration of miri_resolve_frame - should return a struct with 4 fields + miri_resolve_frame(*frame, 0); //~ ERROR Undefined Behavior: bad declaration of miri_resolve_frame - should return a struct with 4 fields } } } diff --git a/tests/compile-fail/backtrace/bad-backtrace-ptr.rs b/tests/compile-fail/backtrace/bad-backtrace-ptr.rs index 3f672eb2dcadc..5e245952e9b24 100644 --- a/tests/compile-fail/backtrace/bad-backtrace-ptr.rs +++ b/tests/compile-fail/backtrace/bad-backtrace-ptr.rs @@ -4,6 +4,6 @@ extern "Rust" { fn main() { unsafe { - miri_resolve_frame(0 as *mut _, 0); //~ ERROR Undefined Behavior: Expected a pointer + miri_resolve_frame(0 as *mut _, 0); //~ ERROR Undefined Behavior: expected a pointer } } From 11e2dbd51c3241d890c8a980a011c0fa3e099011 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Thu, 24 Sep 2020 19:10:09 -0400 Subject: [PATCH 2330/3747] Update README --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 55d3bef727f32..1ebacfc26bef0 100644 --- a/README.md +++ b/README.md @@ -269,10 +269,11 @@ extern "Rust" { /// Miri-provided extern function to obtain a backtrace of the current call stack. /// This returns a boxed slice of pointers - each pointer is an opaque value /// that is only useful when passed to `miri_resolve_frame` - fn miri_get_backtrace() -> Box<[*mut ()]>; + /// The `flags` argument must be `0`. + fn miri_get_backtrace(flags: u64) -> Box<[*mut ()]>; /// Miri-provided extern function to resolve a frame pointer obtained - /// from `miri_get_backtrace`. The `version` argument must be `0`, + /// from `miri_get_backtrace`. The `flags` argument must be `0`, /// and `MiriFrame` should be declared as follows: /// /// ```rust From dba7f135495a4358472bac6c2704703e957ac68d Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Thu, 24 Sep 2020 23:00:32 -0400 Subject: [PATCH 2331/3747] Apply #[inline(never)] to functions that we want in the backtrace --- tests/run-pass/backtrace-api.rs | 6 +++--- tests/run-pass/backtrace-api.stderr | 6 +++--- tests/run-pass/backtrace-api.stdout | 6 +++--- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/tests/run-pass/backtrace-api.rs b/tests/run-pass/backtrace-api.rs index 655a52c7fc7d0..1322e15fc9624 100644 --- a/tests/run-pass/backtrace-api.rs +++ b/tests/run-pass/backtrace-api.rs @@ -14,9 +14,9 @@ struct MiriFrame { colno: u32 } -fn func_a() -> Box<[*mut ()]> { func_b::() } -fn func_b() -> Box<[*mut ()]> { func_c() } -fn func_c() -> Box<[*mut ()]> { unsafe { miri_get_backtrace(0) } } +#[inline(never)] fn func_a() -> Box<[*mut ()]> { func_b::() } +#[inline(never)] fn func_b() -> Box<[*mut ()]> { func_c() } +#[inline(never)] fn func_c() -> Box<[*mut ()]> { unsafe { miri_get_backtrace(0) } } fn main() { let mut seen_main = false; diff --git a/tests/run-pass/backtrace-api.stderr b/tests/run-pass/backtrace-api.stderr index b96def8093a44..d94a7ce4aec22 100644 --- a/tests/run-pass/backtrace-api.stderr +++ b/tests/run-pass/backtrace-api.stderr @@ -1,6 +1,6 @@ -$DIR/backtrace-api.rs:19:42 (func_c) -$DIR/backtrace-api.rs:18:36 (func_b::) -$DIR/backtrace-api.rs:17:33 (func_a) +$DIR/backtrace-api.rs:19:59 (func_c) +$DIR/backtrace-api.rs:18:53 (func_b::) +$DIR/backtrace-api.rs:17:50 (func_a) $DIR/backtrace-api.rs:23:18 (main) RUSTLIB/src/rust/library/core/src/ops/function.rs:LL:COL (>::call_once - shim(fn())) RUSTLIB/src/rust/library/std/src/sys_common/backtrace.rs:LL:COL (std::sys_common::backtrace::__rust_begin_short_backtrace::) diff --git a/tests/run-pass/backtrace-api.stdout b/tests/run-pass/backtrace-api.stdout index 0d8aaa7a3261c..0353f98ed76a4 100644 --- a/tests/run-pass/backtrace-api.stdout +++ b/tests/run-pass/backtrace-api.stdout @@ -1,4 +1,4 @@ -$DIR/backtrace-api.rs:19:42 (func_c) -$DIR/backtrace-api.rs:18:36 (func_b::) -$DIR/backtrace-api.rs:17:33 (func_a) +$DIR/backtrace-api.rs:19:59 (func_c) +$DIR/backtrace-api.rs:18:53 (func_b::) +$DIR/backtrace-api.rs:17:50 (func_a) $DIR/backtrace-api.rs:23:18 (main) From 5571bcfc4fd3e986027e537ed57a4c4321af53ec Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Sat, 26 Sep 2020 14:40:41 -0400 Subject: [PATCH 2332/3747] Require #[repr(C)] on MiriFrame --- README.md | 1 + src/shims/backtrace.rs | 9 +++++++-- tests/run-pass/backtrace-api.rs | 1 + tests/run-pass/backtrace-api.stderr | 8 ++++---- tests/run-pass/backtrace-api.stdout | 8 ++++---- 5 files changed, 17 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 1ebacfc26bef0..b84102598c155 100644 --- a/README.md +++ b/README.md @@ -277,6 +277,7 @@ extern "Rust" { /// and `MiriFrame` should be declared as follows: /// /// ```rust + /// #[repr(C)] /// struct MiriFrame { /// // The name of the function being executed, encoded in UTF-8 /// name: Box<[u8]>, diff --git a/src/shims/backtrace.rs b/src/shims/backtrace.rs index 57d59dd4c098b..75cd61b0f59e7 100644 --- a/src/shims/backtrace.rs +++ b/src/shims/backtrace.rs @@ -1,6 +1,6 @@ use crate::*; use helpers::check_arg_count; -use rustc_middle::ty::TypeAndMut; +use rustc_middle::ty::{self, TypeAndMut}; use rustc_ast::ast::Mutability; use rustc_span::BytePos; use rustc_target::abi::Size; @@ -105,7 +105,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let lineno_alloc = Scalar::from_u32(lineno); let colno_alloc = Scalar::from_u32(colno); - let dest = this.force_allocation_maybe_sized(dest, MemPlaceMeta::None)?.0; + let dest = this.force_allocation(dest)?; + if let ty::Adt(adt, _) = dest.layout.ty.kind() { + if !adt.repr.c() { + throw_ub_format!("miri_resolve_frame must be declared with a `#[repr(C)]` return type"); + } + } this.write_immediate(name_alloc.to_ref(), this.mplace_field(dest, 0)?.into())?; this.write_immediate(filename_alloc.to_ref(), this.mplace_field(dest, 1)?.into())?; diff --git a/tests/run-pass/backtrace-api.rs b/tests/run-pass/backtrace-api.rs index 1322e15fc9624..a58fb83d92f76 100644 --- a/tests/run-pass/backtrace-api.rs +++ b/tests/run-pass/backtrace-api.rs @@ -7,6 +7,7 @@ extern "Rust" { } #[derive(Debug)] +#[repr(C)] struct MiriFrame { name: Box<[u8]>, filename: Box<[u8]>, diff --git a/tests/run-pass/backtrace-api.stderr b/tests/run-pass/backtrace-api.stderr index d94a7ce4aec22..92c5331d6143a 100644 --- a/tests/run-pass/backtrace-api.stderr +++ b/tests/run-pass/backtrace-api.stderr @@ -1,7 +1,7 @@ -$DIR/backtrace-api.rs:19:59 (func_c) -$DIR/backtrace-api.rs:18:53 (func_b::) -$DIR/backtrace-api.rs:17:50 (func_a) -$DIR/backtrace-api.rs:23:18 (main) +$DIR/backtrace-api.rs:20:59 (func_c) +$DIR/backtrace-api.rs:19:53 (func_b::) +$DIR/backtrace-api.rs:18:50 (func_a) +$DIR/backtrace-api.rs:24:18 (main) RUSTLIB/src/rust/library/core/src/ops/function.rs:LL:COL (>::call_once - shim(fn())) RUSTLIB/src/rust/library/std/src/sys_common/backtrace.rs:LL:COL (std::sys_common::backtrace::__rust_begin_short_backtrace::) RUSTLIB/src/rust/library/std/src/rt.rs:LL:COL (std::rt::lang_start::<()>::{{closure}}#0) diff --git a/tests/run-pass/backtrace-api.stdout b/tests/run-pass/backtrace-api.stdout index 0353f98ed76a4..e4130ade62e08 100644 --- a/tests/run-pass/backtrace-api.stdout +++ b/tests/run-pass/backtrace-api.stdout @@ -1,4 +1,4 @@ -$DIR/backtrace-api.rs:19:59 (func_c) -$DIR/backtrace-api.rs:18:53 (func_b::) -$DIR/backtrace-api.rs:17:50 (func_a) -$DIR/backtrace-api.rs:23:18 (main) +$DIR/backtrace-api.rs:20:59 (func_c) +$DIR/backtrace-api.rs:19:53 (func_b::) +$DIR/backtrace-api.rs:18:50 (func_a) +$DIR/backtrace-api.rs:24:18 (main) From b1837d0bc9b8bab3bada98c655b39055fc5d8750 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 28 Sep 2020 19:34:18 +0200 Subject: [PATCH 2333/3747] fix typo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index b84102598c155..2b015104828e9 100644 --- a/README.md +++ b/README.md @@ -291,7 +291,7 @@ extern "Rust" { /// ``` /// /// The fields must be declared in exactly the same order as they appear in `MiriFrame` above. - /// This function can be called on any thread (not just the one which obtained `frame`) + /// This function can be called on any thread (not just the one which obtained `frame`). fn miri_resolve_frame(frame: *mut (), flags: u64) -> MiriFrame; /// Miri-provided extern function to begin unwinding with the given payload. From 7fba3c2cf2058519b784de59605804899e0fe670 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Mon, 28 Sep 2020 13:55:23 -0400 Subject: [PATCH 2334/3747] Normalize out generic arguments in backtrace-api stderr --- tests/run-pass/backtrace-api.rs | 1 + tests/run-pass/backtrace-api.stderr | 22 +++++++++++----------- tests/run-pass/backtrace-api.stdout | 8 ++++---- 3 files changed, 16 insertions(+), 15 deletions(-) diff --git a/tests/run-pass/backtrace-api.rs b/tests/run-pass/backtrace-api.rs index a58fb83d92f76..be1971efe28dd 100644 --- a/tests/run-pass/backtrace-api.rs +++ b/tests/run-pass/backtrace-api.rs @@ -1,5 +1,6 @@ // normalize-stderr-test ".*rustlib" -> "RUSTLIB" // normalize-stderr-test "RUSTLIB/(.*):\d+:\d+ "-> "RUSTLIB/$1:LL:COL " +// normalize-stderr-test "::<.*>" -> "" extern "Rust" { fn miri_get_backtrace(flags: u64) -> Box<[*mut ()]>; diff --git a/tests/run-pass/backtrace-api.stderr b/tests/run-pass/backtrace-api.stderr index 92c5331d6143a..ea25267a1b148 100644 --- a/tests/run-pass/backtrace-api.stderr +++ b/tests/run-pass/backtrace-api.stderr @@ -1,13 +1,13 @@ -$DIR/backtrace-api.rs:20:59 (func_c) -$DIR/backtrace-api.rs:19:53 (func_b::) -$DIR/backtrace-api.rs:18:50 (func_a) -$DIR/backtrace-api.rs:24:18 (main) +$DIR/backtrace-api.rs:21:59 (func_c) +$DIR/backtrace-api.rs:20:53 (func_b) +$DIR/backtrace-api.rs:19:50 (func_a) +$DIR/backtrace-api.rs:25:18 (main) RUSTLIB/src/rust/library/core/src/ops/function.rs:LL:COL (>::call_once - shim(fn())) -RUSTLIB/src/rust/library/std/src/sys_common/backtrace.rs:LL:COL (std::sys_common::backtrace::__rust_begin_short_backtrace::) -RUSTLIB/src/rust/library/std/src/rt.rs:LL:COL (std::rt::lang_start::<()>::{{closure}}#0) -RUSTLIB/src/rust/library/core/src/ops/function.rs:LL:COL (std::ops::function::impls:: for &dyn std::ops::Fn() -> i32 + std::marker::Sync + std::panic::RefUnwindSafe>::call_once) -RUSTLIB/src/rust/library/std/src/panicking.rs:LL:COL (std::panicking::r#try::do_call::<&dyn std::ops::Fn() -> i32 + std::marker::Sync + std::panic::RefUnwindSafe, i32>) -RUSTLIB/src/rust/library/std/src/panicking.rs:LL:COL (std::panicking::r#try:: i32 + std::marker::Sync + std::panic::RefUnwindSafe>) -RUSTLIB/src/rust/library/std/src/panic.rs:LL:COL (std::panic::catch_unwind::<&dyn std::ops::Fn() -> i32 + std::marker::Sync + std::panic::RefUnwindSafe, i32>) +RUSTLIB/src/rust/library/std/src/sys_common/backtrace.rs:LL:COL (std::sys_common::backtrace::__rust_begin_short_backtrace) +RUSTLIB/src/rust/library/std/src/rt.rs:LL:COL (std::rt::lang_start::{closure#0}) +RUSTLIB/src/rust/library/core/src/ops/function.rs:LL:COL (std::ops::function::impls::call_once) +RUSTLIB/src/rust/library/std/src/panicking.rs:LL:COL (std::panicking::r#try::do_call) +RUSTLIB/src/rust/library/std/src/panicking.rs:LL:COL (std::panicking::r#try) +RUSTLIB/src/rust/library/std/src/panic.rs:LL:COL (std::panic::catch_unwind) RUSTLIB/src/rust/library/std/src/rt.rs:LL:COL (std::rt::lang_start_internal) -RUSTLIB/src/rust/library/std/src/rt.rs:LL:COL (std::rt::lang_start::<()>) +RUSTLIB/src/rust/library/std/src/rt.rs:LL:COL (std::rt::lang_start) diff --git a/tests/run-pass/backtrace-api.stdout b/tests/run-pass/backtrace-api.stdout index e4130ade62e08..453cf0b774a10 100644 --- a/tests/run-pass/backtrace-api.stdout +++ b/tests/run-pass/backtrace-api.stdout @@ -1,4 +1,4 @@ -$DIR/backtrace-api.rs:20:59 (func_c) -$DIR/backtrace-api.rs:19:53 (func_b::) -$DIR/backtrace-api.rs:18:50 (func_a) -$DIR/backtrace-api.rs:24:18 (main) +$DIR/backtrace-api.rs:21:59 (func_c) +$DIR/backtrace-api.rs:20:53 (func_b::) +$DIR/backtrace-api.rs:19:50 (func_a) +$DIR/backtrace-api.rs:25:18 (main) From eaf56c57e55503a3aa47333aac73162de6049a51 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 29 Sep 2020 10:31:41 +0200 Subject: [PATCH 2335/3747] rustup; adjust for rustc_driver changes --- benches/helpers/miri_helper.rs | 2 +- rust-version | 2 +- src/bin/miri-rustc-tests.rs | 1 + src/bin/miri.rs | 2 +- 4 files changed, 4 insertions(+), 3 deletions(-) diff --git a/benches/helpers/miri_helper.rs b/benches/helpers/miri_helper.rs index 2e71c7eb8b1d5..a77f914c1c6bf 100644 --- a/benches/helpers/miri_helper.rs +++ b/benches/helpers/miri_helper.rs @@ -55,5 +55,5 @@ pub fn run(filename: &str, bencher: &mut Bencher) { "--sysroot".to_string(), find_sysroot(), ]; - rustc_driver::run_compiler(args, &mut MiriCompilerCalls { bencher }, None, None).unwrap() + rustc_driver::run_compiler(args, &mut MiriCompilerCalls { bencher }, None, None, None).unwrap() } diff --git a/rust-version b/rust-version index 362f89b5d1fee..049d0f2c87822 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -1ec980d225fff2346a1a631a7ffc88b37e9e18af +26373fb4baa9c5b8a7a1e2821fcfa930a85d327d diff --git a/src/bin/miri-rustc-tests.rs b/src/bin/miri-rustc-tests.rs index 56d19e62749ea..7c9dfbb277b95 100644 --- a/src/bin/miri-rustc-tests.rs +++ b/src/bin/miri-rustc-tests.rs @@ -145,6 +145,7 @@ fn main() { &mut MiriCompilerCalls { host_target }, None, Some(Box::new(buf)), + None, ); }); diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 4363f9a150a78..e3317d0d4d680 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -157,7 +157,7 @@ fn run_compiler(mut args: Vec, callbacks: &mut (dyn rustc_driver::Callba // Invoke compiler, and handle return code. let exit_code = rustc_driver::catch_with_exit_code(move || { - rustc_driver::run_compiler(&args, callbacks, None, None) + rustc_driver::run_compiler(&args, callbacks, None, None, None) }); std::process::exit(exit_code) } From 17e16aad62ad06ea1f8bc1bac81c73528f48a3d3 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 30 Sep 2020 09:59:28 +0200 Subject: [PATCH 2336/3747] normalize backtrace stderr even more --- rust-version | 2 +- tests/run-pass/backtrace-api.rs | 2 +- tests/run-pass/backtrace-api.stderr | 18 +++++++++--------- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/rust-version b/rust-version index 049d0f2c87822..1b85e41c8ba28 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -26373fb4baa9c5b8a7a1e2821fcfa930a85d327d +c0127e4dbf3a9d3a67ddb1da19f8441019aab8f8 diff --git a/tests/run-pass/backtrace-api.rs b/tests/run-pass/backtrace-api.rs index be1971efe28dd..80e64c2e1c8ba 100644 --- a/tests/run-pass/backtrace-api.rs +++ b/tests/run-pass/backtrace-api.rs @@ -1,4 +1,4 @@ -// normalize-stderr-test ".*rustlib" -> "RUSTLIB" +// normalize-stderr-test ".*/(rust|checkout)/library/" -> "RUSTLIB/" // normalize-stderr-test "RUSTLIB/(.*):\d+:\d+ "-> "RUSTLIB/$1:LL:COL " // normalize-stderr-test "::<.*>" -> "" diff --git a/tests/run-pass/backtrace-api.stderr b/tests/run-pass/backtrace-api.stderr index ea25267a1b148..15851a1cc7257 100644 --- a/tests/run-pass/backtrace-api.stderr +++ b/tests/run-pass/backtrace-api.stderr @@ -2,12 +2,12 @@ $DIR/backtrace-api.rs:21:59 (func_c) $DIR/backtrace-api.rs:20:53 (func_b) $DIR/backtrace-api.rs:19:50 (func_a) $DIR/backtrace-api.rs:25:18 (main) -RUSTLIB/src/rust/library/core/src/ops/function.rs:LL:COL (>::call_once - shim(fn())) -RUSTLIB/src/rust/library/std/src/sys_common/backtrace.rs:LL:COL (std::sys_common::backtrace::__rust_begin_short_backtrace) -RUSTLIB/src/rust/library/std/src/rt.rs:LL:COL (std::rt::lang_start::{closure#0}) -RUSTLIB/src/rust/library/core/src/ops/function.rs:LL:COL (std::ops::function::impls::call_once) -RUSTLIB/src/rust/library/std/src/panicking.rs:LL:COL (std::panicking::r#try::do_call) -RUSTLIB/src/rust/library/std/src/panicking.rs:LL:COL (std::panicking::r#try) -RUSTLIB/src/rust/library/std/src/panic.rs:LL:COL (std::panic::catch_unwind) -RUSTLIB/src/rust/library/std/src/rt.rs:LL:COL (std::rt::lang_start_internal) -RUSTLIB/src/rust/library/std/src/rt.rs:LL:COL (std::rt::lang_start) +RUSTLIB/core/src/ops/function.rs:LL:COL (>::call_once - shim(fn())) +RUSTLIB/std/src/sys_common/backtrace.rs:LL:COL (std::sys_common::backtrace::__rust_begin_short_backtrace) +RUSTLIB/std/src/rt.rs:LL:COL (std::rt::lang_start::{closure#0}) +RUSTLIB/core/src/ops/function.rs:LL:COL (std::ops::function::impls::call_once) +RUSTLIB/std/src/panicking.rs:LL:COL (std::panicking::r#try::do_call) +RUSTLIB/std/src/panicking.rs:LL:COL (std::panicking::r#try) +RUSTLIB/std/src/panic.rs:LL:COL (std::panic::catch_unwind) +RUSTLIB/std/src/rt.rs:LL:COL (std::rt::lang_start_internal) +RUSTLIB/std/src/rt.rs:LL:COL (std::rt::lang_start) From 1ffc5bb5633dd9bf3a38766fbf78ddc76d8b0bc8 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Thu, 1 Oct 2020 20:47:31 +0200 Subject: [PATCH 2337/3747] Implement futex_wait and futex_wake. This does not support futex_wait with a timeout yet. --- src/shims/posix/linux/foreign_items.rs | 67 ++++++++++++++++++++++++++ src/sync.rs | 27 +++++++++++ 2 files changed, 94 insertions(+) diff --git a/src/shims/posix/linux/foreign_items.rs b/src/shims/posix/linux/foreign_items.rs index 357c55c926f13..8434d7bfa8062 100644 --- a/src/shims/posix/linux/foreign_items.rs +++ b/src/shims/posix/linux/foreign_items.rs @@ -1,4 +1,5 @@ use rustc_middle::mir; +use rustc_target::abi::{Align, Size}; use crate::*; use crate::helpers::check_arg_count; @@ -120,6 +121,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx .eval_libc("SYS_statx")? .to_machine_usize(this)?; + let sys_futex = this + .eval_libc("SYS_futex")? + .to_machine_usize(this)?; + if args.is_empty() { throw_ub_format!("incorrect number of arguments for syscall: got 0, expected at least 1"); } @@ -139,6 +144,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let result = this.linux_statx(dirfd, pathname, flags, mask, statxbuf)?; this.write_scalar(Scalar::from_machine_isize(result.into(), this), dest)?; } + // `futex` is used by some synchonization primitives. + id if id == sys_futex => { + futex(this, args, dest)?; + } id => throw_unsup_format!("miri does not support syscall ID {}", id), } } @@ -192,3 +201,61 @@ fn getrandom<'tcx>( this.write_scalar(Scalar::from_machine_usize(len, this), dest)?; Ok(()) } + +fn futex<'tcx>( + this: &mut MiriEvalContext<'_, 'tcx>, + args: &[OpTy<'tcx, Tag>], + dest: PlaceTy<'tcx, Tag>, +) -> InterpResult<'tcx> { + if args.len() < 4 { + throw_ub_format!("incorrect number of arguments for futex syscall: got {}, expected at least 4", args.len()); + } + let addr = this.read_scalar(args[1])?.check_init()?; + let op = this.read_scalar(args[2])?.to_i32()?; + let val = this.read_scalar(args[3])?.to_i32()?; + + this.memory.check_ptr_access(addr, Size::from_bytes(4), Align::from_bytes(4).unwrap())?; + + let addr = addr.assert_ptr(); + + let thread = this.get_active_thread(); + + let futex_private = this.eval_libc_i32("FUTEX_PRIVATE_FLAG")?; + let futex_wait = this.eval_libc_i32("FUTEX_WAIT")?; + let futex_wake = this.eval_libc_i32("FUTEX_WAKE")?; + + match op & !futex_private { + op if op == futex_wait => { + if args.len() < 5 { + throw_ub_format!("incorrect number of arguments for FUTEX_WAIT syscall: got {}, expected at least 5", args.len()); + } + let timeout = this.read_scalar(args[4])?.check_init()?; + if !this.is_null(timeout)? { + throw_ub_format!("miri does not support timeouts for futex operations"); + } + let futex_val = this.read_scalar_at_offset(args[1], 0, this.machine.layouts.i32)?.to_i32()?; + if val == futex_val { + this.block_thread(thread); + this.futex_wait(addr, thread); + } else { + let eagain = this.eval_libc("EAGAIN")?; + this.set_last_error(eagain)?; + } + } + op if op == futex_wake => { + let mut n = 0; + for _ in 0..val { + if let Some(thread) = this.futex_wake(addr) { + this.unblock_thread(thread); + n += 1; + } else { + break; + } + } + this.write_scalar(Scalar::from_i32(n), dest)?; + } + op => throw_unsup_format!("miri does not support SYS_futex operation {}", op), + } + + Ok(()) +} diff --git a/src/sync.rs b/src/sync.rs index 7e3c27b386dfe..d5594fb9eca4c 100644 --- a/src/sync.rs +++ b/src/sync.rs @@ -96,12 +96,26 @@ struct Condvar { waiters: VecDeque, } +/// The futex state. +#[derive(Default, Debug)] +struct Futex { + waiters: VecDeque, +} + +/// A thread waiting on a futex. +#[derive(Debug)] +struct FutexWaiter { + /// The thread that is waiting on this futex. + thread: ThreadId, +} + /// The state of all synchronization variables. #[derive(Default, Debug)] pub(super) struct SynchronizationState { mutexes: IndexVec, rwlocks: IndexVec, condvars: IndexVec, + futexes: HashMap, Futex>, } // Private extension trait for local helper methods @@ -403,4 +417,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); this.machine.threads.sync.condvars[id].waiters.retain(|waiter| waiter.thread != thread); } + + fn futex_wait(&mut self, addr: Pointer, thread: ThreadId) { + let this = self.eval_context_mut(); + let waiters = &mut this.machine.threads.sync.futexes.entry(addr).or_default().waiters; + assert!(waiters.iter().all(|waiter| waiter.thread != thread), "thread is already waiting"); + waiters.push_back(FutexWaiter { thread }); + } + + fn futex_wake(&mut self, addr: Pointer) -> Option { + let this = self.eval_context_mut(); + let waiters = &mut this.machine.threads.sync.futexes.get_mut(&addr)?.waiters; + waiters.pop_front().map(|waiter| waiter.thread) + } } From 281a5382262af7f6d5d9caf677b4c7f2315dd359 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Thu, 1 Oct 2020 21:03:36 +0200 Subject: [PATCH 2338/3747] Move futex syscall to its own file. --- src/shims/posix/linux/foreign_items.rs | 60 +------------------------ src/shims/posix/linux/mod.rs | 1 + src/shims/posix/linux/sync.rs | 61 ++++++++++++++++++++++++++ 3 files changed, 63 insertions(+), 59 deletions(-) create mode 100644 src/shims/posix/linux/sync.rs diff --git a/src/shims/posix/linux/foreign_items.rs b/src/shims/posix/linux/foreign_items.rs index 8434d7bfa8062..2241b8d4b3b14 100644 --- a/src/shims/posix/linux/foreign_items.rs +++ b/src/shims/posix/linux/foreign_items.rs @@ -1,9 +1,9 @@ use rustc_middle::mir; -use rustc_target::abi::{Align, Size}; use crate::*; use crate::helpers::check_arg_count; use shims::posix::fs::EvalContextExt as _; +use shims::posix::linux::sync::futex; use shims::posix::sync::EvalContextExt as _; use shims::posix::thread::EvalContextExt as _; @@ -201,61 +201,3 @@ fn getrandom<'tcx>( this.write_scalar(Scalar::from_machine_usize(len, this), dest)?; Ok(()) } - -fn futex<'tcx>( - this: &mut MiriEvalContext<'_, 'tcx>, - args: &[OpTy<'tcx, Tag>], - dest: PlaceTy<'tcx, Tag>, -) -> InterpResult<'tcx> { - if args.len() < 4 { - throw_ub_format!("incorrect number of arguments for futex syscall: got {}, expected at least 4", args.len()); - } - let addr = this.read_scalar(args[1])?.check_init()?; - let op = this.read_scalar(args[2])?.to_i32()?; - let val = this.read_scalar(args[3])?.to_i32()?; - - this.memory.check_ptr_access(addr, Size::from_bytes(4), Align::from_bytes(4).unwrap())?; - - let addr = addr.assert_ptr(); - - let thread = this.get_active_thread(); - - let futex_private = this.eval_libc_i32("FUTEX_PRIVATE_FLAG")?; - let futex_wait = this.eval_libc_i32("FUTEX_WAIT")?; - let futex_wake = this.eval_libc_i32("FUTEX_WAKE")?; - - match op & !futex_private { - op if op == futex_wait => { - if args.len() < 5 { - throw_ub_format!("incorrect number of arguments for FUTEX_WAIT syscall: got {}, expected at least 5", args.len()); - } - let timeout = this.read_scalar(args[4])?.check_init()?; - if !this.is_null(timeout)? { - throw_ub_format!("miri does not support timeouts for futex operations"); - } - let futex_val = this.read_scalar_at_offset(args[1], 0, this.machine.layouts.i32)?.to_i32()?; - if val == futex_val { - this.block_thread(thread); - this.futex_wait(addr, thread); - } else { - let eagain = this.eval_libc("EAGAIN")?; - this.set_last_error(eagain)?; - } - } - op if op == futex_wake => { - let mut n = 0; - for _ in 0..val { - if let Some(thread) = this.futex_wake(addr) { - this.unblock_thread(thread); - n += 1; - } else { - break; - } - } - this.write_scalar(Scalar::from_i32(n), dest)?; - } - op => throw_unsup_format!("miri does not support SYS_futex operation {}", op), - } - - Ok(()) -} diff --git a/src/shims/posix/linux/mod.rs b/src/shims/posix/linux/mod.rs index cadd6a8ea384e..eba4a517cf5dc 100644 --- a/src/shims/posix/linux/mod.rs +++ b/src/shims/posix/linux/mod.rs @@ -1,2 +1,3 @@ pub mod foreign_items; pub mod dlsym; +pub mod sync; diff --git a/src/shims/posix/linux/sync.rs b/src/shims/posix/linux/sync.rs new file mode 100644 index 0000000000000..f9cfb3b8a2b0e --- /dev/null +++ b/src/shims/posix/linux/sync.rs @@ -0,0 +1,61 @@ +use crate::*; +use rustc_target::abi::{Align, Size}; + +/// Implementation of the SYS_futex syscall. +pub fn futex<'tcx>( + this: &mut MiriEvalContext<'_, 'tcx>, + args: &[OpTy<'tcx, Tag>], + dest: PlaceTy<'tcx, Tag>, +) -> InterpResult<'tcx> { + if args.len() < 4 { + throw_ub_format!("incorrect number of arguments for futex syscall: got {}, expected at least 4", args.len()); + } + let addr = this.read_scalar(args[1])?.check_init()?; + let op = this.read_scalar(args[2])?.to_i32()?; + let val = this.read_scalar(args[3])?.to_i32()?; + + this.memory.check_ptr_access(addr, Size::from_bytes(4), Align::from_bytes(4).unwrap())?; + + let addr = addr.assert_ptr(); + + let thread = this.get_active_thread(); + + let futex_private = this.eval_libc_i32("FUTEX_PRIVATE_FLAG")?; + let futex_wait = this.eval_libc_i32("FUTEX_WAIT")?; + let futex_wake = this.eval_libc_i32("FUTEX_WAKE")?; + + match op & !futex_private { + op if op == futex_wait => { + if args.len() < 5 { + throw_ub_format!("incorrect number of arguments for FUTEX_WAIT syscall: got {}, expected at least 5", args.len()); + } + let timeout = this.read_scalar(args[4])?.check_init()?; + if !this.is_null(timeout)? { + throw_ub_format!("miri does not support timeouts for futex operations"); + } + let futex_val = this.read_scalar_at_offset(args[1], 0, this.machine.layouts.i32)?.to_i32()?; + if val == futex_val { + this.block_thread(thread); + this.futex_wait(addr, thread); + } else { + let eagain = this.eval_libc("EAGAIN")?; + this.set_last_error(eagain)?; + } + } + op if op == futex_wake => { + let mut n = 0; + for _ in 0..val { + if let Some(thread) = this.futex_wake(addr) { + this.unblock_thread(thread); + n += 1; + } else { + break; + } + } + this.write_scalar(Scalar::from_i32(n), dest)?; + } + op => throw_unsup_format!("miri does not support SYS_futex operation {}", op), + } + + Ok(()) +} From 6c2f36eb6b6f35f94bc006c663d1622ebd71ff87 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Thu, 1 Oct 2020 21:06:16 +0200 Subject: [PATCH 2339/3747] Erase tag from futex pointers. --- src/shims/posix/linux/sync.rs | 2 +- src/sync.rs | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/shims/posix/linux/sync.rs b/src/shims/posix/linux/sync.rs index f9cfb3b8a2b0e..23d3330c74e9e 100644 --- a/src/shims/posix/linux/sync.rs +++ b/src/shims/posix/linux/sync.rs @@ -16,7 +16,7 @@ pub fn futex<'tcx>( this.memory.check_ptr_access(addr, Size::from_bytes(4), Align::from_bytes(4).unwrap())?; - let addr = addr.assert_ptr(); + let addr = addr.assert_ptr().erase_tag(); let thread = this.get_active_thread(); diff --git a/src/sync.rs b/src/sync.rs index d5594fb9eca4c..986857221b62b 100644 --- a/src/sync.rs +++ b/src/sync.rs @@ -115,7 +115,7 @@ pub(super) struct SynchronizationState { mutexes: IndexVec, rwlocks: IndexVec, condvars: IndexVec, - futexes: HashMap, Futex>, + futexes: HashMap, } // Private extension trait for local helper methods @@ -418,14 +418,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.machine.threads.sync.condvars[id].waiters.retain(|waiter| waiter.thread != thread); } - fn futex_wait(&mut self, addr: Pointer, thread: ThreadId) { + fn futex_wait(&mut self, addr: Pointer, thread: ThreadId) { let this = self.eval_context_mut(); let waiters = &mut this.machine.threads.sync.futexes.entry(addr).or_default().waiters; assert!(waiters.iter().all(|waiter| waiter.thread != thread), "thread is already waiting"); waiters.push_back(FutexWaiter { thread }); } - fn futex_wake(&mut self, addr: Pointer) -> Option { + fn futex_wake(&mut self, addr: Pointer) -> Option { let this = self.eval_context_mut(); let waiters = &mut this.machine.threads.sync.futexes.get_mut(&addr)?.waiters; waiters.pop_front().map(|waiter| waiter.thread) From 69cea1dc92695d317145fa057529f8c679e3cfc0 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Thu, 1 Oct 2020 22:57:27 +0200 Subject: [PATCH 2340/3747] Only check futex pointer in futex_wait and not in futex_wake. futex_wake doesn't access the futex itself, so should accept pointers to memory that's no longer there. --- src/shims/posix/linux/sync.rs | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/shims/posix/linux/sync.rs b/src/shims/posix/linux/sync.rs index 23d3330c74e9e..d92fc0441c49d 100644 --- a/src/shims/posix/linux/sync.rs +++ b/src/shims/posix/linux/sync.rs @@ -10,14 +10,12 @@ pub fn futex<'tcx>( if args.len() < 4 { throw_ub_format!("incorrect number of arguments for futex syscall: got {}, expected at least 4", args.len()); } - let addr = this.read_scalar(args[1])?.check_init()?; + let addr = args[1]; + let addr_scalar = this.read_scalar(addr)?.check_init()?; + let futex_ptr = this.force_ptr(addr_scalar)?.erase_tag(); let op = this.read_scalar(args[2])?.to_i32()?; let val = this.read_scalar(args[3])?.to_i32()?; - this.memory.check_ptr_access(addr, Size::from_bytes(4), Align::from_bytes(4).unwrap())?; - - let addr = addr.assert_ptr().erase_tag(); - let thread = this.get_active_thread(); let futex_private = this.eval_libc_i32("FUTEX_PRIVATE_FLAG")?; @@ -33,10 +31,11 @@ pub fn futex<'tcx>( if !this.is_null(timeout)? { throw_ub_format!("miri does not support timeouts for futex operations"); } + this.memory.check_ptr_access(addr_scalar, Size::from_bytes(4), Align::from_bytes(4).unwrap())?; let futex_val = this.read_scalar_at_offset(args[1], 0, this.machine.layouts.i32)?.to_i32()?; if val == futex_val { this.block_thread(thread); - this.futex_wait(addr, thread); + this.futex_wait(futex_ptr, thread); } else { let eagain = this.eval_libc("EAGAIN")?; this.set_last_error(eagain)?; @@ -45,7 +44,7 @@ pub fn futex<'tcx>( op if op == futex_wake => { let mut n = 0; for _ in 0..val { - if let Some(thread) = this.futex_wake(addr) { + if let Some(thread) = this.futex_wake(futex_ptr) { this.unblock_thread(thread); n += 1; } else { From 1c582e7c967577d2760e05dee39cf57ea72c3606 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Fri, 2 Oct 2020 01:49:20 +0200 Subject: [PATCH 2341/3747] Return correct value from futex_wait. --- src/shims/posix/linux/sync.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/shims/posix/linux/sync.rs b/src/shims/posix/linux/sync.rs index d92fc0441c49d..0892eab467393 100644 --- a/src/shims/posix/linux/sync.rs +++ b/src/shims/posix/linux/sync.rs @@ -36,9 +36,11 @@ pub fn futex<'tcx>( if val == futex_val { this.block_thread(thread); this.futex_wait(futex_ptr, thread); + this.write_scalar(Scalar::from_i32(0), dest)?; } else { let eagain = this.eval_libc("EAGAIN")?; this.set_last_error(eagain)?; + this.write_scalar(Scalar::from_i32(-1), dest)?; } } op if op == futex_wake => { From c2fa27c3b8bfd99240bda23fff1b09bb78c5e7fa Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Fri, 2 Oct 2020 10:46:57 +0200 Subject: [PATCH 2342/3747] Check maximum amount of arguments to SYS_futex. --- src/shims/posix/linux/sync.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/shims/posix/linux/sync.rs b/src/shims/posix/linux/sync.rs index 0892eab467393..a891a7dd9946f 100644 --- a/src/shims/posix/linux/sync.rs +++ b/src/shims/posix/linux/sync.rs @@ -7,8 +7,11 @@ pub fn futex<'tcx>( args: &[OpTy<'tcx, Tag>], dest: PlaceTy<'tcx, Tag>, ) -> InterpResult<'tcx> { - if args.len() < 4 { - throw_ub_format!("incorrect number of arguments for futex syscall: got {}, expected at least 4", args.len()); + // The amount of arguments used depends on the type of futex operation. + // Some users always pass all arguments, even the unused ones, due to how they wrap this syscall in their code base. + // Some other users pass only the arguments the operation actually needs. So we don't use `check_arg_count` here. + if !(4..=7).contains(&args.len()) { + throw_ub_format!("incorrect number of arguments for futex syscall: got {}, expected between 4 and 7 (inclusive)", args.len()); } let addr = args[1]; let addr_scalar = this.read_scalar(addr)?.check_init()?; From 712e8006b3c3a055b53326196081df11da123d38 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Fri, 2 Oct 2020 10:47:36 +0200 Subject: [PATCH 2343/3747] Improve handling of the `addr` argument in SYS_futex. --- src/shims/posix/linux/sync.rs | 18 +++++++++++++----- src/sync.rs | 8 ++++---- 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/src/shims/posix/linux/sync.rs b/src/shims/posix/linux/sync.rs index a891a7dd9946f..2b31961559d14 100644 --- a/src/shims/posix/linux/sync.rs +++ b/src/shims/posix/linux/sync.rs @@ -13,12 +13,18 @@ pub fn futex<'tcx>( if !(4..=7).contains(&args.len()) { throw_ub_format!("incorrect number of arguments for futex syscall: got {}, expected between 4 and 7 (inclusive)", args.len()); } - let addr = args[1]; - let addr_scalar = this.read_scalar(addr)?.check_init()?; - let futex_ptr = this.force_ptr(addr_scalar)?.erase_tag(); + + // The first three arguments (after the syscall number itself) are the same to all futex operations: + // (int *addr, int op, int val). + // Although note that the first one is often passed as a different pointer type, e.g. `*const AtomicU32` or `*mut u32`. + let addr = this.deref_operand(args[1])?; let op = this.read_scalar(args[2])?.to_i32()?; let val = this.read_scalar(args[3])?.to_i32()?; + // The raw pointer value is used to identify the mutex. + // Not all mutex operations actually read from this address or even require this address to exist. + let futex_ptr = addr.ptr.assert_ptr(); + let thread = this.get_active_thread(); let futex_private = this.eval_libc_i32("FUTEX_PRIVATE_FLAG")?; @@ -34,8 +40,10 @@ pub fn futex<'tcx>( if !this.is_null(timeout)? { throw_ub_format!("miri does not support timeouts for futex operations"); } - this.memory.check_ptr_access(addr_scalar, Size::from_bytes(4), Align::from_bytes(4).unwrap())?; - let futex_val = this.read_scalar_at_offset(args[1], 0, this.machine.layouts.i32)?.to_i32()?; + // Check the pointer for alignment. Atomic operations are only available for fully aligned values. + this.memory.check_ptr_access(addr.ptr.into(), Size::from_bytes(4), Align::from_bytes(4).unwrap())?; + // Read an `i32` through the pointer, regardless of any wrapper types (e.g. `AtomicI32`). + let futex_val = this.read_scalar(addr.offset(Size::ZERO, MemPlaceMeta::None, this.machine.layouts.i32, this)?.into())?.to_i32()?; if val == futex_val { this.block_thread(thread); this.futex_wait(futex_ptr, thread); diff --git a/src/sync.rs b/src/sync.rs index 986857221b62b..f8b6f99f1e033 100644 --- a/src/sync.rs +++ b/src/sync.rs @@ -418,16 +418,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.machine.threads.sync.condvars[id].waiters.retain(|waiter| waiter.thread != thread); } - fn futex_wait(&mut self, addr: Pointer, thread: ThreadId) { + fn futex_wait(&mut self, addr: Pointer, thread: ThreadId) { let this = self.eval_context_mut(); - let waiters = &mut this.machine.threads.sync.futexes.entry(addr).or_default().waiters; + let waiters = &mut this.machine.threads.sync.futexes.entry(addr.erase_tag()).or_default().waiters; assert!(waiters.iter().all(|waiter| waiter.thread != thread), "thread is already waiting"); waiters.push_back(FutexWaiter { thread }); } - fn futex_wake(&mut self, addr: Pointer) -> Option { + fn futex_wake(&mut self, addr: Pointer) -> Option { let this = self.eval_context_mut(); - let waiters = &mut this.machine.threads.sync.futexes.get_mut(&addr)?.waiters; + let waiters = &mut this.machine.threads.sync.futexes.get_mut(&addr.erase_tag())?.waiters; waiters.pop_front().map(|waiter| waiter.thread) } } From ee3eb4b223f823b5bf7df7ece97621aa36315fdc Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Fri, 2 Oct 2020 10:47:53 +0200 Subject: [PATCH 2344/3747] Add comments that document SYS_futex better. --- src/shims/posix/linux/sync.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/shims/posix/linux/sync.rs b/src/shims/posix/linux/sync.rs index 2b31961559d14..8da6921653cec 100644 --- a/src/shims/posix/linux/sync.rs +++ b/src/shims/posix/linux/sync.rs @@ -31,13 +31,20 @@ pub fn futex<'tcx>( let futex_wait = this.eval_libc_i32("FUTEX_WAIT")?; let futex_wake = this.eval_libc_i32("FUTEX_WAKE")?; + // FUTEX_PRIVATE enables an optimization that stops it from working across processes. + // Miri doesn't support that anyway, so we ignore that flag. match op & !futex_private { + // FUTEX_WAIT: (int *addr, int op = FUTEX_WAIT, int val, const timespec *timeout) + // Blocks the thread if *addr still equals val. Wakes up when FUTEX_WAKE is called on the same address, + // or *timeout expires. `timeout == null` for an infinite timeout. op if op == futex_wait => { if args.len() < 5 { throw_ub_format!("incorrect number of arguments for FUTEX_WAIT syscall: got {}, expected at least 5", args.len()); } let timeout = this.read_scalar(args[4])?.check_init()?; if !this.is_null(timeout)? { + // FIXME: Implement timeouts. The condvar waiting code is probably a good example to start with. + // Note that a triggered timeout should have this syscall return with -1 and errno set to ETIMEOUT. throw_ub_format!("miri does not support timeouts for futex operations"); } // Check the pointer for alignment. Atomic operations are only available for fully aligned values. @@ -45,15 +52,23 @@ pub fn futex<'tcx>( // Read an `i32` through the pointer, regardless of any wrapper types (e.g. `AtomicI32`). let futex_val = this.read_scalar(addr.offset(Size::ZERO, MemPlaceMeta::None, this.machine.layouts.i32, this)?.into())?.to_i32()?; if val == futex_val { + // The value still matches, so we block the trait make it wait for FUTEX_WAKE. this.block_thread(thread); this.futex_wait(futex_ptr, thread); + // Succesfully waking up from FUTEX_WAIT always returns zero. this.write_scalar(Scalar::from_i32(0), dest)?; } else { + // The futex value doesn't match the expected value, so we return failure + // right away without sleeping: -1 and errno set to EAGAIN. let eagain = this.eval_libc("EAGAIN")?; this.set_last_error(eagain)?; this.write_scalar(Scalar::from_i32(-1), dest)?; } } + // FUTEX_WAKE: (int *addr, int op = FUTEX_WAKE, int val) + // Wakes at most `val` threads waiting on the futex at `addr`. + // Returns the amount of threads woken up. + // Does not access the futex value at *addr. op if op == futex_wake => { let mut n = 0; for _ in 0..val { From dabd98056778238e9e1b9f0668183c7cb635d2b1 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Fri, 2 Oct 2020 20:53:31 +0200 Subject: [PATCH 2345/3747] Update note about number of arguments to SYS_futex. --- src/shims/posix/linux/sync.rs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/shims/posix/linux/sync.rs b/src/shims/posix/linux/sync.rs index 8da6921653cec..ae90583686709 100644 --- a/src/shims/posix/linux/sync.rs +++ b/src/shims/posix/linux/sync.rs @@ -8,8 +8,13 @@ pub fn futex<'tcx>( dest: PlaceTy<'tcx, Tag>, ) -> InterpResult<'tcx> { // The amount of arguments used depends on the type of futex operation. - // Some users always pass all arguments, even the unused ones, due to how they wrap this syscall in their code base. - // Some other users pass only the arguments the operation actually needs. So we don't use `check_arg_count` here. + // The full futex syscall takes six arguments (excluding the syscall + // number), which is also the maximum amount of arguments a linux syscall + // can take on most architectures. + // However, not all futex operations use all six arguments. The unused ones + // may or may not be left out from the `syscall()` call. + // Therefore we don't use `check_arg_count` here, but only check for the + // number of arguments to fall within a range. if !(4..=7).contains(&args.len()) { throw_ub_format!("incorrect number of arguments for futex syscall: got {}, expected between 4 and 7 (inclusive)", args.len()); } From 422b5053a9a8730de46b6c22997a04afdd2d4d08 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Fri, 2 Oct 2020 20:56:01 +0200 Subject: [PATCH 2346/3747] Add note about arguments in futex implementation. Co-authored-by: Ralf Jung --- src/shims/posix/linux/sync.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/shims/posix/linux/sync.rs b/src/shims/posix/linux/sync.rs index ae90583686709..e01e716879a8f 100644 --- a/src/shims/posix/linux/sync.rs +++ b/src/shims/posix/linux/sync.rs @@ -21,6 +21,7 @@ pub fn futex<'tcx>( // The first three arguments (after the syscall number itself) are the same to all futex operations: // (int *addr, int op, int val). + // We checked above that these definitely exist. // Although note that the first one is often passed as a different pointer type, e.g. `*const AtomicU32` or `*mut u32`. let addr = this.deref_operand(args[1])?; let op = this.read_scalar(args[2])?.to_i32()?; From d5b3f54b46125a3da9af7e466e004b6905bc2f26 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Fri, 2 Oct 2020 21:59:11 +0200 Subject: [PATCH 2347/3747] Use force_ptr in futex implementation. --- src/shims/posix/linux/sync.rs | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/src/shims/posix/linux/sync.rs b/src/shims/posix/linux/sync.rs index e01e716879a8f..1cfcb65bdc191 100644 --- a/src/shims/posix/linux/sync.rs +++ b/src/shims/posix/linux/sync.rs @@ -22,15 +22,17 @@ pub fn futex<'tcx>( // The first three arguments (after the syscall number itself) are the same to all futex operations: // (int *addr, int op, int val). // We checked above that these definitely exist. - // Although note that the first one is often passed as a different pointer type, e.g. `*const AtomicU32` or `*mut u32`. - let addr = this.deref_operand(args[1])?; + // + // `addr` is used to identify the mutex, but note that not all futex + // operations actually read from this addres or even require this address + // to exist. Also, the type of `addr` is not consistent. The API requires + // it to be a 4-byte aligned pointer, and will use the 4 bytes at the given + // address as an (atomic) i32. It's not uncommon for `addr` to be passed as + // another type than `*mut i32`, such as `*const AtomicI32`. + let addr = this.force_ptr(this.read_scalar(args[1])?.check_init()?)?; let op = this.read_scalar(args[2])?.to_i32()?; let val = this.read_scalar(args[3])?.to_i32()?; - // The raw pointer value is used to identify the mutex. - // Not all mutex operations actually read from this address or even require this address to exist. - let futex_ptr = addr.ptr.assert_ptr(); - let thread = this.get_active_thread(); let futex_private = this.eval_libc_i32("FUTEX_PRIVATE_FLAG")?; @@ -53,14 +55,15 @@ pub fn futex<'tcx>( // Note that a triggered timeout should have this syscall return with -1 and errno set to ETIMEOUT. throw_ub_format!("miri does not support timeouts for futex operations"); } - // Check the pointer for alignment. Atomic operations are only available for fully aligned values. - this.memory.check_ptr_access(addr.ptr.into(), Size::from_bytes(4), Align::from_bytes(4).unwrap())?; + // Check the pointer for alignment and validity. + // Atomic operations are only available for fully aligned values. + this.memory.check_ptr_access(addr.into(), Size::from_bytes(4), Align::from_bytes(4).unwrap())?; // Read an `i32` through the pointer, regardless of any wrapper types (e.g. `AtomicI32`). - let futex_val = this.read_scalar(addr.offset(Size::ZERO, MemPlaceMeta::None, this.machine.layouts.i32, this)?.into())?.to_i32()?; + let futex_val = this.memory.get_raw(addr.alloc_id)?.read_scalar(this, addr, Size::from_bytes(4))?.to_i32()?; if val == futex_val { // The value still matches, so we block the trait make it wait for FUTEX_WAKE. this.block_thread(thread); - this.futex_wait(futex_ptr, thread); + this.futex_wait(addr, thread); // Succesfully waking up from FUTEX_WAIT always returns zero. this.write_scalar(Scalar::from_i32(0), dest)?; } else { @@ -78,7 +81,7 @@ pub fn futex<'tcx>( op if op == futex_wake => { let mut n = 0; for _ in 0..val { - if let Some(thread) = this.futex_wake(futex_ptr) { + if let Some(thread) = this.futex_wake(addr) { this.unblock_thread(thread); n += 1; } else { From e64ead2f46144963bc18ba34477422f39577f7f6 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Fri, 2 Oct 2020 23:34:14 +0200 Subject: [PATCH 2348/3747] Implement timeouts for FUTEX_WAIT. --- src/shims/posix/linux/sync.rs | 47 +++++++++++++++++++++++++++++------ src/sync.rs | 7 ++++++ 2 files changed, 47 insertions(+), 7 deletions(-) diff --git a/src/shims/posix/linux/sync.rs b/src/shims/posix/linux/sync.rs index 1cfcb65bdc191..4201ef3f4790f 100644 --- a/src/shims/posix/linux/sync.rs +++ b/src/shims/posix/linux/sync.rs @@ -1,5 +1,7 @@ +use crate::thread::Time; use crate::*; use rustc_target::abi::{Align, Size}; +use std::time::{Instant, SystemTime}; /// Implementation of the SYS_futex syscall. pub fn futex<'tcx>( @@ -38,6 +40,7 @@ pub fn futex<'tcx>( let futex_private = this.eval_libc_i32("FUTEX_PRIVATE_FLAG")?; let futex_wait = this.eval_libc_i32("FUTEX_WAIT")?; let futex_wake = this.eval_libc_i32("FUTEX_WAKE")?; + let futex_realtime = this.eval_libc_i32("FUTEX_CLOCK_REALTIME")?; // FUTEX_PRIVATE enables an optimization that stops it from working across processes. // Miri doesn't support that anyway, so we ignore that flag. @@ -45,16 +48,29 @@ pub fn futex<'tcx>( // FUTEX_WAIT: (int *addr, int op = FUTEX_WAIT, int val, const timespec *timeout) // Blocks the thread if *addr still equals val. Wakes up when FUTEX_WAKE is called on the same address, // or *timeout expires. `timeout == null` for an infinite timeout. - op if op == futex_wait => { + op if op & !futex_realtime == futex_wait => { if args.len() < 5 { throw_ub_format!("incorrect number of arguments for FUTEX_WAIT syscall: got {}, expected at least 5", args.len()); } - let timeout = this.read_scalar(args[4])?.check_init()?; - if !this.is_null(timeout)? { - // FIXME: Implement timeouts. The condvar waiting code is probably a good example to start with. - // Note that a triggered timeout should have this syscall return with -1 and errno set to ETIMEOUT. - throw_ub_format!("miri does not support timeouts for futex operations"); - } + let timeout = args[4]; + let timeout_time = if this.is_null(this.read_scalar(timeout)?.check_init()?)? { + None + } else { + let duration = match this.read_timespec(timeout)? { + Some(duration) => duration, + None => { + let einval = this.eval_libc("EINVAL")?; + this.set_last_error(einval)?; + this.write_scalar(Scalar::from_i32(-1), dest)?; + return Ok(()); + } + }; + Some(if op & futex_realtime != 0 { + Time::RealTime(SystemTime::now().checked_add(duration).unwrap()) + } else { + Time::Monotonic(Instant::now().checked_add(duration).unwrap()) + }) + }; // Check the pointer for alignment and validity. // Atomic operations are only available for fully aligned values. this.memory.check_ptr_access(addr.into(), Size::from_bytes(4), Align::from_bytes(4).unwrap())?; @@ -66,6 +82,22 @@ pub fn futex<'tcx>( this.futex_wait(addr, thread); // Succesfully waking up from FUTEX_WAIT always returns zero. this.write_scalar(Scalar::from_i32(0), dest)?; + // Register a timeout callback if a timeout was specified. + // This callback will override the return value when the timeout triggers. + if let Some(timeout_time) = timeout_time { + this.register_timeout_callback( + thread, + timeout_time, + Box::new(move |this| { + this.unblock_thread(thread); + this.futex_remove_waiter(addr, thread); + let etimedout = this.eval_libc("ETIMEDOUT")?; + this.set_last_error(etimedout)?; + this.write_scalar(Scalar::from_i32(-1), dest)?; + Ok(()) + }), + ); + } } else { // The futex value doesn't match the expected value, so we return failure // right away without sleeping: -1 and errno set to EAGAIN. @@ -83,6 +115,7 @@ pub fn futex<'tcx>( for _ in 0..val { if let Some(thread) = this.futex_wake(addr) { this.unblock_thread(thread); + this.unregister_timeout_callback_if_exists(thread); n += 1; } else { break; diff --git a/src/sync.rs b/src/sync.rs index f8b6f99f1e033..0c12da8d68456 100644 --- a/src/sync.rs +++ b/src/sync.rs @@ -430,4 +430,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let waiters = &mut this.machine.threads.sync.futexes.get_mut(&addr.erase_tag())?.waiters; waiters.pop_front().map(|waiter| waiter.thread) } + + fn futex_remove_waiter(&mut self, addr: Pointer, thread: ThreadId) { + let this = self.eval_context_mut(); + if let Some(futex) = this.machine.threads.sync.futexes.get_mut(&addr.erase_tag()) { + futex.waiters.retain(|waiter| waiter.thread != thread); + } + } } From 81138825b370e112714d1f16e8f76835d57d8fdf Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Fri, 2 Oct 2020 23:35:00 +0200 Subject: [PATCH 2349/3747] Add park/park_timeout/unpark test. --- tests/run-pass/concurrency/parking.rs | 37 +++++++++++++++++++++++ tests/run-pass/concurrency/parking.stderr | 2 ++ 2 files changed, 39 insertions(+) create mode 100644 tests/run-pass/concurrency/parking.rs create mode 100644 tests/run-pass/concurrency/parking.stderr diff --git a/tests/run-pass/concurrency/parking.rs b/tests/run-pass/concurrency/parking.rs new file mode 100644 index 0000000000000..1ed742931fe6b --- /dev/null +++ b/tests/run-pass/concurrency/parking.rs @@ -0,0 +1,37 @@ +// ignore-windows: Concurrency on Windows is not supported yet. +// compile-flags: -Zmiri-disable-isolation + +use std::thread; +use std::time::{Duration, Instant}; + +// Normally, waiting in park/park_timeout may spuriously wake up early, but we +// know Miri's timed synchronization primitives do not do that. + +fn park_timeout() { + let start = Instant::now(); + + thread::park_timeout(Duration::from_millis(200)); + + assert!((200..500).contains(&start.elapsed().as_millis())); +} + +fn park_unpark() { + let t1 = thread::current(); + let t2 = thread::spawn(move || { + thread::park(); + thread::sleep(Duration::from_millis(200)); + t1.unpark(); + }); + + let start = Instant::now(); + + t2.thread().unpark(); + thread::park(); + + assert!((200..500).contains(&start.elapsed().as_millis())); +} + +fn main() { + park_timeout(); + park_unpark(); +} diff --git a/tests/run-pass/concurrency/parking.stderr b/tests/run-pass/concurrency/parking.stderr new file mode 100644 index 0000000000000..2dbfb7721d368 --- /dev/null +++ b/tests/run-pass/concurrency/parking.stderr @@ -0,0 +1,2 @@ +warning: thread support is experimental. For example, Miri does not detect data races yet. + From c9627b25fb840adfd860aa9e417cc089bd7dc264 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Sat, 3 Oct 2020 00:40:53 +0200 Subject: [PATCH 2350/3747] Use correct return type for syscall(SYS_futex). --- src/shims/posix/linux/sync.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/shims/posix/linux/sync.rs b/src/shims/posix/linux/sync.rs index 4201ef3f4790f..17fd5f0eefb70 100644 --- a/src/shims/posix/linux/sync.rs +++ b/src/shims/posix/linux/sync.rs @@ -61,7 +61,7 @@ pub fn futex<'tcx>( None => { let einval = this.eval_libc("EINVAL")?; this.set_last_error(einval)?; - this.write_scalar(Scalar::from_i32(-1), dest)?; + this.write_scalar(Scalar::from_machine_isize(-1, this), dest)?; return Ok(()); } }; @@ -81,7 +81,7 @@ pub fn futex<'tcx>( this.block_thread(thread); this.futex_wait(addr, thread); // Succesfully waking up from FUTEX_WAIT always returns zero. - this.write_scalar(Scalar::from_i32(0), dest)?; + this.write_scalar(Scalar::from_machine_isize(0, this), dest)?; // Register a timeout callback if a timeout was specified. // This callback will override the return value when the timeout triggers. if let Some(timeout_time) = timeout_time { @@ -93,7 +93,7 @@ pub fn futex<'tcx>( this.futex_remove_waiter(addr, thread); let etimedout = this.eval_libc("ETIMEDOUT")?; this.set_last_error(etimedout)?; - this.write_scalar(Scalar::from_i32(-1), dest)?; + this.write_scalar(Scalar::from_machine_isize(-1, this), dest)?; Ok(()) }), ); @@ -103,7 +103,7 @@ pub fn futex<'tcx>( // right away without sleeping: -1 and errno set to EAGAIN. let eagain = this.eval_libc("EAGAIN")?; this.set_last_error(eagain)?; - this.write_scalar(Scalar::from_i32(-1), dest)?; + this.write_scalar(Scalar::from_machine_isize(-1, this), dest)?; } } // FUTEX_WAKE: (int *addr, int op = FUTEX_WAKE, int val) @@ -121,7 +121,7 @@ pub fn futex<'tcx>( break; } } - this.write_scalar(Scalar::from_i32(n), dest)?; + this.write_scalar(Scalar::from_machine_isize(n, this), dest)?; } op => throw_unsup_format!("miri does not support SYS_futex operation {}", op), } From 924fd56944bbd9138e8e1b59a1a8d5a329ddeb1d Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Sat, 3 Oct 2020 11:35:13 +0200 Subject: [PATCH 2351/3747] Only allow FUTEX_WAIT with timeout when isoloation is disabled. --- src/shims/posix/linux/sync.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/shims/posix/linux/sync.rs b/src/shims/posix/linux/sync.rs index 17fd5f0eefb70..386678508337b 100644 --- a/src/shims/posix/linux/sync.rs +++ b/src/shims/posix/linux/sync.rs @@ -65,6 +65,7 @@ pub fn futex<'tcx>( return Ok(()); } }; + this.check_no_isolation("FUTEX_WAIT with timeout")?; Some(if op & futex_realtime != 0 { Time::RealTime(SystemTime::now().checked_add(duration).unwrap()) } else { From 66282754ff8d279c11dd946e84f1cd18cae8a24c Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Sat, 3 Oct 2020 11:38:16 +0200 Subject: [PATCH 2352/3747] Remove backtics from isolation error. Otherwise `FUTEX_WAIT with timeout` will look weird. --- src/helpers.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/helpers.rs b/src/helpers.rs index abf128ff3e2da..23bc54e76bb07 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -555,7 +555,7 @@ pub fn check_arg_count<'a, 'tcx, const N: usize>(args: &'a [OpTy<'tcx, Tag>]) -> pub fn isolation_error(name: &str) -> InterpResult<'static> { throw_machine_stop!(TerminationInfo::UnsupportedInIsolation(format!( - "`{}` not available when isolation is enabled", + "{} not available when isolation is enabled", name, ))) } From 5880e7d809d20246ce160710ebf7160e4d0c56c1 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Sat, 3 Oct 2020 12:00:29 +0200 Subject: [PATCH 2353/3747] Update expected error messages in tests. --- tests/compile-fail/fs/isolated_file.rs | 2 +- tests/compile-fail/fs/isolated_stdin.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/compile-fail/fs/isolated_file.rs b/tests/compile-fail/fs/isolated_file.rs index 5b7270f18931c..4c6adc8bf4062 100644 --- a/tests/compile-fail/fs/isolated_file.rs +++ b/tests/compile-fail/fs/isolated_file.rs @@ -1,5 +1,5 @@ // ignore-windows: File handling is not implemented yet -// error-pattern: `open` not available when isolation is enabled +// error-pattern: open not available when isolation is enabled fn main() { let _file = std::fs::File::open("file.txt").unwrap(); diff --git a/tests/compile-fail/fs/isolated_stdin.rs b/tests/compile-fail/fs/isolated_stdin.rs index 6c467a2d1f141..19ce064089aaa 100644 --- a/tests/compile-fail/fs/isolated_stdin.rs +++ b/tests/compile-fail/fs/isolated_stdin.rs @@ -7,7 +7,7 @@ extern crate libc; fn main() -> std::io::Result<()> { let mut bytes = [0u8; 512]; unsafe { - libc::read(0, bytes.as_mut_ptr() as *mut libc::c_void, 512); //~ ERROR `read` not available when isolation is enabled + libc::read(0, bytes.as_mut_ptr() as *mut libc::c_void, 512); //~ ERROR read not available when isolation is enabled } Ok(()) } From 6df54c47a7ac0a0788d68c12198f1369b559b93e Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Sat, 3 Oct 2020 12:11:24 +0200 Subject: [PATCH 2354/3747] Use read_scalar_at_offset in futex_wait instead of memory.get_raw. --- src/shims/posix/linux/sync.rs | 29 ++++++++++++++--------------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/src/shims/posix/linux/sync.rs b/src/shims/posix/linux/sync.rs index 386678508337b..cc09b33ba6842 100644 --- a/src/shims/posix/linux/sync.rs +++ b/src/shims/posix/linux/sync.rs @@ -24,17 +24,14 @@ pub fn futex<'tcx>( // The first three arguments (after the syscall number itself) are the same to all futex operations: // (int *addr, int op, int val). // We checked above that these definitely exist. - // - // `addr` is used to identify the mutex, but note that not all futex - // operations actually read from this addres or even require this address - // to exist. Also, the type of `addr` is not consistent. The API requires - // it to be a 4-byte aligned pointer, and will use the 4 bytes at the given - // address as an (atomic) i32. It's not uncommon for `addr` to be passed as - // another type than `*mut i32`, such as `*const AtomicI32`. - let addr = this.force_ptr(this.read_scalar(args[1])?.check_init()?)?; + let addr = this.read_immediate(args[1])?; let op = this.read_scalar(args[2])?.to_i32()?; let val = this.read_scalar(args[3])?.to_i32()?; + // The raw pointer value is used to identify the mutex. + // Not all mutex operations actually read from this address or even require this address to exist. + let futex_ptr = this.force_ptr(addr.to_scalar()?)?; + let thread = this.get_active_thread(); let futex_private = this.eval_libc_i32("FUTEX_PRIVATE_FLAG")?; @@ -73,14 +70,16 @@ pub fn futex<'tcx>( }) }; // Check the pointer for alignment and validity. - // Atomic operations are only available for fully aligned values. - this.memory.check_ptr_access(addr.into(), Size::from_bytes(4), Align::from_bytes(4).unwrap())?; - // Read an `i32` through the pointer, regardless of any wrapper types (e.g. `AtomicI32`). - let futex_val = this.memory.get_raw(addr.alloc_id)?.read_scalar(this, addr, Size::from_bytes(4))?.to_i32()?; + // The API requires `addr` to be a 4-byte aligned pointer, and will + // use the 4 bytes at the given address as an (atomic) i32. + this.memory.check_ptr_access(addr.to_scalar()?, Size::from_bytes(4), Align::from_bytes(4).unwrap())?; + // Read an `i32` through the pointer, regardless of any wrapper types. + // It's not uncommon for `addr` to be passed as another type than `*mut i32`, such as `*const AtomicI32`. + let futex_val = this.read_scalar_at_offset(addr.into(), 0, this.machine.layouts.i32)?.to_i32()?; if val == futex_val { // The value still matches, so we block the trait make it wait for FUTEX_WAKE. this.block_thread(thread); - this.futex_wait(addr, thread); + this.futex_wait(futex_ptr, thread); // Succesfully waking up from FUTEX_WAIT always returns zero. this.write_scalar(Scalar::from_machine_isize(0, this), dest)?; // Register a timeout callback if a timeout was specified. @@ -91,7 +90,7 @@ pub fn futex<'tcx>( timeout_time, Box::new(move |this| { this.unblock_thread(thread); - this.futex_remove_waiter(addr, thread); + this.futex_remove_waiter(futex_ptr, thread); let etimedout = this.eval_libc("ETIMEDOUT")?; this.set_last_error(etimedout)?; this.write_scalar(Scalar::from_machine_isize(-1, this), dest)?; @@ -114,7 +113,7 @@ pub fn futex<'tcx>( op if op == futex_wake => { let mut n = 0; for _ in 0..val { - if let Some(thread) = this.futex_wake(addr) { + if let Some(thread) = this.futex_wake(futex_ptr) { this.unblock_thread(thread); this.unregister_timeout_callback_if_exists(thread); n += 1; From 9d764c57502c1f6badb71684b5d5b5ee081f4dda Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Sat, 3 Oct 2020 12:18:38 +0200 Subject: [PATCH 2355/3747] Add FIXME note about variadic syscall(). --- src/shims/posix/linux/foreign_items.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/shims/posix/linux/foreign_items.rs b/src/shims/posix/linux/foreign_items.rs index 2241b8d4b3b14..328280d459a11 100644 --- a/src/shims/posix/linux/foreign_items.rs +++ b/src/shims/posix/linux/foreign_items.rs @@ -113,6 +113,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Dynamically invoked syscalls "syscall" => { + // FIXME: The libc syscall() function is a variadic function. + // It's valid to call it with more arguments than a syscall + // needs, so none of these syscalls should use check_arg_count. + // However, depending on the calling convention it might depend + // on the type and size of the arguments whether a call with + // the wrong number of arguments (or types) is valid or not. + // So this needs to be researched first. let sys_getrandom = this .eval_libc("SYS_getrandom")? .to_machine_usize(this)?; From dc36988f388258f8ff10441f04f6b9fb30578165 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Sat, 3 Oct 2020 13:09:11 +0200 Subject: [PATCH 2356/3747] Add test for futex syscall. --- tests/run-pass/concurrency/linux-futex.rs | 132 ++++++++++++++++++ tests/run-pass/concurrency/linux-futex.stderr | 2 + 2 files changed, 134 insertions(+) create mode 100644 tests/run-pass/concurrency/linux-futex.rs create mode 100644 tests/run-pass/concurrency/linux-futex.stderr diff --git a/tests/run-pass/concurrency/linux-futex.rs b/tests/run-pass/concurrency/linux-futex.rs new file mode 100644 index 0000000000000..391e9524324ae --- /dev/null +++ b/tests/run-pass/concurrency/linux-futex.rs @@ -0,0 +1,132 @@ +// Unfortunately, the test framework does not support 'only-linux', +// so we need to ignore Windows and macOS instead. +// ignore-macos: Uses Linux-only APIs +// ignore-windows: Uses Linux-only APIs +// compile-flags: -Zmiri-disable-isolation + +#![feature(rustc_private)] +extern crate libc; + +use std::ptr; +use std::thread; +use std::time::{Duration, Instant}; + +fn wake_nobody() { + let futex = 0; + + // Wake 1 waiter. Expect zero waiters woken up, as nobody is waiting. + unsafe { + assert_eq!(libc::syscall( + libc::SYS_futex, + &futex as *const i32, + libc::FUTEX_WAKE, + 1, + ), 0); + } + + // Same, but without omitting the unused arguments. + unsafe { + assert_eq!(libc::syscall( + libc::SYS_futex, + &futex as *const i32, + libc::FUTEX_WAKE, + 1, + 0, + 0, + 0, + ), 0); + } +} + +fn wake_dangling() { + let futex = Box::new(0); + let ptr: *const i32 = &*futex; + drop(futex); + + // Wake 1 waiter. Expect zero waiters woken up, as nobody is waiting. + unsafe { + assert_eq!(libc::syscall( + libc::SYS_futex, + ptr, + libc::FUTEX_WAKE, + 1, + ), 0); + } +} + +fn wait_wrong_val() { + let futex: i32 = 123; + + // Only wait if the futex value is 456. + unsafe { + assert_eq!(libc::syscall( + libc::SYS_futex, + &futex as *const i32, + libc::FUTEX_WAIT, + 456, + ptr::null::(), + ), -1); + assert_eq!(*libc::__errno_location(), libc::EAGAIN); + } +} + +fn wait_timeout() { + let start = Instant::now(); + + let futex: i32 = 123; + + // Wait for 200ms, with nobody waking us up early. + unsafe { + assert_eq!(libc::syscall( + libc::SYS_futex, + &futex as *const i32, + libc::FUTEX_WAIT, + 123, + &libc::timespec { + tv_sec: 0, + tv_nsec: 200_000_000, + }, + ), -1); + assert_eq!(*libc::__errno_location(), libc::ETIMEDOUT); + } + + assert!((200..500).contains(&start.elapsed().as_millis())); +} + +fn wait_wake() { + let start = Instant::now(); + + static FUTEX: i32 = 0; + + thread::spawn(move || { + thread::sleep(Duration::from_millis(200)); + unsafe { + assert_eq!(libc::syscall( + libc::SYS_futex, + &FUTEX as *const i32, + libc::FUTEX_WAKE, + 10, // Wake up at most 10 threads. + ), 1); // Woken up one thread. + } + }); + + unsafe { + assert_eq!(libc::syscall( + libc::SYS_futex, + &FUTEX as *const i32, + libc::FUTEX_WAIT, + 0, + ptr::null::(), + ), 0); + } + + assert!((200..500).contains(&start.elapsed().as_millis())); +} + +fn main() { + wake_nobody(); + wake_dangling(); + wait_wrong_val(); + wait_timeout(); + wait_wake(); +} diff --git a/tests/run-pass/concurrency/linux-futex.stderr b/tests/run-pass/concurrency/linux-futex.stderr new file mode 100644 index 0000000000000..2dbfb7721d368 --- /dev/null +++ b/tests/run-pass/concurrency/linux-futex.stderr @@ -0,0 +1,2 @@ +warning: thread support is experimental. For example, Miri does not detect data races yet. + From dfcb46a4e04743c38a5ef355062bad8764b93ff5 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Sat, 3 Oct 2020 13:39:16 +0200 Subject: [PATCH 2357/3747] Update syscall FIXME to include note about 'wrong' types. --- src/shims/posix/linux/foreign_items.rs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/shims/posix/linux/foreign_items.rs b/src/shims/posix/linux/foreign_items.rs index 328280d459a11..364cfde6c0721 100644 --- a/src/shims/posix/linux/foreign_items.rs +++ b/src/shims/posix/linux/foreign_items.rs @@ -116,10 +116,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // FIXME: The libc syscall() function is a variadic function. // It's valid to call it with more arguments than a syscall // needs, so none of these syscalls should use check_arg_count. - // However, depending on the calling convention it might depend - // on the type and size of the arguments whether a call with - // the wrong number of arguments (or types) is valid or not. + // It's even valid to call it with the wrong type of arguments, + // as long as they'd end up in the same place with the calling + // convention used. (E.g. using a `usize` instead of a pointer.) + // It's not directly clear which number, size, and type of arguments + // are acceptable in which cases and which aren't. (E.g. some + // types might take up the space of two registers.) // So this needs to be researched first. + let sys_getrandom = this .eval_libc("SYS_getrandom")? .to_machine_usize(this)?; From c268ee2bcbffeef4f0c0e8ef121188729933078b Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Sat, 3 Oct 2020 14:21:37 +0200 Subject: [PATCH 2358/3747] Add note about use of force_ptr in futex implementation. Co-authored-by: Ralf Jung --- src/shims/posix/linux/sync.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/shims/posix/linux/sync.rs b/src/shims/posix/linux/sync.rs index cc09b33ba6842..09558554aa221 100644 --- a/src/shims/posix/linux/sync.rs +++ b/src/shims/posix/linux/sync.rs @@ -30,6 +30,8 @@ pub fn futex<'tcx>( // The raw pointer value is used to identify the mutex. // Not all mutex operations actually read from this address or even require this address to exist. + // This will make FUTEX_WAKE fail on an integer cast to a pointer. But FUTEX_WAIT on + // such a pointer can never work anyway, so that seems fine. let futex_ptr = this.force_ptr(addr.to_scalar()?)?; let thread = this.get_active_thread(); From 68776d292196f4e890f860c1464ecc83af80859f Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Sat, 3 Oct 2020 14:32:30 +0200 Subject: [PATCH 2359/3747] Add FIXME about type of `addr` in futex implementation. Co-authored-by: Ralf Jung --- src/shims/posix/linux/sync.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/shims/posix/linux/sync.rs b/src/shims/posix/linux/sync.rs index 09558554aa221..d7ecb45279deb 100644 --- a/src/shims/posix/linux/sync.rs +++ b/src/shims/posix/linux/sync.rs @@ -77,6 +77,7 @@ pub fn futex<'tcx>( this.memory.check_ptr_access(addr.to_scalar()?, Size::from_bytes(4), Align::from_bytes(4).unwrap())?; // Read an `i32` through the pointer, regardless of any wrapper types. // It's not uncommon for `addr` to be passed as another type than `*mut i32`, such as `*const AtomicI32`. + // FIXME: this fails if `addr` is not a pointer type. let futex_val = this.read_scalar_at_offset(addr.into(), 0, this.machine.layouts.i32)?.to_i32()?; if val == futex_val { // The value still matches, so we block the trait make it wait for FUTEX_WAKE. From 044c9ca206e642aa11d6f0937427740cdb6c2fc6 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 3 Oct 2020 15:19:57 +0200 Subject: [PATCH 2360/3747] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 1b85e41c8ba28..9b4e14902aff0 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -c0127e4dbf3a9d3a67ddb1da19f8441019aab8f8 +6f56fbdc1c58992a9db630f5cd2ba9882d32e84b From b350c80a314b0b1a94fbfa2bb5d391df98388992 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 3 Oct 2020 15:20:16 +0200 Subject: [PATCH 2361/3747] add backtics back in isolation error message --- src/shims/env.rs | 8 ++--- src/shims/posix/fs.rs | 42 ++++++++++++------------- src/shims/posix/linux/sync.rs | 2 +- src/shims/posix/sync.rs | 2 +- src/shims/time.rs | 16 +++++----- tests/compile-fail/fs/isolated_file.rs | 2 +- tests/compile-fail/fs/isolated_stdin.rs | 2 +- 7 files changed, 36 insertions(+), 38 deletions(-) diff --git a/src/shims/env.rs b/src/shims/env.rs index d7474dbf87efc..42fd6e3dced8a 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -293,7 +293,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let target_os = &this.tcx.sess.target.target.target_os; assert!(target_os == "linux" || target_os == "macos", "`getcwd` is only available for the UNIX target family"); - this.check_no_isolation("getcwd")?; + this.check_no_isolation("`getcwd`")?; let buf = this.read_scalar(buf_op)?.check_init()?; let size = this.read_scalar(size_op)?.to_machine_usize(&*this.tcx)?; @@ -320,7 +320,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); this.assert_target_os("windows", "GetCurrentDirectoryW"); - this.check_no_isolation("GetCurrentDirectoryW")?; + this.check_no_isolation("`GetCurrentDirectoryW`")?; let size = u64::from(this.read_scalar(size_op)?.to_u32()?); let buf = this.read_scalar(buf_op)?.check_init()?; @@ -339,7 +339,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let target_os = &this.tcx.sess.target.target.target_os; assert!(target_os == "linux" || target_os == "macos", "`getcwd` is only available for the UNIX target family"); - this.check_no_isolation("chdir")?; + this.check_no_isolation("`chdir`")?; let path = this.read_path_from_c_str(this.read_scalar(path_op)?.check_init()?)?; @@ -360,7 +360,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); this.assert_target_os("windows", "SetCurrentDirectoryW"); - this.check_no_isolation("SetCurrentDirectoryW")?; + this.check_no_isolation("`SetCurrentDirectoryW`")?; let path = this.read_path_from_wide_str(this.read_scalar(path_op)?.check_init()?)?; diff --git a/src/shims/posix/fs.rs b/src/shims/posix/fs.rs index c50b41b75ef9e..88597b4a39814 100644 --- a/src/shims/posix/fs.rs +++ b/src/shims/posix/fs.rs @@ -90,7 +90,7 @@ impl FileDescriptor for io::Stdin { fn read<'tcx>(&mut self, communicate_allowed: bool, bytes: &mut [u8]) -> InterpResult<'tcx, io::Result> { if !communicate_allowed { // We want isolation mode to be deterministic, so we have to disallow all reads, even stdin. - helpers::isolation_error("read")?; + helpers::isolation_error("`read` from stdin")?; } Ok(Read::read(self, bytes)) } @@ -417,7 +417,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - this.check_no_isolation("open")?; + this.check_no_isolation("`open`")?; let flag = this.read_scalar(flag_op)?.to_i32()?; @@ -510,7 +510,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - this.check_no_isolation("fcntl")?; + this.check_no_isolation("`fcntl`")?; if args.len() < 2 { throw_ub_format!("incorrect number of arguments for fcntl: got {}, expected at least 2", args.len()); @@ -574,8 +574,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn close(&mut self, fd_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - this.check_no_isolation("close")?; - let fd = this.read_scalar(fd_op)?.to_i32()?; if let Some(file_descriptor) = this.machine.file_handler.handles.remove(&fd) { @@ -709,7 +707,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn unlink(&mut self, path_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - this.check_no_isolation("unlink")?; + this.check_no_isolation("`unlink`")?; let path = this.read_path_from_c_str(this.read_scalar(path_op)?.check_init()?)?; @@ -739,7 +737,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); - this.check_no_isolation("symlink")?; + this.check_no_isolation("`symlink`")?; let target = this.read_path_from_c_str(this.read_scalar(target_op)?.check_init()?)?; let linkpath = this.read_path_from_c_str(this.read_scalar(linkpath_op)?.check_init()?)?; @@ -755,7 +753,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); this.assert_target_os("macos", "stat"); - this.check_no_isolation("stat")?; + this.check_no_isolation("`stat`")?; // `stat` always follows symlinks. this.macos_stat_or_lstat(true, path_op, buf_op) } @@ -768,7 +766,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); this.assert_target_os("macos", "lstat"); - this.check_no_isolation("lstat")?; + this.check_no_isolation("`lstat`")?; this.macos_stat_or_lstat(false, path_op, buf_op) } @@ -780,7 +778,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); this.assert_target_os("macos", "fstat"); - this.check_no_isolation("fstat")?; + this.check_no_isolation("`fstat`")?; let fd = this.read_scalar(fd_op)?.to_i32()?; @@ -802,7 +800,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); this.assert_target_os("linux", "statx"); - this.check_no_isolation("statx")?; + this.check_no_isolation("`statx`")?; let statxbuf_scalar = this.read_scalar(statxbuf_op)?.check_init()?; let pathname_scalar = this.read_scalar(pathname_op)?.check_init()?; @@ -961,7 +959,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - this.check_no_isolation("rename")?; + this.check_no_isolation("`rename`")?; let oldpath_scalar = this.read_scalar(oldpath_op)?.check_init()?; let newpath_scalar = this.read_scalar(newpath_op)?.check_init()?; @@ -987,7 +985,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - this.check_no_isolation("mkdir")?; + this.check_no_isolation("`mkdir`")?; #[cfg_attr(not(unix), allow(unused_variables))] let mode = if this.tcx.sess.target.target.target_os == "macos" { @@ -1020,7 +1018,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - this.check_no_isolation("rmdir")?; + this.check_no_isolation("`rmdir`")?; let path = this.read_path_from_c_str(this.read_scalar(path_op)?.check_init()?)?; @@ -1032,7 +1030,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn opendir(&mut self, name_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); - this.check_no_isolation("opendir")?; + this.check_no_isolation("`opendir`")?; let name = this.read_path_from_c_str(this.read_scalar(name_op)?.check_init()?)?; @@ -1063,7 +1061,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); this.assert_target_os("linux", "readdir64_r"); - this.check_no_isolation("readdir64_r")?; + this.check_no_isolation("`readdir64_r`")?; let dirp = this.read_scalar(dirp_op)?.to_machine_usize(this)?; @@ -1150,7 +1148,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); this.assert_target_os("macos", "readdir_r"); - this.check_no_isolation("readdir_r")?; + this.check_no_isolation("`readdir_r`")?; let dirp = this.read_scalar(dirp_op)?.to_machine_usize(this)?; @@ -1233,7 +1231,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn closedir(&mut self, dirp_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - this.check_no_isolation("closedir")?; + this.check_no_isolation("`closedir`")?; let dirp = this.read_scalar(dirp_op)?.to_machine_usize(this)?; @@ -1252,7 +1250,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - this.check_no_isolation("ftruncate64")?; + this.check_no_isolation("`ftruncate64`")?; let fd = this.read_scalar(fd_op)?.to_i32()?; let length = this.read_scalar(length_op)?.to_i64()?; @@ -1287,7 +1285,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); - this.check_no_isolation("fsync")?; + this.check_no_isolation("`fsync`")?; let fd = this.read_scalar(fd_op)?.to_i32()?; if let Some(file_descriptor) = this.machine.file_handler.handles.get(&fd) { @@ -1303,7 +1301,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn fdatasync(&mut self, fd_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - this.check_no_isolation("fdatasync")?; + this.check_no_isolation("`fdatasync`")?; let fd = this.read_scalar(fd_op)?.to_i32()?; if let Some(file_descriptor) = this.machine.file_handler.handles.get(&fd) { @@ -1325,7 +1323,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - this.check_no_isolation("sync_file_range")?; + this.check_no_isolation("`sync_file_range`")?; let fd = this.read_scalar(fd_op)?.to_i32()?; let offset = this.read_scalar(offset_op)?.to_i64()?; diff --git a/src/shims/posix/linux/sync.rs b/src/shims/posix/linux/sync.rs index d7ecb45279deb..ef172fa2a6715 100644 --- a/src/shims/posix/linux/sync.rs +++ b/src/shims/posix/linux/sync.rs @@ -55,6 +55,7 @@ pub fn futex<'tcx>( let timeout_time = if this.is_null(this.read_scalar(timeout)?.check_init()?)? { None } else { + this.check_no_isolation("`syscall(SYS_FUTEX, op=FUTEX_WAIT)` with timeout")?; let duration = match this.read_timespec(timeout)? { Some(duration) => duration, None => { @@ -64,7 +65,6 @@ pub fn futex<'tcx>( return Ok(()); } }; - this.check_no_isolation("FUTEX_WAIT with timeout")?; Some(if op & futex_realtime != 0 { Time::RealTime(SystemTime::now().checked_add(duration).unwrap()) } else { diff --git a/src/shims/posix/sync.rs b/src/shims/posix/sync.rs index 6918fb7fd7eca..a0b5db42ed066 100644 --- a/src/shims/posix/sync.rs +++ b/src/shims/posix/sync.rs @@ -690,7 +690,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - this.check_no_isolation("pthread_cond_timedwait")?; + this.check_no_isolation("`pthread_cond_timedwait`")?; let id = cond_get_or_create_id(this, cond_op)?; let mutex_id = mutex_get_or_create_id(this, mutex_op)?; diff --git a/src/shims/time.rs b/src/shims/time.rs index 9d6d6ed38daab..806fa65d1564c 100644 --- a/src/shims/time.rs +++ b/src/shims/time.rs @@ -22,7 +22,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); this.assert_target_os("linux", "clock_gettime"); - this.check_no_isolation("clock_gettime")?; + this.check_no_isolation("`clock_gettime`")?; let clk_id = this.read_scalar(clk_id_op)?.to_i32()?; let tp = this.deref_operand(tp_op)?; @@ -60,7 +60,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); this.assert_target_os("macos", "gettimeofday"); - this.check_no_isolation("gettimeofday")?; + this.check_no_isolation("`gettimeofday`")?; // Using tz is obsolete and should always be null let tz = this.read_scalar(tz_op)?.check_init()?; @@ -91,7 +91,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); this.assert_target_os("windows", "GetSystemTimeAsFileTime"); - this.check_no_isolation("GetSystemTimeAsFileTime")?; + this.check_no_isolation("`GetSystemTimeAsFileTime`")?; let NANOS_PER_SEC = this.eval_windows_u64("time", "NANOS_PER_SEC")?; let INTERVALS_PER_SEC = this.eval_windows_u64("time", "INTERVALS_PER_SEC")?; @@ -119,7 +119,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); this.assert_target_os("windows", "QueryPerformanceCounter"); - this.check_no_isolation("QueryPerformanceCounter")?; + this.check_no_isolation("`QueryPerformanceCounter`")?; // QueryPerformanceCounter uses a hardware counter as its basis. // Miri will emulate a counter with a resolution of 1 nanosecond. @@ -135,7 +135,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); this.assert_target_os("windows", "QueryPerformanceFrequency"); - this.check_no_isolation("QueryPerformanceFrequency")?; + this.check_no_isolation("`QueryPerformanceFrequency`")?; // Retrieves the frequency of the hardware performance counter. // The frequency of the performance counter is fixed at system boot and @@ -150,7 +150,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_ref(); this.assert_target_os("macos", "mach_absolute_time"); - this.check_no_isolation("mach_absolute_time")?; + this.check_no_isolation("`mach_absolute_time`")?; // This returns a u64, with time units determined dynamically by `mach_timebase_info`. // We return plain nanoseconds. @@ -163,7 +163,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); this.assert_target_os("macos", "mach_timebase_info"); - this.check_no_isolation("mach_timebase_info")?; + this.check_no_isolation("`mach_timebase_info`")?; let info = this.deref_operand(info_op)?; @@ -188,7 +188,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); - this.check_no_isolation("nanosleep")?; + this.check_no_isolation("`nanosleep`")?; let duration = match this.read_timespec(req_op)? { Some(duration) => duration, diff --git a/tests/compile-fail/fs/isolated_file.rs b/tests/compile-fail/fs/isolated_file.rs index 4c6adc8bf4062..5b7270f18931c 100644 --- a/tests/compile-fail/fs/isolated_file.rs +++ b/tests/compile-fail/fs/isolated_file.rs @@ -1,5 +1,5 @@ // ignore-windows: File handling is not implemented yet -// error-pattern: open not available when isolation is enabled +// error-pattern: `open` not available when isolation is enabled fn main() { let _file = std::fs::File::open("file.txt").unwrap(); diff --git a/tests/compile-fail/fs/isolated_stdin.rs b/tests/compile-fail/fs/isolated_stdin.rs index 19ce064089aaa..4098a104761ee 100644 --- a/tests/compile-fail/fs/isolated_stdin.rs +++ b/tests/compile-fail/fs/isolated_stdin.rs @@ -7,7 +7,7 @@ extern crate libc; fn main() -> std::io::Result<()> { let mut bytes = [0u8; 512]; unsafe { - libc::read(0, bytes.as_mut_ptr() as *mut libc::c_void, 512); //~ ERROR read not available when isolation is enabled + libc::read(0, bytes.as_mut_ptr() as *mut libc::c_void, 512); //~ ERROR `read` from stdin not available when isolation is enabled } Ok(()) } From a4cbbddc8e45ea4271636bc42fea8baf8bc51523 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 3 Oct 2020 15:27:23 +0200 Subject: [PATCH 2362/3747] merge parking test into general synchronization test --- tests/run-pass/concurrency/parking.rs | 37 ----------------------- tests/run-pass/concurrency/parking.stderr | 2 -- tests/run-pass/concurrency/sync.rs | 30 ++++++++++++++++++ 3 files changed, 30 insertions(+), 39 deletions(-) delete mode 100644 tests/run-pass/concurrency/parking.rs delete mode 100644 tests/run-pass/concurrency/parking.stderr diff --git a/tests/run-pass/concurrency/parking.rs b/tests/run-pass/concurrency/parking.rs deleted file mode 100644 index 1ed742931fe6b..0000000000000 --- a/tests/run-pass/concurrency/parking.rs +++ /dev/null @@ -1,37 +0,0 @@ -// ignore-windows: Concurrency on Windows is not supported yet. -// compile-flags: -Zmiri-disable-isolation - -use std::thread; -use std::time::{Duration, Instant}; - -// Normally, waiting in park/park_timeout may spuriously wake up early, but we -// know Miri's timed synchronization primitives do not do that. - -fn park_timeout() { - let start = Instant::now(); - - thread::park_timeout(Duration::from_millis(200)); - - assert!((200..500).contains(&start.elapsed().as_millis())); -} - -fn park_unpark() { - let t1 = thread::current(); - let t2 = thread::spawn(move || { - thread::park(); - thread::sleep(Duration::from_millis(200)); - t1.unpark(); - }); - - let start = Instant::now(); - - t2.thread().unpark(); - thread::park(); - - assert!((200..500).contains(&start.elapsed().as_millis())); -} - -fn main() { - park_timeout(); - park_unpark(); -} diff --git a/tests/run-pass/concurrency/parking.stderr b/tests/run-pass/concurrency/parking.stderr deleted file mode 100644 index 2dbfb7721d368..0000000000000 --- a/tests/run-pass/concurrency/parking.stderr +++ /dev/null @@ -1,2 +0,0 @@ -warning: thread support is experimental. For example, Miri does not detect data races yet. - diff --git a/tests/run-pass/concurrency/sync.rs b/tests/run-pass/concurrency/sync.rs index b36ad27ebe198..69943e5495e2e 100644 --- a/tests/run-pass/concurrency/sync.rs +++ b/tests/run-pass/concurrency/sync.rs @@ -312,6 +312,34 @@ fn check_rwlock_unlock_bug2() { h.join().unwrap(); } +fn park_timeout() { + let start = Instant::now(); + + thread::park_timeout(Duration::from_millis(200)); + // Normally, waiting in park/park_timeout may spuriously wake up early, but we + // know Miri's timed synchronization primitives do not do that. + + assert!((200..500).contains(&start.elapsed().as_millis())); +} + +fn park_unpark() { + let t1 = thread::current(); + let t2 = thread::spawn(move || { + thread::park(); + thread::sleep(Duration::from_millis(200)); + t1.unpark(); + }); + + let start = Instant::now(); + + t2.thread().unpark(); + thread::park(); + // Normally, waiting in park/park_timeout may spuriously wake up early, but we + // know Miri's timed synchronization primitives do not do that. + + assert!((200..500).contains(&start.elapsed().as_millis())); +} + fn main() { check_barriers(); check_conditional_variables_notify_one(); @@ -327,4 +355,6 @@ fn main() { check_once(); check_rwlock_unlock_bug1(); check_rwlock_unlock_bug2(); + park_timeout(); + park_unpark(); } From 2b2a3a0cc11c40a8fd6d8015d0b7fb11b30d8156 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 3 Oct 2020 16:01:53 +0200 Subject: [PATCH 2363/3747] check that all syscall arguments are scalars --- src/bin/miri.rs | 2 +- src/shims/posix/linux/foreign_items.rs | 32 ++++++++++++++------------ src/shims/posix/linux/sync.rs | 10 ++++---- 3 files changed, 23 insertions(+), 21 deletions(-) diff --git a/src/bin/miri.rs b/src/bin/miri.rs index e3317d0d4d680..7b417990af867 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -221,7 +221,7 @@ fn main() { ), FromHexError::OddLength => panic!("-Zmiri-seed should have an even number of digits"), - err => panic!("Unknown error decoding -Zmiri-seed as hex: {:?}", err), + err => panic!("unknown error decoding -Zmiri-seed as hex: {:?}", err), }); if seed_raw.len() > 8 { panic!(format!( diff --git a/src/shims/posix/linux/foreign_items.rs b/src/shims/posix/linux/foreign_items.rs index 364cfde6c0721..04efa79b9d93f 100644 --- a/src/shims/posix/linux/foreign_items.rs +++ b/src/shims/posix/linux/foreign_items.rs @@ -113,16 +113,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Dynamically invoked syscalls "syscall" => { - // FIXME: The libc syscall() function is a variadic function. - // It's valid to call it with more arguments than a syscall - // needs, so none of these syscalls should use check_arg_count. - // It's even valid to call it with the wrong type of arguments, - // as long as they'd end up in the same place with the calling - // convention used. (E.g. using a `usize` instead of a pointer.) - // It's not directly clear which number, size, and type of arguments - // are acceptable in which cases and which aren't. (E.g. some - // types might take up the space of two registers.) - // So this needs to be researched first. + // The syscall variadic function is legal to call with more arguments than needed, + // extra arguments are simply ignored. However, all arguments need to be scalars; + // other types might be treated differently by the calling convention. + for arg in args { + if !matches!(arg.layout.abi, rustc_target::abi::Abi::Scalar(_)) { + throw_ub_format!("`syscall` arguments must all have scalar layout, but {} does not", arg.layout.ty); + } + } let sys_getrandom = this .eval_libc("SYS_getrandom")? @@ -144,22 +142,26 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // is called if a `HashMap` is created the regular way (e.g. HashMap). id if id == sys_getrandom => { // The first argument is the syscall id, so skip over it. - let &[_, ptr, len, flags] = check_arg_count(args)?; - getrandom(this, ptr, len, flags, dest)?; + if args.len() < 4 { + throw_ub_format!("incorrect number of arguments for `getrandom` syscall: got {}, expected at least 4", args.len()); + } + getrandom(this, args[1], args[2], args[3], dest)?; } // `statx` is used by `libstd` to retrieve metadata information on `linux` // instead of using `stat`,`lstat` or `fstat` as on `macos`. id if id == sys_statx => { // The first argument is the syscall id, so skip over it. - let &[_, dirfd, pathname, flags, mask, statxbuf] = check_arg_count(args)?; - let result = this.linux_statx(dirfd, pathname, flags, mask, statxbuf)?; + if args.len() < 6 { + throw_ub_format!("incorrect number of arguments for `statx` syscall: got {}, expected at least 6", args.len()); + } + let result = this.linux_statx(args[1], args[2], args[3], args[4], args[5])?; this.write_scalar(Scalar::from_machine_isize(result.into(), this), dest)?; } // `futex` is used by some synchonization primitives. id if id == sys_futex => { futex(this, args, dest)?; } - id => throw_unsup_format!("miri does not support syscall ID {}", id), + id => throw_unsup_format!("Miri does not support syscall ID {}", id), } } diff --git a/src/shims/posix/linux/sync.rs b/src/shims/posix/linux/sync.rs index ef172fa2a6715..9d124872f5cc9 100644 --- a/src/shims/posix/linux/sync.rs +++ b/src/shims/posix/linux/sync.rs @@ -17,8 +17,8 @@ pub fn futex<'tcx>( // may or may not be left out from the `syscall()` call. // Therefore we don't use `check_arg_count` here, but only check for the // number of arguments to fall within a range. - if !(4..=7).contains(&args.len()) { - throw_ub_format!("incorrect number of arguments for futex syscall: got {}, expected between 4 and 7 (inclusive)", args.len()); + if args.len() < 4 { + throw_ub_format!("incorrect number of arguments for `futex` syscall: got {}, expected at least 4", args.len()); } // The first three arguments (after the syscall number itself) are the same to all futex operations: @@ -49,13 +49,13 @@ pub fn futex<'tcx>( // or *timeout expires. `timeout == null` for an infinite timeout. op if op & !futex_realtime == futex_wait => { if args.len() < 5 { - throw_ub_format!("incorrect number of arguments for FUTEX_WAIT syscall: got {}, expected at least 5", args.len()); + throw_ub_format!("incorrect number of arguments for `futex` syscall with `op=FUTEX_WAIT`: got {}, expected at least 5", args.len()); } let timeout = args[4]; let timeout_time = if this.is_null(this.read_scalar(timeout)?.check_init()?)? { None } else { - this.check_no_isolation("`syscall(SYS_FUTEX, op=FUTEX_WAIT)` with timeout")?; + this.check_no_isolation("`futex` syscall with `op=FUTEX_WAIT` and non-null timeout")?; let duration = match this.read_timespec(timeout)? { Some(duration) => duration, None => { @@ -126,7 +126,7 @@ pub fn futex<'tcx>( } this.write_scalar(Scalar::from_machine_isize(n, this), dest)?; } - op => throw_unsup_format!("miri does not support SYS_futex operation {}", op), + op => throw_unsup_format!("Miri does not support `futex` syscall with op={}", op), } Ok(()) From 1c9db025082283c963f129a747bcb10b532feebb Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Sun, 4 Oct 2020 18:53:13 +0700 Subject: [PATCH 2364/3747] Add a dummy actions template to enable it on CI --- .github/workflows/ci.yml | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 .github/workflows/ci.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000000000..101618d1a7aac --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,35 @@ +name: CI + +on: + push: + # Run in PRs and for bors, but not on master. + branches: + - 'auto' + - 'try' + pull_request: + branches: + - 'master' + schedule: + # Use to conveniently edit cron schedule. + - cron: "0 7 * * *" # At 07:00 UTC every day. + +jobs: + build: + runs-on: ${{ matrix.os }} + env: + RUST_BACKTRACE: 1 + strategy: + matrix: + build: [linux64, macos, win32] + include: + - build: linux64 + os: ubuntu-latest + host_target: x86_64-unknown-linux-gnu + - build: macos + os: macos-latest + host_target: x86_64-apple-darwin + - build: win32 + os: windows-latest + host_target: i686-pc-windows-msvc + steps: + - uses: actions/checkout@v2 From 78bc89b4fc3713869e421048a439e4ca7c6c1bfe Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Mon, 28 Sep 2020 15:02:54 -0400 Subject: [PATCH 2365/3747] Implement `readlink` Due to the truncating behavior of `readlink`, I was not able to directly use any of the existing C-cstring helper functions. --- src/shims/os_str.rs | 33 ++++++++++++----------- src/shims/posix/foreign_items.rs | 5 ++++ src/shims/posix/fs.rs | 33 +++++++++++++++++++++++ tests/run-pass/fs.rs | 45 +++++++++++++++++++++++++++++++- 4 files changed, 100 insertions(+), 16 deletions(-) diff --git a/src/shims/os_str.rs b/src/shims/os_str.rs index 73dc9119a820f..b3d40392ac685 100644 --- a/src/shims/os_str.rs +++ b/src/shims/os_str.rs @@ -118,22 +118,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx scalar: Scalar, size: u64, ) -> InterpResult<'tcx, (bool, u64)> { - #[cfg(unix)] - fn os_str_to_bytes<'tcx, 'a>(os_str: &'a OsStr) -> InterpResult<'tcx, &'a [u8]> { - Ok(os_str.as_bytes()) - } - #[cfg(not(unix))] - fn os_str_to_bytes<'tcx, 'a>(os_str: &'a OsStr) -> InterpResult<'tcx, &'a [u8]> { - // On non-unix platforms the best we can do to transform bytes from/to OS strings is to do the - // intermediate transformation into strings. Which invalidates non-utf8 paths that are actually - // valid. - os_str - .to_str() - .map(|s| s.as_bytes()) - .ok_or_else(|| err_unsup_format!("{:?} is not a valid utf-8 string", os_str).into()) - } - let bytes = os_str_to_bytes(os_str)?; + let bytes = self.os_str_to_bytes(os_str)?; // If `size` is smaller or equal than `bytes.len()`, writing `bytes` plus the required null // terminator to memory using the `ptr` pointer would cause an out-of-bounds access. let string_length = u64::try_from(bytes.len()).unwrap(); @@ -265,4 +251,21 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let os_str = convert_path_separator(Cow::Borrowed(path.as_os_str()), &this.tcx.sess.target.target.target_os, Pathconversion::HostToTarget); this.write_os_str_to_wide_str(&os_str, scalar, size) } + + #[cfg(unix)] + fn os_str_to_bytes<'a>(&mut self, os_str: &'a OsStr) -> InterpResult<'tcx, &'a [u8]> { + Ok(os_str.as_bytes()) + } + + #[cfg(not(unix))] + fn os_str_to_bytes<'a>(&mut self, os_str: &'a OsStr) -> InterpResult<'tcx, &'a [u8]> { + // On non-unix platforms the best we can do to transform bytes from/to OS strings is to do the + // intermediate transformation into strings. Which invalidates non-utf8 paths that are actually + // valid. + os_str + .to_str() + .map(|s| s.as_bytes()) + .ok_or_else(|| err_unsup_format!("{:?} is not a valid utf-8 string", os_str).into()) + } + } diff --git a/src/shims/posix/foreign_items.rs b/src/shims/posix/foreign_items.rs index 26c743b360e06..177678f03d74c 100644 --- a/src/shims/posix/foreign_items.rs +++ b/src/shims/posix/foreign_items.rs @@ -123,6 +123,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let result = this.fdatasync(fd)?; this.write_scalar(Scalar::from_i32(result), dest)?; } + "readlink" => { + let &[pathname, buf, bufsize] = check_arg_count(args)?; + let result = this.readlink(pathname, buf, bufsize)?; + this.write_scalar(Scalar::from_machine_isize(result, this), dest)?; + } // Allocation "posix_memalign" => { diff --git a/src/shims/posix/fs.rs b/src/shims/posix/fs.rs index 88597b4a39814..a5b9642d0604e 100644 --- a/src/shims/posix/fs.rs +++ b/src/shims/posix/fs.rs @@ -1353,6 +1353,39 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.handle_not_found() } } + + fn readlink( + &mut self, + pathname_op: OpTy<'tcx, Tag>, + buf_op: OpTy<'tcx, Tag>, + bufsize_op: OpTy<'tcx, Tag> + ) -> InterpResult<'tcx, i64> { + let this = self.eval_context_mut(); + + this.check_no_isolation("readlink")?; + + let pathname = this.read_path_from_c_str(this.read_scalar(pathname_op)?.check_init()?)?; + let buf = this.read_scalar(buf_op)?.check_init()?; + let bufsize = this.read_scalar(bufsize_op)?.to_machine_usize(this)?; + + let result = std::fs::read_link(pathname); + match result { + Ok(resolved) => { + let mut path_bytes = this.os_str_to_bytes(resolved.as_ref())?; + if path_bytes.len() > bufsize as usize { + path_bytes = &path_bytes[..(bufsize as usize)] + } + // 'readlink' truncates the resolved path if + // the provided buffer is not large enough + this.memory.write_bytes(buf, path_bytes.iter().copied())?; + Ok(path_bytes.len() as i64) + } + Err(e) => { + this.set_last_error_from_io_error(e)?; + Ok(-1) + } + } + } } /// Extracts the number of seconds and nanoseconds elapsed between `time` and the unix epoch when diff --git a/tests/run-pass/fs.rs b/tests/run-pass/fs.rs index caa9bffc2bc86..8f750847b203b 100644 --- a/tests/run-pass/fs.rs +++ b/tests/run-pass/fs.rs @@ -1,12 +1,18 @@ // ignore-windows: File handling is not implemented yet // compile-flags: -Zmiri-disable-isolation +#![feature(rustc_private)] + use std::fs::{ File, create_dir, OpenOptions, read_dir, remove_dir, remove_dir_all, remove_file, rename, }; -use std::io::{Read, Write, ErrorKind, Result, Seek, SeekFrom}; +use std::ffi::CString; +use std::io::{Read, Write, Error, ErrorKind, Result, Seek, SeekFrom}; use std::path::{PathBuf, Path}; +extern crate libc; + + fn main() { test_file(); test_file_clone(); @@ -215,6 +221,43 @@ fn test_symlink() { let mut contents = Vec::new(); symlink_file.read_to_end(&mut contents).unwrap(); assert_eq!(bytes, contents.as_slice()); + + + #[cfg(unix)] + { + use std::os::unix::ffi::OsStrExt; + + let expected_path = path.as_os_str().as_bytes(); + + // Test that the expected string gets written to a buffer of proper + // length, and that a trailing null byte is not written + let symlink_c_str = CString::new(symlink_path.as_os_str().as_bytes()).unwrap(); + let symlink_c_ptr = symlink_c_str.as_ptr(); + + // Make the buf one byte larger than it needs to be, + // and check that the last byte is not overwritten + let mut large_buf = vec![0xFF; expected_path.len() + 1]; + let res = unsafe { libc::readlink(symlink_c_ptr, large_buf.as_mut_ptr().cast(), large_buf.len()) }; + assert_eq!(res, large_buf.len() as isize - 1); + // Check that the resovled path was properly written into the buf + assert_eq!(&large_buf[..(large_buf.len() - 1)], expected_path); + assert_eq!(large_buf.last(), Some(&0xFF)); + + // Test that the resolved path is truncated if the provided buffer + // is too small. + let mut small_buf = [0u8; 2]; + let res = unsafe { libc::readlink(symlink_c_ptr, small_buf.as_mut_ptr().cast(), small_buf.len()) }; + assert_eq!(res, small_buf.len() as isize); + assert_eq!(small_buf, &expected_path[..small_buf.len()]); + + // Test that we report a proper error for a missing path. + let bad_path = CString::new("MIRI_MISSING_FILE_NAME").unwrap(); + let res = unsafe { libc::readlink(bad_path.as_ptr(), small_buf.as_mut_ptr().cast(), small_buf.len()) }; + assert_eq!(res, -1); + assert_eq!(Error::last_os_error().kind(), ErrorKind::NotFound); + } + + // Test that metadata of a symbolic link is correct. check_metadata(bytes, &symlink_path).unwrap(); // Test that the metadata of a symbolic link is correct when not following it. From 186d59a3ecc59e2994f28b1bd2f1110be20c51c1 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Sat, 3 Oct 2020 12:51:46 -0400 Subject: [PATCH 2366/3747] Move some helper functions around --- src/shims/os_str.rs | 58 ++++++++++++++++++++++----------------------- 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/src/shims/os_str.rs b/src/shims/os_str.rs index b3d40392ac685..bb5e7078291fb 100644 --- a/src/shims/os_str.rs +++ b/src/shims/os_str.rs @@ -62,6 +62,18 @@ fn convert_path_separator<'a>( impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { + + #[cfg(unix)] + fn bytes_to_os_str<'a>(&self, bytes: &'a [u8]) -> InterpResult<'tcx, &'a OsStr> { + Ok(OsStr::from_bytes(bytes)) + } + #[cfg(not(unix))] + fn bytes_to_os_str<'a>(&self, bytes: &'a [u8]) -> InterpResult<'tcx, &'a OsStr> { + let s = std::str::from_utf8(bytes) + .map_err(|_| err_unsup_format!("{:?} is not a valid utf-8 string", bytes))?; + Ok(OsStr::new(s)) + } + /// Helper function to read an OsString from a null-terminated sequence of bytes, which is what /// the Unix APIs usually handle. fn read_os_str_from_c_str<'a>(&'a self, scalar: Scalar) -> InterpResult<'tcx, &'a OsStr> @@ -69,20 +81,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx 'tcx: 'a, 'mir: 'a, { - #[cfg(unix)] - fn bytes_to_os_str<'tcx, 'a>(bytes: &'a [u8]) -> InterpResult<'tcx, &'a OsStr> { - Ok(OsStr::from_bytes(bytes)) - } - #[cfg(not(unix))] - fn bytes_to_os_str<'tcx, 'a>(bytes: &'a [u8]) -> InterpResult<'tcx, &'a OsStr> { - let s = std::str::from_utf8(bytes) - .map_err(|_| err_unsup_format!("{:?} is not a valid utf-8 string", bytes))?; - Ok(OsStr::new(s)) - } - let this = self.eval_context_ref(); let bytes = this.memory.read_c_str(scalar)?; - bytes_to_os_str(bytes) + self.bytes_to_os_str(bytes) } /// Helper function to read an OsString from a 0x0000-terminated sequence of u16, @@ -107,6 +108,22 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx u16vec_to_osstring(u16_vec) } + #[cfg(unix)] + fn os_str_to_bytes<'a>(&self, os_str: &'a OsStr) -> InterpResult<'tcx, &'a [u8]> { + Ok(os_str.as_bytes()) + } + + #[cfg(not(unix))] + fn os_str_to_bytes<'a>(&self, os_str: &'a OsStr) -> InterpResult<'tcx, &'a [u8]> { + // On non-unix platforms the best we can do to transform bytes from/to OS strings is to do the + // intermediate transformation into strings. Which invalidates non-utf8 paths that are actually + // valid. + os_str + .to_str() + .map(|s| s.as_bytes()) + .ok_or_else(|| err_unsup_format!("{:?} is not a valid utf-8 string", os_str).into()) + } + /// Helper function to write an OsStr as a null-terminated sequence of bytes, which is what /// the Unix APIs usually handle. This function returns `Ok((false, length))` without trying /// to write if `size` is not large enough to fit the contents of `os_string` plus a null @@ -251,21 +268,4 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let os_str = convert_path_separator(Cow::Borrowed(path.as_os_str()), &this.tcx.sess.target.target.target_os, Pathconversion::HostToTarget); this.write_os_str_to_wide_str(&os_str, scalar, size) } - - #[cfg(unix)] - fn os_str_to_bytes<'a>(&mut self, os_str: &'a OsStr) -> InterpResult<'tcx, &'a [u8]> { - Ok(os_str.as_bytes()) - } - - #[cfg(not(unix))] - fn os_str_to_bytes<'a>(&mut self, os_str: &'a OsStr) -> InterpResult<'tcx, &'a [u8]> { - // On non-unix platforms the best we can do to transform bytes from/to OS strings is to do the - // intermediate transformation into strings. Which invalidates non-utf8 paths that are actually - // valid. - os_str - .to_str() - .map(|s| s.as_bytes()) - .ok_or_else(|| err_unsup_format!("{:?} is not a valid utf-8 string", os_str).into()) - } - } From 8b89c7e1da6231b998addb8d0dab43f68c1975f0 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Sat, 3 Oct 2020 12:52:06 -0400 Subject: [PATCH 2367/3747] Use panicking coversions instead of `as` --- src/shims/posix/fs.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/shims/posix/fs.rs b/src/shims/posix/fs.rs index a5b9642d0604e..1ca05a461bfbc 100644 --- a/src/shims/posix/fs.rs +++ b/src/shims/posix/fs.rs @@ -1372,13 +1372,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx match result { Ok(resolved) => { let mut path_bytes = this.os_str_to_bytes(resolved.as_ref())?; - if path_bytes.len() > bufsize as usize { - path_bytes = &path_bytes[..(bufsize as usize)] + let bufsize: usize = bufsize.try_into().unwrap(); + if path_bytes.len() > bufsize { + path_bytes = &path_bytes[..bufsize] } // 'readlink' truncates the resolved path if // the provided buffer is not large enough this.memory.write_bytes(buf, path_bytes.iter().copied())?; - Ok(path_bytes.len() as i64) + Ok(path_bytes.len().try_into().unwrap()) } Err(e) => { this.set_last_error_from_io_error(e)?; From 0e59b6f6731d80151dfcf3572e93ea52430d8d9c Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Sat, 3 Oct 2020 12:56:32 -0400 Subject: [PATCH 2368/3747] Merge `fs` and `fs_libc` tests --- tests/run-pass/fs.rs | 11 +++++++++++ tests/run-pass/{fs_libc.stderr => fs.stderr} | 0 tests/run-pass/{fs_libc.stdout => fs.stdout} | 0 tests/run-pass/fs_libc.rs | 20 -------------------- 4 files changed, 11 insertions(+), 20 deletions(-) rename tests/run-pass/{fs_libc.stderr => fs.stderr} (100%) rename tests/run-pass/{fs_libc.stdout => fs.stdout} (100%) delete mode 100644 tests/run-pass/fs_libc.rs diff --git a/tests/run-pass/fs.rs b/tests/run-pass/fs.rs index 8f750847b203b..ca3c6a6d29171 100644 --- a/tests/run-pass/fs.rs +++ b/tests/run-pass/fs.rs @@ -25,6 +25,7 @@ fn main() { test_errors(); test_rename(); test_directory(); + test_dup_stdout_stderr(); } fn tmp() -> PathBuf { @@ -335,3 +336,13 @@ fn test_directory() { // Reading the metadata of a non-existent directory should fail with a "not found" error. assert_eq!(ErrorKind::NotFound, check_metadata(&[], &dir_path).unwrap_err().kind()); } + +fn test_dup_stdout_stderr() { + let bytes = b"hello dup fd\n"; + unsafe { + let new_stdout = libc::fcntl(1, libc::F_DUPFD, 0); + let new_stderr = libc::fcntl(2, libc::F_DUPFD, 0); + libc::write(new_stdout, bytes.as_ptr() as *const libc::c_void, bytes.len()); + libc::write(new_stderr, bytes.as_ptr() as *const libc::c_void, bytes.len()); + } +} diff --git a/tests/run-pass/fs_libc.stderr b/tests/run-pass/fs.stderr similarity index 100% rename from tests/run-pass/fs_libc.stderr rename to tests/run-pass/fs.stderr diff --git a/tests/run-pass/fs_libc.stdout b/tests/run-pass/fs.stdout similarity index 100% rename from tests/run-pass/fs_libc.stdout rename to tests/run-pass/fs.stdout diff --git a/tests/run-pass/fs_libc.rs b/tests/run-pass/fs_libc.rs deleted file mode 100644 index e3deb7a5bcd8a..0000000000000 --- a/tests/run-pass/fs_libc.rs +++ /dev/null @@ -1,20 +0,0 @@ -// ignore-windows -// compile-flags: -Zmiri-disable-isolation - -#![feature(rustc_private)] - -extern crate libc; - -fn main() { - dup_stdout_stderr_test(); -} - -fn dup_stdout_stderr_test() { - let bytes = b"hello dup fd\n"; - unsafe { - let new_stdout = libc::fcntl(1, libc::F_DUPFD, 0); - let new_stderr = libc::fcntl(2, libc::F_DUPFD, 0); - libc::write(new_stdout, bytes.as_ptr() as *const libc::c_void, bytes.len()); - libc::write(new_stderr, bytes.as_ptr() as *const libc::c_void, bytes.len()); - } -} From 5fc5490bc84d02408c8fbcc6bf8edd49af06c9a4 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Sat, 3 Oct 2020 12:59:23 -0400 Subject: [PATCH 2369/3747] Add trailing punctuation Co-authored-by: Ralf Jung --- tests/run-pass/fs.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/run-pass/fs.rs b/tests/run-pass/fs.rs index ca3c6a6d29171..7cccf900a1bf6 100644 --- a/tests/run-pass/fs.rs +++ b/tests/run-pass/fs.rs @@ -231,16 +231,16 @@ fn test_symlink() { let expected_path = path.as_os_str().as_bytes(); // Test that the expected string gets written to a buffer of proper - // length, and that a trailing null byte is not written + // length, and that a trailing null byte is not written. let symlink_c_str = CString::new(symlink_path.as_os_str().as_bytes()).unwrap(); let symlink_c_ptr = symlink_c_str.as_ptr(); // Make the buf one byte larger than it needs to be, - // and check that the last byte is not overwritten + // and check that the last byte is not overwritten. let mut large_buf = vec![0xFF; expected_path.len() + 1]; let res = unsafe { libc::readlink(symlink_c_ptr, large_buf.as_mut_ptr().cast(), large_buf.len()) }; assert_eq!(res, large_buf.len() as isize - 1); - // Check that the resovled path was properly written into the buf + // Check that the resovled path was properly written into the buf. assert_eq!(&large_buf[..(large_buf.len() - 1)], expected_path); assert_eq!(large_buf.last(), Some(&0xFF)); From 462f58298a3a75c15509bf57d8935c3954be6685 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Sun, 4 Oct 2020 08:00:26 -0400 Subject: [PATCH 2370/3747] Make helper functions freestanding --- src/shims/os_str.rs | 59 ++++++++++++++++++++++--------------------- src/shims/posix/fs.rs | 2 +- 2 files changed, 31 insertions(+), 30 deletions(-) diff --git a/src/shims/os_str.rs b/src/shims/os_str.rs index bb5e7078291fb..56dcbb9e32f78 100644 --- a/src/shims/os_str.rs +++ b/src/shims/os_str.rs @@ -60,20 +60,36 @@ fn convert_path_separator<'a>( }; } +#[cfg(unix)] +pub fn os_str_to_bytes<'a, 'tcx>(os_str: &'a OsStr) -> InterpResult<'tcx, &'a [u8]> { + Ok(os_str.as_bytes()) +} + +#[cfg(not(unix))] +pub fn os_str_to_bytes<'a, 'tcx>(os_str: &'a OsStr) -> InterpResult<'tcx, &'a [u8]> { + // On non-unix platforms the best we can do to transform bytes from/to OS strings is to do the + // intermediate transformation into strings. Which invalidates non-utf8 paths that are actually + // valid. + os_str + .to_str() + .map(|s| s.as_bytes()) + .ok_or_else(|| err_unsup_format!("{:?} is not a valid utf-8 string", os_str).into()) +} + +#[cfg(unix)] +pub fn bytes_to_os_str<'a, 'tcx>(bytes: &'a [u8]) -> InterpResult<'tcx, &'a OsStr> { + Ok(OsStr::from_bytes(bytes)) +} +#[cfg(not(unix))] +pub fn bytes_to_os_str<'a, 'tcx>(bytes: &'a [u8]) -> InterpResult<'tcx, &'a OsStr> { + let s = std::str::from_utf8(bytes) + .map_err(|_| err_unsup_format!("{:?} is not a valid utf-8 string", bytes))?; + Ok(OsStr::new(s)) +} + impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { - #[cfg(unix)] - fn bytes_to_os_str<'a>(&self, bytes: &'a [u8]) -> InterpResult<'tcx, &'a OsStr> { - Ok(OsStr::from_bytes(bytes)) - } - #[cfg(not(unix))] - fn bytes_to_os_str<'a>(&self, bytes: &'a [u8]) -> InterpResult<'tcx, &'a OsStr> { - let s = std::str::from_utf8(bytes) - .map_err(|_| err_unsup_format!("{:?} is not a valid utf-8 string", bytes))?; - Ok(OsStr::new(s)) - } - /// Helper function to read an OsString from a null-terminated sequence of bytes, which is what /// the Unix APIs usually handle. fn read_os_str_from_c_str<'a>(&'a self, scalar: Scalar) -> InterpResult<'tcx, &'a OsStr> @@ -83,7 +99,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx { let this = self.eval_context_ref(); let bytes = this.memory.read_c_str(scalar)?; - self.bytes_to_os_str(bytes) + bytes_to_os_str(bytes) } /// Helper function to read an OsString from a 0x0000-terminated sequence of u16, @@ -108,22 +124,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx u16vec_to_osstring(u16_vec) } - #[cfg(unix)] - fn os_str_to_bytes<'a>(&self, os_str: &'a OsStr) -> InterpResult<'tcx, &'a [u8]> { - Ok(os_str.as_bytes()) - } - - #[cfg(not(unix))] - fn os_str_to_bytes<'a>(&self, os_str: &'a OsStr) -> InterpResult<'tcx, &'a [u8]> { - // On non-unix platforms the best we can do to transform bytes from/to OS strings is to do the - // intermediate transformation into strings. Which invalidates non-utf8 paths that are actually - // valid. - os_str - .to_str() - .map(|s| s.as_bytes()) - .ok_or_else(|| err_unsup_format!("{:?} is not a valid utf-8 string", os_str).into()) - } - /// Helper function to write an OsStr as a null-terminated sequence of bytes, which is what /// the Unix APIs usually handle. This function returns `Ok((false, length))` without trying /// to write if `size` is not large enough to fit the contents of `os_string` plus a null @@ -136,7 +136,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx size: u64, ) -> InterpResult<'tcx, (bool, u64)> { - let bytes = self.os_str_to_bytes(os_str)?; + let bytes = os_str_to_bytes(os_str)?; // If `size` is smaller or equal than `bytes.len()`, writing `bytes` plus the required null // terminator to memory using the `ptr` pointer would cause an out-of-bounds access. let string_length = u64::try_from(bytes.len()).unwrap(); @@ -269,3 +269,4 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_os_str_to_wide_str(&os_str, scalar, size) } } + diff --git a/src/shims/posix/fs.rs b/src/shims/posix/fs.rs index 1ca05a461bfbc..0247c9df006f1 100644 --- a/src/shims/posix/fs.rs +++ b/src/shims/posix/fs.rs @@ -1371,7 +1371,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let result = std::fs::read_link(pathname); match result { Ok(resolved) => { - let mut path_bytes = this.os_str_to_bytes(resolved.as_ref())?; + let mut path_bytes = crate::shims::os_str::os_str_to_bytes(resolved.as_ref())?; let bufsize: usize = bufsize.try_into().unwrap(); if path_bytes.len() > bufsize { path_bytes = &path_bytes[..bufsize] From bbba87ce5450eb0145e4aec0d50b546effc054ff Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Sun, 4 Oct 2020 09:41:15 -0400 Subject: [PATCH 2371/3747] Swap order of assertions for easier debugging --- tests/run-pass/fs.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/run-pass/fs.rs b/tests/run-pass/fs.rs index 7cccf900a1bf6..947c650197cca 100644 --- a/tests/run-pass/fs.rs +++ b/tests/run-pass/fs.rs @@ -239,17 +239,17 @@ fn test_symlink() { // and check that the last byte is not overwritten. let mut large_buf = vec![0xFF; expected_path.len() + 1]; let res = unsafe { libc::readlink(symlink_c_ptr, large_buf.as_mut_ptr().cast(), large_buf.len()) }; - assert_eq!(res, large_buf.len() as isize - 1); // Check that the resovled path was properly written into the buf. assert_eq!(&large_buf[..(large_buf.len() - 1)], expected_path); assert_eq!(large_buf.last(), Some(&0xFF)); + assert_eq!(res, large_buf.len() as isize - 1); // Test that the resolved path is truncated if the provided buffer // is too small. let mut small_buf = [0u8; 2]; let res = unsafe { libc::readlink(symlink_c_ptr, small_buf.as_mut_ptr().cast(), small_buf.len()) }; - assert_eq!(res, small_buf.len() as isize); assert_eq!(small_buf, &expected_path[..small_buf.len()]); + assert_eq!(res, small_buf.len() as isize); // Test that we report a proper error for a missing path. let bad_path = CString::new("MIRI_MISSING_FILE_NAME").unwrap(); From 9e6320f1017a5af43b8f1726ff68c8c494d3e8bc Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Sun, 4 Oct 2020 12:34:13 -0400 Subject: [PATCH 2372/3747] Move `convert_path_separator` to trait and use it in `readlink` --- src/shims/os_str.rs | 93 ++++++++++++++++++++++--------------------- src/shims/posix/fs.rs | 2 + 2 files changed, 49 insertions(+), 46 deletions(-) diff --git a/src/shims/os_str.rs b/src/shims/os_str.rs index 56dcbb9e32f78..df3c7a5ad99c4 100644 --- a/src/shims/os_str.rs +++ b/src/shims/os_str.rs @@ -14,52 +14,11 @@ use rustc_target::abi::LayoutOf; use crate::*; /// Represent how path separator conversion should be done. -enum Pathconversion { +pub enum Pathconversion { HostToTarget, TargetToHost, } -/// Perform path separator conversion if needed. -fn convert_path_separator<'a>( - os_str: Cow<'a, OsStr>, - target_os: &str, - direction: Pathconversion, -) -> Cow<'a, OsStr> { - #[cfg(windows)] - return if target_os == "windows" { - // Windows-on-Windows, all fine. - os_str - } else { - // Unix target, Windows host. - let (from, to) = match direction { - Pathconversion::HostToTarget => ('\\', '/'), - Pathconversion::TargetToHost => ('/', '\\'), - }; - let converted = os_str - .encode_wide() - .map(|wchar| if wchar == from as u16 { to as u16 } else { wchar }) - .collect::>(); - Cow::Owned(OsString::from_wide(&converted)) - }; - #[cfg(unix)] - return if target_os == "windows" { - // Windows target, Unix host. - let (from, to) = match direction { - Pathconversion::HostToTarget => ('/', '\\'), - Pathconversion::TargetToHost => ('\\', '/'), - }; - let converted = os_str - .as_bytes() - .iter() - .map(|&wchar| if wchar == from as u8 { to as u8 } else { wchar }) - .collect::>(); - Cow::Owned(OsString::from_vec(converted)) - } else { - // Unix-on-Unix, all is fine. - os_str - }; -} - #[cfg(unix)] pub fn os_str_to_bytes<'a, 'tcx>(os_str: &'a OsStr) -> InterpResult<'tcx, &'a [u8]> { Ok(os_str.as_bytes()) @@ -229,7 +188,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_ref(); let os_str = this.read_os_str_from_c_str(scalar)?; - Ok(match convert_path_separator(Cow::Borrowed(os_str), &this.tcx.sess.target.target.target_os, Pathconversion::TargetToHost) { + Ok(match this.convert_path_separator(Cow::Borrowed(os_str), Pathconversion::TargetToHost) { Cow::Borrowed(x) => Cow::Borrowed(Path::new(x)), Cow::Owned(y) => Cow::Owned(PathBuf::from(y)), }) @@ -240,7 +199,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_ref(); let os_str = this.read_os_str_from_wide_str(scalar)?; - Ok(convert_path_separator(Cow::Owned(os_str), &this.tcx.sess.target.target.target_os, Pathconversion::TargetToHost).into_owned().into()) + Ok(this.convert_path_separator(Cow::Owned(os_str), Pathconversion::TargetToHost).into_owned().into()) } /// Write a Path to the machine memory (as a null-terminated sequence of bytes), @@ -252,7 +211,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx size: u64, ) -> InterpResult<'tcx, (bool, u64)> { let this = self.eval_context_mut(); - let os_str = convert_path_separator(Cow::Borrowed(path.as_os_str()), &this.tcx.sess.target.target.target_os, Pathconversion::HostToTarget); + let os_str = this.convert_path_separator(Cow::Borrowed(path.as_os_str()), Pathconversion::HostToTarget); this.write_os_str_to_c_str(&os_str, scalar, size) } @@ -265,8 +224,50 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx size: u64, ) -> InterpResult<'tcx, (bool, u64)> { let this = self.eval_context_mut(); - let os_str = convert_path_separator(Cow::Borrowed(path.as_os_str()), &this.tcx.sess.target.target.target_os, Pathconversion::HostToTarget); + let os_str = this.convert_path_separator(Cow::Borrowed(path.as_os_str()), Pathconversion::HostToTarget); this.write_os_str_to_wide_str(&os_str, scalar, size) } + + fn convert_path_separator<'a>( + &self, + os_str: Cow<'a, OsStr>, + direction: Pathconversion, + ) -> Cow<'a, OsStr> { + let this = self.eval_context_ref(); + let target_os = &this.tcx.sess.target.target.target_os; + #[cfg(windows)] + return if target_os == "windows" { + // Windows-on-Windows, all fine. + os_str + } else { + // Unix target, Windows host. + let (from, to) = match direction { + Pathconversion::HostToTarget => ('\\', '/'), + Pathconversion::TargetToHost => ('/', '\\'), + }; + let converted = os_str + .encode_wide() + .map(|wchar| if wchar == from as u16 { to as u16 } else { wchar }) + .collect::>(); + Cow::Owned(OsString::from_wide(&converted)) + }; + #[cfg(unix)] + return if target_os == "windows" { + // Windows target, Unix host. + let (from, to) = match direction { + Pathconversion::HostToTarget => ('/', '\\'), + Pathconversion::TargetToHost => ('\\', '/'), + }; + let converted = os_str + .as_bytes() + .iter() + .map(|&wchar| if wchar == from as u8 { to as u8 } else { wchar }) + .collect::>(); + Cow::Owned(OsString::from_vec(converted)) + } else { + // Unix-on-Unix, all is fine. + os_str + }; + } } diff --git a/src/shims/posix/fs.rs b/src/shims/posix/fs.rs index 0247c9df006f1..e84731a5ef735 100644 --- a/src/shims/posix/fs.rs +++ b/src/shims/posix/fs.rs @@ -4,6 +4,7 @@ use std::fs::{read_dir, remove_dir, remove_file, rename, DirBuilder, File, FileT use std::io::{self, Read, Seek, SeekFrom, Write}; use std::path::Path; use std::time::SystemTime; +use std::borrow::Cow; use log::trace; @@ -1371,6 +1372,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let result = std::fs::read_link(pathname); match result { Ok(resolved) => { + let resolved = this.convert_path_separator(Cow::Borrowed(resolved.as_ref()), crate::shims::os_str::Pathconversion::HostToTarget); let mut path_bytes = crate::shims::os_str::os_str_to_bytes(resolved.as_ref())?; let bufsize: usize = bufsize.try_into().unwrap(); if path_bytes.len() > bufsize { From 02257870a6b53b25238b5345d17c01fbfc366769 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 4 Oct 2020 18:56:51 +0200 Subject: [PATCH 2373/3747] rustup; test NaN conversion issue --- rust-version | 2 +- tests/run-pass/float.rs | 29 ++++++++++++++++++++++------- 2 files changed, 23 insertions(+), 8 deletions(-) diff --git a/rust-version b/rust-version index 9b4e14902aff0..622fa14d1c29a 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -6f56fbdc1c58992a9db630f5cd2ba9882d32e84b +a835b483fe0418b48ca44afb65cd0dd6bad4eb9b diff --git a/tests/run-pass/float.rs b/tests/run-pass/float.rs index 88f841eae74d9..62d9c60766080 100644 --- a/tests/run-pass/float.rs +++ b/tests/run-pass/float.rs @@ -4,6 +4,14 @@ use std::fmt::Debug; use std::hint::black_box; +fn main() { + basic(); + casts(); + more_casts(); + ops(); + nan_casts(); +} + // Helper function to avoid promotion so that this tests "run-time" casts, not CTFE. // Doesn't make a big difference when running this in Miri, but it means we can compare this // with the LLVM backend by running `rustc -Zmir-opt-level=0 -Zsaturating-float-casts`. @@ -78,13 +86,6 @@ fn test_both_cast(x: F, y: I) assert_eq!(unsafe { x.cast_unchecked() }, y); } -fn main() { - basic(); - casts(); - more_casts(); - ops(); -} - fn basic() { // basic arithmetic assert_eq(6.0_f32*6.0_f32, 36.0_f32); @@ -444,3 +445,17 @@ fn more_casts() { const SECOND_LARGEST_F32: f32 = 340282326356119256160033759537265639424.; test!(SECOND_LARGEST_F32, f32 -> u128, 0xfffffe00000000000000000000000000); } + +fn nan_casts() { + let nan1 = f64::from_bits(0x7FF0_0001_0000_0001u64); + let nan2 = f64::from_bits(0x7FF0_0000_0000_0001u64); + + assert!(nan1.is_nan()); + assert!(nan2.is_nan()); + + let nan1_32 = nan1 as f32; + let nan2_32 = nan2 as f32; + + assert!(nan1_32.is_nan()); + assert!(nan2_32.is_nan()); +} From 4eea02e725052a8941abd728cb1da98e4d9770a8 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Sun, 4 Oct 2020 16:26:09 -0400 Subject: [PATCH 2374/3747] Normalize MIRI_TEMP before using it --- tests/run-pass/fs.rs | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/tests/run-pass/fs.rs b/tests/run-pass/fs.rs index 947c650197cca..f74d1c9a36b1b 100644 --- a/tests/run-pass/fs.rs +++ b/tests/run-pass/fs.rs @@ -29,7 +29,19 @@ fn main() { } fn tmp() -> PathBuf { - std::env::var("MIRI_TEMP").map(PathBuf::from).unwrap_or_else(|_| std::env::temp_dir()) + std::env::var("MIRI_TEMP") + .map(|tmp| { + // MIRI_TEMP is set outside of our emulated + // program, so it may have path separators that don't + // correspond to our target platform. We normalize them here + // before constructing a `PathBuf` + + #[cfg(windows)] + return PathBuf::from(tmp.replace("/", "\\")); + + #[cfg(not(windows))] + return PathBuf::from(tmp.replace("\\", "/")); + }).unwrap_or_else(|_| std::env::temp_dir()) } /// Prepare: compute filename and make sure the file does not exist. From c1c82c2503d1fcc581e230129f84523e59835c13 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Sun, 4 Oct 2020 16:28:09 -0400 Subject: [PATCH 2375/3747] Properly capitalize PathConversion --- src/shims/os_str.rs | 20 ++++++++++---------- src/shims/posix/fs.rs | 2 +- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/shims/os_str.rs b/src/shims/os_str.rs index df3c7a5ad99c4..7635047064f12 100644 --- a/src/shims/os_str.rs +++ b/src/shims/os_str.rs @@ -14,7 +14,7 @@ use rustc_target::abi::LayoutOf; use crate::*; /// Represent how path separator conversion should be done. -pub enum Pathconversion { +pub enum PathConversion { HostToTarget, TargetToHost, } @@ -188,7 +188,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_ref(); let os_str = this.read_os_str_from_c_str(scalar)?; - Ok(match this.convert_path_separator(Cow::Borrowed(os_str), Pathconversion::TargetToHost) { + Ok(match this.convert_path_separator(Cow::Borrowed(os_str), PathConversion::TargetToHost) { Cow::Borrowed(x) => Cow::Borrowed(Path::new(x)), Cow::Owned(y) => Cow::Owned(PathBuf::from(y)), }) @@ -199,7 +199,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_ref(); let os_str = this.read_os_str_from_wide_str(scalar)?; - Ok(this.convert_path_separator(Cow::Owned(os_str), Pathconversion::TargetToHost).into_owned().into()) + Ok(this.convert_path_separator(Cow::Owned(os_str), PathConversion::TargetToHost).into_owned().into()) } /// Write a Path to the machine memory (as a null-terminated sequence of bytes), @@ -211,7 +211,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx size: u64, ) -> InterpResult<'tcx, (bool, u64)> { let this = self.eval_context_mut(); - let os_str = this.convert_path_separator(Cow::Borrowed(path.as_os_str()), Pathconversion::HostToTarget); + let os_str = this.convert_path_separator(Cow::Borrowed(path.as_os_str()), PathConversion::HostToTarget); this.write_os_str_to_c_str(&os_str, scalar, size) } @@ -224,14 +224,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx size: u64, ) -> InterpResult<'tcx, (bool, u64)> { let this = self.eval_context_mut(); - let os_str = this.convert_path_separator(Cow::Borrowed(path.as_os_str()), Pathconversion::HostToTarget); + let os_str = this.convert_path_separator(Cow::Borrowed(path.as_os_str()), PathConversion::HostToTarget); this.write_os_str_to_wide_str(&os_str, scalar, size) } fn convert_path_separator<'a>( &self, os_str: Cow<'a, OsStr>, - direction: Pathconversion, + direction: PathConversion, ) -> Cow<'a, OsStr> { let this = self.eval_context_ref(); let target_os = &this.tcx.sess.target.target.target_os; @@ -242,8 +242,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } else { // Unix target, Windows host. let (from, to) = match direction { - Pathconversion::HostToTarget => ('\\', '/'), - Pathconversion::TargetToHost => ('/', '\\'), + PathConversion::HostToTarget => ('\\', '/'), + PathConversion::TargetToHost => ('/', '\\'), }; let converted = os_str .encode_wide() @@ -255,8 +255,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx return if target_os == "windows" { // Windows target, Unix host. let (from, to) = match direction { - Pathconversion::HostToTarget => ('/', '\\'), - Pathconversion::TargetToHost => ('\\', '/'), + PathConversion::HostToTarget => ('/', '\\'), + PathConversion::TargetToHost => ('\\', '/'), }; let converted = os_str .as_bytes() diff --git a/src/shims/posix/fs.rs b/src/shims/posix/fs.rs index e84731a5ef735..4e8d38a977c56 100644 --- a/src/shims/posix/fs.rs +++ b/src/shims/posix/fs.rs @@ -1372,7 +1372,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let result = std::fs::read_link(pathname); match result { Ok(resolved) => { - let resolved = this.convert_path_separator(Cow::Borrowed(resolved.as_ref()), crate::shims::os_str::Pathconversion::HostToTarget); + let resolved = this.convert_path_separator(Cow::Borrowed(resolved.as_ref()), crate::shims::os_str::PathConversion::HostToTarget); let mut path_bytes = crate::shims::os_str::os_str_to_bytes(resolved.as_ref())?; let bufsize: usize = bufsize.try_into().unwrap(); if path_bytes.len() > bufsize { From 3aaab3dd9809aa8f9576b77122ba2601fb3ddd52 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 4 Oct 2020 23:07:19 +0200 Subject: [PATCH 2376/3747] more punctuation --- src/shims/posix/fs.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shims/posix/fs.rs b/src/shims/posix/fs.rs index 4e8d38a977c56..ebf7e16a15340 100644 --- a/src/shims/posix/fs.rs +++ b/src/shims/posix/fs.rs @@ -1379,7 +1379,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx path_bytes = &path_bytes[..bufsize] } // 'readlink' truncates the resolved path if - // the provided buffer is not large enough + // the provided buffer is not large enough. this.memory.write_bytes(buf, path_bytes.iter().copied())?; Ok(path_bytes.len().try_into().unwrap()) } From 808032a0edc4614079c47d114769e11ceca26a62 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 5 Oct 2020 10:22:41 +0200 Subject: [PATCH 2377/3747] rustup; disable opt level >=2 tests due to ICE --- ci.sh | 3 ++- rust-version | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/ci.sh b/ci.sh index 56a6f1228ab59..a6daa80645307 100755 --- a/ci.sh +++ b/ci.sh @@ -25,7 +25,8 @@ function run_tests { ./miri test --locked if ! [ -n "${MIRI_TEST_TARGET+exists}" ]; then # Only for host architecture: tests with MIR optimizations - MIRIFLAGS="-Z mir-opt-level=3" ./miri test --locked + #FIXME: Only testing opt level 1 due to . + MIRIFLAGS="-Z mir-opt-level=1" ./miri test --locked fi # "miri test" has built the sysroot for us, now this should pass without # any interactive questions. diff --git a/rust-version b/rust-version index 622fa14d1c29a..b0644a3d73199 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -a835b483fe0418b48ca44afb65cd0dd6bad4eb9b +efbaa413061c2a6e52f06f00a60ee7830fcf3ea5 From 8e8828259ac1433dd3981fcec9670d7394c2ade5 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Mon, 5 Oct 2020 17:29:55 -0400 Subject: [PATCH 2378/3747] Use macro callsite spans in backtrace This mirrors what we do in the debuginfo used for runtime backtraces. --- src/shims/backtrace.rs | 8 +++++++- tests/run-pass/backtrace-api.rs | 8 +++++++- tests/run-pass/backtrace-api.stderr | 5 +++-- tests/run-pass/backtrace-api.stdout | 5 +++-- 4 files changed, 20 insertions(+), 6 deletions(-) diff --git a/src/shims/backtrace.rs b/src/shims/backtrace.rs index 75cd61b0f59e7..bd36587116a06 100644 --- a/src/shims/backtrace.rs +++ b/src/shims/backtrace.rs @@ -26,7 +26,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let mut data = Vec::new(); for frame in this.active_thread_stack().iter().rev() { - data.push((frame.instance, frame.current_span().lo())); + let mut span = frame.current_span(); + // Match the behavior of runtime backtrace spans + // by using a non-macro span in our backtrace. See `FunctionCx::debug_loc`. + if span.from_expansion() && !tcx.sess.opts.debugging_opts.debug_macros { + span = rustc_span::hygiene::walk_chain(span, frame.body.span.ctxt()) + } + data.push((frame.instance, span.lo())); } let ptrs: Vec<_> = data.into_iter().map(|(instance, pos)| { diff --git a/tests/run-pass/backtrace-api.rs b/tests/run-pass/backtrace-api.rs index 80e64c2e1c8ba..eaf29abfd9f48 100644 --- a/tests/run-pass/backtrace-api.rs +++ b/tests/run-pass/backtrace-api.rs @@ -18,7 +18,13 @@ struct MiriFrame { #[inline(never)] fn func_a() -> Box<[*mut ()]> { func_b::() } #[inline(never)] fn func_b() -> Box<[*mut ()]> { func_c() } -#[inline(never)] fn func_c() -> Box<[*mut ()]> { unsafe { miri_get_backtrace(0) } } + +macro_rules! invoke_func_d { + () => { func_d() } +} + +#[inline(never)] fn func_c() -> Box<[*mut ()]> { invoke_func_d!() } +#[inline(never)] fn func_d() -> Box<[*mut ()]> { unsafe { miri_get_backtrace(0) } } fn main() { let mut seen_main = false; diff --git a/tests/run-pass/backtrace-api.stderr b/tests/run-pass/backtrace-api.stderr index 15851a1cc7257..02e7a7e1eaf9c 100644 --- a/tests/run-pass/backtrace-api.stderr +++ b/tests/run-pass/backtrace-api.stderr @@ -1,7 +1,8 @@ -$DIR/backtrace-api.rs:21:59 (func_c) +$DIR/backtrace-api.rs:27:59 (func_d) +$DIR/backtrace-api.rs:26:50 (func_c) $DIR/backtrace-api.rs:20:53 (func_b) $DIR/backtrace-api.rs:19:50 (func_a) -$DIR/backtrace-api.rs:25:18 (main) +$DIR/backtrace-api.rs:31:18 (main) RUSTLIB/core/src/ops/function.rs:LL:COL (>::call_once - shim(fn())) RUSTLIB/std/src/sys_common/backtrace.rs:LL:COL (std::sys_common::backtrace::__rust_begin_short_backtrace) RUSTLIB/std/src/rt.rs:LL:COL (std::rt::lang_start::{closure#0}) diff --git a/tests/run-pass/backtrace-api.stdout b/tests/run-pass/backtrace-api.stdout index 453cf0b774a10..90ab4bb96e625 100644 --- a/tests/run-pass/backtrace-api.stdout +++ b/tests/run-pass/backtrace-api.stdout @@ -1,4 +1,5 @@ -$DIR/backtrace-api.rs:21:59 (func_c) +$DIR/backtrace-api.rs:27:59 (func_d) +$DIR/backtrace-api.rs:26:50 (func_c) $DIR/backtrace-api.rs:20:53 (func_b::) $DIR/backtrace-api.rs:19:50 (func_a) -$DIR/backtrace-api.rs:25:18 (main) +$DIR/backtrace-api.rs:31:18 (main) From c3a122523326c3002524f86ae5186592467958d1 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 6 Oct 2020 11:11:14 +0200 Subject: [PATCH 2379/3747] add bors notification jobs --- .github/workflows/ci.yml | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 101618d1a7aac..0e7d6e1cd6165 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -33,3 +33,25 @@ jobs: host_target: i686-pc-windows-msvc steps: - uses: actions/checkout@v2 + + # These jobs doesn't actually test anything, but they're only used to tell + # bors the build completed, as there is no practical way to detect when a + # workflow is successful listening to webhooks only. + # + # ALL THE PREVIOUS JOBS NEED TO BE ADDED TO THE `needs` SECTION OF THIS JOB! + end-success: + name: bors build finished + runs-on: ubuntu-latest + needs: [build] + if: github.event.pusher.name == 'bors' && success() + steps: + - name: mark the job as a success + run: exit 0 + end-failure: + name: bors build finished + runs-on: ubuntu-latest + needs: [build] + if: github.event.pusher.name == 'bors' && (failure() || cancelled()) + steps: + - name: mark the job as a failure + run: exit 1 From 3e655665b76e5771d74b6b2af9de1eaef5f43b60 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 19 Sep 2020 11:33:16 +0200 Subject: [PATCH 2380/3747] test VecDeque::iter_mut aliasing --- tests/run-pass/vecdeque.rs | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/tests/run-pass/vecdeque.rs b/tests/run-pass/vecdeque.rs index 9c9909802e207..34f32ee1d9c12 100644 --- a/tests/run-pass/vecdeque.rs +++ b/tests/run-pass/vecdeque.rs @@ -1,5 +1,17 @@ use std::collections::VecDeque; +fn test_all_refs<'a, T: 'a>(dummy: &mut T, iter: impl Iterator) { + // Gather all those references. + let mut refs: Vec<&mut T> = iter.collect(); + // Use them all. Twice, to be sure we got all interleavings. + for r in refs.iter_mut() { + std::mem::swap(dummy, r); + } + for r in refs { + std::mem::swap(dummy, r); + } +} + fn main() { let mut dst = VecDeque::new(); dst.push_front(Box::new(1)); @@ -18,6 +30,21 @@ fn main() { println!("{:?}", VecDeque::::new().iter()); for a in dst { - assert_eq!(*a, 2); + assert_eq!(*a, 2); } + + // # Aliasing tests. + let mut v = std::collections::VecDeque::new(); + v.push_back(1); + v.push_back(2); + + // Test `fold` bad aliasing. + let mut it = v.iter_mut(); + let ref0 = it.next().unwrap(); + let sum = it.fold(0, |x, y| x + *y); + assert_eq!(*ref0 + sum, 3); + + // Test general iterator aliasing. + v.push_front(0); + test_all_refs(&mut 0, v.iter_mut()); } From 63a0f04ed05af0b0822bfe000511e37489b71662 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 7 Oct 2020 09:05:18 +0200 Subject: [PATCH 2381/3747] rustup; bring back mir-opt-level 3 --- ci.sh | 3 +-- rust-version | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/ci.sh b/ci.sh index a6daa80645307..56a6f1228ab59 100755 --- a/ci.sh +++ b/ci.sh @@ -25,8 +25,7 @@ function run_tests { ./miri test --locked if ! [ -n "${MIRI_TEST_TARGET+exists}" ]; then # Only for host architecture: tests with MIR optimizations - #FIXME: Only testing opt level 1 due to . - MIRIFLAGS="-Z mir-opt-level=1" ./miri test --locked + MIRIFLAGS="-Z mir-opt-level=3" ./miri test --locked fi # "miri test" has built the sysroot for us, now this should pass without # any interactive questions. diff --git a/rust-version b/rust-version index b0644a3d73199..79ba8eebc1923 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -efbaa413061c2a6e52f06f00a60ee7830fcf3ea5 +c9ced8523bbb90561385aab305232f2167228a83 From 5058ec18f161c075e2b754c8a6df131cfeaf6f6a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 7 Oct 2020 19:42:33 +0200 Subject: [PATCH 2382/3747] fix for rlib/cdylib crates in dependency tree --- cargo-miri/bin.rs | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index 5731a9a591f9a..72c873b229e93 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -532,8 +532,7 @@ fn phase_cargo_rustc(args: env::Args) { fn is_runnable_crate() -> bool { let is_bin = get_arg_flag_value("--crate-type").as_deref().unwrap_or("bin") == "bin"; let is_test = has_arg_flag("--test"); - let print = get_arg_flag_value("--print").is_some(); - (is_bin || is_test) && !print + is_bin || is_test } fn out_filename(prefix: &str, suffix: &str) -> PathBuf { @@ -552,8 +551,21 @@ fn phase_cargo_rustc(args: env::Args) { let verbose = std::env::var_os("MIRI_VERBOSE").is_some(); let target_crate = is_target_crate(); + let print = get_arg_flag_value("--print").is_some(); // whether this is cargo passing `--print` to get some infos + + // rlib and cdylib are just skipped, we cannot interpret them and do not need them + // for the rest of the build either. + match get_arg_flag_value("--crate-type").as_deref() { + Some("rlib") | Some("cdylib") => { + if verbose { + eprint!("[cargo-miri rustc] (rlib/cdylib skipped)"); + } + return; + } + _ => {}, + } - if target_crate && is_runnable_crate() { + if !print && target_crate && is_runnable_crate() { // This is the binary or test crate that we want to interpret under Miri. // But we cannot run it here, as cargo invoked us as a compiler -- our stdin and stdout are not // like we want them. @@ -577,7 +589,7 @@ fn phase_cargo_rustc(args: env::Args) { let mut emit_link_hack = false; // Arguments are treated very differently depending on whether this crate is // for interpretation by Miri, or for use by a build script / proc macro. - if target_crate { + if !print && target_crate { // Forward arguments, but remove "link" from "--emit" to make this a check-only build. let emit_flag = "--emit"; for arg in args { @@ -607,7 +619,7 @@ fn phase_cargo_rustc(args: env::Args) { cmd.arg("--sysroot"); cmd.arg(sysroot); } else { - // For host crates, just forward everything. + // For host crates or when we are printing, just forward everything. cmd.args(args); } From e6665109e0708675563d391ede46b2bdf24e8ecc Mon Sep 17 00:00:00 2001 From: Yonggang Luo Date: Fri, 9 Oct 2020 13:16:03 +0800 Subject: [PATCH 2383/3747] Update README.md Note however that [leak checking is currently disabled on Windows targets](https://github.com/rust-lang/miri/issues/1302). Windows issue are fixed --- README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/README.md b/README.md index 2b015104828e9..ceaf993924efd 100644 --- a/README.md +++ b/README.md @@ -19,8 +19,7 @@ for example: On top of that, Miri will also tell you about memory leaks: when there is memory still allocated at the end of the execution, and that memory is not reachable -from a global `static`, Miri will raise an error. Note however that -[leak checking is currently disabled on Windows targets](https://github.com/rust-lang/miri/issues/1302). +from a global `static`, Miri will raise an error. Miri has already discovered some [real-world bugs](#bugs-found-by-miri). If you found a bug with Miri, we'd appreciate if you tell us and we'll add it to the From be51e6bd07c10ff350350fe05f2888c4ce3a08a0 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Sat, 10 Oct 2020 13:07:57 -0400 Subject: [PATCH 2384/3747] Add an `fn_ptr` field to `MiriFrame` The `backtrace-rs` crate can use this to implement `Frame::symbol_address`, which is used to skip frames above the call to `Backtrace::capture` on the stack. The function pointer will not be useable for comparison purposes if the function is generic, as CTFE creates a new function pointer for each cast of a (monomorphized) generic function. However, this already affects code running under Miri, and isn't a problem for `backtrace-rs` (which only casts a non-generic function). I've added logic to allow `MiriFrame` to have either 4 or 5 fields - if a 5th field is present, we write the function pointer to it. --- README.md | 4 ++ src/shims/backtrace.rs | 19 +++++++++- .../backtrace/bad-backtrace-decl.rs | 2 +- tests/run-pass/backtrace-api.rs | 37 ++++++++++++------- tests/run-pass/backtrace-api.stderr | 10 ++--- tests/run-pass/backtrace-api.stdout | 10 ++--- 6 files changed, 55 insertions(+), 27 deletions(-) diff --git a/README.md b/README.md index ceaf993924efd..747afb9c4e93a 100644 --- a/README.md +++ b/README.md @@ -286,6 +286,10 @@ extern "Rust" { /// lineno: u32, /// // The column number currently being executed in `filename`, starting from '1'. /// colno: u32, + /// // The function pointer to the function currently being executed. + /// // This can be compared against function pointers obtained by + /// // casting a function (e.g. `my_fn as *mut ()`) + /// fn_ptr: *mut () /// } /// ``` /// diff --git a/src/shims/backtrace.rs b/src/shims/backtrace.rs index bd36587116a06..9b396c718493f 100644 --- a/src/shims/backtrace.rs +++ b/src/shims/backtrace.rs @@ -92,8 +92,18 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx throw_ub_format!("expected function pointer, found {:?}", ptr); }; - if dest.layout.layout.fields.count() != 4 { - throw_ub_format!("bad declaration of miri_resolve_frame - should return a struct with 4 fields"); + // Reconstruct the original function pointer, + // which we pass to user code. + let mut fn_ptr = ptr; + fn_ptr.offset = Size::from_bytes(0); + let fn_ptr = Scalar::Ptr(fn_ptr); + + let num_fields = dest.layout.layout.fields.count(); + + if num_fields != 4 && num_fields != 5 { + // Always mention 5 fields, since the 4-field struct is only supported + // for backwards compatiblity. New code should declare 5 fields + throw_ub_format!("bad declaration of miri_resolve_frame - should return a struct with 5 fields"); } let pos = BytePos(ptr.offset.bytes().try_into().unwrap()); @@ -122,6 +132,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_immediate(filename_alloc.to_ref(), this.mplace_field(dest, 1)?.into())?; this.write_scalar(lineno_alloc, this.mplace_field(dest, 2)?.into())?; this.write_scalar(colno_alloc, this.mplace_field(dest, 3)?.into())?; + + if num_fields == 5 { + this.write_scalar(fn_ptr, this.mplace_field(dest, 4)?.into())?; + } + Ok(()) } } diff --git a/tests/compile-fail/backtrace/bad-backtrace-decl.rs b/tests/compile-fail/backtrace/bad-backtrace-decl.rs index b9f1c779ae232..23379992d5ecb 100644 --- a/tests/compile-fail/backtrace/bad-backtrace-decl.rs +++ b/tests/compile-fail/backtrace/bad-backtrace-decl.rs @@ -7,7 +7,7 @@ fn main() { let frames = unsafe { miri_get_backtrace(0) }; for frame in frames.into_iter() { unsafe { - miri_resolve_frame(*frame, 0); //~ ERROR Undefined Behavior: bad declaration of miri_resolve_frame - should return a struct with 4 fields + miri_resolve_frame(*frame, 0); //~ ERROR Undefined Behavior: bad declaration of miri_resolve_frame - should return a struct with 5 fields } } } diff --git a/tests/run-pass/backtrace-api.rs b/tests/run-pass/backtrace-api.rs index eaf29abfd9f48..19169060038e0 100644 --- a/tests/run-pass/backtrace-api.rs +++ b/tests/run-pass/backtrace-api.rs @@ -2,20 +2,6 @@ // normalize-stderr-test "RUSTLIB/(.*):\d+:\d+ "-> "RUSTLIB/$1:LL:COL " // normalize-stderr-test "::<.*>" -> "" -extern "Rust" { - fn miri_get_backtrace(flags: u64) -> Box<[*mut ()]>; - fn miri_resolve_frame(ptr: *mut (), flags: u64) -> MiriFrame; -} - -#[derive(Debug)] -#[repr(C)] -struct MiriFrame { - name: Box<[u8]>, - filename: Box<[u8]>, - lineno: u32, - colno: u32 -} - #[inline(never)] fn func_a() -> Box<[*mut ()]> { func_b::() } #[inline(never)] fn func_b() -> Box<[*mut ()]> { func_c() } @@ -34,6 +20,10 @@ fn main() { let name = String::from_utf8(miri_frame.name.into()).unwrap(); let filename = String::from_utf8(miri_frame.filename.into()).unwrap(); + if name == "func_a" { + assert_eq!(func_a as *mut (), miri_frame.fn_ptr); + } + // Print every frame to stderr. let out = format!("{}:{}:{} ({})", filename, miri_frame.lineno, miri_frame.colno, name); eprintln!("{}", out); @@ -45,3 +35,22 @@ fn main() { } } } + +// This goes at the bottom of the file so that we can change it +// without disturbing line numbers of the functions in the backtrace. + +extern "Rust" { + fn miri_get_backtrace(flags: u64) -> Box<[*mut ()]>; + fn miri_resolve_frame(ptr: *mut (), flags: u64) -> MiriFrame; +} + +#[derive(Debug)] +#[repr(C)] +struct MiriFrame { + name: Box<[u8]>, + filename: Box<[u8]>, + lineno: u32, + colno: u32, + fn_ptr: *mut (), +} + diff --git a/tests/run-pass/backtrace-api.stderr b/tests/run-pass/backtrace-api.stderr index 02e7a7e1eaf9c..a5208221da405 100644 --- a/tests/run-pass/backtrace-api.stderr +++ b/tests/run-pass/backtrace-api.stderr @@ -1,8 +1,8 @@ -$DIR/backtrace-api.rs:27:59 (func_d) -$DIR/backtrace-api.rs:26:50 (func_c) -$DIR/backtrace-api.rs:20:53 (func_b) -$DIR/backtrace-api.rs:19:50 (func_a) -$DIR/backtrace-api.rs:31:18 (main) +$DIR/backtrace-api.rs:13:59 (func_d) +$DIR/backtrace-api.rs:12:50 (func_c) +$DIR/backtrace-api.rs:6:53 (func_b) +$DIR/backtrace-api.rs:5:50 (func_a) +$DIR/backtrace-api.rs:17:18 (main) RUSTLIB/core/src/ops/function.rs:LL:COL (>::call_once - shim(fn())) RUSTLIB/std/src/sys_common/backtrace.rs:LL:COL (std::sys_common::backtrace::__rust_begin_short_backtrace) RUSTLIB/std/src/rt.rs:LL:COL (std::rt::lang_start::{closure#0}) diff --git a/tests/run-pass/backtrace-api.stdout b/tests/run-pass/backtrace-api.stdout index 90ab4bb96e625..175ff3b829461 100644 --- a/tests/run-pass/backtrace-api.stdout +++ b/tests/run-pass/backtrace-api.stdout @@ -1,5 +1,5 @@ -$DIR/backtrace-api.rs:27:59 (func_d) -$DIR/backtrace-api.rs:26:50 (func_c) -$DIR/backtrace-api.rs:20:53 (func_b::) -$DIR/backtrace-api.rs:19:50 (func_a) -$DIR/backtrace-api.rs:31:18 (main) +$DIR/backtrace-api.rs:13:59 (func_d) +$DIR/backtrace-api.rs:12:50 (func_c) +$DIR/backtrace-api.rs:6:53 (func_b::) +$DIR/backtrace-api.rs:5:50 (func_a) +$DIR/backtrace-api.rs:17:18 (main) From 71e0e59b63a5476e8a215d76014efb51335e2151 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 11 Oct 2020 10:48:34 +0200 Subject: [PATCH 2385/3747] README: make our cross-interpretation feature stand out more --- README.md | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index ceaf993924efd..66f4801fc6055 100644 --- a/README.md +++ b/README.md @@ -87,11 +87,6 @@ can pass arguments to Miri via `MIRIFLAGS`. For example, `MIRIFLAGS="-Zmiri-disable-stacked-borrows" cargo miri run` runs the program without checking the aliasing of references. -Miri supports cross-execution: if you want to run the program as if it was a -Linux program, you can do `cargo miri run --target x86_64-unknown-linux-gnu`. -This is particularly useful if you are using Windows, as the Linux target is -much better supported than Windows targets. - When compiling code via `cargo miri`, the `cfg(miri)` config flag is set. You can use this to ignore test cases that fail under Miri because they do things Miri does not support: @@ -116,6 +111,19 @@ error: unsupported operation: can't call foreign function: bind performed an operation that the interpreter does not support ``` +### Cross-interpretation: running for different targets + +Miri cannot just run a binary or test suite for your host target, it can also +perform cross-interpretation for arbitrary foreign targets: `cargo miri run +--target x86_64-unknown-linux-gnu` will run your program as if it was a Linux +program, no matter your host OS. This is particularly useful if you are using +Windows, as the Linux target is much better supported than Windows targets. + +You can also use this to test platforms with different properties than your host +platform. For example `cargo miri test --target mips64-unknown-linux-gnuabi64` +will run your test suite on a big-endian target, which is useful for testing +endian-sensitive code. + ### Running Miri on CI To run Miri on CI, make sure that you handle the case where the latest nightly From 6acde94931c5a7ac0f8b2abb38a91139d89c0675 Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Sun, 4 Oct 2020 22:01:10 +0700 Subject: [PATCH 2386/3747] Add a working github actions template --- .appveyor.yml | 7 +++-- .github/workflows/ci.yml | 60 +++++++++++++++++++++++++++++++++++++++- .travis.yml | 9 ++++-- README.md | 8 +++++- ci.sh | 46 ++++++++++++++++++------------ 5 files changed, 105 insertions(+), 25 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index 5cb5267a6da54..82c668f0e75d7 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -3,7 +3,7 @@ environment: global: PROJECT_NAME: miri matrix: - - TARGET: i686-pc-windows-msvc + - HOST_TARGET: i686-pc-windows-msvc matrix: fast_finish: true # Immediately finish build once one of the jobs fails. cache: @@ -23,7 +23,7 @@ install: # Install Rust. We use the "stable" toolchain for better caching, it is just used to build `rustup-toolchain-install-master`. # But we also need to take into account that the build cache might have a different, outdated default. - curl -sSf --retry 3 -o rustup-init.exe https://win.rustup.rs/ -- rustup-init.exe -y --default-host %TARGET% --default-toolchain none --profile minimal +- rustup-init.exe -y --default-host %HOST_TARGET% --default-toolchain none --profile minimal - set PATH=%USERPROFILE%\.cargo\bin;%PATH% - rustup default stable - rustup toolchain uninstall beta nightly @@ -36,7 +36,8 @@ install: - cargo --version test_script: -- set PYTHON=C:\msys64\mingw64\bin\python3.exe +# Add python3 path: https://www.appveyor.com/docs/windows-images-software/#python +- set PATH=C:\Python35-x64;%PATH% - bash ci.sh after_test: diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0e7d6e1cd6165..b5ef3d861eadc 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -11,13 +11,14 @@ on: - 'master' schedule: # Use to conveniently edit cron schedule. - - cron: "0 7 * * *" # At 07:00 UTC every day. + - cron: '0 7 * * *' # At 07:00 UTC every day. jobs: build: runs-on: ${{ matrix.os }} env: RUST_BACKTRACE: 1 + HOST_TARGET: ${{ matrix.host_target }} strategy: matrix: build: [linux64, macos, win32] @@ -34,6 +35,63 @@ jobs: steps: - uses: actions/checkout@v2 + # We install gnu-tar because BSD tar is buggy on macOS builders of GHA. + # See . + - name: Install GNU tar + if: runner.os == 'macOS' + run: | + brew install gnu-tar + echo "/usr/local/opt/gnu-tar/libexec/gnubin" >> $GITHUB_PATH + + # Cache the global cargo directory, but NOT the local `target` directory which + # we cannot reuse anyway when the nightly changes (and it grows quite large + # over time). + - name: Add cache for cargo + uses: actions/cache@v2 + with: + path: | + # Taken from . + ~/.cargo/bin + ~/.cargo/registry/index + ~/.cargo/registry/cache + ~/.cargo/git/db + # contains package information of crates installed via `cargo install`. + ~/.cargo/.crates.toml + key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }} + restore-keys: ${{ runner.os }}-cargo + + - name: Install rustup-toolchain-install-master and xargo + run: | + cargo install rustup-toolchain-install-master + cargo install xargo + shell: bash + + - name: Install "master" toolchain + run: | + if [[ ${{ github.event_name }} == 'schedule' ]]; then + RUSTC_HASH=$(git ls-remote https://github.com/rust-lang/rust.git master | awk '{print $1}') + else + RUSTC_HASH=$(< rust-version) + fi + rustup-toolchain-install-master \ + -f \ + -n master "$RUSTC_HASH" \ + -c rust-src \ + -c rustc-dev \ + -c llvm-tools \ + --host ${{ matrix.host_target }} + rustup default master + shell: bash + + - name: Show Rust version + run: | + rustup show + rustc -Vv + cargo -V + + - name: Test + run: bash ./ci.sh + # These jobs doesn't actually test anything, but they're only used to tell # bors the build completed, as there is no practical way to detect when a # workflow is successful listening to webhooks only. diff --git a/.travis.yml b/.travis.yml index fcef17b124ddd..86dcf78435b2b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,10 @@ language: generic -os: -- linux -- osx +jobs: + include: + - os: linux + env: HOST_TARGET=x86_64-unknown-linux-gnu + - os: osx + env: HOST_TARGET=x86_64-apple-darwin dist: xenial cache: # Cache the global cargo directory, but NOT the local `target` directory which diff --git a/README.md b/README.md index 2b015104828e9..418b7a1ee3013 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,11 @@ -# Miri [![Build Status](https://travis-ci.com/rust-lang/miri.svg?branch=master)](https://travis-ci.com/rust-lang/miri) [![Windows build status](https://ci.appveyor.com/api/projects/status/github/rust-lang/miri?svg=true)](https://ci.appveyor.com/project/rust-lang-libs/miri) +# Miri +[![Actions build status][actions-badge]][actions-url] +[![Travis build status](https://travis-ci.com/rust-lang/miri.svg?branch=master)](https://travis-ci.com/rust-lang/miri) +[![Appveyor Windows build status](https://ci.appveyor.com/api/projects/status/github/rust-lang/miri?svg=true)](https://ci.appveyor.com/project/rust-lang-libs/miri) + +[actions-badge]: https://github.com/rust-lang/miri/workflows/CI/badge.svg?branch=master +[actions-url]: https://github.com/rust-lang/miri/actions An experimental interpreter for [Rust][rust]'s [mid-level intermediate representation][mir] (MIR). It can run binaries and diff --git a/ci.sh b/ci.sh index a6daa80645307..8827c90d3bdf1 100755 --- a/ci.sh +++ b/ci.sh @@ -23,32 +23,44 @@ function run_tests { fi ./miri test --locked - if ! [ -n "${MIRI_TEST_TARGET+exists}" ]; then + if [ -z "${MIRI_TEST_TARGET+exists}" ]; then # Only for host architecture: tests with MIR optimizations #FIXME: Only testing opt level 1 due to . MIRIFLAGS="-Z mir-opt-level=1" ./miri test --locked fi + + # On Windows, there is always "python", not "python3" or "python2". + if command -v python3 > /dev/null; then + PYTHON=python3 + else + PYTHON=python + fi + # "miri test" has built the sysroot for us, now this should pass without # any interactive questions. - ${PYTHON:-python3} test-cargo-miri/run-test.py - + ${PYTHON} test-cargo-miri/run-test.py echo } # host run_tests -if [ "${TRAVIS_OS_NAME:-}" == linux ]; then - MIRI_TEST_TARGET=i686-unknown-linux-gnu run_tests - MIRI_TEST_TARGET=x86_64-apple-darwin run_tests - MIRI_TEST_TARGET=i686-pc-windows-msvc run_tests -elif [ "${TRAVIS_OS_NAME:-}" == osx ]; then - MIRI_TEST_TARGET=mips64-unknown-linux-gnuabi64 run_tests # big-endian architecture - MIRI_TEST_TARGET=x86_64-pc-windows-msvc run_tests -elif [ "${CI_WINDOWS:-}" == True ]; then - MIRI_TEST_TARGET=x86_64-unknown-linux-gnu run_tests - MIRI_TEST_TARGET=x86_64-apple-darwin run_tests -else - echo "FATAL: unknown CI platform" - exit 1 -fi +case $HOST_TARGET in + x86_64-unknown-linux-gnu) + MIRI_TEST_TARGET=i686-unknown-linux-gnu run_tests + MIRI_TEST_TARGET=x86_64-apple-darwin run_tests + MIRI_TEST_TARGET=i686-pc-windows-msvc run_tests + ;; + x86_64-apple-darwin) + MIRI_TEST_TARGET=mips64-unknown-linux-gnuabi64 run_tests # big-endian architecture + MIRI_TEST_TARGET=x86_64-pc-windows-msvc run_tests + ;; + i686-pc-windows-msvc) + MIRI_TEST_TARGET=x86_64-unknown-linux-gnu run_tests + MIRI_TEST_TARGET=x86_64-apple-darwin run_tests + ;; + *) + echo "FATAL: unknown OS" + exit 1 + ;; +esac From 6a6767fa2aa87567ec7dfa82f3cecaf773b0b1d0 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Sun, 11 Oct 2020 11:05:14 -0400 Subject: [PATCH 2387/3747] Apply suggestions from code review Co-authored-by: Ralf Jung --- src/shims/backtrace.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/shims/backtrace.rs b/src/shims/backtrace.rs index 9b396c718493f..74edce612a293 100644 --- a/src/shims/backtrace.rs +++ b/src/shims/backtrace.rs @@ -100,9 +100,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let num_fields = dest.layout.layout.fields.count(); - if num_fields != 4 && num_fields != 5 { + if !(4..=5).contains(&num_fields) { // Always mention 5 fields, since the 4-field struct is only supported - // for backwards compatiblity. New code should declare 5 fields + // for backwards compatiblity. New code should declare 5 fields. throw_ub_format!("bad declaration of miri_resolve_frame - should return a struct with 5 fields"); } From 0893ea1973b479198722556ec2115af21e3b097c Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Sun, 11 Oct 2020 17:05:40 -0400 Subject: [PATCH 2388/3747] Rustup This gets Miri building again after the `run_compiler` changes --- benches/helpers/miri_helper.rs | 2 +- rust-version | 2 +- src/bin/miri-rustc-tests.rs | 11 ++++------- src/bin/miri.rs | 2 +- 4 files changed, 7 insertions(+), 10 deletions(-) diff --git a/benches/helpers/miri_helper.rs b/benches/helpers/miri_helper.rs index a77f914c1c6bf..261be48aa0a3d 100644 --- a/benches/helpers/miri_helper.rs +++ b/benches/helpers/miri_helper.rs @@ -55,5 +55,5 @@ pub fn run(filename: &str, bencher: &mut Bencher) { "--sysroot".to_string(), find_sysroot(), ]; - rustc_driver::run_compiler(args, &mut MiriCompilerCalls { bencher }, None, None, None).unwrap() + rustc_driver::RunCompiler::new(args, &mut MiriCompilerCalls { bencher }).run().unwrap() } diff --git a/rust-version b/rust-version index 79ba8eebc1923..6c876993b798e 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -c9ced8523bbb90561385aab305232f2167228a83 +06a079c43efb062e335e6e6c9dabd3c750619980 diff --git a/src/bin/miri-rustc-tests.rs b/src/bin/miri-rustc-tests.rs index 7c9dfbb277b95..7c2419dde3f49 100644 --- a/src/bin/miri-rustc-tests.rs +++ b/src/bin/miri-rustc-tests.rs @@ -140,13 +140,10 @@ fn main() { let buf = BufWriter::default(); let output = buf.clone(); let result = std::panic::catch_unwind(|| { - let _ = rustc_driver::run_compiler( - &args, - &mut MiriCompilerCalls { host_target }, - None, - Some(Box::new(buf)), - None, - ); + let mut callbacks = MiriCompilerCalls { host_target }; + let mut run = rustc_driver::RunCompiler::new(&args, &mut callbacks); + run.set_emitter(Some(Box::new(buf))); + let _ = run.run(); }); match result { diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 7b417990af867..71d561b9f7da3 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -157,7 +157,7 @@ fn run_compiler(mut args: Vec, callbacks: &mut (dyn rustc_driver::Callba // Invoke compiler, and handle return code. let exit_code = rustc_driver::catch_with_exit_code(move || { - rustc_driver::run_compiler(&args, callbacks, None, None, None) + rustc_driver::RunCompiler::new(&args, callbacks).run() }); std::process::exit(exit_code) } From c889eba4b27e9b365a8824969aa3deb0525fa0c0 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Sun, 11 Oct 2020 17:57:49 -0400 Subject: [PATCH 2389/3747] Add comment about deprecation --- src/shims/backtrace.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/shims/backtrace.rs b/src/shims/backtrace.rs index 74edce612a293..8cf7ac207528c 100644 --- a/src/shims/backtrace.rs +++ b/src/shims/backtrace.rs @@ -101,8 +101,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let num_fields = dest.layout.layout.fields.count(); if !(4..=5).contains(&num_fields) { - // Always mention 5 fields, since the 4-field struct is only supported - // for backwards compatiblity. New code should declare 5 fields. + // Always mention 5 fields, since the 4-field struct + // is deprecated and slated for removal. throw_ub_format!("bad declaration of miri_resolve_frame - should return a struct with 5 fields"); } @@ -133,6 +133,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(lineno_alloc, this.mplace_field(dest, 2)?.into())?; this.write_scalar(colno_alloc, this.mplace_field(dest, 3)?.into())?; + // Support a 4-field struct for now - this is deprecated + // and slated for removal. if num_fields == 5 { this.write_scalar(fn_ptr, this.mplace_field(dest, 4)?.into())?; } From 3bdf2bccaed5fa6fb21125f4563aef22810d4ef0 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 12 Oct 2020 00:15:01 +0200 Subject: [PATCH 2390/3747] Improve wording Co-authored-by: Aaron Hill --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 66f4801fc6055..be0df81f7943f 100644 --- a/README.md +++ b/README.md @@ -113,7 +113,7 @@ error: unsupported operation: can't call foreign function: bind ### Cross-interpretation: running for different targets -Miri cannot just run a binary or test suite for your host target, it can also +Miri can not only run a binary or test suite for your host target, it can also perform cross-interpretation for arbitrary foreign targets: `cargo miri run --target x86_64-unknown-linux-gnu` will run your program as if it was a Linux program, no matter your host OS. This is particularly useful if you are using From 1ae157bc9e066c0228d826720babc4d09154e682 Mon Sep 17 00:00:00 2001 From: est31 Date: Wed, 14 Oct 2020 19:16:00 +0200 Subject: [PATCH 2391/3747] Replace target.target with target Rustc removed the target wrapper and exposed the target directly. Result of running: find . -type f -exec sed -i -e 's/target\.target\([)\.,;]\)/target\1/g' {} \; Plus one manual edit of the rust-version file --- rust-version | 2 +- src/helpers.rs | 4 ++-- src/machine.rs | 2 +- src/shims/env.rs | 12 ++++++------ src/shims/foreign_items.rs | 6 +++--- src/shims/os_str.rs | 2 +- src/shims/posix/foreign_items.rs | 4 ++-- src/shims/posix/fs.rs | 4 ++-- src/shims/posix/linux/dlsym.rs | 2 +- src/shims/posix/macos/dlsym.rs | 2 +- src/shims/tls.rs | 2 +- src/shims/windows/dlsym.rs | 2 +- src/shims/windows/foreign_items.rs | 2 +- 13 files changed, 23 insertions(+), 23 deletions(-) diff --git a/rust-version b/rust-version index 6c876993b798e..e00bba6867664 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -06a079c43efb062e335e6e6c9dabd3c750619980 +b5c9e2448c9ace53ad5c11585803894651b18b0a diff --git a/src/helpers.rs b/src/helpers.rs index 23bc54e76bb07..a13d9b4519bd1 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -387,7 +387,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// if this is not the case. fn assert_target_os(&self, target_os: &str, name: &str) { assert_eq!( - self.eval_context_ref().tcx.sess.target.target.target_os, + self.eval_context_ref().tcx.sess.target.target_os, target_os, "`{}` is only available on the `{}` target OS", name, @@ -430,7 +430,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn set_last_error_from_io_error(&mut self, e: std::io::Error) -> InterpResult<'tcx> { use std::io::ErrorKind::*; let this = self.eval_context_mut(); - let target = &this.tcx.sess.target.target; + let target = &this.tcx.sess.target; let target_os = &target.target_os; let last_error = if target.options.target_family == Some("unix".to_owned()) { this.eval_libc(match e.kind() { diff --git a/src/machine.rs b/src/machine.rs index 6defb2d053aa7..544f4667e8461 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -173,7 +173,7 @@ impl MemoryExtra { pub fn init_extern_statics<'tcx, 'mir>( this: &mut MiriEvalContext<'mir, 'tcx>, ) -> InterpResult<'tcx> { - match this.tcx.sess.target.target.target_os.as_str() { + match this.tcx.sess.target.target_os.as_str() { "linux" => { // "__cxa_thread_atexit_impl" // This should be all-zero, pointer-sized. diff --git a/src/shims/env.rs b/src/shims/env.rs index 42fd6e3dced8a..2db64ad5a14c6 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -38,7 +38,7 @@ impl<'tcx> EnvVars<'tcx> { ecx: &mut InterpCx<'mir, 'tcx, Evaluator<'mir, 'tcx>>, mut excluded_env_vars: Vec, ) -> InterpResult<'tcx> { - let target_os = ecx.tcx.sess.target.target.target_os.as_str(); + let target_os = ecx.tcx.sess.target.target_os.as_str(); if target_os == "windows" { // Temporary hack: Exclude `TERM` var to avoid terminfo trying to open the termcap file. // Can be removed once https://github.com/rust-lang/miri/issues/1013 is resolved. @@ -101,7 +101,7 @@ impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mi pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { fn getenv(&mut self, name_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); - let target_os = &this.tcx.sess.target.target.target_os; + let target_os = &this.tcx.sess.target.target_os; assert!(target_os == "linux" || target_os == "macos", "`getenv` is only available for the UNIX target family"); let name_ptr = this.read_scalar(name_op)?.check_init()?; @@ -185,7 +185,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx value_op: OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, i32> { let mut this = self.eval_context_mut(); - let target_os = &this.tcx.sess.target.target.target_os; + let target_os = &this.tcx.sess.target.target_os; assert!(target_os == "linux" || target_os == "macos", "`setenv` is only available for the UNIX target family"); let name_ptr = this.read_scalar(name_op)?.check_init()?; @@ -258,7 +258,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn unsetenv(&mut self, name_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - let target_os = &this.tcx.sess.target.target.target_os; + let target_os = &this.tcx.sess.target.target_os; assert!(target_os == "linux" || target_os == "macos", "`unsetenv` is only available for the UNIX target family"); let name_ptr = this.read_scalar(name_op)?.check_init()?; @@ -290,7 +290,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx size_op: OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); - let target_os = &this.tcx.sess.target.target.target_os; + let target_os = &this.tcx.sess.target.target_os; assert!(target_os == "linux" || target_os == "macos", "`getcwd` is only available for the UNIX target family"); this.check_no_isolation("`getcwd`")?; @@ -336,7 +336,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn chdir(&mut self, path_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - let target_os = &this.tcx.sess.target.target.target_os; + let target_os = &this.tcx.sess.target.target_os; assert!(target_os == "linux" || target_os == "macos", "`getcwd` is only available for the UNIX target family"); this.check_no_isolation("`chdir`")?; diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 7118fbda2403a..cd6024444fa54 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -19,7 +19,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn min_align(&self, size: u64, kind: MiriMemoryKind) -> Align { let this = self.eval_context_ref(); // List taken from `libstd/sys_common/alloc.rs`. - let min_align = match this.tcx.sess.target.target.arch.as_str() { + let min_align = match this.tcx.sess.target.arch.as_str() { "x86" | "arm" | "mips" | "powerpc" | "powerpc64" | "asmjs" | "wasm32" => 8, "x86_64" | "aarch64" | "mips64" | "s390x" | "sparc64" => 16, arch => bug!("Unsupported target architecture: {}", arch), @@ -480,13 +480,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // Architecture-specific shims - "llvm.x86.sse2.pause" if this.tcx.sess.target.target.arch == "x86" || this.tcx.sess.target.target.arch == "x86_64" => { + "llvm.x86.sse2.pause" if this.tcx.sess.target.arch == "x86" || this.tcx.sess.target.arch == "x86_64" => { let &[] = check_arg_count(args)?; this.yield_active_thread(); } // Platform-specific shims - _ => match this.tcx.sess.target.target.target_os.as_str() { + _ => match this.tcx.sess.target.target_os.as_str() { "linux" | "macos" => return shims::posix::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, args, dest, ret), "windows" => return shims::windows::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, args, dest, ret), target => throw_unsup_format!("the target `{}` is not supported", target), diff --git a/src/shims/os_str.rs b/src/shims/os_str.rs index 7635047064f12..268b0902e9c29 100644 --- a/src/shims/os_str.rs +++ b/src/shims/os_str.rs @@ -234,7 +234,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx direction: PathConversion, ) -> Cow<'a, OsStr> { let this = self.eval_context_ref(); - let target_os = &this.tcx.sess.target.target.target_os; + let target_os = &this.tcx.sess.target.target_os; #[cfg(windows)] return if target_os == "windows" { // Windows-on-Windows, all fine. diff --git a/src/shims/posix/foreign_items.rs b/src/shims/posix/foreign_items.rs index 177678f03d74c..c527fa0d064a9 100644 --- a/src/shims/posix/foreign_items.rs +++ b/src/shims/posix/foreign_items.rs @@ -165,7 +165,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.read_scalar(handle)?.to_machine_usize(this)?; let symbol = this.read_scalar(symbol)?.check_init()?; let symbol_name = this.memory.read_c_str(symbol)?; - if let Some(dlsym) = Dlsym::from_str(symbol_name, &this.tcx.sess.target.target.target_os)? { + if let Some(dlsym) = Dlsym::from_str(symbol_name, &this.tcx.sess.target.target_os)? { let ptr = this.memory.create_fn_alloc(FnVal::Other(dlsym)); this.write_scalar(Scalar::from(ptr), dest)?; } else { @@ -452,7 +452,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Platform-specific shims _ => { - match this.tcx.sess.target.target.target_os.as_str() { + match this.tcx.sess.target.target_os.as_str() { "linux" => return shims::posix::linux::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, args, dest, ret), "macos" => return shims::posix::macos::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, args, dest, ret), _ => unreachable!(), diff --git a/src/shims/posix/fs.rs b/src/shims/posix/fs.rs index ebf7e16a15340..a9d102912ab20 100644 --- a/src/shims/posix/fs.rs +++ b/src/shims/posix/fs.rs @@ -555,7 +555,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx }, None => return this.handle_not_found(), } - } else if this.tcx.sess.target.target.target_os == "macos" + } else if this.tcx.sess.target.target_os == "macos" && cmd == this.eval_libc_i32("F_FULLFSYNC")? { let &[_, _] = check_arg_count(args)?; @@ -989,7 +989,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.check_no_isolation("`mkdir`")?; #[cfg_attr(not(unix), allow(unused_variables))] - let mode = if this.tcx.sess.target.target.target_os == "macos" { + let mode = if this.tcx.sess.target.target_os == "macos" { u32::from(this.read_scalar(mode_op)?.check_init()?.to_u16()?) } else { this.read_scalar(mode_op)?.to_u32()? diff --git a/src/shims/posix/linux/dlsym.rs b/src/shims/posix/linux/dlsym.rs index 9be300edf495a..af5f5a20e4454 100644 --- a/src/shims/posix/linux/dlsym.rs +++ b/src/shims/posix/linux/dlsym.rs @@ -27,7 +27,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let (_dest, _ret) = ret.expect("we don't support any diverging dlsym"); - assert!(this.tcx.sess.target.target.target_os == "linux"); + assert!(this.tcx.sess.target.target_os == "linux"); match dlsym {} } diff --git a/src/shims/posix/macos/dlsym.rs b/src/shims/posix/macos/dlsym.rs index c9f57090ff8a2..82d8b16ad66ac 100644 --- a/src/shims/posix/macos/dlsym.rs +++ b/src/shims/posix/macos/dlsym.rs @@ -32,7 +32,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let (dest, ret) = ret.expect("we don't support any diverging dlsym"); - assert!(this.tcx.sess.target.target.target_os == "macos"); + assert!(this.tcx.sess.target.target_os == "macos"); match dlsym { Dlsym::getentropy => { diff --git a/src/shims/tls.rs b/src/shims/tls.rs index 2ba0782f7054f..7b4d8fa56ae4f 100644 --- a/src/shims/tls.rs +++ b/src/shims/tls.rs @@ -340,7 +340,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // This is the first time we got asked to schedule a destructor. The // Windows schedule destructor function must be called exactly once, // this is why it is in this block. - if this.tcx.sess.target.target.target_os == "windows" { + if this.tcx.sess.target.target_os == "windows" { // On Windows, we signal that the thread quit by starting the // relevant function, reenabling the thread, and going back to // the scheduler. diff --git a/src/shims/windows/dlsym.rs b/src/shims/windows/dlsym.rs index 91bfedff8db68..5454a00f14d5b 100644 --- a/src/shims/windows/dlsym.rs +++ b/src/shims/windows/dlsym.rs @@ -44,7 +44,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let (dest, ret) = ret.expect("we don't support any diverging dlsym"); - assert!(this.tcx.sess.target.target.target_os == "windows"); + assert!(this.tcx.sess.target.target_os == "windows"); match dlsym { Dlsym::AcquireSRWLockExclusive => { diff --git a/src/shims/windows/foreign_items.rs b/src/shims/windows/foreign_items.rs index fc1093b64fb4b..d141fa57e13a4 100644 --- a/src/shims/windows/foreign_items.rs +++ b/src/shims/windows/foreign_items.rs @@ -213,7 +213,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let &[hModule, lpProcName] = check_arg_count(args)?; this.read_scalar(hModule)?.to_machine_isize(this)?; let name = this.memory.read_c_str(this.read_scalar(lpProcName)?.check_init()?)?; - if let Some(dlsym) = Dlsym::from_str(name, &this.tcx.sess.target.target.target_os)? { + if let Some(dlsym) = Dlsym::from_str(name, &this.tcx.sess.target.target_os)? { let ptr = this.memory.create_fn_alloc(FnVal::Other(dlsym)); this.write_scalar(Scalar::from(ptr), dest)?; } else { From 67cf6c21761a778d45784bc1189bdba7618a6ff1 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 18 Oct 2020 00:49:52 +0200 Subject: [PATCH 2392/3747] rustup; the bad compile times for the float test are fixed --- rust-version | 2 +- tests/run-pass/float.rs | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/rust-version b/rust-version index e00bba6867664..13526a3fac9be 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -b5c9e2448c9ace53ad5c11585803894651b18b0a +043eca7f0b34d12e61c44206beca740628647080 diff --git a/tests/run-pass/float.rs b/tests/run-pass/float.rs index 62d9c60766080..d0df13490f0c8 100644 --- a/tests/run-pass/float.rs +++ b/tests/run-pass/float.rs @@ -1,5 +1,3 @@ -// compile-flags: -Zmir-opt-level=0 -// FIXME: Using opt-level 2 here makes the test take forever (https://github.com/rust-lang/rust/issues/73717). #![feature(stmt_expr_attributes, test)] use std::fmt::Debug; use std::hint::black_box; From 8b10dbfeaab5826fb3d179bb94454a80182a9c3a Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Sat, 17 Oct 2020 15:36:05 -0400 Subject: [PATCH 2393/3747] Test std::backtrace::Backtrace Fixes #1578 --- tests/run-pass/backtrace-std.rs | 22 ++++++++++++++++++++++ tests/run-pass/backtrace-std.stderr | 28 ++++++++++++++++++++++++++++ 2 files changed, 50 insertions(+) create mode 100644 tests/run-pass/backtrace-std.rs create mode 100644 tests/run-pass/backtrace-std.stderr diff --git a/tests/run-pass/backtrace-std.rs b/tests/run-pass/backtrace-std.rs new file mode 100644 index 0000000000000..579b4f32e7ccf --- /dev/null +++ b/tests/run-pass/backtrace-std.rs @@ -0,0 +1,22 @@ +// normalize-stderr-test ".*/(rust|checkout)/library/" -> "RUSTLIB/" +// normalize-stderr-test "RUSTLIB/(.*):\d+:\d+ "-> "RUSTLIB/$1:LL:COL " +// normalize-stderr-test "::<.*>" -> "" +// compile-flags: -Zmiri-disable-isolation + +#![feature(backtrace)] + +use std::backtrace::Backtrace; + +#[inline(never)] fn func_a() -> Backtrace { func_b::() } +#[inline(never)] fn func_b() -> Backtrace { func_c() } + +macro_rules! invoke_func_d { + () => { func_d() } +} + +#[inline(never)] fn func_c() -> Backtrace { invoke_func_d!() } +#[inline(never)] fn func_d() -> Backtrace { Backtrace::capture() } + +fn main() { + eprint!("{}", func_a()); +} diff --git a/tests/run-pass/backtrace-std.stderr b/tests/run-pass/backtrace-std.stderr new file mode 100644 index 0000000000000..d14735c0405f1 --- /dev/null +++ b/tests/run-pass/backtrace-std.stderr @@ -0,0 +1,28 @@ + 0: func_d + at $DIR/backtrace-std.rs:18 + 1: func_c + at $DIR/backtrace-std.rs:17 + 2: func_b + at $DIR/backtrace-std.rs:11 + 3: func_a + at $DIR/backtrace-std.rs:10 + 4: main + at $DIR/backtrace-std.rs:21 + 5: >::call_once - shim(fn()) +RUSTLIB/core/src/ops/function.rs:227 + 6: std::sys_common::backtrace::__rust_begin_short_backtrace +RUSTLIB/std/src/sys_common/backtrace.rs:125 + 7: std::rt::lang_start::{closure#0} +RUSTLIB/std/src/rt.rs:66 + 8: std::ops::function::impls::call_once +RUSTLIB/core/src/ops/function.rs:259 + 9: std::panicking::r#try::do_call +RUSTLIB/std/src/panicking.rs:381 + 10: std::panicking::r#try +RUSTLIB/std/src/panicking.rs:345 + 11: std::panic::catch_unwind +RUSTLIB/std/src/panic.rs:382 + 12: std::rt::lang_start_internal +RUSTLIB/std/src/rt.rs:51 + 13: std::rt::lang_start +RUSTLIB/std/src/rt.rs:65 From 5df6d8bec6155e5300d28454a1fff7b52e7c7748 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 18 Oct 2020 11:22:09 +0200 Subject: [PATCH 2394/3747] test new available_concurrency function --- rust-version | 2 +- tests/run-pass/available-concurrency.rs | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) create mode 100644 tests/run-pass/available-concurrency.rs diff --git a/rust-version b/rust-version index 13526a3fac9be..d5ddd1d0371e6 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -043eca7f0b34d12e61c44206beca740628647080 +c38ddb8040edce1b05bc09a0e8439472e9f67623 diff --git a/tests/run-pass/available-concurrency.rs b/tests/run-pass/available-concurrency.rs new file mode 100644 index 0000000000000..5f3121ca8a63e --- /dev/null +++ b/tests/run-pass/available-concurrency.rs @@ -0,0 +1,5 @@ +#![feature(available_concurrency)] + +fn main() { + assert_eq!(std::thread::available_concurrency().unwrap().get(), 1); +} From 8462558b6c819e4dc9c82981f101fcb3e2853811 Mon Sep 17 00:00:00 2001 From: Lzu Tao Date: Tue, 20 Oct 2020 12:26:30 +0700 Subject: [PATCH 2395/3747] build: Gate only on GHA: remove travis and appveyor ci config --- .appveyor.yml | 50 ------------------------------------------ .travis.yml | 60 --------------------------------------------------- 2 files changed, 110 deletions(-) delete mode 100644 .appveyor.yml delete mode 100644 .travis.yml diff --git a/.appveyor.yml b/.appveyor.yml deleted file mode 100644 index 82c668f0e75d7..0000000000000 --- a/.appveyor.yml +++ /dev/null @@ -1,50 +0,0 @@ -build: off # No Visual Studio auto-build. -environment: - global: - PROJECT_NAME: miri - matrix: - - HOST_TARGET: i686-pc-windows-msvc -matrix: - fast_finish: true # Immediately finish build once one of the jobs fails. -cache: -- '%USERPROFILE%\.cargo' -- '%USERPROFILE%\.rustup' - -# branches to build -branches: - # whitelist - only: - - auto - - try - -install: -# Compute the Rust version we use. -- set /p RUSTC_HASH= Date: Tue, 20 Oct 2020 13:27:58 -0400 Subject: [PATCH 2396/3747] Enable `backtrace` feature in the generated `Xargo.toml` This allows the normal std panic hook to print a backtrace if `RUST_BACKTRACE=1` and `-Z miri-disable-isolation` are set --- README.md | 13 ++++++++++ cargo-miri/bin.rs | 2 +- tests/run-pass/concurrency/simple.stderr | 1 + tests/run-pass/panic/catch_panic.stderr | 1 + tests/run-pass/panic/concurrent-panic.stderr | 1 + tests/run-pass/panic/div-by-zero-2.stderr | 1 + .../run-pass/panic/overflowing-lsh-neg.stderr | 1 + tests/run-pass/panic/overflowing-rsh-1.stderr | 1 + tests/run-pass/panic/overflowing-rsh-2.stderr | 1 + tests/run-pass/panic/panic1.rs | 6 +++++ tests/run-pass/panic/panic1.stderr | 24 ++++++++++++++++++- tests/run-pass/panic/panic2.stderr | 1 + tests/run-pass/panic/panic3.stderr | 1 + tests/run-pass/panic/panic4.stderr | 1 + tests/run-pass/transmute_fat2.stderr | 1 + 15 files changed, 54 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index d8f0ef583f116..d41dc862e5999 100644 --- a/README.md +++ b/README.md @@ -152,6 +152,19 @@ cargo miri test When using the above instructions, you may encounter a number of confusing compiler errors. +### "note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace" + +You may see this when trying to get Miri to display a backtrace. By default, Miri +doesn't expose any environment to the program, so running +`RUST_BACKTRACE=1 cargo miri test` will not do what you expect. + +To get a backtrace, you need to disable isolation +[using `-Zmiri-disable-isolation`](#miri-flags): + +```sh +RUST_BACKTRACE=1 MIRIFLAGS="-Zmiri-disable-isolation" cargo miri test +``` + #### "found possibly newer version of crate `std` which `` depends on" Your build directory may contain artifacts from an earlier build that have/have diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index 72c873b229e93..62fb9299c4563 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -296,7 +296,7 @@ fn setup(subcommand: MiriCommand) { [dependencies.std] default_features = false # We support unwinding, so enable that panic runtime. -features = ["panic_unwind"] +features = ["panic_unwind", "backtrace"] [dependencies.test] "#, diff --git a/tests/run-pass/concurrency/simple.stderr b/tests/run-pass/concurrency/simple.stderr index e52d07cdc73f7..7060411278e6e 100644 --- a/tests/run-pass/concurrency/simple.stderr +++ b/tests/run-pass/concurrency/simple.stderr @@ -1,4 +1,5 @@ warning: thread support is experimental. For example, Miri does not detect data races yet. thread '' panicked at 'Hello!', $DIR/simple.rs:54:9 +note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace thread 'childthread' panicked at 'Hello, world!', $DIR/simple.rs:64:9 diff --git a/tests/run-pass/panic/catch_panic.stderr b/tests/run-pass/panic/catch_panic.stderr index c31f54aac729a..30c7767b5642b 100644 --- a/tests/run-pass/panic/catch_panic.stderr +++ b/tests/run-pass/panic/catch_panic.stderr @@ -1,4 +1,5 @@ thread 'main' panicked at 'Hello from panic: std', $DIR/catch_panic.rs:LL:27 +note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace Caught panic message (&str): Hello from panic: std thread 'main' panicked at 'Hello from panic: 1', $DIR/catch_panic.rs:LL:26 Caught panic message (String): Hello from panic: 1 diff --git a/tests/run-pass/panic/concurrent-panic.stderr b/tests/run-pass/panic/concurrent-panic.stderr index d538efdb0e88f..eb5b5f59a0cb1 100644 --- a/tests/run-pass/panic/concurrent-panic.stderr +++ b/tests/run-pass/panic/concurrent-panic.stderr @@ -3,6 +3,7 @@ warning: thread support is experimental. For example, Miri does not detect data Thread 1 starting, will block on mutex Thread 1 reported it has started thread '' panicked at 'panic in thread 2', $DIR/concurrent-panic.rs:65:13 +note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace Thread 2 blocking on thread 1 Thread 2 reported it has started Unlocking mutex diff --git a/tests/run-pass/panic/div-by-zero-2.stderr b/tests/run-pass/panic/div-by-zero-2.stderr index d255811be2a94..60ff33c8bfcd3 100644 --- a/tests/run-pass/panic/div-by-zero-2.stderr +++ b/tests/run-pass/panic/div-by-zero-2.stderr @@ -1 +1,2 @@ thread 'main' panicked at 'attempt to divide by zero', $DIR/div-by-zero-2.rs:4:14 +note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace diff --git a/tests/run-pass/panic/overflowing-lsh-neg.stderr b/tests/run-pass/panic/overflowing-lsh-neg.stderr index 04d98a0a2f155..64959da0faea7 100644 --- a/tests/run-pass/panic/overflowing-lsh-neg.stderr +++ b/tests/run-pass/panic/overflowing-lsh-neg.stderr @@ -1 +1,2 @@ thread 'main' panicked at 'attempt to shift left with overflow', $DIR/overflowing-lsh-neg.rs:4:14 +note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace diff --git a/tests/run-pass/panic/overflowing-rsh-1.stderr b/tests/run-pass/panic/overflowing-rsh-1.stderr index a9a72f46222df..bd8843f8d6039 100644 --- a/tests/run-pass/panic/overflowing-rsh-1.stderr +++ b/tests/run-pass/panic/overflowing-rsh-1.stderr @@ -1 +1,2 @@ thread 'main' panicked at 'attempt to shift right with overflow', $DIR/overflowing-rsh-1.rs:4:14 +note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace diff --git a/tests/run-pass/panic/overflowing-rsh-2.stderr b/tests/run-pass/panic/overflowing-rsh-2.stderr index 24b61194565dd..c43090ea70371 100644 --- a/tests/run-pass/panic/overflowing-rsh-2.stderr +++ b/tests/run-pass/panic/overflowing-rsh-2.stderr @@ -1 +1,2 @@ thread 'main' panicked at 'attempt to shift right with overflow', $DIR/overflowing-rsh-2.rs:5:14 +note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace diff --git a/tests/run-pass/panic/panic1.rs b/tests/run-pass/panic/panic1.rs index 9d9ad28df5a71..4500c916ad6a5 100644 --- a/tests/run-pass/panic/panic1.rs +++ b/tests/run-pass/panic/panic1.rs @@ -1,3 +1,9 @@ +// rustc-env: RUST_BACKTRACE=1 +// compile-flags: -Zmiri-disable-isolation +// normalize-stderr-test ".*/(rust|checkout)/library/" -> "RUSTLIB/" +// normalize-stderr-test "RUSTLIB/(.*):\d+:\d+ "-> "RUSTLIB/$1:LL:COL " +// normalize-stderr-test "::<.*>" -> "" + fn main() { std::panic!("panicking from libstd"); } diff --git a/tests/run-pass/panic/panic1.stderr b/tests/run-pass/panic/panic1.stderr index 954b8799a0823..e06ec1b9ce32d 100644 --- a/tests/run-pass/panic/panic1.stderr +++ b/tests/run-pass/panic/panic1.stderr @@ -1 +1,23 @@ -thread 'main' panicked at 'panicking from libstd', $DIR/panic1.rs:2:5 +thread 'main' panicked at 'panicking from libstd', $DIR/panic1.rs:8:5 +stack backtrace: + 0: std::rt::begin_panic +RUSTLIB/std/src/panicking.rs:505:12 + 1: main + at $DIR/panic1.rs:8:5 + 2: >::call_once - shim(fn()) +RUSTLIB/core/src/ops/function.rs:227:5 + 3: std::rt::lang_start::{closure#0} +RUSTLIB/std/src/rt.rs:66:18 + 4: std::ops::function::impls::call_once +RUSTLIB/core/src/ops/function.rs:259:13 + 5: std::panicking::r#try::do_call +RUSTLIB/std/src/panicking.rs:381:40 + 6: std::panicking::r#try +RUSTLIB/std/src/panicking.rs:345:19 + 7: std::panic::catch_unwind +RUSTLIB/std/src/panic.rs:382:14 + 8: std::rt::lang_start_internal +RUSTLIB/std/src/rt.rs:51:25 + 9: std::rt::lang_start +RUSTLIB/std/src/rt.rs:65:5 +note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace. diff --git a/tests/run-pass/panic/panic2.stderr b/tests/run-pass/panic/panic2.stderr index e90e3502cbfbf..c0415b4e70f07 100644 --- a/tests/run-pass/panic/panic2.stderr +++ b/tests/run-pass/panic/panic2.stderr @@ -1 +1,2 @@ thread 'main' panicked at '42-panicking from libstd', $DIR/panic2.rs:2:5 +note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace diff --git a/tests/run-pass/panic/panic3.stderr b/tests/run-pass/panic/panic3.stderr index 0a3c191b282ec..8aa8761aebf77 100644 --- a/tests/run-pass/panic/panic3.stderr +++ b/tests/run-pass/panic/panic3.stderr @@ -1 +1,2 @@ thread 'main' panicked at 'panicking from libcore', $DIR/panic3.rs:2:5 +note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace diff --git a/tests/run-pass/panic/panic4.stderr b/tests/run-pass/panic/panic4.stderr index 946059b1e49fc..a71d25b74c435 100644 --- a/tests/run-pass/panic/panic4.stderr +++ b/tests/run-pass/panic/panic4.stderr @@ -1 +1,2 @@ thread 'main' panicked at '42-panicking from libcore', $DIR/panic4.rs:2:5 +note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace diff --git a/tests/run-pass/transmute_fat2.stderr b/tests/run-pass/transmute_fat2.stderr index c8298a6c23c66..54ccdfb5e4656 100644 --- a/tests/run-pass/transmute_fat2.stderr +++ b/tests/run-pass/transmute_fat2.stderr @@ -1 +1,2 @@ thread 'main' panicked at 'index out of bounds: the len is 0 but the index is 0', $DIR/transmute_fat2.rs:15:5 +note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace From 0835ac6ec3d071440cc4fa7490a884615dad862d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 21 Oct 2020 12:50:45 +0200 Subject: [PATCH 2397/3747] another TiKV bug for the trophy case :) --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index d8f0ef583f116..8c908149998d1 100644 --- a/README.md +++ b/README.md @@ -372,6 +372,7 @@ Definite bugs found: * [`servo_arc` creating a dangling shared reference](https://github.com/servo/servo/issues/26357) * [TiKV constructing out-of-bounds pointers (and overlapping mutable references)](https://github.com/tikv/tikv/pull/7751) * [`encoding_rs` doing out-of-bounds pointer arithmetic](https://github.com/hsivonen/encoding_rs/pull/53) +* [TiKV using `Vec::from_raw_parts` incorrectly](https://github.com/tikv/agatedb/pull/24) Violations of [Stacked Borrows] found that are likely bugs (but Stacked Borrows is currently just an experiment): From ad07b2bd4479f75ae58b0f9aeaae1c951c3ecc92 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 22 Oct 2020 09:47:02 +0200 Subject: [PATCH 2398/3747] rustup; increase slack for timing tests --- rust-version | 2 +- tests/run-pass/concurrency/sync.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/rust-version b/rust-version index d5ddd1d0371e6..d661d821503bc 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -c38ddb8040edce1b05bc09a0e8439472e9f67623 +8f0fa9d51ff4ad2c0869e660856cd327e79915e9 diff --git a/tests/run-pass/concurrency/sync.rs b/tests/run-pass/concurrency/sync.rs index 69943e5495e2e..bdbc4b90f6ed4 100644 --- a/tests/run-pass/concurrency/sync.rs +++ b/tests/run-pass/concurrency/sync.rs @@ -319,7 +319,7 @@ fn park_timeout() { // Normally, waiting in park/park_timeout may spuriously wake up early, but we // know Miri's timed synchronization primitives do not do that. - assert!((200..500).contains(&start.elapsed().as_millis())); + assert!((200..1000).contains(&start.elapsed().as_millis())); } fn park_unpark() { @@ -337,7 +337,7 @@ fn park_unpark() { // Normally, waiting in park/park_timeout may spuriously wake up early, but we // know Miri's timed synchronization primitives do not do that. - assert!((200..500).contains(&start.elapsed().as_millis())); + assert!((200..1000).contains(&start.elapsed().as_millis())); } fn main() { From 80c4b5d6741745803f86c8a96389001e3cf617ca Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 22 Oct 2020 10:36:01 +0200 Subject: [PATCH 2399/3747] fix './miri test' --- tests/compiletest.rs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/tests/compiletest.rs b/tests/compiletest.rs index 35c1de3399c02..ac44c48d6214a 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -24,10 +24,10 @@ fn run_tests(mode: &str, path: &str, target: &str) { } else { flags.push("-Dwarnings -Dunused".to_owned()); // overwrite the -Aunused in compiletest-rs } - if let Ok(sysroot) = std::env::var("MIRI_SYSROOT") { + if let Ok(sysroot) = env::var("MIRI_SYSROOT") { flags.push(format!("--sysroot {}", sysroot)); } - if let Ok(extra_flags) = std::env::var("MIRIFLAGS") { + if let Ok(extra_flags) = env::var("MIRIFLAGS") { flags.push(extra_flags); } @@ -80,14 +80,16 @@ fn get_host() -> String { } fn get_target() -> String { - std::env::var("MIRI_TEST_TARGET").unwrap_or_else(|_| get_host()) + env::var("MIRI_TEST_TARGET").unwrap_or_else(|_| get_host()) } fn test_runner(_tests: &[&()]) { // Add a test env var to do environment communication tests. - std::env::set_var("MIRI_ENV_VAR_TEST", "0"); + env::set_var("MIRI_ENV_VAR_TEST", "0"); // Let the tests know where to store temp files (they might run for a different target, which can make this hard to find). - std::env::set_var("MIRI_TEMP", std::env::temp_dir()); + env::set_var("MIRI_TEMP", env::temp_dir()); + // Panic tests expect backtraces to be printed. + env::set_var("RUST_BACKTRACE", "1"); let target = get_target(); miri_pass("tests/run-pass", &target); From e9b8693aaae84d317d92de7c6438c3117af83122 Mon Sep 17 00:00:00 2001 From: Camelid Date: Fri, 23 Oct 2020 11:48:34 -0700 Subject: [PATCH 2400/3747] Don't force-install xargo Previously miri used `cargo install xargo -f` which shouldn't be necessary anymore since `cargo install` will now upgrade without `-f`. The only reason I can see to use `-f` is from the cargo docs: > This is also useful if something has changed on the system that you > want to rebuild with, such as a newer version of `rustc`. See the [discussion on Zulip](https://rust-lang.zulipchat.com/#narrow/stream/131828-t-compiler/topic/why.20does.20miri.20require.20xargo/near/214351239). --- cargo-miri/bin.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index 62fb9299c4563..a13e689cad20a 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -241,7 +241,7 @@ fn setup(subcommand: MiriCommand) { show_error(format!("xargo is too old; please upgrade to the latest version")) } let mut cmd = cargo(); - cmd.args(&["install", "xargo", "-f"]); + cmd.args(&["install", "xargo"]); ask_to_run(cmd, ask_user, "install a recent enough xargo"); } From 8df239b020694b6d150de1a719a80490337cdd55 Mon Sep 17 00:00:00 2001 From: Camelid Date: Fri, 23 Oct 2020 11:53:34 -0700 Subject: [PATCH 2401/3747] Fix README --- README.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 078e5a8acc094..b638c3bca1ce9 100644 --- a/README.md +++ b/README.md @@ -406,10 +406,13 @@ Violations of [Stacked Borrows] found that are likely bugs (but Stacked Borrows ## License Licensed under either of + * Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) * MIT license ([LICENSE-MIT](LICENSE-MIT) or - http://opensource.org/licenses/MIT) at your option. + http://opensource.org/licenses/MIT) + +at your option. ### Contribution From 60a2c9b1f823259bf1fa0ce238b09d1064066dd8 Mon Sep 17 00:00:00 2001 From: Camelid Date: Fri, 23 Oct 2020 13:00:33 -0700 Subject: [PATCH 2402/3747] Hide readlink error in `./miri` `./miri` is just testing whether the platform supports `readlink -e`, but it didn't hide properly hide the stderr output. This fixes that. --- miri | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/miri b/miri index aef61b6dd68d3..161276c52b9c7 100755 --- a/miri +++ b/miri @@ -40,7 +40,7 @@ TARGET=$(rustc --version --verbose | grep "^host:" | cut -d ' ' -f 2) SYSROOT=$(rustc --print sysroot) LIBDIR=$SYSROOT/lib/rustlib/$TARGET/lib MIRIDIR=$(dirname "$0") -if readlink -e . >/dev/null; then +if readlink -e . &>/dev/null; then # This platform supports `readlink -e`. MIRIDIR=$(readlink -e "$MIRIDIR") fi From 05e9ae042c83345d00d6abba2e4f567b163a90f7 Mon Sep 17 00:00:00 2001 From: Camelid Date: Sat, 24 Oct 2020 12:46:02 -0700 Subject: [PATCH 2403/3747] Make `miri_default_args()` a constant --- src/bin/miri-rustc-tests.rs | 2 +- src/bin/miri.rs | 2 +- src/lib.rs | 16 +++++++--------- 3 files changed, 9 insertions(+), 11 deletions(-) diff --git a/src/bin/miri-rustc-tests.rs b/src/bin/miri-rustc-tests.rs index 7c2419dde3f49..cef71a9889f12 100644 --- a/src/bin/miri-rustc-tests.rs +++ b/src/bin/miri-rustc-tests.rs @@ -109,7 +109,7 @@ fn main() { } }) .collect(); - args.splice(1..1, miri::miri_default_args().iter().map(ToString::to_string)); + args.splice(1..1, miri::MIRI_DEFAULT_ARGS.iter().map(ToString::to_string)); // file to process args.push(path.display().to_string()); diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 71d561b9f7da3..5769590ad094e 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -153,7 +153,7 @@ fn run_compiler(mut args: Vec, callbacks: &mut (dyn rustc_driver::Callba // Some options have different defaults in Miri than in plain rustc; apply those by making // them the first arguments after the binary name (but later arguments can overwrite them). - args.splice(1..1, miri::miri_default_args().iter().map(ToString::to_string)); + args.splice(1..1, miri::MIRI_DEFAULT_ARGS.iter().map(ToString::to_string)); // Invoke compiler, and handle return code. let exit_code = rustc_driver::catch_with_exit_code(move || { diff --git a/src/lib.rs b/src/lib.rs index 77eac9a6324a4..d4802f3b11fa4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -77,12 +77,10 @@ pub use crate::sync::{ /// Insert rustc arguments at the beginning of the argument list that Miri wants to be /// set per default, for maximal validation power. -pub fn miri_default_args() -> &'static [&'static str] { - &[ - "-Zalways-encode-mir", - "-Zmir-emit-retag", - "-Zmir-opt-level=0", - "--cfg=miri", - "-Cdebug-assertions=on", - ] -} +pub const MIRI_DEFAULT_ARGS: &[&str] = &[ + "-Zalways-encode-mir", + "-Zmir-emit-retag", + "-Zmir-opt-level=0", + "--cfg=miri", + "-Cdebug-assertions=on", +]; From ddcc4f241e1e9987b050067f4303d0449774b36e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 25 Oct 2020 10:00:50 +0100 Subject: [PATCH 2404/3747] rustup; make panic output less dependent on stdlib internals --- rust-version | 2 +- tests/run-pass/backtrace-std.rs | 4 ++-- tests/run-pass/backtrace-std.stderr | 18 +++++++++--------- tests/run-pass/panic/catch_panic.stderr | 8 ++++---- tests/run-pass/panic/panic1.rs | 4 ++-- tests/run-pass/panic/panic1.stderr | 18 +++++++++--------- 6 files changed, 27 insertions(+), 27 deletions(-) diff --git a/rust-version b/rust-version index d661d821503bc..44e9a77940d6e 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -8f0fa9d51ff4ad2c0869e660856cd327e79915e9 +17cc9b6256c95c31944591aec683884fead4e3b6 diff --git a/tests/run-pass/backtrace-std.rs b/tests/run-pass/backtrace-std.rs index 579b4f32e7ccf..fb596b1d2020c 100644 --- a/tests/run-pass/backtrace-std.rs +++ b/tests/run-pass/backtrace-std.rs @@ -1,5 +1,5 @@ -// normalize-stderr-test ".*/(rust|checkout)/library/" -> "RUSTLIB/" -// normalize-stderr-test "RUSTLIB/(.*):\d+:\d+ "-> "RUSTLIB/$1:LL:COL " +// normalize-stderr-test "at .*/(rust|checkout)/library/" -> "at RUSTLIB/" +// normalize-stderr-test "RUSTLIB/(.*):\d+"-> "RUSTLIB/$1:LL" // normalize-stderr-test "::<.*>" -> "" // compile-flags: -Zmiri-disable-isolation diff --git a/tests/run-pass/backtrace-std.stderr b/tests/run-pass/backtrace-std.stderr index d14735c0405f1..45c46acc331c9 100644 --- a/tests/run-pass/backtrace-std.stderr +++ b/tests/run-pass/backtrace-std.stderr @@ -9,20 +9,20 @@ 4: main at $DIR/backtrace-std.rs:21 5: >::call_once - shim(fn()) -RUSTLIB/core/src/ops/function.rs:227 + at RUSTLIB/core/src/ops/function.rs:LL 6: std::sys_common::backtrace::__rust_begin_short_backtrace -RUSTLIB/std/src/sys_common/backtrace.rs:125 + at RUSTLIB/std/src/sys_common/backtrace.rs:LL 7: std::rt::lang_start::{closure#0} -RUSTLIB/std/src/rt.rs:66 + at RUSTLIB/std/src/rt.rs:LL 8: std::ops::function::impls::call_once -RUSTLIB/core/src/ops/function.rs:259 + at RUSTLIB/core/src/ops/function.rs:LL 9: std::panicking::r#try::do_call -RUSTLIB/std/src/panicking.rs:381 + at RUSTLIB/std/src/panicking.rs:LL 10: std::panicking::r#try -RUSTLIB/std/src/panicking.rs:345 + at RUSTLIB/std/src/panicking.rs:LL 11: std::panic::catch_unwind -RUSTLIB/std/src/panic.rs:382 + at RUSTLIB/std/src/panic.rs:LL 12: std::rt::lang_start_internal -RUSTLIB/std/src/rt.rs:51 + at RUSTLIB/std/src/rt.rs:LL 13: std::rt::lang_start -RUSTLIB/std/src/rt.rs:65 + at RUSTLIB/std/src/rt.rs:LL diff --git a/tests/run-pass/panic/catch_panic.stderr b/tests/run-pass/panic/catch_panic.stderr index 30c7767b5642b..c4c04fece901c 100644 --- a/tests/run-pass/panic/catch_panic.stderr +++ b/tests/run-pass/panic/catch_panic.stderr @@ -8,7 +8,7 @@ Caught panic message (String): Hello from panic: 2 thread 'main' panicked at 'Box', $DIR/catch_panic.rs:LL:27 Failed to get caught panic message. thread 'main' panicked at 'Hello from panic: core', $DIR/catch_panic.rs:LL:27 -Caught panic message (String): Hello from panic: core +Caught panic message (&str): Hello from panic: core thread 'main' panicked at 'Hello from panic: 5', $DIR/catch_panic.rs:LL:26 Caught panic message (String): Hello from panic: 5 thread 'main' panicked at 'Hello from panic: 6', $DIR/catch_panic.rs:LL:26 @@ -16,13 +16,13 @@ Caught panic message (String): Hello from panic: 6 thread 'main' panicked at 'index out of bounds: the len is 3 but the index is 4', $DIR/catch_panic.rs:LL:33 Caught panic message (String): index out of bounds: the len is 3 but the index is 4 thread 'main' panicked at 'attempt to divide by zero', $DIR/catch_panic.rs:LL:33 -Caught panic message (String): attempt to divide by zero +Caught panic message (&str): attempt to divide by zero thread 'main' panicked at 'align_offset: align is not a power-of-two', $LOC -Caught panic message (String): align_offset: align is not a power-of-two +Caught panic message (&str): align_offset: align is not a power-of-two thread 'main' panicked at 'assertion failed: false', $DIR/catch_panic.rs:LL:29 Caught panic message (&str): assertion failed: false thread 'main' panicked at 'assertion failed: false', $DIR/catch_panic.rs:LL:29 Caught panic message (&str): assertion failed: false thread 'main' panicked at 'called `Option::unwrap()` on a `None` value', $LOC -Caught panic message (String): called `Option::unwrap()` on a `None` value +Caught panic message (&str): called `Option::unwrap()` on a `None` value Success! diff --git a/tests/run-pass/panic/panic1.rs b/tests/run-pass/panic/panic1.rs index 4500c916ad6a5..08ac3a0728522 100644 --- a/tests/run-pass/panic/panic1.rs +++ b/tests/run-pass/panic/panic1.rs @@ -1,9 +1,9 @@ // rustc-env: RUST_BACKTRACE=1 // compile-flags: -Zmiri-disable-isolation -// normalize-stderr-test ".*/(rust|checkout)/library/" -> "RUSTLIB/" -// normalize-stderr-test "RUSTLIB/(.*):\d+:\d+ "-> "RUSTLIB/$1:LL:COL " +// normalize-stderr-test "at .*/(rust|checkout)/library/.*" -> "at RUSTLIB/$$FILE:LL:COL" // normalize-stderr-test "::<.*>" -> "" + fn main() { std::panic!("panicking from libstd"); } diff --git a/tests/run-pass/panic/panic1.stderr b/tests/run-pass/panic/panic1.stderr index e06ec1b9ce32d..e0f1aa5dad70b 100644 --- a/tests/run-pass/panic/panic1.stderr +++ b/tests/run-pass/panic/panic1.stderr @@ -1,23 +1,23 @@ thread 'main' panicked at 'panicking from libstd', $DIR/panic1.rs:8:5 stack backtrace: 0: std::rt::begin_panic -RUSTLIB/std/src/panicking.rs:505:12 + at RUSTLIB/$FILE:LL:COL 1: main at $DIR/panic1.rs:8:5 2: >::call_once - shim(fn()) -RUSTLIB/core/src/ops/function.rs:227:5 + at RUSTLIB/$FILE:LL:COL 3: std::rt::lang_start::{closure#0} -RUSTLIB/std/src/rt.rs:66:18 + at RUSTLIB/$FILE:LL:COL 4: std::ops::function::impls::call_once -RUSTLIB/core/src/ops/function.rs:259:13 + at RUSTLIB/$FILE:LL:COL 5: std::panicking::r#try::do_call -RUSTLIB/std/src/panicking.rs:381:40 + at RUSTLIB/$FILE:LL:COL 6: std::panicking::r#try -RUSTLIB/std/src/panicking.rs:345:19 + at RUSTLIB/$FILE:LL:COL 7: std::panic::catch_unwind -RUSTLIB/std/src/panic.rs:382:14 + at RUSTLIB/$FILE:LL:COL 8: std::rt::lang_start_internal -RUSTLIB/std/src/rt.rs:51:25 + at RUSTLIB/$FILE:LL:COL 9: std::rt::lang_start -RUSTLIB/std/src/rt.rs:65:5 + at RUSTLIB/$FILE:LL:COL note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace. From 16491aef42d386a9e721b913b9b4d8361a127a5a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 27 Oct 2020 14:21:59 +0100 Subject: [PATCH 2405/3747] Use bash to make sure &> works --- miri | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/miri b/miri index 161276c52b9c7..337b2a496de87 100755 --- a/miri +++ b/miri @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/bash set -e USAGE=$(cat <<"EOF" COMMANDS From 086e9c49a95ab30380954cc3bca632145786cee2 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 27 Oct 2020 14:22:29 +0100 Subject: [PATCH 2406/3747] pointer tag tracking: also show when tag is being created --- src/diagnostics.rs | 4 ++++ src/stacked_borrows.rs | 3 +++ 2 files changed, 7 insertions(+) diff --git a/src/diagnostics.rs b/src/diagnostics.rs index 81cd049217227..12ad93a5289ee 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -1,5 +1,6 @@ use std::cell::RefCell; use std::fmt; +use std::num::NonZeroU64; use log::trace; @@ -41,6 +42,7 @@ impl MachineStopType for TerminationInfo {} /// Miri specific diagnostics pub enum NonHaltingDiagnostic { + CreatedPointerTag(NonZeroU64), PoppedPointerTag(Item), CreatedCallId(CallId), CreatedAlloc(AllocId), @@ -266,6 +268,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx for e in diagnostics.drain(..) { use NonHaltingDiagnostic::*; let msg = match e { + CreatedPointerTag(tag) => + format!("created tag {:?}", tag), PoppedPointerTag(item) => format!("popped tracked tag for item {:?}", item), CreatedCallId(id) => diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 817ed99d2bb27..257208056d764 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -168,6 +168,9 @@ impl GlobalState { fn new_ptr(&mut self) -> PtrId { let id = self.next_ptr_id; + if Some(id) == self.tracked_pointer_tag { + register_diagnostic(NonHaltingDiagnostic::CreatedPointerTag(id)); + } self.next_ptr_id = NonZeroU64::new(id.get() + 1).unwrap(); id } From ecf330f39eaed1f798445ae018cfb645517078bc Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 27 Oct 2020 16:58:08 +0100 Subject: [PATCH 2407/3747] test Box::into_raw aliasing --- tests/run-pass/box-pair-to-vec.rs | 28 --------- tests/run-pass/box.rs | 60 +++++++++++++++++++ .../{box-pair-to-vec.stdout => box.stdout} | 0 3 files changed, 60 insertions(+), 28 deletions(-) delete mode 100644 tests/run-pass/box-pair-to-vec.rs create mode 100644 tests/run-pass/box.rs rename tests/run-pass/{box-pair-to-vec.stdout => box.stdout} (100%) diff --git a/tests/run-pass/box-pair-to-vec.rs b/tests/run-pass/box-pair-to-vec.rs deleted file mode 100644 index 353afb9d32100..0000000000000 --- a/tests/run-pass/box-pair-to-vec.rs +++ /dev/null @@ -1,28 +0,0 @@ -#[repr(C)] -#[derive(Debug)] -struct PairFoo { - fst: Foo, - snd: Foo, -} - -#[derive(Debug)] -struct Foo(u64); -fn reinterstruct(box_pair: Box) -> Vec { - let ref_pair = Box::leak(box_pair) as *mut PairFoo; - let ptr_foo = unsafe { &mut (*ref_pair).fst as *mut Foo }; - unsafe { - Vec::from_raw_parts(ptr_foo, 2, 2) - } -} - -fn main() { - let pair_foo = Box::new(PairFoo { - fst: Foo(42), - snd: Foo(1337), - }); - println!("pair_foo = {:?}", pair_foo); - for (n, foo) in reinterstruct(pair_foo).into_iter().enumerate() { - println!("foo #{} = {:?}", n, foo); - } -} - diff --git a/tests/run-pass/box.rs b/tests/run-pass/box.rs new file mode 100644 index 0000000000000..b89c0ac1286eb --- /dev/null +++ b/tests/run-pass/box.rs @@ -0,0 +1,60 @@ +#![feature(ptr_internals)] + +fn main() { + into_raw(); + into_unique(); + boxed_pair_to_vec(); +} + +fn into_raw() { unsafe { + let b = Box::new(4i32); + let r = Box::into_raw(b); + + // "lose the tag" + let r2 = ((r as usize)+0) as *mut i32; + *(&mut *r2) = 7; + + // Use original ptr again + *(&mut *r) = 17; + drop(Box::from_raw(r)); +}} + +fn into_unique() { unsafe { + let b = Box::new(4i32); + let u = Box::into_unique(b); + + // "lose the tag" + let r = ((u.as_ptr() as usize)+0) as *mut i32; + *(&mut *r) = 7; + + // Use original ptr again. + drop(Box::from_raw(u.as_ptr())); +}} + +fn boxed_pair_to_vec() { + #[repr(C)] + #[derive(Debug)] + struct PairFoo { + fst: Foo, + snd: Foo, + } + + #[derive(Debug)] + struct Foo(u64); + fn reinterstruct(box_pair: Box) -> Vec { + let ref_pair = Box::leak(box_pair) as *mut PairFoo; + let ptr_foo = unsafe { &mut (*ref_pair).fst as *mut Foo }; + unsafe { + Vec::from_raw_parts(ptr_foo, 2, 2) + } + } + + let pair_foo = Box::new(PairFoo { + fst: Foo(42), + snd: Foo(1337), + }); + println!("pair_foo = {:?}", pair_foo); + for (n, foo) in reinterstruct(pair_foo).into_iter().enumerate() { + println!("foo #{} = {:?}", n, foo); + } +} diff --git a/tests/run-pass/box-pair-to-vec.stdout b/tests/run-pass/box.stdout similarity index 100% rename from tests/run-pass/box-pair-to-vec.stdout rename to tests/run-pass/box.stdout From 39f7b35327cd4747da1a20a187fbaf220ee4a09c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 28 Oct 2020 12:04:39 +0100 Subject: [PATCH 2408/3747] Stacked Borrows: print affected memory location on errors --- src/range_map.rs | 30 ++++++++++++---------- src/stacked_borrows.rs | 56 ++++++++++++++++++++---------------------- 2 files changed, 43 insertions(+), 43 deletions(-) diff --git a/src/range_map.rs b/src/range_map.rs index 16ad5fd7c2b26..607c830530e1f 100644 --- a/src/range_map.rs +++ b/src/range_map.rs @@ -61,7 +61,9 @@ impl RangeMap { /// Provides read-only iteration over everything in the given range. This does /// *not* split items if they overlap with the edges. Do not use this to mutate /// through interior mutability. - pub fn iter<'a>(&'a self, offset: Size, len: Size) -> impl Iterator + 'a { + /// + /// The iterator also provides the offset of the given element. + pub fn iter<'a>(&'a self, offset: Size, len: Size) -> impl Iterator + 'a { let offset = offset.bytes(); let len = len.bytes(); // Compute a slice starting with the elements we care about. @@ -75,7 +77,7 @@ impl RangeMap { }; // The first offset that is not included any more. let end = offset + len; - slice.iter().take_while(move |elem| elem.range.start < end).map(|elem| &elem.data) + slice.iter().take_while(move |elem| elem.range.start < end).map(|elem| (Size::from_bytes(elem.range.start), &elem.data)) } pub fn iter_mut_all<'a>(&'a mut self) -> impl Iterator + 'a { @@ -112,11 +114,13 @@ impl RangeMap { /// this will split entries in the map that are only partially hit by the given range, /// to make sure that when they are mutated, the effect is constrained to the given range. /// Moreover, this will opportunistically merge neighbouring equal blocks. + /// + /// The iterator also provides the offset of the given element. pub fn iter_mut<'a>( &'a mut self, offset: Size, len: Size, - ) -> impl Iterator + 'a + ) -> impl Iterator + 'a where T: Clone + PartialEq, { @@ -197,7 +201,7 @@ impl RangeMap { // Now we yield the slice. `end` is inclusive. &mut self.v[first_idx..=end_idx] }; - slice.iter_mut().map(|elem| &mut elem.data) + slice.iter_mut().map(|elem| (Size::from_bytes(elem.range.start), &mut elem.data)) } } @@ -209,7 +213,7 @@ mod tests { fn to_vec(map: &RangeMap, offset: u64, len: u64) -> Vec { (offset..offset + len) .into_iter() - .map(|i| map.iter(Size::from_bytes(i), Size::from_bytes(1)).next().map(|&t| t).unwrap()) + .map(|i| map.iter(Size::from_bytes(i), Size::from_bytes(1)).next().map(|(_, &t)| t).unwrap()) .collect() } @@ -217,7 +221,7 @@ mod tests { fn basic_insert() { let mut map = RangeMap::::new(Size::from_bytes(20), -1); // Insert. - for x in map.iter_mut(Size::from_bytes(10), Size::from_bytes(1)) { + for (_, x) in map.iter_mut(Size::from_bytes(10), Size::from_bytes(1)) { *x = 42; } // Check. @@ -225,10 +229,10 @@ mod tests { assert_eq!(map.v.len(), 3); // Insert with size 0. - for x in map.iter_mut(Size::from_bytes(10), Size::from_bytes(0)) { + for (_, x) in map.iter_mut(Size::from_bytes(10), Size::from_bytes(0)) { *x = 19; } - for x in map.iter_mut(Size::from_bytes(11), Size::from_bytes(0)) { + for (_, x) in map.iter_mut(Size::from_bytes(11), Size::from_bytes(0)) { *x = 19; } assert_eq!(to_vec(&map, 10, 2), vec![42, -1]); @@ -238,16 +242,16 @@ mod tests { #[test] fn gaps() { let mut map = RangeMap::::new(Size::from_bytes(20), -1); - for x in map.iter_mut(Size::from_bytes(11), Size::from_bytes(1)) { + for (_, x) in map.iter_mut(Size::from_bytes(11), Size::from_bytes(1)) { *x = 42; } - for x in map.iter_mut(Size::from_bytes(15), Size::from_bytes(1)) { + for (_, x) in map.iter_mut(Size::from_bytes(15), Size::from_bytes(1)) { *x = 43; } assert_eq!(map.v.len(), 5); assert_eq!(to_vec(&map, 10, 10), vec![-1, 42, -1, -1, -1, 43, -1, -1, -1, -1]); - for x in map.iter_mut(Size::from_bytes(10), Size::from_bytes(10)) { + for (_, x) in map.iter_mut(Size::from_bytes(10), Size::from_bytes(10)) { if *x < 42 { *x = 23; } @@ -256,14 +260,14 @@ mod tests { assert_eq!(to_vec(&map, 10, 10), vec![23, 42, 23, 23, 23, 43, 23, 23, 23, 23]); assert_eq!(to_vec(&map, 13, 5), vec![23, 23, 43, 23, 23]); - for x in map.iter_mut(Size::from_bytes(15), Size::from_bytes(5)) { + for (_, x) in map.iter_mut(Size::from_bytes(15), Size::from_bytes(5)) { *x = 19; } assert_eq!(map.v.len(), 6); assert_eq!(to_vec(&map, 10, 10), vec![23, 42, 23, 23, 23, 19, 19, 19, 19, 19]); // Should be seeing two blocks with 19. assert_eq!( - map.iter(Size::from_bytes(15), Size::from_bytes(2)).map(|&t| t).collect::>(), + map.iter(Size::from_bytes(15), Size::from_bytes(2)).map(|(_, &t)| t).collect::>(), vec![19, 19] ); diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 257208056d764..cf5b31597daa7 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -309,14 +309,14 @@ impl<'tcx> Stack { /// Test if a memory `access` using pointer tagged `tag` is granted. /// If yes, return the index of the item that granted it. - fn access(&mut self, access: AccessKind, tag: Tag, global: &GlobalState) -> InterpResult<'tcx> { + fn access(&mut self, access: AccessKind, ptr: Pointer, global: &GlobalState) -> InterpResult<'tcx> { // Two main steps: Find granting item, remove incompatible items above. // Step 1: Find granting item. - let granting_idx = self.find_granting(access, tag).ok_or_else(|| { + let granting_idx = self.find_granting(access, ptr.tag).ok_or_else(|| { err_sb_ub(format!( - "no item granting {} to tag {:?} found in borrow stack.", - access, tag + "no item granting {} to tag {:?} at {} found in borrow stack.", + access, ptr.tag, ptr.erase_tag(), )) })?; @@ -328,7 +328,7 @@ impl<'tcx> Stack { let first_incompatible_idx = self.find_first_write_incompatible(granting_idx); for item in self.borrows.drain(first_incompatible_idx..).rev() { trace!("access: popping item {:?}", item); - Stack::check_protector(&item, Some(tag), global)?; + Stack::check_protector(&item, Some(ptr.tag), global)?; } } else { // On a read, *disable* all `Unique` above the granting item. This ensures U2 for read accesses. @@ -343,7 +343,7 @@ impl<'tcx> Stack { let item = &mut self.borrows[idx]; if item.perm == Permission::Unique { trace!("access: disabling item {:?}", item); - Stack::check_protector(item, Some(tag), global)?; + Stack::check_protector(item, Some(ptr.tag), global)?; item.perm = Permission::Disabled; } } @@ -355,12 +355,12 @@ impl<'tcx> Stack { /// Deallocate a location: Like a write access, but also there must be no /// active protectors at all because we will remove all items. - fn dealloc(&mut self, tag: Tag, global: &GlobalState) -> InterpResult<'tcx> { + fn dealloc(&mut self, ptr: Pointer, global: &GlobalState) -> InterpResult<'tcx> { // Step 1: Find granting item. - self.find_granting(AccessKind::Write, tag).ok_or_else(|| { + self.find_granting(AccessKind::Write, ptr.tag).ok_or_else(|| { err_sb_ub(format!( - "no item granting write access for deallocation to tag {:?} found in borrow stack", - tag, + "no item granting write access for deallocation to tag {:?} at {} found in borrow stack", + ptr.tag, ptr.erase_tag(), )) })?; @@ -372,20 +372,20 @@ impl<'tcx> Stack { Ok(()) } - /// Derived a new pointer from one with the given tag. + /// Derive a new pointer from one with the given tag. /// `weak` controls whether this operation is weak or strong: weak granting does not act as /// an access, and they add the new item directly on top of the one it is derived /// from instead of all the way at the top of the stack. - fn grant(&mut self, derived_from: Tag, new: Item, global: &GlobalState) -> InterpResult<'tcx> { + fn grant(&mut self, derived_from: Pointer, new: Item, global: &GlobalState) -> InterpResult<'tcx> { // Figure out which access `perm` corresponds to. let access = if new.perm.grants(AccessKind::Write) { AccessKind::Write } else { AccessKind::Read }; // Now we figure out which item grants our parent (`derived_from`) this kind of access. // We use that to determine where to put the new item. - let granting_idx = self.find_granting(access, derived_from) + let granting_idx = self.find_granting(access, derived_from.tag) .ok_or_else(|| err_sb_ub(format!( - "trying to reborrow for {:?}, but parent tag {:?} does not have an appropriate item in the borrow stack", - new.perm, derived_from, + "trying to reborrow for {:?} at {}, but parent tag {:?} does not have an appropriate item in the borrow stack", + new.perm, derived_from.erase_tag(), derived_from.tag, )))?; // Compute where to put the new item. @@ -443,12 +443,14 @@ impl<'tcx> Stacks { &self, ptr: Pointer, size: Size, - f: impl Fn(&mut Stack, &GlobalState) -> InterpResult<'tcx>, + f: impl Fn(Pointer, &mut Stack, &GlobalState) -> InterpResult<'tcx>, ) -> InterpResult<'tcx> { let global = self.global.borrow(); let mut stacks = self.stacks.borrow_mut(); - for stack in stacks.iter_mut(ptr.offset, size) { - f(stack, &*global)?; + for (offset, stack) in stacks.iter_mut(ptr.offset, size) { + let mut cur_ptr = ptr; + cur_ptr.offset = offset; + f(cur_ptr, stack, &*global)?; } Ok(()) } @@ -487,19 +489,13 @@ impl Stacks { #[inline(always)] pub fn memory_read<'tcx>(&self, ptr: Pointer, size: Size) -> InterpResult<'tcx> { trace!("read access with tag {:?}: {:?}, size {}", ptr.tag, ptr.erase_tag(), size.bytes()); - self.for_each(ptr, size, |stack, global| { - stack.access(AccessKind::Read, ptr.tag, global)?; - Ok(()) - }) + self.for_each(ptr, size, |ptr, stack, global| stack.access(AccessKind::Read, ptr, global)) } #[inline(always)] pub fn memory_written<'tcx>(&mut self, ptr: Pointer, size: Size) -> InterpResult<'tcx> { trace!("write access with tag {:?}: {:?}, size {}", ptr.tag, ptr.erase_tag(), size.bytes()); - self.for_each(ptr, size, |stack, global| { - stack.access(AccessKind::Write, ptr.tag, global)?; - Ok(()) - }) + self.for_each(ptr, size, |ptr, stack, global| stack.access(AccessKind::Write, ptr, global)) } #[inline(always)] @@ -509,7 +505,7 @@ impl Stacks { size: Size, ) -> InterpResult<'tcx> { trace!("deallocation with tag {:?}: {:?}, size {}", ptr.tag, ptr.erase_tag(), size.bytes()); - self.for_each(ptr, size, |stack, global| stack.dealloc(ptr.tag, global)) + self.for_each(ptr, size, |ptr, stack, global| stack.dealloc(ptr, global)) } } @@ -561,14 +557,14 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Permission::SharedReadWrite }; let item = Item { perm, tag: new_tag, protector }; - stacked_borrows.for_each(cur_ptr, size, |stack, global| { - stack.grant(cur_ptr.tag, item, global) + stacked_borrows.for_each(cur_ptr, size, |cur_ptr, stack, global| { + stack.grant(cur_ptr, item, global) }) }); } }; let item = Item { perm, tag: new_tag, protector }; - stacked_borrows.for_each(ptr, size, |stack, global| stack.grant(ptr.tag, item, global)) + stacked_borrows.for_each(ptr, size, |ptr, stack, global| stack.grant(ptr, item, global)) } /// Retags an indidual pointer, returning the retagged version. From 194451345dc6b7d269a5ded6fde49883cb862d75 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 28 Oct 2020 12:23:35 +0100 Subject: [PATCH 2409/3747] add an option to track raw pointer tags in Stacked Borrows --- README.md | 10 +++++++--- src/bin/miri.rs | 3 +++ src/eval.rs | 14 ++++---------- src/machine.rs | 23 +++++++++++------------ src/stacked_borrows.rs | 32 ++++++++++++++++++-------------- 5 files changed, 43 insertions(+), 39 deletions(-) diff --git a/README.md b/README.md index b638c3bca1ce9..0aa22a81ad5cb 100644 --- a/README.md +++ b/README.md @@ -232,13 +232,17 @@ environment variable: * `-Zmiri-track-alloc-id=` shows a backtrace when the given allocation is being allocated or freed. This helps in debugging memory leaks and use after free bugs. +* `-Zmiri-track-call-id=` shows a backtrace when the given call id is + assigned to a stack frame. This helps in debugging UB related to Stacked + Borrows "protectors". * `-Zmiri-track-pointer-tag=` shows a backtrace when the given pointer tag is popped from a borrow stack (which is where the tag becomes invalid and any future use of it will error). This helps you in finding out why UB is happening and where in your code would be a good place to look for it. -* `-Zmiri-track-call-id=` shows a backtrace when the given call id is - assigned to a stack frame. This helps in debugging UB related to Stacked - Borrows "protectors". +* `-Zmiri-track-raw-pointers` makes Stacked Borrows track a pointer tag even for + raw pointers. This can make valid code fail to pass the checks (when + integer-pointer casts are involved), but also can help identify latent + aliasing issues in code that Miri accepts by default. Some native rustc `-Z` flags are also very relevant for Miri: diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 5769590ad094e..ef1429a35020a 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -207,6 +207,9 @@ fn main() { "-Zmiri-ignore-leaks" => { miri_config.ignore_leaks = true; } + "-Zmiri-track-raw-pointers" => { + miri_config.track_raw = true; + } "--" => { after_dashdash = true; } diff --git a/src/eval.rs b/src/eval.rs index e36a0019cdcb2..54d06feec36dd 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -3,8 +3,6 @@ use std::convert::TryFrom; use std::ffi::OsStr; -use rand::rngs::StdRng; -use rand::SeedableRng; use log::info; use rustc_hir::def_id::DefId; @@ -48,6 +46,8 @@ pub struct MiriConfig { pub tracked_call_id: Option, /// The allocation id to report about. pub tracked_alloc_id: Option, + /// Whether to track raw pointers in stacked borrows. + pub track_raw: bool, } impl Default for MiriConfig { @@ -64,6 +64,7 @@ impl Default for MiriConfig { tracked_pointer_tag: None, tracked_call_id: None, tracked_alloc_id: None, + track_raw: false, } } } @@ -84,14 +85,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( rustc_span::source_map::DUMMY_SP, param_env, Evaluator::new(config.communicate, config.validate, layout_cx), - MemoryExtra::new( - StdRng::seed_from_u64(config.seed.unwrap_or(0)), - config.stacked_borrows, - config.tracked_pointer_tag, - config.tracked_call_id, - config.tracked_alloc_id, - config.check_alignment, - ), + MemoryExtra::new(&config), ); // Complete initialization. EnvVars::init(&mut ecx, config.excluded_env_vars)?; diff --git a/src/machine.rs b/src/machine.rs index 544f4667e8461..e9f9298e566c8 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -10,6 +10,7 @@ use std::fmt; use log::trace; use rand::rngs::StdRng; +use rand::SeedableRng; use rustc_data_structures::fx::FxHashMap; use rustc_middle::{ @@ -132,16 +133,14 @@ pub struct MemoryExtra { } impl MemoryExtra { - pub fn new( - rng: StdRng, - stacked_borrows: bool, - tracked_pointer_tag: Option, - tracked_call_id: Option, - tracked_alloc_id: Option, - check_alignment: AlignmentCheck, - ) -> Self { - let stacked_borrows = if stacked_borrows { - Some(Rc::new(RefCell::new(stacked_borrows::GlobalState::new(tracked_pointer_tag, tracked_call_id)))) + pub fn new(config: &MiriConfig) -> Self { + let rng = StdRng::seed_from_u64(config.seed.unwrap_or(0)); + let stacked_borrows = if config.stacked_borrows { + Some(Rc::new(RefCell::new(stacked_borrows::GlobalState::new( + config.tracked_pointer_tag, + config.tracked_call_id, + config.track_raw, + )))) } else { None }; @@ -150,8 +149,8 @@ impl MemoryExtra { intptrcast: Default::default(), extern_statics: FxHashMap::default(), rng: RefCell::new(rng), - tracked_alloc_id, - check_alignment, + tracked_alloc_id: config.tracked_alloc_id, + check_alignment: config.check_alignment, } } diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index cf5b31597daa7..616950eb0a0a4 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -108,6 +108,8 @@ pub struct GlobalState { tracked_pointer_tag: Option, /// The call id to trace tracked_call_id: Option, + /// Whether to track raw pointers. + track_raw: bool, } /// Memory extra state gives us interior mutable access to the global state. pub type MemoryExtra = Rc>; @@ -155,7 +157,7 @@ impl fmt::Display for RefKind { /// Utilities for initialization and ID generation impl GlobalState { - pub fn new(tracked_pointer_tag: Option, tracked_call_id: Option) -> Self { + pub fn new(tracked_pointer_tag: Option, tracked_call_id: Option, track_raw: bool) -> Self { GlobalState { next_ptr_id: NonZeroU64::new(1).unwrap(), base_ptr_ids: FxHashMap::default(), @@ -163,6 +165,7 @@ impl GlobalState { active_calls: FxHashSet::default(), tracked_pointer_tag, tracked_call_id, + track_raw, } } @@ -479,9 +482,12 @@ impl Stacks { // The base pointer is not unique, so the base permission is `SharedReadWrite`. MemoryKind::Machine(MiriMemoryKind::Global | MiriMemoryKind::ExternStatic | MiriMemoryKind::Tls | MiriMemoryKind::Env) => (extra.borrow_mut().global_base_ptr(id), Permission::SharedReadWrite), - // Everything else we handle entirely untagged for now. - // FIXME: experiment with more precise tracking. - _ => (Tag::Untagged, Permission::SharedReadWrite), + // Everything else we handle like raw pointers for now. + _ => { + let mut extra = extra.borrow_mut(); + let tag = if extra.track_raw { Tag::Tagged(extra.new_ptr()) } else { Tag::Untagged }; + (tag, Permission::SharedReadWrite) + } }; (Stacks::new(size, perm, tag, extra), tag) } @@ -593,16 +599,14 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // Compute new borrow. - let new_tag = match kind { - // Give up tracking for raw pointers. - // FIXME: Experiment with more precise tracking. Blocked on `&raw` - // because `Rc::into_raw` currently creates intermediate references, - // breaking `Rc::from_raw`. - RefKind::Raw { .. } => Tag::Untagged, - // All other pointesr are properly tracked. - _ => Tag::Tagged( - this.memory.extra.stacked_borrows.as_ref().unwrap().borrow_mut().new_ptr(), - ), + let new_tag = { + let mut mem_extra = this.memory.extra.stacked_borrows.as_ref().unwrap().borrow_mut(); + match kind { + // Give up tracking for raw pointers. + RefKind::Raw { .. } if !mem_extra.track_raw => Tag::Untagged, + // All other pointers are properly tracked. + _ => Tag::Tagged(mem_extra.new_ptr()), + } }; // Reborrow. From 19e78a65d95d03b6d7ac670075231837cc00edf4 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 28 Oct 2020 12:35:05 +0100 Subject: [PATCH 2410/3747] run some tests with raw pointer tracking --- tests/run-pass/format.rs | 2 ++ tests/run-pass/slices.rs | 1 + tests/run-pass/vec.rs | 1 + tests/run-pass/vecdeque.rs | 1 + 4 files changed, 5 insertions(+) diff --git a/tests/run-pass/format.rs b/tests/run-pass/format.rs index 053cce36130c7..3893efcb26a1a 100644 --- a/tests/run-pass/format.rs +++ b/tests/run-pass/format.rs @@ -1,3 +1,5 @@ +// compile-flags: -Zmiri-track-raw-pointers + fn main() { println!("Hello {}", 13); println!("{:0(dummy: &mut T, iter: impl Iterator) { diff --git a/tests/run-pass/vecdeque.rs b/tests/run-pass/vecdeque.rs index 34f32ee1d9c12..54aeb89ec83ff 100644 --- a/tests/run-pass/vecdeque.rs +++ b/tests/run-pass/vecdeque.rs @@ -1,3 +1,4 @@ +// compile-flags: -Zmiri-track-raw-pointers use std::collections::VecDeque; fn test_all_refs<'a, T: 'a>(dummy: &mut T, iter: impl Iterator) { From 1044099c196ced6108234fe2450fcd2f7f969fa7 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 28 Oct 2020 10:48:33 +0100 Subject: [PATCH 2411/3747] disable debug assertions in the standard library --- cargo-miri/bin.rs | 2 ++ tests/run-pass/panic/catch_panic.rs | 1 - tests/run-pass/panic/catch_panic.stderr | 2 -- 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index a13e689cad20a..6eff5f795e7cb 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -353,6 +353,8 @@ path = "lib.rs" // to the sysroot either. command.env_remove("RUSTC_WRAPPER"); command.env_remove("RUSTFLAGS"); + // Disable debug assertions in the standard library -- Miri is already slow enough. + command.env("RUSTFLAGS", "-Cdebug-assertions=off"); // Finally run it! if command.status().expect("failed to run xargo").success().not() { show_error(format!("failed to run xargo")); diff --git a/tests/run-pass/panic/catch_panic.rs b/tests/run-pass/panic/catch_panic.rs index 3afff1d36d36e..941f79c7ad903 100644 --- a/tests/run-pass/panic/catch_panic.rs +++ b/tests/run-pass/panic/catch_panic.rs @@ -78,7 +78,6 @@ fn main() { // Assertion and debug assertion test(None, |_old_val| { assert!(false); loop {} }); test(None, |_old_val| { debug_assert!(false); loop {} }); - test(None, |_old_val| { unsafe { std::char::from_u32_unchecked(0xFD10000); } loop {} }); // trigger debug-assertion in libstd eprintln!("Success!"); // Make sure we get this in stderr } diff --git a/tests/run-pass/panic/catch_panic.stderr b/tests/run-pass/panic/catch_panic.stderr index c4c04fece901c..696dbc1f81813 100644 --- a/tests/run-pass/panic/catch_panic.stderr +++ b/tests/run-pass/panic/catch_panic.stderr @@ -23,6 +23,4 @@ thread 'main' panicked at 'assertion failed: false', $DIR/catch_panic.rs:LL:29 Caught panic message (&str): assertion failed: false thread 'main' panicked at 'assertion failed: false', $DIR/catch_panic.rs:LL:29 Caught panic message (&str): assertion failed: false -thread 'main' panicked at 'called `Option::unwrap()` on a `None` value', $LOC -Caught panic message (&str): called `Option::unwrap()` on a `None` value Success! From 00c4869d560e108a9b8298c7d1861c7320be45c6 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 28 Oct 2020 12:57:41 +0100 Subject: [PATCH 2412/3747] remove outdated CI badges --- README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/README.md b/README.md index b638c3bca1ce9..1de1c2e4c1b19 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,6 @@ # Miri [![Actions build status][actions-badge]][actions-url] -[![Travis build status](https://travis-ci.com/rust-lang/miri.svg?branch=master)](https://travis-ci.com/rust-lang/miri) -[![Appveyor Windows build status](https://ci.appveyor.com/api/projects/status/github/rust-lang/miri?svg=true)](https://ci.appveyor.com/project/rust-lang-libs/miri) [actions-badge]: https://github.com/rust-lang/miri/workflows/CI/badge.svg?branch=master [actions-url]: https://github.com/rust-lang/miri/actions From 70af7aed88456b8c478e06d1d28b0d8523a46b38 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 28 Oct 2020 12:51:25 +0100 Subject: [PATCH 2413/3747] expand flag docs --- README.md | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 0aa22a81ad5cb..0c280edec0ce6 100644 --- a/README.md +++ b/README.md @@ -240,9 +240,12 @@ environment variable: future use of it will error). This helps you in finding out why UB is happening and where in your code would be a good place to look for it. * `-Zmiri-track-raw-pointers` makes Stacked Borrows track a pointer tag even for - raw pointers. This can make valid code fail to pass the checks (when - integer-pointer casts are involved), but also can help identify latent - aliasing issues in code that Miri accepts by default. + raw pointers. This can make valid code fail to pass the checks, but also can + help identify latent aliasing issues in code that Miri accepts by default. You + can recognize false positives by "" occurring in the message -- this + indicates a pointer that was cast from an integer, so Miri was unable to track + this pointer. Make sure to use a non-Windows target with this flag, as the + Windows runtime makes use of integer-pointer casts. Some native rustc `-Z` flags are also very relevant for Miri: From bf54607ba03cf12a015e7027be6d5ffdf08cc3ca Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 28 Oct 2020 13:50:27 +0100 Subject: [PATCH 2414/3747] test raw pointer tracking; we cannot track raw pointers on Windows --- tests/compile-fail/stacked_borrows/raw_tracking.rs | 13 +++++++++++++ tests/run-pass/format.rs | 2 -- tests/run-pass/slices.rs | 1 - tests/run-pass/vec.rs | 1 + tests/run-pass/vecdeque.rs | 1 + 5 files changed, 15 insertions(+), 3 deletions(-) create mode 100644 tests/compile-fail/stacked_borrows/raw_tracking.rs diff --git a/tests/compile-fail/stacked_borrows/raw_tracking.rs b/tests/compile-fail/stacked_borrows/raw_tracking.rs new file mode 100644 index 0000000000000..b9ddee328f7a6 --- /dev/null +++ b/tests/compile-fail/stacked_borrows/raw_tracking.rs @@ -0,0 +1,13 @@ +// compile-flags: -Zmiri-track-raw-pointers +// ignore-windows (FIXME: tracking raw pointers does not work on Windows) +//! This demonstrates a provenance problem that requires tracking of raw pointers to be detected. + +fn main() { + let mut l = 13; + let raw1 = &mut l as *mut _; + let raw2 = &mut l as *mut _; // invalidates raw1 + // Without raw pointer tracking, Stacked Borrows cannot distinguish raw1 and raw2, and thus + // fails to realize that raw1 should not be used any more. + unsafe { *raw1 = 13; } //~ ERROR no item granting write access to tag + unsafe { *raw2 = 13; } +} diff --git a/tests/run-pass/format.rs b/tests/run-pass/format.rs index 3893efcb26a1a..053cce36130c7 100644 --- a/tests/run-pass/format.rs +++ b/tests/run-pass/format.rs @@ -1,5 +1,3 @@ -// compile-flags: -Zmiri-track-raw-pointers - fn main() { println!("Hello {}", 13); println!("{:0(dummy: &mut T, iter: impl Iterator) { diff --git a/tests/run-pass/vecdeque.rs b/tests/run-pass/vecdeque.rs index 54aeb89ec83ff..55b47f622fde3 100644 --- a/tests/run-pass/vecdeque.rs +++ b/tests/run-pass/vecdeque.rs @@ -1,4 +1,5 @@ // compile-flags: -Zmiri-track-raw-pointers +// ignore-windows (FIXME: tracking raw pointers does not work on Windows) use std::collections::VecDeque; fn test_all_refs<'a, T: 'a>(dummy: &mut T, iter: impl Iterator) { From 2589b482516941c109c1ab2f98dd446e23ca6887 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 28 Oct 2020 14:05:37 +0100 Subject: [PATCH 2415/3747] update trophy case --- README.md | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 1de1c2e4c1b19..15dfddd65896c 100644 --- a/README.md +++ b/README.md @@ -388,7 +388,10 @@ Definite bugs found: Violations of [Stacked Borrows] found that are likely bugs (but Stacked Borrows is currently just an experiment): * [`VecDeque::drain` creating overlapping mutable references](https://github.com/rust-lang/rust/pull/56161) -* [`BTreeMap` iterators creating mutable references that overlap with shared references](https://github.com/rust-lang/rust/pull/58431) +* Various `BTreeMap` problems + * [`BTreeMap` iterators creating mutable references that overlap with shared references](https://github.com/rust-lang/rust/pull/58431) + * [`BTreeMap::iter_mut` creating overlapping mutable references](https://github.com/rust-lang/rust/issues/73915) + * [`BTreeMap` node insertion using raw pointers outside their valid memory area](https://github.com/rust-lang/rust/issues/78477) * [`LinkedList` cursor insertion creating overlapping mutable references](https://github.com/rust-lang/rust/pull/60072) * [`Vec::push` invalidating existing references into the vector](https://github.com/rust-lang/rust/issues/60847) * [`align_to_mut` violating uniqueness of mutable references](https://github.com/rust-lang/rust/issues/68549) @@ -397,9 +400,9 @@ Violations of [Stacked Borrows] found that are likely bugs (but Stacked Borrows * [`ryu` using raw pointers outside their valid memory area](https://github.com/dtolnay/ryu/issues/24) * [ink! creating overlapping mutable references](https://github.com/rust-lang/miri/issues/1364) * [TiKV creating overlapping mutable reference and raw pointer](https://github.com/tikv/tikv/pull/7709) -* [Windows `Env` iterator creating `*const T` from `&T` to read memory outside of `T`](https://github.com/rust-lang/rust/pull/70479) -* [`BTreeMap::iter_mut` creating overlapping mutable references](https://github.com/rust-lang/rust/issues/73915) +* [Windows `Env` iterator using a raw pointer outside its valid memory area](https://github.com/rust-lang/rust/pull/70479) * [`VecDeque::iter_mut` creating overlapping mutable references](https://github.com/rust-lang/rust/issues/74029) +* [Standard library `SipHasher` using a raw pointer outside its valid memory area](https://github.com/rust-lang/rust/pull/78484) ## License From 1ad827c511bdde7ddca7010da7320f2051fc58d4 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 29 Oct 2020 20:57:38 +0100 Subject: [PATCH 2416/3747] rustup --- rust-version | 2 +- tests/run-pass/box.rs | 2 +- tests/run-pass/dyn-traits.rs | 3 ++- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/rust-version b/rust-version index 44e9a77940d6e..40aa78ae9a9c3 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -17cc9b6256c95c31944591aec683884fead4e3b6 +a53fb30e3bf2655b0563da6d561c23cda5f3ec11 diff --git a/tests/run-pass/box.rs b/tests/run-pass/box.rs index b89c0ac1286eb..c29a83507677f 100644 --- a/tests/run-pass/box.rs +++ b/tests/run-pass/box.rs @@ -21,7 +21,7 @@ fn into_raw() { unsafe { fn into_unique() { unsafe { let b = Box::new(4i32); - let u = Box::into_unique(b); + let u = Box::into_unique(b).0; // "lose the tag" let r = ((u.as_ptr() as usize)+0) as *mut i32; diff --git a/tests/run-pass/dyn-traits.rs b/tests/run-pass/dyn-traits.rs index 33d1f4fc1cf0c..51c2130bcd3f3 100644 --- a/tests/run-pass/dyn-traits.rs +++ b/tests/run-pass/dyn-traits.rs @@ -1,4 +1,5 @@ -#![feature(unsized_locals)] +#![feature(unsized_locals, unsized_fn_params)] +#![allow(incomplete_features)] fn ref_box_dyn() { struct Struct(i32); From 02af2a38acc9c96e6012f8647d063669b19c0a32 Mon Sep 17 00:00:00 2001 From: Camelid Date: Thu, 29 Oct 2020 16:14:54 -0700 Subject: [PATCH 2417/3747] Fix link in README --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index ebc740bf3f03c..4b09d1586ad4d 100644 --- a/README.md +++ b/README.md @@ -259,7 +259,7 @@ Some native rustc `-Z` flags are also very relevant for Miri: Moreover, Miri recognizes some environment variables: * `MIRI_LOG`, `MIRI_BACKTRACE` control logging and backtrace printing during - Miri executions, also [see above][testing-miri]. + Miri executions, also [see "Testing the Miri driver" in `CONTRIBUTING.md`][testing-miri]. * `MIRIFLAGS` (recognized by `cargo miri` and the test suite) defines extra flags to be passed to Miri. * `MIRI_SYSROOT` (recognized by `cargo miri` and the test suite) @@ -281,6 +281,8 @@ different Miri binaries, and as such worth documenting: directory after loading all the source files, but before commencing interpretation. This is useful if the interpreted program wants a different working directory at run-time than at build-time. + +[testing-miri]: CONTRIBUTING.md#testing-the-miri-driver ## Miri `extern` functions From 1496462a89977afdf328b5ecd4d5912344ad863a Mon Sep 17 00:00:00 2001 From: Camelid Date: Thu, 29 Oct 2020 17:00:12 -0700 Subject: [PATCH 2418/3747] Update locally-built rustc instructions --- CONTRIBUTING.md | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index a143190d5bdb7..a4a589156169e 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -141,19 +141,22 @@ tracing) enabled. The setup for a local rustc works as follows: ```sh +# Clone the rust-lang/rust repo. git clone https://github.com/rust-lang/rust/ rustc cd rustc cp config.toml.example config.toml # Now edit `config.toml` and set `debug-assertions = true`. -# This step can take 30 minutes and more. -./x.py build src/rustc + +# Build a stage 2 rustc. +# This step can take 30 minutes or more. +./x.py build --stage 2 compiler/rustc # If you change something, you can get a faster rebuild by doing -./x.py --keep-stage 0 build src/rustc +./x.py build --keep-stage 0 --stage 2 compiler/rustc # You may have to change the architecture in the next command rustup toolchain link custom build/x86_64-unknown-linux-gnu/stage2 # Now cd to your Miri directory, then configure rustup rustup override set custom ``` -With this, you should now have a working development setup! See +With this, you should now have a working development setup! See [above](#building-and-testing-miri) for how to proceed working on Miri. From 2a4faf638bb65d26a92cf9d8047818f6105dd078 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 30 Oct 2020 18:59:58 +0100 Subject: [PATCH 2419/3747] increase timeout to avoid spurious test failures --- tests/run-pass/concurrency/sync.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/run-pass/concurrency/sync.rs b/tests/run-pass/concurrency/sync.rs index bdbc4b90f6ed4..e97da415cbb1c 100644 --- a/tests/run-pass/concurrency/sync.rs +++ b/tests/run-pass/concurrency/sync.rs @@ -109,7 +109,7 @@ fn check_conditional_variables_timed_wait_notimeout() { cvar.notify_one(); }); - let (_guard, timeout) = cvar.wait_timeout(guard, Duration::from_millis(200)).unwrap(); + let (_guard, timeout) = cvar.wait_timeout(guard, Duration::from_millis(500)).unwrap(); assert!(!timeout.timed_out()); handle.join().unwrap(); } From bb59980b2da10437ce1ee4d53bdb3feb1f4a9c5f Mon Sep 17 00:00:00 2001 From: Camelid Date: Fri, 30 Oct 2020 14:33:12 -0700 Subject: [PATCH 2420/3747] CONTRIBUTING.md: Use `build --stage 1` instead of `build --stage 2` It seems to work fine with `--stage 1` and it should be faster. --- CONTRIBUTING.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index a4a589156169e..20f01f151a650 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -142,20 +142,20 @@ tracing) enabled. The setup for a local rustc works as follows: ```sh # Clone the rust-lang/rust repo. -git clone https://github.com/rust-lang/rust/ rustc +git clone https://github.com/rust-lang/rust rustc cd rustc cp config.toml.example config.toml # Now edit `config.toml` and set `debug-assertions = true`. -# Build a stage 2 rustc. +# Build a stage 1 rustc. # This step can take 30 minutes or more. -./x.py build --stage 2 compiler/rustc +./x.py build --stage 1 compiler/rustc # If you change something, you can get a faster rebuild by doing -./x.py build --keep-stage 0 --stage 2 compiler/rustc +./x.py build --keep-stage 0 --stage 1 compiler/rustc # You may have to change the architecture in the next command -rustup toolchain link custom build/x86_64-unknown-linux-gnu/stage2 +rustup toolchain link stage1 build/x86_64-unknown-linux-gnu/stage1 # Now cd to your Miri directory, then configure rustup -rustup override set custom +rustup override set stage1 ``` With this, you should now have a working development setup! See From e7246be4f0d6cbaf714f6e695cd50fc7f0688a95 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 31 Oct 2020 13:47:42 +0100 Subject: [PATCH 2421/3747] backtrace tests: support more ways of checking out Rust locally --- tests/run-pass/backtrace-api.rs | 2 +- tests/run-pass/backtrace-std.rs | 2 +- tests/run-pass/panic/panic1.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/run-pass/backtrace-api.rs b/tests/run-pass/backtrace-api.rs index 19169060038e0..cb3706e9f5132 100644 --- a/tests/run-pass/backtrace-api.rs +++ b/tests/run-pass/backtrace-api.rs @@ -1,4 +1,4 @@ -// normalize-stderr-test ".*/(rust|checkout)/library/" -> "RUSTLIB/" +// normalize-stderr-test ".*/(rust[^/]*|checkout)/library/" -> "RUSTLIB/" // normalize-stderr-test "RUSTLIB/(.*):\d+:\d+ "-> "RUSTLIB/$1:LL:COL " // normalize-stderr-test "::<.*>" -> "" diff --git a/tests/run-pass/backtrace-std.rs b/tests/run-pass/backtrace-std.rs index fb596b1d2020c..7a793e092a816 100644 --- a/tests/run-pass/backtrace-std.rs +++ b/tests/run-pass/backtrace-std.rs @@ -1,4 +1,4 @@ -// normalize-stderr-test "at .*/(rust|checkout)/library/" -> "at RUSTLIB/" +// normalize-stderr-test "at .*/(rust[^/]*|checkout)/library/" -> "at RUSTLIB/" // normalize-stderr-test "RUSTLIB/(.*):\d+"-> "RUSTLIB/$1:LL" // normalize-stderr-test "::<.*>" -> "" // compile-flags: -Zmiri-disable-isolation diff --git a/tests/run-pass/panic/panic1.rs b/tests/run-pass/panic/panic1.rs index 08ac3a0728522..da300ecb59f60 100644 --- a/tests/run-pass/panic/panic1.rs +++ b/tests/run-pass/panic/panic1.rs @@ -1,6 +1,6 @@ // rustc-env: RUST_BACKTRACE=1 // compile-flags: -Zmiri-disable-isolation -// normalize-stderr-test "at .*/(rust|checkout)/library/.*" -> "at RUSTLIB/$$FILE:LL:COL" +// normalize-stderr-test "at .*/(rust[^/]*|checkout)/library/.*" -> "at RUSTLIB/$$FILE:LL:COL" // normalize-stderr-test "::<.*>" -> "" From 80a0a12b07e4c3346cbacf70dcea810779ca0574 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 31 Oct 2020 13:56:46 +0100 Subject: [PATCH 2422/3747] Stacked Borrows: test raw-ref-to-field with raw ptr tracking --- tests/run-pass/stacked-borrows/int-to-ptr.rs | 13 +++++++ .../stacked-borrows/stacked-borrows.rs | 36 +++++++++++++------ 2 files changed, 38 insertions(+), 11 deletions(-) create mode 100644 tests/run-pass/stacked-borrows/int-to-ptr.rs diff --git a/tests/run-pass/stacked-borrows/int-to-ptr.rs b/tests/run-pass/stacked-borrows/int-to-ptr.rs new file mode 100644 index 0000000000000..efba0da1b9358 --- /dev/null +++ b/tests/run-pass/stacked-borrows/int-to-ptr.rs @@ -0,0 +1,13 @@ +fn main() { + ref_raw_int_raw(); +} + +// Just to make sure that casting a ref to raw, to int and back to raw +// and only then using it works. This rules out ideas like "do escape-to-raw lazily"; +// after casting to int and back, we lost the tag that could have let us do that. +fn ref_raw_int_raw() { + let mut x = 3; + let xref = &mut x; + let xraw = xref as *mut i32 as usize as *mut i32; + assert_eq!(unsafe { *xraw }, 3); +} diff --git a/tests/run-pass/stacked-borrows/stacked-borrows.rs b/tests/run-pass/stacked-borrows/stacked-borrows.rs index 765c6188b6e17..ad1877fc019bc 100644 --- a/tests/run-pass/stacked-borrows/stacked-borrows.rs +++ b/tests/run-pass/stacked-borrows/stacked-borrows.rs @@ -1,8 +1,12 @@ +// compile-flags: -Zmiri-track-raw-pointers +// ignore-windows (FIXME: tracking raw pointers does not work on Windows) +#![feature(raw_ref_macros)] +use std::ptr; + // Test various stacked-borrows-related things. fn main() { read_does_not_invalidate1(); read_does_not_invalidate2(); - ref_raw_int_raw(); mut_raw_then_mut_shr(); mut_shr_then_mut_raw(); mut_raw_mut(); @@ -12,6 +16,7 @@ fn main() { two_raw(); shr_and_raw(); disjoint_mutable_subborrows(); + raw_ref_to_part(); } // Make sure that reading from an `&mut` does, like reborrowing to `&`, @@ -37,16 +42,6 @@ fn read_does_not_invalidate2() { assert_eq!(*foo(&mut (1, 2)), 2); } -// Just to make sure that casting a ref to raw, to int and back to raw -// and only then using it works. This rules out ideas like "do escape-to-raw lazily"; -// after casting to int and back, we lost the tag that could have let us do that. -fn ref_raw_int_raw() { - let mut x = 3; - let xref = &mut x; - let xraw = xref as *mut i32 as usize as *mut i32; - assert_eq!(unsafe { *xraw }, 3); -} - // Escape a mut to raw, then share the same mut and use the share, then the raw. // That should work. fn mut_raw_then_mut_shr() { @@ -162,3 +157,22 @@ fn disjoint_mutable_subborrows() { a.push_str(" world"); eprintln!("{:?} {:?}", a, b); } + +fn raw_ref_to_part() { + struct Part { + _lame: i32, + } + + #[repr(C)] + struct Whole { + part: Part, + extra: i32, + } + + let it = Box::new(Whole { part: Part { _lame: 0 }, extra: 42 }); + let whole = ptr::raw_mut!(*Box::leak(it)); + let part = unsafe { ptr::raw_mut!((*whole).part) }; + let typed = unsafe { &mut *(part as *mut Whole) }; + assert!(typed.extra == 42); + drop(unsafe { Box::from_raw(whole) }); +} From f936bc6b92dbee4e94988b9c46298f59481bd2ea Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 31 Oct 2020 16:22:16 +0100 Subject: [PATCH 2423/3747] fix writing to read-only raw pointer in thread-local test --- tests/run-pass/thread-local.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/run-pass/thread-local.rs b/tests/run-pass/thread-local.rs index 1aa442edad3b2..72ab973b0f08f 100644 --- a/tests/run-pass/thread-local.rs +++ b/tests/run-pass/thread-local.rs @@ -58,7 +58,7 @@ fn main() { // Initialize the keys we use to check destructor ordering for (key, global) in KEYS.iter_mut().zip(GLOBALS.iter_mut()) { *key = create(Some(mem::transmute(dtor as unsafe extern fn(*mut u64)))); - set(*key, global as *const _ as *mut _); + set(*key, global as *mut _ as *mut u8); } // Initialize cannary From 00bc944eeac0eaa12a1facf2e623f7832f402e57 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 31 Oct 2020 16:23:41 +0100 Subject: [PATCH 2424/3747] test Rc with raw pointer tracking --- tests/run-pass/rc.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/run-pass/rc.rs b/tests/run-pass/rc.rs index 3dc61fe1f00d5..47f29992c459d 100644 --- a/tests/run-pass/rc.rs +++ b/tests/run-pass/rc.rs @@ -1,3 +1,5 @@ +// compile-flags: -Zmiri-track-raw-pointers +// ignore-windows (FIXME: tracking raw pointers does not work on Windows) #![feature(new_uninit)] #![feature(get_mut_unchecked)] From 7eaba6684cab6247a791cd5620710773e5308c33 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 31 Oct 2020 16:28:56 +0100 Subject: [PATCH 2425/3747] fix trophy case URL --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 4b09d1586ad4d..578ca0251c5e4 100644 --- a/README.md +++ b/README.md @@ -411,7 +411,7 @@ Violations of [Stacked Borrows] found that are likely bugs (but Stacked Borrows * [TiKV creating overlapping mutable reference and raw pointer](https://github.com/tikv/tikv/pull/7709) * [Windows `Env` iterator using a raw pointer outside its valid memory area](https://github.com/rust-lang/rust/pull/70479) * [`VecDeque::iter_mut` creating overlapping mutable references](https://github.com/rust-lang/rust/issues/74029) -* [Standard library `SipHasher` using a raw pointer outside its valid memory area](https://github.com/rust-lang/rust/pull/78484) +* [Various standard library aliasing issues involving raw pointers](https://github.com/rust-lang/rust/pull/78602) ## License From 89814f1b3f6c239f472dea4798a1189a30d7efa2 Mon Sep 17 00:00:00 2001 From: JCTyBlaidd Date: Mon, 2 Nov 2020 00:23:27 +0000 Subject: [PATCH 2426/3747] Initial data-race detector, passes all current tests but additional tests are required --- Cargo.lock | 7 + Cargo.toml | 1 + src/data_race.rs | 1406 +++++++++++++++++++++++++++++++++++++ src/lib.rs | 5 + src/machine.rs | 11 +- src/shims/intrinsics.rs | 425 +++++++---- src/shims/posix/sync.rs | 16 +- src/shims/posix/thread.rs | 17 +- src/sync.rs | 64 +- src/thread.rs | 30 +- 10 files changed, 1802 insertions(+), 180 deletions(-) create mode 100644 src/data_race.rs diff --git a/Cargo.lock b/Cargo.lock index 8c73cb05535c9..78838acb2a5fc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -282,6 +282,7 @@ dependencies = [ "rustc-workspace-hack", "rustc_version", "shell-escape", + "smallvec", ] [[package]] @@ -496,6 +497,12 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "45bb67a18fa91266cc7807181f62f9178a6873bfad7dc788c42e6430db40184f" +[[package]] +name = "smallvec" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbee7696b84bbf3d89a1c2eccff0850e3047ed46bfcd2e92c29a2d074d57e252" + [[package]] name = "socket2" version = "0.3.15" diff --git a/Cargo.toml b/Cargo.toml index c36a97bb0a1ae..4413dab321e72 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -30,6 +30,7 @@ log = "0.4" shell-escape = "0.1.4" hex = "0.4.0" rand = "0.7" +smallvec = "1.4.2" # A noop dependency that changes in the Rust repository, it's a bit of a hack. # See the `src/tools/rustc-workspace-hack/README.md` file in `rust-lang/rust` diff --git a/src/data_race.rs b/src/data_race.rs new file mode 100644 index 0000000000000..59526063945a9 --- /dev/null +++ b/src/data_race.rs @@ -0,0 +1,1406 @@ +//! Implementation of a data-race detector +//! uses Lamport Timestamps / Vector-clocks +//! base on the Dyamic Race Detection for C++: +//! - https://www.doc.ic.ac.uk/~afd/homepages/papers/pdfs/2017/POPL.pdf +//! to extend data-race detection to work correctly with fences +//! and RMW operations +//! This does not explore weak memory orders and so can still miss data-races +//! but should not report false-positives + +use std::{fmt::{self, Debug}, cmp::Ordering, rc::Rc, cell::{Cell, RefCell, Ref, RefMut}, ops::Index}; + +use rustc_index::vec::{Idx, IndexVec}; +use rustc_target::abi::Size; +use rustc_middle::ty::layout::TyAndLayout; +use rustc_data_structures::fx::FxHashMap; + +use smallvec::SmallVec; + +use crate::*; + +pub type AllocExtra = VClockAlloc; +pub type MemoryExtra = Rc; + +/// Valid atomic read-write operations, alias of atomic::Ordering (not non-exhaustive) +#[derive(Copy, Clone, PartialEq, Eq, Debug)] +pub enum AtomicRWOp { + Relaxed, + Acquire, + Release, + AcqRel, + SeqCst, +} + +/// Valid atomic read operations, subset of atomic::Ordering +#[derive(Copy, Clone, PartialEq, Eq, Debug)] +pub enum AtomicReadOp { + Relaxed, + Acquire, + SeqCst, +} + +/// Valid atomic write operations, subset of atomic::Ordering +#[derive(Copy, Clone, PartialEq, Eq, Debug)] +pub enum AtomicWriteOp { + Relaxed, + Release, + SeqCst, +} + + +/// Valid atomic fence operations, subset of atomic::Ordering +#[derive(Copy, Clone, PartialEq, Eq, Debug)] +pub enum AtomicFenceOp { + Acquire, + Release, + AcqRel, + SeqCst, +} + +/// Evaluation context extensions +impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} +pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { + + /// Variant of `read_immediate` that does not perform `data-race` checks. + fn read_immediate_racy(&self, op: MPlaceTy<'tcx, Tag>) -> InterpResult<'tcx, ImmTy<'tcx, Tag>> { + let this = self.eval_context_ref(); + let data_race = &*this.memory.extra.data_race; + let old = data_race.multi_threaded.get(); + + data_race.multi_threaded.set(false); + let res = this.read_immediate(op.into()); + + data_race.multi_threaded.set(old); + res + } + + /// Variant of `write_immediate` that does not perform `data-race` checks. + fn write_immediate_racy( + &mut self, src: Immediate, dest: MPlaceTy<'tcx, Tag> + ) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + let data_race = &*this.memory.extra.data_race; + let old = data_race.multi_threaded.get(); + + data_race.multi_threaded.set(false); + let imm = this.write_immediate(src, dest.into()); + + let data_race = &*this.memory.extra.data_race; + data_race.multi_threaded.set(old); + imm + } + + /// Variant of `read_scalar` that does not perform data-race checks. + fn read_scalar_racy( + &self, op: MPlaceTy<'tcx, Tag> + )-> InterpResult<'tcx, ScalarMaybeUninit> { + Ok(self.read_immediate_racy(op)?.to_scalar_or_uninit()) + } + + /// Variant of `write_scalar` that does not perform data-race checks. + fn write_scalar_racy( + &mut self, val: ScalarMaybeUninit, dest: MPlaceTy<'tcx, Tag> + ) -> InterpResult<'tcx> { + self.write_immediate_racy(Immediate::Scalar(val.into()), dest) + } + + /// Variant of `read_scalar_at_offset` helper function that does not perform + /// `data-race checks. + fn read_scalar_at_offset_racy( + &self, + op: OpTy<'tcx, Tag>, + offset: u64, + layout: TyAndLayout<'tcx>, + ) -> InterpResult<'tcx, ScalarMaybeUninit> { + let this = self.eval_context_ref(); + let op_place = this.deref_operand(op)?; + let offset = Size::from_bytes(offset); + // Ensure that the following read at an offset is within bounds + assert!(op_place.layout.size >= offset + layout.size); + let value_place = op_place.offset(offset, MemPlaceMeta::None, layout, this)?; + this.read_scalar_racy(value_place.into()) + } + + /// Variant of `write_scalar_at_offfset` helper function that does not perform + /// data-race checks. + fn write_scalar_at_offset_racy( + &mut self, + op: OpTy<'tcx, Tag>, + offset: u64, + value: impl Into>, + layout: TyAndLayout<'tcx>, + ) -> InterpResult<'tcx, ()> { + let this = self.eval_context_mut(); + let op_place = this.deref_operand(op)?; + let offset = Size::from_bytes(offset); + // Ensure that the following read at an offset is within bounds + assert!(op_place.layout.size >= offset + layout.size); + let value_place = op_place.offset(offset, MemPlaceMeta::None, layout, this)?; + this.write_scalar_racy(value.into(), value_place.into()) + } + + /// Load the data race allocation state for a given memory place + /// also returns the size and the offset of the result in the allocation + /// metadata + fn load_data_race_state<'a>( + &'a mut self, place: MPlaceTy<'tcx, Tag> + ) -> InterpResult<'tcx, (&'a mut VClockAlloc, Size, Size)> where 'mir: 'a { + let this = self.eval_context_mut(); + + let ptr = place.ptr.assert_ptr(); + let size = place.layout.size; + let data_race = &mut this.memory.get_raw_mut(ptr.alloc_id)?.extra.data_race; + + Ok((data_race, size, ptr.offset)) + } + + /// Update the data-race detector for an atomic read occuring at the + /// associated memory-place and on the current thread + fn validate_atomic_load( + &mut self, place: MPlaceTy<'tcx, Tag>, atomic: AtomicReadOp + ) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + let data_race = &*this.memory.extra.data_race; + if data_race.multi_threaded.get() { + data_race.advance_vector_clock(); + + let ( + alloc, size, offset + ) = this.load_data_race_state(place)?; + log::trace!( + "Atomic load on {:?} with ordering {:?}, in memory({:?}, offset={}, size={})", + alloc.global.current_thread(), atomic, + place.ptr.assert_ptr().alloc_id, offset.bytes(), size.bytes() + ); + + let mut current_state = alloc.global.current_thread_state_mut(); + if atomic == AtomicReadOp::Relaxed { + // Perform relaxed atomic load + for range in alloc.alloc_ranges.get_mut().iter_mut(offset, size) { + range.load_relaxed(&mut *current_state); + } + }else{ + // Perform acquire(or seq-cst) atomic load + for range in alloc.alloc_ranges.get_mut().iter_mut(offset, size) { + range.acquire(&mut *current_state); + } + } + + // Log changes to atomic memory + if log::log_enabled!(log::Level::Trace) { + for range in alloc.alloc_ranges.get_mut().iter(offset, size) { + log::trace!( + " updated atomic memory({:?}, offset={}, size={}) to {:#?}", + place.ptr.assert_ptr().alloc_id, offset.bytes(), size.bytes(), + range.atomic_ops + ); + } + } + + std::mem::drop(current_state); + let data_race = &*this.memory.extra.data_race; + data_race.advance_vector_clock(); + } + Ok(()) + } + + /// Update the data-race detector for an atomic write occuring at the + /// associated memory-place and on the current thread + fn validate_atomic_store( + &mut self, place: MPlaceTy<'tcx, Tag>, atomic: AtomicWriteOp + ) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + let data_race = &*this.memory.extra.data_race; + if data_race.multi_threaded.get() { + data_race.advance_vector_clock(); + + let ( + alloc, size, offset + ) = this.load_data_race_state(place)?; + let current_thread = alloc.global.current_thread(); + let mut current_state = alloc.global.current_thread_state_mut(); + log::trace!( + "Atomic store on {:?} with ordering {:?}, in memory({:?}, offset={}, size={})", + current_thread, atomic, + place.ptr.assert_ptr().alloc_id, offset.bytes(), size.bytes() + ); + + if atomic == AtomicWriteOp::Relaxed { + // Perform relaxed atomic store + for range in alloc.alloc_ranges.get_mut().iter_mut(offset, size) { + range.store_relaxed(&mut *current_state, current_thread); + } + }else{ + // Perform release(or seq-cst) atomic store + for range in alloc.alloc_ranges.get_mut().iter_mut(offset, size) { + range.release(&mut *current_state, current_thread); + } + } + + // Log changes to atomic memory + if log::log_enabled!(log::Level::Trace) { + for range in alloc.alloc_ranges.get_mut().iter(offset, size) { + log::trace!( + " updated atomic memory({:?}, offset={}, size={}) to {:#?}", + place.ptr.assert_ptr().alloc_id, offset.bytes(), size.bytes(), + range.atomic_ops + ); + } + } + + std::mem::drop(current_state); + let data_race = &*this.memory.extra.data_race; + data_race.advance_vector_clock(); + } + Ok(()) + } + + /// Update the data-race detector for an atomic read-modify-write occuring + /// at the associated memory place and on the current thread + fn validate_atomic_rmw( + &mut self, place: MPlaceTy<'tcx, Tag>, atomic: AtomicRWOp + ) -> InterpResult<'tcx> { + use AtomicRWOp::*; + let this = self.eval_context_mut(); + let data_race = &*this.memory.extra.data_race; + if data_race.multi_threaded.get() { + data_race.advance_vector_clock(); + + let ( + alloc, size, offset + ) = this.load_data_race_state(place)?; + let current_thread = alloc.global.current_thread(); + let mut current_state = alloc.global.current_thread_state_mut(); + log::trace!( + "Atomic RMW on {:?} with ordering {:?}, in memory({:?}, offset={}, size={})", + current_thread, atomic, + place.ptr.assert_ptr().alloc_id, offset.bytes(), size.bytes() + ); + + let acquire = matches!(atomic, Acquire | AcqRel | SeqCst); + let release = matches!(atomic, Release | AcqRel | SeqCst); + for range in alloc.alloc_ranges.get_mut().iter_mut(offset, size) { + //FIXME: this is probably still slightly wrong due to the quirks + // in the c++11 memory model + if acquire { + // Atomic RW-Op acquire + range.acquire(&mut *current_state); + }else{ + range.load_relaxed(&mut *current_state); + } + if release { + // Atomic RW-Op release + range.rmw_release(&mut *current_state, current_thread); + }else{ + range.rmw_relaxed(&mut *current_state); + } + } + + // Log changes to atomic memory + if log::log_enabled!(log::Level::Trace) { + for range in alloc.alloc_ranges.get_mut().iter(offset, size) { + log::trace!( + " updated atomic memory({:?}, offset={}, size={}) to {:#?}", + place.ptr.assert_ptr().alloc_id, offset.bytes(), size.bytes(), + range.atomic_ops + ); + } + } + + std::mem::drop(current_state); + let data_race = &*this.memory.extra.data_race; + data_race.advance_vector_clock(); + } + Ok(()) + } + + /// Update the data-race detector for an atomic fence on the current thread + fn validate_atomic_fence(&mut self, atomic: AtomicFenceOp) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + let data_race = &*this.memory.extra.data_race; + if data_race.multi_threaded.get() { + data_race.advance_vector_clock(); + + log::trace!("Atomic fence on {:?} with ordering {:?}", data_race.current_thread(), atomic); + // Apply data-race detection for the current fences + // this treats AcqRel and SeqCst as the same as a acquire + // and release fence applied in the same timestamp. + if atomic != AtomicFenceOp::Release { + // Either Acquire | AcqRel | SeqCst + data_race.current_thread_state_mut().apply_acquire_fence(); + } + if atomic != AtomicFenceOp::Acquire { + // Either Release | AcqRel | SeqCst + data_race.current_thread_state_mut().apply_release_fence(); + } + + data_race.advance_vector_clock(); + } + Ok(()) + } +} + +/// Handle for locks to express their +/// acquire-release semantics +#[derive(Clone, Debug, Default)] +pub struct DataRaceLockHandle { + + /// Internal acquire-release clock + /// to express the acquire release sync + /// found in concurrency primitives + clock: VClock, +} +impl DataRaceLockHandle { + pub fn set_values(&mut self, other: &Self) { + self.clock.set_values(&other.clock) + } + pub fn reset(&mut self) { + self.clock.set_zero_vector(); + } +} + + +/// Avoid an atomic allocation for the common +/// case with atomic operations where the number +/// of active release sequences is small +#[derive(Clone, PartialEq, Eq)] +enum AtomicReleaseSequences { + + /// Contains one or no values + /// if empty: (None, reset vector clock) + /// if one: (Some(thread), thread_clock) + ReleaseOneOrEmpty(Option, VClock), + + /// Contains two or more values + /// stored in a hash-map of thread id to + /// vector clocks + ReleaseMany(FxHashMap) +} +impl AtomicReleaseSequences { + + /// Return an empty set of atomic release sequences + #[inline] + fn new() -> AtomicReleaseSequences { + Self::ReleaseOneOrEmpty(None, VClock::default()) + } + + /// Remove all values except for the value stored at `thread` and set + /// the vector clock to the associated `clock` value + #[inline] + fn clear_and_set(&mut self, thread: ThreadId, clock: &VClock) { + match self { + Self::ReleaseOneOrEmpty(id, rel_clock) => { + *id = Some(thread); + rel_clock.set_values(clock); + } + Self::ReleaseMany(_) => { + *self = Self::ReleaseOneOrEmpty(Some(thread), clock.clone()); + } + } + } + + /// Remove all values except for the value stored at `thread` + #[inline] + fn clear_and_retain(&mut self, thread: ThreadId) { + match self { + Self::ReleaseOneOrEmpty(id, rel_clock) => { + // Keep or forget depending on id + if *id == Some(thread) { + *id = None; + rel_clock.set_zero_vector(); + } + }, + Self::ReleaseMany(hash_map) => { + // Retain only the thread element, so reduce to size + // of 1 or 0, and move to smaller format + if let Some(clock) = hash_map.remove(&thread) { + *self = Self::ReleaseOneOrEmpty(Some(thread), clock); + }else{ + *self = Self::new(); + } + } + } + } + + /// Insert a release sequence at `thread` with values `clock` + fn insert(&mut self, thread: ThreadId, clock: &VClock) { + match self { + Self::ReleaseOneOrEmpty(id, rel_clock) => { + if id.map_or(true, |id| id == thread) { + *id = Some(thread); + rel_clock.set_values(clock); + }else{ + let mut hash_map = FxHashMap::default(); + hash_map.insert(thread, clock.clone()); + hash_map.insert(id.unwrap(), rel_clock.clone()); + *self = Self::ReleaseMany(hash_map); + } + }, + Self::ReleaseMany(hash_map) => { + hash_map.insert(thread, clock.clone()); + } + } + } + + /// Return the release sequence at `thread` if one exists + #[inline] + fn load(&self, thread: ThreadId) -> Option<&VClock> { + match self { + Self::ReleaseOneOrEmpty(id, clock) => { + if *id == Some(thread) { + Some(clock) + }else{ + None + } + }, + Self::ReleaseMany(hash_map) => { + hash_map.get(&thread) + } + } + } +} + +/// Custom debug implementation to correctly +/// print debug as a logical mapping from threads +/// to vector-clocks +impl Debug for AtomicReleaseSequences { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::ReleaseOneOrEmpty(None,_) => { + f.debug_map().finish() + }, + Self::ReleaseOneOrEmpty(Some(id), clock) => { + f.debug_map().entry(&id, &clock).finish() + }, + Self::ReleaseMany(hash_map) => { + Debug::fmt(hash_map, f) + } + } + } +} + +/// Externally stored memory cell clocks +/// explicitly to reduce memory usage for the +/// common case where no atomic operations +/// exists on the memory cell +#[derive(Clone, PartialEq, Eq, Debug)] +struct AtomicMemoryCellClocks { + + /// Synchronization vector for acquire-release semantics + sync_vector: VClock, + + /// The Hash-Map of all threads for which a release + /// sequence exists in the memory cell + release_sequences: AtomicReleaseSequences, +} + +/// Memory Cell vector clock metadata +/// for data-race detection +#[derive(Clone, PartialEq, Eq, Debug)] +struct MemoryCellClocks { + + /// The vector-clock of the last write + write: Timestamp, + + /// The id of the thread that performed the last write to this memory location + write_thread: ThreadId, + + /// The vector-clock of the set of previous reads + /// each index is set to the timestamp that the associated + /// thread last read this value. + read: VClock, + + /// Atomic acquire & release sequence tracking clocks + /// for non-atomic memory in the common case this + /// value is set to None + atomic_ops: Option>, +} + +/// Create a default memory cell clocks instance +/// for uninitialized memory +impl Default for MemoryCellClocks { + fn default() -> Self { + MemoryCellClocks { + read: VClock::default(), + write: 0, + write_thread: ThreadId::new(u32::MAX as usize), + atomic_ops: None + } + } +} + +impl MemoryCellClocks { + + /// Load the internal atomic memory cells if they exist + #[inline] + fn atomic(&mut self) -> Option<&AtomicMemoryCellClocks> { + match &self.atomic_ops { + Some(op) => Some(&*op), + None => None + } + } + + /// Load or create the internal atomic memory metadata + /// if it does not exist + #[inline] + fn atomic_mut(&mut self) -> &mut AtomicMemoryCellClocks { + self.atomic_ops.get_or_insert_with(|| { + Box::new(AtomicMemoryCellClocks { + sync_vector: VClock::default(), + release_sequences: AtomicReleaseSequences::new() + }) + }) + } + + /// Update memory cell data-race tracking for atomic + /// load acquire semantics, is a no-op if this memory was + /// not used previously as atomic memory + fn acquire(&mut self, clocks: &mut ThreadClockSet) { + if let Some(atomic) = self.atomic() { + clocks.clock.join(&atomic.sync_vector); + } + } + /// Update memory cell data-race tracking for atomic + /// load relaxed semantics, is a no-op if this memory was + /// not used previously as atomic memory + fn load_relaxed(&mut self, clocks: &mut ThreadClockSet) { + if let Some(atomic) = self.atomic() { + clocks.fence_acquire.join(&atomic.sync_vector); + } + } + + + /// Update the memory cell data-race tracking for atomic + /// store release semantics + fn release(&mut self, clocks: &ThreadClockSet, thread: ThreadId) { + let atomic = self.atomic_mut(); + atomic.sync_vector.set_values(&clocks.clock); + atomic.release_sequences.clear_and_set(thread, &clocks.clock); + } + /// Update the memory cell data-race tracking for atomic + /// store relaxed semantics + fn store_relaxed(&mut self, clocks: &ThreadClockSet, thread: ThreadId) { + let atomic = self.atomic_mut(); + atomic.sync_vector.set_values(&clocks.fence_release); + if let Some(release) = atomic.release_sequences.load(thread) { + atomic.sync_vector.join(release); + } + atomic.release_sequences.clear_and_retain(thread); + } + /// Update the memory cell data-race tracking for atomic + /// store release semantics for RMW operations + fn rmw_release(&mut self, clocks: &ThreadClockSet, thread: ThreadId) { + let atomic = self.atomic_mut(); + atomic.sync_vector.join(&clocks.clock); + atomic.release_sequences.insert(thread, &clocks.clock); + } + /// Update the memory cell data-race tracking for atomic + /// store relaxed semantics for RMW operations + fn rmw_relaxed(&mut self, clocks: &ThreadClockSet) { + let atomic = self.atomic_mut(); + atomic.sync_vector.join(&clocks.fence_release); + } + + + + /// Detect races for non-atomic read operations at the current memory cell + /// returns true if a data-race is detected + fn read_race_detect(&mut self, clocks: &ThreadClockSet, thread: ThreadId) -> bool { + if self.write <= clocks.clock[self.write_thread] { + self.read.set_at_thread(&clocks.clock, thread); + false + }else{ + true + } + } + + /// Detect races for non-atomic write operations at the current memory cell + /// returns true if a data-race is detected + fn write_race_detect(&mut self, clocks: &ThreadClockSet, thread: ThreadId) -> bool { + if self.write <= clocks.clock[self.write_thread] && self.read <= clocks.clock { + self.write = clocks.clock[thread]; + self.write_thread = thread; + self.read.set_zero_vector(); + false + }else{ + true + } + } +} + +/// Vector clock metadata for a logical memory allocation +#[derive(Debug, Clone)] +pub struct VClockAlloc { + + /// Range of Vector clocks, mapping to the vector-clock + /// index of the last write to the bytes in this allocation + alloc_ranges: RefCell>, + + // Pointer to global state + global: MemoryExtra, +} + +impl VClockAlloc { + + /// Create a new data-race allocation detector + pub fn new_allocation(global: &MemoryExtra, len: Size) -> VClockAlloc { + VClockAlloc { + global: Rc::clone(global), + alloc_ranges: RefCell::new( + RangeMap::new(len, MemoryCellClocks::default()) + ) + } + } + + /// Report a data-race found in the program + /// this finds the two racing threads and the type + /// of data-race that occured, this will also + /// return info about the memory location the data-race + /// occured in + #[cold] + #[inline(never)] + fn report_data_race<'tcx>( + global: &MemoryExtra, range: &MemoryCellClocks, action: &str, + pointer: Pointer, len: Size + ) -> InterpResult<'tcx> { + let current_thread = global.current_thread(); + let current_state = global.current_thread_state(); + let mut write_clock = VClock::default(); + let ( + other_action, other_thread, other_clock + ) = if range.write > current_state.clock[range.write_thread] { + + // Create effective write-clock that the data-race occured with + let wclock = write_clock.get_mut_with_min_len( + current_state.clock.as_slice().len() + .max(range.write_thread.to_u32() as usize + 1) + ); + wclock[range.write_thread.to_u32() as usize] = range.write; + ("WRITE", range.write_thread, write_clock.as_slice()) + }else{ + + // Find index in the read-clock that the data-race occured with + let read_slice = range.read.as_slice(); + let clock_slice = current_state.clock.as_slice(); + let conflicting_index = read_slice.iter() + .zip(clock_slice.iter()) + .enumerate().find_map(|(idx,(&read, &clock))| { + if read > clock { + Some(idx) + }else{ + None + } + }).unwrap_or_else(|| { + assert!(read_slice.len() > clock_slice.len(), "BUG: cannot find read race yet reported data-race"); + let rest_read = &read_slice[clock_slice.len()..]; + rest_read.iter().enumerate().find_map(|(idx, &val)| { + if val > 0 { + Some(idx + clock_slice.len()) + }else{ + None + } + }).expect("Invariant broken for read-slice, no 0 element at the tail") + }); + ("READ", ThreadId::new(conflicting_index), range.read.as_slice()) + }; + + let current_thread_info = global.print_thread_metadata(current_thread); + let other_thread_info = global.print_thread_metadata(other_thread); + + // Throw the data-race detection + throw_ub_format!( + "Data race detected between {} on {} and {} on {}, memory({:?},offset={},size={})\ + \n\t\t -current vector clock = {:?}\ + \n\t\t -conflicting timestamp = {:?}", + action, current_thread_info, + other_action, other_thread_info, + pointer.alloc_id, pointer.offset.bytes(), len.bytes(), + current_state.clock, + other_clock + ) + } + + /// Detect data-races for an unsychronized read operation, will not perform + /// data-race threads if `multi-threaded` is false, either due to no threads + /// being created or if it is temporarily disabled during a racy read or write + /// operation + pub fn read<'tcx>(&self, pointer: Pointer, len: Size) -> InterpResult<'tcx> { + if self.global.multi_threaded.get() { + let current_thread = self.global.current_thread(); + let current_state = self.global.current_thread_state(); + + // The alloc-ranges are not split, however changes are not going to be made + // to the ranges being tested, so this is ok + let mut alloc_ranges = self.alloc_ranges.borrow_mut(); + for range in alloc_ranges.iter_mut(pointer.offset, len) { + if range.read_race_detect(&*current_state, current_thread) { + // Report data-race + return Self::report_data_race( + &self.global,range, "READ", pointer, len + ); + } + } + Ok(()) + }else{ + Ok(()) + } + } + /// Detect data-races for an unsychronized write operation, will not perform + /// data-race threads if `multi-threaded` is false, either due to no threads + /// being created or if it is temporarily disabled during a racy read or write + /// operation + pub fn write<'tcx>(&mut self, pointer: Pointer, len: Size) -> InterpResult<'tcx> { + if self.global.multi_threaded.get() { + let current_thread = self.global.current_thread(); + let current_state = self.global.current_thread_state(); + for range in self.alloc_ranges.get_mut().iter_mut(pointer.offset, len) { + if range.write_race_detect(&*current_state, current_thread) { + // Report data-race + return Self::report_data_race( + &self.global, range, "WRITE", pointer, len + ); + } + } + Ok(()) + }else{ + Ok(()) + } + } + /// Detect data-races for an unsychronized deallocate operation, will not perform + /// data-race threads if `multi-threaded` is false, either due to no threads + /// being created or if it is temporarily disabled during a racy read or write + /// operation + pub fn deallocate<'tcx>(&mut self, pointer: Pointer, len: Size) -> InterpResult<'tcx> { + if self.global.multi_threaded.get() { + let current_thread = self.global.current_thread(); + let current_state = self.global.current_thread_state(); + for range in self.alloc_ranges.get_mut().iter_mut(pointer.offset, len) { + if range.write_race_detect(&*current_state, current_thread) { + // Report data-race + return Self::report_data_race( + &self.global, range, "DEALLOCATE", pointer, len + ); + } + } + Ok(()) + }else{ + Ok(()) + } + } +} + +/// The current set of vector clocks describing the state +/// of a thread, contains the happens-before clock and +/// additional metadata to model atomic fence operations +#[derive(Clone, Default, Debug)] +struct ThreadClockSet { + /// The increasing clock representing timestamps + /// that happen-before this thread. + clock: VClock, + + /// The set of timestamps that will happen-before this + /// thread once it performs an acquire fence + fence_acquire: VClock, + + /// The last timesamp of happens-before relations that + /// have been released by this thread by a fence + fence_release: VClock, +} + +impl ThreadClockSet { + + /// Apply the effects of a release fence to this + /// set of thread vector clocks + #[inline] + fn apply_release_fence(&mut self) { + self.fence_release.set_values(&self.clock); + } + + /// Apply the effects of a acquire fence to this + /// set of thread vector clocks + #[inline] + fn apply_acquire_fence(&mut self) { + self.clock.join(&self.fence_acquire); + } + + /// Increment the happens-before clock at a + /// known index + #[inline] + fn increment_clock(&mut self, thread: ThreadId) { + self.clock.increment_thread(thread); + } + + /// Join the happens-before clock with that of + /// another thread, used to model thread join + /// operations + fn join_with(&mut self, other: &ThreadClockSet) { + self.clock.join(&other.clock); + } +} + +/// Global data-race detection state, contains the currently +/// executing thread as well as the vector-clocks associated +/// with each of the threads. +#[derive(Debug, Clone)] +pub struct GlobalState { + + /// Set to true once the first additional + /// thread has launched, due to the dependency + /// between before and after a thread launch + /// Any data-races must be recorded after this + /// so concurrent execution can ignore recording + /// any data-races + multi_threaded: Cell, + + /// The current vector clock for all threads + /// this includes threads that have terminated + /// execution + thread_clocks: RefCell>, + + /// Thread name cache for better diagnostics on the reporting + /// of a data-race + thread_names: RefCell>>>, + + /// The current thread being executed, + /// this is mirrored from the scheduler since + /// it is required for loading the current vector + /// clock for data-race detection + current_thread_id: Cell, +} +impl GlobalState { + + /// Create a new global state, setup with just thread-id=0 + /// advanced to timestamp = 1 + pub fn new() -> Self { + let mut vec = IndexVec::new(); + let thread_id = vec.push(ThreadClockSet::default()); + vec[thread_id].increment_clock(thread_id); + GlobalState { + multi_threaded: Cell::new(false), + thread_clocks: RefCell::new(vec), + thread_names: RefCell::new(IndexVec::new()), + current_thread_id: Cell::new(thread_id), + } + } + + + // Hook for thread creation, enabled multi-threaded execution and marks + // the current thread timestamp as happening-before the current thread + #[inline] + pub fn thread_created(&self, thread: ThreadId) { + + // Enable multi-threaded execution mode now that there are at least + // two threads + self.multi_threaded.set(true); + let current_thread = self.current_thread_id.get(); + let mut vectors = self.thread_clocks.borrow_mut(); + vectors.ensure_contains_elem(thread, Default::default); + let (current, created) = vectors.pick2_mut(current_thread, thread); + + // Pre increment clocks before atomic operation + current.increment_clock(current_thread); + + // The current thread happens-before the created thread + // so update the created vector clock + created.join_with(current); + + // Post increment clocks after atomic operation + current.increment_clock(current_thread); + created.increment_clock(thread); + } + + /// Hook on a thread join to update the implicit happens-before relation + /// between the joined thead and the current thread + #[inline] + pub fn thread_joined(&self, current_thread: ThreadId, join_thread: ThreadId) { + let mut vectors = self.thread_clocks.borrow_mut(); + let (current, join) = vectors.pick2_mut(current_thread, join_thread); + + // Pre increment clocks before atomic operation + current.increment_clock(current_thread); + join.increment_clock(join_thread); + + // The join thread happens-before the current thread + // so update the current vector clock + current.join_with(join); + + // Post increment clocks after atomic operation + current.increment_clock(current_thread); + join.increment_clock(join_thread); + } + + /// Hook for updating the local tracker of the currently + /// enabled thread, should always be updated whenever + /// `active_thread` in thread.rs is updated + #[inline] + pub fn thread_set_active(&self, thread: ThreadId) { + self.current_thread_id.set(thread); + } + + /// Hook for updating the local tracker of the threads name + /// this should always mirror the local value in thread.rs + /// the thread name is used for improved diagnostics + /// during a data-race + #[inline] + pub fn thread_set_name(&self, name: String) { + let name = name.into_boxed_str(); + let mut names = self.thread_names.borrow_mut(); + let thread = self.current_thread_id.get(); + names.ensure_contains_elem(thread, Default::default); + names[thread] = Some(name); + } + + + /// Advance the vector clock for a thread + /// this is called before and after any atomic/synchronizing operations + /// that may manipulate state + #[inline] + fn advance_vector_clock(&self) { + let thread = self.current_thread_id.get(); + let mut vectors = self.thread_clocks.borrow_mut(); + vectors[thread].increment_clock(thread); + + // Log the increment in the atomic vector clock + log::trace!("Atomic vector clock increase for {:?} to {:?}",thread, vectors[thread].clock); + } + + + /// Internal utility to identify a thread stored internally + /// returns the id and the name for better diagnostics + fn print_thread_metadata(&self, thread: ThreadId) -> String { + if let Some(Some(name)) = self.thread_names.borrow().get(thread) { + let name: &str = name; + format!("Thread(id = {:?}, name = {:?})", thread.to_u32(), &*name) + }else{ + format!("Thread(id = {:?})", thread.to_u32()) + } + } + + + /// Acquire a lock, express that the previous call of + /// `validate_lock_release` must happen before this + pub fn validate_lock_acquire(&self, lock: &DataRaceLockHandle, thread: ThreadId) { + let mut ref_vector = self.thread_clocks.borrow_mut(); + ref_vector[thread].increment_clock(thread); + + let clocks = &mut ref_vector[thread]; + clocks.clock.join(&lock.clock); + + ref_vector[thread].increment_clock(thread); + } + + /// Release a lock handle, express that this happens-before + /// any subsequent calls to `validate_lock_acquire` + pub fn validate_lock_release(&self, lock: &mut DataRaceLockHandle, thread: ThreadId) { + let mut ref_vector = self.thread_clocks.borrow_mut(); + ref_vector[thread].increment_clock(thread); + + let clocks = &ref_vector[thread]; + lock.clock.set_values(&clocks.clock); + + ref_vector[thread].increment_clock(thread); + } + + /// Release a lock handle, express that this happens-before + /// any subsequent calls to `validate_lock_acquire` as well + /// as any previous calls to this function after any + /// `validate_lock_release` calls + pub fn validate_lock_release_shared(&self, lock: &mut DataRaceLockHandle, thread: ThreadId) { + let mut ref_vector = self.thread_clocks.borrow_mut(); + ref_vector[thread].increment_clock(thread); + + let clocks = &ref_vector[thread]; + lock.clock.join(&clocks.clock); + + ref_vector[thread].increment_clock(thread); + } + + /// Load the thread clock set associated with the current thread + #[inline] + fn current_thread_state(&self) -> Ref<'_, ThreadClockSet> { + let ref_vector = self.thread_clocks.borrow(); + let thread = self.current_thread_id.get(); + Ref::map(ref_vector, |vector| &vector[thread]) + } + + /// Load the thread clock set associated with the current thread + /// mutably for modification + #[inline] + fn current_thread_state_mut(&self) -> RefMut<'_, ThreadClockSet> { + let ref_vector = self.thread_clocks.borrow_mut(); + let thread = self.current_thread_id.get(); + RefMut::map(ref_vector, |vector| &mut vector[thread]) + } + + /// Return the current thread, should be the same + /// as the data-race active thread + #[inline] + fn current_thread(&self) -> ThreadId { + self.current_thread_id.get() + } +} + + +/// The size of the vector-clock to store inline +/// clock vectors larger than this will be stored on the heap +const SMALL_VECTOR: usize = 4; + +/// The type of the time-stamps recorded in the data-race detector +/// set to a type of unsigned integer +type Timestamp = u32; + +/// A vector clock for detecting data-races +/// invariants: +/// - the last element in a VClock must not be 0 +/// -- this means that derive(PartialEq & Eq) is correct +/// -- as there is no implicit zero tail that might be equal +/// -- also simplifies the implementation of PartialOrd +#[derive(Clone, PartialEq, Eq, Default, Debug)] +pub struct VClock(SmallVec<[Timestamp; SMALL_VECTOR]>); + +impl VClock { + + /// Load the backing slice behind the clock vector. + #[inline] + fn as_slice(&self) -> &[Timestamp] { + self.0.as_slice() + } + + /// Get a mutable slice to the internal vector with minimum `min_len` + /// elements, to preserve invariants this vector must modify + /// the `min_len`-1 nth element to a non-zero value + #[inline] + fn get_mut_with_min_len(&mut self, min_len: usize) -> &mut [Timestamp] { + if self.0.len() < min_len { + self.0.resize(min_len, 0); + } + assert!(self.0.len() >= min_len); + self.0.as_mut_slice() + } + + /// Increment the vector clock at a known index + #[inline] + fn increment_index(&mut self, idx: usize) { + let mut_slice = self.get_mut_with_min_len(idx + 1); + let idx_ref = &mut mut_slice[idx]; + *idx_ref = idx_ref.checked_add(1).expect("Vector clock overflow") + } + + // Increment the vector element representing the progress + // of execution in the given thread + #[inline] + pub fn increment_thread(&mut self, thread: ThreadId) { + self.increment_index(thread.to_u32() as usize); + } + + // Join the two vector-clocks together, this + // sets each vector-element to the maximum value + // of that element in either of the two source elements. + pub fn join(&mut self, other: &Self) { + let rhs_slice = other.as_slice(); + let lhs_slice = self.get_mut_with_min_len(rhs_slice.len()); + + // Element-wise set to maximum. + for (l, &r) in lhs_slice.iter_mut().zip(rhs_slice.iter()) { + *l = r.max(*l); + } + } + + /// Joins with a thread at a known index + fn set_at_index(&mut self, other: &Self, idx: usize){ + let mut_slice = self.get_mut_with_min_len(idx + 1); + let slice = other.as_slice(); + mut_slice[idx] = slice[idx]; + } + + /// Join with a threads vector clock only at the desired index + /// returns true if the value updated + #[inline] + pub fn set_at_thread(&mut self, other: &Self, thread: ThreadId){ + self.set_at_index(other, thread.to_u32() as usize); + } + + /// Clear the vector to all zeros, stored as an empty internal + /// vector + #[inline] + pub fn set_zero_vector(&mut self) { + self.0.clear(); + } + + /// Set the values stored in this vector clock + /// to the values stored in another. + pub fn set_values(&mut self, new_value: &VClock) { + let new_slice = new_value.as_slice(); + self.0.resize(new_slice.len(), 0); + self.0.copy_from_slice(new_slice); + } +} + + +impl PartialOrd for VClock { + fn partial_cmp(&self, other: &VClock) -> Option { + + // Load the values as slices + let lhs_slice = self.as_slice(); + let rhs_slice = other.as_slice(); + + // Iterate through the combined vector slice + // keeping track of the order that is currently possible to satisfy. + // If an ordering relation is detected to be impossible, then bail and + // directly return None + let mut iter = lhs_slice.iter().zip(rhs_slice.iter()); + let mut order = match iter.next() { + Some((lhs, rhs)) => lhs.cmp(rhs), + None => Ordering::Equal + }; + for (l, r) in iter { + match order { + Ordering::Equal => order = l.cmp(r), + Ordering::Less => if l > r { + return None + }, + Ordering::Greater => if l < r { + return None + } + } + } + + //Now test if either left or right have trailing elements + // by the invariant the trailing elements have at least 1 + // non zero value, so no additional calculation is required + // to determine the result of the PartialOrder + let l_len = lhs_slice.len(); + let r_len = rhs_slice.len(); + match l_len.cmp(&r_len) { + // Equal has no additional elements: return current order + Ordering::Equal => Some(order), + // Right has at least 1 element > than the implicit 0, + // so the only valid values are Ordering::Less or None + Ordering::Less => match order { + Ordering::Less | Ordering::Equal => Some(Ordering::Less), + Ordering::Greater => None + } + // Left has at least 1 element > than the implicit 0, + // so the only valid values are Ordering::Greater or None + Ordering::Greater => match order { + Ordering::Greater | Ordering::Equal => Some(Ordering::Greater), + Ordering::Less => None + } + } + } + + fn lt(&self, other: &VClock) -> bool { + // Load the values as slices + let lhs_slice = self.as_slice(); + let rhs_slice = other.as_slice(); + + // If l_len > r_len then at least one element + // in l_len is > than r_len, therefore the result + // is either Some(Greater) or None, so return false + // early. + let l_len = lhs_slice.len(); + let r_len = rhs_slice.len(); + if l_len <= r_len { + // If any elements on the left are greater than the right + // then the result is None or Some(Greater), both of which + // return false, the earlier test asserts that no elements in the + // extended tail violate this assumption. Otherwise l <= r, finally + // the case where the values are potentially equal needs to be considered + // and false returned as well + let mut equal = l_len == r_len; + for (&l, &r) in lhs_slice.iter().zip(rhs_slice.iter()) { + if l > r { + return false + }else if l < r { + equal = false; + } + } + !equal + }else{ + false + } + } + + fn le(&self, other: &VClock) -> bool { + // Load the values as slices + let lhs_slice = self.as_slice(); + let rhs_slice = other.as_slice(); + + // If l_len > r_len then at least one element + // in l_len is > than r_len, therefore the result + // is either Some(Greater) or None, so return false + // early. + let l_len = lhs_slice.len(); + let r_len = rhs_slice.len(); + if l_len <= r_len { + // If any elements on the left are greater than the right + // then the result is None or Some(Greater), both of which + // return false, the earlier test asserts that no elements in the + // extended tail violate this assumption. Otherwise l <= r + !lhs_slice.iter().zip(rhs_slice.iter()).any(|(&l, &r)| l > r) + }else{ + false + } + } + + fn gt(&self, other: &VClock) -> bool { + // Load the values as slices + let lhs_slice = self.as_slice(); + let rhs_slice = other.as_slice(); + + // If r_len > l_len then at least one element + // in r_len is > than l_len, therefore the result + // is either Some(Less) or None, so return false + // early. + let l_len = lhs_slice.len(); + let r_len = rhs_slice.len(); + if l_len >= r_len { + // If any elements on the left are less than the right + // then the result is None or Some(Less), both of which + // return false, the earlier test asserts that no elements in the + // extended tail violate this assumption. Otherwise l >=, finally + // the case where the values are potentially equal needs to be considered + // and false returned as well + let mut equal = l_len == r_len; + for (&l, &r) in lhs_slice.iter().zip(rhs_slice.iter()) { + if l < r { + return false + }else if l > r { + equal = false; + } + } + !equal + }else{ + false + } + } + + fn ge(&self, other: &VClock) -> bool { + // Load the values as slices + let lhs_slice = self.as_slice(); + let rhs_slice = other.as_slice(); + + // If r_len > l_len then at least one element + // in r_len is > than l_len, therefore the result + // is either Some(Less) or None, so return false + // early. + let l_len = lhs_slice.len(); + let r_len = rhs_slice.len(); + if l_len >= r_len { + // If any elements on the left are less than the right + // then the result is None or Some(Less), both of which + // return false, the earlier test asserts that no elements in the + // extended tail violate this assumption. Otherwise l >= r + !lhs_slice.iter().zip(rhs_slice.iter()).any(|(&l, &r)| l < r) + }else{ + false + } + } +} + +impl Index for VClock { + type Output = Timestamp; + + #[inline] + fn index(&self, index: ThreadId) -> &Timestamp { + self.as_slice().get(index.to_u32() as usize).unwrap_or(&0) + } +} + + +/// Test vector clock ordering operations +/// data-race detection is tested in the external +/// test suite +#[cfg(test)] +mod tests { + use super::{VClock, Timestamp}; + use std::cmp::Ordering; + + #[test] + fn test_equal() { + let mut c1 = VClock::default(); + let mut c2 = VClock::default(); + assert_eq!(c1, c2); + c1.increment_index(5); + assert_ne!(c1, c2); + c2.increment_index(53); + assert_ne!(c1, c2); + c1.increment_index(53); + assert_ne!(c1, c2); + c2.increment_index(5); + assert_eq!(c1, c2); + } + + #[test] + fn test_partial_order() { + // Small test + assert_order(&[1], &[1], Some(Ordering::Equal)); + assert_order(&[1], &[2], Some(Ordering::Less)); + assert_order(&[2], &[1], Some(Ordering::Greater)); + assert_order(&[1], &[1,2], Some(Ordering::Less)); + assert_order(&[2], &[1,2], None); + + // Misc tests + assert_order(&[400], &[0, 1], None); + + // Large test + assert_order(&[0,1,2,3,4,5,6,7,8,9,10], &[0,1,2,3,4,5,6,7,8,9,10,0,0,0], Some(Ordering::Equal)); + assert_order(&[0,1,2,3,4,5,6,7,8,9,10], &[0,1,2,3,4,5,6,7,8,9,10,0,1,0], Some(Ordering::Less)); + assert_order(&[0,1,2,3,4,5,6,7,8,9,11], &[0,1,2,3,4,5,6,7,8,9,10,0,0,0], Some(Ordering::Greater)); + assert_order(&[0,1,2,3,4,5,6,7,8,9,11], &[0,1,2,3,4,5,6,7,8,9,10,0,1,0], None); + assert_order(&[0,1,2,3,4,5,6,7,8,9,9 ], &[0,1,2,3,4,5,6,7,8,9,10,0,0,0], Some(Ordering::Less)); + assert_order(&[0,1,2,3,4,5,6,7,8,9,9 ], &[0,1,2,3,4,5,6,7,8,9,10,0,1,0], Some(Ordering::Less)); + } + + fn from_slice(mut slice: &[Timestamp]) -> VClock { + while let Some(0) = slice.last() { + slice = &slice[..slice.len() - 1] + } + VClock(smallvec::SmallVec::from_slice(slice)) + } + + fn assert_order(l: &[Timestamp], r: &[Timestamp], o: Option) { + let l = from_slice(l); + let r = from_slice(r); + + //Test partial_cmp + let compare = l.partial_cmp(&r); + assert_eq!(compare, o, "Invalid comparison\n l: {:?}\n r: {:?}",l,r); + let alt_compare = r.partial_cmp(&l); + assert_eq!(alt_compare, o.map(Ordering::reverse), "Invalid alt comparison\n l: {:?}\n r: {:?}",l,r); + + //Test operatorsm with faster implementations + assert_eq!( + matches!(compare,Some(Ordering::Less)), l < r, + "Invalid (<):\n l: {:?}\n r: {:?}",l,r + ); + assert_eq!( + matches!(compare,Some(Ordering::Less) | Some(Ordering::Equal)), l <= r, + "Invalid (<=):\n l: {:?}\n r: {:?}",l,r + ); + assert_eq!( + matches!(compare,Some(Ordering::Greater)), l > r, + "Invalid (>):\n l: {:?}\n r: {:?}",l,r + ); + assert_eq!( + matches!(compare,Some(Ordering::Greater) | Some(Ordering::Equal)), l >= r, + "Invalid (>=):\n l: {:?}\n r: {:?}",l,r + ); + assert_eq!( + matches!(alt_compare,Some(Ordering::Less)), r < l, + "Invalid alt (<):\n l: {:?}\n r: {:?}",l,r + ); + assert_eq!( + matches!(alt_compare,Some(Ordering::Less) | Some(Ordering::Equal)), r <= l, + "Invalid alt (<=):\n l: {:?}\n r: {:?}",l,r + ); + assert_eq!( + matches!(alt_compare,Some(Ordering::Greater)), r > l, + "Invalid alt (>):\n l: {:?}\n r: {:?}",l,r + ); + assert_eq!( + matches!(alt_compare,Some(Ordering::Greater) | Some(Ordering::Equal)), r >= l, + "Invalid alt (>=):\n l: {:?}\n r: {:?}",l,r + ); + } +} \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index d4802f3b11fa4..f384787e4c681 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -22,6 +22,7 @@ extern crate rustc_mir; extern crate rustc_span; extern crate rustc_target; +mod data_race; mod diagnostics; mod eval; mod helpers; @@ -52,6 +53,10 @@ pub use crate::shims::panic::{CatchUnwindData, EvalContextExt as _}; pub use crate::shims::tls::{EvalContextExt as _, TlsData}; pub use crate::shims::EvalContextExt as _; +pub use crate::data_race::{ + AtomicReadOp, AtomicWriteOp, AtomicRWOp, AtomicFenceOp, DataRaceLockHandle, + EvalContextExt as DataRaceEvalContextExt +}; pub use crate::diagnostics::{ register_diagnostic, report_error, EvalContextExt as DiagnosticsEvalContextExt, TerminationInfo, NonHaltingDiagnostic, diff --git a/src/machine.rs b/src/machine.rs index e9f9298e566c8..363513f636c9e 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -109,12 +109,15 @@ impl fmt::Display for MiriMemoryKind { pub struct AllocExtra { /// Stacked Borrows state is only added if it is enabled. pub stacked_borrows: Option, + /// Data race detection via the use of a vector-clock. + pub data_race: data_race::AllocExtra, } /// Extra global memory data #[derive(Clone, Debug)] pub struct MemoryExtra { pub stacked_borrows: Option, + pub data_race: data_race::MemoryExtra, pub intptrcast: intptrcast::MemoryExtra, /// Mapping extern static names to their canonical allocation. @@ -144,8 +147,10 @@ impl MemoryExtra { } else { None }; + let data_race = Rc::new(data_race::GlobalState::new()); MemoryExtra { stacked_borrows, + data_race, intptrcast: Default::default(), extern_statics: FxHashMap::default(), rng: RefCell::new(rng), @@ -467,6 +472,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { // No stacks, no tag. (None, Tag::Untagged) }; + let race_alloc = data_race::AllocExtra::new_allocation(&memory_extra.data_race, alloc.size); let mut stacked_borrows = memory_extra.stacked_borrows.as_ref().map(|sb| sb.borrow_mut()); let alloc: Allocation = alloc.with_tags_and_extra( |alloc| { @@ -478,7 +484,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { Tag::Untagged } }, - AllocExtra { stacked_borrows: stacks }, + AllocExtra { stacked_borrows: stacks, data_race: race_alloc }, ); (Cow::Owned(alloc), base_tag) } @@ -584,6 +590,7 @@ impl AllocationExtra for AllocExtra { ptr: Pointer, size: Size, ) -> InterpResult<'tcx> { + alloc.extra.data_race.read(ptr, size)?; if let Some(stacked_borrows) = &alloc.extra.stacked_borrows { stacked_borrows.memory_read(ptr, size) } else { @@ -597,6 +604,7 @@ impl AllocationExtra for AllocExtra { ptr: Pointer, size: Size, ) -> InterpResult<'tcx> { + alloc.extra.data_race.write(ptr, size)?; if let Some(stacked_borrows) = &mut alloc.extra.stacked_borrows { stacked_borrows.memory_written(ptr, size) } else { @@ -610,6 +618,7 @@ impl AllocationExtra for AllocExtra { ptr: Pointer, size: Size, ) -> InterpResult<'tcx> { + alloc.extra.data_race.deallocate(ptr, size)?; if let Some(stacked_borrows) = &mut alloc.extra.stacked_borrows { stacked_borrows.memory_deallocated(ptr, size) } else { diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index b401bd8adaee4..2bb15e712c5f2 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -4,7 +4,7 @@ use log::trace; use rustc_attr as attr; use rustc_ast::ast::FloatTy; -use rustc_middle::{mir, ty}; +use rustc_middle::{mir, mir::BinOp, ty}; use rustc_middle::ty::layout::IntegerExt; use rustc_apfloat::{Float, Round}; use rustc_target::abi::{Align, Integer, LayoutOf}; @@ -306,157 +306,117 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // Atomic operations - #[rustfmt::skip] - | "atomic_load" - | "atomic_load_relaxed" - | "atomic_load_acq" - => { - let &[place] = check_arg_count(args)?; - let place = this.deref_operand(place)?; - let val = this.read_scalar(place.into())?; // make sure it fits into a scalar; otherwise it cannot be atomic - - // Check alignment requirements. Atomics must always be aligned to their size, - // even if the type they wrap would be less aligned (e.g. AtomicU64 on 32bit must - // be 8-aligned). - let align = Align::from_bytes(place.layout.size.bytes()).unwrap(); - this.memory.check_ptr_access(place.ptr, place.layout.size, align)?; - - this.write_scalar(val, dest)?; - } - - #[rustfmt::skip] - | "atomic_store" - | "atomic_store_relaxed" - | "atomic_store_rel" - => { - let &[place, val] = check_arg_count(args)?; - let place = this.deref_operand(place)?; - let val = this.read_scalar(val)?; // make sure it fits into a scalar; otherwise it cannot be atomic + "atomic_load" => this.atomic_load(args, dest, AtomicReadOp::SeqCst)?, + "atomic_load_relaxed" => this.atomic_load(args, dest, AtomicReadOp::Relaxed)?, + "atomic_load_acq" => this.atomic_load(args, dest, AtomicReadOp::Acquire)?, + + "atomic_store" => this.atomic_store(args, AtomicWriteOp::SeqCst)?, + "atomic_store_relaxed" => this.atomic_store(args, AtomicWriteOp::Relaxed)?, + "atomic_store_rel" => this.atomic_store(args, AtomicWriteOp::Release)?, + + "atomic_fence_acq" => this.atomic_fence(args, AtomicFenceOp::Acquire)?, + "atomic_fence_rel" => this.atomic_fence(args, AtomicFenceOp::Release)?, + "atomic_fence_acqrel" => this.atomic_fence(args, AtomicFenceOp::AcqRel)?, + "atomic_fence" => this.atomic_fence(args, AtomicFenceOp::SeqCst)?, + + "atomic_singlethreadfence_acq" => this.compiler_fence(args, AtomicFenceOp::Acquire)?, + "atomic_singlethreadfence_rel" => this.compiler_fence(args, AtomicFenceOp::Release)?, + "atomic_singlethreadfence_acqrel" => this.compiler_fence(args, AtomicFenceOp::AcqRel)?, + "atomic_singlethreadfence" => this.compiler_fence(args, AtomicFenceOp::SeqCst)?, + + "atomic_xchg" => this.atomic_exchange(args, dest, AtomicRWOp::SeqCst)?, + "atomic_xchg_acq" => this.atomic_exchange(args, dest, AtomicRWOp::Acquire)?, + "atomic_xchg_rel" => this.atomic_exchange(args, dest, AtomicRWOp::Release)?, + "atomic_xchg_acqrel" => this.atomic_exchange(args, dest, AtomicRWOp::AcqRel)?, + "atomic_xchg_relaxed" => this.atomic_exchange(args, dest, AtomicRWOp::Relaxed)?, + + "atomic_cxchg" => this.atomic_compare_exchange( + args, dest, AtomicRWOp::SeqCst, AtomicReadOp::SeqCst + )?, + "atomic_cxchg_acq" => this.atomic_compare_exchange( + args, dest, AtomicRWOp::Acquire, AtomicReadOp::Acquire + )?, + "atomic_cxchg_rel" => this.atomic_compare_exchange( + args, dest, AtomicRWOp::Release, AtomicReadOp::Relaxed + )?, + "atomic_cxchg_acqrel" => this.atomic_compare_exchange + (args, dest, AtomicRWOp::AcqRel, AtomicReadOp::Acquire + )?, + "atomic_cxchg_relaxed" => this.atomic_compare_exchange( + args, dest, AtomicRWOp::Relaxed, AtomicReadOp::Relaxed + )?, + "atomic_cxchg_acq_failrelaxed" => this.atomic_compare_exchange( + args, dest, AtomicRWOp::Acquire, AtomicReadOp::Relaxed + )?, + "atomic_cxchg_acqrel_failrelaxed" => this.atomic_compare_exchange( + args, dest, AtomicRWOp::AcqRel, AtomicReadOp::Relaxed + )?, + "atomic_cxchg_failrelaxed" => this.atomic_compare_exchange( + args, dest, AtomicRWOp::SeqCst, AtomicReadOp::Relaxed + )?, + "atomic_cxchg_failacq" => this.atomic_compare_exchange( + args, dest, AtomicRWOp::SeqCst, AtomicReadOp::Acquire + )?, + + "atomic_cxchgweak" => this.atomic_compare_exchange_weak( + args, dest, AtomicRWOp::SeqCst, AtomicReadOp::SeqCst + )?, + "atomic_cxchgweak_acq" => this.atomic_compare_exchange_weak( + args, dest, AtomicRWOp::Acquire, AtomicReadOp::Acquire + )?, + "atomic_cxchgweak_rel" => this.atomic_compare_exchange_weak( + args, dest, AtomicRWOp::Release, AtomicReadOp::Relaxed + )?, + "atomic_cxchgweak_acqrel" => this.atomic_compare_exchange_weak( + args, dest, AtomicRWOp::AcqRel, AtomicReadOp::Acquire + )?, + "atomic_cxchgweak_relaxed" => this.atomic_compare_exchange_weak( + args, dest, AtomicRWOp::Relaxed, AtomicReadOp::Relaxed + )?, + "atomic_cxchgweak_acq_failrelaxed" => this.atomic_compare_exchange_weak( + args, dest, AtomicRWOp::Acquire, AtomicReadOp::Relaxed + )?, + "atomic_cxchgweak_acqrel_failrelaxed" => this.atomic_compare_exchange_weak( + args, dest, AtomicRWOp::AcqRel, AtomicReadOp::Relaxed + )?, + "atomic_cxchgweak_failrelaxed" => this.atomic_compare_exchange_weak( + args, dest, AtomicRWOp::SeqCst, AtomicReadOp::Relaxed + )?, + "atomic_cxchgweak_failacq" => this.atomic_compare_exchange_weak( + args, dest, AtomicRWOp::SeqCst, AtomicReadOp::Acquire + )?, + + "atomic_or" => this.atomic_op(args, dest, BinOp::BitOr, false, AtomicRWOp::SeqCst)?, + "atomic_or_acq" => this.atomic_op(args, dest, BinOp::BitOr, false, AtomicRWOp::Acquire)?, + "atomic_or_rel" => this.atomic_op(args, dest, BinOp::BitOr, false, AtomicRWOp::Release)?, + "atomic_or_acqrel" => this.atomic_op(args, dest, BinOp::BitOr, false, AtomicRWOp::AcqRel)?, + "atomic_or_relaxed" => this.atomic_op(args, dest, BinOp::BitOr, false, AtomicRWOp::Relaxed)?, + "atomic_xor" => this.atomic_op(args, dest, BinOp::BitXor, false, AtomicRWOp::SeqCst)?, + "atomic_xor_acq" => this.atomic_op(args, dest, BinOp::BitXor, false, AtomicRWOp::Acquire)?, + "atomic_xor_rel" => this.atomic_op(args, dest, BinOp::BitXor, false, AtomicRWOp::Release)?, + "atomic_xor_acqrel" => this.atomic_op(args, dest, BinOp::BitXor, false, AtomicRWOp::AcqRel)?, + "atomic_xor_relaxed" => this.atomic_op(args, dest, BinOp::BitXor, false, AtomicRWOp::Relaxed)?, + "atomic_and" => this.atomic_op(args, dest, BinOp::BitAnd, false, AtomicRWOp::SeqCst)?, + "atomic_and_acq" => this.atomic_op(args, dest, BinOp::BitAnd, false, AtomicRWOp::Acquire)?, + "atomic_and_rel" => this.atomic_op(args, dest, BinOp::BitAnd, false, AtomicRWOp::Release)?, + "atomic_and_acqrel" => this.atomic_op(args, dest, BinOp::BitAnd, false, AtomicRWOp::AcqRel)?, + "atomic_and_relaxed" => this.atomic_op(args, dest, BinOp::BitAnd, false, AtomicRWOp::Relaxed)?, + "atomic_nand" => this.atomic_op(args, dest, BinOp::BitAnd, true, AtomicRWOp::SeqCst)?, + "atomic_nand_acq" => this.atomic_op(args, dest, BinOp::BitAnd, true, AtomicRWOp::Acquire)?, + "atomic_nand_rel" => this.atomic_op(args, dest, BinOp::BitAnd, true, AtomicRWOp::Release)?, + "atomic_nand_acqrel" => this.atomic_op(args, dest, BinOp::BitAnd, true, AtomicRWOp::AcqRel)?, + "atomic_nand_relaxed" => this.atomic_op(args, dest, BinOp::BitAnd, true, AtomicRWOp::Relaxed)?, + "atomic_xadd" => this.atomic_op(args, dest, BinOp::Add, false, AtomicRWOp::SeqCst)?, + "atomic_xadd_acq" => this.atomic_op(args, dest, BinOp::Add, false, AtomicRWOp::Acquire)?, + "atomic_xadd_rel" => this.atomic_op(args, dest, BinOp::Add, false, AtomicRWOp::Release)?, + "atomic_xadd_acqrel" => this.atomic_op(args, dest, BinOp::Add, false, AtomicRWOp::AcqRel)?, + "atomic_xadd_relaxed" => this.atomic_op(args, dest, BinOp::Add, false, AtomicRWOp::Relaxed)?, + "atomic_xsub" => this.atomic_op(args, dest, BinOp::Sub, false, AtomicRWOp::SeqCst)?, + "atomic_xsub_acq" => this.atomic_op(args, dest, BinOp::Sub, false, AtomicRWOp::Acquire)?, + "atomic_xsub_rel" => this.atomic_op(args, dest, BinOp::Sub, false, AtomicRWOp::Release)?, + "atomic_xsub_acqrel" => this.atomic_op(args, dest, BinOp::Sub, false, AtomicRWOp::AcqRel)?, + "atomic_xsub_relaxed" => this.atomic_op(args, dest, BinOp::Sub, false, AtomicRWOp::Relaxed)?, - // Check alignment requirements. Atomics must always be aligned to their size, - // even if the type they wrap would be less aligned (e.g. AtomicU64 on 32bit must - // be 8-aligned). - let align = Align::from_bytes(place.layout.size.bytes()).unwrap(); - this.memory.check_ptr_access(place.ptr, place.layout.size, align)?; - - this.write_scalar(val, place.into())?; - } - - #[rustfmt::skip] - | "atomic_fence_acq" - | "atomic_fence_rel" - | "atomic_fence_acqrel" - | "atomic_fence" - | "atomic_singlethreadfence_acq" - | "atomic_singlethreadfence_rel" - | "atomic_singlethreadfence_acqrel" - | "atomic_singlethreadfence" - => { - let &[] = check_arg_count(args)?; - // FIXME: this will become relevant once we try to detect data races. - } - - _ if intrinsic_name.starts_with("atomic_xchg") => { - let &[place, new] = check_arg_count(args)?; - let place = this.deref_operand(place)?; - let new = this.read_scalar(new)?; - let old = this.read_scalar(place.into())?; - - // Check alignment requirements. Atomics must always be aligned to their size, - // even if the type they wrap would be less aligned (e.g. AtomicU64 on 32bit must - // be 8-aligned). - let align = Align::from_bytes(place.layout.size.bytes()).unwrap(); - this.memory.check_ptr_access(place.ptr, place.layout.size, align)?; - - this.write_scalar(old, dest)?; // old value is returned - this.write_scalar(new, place.into())?; - } - - _ if intrinsic_name.starts_with("atomic_cxchg") => { - let &[place, expect_old, new] = check_arg_count(args)?; - let place = this.deref_operand(place)?; - let expect_old = this.read_immediate(expect_old)?; // read as immediate for the sake of `binary_op()` - let new = this.read_scalar(new)?; - let old = this.read_immediate(place.into())?; // read as immediate for the sake of `binary_op()` - - // Check alignment requirements. Atomics must always be aligned to their size, - // even if the type they wrap would be less aligned (e.g. AtomicU64 on 32bit must - // be 8-aligned). - let align = Align::from_bytes(place.layout.size.bytes()).unwrap(); - this.memory.check_ptr_access(place.ptr, place.layout.size, align)?; - - // `binary_op` will bail if either of them is not a scalar. - let eq = this.overflowing_binary_op(mir::BinOp::Eq, old, expect_old)?.0; - let res = Immediate::ScalarPair(old.to_scalar_or_uninit(), eq.into()); - // Return old value. - this.write_immediate(res, dest)?; - // Update ptr depending on comparison. - if eq.to_bool()? { - this.write_scalar(new, place.into())?; - } - } - - #[rustfmt::skip] - | "atomic_or" - | "atomic_or_acq" - | "atomic_or_rel" - | "atomic_or_acqrel" - | "atomic_or_relaxed" - | "atomic_xor" - | "atomic_xor_acq" - | "atomic_xor_rel" - | "atomic_xor_acqrel" - | "atomic_xor_relaxed" - | "atomic_and" - | "atomic_and_acq" - | "atomic_and_rel" - | "atomic_and_acqrel" - | "atomic_and_relaxed" - | "atomic_nand" - | "atomic_nand_acq" - | "atomic_nand_rel" - | "atomic_nand_acqrel" - | "atomic_nand_relaxed" - | "atomic_xadd" - | "atomic_xadd_acq" - | "atomic_xadd_rel" - | "atomic_xadd_acqrel" - | "atomic_xadd_relaxed" - | "atomic_xsub" - | "atomic_xsub_acq" - | "atomic_xsub_rel" - | "atomic_xsub_acqrel" - | "atomic_xsub_relaxed" - => { - let &[place, rhs] = check_arg_count(args)?; - let place = this.deref_operand(place)?; - if !place.layout.ty.is_integral() { - bug!("Atomic arithmetic operations only work on integer types"); - } - let rhs = this.read_immediate(rhs)?; - let old = this.read_immediate(place.into())?; - - // Check alignment requirements. Atomics must always be aligned to their size, - // even if the type they wrap would be less aligned (e.g. AtomicU64 on 32bit must - // be 8-aligned). - let align = Align::from_bytes(place.layout.size.bytes()).unwrap(); - this.memory.check_ptr_access(place.ptr, place.layout.size, align)?; - - this.write_immediate(*old, dest)?; // old value is returned - let (op, neg) = match intrinsic_name.split('_').nth(1).unwrap() { - "or" => (mir::BinOp::BitOr, false), - "xor" => (mir::BinOp::BitXor, false), - "and" => (mir::BinOp::BitAnd, false), - "xadd" => (mir::BinOp::Add, false), - "xsub" => (mir::BinOp::Sub, false), - "nand" => (mir::BinOp::BitAnd, true), - _ => bug!(), - }; - // Atomics wrap around on overflow. - let val = this.binary_op(op, old, rhs)?; - let val = if neg { this.unary_op(mir::UnOp::Not, val)? } else { val }; - this.write_immediate(*val, place.into())?; - } // Query type information "assert_inhabited" | @@ -498,6 +458,169 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(()) } + fn atomic_load( + &mut self, args: &[OpTy<'tcx, Tag>], dest: PlaceTy<'tcx, Tag>, + atomic: AtomicReadOp + ) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + + + let &[place] = check_arg_count(args)?; + let place = this.deref_operand(place)?; + + // make sure it fits into a scalar; otherwise it cannot be atomic + let val = this.read_scalar_racy(place)?; + this.validate_atomic_load(place, atomic)?; + + // Check alignment requirements. Atomics must always be aligned to their size, + // even if the type they wrap would be less aligned (e.g. AtomicU64 on 32bit must + // be 8-aligned). + let align = Align::from_bytes(place.layout.size.bytes()).unwrap(); + this.memory.check_ptr_access(place.ptr, place.layout.size, align)?; + this.write_scalar(val, dest)?; + Ok(()) + } + + fn atomic_store(&mut self, args: &[OpTy<'tcx, Tag>], atomic: AtomicWriteOp) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + + let &[place, val] = check_arg_count(args)?; + let place = this.deref_operand(place)?; + let val = this.read_scalar(val)?; // make sure it fits into a scalar; otherwise it cannot be atomic + + // Check alignment requirements. Atomics must always be aligned to their size, + // even if the type they wrap would be less aligned (e.g. AtomicU64 on 32bit must + // be 8-aligned). + let align = Align::from_bytes(place.layout.size.bytes()).unwrap(); + this.memory.check_ptr_access(place.ptr, place.layout.size, align)?; + + // Perform atomic store + this.write_scalar_racy(val, place)?; + + this.validate_atomic_store(place, atomic)?; + Ok(()) + } + + fn compiler_fence(&mut self, args: &[OpTy<'tcx, Tag>], atomic: AtomicFenceOp) -> InterpResult<'tcx> { + let &[] = check_arg_count(args)?; + let _ = atomic; + //FIXME: compiler fences are currently ignored + Ok(()) + } + + fn atomic_fence(&mut self, args: &[OpTy<'tcx, Tag>], atomic: AtomicFenceOp) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + let &[] = check_arg_count(args)?; + this.validate_atomic_fence(atomic)?; + Ok(()) + } + + fn atomic_op( + &mut self, args: &[OpTy<'tcx, Tag>], dest: PlaceTy<'tcx, Tag>, + op: mir::BinOp, neg: bool, atomic: AtomicRWOp + ) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + + let &[place, rhs] = check_arg_count(args)?; + let place = this.deref_operand(place)?; + if !place.layout.ty.is_integral() { + bug!("Atomic arithmetic operations only work on integer types"); + } + let rhs = this.read_immediate(rhs)?; + let old = this.read_immediate_racy(place)?; + + // Check alignment requirements. Atomics must always be aligned to their size, + // even if the type they wrap would be less aligned (e.g. AtomicU64 on 32bit must + // be 8-aligned). + let align = Align::from_bytes(place.layout.size.bytes()).unwrap(); + this.memory.check_ptr_access(place.ptr, place.layout.size, align)?; + this.write_immediate(*old, dest)?; // old value is returned + + // Atomics wrap around on overflow. + let val = this.binary_op(op, old, rhs)?; + let val = if neg { this.unary_op(mir::UnOp::Not, val)? } else { val }; + this.write_immediate_racy(*val, place)?; + + this.validate_atomic_rmw(place, atomic)?; + Ok(()) + } + + fn atomic_exchange( + &mut self, args: &[OpTy<'tcx, Tag>], dest: PlaceTy<'tcx, Tag>, atomic: AtomicRWOp + ) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + + let &[place, new] = check_arg_count(args)?; + let place = this.deref_operand(place)?; + let new = this.read_scalar(new)?; + let old = this.read_scalar_racy(place)?; + + // Check alignment requirements. Atomics must always be aligned to their size, + // even if the type they wrap would be less aligned (e.g. AtomicU64 on 32bit must + // be 8-aligned). + let align = Align::from_bytes(place.layout.size.bytes()).unwrap(); + this.memory.check_ptr_access(place.ptr, place.layout.size, align)?; + + this.write_scalar(old, dest)?; // old value is returned + this.write_scalar_racy(new, place)?; + + this.validate_atomic_rmw(place, atomic)?; + Ok(()) + } + + fn atomic_compare_exchange( + &mut self, args: &[OpTy<'tcx, Tag>], dest: PlaceTy<'tcx, Tag>, + success: AtomicRWOp, fail: AtomicReadOp + ) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + + let &[place, expect_old, new] = check_arg_count(args)?; + let place = this.deref_operand(place)?; + let expect_old = this.read_immediate(expect_old)?; // read as immediate for the sake of `binary_op()` + let new = this.read_scalar(new)?; + + // Failure ordering cannot be stronger than success ordering, therefore first attempt + // to read with the failure ordering and if successfull then try again with the success + // read ordering and write in the success case. + // Read as immediate for the sake of `binary_op()` + let old = this.read_immediate_racy(place)?; + + // Check alignment requirements. Atomics must always be aligned to their size, + // even if the type they wrap would be less aligned (e.g. AtomicU64 on 32bit must + // be 8-aligned). + let align = Align::from_bytes(place.layout.size.bytes()).unwrap(); + this.memory.check_ptr_access(place.ptr, place.layout.size, align)?; + + // `binary_op` will bail if either of them is not a scalar. + let eq = this.overflowing_binary_op(mir::BinOp::Eq, old, expect_old)?.0; + let res = Immediate::ScalarPair(old.to_scalar_or_uninit(), eq.into()); + + // Return old value. + this.write_immediate(res, dest)?; + + // Update ptr depending on comparison. + // if successful, perform a full rw-atomic validation + // otherwise treat this as an atomic load with the fail ordering + if eq.to_bool()? { + this.write_scalar_racy(new, place)?; + this.validate_atomic_rmw(place, success)?; + } else { + this.validate_atomic_load(place, fail)?; + } + + Ok(()) + } + + fn atomic_compare_exchange_weak( + &mut self, args: &[OpTy<'tcx, Tag>], dest: PlaceTy<'tcx, Tag>, + success: AtomicRWOp, fail: AtomicReadOp + ) -> InterpResult<'tcx> { + + // FIXME: the weak part of this is currently not modelled, + // it is assumed to always succeed unconditionally. + self.atomic_compare_exchange(args, dest, success, fail) + } + fn float_to_int_unchecked( &self, f: F, diff --git a/src/shims/posix/sync.rs b/src/shims/posix/sync.rs index a0b5db42ed066..332e79071a0ab 100644 --- a/src/shims/posix/sync.rs +++ b/src/shims/posix/sync.rs @@ -62,7 +62,7 @@ fn mutex_get_kind<'mir, 'tcx: 'mir>( mutex_op: OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, ScalarMaybeUninit> { let offset = if ecx.pointer_size().bytes() == 8 { 16 } else { 12 }; - ecx.read_scalar_at_offset(mutex_op, offset, ecx.machine.layouts.i32) + ecx.read_scalar_at_offset_racy(mutex_op, offset, ecx.machine.layouts.i32) } fn mutex_set_kind<'mir, 'tcx: 'mir>( @@ -71,14 +71,14 @@ fn mutex_set_kind<'mir, 'tcx: 'mir>( kind: impl Into>, ) -> InterpResult<'tcx, ()> { let offset = if ecx.pointer_size().bytes() == 8 { 16 } else { 12 }; - ecx.write_scalar_at_offset(mutex_op, offset, kind, ecx.machine.layouts.i32) + ecx.write_scalar_at_offset_racy(mutex_op, offset, kind, ecx.machine.layouts.i32) } fn mutex_get_id<'mir, 'tcx: 'mir>( ecx: &MiriEvalContext<'mir, 'tcx>, mutex_op: OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, ScalarMaybeUninit> { - ecx.read_scalar_at_offset(mutex_op, 4, ecx.machine.layouts.u32) + ecx.read_scalar_at_offset_racy(mutex_op, 4, ecx.machine.layouts.u32) } fn mutex_set_id<'mir, 'tcx: 'mir>( @@ -86,7 +86,7 @@ fn mutex_set_id<'mir, 'tcx: 'mir>( mutex_op: OpTy<'tcx, Tag>, id: impl Into>, ) -> InterpResult<'tcx, ()> { - ecx.write_scalar_at_offset(mutex_op, 4, id, ecx.machine.layouts.u32) + ecx.write_scalar_at_offset_racy(mutex_op, 4, id, ecx.machine.layouts.u32) } fn mutex_get_or_create_id<'mir, 'tcx: 'mir>( @@ -116,7 +116,7 @@ fn rwlock_get_id<'mir, 'tcx: 'mir>( ecx: &MiriEvalContext<'mir, 'tcx>, rwlock_op: OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, ScalarMaybeUninit> { - ecx.read_scalar_at_offset(rwlock_op, 4, ecx.machine.layouts.u32) + ecx.read_scalar_at_offset_racy(rwlock_op, 4, ecx.machine.layouts.u32) } fn rwlock_set_id<'mir, 'tcx: 'mir>( @@ -124,7 +124,7 @@ fn rwlock_set_id<'mir, 'tcx: 'mir>( rwlock_op: OpTy<'tcx, Tag>, id: impl Into>, ) -> InterpResult<'tcx, ()> { - ecx.write_scalar_at_offset(rwlock_op, 4, id, ecx.machine.layouts.u32) + ecx.write_scalar_at_offset_racy(rwlock_op, 4, id, ecx.machine.layouts.u32) } fn rwlock_get_or_create_id<'mir, 'tcx: 'mir>( @@ -177,7 +177,7 @@ fn cond_get_id<'mir, 'tcx: 'mir>( ecx: &MiriEvalContext<'mir, 'tcx>, cond_op: OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, ScalarMaybeUninit> { - ecx.read_scalar_at_offset(cond_op, 4, ecx.machine.layouts.u32) + ecx.read_scalar_at_offset_racy(cond_op, 4, ecx.machine.layouts.u32) } fn cond_set_id<'mir, 'tcx: 'mir>( @@ -185,7 +185,7 @@ fn cond_set_id<'mir, 'tcx: 'mir>( cond_op: OpTy<'tcx, Tag>, id: impl Into>, ) -> InterpResult<'tcx, ()> { - ecx.write_scalar_at_offset(cond_op, 4, id, ecx.machine.layouts.u32) + ecx.write_scalar_at_offset_racy(cond_op, 4, id, ecx.machine.layouts.u32) } fn cond_get_or_create_id<'mir, 'tcx: 'mir>( diff --git a/src/shims/posix/thread.rs b/src/shims/posix/thread.rs index 7c9c489e6fb4c..e420457765b2d 100644 --- a/src/shims/posix/thread.rs +++ b/src/shims/posix/thread.rs @@ -19,21 +19,29 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx For example, Miri does not detect data races yet.", ); + // Create the new thread let new_thread_id = this.create_thread(); - // Also switch to new thread so that we can push the first stackframe. - let old_thread_id = this.set_active_thread(new_thread_id); + // Write the current thread-id, switch to the next thread later + // to treat this write operation as occuring on this thread index let thread_info_place = this.deref_operand(thread)?; this.write_scalar( Scalar::from_uint(new_thread_id.to_u32(), thread_info_place.layout.size), thread_info_place.into(), )?; + // Read the function argument that will be sent to the new thread + // again perform the read before the thread starts executing. let fn_ptr = this.read_scalar(start_routine)?.check_init()?; - let instance = this.memory.get_fn(fn_ptr)?.as_instance()?; - let func_arg = this.read_immediate(arg)?; + // Also switch to new thread so that we can push the first stackframe. + // after this all accesses will be treated as occuring in the new thread + let old_thread_id = this.set_active_thread(new_thread_id); + + // Perform the function pointer load in the new thread frame + let instance = this.memory.get_fn(fn_ptr)?.as_instance()?; + // Note: the returned value is currently ignored (see the FIXME in // pthread_join below) because the Rust standard library does not use // it. @@ -47,6 +55,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx StackPopCleanup::None { cleanup: true }, )?; + // Restore the old active thread frame this.set_active_thread(old_thread_id); Ok(0) diff --git a/src/sync.rs b/src/sync.rs index 0c12da8d68456..3469afdcd276e 100644 --- a/src/sync.rs +++ b/src/sync.rs @@ -61,6 +61,8 @@ struct Mutex { lock_count: usize, /// The queue of threads waiting for this mutex. queue: VecDeque, + /// Data race handle + data_race: DataRaceLockHandle } declare_id!(RwLockId); @@ -77,6 +79,10 @@ struct RwLock { writer_queue: VecDeque, /// The queue of reader threads waiting for this lock. reader_queue: VecDeque, + /// Data race handle for writers + data_race: DataRaceLockHandle, + /// Data race handle for readers + data_race_reader: DataRaceLockHandle, } declare_id!(CondvarId); @@ -94,12 +100,14 @@ struct CondvarWaiter { #[derive(Default, Debug)] struct Condvar { waiters: VecDeque, + data_race: DataRaceLockHandle, } /// The futex state. #[derive(Default, Debug)] struct Futex { waiters: VecDeque, + data_race: DataRaceLockHandle, } /// A thread waiting on a futex. @@ -205,6 +213,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx mutex.owner = Some(thread); } mutex.lock_count = mutex.lock_count.checked_add(1).unwrap(); + this.memory.extra.data_race.validate_lock_acquire(&mutex.data_race, thread); } /// Try unlocking by decreasing the lock count and returning the old lock @@ -232,6 +241,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx mutex.owner = None; // The mutex is completely unlocked. Try transfering ownership // to another thread. + this.memory.extra.data_race.validate_lock_release(&mut mutex.data_race, current_owner); this.mutex_dequeue_and_lock(id); } Some(old_lock_count) @@ -284,15 +294,18 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); assert!(!this.rwlock_is_write_locked(id), "the lock is write locked"); trace!("rwlock_reader_lock: {:?} now also held (one more time) by {:?}", id, reader); - let count = this.machine.threads.sync.rwlocks[id].readers.entry(reader).or_insert(0); + let rwlock = &mut this.machine.threads.sync.rwlocks[id]; + let count = rwlock.readers.entry(reader).or_insert(0); *count = count.checked_add(1).expect("the reader counter overflowed"); + this.memory.extra.data_race.validate_lock_acquire(&rwlock.data_race, reader); } /// Try read-unlock the lock for `reader` and potentially give the lock to a new owner. /// Returns `true` if succeeded, `false` if this `reader` did not hold the lock. fn rwlock_reader_unlock(&mut self, id: RwLockId, reader: ThreadId) -> bool { let this = self.eval_context_mut(); - match this.machine.threads.sync.rwlocks[id].readers.entry(reader) { + let rwlock = &mut this.machine.threads.sync.rwlocks[id]; + match rwlock.readers.entry(reader) { Entry::Occupied(mut entry) => { let count = entry.get_mut(); assert!(*count > 0, "rwlock locked with count == 0"); @@ -306,8 +319,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } Entry::Vacant(_) => return false, // we did not even own this lock } + this.memory.extra.data_race.validate_lock_release_shared(&mut rwlock.data_race_reader, reader); + // The thread was a reader. If the lock is not held any more, give it to a writer. if this.rwlock_is_locked(id).not() { + + // All the readers are finished, so set the writer data-race handle to the value + // of the union of all reader data race handles, since the set of readers + // happen-before the writers + let rwlock = &mut this.machine.threads.sync.rwlocks[id]; + rwlock.data_race.set_values(&rwlock.data_race_reader); this.rwlock_dequeue_and_lock_writer(id); } true @@ -332,7 +353,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); assert!(!this.rwlock_is_locked(id), "the rwlock is already locked"); trace!("rwlock_writer_lock: {:?} now held by {:?}", id, writer); - this.machine.threads.sync.rwlocks[id].writer = Some(writer); + let rwlock = &mut this.machine.threads.sync.rwlocks[id]; + rwlock.writer = Some(writer); + this.memory.extra.data_race.validate_lock_acquire(&rwlock.data_race, writer); } #[inline] @@ -347,6 +370,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } rwlock.writer = None; trace!("rwlock_writer_unlock: {:?} unlocked by {:?}", id, expected_writer); + // Release memory to both reader and writer vector clocks + // since this writer happens-before both the union of readers once they are finished + // and the next writer + this.memory.extra.data_race.validate_lock_release(&mut rwlock.data_race, current_writer); + this.memory.extra.data_race.validate_lock_release(&mut rwlock.data_race_reader, current_writer); // The thread was a writer. // // We are prioritizing writers here against the readers. As a @@ -405,10 +433,18 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// variable. fn condvar_signal(&mut self, id: CondvarId) -> Option<(ThreadId, MutexId)> { let this = self.eval_context_mut(); - this.machine.threads.sync.condvars[id] - .waiters + let current_thread = this.get_active_thread(); + let condvar = &mut this.machine.threads.sync.condvars[id]; + let data_race = &mut this.memory.extra.data_race; + + // Each condvar signal happens-before the end of the condvar wake + data_race.validate_lock_release(&mut condvar.data_race, current_thread); + condvar.waiters .pop_front() - .map(|waiter| (waiter.thread, waiter.mutex)) + .map(|waiter| { + data_race.validate_lock_acquire(&mut condvar.data_race, waiter.thread); + (waiter.thread, waiter.mutex) + }) } #[inline] @@ -420,15 +456,25 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn futex_wait(&mut self, addr: Pointer, thread: ThreadId) { let this = self.eval_context_mut(); - let waiters = &mut this.machine.threads.sync.futexes.entry(addr.erase_tag()).or_default().waiters; + let futex = &mut this.machine.threads.sync.futexes.entry(addr.erase_tag()).or_default(); + let waiters = &mut futex.waiters; assert!(waiters.iter().all(|waiter| waiter.thread != thread), "thread is already waiting"); waiters.push_back(FutexWaiter { thread }); } fn futex_wake(&mut self, addr: Pointer) -> Option { let this = self.eval_context_mut(); - let waiters = &mut this.machine.threads.sync.futexes.get_mut(&addr.erase_tag())?.waiters; - waiters.pop_front().map(|waiter| waiter.thread) + let current_thread = this.get_active_thread(); + let futex = &mut this.machine.threads.sync.futexes.get_mut(&addr.erase_tag())?; + let data_race = &mut this.memory.extra.data_race; + + // Each futex-wake happens-before the end of the futex wait + data_race.validate_lock_release(&mut futex.data_race, current_thread); + let res = futex.waiters.pop_front().map(|waiter| { + data_race.validate_lock_acquire(&futex.data_race, waiter.thread); + waiter.thread + }); + res } fn futex_remove_waiter(&mut self, addr: Pointer, thread: ThreadId) { diff --git a/src/thread.rs b/src/thread.rs index eeaee7dc44d5d..08aeaa4fd095f 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -327,7 +327,7 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { } /// Mark that the active thread tries to join the thread with `joined_thread_id`. - fn join_thread(&mut self, joined_thread_id: ThreadId) -> InterpResult<'tcx> { + fn join_thread(&mut self, joined_thread_id: ThreadId, data_race: &data_race::GlobalState) -> InterpResult<'tcx> { if self.threads[joined_thread_id].join_status != ThreadJoinStatus::Joinable { throw_ub_format!("trying to join a detached or already joined thread"); } @@ -351,6 +351,9 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { self.active_thread, joined_thread_id ); + }else{ + // The thread has already terminated - mark join happens-before + data_race.thread_joined(self.active_thread, joined_thread_id); } Ok(()) } @@ -425,7 +428,7 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { /// Wakes up threads joining on the active one and deallocates thread-local statics. /// The `AllocId` that can now be freed is returned. - fn thread_terminated(&mut self) -> Vec { + fn thread_terminated(&mut self, data_race: &data_race::GlobalState) -> Vec { let mut free_tls_statics = Vec::new(); { let mut thread_local_statics = self.thread_local_alloc_ids.borrow_mut(); @@ -443,6 +446,8 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { // Check if we need to unblock any threads. for (i, thread) in self.threads.iter_enumerated_mut() { if thread.state == ThreadState::BlockedOnJoin(self.active_thread) { + // The thread has terminated, mark happens-before edge to joining thread + data_race.thread_joined(i, self.active_thread); trace!("unblocking {:?} because {:?} terminated", i, self.active_thread); thread.state = ThreadState::Enabled; } @@ -456,7 +461,7 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { /// used in stateless model checkers such as Loom: run the active thread as /// long as we can and switch only when we have to (the active thread was /// blocked, terminated, or has explicitly asked to be preempted). - fn schedule(&mut self) -> InterpResult<'tcx, SchedulingAction> { + fn schedule(&mut self, data_race: &data_race::GlobalState) -> InterpResult<'tcx, SchedulingAction> { // Check whether the thread has **just** terminated (`check_terminated` // checks whether the thread has popped all its stack and if yes, sets // the thread state to terminated). @@ -501,6 +506,7 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { if thread.state == ThreadState::Enabled { if !self.yield_active_thread || id != self.active_thread { self.active_thread = id; + data_race.thread_set_active(self.active_thread); break; } } @@ -554,7 +560,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx #[inline] fn create_thread(&mut self) -> ThreadId { let this = self.eval_context_mut(); - this.machine.threads.create_thread() + let id = this.machine.threads.create_thread(); + this.memory.extra.data_race.thread_created(id); + id } #[inline] @@ -566,12 +574,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx #[inline] fn join_thread(&mut self, joined_thread_id: ThreadId) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - this.machine.threads.join_thread(joined_thread_id) + let data_race = &*this.memory.extra.data_race; + this.machine.threads.join_thread(joined_thread_id, data_race)?; + Ok(()) } #[inline] fn set_active_thread(&mut self, thread_id: ThreadId) -> ThreadId { let this = self.eval_context_mut(); + this.memory.extra.data_race.thread_set_active(thread_id); this.machine.threads.set_active_thread_id(thread_id) } @@ -626,6 +637,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx #[inline] fn set_active_thread_name(&mut self, new_thread_name: Vec) { let this = self.eval_context_mut(); + if let Ok(string) = String::from_utf8(new_thread_name.clone()) { + this.memory.extra.data_race.thread_set_name(string); + } this.machine.threads.set_thread_name(new_thread_name); } @@ -695,7 +709,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx #[inline] fn schedule(&mut self) -> InterpResult<'tcx, SchedulingAction> { let this = self.eval_context_mut(); - this.machine.threads.schedule() + let data_race = &*this.memory.extra.data_race; + this.machine.threads.schedule(data_race) } /// Handles thread termination of the active thread: wakes up threads joining on this one, @@ -705,7 +720,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx #[inline] fn thread_terminated(&mut self) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - for alloc_id in this.machine.threads.thread_terminated() { + let data_race = &*this.memory.extra.data_race; + for alloc_id in this.machine.threads.thread_terminated(data_race) { let ptr = this.memory.global_base_pointer(alloc_id.into())?; this.memory.deallocate(ptr, None, MiriMemoryKind::Tls.into())?; } From ed32b260f9243b1ebb08c033acd3d5079407a309 Mon Sep 17 00:00:00 2001 From: JCTyBlaidd Date: Mon, 2 Nov 2020 01:46:42 +0000 Subject: [PATCH 2427/3747] Add tests, and fix bug in atomic RMW relaxed stores --- src/data_race.rs | 5 +- src/shims/posix/thread.rs | 3 +- .../compile-fail/data_race/read_write_race.rs | 26 ++++ .../data_race/relax_acquire_race.rs | 42 +++++++ .../data_race/release_seq_race.rs | 46 +++++++ tests/compile-fail/data_race/rmw_race.rs | 43 +++++++ .../data_race/write_write_race.rs | 26 ++++ tests/run-pass/concurrency/data_race.rs | 119 ++++++++++++++++++ tests/run-pass/concurrency/data_race.stderr | 2 + tests/run-pass/concurrency/linux-futex.stderr | 2 +- tests/run-pass/concurrency/simple.stderr | 2 +- tests/run-pass/concurrency/sync.stderr | 2 +- .../run-pass/concurrency/thread_locals.stderr | 2 +- .../run-pass/concurrency/tls_lib_drop.stderr | 2 +- tests/run-pass/libc.stderr | 2 +- tests/run-pass/panic/concurrent-panic.stderr | 2 +- 16 files changed, 315 insertions(+), 11 deletions(-) create mode 100644 tests/compile-fail/data_race/read_write_race.rs create mode 100644 tests/compile-fail/data_race/relax_acquire_race.rs create mode 100644 tests/compile-fail/data_race/release_seq_race.rs create mode 100644 tests/compile-fail/data_race/rmw_race.rs create mode 100644 tests/compile-fail/data_race/write_write_race.rs create mode 100644 tests/run-pass/concurrency/data_race.rs create mode 100644 tests/run-pass/concurrency/data_race.stderr diff --git a/src/data_race.rs b/src/data_race.rs index 59526063945a9..ac928071bef18 100644 --- a/src/data_race.rs +++ b/src/data_race.rs @@ -404,8 +404,9 @@ impl AtomicReleaseSequences { fn clear_and_retain(&mut self, thread: ThreadId) { match self { Self::ReleaseOneOrEmpty(id, rel_clock) => { - // Keep or forget depending on id - if *id == Some(thread) { + // If the id is the same, then reatin the value + // otherwise delete and clear the release vector clock + if *id != Some(thread) { *id = None; rel_clock.set_zero_vector(); } diff --git a/src/shims/posix/thread.rs b/src/shims/posix/thread.rs index e420457765b2d..e823a7d88d6a9 100644 --- a/src/shims/posix/thread.rs +++ b/src/shims/posix/thread.rs @@ -15,8 +15,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); this.tcx.sess.warn( - "thread support is experimental. \ - For example, Miri does not detect data races yet.", + "thread support is experimental.", ); // Create the new thread diff --git a/tests/compile-fail/data_race/read_write_race.rs b/tests/compile-fail/data_race/read_write_race.rs new file mode 100644 index 0000000000000..ece99b4a87a11 --- /dev/null +++ b/tests/compile-fail/data_race/read_write_race.rs @@ -0,0 +1,26 @@ + +use std::thread::spawn; + +#[derive(Copy, Clone)] +struct EvilSend(pub T); + +unsafe impl Send for EvilSend {} +unsafe impl Sync for EvilSend {} + +pub fn main() { + let mut a = 0u32; + let b = &mut a as *mut u32; + let c = EvilSend(b); + unsafe { + let j1 = spawn(move || { + *c.0 + }); + + let j2 = spawn(move || { + *c.0 = 64; //~ ERROR Data race + }); + + j1.join().unwrap(); + j2.join().unwrap(); + } +} \ No newline at end of file diff --git a/tests/compile-fail/data_race/relax_acquire_race.rs b/tests/compile-fail/data_race/relax_acquire_race.rs new file mode 100644 index 0000000000000..cc96083546a29 --- /dev/null +++ b/tests/compile-fail/data_race/relax_acquire_race.rs @@ -0,0 +1,42 @@ + +use std::thread::spawn; +use std::sync::atomic::{AtomicUsize, Ordering}; + +#[derive(Copy, Clone)] +struct EvilSend(pub T); + +unsafe impl Send for EvilSend {} +unsafe impl Sync for EvilSend {} + +static SYNC: AtomicUsize = AtomicUsize::new(0); + +pub fn main() { + let mut a = 0u32; + let b = &mut a as *mut u32; + let c = EvilSend(b); + + unsafe { + let j1 = spawn(move || { + *c.0 = 1; + SYNC.store(1, Ordering::Release); + }); + + let j2 = spawn(move || { + if SYNC.load(Ordering::Acquire) == 1 { + SYNC.store(2, Ordering::Relaxed); + } + }); + + let j3 = spawn(move || { + if SYNC.load(Ordering::Acquire) == 2 { + *c.0 //~ ERROR Data race + }else{ + 0 + } + }); + + j1.join().unwrap(); + j2.join().unwrap(); + j3.join().unwrap(); + } +} \ No newline at end of file diff --git a/tests/compile-fail/data_race/release_seq_race.rs b/tests/compile-fail/data_race/release_seq_race.rs new file mode 100644 index 0000000000000..8b3ffbcd9dd88 --- /dev/null +++ b/tests/compile-fail/data_race/release_seq_race.rs @@ -0,0 +1,46 @@ +// compile-flags: -Zmiri-disable-isolation + +use std::thread::{spawn, sleep}; +use std::sync::atomic::{AtomicUsize, Ordering}; +use std::time::Duration; + +#[derive(Copy, Clone)] +struct EvilSend(pub T); + +unsafe impl Send for EvilSend {} +unsafe impl Sync for EvilSend {} + +static SYNC: AtomicUsize = AtomicUsize::new(0); + +pub fn main() { + let mut a = 0u32; + let b = &mut a as *mut u32; + let c = EvilSend(b); + + unsafe { + let j1 = spawn(move || { + *c.0 = 1; + SYNC.store(1, Ordering::Release); + sleep(Duration::from_millis(100)); + SYNC.store(3, Ordering::Relaxed); + }); + + let j2 = spawn(move || { + // Blocks the acquire-release sequence + SYNC.store(2, Ordering::Relaxed); + }); + + let j3 = spawn(move || { + sleep(Duration::from_millis(1000)); + if SYNC.load(Ordering::Acquire) == 3 { + *c.0 //~ ERROR Data race + }else{ + 0 + } + }); + + j1.join().unwrap(); + j2.join().unwrap(); + j3.join().unwrap(); + } +} \ No newline at end of file diff --git a/tests/compile-fail/data_race/rmw_race.rs b/tests/compile-fail/data_race/rmw_race.rs new file mode 100644 index 0000000000000..9c31c79ebf131 --- /dev/null +++ b/tests/compile-fail/data_race/rmw_race.rs @@ -0,0 +1,43 @@ + +use std::thread::spawn; +use std::sync::atomic::{AtomicUsize, Ordering}; + +#[derive(Copy, Clone)] +struct EvilSend(pub T); + +unsafe impl Send for EvilSend {} +unsafe impl Sync for EvilSend {} + +static SYNC: AtomicUsize = AtomicUsize::new(0); + +pub fn main() { + let mut a = 0u32; + let b = &mut a as *mut u32; + let c = EvilSend(b); + + unsafe { + let j1 = spawn(move || { + *c.0 = 1; + SYNC.store(1, Ordering::Release); + }); + + let j2 = spawn(move || { + if SYNC.swap(2, Ordering::Relaxed) == 1 { + // Blocks the acquire-release sequence + SYNC.store(3, Ordering::Relaxed); + } + }); + + let j3 = spawn(move || { + if SYNC.load(Ordering::Acquire) == 3 { + *c.0 //~ ERROR Data race + }else{ + 0 + } + }); + + j1.join().unwrap(); + j2.join().unwrap(); + j3.join().unwrap(); + } +} \ No newline at end of file diff --git a/tests/compile-fail/data_race/write_write_race.rs b/tests/compile-fail/data_race/write_write_race.rs new file mode 100644 index 0000000000000..22caf5f0f7f34 --- /dev/null +++ b/tests/compile-fail/data_race/write_write_race.rs @@ -0,0 +1,26 @@ + +use std::thread::spawn; + +#[derive(Copy, Clone)] +struct EvilSend(pub T); + +unsafe impl Send for EvilSend {} +unsafe impl Sync for EvilSend {} + +pub fn main() { + let mut a = 0u32; + let b = &mut a as *mut u32; + let c = EvilSend(b); + unsafe { + let j1 = spawn(move || { + *c.0 = 32; + }); + + let j2 = spawn(move || { + *c.0 = 64; //~ ERROR Data race + }); + + j1.join().unwrap(); + j2.join().unwrap(); + } +} \ No newline at end of file diff --git a/tests/run-pass/concurrency/data_race.rs b/tests/run-pass/concurrency/data_race.rs new file mode 100644 index 0000000000000..bc4a4e30e8915 --- /dev/null +++ b/tests/run-pass/concurrency/data_race.rs @@ -0,0 +1,119 @@ +use std::sync::atomic::{AtomicUsize, fence, Ordering}; +use std::thread::spawn; + +#[derive(Copy, Clone)] +struct EvilSend(pub T); + +unsafe impl Send for EvilSend {} +unsafe impl Sync for EvilSend {} + +static SYNC: AtomicUsize = AtomicUsize::new(0); + +fn test_fence_sync() { + let mut var = 0u32; + let ptr = &mut var as *mut u32; + let evil_ptr = EvilSend(ptr); + + + let j1 = spawn(move || { + unsafe { *evil_ptr.0 = 1; } + fence(Ordering::Release); + SYNC.store(1, Ordering::Relaxed) + }); + + let j2 = spawn(move || { + if SYNC.load(Ordering::Relaxed) == 1 { + fence(Ordering::Acquire); + unsafe { *evil_ptr.0 } + }else{ + 0 + } + }); + + j1.join().unwrap(); + j2.join().unwrap(); +} + + +fn test_multiple_reads() { + let mut var = 42u32; + let ptr = &mut var as *mut u32; + let evil_ptr = EvilSend(ptr); + + let j1 = spawn(move || unsafe {*evil_ptr.0}); + let j2 = spawn(move || unsafe {*evil_ptr.0}); + let j3 = spawn(move || unsafe {*evil_ptr.0}); + let j4 = spawn(move || unsafe {*evil_ptr.0}); + + assert_eq!(j1.join().unwrap(), 42); + assert_eq!(j2.join().unwrap(), 42); + assert_eq!(j3.join().unwrap(), 42); + assert_eq!(j4.join().unwrap(), 42); + + var = 10; + assert_eq!(var, 10); +} + +pub fn test_rmw_no_block() { + let mut a = 0u32; + let b = &mut a as *mut u32; + let c = EvilSend(b); + + unsafe { + let j1 = spawn(move || { + *c.0 = 1; + SYNC.store(1, Ordering::Release); + }); + + let j2 = spawn(move || { + if SYNC.swap(2, Ordering::Relaxed) == 1 { + //No op, blocking store removed + } + }); + + let j3 = spawn(move || { + if SYNC.load(Ordering::Acquire) == 2 { + *c.0 + }else{ + 0 + } + }); + + j1.join().unwrap(); + j2.join().unwrap(); + let v = j3.join().unwrap(); + assert!(v == 1 || v == 2); + } +} + +pub fn test_release_no_block() { + let mut a = 0u32; + let b = &mut a as *mut u32; + let c = EvilSend(b); + + unsafe { + let j1 = spawn(move || { + *c.0 = 1; + SYNC.store(1, Ordering::Release); + SYNC.store(3, Ordering::Relaxed); + }); + + let j2 = spawn(move || { + if SYNC.load(Ordering::Acquire) == 3 { + *c.0 + }else{ + 0 + } + }); + + j1.join().unwrap(); + assert_eq!(j2.join().unwrap(),1); + } +} + +pub fn main() { + test_fence_sync(); + test_multiple_reads(); + test_rmw_no_block(); + test_release_no_block(); +} \ No newline at end of file diff --git a/tests/run-pass/concurrency/data_race.stderr b/tests/run-pass/concurrency/data_race.stderr new file mode 100644 index 0000000000000..b01247aea4e0e --- /dev/null +++ b/tests/run-pass/concurrency/data_race.stderr @@ -0,0 +1,2 @@ +warning: thread support is experimental. + diff --git a/tests/run-pass/concurrency/linux-futex.stderr b/tests/run-pass/concurrency/linux-futex.stderr index 2dbfb7721d368..b01247aea4e0e 100644 --- a/tests/run-pass/concurrency/linux-futex.stderr +++ b/tests/run-pass/concurrency/linux-futex.stderr @@ -1,2 +1,2 @@ -warning: thread support is experimental. For example, Miri does not detect data races yet. +warning: thread support is experimental. diff --git a/tests/run-pass/concurrency/simple.stderr b/tests/run-pass/concurrency/simple.stderr index 7060411278e6e..f1550dd25aa0c 100644 --- a/tests/run-pass/concurrency/simple.stderr +++ b/tests/run-pass/concurrency/simple.stderr @@ -1,4 +1,4 @@ -warning: thread support is experimental. For example, Miri does not detect data races yet. +warning: thread support is experimental. thread '' panicked at 'Hello!', $DIR/simple.rs:54:9 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace diff --git a/tests/run-pass/concurrency/sync.stderr b/tests/run-pass/concurrency/sync.stderr index 2dbfb7721d368..b01247aea4e0e 100644 --- a/tests/run-pass/concurrency/sync.stderr +++ b/tests/run-pass/concurrency/sync.stderr @@ -1,2 +1,2 @@ -warning: thread support is experimental. For example, Miri does not detect data races yet. +warning: thread support is experimental. diff --git a/tests/run-pass/concurrency/thread_locals.stderr b/tests/run-pass/concurrency/thread_locals.stderr index 2dbfb7721d368..b01247aea4e0e 100644 --- a/tests/run-pass/concurrency/thread_locals.stderr +++ b/tests/run-pass/concurrency/thread_locals.stderr @@ -1,2 +1,2 @@ -warning: thread support is experimental. For example, Miri does not detect data races yet. +warning: thread support is experimental. diff --git a/tests/run-pass/concurrency/tls_lib_drop.stderr b/tests/run-pass/concurrency/tls_lib_drop.stderr index 2dbfb7721d368..b01247aea4e0e 100644 --- a/tests/run-pass/concurrency/tls_lib_drop.stderr +++ b/tests/run-pass/concurrency/tls_lib_drop.stderr @@ -1,2 +1,2 @@ -warning: thread support is experimental. For example, Miri does not detect data races yet. +warning: thread support is experimental. diff --git a/tests/run-pass/libc.stderr b/tests/run-pass/libc.stderr index 2dbfb7721d368..b01247aea4e0e 100644 --- a/tests/run-pass/libc.stderr +++ b/tests/run-pass/libc.stderr @@ -1,2 +1,2 @@ -warning: thread support is experimental. For example, Miri does not detect data races yet. +warning: thread support is experimental. diff --git a/tests/run-pass/panic/concurrent-panic.stderr b/tests/run-pass/panic/concurrent-panic.stderr index eb5b5f59a0cb1..ca6031e57b402 100644 --- a/tests/run-pass/panic/concurrent-panic.stderr +++ b/tests/run-pass/panic/concurrent-panic.stderr @@ -1,4 +1,4 @@ -warning: thread support is experimental. For example, Miri does not detect data races yet. +warning: thread support is experimental. Thread 1 starting, will block on mutex Thread 1 reported it has started From cae4302003f32e808b822b1b7b351894548c6c0e Mon Sep 17 00:00:00 2001 From: JCTyBlaidd Date: Mon, 2 Nov 2020 03:06:30 +0000 Subject: [PATCH 2428/3747] Fix & rebase --- src/data_race.rs | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/data_race.rs b/src/data_race.rs index ac928071bef18..35898f1d937f8 100644 --- a/src/data_race.rs +++ b/src/data_race.rs @@ -176,19 +176,19 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let mut current_state = alloc.global.current_thread_state_mut(); if atomic == AtomicReadOp::Relaxed { // Perform relaxed atomic load - for range in alloc.alloc_ranges.get_mut().iter_mut(offset, size) { + for (_,range) in alloc.alloc_ranges.get_mut().iter_mut(offset, size) { range.load_relaxed(&mut *current_state); } }else{ // Perform acquire(or seq-cst) atomic load - for range in alloc.alloc_ranges.get_mut().iter_mut(offset, size) { + for (_,range) in alloc.alloc_ranges.get_mut().iter_mut(offset, size) { range.acquire(&mut *current_state); } } // Log changes to atomic memory if log::log_enabled!(log::Level::Trace) { - for range in alloc.alloc_ranges.get_mut().iter(offset, size) { + for (_,range) in alloc.alloc_ranges.get_mut().iter(offset, size) { log::trace!( " updated atomic memory({:?}, offset={}, size={}) to {:#?}", place.ptr.assert_ptr().alloc_id, offset.bytes(), size.bytes(), @@ -227,19 +227,19 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if atomic == AtomicWriteOp::Relaxed { // Perform relaxed atomic store - for range in alloc.alloc_ranges.get_mut().iter_mut(offset, size) { + for (_,range) in alloc.alloc_ranges.get_mut().iter_mut(offset, size) { range.store_relaxed(&mut *current_state, current_thread); } }else{ // Perform release(or seq-cst) atomic store - for range in alloc.alloc_ranges.get_mut().iter_mut(offset, size) { + for (_,range) in alloc.alloc_ranges.get_mut().iter_mut(offset, size) { range.release(&mut *current_state, current_thread); } } // Log changes to atomic memory if log::log_enabled!(log::Level::Trace) { - for range in alloc.alloc_ranges.get_mut().iter(offset, size) { + for (_,range) in alloc.alloc_ranges.get_mut().iter(offset, size) { log::trace!( " updated atomic memory({:?}, offset={}, size={}) to {:#?}", place.ptr.assert_ptr().alloc_id, offset.bytes(), size.bytes(), @@ -279,7 +279,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let acquire = matches!(atomic, Acquire | AcqRel | SeqCst); let release = matches!(atomic, Release | AcqRel | SeqCst); - for range in alloc.alloc_ranges.get_mut().iter_mut(offset, size) { + for (_,range) in alloc.alloc_ranges.get_mut().iter_mut(offset, size) { //FIXME: this is probably still slightly wrong due to the quirks // in the c++11 memory model if acquire { @@ -298,7 +298,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Log changes to atomic memory if log::log_enabled!(log::Level::Trace) { - for range in alloc.alloc_ranges.get_mut().iter(offset, size) { + for (_,range) in alloc.alloc_ranges.get_mut().iter(offset, size) { log::trace!( " updated atomic memory({:?}, offset={}, size={}) to {:#?}", place.ptr.assert_ptr().alloc_id, offset.bytes(), size.bytes(), @@ -733,7 +733,7 @@ impl VClockAlloc { // The alloc-ranges are not split, however changes are not going to be made // to the ranges being tested, so this is ok let mut alloc_ranges = self.alloc_ranges.borrow_mut(); - for range in alloc_ranges.iter_mut(pointer.offset, len) { + for (_,range) in alloc_ranges.iter_mut(pointer.offset, len) { if range.read_race_detect(&*current_state, current_thread) { // Report data-race return Self::report_data_race( @@ -754,7 +754,7 @@ impl VClockAlloc { if self.global.multi_threaded.get() { let current_thread = self.global.current_thread(); let current_state = self.global.current_thread_state(); - for range in self.alloc_ranges.get_mut().iter_mut(pointer.offset, len) { + for (_,range) in self.alloc_ranges.get_mut().iter_mut(pointer.offset, len) { if range.write_race_detect(&*current_state, current_thread) { // Report data-race return Self::report_data_race( @@ -775,7 +775,7 @@ impl VClockAlloc { if self.global.multi_threaded.get() { let current_thread = self.global.current_thread(); let current_state = self.global.current_thread_state(); - for range in self.alloc_ranges.get_mut().iter_mut(pointer.offset, len) { + for (_,range) in self.alloc_ranges.get_mut().iter_mut(pointer.offset, len) { if range.write_race_detect(&*current_state, current_thread) { // Report data-race return Self::report_data_race( From 2e75de5ac9c2805d25f6b5452d8397f99ee5e342 Mon Sep 17 00:00:00 2001 From: JCTyBlaidd Date: Mon, 2 Nov 2020 12:40:12 +0000 Subject: [PATCH 2429/3747] Mark all new tests as disabled on windows --- tests/compile-fail/data_race/read_write_race.rs | 1 + tests/compile-fail/data_race/relax_acquire_race.rs | 1 + tests/compile-fail/data_race/release_seq_race.rs | 1 + tests/compile-fail/data_race/rmw_race.rs | 1 + tests/compile-fail/data_race/write_write_race.rs | 1 + tests/run-pass/concurrency/data_race.rs | 3 +++ 6 files changed, 8 insertions(+) diff --git a/tests/compile-fail/data_race/read_write_race.rs b/tests/compile-fail/data_race/read_write_race.rs index ece99b4a87a11..6a5f3f7d20769 100644 --- a/tests/compile-fail/data_race/read_write_race.rs +++ b/tests/compile-fail/data_race/read_write_race.rs @@ -1,3 +1,4 @@ +// ignore-windows: Concurrency on Windows is not supported yet. use std::thread::spawn; diff --git a/tests/compile-fail/data_race/relax_acquire_race.rs b/tests/compile-fail/data_race/relax_acquire_race.rs index cc96083546a29..753d30b8f5708 100644 --- a/tests/compile-fail/data_race/relax_acquire_race.rs +++ b/tests/compile-fail/data_race/relax_acquire_race.rs @@ -1,3 +1,4 @@ +// ignore-windows: Concurrency on Windows is not supported yet. use std::thread::spawn; use std::sync::atomic::{AtomicUsize, Ordering}; diff --git a/tests/compile-fail/data_race/release_seq_race.rs b/tests/compile-fail/data_race/release_seq_race.rs index 8b3ffbcd9dd88..44360f70d5d66 100644 --- a/tests/compile-fail/data_race/release_seq_race.rs +++ b/tests/compile-fail/data_race/release_seq_race.rs @@ -1,3 +1,4 @@ +// ignore-windows: Concurrency on Windows is not supported yet. // compile-flags: -Zmiri-disable-isolation use std::thread::{spawn, sleep}; diff --git a/tests/compile-fail/data_race/rmw_race.rs b/tests/compile-fail/data_race/rmw_race.rs index 9c31c79ebf131..9dfa2751d587e 100644 --- a/tests/compile-fail/data_race/rmw_race.rs +++ b/tests/compile-fail/data_race/rmw_race.rs @@ -1,3 +1,4 @@ +// ignore-windows: Concurrency on Windows is not supported yet. use std::thread::spawn; use std::sync::atomic::{AtomicUsize, Ordering}; diff --git a/tests/compile-fail/data_race/write_write_race.rs b/tests/compile-fail/data_race/write_write_race.rs index 22caf5f0f7f34..0c46e5c925157 100644 --- a/tests/compile-fail/data_race/write_write_race.rs +++ b/tests/compile-fail/data_race/write_write_race.rs @@ -1,3 +1,4 @@ +// ignore-windows: Concurrency on Windows is not supported yet. use std::thread::spawn; diff --git a/tests/run-pass/concurrency/data_race.rs b/tests/run-pass/concurrency/data_race.rs index bc4a4e30e8915..40a7c162a0c18 100644 --- a/tests/run-pass/concurrency/data_race.rs +++ b/tests/run-pass/concurrency/data_race.rs @@ -1,3 +1,6 @@ +// ignore-windows: Concurrency on Windows is not supported yet. + + use std::sync::atomic::{AtomicUsize, fence, Ordering}; use std::thread::spawn; From fe2e857cc3744a69b1d1dc2fe77f94da10978091 Mon Sep 17 00:00:00 2001 From: JCTyBlaidd Date: Mon, 2 Nov 2020 13:08:09 +0000 Subject: [PATCH 2430/3747] Add newlines at end of file + use replace. add dangling thread variant of one of the benchmarks --- .../mse_and_dangling_thread/Cargo.toml | 7 +++++ .../mse_and_dangling_thread/src/main.rs | 30 +++++++++++++++++++ src/data_race.rs | 10 +++---- .../compile-fail/data_race/read_write_race.rs | 2 +- .../data_race/relax_acquire_race.rs | 2 +- .../data_race/release_seq_race.rs | 2 +- tests/compile-fail/data_race/rmw_race.rs | 2 +- .../data_race/write_write_race.rs | 2 +- tests/run-pass/concurrency/data_race.rs | 2 +- 9 files changed, 47 insertions(+), 12 deletions(-) create mode 100644 bench-cargo-miri/mse_and_dangling_thread/Cargo.toml create mode 100644 bench-cargo-miri/mse_and_dangling_thread/src/main.rs diff --git a/bench-cargo-miri/mse_and_dangling_thread/Cargo.toml b/bench-cargo-miri/mse_and_dangling_thread/Cargo.toml new file mode 100644 index 0000000000000..7b4c2dc758faa --- /dev/null +++ b/bench-cargo-miri/mse_and_dangling_thread/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "mse" +version = "0.1.0" +authors = ["Ralf Jung "] +edition = "2018" + +[dependencies] diff --git a/bench-cargo-miri/mse_and_dangling_thread/src/main.rs b/bench-cargo-miri/mse_and_dangling_thread/src/main.rs new file mode 100644 index 0000000000000..008e9c80eff1a --- /dev/null +++ b/bench-cargo-miri/mse_and_dangling_thread/src/main.rs @@ -0,0 +1,30 @@ +static EXPECTED: &[u8] = &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 0, 0, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 1, 0, 255, 255, 1, 0, 255, 255, 1, 0, 255, 255, 1, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 254, 255, 0, 0, 254, 255, 0, 0, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 255, 255, 1, 0, 255, 255, 1, 0, 0, 0, 1, 0, 255, 255, 2, 0, 255, 255, 2, 0, 255, 255, 2, 0, 255, 255, 2, 0, 255, 255, 2, 0, 255, 255, 1, 0, 255, 255, 1, 0, 255, 255, 0, 0, 254, 255, 0, 0, 254, 255, 0, 0, 254, 255, 255, 255, 254, 255, 254, 255, 254, 255, 253, 255, 253, 255, 253, 255, 253, 255, 252, 255, 254, 255, 251, 255, 254, 255, 251, 255, 254, 255, 252, 255, 255, 255, 252, 255, 0, 0, 252, 255, 0, 0, 252, 255, 1, 0, 252, 255, 1, 0, 252, 255, 2, 0, 252, 255, 2, 0, 252, 255, 2, 0, 252, 255, 2, 0, 252, 255, 2, 0, 253, 255, 1, 0, 252, 255, 0, 0, 252, 255, 255, 255, 251, 255, 0, 0, 251, 255, 0, 0, 251, 255, 0, 0, 252, 255, 2, 0, 252, 255, 3, 0, 252, 255, 4, 0, 253, 255, 5, 0, 254, 255, 5, 0, 253, 255, 6, 0, 253, 255, 6, 0, 253, 255, 5, 0, 253, 255, 5, 0, 254, 255, 4, 0, 254, 255, 3, 0, 251, 255, 0, 0, 250, 255, 255, 255, 253, 255, 254, 255, 252, 255, 252, 255, 247, 255, 251, 255, 247, 255, 252, 255, 252, 255, 254, 255, 252, 255, 254, 255, 252, 255, 255, 255, 254, 255, 1, 0, 1, 0, 1, 0, 4, 0, 2, 0, 8, 0, 2, 0, 12, 0, 1, 0, 13, 0, 0, 0, 12, 0, 0, 0, 11, 0, 255, 255, 8, 0, 254, 255, 7, 0, 0, 0, 7, 0, 253, 255, 11, 0, 248, 255, 15, 0, 247, 255, 17, 0, 250, 255, 17, 0, 251, 255, 13, 0, 253, 255, 7, 0, 255, 255, 3, 0, 255, 255, 254, 255, 255, 255, 252, 255, 255, 255, 252, 255, 254, 255, 250, 255, 255, 255, 242, 255, 254, 255, 239, 255, 252, 255, 248, 255, 255, 255, 249, 255, 5, 0, 239, 255, 7, 0, 238, 255, 10, 0, 249, 255, 18, 0, 254, 255, 25, 0, 253, 255, 27, 0, 0, 0, 31, 0, 4, 0, 34, 0, 4, 0, 34, 0, 8, 0, 36, 0, 8, 0, 37, 0, 2, 0, 36, 0, 4, 0, 34, 0, 8, 0, 28, 0, 3, 0, 15, 0, 255, 255, 11, 0, 0, 0, 12, 0, 251, 255, 8, 0, 252, 255, 10, 0, 0, 0, 23, 0, 252, 255, 31, 0, 248, 255, 30, 0, 254, 255, 30, 0, 255, 255, 26, 0, 250, 255, 22, 0, 250, 255, 20, 0, 244, 255, 15, 0, 237, 255, 10, 0, 246, 255, 13, 0, 242, 255, 6, 0, 213, 255, 243, 255, 213, 255, 240, 255, 247, 255, 244, 255, 246, 255, 227, 255, 214, 255, 216, 255, 219, 255, 228, 255, 251, 255, 235, 255, 1, 0, 232, 255, 248, 255, 236, 255, 4, 0, 238, 255, 26, 0, 232, 255, 44, 0, 230, 255, 66, 0, 226, 255, 86, 0, 219, 255, 88, 0, 215, 255, 72, 0, 210, 255, 50, 0, 225, 255, 28, 0, 23, 0, 14, 0, 64, 0, 16, 0, 51, 0, 26, 0, 32, 0, 34, 0, 39, 0, 42, 0, 48, 0, 35, 0, 58, 0, 255, 255, 72, 0, 220, 255, 69, 0, 197, 255, 58, 0, 158, 255, 54, 0, 132, 255, 36, 0, 153, 255, 12, 0, 146, 255, 5, 0, 83, 255, 237, 255, 110, 255, 197, 255, 252, 255, 214, 255, 51, 0, 1, 0, 233, 255, 250, 255, 226, 255, 250, 255, 45, 0, 46, 0, 47, 0, 70, 0, 6, 0, 55, 0, 19, 0, 60, 0, 38, 0, 62, 0, 42, 0, 47, 0, 61, 0, 46, 0, 40, 0, 42, 0, 237, 255, 22, 0, 222, 255, 6, 0, 221, 255, 206, 255, 195, 255, 115, 255, 219, 255, 85, 255, 17, 0, 93, 255, 26, 0, 76, 255, 46, 0, 102, 255, 80, 0, 193, 255, 48, 0, 252, 255, 18, 0, 20, 0, 50, 0, 47, 0, 58, 0, 53, 0, 44, 0, 61, 0, 57, 0, 85, 0, 37, 0, 80, 0, 0, 0, 86, 0, 248, 255, 106, 0, 161, 255, 49, 0, 43, 255, 248, 255, 125, 255, 47, 0, 49, 0, 63, 0, 40, 0, 217, 255, 187, 255, 182, 255, 219, 255, 236, 255, 63, 0, 244, 255, 58, 0, 242, 255, 244, 255, 25, 0, 225, 255, 41, 0, 11, 0, 45, 0, 76, 0, 47, 0, 167, 0, 5, 0, 5, 1, 219, 255, 21, 1, 173, 255, 183, 0, 84, 255, 35, 0, 134, 255, 177, 255, 138, 0, 186, 255, 10, 1, 69, 0, 124, 0, 228, 0, 0, 0, 135, 1, 227, 255, 82, 2, 172, 255, 190, 2, 178, 255, 115, 2, 248, 255, 39, 2, 243, 255, 253, 1, 13, 0, 116, 1, 120, 0, 96, 1, 125, 0, 110, 2, 127, 0, 179, 2, 223, 0, 106, 1, 126, 0, 130, 1, 223, 255, 147, 3, 198, 0, 190, 3, 201, 1, 200, 1, 42, 1, 244, 1, 233, 0, 3, 4, 213, 1, 72, 4, 170, 1, 150, 3, 160, 0, 43, 4, 141, 0, 196, 4, 189, 0, 221, 4, 164, 0, 95, 5, 41, 1, 98, 5, 247, 1, 19, 5, 190, 2, 14, 6, 161, 3, 7, 7, 87, 3, 216, 6, 35, 2, 38, 7, 90, 2, 136, 7, 64, 3, 200, 6, 28, 3, 199, 6, 165, 3, 169, 7, 105, 5, 143, 7, 26, 6, 57, 8, 205, 5, 156, 10, 169, 5, 132, 11, 25, 5, 208, 10, 181, 4, 156, 10, 66, 5, 227, 9, 170, 5, 166, 9, 117, 6, 45, 12, 63, 8, 42, 13, 128, 8, 136, 10, 155, 7, 109, 11, 1, 9, 6, 15, 98, 10, 121, 9, 136, 8, 147, 252, 189, 7, 43, 247, 63, 10, 147, 249, 92, 11, 172, 248, 172, 10, 112, 245, 137, 11, 76, 246, 44, 12, 184, 247, 138, 11, 118, 246, 144, 12, 94, 246, 171, 13, 112, 247, 162, 12, 168, 246, 33, 13, 63, 246, 29, 15, 226, 247, 188, 14, 190, 248, 75, 15, 238, 247, 86, 17, 19, 247, 118, 11, 10, 247, 232, 254, 238, 247, 30, 249, 56, 248, 124, 250, 6, 247, 1, 250, 161, 246, 3, 249, 81, 247, 117, 250, 60, 247, 202, 250, 212, 247, 60, 250, 15, 249, 140, 250, 34, 248, 221, 249, 105, 247, 218, 249, 205, 248, 113, 251, 138, 248, 90, 250, 41, 248, 230, 248]; +static PCM: &[i16] = &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, -2, 0, -2, 0, -2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 1, 0, 1, 0, 0, -2, 0, -2, 0, -2, 0, -2, -2, -2, -3, -3, -3, -3, -4, -2, -5, -2, -5, -2, -4, 0, -4, 0, -4, 0, -4, 1, -4, 1, -4, 2, -4, 2, -4, 2, -4, 2, -4, 2, -3, 1, -4, 0, -4, 0, -5, 0, -5, 0, -5, 0, -4, 2, -4, 3, -4, 4, -3, 5, -2, 5, -3, 6, -3, 6, -3, 5, -3, 5, -2, 4, -2, 3, -5, 0, -6, 0, -3, -2, -4, -4, -9, -5, -9, -4, -4, -2, -4, -2, -4, 0, -2, 1, 1, 1, 4, 2, 8, 2, 12, 1, 13, 0, 12, 0, 11, 0, 8, -2, 7, 0, 7, -3, 11, -8, 15, -9, 17, -6, 17, -5, 13, -3, 7, 0, 3, 0, -2, 0, -4, 0, -4, -2, -6, 0, -14, -2, -17, -4, -8, 0, -7, 5, -17, 7, -18, 10, -7, 18, -2, 25, -3, 27, 0, 31, 4, 34, 4, 34, 8, 36, 8, 37, 2, 36, 4, 34, 8, 28, 3, 15, 0, 11, 0, 12, -5, 8, -4, 10, 0, 23, -4, 31, -8, 30, -2, 30, 0, 26, -6, 22, -6, 20, -12, 15, -19, 10, -10, 13, -14, 6, -43, -13, -43, -16, -9, -12, -10, -29, -42, -40, -37, -28, -5, -21, 1, -24, -8, -20, 4, -18, 26, -24, 44, -26, 66, -30, 86, -37, 88, -41, 72, -46, 50, -31, 28, 23, 14, 64, 16, 51, 26, 32, 34, 39, 42, 48, 35, 58, 0, 72, -36, 69, -59, 58, -98, 54, -124, 36, -103, 12, -110, 5, -173, -19, -146, -59, -4, -42, 51, 1, -23, -6, -30, -6, 45, 46, 47, 70, 6, 55, 19, 60, 38, 62, 42, 47, 61, 46, 40, 42, -19, 22, -34, 6, -35, -50, -61, -141, -37, -171, 17, -163, 26, -180, 46, -154, 80, -63, 48, -4, 18, 20, 50, 47, 58, 53, 44, 61, 57, 85, 37, 80, 0, 86, -8, 106, -95, 49, -213, -8, -131, 47, 49, 63, 40, -39, -69, -74, -37, -20, 63, -12, 58, -14, -12, 25, -31, 41, 11, 45, 76, 47, 167, 5, 261, -37, 277, -83, 183, -172, 35, -122, -79, 138, -70, 266, 69, 124, 228, 0, 391, -29, 594, -84, 702, -78, 627, -8, 551, -13, 509, 13, 372, 120, 352, 125, 622, 127, 691, 223, 362, 126, 386, -33, 915, 198, 958, 457, 456, 298, 500, 233, 1027, 469, 1096, 426, 918, 160, 1067, 141, 1220, 189, 1245, 164, 1375, 297, 1378, 503, 1299, 702, 1550, 929, 1799, 855, 1752, 547, 1830, 602, 1928, 832, 1736, 796, 1735, 933, 1961, 1385, 1935, 1562, 2105, 1485, 2716, 1449, 2948, 1305, 2768, 1205, 2716, 1346, 2531, 1450, 2470, 1653, 3117, 2111, 3370, 2176, 2696, 1947, 2925, 2305, 3846, 2658, 2425, 2184, -877, 1981, -2261, 2623, -1645, 2908, -1876, 2732, -2704, 2953, -2484, 3116, -2120, 2954, -2442, 3216, -2466, 3499, -2192, 3234, -2392, 3361, -2497, 3869, -2078, 3772, -1858, 3915, -2066, 4438, -2285, 2934, -2294, -280, -2066, -1762, -1992, -1412, -2298, -1535, -2399, -1789, -2223, -1419, -2244, -1334, -2092, -1476, -1777, -1396, -2014, -1571, -2199, -1574, -1843, -1167, -1910, -1446, -2007, -1818]; + +fn main() { + let thread = std::thread::spawn(|| 4); + for _ in 0..2 { + mse(PCM.len(), PCM, EXPECTED); + } + assert_eq!(4, thread.join().unwrap()); +} + +fn read_i16(buffer: &[u8], index: usize) -> i16 { + const SIZE: usize = std::mem::size_of::(); + let mut bytes: [u8; SIZE] = [0u8; SIZE]; + bytes.copy_from_slice(&buffer[(index * SIZE)..(index * SIZE + SIZE)]); + unsafe { std::mem::transmute(bytes) } +} + +fn mse(samples: usize, frame_buf: &[i16], buf_ref: &[u8]) -> f64 { + let mut mse = 0.0; + let max_samples = std::cmp::min(buf_ref.len() / 2, samples as usize); + for i in 0..max_samples { + let ref_res = read_i16(buf_ref, i); + let info_res = frame_buf[i as usize]; + let diff = (ref_res - info_res).abs(); + mse += f64::from(diff.pow(2)); + } + mse / max_samples as f64 +} + diff --git a/src/data_race.rs b/src/data_race.rs index 35898f1d937f8..bd75299af490f 100644 --- a/src/data_race.rs +++ b/src/data_race.rs @@ -65,12 +65,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn read_immediate_racy(&self, op: MPlaceTy<'tcx, Tag>) -> InterpResult<'tcx, ImmTy<'tcx, Tag>> { let this = self.eval_context_ref(); let data_race = &*this.memory.extra.data_race; - let old = data_race.multi_threaded.get(); - data_race.multi_threaded.set(false); + let old = data_race.multi_threaded.replace(false); let res = this.read_immediate(op.into()); - data_race.multi_threaded.set(old); + res } @@ -80,9 +79,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let data_race = &*this.memory.extra.data_race; - let old = data_race.multi_threaded.get(); + let old = data_race.multi_threaded.replace(false); - data_race.multi_threaded.set(false); let imm = this.write_immediate(src, dest.into()); let data_race = &*this.memory.extra.data_race; @@ -1404,4 +1402,4 @@ mod tests { "Invalid alt (>=):\n l: {:?}\n r: {:?}",l,r ); } -} \ No newline at end of file +} diff --git a/tests/compile-fail/data_race/read_write_race.rs b/tests/compile-fail/data_race/read_write_race.rs index 6a5f3f7d20769..42fd7a51ffbda 100644 --- a/tests/compile-fail/data_race/read_write_race.rs +++ b/tests/compile-fail/data_race/read_write_race.rs @@ -24,4 +24,4 @@ pub fn main() { j1.join().unwrap(); j2.join().unwrap(); } -} \ No newline at end of file +} diff --git a/tests/compile-fail/data_race/relax_acquire_race.rs b/tests/compile-fail/data_race/relax_acquire_race.rs index 753d30b8f5708..f7d44c30b66ba 100644 --- a/tests/compile-fail/data_race/relax_acquire_race.rs +++ b/tests/compile-fail/data_race/relax_acquire_race.rs @@ -40,4 +40,4 @@ pub fn main() { j2.join().unwrap(); j3.join().unwrap(); } -} \ No newline at end of file +} diff --git a/tests/compile-fail/data_race/release_seq_race.rs b/tests/compile-fail/data_race/release_seq_race.rs index 44360f70d5d66..dc852cdb4d810 100644 --- a/tests/compile-fail/data_race/release_seq_race.rs +++ b/tests/compile-fail/data_race/release_seq_race.rs @@ -44,4 +44,4 @@ pub fn main() { j2.join().unwrap(); j3.join().unwrap(); } -} \ No newline at end of file +} diff --git a/tests/compile-fail/data_race/rmw_race.rs b/tests/compile-fail/data_race/rmw_race.rs index 9dfa2751d587e..bebd01efa1718 100644 --- a/tests/compile-fail/data_race/rmw_race.rs +++ b/tests/compile-fail/data_race/rmw_race.rs @@ -41,4 +41,4 @@ pub fn main() { j2.join().unwrap(); j3.join().unwrap(); } -} \ No newline at end of file +} diff --git a/tests/compile-fail/data_race/write_write_race.rs b/tests/compile-fail/data_race/write_write_race.rs index 0c46e5c925157..aca19a46c13d7 100644 --- a/tests/compile-fail/data_race/write_write_race.rs +++ b/tests/compile-fail/data_race/write_write_race.rs @@ -24,4 +24,4 @@ pub fn main() { j1.join().unwrap(); j2.join().unwrap(); } -} \ No newline at end of file +} diff --git a/tests/run-pass/concurrency/data_race.rs b/tests/run-pass/concurrency/data_race.rs index 40a7c162a0c18..75e56e8c8d2a1 100644 --- a/tests/run-pass/concurrency/data_race.rs +++ b/tests/run-pass/concurrency/data_race.rs @@ -119,4 +119,4 @@ pub fn main() { test_multiple_reads(); test_rmw_no_block(); test_release_no_block(); -} \ No newline at end of file +} From 571b48cc47a7a4826f16766a4668168dd090a6f8 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 3 Nov 2020 20:07:19 +0100 Subject: [PATCH 2431/3747] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 40aa78ae9a9c3..efb6b94d3b40f 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -a53fb30e3bf2655b0563da6d561c23cda5f3ec11 +5cdf5b882da9e8b7c73b5cadeb7745cb68f6ff63 From 95c99b2044a75f27e691308ebbb7ed0d4e2cbf3b Mon Sep 17 00:00:00 2001 From: JCTyBlaidd Date: Wed, 4 Nov 2020 21:35:48 +0000 Subject: [PATCH 2432/3747] Detect races between atomic and non-atomic accesses of a variable, previously only data races between two non-atomic accesses were detected. --- src/data_race.rs | 350 ++++++++++++++---- src/shims/posix/linux/sync.rs | 5 +- .../data_race/atomic_read_write_race.rs | 31 ++ .../data_race/atomic_read_write_race_alt.rs | 31 ++ .../data_race/atomic_write_read_race.rs | 31 ++ .../data_race/atomic_write_read_race_alt.rs | 31 ++ .../data_race/atomic_write_write_race.rs | 31 ++ .../data_race/atomic_write_write_race_alt.rs | 31 ++ 8 files changed, 463 insertions(+), 78 deletions(-) create mode 100644 tests/compile-fail/data_race/atomic_read_write_race.rs create mode 100644 tests/compile-fail/data_race/atomic_read_write_race_alt.rs create mode 100644 tests/compile-fail/data_race/atomic_write_read_race.rs create mode 100644 tests/compile-fail/data_race/atomic_write_read_race_alt.rs create mode 100644 tests/compile-fail/data_race/atomic_write_write_race.rs create mode 100644 tests/compile-fail/data_race/atomic_write_write_race_alt.rs diff --git a/src/data_race.rs b/src/data_race.rs index bd75299af490f..8e7a3548f5cf0 100644 --- a/src/data_race.rs +++ b/src/data_race.rs @@ -6,8 +6,16 @@ //! and RMW operations //! This does not explore weak memory orders and so can still miss data-races //! but should not report false-positives +//! Data-race definiton from(https://en.cppreference.com/w/cpp/language/memory_model#Threads_and_data_races): +//! - if a memory location is accessed by twice is a data-race unless: +//! - both operations execute on the same thread/signal-handler +//! - both conflicting operations are atomic operations (1 atomic and 1 non-atomic race) +//! - 1 of the operations happens-before the other operation (see link for definition) -use std::{fmt::{self, Debug}, cmp::Ordering, rc::Rc, cell::{Cell, RefCell, Ref, RefMut}, ops::Index}; +use std::{ + fmt::{self, Debug}, cmp::Ordering, rc::Rc, + cell::{Cell, RefCell, Ref, RefMut}, ops::Index, mem +}; use rustc_index::vec::{Idx, IndexVec}; use rustc_target::abi::Size; @@ -16,7 +24,11 @@ use rustc_data_structures::fx::FxHashMap; use smallvec::SmallVec; -use crate::*; +use crate::{ + MiriEvalContext, ThreadId, Tag, MiriEvalContextExt, RangeMap, + MPlaceTy, ImmTy, InterpResult, Pointer, ScalarMaybeUninit, + OpTy, Immediate, MemPlaceMeta +}; pub type AllocExtra = VClockAlloc; pub type MemoryExtra = Rc; @@ -58,8 +70,8 @@ pub enum AtomicFenceOp { } /// Evaluation context extensions -impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} -pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { +impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for MiriEvalContext<'mir, 'tcx> {} +pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { /// Variant of `read_immediate` that does not perform `data-race` checks. fn read_immediate_racy(&self, op: MPlaceTy<'tcx, Tag>) -> InterpResult<'tcx, ImmTy<'tcx, Tag>> { @@ -119,6 +131,26 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.read_scalar_racy(value_place.into()) } + /// Variant of `write_scalar_at_offfset` helper function that performs + /// an atomic load operation with verification instead + fn read_scalar_at_offset_atomic( + &mut self, + op: OpTy<'tcx, Tag>, + offset: u64, + layout: TyAndLayout<'tcx>, + atomic: AtomicReadOp + ) -> InterpResult<'tcx, ScalarMaybeUninit> { + let this = self.eval_context_mut(); + let op_place = this.deref_operand(op)?; + let offset = Size::from_bytes(offset); + // Ensure that the following read at an offset is within bounds + assert!(op_place.layout.size >= offset + layout.size); + let value_place = op_place.offset(offset, MemPlaceMeta::None, layout, this)?; + let res = this.read_scalar_racy(value_place.into())?; + this.validate_atomic_load(value_place, atomic)?; + Ok(res) + } + /// Variant of `write_scalar_at_offfset` helper function that does not perform /// data-race checks. fn write_scalar_at_offset_racy( @@ -137,10 +169,28 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar_racy(value.into(), value_place.into()) } + /// Load the data race allocation state for a given memory place + /// also returns the size and offset of the result in the allocation + /// metadata + /// This is used for atomic loads since unconditionally requesteing + /// mutable access causes issues for read-only memory, which will + /// fail validation on mutable access + fn load_data_race_state_ref<'a>( + &'a self, place: MPlaceTy<'tcx, Tag> + ) -> InterpResult<'tcx, (&'a VClockAlloc, Size, Size)> where 'mir: 'a { + let this = self.eval_context_ref(); + + let ptr = place.ptr.assert_ptr(); + let size = place.layout.size; + let data_race = &this.memory.get_raw(ptr.alloc_id)?.extra.data_race; + + Ok((data_race, size, ptr.offset)) + } + /// Load the data race allocation state for a given memory place /// also returns the size and the offset of the result in the allocation /// metadata - fn load_data_race_state<'a>( + fn load_data_race_state_mut<'a>( &'a mut self, place: MPlaceTy<'tcx, Tag> ) -> InterpResult<'tcx, (&'a mut VClockAlloc, Size, Size)> where 'mir: 'a { let this = self.eval_context_mut(); @@ -164,29 +214,42 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let ( alloc, size, offset - ) = this.load_data_race_state(place)?; + ) = this.load_data_race_state_ref(place)?; log::trace!( "Atomic load on {:?} with ordering {:?}, in memory({:?}, offset={}, size={})", alloc.global.current_thread(), atomic, place.ptr.assert_ptr().alloc_id, offset.bytes(), size.bytes() ); + let current_thread = alloc.global.current_thread(); let mut current_state = alloc.global.current_thread_state_mut(); if atomic == AtomicReadOp::Relaxed { // Perform relaxed atomic load - for (_,range) in alloc.alloc_ranges.get_mut().iter_mut(offset, size) { - range.load_relaxed(&mut *current_state); + for (_,range) in alloc.alloc_ranges.borrow_mut().iter_mut(offset, size) { + if range.load_relaxed(&mut *current_state, current_thread) == Err(DataRace) { + mem::drop(current_state); + return VClockAlloc::report_data_race( + &alloc.global, range, "ATOMIC_LOAD", true, + place.ptr.assert_ptr(), size + ); + } } }else{ // Perform acquire(or seq-cst) atomic load - for (_,range) in alloc.alloc_ranges.get_mut().iter_mut(offset, size) { - range.acquire(&mut *current_state); + for (_,range) in alloc.alloc_ranges.borrow_mut().iter_mut(offset, size) { + if range.acquire(&mut *current_state, current_thread) == Err(DataRace) { + mem::drop(current_state); + return VClockAlloc::report_data_race( + &alloc.global, range, "ATOMIC_LOAD", true, + place.ptr.assert_ptr(), size + ); + } } } // Log changes to atomic memory if log::log_enabled!(log::Level::Trace) { - for (_,range) in alloc.alloc_ranges.get_mut().iter(offset, size) { + for (_,range) in alloc.alloc_ranges.borrow_mut().iter(offset, size) { log::trace!( " updated atomic memory({:?}, offset={}, size={}) to {:#?}", place.ptr.assert_ptr().alloc_id, offset.bytes(), size.bytes(), @@ -195,7 +258,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } - std::mem::drop(current_state); + mem::drop(current_state); let data_race = &*this.memory.extra.data_race; data_race.advance_vector_clock(); } @@ -214,7 +277,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let ( alloc, size, offset - ) = this.load_data_race_state(place)?; + ) = this.load_data_race_state_mut(place)?; let current_thread = alloc.global.current_thread(); let mut current_state = alloc.global.current_thread_state_mut(); log::trace!( @@ -226,12 +289,24 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if atomic == AtomicWriteOp::Relaxed { // Perform relaxed atomic store for (_,range) in alloc.alloc_ranges.get_mut().iter_mut(offset, size) { - range.store_relaxed(&mut *current_state, current_thread); + if range.store_relaxed(&mut *current_state, current_thread) == Err(DataRace) { + mem::drop(current_state); + return VClockAlloc::report_data_race( + &alloc.global, range, "ATOMIC_STORE", true, + place.ptr.assert_ptr(), size + ); + } } }else{ // Perform release(or seq-cst) atomic store for (_,range) in alloc.alloc_ranges.get_mut().iter_mut(offset, size) { - range.release(&mut *current_state, current_thread); + if range.release(&mut *current_state, current_thread) == Err(DataRace) { + mem::drop(current_state); + return VClockAlloc::report_data_race( + &alloc.global, range, "ATOMIC_STORE", true, + place.ptr.assert_ptr(), size + ); + } } } @@ -246,7 +321,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } - std::mem::drop(current_state); + mem::drop(current_state); let data_race = &*this.memory.extra.data_race; data_race.advance_vector_clock(); } @@ -266,7 +341,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let ( alloc, size, offset - ) = this.load_data_race_state(place)?; + ) = this.load_data_race_state_mut(place)?; let current_thread = alloc.global.current_thread(); let mut current_state = alloc.global.current_thread_state_mut(); log::trace!( @@ -280,17 +355,31 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx for (_,range) in alloc.alloc_ranges.get_mut().iter_mut(offset, size) { //FIXME: this is probably still slightly wrong due to the quirks // in the c++11 memory model - if acquire { + let maybe_race = if acquire { // Atomic RW-Op acquire - range.acquire(&mut *current_state); + range.acquire(&mut *current_state, current_thread) }else{ - range.load_relaxed(&mut *current_state); + range.load_relaxed(&mut *current_state, current_thread) + }; + if maybe_race == Err(DataRace) { + mem::drop(current_state); + return VClockAlloc::report_data_race( + &alloc.global, range, "ATOMIC_RMW(LOAD)", true, + place.ptr.assert_ptr(), size + ); } - if release { + let maybe_race = if release { // Atomic RW-Op release - range.rmw_release(&mut *current_state, current_thread); + range.rmw_release(&mut *current_state, current_thread) }else{ - range.rmw_relaxed(&mut *current_state); + range.rmw_relaxed(&mut *current_state, current_thread) + }; + if maybe_race == Err(DataRace) { + mem::drop(current_state); + return VClockAlloc::report_data_race( + &alloc.global, range, "ATOMIC_RMW(STORE)", true, + place.ptr.assert_ptr(), size + ); } } @@ -305,7 +394,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } - std::mem::drop(current_state); + mem::drop(current_state); let data_race = &*this.memory.extra.data_race; data_race.advance_vector_clock(); } @@ -478,6 +567,11 @@ impl Debug for AtomicReleaseSequences { } } +/// Error returned by finding a data race +/// should be elaborated upon +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] +pub struct DataRace; + /// Externally stored memory cell clocks /// explicitly to reduce memory usage for the /// common case where no atomic operations @@ -485,11 +579,26 @@ impl Debug for AtomicReleaseSequences { #[derive(Clone, PartialEq, Eq, Debug)] struct AtomicMemoryCellClocks { + /// The clock-vector for the set of atomic read operations + /// used for detecting data-races with non-atomic write + /// operations + read_vector: VClock, + + /// The clock-vector for the set of atomic write operations + /// used for detecting data-races with non-atomic read or + /// write operations + write_vector: VClock, + /// Synchronization vector for acquire-release semantics + /// contains the vector of timestamps that will + /// happen-before a thread if an acquire-load is + /// performed on the data sync_vector: VClock, /// The Hash-Map of all threads for which a release - /// sequence exists in the memory cell + /// sequence exists in the memory cell, required + /// since read-modify-write operations do not + /// invalidate existing release sequences release_sequences: AtomicReleaseSequences, } @@ -498,10 +607,12 @@ struct AtomicMemoryCellClocks { #[derive(Clone, PartialEq, Eq, Debug)] struct MemoryCellClocks { - /// The vector-clock of the last write + /// The vector-clock of the last write, only one value is stored + /// since all previous writes happened-before the current write write: Timestamp, - /// The id of the thread that performed the last write to this memory location + /// The identifier of the thread that performed the last write + /// operation write_thread: ThreadId, /// The vector-clock of the set of previous reads @@ -532,7 +643,7 @@ impl MemoryCellClocks { /// Load the internal atomic memory cells if they exist #[inline] - fn atomic(&mut self) -> Option<&AtomicMemoryCellClocks> { + fn atomic(&self) -> Option<&AtomicMemoryCellClocks> { match &self.atomic_ops { Some(op) => Some(&*op), None => None @@ -545,6 +656,8 @@ impl MemoryCellClocks { fn atomic_mut(&mut self) -> &mut AtomicMemoryCellClocks { self.atomic_ops.get_or_insert_with(|| { Box::new(AtomicMemoryCellClocks { + read_vector: VClock::default(), + write_vector: VClock::default(), sync_vector: VClock::default(), release_sequences: AtomicReleaseSequences::new() }) @@ -554,75 +667,131 @@ impl MemoryCellClocks { /// Update memory cell data-race tracking for atomic /// load acquire semantics, is a no-op if this memory was /// not used previously as atomic memory - fn acquire(&mut self, clocks: &mut ThreadClockSet) { + fn acquire(&mut self, clocks: &mut ThreadClockSet, thread: ThreadId) -> Result<(), DataRace> { + self.atomic_read_detect(clocks, thread)?; if let Some(atomic) = self.atomic() { clocks.clock.join(&atomic.sync_vector); } + Ok(()) } /// Update memory cell data-race tracking for atomic /// load relaxed semantics, is a no-op if this memory was /// not used previously as atomic memory - fn load_relaxed(&mut self, clocks: &mut ThreadClockSet) { + fn load_relaxed(&mut self, clocks: &mut ThreadClockSet, thread: ThreadId) -> Result<(), DataRace> { + self.atomic_read_detect(clocks, thread)?; if let Some(atomic) = self.atomic() { clocks.fence_acquire.join(&atomic.sync_vector); } + Ok(()) } /// Update the memory cell data-race tracking for atomic /// store release semantics - fn release(&mut self, clocks: &ThreadClockSet, thread: ThreadId) { + fn release(&mut self, clocks: &ThreadClockSet, thread: ThreadId) -> Result<(), DataRace> { + self.atomic_write_detect(clocks, thread)?; let atomic = self.atomic_mut(); atomic.sync_vector.set_values(&clocks.clock); atomic.release_sequences.clear_and_set(thread, &clocks.clock); + Ok(()) } /// Update the memory cell data-race tracking for atomic /// store relaxed semantics - fn store_relaxed(&mut self, clocks: &ThreadClockSet, thread: ThreadId) { + fn store_relaxed(&mut self, clocks: &ThreadClockSet, thread: ThreadId) -> Result<(), DataRace> { + self.atomic_write_detect(clocks, thread)?; let atomic = self.atomic_mut(); atomic.sync_vector.set_values(&clocks.fence_release); if let Some(release) = atomic.release_sequences.load(thread) { atomic.sync_vector.join(release); } atomic.release_sequences.clear_and_retain(thread); + Ok(()) } /// Update the memory cell data-race tracking for atomic /// store release semantics for RMW operations - fn rmw_release(&mut self, clocks: &ThreadClockSet, thread: ThreadId) { + fn rmw_release(&mut self, clocks: &ThreadClockSet, thread: ThreadId) -> Result<(), DataRace> { + self.atomic_write_detect(clocks, thread)?; let atomic = self.atomic_mut(); atomic.sync_vector.join(&clocks.clock); atomic.release_sequences.insert(thread, &clocks.clock); + Ok(()) } /// Update the memory cell data-race tracking for atomic /// store relaxed semantics for RMW operations - fn rmw_relaxed(&mut self, clocks: &ThreadClockSet) { + fn rmw_relaxed(&mut self, clocks: &ThreadClockSet, thread: ThreadId) -> Result<(), DataRace> { + self.atomic_write_detect(clocks, thread)?; let atomic = self.atomic_mut(); atomic.sync_vector.join(&clocks.fence_release); + Ok(()) } - + /// Detect data-races with an atomic read, caused by a non-atomic write that does + /// not happen-before the atomic-read + fn atomic_read_detect(&mut self, clocks: &ThreadClockSet, thread: ThreadId) -> Result<(), DataRace> { + log::trace!("Atomic read with vectors: {:#?} :: {:#?}", self, clocks); + if self.write <= clocks.clock[self.write_thread] { + let atomic = self.atomic_mut(); + atomic.read_vector.set_at_thread(&clocks.clock, thread); + Ok(()) + }else{ + Err(DataRace) + } + } + + /// Detect data-races with an atomic write, either with a non-atomic read or with + /// a non-atomic write: + fn atomic_write_detect(&mut self, clocks: &ThreadClockSet, thread: ThreadId) -> Result<(), DataRace> { + log::trace!("Atomic write with vectors: {:#?} :: {:#?}", self, clocks); + if self.write <= clocks.clock[self.write_thread] && self.read <= clocks.clock { + let atomic = self.atomic_mut(); + atomic.write_vector.set_at_thread(&clocks.clock, thread); + Ok(()) + }else{ + Err(DataRace) + } + } /// Detect races for non-atomic read operations at the current memory cell /// returns true if a data-race is detected - fn read_race_detect(&mut self, clocks: &ThreadClockSet, thread: ThreadId) -> bool { + fn read_race_detect(&mut self, clocks: &ThreadClockSet, thread: ThreadId) -> Result<(), DataRace> { + log::trace!("Unsynchronized read with vectors: {:#?} :: {:#?}", self, clocks); if self.write <= clocks.clock[self.write_thread] { - self.read.set_at_thread(&clocks.clock, thread); - false + let race_free = if let Some(atomic) = self.atomic() { + atomic.write_vector <= clocks.clock + }else{ + true + }; + if race_free { + self.read.set_at_thread(&clocks.clock, thread); + Ok(()) + }else{ + Err(DataRace) + } }else{ - true + Err(DataRace) } } /// Detect races for non-atomic write operations at the current memory cell /// returns true if a data-race is detected - fn write_race_detect(&mut self, clocks: &ThreadClockSet, thread: ThreadId) -> bool { + fn write_race_detect(&mut self, clocks: &ThreadClockSet, thread: ThreadId) -> Result<(), DataRace> { + log::trace!("Unsynchronized write with vectors: {:#?} :: {:#?}", self, clocks); if self.write <= clocks.clock[self.write_thread] && self.read <= clocks.clock { - self.write = clocks.clock[thread]; - self.write_thread = thread; - self.read.set_zero_vector(); - false + let race_free = if let Some(atomic) = self.atomic() { + atomic.write_vector <= clocks.clock && atomic.read_vector <= clocks.clock + }else{ + true + }; + if race_free { + self.write = clocks.clock[thread]; + self.write_thread = thread; + self.read.set_zero_vector(); + Ok(()) + }else{ + Err(DataRace) + } }else{ - true + Err(DataRace) } } } @@ -651,6 +820,33 @@ impl VClockAlloc { } } + // Find an index, if one exists where the value + // in `l` is greater than the value in `r` + fn find_gt_index(l: &VClock, r: &VClock) -> Option { + let l_slice = l.as_slice(); + let r_slice = r.as_slice(); + l_slice.iter().zip(r_slice.iter()) + .enumerate() + .find_map(|(idx, (&l, &r))| { + if l > r { Some(idx) } else { None } + }).or_else(|| { + if l_slice.len() > r_slice.len() { + // By invariant, if l_slice is longer + // then one element must be larger + // This just validates that this is true + // and reports earlier elements first + let l_remainder_slice = &l_slice[r_slice.len()..]; + let idx = l_remainder_slice.iter().enumerate() + .find_map(|(idx, &r)| { + if r == 0 { None } else { Some(idx) } + }).expect("Invalid VClock Invariant"); + Some(idx) + }else{ + None + } + }) + } + /// Report a data-race found in the program /// this finds the two racing threads and the type /// of data-race that occured, this will also @@ -659,7 +855,8 @@ impl VClockAlloc { #[cold] #[inline(never)] fn report_data_race<'tcx>( - global: &MemoryExtra, range: &MemoryCellClocks, action: &str, + global: &MemoryExtra, range: &MemoryCellClocks, + action: &str, is_atomic: bool, pointer: Pointer, len: Size ) -> InterpResult<'tcx> { let current_thread = global.current_thread(); @@ -669,40 +866,39 @@ impl VClockAlloc { other_action, other_thread, other_clock ) = if range.write > current_state.clock[range.write_thread] { - // Create effective write-clock that the data-race occured with + // Convert the write action into the vector clock it + // represents for diagnostic purposes let wclock = write_clock.get_mut_with_min_len( current_state.clock.as_slice().len() .max(range.write_thread.to_u32() as usize + 1) ); wclock[range.write_thread.to_u32() as usize] = range.write; ("WRITE", range.write_thread, write_clock.as_slice()) + }else if let Some(idx) = Self::find_gt_index( + &range.read, ¤t_state.clock + ){ + ("READ", ThreadId::new(idx), range.read.as_slice()) + }else if !is_atomic { + if let Some(atomic) = range.atomic() { + if let Some(idx) = Self::find_gt_index( + &atomic.write_vector, ¤t_state.clock + ) { + ("ATOMIC_STORE", ThreadId::new(idx), atomic.write_vector.as_slice()) + }else if let Some(idx) = Self::find_gt_index( + &atomic.read_vector, ¤t_state.clock + ) { + ("ATOMIC_LOAD", ThreadId::new(idx), atomic.read_vector.as_slice()) + }else{ + unreachable!("Failed to find report data-race for non-atomic operation: no race found") + } + }else{ + unreachable!("Failed to report data-race for non-atomic operation: no atomic component") + } }else{ - - // Find index in the read-clock that the data-race occured with - let read_slice = range.read.as_slice(); - let clock_slice = current_state.clock.as_slice(); - let conflicting_index = read_slice.iter() - .zip(clock_slice.iter()) - .enumerate().find_map(|(idx,(&read, &clock))| { - if read > clock { - Some(idx) - }else{ - None - } - }).unwrap_or_else(|| { - assert!(read_slice.len() > clock_slice.len(), "BUG: cannot find read race yet reported data-race"); - let rest_read = &read_slice[clock_slice.len()..]; - rest_read.iter().enumerate().find_map(|(idx, &val)| { - if val > 0 { - Some(idx + clock_slice.len()) - }else{ - None - } - }).expect("Invariant broken for read-slice, no 0 element at the tail") - }); - ("READ", ThreadId::new(conflicting_index), range.read.as_slice()) + unreachable!("Failed to report data-race for atomic operation") }; + // Load elaborated thread information about the racing thread actions let current_thread_info = global.print_thread_metadata(current_thread); let other_thread_info = global.print_thread_metadata(other_thread); @@ -732,10 +928,10 @@ impl VClockAlloc { // to the ranges being tested, so this is ok let mut alloc_ranges = self.alloc_ranges.borrow_mut(); for (_,range) in alloc_ranges.iter_mut(pointer.offset, len) { - if range.read_race_detect(&*current_state, current_thread) { + if range.read_race_detect(&*current_state, current_thread) == Err(DataRace) { // Report data-race return Self::report_data_race( - &self.global,range, "READ", pointer, len + &self.global,range, "READ", false, pointer, len ); } } @@ -753,10 +949,10 @@ impl VClockAlloc { let current_thread = self.global.current_thread(); let current_state = self.global.current_thread_state(); for (_,range) in self.alloc_ranges.get_mut().iter_mut(pointer.offset, len) { - if range.write_race_detect(&*current_state, current_thread) { + if range.write_race_detect(&*current_state, current_thread) == Err(DataRace) { // Report data-race return Self::report_data_race( - &self.global, range, "WRITE", pointer, len + &self.global, range, "WRITE", false, pointer, len ); } } @@ -774,10 +970,10 @@ impl VClockAlloc { let current_thread = self.global.current_thread(); let current_state = self.global.current_thread_state(); for (_,range) in self.alloc_ranges.get_mut().iter_mut(pointer.offset, len) { - if range.write_race_detect(&*current_state, current_thread) { + if range.write_race_detect(&*current_state, current_thread) == Err(DataRace) { // Report data-race return Self::report_data_race( - &self.global, range, "DEALLOCATE", pointer, len + &self.global, range, "DEALLOCATE", false, pointer, len ); } } diff --git a/src/shims/posix/linux/sync.rs b/src/shims/posix/linux/sync.rs index 9d124872f5cc9..67cea55077376 100644 --- a/src/shims/posix/linux/sync.rs +++ b/src/shims/posix/linux/sync.rs @@ -78,7 +78,10 @@ pub fn futex<'tcx>( // Read an `i32` through the pointer, regardless of any wrapper types. // It's not uncommon for `addr` to be passed as another type than `*mut i32`, such as `*const AtomicI32`. // FIXME: this fails if `addr` is not a pointer type. - let futex_val = this.read_scalar_at_offset(addr.into(), 0, this.machine.layouts.i32)?.to_i32()?; + // FIXME: what form of atomic operation should the `futex` use to load the value? + let futex_val = this.read_scalar_at_offset_atomic( + addr.into(), 0, this.machine.layouts.i32, AtomicReadOp::Acquire + )?.to_i32()?; if val == futex_val { // The value still matches, so we block the trait make it wait for FUTEX_WAKE. this.block_thread(thread); diff --git a/tests/compile-fail/data_race/atomic_read_write_race.rs b/tests/compile-fail/data_race/atomic_read_write_race.rs new file mode 100644 index 0000000000000..0b9610edc64b3 --- /dev/null +++ b/tests/compile-fail/data_race/atomic_read_write_race.rs @@ -0,0 +1,31 @@ +// ignore-windows: Concurrency on Windows is not supported yet. +#![feature(core_intrinsics)] + +use std::thread::spawn; +use std::sync::atomic::AtomicUsize; +use std::intrinsics::atomic_load; + +#[derive(Copy, Clone)] +struct EvilSend(pub T); + +unsafe impl Send for EvilSend {} +unsafe impl Sync for EvilSend {} + +pub fn main() { + let mut a = AtomicUsize::new(0); + let b = &mut a as *mut AtomicUsize; + let c = EvilSend(b); + unsafe { + let j1 = spawn(move || { + *(c.0 as *mut usize) = 32; + }); + + let j2 = spawn(move || { + //Equivalent to: (&*c.0).load(Ordering::SeqCst) + atomic_load(c.0 as *mut usize) //~ ERROR Data race + }); + + j1.join().unwrap(); + j2.join().unwrap(); + } +} diff --git a/tests/compile-fail/data_race/atomic_read_write_race_alt.rs b/tests/compile-fail/data_race/atomic_read_write_race_alt.rs new file mode 100644 index 0000000000000..779babefd8e60 --- /dev/null +++ b/tests/compile-fail/data_race/atomic_read_write_race_alt.rs @@ -0,0 +1,31 @@ +// ignore-windows: Concurrency on Windows is not supported yet. + +use std::thread::spawn; +use std::sync::atomic::AtomicUsize; +use std::sync::atomic::Ordering; + +#[derive(Copy, Clone)] +struct EvilSend(pub T); + +unsafe impl Send for EvilSend {} +unsafe impl Sync for EvilSend {} + +pub fn main() { + let mut a = AtomicUsize::new(0); + let b = &mut a as *mut AtomicUsize; + let c = EvilSend(b); + unsafe { + let j1 = spawn(move || { + let atomic_ref = &mut *c.0; + atomic_ref.load(Ordering::SeqCst) + }); + + let j2 = spawn(move || { + let atomic_ref = &mut *c.0; + *atomic_ref.get_mut() = 32; //~ ERROR Data race + }); + + j1.join().unwrap(); + j2.join().unwrap(); + } +} diff --git a/tests/compile-fail/data_race/atomic_write_read_race.rs b/tests/compile-fail/data_race/atomic_write_read_race.rs new file mode 100644 index 0000000000000..3211a5ae53442 --- /dev/null +++ b/tests/compile-fail/data_race/atomic_write_read_race.rs @@ -0,0 +1,31 @@ +// ignore-windows: Concurrency on Windows is not supported yet. + +use std::thread::spawn; +use std::sync::atomic::AtomicUsize; +use std::sync::atomic::Ordering; + +#[derive(Copy, Clone)] +struct EvilSend(pub T); + +unsafe impl Send for EvilSend {} +unsafe impl Sync for EvilSend {} + +pub fn main() { + let mut a = AtomicUsize::new(0); + let b = &mut a as *mut AtomicUsize; + let c = EvilSend(b); + unsafe { + let j1 = spawn(move || { + let atomic_ref = &mut *c.0; + atomic_ref.store(32, Ordering::SeqCst) + }); + + let j2 = spawn(move || { + let atomic_ref = &mut *c.0; + *atomic_ref.get_mut() //~ ERROR Data race + }); + + j1.join().unwrap(); + j2.join().unwrap(); + } +} diff --git a/tests/compile-fail/data_race/atomic_write_read_race_alt.rs b/tests/compile-fail/data_race/atomic_write_read_race_alt.rs new file mode 100644 index 0000000000000..131d4e07b829f --- /dev/null +++ b/tests/compile-fail/data_race/atomic_write_read_race_alt.rs @@ -0,0 +1,31 @@ +// ignore-windows: Concurrency on Windows is not supported yet. +#![feature(core_intrinsics)] + +use std::thread::spawn; +use std::sync::atomic::AtomicUsize; +use std::intrinsics::atomic_store; + +#[derive(Copy, Clone)] +struct EvilSend(pub T); + +unsafe impl Send for EvilSend {} +unsafe impl Sync for EvilSend {} + +pub fn main() { + let mut a = AtomicUsize::new(0); + let b = &mut a as *mut AtomicUsize; + let c = EvilSend(b); + unsafe { + let j1 = spawn(move || { + *(c.0 as *mut usize) + }); + + let j2 = spawn(move || { + //Equivalent to: (&*c.0).store(32, Ordering::SeqCst) + atomic_store(c.0 as *mut usize, 32); //~ ERROR Data race + }); + + j1.join().unwrap(); + j2.join().unwrap(); + } +} diff --git a/tests/compile-fail/data_race/atomic_write_write_race.rs b/tests/compile-fail/data_race/atomic_write_write_race.rs new file mode 100644 index 0000000000000..74adf7ae4b8d2 --- /dev/null +++ b/tests/compile-fail/data_race/atomic_write_write_race.rs @@ -0,0 +1,31 @@ +// ignore-windows: Concurrency on Windows is not supported yet. +#![feature(core_intrinsics)] + +use std::thread::spawn; +use std::sync::atomic::AtomicUsize; +use std::intrinsics::atomic_store; + +#[derive(Copy, Clone)] +struct EvilSend(pub T); + +unsafe impl Send for EvilSend {} +unsafe impl Sync for EvilSend {} + +pub fn main() { + let mut a = AtomicUsize::new(0); + let b = &mut a as *mut AtomicUsize; + let c = EvilSend(b); + unsafe { + let j1 = spawn(move || { + *(c.0 as *mut usize) = 32; + }); + + let j2 = spawn(move || { + //Equivalent to: (&*c.0).store(64, Ordering::SeqCst) + atomic_store(c.0 as *mut usize, 64); //~ ERROR Data race + }); + + j1.join().unwrap(); + j2.join().unwrap(); + } +} diff --git a/tests/compile-fail/data_race/atomic_write_write_race_alt.rs b/tests/compile-fail/data_race/atomic_write_write_race_alt.rs new file mode 100644 index 0000000000000..75ad755fbd2c3 --- /dev/null +++ b/tests/compile-fail/data_race/atomic_write_write_race_alt.rs @@ -0,0 +1,31 @@ +// ignore-windows: Concurrency on Windows is not supported yet. + +use std::thread::spawn; +use std::sync::atomic::AtomicUsize; +use std::sync::atomic::Ordering; + +#[derive(Copy, Clone)] +struct EvilSend(pub T); + +unsafe impl Send for EvilSend {} +unsafe impl Sync for EvilSend {} + +pub fn main() { + let mut a = AtomicUsize::new(0); + let b = &mut a as *mut AtomicUsize; + let c = EvilSend(b); + unsafe { + let j1 = spawn(move || { + let atomic_ref = &mut *c.0; + atomic_ref.store(64, Ordering::SeqCst); + }); + + let j2 = spawn(move || { + let atomic_ref = &mut *c.0; + *atomic_ref.get_mut() = 32; //~ ERROR Data race + }); + + j1.join().unwrap(); + j2.join().unwrap(); + } +} From 9cb6b8da3f6ca2da1139c91754d520bf2d354f31 Mon Sep 17 00:00:00 2001 From: JCTyBlaidd Date: Thu, 5 Nov 2020 03:54:39 +0000 Subject: [PATCH 2433/3747] Split out vector_clock to separate file, general tidy up of some of the code & add support for vector index re-use for multiple threads after termination. --- src/data_race.rs | 1333 +++++++++++++-------------------------- src/lib.rs | 4 + src/shims/intrinsics.rs | 31 +- src/shims/posix/sync.rs | 39 +- src/thread.rs | 4 +- src/vector_clock.rs | 602 ++++++++++++++++++ 6 files changed, 1084 insertions(+), 929 deletions(-) create mode 100644 src/vector_clock.rs diff --git a/src/data_race.rs b/src/data_race.rs index 8e7a3548f5cf0..e992c5a1d5899 100644 --- a/src/data_race.rs +++ b/src/data_race.rs @@ -13,21 +13,21 @@ //! - 1 of the operations happens-before the other operation (see link for definition) use std::{ - fmt::{self, Debug}, cmp::Ordering, rc::Rc, - cell::{Cell, RefCell, Ref, RefMut}, ops::Index, mem + fmt::Debug, rc::Rc, + cell::{Cell, RefCell, Ref, RefMut}, mem }; use rustc_index::vec::{Idx, IndexVec}; use rustc_target::abi::Size; use rustc_middle::ty::layout::TyAndLayout; -use rustc_data_structures::fx::FxHashMap; - -use smallvec::SmallVec; +use rustc_data_structures::fx::FxHashSet; use crate::{ - MiriEvalContext, ThreadId, Tag, MiriEvalContextExt, RangeMap, - MPlaceTy, ImmTy, InterpResult, Pointer, ScalarMaybeUninit, - OpTy, Immediate, MemPlaceMeta + MiriEvalContext, MiriEvalContextExt, + ThreadId, Tag, RangeMap, + InterpResult, Pointer, ScalarMaybeUninit, + MPlaceTy, OpTy, MemPlaceMeta, + VClock, VSmallClockSet, VectorIdx, VTimestamp }; pub type AllocExtra = VClockAlloc; @@ -73,194 +73,136 @@ pub enum AtomicFenceOp { impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { - /// Variant of `read_immediate` that does not perform `data-race` checks. - fn read_immediate_racy(&self, op: MPlaceTy<'tcx, Tag>) -> InterpResult<'tcx, ImmTy<'tcx, Tag>> { + // Temporarily allow data-races to occur, this should only be + // used if either one of the appropiate `validate_atomic` functions + // will be called to treat a memory access as atomic or if the memory + // being accessed should be treated as internal state, that cannot be + // accessed by the interpreted program. + #[inline] + fn allow_data_races_ref(&self, op: impl FnOnce(&MiriEvalContext<'mir, 'tcx>) -> R) -> R { let this = self.eval_context_ref(); let data_race = &*this.memory.extra.data_race; - let old = data_race.multi_threaded.replace(false); - let res = this.read_immediate(op.into()); + let result = op(this); data_race.multi_threaded.set(old); - - res + result } - - /// Variant of `write_immediate` that does not perform `data-race` checks. - fn write_immediate_racy( - &mut self, src: Immediate, dest: MPlaceTy<'tcx, Tag> - ) -> InterpResult<'tcx> { + + /// Same as `allow_data_races_ref`, this temporarily disables any data-race detection and + /// so should only be used for atomic operations or internal state that the program cannot + /// access + #[inline] + fn allow_data_races_mut(&mut self, op: impl FnOnce(&mut MiriEvalContext<'mir, 'tcx>) -> R) -> R { let this = self.eval_context_mut(); let data_race = &*this.memory.extra.data_race; let old = data_race.multi_threaded.replace(false); - - let imm = this.write_immediate(src, dest.into()); - + let result = op(this); let data_race = &*this.memory.extra.data_race; data_race.multi_threaded.set(old); - imm + result } - /// Variant of `read_scalar` that does not perform data-race checks. - fn read_scalar_racy( - &self, op: MPlaceTy<'tcx, Tag> - )-> InterpResult<'tcx, ScalarMaybeUninit> { - Ok(self.read_immediate_racy(op)?.to_scalar_or_uninit()) - } - /// Variant of `write_scalar` that does not perform data-race checks. - fn write_scalar_racy( - &mut self, val: ScalarMaybeUninit, dest: MPlaceTy<'tcx, Tag> - ) -> InterpResult<'tcx> { - self.write_immediate_racy(Immediate::Scalar(val.into()), dest) - } - - /// Variant of `read_scalar_at_offset` helper function that does not perform - /// `data-race checks. - fn read_scalar_at_offset_racy( - &self, - op: OpTy<'tcx, Tag>, - offset: u64, - layout: TyAndLayout<'tcx>, - ) -> InterpResult<'tcx, ScalarMaybeUninit> { - let this = self.eval_context_ref(); - let op_place = this.deref_operand(op)?; - let offset = Size::from_bytes(offset); - // Ensure that the following read at an offset is within bounds - assert!(op_place.layout.size >= offset + layout.size); - let value_place = op_place.offset(offset, MemPlaceMeta::None, layout, this)?; - this.read_scalar_racy(value_place.into()) - } - - /// Variant of `write_scalar_at_offfset` helper function that performs - /// an atomic load operation with verification instead fn read_scalar_at_offset_atomic( - &mut self, + &self, op: OpTy<'tcx, Tag>, offset: u64, layout: TyAndLayout<'tcx>, atomic: AtomicReadOp ) -> InterpResult<'tcx, ScalarMaybeUninit> { - let this = self.eval_context_mut(); + let this = self.eval_context_ref(); let op_place = this.deref_operand(op)?; let offset = Size::from_bytes(offset); // Ensure that the following read at an offset is within bounds assert!(op_place.layout.size >= offset + layout.size); let value_place = op_place.offset(offset, MemPlaceMeta::None, layout, this)?; - let res = this.read_scalar_racy(value_place.into())?; - this.validate_atomic_load(value_place, atomic)?; - Ok(res) + this.read_scalar_atomic(value_place, atomic) } - - /// Variant of `write_scalar_at_offfset` helper function that does not perform - /// data-race checks. - fn write_scalar_at_offset_racy( + fn write_scalar_at_offset_atomic( &mut self, op: OpTy<'tcx, Tag>, offset: u64, value: impl Into>, layout: TyAndLayout<'tcx>, - ) -> InterpResult<'tcx, ()> { + atomic: AtomicWriteOp + ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let op_place = this.deref_operand(op)?; let offset = Size::from_bytes(offset); // Ensure that the following read at an offset is within bounds assert!(op_place.layout.size >= offset + layout.size); let value_place = op_place.offset(offset, MemPlaceMeta::None, layout, this)?; - this.write_scalar_racy(value.into(), value_place.into()) + this.write_scalar_atomic(value.into(), value_place, atomic) } - - /// Load the data race allocation state for a given memory place - /// also returns the size and offset of the result in the allocation - /// metadata - /// This is used for atomic loads since unconditionally requesteing - /// mutable access causes issues for read-only memory, which will - /// fail validation on mutable access - fn load_data_race_state_ref<'a>( - &'a self, place: MPlaceTy<'tcx, Tag> - ) -> InterpResult<'tcx, (&'a VClockAlloc, Size, Size)> where 'mir: 'a { - let this = self.eval_context_ref(); - - let ptr = place.ptr.assert_ptr(); - let size = place.layout.size; - let data_race = &this.memory.get_raw(ptr.alloc_id)?.extra.data_race; - - Ok((data_race, size, ptr.offset)) - } - - /// Load the data race allocation state for a given memory place - /// also returns the size and the offset of the result in the allocation - /// metadata - fn load_data_race_state_mut<'a>( - &'a mut self, place: MPlaceTy<'tcx, Tag> - ) -> InterpResult<'tcx, (&'a mut VClockAlloc, Size, Size)> where 'mir: 'a { - let this = self.eval_context_mut(); - - let ptr = place.ptr.assert_ptr(); - let size = place.layout.size; - let data_race = &mut this.memory.get_raw_mut(ptr.alloc_id)?.extra.data_race; - - Ok((data_race, size, ptr.offset)) + fn read_scalar_atomic( + &self, place: MPlaceTy<'tcx, Tag>, atomic: AtomicReadOp + ) -> InterpResult<'tcx, ScalarMaybeUninit> { + let scalar = self.allow_data_races_ref(move |this| { + this.read_scalar(place.into()) + })?; + self.validate_atomic_load(place, atomic)?; + Ok(scalar) + } + fn write_scalar_atomic( + &mut self, val: ScalarMaybeUninit, dest: MPlaceTy<'tcx, Tag>, + atomic: AtomicWriteOp + ) -> InterpResult<'tcx> { + self.allow_data_races_mut(move |this| { + this.write_scalar(val, dest.into()) + })?; + self.validate_atomic_store(dest, atomic) } /// Update the data-race detector for an atomic read occuring at the /// associated memory-place and on the current thread fn validate_atomic_load( - &mut self, place: MPlaceTy<'tcx, Tag>, atomic: AtomicReadOp + &self, place: MPlaceTy<'tcx, Tag>, atomic: AtomicReadOp ) -> InterpResult<'tcx> { - let this = self.eval_context_mut(); + let this = self.eval_context_ref(); let data_race = &*this.memory.extra.data_race; if data_race.multi_threaded.get() { - data_race.advance_vector_clock(); - let ( - alloc, size, offset - ) = this.load_data_race_state_ref(place)?; + // Load an log the atomic operation + // the memory access has to be `get_raw` since otherwise this despite only + // mutating MemoryExtra will still trigger errors on read-only memory + let place_ptr = place.ptr.assert_ptr(); + let size = place.layout.size; + let alloc_meta = &this.memory.get_raw(place_ptr.alloc_id)?.extra.data_race; log::trace!( - "Atomic load on {:?} with ordering {:?}, in memory({:?}, offset={}, size={})", - alloc.global.current_thread(), atomic, - place.ptr.assert_ptr().alloc_id, offset.bytes(), size.bytes() + "Atomic op({}) with ordering {:?} on memory({:?}, offset={}, size={})", + "Atomic load", &atomic, place_ptr.alloc_id, place_ptr.offset.bytes(), size.bytes() ); - let current_thread = alloc.global.current_thread(); - let mut current_state = alloc.global.current_thread_state_mut(); - if atomic == AtomicReadOp::Relaxed { - // Perform relaxed atomic load - for (_,range) in alloc.alloc_ranges.borrow_mut().iter_mut(offset, size) { - if range.load_relaxed(&mut *current_state, current_thread) == Err(DataRace) { - mem::drop(current_state); + // Perform the atomic operation + let data_race = &alloc_meta.global; + data_race.maybe_perform_sync_operation(move |index, mut clocks| { + for (_,range) in alloc_meta.alloc_ranges.borrow_mut().iter_mut(place_ptr.offset, size) { + let res = if atomic == AtomicReadOp::Relaxed { + range.load_relaxed(&mut *clocks, index) + }else{ + range.acquire(&mut *clocks, index) + }; + if let Err(DataRace) = res { + mem::drop(clocks); return VClockAlloc::report_data_race( - &alloc.global, range, "ATOMIC_LOAD", true, - place.ptr.assert_ptr(), size + &alloc_meta.global, range, "Atomic load", true, + place_ptr, size ); } } - }else{ - // Perform acquire(or seq-cst) atomic load - for (_,range) in alloc.alloc_ranges.borrow_mut().iter_mut(offset, size) { - if range.acquire(&mut *current_state, current_thread) == Err(DataRace) { - mem::drop(current_state); - return VClockAlloc::report_data_race( - &alloc.global, range, "ATOMIC_LOAD", true, - place.ptr.assert_ptr(), size - ); - } - } - } + Ok(()) + })?; // Log changes to atomic memory if log::log_enabled!(log::Level::Trace) { - for (_,range) in alloc.alloc_ranges.borrow_mut().iter(offset, size) { + for (_,range) in alloc_meta.alloc_ranges.borrow().iter(place_ptr.offset, size) { log::trace!( - " updated atomic memory({:?}, offset={}, size={}) to {:#?}", - place.ptr.assert_ptr().alloc_id, offset.bytes(), size.bytes(), + "Updated atomic memory({:?}, offset={}, size={}) to {:#?}", + place.ptr.assert_ptr().alloc_id, place_ptr.offset.bytes(), size.bytes(), range.atomic_ops ); } } - - mem::drop(current_state); - let data_race = &*this.memory.extra.data_race; - data_race.advance_vector_clock(); } Ok(()) } @@ -271,61 +213,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { &mut self, place: MPlaceTy<'tcx, Tag>, atomic: AtomicWriteOp ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - let data_race = &*this.memory.extra.data_race; - if data_race.multi_threaded.get() { - data_race.advance_vector_clock(); - - let ( - alloc, size, offset - ) = this.load_data_race_state_mut(place)?; - let current_thread = alloc.global.current_thread(); - let mut current_state = alloc.global.current_thread_state_mut(); - log::trace!( - "Atomic store on {:?} with ordering {:?}, in memory({:?}, offset={}, size={})", - current_thread, atomic, - place.ptr.assert_ptr().alloc_id, offset.bytes(), size.bytes() - ); - - if atomic == AtomicWriteOp::Relaxed { - // Perform relaxed atomic store - for (_,range) in alloc.alloc_ranges.get_mut().iter_mut(offset, size) { - if range.store_relaxed(&mut *current_state, current_thread) == Err(DataRace) { - mem::drop(current_state); - return VClockAlloc::report_data_race( - &alloc.global, range, "ATOMIC_STORE", true, - place.ptr.assert_ptr(), size - ); - } - } - }else{ - // Perform release(or seq-cst) atomic store - for (_,range) in alloc.alloc_ranges.get_mut().iter_mut(offset, size) { - if range.release(&mut *current_state, current_thread) == Err(DataRace) { - mem::drop(current_state); - return VClockAlloc::report_data_race( - &alloc.global, range, "ATOMIC_STORE", true, - place.ptr.assert_ptr(), size - ); - } - } - } - - // Log changes to atomic memory - if log::log_enabled!(log::Level::Trace) { - for (_,range) in alloc.alloc_ranges.get_mut().iter(offset, size) { - log::trace!( - " updated atomic memory({:?}, offset={}, size={}) to {:#?}", - place.ptr.assert_ptr().alloc_id, offset.bytes(), size.bytes(), - range.atomic_ops - ); + this.validate_atomic_op_mut( + place, atomic, "Atomic Store", + move |memory, clocks, index, atomic| { + if atomic == AtomicWriteOp::Relaxed { + memory.store_relaxed(clocks, index) + }else{ + memory.release(clocks, index) } } - - mem::drop(current_state); - let data_race = &*this.memory.extra.data_race; - data_race.advance_vector_clock(); - } - Ok(()) + ) } /// Update the data-race detector for an atomic read-modify-write occuring @@ -334,97 +231,104 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { &mut self, place: MPlaceTy<'tcx, Tag>, atomic: AtomicRWOp ) -> InterpResult<'tcx> { use AtomicRWOp::*; + let acquire = matches!(atomic, Acquire | AcqRel | SeqCst); + let release = matches!(atomic, Release | AcqRel | SeqCst); let this = self.eval_context_mut(); - let data_race = &*this.memory.extra.data_race; - if data_race.multi_threaded.get() { - data_race.advance_vector_clock(); - - let ( - alloc, size, offset - ) = this.load_data_race_state_mut(place)?; - let current_thread = alloc.global.current_thread(); - let mut current_state = alloc.global.current_thread_state_mut(); - log::trace!( - "Atomic RMW on {:?} with ordering {:?}, in memory({:?}, offset={}, size={})", - current_thread, atomic, - place.ptr.assert_ptr().alloc_id, offset.bytes(), size.bytes() - ); - - let acquire = matches!(atomic, Acquire | AcqRel | SeqCst); - let release = matches!(atomic, Release | AcqRel | SeqCst); - for (_,range) in alloc.alloc_ranges.get_mut().iter_mut(offset, size) { - //FIXME: this is probably still slightly wrong due to the quirks - // in the c++11 memory model - let maybe_race = if acquire { - // Atomic RW-Op acquire - range.acquire(&mut *current_state, current_thread) + this.validate_atomic_op_mut( + place, atomic, "Atomic RMW", + move |memory, clocks, index, _| { + if acquire { + memory.acquire(clocks, index)?; }else{ - range.load_relaxed(&mut *current_state, current_thread) - }; - if maybe_race == Err(DataRace) { - mem::drop(current_state); - return VClockAlloc::report_data_race( - &alloc.global, range, "ATOMIC_RMW(LOAD)", true, - place.ptr.assert_ptr(), size - ); + memory.load_relaxed(clocks, index)?; } - let maybe_race = if release { - // Atomic RW-Op release - range.rmw_release(&mut *current_state, current_thread) + if release { + memory.rmw_release(clocks, index) }else{ - range.rmw_relaxed(&mut *current_state, current_thread) - }; - if maybe_race == Err(DataRace) { - mem::drop(current_state); - return VClockAlloc::report_data_race( - &alloc.global, range, "ATOMIC_RMW(STORE)", true, - place.ptr.assert_ptr(), size - ); + memory.rmw_relaxed(clocks, index) } } - - // Log changes to atomic memory - if log::log_enabled!(log::Level::Trace) { - for (_,range) in alloc.alloc_ranges.get_mut().iter(offset, size) { - log::trace!( - " updated atomic memory({:?}, offset={}, size={}) to {:#?}", - place.ptr.assert_ptr().alloc_id, offset.bytes(), size.bytes(), - range.atomic_ops - ); - } - } - - mem::drop(current_state); - let data_race = &*this.memory.extra.data_race; - data_race.advance_vector_clock(); - } - Ok(()) + ) } /// Update the data-race detector for an atomic fence on the current thread fn validate_atomic_fence(&mut self, atomic: AtomicFenceOp) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let data_race = &*this.memory.extra.data_race; - if data_race.multi_threaded.get() { - data_race.advance_vector_clock(); - - log::trace!("Atomic fence on {:?} with ordering {:?}", data_race.current_thread(), atomic); + data_race.maybe_perform_sync_operation(move |index, mut clocks| { + log::trace!("Atomic fence on {:?} with ordering {:?}", index, atomic); // Apply data-race detection for the current fences // this treats AcqRel and SeqCst as the same as a acquire // and release fence applied in the same timestamp. if atomic != AtomicFenceOp::Release { // Either Acquire | AcqRel | SeqCst - data_race.current_thread_state_mut().apply_acquire_fence(); + clocks.apply_acquire_fence(); } if atomic != AtomicFenceOp::Acquire { // Either Release | AcqRel | SeqCst - data_race.current_thread_state_mut().apply_release_fence(); + clocks.apply_release_fence(); } + Ok(()) + }) + } +} - data_race.advance_vector_clock(); +impl<'mir, 'tcx: 'mir> EvalContextPrivExt<'mir, 'tcx> for MiriEvalContext<'mir, 'tcx> {} +trait EvalContextPrivExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { + + /// Generic atomic operation implementation, this however + /// cannot be used for the atomic read operation since + /// that requires non mutable memory access to not trigger + /// the writing to read-only memory errors during `get_raw_mut` + fn validate_atomic_op_mut( + &mut self, place: MPlaceTy<'tcx, Tag>, + atomic: A, description: &str, + mut op: impl FnMut( + &mut MemoryCellClocks, &mut ThreadClockSet, VectorIdx, A + ) -> Result<(), DataRace> + ) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + let data_race = &*this.memory.extra.data_race; + if data_race.multi_threaded.get() { + + // Load an log the atomic operation + let place_ptr = place.ptr.assert_ptr(); + let size = place.layout.size; + let alloc_meta = &mut this.memory.get_raw_mut(place_ptr.alloc_id)?.extra.data_race; + log::trace!( + "Atomic op({}) with ordering {:?} on memory({:?}, offset={}, size={})", + description, &atomic, place_ptr.alloc_id, place_ptr.offset.bytes(), size.bytes() + ); + + // Perform the atomic operation + let data_race = &alloc_meta.global; + data_race.maybe_perform_sync_operation(|index, mut clocks| { + for (_,range) in alloc_meta.alloc_ranges.borrow_mut().iter_mut(place_ptr.offset, size) { + if let Err(DataRace) = op(range, &mut *clocks, index, atomic) { + mem::drop(clocks); + return VClockAlloc::report_data_race( + &alloc_meta.global, range, description, true, + place_ptr, size + ); + } + } + Ok(()) + })?; + + // Log changes to atomic memory + if log::log_enabled!(log::Level::Trace) { + for (_,range) in alloc_meta.alloc_ranges.borrow().iter(place_ptr.offset, size) { + log::trace!( + "Updated atomic memory({:?}, offset={}, size={}) to {:#?}", + place.ptr.assert_ptr().alloc_id, place_ptr.offset.bytes(), size.bytes(), + range.atomic_ops + ); + } + } } Ok(()) } + } /// Handle for locks to express their @@ -439,7 +343,7 @@ pub struct DataRaceLockHandle { } impl DataRaceLockHandle { pub fn set_values(&mut self, other: &Self) { - self.clock.set_values(&other.clock) + self.clock.clone_from(&other.clock) } pub fn reset(&mut self) { self.clock.set_zero_vector(); @@ -447,126 +351,6 @@ impl DataRaceLockHandle { } -/// Avoid an atomic allocation for the common -/// case with atomic operations where the number -/// of active release sequences is small -#[derive(Clone, PartialEq, Eq)] -enum AtomicReleaseSequences { - - /// Contains one or no values - /// if empty: (None, reset vector clock) - /// if one: (Some(thread), thread_clock) - ReleaseOneOrEmpty(Option, VClock), - - /// Contains two or more values - /// stored in a hash-map of thread id to - /// vector clocks - ReleaseMany(FxHashMap) -} -impl AtomicReleaseSequences { - - /// Return an empty set of atomic release sequences - #[inline] - fn new() -> AtomicReleaseSequences { - Self::ReleaseOneOrEmpty(None, VClock::default()) - } - - /// Remove all values except for the value stored at `thread` and set - /// the vector clock to the associated `clock` value - #[inline] - fn clear_and_set(&mut self, thread: ThreadId, clock: &VClock) { - match self { - Self::ReleaseOneOrEmpty(id, rel_clock) => { - *id = Some(thread); - rel_clock.set_values(clock); - } - Self::ReleaseMany(_) => { - *self = Self::ReleaseOneOrEmpty(Some(thread), clock.clone()); - } - } - } - - /// Remove all values except for the value stored at `thread` - #[inline] - fn clear_and_retain(&mut self, thread: ThreadId) { - match self { - Self::ReleaseOneOrEmpty(id, rel_clock) => { - // If the id is the same, then reatin the value - // otherwise delete and clear the release vector clock - if *id != Some(thread) { - *id = None; - rel_clock.set_zero_vector(); - } - }, - Self::ReleaseMany(hash_map) => { - // Retain only the thread element, so reduce to size - // of 1 or 0, and move to smaller format - if let Some(clock) = hash_map.remove(&thread) { - *self = Self::ReleaseOneOrEmpty(Some(thread), clock); - }else{ - *self = Self::new(); - } - } - } - } - - /// Insert a release sequence at `thread` with values `clock` - fn insert(&mut self, thread: ThreadId, clock: &VClock) { - match self { - Self::ReleaseOneOrEmpty(id, rel_clock) => { - if id.map_or(true, |id| id == thread) { - *id = Some(thread); - rel_clock.set_values(clock); - }else{ - let mut hash_map = FxHashMap::default(); - hash_map.insert(thread, clock.clone()); - hash_map.insert(id.unwrap(), rel_clock.clone()); - *self = Self::ReleaseMany(hash_map); - } - }, - Self::ReleaseMany(hash_map) => { - hash_map.insert(thread, clock.clone()); - } - } - } - - /// Return the release sequence at `thread` if one exists - #[inline] - fn load(&self, thread: ThreadId) -> Option<&VClock> { - match self { - Self::ReleaseOneOrEmpty(id, clock) => { - if *id == Some(thread) { - Some(clock) - }else{ - None - } - }, - Self::ReleaseMany(hash_map) => { - hash_map.get(&thread) - } - } - } -} - -/// Custom debug implementation to correctly -/// print debug as a logical mapping from threads -/// to vector-clocks -impl Debug for AtomicReleaseSequences { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - Self::ReleaseOneOrEmpty(None,_) => { - f.debug_map().finish() - }, - Self::ReleaseOneOrEmpty(Some(id), clock) => { - f.debug_map().entry(&id, &clock).finish() - }, - Self::ReleaseMany(hash_map) => { - Debug::fmt(hash_map, f) - } - } - } -} - /// Error returned by finding a data race /// should be elaborated upon #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] @@ -576,7 +360,7 @@ pub struct DataRace; /// explicitly to reduce memory usage for the /// common case where no atomic operations /// exists on the memory cell -#[derive(Clone, PartialEq, Eq, Debug)] +#[derive(Clone, PartialEq, Eq, Default, Debug)] struct AtomicMemoryCellClocks { /// The clock-vector for the set of atomic read operations @@ -599,7 +383,7 @@ struct AtomicMemoryCellClocks { /// sequence exists in the memory cell, required /// since read-modify-write operations do not /// invalidate existing release sequences - release_sequences: AtomicReleaseSequences, + release_sequences: VSmallClockSet, } /// Memory Cell vector clock metadata @@ -609,11 +393,11 @@ struct MemoryCellClocks { /// The vector-clock of the last write, only one value is stored /// since all previous writes happened-before the current write - write: Timestamp, + write: VTimestamp, /// The identifier of the thread that performed the last write /// operation - write_thread: ThreadId, + write_index: VectorIdx, /// The vector-clock of the set of previous reads /// each index is set to the timestamp that the associated @@ -633,7 +417,7 @@ impl Default for MemoryCellClocks { MemoryCellClocks { read: VClock::default(), write: 0, - write_thread: ThreadId::new(u32::MAX as usize), + write_index: VectorIdx::MAX_INDEX, atomic_ops: None } } @@ -654,21 +438,14 @@ impl MemoryCellClocks { /// if it does not exist #[inline] fn atomic_mut(&mut self) -> &mut AtomicMemoryCellClocks { - self.atomic_ops.get_or_insert_with(|| { - Box::new(AtomicMemoryCellClocks { - read_vector: VClock::default(), - write_vector: VClock::default(), - sync_vector: VClock::default(), - release_sequences: AtomicReleaseSequences::new() - }) - }) + self.atomic_ops.get_or_insert_with(Default::default) } /// Update memory cell data-race tracking for atomic /// load acquire semantics, is a no-op if this memory was /// not used previously as atomic memory - fn acquire(&mut self, clocks: &mut ThreadClockSet, thread: ThreadId) -> Result<(), DataRace> { - self.atomic_read_detect(clocks, thread)?; + fn acquire(&mut self, clocks: &mut ThreadClockSet, index: VectorIdx) -> Result<(), DataRace> { + self.atomic_read_detect(clocks, index)?; if let Some(atomic) = self.atomic() { clocks.clock.join(&atomic.sync_vector); } @@ -677,8 +454,8 @@ impl MemoryCellClocks { /// Update memory cell data-race tracking for atomic /// load relaxed semantics, is a no-op if this memory was /// not used previously as atomic memory - fn load_relaxed(&mut self, clocks: &mut ThreadClockSet, thread: ThreadId) -> Result<(), DataRace> { - self.atomic_read_detect(clocks, thread)?; + fn load_relaxed(&mut self, clocks: &mut ThreadClockSet, index: VectorIdx) -> Result<(), DataRace> { + self.atomic_read_detect(clocks, index)?; if let Some(atomic) = self.atomic() { clocks.fence_acquire.join(&atomic.sync_vector); } @@ -688,38 +465,39 @@ impl MemoryCellClocks { /// Update the memory cell data-race tracking for atomic /// store release semantics - fn release(&mut self, clocks: &ThreadClockSet, thread: ThreadId) -> Result<(), DataRace> { - self.atomic_write_detect(clocks, thread)?; + fn release(&mut self, clocks: &ThreadClockSet, index: VectorIdx) -> Result<(), DataRace> { + self.atomic_write_detect(clocks, index)?; let atomic = self.atomic_mut(); - atomic.sync_vector.set_values(&clocks.clock); - atomic.release_sequences.clear_and_set(thread, &clocks.clock); + atomic.sync_vector.clone_from(&clocks.clock); + atomic.release_sequences.clear(); + atomic.release_sequences.insert(index, &clocks.clock); Ok(()) } /// Update the memory cell data-race tracking for atomic /// store relaxed semantics - fn store_relaxed(&mut self, clocks: &ThreadClockSet, thread: ThreadId) -> Result<(), DataRace> { - self.atomic_write_detect(clocks, thread)?; + fn store_relaxed(&mut self, clocks: &ThreadClockSet, index: VectorIdx) -> Result<(), DataRace> { + self.atomic_write_detect(clocks, index)?; let atomic = self.atomic_mut(); - atomic.sync_vector.set_values(&clocks.fence_release); - if let Some(release) = atomic.release_sequences.load(thread) { + atomic.sync_vector.clone_from(&clocks.fence_release); + if let Some(release) = atomic.release_sequences.get(index) { atomic.sync_vector.join(release); } - atomic.release_sequences.clear_and_retain(thread); + atomic.release_sequences.retain_index(index); Ok(()) } /// Update the memory cell data-race tracking for atomic /// store release semantics for RMW operations - fn rmw_release(&mut self, clocks: &ThreadClockSet, thread: ThreadId) -> Result<(), DataRace> { - self.atomic_write_detect(clocks, thread)?; + fn rmw_release(&mut self, clocks: &ThreadClockSet, index: VectorIdx) -> Result<(), DataRace> { + self.atomic_write_detect(clocks, index)?; let atomic = self.atomic_mut(); atomic.sync_vector.join(&clocks.clock); - atomic.release_sequences.insert(thread, &clocks.clock); + atomic.release_sequences.insert(index, &clocks.clock); Ok(()) } /// Update the memory cell data-race tracking for atomic /// store relaxed semantics for RMW operations - fn rmw_relaxed(&mut self, clocks: &ThreadClockSet, thread: ThreadId) -> Result<(), DataRace> { - self.atomic_write_detect(clocks, thread)?; + fn rmw_relaxed(&mut self, clocks: &ThreadClockSet, index: VectorIdx) -> Result<(), DataRace> { + self.atomic_write_detect(clocks, index)?; let atomic = self.atomic_mut(); atomic.sync_vector.join(&clocks.fence_release); Ok(()) @@ -727,11 +505,11 @@ impl MemoryCellClocks { /// Detect data-races with an atomic read, caused by a non-atomic write that does /// not happen-before the atomic-read - fn atomic_read_detect(&mut self, clocks: &ThreadClockSet, thread: ThreadId) -> Result<(), DataRace> { + fn atomic_read_detect(&mut self, clocks: &ThreadClockSet, index: VectorIdx) -> Result<(), DataRace> { log::trace!("Atomic read with vectors: {:#?} :: {:#?}", self, clocks); - if self.write <= clocks.clock[self.write_thread] { + if self.write <= clocks.clock[self.write_index] { let atomic = self.atomic_mut(); - atomic.read_vector.set_at_thread(&clocks.clock, thread); + atomic.read_vector.set_at_index(&clocks.clock, index); Ok(()) }else{ Err(DataRace) @@ -740,11 +518,11 @@ impl MemoryCellClocks { /// Detect data-races with an atomic write, either with a non-atomic read or with /// a non-atomic write: - fn atomic_write_detect(&mut self, clocks: &ThreadClockSet, thread: ThreadId) -> Result<(), DataRace> { + fn atomic_write_detect(&mut self, clocks: &ThreadClockSet, index: VectorIdx) -> Result<(), DataRace> { log::trace!("Atomic write with vectors: {:#?} :: {:#?}", self, clocks); - if self.write <= clocks.clock[self.write_thread] && self.read <= clocks.clock { + if self.write <= clocks.clock[self.write_index] && self.read <= clocks.clock { let atomic = self.atomic_mut(); - atomic.write_vector.set_at_thread(&clocks.clock, thread); + atomic.write_vector.set_at_index(&clocks.clock, index); Ok(()) }else{ Err(DataRace) @@ -753,16 +531,16 @@ impl MemoryCellClocks { /// Detect races for non-atomic read operations at the current memory cell /// returns true if a data-race is detected - fn read_race_detect(&mut self, clocks: &ThreadClockSet, thread: ThreadId) -> Result<(), DataRace> { + fn read_race_detect(&mut self, clocks: &ThreadClockSet, index: VectorIdx) -> Result<(), DataRace> { log::trace!("Unsynchronized read with vectors: {:#?} :: {:#?}", self, clocks); - if self.write <= clocks.clock[self.write_thread] { + if self.write <= clocks.clock[self.write_index] { let race_free = if let Some(atomic) = self.atomic() { atomic.write_vector <= clocks.clock }else{ true }; if race_free { - self.read.set_at_thread(&clocks.clock, thread); + self.read.set_at_index(&clocks.clock, index); Ok(()) }else{ Err(DataRace) @@ -774,17 +552,17 @@ impl MemoryCellClocks { /// Detect races for non-atomic write operations at the current memory cell /// returns true if a data-race is detected - fn write_race_detect(&mut self, clocks: &ThreadClockSet, thread: ThreadId) -> Result<(), DataRace> { + fn write_race_detect(&mut self, clocks: &ThreadClockSet, index: VectorIdx) -> Result<(), DataRace> { log::trace!("Unsynchronized write with vectors: {:#?} :: {:#?}", self, clocks); - if self.write <= clocks.clock[self.write_thread] && self.read <= clocks.clock { + if self.write <= clocks.clock[self.write_index] && self.read <= clocks.clock { let race_free = if let Some(atomic) = self.atomic() { atomic.write_vector <= clocks.clock && atomic.read_vector <= clocks.clock }else{ true }; if race_free { - self.write = clocks.clock[thread]; - self.write_thread = thread; + self.write = clocks.clock[index]; + self.write_index = index; self.read.set_zero_vector(); Ok(()) }else{ @@ -822,7 +600,7 @@ impl VClockAlloc { // Find an index, if one exists where the value // in `l` is greater than the value in `r` - fn find_gt_index(l: &VClock, r: &VClock) -> Option { + fn find_gt_index(l: &VClock, r: &VClock) -> Option { let l_slice = l.as_slice(); let r_slice = r.as_slice(); l_slice.iter().zip(r_slice.iter()) @@ -844,7 +622,7 @@ impl VClockAlloc { }else{ None } - }) + }).map(|idx| VectorIdx::new(idx)) } /// Report a data-race found in the program @@ -859,35 +637,29 @@ impl VClockAlloc { action: &str, is_atomic: bool, pointer: Pointer, len: Size ) -> InterpResult<'tcx> { - let current_thread = global.current_thread(); - let current_state = global.current_thread_state(); - let mut write_clock = VClock::default(); + let (current_index, current_clocks) = global.current_thread_state(); + let write_clock; let ( other_action, other_thread, other_clock - ) = if range.write > current_state.clock[range.write_thread] { - + ) = if range.write > current_clocks.clock[range.write_index] { // Convert the write action into the vector clock it // represents for diagnostic purposes - let wclock = write_clock.get_mut_with_min_len( - current_state.clock.as_slice().len() - .max(range.write_thread.to_u32() as usize + 1) - ); - wclock[range.write_thread.to_u32() as usize] = range.write; - ("WRITE", range.write_thread, write_clock.as_slice()) + write_clock = VClock::new_with_index(range.write_index, range.write); + ("WRITE", range.write_index, &write_clock) }else if let Some(idx) = Self::find_gt_index( - &range.read, ¤t_state.clock + &range.read, ¤t_clocks.clock ){ - ("READ", ThreadId::new(idx), range.read.as_slice()) + ("READ", idx, &range.read) }else if !is_atomic { if let Some(atomic) = range.atomic() { if let Some(idx) = Self::find_gt_index( - &atomic.write_vector, ¤t_state.clock + &atomic.write_vector, ¤t_clocks.clock ) { - ("ATOMIC_STORE", ThreadId::new(idx), atomic.write_vector.as_slice()) + ("ATOMIC_STORE", idx, &atomic.write_vector) }else if let Some(idx) = Self::find_gt_index( - &atomic.read_vector, ¤t_state.clock + &atomic.read_vector, ¤t_clocks.clock ) { - ("ATOMIC_LOAD", ThreadId::new(idx), atomic.read_vector.as_slice()) + ("ATOMIC_LOAD", idx, &atomic.read_vector) }else{ unreachable!("Failed to find report data-race for non-atomic operation: no race found") } @@ -899,7 +671,7 @@ impl VClockAlloc { }; // Load elaborated thread information about the racing thread actions - let current_thread_info = global.print_thread_metadata(current_thread); + let current_thread_info = global.print_thread_metadata(current_index); let other_thread_info = global.print_thread_metadata(other_thread); // Throw the data-race detection @@ -910,7 +682,7 @@ impl VClockAlloc { action, current_thread_info, other_action, other_thread_info, pointer.alloc_id, pointer.offset.bytes(), len.bytes(), - current_state.clock, + current_clocks.clock, other_clock ) } @@ -921,14 +693,10 @@ impl VClockAlloc { /// operation pub fn read<'tcx>(&self, pointer: Pointer, len: Size) -> InterpResult<'tcx> { if self.global.multi_threaded.get() { - let current_thread = self.global.current_thread(); - let current_state = self.global.current_thread_state(); - - // The alloc-ranges are not split, however changes are not going to be made - // to the ranges being tested, so this is ok + let (index, clocks) = self.global.current_thread_state(); let mut alloc_ranges = self.alloc_ranges.borrow_mut(); for (_,range) in alloc_ranges.iter_mut(pointer.offset, len) { - if range.read_race_detect(&*current_state, current_thread) == Err(DataRace) { + if range.read_race_detect(&*clocks, index) == Err(DataRace) { // Report data-race return Self::report_data_race( &self.global,range, "READ", false, pointer, len @@ -946,10 +714,9 @@ impl VClockAlloc { /// operation pub fn write<'tcx>(&mut self, pointer: Pointer, len: Size) -> InterpResult<'tcx> { if self.global.multi_threaded.get() { - let current_thread = self.global.current_thread(); - let current_state = self.global.current_thread_state(); + let (index, clocks) = self.global.current_thread_state(); for (_,range) in self.alloc_ranges.get_mut().iter_mut(pointer.offset, len) { - if range.write_race_detect(&*current_state, current_thread) == Err(DataRace) { + if range.write_race_detect(&*clocks, index) == Err(DataRace) { // Report data-race return Self::report_data_race( &self.global, range, "WRITE", false, pointer, len @@ -967,10 +734,9 @@ impl VClockAlloc { /// operation pub fn deallocate<'tcx>(&mut self, pointer: Pointer, len: Size) -> InterpResult<'tcx> { if self.global.multi_threaded.get() { - let current_thread = self.global.current_thread(); - let current_state = self.global.current_thread_state(); + let (index, clocks) = self.global.current_thread_state(); for (_,range) in self.alloc_ranges.get_mut().iter_mut(pointer.offset, len) { - if range.write_race_detect(&*current_state, current_thread) == Err(DataRace) { + if range.write_race_detect(&*clocks, index) == Err(DataRace) { // Report data-race return Self::report_data_race( &self.global, range, "DEALLOCATE", false, pointer, len @@ -989,6 +755,7 @@ impl VClockAlloc { /// additional metadata to model atomic fence operations #[derive(Clone, Default, Debug)] struct ThreadClockSet { + /// The increasing clock representing timestamps /// that happen-before this thread. clock: VClock, @@ -1008,7 +775,7 @@ impl ThreadClockSet { /// set of thread vector clocks #[inline] fn apply_release_fence(&mut self) { - self.fence_release.set_values(&self.clock); + self.fence_release.clone_from(&self.clock); } /// Apply the effects of a acquire fence to this @@ -1021,8 +788,8 @@ impl ThreadClockSet { /// Increment the happens-before clock at a /// known index #[inline] - fn increment_clock(&mut self, thread: ThreadId) { - self.clock.increment_thread(thread); + fn increment_clock(&mut self, index: VectorIdx) { + self.clock.increment_index(index); } /// Join the happens-before clock with that of @@ -1047,81 +814,178 @@ pub struct GlobalState { /// any data-races multi_threaded: Cell, - /// The current vector clock for all threads - /// this includes threads that have terminated - /// execution - thread_clocks: RefCell>, + /// Mapping of a vector index to a known set of thread + /// clocks, this is not directly mapping from a thread id + /// since it may refer to multiple threads + vector_clocks: RefCell>, + + /// Mapping of a given vector index to the current thread + /// that the execution is representing, this may change + /// if a vector index is re-assigned to a new thread + vector_info: RefCell>, //FIXME: make option + + /// The mapping of a given thread to a known vector clock + thread_info: RefCell, Option>)>>, - /// Thread name cache for better diagnostics on the reporting - /// of a data-race - thread_names: RefCell>>>, + /// The current vector index being executed + current_index: Cell, - /// The current thread being executed, - /// this is mirrored from the scheduler since - /// it is required for loading the current vector - /// clock for data-race detection - current_thread_id: Cell, + /// Potential vector indices that could be re-used on thread creation + /// values are inserted here on thread join events, and can be + /// re-used once the vector clocks of all current threads + /// are equal to the vector clock of the joined thread + reuse_candidates: RefCell>, } impl GlobalState { /// Create a new global state, setup with just thread-id=0 /// advanced to timestamp = 1 pub fn new() -> Self { - let mut vec = IndexVec::new(); - let thread_id = vec.push(ThreadClockSet::default()); - vec[thread_id].increment_clock(thread_id); - GlobalState { + let global_state = GlobalState { multi_threaded: Cell::new(false), - thread_clocks: RefCell::new(vec), - thread_names: RefCell::new(IndexVec::new()), - current_thread_id: Cell::new(thread_id), - } + vector_clocks: RefCell::new(IndexVec::new()), + vector_info: RefCell::new(IndexVec::new()), + thread_info: RefCell::new(IndexVec::new()), + current_index: Cell::new(VectorIdx::new(0)), + reuse_candidates: RefCell::new(FxHashSet::default()), + }; + + // Setup the main-thread since it is not explicitly created: + // uses vector index and thread-id 0, also the rust runtime gives + // the main-thread a name of "main". + let index = global_state.vector_clocks.borrow_mut().push(ThreadClockSet::default()); + global_state.vector_info.borrow_mut().push(ThreadId::new(0)); + global_state.thread_info.borrow_mut().push( + (Some(index), Some("main".to_string().into_boxed_str()) + )); + + global_state } + // Try to find vector index values that can potentially be re-used + // by a new thread instead of a new vector index being created + fn find_vector_index_reuse_candidate(&self) -> Option { + let mut reuse = self.reuse_candidates.borrow_mut(); + let vector_clocks = self.vector_clocks.borrow(); + for &candidate in reuse.iter() { + let target_timestamp = vector_clocks[candidate].clock[candidate]; + if vector_clocks.iter().all(|clock| { + clock.clock[candidate] == target_timestamp + }) { + // All vector clocks for each vector index are equal to + // the target timestamp, therefore since the thread has + // terminated and cannot update the vector clock. + // No more data-races involving this vector index are possible + // so it can be re-used + assert!(reuse.remove(&candidate)); + return Some(candidate) + } + } + None + } // Hook for thread creation, enabled multi-threaded execution and marks // the current thread timestamp as happening-before the current thread #[inline] pub fn thread_created(&self, thread: ThreadId) { + let current_index = self.current_index(); - // Enable multi-threaded execution mode now that there are at least - // two threads + // Enable multi-threaded execution, there are now two threads + // so data-races are now possible. self.multi_threaded.set(true); - let current_thread = self.current_thread_id.get(); - let mut vectors = self.thread_clocks.borrow_mut(); - vectors.ensure_contains_elem(thread, Default::default); - let (current, created) = vectors.pick2_mut(current_thread, thread); - // Pre increment clocks before atomic operation - current.increment_clock(current_thread); + // Load and setup the associated thread metadata + let mut thread_info = self.thread_info.borrow_mut(); + thread_info.ensure_contains_elem(thread, Default::default); + + // Assign a vector index for the thread, attempting to re-use an old + // vector index that can no longer report any data-races if possible + let created_index = if let Some( + reuse_index + ) = self.find_vector_index_reuse_candidate() { + // Now re-configure the re-use candidate, increment the clock + // for the new sync use of the vector + let mut vector_clocks = self.vector_clocks.borrow_mut(); + vector_clocks[reuse_index].increment_clock(reuse_index); + + // Locate the old thread the vector was associated with and update + // it to represent the new thread instead + let mut vector_info = self.vector_info.borrow_mut(); + let old_thread = vector_info[reuse_index]; + vector_info[reuse_index] = thread; + + // Mark the thread the vector index was associated with as no longer + // representing a thread index + thread_info[old_thread].0 = None; + + reuse_index + }else{ + // No vector re-use candidates available, instead create + // a new vector index + let mut vector_info = self.vector_info.borrow_mut(); + vector_info.push(thread) + }; + + // Mark the chosen vector index as in use by the thread + thread_info[thread].0 = Some(created_index); + + // Create a thread clock set if applicable + let mut vector_clocks = self.vector_clocks.borrow_mut(); + if created_index == vector_clocks.next_index() { + vector_clocks.push(ThreadClockSet::default()); + } - // The current thread happens-before the created thread - // so update the created vector clock + // Now load the two clocks and configure the initial state + let (current, created) = vector_clocks.pick2_mut(current_index, created_index); + + // Advance the current thread before the synchronized operation + current.increment_clock(current_index); + + // Join the created with current, since the current threads + // previous actions happen-before the created thread created.join_with(current); - // Post increment clocks after atomic operation - current.increment_clock(current_thread); - created.increment_clock(thread); + // Advance both threads after the synchronized operation + current.increment_clock(current_index); + created.increment_clock(created_index); } /// Hook on a thread join to update the implicit happens-before relation - /// between the joined thead and the current thread + /// between the joined thead and the current thread. + /// Called after the join has occured, and hence implicitly also states + /// that the thread must have terminated as well #[inline] pub fn thread_joined(&self, current_thread: ThreadId, join_thread: ThreadId) { - let mut vectors = self.thread_clocks.borrow_mut(); - let (current, join) = vectors.pick2_mut(current_thread, join_thread); + let (current_index, join_index) = { + let thread_info = self.thread_info.borrow(); + let current_index = thread_info[current_thread].0 + .expect("Joining into thread with no assigned vector"); + let join_index = thread_info[join_thread].0 + .expect("Joining thread with no assigned vector"); + (current_index, join_index) + }; + let mut clocks_vec = self.vector_clocks.borrow_mut(); + let (current, join) = clocks_vec.pick2_mut(current_index, join_index); // Pre increment clocks before atomic operation - current.increment_clock(current_thread); - join.increment_clock(join_thread); + current.increment_clock(current_index); + join.increment_clock(join_index); // The join thread happens-before the current thread // so update the current vector clock current.join_with(join); // Post increment clocks after atomic operation - current.increment_clock(current_thread); - join.increment_clock(join_thread); + current.increment_clock(current_index); + join.increment_clock(join_index); + + // The joined thread vector clock is a potential candidate + // for re-use given sufficient time, mark as available once + // threads have been created. This is because this function + // is called once join_thread has terminated and such cannot + // update any-more + let mut reuse = self.reuse_candidates.borrow_mut(); + reuse.insert(join_index); } /// Hook for updating the local tracker of the currently @@ -1129,7 +993,10 @@ impl GlobalState { /// `active_thread` in thread.rs is updated #[inline] pub fn thread_set_active(&self, thread: ThreadId) { - self.current_thread_id.set(thread); + let thread_info = self.thread_info.borrow(); + let vector_idx = thread_info[thread].0 + .expect("Setting thread active with no assigned vector"); + self.current_index.set(vector_idx); } /// Hook for updating the local tracker of the threads name @@ -1137,33 +1004,40 @@ impl GlobalState { /// the thread name is used for improved diagnostics /// during a data-race #[inline] - pub fn thread_set_name(&self, name: String) { + pub fn thread_set_name(&self, thread: ThreadId, name: String) { let name = name.into_boxed_str(); - let mut names = self.thread_names.borrow_mut(); - let thread = self.current_thread_id.get(); - names.ensure_contains_elem(thread, Default::default); - names[thread] = Some(name); + let mut thread_info = self.thread_info.borrow_mut(); + thread_info[thread].1 = Some(name); } - /// Advance the vector clock for a thread - /// this is called before and after any atomic/synchronizing operations - /// that may manipulate state - #[inline] - fn advance_vector_clock(&self) { - let thread = self.current_thread_id.get(); - let mut vectors = self.thread_clocks.borrow_mut(); - vectors[thread].increment_clock(thread); - - // Log the increment in the atomic vector clock - log::trace!("Atomic vector clock increase for {:?} to {:?}",thread, vectors[thread].clock); + /// Attempt to perform a synchronized operation, this + /// will perform no operation if multi-threading is + /// not currently enabled. + /// Otherwise it will increment the clock for the current + /// vector before and after the operation for data-race + /// detection between any happens-before edges the + /// operation may create + fn maybe_perform_sync_operation<'tcx>( + &self, op: impl FnOnce(VectorIdx, RefMut<'_,ThreadClockSet>) -> InterpResult<'tcx>, + ) -> InterpResult<'tcx> { + if self.multi_threaded.get() { + let (index, mut clocks) = self.current_thread_state_mut(); + clocks.increment_clock(index); + op(index, clocks)?; + let (_, mut clocks) = self.current_thread_state_mut(); + clocks.increment_clock(index); + } + Ok(()) } /// Internal utility to identify a thread stored internally /// returns the id and the name for better diagnostics - fn print_thread_metadata(&self, thread: ThreadId) -> String { - if let Some(Some(name)) = self.thread_names.borrow().get(thread) { + fn print_thread_metadata(&self, vector: VectorIdx) -> String { + let thread = self.vector_info.borrow()[vector]; + let thread_name = &self.thread_info.borrow()[thread].1; + if let Some(name) = thread_name { let name: &str = name; format!("Thread(id = {:?}, name = {:?})", thread.to_u32(), &*name) }else{ @@ -1175,25 +1049,19 @@ impl GlobalState { /// Acquire a lock, express that the previous call of /// `validate_lock_release` must happen before this pub fn validate_lock_acquire(&self, lock: &DataRaceLockHandle, thread: ThreadId) { - let mut ref_vector = self.thread_clocks.borrow_mut(); - ref_vector[thread].increment_clock(thread); - - let clocks = &mut ref_vector[thread]; + let (index, mut clocks) = self.load_thread_state_mut(thread); + clocks.increment_clock(index); clocks.clock.join(&lock.clock); - - ref_vector[thread].increment_clock(thread); + clocks.increment_clock(index); } /// Release a lock handle, express that this happens-before /// any subsequent calls to `validate_lock_acquire` pub fn validate_lock_release(&self, lock: &mut DataRaceLockHandle, thread: ThreadId) { - let mut ref_vector = self.thread_clocks.borrow_mut(); - ref_vector[thread].increment_clock(thread); - - let clocks = &ref_vector[thread]; - lock.clock.set_values(&clocks.clock); - - ref_vector[thread].increment_clock(thread); + let (index, mut clocks) = self.load_thread_state_mut(thread); + clocks.increment_clock(index); + lock.clock.clone_from(&clocks.clock); + clocks.increment_clock(index); } /// Release a lock handle, express that this happens-before @@ -1201,401 +1069,48 @@ impl GlobalState { /// as any previous calls to this function after any /// `validate_lock_release` calls pub fn validate_lock_release_shared(&self, lock: &mut DataRaceLockHandle, thread: ThreadId) { - let mut ref_vector = self.thread_clocks.borrow_mut(); - ref_vector[thread].increment_clock(thread); - - let clocks = &ref_vector[thread]; + let (index, mut clocks) = self.load_thread_state_mut(thread); + clocks.increment_clock(index); lock.clock.join(&clocks.clock); - - ref_vector[thread].increment_clock(thread); - } - - /// Load the thread clock set associated with the current thread - #[inline] - fn current_thread_state(&self) -> Ref<'_, ThreadClockSet> { - let ref_vector = self.thread_clocks.borrow(); - let thread = self.current_thread_id.get(); - Ref::map(ref_vector, |vector| &vector[thread]) - } - - /// Load the thread clock set associated with the current thread - /// mutably for modification - #[inline] - fn current_thread_state_mut(&self) -> RefMut<'_, ThreadClockSet> { - let ref_vector = self.thread_clocks.borrow_mut(); - let thread = self.current_thread_id.get(); - RefMut::map(ref_vector, |vector| &mut vector[thread]) - } - - /// Return the current thread, should be the same - /// as the data-race active thread - #[inline] - fn current_thread(&self) -> ThreadId { - self.current_thread_id.get() + clocks.increment_clock(index); } -} - - -/// The size of the vector-clock to store inline -/// clock vectors larger than this will be stored on the heap -const SMALL_VECTOR: usize = 4; - -/// The type of the time-stamps recorded in the data-race detector -/// set to a type of unsigned integer -type Timestamp = u32; - -/// A vector clock for detecting data-races -/// invariants: -/// - the last element in a VClock must not be 0 -/// -- this means that derive(PartialEq & Eq) is correct -/// -- as there is no implicit zero tail that might be equal -/// -- also simplifies the implementation of PartialOrd -#[derive(Clone, PartialEq, Eq, Default, Debug)] -pub struct VClock(SmallVec<[Timestamp; SMALL_VECTOR]>); - -impl VClock { - /// Load the backing slice behind the clock vector. + /// Load the vector index used by the given thread as well as the set of vector clocks + /// used by the thread #[inline] - fn as_slice(&self) -> &[Timestamp] { - self.0.as_slice() + fn load_thread_state_mut(&self, thread: ThreadId) -> (VectorIdx, RefMut<'_, ThreadClockSet>) { + let index = self.thread_info.borrow()[thread].0 + .expect("Loading thread state for thread with no assigned vector"); + let ref_vector = self.vector_clocks.borrow_mut(); + let clocks = RefMut::map(ref_vector, |vec| &mut vec[index]); + (index, clocks) } - /// Get a mutable slice to the internal vector with minimum `min_len` - /// elements, to preserve invariants this vector must modify - /// the `min_len`-1 nth element to a non-zero value + /// Load the current vector clock in use and the current set of thread clocks + /// in use for the vector #[inline] - fn get_mut_with_min_len(&mut self, min_len: usize) -> &mut [Timestamp] { - if self.0.len() < min_len { - self.0.resize(min_len, 0); - } - assert!(self.0.len() >= min_len); - self.0.as_mut_slice() + fn current_thread_state(&self) -> (VectorIdx, Ref<'_, ThreadClockSet>) { + let index = self.current_index(); + let ref_vector = self.vector_clocks.borrow(); + let clocks = Ref::map(ref_vector, |vec| &vec[index]); + (index, clocks) } - /// Increment the vector clock at a known index + /// Load the current vector clock in use and the current set of thread clocks + /// in use for the vector mutably for modification #[inline] - fn increment_index(&mut self, idx: usize) { - let mut_slice = self.get_mut_with_min_len(idx + 1); - let idx_ref = &mut mut_slice[idx]; - *idx_ref = idx_ref.checked_add(1).expect("Vector clock overflow") + fn current_thread_state_mut(&self) -> (VectorIdx, RefMut<'_, ThreadClockSet>) { + let index = self.current_index(); + let ref_vector = self.vector_clocks.borrow_mut(); + let clocks = RefMut::map(ref_vector, |vec| &mut vec[index]); + (index, clocks) } - // Increment the vector element representing the progress - // of execution in the given thread - #[inline] - pub fn increment_thread(&mut self, thread: ThreadId) { - self.increment_index(thread.to_u32() as usize); - } - - // Join the two vector-clocks together, this - // sets each vector-element to the maximum value - // of that element in either of the two source elements. - pub fn join(&mut self, other: &Self) { - let rhs_slice = other.as_slice(); - let lhs_slice = self.get_mut_with_min_len(rhs_slice.len()); - - // Element-wise set to maximum. - for (l, &r) in lhs_slice.iter_mut().zip(rhs_slice.iter()) { - *l = r.max(*l); - } - } - - /// Joins with a thread at a known index - fn set_at_index(&mut self, other: &Self, idx: usize){ - let mut_slice = self.get_mut_with_min_len(idx + 1); - let slice = other.as_slice(); - mut_slice[idx] = slice[idx]; - } - - /// Join with a threads vector clock only at the desired index - /// returns true if the value updated - #[inline] - pub fn set_at_thread(&mut self, other: &Self, thread: ThreadId){ - self.set_at_index(other, thread.to_u32() as usize); - } - - /// Clear the vector to all zeros, stored as an empty internal - /// vector - #[inline] - pub fn set_zero_vector(&mut self) { - self.0.clear(); - } - - /// Set the values stored in this vector clock - /// to the values stored in another. - pub fn set_values(&mut self, new_value: &VClock) { - let new_slice = new_value.as_slice(); - self.0.resize(new_slice.len(), 0); - self.0.copy_from_slice(new_slice); - } -} - - -impl PartialOrd for VClock { - fn partial_cmp(&self, other: &VClock) -> Option { - - // Load the values as slices - let lhs_slice = self.as_slice(); - let rhs_slice = other.as_slice(); - - // Iterate through the combined vector slice - // keeping track of the order that is currently possible to satisfy. - // If an ordering relation is detected to be impossible, then bail and - // directly return None - let mut iter = lhs_slice.iter().zip(rhs_slice.iter()); - let mut order = match iter.next() { - Some((lhs, rhs)) => lhs.cmp(rhs), - None => Ordering::Equal - }; - for (l, r) in iter { - match order { - Ordering::Equal => order = l.cmp(r), - Ordering::Less => if l > r { - return None - }, - Ordering::Greater => if l < r { - return None - } - } - } - - //Now test if either left or right have trailing elements - // by the invariant the trailing elements have at least 1 - // non zero value, so no additional calculation is required - // to determine the result of the PartialOrder - let l_len = lhs_slice.len(); - let r_len = rhs_slice.len(); - match l_len.cmp(&r_len) { - // Equal has no additional elements: return current order - Ordering::Equal => Some(order), - // Right has at least 1 element > than the implicit 0, - // so the only valid values are Ordering::Less or None - Ordering::Less => match order { - Ordering::Less | Ordering::Equal => Some(Ordering::Less), - Ordering::Greater => None - } - // Left has at least 1 element > than the implicit 0, - // so the only valid values are Ordering::Greater or None - Ordering::Greater => match order { - Ordering::Greater | Ordering::Equal => Some(Ordering::Greater), - Ordering::Less => None - } - } - } - - fn lt(&self, other: &VClock) -> bool { - // Load the values as slices - let lhs_slice = self.as_slice(); - let rhs_slice = other.as_slice(); - - // If l_len > r_len then at least one element - // in l_len is > than r_len, therefore the result - // is either Some(Greater) or None, so return false - // early. - let l_len = lhs_slice.len(); - let r_len = rhs_slice.len(); - if l_len <= r_len { - // If any elements on the left are greater than the right - // then the result is None or Some(Greater), both of which - // return false, the earlier test asserts that no elements in the - // extended tail violate this assumption. Otherwise l <= r, finally - // the case where the values are potentially equal needs to be considered - // and false returned as well - let mut equal = l_len == r_len; - for (&l, &r) in lhs_slice.iter().zip(rhs_slice.iter()) { - if l > r { - return false - }else if l < r { - equal = false; - } - } - !equal - }else{ - false - } - } - - fn le(&self, other: &VClock) -> bool { - // Load the values as slices - let lhs_slice = self.as_slice(); - let rhs_slice = other.as_slice(); - - // If l_len > r_len then at least one element - // in l_len is > than r_len, therefore the result - // is either Some(Greater) or None, so return false - // early. - let l_len = lhs_slice.len(); - let r_len = rhs_slice.len(); - if l_len <= r_len { - // If any elements on the left are greater than the right - // then the result is None or Some(Greater), both of which - // return false, the earlier test asserts that no elements in the - // extended tail violate this assumption. Otherwise l <= r - !lhs_slice.iter().zip(rhs_slice.iter()).any(|(&l, &r)| l > r) - }else{ - false - } - } - - fn gt(&self, other: &VClock) -> bool { - // Load the values as slices - let lhs_slice = self.as_slice(); - let rhs_slice = other.as_slice(); - - // If r_len > l_len then at least one element - // in r_len is > than l_len, therefore the result - // is either Some(Less) or None, so return false - // early. - let l_len = lhs_slice.len(); - let r_len = rhs_slice.len(); - if l_len >= r_len { - // If any elements on the left are less than the right - // then the result is None or Some(Less), both of which - // return false, the earlier test asserts that no elements in the - // extended tail violate this assumption. Otherwise l >=, finally - // the case where the values are potentially equal needs to be considered - // and false returned as well - let mut equal = l_len == r_len; - for (&l, &r) in lhs_slice.iter().zip(rhs_slice.iter()) { - if l < r { - return false - }else if l > r { - equal = false; - } - } - !equal - }else{ - false - } - } - - fn ge(&self, other: &VClock) -> bool { - // Load the values as slices - let lhs_slice = self.as_slice(); - let rhs_slice = other.as_slice(); - - // If r_len > l_len then at least one element - // in r_len is > than l_len, therefore the result - // is either Some(Less) or None, so return false - // early. - let l_len = lhs_slice.len(); - let r_len = rhs_slice.len(); - if l_len >= r_len { - // If any elements on the left are less than the right - // then the result is None or Some(Less), both of which - // return false, the earlier test asserts that no elements in the - // extended tail violate this assumption. Otherwise l >= r - !lhs_slice.iter().zip(rhs_slice.iter()).any(|(&l, &r)| l < r) - }else{ - false - } - } -} - -impl Index for VClock { - type Output = Timestamp; - + /// Return the current thread, should be the same + /// as the data-race active thread #[inline] - fn index(&self, index: ThreadId) -> &Timestamp { - self.as_slice().get(index.to_u32() as usize).unwrap_or(&0) + fn current_index(&self) -> VectorIdx { + self.current_index.get() } } - -/// Test vector clock ordering operations -/// data-race detection is tested in the external -/// test suite -#[cfg(test)] -mod tests { - use super::{VClock, Timestamp}; - use std::cmp::Ordering; - - #[test] - fn test_equal() { - let mut c1 = VClock::default(); - let mut c2 = VClock::default(); - assert_eq!(c1, c2); - c1.increment_index(5); - assert_ne!(c1, c2); - c2.increment_index(53); - assert_ne!(c1, c2); - c1.increment_index(53); - assert_ne!(c1, c2); - c2.increment_index(5); - assert_eq!(c1, c2); - } - - #[test] - fn test_partial_order() { - // Small test - assert_order(&[1], &[1], Some(Ordering::Equal)); - assert_order(&[1], &[2], Some(Ordering::Less)); - assert_order(&[2], &[1], Some(Ordering::Greater)); - assert_order(&[1], &[1,2], Some(Ordering::Less)); - assert_order(&[2], &[1,2], None); - - // Misc tests - assert_order(&[400], &[0, 1], None); - - // Large test - assert_order(&[0,1,2,3,4,5,6,7,8,9,10], &[0,1,2,3,4,5,6,7,8,9,10,0,0,0], Some(Ordering::Equal)); - assert_order(&[0,1,2,3,4,5,6,7,8,9,10], &[0,1,2,3,4,5,6,7,8,9,10,0,1,0], Some(Ordering::Less)); - assert_order(&[0,1,2,3,4,5,6,7,8,9,11], &[0,1,2,3,4,5,6,7,8,9,10,0,0,0], Some(Ordering::Greater)); - assert_order(&[0,1,2,3,4,5,6,7,8,9,11], &[0,1,2,3,4,5,6,7,8,9,10,0,1,0], None); - assert_order(&[0,1,2,3,4,5,6,7,8,9,9 ], &[0,1,2,3,4,5,6,7,8,9,10,0,0,0], Some(Ordering::Less)); - assert_order(&[0,1,2,3,4,5,6,7,8,9,9 ], &[0,1,2,3,4,5,6,7,8,9,10,0,1,0], Some(Ordering::Less)); - } - - fn from_slice(mut slice: &[Timestamp]) -> VClock { - while let Some(0) = slice.last() { - slice = &slice[..slice.len() - 1] - } - VClock(smallvec::SmallVec::from_slice(slice)) - } - - fn assert_order(l: &[Timestamp], r: &[Timestamp], o: Option) { - let l = from_slice(l); - let r = from_slice(r); - - //Test partial_cmp - let compare = l.partial_cmp(&r); - assert_eq!(compare, o, "Invalid comparison\n l: {:?}\n r: {:?}",l,r); - let alt_compare = r.partial_cmp(&l); - assert_eq!(alt_compare, o.map(Ordering::reverse), "Invalid alt comparison\n l: {:?}\n r: {:?}",l,r); - - //Test operatorsm with faster implementations - assert_eq!( - matches!(compare,Some(Ordering::Less)), l < r, - "Invalid (<):\n l: {:?}\n r: {:?}",l,r - ); - assert_eq!( - matches!(compare,Some(Ordering::Less) | Some(Ordering::Equal)), l <= r, - "Invalid (<=):\n l: {:?}\n r: {:?}",l,r - ); - assert_eq!( - matches!(compare,Some(Ordering::Greater)), l > r, - "Invalid (>):\n l: {:?}\n r: {:?}",l,r - ); - assert_eq!( - matches!(compare,Some(Ordering::Greater) | Some(Ordering::Equal)), l >= r, - "Invalid (>=):\n l: {:?}\n r: {:?}",l,r - ); - assert_eq!( - matches!(alt_compare,Some(Ordering::Less)), r < l, - "Invalid alt (<):\n l: {:?}\n r: {:?}",l,r - ); - assert_eq!( - matches!(alt_compare,Some(Ordering::Less) | Some(Ordering::Equal)), r <= l, - "Invalid alt (<=):\n l: {:?}\n r: {:?}",l,r - ); - assert_eq!( - matches!(alt_compare,Some(Ordering::Greater)), r > l, - "Invalid alt (>):\n l: {:?}\n r: {:?}",l,r - ); - assert_eq!( - matches!(alt_compare,Some(Ordering::Greater) | Some(Ordering::Equal)), r >= l, - "Invalid alt (>=):\n l: {:?}\n r: {:?}",l,r - ); - } -} diff --git a/src/lib.rs b/src/lib.rs index f384787e4c681..c8c9e70ec3deb 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -35,6 +35,7 @@ mod shims; mod stacked_borrows; mod sync; mod thread; +mod vector_clock; // Establish a "crate-wide prelude": we often import `crate::*`. @@ -79,6 +80,9 @@ pub use crate::thread::{ pub use crate::sync::{ EvalContextExt as SyncEvalContextExt, CondvarId, MutexId, RwLockId }; +pub use crate::vector_clock::{ + VClock, VSmallClockSet, VectorIdx, VTimestamp +}; /// Insert rustc arguments at the beginning of the argument list that Miri wants to be /// set per default, for maximal validation power. diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 2bb15e712c5f2..50f97af8453e6 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -469,8 +469,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let place = this.deref_operand(place)?; // make sure it fits into a scalar; otherwise it cannot be atomic - let val = this.read_scalar_racy(place)?; - this.validate_atomic_load(place, atomic)?; + let val = this.read_scalar_atomic(place, atomic)?; // Check alignment requirements. Atomics must always be aligned to their size, // even if the type they wrap would be less aligned (e.g. AtomicU64 on 32bit must @@ -495,9 +494,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.memory.check_ptr_access(place.ptr, place.layout.size, align)?; // Perform atomic store - this.write_scalar_racy(val, place)?; - - this.validate_atomic_store(place, atomic)?; + this.write_scalar_atomic(val, place, atomic)?; Ok(()) } @@ -527,7 +524,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx bug!("Atomic arithmetic operations only work on integer types"); } let rhs = this.read_immediate(rhs)?; - let old = this.read_immediate_racy(place)?; + let old = this.allow_data_races_mut(|this| { + this.read_immediate(place. into()) + })?; // Check alignment requirements. Atomics must always be aligned to their size, // even if the type they wrap would be less aligned (e.g. AtomicU64 on 32bit must @@ -539,7 +538,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Atomics wrap around on overflow. let val = this.binary_op(op, old, rhs)?; let val = if neg { this.unary_op(mir::UnOp::Not, val)? } else { val }; - this.write_immediate_racy(*val, place)?; + this.allow_data_races_mut(|this| { + this.write_immediate(*val, place.into()) + })?; this.validate_atomic_rmw(place, atomic)?; Ok(()) @@ -553,7 +554,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let &[place, new] = check_arg_count(args)?; let place = this.deref_operand(place)?; let new = this.read_scalar(new)?; - let old = this.read_scalar_racy(place)?; + let old = this.allow_data_races_mut(|this| { + this.read_scalar(place.into()) + })?; // Check alignment requirements. Atomics must always be aligned to their size, // even if the type they wrap would be less aligned (e.g. AtomicU64 on 32bit must @@ -562,7 +565,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.memory.check_ptr_access(place.ptr, place.layout.size, align)?; this.write_scalar(old, dest)?; // old value is returned - this.write_scalar_racy(new, place)?; + this.allow_data_races_mut(|this| { + this.write_scalar(new, place.into()) + })?; this.validate_atomic_rmw(place, atomic)?; Ok(()) @@ -583,7 +588,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // to read with the failure ordering and if successfull then try again with the success // read ordering and write in the success case. // Read as immediate for the sake of `binary_op()` - let old = this.read_immediate_racy(place)?; + let old = this.allow_data_races_mut(|this| { + this.read_immediate(place.into()) + })?; // Check alignment requirements. Atomics must always be aligned to their size, // even if the type they wrap would be less aligned (e.g. AtomicU64 on 32bit must @@ -602,7 +609,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // if successful, perform a full rw-atomic validation // otherwise treat this as an atomic load with the fail ordering if eq.to_bool()? { - this.write_scalar_racy(new, place)?; + this.allow_data_races_mut(|this| { + this.write_scalar(new, place.into()) + })?; this.validate_atomic_rmw(place, success)?; } else { this.validate_atomic_load(place, fail)?; diff --git a/src/shims/posix/sync.rs b/src/shims/posix/sync.rs index 332e79071a0ab..d741ef346e945 100644 --- a/src/shims/posix/sync.rs +++ b/src/shims/posix/sync.rs @@ -62,7 +62,10 @@ fn mutex_get_kind<'mir, 'tcx: 'mir>( mutex_op: OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, ScalarMaybeUninit> { let offset = if ecx.pointer_size().bytes() == 8 { 16 } else { 12 }; - ecx.read_scalar_at_offset_racy(mutex_op, offset, ecx.machine.layouts.i32) + ecx.read_scalar_at_offset_atomic( + mutex_op, offset, ecx.machine.layouts.i32, + AtomicReadOp::SeqCst + ) } fn mutex_set_kind<'mir, 'tcx: 'mir>( @@ -71,14 +74,19 @@ fn mutex_set_kind<'mir, 'tcx: 'mir>( kind: impl Into>, ) -> InterpResult<'tcx, ()> { let offset = if ecx.pointer_size().bytes() == 8 { 16 } else { 12 }; - ecx.write_scalar_at_offset_racy(mutex_op, offset, kind, ecx.machine.layouts.i32) + ecx.write_scalar_at_offset_atomic( + mutex_op, offset, kind, ecx.machine.layouts.i32, + AtomicWriteOp::SeqCst + ) } fn mutex_get_id<'mir, 'tcx: 'mir>( ecx: &MiriEvalContext<'mir, 'tcx>, mutex_op: OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, ScalarMaybeUninit> { - ecx.read_scalar_at_offset_racy(mutex_op, 4, ecx.machine.layouts.u32) + ecx.read_scalar_at_offset_atomic( + mutex_op, 4, ecx.machine.layouts.u32, AtomicReadOp::SeqCst + ) } fn mutex_set_id<'mir, 'tcx: 'mir>( @@ -86,7 +94,10 @@ fn mutex_set_id<'mir, 'tcx: 'mir>( mutex_op: OpTy<'tcx, Tag>, id: impl Into>, ) -> InterpResult<'tcx, ()> { - ecx.write_scalar_at_offset_racy(mutex_op, 4, id, ecx.machine.layouts.u32) + ecx.write_scalar_at_offset_atomic( + mutex_op, 4, id, ecx.machine.layouts.u32, + AtomicWriteOp::SeqCst + ) } fn mutex_get_or_create_id<'mir, 'tcx: 'mir>( @@ -116,7 +127,10 @@ fn rwlock_get_id<'mir, 'tcx: 'mir>( ecx: &MiriEvalContext<'mir, 'tcx>, rwlock_op: OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, ScalarMaybeUninit> { - ecx.read_scalar_at_offset_racy(rwlock_op, 4, ecx.machine.layouts.u32) + ecx.read_scalar_at_offset_atomic( + rwlock_op, 4, ecx.machine.layouts.u32, + AtomicReadOp::SeqCst + ) } fn rwlock_set_id<'mir, 'tcx: 'mir>( @@ -124,7 +138,10 @@ fn rwlock_set_id<'mir, 'tcx: 'mir>( rwlock_op: OpTy<'tcx, Tag>, id: impl Into>, ) -> InterpResult<'tcx, ()> { - ecx.write_scalar_at_offset_racy(rwlock_op, 4, id, ecx.machine.layouts.u32) + ecx.write_scalar_at_offset_atomic( + rwlock_op, 4, id, ecx.machine.layouts.u32, + AtomicWriteOp::SeqCst + ) } fn rwlock_get_or_create_id<'mir, 'tcx: 'mir>( @@ -177,7 +194,10 @@ fn cond_get_id<'mir, 'tcx: 'mir>( ecx: &MiriEvalContext<'mir, 'tcx>, cond_op: OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, ScalarMaybeUninit> { - ecx.read_scalar_at_offset_racy(cond_op, 4, ecx.machine.layouts.u32) + ecx.read_scalar_at_offset_atomic( + cond_op, 4, ecx.machine.layouts.u32, + AtomicReadOp::SeqCst + ) } fn cond_set_id<'mir, 'tcx: 'mir>( @@ -185,7 +205,10 @@ fn cond_set_id<'mir, 'tcx: 'mir>( cond_op: OpTy<'tcx, Tag>, id: impl Into>, ) -> InterpResult<'tcx, ()> { - ecx.write_scalar_at_offset_racy(cond_op, 4, id, ecx.machine.layouts.u32) + ecx.write_scalar_at_offset_atomic( + cond_op, 4, id, ecx.machine.layouts.u32, + AtomicWriteOp::SeqCst + ) } fn cond_get_or_create_id<'mir, 'tcx: 'mir>( diff --git a/src/thread.rs b/src/thread.rs index 08aeaa4fd095f..f94805ae022af 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -638,7 +638,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn set_active_thread_name(&mut self, new_thread_name: Vec) { let this = self.eval_context_mut(); if let Ok(string) = String::from_utf8(new_thread_name.clone()) { - this.memory.extra.data_race.thread_set_name(string); + this.memory.extra.data_race.thread_set_name( + this.machine.threads.active_thread, string + ); } this.machine.threads.set_thread_name(new_thread_name); } diff --git a/src/vector_clock.rs b/src/vector_clock.rs new file mode 100644 index 0000000000000..8d05eb1b992bb --- /dev/null +++ b/src/vector_clock.rs @@ -0,0 +1,602 @@ +use std::{ + fmt::{self, Debug}, cmp::Ordering, ops::Index, + num::TryFromIntError, convert::TryFrom, mem +}; +use smallvec::SmallVec; +use rustc_index::vec::Idx; +use rustc_data_structures::fx::FxHashMap; + +/// A vector clock index, this is associated with a thread id +/// but in some cases one vector index may be shared with +/// multiple thread ids. +#[derive(Clone, Copy, Debug, PartialOrd, Ord, PartialEq, Eq, Hash)] +pub struct VectorIdx(u32); + +impl VectorIdx{ + pub fn to_u32(self) -> u32 { + self.0 + } + pub const MAX_INDEX: VectorIdx = VectorIdx(u32::MAX); +} + +impl Idx for VectorIdx { + fn new(idx: usize) -> Self { + VectorIdx(u32::try_from(idx).unwrap()) + } + + fn index(self) -> usize { + usize::try_from(self.0).unwrap() + } +} + +impl TryFrom for VectorIdx { + type Error = TryFromIntError; + fn try_from(id: u64) -> Result { + u32::try_from(id).map(|id_u32| Self(id_u32)) + } +} + +impl From for VectorIdx { + fn from(id: u32) -> Self { + Self(id) + } +} + + +/// A sparse set of vector clocks, where each vector index +/// is associated with a vector clock. +/// This treats all vector clocks that have not been assigned +/// as equal to the all zero vector clocks +/// Is optimized for the common case where only 1 element is stored +/// in the set and the rest can be ignored, falling-back to +/// using an internal hash-map once more than 1 element is assigned +/// at any one time +#[derive(Clone)] +pub struct VSmallClockSet(VSmallClockSetInner); + +#[derive(Clone)] +enum VSmallClockSetInner { + /// Zero or 1 vector elements, common + /// case for the sparse set. + /// The all zero vector clock is treated + /// as equal to the empty element + Small(VectorIdx, VClock), + + /// Hash-map of vector clocks + Large(FxHashMap) +} + +impl VSmallClockSet { + + /// Remove all clock vectors from the map, setting them + /// to the zero vector + pub fn clear(&mut self) { + match &mut self.0 { + VSmallClockSetInner::Small(_, clock) => { + clock.set_zero_vector() + } + VSmallClockSetInner::Large(hash_map) => { + hash_map.clear(); + } + } + } + + /// Remove all clock vectors except for the clock vector + /// stored at the given index, which is retained + pub fn retain_index(&mut self, index: VectorIdx) { + match &mut self.0 { + VSmallClockSetInner::Small(small_idx, clock) => { + if index != *small_idx { + // The zero-vector is considered to equal + // the empty element + clock.set_zero_vector() + } + }, + VSmallClockSetInner::Large(hash_map) => { + hash_map.retain(|idx,_| { + *idx == index + }); + } + } + } + + /// Insert the vector clock into the associated vector + /// index + pub fn insert(&mut self, index: VectorIdx, clock: &VClock) { + match &mut self.0 { + VSmallClockSetInner::Small(small_idx, small_clock) => { + if small_clock.is_zero_vector() { + *small_idx = index; + small_clock.clone_from(clock); + }else if !clock.is_zero_vector() { + let mut hash_map = FxHashMap::default(); + hash_map.insert(*small_idx, mem::take(small_clock)); + hash_map.insert(index, clock.clone()); + self.0 = VSmallClockSetInner::Large(hash_map); + } + }, + VSmallClockSetInner::Large(hash_map) => { + if !clock.is_zero_vector() { + hash_map.insert(index, clock.clone()); + } + } + } + } + + /// Try to load the vector clock associated with the current + /// vector index. + pub fn get(&self, index: VectorIdx) -> Option<&VClock> { + match &self.0 { + VSmallClockSetInner::Small(small_idx, small_clock) => { + if *small_idx == index && !small_clock.is_zero_vector() { + Some(small_clock) + }else{ + None + } + }, + VSmallClockSetInner::Large(hash_map) => { + hash_map.get(&index) + } + } + } +} + +impl Default for VSmallClockSet { + #[inline] + fn default() -> Self { + VSmallClockSet( + VSmallClockSetInner::Small(VectorIdx::new(0), VClock::default()) + ) + } +} + +impl Debug for VSmallClockSet { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + // Print the contents of the small vector clock set as the map + // of vector index to vector clock that they represent + let mut map = f.debug_map(); + match &self.0 { + VSmallClockSetInner::Small(small_idx, small_clock) => { + if !small_clock.is_zero_vector() { + map.entry(&small_idx, &small_clock); + } + }, + VSmallClockSetInner::Large(hash_map) => { + for (idx, elem) in hash_map.iter() { + map.entry(idx, elem); + } + } + } + map.finish() + } +} +impl PartialEq for VSmallClockSet { + fn eq(&self, other: &Self) -> bool { + use VSmallClockSetInner::*; + match (&self.0, &other.0) { + (Small(i1, c1), Small(i2, c2)) => { + if c1.is_zero_vector() { + // Either they are both zero or they are non-equal + c2.is_zero_vector() + }else{ + // At least one is non-zero, so the full comparison is correct + i1 == i2 && c1 == c2 + } + } + (VSmallClockSetInner::Small(idx, clock), VSmallClockSetInner::Large(hash_map)) | + (VSmallClockSetInner::Large(hash_map), VSmallClockSetInner::Small(idx, clock)) => { + if hash_map.len() == 0 { + // Equal to the empty hash-map + clock.is_zero_vector() + }else if hash_map.len() == 1 { + // Equal to the hash-map with one element + let (hash_idx, hash_clock) = hash_map.iter().next().unwrap(); + hash_idx == idx && hash_clock == clock + }else{ + false + } + } + (Large(map1), Large(map2)) => { + map1 == map2 + } + } + } +} +impl Eq for VSmallClockSet {} + + + +/// The size of the vector-clock to store inline +/// clock vectors larger than this will be stored on the heap +const SMALL_VECTOR: usize = 4; + +/// The type of the time-stamps recorded in the data-race detector +/// set to a type of unsigned integer +pub type VTimestamp = u32; + +/// A vector clock for detecting data-races +/// invariants: +/// - the last element in a VClock must not be 0 +/// -- this means that derive(PartialEq & Eq) is correct +/// -- as there is no implicit zero tail that might be equal +/// -- also simplifies the implementation of PartialOrd +#[derive(PartialEq, Eq, Default, Debug)] +pub struct VClock(SmallVec<[VTimestamp; SMALL_VECTOR]>); + +impl VClock { + + /// Create a new vector-clock containing all zeros except + /// for a value at the given index + pub fn new_with_index(index: VectorIdx, timestamp: VTimestamp) -> VClock { + let len = index.index() + 1; + let mut vec = smallvec::smallvec![0; len]; + vec[index.index()] = timestamp; + VClock(vec) + } + + /// Load the internal timestamp slice in the vector clock + #[inline] + pub fn as_slice(&self) -> &[VTimestamp] { + self.0.as_slice() + } + + /// Get a mutable slice to the internal vector with minimum `min_len` + /// elements, to preserve invariants this vector must modify + /// the `min_len`-1 nth element to a non-zero value + #[inline] + fn get_mut_with_min_len(&mut self, min_len: usize) -> &mut [VTimestamp] { + if self.0.len() < min_len { + self.0.resize(min_len, 0); + } + assert!(self.0.len() >= min_len); + self.0.as_mut_slice() + } + + /// Increment the vector clock at a known index + /// this will panic if the vector index overflows + #[inline] + pub fn increment_index(&mut self, idx: VectorIdx) { + let idx = idx.index(); + let mut_slice = self.get_mut_with_min_len(idx + 1); + let idx_ref = &mut mut_slice[idx]; + *idx_ref = idx_ref.checked_add(1).expect("Vector clock overflow") + } + + // Join the two vector-clocks together, this + // sets each vector-element to the maximum value + // of that element in either of the two source elements. + pub fn join(&mut self, other: &Self) { + let rhs_slice = other.as_slice(); + let lhs_slice = self.get_mut_with_min_len(rhs_slice.len()); + for (l, &r) in lhs_slice.iter_mut().zip(rhs_slice.iter()) { + *l = r.max(*l); + } + } + + /// Set the element at the current index of the vector + pub fn set_at_index(&mut self, other: &Self, idx: VectorIdx) { + let idx = idx.index(); + let mut_slice = self.get_mut_with_min_len(idx + 1); + let slice = other.as_slice(); + mut_slice[idx] = slice[idx]; + } + + /// Set the vector to the all-zero vector + #[inline] + pub fn set_zero_vector(&mut self) { + self.0.clear(); + } + + /// Return if this vector is the all-zero vector + pub fn is_zero_vector(&self) -> bool { + self.0.is_empty() + } +} + +impl Clone for VClock { + fn clone(&self) -> Self { + VClock(self.0.clone()) + } + fn clone_from(&mut self, source: &Self) { + let source_slice = source.as_slice(); + self.0.clear(); + self.0.extend_from_slice(source_slice); + } +} + +impl PartialOrd for VClock { + fn partial_cmp(&self, other: &VClock) -> Option { + + // Load the values as slices + let lhs_slice = self.as_slice(); + let rhs_slice = other.as_slice(); + + // Iterate through the combined vector slice + // keeping track of the order that is currently possible to satisfy. + // If an ordering relation is detected to be impossible, then bail and + // directly return None + let mut iter = lhs_slice.iter().zip(rhs_slice.iter()); + let mut order = match iter.next() { + Some((lhs, rhs)) => lhs.cmp(rhs), + None => Ordering::Equal + }; + for (l, r) in iter { + match order { + Ordering::Equal => order = l.cmp(r), + Ordering::Less => if l > r { + return None + }, + Ordering::Greater => if l < r { + return None + } + } + } + + //Now test if either left or right have trailing elements + // by the invariant the trailing elements have at least 1 + // non zero value, so no additional calculation is required + // to determine the result of the PartialOrder + let l_len = lhs_slice.len(); + let r_len = rhs_slice.len(); + match l_len.cmp(&r_len) { + // Equal has no additional elements: return current order + Ordering::Equal => Some(order), + // Right has at least 1 element > than the implicit 0, + // so the only valid values are Ordering::Less or None + Ordering::Less => match order { + Ordering::Less | Ordering::Equal => Some(Ordering::Less), + Ordering::Greater => None + } + // Left has at least 1 element > than the implicit 0, + // so the only valid values are Ordering::Greater or None + Ordering::Greater => match order { + Ordering::Greater | Ordering::Equal => Some(Ordering::Greater), + Ordering::Less => None + } + } + } + + fn lt(&self, other: &VClock) -> bool { + // Load the values as slices + let lhs_slice = self.as_slice(); + let rhs_slice = other.as_slice(); + + // If l_len > r_len then at least one element + // in l_len is > than r_len, therefore the result + // is either Some(Greater) or None, so return false + // early. + let l_len = lhs_slice.len(); + let r_len = rhs_slice.len(); + if l_len <= r_len { + // If any elements on the left are greater than the right + // then the result is None or Some(Greater), both of which + // return false, the earlier test asserts that no elements in the + // extended tail violate this assumption. Otherwise l <= r, finally + // the case where the values are potentially equal needs to be considered + // and false returned as well + let mut equal = l_len == r_len; + for (&l, &r) in lhs_slice.iter().zip(rhs_slice.iter()) { + if l > r { + return false + }else if l < r { + equal = false; + } + } + !equal + }else{ + false + } + } + + fn le(&self, other: &VClock) -> bool { + // Load the values as slices + let lhs_slice = self.as_slice(); + let rhs_slice = other.as_slice(); + + // If l_len > r_len then at least one element + // in l_len is > than r_len, therefore the result + // is either Some(Greater) or None, so return false + // early. + let l_len = lhs_slice.len(); + let r_len = rhs_slice.len(); + if l_len <= r_len { + // If any elements on the left are greater than the right + // then the result is None or Some(Greater), both of which + // return false, the earlier test asserts that no elements in the + // extended tail violate this assumption. Otherwise l <= r + !lhs_slice.iter().zip(rhs_slice.iter()).any(|(&l, &r)| l > r) + }else{ + false + } + } + + fn gt(&self, other: &VClock) -> bool { + // Load the values as slices + let lhs_slice = self.as_slice(); + let rhs_slice = other.as_slice(); + + // If r_len > l_len then at least one element + // in r_len is > than l_len, therefore the result + // is either Some(Less) or None, so return false + // early. + let l_len = lhs_slice.len(); + let r_len = rhs_slice.len(); + if l_len >= r_len { + // If any elements on the left are less than the right + // then the result is None or Some(Less), both of which + // return false, the earlier test asserts that no elements in the + // extended tail violate this assumption. Otherwise l >=, finally + // the case where the values are potentially equal needs to be considered + // and false returned as well + let mut equal = l_len == r_len; + for (&l, &r) in lhs_slice.iter().zip(rhs_slice.iter()) { + if l < r { + return false + }else if l > r { + equal = false; + } + } + !equal + }else{ + false + } + } + + fn ge(&self, other: &VClock) -> bool { + // Load the values as slices + let lhs_slice = self.as_slice(); + let rhs_slice = other.as_slice(); + + // If r_len > l_len then at least one element + // in r_len is > than l_len, therefore the result + // is either Some(Less) or None, so return false + // early. + let l_len = lhs_slice.len(); + let r_len = rhs_slice.len(); + if l_len >= r_len { + // If any elements on the left are less than the right + // then the result is None or Some(Less), both of which + // return false, the earlier test asserts that no elements in the + // extended tail violate this assumption. Otherwise l >= r + !lhs_slice.iter().zip(rhs_slice.iter()).any(|(&l, &r)| l < r) + }else{ + false + } + } +} + +impl Index for VClock { + type Output = VTimestamp; + + #[inline] + fn index(&self, index: VectorIdx) -> &VTimestamp { + self.as_slice().get(index.to_u32() as usize).unwrap_or(&0) + } +} + + +/// Test vector clock ordering operations +/// data-race detection is tested in the external +/// test suite +#[cfg(test)] +mod tests { + use super::{VClock, VTimestamp, VectorIdx, VSmallClockSet}; + use std::cmp::Ordering; + + #[test] + fn test_equal() { + let mut c1 = VClock::default(); + let mut c2 = VClock::default(); + assert_eq!(c1, c2); + c1.increment_index(VectorIdx(5)); + assert_ne!(c1, c2); + c2.increment_index(VectorIdx(53)); + assert_ne!(c1, c2); + c1.increment_index(VectorIdx(53)); + assert_ne!(c1, c2); + c2.increment_index(VectorIdx(5)); + assert_eq!(c1, c2); + } + + #[test] + fn test_partial_order() { + // Small test + assert_order(&[1], &[1], Some(Ordering::Equal)); + assert_order(&[1], &[2], Some(Ordering::Less)); + assert_order(&[2], &[1], Some(Ordering::Greater)); + assert_order(&[1], &[1,2], Some(Ordering::Less)); + assert_order(&[2], &[1,2], None); + + // Misc tests + assert_order(&[400], &[0, 1], None); + + // Large test + assert_order(&[0,1,2,3,4,5,6,7,8,9,10], &[0,1,2,3,4,5,6,7,8,9,10,0,0,0], Some(Ordering::Equal)); + assert_order(&[0,1,2,3,4,5,6,7,8,9,10], &[0,1,2,3,4,5,6,7,8,9,10,0,1,0], Some(Ordering::Less)); + assert_order(&[0,1,2,3,4,5,6,7,8,9,11], &[0,1,2,3,4,5,6,7,8,9,10,0,0,0], Some(Ordering::Greater)); + assert_order(&[0,1,2,3,4,5,6,7,8,9,11], &[0,1,2,3,4,5,6,7,8,9,10,0,1,0], None); + assert_order(&[0,1,2,3,4,5,6,7,8,9,9 ], &[0,1,2,3,4,5,6,7,8,9,10,0,0,0], Some(Ordering::Less)); + assert_order(&[0,1,2,3,4,5,6,7,8,9,9 ], &[0,1,2,3,4,5,6,7,8,9,10,0,1,0], Some(Ordering::Less)); + } + + fn from_slice(mut slice: &[VTimestamp]) -> VClock { + while let Some(0) = slice.last() { + slice = &slice[..slice.len() - 1] + } + VClock(smallvec::SmallVec::from_slice(slice)) + } + + fn assert_order(l: &[VTimestamp], r: &[VTimestamp], o: Option) { + let l = from_slice(l); + let r = from_slice(r); + + //Test partial_cmp + let compare = l.partial_cmp(&r); + assert_eq!(compare, o, "Invalid comparison\n l: {:?}\n r: {:?}",l,r); + let alt_compare = r.partial_cmp(&l); + assert_eq!(alt_compare, o.map(Ordering::reverse), "Invalid alt comparison\n l: {:?}\n r: {:?}",l,r); + + //Test operatorsm with faster implementations + assert_eq!( + matches!(compare,Some(Ordering::Less)), l < r, + "Invalid (<):\n l: {:?}\n r: {:?}",l,r + ); + assert_eq!( + matches!(compare,Some(Ordering::Less) | Some(Ordering::Equal)), l <= r, + "Invalid (<=):\n l: {:?}\n r: {:?}",l,r + ); + assert_eq!( + matches!(compare,Some(Ordering::Greater)), l > r, + "Invalid (>):\n l: {:?}\n r: {:?}",l,r + ); + assert_eq!( + matches!(compare,Some(Ordering::Greater) | Some(Ordering::Equal)), l >= r, + "Invalid (>=):\n l: {:?}\n r: {:?}",l,r + ); + assert_eq!( + matches!(alt_compare,Some(Ordering::Less)), r < l, + "Invalid alt (<):\n l: {:?}\n r: {:?}",l,r + ); + assert_eq!( + matches!(alt_compare,Some(Ordering::Less) | Some(Ordering::Equal)), r <= l, + "Invalid alt (<=):\n l: {:?}\n r: {:?}",l,r + ); + assert_eq!( + matches!(alt_compare,Some(Ordering::Greater)), r > l, + "Invalid alt (>):\n l: {:?}\n r: {:?}",l,r + ); + assert_eq!( + matches!(alt_compare,Some(Ordering::Greater) | Some(Ordering::Equal)), r >= l, + "Invalid alt (>=):\n l: {:?}\n r: {:?}",l,r + ); + } + + #[test] + pub fn test_vclock_set() { + let mut set = VSmallClockSet::default(); + let v1 = from_slice(&[3,0,1]); + let v2 = from_slice(&[4,2,3]); + let v3 = from_slice(&[4,8,3]); + set.insert(VectorIdx(0), &v1); + assert_eq!(set.get(VectorIdx(0)), Some(&v1)); + set.insert(VectorIdx(5), &v2); + assert_eq!(set.get(VectorIdx(0)), Some(&v1)); + assert_eq!(set.get(VectorIdx(5)), Some(&v2)); + set.insert(VectorIdx(53), &v3); + assert_eq!(set.get(VectorIdx(0)), Some(&v1)); + assert_eq!(set.get(VectorIdx(5)), Some(&v2)); + assert_eq!(set.get(VectorIdx(53)), Some(&v3)); + set.retain_index(VectorIdx(53)); + assert_eq!(set.get(VectorIdx(0)), None); + assert_eq!(set.get(VectorIdx(5)), None); + assert_eq!(set.get(VectorIdx(53)), Some(&v3)); + set.clear(); + assert_eq!(set.get(VectorIdx(0)), None); + assert_eq!(set.get(VectorIdx(5)), None); + assert_eq!(set.get(VectorIdx(53)), None); + set.insert(VectorIdx(53), &v3); + assert_eq!(set.get(VectorIdx(0)), None); + assert_eq!(set.get(VectorIdx(5)), None); + assert_eq!(set.get(VectorIdx(53)), Some(&v3)); + } +} From c70bbea257d43242fa9f700d099c4a8a8eae2971 Mon Sep 17 00:00:00 2001 From: JCTyBlaidd Date: Thu, 5 Nov 2020 14:18:28 +0000 Subject: [PATCH 2434/3747] Move to use of thread termination hook for vector re-use, convert validate atomic op to use shared reference and get_raw instead of get_raw_mut so it can be used for validate_atomic_load as well --- src/data_race.rs | 175 ++++++++++++++++++++++++----------------------- src/thread.rs | 1 + 2 files changed, 91 insertions(+), 85 deletions(-) diff --git a/src/data_race.rs b/src/data_race.rs index e992c5a1d5899..153e63b77dfd8 100644 --- a/src/data_race.rs +++ b/src/data_race.rs @@ -159,52 +159,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { &self, place: MPlaceTy<'tcx, Tag>, atomic: AtomicReadOp ) -> InterpResult<'tcx> { let this = self.eval_context_ref(); - let data_race = &*this.memory.extra.data_race; - if data_race.multi_threaded.get() { - - // Load an log the atomic operation - // the memory access has to be `get_raw` since otherwise this despite only - // mutating MemoryExtra will still trigger errors on read-only memory - let place_ptr = place.ptr.assert_ptr(); - let size = place.layout.size; - let alloc_meta = &this.memory.get_raw(place_ptr.alloc_id)?.extra.data_race; - log::trace!( - "Atomic op({}) with ordering {:?} on memory({:?}, offset={}, size={})", - "Atomic load", &atomic, place_ptr.alloc_id, place_ptr.offset.bytes(), size.bytes() - ); - - // Perform the atomic operation - let data_race = &alloc_meta.global; - data_race.maybe_perform_sync_operation(move |index, mut clocks| { - for (_,range) in alloc_meta.alloc_ranges.borrow_mut().iter_mut(place_ptr.offset, size) { - let res = if atomic == AtomicReadOp::Relaxed { - range.load_relaxed(&mut *clocks, index) - }else{ - range.acquire(&mut *clocks, index) - }; - if let Err(DataRace) = res { - mem::drop(clocks); - return VClockAlloc::report_data_race( - &alloc_meta.global, range, "Atomic load", true, - place_ptr, size - ); - } - } - Ok(()) - })?; - - // Log changes to atomic memory - if log::log_enabled!(log::Level::Trace) { - for (_,range) in alloc_meta.alloc_ranges.borrow().iter(place_ptr.offset, size) { - log::trace!( - "Updated atomic memory({:?}, offset={}, size={}) to {:#?}", - place.ptr.assert_ptr().alloc_id, place_ptr.offset.bytes(), size.bytes(), - range.atomic_ops - ); + this.validate_atomic_op( + place, atomic, "Atomic Load", + move |memory, clocks, index, atomic| { + if atomic == AtomicReadOp::Relaxed { + memory.load_relaxed(&mut *clocks, index) + }else{ + memory.acquire(&mut *clocks, index) } } - } - Ok(()) + ) } /// Update the data-race detector for an atomic write occuring at the @@ -212,8 +176,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { fn validate_atomic_store( &mut self, place: MPlaceTy<'tcx, Tag>, atomic: AtomicWriteOp ) -> InterpResult<'tcx> { - let this = self.eval_context_mut(); - this.validate_atomic_op_mut( + let this = self.eval_context_ref(); + this.validate_atomic_op( place, atomic, "Atomic Store", move |memory, clocks, index, atomic| { if atomic == AtomicWriteOp::Relaxed { @@ -233,8 +197,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { use AtomicRWOp::*; let acquire = matches!(atomic, Acquire | AcqRel | SeqCst); let release = matches!(atomic, Release | AcqRel | SeqCst); - let this = self.eval_context_mut(); - this.validate_atomic_op_mut( + let this = self.eval_context_ref(); + this.validate_atomic_op( place, atomic, "Atomic RMW", move |memory, clocks, index, _| { if acquire { @@ -276,25 +240,27 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { impl<'mir, 'tcx: 'mir> EvalContextPrivExt<'mir, 'tcx> for MiriEvalContext<'mir, 'tcx> {} trait EvalContextPrivExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { - /// Generic atomic operation implementation, this however - /// cannot be used for the atomic read operation since - /// that requires non mutable memory access to not trigger - /// the writing to read-only memory errors during `get_raw_mut` - fn validate_atomic_op_mut( - &mut self, place: MPlaceTy<'tcx, Tag>, + /// Generic atomic operation implementation, + /// this accesses memory via get_raw instead of + /// get_raw_mut, due to issues calling get_raw_mut + /// for atomic loads from read-only memory + /// FIXME: is this valid, or should get_raw_mut be used for + /// atomic-stores/atomic-rmw? + fn validate_atomic_op( + &self, place: MPlaceTy<'tcx, Tag>, atomic: A, description: &str, mut op: impl FnMut( &mut MemoryCellClocks, &mut ThreadClockSet, VectorIdx, A ) -> Result<(), DataRace> ) -> InterpResult<'tcx> { - let this = self.eval_context_mut(); + let this = self.eval_context_ref(); let data_race = &*this.memory.extra.data_race; if data_race.multi_threaded.get() { // Load an log the atomic operation let place_ptr = place.ptr.assert_ptr(); let size = place.layout.size; - let alloc_meta = &mut this.memory.get_raw_mut(place_ptr.alloc_id)?.extra.data_race; + let alloc_meta = &this.memory.get_raw(place_ptr.alloc_id)?.extra.data_race; log::trace!( "Atomic op({}) with ordering {:?} on memory({:?}, offset={}, size={})", description, &atomic, place_ptr.alloc_id, place_ptr.offset.bytes(), size.bytes() @@ -800,6 +766,29 @@ impl ThreadClockSet { } } +/// Extra metadata associated with a thread +#[derive(Debug, Clone, Default)] +struct ThreadExtraState { + + /// The current vector index in use by the + /// thread currently, this is set to None + /// after the vector index has been re-used + vector_index: Option, + + /// The name of the thread, updated for better + /// diagnostics when reporting detected data + /// races + thread_name: Option>, + + /// Thread termination vector clock, this + /// is set on thread termination and is used + /// for joining on threads that have already + /// terminated. This should be used first + /// on joining as there is the possibility + /// that `vector_index` is None in some cases + termination_vector_clock: Option, +} + /// Global data-race detection state, contains the currently /// executing thread as well as the vector-clocks associated /// with each of the threads. @@ -822,18 +811,18 @@ pub struct GlobalState { /// Mapping of a given vector index to the current thread /// that the execution is representing, this may change /// if a vector index is re-assigned to a new thread - vector_info: RefCell>, //FIXME: make option + vector_info: RefCell>, - /// The mapping of a given thread to a known vector clock - thread_info: RefCell, Option>)>>, + /// The mapping of a given thread to assocaited thread metadata + thread_info: RefCell>, /// The current vector index being executed current_index: Cell, /// Potential vector indices that could be re-used on thread creation - /// values are inserted here on thread join events, and can be - /// re-used once the vector clocks of all current threads - /// are equal to the vector clock of the joined thread + /// values are inserted here on thread termination, vector index values + /// are then re-used once all the termination event happens-before all + /// existing thread-clocks reuse_candidates: RefCell>, } impl GlobalState { @@ -856,8 +845,12 @@ impl GlobalState { let index = global_state.vector_clocks.borrow_mut().push(ThreadClockSet::default()); global_state.vector_info.borrow_mut().push(ThreadId::new(0)); global_state.thread_info.borrow_mut().push( - (Some(index), Some("main".to_string().into_boxed_str()) - )); + ThreadExtraState { + vector_index: Some(index), + thread_name: Some("main".to_string().into_boxed_str()), + termination_vector_clock: None + } + ); global_state } @@ -873,10 +866,9 @@ impl GlobalState { clock.clock[candidate] == target_timestamp }) { // All vector clocks for each vector index are equal to - // the target timestamp, therefore since the thread has - // terminated and cannot update the vector clock. - // No more data-races involving this vector index are possible - // so it can be re-used + // the target timestamp, and the thread is known to have + // terminated, therefore this vector clock index cannot + // report any more data-races assert!(reuse.remove(&candidate)); return Some(candidate) } @@ -916,7 +908,7 @@ impl GlobalState { // Mark the thread the vector index was associated with as no longer // representing a thread index - thread_info[old_thread].0 = None; + thread_info[old_thread].vector_index = None; reuse_index }else{ @@ -927,7 +919,7 @@ impl GlobalState { }; // Mark the chosen vector index as in use by the thread - thread_info[thread].0 = Some(created_index); + thread_info[thread].vector_index = Some(created_index); // Create a thread clock set if applicable let mut vector_clocks = self.vector_clocks.borrow_mut(); @@ -952,15 +944,13 @@ impl GlobalState { /// Hook on a thread join to update the implicit happens-before relation /// between the joined thead and the current thread. - /// Called after the join has occured, and hence implicitly also states - /// that the thread must have terminated as well #[inline] pub fn thread_joined(&self, current_thread: ThreadId, join_thread: ThreadId) { let (current_index, join_index) = { let thread_info = self.thread_info.borrow(); - let current_index = thread_info[current_thread].0 + let current_index = thread_info[current_thread].vector_index .expect("Joining into thread with no assigned vector"); - let join_index = thread_info[join_thread].0 + let join_index = thread_info[join_thread].vector_index .expect("Joining thread with no assigned vector"); (current_index, join_index) }; @@ -976,16 +966,31 @@ impl GlobalState { current.join_with(join); // Post increment clocks after atomic operation + // the join clock is not incremented, since there will + // be no future events, also if it was incremented + // the thread re-use condition would never pass current.increment_clock(current_index); - join.increment_clock(join_index); + } + + /// On thread termination, the vector-clock may re-used + /// in the future once all remaining thread-clocks catch + /// up with the time index of the terminated thread + #[inline] + pub fn thread_terminated(&self, terminated_thread: ThreadId) { + let mut thread_info = self.thread_info.borrow_mut(); + let termination_meta = &mut thread_info[terminated_thread]; + + // Find the terminated index & setup the termination vector-clock + // in case thread join is called in the future after the thread + // has been re-used + let terminated_index = termination_meta.vector_index + .expect("Joining into thread with no assigned vector"); + let vector_clocks = self.vector_clocks.borrow(); + termination_meta.termination_vector_clock = Some(vector_clocks[terminated_index].clock.clone()); - // The joined thread vector clock is a potential candidate - // for re-use given sufficient time, mark as available once - // threads have been created. This is because this function - // is called once join_thread has terminated and such cannot - // update any-more + // Add this thread as a candidate for re-use let mut reuse = self.reuse_candidates.borrow_mut(); - reuse.insert(join_index); + reuse.insert(terminated_index); } /// Hook for updating the local tracker of the currently @@ -994,7 +999,7 @@ impl GlobalState { #[inline] pub fn thread_set_active(&self, thread: ThreadId) { let thread_info = self.thread_info.borrow(); - let vector_idx = thread_info[thread].0 + let vector_idx = thread_info[thread].vector_index .expect("Setting thread active with no assigned vector"); self.current_index.set(vector_idx); } @@ -1007,7 +1012,7 @@ impl GlobalState { pub fn thread_set_name(&self, thread: ThreadId, name: String) { let name = name.into_boxed_str(); let mut thread_info = self.thread_info.borrow_mut(); - thread_info[thread].1 = Some(name); + thread_info[thread].thread_name = Some(name); } @@ -1036,7 +1041,7 @@ impl GlobalState { /// returns the id and the name for better diagnostics fn print_thread_metadata(&self, vector: VectorIdx) -> String { let thread = self.vector_info.borrow()[vector]; - let thread_name = &self.thread_info.borrow()[thread].1; + let thread_name = &self.thread_info.borrow()[thread].thread_name; if let Some(name) = thread_name { let name: &str = name; format!("Thread(id = {:?}, name = {:?})", thread.to_u32(), &*name) @@ -1079,7 +1084,7 @@ impl GlobalState { /// used by the thread #[inline] fn load_thread_state_mut(&self, thread: ThreadId) -> (VectorIdx, RefMut<'_, ThreadClockSet>) { - let index = self.thread_info.borrow()[thread].0 + let index = self.thread_info.borrow()[thread].vector_index .expect("Loading thread state for thread with no assigned vector"); let ref_vector = self.vector_clocks.borrow_mut(); let clocks = RefMut::map(ref_vector, |vec| &mut vec[index]); diff --git a/src/thread.rs b/src/thread.rs index f94805ae022af..976ac816a0485 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -452,6 +452,7 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { thread.state = ThreadState::Enabled; } } + data_race.thread_terminated(self.active_thread); return free_tls_statics; } From f31f00d5af9b5e6ec445c8a61349831182f90d53 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 5 Nov 2020 17:09:44 +0100 Subject: [PATCH 2435/3747] rustup --- rust-version | 2 +- src/shims/backtrace.rs | 5 +---- tests/compile-fail/backtrace/bad-backtrace-ptr.rs | 2 +- 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/rust-version b/rust-version index efb6b94d3b40f..514517267a01c 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -5cdf5b882da9e8b7c73b5cadeb7745cb68f6ff63 +89631663b7ad2d46d3e4f52bcfa7bee2be9eb82b diff --git a/src/shims/backtrace.rs b/src/shims/backtrace.rs index 8cf7ac207528c..a599ee70efae9 100644 --- a/src/shims/backtrace.rs +++ b/src/shims/backtrace.rs @@ -81,10 +81,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx throw_unsup_format!("unknown `miri_resolve_frame` flags {}", flags); } - let ptr = match this.read_scalar(ptr)?.check_init()? { - Scalar::Ptr(ptr) => ptr, - Scalar::Raw { .. } => throw_ub_format!("expected a pointer in `rust_miri_resolve_frame`, found {:?}", ptr) - }; + let ptr = this.force_ptr(this.read_scalar(ptr)?.check_init()?)?; let fn_instance = if let Some(GlobalAlloc::Function(instance)) = this.tcx.get_global_alloc(ptr.alloc_id) { instance diff --git a/tests/compile-fail/backtrace/bad-backtrace-ptr.rs b/tests/compile-fail/backtrace/bad-backtrace-ptr.rs index 5e245952e9b24..0c49a527bc161 100644 --- a/tests/compile-fail/backtrace/bad-backtrace-ptr.rs +++ b/tests/compile-fail/backtrace/bad-backtrace-ptr.rs @@ -4,6 +4,6 @@ extern "Rust" { fn main() { unsafe { - miri_resolve_frame(0 as *mut _, 0); //~ ERROR Undefined Behavior: expected a pointer + miri_resolve_frame(0 as *mut _, 0); //~ ERROR 0x0 is not a valid pointer } } From 2a40d9b7a07f9a770455de26e46b766bdb395206 Mon Sep 17 00:00:00 2001 From: JCTyBlaidd Date: Fri, 6 Nov 2020 17:29:54 +0000 Subject: [PATCH 2436/3747] More aggressive vector index re-use, and added some tests. --- src/data_race.rs | 190 ++++++++++++------ src/thread.rs | 3 +- .../data_race/dangling_thread_async_race.rs | 44 ++++ .../data_race/dangling_thread_race.rs | 41 ++++ .../data_race/enable_after_join_to_main.rs | 38 ++++ 5 files changed, 254 insertions(+), 62 deletions(-) create mode 100644 tests/compile-fail/data_race/dangling_thread_async_race.rs create mode 100644 tests/compile-fail/data_race/dangling_thread_race.rs create mode 100644 tests/compile-fail/data_race/enable_after_join_to_main.rs diff --git a/src/data_race.rs b/src/data_race.rs index 153e63b77dfd8..57f09146d6f82 100644 --- a/src/data_race.rs +++ b/src/data_race.rs @@ -20,7 +20,7 @@ use std::{ use rustc_index::vec::{Idx, IndexVec}; use rustc_target::abi::Size; use rustc_middle::ty::layout::TyAndLayout; -use rustc_data_structures::fx::FxHashSet; +use rustc_data_structures::fx::{FxHashSet, FxHashMap}; use crate::{ MiriEvalContext, MiriEvalContextExt, @@ -662,7 +662,7 @@ impl VClockAlloc { let (index, clocks) = self.global.current_thread_state(); let mut alloc_ranges = self.alloc_ranges.borrow_mut(); for (_,range) in alloc_ranges.iter_mut(pointer.offset, len) { - if range.read_race_detect(&*clocks, index) == Err(DataRace) { + if let Err(DataRace) = range.read_race_detect(&*clocks, index) { // Report data-race return Self::report_data_race( &self.global,range, "READ", false, pointer, len @@ -674,18 +674,17 @@ impl VClockAlloc { Ok(()) } } - /// Detect data-races for an unsychronized write operation, will not perform - /// data-race threads if `multi-threaded` is false, either due to no threads - /// being created or if it is temporarily disabled during a racy read or write - /// operation - pub fn write<'tcx>(&mut self, pointer: Pointer, len: Size) -> InterpResult<'tcx> { + + + // Shared code for detecting data-races on unique access to a section of memory + fn unique_access<'tcx>(&mut self, pointer: Pointer, len: Size, action: &str) -> InterpResult<'tcx> { if self.global.multi_threaded.get() { let (index, clocks) = self.global.current_thread_state(); for (_,range) in self.alloc_ranges.get_mut().iter_mut(pointer.offset, len) { - if range.write_race_detect(&*clocks, index) == Err(DataRace) { + if let Err(DataRace) = range.write_race_detect(&*clocks, index) { // Report data-race return Self::report_data_race( - &self.global, range, "WRITE", false, pointer, len + &self.global, range, action, false, pointer, len ); } } @@ -694,25 +693,20 @@ impl VClockAlloc { Ok(()) } } + + /// Detect data-races for an unsychronized write operation, will not perform + /// data-race threads if `multi-threaded` is false, either due to no threads + /// being created or if it is temporarily disabled during a racy read or write + /// operation + pub fn write<'tcx>(&mut self, pointer: Pointer, len: Size) -> InterpResult<'tcx> { + self.unique_access(pointer, len, "Write") + } /// Detect data-races for an unsychronized deallocate operation, will not perform /// data-race threads if `multi-threaded` is false, either due to no threads /// being created or if it is temporarily disabled during a racy read or write /// operation pub fn deallocate<'tcx>(&mut self, pointer: Pointer, len: Size) -> InterpResult<'tcx> { - if self.global.multi_threaded.get() { - let (index, clocks) = self.global.current_thread_state(); - for (_,range) in self.alloc_ranges.get_mut().iter_mut(pointer.offset, len) { - if range.write_race_detect(&*clocks, index) == Err(DataRace) { - // Report data-race - return Self::report_data_race( - &self.global, range, "DEALLOCATE", false, pointer, len - ); - } - } - Ok(()) - }else{ - Ok(()) - } + self.unique_access(pointer, len, "Deallocate") } } @@ -773,6 +767,8 @@ struct ThreadExtraState { /// The current vector index in use by the /// thread currently, this is set to None /// after the vector index has been re-used + /// and hence the value will never need to be + /// read during data-race reporting vector_index: Option, /// The name of the thread, updated for better @@ -782,10 +778,8 @@ struct ThreadExtraState { /// Thread termination vector clock, this /// is set on thread termination and is used - /// for joining on threads that have already - /// terminated. This should be used first - /// on joining as there is the possibility - /// that `vector_index` is None in some cases + /// for joining on threads since the vector_index + /// may be re-used when the join operation occurs termination_vector_clock: Option, } @@ -820,10 +814,26 @@ pub struct GlobalState { current_index: Cell, /// Potential vector indices that could be re-used on thread creation - /// values are inserted here on thread termination, vector index values - /// are then re-used once all the termination event happens-before all - /// existing thread-clocks + /// values are inserted here on after the thread has terminated and + /// been joined with, and hence may potentially become free + /// for use as the index for a new thread. + /// Elements in this set may still require the vector index to + /// report data-races, and can only be re-used after all + /// active vector-clocks catch up with the threads timestamp. reuse_candidates: RefCell>, + + /// Counts the number of threads that are currently active + /// if the number of active threads reduces to 1 and then + /// a join operation occures with the remaining main thread + /// then multi-threaded execution may be disabled + active_thread_count: Cell, + + /// This contains threads that have terminated, but not yet joined + /// and so cannot become re-use candidates until a join operation + /// occurs. + /// The associated vector index will be moved into re-use candidates + /// after the join operation occurs + terminated_threads: RefCell>, } impl GlobalState { @@ -836,7 +846,9 @@ impl GlobalState { vector_info: RefCell::new(IndexVec::new()), thread_info: RefCell::new(IndexVec::new()), current_index: Cell::new(VectorIdx::new(0)), + active_thread_count: Cell::new(1), reuse_candidates: RefCell::new(FxHashSet::default()), + terminated_threads: RefCell::new(FxHashMap::default()) }; // Setup the main-thread since it is not explicitly created: @@ -860,10 +872,24 @@ impl GlobalState { fn find_vector_index_reuse_candidate(&self) -> Option { let mut reuse = self.reuse_candidates.borrow_mut(); let vector_clocks = self.vector_clocks.borrow(); + let vector_info = self.vector_info.borrow(); + let terminated_threads = self.terminated_threads.borrow(); for &candidate in reuse.iter() { let target_timestamp = vector_clocks[candidate].clock[candidate]; - if vector_clocks.iter().all(|clock| { - clock.clock[candidate] == target_timestamp + if vector_clocks.iter_enumerated().all(|(clock_idx, clock)| { + // The thread happens before the clock, and hence cannot report + // a data-race with this the candidate index + let no_data_race = clock.clock[candidate] >= target_timestamp; + + // The vector represents a thread that has terminated and hence cannot + // report a data-race with the candidate index + let thread_id = vector_info[clock_idx]; + let vector_terminated = reuse.contains(&clock_idx) + || terminated_threads.contains_key(&thread_id); + + // The vector index cannot report a race with the candidate index + // and hence allows the candidate index to be re-used + no_data_race || vector_terminated }) { // All vector clocks for each vector index are equal to // the target timestamp, and the thread is known to have @@ -882,6 +908,10 @@ impl GlobalState { pub fn thread_created(&self, thread: ThreadId) { let current_index = self.current_index(); + // Increment the number of active threads + let active_threads = self.active_thread_count.get(); + self.active_thread_count.set(active_threads + 1); + // Enable multi-threaded execution, there are now two threads // so data-races are now possible. self.multi_threaded.set(true); @@ -946,51 +976,90 @@ impl GlobalState { /// between the joined thead and the current thread. #[inline] pub fn thread_joined(&self, current_thread: ThreadId, join_thread: ThreadId) { - let (current_index, join_index) = { - let thread_info = self.thread_info.borrow(); - let current_index = thread_info[current_thread].vector_index - .expect("Joining into thread with no assigned vector"); - let join_index = thread_info[join_thread].vector_index - .expect("Joining thread with no assigned vector"); - (current_index, join_index) - }; let mut clocks_vec = self.vector_clocks.borrow_mut(); - let (current, join) = clocks_vec.pick2_mut(current_index, join_index); + let thread_info = self.thread_info.borrow(); + + // Load the vector clock of the current thread + let current_index = thread_info[current_thread].vector_index + .expect("Performed thread join on thread with no assigned vector"); + let current = &mut clocks_vec[current_index]; + + // Load the associated vector clock for the terminated thread + let join_clock = thread_info[join_thread].termination_vector_clock + .as_ref().expect("Joined with thread but thread has not terminated"); // Pre increment clocks before atomic operation current.increment_clock(current_index); - join.increment_clock(join_index); // The join thread happens-before the current thread // so update the current vector clock - current.join_with(join); + current.clock.join(join_clock); // Post increment clocks after atomic operation - // the join clock is not incremented, since there will - // be no future events, also if it was incremented - // the thread re-use condition would never pass current.increment_clock(current_index); + + // Check the number of active threads, if the value is 1 + // then test for potentially disabling multi-threaded execution + let active_threads = self.active_thread_count.get(); + if active_threads == 1 { + // May potentially be able to disable multi-threaded execution + let current_clock = &clocks_vec[current_index]; + if clocks_vec.iter_enumerated().all(|(idx, clocks)| { + clocks.clock[idx] <= current_clock.clock[idx] + }) { + // The all thread termations happen-before the current clock + // therefore no data-races can be reported until a new thread + // is created, so disable multi-threaded execution + self.multi_threaded.set(false); + } + } + + // If the thread is marked as terminated but not joined + // then move the thread to the re-use set + let mut termination = self.terminated_threads.borrow_mut(); + if let Some(index) = termination.remove(&join_thread) { + let mut reuse = self.reuse_candidates.borrow_mut(); + reuse.insert(index); + } } /// On thread termination, the vector-clock may re-used /// in the future once all remaining thread-clocks catch - /// up with the time index of the terminated thread + /// up with the time index of the terminated thread. + /// This assiges thread termination with a unique index + /// which will be used to join the thread + /// This should be called strictly before any calls to + /// `thread_joined` #[inline] - pub fn thread_terminated(&self, terminated_thread: ThreadId) { - let mut thread_info = self.thread_info.borrow_mut(); - let termination_meta = &mut thread_info[terminated_thread]; + pub fn thread_terminated(&self) { + let current_index = self.current_index(); + + // Increment the clock to a unique termination timestamp + let mut vector_clocks = self.vector_clocks.borrow_mut(); + let current_clocks = &mut vector_clocks[current_index]; + current_clocks.increment_clock(current_index); - // Find the terminated index & setup the termination vector-clock - // in case thread join is called in the future after the thread - // has been re-used - let terminated_index = termination_meta.vector_index - .expect("Joining into thread with no assigned vector"); - let vector_clocks = self.vector_clocks.borrow(); - termination_meta.termination_vector_clock = Some(vector_clocks[terminated_index].clock.clone()); + // Load the current thread id for the executing vector + let vector_info = self.vector_info.borrow(); + let current_thread = vector_info[current_index]; - // Add this thread as a candidate for re-use - let mut reuse = self.reuse_candidates.borrow_mut(); - reuse.insert(terminated_index); + // Load the current thread metadata, and move to a terminated + // vector state. Setting up the vector clock all join operations + // will use. + let mut thread_info = self.thread_info.borrow_mut(); + let current = &mut thread_info[current_thread]; + current.termination_vector_clock = Some(current_clocks.clock.clone()); + + // Add this thread as a candidate for re-use after a thread join + // occurs + let mut termination = self.terminated_threads.borrow_mut(); + termination.insert(current_thread, current_index); + + // Reduce the number of active threads, now that a thread has + // terminated + let mut active_threads = self.active_thread_count.get(); + active_threads -= 1; + self.active_thread_count.set(active_threads); } /// Hook for updating the local tracker of the currently @@ -1118,4 +1187,3 @@ impl GlobalState { self.current_index.get() } } - diff --git a/src/thread.rs b/src/thread.rs index 976ac816a0485..40cfd04d7923e 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -443,6 +443,8 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { return false; }); } + // Set the thread into a terminated state in the data-race detector + data_race.thread_terminated(); // Check if we need to unblock any threads. for (i, thread) in self.threads.iter_enumerated_mut() { if thread.state == ThreadState::BlockedOnJoin(self.active_thread) { @@ -452,7 +454,6 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { thread.state = ThreadState::Enabled; } } - data_race.thread_terminated(self.active_thread); return free_tls_statics; } diff --git a/tests/compile-fail/data_race/dangling_thread_async_race.rs b/tests/compile-fail/data_race/dangling_thread_async_race.rs new file mode 100644 index 0000000000000..6af5706835e36 --- /dev/null +++ b/tests/compile-fail/data_race/dangling_thread_async_race.rs @@ -0,0 +1,44 @@ +// ignore-windows: Concurrency on Windows is not supported yet. +// compile-flags: -Zmiri-disable-isolation + +use std::thread::{spawn, sleep}; +use std::time::Duration; +use std::mem; + + +#[derive(Copy, Clone)] +struct EvilSend(pub T); + +unsafe impl Send for EvilSend {} +unsafe impl Sync for EvilSend {} + + +fn main() { + let mut a = 0u32; + let b = &mut a as *mut u32; + let c = EvilSend(b); + + let join = unsafe { + spawn(move || { + *c.0 = 32; + }) + }; + + // Detatch the thread and sleep until it terminates + mem::drop(join); + sleep(Duration::from_millis(100)); + + // Spawn and immediately join a thread + // to execute the join code-path + // and ensure that data-race detection + // remains enabled + spawn(|| ()).join().unwrap(); + + let join2 = unsafe { + spawn(move || { + *c.0 = 64; //~ ERROR Data race + }) + }; + + join2.join().unwrap(); +} diff --git a/tests/compile-fail/data_race/dangling_thread_race.rs b/tests/compile-fail/data_race/dangling_thread_race.rs new file mode 100644 index 0000000000000..c37f303bbab27 --- /dev/null +++ b/tests/compile-fail/data_race/dangling_thread_race.rs @@ -0,0 +1,41 @@ +// ignore-windows: Concurrency on Windows is not supported yet. +// compile-flags: -Zmiri-disable-isolation + +use std::thread::{spawn, sleep}; +use std::time::Duration; +use std::mem; + + +#[derive(Copy, Clone)] +struct EvilSend(pub T); + +unsafe impl Send for EvilSend {} +unsafe impl Sync for EvilSend {} + + +fn main() { + let mut a = 0u32; + let b = &mut a as *mut u32; + let c = EvilSend(b); + + let join = unsafe { + spawn(move || { + *c.0 = 32; + }) + }; + + // Detatch the thread and sleep until it terminates + mem::drop(join); + sleep(Duration::from_millis(100)); + + // Spawn and immediately join a thread + // to execute the join code-path + // and ensure that data-race detection + // remains enabled + spawn(|| ()).join().unwrap(); + + + unsafe { + *c.0 = 64; //~ ERROR Data race + } +} diff --git a/tests/compile-fail/data_race/enable_after_join_to_main.rs b/tests/compile-fail/data_race/enable_after_join_to_main.rs new file mode 100644 index 0000000000000..fba7ba4841ccd --- /dev/null +++ b/tests/compile-fail/data_race/enable_after_join_to_main.rs @@ -0,0 +1,38 @@ +// ignore-windows: Concurrency on Windows is not supported yet. + +use std::thread::spawn; + +#[derive(Copy, Clone)] +struct EvilSend(pub T); + +unsafe impl Send for EvilSend {} +unsafe impl Sync for EvilSend {} + +pub fn main() { + // Enable and the join with multiple threads + let t1 = spawn(|| ()); + let t2 = spawn(|| ()); + let t3 = spawn(|| ()); + let t4 = spawn(|| ()); + t1.join().unwrap(); + t2.join().unwrap(); + t3.join().unwrap(); + t4.join().unwrap(); + + // Perform write-write data race detection + let mut a = 0u32; + let b = &mut a as *mut u32; + let c = EvilSend(b); + unsafe { + let j1 = spawn(move || { + *c.0 = 32; + }); + + let j2 = spawn(move || { + *c.0 = 64; //~ ERROR Data race + }); + + j1.join().unwrap(); + j2.join().unwrap(); + } +} From 330ec0acdbdff74be1fa75e86aab561302bf5700 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 7 Nov 2020 15:56:25 +0100 Subject: [PATCH 2437/3747] enable overflow checks in the standard library --- cargo-miri/bin.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index 6eff5f795e7cb..d18e9608cf500 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -354,7 +354,8 @@ path = "lib.rs" command.env_remove("RUSTC_WRAPPER"); command.env_remove("RUSTFLAGS"); // Disable debug assertions in the standard library -- Miri is already slow enough. - command.env("RUSTFLAGS", "-Cdebug-assertions=off"); + // But keep the overflow checks, they are cheap. + command.env("RUSTFLAGS", "-Cdebug-assertions=off -Coverflow-checks=on"); // Finally run it! if command.status().expect("failed to run xargo").success().not() { show_error(format!("failed to run xargo")); From 6a475c3ddf8ee0868f0723683aa2720e8f87d44a Mon Sep 17 00:00:00 2001 From: Camelid Date: Sat, 7 Nov 2020 11:26:41 -0800 Subject: [PATCH 2438/3747] CONTRIBUTING.md: Update comment Co-authored-by: Ralf Jung --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 20f01f151a650..08dcd541f7bfb 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -147,7 +147,7 @@ cd rustc cp config.toml.example config.toml # Now edit `config.toml` and set `debug-assertions = true`. -# Build a stage 1 rustc. +# Build a stage 1 rustc, and build the rustc libraries with that rustc. # This step can take 30 minutes or more. ./x.py build --stage 1 compiler/rustc # If you change something, you can get a faster rebuild by doing From 43ce2c2844ebe1918716a1e599b159a0eb5885cd Mon Sep 17 00:00:00 2001 From: Joshua Nelson Date: Sat, 31 Oct 2020 15:06:06 -0400 Subject: [PATCH 2439/3747] Improve contributing instructions - Fix incorrect comment - Recommend `x.py setup` over manually editing config.toml - Link to rustc-dev-guide --- CONTRIBUTING.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 08dcd541f7bfb..bbfcb7638f382 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -144,8 +144,9 @@ The setup for a local rustc works as follows: # Clone the rust-lang/rust repo. git clone https://github.com/rust-lang/rust rustc cd rustc -cp config.toml.example config.toml -# Now edit `config.toml` and set `debug-assertions = true`. +# Create a config.toml with defaults for working on miri. +./x.py setup compiler + # Now edit `config.toml` and under `[rust]` set `debug-assertions = true`. # Build a stage 1 rustc, and build the rustc libraries with that rustc. # This step can take 30 minutes or more. @@ -158,5 +159,8 @@ rustup toolchain link stage1 build/x86_64-unknown-linux-gnu/stage1 rustup override set stage1 ``` +For more information about building and configuring a local compiler, +see . + With this, you should now have a working development setup! See [above](#building-and-testing-miri) for how to proceed working on Miri. From 737ecef376925f77500495d431a22cfbaecddcbe Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 10 Nov 2020 16:47:56 +0100 Subject: [PATCH 2440/3747] rustup and update test --- rust-version | 2 +- tests/run-pass/concurrency/sync_singlethread.rs | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/rust-version b/rust-version index 514517267a01c..c6a3130a5a493 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -89631663b7ad2d46d3e4f52bcfa7bee2be9eb82b +cf9cf7c923eb01146971429044f216a3ca905e06 diff --git a/tests/run-pass/concurrency/sync_singlethread.rs b/tests/run-pass/concurrency/sync_singlethread.rs index 749db855e296f..ab0203906d365 100644 --- a/tests/run-pass/concurrency/sync_singlethread.rs +++ b/tests/run-pass/concurrency/sync_singlethread.rs @@ -1,5 +1,3 @@ -#![feature(rustc_private, renamed_spin_loop)] - use std::sync::{Mutex, TryLockError}; use std::sync::atomic; use std::hint; From db718d72aef42618343cbefb0350ac95b1f80af0 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 10 Nov 2020 16:51:07 +0100 Subject: [PATCH 2441/3747] remove some unnecessary feature flags --- tests/compile-fail/check_arg_count_too_few_args.rs | 1 - tests/compile-fail/check_arg_count_too_many_args.rs | 1 - tests/compile-fail/shim_arg_size.rs | 2 -- tests/run-pass/calloc.rs | 4 ++-- tests/run-pass/fs.rs | 4 ++-- tests/run-pass/malloc.rs | 4 ++-- tests/run-pass/regions-mock-trans.rs | 1 + 7 files changed, 7 insertions(+), 10 deletions(-) diff --git a/tests/compile-fail/check_arg_count_too_few_args.rs b/tests/compile-fail/check_arg_count_too_few_args.rs index c6c19e042dd48..f8d11832683b4 100644 --- a/tests/compile-fail/check_arg_count_too_few_args.rs +++ b/tests/compile-fail/check_arg_count_too_few_args.rs @@ -1,5 +1,4 @@ #![feature(core_intrinsics)] -#![feature(rustc_private)] fn main() { extern "C" { diff --git a/tests/compile-fail/check_arg_count_too_many_args.rs b/tests/compile-fail/check_arg_count_too_many_args.rs index cca03e53ec10e..5163d223fa425 100644 --- a/tests/compile-fail/check_arg_count_too_many_args.rs +++ b/tests/compile-fail/check_arg_count_too_many_args.rs @@ -1,5 +1,4 @@ #![feature(core_intrinsics)] -#![feature(rustc_private)] fn main() { extern "C" { diff --git a/tests/compile-fail/shim_arg_size.rs b/tests/compile-fail/shim_arg_size.rs index dd8d6dac51de8..556195d6e9050 100644 --- a/tests/compile-fail/shim_arg_size.rs +++ b/tests/compile-fail/shim_arg_size.rs @@ -1,5 +1,3 @@ -#![feature(rustc_private)] - fn main() { extern "C" { // Use the wrong type(ie. not the pointer width) for the `size` diff --git a/tests/run-pass/calloc.rs b/tests/run-pass/calloc.rs index 6793f86c116cb..9f614ce971ba9 100644 --- a/tests/run-pass/calloc.rs +++ b/tests/run-pass/calloc.rs @@ -2,10 +2,10 @@ #![feature(rustc_private)] -use core::slice; - extern crate libc; +use core::slice; + fn main() { unsafe { let p1 = libc::calloc(0, 0); diff --git a/tests/run-pass/fs.rs b/tests/run-pass/fs.rs index f74d1c9a36b1b..1261dbf1768d6 100644 --- a/tests/run-pass/fs.rs +++ b/tests/run-pass/fs.rs @@ -3,6 +3,8 @@ #![feature(rustc_private)] +extern crate libc; + use std::fs::{ File, create_dir, OpenOptions, read_dir, remove_dir, remove_dir_all, remove_file, rename, }; @@ -10,8 +12,6 @@ use std::ffi::CString; use std::io::{Read, Write, Error, ErrorKind, Result, Seek, SeekFrom}; use std::path::{PathBuf, Path}; -extern crate libc; - fn main() { test_file(); diff --git a/tests/run-pass/malloc.rs b/tests/run-pass/malloc.rs index 8e0d9ac629328..b8eb7b50d3403 100644 --- a/tests/run-pass/malloc.rs +++ b/tests/run-pass/malloc.rs @@ -2,10 +2,10 @@ #![feature(rustc_private)] -use core::{slice, ptr}; - extern crate libc; +use core::{slice, ptr}; + fn main() { // Test that small allocations sometimes *are* not very aligned. let saw_unaligned = (0..64).any(|_| unsafe { diff --git a/tests/run-pass/regions-mock-trans.rs b/tests/run-pass/regions-mock-trans.rs index 0b2433d84fa88..23ec91461db5f 100644 --- a/tests/run-pass/regions-mock-trans.rs +++ b/tests/run-pass/regions-mock-trans.rs @@ -3,6 +3,7 @@ #![feature(rustc_private)] extern crate libc; + use std::mem; struct Arena(()); From df0de77fd1b5debc1e9aff4ddfcd73d24e21006f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 10 Nov 2020 16:51:55 +0100 Subject: [PATCH 2442/3747] test btreemap with raw ptr tracking --- tests/run-pass/btreemap.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/run-pass/btreemap.rs b/tests/run-pass/btreemap.rs index e639ba6225ca3..ca548a03703e6 100644 --- a/tests/run-pass/btreemap.rs +++ b/tests/run-pass/btreemap.rs @@ -1,3 +1,5 @@ +// compile-flags: -Zmiri-track-raw-pointers +// ignore-windows (FIXME: tracking raw pointers does not work on Windows) #![feature(btree_drain_filter)] use std::collections::{BTreeMap, BTreeSet}; use std::mem; From 43673d9a87200f55423c01e85e108c2c9cfcefcb Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 11 Nov 2020 10:29:10 +0100 Subject: [PATCH 2443/3747] rustup --- rust-version | 2 +- src/helpers.rs | 6 +++--- src/machine.rs | 2 +- src/shims/env.rs | 12 ++++++------ src/shims/foreign_items.rs | 2 +- src/shims/os_str.rs | 2 +- src/shims/posix/foreign_items.rs | 4 ++-- src/shims/posix/fs.rs | 4 ++-- src/shims/posix/linux/dlsym.rs | 2 +- src/shims/posix/macos/dlsym.rs | 2 +- src/shims/tls.rs | 2 +- src/shims/windows/dlsym.rs | 2 +- src/shims/windows/foreign_items.rs | 2 +- 13 files changed, 22 insertions(+), 22 deletions(-) diff --git a/rust-version b/rust-version index c6a3130a5a493..e19cca38c0407 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -cf9cf7c923eb01146971429044f216a3ca905e06 +38030ffb4e735b26260848b744c0910a5641e1db diff --git a/src/helpers.rs b/src/helpers.rs index a13d9b4519bd1..4c989db0170b5 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -387,7 +387,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// if this is not the case. fn assert_target_os(&self, target_os: &str, name: &str) { assert_eq!( - self.eval_context_ref().tcx.sess.target.target_os, + self.eval_context_ref().tcx.sess.target.os, target_os, "`{}` is only available on the `{}` target OS", name, @@ -431,8 +431,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx use std::io::ErrorKind::*; let this = self.eval_context_mut(); let target = &this.tcx.sess.target; - let target_os = &target.target_os; - let last_error = if target.options.target_family == Some("unix".to_owned()) { + let target_os = &target.os; + let last_error = if target.os_family == Some("unix".to_owned()) { this.eval_libc(match e.kind() { ConnectionRefused => "ECONNREFUSED", ConnectionReset => "ECONNRESET", diff --git a/src/machine.rs b/src/machine.rs index e9f9298e566c8..2537956228adb 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -172,7 +172,7 @@ impl MemoryExtra { pub fn init_extern_statics<'tcx, 'mir>( this: &mut MiriEvalContext<'mir, 'tcx>, ) -> InterpResult<'tcx> { - match this.tcx.sess.target.target_os.as_str() { + match this.tcx.sess.target.os.as_str() { "linux" => { // "__cxa_thread_atexit_impl" // This should be all-zero, pointer-sized. diff --git a/src/shims/env.rs b/src/shims/env.rs index 2db64ad5a14c6..12d1cda96da04 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -38,7 +38,7 @@ impl<'tcx> EnvVars<'tcx> { ecx: &mut InterpCx<'mir, 'tcx, Evaluator<'mir, 'tcx>>, mut excluded_env_vars: Vec, ) -> InterpResult<'tcx> { - let target_os = ecx.tcx.sess.target.target_os.as_str(); + let target_os = ecx.tcx.sess.target.os.as_str(); if target_os == "windows" { // Temporary hack: Exclude `TERM` var to avoid terminfo trying to open the termcap file. // Can be removed once https://github.com/rust-lang/miri/issues/1013 is resolved. @@ -101,7 +101,7 @@ impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mi pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { fn getenv(&mut self, name_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); - let target_os = &this.tcx.sess.target.target_os; + let target_os = &this.tcx.sess.target.os; assert!(target_os == "linux" || target_os == "macos", "`getenv` is only available for the UNIX target family"); let name_ptr = this.read_scalar(name_op)?.check_init()?; @@ -185,7 +185,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx value_op: OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, i32> { let mut this = self.eval_context_mut(); - let target_os = &this.tcx.sess.target.target_os; + let target_os = &this.tcx.sess.target.os; assert!(target_os == "linux" || target_os == "macos", "`setenv` is only available for the UNIX target family"); let name_ptr = this.read_scalar(name_op)?.check_init()?; @@ -258,7 +258,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn unsetenv(&mut self, name_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - let target_os = &this.tcx.sess.target.target_os; + let target_os = &this.tcx.sess.target.os; assert!(target_os == "linux" || target_os == "macos", "`unsetenv` is only available for the UNIX target family"); let name_ptr = this.read_scalar(name_op)?.check_init()?; @@ -290,7 +290,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx size_op: OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); - let target_os = &this.tcx.sess.target.target_os; + let target_os = &this.tcx.sess.target.os; assert!(target_os == "linux" || target_os == "macos", "`getcwd` is only available for the UNIX target family"); this.check_no_isolation("`getcwd`")?; @@ -336,7 +336,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn chdir(&mut self, path_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - let target_os = &this.tcx.sess.target.target_os; + let target_os = &this.tcx.sess.target.os; assert!(target_os == "linux" || target_os == "macos", "`getcwd` is only available for the UNIX target family"); this.check_no_isolation("`chdir`")?; diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index cd6024444fa54..24fa119446e85 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -486,7 +486,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // Platform-specific shims - _ => match this.tcx.sess.target.target_os.as_str() { + _ => match this.tcx.sess.target.os.as_str() { "linux" | "macos" => return shims::posix::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, args, dest, ret), "windows" => return shims::windows::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, args, dest, ret), target => throw_unsup_format!("the target `{}` is not supported", target), diff --git a/src/shims/os_str.rs b/src/shims/os_str.rs index 268b0902e9c29..21b5a876463e9 100644 --- a/src/shims/os_str.rs +++ b/src/shims/os_str.rs @@ -234,7 +234,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx direction: PathConversion, ) -> Cow<'a, OsStr> { let this = self.eval_context_ref(); - let target_os = &this.tcx.sess.target.target_os; + let target_os = &this.tcx.sess.target.os; #[cfg(windows)] return if target_os == "windows" { // Windows-on-Windows, all fine. diff --git a/src/shims/posix/foreign_items.rs b/src/shims/posix/foreign_items.rs index c527fa0d064a9..aac164b709b21 100644 --- a/src/shims/posix/foreign_items.rs +++ b/src/shims/posix/foreign_items.rs @@ -165,7 +165,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.read_scalar(handle)?.to_machine_usize(this)?; let symbol = this.read_scalar(symbol)?.check_init()?; let symbol_name = this.memory.read_c_str(symbol)?; - if let Some(dlsym) = Dlsym::from_str(symbol_name, &this.tcx.sess.target.target_os)? { + if let Some(dlsym) = Dlsym::from_str(symbol_name, &this.tcx.sess.target.os)? { let ptr = this.memory.create_fn_alloc(FnVal::Other(dlsym)); this.write_scalar(Scalar::from(ptr), dest)?; } else { @@ -452,7 +452,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Platform-specific shims _ => { - match this.tcx.sess.target.target_os.as_str() { + match this.tcx.sess.target.os.as_str() { "linux" => return shims::posix::linux::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, args, dest, ret), "macos" => return shims::posix::macos::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, args, dest, ret), _ => unreachable!(), diff --git a/src/shims/posix/fs.rs b/src/shims/posix/fs.rs index a9d102912ab20..50589ca322dbe 100644 --- a/src/shims/posix/fs.rs +++ b/src/shims/posix/fs.rs @@ -555,7 +555,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx }, None => return this.handle_not_found(), } - } else if this.tcx.sess.target.target_os == "macos" + } else if this.tcx.sess.target.os == "macos" && cmd == this.eval_libc_i32("F_FULLFSYNC")? { let &[_, _] = check_arg_count(args)?; @@ -989,7 +989,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.check_no_isolation("`mkdir`")?; #[cfg_attr(not(unix), allow(unused_variables))] - let mode = if this.tcx.sess.target.target_os == "macos" { + let mode = if this.tcx.sess.target.os == "macos" { u32::from(this.read_scalar(mode_op)?.check_init()?.to_u16()?) } else { this.read_scalar(mode_op)?.to_u32()? diff --git a/src/shims/posix/linux/dlsym.rs b/src/shims/posix/linux/dlsym.rs index af5f5a20e4454..ca5cf3ffe8f34 100644 --- a/src/shims/posix/linux/dlsym.rs +++ b/src/shims/posix/linux/dlsym.rs @@ -27,7 +27,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let (_dest, _ret) = ret.expect("we don't support any diverging dlsym"); - assert!(this.tcx.sess.target.target_os == "linux"); + assert!(this.tcx.sess.target.os == "linux"); match dlsym {} } diff --git a/src/shims/posix/macos/dlsym.rs b/src/shims/posix/macos/dlsym.rs index 82d8b16ad66ac..5b59cf27ee3be 100644 --- a/src/shims/posix/macos/dlsym.rs +++ b/src/shims/posix/macos/dlsym.rs @@ -32,7 +32,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let (dest, ret) = ret.expect("we don't support any diverging dlsym"); - assert!(this.tcx.sess.target.target_os == "macos"); + assert!(this.tcx.sess.target.os == "macos"); match dlsym { Dlsym::getentropy => { diff --git a/src/shims/tls.rs b/src/shims/tls.rs index 7b4d8fa56ae4f..2ca860367effe 100644 --- a/src/shims/tls.rs +++ b/src/shims/tls.rs @@ -340,7 +340,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // This is the first time we got asked to schedule a destructor. The // Windows schedule destructor function must be called exactly once, // this is why it is in this block. - if this.tcx.sess.target.target_os == "windows" { + if this.tcx.sess.target.os == "windows" { // On Windows, we signal that the thread quit by starting the // relevant function, reenabling the thread, and going back to // the scheduler. diff --git a/src/shims/windows/dlsym.rs b/src/shims/windows/dlsym.rs index 5454a00f14d5b..415299c51fc66 100644 --- a/src/shims/windows/dlsym.rs +++ b/src/shims/windows/dlsym.rs @@ -44,7 +44,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let (dest, ret) = ret.expect("we don't support any diverging dlsym"); - assert!(this.tcx.sess.target.target_os == "windows"); + assert!(this.tcx.sess.target.os == "windows"); match dlsym { Dlsym::AcquireSRWLockExclusive => { diff --git a/src/shims/windows/foreign_items.rs b/src/shims/windows/foreign_items.rs index d141fa57e13a4..12b714880b359 100644 --- a/src/shims/windows/foreign_items.rs +++ b/src/shims/windows/foreign_items.rs @@ -213,7 +213,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let &[hModule, lpProcName] = check_arg_count(args)?; this.read_scalar(hModule)?.to_machine_isize(this)?; let name = this.memory.read_c_str(this.read_scalar(lpProcName)?.check_init()?)?; - if let Some(dlsym) = Dlsym::from_str(name, &this.tcx.sess.target.target_os)? { + if let Some(dlsym) = Dlsym::from_str(name, &this.tcx.sess.target.os)? { let ptr = this.memory.create_fn_alloc(FnVal::Other(dlsym)); this.write_scalar(Scalar::from(ptr), dest)?; } else { From 915d091973214c4379409fed7ed36b26c9d7750a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 12 Nov 2020 16:50:24 +0100 Subject: [PATCH 2444/3747] rustup; less strict timing tests --- rust-version | 2 +- tests/run-pass/concurrency/linux-futex.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/rust-version b/rust-version index e19cca38c0407..3b96c994a7825 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -38030ffb4e735b26260848b744c0910a5641e1db +12f0dba618e761c987142474435dff95ab177f3c diff --git a/tests/run-pass/concurrency/linux-futex.rs b/tests/run-pass/concurrency/linux-futex.rs index 391e9524324ae..0f2a0236326b1 100644 --- a/tests/run-pass/concurrency/linux-futex.rs +++ b/tests/run-pass/concurrency/linux-futex.rs @@ -90,7 +90,7 @@ fn wait_timeout() { assert_eq!(*libc::__errno_location(), libc::ETIMEDOUT); } - assert!((200..500).contains(&start.elapsed().as_millis())); + assert!((200..1000).contains(&start.elapsed().as_millis())); } fn wait_wake() { @@ -120,7 +120,7 @@ fn wait_wake() { ), 0); } - assert!((200..500).contains(&start.elapsed().as_millis())); + assert!((200..1000).contains(&start.elapsed().as_millis())); } fn main() { From 69fb6413ddc5b7fd5d9cb0a68ebf58ee513bf9d5 Mon Sep 17 00:00:00 2001 From: JCTyBlaidd Date: Sun, 15 Nov 2020 18:30:26 +0000 Subject: [PATCH 2445/3747] Tidy up comments and function layout, should fix most of the review notes. --- src/bin/miri.rs | 3 + src/data_race.rs | 1104 +++++++++-------- src/eval.rs | 3 + src/lib.rs | 4 +- src/machine.rs | 31 +- src/shims/intrinsics.rs | 166 +-- src/shims/posix/linux/sync.rs | 12 +- src/shims/posix/sync.rs | 16 +- src/shims/posix/thread.rs | 15 +- src/sync.rs | 58 +- src/thread.rs | 49 +- src/vector_clock.rs | 323 ++--- tests/run-pass/concurrency/data_race.stderr | 2 +- tests/run-pass/concurrency/linux-futex.stderr | 2 +- tests/run-pass/concurrency/simple.stderr | 2 +- tests/run-pass/concurrency/sync.stderr | 2 +- .../run-pass/concurrency/thread_locals.stderr | 2 +- .../run-pass/concurrency/tls_lib_drop.stderr | 2 +- tests/run-pass/libc.stderr | 2 +- tests/run-pass/panic/concurrent-panic.stderr | 2 +- 20 files changed, 1005 insertions(+), 795 deletions(-) diff --git a/src/bin/miri.rs b/src/bin/miri.rs index ef1429a35020a..1117b69116a5d 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -195,6 +195,9 @@ fn main() { "-Zmiri-disable-stacked-borrows" => { miri_config.stacked_borrows = false; } + "-Zmiri-disable-data-race-detector" => { + miri_config.data_race_detector = false; + } "-Zmiri-disable-alignment-check" => { miri_config.check_alignment = miri::AlignmentCheck::None; } diff --git a/src/data_race.rs b/src/data_race.rs index 57f09146d6f82..822ceab8fa04c 100644 --- a/src/data_race.rs +++ b/src/data_race.rs @@ -1,16 +1,36 @@ -//! Implementation of a data-race detector -//! uses Lamport Timestamps / Vector-clocks -//! base on the Dyamic Race Detection for C++: -//! - https://www.doc.ic.ac.uk/~afd/homepages/papers/pdfs/2017/POPL.pdf -//! to extend data-race detection to work correctly with fences -//! and RMW operations +//! Implementation of a data-race detector using Lamport Timestamps / Vector-clocks +//! based on the Dyamic Race Detection for C++: +//! https://www.doc.ic.ac.uk/~afd/homepages/papers/pdfs/2017/POPL.pdf +//! which does not report false-positives when fences are used, and gives better +//! accuracy in presence of read-modify-write operations. +//! //! This does not explore weak memory orders and so can still miss data-races -//! but should not report false-positives +//! but should not report false-positives +//! //! Data-race definiton from(https://en.cppreference.com/w/cpp/language/memory_model#Threads_and_data_races): -//! - if a memory location is accessed by twice is a data-race unless: -//! - both operations execute on the same thread/signal-handler -//! - both conflicting operations are atomic operations (1 atomic and 1 non-atomic race) -//! - 1 of the operations happens-before the other operation (see link for definition) +//! a data race occurs between two memory accesses if they are on different threads, at least one operation +//! is non-atomic, at least one operation is a write and neither access happens-before the other. Read the link +//! for full definition. +//! +//! This re-uses vector indexes for threads that are known to be unable to report data-races, this is valid +//! because it only re-uses vector indexes once all currently-active (not-terminated) threads have an internal +//! vector clock that happens-after the join operation of the candidate thread. Threads that have not been joined +//! on are not considered. Since the thread's vector clock will only increase and a data-race implies that +//! there is some index x where clock[x] > thread_clock, when this is true clock[candidate-idx] > thread_clock +//! can never hold and hence a data-race can never be reported in that vector index again. +//! This means that the thread-index can be safely re-used, starting on the next timestamp for the newly created +//! thread. +//! +//! The sequentially consistant ordering corresponds to the ordering that the threads +//! are currently scheduled, this means that the data-race detector has no additional +//! logic for sequentially consistent accesses at the moment since they are indistinguishable +//! from acquire/release operations. If weak memory orderings are explored then this +//! may need to change or be updated accordingly. +//! +//! FIXME: +//! currently we have our own local copy of the currently active thread index and names, this is due +//! in part to the inability to access the current location of threads.active_thread inside the AllocExtra +//! read, write and deallocate functions and should be cleaned up in the future. use std::{ fmt::Debug, rc::Rc, @@ -19,23 +39,23 @@ use std::{ use rustc_index::vec::{Idx, IndexVec}; use rustc_target::abi::Size; -use rustc_middle::ty::layout::TyAndLayout; +use rustc_middle::{mir, ty::layout::TyAndLayout}; use rustc_data_structures::fx::{FxHashSet, FxHashMap}; use crate::{ MiriEvalContext, MiriEvalContextExt, ThreadId, Tag, RangeMap, InterpResult, Pointer, ScalarMaybeUninit, - MPlaceTy, OpTy, MemPlaceMeta, - VClock, VSmallClockSet, VectorIdx, VTimestamp + MPlaceTy, OpTy, MemPlaceMeta, ImmTy, Immediate, + VClock, VSmallClockMap, VectorIdx, VTimestamp }; pub type AllocExtra = VClockAlloc; pub type MemoryExtra = Rc; -/// Valid atomic read-write operations, alias of atomic::Ordering (not non-exhaustive) +/// Valid atomic read-write operations, alias of atomic::Ordering (not non-exhaustive). #[derive(Copy, Clone, PartialEq, Eq, Debug)] -pub enum AtomicRWOp { +pub enum AtomicRwOp { Relaxed, Acquire, Release, @@ -43,7 +63,7 @@ pub enum AtomicRWOp { SeqCst, } -/// Valid atomic read operations, subset of atomic::Ordering +/// Valid atomic read operations, subset of atomic::Ordering. #[derive(Copy, Clone, PartialEq, Eq, Debug)] pub enum AtomicReadOp { Relaxed, @@ -51,7 +71,7 @@ pub enum AtomicReadOp { SeqCst, } -/// Valid atomic write operations, subset of atomic::Ordering +/// Valid atomic write operations, subset of atomic::Ordering. #[derive(Copy, Clone, PartialEq, Eq, Debug)] pub enum AtomicWriteOp { Relaxed, @@ -60,7 +80,7 @@ pub enum AtomicWriteOp { } -/// Valid atomic fence operations, subset of atomic::Ordering +/// Valid atomic fence operations, subset of atomic::Ordering. #[derive(Copy, Clone, PartialEq, Eq, Debug)] pub enum AtomicFenceOp { Acquire, @@ -69,315 +89,124 @@ pub enum AtomicFenceOp { SeqCst, } -/// Evaluation context extensions -impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for MiriEvalContext<'mir, 'tcx> {} -pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { - // Temporarily allow data-races to occur, this should only be - // used if either one of the appropiate `validate_atomic` functions - // will be called to treat a memory access as atomic or if the memory - // being accessed should be treated as internal state, that cannot be - // accessed by the interpreted program. - #[inline] - fn allow_data_races_ref(&self, op: impl FnOnce(&MiriEvalContext<'mir, 'tcx>) -> R) -> R { - let this = self.eval_context_ref(); - let data_race = &*this.memory.extra.data_race; - let old = data_race.multi_threaded.replace(false); - let result = op(this); - data_race.multi_threaded.set(old); - result - } - /// Same as `allow_data_races_ref`, this temporarily disables any data-race detection and - /// so should only be used for atomic operations or internal state that the program cannot - /// access - #[inline] - fn allow_data_races_mut(&mut self, op: impl FnOnce(&mut MiriEvalContext<'mir, 'tcx>) -> R) -> R { - let this = self.eval_context_mut(); - let data_race = &*this.memory.extra.data_race; - let old = data_race.multi_threaded.replace(false); - let result = op(this); - let data_race = &*this.memory.extra.data_race; - data_race.multi_threaded.set(old); - result - } - - - fn read_scalar_at_offset_atomic( - &self, - op: OpTy<'tcx, Tag>, - offset: u64, - layout: TyAndLayout<'tcx>, - atomic: AtomicReadOp - ) -> InterpResult<'tcx, ScalarMaybeUninit> { - let this = self.eval_context_ref(); - let op_place = this.deref_operand(op)?; - let offset = Size::from_bytes(offset); - // Ensure that the following read at an offset is within bounds - assert!(op_place.layout.size >= offset + layout.size); - let value_place = op_place.offset(offset, MemPlaceMeta::None, layout, this)?; - this.read_scalar_atomic(value_place, atomic) - } - fn write_scalar_at_offset_atomic( - &mut self, - op: OpTy<'tcx, Tag>, - offset: u64, - value: impl Into>, - layout: TyAndLayout<'tcx>, - atomic: AtomicWriteOp - ) -> InterpResult<'tcx> { - let this = self.eval_context_mut(); - let op_place = this.deref_operand(op)?; - let offset = Size::from_bytes(offset); - // Ensure that the following read at an offset is within bounds - assert!(op_place.layout.size >= offset + layout.size); - let value_place = op_place.offset(offset, MemPlaceMeta::None, layout, this)?; - this.write_scalar_atomic(value.into(), value_place, atomic) - } - fn read_scalar_atomic( - &self, place: MPlaceTy<'tcx, Tag>, atomic: AtomicReadOp - ) -> InterpResult<'tcx, ScalarMaybeUninit> { - let scalar = self.allow_data_races_ref(move |this| { - this.read_scalar(place.into()) - })?; - self.validate_atomic_load(place, atomic)?; - Ok(scalar) - } - fn write_scalar_atomic( - &mut self, val: ScalarMaybeUninit, dest: MPlaceTy<'tcx, Tag>, - atomic: AtomicWriteOp - ) -> InterpResult<'tcx> { - self.allow_data_races_mut(move |this| { - this.write_scalar(val, dest.into()) - })?; - self.validate_atomic_store(dest, atomic) - } - - /// Update the data-race detector for an atomic read occuring at the - /// associated memory-place and on the current thread - fn validate_atomic_load( - &self, place: MPlaceTy<'tcx, Tag>, atomic: AtomicReadOp - ) -> InterpResult<'tcx> { - let this = self.eval_context_ref(); - this.validate_atomic_op( - place, atomic, "Atomic Load", - move |memory, clocks, index, atomic| { - if atomic == AtomicReadOp::Relaxed { - memory.load_relaxed(&mut *clocks, index) - }else{ - memory.acquire(&mut *clocks, index) - } - } - ) - } +/// The current set of vector clocks describing the state +/// of a thread, contains the happens-before clock and +/// additional metadata to model atomic fence operations. +#[derive(Clone, Default, Debug)] +struct ThreadClockSet { - /// Update the data-race detector for an atomic write occuring at the - /// associated memory-place and on the current thread - fn validate_atomic_store( - &mut self, place: MPlaceTy<'tcx, Tag>, atomic: AtomicWriteOp - ) -> InterpResult<'tcx> { - let this = self.eval_context_ref(); - this.validate_atomic_op( - place, atomic, "Atomic Store", - move |memory, clocks, index, atomic| { - if atomic == AtomicWriteOp::Relaxed { - memory.store_relaxed(clocks, index) - }else{ - memory.release(clocks, index) - } - } - ) - } + /// The increasing clock representing timestamps + /// that happen-before this thread. + clock: VClock, - /// Update the data-race detector for an atomic read-modify-write occuring - /// at the associated memory place and on the current thread - fn validate_atomic_rmw( - &mut self, place: MPlaceTy<'tcx, Tag>, atomic: AtomicRWOp - ) -> InterpResult<'tcx> { - use AtomicRWOp::*; - let acquire = matches!(atomic, Acquire | AcqRel | SeqCst); - let release = matches!(atomic, Release | AcqRel | SeqCst); - let this = self.eval_context_ref(); - this.validate_atomic_op( - place, atomic, "Atomic RMW", - move |memory, clocks, index, _| { - if acquire { - memory.acquire(clocks, index)?; - }else{ - memory.load_relaxed(clocks, index)?; - } - if release { - memory.rmw_release(clocks, index) - }else{ - memory.rmw_relaxed(clocks, index) - } - } - ) - } + /// The set of timestamps that will happen-before this + /// thread once it performs an acquire fence. + fence_acquire: VClock, - /// Update the data-race detector for an atomic fence on the current thread - fn validate_atomic_fence(&mut self, atomic: AtomicFenceOp) -> InterpResult<'tcx> { - let this = self.eval_context_mut(); - let data_race = &*this.memory.extra.data_race; - data_race.maybe_perform_sync_operation(move |index, mut clocks| { - log::trace!("Atomic fence on {:?} with ordering {:?}", index, atomic); - // Apply data-race detection for the current fences - // this treats AcqRel and SeqCst as the same as a acquire - // and release fence applied in the same timestamp. - if atomic != AtomicFenceOp::Release { - // Either Acquire | AcqRel | SeqCst - clocks.apply_acquire_fence(); - } - if atomic != AtomicFenceOp::Acquire { - // Either Release | AcqRel | SeqCst - clocks.apply_release_fence(); - } - Ok(()) - }) - } + /// The last timesamp of happens-before relations that + /// have been released by this thread by a fence. + fence_release: VClock, } -impl<'mir, 'tcx: 'mir> EvalContextPrivExt<'mir, 'tcx> for MiriEvalContext<'mir, 'tcx> {} -trait EvalContextPrivExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { - /// Generic atomic operation implementation, - /// this accesses memory via get_raw instead of - /// get_raw_mut, due to issues calling get_raw_mut - /// for atomic loads from read-only memory - /// FIXME: is this valid, or should get_raw_mut be used for - /// atomic-stores/atomic-rmw? - fn validate_atomic_op( - &self, place: MPlaceTy<'tcx, Tag>, - atomic: A, description: &str, - mut op: impl FnMut( - &mut MemoryCellClocks, &mut ThreadClockSet, VectorIdx, A - ) -> Result<(), DataRace> - ) -> InterpResult<'tcx> { - let this = self.eval_context_ref(); - let data_race = &*this.memory.extra.data_race; - if data_race.multi_threaded.get() { - - // Load an log the atomic operation - let place_ptr = place.ptr.assert_ptr(); - let size = place.layout.size; - let alloc_meta = &this.memory.get_raw(place_ptr.alloc_id)?.extra.data_race; - log::trace!( - "Atomic op({}) with ordering {:?} on memory({:?}, offset={}, size={})", - description, &atomic, place_ptr.alloc_id, place_ptr.offset.bytes(), size.bytes() - ); - - // Perform the atomic operation - let data_race = &alloc_meta.global; - data_race.maybe_perform_sync_operation(|index, mut clocks| { - for (_,range) in alloc_meta.alloc_ranges.borrow_mut().iter_mut(place_ptr.offset, size) { - if let Err(DataRace) = op(range, &mut *clocks, index, atomic) { - mem::drop(clocks); - return VClockAlloc::report_data_race( - &alloc_meta.global, range, description, true, - place_ptr, size - ); - } - } - Ok(()) - })?; +impl ThreadClockSet { - // Log changes to atomic memory - if log::log_enabled!(log::Level::Trace) { - for (_,range) in alloc_meta.alloc_ranges.borrow().iter(place_ptr.offset, size) { - log::trace!( - "Updated atomic memory({:?}, offset={}, size={}) to {:#?}", - place.ptr.assert_ptr().alloc_id, place_ptr.offset.bytes(), size.bytes(), - range.atomic_ops - ); - } - } - } - Ok(()) + /// Apply the effects of a release fence to this + /// set of thread vector clocks. + #[inline] + fn apply_release_fence(&mut self) { + self.fence_release.clone_from(&self.clock); } -} - -/// Handle for locks to express their -/// acquire-release semantics -#[derive(Clone, Debug, Default)] -pub struct DataRaceLockHandle { + /// Apply the effects of a acquire fence to this + /// set of thread vector clocks. + #[inline] + fn apply_acquire_fence(&mut self) { + self.clock.join(&self.fence_acquire); + } - /// Internal acquire-release clock - /// to express the acquire release sync - /// found in concurrency primitives - clock: VClock, -} -impl DataRaceLockHandle { - pub fn set_values(&mut self, other: &Self) { - self.clock.clone_from(&other.clock) + /// Increment the happens-before clock at a + /// known index. + #[inline] + fn increment_clock(&mut self, index: VectorIdx) { + self.clock.increment_index(index); } - pub fn reset(&mut self) { - self.clock.set_zero_vector(); + + /// Join the happens-before clock with that of + /// another thread, used to model thread join + /// operations. + fn join_with(&mut self, other: &ThreadClockSet) { + self.clock.join(&other.clock); } } /// Error returned by finding a data race -/// should be elaborated upon +/// should be elaborated upon. #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] pub struct DataRace; /// Externally stored memory cell clocks -/// explicitly to reduce memory usage for the -/// common case where no atomic operations -/// exists on the memory cell +/// explicitly to reduce memory usage for the +/// common case where no atomic operations +/// exists on the memory cell. #[derive(Clone, PartialEq, Eq, Default, Debug)] struct AtomicMemoryCellClocks { - /// The clock-vector for the set of atomic read operations - /// used for detecting data-races with non-atomic write - /// operations + /// The clock-vector of the timestamp of the last atomic + /// read operation performed by each thread. + /// This detects potential data-races between atomic read + /// and non-atomic write operations. read_vector: VClock, - /// The clock-vector for the set of atomic write operations - /// used for detecting data-races with non-atomic read or - /// write operations + /// The clock-vector of the timestamp of the last atomic + /// write operation performed by each thread. + /// This detects potential data-races between atomic write + /// and non-atomic read or write operations. write_vector: VClock, /// Synchronization vector for acquire-release semantics - /// contains the vector of timestamps that will - /// happen-before a thread if an acquire-load is - /// performed on the data + /// contains the vector of timestamps that will + /// happen-before a thread if an acquire-load is + /// performed on the data. sync_vector: VClock, /// The Hash-Map of all threads for which a release - /// sequence exists in the memory cell, required - /// since read-modify-write operations do not - /// invalidate existing release sequences - release_sequences: VSmallClockSet, + /// sequence exists in the memory cell, required + /// since read-modify-write operations do not + /// invalidate existing release sequences. + /// See page 6 of linked paper. + release_sequences: VSmallClockMap, } /// Memory Cell vector clock metadata -/// for data-race detection +/// for data-race detection. #[derive(Clone, PartialEq, Eq, Debug)] struct MemoryCellClocks { - /// The vector-clock of the last write, only one value is stored - /// since all previous writes happened-before the current write + /// The vector-clock timestamp of the last write + /// corresponding to the writing threads timestamp. write: VTimestamp, - /// The identifier of the thread that performed the last write - /// operation + /// The identifier of the vector index, corresponding to a thread + /// that performed the last write operation. write_index: VectorIdx, - /// The vector-clock of the set of previous reads - /// each index is set to the timestamp that the associated - /// thread last read this value. + /// The vector-clock of the timestamp of the last read operation + /// performed by a thread since the last write operation occured. read: VClock, - /// Atomic acquire & release sequence tracking clocks - /// for non-atomic memory in the common case this - /// value is set to None + /// Atomic acquire & release sequence tracking clocks. + /// For non-atomic memory in the common case this + /// value is set to None. atomic_ops: Option>, } + /// Create a default memory cell clocks instance -/// for uninitialized memory +/// for uninitialized memory. impl Default for MemoryCellClocks { fn default() -> Self { MemoryCellClocks { @@ -389,9 +218,10 @@ impl Default for MemoryCellClocks { } } + impl MemoryCellClocks { - /// Load the internal atomic memory cells if they exist + /// Load the internal atomic memory cells if they exist. #[inline] fn atomic(&self) -> Option<&AtomicMemoryCellClocks> { match &self.atomic_ops { @@ -401,25 +231,26 @@ impl MemoryCellClocks { } /// Load or create the internal atomic memory metadata - /// if it does not exist + /// if it does not exist. #[inline] fn atomic_mut(&mut self) -> &mut AtomicMemoryCellClocks { self.atomic_ops.get_or_insert_with(Default::default) } /// Update memory cell data-race tracking for atomic - /// load acquire semantics, is a no-op if this memory was - /// not used previously as atomic memory - fn acquire(&mut self, clocks: &mut ThreadClockSet, index: VectorIdx) -> Result<(), DataRace> { + /// load acquire semantics, is a no-op if this memory was + /// not used previously as atomic memory. + fn load_acquire(&mut self, clocks: &mut ThreadClockSet, index: VectorIdx) -> Result<(), DataRace> { self.atomic_read_detect(clocks, index)?; if let Some(atomic) = self.atomic() { clocks.clock.join(&atomic.sync_vector); } Ok(()) } + /// Update memory cell data-race tracking for atomic - /// load relaxed semantics, is a no-op if this memory was - /// not used previously as atomic memory + /// load relaxed semantics, is a no-op if this memory was + /// not used previously as atomic memory. fn load_relaxed(&mut self, clocks: &mut ThreadClockSet, index: VectorIdx) -> Result<(), DataRace> { self.atomic_read_detect(clocks, index)?; if let Some(atomic) = self.atomic() { @@ -430,8 +261,8 @@ impl MemoryCellClocks { /// Update the memory cell data-race tracking for atomic - /// store release semantics - fn release(&mut self, clocks: &ThreadClockSet, index: VectorIdx) -> Result<(), DataRace> { + /// store release semantics. + fn store_release(&mut self, clocks: &ThreadClockSet, index: VectorIdx) -> Result<(), DataRace> { self.atomic_write_detect(clocks, index)?; let atomic = self.atomic_mut(); atomic.sync_vector.clone_from(&clocks.clock); @@ -439,8 +270,9 @@ impl MemoryCellClocks { atomic.release_sequences.insert(index, &clocks.clock); Ok(()) } + /// Update the memory cell data-race tracking for atomic - /// store relaxed semantics + /// store relaxed semantics. fn store_relaxed(&mut self, clocks: &ThreadClockSet, index: VectorIdx) -> Result<(), DataRace> { self.atomic_write_detect(clocks, index)?; let atomic = self.atomic_mut(); @@ -451,8 +283,9 @@ impl MemoryCellClocks { atomic.release_sequences.retain_index(index); Ok(()) } + /// Update the memory cell data-race tracking for atomic - /// store release semantics for RMW operations + /// store release semantics for RMW operations. fn rmw_release(&mut self, clocks: &ThreadClockSet, index: VectorIdx) -> Result<(), DataRace> { self.atomic_write_detect(clocks, index)?; let atomic = self.atomic_mut(); @@ -460,8 +293,9 @@ impl MemoryCellClocks { atomic.release_sequences.insert(index, &clocks.clock); Ok(()) } + /// Update the memory cell data-race tracking for atomic - /// store relaxed semantics for RMW operations + /// store relaxed semantics for RMW operations. fn rmw_relaxed(&mut self, clocks: &ThreadClockSet, index: VectorIdx) -> Result<(), DataRace> { self.atomic_write_detect(clocks, index)?; let atomic = self.atomic_mut(); @@ -470,60 +304,60 @@ impl MemoryCellClocks { } /// Detect data-races with an atomic read, caused by a non-atomic write that does - /// not happen-before the atomic-read + /// not happen-before the atomic-read. fn atomic_read_detect(&mut self, clocks: &ThreadClockSet, index: VectorIdx) -> Result<(), DataRace> { log::trace!("Atomic read with vectors: {:#?} :: {:#?}", self, clocks); if self.write <= clocks.clock[self.write_index] { let atomic = self.atomic_mut(); atomic.read_vector.set_at_index(&clocks.clock, index); Ok(()) - }else{ + } else { Err(DataRace) } } /// Detect data-races with an atomic write, either with a non-atomic read or with - /// a non-atomic write: + /// a non-atomic write. fn atomic_write_detect(&mut self, clocks: &ThreadClockSet, index: VectorIdx) -> Result<(), DataRace> { log::trace!("Atomic write with vectors: {:#?} :: {:#?}", self, clocks); if self.write <= clocks.clock[self.write_index] && self.read <= clocks.clock { let atomic = self.atomic_mut(); atomic.write_vector.set_at_index(&clocks.clock, index); Ok(()) - }else{ + } else { Err(DataRace) } } /// Detect races for non-atomic read operations at the current memory cell - /// returns true if a data-race is detected + /// returns true if a data-race is detected. fn read_race_detect(&mut self, clocks: &ThreadClockSet, index: VectorIdx) -> Result<(), DataRace> { log::trace!("Unsynchronized read with vectors: {:#?} :: {:#?}", self, clocks); if self.write <= clocks.clock[self.write_index] { let race_free = if let Some(atomic) = self.atomic() { atomic.write_vector <= clocks.clock - }else{ + } else { true }; if race_free { self.read.set_at_index(&clocks.clock, index); Ok(()) - }else{ + } else { Err(DataRace) } - }else{ + } else { Err(DataRace) } } /// Detect races for non-atomic write operations at the current memory cell - /// returns true if a data-race is detected + /// returns true if a data-race is detected. fn write_race_detect(&mut self, clocks: &ThreadClockSet, index: VectorIdx) -> Result<(), DataRace> { log::trace!("Unsynchronized write with vectors: {:#?} :: {:#?}", self, clocks); if self.write <= clocks.clock[self.write_index] && self.read <= clocks.clock { let race_free = if let Some(atomic) = self.atomic() { atomic.write_vector <= clocks.clock && atomic.read_vector <= clocks.clock - }else{ + } else { true }; if race_free { @@ -531,30 +365,269 @@ impl MemoryCellClocks { self.write_index = index; self.read.set_zero_vector(); Ok(()) - }else{ + } else { Err(DataRace) } - }else{ + } else { Err(DataRace) } } } -/// Vector clock metadata for a logical memory allocation + +/// Evaluation context extensions. +impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for MiriEvalContext<'mir, 'tcx> {} +pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { + + /// Atomic variant of read_scalar_at_offset. + fn read_scalar_at_offset_atomic( + &self, + op: OpTy<'tcx, Tag>, + offset: u64, + layout: TyAndLayout<'tcx>, + atomic: AtomicReadOp + ) -> InterpResult<'tcx, ScalarMaybeUninit> { + let this = self.eval_context_ref(); + let op_place = this.deref_operand(op)?; + let offset = Size::from_bytes(offset); + + // Ensure that the following read at an offset is within bounds. + assert!(op_place.layout.size >= offset + layout.size); + let value_place = op_place.offset(offset, MemPlaceMeta::None, layout, this)?; + this.read_scalar_atomic(value_place, atomic) + } + + /// Atomic variant of write_scalar_at_offset. + fn write_scalar_at_offset_atomic( + &mut self, + op: OpTy<'tcx, Tag>, + offset: u64, + value: impl Into>, + layout: TyAndLayout<'tcx>, + atomic: AtomicWriteOp + ) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + let op_place = this.deref_operand(op)?; + let offset = Size::from_bytes(offset); + + // Ensure that the following read at an offset is within bounds. + assert!(op_place.layout.size >= offset + layout.size); + let value_place = op_place.offset(offset, MemPlaceMeta::None, layout, this)?; + this.write_scalar_atomic(value.into(), value_place, atomic) + } + + /// Perform an atomic read operation at the memory location. + fn read_scalar_atomic( + &self, place: MPlaceTy<'tcx, Tag>, atomic: AtomicReadOp + ) -> InterpResult<'tcx, ScalarMaybeUninit> { + let this = self.eval_context_ref(); + let scalar = this.allow_data_races_ref(move |this| { + this.read_scalar(place.into()) + })?; + self.validate_atomic_load(place, atomic)?; + Ok(scalar) + } + + /// Perform an atomic write operation at the memory location. + fn write_scalar_atomic( + &mut self, val: ScalarMaybeUninit, dest: MPlaceTy<'tcx, Tag>, + atomic: AtomicWriteOp + ) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + this.allow_data_races_mut(move |this| { + this.write_scalar(val, dest.into()) + })?; + self.validate_atomic_store(dest, atomic) + } + + /// Perform a atomic operation on a memory location. + fn atomic_op_immediate( + &mut self, + place: MPlaceTy<'tcx, Tag>, rhs: ImmTy<'tcx, Tag>, + op: mir::BinOp, neg: bool, atomic: AtomicRwOp + ) -> InterpResult<'tcx, ImmTy<'tcx, Tag>> { + let this = self.eval_context_mut(); + + let old = this.allow_data_races_mut(|this| { + this.read_immediate(place. into()) + })?; + + // Atomics wrap around on overflow. + let val = this.binary_op(op, old, rhs)?; + let val = if neg { this.unary_op(mir::UnOp::Not, val)? } else { val }; + this.allow_data_races_mut(|this| { + this.write_immediate(*val, place.into()) + })?; + + this.validate_atomic_rmw(place, atomic)?; + Ok(old) + } + + /// Perform an atomic exchange with a memory place and a new + /// scalar value, the old value is returned. + fn atomic_exchange_scalar( + &mut self, + place: MPlaceTy<'tcx, Tag>, new: ScalarMaybeUninit, + atomic: AtomicRwOp + ) -> InterpResult<'tcx, ScalarMaybeUninit> { + let this = self.eval_context_mut(); + + let old = this.allow_data_races_mut(|this| { + this.read_scalar(place.into()) + })?; + this.allow_data_races_mut(|this| { + this.write_scalar(new, place.into()) + })?; + this.validate_atomic_rmw(place, atomic)?; + Ok(old) + } + + /// Perform an atomic compare and exchange at a given memory location + /// on success an atomic RMW operation is performed and on failure + /// only an atomic read occurs. + fn atomic_compare_exchange_scalar( + &mut self, place: MPlaceTy<'tcx, Tag>, + expect_old: ImmTy<'tcx, Tag>, new: ScalarMaybeUninit, + success: AtomicRwOp, fail: AtomicReadOp + ) -> InterpResult<'tcx, Immediate> { + let this = self.eval_context_mut(); + + // Failure ordering cannot be stronger than success ordering, therefore first attempt + // to read with the failure ordering and if successfull then try again with the success + // read ordering and write in the success case. + // Read as immediate for the sake of `binary_op()` + let old = this.allow_data_races_mut(|this| { + this.read_immediate(place.into()) + })?; + + // `binary_op` will bail if either of them is not a scalar. + let eq = this.overflowing_binary_op(mir::BinOp::Eq, old, expect_old)?.0; + let res = Immediate::ScalarPair(old.to_scalar_or_uninit(), eq.into()); + + // Update ptr depending on comparison. + // if successful, perform a full rw-atomic validation + // otherwise treat this as an atomic load with the fail ordering. + if eq.to_bool()? { + this.allow_data_races_mut(|this| { + this.write_scalar(new, place.into()) + })?; + this.validate_atomic_rmw(place, success)?; + } else { + this.validate_atomic_load(place, fail)?; + } + + // Return the old value. + Ok(res) + } + + + /// Update the data-race detector for an atomic read occuring at the + /// associated memory-place and on the current thread. + fn validate_atomic_load( + &self, place: MPlaceTy<'tcx, Tag>, atomic: AtomicReadOp + ) -> InterpResult<'tcx> { + let this = self.eval_context_ref(); + this.validate_atomic_op( + place, atomic, "Atomic Load", + move |memory, clocks, index, atomic| { + if atomic == AtomicReadOp::Relaxed { + memory.load_relaxed(&mut *clocks, index) + } else { + memory.load_acquire(&mut *clocks, index) + } + } + ) + } + + /// Update the data-race detector for an atomic write occuring at the + /// associated memory-place and on the current thread. + fn validate_atomic_store( + &mut self, place: MPlaceTy<'tcx, Tag>, atomic: AtomicWriteOp + ) -> InterpResult<'tcx> { + let this = self.eval_context_ref(); + this.validate_atomic_op( + place, atomic, "Atomic Store", + move |memory, clocks, index, atomic| { + if atomic == AtomicWriteOp::Relaxed { + memory.store_relaxed(clocks, index) + } else { + memory.store_release(clocks, index) + } + } + ) + } + + /// Update the data-race detector for an atomic read-modify-write occuring + /// at the associated memory place and on the current thread. + fn validate_atomic_rmw( + &mut self, place: MPlaceTy<'tcx, Tag>, atomic: AtomicRwOp + ) -> InterpResult<'tcx> { + use AtomicRwOp::*; + let acquire = matches!(atomic, Acquire | AcqRel | SeqCst); + let release = matches!(atomic, Release | AcqRel | SeqCst); + let this = self.eval_context_ref(); + this.validate_atomic_op( + place, atomic, "Atomic RMW", + move |memory, clocks, index, _| { + if acquire { + memory.load_acquire(clocks, index)?; + } else { + memory.load_relaxed(clocks, index)?; + } + if release { + memory.rmw_release(clocks, index) + } else { + memory.rmw_relaxed(clocks, index) + } + } + ) + } + + /// Update the data-race detector for an atomic fence on the current thread. + fn validate_atomic_fence(&mut self, atomic: AtomicFenceOp) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + if let Some(data_race) = &this.memory.extra.data_race { + data_race.maybe_perform_sync_operation(move |index, mut clocks| { + log::trace!("Atomic fence on {:?} with ordering {:?}", index, atomic); + + // Apply data-race detection for the current fences + // this treats AcqRel and SeqCst as the same as a acquire + // and release fence applied in the same timestamp. + if atomic != AtomicFenceOp::Release { + // Either Acquire | AcqRel | SeqCst + clocks.apply_acquire_fence(); + } + if atomic != AtomicFenceOp::Acquire { + // Either Release | AcqRel | SeqCst + clocks.apply_release_fence(); + } + Ok(()) + }) + } else { + Ok(()) + } + } +} + + + +/// Vector clock metadata for a logical memory allocation. #[derive(Debug, Clone)] pub struct VClockAlloc { - /// Range of Vector clocks, mapping to the vector-clock - /// index of the last write to the bytes in this allocation + /// Range of Vector clocks, this gives each byte a potentially + /// unqiue set of vector clocks, but merges identical information + /// together for improved efficiency. alloc_ranges: RefCell>, - // Pointer to global state + // Pointer to global state. global: MemoryExtra, } + impl VClockAlloc { - /// Create a new data-race allocation detector + /// Create a new data-race allocation detector. pub fn new_allocation(global: &MemoryExtra, len: Size) -> VClockAlloc { VClockAlloc { global: Rc::clone(global), @@ -565,7 +638,7 @@ impl VClockAlloc { } // Find an index, if one exists where the value - // in `l` is greater than the value in `r` + // in `l` is greater than the value in `r`. fn find_gt_index(l: &VClock, r: &VClock) -> Option { let l_slice = l.as_slice(); let r_slice = r.as_slice(); @@ -575,27 +648,28 @@ impl VClockAlloc { if l > r { Some(idx) } else { None } }).or_else(|| { if l_slice.len() > r_slice.len() { + // By invariant, if l_slice is longer - // then one element must be larger + // then one element must be larger. // This just validates that this is true - // and reports earlier elements first + // and reports earlier elements first. let l_remainder_slice = &l_slice[r_slice.len()..]; let idx = l_remainder_slice.iter().enumerate() .find_map(|(idx, &r)| { if r == 0 { None } else { Some(idx) } }).expect("Invalid VClock Invariant"); Some(idx) - }else{ + } else { None } }).map(|idx| VectorIdx::new(idx)) } - /// Report a data-race found in the program - /// this finds the two racing threads and the type - /// of data-race that occured, this will also - /// return info about the memory location the data-race - /// occured in + /// Report a data-race found in the program. + /// This finds the two racing threads and the type + /// of data-race that occured. This will also + /// return info about the memory location the data-race + /// occured in. #[cold] #[inline(never)] fn report_data_race<'tcx>( @@ -608,39 +682,40 @@ impl VClockAlloc { let ( other_action, other_thread, other_clock ) = if range.write > current_clocks.clock[range.write_index] { + // Convert the write action into the vector clock it - // represents for diagnostic purposes + // represents for diagnostic purposes. write_clock = VClock::new_with_index(range.write_index, range.write); ("WRITE", range.write_index, &write_clock) - }else if let Some(idx) = Self::find_gt_index( + } else if let Some(idx) = Self::find_gt_index( &range.read, ¤t_clocks.clock ){ ("READ", idx, &range.read) - }else if !is_atomic { + } else if !is_atomic { if let Some(atomic) = range.atomic() { if let Some(idx) = Self::find_gt_index( &atomic.write_vector, ¤t_clocks.clock ) { ("ATOMIC_STORE", idx, &atomic.write_vector) - }else if let Some(idx) = Self::find_gt_index( + } else if let Some(idx) = Self::find_gt_index( &atomic.read_vector, ¤t_clocks.clock ) { ("ATOMIC_LOAD", idx, &atomic.read_vector) - }else{ - unreachable!("Failed to find report data-race for non-atomic operation: no race found") + } else { + unreachable!("Failed to report data-race for non-atomic operation: no race found") } - }else{ + } else { unreachable!("Failed to report data-race for non-atomic operation: no atomic component") } - }else{ + } else { unreachable!("Failed to report data-race for atomic operation") }; - // Load elaborated thread information about the racing thread actions + // Load elaborated thread information about the racing thread actions. let current_thread_info = global.print_thread_metadata(current_index); let other_thread_info = global.print_thread_metadata(other_thread); - // Throw the data-race detection + // Throw the data-race detection. throw_ub_format!( "Data race detected between {} on {} and {} on {}, memory({:?},offset={},size={})\ \n\t\t -current vector clock = {:?}\ @@ -654,23 +729,25 @@ impl VClockAlloc { } /// Detect data-races for an unsychronized read operation, will not perform - /// data-race threads if `multi-threaded` is false, either due to no threads - /// being created or if it is temporarily disabled during a racy read or write - /// operation + /// data-race detection if `multi-threaded` is false, either due to no threads + /// being created or if it is temporarily disabled during a racy read or write + /// operation for which data-race detection is handled separately, for example + /// atomic read operations. pub fn read<'tcx>(&self, pointer: Pointer, len: Size) -> InterpResult<'tcx> { if self.global.multi_threaded.get() { let (index, clocks) = self.global.current_thread_state(); let mut alloc_ranges = self.alloc_ranges.borrow_mut(); for (_,range) in alloc_ranges.iter_mut(pointer.offset, len) { if let Err(DataRace) = range.read_race_detect(&*clocks, index) { - // Report data-race + + // Report data-race. return Self::report_data_race( &self.global,range, "READ", false, pointer, len ); } } Ok(()) - }else{ + } else { Ok(()) } } @@ -682,6 +759,7 @@ impl VClockAlloc { let (index, clocks) = self.global.current_thread_state(); for (_,range) in self.alloc_ranges.get_mut().iter_mut(pointer.offset, len) { if let Err(DataRace) = range.write_race_detect(&*clocks, index) { + // Report data-race return Self::report_data_race( &self.global, range, action, false, pointer, len @@ -689,156 +767,208 @@ impl VClockAlloc { } } Ok(()) - }else{ + } else { Ok(()) } } /// Detect data-races for an unsychronized write operation, will not perform - /// data-race threads if `multi-threaded` is false, either due to no threads - /// being created or if it is temporarily disabled during a racy read or write - /// operation + /// data-race threads if `multi-threaded` is false, either due to no threads + /// being created or if it is temporarily disabled during a racy read or write + /// operation pub fn write<'tcx>(&mut self, pointer: Pointer, len: Size) -> InterpResult<'tcx> { self.unique_access(pointer, len, "Write") } + /// Detect data-races for an unsychronized deallocate operation, will not perform - /// data-race threads if `multi-threaded` is false, either due to no threads - /// being created or if it is temporarily disabled during a racy read or write - /// operation + /// data-race threads if `multi-threaded` is false, either due to no threads + /// being created or if it is temporarily disabled during a racy read or write + /// operation pub fn deallocate<'tcx>(&mut self, pointer: Pointer, len: Size) -> InterpResult<'tcx> { self.unique_access(pointer, len, "Deallocate") } } -/// The current set of vector clocks describing the state -/// of a thread, contains the happens-before clock and -/// additional metadata to model atomic fence operations -#[derive(Clone, Default, Debug)] -struct ThreadClockSet { - - /// The increasing clock representing timestamps - /// that happen-before this thread. - clock: VClock, - - /// The set of timestamps that will happen-before this - /// thread once it performs an acquire fence - fence_acquire: VClock, - - /// The last timesamp of happens-before relations that - /// have been released by this thread by a fence - fence_release: VClock, -} - -impl ThreadClockSet { +impl<'mir, 'tcx: 'mir> EvalContextPrivExt<'mir, 'tcx> for MiriEvalContext<'mir, 'tcx> {} +trait EvalContextPrivExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { - /// Apply the effects of a release fence to this - /// set of thread vector clocks + // Temporarily allow data-races to occur, this should only be + // used if either one of the appropiate `validate_atomic` functions + // will be called to treat a memory access as atomic or if the memory + // being accessed should be treated as internal state, that cannot be + // accessed by the interpreted program. #[inline] - fn apply_release_fence(&mut self) { - self.fence_release.clone_from(&self.clock); + fn allow_data_races_ref(&self, op: impl FnOnce(&MiriEvalContext<'mir, 'tcx>) -> R) -> R { + let this = self.eval_context_ref(); + let old = if let Some(data_race) = &this.memory.extra.data_race { + data_race.multi_threaded.replace(false) + } else { + false + }; + let result = op(this); + if let Some(data_race) = &this.memory.extra.data_race { + data_race.multi_threaded.set(old); + } + result } - /// Apply the effects of a acquire fence to this - /// set of thread vector clocks + /// Same as `allow_data_races_ref`, this temporarily disables any data-race detection and + /// so should only be used for atomic operations or internal state that the program cannot + /// access. #[inline] - fn apply_acquire_fence(&mut self) { - self.clock.join(&self.fence_acquire); + fn allow_data_races_mut(&mut self, op: impl FnOnce(&mut MiriEvalContext<'mir, 'tcx>) -> R) -> R { + let this = self.eval_context_mut(); + let old = if let Some(data_race) = &this.memory.extra.data_race { + data_race.multi_threaded.replace(false) + } else { + false + }; + let result = op(this); + if let Some(data_race) = &this.memory.extra.data_race { + data_race.multi_threaded.set(old); + } + result } - /// Increment the happens-before clock at a - /// known index - #[inline] - fn increment_clock(&mut self, index: VectorIdx) { - self.clock.increment_index(index); + /// Generic atomic operation implementation, + /// this accesses memory via get_raw instead of + /// get_raw_mut, due to issues calling get_raw_mut + /// for atomic loads from read-only memory. + /// FIXME: is this valid, or should get_raw_mut be used for + /// atomic-stores/atomic-rmw? + fn validate_atomic_op( + &self, place: MPlaceTy<'tcx, Tag>, + atomic: A, description: &str, + mut op: impl FnMut( + &mut MemoryCellClocks, &mut ThreadClockSet, VectorIdx, A + ) -> Result<(), DataRace> + ) -> InterpResult<'tcx> { + let this = self.eval_context_ref(); + if let Some(data_race) = &this.memory.extra.data_race { + if data_race.multi_threaded.get() { + + // Load and log the atomic operation. + let place_ptr = place.ptr.assert_ptr(); + let size = place.layout.size; + let alloc_meta = &this.memory.get_raw(place_ptr.alloc_id)?.extra.data_race.as_ref().unwrap(); + log::trace!( + "Atomic op({}) with ordering {:?} on memory({:?}, offset={}, size={})", + description, &atomic, place_ptr.alloc_id, place_ptr.offset.bytes(), size.bytes() + ); + + // Perform the atomic operation. + let data_race = &alloc_meta.global; + data_race.maybe_perform_sync_operation(|index, mut clocks| { + for (_,range) in alloc_meta.alloc_ranges.borrow_mut().iter_mut(place_ptr.offset, size) { + if let Err(DataRace) = op(range, &mut *clocks, index, atomic) { + mem::drop(clocks); + return VClockAlloc::report_data_race( + &alloc_meta.global, range, description, true, + place_ptr, size + ); + } + } + Ok(()) + })?; + + // Log changes to atomic memory. + if log::log_enabled!(log::Level::Trace) { + for (_,range) in alloc_meta.alloc_ranges.borrow().iter(place_ptr.offset, size) { + log::trace!( + "Updated atomic memory({:?}, offset={}, size={}) to {:#?}", + place.ptr.assert_ptr().alloc_id, place_ptr.offset.bytes(), size.bytes(), + range.atomic_ops + ); + } + } + } + } + Ok(()) } - /// Join the happens-before clock with that of - /// another thread, used to model thread join - /// operations - fn join_with(&mut self, other: &ThreadClockSet) { - self.clock.join(&other.clock); - } } -/// Extra metadata associated with a thread + +/// Extra metadata associated with a thread. #[derive(Debug, Clone, Default)] struct ThreadExtraState { /// The current vector index in use by the - /// thread currently, this is set to None - /// after the vector index has been re-used - /// and hence the value will never need to be - /// read during data-race reporting + /// thread currently, this is set to None + /// after the vector index has been re-used + /// and hence the value will never need to be + /// read during data-race reporting. vector_index: Option, /// The name of the thread, updated for better - /// diagnostics when reporting detected data - /// races + /// diagnostics when reporting detected data + /// races. thread_name: Option>, /// Thread termination vector clock, this - /// is set on thread termination and is used - /// for joining on threads since the vector_index - /// may be re-used when the join operation occurs + /// is set on thread termination and is used + /// for joining on threads since the vector_index + /// may be re-used when the join operation occurs. termination_vector_clock: Option, } /// Global data-race detection state, contains the currently -/// executing thread as well as the vector-clocks associated -/// with each of the threads. +/// executing thread as well as the vector-clocks associated +/// with each of the threads. #[derive(Debug, Clone)] pub struct GlobalState { /// Set to true once the first additional - /// thread has launched, due to the dependency - /// between before and after a thread launch + /// thread has launched, due to the dependency + /// between before and after a thread launch. /// Any data-races must be recorded after this - /// so concurrent execution can ignore recording - /// any data-races + /// so concurrent execution can ignore recording + /// any data-races. multi_threaded: Cell, /// Mapping of a vector index to a known set of thread - /// clocks, this is not directly mapping from a thread id - /// since it may refer to multiple threads + /// clocks, this is not directly mapping from a thread id + /// since it may refer to multiple threads. vector_clocks: RefCell>, /// Mapping of a given vector index to the current thread - /// that the execution is representing, this may change - /// if a vector index is re-assigned to a new thread + /// that the execution is representing, this may change + /// if a vector index is re-assigned to a new thread. vector_info: RefCell>, - /// The mapping of a given thread to assocaited thread metadata + /// The mapping of a given thread to assocaited thread metadata. thread_info: RefCell>, - /// The current vector index being executed + /// The current vector index being executed. current_index: Cell, /// Potential vector indices that could be re-used on thread creation - /// values are inserted here on after the thread has terminated and - /// been joined with, and hence may potentially become free - /// for use as the index for a new thread. + /// values are inserted here on after the thread has terminated and + /// been joined with, and hence may potentially become free + /// for use as the index for a new thread. /// Elements in this set may still require the vector index to - /// report data-races, and can only be re-used after all - /// active vector-clocks catch up with the threads timestamp. + /// report data-races, and can only be re-used after all + /// active vector-clocks catch up with the threads timestamp. reuse_candidates: RefCell>, /// Counts the number of threads that are currently active - /// if the number of active threads reduces to 1 and then - /// a join operation occures with the remaining main thread - /// then multi-threaded execution may be disabled + /// if the number of active threads reduces to 1 and then + /// a join operation occures with the remaining main thread + /// then multi-threaded execution may be disabled. active_thread_count: Cell, /// This contains threads that have terminated, but not yet joined - /// and so cannot become re-use candidates until a join operation - /// occurs. + /// and so cannot become re-use candidates until a join operation + /// occurs. /// The associated vector index will be moved into re-use candidates - /// after the join operation occurs + /// after the join operation occurs. terminated_threads: RefCell>, } + impl GlobalState { /// Create a new global state, setup with just thread-id=0 - /// advanced to timestamp = 1 + /// advanced to timestamp = 1. pub fn new() -> Self { let global_state = GlobalState { multi_threaded: Cell::new(false), @@ -852,8 +982,8 @@ impl GlobalState { }; // Setup the main-thread since it is not explicitly created: - // uses vector index and thread-id 0, also the rust runtime gives - // the main-thread a name of "main". + // uses vector index and thread-id 0, also the rust runtime gives + // the main-thread a name of "main". let index = global_state.vector_clocks.borrow_mut().push(ThreadClockSet::default()); global_state.vector_info.borrow_mut().push(ThreadId::new(0)); global_state.thread_info.borrow_mut().push( @@ -868,7 +998,7 @@ impl GlobalState { } // Try to find vector index values that can potentially be re-used - // by a new thread instead of a new vector index being created + // by a new thread instead of a new vector index being created. fn find_vector_index_reuse_candidate(&self) -> Option { let mut reuse = self.reuse_candidates.borrow_mut(); let vector_clocks = self.vector_clocks.borrow(); @@ -877,24 +1007,26 @@ impl GlobalState { for &candidate in reuse.iter() { let target_timestamp = vector_clocks[candidate].clock[candidate]; if vector_clocks.iter_enumerated().all(|(clock_idx, clock)| { + // The thread happens before the clock, and hence cannot report - // a data-race with this the candidate index + // a data-race with this the candidate index. let no_data_race = clock.clock[candidate] >= target_timestamp; // The vector represents a thread that has terminated and hence cannot - // report a data-race with the candidate index + // report a data-race with the candidate index. let thread_id = vector_info[clock_idx]; let vector_terminated = reuse.contains(&clock_idx) || terminated_threads.contains_key(&thread_id); // The vector index cannot report a race with the candidate index - // and hence allows the candidate index to be re-used + // and hence allows the candidate index to be re-used. no_data_race || vector_terminated }) { + // All vector clocks for each vector index are equal to - // the target timestamp, and the thread is known to have - // terminated, therefore this vector clock index cannot - // report any more data-races + // the target timestamp, and the thread is known to have + // terminated, therefore this vector clock index cannot + // report any more data-races. assert!(reuse.remove(&candidate)); return Some(candidate) } @@ -903,17 +1035,17 @@ impl GlobalState { } // Hook for thread creation, enabled multi-threaded execution and marks - // the current thread timestamp as happening-before the current thread + // the current thread timestamp as happening-before the current thread. #[inline] pub fn thread_created(&self, thread: ThreadId) { let current_index = self.current_index(); - // Increment the number of active threads + // Increment the number of active threads. let active_threads = self.active_thread_count.get(); self.active_thread_count.set(active_threads + 1); // Enable multi-threaded execution, there are now two threads - // so data-races are now possible. + // so data-races are now possible. self.multi_threaded.set(true); // Load and setup the associated thread metadata @@ -921,101 +1053,105 @@ impl GlobalState { thread_info.ensure_contains_elem(thread, Default::default); // Assign a vector index for the thread, attempting to re-use an old - // vector index that can no longer report any data-races if possible + // vector index that can no longer report any data-races if possible. let created_index = if let Some( reuse_index ) = self.find_vector_index_reuse_candidate() { + // Now re-configure the re-use candidate, increment the clock - // for the new sync use of the vector + // for the new sync use of the vector. let mut vector_clocks = self.vector_clocks.borrow_mut(); vector_clocks[reuse_index].increment_clock(reuse_index); // Locate the old thread the vector was associated with and update - // it to represent the new thread instead + // it to represent the new thread instead. let mut vector_info = self.vector_info.borrow_mut(); let old_thread = vector_info[reuse_index]; vector_info[reuse_index] = thread; // Mark the thread the vector index was associated with as no longer - // representing a thread index + // representing a thread index. thread_info[old_thread].vector_index = None; reuse_index - }else{ + } else { + // No vector re-use candidates available, instead create - // a new vector index + // a new vector index. let mut vector_info = self.vector_info.borrow_mut(); vector_info.push(thread) }; - // Mark the chosen vector index as in use by the thread + // Mark the chosen vector index as in use by the thread. thread_info[thread].vector_index = Some(created_index); - // Create a thread clock set if applicable + // Create a thread clock set if applicable. let mut vector_clocks = self.vector_clocks.borrow_mut(); if created_index == vector_clocks.next_index() { vector_clocks.push(ThreadClockSet::default()); } - // Now load the two clocks and configure the initial state + // Now load the two clocks and configure the initial state. let (current, created) = vector_clocks.pick2_mut(current_index, created_index); - // Advance the current thread before the synchronized operation + // Advance the current thread before the synchronized operation. current.increment_clock(current_index); // Join the created with current, since the current threads - // previous actions happen-before the created thread + // previous actions happen-before the created thread. created.join_with(current); - // Advance both threads after the synchronized operation + // Advance both threads after the synchronized operation. current.increment_clock(current_index); created.increment_clock(created_index); } /// Hook on a thread join to update the implicit happens-before relation - /// between the joined thead and the current thread. + /// between the joined thead and the current thread. #[inline] pub fn thread_joined(&self, current_thread: ThreadId, join_thread: ThreadId) { let mut clocks_vec = self.vector_clocks.borrow_mut(); let thread_info = self.thread_info.borrow(); - // Load the vector clock of the current thread + // Load the vector clock of the current thread. let current_index = thread_info[current_thread].vector_index .expect("Performed thread join on thread with no assigned vector"); let current = &mut clocks_vec[current_index]; - // Load the associated vector clock for the terminated thread + // Load the associated vector clock for the terminated thread. let join_clock = thread_info[join_thread].termination_vector_clock .as_ref().expect("Joined with thread but thread has not terminated"); - // Pre increment clocks before atomic operation + // Pre increment clocks before atomic operation. current.increment_clock(current_index); // The join thread happens-before the current thread - // so update the current vector clock + // so update the current vector clock. current.clock.join(join_clock); - // Post increment clocks after atomic operation + // Post increment clocks after atomic operation. current.increment_clock(current_index); // Check the number of active threads, if the value is 1 - // then test for potentially disabling multi-threaded execution + // then test for potentially disabling multi-threaded execution. let active_threads = self.active_thread_count.get(); if active_threads == 1 { - // May potentially be able to disable multi-threaded execution + + // May potentially be able to disable multi-threaded execution. let current_clock = &clocks_vec[current_index]; if clocks_vec.iter_enumerated().all(|(idx, clocks)| { clocks.clock[idx] <= current_clock.clock[idx] }) { + // The all thread termations happen-before the current clock - // therefore no data-races can be reported until a new thread - // is created, so disable multi-threaded execution + // therefore no data-races can be reported until a new thread + // is created, so disable multi-threaded execution. self.multi_threaded.set(false); } } // If the thread is marked as terminated but not joined - // then move the thread to the re-use set + // then move the thread to the re-use set. let mut termination = self.terminated_threads.borrow_mut(); if let Some(index) = termination.remove(&join_thread) { let mut reuse = self.reuse_candidates.borrow_mut(); @@ -1024,47 +1160,47 @@ impl GlobalState { } /// On thread termination, the vector-clock may re-used - /// in the future once all remaining thread-clocks catch - /// up with the time index of the terminated thread. + /// in the future once all remaining thread-clocks catch + /// up with the time index of the terminated thread. /// This assiges thread termination with a unique index - /// which will be used to join the thread + /// which will be used to join the thread /// This should be called strictly before any calls to - /// `thread_joined` + /// `thread_joined`. #[inline] pub fn thread_terminated(&self) { let current_index = self.current_index(); - // Increment the clock to a unique termination timestamp + // Increment the clock to a unique termination timestamp. let mut vector_clocks = self.vector_clocks.borrow_mut(); let current_clocks = &mut vector_clocks[current_index]; current_clocks.increment_clock(current_index); - // Load the current thread id for the executing vector + // Load the current thread id for the executing vector. let vector_info = self.vector_info.borrow(); let current_thread = vector_info[current_index]; // Load the current thread metadata, and move to a terminated - // vector state. Setting up the vector clock all join operations - // will use. + // vector state. Setting up the vector clock all join operations + // will use. let mut thread_info = self.thread_info.borrow_mut(); let current = &mut thread_info[current_thread]; current.termination_vector_clock = Some(current_clocks.clock.clone()); // Add this thread as a candidate for re-use after a thread join - // occurs + // occurs. let mut termination = self.terminated_threads.borrow_mut(); termination.insert(current_thread, current_index); // Reduce the number of active threads, now that a thread has - // terminated + // terminated. let mut active_threads = self.active_thread_count.get(); active_threads -= 1; self.active_thread_count.set(active_threads); } /// Hook for updating the local tracker of the currently - /// enabled thread, should always be updated whenever - /// `active_thread` in thread.rs is updated + /// enabled thread, should always be updated whenever + /// `active_thread` in thread.rs is updated. #[inline] pub fn thread_set_active(&self, thread: ThreadId) { let thread_info = self.thread_info.borrow(); @@ -1074,9 +1210,9 @@ impl GlobalState { } /// Hook for updating the local tracker of the threads name - /// this should always mirror the local value in thread.rs - /// the thread name is used for improved diagnostics - /// during a data-race + /// this should always mirror the local value in thread.rs + /// the thread name is used for improved diagnostics + /// during a data-race. #[inline] pub fn thread_set_name(&self, thread: ThreadId, name: String) { let name = name.into_boxed_str(); @@ -1086,12 +1222,12 @@ impl GlobalState { /// Attempt to perform a synchronized operation, this - /// will perform no operation if multi-threading is - /// not currently enabled. + /// will perform no operation if multi-threading is + /// not currently enabled. /// Otherwise it will increment the clock for the current - /// vector before and after the operation for data-race - /// detection between any happens-before edges the - /// operation may create + /// vector before and after the operation for data-race + /// detection between any happens-before edges the + /// operation may create. fn maybe_perform_sync_operation<'tcx>( &self, op: impl FnOnce(VectorIdx, RefMut<'_,ThreadClockSet>) -> InterpResult<'tcx>, ) -> InterpResult<'tcx> { @@ -1107,50 +1243,50 @@ impl GlobalState { /// Internal utility to identify a thread stored internally - /// returns the id and the name for better diagnostics + /// returns the id and the name for better diagnostics. fn print_thread_metadata(&self, vector: VectorIdx) -> String { let thread = self.vector_info.borrow()[vector]; let thread_name = &self.thread_info.borrow()[thread].thread_name; if let Some(name) = thread_name { let name: &str = name; format!("Thread(id = {:?}, name = {:?})", thread.to_u32(), &*name) - }else{ + } else { format!("Thread(id = {:?})", thread.to_u32()) } } /// Acquire a lock, express that the previous call of - /// `validate_lock_release` must happen before this - pub fn validate_lock_acquire(&self, lock: &DataRaceLockHandle, thread: ThreadId) { + /// `validate_lock_release` must happen before this. + pub fn validate_lock_acquire(&self, lock: &VClock, thread: ThreadId) { let (index, mut clocks) = self.load_thread_state_mut(thread); clocks.increment_clock(index); - clocks.clock.join(&lock.clock); + clocks.clock.join(&lock); clocks.increment_clock(index); } /// Release a lock handle, express that this happens-before - /// any subsequent calls to `validate_lock_acquire` - pub fn validate_lock_release(&self, lock: &mut DataRaceLockHandle, thread: ThreadId) { + /// any subsequent calls to `validate_lock_acquire`. + pub fn validate_lock_release(&self, lock: &mut VClock, thread: ThreadId) { let (index, mut clocks) = self.load_thread_state_mut(thread); clocks.increment_clock(index); - lock.clock.clone_from(&clocks.clock); + lock.clone_from(&clocks.clock); clocks.increment_clock(index); } /// Release a lock handle, express that this happens-before - /// any subsequent calls to `validate_lock_acquire` as well - /// as any previous calls to this function after any - /// `validate_lock_release` calls - pub fn validate_lock_release_shared(&self, lock: &mut DataRaceLockHandle, thread: ThreadId) { + /// any subsequent calls to `validate_lock_acquire` as well + /// as any previous calls to this function after any + /// `validate_lock_release` calls. + pub fn validate_lock_release_shared(&self, lock: &mut VClock, thread: ThreadId) { let (index, mut clocks) = self.load_thread_state_mut(thread); clocks.increment_clock(index); - lock.clock.join(&clocks.clock); + lock.join(&clocks.clock); clocks.increment_clock(index); } /// Load the vector index used by the given thread as well as the set of vector clocks - /// used by the thread + /// used by the thread. #[inline] fn load_thread_state_mut(&self, thread: ThreadId) -> (VectorIdx, RefMut<'_, ThreadClockSet>) { let index = self.thread_info.borrow()[thread].vector_index @@ -1161,7 +1297,7 @@ impl GlobalState { } /// Load the current vector clock in use and the current set of thread clocks - /// in use for the vector + /// in use for the vector. #[inline] fn current_thread_state(&self) -> (VectorIdx, Ref<'_, ThreadClockSet>) { let index = self.current_index(); @@ -1171,7 +1307,7 @@ impl GlobalState { } /// Load the current vector clock in use and the current set of thread clocks - /// in use for the vector mutably for modification + /// in use for the vector mutably for modification. #[inline] fn current_thread_state_mut(&self) -> (VectorIdx, RefMut<'_, ThreadClockSet>) { let index = self.current_index(); @@ -1181,7 +1317,7 @@ impl GlobalState { } /// Return the current thread, should be the same - /// as the data-race active thread + /// as the data-race active thread. #[inline] fn current_index(&self) -> VectorIdx { self.current_index.get() diff --git a/src/eval.rs b/src/eval.rs index 54d06feec36dd..0a62f14dd3a15 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -48,6 +48,8 @@ pub struct MiriConfig { pub tracked_alloc_id: Option, /// Whether to track raw pointers in stacked borrows. pub track_raw: bool, + /// Determine if data race detection should be enabled + pub data_race_detector: bool, } impl Default for MiriConfig { @@ -65,6 +67,7 @@ impl Default for MiriConfig { tracked_call_id: None, tracked_alloc_id: None, track_raw: false, + data_race_detector: true, } } } diff --git a/src/lib.rs b/src/lib.rs index c8c9e70ec3deb..87effe9c68852 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -55,7 +55,7 @@ pub use crate::shims::tls::{EvalContextExt as _, TlsData}; pub use crate::shims::EvalContextExt as _; pub use crate::data_race::{ - AtomicReadOp, AtomicWriteOp, AtomicRWOp, AtomicFenceOp, DataRaceLockHandle, + AtomicReadOp, AtomicWriteOp, AtomicRwOp, AtomicFenceOp, EvalContextExt as DataRaceEvalContextExt }; pub use crate::diagnostics::{ @@ -81,7 +81,7 @@ pub use crate::sync::{ EvalContextExt as SyncEvalContextExt, CondvarId, MutexId, RwLockId }; pub use crate::vector_clock::{ - VClock, VSmallClockSet, VectorIdx, VTimestamp + VClock, VSmallClockMap, VectorIdx, VTimestamp }; /// Insert rustc arguments at the beginning of the argument list that Miri wants to be diff --git a/src/machine.rs b/src/machine.rs index 363513f636c9e..9612d9e191107 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -109,15 +109,16 @@ impl fmt::Display for MiriMemoryKind { pub struct AllocExtra { /// Stacked Borrows state is only added if it is enabled. pub stacked_borrows: Option, - /// Data race detection via the use of a vector-clock. - pub data_race: data_race::AllocExtra, + /// Data race detection via the use of a vector-clock, + /// this is only added if it is enabled. + pub data_race: Option, } /// Extra global memory data #[derive(Clone, Debug)] pub struct MemoryExtra { pub stacked_borrows: Option, - pub data_race: data_race::MemoryExtra, + pub data_race: Option, pub intptrcast: intptrcast::MemoryExtra, /// Mapping extern static names to their canonical allocation. @@ -147,7 +148,11 @@ impl MemoryExtra { } else { None }; - let data_race = Rc::new(data_race::GlobalState::new()); + let data_race = if config.data_race_detector { + Some(Rc::new(data_race::GlobalState::new())) + }else{ + None + }; MemoryExtra { stacked_borrows, data_race, @@ -472,7 +477,11 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { // No stacks, no tag. (None, Tag::Untagged) }; - let race_alloc = data_race::AllocExtra::new_allocation(&memory_extra.data_race, alloc.size); + let race_alloc = if let Some(data_race) = &memory_extra.data_race { + Some(data_race::AllocExtra::new_allocation(&data_race, alloc.size)) + } else { + None + }; let mut stacked_borrows = memory_extra.stacked_borrows.as_ref().map(|sb| sb.borrow_mut()); let alloc: Allocation = alloc.with_tags_and_extra( |alloc| { @@ -590,7 +599,9 @@ impl AllocationExtra for AllocExtra { ptr: Pointer, size: Size, ) -> InterpResult<'tcx> { - alloc.extra.data_race.read(ptr, size)?; + if let Some(data_race) = &alloc.extra.data_race { + data_race.read(ptr, size)?; + } if let Some(stacked_borrows) = &alloc.extra.stacked_borrows { stacked_borrows.memory_read(ptr, size) } else { @@ -604,7 +615,9 @@ impl AllocationExtra for AllocExtra { ptr: Pointer, size: Size, ) -> InterpResult<'tcx> { - alloc.extra.data_race.write(ptr, size)?; + if let Some(data_race) = &mut alloc.extra.data_race { + data_race.write(ptr, size)?; + } if let Some(stacked_borrows) = &mut alloc.extra.stacked_borrows { stacked_borrows.memory_written(ptr, size) } else { @@ -618,7 +631,9 @@ impl AllocationExtra for AllocExtra { ptr: Pointer, size: Size, ) -> InterpResult<'tcx> { - alloc.extra.data_race.deallocate(ptr, size)?; + if let Some(data_race) = &mut alloc.extra.data_race { + data_race.deallocate(ptr, size)?; + } if let Some(stacked_borrows) = &mut alloc.extra.stacked_borrows { stacked_borrows.memory_deallocated(ptr, size) } else { diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 50f97af8453e6..8f7ae6bebb52e 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -324,98 +324,98 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "atomic_singlethreadfence_acqrel" => this.compiler_fence(args, AtomicFenceOp::AcqRel)?, "atomic_singlethreadfence" => this.compiler_fence(args, AtomicFenceOp::SeqCst)?, - "atomic_xchg" => this.atomic_exchange(args, dest, AtomicRWOp::SeqCst)?, - "atomic_xchg_acq" => this.atomic_exchange(args, dest, AtomicRWOp::Acquire)?, - "atomic_xchg_rel" => this.atomic_exchange(args, dest, AtomicRWOp::Release)?, - "atomic_xchg_acqrel" => this.atomic_exchange(args, dest, AtomicRWOp::AcqRel)?, - "atomic_xchg_relaxed" => this.atomic_exchange(args, dest, AtomicRWOp::Relaxed)?, + "atomic_xchg" => this.atomic_exchange(args, dest, AtomicRwOp::SeqCst)?, + "atomic_xchg_acq" => this.atomic_exchange(args, dest, AtomicRwOp::Acquire)?, + "atomic_xchg_rel" => this.atomic_exchange(args, dest, AtomicRwOp::Release)?, + "atomic_xchg_acqrel" => this.atomic_exchange(args, dest, AtomicRwOp::AcqRel)?, + "atomic_xchg_relaxed" => this.atomic_exchange(args, dest, AtomicRwOp::Relaxed)?, "atomic_cxchg" => this.atomic_compare_exchange( - args, dest, AtomicRWOp::SeqCst, AtomicReadOp::SeqCst + args, dest, AtomicRwOp::SeqCst, AtomicReadOp::SeqCst )?, "atomic_cxchg_acq" => this.atomic_compare_exchange( - args, dest, AtomicRWOp::Acquire, AtomicReadOp::Acquire + args, dest, AtomicRwOp::Acquire, AtomicReadOp::Acquire )?, "atomic_cxchg_rel" => this.atomic_compare_exchange( - args, dest, AtomicRWOp::Release, AtomicReadOp::Relaxed + args, dest, AtomicRwOp::Release, AtomicReadOp::Relaxed )?, "atomic_cxchg_acqrel" => this.atomic_compare_exchange - (args, dest, AtomicRWOp::AcqRel, AtomicReadOp::Acquire + (args, dest, AtomicRwOp::AcqRel, AtomicReadOp::Acquire )?, "atomic_cxchg_relaxed" => this.atomic_compare_exchange( - args, dest, AtomicRWOp::Relaxed, AtomicReadOp::Relaxed + args, dest, AtomicRwOp::Relaxed, AtomicReadOp::Relaxed )?, "atomic_cxchg_acq_failrelaxed" => this.atomic_compare_exchange( - args, dest, AtomicRWOp::Acquire, AtomicReadOp::Relaxed + args, dest, AtomicRwOp::Acquire, AtomicReadOp::Relaxed )?, "atomic_cxchg_acqrel_failrelaxed" => this.atomic_compare_exchange( - args, dest, AtomicRWOp::AcqRel, AtomicReadOp::Relaxed + args, dest, AtomicRwOp::AcqRel, AtomicReadOp::Relaxed )?, "atomic_cxchg_failrelaxed" => this.atomic_compare_exchange( - args, dest, AtomicRWOp::SeqCst, AtomicReadOp::Relaxed + args, dest, AtomicRwOp::SeqCst, AtomicReadOp::Relaxed )?, "atomic_cxchg_failacq" => this.atomic_compare_exchange( - args, dest, AtomicRWOp::SeqCst, AtomicReadOp::Acquire + args, dest, AtomicRwOp::SeqCst, AtomicReadOp::Acquire )?, "atomic_cxchgweak" => this.atomic_compare_exchange_weak( - args, dest, AtomicRWOp::SeqCst, AtomicReadOp::SeqCst + args, dest, AtomicRwOp::SeqCst, AtomicReadOp::SeqCst )?, "atomic_cxchgweak_acq" => this.atomic_compare_exchange_weak( - args, dest, AtomicRWOp::Acquire, AtomicReadOp::Acquire + args, dest, AtomicRwOp::Acquire, AtomicReadOp::Acquire )?, "atomic_cxchgweak_rel" => this.atomic_compare_exchange_weak( - args, dest, AtomicRWOp::Release, AtomicReadOp::Relaxed + args, dest, AtomicRwOp::Release, AtomicReadOp::Relaxed )?, "atomic_cxchgweak_acqrel" => this.atomic_compare_exchange_weak( - args, dest, AtomicRWOp::AcqRel, AtomicReadOp::Acquire + args, dest, AtomicRwOp::AcqRel, AtomicReadOp::Acquire )?, "atomic_cxchgweak_relaxed" => this.atomic_compare_exchange_weak( - args, dest, AtomicRWOp::Relaxed, AtomicReadOp::Relaxed + args, dest, AtomicRwOp::Relaxed, AtomicReadOp::Relaxed )?, "atomic_cxchgweak_acq_failrelaxed" => this.atomic_compare_exchange_weak( - args, dest, AtomicRWOp::Acquire, AtomicReadOp::Relaxed + args, dest, AtomicRwOp::Acquire, AtomicReadOp::Relaxed )?, "atomic_cxchgweak_acqrel_failrelaxed" => this.atomic_compare_exchange_weak( - args, dest, AtomicRWOp::AcqRel, AtomicReadOp::Relaxed + args, dest, AtomicRwOp::AcqRel, AtomicReadOp::Relaxed )?, "atomic_cxchgweak_failrelaxed" => this.atomic_compare_exchange_weak( - args, dest, AtomicRWOp::SeqCst, AtomicReadOp::Relaxed + args, dest, AtomicRwOp::SeqCst, AtomicReadOp::Relaxed )?, "atomic_cxchgweak_failacq" => this.atomic_compare_exchange_weak( - args, dest, AtomicRWOp::SeqCst, AtomicReadOp::Acquire + args, dest, AtomicRwOp::SeqCst, AtomicReadOp::Acquire )?, - "atomic_or" => this.atomic_op(args, dest, BinOp::BitOr, false, AtomicRWOp::SeqCst)?, - "atomic_or_acq" => this.atomic_op(args, dest, BinOp::BitOr, false, AtomicRWOp::Acquire)?, - "atomic_or_rel" => this.atomic_op(args, dest, BinOp::BitOr, false, AtomicRWOp::Release)?, - "atomic_or_acqrel" => this.atomic_op(args, dest, BinOp::BitOr, false, AtomicRWOp::AcqRel)?, - "atomic_or_relaxed" => this.atomic_op(args, dest, BinOp::BitOr, false, AtomicRWOp::Relaxed)?, - "atomic_xor" => this.atomic_op(args, dest, BinOp::BitXor, false, AtomicRWOp::SeqCst)?, - "atomic_xor_acq" => this.atomic_op(args, dest, BinOp::BitXor, false, AtomicRWOp::Acquire)?, - "atomic_xor_rel" => this.atomic_op(args, dest, BinOp::BitXor, false, AtomicRWOp::Release)?, - "atomic_xor_acqrel" => this.atomic_op(args, dest, BinOp::BitXor, false, AtomicRWOp::AcqRel)?, - "atomic_xor_relaxed" => this.atomic_op(args, dest, BinOp::BitXor, false, AtomicRWOp::Relaxed)?, - "atomic_and" => this.atomic_op(args, dest, BinOp::BitAnd, false, AtomicRWOp::SeqCst)?, - "atomic_and_acq" => this.atomic_op(args, dest, BinOp::BitAnd, false, AtomicRWOp::Acquire)?, - "atomic_and_rel" => this.atomic_op(args, dest, BinOp::BitAnd, false, AtomicRWOp::Release)?, - "atomic_and_acqrel" => this.atomic_op(args, dest, BinOp::BitAnd, false, AtomicRWOp::AcqRel)?, - "atomic_and_relaxed" => this.atomic_op(args, dest, BinOp::BitAnd, false, AtomicRWOp::Relaxed)?, - "atomic_nand" => this.atomic_op(args, dest, BinOp::BitAnd, true, AtomicRWOp::SeqCst)?, - "atomic_nand_acq" => this.atomic_op(args, dest, BinOp::BitAnd, true, AtomicRWOp::Acquire)?, - "atomic_nand_rel" => this.atomic_op(args, dest, BinOp::BitAnd, true, AtomicRWOp::Release)?, - "atomic_nand_acqrel" => this.atomic_op(args, dest, BinOp::BitAnd, true, AtomicRWOp::AcqRel)?, - "atomic_nand_relaxed" => this.atomic_op(args, dest, BinOp::BitAnd, true, AtomicRWOp::Relaxed)?, - "atomic_xadd" => this.atomic_op(args, dest, BinOp::Add, false, AtomicRWOp::SeqCst)?, - "atomic_xadd_acq" => this.atomic_op(args, dest, BinOp::Add, false, AtomicRWOp::Acquire)?, - "atomic_xadd_rel" => this.atomic_op(args, dest, BinOp::Add, false, AtomicRWOp::Release)?, - "atomic_xadd_acqrel" => this.atomic_op(args, dest, BinOp::Add, false, AtomicRWOp::AcqRel)?, - "atomic_xadd_relaxed" => this.atomic_op(args, dest, BinOp::Add, false, AtomicRWOp::Relaxed)?, - "atomic_xsub" => this.atomic_op(args, dest, BinOp::Sub, false, AtomicRWOp::SeqCst)?, - "atomic_xsub_acq" => this.atomic_op(args, dest, BinOp::Sub, false, AtomicRWOp::Acquire)?, - "atomic_xsub_rel" => this.atomic_op(args, dest, BinOp::Sub, false, AtomicRWOp::Release)?, - "atomic_xsub_acqrel" => this.atomic_op(args, dest, BinOp::Sub, false, AtomicRWOp::AcqRel)?, - "atomic_xsub_relaxed" => this.atomic_op(args, dest, BinOp::Sub, false, AtomicRWOp::Relaxed)?, + "atomic_or" => this.atomic_op(args, dest, BinOp::BitOr, false, AtomicRwOp::SeqCst)?, + "atomic_or_acq" => this.atomic_op(args, dest, BinOp::BitOr, false, AtomicRwOp::Acquire)?, + "atomic_or_rel" => this.atomic_op(args, dest, BinOp::BitOr, false, AtomicRwOp::Release)?, + "atomic_or_acqrel" => this.atomic_op(args, dest, BinOp::BitOr, false, AtomicRwOp::AcqRel)?, + "atomic_or_relaxed" => this.atomic_op(args, dest, BinOp::BitOr, false, AtomicRwOp::Relaxed)?, + "atomic_xor" => this.atomic_op(args, dest, BinOp::BitXor, false, AtomicRwOp::SeqCst)?, + "atomic_xor_acq" => this.atomic_op(args, dest, BinOp::BitXor, false, AtomicRwOp::Acquire)?, + "atomic_xor_rel" => this.atomic_op(args, dest, BinOp::BitXor, false, AtomicRwOp::Release)?, + "atomic_xor_acqrel" => this.atomic_op(args, dest, BinOp::BitXor, false, AtomicRwOp::AcqRel)?, + "atomic_xor_relaxed" => this.atomic_op(args, dest, BinOp::BitXor, false, AtomicRwOp::Relaxed)?, + "atomic_and" => this.atomic_op(args, dest, BinOp::BitAnd, false, AtomicRwOp::SeqCst)?, + "atomic_and_acq" => this.atomic_op(args, dest, BinOp::BitAnd, false, AtomicRwOp::Acquire)?, + "atomic_and_rel" => this.atomic_op(args, dest, BinOp::BitAnd, false, AtomicRwOp::Release)?, + "atomic_and_acqrel" => this.atomic_op(args, dest, BinOp::BitAnd, false, AtomicRwOp::AcqRel)?, + "atomic_and_relaxed" => this.atomic_op(args, dest, BinOp::BitAnd, false, AtomicRwOp::Relaxed)?, + "atomic_nand" => this.atomic_op(args, dest, BinOp::BitAnd, true, AtomicRwOp::SeqCst)?, + "atomic_nand_acq" => this.atomic_op(args, dest, BinOp::BitAnd, true, AtomicRwOp::Acquire)?, + "atomic_nand_rel" => this.atomic_op(args, dest, BinOp::BitAnd, true, AtomicRwOp::Release)?, + "atomic_nand_acqrel" => this.atomic_op(args, dest, BinOp::BitAnd, true, AtomicRwOp::AcqRel)?, + "atomic_nand_relaxed" => this.atomic_op(args, dest, BinOp::BitAnd, true, AtomicRwOp::Relaxed)?, + "atomic_xadd" => this.atomic_op(args, dest, BinOp::Add, false, AtomicRwOp::SeqCst)?, + "atomic_xadd_acq" => this.atomic_op(args, dest, BinOp::Add, false, AtomicRwOp::Acquire)?, + "atomic_xadd_rel" => this.atomic_op(args, dest, BinOp::Add, false, AtomicRwOp::Release)?, + "atomic_xadd_acqrel" => this.atomic_op(args, dest, BinOp::Add, false, AtomicRwOp::AcqRel)?, + "atomic_xadd_relaxed" => this.atomic_op(args, dest, BinOp::Add, false, AtomicRwOp::Relaxed)?, + "atomic_xsub" => this.atomic_op(args, dest, BinOp::Sub, false, AtomicRwOp::SeqCst)?, + "atomic_xsub_acq" => this.atomic_op(args, dest, BinOp::Sub, false, AtomicRwOp::Acquire)?, + "atomic_xsub_rel" => this.atomic_op(args, dest, BinOp::Sub, false, AtomicRwOp::Release)?, + "atomic_xsub_acqrel" => this.atomic_op(args, dest, BinOp::Sub, false, AtomicRwOp::AcqRel)?, + "atomic_xsub_relaxed" => this.atomic_op(args, dest, BinOp::Sub, false, AtomicRwOp::Relaxed)?, // Query type information @@ -514,7 +514,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn atomic_op( &mut self, args: &[OpTy<'tcx, Tag>], dest: PlaceTy<'tcx, Tag>, - op: mir::BinOp, neg: bool, atomic: AtomicRWOp + op: mir::BinOp, neg: bool, atomic: AtomicRwOp ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); @@ -524,39 +524,26 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx bug!("Atomic arithmetic operations only work on integer types"); } let rhs = this.read_immediate(rhs)?; - let old = this.allow_data_races_mut(|this| { - this.read_immediate(place. into()) - })?; // Check alignment requirements. Atomics must always be aligned to their size, // even if the type they wrap would be less aligned (e.g. AtomicU64 on 32bit must // be 8-aligned). let align = Align::from_bytes(place.layout.size.bytes()).unwrap(); this.memory.check_ptr_access(place.ptr, place.layout.size, align)?; + + let old = this.atomic_op_immediate(place, rhs, op, neg, atomic)?; this.write_immediate(*old, dest)?; // old value is returned - - // Atomics wrap around on overflow. - let val = this.binary_op(op, old, rhs)?; - let val = if neg { this.unary_op(mir::UnOp::Not, val)? } else { val }; - this.allow_data_races_mut(|this| { - this.write_immediate(*val, place.into()) - })?; - - this.validate_atomic_rmw(place, atomic)?; Ok(()) } fn atomic_exchange( - &mut self, args: &[OpTy<'tcx, Tag>], dest: PlaceTy<'tcx, Tag>, atomic: AtomicRWOp + &mut self, args: &[OpTy<'tcx, Tag>], dest: PlaceTy<'tcx, Tag>, atomic: AtomicRwOp ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let &[place, new] = check_arg_count(args)?; let place = this.deref_operand(place)?; let new = this.read_scalar(new)?; - let old = this.allow_data_races_mut(|this| { - this.read_scalar(place.into()) - })?; // Check alignment requirements. Atomics must always be aligned to their size, // even if the type they wrap would be less aligned (e.g. AtomicU64 on 32bit must @@ -564,18 +551,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let align = Align::from_bytes(place.layout.size.bytes()).unwrap(); this.memory.check_ptr_access(place.ptr, place.layout.size, align)?; + let old = this.atomic_exchange_scalar(place, new, atomic)?; this.write_scalar(old, dest)?; // old value is returned - this.allow_data_races_mut(|this| { - this.write_scalar(new, place.into()) - })?; - - this.validate_atomic_rmw(place, atomic)?; Ok(()) } fn atomic_compare_exchange( &mut self, args: &[OpTy<'tcx, Tag>], dest: PlaceTy<'tcx, Tag>, - success: AtomicRWOp, fail: AtomicReadOp + success: AtomicRwOp, fail: AtomicReadOp ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); @@ -584,13 +567,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let expect_old = this.read_immediate(expect_old)?; // read as immediate for the sake of `binary_op()` let new = this.read_scalar(new)?; - // Failure ordering cannot be stronger than success ordering, therefore first attempt - // to read with the failure ordering and if successfull then try again with the success - // read ordering and write in the success case. - // Read as immediate for the sake of `binary_op()` - let old = this.allow_data_races_mut(|this| { - this.read_immediate(place.into()) - })?; // Check alignment requirements. Atomics must always be aligned to their size, // even if the type they wrap would be less aligned (e.g. AtomicU64 on 32bit must @@ -598,31 +574,19 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let align = Align::from_bytes(place.layout.size.bytes()).unwrap(); this.memory.check_ptr_access(place.ptr, place.layout.size, align)?; - // `binary_op` will bail if either of them is not a scalar. - let eq = this.overflowing_binary_op(mir::BinOp::Eq, old, expect_old)?.0; - let res = Immediate::ScalarPair(old.to_scalar_or_uninit(), eq.into()); + + let old = this.atomic_compare_exchange_scalar( + place, expect_old, new, success, fail + )?; // Return old value. - this.write_immediate(res, dest)?; - - // Update ptr depending on comparison. - // if successful, perform a full rw-atomic validation - // otherwise treat this as an atomic load with the fail ordering - if eq.to_bool()? { - this.allow_data_races_mut(|this| { - this.write_scalar(new, place.into()) - })?; - this.validate_atomic_rmw(place, success)?; - } else { - this.validate_atomic_load(place, fail)?; - } - + this.write_immediate(old, dest)?; Ok(()) } fn atomic_compare_exchange_weak( &mut self, args: &[OpTy<'tcx, Tag>], dest: PlaceTy<'tcx, Tag>, - success: AtomicRWOp, fail: AtomicReadOp + success: AtomicRwOp, fail: AtomicReadOp ) -> InterpResult<'tcx> { // FIXME: the weak part of this is currently not modelled, diff --git a/src/shims/posix/linux/sync.rs b/src/shims/posix/linux/sync.rs index 67cea55077376..78244ab7b8794 100644 --- a/src/shims/posix/linux/sync.rs +++ b/src/shims/posix/linux/sync.rs @@ -78,7 +78,17 @@ pub fn futex<'tcx>( // Read an `i32` through the pointer, regardless of any wrapper types. // It's not uncommon for `addr` to be passed as another type than `*mut i32`, such as `*const AtomicI32`. // FIXME: this fails if `addr` is not a pointer type. - // FIXME: what form of atomic operation should the `futex` use to load the value? + // The atomic ordering for futex(https://man7.org/linux/man-pages/man2/futex.2.html): + // "The load of the value of the futex word is an + // atomic memory access (i.e., using atomic machine instructions + // of the respective architecture). This load, the comparison + // with the expected value, and starting to sleep are performed + // atomically and totally ordered with respect to other futex + // operations on the same futex word." + // SeqCst is total order over all operations, so uses acquire, + // either are equal under the current implementation. + // FIXME: is Acquire correct or should some additional ordering constraints be observed? + // FIXME: use RMW or similar? let futex_val = this.read_scalar_at_offset_atomic( addr.into(), 0, this.machine.layouts.i32, AtomicReadOp::Acquire )?.to_i32()?; diff --git a/src/shims/posix/sync.rs b/src/shims/posix/sync.rs index d741ef346e945..64308d06139f3 100644 --- a/src/shims/posix/sync.rs +++ b/src/shims/posix/sync.rs @@ -64,7 +64,7 @@ fn mutex_get_kind<'mir, 'tcx: 'mir>( let offset = if ecx.pointer_size().bytes() == 8 { 16 } else { 12 }; ecx.read_scalar_at_offset_atomic( mutex_op, offset, ecx.machine.layouts.i32, - AtomicReadOp::SeqCst + AtomicReadOp::Acquire ) } @@ -76,7 +76,7 @@ fn mutex_set_kind<'mir, 'tcx: 'mir>( let offset = if ecx.pointer_size().bytes() == 8 { 16 } else { 12 }; ecx.write_scalar_at_offset_atomic( mutex_op, offset, kind, ecx.machine.layouts.i32, - AtomicWriteOp::SeqCst + AtomicWriteOp::Release ) } @@ -85,7 +85,7 @@ fn mutex_get_id<'mir, 'tcx: 'mir>( mutex_op: OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, ScalarMaybeUninit> { ecx.read_scalar_at_offset_atomic( - mutex_op, 4, ecx.machine.layouts.u32, AtomicReadOp::SeqCst + mutex_op, 4, ecx.machine.layouts.u32, AtomicReadOp::Acquire ) } @@ -96,7 +96,7 @@ fn mutex_set_id<'mir, 'tcx: 'mir>( ) -> InterpResult<'tcx, ()> { ecx.write_scalar_at_offset_atomic( mutex_op, 4, id, ecx.machine.layouts.u32, - AtomicWriteOp::SeqCst + AtomicWriteOp::Release ) } @@ -129,7 +129,7 @@ fn rwlock_get_id<'mir, 'tcx: 'mir>( ) -> InterpResult<'tcx, ScalarMaybeUninit> { ecx.read_scalar_at_offset_atomic( rwlock_op, 4, ecx.machine.layouts.u32, - AtomicReadOp::SeqCst + AtomicReadOp::Acquire ) } @@ -140,7 +140,7 @@ fn rwlock_set_id<'mir, 'tcx: 'mir>( ) -> InterpResult<'tcx, ()> { ecx.write_scalar_at_offset_atomic( rwlock_op, 4, id, ecx.machine.layouts.u32, - AtomicWriteOp::SeqCst + AtomicWriteOp::Release ) } @@ -196,7 +196,7 @@ fn cond_get_id<'mir, 'tcx: 'mir>( ) -> InterpResult<'tcx, ScalarMaybeUninit> { ecx.read_scalar_at_offset_atomic( cond_op, 4, ecx.machine.layouts.u32, - AtomicReadOp::SeqCst + AtomicReadOp::Acquire ) } @@ -207,7 +207,7 @@ fn cond_set_id<'mir, 'tcx: 'mir>( ) -> InterpResult<'tcx, ()> { ecx.write_scalar_at_offset_atomic( cond_op, 4, id, ecx.machine.layouts.u32, - AtomicWriteOp::SeqCst + AtomicWriteOp::Release ) } diff --git a/src/shims/posix/thread.rs b/src/shims/posix/thread.rs index e823a7d88d6a9..847d083bfa9f7 100644 --- a/src/shims/posix/thread.rs +++ b/src/shims/posix/thread.rs @@ -15,14 +15,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); this.tcx.sess.warn( - "thread support is experimental.", + "thread support is experimental, no weak memory effects are currently emulated.", ); // Create the new thread let new_thread_id = this.create_thread(); // Write the current thread-id, switch to the next thread later - // to treat this write operation as occuring on this thread index + // to treat this write operation as occuring on the current thread. let thread_info_place = this.deref_operand(thread)?; this.write_scalar( Scalar::from_uint(new_thread_id.to_u32(), thread_info_place.layout.size), @@ -30,15 +30,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx )?; // Read the function argument that will be sent to the new thread - // again perform the read before the thread starts executing. + // before the thread starts executing since reading after the + // context switch will incorrectly report a data-race. let fn_ptr = this.read_scalar(start_routine)?.check_init()?; let func_arg = this.read_immediate(arg)?; - // Also switch to new thread so that we can push the first stackframe. - // after this all accesses will be treated as occuring in the new thread + // Finally switch to new thread so that we can push the first stackframe. + // After this all accesses will be treated as occuring in the new thread. let old_thread_id = this.set_active_thread(new_thread_id); - // Perform the function pointer load in the new thread frame + // Perform the function pointer load in the new thread frame. let instance = this.memory.get_fn(fn_ptr)?.as_instance()?; // Note: the returned value is currently ignored (see the FIXME in @@ -54,7 +55,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx StackPopCleanup::None { cleanup: true }, )?; - // Restore the old active thread frame + // Restore the old active thread frame. this.set_active_thread(old_thread_id); Ok(0) diff --git a/src/sync.rs b/src/sync.rs index 3469afdcd276e..828268c06ccf0 100644 --- a/src/sync.rs +++ b/src/sync.rs @@ -62,7 +62,7 @@ struct Mutex { /// The queue of threads waiting for this mutex. queue: VecDeque, /// Data race handle - data_race: DataRaceLockHandle + data_race: VClock } declare_id!(RwLockId); @@ -80,9 +80,9 @@ struct RwLock { /// The queue of reader threads waiting for this lock. reader_queue: VecDeque, /// Data race handle for writers - data_race: DataRaceLockHandle, + data_race: VClock, /// Data race handle for readers - data_race_reader: DataRaceLockHandle, + data_race_reader: VClock, } declare_id!(CondvarId); @@ -100,14 +100,14 @@ struct CondvarWaiter { #[derive(Default, Debug)] struct Condvar { waiters: VecDeque, - data_race: DataRaceLockHandle, + data_race: VClock, } /// The futex state. #[derive(Default, Debug)] struct Futex { waiters: VecDeque, - data_race: DataRaceLockHandle, + data_race: VClock, } /// A thread waiting on a futex. @@ -213,7 +213,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx mutex.owner = Some(thread); } mutex.lock_count = mutex.lock_count.checked_add(1).unwrap(); - this.memory.extra.data_race.validate_lock_acquire(&mutex.data_race, thread); + if let Some(data_race) = &this.memory.extra.data_race { + data_race.validate_lock_acquire(&mutex.data_race, thread); + } } /// Try unlocking by decreasing the lock count and returning the old lock @@ -241,7 +243,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx mutex.owner = None; // The mutex is completely unlocked. Try transfering ownership // to another thread. - this.memory.extra.data_race.validate_lock_release(&mut mutex.data_race, current_owner); + if let Some(data_race) = &this.memory.extra.data_race { + data_race.validate_lock_release(&mut mutex.data_race, current_owner); + } this.mutex_dequeue_and_lock(id); } Some(old_lock_count) @@ -297,7 +301,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let rwlock = &mut this.machine.threads.sync.rwlocks[id]; let count = rwlock.readers.entry(reader).or_insert(0); *count = count.checked_add(1).expect("the reader counter overflowed"); - this.memory.extra.data_race.validate_lock_acquire(&rwlock.data_race, reader); + if let Some(data_race) = &this.memory.extra.data_race { + data_race.validate_lock_acquire(&rwlock.data_race, reader); + } } /// Try read-unlock the lock for `reader` and potentially give the lock to a new owner. @@ -319,7 +325,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } Entry::Vacant(_) => return false, // we did not even own this lock } - this.memory.extra.data_race.validate_lock_release_shared(&mut rwlock.data_race_reader, reader); + if let Some(data_race) = &this.memory.extra.data_race { + data_race.validate_lock_release_shared(&mut rwlock.data_race_reader, reader); + } // The thread was a reader. If the lock is not held any more, give it to a writer. if this.rwlock_is_locked(id).not() { @@ -328,7 +336,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // of the union of all reader data race handles, since the set of readers // happen-before the writers let rwlock = &mut this.machine.threads.sync.rwlocks[id]; - rwlock.data_race.set_values(&rwlock.data_race_reader); + rwlock.data_race.clone_from(&rwlock.data_race_reader); this.rwlock_dequeue_and_lock_writer(id); } true @@ -355,7 +363,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx trace!("rwlock_writer_lock: {:?} now held by {:?}", id, writer); let rwlock = &mut this.machine.threads.sync.rwlocks[id]; rwlock.writer = Some(writer); - this.memory.extra.data_race.validate_lock_acquire(&rwlock.data_race, writer); + if let Some(data_race) = &this.memory.extra.data_race { + data_race.validate_lock_acquire(&rwlock.data_race, writer); + } } #[inline] @@ -373,8 +383,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Release memory to both reader and writer vector clocks // since this writer happens-before both the union of readers once they are finished // and the next writer - this.memory.extra.data_race.validate_lock_release(&mut rwlock.data_race, current_writer); - this.memory.extra.data_race.validate_lock_release(&mut rwlock.data_race_reader, current_writer); + if let Some(data_race) = &this.memory.extra.data_race { + data_race.validate_lock_release(&mut rwlock.data_race, current_writer); + data_race.validate_lock_release(&mut rwlock.data_race_reader, current_writer); + } // The thread was a writer. // // We are prioritizing writers here against the readers. As a @@ -435,14 +447,18 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); let current_thread = this.get_active_thread(); let condvar = &mut this.machine.threads.sync.condvars[id]; - let data_race = &mut this.memory.extra.data_race; + let data_race = &this.memory.extra.data_race; // Each condvar signal happens-before the end of the condvar wake - data_race.validate_lock_release(&mut condvar.data_race, current_thread); + if let Some(data_race) = data_race { + data_race.validate_lock_release(&mut condvar.data_race, current_thread); + } condvar.waiters .pop_front() .map(|waiter| { - data_race.validate_lock_acquire(&mut condvar.data_race, waiter.thread); + if let Some(data_race) = data_race { + data_race.validate_lock_acquire(&mut condvar.data_race, waiter.thread); + } (waiter.thread, waiter.mutex) }) } @@ -466,12 +482,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); let current_thread = this.get_active_thread(); let futex = &mut this.machine.threads.sync.futexes.get_mut(&addr.erase_tag())?; - let data_race = &mut this.memory.extra.data_race; + let data_race = &this.memory.extra.data_race; // Each futex-wake happens-before the end of the futex wait - data_race.validate_lock_release(&mut futex.data_race, current_thread); + if let Some(data_race) = data_race { + data_race.validate_lock_release(&mut futex.data_race, current_thread); + } let res = futex.waiters.pop_front().map(|waiter| { - data_race.validate_lock_acquire(&futex.data_race, waiter.thread); + if let Some(data_race) = data_race { + data_race.validate_lock_acquire(&futex.data_race, waiter.thread); + } waiter.thread }); res diff --git a/src/thread.rs b/src/thread.rs index 40cfd04d7923e..5d783430417be 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -3,6 +3,7 @@ use std::cell::RefCell; use std::collections::hash_map::Entry; use std::convert::TryFrom; +use std::rc::Rc; use std::num::TryFromIntError; use std::time::{Duration, Instant, SystemTime}; @@ -327,7 +328,7 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { } /// Mark that the active thread tries to join the thread with `joined_thread_id`. - fn join_thread(&mut self, joined_thread_id: ThreadId, data_race: &data_race::GlobalState) -> InterpResult<'tcx> { + fn join_thread(&mut self, joined_thread_id: ThreadId, data_race: &Option>) -> InterpResult<'tcx> { if self.threads[joined_thread_id].join_status != ThreadJoinStatus::Joinable { throw_ub_format!("trying to join a detached or already joined thread"); } @@ -351,9 +352,11 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { self.active_thread, joined_thread_id ); - }else{ + } else { // The thread has already terminated - mark join happens-before - data_race.thread_joined(self.active_thread, joined_thread_id); + if let Some(data_race) = data_race { + data_race.thread_joined(self.active_thread, joined_thread_id); + } } Ok(()) } @@ -428,7 +431,7 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { /// Wakes up threads joining on the active one and deallocates thread-local statics. /// The `AllocId` that can now be freed is returned. - fn thread_terminated(&mut self, data_race: &data_race::GlobalState) -> Vec { + fn thread_terminated(&mut self, data_race: &Option>) -> Vec { let mut free_tls_statics = Vec::new(); { let mut thread_local_statics = self.thread_local_alloc_ids.borrow_mut(); @@ -444,12 +447,16 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { }); } // Set the thread into a terminated state in the data-race detector - data_race.thread_terminated(); + if let Some(data_race) = data_race { + data_race.thread_terminated(); + } // Check if we need to unblock any threads. for (i, thread) in self.threads.iter_enumerated_mut() { if thread.state == ThreadState::BlockedOnJoin(self.active_thread) { // The thread has terminated, mark happens-before edge to joining thread - data_race.thread_joined(i, self.active_thread); + if let Some(data_race) = data_race { + data_race.thread_joined(i, self.active_thread); + } trace!("unblocking {:?} because {:?} terminated", i, self.active_thread); thread.state = ThreadState::Enabled; } @@ -463,7 +470,7 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { /// used in stateless model checkers such as Loom: run the active thread as /// long as we can and switch only when we have to (the active thread was /// blocked, terminated, or has explicitly asked to be preempted). - fn schedule(&mut self, data_race: &data_race::GlobalState) -> InterpResult<'tcx, SchedulingAction> { + fn schedule(&mut self, data_race: &Option>) -> InterpResult<'tcx, SchedulingAction> { // Check whether the thread has **just** terminated (`check_terminated` // checks whether the thread has popped all its stack and if yes, sets // the thread state to terminated). @@ -508,7 +515,9 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { if thread.state == ThreadState::Enabled { if !self.yield_active_thread || id != self.active_thread { self.active_thread = id; - data_race.thread_set_active(self.active_thread); + if let Some(data_race) = data_race { + data_race.thread_set_active(self.active_thread); + } break; } } @@ -563,7 +572,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn create_thread(&mut self) -> ThreadId { let this = self.eval_context_mut(); let id = this.machine.threads.create_thread(); - this.memory.extra.data_race.thread_created(id); + if let Some(data_race) = &this.memory.extra.data_race { + data_race.thread_created(id); + } id } @@ -576,7 +587,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx #[inline] fn join_thread(&mut self, joined_thread_id: ThreadId) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - let data_race = &*this.memory.extra.data_race; + let data_race = &this.memory.extra.data_race; this.machine.threads.join_thread(joined_thread_id, data_race)?; Ok(()) } @@ -584,7 +595,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx #[inline] fn set_active_thread(&mut self, thread_id: ThreadId) -> ThreadId { let this = self.eval_context_mut(); - this.memory.extra.data_race.thread_set_active(thread_id); + if let Some(data_race) = &this.memory.extra.data_race { + data_race.thread_set_active(thread_id); + } this.machine.threads.set_active_thread_id(thread_id) } @@ -639,10 +652,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx #[inline] fn set_active_thread_name(&mut self, new_thread_name: Vec) { let this = self.eval_context_mut(); - if let Ok(string) = String::from_utf8(new_thread_name.clone()) { - this.memory.extra.data_race.thread_set_name( - this.machine.threads.active_thread, string - ); + if let Some(data_race) = &this.memory.extra.data_race { + if let Ok(string) = String::from_utf8(new_thread_name.clone()) { + data_race.thread_set_name( + this.machine.threads.active_thread, string + ); + } } this.machine.threads.set_thread_name(new_thread_name); } @@ -713,7 +728,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx #[inline] fn schedule(&mut self) -> InterpResult<'tcx, SchedulingAction> { let this = self.eval_context_mut(); - let data_race = &*this.memory.extra.data_race; + let data_race = &this.memory.extra.data_race; this.machine.threads.schedule(data_race) } @@ -724,7 +739,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx #[inline] fn thread_terminated(&mut self) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - let data_race = &*this.memory.extra.data_race; + let data_race = &this.memory.extra.data_race; for alloc_id in this.machine.threads.thread_terminated(data_race) { let ptr = this.memory.global_base_pointer(alloc_id.into())?; this.memory.deallocate(ptr, None, MiriMemoryKind::Tls.into())?; diff --git a/src/vector_clock.rs b/src/vector_clock.rs index 8d05eb1b992bb..110b278852d50 100644 --- a/src/vector_clock.rs +++ b/src/vector_clock.rs @@ -1,121 +1,132 @@ use std::{ fmt::{self, Debug}, cmp::Ordering, ops::Index, - num::TryFromIntError, convert::TryFrom, mem + convert::TryFrom, mem }; use smallvec::SmallVec; use rustc_index::vec::Idx; use rustc_data_structures::fx::FxHashMap; /// A vector clock index, this is associated with a thread id -/// but in some cases one vector index may be shared with -/// multiple thread ids. +/// but in some cases one vector index may be shared with +/// multiple thread ids id it safe to do so. #[derive(Clone, Copy, Debug, PartialOrd, Ord, PartialEq, Eq, Hash)] pub struct VectorIdx(u32); -impl VectorIdx{ +impl VectorIdx { + + #[inline(always)] pub fn to_u32(self) -> u32 { self.0 } + pub const MAX_INDEX: VectorIdx = VectorIdx(u32::MAX); + } impl Idx for VectorIdx { + + #[inline] fn new(idx: usize) -> Self { VectorIdx(u32::try_from(idx).unwrap()) } + #[inline] fn index(self) -> usize { usize::try_from(self.0).unwrap() } -} -impl TryFrom for VectorIdx { - type Error = TryFromIntError; - fn try_from(id: u64) -> Result { - u32::try_from(id).map(|id_u32| Self(id_u32)) - } } impl From for VectorIdx { + + #[inline] fn from(id: u32) -> Self { Self(id) } -} +} -/// A sparse set of vector clocks, where each vector index -/// is associated with a vector clock. -/// This treats all vector clocks that have not been assigned -/// as equal to the all zero vector clocks -/// Is optimized for the common case where only 1 element is stored -/// in the set and the rest can be ignored, falling-back to -/// using an internal hash-map once more than 1 element is assigned -/// at any one time +/// A sparse mapping of vector index values to vector clocks, this +/// is optimized for the common case with only one element stored +/// inside the map. +/// This is used to store the set of currently active release +/// sequences at a given memory location, since RMW operations +/// allow for multiple release sequences to be active at once +/// and to be collapsed back to one active release sequence +/// once a non RMW atomic store operation occurs. +/// An all zero vector is considered to be equal to no +/// element stored internally since it will never be +/// stored and has no meaning as a release sequence +/// vector clock. #[derive(Clone)] -pub struct VSmallClockSet(VSmallClockSetInner); +pub struct VSmallClockMap(VSmallClockMapInner); #[derive(Clone)] -enum VSmallClockSetInner { +enum VSmallClockMapInner { + /// Zero or 1 vector elements, common - /// case for the sparse set. + /// case for the sparse set. /// The all zero vector clock is treated - /// as equal to the empty element + /// as equal to the empty element. Small(VectorIdx, VClock), - /// Hash-map of vector clocks + /// Hash-map of vector clocks. Large(FxHashMap) } -impl VSmallClockSet { +impl VSmallClockMap { /// Remove all clock vectors from the map, setting them - /// to the zero vector + /// to the zero vector. pub fn clear(&mut self) { match &mut self.0 { - VSmallClockSetInner::Small(_, clock) => { + VSmallClockMapInner::Small(_, clock) => { clock.set_zero_vector() } - VSmallClockSetInner::Large(hash_map) => { + VSmallClockMapInner::Large(hash_map) => { hash_map.clear(); } } } /// Remove all clock vectors except for the clock vector - /// stored at the given index, which is retained + /// stored at the given index, which is retained. pub fn retain_index(&mut self, index: VectorIdx) { match &mut self.0 { - VSmallClockSetInner::Small(small_idx, clock) => { + VSmallClockMapInner::Small(small_idx, clock) => { if index != *small_idx { + // The zero-vector is considered to equal - // the empty element + // the empty element. clock.set_zero_vector() } }, - VSmallClockSetInner::Large(hash_map) => { - hash_map.retain(|idx,_| { - *idx == index - }); + VSmallClockMapInner::Large(hash_map) => { + let value = hash_map.remove(&index).unwrap_or_default(); + self.0 = VSmallClockMapInner::Small(index, value); } } } /// Insert the vector clock into the associated vector - /// index + /// index. pub fn insert(&mut self, index: VectorIdx, clock: &VClock) { match &mut self.0 { - VSmallClockSetInner::Small(small_idx, small_clock) => { + VSmallClockMapInner::Small(small_idx, small_clock) => { if small_clock.is_zero_vector() { + *small_idx = index; small_clock.clone_from(clock); - }else if !clock.is_zero_vector() { + } else if !clock.is_zero_vector() { + + // Convert to using the hash-map representation. let mut hash_map = FxHashMap::default(); hash_map.insert(*small_idx, mem::take(small_clock)); hash_map.insert(index, clock.clone()); - self.0 = VSmallClockSetInner::Large(hash_map); + self.0 = VSmallClockMapInner::Large(hash_map); } }, - VSmallClockSetInner::Large(hash_map) => { + VSmallClockMapInner::Large(hash_map) => { if !clock.is_zero_vector() { hash_map.insert(index, clock.clone()); } @@ -127,41 +138,44 @@ impl VSmallClockSet { /// vector index. pub fn get(&self, index: VectorIdx) -> Option<&VClock> { match &self.0 { - VSmallClockSetInner::Small(small_idx, small_clock) => { + VSmallClockMapInner::Small(small_idx, small_clock) => { if *small_idx == index && !small_clock.is_zero_vector() { Some(small_clock) - }else{ + } else { None } }, - VSmallClockSetInner::Large(hash_map) => { + VSmallClockMapInner::Large(hash_map) => { hash_map.get(&index) } } } } -impl Default for VSmallClockSet { +impl Default for VSmallClockMap { + #[inline] fn default() -> Self { - VSmallClockSet( - VSmallClockSetInner::Small(VectorIdx::new(0), VClock::default()) + VSmallClockMap( + VSmallClockMapInner::Small(VectorIdx::new(0), VClock::default()) ) } + } -impl Debug for VSmallClockSet { +impl Debug for VSmallClockMap { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { // Print the contents of the small vector clock set as the map - // of vector index to vector clock that they represent + // of vector index to vector clock that they represent. let mut map = f.debug_map(); match &self.0 { - VSmallClockSetInner::Small(small_idx, small_clock) => { + VSmallClockMapInner::Small(small_idx, small_clock) => { if !small_clock.is_zero_vector() { map.entry(&small_idx, &small_clock); } }, - VSmallClockSetInner::Large(hash_map) => { + VSmallClockMapInner::Large(hash_map) => { for (idx, elem) in hash_map.iter() { map.entry(idx, elem); } @@ -169,30 +183,35 @@ impl Debug for VSmallClockSet { } map.finish() } + } -impl PartialEq for VSmallClockSet { + + +impl PartialEq for VSmallClockMap { + fn eq(&self, other: &Self) -> bool { - use VSmallClockSetInner::*; + use VSmallClockMapInner::*; match (&self.0, &other.0) { (Small(i1, c1), Small(i2, c2)) => { if c1.is_zero_vector() { // Either they are both zero or they are non-equal c2.is_zero_vector() - }else{ + } else { // At least one is non-zero, so the full comparison is correct i1 == i2 && c1 == c2 } } - (VSmallClockSetInner::Small(idx, clock), VSmallClockSetInner::Large(hash_map)) | - (VSmallClockSetInner::Large(hash_map), VSmallClockSetInner::Small(idx, clock)) => { + (Small(idx, clock), Large(hash_map)) | + (Large(hash_map), Small(idx, clock)) => { + if hash_map.len() == 0 { // Equal to the empty hash-map clock.is_zero_vector() - }else if hash_map.len() == 1 { + } else if hash_map.len() == 1 { // Equal to the hash-map with one element let (hash_idx, hash_clock) = hash_map.iter().next().unwrap(); hash_idx == idx && hash_clock == clock - }else{ + } else { false } } @@ -201,32 +220,38 @@ impl PartialEq for VSmallClockSet { } } } + } -impl Eq for VSmallClockSet {} + +impl Eq for VSmallClockMap {} /// The size of the vector-clock to store inline -/// clock vectors larger than this will be stored on the heap +/// clock vectors larger than this will be stored on the heap const SMALL_VECTOR: usize = 4; /// The type of the time-stamps recorded in the data-race detector -/// set to a type of unsigned integer +/// set to a type of unsigned integer pub type VTimestamp = u32; -/// A vector clock for detecting data-races -/// invariants: -/// - the last element in a VClock must not be 0 -/// -- this means that derive(PartialEq & Eq) is correct -/// -- as there is no implicit zero tail that might be equal -/// -- also simplifies the implementation of PartialOrd +/// A vector clock for detecting data-races, this is conceptually +/// a map from a vector index (and thus a thread id) to a timestamp. +/// The compare operations require that the invariant that the last +/// element in the internal timestamp slice must not be a 0, hence +/// all zero vector clocks are always represented by the empty slice; +/// and allows for the implementation of compare operations to short +/// circuit the calculation and return the correct result faster, +/// also this means that there is only one unique valid length +/// for each set of vector clock values and hence the PartialEq +// and Eq derivations are correct. #[derive(PartialEq, Eq, Default, Debug)] pub struct VClock(SmallVec<[VTimestamp; SMALL_VECTOR]>); impl VClock { /// Create a new vector-clock containing all zeros except - /// for a value at the given index + /// for a value at the given index pub fn new_with_index(index: VectorIdx, timestamp: VTimestamp) -> VClock { let len = index.index() + 1; let mut vec = smallvec::smallvec![0; len]; @@ -241,8 +266,8 @@ impl VClock { } /// Get a mutable slice to the internal vector with minimum `min_len` - /// elements, to preserve invariants this vector must modify - /// the `min_len`-1 nth element to a non-zero value + /// elements, to preserve invariants this vector must modify + /// the `min_len`-1 nth element to a non-zero value #[inline] fn get_mut_with_min_len(&mut self, min_len: usize) -> &mut [VTimestamp] { if self.0.len() < min_len { @@ -253,7 +278,7 @@ impl VClock { } /// Increment the vector clock at a known index - /// this will panic if the vector index overflows + /// this will panic if the vector index overflows #[inline] pub fn increment_index(&mut self, idx: VectorIdx) { let idx = idx.index(); @@ -263,8 +288,8 @@ impl VClock { } // Join the two vector-clocks together, this - // sets each vector-element to the maximum value - // of that element in either of the two source elements. + // sets each vector-element to the maximum value + // of that element in either of the two source elements. pub fn join(&mut self, other: &Self) { let rhs_slice = other.as_slice(); let lhs_slice = self.get_mut_with_min_len(rhs_slice.len()); @@ -291,30 +316,43 @@ impl VClock { pub fn is_zero_vector(&self) -> bool { self.0.is_empty() } + } impl Clone for VClock { + fn clone(&self) -> Self { VClock(self.0.clone()) } + + // Optimized clone-from, can be removed + // and replaced with a derive once a similar + // optimization is inserted into SmallVec's + // clone implementation. fn clone_from(&mut self, source: &Self) { let source_slice = source.as_slice(); self.0.clear(); self.0.extend_from_slice(source_slice); } + } impl PartialOrd for VClock { + fn partial_cmp(&self, other: &VClock) -> Option { // Load the values as slices let lhs_slice = self.as_slice(); let rhs_slice = other.as_slice(); - // Iterate through the combined vector slice - // keeping track of the order that is currently possible to satisfy. - // If an ordering relation is detected to be impossible, then bail and - // directly return None + // Iterate through the combined vector slice continuously updating + // the value of `order` to the current comparison of the vector from + // index 0 to the currently checked index. + // An Equal ordering can be converted into Less or Greater ordering + // on finding an element that is less than or greater than the other + // but if one Greater and one Less element-wise comparison is found + // then no ordering is possible and so directly return an ordering + // of None. let mut iter = lhs_slice.iter().zip(rhs_slice.iter()); let mut order = match iter.next() { Some((lhs, rhs)) => lhs.cmp(rhs), @@ -332,23 +370,23 @@ impl PartialOrd for VClock { } } - //Now test if either left or right have trailing elements + // Now test if either left or right have trailing elements, // by the invariant the trailing elements have at least 1 // non zero value, so no additional calculation is required - // to determine the result of the PartialOrder + // to determine the result of the PartialOrder. let l_len = lhs_slice.len(); let r_len = rhs_slice.len(); match l_len.cmp(&r_len) { - // Equal has no additional elements: return current order + // Equal means no additional elements: return current order Ordering::Equal => Some(order), // Right has at least 1 element > than the implicit 0, - // so the only valid values are Ordering::Less or None + // so the only valid values are Ordering::Less or None. Ordering::Less => match order { Ordering::Less | Ordering::Equal => Some(Ordering::Less), Ordering::Greater => None } // Left has at least 1 element > than the implicit 0, - // so the only valid values are Ordering::Greater or None + // so the only valid values are Ordering::Greater or None. Ordering::Greater => match order { Ordering::Greater | Ordering::Equal => Some(Ordering::Greater), Ordering::Less => None @@ -362,28 +400,28 @@ impl PartialOrd for VClock { let rhs_slice = other.as_slice(); // If l_len > r_len then at least one element - // in l_len is > than r_len, therefore the result - // is either Some(Greater) or None, so return false - // early. + // in l_len is > than r_len, therefore the result + // is either Some(Greater) or None, so return false + // early. let l_len = lhs_slice.len(); let r_len = rhs_slice.len(); if l_len <= r_len { // If any elements on the left are greater than the right - // then the result is None or Some(Greater), both of which - // return false, the earlier test asserts that no elements in the - // extended tail violate this assumption. Otherwise l <= r, finally - // the case where the values are potentially equal needs to be considered - // and false returned as well + // then the result is None or Some(Greater), both of which + // return false, the earlier test asserts that no elements in the + // extended tail violate this assumption. Otherwise l <= r, finally + // the case where the values are potentially equal needs to be considered + // and false returned as well let mut equal = l_len == r_len; for (&l, &r) in lhs_slice.iter().zip(rhs_slice.iter()) { if l > r { return false - }else if l < r { + } else if l < r { equal = false; } } !equal - }else{ + } else { false } } @@ -394,18 +432,18 @@ impl PartialOrd for VClock { let rhs_slice = other.as_slice(); // If l_len > r_len then at least one element - // in l_len is > than r_len, therefore the result - // is either Some(Greater) or None, so return false - // early. + // in l_len is > than r_len, therefore the result + // is either Some(Greater) or None, so return false + // early. let l_len = lhs_slice.len(); let r_len = rhs_slice.len(); if l_len <= r_len { // If any elements on the left are greater than the right - // then the result is None or Some(Greater), both of which - // return false, the earlier test asserts that no elements in the - // extended tail violate this assumption. Otherwise l <= r + // then the result is None or Some(Greater), both of which + // return false, the earlier test asserts that no elements in the + // extended tail violate this assumption. Otherwise l <= r !lhs_slice.iter().zip(rhs_slice.iter()).any(|(&l, &r)| l > r) - }else{ + } else { false } } @@ -416,28 +454,28 @@ impl PartialOrd for VClock { let rhs_slice = other.as_slice(); // If r_len > l_len then at least one element - // in r_len is > than l_len, therefore the result - // is either Some(Less) or None, so return false - // early. + // in r_len is > than l_len, therefore the result + // is either Some(Less) or None, so return false + // early. let l_len = lhs_slice.len(); let r_len = rhs_slice.len(); if l_len >= r_len { // If any elements on the left are less than the right - // then the result is None or Some(Less), both of which - // return false, the earlier test asserts that no elements in the - // extended tail violate this assumption. Otherwise l >=, finally - // the case where the values are potentially equal needs to be considered - // and false returned as well + // then the result is None or Some(Less), both of which + // return false, the earlier test asserts that no elements in the + // extended tail violate this assumption. Otherwise l >=, finally + // the case where the values are potentially equal needs to be considered + // and false returned as well let mut equal = l_len == r_len; for (&l, &r) in lhs_slice.iter().zip(rhs_slice.iter()) { if l < r { return false - }else if l > r { + } else if l > r { equal = false; } } !equal - }else{ + } else { false } } @@ -448,30 +486,33 @@ impl PartialOrd for VClock { let rhs_slice = other.as_slice(); // If r_len > l_len then at least one element - // in r_len is > than l_len, therefore the result - // is either Some(Less) or None, so return false - // early. + // in r_len is > than l_len, therefore the result + // is either Some(Less) or None, so return false + // early. let l_len = lhs_slice.len(); let r_len = rhs_slice.len(); if l_len >= r_len { // If any elements on the left are less than the right - // then the result is None or Some(Less), both of which - // return false, the earlier test asserts that no elements in the - // extended tail violate this assumption. Otherwise l >= r + // then the result is None or Some(Less), both of which + // return false, the earlier test asserts that no elements in the + // extended tail violate this assumption. Otherwise l >= r !lhs_slice.iter().zip(rhs_slice.iter()).any(|(&l, &r)| l < r) - }else{ + } else { false } } + } impl Index for VClock { + type Output = VTimestamp; #[inline] fn index(&self, index: VectorIdx) -> &VTimestamp { self.as_slice().get(index.to_u32() as usize).unwrap_or(&0) } + } @@ -480,7 +521,8 @@ impl Index for VClock { /// test suite #[cfg(test)] mod tests { - use super::{VClock, VTimestamp, VectorIdx, VSmallClockSet}; + + use super::{VClock, VTimestamp, VectorIdx, VSmallClockMap}; use std::cmp::Ordering; #[test] @@ -536,7 +578,7 @@ mod tests { let alt_compare = r.partial_cmp(&l); assert_eq!(alt_compare, o.map(Ordering::reverse), "Invalid alt comparison\n l: {:?}\n r: {:?}",l,r); - //Test operatorsm with faster implementations + //Test operators with faster implementations assert_eq!( matches!(compare,Some(Ordering::Less)), l < r, "Invalid (<):\n l: {:?}\n r: {:?}",l,r @@ -573,30 +615,31 @@ mod tests { #[test] pub fn test_vclock_set() { - let mut set = VSmallClockSet::default(); + let mut map = VSmallClockMap::default(); let v1 = from_slice(&[3,0,1]); let v2 = from_slice(&[4,2,3]); let v3 = from_slice(&[4,8,3]); - set.insert(VectorIdx(0), &v1); - assert_eq!(set.get(VectorIdx(0)), Some(&v1)); - set.insert(VectorIdx(5), &v2); - assert_eq!(set.get(VectorIdx(0)), Some(&v1)); - assert_eq!(set.get(VectorIdx(5)), Some(&v2)); - set.insert(VectorIdx(53), &v3); - assert_eq!(set.get(VectorIdx(0)), Some(&v1)); - assert_eq!(set.get(VectorIdx(5)), Some(&v2)); - assert_eq!(set.get(VectorIdx(53)), Some(&v3)); - set.retain_index(VectorIdx(53)); - assert_eq!(set.get(VectorIdx(0)), None); - assert_eq!(set.get(VectorIdx(5)), None); - assert_eq!(set.get(VectorIdx(53)), Some(&v3)); - set.clear(); - assert_eq!(set.get(VectorIdx(0)), None); - assert_eq!(set.get(VectorIdx(5)), None); - assert_eq!(set.get(VectorIdx(53)), None); - set.insert(VectorIdx(53), &v3); - assert_eq!(set.get(VectorIdx(0)), None); - assert_eq!(set.get(VectorIdx(5)), None); - assert_eq!(set.get(VectorIdx(53)), Some(&v3)); - } + map.insert(VectorIdx(0), &v1); + assert_eq!(map.get(VectorIdx(0)), Some(&v1)); + map.insert(VectorIdx(5), &v2); + assert_eq!(map.get(VectorIdx(0)), Some(&v1)); + assert_eq!(map.get(VectorIdx(5)), Some(&v2)); + map.insert(VectorIdx(53), &v3); + assert_eq!(map.get(VectorIdx(0)), Some(&v1)); + assert_eq!(map.get(VectorIdx(5)), Some(&v2)); + assert_eq!(map.get(VectorIdx(53)), Some(&v3)); + map.retain_index(VectorIdx(53)); + assert_eq!(map.get(VectorIdx(0)), None); + assert_eq!(map.get(VectorIdx(5)), None); + assert_eq!(map.get(VectorIdx(53)), Some(&v3)); + map.clear(); + assert_eq!(map.get(VectorIdx(0)), None); + assert_eq!(map.get(VectorIdx(5)), None); + assert_eq!(map.get(VectorIdx(53)), None); + map.insert(VectorIdx(53), &v3); + assert_eq!(map.get(VectorIdx(0)), None); + assert_eq!(map.get(VectorIdx(5)), None); + assert_eq!(map.get(VectorIdx(53)), Some(&v3)); + } + } diff --git a/tests/run-pass/concurrency/data_race.stderr b/tests/run-pass/concurrency/data_race.stderr index b01247aea4e0e..7ba8087a9b4bc 100644 --- a/tests/run-pass/concurrency/data_race.stderr +++ b/tests/run-pass/concurrency/data_race.stderr @@ -1,2 +1,2 @@ -warning: thread support is experimental. +warning: thread support is experimental, no weak memory effects are currently emulated. diff --git a/tests/run-pass/concurrency/linux-futex.stderr b/tests/run-pass/concurrency/linux-futex.stderr index b01247aea4e0e..7ba8087a9b4bc 100644 --- a/tests/run-pass/concurrency/linux-futex.stderr +++ b/tests/run-pass/concurrency/linux-futex.stderr @@ -1,2 +1,2 @@ -warning: thread support is experimental. +warning: thread support is experimental, no weak memory effects are currently emulated. diff --git a/tests/run-pass/concurrency/simple.stderr b/tests/run-pass/concurrency/simple.stderr index f1550dd25aa0c..24444fdc17c17 100644 --- a/tests/run-pass/concurrency/simple.stderr +++ b/tests/run-pass/concurrency/simple.stderr @@ -1,4 +1,4 @@ -warning: thread support is experimental. +warning: thread support is experimental, no weak memory effects are currently emulated. thread '' panicked at 'Hello!', $DIR/simple.rs:54:9 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace diff --git a/tests/run-pass/concurrency/sync.stderr b/tests/run-pass/concurrency/sync.stderr index b01247aea4e0e..7ba8087a9b4bc 100644 --- a/tests/run-pass/concurrency/sync.stderr +++ b/tests/run-pass/concurrency/sync.stderr @@ -1,2 +1,2 @@ -warning: thread support is experimental. +warning: thread support is experimental, no weak memory effects are currently emulated. diff --git a/tests/run-pass/concurrency/thread_locals.stderr b/tests/run-pass/concurrency/thread_locals.stderr index b01247aea4e0e..7ba8087a9b4bc 100644 --- a/tests/run-pass/concurrency/thread_locals.stderr +++ b/tests/run-pass/concurrency/thread_locals.stderr @@ -1,2 +1,2 @@ -warning: thread support is experimental. +warning: thread support is experimental, no weak memory effects are currently emulated. diff --git a/tests/run-pass/concurrency/tls_lib_drop.stderr b/tests/run-pass/concurrency/tls_lib_drop.stderr index b01247aea4e0e..7ba8087a9b4bc 100644 --- a/tests/run-pass/concurrency/tls_lib_drop.stderr +++ b/tests/run-pass/concurrency/tls_lib_drop.stderr @@ -1,2 +1,2 @@ -warning: thread support is experimental. +warning: thread support is experimental, no weak memory effects are currently emulated. diff --git a/tests/run-pass/libc.stderr b/tests/run-pass/libc.stderr index b01247aea4e0e..7ba8087a9b4bc 100644 --- a/tests/run-pass/libc.stderr +++ b/tests/run-pass/libc.stderr @@ -1,2 +1,2 @@ -warning: thread support is experimental. +warning: thread support is experimental, no weak memory effects are currently emulated. diff --git a/tests/run-pass/panic/concurrent-panic.stderr b/tests/run-pass/panic/concurrent-panic.stderr index ca6031e57b402..885385a8dd937 100644 --- a/tests/run-pass/panic/concurrent-panic.stderr +++ b/tests/run-pass/panic/concurrent-panic.stderr @@ -1,4 +1,4 @@ -warning: thread support is experimental. +warning: thread support is experimental, no weak memory effects are currently emulated. Thread 1 starting, will block on mutex Thread 1 reported it has started From 4a1f7ac1f153c7b0df8d7603b4852cc24b22c039 Mon Sep 17 00:00:00 2001 From: JCTyBlaidd Date: Sun, 15 Nov 2020 19:50:38 +0000 Subject: [PATCH 2446/3747] Convert extra benchmark program into cfg option. --- bench-cargo-miri/mse/src/main.rs | 3 ++ .../mse_and_dangling_thread/Cargo.toml | 7 ----- .../mse_and_dangling_thread/src/main.rs | 30 ------------------- 3 files changed, 3 insertions(+), 37 deletions(-) delete mode 100644 bench-cargo-miri/mse_and_dangling_thread/Cargo.toml delete mode 100644 bench-cargo-miri/mse_and_dangling_thread/src/main.rs diff --git a/bench-cargo-miri/mse/src/main.rs b/bench-cargo-miri/mse/src/main.rs index b4ad1575104e2..57e2860710556 100644 --- a/bench-cargo-miri/mse/src/main.rs +++ b/bench-cargo-miri/mse/src/main.rs @@ -2,6 +2,9 @@ static EXPECTED: &[u8] = &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, static PCM: &[i16] = &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, -2, 0, -2, 0, -2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 1, 0, 1, 0, 0, -2, 0, -2, 0, -2, 0, -2, -2, -2, -3, -3, -3, -3, -4, -2, -5, -2, -5, -2, -4, 0, -4, 0, -4, 0, -4, 1, -4, 1, -4, 2, -4, 2, -4, 2, -4, 2, -4, 2, -3, 1, -4, 0, -4, 0, -5, 0, -5, 0, -5, 0, -4, 2, -4, 3, -4, 4, -3, 5, -2, 5, -3, 6, -3, 6, -3, 5, -3, 5, -2, 4, -2, 3, -5, 0, -6, 0, -3, -2, -4, -4, -9, -5, -9, -4, -4, -2, -4, -2, -4, 0, -2, 1, 1, 1, 4, 2, 8, 2, 12, 1, 13, 0, 12, 0, 11, 0, 8, -2, 7, 0, 7, -3, 11, -8, 15, -9, 17, -6, 17, -5, 13, -3, 7, 0, 3, 0, -2, 0, -4, 0, -4, -2, -6, 0, -14, -2, -17, -4, -8, 0, -7, 5, -17, 7, -18, 10, -7, 18, -2, 25, -3, 27, 0, 31, 4, 34, 4, 34, 8, 36, 8, 37, 2, 36, 4, 34, 8, 28, 3, 15, 0, 11, 0, 12, -5, 8, -4, 10, 0, 23, -4, 31, -8, 30, -2, 30, 0, 26, -6, 22, -6, 20, -12, 15, -19, 10, -10, 13, -14, 6, -43, -13, -43, -16, -9, -12, -10, -29, -42, -40, -37, -28, -5, -21, 1, -24, -8, -20, 4, -18, 26, -24, 44, -26, 66, -30, 86, -37, 88, -41, 72, -46, 50, -31, 28, 23, 14, 64, 16, 51, 26, 32, 34, 39, 42, 48, 35, 58, 0, 72, -36, 69, -59, 58, -98, 54, -124, 36, -103, 12, -110, 5, -173, -19, -146, -59, -4, -42, 51, 1, -23, -6, -30, -6, 45, 46, 47, 70, 6, 55, 19, 60, 38, 62, 42, 47, 61, 46, 40, 42, -19, 22, -34, 6, -35, -50, -61, -141, -37, -171, 17, -163, 26, -180, 46, -154, 80, -63, 48, -4, 18, 20, 50, 47, 58, 53, 44, 61, 57, 85, 37, 80, 0, 86, -8, 106, -95, 49, -213, -8, -131, 47, 49, 63, 40, -39, -69, -74, -37, -20, 63, -12, 58, -14, -12, 25, -31, 41, 11, 45, 76, 47, 167, 5, 261, -37, 277, -83, 183, -172, 35, -122, -79, 138, -70, 266, 69, 124, 228, 0, 391, -29, 594, -84, 702, -78, 627, -8, 551, -13, 509, 13, 372, 120, 352, 125, 622, 127, 691, 223, 362, 126, 386, -33, 915, 198, 958, 457, 456, 298, 500, 233, 1027, 469, 1096, 426, 918, 160, 1067, 141, 1220, 189, 1245, 164, 1375, 297, 1378, 503, 1299, 702, 1550, 929, 1799, 855, 1752, 547, 1830, 602, 1928, 832, 1736, 796, 1735, 933, 1961, 1385, 1935, 1562, 2105, 1485, 2716, 1449, 2948, 1305, 2768, 1205, 2716, 1346, 2531, 1450, 2470, 1653, 3117, 2111, 3370, 2176, 2696, 1947, 2925, 2305, 3846, 2658, 2425, 2184, -877, 1981, -2261, 2623, -1645, 2908, -1876, 2732, -2704, 2953, -2484, 3116, -2120, 2954, -2442, 3216, -2466, 3499, -2192, 3234, -2392, 3361, -2497, 3869, -2078, 3772, -1858, 3915, -2066, 4438, -2285, 2934, -2294, -280, -2066, -1762, -1992, -1412, -2298, -1535, -2399, -1789, -2223, -1419, -2244, -1334, -2092, -1476, -1777, -1396, -2014, -1571, -2199, -1574, -1843, -1167, -1910, -1446, -2007, -1818]; fn main() { + #[cfg(increase_thread_usage)] + let thread = std::thread::spawn(|| 4); + for _ in 0..2 { mse(PCM.len(), PCM, EXPECTED); } diff --git a/bench-cargo-miri/mse_and_dangling_thread/Cargo.toml b/bench-cargo-miri/mse_and_dangling_thread/Cargo.toml deleted file mode 100644 index 7b4c2dc758faa..0000000000000 --- a/bench-cargo-miri/mse_and_dangling_thread/Cargo.toml +++ /dev/null @@ -1,7 +0,0 @@ -[package] -name = "mse" -version = "0.1.0" -authors = ["Ralf Jung "] -edition = "2018" - -[dependencies] diff --git a/bench-cargo-miri/mse_and_dangling_thread/src/main.rs b/bench-cargo-miri/mse_and_dangling_thread/src/main.rs deleted file mode 100644 index 008e9c80eff1a..0000000000000 --- a/bench-cargo-miri/mse_and_dangling_thread/src/main.rs +++ /dev/null @@ -1,30 +0,0 @@ -static EXPECTED: &[u8] = &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 0, 0, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 1, 0, 255, 255, 1, 0, 255, 255, 1, 0, 255, 255, 1, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 254, 255, 0, 0, 254, 255, 0, 0, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 255, 255, 1, 0, 255, 255, 1, 0, 0, 0, 1, 0, 255, 255, 2, 0, 255, 255, 2, 0, 255, 255, 2, 0, 255, 255, 2, 0, 255, 255, 2, 0, 255, 255, 1, 0, 255, 255, 1, 0, 255, 255, 0, 0, 254, 255, 0, 0, 254, 255, 0, 0, 254, 255, 255, 255, 254, 255, 254, 255, 254, 255, 253, 255, 253, 255, 253, 255, 253, 255, 252, 255, 254, 255, 251, 255, 254, 255, 251, 255, 254, 255, 252, 255, 255, 255, 252, 255, 0, 0, 252, 255, 0, 0, 252, 255, 1, 0, 252, 255, 1, 0, 252, 255, 2, 0, 252, 255, 2, 0, 252, 255, 2, 0, 252, 255, 2, 0, 252, 255, 2, 0, 253, 255, 1, 0, 252, 255, 0, 0, 252, 255, 255, 255, 251, 255, 0, 0, 251, 255, 0, 0, 251, 255, 0, 0, 252, 255, 2, 0, 252, 255, 3, 0, 252, 255, 4, 0, 253, 255, 5, 0, 254, 255, 5, 0, 253, 255, 6, 0, 253, 255, 6, 0, 253, 255, 5, 0, 253, 255, 5, 0, 254, 255, 4, 0, 254, 255, 3, 0, 251, 255, 0, 0, 250, 255, 255, 255, 253, 255, 254, 255, 252, 255, 252, 255, 247, 255, 251, 255, 247, 255, 252, 255, 252, 255, 254, 255, 252, 255, 254, 255, 252, 255, 255, 255, 254, 255, 1, 0, 1, 0, 1, 0, 4, 0, 2, 0, 8, 0, 2, 0, 12, 0, 1, 0, 13, 0, 0, 0, 12, 0, 0, 0, 11, 0, 255, 255, 8, 0, 254, 255, 7, 0, 0, 0, 7, 0, 253, 255, 11, 0, 248, 255, 15, 0, 247, 255, 17, 0, 250, 255, 17, 0, 251, 255, 13, 0, 253, 255, 7, 0, 255, 255, 3, 0, 255, 255, 254, 255, 255, 255, 252, 255, 255, 255, 252, 255, 254, 255, 250, 255, 255, 255, 242, 255, 254, 255, 239, 255, 252, 255, 248, 255, 255, 255, 249, 255, 5, 0, 239, 255, 7, 0, 238, 255, 10, 0, 249, 255, 18, 0, 254, 255, 25, 0, 253, 255, 27, 0, 0, 0, 31, 0, 4, 0, 34, 0, 4, 0, 34, 0, 8, 0, 36, 0, 8, 0, 37, 0, 2, 0, 36, 0, 4, 0, 34, 0, 8, 0, 28, 0, 3, 0, 15, 0, 255, 255, 11, 0, 0, 0, 12, 0, 251, 255, 8, 0, 252, 255, 10, 0, 0, 0, 23, 0, 252, 255, 31, 0, 248, 255, 30, 0, 254, 255, 30, 0, 255, 255, 26, 0, 250, 255, 22, 0, 250, 255, 20, 0, 244, 255, 15, 0, 237, 255, 10, 0, 246, 255, 13, 0, 242, 255, 6, 0, 213, 255, 243, 255, 213, 255, 240, 255, 247, 255, 244, 255, 246, 255, 227, 255, 214, 255, 216, 255, 219, 255, 228, 255, 251, 255, 235, 255, 1, 0, 232, 255, 248, 255, 236, 255, 4, 0, 238, 255, 26, 0, 232, 255, 44, 0, 230, 255, 66, 0, 226, 255, 86, 0, 219, 255, 88, 0, 215, 255, 72, 0, 210, 255, 50, 0, 225, 255, 28, 0, 23, 0, 14, 0, 64, 0, 16, 0, 51, 0, 26, 0, 32, 0, 34, 0, 39, 0, 42, 0, 48, 0, 35, 0, 58, 0, 255, 255, 72, 0, 220, 255, 69, 0, 197, 255, 58, 0, 158, 255, 54, 0, 132, 255, 36, 0, 153, 255, 12, 0, 146, 255, 5, 0, 83, 255, 237, 255, 110, 255, 197, 255, 252, 255, 214, 255, 51, 0, 1, 0, 233, 255, 250, 255, 226, 255, 250, 255, 45, 0, 46, 0, 47, 0, 70, 0, 6, 0, 55, 0, 19, 0, 60, 0, 38, 0, 62, 0, 42, 0, 47, 0, 61, 0, 46, 0, 40, 0, 42, 0, 237, 255, 22, 0, 222, 255, 6, 0, 221, 255, 206, 255, 195, 255, 115, 255, 219, 255, 85, 255, 17, 0, 93, 255, 26, 0, 76, 255, 46, 0, 102, 255, 80, 0, 193, 255, 48, 0, 252, 255, 18, 0, 20, 0, 50, 0, 47, 0, 58, 0, 53, 0, 44, 0, 61, 0, 57, 0, 85, 0, 37, 0, 80, 0, 0, 0, 86, 0, 248, 255, 106, 0, 161, 255, 49, 0, 43, 255, 248, 255, 125, 255, 47, 0, 49, 0, 63, 0, 40, 0, 217, 255, 187, 255, 182, 255, 219, 255, 236, 255, 63, 0, 244, 255, 58, 0, 242, 255, 244, 255, 25, 0, 225, 255, 41, 0, 11, 0, 45, 0, 76, 0, 47, 0, 167, 0, 5, 0, 5, 1, 219, 255, 21, 1, 173, 255, 183, 0, 84, 255, 35, 0, 134, 255, 177, 255, 138, 0, 186, 255, 10, 1, 69, 0, 124, 0, 228, 0, 0, 0, 135, 1, 227, 255, 82, 2, 172, 255, 190, 2, 178, 255, 115, 2, 248, 255, 39, 2, 243, 255, 253, 1, 13, 0, 116, 1, 120, 0, 96, 1, 125, 0, 110, 2, 127, 0, 179, 2, 223, 0, 106, 1, 126, 0, 130, 1, 223, 255, 147, 3, 198, 0, 190, 3, 201, 1, 200, 1, 42, 1, 244, 1, 233, 0, 3, 4, 213, 1, 72, 4, 170, 1, 150, 3, 160, 0, 43, 4, 141, 0, 196, 4, 189, 0, 221, 4, 164, 0, 95, 5, 41, 1, 98, 5, 247, 1, 19, 5, 190, 2, 14, 6, 161, 3, 7, 7, 87, 3, 216, 6, 35, 2, 38, 7, 90, 2, 136, 7, 64, 3, 200, 6, 28, 3, 199, 6, 165, 3, 169, 7, 105, 5, 143, 7, 26, 6, 57, 8, 205, 5, 156, 10, 169, 5, 132, 11, 25, 5, 208, 10, 181, 4, 156, 10, 66, 5, 227, 9, 170, 5, 166, 9, 117, 6, 45, 12, 63, 8, 42, 13, 128, 8, 136, 10, 155, 7, 109, 11, 1, 9, 6, 15, 98, 10, 121, 9, 136, 8, 147, 252, 189, 7, 43, 247, 63, 10, 147, 249, 92, 11, 172, 248, 172, 10, 112, 245, 137, 11, 76, 246, 44, 12, 184, 247, 138, 11, 118, 246, 144, 12, 94, 246, 171, 13, 112, 247, 162, 12, 168, 246, 33, 13, 63, 246, 29, 15, 226, 247, 188, 14, 190, 248, 75, 15, 238, 247, 86, 17, 19, 247, 118, 11, 10, 247, 232, 254, 238, 247, 30, 249, 56, 248, 124, 250, 6, 247, 1, 250, 161, 246, 3, 249, 81, 247, 117, 250, 60, 247, 202, 250, 212, 247, 60, 250, 15, 249, 140, 250, 34, 248, 221, 249, 105, 247, 218, 249, 205, 248, 113, 251, 138, 248, 90, 250, 41, 248, 230, 248]; -static PCM: &[i16] = &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, -2, 0, -2, 0, -2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 1, 0, 1, 0, 0, -2, 0, -2, 0, -2, 0, -2, -2, -2, -3, -3, -3, -3, -4, -2, -5, -2, -5, -2, -4, 0, -4, 0, -4, 0, -4, 1, -4, 1, -4, 2, -4, 2, -4, 2, -4, 2, -4, 2, -3, 1, -4, 0, -4, 0, -5, 0, -5, 0, -5, 0, -4, 2, -4, 3, -4, 4, -3, 5, -2, 5, -3, 6, -3, 6, -3, 5, -3, 5, -2, 4, -2, 3, -5, 0, -6, 0, -3, -2, -4, -4, -9, -5, -9, -4, -4, -2, -4, -2, -4, 0, -2, 1, 1, 1, 4, 2, 8, 2, 12, 1, 13, 0, 12, 0, 11, 0, 8, -2, 7, 0, 7, -3, 11, -8, 15, -9, 17, -6, 17, -5, 13, -3, 7, 0, 3, 0, -2, 0, -4, 0, -4, -2, -6, 0, -14, -2, -17, -4, -8, 0, -7, 5, -17, 7, -18, 10, -7, 18, -2, 25, -3, 27, 0, 31, 4, 34, 4, 34, 8, 36, 8, 37, 2, 36, 4, 34, 8, 28, 3, 15, 0, 11, 0, 12, -5, 8, -4, 10, 0, 23, -4, 31, -8, 30, -2, 30, 0, 26, -6, 22, -6, 20, -12, 15, -19, 10, -10, 13, -14, 6, -43, -13, -43, -16, -9, -12, -10, -29, -42, -40, -37, -28, -5, -21, 1, -24, -8, -20, 4, -18, 26, -24, 44, -26, 66, -30, 86, -37, 88, -41, 72, -46, 50, -31, 28, 23, 14, 64, 16, 51, 26, 32, 34, 39, 42, 48, 35, 58, 0, 72, -36, 69, -59, 58, -98, 54, -124, 36, -103, 12, -110, 5, -173, -19, -146, -59, -4, -42, 51, 1, -23, -6, -30, -6, 45, 46, 47, 70, 6, 55, 19, 60, 38, 62, 42, 47, 61, 46, 40, 42, -19, 22, -34, 6, -35, -50, -61, -141, -37, -171, 17, -163, 26, -180, 46, -154, 80, -63, 48, -4, 18, 20, 50, 47, 58, 53, 44, 61, 57, 85, 37, 80, 0, 86, -8, 106, -95, 49, -213, -8, -131, 47, 49, 63, 40, -39, -69, -74, -37, -20, 63, -12, 58, -14, -12, 25, -31, 41, 11, 45, 76, 47, 167, 5, 261, -37, 277, -83, 183, -172, 35, -122, -79, 138, -70, 266, 69, 124, 228, 0, 391, -29, 594, -84, 702, -78, 627, -8, 551, -13, 509, 13, 372, 120, 352, 125, 622, 127, 691, 223, 362, 126, 386, -33, 915, 198, 958, 457, 456, 298, 500, 233, 1027, 469, 1096, 426, 918, 160, 1067, 141, 1220, 189, 1245, 164, 1375, 297, 1378, 503, 1299, 702, 1550, 929, 1799, 855, 1752, 547, 1830, 602, 1928, 832, 1736, 796, 1735, 933, 1961, 1385, 1935, 1562, 2105, 1485, 2716, 1449, 2948, 1305, 2768, 1205, 2716, 1346, 2531, 1450, 2470, 1653, 3117, 2111, 3370, 2176, 2696, 1947, 2925, 2305, 3846, 2658, 2425, 2184, -877, 1981, -2261, 2623, -1645, 2908, -1876, 2732, -2704, 2953, -2484, 3116, -2120, 2954, -2442, 3216, -2466, 3499, -2192, 3234, -2392, 3361, -2497, 3869, -2078, 3772, -1858, 3915, -2066, 4438, -2285, 2934, -2294, -280, -2066, -1762, -1992, -1412, -2298, -1535, -2399, -1789, -2223, -1419, -2244, -1334, -2092, -1476, -1777, -1396, -2014, -1571, -2199, -1574, -1843, -1167, -1910, -1446, -2007, -1818]; - -fn main() { - let thread = std::thread::spawn(|| 4); - for _ in 0..2 { - mse(PCM.len(), PCM, EXPECTED); - } - assert_eq!(4, thread.join().unwrap()); -} - -fn read_i16(buffer: &[u8], index: usize) -> i16 { - const SIZE: usize = std::mem::size_of::(); - let mut bytes: [u8; SIZE] = [0u8; SIZE]; - bytes.copy_from_slice(&buffer[(index * SIZE)..(index * SIZE + SIZE)]); - unsafe { std::mem::transmute(bytes) } -} - -fn mse(samples: usize, frame_buf: &[i16], buf_ref: &[u8]) -> f64 { - let mut mse = 0.0; - let max_samples = std::cmp::min(buf_ref.len() / 2, samples as usize); - for i in 0..max_samples { - let ref_res = read_i16(buf_ref, i); - let info_res = frame_buf[i as usize]; - let diff = (ref_res - info_res).abs(); - mse += f64::from(diff.pow(2)); - } - mse / max_samples as f64 -} - From a3b7839bbdde0c5856720dc885250752aefd4207 Mon Sep 17 00:00:00 2001 From: JCTyBlaidd Date: Sun, 15 Nov 2020 20:12:58 +0000 Subject: [PATCH 2447/3747] Add comment regarding seq-cst ordering & add test for disabling the data-race detector. --- src/data_race.rs | 11 ++++++++ .../concurrency/disable_data_race_detector.rs | 28 +++++++++++++++++++ .../disable_data_race_detector.stderr | 2 ++ 3 files changed, 41 insertions(+) create mode 100644 tests/run-pass/concurrency/disable_data_race_detector.rs create mode 100644 tests/run-pass/concurrency/disable_data_race_detector.stderr diff --git a/src/data_race.rs b/src/data_race.rs index 822ceab8fa04c..bad757bc70e59 100644 --- a/src/data_race.rs +++ b/src/data_race.rs @@ -27,6 +27,16 @@ //! from acquire/release operations. If weak memory orderings are explored then this //! may need to change or be updated accordingly. //! +//! Per the C++ spec for the memory model a sequentially consistent operation: +//! "A load operation with this memory order performs an acquire operation, +//! a store performs a release operation, and read-modify-write performs +//! both an acquire operation and a release operation, plus a single total +//! order exists in which all threads observe all modifications in the same +//! order (see Sequentially-consistent ordering below) " +//! So in the absence of weak memory effects a seq-cst load & a seq-cst store is identical +//! to a acquire load and a release store given the global sequentially consistent order +//! of the schedule. +//! //! FIXME: //! currently we have our own local copy of the currently active thread index and names, this is due //! in part to the inability to access the current location of threads.active_thread inside the AllocExtra @@ -196,6 +206,7 @@ struct MemoryCellClocks { /// The vector-clock of the timestamp of the last read operation /// performed by a thread since the last write operation occured. + /// It is reset to zero on each write operation. read: VClock, /// Atomic acquire & release sequence tracking clocks. diff --git a/tests/run-pass/concurrency/disable_data_race_detector.rs b/tests/run-pass/concurrency/disable_data_race_detector.rs new file mode 100644 index 0000000000000..e47a2079c205d --- /dev/null +++ b/tests/run-pass/concurrency/disable_data_race_detector.rs @@ -0,0 +1,28 @@ +// ignore-windows: Concurrency on Windows is not supported yet. +// compile-flags: -Zmiri-disable-data-race-detector + +use std::thread::spawn; + +#[derive(Copy, Clone)] +struct EvilSend(pub T); + +unsafe impl Send for EvilSend {} +unsafe impl Sync for EvilSend {} + +pub fn main() { + let mut a = 0u32; + let b = &mut a as *mut u32; + let c = EvilSend(b); + unsafe { + let j1 = spawn(move || { + *c.0 = 32; + }); + + let j2 = spawn(move || { + *c.0 = 64; //~ ERROR Data race + }); + + j1.join().unwrap(); + j2.join().unwrap(); + } +} diff --git a/tests/run-pass/concurrency/disable_data_race_detector.stderr b/tests/run-pass/concurrency/disable_data_race_detector.stderr new file mode 100644 index 0000000000000..7ba8087a9b4bc --- /dev/null +++ b/tests/run-pass/concurrency/disable_data_race_detector.stderr @@ -0,0 +1,2 @@ +warning: thread support is experimental, no weak memory effects are currently emulated. + From 0b0264fc820d12d6c5e6f9f702bc33e8921bb110 Mon Sep 17 00:00:00 2001 From: JCTyBlaidd Date: Sun, 15 Nov 2020 20:19:34 +0000 Subject: [PATCH 2448/3747] Run rustfmt on vector_clock.rs and data_race.rs --- src/data_race.rs | 431 ++++++++++++++++++++++++-------------------- src/vector_clock.rs | 233 +++++++++++++----------- 2 files changed, 356 insertions(+), 308 deletions(-) diff --git a/src/data_race.rs b/src/data_race.rs index bad757bc70e59..b9542f6e2d62c 100644 --- a/src/data_race.rs +++ b/src/data_race.rs @@ -11,7 +11,7 @@ //! a data race occurs between two memory accesses if they are on different threads, at least one operation //! is non-atomic, at least one operation is a write and neither access happens-before the other. Read the link //! for full definition. -//! +//! //! This re-uses vector indexes for threads that are known to be unable to report data-races, this is valid //! because it only re-uses vector indexes once all currently-active (not-terminated) threads have an internal //! vector clock that happens-after the join operation of the candidate thread. Threads that have not been joined @@ -43,21 +43,21 @@ //! read, write and deallocate functions and should be cleaned up in the future. use std::{ - fmt::Debug, rc::Rc, - cell::{Cell, RefCell, Ref, RefMut}, mem + cell::{Cell, Ref, RefCell, RefMut}, + fmt::Debug, + mem, + rc::Rc, }; +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_index::vec::{Idx, IndexVec}; -use rustc_target::abi::Size; use rustc_middle::{mir, ty::layout::TyAndLayout}; -use rustc_data_structures::fx::{FxHashSet, FxHashMap}; +use rustc_target::abi::Size; use crate::{ - MiriEvalContext, MiriEvalContextExt, - ThreadId, Tag, RangeMap, - InterpResult, Pointer, ScalarMaybeUninit, - MPlaceTy, OpTy, MemPlaceMeta, ImmTy, Immediate, - VClock, VSmallClockMap, VectorIdx, VTimestamp + ImmTy, Immediate, InterpResult, MPlaceTy, MemPlaceMeta, MiriEvalContext, MiriEvalContextExt, + OpTy, Pointer, RangeMap, ScalarMaybeUninit, Tag, ThreadId, VClock, VSmallClockMap, VTimestamp, + VectorIdx, }; pub type AllocExtra = VClockAlloc; @@ -89,7 +89,6 @@ pub enum AtomicWriteOp { SeqCst, } - /// Valid atomic fence operations, subset of atomic::Ordering. #[derive(Copy, Clone, PartialEq, Eq, Debug)] pub enum AtomicFenceOp { @@ -99,14 +98,11 @@ pub enum AtomicFenceOp { SeqCst, } - - /// The current set of vector clocks describing the state /// of a thread, contains the happens-before clock and /// additional metadata to model atomic fence operations. #[derive(Clone, Default, Debug)] struct ThreadClockSet { - /// The increasing clock representing timestamps /// that happen-before this thread. clock: VClock, @@ -120,9 +116,7 @@ struct ThreadClockSet { fence_release: VClock, } - impl ThreadClockSet { - /// Apply the effects of a release fence to this /// set of thread vector clocks. #[inline] @@ -152,7 +146,6 @@ impl ThreadClockSet { } } - /// Error returned by finding a data race /// should be elaborated upon. #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)] @@ -164,7 +157,6 @@ pub struct DataRace; /// exists on the memory cell. #[derive(Clone, PartialEq, Eq, Default, Debug)] struct AtomicMemoryCellClocks { - /// The clock-vector of the timestamp of the last atomic /// read operation performed by each thread. /// This detects potential data-races between atomic read @@ -179,7 +171,7 @@ struct AtomicMemoryCellClocks { /// Synchronization vector for acquire-release semantics /// contains the vector of timestamps that will - /// happen-before a thread if an acquire-load is + /// happen-before a thread if an acquire-load is /// performed on the data. sync_vector: VClock, @@ -195,7 +187,6 @@ struct AtomicMemoryCellClocks { /// for data-race detection. #[derive(Clone, PartialEq, Eq, Debug)] struct MemoryCellClocks { - /// The vector-clock timestamp of the last write /// corresponding to the writing threads timestamp. write: VTimestamp, @@ -215,7 +206,6 @@ struct MemoryCellClocks { atomic_ops: Option>, } - /// Create a default memory cell clocks instance /// for uninitialized memory. impl Default for MemoryCellClocks { @@ -224,20 +214,18 @@ impl Default for MemoryCellClocks { read: VClock::default(), write: 0, write_index: VectorIdx::MAX_INDEX, - atomic_ops: None + atomic_ops: None, } } } - impl MemoryCellClocks { - /// Load the internal atomic memory cells if they exist. #[inline] fn atomic(&self) -> Option<&AtomicMemoryCellClocks> { match &self.atomic_ops { Some(op) => Some(&*op), - None => None + None => None, } } @@ -251,7 +239,11 @@ impl MemoryCellClocks { /// Update memory cell data-race tracking for atomic /// load acquire semantics, is a no-op if this memory was /// not used previously as atomic memory. - fn load_acquire(&mut self, clocks: &mut ThreadClockSet, index: VectorIdx) -> Result<(), DataRace> { + fn load_acquire( + &mut self, + clocks: &mut ThreadClockSet, + index: VectorIdx, + ) -> Result<(), DataRace> { self.atomic_read_detect(clocks, index)?; if let Some(atomic) = self.atomic() { clocks.clock.join(&atomic.sync_vector); @@ -262,7 +254,11 @@ impl MemoryCellClocks { /// Update memory cell data-race tracking for atomic /// load relaxed semantics, is a no-op if this memory was /// not used previously as atomic memory. - fn load_relaxed(&mut self, clocks: &mut ThreadClockSet, index: VectorIdx) -> Result<(), DataRace> { + fn load_relaxed( + &mut self, + clocks: &mut ThreadClockSet, + index: VectorIdx, + ) -> Result<(), DataRace> { self.atomic_read_detect(clocks, index)?; if let Some(atomic) = self.atomic() { clocks.fence_acquire.join(&atomic.sync_vector); @@ -270,7 +266,6 @@ impl MemoryCellClocks { Ok(()) } - /// Update the memory cell data-race tracking for atomic /// store release semantics. fn store_release(&mut self, clocks: &ThreadClockSet, index: VectorIdx) -> Result<(), DataRace> { @@ -313,10 +308,14 @@ impl MemoryCellClocks { atomic.sync_vector.join(&clocks.fence_release); Ok(()) } - + /// Detect data-races with an atomic read, caused by a non-atomic write that does /// not happen-before the atomic-read. - fn atomic_read_detect(&mut self, clocks: &ThreadClockSet, index: VectorIdx) -> Result<(), DataRace> { + fn atomic_read_detect( + &mut self, + clocks: &ThreadClockSet, + index: VectorIdx, + ) -> Result<(), DataRace> { log::trace!("Atomic read with vectors: {:#?} :: {:#?}", self, clocks); if self.write <= clocks.clock[self.write_index] { let atomic = self.atomic_mut(); @@ -329,7 +328,11 @@ impl MemoryCellClocks { /// Detect data-races with an atomic write, either with a non-atomic read or with /// a non-atomic write. - fn atomic_write_detect(&mut self, clocks: &ThreadClockSet, index: VectorIdx) -> Result<(), DataRace> { + fn atomic_write_detect( + &mut self, + clocks: &ThreadClockSet, + index: VectorIdx, + ) -> Result<(), DataRace> { log::trace!("Atomic write with vectors: {:#?} :: {:#?}", self, clocks); if self.write <= clocks.clock[self.write_index] && self.read <= clocks.clock { let atomic = self.atomic_mut(); @@ -342,7 +345,11 @@ impl MemoryCellClocks { /// Detect races for non-atomic read operations at the current memory cell /// returns true if a data-race is detected. - fn read_race_detect(&mut self, clocks: &ThreadClockSet, index: VectorIdx) -> Result<(), DataRace> { + fn read_race_detect( + &mut self, + clocks: &ThreadClockSet, + index: VectorIdx, + ) -> Result<(), DataRace> { log::trace!("Unsynchronized read with vectors: {:#?} :: {:#?}", self, clocks); if self.write <= clocks.clock[self.write_index] { let race_free = if let Some(atomic) = self.atomic() { @@ -363,7 +370,11 @@ impl MemoryCellClocks { /// Detect races for non-atomic write operations at the current memory cell /// returns true if a data-race is detected. - fn write_race_detect(&mut self, clocks: &ThreadClockSet, index: VectorIdx) -> Result<(), DataRace> { + fn write_race_detect( + &mut self, + clocks: &ThreadClockSet, + index: VectorIdx, + ) -> Result<(), DataRace> { log::trace!("Unsynchronized write with vectors: {:#?} :: {:#?}", self, clocks); if self.write <= clocks.clock[self.write_index] && self.read <= clocks.clock { let race_free = if let Some(atomic) = self.atomic() { @@ -385,18 +396,16 @@ impl MemoryCellClocks { } } - /// Evaluation context extensions. impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { - /// Atomic variant of read_scalar_at_offset. fn read_scalar_at_offset_atomic( &self, op: OpTy<'tcx, Tag>, offset: u64, layout: TyAndLayout<'tcx>, - atomic: AtomicReadOp + atomic: AtomicReadOp, ) -> InterpResult<'tcx, ScalarMaybeUninit> { let this = self.eval_context_ref(); let op_place = this.deref_operand(op)?; @@ -415,7 +424,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { offset: u64, value: impl Into>, layout: TyAndLayout<'tcx>, - atomic: AtomicWriteOp + atomic: AtomicWriteOp, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let op_place = this.deref_operand(op)?; @@ -429,46 +438,45 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { /// Perform an atomic read operation at the memory location. fn read_scalar_atomic( - &self, place: MPlaceTy<'tcx, Tag>, atomic: AtomicReadOp + &self, + place: MPlaceTy<'tcx, Tag>, + atomic: AtomicReadOp, ) -> InterpResult<'tcx, ScalarMaybeUninit> { let this = self.eval_context_ref(); - let scalar = this.allow_data_races_ref(move |this| { - this.read_scalar(place.into()) - })?; + let scalar = this.allow_data_races_ref(move |this| this.read_scalar(place.into()))?; self.validate_atomic_load(place, atomic)?; Ok(scalar) } /// Perform an atomic write operation at the memory location. fn write_scalar_atomic( - &mut self, val: ScalarMaybeUninit, dest: MPlaceTy<'tcx, Tag>, - atomic: AtomicWriteOp + &mut self, + val: ScalarMaybeUninit, + dest: MPlaceTy<'tcx, Tag>, + atomic: AtomicWriteOp, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - this.allow_data_races_mut(move |this| { - this.write_scalar(val, dest.into()) - })?; + this.allow_data_races_mut(move |this| this.write_scalar(val, dest.into()))?; self.validate_atomic_store(dest, atomic) } /// Perform a atomic operation on a memory location. fn atomic_op_immediate( &mut self, - place: MPlaceTy<'tcx, Tag>, rhs: ImmTy<'tcx, Tag>, - op: mir::BinOp, neg: bool, atomic: AtomicRwOp + place: MPlaceTy<'tcx, Tag>, + rhs: ImmTy<'tcx, Tag>, + op: mir::BinOp, + neg: bool, + atomic: AtomicRwOp, ) -> InterpResult<'tcx, ImmTy<'tcx, Tag>> { let this = self.eval_context_mut(); - let old = this.allow_data_races_mut(|this| { - this.read_immediate(place. into()) - })?; + let old = this.allow_data_races_mut(|this| this.read_immediate(place.into()))?; // Atomics wrap around on overflow. let val = this.binary_op(op, old, rhs)?; let val = if neg { this.unary_op(mir::UnOp::Not, val)? } else { val }; - this.allow_data_races_mut(|this| { - this.write_immediate(*val, place.into()) - })?; + this.allow_data_races_mut(|this| this.write_immediate(*val, place.into()))?; this.validate_atomic_rmw(place, atomic)?; Ok(old) @@ -478,17 +486,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { /// scalar value, the old value is returned. fn atomic_exchange_scalar( &mut self, - place: MPlaceTy<'tcx, Tag>, new: ScalarMaybeUninit, - atomic: AtomicRwOp + place: MPlaceTy<'tcx, Tag>, + new: ScalarMaybeUninit, + atomic: AtomicRwOp, ) -> InterpResult<'tcx, ScalarMaybeUninit> { let this = self.eval_context_mut(); - let old = this.allow_data_races_mut(|this| { - this.read_scalar(place.into()) - })?; - this.allow_data_races_mut(|this| { - this.write_scalar(new, place.into()) - })?; + let old = this.allow_data_races_mut(|this| this.read_scalar(place.into()))?; + this.allow_data_races_mut(|this| this.write_scalar(new, place.into()))?; this.validate_atomic_rmw(place, atomic)?; Ok(old) } @@ -497,9 +502,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { /// on success an atomic RMW operation is performed and on failure /// only an atomic read occurs. fn atomic_compare_exchange_scalar( - &mut self, place: MPlaceTy<'tcx, Tag>, - expect_old: ImmTy<'tcx, Tag>, new: ScalarMaybeUninit, - success: AtomicRwOp, fail: AtomicReadOp + &mut self, + place: MPlaceTy<'tcx, Tag>, + expect_old: ImmTy<'tcx, Tag>, + new: ScalarMaybeUninit, + success: AtomicRwOp, + fail: AtomicReadOp, ) -> InterpResult<'tcx, Immediate> { let this = self.eval_context_mut(); @@ -507,9 +515,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { // to read with the failure ordering and if successfull then try again with the success // read ordering and write in the success case. // Read as immediate for the sake of `binary_op()` - let old = this.allow_data_races_mut(|this| { - this.read_immediate(place.into()) - })?; + let old = this.allow_data_races_mut(|this| this.read_immediate(place.into()))?; // `binary_op` will bail if either of them is not a scalar. let eq = this.overflowing_binary_op(mir::BinOp::Eq, old, expect_old)?.0; @@ -519,9 +525,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { // if successful, perform a full rw-atomic validation // otherwise treat this as an atomic load with the fail ordering. if eq.to_bool()? { - this.allow_data_races_mut(|this| { - this.write_scalar(new, place.into()) - })?; + this.allow_data_races_mut(|this| this.write_scalar(new, place.into()))?; this.validate_atomic_rmw(place, success)?; } else { this.validate_atomic_load(place, fail)?; @@ -530,68 +534,74 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { // Return the old value. Ok(res) } - - + /// Update the data-race detector for an atomic read occuring at the /// associated memory-place and on the current thread. fn validate_atomic_load( - &self, place: MPlaceTy<'tcx, Tag>, atomic: AtomicReadOp + &self, + place: MPlaceTy<'tcx, Tag>, + atomic: AtomicReadOp, ) -> InterpResult<'tcx> { let this = self.eval_context_ref(); this.validate_atomic_op( - place, atomic, "Atomic Load", + place, + atomic, + "Atomic Load", move |memory, clocks, index, atomic| { if atomic == AtomicReadOp::Relaxed { memory.load_relaxed(&mut *clocks, index) } else { memory.load_acquire(&mut *clocks, index) } - } + }, ) } /// Update the data-race detector for an atomic write occuring at the /// associated memory-place and on the current thread. fn validate_atomic_store( - &mut self, place: MPlaceTy<'tcx, Tag>, atomic: AtomicWriteOp + &mut self, + place: MPlaceTy<'tcx, Tag>, + atomic: AtomicWriteOp, ) -> InterpResult<'tcx> { let this = self.eval_context_ref(); this.validate_atomic_op( - place, atomic, "Atomic Store", + place, + atomic, + "Atomic Store", move |memory, clocks, index, atomic| { if atomic == AtomicWriteOp::Relaxed { memory.store_relaxed(clocks, index) } else { memory.store_release(clocks, index) } - } + }, ) } /// Update the data-race detector for an atomic read-modify-write occuring /// at the associated memory place and on the current thread. fn validate_atomic_rmw( - &mut self, place: MPlaceTy<'tcx, Tag>, atomic: AtomicRwOp + &mut self, + place: MPlaceTy<'tcx, Tag>, + atomic: AtomicRwOp, ) -> InterpResult<'tcx> { use AtomicRwOp::*; let acquire = matches!(atomic, Acquire | AcqRel | SeqCst); let release = matches!(atomic, Release | AcqRel | SeqCst); let this = self.eval_context_ref(); - this.validate_atomic_op( - place, atomic, "Atomic RMW", - move |memory, clocks, index, _| { - if acquire { - memory.load_acquire(clocks, index)?; - } else { - memory.load_relaxed(clocks, index)?; - } - if release { - memory.rmw_release(clocks, index) - } else { - memory.rmw_relaxed(clocks, index) - } + this.validate_atomic_op(place, atomic, "Atomic RMW", move |memory, clocks, index, _| { + if acquire { + memory.load_acquire(clocks, index)?; + } else { + memory.load_relaxed(clocks, index)?; } - ) + if release { + memory.rmw_release(clocks, index) + } else { + memory.rmw_relaxed(clocks, index) + } + }) } /// Update the data-race detector for an atomic fence on the current thread. @@ -620,12 +630,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { } } - - /// Vector clock metadata for a logical memory allocation. #[derive(Debug, Clone)] pub struct VClockAlloc { - /// Range of Vector clocks, this gives each byte a potentially /// unqiue set of vector clocks, but merges identical information /// together for improved efficiency. @@ -635,16 +642,12 @@ pub struct VClockAlloc { global: MemoryExtra, } - impl VClockAlloc { - /// Create a new data-race allocation detector. pub fn new_allocation(global: &MemoryExtra, len: Size) -> VClockAlloc { VClockAlloc { global: Rc::clone(global), - alloc_ranges: RefCell::new( - RangeMap::new(len, MemoryCellClocks::default()) - ) + alloc_ranges: RefCell::new(RangeMap::new(len, MemoryCellClocks::default())), } } @@ -653,27 +656,29 @@ impl VClockAlloc { fn find_gt_index(l: &VClock, r: &VClock) -> Option { let l_slice = l.as_slice(); let r_slice = r.as_slice(); - l_slice.iter().zip(r_slice.iter()) + l_slice + .iter() + .zip(r_slice.iter()) .enumerate() - .find_map(|(idx, (&l, &r))| { - if l > r { Some(idx) } else { None } - }).or_else(|| { + .find_map(|(idx, (&l, &r))| if l > r { Some(idx) } else { None }) + .or_else(|| { if l_slice.len() > r_slice.len() { - // By invariant, if l_slice is longer // then one element must be larger. // This just validates that this is true // and reports earlier elements first. let l_remainder_slice = &l_slice[r_slice.len()..]; - let idx = l_remainder_slice.iter().enumerate() - .find_map(|(idx, &r)| { - if r == 0 { None } else { Some(idx) } - }).expect("Invalid VClock Invariant"); + let idx = l_remainder_slice + .iter() + .enumerate() + .find_map(|(idx, &r)| if r == 0 { None } else { Some(idx) }) + .expect("Invalid VClock Invariant"); Some(idx) } else { None } - }).map(|idx| VectorIdx::new(idx)) + }) + .map(|idx| VectorIdx::new(idx)) } /// Report a data-race found in the program. @@ -684,39 +689,42 @@ impl VClockAlloc { #[cold] #[inline(never)] fn report_data_race<'tcx>( - global: &MemoryExtra, range: &MemoryCellClocks, - action: &str, is_atomic: bool, - pointer: Pointer, len: Size + global: &MemoryExtra, + range: &MemoryCellClocks, + action: &str, + is_atomic: bool, + pointer: Pointer, + len: Size, ) -> InterpResult<'tcx> { let (current_index, current_clocks) = global.current_thread_state(); let write_clock; - let ( - other_action, other_thread, other_clock - ) = if range.write > current_clocks.clock[range.write_index] { - + let (other_action, other_thread, other_clock) = if range.write + > current_clocks.clock[range.write_index] + { // Convert the write action into the vector clock it // represents for diagnostic purposes. write_clock = VClock::new_with_index(range.write_index, range.write); ("WRITE", range.write_index, &write_clock) - } else if let Some(idx) = Self::find_gt_index( - &range.read, ¤t_clocks.clock - ){ + } else if let Some(idx) = Self::find_gt_index(&range.read, ¤t_clocks.clock) { ("READ", idx, &range.read) } else if !is_atomic { if let Some(atomic) = range.atomic() { - if let Some(idx) = Self::find_gt_index( - &atomic.write_vector, ¤t_clocks.clock - ) { + if let Some(idx) = Self::find_gt_index(&atomic.write_vector, ¤t_clocks.clock) + { ("ATOMIC_STORE", idx, &atomic.write_vector) - } else if let Some(idx) = Self::find_gt_index( - &atomic.read_vector, ¤t_clocks.clock - ) { + } else if let Some(idx) = + Self::find_gt_index(&atomic.read_vector, ¤t_clocks.clock) + { ("ATOMIC_LOAD", idx, &atomic.read_vector) } else { - unreachable!("Failed to report data-race for non-atomic operation: no race found") + unreachable!( + "Failed to report data-race for non-atomic operation: no race found" + ) } } else { - unreachable!("Failed to report data-race for non-atomic operation: no atomic component") + unreachable!( + "Failed to report data-race for non-atomic operation: no atomic component" + ) } } else { unreachable!("Failed to report data-race for atomic operation") @@ -725,15 +733,19 @@ impl VClockAlloc { // Load elaborated thread information about the racing thread actions. let current_thread_info = global.print_thread_metadata(current_index); let other_thread_info = global.print_thread_metadata(other_thread); - + // Throw the data-race detection. throw_ub_format!( "Data race detected between {} on {} and {} on {}, memory({:?},offset={},size={})\ \n\t\t -current vector clock = {:?}\ \n\t\t -conflicting timestamp = {:?}", - action, current_thread_info, - other_action, other_thread_info, - pointer.alloc_id, pointer.offset.bytes(), len.bytes(), + action, + current_thread_info, + other_action, + other_thread_info, + pointer.alloc_id, + pointer.offset.bytes(), + len.bytes(), current_clocks.clock, other_clock ) @@ -748,12 +760,16 @@ impl VClockAlloc { if self.global.multi_threaded.get() { let (index, clocks) = self.global.current_thread_state(); let mut alloc_ranges = self.alloc_ranges.borrow_mut(); - for (_,range) in alloc_ranges.iter_mut(pointer.offset, len) { + for (_, range) in alloc_ranges.iter_mut(pointer.offset, len) { if let Err(DataRace) = range.read_race_detect(&*clocks, index) { - // Report data-race. return Self::report_data_race( - &self.global,range, "READ", false, pointer, len + &self.global, + range, + "READ", + false, + pointer, + len, ); } } @@ -763,17 +779,25 @@ impl VClockAlloc { } } - // Shared code for detecting data-races on unique access to a section of memory - fn unique_access<'tcx>(&mut self, pointer: Pointer, len: Size, action: &str) -> InterpResult<'tcx> { + fn unique_access<'tcx>( + &mut self, + pointer: Pointer, + len: Size, + action: &str, + ) -> InterpResult<'tcx> { if self.global.multi_threaded.get() { let (index, clocks) = self.global.current_thread_state(); - for (_,range) in self.alloc_ranges.get_mut().iter_mut(pointer.offset, len) { + for (_, range) in self.alloc_ranges.get_mut().iter_mut(pointer.offset, len) { if let Err(DataRace) = range.write_race_detect(&*clocks, index) { - // Report data-race return Self::report_data_race( - &self.global, range, action, false, pointer, len + &self.global, + range, + action, + false, + pointer, + len, ); } } @@ -802,7 +826,6 @@ impl VClockAlloc { impl<'mir, 'tcx: 'mir> EvalContextPrivExt<'mir, 'tcx> for MiriEvalContext<'mir, 'tcx> {} trait EvalContextPrivExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { - // Temporarily allow data-races to occur, this should only be // used if either one of the appropiate `validate_atomic` functions // will be called to treat a memory access as atomic or if the memory @@ -827,7 +850,10 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { /// so should only be used for atomic operations or internal state that the program cannot /// access. #[inline] - fn allow_data_races_mut(&mut self, op: impl FnOnce(&mut MiriEvalContext<'mir, 'tcx>) -> R) -> R { + fn allow_data_races_mut( + &mut self, + op: impl FnOnce(&mut MiriEvalContext<'mir, 'tcx>) -> R, + ) -> R { let this = self.eval_context_mut(); let old = if let Some(data_race) = &this.memory.extra.data_race { data_race.multi_threaded.replace(false) @@ -848,34 +874,49 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { /// FIXME: is this valid, or should get_raw_mut be used for /// atomic-stores/atomic-rmw? fn validate_atomic_op( - &self, place: MPlaceTy<'tcx, Tag>, - atomic: A, description: &str, + &self, + place: MPlaceTy<'tcx, Tag>, + atomic: A, + description: &str, mut op: impl FnMut( - &mut MemoryCellClocks, &mut ThreadClockSet, VectorIdx, A - ) -> Result<(), DataRace> + &mut MemoryCellClocks, + &mut ThreadClockSet, + VectorIdx, + A, + ) -> Result<(), DataRace>, ) -> InterpResult<'tcx> { let this = self.eval_context_ref(); if let Some(data_race) = &this.memory.extra.data_race { if data_race.multi_threaded.get() { - // Load and log the atomic operation. let place_ptr = place.ptr.assert_ptr(); let size = place.layout.size; - let alloc_meta = &this.memory.get_raw(place_ptr.alloc_id)?.extra.data_race.as_ref().unwrap(); + let alloc_meta = + &this.memory.get_raw(place_ptr.alloc_id)?.extra.data_race.as_ref().unwrap(); log::trace!( "Atomic op({}) with ordering {:?} on memory({:?}, offset={}, size={})", - description, &atomic, place_ptr.alloc_id, place_ptr.offset.bytes(), size.bytes() + description, + &atomic, + place_ptr.alloc_id, + place_ptr.offset.bytes(), + size.bytes() ); // Perform the atomic operation. let data_race = &alloc_meta.global; data_race.maybe_perform_sync_operation(|index, mut clocks| { - for (_,range) in alloc_meta.alloc_ranges.borrow_mut().iter_mut(place_ptr.offset, size) { + for (_, range) in + alloc_meta.alloc_ranges.borrow_mut().iter_mut(place_ptr.offset, size) + { if let Err(DataRace) = op(range, &mut *clocks, index, atomic) { mem::drop(clocks); return VClockAlloc::report_data_race( - &alloc_meta.global, range, description, true, - place_ptr, size + &alloc_meta.global, + range, + description, + true, + place_ptr, + size, ); } } @@ -884,10 +925,13 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { // Log changes to atomic memory. if log::log_enabled!(log::Level::Trace) { - for (_,range) in alloc_meta.alloc_ranges.borrow().iter(place_ptr.offset, size) { + for (_, range) in alloc_meta.alloc_ranges.borrow().iter(place_ptr.offset, size) + { log::trace!( "Updated atomic memory({:?}, offset={}, size={}) to {:#?}", - place.ptr.assert_ptr().alloc_id, place_ptr.offset.bytes(), size.bytes(), + place.ptr.assert_ptr().alloc_id, + place_ptr.offset.bytes(), + size.bytes(), range.atomic_ops ); } @@ -896,14 +940,11 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { } Ok(()) } - } - /// Extra metadata associated with a thread. #[derive(Debug, Clone, Default)] struct ThreadExtraState { - /// The current vector index in use by the /// thread currently, this is set to None /// after the vector index has been re-used @@ -915,7 +956,7 @@ struct ThreadExtraState { /// diagnostics when reporting detected data /// races. thread_name: Option>, - + /// Thread termination vector clock, this /// is set on thread termination and is used /// for joining on threads since the vector_index @@ -928,7 +969,6 @@ struct ThreadExtraState { /// with each of the threads. #[derive(Debug, Clone)] pub struct GlobalState { - /// Set to true once the first additional /// thread has launched, due to the dependency /// between before and after a thread launch. @@ -966,7 +1006,7 @@ pub struct GlobalState { /// if the number of active threads reduces to 1 and then /// a join operation occures with the remaining main thread /// then multi-threaded execution may be disabled. - active_thread_count: Cell, + active_thread_count: Cell, /// This contains threads that have terminated, but not yet joined /// and so cannot become re-use candidates until a join operation @@ -977,7 +1017,6 @@ pub struct GlobalState { } impl GlobalState { - /// Create a new global state, setup with just thread-id=0 /// advanced to timestamp = 1. pub fn new() -> Self { @@ -989,7 +1028,7 @@ impl GlobalState { current_index: Cell::new(VectorIdx::new(0)), active_thread_count: Cell::new(1), reuse_candidates: RefCell::new(FxHashSet::default()), - terminated_threads: RefCell::new(FxHashMap::default()) + terminated_threads: RefCell::new(FxHashMap::default()), }; // Setup the main-thread since it is not explicitly created: @@ -997,17 +1036,15 @@ impl GlobalState { // the main-thread a name of "main". let index = global_state.vector_clocks.borrow_mut().push(ThreadClockSet::default()); global_state.vector_info.borrow_mut().push(ThreadId::new(0)); - global_state.thread_info.borrow_mut().push( - ThreadExtraState { - vector_index: Some(index), - thread_name: Some("main".to_string().into_boxed_str()), - termination_vector_clock: None - } - ); + global_state.thread_info.borrow_mut().push(ThreadExtraState { + vector_index: Some(index), + thread_name: Some("main".to_string().into_boxed_str()), + termination_vector_clock: None, + }); global_state } - + // Try to find vector index values that can potentially be re-used // by a new thread instead of a new vector index being created. fn find_vector_index_reuse_candidate(&self) -> Option { @@ -1015,10 +1052,9 @@ impl GlobalState { let vector_clocks = self.vector_clocks.borrow(); let vector_info = self.vector_info.borrow(); let terminated_threads = self.terminated_threads.borrow(); - for &candidate in reuse.iter() { + for &candidate in reuse.iter() { let target_timestamp = vector_clocks[candidate].clock[candidate]; if vector_clocks.iter_enumerated().all(|(clock_idx, clock)| { - // The thread happens before the clock, and hence cannot report // a data-race with this the candidate index. let no_data_race = clock.clock[candidate] >= target_timestamp; @@ -1026,20 +1062,19 @@ impl GlobalState { // The vector represents a thread that has terminated and hence cannot // report a data-race with the candidate index. let thread_id = vector_info[clock_idx]; - let vector_terminated = reuse.contains(&clock_idx) - || terminated_threads.contains_key(&thread_id); + let vector_terminated = + reuse.contains(&clock_idx) || terminated_threads.contains_key(&thread_id); // The vector index cannot report a race with the candidate index // and hence allows the candidate index to be re-used. no_data_race || vector_terminated }) { - // All vector clocks for each vector index are equal to // the target timestamp, and the thread is known to have // terminated, therefore this vector clock index cannot // report any more data-races. assert!(reuse.remove(&candidate)); - return Some(candidate) + return Some(candidate); } } None @@ -1065,10 +1100,7 @@ impl GlobalState { // Assign a vector index for the thread, attempting to re-use an old // vector index that can no longer report any data-races if possible. - let created_index = if let Some( - reuse_index - ) = self.find_vector_index_reuse_candidate() { - + let created_index = if let Some(reuse_index) = self.find_vector_index_reuse_candidate() { // Now re-configure the re-use candidate, increment the clock // for the new sync use of the vector. let mut vector_clocks = self.vector_clocks.borrow_mut(); @@ -1086,7 +1118,6 @@ impl GlobalState { reuse_index } else { - // No vector re-use candidates available, instead create // a new vector index. let mut vector_info = self.vector_info.borrow_mut(); @@ -1125,13 +1156,16 @@ impl GlobalState { let thread_info = self.thread_info.borrow(); // Load the vector clock of the current thread. - let current_index = thread_info[current_thread].vector_index + let current_index = thread_info[current_thread] + .vector_index .expect("Performed thread join on thread with no assigned vector"); let current = &mut clocks_vec[current_index]; // Load the associated vector clock for the terminated thread. - let join_clock = thread_info[join_thread].termination_vector_clock - .as_ref().expect("Joined with thread but thread has not terminated"); + let join_clock = thread_info[join_thread] + .termination_vector_clock + .as_ref() + .expect("Joined with thread but thread has not terminated"); // Pre increment clocks before atomic operation. current.increment_clock(current_index); @@ -1147,13 +1181,12 @@ impl GlobalState { // then test for potentially disabling multi-threaded execution. let active_threads = self.active_thread_count.get(); if active_threads == 1 { - // May potentially be able to disable multi-threaded execution. let current_clock = &clocks_vec[current_index]; - if clocks_vec.iter_enumerated().all(|(idx, clocks)| { - clocks.clock[idx] <= current_clock.clock[idx] - }) { - + if clocks_vec + .iter_enumerated() + .all(|(idx, clocks)| clocks.clock[idx] <= current_clock.clock[idx]) + { // The all thread termations happen-before the current clock // therefore no data-races can be reported until a new thread // is created, so disable multi-threaded execution. @@ -1180,7 +1213,7 @@ impl GlobalState { #[inline] pub fn thread_terminated(&self) { let current_index = self.current_index(); - + // Increment the clock to a unique termination timestamp. let mut vector_clocks = self.vector_clocks.borrow_mut(); let current_clocks = &mut vector_clocks[current_index]; @@ -1201,7 +1234,7 @@ impl GlobalState { // occurs. let mut termination = self.terminated_threads.borrow_mut(); termination.insert(current_thread, current_index); - + // Reduce the number of active threads, now that a thread has // terminated. let mut active_threads = self.active_thread_count.get(); @@ -1215,7 +1248,8 @@ impl GlobalState { #[inline] pub fn thread_set_active(&self, thread: ThreadId) { let thread_info = self.thread_info.borrow(); - let vector_idx = thread_info[thread].vector_index + let vector_idx = thread_info[thread] + .vector_index .expect("Setting thread active with no assigned vector"); self.current_index.set(vector_idx); } @@ -1231,7 +1265,6 @@ impl GlobalState { thread_info[thread].thread_name = Some(name); } - /// Attempt to perform a synchronized operation, this /// will perform no operation if multi-threading is /// not currently enabled. @@ -1240,7 +1273,8 @@ impl GlobalState { /// detection between any happens-before edges the /// operation may create. fn maybe_perform_sync_operation<'tcx>( - &self, op: impl FnOnce(VectorIdx, RefMut<'_,ThreadClockSet>) -> InterpResult<'tcx>, + &self, + op: impl FnOnce(VectorIdx, RefMut<'_, ThreadClockSet>) -> InterpResult<'tcx>, ) -> InterpResult<'tcx> { if self.multi_threaded.get() { let (index, mut clocks) = self.current_thread_state_mut(); @@ -1251,7 +1285,6 @@ impl GlobalState { } Ok(()) } - /// Internal utility to identify a thread stored internally /// returns the id and the name for better diagnostics. @@ -1266,7 +1299,6 @@ impl GlobalState { } } - /// Acquire a lock, express that the previous call of /// `validate_lock_release` must happen before this. pub fn validate_lock_acquire(&self, lock: &VClock, thread: ThreadId) { @@ -1300,7 +1332,8 @@ impl GlobalState { /// used by the thread. #[inline] fn load_thread_state_mut(&self, thread: ThreadId) -> (VectorIdx, RefMut<'_, ThreadClockSet>) { - let index = self.thread_info.borrow()[thread].vector_index + let index = self.thread_info.borrow()[thread] + .vector_index .expect("Loading thread state for thread with no assigned vector"); let ref_vector = self.vector_clocks.borrow_mut(); let clocks = RefMut::map(ref_vector, |vec| &mut vec[index]); diff --git a/src/vector_clock.rs b/src/vector_clock.rs index 110b278852d50..ddee98bcf624c 100644 --- a/src/vector_clock.rs +++ b/src/vector_clock.rs @@ -1,10 +1,13 @@ +use rustc_data_structures::fx::FxHashMap; +use rustc_index::vec::Idx; +use smallvec::SmallVec; use std::{ - fmt::{self, Debug}, cmp::Ordering, ops::Index, - convert::TryFrom, mem + cmp::Ordering, + convert::TryFrom, + fmt::{self, Debug}, + mem, + ops::Index, }; -use smallvec::SmallVec; -use rustc_index::vec::Idx; -use rustc_data_structures::fx::FxHashMap; /// A vector clock index, this is associated with a thread id /// but in some cases one vector index may be shared with @@ -13,18 +16,15 @@ use rustc_data_structures::fx::FxHashMap; pub struct VectorIdx(u32); impl VectorIdx { - #[inline(always)] pub fn to_u32(self) -> u32 { self.0 } pub const MAX_INDEX: VectorIdx = VectorIdx(u32::MAX); - } impl Idx for VectorIdx { - #[inline] fn new(idx: usize) -> Self { VectorIdx(u32::try_from(idx).unwrap()) @@ -34,16 +34,13 @@ impl Idx for VectorIdx { fn index(self) -> usize { usize::try_from(self.0).unwrap() } - } impl From for VectorIdx { - #[inline] fn from(id: u32) -> Self { Self(id) } - } /// A sparse mapping of vector index values to vector clocks, this @@ -52,7 +49,7 @@ impl From for VectorIdx { /// This is used to store the set of currently active release /// sequences at a given memory location, since RMW operations /// allow for multiple release sequences to be active at once -/// and to be collapsed back to one active release sequence +/// and to be collapsed back to one active release sequence /// once a non RMW atomic store operation occurs. /// An all zero vector is considered to be equal to no /// element stored internally since it will never be @@ -63,7 +60,6 @@ pub struct VSmallClockMap(VSmallClockMapInner); #[derive(Clone)] enum VSmallClockMapInner { - /// Zero or 1 vector elements, common /// case for the sparse set. /// The all zero vector clock is treated @@ -71,18 +67,15 @@ enum VSmallClockMapInner { Small(VectorIdx, VClock), /// Hash-map of vector clocks. - Large(FxHashMap) + Large(FxHashMap), } impl VSmallClockMap { - /// Remove all clock vectors from the map, setting them /// to the zero vector. pub fn clear(&mut self) { match &mut self.0 { - VSmallClockMapInner::Small(_, clock) => { - clock.set_zero_vector() - } + VSmallClockMapInner::Small(_, clock) => clock.set_zero_vector(), VSmallClockMapInner::Large(hash_map) => { hash_map.clear(); } @@ -95,12 +88,11 @@ impl VSmallClockMap { match &mut self.0 { VSmallClockMapInner::Small(small_idx, clock) => { if index != *small_idx { - // The zero-vector is considered to equal // the empty element. clock.set_zero_vector() } - }, + } VSmallClockMapInner::Large(hash_map) => { let value = hash_map.remove(&index).unwrap_or_default(); self.0 = VSmallClockMapInner::Small(index, value); @@ -114,23 +106,20 @@ impl VSmallClockMap { match &mut self.0 { VSmallClockMapInner::Small(small_idx, small_clock) => { if small_clock.is_zero_vector() { - *small_idx = index; small_clock.clone_from(clock); } else if !clock.is_zero_vector() { - // Convert to using the hash-map representation. let mut hash_map = FxHashMap::default(); hash_map.insert(*small_idx, mem::take(small_clock)); hash_map.insert(index, clock.clone()); self.0 = VSmallClockMapInner::Large(hash_map); } - }, - VSmallClockMapInner::Large(hash_map) => { + } + VSmallClockMapInner::Large(hash_map) => if !clock.is_zero_vector() { hash_map.insert(index, clock.clone()); - } - } + }, } } @@ -144,51 +133,39 @@ impl VSmallClockMap { } else { None } - }, - VSmallClockMapInner::Large(hash_map) => { - hash_map.get(&index) } + VSmallClockMapInner::Large(hash_map) => hash_map.get(&index), } } } impl Default for VSmallClockMap { - #[inline] fn default() -> Self { - VSmallClockMap( - VSmallClockMapInner::Small(VectorIdx::new(0), VClock::default()) - ) + VSmallClockMap(VSmallClockMapInner::Small(VectorIdx::new(0), VClock::default())) } - } impl Debug for VSmallClockMap { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { // Print the contents of the small vector clock set as the map // of vector index to vector clock that they represent. let mut map = f.debug_map(); match &self.0 { - VSmallClockMapInner::Small(small_idx, small_clock) => { + VSmallClockMapInner::Small(small_idx, small_clock) => if !small_clock.is_zero_vector() { map.entry(&small_idx, &small_clock); - } - }, - VSmallClockMapInner::Large(hash_map) => { + }, + VSmallClockMapInner::Large(hash_map) => for (idx, elem) in hash_map.iter() { map.entry(idx, elem); - } - } + }, } map.finish() } - } - impl PartialEq for VSmallClockMap { - fn eq(&self, other: &Self) -> bool { use VSmallClockMapInner::*; match (&self.0, &other.0) { @@ -201,9 +178,7 @@ impl PartialEq for VSmallClockMap { i1 == i2 && c1 == c2 } } - (Small(idx, clock), Large(hash_map)) | - (Large(hash_map), Small(idx, clock)) => { - + (Small(idx, clock), Large(hash_map)) | (Large(hash_map), Small(idx, clock)) => { if hash_map.len() == 0 { // Equal to the empty hash-map clock.is_zero_vector() @@ -215,18 +190,13 @@ impl PartialEq for VSmallClockMap { false } } - (Large(map1), Large(map2)) => { - map1 == map2 - } + (Large(map1), Large(map2)) => map1 == map2, } } - } impl Eq for VSmallClockMap {} - - /// The size of the vector-clock to store inline /// clock vectors larger than this will be stored on the heap const SMALL_VECTOR: usize = 4; @@ -249,7 +219,6 @@ pub type VTimestamp = u32; pub struct VClock(SmallVec<[VTimestamp; SMALL_VECTOR]>); impl VClock { - /// Create a new vector-clock containing all zeros except /// for a value at the given index pub fn new_with_index(index: VectorIdx, timestamp: VTimestamp) -> VClock { @@ -316,11 +285,9 @@ impl VClock { pub fn is_zero_vector(&self) -> bool { self.0.is_empty() } - } impl Clone for VClock { - fn clone(&self) -> Self { VClock(self.0.clone()) } @@ -334,13 +301,10 @@ impl Clone for VClock { self.0.clear(); self.0.extend_from_slice(source_slice); } - } impl PartialOrd for VClock { - fn partial_cmp(&self, other: &VClock) -> Option { - // Load the values as slices let lhs_slice = self.as_slice(); let rhs_slice = other.as_slice(); @@ -356,17 +320,19 @@ impl PartialOrd for VClock { let mut iter = lhs_slice.iter().zip(rhs_slice.iter()); let mut order = match iter.next() { Some((lhs, rhs)) => lhs.cmp(rhs), - None => Ordering::Equal + None => Ordering::Equal, }; for (l, r) in iter { match order { Ordering::Equal => order = l.cmp(r), - Ordering::Less => if l > r { - return None - }, - Ordering::Greater => if l < r { - return None - } + Ordering::Less => + if l > r { + return None; + }, + Ordering::Greater => + if l < r { + return None; + }, } } @@ -383,14 +349,14 @@ impl PartialOrd for VClock { // so the only valid values are Ordering::Less or None. Ordering::Less => match order { Ordering::Less | Ordering::Equal => Some(Ordering::Less), - Ordering::Greater => None - } + Ordering::Greater => None, + }, // Left has at least 1 element > than the implicit 0, // so the only valid values are Ordering::Greater or None. Ordering::Greater => match order { Ordering::Greater | Ordering::Equal => Some(Ordering::Greater), - Ordering::Less => None - } + Ordering::Less => None, + }, } } @@ -415,13 +381,13 @@ impl PartialOrd for VClock { let mut equal = l_len == r_len; for (&l, &r) in lhs_slice.iter().zip(rhs_slice.iter()) { if l > r { - return false + return false; } else if l < r { equal = false; } } !equal - } else { + } else { false } } @@ -469,7 +435,7 @@ impl PartialOrd for VClock { let mut equal = l_len == r_len; for (&l, &r) in lhs_slice.iter().zip(rhs_slice.iter()) { if l < r { - return false + return false; } else if l > r { equal = false; } @@ -501,28 +467,24 @@ impl PartialOrd for VClock { false } } - } impl Index for VClock { - type Output = VTimestamp; #[inline] fn index(&self, index: VectorIdx) -> &VTimestamp { - self.as_slice().get(index.to_u32() as usize).unwrap_or(&0) + self.as_slice().get(index.to_u32() as usize).unwrap_or(&0) } - } - /// Test vector clock ordering operations /// data-race detection is tested in the external /// test suite #[cfg(test)] mod tests { - use super::{VClock, VTimestamp, VectorIdx, VSmallClockMap}; + use super::{VClock, VSmallClockMap, VTimestamp, VectorIdx}; use std::cmp::Ordering; #[test] @@ -546,19 +508,43 @@ mod tests { assert_order(&[1], &[1], Some(Ordering::Equal)); assert_order(&[1], &[2], Some(Ordering::Less)); assert_order(&[2], &[1], Some(Ordering::Greater)); - assert_order(&[1], &[1,2], Some(Ordering::Less)); - assert_order(&[2], &[1,2], None); + assert_order(&[1], &[1, 2], Some(Ordering::Less)); + assert_order(&[2], &[1, 2], None); // Misc tests assert_order(&[400], &[0, 1], None); // Large test - assert_order(&[0,1,2,3,4,5,6,7,8,9,10], &[0,1,2,3,4,5,6,7,8,9,10,0,0,0], Some(Ordering::Equal)); - assert_order(&[0,1,2,3,4,5,6,7,8,9,10], &[0,1,2,3,4,5,6,7,8,9,10,0,1,0], Some(Ordering::Less)); - assert_order(&[0,1,2,3,4,5,6,7,8,9,11], &[0,1,2,3,4,5,6,7,8,9,10,0,0,0], Some(Ordering::Greater)); - assert_order(&[0,1,2,3,4,5,6,7,8,9,11], &[0,1,2,3,4,5,6,7,8,9,10,0,1,0], None); - assert_order(&[0,1,2,3,4,5,6,7,8,9,9 ], &[0,1,2,3,4,5,6,7,8,9,10,0,0,0], Some(Ordering::Less)); - assert_order(&[0,1,2,3,4,5,6,7,8,9,9 ], &[0,1,2,3,4,5,6,7,8,9,10,0,1,0], Some(Ordering::Less)); + assert_order( + &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10], + &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 0, 0, 0], + Some(Ordering::Equal), + ); + assert_order( + &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10], + &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 0, 1, 0], + Some(Ordering::Less), + ); + assert_order( + &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 11], + &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 0, 0, 0], + Some(Ordering::Greater), + ); + assert_order( + &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 11], + &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 0, 1, 0], + None, + ); + assert_order( + &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 9], + &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 0, 0, 0], + Some(Ordering::Less), + ); + assert_order( + &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 9], + &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 0, 1, 0], + Some(Ordering::Less), + ); } fn from_slice(mut slice: &[VTimestamp]) -> VClock { @@ -574,51 +560,81 @@ mod tests { //Test partial_cmp let compare = l.partial_cmp(&r); - assert_eq!(compare, o, "Invalid comparison\n l: {:?}\n r: {:?}",l,r); + assert_eq!(compare, o, "Invalid comparison\n l: {:?}\n r: {:?}", l, r); let alt_compare = r.partial_cmp(&l); - assert_eq!(alt_compare, o.map(Ordering::reverse), "Invalid alt comparison\n l: {:?}\n r: {:?}",l,r); + assert_eq!( + alt_compare, + o.map(Ordering::reverse), + "Invalid alt comparison\n l: {:?}\n r: {:?}", + l, + r + ); //Test operators with faster implementations assert_eq!( - matches!(compare,Some(Ordering::Less)), l < r, - "Invalid (<):\n l: {:?}\n r: {:?}",l,r + matches!(compare, Some(Ordering::Less)), + l < r, + "Invalid (<):\n l: {:?}\n r: {:?}", + l, + r ); assert_eq!( - matches!(compare,Some(Ordering::Less) | Some(Ordering::Equal)), l <= r, - "Invalid (<=):\n l: {:?}\n r: {:?}",l,r + matches!(compare, Some(Ordering::Less) | Some(Ordering::Equal)), + l <= r, + "Invalid (<=):\n l: {:?}\n r: {:?}", + l, + r ); assert_eq!( - matches!(compare,Some(Ordering::Greater)), l > r, - "Invalid (>):\n l: {:?}\n r: {:?}",l,r + matches!(compare, Some(Ordering::Greater)), + l > r, + "Invalid (>):\n l: {:?}\n r: {:?}", + l, + r ); assert_eq!( - matches!(compare,Some(Ordering::Greater) | Some(Ordering::Equal)), l >= r, - "Invalid (>=):\n l: {:?}\n r: {:?}",l,r + matches!(compare, Some(Ordering::Greater) | Some(Ordering::Equal)), + l >= r, + "Invalid (>=):\n l: {:?}\n r: {:?}", + l, + r ); assert_eq!( - matches!(alt_compare,Some(Ordering::Less)), r < l, - "Invalid alt (<):\n l: {:?}\n r: {:?}",l,r + matches!(alt_compare, Some(Ordering::Less)), + r < l, + "Invalid alt (<):\n l: {:?}\n r: {:?}", + l, + r ); assert_eq!( - matches!(alt_compare,Some(Ordering::Less) | Some(Ordering::Equal)), r <= l, - "Invalid alt (<=):\n l: {:?}\n r: {:?}",l,r + matches!(alt_compare, Some(Ordering::Less) | Some(Ordering::Equal)), + r <= l, + "Invalid alt (<=):\n l: {:?}\n r: {:?}", + l, + r ); assert_eq!( - matches!(alt_compare,Some(Ordering::Greater)), r > l, - "Invalid alt (>):\n l: {:?}\n r: {:?}",l,r + matches!(alt_compare, Some(Ordering::Greater)), + r > l, + "Invalid alt (>):\n l: {:?}\n r: {:?}", + l, + r ); assert_eq!( - matches!(alt_compare,Some(Ordering::Greater) | Some(Ordering::Equal)), r >= l, - "Invalid alt (>=):\n l: {:?}\n r: {:?}",l,r + matches!(alt_compare, Some(Ordering::Greater) | Some(Ordering::Equal)), + r >= l, + "Invalid alt (>=):\n l: {:?}\n r: {:?}", + l, + r ); } #[test] pub fn test_vclock_set() { let mut map = VSmallClockMap::default(); - let v1 = from_slice(&[3,0,1]); - let v2 = from_slice(&[4,2,3]); - let v3 = from_slice(&[4,8,3]); + let v1 = from_slice(&[3, 0, 1]); + let v2 = from_slice(&[4, 2, 3]); + let v3 = from_slice(&[4, 8, 3]); map.insert(VectorIdx(0), &v1); assert_eq!(map.get(VectorIdx(0)), Some(&v1)); map.insert(VectorIdx(5), &v2); @@ -641,5 +657,4 @@ mod tests { assert_eq!(map.get(VectorIdx(5)), None); assert_eq!(map.get(VectorIdx(53)), Some(&v3)); } - } From a37cfed062bd4106fb1462a0a1e13010307bd262 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 19 Nov 2020 09:21:03 +0100 Subject: [PATCH 2449/3747] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 3b96c994a7825..5d44fe9e4b837 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -12f0dba618e761c987142474435dff95ab177f3c +bf469eb6c20ccea05400a1942c70343f36705e1c From 4de113acba482ecee67a2098e9e1ba6068304ccc Mon Sep 17 00:00:00 2001 From: est31 Date: Sun, 15 Nov 2020 05:01:10 +0100 Subject: [PATCH 2450/3747] Normalize column numbers --- tests/run-pass/backtrace-std.rs | 2 +- tests/run-pass/backtrace-std.stderr | 28 ++++++++++++++-------------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/tests/run-pass/backtrace-std.rs b/tests/run-pass/backtrace-std.rs index 7a793e092a816..9b61aabab3b23 100644 --- a/tests/run-pass/backtrace-std.rs +++ b/tests/run-pass/backtrace-std.rs @@ -1,5 +1,5 @@ // normalize-stderr-test "at .*/(rust[^/]*|checkout)/library/" -> "at RUSTLIB/" -// normalize-stderr-test "RUSTLIB/(.*):\d+"-> "RUSTLIB/$1:LL" +// normalize-stderr-test "RUSTLIB/([^:]*):\d+:\d+"-> "RUSTLIB/$1:LL:CC" // normalize-stderr-test "::<.*>" -> "" // compile-flags: -Zmiri-disable-isolation diff --git a/tests/run-pass/backtrace-std.stderr b/tests/run-pass/backtrace-std.stderr index 45c46acc331c9..09f035b9724ee 100644 --- a/tests/run-pass/backtrace-std.stderr +++ b/tests/run-pass/backtrace-std.stderr @@ -1,28 +1,28 @@ 0: func_d - at $DIR/backtrace-std.rs:18 + at $DIR/backtrace-std.rs:18:45 1: func_c - at $DIR/backtrace-std.rs:17 + at $DIR/backtrace-std.rs:17:45 2: func_b - at $DIR/backtrace-std.rs:11 + at $DIR/backtrace-std.rs:11:48 3: func_a - at $DIR/backtrace-std.rs:10 + at $DIR/backtrace-std.rs:10:45 4: main - at $DIR/backtrace-std.rs:21 + at $DIR/backtrace-std.rs:21:19 5: >::call_once - shim(fn()) - at RUSTLIB/core/src/ops/function.rs:LL + at RUSTLIB/core/src/ops/function.rs:LL:CC 6: std::sys_common::backtrace::__rust_begin_short_backtrace - at RUSTLIB/std/src/sys_common/backtrace.rs:LL + at RUSTLIB/std/src/sys_common/backtrace.rs:LL:CC 7: std::rt::lang_start::{closure#0} - at RUSTLIB/std/src/rt.rs:LL + at RUSTLIB/std/src/rt.rs:LL:CC 8: std::ops::function::impls::call_once - at RUSTLIB/core/src/ops/function.rs:LL + at RUSTLIB/core/src/ops/function.rs:LL:CC 9: std::panicking::r#try::do_call - at RUSTLIB/std/src/panicking.rs:LL + at RUSTLIB/std/src/panicking.rs:LL:CC 10: std::panicking::r#try - at RUSTLIB/std/src/panicking.rs:LL + at RUSTLIB/std/src/panicking.rs:LL:CC 11: std::panic::catch_unwind - at RUSTLIB/std/src/panic.rs:LL + at RUSTLIB/std/src/panic.rs:LL:CC 12: std::rt::lang_start_internal - at RUSTLIB/std/src/rt.rs:LL + at RUSTLIB/std/src/rt.rs:LL:CC 13: std::rt::lang_start - at RUSTLIB/std/src/rt.rs:LL + at RUSTLIB/std/src/rt.rs:LL:CC From cdb7adb4b32168b79a44f332ceace67aee727c42 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Wed, 18 Nov 2020 23:15:32 +0100 Subject: [PATCH 2451/3747] Make weak syscalls in std work. std now looks up `getrandom` and `statx` with `dlsym` before attempting to use `syscall(SYS_.., ..)`. It also now passes all arguments as a machine-sized word, instead of their original types. --- src/shims/posix/linux/dlsym.rs | 2 ++ src/shims/posix/linux/foreign_items.rs | 6 +++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/shims/posix/linux/dlsym.rs b/src/shims/posix/linux/dlsym.rs index ca5cf3ffe8f34..2685a93726d8f 100644 --- a/src/shims/posix/linux/dlsym.rs +++ b/src/shims/posix/linux/dlsym.rs @@ -12,6 +12,8 @@ impl Dlsym { pub fn from_str(name: &str) -> InterpResult<'static, Option> { Ok(match &*name { "__pthread_get_minstack" => None, + "getrandom" => None, // std falls back to syscall(SYS_getrandom, ...) when this is NULL. + "statx" => None, // std falls back to syscall(SYS_statx, ...) when this is NULL. _ => throw_unsup_format!("unsupported Linux dlsym: {}", name), }) } diff --git a/src/shims/posix/linux/foreign_items.rs b/src/shims/posix/linux/foreign_items.rs index 04efa79b9d93f..21d765621f731 100644 --- a/src/shims/posix/linux/foreign_items.rs +++ b/src/shims/posix/linux/foreign_items.rs @@ -208,7 +208,11 @@ fn getrandom<'tcx>( // The only supported flags are GRND_RANDOM and GRND_NONBLOCK, // neither of which have any effect on our current PRNG. - this.read_scalar(flags)?.to_i32()?; + let flags = this.read_scalar(flags)?; + // Either `i32` or `isize` is fine. + if flags.to_machine_isize(this).is_err() { + flags.to_i32()?; + } this.gen_random(ptr, len)?; this.write_scalar(Scalar::from_machine_usize(len, this), dest)?; From 517728bf97b5be2f609a9c539c7fdade2c601555 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 19 Nov 2020 09:36:06 +0100 Subject: [PATCH 2452/3747] avoid fallback logic (and we do not need the flag value currently anyway) --- src/shims/posix/linux/foreign_items.rs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/shims/posix/linux/foreign_items.rs b/src/shims/posix/linux/foreign_items.rs index 21d765621f731..23dc02a6affd3 100644 --- a/src/shims/posix/linux/foreign_items.rs +++ b/src/shims/posix/linux/foreign_items.rs @@ -208,11 +208,9 @@ fn getrandom<'tcx>( // The only supported flags are GRND_RANDOM and GRND_NONBLOCK, // neither of which have any effect on our current PRNG. - let flags = this.read_scalar(flags)?; - // Either `i32` or `isize` is fine. - if flags.to_machine_isize(this).is_err() { - flags.to_i32()?; - } + let _flags = this.read_scalar(flags)?; + // FIXME: Check that this is an integer type of the right size. + // Currently, some callers pass i32 and some usize, is that even allowed? this.gen_random(ptr, len)?; this.write_scalar(Scalar::from_machine_usize(len, this), dest)?; From 697f6e36bd747fe0a2850324f39dadd1008e4592 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 20 Nov 2020 14:07:52 +0100 Subject: [PATCH 2453/3747] rustup --- rust-version | 2 +- src/shims/posix/fs.rs | 13 +++---------- src/shims/posix/linux/foreign_items.rs | 5 ++--- 3 files changed, 6 insertions(+), 14 deletions(-) diff --git a/rust-version b/rust-version index 5d44fe9e4b837..0260e9beab173 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -bf469eb6c20ccea05400a1942c70343f36705e1c +172acf8f61018df3719e42e633ffd62ebecaa1e7 diff --git a/src/shims/posix/fs.rs b/src/shims/posix/fs.rs index 50589ca322dbe..10f0c91097922 100644 --- a/src/shims/posix/fs.rs +++ b/src/shims/posix/fs.rs @@ -831,17 +831,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx }; let path = this.read_path_from_c_str(pathname_scalar)?.into_owned(); - // `flags` should be a `c_int` but the `syscall` function provides an `isize`. - let flags: i32 = - this.read_scalar(flags_op)?.to_machine_isize(&*this.tcx)?.try_into().map_err(|e| { - err_unsup_format!("failed to convert pointer sized operand to integer: {}", e) - })?; + // See for a discussion of argument sizes. + let flags = this.read_scalar(flags_op)?.to_i32()?; let empty_path_flag = flags & this.eval_libc("AT_EMPTY_PATH")?.to_i32()? != 0; - // `dirfd` should be a `c_int` but the `syscall` function provides an `isize`. - let dirfd: i32 = - this.read_scalar(dirfd_op)?.to_machine_isize(&*this.tcx)?.try_into().map_err(|e| { - err_unsup_format!("failed to convert pointer sized operand to integer: {}", e) - })?; + let dirfd = this.read_scalar(dirfd_op)?.to_i32()?; // We only support: // * interpreting `path` as an absolute directory, // * interpreting `path` as a path relative to `dirfd` when the latter is `AT_FDCWD`, or diff --git a/src/shims/posix/linux/foreign_items.rs b/src/shims/posix/linux/foreign_items.rs index 23dc02a6affd3..45afbd05efc25 100644 --- a/src/shims/posix/linux/foreign_items.rs +++ b/src/shims/posix/linux/foreign_items.rs @@ -208,9 +208,8 @@ fn getrandom<'tcx>( // The only supported flags are GRND_RANDOM and GRND_NONBLOCK, // neither of which have any effect on our current PRNG. - let _flags = this.read_scalar(flags)?; - // FIXME: Check that this is an integer type of the right size. - // Currently, some callers pass i32 and some usize, is that even allowed? + // See for a discussion of argument sizes. + let _flags = this.read_scalar(flags)?.to_i32(); this.gen_random(ptr, len)?; this.write_scalar(Scalar::from_machine_usize(len, this), dest)?; From 7a2c2f8dde970723bf83bae346965ad3a8198f99 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 22 Nov 2020 18:08:57 +0100 Subject: [PATCH 2454/3747] rustup; test sorting for provenance-correctness --- rust-version | 2 +- tests/run-pass/vec.rs | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 0260e9beab173..c3173f6245b68 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -172acf8f61018df3719e42e633ffd62ebecaa1e7 +828461b4b27c4a955587887936e54057efc5e2c1 diff --git a/tests/run-pass/vec.rs b/tests/run-pass/vec.rs index ad6c5363ac1f4..f243aa45a1a66 100644 --- a/tests/run-pass/vec.rs +++ b/tests/run-pass/vec.rs @@ -130,6 +130,12 @@ fn push_str_ptr_stable() { assert_eq!(format!("{}", hello), "hello"); } +fn sort() { + let mut v = vec![1; 20]; + v.push(0); + v.sort(); +} + fn main() { assert_eq!(vec_reallocate().len(), 5); @@ -154,4 +160,6 @@ fn main() { vec_extend_ptr_stable(); vec_truncate_ptr_stable(); push_str_ptr_stable(); + + sort(); } From 3268f56a97f2ac7fbcdf6f23e31445a29c529674 Mon Sep 17 00:00:00 2001 From: JCTyBlaidd Date: Sun, 22 Nov 2020 17:28:12 +0000 Subject: [PATCH 2455/3747] Fix review changes --- src/machine.rs | 2 +- src/shims/posix/linux/sync.rs | 8 ++--- src/sync.rs | 35 +++++++++++++++++-- src/vector_clock.rs | 2 +- .../data_race/relax_acquire_race.rs | 2 +- .../data_race/release_seq_race.rs | 2 +- tests/compile-fail/data_race/rmw_race.rs | 2 +- tests/run-pass/concurrency/data_race.rs | 6 ++-- 8 files changed, 43 insertions(+), 16 deletions(-) diff --git a/src/machine.rs b/src/machine.rs index 9612d9e191107..02c66915564d3 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -150,7 +150,7 @@ impl MemoryExtra { }; let data_race = if config.data_race_detector { Some(Rc::new(data_race::GlobalState::new())) - }else{ + } else { None }; MemoryExtra { diff --git a/src/shims/posix/linux/sync.rs b/src/shims/posix/linux/sync.rs index 78244ab7b8794..5243431194eba 100644 --- a/src/shims/posix/linux/sync.rs +++ b/src/shims/posix/linux/sync.rs @@ -85,12 +85,10 @@ pub fn futex<'tcx>( // with the expected value, and starting to sleep are performed // atomically and totally ordered with respect to other futex // operations on the same futex word." - // SeqCst is total order over all operations, so uses acquire, - // either are equal under the current implementation. - // FIXME: is Acquire correct or should some additional ordering constraints be observed? - // FIXME: use RMW or similar? + // SeqCst is total order over all operations. + // FIXME: check if this should be changed when weak memory orders are added. let futex_val = this.read_scalar_at_offset_atomic( - addr.into(), 0, this.machine.layouts.i32, AtomicReadOp::Acquire + addr.into(), 0, this.machine.layouts.i32, AtomicReadOp::SeqCst )?.to_i32()?; if val == futex_val { // The value still matches, so we block the trait make it wait for FUTEX_WAKE. diff --git a/src/sync.rs b/src/sync.rs index 828268c06ccf0..4d488565faf3e 100644 --- a/src/sync.rs +++ b/src/sync.rs @@ -61,7 +61,11 @@ struct Mutex { lock_count: usize, /// The queue of threads waiting for this mutex. queue: VecDeque, - /// Data race handle + /// Data race handle, this tracks the happens-before + /// relationship between each mutex access. It is + /// released to during unlock and acquired from during + /// locking, and therefore stores the clock of the last + /// thread to release this mutex. data_race: VClock } @@ -79,9 +83,24 @@ struct RwLock { writer_queue: VecDeque, /// The queue of reader threads waiting for this lock. reader_queue: VecDeque, - /// Data race handle for writers + /// Data race handle for writers, tracks the happens-before + /// ordering between each write access to a rwlock and is updated + /// after a sequence of concurrent readers to track the happens- + /// before ordering between the set of previous readers and + /// the current writer. + /// Contains the clock of the last thread to release a writer + /// lock or the joined clock of the set of last threads to release + /// shared reader locks. data_race: VClock, - /// Data race handle for readers + /// Data race handle for readers, this is temporary storage + /// for the combined happens-before ordering for between all + /// concurrent readers and the next writer, and the value + /// is stored to the main data_race variable once all + /// readers are finished. + /// Has to be stored separately since reader lock acquires + /// must load the clock of the last write and must not + /// add happens-before orderings between shared reader + /// locks. data_race_reader: VClock, } @@ -100,6 +119,11 @@ struct CondvarWaiter { #[derive(Default, Debug)] struct Condvar { waiters: VecDeque, + /// Tracks the happens-before relationship + /// between a cond-var signal and a cond-var + /// wait during a non-suprious signal event. + /// Contains the clock of the last thread to + /// perform a futex-signal. data_race: VClock, } @@ -107,6 +131,11 @@ struct Condvar { #[derive(Default, Debug)] struct Futex { waiters: VecDeque, + /// Tracks the happens-before relationship + /// between a futex-wake and a futex-wait + /// during a non-spurious wake event. + /// Contains the clock of the last thread to + /// perform a futex-wake. data_race: VClock, } diff --git a/src/vector_clock.rs b/src/vector_clock.rs index ddee98bcf624c..6840d7e6cb990 100644 --- a/src/vector_clock.rs +++ b/src/vector_clock.rs @@ -11,7 +11,7 @@ use std::{ /// A vector clock index, this is associated with a thread id /// but in some cases one vector index may be shared with -/// multiple thread ids id it safe to do so. +/// multiple thread ids if it safe to do so. #[derive(Clone, Copy, Debug, PartialOrd, Ord, PartialEq, Eq, Hash)] pub struct VectorIdx(u32); diff --git a/tests/compile-fail/data_race/relax_acquire_race.rs b/tests/compile-fail/data_race/relax_acquire_race.rs index f7d44c30b66ba..4b736e57208a2 100644 --- a/tests/compile-fail/data_race/relax_acquire_race.rs +++ b/tests/compile-fail/data_race/relax_acquire_race.rs @@ -31,7 +31,7 @@ pub fn main() { let j3 = spawn(move || { if SYNC.load(Ordering::Acquire) == 2 { *c.0 //~ ERROR Data race - }else{ + } else { 0 } }); diff --git a/tests/compile-fail/data_race/release_seq_race.rs b/tests/compile-fail/data_race/release_seq_race.rs index dc852cdb4d810..0278e9864353e 100644 --- a/tests/compile-fail/data_race/release_seq_race.rs +++ b/tests/compile-fail/data_race/release_seq_race.rs @@ -35,7 +35,7 @@ pub fn main() { sleep(Duration::from_millis(1000)); if SYNC.load(Ordering::Acquire) == 3 { *c.0 //~ ERROR Data race - }else{ + } else { 0 } }); diff --git a/tests/compile-fail/data_race/rmw_race.rs b/tests/compile-fail/data_race/rmw_race.rs index bebd01efa1718..c533f595f1602 100644 --- a/tests/compile-fail/data_race/rmw_race.rs +++ b/tests/compile-fail/data_race/rmw_race.rs @@ -32,7 +32,7 @@ pub fn main() { let j3 = spawn(move || { if SYNC.load(Ordering::Acquire) == 3 { *c.0 //~ ERROR Data race - }else{ + } else { 0 } }); diff --git a/tests/run-pass/concurrency/data_race.rs b/tests/run-pass/concurrency/data_race.rs index 75e56e8c8d2a1..64e90024ed49b 100644 --- a/tests/run-pass/concurrency/data_race.rs +++ b/tests/run-pass/concurrency/data_race.rs @@ -28,7 +28,7 @@ fn test_fence_sync() { if SYNC.load(Ordering::Relaxed) == 1 { fence(Ordering::Acquire); unsafe { *evil_ptr.0 } - }else{ + } else { 0 } }); @@ -77,7 +77,7 @@ pub fn test_rmw_no_block() { let j3 = spawn(move || { if SYNC.load(Ordering::Acquire) == 2 { *c.0 - }else{ + } else { 0 } }); @@ -104,7 +104,7 @@ pub fn test_release_no_block() { let j2 = spawn(move || { if SYNC.load(Ordering::Acquire) == 3 { *c.0 - }else{ + } else { 0 } }); From 55fc552d9900e2f53ad4302da9387da32d7bcf8d Mon Sep 17 00:00:00 2001 From: JCTyBlaidd Date: Fri, 27 Nov 2020 19:26:06 +0000 Subject: [PATCH 2456/3747] Apply review changes, incrementing the clocks twice is an unnecessary hold-over from earlier versions so fixed. --- src/data_race.rs | 40 +++++++++++++------ src/shims/posix/sync.rs | 35 +++++++++++----- src/shims/posix/thread.rs | 2 +- ..._race.rs => atomic_read_na_write_race1.rs} | 0 ...e_alt.rs => atomic_read_na_write_race2.rs} | 0 ..._race.rs => atomic_write_na_read_race1.rs} | 0 ...e_alt.rs => atomic_write_na_read_race2.rs} | 0 ...race.rs => atomic_write_na_write_race1.rs} | 0 ..._alt.rs => atomic_write_na_write_race2.rs} | 0 .../data_race/dangling_thread_async_race.rs | 6 +-- .../data_race/dangling_thread_race.rs | 6 +-- .../data_race/enable_after_join_to_main.rs | 4 +- .../data_race/relax_acquire_race.rs | 7 ++++ .../data_race/release_seq_race.rs | 8 ++++ tests/compile-fail/data_race/rmw_race.rs | 7 ++++ tests/run-pass/concurrency/data_race.stderr | 2 +- .../concurrency/disable_data_race_detector.rs | 2 +- .../disable_data_race_detector.stderr | 2 +- tests/run-pass/concurrency/linux-futex.stderr | 2 +- tests/run-pass/concurrency/simple.stderr | 2 +- tests/run-pass/concurrency/sync.stderr | 2 +- .../run-pass/concurrency/thread_locals.stderr | 2 +- .../run-pass/concurrency/tls_lib_drop.stderr | 2 +- tests/run-pass/libc.stderr | 2 +- tests/run-pass/panic/concurrent-panic.stderr | 2 +- 25 files changed, 95 insertions(+), 40 deletions(-) rename tests/compile-fail/data_race/{atomic_read_write_race.rs => atomic_read_na_write_race1.rs} (100%) rename tests/compile-fail/data_race/{atomic_read_write_race_alt.rs => atomic_read_na_write_race2.rs} (100%) rename tests/compile-fail/data_race/{atomic_write_read_race.rs => atomic_write_na_read_race1.rs} (100%) rename tests/compile-fail/data_race/{atomic_write_read_race_alt.rs => atomic_write_na_read_race2.rs} (100%) rename tests/compile-fail/data_race/{atomic_write_write_race.rs => atomic_write_na_write_race1.rs} (100%) rename tests/compile-fail/data_race/{atomic_write_write_race_alt.rs => atomic_write_na_write_race2.rs} (100%) diff --git a/src/data_race.rs b/src/data_race.rs index b9542f6e2d62c..3f70631d1362c 100644 --- a/src/data_race.rs +++ b/src/data_race.rs @@ -37,6 +37,24 @@ //! to a acquire load and a release store given the global sequentially consistent order //! of the schedule. //! +//! The timestamps used in the data-race detector assign each sequence of non-atomic operations +//! followed by a single atomic or concurrent operation a single timestamp. +//! Write, Read, Write, ThreadJoin will be represented by a single timestamp value on a thread +//! This is because extra increment operations between the operations in the sequence are not +//! required for accurate reporting of data-race values. +//! +//! If the timestamp was not incremented after the atomic operation, then data-races would not be detected: +//! Example - this should report a data-race but does not: +//! t1: (x,0), atomic[release A], t1=(x+1, 0 ), write(var B), +//! t2: (0,y) , atomic[acquire A], t2=(x+1, y+1), ,write(var B) +//! +//! The timestamp is not incremented before an atomic operation, since the result is indistinguishable +//! from the value not being incremented. +//! t: (x, 0), atomic[release _], (x + 1, 0) || (0, y), atomic[acquire _], (x, _) +//! vs t: (x, 0), atomic[release _], (x + 1, 0) || (0, y), atomic[acquire _], (x+1, _) +//! Both result in the sequence on thread x up to and including the atomic release as happening +//! before the acquire. +//! //! FIXME: //! currently we have our own local copy of the currently active thread index and names, this is due //! in part to the inability to access the current location of threads.active_thread inside the AllocExtra @@ -499,7 +517,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { } /// Perform an atomic compare and exchange at a given memory location - /// on success an atomic RMW operation is performed and on failure + /// On success an atomic RMW operation is performed and on failure /// only an atomic read occurs. fn atomic_compare_exchange_scalar( &mut self, @@ -1136,9 +1154,6 @@ impl GlobalState { // Now load the two clocks and configure the initial state. let (current, created) = vector_clocks.pick2_mut(current_index, created_index); - // Advance the current thread before the synchronized operation. - current.increment_clock(current_index); - // Join the created with current, since the current threads // previous actions happen-before the created thread. created.join_with(current); @@ -1167,14 +1182,12 @@ impl GlobalState { .as_ref() .expect("Joined with thread but thread has not terminated"); - // Pre increment clocks before atomic operation. - current.increment_clock(current_index); // The join thread happens-before the current thread // so update the current vector clock. current.clock.join(join_clock); - // Post increment clocks after atomic operation. + // Increment clocks after atomic operation. current.increment_clock(current_index); // Check the number of active threads, if the value is 1 @@ -1277,8 +1290,7 @@ impl GlobalState { op: impl FnOnce(VectorIdx, RefMut<'_, ThreadClockSet>) -> InterpResult<'tcx>, ) -> InterpResult<'tcx> { if self.multi_threaded.get() { - let (index, mut clocks) = self.current_thread_state_mut(); - clocks.increment_clock(index); + let (index, clocks) = self.current_thread_state_mut(); op(index, clocks)?; let (_, mut clocks) = self.current_thread_state_mut(); clocks.increment_clock(index); @@ -1303,16 +1315,18 @@ impl GlobalState { /// `validate_lock_release` must happen before this. pub fn validate_lock_acquire(&self, lock: &VClock, thread: ThreadId) { let (index, mut clocks) = self.load_thread_state_mut(thread); - clocks.increment_clock(index); clocks.clock.join(&lock); clocks.increment_clock(index); } /// Release a lock handle, express that this happens-before /// any subsequent calls to `validate_lock_acquire`. + /// For normal locks this should be equivalent to `validate_lock_release_shared` + /// since an acquire operation should have occured before, however + /// for futex & cond-var operations this is not the case and this + /// operation must be used. pub fn validate_lock_release(&self, lock: &mut VClock, thread: ThreadId) { let (index, mut clocks) = self.load_thread_state_mut(thread); - clocks.increment_clock(index); lock.clone_from(&clocks.clock); clocks.increment_clock(index); } @@ -1321,9 +1335,11 @@ impl GlobalState { /// any subsequent calls to `validate_lock_acquire` as well /// as any previous calls to this function after any /// `validate_lock_release` calls. + /// For normal locks this should be equivalent to `validate_lock_release` + /// this function only exists for joining over the set of concurrent readers + /// in a read-write lock and should not be used for anything else. pub fn validate_lock_release_shared(&self, lock: &mut VClock, thread: ThreadId) { let (index, mut clocks) = self.load_thread_state_mut(thread); - clocks.increment_clock(index); lock.join(&clocks.clock); clocks.increment_clock(index); } diff --git a/src/shims/posix/sync.rs b/src/shims/posix/sync.rs index 64308d06139f3..efa4412991948 100644 --- a/src/shims/posix/sync.rs +++ b/src/shims/posix/sync.rs @@ -62,9 +62,11 @@ fn mutex_get_kind<'mir, 'tcx: 'mir>( mutex_op: OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, ScalarMaybeUninit> { let offset = if ecx.pointer_size().bytes() == 8 { 16 } else { 12 }; + //FIXME: this has been made atomic to fix data-race reporting inside the internal + // mutex implementation, it may not need to be atomic. ecx.read_scalar_at_offset_atomic( mutex_op, offset, ecx.machine.layouts.i32, - AtomicReadOp::Acquire + AtomicReadOp::Relaxed ) } @@ -74,9 +76,11 @@ fn mutex_set_kind<'mir, 'tcx: 'mir>( kind: impl Into>, ) -> InterpResult<'tcx, ()> { let offset = if ecx.pointer_size().bytes() == 8 { 16 } else { 12 }; + //FIXME: this has been made atomic to fix data-race reporting inside the internal + // mutex implementation, it may not need to be atomic. ecx.write_scalar_at_offset_atomic( - mutex_op, offset, kind, ecx.machine.layouts.i32, - AtomicWriteOp::Release + mutex_op, offset, kind, ecx.machine.layouts.i32, + AtomicWriteOp::Relaxed ) } @@ -84,8 +88,11 @@ fn mutex_get_id<'mir, 'tcx: 'mir>( ecx: &MiriEvalContext<'mir, 'tcx>, mutex_op: OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, ScalarMaybeUninit> { + //FIXME: this has been made atomic to fix data-race reporting inside the internal + // mutex implementation, it may not need to be atomic. ecx.read_scalar_at_offset_atomic( - mutex_op, 4, ecx.machine.layouts.u32, AtomicReadOp::Acquire + mutex_op, 4, ecx.machine.layouts.u32, + AtomicReadOp::Relaxed ) } @@ -94,9 +101,11 @@ fn mutex_set_id<'mir, 'tcx: 'mir>( mutex_op: OpTy<'tcx, Tag>, id: impl Into>, ) -> InterpResult<'tcx, ()> { + //FIXME: this has been made atomic to fix data-race reporting inside the internal + // mutex implementation, it may not need to be atomic. ecx.write_scalar_at_offset_atomic( mutex_op, 4, id, ecx.machine.layouts.u32, - AtomicWriteOp::Release + AtomicWriteOp::Relaxed ) } @@ -126,10 +135,12 @@ fn mutex_get_or_create_id<'mir, 'tcx: 'mir>( fn rwlock_get_id<'mir, 'tcx: 'mir>( ecx: &MiriEvalContext<'mir, 'tcx>, rwlock_op: OpTy<'tcx, Tag>, + //FIXME: this has been made atomic to fix data-race reporting inside the internal + // rw-lock implementation, it may not need to be atomic. ) -> InterpResult<'tcx, ScalarMaybeUninit> { ecx.read_scalar_at_offset_atomic( rwlock_op, 4, ecx.machine.layouts.u32, - AtomicReadOp::Acquire + AtomicReadOp::Relaxed ) } @@ -138,9 +149,11 @@ fn rwlock_set_id<'mir, 'tcx: 'mir>( rwlock_op: OpTy<'tcx, Tag>, id: impl Into>, ) -> InterpResult<'tcx, ()> { + //FIXME: this has been made atomic to fix data-race reporting inside the internal + // rw-lock implementation, it may not need to be atomic. ecx.write_scalar_at_offset_atomic( rwlock_op, 4, id, ecx.machine.layouts.u32, - AtomicWriteOp::Release + AtomicWriteOp::Relaxed ) } @@ -194,9 +207,11 @@ fn cond_get_id<'mir, 'tcx: 'mir>( ecx: &MiriEvalContext<'mir, 'tcx>, cond_op: OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, ScalarMaybeUninit> { + //FIXME: this has been made atomic to fix data-race reporting inside the internal + // cond-var implementation, it may not need to be atomic. ecx.read_scalar_at_offset_atomic( cond_op, 4, ecx.machine.layouts.u32, - AtomicReadOp::Acquire + AtomicReadOp::Relaxed ) } @@ -205,9 +220,11 @@ fn cond_set_id<'mir, 'tcx: 'mir>( cond_op: OpTy<'tcx, Tag>, id: impl Into>, ) -> InterpResult<'tcx, ()> { + //FIXME: this has been made atomic to fix data-race reporting inside the internal + // cond-var implementation, it may not need to be atomic. ecx.write_scalar_at_offset_atomic( cond_op, 4, id, ecx.machine.layouts.u32, - AtomicWriteOp::Release + AtomicWriteOp::Relaxed ) } diff --git a/src/shims/posix/thread.rs b/src/shims/posix/thread.rs index 847d083bfa9f7..0ea20cdff6cb3 100644 --- a/src/shims/posix/thread.rs +++ b/src/shims/posix/thread.rs @@ -15,7 +15,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); this.tcx.sess.warn( - "thread support is experimental, no weak memory effects are currently emulated.", + "thread support is experimental and incomplete: weak memory effects are not emulated." ); // Create the new thread diff --git a/tests/compile-fail/data_race/atomic_read_write_race.rs b/tests/compile-fail/data_race/atomic_read_na_write_race1.rs similarity index 100% rename from tests/compile-fail/data_race/atomic_read_write_race.rs rename to tests/compile-fail/data_race/atomic_read_na_write_race1.rs diff --git a/tests/compile-fail/data_race/atomic_read_write_race_alt.rs b/tests/compile-fail/data_race/atomic_read_na_write_race2.rs similarity index 100% rename from tests/compile-fail/data_race/atomic_read_write_race_alt.rs rename to tests/compile-fail/data_race/atomic_read_na_write_race2.rs diff --git a/tests/compile-fail/data_race/atomic_write_read_race.rs b/tests/compile-fail/data_race/atomic_write_na_read_race1.rs similarity index 100% rename from tests/compile-fail/data_race/atomic_write_read_race.rs rename to tests/compile-fail/data_race/atomic_write_na_read_race1.rs diff --git a/tests/compile-fail/data_race/atomic_write_read_race_alt.rs b/tests/compile-fail/data_race/atomic_write_na_read_race2.rs similarity index 100% rename from tests/compile-fail/data_race/atomic_write_read_race_alt.rs rename to tests/compile-fail/data_race/atomic_write_na_read_race2.rs diff --git a/tests/compile-fail/data_race/atomic_write_write_race.rs b/tests/compile-fail/data_race/atomic_write_na_write_race1.rs similarity index 100% rename from tests/compile-fail/data_race/atomic_write_write_race.rs rename to tests/compile-fail/data_race/atomic_write_na_write_race1.rs diff --git a/tests/compile-fail/data_race/atomic_write_write_race_alt.rs b/tests/compile-fail/data_race/atomic_write_na_write_race2.rs similarity index 100% rename from tests/compile-fail/data_race/atomic_write_write_race_alt.rs rename to tests/compile-fail/data_race/atomic_write_na_write_race2.rs diff --git a/tests/compile-fail/data_race/dangling_thread_async_race.rs b/tests/compile-fail/data_race/dangling_thread_async_race.rs index 6af5706835e36..d8b5d82f83048 100644 --- a/tests/compile-fail/data_race/dangling_thread_async_race.rs +++ b/tests/compile-fail/data_race/dangling_thread_async_race.rs @@ -29,9 +29,9 @@ fn main() { sleep(Duration::from_millis(100)); // Spawn and immediately join a thread - // to execute the join code-path - // and ensure that data-race detection - // remains enabled + // to execute the join code-path + // and ensure that data-race detection + // remains enabled nevertheless. spawn(|| ()).join().unwrap(); let join2 = unsafe { diff --git a/tests/compile-fail/data_race/dangling_thread_race.rs b/tests/compile-fail/data_race/dangling_thread_race.rs index c37f303bbab27..172b05bd4f0bb 100644 --- a/tests/compile-fail/data_race/dangling_thread_race.rs +++ b/tests/compile-fail/data_race/dangling_thread_race.rs @@ -29,9 +29,9 @@ fn main() { sleep(Duration::from_millis(100)); // Spawn and immediately join a thread - // to execute the join code-path - // and ensure that data-race detection - // remains enabled + // to execute the join code-path + // and ensure that data-race detection + // remains enabled nevertheless. spawn(|| ()).join().unwrap(); diff --git a/tests/compile-fail/data_race/enable_after_join_to_main.rs b/tests/compile-fail/data_race/enable_after_join_to_main.rs index fba7ba4841ccd..c294317771379 100644 --- a/tests/compile-fail/data_race/enable_after_join_to_main.rs +++ b/tests/compile-fail/data_race/enable_after_join_to_main.rs @@ -9,7 +9,7 @@ unsafe impl Send for EvilSend {} unsafe impl Sync for EvilSend {} pub fn main() { - // Enable and the join with multiple threads + // Enable and then join with multiple threads. let t1 = spawn(|| ()); let t2 = spawn(|| ()); let t3 = spawn(|| ()); @@ -19,7 +19,7 @@ pub fn main() { t3.join().unwrap(); t4.join().unwrap(); - // Perform write-write data race detection + // Perform write-write data race detection. let mut a = 0u32; let b = &mut a as *mut u32; let c = EvilSend(b); diff --git a/tests/compile-fail/data_race/relax_acquire_race.rs b/tests/compile-fail/data_race/relax_acquire_race.rs index 4b736e57208a2..2ae0aacbcf776 100644 --- a/tests/compile-fail/data_race/relax_acquire_race.rs +++ b/tests/compile-fail/data_race/relax_acquire_race.rs @@ -16,6 +16,13 @@ pub fn main() { let b = &mut a as *mut u32; let c = EvilSend(b); + // Note: this is scheduler-dependent + // the operations need to occur in + // order: + // 1. store release : 1 + // 2. load acquire : 1 + // 3. store relaxed : 2 + // 4. load acquire : 2 unsafe { let j1 = spawn(move || { *c.0 = 1; diff --git a/tests/compile-fail/data_race/release_seq_race.rs b/tests/compile-fail/data_race/release_seq_race.rs index 0278e9864353e..59263cb712042 100644 --- a/tests/compile-fail/data_race/release_seq_race.rs +++ b/tests/compile-fail/data_race/release_seq_race.rs @@ -18,6 +18,14 @@ pub fn main() { let b = &mut a as *mut u32; let c = EvilSend(b); + // Note: this is scheduler-dependent + // the operations need to occur in + // order, the sleep operations currently + // force the desired ordering: + // 1. store release : 1 + // 2. store relaxed : 2 + // 3. store relaxed : 3 + // 4. load acquire : 3 unsafe { let j1 = spawn(move || { *c.0 = 1; diff --git a/tests/compile-fail/data_race/rmw_race.rs b/tests/compile-fail/data_race/rmw_race.rs index c533f595f1602..e523f8b374cc2 100644 --- a/tests/compile-fail/data_race/rmw_race.rs +++ b/tests/compile-fail/data_race/rmw_race.rs @@ -16,6 +16,13 @@ pub fn main() { let b = &mut a as *mut u32; let c = EvilSend(b); + // Note: this is scheduler-dependent + // the operations need to occur in + // order: + // 1. store release : 1 + // 2. RMW relaxed : 1 -> 2 + // 3. store relaxed : 3 + // 4. load acquire : 3 unsafe { let j1 = spawn(move || { *c.0 = 1; diff --git a/tests/run-pass/concurrency/data_race.stderr b/tests/run-pass/concurrency/data_race.stderr index 7ba8087a9b4bc..03676519d4f1c 100644 --- a/tests/run-pass/concurrency/data_race.stderr +++ b/tests/run-pass/concurrency/data_race.stderr @@ -1,2 +1,2 @@ -warning: thread support is experimental, no weak memory effects are currently emulated. +warning: thread support is experimental and incomplete: weak memory effects are not emulated. diff --git a/tests/run-pass/concurrency/disable_data_race_detector.rs b/tests/run-pass/concurrency/disable_data_race_detector.rs index e47a2079c205d..8b2d180f11d4a 100644 --- a/tests/run-pass/concurrency/disable_data_race_detector.rs +++ b/tests/run-pass/concurrency/disable_data_race_detector.rs @@ -19,7 +19,7 @@ pub fn main() { }); let j2 = spawn(move || { - *c.0 = 64; //~ ERROR Data race + *c.0 = 64; //~ ERROR Data race (but not detected as the detector is disabled) }); j1.join().unwrap(); diff --git a/tests/run-pass/concurrency/disable_data_race_detector.stderr b/tests/run-pass/concurrency/disable_data_race_detector.stderr index 7ba8087a9b4bc..03676519d4f1c 100644 --- a/tests/run-pass/concurrency/disable_data_race_detector.stderr +++ b/tests/run-pass/concurrency/disable_data_race_detector.stderr @@ -1,2 +1,2 @@ -warning: thread support is experimental, no weak memory effects are currently emulated. +warning: thread support is experimental and incomplete: weak memory effects are not emulated. diff --git a/tests/run-pass/concurrency/linux-futex.stderr b/tests/run-pass/concurrency/linux-futex.stderr index 7ba8087a9b4bc..03676519d4f1c 100644 --- a/tests/run-pass/concurrency/linux-futex.stderr +++ b/tests/run-pass/concurrency/linux-futex.stderr @@ -1,2 +1,2 @@ -warning: thread support is experimental, no weak memory effects are currently emulated. +warning: thread support is experimental and incomplete: weak memory effects are not emulated. diff --git a/tests/run-pass/concurrency/simple.stderr b/tests/run-pass/concurrency/simple.stderr index 24444fdc17c17..f46b1442d749f 100644 --- a/tests/run-pass/concurrency/simple.stderr +++ b/tests/run-pass/concurrency/simple.stderr @@ -1,4 +1,4 @@ -warning: thread support is experimental, no weak memory effects are currently emulated. +warning: thread support is experimental and incomplete: weak memory effects are not emulated. thread '' panicked at 'Hello!', $DIR/simple.rs:54:9 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace diff --git a/tests/run-pass/concurrency/sync.stderr b/tests/run-pass/concurrency/sync.stderr index 7ba8087a9b4bc..03676519d4f1c 100644 --- a/tests/run-pass/concurrency/sync.stderr +++ b/tests/run-pass/concurrency/sync.stderr @@ -1,2 +1,2 @@ -warning: thread support is experimental, no weak memory effects are currently emulated. +warning: thread support is experimental and incomplete: weak memory effects are not emulated. diff --git a/tests/run-pass/concurrency/thread_locals.stderr b/tests/run-pass/concurrency/thread_locals.stderr index 7ba8087a9b4bc..03676519d4f1c 100644 --- a/tests/run-pass/concurrency/thread_locals.stderr +++ b/tests/run-pass/concurrency/thread_locals.stderr @@ -1,2 +1,2 @@ -warning: thread support is experimental, no weak memory effects are currently emulated. +warning: thread support is experimental and incomplete: weak memory effects are not emulated. diff --git a/tests/run-pass/concurrency/tls_lib_drop.stderr b/tests/run-pass/concurrency/tls_lib_drop.stderr index 7ba8087a9b4bc..03676519d4f1c 100644 --- a/tests/run-pass/concurrency/tls_lib_drop.stderr +++ b/tests/run-pass/concurrency/tls_lib_drop.stderr @@ -1,2 +1,2 @@ -warning: thread support is experimental, no weak memory effects are currently emulated. +warning: thread support is experimental and incomplete: weak memory effects are not emulated. diff --git a/tests/run-pass/libc.stderr b/tests/run-pass/libc.stderr index 7ba8087a9b4bc..03676519d4f1c 100644 --- a/tests/run-pass/libc.stderr +++ b/tests/run-pass/libc.stderr @@ -1,2 +1,2 @@ -warning: thread support is experimental, no weak memory effects are currently emulated. +warning: thread support is experimental and incomplete: weak memory effects are not emulated. diff --git a/tests/run-pass/panic/concurrent-panic.stderr b/tests/run-pass/panic/concurrent-panic.stderr index 885385a8dd937..1ee688c1d32cc 100644 --- a/tests/run-pass/panic/concurrent-panic.stderr +++ b/tests/run-pass/panic/concurrent-panic.stderr @@ -1,4 +1,4 @@ -warning: thread support is experimental, no weak memory effects are currently emulated. +warning: thread support is experimental and incomplete: weak memory effects are not emulated. Thread 1 starting, will block on mutex Thread 1 reported it has started From 6c5722933e5233b4b64134680baae1f48e1e47ea Mon Sep 17 00:00:00 2001 From: JCTyBlaidd Date: Sat, 28 Nov 2020 17:17:07 +0000 Subject: [PATCH 2457/3747] Fix typos - looked into the papers handling of timestamps, after looking into it again, it seems the paper only increments the timestamp after release operations, so changed to approximation of that implementation. --- src/data_race.rs | 56 +++++++++++++++++++---------------------- src/shims/posix/sync.rs | 16 ------------ 2 files changed, 26 insertions(+), 46 deletions(-) diff --git a/src/data_race.rs b/src/data_race.rs index 3f70631d1362c..49332721fcbd1 100644 --- a/src/data_race.rs +++ b/src/data_race.rs @@ -39,21 +39,14 @@ //! //! The timestamps used in the data-race detector assign each sequence of non-atomic operations //! followed by a single atomic or concurrent operation a single timestamp. -//! Write, Read, Write, ThreadJoin will be represented by a single timestamp value on a thread +//! Write, Read, Write, ThreadJoin will be represented by a single timestamp value on a thread. //! This is because extra increment operations between the operations in the sequence are not //! required for accurate reporting of data-race values. //! -//! If the timestamp was not incremented after the atomic operation, then data-races would not be detected: -//! Example - this should report a data-race but does not: -//! t1: (x,0), atomic[release A], t1=(x+1, 0 ), write(var B), -//! t2: (0,y) , atomic[acquire A], t2=(x+1, y+1), ,write(var B) -//! -//! The timestamp is not incremented before an atomic operation, since the result is indistinguishable -//! from the value not being incremented. -//! t: (x, 0), atomic[release _], (x + 1, 0) || (0, y), atomic[acquire _], (x, _) -//! vs t: (x, 0), atomic[release _], (x + 1, 0) || (0, y), atomic[acquire _], (x+1, _) -//! Both result in the sequence on thread x up to and including the atomic release as happening -//! before the acquire. +//! As per the paper a threads timestamp is only incremented after a release operation is performed +//! so some atomic operations that only perform acquires do not increment the timestamp, due to shared +//! code some atomic operations may increment the timestamp when not necessary but this has no effect +//! on the data-race detection code. //! //! FIXME: //! currently we have our own local copy of the currently active thread index and names, this is due @@ -516,7 +509,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { Ok(old) } - /// Perform an atomic compare and exchange at a given memory location + /// Perform an atomic compare and exchange at a given memory location. /// On success an atomic RMW operation is performed and on failure /// only an atomic read occurs. fn atomic_compare_exchange_scalar( @@ -640,7 +633,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { // Either Release | AcqRel | SeqCst clocks.apply_release_fence(); } - Ok(()) + + // Increment timestamp if hase release semantics + Ok(atomic != AtomicFenceOp::Acquire) }) } else { Ok(()) @@ -651,9 +646,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { /// Vector clock metadata for a logical memory allocation. #[derive(Debug, Clone)] pub struct VClockAlloc { - /// Range of Vector clocks, this gives each byte a potentially - /// unqiue set of vector clocks, but merges identical information - /// together for improved efficiency. + /// Assigning each byte a MemoryCellClocks. alloc_ranges: RefCell>, // Pointer to global state. @@ -935,10 +928,12 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { true, place_ptr, size, - ); + ).map(|_| true); } } - Ok(()) + + // This conservatively assumes all operations have release semantics + Ok(true) })?; // Log changes to atomic memory. @@ -1159,6 +1154,7 @@ impl GlobalState { created.join_with(current); // Advance both threads after the synchronized operation. + // Both operations are considered to have release semantics. current.increment_clock(current_index); created.increment_clock(created_index); } @@ -1185,11 +1181,9 @@ impl GlobalState { // The join thread happens-before the current thread // so update the current vector clock. + // Is not a release operation so the clock is not incremented. current.clock.join(join_clock); - // Increment clocks after atomic operation. - current.increment_clock(current_index); - // Check the number of active threads, if the value is 1 // then test for potentially disabling multi-threaded execution. let active_threads = self.active_thread_count.get(); @@ -1287,13 +1281,14 @@ impl GlobalState { /// operation may create. fn maybe_perform_sync_operation<'tcx>( &self, - op: impl FnOnce(VectorIdx, RefMut<'_, ThreadClockSet>) -> InterpResult<'tcx>, + op: impl FnOnce(VectorIdx, RefMut<'_, ThreadClockSet>) -> InterpResult<'tcx, bool>, ) -> InterpResult<'tcx> { if self.multi_threaded.get() { let (index, clocks) = self.current_thread_state_mut(); - op(index, clocks)?; - let (_, mut clocks) = self.current_thread_state_mut(); - clocks.increment_clock(index); + if op(index, clocks)? { + let (_, mut clocks) = self.current_thread_state_mut(); + clocks.increment_clock(index); + } } Ok(()) } @@ -1313,10 +1308,11 @@ impl GlobalState { /// Acquire a lock, express that the previous call of /// `validate_lock_release` must happen before this. + /// As this is an acquire operation, the thread timestamp is not + /// incremented. pub fn validate_lock_acquire(&self, lock: &VClock, thread: ThreadId) { - let (index, mut clocks) = self.load_thread_state_mut(thread); + let (_, mut clocks) = self.load_thread_state_mut(thread); clocks.clock.join(&lock); - clocks.increment_clock(index); } /// Release a lock handle, express that this happens-before @@ -1335,8 +1331,8 @@ impl GlobalState { /// any subsequent calls to `validate_lock_acquire` as well /// as any previous calls to this function after any /// `validate_lock_release` calls. - /// For normal locks this should be equivalent to `validate_lock_release` - /// this function only exists for joining over the set of concurrent readers + /// For normal locks this should be equivalent to `validate_lock_release`. + /// This function only exists for joining over the set of concurrent readers /// in a read-write lock and should not be used for anything else. pub fn validate_lock_release_shared(&self, lock: &mut VClock, thread: ThreadId) { let (index, mut clocks) = self.load_thread_state_mut(thread); diff --git a/src/shims/posix/sync.rs b/src/shims/posix/sync.rs index efa4412991948..868c72289a1a0 100644 --- a/src/shims/posix/sync.rs +++ b/src/shims/posix/sync.rs @@ -62,8 +62,6 @@ fn mutex_get_kind<'mir, 'tcx: 'mir>( mutex_op: OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, ScalarMaybeUninit> { let offset = if ecx.pointer_size().bytes() == 8 { 16 } else { 12 }; - //FIXME: this has been made atomic to fix data-race reporting inside the internal - // mutex implementation, it may not need to be atomic. ecx.read_scalar_at_offset_atomic( mutex_op, offset, ecx.machine.layouts.i32, AtomicReadOp::Relaxed @@ -76,8 +74,6 @@ fn mutex_set_kind<'mir, 'tcx: 'mir>( kind: impl Into>, ) -> InterpResult<'tcx, ()> { let offset = if ecx.pointer_size().bytes() == 8 { 16 } else { 12 }; - //FIXME: this has been made atomic to fix data-race reporting inside the internal - // mutex implementation, it may not need to be atomic. ecx.write_scalar_at_offset_atomic( mutex_op, offset, kind, ecx.machine.layouts.i32, AtomicWriteOp::Relaxed @@ -88,8 +84,6 @@ fn mutex_get_id<'mir, 'tcx: 'mir>( ecx: &MiriEvalContext<'mir, 'tcx>, mutex_op: OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, ScalarMaybeUninit> { - //FIXME: this has been made atomic to fix data-race reporting inside the internal - // mutex implementation, it may not need to be atomic. ecx.read_scalar_at_offset_atomic( mutex_op, 4, ecx.machine.layouts.u32, AtomicReadOp::Relaxed @@ -101,8 +95,6 @@ fn mutex_set_id<'mir, 'tcx: 'mir>( mutex_op: OpTy<'tcx, Tag>, id: impl Into>, ) -> InterpResult<'tcx, ()> { - //FIXME: this has been made atomic to fix data-race reporting inside the internal - // mutex implementation, it may not need to be atomic. ecx.write_scalar_at_offset_atomic( mutex_op, 4, id, ecx.machine.layouts.u32, AtomicWriteOp::Relaxed @@ -135,8 +127,6 @@ fn mutex_get_or_create_id<'mir, 'tcx: 'mir>( fn rwlock_get_id<'mir, 'tcx: 'mir>( ecx: &MiriEvalContext<'mir, 'tcx>, rwlock_op: OpTy<'tcx, Tag>, - //FIXME: this has been made atomic to fix data-race reporting inside the internal - // rw-lock implementation, it may not need to be atomic. ) -> InterpResult<'tcx, ScalarMaybeUninit> { ecx.read_scalar_at_offset_atomic( rwlock_op, 4, ecx.machine.layouts.u32, @@ -149,8 +139,6 @@ fn rwlock_set_id<'mir, 'tcx: 'mir>( rwlock_op: OpTy<'tcx, Tag>, id: impl Into>, ) -> InterpResult<'tcx, ()> { - //FIXME: this has been made atomic to fix data-race reporting inside the internal - // rw-lock implementation, it may not need to be atomic. ecx.write_scalar_at_offset_atomic( rwlock_op, 4, id, ecx.machine.layouts.u32, AtomicWriteOp::Relaxed @@ -207,8 +195,6 @@ fn cond_get_id<'mir, 'tcx: 'mir>( ecx: &MiriEvalContext<'mir, 'tcx>, cond_op: OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, ScalarMaybeUninit> { - //FIXME: this has been made atomic to fix data-race reporting inside the internal - // cond-var implementation, it may not need to be atomic. ecx.read_scalar_at_offset_atomic( cond_op, 4, ecx.machine.layouts.u32, AtomicReadOp::Relaxed @@ -220,8 +206,6 @@ fn cond_set_id<'mir, 'tcx: 'mir>( cond_op: OpTy<'tcx, Tag>, id: impl Into>, ) -> InterpResult<'tcx, ()> { - //FIXME: this has been made atomic to fix data-race reporting inside the internal - // cond-var implementation, it may not need to be atomic. ecx.write_scalar_at_offset_atomic( cond_op, 4, id, ecx.machine.layouts.u32, AtomicWriteOp::Relaxed From cbb695f782dceca959661e9c57d7aeb120cbc1d8 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 29 Nov 2020 19:43:44 +0100 Subject: [PATCH 2458/3747] fix some typos --- src/data_race.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/data_race.rs b/src/data_race.rs index 49332721fcbd1..aca735e6f2220 100644 --- a/src/data_race.rs +++ b/src/data_race.rs @@ -44,7 +44,7 @@ //! required for accurate reporting of data-race values. //! //! As per the paper a threads timestamp is only incremented after a release operation is performed -//! so some atomic operations that only perform acquires do not increment the timestamp, due to shared +//! so some atomic operations that only perform acquires do not increment the timestamp. Due to shared //! code some atomic operations may increment the timestamp when not necessary but this has no effect //! on the data-race detection code. //! @@ -634,7 +634,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { clocks.apply_release_fence(); } - // Increment timestamp if hase release semantics + // Increment timestamp in case of release semantics. Ok(atomic != AtomicFenceOp::Acquire) }) } else { From d697de7538c2ec33968663ab4ed8756bfcc17c6e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 29 Nov 2020 20:54:56 +0100 Subject: [PATCH 2459/3747] update README --- README.md | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 578ca0251c5e4..02a64b3d5f7dc 100644 --- a/README.md +++ b/README.md @@ -43,16 +43,15 @@ in your program, and cannot run all programs: still run fine in Miri -- but might break (including causing UB) on different compiler versions or different platforms. * Program execution is non-deterministic when it depends, for example, on where - exactly in memory allocations end up. Miri tests one of many possible - executions of your program. If your code is sensitive to allocation base - addresses or other non-deterministic data, try running Miri with different - values for `-Zmiri-seed` to test different executions. + exactly in memory allocations end up, or on the exact interleaving of + concurrent threads. Miri tests one of many possible executions of your + program. You can alleviate this to some extend by running Miri with different + values for `-Zmiri-seed`, but that will still by far not explore all possible + executions. * Miri runs the program as a platform-independent interpreter, so the program has no access to most platform-specific APIs or FFI. A few APIs have been implemented (such as printing to stdout) but most have not: for example, Miri currently does not support SIMD or networking. -* Miri currently does not check for data-races and most other concurrency-related - issues. [rust]: https://www.rust-lang.org/ [mir]: https://github.com/rust-lang/rfcs/blob/master/text/1211-mir.md From 6145709bfc5b0a298d957a7f705a3c64d63421a5 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 29 Nov 2020 21:00:50 +0100 Subject: [PATCH 2460/3747] remove miri-rustc-tests --- Cargo.toml | 9 -- rust-version | 2 +- src/bin/miri-rustc-tests.rs | 260 ------------------------------------ 3 files changed, 1 insertion(+), 270 deletions(-) delete mode 100644 src/bin/miri-rustc-tests.rs diff --git a/Cargo.toml b/Cargo.toml index 4413dab321e72..7580d140b55f7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,12 +17,6 @@ name = "miri" test = false # we have no unit tests doctest = false # and no doc tests -[[bin]] -name = "miri-rustc-tests" -test = false # we have no unit tests -doctest = false # and no doc tests -required-features = ["rustc_tests"] - [dependencies] getrandom = { version = "0.2", features = ["std"] } env_logger = "0.7.1" @@ -46,6 +40,3 @@ libc = "0.2" compiletest_rs = { version = "0.5", features = ["tmp"] } rustc_version = "0.2.3" colored = "2" - -[features] -rustc_tests = [] diff --git a/rust-version b/rust-version index c3173f6245b68..485cc2dd4b9f7 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -828461b4b27c4a955587887936e54057efc5e2c1 +88b81970ba7a989a728b32039dd075dc206f1360 diff --git a/src/bin/miri-rustc-tests.rs b/src/bin/miri-rustc-tests.rs deleted file mode 100644 index cef71a9889f12..0000000000000 --- a/src/bin/miri-rustc-tests.rs +++ /dev/null @@ -1,260 +0,0 @@ -#![feature(rustc_private)] - -extern crate rustc_middle; -extern crate rustc_driver; -extern crate rustc_hir; -extern crate rustc_interface; -extern crate rustc_span; - -use std::io; -use std::io::Write; -use std::path::Path; -use std::sync::{Arc, Mutex}; - -use rustc_middle::ty::TyCtxt; -use rustc_driver::Compilation; -use rustc_hir as hir; -use rustc_hir::def_id::LOCAL_CRATE; -use rustc_hir::itemlikevisit; -use rustc_interface::{interface, Queries}; - -struct MiriCompilerCalls { - /// whether we are building for the host - host_target: bool, -} - -impl rustc_driver::Callbacks for MiriCompilerCalls { - fn after_analysis<'tcx>( - &mut self, - compiler: &interface::Compiler, - queries: &'tcx Queries<'tcx>, - ) -> Compilation { - compiler.session().abort_if_errors(); - queries.global_ctxt().unwrap().peek_mut().enter(|tcx| { - if std::env::args().any(|arg| arg == "--test") { - struct Visitor<'tcx>(TyCtxt<'tcx>); - impl<'tcx, 'hir> itemlikevisit::ItemLikeVisitor<'hir> for Visitor<'tcx> { - fn visit_item(&mut self, i: &'hir hir::Item) { - if let hir::ItemKind::Fn(.., body_id) = i.kind { - if i.attrs - .iter() - .any(|attr| self.0.sess.check_name(attr, rustc_span::symbol::sym::test)) - { - let config = miri::MiriConfig::default(); - let did = self.0.hir().body_owner_def_id(body_id).to_def_id(); - println!("running test: {}", self.0.def_path_debug_str(did)); - miri::eval_main(self.0, did, config); - self.0.sess.abort_if_errors(); - } - } - } - fn visit_trait_item(&mut self, _trait_item: &'hir hir::TraitItem) {} - fn visit_impl_item(&mut self, _impl_item: &'hir hir::ImplItem) {} - } - tcx.hir().krate().visit_all_item_likes(&mut Visitor(tcx)); - } else if let Some((entry_def_id, _)) = tcx.entry_fn(LOCAL_CRATE) { - let config = miri::MiriConfig::default(); - miri::eval_main(tcx, entry_def_id.to_def_id(), config); - - compiler.session().abort_if_errors(); - } else { - println!("no main function found, assuming auxiliary build"); - } - }); - - // Continue execution on host target - if self.host_target { Compilation::Continue } else { Compilation::Stop } - } -} - -fn main() { - let path = option_env!("MIRI_RUSTC_TEST").map(String::from).unwrap_or_else(|| { - std::env::var("MIRI_RUSTC_TEST") - .expect("need to set MIRI_RUSTC_TEST to path of rustc tests") - }); - - let mut mir_not_found = Vec::new(); - let mut crate_not_found = Vec::new(); - let mut success = 0; - let mut failed = Vec::new(); - let mut c_abi_fns = Vec::new(); - let mut abi = Vec::new(); - let mut unsupported = Vec::new(); - let mut unimplemented_intrinsic = Vec::new(); - let mut limits = Vec::new(); - let mut files: Vec<_> = std::fs::read_dir(path).unwrap().collect(); - while let Some(file) = files.pop() { - let file = file.unwrap(); - let path = file.path(); - if file.metadata().unwrap().is_dir() { - if !path.to_str().unwrap().ends_with("auxiliary") { - // add subdirs recursively - files.extend(std::fs::read_dir(path).unwrap()); - } - continue; - } - if !file.metadata().unwrap().is_file() || !path.to_str().unwrap().ends_with(".rs") { - continue; - } - let stderr = std::io::stderr(); - write!(stderr.lock(), "test [miri-pass] {} ... ", path.display()).unwrap(); - let mut host_target = false; - let mut args: Vec = 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(); - args.splice(1..1, miri::MIRI_DEFAULT_ARGS.iter().map(ToString::to_string)); - // file to process - args.push(path.display().to_string()); - - let sysroot_flag = String::from("--sysroot"); - if !args.contains(&sysroot_flag) { - args.push(sysroot_flag); - args.push( - Path::new(&std::env::var("HOME").unwrap()) - .join(".xargo") - .join("HOST") - .display() - .to_string(), - ); - } - - // A threadsafe buffer for writing. - #[derive(Default, Clone)] - struct BufWriter(Arc>>); - - impl Write for BufWriter { - fn write(&mut self, buf: &[u8]) -> io::Result { - self.0.lock().unwrap().write(buf) - } - fn flush(&mut self) -> io::Result<()> { - self.0.lock().unwrap().flush() - } - } - let buf = BufWriter::default(); - let output = buf.clone(); - let result = std::panic::catch_unwind(|| { - let mut callbacks = MiriCompilerCalls { host_target }; - let mut run = rustc_driver::RunCompiler::new(&args, &mut callbacks); - run.set_emitter(Some(Box::new(buf))); - let _ = run.run(); - }); - - match result { - Ok(()) => { - success += 1; - writeln!(stderr.lock(), "ok").unwrap() - } - Err(_) => { - let output = output.0.lock().unwrap(); - let output_err = std::str::from_utf8(&output).unwrap(); - if let Some(text) = output_err.splitn(2, "no mir for `").nth(1) { - let end = text.find('`').unwrap(); - mir_not_found.push(text[..end].to_string()); - writeln!(stderr.lock(), "NO MIR FOR `{}`", &text[..end]).unwrap(); - } else if let Some(text) = output_err.splitn(2, "can't find crate for `").nth(1) { - let end = text.find('`').unwrap(); - crate_not_found.push(text[..end].to_string()); - writeln!(stderr.lock(), "CAN'T FIND CRATE FOR `{}`", &text[..end]).unwrap(); - } else { - for text in output_err.split("error: ").skip(1) { - let end = text.find('\n').unwrap_or(text.len()); - let c_abi = "can't call C ABI function: "; - let unimplemented_intrinsic_s = "unimplemented intrinsic: "; - let unsupported_s = "miri does not support "; - let abi_s = "can't handle function with "; - let limit_s = "reached the configured maximum "; - if text.starts_with(c_abi) { - c_abi_fns.push(text[c_abi.len()..end].to_string()); - } else if text.starts_with(unimplemented_intrinsic_s) { - unimplemented_intrinsic - .push(text[unimplemented_intrinsic_s.len()..end].to_string()); - } else if text.starts_with(unsupported_s) { - unsupported.push(text[unsupported_s.len()..end].to_string()); - } else if text.starts_with(abi_s) { - abi.push(text[abi_s.len()..end].to_string()); - } else if text.starts_with(limit_s) { - limits.push(text[limit_s.len()..end].to_string()); - } else if text.find("aborting").is_none() { - failed.push(text[..end].to_string()); - } - } - writeln!(stderr.lock(), "stderr: \n {}", output_err).unwrap(); - } - } - } - } - let stderr = std::io::stderr(); - let mut stderr = stderr.lock(); - writeln!( - stderr, - "{} success, {} no mir, {} crate not found, {} failed, {} C fn, {} ABI, {} unsupported, {} intrinsic", - success, - mir_not_found.len(), - crate_not_found.len(), - failed.len(), - c_abi_fns.len(), - abi.len(), - unsupported.len(), - unimplemented_intrinsic.len() - ) - .unwrap(); - writeln!(stderr, "# The \"other reasons\" errors").unwrap(); - writeln!(stderr, "(sorted, deduplicated)").unwrap(); - print_vec(&mut stderr, failed); - - writeln!(stderr, "# can't call C ABI function").unwrap(); - print_vec(&mut stderr, c_abi_fns); - - writeln!(stderr, "# unsupported ABI").unwrap(); - print_vec(&mut stderr, abi); - - writeln!(stderr, "# unsupported").unwrap(); - print_vec(&mut stderr, unsupported); - - writeln!(stderr, "# unimplemented intrinsics").unwrap(); - print_vec(&mut stderr, unimplemented_intrinsic); - - writeln!(stderr, "# mir not found").unwrap(); - print_vec(&mut stderr, mir_not_found); - - writeln!(stderr, "# crate not found").unwrap(); - print_vec(&mut stderr, crate_not_found); -} - -fn print_vec(stderr: &mut W, v: Vec) { - writeln!(stderr, "```").unwrap(); - for (n, s) in vec_to_hist(v).into_iter().rev() { - writeln!(stderr, "{:4} {}", n, s).unwrap(); - } - writeln!(stderr, "```").unwrap(); -} - -fn vec_to_hist(mut v: Vec) -> Vec<(usize, T)> { - v.sort(); - let mut v = v.into_iter(); - let mut result = Vec::new(); - let mut current = v.next(); - 'outer: while let Some(current_val) = current { - let mut n = 1; - for next in &mut v { - if next == current_val { - n += 1; - } else { - result.push((n, current_val)); - current = Some(next); - continue 'outer; - } - } - result.push((n, current_val)); - break; - } - result.sort(); - result -} From de5b26d7f03208f4fb18872772da4a7ff52f57df Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Fri, 4 Dec 2020 23:52:13 +0100 Subject: [PATCH 2461/3747] Use new std::alloc::Allocator interface. This was changed in core. --- rust-version | 2 +- tests/run-pass/heap_allocator.rs | 22 +++++++++++----------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/rust-version b/rust-version index 485cc2dd4b9f7..58948e2fc69ae 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -88b81970ba7a989a728b32039dd075dc206f1360 +3ff10e74a74ed093fcabac1de27fe1cd65bbbb4a diff --git a/tests/run-pass/heap_allocator.rs b/tests/run-pass/heap_allocator.rs index 5d89243b86a93..e428868af78bf 100644 --- a/tests/run-pass/heap_allocator.rs +++ b/tests/run-pass/heap_allocator.rs @@ -1,22 +1,22 @@ #![feature(allocator_api, slice_ptr_get)] use std::ptr::NonNull; -use std::alloc::{Global, AllocRef, Layout, System}; +use std::alloc::{Global, Allocator, Layout, System}; use std::slice; -fn check_alloc(allocator: T) { unsafe { +fn check_alloc(allocator: T) { unsafe { for &align in &[4, 8, 16, 32] { let layout_20 = Layout::from_size_align(20, align).unwrap(); let layout_40 = Layout::from_size_align(40, 4*align).unwrap(); let layout_10 = Layout::from_size_align(10, align/2).unwrap(); for _ in 0..32 { - let a = allocator.alloc(layout_20).unwrap().as_non_null_ptr(); + let a = allocator.allocate(layout_20).unwrap().as_non_null_ptr(); assert_eq!(a.as_ptr() as usize % layout_20.align(), 0, "pointer is incorrectly aligned"); - allocator.dealloc(a, layout_20); + allocator.deallocate(a, layout_20); } - let p1 = allocator.alloc_zeroed(layout_20).unwrap().as_non_null_ptr(); + let p1 = allocator.allocate_zeroed(layout_20).unwrap().as_non_null_ptr(); assert_eq!(p1.as_ptr() as usize % layout_20.align(), 0, "pointer is incorrectly aligned"); assert_eq!(*p1.as_ptr(), 0); @@ -38,17 +38,17 @@ fn check_alloc(allocator: T) { unsafe { let slice = slice::from_raw_parts(p4.as_ptr(), 10); assert_eq!(&slice, &[0_u8; 10]); - allocator.dealloc(p4, layout_10); + allocator.deallocate(p4, layout_10); } } } -fn check_align_requests(allocator: T) { +fn check_align_requests(allocator: T) { for &size in &[2, 8, 64] { // size less than and bigger than alignment for &align in &[4, 8, 16, 32] { // Be sure to cover less than and bigger than `MIN_ALIGN` for all architectures let iterations = 32; unsafe { let pointers: Vec<_> = (0..iterations).map(|_| { - allocator.alloc(Layout::from_size_align(size, align).unwrap()).unwrap().as_non_null_ptr() + allocator.allocate(Layout::from_size_align(size, align).unwrap()).unwrap().as_non_null_ptr() }).collect(); for &ptr in &pointers { assert_eq!((ptr.as_ptr() as usize) % align, 0, @@ -57,7 +57,7 @@ fn check_align_requests(allocator: T) { // Clean up. for &ptr in &pointers { - allocator.dealloc(ptr, Layout::from_size_align(size, align).unwrap()) + allocator.deallocate(ptr, Layout::from_size_align(size, align).unwrap()) } } } @@ -69,7 +69,7 @@ fn global_to_box() { let l = Layout::new::(); // allocate manually with global allocator, then turn into Box and free there unsafe { - let ptr = Global.alloc(l).unwrap().as_non_null_ptr().as_ptr() as *mut T; + let ptr = Global.allocate(l).unwrap().as_non_null_ptr().as_ptr() as *mut T; let b = Box::from_raw(ptr); drop(b); } @@ -82,7 +82,7 @@ fn box_to_global() { unsafe { let b = Box::new(T::default()); let ptr = Box::into_raw(b); - Global.dealloc(NonNull::new(ptr as *mut u8).unwrap(), l); + Global.deallocate(NonNull::new(ptr as *mut u8).unwrap(), l); } } From 7fb012fdb2608c51f2eba7f2ec00525b4d3cd6ad Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 5 Dec 2020 12:14:52 +0100 Subject: [PATCH 2462/3747] readme: mention data races, and mention cross-interpretation already in the intro --- README.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/README.md b/README.md index 02a64b3d5f7dc..3a8524ec01d34 100644 --- a/README.md +++ b/README.md @@ -20,11 +20,18 @@ for example: or an invalid enum discriminant) * **Experimental**: Violations of the [Stacked Borrows] rules governing aliasing for reference types +* **Experimental**: Data races (but no weak memory effects) On top of that, Miri will also tell you about memory leaks: when there is memory still allocated at the end of the execution, and that memory is not reachable from a global `static`, Miri will raise an error. +You can use Miri to emulate programs on other targets, e.g. to ensure that +byte-level data manipulation works correctly both on little-endian and +big-endian systems. See +[cross-interpretation](#cross-interpretation-running-for-different-targets) +below. + Miri has already discovered some [real-world bugs](#bugs-found-by-miri). If you found a bug with Miri, we'd appreciate if you tell us and we'll add it to the list! From 4cf614ef3301a5c9f93a4e51b8b603b4d0b0b5ad Mon Sep 17 00:00:00 2001 From: JCTyBlaidd Date: Sun, 6 Dec 2020 16:58:32 +0000 Subject: [PATCH 2463/3747] Update release sequence handling to C++20 semantics. --- src/data_race.rs | 71 ++++--- src/lib.rs | 2 +- src/vector_clock.rs | 189 +----------------- .../data_race/release_seq_race_same_thread.rs | 49 +++++ tests/run-pass/concurrency/data_race.rs | 7 +- 5 files changed, 89 insertions(+), 229 deletions(-) create mode 100644 tests/compile-fail/data_race/release_seq_race_same_thread.rs diff --git a/src/data_race.rs b/src/data_race.rs index aca735e6f2220..d4438984a284a 100644 --- a/src/data_race.rs +++ b/src/data_race.rs @@ -1,13 +1,18 @@ //! Implementation of a data-race detector using Lamport Timestamps / Vector-clocks -//! based on the Dyamic Race Detection for C++: +//! based on the Dynamic Race Detection for C++: //! https://www.doc.ic.ac.uk/~afd/homepages/papers/pdfs/2017/POPL.pdf //! which does not report false-positives when fences are used, and gives better //! accuracy in presence of read-modify-write operations. //! +//! The implementation contains modifications to correctly model the changes to the memory model in C++20 +//! regarding the weakening of release sequences: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0982r1.html. +//! Relaxed stores now unconditionally block all currently active release sequences and so per-thread tracking of release +//! sequences is not needed. +//! //! This does not explore weak memory orders and so can still miss data-races //! but should not report false-positives //! -//! Data-race definiton from(https://en.cppreference.com/w/cpp/language/memory_model#Threads_and_data_races): +//! Data-race definition from(https://en.cppreference.com/w/cpp/language/memory_model#Threads_and_data_races): //! a data race occurs between two memory accesses if they are on different threads, at least one operation //! is non-atomic, at least one operation is a write and neither access happens-before the other. Read the link //! for full definition. @@ -21,7 +26,7 @@ //! This means that the thread-index can be safely re-used, starting on the next timestamp for the newly created //! thread. //! -//! The sequentially consistant ordering corresponds to the ordering that the threads +//! The sequentially consistent ordering corresponds to the ordering that the threads //! are currently scheduled, this means that the data-race detector has no additional //! logic for sequentially consistent accesses at the moment since they are indistinguishable //! from acquire/release operations. If weak memory orderings are explored then this @@ -67,7 +72,7 @@ use rustc_target::abi::Size; use crate::{ ImmTy, Immediate, InterpResult, MPlaceTy, MemPlaceMeta, MiriEvalContext, MiriEvalContextExt, - OpTy, Pointer, RangeMap, ScalarMaybeUninit, Tag, ThreadId, VClock, VSmallClockMap, VTimestamp, + OpTy, Pointer, RangeMap, ScalarMaybeUninit, Tag, ThreadId, VClock, VTimestamp, VectorIdx, }; @@ -122,7 +127,7 @@ struct ThreadClockSet { /// thread once it performs an acquire fence. fence_acquire: VClock, - /// The last timesamp of happens-before relations that + /// The last timestamp of happens-before relations that /// have been released by this thread by a fence. fence_release: VClock, } @@ -185,13 +190,6 @@ struct AtomicMemoryCellClocks { /// happen-before a thread if an acquire-load is /// performed on the data. sync_vector: VClock, - - /// The Hash-Map of all threads for which a release - /// sequence exists in the memory cell, required - /// since read-modify-write operations do not - /// invalidate existing release sequences. - /// See page 6 of linked paper. - release_sequences: VSmallClockMap, } /// Memory Cell vector clock metadata @@ -207,7 +205,7 @@ struct MemoryCellClocks { write_index: VectorIdx, /// The vector-clock of the timestamp of the last read operation - /// performed by a thread since the last write operation occured. + /// performed by a thread since the last write operation occurred. /// It is reset to zero on each write operation. read: VClock, @@ -231,6 +229,7 @@ impl Default for MemoryCellClocks { } impl MemoryCellClocks { + /// Load the internal atomic memory cells if they exist. #[inline] fn atomic(&self) -> Option<&AtomicMemoryCellClocks> { @@ -283,8 +282,6 @@ impl MemoryCellClocks { self.atomic_write_detect(clocks, index)?; let atomic = self.atomic_mut(); atomic.sync_vector.clone_from(&clocks.clock); - atomic.release_sequences.clear(); - atomic.release_sequences.insert(index, &clocks.clock); Ok(()) } @@ -292,12 +289,13 @@ impl MemoryCellClocks { /// store relaxed semantics. fn store_relaxed(&mut self, clocks: &ThreadClockSet, index: VectorIdx) -> Result<(), DataRace> { self.atomic_write_detect(clocks, index)?; + + // The handling of release sequences was changed in C++20 and so + // the code here is different to the paper since now all relaxed + // stored block release sequences, the exception for same-thread + // relaxed stores has been removed. let atomic = self.atomic_mut(); atomic.sync_vector.clone_from(&clocks.fence_release); - if let Some(release) = atomic.release_sequences.get(index) { - atomic.sync_vector.join(release); - } - atomic.release_sequences.retain_index(index); Ok(()) } @@ -307,7 +305,6 @@ impl MemoryCellClocks { self.atomic_write_detect(clocks, index)?; let atomic = self.atomic_mut(); atomic.sync_vector.join(&clocks.clock); - atomic.release_sequences.insert(index, &clocks.clock); Ok(()) } @@ -523,7 +520,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { let this = self.eval_context_mut(); // Failure ordering cannot be stronger than success ordering, therefore first attempt - // to read with the failure ordering and if successfull then try again with the success + // to read with the failure ordering and if successful then try again with the success // read ordering and write in the success case. // Read as immediate for the sake of `binary_op()` let old = this.allow_data_races_mut(|this| this.read_immediate(place.into()))?; @@ -546,7 +543,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { Ok(res) } - /// Update the data-race detector for an atomic read occuring at the + /// Update the data-race detector for an atomic read occurring at the /// associated memory-place and on the current thread. fn validate_atomic_load( &self, @@ -568,7 +565,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { ) } - /// Update the data-race detector for an atomic write occuring at the + /// Update the data-race detector for an atomic write occurring at the /// associated memory-place and on the current thread. fn validate_atomic_store( &mut self, @@ -590,7 +587,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { ) } - /// Update the data-race detector for an atomic read-modify-write occuring + /// Update the data-race detector for an atomic read-modify-write occurring /// at the associated memory place and on the current thread. fn validate_atomic_rmw( &mut self, @@ -694,9 +691,9 @@ impl VClockAlloc { /// Report a data-race found in the program. /// This finds the two racing threads and the type - /// of data-race that occured. This will also + /// of data-race that occurred. This will also /// return info about the memory location the data-race - /// occured in. + /// occurred in. #[cold] #[inline(never)] fn report_data_race<'tcx>( @@ -762,7 +759,7 @@ impl VClockAlloc { ) } - /// Detect data-races for an unsychronized read operation, will not perform + /// Detect data-races for an unsynchronized read operation, will not perform /// data-race detection if `multi-threaded` is false, either due to no threads /// being created or if it is temporarily disabled during a racy read or write /// operation for which data-race detection is handled separately, for example @@ -818,7 +815,7 @@ impl VClockAlloc { } } - /// Detect data-races for an unsychronized write operation, will not perform + /// Detect data-races for an unsynchronized write operation, will not perform /// data-race threads if `multi-threaded` is false, either due to no threads /// being created or if it is temporarily disabled during a racy read or write /// operation @@ -826,7 +823,7 @@ impl VClockAlloc { self.unique_access(pointer, len, "Write") } - /// Detect data-races for an unsychronized deallocate operation, will not perform + /// Detect data-races for an unsynchronized deallocate operation, will not perform /// data-race threads if `multi-threaded` is false, either due to no threads /// being created or if it is temporarily disabled during a racy read or write /// operation @@ -838,7 +835,7 @@ impl VClockAlloc { impl<'mir, 'tcx: 'mir> EvalContextPrivExt<'mir, 'tcx> for MiriEvalContext<'mir, 'tcx> {} trait EvalContextPrivExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { // Temporarily allow data-races to occur, this should only be - // used if either one of the appropiate `validate_atomic` functions + // used if either one of the appropriate `validate_atomic` functions // will be called to treat a memory access as atomic or if the memory // being accessed should be treated as internal state, that cannot be // accessed by the interpreted program. @@ -1000,7 +997,7 @@ pub struct GlobalState { /// if a vector index is re-assigned to a new thread. vector_info: RefCell>, - /// The mapping of a given thread to assocaited thread metadata. + /// The mapping of a given thread to associated thread metadata. thread_info: RefCell>, /// The current vector index being executed. @@ -1017,7 +1014,7 @@ pub struct GlobalState { /// Counts the number of threads that are currently active /// if the number of active threads reduces to 1 and then - /// a join operation occures with the remaining main thread + /// a join operation occurs with the remaining main thread /// then multi-threaded execution may be disabled. active_thread_count: Cell, @@ -1160,7 +1157,7 @@ impl GlobalState { } /// Hook on a thread join to update the implicit happens-before relation - /// between the joined thead and the current thread. + /// between the joined thread and the current thread. #[inline] pub fn thread_joined(&self, current_thread: ThreadId, join_thread: ThreadId) { let mut clocks_vec = self.vector_clocks.borrow_mut(); @@ -1194,7 +1191,7 @@ impl GlobalState { .iter_enumerated() .all(|(idx, clocks)| clocks.clock[idx] <= current_clock.clock[idx]) { - // The all thread termations happen-before the current clock + // All thread terminations happen-before the current clock // therefore no data-races can be reported until a new thread // is created, so disable multi-threaded execution. self.multi_threaded.set(false); @@ -1213,7 +1210,7 @@ impl GlobalState { /// On thread termination, the vector-clock may re-used /// in the future once all remaining thread-clocks catch /// up with the time index of the terminated thread. - /// This assiges thread termination with a unique index + /// This assigns thread termination with a unique index /// which will be used to join the thread /// This should be called strictly before any calls to /// `thread_joined`. @@ -1318,8 +1315,8 @@ impl GlobalState { /// Release a lock handle, express that this happens-before /// any subsequent calls to `validate_lock_acquire`. /// For normal locks this should be equivalent to `validate_lock_release_shared` - /// since an acquire operation should have occured before, however - /// for futex & cond-var operations this is not the case and this + /// since an acquire operation should have occurred before, however + /// for futex & condvar operations this is not the case and this /// operation must be used. pub fn validate_lock_release(&self, lock: &mut VClock, thread: ThreadId) { let (index, mut clocks) = self.load_thread_state_mut(thread); diff --git a/src/lib.rs b/src/lib.rs index 87effe9c68852..581da0976e512 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -81,7 +81,7 @@ pub use crate::sync::{ EvalContextExt as SyncEvalContextExt, CondvarId, MutexId, RwLockId }; pub use crate::vector_clock::{ - VClock, VSmallClockMap, VectorIdx, VTimestamp + VClock, VectorIdx, VTimestamp }; /// Insert rustc arguments at the beginning of the argument list that Miri wants to be diff --git a/src/vector_clock.rs b/src/vector_clock.rs index 6840d7e6cb990..1ce6511ee4aeb 100644 --- a/src/vector_clock.rs +++ b/src/vector_clock.rs @@ -1,11 +1,9 @@ -use rustc_data_structures::fx::FxHashMap; use rustc_index::vec::Idx; use smallvec::SmallVec; use std::{ cmp::Ordering, convert::TryFrom, - fmt::{self, Debug}, - mem, + fmt::Debug, ops::Index, }; @@ -43,160 +41,6 @@ impl From for VectorIdx { } } -/// A sparse mapping of vector index values to vector clocks, this -/// is optimized for the common case with only one element stored -/// inside the map. -/// This is used to store the set of currently active release -/// sequences at a given memory location, since RMW operations -/// allow for multiple release sequences to be active at once -/// and to be collapsed back to one active release sequence -/// once a non RMW atomic store operation occurs. -/// An all zero vector is considered to be equal to no -/// element stored internally since it will never be -/// stored and has no meaning as a release sequence -/// vector clock. -#[derive(Clone)] -pub struct VSmallClockMap(VSmallClockMapInner); - -#[derive(Clone)] -enum VSmallClockMapInner { - /// Zero or 1 vector elements, common - /// case for the sparse set. - /// The all zero vector clock is treated - /// as equal to the empty element. - Small(VectorIdx, VClock), - - /// Hash-map of vector clocks. - Large(FxHashMap), -} - -impl VSmallClockMap { - /// Remove all clock vectors from the map, setting them - /// to the zero vector. - pub fn clear(&mut self) { - match &mut self.0 { - VSmallClockMapInner::Small(_, clock) => clock.set_zero_vector(), - VSmallClockMapInner::Large(hash_map) => { - hash_map.clear(); - } - } - } - - /// Remove all clock vectors except for the clock vector - /// stored at the given index, which is retained. - pub fn retain_index(&mut self, index: VectorIdx) { - match &mut self.0 { - VSmallClockMapInner::Small(small_idx, clock) => { - if index != *small_idx { - // The zero-vector is considered to equal - // the empty element. - clock.set_zero_vector() - } - } - VSmallClockMapInner::Large(hash_map) => { - let value = hash_map.remove(&index).unwrap_or_default(); - self.0 = VSmallClockMapInner::Small(index, value); - } - } - } - - /// Insert the vector clock into the associated vector - /// index. - pub fn insert(&mut self, index: VectorIdx, clock: &VClock) { - match &mut self.0 { - VSmallClockMapInner::Small(small_idx, small_clock) => { - if small_clock.is_zero_vector() { - *small_idx = index; - small_clock.clone_from(clock); - } else if !clock.is_zero_vector() { - // Convert to using the hash-map representation. - let mut hash_map = FxHashMap::default(); - hash_map.insert(*small_idx, mem::take(small_clock)); - hash_map.insert(index, clock.clone()); - self.0 = VSmallClockMapInner::Large(hash_map); - } - } - VSmallClockMapInner::Large(hash_map) => - if !clock.is_zero_vector() { - hash_map.insert(index, clock.clone()); - }, - } - } - - /// Try to load the vector clock associated with the current - /// vector index. - pub fn get(&self, index: VectorIdx) -> Option<&VClock> { - match &self.0 { - VSmallClockMapInner::Small(small_idx, small_clock) => { - if *small_idx == index && !small_clock.is_zero_vector() { - Some(small_clock) - } else { - None - } - } - VSmallClockMapInner::Large(hash_map) => hash_map.get(&index), - } - } -} - -impl Default for VSmallClockMap { - #[inline] - fn default() -> Self { - VSmallClockMap(VSmallClockMapInner::Small(VectorIdx::new(0), VClock::default())) - } -} - -impl Debug for VSmallClockMap { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - // Print the contents of the small vector clock set as the map - // of vector index to vector clock that they represent. - let mut map = f.debug_map(); - match &self.0 { - VSmallClockMapInner::Small(small_idx, small_clock) => - if !small_clock.is_zero_vector() { - map.entry(&small_idx, &small_clock); - }, - VSmallClockMapInner::Large(hash_map) => - for (idx, elem) in hash_map.iter() { - map.entry(idx, elem); - }, - } - map.finish() - } -} - -impl PartialEq for VSmallClockMap { - fn eq(&self, other: &Self) -> bool { - use VSmallClockMapInner::*; - match (&self.0, &other.0) { - (Small(i1, c1), Small(i2, c2)) => { - if c1.is_zero_vector() { - // Either they are both zero or they are non-equal - c2.is_zero_vector() - } else { - // At least one is non-zero, so the full comparison is correct - i1 == i2 && c1 == c2 - } - } - (Small(idx, clock), Large(hash_map)) | (Large(hash_map), Small(idx, clock)) => { - if hash_map.len() == 0 { - // Equal to the empty hash-map - clock.is_zero_vector() - } else if hash_map.len() == 1 { - // Equal to the hash-map with one element - let (hash_idx, hash_clock) = hash_map.iter().next().unwrap(); - hash_idx == idx && hash_clock == clock - } else { - false - } - } - (Large(map1), Large(map2)) => map1 == map2, - } - } -} - -impl Eq for VSmallClockMap {} - /// The size of the vector-clock to store inline /// clock vectors larger than this will be stored on the heap const SMALL_VECTOR: usize = 4; @@ -484,7 +328,7 @@ impl Index for VClock { #[cfg(test)] mod tests { - use super::{VClock, VSmallClockMap, VTimestamp, VectorIdx}; + use super::{VClock, VTimestamp, VectorIdx}; use std::cmp::Ordering; #[test] @@ -628,33 +472,4 @@ mod tests { r ); } - - #[test] - pub fn test_vclock_set() { - let mut map = VSmallClockMap::default(); - let v1 = from_slice(&[3, 0, 1]); - let v2 = from_slice(&[4, 2, 3]); - let v3 = from_slice(&[4, 8, 3]); - map.insert(VectorIdx(0), &v1); - assert_eq!(map.get(VectorIdx(0)), Some(&v1)); - map.insert(VectorIdx(5), &v2); - assert_eq!(map.get(VectorIdx(0)), Some(&v1)); - assert_eq!(map.get(VectorIdx(5)), Some(&v2)); - map.insert(VectorIdx(53), &v3); - assert_eq!(map.get(VectorIdx(0)), Some(&v1)); - assert_eq!(map.get(VectorIdx(5)), Some(&v2)); - assert_eq!(map.get(VectorIdx(53)), Some(&v3)); - map.retain_index(VectorIdx(53)); - assert_eq!(map.get(VectorIdx(0)), None); - assert_eq!(map.get(VectorIdx(5)), None); - assert_eq!(map.get(VectorIdx(53)), Some(&v3)); - map.clear(); - assert_eq!(map.get(VectorIdx(0)), None); - assert_eq!(map.get(VectorIdx(5)), None); - assert_eq!(map.get(VectorIdx(53)), None); - map.insert(VectorIdx(53), &v3); - assert_eq!(map.get(VectorIdx(0)), None); - assert_eq!(map.get(VectorIdx(5)), None); - assert_eq!(map.get(VectorIdx(53)), Some(&v3)); - } } diff --git a/tests/compile-fail/data_race/release_seq_race_same_thread.rs b/tests/compile-fail/data_race/release_seq_race_same_thread.rs new file mode 100644 index 0000000000000..a7cae5574dd38 --- /dev/null +++ b/tests/compile-fail/data_race/release_seq_race_same_thread.rs @@ -0,0 +1,49 @@ +// ignore-windows: Concurrency on Windows is not supported yet. +// compile-flags: -Zmiri-disable-isolation + +use std::thread::spawn; +use std::sync::atomic::{AtomicUsize, Ordering}; + +#[derive(Copy, Clone)] +struct EvilSend(pub T); + +unsafe impl Send for EvilSend {} +unsafe impl Sync for EvilSend {} + +static SYNC: AtomicUsize = AtomicUsize::new(0); + +pub fn main() { + let mut a = 0u32; + let b = &mut a as *mut u32; + let c = EvilSend(b); + + // Note: this is scheduler-dependent + // the operations need to occur in + // order, the sleep operations currently + // force the desired ordering: + // 1. store release : 1 + // 2. store relaxed : 2 + // 3. load acquire : 2 + unsafe { + let j1 = spawn(move || { + *c.0 = 1; + SYNC.store(1, Ordering::Release); + + // C++20 update to release sequences + // makes this block the release sequence + // despite the same thread. + SYNC.store(2, Ordering::Relaxed); + }); + + let j2 = spawn(move || { + if SYNC.load(Ordering::Acquire) == 2 { + *c.0 //~ ERROR Data race + } else { + 0 + } + }); + + j1.join().unwrap(); + j2.join().unwrap(); + } +} diff --git a/tests/run-pass/concurrency/data_race.rs b/tests/run-pass/concurrency/data_race.rs index 64e90024ed49b..b53acc2691ff6 100644 --- a/tests/run-pass/concurrency/data_race.rs +++ b/tests/run-pass/concurrency/data_race.rs @@ -89,7 +89,7 @@ pub fn test_rmw_no_block() { } } -pub fn test_release_no_block() { +pub fn test_simple_release() { let mut a = 0u32; let b = &mut a as *mut u32; let c = EvilSend(b); @@ -98,11 +98,10 @@ pub fn test_release_no_block() { let j1 = spawn(move || { *c.0 = 1; SYNC.store(1, Ordering::Release); - SYNC.store(3, Ordering::Relaxed); }); let j2 = spawn(move || { - if SYNC.load(Ordering::Acquire) == 3 { + if SYNC.load(Ordering::Acquire) == 1 { *c.0 } else { 0 @@ -118,5 +117,5 @@ pub fn main() { test_fence_sync(); test_multiple_reads(); test_rmw_no_block(); - test_release_no_block(); + test_simple_release(); } From a6f377e48e57e43683fef86d8b84cf26ba989b83 Mon Sep 17 00:00:00 2001 From: JCTyBlaidd Date: Sun, 6 Dec 2020 17:11:24 +0000 Subject: [PATCH 2464/3747] Fix typo --- tests/compile-fail/data_race/release_seq_race_same_thread.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/compile-fail/data_race/release_seq_race_same_thread.rs b/tests/compile-fail/data_race/release_seq_race_same_thread.rs index a7cae5574dd38..d64b80dbd84c6 100644 --- a/tests/compile-fail/data_race/release_seq_race_same_thread.rs +++ b/tests/compile-fail/data_race/release_seq_race_same_thread.rs @@ -31,7 +31,8 @@ pub fn main() { // C++20 update to release sequences // makes this block the release sequence - // despite the same thread. + // despite the being on the same thread + // as the release store. SYNC.store(2, Ordering::Relaxed); }); From 6db821537f6900bfce2d46911c5243043d5700a0 Mon Sep 17 00:00:00 2001 From: JCTyblaidd Date: Sun, 6 Dec 2020 17:59:49 +0000 Subject: [PATCH 2465/3747] Fix caps Co-authored-by: Ralf Jung --- src/data_race.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/data_race.rs b/src/data_race.rs index d4438984a284a..aec22dadc1b6b 100644 --- a/src/data_race.rs +++ b/src/data_race.rs @@ -292,7 +292,7 @@ impl MemoryCellClocks { // The handling of release sequences was changed in C++20 and so // the code here is different to the paper since now all relaxed - // stored block release sequences, the exception for same-thread + // stores block release sequences. The exception for same-thread // relaxed stores has been removed. let atomic = self.atomic_mut(); atomic.sync_vector.clone_from(&clocks.fence_release); From 789c8a006ba02ddad05513f47226406735ed33a5 Mon Sep 17 00:00:00 2001 From: Jonah Williams Date: Sun, 6 Dec 2020 17:54:59 -0800 Subject: [PATCH 2466/3747] Fix README.md typo "extend" -> "extent" Just something I noticed while reading --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 3a8524ec01d34..7c6b09968f477 100644 --- a/README.md +++ b/README.md @@ -52,7 +52,7 @@ in your program, and cannot run all programs: * Program execution is non-deterministic when it depends, for example, on where exactly in memory allocations end up, or on the exact interleaving of concurrent threads. Miri tests one of many possible executions of your - program. You can alleviate this to some extend by running Miri with different + program. You can alleviate this to some extent by running Miri with different values for `-Zmiri-seed`, but that will still by far not explore all possible executions. * Miri runs the program as a platform-independent interpreter, so the program From 2f0d7d38b44351525be19b14d73043468950cd71 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 10 Dec 2020 00:09:52 +0100 Subject: [PATCH 2467/3747] rustup; test AtomicPtr leak checker --- rust-version | 2 +- tests/run-pass/leak-in-static.rs | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 58948e2fc69ae..ac50cd77052ca 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -3ff10e74a74ed093fcabac1de27fe1cd65bbbb4a +f0f68778f798d6d34649745b41770829b17ba5b8 diff --git a/tests/run-pass/leak-in-static.rs b/tests/run-pass/leak-in-static.rs index b12cbbf6e64f7..2914b1149c06f 100644 --- a/tests/run-pass/leak-in-static.rs +++ b/tests/run-pass/leak-in-static.rs @@ -1,3 +1,5 @@ +use std::{ptr, sync::atomic::{AtomicPtr, Ordering}}; + static mut LEAKER: Option>> = None; fn main() { @@ -5,4 +7,10 @@ fn main() { unsafe { LEAKER = Some(Box::new(vec![0; 42])); } + + // Make sure this is allowed even when `AtomicPtr` is used. + { + static LEAK: AtomicPtr = AtomicPtr::new(ptr::null_mut()); + LEAK.store(Box::into_raw(Box::new(0usize)), Ordering::SeqCst); + } } From 7bbd6bca7778210f6cddf8cc668d34bbd46f00dc Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 10 Dec 2020 19:53:45 +0100 Subject: [PATCH 2468/3747] rustup --- rust-version | 2 +- src/diagnostics.rs | 8 +++----- src/machine.rs | 4 ++-- src/shims/foreign_items.rs | 2 +- src/shims/intrinsics.rs | 8 ++++---- tests/compile-fail/abort-terminator.rs | 2 +- tests/compile-fail/intrinsics/uninit_uninhabited_type.rs | 2 +- tests/compile-fail/intrinsics/zero_fn_ptr.rs | 2 +- tests/compile-fail/panic/double_panic.rs | 2 +- tests/compile-fail/panic/panic_abort1.rs | 2 +- tests/compile-fail/panic/panic_abort2.rs | 2 +- tests/compile-fail/panic/panic_abort3.rs | 2 +- tests/compile-fail/panic/panic_abort4.rs | 2 +- 13 files changed, 19 insertions(+), 21 deletions(-) diff --git a/rust-version b/rust-version index ac50cd77052ca..84526eacb7d8f 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -f0f68778f798d6d34649745b41770829b17ba5b8 +39b841dfe36f90a7cd111e7f0c55f32594f6e578 diff --git a/src/diagnostics.rs b/src/diagnostics.rs index 12ad93a5289ee..3f1f67218fdb6 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -12,7 +12,7 @@ use crate::*; /// Details of premature program termination. pub enum TerminationInfo { Exit(i64), - Abort(Option), + Abort(String), UnsupportedInIsolation(String), ExperimentalUb { msg: String, url: String }, Deadlock, @@ -24,10 +24,8 @@ impl fmt::Display for TerminationInfo { match self { Exit(code) => write!(f, "the evaluated program completed with exit code {}", code), - Abort(None) => - write!(f, "the evaluated program aborted execution"), - Abort(Some(msg)) => - write!(f, "the evaluated program aborted execution: {}", msg), + Abort(msg) => + write!(f, "{}", msg), UnsupportedInIsolation(msg) => write!(f, "{}", msg), ExperimentalUb { msg, .. } => diff --git a/src/machine.rs b/src/machine.rs index 70f4bd722df75..4b9cad8420db8 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -391,8 +391,8 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { } #[inline(always)] - fn abort(_ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx, !> { - throw_machine_stop!(TerminationInfo::Abort(None)) + fn abort(_ecx: &mut InterpCx<'mir, 'tcx, Self>, msg: String) -> InterpResult<'tcx, !> { + throw_machine_stop!(TerminationInfo::Abort(msg)) } #[inline(always)] diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 24fa119446e85..d588e2962a150 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -149,7 +149,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx throw_machine_stop!(TerminationInfo::Exit(code.into())); } "abort" => { - throw_machine_stop!(TerminationInfo::Abort(None)) + throw_machine_stop!(TerminationInfo::Abort("the program aborted execution".to_owned())) } _ => throw_unsup_format!("can't call (diverging) foreign function: {}", link_name), }, diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 8f7ae6bebb52e..956f3b5bde4fb 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -419,7 +419,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Query type information - "assert_inhabited" | "assert_zero_valid" | "assert_uninit_valid" => { let &[] = check_arg_count(args)?; @@ -427,13 +426,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let layout = this.layout_of(ty)?; // Abort here because the caller might not be panic safe. if layout.abi.is_uninhabited() { - throw_machine_stop!(TerminationInfo::Abort(Some(format!("attempted to instantiate uninhabited type `{}`", ty)))) + // Use this message even for the other intrinsics, as that's what codegen does + throw_machine_stop!(TerminationInfo::Abort(format!("aborted execution: attempted to instantiate uninhabited type `{}`", ty))) } if intrinsic_name == "assert_zero_valid" && !layout.might_permit_raw_init(this, /*zero:*/ true).unwrap() { - throw_machine_stop!(TerminationInfo::Abort(Some(format!("attempted to zero-initialize type `{}`, which is invalid", ty)))) + throw_machine_stop!(TerminationInfo::Abort(format!("aborted execution: attempted to zero-initialize type `{}`, which is invalid", ty))) } if intrinsic_name == "assert_uninit_valid" && !layout.might_permit_raw_init(this, /*zero:*/ false).unwrap() { - throw_machine_stop!(TerminationInfo::Abort(Some(format!("attempted to leave type `{}` uninitialized, which is invalid", ty)))) + throw_machine_stop!(TerminationInfo::Abort(format!("aborted execution: attempted to leave type `{}` uninitialized, which is invalid", ty))) } } diff --git a/tests/compile-fail/abort-terminator.rs b/tests/compile-fail/abort-terminator.rs index 1bfa289a52b4e..73286a1759baf 100644 --- a/tests/compile-fail/abort-terminator.rs +++ b/tests/compile-fail/abort-terminator.rs @@ -1,4 +1,4 @@ -// error-pattern: the evaluated program aborted +// error-pattern: the program aborted #![feature(unwind_attributes)] #[unwind(aborts)] diff --git a/tests/compile-fail/intrinsics/uninit_uninhabited_type.rs b/tests/compile-fail/intrinsics/uninit_uninhabited_type.rs index deb3586c781e2..2337ff0f6c26c 100644 --- a/tests/compile-fail/intrinsics/uninit_uninhabited_type.rs +++ b/tests/compile-fail/intrinsics/uninit_uninhabited_type.rs @@ -1,4 +1,4 @@ -// error-pattern: the evaluated program aborted execution: attempted to instantiate uninhabited type `!` +// error-pattern: attempted to instantiate uninhabited type `!` #![feature(never_type)] #[allow(deprecated, invalid_value)] diff --git a/tests/compile-fail/intrinsics/zero_fn_ptr.rs b/tests/compile-fail/intrinsics/zero_fn_ptr.rs index 81dbf6c429b33..098a8e01347f3 100644 --- a/tests/compile-fail/intrinsics/zero_fn_ptr.rs +++ b/tests/compile-fail/intrinsics/zero_fn_ptr.rs @@ -1,4 +1,4 @@ -// error-pattern: the evaluated program aborted execution: attempted to zero-initialize type `fn()`, which is invalid +// error-pattern: attempted to zero-initialize type `fn()`, which is invalid #[allow(deprecated, invalid_value)] fn main() { diff --git a/tests/compile-fail/panic/double_panic.rs b/tests/compile-fail/panic/double_panic.rs index 80d74f026232e..b42c1aff10324 100644 --- a/tests/compile-fail/panic/double_panic.rs +++ b/tests/compile-fail/panic/double_panic.rs @@ -1,4 +1,4 @@ -// error-pattern: the evaluated program aborted +// error-pattern: the program aborted struct Foo; impl Drop for Foo { diff --git a/tests/compile-fail/panic/panic_abort1.rs b/tests/compile-fail/panic/panic_abort1.rs index 02f8f25880f3d..095d9e3d75b02 100644 --- a/tests/compile-fail/panic/panic_abort1.rs +++ b/tests/compile-fail/panic/panic_abort1.rs @@ -1,4 +1,4 @@ -// error-pattern: the evaluated program aborted execution +// error-pattern: the program aborted execution // compile-flags: -C panic=abort fn main() { diff --git a/tests/compile-fail/panic/panic_abort2.rs b/tests/compile-fail/panic/panic_abort2.rs index 0d6808dd22e04..de177bc4e7167 100644 --- a/tests/compile-fail/panic/panic_abort2.rs +++ b/tests/compile-fail/panic/panic_abort2.rs @@ -1,4 +1,4 @@ -// error-pattern: the evaluated program aborted execution +// error-pattern: the program aborted execution // compile-flags: -C panic=abort fn main() { diff --git a/tests/compile-fail/panic/panic_abort3.rs b/tests/compile-fail/panic/panic_abort3.rs index 6640a56c0be28..2d65da4fe3416 100644 --- a/tests/compile-fail/panic/panic_abort3.rs +++ b/tests/compile-fail/panic/panic_abort3.rs @@ -1,4 +1,4 @@ -// error-pattern: the evaluated program aborted execution +// error-pattern: the program aborted execution // compile-flags: -C panic=abort fn main() { diff --git a/tests/compile-fail/panic/panic_abort4.rs b/tests/compile-fail/panic/panic_abort4.rs index d39b1794e676a..41d32a604fede 100644 --- a/tests/compile-fail/panic/panic_abort4.rs +++ b/tests/compile-fail/panic/panic_abort4.rs @@ -1,4 +1,4 @@ -// error-pattern: the evaluated program aborted execution +// error-pattern: the program aborted execution // compile-flags: -C panic=abort fn main() { From 27a518e166f778d6c0d4727c9917a0db8454958e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 10 Dec 2020 00:11:00 +0100 Subject: [PATCH 2469/3747] enable track-raw-ptr tests on Windows --- README.md | 3 +-- tests/compile-fail/stacked_borrows/raw_tracking.rs | 1 - tests/run-pass/btreemap.rs | 1 - tests/run-pass/rc.rs | 1 - tests/run-pass/stacked-borrows/stacked-borrows.rs | 1 - tests/run-pass/vec.rs | 1 - tests/run-pass/vecdeque.rs | 1 - 7 files changed, 1 insertion(+), 8 deletions(-) diff --git a/README.md b/README.md index 7c6b09968f477..38663b408a3d8 100644 --- a/README.md +++ b/README.md @@ -248,8 +248,7 @@ environment variable: help identify latent aliasing issues in code that Miri accepts by default. You can recognize false positives by "" occurring in the message -- this indicates a pointer that was cast from an integer, so Miri was unable to track - this pointer. Make sure to use a non-Windows target with this flag, as the - Windows runtime makes use of integer-pointer casts. + this pointer. Some native rustc `-Z` flags are also very relevant for Miri: diff --git a/tests/compile-fail/stacked_borrows/raw_tracking.rs b/tests/compile-fail/stacked_borrows/raw_tracking.rs index b9ddee328f7a6..975aec945c7f5 100644 --- a/tests/compile-fail/stacked_borrows/raw_tracking.rs +++ b/tests/compile-fail/stacked_borrows/raw_tracking.rs @@ -1,5 +1,4 @@ // compile-flags: -Zmiri-track-raw-pointers -// ignore-windows (FIXME: tracking raw pointers does not work on Windows) //! This demonstrates a provenance problem that requires tracking of raw pointers to be detected. fn main() { diff --git a/tests/run-pass/btreemap.rs b/tests/run-pass/btreemap.rs index ca548a03703e6..b704b89fd0507 100644 --- a/tests/run-pass/btreemap.rs +++ b/tests/run-pass/btreemap.rs @@ -1,5 +1,4 @@ // compile-flags: -Zmiri-track-raw-pointers -// ignore-windows (FIXME: tracking raw pointers does not work on Windows) #![feature(btree_drain_filter)] use std::collections::{BTreeMap, BTreeSet}; use std::mem; diff --git a/tests/run-pass/rc.rs b/tests/run-pass/rc.rs index 47f29992c459d..69bd1f8d9ae2d 100644 --- a/tests/run-pass/rc.rs +++ b/tests/run-pass/rc.rs @@ -1,5 +1,4 @@ // compile-flags: -Zmiri-track-raw-pointers -// ignore-windows (FIXME: tracking raw pointers does not work on Windows) #![feature(new_uninit)] #![feature(get_mut_unchecked)] diff --git a/tests/run-pass/stacked-borrows/stacked-borrows.rs b/tests/run-pass/stacked-borrows/stacked-borrows.rs index ad1877fc019bc..99bd0fb9d8057 100644 --- a/tests/run-pass/stacked-borrows/stacked-borrows.rs +++ b/tests/run-pass/stacked-borrows/stacked-borrows.rs @@ -1,5 +1,4 @@ // compile-flags: -Zmiri-track-raw-pointers -// ignore-windows (FIXME: tracking raw pointers does not work on Windows) #![feature(raw_ref_macros)] use std::ptr; diff --git a/tests/run-pass/vec.rs b/tests/run-pass/vec.rs index f243aa45a1a66..8d83f6380b8f8 100644 --- a/tests/run-pass/vec.rs +++ b/tests/run-pass/vec.rs @@ -1,5 +1,4 @@ // compile-flags: -Zmiri-track-raw-pointers -// ignore-windows (FIXME: tracking raw pointers does not work on Windows) // Gather all references from a mutable iterator and make sure Miri notices if // using them is dangerous. fn test_all_refs<'a, T: 'a>(dummy: &mut T, iter: impl Iterator) { diff --git a/tests/run-pass/vecdeque.rs b/tests/run-pass/vecdeque.rs index 55b47f622fde3..54aeb89ec83ff 100644 --- a/tests/run-pass/vecdeque.rs +++ b/tests/run-pass/vecdeque.rs @@ -1,5 +1,4 @@ // compile-flags: -Zmiri-track-raw-pointers -// ignore-windows (FIXME: tracking raw pointers does not work on Windows) use std::collections::VecDeque; fn test_all_refs<'a, T: 'a>(dummy: &mut T, iter: impl Iterator) { From 19d3d9e313af703fae223e06ba317fbd51a12bbd Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 11 Dec 2020 11:36:17 +0100 Subject: [PATCH 2470/3747] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 84526eacb7d8f..a11d33b3d336f 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -39b841dfe36f90a7cd111e7f0c55f32594f6e578 +a2e29d67c26bdf8f278c98ee02d6cc77a279ed2e From c45b1b16be9ce362f5e23bd5335cffac6679ea59 Mon Sep 17 00:00:00 2001 From: JCTyBlaidd Date: Mon, 7 Dec 2020 18:16:06 +0000 Subject: [PATCH 2471/3747] More tests, fix issue 1643 and detect races with allocation. --- src/data_race.rs | 75 ++++++++++++++----- src/machine.rs | 19 ++++- .../compile-fail/data_race/alloc_read_race.rs | 45 +++++++++++ .../data_race/alloc_write_race.rs | 45 +++++++++++ .../data_race/dealloc_read_race.rs | 32 ++++++++ .../data_race/dealloc_read_race_stack.rs | 52 +++++++++++++ .../data_race/dealloc_read_race_stack_drop.rs | 53 +++++++++++++ .../data_race/dealloc_write_race.rs | 31 ++++++++ .../data_race/dealloc_write_race_stack.rs | 52 +++++++++++++ .../dealloc_write_race_stack_drop.rs | 52 +++++++++++++ .../data_race/read_write_race_stack.rs | 55 ++++++++++++++ .../data_race/write_write_race_stack.rs | 57 ++++++++++++++ tests/run-pass/concurrency/issue1643.rs | 14 ++++ tests/run-pass/concurrency/issue1643.stderr | 2 + 14 files changed, 564 insertions(+), 20 deletions(-) create mode 100644 tests/compile-fail/data_race/alloc_read_race.rs create mode 100644 tests/compile-fail/data_race/alloc_write_race.rs create mode 100644 tests/compile-fail/data_race/dealloc_read_race.rs create mode 100644 tests/compile-fail/data_race/dealloc_read_race_stack.rs create mode 100644 tests/compile-fail/data_race/dealloc_read_race_stack_drop.rs create mode 100644 tests/compile-fail/data_race/dealloc_write_race.rs create mode 100644 tests/compile-fail/data_race/dealloc_write_race_stack.rs create mode 100644 tests/compile-fail/data_race/dealloc_write_race_stack_drop.rs create mode 100644 tests/compile-fail/data_race/read_write_race_stack.rs create mode 100644 tests/compile-fail/data_race/write_write_race_stack.rs create mode 100644 tests/run-pass/concurrency/issue1643.rs create mode 100644 tests/run-pass/concurrency/issue1643.stderr diff --git a/src/data_race.rs b/src/data_race.rs index aec22dadc1b6b..a70c4a4e4c70f 100644 --- a/src/data_race.rs +++ b/src/data_race.rs @@ -192,6 +192,25 @@ struct AtomicMemoryCellClocks { sync_vector: VClock, } +#[derive(Copy, Clone, PartialEq, Eq, Debug)] +enum WriteType { + /// Allocate memory. + Allocate, + /// Standard unsynchronized write. + Write, + /// Deallocate memory + Deallocate, +} +impl WriteType { + fn get_descriptor(self) -> &'static str { + match self { + WriteType::Allocate => "ALLOCATE", + WriteType::Write => "WRITE", + WriteType::Deallocate => "DEALLOCATE", + } + } +} + /// Memory Cell vector clock metadata /// for data-race detection. #[derive(Clone, PartialEq, Eq, Debug)] @@ -204,6 +223,11 @@ struct MemoryCellClocks { /// that performed the last write operation. write_index: VectorIdx, + /// The type of operation that the write index represents, + /// either newly allocated memory, a non-atomic write or + /// a deallocation of memory. + write_type: WriteType, + /// The vector-clock of the timestamp of the last read operation /// performed by a thread since the last write operation occurred. /// It is reset to zero on each write operation. @@ -215,20 +239,19 @@ struct MemoryCellClocks { atomic_ops: Option>, } -/// Create a default memory cell clocks instance -/// for uninitialized memory. -impl Default for MemoryCellClocks { - fn default() -> Self { +impl MemoryCellClocks { + + /// Create a new set of clocks representing memory allocated + /// at a given vector timestamp and index. + fn new(alloc: VTimestamp, alloc_index: VectorIdx) -> Self { MemoryCellClocks { read: VClock::default(), - write: 0, - write_index: VectorIdx::MAX_INDEX, + write: alloc, + write_index: alloc_index, + write_type: WriteType::Allocate, atomic_ops: None, } } -} - -impl MemoryCellClocks { /// Load the internal atomic memory cells if they exist. #[inline] @@ -382,6 +405,7 @@ impl MemoryCellClocks { &mut self, clocks: &ThreadClockSet, index: VectorIdx, + write_type: WriteType, ) -> Result<(), DataRace> { log::trace!("Unsynchronized write with vectors: {:#?} :: {:#?}", self, clocks); if self.write <= clocks.clock[self.write_index] && self.read <= clocks.clock { @@ -393,6 +417,7 @@ impl MemoryCellClocks { if race_free { self.write = clocks.clock[index]; self.write_index = index; + self.write_type = write_type; self.read.set_zero_vector(); Ok(()) } else { @@ -646,16 +671,28 @@ pub struct VClockAlloc { /// Assigning each byte a MemoryCellClocks. alloc_ranges: RefCell>, - // Pointer to global state. + /// Pointer to global state. global: MemoryExtra, } impl VClockAlloc { - /// Create a new data-race allocation detector. - pub fn new_allocation(global: &MemoryExtra, len: Size) -> VClockAlloc { + + /// Create a new data-race detector for newly allocated memory. + pub fn new_allocation(global: &MemoryExtra, len: Size, track_alloc: bool) -> VClockAlloc { + //FIXME: stack allocations are currently ignored due to the lazy nature of stack + // allocation, this results in data-races being missed. + let (alloc_timestamp, alloc_index) = if !track_alloc { + (0, VectorIdx::MAX_INDEX) + }else{ + let (alloc_index, clocks) = global.current_thread_state(); + let alloc_timestamp = clocks.clock[alloc_index]; + (alloc_timestamp, alloc_index) + }; VClockAlloc { global: Rc::clone(global), - alloc_ranges: RefCell::new(RangeMap::new(len, MemoryCellClocks::default())), + alloc_ranges: RefCell::new(RangeMap::new( + len, MemoryCellClocks::new(alloc_timestamp, alloc_index) + )), } } @@ -712,7 +749,7 @@ impl VClockAlloc { // Convert the write action into the vector clock it // represents for diagnostic purposes. write_clock = VClock::new_with_index(range.write_index, range.write); - ("WRITE", range.write_index, &write_clock) + (range.write_type.get_descriptor(), range.write_index, &write_clock) } else if let Some(idx) = Self::find_gt_index(&range.read, ¤t_clocks.clock) { ("READ", idx, &range.read) } else if !is_atomic { @@ -792,17 +829,17 @@ impl VClockAlloc { &mut self, pointer: Pointer, len: Size, - action: &str, + write_type: WriteType, ) -> InterpResult<'tcx> { if self.global.multi_threaded.get() { let (index, clocks) = self.global.current_thread_state(); for (_, range) in self.alloc_ranges.get_mut().iter_mut(pointer.offset, len) { - if let Err(DataRace) = range.write_race_detect(&*clocks, index) { + if let Err(DataRace) = range.write_race_detect(&*clocks, index, write_type) { // Report data-race return Self::report_data_race( &self.global, range, - action, + write_type.get_descriptor(), false, pointer, len, @@ -820,7 +857,7 @@ impl VClockAlloc { /// being created or if it is temporarily disabled during a racy read or write /// operation pub fn write<'tcx>(&mut self, pointer: Pointer, len: Size) -> InterpResult<'tcx> { - self.unique_access(pointer, len, "Write") + self.unique_access(pointer, len, WriteType::Write) } /// Detect data-races for an unsynchronized deallocate operation, will not perform @@ -828,7 +865,7 @@ impl VClockAlloc { /// being created or if it is temporarily disabled during a racy read or write /// operation pub fn deallocate<'tcx>(&mut self, pointer: Pointer, len: Size) -> InterpResult<'tcx> { - self.unique_access(pointer, len, "Deallocate") + self.unique_access(pointer, len, WriteType::Deallocate) } } diff --git a/src/machine.rs b/src/machine.rs index 4b9cad8420db8..159e08c87d3f0 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -478,7 +478,24 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { (None, Tag::Untagged) }; let race_alloc = if let Some(data_race) = &memory_extra.data_race { - Some(data_race::AllocExtra::new_allocation(&data_race, alloc.size)) + match kind { + // V-Table generation is lazy and so racy, so do not track races. + // Also V-Tables are read only so no data races can be detected. + MemoryKind::Vtable => None, + // User allocated and stack memory should track allocation. + MemoryKind::Machine( + MiriMemoryKind::Rust | MiriMemoryKind::C | MiriMemoryKind::WinHeap + ) | MemoryKind::Stack => Some( + data_race::AllocExtra::new_allocation(&data_race, alloc.size, true) + ), + // Other global memory should trace races but be allocated at the 0 timestamp. + MemoryKind::Machine( + MiriMemoryKind::Global | MiriMemoryKind::Machine | MiriMemoryKind::Env | + MiriMemoryKind::ExternStatic | MiriMemoryKind::Tls + ) | MemoryKind::CallerLocation => Some( + data_race::AllocExtra::new_allocation(&data_race, alloc.size, false) + ) + } } else { None }; diff --git a/tests/compile-fail/data_race/alloc_read_race.rs b/tests/compile-fail/data_race/alloc_read_race.rs new file mode 100644 index 0000000000000..53b3866a2ed32 --- /dev/null +++ b/tests/compile-fail/data_race/alloc_read_race.rs @@ -0,0 +1,45 @@ +// ignore-windows: Concurrency on Windows is not supported yet. + +use std::thread::spawn; +use std::ptr::null_mut; +use std::sync::atomic::{Ordering, AtomicPtr}; + +#[derive(Copy, Clone)] +struct EvilSend(pub T); + +unsafe impl Send for EvilSend {} +unsafe impl Sync for EvilSend {} + +pub fn main() { + // Shared atomic pointer + let pointer = AtomicPtr::new(null_mut::()); + let ptr = EvilSend(&pointer as *const AtomicPtr); + + // Note: this is scheduler-dependent + // the operations need to occur in + // order, otherwise the allocation is + // not visible to the other-thread to + // detect the race: + // 1. alloc + // 2. write + unsafe { + let j1 = spawn(move || { + //Concurrent allocate the memory. + //Uses relaxed semantics to not generate + //a release sequence. + let pointer = &*ptr.0; + pointer.store(Box::into_raw(Box::new(0usize)), Ordering::Relaxed); + }); + + let j2 = spawn(move || { + let pointer = &*ptr.0; + *pointer.load(Ordering::Relaxed) //~ ERROR Data race + }); + + j1.join().unwrap(); + j2.join().unwrap(); + + // Clean up memory, will never be executed + drop(Box::from_raw(pointer.load(Ordering::Relaxed))); + } +} diff --git a/tests/compile-fail/data_race/alloc_write_race.rs b/tests/compile-fail/data_race/alloc_write_race.rs new file mode 100644 index 0000000000000..e84ffa9dfef34 --- /dev/null +++ b/tests/compile-fail/data_race/alloc_write_race.rs @@ -0,0 +1,45 @@ +// ignore-windows: Concurrency on Windows is not supported yet. + +use std::thread::spawn; +use std::ptr::null_mut; +use std::sync::atomic::{Ordering, AtomicPtr}; + +#[derive(Copy, Clone)] +struct EvilSend(pub T); + +unsafe impl Send for EvilSend {} +unsafe impl Sync for EvilSend {} + +pub fn main() { + // Shared atomic pointer + let pointer = AtomicPtr::new(null_mut::()); + let ptr = EvilSend(&pointer as *const AtomicPtr); + + // Note: this is scheduler-dependent + // the operations need to occur in + // order, otherwise the allocation is + // not visible to the other-thread to + // detect the race: + // 1. alloc + // 2. write + unsafe { + let j1 = spawn(move || { + //Concurrent allocate the memory. + //Uses relaxed semantics to not generate + //a release sequence. + let pointer = &*ptr.0; + pointer.store(Box::into_raw(Box::new(0usize)), Ordering::Relaxed); + }); + + let j2 = spawn(move || { + let pointer = &*ptr.0; + *pointer.load(Ordering::Relaxed) = 2; //~ ERROR Data race + }); + + j1.join().unwrap(); + j2.join().unwrap(); + + // Clean up memory, will never be executed + drop(Box::from_raw(pointer.load(Ordering::Relaxed))); + } +} diff --git a/tests/compile-fail/data_race/dealloc_read_race.rs b/tests/compile-fail/data_race/dealloc_read_race.rs new file mode 100644 index 0000000000000..f6479d246f8d7 --- /dev/null +++ b/tests/compile-fail/data_race/dealloc_read_race.rs @@ -0,0 +1,32 @@ +// ignore-windows: Concurrency on Windows is not supported yet. + +use std::thread::spawn; + +#[derive(Copy, Clone)] +struct EvilSend(pub T); + +unsafe impl Send for EvilSend {} +unsafe impl Sync for EvilSend {} + +extern "Rust" { + fn __rust_dealloc(ptr: *mut u8, size: usize, align: usize); +} + +pub fn main() { + // Shared atomic pointer + let pointer: *mut usize = Box::into_raw(Box::new(0usize)); + let ptr = EvilSend(pointer); + + unsafe { + let j1 = spawn(move || { + *ptr.0 + }); + + let j2 = spawn(move || { + __rust_dealloc(ptr.0 as *mut _, std::mem::size_of::(), std::mem::align_of::()); //~ ERROR Data race + }); + + j1.join().unwrap(); + j2.join().unwrap(); + } +} diff --git a/tests/compile-fail/data_race/dealloc_read_race_stack.rs b/tests/compile-fail/data_race/dealloc_read_race_stack.rs new file mode 100644 index 0000000000000..67eda4d431e68 --- /dev/null +++ b/tests/compile-fail/data_race/dealloc_read_race_stack.rs @@ -0,0 +1,52 @@ +// ignore-windows: Concurrency on Windows is not supported yet. +// compile-flags: -Zmiri-disable-isolation + +use std::thread::{spawn, sleep}; +use std::ptr::null_mut; +use std::sync::atomic::{Ordering, AtomicPtr}; +use std::time::Duration; + +#[derive(Copy, Clone)] +struct EvilSend(pub T); + +unsafe impl Send for EvilSend {} +unsafe impl Sync for EvilSend {} + +pub fn main() { + // Shared atomic pointer + let pointer = AtomicPtr::new(null_mut::()); + let ptr = EvilSend(&pointer as *const AtomicPtr); + + // Note: this is scheduler-dependent + // the operations need to occur in + // order, otherwise the allocation is + // not visible to the other-thread to + // detect the race: + // 1. stack-allocate + // 2. read + // 3. stack-deallocate + unsafe { + let j1 = spawn(move || { + //Concurrent allocate the memory. + //Uses relaxed semantics to not generate + //a release sequence. + let pointer = &*ptr.0; + { + let mut stack_var = 0usize; + + pointer.store(&mut stack_var as *mut _, Ordering::Release); + + sleep(Duration::from_millis(100)); + + } //~ ERROR Data race + }); + + let j2 = spawn(move || { + let pointer = &*ptr.0; + *pointer.load(Ordering::Acquire) + }); + + j1.join().unwrap(); + j2.join().unwrap(); + } +} diff --git a/tests/compile-fail/data_race/dealloc_read_race_stack_drop.rs b/tests/compile-fail/data_race/dealloc_read_race_stack_drop.rs new file mode 100644 index 0000000000000..81ad50c44a056 --- /dev/null +++ b/tests/compile-fail/data_race/dealloc_read_race_stack_drop.rs @@ -0,0 +1,53 @@ +// ignore-windows: Concurrency on Windows is not supported yet. +// compile-flags: -Zmiri-disable-isolation + +use std::thread::{spawn, sleep}; +use std::ptr::null_mut; +use std::sync::atomic::{Ordering, AtomicPtr}; +use std::time::Duration; + +#[derive(Copy, Clone)] +struct EvilSend(pub T); + +unsafe impl Send for EvilSend {} +unsafe impl Sync for EvilSend {} + +pub fn main() { + // Shared atomic pointer + let pointer = AtomicPtr::new(null_mut::()); + let ptr = EvilSend(&pointer as *const AtomicPtr); + + // Note: this is scheduler-dependent + // the operations need to occur in + // order, otherwise the allocation is + // not visible to the other-thread to + // detect the race: + // 1. stack-allocate + // 2. read + // 3. stack-deallocate + unsafe { + let j1 = spawn(move || { + //Concurrent allocate the memory. + //Uses relaxed semantics to not generate + //a release sequence. + let pointer = &*ptr.0; + + let mut stack_var = 0usize; + + pointer.store(&mut stack_var as *mut _, Ordering::Release); + + sleep(Duration::from_millis(100)); + + // NOTE: the race is also detected with thread 0, and so reported for thread 0 instead of 2, unsure of the cause. + drop(stack_var); + }); //~ ERROR Data race detected between DEALLOCATE on Thread(id = 1) and READ on Thread(id = 0, name = "main") + + let j2 = spawn(move || { + let pointer = &*ptr.0; + *pointer.load(Ordering::Acquire) + }); + + j1.join().unwrap(); + j2.join().unwrap(); + } +} diff --git a/tests/compile-fail/data_race/dealloc_write_race.rs b/tests/compile-fail/data_race/dealloc_write_race.rs new file mode 100644 index 0000000000000..e2527f6e90452 --- /dev/null +++ b/tests/compile-fail/data_race/dealloc_write_race.rs @@ -0,0 +1,31 @@ +// ignore-windows: Concurrency on Windows is not supported yet. + +use std::thread::spawn; + +#[derive(Copy, Clone)] +struct EvilSend(pub T); + +unsafe impl Send for EvilSend {} +unsafe impl Sync for EvilSend {} + +extern "Rust" { + fn __rust_dealloc(ptr: *mut u8, size: usize, align: usize); +} +pub fn main() { + // Shared atomic pointer + let pointer: *mut usize = Box::into_raw(Box::new(0usize)); + let ptr = EvilSend(pointer); + + unsafe { + let j1 = spawn(move || { + *ptr.0 = 2; + }); + + let j2 = spawn(move || { + __rust_dealloc(ptr.0 as *mut _, std::mem::size_of::(), std::mem::align_of::()); //~ ERROR Data race + }); + + j1.join().unwrap(); + j2.join().unwrap(); + } +} diff --git a/tests/compile-fail/data_race/dealloc_write_race_stack.rs b/tests/compile-fail/data_race/dealloc_write_race_stack.rs new file mode 100644 index 0000000000000..cda6e317aaeb2 --- /dev/null +++ b/tests/compile-fail/data_race/dealloc_write_race_stack.rs @@ -0,0 +1,52 @@ +// ignore-windows: Concurrency on Windows is not supported yet. +// compile-flags: -Zmiri-disable-isolation + +use std::thread::{spawn, sleep}; +use std::ptr::null_mut; +use std::sync::atomic::{Ordering, AtomicPtr}; +use std::time::Duration; + +#[derive(Copy, Clone)] +struct EvilSend(pub T); + +unsafe impl Send for EvilSend {} +unsafe impl Sync for EvilSend {} + +pub fn main() { + // Shared atomic pointer + let pointer = AtomicPtr::new(null_mut::()); + let ptr = EvilSend(&pointer as *const AtomicPtr); + + // Note: this is scheduler-dependent + // the operations need to occur in + // order, otherwise the allocation is + // not visible to the other-thread to + // detect the race: + // 1. stack-allocate + // 2. read + // 3. stack-deallocate + unsafe { + let j1 = spawn(move || { + //Concurrent allocate the memory. + //Uses relaxed semantics to not generate + //a release sequence. + let pointer = &*ptr.0; + { + let mut stack_var = 0usize; + + pointer.store(&mut stack_var as *mut _, Ordering::Release); + + sleep(Duration::from_millis(100)); + + } //~ ERROR Data race + }); + + let j2 = spawn(move || { + let pointer = &*ptr.0; + *pointer.load(Ordering::Acquire) = 3; + }); + + j1.join().unwrap(); + j2.join().unwrap(); + } +} diff --git a/tests/compile-fail/data_race/dealloc_write_race_stack_drop.rs b/tests/compile-fail/data_race/dealloc_write_race_stack_drop.rs new file mode 100644 index 0000000000000..9a633518a214d --- /dev/null +++ b/tests/compile-fail/data_race/dealloc_write_race_stack_drop.rs @@ -0,0 +1,52 @@ +// ignore-windows: Concurrency on Windows is not supported yet. +// compile-flags: -Zmiri-disable-isolation + +use std::thread::{spawn, sleep}; +use std::ptr::null_mut; +use std::sync::atomic::{Ordering, AtomicPtr}; +use std::time::Duration; + +#[derive(Copy, Clone)] +struct EvilSend(pub T); + +unsafe impl Send for EvilSend {} +unsafe impl Sync for EvilSend {} + +pub fn main() { + // Shared atomic pointer + let pointer = AtomicPtr::new(null_mut::()); + let ptr = EvilSend(&pointer as *const AtomicPtr); + + // Note: this is scheduler-dependent + // the operations need to occur in + // order, otherwise the allocation is + // not visible to the other-thread to + // detect the race: + // 1. stack-allocate + // 2. read + // 3. stack-deallocate + unsafe { + let j1 = spawn(move || { + //Concurrent allocate the memory. + //Uses relaxed semantics to not generate + //a release sequence. + let pointer = &*ptr.0; + + let mut stack_var = 0usize; + + pointer.store(&mut stack_var as *mut _, Ordering::Release); + + sleep(Duration::from_millis(100)); + + drop(stack_var); //~ ERROR Data race + }); + + let j2 = spawn(move || { + let pointer = &*ptr.0; + *pointer.load(Ordering::Acquire) = 3; + }); + + j1.join().unwrap(); + j2.join().unwrap(); + } +} diff --git a/tests/compile-fail/data_race/read_write_race_stack.rs b/tests/compile-fail/data_race/read_write_race_stack.rs new file mode 100644 index 0000000000000..1762e12c28f0d --- /dev/null +++ b/tests/compile-fail/data_race/read_write_race_stack.rs @@ -0,0 +1,55 @@ +// ignore-windows: Concurrency on Windows is not supported yet. +// compile-flags: -Zmiri-disable-isolation + +use std::thread::{spawn, sleep}; +use std::ptr::null_mut; +use std::sync::atomic::{Ordering, AtomicPtr}; +use std::time::Duration; + +#[derive(Copy, Clone)] +struct EvilSend(pub T); + +unsafe impl Send for EvilSend {} +unsafe impl Sync for EvilSend {} + +pub fn main() { + // Shared atomic pointer + let pointer = AtomicPtr::new(null_mut::()); + let ptr = EvilSend(&pointer as *const AtomicPtr); + + // Note: this is scheduler-dependent + // the operations need to occur in + // order, otherwise the allocation is + // not visible to the other-thread to + // detect the race: + // 1. stack-allocate + // 2. atomic_store + // 3. atomic_load + // 4. write-value + // 5. read-value + unsafe { + let j1 = spawn(move || { + //Concurrent allocate the memory. + //Uses relaxed semantics to not generate + //a release sequence. + let pointer = &*ptr.0; + + let mut stack_var = 0usize; + + pointer.store(&mut stack_var as *mut _, Ordering::Release); + + sleep(Duration::from_millis(100)); + + //read + stack_var //~ ERROR Data race + }); + + let j2 = spawn(move || { + let pointer = &*ptr.0; + *pointer.load(Ordering::Acquire) = 3; + }); + + j1.join().unwrap(); + j2.join().unwrap(); + } +} diff --git a/tests/compile-fail/data_race/write_write_race_stack.rs b/tests/compile-fail/data_race/write_write_race_stack.rs new file mode 100644 index 0000000000000..9acc26685d894 --- /dev/null +++ b/tests/compile-fail/data_race/write_write_race_stack.rs @@ -0,0 +1,57 @@ +// ignore-windows: Concurrency on Windows is not supported yet. +// compile-flags: -Zmiri-disable-isolation + +use std::thread::{spawn, sleep}; +use std::ptr::null_mut; +use std::sync::atomic::{Ordering, AtomicPtr}; +use std::time::Duration; + +#[derive(Copy, Clone)] +struct EvilSend(pub T); + +unsafe impl Send for EvilSend {} +unsafe impl Sync for EvilSend {} + +pub fn main() { + // Shared atomic pointer + let pointer = AtomicPtr::new(null_mut::()); + let ptr = EvilSend(&pointer as *const AtomicPtr); + + // Note: this is scheduler-dependent + // the operations need to occur in + // order, otherwise the allocation is + // not visible to the other-thread to + // detect the race: + // 1. stack-allocate + // 2. atomic_store + // 3. atomic_load + // 4. write-value + // 5. write-value + unsafe { + let j1 = spawn(move || { + //Concurrent allocate the memory. + //Uses relaxed semantics to not generate + //a release sequence. + let pointer = &*ptr.0; + + let mut stack_var = 0usize; + + pointer.store(&mut stack_var as *mut _, Ordering::Release); + + sleep(Duration::from_millis(100)); + + stack_var = 1usize; //~ ERROR Data race + + // read to silence errors + stack_var + }); + + let j2 = spawn(move || { + let pointer = &*ptr.0; + *pointer.load(Ordering::Acquire) = 3; + }); + + j1.join().unwrap(); + j2.join().unwrap(); + } +} diff --git a/tests/run-pass/concurrency/issue1643.rs b/tests/run-pass/concurrency/issue1643.rs new file mode 100644 index 0000000000000..c0956569ad8f9 --- /dev/null +++ b/tests/run-pass/concurrency/issue1643.rs @@ -0,0 +1,14 @@ +use std::thread::spawn; + +fn initialize() { + initialize_inner(&mut || false) +} + +fn initialize_inner(_init: &mut dyn FnMut() -> bool) {} + +fn main() { + let j1 = spawn(initialize); + let j2 = spawn(initialize); + j1.join().unwrap(); + j2.join().unwrap(); +} diff --git a/tests/run-pass/concurrency/issue1643.stderr b/tests/run-pass/concurrency/issue1643.stderr new file mode 100644 index 0000000000000..03676519d4f1c --- /dev/null +++ b/tests/run-pass/concurrency/issue1643.stderr @@ -0,0 +1,2 @@ +warning: thread support is experimental and incomplete: weak memory effects are not emulated. + From 1ded6d328aa0c1a93f81491ea7821e9b6a7e0d12 Mon Sep 17 00:00:00 2001 From: JCTyBlaidd Date: Mon, 7 Dec 2020 18:21:12 +0000 Subject: [PATCH 2472/3747] Remove old FIXME --- src/data_race.rs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/data_race.rs b/src/data_race.rs index a70c4a4e4c70f..382a87e2f5151 100644 --- a/src/data_race.rs +++ b/src/data_race.rs @@ -679,14 +679,12 @@ impl VClockAlloc { /// Create a new data-race detector for newly allocated memory. pub fn new_allocation(global: &MemoryExtra, len: Size, track_alloc: bool) -> VClockAlloc { - //FIXME: stack allocations are currently ignored due to the lazy nature of stack - // allocation, this results in data-races being missed. - let (alloc_timestamp, alloc_index) = if !track_alloc { - (0, VectorIdx::MAX_INDEX) - }else{ + let (alloc_timestamp, alloc_index) = if track_alloc { let (alloc_index, clocks) = global.current_thread_state(); let alloc_timestamp = clocks.clock[alloc_index]; (alloc_timestamp, alloc_index) + }else{ + (0, VectorIdx::MAX_INDEX) }; VClockAlloc { global: Rc::clone(global), From f4bcef11136922e17eb7d202ebe76d28e6b4e7d4 Mon Sep 17 00:00:00 2001 From: JCTyBlaidd Date: Mon, 7 Dec 2020 18:58:31 +0000 Subject: [PATCH 2473/3747] Increase sleep times for the scheduler --- tests/compile-fail/data_race/dangling_thread_async_race.rs | 2 +- tests/compile-fail/data_race/dangling_thread_race.rs | 2 +- tests/compile-fail/data_race/dealloc_read_race_stack.rs | 2 +- tests/compile-fail/data_race/dealloc_read_race_stack_drop.rs | 2 +- tests/compile-fail/data_race/dealloc_write_race_stack.rs | 2 +- tests/compile-fail/data_race/dealloc_write_race_stack_drop.rs | 2 +- tests/compile-fail/data_race/read_write_race_stack.rs | 2 +- tests/compile-fail/data_race/release_seq_race.rs | 4 ++-- tests/compile-fail/data_race/write_write_race_stack.rs | 2 +- 9 files changed, 10 insertions(+), 10 deletions(-) diff --git a/tests/compile-fail/data_race/dangling_thread_async_race.rs b/tests/compile-fail/data_race/dangling_thread_async_race.rs index d8b5d82f83048..ece831685287b 100644 --- a/tests/compile-fail/data_race/dangling_thread_async_race.rs +++ b/tests/compile-fail/data_race/dangling_thread_async_race.rs @@ -26,7 +26,7 @@ fn main() { // Detatch the thread and sleep until it terminates mem::drop(join); - sleep(Duration::from_millis(100)); + sleep(Duration::from_millis(1000)); // Spawn and immediately join a thread // to execute the join code-path diff --git a/tests/compile-fail/data_race/dangling_thread_race.rs b/tests/compile-fail/data_race/dangling_thread_race.rs index 172b05bd4f0bb..873d10b788f18 100644 --- a/tests/compile-fail/data_race/dangling_thread_race.rs +++ b/tests/compile-fail/data_race/dangling_thread_race.rs @@ -26,7 +26,7 @@ fn main() { // Detatch the thread and sleep until it terminates mem::drop(join); - sleep(Duration::from_millis(100)); + sleep(Duration::from_millis(1000)); // Spawn and immediately join a thread // to execute the join code-path diff --git a/tests/compile-fail/data_race/dealloc_read_race_stack.rs b/tests/compile-fail/data_race/dealloc_read_race_stack.rs index 67eda4d431e68..95d7acea26607 100644 --- a/tests/compile-fail/data_race/dealloc_read_race_stack.rs +++ b/tests/compile-fail/data_race/dealloc_read_race_stack.rs @@ -36,7 +36,7 @@ pub fn main() { pointer.store(&mut stack_var as *mut _, Ordering::Release); - sleep(Duration::from_millis(100)); + sleep(Duration::from_millis(1000)); } //~ ERROR Data race }); diff --git a/tests/compile-fail/data_race/dealloc_read_race_stack_drop.rs b/tests/compile-fail/data_race/dealloc_read_race_stack_drop.rs index 81ad50c44a056..ecdd841965e93 100644 --- a/tests/compile-fail/data_race/dealloc_read_race_stack_drop.rs +++ b/tests/compile-fail/data_race/dealloc_read_race_stack_drop.rs @@ -36,7 +36,7 @@ pub fn main() { pointer.store(&mut stack_var as *mut _, Ordering::Release); - sleep(Duration::from_millis(100)); + sleep(Duration::from_millis(1000)); // NOTE: the race is also detected with thread 0, and so reported for thread 0 instead of 2, unsure of the cause. drop(stack_var); diff --git a/tests/compile-fail/data_race/dealloc_write_race_stack.rs b/tests/compile-fail/data_race/dealloc_write_race_stack.rs index cda6e317aaeb2..8008b6cdb91e7 100644 --- a/tests/compile-fail/data_race/dealloc_write_race_stack.rs +++ b/tests/compile-fail/data_race/dealloc_write_race_stack.rs @@ -36,7 +36,7 @@ pub fn main() { pointer.store(&mut stack_var as *mut _, Ordering::Release); - sleep(Duration::from_millis(100)); + sleep(Duration::from_millis(1000)); } //~ ERROR Data race }); diff --git a/tests/compile-fail/data_race/dealloc_write_race_stack_drop.rs b/tests/compile-fail/data_race/dealloc_write_race_stack_drop.rs index 9a633518a214d..733cdb7b1f04a 100644 --- a/tests/compile-fail/data_race/dealloc_write_race_stack_drop.rs +++ b/tests/compile-fail/data_race/dealloc_write_race_stack_drop.rs @@ -36,7 +36,7 @@ pub fn main() { pointer.store(&mut stack_var as *mut _, Ordering::Release); - sleep(Duration::from_millis(100)); + sleep(Duration::from_millis(1000)); drop(stack_var); //~ ERROR Data race }); diff --git a/tests/compile-fail/data_race/read_write_race_stack.rs b/tests/compile-fail/data_race/read_write_race_stack.rs index 1762e12c28f0d..fcd8a0606bae1 100644 --- a/tests/compile-fail/data_race/read_write_race_stack.rs +++ b/tests/compile-fail/data_race/read_write_race_stack.rs @@ -38,7 +38,7 @@ pub fn main() { pointer.store(&mut stack_var as *mut _, Ordering::Release); - sleep(Duration::from_millis(100)); + sleep(Duration::from_millis(1000)); //read stack_var //~ ERROR Data race diff --git a/tests/compile-fail/data_race/release_seq_race.rs b/tests/compile-fail/data_race/release_seq_race.rs index 59263cb712042..d0d625a6ce177 100644 --- a/tests/compile-fail/data_race/release_seq_race.rs +++ b/tests/compile-fail/data_race/release_seq_race.rs @@ -30,7 +30,7 @@ pub fn main() { let j1 = spawn(move || { *c.0 = 1; SYNC.store(1, Ordering::Release); - sleep(Duration::from_millis(100)); + sleep(Duration::from_millis(1000)); SYNC.store(3, Ordering::Relaxed); }); @@ -40,7 +40,7 @@ pub fn main() { }); let j3 = spawn(move || { - sleep(Duration::from_millis(1000)); + sleep(Duration::from_millis(5000)); if SYNC.load(Ordering::Acquire) == 3 { *c.0 //~ ERROR Data race } else { diff --git a/tests/compile-fail/data_race/write_write_race_stack.rs b/tests/compile-fail/data_race/write_write_race_stack.rs index 9acc26685d894..46d0911be189f 100644 --- a/tests/compile-fail/data_race/write_write_race_stack.rs +++ b/tests/compile-fail/data_race/write_write_race_stack.rs @@ -38,7 +38,7 @@ pub fn main() { pointer.store(&mut stack_var as *mut _, Ordering::Release); - sleep(Duration::from_millis(100)); + sleep(Duration::from_millis(1000)); stack_var = 1usize; //~ ERROR Data race From c4ccd0b6a1dbf52a98fa3e086919346213f87f6e Mon Sep 17 00:00:00 2001 From: JCTyblaidd Date: Mon, 7 Dec 2020 19:10:01 +0000 Subject: [PATCH 2474/3747] Fix nits Co-authored-by: bjorn3 --- src/data_race.rs | 2 -- tests/compile-fail/data_race/alloc_read_race.rs | 6 +++--- tests/compile-fail/data_race/alloc_write_race.rs | 6 +++--- tests/compile-fail/data_race/dealloc_read_race_stack.rs | 6 +++--- .../compile-fail/data_race/dealloc_read_race_stack_drop.rs | 6 +++--- tests/compile-fail/data_race/dealloc_write_race_stack.rs | 6 +++--- .../compile-fail/data_race/dealloc_write_race_stack_drop.rs | 6 +++--- tests/compile-fail/data_race/read_write_race_stack.rs | 6 +++--- tests/compile-fail/data_race/write_write_race_stack.rs | 6 +++--- 9 files changed, 24 insertions(+), 26 deletions(-) diff --git a/src/data_race.rs b/src/data_race.rs index 382a87e2f5151..052b924530829 100644 --- a/src/data_race.rs +++ b/src/data_race.rs @@ -240,7 +240,6 @@ struct MemoryCellClocks { } impl MemoryCellClocks { - /// Create a new set of clocks representing memory allocated /// at a given vector timestamp and index. fn new(alloc: VTimestamp, alloc_index: VectorIdx) -> Self { @@ -676,7 +675,6 @@ pub struct VClockAlloc { } impl VClockAlloc { - /// Create a new data-race detector for newly allocated memory. pub fn new_allocation(global: &MemoryExtra, len: Size, track_alloc: bool) -> VClockAlloc { let (alloc_timestamp, alloc_index) = if track_alloc { diff --git a/tests/compile-fail/data_race/alloc_read_race.rs b/tests/compile-fail/data_race/alloc_read_race.rs index 53b3866a2ed32..9ebb793c71ba9 100644 --- a/tests/compile-fail/data_race/alloc_read_race.rs +++ b/tests/compile-fail/data_race/alloc_read_race.rs @@ -24,9 +24,9 @@ pub fn main() { // 2. write unsafe { let j1 = spawn(move || { - //Concurrent allocate the memory. - //Uses relaxed semantics to not generate - //a release sequence. + // Concurrent allocate the memory. + // Uses relaxed semantics to not generate + // a release sequence. let pointer = &*ptr.0; pointer.store(Box::into_raw(Box::new(0usize)), Ordering::Relaxed); }); diff --git a/tests/compile-fail/data_race/alloc_write_race.rs b/tests/compile-fail/data_race/alloc_write_race.rs index e84ffa9dfef34..229d3cea2c934 100644 --- a/tests/compile-fail/data_race/alloc_write_race.rs +++ b/tests/compile-fail/data_race/alloc_write_race.rs @@ -24,9 +24,9 @@ pub fn main() { // 2. write unsafe { let j1 = spawn(move || { - //Concurrent allocate the memory. - //Uses relaxed semantics to not generate - //a release sequence. + // Concurrent allocate the memory. + // Uses relaxed semantics to not generate + // a release sequence. let pointer = &*ptr.0; pointer.store(Box::into_raw(Box::new(0usize)), Ordering::Relaxed); }); diff --git a/tests/compile-fail/data_race/dealloc_read_race_stack.rs b/tests/compile-fail/data_race/dealloc_read_race_stack.rs index 95d7acea26607..275d1d1cccf0c 100644 --- a/tests/compile-fail/data_race/dealloc_read_race_stack.rs +++ b/tests/compile-fail/data_race/dealloc_read_race_stack.rs @@ -27,9 +27,9 @@ pub fn main() { // 3. stack-deallocate unsafe { let j1 = spawn(move || { - //Concurrent allocate the memory. - //Uses relaxed semantics to not generate - //a release sequence. + // Concurrent allocate the memory. + // Uses relaxed semantics to not generate + // a release sequence. let pointer = &*ptr.0; { let mut stack_var = 0usize; diff --git a/tests/compile-fail/data_race/dealloc_read_race_stack_drop.rs b/tests/compile-fail/data_race/dealloc_read_race_stack_drop.rs index ecdd841965e93..d5131687d78b3 100644 --- a/tests/compile-fail/data_race/dealloc_read_race_stack_drop.rs +++ b/tests/compile-fail/data_race/dealloc_read_race_stack_drop.rs @@ -27,9 +27,9 @@ pub fn main() { // 3. stack-deallocate unsafe { let j1 = spawn(move || { - //Concurrent allocate the memory. - //Uses relaxed semantics to not generate - //a release sequence. + // Concurrent allocate the memory. + // Uses relaxed semantics to not generate + // a release sequence. let pointer = &*ptr.0; let mut stack_var = 0usize; diff --git a/tests/compile-fail/data_race/dealloc_write_race_stack.rs b/tests/compile-fail/data_race/dealloc_write_race_stack.rs index 8008b6cdb91e7..3fcbe7661ff4a 100644 --- a/tests/compile-fail/data_race/dealloc_write_race_stack.rs +++ b/tests/compile-fail/data_race/dealloc_write_race_stack.rs @@ -27,9 +27,9 @@ pub fn main() { // 3. stack-deallocate unsafe { let j1 = spawn(move || { - //Concurrent allocate the memory. - //Uses relaxed semantics to not generate - //a release sequence. + // Concurrent allocate the memory. + // Uses relaxed semantics to not generate + // a release sequence. let pointer = &*ptr.0; { let mut stack_var = 0usize; diff --git a/tests/compile-fail/data_race/dealloc_write_race_stack_drop.rs b/tests/compile-fail/data_race/dealloc_write_race_stack_drop.rs index 733cdb7b1f04a..5483be9f788fd 100644 --- a/tests/compile-fail/data_race/dealloc_write_race_stack_drop.rs +++ b/tests/compile-fail/data_race/dealloc_write_race_stack_drop.rs @@ -27,9 +27,9 @@ pub fn main() { // 3. stack-deallocate unsafe { let j1 = spawn(move || { - //Concurrent allocate the memory. - //Uses relaxed semantics to not generate - //a release sequence. + // Concurrent allocate the memory. + // Uses relaxed semantics to not generate + // a release sequence. let pointer = &*ptr.0; let mut stack_var = 0usize; diff --git a/tests/compile-fail/data_race/read_write_race_stack.rs b/tests/compile-fail/data_race/read_write_race_stack.rs index fcd8a0606bae1..7f2dbcc6ed5df 100644 --- a/tests/compile-fail/data_race/read_write_race_stack.rs +++ b/tests/compile-fail/data_race/read_write_race_stack.rs @@ -29,9 +29,9 @@ pub fn main() { // 5. read-value unsafe { let j1 = spawn(move || { - //Concurrent allocate the memory. - //Uses relaxed semantics to not generate - //a release sequence. + // Concurrent allocate the memory. + // Uses relaxed semantics to not generate + // a release sequence. let pointer = &*ptr.0; let mut stack_var = 0usize; diff --git a/tests/compile-fail/data_race/write_write_race_stack.rs b/tests/compile-fail/data_race/write_write_race_stack.rs index 46d0911be189f..51bf0120d69fd 100644 --- a/tests/compile-fail/data_race/write_write_race_stack.rs +++ b/tests/compile-fail/data_race/write_write_race_stack.rs @@ -29,9 +29,9 @@ pub fn main() { // 5. write-value unsafe { let j1 = spawn(move || { - //Concurrent allocate the memory. - //Uses relaxed semantics to not generate - //a release sequence. + // Concurrent allocate the memory. + // Uses relaxed semantics to not generate + // a release sequence. let pointer = &*ptr.0; let mut stack_var = 0usize; From fbe7fbb8900a93cbe080db35e68f35fd515fa87d Mon Sep 17 00:00:00 2001 From: JCTyBlaidd Date: Mon, 7 Dec 2020 21:13:11 +0000 Subject: [PATCH 2475/3747] Add concurrent caller location test --- .../concurrency/concurrent_caller_location.rs | 17 +++++++++++++++++ .../concurrent_caller_location.stderr | 2 ++ 2 files changed, 19 insertions(+) create mode 100644 tests/run-pass/concurrency/concurrent_caller_location.rs create mode 100644 tests/run-pass/concurrency/concurrent_caller_location.stderr diff --git a/tests/run-pass/concurrency/concurrent_caller_location.rs b/tests/run-pass/concurrency/concurrent_caller_location.rs new file mode 100644 index 0000000000000..e3e2f9ac60aee --- /dev/null +++ b/tests/run-pass/concurrency/concurrent_caller_location.rs @@ -0,0 +1,17 @@ +use std::thread::spawn; +use std::panic::Location; + +fn initialize() { + let _ignore = initialize_inner(); +} + +fn initialize_inner() -> &'static Location<'static> { + Location::caller() +} + +fn main() { + let j1 = spawn(initialize); + let j2 = spawn(initialize); + j1.join().unwrap(); + j2.join().unwrap(); +} diff --git a/tests/run-pass/concurrency/concurrent_caller_location.stderr b/tests/run-pass/concurrency/concurrent_caller_location.stderr new file mode 100644 index 0000000000000..03676519d4f1c --- /dev/null +++ b/tests/run-pass/concurrency/concurrent_caller_location.stderr @@ -0,0 +1,2 @@ +warning: thread support is experimental and incomplete: weak memory effects are not emulated. + From 296ba8b1c84f65d123fa5b35f6f2e47e73710b08 Mon Sep 17 00:00:00 2001 From: JCTyBlaidd Date: Mon, 7 Dec 2020 23:18:57 +0000 Subject: [PATCH 2476/3747] Fix bug with reporting wrong thread for races with reads & add thread ids to data-race tests --- src/data_race.rs | 19 +++++++++++-------- .../compile-fail/data_race/alloc_read_race.rs | 4 +++- .../data_race/alloc_write_race.rs | 11 ++++++++--- .../data_race/atomic_read_na_write_race1.rs | 2 +- .../data_race/atomic_read_na_write_race2.rs | 2 +- .../data_race/atomic_write_na_read_race1.rs | 2 +- .../data_race/atomic_write_na_read_race2.rs | 2 +- .../data_race/atomic_write_na_write_race1.rs | 2 +- .../data_race/atomic_write_na_write_race2.rs | 2 +- .../data_race/dangling_thread_async_race.rs | 4 ++-- .../data_race/dangling_thread_race.rs | 2 +- .../data_race/dealloc_read_race.rs | 2 +- .../data_race/dealloc_read_race_stack.rs | 2 +- .../data_race/dealloc_read_race_stack_drop.rs | 3 +-- .../data_race/dealloc_write_race.rs | 2 +- .../data_race/dealloc_write_race_stack.rs | 2 +- .../dealloc_write_race_stack_drop.rs | 3 ++- .../data_race/enable_after_join_to_main.rs | 2 +- .../compile-fail/data_race/read_write_race.rs | 2 +- .../data_race/read_write_race_stack.rs | 2 +- .../data_race/relax_acquire_race.rs | 2 +- .../data_race/release_seq_race.rs | 2 +- .../data_race/release_seq_race_same_thread.rs | 2 +- tests/compile-fail/data_race/rmw_race.rs | 2 +- .../data_race/write_write_race.rs | 2 +- .../data_race/write_write_race_stack.rs | 2 +- 26 files changed, 47 insertions(+), 37 deletions(-) diff --git a/src/data_race.rs b/src/data_race.rs index 052b924530829..7211f3176350b 100644 --- a/src/data_race.rs +++ b/src/data_race.rs @@ -204,9 +204,9 @@ enum WriteType { impl WriteType { fn get_descriptor(self) -> &'static str { match self { - WriteType::Allocate => "ALLOCATE", - WriteType::Write => "WRITE", - WriteType::Deallocate => "DEALLOCATE", + WriteType::Allocate => "Allocate", + WriteType::Write => "Write", + WriteType::Deallocate => "Deallocate", } } } @@ -695,6 +695,7 @@ impl VClockAlloc { // Find an index, if one exists where the value // in `l` is greater than the value in `r`. fn find_gt_index(l: &VClock, r: &VClock) -> Option { + log::info!("Find index where not {:?} <= {:?}", l, r); let l_slice = l.as_slice(); let r_slice = r.as_slice(); l_slice @@ -714,7 +715,7 @@ impl VClockAlloc { .enumerate() .find_map(|(idx, &r)| if r == 0 { None } else { Some(idx) }) .expect("Invalid VClock Invariant"); - Some(idx) + Some(idx + r_slice.len()) } else { None } @@ -747,16 +748,16 @@ impl VClockAlloc { write_clock = VClock::new_with_index(range.write_index, range.write); (range.write_type.get_descriptor(), range.write_index, &write_clock) } else if let Some(idx) = Self::find_gt_index(&range.read, ¤t_clocks.clock) { - ("READ", idx, &range.read) + ("Read", idx, &range.read) } else if !is_atomic { if let Some(atomic) = range.atomic() { if let Some(idx) = Self::find_gt_index(&atomic.write_vector, ¤t_clocks.clock) { - ("ATOMIC_STORE", idx, &atomic.write_vector) + ("Atomic Store", idx, &atomic.write_vector) } else if let Some(idx) = Self::find_gt_index(&atomic.read_vector, ¤t_clocks.clock) { - ("ATOMIC_LOAD", idx, &atomic.read_vector) + ("Atomic Load", idx, &atomic.read_vector) } else { unreachable!( "Failed to report data-race for non-atomic operation: no race found" @@ -807,7 +808,7 @@ impl VClockAlloc { return Self::report_data_race( &self.global, range, - "READ", + "Read", false, pointer, len, @@ -1167,6 +1168,8 @@ impl GlobalState { vector_info.push(thread) }; + log::info!("Creating thread = {:?} with vector index = {:?}", thread, created_index); + // Mark the chosen vector index as in use by the thread. thread_info[thread].vector_index = Some(created_index); diff --git a/tests/compile-fail/data_race/alloc_read_race.rs b/tests/compile-fail/data_race/alloc_read_race.rs index 9ebb793c71ba9..620a019b65c7e 100644 --- a/tests/compile-fail/data_race/alloc_read_race.rs +++ b/tests/compile-fail/data_race/alloc_read_race.rs @@ -33,7 +33,9 @@ pub fn main() { let j2 = spawn(move || { let pointer = &*ptr.0; - *pointer.load(Ordering::Relaxed) //~ ERROR Data race + + //Note detects with write due to the initialization of memory + *pointer.load(Ordering::Relaxed) //~ ERROR Data race detected between Read on Thread(id = 2) and Write on Thread(id = 1) }); j1.join().unwrap(); diff --git a/tests/compile-fail/data_race/alloc_write_race.rs b/tests/compile-fail/data_race/alloc_write_race.rs index 229d3cea2c934..d9f5af396a2d8 100644 --- a/tests/compile-fail/data_race/alloc_write_race.rs +++ b/tests/compile-fail/data_race/alloc_write_race.rs @@ -10,6 +10,11 @@ struct EvilSend(pub T); unsafe impl Send for EvilSend {} unsafe impl Sync for EvilSend {} +extern "C" { + fn malloc(size: usize) -> *mut u8; + fn free(ptr: *mut u8); +} + pub fn main() { // Shared atomic pointer let pointer = AtomicPtr::new(null_mut::()); @@ -28,18 +33,18 @@ pub fn main() { // Uses relaxed semantics to not generate // a release sequence. let pointer = &*ptr.0; - pointer.store(Box::into_raw(Box::new(0usize)), Ordering::Relaxed); + pointer.store(malloc(std::mem::size_of::()) as *mut usize, Ordering::Relaxed); }); let j2 = spawn(move || { let pointer = &*ptr.0; - *pointer.load(Ordering::Relaxed) = 2; //~ ERROR Data race + *pointer.load(Ordering::Relaxed) = 2; //~ ERROR Data race detected between Write on Thread(id = 2) and Allocate on Thread(id = 1) }); j1.join().unwrap(); j2.join().unwrap(); // Clean up memory, will never be executed - drop(Box::from_raw(pointer.load(Ordering::Relaxed))); + free(pointer.load(Ordering::Relaxed) as *mut _); } } diff --git a/tests/compile-fail/data_race/atomic_read_na_write_race1.rs b/tests/compile-fail/data_race/atomic_read_na_write_race1.rs index 0b9610edc64b3..44860ee628003 100644 --- a/tests/compile-fail/data_race/atomic_read_na_write_race1.rs +++ b/tests/compile-fail/data_race/atomic_read_na_write_race1.rs @@ -22,7 +22,7 @@ pub fn main() { let j2 = spawn(move || { //Equivalent to: (&*c.0).load(Ordering::SeqCst) - atomic_load(c.0 as *mut usize) //~ ERROR Data race + atomic_load(c.0 as *mut usize) //~ ERROR Data race detected between Atomic Load on Thread(id = 2) and Write on Thread(id = 1) }); j1.join().unwrap(); diff --git a/tests/compile-fail/data_race/atomic_read_na_write_race2.rs b/tests/compile-fail/data_race/atomic_read_na_write_race2.rs index 779babefd8e60..6d28e18886cd8 100644 --- a/tests/compile-fail/data_race/atomic_read_na_write_race2.rs +++ b/tests/compile-fail/data_race/atomic_read_na_write_race2.rs @@ -22,7 +22,7 @@ pub fn main() { let j2 = spawn(move || { let atomic_ref = &mut *c.0; - *atomic_ref.get_mut() = 32; //~ ERROR Data race + *atomic_ref.get_mut() = 32; //~ ERROR Data race detected between Write on Thread(id = 2) and Atomic Load on Thread(id = 1) }); j1.join().unwrap(); diff --git a/tests/compile-fail/data_race/atomic_write_na_read_race1.rs b/tests/compile-fail/data_race/atomic_write_na_read_race1.rs index 3211a5ae53442..0b753f6710a5f 100644 --- a/tests/compile-fail/data_race/atomic_write_na_read_race1.rs +++ b/tests/compile-fail/data_race/atomic_write_na_read_race1.rs @@ -22,7 +22,7 @@ pub fn main() { let j2 = spawn(move || { let atomic_ref = &mut *c.0; - *atomic_ref.get_mut() //~ ERROR Data race + *atomic_ref.get_mut() //~ ERROR Data race detected between Read on Thread(id = 2) and Atomic Store on Thread(id = 1) }); j1.join().unwrap(); diff --git a/tests/compile-fail/data_race/atomic_write_na_read_race2.rs b/tests/compile-fail/data_race/atomic_write_na_read_race2.rs index 131d4e07b829f..a9f5fb2fe5bc5 100644 --- a/tests/compile-fail/data_race/atomic_write_na_read_race2.rs +++ b/tests/compile-fail/data_race/atomic_write_na_read_race2.rs @@ -22,7 +22,7 @@ pub fn main() { let j2 = spawn(move || { //Equivalent to: (&*c.0).store(32, Ordering::SeqCst) - atomic_store(c.0 as *mut usize, 32); //~ ERROR Data race + atomic_store(c.0 as *mut usize, 32); //~ ERROR Data race detected between Atomic Store on Thread(id = 2) and Read on Thread(id = 1) }); j1.join().unwrap(); diff --git a/tests/compile-fail/data_race/atomic_write_na_write_race1.rs b/tests/compile-fail/data_race/atomic_write_na_write_race1.rs index 74adf7ae4b8d2..d5a828fa6e41c 100644 --- a/tests/compile-fail/data_race/atomic_write_na_write_race1.rs +++ b/tests/compile-fail/data_race/atomic_write_na_write_race1.rs @@ -22,7 +22,7 @@ pub fn main() { let j2 = spawn(move || { //Equivalent to: (&*c.0).store(64, Ordering::SeqCst) - atomic_store(c.0 as *mut usize, 64); //~ ERROR Data race + atomic_store(c.0 as *mut usize, 64); //~ ERROR Data race detected between Atomic Store on Thread(id = 2) and Write on Thread(id = 1) }); j1.join().unwrap(); diff --git a/tests/compile-fail/data_race/atomic_write_na_write_race2.rs b/tests/compile-fail/data_race/atomic_write_na_write_race2.rs index 75ad755fbd2c3..9812dcd79920a 100644 --- a/tests/compile-fail/data_race/atomic_write_na_write_race2.rs +++ b/tests/compile-fail/data_race/atomic_write_na_write_race2.rs @@ -22,7 +22,7 @@ pub fn main() { let j2 = spawn(move || { let atomic_ref = &mut *c.0; - *atomic_ref.get_mut() = 32; //~ ERROR Data race + *atomic_ref.get_mut() = 32; //~ ERROR Data race detected between Write on Thread(id = 2) and Atomic Store on Thread(id = 1) }); j1.join().unwrap(); diff --git a/tests/compile-fail/data_race/dangling_thread_async_race.rs b/tests/compile-fail/data_race/dangling_thread_async_race.rs index ece831685287b..61587dc6384a2 100644 --- a/tests/compile-fail/data_race/dangling_thread_async_race.rs +++ b/tests/compile-fail/data_race/dangling_thread_async_race.rs @@ -24,7 +24,7 @@ fn main() { }) }; - // Detatch the thread and sleep until it terminates + // Detach the thread and sleep until it terminates mem::drop(join); sleep(Duration::from_millis(1000)); @@ -36,7 +36,7 @@ fn main() { let join2 = unsafe { spawn(move || { - *c.0 = 64; //~ ERROR Data race + *c.0 = 64; //~ ERROR Data race detected between Write on Thread(id = 3) and Write on Thread(id = 1) }) }; diff --git a/tests/compile-fail/data_race/dangling_thread_race.rs b/tests/compile-fail/data_race/dangling_thread_race.rs index 873d10b788f18..c14b68080cc82 100644 --- a/tests/compile-fail/data_race/dangling_thread_race.rs +++ b/tests/compile-fail/data_race/dangling_thread_race.rs @@ -36,6 +36,6 @@ fn main() { unsafe { - *c.0 = 64; //~ ERROR Data race + *c.0 = 64; //~ ERROR Data race detected between Write on Thread(id = 0, name = "main") and Write on Thread(id = 1) } } diff --git a/tests/compile-fail/data_race/dealloc_read_race.rs b/tests/compile-fail/data_race/dealloc_read_race.rs index f6479d246f8d7..14b02e95cc233 100644 --- a/tests/compile-fail/data_race/dealloc_read_race.rs +++ b/tests/compile-fail/data_race/dealloc_read_race.rs @@ -23,7 +23,7 @@ pub fn main() { }); let j2 = spawn(move || { - __rust_dealloc(ptr.0 as *mut _, std::mem::size_of::(), std::mem::align_of::()); //~ ERROR Data race + __rust_dealloc(ptr.0 as *mut _, std::mem::size_of::(), std::mem::align_of::()); //~ ERROR Data race detected between Deallocate on Thread(id = 2) and Read on Thread(id = 1) }); j1.join().unwrap(); diff --git a/tests/compile-fail/data_race/dealloc_read_race_stack.rs b/tests/compile-fail/data_race/dealloc_read_race_stack.rs index 275d1d1cccf0c..8a770563c753f 100644 --- a/tests/compile-fail/data_race/dealloc_read_race_stack.rs +++ b/tests/compile-fail/data_race/dealloc_read_race_stack.rs @@ -38,7 +38,7 @@ pub fn main() { sleep(Duration::from_millis(1000)); - } //~ ERROR Data race + } //~ ERROR Data race detected between Deallocate on Thread(id = 1) and Read on Thread(id = 2) }); let j2 = spawn(move || { diff --git a/tests/compile-fail/data_race/dealloc_read_race_stack_drop.rs b/tests/compile-fail/data_race/dealloc_read_race_stack_drop.rs index d5131687d78b3..315d5eef3f01e 100644 --- a/tests/compile-fail/data_race/dealloc_read_race_stack_drop.rs +++ b/tests/compile-fail/data_race/dealloc_read_race_stack_drop.rs @@ -38,9 +38,8 @@ pub fn main() { sleep(Duration::from_millis(1000)); - // NOTE: the race is also detected with thread 0, and so reported for thread 0 instead of 2, unsure of the cause. drop(stack_var); - }); //~ ERROR Data race detected between DEALLOCATE on Thread(id = 1) and READ on Thread(id = 0, name = "main") + }); //~ ERROR Data race detected between Deallocate on Thread(id = 1) and Read on Thread(id = 2) let j2 = spawn(move || { let pointer = &*ptr.0; diff --git a/tests/compile-fail/data_race/dealloc_write_race.rs b/tests/compile-fail/data_race/dealloc_write_race.rs index e2527f6e90452..edcdfffdb5f53 100644 --- a/tests/compile-fail/data_race/dealloc_write_race.rs +++ b/tests/compile-fail/data_race/dealloc_write_race.rs @@ -22,7 +22,7 @@ pub fn main() { }); let j2 = spawn(move || { - __rust_dealloc(ptr.0 as *mut _, std::mem::size_of::(), std::mem::align_of::()); //~ ERROR Data race + __rust_dealloc(ptr.0 as *mut _, std::mem::size_of::(), std::mem::align_of::()); //~ ERROR Data race detected between Deallocate on Thread(id = 2) and Write on Thread(id = 1) }); j1.join().unwrap(); diff --git a/tests/compile-fail/data_race/dealloc_write_race_stack.rs b/tests/compile-fail/data_race/dealloc_write_race_stack.rs index 3fcbe7661ff4a..a245522b06f37 100644 --- a/tests/compile-fail/data_race/dealloc_write_race_stack.rs +++ b/tests/compile-fail/data_race/dealloc_write_race_stack.rs @@ -38,7 +38,7 @@ pub fn main() { sleep(Duration::from_millis(1000)); - } //~ ERROR Data race + } //~ ERROR Data race detected between Deallocate on Thread(id = 1) and Write on Thread(id = 2) }); let j2 = spawn(move || { diff --git a/tests/compile-fail/data_race/dealloc_write_race_stack_drop.rs b/tests/compile-fail/data_race/dealloc_write_race_stack_drop.rs index 5483be9f788fd..db0bb25277630 100644 --- a/tests/compile-fail/data_race/dealloc_write_race_stack_drop.rs +++ b/tests/compile-fail/data_race/dealloc_write_race_stack_drop.rs @@ -38,7 +38,8 @@ pub fn main() { sleep(Duration::from_millis(1000)); - drop(stack_var); //~ ERROR Data race + // FIXME: find cause of implicit read event + drop(stack_var); //~ ERROR Data race detected between Read on Thread(id = 1) and Write on Thread(id = 2) }); let j2 = spawn(move || { diff --git a/tests/compile-fail/data_race/enable_after_join_to_main.rs b/tests/compile-fail/data_race/enable_after_join_to_main.rs index c294317771379..832158a34a6a6 100644 --- a/tests/compile-fail/data_race/enable_after_join_to_main.rs +++ b/tests/compile-fail/data_race/enable_after_join_to_main.rs @@ -29,7 +29,7 @@ pub fn main() { }); let j2 = spawn(move || { - *c.0 = 64; //~ ERROR Data race + *c.0 = 64; //~ ERROR Data race detected between Write on Thread(id = 6) and Write on Thread(id = 5) }); j1.join().unwrap(); diff --git a/tests/compile-fail/data_race/read_write_race.rs b/tests/compile-fail/data_race/read_write_race.rs index 42fd7a51ffbda..0df66d66ad077 100644 --- a/tests/compile-fail/data_race/read_write_race.rs +++ b/tests/compile-fail/data_race/read_write_race.rs @@ -18,7 +18,7 @@ pub fn main() { }); let j2 = spawn(move || { - *c.0 = 64; //~ ERROR Data race + *c.0 = 64; //~ ERROR Data race detected between Write on Thread(id = 2) and Read on Thread(id = 1) }); j1.join().unwrap(); diff --git a/tests/compile-fail/data_race/read_write_race_stack.rs b/tests/compile-fail/data_race/read_write_race_stack.rs index 7f2dbcc6ed5df..43270e0e915dc 100644 --- a/tests/compile-fail/data_race/read_write_race_stack.rs +++ b/tests/compile-fail/data_race/read_write_race_stack.rs @@ -41,7 +41,7 @@ pub fn main() { sleep(Duration::from_millis(1000)); //read - stack_var //~ ERROR Data race + stack_var //~ ERROR Data race detected between Read on Thread(id = 1) and Write on Thread(id = 2) }); let j2 = spawn(move || { diff --git a/tests/compile-fail/data_race/relax_acquire_race.rs b/tests/compile-fail/data_race/relax_acquire_race.rs index 2ae0aacbcf776..8b8616431f37a 100644 --- a/tests/compile-fail/data_race/relax_acquire_race.rs +++ b/tests/compile-fail/data_race/relax_acquire_race.rs @@ -37,7 +37,7 @@ pub fn main() { let j3 = spawn(move || { if SYNC.load(Ordering::Acquire) == 2 { - *c.0 //~ ERROR Data race + *c.0 //~ ERROR Data race detected between Read on Thread(id = 3) and Write on Thread(id = 1) } else { 0 } diff --git a/tests/compile-fail/data_race/release_seq_race.rs b/tests/compile-fail/data_race/release_seq_race.rs index d0d625a6ce177..91235280d210a 100644 --- a/tests/compile-fail/data_race/release_seq_race.rs +++ b/tests/compile-fail/data_race/release_seq_race.rs @@ -42,7 +42,7 @@ pub fn main() { let j3 = spawn(move || { sleep(Duration::from_millis(5000)); if SYNC.load(Ordering::Acquire) == 3 { - *c.0 //~ ERROR Data race + *c.0 //~ ERROR Data race detected between Read on Thread(id = 3) and Write on Thread(id = 1) } else { 0 } diff --git a/tests/compile-fail/data_race/release_seq_race_same_thread.rs b/tests/compile-fail/data_race/release_seq_race_same_thread.rs index d64b80dbd84c6..54b9f49937c88 100644 --- a/tests/compile-fail/data_race/release_seq_race_same_thread.rs +++ b/tests/compile-fail/data_race/release_seq_race_same_thread.rs @@ -38,7 +38,7 @@ pub fn main() { let j2 = spawn(move || { if SYNC.load(Ordering::Acquire) == 2 { - *c.0 //~ ERROR Data race + *c.0 //~ ERROR Data race detected between Read on Thread(id = 2) and Write on Thread(id = 1) } else { 0 } diff --git a/tests/compile-fail/data_race/rmw_race.rs b/tests/compile-fail/data_race/rmw_race.rs index e523f8b374cc2..fcf683a65d8ed 100644 --- a/tests/compile-fail/data_race/rmw_race.rs +++ b/tests/compile-fail/data_race/rmw_race.rs @@ -38,7 +38,7 @@ pub fn main() { let j3 = spawn(move || { if SYNC.load(Ordering::Acquire) == 3 { - *c.0 //~ ERROR Data race + *c.0 //~ ERROR Data race detected between Read on Thread(id = 3) and Write on Thread(id = 1) } else { 0 } diff --git a/tests/compile-fail/data_race/write_write_race.rs b/tests/compile-fail/data_race/write_write_race.rs index aca19a46c13d7..61909eda86337 100644 --- a/tests/compile-fail/data_race/write_write_race.rs +++ b/tests/compile-fail/data_race/write_write_race.rs @@ -18,7 +18,7 @@ pub fn main() { }); let j2 = spawn(move || { - *c.0 = 64; //~ ERROR Data race + *c.0 = 64; //~ ERROR Data race detected between Write on Thread(id = 2) and Write on Thread(id = 1) }); j1.join().unwrap(); diff --git a/tests/compile-fail/data_race/write_write_race_stack.rs b/tests/compile-fail/data_race/write_write_race_stack.rs index 51bf0120d69fd..91ac51787fbeb 100644 --- a/tests/compile-fail/data_race/write_write_race_stack.rs +++ b/tests/compile-fail/data_race/write_write_race_stack.rs @@ -40,7 +40,7 @@ pub fn main() { sleep(Duration::from_millis(1000)); - stack_var = 1usize; //~ ERROR Data race + stack_var = 1usize; //~ ERROR Data race detected between Write on Thread(id = 1) and Write on Thread(id = 2) // read to silence errors stack_var From 8676c60f87b299fdcfa1a9f5d97ebd6340a09913 Mon Sep 17 00:00:00 2001 From: JCTyBlaidd Date: Mon, 7 Dec 2020 23:21:58 +0000 Subject: [PATCH 2477/3747] Update note --- tests/compile-fail/data_race/dealloc_write_race_stack_drop.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/compile-fail/data_race/dealloc_write_race_stack_drop.rs b/tests/compile-fail/data_race/dealloc_write_race_stack_drop.rs index db0bb25277630..e936a2154ad13 100644 --- a/tests/compile-fail/data_race/dealloc_write_race_stack_drop.rs +++ b/tests/compile-fail/data_race/dealloc_write_race_stack_drop.rs @@ -38,7 +38,7 @@ pub fn main() { sleep(Duration::from_millis(1000)); - // FIXME: find cause of implicit read event + // Note: Implicit read for drop(_) races with write, would detect race with deallocate after. drop(stack_var); //~ ERROR Data race detected between Read on Thread(id = 1) and Write on Thread(id = 2) }); From a30105df0ba441649817f6c952d5863f730c67d5 Mon Sep 17 00:00:00 2001 From: JCTyBlaidd Date: Mon, 7 Dec 2020 23:30:55 +0000 Subject: [PATCH 2478/3747] Defeat the mir-opt=3 optimizer. --- tests/compile-fail/data_race/read_write_race_stack.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/compile-fail/data_race/read_write_race_stack.rs b/tests/compile-fail/data_race/read_write_race_stack.rs index 43270e0e915dc..d3d0bfdfc4808 100644 --- a/tests/compile-fail/data_race/read_write_race_stack.rs +++ b/tests/compile-fail/data_race/read_write_race_stack.rs @@ -40,8 +40,9 @@ pub fn main() { sleep(Duration::from_millis(1000)); - //read - stack_var //~ ERROR Data race detected between Read on Thread(id = 1) and Write on Thread(id = 2) + // Read, the add 1 fixes -Z mir-opt-level=3 from removing the read via dest-prop and breaking + // the test. + stack_var + 1 //~ ERROR Data race detected between Read on Thread(id = 1) and Write on Thread(id = 2) }); let j2 = spawn(move || { From 3df67141e67a289bf410742ace2b6d5b86ce07ae Mon Sep 17 00:00:00 2001 From: JCTyBlaidd Date: Mon, 7 Dec 2020 23:43:19 +0000 Subject: [PATCH 2479/3747] Disable tests in windows --- tests/run-pass/concurrency/concurrent_caller_location.rs | 2 ++ tests/run-pass/concurrency/issue1643.rs | 2 ++ 2 files changed, 4 insertions(+) diff --git a/tests/run-pass/concurrency/concurrent_caller_location.rs b/tests/run-pass/concurrency/concurrent_caller_location.rs index e3e2f9ac60aee..d509d1b3f797d 100644 --- a/tests/run-pass/concurrency/concurrent_caller_location.rs +++ b/tests/run-pass/concurrency/concurrent_caller_location.rs @@ -1,3 +1,5 @@ +// ignore-windows: Concurrency on Windows is not supported yet. + use std::thread::spawn; use std::panic::Location; diff --git a/tests/run-pass/concurrency/issue1643.rs b/tests/run-pass/concurrency/issue1643.rs index c0956569ad8f9..1238a1bd6f5e1 100644 --- a/tests/run-pass/concurrency/issue1643.rs +++ b/tests/run-pass/concurrency/issue1643.rs @@ -1,3 +1,5 @@ +// ignore-windows: Concurrency on Windows is not supported yet. + use std::thread::spawn; fn initialize() { From 4e74f9f013f6093a4f1cb601667a07aadac75b42 Mon Sep 17 00:00:00 2001 From: JCTyBlaidd Date: Tue, 8 Dec 2020 14:16:39 +0000 Subject: [PATCH 2480/3747] Change to disable mir-opt in compile-flags --- tests/compile-fail/data_race/read_write_race_stack.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/tests/compile-fail/data_race/read_write_race_stack.rs b/tests/compile-fail/data_race/read_write_race_stack.rs index d3d0bfdfc4808..0fc45c8fafc73 100644 --- a/tests/compile-fail/data_race/read_write_race_stack.rs +++ b/tests/compile-fail/data_race/read_write_race_stack.rs @@ -1,5 +1,5 @@ // ignore-windows: Concurrency on Windows is not supported yet. -// compile-flags: -Zmiri-disable-isolation +// compile-flags: -Zmiri-disable-isolation -Zmir-opt-level=0 use std::thread::{spawn, sleep}; use std::ptr::null_mut; @@ -40,9 +40,7 @@ pub fn main() { sleep(Duration::from_millis(1000)); - // Read, the add 1 fixes -Z mir-opt-level=3 from removing the read via dest-prop and breaking - // the test. - stack_var + 1 //~ ERROR Data race detected between Read on Thread(id = 1) and Write on Thread(id = 2) + stack_var //~ ERROR Data race detected between Read on Thread(id = 1) and Write on Thread(id = 2) }); let j2 = spawn(move || { From aaf8ca4c770f7e18b3191e9f0124ac2e60542e42 Mon Sep 17 00:00:00 2001 From: JCTyBlaidd Date: Wed, 9 Dec 2020 13:35:42 +0000 Subject: [PATCH 2481/3747] Fix review changes --- src/data_race.rs | 20 ++++++++--- src/machine.rs | 5 ++- .../compile-fail/data_race/alloc_read_race.rs | 11 +++--- .../data_race/dangling_thread_async_race.rs | 2 +- .../data_race/dangling_thread_race.rs | 4 +-- ...loc_read_race.rs => dealloc_read_race1.rs} | 0 .../data_race/dealloc_read_race2.rs | 34 +++++++++++++++++++ .../data_race/dealloc_read_race_stack.rs | 2 +- .../data_race/dealloc_read_race_stack_drop.rs | 2 +- ...c_write_race.rs => dealloc_write_race1.rs} | 0 .../data_race/dealloc_write_race2.rs | 33 ++++++++++++++++++ .../data_race/dealloc_write_race_stack.rs | 2 +- .../dealloc_write_race_stack_drop.rs | 2 +- .../data_race/read_write_race_stack.rs | 5 ++- .../data_race/release_seq_race.rs | 4 +-- .../data_race/write_write_race_stack.rs | 2 +- 16 files changed, 107 insertions(+), 21 deletions(-) rename tests/compile-fail/data_race/{dealloc_read_race.rs => dealloc_read_race1.rs} (100%) create mode 100644 tests/compile-fail/data_race/dealloc_read_race2.rs rename tests/compile-fail/data_race/{dealloc_write_race.rs => dealloc_write_race1.rs} (100%) create mode 100644 tests/compile-fail/data_race/dealloc_write_race2.rs diff --git a/src/data_race.rs b/src/data_race.rs index 7211f3176350b..2fff13a80661d 100644 --- a/src/data_race.rs +++ b/src/data_race.rs @@ -9,6 +9,9 @@ //! Relaxed stores now unconditionally block all currently active release sequences and so per-thread tracking of release //! sequences is not needed. //! +//! The implementation also models races with memory allocation and deallocation via treating allocation and +//! deallocation as a type of write internally for detecting data-races. +//! //! This does not explore weak memory orders and so can still miss data-races //! but should not report false-positives //! @@ -192,13 +195,22 @@ struct AtomicMemoryCellClocks { sync_vector: VClock, } +/// Type of write operation: allocating memory +/// non-atomic writes and deallocating memory +/// are all treated as writes for the purpose +/// of the data-race detector. #[derive(Copy, Clone, PartialEq, Eq, Debug)] enum WriteType { /// Allocate memory. Allocate, + /// Standard unsynchronized write. Write, - /// Deallocate memory + + /// Deallocate memory. + /// Some races with deallocation will be missed and instead + /// reported as invalid accesses of freed memory due to + /// the order of checks. Deallocate, } impl WriteType { @@ -681,7 +693,7 @@ impl VClockAlloc { let (alloc_index, clocks) = global.current_thread_state(); let alloc_timestamp = clocks.clock[alloc_index]; (alloc_timestamp, alloc_index) - }else{ + } else { (0, VectorIdx::MAX_INDEX) }; VClockAlloc { @@ -695,7 +707,7 @@ impl VClockAlloc { // Find an index, if one exists where the value // in `l` is greater than the value in `r`. fn find_gt_index(l: &VClock, r: &VClock) -> Option { - log::info!("Find index where not {:?} <= {:?}", l, r); + log::trace!("Find index where not {:?} <= {:?}", l, r); let l_slice = l.as_slice(); let r_slice = r.as_slice(); l_slice @@ -1168,7 +1180,7 @@ impl GlobalState { vector_info.push(thread) }; - log::info!("Creating thread = {:?} with vector index = {:?}", thread, created_index); + log::trace!("Creating thread = {:?} with vector index = {:?}", thread, created_index); // Mark the chosen vector index as in use by the thread. thread_info[thread].vector_index = Some(created_index); diff --git a/src/machine.rs b/src/machine.rs index 159e08c87d3f0..9825467a2cae1 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -480,7 +480,10 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { let race_alloc = if let Some(data_race) = &memory_extra.data_race { match kind { // V-Table generation is lazy and so racy, so do not track races. - // Also V-Tables are read only so no data races can be detected. + // Also V-Tables are read only so no data races can be occur. + // Must be disabled since V-Tables are initialized via interpreter + // writes on demand and can incorrectly cause the data-race detector + // to trigger. MemoryKind::Vtable => None, // User allocated and stack memory should track allocation. MemoryKind::Machine( diff --git a/tests/compile-fail/data_race/alloc_read_race.rs b/tests/compile-fail/data_race/alloc_read_race.rs index 620a019b65c7e..fc1e9d30e637a 100644 --- a/tests/compile-fail/data_race/alloc_read_race.rs +++ b/tests/compile-fail/data_race/alloc_read_race.rs @@ -3,6 +3,7 @@ use std::thread::spawn; use std::ptr::null_mut; use std::sync::atomic::{Ordering, AtomicPtr}; +use std::mem::MaybeUninit; #[derive(Copy, Clone)] struct EvilSend(pub T); @@ -12,8 +13,8 @@ unsafe impl Sync for EvilSend {} pub fn main() { // Shared atomic pointer - let pointer = AtomicPtr::new(null_mut::()); - let ptr = EvilSend(&pointer as *const AtomicPtr); + let pointer = AtomicPtr::new(null_mut::>()); + let ptr = EvilSend(&pointer as *const AtomicPtr>); // Note: this is scheduler-dependent // the operations need to occur in @@ -28,14 +29,14 @@ pub fn main() { // Uses relaxed semantics to not generate // a release sequence. let pointer = &*ptr.0; - pointer.store(Box::into_raw(Box::new(0usize)), Ordering::Relaxed); + pointer.store(Box::into_raw(Box::new(MaybeUninit::uninit())), Ordering::Relaxed); }); let j2 = spawn(move || { let pointer = &*ptr.0; - //Note detects with write due to the initialization of memory - *pointer.load(Ordering::Relaxed) //~ ERROR Data race detected between Read on Thread(id = 2) and Write on Thread(id = 1) + // Note: could also error due to reading uninitialized memory, but the data-race detector triggers first. + *pointer.load(Ordering::Relaxed) //~ ERROR Data race detected between Read on Thread(id = 2) and Allocate on Thread(id = 1) }); j1.join().unwrap(); diff --git a/tests/compile-fail/data_race/dangling_thread_async_race.rs b/tests/compile-fail/data_race/dangling_thread_async_race.rs index 61587dc6384a2..ad539ec5b0839 100644 --- a/tests/compile-fail/data_race/dangling_thread_async_race.rs +++ b/tests/compile-fail/data_race/dangling_thread_async_race.rs @@ -26,7 +26,7 @@ fn main() { // Detach the thread and sleep until it terminates mem::drop(join); - sleep(Duration::from_millis(1000)); + sleep(Duration::from_millis(200)); // Spawn and immediately join a thread // to execute the join code-path diff --git a/tests/compile-fail/data_race/dangling_thread_race.rs b/tests/compile-fail/data_race/dangling_thread_race.rs index c14b68080cc82..755ba8efdae95 100644 --- a/tests/compile-fail/data_race/dangling_thread_race.rs +++ b/tests/compile-fail/data_race/dangling_thread_race.rs @@ -24,9 +24,9 @@ fn main() { }) }; - // Detatch the thread and sleep until it terminates + // Detach the thread and sleep until it terminates mem::drop(join); - sleep(Duration::from_millis(1000)); + sleep(Duration::from_millis(200)); // Spawn and immediately join a thread // to execute the join code-path diff --git a/tests/compile-fail/data_race/dealloc_read_race.rs b/tests/compile-fail/data_race/dealloc_read_race1.rs similarity index 100% rename from tests/compile-fail/data_race/dealloc_read_race.rs rename to tests/compile-fail/data_race/dealloc_read_race1.rs diff --git a/tests/compile-fail/data_race/dealloc_read_race2.rs b/tests/compile-fail/data_race/dealloc_read_race2.rs new file mode 100644 index 0000000000000..a4bf210ef439f --- /dev/null +++ b/tests/compile-fail/data_race/dealloc_read_race2.rs @@ -0,0 +1,34 @@ +// ignore-windows: Concurrency on Windows is not supported yet. + +use std::thread::spawn; + +#[derive(Copy, Clone)] +struct EvilSend(pub T); + +unsafe impl Send for EvilSend {} +unsafe impl Sync for EvilSend {} + +extern "Rust" { + fn __rust_dealloc(ptr: *mut u8, size: usize, align: usize); +} + +pub fn main() { + // Shared atomic pointer + let pointer: *mut usize = Box::into_raw(Box::new(0usize)); + let ptr = EvilSend(pointer); + + unsafe { + let j1 = spawn(move || { + __rust_dealloc(ptr.0 as *mut _, std::mem::size_of::(), std::mem::align_of::()) + }); + + let j2 = spawn(move || { + // Also an error of the form: Data race detected between Read on Thread(id = 2) and Deallocate on Thread(id = 1) + // but the invalid allocation is detected first. + *ptr.0 //~ ERROR dereferenced after this allocation got freed + }); + + j1.join().unwrap(); + j2.join().unwrap(); + } +} diff --git a/tests/compile-fail/data_race/dealloc_read_race_stack.rs b/tests/compile-fail/data_race/dealloc_read_race_stack.rs index 8a770563c753f..31960fb2162bf 100644 --- a/tests/compile-fail/data_race/dealloc_read_race_stack.rs +++ b/tests/compile-fail/data_race/dealloc_read_race_stack.rs @@ -36,7 +36,7 @@ pub fn main() { pointer.store(&mut stack_var as *mut _, Ordering::Release); - sleep(Duration::from_millis(1000)); + sleep(Duration::from_millis(200)); } //~ ERROR Data race detected between Deallocate on Thread(id = 1) and Read on Thread(id = 2) }); diff --git a/tests/compile-fail/data_race/dealloc_read_race_stack_drop.rs b/tests/compile-fail/data_race/dealloc_read_race_stack_drop.rs index 315d5eef3f01e..44950a34db2f8 100644 --- a/tests/compile-fail/data_race/dealloc_read_race_stack_drop.rs +++ b/tests/compile-fail/data_race/dealloc_read_race_stack_drop.rs @@ -36,7 +36,7 @@ pub fn main() { pointer.store(&mut stack_var as *mut _, Ordering::Release); - sleep(Duration::from_millis(1000)); + sleep(Duration::from_millis(200)); drop(stack_var); }); //~ ERROR Data race detected between Deallocate on Thread(id = 1) and Read on Thread(id = 2) diff --git a/tests/compile-fail/data_race/dealloc_write_race.rs b/tests/compile-fail/data_race/dealloc_write_race1.rs similarity index 100% rename from tests/compile-fail/data_race/dealloc_write_race.rs rename to tests/compile-fail/data_race/dealloc_write_race1.rs diff --git a/tests/compile-fail/data_race/dealloc_write_race2.rs b/tests/compile-fail/data_race/dealloc_write_race2.rs new file mode 100644 index 0000000000000..20c05fa8f17bc --- /dev/null +++ b/tests/compile-fail/data_race/dealloc_write_race2.rs @@ -0,0 +1,33 @@ +// ignore-windows: Concurrency on Windows is not supported yet. + +use std::thread::spawn; + +#[derive(Copy, Clone)] +struct EvilSend(pub T); + +unsafe impl Send for EvilSend {} +unsafe impl Sync for EvilSend {} + +extern "Rust" { + fn __rust_dealloc(ptr: *mut u8, size: usize, align: usize); +} +pub fn main() { + // Shared atomic pointer + let pointer: *mut usize = Box::into_raw(Box::new(0usize)); + let ptr = EvilSend(pointer); + + unsafe { + let j1 = spawn(move || { + __rust_dealloc(ptr.0 as *mut _, std::mem::size_of::(), std::mem::align_of::()); + }); + + let j2 = spawn(move || { + // Also an error of the form: Data race detected between Write on Thread(id = 2) and Deallocate on Thread(id = 1) + // but the invalid allocation is detected first. + *ptr.0 = 2; //~ ERROR dereferenced after this allocation got freed + }); + + j1.join().unwrap(); + j2.join().unwrap(); + } +} diff --git a/tests/compile-fail/data_race/dealloc_write_race_stack.rs b/tests/compile-fail/data_race/dealloc_write_race_stack.rs index a245522b06f37..25dea65fe7e09 100644 --- a/tests/compile-fail/data_race/dealloc_write_race_stack.rs +++ b/tests/compile-fail/data_race/dealloc_write_race_stack.rs @@ -36,7 +36,7 @@ pub fn main() { pointer.store(&mut stack_var as *mut _, Ordering::Release); - sleep(Duration::from_millis(1000)); + sleep(Duration::from_millis(200)); } //~ ERROR Data race detected between Deallocate on Thread(id = 1) and Write on Thread(id = 2) }); diff --git a/tests/compile-fail/data_race/dealloc_write_race_stack_drop.rs b/tests/compile-fail/data_race/dealloc_write_race_stack_drop.rs index e936a2154ad13..1d239e9eb74d0 100644 --- a/tests/compile-fail/data_race/dealloc_write_race_stack_drop.rs +++ b/tests/compile-fail/data_race/dealloc_write_race_stack_drop.rs @@ -36,7 +36,7 @@ pub fn main() { pointer.store(&mut stack_var as *mut _, Ordering::Release); - sleep(Duration::from_millis(1000)); + sleep(Duration::from_millis(200)); // Note: Implicit read for drop(_) races with write, would detect race with deallocate after. drop(stack_var); //~ ERROR Data race detected between Read on Thread(id = 1) and Write on Thread(id = 2) diff --git a/tests/compile-fail/data_race/read_write_race_stack.rs b/tests/compile-fail/data_race/read_write_race_stack.rs index 0fc45c8fafc73..0cf915cdef2b1 100644 --- a/tests/compile-fail/data_race/read_write_race_stack.rs +++ b/tests/compile-fail/data_race/read_write_race_stack.rs @@ -1,6 +1,9 @@ // ignore-windows: Concurrency on Windows is not supported yet. // compile-flags: -Zmiri-disable-isolation -Zmir-opt-level=0 +// Note: mir-opt-level set to 0 to prevent the read of stack_var in thread 1 +// from being optimized away and preventing the detection of the data-race. + use std::thread::{spawn, sleep}; use std::ptr::null_mut; use std::sync::atomic::{Ordering, AtomicPtr}; @@ -38,7 +41,7 @@ pub fn main() { pointer.store(&mut stack_var as *mut _, Ordering::Release); - sleep(Duration::from_millis(1000)); + sleep(Duration::from_millis(200)); stack_var //~ ERROR Data race detected between Read on Thread(id = 1) and Write on Thread(id = 2) }); diff --git a/tests/compile-fail/data_race/release_seq_race.rs b/tests/compile-fail/data_race/release_seq_race.rs index 91235280d210a..29c428b388d43 100644 --- a/tests/compile-fail/data_race/release_seq_race.rs +++ b/tests/compile-fail/data_race/release_seq_race.rs @@ -30,7 +30,7 @@ pub fn main() { let j1 = spawn(move || { *c.0 = 1; SYNC.store(1, Ordering::Release); - sleep(Duration::from_millis(1000)); + sleep(Duration::from_millis(200)); SYNC.store(3, Ordering::Relaxed); }); @@ -40,7 +40,7 @@ pub fn main() { }); let j3 = spawn(move || { - sleep(Duration::from_millis(5000)); + sleep(Duration::from_millis(500)); if SYNC.load(Ordering::Acquire) == 3 { *c.0 //~ ERROR Data race detected between Read on Thread(id = 3) and Write on Thread(id = 1) } else { diff --git a/tests/compile-fail/data_race/write_write_race_stack.rs b/tests/compile-fail/data_race/write_write_race_stack.rs index 91ac51787fbeb..aa1428f8a74b7 100644 --- a/tests/compile-fail/data_race/write_write_race_stack.rs +++ b/tests/compile-fail/data_race/write_write_race_stack.rs @@ -38,7 +38,7 @@ pub fn main() { pointer.store(&mut stack_var as *mut _, Ordering::Release); - sleep(Duration::from_millis(1000)); + sleep(Duration::from_millis(200)); stack_var = 1usize; //~ ERROR Data race detected between Write on Thread(id = 1) and Write on Thread(id = 2) From 81c4eb7d74624d41b5fdddffa2d239d35c32f4b4 Mon Sep 17 00:00:00 2001 From: JCTyblaidd Date: Thu, 10 Dec 2020 16:56:09 +0000 Subject: [PATCH 2482/3747] Update src/data_race.rs Co-authored-by: Ralf Jung --- src/data_race.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/data_race.rs b/src/data_race.rs index 2fff13a80661d..d16391d0d4321 100644 --- a/src/data_race.rs +++ b/src/data_race.rs @@ -208,9 +208,9 @@ enum WriteType { Write, /// Deallocate memory. - /// Some races with deallocation will be missed and instead - /// reported as invalid accesses of freed memory due to - /// the order of checks. + /// Note that when memory is deallocated first, later non-atomic accesses + /// will be reported as use-after-free, not as data races. + /// (Same for `Allocate` above.) Deallocate, } impl WriteType { From e73579632b6d5598406fdb15f32dd0c64d58bebc Mon Sep 17 00:00:00 2001 From: JCTyblaidd Date: Fri, 11 Dec 2020 19:32:25 +0000 Subject: [PATCH 2483/3747] Rework to work with machine hook. --- src/data_race.rs | 38 ++++++++++++++++++++++++++++++++++++-- src/machine.rs | 34 +++++++++++++--------------------- 2 files changed, 49 insertions(+), 23 deletions(-) diff --git a/src/data_race.rs b/src/data_race.rs index d16391d0d4321..ceb715613beb7 100644 --- a/src/data_race.rs +++ b/src/data_race.rs @@ -76,7 +76,7 @@ use rustc_target::abi::Size; use crate::{ ImmTy, Immediate, InterpResult, MPlaceTy, MemPlaceMeta, MiriEvalContext, MiriEvalContextExt, OpTy, Pointer, RangeMap, ScalarMaybeUninit, Tag, ThreadId, VClock, VTimestamp, - VectorIdx, + VectorIdx, MemoryKind, MiriMemoryKind }; pub type AllocExtra = VClockAlloc; @@ -674,6 +674,21 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { Ok(()) } } + + fn reset_vector_clocks( + &mut self, + ptr: Pointer, + size: Size + ) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + if let Some(data_race) = &mut this.memory.extra.data_race { + if data_race.multi_threaded.get() { + let alloc_meta = this.memory.get_raw_mut(ptr.alloc_id)?.extra.data_race.as_mut().unwrap(); + alloc_meta.reset_clocks(ptr.offset, size); + } + } + Ok(()) + } } /// Vector clock metadata for a logical memory allocation. @@ -688,7 +703,18 @@ pub struct VClockAlloc { impl VClockAlloc { /// Create a new data-race detector for newly allocated memory. - pub fn new_allocation(global: &MemoryExtra, len: Size, track_alloc: bool) -> VClockAlloc { + pub fn new_allocation(global: &MemoryExtra, len: Size, kind: MemoryKind) -> VClockAlloc { + let track_alloc = match kind { + // User allocated and stack memory should track allocation. + MemoryKind::Machine( + MiriMemoryKind::Rust | MiriMemoryKind::C | MiriMemoryKind::WinHeap + ) | MemoryKind::Stack => true, + // Other global memory should trace races but be allocated at the 0 timestamp. + MemoryKind::Machine( + MiriMemoryKind::Global | MiriMemoryKind::Machine | MiriMemoryKind::Env | + MiriMemoryKind::ExternStatic | MiriMemoryKind::Tls + ) | MemoryKind::CallerLocation | MemoryKind::Vtable => false + }; let (alloc_timestamp, alloc_index) = if track_alloc { let (alloc_index, clocks) = global.current_thread_state(); let alloc_timestamp = clocks.clock[alloc_index]; @@ -704,6 +730,14 @@ impl VClockAlloc { } } + fn reset_clocks(&mut self, offset: Size, len: Size) { + let mut alloc_ranges = self.alloc_ranges.borrow_mut(); + for (_, range) in alloc_ranges.iter_mut(offset, len) { + // Reset the portion of the range + *range = MemoryCellClocks::new(0, VectorIdx::MAX_INDEX); + } + } + // Find an index, if one exists where the value // in `l` is greater than the value in `r`. fn find_gt_index(l: &VClock, r: &VClock) -> Option { diff --git a/src/machine.rs b/src/machine.rs index 9825467a2cae1..e639bf450ada9 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -478,27 +478,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { (None, Tag::Untagged) }; let race_alloc = if let Some(data_race) = &memory_extra.data_race { - match kind { - // V-Table generation is lazy and so racy, so do not track races. - // Also V-Tables are read only so no data races can be occur. - // Must be disabled since V-Tables are initialized via interpreter - // writes on demand and can incorrectly cause the data-race detector - // to trigger. - MemoryKind::Vtable => None, - // User allocated and stack memory should track allocation. - MemoryKind::Machine( - MiriMemoryKind::Rust | MiriMemoryKind::C | MiriMemoryKind::WinHeap - ) | MemoryKind::Stack => Some( - data_race::AllocExtra::new_allocation(&data_race, alloc.size, true) - ), - // Other global memory should trace races but be allocated at the 0 timestamp. - MemoryKind::Machine( - MiriMemoryKind::Global | MiriMemoryKind::Machine | MiriMemoryKind::Env | - MiriMemoryKind::ExternStatic | MiriMemoryKind::Tls - ) | MemoryKind::CallerLocation => Some( - data_race::AllocExtra::new_allocation(&data_race, alloc.size, false) - ) - } + Some(data_race::AllocExtra::new_allocation(&data_race, alloc.size, kind)) } else { None }; @@ -530,6 +510,18 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { Ok(()) } + + fn after_static_mem_initialized( + ecx: &mut InterpCx<'mir, 'tcx, Self>, + ptr: Pointer, + size: Size, + ) -> InterpResult<'tcx> { + if ecx.memory.extra.data_race.is_some() { + ecx.reset_vector_clocks(ptr, size)?; + } + Ok(()) + } + #[inline(always)] fn tag_global_base_pointer(memory_extra: &MemoryExtra, id: AllocId) -> Self::PointerTag { if let Some(stacked_borrows) = &memory_extra.stacked_borrows { From aa4e5b26e6cebac766ea5e06dfee0ca5a34df01d Mon Sep 17 00:00:00 2001 From: JCTyblaidd Date: Sun, 13 Dec 2020 11:08:19 +0000 Subject: [PATCH 2484/3747] Update rust version --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index a11d33b3d336f..3b6723b944373 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -a2e29d67c26bdf8f278c98ee02d6cc77a279ed2e +12813159a985d87a98578e05cc39200e4e8c2102 From c13aabcb456c54f3f5ecfb48b874293ba1a46b46 Mon Sep 17 00:00:00 2001 From: JCTyblaidd Date: Sun, 13 Dec 2020 11:14:41 +0000 Subject: [PATCH 2485/3747] Tidy new_allocation --- src/data_race.rs | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/src/data_race.rs b/src/data_race.rs index ceb715613beb7..44cce53957773 100644 --- a/src/data_race.rs +++ b/src/data_race.rs @@ -704,23 +704,22 @@ pub struct VClockAlloc { impl VClockAlloc { /// Create a new data-race detector for newly allocated memory. pub fn new_allocation(global: &MemoryExtra, len: Size, kind: MemoryKind) -> VClockAlloc { - let track_alloc = match kind { + let (alloc_timestamp, alloc_index) = match kind { // User allocated and stack memory should track allocation. MemoryKind::Machine( MiriMemoryKind::Rust | MiriMemoryKind::C | MiriMemoryKind::WinHeap - ) | MemoryKind::Stack => true, + ) | MemoryKind::Stack => { + let (alloc_index, clocks) = global.current_thread_state(); + let alloc_timestamp = clocks.clock[alloc_index]; + (alloc_timestamp, alloc_index) + } // Other global memory should trace races but be allocated at the 0 timestamp. MemoryKind::Machine( MiriMemoryKind::Global | MiriMemoryKind::Machine | MiriMemoryKind::Env | MiriMemoryKind::ExternStatic | MiriMemoryKind::Tls - ) | MemoryKind::CallerLocation | MemoryKind::Vtable => false - }; - let (alloc_timestamp, alloc_index) = if track_alloc { - let (alloc_index, clocks) = global.current_thread_state(); - let alloc_timestamp = clocks.clock[alloc_index]; - (alloc_timestamp, alloc_index) - } else { - (0, VectorIdx::MAX_INDEX) + ) | MemoryKind::CallerLocation | MemoryKind::Vtable => { + (0, VectorIdx::MAX_INDEX) + } }; VClockAlloc { global: Rc::clone(global), From 46162ecb690e956beb2dea7faf43790b6f66f4b7 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 17 Dec 2020 12:53:10 +0100 Subject: [PATCH 2486/3747] rustup + cargo update --- Cargo.lock | 115 +++++++++++++++++++++++++++------------------------ rust-version | 2 +- 2 files changed, 61 insertions(+), 56 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 78838acb2a5fc..102d29a804355 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,18 +2,18 @@ # It is not intended for manual editing. [[package]] name = "aho-corasick" -version = "0.7.13" +version = "0.7.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "043164d8ba5c4c3035fec9bbee8647c0261d788f3474306f93bb65901cae0e86" +checksum = "7404febffaa47dac81aa44dba71523c9d069b1bdc50a77db41195149e17f68e5" dependencies = [ "memchr", ] [[package]] name = "anyhow" -version = "1.0.32" +version = "1.0.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b602bfe940d21c130f3895acd65221e8a61270debe89d628b9cb4e3ccb8569b" +checksum = "2c0df63cb2955042487fad3aefd2c6e3ae7389ac5dc1beb28921de0b69f779d4" [[package]] name = "arrayref" @@ -23,9 +23,9 @@ checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544" [[package]] name = "arrayvec" -version = "0.5.1" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cff77d8686867eceff3105329d4698d96c2391c176d5d03adc90c7389162b5b8" +checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" [[package]] name = "atty" @@ -46,15 +46,15 @@ checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" [[package]] name = "base64" -version = "0.12.3" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3441f0f7b02788e948e47f457ca01f1d7e6d92c693bc132c22b087d3141c03ff" +checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" [[package]] name = "blake2b_simd" -version = "0.5.10" +version = "0.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8fb2d74254a3a0b5cac33ac9f8ed0e44aa50378d9dbb2e5d83bd21ed1dc2c8a" +checksum = "afa748e348ad3be8263be728124b24a24f268266f6f5d58af9d75f6a40b5c587" dependencies = [ "arrayref", "arrayvec", @@ -67,6 +67,12 @@ version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + [[package]] name = "colored" version = "2.0.0" @@ -108,12 +114,12 @@ checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" [[package]] name = "crossbeam-utils" -version = "0.7.2" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8" +checksum = "02d96d1e189ef58269ebe5b97953da3274d83a93af647c2ddd6f9dab28cedb8d" dependencies = [ "autocfg", - "cfg-if", + "cfg-if 1.0.0", "lazy_static", ] @@ -129,7 +135,7 @@ version = "2.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13aea89a5c93364a98e9b37b2fa237effbb694d5cfe01c5b70941f7eb087d5e3" dependencies = [ - "cfg-if", + "cfg-if 0.1.10", "dirs-sys", ] @@ -159,11 +165,11 @@ dependencies = [ [[package]] name = "filetime" -version = "0.2.12" +version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ed85775dcc68644b5c950ac06a2b23768d3bc9390464151aaf27136998dcf9e" +checksum = "0c122a393ea57648015bf06fbd3d372378992e86b9ff5a7a497b076a28c79efe" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "libc", "redox_syscall", "winapi", @@ -184,7 +190,7 @@ version = "0.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc587bc0ec293155d5bfa6b9891ec18a1e330c234f896ea47fbada4cadbe47e6" dependencies = [ - "cfg-if", + "cfg-if 0.1.10", "libc", "wasi", ] @@ -195,16 +201,16 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ee8025cf36f917e6a52cce185b7c7177689b838b7ec138364e50cc2277a56cf4" dependencies = [ - "cfg-if", + "cfg-if 0.1.10", "libc", "wasi", ] [[package]] name = "hermit-abi" -version = "0.1.15" +version = "0.1.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3deed196b6e7f9e44a2ae8d94225d80302d81208b1bb673fd21fe634645c85a9" +checksum = "5aca5565f760fb5b220e499d72710ed156fdb74e631659e99377d9ebfbd13ae8" dependencies = [ "libc", ] @@ -238,9 +244,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.77" +version = "0.2.81" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2f96b10ec2560088a8e76961b00d47107b3a625fecb76dedb29ee7ccbf98235" +checksum = "1482821306169ec4d07f6aca392a4681f66c75c9918aa49641a2595db64053cb" [[package]] name = "log" @@ -248,20 +254,20 @@ version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4fabed175da42fed1fa0746b0ea71f412aa9d35e76e95e59b192c64b9dc2bf8b" dependencies = [ - "cfg-if", + "cfg-if 0.1.10", ] [[package]] name = "memchr" -version = "2.3.3" +version = "2.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3728d817d99e5ac407411fa471ff9800a778d88a24685968b36824eaf4bee400" +checksum = "0ee1c47aaa256ecabcaea351eae4a9b01ef39ed810004e298d2511ed284b1525" [[package]] name = "miow" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07b88fb9795d4d36d62a012dfbf49a8f5cf12751f36d31a9dbe66d528e58979e" +checksum = "5a33c1b55807fbed163481b5ba66db4b2fa6cde694a5027be10fb724206c5897" dependencies = [ "socket2", "winapi", @@ -287,15 +293,15 @@ dependencies = [ [[package]] name = "ppv-lite86" -version = "0.2.9" +version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c36fa947111f5c62a733b652544dd0016a43ce89619538a8ef92724a6f501a20" +checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857" [[package]] name = "proc-macro2" -version = "1.0.21" +version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36e28516df94f3dd551a587da5357459d9b36d945a7c37c3557928c1c2ff2a2c" +checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71" dependencies = [ "unicode-xid", ] @@ -375,9 +381,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.3.9" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c3780fcf44b193bc4d09f36d2a3c87b251da4a046c87795a0d35f4f927ad8e6" +checksum = "38cf2c13ed4745de91a5eb834e11c00bcc3709e773173b2ce4c56c9fbde04b9c" dependencies = [ "aho-corasick", "memchr", @@ -387,9 +393,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.6.18" +version = "0.6.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26412eb97c6b088a6997e05f69403a802a92d520de2f8e63c2b65f9e0f47c4e8" +checksum = "3b181ba2dcf07aaccad5448e8ead58db5b742cf85dfe035e2227f137a539a189" [[package]] name = "remove_dir_all" @@ -402,9 +408,9 @@ dependencies = [ [[package]] name = "rust-argon2" -version = "0.8.2" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9dab61250775933275e84053ac235621dfb739556d5c54a2f2e9313b7cf43a19" +checksum = "4b18820d944b33caa75a71378964ac46f58517c92b6ae5f762636247c09e78fb" dependencies = [ "base64", "blake2b_simd", @@ -462,18 +468,18 @@ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" [[package]] name = "serde" -version = "1.0.116" +version = "1.0.118" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96fe57af81d28386a513cbc6858332abc6117cfdb5999647c6444b8f43a370a5" +checksum = "06c64263859d87aa2eb554587e2d23183398d617427327cf2b3d0ed8c69e4800" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.116" +version = "1.0.118" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f630a6370fd8e457873b4bd2ffdae75408bc291ba72be773772a4c2a065d9ae8" +checksum = "c84d3526699cd55261af4b941e4e725444df67aa4f9e6a3564f18030d12672df" dependencies = [ "proc-macro2", "quote", @@ -482,9 +488,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.57" +version = "1.0.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "164eacbdb13512ec2745fb09d51fd5b22b0d65ed294a1dcf7285a360c80a675c" +checksum = "1500e84d27fe482ed1dc791a56eddc2f230046a040fa908c08bda1d9fb615779" dependencies = [ "itoa", "ryu", @@ -499,27 +505,26 @@ checksum = "45bb67a18fa91266cc7807181f62f9178a6873bfad7dc788c42e6430db40184f" [[package]] name = "smallvec" -version = "1.4.2" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbee7696b84bbf3d89a1c2eccff0850e3047ed46bfcd2e92c29a2d074d57e252" +checksum = "ae524f056d7d770e174287294f562e95044c68e88dec909a00d2094805db9d75" [[package]] name = "socket2" -version = "0.3.15" +version = "0.3.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1fa70dc5c8104ec096f4fe7ede7a221d35ae13dcd19ba1ad9a81d2cab9a1c44" +checksum = "97e0e9fd577458a4f61fb91fcb559ea2afecc54c934119421f9f5d3d5b1a1057" dependencies = [ - "cfg-if", + "cfg-if 1.0.0", "libc", - "redox_syscall", "winapi", ] [[package]] name = "syn" -version = "1.0.41" +version = "1.0.54" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6690e3e9f692504b941dc6c3b188fd28df054f7fb8469ab40680df52fdcc842b" +checksum = "9a2af957a63d6bd42255c359c93d9bfdb97076bd3b820897ce55ffbfbf107f44" dependencies = [ "proc-macro2", "quote", @@ -532,7 +537,7 @@ version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9" dependencies = [ - "cfg-if", + "cfg-if 0.1.10", "libc", "rand", "redox_syscall", @@ -552,9 +557,9 @@ dependencies = [ [[package]] name = "termcolor" -version = "1.1.0" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb6bfa289a4d7c5766392812c0a1f4c1ba45afa1ad47803c11e1f407d846d75f" +checksum = "2dfed899f0eb03f32ee8c6a0aabdb8a7949659e3466561fc0adf54e26d88c5f4" dependencies = [ "winapi-util", ] diff --git a/rust-version b/rust-version index 3b6723b944373..177c1ee97d6e7 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -12813159a985d87a98578e05cc39200e4e8c2102 +bdd0a78582efd17f588b35e3e227a65617d5afec From ba0d229752152f67467fc3cbd5c35c3937c46d04 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 21 Dec 2020 10:53:55 +0100 Subject: [PATCH 2487/3747] rustup + cargo-miri 'cargo update' --- cargo-miri/Cargo.lock | 72 +++++++++++++++++++++----------------- rust-version | 2 +- test-cargo-miri/Cargo.lock | 28 +++++++-------- 3 files changed, 55 insertions(+), 47 deletions(-) diff --git a/cargo-miri/Cargo.lock b/cargo-miri/Cargo.lock index 54472947b691d..b6abfb1031e6d 100644 --- a/cargo-miri/Cargo.lock +++ b/cargo-miri/Cargo.lock @@ -8,9 +8,9 @@ checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544" [[package]] name = "arrayvec" -version = "0.5.1" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cff77d8686867eceff3105329d4698d96c2391c176d5d03adc90c7389162b5b8" +checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" [[package]] name = "autocfg" @@ -20,9 +20,9 @@ checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" [[package]] name = "base64" -version = "0.12.3" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3441f0f7b02788e948e47f457ca01f1d7e6d92c693bc132c22b087d3141c03ff" +checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" [[package]] name = "bitflags" @@ -32,9 +32,9 @@ checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" [[package]] name = "blake2b_simd" -version = "0.5.10" +version = "0.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8fb2d74254a3a0b5cac33ac9f8ed0e44aa50378d9dbb2e5d83bd21ed1dc2c8a" +checksum = "afa748e348ad3be8263be728124b24a24f268266f6f5d58af9d75f6a40b5c587" dependencies = [ "arrayref", "arrayvec", @@ -59,15 +59,23 @@ version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + [[package]] name = "chrono" -version = "0.4.15" +version = "0.4.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "942f72db697d8767c22d46a598e01f2d3b475501ea43d0db4f16d90259182d0b" +checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73" dependencies = [ + "libc", "num-integer", "num-traits", "time", + "winapi", ] [[package]] @@ -78,12 +86,12 @@ checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" [[package]] name = "crossbeam-utils" -version = "0.7.2" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8" +checksum = "02d96d1e189ef58269ebe5b97953da3274d83a93af647c2ddd6f9dab28cedb8d" dependencies = [ "autocfg", - "cfg-if", + "cfg-if 1.0.0", "lazy_static", ] @@ -113,7 +121,7 @@ version = "0.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc587bc0ec293155d5bfa6b9891ec18a1e330c234f896ea47fbada4cadbe47e6" dependencies = [ - "cfg-if", + "cfg-if 0.1.10", "libc", "wasi 0.9.0+wasi-snapshot-preview1", ] @@ -132,15 +140,15 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.77" +version = "0.2.81" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2f96b10ec2560088a8e76961b00d47107b3a625fecb76dedb29ee7ccbf98235" +checksum = "1482821306169ec4d07f6aca392a4681f66c75c9918aa49641a2595db64053cb" [[package]] name = "num-integer" -version = "0.1.43" +version = "0.1.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d59457e662d541ba17869cf51cf177c0b5f0cbf476c66bdc90bf1edac4f875b" +checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db" dependencies = [ "autocfg", "num-traits", @@ -148,27 +156,27 @@ dependencies = [ [[package]] name = "num-traits" -version = "0.2.12" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac267bcc07f48ee5f8935ab0d24f316fb722d7a1292e2913f0cc196b29ffd611" +checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" dependencies = [ "autocfg", ] [[package]] name = "proc-macro2" -version = "1.0.21" +version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36e28516df94f3dd551a587da5357459d9b36d945a7c37c3557928c1c2ff2a2c" +checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71" dependencies = [ "unicode-xid", ] [[package]] name = "quote" -version = "1.0.7" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa563d17ecb180e500da1cfd2b028310ac758de548efdd203e18f283af693f37" +checksum = "991431c3519a3f36861882da93630ce66b52918dcf1b8e2fd66b397fc96f28df" dependencies = [ "proc-macro2", ] @@ -192,9 +200,9 @@ dependencies = [ [[package]] name = "rust-argon2" -version = "0.8.2" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9dab61250775933275e84053ac235621dfb739556d5c54a2f2e9313b7cf43a19" +checksum = "4b18820d944b33caa75a71378964ac46f58517c92b6ae5f762636247c09e78fb" dependencies = [ "base64", "blake2b_simd", @@ -240,18 +248,18 @@ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" [[package]] name = "serde" -version = "1.0.116" +version = "1.0.118" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96fe57af81d28386a513cbc6858332abc6117cfdb5999647c6444b8f43a370a5" +checksum = "06c64263859d87aa2eb554587e2d23183398d617427327cf2b3d0ed8c69e4800" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.116" +version = "1.0.118" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f630a6370fd8e457873b4bd2ffdae75408bc291ba72be773772a4c2a065d9ae8" +checksum = "c84d3526699cd55261af4b941e4e725444df67aa4f9e6a3564f18030d12672df" dependencies = [ "proc-macro2", "quote", @@ -260,9 +268,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.57" +version = "1.0.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "164eacbdb13512ec2745fb09d51fd5b22b0d65ed294a1dcf7285a360c80a675c" +checksum = "1500e84d27fe482ed1dc791a56eddc2f230046a040fa908c08bda1d9fb615779" dependencies = [ "itoa", "ryu", @@ -271,9 +279,9 @@ dependencies = [ [[package]] name = "syn" -version = "1.0.41" +version = "1.0.55" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6690e3e9f692504b941dc6c3b188fd28df054f7fb8469ab40680df52fdcc842b" +checksum = "a571a711dddd09019ccc628e1b17fe87c59b09d513c06c026877aa708334f37a" dependencies = [ "proc-macro2", "quote", diff --git a/rust-version b/rust-version index 177c1ee97d6e7..ec1eb6932417b 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -bdd0a78582efd17f588b35e3e227a65617d5afec +15d1f811963649c2f18a88c8e0b39958ec02fd70 diff --git a/test-cargo-miri/Cargo.lock b/test-cargo-miri/Cargo.lock index b03347d9f0dec..8c287098d323b 100644 --- a/test-cargo-miri/Cargo.lock +++ b/test-cargo-miri/Cargo.lock @@ -34,18 +34,18 @@ dependencies = [ [[package]] name = "hermit-abi" -version = "0.1.15" +version = "0.1.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3deed196b6e7f9e44a2ae8d94225d80302d81208b1bb673fd21fe634645c85a9" +checksum = "5aca5565f760fb5b220e499d72710ed156fdb74e631659e99377d9ebfbd13ae8" dependencies = [ "libc", ] [[package]] name = "libc" -version = "0.2.77" +version = "0.2.81" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2f96b10ec2560088a8e76961b00d47107b3a625fecb76dedb29ee7ccbf98235" +checksum = "1482821306169ec4d07f6aca392a4681f66c75c9918aa49641a2595db64053cb" [[package]] name = "num_cpus" @@ -59,24 +59,24 @@ dependencies = [ [[package]] name = "ppv-lite86" -version = "0.2.9" +version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c36fa947111f5c62a733b652544dd0016a43ce89619538a8ef92724a6f501a20" +checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857" [[package]] name = "proc-macro2" -version = "1.0.21" +version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36e28516df94f3dd551a587da5357459d9b36d945a7c37c3557928c1c2ff2a2c" +checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71" dependencies = [ "unicode-xid", ] [[package]] name = "quote" -version = "1.0.7" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa563d17ecb180e500da1cfd2b028310ac758de548efdd203e18f283af693f37" +checksum = "991431c3519a3f36861882da93630ce66b52918dcf1b8e2fd66b397fc96f28df" dependencies = [ "proc-macro2", ] @@ -134,9 +134,9 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.116" +version = "1.0.118" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f630a6370fd8e457873b4bd2ffdae75408bc291ba72be773772a4c2a065d9ae8" +checksum = "c84d3526699cd55261af4b941e4e725444df67aa4f9e6a3564f18030d12672df" dependencies = [ "proc-macro2", "quote", @@ -152,9 +152,9 @@ dependencies = [ [[package]] name = "syn" -version = "1.0.41" +version = "1.0.55" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6690e3e9f692504b941dc6c3b188fd28df054f7fb8469ab40680df52fdcc842b" +checksum = "a571a711dddd09019ccc628e1b17fe87c59b09d513c06c026877aa708334f37a" dependencies = [ "proc-macro2", "quote", From 05fcf86f11099b8a416b29ae6d37b870de371041 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 21 Dec 2020 11:29:49 +0100 Subject: [PATCH 2488/3747] rename test ref files for proper names --- test-cargo-miri/run-test.py | 20 +++++++++---------- .../{stderr.ref2 => run.args.stderr.ref} | 0 .../{stdout.ref2 => run.args.stdout.ref} | 0 .../{stderr.ref1 => run.default.stderr.ref} | 0 .../{stdout.ref1 => run.default.stdout.ref} | 0 .../{stderr.ref3 => run.subcrate.stderr.ref} | 0 .../{stdout.ref3 => run.subcrate.stdout.ref} | 0 ...stdout.ref4 => test.bin-target.stdout.ref} | 0 ...st.stdout.ref1 => test.default.stdout.ref} | 0 ...est.stdout.ref2 => test.filter.stdout.ref} | 0 ...test.stderr.ref2 => test.stderr-empty.ref} | 0 ...st.stderr.ref1 => test.stderr-rustdoc.ref} | 0 ...t.stdout.ref5 => test.subcrate.stdout.ref} | 0 ...tdout.ref3 => test.test-target.stdout.ref} | 0 14 files changed, 10 insertions(+), 10 deletions(-) rename test-cargo-miri/{stderr.ref2 => run.args.stderr.ref} (100%) rename test-cargo-miri/{stdout.ref2 => run.args.stdout.ref} (100%) rename test-cargo-miri/{stderr.ref1 => run.default.stderr.ref} (100%) rename test-cargo-miri/{stdout.ref1 => run.default.stdout.ref} (100%) rename test-cargo-miri/{stderr.ref3 => run.subcrate.stderr.ref} (100%) rename test-cargo-miri/{stdout.ref3 => run.subcrate.stdout.ref} (100%) rename test-cargo-miri/{test.stdout.ref4 => test.bin-target.stdout.ref} (100%) rename test-cargo-miri/{test.stdout.ref1 => test.default.stdout.ref} (100%) rename test-cargo-miri/{test.stdout.ref2 => test.filter.stdout.ref} (100%) rename test-cargo-miri/{test.stderr.ref2 => test.stderr-empty.ref} (100%) rename test-cargo-miri/{test.stderr.ref1 => test.stderr-rustdoc.ref} (100%) rename test-cargo-miri/{test.stdout.ref5 => test.subcrate.stdout.ref} (100%) rename test-cargo-miri/{test.stdout.ref3 => test.test-target.stdout.ref} (100%) diff --git a/test-cargo-miri/run-test.py b/test-cargo-miri/run-test.py index e7c341a1f0408..636f4b3bf5f50 100755 --- a/test-cargo-miri/run-test.py +++ b/test-cargo-miri/run-test.py @@ -51,7 +51,7 @@ def test(name, cmd, stdout_ref, stderr_ref, stdin=b'', env={}): def test_cargo_miri_run(): test("`cargo miri run` (no isolation)", cargo_miri("run"), - "stdout.ref1", "stderr.ref1", + "run.default.stdout.ref", "run.default.stderr.ref", stdin=b'12\n21\n', env={ 'MIRIFLAGS': "-Zmiri-disable-isolation", @@ -60,44 +60,44 @@ def test_cargo_miri_run(): ) test("`cargo miri run` (with arguments and target)", cargo_miri("run") + ["--bin", "cargo-miri-test", "--", "hello world", '"hello world"'], - "stdout.ref2", "stderr.ref2", + "run.args.stdout.ref", "run.args.stderr.ref", ) test("`cargo miri run` (subcrate, no ioslation)", cargo_miri("run") + ["-p", "subcrate"], - "stdout.ref3", "stderr.ref3", + "run.subcrate.stdout.ref", "run.subcrate.stderr.ref", env={'MIRIFLAGS': "-Zmiri-disable-isolation"}, ) def test_cargo_miri_test(): # rustdoc is not run on foreign targets is_foreign = 'MIRI_TEST_TARGET' in os.environ - rustdoc_ref = "test.stderr.ref2" if is_foreign else "test.stderr.ref1" + rustdoc_ref = "test.stderr-empty.ref" if is_foreign else "test.stderr-rustdoc.ref" test("`cargo miri test`", cargo_miri("test"), - "test.stdout.ref1", rustdoc_ref, + "test.default.stdout.ref", rustdoc_ref, env={'MIRIFLAGS': "-Zmiri-seed=feed"}, ) test("`cargo miri test` (no isolation)", cargo_miri("test"), - "test.stdout.ref1", rustdoc_ref, + "test.default.stdout.ref", rustdoc_ref, env={'MIRIFLAGS': "-Zmiri-disable-isolation"}, ) test("`cargo miri test` (with filter)", cargo_miri("test") + ["--", "--format=pretty", "le1"], - "test.stdout.ref2", rustdoc_ref, + "test.filter.stdout.ref", rustdoc_ref, ) test("`cargo miri test` (test target)", cargo_miri("test") + ["--test", "test", "--", "--format=pretty"], - "test.stdout.ref3", "test.stderr.ref2", + "test.test-target.stdout.ref", "test.stderr-empty.ref", ) test("`cargo miri test` (bin target)", cargo_miri("test") + ["--bin", "cargo-miri-test", "--", "--format=pretty"], - "test.stdout.ref4", "test.stderr.ref2", + "test.bin-target.stdout.ref", "test.stderr-empty.ref", ) test("`cargo miri test` (subcrate, no isolation)", cargo_miri("test") + ["-p", "subcrate"], - "test.stdout.ref5", "test.stderr.ref2", + "test.subcrate.stdout.ref", "test.stderr-empty.ref", env={'MIRIFLAGS': "-Zmiri-disable-isolation"}, ) diff --git a/test-cargo-miri/stderr.ref2 b/test-cargo-miri/run.args.stderr.ref similarity index 100% rename from test-cargo-miri/stderr.ref2 rename to test-cargo-miri/run.args.stderr.ref diff --git a/test-cargo-miri/stdout.ref2 b/test-cargo-miri/run.args.stdout.ref similarity index 100% rename from test-cargo-miri/stdout.ref2 rename to test-cargo-miri/run.args.stdout.ref diff --git a/test-cargo-miri/stderr.ref1 b/test-cargo-miri/run.default.stderr.ref similarity index 100% rename from test-cargo-miri/stderr.ref1 rename to test-cargo-miri/run.default.stderr.ref diff --git a/test-cargo-miri/stdout.ref1 b/test-cargo-miri/run.default.stdout.ref similarity index 100% rename from test-cargo-miri/stdout.ref1 rename to test-cargo-miri/run.default.stdout.ref diff --git a/test-cargo-miri/stderr.ref3 b/test-cargo-miri/run.subcrate.stderr.ref similarity index 100% rename from test-cargo-miri/stderr.ref3 rename to test-cargo-miri/run.subcrate.stderr.ref diff --git a/test-cargo-miri/stdout.ref3 b/test-cargo-miri/run.subcrate.stdout.ref similarity index 100% rename from test-cargo-miri/stdout.ref3 rename to test-cargo-miri/run.subcrate.stdout.ref diff --git a/test-cargo-miri/test.stdout.ref4 b/test-cargo-miri/test.bin-target.stdout.ref similarity index 100% rename from test-cargo-miri/test.stdout.ref4 rename to test-cargo-miri/test.bin-target.stdout.ref diff --git a/test-cargo-miri/test.stdout.ref1 b/test-cargo-miri/test.default.stdout.ref similarity index 100% rename from test-cargo-miri/test.stdout.ref1 rename to test-cargo-miri/test.default.stdout.ref diff --git a/test-cargo-miri/test.stdout.ref2 b/test-cargo-miri/test.filter.stdout.ref similarity index 100% rename from test-cargo-miri/test.stdout.ref2 rename to test-cargo-miri/test.filter.stdout.ref diff --git a/test-cargo-miri/test.stderr.ref2 b/test-cargo-miri/test.stderr-empty.ref similarity index 100% rename from test-cargo-miri/test.stderr.ref2 rename to test-cargo-miri/test.stderr-empty.ref diff --git a/test-cargo-miri/test.stderr.ref1 b/test-cargo-miri/test.stderr-rustdoc.ref similarity index 100% rename from test-cargo-miri/test.stderr.ref1 rename to test-cargo-miri/test.stderr-rustdoc.ref diff --git a/test-cargo-miri/test.stdout.ref5 b/test-cargo-miri/test.subcrate.stdout.ref similarity index 100% rename from test-cargo-miri/test.stdout.ref5 rename to test-cargo-miri/test.subcrate.stdout.ref diff --git a/test-cargo-miri/test.stdout.ref3 b/test-cargo-miri/test.test-target.stdout.ref similarity index 100% rename from test-cargo-miri/test.stdout.ref3 rename to test-cargo-miri/test.test-target.stdout.ref From 3d151c8b62dbb9b4234387fcd6e4a6eb87a07ef0 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 21 Dec 2020 11:33:46 +0100 Subject: [PATCH 2489/3747] leak checker: also test AtomicPtr stored via 'swap' --- tests/run-pass/leak-in-static.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/run-pass/leak-in-static.rs b/tests/run-pass/leak-in-static.rs index 2914b1149c06f..a20577125e73f 100644 --- a/tests/run-pass/leak-in-static.rs +++ b/tests/run-pass/leak-in-static.rs @@ -12,5 +12,9 @@ fn main() { { static LEAK: AtomicPtr = AtomicPtr::new(ptr::null_mut()); LEAK.store(Box::into_raw(Box::new(0usize)), Ordering::SeqCst); + + static LEAK2: AtomicPtr = AtomicPtr::new(ptr::null_mut()); + // Make sure this also works when using 'swap'. + LEAK2.swap(Box::into_raw(Box::new(0usize)), Ordering::SeqCst); } } From 6dc353c0915c8d85218e984d1064a52c0711d2e2 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 21 Dec 2020 11:34:27 +0100 Subject: [PATCH 2490/3747] test test suite harness with raw-ptr tracking --- test-cargo-miri/run-test.py | 5 +++++ test-cargo-miri/test.raw-ptr-track.stdout.ref | 10 ++++++++++ 2 files changed, 15 insertions(+) create mode 100644 test-cargo-miri/test.raw-ptr-track.stdout.ref diff --git a/test-cargo-miri/run-test.py b/test-cargo-miri/run-test.py index 636f4b3bf5f50..8eeafc4ed6749 100755 --- a/test-cargo-miri/run-test.py +++ b/test-cargo-miri/run-test.py @@ -83,6 +83,11 @@ def test_cargo_miri_test(): "test.default.stdout.ref", rustdoc_ref, env={'MIRIFLAGS': "-Zmiri-disable-isolation"}, ) + test("`cargo miri test` (raw-ptr tracking)", + cargo_miri("test") + ["--", "-Zunstable-options", "--exclude-should-panic"], + "test.raw-ptr-track.stdout.ref", rustdoc_ref, + env={'MIRIFLAGS': "-Zmiri-track-raw-pointers"}, + ) test("`cargo miri test` (with filter)", cargo_miri("test") + ["--", "--format=pretty", "le1"], "test.filter.stdout.ref", rustdoc_ref, diff --git a/test-cargo-miri/test.raw-ptr-track.stdout.ref b/test-cargo-miri/test.raw-ptr-track.stdout.ref new file mode 100644 index 0000000000000..c9678beac8f4b --- /dev/null +++ b/test-cargo-miri/test.raw-ptr-track.stdout.ref @@ -0,0 +1,10 @@ + +running 1 test +. +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out + + +running 5 tests +.i... +test result: ok. 4 passed; 0 failed; 1 ignored; 0 measured; 2 filtered out + From e204c0fbaba21ba3771cdbfbbbd2aab9abfc4864 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 21 Dec 2020 14:39:18 +0100 Subject: [PATCH 2491/3747] link to our shiny new Zulip stream --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 38663b408a3d8..fdf45951c6f29 100644 --- a/README.md +++ b/README.md @@ -350,9 +350,9 @@ If you want to contribute to Miri, great! Please check out our [contribution guide](CONTRIBUTING.md). For help with running Miri, you can open an issue here on -GitHub or contact us (`oli-obk` and `RalfJ`) on the [Rust Zulip]. +GitHub or use the [Miri stream on the Rust Zulip][zulip]. -[Rust Zulip]: https://rust-lang.zulipchat.com +[zulip]: https://rust-lang.zulipchat.com/#narrow/stream/269128-miri ## History From 65f5c27d61a401f7429a1b3b52026118e1050def Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 22 Dec 2020 12:47:59 +0100 Subject: [PATCH 2492/3747] remove intrinsic that is now implemented in the rustc side --- src/shims/intrinsics.rs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 956f3b5bde4fb..47a642564e450 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -443,11 +443,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.exact_div(this.read_immediate(num)?, this.read_immediate(denom)?, dest)?; } - "forget" => { - // We get an argument... and forget about it. - let &[_] = check_arg_count(args)?; - } - "try" => return this.handle_try(args, dest, ret), name => throw_unsup_format!("unimplemented intrinsic: {}", name), From a81ebd8fe3f60ef93dfbe85e30c9a7d005befd69 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 29 Dec 2020 19:27:23 +0100 Subject: [PATCH 2493/3747] rustup; add an interesting alias test case --- rust-version | 2 +- tests/compile-fail/box-cell-alias.rs | 18 ++++++++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) create mode 100644 tests/compile-fail/box-cell-alias.rs diff --git a/rust-version b/rust-version index ec1eb6932417b..e261b13e81830 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -15d1f811963649c2f18a88c8e0b39958ec02fd70 +158f8d034b15e65ba8dc0d066358dd0632bfcd6e diff --git a/tests/compile-fail/box-cell-alias.rs b/tests/compile-fail/box-cell-alias.rs new file mode 100644 index 0000000000000..5d63fc1d44a5b --- /dev/null +++ b/tests/compile-fail/box-cell-alias.rs @@ -0,0 +1,18 @@ +// compile-flags: -Zmiri-track-raw-pointers + +// Taken from . + +use std::cell::Cell; + +fn helper(val: Box>, ptr: *const Cell) -> u8 { + val.set(10); + unsafe { (*ptr).set(20); } //~ ERROR does not have an appropriate item in the borrow stack + val.get() +} + +fn main() { + let val: Box> = Box::new(Cell::new(25)); + let ptr: *const Cell = &*val; + let res = helper(val, ptr); + assert_eq!(res, 20); +} From 7e198147df98fa09b09bb1f878a4989754915106 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 31 Dec 2020 00:17:08 +0100 Subject: [PATCH 2494/3747] panicing now works with -Zmiri-track-raw-pointers --- rust-version | 2 +- test-cargo-miri/run-test.py | 4 ++-- test-cargo-miri/test.raw-ptr-track.stdout.ref | 10 ---------- tests/run-pass/dyn-lcsit.rs | 2 +- tests/run-pass/intrinsics.rs | 2 +- 5 files changed, 5 insertions(+), 15 deletions(-) delete mode 100644 test-cargo-miri/test.raw-ptr-track.stdout.ref diff --git a/rust-version b/rust-version index e261b13e81830..9d755c7309346 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -158f8d034b15e65ba8dc0d066358dd0632bfcd6e +507bff92fadf1f25a830da5065a5a87113345163 diff --git a/test-cargo-miri/run-test.py b/test-cargo-miri/run-test.py index 8eeafc4ed6749..60924d4f8ddca 100755 --- a/test-cargo-miri/run-test.py +++ b/test-cargo-miri/run-test.py @@ -84,8 +84,8 @@ def test_cargo_miri_test(): env={'MIRIFLAGS': "-Zmiri-disable-isolation"}, ) test("`cargo miri test` (raw-ptr tracking)", - cargo_miri("test") + ["--", "-Zunstable-options", "--exclude-should-panic"], - "test.raw-ptr-track.stdout.ref", rustdoc_ref, + cargo_miri("test"), + "test.default.stdout.ref", rustdoc_ref, env={'MIRIFLAGS': "-Zmiri-track-raw-pointers"}, ) test("`cargo miri test` (with filter)", diff --git a/test-cargo-miri/test.raw-ptr-track.stdout.ref b/test-cargo-miri/test.raw-ptr-track.stdout.ref deleted file mode 100644 index c9678beac8f4b..0000000000000 --- a/test-cargo-miri/test.raw-ptr-track.stdout.ref +++ /dev/null @@ -1,10 +0,0 @@ - -running 1 test -. -test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out - - -running 5 tests -.i... -test result: ok. 4 passed; 0 failed; 1 ignored; 0 measured; 2 filtered out - diff --git a/tests/run-pass/dyn-lcsit.rs b/tests/run-pass/dyn-lcsit.rs index fa11e9a2a318e..e7a5f13923a8d 100644 --- a/tests/run-pass/dyn-lcsit.rs +++ b/tests/run-pass/dyn-lcsit.rs @@ -32,7 +32,7 @@ const cdef_et3: &dyn Tr1>>> impl Tr1 for A { type As1 = core::ops::Range; fn mk(&self) -> Self::As1 { 0..10 } - }; + } &A }; pub fn use_et3() { diff --git a/tests/run-pass/intrinsics.rs b/tests/run-pass/intrinsics.rs index 8f7dbac670646..00c966b049c4b 100644 --- a/tests/run-pass/intrinsics.rs +++ b/tests/run-pass/intrinsics.rs @@ -24,7 +24,7 @@ fn main() { assert_eq!(intrinsics::likely(false), false); assert_eq!(intrinsics::unlikely(true), true); - unsafe { intrinsics::forget(Bomb); } + intrinsics::forget(Bomb); let _v = intrinsics::discriminant_value(&Some(())); let _v = intrinsics::discriminant_value(&0); From 82c6c77b9a1288ecc955282c9e0de19b96db5203 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 31 Dec 2020 13:11:34 +0100 Subject: [PATCH 2495/3747] test Weak into_raw/from_raw on dangling ptrs --- rust-version | 2 +- tests/run-pass/intrinsics.rs | 6 +++++- tests/run-pass/rc.rs | 8 +++++++- 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/rust-version b/rust-version index 9d755c7309346..1cdca76aa6cbe 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -507bff92fadf1f25a830da5065a5a87113345163 +8b002d5c3489a21db2c16e5af63cf5d234f6972c diff --git a/tests/run-pass/intrinsics.rs b/tests/run-pass/intrinsics.rs index 00c966b049c4b..6885641c02ea0 100644 --- a/tests/run-pass/intrinsics.rs +++ b/tests/run-pass/intrinsics.rs @@ -1,7 +1,8 @@ #![feature(core_intrinsics, const_raw_ptr_comparison)] +#![feature(layout_for_ptr)] use std::intrinsics; -use std::mem::{size_of, size_of_val}; +use std::mem::{size_of, size_of_val, size_of_val_raw}; struct Bomb; @@ -19,6 +20,9 @@ fn main() { assert_eq!(size_of_val(&[1, 2, 3] as &[i32]), 12); assert_eq!(size_of_val("foobar"), 6); + unsafe { assert_eq!(size_of_val_raw(&[1] as &[i32] as *const [i32]), 4); } + unsafe { assert_eq!(size_of_val_raw(0x100 as *const i32), 4); } + assert_eq!(intrinsics::type_name::>(), "core::option::Option"); assert_eq!(intrinsics::likely(false), false); diff --git a/tests/run-pass/rc.rs b/tests/run-pass/rc.rs index 69bd1f8d9ae2d..91de20ae2b7f3 100644 --- a/tests/run-pass/rc.rs +++ b/tests/run-pass/rc.rs @@ -4,7 +4,7 @@ use std::cell::{Cell, RefCell}; use std::rc::{Rc, Weak}; -use std::sync::Arc; +use std::sync::{Arc, Weak as ArcWeak}; use std::fmt::Debug; fn rc_refcell() { @@ -48,6 +48,9 @@ fn arc() { a } assert_eq!(*test(), 42); + + let raw = ArcWeak::into_raw(ArcWeak::::new()); + drop(unsafe { ArcWeak::from_raw(raw) }); } // Make sure this Rc doesn't fall apart when touched @@ -84,6 +87,9 @@ fn weak_into_raw() { drop(unsafe { Weak::from_raw(raw) }); assert_eq!(0, Rc::weak_count(&strong)); + + let raw = Weak::into_raw(Weak::::new()); + drop(unsafe { Weak::from_raw(raw) }); } /// Taken from the `Weak::from_raw` doctest. From 333d7bb2c5f197c21922e5505384ee0c24f7c931 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 10 Jan 2021 19:12:11 +0100 Subject: [PATCH 2496/3747] send Zulip notification when cron job fails --- .github/workflows/ci.yml | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b5ef3d861eadc..fd6258693af69 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -61,15 +61,17 @@ jobs: restore-keys: ${{ runner.os }}-cargo - name: Install rustup-toolchain-install-master and xargo + shell: bash run: | cargo install rustup-toolchain-install-master cargo install xargo - shell: bash - name: Install "master" toolchain + shell: bash run: | if [[ ${{ github.event_name }} == 'schedule' ]]; then RUSTC_HASH=$(git ls-remote https://github.com/rust-lang/rust.git master | awk '{print $1}') + exit 1 # just to test cron notifications else RUSTC_HASH=$(< rust-version) fi @@ -81,7 +83,6 @@ jobs: -c llvm-tools \ --host ${{ matrix.host_target }} rustup default master - shell: bash - name: Show Rust version run: | @@ -113,3 +114,22 @@ jobs: steps: - name: mark the job as a failure run: exit 1 + + # Send a Zulip notification when a cron job fails + cron-fail-notify: + name: cronjob failure notification + runs-on: ubuntu-latest + needs: [build] + if: github.event_name == 'schedule' && (failure() || cancelled()) + steps: + - name: Install zulip-send + run: pip3 install zulip + - name: Send Zulip notification + shell: bash + env: + ZULIP_BOT_EMAIL: ${{ secrets.ZULIP_BOT_EMAIL }} + ZULIP_API_TOKEN: ${{ secrets.ZULIP_API_TOKEN }} + run: | + zulip-send --stream miri --subject "Cron Job Failure" \ + --message '@**RalfJ** @**oli** the Miri cron job build failed. Please investigate!' \ + --user $ZULIP_BOT_EMAIL --api-key $ZULIP_API_TOKEN From 6c112e045956a3c3758cf2225cf0ec0a3a922944 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 11 Jan 2021 12:09:55 +0100 Subject: [PATCH 2497/3747] fix zulip-send path --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index fd6258693af69..ba26a7772d17f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -130,6 +130,6 @@ jobs: ZULIP_BOT_EMAIL: ${{ secrets.ZULIP_BOT_EMAIL }} ZULIP_API_TOKEN: ${{ secrets.ZULIP_API_TOKEN }} run: | - zulip-send --stream miri --subject "Cron Job Failure" \ + ~/.local/bin/zulip-send --stream miri --subject "Cron Job Failure" \ --message '@**RalfJ** @**oli** the Miri cron job build failed. Please investigate!' \ --user $ZULIP_BOT_EMAIL --api-key $ZULIP_API_TOKEN From 8e15f3221e98b1bb96e4e8df080c15b4b7424ade Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 11 Jan 2021 12:35:13 +0100 Subject: [PATCH 2498/3747] rustup --- rust-version | 2 +- src/machine.rs | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 1cdca76aa6cbe..3c44be9d9a760 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -8b002d5c3489a21db2c16e5af63cf5d234f6972c +a2cd91ceb0f156cb442d75e12dc77c3d064cdde4 diff --git a/src/machine.rs b/src/machine.rs index e639bf450ada9..d28aa34c75e8a 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -24,6 +24,7 @@ use rustc_middle::{ use rustc_span::symbol::{sym, Symbol}; use rustc_span::def_id::DefId; use rustc_target::abi::{LayoutOf, Size}; +use rustc_target::spec::abi::Abi; use crate::*; @@ -352,6 +353,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { fn find_mir_or_eval_fn( ecx: &mut InterpCx<'mir, 'tcx, Self>, instance: ty::Instance<'tcx>, + _abi: Abi, args: &[OpTy<'tcx, Tag>], ret: Option<(PlaceTy<'tcx, Tag>, mir::BasicBlock)>, unwind: Option, @@ -363,6 +365,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { fn call_extra_fn( ecx: &mut InterpCx<'mir, 'tcx, Self>, fn_val: Dlsym, + _abi: Abi, args: &[OpTy<'tcx, Tag>], ret: Option<(PlaceTy<'tcx, Tag>, mir::BasicBlock)>, _unwind: Option, From d6b5ead0bae68b5c72a9db657f299aa304e30dc4 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 15 Jan 2021 15:23:20 +0100 Subject: [PATCH 2499/3747] add Zulip site information --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ba26a7772d17f..2119d245b9c82 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -132,4 +132,4 @@ jobs: run: | ~/.local/bin/zulip-send --stream miri --subject "Cron Job Failure" \ --message '@**RalfJ** @**oli** the Miri cron job build failed. Please investigate!' \ - --user $ZULIP_BOT_EMAIL --api-key $ZULIP_API_TOKEN + --user $ZULIP_BOT_EMAIL --api-key $ZULIP_API_TOKEN --site https://rust-lang.zulipchat.com From 4a035103dc4afe952bc89bec3aa2f78d50027778 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 15 Jan 2021 16:41:14 +0100 Subject: [PATCH 2500/3747] rustup; make tests pass again --- rust-version | 2 +- src/data_race.rs | 3 +-- tests/run-pass/concurrency/sync_singlethread.rs | 1 + 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/rust-version b/rust-version index 3c44be9d9a760..0ff7406c5613b 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -a2cd91ceb0f156cb442d75e12dc77c3d064cdde4 +4e208f6a3afb42528878b0f3464e337c4bf3bbc8 diff --git a/src/data_race.rs b/src/data_race.rs index 44cce53957773..d204d60f1565f 100644 --- a/src/data_race.rs +++ b/src/data_race.rs @@ -824,8 +824,7 @@ impl VClockAlloc { // Throw the data-race detection. throw_ub_format!( "Data race detected between {} on {} and {} on {}, memory({:?},offset={},size={})\ - \n\t\t -current vector clock = {:?}\ - \n\t\t -conflicting timestamp = {:?}", + \n(current vector clock = {:?}, conflicting timestamp = {:?})", action, current_thread_info, other_action, diff --git a/tests/run-pass/concurrency/sync_singlethread.rs b/tests/run-pass/concurrency/sync_singlethread.rs index ab0203906d365..2474fe6633c36 100644 --- a/tests/run-pass/concurrency/sync_singlethread.rs +++ b/tests/run-pass/concurrency/sync_singlethread.rs @@ -50,6 +50,7 @@ impl TryLockErrorExt for TryLockError { } fn test_spin_loop_hint() { + #[allow(deprecated)] atomic::spin_loop_hint(); hint::spin_loop(); } From 0b9ee1624899758fc4575cecfa60bb32d36138c6 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 16 Jan 2021 10:29:37 +0100 Subject: [PATCH 2501/3747] undo cronjob deliberate failure --- .github/workflows/ci.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2119d245b9c82..818e3a9038f74 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -71,7 +71,6 @@ jobs: run: | if [[ ${{ github.event_name }} == 'schedule' ]]; then RUSTC_HASH=$(git ls-remote https://github.com/rust-lang/rust.git master | awk '{print $1}') - exit 1 # just to test cron notifications else RUSTC_HASH=$(< rust-version) fi From 7125b86c338a623bbaff5d4e86c73f19e4653c0a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 16 Jan 2021 18:27:10 +0100 Subject: [PATCH 2502/3747] remove some unnecessary feature gates --- tests/compile-fail/check_arg_count_too_few_args.rs | 2 -- tests/compile-fail/check_arg_count_too_many_args.rs | 2 -- 2 files changed, 4 deletions(-) diff --git a/tests/compile-fail/check_arg_count_too_few_args.rs b/tests/compile-fail/check_arg_count_too_few_args.rs index f8d11832683b4..e1cea99eb90b2 100644 --- a/tests/compile-fail/check_arg_count_too_few_args.rs +++ b/tests/compile-fail/check_arg_count_too_few_args.rs @@ -1,5 +1,3 @@ -#![feature(core_intrinsics)] - fn main() { extern "C" { fn malloc() -> *mut std::ffi::c_void; diff --git a/tests/compile-fail/check_arg_count_too_many_args.rs b/tests/compile-fail/check_arg_count_too_many_args.rs index 5163d223fa425..c4028b940ff03 100644 --- a/tests/compile-fail/check_arg_count_too_many_args.rs +++ b/tests/compile-fail/check_arg_count_too_many_args.rs @@ -1,5 +1,3 @@ -#![feature(core_intrinsics)] - fn main() { extern "C" { fn malloc(_: i32, _: i32) -> *mut std::ffi::c_void; From 9949d9e417ff563c3cf7fbadb3ae6d865ab08c53 Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Sun, 17 Jan 2021 23:09:04 +0800 Subject: [PATCH 2503/3747] Remove `#![feature(const_generics)]` and `#![allow(incomplete_features)]` --- src/lib.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 581da0976e512..aadbb0270de49 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -8,9 +8,6 @@ #![warn(rust_2018_idioms)] #![allow(clippy::cast_lossless)] -#![allow(incomplete_features)] -#![feature(const_generics)] - extern crate rustc_attr; extern crate rustc_apfloat; extern crate rustc_ast; From a4a643e7cbd364e72b27f580750da61dbd607047 Mon Sep 17 00:00:00 2001 From: LeSeulArtichaut Date: Sun, 17 Jan 2021 21:26:24 +0100 Subject: [PATCH 2504/3747] Teach the miri cronjobs to speak politely --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 818e3a9038f74..43a964280d5af 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -130,5 +130,5 @@ jobs: ZULIP_API_TOKEN: ${{ secrets.ZULIP_API_TOKEN }} run: | ~/.local/bin/zulip-send --stream miri --subject "Cron Job Failure" \ - --message '@**RalfJ** @**oli** the Miri cron job build failed. Please investigate!' \ + --message 'Dear @**RalfJ** and @**oli**\n\nIt would appear that the Miri cron job build failed. Would you mind investigating this issue?\n\nThanks in advance!\nSincerely,\nThe Miri Cronjobs Bot' \ --user $ZULIP_BOT_EMAIL --api-key $ZULIP_API_TOKEN --site https://rust-lang.zulipchat.com From 3d01ba11c0741a76a562c4b49246deea090d7c03 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 18 Jan 2021 12:55:30 +0100 Subject: [PATCH 2505/3747] rustup; remove some intrinsics that are gone or moved to rustc --- rust-version | 2 +- src/shims/intrinsics.rs | 33 --------------------------------- 2 files changed, 1 insertion(+), 34 deletions(-) diff --git a/rust-version b/rust-version index 0ff7406c5613b..6da6e700194da 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -4e208f6a3afb42528878b0f3464e337c4bf3bbc8 +0677d9729318441a1cdb0c74812ec4140fa4d35f diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 47a642564e450..840dd9f14336d 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -51,39 +51,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // Raw memory accesses - #[rustfmt::skip] - | "copy" - | "copy_nonoverlapping" - => { - let &[src, dest, count] = check_arg_count(args)?; - let elem_ty = instance.substs.type_at(0); - let elem_layout = this.layout_of(elem_ty)?; - let count = this.read_scalar(count)?.to_machine_usize(this)?; - let elem_align = elem_layout.align.abi; - - let size = elem_layout.size.checked_mul(count, this) - .ok_or_else(|| err_ub_format!("overflow computing total size of `{}`", intrinsic_name))?; - let src = this.read_scalar(src)?.check_init()?; - let src = this.memory.check_ptr_access(src, size, elem_align)?; - let dest = this.read_scalar(dest)?.check_init()?; - let dest = this.memory.check_ptr_access(dest, size, elem_align)?; - - if let (Some(src), Some(dest)) = (src, dest) { - this.memory.copy( - src, - dest, - size, - intrinsic_name.ends_with("_nonoverlapping"), - )?; - } - } - - "move_val_init" => { - let &[place, dest] = check_arg_count(args)?; - let place = this.deref_operand(place)?; - this.copy_op(dest, place.into())?; - } - "volatile_load" => { let &[place] = check_arg_count(args)?; let place = this.deref_operand(place)?; From eae95693d8ae5416cc24153a4055661116100467 Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Mon, 18 Jan 2021 18:17:25 +0800 Subject: [PATCH 2506/3747] Add `ArgFlagValueIter` --- cargo-miri/bin.rs | 59 +++++++++++++++++++++++++++++++---------------- 1 file changed, 39 insertions(+), 20 deletions(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index d18e9608cf500..c312a581621a9 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -2,6 +2,7 @@ use std::env; use std::ffi::OsString; use std::fs::{self, File}; use std::io::{self, BufRead, BufReader, BufWriter, Write}; +use std::iter::TakeWhile; use std::ops::Not; use std::path::{Path, PathBuf}; use std::process::Command; @@ -89,31 +90,49 @@ fn has_arg_flag(name: &str) -> bool { args.any(|val| val == name) } -/// Gets the value of a `--flag`. -fn get_arg_flag_value(name: &str) -> Option { - // Stop searching at `--`. - let mut args = std::env::args().take_while(|val| val != "--"); - loop { - let arg = match args.next() { - Some(arg) => arg, - None => return None, - }; - if !arg.starts_with(name) { - continue; +struct ArgFlagValueIter<'a> { + args: TakeWhile bool>, + name: &'a str, +} + +impl<'a> ArgFlagValueIter<'a> { + fn new(name: &'a str) -> Self { + Self { + // Stop searching at `--`. + args: env::args().take_while(|val| val != "--"), + name, } - // Strip leading `name`. - let suffix = &arg[name.len()..]; - if suffix.is_empty() { - // This argument is exactly `name`; the next one is the value. - return args.next(); - } else if suffix.starts_with('=') { - // This argument is `name=value`; get the value. - // Strip leading `=`. - return Some(suffix[1..].to_owned()); + } +} + +impl Iterator for ArgFlagValueIter<'_> { + type Item = String; + + fn next(&mut self) -> Option { + loop { + let arg = self.args.next()?; + if !arg.starts_with(self.name) { + continue; + } + // Strip leading `name`. + let suffix = &arg[self.name.len()..]; + if suffix.is_empty() { + // This argument is exactly `name`; the next one is the value. + return self.args.next(); + } else if suffix.starts_with('=') { + // This argument is `name=value`; get the value. + // Strip leading `=`. + return Some(suffix[1..].to_owned()); + } } } } +/// Gets the value of a `--flag`. +fn get_arg_flag_value(name: &str) -> Option { + ArgFlagValueIter::new(name).next() +} + /// Returns the path to the `miri` binary fn find_miri() -> PathBuf { if let Some(path) = env::var_os("MIRI") { From 3990debf824925230abca279661d7630fd859409 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 22 Jan 2021 09:22:53 +0100 Subject: [PATCH 2507/3747] rustup; test swap of element with itself --- rust-version | 2 +- tests/run-pass/vec.rs | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 6da6e700194da..25ee0983ab43e 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -0677d9729318441a1cdb0c74812ec4140fa4d35f +dc1eee2f256efbd1d3b50b6b090232f81cac6d72 diff --git a/tests/run-pass/vec.rs b/tests/run-pass/vec.rs index 8d83f6380b8f8..5676f9b676bfc 100644 --- a/tests/run-pass/vec.rs +++ b/tests/run-pass/vec.rs @@ -135,6 +135,11 @@ fn sort() { v.sort(); } +fn swap() { + let mut v = vec![1, 2, 3, 4]; + v.swap(2, 2); +} + fn main() { assert_eq!(vec_reallocate().len(), 5); @@ -161,4 +166,5 @@ fn main() { push_str_ptr_stable(); sort(); + swap(); } From 2aedbf0993737939fdff3eb9ded7c8630144f1bc Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Fri, 22 Jan 2021 09:16:27 -0500 Subject: [PATCH 2508/3747] Add shim for libc::sysconf(libc::_SC_NPROCESSORS_CONF) --- src/shims/posix/foreign_items.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/shims/posix/foreign_items.rs b/src/shims/posix/foreign_items.rs index aac164b709b21..f92242f56d9e4 100644 --- a/src/shims/posix/foreign_items.rs +++ b/src/shims/posix/foreign_items.rs @@ -180,6 +180,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let sysconfs = &[ ("_SC_PAGESIZE", Scalar::from_int(PAGE_SIZE, this.pointer_size())), + ("_SC_NPROCESSORS_CONF", Scalar::from_int(NUM_CPUS, this.pointer_size())), ("_SC_NPROCESSORS_ONLN", Scalar::from_int(NUM_CPUS, this.pointer_size())), ]; let mut result = None; From 225e255cfe6995ef241c67dd3eb2264f9b62cbbc Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 23 Jan 2021 16:51:29 +0100 Subject: [PATCH 2509/3747] prefer build-time env vars over run-time values --- cargo-miri/bin.rs | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index d18e9608cf500..b413a0b222e51 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -655,16 +655,21 @@ fn phase_cargo_runner(binary: &Path, binary_args: env::Args) { let info: CrateRunInfo = serde_json::from_reader(file) .unwrap_or_else(|_| show_error(format!("file {:?} contains outdated or invalid JSON; try `cargo clean`", binary))); - // Set missing env vars. Looks like `build.rs` vars are still set at run-time, but - // `CARGO_BIN_EXE_*` are not. This means we can give the run-time environment precedence, - // to rather do too little than too much. + let mut cmd = miri(); + + // Set missing env vars. We prefer build-time env vars over run-time ones; see + // for the kind of issue that fixes. for (name, val) in info.env { - if env::var_os(&name).is_none() { - env::set_var(name, val); + if verbose { + if let Some(old_val) = env::var_os(&name) { + if old_val != val { + eprintln!("[cargo-miri runner] Overwriting run-time env var {:?}={:?} with build-time value {:?}", name, old_val, val); + } + } } + cmd.env(name, val); } - let mut cmd = miri(); // Forward rustc arguments. // We need to patch "--extern" filenames because we forced a check-only // build without cargo knowing about that: replace `.rlib` suffix by From 36ce77699743802bd4ebb2f783df15f25e412e0b Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Sat, 23 Jan 2021 10:51:36 -0500 Subject: [PATCH 2510/3747] Test aarch64-apple-darwin --- ci.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci.sh b/ci.sh index 17bc8df83e182..a1f4a00139461 100755 --- a/ci.sh +++ b/ci.sh @@ -47,7 +47,7 @@ run_tests case $HOST_TARGET in x86_64-unknown-linux-gnu) MIRI_TEST_TARGET=i686-unknown-linux-gnu run_tests - MIRI_TEST_TARGET=x86_64-apple-darwin run_tests + MIRI_TEST_TARGET=aarch64-apple-darwin run_tests MIRI_TEST_TARGET=i686-pc-windows-msvc run_tests ;; x86_64-apple-darwin) From 4a13f24839b2e0fdbf356530d5569a8e322c39d7 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 23 Jan 2021 16:54:00 +0100 Subject: [PATCH 2511/3747] expand README --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index fdf45951c6f29..f4a762937ecd7 100644 --- a/README.md +++ b/README.md @@ -286,6 +286,8 @@ different Miri binaries, and as such worth documenting: directory after loading all the source files, but before commencing interpretation. This is useful if the interpreted program wants a different working directory at run-time than at build-time. +* `MIRI_VERBOSE` when set to any value tells the various `cargo-miri` phases to + perform verbose logging. [testing-miri]: CONTRIBUTING.md#testing-the-miri-driver From 848be1bf824dfbdaa99c016019ef3d60234590ed Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 23 Jan 2021 18:11:01 +0100 Subject: [PATCH 2512/3747] implement aarch64 hint 'intrinsic' --- src/shims/foreign_items.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index d588e2962a150..237fb27d9222b 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -484,6 +484,18 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let &[] = check_arg_count(args)?; this.yield_active_thread(); } + "llvm.aarch64.hint" if this.tcx.sess.target.arch == "aarch64" => { + let &[hint] = check_arg_count(args)?; + let hint = this.read_scalar(hint)?.to_i32()?; + match hint { + 1 => { // HINT_YIELD + this.yield_active_thread(); + } + _ => { + throw_unsup_format!("unsupported llvm.aarch64.hint argument {}", hint); + } + } + } // Platform-specific shims _ => match this.tcx.sess.target.os.as_str() { From 7d8f8c405ff069a5e8e3347b8af8e73b8224a911 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 23 Jan 2021 18:14:57 +0100 Subject: [PATCH 2513/3747] macos: support aarch64 link names --- src/shims/posix/macos/foreign_items.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/shims/posix/macos/foreign_items.rs b/src/shims/posix/macos/foreign_items.rs index 72ec7a5d97022..a4b0ce524df24 100644 --- a/src/shims/posix/macos/foreign_items.rs +++ b/src/shims/posix/macos/foreign_items.rs @@ -25,32 +25,32 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // File related shims - "close$NOCANCEL" => { + "close" | "close$NOCANCEL" => { let &[result] = check_arg_count(args)?; let result = this.close(result)?; this.write_scalar(Scalar::from_i32(result), dest)?; } - "stat$INODE64" => { + "stat" | "stat$INODE64" => { let &[path, buf] = check_arg_count(args)?; let result = this.macos_stat(path, buf)?; this.write_scalar(Scalar::from_i32(result), dest)?; } - "lstat$INODE64" => { + "lstat" | "lstat$INODE64" => { let &[path, buf] = check_arg_count(args)?; let result = this.macos_lstat(path, buf)?; this.write_scalar(Scalar::from_i32(result), dest)?; } - "fstat$INODE64" => { + "fstat" | "fstat$INODE64" => { let &[fd, buf] = check_arg_count(args)?; let result = this.macos_fstat(fd, buf)?; this.write_scalar(Scalar::from_i32(result), dest)?; } - "opendir$INODE64" => { + "opendir" | "opendir$INODE64" => { let &[name] = check_arg_count(args)?; let result = this.opendir(name)?; this.write_scalar(result, dest)?; } - "readdir_r$INODE64" => { + "readdir_r" | "readdir_r$INODE64" => { let &[dirp, entry, result] = check_arg_count(args)?; let result = this.macos_readdir_r(dirp, entry, result)?; this.write_scalar(Scalar::from_i32(result), dest)?; From 056016571fbcbe3f1f8d14f2595aa941108328d8 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 24 Jan 2021 15:58:37 +0100 Subject: [PATCH 2514/3747] add -Zmiri-disable-data-race-detector to readme --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index f4a762937ecd7..b2f0babfc9bc0 100644 --- a/README.md +++ b/README.md @@ -198,6 +198,8 @@ environment variable: * `-Zmiri-disable-alignment-check` disables checking pointer alignment, so you can focus on other failures, but it means Miri can miss bugs in your program. Using this flag is **unsound**. +* `-Zmiri-disable-data-race-detector` disables checking for data races. Using + this flag is **unsound**. * `-Zmiri-disable-stacked-borrows` disables checking the experimental [Stacked Borrows] aliasing rules. This can make Miri run faster, but it also means no aliasing violations will be detected. Using this flag is **unsound** From ecab8a4fae3668f9f06e1524345732f194573e9d Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Mon, 18 Jan 2021 23:50:10 +0800 Subject: [PATCH 2515/3747] Skip unit tests of `proc-macro` crates --- cargo-miri/bin.rs | 78 +++++++++++++++++++++++++++++++++++------------ 1 file changed, 59 insertions(+), 19 deletions(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index c312a581621a9..b968b9df5918c 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -37,9 +37,9 @@ enum MiriCommand { Setup, } -/// The inforamtion Miri needs to run a crate. Stored as JSON when the crate is "compiled". +/// The information to run a crate with the given environment. #[derive(Serialize, Deserialize)] -struct CrateRunInfo { +struct CrateRunEnv { /// The command-line arguments. args: Vec, /// The environment. @@ -48,13 +48,22 @@ struct CrateRunInfo { current_dir: OsString, } +/// The information Miri needs to run a crate. Stored as JSON when the crate is "compiled". +#[derive(Serialize, Deserialize)] +enum CrateRunInfo { + /// Run it with the given environment. + RunWith(CrateRunEnv), + /// Skip it as Miri does not support interpreting such kind of crates. + SkipProcMacroTest, +} + impl CrateRunInfo { /// Gather all the information we need. fn collect(args: env::Args) -> Self { let args = args.collect(); let env = env::vars_os().collect(); let current_dir = env::current_dir().unwrap().into_os_string(); - CrateRunInfo { args, env, current_dir } + Self::RunWith(CrateRunEnv { args, env, current_dir }) } fn store(&self, filename: &Path) { @@ -90,6 +99,7 @@ fn has_arg_flag(name: &str) -> bool { args.any(|val| val == name) } +/// Yields all values of command line flag `name`. struct ArgFlagValueIter<'a> { args: TakeWhile bool>, name: &'a str, @@ -455,14 +465,15 @@ fn phase_cargo_miri(mut args: env::Args) { // This is needed to make the `CARGO_TARGET_*_RUNNER` env var do something, // and it later helps us detect which crates are proc-macro/build-script // (host crates) and which crates are needed for the program itself. - let target = if let Some(target) = get_arg_flag_value("--target") { + let host = version_info().host; + let target = get_arg_flag_value("--target"); + let target = if let Some(ref target) = target { target } else { // No target given. Pick default and tell cargo about it. - let host = version_info().host; cmd.arg("--target"); cmd.arg(&host); - host + &host }; // Forward all further arguments. We do some processing here because we want to @@ -514,9 +525,16 @@ fn phase_cargo_miri(mut args: env::Args) { } cmd.env("RUSTC_WRAPPER", &cargo_miri_path); - // Set the runner for the current target to us as well, so we can interpret the binaries. - let runner_env_name = format!("CARGO_TARGET_{}_RUNNER", target.to_uppercase().replace('-', "_")); - cmd.env(&runner_env_name, &cargo_miri_path); + let runner_env_name = |triple: &str| { + format!("CARGO_TARGET_{}_RUNNER", triple.to_uppercase().replace('-', "_")) + }; + let host_runner_env_name = runner_env_name(&host); + let target_runner_env_name = runner_env_name(target); + // Set the target runner to us, so we can interpret the binaries. + cmd.env(&target_runner_env_name, &cargo_miri_path); + // Unit tests of `proc-macro` crates are run on the host, so we set the host runner to + // us in order to skip them. + cmd.env(&host_runner_env_name, &cargo_miri_path); // Set rustdoc to us as well, so we can make it do nothing (see issue #584). cmd.env("RUSTDOC", &cargo_miri_path); @@ -524,7 +542,10 @@ fn phase_cargo_miri(mut args: env::Args) { // Run cargo. if verbose { eprintln!("[cargo-miri miri] RUSTC_WRAPPER={:?}", cargo_miri_path); - eprintln!("[cargo-miri miri] {}={:?}", runner_env_name, cargo_miri_path); + eprintln!("[cargo-miri miri] {}={:?}", target_runner_env_name, cargo_miri_path); + if *target != host { + eprintln!("[cargo-miri miri] {}={:?}", host_runner_env_name, cargo_miri_path); + } eprintln!("[cargo-miri miri] RUSTDOC={:?}", cargo_miri_path); eprintln!("[cargo-miri miri] {:?}", cmd); cmd.env("MIRI_VERBOSE", ""); // This makes the other phases verbose. @@ -587,23 +608,34 @@ fn phase_cargo_rustc(args: env::Args) { _ => {}, } - if !print && target_crate && is_runnable_crate() { - // This is the binary or test crate that we want to interpret under Miri. - // But we cannot run it here, as cargo invoked us as a compiler -- our stdin and stdout are not - // like we want them. - // Instead of compiling, we write JSON into the output file with all the relevant command-line flags - // and environment variables; this is used when cargo calls us again in the CARGO_TARGET_RUNNER phase. - let info = CrateRunInfo::collect(args); + let store_json = |info: CrateRunInfo| { let filename = out_filename("", ""); if verbose { eprintln!("[cargo-miri rustc] writing run info to `{}`", filename.display()); } - info.store(&filename); // For Windows, do the same thing again with `.exe` appended to the filename. // (Need to do this here as cargo moves that "binary" to a different place before running it.) info.store(&out_filename("", ".exe")); + }; + let runnable_crate = !print && is_runnable_crate(); + + if runnable_crate && target_crate { + // This is the binary or test crate that we want to interpret under Miri. + // But we cannot run it here, as cargo invoked us as a compiler -- our stdin and stdout are not + // like we want them. + // Instead of compiling, we write JSON into the output file with all the relevant command-line flags + // and environment variables; this is used when cargo calls us again in the CARGO_TARGET_RUNNER phase. + store_json(CrateRunInfo::collect(args)); + return; + } + + if runnable_crate && ArgFlagValueIter::new("--extern").any(|krate| krate == "proc_macro") { + // This is a "runnable" `proc-macro` crate (unit tests). We do not support + // interpreting that under Miri now, so we write a JSON file to (display a + // helpful message and) skip it in the runner phase. + store_json(CrateRunInfo::SkipProcMacroTest); return; } @@ -671,8 +703,16 @@ fn phase_cargo_runner(binary: &Path, binary_args: env::Args) { let file = File::open(&binary) .unwrap_or_else(|_| show_error(format!("file {:?} not found or `cargo-miri` invoked incorrectly; please only invoke this binary through `cargo miri`", binary))); let file = BufReader::new(file); - let info: CrateRunInfo = serde_json::from_reader(file) + + let info = serde_json::from_reader(file) .unwrap_or_else(|_| show_error(format!("file {:?} contains outdated or invalid JSON; try `cargo clean`", binary))); + let info = match info { + CrateRunInfo::RunWith(info) => info, + CrateRunInfo::SkipProcMacroTest => { + eprintln!("Running unit tests of `proc-macro` crates is not currently supported by Miri."); + return; + } + }; // Set missing env vars. Looks like `build.rs` vars are still set at run-time, but // `CARGO_BIN_EXE_*` are not. This means we can give the run-time environment precedence, From 28577924e7de574ae41f7bd99591da280cb57a15 Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Tue, 19 Jan 2021 00:26:15 +0800 Subject: [PATCH 2516/3747] Add a test for unit test of `proc-macro` crate --- test-cargo-miri/run-test.py | 2 +- test-cargo-miri/subcrate/Cargo.toml | 4 ++++ test-cargo-miri/subcrate/src/lib.rs | 2 ++ test-cargo-miri/test.stderr-proc-macro.ref | 1 + 4 files changed, 8 insertions(+), 1 deletion(-) create mode 100644 test-cargo-miri/subcrate/src/lib.rs create mode 100644 test-cargo-miri/test.stderr-proc-macro.ref diff --git a/test-cargo-miri/run-test.py b/test-cargo-miri/run-test.py index 60924d4f8ddca..8edd947c3b0fa 100755 --- a/test-cargo-miri/run-test.py +++ b/test-cargo-miri/run-test.py @@ -102,7 +102,7 @@ def test_cargo_miri_test(): ) test("`cargo miri test` (subcrate, no isolation)", cargo_miri("test") + ["-p", "subcrate"], - "test.subcrate.stdout.ref", "test.stderr-empty.ref", + "test.subcrate.stdout.ref", "test.stderr-proc-macro.ref", env={'MIRIFLAGS': "-Zmiri-disable-isolation"}, ) diff --git a/test-cargo-miri/subcrate/Cargo.toml b/test-cargo-miri/subcrate/Cargo.toml index be27f88ad9a1c..ea2936d52a054 100644 --- a/test-cargo-miri/subcrate/Cargo.toml +++ b/test-cargo-miri/subcrate/Cargo.toml @@ -4,6 +4,10 @@ version = "0.1.0" authors = ["Miri Team"] edition = "2018" +[lib] +proc-macro = true +doctest = false + [[bin]] name = "subcrate" path = "main.rs" diff --git a/test-cargo-miri/subcrate/src/lib.rs b/test-cargo-miri/subcrate/src/lib.rs new file mode 100644 index 0000000000000..706e368017c0e --- /dev/null +++ b/test-cargo-miri/subcrate/src/lib.rs @@ -0,0 +1,2 @@ +#[cfg(test)] +compile_error!("Miri should not touch me"); diff --git a/test-cargo-miri/test.stderr-proc-macro.ref b/test-cargo-miri/test.stderr-proc-macro.ref new file mode 100644 index 0000000000000..4983250917b59 --- /dev/null +++ b/test-cargo-miri/test.stderr-proc-macro.ref @@ -0,0 +1 @@ +Running unit tests of `proc-macro` crates is not currently supported by Miri. From a5d7ae5816e22dcd37989e45ca3d36e6366e1c53 Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Mon, 25 Jan 2021 16:10:28 +0800 Subject: [PATCH 2517/3747] Fix `\n` in Zulip message https://rust-lang.zulipchat.com/#narrow/stream/269128-miri/topic/Cron.20Job.20Failure/near/223865005 --- .github/workflows/ci.yml | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 43a964280d5af..a55cd8212517e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -130,5 +130,11 @@ jobs: ZULIP_API_TOKEN: ${{ secrets.ZULIP_API_TOKEN }} run: | ~/.local/bin/zulip-send --stream miri --subject "Cron Job Failure" \ - --message 'Dear @**RalfJ** and @**oli**\n\nIt would appear that the Miri cron job build failed. Would you mind investigating this issue?\n\nThanks in advance!\nSincerely,\nThe Miri Cronjobs Bot' \ + --message 'Dear @**RalfJ** and @**oli** + + It would appear that the Miri cron job build failed. Would you mind investigating this issue? + + Thanks in advance! + Sincerely, + The Miri Cronjobs Bot' \ --user $ZULIP_BOT_EMAIL --api-key $ZULIP_API_TOKEN --site https://rust-lang.zulipchat.com From 13dd513254f92e5faa3f4ac7d41fc084c11fbb85 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 25 Jan 2021 09:46:10 +0100 Subject: [PATCH 2518/3747] adjust Windows shims for stdlib changes (Windows XP removal) --- rust-version | 2 +- src/shims/windows/dlsym.rs | 1 - src/shims/windows/foreign_items.rs | 35 ++++++++++++++++++++++++++++++ 3 files changed, 36 insertions(+), 2 deletions(-) diff --git a/rust-version b/rust-version index 25ee0983ab43e..2064258addf68 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -dc1eee2f256efbd1d3b50b6b090232f81cac6d72 +9a9477fada5baf69d693e717d6df902e411a73d6 diff --git a/src/shims/windows/dlsym.rs b/src/shims/windows/dlsym.rs index 415299c51fc66..c88a16461153d 100644 --- a/src/shims/windows/dlsym.rs +++ b/src/shims/windows/dlsym.rs @@ -27,7 +27,6 @@ impl Dlsym { "AcquireSRWLockShared" => Some(Dlsym::AcquireSRWLockShared), "ReleaseSRWLockShared" => Some(Dlsym::ReleaseSRWLockShared), "TryAcquireSRWLockShared" => Some(Dlsym::TryAcquireSRWLockShared), - "SetThreadStackGuarantee" => None, "GetSystemTimePreciseAsFileTime" => None, _ => throw_unsup_format!("unsupported Windows dlsym: {}", name), }) diff --git a/src/shims/windows/foreign_items.rs b/src/shims/windows/foreign_items.rs index 12b714880b359..17d566d18eea1 100644 --- a/src/shims/windows/foreign_items.rs +++ b/src/shims/windows/foreign_items.rs @@ -5,6 +5,7 @@ use rustc_target::abi::Size; use crate::*; use helpers::check_arg_count; +use shims::windows::sync::EvalContextExt as _; impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { @@ -207,6 +208,34 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_i32(result), dest)?; } + // Synchronization primitives + "AcquireSRWLockExclusive" => { + let &[ptr] = check_arg_count(args)?; + this.AcquireSRWLockExclusive(ptr)?; + } + "ReleaseSRWLockExclusive" => { + let &[ptr] = check_arg_count(args)?; + this.ReleaseSRWLockExclusive(ptr)?; + } + "TryAcquireSRWLockExclusive" => { + let &[ptr] = check_arg_count(args)?; + let ret = this.TryAcquireSRWLockExclusive(ptr)?; + this.write_scalar(Scalar::from_u8(ret), dest)?; + } + "AcquireSRWLockShared" => { + let &[ptr] = check_arg_count(args)?; + this.AcquireSRWLockShared(ptr)?; + } + "ReleaseSRWLockShared" => { + let &[ptr] = check_arg_count(args)?; + this.ReleaseSRWLockShared(ptr)?; + } + "TryAcquireSRWLockShared" => { + let &[ptr] = check_arg_count(args)?; + let ret = this.TryAcquireSRWLockShared(ptr)?; + this.write_scalar(Scalar::from_u8(ret), dest)?; + } + // Dynamic symbol loading "GetProcAddress" => { #[allow(non_snake_case)] @@ -285,6 +314,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Any non zero value works for the stdlib. This is just used for stack overflows anyway. this.write_scalar(Scalar::from_machine_usize(1, this), dest)?; } + "SetThreadStackGuarantee" if this.frame().instance.to_string().starts_with("std::sys::windows::") => { + #[allow(non_snake_case)] + let &[_StackSizeInBytes] = check_arg_count(args)?; + // Any non zero value works for the stdlib. This is just used for stack overflows anyway. + this.write_scalar(Scalar::from_u32(1), dest)?; + } | "InitializeCriticalSection" | "EnterCriticalSection" | "LeaveCriticalSection" From c678bd722ea6fe8d1827787d5ecd411a77f411ca Mon Sep 17 00:00:00 2001 From: Thom Chiovoloni Date: Sun, 24 Jan 2021 13:45:45 -0800 Subject: [PATCH 2519/3747] Add random failures to compare_exchange_weak --- src/data_race.rs | 21 ++++++++++++++++----- src/shims/intrinsics.rs | 18 +++++++++++------- tests/run-pass/atomic.rs | 26 ++++++++++++++++++-------- 3 files changed, 45 insertions(+), 20 deletions(-) diff --git a/src/data_race.rs b/src/data_race.rs index d204d60f1565f..31a167af8899a 100644 --- a/src/data_race.rs +++ b/src/data_race.rs @@ -75,7 +75,7 @@ use rustc_target::abi::Size; use crate::{ ImmTy, Immediate, InterpResult, MPlaceTy, MemPlaceMeta, MiriEvalContext, MiriEvalContextExt, - OpTy, Pointer, RangeMap, ScalarMaybeUninit, Tag, ThreadId, VClock, VTimestamp, + OpTy, Pointer, RangeMap, Scalar, ScalarMaybeUninit, Tag, ThreadId, VClock, VTimestamp, VectorIdx, MemoryKind, MiriMemoryKind }; @@ -544,7 +544,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { /// Perform an atomic compare and exchange at a given memory location. /// On success an atomic RMW operation is performed and on failure - /// only an atomic read occurs. + /// only an atomic read occurs. If `can_fail_spuriously` is true, + /// then we treat it as a "compare_exchange_weak" operation, and + /// some portion of the time fail even when the values are actually + /// identical. fn atomic_compare_exchange_scalar( &mut self, place: MPlaceTy<'tcx, Tag>, @@ -552,7 +555,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { new: ScalarMaybeUninit, success: AtomicRwOp, fail: AtomicReadOp, + can_fail_spuriously: bool, ) -> InterpResult<'tcx, Immediate> { + use rand::Rng as _; let this = self.eval_context_mut(); // Failure ordering cannot be stronger than success ordering, therefore first attempt @@ -560,15 +565,21 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { // read ordering and write in the success case. // Read as immediate for the sake of `binary_op()` let old = this.allow_data_races_mut(|this| this.read_immediate(place.into()))?; - // `binary_op` will bail if either of them is not a scalar. let eq = this.overflowing_binary_op(mir::BinOp::Eq, old, expect_old)?.0; - let res = Immediate::ScalarPair(old.to_scalar_or_uninit(), eq.into()); + // If the operation would succeed, but is "weak", fail 50% of the time. + // FIXME: this is quite arbitrary. + let cmpxchg_success = eq.to_bool()? + && (!can_fail_spuriously || this.memory.extra.rng.borrow_mut().gen_range(0, 2) == 0); + let res = Immediate::ScalarPair( + old.to_scalar_or_uninit(), + Scalar::from_bool(cmpxchg_success).into(), + ); // Update ptr depending on comparison. // if successful, perform a full rw-atomic validation // otherwise treat this as an atomic load with the fail ordering. - if eq.to_bool()? { + if cmpxchg_success { this.allow_data_races_mut(|this| this.write_scalar(new, place.into()))?; this.validate_atomic_rmw(place, success)?; } else { diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 840dd9f14336d..73419a9f97647 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -518,9 +518,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(()) } - fn atomic_compare_exchange( + fn atomic_compare_exchange_impl( &mut self, args: &[OpTy<'tcx, Tag>], dest: PlaceTy<'tcx, Tag>, - success: AtomicRwOp, fail: AtomicReadOp + success: AtomicRwOp, fail: AtomicReadOp, can_fail_spuriously: bool ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); @@ -538,7 +538,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let old = this.atomic_compare_exchange_scalar( - place, expect_old, new, success, fail + place, expect_old, new, success, fail, can_fail_spuriously )?; // Return old value. @@ -546,14 +546,18 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(()) } - fn atomic_compare_exchange_weak( + fn atomic_compare_exchange( &mut self, args: &[OpTy<'tcx, Tag>], dest: PlaceTy<'tcx, Tag>, success: AtomicRwOp, fail: AtomicReadOp ) -> InterpResult<'tcx> { + self.atomic_compare_exchange_impl(args, dest, success, fail, false) + } - // FIXME: the weak part of this is currently not modelled, - // it is assumed to always succeed unconditionally. - self.atomic_compare_exchange(args, dest, success, fail) + fn atomic_compare_exchange_weak( + &mut self, args: &[OpTy<'tcx, Tag>], dest: PlaceTy<'tcx, Tag>, + success: AtomicRwOp, fail: AtomicReadOp + ) -> InterpResult<'tcx> { + self.atomic_compare_exchange_impl(args, dest, success, fail, true) } fn float_to_int_unchecked( diff --git a/tests/run-pass/atomic.rs b/tests/run-pass/atomic.rs index b03a8c8901e18..4ebca71c7cf38 100644 --- a/tests/run-pass/atomic.rs +++ b/tests/run-pass/atomic.rs @@ -24,7 +24,20 @@ fn atomic_bool() { assert_eq!(*ATOMIC.get_mut(), false); } } - +// There isn't a trait to use to make this generic, so just use a macro +macro_rules! compare_exchange_weak_loop { + ($atom:expr, $from:expr, $to:expr, $succ_order:expr, $fail_order:expr) => { + loop { + match $atom.compare_exchange_weak($from, $to, $succ_order, $fail_order) { + Ok(n) => { + assert_eq!(n, $from); + break; + } + Err(n) => assert_eq!(n, $from), + } + } + }; +} fn atomic_isize() { static ATOMIC: AtomicIsize = AtomicIsize::new(0); @@ -40,11 +53,11 @@ fn atomic_isize() { ATOMIC.compare_exchange(0, 1, SeqCst, SeqCst).ok(); ATOMIC.store(0, SeqCst); - - assert_eq!(ATOMIC.compare_exchange_weak(0, 1, Relaxed, Relaxed), Ok(0)); + compare_exchange_weak_loop!(ATOMIC, 0, 1, Relaxed, Relaxed); assert_eq!(ATOMIC.compare_exchange_weak(0, 2, Acquire, Relaxed), Err(1)); assert_eq!(ATOMIC.compare_exchange_weak(0, 1, Release, Relaxed), Err(1)); - assert_eq!(ATOMIC.compare_exchange_weak(1, 0, AcqRel, Relaxed), Ok(1)); + compare_exchange_weak_loop!(ATOMIC, 1, 0, AcqRel, Relaxed); + assert_eq!(ATOMIC.load(Relaxed), 0); ATOMIC.compare_exchange_weak(0, 1, AcqRel, Relaxed).ok(); ATOMIC.compare_exchange_weak(0, 1, SeqCst, Relaxed).ok(); ATOMIC.compare_exchange_weak(0, 1, Acquire, Acquire).ok(); @@ -58,10 +71,7 @@ fn atomic_u64() { ATOMIC.store(1, SeqCst); assert_eq!(ATOMIC.compare_exchange(0, 0x100, AcqRel, Acquire), Err(1)); - assert_eq!( - ATOMIC.compare_exchange_weak(1, 0x100, AcqRel, Acquire), - Ok(1) - ); + compare_exchange_weak_loop!(ATOMIC, 1, 0x100, AcqRel, Acquire); assert_eq!(ATOMIC.load(Relaxed), 0x100); } From b6eccc6482ba9524b0ad7f0561bc0e77adcd5d24 Mon Sep 17 00:00:00 2001 From: Thom Chiovoloni Date: Mon, 25 Jan 2021 02:41:03 -0800 Subject: [PATCH 2520/3747] Test that _weak atomics sometimes fail --- tests/run-pass/atomic.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/tests/run-pass/atomic.rs b/tests/run-pass/atomic.rs index 4ebca71c7cf38..4871aa9fe0f65 100644 --- a/tests/run-pass/atomic.rs +++ b/tests/run-pass/atomic.rs @@ -5,6 +5,7 @@ fn main() { atomic_isize(); atomic_u64(); atomic_fences(); + weak_sometimes_fails(); } fn atomic_bool() { @@ -85,3 +86,17 @@ fn atomic_fences() { compiler_fence(Acquire); compiler_fence(AcqRel); } + +fn weak_sometimes_fails() { + static ATOMIC: AtomicBool = AtomicBool::new(false); + let tries = 20; + for _ in 0..tries { + let cur = ATOMIC.load(Relaxed); + // Try (weakly) to flip the flag. + if ATOMIC.compare_exchange_weak(cur, !cur, Relaxed, Relaxed).is_err() { + // We succeeded, so return and skip the panic. + return; + } + } + panic!("compare_exchange_weak succeeded {} tries in a row", tries); +} From efd2d55e001de2a069d9ad45687abb5834f227da Mon Sep 17 00:00:00 2001 From: Thom Chiovoloni Date: Mon, 25 Jan 2021 02:52:55 -0800 Subject: [PATCH 2521/3747] review nits --- tests/run-pass/atomic.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/run-pass/atomic.rs b/tests/run-pass/atomic.rs index 4871aa9fe0f65..66d25ca01ea97 100644 --- a/tests/run-pass/atomic.rs +++ b/tests/run-pass/atomic.rs @@ -88,13 +88,13 @@ fn atomic_fences() { } fn weak_sometimes_fails() { - static ATOMIC: AtomicBool = AtomicBool::new(false); + let atomic = AtomicBool::new(false); let tries = 20; for _ in 0..tries { - let cur = ATOMIC.load(Relaxed); + let cur = atomic.load(Relaxed); // Try (weakly) to flip the flag. - if ATOMIC.compare_exchange_weak(cur, !cur, Relaxed, Relaxed).is_err() { - // We succeeded, so return and skip the panic. + if atomic.compare_exchange_weak(cur, !cur, Relaxed, Relaxed).is_err() { + // We failed, so return and skip the panic. return; } } From d4b592ed17471622d27deeab8a1d8d89bc5c17d1 Mon Sep 17 00:00:00 2001 From: Thom Chiovoloni Date: Mon, 25 Jan 2021 02:59:12 -0800 Subject: [PATCH 2522/3747] Fail 80% of the time on weak cmpxchg, not 50% --- src/data_race.rs | 4 ++-- tests/run-pass/atomic.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/data_race.rs b/src/data_race.rs index 31a167af8899a..dd0dccd0e9504 100644 --- a/src/data_race.rs +++ b/src/data_race.rs @@ -567,10 +567,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { let old = this.allow_data_races_mut(|this| this.read_immediate(place.into()))?; // `binary_op` will bail if either of them is not a scalar. let eq = this.overflowing_binary_op(mir::BinOp::Eq, old, expect_old)?.0; - // If the operation would succeed, but is "weak", fail 50% of the time. + // If the operation would succeed, but is "weak", fail 80% of the time. // FIXME: this is quite arbitrary. let cmpxchg_success = eq.to_bool()? - && (!can_fail_spuriously || this.memory.extra.rng.borrow_mut().gen_range(0, 2) == 0); + && (!can_fail_spuriously || this.memory.extra.rng.borrow_mut().gen_range(0, 10) < 8); let res = Immediate::ScalarPair( old.to_scalar_or_uninit(), Scalar::from_bool(cmpxchg_success).into(), diff --git a/tests/run-pass/atomic.rs b/tests/run-pass/atomic.rs index 66d25ca01ea97..4f27c2bd54d67 100644 --- a/tests/run-pass/atomic.rs +++ b/tests/run-pass/atomic.rs @@ -89,7 +89,7 @@ fn atomic_fences() { fn weak_sometimes_fails() { let atomic = AtomicBool::new(false); - let tries = 20; + let tries = 100; for _ in 0..tries { let cur = atomic.load(Relaxed); // Try (weakly) to flip the flag. From d310620c11bb61156d9198b7c5c3c574846ff73d Mon Sep 17 00:00:00 2001 From: Thom Chiovoloni Date: Tue, 26 Jan 2021 00:07:43 -0800 Subject: [PATCH 2523/3747] Allow configuring the failure rate with -Zmiri-compare-exchange-weak-failure-rate --- src/bin/miri.rs | 8 ++++++++ src/data_race.rs | 7 ++++--- src/eval.rs | 4 ++++ src/machine.rs | 4 ++++ 4 files changed, 20 insertions(+), 3 deletions(-) diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 1117b69116a5d..bd3bc8dbb4125 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -282,6 +282,14 @@ fn main() { }; miri_config.tracked_alloc_id = Some(miri::AllocId(id)); } + arg if arg.starts_with("-Zmiri-compare-exchange-weak-failure-rate=") => { + let rate = match arg.strip_prefix("-Zmiri-compare-exchange-weak-failure-rate=").unwrap().parse::() { + Ok(rate) if rate >= 0.0 && rate <= 1.0 => rate, + Ok(_) => panic!("-Zmiri-compare-exchange-weak-failure-rate must be between `0.0` and `1.0`"), + Err(err) => panic!("-Zmiri-compare-exchange-weak-failure-rate requires a `f64` between `0.0` and `1.0`: {}", err), + }; + miri_config.cmpxchg_weak_failure_rate = rate; + } _ => { // Forward to rustc. rustc_args.push(arg); diff --git a/src/data_race.rs b/src/data_race.rs index dd0dccd0e9504..f79775e12fe74 100644 --- a/src/data_race.rs +++ b/src/data_race.rs @@ -567,10 +567,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { let old = this.allow_data_races_mut(|this| this.read_immediate(place.into()))?; // `binary_op` will bail if either of them is not a scalar. let eq = this.overflowing_binary_op(mir::BinOp::Eq, old, expect_old)?.0; - // If the operation would succeed, but is "weak", fail 80% of the time. - // FIXME: this is quite arbitrary. + // If the operation would succeed, but is "weak", fail some portion + // of the time, based on `rate`. + let rate = this.memory.extra.cmpxchg_weak_failure_rate; let cmpxchg_success = eq.to_bool()? - && (!can_fail_spuriously || this.memory.extra.rng.borrow_mut().gen_range(0, 10) < 8); + && (!can_fail_spuriously || this.memory.extra.rng.borrow_mut().gen::() < rate); let res = Immediate::ScalarPair( old.to_scalar_or_uninit(), Scalar::from_bool(cmpxchg_success).into(), diff --git a/src/eval.rs b/src/eval.rs index 0a62f14dd3a15..b6d4fa05e1e5a 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -50,6 +50,9 @@ pub struct MiriConfig { pub track_raw: bool, /// Determine if data race detection should be enabled pub data_race_detector: bool, + /// Rate of spurious failures for compare_exchange_weak atomic operations, + /// between 0.0 and 1.0, defaulting to 0.8 (80% chance of failure). + pub cmpxchg_weak_failure_rate: f64, } impl Default for MiriConfig { @@ -68,6 +71,7 @@ impl Default for MiriConfig { tracked_alloc_id: None, track_raw: false, data_race_detector: true, + cmpxchg_weak_failure_rate: 0.8, } } } diff --git a/src/machine.rs b/src/machine.rs index d28aa34c75e8a..60a6dae0f81b3 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -135,6 +135,9 @@ pub struct MemoryExtra { /// Controls whether alignment of memory accesses is being checked. pub(crate) check_alignment: AlignmentCheck, + + /// Failure rate of compare_exchange_weak, between 0.0 and 1.0 + pub(crate) cmpxchg_weak_failure_rate: f64, } impl MemoryExtra { @@ -162,6 +165,7 @@ impl MemoryExtra { rng: RefCell::new(rng), tracked_alloc_id: config.tracked_alloc_id, check_alignment: config.check_alignment, + cmpxchg_weak_failure_rate: config.cmpxchg_weak_failure_rate, } } From d38e861f1e0afc7f9853935d41c92f91d8c3cf78 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 26 Jan 2021 11:43:39 +0100 Subject: [PATCH 2524/3747] rustup; allow some lints --- rust-version | 2 +- tests/run-pass/float.rs | 1 + tests/run-pass/integer-ops.rs | 10 +--------- 3 files changed, 3 insertions(+), 10 deletions(-) diff --git a/rust-version b/rust-version index 2064258addf68..d4006f955da54 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -9a9477fada5baf69d693e717d6df902e411a73d6 +a8f707553276a15565860af3d415aae18428aa96 diff --git a/tests/run-pass/float.rs b/tests/run-pass/float.rs index d0df13490f0c8..d9dba770dabd7 100644 --- a/tests/run-pass/float.rs +++ b/tests/run-pass/float.rs @@ -1,4 +1,5 @@ #![feature(stmt_expr_attributes, test)] +#![allow(arithmetic_overflow)] use std::fmt::Debug; use std::hint::black_box; diff --git a/tests/run-pass/integer-ops.rs b/tests/run-pass/integer-ops.rs index 4ae42df592002..36bd5797177a2 100644 --- a/tests/run-pass/integer-ops.rs +++ b/tests/run-pass/integer-ops.rs @@ -1,12 +1,4 @@ -// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. +#![allow(arithmetic_overflow)] pub fn main() { // This tests that do (not) do sign extension properly when loading integers From 0e56bff5f92a557113d92758b0a4570455286a3d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 26 Jan 2021 11:48:11 +0100 Subject: [PATCH 2525/3747] erroneous_const span now changes with inlining --- tests/compile-fail/erroneous_const.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/compile-fail/erroneous_const.rs b/tests/compile-fail/erroneous_const.rs index 287e073581416..7f1a818208902 100644 --- a/tests/compile-fail/erroneous_const.rs +++ b/tests/compile-fail/erroneous_const.rs @@ -1,5 +1,7 @@ //! Make sure we detect erroneous constants post-monomorphization even when they are unused. //! (https://github.com/rust-lang/miri/issues/1382) +// Inlining changes the error location +// compile-flags: -Zmir-opt-level=0 #![feature(const_panic)] #![feature(never_type)] #![warn(warnings, const_err)] From e308eeb3f13b6ee8665f9d10a3b184383431fdeb Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 27 Jan 2021 10:43:59 +0100 Subject: [PATCH 2526/3747] rustup; more slack for timing tests --- rust-version | 2 +- tests/run-pass/concurrency/sync.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/rust-version b/rust-version index d4006f955da54..af4bc45869dcd 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -a8f707553276a15565860af3d415aae18428aa96 +78e22069d018e83915201c8a218a0a94227f6420 diff --git a/tests/run-pass/concurrency/sync.rs b/tests/run-pass/concurrency/sync.rs index e97da415cbb1c..88187d64e604a 100644 --- a/tests/run-pass/concurrency/sync.rs +++ b/tests/run-pass/concurrency/sync.rs @@ -92,7 +92,7 @@ fn check_conditional_variables_timed_wait_timeout() { let (_guard, timeout) = cvar.wait_timeout(guard, Duration::from_millis(100)).unwrap(); assert!(timeout.timed_out()); let elapsed_time = now.elapsed().as_millis(); - assert!(100 <= elapsed_time && elapsed_time <= 300); + assert!(100 <= elapsed_time && elapsed_time <= 500); } /// Test that signaling a conditional variable when waiting with a timeout works From de4eea9d49b5d4d5e10e67e1ae2754bbb720564c Mon Sep 17 00:00:00 2001 From: Nym Seddon Date: Fri, 22 Jan 2021 02:45:39 +0000 Subject: [PATCH 2527/3747] Add ABI check for shims --- src/helpers.rs | 10 ++++++++ src/machine.rs | 8 +++--- src/shims/dlsym.rs | 6 +++-- src/shims/foreign_items.rs | 39 ++++++++++++++++++++++++++---- src/shims/mod.rs | 4 ++- src/shims/posix/dlsym.rs | 4 +++ src/shims/posix/foreign_items.rs | 6 ++++- src/shims/windows/dlsym.rs | 6 ++++- src/shims/windows/foreign_items.rs | 6 ++++- 9 files changed, 74 insertions(+), 15 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index 4c989db0170b5..6a12a8f6ba35a 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -9,6 +9,7 @@ use rustc_middle::mir; use rustc_middle::ty::{self, List, TyCtxt, layout::TyAndLayout}; use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX}; use rustc_target::abi::{LayoutOf, Size, FieldsShape, Variants}; +use rustc_target::spec::abi::Abi; use rand::RngCore; @@ -553,6 +554,15 @@ pub fn check_arg_count<'a, 'tcx, const N: usize>(args: &'a [OpTy<'tcx, Tag>]) -> throw_ub_format!("incorrect number of arguments: got {}, expected {}", args.len(), N) } +/// Check that the ABI is what we expect. +pub fn check_abi<'a>(abi: Abi, exp_abi: Abi) -> InterpResult<'a, ()> { + if abi == exp_abi { + Ok(()) + } else { + throw_ub_format!("calling a function with ABI {:?} using caller ABI {:?}", exp_abi, abi) + } +} + pub fn isolation_error(name: &str) -> InterpResult<'static> { throw_machine_stop!(TerminationInfo::UnsupportedInIsolation(format!( "{} not available when isolation is enabled", diff --git a/src/machine.rs b/src/machine.rs index d28aa34c75e8a..ab7abebaeabcd 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -353,24 +353,24 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { fn find_mir_or_eval_fn( ecx: &mut InterpCx<'mir, 'tcx, Self>, instance: ty::Instance<'tcx>, - _abi: Abi, + abi: Abi, args: &[OpTy<'tcx, Tag>], ret: Option<(PlaceTy<'tcx, Tag>, mir::BasicBlock)>, unwind: Option, ) -> InterpResult<'tcx, Option<&'mir mir::Body<'tcx>>> { - ecx.find_mir_or_eval_fn(instance, args, ret, unwind) + ecx.find_mir_or_eval_fn(instance, abi, args, ret, unwind) } #[inline(always)] fn call_extra_fn( ecx: &mut InterpCx<'mir, 'tcx, Self>, fn_val: Dlsym, - _abi: Abi, + abi: Abi, args: &[OpTy<'tcx, Tag>], ret: Option<(PlaceTy<'tcx, Tag>, mir::BasicBlock)>, _unwind: Option, ) -> InterpResult<'tcx> { - ecx.call_dlsym(fn_val, args, ret) + ecx.call_dlsym(fn_val, abi, args, ret) } #[inline(always)] diff --git a/src/shims/dlsym.rs b/src/shims/dlsym.rs index 9b15cb9ac9a31..a87d8a0175734 100644 --- a/src/shims/dlsym.rs +++ b/src/shims/dlsym.rs @@ -1,4 +1,5 @@ use rustc_middle::mir; +use rustc_target::spec::abi::Abi; use crate::*; use shims::posix::dlsym as posix; @@ -29,13 +30,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn call_dlsym( &mut self, dlsym: Dlsym, + abi: Abi, args: &[OpTy<'tcx, Tag>], ret: Option<(PlaceTy<'tcx, Tag>, mir::BasicBlock)>, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); match dlsym { - Dlsym::Posix(dlsym) => posix::EvalContextExt::call_dlsym(this, dlsym, args, ret), - Dlsym::Windows(dlsym) => windows::EvalContextExt::call_dlsym(this, dlsym, args, ret), + Dlsym::Posix(dlsym) => posix::EvalContextExt::call_dlsym(this, dlsym, abi, args, ret), + Dlsym::Windows(dlsym) => windows::EvalContextExt::call_dlsym(this, dlsym, abi, args, ret), } } } diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 237fb27d9222b..628e9b69e1741 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -4,14 +4,14 @@ use log::trace; use rustc_hir::def_id::DefId; use rustc_middle::mir; -use rustc_target::{abi::{Align, Size}, spec::PanicStrategy}; +use rustc_target::{abi::{Align, Size}, spec::{PanicStrategy, abi::Abi}}; use rustc_middle::ty; use rustc_apfloat::Float; use rustc_span::symbol::sym; use crate::*; use super::backtrace::EvalContextExt as _; -use helpers::check_arg_count; +use helpers::{check_abi, check_arg_count}; impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { @@ -112,6 +112,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn emulate_foreign_item( &mut self, def_id: DefId, + abi: Abi, args: &[OpTy<'tcx, Tag>], ret: Option<(PlaceTy<'tcx, Tag>, mir::BasicBlock)>, unwind: Option, @@ -130,12 +131,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let (dest, ret) = match ret { None => match link_name { "miri_start_panic" => { + check_abi(abi, Abi::Rust)?; this.handle_miri_start_panic(args, unwind)?; return Ok(None); } // This matches calls to the foreign item `panic_impl`. // The implementation is provided by the function with the `#[panic_handler]` attribute. "panic_impl" => { + check_abi(abi, Abi::Rust)?; let panic_impl_id = tcx.lang_items().panic_impl().unwrap(); let panic_impl_instance = ty::Instance::mono(tcx, panic_impl_id); return Ok(Some(&*this.load_mir(panic_impl_instance.def, None)?)); @@ -143,12 +146,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "exit" | "ExitProcess" => { + check_abi(abi, if link_name == "exit" { Abi::C } else { Abi::System })?; let &[code] = check_arg_count(args)?; // it's really u32 for ExitProcess, but we have to put it into the `Exit` variant anyway let code = this.read_scalar(code)?.to_i32()?; throw_machine_stop!(TerminationInfo::Exit(code.into())); } "abort" => { + check_abi(abi, Abi::C)?; throw_machine_stop!(TerminationInfo::Abort("the program aborted execution".to_owned())) } _ => throw_unsup_format!("can't call (diverging) foreign function: {}", link_name), @@ -165,6 +170,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Normally, this will be either `libpanic_unwind` or `libpanic_abort`, but it could // also be a custom user-provided implementation via `#![feature(panic_runtime)]` "__rust_start_panic" | "__rust_panic_cleanup" => { + check_abi(abi, Abi::C)?; // This replicates some of the logic in `inject_panic_runtime`. // FIXME: is there a way to reuse that logic? let panic_runtime = match this.tcx.sess.panic_strategy() { @@ -179,7 +185,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // Third: functions that return. - if this.emulate_foreign_item_by_name(link_name, args, dest, ret)? { + if this.emulate_foreign_item_by_name(link_name, abi, args, dest, ret)? { trace!("{:?}", this.dump_place(*dest)); this.go_to_block(ret); } @@ -193,6 +199,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn emulate_foreign_item_by_name( &mut self, link_name: &str, + abi: Abi, args: &[OpTy<'tcx, Tag>], dest: PlaceTy<'tcx, Tag>, ret: mir::BasicBlock, @@ -204,6 +211,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx match link_name { // Miri-specific extern functions "miri_static_root" => { + check_abi(abi, Abi::Rust)?; let &[ptr] = check_arg_count(args)?; let ptr = this.read_scalar(ptr)?.check_init()?; let ptr = this.force_ptr(ptr)?; @@ -215,23 +223,27 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Obtains a Miri backtrace. See the README for details. "miri_get_backtrace" => { + check_abi(abi, Abi::Rust)?; this.handle_miri_get_backtrace(args, dest)?; } // Resolves a Miri backtrace frame. See the README for details. "miri_resolve_frame" => { + check_abi(abi, Abi::Rust)?; this.handle_miri_resolve_frame(args, dest)?; } // Standard C allocation "malloc" => { + check_abi(abi, Abi::C)?; let &[size] = check_arg_count(args)?; let size = this.read_scalar(size)?.to_machine_usize(this)?; let res = this.malloc(size, /*zero_init:*/ false, MiriMemoryKind::C); this.write_scalar(res, dest)?; } "calloc" => { + check_abi(abi, Abi::C)?; let &[items, len] = check_arg_count(args)?; let items = this.read_scalar(items)?.to_machine_usize(this)?; let len = this.read_scalar(len)?.to_machine_usize(this)?; @@ -241,11 +253,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(res, dest)?; } "free" => { + check_abi(abi, Abi::C)?; let &[ptr] = check_arg_count(args)?; let ptr = this.read_scalar(ptr)?.check_init()?; this.free(ptr, MiriMemoryKind::C)?; } "realloc" => { + check_abi(abi, Abi::C)?; let &[old_ptr, new_size] = check_arg_count(args)?; let old_ptr = this.read_scalar(old_ptr)?.check_init()?; let new_size = this.read_scalar(new_size)?.to_machine_usize(this)?; @@ -257,6 +271,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // (Usually these would be forwarded to to `#[global_allocator]`; we instead implement a generic // allocation that also checks that all conditions are met, such as not permitting zero-sized allocations.) "__rust_alloc" => { + check_abi(abi, Abi::Rust)?; let &[size, align] = check_arg_count(args)?; let size = this.read_scalar(size)?.to_machine_usize(this)?; let align = this.read_scalar(align)?.to_machine_usize(this)?; @@ -269,6 +284,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(ptr, dest)?; } "__rust_alloc_zeroed" => { + check_abi(abi, Abi::Rust)?; let &[size, align] = check_arg_count(args)?; let size = this.read_scalar(size)?.to_machine_usize(this)?; let align = this.read_scalar(align)?.to_machine_usize(this)?; @@ -283,6 +299,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(ptr, dest)?; } "__rust_dealloc" => { + check_abi(abi, Abi::Rust)?; let &[ptr, old_size, align] = check_arg_count(args)?; let ptr = this.read_scalar(ptr)?.check_init()?; let old_size = this.read_scalar(old_size)?.to_machine_usize(this)?; @@ -296,6 +313,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx )?; } "__rust_realloc" => { + check_abi(abi, Abi::Rust)?; let &[ptr, old_size, align, new_size] = check_arg_count(args)?; let ptr = this.force_ptr(this.read_scalar(ptr)?.check_init()?)?; let old_size = this.read_scalar(old_size)?.to_machine_usize(this)?; @@ -316,6 +334,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // C memory handling functions "memcmp" => { + check_abi(abi, Abi::C)?; let &[left, right, n] = check_arg_count(args)?; let left = this.read_scalar(left)?.check_init()?; let right = this.read_scalar(right)?.check_init()?; @@ -336,6 +355,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_i32(result), dest)?; } "memrchr" => { + check_abi(abi, Abi::C)?; let &[ptr, val, num] = check_arg_count(args)?; let ptr = this.read_scalar(ptr)?.check_init()?; let val = this.read_scalar(val)?.to_i32()? as u8; @@ -354,6 +374,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } "memchr" => { + check_abi(abi, Abi::C)?; let &[ptr, val, num] = check_arg_count(args)?; let ptr = this.read_scalar(ptr)?.check_init()?; let val = this.read_scalar(val)?.to_i32()? as u8; @@ -371,6 +392,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } "strlen" => { + check_abi(abi, Abi::C)?; let &[ptr] = check_arg_count(args)?; let ptr = this.read_scalar(ptr)?.check_init()?; let n = this.memory.read_c_str(ptr)?.len(); @@ -386,6 +408,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "asinf" | "atanf" => { + check_abi(abi, Abi::C)?; let &[f] = check_arg_count(args)?; // FIXME: Using host floats. let f = f32::from_bits(this.read_scalar(f)?.to_u32()?); @@ -405,6 +428,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "hypotf" | "atan2f" => { + check_abi(abi, Abi::C)?; let &[f1, f2] = check_arg_count(args)?; // underscore case for windows, here and below // (see https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/floating-point-primitives?view=vs-2019) @@ -426,6 +450,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "asin" | "atan" => { + check_abi(abi, Abi::C)?; let &[f] = check_arg_count(args)?; // FIXME: Using host floats. let f = f64::from_bits(this.read_scalar(f)?.to_u64()?); @@ -445,6 +470,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "hypot" | "atan2" => { + check_abi(abi, Abi::C)?; let &[f1, f2] = check_arg_count(args)?; // FIXME: Using host floats. let f1 = f64::from_bits(this.read_scalar(f1)?.to_u64()?); @@ -460,6 +486,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "ldexp" | "scalbn" => { + check_abi(abi, Abi::C)?; let &[x, exp] = check_arg_count(args)?; // For radix-2 (binary) systems, `ldexp` and `scalbn` are the same. let x = this.read_scalar(x)?.to_f64()?; @@ -481,10 +508,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Architecture-specific shims "llvm.x86.sse2.pause" if this.tcx.sess.target.arch == "x86" || this.tcx.sess.target.arch == "x86_64" => { + check_abi(abi, Abi::C)?; let &[] = check_arg_count(args)?; this.yield_active_thread(); } "llvm.aarch64.hint" if this.tcx.sess.target.arch == "aarch64" => { + check_abi(abi, Abi::C)?; let &[hint] = check_arg_count(args)?; let hint = this.read_scalar(hint)?.to_i32()?; match hint { @@ -499,8 +528,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Platform-specific shims _ => match this.tcx.sess.target.os.as_str() { - "linux" | "macos" => return shims::posix::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, args, dest, ret), - "windows" => return shims::windows::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, args, dest, ret), + "linux" | "macos" => return shims::posix::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, abi, args, dest, ret), + "windows" => return shims::windows::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, abi, args, dest, ret), target => throw_unsup_format!("the target `{}` is not supported", target), } }; diff --git a/src/shims/mod.rs b/src/shims/mod.rs index 90dcc4d8ff1e4..c2b8809efbb66 100644 --- a/src/shims/mod.rs +++ b/src/shims/mod.rs @@ -16,6 +16,7 @@ pub mod tls; use log::trace; use rustc_middle::{mir, ty}; +use rustc_target::spec::abi::Abi; use crate::*; use helpers::check_arg_count; @@ -25,6 +26,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn find_mir_or_eval_fn( &mut self, instance: ty::Instance<'tcx>, + abi: Abi, args: &[OpTy<'tcx, Tag>], ret: Option<(PlaceTy<'tcx, Tag>, mir::BasicBlock)>, unwind: Option, @@ -48,7 +50,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // to run extra MIR), and Ok(Some(body)) if we found MIR to run for the // foreign function // Any needed call to `goto_block` will be performed by `emulate_foreign_item`. - return this.emulate_foreign_item(instance.def_id(), args, ret, unwind); + return this.emulate_foreign_item(instance.def_id(), abi, args, ret, unwind); } // Otherwise, load the MIR. diff --git a/src/shims/posix/dlsym.rs b/src/shims/posix/dlsym.rs index 52d9844bed511..e05419f47e938 100644 --- a/src/shims/posix/dlsym.rs +++ b/src/shims/posix/dlsym.rs @@ -1,6 +1,8 @@ use rustc_middle::mir; +use rustc_target::spec::abi::Abi; use crate::*; +use helpers::check_abi; use shims::posix::linux::dlsym as linux; use shims::posix::macos::dlsym as macos; @@ -27,10 +29,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn call_dlsym( &mut self, dlsym: Dlsym, + abi: Abi, args: &[OpTy<'tcx, Tag>], ret: Option<(PlaceTy<'tcx, Tag>, mir::BasicBlock)>, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); + check_abi(abi, Abi::C)?; match dlsym { Dlsym::Linux(dlsym) => linux::EvalContextExt::call_dlsym(this, dlsym, args, ret), Dlsym::MacOs(dlsym) => macos::EvalContextExt::call_dlsym(this, dlsym, args, ret), diff --git a/src/shims/posix/foreign_items.rs b/src/shims/posix/foreign_items.rs index f92242f56d9e4..e576c6f32e904 100644 --- a/src/shims/posix/foreign_items.rs +++ b/src/shims/posix/foreign_items.rs @@ -2,9 +2,10 @@ use log::trace; use rustc_middle::mir; use rustc_target::abi::{Align, LayoutOf, Size}; +use rustc_target::spec::abi::Abi; use crate::*; -use helpers::check_arg_count; +use helpers::{check_abi, check_arg_count}; use shims::posix::fs::EvalContextExt as _; use shims::posix::sync::EvalContextExt as _; use shims::posix::thread::EvalContextExt as _; @@ -14,12 +15,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn emulate_foreign_item_by_name( &mut self, link_name: &str, + abi: Abi, args: &[OpTy<'tcx, Tag>], dest: PlaceTy<'tcx, Tag>, ret: mir::BasicBlock, ) -> InterpResult<'tcx, bool> { let this = self.eval_context_mut(); + check_abi(abi, Abi::C)?; + match link_name { // Environment related shims "getenv" => { diff --git a/src/shims/windows/dlsym.rs b/src/shims/windows/dlsym.rs index c88a16461153d..ce119d1090b1c 100644 --- a/src/shims/windows/dlsym.rs +++ b/src/shims/windows/dlsym.rs @@ -1,9 +1,10 @@ use rustc_middle::mir; +use rustc_target::spec::abi::Abi; use log::trace; use crate::*; -use helpers::check_arg_count; +use helpers::{check_abi, check_arg_count}; use shims::windows::sync::EvalContextExt as _; #[derive(Debug, Copy, Clone)] @@ -38,6 +39,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn call_dlsym( &mut self, dlsym: Dlsym, + abi: Abi, args: &[OpTy<'tcx, Tag>], ret: Option<(PlaceTy<'tcx, Tag>, mir::BasicBlock)>, ) -> InterpResult<'tcx> { @@ -45,6 +47,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let (dest, ret) = ret.expect("we don't support any diverging dlsym"); assert!(this.tcx.sess.target.os == "windows"); + check_abi(abi, Abi::System)?; + match dlsym { Dlsym::AcquireSRWLockExclusive => { let &[ptr] = check_arg_count(args)?; diff --git a/src/shims/windows/foreign_items.rs b/src/shims/windows/foreign_items.rs index 17d566d18eea1..52b68b9f1bc36 100644 --- a/src/shims/windows/foreign_items.rs +++ b/src/shims/windows/foreign_items.rs @@ -2,9 +2,10 @@ use std::iter; use rustc_middle::mir; use rustc_target::abi::Size; +use rustc_target::spec::abi::Abi; use crate::*; -use helpers::check_arg_count; +use helpers::{check_abi, check_arg_count}; use shims::windows::sync::EvalContextExt as _; impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} @@ -12,12 +13,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn emulate_foreign_item_by_name( &mut self, link_name: &str, + abi: Abi, args: &[OpTy<'tcx, Tag>], dest: PlaceTy<'tcx, Tag>, _ret: mir::BasicBlock, ) -> InterpResult<'tcx, bool> { let this = self.eval_context_mut(); + check_abi(abi, Abi::System)?; + // Windows API stubs. // HANDLE = isize // DWORD = ULONG = u32 From 35ece43ef79b1b472ed13b6eb353fb38a2c4a544 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Thu, 28 Jan 2021 10:58:33 +0100 Subject: [PATCH 2528/3747] Document -Zmiri-compare-exchange-weak-failure-rate --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index b2f0babfc9bc0..72e69d45033b1 100644 --- a/README.md +++ b/README.md @@ -251,6 +251,10 @@ environment variable: can recognize false positives by "" occurring in the message -- this indicates a pointer that was cast from an integer, so Miri was unable to track this pointer. +* `-Zmiri-compare-exchange-weak-failure-rate=` changes the failure rate of + weak atomic operations. The default is `0.8` (so 4 out of 5 weak ops will fail. + You can change it to any value between `0.0` and `1.0`, where `1.0` means it + will always fail and `0.0` means it will never fail. Some native rustc `-Z` flags are also very relevant for Miri: From 53612ece7c167395719b03a3e60d8105fa1babd1 Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Thu, 28 Jan 2021 21:30:36 +0900 Subject: [PATCH 2529/3747] Rustup for rust-lang/rust#79951 --- rust-version | 2 +- src/lib.rs | 1 - src/shims/intrinsics.rs | 8 +++----- 3 files changed, 4 insertions(+), 7 deletions(-) diff --git a/rust-version b/rust-version index af4bc45869dcd..5752b651d2a21 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -78e22069d018e83915201c8a218a0a94227f6420 +0e190206e2ff0c13d64701d9b4145bf89a2d0cab diff --git a/src/lib.rs b/src/lib.rs index aadbb0270de49..5ed3d8950d04a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -8,7 +8,6 @@ #![warn(rust_2018_idioms)] #![allow(clippy::cast_lossless)] -extern crate rustc_attr; extern crate rustc_apfloat; extern crate rustc_ast; #[macro_use] extern crate rustc_middle; diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 73419a9f97647..fc859bc530205 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -2,9 +2,7 @@ use std::iter; use log::trace; -use rustc_attr as attr; -use rustc_ast::ast::FloatTy; -use rustc_middle::{mir, mir::BinOp, ty}; +use rustc_middle::{mir, mir::BinOp, ty, ty::FloatTy}; use rustc_middle::ty::layout::IntegerExt; use rustc_apfloat::{Float, Round}; use rustc_target::abi::{Align, Integer, LayoutOf}; @@ -578,7 +576,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(match dest_ty.kind() { // Unsigned ty::Uint(t) => { - let size = Integer::from_attr(this, attr::IntType::UnsignedInt(*t)).size(); + let size = Integer::from_uint_ty(this, *t).size(); let res = f.to_u128(size.bits_usize()); if res.status.is_empty() { // No status flags means there was no further rounding or other loss of precision. @@ -593,7 +591,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // Signed ty::Int(t) => { - let size = Integer::from_attr(this, attr::IntType::SignedInt(*t)).size(); + let size = Integer::from_int_ty(this, *t).size(); let res = f.to_i128(size.bits_usize()); if res.status.is_empty() { // No status flags means there was no further rounding or other loss of precision. From 9d777d84109ab6ef7b36d9ef42c94a1ff6c7d65c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 29 Jan 2021 21:16:17 +0100 Subject: [PATCH 2530/3747] add test for caller ABI check --- tests/compile-fail/check_arg_abi.rs | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 tests/compile-fail/check_arg_abi.rs diff --git a/tests/compile-fail/check_arg_abi.rs b/tests/compile-fail/check_arg_abi.rs new file mode 100644 index 0000000000000..5656c7a0e4cb6 --- /dev/null +++ b/tests/compile-fail/check_arg_abi.rs @@ -0,0 +1,9 @@ +fn main() { + extern "Rust" { + fn malloc(size: usize) -> *mut std::ffi::c_void; + } + + unsafe { + let _ = malloc(0); //~ ERROR calling a function with ABI C using caller ABI Rust + }; +} From bd04091a16156f4702118b371e02ef1460b9e0b8 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Sat, 30 Jan 2021 20:05:21 +0100 Subject: [PATCH 2531/3747] Update README.md Co-authored-by: Ralf Jung --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 72e69d45033b1..d742d7558c4db 100644 --- a/README.md +++ b/README.md @@ -252,7 +252,7 @@ environment variable: indicates a pointer that was cast from an integer, so Miri was unable to track this pointer. * `-Zmiri-compare-exchange-weak-failure-rate=` changes the failure rate of - weak atomic operations. The default is `0.8` (so 4 out of 5 weak ops will fail. + `compare_exchange_weak` operations. The default is `0.8` (so 4 out of 5 weak ops will fail). You can change it to any value between `0.0` and `1.0`, where `1.0` means it will always fail and `0.0` means it will never fail. From 397443093de127ada63ec74bd048394050aa1a10 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Sat, 30 Jan 2021 20:06:05 +0100 Subject: [PATCH 2532/3747] Update README.md --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index d742d7558c4db..ae70c80d5f0a1 100644 --- a/README.md +++ b/README.md @@ -195,6 +195,10 @@ up the sysroot. If you are using `miri` (the Miri driver) directly, see the Miri adds its own set of `-Z` flags, which are usually set via the `MIRIFLAGS` environment variable: +* `-Zmiri-compare-exchange-weak-failure-rate=` changes the failure rate of + `compare_exchange_weak` operations. The default is `0.8` (so 4 out of 5 weak ops will fail). + You can change it to any value between `0.0` and `1.0`, where `1.0` means it + will always fail and `0.0` means it will never fail. * `-Zmiri-disable-alignment-check` disables checking pointer alignment, so you can focus on other failures, but it means Miri can miss bugs in your program. Using this flag is **unsound**. @@ -251,10 +255,6 @@ environment variable: can recognize false positives by "" occurring in the message -- this indicates a pointer that was cast from an integer, so Miri was unable to track this pointer. -* `-Zmiri-compare-exchange-weak-failure-rate=` changes the failure rate of - `compare_exchange_weak` operations. The default is `0.8` (so 4 out of 5 weak ops will fail). - You can change it to any value between `0.0` and `1.0`, where `1.0` means it - will always fail and `0.0` means it will never fail. Some native rustc `-Z` flags are also very relevant for Miri: From 6f5a91f70a3f0b4966dfd5e06dbd69b87f363afd Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 31 Jan 2021 13:12:25 +0100 Subject: [PATCH 2533/3747] rustup --- rust-version | 2 +- .../dangling_pointers/dangling_pointer_addr_of.rs | 3 +-- tests/compile-fail/extern_static.rs | 3 +-- .../unaligned_pointers/unaligned_ptr_addr_of.rs | 3 +-- tests/run-pass/issue-73223.rs | 1 + tests/run-pass/many_shr_bor.rs | 1 + tests/run-pass/packed_struct.rs | 8 +++----- tests/run-pass/stacked-borrows/stacked-borrows.rs | 5 ++--- 8 files changed, 11 insertions(+), 15 deletions(-) diff --git a/rust-version b/rust-version index 5752b651d2a21..e9314ffced056 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -0e190206e2ff0c13d64701d9b4145bf89a2d0cab +9b3242982202707be2485b1e4cf5f3b34466a38d diff --git a/tests/compile-fail/dangling_pointers/dangling_pointer_addr_of.rs b/tests/compile-fail/dangling_pointers/dangling_pointer_addr_of.rs index 5df5b324f4579..5de4138711716 100644 --- a/tests/compile-fail/dangling_pointers/dangling_pointer_addr_of.rs +++ b/tests/compile-fail/dangling_pointers/dangling_pointer_addr_of.rs @@ -1,6 +1,5 @@ // Make sure we find these even with many checks disabled. // compile-flags: -Zmiri-disable-alignment-check -Zmiri-disable-stacked-borrows -Zmiri-disable-validation -#![feature(raw_ref_macros)] use std::ptr; fn main() { @@ -8,6 +7,6 @@ fn main() { let b = Box::new(42); &*b as *const i32 }; - let x = unsafe { ptr::raw_const!(*p) }; //~ ERROR dereferenced after this allocation got freed + let x = unsafe { ptr::addr_of!(*p) }; //~ ERROR dereferenced after this allocation got freed panic!("this should never print: {:?}", x); } diff --git a/tests/compile-fail/extern_static.rs b/tests/compile-fail/extern_static.rs index 650dfd0ac7878..f3466d5e7180c 100644 --- a/tests/compile-fail/extern_static.rs +++ b/tests/compile-fail/extern_static.rs @@ -1,4 +1,3 @@ -#![feature(raw_ref_op)] //! Even referencing an unknown `extern static` already triggers an error. extern "C" { @@ -6,5 +5,5 @@ extern "C" { } fn main() { - let _val = unsafe { &raw const FOO }; //~ ERROR is not supported by Miri + let _val = unsafe { std::ptr::addr_of!(FOO) }; //~ ERROR is not supported by Miri } diff --git a/tests/compile-fail/unaligned_pointers/unaligned_ptr_addr_of.rs b/tests/compile-fail/unaligned_pointers/unaligned_ptr_addr_of.rs index 88e2634efaf61..e33f3c8598f33 100644 --- a/tests/compile-fail/unaligned_pointers/unaligned_ptr_addr_of.rs +++ b/tests/compile-fail/unaligned_pointers/unaligned_ptr_addr_of.rs @@ -1,6 +1,5 @@ // This should fail even without validation or Stacked Borrows. // compile-flags: -Zmiri-disable-validation -Zmiri-disable-stacked-borrows -#![feature(raw_ref_macros)] use std::ptr; fn main() { @@ -9,6 +8,6 @@ fn main() { let x = &x[0] as *const _ as *const u32; // This must fail because alignment is violated: the allocation's base is not sufficiently aligned. // The deref is UB even if we just put the result into a raw pointer. - let _x = unsafe { ptr::raw_const!(*x) }; //~ ERROR memory with alignment 2, but alignment 4 is required + let _x = unsafe { ptr::addr_of!(*x) }; //~ ERROR memory with alignment 2, but alignment 4 is required } } diff --git a/tests/run-pass/issue-73223.rs b/tests/run-pass/issue-73223.rs index 3a32d970d637a..df13787aad698 100644 --- a/tests/run-pass/issue-73223.rs +++ b/tests/run-pass/issue-73223.rs @@ -4,6 +4,7 @@ fn main() { assert_eq!(state.rest(path), "some/more"); } +#[allow(unused)] struct State { prev: Option, next: Option, diff --git a/tests/run-pass/many_shr_bor.rs b/tests/run-pass/many_shr_bor.rs index d4901abb808f4..ba2f9b61b1f30 100644 --- a/tests/run-pass/many_shr_bor.rs +++ b/tests/run-pass/many_shr_bor.rs @@ -1,6 +1,7 @@ // Make sure validation can handle many overlapping shared borrows for different parts of a data structure use std::cell::RefCell; +#[allow(unused)] struct Test { a: u32, b: u32, diff --git a/tests/run-pass/packed_struct.rs b/tests/run-pass/packed_struct.rs index 43419695ba044..dd95d660d75ec 100644 --- a/tests/run-pass/packed_struct.rs +++ b/tests/run-pass/packed_struct.rs @@ -1,4 +1,4 @@ -#![feature(unsize, coerce_unsized, raw_ref_op, raw_ref_macros)] +#![feature(unsize, coerce_unsized)] use std::collections::hash_map::DefaultHasher; use std::hash::Hash; @@ -45,10 +45,8 @@ fn test_basic() { assert_eq!({x.a}, 42); assert_eq!({x.b}, 99); // but we *can* take a raw pointer! - assert_eq!(unsafe { (&raw const x.a).read_unaligned() }, 42); - assert_eq!(unsafe { ptr::raw_const!(x.a).read_unaligned() }, 42); - assert_eq!(unsafe { (&raw const x.b).read_unaligned() }, 99); - assert_eq!(unsafe { ptr::raw_const!(x.b).read_unaligned() }, 99); + assert_eq!(unsafe { ptr::addr_of!(x.a).read_unaligned() }, 42); + assert_eq!(unsafe { ptr::addr_of!(x.b).read_unaligned() }, 99); x.b = 77; assert_eq!({x.b}, 77); diff --git a/tests/run-pass/stacked-borrows/stacked-borrows.rs b/tests/run-pass/stacked-borrows/stacked-borrows.rs index 99bd0fb9d8057..f76d4e64c6c9a 100644 --- a/tests/run-pass/stacked-borrows/stacked-borrows.rs +++ b/tests/run-pass/stacked-borrows/stacked-borrows.rs @@ -1,5 +1,4 @@ // compile-flags: -Zmiri-track-raw-pointers -#![feature(raw_ref_macros)] use std::ptr; // Test various stacked-borrows-related things. @@ -169,8 +168,8 @@ fn raw_ref_to_part() { } let it = Box::new(Whole { part: Part { _lame: 0 }, extra: 42 }); - let whole = ptr::raw_mut!(*Box::leak(it)); - let part = unsafe { ptr::raw_mut!((*whole).part) }; + let whole = ptr::addr_of_mut!(*Box::leak(it)); + let part = unsafe { ptr::addr_of_mut!((*whole).part) }; let typed = unsafe { &mut *(part as *mut Whole) }; assert!(typed.extra == 42); drop(unsafe { Box::from_raw(whole) }); From 052cd3bff7c0008cedb153abc38f12b3938c7f0c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 31 Jan 2021 14:23:49 +0100 Subject: [PATCH 2534/3747] rustup; remove some no-longer-needed Windows shims --- rust-version | 2 +- src/shims/posix/dlsym.rs | 2 ++ src/shims/windows/dlsym.rs | 54 +++--------------------------- src/shims/windows/foreign_items.rs | 6 ---- 4 files changed, 7 insertions(+), 57 deletions(-) diff --git a/rust-version b/rust-version index e9314ffced056..1aa101dca1418 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -9b3242982202707be2485b1e4cf5f3b34466a38d +0e63af5da3400ace48a0345117980473fd21ad73 diff --git a/src/shims/posix/dlsym.rs b/src/shims/posix/dlsym.rs index e05419f47e938..660c6dc0ebaec 100644 --- a/src/shims/posix/dlsym.rs +++ b/src/shims/posix/dlsym.rs @@ -34,7 +34,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ret: Option<(PlaceTy<'tcx, Tag>, mir::BasicBlock)>, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); + check_abi(abi, Abi::C)?; + match dlsym { Dlsym::Linux(dlsym) => linux::EvalContextExt::call_dlsym(this, dlsym, args, ret), Dlsym::MacOs(dlsym) => macos::EvalContextExt::call_dlsym(this, dlsym, args, ret), diff --git a/src/shims/windows/dlsym.rs b/src/shims/windows/dlsym.rs index ce119d1090b1c..57766bd344a45 100644 --- a/src/shims/windows/dlsym.rs +++ b/src/shims/windows/dlsym.rs @@ -1,20 +1,11 @@ use rustc_middle::mir; use rustc_target::spec::abi::Abi; -use log::trace; - use crate::*; -use helpers::{check_abi, check_arg_count}; -use shims::windows::sync::EvalContextExt as _; +use helpers::check_abi; #[derive(Debug, Copy, Clone)] pub enum Dlsym { - AcquireSRWLockExclusive, - ReleaseSRWLockExclusive, - TryAcquireSRWLockExclusive, - AcquireSRWLockShared, - ReleaseSRWLockShared, - TryAcquireSRWLockShared, } impl Dlsym { @@ -22,12 +13,6 @@ impl Dlsym { // should become a NULL pointer (pretend it does not exist). pub fn from_str(name: &str) -> InterpResult<'static, Option> { Ok(match name { - "AcquireSRWLockExclusive" => Some(Dlsym::AcquireSRWLockExclusive), - "ReleaseSRWLockExclusive" => Some(Dlsym::ReleaseSRWLockExclusive), - "TryAcquireSRWLockExclusive" => Some(Dlsym::TryAcquireSRWLockExclusive), - "AcquireSRWLockShared" => Some(Dlsym::AcquireSRWLockShared), - "ReleaseSRWLockShared" => Some(Dlsym::ReleaseSRWLockShared), - "TryAcquireSRWLockShared" => Some(Dlsym::TryAcquireSRWLockShared), "GetSystemTimePreciseAsFileTime" => None, _ => throw_unsup_format!("unsupported Windows dlsym: {}", name), }) @@ -40,46 +25,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx &mut self, dlsym: Dlsym, abi: Abi, - args: &[OpTy<'tcx, Tag>], + _args: &[OpTy<'tcx, Tag>], ret: Option<(PlaceTy<'tcx, Tag>, mir::BasicBlock)>, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - let (dest, ret) = ret.expect("we don't support any diverging dlsym"); + let (_dest, _ret) = ret.expect("we don't support any diverging dlsym"); assert!(this.tcx.sess.target.os == "windows"); check_abi(abi, Abi::System)?; - match dlsym { - Dlsym::AcquireSRWLockExclusive => { - let &[ptr] = check_arg_count(args)?; - this.AcquireSRWLockExclusive(ptr)?; - } - Dlsym::ReleaseSRWLockExclusive => { - let &[ptr] = check_arg_count(args)?; - this.ReleaseSRWLockExclusive(ptr)?; - } - Dlsym::TryAcquireSRWLockExclusive => { - let &[ptr] = check_arg_count(args)?; - let ret = this.TryAcquireSRWLockExclusive(ptr)?; - this.write_scalar(Scalar::from_u8(ret), dest)?; - } - Dlsym::AcquireSRWLockShared => { - let &[ptr] = check_arg_count(args)?; - this.AcquireSRWLockShared(ptr)?; - } - Dlsym::ReleaseSRWLockShared => { - let &[ptr] = check_arg_count(args)?; - this.ReleaseSRWLockShared(ptr)?; - } - Dlsym::TryAcquireSRWLockShared => { - let &[ptr] = check_arg_count(args)?; - let ret = this.TryAcquireSRWLockShared(ptr)?; - this.write_scalar(Scalar::from_u8(ret), dest)?; - } - } - - trace!("{:?}", this.dump_place(*dest)); - this.go_to_block(ret); - Ok(()) + match dlsym {} } } diff --git a/src/shims/windows/foreign_items.rs b/src/shims/windows/foreign_items.rs index 52b68b9f1bc36..0eeec08901db7 100644 --- a/src/shims/windows/foreign_items.rs +++ b/src/shims/windows/foreign_items.rs @@ -300,12 +300,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Just fake a HANDLE this.write_scalar(Scalar::from_machine_isize(1, this), dest)?; } - "GetModuleHandleW" if this.frame().instance.to_string().starts_with("std::sys::windows::") => { - #[allow(non_snake_case)] - let &[_lpModuleName] = check_arg_count(args)?; - // Pretend this does not exist / nothing happened, by returning zero. - this.write_null(dest)?; - } "SetConsoleTextAttribute" if this.frame().instance.to_string().starts_with("std::sys::windows::") => { #[allow(non_snake_case)] let &[_hConsoleOutput, _wAttribute] = check_arg_count(args)?; From c5bb29141e6deb4b3eb758da60f5767a662c888b Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Tue, 2 Feb 2021 21:40:30 +0100 Subject: [PATCH 2535/3747] Remove unnecessary `format!()` in `panic!()`. --- src/bin/miri.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/bin/miri.rs b/src/bin/miri.rs index bd3bc8dbb4125..8256bbd8f847e 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -230,10 +230,10 @@ fn main() { err => panic!("unknown error decoding -Zmiri-seed as hex: {:?}", err), }); if seed_raw.len() > 8 { - panic!(format!( + panic!( "-Zmiri-seed must be at most 8 bytes, was {}", seed_raw.len() - )); + ); } let mut bytes = [0; 8]; From d3098043953626e2a2517523788d1949e5b6e80f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 3 Feb 2021 23:37:40 +0100 Subject: [PATCH 2536/3747] rustup --- rust-version | 2 +- tests/compile-fail/erroneous_const.rs | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 1aa101dca1418..555bac8c190a6 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -0e63af5da3400ace48a0345117980473fd21ad73 +120b2a704a60d4341286bd82f6e638c65ca169b6 diff --git a/tests/compile-fail/erroneous_const.rs b/tests/compile-fail/erroneous_const.rs index 7f1a818208902..49dcea62a2434 100644 --- a/tests/compile-fail/erroneous_const.rs +++ b/tests/compile-fail/erroneous_const.rs @@ -9,6 +9,7 @@ struct PrintName(T); impl PrintName { const VOID: ! = panic!(); //~WARN any use of this value will cause an error + //~^ WARN this was previously accepted } fn no_codegen() { From 7fc24442bd6e35a0d7a7f025da41870506490605 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Fri, 5 Feb 2021 10:02:47 +0100 Subject: [PATCH 2537/3747] Update rust version. - Allow new non_fmt_panic lint in test. - Remove stabilized feature(wake_trait). --- rust-version | 2 +- tests/run-pass/async-fn.rs | 1 - tests/run-pass/panic/catch_panic.rs | 2 +- 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/rust-version b/rust-version index 555bac8c190a6..3fb38bf7383b4 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -120b2a704a60d4341286bd82f6e638c65ca169b6 +6a388dcfbb07b3ca3d4ad3fd3902ac7e3b11b5f6 diff --git a/tests/run-pass/async-fn.rs b/tests/run-pass/async-fn.rs index b0a9791233437..d03c2cf282b8d 100644 --- a/tests/run-pass/async-fn.rs +++ b/tests/run-pass/async-fn.rs @@ -1,5 +1,4 @@ #![feature(never_type)] -#![feature(wake_trait)] use std::{future::Future, pin::Pin, task::Poll}; use std::task::{Wake, Waker, Context}; diff --git a/tests/run-pass/panic/catch_panic.rs b/tests/run-pass/panic/catch_panic.rs index 941f79c7ad903..9f9a2b493cef3 100644 --- a/tests/run-pass/panic/catch_panic.rs +++ b/tests/run-pass/panic/catch_panic.rs @@ -3,7 +3,7 @@ // We test the `align_offset` panic below, make sure we test the interpreter impl and not the "real" one. // compile-flags: -Zmiri-symbolic-alignment-check #![feature(never_type)] -#![allow(unconditional_panic)] +#![allow(unconditional_panic, non_fmt_panic)] use std::panic::{catch_unwind, AssertUnwindSafe}; use std::cell::Cell; From dd81fb3f10f24859442ab9cc7b51d1cd5a31b04d Mon Sep 17 00:00:00 2001 From: Caleb Zulawski Date: Mon, 8 Feb 2021 00:16:22 -0500 Subject: [PATCH 2538/3747] Remove non-power-of-two SIMD vectors --- tests/run-pass/simd-intrinsic-generic-elements.rs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/tests/run-pass/simd-intrinsic-generic-elements.rs b/tests/run-pass/simd-intrinsic-generic-elements.rs index e8fba6707db1e..32de27a96233a 100644 --- a/tests/run-pass/simd-intrinsic-generic-elements.rs +++ b/tests/run-pass/simd-intrinsic-generic-elements.rs @@ -7,10 +7,6 @@ struct i32x2(i32, i32); #[repr(simd)] #[derive(Copy, Clone, Debug, PartialEq)] #[allow(non_camel_case_types)] -struct i32x3(i32, i32, i32); -#[repr(simd)] -#[derive(Copy, Clone, Debug, PartialEq)] -#[allow(non_camel_case_types)] struct i32x4(i32, i32, i32, i32); #[repr(simd)] #[derive(Copy, Clone, Debug, PartialEq)] @@ -20,12 +16,10 @@ struct i32x8(i32, i32, i32, i32, fn main() { let _x2 = i32x2(20, 21); - let _x3 = i32x3(30, 31, 32); let _x4 = i32x4(40, 41, 42, 43); let _x8 = i32x8(80, 81, 82, 83, 84, 85, 86, 87); let _y2 = i32x2(120, 121); - let _y3 = i32x3(130, 131, 132); let _y4 = i32x4(140, 141, 142, 143); let _y8 = i32x8(180, 181, 182, 183, 184, 185, 186, 187); From 053124aa52aed422e7928db60817cd3216d9de6f Mon Sep 17 00:00:00 2001 From: Caleb Zulawski Date: Mon, 8 Feb 2021 23:11:33 -0500 Subject: [PATCH 2539/3747] Update rust-version --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 3fb38bf7383b4..26199e0b483cd 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -6a388dcfbb07b3ca3d4ad3fd3902ac7e3b11b5f6 +bb587b1a1737738658d2eaecd4c8c1cab555257a From b3757d0e514e4bcac5b783daade1bed3c99220bc Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 13 Feb 2021 19:39:03 +0100 Subject: [PATCH 2540/3747] add regression test for #1567 --- test-cargo-miri/Cargo.lock | 8 ++++++++ test-cargo-miri/Cargo.toml | 3 ++- test-cargo-miri/issue-1567/Cargo.toml | 13 +++++++++++++ test-cargo-miri/issue-1567/src/lib.rs | 5 +++++ 4 files changed, 28 insertions(+), 1 deletion(-) create mode 100644 test-cargo-miri/issue-1567/Cargo.toml create mode 100644 test-cargo-miri/issue-1567/src/lib.rs diff --git a/test-cargo-miri/Cargo.lock b/test-cargo-miri/Cargo.lock index 8c287098d323b..e02439df5d5cf 100644 --- a/test-cargo-miri/Cargo.lock +++ b/test-cargo-miri/Cargo.lock @@ -11,6 +11,7 @@ name = "cargo-miri-test" version = "0.1.0" dependencies = [ "byteorder", + "issue_1567", "rand", "serde_derive", ] @@ -41,6 +42,13 @@ dependencies = [ "libc", ] +[[package]] +name = "issue_1567" +version = "0.1.0" +dependencies = [ + "byteorder", +] + [[package]] name = "libc" version = "0.2.81" diff --git a/test-cargo-miri/Cargo.toml b/test-cargo-miri/Cargo.toml index 54a03f5f5ded1..1613f067ed34f 100644 --- a/test-cargo-miri/Cargo.toml +++ b/test-cargo-miri/Cargo.toml @@ -1,5 +1,5 @@ [workspace] -members = ["subcrate"] +members = ["subcrate", "issue-1567"] [package] name = "cargo-miri-test" @@ -9,6 +9,7 @@ edition = "2018" [dependencies] byteorder = "1.0" +issue_1567 = { path ="issue-1567" } [dev-dependencies] rand = { version = "0.7", features = ["small_rng"] } diff --git a/test-cargo-miri/issue-1567/Cargo.toml b/test-cargo-miri/issue-1567/Cargo.toml new file mode 100644 index 0000000000000..6a6e09036a01d --- /dev/null +++ b/test-cargo-miri/issue-1567/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "issue_1567" +version = "0.1.0" +authors = ["Miri Team"] +edition = "2018" + +[lib] +# Regression test for https://github.com/rust-lang/miri/issues/1567: crate must have this crate-type set. +# It must also depend on some other crate and use that dependency (we use byteorder). +crate-type = ["cdylib", "rlib"] + +[dependencies] +byteorder = "1.0" diff --git a/test-cargo-miri/issue-1567/src/lib.rs b/test-cargo-miri/issue-1567/src/lib.rs new file mode 100644 index 0000000000000..568617c3ba3ca --- /dev/null +++ b/test-cargo-miri/issue-1567/src/lib.rs @@ -0,0 +1,5 @@ +use byteorder::{BigEndian, ByteOrder}; + +pub fn use_the_dependency() { + let _n = ::read_u32(&[1,2,3,4]); +} From 80112820fdb887eaff93a811e33e985e0c93c36a Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Sun, 14 Feb 2021 02:02:21 +0800 Subject: [PATCH 2541/3747] [cargo-miri] Don't skip `rlib` crates --- cargo-miri/bin.rs | 13 +++++-------- test-cargo-miri/Cargo.lock | 7 +++++++ test-cargo-miri/Cargo.toml | 1 + test-cargo-miri/rlib-dep/Cargo.toml | 8 ++++++++ test-cargo-miri/rlib-dep/src/lib.rs | 3 +++ test-cargo-miri/src/lib.rs | 2 +- 6 files changed, 25 insertions(+), 9 deletions(-) create mode 100644 test-cargo-miri/rlib-dep/Cargo.toml create mode 100644 test-cargo-miri/rlib-dep/src/lib.rs diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index 21a6b68c61978..f38e79732b274 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -596,16 +596,13 @@ fn phase_cargo_rustc(args: env::Args) { let target_crate = is_target_crate(); let print = get_arg_flag_value("--print").is_some(); // whether this is cargo passing `--print` to get some infos - // rlib and cdylib are just skipped, we cannot interpret them and do not need them + // cdylib is just skipped, we cannot interpret it and do not need it // for the rest of the build either. - match get_arg_flag_value("--crate-type").as_deref() { - Some("rlib") | Some("cdylib") => { - if verbose { - eprint!("[cargo-miri rustc] (rlib/cdylib skipped)"); - } - return; + if get_arg_flag_value("--crate-type").as_deref() == Some("cdylib") { + if verbose { + eprint!("[cargo-miri rustc] (cdylib skipped)"); } - _ => {}, + return; } let store_json = |info: CrateRunInfo| { diff --git a/test-cargo-miri/Cargo.lock b/test-cargo-miri/Cargo.lock index e02439df5d5cf..84b69f57333e2 100644 --- a/test-cargo-miri/Cargo.lock +++ b/test-cargo-miri/Cargo.lock @@ -1,5 +1,7 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. +version = 3 + [[package]] name = "byteorder" version = "1.3.4" @@ -13,6 +15,7 @@ dependencies = [ "byteorder", "issue_1567", "rand", + "rlib-dep", "serde_derive", ] @@ -140,6 +143,10 @@ dependencies = [ "rand_core", ] +[[package]] +name = "rlib-dep" +version = "0.1.0" + [[package]] name = "serde_derive" version = "1.0.118" diff --git a/test-cargo-miri/Cargo.toml b/test-cargo-miri/Cargo.toml index 1613f067ed34f..ab44f6b304a7b 100644 --- a/test-cargo-miri/Cargo.toml +++ b/test-cargo-miri/Cargo.toml @@ -9,6 +9,7 @@ edition = "2018" [dependencies] byteorder = "1.0" +rlib-dep.path = "rlib-dep" issue_1567 = { path ="issue-1567" } [dev-dependencies] diff --git a/test-cargo-miri/rlib-dep/Cargo.toml b/test-cargo-miri/rlib-dep/Cargo.toml new file mode 100644 index 0000000000000..c12653e9c839c --- /dev/null +++ b/test-cargo-miri/rlib-dep/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "rlib-dep" +version = "0.1.0" +authors = ["Miri Team"] +edition = "2018" + +[lib] +crate-type = ["rlib"] diff --git a/test-cargo-miri/rlib-dep/src/lib.rs b/test-cargo-miri/rlib-dep/src/lib.rs new file mode 100644 index 0000000000000..efde2b58e199e --- /dev/null +++ b/test-cargo-miri/rlib-dep/src/lib.rs @@ -0,0 +1,3 @@ +pub fn use_me() -> bool { + true +} diff --git a/test-cargo-miri/src/lib.rs b/test-cargo-miri/src/lib.rs index 4e2c8b572c777..46d76bce1277c 100644 --- a/test-cargo-miri/src/lib.rs +++ b/test-cargo-miri/src/lib.rs @@ -3,5 +3,5 @@ /// assert!(cargo_miri_test::make_true()); /// ``` pub fn make_true() -> bool { - true + rlib_dep::use_me() } From 304cd3e4104551b990644265caf2954908679cd5 Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Sun, 14 Feb 2021 19:08:47 +0800 Subject: [PATCH 2542/3747] Make the test more consistent with other tests --- test-cargo-miri/Cargo.lock | 10 +++++----- test-cargo-miri/Cargo.toml | 4 ++-- test-cargo-miri/{rlib-dep => issue-1691}/Cargo.toml | 2 +- test-cargo-miri/{rlib-dep => issue-1691}/src/lib.rs | 0 test-cargo-miri/src/lib.rs | 2 +- 5 files changed, 9 insertions(+), 9 deletions(-) rename test-cargo-miri/{rlib-dep => issue-1691}/Cargo.toml (83%) rename test-cargo-miri/{rlib-dep => issue-1691}/src/lib.rs (100%) diff --git a/test-cargo-miri/Cargo.lock b/test-cargo-miri/Cargo.lock index 84b69f57333e2..63e03b37cca54 100644 --- a/test-cargo-miri/Cargo.lock +++ b/test-cargo-miri/Cargo.lock @@ -14,8 +14,8 @@ version = "0.1.0" dependencies = [ "byteorder", "issue_1567", + "issue_1691", "rand", - "rlib-dep", "serde_derive", ] @@ -52,6 +52,10 @@ dependencies = [ "byteorder", ] +[[package]] +name = "issue_1691" +version = "0.1.0" + [[package]] name = "libc" version = "0.2.81" @@ -143,10 +147,6 @@ dependencies = [ "rand_core", ] -[[package]] -name = "rlib-dep" -version = "0.1.0" - [[package]] name = "serde_derive" version = "1.0.118" diff --git a/test-cargo-miri/Cargo.toml b/test-cargo-miri/Cargo.toml index ab44f6b304a7b..c42d6753e8e0b 100644 --- a/test-cargo-miri/Cargo.toml +++ b/test-cargo-miri/Cargo.toml @@ -9,8 +9,8 @@ edition = "2018" [dependencies] byteorder = "1.0" -rlib-dep.path = "rlib-dep" -issue_1567 = { path ="issue-1567" } +issue_1567 = { path = "issue-1567" } +issue_1691 = { path = "issue-1691" } [dev-dependencies] rand = { version = "0.7", features = ["small_rng"] } diff --git a/test-cargo-miri/rlib-dep/Cargo.toml b/test-cargo-miri/issue-1691/Cargo.toml similarity index 83% rename from test-cargo-miri/rlib-dep/Cargo.toml rename to test-cargo-miri/issue-1691/Cargo.toml index c12653e9c839c..3100cc6a60b58 100644 --- a/test-cargo-miri/rlib-dep/Cargo.toml +++ b/test-cargo-miri/issue-1691/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "rlib-dep" +name = "issue_1691" version = "0.1.0" authors = ["Miri Team"] edition = "2018" diff --git a/test-cargo-miri/rlib-dep/src/lib.rs b/test-cargo-miri/issue-1691/src/lib.rs similarity index 100% rename from test-cargo-miri/rlib-dep/src/lib.rs rename to test-cargo-miri/issue-1691/src/lib.rs diff --git a/test-cargo-miri/src/lib.rs b/test-cargo-miri/src/lib.rs index 46d76bce1277c..b50dfbe51eb37 100644 --- a/test-cargo-miri/src/lib.rs +++ b/test-cargo-miri/src/lib.rs @@ -3,5 +3,5 @@ /// assert!(cargo_miri_test::make_true()); /// ``` pub fn make_true() -> bool { - rlib_dep::use_me() + issue_1691::use_me() } From 0737de86f760a35408088f19c45c0617ffed21d0 Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Sun, 14 Feb 2021 19:09:22 +0800 Subject: [PATCH 2543/3747] Revert the lock file version change --- test-cargo-miri/Cargo.lock | 2 -- 1 file changed, 2 deletions(-) diff --git a/test-cargo-miri/Cargo.lock b/test-cargo-miri/Cargo.lock index 63e03b37cca54..a3a708c6b5447 100644 --- a/test-cargo-miri/Cargo.lock +++ b/test-cargo-miri/Cargo.lock @@ -1,7 +1,5 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 - [[package]] name = "byteorder" version = "1.3.4" From 56250ccbf20babae5b110ddae60598defdd1e328 Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Mon, 15 Feb 2021 00:52:18 +0800 Subject: [PATCH 2544/3747] Extract `--extern` filenames patching code to `forward_patched_extern_arg()` Co-authored-by: Tristan Dannenberg --- cargo-miri/bin.rs | 26 ++++++++++++++------------ 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index f38e79732b274..7edd46c24ba4d 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -143,6 +143,18 @@ fn get_arg_flag_value(name: &str) -> Option { ArgFlagValueIter::new(name).next() } +fn forward_patched_extern_arg(args: &mut impl Iterator, cmd: &mut Command) { + cmd.arg("--extern"); // always forward flag, but adjust filename: + let path = args.next().expect("`--extern` should be followed by a filename"); + if let Some(lib) = path.strip_suffix(".rlib") { + // If this is an rlib, make it an rmeta. + cmd.arg(format!("{}.rmeta", lib)); + } else { + // Some other extern file (e.g. a `.so`). Forward unchanged. + cmd.arg(path); + } +} + /// Returns the path to the `miri` binary fn find_miri() -> PathBuf { if let Some(path) = env::var_os("MIRI") { @@ -734,21 +746,11 @@ fn phase_cargo_runner(binary: &Path, binary_args: env::Args) { // but when we run here, cargo does not interpret the JSON any more. `--json` // then also nees to be dropped. let mut args = info.args.into_iter(); - let extern_flag = "--extern"; let error_format_flag = "--error-format"; let json_flag = "--json"; while let Some(arg) = args.next() { - if arg == extern_flag { - cmd.arg(extern_flag); // always forward flag, but adjust filename - // `--extern` is always passed as a separate argument by cargo. - let next_arg = args.next().expect("`--extern` should be followed by a filename"); - if let Some(next_lib) = next_arg.strip_suffix(".rlib") { - // If this is an rlib, make it an rmeta. - cmd.arg(format!("{}.rmeta", next_lib)); - } else { - // Some other extern file (e.g., a `.so`). Forward unchanged. - cmd.arg(next_arg); - } + if arg == "--extern" { + forward_patched_extern_arg(&mut args, &mut cmd); } else if arg.starts_with(error_format_flag) { let suffix = &arg[error_format_flag.len()..]; assert!(suffix.starts_with('=')); From c0eb13ba2af21239617fb7b7a8ad7f129656812a Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Sun, 14 Feb 2021 18:12:33 +0800 Subject: [PATCH 2545/3747] Patch `--extern` arguments in `phase_cargo_rustc` as well --- cargo-miri/bin.rs | 8 ++++++-- test-cargo-miri/Cargo.lock | 8 ++++++++ test-cargo-miri/Cargo.toml | 1 + test-cargo-miri/issue-1705/Cargo.toml | 11 +++++++++++ test-cargo-miri/issue-1705/src/lib.rs | 5 +++++ test-cargo-miri/src/lib.rs | 1 + 6 files changed, 32 insertions(+), 2 deletions(-) create mode 100644 test-cargo-miri/issue-1705/Cargo.toml create mode 100644 test-cargo-miri/issue-1705/src/lib.rs diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index 7edd46c24ba4d..77ccaea4bf69c 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -565,7 +565,7 @@ fn phase_cargo_miri(mut args: env::Args) { exec(cmd) } -fn phase_cargo_rustc(args: env::Args) { +fn phase_cargo_rustc(mut args: env::Args) { /// Determines if we are being invoked (as rustc) to build a crate for /// the "target" architecture, in contrast to the "host" architecture. /// Host crates are for build scripts and proc macros and still need to @@ -655,7 +655,7 @@ fn phase_cargo_rustc(args: env::Args) { if !print && target_crate { // Forward arguments, but remove "link" from "--emit" to make this a check-only build. let emit_flag = "--emit"; - for arg in args { + while let Some(arg) = args.next() { if arg.starts_with(emit_flag) { // Patch this argument. First, extract its value. let val = &arg[emit_flag.len()..]; @@ -671,6 +671,10 @@ fn phase_cargo_rustc(args: env::Args) { } } cmd.arg(format!("{}={}", emit_flag, val.join(","))); + } else if arg == "--extern" { + // Patch `--extern` filenames, since Cargo sometimes passes stub `.rlib` files: + // https://github.com/rust-lang/miri/issues/1705 + forward_patched_extern_arg(&mut args, &mut cmd); } else { cmd.arg(arg); } diff --git a/test-cargo-miri/Cargo.lock b/test-cargo-miri/Cargo.lock index a3a708c6b5447..eff36026defef 100644 --- a/test-cargo-miri/Cargo.lock +++ b/test-cargo-miri/Cargo.lock @@ -13,6 +13,7 @@ dependencies = [ "byteorder", "issue_1567", "issue_1691", + "issue_1705", "rand", "serde_derive", ] @@ -54,6 +55,13 @@ dependencies = [ name = "issue_1691" version = "0.1.0" +[[package]] +name = "issue_1705" +version = "0.1.0" +dependencies = [ + "byteorder", +] + [[package]] name = "libc" version = "0.2.81" diff --git a/test-cargo-miri/Cargo.toml b/test-cargo-miri/Cargo.toml index c42d6753e8e0b..4bc5d121ac79c 100644 --- a/test-cargo-miri/Cargo.toml +++ b/test-cargo-miri/Cargo.toml @@ -11,6 +11,7 @@ edition = "2018" byteorder = "1.0" issue_1567 = { path = "issue-1567" } issue_1691 = { path = "issue-1691" } +issue_1705 = { path = "issue-1705" } [dev-dependencies] rand = { version = "0.7", features = ["small_rng"] } diff --git a/test-cargo-miri/issue-1705/Cargo.toml b/test-cargo-miri/issue-1705/Cargo.toml new file mode 100644 index 0000000000000..ae63647a88819 --- /dev/null +++ b/test-cargo-miri/issue-1705/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "issue_1705" +version = "0.1.0" +authors = ["Miri Team"] +edition = "2018" + +[lib] +crate-type = ["lib", "staticlib", "cdylib"] + +[dependencies] +byteorder = "1.0" diff --git a/test-cargo-miri/issue-1705/src/lib.rs b/test-cargo-miri/issue-1705/src/lib.rs new file mode 100644 index 0000000000000..ef24d3f1a06da --- /dev/null +++ b/test-cargo-miri/issue-1705/src/lib.rs @@ -0,0 +1,5 @@ +use byteorder::{LittleEndian, ByteOrder}; + +pub fn use_the_dependency() { + let _n = ::read_u32(&[1,2,3,4]); +} diff --git a/test-cargo-miri/src/lib.rs b/test-cargo-miri/src/lib.rs index b50dfbe51eb37..1da169bd51cff 100644 --- a/test-cargo-miri/src/lib.rs +++ b/test-cargo-miri/src/lib.rs @@ -3,5 +3,6 @@ /// assert!(cargo_miri_test::make_true()); /// ``` pub fn make_true() -> bool { + issue_1705::use_the_dependency(); issue_1691::use_me() } From eec5423aa738b55e4541324ad490507e30d2cf38 Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Sun, 14 Feb 2021 21:57:31 +0800 Subject: [PATCH 2546/3747] Stop skipping `cdylib` --- cargo-miri/bin.rs | 9 --------- 1 file changed, 9 deletions(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index 77ccaea4bf69c..cb003c0f3e8bd 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -608,15 +608,6 @@ fn phase_cargo_rustc(mut args: env::Args) { let target_crate = is_target_crate(); let print = get_arg_flag_value("--print").is_some(); // whether this is cargo passing `--print` to get some infos - // cdylib is just skipped, we cannot interpret it and do not need it - // for the rest of the build either. - if get_arg_flag_value("--crate-type").as_deref() == Some("cdylib") { - if verbose { - eprint!("[cargo-miri rustc] (cdylib skipped)"); - } - return; - } - let store_json = |info: CrateRunInfo| { let filename = out_filename("", ""); if verbose { From 51c6f51c36b95420d9748b0d9d372ccbbaafc93d Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Sun, 14 Feb 2021 22:38:56 +0800 Subject: [PATCH 2547/3747] Use the `issue-1567` dependency in the test --- test-cargo-miri/src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/test-cargo-miri/src/lib.rs b/test-cargo-miri/src/lib.rs index 1da169bd51cff..33bbd8c966e58 100644 --- a/test-cargo-miri/src/lib.rs +++ b/test-cargo-miri/src/lib.rs @@ -3,6 +3,7 @@ /// assert!(cargo_miri_test::make_true()); /// ``` pub fn make_true() -> bool { + issue_1567::use_the_dependency(); issue_1705::use_the_dependency(); issue_1691::use_me() } From 1923044705b2e9d54f7fa8f40e1c0bab5ea081ff Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Sun, 14 Feb 2021 23:33:24 +0800 Subject: [PATCH 2548/3747] Add a `cdylib`-only crate test --- test-cargo-miri/Cargo.lock | 8 ++++++++ test-cargo-miri/Cargo.toml | 1 + test-cargo-miri/cdylib/Cargo.toml | 12 ++++++++++++ test-cargo-miri/cdylib/src/lib.rs | 6 ++++++ 4 files changed, 27 insertions(+) create mode 100644 test-cargo-miri/cdylib/Cargo.toml create mode 100644 test-cargo-miri/cdylib/src/lib.rs diff --git a/test-cargo-miri/Cargo.lock b/test-cargo-miri/Cargo.lock index eff36026defef..1f1541b92a563 100644 --- a/test-cargo-miri/Cargo.lock +++ b/test-cargo-miri/Cargo.lock @@ -11,6 +11,7 @@ name = "cargo-miri-test" version = "0.1.0" dependencies = [ "byteorder", + "cdylib", "issue_1567", "issue_1691", "issue_1705", @@ -18,6 +19,13 @@ dependencies = [ "serde_derive", ] +[[package]] +name = "cdylib" +version = "0.1.0" +dependencies = [ + "byteorder", +] + [[package]] name = "cfg-if" version = "0.1.10" diff --git a/test-cargo-miri/Cargo.toml b/test-cargo-miri/Cargo.toml index 4bc5d121ac79c..7ffe7d04ea475 100644 --- a/test-cargo-miri/Cargo.toml +++ b/test-cargo-miri/Cargo.toml @@ -9,6 +9,7 @@ edition = "2018" [dependencies] byteorder = "1.0" +cdylib = { path = "cdylib" } issue_1567 = { path = "issue-1567" } issue_1691 = { path = "issue-1691" } issue_1705 = { path = "issue-1705" } diff --git a/test-cargo-miri/cdylib/Cargo.toml b/test-cargo-miri/cdylib/Cargo.toml new file mode 100644 index 0000000000000..4e5b5601a56ce --- /dev/null +++ b/test-cargo-miri/cdylib/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "cdylib" +version = "0.1.0" +authors = ["Miri Team"] +edition = "2018" + +[lib] +# cargo-miri used to handle `cdylib` crate-type specially (https://github.com/rust-lang/miri/pull/1577). +crate-type = ["cdylib"] + +[dependencies] +byteorder = "1.0" diff --git a/test-cargo-miri/cdylib/src/lib.rs b/test-cargo-miri/cdylib/src/lib.rs new file mode 100644 index 0000000000000..dd89048284dee --- /dev/null +++ b/test-cargo-miri/cdylib/src/lib.rs @@ -0,0 +1,6 @@ +use byteorder::{BigEndian, ByteOrder}; + +#[no_mangle] +extern "C" fn use_the_dependency() { + let _n = ::read_u64(&[1,2,3,4,5,6,7,8]); +} From 0b3dba8e702fa7f4a0135098dfe77c98db45490a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 16 Feb 2021 09:51:53 +0100 Subject: [PATCH 2549/3747] rustup and temporarily disable broken tests --- rust-version | 2 +- tests/compile-fail/validity/execute_memory.rs | 1 + tests/compile-fail/validity/invalid_fnptr_uninit.rs | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 26199e0b483cd..0c82a59c6d1d9 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -bb587b1a1737738658d2eaecd4c8c1cab555257a +42a4673fbd40b09a99d057eaa9b3e5579b54c184 diff --git a/tests/compile-fail/validity/execute_memory.rs b/tests/compile-fail/validity/execute_memory.rs index 5230e7fdf5297..4be80fe39d019 100644 --- a/tests/compile-fail/validity/execute_memory.rs +++ b/tests/compile-fail/validity/execute_memory.rs @@ -1,3 +1,4 @@ +// ignore-test FIXME (Miri issue #1711) #![feature(box_syntax)] fn main() { diff --git a/tests/compile-fail/validity/invalid_fnptr_uninit.rs b/tests/compile-fail/validity/invalid_fnptr_uninit.rs index dbd6711dc65a4..ab0e870b420bd 100644 --- a/tests/compile-fail/validity/invalid_fnptr_uninit.rs +++ b/tests/compile-fail/validity/invalid_fnptr_uninit.rs @@ -1,3 +1,4 @@ +// ignore-test FIXME (Miri issue #1711) #![allow(invalid_value)] union MyUninit { From 4c867feeb637e0172f4c72a3732f9beb5e4f922d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 16 Feb 2021 09:55:44 +0100 Subject: [PATCH 2550/3747] add test by @eddyb --- .../branchless-select-i128-pointer.rs | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) create mode 100644 tests/compile-fail/branchless-select-i128-pointer.rs diff --git a/tests/compile-fail/branchless-select-i128-pointer.rs b/tests/compile-fail/branchless-select-i128-pointer.rs new file mode 100644 index 0000000000000..61fd57f8f0501 --- /dev/null +++ b/tests/compile-fail/branchless-select-i128-pointer.rs @@ -0,0 +1,20 @@ +use std::mem::transmute; + +#[cfg(target_pointer_width = "32")] +type TwoPtrs = i64; +#[cfg(target_pointer_width = "64")] +type TwoPtrs = i128; + +fn main() { + for &my_bool in &[true, false] { + let mask = -(my_bool as TwoPtrs); // false -> 0, true -> -1 aka !0 + // This is branchless code to select one or the other pointer. + // For now, Miri brafs on it, but if this code ever passes we better make sure it behaves correctly. + let val = unsafe { + transmute::<_, &str>( + !mask & transmute::<_, TwoPtrs>("false !") | mask & transmute::<_, TwoPtrs>("true !"), //~ERROR encountered (potentially part of) a pointer, but expected plain (non-pointer) bytes + ) + }; + println!("{}", val); + } +} From a5a751e7957e043faa1a8c080a1c51dee712faae Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 17 Feb 2021 09:37:21 +0100 Subject: [PATCH 2551/3747] rustup --- rust-version | 2 +- tests/compile-fail/validity/execute_memory.rs | 1 - tests/compile-fail/validity/invalid_fnptr_uninit.rs | 1 - 3 files changed, 1 insertion(+), 3 deletions(-) diff --git a/rust-version b/rust-version index 0c82a59c6d1d9..208d29f79704f 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -42a4673fbd40b09a99d057eaa9b3e5579b54c184 +a143517d44cac50b20cbd3a0b579addab40dd399 diff --git a/tests/compile-fail/validity/execute_memory.rs b/tests/compile-fail/validity/execute_memory.rs index 4be80fe39d019..5230e7fdf5297 100644 --- a/tests/compile-fail/validity/execute_memory.rs +++ b/tests/compile-fail/validity/execute_memory.rs @@ -1,4 +1,3 @@ -// ignore-test FIXME (Miri issue #1711) #![feature(box_syntax)] fn main() { diff --git a/tests/compile-fail/validity/invalid_fnptr_uninit.rs b/tests/compile-fail/validity/invalid_fnptr_uninit.rs index ab0e870b420bd..dbd6711dc65a4 100644 --- a/tests/compile-fail/validity/invalid_fnptr_uninit.rs +++ b/tests/compile-fail/validity/invalid_fnptr_uninit.rs @@ -1,4 +1,3 @@ -// ignore-test FIXME (Miri issue #1711) #![allow(invalid_value)] union MyUninit { From 2672baafe1d52cdcb0b7b84f77c9950771be7332 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 18 Feb 2021 10:34:32 +0100 Subject: [PATCH 2552/3747] rustup --- rust-version | 2 +- src/diagnostics.rs | 10 +++++----- src/eval.rs | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/rust-version b/rust-version index 208d29f79704f..189317a54a356 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -a143517d44cac50b20cbd3a0b579addab40dd399 +d1462d8558cf4551608457f63d9b999185ebf3bf diff --git a/src/diagnostics.rs b/src/diagnostics.rs index 3f1f67218fdb6..45c0996355bff 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -54,7 +54,7 @@ pub fn report_error<'tcx, 'mir>( ) -> Option { use InterpError::*; - let (title, helps) = match &e.kind { + let (title, helps) = match &e.kind() { MachineStop(info) => { let info = info.downcast_ref::().expect("invalid MachineStop payload"); use TerminationInfo::*; @@ -81,7 +81,7 @@ pub fn report_error<'tcx, 'mir>( (title, helps) } _ => { - let title = match e.kind { + let title = match e.kind() { Unsupported(_) => "unsupported operation", UndefinedBehavior(_) => @@ -93,11 +93,11 @@ pub fn report_error<'tcx, 'mir>( _ => bug!("This error should be impossible in Miri: {}", e), }; - let helps = match e.kind { + let helps = match e.kind() { Unsupported(UnsupportedOpInfo::NoMirFor(..)) => vec![format!("make sure to use a Miri sysroot, which you can prepare with `cargo miri setup`")], Unsupported(UnsupportedOpInfo::ReadBytesAsPointer | UnsupportedOpInfo::ThreadLocalStatic(_) | UnsupportedOpInfo::ReadExternStatic(_)) => - panic!("Error should never be raised by Miri: {:?}", e.kind), + panic!("Error should never be raised by Miri: {:?}", e.kind()), Unsupported(_) => vec![format!("this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support")], UndefinedBehavior(UndefinedBehaviorInfo::AlignmentCheckFailed { .. }) @@ -133,7 +133,7 @@ pub fn report_error<'tcx, 'mir>( } // Extra output to help debug specific issues. - match e.kind { + match e.kind() { UndefinedBehavior(UndefinedBehaviorInfo::InvalidUninitBytes(Some(access))) => { eprintln!( "Uninitialized read occurred at offsets 0x{:x}..0x{:x} into this allocation:", diff --git a/src/eval.rs b/src/eval.rs index b6d4fa05e1e5a..16fe5d5f20a1f 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -208,7 +208,7 @@ pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) -> Ok(v) => v, Err(err) => { err.print_backtrace(); - panic!("Miri initialization error: {}", err.kind) + panic!("Miri initialization error: {}", err.kind()) } }; From 0eb341417cc2261a664a83f26b6c04bf1e16e295 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Mi=C4=85sko?= Date: Sat, 20 Feb 2021 00:00:00 +0000 Subject: [PATCH 2553/3747] rustup to e7c23ab933ebc1f205c3b59f4ebc85d40f67d404 --- rust-version | 2 +- src/data_race.rs | 52 +++++------ src/eval.rs | 16 ++-- src/helpers.rs | 50 +++++----- src/machine.rs | 18 ++-- src/operator.rs | 10 +- src/shims/backtrace.rs | 22 ++--- src/shims/dlsym.rs | 2 +- src/shims/env.rs | 46 ++++----- src/shims/foreign_items.rs | 46 ++++----- src/shims/intrinsics.rs | 84 ++++++++--------- src/shims/mod.rs | 12 +-- src/shims/panic.rs | 18 ++-- src/shims/posix/dlsym.rs | 2 +- src/shims/posix/foreign_items.rs | 118 +++++++++++------------ src/shims/posix/fs.rs | 124 ++++++++++++------------- src/shims/posix/linux/dlsym.rs | 2 +- src/shims/posix/linux/foreign_items.rs | 48 +++++----- src/shims/posix/linux/sync.rs | 15 +-- src/shims/posix/macos/dlsym.rs | 6 +- src/shims/posix/macos/foreign_items.rs | 30 +++--- src/shims/posix/sync.rs | 106 ++++++++++----------- src/shims/posix/thread.rs | 30 +++--- src/shims/time.rs | 32 +++---- src/shims/tls.rs | 6 +- src/shims/windows/dlsym.rs | 2 +- src/shims/windows/foreign_items.rs | 72 +++++++------- src/shims/windows/sync.rs | 14 +-- src/stacked_borrows.rs | 22 ++--- 29 files changed, 505 insertions(+), 502 deletions(-) diff --git a/rust-version b/rust-version index 189317a54a356..6c6212ec839cc 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -d1462d8558cf4551608457f63d9b999185ebf3bf +e7c23ab933ebc1f205c3b59f4ebc85d40f67d404 diff --git a/src/data_race.rs b/src/data_race.rs index f79775e12fe74..dcff896c1f161 100644 --- a/src/data_race.rs +++ b/src/data_race.rs @@ -446,7 +446,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { /// Atomic variant of read_scalar_at_offset. fn read_scalar_at_offset_atomic( &self, - op: OpTy<'tcx, Tag>, + op: &OpTy<'tcx, Tag>, offset: u64, layout: TyAndLayout<'tcx>, atomic: AtomicReadOp, @@ -458,13 +458,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { // Ensure that the following read at an offset is within bounds. assert!(op_place.layout.size >= offset + layout.size); let value_place = op_place.offset(offset, MemPlaceMeta::None, layout, this)?; - this.read_scalar_atomic(value_place, atomic) + this.read_scalar_atomic(&value_place, atomic) } /// Atomic variant of write_scalar_at_offset. fn write_scalar_at_offset_atomic( &mut self, - op: OpTy<'tcx, Tag>, + op: &OpTy<'tcx, Tag>, offset: u64, value: impl Into>, layout: TyAndLayout<'tcx>, @@ -477,17 +477,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { // Ensure that the following read at an offset is within bounds. assert!(op_place.layout.size >= offset + layout.size); let value_place = op_place.offset(offset, MemPlaceMeta::None, layout, this)?; - this.write_scalar_atomic(value.into(), value_place, atomic) + this.write_scalar_atomic(value.into(), &value_place, atomic) } /// Perform an atomic read operation at the memory location. fn read_scalar_atomic( &self, - place: MPlaceTy<'tcx, Tag>, + place: &MPlaceTy<'tcx, Tag>, atomic: AtomicReadOp, ) -> InterpResult<'tcx, ScalarMaybeUninit> { let this = self.eval_context_ref(); - let scalar = this.allow_data_races_ref(move |this| this.read_scalar(place.into()))?; + let scalar = this.allow_data_races_ref(move |this| this.read_scalar(&place.into()))?; self.validate_atomic_load(place, atomic)?; Ok(scalar) } @@ -496,31 +496,31 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { fn write_scalar_atomic( &mut self, val: ScalarMaybeUninit, - dest: MPlaceTy<'tcx, Tag>, + dest: &MPlaceTy<'tcx, Tag>, atomic: AtomicWriteOp, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - this.allow_data_races_mut(move |this| this.write_scalar(val, dest.into()))?; + this.allow_data_races_mut(move |this| this.write_scalar(val, &(*dest).into()))?; self.validate_atomic_store(dest, atomic) } /// Perform a atomic operation on a memory location. fn atomic_op_immediate( &mut self, - place: MPlaceTy<'tcx, Tag>, - rhs: ImmTy<'tcx, Tag>, + place: &MPlaceTy<'tcx, Tag>, + rhs: &ImmTy<'tcx, Tag>, op: mir::BinOp, neg: bool, atomic: AtomicRwOp, ) -> InterpResult<'tcx, ImmTy<'tcx, Tag>> { let this = self.eval_context_mut(); - let old = this.allow_data_races_mut(|this| this.read_immediate(place.into()))?; + let old = this.allow_data_races_mut(|this| this.read_immediate(&place.into()))?; // Atomics wrap around on overflow. - let val = this.binary_op(op, old, rhs)?; - let val = if neg { this.unary_op(mir::UnOp::Not, val)? } else { val }; - this.allow_data_races_mut(|this| this.write_immediate(*val, place.into()))?; + let val = this.binary_op(op, &old, rhs)?; + let val = if neg { this.unary_op(mir::UnOp::Not, &val)? } else { val }; + this.allow_data_races_mut(|this| this.write_immediate(*val, &(*place).into()))?; this.validate_atomic_rmw(place, atomic)?; Ok(old) @@ -530,14 +530,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { /// scalar value, the old value is returned. fn atomic_exchange_scalar( &mut self, - place: MPlaceTy<'tcx, Tag>, + place: &MPlaceTy<'tcx, Tag>, new: ScalarMaybeUninit, atomic: AtomicRwOp, ) -> InterpResult<'tcx, ScalarMaybeUninit> { let this = self.eval_context_mut(); - let old = this.allow_data_races_mut(|this| this.read_scalar(place.into()))?; - this.allow_data_races_mut(|this| this.write_scalar(new, place.into()))?; + let old = this.allow_data_races_mut(|this| this.read_scalar(&place.into()))?; + this.allow_data_races_mut(|this| this.write_scalar(new, &(*place).into()))?; this.validate_atomic_rmw(place, atomic)?; Ok(old) } @@ -550,8 +550,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { /// identical. fn atomic_compare_exchange_scalar( &mut self, - place: MPlaceTy<'tcx, Tag>, - expect_old: ImmTy<'tcx, Tag>, + place: &MPlaceTy<'tcx, Tag>, + expect_old: &ImmTy<'tcx, Tag>, new: ScalarMaybeUninit, success: AtomicRwOp, fail: AtomicReadOp, @@ -564,9 +564,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { // to read with the failure ordering and if successful then try again with the success // read ordering and write in the success case. // Read as immediate for the sake of `binary_op()` - let old = this.allow_data_races_mut(|this| this.read_immediate(place.into()))?; + let old = this.allow_data_races_mut(|this| this.read_immediate(&(place.into())))?; // `binary_op` will bail if either of them is not a scalar. - let eq = this.overflowing_binary_op(mir::BinOp::Eq, old, expect_old)?.0; + let eq = this.overflowing_binary_op(mir::BinOp::Eq, &old, expect_old)?.0; // If the operation would succeed, but is "weak", fail some portion // of the time, based on `rate`. let rate = this.memory.extra.cmpxchg_weak_failure_rate; @@ -581,7 +581,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { // if successful, perform a full rw-atomic validation // otherwise treat this as an atomic load with the fail ordering. if cmpxchg_success { - this.allow_data_races_mut(|this| this.write_scalar(new, place.into()))?; + this.allow_data_races_mut(|this| this.write_scalar(new, &(*place).into()))?; this.validate_atomic_rmw(place, success)?; } else { this.validate_atomic_load(place, fail)?; @@ -595,7 +595,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { /// associated memory-place and on the current thread. fn validate_atomic_load( &self, - place: MPlaceTy<'tcx, Tag>, + place: &MPlaceTy<'tcx, Tag>, atomic: AtomicReadOp, ) -> InterpResult<'tcx> { let this = self.eval_context_ref(); @@ -617,7 +617,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { /// associated memory-place and on the current thread. fn validate_atomic_store( &mut self, - place: MPlaceTy<'tcx, Tag>, + place: &MPlaceTy<'tcx, Tag>, atomic: AtomicWriteOp, ) -> InterpResult<'tcx> { let this = self.eval_context_ref(); @@ -639,7 +639,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { /// at the associated memory place and on the current thread. fn validate_atomic_rmw( &mut self, - place: MPlaceTy<'tcx, Tag>, + place: &MPlaceTy<'tcx, Tag>, atomic: AtomicRwOp, ) -> InterpResult<'tcx> { use AtomicRwOp::*; @@ -973,7 +973,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { /// atomic-stores/atomic-rmw? fn validate_atomic_op( &self, - place: MPlaceTy<'tcx, Tag>, + place: &MPlaceTy<'tcx, Tag>, atomic: A, description: &str, mut op: impl FnMut( diff --git a/src/eval.rs b/src/eval.rs index 16fe5d5f20a1f..7a29d91d2d8ed 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -138,8 +138,8 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( ecx.layout_of(tcx.mk_array(tcx.mk_imm_ptr(tcx.types.u8), u64::try_from(argvs.len()).unwrap()))?; let argvs_place = ecx.allocate(argvs_layout, MiriMemoryKind::Machine.into()); for (idx, arg) in argvs.into_iter().enumerate() { - let place = ecx.mplace_field(argvs_place, idx)?; - ecx.write_scalar(arg, place.into())?; + let place = ecx.mplace_field(&argvs_place, idx)?; + ecx.write_scalar(arg, &place.into())?; } ecx.memory.mark_immutable(argvs_place.ptr.assert_ptr().alloc_id)?; // A pointer to that place is the 3rd argument for main. @@ -148,14 +148,14 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( { let argc_place = ecx.allocate(ecx.machine.layouts.isize, MiriMemoryKind::Machine.into()); - ecx.write_scalar(argc, argc_place.into())?; + ecx.write_scalar(argc, &argc_place.into())?; ecx.machine.argc = Some(argc_place.ptr); let argv_place = ecx.allocate( ecx.layout_of(tcx.mk_imm_ptr(tcx.types.unit))?, MiriMemoryKind::Machine.into(), ); - ecx.write_scalar(argv, argv_place.into())?; + ecx.write_scalar(argv, &argv_place.into())?; ecx.machine.argv = Some(argv_place.ptr); } // Store command line as UTF-16 for Windows `GetCommandLineW`. @@ -177,8 +177,8 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( ecx.machine.cmd_line = Some(cmd_place.ptr); // Store the UTF-16 string. We just allocated so we know the bounds are fine. for (idx, &c) in cmd_utf16.iter().enumerate() { - let place = ecx.mplace_field(cmd_place, idx)?; - ecx.write_scalar(Scalar::from_u16(c), place.into())?; + let place = ecx.mplace_field(&cmd_place, idx)?; + ecx.write_scalar(Scalar::from_u16(c), &place.into())?; } } argv @@ -190,7 +190,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( ecx.call_function( start_instance, &[main_ptr.into(), argc.into(), argv.into()], - Some(ret_place.into()), + Some(&ret_place.into()), StackPopCleanup::None { cleanup: true }, )?; @@ -239,7 +239,7 @@ pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) -> } ecx.process_diagnostics(info); } - let return_code = ecx.read_scalar(ret_place.into())?.check_init()?.to_machine_isize(&ecx)?; + let return_code = ecx.read_scalar(&ret_place.into())?.check_init()?.to_machine_isize(&ecx)?; Ok(return_code) })(); diff --git a/src/helpers.rs b/src/helpers.rs index 6a12a8f6ba35a..2baaebb0ae206 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -61,7 +61,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let instance = this.resolve_path(path); let cid = GlobalId { instance, promoted: None }; let const_val = this.eval_to_allocation(cid)?; - let const_val = this.read_scalar(const_val.into())?; + let const_val = this.read_scalar(&const_val.into())?; return Ok(const_val); } @@ -106,7 +106,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } /// Write a 0 of the appropriate size to `dest`. - fn write_null(&mut self, dest: PlaceTy<'tcx, Tag>) -> InterpResult<'tcx> { + fn write_null(&mut self, dest: &PlaceTy<'tcx, Tag>) -> InterpResult<'tcx> { self.eval_context_mut().write_scalar(Scalar::from_int(0, dest.layout.size), dest) } @@ -162,7 +162,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx &mut self, f: ty::Instance<'tcx>, args: &[Immediate], - dest: Option>, + dest: Option<&PlaceTy<'tcx, Tag>>, stack_pop: StackPopCleanup, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); @@ -177,7 +177,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let callee_arg = this.local_place( callee_args.next().expect("callee has fewer arguments than expected"), )?; - this.write_immediate(*arg, callee_arg)?; + this.write_immediate(*arg, &callee_arg)?; } callee_args.next().expect_none("callee has more arguments than expected"); @@ -188,7 +188,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// will be true if this is frozen, false if this is in an `UnsafeCell`. fn visit_freeze_sensitive( &self, - place: MPlaceTy<'tcx, Tag>, + place: &MPlaceTy<'tcx, Tag>, size: Size, mut action: impl FnMut(Pointer, Size, bool) -> InterpResult<'tcx>, ) -> InterpResult<'tcx> { @@ -237,7 +237,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx trace!("unsafe_cell_action on {:?}", place.ptr); // We need a size to go on. let unsafe_cell_size = this - .size_and_align_of_mplace(place)? + .size_and_align_of_mplace(&place)? .map(|(size, _)| size) // for extern types, just cover what we can .unwrap_or_else(|| place.layout.size); @@ -261,7 +261,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// whether we are inside an `UnsafeCell` or not. struct UnsafeCellVisitor<'ecx, 'mir, 'tcx, F> where - F: FnMut(MPlaceTy<'tcx, Tag>) -> InterpResult<'tcx>, + F: FnMut(&MPlaceTy<'tcx, Tag>) -> InterpResult<'tcx>, { ecx: &'ecx MiriEvalContext<'mir, 'tcx>, unsafe_cell_action: F, @@ -270,7 +270,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx impl<'ecx, 'mir, 'tcx: 'mir, F> ValueVisitor<'mir, 'tcx, Evaluator<'mir, 'tcx>> for UnsafeCellVisitor<'ecx, 'mir, 'tcx, F> where - F: FnMut(MPlaceTy<'tcx, Tag>) -> InterpResult<'tcx>, + F: FnMut(&MPlaceTy<'tcx, Tag>) -> InterpResult<'tcx>, { type V = MPlaceTy<'tcx, Tag>; @@ -280,7 +280,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // Hook to detect `UnsafeCell`. - fn visit_value(&mut self, v: MPlaceTy<'tcx, Tag>) -> InterpResult<'tcx> { + fn visit_value(&mut self, v: &MPlaceTy<'tcx, Tag>) -> InterpResult<'tcx> { trace!("UnsafeCellVisitor: {:?} {:?}", *v, v.layout.ty); let is_unsafe_cell = match v.layout.ty.kind() { ty::Adt(adt, _) => @@ -323,7 +323,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Make sure we visit aggregrates in increasing offset order. fn visit_aggregate( &mut self, - place: MPlaceTy<'tcx, Tag>, + place: &MPlaceTy<'tcx, Tag>, fields: impl Iterator>>, ) -> InterpResult<'tcx> { match place.layout.fields { @@ -346,7 +346,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } - fn visit_union(&mut self, _v: MPlaceTy<'tcx, Tag>, _fields: NonZeroUsize) -> InterpResult<'tcx> { + fn visit_union(&mut self, _v: &MPlaceTy<'tcx, Tag>, _fields: NonZeroUsize) -> InterpResult<'tcx> { bug!("we should have already handled unions in `visit_value`") } } @@ -356,7 +356,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // different values into a struct. fn write_packed_immediates( &mut self, - place: MPlaceTy<'tcx, Tag>, + place: &MPlaceTy<'tcx, Tag>, imms: &[ImmTy<'tcx, Tag>], ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); @@ -366,7 +366,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx for &imm in imms { this.write_immediate_to_mplace( *imm, - place.offset(offset, MemPlaceMeta::None, imm.layout, &*this.tcx)?, + &place.offset(offset, MemPlaceMeta::None, imm.layout, &*this.tcx)?, )?; offset += imm.layout.size; } @@ -406,7 +406,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Allocate new place, set initial value to 0. let errno_layout = this.machine.layouts.u32; let errno_place = this.allocate(errno_layout, MiriMemoryKind::Machine.into()); - this.write_scalar(Scalar::from_u32(0), errno_place.into())?; + this.write_scalar(Scalar::from_u32(0), &errno_place.into())?; this.active_thread_mut().last_error = Some(errno_place); Ok(errno_place) } @@ -416,14 +416,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn set_last_error(&mut self, scalar: Scalar) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let errno_place = this.last_error_place()?; - this.write_scalar(scalar, errno_place.into()) + this.write_scalar(scalar, &errno_place.into()) } /// Gets the last error variable. fn get_last_error(&mut self) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); let errno_place = this.last_error_place()?; - this.read_scalar(errno_place.into())?.check_init() + this.read_scalar(&errno_place.into())?.check_init() } /// Sets the last OS error using a `std::io::Error`. This function tries to produce the most @@ -486,7 +486,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn read_scalar_at_offset( &self, - op: OpTy<'tcx, Tag>, + op: &OpTy<'tcx, Tag>, offset: u64, layout: TyAndLayout<'tcx>, ) -> InterpResult<'tcx, ScalarMaybeUninit> { @@ -496,12 +496,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Ensure that the following read at an offset is within bounds assert!(op_place.layout.size >= offset + layout.size); let value_place = op_place.offset(offset, MemPlaceMeta::None, layout, this)?; - this.read_scalar(value_place.into()) + this.read_scalar(&value_place.into()) } fn write_scalar_at_offset( &mut self, - op: OpTy<'tcx, Tag>, + op: &OpTy<'tcx, Tag>, offset: u64, value: impl Into>, layout: TyAndLayout<'tcx>, @@ -512,7 +512,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Ensure that the following read at an offset is within bounds assert!(op_place.layout.size >= offset + layout.size); let value_place = op_place.offset(offset, MemPlaceMeta::None, layout, this)?; - this.write_scalar(value, value_place.into()) + this.write_scalar(value, &value_place.into()) } /// Parse a `timespec` struct and return it as a `std::time::Duration`. It returns `None` @@ -520,15 +520,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// `EINVAL` in this case. fn read_timespec( &mut self, - timespec_ptr_op: OpTy<'tcx, Tag>, + timespec_ptr_op: &OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, Option> { let this = self.eval_context_mut(); let tp = this.deref_operand(timespec_ptr_op)?; - let seconds_place = this.mplace_field(tp, 0)?; - let seconds_scalar = this.read_scalar(seconds_place.into())?; + let seconds_place = this.mplace_field(&tp, 0)?; + let seconds_scalar = this.read_scalar(&seconds_place.into())?; let seconds = seconds_scalar.to_machine_isize(this)?; - let nanoseconds_place = this.mplace_field(tp, 1)?; - let nanoseconds_scalar = this.read_scalar(nanoseconds_place.into())?; + let nanoseconds_place = this.mplace_field(&tp, 1)?; + let nanoseconds_scalar = this.read_scalar(&nanoseconds_place.into())?; let nanoseconds = nanoseconds_scalar.to_machine_isize(this)?; Ok(try { diff --git a/src/machine.rs b/src/machine.rs index dd7d0dd3b647d..32aae4a8c8e51 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -193,7 +193,7 @@ impl MemoryExtra { // This should be all-zero, pointer-sized. let layout = this.machine.layouts.usize; let place = this.allocate(layout, MiriMemoryKind::ExternStatic.into()); - this.write_scalar(Scalar::from_machine_usize(0, this), place.into())?; + this.write_scalar(Scalar::from_machine_usize(0, this), &place.into())?; Self::add_extern_static(this, "__cxa_thread_atexit_impl", place.ptr); // "environ" Self::add_extern_static(this, "environ", this.machine.env_vars.environ.unwrap().ptr); @@ -203,7 +203,7 @@ impl MemoryExtra { // This is some obscure hack that is part of the Windows TLS story. It's a `u8`. let layout = this.machine.layouts.u8; let place = this.allocate(layout, MiriMemoryKind::ExternStatic.into()); - this.write_scalar(Scalar::from_u8(0), place.into())?; + this.write_scalar(Scalar::from_u8(0), &place.into())?; Self::add_extern_static(this, "_tls_used", place.ptr); } _ => {} // No "extern statics" supported on this target @@ -359,7 +359,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { instance: ty::Instance<'tcx>, abi: Abi, args: &[OpTy<'tcx, Tag>], - ret: Option<(PlaceTy<'tcx, Tag>, mir::BasicBlock)>, + ret: Option<(&PlaceTy<'tcx, Tag>, mir::BasicBlock)>, unwind: Option, ) -> InterpResult<'tcx, Option<&'mir mir::Body<'tcx>>> { ecx.find_mir_or_eval_fn(instance, abi, args, ret, unwind) @@ -371,7 +371,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { fn_val: Dlsym, abi: Abi, args: &[OpTy<'tcx, Tag>], - ret: Option<(PlaceTy<'tcx, Tag>, mir::BasicBlock)>, + ret: Option<(&PlaceTy<'tcx, Tag>, mir::BasicBlock)>, _unwind: Option, ) -> InterpResult<'tcx> { ecx.call_dlsym(fn_val, abi, args, ret) @@ -382,7 +382,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { ecx: &mut rustc_mir::interpret::InterpCx<'mir, 'tcx, Self>, instance: ty::Instance<'tcx>, args: &[OpTy<'tcx, Tag>], - ret: Option<(PlaceTy<'tcx, Tag>, mir::BasicBlock)>, + ret: Option<(&PlaceTy<'tcx, Tag>, mir::BasicBlock)>, unwind: Option, ) -> InterpResult<'tcx> { ecx.call_intrinsic(instance, args, ret, unwind) @@ -406,15 +406,15 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { fn binary_ptr_op( ecx: &rustc_mir::interpret::InterpCx<'mir, 'tcx, Self>, bin_op: mir::BinOp, - left: ImmTy<'tcx, Tag>, - right: ImmTy<'tcx, Tag>, + left: &ImmTy<'tcx, Tag>, + right: &ImmTy<'tcx, Tag>, ) -> InterpResult<'tcx, (Scalar, bool, ty::Ty<'tcx>)> { ecx.binary_ptr_op(bin_op, left, right) } fn box_alloc( ecx: &mut InterpCx<'mir, 'tcx, Self>, - dest: PlaceTy<'tcx, Tag>, + dest: &PlaceTy<'tcx, Tag>, ) -> InterpResult<'tcx> { trace!("box_alloc for {:?}", dest.layout.ty); let layout = ecx.layout_of(dest.layout.ty.builtin_deref(false).unwrap().ty)?; @@ -542,7 +542,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { fn retag( ecx: &mut InterpCx<'mir, 'tcx, Self>, kind: mir::RetagKind, - place: PlaceTy<'tcx, Tag>, + place: &PlaceTy<'tcx, Tag>, ) -> InterpResult<'tcx> { if ecx.memory.extra.stacked_borrows.is_some() { ecx.retag(kind, place) diff --git a/src/operator.rs b/src/operator.rs index 5b86b9a76f6b4..cf92aed9ccb2c 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -8,8 +8,8 @@ pub trait EvalContextExt<'tcx> { fn binary_ptr_op( &self, bin_op: mir::BinOp, - left: ImmTy<'tcx, Tag>, - right: ImmTy<'tcx, Tag>, + left: &ImmTy<'tcx, Tag>, + right: &ImmTy<'tcx, Tag>, ) -> InterpResult<'tcx, (Scalar, bool, Ty<'tcx>)>; fn ptr_eq(&self, left: Scalar, right: Scalar) -> InterpResult<'tcx, bool>; @@ -19,8 +19,8 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { fn binary_ptr_op( &self, bin_op: mir::BinOp, - left: ImmTy<'tcx, Tag>, - right: ImmTy<'tcx, Tag>, + left: &ImmTy<'tcx, Tag>, + right: &ImmTy<'tcx, Tag>, ) -> InterpResult<'tcx, (Scalar, bool, Ty<'tcx>)> { use rustc_middle::mir::BinOp::*; @@ -30,7 +30,7 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { Eq | Ne => { // This supports fat pointers. #[rustfmt::skip] - let eq = match (*left, *right) { + let eq = match (**left, **right) { (Immediate::Scalar(left), Immediate::Scalar(right)) => { self.ptr_eq(left.check_init()?, right.check_init()?)? } diff --git a/src/shims/backtrace.rs b/src/shims/backtrace.rs index a599ee70efae9..159a0bc1f8cdf 100644 --- a/src/shims/backtrace.rs +++ b/src/shims/backtrace.rs @@ -13,11 +13,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn handle_miri_get_backtrace( &mut self, args: &[OpTy<'tcx, Tag>], - dest: PlaceTy<'tcx, Tag> + dest: &PlaceTy<'tcx, Tag> ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let tcx = this.tcx; - let &[flags] = check_arg_count(args)?; + let &[ref flags] = check_arg_count(args)?; let flags = this.read_scalar(flags)?.to_u64()?; if flags != 0 { @@ -59,8 +59,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Write pointers into array let alloc = this.allocate(this.layout_of(array_ty).unwrap(), MiriMemoryKind::Rust.into()); for (i, ptr) in ptrs.into_iter().enumerate() { - let place = this.mplace_index(alloc, i as u64)?; - this.write_immediate_to_mplace(ptr.into(), place)?; + let place = this.mplace_index(&alloc, i as u64)?; + this.write_immediate_to_mplace(ptr.into(), &place)?; } this.write_immediate(Immediate::new_slice(alloc.ptr.into(), len.try_into().unwrap(), this), dest)?; @@ -70,11 +70,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn handle_miri_resolve_frame( &mut self, args: &[OpTy<'tcx, Tag>], - dest: PlaceTy<'tcx, Tag> + dest: &PlaceTy<'tcx, Tag> ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let tcx = this.tcx; - let &[ptr, flags] = check_arg_count(args)?; + let &[ref ptr, ref flags] = check_arg_count(args)?; let flags = this.read_scalar(flags)?.to_u64()?; if flags != 0 { @@ -125,15 +125,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } - this.write_immediate(name_alloc.to_ref(), this.mplace_field(dest, 0)?.into())?; - this.write_immediate(filename_alloc.to_ref(), this.mplace_field(dest, 1)?.into())?; - this.write_scalar(lineno_alloc, this.mplace_field(dest, 2)?.into())?; - this.write_scalar(colno_alloc, this.mplace_field(dest, 3)?.into())?; + this.write_immediate(name_alloc.to_ref(), &this.mplace_field(&dest, 0)?.into())?; + this.write_immediate(filename_alloc.to_ref(), &this.mplace_field(&dest, 1)?.into())?; + this.write_scalar(lineno_alloc, &this.mplace_field(&dest, 2)?.into())?; + this.write_scalar(colno_alloc, &this.mplace_field(&dest, 3)?.into())?; // Support a 4-field struct for now - this is deprecated // and slated for removal. if num_fields == 5 { - this.write_scalar(fn_ptr, this.mplace_field(dest, 4)?.into())?; + this.write_scalar(fn_ptr, &this.mplace_field(&dest, 4)?.into())?; } Ok(()) diff --git a/src/shims/dlsym.rs b/src/shims/dlsym.rs index a87d8a0175734..e45556f9a1d13 100644 --- a/src/shims/dlsym.rs +++ b/src/shims/dlsym.rs @@ -32,7 +32,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx dlsym: Dlsym, abi: Abi, args: &[OpTy<'tcx, Tag>], - ret: Option<(PlaceTy<'tcx, Tag>, mir::BasicBlock)>, + ret: Option<(&PlaceTy<'tcx, Tag>, mir::BasicBlock)>, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); match dlsym { diff --git a/src/shims/env.rs b/src/shims/env.rs index 12d1cda96da04..53770fd4f05ba 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -69,7 +69,7 @@ impl<'tcx> EnvVars<'tcx> { } // Deallocate environ var list. let environ = ecx.machine.env_vars.environ.unwrap(); - let old_vars_ptr = ecx.read_scalar(environ.into())?.check_init()?; + let old_vars_ptr = ecx.read_scalar(&environ.into())?.check_init()?; ecx.memory.deallocate(ecx.force_ptr(old_vars_ptr)?, None, MiriMemoryKind::Env.into())?; Ok(()) } @@ -99,7 +99,7 @@ fn alloc_env_var_as_wide_str<'mir, 'tcx>( impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { - fn getenv(&mut self, name_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, Scalar> { + fn getenv(&mut self, name_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); let target_os = &this.tcx.sess.target.os; assert!(target_os == "linux" || target_os == "macos", "`getenv` is only available for the UNIX target family"); @@ -118,9 +118,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx #[allow(non_snake_case)] fn GetEnvironmentVariableW( &mut self, - name_op: OpTy<'tcx, Tag>, // LPCWSTR - buf_op: OpTy<'tcx, Tag>, // LPWSTR - size_op: OpTy<'tcx, Tag>, // DWORD + name_op: &OpTy<'tcx, Tag>, // LPCWSTR + buf_op: &OpTy<'tcx, Tag>, // LPWSTR + size_op: &OpTy<'tcx, Tag>, // DWORD ) -> InterpResult<'tcx, u32> { // Returns DWORD (u32 in Windows) let this = self.eval_context_mut(); this.assert_target_os("windows", "GetEnvironmentVariableW"); @@ -169,7 +169,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } #[allow(non_snake_case)] - fn FreeEnvironmentStringsW(&mut self, env_block_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + fn FreeEnvironmentStringsW(&mut self, env_block_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); this.assert_target_os("windows", "FreeEnvironmentStringsW"); @@ -181,8 +181,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn setenv( &mut self, - name_op: OpTy<'tcx, Tag>, - value_op: OpTy<'tcx, Tag>, + name_op: &OpTy<'tcx, Tag>, + value_op: &OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, i32> { let mut this = self.eval_context_mut(); let target_os = &this.tcx.sess.target.os; @@ -218,8 +218,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx #[allow(non_snake_case)] fn SetEnvironmentVariableW( &mut self, - name_op: OpTy<'tcx, Tag>, // LPCWSTR - value_op: OpTy<'tcx, Tag>, // LPCWSTR + name_op: &OpTy<'tcx, Tag>, // LPCWSTR + value_op: &OpTy<'tcx, Tag>, // LPCWSTR ) -> InterpResult<'tcx, i32> { let mut this = self.eval_context_mut(); this.assert_target_os("windows", "SetEnvironmentVariableW"); @@ -256,7 +256,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } - fn unsetenv(&mut self, name_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + fn unsetenv(&mut self, name_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); let target_os = &this.tcx.sess.target.os; assert!(target_os == "linux" || target_os == "macos", "`unsetenv` is only available for the UNIX target family"); @@ -286,8 +286,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn getcwd( &mut self, - buf_op: OpTy<'tcx, Tag>, - size_op: OpTy<'tcx, Tag>, + buf_op: &OpTy<'tcx, Tag>, + size_op: &OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); let target_os = &this.tcx.sess.target.os; @@ -295,8 +295,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.check_no_isolation("`getcwd`")?; - let buf = this.read_scalar(buf_op)?.check_init()?; - let size = this.read_scalar(size_op)?.to_machine_usize(&*this.tcx)?; + let buf = this.read_scalar(&buf_op)?.check_init()?; + let size = this.read_scalar(&size_op)?.to_machine_usize(&*this.tcx)?; // If we cannot get the current directory, we return null match env::current_dir() { Ok(cwd) => { @@ -314,8 +314,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx #[allow(non_snake_case)] fn GetCurrentDirectoryW( &mut self, - size_op: OpTy<'tcx, Tag>, // DWORD - buf_op: OpTy<'tcx, Tag>, // LPTSTR + size_op: &OpTy<'tcx, Tag>, // DWORD + buf_op: &OpTy<'tcx, Tag>, // LPTSTR ) -> InterpResult<'tcx, u32> { let this = self.eval_context_mut(); this.assert_target_os("windows", "GetCurrentDirectoryW"); @@ -334,7 +334,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(0) } - fn chdir(&mut self, path_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + fn chdir(&mut self, path_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); let target_os = &this.tcx.sess.target.os; assert!(target_os == "linux" || target_os == "macos", "`getcwd` is only available for the UNIX target family"); @@ -355,7 +355,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx #[allow(non_snake_case)] fn SetCurrentDirectoryW ( &mut self, - path_op: OpTy<'tcx, Tag> // LPCTSTR + path_op: &OpTy<'tcx, Tag> // LPCTSTR ) -> InterpResult<'tcx, i32> { // Returns BOOL (i32 in Windows) let this = self.eval_context_mut(); this.assert_target_os("windows", "SetCurrentDirectoryW"); @@ -379,7 +379,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); // Deallocate the old environ list, if any. if let Some(environ) = this.machine.env_vars.environ { - let old_vars_ptr = this.read_scalar(environ.into())?.check_init()?; + let old_vars_ptr = this.read_scalar(&environ.into())?.check_init()?; this.memory.deallocate(this.force_ptr(old_vars_ptr)?, None, MiriMemoryKind::Env.into())?; } else { // No `environ` allocated yet, let's do that. @@ -399,12 +399,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.layout_of(tcx.mk_array(tcx.types.usize, u64::try_from(vars.len()).unwrap()))?; let vars_place = this.allocate(vars_layout, MiriMemoryKind::Env.into()); for (idx, var) in vars.into_iter().enumerate() { - let place = this.mplace_field(vars_place, idx)?; - this.write_scalar(var, place.into())?; + let place = this.mplace_field(&vars_place, idx)?; + this.write_scalar(var, &place.into())?; } this.write_scalar( vars_place.ptr, - this.machine.env_vars.environ.unwrap().into(), + &this.machine.env_vars.environ.unwrap().into(), )?; Ok(()) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 628e9b69e1741..9203aafd57673 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -114,7 +114,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx def_id: DefId, abi: Abi, args: &[OpTy<'tcx, Tag>], - ret: Option<(PlaceTy<'tcx, Tag>, mir::BasicBlock)>, + ret: Option<(&PlaceTy<'tcx, Tag>, mir::BasicBlock)>, unwind: Option, ) -> InterpResult<'tcx, Option<&'mir mir::Body<'tcx>>> { let this = self.eval_context_mut(); @@ -147,7 +147,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "ExitProcess" => { check_abi(abi, if link_name == "exit" { Abi::C } else { Abi::System })?; - let &[code] = check_arg_count(args)?; + let &[ref code] = check_arg_count(args)?; // it's really u32 for ExitProcess, but we have to put it into the `Exit` variant anyway let code = this.read_scalar(code)?.to_i32()?; throw_machine_stop!(TerminationInfo::Exit(code.into())); @@ -186,7 +186,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Third: functions that return. if this.emulate_foreign_item_by_name(link_name, abi, args, dest, ret)? { - trace!("{:?}", this.dump_place(*dest)); + trace!("{:?}", this.dump_place(**dest)); this.go_to_block(ret); } @@ -201,7 +201,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx link_name: &str, abi: Abi, args: &[OpTy<'tcx, Tag>], - dest: PlaceTy<'tcx, Tag>, + dest: &PlaceTy<'tcx, Tag>, ret: mir::BasicBlock, ) -> InterpResult<'tcx, bool> { let this = self.eval_context_mut(); @@ -212,7 +212,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Miri-specific extern functions "miri_static_root" => { check_abi(abi, Abi::Rust)?; - let &[ptr] = check_arg_count(args)?; + let &[ref ptr] = check_arg_count(args)?; let ptr = this.read_scalar(ptr)?.check_init()?; let ptr = this.force_ptr(ptr)?; if ptr.offset != Size::ZERO { @@ -237,14 +237,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Standard C allocation "malloc" => { check_abi(abi, Abi::C)?; - let &[size] = check_arg_count(args)?; + let &[ref size] = check_arg_count(args)?; let size = this.read_scalar(size)?.to_machine_usize(this)?; let res = this.malloc(size, /*zero_init:*/ false, MiriMemoryKind::C); this.write_scalar(res, dest)?; } "calloc" => { check_abi(abi, Abi::C)?; - let &[items, len] = check_arg_count(args)?; + let &[ref items, ref len] = check_arg_count(args)?; let items = this.read_scalar(items)?.to_machine_usize(this)?; let len = this.read_scalar(len)?.to_machine_usize(this)?; let size = @@ -254,13 +254,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "free" => { check_abi(abi, Abi::C)?; - let &[ptr] = check_arg_count(args)?; + let &[ref ptr] = check_arg_count(args)?; let ptr = this.read_scalar(ptr)?.check_init()?; this.free(ptr, MiriMemoryKind::C)?; } "realloc" => { check_abi(abi, Abi::C)?; - let &[old_ptr, new_size] = check_arg_count(args)?; + let &[ref old_ptr, ref new_size] = check_arg_count(args)?; let old_ptr = this.read_scalar(old_ptr)?.check_init()?; let new_size = this.read_scalar(new_size)?.to_machine_usize(this)?; let res = this.realloc(old_ptr, new_size, MiriMemoryKind::C)?; @@ -272,7 +272,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // allocation that also checks that all conditions are met, such as not permitting zero-sized allocations.) "__rust_alloc" => { check_abi(abi, Abi::Rust)?; - let &[size, align] = check_arg_count(args)?; + let &[ref size, ref align] = check_arg_count(args)?; let size = this.read_scalar(size)?.to_machine_usize(this)?; let align = this.read_scalar(align)?.to_machine_usize(this)?; Self::check_alloc_request(size, align)?; @@ -285,7 +285,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "__rust_alloc_zeroed" => { check_abi(abi, Abi::Rust)?; - let &[size, align] = check_arg_count(args)?; + let &[ref size, ref align] = check_arg_count(args)?; let size = this.read_scalar(size)?.to_machine_usize(this)?; let align = this.read_scalar(align)?.to_machine_usize(this)?; Self::check_alloc_request(size, align)?; @@ -300,7 +300,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "__rust_dealloc" => { check_abi(abi, Abi::Rust)?; - let &[ptr, old_size, align] = check_arg_count(args)?; + let &[ref ptr, ref old_size, ref align] = check_arg_count(args)?; let ptr = this.read_scalar(ptr)?.check_init()?; let old_size = this.read_scalar(old_size)?.to_machine_usize(this)?; let align = this.read_scalar(align)?.to_machine_usize(this)?; @@ -314,7 +314,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "__rust_realloc" => { check_abi(abi, Abi::Rust)?; - let &[ptr, old_size, align, new_size] = check_arg_count(args)?; + let &[ref ptr, ref old_size, ref align, ref new_size] = check_arg_count(args)?; let ptr = this.force_ptr(this.read_scalar(ptr)?.check_init()?)?; let old_size = this.read_scalar(old_size)?.to_machine_usize(this)?; let align = this.read_scalar(align)?.to_machine_usize(this)?; @@ -335,7 +335,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // C memory handling functions "memcmp" => { check_abi(abi, Abi::C)?; - let &[left, right, n] = check_arg_count(args)?; + let &[ref left, ref right, ref n] = check_arg_count(args)?; let left = this.read_scalar(left)?.check_init()?; let right = this.read_scalar(right)?.check_init()?; let n = Size::from_bytes(this.read_scalar(n)?.to_machine_usize(this)?); @@ -356,7 +356,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "memrchr" => { check_abi(abi, Abi::C)?; - let &[ptr, val, num] = check_arg_count(args)?; + let &[ref ptr, ref val, ref num] = check_arg_count(args)?; let ptr = this.read_scalar(ptr)?.check_init()?; let val = this.read_scalar(val)?.to_i32()? as u8; let num = this.read_scalar(num)?.to_machine_usize(this)?; @@ -375,7 +375,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "memchr" => { check_abi(abi, Abi::C)?; - let &[ptr, val, num] = check_arg_count(args)?; + let &[ref ptr, ref val, ref num] = check_arg_count(args)?; let ptr = this.read_scalar(ptr)?.check_init()?; let val = this.read_scalar(val)?.to_i32()? as u8; let num = this.read_scalar(num)?.to_machine_usize(this)?; @@ -393,7 +393,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "strlen" => { check_abi(abi, Abi::C)?; - let &[ptr] = check_arg_count(args)?; + let &[ref ptr] = check_arg_count(args)?; let ptr = this.read_scalar(ptr)?.check_init()?; let n = this.memory.read_c_str(ptr)?.len(); this.write_scalar(Scalar::from_machine_usize(u64::try_from(n).unwrap(), this), dest)?; @@ -409,7 +409,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "atanf" => { check_abi(abi, Abi::C)?; - let &[f] = check_arg_count(args)?; + let &[ref f] = check_arg_count(args)?; // FIXME: Using host floats. let f = f32::from_bits(this.read_scalar(f)?.to_u32()?); let f = match link_name { @@ -429,7 +429,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "atan2f" => { check_abi(abi, Abi::C)?; - let &[f1, f2] = check_arg_count(args)?; + let &[ref f1, ref f2] = check_arg_count(args)?; // underscore case for windows, here and below // (see https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/floating-point-primitives?view=vs-2019) // FIXME: Using host floats. @@ -451,7 +451,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "atan" => { check_abi(abi, Abi::C)?; - let &[f] = check_arg_count(args)?; + let &[ref f] = check_arg_count(args)?; // FIXME: Using host floats. let f = f64::from_bits(this.read_scalar(f)?.to_u64()?); let f = match link_name { @@ -471,7 +471,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "atan2" => { check_abi(abi, Abi::C)?; - let &[f1, f2] = check_arg_count(args)?; + let &[ref f1, ref f2] = check_arg_count(args)?; // FIXME: Using host floats. let f1 = f64::from_bits(this.read_scalar(f1)?.to_u64()?); let f2 = f64::from_bits(this.read_scalar(f2)?.to_u64()?); @@ -487,7 +487,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "scalbn" => { check_abi(abi, Abi::C)?; - let &[x, exp] = check_arg_count(args)?; + let &[ref x, ref exp] = check_arg_count(args)?; // For radix-2 (binary) systems, `ldexp` and `scalbn` are the same. let x = this.read_scalar(x)?.to_f64()?; let exp = this.read_scalar(exp)?.to_i32()?; @@ -514,7 +514,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "llvm.aarch64.hint" if this.tcx.sess.target.arch == "aarch64" => { check_abi(abi, Abi::C)?; - let &[hint] = check_arg_count(args)?; + let &[ref hint] = check_arg_count(args)?; let hint = this.read_scalar(hint)?.to_i32()?; match hint { 1 => { // HINT_YIELD diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index fc859bc530205..33aa7b28bb5b5 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -16,7 +16,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx &mut self, instance: ty::Instance<'tcx>, args: &[OpTy<'tcx, Tag>], - ret: Option<(PlaceTy<'tcx, Tag>, mir::BasicBlock)>, + ret: Option<(&PlaceTy<'tcx, Tag>, mir::BasicBlock)>, _unwind: Option, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); @@ -36,32 +36,32 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx match intrinsic_name { // Miri overwriting CTFE intrinsics. "ptr_guaranteed_eq" => { - let &[left, right] = check_arg_count(args)?; + let &[ref left, ref right] = check_arg_count(args)?; let left = this.read_immediate(left)?; let right = this.read_immediate(right)?; - this.binop_ignore_overflow(mir::BinOp::Eq, left, right, dest)?; + this.binop_ignore_overflow(mir::BinOp::Eq, &left, &right, dest)?; } "ptr_guaranteed_ne" => { - let &[left, right] = check_arg_count(args)?; + let &[ref left, ref right] = check_arg_count(args)?; let left = this.read_immediate(left)?; let right = this.read_immediate(right)?; - this.binop_ignore_overflow(mir::BinOp::Ne, left, right, dest)?; + this.binop_ignore_overflow(mir::BinOp::Ne, &left, &right, dest)?; } // Raw memory accesses "volatile_load" => { - let &[place] = check_arg_count(args)?; + let &[ref place] = check_arg_count(args)?; let place = this.deref_operand(place)?; - this.copy_op(place.into(), dest)?; + this.copy_op(&place.into(), dest)?; } "volatile_store" => { - let &[place, dest] = check_arg_count(args)?; + let &[ref place, ref dest] = check_arg_count(args)?; let place = this.deref_operand(place)?; - this.copy_op(dest, place.into())?; + this.copy_op(dest, &place.into())?; } "write_bytes" => { - let &[ptr, val_byte, count] = check_arg_count(args)?; + let &[ref ptr, ref val_byte, ref count] = check_arg_count(args)?; let ty = instance.substs.type_at(0); let ty_layout = this.layout_of(ty)?; let val_byte = this.read_scalar(val_byte)?.to_u8()?; @@ -89,7 +89,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "truncf32" | "roundf32" => { - let &[f] = check_arg_count(args)?; + let &[ref f] = check_arg_count(args)?; // FIXME: Using host floats. let f = f32::from_bits(this.read_scalar(f)?.to_u32()?); let f = match intrinsic_name { @@ -126,7 +126,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "truncf64" | "roundf64" => { - let &[f] = check_arg_count(args)?; + let &[ref f] = check_arg_count(args)?; // FIXME: Using host floats. let f = f64::from_bits(this.read_scalar(f)?.to_u64()?); let f = match intrinsic_name { @@ -155,7 +155,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "fdiv_fast" | "frem_fast" => { - let &[a, b] = check_arg_count(args)?; + let &[ref a, ref b] = check_arg_count(args)?; let a = this.read_immediate(a)?; let b = this.read_immediate(b)?; let op = match intrinsic_name { @@ -166,7 +166,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "frem_fast" => mir::BinOp::Rem, _ => bug!(), }; - this.binop_ignore_overflow(op, a, b, dest)?; + this.binop_ignore_overflow(op, &a, &b, dest)?; } #[rustfmt::skip] @@ -174,7 +174,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "maxnumf32" | "copysignf32" => { - let &[a, b] = check_arg_count(args)?; + let &[ref a, ref b] = check_arg_count(args)?; let a = this.read_scalar(a)?.to_f32()?; let b = this.read_scalar(b)?.to_f32()?; let res = match intrinsic_name { @@ -191,7 +191,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "maxnumf64" | "copysignf64" => { - let &[a, b] = check_arg_count(args)?; + let &[ref a, ref b] = check_arg_count(args)?; let a = this.read_scalar(a)?.to_f64()?; let b = this.read_scalar(b)?.to_f64()?; let res = match intrinsic_name { @@ -204,7 +204,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "powf32" => { - let &[f, f2] = check_arg_count(args)?; + let &[ref f, ref f2] = check_arg_count(args)?; // FIXME: Using host floats. let f = f32::from_bits(this.read_scalar(f)?.to_u32()?); let f2 = f32::from_bits(this.read_scalar(f2)?.to_u32()?); @@ -212,7 +212,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "powf64" => { - let &[f, f2] = check_arg_count(args)?; + let &[ref f, ref f2] = check_arg_count(args)?; // FIXME: Using host floats. let f = f64::from_bits(this.read_scalar(f)?.to_u64()?); let f2 = f64::from_bits(this.read_scalar(f2)?.to_u64()?); @@ -220,7 +220,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "fmaf32" => { - let &[a, b, c] = check_arg_count(args)?; + let &[ref a, ref b, ref c] = check_arg_count(args)?; let a = this.read_scalar(a)?.to_f32()?; let b = this.read_scalar(b)?.to_f32()?; let c = this.read_scalar(c)?.to_f32()?; @@ -229,7 +229,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "fmaf64" => { - let &[a, b, c] = check_arg_count(args)?; + let &[ref a, ref b, ref c] = check_arg_count(args)?; let a = this.read_scalar(a)?.to_f64()?; let b = this.read_scalar(b)?.to_f64()?; let c = this.read_scalar(c)?.to_f64()?; @@ -238,7 +238,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "powif32" => { - let &[f, i] = check_arg_count(args)?; + let &[ref f, ref i] = check_arg_count(args)?; // FIXME: Using host floats. let f = f32::from_bits(this.read_scalar(f)?.to_u32()?); let i = this.read_scalar(i)?.to_i32()?; @@ -246,7 +246,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "powif64" => { - let &[f, i] = check_arg_count(args)?; + let &[ref f, ref i] = check_arg_count(args)?; // FIXME: Using host floats. let f = f64::from_bits(this.read_scalar(f)?.to_u64()?); let i = this.read_scalar(i)?.to_i32()?; @@ -254,7 +254,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "float_to_int_unchecked" => { - let &[val] = check_arg_count(args)?; + let &[ref val] = check_arg_count(args)?; let val = this.read_immediate(val)?; let res = match val.layout.ty.kind() { @@ -404,8 +404,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Other "exact_div" => { - let &[num, denom] = check_arg_count(args)?; - this.exact_div(this.read_immediate(num)?, this.read_immediate(denom)?, dest)?; + let &[ref num, ref denom] = check_arg_count(args)?; + this.exact_div(&this.read_immediate(num)?, &this.read_immediate(denom)?, dest)?; } "try" => return this.handle_try(args, dest, ret), @@ -413,23 +413,23 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx name => throw_unsup_format!("unimplemented intrinsic: {}", name), } - trace!("{:?}", this.dump_place(*dest)); + trace!("{:?}", this.dump_place(**dest)); this.go_to_block(ret); Ok(()) } fn atomic_load( - &mut self, args: &[OpTy<'tcx, Tag>], dest: PlaceTy<'tcx, Tag>, + &mut self, args: &[OpTy<'tcx, Tag>], dest: &PlaceTy<'tcx, Tag>, atomic: AtomicReadOp ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - let &[place] = check_arg_count(args)?; + let &[ref place] = check_arg_count(args)?; let place = this.deref_operand(place)?; // make sure it fits into a scalar; otherwise it cannot be atomic - let val = this.read_scalar_atomic(place, atomic)?; + let val = this.read_scalar_atomic(&place, atomic)?; // Check alignment requirements. Atomics must always be aligned to their size, // even if the type they wrap would be less aligned (e.g. AtomicU64 on 32bit must @@ -443,7 +443,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn atomic_store(&mut self, args: &[OpTy<'tcx, Tag>], atomic: AtomicWriteOp) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - let &[place, val] = check_arg_count(args)?; + let &[ref place, ref val] = check_arg_count(args)?; let place = this.deref_operand(place)?; let val = this.read_scalar(val)?; // make sure it fits into a scalar; otherwise it cannot be atomic @@ -454,7 +454,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.memory.check_ptr_access(place.ptr, place.layout.size, align)?; // Perform atomic store - this.write_scalar_atomic(val, place, atomic)?; + this.write_scalar_atomic(val, &place, atomic)?; Ok(()) } @@ -473,12 +473,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } fn atomic_op( - &mut self, args: &[OpTy<'tcx, Tag>], dest: PlaceTy<'tcx, Tag>, + &mut self, args: &[OpTy<'tcx, Tag>], dest: &PlaceTy<'tcx, Tag>, op: mir::BinOp, neg: bool, atomic: AtomicRwOp ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - let &[place, rhs] = check_arg_count(args)?; + let &[ref place, ref rhs] = check_arg_count(args)?; let place = this.deref_operand(place)?; if !place.layout.ty.is_integral() { bug!("Atomic arithmetic operations only work on integer types"); @@ -491,17 +491,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let align = Align::from_bytes(place.layout.size.bytes()).unwrap(); this.memory.check_ptr_access(place.ptr, place.layout.size, align)?; - let old = this.atomic_op_immediate(place, rhs, op, neg, atomic)?; + let old = this.atomic_op_immediate(&place, &rhs, op, neg, atomic)?; this.write_immediate(*old, dest)?; // old value is returned Ok(()) } fn atomic_exchange( - &mut self, args: &[OpTy<'tcx, Tag>], dest: PlaceTy<'tcx, Tag>, atomic: AtomicRwOp + &mut self, args: &[OpTy<'tcx, Tag>], dest: &PlaceTy<'tcx, Tag>, atomic: AtomicRwOp ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - let &[place, new] = check_arg_count(args)?; + let &[ref place, ref new] = check_arg_count(args)?; let place = this.deref_operand(place)?; let new = this.read_scalar(new)?; @@ -511,18 +511,18 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let align = Align::from_bytes(place.layout.size.bytes()).unwrap(); this.memory.check_ptr_access(place.ptr, place.layout.size, align)?; - let old = this.atomic_exchange_scalar(place, new, atomic)?; + let old = this.atomic_exchange_scalar(&place, new, atomic)?; this.write_scalar(old, dest)?; // old value is returned Ok(()) } fn atomic_compare_exchange_impl( - &mut self, args: &[OpTy<'tcx, Tag>], dest: PlaceTy<'tcx, Tag>, + &mut self, args: &[OpTy<'tcx, Tag>], dest: &PlaceTy<'tcx, Tag>, success: AtomicRwOp, fail: AtomicReadOp, can_fail_spuriously: bool ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - let &[place, expect_old, new] = check_arg_count(args)?; + let &[ref place, ref expect_old, ref new] = check_arg_count(args)?; let place = this.deref_operand(place)?; let expect_old = this.read_immediate(expect_old)?; // read as immediate for the sake of `binary_op()` let new = this.read_scalar(new)?; @@ -536,7 +536,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let old = this.atomic_compare_exchange_scalar( - place, expect_old, new, success, fail, can_fail_spuriously + &place, &expect_old, new, success, fail, can_fail_spuriously )?; // Return old value. @@ -545,14 +545,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } fn atomic_compare_exchange( - &mut self, args: &[OpTy<'tcx, Tag>], dest: PlaceTy<'tcx, Tag>, + &mut self, args: &[OpTy<'tcx, Tag>], dest: &PlaceTy<'tcx, Tag>, success: AtomicRwOp, fail: AtomicReadOp ) -> InterpResult<'tcx> { self.atomic_compare_exchange_impl(args, dest, success, fail, false) } fn atomic_compare_exchange_weak( - &mut self, args: &[OpTy<'tcx, Tag>], dest: PlaceTy<'tcx, Tag>, + &mut self, args: &[OpTy<'tcx, Tag>], dest: &PlaceTy<'tcx, Tag>, success: AtomicRwOp, fail: AtomicReadOp ) -> InterpResult<'tcx> { self.atomic_compare_exchange_impl(args, dest, success, fail, true) diff --git a/src/shims/mod.rs b/src/shims/mod.rs index c2b8809efbb66..1605ea2f6a894 100644 --- a/src/shims/mod.rs +++ b/src/shims/mod.rs @@ -28,15 +28,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx instance: ty::Instance<'tcx>, abi: Abi, args: &[OpTy<'tcx, Tag>], - ret: Option<(PlaceTy<'tcx, Tag>, mir::BasicBlock)>, + ret: Option<(&PlaceTy<'tcx, Tag>, mir::BasicBlock)>, unwind: Option, ) -> InterpResult<'tcx, Option<&'mir mir::Body<'tcx>>> { let this = self.eval_context_mut(); - trace!("eval_fn_call: {:#?}, {:?}", instance, ret.map(|p| *p.0)); + trace!("eval_fn_call: {:#?}, {:?}", instance, ret.map(|p| p.0)); // There are some more lang items we want to hook that CTFE does not hook (yet). if this.tcx.lang_items().align_offset_fn() == Some(instance.def.def_id()) { - let &[ptr, align] = check_arg_count(args)?; + let &[ref ptr, ref align] = check_arg_count(args)?; if this.align_offset(ptr, align, ret, unwind)? { return Ok(None); } @@ -61,9 +61,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// the actual MIR of `align_offset`. fn align_offset( &mut self, - ptr_op: OpTy<'tcx, Tag>, - align_op: OpTy<'tcx, Tag>, - ret: Option<(PlaceTy<'tcx, Tag>, mir::BasicBlock)>, + ptr_op: &OpTy<'tcx, Tag>, + align_op: &OpTy<'tcx, Tag>, + ret: Option<(&PlaceTy<'tcx, Tag>, mir::BasicBlock)>, unwind: Option, ) -> InterpResult<'tcx, bool> { let this = self.eval_context_mut(); diff --git a/src/shims/panic.rs b/src/shims/panic.rs index 52d27a1bb5c2d..abc7aa2ad1bdc 100644 --- a/src/shims/panic.rs +++ b/src/shims/panic.rs @@ -48,7 +48,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx assert_eq!(this.tcx.sess.panic_strategy(), PanicStrategy::Unwind); // Get the raw pointer stored in arg[0] (the panic payload). - let &[payload] = check_arg_count(args)?; + let &[ref payload] = check_arg_count(args)?; let payload = this.read_scalar(payload)?.check_init()?; let thread = this.active_thread_mut(); assert!( @@ -66,7 +66,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn handle_try( &mut self, args: &[OpTy<'tcx, Tag>], - dest: PlaceTy<'tcx, Tag>, + dest: &PlaceTy<'tcx, Tag>, ret: mir::BasicBlock, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); @@ -83,7 +83,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // a pointer to `Box`. // Get all the arguments. - let &[try_fn, data, catch_fn] = check_arg_count(args)?; + let &[ref try_fn, ref data, ref catch_fn] = check_arg_count(args)?; let try_fn = this.read_scalar(try_fn)?.check_init()?; let data = this.read_scalar(data)?.check_init()?; let catch_fn = this.read_scalar(catch_fn)?.check_init()?; @@ -95,7 +95,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.call_function( f_instance, &[data.into()], - Some(ret_place), + Some(&ret_place), // Directly return to caller. StackPopCleanup::Goto { ret: Some(ret), unwind: None }, )?; @@ -107,7 +107,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // This lets `handle_stack_pop` (below) know that we should stop unwinding // when we pop this frame. if this.tcx.sess.panic_strategy() == PanicStrategy::Unwind { - this.frame_mut().extra.catch_unwind = Some(CatchUnwindData { catch_fn, data, dest, ret }); + this.frame_mut().extra.catch_unwind = Some(CatchUnwindData { catch_fn, data, dest: *dest, ret }); } return Ok(()); @@ -133,7 +133,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx trace!("unwinding: found catch_panic frame during unwinding: {:?}", this.frame().instance); // We set the return value of `try` to 1, since there was a panic. - this.write_scalar(Scalar::from_i32(1), catch_unwind.dest)?; + this.write_scalar(Scalar::from_i32(1), &catch_unwind.dest)?; // The Thread's `panic_payload` holds what was passed to `miri_start_panic`. // This is exactly the second argument we need to pass to `catch_fn`. @@ -146,7 +146,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.call_function( f_instance, &[catch_unwind.data.into(), payload.into()], - Some(ret_place), + Some(&ret_place), // Directly return to caller of `try`. StackPopCleanup::Goto { ret: Some(catch_unwind.ret), unwind: None }, )?; @@ -193,9 +193,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Forward to `panic_bounds_check` lang item. // First arg: index. - let index = this.read_scalar(this.eval_operand(index, None)?)?; + let index = this.read_scalar(&this.eval_operand(index, None)?)?; // Second arg: len. - let len = this.read_scalar(this.eval_operand(len, None)?)?; + let len = this.read_scalar(&this.eval_operand(len, None)?)?; // Call the lang item. let panic_bounds_check = this.tcx.lang_items().panic_bounds_check_fn().unwrap(); diff --git a/src/shims/posix/dlsym.rs b/src/shims/posix/dlsym.rs index 660c6dc0ebaec..e1eccc680883f 100644 --- a/src/shims/posix/dlsym.rs +++ b/src/shims/posix/dlsym.rs @@ -31,7 +31,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx dlsym: Dlsym, abi: Abi, args: &[OpTy<'tcx, Tag>], - ret: Option<(PlaceTy<'tcx, Tag>, mir::BasicBlock)>, + ret: Option<(&PlaceTy<'tcx, Tag>, mir::BasicBlock)>, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); diff --git a/src/shims/posix/foreign_items.rs b/src/shims/posix/foreign_items.rs index e576c6f32e904..21b5ed62bbb51 100644 --- a/src/shims/posix/foreign_items.rs +++ b/src/shims/posix/foreign_items.rs @@ -17,7 +17,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx link_name: &str, abi: Abi, args: &[OpTy<'tcx, Tag>], - dest: PlaceTy<'tcx, Tag>, + dest: &PlaceTy<'tcx, Tag>, ret: mir::BasicBlock, ) -> InterpResult<'tcx, bool> { let this = self.eval_context_mut(); @@ -27,35 +27,35 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx match link_name { // Environment related shims "getenv" => { - let &[name] = check_arg_count(args)?; + let &[ref name] = check_arg_count(args)?; let result = this.getenv(name)?; this.write_scalar(result, dest)?; } "unsetenv" => { - let &[name] = check_arg_count(args)?; + let &[ref name] = check_arg_count(args)?; let result = this.unsetenv(name)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "setenv" => { - let &[name, value, overwrite] = check_arg_count(args)?; + let &[ref name, ref value, ref overwrite] = check_arg_count(args)?; this.read_scalar(overwrite)?.to_i32()?; let result = this.setenv(name, value)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "getcwd" => { - let &[buf, size] = check_arg_count(args)?; + let &[ref buf, ref size] = check_arg_count(args)?; let result = this.getcwd(buf, size)?; this.write_scalar(result, dest)?; } "chdir" => { - let &[path] = check_arg_count(args)?; + let &[ref path] = check_arg_count(args)?; let result = this.chdir(path)?; this.write_scalar(Scalar::from_i32(result), dest)?; } // File related shims "open" | "open64" => { - let &[path, flag, mode] = check_arg_count(args)?; + let &[ref path, ref flag, ref mode] = check_arg_count(args)?; let result = this.open(path, flag, mode)?; this.write_scalar(Scalar::from_i32(result), dest)?; } @@ -64,7 +64,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_i32(result), dest)?; } "read" => { - let &[fd, buf, count] = check_arg_count(args)?; + let &[ref fd, ref buf, ref count] = check_arg_count(args)?; let fd = this.read_scalar(fd)?.to_i32()?; let buf = this.read_scalar(buf)?.check_init()?; let count = this.read_scalar(count)?.to_machine_usize(this)?; @@ -72,7 +72,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_machine_isize(result, this), dest)?; } "write" => { - let &[fd, buf, n] = check_arg_count(args)?; + let &[ref fd, ref buf, ref n] = check_arg_count(args)?; let fd = this.read_scalar(fd)?.to_i32()?; let buf = this.read_scalar(buf)?.check_init()?; let count = this.read_scalar(n)?.to_machine_usize(this)?; @@ -82,60 +82,60 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_machine_isize(result, this), dest)?; } "unlink" => { - let &[path] = check_arg_count(args)?; + let &[ref path] = check_arg_count(args)?; let result = this.unlink(path)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "symlink" => { - let &[target, linkpath] = check_arg_count(args)?; + let &[ref target, ref linkpath] = check_arg_count(args)?; let result = this.symlink(target, linkpath)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "rename" => { - let &[oldpath, newpath] = check_arg_count(args)?; + let &[ref oldpath, ref newpath] = check_arg_count(args)?; let result = this.rename(oldpath, newpath)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "mkdir" => { - let &[path, mode] = check_arg_count(args)?; + let &[ref path, ref mode] = check_arg_count(args)?; let result = this.mkdir(path, mode)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "rmdir" => { - let &[path] = check_arg_count(args)?; + let &[ref path] = check_arg_count(args)?; let result = this.rmdir(path)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "closedir" => { - let &[dirp] = check_arg_count(args)?; + let &[ref dirp] = check_arg_count(args)?; let result = this.closedir(dirp)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "lseek" | "lseek64" => { - let &[fd, offset, whence] = check_arg_count(args)?; + let &[ref fd, ref offset, ref whence] = check_arg_count(args)?; let result = this.lseek64(fd, offset, whence)?; // "lseek" is only used on macOS which is 64bit-only, so `i64` always works. this.write_scalar(Scalar::from_i64(result), dest)?; } "fsync" => { - let &[fd] = check_arg_count(args)?; + let &[ref fd] = check_arg_count(args)?; let result = this.fsync(fd)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "fdatasync" => { - let &[fd] = check_arg_count(args)?; + let &[ref fd] = check_arg_count(args)?; let result = this.fdatasync(fd)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "readlink" => { - let &[pathname, buf, bufsize] = check_arg_count(args)?; + let &[ref pathname, ref buf, ref bufsize] = check_arg_count(args)?; let result = this.readlink(pathname, buf, bufsize)?; this.write_scalar(Scalar::from_machine_isize(result, this), dest)?; } // Allocation "posix_memalign" => { - let &[ret, align, size] = check_arg_count(args)?; + let &[ref ret, ref align, ref size] = check_arg_count(args)?; let ret = this.deref_operand(ret)?; let align = this.read_scalar(align)?.to_machine_usize(this)?; let size = this.read_scalar(size)?.to_machine_usize(this)?; @@ -151,21 +151,21 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } if size == 0 { - this.write_null(ret.into())?; + this.write_null(&ret.into())?; } else { let ptr = this.memory.allocate( Size::from_bytes(size), Align::from_bytes(align).unwrap(), MiriMemoryKind::C.into(), ); - this.write_scalar(ptr, ret.into())?; + this.write_scalar(ptr, &ret.into())?; } this.write_null(dest)?; } // Dynamic symbol loading "dlsym" => { - let &[handle, symbol] = check_arg_count(args)?; + let &[ref handle, ref symbol] = check_arg_count(args)?; this.read_scalar(handle)?.to_machine_usize(this)?; let symbol = this.read_scalar(symbol)?.check_init()?; let symbol_name = this.memory.read_c_str(symbol)?; @@ -179,7 +179,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Querying system information "sysconf" => { - let &[name] = check_arg_count(args)?; + let &[ref name] = check_arg_count(args)?; let name = this.read_scalar(name)?.to_i32()?; let sysconfs = &[ @@ -204,7 +204,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Thread-local storage "pthread_key_create" => { - let &[key, dtor] = check_arg_count(args)?; + let &[ref key, ref dtor] = check_arg_count(args)?; let key_place = this.deref_operand(key)?; let dtor = this.read_scalar(dtor)?.check_init()?; @@ -226,27 +226,27 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Create key and write it into the memory where `key_ptr` wants it. let key = this.machine.tls.create_tls_key(dtor, key_layout.size)?; - this.write_scalar(Scalar::from_uint(key, key_layout.size), key_place.into())?; + this.write_scalar(Scalar::from_uint(key, key_layout.size), &key_place.into())?; // Return success (`0`). this.write_null(dest)?; } "pthread_key_delete" => { - let &[key] = check_arg_count(args)?; + let &[ref key] = check_arg_count(args)?; let key = this.force_bits(this.read_scalar(key)?.check_init()?, key.layout.size)?; this.machine.tls.delete_tls_key(key)?; // Return success (0) this.write_null(dest)?; } "pthread_getspecific" => { - let &[key] = check_arg_count(args)?; + let &[ref key] = check_arg_count(args)?; let key = this.force_bits(this.read_scalar(key)?.check_init()?, key.layout.size)?; let active_thread = this.get_active_thread(); let ptr = this.machine.tls.load_tls(key, active_thread, this)?; this.write_scalar(ptr, dest)?; } "pthread_setspecific" => { - let &[key, new_ptr] = check_arg_count(args)?; + let &[ref key, ref new_ptr] = check_arg_count(args)?; let key = this.force_bits(this.read_scalar(key)?.check_init()?, key.layout.size)?; let active_thread = this.get_active_thread(); let new_ptr = this.read_scalar(new_ptr)?.check_init()?; @@ -258,128 +258,128 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Synchronization primitives "pthread_mutexattr_init" => { - let &[attr] = check_arg_count(args)?; + let &[ref attr] = check_arg_count(args)?; let result = this.pthread_mutexattr_init(attr)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_mutexattr_settype" => { - let &[attr, kind] = check_arg_count(args)?; + let &[ref attr, ref kind] = check_arg_count(args)?; let result = this.pthread_mutexattr_settype(attr, kind)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_mutexattr_destroy" => { - let &[attr] = check_arg_count(args)?; + let &[ref attr] = check_arg_count(args)?; let result = this.pthread_mutexattr_destroy(attr)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_mutex_init" => { - let &[mutex, attr] = check_arg_count(args)?; + let &[ref mutex, ref attr] = check_arg_count(args)?; let result = this.pthread_mutex_init(mutex, attr)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_mutex_lock" => { - let &[mutex] = check_arg_count(args)?; + let &[ref mutex] = check_arg_count(args)?; let result = this.pthread_mutex_lock(mutex)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_mutex_trylock" => { - let &[mutex] = check_arg_count(args)?; + let &[ref mutex] = check_arg_count(args)?; let result = this.pthread_mutex_trylock(mutex)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_mutex_unlock" => { - let &[mutex] = check_arg_count(args)?; + let &[ref mutex] = check_arg_count(args)?; let result = this.pthread_mutex_unlock(mutex)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_mutex_destroy" => { - let &[mutex] = check_arg_count(args)?; + let &[ref mutex] = check_arg_count(args)?; let result = this.pthread_mutex_destroy(mutex)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_rwlock_rdlock" => { - let &[rwlock] = check_arg_count(args)?; + let &[ref rwlock] = check_arg_count(args)?; let result = this.pthread_rwlock_rdlock(rwlock)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_rwlock_tryrdlock" => { - let &[rwlock] = check_arg_count(args)?; + let &[ref rwlock] = check_arg_count(args)?; let result = this.pthread_rwlock_tryrdlock(rwlock)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_rwlock_wrlock" => { - let &[rwlock] = check_arg_count(args)?; + let &[ref rwlock] = check_arg_count(args)?; let result = this.pthread_rwlock_wrlock(rwlock)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_rwlock_trywrlock" => { - let &[rwlock] = check_arg_count(args)?; + let &[ref rwlock] = check_arg_count(args)?; let result = this.pthread_rwlock_trywrlock(rwlock)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_rwlock_unlock" => { - let &[rwlock] = check_arg_count(args)?; + let &[ref rwlock] = check_arg_count(args)?; let result = this.pthread_rwlock_unlock(rwlock)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_rwlock_destroy" => { - let &[rwlock] = check_arg_count(args)?; + let &[ref rwlock] = check_arg_count(args)?; let result = this.pthread_rwlock_destroy(rwlock)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_condattr_init" => { - let &[attr] = check_arg_count(args)?; + let &[ref attr] = check_arg_count(args)?; let result = this.pthread_condattr_init(attr)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_condattr_destroy" => { - let &[attr] = check_arg_count(args)?; + let &[ref attr] = check_arg_count(args)?; let result = this.pthread_condattr_destroy(attr)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_cond_init" => { - let &[cond, attr] = check_arg_count(args)?; + let &[ref cond, ref attr] = check_arg_count(args)?; let result = this.pthread_cond_init(cond, attr)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_cond_signal" => { - let &[cond] = check_arg_count(args)?; + let &[ref cond] = check_arg_count(args)?; let result = this.pthread_cond_signal(cond)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_cond_broadcast" => { - let &[cond] = check_arg_count(args)?; + let &[ref cond] = check_arg_count(args)?; let result = this.pthread_cond_broadcast(cond)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_cond_wait" => { - let &[cond, mutex] = check_arg_count(args)?; + let &[ref cond, ref mutex] = check_arg_count(args)?; let result = this.pthread_cond_wait(cond, mutex)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_cond_timedwait" => { - let &[cond, mutex, abstime] = check_arg_count(args)?; + let &[ref cond, ref mutex, ref abstime] = check_arg_count(args)?; this.pthread_cond_timedwait(cond, mutex, abstime, dest)?; } "pthread_cond_destroy" => { - let &[cond] = check_arg_count(args)?; + let &[ref cond] = check_arg_count(args)?; let result = this.pthread_cond_destroy(cond)?; this.write_scalar(Scalar::from_i32(result), dest)?; } // Threading "pthread_create" => { - let &[thread, attr, start, arg] = check_arg_count(args)?; + let &[ref thread, ref attr, ref start, ref arg] = check_arg_count(args)?; let result = this.pthread_create(thread, attr, start, arg)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_join" => { - let &[thread, retval] = check_arg_count(args)?; + let &[ref thread, ref retval] = check_arg_count(args)?; let result = this.pthread_join(thread, retval)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_detach" => { - let &[thread] = check_arg_count(args)?; + let &[ref thread] = check_arg_count(args)?; let result = this.pthread_detach(thread)?; this.write_scalar(Scalar::from_i32(result), dest)?; } @@ -393,14 +393,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_i32(result), dest)?; } "nanosleep" => { - let &[req, rem] = check_arg_count(args)?; + let &[ref req, ref rem] = check_arg_count(args)?; let result = this.nanosleep(req, rem)?; this.write_scalar(Scalar::from_i32(result), dest)?; } // Miscellaneous "isatty" => { - let &[fd] = check_arg_count(args)?; + let &[ref fd] = check_arg_count(args)?; this.read_scalar(fd)?.to_i32()?; // "returns 1 if fd is an open file descriptor referring to a terminal; otherwise 0 is returned, and errno is set to indicate the error" // FIXME: we just say nothing is a terminal. @@ -409,7 +409,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_null(dest)?; } "pthread_atfork" => { - let &[prepare, parent, child] = check_arg_count(args)?; + let &[ref prepare, ref parent, ref child] = check_arg_count(args)?; this.force_bits(this.read_scalar(prepare)?.check_init()?, this.memory.pointer_size())?; this.force_bits(this.read_scalar(parent)?.check_init()?, this.memory.pointer_size())?; this.force_bits(this.read_scalar(child)?.check_init()?, this.memory.pointer_size())?; @@ -421,10 +421,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // These shims are enabled only when the caller is in the standard library. "pthread_attr_getguardsize" if this.frame().instance.to_string().starts_with("std::sys::unix::") => { - let &[_attr, guard_size] = check_arg_count(args)?; + let &[ref _attr, ref guard_size] = check_arg_count(args)?; let guard_size = this.deref_operand(guard_size)?; let guard_size_layout = this.libc_ty_layout("size_t")?; - this.write_scalar(Scalar::from_uint(crate::PAGE_SIZE, guard_size_layout.size), guard_size.into())?; + this.write_scalar(Scalar::from_uint(crate::PAGE_SIZE, guard_size_layout.size), &guard_size.into())?; // Return success (`0`). this.write_null(dest)?; diff --git a/src/shims/posix/fs.rs b/src/shims/posix/fs.rs index 10f0c91097922..2f1efee8c8937 100644 --- a/src/shims/posix/fs.rs +++ b/src/shims/posix/fs.rs @@ -237,8 +237,8 @@ trait EvalContextExtPrivate<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, ' fn macos_stat_or_lstat( &mut self, follow_symlink: bool, - path_op: OpTy<'tcx, Tag>, - buf_op: OpTy<'tcx, Tag>, + path_op: &OpTy<'tcx, Tag>, + buf_op: &OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); @@ -255,7 +255,7 @@ trait EvalContextExtPrivate<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, ' fn macos_stat_write_buf( &mut self, metadata: FileMetadata, - buf_op: OpTy<'tcx, Tag>, + buf_op: &OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); @@ -303,7 +303,7 @@ trait EvalContextExtPrivate<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, ' ]; let buf = this.deref_operand(buf_op)?; - this.write_packed_immediates(buf, &imms)?; + this.write_packed_immediates(&buf, &imms)?; Ok(0) } @@ -412,9 +412,9 @@ impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mi pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { fn open( &mut self, - path_op: OpTy<'tcx, Tag>, - flag_op: OpTy<'tcx, Tag>, - mode_op: OpTy<'tcx, Tag>, + path_op: &OpTy<'tcx, Tag>, + flag_op: &OpTy<'tcx, Tag>, + mode_op: &OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); @@ -516,8 +516,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if args.len() < 2 { throw_ub_format!("incorrect number of arguments for fcntl: got {}, expected at least 2", args.len()); } - let fd = this.read_scalar(args[0])?.to_i32()?; - let cmd = this.read_scalar(args[1])?.to_i32()?; + let fd = this.read_scalar(&args[0])?.to_i32()?; + let cmd = this.read_scalar(&args[1])?.to_i32()?; // We only support getting the flags for a descriptor. if cmd == this.eval_libc_i32("F_GETFD")? { // Currently this is the only flag that `F_GETFD` returns. It is OK to just return the @@ -537,7 +537,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // because exec() isn't supported. The F_DUPFD and F_DUPFD_CLOEXEC commands only // differ in whether the FD_CLOEXEC flag is pre-set on the new file descriptor, // thus they can share the same implementation here. - let &[_, _, start] = check_arg_count(args)?; + let &[_, _, ref start] = check_arg_count(args)?; let start = this.read_scalar(start)?.to_i32()?; let fh = &mut this.machine.file_handler; @@ -572,7 +572,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } - fn close(&mut self, fd_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + fn close(&mut self, fd_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); let fd = this.read_scalar(fd_op)?.to_i32()?; @@ -671,9 +671,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn lseek64( &mut self, - fd_op: OpTy<'tcx, Tag>, - offset_op: OpTy<'tcx, Tag>, - whence_op: OpTy<'tcx, Tag>, + fd_op: &OpTy<'tcx, Tag>, + offset_op: &OpTy<'tcx, Tag>, + whence_op: &OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, i64> { let this = self.eval_context_mut(); @@ -705,7 +705,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } - fn unlink(&mut self, path_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + fn unlink(&mut self, path_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); this.check_no_isolation("`unlink`")?; @@ -718,8 +718,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn symlink( &mut self, - target_op: OpTy<'tcx, Tag>, - linkpath_op: OpTy<'tcx, Tag> + target_op: &OpTy<'tcx, Tag>, + linkpath_op: &OpTy<'tcx, Tag> ) -> InterpResult<'tcx, i32> { #[cfg(unix)] fn create_link(src: &Path, dst: &Path) -> std::io::Result<()> { @@ -749,8 +749,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn macos_stat( &mut self, - path_op: OpTy<'tcx, Tag>, - buf_op: OpTy<'tcx, Tag>, + path_op: &OpTy<'tcx, Tag>, + buf_op: &OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); this.assert_target_os("macos", "stat"); @@ -762,8 +762,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // `lstat` is used to get symlink metadata. fn macos_lstat( &mut self, - path_op: OpTy<'tcx, Tag>, - buf_op: OpTy<'tcx, Tag>, + path_op: &OpTy<'tcx, Tag>, + buf_op: &OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); this.assert_target_os("macos", "lstat"); @@ -773,8 +773,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn macos_fstat( &mut self, - fd_op: OpTy<'tcx, Tag>, - buf_op: OpTy<'tcx, Tag>, + fd_op: &OpTy<'tcx, Tag>, + buf_op: &OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); @@ -792,11 +792,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn linux_statx( &mut self, - dirfd_op: OpTy<'tcx, Tag>, // Should be an `int` - pathname_op: OpTy<'tcx, Tag>, // Should be a `const char *` - flags_op: OpTy<'tcx, Tag>, // Should be an `int` - _mask_op: OpTy<'tcx, Tag>, // Should be an `unsigned int` - statxbuf_op: OpTy<'tcx, Tag>, // Should be a `struct statx *` + dirfd_op: &OpTy<'tcx, Tag>, // Should be an `int` + pathname_op: &OpTy<'tcx, Tag>, // Should be a `const char *` + flags_op: &OpTy<'tcx, Tag>, // Should be an `int` + _mask_op: &OpTy<'tcx, Tag>, // Should be an `unsigned int` + statxbuf_op: &OpTy<'tcx, Tag>, // Should be a `struct statx *` ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); @@ -827,7 +827,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let statxbuf_ty = this.tcx.mk_mut_ptr(statx_ty); let statxbuf_layout = this.layout_of(statxbuf_ty)?; let statxbuf_imm = ImmTy::from_scalar(statxbuf_scalar, statxbuf_layout); - this.ref_to_mplace(statxbuf_imm)? + this.ref_to_mplace(&statxbuf_imm)? }; let path = this.read_path_from_c_str(pathname_scalar)?.into_owned(); @@ -941,15 +941,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx immty_from_uint_checked(0u128, __u64_layout)?, // stx_dev_minor ]; - this.write_packed_immediates(statxbuf_place, &imms)?; + this.write_packed_immediates(&statxbuf_place, &imms)?; Ok(0) } fn rename( &mut self, - oldpath_op: OpTy<'tcx, Tag>, - newpath_op: OpTy<'tcx, Tag>, + oldpath_op: &OpTy<'tcx, Tag>, + newpath_op: &OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); @@ -974,8 +974,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn mkdir( &mut self, - path_op: OpTy<'tcx, Tag>, - mode_op: OpTy<'tcx, Tag>, + path_op: &OpTy<'tcx, Tag>, + mode_op: &OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); @@ -1008,7 +1008,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn rmdir( &mut self, - path_op: OpTy<'tcx, Tag>, + path_op: &OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); @@ -1021,7 +1021,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.try_unwrap_io_result(result) } - fn opendir(&mut self, name_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, Scalar> { + fn opendir(&mut self, name_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); this.check_no_isolation("`opendir`")?; @@ -1048,9 +1048,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn linux_readdir64_r( &mut self, - dirp_op: OpTy<'tcx, Tag>, - entry_op: OpTy<'tcx, Tag>, - result_op: OpTy<'tcx, Tag>, + dirp_op: &OpTy<'tcx, Tag>, + entry_op: &OpTy<'tcx, Tag>, + result_op: &OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); @@ -1078,7 +1078,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // } let entry_place = this.deref_operand(entry_op)?; - let name_place = this.mplace_field(entry_place, 4)?; + let name_place = this.mplace_field(&entry_place, 4)?; let file_name = dir_entry.file_name(); // not a Path as there are no separators! let (name_fits, _) = this.write_os_str_to_c_str( @@ -1111,16 +1111,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx immty_from_uint_checked(0u128, c_ushort_layout)?, // d_reclen immty_from_int_checked(file_type, c_uchar_layout)?, // d_type ]; - this.write_packed_immediates(entry_place, &imms)?; + this.write_packed_immediates(&entry_place, &imms)?; let result_place = this.deref_operand(result_op)?; - this.write_scalar(this.read_scalar(entry_op)?, result_place.into())?; + this.write_scalar(this.read_scalar(entry_op)?, &result_place.into())?; Ok(0) } None => { // end of stream: return 0, assign *result=NULL - this.write_null(this.deref_operand(result_op)?.into())?; + this.write_null(&this.deref_operand(result_op)?.into())?; Ok(0) } Some(Err(e)) => match e.raw_os_error() { @@ -1135,9 +1135,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn macos_readdir_r( &mut self, - dirp_op: OpTy<'tcx, Tag>, - entry_op: OpTy<'tcx, Tag>, - result_op: OpTy<'tcx, Tag>, + dirp_op: &OpTy<'tcx, Tag>, + entry_op: &OpTy<'tcx, Tag>, + result_op: &OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); @@ -1166,7 +1166,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // } let entry_place = this.deref_operand(entry_op)?; - let name_place = this.mplace_field(entry_place, 5)?; + let name_place = this.mplace_field(&entry_place, 5)?; let file_name = dir_entry.file_name(); // not a Path as there are no separators! let (name_fits, file_name_len) = this.write_os_str_to_c_str( @@ -1200,16 +1200,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx immty_from_uint_checked(file_name_len, c_ushort_layout)?, // d_namlen immty_from_int_checked(file_type, c_uchar_layout)?, // d_type ]; - this.write_packed_immediates(entry_place, &imms)?; + this.write_packed_immediates(&entry_place, &imms)?; let result_place = this.deref_operand(result_op)?; - this.write_scalar(this.read_scalar(entry_op)?, result_place.into())?; + this.write_scalar(this.read_scalar(entry_op)?, &result_place.into())?; Ok(0) } None => { // end of stream: return 0, assign *result=NULL - this.write_null(this.deref_operand(result_op)?.into())?; + this.write_null(&this.deref_operand(result_op)?.into())?; Ok(0) } Some(Err(e)) => match e.raw_os_error() { @@ -1222,7 +1222,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } - fn closedir(&mut self, dirp_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + fn closedir(&mut self, dirp_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); this.check_no_isolation("`closedir`")?; @@ -1239,8 +1239,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn ftruncate64( &mut self, - fd_op: OpTy<'tcx, Tag>, - length_op: OpTy<'tcx, Tag>, + fd_op: &OpTy<'tcx, Tag>, + length_op: &OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); @@ -1271,7 +1271,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } - fn fsync(&mut self, fd_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + fn fsync(&mut self, fd_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { // On macOS, `fsync` (unlike `fcntl(F_FULLFSYNC)`) does not wait for the // underlying disk to finish writing. In the interest of host compatibility, // we conservatively implement this with `sync_all`, which @@ -1292,7 +1292,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } - fn fdatasync(&mut self, fd_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + fn fdatasync(&mut self, fd_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); this.check_no_isolation("`fdatasync`")?; @@ -1310,10 +1310,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn sync_file_range( &mut self, - fd_op: OpTy<'tcx, Tag>, - offset_op: OpTy<'tcx, Tag>, - nbytes_op: OpTy<'tcx, Tag>, - flags_op: OpTy<'tcx, Tag>, + fd_op: &OpTy<'tcx, Tag>, + offset_op: &OpTy<'tcx, Tag>, + nbytes_op: &OpTy<'tcx, Tag>, + flags_op: &OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); @@ -1350,9 +1350,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn readlink( &mut self, - pathname_op: OpTy<'tcx, Tag>, - buf_op: OpTy<'tcx, Tag>, - bufsize_op: OpTy<'tcx, Tag> + pathname_op: &OpTy<'tcx, Tag>, + buf_op: &OpTy<'tcx, Tag>, + bufsize_op: &OpTy<'tcx, Tag> ) -> InterpResult<'tcx, i64> { let this = self.eval_context_mut(); diff --git a/src/shims/posix/linux/dlsym.rs b/src/shims/posix/linux/dlsym.rs index 2685a93726d8f..e7ffb68ff2ec0 100644 --- a/src/shims/posix/linux/dlsym.rs +++ b/src/shims/posix/linux/dlsym.rs @@ -25,7 +25,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx &mut self, dlsym: Dlsym, _args: &[OpTy<'tcx, Tag>], - ret: Option<(PlaceTy<'tcx, Tag>, mir::BasicBlock)>, + ret: Option<(&PlaceTy<'tcx, Tag>, mir::BasicBlock)>, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let (_dest, _ret) = ret.expect("we don't support any diverging dlsym"); diff --git a/src/shims/posix/linux/foreign_items.rs b/src/shims/posix/linux/foreign_items.rs index 45afbd05efc25..2a3b512bcdb95 100644 --- a/src/shims/posix/linux/foreign_items.rs +++ b/src/shims/posix/linux/foreign_items.rs @@ -13,7 +13,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx &mut self, link_name: &str, args: &[OpTy<'tcx, Tag>], - dest: PlaceTy<'tcx, Tag>, + dest: &PlaceTy<'tcx, Tag>, _ret: mir::BasicBlock, ) -> InterpResult<'tcx, bool> { let this = self.eval_context_mut(); @@ -30,28 +30,28 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // These symbols have different names on Linux and macOS, which is the only reason they are not // in the `posix` module. "close" => { - let &[fd] = check_arg_count(args)?; + let &[ref fd] = check_arg_count(args)?; let result = this.close(fd)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "opendir" => { - let &[name] = check_arg_count(args)?; + let &[ref name] = check_arg_count(args)?; let result = this.opendir(name)?; this.write_scalar(result, dest)?; } "readdir64_r" => { - let &[dirp, entry, result] = check_arg_count(args)?; + let &[ref dirp, ref entry, ref result] = check_arg_count(args)?; let result = this.linux_readdir64_r(dirp, entry, result)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "ftruncate64" => { - let &[fd, length] = check_arg_count(args)?; + let &[ref fd, ref length] = check_arg_count(args)?; let result = this.ftruncate64(fd, length)?; this.write_scalar(Scalar::from_i32(result), dest)?; } // Linux-only "posix_fadvise" => { - let &[fd, offset, len, advice] = check_arg_count(args)?; + let &[ref fd, ref offset, ref len, ref advice] = check_arg_count(args)?; this.read_scalar(fd)?.to_i32()?; this.read_scalar(offset)?.to_machine_isize(this)?; this.read_scalar(len)?.to_machine_isize(this)?; @@ -60,7 +60,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_null(dest)?; } "sync_file_range" => { - let &[fd, offset, nbytes, flags] = check_arg_count(args)?; + let &[ref fd, ref offset, ref nbytes, ref flags] = check_arg_count(args)?; let result = this.sync_file_range(fd, offset, nbytes, flags)?; this.write_scalar(Scalar::from_i32(result), dest)?; } @@ -68,7 +68,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Time related shims "clock_gettime" => { // This is a POSIX function but it has only been tested on linux. - let &[clk_id, tp] = check_arg_count(args)?; + let &[ref clk_id, ref tp] = check_arg_count(args)?; let result = this.clock_gettime(clk_id, tp)?; this.write_scalar(Scalar::from_i32(result), dest)?; } @@ -76,18 +76,18 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Querying system information "pthread_attr_getstack" => { // We don't support "pthread_attr_setstack", so we just pretend all stacks have the same values here. - let &[attr_place, addr_place, size_place] = check_arg_count(args)?; + let &[ref attr_place, ref addr_place, ref size_place] = check_arg_count(args)?; this.deref_operand(attr_place)?; let addr_place = this.deref_operand(addr_place)?; let size_place = this.deref_operand(size_place)?; this.write_scalar( Scalar::from_uint(STACK_ADDR, this.pointer_size()), - addr_place.into(), + &addr_place.into(), )?; this.write_scalar( Scalar::from_uint(STACK_SIZE, this.pointer_size()), - size_place.into(), + &size_place.into(), )?; // Return success (`0`). @@ -96,17 +96,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Threading "prctl" => { - let &[option, arg2, arg3, arg4, arg5] = check_arg_count(args)?; + let &[ref option, ref arg2, ref arg3, ref arg4, ref arg5] = check_arg_count(args)?; let result = this.prctl(option, arg2, arg3, arg4, arg5)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_condattr_setclock" => { - let &[attr, clock_id] = check_arg_count(args)?; + let &[ref attr, ref clock_id] = check_arg_count(args)?; let result = this.pthread_condattr_setclock(attr, clock_id)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_condattr_getclock" => { - let &[attr, clock_id] = check_arg_count(args)?; + let &[ref attr, ref clock_id] = check_arg_count(args)?; let result = this.pthread_condattr_getclock(attr, clock_id)?; this.write_scalar(Scalar::from_i32(result), dest)?; } @@ -137,7 +137,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if args.is_empty() { throw_ub_format!("incorrect number of arguments for syscall: got 0, expected at least 1"); } - match this.read_scalar(args[0])?.to_machine_usize(this)? { + match this.read_scalar(&args[0])?.to_machine_usize(this)? { // `libc::syscall(NR_GETRANDOM, buf.as_mut_ptr(), buf.len(), GRND_NONBLOCK)` // is called if a `HashMap` is created the regular way (e.g. HashMap). id if id == sys_getrandom => { @@ -145,7 +145,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if args.len() < 4 { throw_ub_format!("incorrect number of arguments for `getrandom` syscall: got {}, expected at least 4", args.len()); } - getrandom(this, args[1], args[2], args[3], dest)?; + getrandom(this, &args[1], &args[2], &args[3], dest)?; } // `statx` is used by `libstd` to retrieve metadata information on `linux` // instead of using `stat`,`lstat` or `fstat` as on `macos`. @@ -154,7 +154,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if args.len() < 6 { throw_ub_format!("incorrect number of arguments for `statx` syscall: got {}, expected at least 6", args.len()); } - let result = this.linux_statx(args[1], args[2], args[3], args[4], args[5])?; + let result = this.linux_statx(&args[1], &args[2], &args[3], &args[4], &args[5])?; this.write_scalar(Scalar::from_machine_isize(result.into(), this), dest)?; } // `futex` is used by some synchonization primitives. @@ -167,11 +167,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Miscelanneous "getrandom" => { - let &[ptr, len, flags] = check_arg_count(args)?; + let &[ref ptr, ref len, ref flags] = check_arg_count(args)?; getrandom(this, ptr, len, flags, dest)?; } "sched_getaffinity" => { - let &[pid, cpusetsize, mask] = check_arg_count(args)?; + let &[ref pid, ref cpusetsize, ref mask] = check_arg_count(args)?; this.read_scalar(pid)?.to_i32()?; this.read_scalar(cpusetsize)?.to_machine_usize(this)?; this.deref_operand(mask)?; @@ -184,7 +184,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Incomplete shims that we "stub out" just to get pre-main initialization code to work. // These shims are enabled only when the caller is in the standard library. "pthread_getattr_np" if this.frame().instance.to_string().starts_with("std::sys::unix::") => { - let &[_thread, _attr] = check_arg_count(args)?; + let &[ref _thread, ref _attr] = check_arg_count(args)?; this.write_null(dest)?; } @@ -198,10 +198,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Shims the linux `getrandom` syscall. fn getrandom<'tcx>( this: &mut MiriEvalContext<'_, 'tcx>, - ptr: OpTy<'tcx, Tag>, - len: OpTy<'tcx, Tag>, - flags: OpTy<'tcx, Tag>, - dest: PlaceTy<'tcx, Tag>, + ptr: &OpTy<'tcx, Tag>, + len: &OpTy<'tcx, Tag>, + flags: &OpTy<'tcx, Tag>, + dest: &PlaceTy<'tcx, Tag>, ) -> InterpResult<'tcx> { let ptr = this.read_scalar(ptr)?.check_init()?; let len = this.read_scalar(len)?.to_machine_usize(this)?; diff --git a/src/shims/posix/linux/sync.rs b/src/shims/posix/linux/sync.rs index 5243431194eba..fdd11fd73e408 100644 --- a/src/shims/posix/linux/sync.rs +++ b/src/shims/posix/linux/sync.rs @@ -7,7 +7,7 @@ use std::time::{Instant, SystemTime}; pub fn futex<'tcx>( this: &mut MiriEvalContext<'_, 'tcx>, args: &[OpTy<'tcx, Tag>], - dest: PlaceTy<'tcx, Tag>, + dest: &PlaceTy<'tcx, Tag>, ) -> InterpResult<'tcx> { // The amount of arguments used depends on the type of futex operation. // The full futex syscall takes six arguments (excluding the syscall @@ -24,9 +24,9 @@ pub fn futex<'tcx>( // The first three arguments (after the syscall number itself) are the same to all futex operations: // (int *addr, int op, int val). // We checked above that these definitely exist. - let addr = this.read_immediate(args[1])?; - let op = this.read_scalar(args[2])?.to_i32()?; - let val = this.read_scalar(args[3])?.to_i32()?; + let addr = this.read_immediate(&args[1])?; + let op = this.read_scalar(&args[2])?.to_i32()?; + let val = this.read_scalar(&args[3])?.to_i32()?; // The raw pointer value is used to identify the mutex. // Not all mutex operations actually read from this address or even require this address to exist. @@ -51,7 +51,7 @@ pub fn futex<'tcx>( if args.len() < 5 { throw_ub_format!("incorrect number of arguments for `futex` syscall with `op=FUTEX_WAIT`: got {}, expected at least 5", args.len()); } - let timeout = args[4]; + let timeout = &args[4]; let timeout_time = if this.is_null(this.read_scalar(timeout)?.check_init()?)? { None } else { @@ -88,7 +88,7 @@ pub fn futex<'tcx>( // SeqCst is total order over all operations. // FIXME: check if this should be changed when weak memory orders are added. let futex_val = this.read_scalar_at_offset_atomic( - addr.into(), 0, this.machine.layouts.i32, AtomicReadOp::SeqCst + &addr.into(), 0, this.machine.layouts.i32, AtomicReadOp::SeqCst )?.to_i32()?; if val == futex_val { // The value still matches, so we block the trait make it wait for FUTEX_WAKE. @@ -98,6 +98,7 @@ pub fn futex<'tcx>( this.write_scalar(Scalar::from_machine_isize(0, this), dest)?; // Register a timeout callback if a timeout was specified. // This callback will override the return value when the timeout triggers. + let dest = *dest; if let Some(timeout_time) = timeout_time { this.register_timeout_callback( thread, @@ -107,7 +108,7 @@ pub fn futex<'tcx>( this.futex_remove_waiter(futex_ptr, thread); let etimedout = this.eval_libc("ETIMEDOUT")?; this.set_last_error(etimedout)?; - this.write_scalar(Scalar::from_machine_isize(-1, this), dest)?; + this.write_scalar(Scalar::from_machine_isize(-1, this), &dest)?; Ok(()) }), ); diff --git a/src/shims/posix/macos/dlsym.rs b/src/shims/posix/macos/dlsym.rs index 5b59cf27ee3be..7f3958797449c 100644 --- a/src/shims/posix/macos/dlsym.rs +++ b/src/shims/posix/macos/dlsym.rs @@ -28,7 +28,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx &mut self, dlsym: Dlsym, args: &[OpTy<'tcx, Tag>], - ret: Option<(PlaceTy<'tcx, Tag>, mir::BasicBlock)>, + ret: Option<(&PlaceTy<'tcx, Tag>, mir::BasicBlock)>, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let (dest, ret) = ret.expect("we don't support any diverging dlsym"); @@ -36,7 +36,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx match dlsym { Dlsym::getentropy => { - let &[ptr, len] = check_arg_count(args)?; + let &[ref ptr, ref len] = check_arg_count(args)?; let ptr = this.read_scalar(ptr)?.check_init()?; let len = this.read_scalar(len)?.to_machine_usize(this)?; this.gen_random(ptr, len)?; @@ -44,7 +44,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } - trace!("{:?}", this.dump_place(*dest)); + trace!("{:?}", this.dump_place(**dest)); this.go_to_block(ret); Ok(()) } diff --git a/src/shims/posix/macos/foreign_items.rs b/src/shims/posix/macos/foreign_items.rs index a4b0ce524df24..1ea12148303e2 100644 --- a/src/shims/posix/macos/foreign_items.rs +++ b/src/shims/posix/macos/foreign_items.rs @@ -11,7 +11,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx &mut self, link_name: &str, args: &[OpTy<'tcx, Tag>], - dest: PlaceTy<'tcx, Tag>, + dest: &PlaceTy<'tcx, Tag>, _ret: mir::BasicBlock, ) -> InterpResult<'tcx, bool> { let this = self.eval_context_mut(); @@ -26,37 +26,37 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // File related shims "close" | "close$NOCANCEL" => { - let &[result] = check_arg_count(args)?; + let &[ref result] = check_arg_count(args)?; let result = this.close(result)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "stat" | "stat$INODE64" => { - let &[path, buf] = check_arg_count(args)?; + let &[ref path, ref buf] = check_arg_count(args)?; let result = this.macos_stat(path, buf)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "lstat" | "lstat$INODE64" => { - let &[path, buf] = check_arg_count(args)?; + let &[ref path, ref buf] = check_arg_count(args)?; let result = this.macos_lstat(path, buf)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "fstat" | "fstat$INODE64" => { - let &[fd, buf] = check_arg_count(args)?; + let &[ref fd, ref buf] = check_arg_count(args)?; let result = this.macos_fstat(fd, buf)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "opendir" | "opendir$INODE64" => { - let &[name] = check_arg_count(args)?; + let &[ref name] = check_arg_count(args)?; let result = this.opendir(name)?; this.write_scalar(result, dest)?; } "readdir_r" | "readdir_r$INODE64" => { - let &[dirp, entry, result] = check_arg_count(args)?; + let &[ref dirp, ref entry, ref result] = check_arg_count(args)?; let result = this.macos_readdir_r(dirp, entry, result)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "ftruncate" => { - let &[fd, length] = check_arg_count(args)?; + let &[ref fd, ref length] = check_arg_count(args)?; let result = this.ftruncate64(fd, length)?; this.write_scalar(Scalar::from_i32(result), dest)?; } @@ -69,7 +69,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Time related shims "gettimeofday" => { - let &[tv, tz] = check_arg_count(args)?; + let &[ref tv, ref tz] = check_arg_count(args)?; let result = this.gettimeofday(tv, tz)?; this.write_scalar(Scalar::from_i32(result), dest)?; } @@ -80,7 +80,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "mach_timebase_info" => { - let &[info] = check_arg_count(args)?; + let &[ref info] = check_arg_count(args)?; let result = this.mach_timebase_info(info)?; this.write_scalar(Scalar::from_i32(result), dest)?; }, @@ -97,7 +97,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Thread-local storage "_tlv_atexit" => { - let &[dtor, data] = check_arg_count(args)?; + let &[ref dtor, ref data] = check_arg_count(args)?; let dtor = this.read_scalar(dtor)?.check_init()?; let dtor = this.memory.get_fn(dtor)?.as_instance()?; let data = this.read_scalar(data)?.check_init()?; @@ -107,13 +107,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Querying system information "pthread_get_stackaddr_np" => { - let &[thread] = check_arg_count(args)?; + let &[ref thread] = check_arg_count(args)?; this.read_scalar(thread)?.to_machine_usize(this)?; let stack_addr = Scalar::from_uint(STACK_ADDR, this.pointer_size()); this.write_scalar(stack_addr, dest)?; } "pthread_get_stacksize_np" => { - let &[thread] = check_arg_count(args)?; + let &[ref thread] = check_arg_count(args)?; this.read_scalar(thread)?.to_machine_usize(this)?; let stack_size = Scalar::from_uint(STACK_SIZE, this.pointer_size()); this.write_scalar(stack_size, dest)?; @@ -121,7 +121,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Threading "pthread_setname_np" => { - let &[name] = check_arg_count(args)?; + let &[ref name] = check_arg_count(args)?; let name = this.read_scalar(name)?.check_init()?; this.pthread_setname_np(name)?; } @@ -130,7 +130,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // These shims are enabled only when the caller is in the standard library. "mmap" if this.frame().instance.to_string().starts_with("std::sys::unix::") => { // This is a horrible hack, but since the guard page mechanism calls mmap and expects a particular return value, we just give it that value. - let &[addr, _, _, _, _, _] = check_arg_count(args)?; + let &[ref addr, _, _, _, _, _] = check_arg_count(args)?; let addr = this.read_scalar(addr)?.check_init()?; this.write_scalar(addr, dest)?; } diff --git a/src/shims/posix/sync.rs b/src/shims/posix/sync.rs index 868c72289a1a0..0688614a383d6 100644 --- a/src/shims/posix/sync.rs +++ b/src/shims/posix/sync.rs @@ -35,14 +35,14 @@ fn is_mutex_kind_normal<'mir, 'tcx: 'mir>( fn mutexattr_get_kind<'mir, 'tcx: 'mir>( ecx: &MiriEvalContext<'mir, 'tcx>, - attr_op: OpTy<'tcx, Tag>, + attr_op: &OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, ScalarMaybeUninit> { ecx.read_scalar_at_offset(attr_op, 0, ecx.machine.layouts.i32) } fn mutexattr_set_kind<'mir, 'tcx: 'mir>( ecx: &mut MiriEvalContext<'mir, 'tcx>, - attr_op: OpTy<'tcx, Tag>, + attr_op: &OpTy<'tcx, Tag>, kind: impl Into>, ) -> InterpResult<'tcx, ()> { ecx.write_scalar_at_offset(attr_op, 0, kind, ecx.machine.layouts.i32) @@ -59,7 +59,7 @@ fn mutexattr_set_kind<'mir, 'tcx: 'mir>( fn mutex_get_kind<'mir, 'tcx: 'mir>( ecx: &mut MiriEvalContext<'mir, 'tcx>, - mutex_op: OpTy<'tcx, Tag>, + mutex_op: &OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, ScalarMaybeUninit> { let offset = if ecx.pointer_size().bytes() == 8 { 16 } else { 12 }; ecx.read_scalar_at_offset_atomic( @@ -70,7 +70,7 @@ fn mutex_get_kind<'mir, 'tcx: 'mir>( fn mutex_set_kind<'mir, 'tcx: 'mir>( ecx: &mut MiriEvalContext<'mir, 'tcx>, - mutex_op: OpTy<'tcx, Tag>, + mutex_op: &OpTy<'tcx, Tag>, kind: impl Into>, ) -> InterpResult<'tcx, ()> { let offset = if ecx.pointer_size().bytes() == 8 { 16 } else { 12 }; @@ -82,7 +82,7 @@ fn mutex_set_kind<'mir, 'tcx: 'mir>( fn mutex_get_id<'mir, 'tcx: 'mir>( ecx: &MiriEvalContext<'mir, 'tcx>, - mutex_op: OpTy<'tcx, Tag>, + mutex_op: &OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, ScalarMaybeUninit> { ecx.read_scalar_at_offset_atomic( mutex_op, 4, ecx.machine.layouts.u32, @@ -92,7 +92,7 @@ fn mutex_get_id<'mir, 'tcx: 'mir>( fn mutex_set_id<'mir, 'tcx: 'mir>( ecx: &mut MiriEvalContext<'mir, 'tcx>, - mutex_op: OpTy<'tcx, Tag>, + mutex_op: &OpTy<'tcx, Tag>, id: impl Into>, ) -> InterpResult<'tcx, ()> { ecx.write_scalar_at_offset_atomic( @@ -103,7 +103,7 @@ fn mutex_set_id<'mir, 'tcx: 'mir>( fn mutex_get_or_create_id<'mir, 'tcx: 'mir>( ecx: &mut MiriEvalContext<'mir, 'tcx>, - mutex_op: OpTy<'tcx, Tag>, + mutex_op: &OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, MutexId> { let id = mutex_get_id(ecx, mutex_op)?.to_u32()?; if id == 0 { @@ -126,7 +126,7 @@ fn mutex_get_or_create_id<'mir, 'tcx: 'mir>( fn rwlock_get_id<'mir, 'tcx: 'mir>( ecx: &MiriEvalContext<'mir, 'tcx>, - rwlock_op: OpTy<'tcx, Tag>, + rwlock_op: &OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, ScalarMaybeUninit> { ecx.read_scalar_at_offset_atomic( rwlock_op, 4, ecx.machine.layouts.u32, @@ -136,7 +136,7 @@ fn rwlock_get_id<'mir, 'tcx: 'mir>( fn rwlock_set_id<'mir, 'tcx: 'mir>( ecx: &mut MiriEvalContext<'mir, 'tcx>, - rwlock_op: OpTy<'tcx, Tag>, + rwlock_op: &OpTy<'tcx, Tag>, id: impl Into>, ) -> InterpResult<'tcx, ()> { ecx.write_scalar_at_offset_atomic( @@ -147,7 +147,7 @@ fn rwlock_set_id<'mir, 'tcx: 'mir>( fn rwlock_get_or_create_id<'mir, 'tcx: 'mir>( ecx: &mut MiriEvalContext<'mir, 'tcx>, - rwlock_op: OpTy<'tcx, Tag>, + rwlock_op: &OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, RwLockId> { let id = rwlock_get_id(ecx, rwlock_op)?.to_u32()?; if id == 0 { @@ -169,14 +169,14 @@ fn rwlock_get_or_create_id<'mir, 'tcx: 'mir>( fn condattr_get_clock_id<'mir, 'tcx: 'mir>( ecx: &MiriEvalContext<'mir, 'tcx>, - attr_op: OpTy<'tcx, Tag>, + attr_op: &OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, ScalarMaybeUninit> { ecx.read_scalar_at_offset(attr_op, 0, ecx.machine.layouts.i32) } fn condattr_set_clock_id<'mir, 'tcx: 'mir>( ecx: &mut MiriEvalContext<'mir, 'tcx>, - attr_op: OpTy<'tcx, Tag>, + attr_op: &OpTy<'tcx, Tag>, clock_id: impl Into>, ) -> InterpResult<'tcx, ()> { ecx.write_scalar_at_offset(attr_op, 0, clock_id, ecx.machine.layouts.i32) @@ -193,7 +193,7 @@ fn condattr_set_clock_id<'mir, 'tcx: 'mir>( fn cond_get_id<'mir, 'tcx: 'mir>( ecx: &MiriEvalContext<'mir, 'tcx>, - cond_op: OpTy<'tcx, Tag>, + cond_op: &OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, ScalarMaybeUninit> { ecx.read_scalar_at_offset_atomic( cond_op, 4, ecx.machine.layouts.u32, @@ -203,7 +203,7 @@ fn cond_get_id<'mir, 'tcx: 'mir>( fn cond_set_id<'mir, 'tcx: 'mir>( ecx: &mut MiriEvalContext<'mir, 'tcx>, - cond_op: OpTy<'tcx, Tag>, + cond_op: &OpTy<'tcx, Tag>, id: impl Into>, ) -> InterpResult<'tcx, ()> { ecx.write_scalar_at_offset_atomic( @@ -214,7 +214,7 @@ fn cond_set_id<'mir, 'tcx: 'mir>( fn cond_get_or_create_id<'mir, 'tcx: 'mir>( ecx: &mut MiriEvalContext<'mir, 'tcx>, - cond_op: OpTy<'tcx, Tag>, + cond_op: &OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, CondvarId> { let id = cond_get_id(ecx, cond_op)?.to_u32()?; if id == 0 { @@ -230,14 +230,14 @@ fn cond_get_or_create_id<'mir, 'tcx: 'mir>( fn cond_get_clock_id<'mir, 'tcx: 'mir>( ecx: &MiriEvalContext<'mir, 'tcx>, - cond_op: OpTy<'tcx, Tag>, + cond_op: &OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, ScalarMaybeUninit> { ecx.read_scalar_at_offset(cond_op, 8, ecx.machine.layouts.i32) } fn cond_set_clock_id<'mir, 'tcx: 'mir>( ecx: &mut MiriEvalContext<'mir, 'tcx>, - cond_op: OpTy<'tcx, Tag>, + cond_op: &OpTy<'tcx, Tag>, clock_id: impl Into>, ) -> InterpResult<'tcx, ()> { ecx.write_scalar_at_offset(cond_op, 8, clock_id, ecx.machine.layouts.i32) @@ -294,7 +294,7 @@ fn release_cond_mutex_and_block<'mir, 'tcx: 'mir>( impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { - fn pthread_mutexattr_init(&mut self, attr_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + fn pthread_mutexattr_init(&mut self, attr_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); let default_kind = this.eval_libc("PTHREAD_MUTEX_DEFAULT")?; @@ -305,8 +305,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn pthread_mutexattr_settype( &mut self, - attr_op: OpTy<'tcx, Tag>, - kind_op: OpTy<'tcx, Tag>, + attr_op: &OpTy<'tcx, Tag>, + kind_op: &OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); @@ -344,7 +344,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(0) } - fn pthread_mutexattr_destroy(&mut self, attr_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + fn pthread_mutexattr_destroy(&mut self, attr_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); mutexattr_set_kind(this, attr_op, ScalarMaybeUninit::Uninit)?; @@ -354,8 +354,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn pthread_mutex_init( &mut self, - mutex_op: OpTy<'tcx, Tag>, - attr_op: OpTy<'tcx, Tag>, + mutex_op: &OpTy<'tcx, Tag>, + attr_op: &OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); @@ -374,7 +374,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(0) } - fn pthread_mutex_lock(&mut self, mutex_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + fn pthread_mutex_lock(&mut self, mutex_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); let kind = mutex_get_kind(this, mutex_op)?.check_init()?; @@ -411,7 +411,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } - fn pthread_mutex_trylock(&mut self, mutex_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + fn pthread_mutex_trylock(&mut self, mutex_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); let kind = mutex_get_kind(this, mutex_op)?.check_init()?; @@ -444,7 +444,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } - fn pthread_mutex_unlock(&mut self, mutex_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + fn pthread_mutex_unlock(&mut self, mutex_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); let kind = mutex_get_kind(this, mutex_op)?.check_init()?; @@ -476,7 +476,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } - fn pthread_mutex_destroy(&mut self, mutex_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + fn pthread_mutex_destroy(&mut self, mutex_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); let id = mutex_get_or_create_id(this, mutex_op)?; @@ -492,7 +492,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(0) } - fn pthread_rwlock_rdlock(&mut self, rwlock_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + fn pthread_rwlock_rdlock(&mut self, rwlock_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); let id = rwlock_get_or_create_id(this, rwlock_op)?; @@ -507,7 +507,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } - fn pthread_rwlock_tryrdlock(&mut self, rwlock_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + fn pthread_rwlock_tryrdlock(&mut self, rwlock_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); let id = rwlock_get_or_create_id(this, rwlock_op)?; @@ -521,7 +521,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } - fn pthread_rwlock_wrlock(&mut self, rwlock_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + fn pthread_rwlock_wrlock(&mut self, rwlock_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); let id = rwlock_get_or_create_id(this, rwlock_op)?; @@ -548,7 +548,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(0) } - fn pthread_rwlock_trywrlock(&mut self, rwlock_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + fn pthread_rwlock_trywrlock(&mut self, rwlock_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); let id = rwlock_get_or_create_id(this, rwlock_op)?; @@ -562,7 +562,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } - fn pthread_rwlock_unlock(&mut self, rwlock_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + fn pthread_rwlock_unlock(&mut self, rwlock_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); let id = rwlock_get_or_create_id(this, rwlock_op)?; @@ -577,7 +577,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } - fn pthread_rwlock_destroy(&mut self, rwlock_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + fn pthread_rwlock_destroy(&mut self, rwlock_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); let id = rwlock_get_or_create_id(this, rwlock_op)?; @@ -592,7 +592,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(0) } - fn pthread_condattr_init(&mut self, attr_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + fn pthread_condattr_init(&mut self, attr_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); // The default value of the clock attribute shall refer to the system @@ -606,8 +606,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn pthread_condattr_setclock( &mut self, - attr_op: OpTy<'tcx, Tag>, - clock_id_op: OpTy<'tcx, Tag>, + attr_op: &OpTy<'tcx, Tag>, + clock_id_op: &OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); @@ -626,18 +626,18 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn pthread_condattr_getclock( &mut self, - attr_op: OpTy<'tcx, Tag>, - clk_id_op: OpTy<'tcx, Tag>, + attr_op: &OpTy<'tcx, Tag>, + clk_id_op: &OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); let clock_id = condattr_get_clock_id(this, attr_op)?; - this.write_scalar(clock_id, this.deref_operand(clk_id_op)?.into())?; + this.write_scalar(clock_id, &this.deref_operand(clk_id_op)?.into())?; Ok(0) } - fn pthread_condattr_destroy(&mut self, attr_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + fn pthread_condattr_destroy(&mut self, attr_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); condattr_set_clock_id(this, attr_op, ScalarMaybeUninit::Uninit)?; @@ -647,8 +647,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn pthread_cond_init( &mut self, - cond_op: OpTy<'tcx, Tag>, - attr_op: OpTy<'tcx, Tag>, + cond_op: &OpTy<'tcx, Tag>, + attr_op: &OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); @@ -667,7 +667,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(0) } - fn pthread_cond_signal(&mut self, cond_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + fn pthread_cond_signal(&mut self, cond_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); let id = cond_get_or_create_id(this, cond_op)?; if let Some((thread, mutex)) = this.condvar_signal(id) { @@ -677,7 +677,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(0) } - fn pthread_cond_broadcast(&mut self, cond_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + fn pthread_cond_broadcast(&mut self, cond_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); let id = cond_get_or_create_id(this, cond_op)?; @@ -690,8 +690,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn pthread_cond_wait( &mut self, - cond_op: OpTy<'tcx, Tag>, - mutex_op: OpTy<'tcx, Tag>, + cond_op: &OpTy<'tcx, Tag>, + mutex_op: &OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); @@ -707,10 +707,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn pthread_cond_timedwait( &mut self, - cond_op: OpTy<'tcx, Tag>, - mutex_op: OpTy<'tcx, Tag>, - abstime_op: OpTy<'tcx, Tag>, - dest: PlaceTy<'tcx, Tag>, + cond_op: &OpTy<'tcx, Tag>, + mutex_op: &OpTy<'tcx, Tag>, + abstime_op: &OpTy<'tcx, Tag>, + dest: &PlaceTy<'tcx, Tag>, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); @@ -745,6 +745,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // We return success for now and override it in the timeout callback. this.write_scalar(Scalar::from_i32(0), dest)?; + let dest = *dest; + // Register the timeout callback. this.register_timeout_callback( active_thread, @@ -759,7 +761,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Set the return value: we timed out. let etimedout = ecx.eval_libc("ETIMEDOUT")?; - ecx.write_scalar(etimedout, dest)?; + ecx.write_scalar(etimedout, &dest)?; Ok(()) }), @@ -768,7 +770,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(()) } - fn pthread_cond_destroy(&mut self, cond_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + fn pthread_cond_destroy(&mut self, cond_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); let id = cond_get_or_create_id(this, cond_op)?; diff --git a/src/shims/posix/thread.rs b/src/shims/posix/thread.rs index 0ea20cdff6cb3..40663326b4651 100644 --- a/src/shims/posix/thread.rs +++ b/src/shims/posix/thread.rs @@ -7,10 +7,10 @@ impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tc pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { fn pthread_create( &mut self, - thread: OpTy<'tcx, Tag>, - _attr: OpTy<'tcx, Tag>, - start_routine: OpTy<'tcx, Tag>, - arg: OpTy<'tcx, Tag>, + thread: &OpTy<'tcx, Tag>, + _attr: &OpTy<'tcx, Tag>, + start_routine: &OpTy<'tcx, Tag>, + arg: &OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); @@ -26,7 +26,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let thread_info_place = this.deref_operand(thread)?; this.write_scalar( Scalar::from_uint(new_thread_id.to_u32(), thread_info_place.layout.size), - thread_info_place.into(), + &thread_info_place.into(), )?; // Read the function argument that will be sent to the new thread @@ -51,7 +51,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.call_function( instance, &[*func_arg], - Some(ret_place.into()), + Some(&ret_place.into()), StackPopCleanup::None { cleanup: true }, )?; @@ -63,8 +63,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn pthread_join( &mut self, - thread: OpTy<'tcx, Tag>, - retval: OpTy<'tcx, Tag>, + thread: &OpTy<'tcx, Tag>, + retval: &OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); @@ -79,7 +79,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(0) } - fn pthread_detach(&mut self, thread: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + fn pthread_detach(&mut self, thread: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); let thread_id = this.read_scalar(thread)?.to_machine_usize(this)?; @@ -88,7 +88,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(0) } - fn pthread_self(&mut self, dest: PlaceTy<'tcx, Tag>) -> InterpResult<'tcx> { + fn pthread_self(&mut self, dest: &PlaceTy<'tcx, Tag>) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let thread_id = this.get_active_thread(); @@ -97,11 +97,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn prctl( &mut self, - option: OpTy<'tcx, Tag>, - arg2: OpTy<'tcx, Tag>, - _arg3: OpTy<'tcx, Tag>, - _arg4: OpTy<'tcx, Tag>, - _arg5: OpTy<'tcx, Tag>, + option: &OpTy<'tcx, Tag>, + arg2: &OpTy<'tcx, Tag>, + _arg3: &OpTy<'tcx, Tag>, + _arg4: &OpTy<'tcx, Tag>, + _arg5: &OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); this.assert_target_os("linux", "prctl"); diff --git a/src/shims/time.rs b/src/shims/time.rs index 806fa65d1564c..5af2e5ab67e7f 100644 --- a/src/shims/time.rs +++ b/src/shims/time.rs @@ -16,8 +16,8 @@ impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mi pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { fn clock_gettime( &mut self, - clk_id_op: OpTy<'tcx, Tag>, - tp_op: OpTy<'tcx, Tag>, + clk_id_op: &OpTy<'tcx, Tag>, + tp_op: &OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); @@ -47,15 +47,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx immty_from_int_checked(tv_nsec, this.libc_ty_layout("c_long")?)?, ]; - this.write_packed_immediates(tp, &imms)?; + this.write_packed_immediates(&tp, &imms)?; Ok(0) } fn gettimeofday( &mut self, - tv_op: OpTy<'tcx, Tag>, - tz_op: OpTy<'tcx, Tag>, + tv_op: &OpTy<'tcx, Tag>, + tz_op: &OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); @@ -81,13 +81,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx immty_from_int_checked(tv_usec, this.libc_ty_layout("suseconds_t")?)?, ]; - this.write_packed_immediates(tv, &imms)?; + this.write_packed_immediates(&tv, &imms)?; Ok(0) } #[allow(non_snake_case)] - fn GetSystemTimeAsFileTime(&mut self, LPFILETIME_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx> { + fn GetSystemTimeAsFileTime(&mut self, LPFILETIME_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx> { let this = self.eval_context_mut(); this.assert_target_os("windows", "GetSystemTimeAsFileTime"); @@ -110,12 +110,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx immty_from_uint_checked(dwLowDateTime, DWORD_tylayout)?, immty_from_uint_checked(dwHighDateTime, DWORD_tylayout)?, ]; - this.write_packed_immediates(this.deref_operand(LPFILETIME_op)?, &imms)?; + this.write_packed_immediates(&this.deref_operand(LPFILETIME_op)?, &imms)?; Ok(()) } #[allow(non_snake_case)] - fn QueryPerformanceCounter(&mut self, lpPerformanceCount_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + fn QueryPerformanceCounter(&mut self, lpPerformanceCount_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); this.assert_target_os("windows", "QueryPerformanceCounter"); @@ -126,12 +126,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let duration = Instant::now().duration_since(this.machine.time_anchor); let qpc = i64::try_from(duration.as_nanos()) .map_err(|_| err_unsup_format!("programs running longer than 2^63 nanoseconds are not supported"))?; - this.write_scalar(Scalar::from_i64(qpc), this.deref_operand(lpPerformanceCount_op)?.into())?; + this.write_scalar(Scalar::from_i64(qpc), &this.deref_operand(lpPerformanceCount_op)?.into())?; Ok(-1) // return non-zero on success } #[allow(non_snake_case)] - fn QueryPerformanceFrequency(&mut self, lpFrequency_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + fn QueryPerformanceFrequency(&mut self, lpFrequency_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); this.assert_target_os("windows", "QueryPerformanceFrequency"); @@ -142,7 +142,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // is consistent across all processors. // Miri emulates a "hardware" performance counter with a resolution of 1ns, // and thus 10^9 counts per second. - this.write_scalar(Scalar::from_i64(1_000_000_000), this.deref_operand(lpFrequency_op)?.into())?; + this.write_scalar(Scalar::from_i64(1_000_000_000), &this.deref_operand(lpFrequency_op)?.into())?; Ok(-1) // Return non-zero on success } @@ -159,7 +159,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx .map_err(|_| err_unsup_format!("programs running longer than 2^64 nanoseconds are not supported").into()) } - fn mach_timebase_info(&mut self, info_op: OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + fn mach_timebase_info(&mut self, info_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); this.assert_target_os("macos", "mach_timebase_info"); @@ -175,14 +175,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx immty_from_int_checked(denom, this.machine.layouts.u32)? ]; - this.write_packed_immediates(info, &imms)?; + this.write_packed_immediates(&info, &imms)?; Ok(0) // KERN_SUCCESS } fn nanosleep( &mut self, - req_op: OpTy<'tcx, Tag>, - _rem: OpTy<'tcx, Tag>, + req_op: &OpTy<'tcx, Tag>, + _rem: &OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, i32> { // Signal handlers are not supported, so rem will never be written to. diff --git a/src/shims/tls.rs b/src/shims/tls.rs index 2ca860367effe..7f19fd1673660 100644 --- a/src/shims/tls.rs +++ b/src/shims/tls.rs @@ -245,7 +245,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.call_function( thread_callback, &[Scalar::null_ptr(this).into(), reason.into(), Scalar::null_ptr(this).into()], - Some(ret_place), + Some(&ret_place), StackPopCleanup::None { cleanup: true }, )?; @@ -267,7 +267,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.call_function( instance, &[data.into()], - Some(ret_place), + Some(&ret_place), StackPopCleanup::None { cleanup: true }, )?; @@ -307,7 +307,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.call_function( instance, &[ptr.into()], - Some(ret_place), + Some(&ret_place), StackPopCleanup::None { cleanup: true }, )?; diff --git a/src/shims/windows/dlsym.rs b/src/shims/windows/dlsym.rs index 57766bd344a45..1f136060259a1 100644 --- a/src/shims/windows/dlsym.rs +++ b/src/shims/windows/dlsym.rs @@ -26,7 +26,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx dlsym: Dlsym, abi: Abi, _args: &[OpTy<'tcx, Tag>], - ret: Option<(PlaceTy<'tcx, Tag>, mir::BasicBlock)>, + ret: Option<(&PlaceTy<'tcx, Tag>, mir::BasicBlock)>, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let (_dest, _ret) = ret.expect("we don't support any diverging dlsym"); diff --git a/src/shims/windows/foreign_items.rs b/src/shims/windows/foreign_items.rs index 0eeec08901db7..f8d62f6b323bf 100644 --- a/src/shims/windows/foreign_items.rs +++ b/src/shims/windows/foreign_items.rs @@ -15,7 +15,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx link_name: &str, abi: Abi, args: &[OpTy<'tcx, Tag>], - dest: PlaceTy<'tcx, Tag>, + dest: &PlaceTy<'tcx, Tag>, _ret: mir::BasicBlock, ) -> InterpResult<'tcx, bool> { let this = self.eval_context_mut(); @@ -30,12 +30,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx match link_name { // Environment related shims "GetEnvironmentVariableW" => { - let &[name, buf, size] = check_arg_count(args)?; + let &[ref name, ref buf, ref size] = check_arg_count(args)?; let result = this.GetEnvironmentVariableW(name, buf, size)?; this.write_scalar(Scalar::from_u32(result), dest)?; } "SetEnvironmentVariableW" => { - let &[name, value] = check_arg_count(args)?; + let &[ref name, ref value] = check_arg_count(args)?; let result = this.SetEnvironmentVariableW(name, value)?; this.write_scalar(Scalar::from_i32(result), dest)?; } @@ -45,38 +45,38 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(result, dest)?; } "FreeEnvironmentStringsW" => { - let &[env_block] = check_arg_count(args)?; + let &[ref env_block] = check_arg_count(args)?; let result = this.FreeEnvironmentStringsW(env_block)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "GetCurrentDirectoryW" => { - let &[size, buf] = check_arg_count(args)?; + let &[ref size, ref buf] = check_arg_count(args)?; let result = this.GetCurrentDirectoryW(size, buf)?; this.write_scalar(Scalar::from_u32(result), dest)?; } "SetCurrentDirectoryW" => { - let &[path] = check_arg_count(args)?; + let &[ref path] = check_arg_count(args)?; let result = this.SetCurrentDirectoryW(path)?; this.write_scalar(Scalar::from_i32(result), dest)?; } // File related shims "GetStdHandle" => { - let &[which] = check_arg_count(args)?; + let &[ref which] = check_arg_count(args)?; let which = this.read_scalar(which)?.to_i32()?; // We just make this the identity function, so we know later in `WriteFile` // which one it is. this.write_scalar(Scalar::from_machine_isize(which.into(), this), dest)?; } "WriteFile" => { - let &[handle, buf, n, written_ptr, overlapped] = check_arg_count(args)?; + let &[ref handle, ref buf, ref n, ref written_ptr, ref overlapped] = check_arg_count(args)?; this.read_scalar(overlapped)?.to_machine_usize(this)?; // this is a poiner, that we ignore let handle = this.read_scalar(handle)?.to_machine_isize(this)?; let buf = this.read_scalar(buf)?.check_init()?; let n = this.read_scalar(n)?.to_u32()?; let written_place = this.deref_operand(written_ptr)?; // Spec says to always write `0` first. - this.write_null(written_place.into())?; + this.write_null(&written_place.into())?; let written = if handle == -11 || handle == -12 { // stdout/stderr use std::io::{self, Write}; @@ -93,7 +93,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx }; // If there was no error, write back how much was written. if let Some(n) = written { - this.write_scalar(Scalar::from_u32(n), written_place.into())?; + this.write_scalar(Scalar::from_u32(n), &written_place.into())?; } // Return whether this was a success. this.write_scalar( @@ -104,7 +104,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Allocation "HeapAlloc" => { - let &[handle, flags, size] = check_arg_count(args)?; + let &[ref handle, ref flags, ref size] = check_arg_count(args)?; this.read_scalar(handle)?.to_machine_isize(this)?; let flags = this.read_scalar(flags)?.to_u32()?; let size = this.read_scalar(size)?.to_machine_usize(this)?; @@ -113,7 +113,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(res, dest)?; } "HeapFree" => { - let &[handle, flags, ptr] = check_arg_count(args)?; + let &[ref handle, ref flags, ref ptr] = check_arg_count(args)?; this.read_scalar(handle)?.to_machine_isize(this)?; this.read_scalar(flags)?.to_u32()?; let ptr = this.read_scalar(ptr)?.check_init()?; @@ -121,7 +121,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_i32(1), dest)?; } "HeapReAlloc" => { - let &[handle, flags, ptr, size] = check_arg_count(args)?; + let &[ref handle, ref flags, ref ptr, ref size] = check_arg_count(args)?; this.read_scalar(handle)?.to_machine_isize(this)?; this.read_scalar(flags)?.to_u32()?; let ptr = this.read_scalar(ptr)?.check_init()?; @@ -132,7 +132,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // errno "SetLastError" => { - let &[error] = check_arg_count(args)?; + let &[ref error] = check_arg_count(args)?; let error = this.read_scalar(error)?.check_init()?; this.set_last_error(error)?; } @@ -144,7 +144,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Querying system information "GetSystemInfo" => { - let &[system_info] = check_arg_count(args)?; + let &[ref system_info] = check_arg_count(args)?; let system_info = this.deref_operand(system_info)?; // Initialize with `0`. this.memory.write_bytes( @@ -153,8 +153,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx )?; // Set number of processors. let dword_size = Size::from_bytes(4); - let num_cpus = this.mplace_field(system_info, 6)?; - this.write_scalar(Scalar::from_int(NUM_CPUS, dword_size), num_cpus.into())?; + let num_cpus = this.mplace_field(&system_info, 6)?; + this.write_scalar(Scalar::from_int(NUM_CPUS, dword_size), &num_cpus.into())?; } // Thread-local storage @@ -167,14 +167,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_uint(key, dest.layout.size), dest)?; } "TlsGetValue" => { - let &[key] = check_arg_count(args)?; + let &[ref key] = check_arg_count(args)?; let key = u128::from(this.read_scalar(key)?.to_u32()?); let active_thread = this.get_active_thread(); let ptr = this.machine.tls.load_tls(key, active_thread, this)?; this.write_scalar(ptr, dest)?; } "TlsSetValue" => { - let &[key, new_ptr] = check_arg_count(args)?; + let &[ref key, ref new_ptr] = check_arg_count(args)?; let key = u128::from(this.read_scalar(key)?.to_u32()?); let active_thread = this.get_active_thread(); let new_ptr = this.read_scalar(new_ptr)?.check_init()?; @@ -196,46 +196,46 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Time related shims "GetSystemTimeAsFileTime" => { #[allow(non_snake_case)] - let &[LPFILETIME] = check_arg_count(args)?; + let &[ref LPFILETIME] = check_arg_count(args)?; this.GetSystemTimeAsFileTime(LPFILETIME)?; } "QueryPerformanceCounter" => { #[allow(non_snake_case)] - let &[lpPerformanceCount] = check_arg_count(args)?; + let &[ref lpPerformanceCount] = check_arg_count(args)?; let result = this.QueryPerformanceCounter(lpPerformanceCount)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "QueryPerformanceFrequency" => { #[allow(non_snake_case)] - let &[lpFrequency] = check_arg_count(args)?; + let &[ref lpFrequency] = check_arg_count(args)?; let result = this.QueryPerformanceFrequency(lpFrequency)?; this.write_scalar(Scalar::from_i32(result), dest)?; } // Synchronization primitives "AcquireSRWLockExclusive" => { - let &[ptr] = check_arg_count(args)?; + let &[ref ptr] = check_arg_count(args)?; this.AcquireSRWLockExclusive(ptr)?; } "ReleaseSRWLockExclusive" => { - let &[ptr] = check_arg_count(args)?; + let &[ref ptr] = check_arg_count(args)?; this.ReleaseSRWLockExclusive(ptr)?; } "TryAcquireSRWLockExclusive" => { - let &[ptr] = check_arg_count(args)?; + let &[ref ptr] = check_arg_count(args)?; let ret = this.TryAcquireSRWLockExclusive(ptr)?; this.write_scalar(Scalar::from_u8(ret), dest)?; } "AcquireSRWLockShared" => { - let &[ptr] = check_arg_count(args)?; + let &[ref ptr] = check_arg_count(args)?; this.AcquireSRWLockShared(ptr)?; } "ReleaseSRWLockShared" => { - let &[ptr] = check_arg_count(args)?; + let &[ref ptr] = check_arg_count(args)?; this.ReleaseSRWLockShared(ptr)?; } "TryAcquireSRWLockShared" => { - let &[ptr] = check_arg_count(args)?; + let &[ref ptr] = check_arg_count(args)?; let ret = this.TryAcquireSRWLockShared(ptr)?; this.write_scalar(Scalar::from_u8(ret), dest)?; } @@ -243,7 +243,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Dynamic symbol loading "GetProcAddress" => { #[allow(non_snake_case)] - let &[hModule, lpProcName] = check_arg_count(args)?; + let &[ref hModule, ref lpProcName] = check_arg_count(args)?; this.read_scalar(hModule)?.to_machine_isize(this)?; let name = this.memory.read_c_str(this.read_scalar(lpProcName)?.check_init()?)?; if let Some(dlsym) = Dlsym::from_str(name, &this.tcx.sess.target.os)? { @@ -257,7 +257,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Miscellaneous "SystemFunction036" => { // The actual name of 'RtlGenRandom' - let &[ptr, len] = check_arg_count(args)?; + let &[ref ptr, ref len] = check_arg_count(args)?; let ptr = this.read_scalar(ptr)?.check_init()?; let len = this.read_scalar(len)?.to_u32()?; this.gen_random(ptr, len.into())?; @@ -265,7 +265,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "GetConsoleScreenBufferInfo" => { // `term` needs this, so we fake it. - let &[console, buffer_info] = check_arg_count(args)?; + let &[ref console, ref buffer_info] = check_arg_count(args)?; this.read_scalar(console)?.to_machine_isize(this)?; this.deref_operand(buffer_info)?; // Indicate an error. @@ -274,7 +274,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "GetConsoleMode" => { // Windows "isatty" (in libtest) needs this, so we fake it. - let &[console, mode] = check_arg_count(args)?; + let &[ref console, ref mode] = check_arg_count(args)?; this.read_scalar(console)?.to_machine_isize(this)?; this.deref_operand(mode)?; // Indicate an error. @@ -302,13 +302,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "SetConsoleTextAttribute" if this.frame().instance.to_string().starts_with("std::sys::windows::") => { #[allow(non_snake_case)] - let &[_hConsoleOutput, _wAttribute] = check_arg_count(args)?; + let &[ref _hConsoleOutput, ref _wAttribute] = check_arg_count(args)?; // Pretend these does not exist / nothing happened, by returning zero. this.write_null(dest)?; } "AddVectoredExceptionHandler" if this.frame().instance.to_string().starts_with("std::sys::windows::") => { #[allow(non_snake_case)] - let &[_First, _Handler] = check_arg_count(args)?; + let &[ref _First, ref _Handler] = check_arg_count(args)?; // Any non zero value works for the stdlib. This is just used for stack overflows anyway. this.write_scalar(Scalar::from_machine_usize(1, this), dest)?; } @@ -324,7 +324,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "DeleteCriticalSection" if this.frame().instance.to_string().starts_with("std::sys::windows::") => { #[allow(non_snake_case)] - let &[_lpCriticalSection] = check_arg_count(args)?; + let &[ref _lpCriticalSection] = check_arg_count(args)?; assert_eq!(this.get_total_thread_count(), 1, "concurrency on Windows is not supported"); // Nothing to do, not even a return value. // (Windows locks are reentrant, and we have only 1 thread, @@ -333,7 +333,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "TryEnterCriticalSection" if this.frame().instance.to_string().starts_with("std::sys::windows::") => { #[allow(non_snake_case)] - let &[_lpCriticalSection] = check_arg_count(args)?; + let &[ref _lpCriticalSection] = check_arg_count(args)?; assert_eq!(this.get_total_thread_count(), 1, "concurrency on Windows is not supported"); // There is only one thread, so this always succeeds and returns TRUE. this.write_scalar(Scalar::from_i32(1), dest)?; diff --git a/src/shims/windows/sync.rs b/src/shims/windows/sync.rs index 7bad3c08a598f..caf8942afd930 100644 --- a/src/shims/windows/sync.rs +++ b/src/shims/windows/sync.rs @@ -5,7 +5,7 @@ use crate::*; fn srwlock_get_or_create_id<'mir, 'tcx: 'mir>( ecx: &mut MiriEvalContext<'mir, 'tcx>, - lock_op: OpTy<'tcx, Tag>, + lock_op: &OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, RwLockId> { let id = ecx.read_scalar_at_offset(lock_op, 0, ecx.machine.layouts.u32)?.to_u32()?; if id == 0 { @@ -24,7 +24,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx #[allow(non_snake_case)] fn AcquireSRWLockExclusive( &mut self, - lock_op: OpTy<'tcx, Tag>, + lock_op: &OpTy<'tcx, Tag>, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let id = srwlock_get_or_create_id(this, lock_op)?; @@ -49,7 +49,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx #[allow(non_snake_case)] fn TryAcquireSRWLockExclusive( &mut self, - lock_op: OpTy<'tcx, Tag>, + lock_op: &OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, u8> { let this = self.eval_context_mut(); let id = srwlock_get_or_create_id(this, lock_op)?; @@ -67,7 +67,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx #[allow(non_snake_case)] fn ReleaseSRWLockExclusive( &mut self, - lock_op: OpTy<'tcx, Tag>, + lock_op: &OpTy<'tcx, Tag>, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let id = srwlock_get_or_create_id(this, lock_op)?; @@ -84,7 +84,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx #[allow(non_snake_case)] fn AcquireSRWLockShared( &mut self, - lock_op: OpTy<'tcx, Tag>, + lock_op: &OpTy<'tcx, Tag>, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let id = srwlock_get_or_create_id(this, lock_op)?; @@ -102,7 +102,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx #[allow(non_snake_case)] fn TryAcquireSRWLockShared( &mut self, - lock_op: OpTy<'tcx, Tag>, + lock_op: &OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, u8> { let this = self.eval_context_mut(); let id = srwlock_get_or_create_id(this, lock_op)?; @@ -119,7 +119,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx #[allow(non_snake_case)] fn ReleaseSRWLockShared( &mut self, - lock_op: OpTy<'tcx, Tag>, + lock_op: &OpTy<'tcx, Tag>, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let id = srwlock_get_or_create_id(this, lock_op)?; diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 616950eb0a0a4..52f4ddbc386c8 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -521,7 +521,7 @@ impl<'mir, 'tcx: 'mir> EvalContextPrivExt<'mir, 'tcx> for crate::MiriEvalContext trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { fn reborrow( &mut self, - place: MPlaceTy<'tcx, Tag>, + place: &MPlaceTy<'tcx, Tag>, size: Size, kind: RefKind, new_tag: Tag, @@ -577,7 +577,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// `mutbl` can be `None` to make this a raw pointer. fn retag_reference( &mut self, - val: ImmTy<'tcx, Tag>, + val: &ImmTy<'tcx, Tag>, kind: RefKind, protect: bool, ) -> InterpResult<'tcx, ImmTy<'tcx, Tag>> { @@ -585,7 +585,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // We want a place for where the ptr *points to*, so we get one. let place = this.ref_to_mplace(val)?; let size = this - .size_and_align_of_mplace(place)? + .size_and_align_of_mplace(&place)? .map(|(size, _)| size) .unwrap_or_else(|| place.layout.size); // `reborrow` relies on getting a `Pointer` and everything being in-bounds, @@ -595,7 +595,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let place = this.mplace_access_checked(place, Some(Align::from_bytes(1).unwrap()))?; // Nothing to do for ZSTs. if size == Size::ZERO { - return Ok(val); + return Ok(*val); } // Compute new borrow. @@ -610,7 +610,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx }; // Reborrow. - this.reborrow(place, size, kind, new_tag, protect)?; + this.reborrow(&place, size, kind, new_tag, protect)?; let new_place = place.replace_tag(new_tag); // Return new pointer. @@ -620,7 +620,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { - fn retag(&mut self, kind: RetagKind, place: PlaceTy<'tcx, Tag>) -> InterpResult<'tcx> { + fn retag(&mut self, kind: RetagKind, place: &PlaceTy<'tcx, Tag>) -> InterpResult<'tcx> { let this = self.eval_context_mut(); // Determine mutability and whether to add a protector. // Cannot use `builtin_deref` because that reports *immutable* for `Box`, @@ -649,8 +649,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // but might also cost us optimization and analyses. We will have to experiment more with this. if let Some((mutbl, protector)) = qualify(place.layout.ty, kind) { // Fast path. - let val = this.read_immediate(this.place_to_op(place)?)?; - let val = this.retag_reference(val, mutbl, protector)?; + let val = this.read_immediate(&this.place_to_op(place)?)?; + let val = this.retag_reference(&val, mutbl, protector)?; this.write_immediate(*val, place)?; } @@ -675,16 +675,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx return Ok(()); } // We need this to be in-memory to use tagged pointers. - let return_place = this.force_allocation(return_place)?; + let return_place = this.force_allocation(&return_place)?; // We have to turn the place into a pointer to use the existing code. // (The pointer type does not matter, so we use a raw pointer.) let ptr_layout = this.layout_of(this.tcx.mk_mut_ptr(return_place.layout.ty))?; let val = ImmTy::from_immediate(return_place.to_ref(), ptr_layout); // Reborrow it. - let val = this.retag_reference(val, RefKind::Unique { two_phase: false }, /*protector*/ true)?; + let val = this.retag_reference(&val, RefKind::Unique { two_phase: false }, /*protector*/ true)?; // And use reborrowed pointer for return place. - let return_place = this.ref_to_mplace(val)?; + let return_place = this.ref_to_mplace(&val)?; this.frame_mut().return_place = Some(return_place.into()); Ok(()) From c003fd0157e0b19f0fba8d3491423d6bf678d873 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 23 Feb 2021 09:23:49 +0100 Subject: [PATCH 2554/3747] rustup --- rust-version | 2 +- tests/compile-fail/transmute-pair-uninit.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/rust-version b/rust-version index 6c6212ec839cc..f76caa2c0f335 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -e7c23ab933ebc1f205c3b59f4ebc85d40f67d404 +a4e595db8f12f9ee926256745d757004b850703f diff --git a/tests/compile-fail/transmute-pair-uninit.rs b/tests/compile-fail/transmute-pair-uninit.rs index 0f02697f26152..42aa7a9692788 100644 --- a/tests/compile-fail/transmute-pair-uninit.rs +++ b/tests/compile-fail/transmute-pair-uninit.rs @@ -17,6 +17,6 @@ fn main() { assert_eq!(byte, 0); } let v = unsafe { *z.offset(first_undef) }; - if v == 0 {} + if v == 0 { println!("it is zero"); } //~^ ERROR this operation requires initialized memory } From f85bb0fb09a1932cdc17ebb0dcd13b81c93346f7 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 27 Feb 2021 12:24:58 +0100 Subject: [PATCH 2555/3747] test for unnecessary rebuilds in 'cargo miri run' --- test-cargo-miri/run-test.py | 30 ++++++++++++++++++++++++++++-- 1 file changed, 28 insertions(+), 2 deletions(-) diff --git a/test-cargo-miri/run-test.py b/test-cargo-miri/run-test.py index 8edd947c3b0fa..0505b422d95f1 100755 --- a/test-cargo-miri/run-test.py +++ b/test-cargo-miri/run-test.py @@ -15,8 +15,10 @@ def fail(msg): print("\nTEST FAIL: {}".format(msg)) sys.exit(1) -def cargo_miri(cmd): - args = ["cargo", "miri", cmd, "-q"] +def cargo_miri(cmd, quiet = True): + args = ["cargo", "miri", cmd] + if quiet: + args += ["-q"] if 'MIRI_TEST_TARGET' in os.environ: args += ["--target", os.environ['MIRI_TEST_TARGET']] return args @@ -48,6 +50,25 @@ def test(name, cmd, stdout_ref, stderr_ref, stdin=b'', env={}): print("--- END stderr ---") fail("exit code was {}".format(p.returncode)) +def test_rebuild(name, cmd, rebuild_count_expected): + print("Testing {}...".format(name)) + p = subprocess.Popen( + cmd, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + ) + (stdout, stderr) = p.communicate() + stdout = stdout.decode("UTF-8") + stderr = stderr.decode("UTF-8") + if p.returncode != 0: + fail("rebuild failed"); + rebuild_count = stderr.count(" Compiling "); + if rebuild_count != rebuild_count_expected: + print("--- BEGIN stderr ---") + print(stderr, end="") + print("--- END stderr ---") + fail("Expected {} rebuild(s), but got {}".format(rebuild_count_expected, rebuild_count)); + def test_cargo_miri_run(): test("`cargo miri run` (no isolation)", cargo_miri("run"), @@ -67,6 +88,11 @@ def test_cargo_miri_run(): "run.subcrate.stdout.ref", "run.subcrate.stderr.ref", env={'MIRIFLAGS': "-Zmiri-disable-isolation"}, ) + # Special test: run it again *without* `-q` to make sure nothing is being rebuilt (Miri issue #1722) + test_rebuild("`cargo miri run` (clean rebuild)", + cargo_miri("run", quiet=False) + ["--", ""], + rebuild_count_expected=1, + ) def test_cargo_miri_test(): # rustdoc is not run on foreign targets From 3e987e127c9865189af59f7878e172b9f1297de5 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 27 Feb 2021 12:32:06 +0100 Subject: [PATCH 2556/3747] create more fake files for cdylibs and staticlibs --- cargo-miri/bin.rs | 13 +++++++++---- test-cargo-miri/run-test.py | 13 +++++++------ 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index cb003c0f3e8bd..051f3dd3b6fc7 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -692,12 +692,17 @@ fn phase_cargo_rustc(mut args: env::Args) { exec(cmd); // Create a stub .rlib file if "link" was requested by cargo. + // This is necessary to prevent cargo from doing rebuilds all the time. if emit_link_hack { // Some platforms prepend "lib", some do not... let's just create both files. - let filename = out_filename("lib", ".rlib"); - File::create(filename).expect("failed to create rlib file"); - let filename = out_filename("", ".rlib"); - File::create(filename).expect("failed to create rlib file"); + File::create(out_filename("lib", ".rlib")).expect("failed to create fake .rlib file"); + File::create(out_filename("", ".rlib")).expect("failed to create fake .rlib file"); + // Just in case this is a cdylib or staticlib, also create those fake files. + File::create(out_filename("lib", ".so")).expect("failed to create fake .so file"); + File::create(out_filename("lib", ".a")).expect("failed to create fake .a file"); + File::create(out_filename("lib", ".dylib")).expect("failed to create fake .dylib file"); + File::create(out_filename("", ".dll")).expect("failed to create fake .dll file"); + File::create(out_filename("", ".lib")).expect("failed to create fake .lib file"); } } diff --git a/test-cargo-miri/run-test.py b/test-cargo-miri/run-test.py index 0505b422d95f1..b9259b7d0d225 100755 --- a/test-cargo-miri/run-test.py +++ b/test-cargo-miri/run-test.py @@ -50,7 +50,7 @@ def test(name, cmd, stdout_ref, stderr_ref, stdin=b'', env={}): print("--- END stderr ---") fail("exit code was {}".format(p.returncode)) -def test_rebuild(name, cmd, rebuild_count_expected): +def test_no_rebuild(name, cmd): print("Testing {}...".format(name)) p = subprocess.Popen( cmd, @@ -62,12 +62,12 @@ def test_rebuild(name, cmd, rebuild_count_expected): stderr = stderr.decode("UTF-8") if p.returncode != 0: fail("rebuild failed"); - rebuild_count = stderr.count(" Compiling "); - if rebuild_count != rebuild_count_expected: + # Also check for 'Running' as a sanity check. + if stderr.count(" Compiling ") > 0 or stderr.count(" Running ") == 0: print("--- BEGIN stderr ---") print(stderr, end="") print("--- END stderr ---") - fail("Expected {} rebuild(s), but got {}".format(rebuild_count_expected, rebuild_count)); + fail("Something was being rebuilt when it should not be (or we got no output)"); def test_cargo_miri_run(): test("`cargo miri run` (no isolation)", @@ -89,9 +89,10 @@ def test_cargo_miri_run(): env={'MIRIFLAGS': "-Zmiri-disable-isolation"}, ) # Special test: run it again *without* `-q` to make sure nothing is being rebuilt (Miri issue #1722) - test_rebuild("`cargo miri run` (clean rebuild)", + # FIXME: move this test up to right after the first `test` + # (currently that fails, only the 3rd and later runs are really clean... see Miri issue #1722) + test_no_rebuild("`cargo miri run` (no rebuild)", cargo_miri("run", quiet=False) + ["--", ""], - rebuild_count_expected=1, ) def test_cargo_miri_test(): From 48f7c8e2e6a42b441aa21068ae526ec5affd0c40 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 27 Feb 2021 20:03:51 +0100 Subject: [PATCH 2557/3747] fix reborrowing of tagged ZST references --- src/stacked_borrows.rs | 16 ++++++++++++---- tests/compile-fail/stacked_borrows/zst_slice.rs | 11 +++++++++++ 2 files changed, 23 insertions(+), 4 deletions(-) create mode 100644 tests/compile-fail/stacked_borrows/zst_slice.rs diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 52f4ddbc386c8..cfaf8a9005ca5 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -586,15 +586,23 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let place = this.ref_to_mplace(val)?; let size = this .size_and_align_of_mplace(&place)? - .map(|(size, _)| size) - .unwrap_or_else(|| place.layout.size); + .map(|(size, _)| size); + // FIXME: If we cannot determine the size (because the unsized tail is an `extern type`), + // bail out -- we cannot reasonably figure out which memory range to reborrow. + // See https://github.com/rust-lang/unsafe-code-guidelines/issues/276. + let size = match size { + Some(size) => size, + None => return Ok(*val), + }; // `reborrow` relies on getting a `Pointer` and everything being in-bounds, // so let's ensure that. However, we do not care about alignment. // We can see dangling ptrs in here e.g. after a Box's `Unique` was // updated using "self.0 = ..." (can happen in Box::from_raw) so we cannot ICE; see miri#1050. let place = this.mplace_access_checked(place, Some(Align::from_bytes(1).unwrap()))?; - // Nothing to do for ZSTs. - if size == Size::ZERO { + // Nothing to do for ZSTs. We use `is_bits` here because we *do* need to retag even ZSTs + // when there actually is a tag (to avoid inheriting a tag that would let us access more + // than 0 bytes). + if size == Size::ZERO && place.ptr.is_bits() { return Ok(*val); } diff --git a/tests/compile-fail/stacked_borrows/zst_slice.rs b/tests/compile-fail/stacked_borrows/zst_slice.rs new file mode 100644 index 0000000000000..0804f7303082d --- /dev/null +++ b/tests/compile-fail/stacked_borrows/zst_slice.rs @@ -0,0 +1,11 @@ +// compile-flags: -Zmiri-track-raw-pointers +// error-pattern: does not have an appropriate item in the borrow stack + +fn main() { + unsafe { + let a = [1, 2, 3]; + let s = &a[0..0]; + assert_eq!(s.len(), 0); + assert_eq!(*s.get_unchecked(1), 2); + } +} From 49cd383537580861f6bfd2daa6765409ca15b119 Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Sun, 28 Feb 2021 04:52:27 +0800 Subject: [PATCH 2558/3747] Create stub .d files --- cargo-miri/bin.rs | 8 ++++++++ test-cargo-miri/run-test.py | 25 ++++++++++++++----------- 2 files changed, 22 insertions(+), 11 deletions(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index 051f3dd3b6fc7..535acf36df73f 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -609,6 +609,14 @@ fn phase_cargo_rustc(mut args: env::Args) { let print = get_arg_flag_value("--print").is_some(); // whether this is cargo passing `--print` to get some infos let store_json = |info: CrateRunInfo| { + // Create a stub .d file to stop Cargo from "rebuilding" the crate: + // https://github.com/rust-lang/miri/issues/1724#issuecomment-787115693 + // As we store a JSON file instead of building the crate here, an empty file is fine. + let dep_info_name = out_filename("", ".d"); + if verbose { + eprintln!("[cargo-miri rustc] writing dep-info to `{}`", dep_info_name.display()); + } + File::create(dep_info_name).expect("failed to create fake .d file"); let filename = out_filename("", ""); if verbose { eprintln!("[cargo-miri rustc] writing run info to `{}`", filename.display()); diff --git a/test-cargo-miri/run-test.py b/test-cargo-miri/run-test.py index b9259b7d0d225..3a8a32db1ede6 100755 --- a/test-cargo-miri/run-test.py +++ b/test-cargo-miri/run-test.py @@ -50,12 +50,15 @@ def test(name, cmd, stdout_ref, stderr_ref, stdin=b'', env={}): print("--- END stderr ---") fail("exit code was {}".format(p.returncode)) -def test_no_rebuild(name, cmd): +def test_no_rebuild(name, cmd, env={}): print("Testing {}...".format(name)) + p_env = os.environ.copy() + p_env.update(env) p = subprocess.Popen( cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, + env=p_env, ) (stdout, stderr) = p.communicate() stdout = stdout.decode("UTF-8") @@ -70,14 +73,20 @@ def test_no_rebuild(name, cmd): fail("Something was being rebuilt when it should not be (or we got no output)"); def test_cargo_miri_run(): + default_env={ + 'MIRIFLAGS': "-Zmiri-disable-isolation", + 'MIRITESTVAR': "wrongval", # make sure the build.rs value takes precedence + } test("`cargo miri run` (no isolation)", cargo_miri("run"), "run.default.stdout.ref", "run.default.stderr.ref", stdin=b'12\n21\n', - env={ - 'MIRIFLAGS': "-Zmiri-disable-isolation", - 'MIRITESTVAR': "wrongval", # make sure the build.rs value takes precedence - }, + env=default_env, + ) + # Special test: run it again *without* `-q` to make sure nothing is being rebuilt (Miri issue #1722) + test_no_rebuild("`cargo miri run` (no rebuild, no isolation)", + cargo_miri("run", quiet=False) + ["--", ""], + env=default_env, ) test("`cargo miri run` (with arguments and target)", cargo_miri("run") + ["--bin", "cargo-miri-test", "--", "hello world", '"hello world"'], @@ -88,12 +97,6 @@ def test_cargo_miri_run(): "run.subcrate.stdout.ref", "run.subcrate.stderr.ref", env={'MIRIFLAGS': "-Zmiri-disable-isolation"}, ) - # Special test: run it again *without* `-q` to make sure nothing is being rebuilt (Miri issue #1722) - # FIXME: move this test up to right after the first `test` - # (currently that fails, only the 3rd and later runs are really clean... see Miri issue #1722) - test_no_rebuild("`cargo miri run` (no rebuild)", - cargo_miri("run", quiet=False) + ["--", ""], - ) def test_cargo_miri_test(): # rustdoc is not run on foreign targets From 9c1342b152a124c4f0e8869f626bb1a6b1ef072f Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Sun, 28 Feb 2021 15:57:49 +0800 Subject: [PATCH 2559/3747] Clarify that the "dep-info" is fake and add a newline --- cargo-miri/bin.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index 535acf36df73f..2cd0c0c972f55 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -614,9 +614,10 @@ fn phase_cargo_rustc(mut args: env::Args) { // As we store a JSON file instead of building the crate here, an empty file is fine. let dep_info_name = out_filename("", ".d"); if verbose { - eprintln!("[cargo-miri rustc] writing dep-info to `{}`", dep_info_name.display()); + eprintln!("[cargo-miri rustc] writing stub dep-info to `{}`", dep_info_name.display()); } File::create(dep_info_name).expect("failed to create fake .d file"); + let filename = out_filename("", ""); if verbose { eprintln!("[cargo-miri rustc] writing run info to `{}`", filename.display()); From 46af1890a51db4b7f6ca122123704fef65980a5c Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Sun, 28 Feb 2021 16:10:35 +0800 Subject: [PATCH 2560/3747] Drop MIRIFLAGS from "no rebuild" test --- test-cargo-miri/run-test.py | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/test-cargo-miri/run-test.py b/test-cargo-miri/run-test.py index 3a8a32db1ede6..36c6af87d8946 100755 --- a/test-cargo-miri/run-test.py +++ b/test-cargo-miri/run-test.py @@ -73,20 +73,19 @@ def test_no_rebuild(name, cmd, env={}): fail("Something was being rebuilt when it should not be (or we got no output)"); def test_cargo_miri_run(): - default_env={ - 'MIRIFLAGS': "-Zmiri-disable-isolation", - 'MIRITESTVAR': "wrongval", # make sure the build.rs value takes precedence - } test("`cargo miri run` (no isolation)", cargo_miri("run"), "run.default.stdout.ref", "run.default.stderr.ref", stdin=b'12\n21\n', - env=default_env, + env={ + 'MIRIFLAGS': "-Zmiri-disable-isolation", + 'MIRITESTVAR': "wrongval", # make sure the build.rs value takes precedence + }, ) # Special test: run it again *without* `-q` to make sure nothing is being rebuilt (Miri issue #1722) test_no_rebuild("`cargo miri run` (no rebuild, no isolation)", cargo_miri("run", quiet=False) + ["--", ""], - env=default_env, + env={'MIRITESTVAR': "wrongval"}, ) test("`cargo miri run` (with arguments and target)", cargo_miri("run") + ["--bin", "cargo-miri-test", "--", "hello world", '"hello world"'], From 6d5ce21c92de3bb2bfb9976cf278e7ae11f69d6b Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Sun, 28 Feb 2021 18:13:17 +0800 Subject: [PATCH 2561/3747] Cleanup test-cargo-miri/run-test.py --- test-cargo-miri/run-test.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/test-cargo-miri/run-test.py b/test-cargo-miri/run-test.py index 36c6af87d8946..81f589705dc33 100755 --- a/test-cargo-miri/run-test.py +++ b/test-cargo-miri/run-test.py @@ -83,9 +83,10 @@ def test_cargo_miri_run(): }, ) # Special test: run it again *without* `-q` to make sure nothing is being rebuilt (Miri issue #1722) - test_no_rebuild("`cargo miri run` (no rebuild, no isolation)", + test_no_rebuild("`cargo miri run` (no rebuild)", cargo_miri("run", quiet=False) + ["--", ""], - env={'MIRITESTVAR': "wrongval"}, + env={'MIRITESTVAR': "wrongval"}, # changing the env var causes a rebuild (re-runs build.rs), + # so keep it set ) test("`cargo miri run` (with arguments and target)", cargo_miri("run") + ["--bin", "cargo-miri-test", "--", "hello world", '"hello world"'], From df2d498a05ab0b250b468e5bce54ee2a43f641e2 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 2 Mar 2021 10:16:44 +0100 Subject: [PATCH 2562/3747] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index f76caa2c0f335..059dfeb2e6d35 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -a4e595db8f12f9ee926256745d757004b850703f +d2731d8e9338d8fe844e19d3fbb39617753e65f4 From 7acf80d2bb7c50c2f60807cb3f543955e7fef677 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 2 Mar 2021 10:44:06 +0100 Subject: [PATCH 2563/3747] rustup; fix tests for new MIR optimization --- rust-version | 2 +- .../data_race/dealloc_read_race_stack.rs | 8 +-- .../data_race/dealloc_read_race_stack_drop.rs | 52 ------------------ .../data_race/dealloc_write_race_stack.rs | 8 +-- .../dealloc_write_race_stack_drop.rs | 53 ------------------- ...lock_read_write_deadlock_single_thread.rs} | 3 +- ...wlock_write_read_deadlock_single_thread.rs | 3 +- ...lock_write_write_deadlock_single_thread.rs | 3 +- 8 files changed, 15 insertions(+), 117 deletions(-) delete mode 100644 tests/compile-fail/data_race/dealloc_read_race_stack_drop.rs delete mode 100644 tests/compile-fail/data_race/dealloc_write_race_stack_drop.rs rename tests/compile-fail/sync/{libc_pthread_rwlock_read_write_deadlock.rs => libc_pthread_rwlock_read_write_deadlock_single_thread.rs} (77%) diff --git a/rust-version b/rust-version index 059dfeb2e6d35..65644e75d9770 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -d2731d8e9338d8fe844e19d3fbb39617753e65f4 +09db05762b283bed62d4f92729cfee4646519833 diff --git a/tests/compile-fail/data_race/dealloc_read_race_stack.rs b/tests/compile-fail/data_race/dealloc_read_race_stack.rs index 31960fb2162bf..281aff8631468 100644 --- a/tests/compile-fail/data_race/dealloc_read_race_stack.rs +++ b/tests/compile-fail/data_race/dealloc_read_race_stack.rs @@ -1,5 +1,6 @@ // ignore-windows: Concurrency on Windows is not supported yet. -// compile-flags: -Zmiri-disable-isolation +// compile-flags: -Zmiri-disable-isolation -Zmir-opt-level=0 +// With optimizations (in particular #78360), the span becomes much worse, so we disable them. use std::thread::{spawn, sleep}; use std::ptr::null_mut; @@ -27,9 +28,6 @@ pub fn main() { // 3. stack-deallocate unsafe { let j1 = spawn(move || { - // Concurrent allocate the memory. - // Uses relaxed semantics to not generate - // a release sequence. let pointer = &*ptr.0; { let mut stack_var = 0usize; @@ -38,6 +36,8 @@ pub fn main() { sleep(Duration::from_millis(200)); + // Now `stack_var` gets deallocated. + } //~ ERROR Data race detected between Deallocate on Thread(id = 1) and Read on Thread(id = 2) }); diff --git a/tests/compile-fail/data_race/dealloc_read_race_stack_drop.rs b/tests/compile-fail/data_race/dealloc_read_race_stack_drop.rs deleted file mode 100644 index 44950a34db2f8..0000000000000 --- a/tests/compile-fail/data_race/dealloc_read_race_stack_drop.rs +++ /dev/null @@ -1,52 +0,0 @@ -// ignore-windows: Concurrency on Windows is not supported yet. -// compile-flags: -Zmiri-disable-isolation - -use std::thread::{spawn, sleep}; -use std::ptr::null_mut; -use std::sync::atomic::{Ordering, AtomicPtr}; -use std::time::Duration; - -#[derive(Copy, Clone)] -struct EvilSend(pub T); - -unsafe impl Send for EvilSend {} -unsafe impl Sync for EvilSend {} - -pub fn main() { - // Shared atomic pointer - let pointer = AtomicPtr::new(null_mut::()); - let ptr = EvilSend(&pointer as *const AtomicPtr); - - // Note: this is scheduler-dependent - // the operations need to occur in - // order, otherwise the allocation is - // not visible to the other-thread to - // detect the race: - // 1. stack-allocate - // 2. read - // 3. stack-deallocate - unsafe { - let j1 = spawn(move || { - // Concurrent allocate the memory. - // Uses relaxed semantics to not generate - // a release sequence. - let pointer = &*ptr.0; - - let mut stack_var = 0usize; - - pointer.store(&mut stack_var as *mut _, Ordering::Release); - - sleep(Duration::from_millis(200)); - - drop(stack_var); - }); //~ ERROR Data race detected between Deallocate on Thread(id = 1) and Read on Thread(id = 2) - - let j2 = spawn(move || { - let pointer = &*ptr.0; - *pointer.load(Ordering::Acquire) - }); - - j1.join().unwrap(); - j2.join().unwrap(); - } -} diff --git a/tests/compile-fail/data_race/dealloc_write_race_stack.rs b/tests/compile-fail/data_race/dealloc_write_race_stack.rs index 25dea65fe7e09..55aaa0c1635a5 100644 --- a/tests/compile-fail/data_race/dealloc_write_race_stack.rs +++ b/tests/compile-fail/data_race/dealloc_write_race_stack.rs @@ -1,5 +1,6 @@ // ignore-windows: Concurrency on Windows is not supported yet. -// compile-flags: -Zmiri-disable-isolation +// compile-flags: -Zmiri-disable-isolation -Zmir-opt-level=0 +// With optimizations (in particular #78360), the span becomes much worse, so we disable them. use std::thread::{spawn, sleep}; use std::ptr::null_mut; @@ -27,9 +28,6 @@ pub fn main() { // 3. stack-deallocate unsafe { let j1 = spawn(move || { - // Concurrent allocate the memory. - // Uses relaxed semantics to not generate - // a release sequence. let pointer = &*ptr.0; { let mut stack_var = 0usize; @@ -38,6 +36,8 @@ pub fn main() { sleep(Duration::from_millis(200)); + // Now `stack_var` gets deallocated. + } //~ ERROR Data race detected between Deallocate on Thread(id = 1) and Write on Thread(id = 2) }); diff --git a/tests/compile-fail/data_race/dealloc_write_race_stack_drop.rs b/tests/compile-fail/data_race/dealloc_write_race_stack_drop.rs deleted file mode 100644 index 1d239e9eb74d0..0000000000000 --- a/tests/compile-fail/data_race/dealloc_write_race_stack_drop.rs +++ /dev/null @@ -1,53 +0,0 @@ -// ignore-windows: Concurrency on Windows is not supported yet. -// compile-flags: -Zmiri-disable-isolation - -use std::thread::{spawn, sleep}; -use std::ptr::null_mut; -use std::sync::atomic::{Ordering, AtomicPtr}; -use std::time::Duration; - -#[derive(Copy, Clone)] -struct EvilSend(pub T); - -unsafe impl Send for EvilSend {} -unsafe impl Sync for EvilSend {} - -pub fn main() { - // Shared atomic pointer - let pointer = AtomicPtr::new(null_mut::()); - let ptr = EvilSend(&pointer as *const AtomicPtr); - - // Note: this is scheduler-dependent - // the operations need to occur in - // order, otherwise the allocation is - // not visible to the other-thread to - // detect the race: - // 1. stack-allocate - // 2. read - // 3. stack-deallocate - unsafe { - let j1 = spawn(move || { - // Concurrent allocate the memory. - // Uses relaxed semantics to not generate - // a release sequence. - let pointer = &*ptr.0; - - let mut stack_var = 0usize; - - pointer.store(&mut stack_var as *mut _, Ordering::Release); - - sleep(Duration::from_millis(200)); - - // Note: Implicit read for drop(_) races with write, would detect race with deallocate after. - drop(stack_var); //~ ERROR Data race detected between Read on Thread(id = 1) and Write on Thread(id = 2) - }); - - let j2 = spawn(move || { - let pointer = &*ptr.0; - *pointer.load(Ordering::Acquire) = 3; - }); - - j1.join().unwrap(); - j2.join().unwrap(); - } -} diff --git a/tests/compile-fail/sync/libc_pthread_rwlock_read_write_deadlock.rs b/tests/compile-fail/sync/libc_pthread_rwlock_read_write_deadlock_single_thread.rs similarity index 77% rename from tests/compile-fail/sync/libc_pthread_rwlock_read_write_deadlock.rs rename to tests/compile-fail/sync/libc_pthread_rwlock_read_write_deadlock_single_thread.rs index dd4707d60e4ca..da45d062d03b8 100644 --- a/tests/compile-fail/sync/libc_pthread_rwlock_read_write_deadlock.rs +++ b/tests/compile-fail/sync/libc_pthread_rwlock_read_write_deadlock_single_thread.rs @@ -1,4 +1,5 @@ // ignore-windows: No libc on Windows +// error-pattern: deadlock #![feature(rustc_private)] @@ -8,6 +9,6 @@ fn main() { let rw = std::cell::UnsafeCell::new(libc::PTHREAD_RWLOCK_INITIALIZER); unsafe { assert_eq!(libc::pthread_rwlock_rdlock(rw.get()), 0); - libc::pthread_rwlock_wrlock(rw.get()); //~ ERROR: deadlock + libc::pthread_rwlock_wrlock(rw.get()); } } diff --git a/tests/compile-fail/sync/libc_pthread_rwlock_write_read_deadlock_single_thread.rs b/tests/compile-fail/sync/libc_pthread_rwlock_write_read_deadlock_single_thread.rs index 1b460e7174d28..ee2e57a9ab375 100644 --- a/tests/compile-fail/sync/libc_pthread_rwlock_write_read_deadlock_single_thread.rs +++ b/tests/compile-fail/sync/libc_pthread_rwlock_write_read_deadlock_single_thread.rs @@ -1,4 +1,5 @@ // ignore-windows: No libc on Windows +// error-pattern: deadlock #![feature(rustc_private)] @@ -8,6 +9,6 @@ fn main() { let rw = std::cell::UnsafeCell::new(libc::PTHREAD_RWLOCK_INITIALIZER); unsafe { assert_eq!(libc::pthread_rwlock_wrlock(rw.get()), 0); - libc::pthread_rwlock_rdlock(rw.get()); //~ ERROR: deadlock + libc::pthread_rwlock_rdlock(rw.get()); } } diff --git a/tests/compile-fail/sync/libc_pthread_rwlock_write_write_deadlock_single_thread.rs b/tests/compile-fail/sync/libc_pthread_rwlock_write_write_deadlock_single_thread.rs index cc327ec46bc29..f0404f202e561 100644 --- a/tests/compile-fail/sync/libc_pthread_rwlock_write_write_deadlock_single_thread.rs +++ b/tests/compile-fail/sync/libc_pthread_rwlock_write_write_deadlock_single_thread.rs @@ -1,4 +1,5 @@ // ignore-windows: No libc on Windows +// error-pattern: deadlock #![feature(rustc_private)] @@ -8,6 +9,6 @@ fn main() { let rw = std::cell::UnsafeCell::new(libc::PTHREAD_RWLOCK_INITIALIZER); unsafe { assert_eq!(libc::pthread_rwlock_wrlock(rw.get()), 0); - libc::pthread_rwlock_wrlock(rw.get()); //~ ERROR: deadlock + libc::pthread_rwlock_wrlock(rw.get()); } } From 97e45e0699e2fc8397b1e2cfb55743365d749b6e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 2 Mar 2021 11:04:35 +0100 Subject: [PATCH 2564/3747] make optimized-test-run a bit more like what cargo does --- ci.sh | 5 +++-- tests/compile-fail/data_race/dealloc_read_race_stack.rs | 3 +-- tests/compile-fail/data_race/dealloc_write_race_stack.rs | 3 +-- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/ci.sh b/ci.sh index a1f4a00139461..3484040119cae 100755 --- a/ci.sh +++ b/ci.sh @@ -24,8 +24,9 @@ function run_tests { ./miri test --locked if [ -z "${MIRI_TEST_TARGET+exists}" ]; then - # Only for host architecture: tests with MIR optimizations - MIRIFLAGS="-Z mir-opt-level=3" ./miri test --locked + # Only for host architecture: tests with optimizations (`-O` is what cargo passes, but crank MIR + # optimizations up all the way). + MIRIFLAGS="-O -Zmir-opt-level=3" ./miri test --locked fi # On Windows, there is always "python", not "python3" or "python2". diff --git a/tests/compile-fail/data_race/dealloc_read_race_stack.rs b/tests/compile-fail/data_race/dealloc_read_race_stack.rs index 281aff8631468..6b573121e5992 100644 --- a/tests/compile-fail/data_race/dealloc_read_race_stack.rs +++ b/tests/compile-fail/data_race/dealloc_read_race_stack.rs @@ -1,6 +1,5 @@ // ignore-windows: Concurrency on Windows is not supported yet. -// compile-flags: -Zmiri-disable-isolation -Zmir-opt-level=0 -// With optimizations (in particular #78360), the span becomes much worse, so we disable them. +// compile-flags: -Zmiri-disable-isolation use std::thread::{spawn, sleep}; use std::ptr::null_mut; diff --git a/tests/compile-fail/data_race/dealloc_write_race_stack.rs b/tests/compile-fail/data_race/dealloc_write_race_stack.rs index 55aaa0c1635a5..34a16b00b83d3 100644 --- a/tests/compile-fail/data_race/dealloc_write_race_stack.rs +++ b/tests/compile-fail/data_race/dealloc_write_race_stack.rs @@ -1,6 +1,5 @@ // ignore-windows: Concurrency on Windows is not supported yet. -// compile-flags: -Zmiri-disable-isolation -Zmir-opt-level=0 -// With optimizations (in particular #78360), the span becomes much worse, so we disable them. +// compile-flags: -Zmiri-disable-isolation use std::thread::{spawn, sleep}; use std::ptr::null_mut; From 2902ad91deb5593dca3ee98b8bfa869747240e65 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 2 Mar 2021 11:09:06 +0100 Subject: [PATCH 2565/3747] add date to Zulip notification subject --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a55cd8212517e..d3d5d65bb94ed 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -129,7 +129,7 @@ jobs: ZULIP_BOT_EMAIL: ${{ secrets.ZULIP_BOT_EMAIL }} ZULIP_API_TOKEN: ${{ secrets.ZULIP_API_TOKEN }} run: | - ~/.local/bin/zulip-send --stream miri --subject "Cron Job Failure" \ + ~/.local/bin/zulip-send --stream miri --subject "Cron Job Failure $(date -uI)" \ --message 'Dear @**RalfJ** and @**oli** It would appear that the Miri cron job build failed. Would you mind investigating this issue? From 47ec9b878e7d9bb308e7991b69a76d98641c793f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 2 Mar 2021 11:24:56 +0100 Subject: [PATCH 2566/3747] adjust CI test flags --- ci.sh | 2 -- 1 file changed, 2 deletions(-) diff --git a/ci.sh b/ci.sh index a1f4a00139461..8b0280b25787e 100755 --- a/ci.sh +++ b/ci.sh @@ -2,8 +2,6 @@ set -euo pipefail # Determine configuration -export RUST_TEST_NOCAPTURE=1 -export RUST_BACKTRACE=1 export RUSTFLAGS="-D warnings" export CARGO_INCREMENTAL=0 export CARGO_EXTRA_FLAGS="--all-features" From 7d1531f3c134859fc4f733ebddcfd38a8987d5cf Mon Sep 17 00:00:00 2001 From: Henry Boisdequin <65845077+henryboisdequin@users.noreply.github.com> Date: Tue, 2 Mar 2021 18:06:12 +0530 Subject: [PATCH 2567/3747] fmt data_race.rs and intrinsics.rs --- src/data_race.rs | 6 +- src/shims/intrinsics.rs | 297 +++++++++++++++++++++++++++------------- 2 files changed, 205 insertions(+), 98 deletions(-) diff --git a/src/data_race.rs b/src/data_race.rs index dcff896c1f161..c7bafb60a6191 100644 --- a/src/data_race.rs +++ b/src/data_race.rs @@ -263,7 +263,7 @@ impl MemoryCellClocks { atomic_ops: None, } } - + /// Load the internal atomic memory cells if they exist. #[inline] fn atomic(&self) -> Option<&AtomicMemoryCellClocks> { @@ -323,7 +323,7 @@ impl MemoryCellClocks { /// store relaxed semantics. fn store_relaxed(&mut self, clocks: &ThreadClockSet, index: VectorIdx) -> Result<(), DataRace> { self.atomic_write_detect(clocks, index)?; - + // The handling of release sequences was changed in C++20 and so // the code here is different to the paper since now all relaxed // stores block release sequences. The exception for same-thread @@ -678,7 +678,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { // Either Release | AcqRel | SeqCst clocks.apply_release_fence(); } - + // Increment timestamp in case of release semantics. Ok(atomic != AtomicFenceOp::Acquire) }) diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 33aa7b28bb5b5..f9ec62d7514d6 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -2,9 +2,9 @@ use std::iter; use log::trace; -use rustc_middle::{mir, mir::BinOp, ty, ty::FloatTy}; -use rustc_middle::ty::layout::IntegerExt; use rustc_apfloat::{Float, Round}; +use rustc_middle::ty::layout::IntegerExt; +use rustc_middle::{mir, mir::BinOp, ty, ty::FloatTy}; use rustc_target::abi::{Align, Integer, LayoutOf}; use crate::*; @@ -67,8 +67,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let val_byte = this.read_scalar(val_byte)?.to_u8()?; let ptr = this.read_scalar(ptr)?.check_init()?; let count = this.read_scalar(count)?.to_machine_usize(this)?; - let byte_count = ty_layout.size.checked_mul(count, this) - .ok_or_else(|| err_ub_format!("overflow computing total size of `write_bytes`"))?; + let byte_count = ty_layout.size.checked_mul(count, this).ok_or_else(|| { + err_ub_format!("overflow computing total size of `write_bytes`") + })?; this.memory .write_bytes(ptr, iter::repeat(val_byte).take(byte_count.bytes() as usize))?; } @@ -258,13 +259,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let val = this.read_immediate(val)?; let res = match val.layout.ty.kind() { - ty::Float(FloatTy::F32) => { - this.float_to_int_unchecked(val.to_scalar()?.to_f32()?, dest.layout.ty)? - } - ty::Float(FloatTy::F64) => { - this.float_to_int_unchecked(val.to_scalar()?.to_f64()?, dest.layout.ty)? - } - _ => bug!("`float_to_int_unchecked` called with non-float input type {:?}", val.layout.ty), + ty::Float(FloatTy::F32) => + this.float_to_int_unchecked(val.to_scalar()?.to_f32()?, dest.layout.ty)?, + ty::Float(FloatTy::F64) => + this.float_to_int_unchecked(val.to_scalar()?.to_f64()?, dest.layout.ty)?, + _ => bug!( + "`float_to_int_unchecked` called with non-float input type {:?}", + val.layout.ty + ), }; this.write_scalar(res, dest)?; @@ -286,7 +288,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "atomic_singlethreadfence_acq" => this.compiler_fence(args, AtomicFenceOp::Acquire)?, "atomic_singlethreadfence_rel" => this.compiler_fence(args, AtomicFenceOp::Release)?, - "atomic_singlethreadfence_acqrel" => this.compiler_fence(args, AtomicFenceOp::AcqRel)?, + "atomic_singlethreadfence_acqrel" => + this.compiler_fence(args, AtomicFenceOp::AcqRel)?, "atomic_singlethreadfence" => this.compiler_fence(args, AtomicFenceOp::SeqCst)?, "atomic_xchg" => this.atomic_exchange(args, dest, AtomicRwOp::SeqCst)?, @@ -295,110 +298,179 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "atomic_xchg_acqrel" => this.atomic_exchange(args, dest, AtomicRwOp::AcqRel)?, "atomic_xchg_relaxed" => this.atomic_exchange(args, dest, AtomicRwOp::Relaxed)?, - "atomic_cxchg" => this.atomic_compare_exchange( - args, dest, AtomicRwOp::SeqCst, AtomicReadOp::SeqCst - )?, + "atomic_cxchg" => + this.atomic_compare_exchange(args, dest, AtomicRwOp::SeqCst, AtomicReadOp::SeqCst)?, "atomic_cxchg_acq" => this.atomic_compare_exchange( - args, dest, AtomicRwOp::Acquire, AtomicReadOp::Acquire + args, + dest, + AtomicRwOp::Acquire, + AtomicReadOp::Acquire, )?, "atomic_cxchg_rel" => this.atomic_compare_exchange( - args, dest, AtomicRwOp::Release, AtomicReadOp::Relaxed - )?, - "atomic_cxchg_acqrel" => this.atomic_compare_exchange - (args, dest, AtomicRwOp::AcqRel, AtomicReadOp::Acquire + args, + dest, + AtomicRwOp::Release, + AtomicReadOp::Relaxed, )?, + "atomic_cxchg_acqrel" => + this.atomic_compare_exchange(args, dest, AtomicRwOp::AcqRel, AtomicReadOp::Acquire)?, "atomic_cxchg_relaxed" => this.atomic_compare_exchange( - args, dest, AtomicRwOp::Relaxed, AtomicReadOp::Relaxed + args, + dest, + AtomicRwOp::Relaxed, + AtomicReadOp::Relaxed, )?, "atomic_cxchg_acq_failrelaxed" => this.atomic_compare_exchange( - args, dest, AtomicRwOp::Acquire, AtomicReadOp::Relaxed - )?, - "atomic_cxchg_acqrel_failrelaxed" => this.atomic_compare_exchange( - args, dest, AtomicRwOp::AcqRel, AtomicReadOp::Relaxed - )?, - "atomic_cxchg_failrelaxed" => this.atomic_compare_exchange( - args, dest, AtomicRwOp::SeqCst, AtomicReadOp::Relaxed - )?, - "atomic_cxchg_failacq" => this.atomic_compare_exchange( - args, dest, AtomicRwOp::SeqCst, AtomicReadOp::Acquire + args, + dest, + AtomicRwOp::Acquire, + AtomicReadOp::Relaxed, )?, + "atomic_cxchg_acqrel_failrelaxed" => + this.atomic_compare_exchange(args, dest, AtomicRwOp::AcqRel, AtomicReadOp::Relaxed)?, + "atomic_cxchg_failrelaxed" => + this.atomic_compare_exchange(args, dest, AtomicRwOp::SeqCst, AtomicReadOp::Relaxed)?, + "atomic_cxchg_failacq" => + this.atomic_compare_exchange(args, dest, AtomicRwOp::SeqCst, AtomicReadOp::Acquire)?, "atomic_cxchgweak" => this.atomic_compare_exchange_weak( - args, dest, AtomicRwOp::SeqCst, AtomicReadOp::SeqCst + args, + dest, + AtomicRwOp::SeqCst, + AtomicReadOp::SeqCst, )?, "atomic_cxchgweak_acq" => this.atomic_compare_exchange_weak( - args, dest, AtomicRwOp::Acquire, AtomicReadOp::Acquire + args, + dest, + AtomicRwOp::Acquire, + AtomicReadOp::Acquire, )?, "atomic_cxchgweak_rel" => this.atomic_compare_exchange_weak( - args, dest, AtomicRwOp::Release, AtomicReadOp::Relaxed + args, + dest, + AtomicRwOp::Release, + AtomicReadOp::Relaxed, )?, "atomic_cxchgweak_acqrel" => this.atomic_compare_exchange_weak( - args, dest, AtomicRwOp::AcqRel, AtomicReadOp::Acquire + args, + dest, + AtomicRwOp::AcqRel, + AtomicReadOp::Acquire, )?, "atomic_cxchgweak_relaxed" => this.atomic_compare_exchange_weak( - args, dest, AtomicRwOp::Relaxed, AtomicReadOp::Relaxed + args, + dest, + AtomicRwOp::Relaxed, + AtomicReadOp::Relaxed, )?, "atomic_cxchgweak_acq_failrelaxed" => this.atomic_compare_exchange_weak( - args, dest, AtomicRwOp::Acquire, AtomicReadOp::Relaxed + args, + dest, + AtomicRwOp::Acquire, + AtomicReadOp::Relaxed, )?, "atomic_cxchgweak_acqrel_failrelaxed" => this.atomic_compare_exchange_weak( - args, dest, AtomicRwOp::AcqRel, AtomicReadOp::Relaxed + args, + dest, + AtomicRwOp::AcqRel, + AtomicReadOp::Relaxed, )?, "atomic_cxchgweak_failrelaxed" => this.atomic_compare_exchange_weak( - args, dest, AtomicRwOp::SeqCst, AtomicReadOp::Relaxed + args, + dest, + AtomicRwOp::SeqCst, + AtomicReadOp::Relaxed, )?, "atomic_cxchgweak_failacq" => this.atomic_compare_exchange_weak( - args, dest, AtomicRwOp::SeqCst, AtomicReadOp::Acquire + args, + dest, + AtomicRwOp::SeqCst, + AtomicReadOp::Acquire, )?, "atomic_or" => this.atomic_op(args, dest, BinOp::BitOr, false, AtomicRwOp::SeqCst)?, - "atomic_or_acq" => this.atomic_op(args, dest, BinOp::BitOr, false, AtomicRwOp::Acquire)?, - "atomic_or_rel" => this.atomic_op(args, dest, BinOp::BitOr, false, AtomicRwOp::Release)?, - "atomic_or_acqrel" => this.atomic_op(args, dest, BinOp::BitOr, false, AtomicRwOp::AcqRel)?, - "atomic_or_relaxed" => this.atomic_op(args, dest, BinOp::BitOr, false, AtomicRwOp::Relaxed)?, + "atomic_or_acq" => + this.atomic_op(args, dest, BinOp::BitOr, false, AtomicRwOp::Acquire)?, + "atomic_or_rel" => + this.atomic_op(args, dest, BinOp::BitOr, false, AtomicRwOp::Release)?, + "atomic_or_acqrel" => + this.atomic_op(args, dest, BinOp::BitOr, false, AtomicRwOp::AcqRel)?, + "atomic_or_relaxed" => + this.atomic_op(args, dest, BinOp::BitOr, false, AtomicRwOp::Relaxed)?, "atomic_xor" => this.atomic_op(args, dest, BinOp::BitXor, false, AtomicRwOp::SeqCst)?, - "atomic_xor_acq" => this.atomic_op(args, dest, BinOp::BitXor, false, AtomicRwOp::Acquire)?, - "atomic_xor_rel" => this.atomic_op(args, dest, BinOp::BitXor, false, AtomicRwOp::Release)?, - "atomic_xor_acqrel" => this.atomic_op(args, dest, BinOp::BitXor, false, AtomicRwOp::AcqRel)?, - "atomic_xor_relaxed" => this.atomic_op(args, dest, BinOp::BitXor, false, AtomicRwOp::Relaxed)?, + "atomic_xor_acq" => + this.atomic_op(args, dest, BinOp::BitXor, false, AtomicRwOp::Acquire)?, + "atomic_xor_rel" => + this.atomic_op(args, dest, BinOp::BitXor, false, AtomicRwOp::Release)?, + "atomic_xor_acqrel" => + this.atomic_op(args, dest, BinOp::BitXor, false, AtomicRwOp::AcqRel)?, + "atomic_xor_relaxed" => + this.atomic_op(args, dest, BinOp::BitXor, false, AtomicRwOp::Relaxed)?, "atomic_and" => this.atomic_op(args, dest, BinOp::BitAnd, false, AtomicRwOp::SeqCst)?, - "atomic_and_acq" => this.atomic_op(args, dest, BinOp::BitAnd, false, AtomicRwOp::Acquire)?, - "atomic_and_rel" => this.atomic_op(args, dest, BinOp::BitAnd, false, AtomicRwOp::Release)?, - "atomic_and_acqrel" => this.atomic_op(args, dest, BinOp::BitAnd, false, AtomicRwOp::AcqRel)?, - "atomic_and_relaxed" => this.atomic_op(args, dest, BinOp::BitAnd, false, AtomicRwOp::Relaxed)?, + "atomic_and_acq" => + this.atomic_op(args, dest, BinOp::BitAnd, false, AtomicRwOp::Acquire)?, + "atomic_and_rel" => + this.atomic_op(args, dest, BinOp::BitAnd, false, AtomicRwOp::Release)?, + "atomic_and_acqrel" => + this.atomic_op(args, dest, BinOp::BitAnd, false, AtomicRwOp::AcqRel)?, + "atomic_and_relaxed" => + this.atomic_op(args, dest, BinOp::BitAnd, false, AtomicRwOp::Relaxed)?, "atomic_nand" => this.atomic_op(args, dest, BinOp::BitAnd, true, AtomicRwOp::SeqCst)?, - "atomic_nand_acq" => this.atomic_op(args, dest, BinOp::BitAnd, true, AtomicRwOp::Acquire)?, - "atomic_nand_rel" => this.atomic_op(args, dest, BinOp::BitAnd, true, AtomicRwOp::Release)?, - "atomic_nand_acqrel" => this.atomic_op(args, dest, BinOp::BitAnd, true, AtomicRwOp::AcqRel)?, - "atomic_nand_relaxed" => this.atomic_op(args, dest, BinOp::BitAnd, true, AtomicRwOp::Relaxed)?, + "atomic_nand_acq" => + this.atomic_op(args, dest, BinOp::BitAnd, true, AtomicRwOp::Acquire)?, + "atomic_nand_rel" => + this.atomic_op(args, dest, BinOp::BitAnd, true, AtomicRwOp::Release)?, + "atomic_nand_acqrel" => + this.atomic_op(args, dest, BinOp::BitAnd, true, AtomicRwOp::AcqRel)?, + "atomic_nand_relaxed" => + this.atomic_op(args, dest, BinOp::BitAnd, true, AtomicRwOp::Relaxed)?, "atomic_xadd" => this.atomic_op(args, dest, BinOp::Add, false, AtomicRwOp::SeqCst)?, - "atomic_xadd_acq" => this.atomic_op(args, dest, BinOp::Add, false, AtomicRwOp::Acquire)?, - "atomic_xadd_rel" => this.atomic_op(args, dest, BinOp::Add, false, AtomicRwOp::Release)?, - "atomic_xadd_acqrel" => this.atomic_op(args, dest, BinOp::Add, false, AtomicRwOp::AcqRel)?, - "atomic_xadd_relaxed" => this.atomic_op(args, dest, BinOp::Add, false, AtomicRwOp::Relaxed)?, + "atomic_xadd_acq" => + this.atomic_op(args, dest, BinOp::Add, false, AtomicRwOp::Acquire)?, + "atomic_xadd_rel" => + this.atomic_op(args, dest, BinOp::Add, false, AtomicRwOp::Release)?, + "atomic_xadd_acqrel" => + this.atomic_op(args, dest, BinOp::Add, false, AtomicRwOp::AcqRel)?, + "atomic_xadd_relaxed" => + this.atomic_op(args, dest, BinOp::Add, false, AtomicRwOp::Relaxed)?, "atomic_xsub" => this.atomic_op(args, dest, BinOp::Sub, false, AtomicRwOp::SeqCst)?, - "atomic_xsub_acq" => this.atomic_op(args, dest, BinOp::Sub, false, AtomicRwOp::Acquire)?, - "atomic_xsub_rel" => this.atomic_op(args, dest, BinOp::Sub, false, AtomicRwOp::Release)?, - "atomic_xsub_acqrel" => this.atomic_op(args, dest, BinOp::Sub, false, AtomicRwOp::AcqRel)?, - "atomic_xsub_relaxed" => this.atomic_op(args, dest, BinOp::Sub, false, AtomicRwOp::Relaxed)?, - + "atomic_xsub_acq" => + this.atomic_op(args, dest, BinOp::Sub, false, AtomicRwOp::Acquire)?, + "atomic_xsub_rel" => + this.atomic_op(args, dest, BinOp::Sub, false, AtomicRwOp::Release)?, + "atomic_xsub_acqrel" => + this.atomic_op(args, dest, BinOp::Sub, false, AtomicRwOp::AcqRel)?, + "atomic_xsub_relaxed" => + this.atomic_op(args, dest, BinOp::Sub, false, AtomicRwOp::Relaxed)?, // Query type information - "assert_zero_valid" | - "assert_uninit_valid" => { + "assert_zero_valid" | "assert_uninit_valid" => { let &[] = check_arg_count(args)?; let ty = instance.substs.type_at(0); let layout = this.layout_of(ty)?; // Abort here because the caller might not be panic safe. if layout.abi.is_uninhabited() { // Use this message even for the other intrinsics, as that's what codegen does - throw_machine_stop!(TerminationInfo::Abort(format!("aborted execution: attempted to instantiate uninhabited type `{}`", ty))) + throw_machine_stop!(TerminationInfo::Abort(format!( + "aborted execution: attempted to instantiate uninhabited type `{}`", + ty + ))) } - if intrinsic_name == "assert_zero_valid" && !layout.might_permit_raw_init(this, /*zero:*/ true).unwrap() { - throw_machine_stop!(TerminationInfo::Abort(format!("aborted execution: attempted to zero-initialize type `{}`, which is invalid", ty))) + if intrinsic_name == "assert_zero_valid" + && !layout.might_permit_raw_init(this, /*zero:*/ true).unwrap() + { + throw_machine_stop!(TerminationInfo::Abort(format!( + "aborted execution: attempted to zero-initialize type `{}`, which is invalid", + ty + ))) } - if intrinsic_name == "assert_uninit_valid" && !layout.might_permit_raw_init(this, /*zero:*/ false).unwrap() { - throw_machine_stop!(TerminationInfo::Abort(format!("aborted execution: attempted to leave type `{}` uninitialized, which is invalid", ty))) + if intrinsic_name == "assert_uninit_valid" + && !layout.might_permit_raw_init(this, /*zero:*/ false).unwrap() + { + throw_machine_stop!(TerminationInfo::Abort(format!( + "aborted execution: attempted to leave type `{}` uninitialized, which is invalid", + ty + ))) } } @@ -419,12 +491,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } fn atomic_load( - &mut self, args: &[OpTy<'tcx, Tag>], dest: &PlaceTy<'tcx, Tag>, - atomic: AtomicReadOp + &mut self, + args: &[OpTy<'tcx, Tag>], + dest: &PlaceTy<'tcx, Tag>, + atomic: AtomicReadOp, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - let &[ref place] = check_arg_count(args)?; let place = this.deref_operand(place)?; @@ -440,7 +513,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(()) } - fn atomic_store(&mut self, args: &[OpTy<'tcx, Tag>], atomic: AtomicWriteOp) -> InterpResult<'tcx> { + fn atomic_store( + &mut self, + args: &[OpTy<'tcx, Tag>], + atomic: AtomicWriteOp, + ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let &[ref place, ref val] = check_arg_count(args)?; @@ -458,14 +535,22 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(()) } - fn compiler_fence(&mut self, args: &[OpTy<'tcx, Tag>], atomic: AtomicFenceOp) -> InterpResult<'tcx> { + fn compiler_fence( + &mut self, + args: &[OpTy<'tcx, Tag>], + atomic: AtomicFenceOp, + ) -> InterpResult<'tcx> { let &[] = check_arg_count(args)?; let _ = atomic; //FIXME: compiler fences are currently ignored Ok(()) } - fn atomic_fence(&mut self, args: &[OpTy<'tcx, Tag>], atomic: AtomicFenceOp) -> InterpResult<'tcx> { + fn atomic_fence( + &mut self, + args: &[OpTy<'tcx, Tag>], + atomic: AtomicFenceOp, + ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let &[] = check_arg_count(args)?; this.validate_atomic_fence(atomic)?; @@ -473,8 +558,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } fn atomic_op( - &mut self, args: &[OpTy<'tcx, Tag>], dest: &PlaceTy<'tcx, Tag>, - op: mir::BinOp, neg: bool, atomic: AtomicRwOp + &mut self, + args: &[OpTy<'tcx, Tag>], + dest: &PlaceTy<'tcx, Tag>, + op: mir::BinOp, + neg: bool, + atomic: AtomicRwOp, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); @@ -490,14 +579,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // be 8-aligned). let align = Align::from_bytes(place.layout.size.bytes()).unwrap(); this.memory.check_ptr_access(place.ptr, place.layout.size, align)?; - + let old = this.atomic_op_immediate(&place, &rhs, op, neg, atomic)?; this.write_immediate(*old, dest)?; // old value is returned Ok(()) } - + fn atomic_exchange( - &mut self, args: &[OpTy<'tcx, Tag>], dest: &PlaceTy<'tcx, Tag>, atomic: AtomicRwOp + &mut self, + args: &[OpTy<'tcx, Tag>], + dest: &PlaceTy<'tcx, Tag>, + atomic: AtomicRwOp, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); @@ -517,8 +609,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } fn atomic_compare_exchange_impl( - &mut self, args: &[OpTy<'tcx, Tag>], dest: &PlaceTy<'tcx, Tag>, - success: AtomicRwOp, fail: AtomicReadOp, can_fail_spuriously: bool + &mut self, + args: &[OpTy<'tcx, Tag>], + dest: &PlaceTy<'tcx, Tag>, + success: AtomicRwOp, + fail: AtomicReadOp, + can_fail_spuriously: bool, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); @@ -527,16 +623,19 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let expect_old = this.read_immediate(expect_old)?; // read as immediate for the sake of `binary_op()` let new = this.read_scalar(new)?; - // Check alignment requirements. Atomics must always be aligned to their size, // even if the type they wrap would be less aligned (e.g. AtomicU64 on 32bit must // be 8-aligned). let align = Align::from_bytes(place.layout.size.bytes()).unwrap(); this.memory.check_ptr_access(place.ptr, place.layout.size, align)?; - let old = this.atomic_compare_exchange_scalar( - &place, &expect_old, new, success, fail, can_fail_spuriously + &place, + &expect_old, + new, + success, + fail, + can_fail_spuriously, )?; // Return old value. @@ -545,15 +644,21 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } fn atomic_compare_exchange( - &mut self, args: &[OpTy<'tcx, Tag>], dest: &PlaceTy<'tcx, Tag>, - success: AtomicRwOp, fail: AtomicReadOp + &mut self, + args: &[OpTy<'tcx, Tag>], + dest: &PlaceTy<'tcx, Tag>, + success: AtomicRwOp, + fail: AtomicReadOp, ) -> InterpResult<'tcx> { self.atomic_compare_exchange_impl(args, dest, success, fail, false) } fn atomic_compare_exchange_weak( - &mut self, args: &[OpTy<'tcx, Tag>], dest: &PlaceTy<'tcx, Tag>, - success: AtomicRwOp, fail: AtomicReadOp + &mut self, + args: &[OpTy<'tcx, Tag>], + dest: &PlaceTy<'tcx, Tag>, + success: AtomicRwOp, + fail: AtomicReadOp, ) -> InterpResult<'tcx> { self.atomic_compare_exchange_impl(args, dest, success, fail, true) } @@ -564,7 +669,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx dest_ty: ty::Ty<'tcx>, ) -> InterpResult<'tcx, Scalar> where - F: Float + Into> + F: Float + Into>, { let this = self.eval_context_ref(); @@ -585,7 +690,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // `f` was not representable in this integer type. throw_ub_format!( "`float_to_int_unchecked` intrinsic called on {} which cannot be represented in target type `{:?}`", - f, dest_ty, + f, + dest_ty, ); } } @@ -600,7 +706,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // `f` was not representable in this integer type. throw_ub_format!( "`float_to_int_unchecked` intrinsic called on {} which cannot be represented in target type `{:?}`", - f, dest_ty, + f, + dest_ty, ); } } From f8440d6c998b6f30fa04d6ed6f1e4f19242283af Mon Sep 17 00:00:00 2001 From: Henry Boisdequin <65845077+henryboisdequin@users.noreply.github.com> Date: Tue, 2 Mar 2021 18:10:27 +0530 Subject: [PATCH 2568/3747] Add in `atomic_{min,max}_x` intrinsics Co-authored-by: Greg Bowyer --- src/data_race.rs | 74 +++++++--- src/shims/intrinsics.rs | 306 +++++++++++++++++++++++++++++++-------- tests/run-pass/atomic.rs | 14 ++ 3 files changed, 314 insertions(+), 80 deletions(-) diff --git a/src/data_race.rs b/src/data_race.rs index c7bafb60a6191..e8071845c7d76 100644 --- a/src/data_race.rs +++ b/src/data_race.rs @@ -74,9 +74,9 @@ use rustc_middle::{mir, ty::layout::TyAndLayout}; use rustc_target::abi::Size; use crate::{ - ImmTy, Immediate, InterpResult, MPlaceTy, MemPlaceMeta, MiriEvalContext, MiriEvalContextExt, - OpTy, Pointer, RangeMap, Scalar, ScalarMaybeUninit, Tag, ThreadId, VClock, VTimestamp, - VectorIdx, MemoryKind, MiriMemoryKind + ImmTy, Immediate, InterpResult, MPlaceTy, MemPlaceMeta, MemoryKind, MiriEvalContext, + MiriEvalContextExt, MiriMemoryKind, OpTy, Pointer, RangeMap, Scalar, ScalarMaybeUninit, Tag, + ThreadId, VClock, VTimestamp, VectorIdx, }; pub type AllocExtra = VClockAlloc; @@ -542,6 +542,34 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { Ok(old) } + /// Perform an conditional atomic exchange with a memory place and a new + /// scalar value, the old value is returned. + fn atomic_min_max_scalar( + &mut self, + place: &MPlaceTy<'tcx, Tag>, + rhs: ImmTy<'tcx, Tag>, + min: bool, + atomic: AtomicRwOp, + ) -> InterpResult<'tcx, ImmTy<'tcx, Tag>> { + let this = self.eval_context_mut(); + + let old = this.allow_data_races_mut(|this| this.read_immediate(&place.into()))?; + let lt = this.overflowing_binary_op(mir::BinOp::Lt, &old, &rhs)?.0.to_bool()?; + + let new_val = if min { + if lt { &old } else { &rhs } + } else { + if lt { &rhs } else { &old } + }; + + this.allow_data_races_mut(|this| this.write_immediate_to_mplace(**new_val, place))?; + + this.validate_atomic_rmw(&place, atomic)?; + + // Return the old value. + Ok(old) + } + /// Perform an atomic compare and exchange at a given memory location. /// On success an atomic RMW operation is performed and on failure /// only an atomic read occurs. If `can_fail_spuriously` is true, @@ -687,15 +715,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { } } - fn reset_vector_clocks( - &mut self, - ptr: Pointer, - size: Size - ) -> InterpResult<'tcx> { + fn reset_vector_clocks(&mut self, ptr: Pointer, size: Size) -> InterpResult<'tcx> { let this = self.eval_context_mut(); if let Some(data_race) = &mut this.memory.extra.data_race { if data_race.multi_threaded.get() { - let alloc_meta = this.memory.get_raw_mut(ptr.alloc_id)?.extra.data_race.as_mut().unwrap(); + let alloc_meta = + this.memory.get_raw_mut(ptr.alloc_id)?.extra.data_race.as_mut().unwrap(); alloc_meta.reset_clocks(ptr.offset, size); } } @@ -715,28 +740,37 @@ pub struct VClockAlloc { impl VClockAlloc { /// Create a new data-race detector for newly allocated memory. - pub fn new_allocation(global: &MemoryExtra, len: Size, kind: MemoryKind) -> VClockAlloc { + pub fn new_allocation( + global: &MemoryExtra, + len: Size, + kind: MemoryKind, + ) -> VClockAlloc { let (alloc_timestamp, alloc_index) = match kind { // User allocated and stack memory should track allocation. MemoryKind::Machine( - MiriMemoryKind::Rust | MiriMemoryKind::C | MiriMemoryKind::WinHeap - ) | MemoryKind::Stack => { + MiriMemoryKind::Rust | MiriMemoryKind::C | MiriMemoryKind::WinHeap, + ) + | MemoryKind::Stack => { let (alloc_index, clocks) = global.current_thread_state(); let alloc_timestamp = clocks.clock[alloc_index]; (alloc_timestamp, alloc_index) } // Other global memory should trace races but be allocated at the 0 timestamp. MemoryKind::Machine( - MiriMemoryKind::Global | MiriMemoryKind::Machine | MiriMemoryKind::Env | - MiriMemoryKind::ExternStatic | MiriMemoryKind::Tls - ) | MemoryKind::CallerLocation | MemoryKind::Vtable => { - (0, VectorIdx::MAX_INDEX) - } + MiriMemoryKind::Global + | MiriMemoryKind::Machine + | MiriMemoryKind::Env + | MiriMemoryKind::ExternStatic + | MiriMemoryKind::Tls, + ) + | MemoryKind::CallerLocation + | MemoryKind::Vtable => (0, VectorIdx::MAX_INDEX), }; VClockAlloc { global: Rc::clone(global), alloc_ranges: RefCell::new(RangeMap::new( - len, MemoryCellClocks::new(alloc_timestamp, alloc_index) + len, + MemoryCellClocks::new(alloc_timestamp, alloc_index), )), } } @@ -1015,7 +1049,8 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { true, place_ptr, size, - ).map(|_| true); + ) + .map(|_| true); } } @@ -1267,7 +1302,6 @@ impl GlobalState { .as_ref() .expect("Joined with thread but thread has not terminated"); - // The join thread happens-before the current thread // so update the current vector clock. // Is not a release operation so the clock is not incremented. diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index f9ec62d7514d6..66ba42c5a017b 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -10,6 +10,12 @@ use rustc_target::abi::{Align, Integer, LayoutOf}; use crate::*; use helpers::check_arg_count; +pub enum AtomicOp { + MirOp(mir::BinOp, bool), + Max, + Min, +} + impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { fn call_intrinsic( @@ -388,60 +394,226 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx AtomicReadOp::Acquire, )?, - "atomic_or" => this.atomic_op(args, dest, BinOp::BitOr, false, AtomicRwOp::SeqCst)?, - "atomic_or_acq" => - this.atomic_op(args, dest, BinOp::BitOr, false, AtomicRwOp::Acquire)?, - "atomic_or_rel" => - this.atomic_op(args, dest, BinOp::BitOr, false, AtomicRwOp::Release)?, - "atomic_or_acqrel" => - this.atomic_op(args, dest, BinOp::BitOr, false, AtomicRwOp::AcqRel)?, - "atomic_or_relaxed" => - this.atomic_op(args, dest, BinOp::BitOr, false, AtomicRwOp::Relaxed)?, - "atomic_xor" => this.atomic_op(args, dest, BinOp::BitXor, false, AtomicRwOp::SeqCst)?, - "atomic_xor_acq" => - this.atomic_op(args, dest, BinOp::BitXor, false, AtomicRwOp::Acquire)?, - "atomic_xor_rel" => - this.atomic_op(args, dest, BinOp::BitXor, false, AtomicRwOp::Release)?, - "atomic_xor_acqrel" => - this.atomic_op(args, dest, BinOp::BitXor, false, AtomicRwOp::AcqRel)?, - "atomic_xor_relaxed" => - this.atomic_op(args, dest, BinOp::BitXor, false, AtomicRwOp::Relaxed)?, - "atomic_and" => this.atomic_op(args, dest, BinOp::BitAnd, false, AtomicRwOp::SeqCst)?, - "atomic_and_acq" => - this.atomic_op(args, dest, BinOp::BitAnd, false, AtomicRwOp::Acquire)?, - "atomic_and_rel" => - this.atomic_op(args, dest, BinOp::BitAnd, false, AtomicRwOp::Release)?, - "atomic_and_acqrel" => - this.atomic_op(args, dest, BinOp::BitAnd, false, AtomicRwOp::AcqRel)?, - "atomic_and_relaxed" => - this.atomic_op(args, dest, BinOp::BitAnd, false, AtomicRwOp::Relaxed)?, - "atomic_nand" => this.atomic_op(args, dest, BinOp::BitAnd, true, AtomicRwOp::SeqCst)?, - "atomic_nand_acq" => - this.atomic_op(args, dest, BinOp::BitAnd, true, AtomicRwOp::Acquire)?, - "atomic_nand_rel" => - this.atomic_op(args, dest, BinOp::BitAnd, true, AtomicRwOp::Release)?, - "atomic_nand_acqrel" => - this.atomic_op(args, dest, BinOp::BitAnd, true, AtomicRwOp::AcqRel)?, - "atomic_nand_relaxed" => - this.atomic_op(args, dest, BinOp::BitAnd, true, AtomicRwOp::Relaxed)?, - "atomic_xadd" => this.atomic_op(args, dest, BinOp::Add, false, AtomicRwOp::SeqCst)?, - "atomic_xadd_acq" => - this.atomic_op(args, dest, BinOp::Add, false, AtomicRwOp::Acquire)?, - "atomic_xadd_rel" => - this.atomic_op(args, dest, BinOp::Add, false, AtomicRwOp::Release)?, - "atomic_xadd_acqrel" => - this.atomic_op(args, dest, BinOp::Add, false, AtomicRwOp::AcqRel)?, - "atomic_xadd_relaxed" => - this.atomic_op(args, dest, BinOp::Add, false, AtomicRwOp::Relaxed)?, - "atomic_xsub" => this.atomic_op(args, dest, BinOp::Sub, false, AtomicRwOp::SeqCst)?, - "atomic_xsub_acq" => - this.atomic_op(args, dest, BinOp::Sub, false, AtomicRwOp::Acquire)?, - "atomic_xsub_rel" => - this.atomic_op(args, dest, BinOp::Sub, false, AtomicRwOp::Release)?, - "atomic_xsub_acqrel" => - this.atomic_op(args, dest, BinOp::Sub, false, AtomicRwOp::AcqRel)?, - "atomic_xsub_relaxed" => - this.atomic_op(args, dest, BinOp::Sub, false, AtomicRwOp::Relaxed)?, + "atomic_or" => this.atomic_op_min_max( + args, + dest, + AtomicOp::MirOp(BinOp::BitOr, false), + AtomicRwOp::SeqCst, + )?, + "atomic_or_acq" => this.atomic_op_min_max( + args, + dest, + AtomicOp::MirOp(BinOp::BitOr, false), + AtomicRwOp::Acquire, + )?, + "atomic_or_rel" => this.atomic_op_min_max( + args, + dest, + AtomicOp::MirOp(BinOp::BitOr, false), + AtomicRwOp::Release, + )?, + "atomic_or_acqrel" => this.atomic_op_min_max( + args, + dest, + AtomicOp::MirOp(BinOp::BitOr, false), + AtomicRwOp::AcqRel, + )?, + "atomic_or_relaxed" => this.atomic_op_min_max( + args, + dest, + AtomicOp::MirOp(BinOp::BitOr, false), + AtomicRwOp::Relaxed, + )?, + "atomic_xor" => this.atomic_op_min_max( + args, + dest, + AtomicOp::MirOp(BinOp::BitXor, false), + AtomicRwOp::SeqCst, + )?, + "atomic_xor_acq" => this.atomic_op_min_max( + args, + dest, + AtomicOp::MirOp(BinOp::BitXor, false), + AtomicRwOp::Acquire, + )?, + "atomic_xor_rel" => this.atomic_op_min_max( + args, + dest, + AtomicOp::MirOp(BinOp::BitXor, false), + AtomicRwOp::Release, + )?, + "atomic_xor_acqrel" => this.atomic_op_min_max( + args, + dest, + AtomicOp::MirOp(BinOp::BitXor, false), + AtomicRwOp::AcqRel, + )?, + "atomic_xor_relaxed" => this.atomic_op_min_max( + args, + dest, + AtomicOp::MirOp(BinOp::BitXor, false), + AtomicRwOp::Relaxed, + )?, + "atomic_and" => this.atomic_op_min_max( + args, + dest, + AtomicOp::MirOp(BinOp::BitAnd, false), + AtomicRwOp::SeqCst, + )?, + "atomic_and_acq" => this.atomic_op_min_max( + args, + dest, + AtomicOp::MirOp(BinOp::BitAnd, false), + AtomicRwOp::Acquire, + )?, + "atomic_and_rel" => this.atomic_op_min_max( + args, + dest, + AtomicOp::MirOp(BinOp::BitAnd, false), + AtomicRwOp::Release, + )?, + "atomic_and_acqrel" => this.atomic_op_min_max( + args, + dest, + AtomicOp::MirOp(BinOp::BitAnd, false), + AtomicRwOp::AcqRel, + )?, + "atomic_and_relaxed" => this.atomic_op_min_max( + args, + dest, + AtomicOp::MirOp(BinOp::BitAnd, false), + AtomicRwOp::Relaxed, + )?, + "atomic_nand" => this.atomic_op_min_max( + args, + dest, + AtomicOp::MirOp(BinOp::BitAnd, true), + AtomicRwOp::SeqCst, + )?, + "atomic_nand_acq" => this.atomic_op_min_max( + args, + dest, + AtomicOp::MirOp(BinOp::BitAnd, true), + AtomicRwOp::Acquire, + )?, + "atomic_nand_rel" => this.atomic_op_min_max( + args, + dest, + AtomicOp::MirOp(BinOp::BitAnd, true), + AtomicRwOp::Release, + )?, + "atomic_nand_acqrel" => this.atomic_op_min_max( + args, + dest, + AtomicOp::MirOp(BinOp::BitAnd, true), + AtomicRwOp::AcqRel, + )?, + "atomic_nand_relaxed" => this.atomic_op_min_max( + args, + dest, + AtomicOp::MirOp(BinOp::BitAnd, true), + AtomicRwOp::Relaxed, + )?, + "atomic_xadd" => this.atomic_op_min_max( + args, + dest, + AtomicOp::MirOp(BinOp::Add, false), + AtomicRwOp::SeqCst, + )?, + "atomic_xadd_acq" => this.atomic_op_min_max( + args, + dest, + AtomicOp::MirOp(BinOp::Add, false), + AtomicRwOp::Acquire, + )?, + "atomic_xadd_rel" => this.atomic_op_min_max( + args, + dest, + AtomicOp::MirOp(BinOp::Add, false), + AtomicRwOp::Release, + )?, + "atomic_xadd_acqrel" => this.atomic_op_min_max( + args, + dest, + AtomicOp::MirOp(BinOp::Add, false), + AtomicRwOp::AcqRel, + )?, + "atomic_xadd_relaxed" => this.atomic_op_min_max( + args, + dest, + AtomicOp::MirOp(BinOp::Add, false), + AtomicRwOp::Relaxed, + )?, + "atomic_xsub" => this.atomic_op_min_max( + args, + dest, + AtomicOp::MirOp(BinOp::Sub, false), + AtomicRwOp::SeqCst, + )?, + "atomic_xsub_acq" => this.atomic_op_min_max( + args, + dest, + AtomicOp::MirOp(BinOp::Sub, false), + AtomicRwOp::Acquire, + )?, + "atomic_xsub_rel" => this.atomic_op_min_max( + args, + dest, + AtomicOp::MirOp(BinOp::Sub, false), + AtomicRwOp::Release, + )?, + "atomic_xsub_acqrel" => this.atomic_op_min_max( + args, + dest, + AtomicOp::MirOp(BinOp::Sub, false), + AtomicRwOp::AcqRel, + )?, + "atomic_xsub_relaxed" => this.atomic_op_min_max( + args, + dest, + AtomicOp::MirOp(BinOp::Sub, false), + AtomicRwOp::Relaxed, + )?, + "atomic_min" => + this.atomic_op_min_max(args, dest, AtomicOp::Min, AtomicRwOp::SeqCst)?, + "atomic_min_acq" => + this.atomic_op_min_max(args, dest, AtomicOp::Min, AtomicRwOp::Acquire)?, + "atomic_min_rel" => + this.atomic_op_min_max(args, dest, AtomicOp::Min, AtomicRwOp::Release)?, + "atomic_min_acqrel" => + this.atomic_op_min_max(args, dest, AtomicOp::Min, AtomicRwOp::AcqRel)?, + "atomic_min_relaxed" => + this.atomic_op_min_max(args, dest, AtomicOp::Min, AtomicRwOp::Relaxed)?, + "atomic_max" => + this.atomic_op_min_max(args, dest, AtomicOp::Max, AtomicRwOp::SeqCst)?, + "atomic_max_acq" => + this.atomic_op_min_max(args, dest, AtomicOp::Max, AtomicRwOp::Acquire)?, + "atomic_max_rel" => + this.atomic_op_min_max(args, dest, AtomicOp::Max, AtomicRwOp::Release)?, + "atomic_max_acqrel" => + this.atomic_op_min_max(args, dest, AtomicOp::Max, AtomicRwOp::AcqRel)?, + "atomic_max_relaxed" => + this.atomic_op_min_max(args, dest, AtomicOp::Max, AtomicRwOp::Relaxed)?, + "atomic_umin" => + this.atomic_op_min_max(args, dest, AtomicOp::Min, AtomicRwOp::SeqCst)?, + "atomic_umin_acq" => + this.atomic_op_min_max(args, dest, AtomicOp::Min, AtomicRwOp::Acquire)?, + "atomic_umin_rel" => + this.atomic_op_min_max(args, dest, AtomicOp::Min, AtomicRwOp::Release)?, + "atomic_umin_acqrel" => + this.atomic_op_min_max(args, dest, AtomicOp::Min, AtomicRwOp::AcqRel)?, + "atomic_umin_relaxed" => + this.atomic_op_min_max(args, dest, AtomicOp::Min, AtomicRwOp::Relaxed)?, + "atomic_umax" => + this.atomic_op_min_max(args, dest, AtomicOp::Max, AtomicRwOp::SeqCst)?, + "atomic_umax_acq" => + this.atomic_op_min_max(args, dest, AtomicOp::Max, AtomicRwOp::Acquire)?, + "atomic_umax_rel" => + this.atomic_op_min_max(args, dest, AtomicOp::Max, AtomicRwOp::Release)?, + "atomic_umax_acqrel" => + this.atomic_op_min_max(args, dest, AtomicOp::Max, AtomicRwOp::AcqRel)?, + "atomic_umax_relaxed" => + this.atomic_op_min_max(args, dest, AtomicOp::Max, AtomicRwOp::Relaxed)?, // Query type information "assert_zero_valid" | "assert_uninit_valid" => { @@ -557,18 +729,18 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(()) } - fn atomic_op( + fn atomic_op_min_max( &mut self, args: &[OpTy<'tcx, Tag>], dest: &PlaceTy<'tcx, Tag>, - op: mir::BinOp, - neg: bool, + atomic_op: AtomicOp, atomic: AtomicRwOp, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let &[ref place, ref rhs] = check_arg_count(args)?; let place = this.deref_operand(place)?; + if !place.layout.ty.is_integral() { bug!("Atomic arithmetic operations only work on integer types"); } @@ -580,9 +752,23 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let align = Align::from_bytes(place.layout.size.bytes()).unwrap(); this.memory.check_ptr_access(place.ptr, place.layout.size, align)?; - let old = this.atomic_op_immediate(&place, &rhs, op, neg, atomic)?; - this.write_immediate(*old, dest)?; // old value is returned - Ok(()) + match atomic_op { + AtomicOp::Min => { + let old = this.atomic_min_max_scalar(&place, rhs, true, atomic)?; + this.write_immediate(*old, &dest)?; // old value is returned + Ok(()) + } + AtomicOp::Max => { + let old = this.atomic_min_max_scalar(&place, rhs, false, atomic)?; + this.write_immediate(*old, &dest)?; // old value is returned + Ok(()) + } + AtomicOp::MirOp(op, neg) => { + let old = this.atomic_op_immediate(&place, &rhs, op, neg, atomic)?; + this.write_immediate(*old, dest)?; // old value is returned + Ok(()) + } + } } fn atomic_exchange( diff --git a/tests/run-pass/atomic.rs b/tests/run-pass/atomic.rs index 4f27c2bd54d67..9a9e852ecf50f 100644 --- a/tests/run-pass/atomic.rs +++ b/tests/run-pass/atomic.rs @@ -74,6 +74,20 @@ fn atomic_u64() { assert_eq!(ATOMIC.compare_exchange(0, 0x100, AcqRel, Acquire), Err(1)); compare_exchange_weak_loop!(ATOMIC, 1, 0x100, AcqRel, Acquire); assert_eq!(ATOMIC.load(Relaxed), 0x100); + + assert_eq!(ATOMIC.fetch_max(0x10, SeqCst), 0x100); + assert_eq!(ATOMIC.fetch_max(0x100, SeqCst), 0x100); + assert_eq!(ATOMIC.fetch_max(0x1000, SeqCst), 0x100); + assert_eq!(ATOMIC.fetch_max(0x1000, SeqCst), 0x1000); + assert_eq!(ATOMIC.fetch_max(0x2000, SeqCst), 0x1000); + assert_eq!(ATOMIC.fetch_max(0x2000, SeqCst), 0x2000); + + assert_eq!(ATOMIC.fetch_min(0x2000, SeqCst), 0x2000); + assert_eq!(ATOMIC.fetch_min(0x2000, SeqCst), 0x2000); + assert_eq!(ATOMIC.fetch_min(0x1000, SeqCst), 0x2000); + assert_eq!(ATOMIC.fetch_min(0x1000, SeqCst), 0x1000); + assert_eq!(ATOMIC.fetch_min(0x100, SeqCst), 0x1000); + assert_eq!(ATOMIC.fetch_min(0x10, SeqCst), 0x100); } fn atomic_fences() { From 9f3dbad5d073f764a28e9c3c1397b4b39d6a3fc2 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 2 Mar 2021 19:54:45 +0100 Subject: [PATCH 2569/3747] rename atomic_op_min_max -> atomic_op --- src/shims/intrinsics.rs | 102 ++++++++++++++++++++-------------------- 1 file changed, 51 insertions(+), 51 deletions(-) diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 66ba42c5a017b..d7e025f023843 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -394,226 +394,226 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx AtomicReadOp::Acquire, )?, - "atomic_or" => this.atomic_op_min_max( + "atomic_or" => this.atomic_op( args, dest, AtomicOp::MirOp(BinOp::BitOr, false), AtomicRwOp::SeqCst, )?, - "atomic_or_acq" => this.atomic_op_min_max( + "atomic_or_acq" => this.atomic_op( args, dest, AtomicOp::MirOp(BinOp::BitOr, false), AtomicRwOp::Acquire, )?, - "atomic_or_rel" => this.atomic_op_min_max( + "atomic_or_rel" => this.atomic_op( args, dest, AtomicOp::MirOp(BinOp::BitOr, false), AtomicRwOp::Release, )?, - "atomic_or_acqrel" => this.atomic_op_min_max( + "atomic_or_acqrel" => this.atomic_op( args, dest, AtomicOp::MirOp(BinOp::BitOr, false), AtomicRwOp::AcqRel, )?, - "atomic_or_relaxed" => this.atomic_op_min_max( + "atomic_or_relaxed" => this.atomic_op( args, dest, AtomicOp::MirOp(BinOp::BitOr, false), AtomicRwOp::Relaxed, )?, - "atomic_xor" => this.atomic_op_min_max( + "atomic_xor" => this.atomic_op( args, dest, AtomicOp::MirOp(BinOp::BitXor, false), AtomicRwOp::SeqCst, )?, - "atomic_xor_acq" => this.atomic_op_min_max( + "atomic_xor_acq" => this.atomic_op( args, dest, AtomicOp::MirOp(BinOp::BitXor, false), AtomicRwOp::Acquire, )?, - "atomic_xor_rel" => this.atomic_op_min_max( + "atomic_xor_rel" => this.atomic_op( args, dest, AtomicOp::MirOp(BinOp::BitXor, false), AtomicRwOp::Release, )?, - "atomic_xor_acqrel" => this.atomic_op_min_max( + "atomic_xor_acqrel" => this.atomic_op( args, dest, AtomicOp::MirOp(BinOp::BitXor, false), AtomicRwOp::AcqRel, )?, - "atomic_xor_relaxed" => this.atomic_op_min_max( + "atomic_xor_relaxed" => this.atomic_op( args, dest, AtomicOp::MirOp(BinOp::BitXor, false), AtomicRwOp::Relaxed, )?, - "atomic_and" => this.atomic_op_min_max( + "atomic_and" => this.atomic_op( args, dest, AtomicOp::MirOp(BinOp::BitAnd, false), AtomicRwOp::SeqCst, )?, - "atomic_and_acq" => this.atomic_op_min_max( + "atomic_and_acq" => this.atomic_op( args, dest, AtomicOp::MirOp(BinOp::BitAnd, false), AtomicRwOp::Acquire, )?, - "atomic_and_rel" => this.atomic_op_min_max( + "atomic_and_rel" => this.atomic_op( args, dest, AtomicOp::MirOp(BinOp::BitAnd, false), AtomicRwOp::Release, )?, - "atomic_and_acqrel" => this.atomic_op_min_max( + "atomic_and_acqrel" => this.atomic_op( args, dest, AtomicOp::MirOp(BinOp::BitAnd, false), AtomicRwOp::AcqRel, )?, - "atomic_and_relaxed" => this.atomic_op_min_max( + "atomic_and_relaxed" => this.atomic_op( args, dest, AtomicOp::MirOp(BinOp::BitAnd, false), AtomicRwOp::Relaxed, )?, - "atomic_nand" => this.atomic_op_min_max( + "atomic_nand" => this.atomic_op( args, dest, AtomicOp::MirOp(BinOp::BitAnd, true), AtomicRwOp::SeqCst, )?, - "atomic_nand_acq" => this.atomic_op_min_max( + "atomic_nand_acq" => this.atomic_op( args, dest, AtomicOp::MirOp(BinOp::BitAnd, true), AtomicRwOp::Acquire, )?, - "atomic_nand_rel" => this.atomic_op_min_max( + "atomic_nand_rel" => this.atomic_op( args, dest, AtomicOp::MirOp(BinOp::BitAnd, true), AtomicRwOp::Release, )?, - "atomic_nand_acqrel" => this.atomic_op_min_max( + "atomic_nand_acqrel" => this.atomic_op( args, dest, AtomicOp::MirOp(BinOp::BitAnd, true), AtomicRwOp::AcqRel, )?, - "atomic_nand_relaxed" => this.atomic_op_min_max( + "atomic_nand_relaxed" => this.atomic_op( args, dest, AtomicOp::MirOp(BinOp::BitAnd, true), AtomicRwOp::Relaxed, )?, - "atomic_xadd" => this.atomic_op_min_max( + "atomic_xadd" => this.atomic_op( args, dest, AtomicOp::MirOp(BinOp::Add, false), AtomicRwOp::SeqCst, )?, - "atomic_xadd_acq" => this.atomic_op_min_max( + "atomic_xadd_acq" => this.atomic_op( args, dest, AtomicOp::MirOp(BinOp::Add, false), AtomicRwOp::Acquire, )?, - "atomic_xadd_rel" => this.atomic_op_min_max( + "atomic_xadd_rel" => this.atomic_op( args, dest, AtomicOp::MirOp(BinOp::Add, false), AtomicRwOp::Release, )?, - "atomic_xadd_acqrel" => this.atomic_op_min_max( + "atomic_xadd_acqrel" => this.atomic_op( args, dest, AtomicOp::MirOp(BinOp::Add, false), AtomicRwOp::AcqRel, )?, - "atomic_xadd_relaxed" => this.atomic_op_min_max( + "atomic_xadd_relaxed" => this.atomic_op( args, dest, AtomicOp::MirOp(BinOp::Add, false), AtomicRwOp::Relaxed, )?, - "atomic_xsub" => this.atomic_op_min_max( + "atomic_xsub" => this.atomic_op( args, dest, AtomicOp::MirOp(BinOp::Sub, false), AtomicRwOp::SeqCst, )?, - "atomic_xsub_acq" => this.atomic_op_min_max( + "atomic_xsub_acq" => this.atomic_op( args, dest, AtomicOp::MirOp(BinOp::Sub, false), AtomicRwOp::Acquire, )?, - "atomic_xsub_rel" => this.atomic_op_min_max( + "atomic_xsub_rel" => this.atomic_op( args, dest, AtomicOp::MirOp(BinOp::Sub, false), AtomicRwOp::Release, )?, - "atomic_xsub_acqrel" => this.atomic_op_min_max( + "atomic_xsub_acqrel" => this.atomic_op( args, dest, AtomicOp::MirOp(BinOp::Sub, false), AtomicRwOp::AcqRel, )?, - "atomic_xsub_relaxed" => this.atomic_op_min_max( + "atomic_xsub_relaxed" => this.atomic_op( args, dest, AtomicOp::MirOp(BinOp::Sub, false), AtomicRwOp::Relaxed, )?, "atomic_min" => - this.atomic_op_min_max(args, dest, AtomicOp::Min, AtomicRwOp::SeqCst)?, + this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOp::SeqCst)?, "atomic_min_acq" => - this.atomic_op_min_max(args, dest, AtomicOp::Min, AtomicRwOp::Acquire)?, + this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOp::Acquire)?, "atomic_min_rel" => - this.atomic_op_min_max(args, dest, AtomicOp::Min, AtomicRwOp::Release)?, + this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOp::Release)?, "atomic_min_acqrel" => - this.atomic_op_min_max(args, dest, AtomicOp::Min, AtomicRwOp::AcqRel)?, + this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOp::AcqRel)?, "atomic_min_relaxed" => - this.atomic_op_min_max(args, dest, AtomicOp::Min, AtomicRwOp::Relaxed)?, + this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOp::Relaxed)?, "atomic_max" => - this.atomic_op_min_max(args, dest, AtomicOp::Max, AtomicRwOp::SeqCst)?, + this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOp::SeqCst)?, "atomic_max_acq" => - this.atomic_op_min_max(args, dest, AtomicOp::Max, AtomicRwOp::Acquire)?, + this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOp::Acquire)?, "atomic_max_rel" => - this.atomic_op_min_max(args, dest, AtomicOp::Max, AtomicRwOp::Release)?, + this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOp::Release)?, "atomic_max_acqrel" => - this.atomic_op_min_max(args, dest, AtomicOp::Max, AtomicRwOp::AcqRel)?, + this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOp::AcqRel)?, "atomic_max_relaxed" => - this.atomic_op_min_max(args, dest, AtomicOp::Max, AtomicRwOp::Relaxed)?, + this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOp::Relaxed)?, "atomic_umin" => - this.atomic_op_min_max(args, dest, AtomicOp::Min, AtomicRwOp::SeqCst)?, + this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOp::SeqCst)?, "atomic_umin_acq" => - this.atomic_op_min_max(args, dest, AtomicOp::Min, AtomicRwOp::Acquire)?, + this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOp::Acquire)?, "atomic_umin_rel" => - this.atomic_op_min_max(args, dest, AtomicOp::Min, AtomicRwOp::Release)?, + this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOp::Release)?, "atomic_umin_acqrel" => - this.atomic_op_min_max(args, dest, AtomicOp::Min, AtomicRwOp::AcqRel)?, + this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOp::AcqRel)?, "atomic_umin_relaxed" => - this.atomic_op_min_max(args, dest, AtomicOp::Min, AtomicRwOp::Relaxed)?, + this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOp::Relaxed)?, "atomic_umax" => - this.atomic_op_min_max(args, dest, AtomicOp::Max, AtomicRwOp::SeqCst)?, + this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOp::SeqCst)?, "atomic_umax_acq" => - this.atomic_op_min_max(args, dest, AtomicOp::Max, AtomicRwOp::Acquire)?, + this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOp::Acquire)?, "atomic_umax_rel" => - this.atomic_op_min_max(args, dest, AtomicOp::Max, AtomicRwOp::Release)?, + this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOp::Release)?, "atomic_umax_acqrel" => - this.atomic_op_min_max(args, dest, AtomicOp::Max, AtomicRwOp::AcqRel)?, + this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOp::AcqRel)?, "atomic_umax_relaxed" => - this.atomic_op_min_max(args, dest, AtomicOp::Max, AtomicRwOp::Relaxed)?, + this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOp::Relaxed)?, // Query type information "assert_zero_valid" | "assert_uninit_valid" => { @@ -729,7 +729,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(()) } - fn atomic_op_min_max( + fn atomic_op( &mut self, args: &[OpTy<'tcx, Tag>], dest: &PlaceTy<'tcx, Tag>, From 26e97ec54f665d5d7e35f61fe6f5a6deac5afe7f Mon Sep 17 00:00:00 2001 From: Smitty Date: Thu, 4 Mar 2021 07:48:28 -0500 Subject: [PATCH 2570/3747] Support breakpoint intrinsic --- src/shims/intrinsics.rs | 5 +++++ tests/compile-fail/breakpoint.rs | 7 +++++++ 2 files changed, 12 insertions(+) create mode 100644 tests/compile-fail/breakpoint.rs diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index d7e025f023843..c5f1f58f70681 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -654,6 +654,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "try" => return this.handle_try(args, dest, ret), + "breakpoint" => { + // normally this would raise a SIGTRAP, which aborts if no debugger is connected + throw_machine_stop!(TerminationInfo::Abort("Trace/breakpoint trap".to_string())) + } + name => throw_unsup_format!("unimplemented intrinsic: {}", name), } diff --git a/tests/compile-fail/breakpoint.rs b/tests/compile-fail/breakpoint.rs new file mode 100644 index 0000000000000..d0a0239eb933b --- /dev/null +++ b/tests/compile-fail/breakpoint.rs @@ -0,0 +1,7 @@ +#![feature(core_intrinsics)] + +fn main() { + unsafe { + core::intrinsics::breakpoint() //~ ERROR Trace/breakpoint trap + }; +} From 8d43d727f42e918a7aeb76b4596f0726c0e8e0ae Mon Sep 17 00:00:00 2001 From: Smittyvb Date: Fri, 5 Mar 2021 07:16:50 -0500 Subject: [PATCH 2571/3747] Check arg count Co-authored-by: Ralf Jung --- src/shims/intrinsics.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index c5f1f58f70681..64c6e0a540f84 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -655,6 +655,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "try" => return this.handle_try(args, dest, ret), "breakpoint" => { + let &[] = check_arg_count(args)?; // normally this would raise a SIGTRAP, which aborts if no debugger is connected throw_machine_stop!(TerminationInfo::Abort("Trace/breakpoint trap".to_string())) } From 5bd5ea21ea97800e4173a8793beebc424d45358b Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Mon, 8 Mar 2021 16:57:09 +0100 Subject: [PATCH 2572/3747] Remove unwrap_none as it won't be stabilized. This upgrades to the latest rustc to be able to use try_insert() instead. --- rust-version | 2 +- src/helpers.rs | 2 +- src/lib.rs | 2 +- src/machine.rs | 4 ++-- src/shims/posix/fs.rs | 4 ++-- src/shims/tls.rs | 2 +- src/stacked_borrows.rs | 2 +- src/thread.rs | 8 ++++---- tests/run-pass/panic/std-panic-locations.rs | 5 ----- 9 files changed, 13 insertions(+), 18 deletions(-) diff --git a/rust-version b/rust-version index 65644e75d9770..e518870d5b779 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -09db05762b283bed62d4f92729cfee4646519833 +1d6b0f626aad4ee9f2eaec4d5582f45620ccab80 diff --git a/src/helpers.rs b/src/helpers.rs index 2baaebb0ae206..07356ab020327 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -179,7 +179,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx )?; this.write_immediate(*arg, &callee_arg)?; } - callee_args.next().expect_none("callee has more arguments than expected"); + assert_eq!(callee_args.next(), None, "callee has more arguments than expected"); Ok(()) } diff --git a/src/lib.rs b/src/lib.rs index 5ed3d8950d04a..7fc080a937f00 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,6 +1,6 @@ #![feature(rustc_private)] -#![feature(option_expect_none, option_unwrap_none)] #![feature(map_first_last)] +#![feature(map_try_insert)] #![feature(never_type)] #![feature(or_patterns)] #![feature(try_blocks)] diff --git a/src/machine.rs b/src/machine.rs index 32aae4a8c8e51..1415f7506a4ec 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -179,8 +179,8 @@ impl MemoryExtra { this.memory .extra .extern_statics - .insert(Symbol::intern(name), ptr.alloc_id) - .unwrap_none(); + .try_insert(Symbol::intern(name), ptr.alloc_id) + .unwrap(); } /// Sets up the "extern statics" for this machine. diff --git a/src/shims/posix/fs.rs b/src/shims/posix/fs.rs index 2f1efee8c8937..def2aca292a53 100644 --- a/src/shims/posix/fs.rs +++ b/src/shims/posix/fs.rs @@ -223,7 +223,7 @@ impl<'tcx> FileHandler { self.handles.last_key_value().map(|(fd, _)| fd.checked_add(1).unwrap()).unwrap_or(min_fd) }); - self.handles.insert(new_fd, file_handle).unwrap_none(); + self.handles.try_insert(new_fd, file_handle).unwrap(); new_fd } } @@ -381,7 +381,7 @@ impl DirHandler { fn insert_new(&mut self, read_dir: ReadDir) -> u64 { let id = self.next_id; self.next_id += 1; - self.streams.insert(id, read_dir).unwrap_none(); + self.streams.try_insert(id, read_dir).unwrap(); id } } diff --git a/src/shims/tls.rs b/src/shims/tls.rs index 7f19fd1673660..36bae2af9cd03 100644 --- a/src/shims/tls.rs +++ b/src/shims/tls.rs @@ -65,7 +65,7 @@ impl<'tcx> TlsData<'tcx> { pub fn create_tls_key(&mut self, dtor: Option>, max_size: Size) -> InterpResult<'tcx, TlsKey> { let new_key = self.next_key; self.next_key += 1; - self.keys.insert(new_key, TlsEntry { data: Default::default(), dtor }).unwrap_none(); + self.keys.try_insert(new_key, TlsEntry { data: Default::default(), dtor }).unwrap(); trace!("New TLS key allocated: {} with dtor {:?}", new_key, dtor); if max_size.bits() < 128 && new_key >= (1u128 << max_size.bits() as u128) { diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index cfaf8a9005ca5..fbcd265baa113 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -201,7 +201,7 @@ impl GlobalState { self.base_ptr_ids.get(&id).copied().unwrap_or_else(|| { let tag = Tag::Tagged(self.new_ptr()); trace!("New allocation {:?} has base tag {:?}", id, tag); - self.base_ptr_ids.insert(id, tag).unwrap_none(); + self.base_ptr_ids.try_insert(id, tag).unwrap(); tag }) } diff --git a/src/thread.rs b/src/thread.rs index 5d783430417be..4fe44ef9d4a7d 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -257,8 +257,8 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { fn set_thread_local_alloc_id(&self, def_id: DefId, new_alloc_id: AllocId) { self.thread_local_alloc_ids .borrow_mut() - .insert((def_id, self.active_thread), new_alloc_id) - .unwrap_none(); + .try_insert((def_id, self.active_thread), new_alloc_id) + .unwrap(); } /// Borrow the stack of the active thread. @@ -404,8 +404,8 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { callback: TimeoutCallback<'mir, 'tcx>, ) { self.timeout_callbacks - .insert(thread, TimeoutCallbackInfo { call_time, callback }) - .unwrap_none(); + .try_insert(thread, TimeoutCallbackInfo { call_time, callback }) + .unwrap(); } /// Unregister the callback for the `thread`. diff --git a/tests/run-pass/panic/std-panic-locations.rs b/tests/run-pass/panic/std-panic-locations.rs index ac2e8d5305dfe..e3050ad11835e 100644 --- a/tests/run-pass/panic/std-panic-locations.rs +++ b/tests/run-pass/panic/std-panic-locations.rs @@ -1,4 +1,3 @@ -#![feature(option_expect_none, option_unwrap_none)] //! Test that panic locations for `#[track_caller]` functions in std have the correct //! location reported. @@ -25,10 +24,6 @@ fn main() { assert_panicked(|| nope.unwrap()); assert_panicked(|| nope.expect("")); - let yep: Option<()> = Some(()); - assert_panicked(|| yep.unwrap_none()); - assert_panicked(|| yep.expect_none("")); - let oops: Result<(), ()> = Err(()); assert_panicked(|| oops.unwrap()); assert_panicked(|| oops.expect("")); From 90e218ad90a04d8a014811372188d3e85ec8480f Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Mon, 8 Mar 2021 17:06:50 +0100 Subject: [PATCH 2573/3747] Fix panic test. --- tests/run-pass/panic/std-panic-locations.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/run-pass/panic/std-panic-locations.rs b/tests/run-pass/panic/std-panic-locations.rs index e3050ad11835e..8781a371d51fa 100644 --- a/tests/run-pass/panic/std-panic-locations.rs +++ b/tests/run-pass/panic/std-panic-locations.rs @@ -35,5 +35,5 @@ fn main() { // Cleanup: reset to default hook. drop(std::panic::take_hook()); - assert_eq!(HOOK_COUNT.load(Ordering::Relaxed), 8); + assert_eq!(HOOK_COUNT.load(Ordering::Relaxed), 6); } From 1e19150d1eb6bd799e5d066adff83ce69df69e34 Mon Sep 17 00:00:00 2001 From: Daniel McNab <36049421+DJMcNab@users.noreply.github.com> Date: Mon, 8 Mar 2021 17:28:52 +0000 Subject: [PATCH 2574/3747] Opt-in to rustc_private for `rust-analyzer` rust-analyzer/rust-analyzer#7891 --- Cargo.toml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Cargo.toml b/Cargo.toml index 7580d140b55f7..123594afe56c4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -40,3 +40,7 @@ libc = "0.2" compiletest_rs = { version = "0.5", features = ["tmp"] } rustc_version = "0.2.3" colored = "2" + +[package.metadata.rust-analyzer] +# This crate uses #[feature(rustc_private)] +rustc_private = true From 38da1fab787edc090f068a4226c07373dfa2f5b7 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Tue, 9 Mar 2021 14:50:38 +0100 Subject: [PATCH 2575/3747] mir-opt-level 4 is the new 3 --- ci.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci.sh b/ci.sh index 6dae2cfd46c6a..a86c5ca490a40 100755 --- a/ci.sh +++ b/ci.sh @@ -24,7 +24,7 @@ function run_tests { if [ -z "${MIRI_TEST_TARGET+exists}" ]; then # Only for host architecture: tests with optimizations (`-O` is what cargo passes, but crank MIR # optimizations up all the way). - MIRIFLAGS="-O -Zmir-opt-level=3" ./miri test --locked + MIRIFLAGS="-O -Zmir-opt-level=4" ./miri test --locked fi # On Windows, there is always "python", not "python3" or "python2". From 6106ee214c467450bd5b028e3cd64a675a710a6e Mon Sep 17 00:00:00 2001 From: Daniel McNab <36049421+DJMcNab@users.noreply.github.com> Date: Tue, 9 Mar 2021 18:27:22 +0000 Subject: [PATCH 2576/3747] Add link to pr for documentation --- Cargo.toml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 123594afe56c4..5f9e93f2347ba 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -42,5 +42,6 @@ rustc_version = "0.2.3" colored = "2" [package.metadata.rust-analyzer] -# This crate uses #[feature(rustc_private)] +# This crate uses #[feature(rustc_private)]. +# See https://github.com/rust-analyzer/rust-analyzer/pull/7891 rustc_private = true From 7a7f7b1a7a2361354bc82870aab2875951d5a6e4 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 10 Mar 2021 15:21:12 +0100 Subject: [PATCH 2577/3747] rustup --- rust-version | 2 +- tests/compile-fail/intrinsics/copy_overflow.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/rust-version b/rust-version index e518870d5b779..53ac7c54983bc 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -1d6b0f626aad4ee9f2eaec4d5582f45620ccab80 +a4d9624242df6bfe6c0a298867dd2bd527263424 diff --git a/tests/compile-fail/intrinsics/copy_overflow.rs b/tests/compile-fail/intrinsics/copy_overflow.rs index c75cf6917b108..b09aedcf7470e 100644 --- a/tests/compile-fail/intrinsics/copy_overflow.rs +++ b/tests/compile-fail/intrinsics/copy_overflow.rs @@ -1,4 +1,4 @@ -// error-pattern: overflow computing total size of `copy` +// error-pattern: overflow computing total size use std::mem; fn main() { From 98f28ac9c8f29b12a0aa56ea13720db5d469fb2a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 11 Mar 2021 09:07:05 +0100 Subject: [PATCH 2578/3747] rustup --- rust-version | 2 +- src/helpers.rs | 2 +- src/shims/foreign_items.rs | 36 +++++++++---------- src/shims/posix/dlsym.rs | 2 +- src/shims/posix/foreign_items.rs | 2 +- src/shims/windows/dlsym.rs | 2 +- src/shims/windows/foreign_items.rs | 2 +- .../concurrency/unwind_top_of_stack.rs | 7 ++-- 8 files changed, 29 insertions(+), 26 deletions(-) diff --git a/rust-version b/rust-version index 53ac7c54983bc..f064064db14c9 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -a4d9624242df6bfe6c0a298867dd2bd527263424 +b3ac52646f7591a811fa9bf55995b24fd17ece08 diff --git a/src/helpers.rs b/src/helpers.rs index 07356ab020327..e98488b9bf612 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -559,7 +559,7 @@ pub fn check_abi<'a>(abi: Abi, exp_abi: Abi) -> InterpResult<'a, ()> { if abi == exp_abi { Ok(()) } else { - throw_ub_format!("calling a function with ABI {:?} using caller ABI {:?}", exp_abi, abi) + throw_ub_format!("calling a function with ABI {} using caller ABI {}", exp_abi.name(), abi.name()) } } diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 9203aafd57673..373d5299618d5 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -146,14 +146,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "exit" | "ExitProcess" => { - check_abi(abi, if link_name == "exit" { Abi::C } else { Abi::System })?; + check_abi(abi, if link_name == "exit" { Abi::C { unwind: false } } else { Abi::System { unwind: false } })?; let &[ref code] = check_arg_count(args)?; // it's really u32 for ExitProcess, but we have to put it into the `Exit` variant anyway let code = this.read_scalar(code)?.to_i32()?; throw_machine_stop!(TerminationInfo::Exit(code.into())); } "abort" => { - check_abi(abi, Abi::C)?; + check_abi(abi, Abi::C { unwind: false })?; throw_machine_stop!(TerminationInfo::Abort("the program aborted execution".to_owned())) } _ => throw_unsup_format!("can't call (diverging) foreign function: {}", link_name), @@ -170,7 +170,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Normally, this will be either `libpanic_unwind` or `libpanic_abort`, but it could // also be a custom user-provided implementation via `#![feature(panic_runtime)]` "__rust_start_panic" | "__rust_panic_cleanup" => { - check_abi(abi, Abi::C)?; + check_abi(abi, Abi::C { unwind: false })?; // This replicates some of the logic in `inject_panic_runtime`. // FIXME: is there a way to reuse that logic? let panic_runtime = match this.tcx.sess.panic_strategy() { @@ -236,14 +236,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Standard C allocation "malloc" => { - check_abi(abi, Abi::C)?; + check_abi(abi, Abi::C { unwind: false })?; let &[ref size] = check_arg_count(args)?; let size = this.read_scalar(size)?.to_machine_usize(this)?; let res = this.malloc(size, /*zero_init:*/ false, MiriMemoryKind::C); this.write_scalar(res, dest)?; } "calloc" => { - check_abi(abi, Abi::C)?; + check_abi(abi, Abi::C { unwind: false })?; let &[ref items, ref len] = check_arg_count(args)?; let items = this.read_scalar(items)?.to_machine_usize(this)?; let len = this.read_scalar(len)?.to_machine_usize(this)?; @@ -253,13 +253,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(res, dest)?; } "free" => { - check_abi(abi, Abi::C)?; + check_abi(abi, Abi::C { unwind: false })?; let &[ref ptr] = check_arg_count(args)?; let ptr = this.read_scalar(ptr)?.check_init()?; this.free(ptr, MiriMemoryKind::C)?; } "realloc" => { - check_abi(abi, Abi::C)?; + check_abi(abi, Abi::C { unwind: false })?; let &[ref old_ptr, ref new_size] = check_arg_count(args)?; let old_ptr = this.read_scalar(old_ptr)?.check_init()?; let new_size = this.read_scalar(new_size)?.to_machine_usize(this)?; @@ -334,7 +334,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // C memory handling functions "memcmp" => { - check_abi(abi, Abi::C)?; + check_abi(abi, Abi::C { unwind: false })?; let &[ref left, ref right, ref n] = check_arg_count(args)?; let left = this.read_scalar(left)?.check_init()?; let right = this.read_scalar(right)?.check_init()?; @@ -355,7 +355,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_i32(result), dest)?; } "memrchr" => { - check_abi(abi, Abi::C)?; + check_abi(abi, Abi::C { unwind: false })?; let &[ref ptr, ref val, ref num] = check_arg_count(args)?; let ptr = this.read_scalar(ptr)?.check_init()?; let val = this.read_scalar(val)?.to_i32()? as u8; @@ -374,7 +374,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } "memchr" => { - check_abi(abi, Abi::C)?; + check_abi(abi, Abi::C { unwind: false })?; let &[ref ptr, ref val, ref num] = check_arg_count(args)?; let ptr = this.read_scalar(ptr)?.check_init()?; let val = this.read_scalar(val)?.to_i32()? as u8; @@ -392,7 +392,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } "strlen" => { - check_abi(abi, Abi::C)?; + check_abi(abi, Abi::C { unwind: false })?; let &[ref ptr] = check_arg_count(args)?; let ptr = this.read_scalar(ptr)?.check_init()?; let n = this.memory.read_c_str(ptr)?.len(); @@ -408,7 +408,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "asinf" | "atanf" => { - check_abi(abi, Abi::C)?; + check_abi(abi, Abi::C { unwind: false })?; let &[ref f] = check_arg_count(args)?; // FIXME: Using host floats. let f = f32::from_bits(this.read_scalar(f)?.to_u32()?); @@ -428,7 +428,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "hypotf" | "atan2f" => { - check_abi(abi, Abi::C)?; + check_abi(abi, Abi::C { unwind: false })?; let &[ref f1, ref f2] = check_arg_count(args)?; // underscore case for windows, here and below // (see https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/floating-point-primitives?view=vs-2019) @@ -450,7 +450,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "asin" | "atan" => { - check_abi(abi, Abi::C)?; + check_abi(abi, Abi::C { unwind: false })?; let &[ref f] = check_arg_count(args)?; // FIXME: Using host floats. let f = f64::from_bits(this.read_scalar(f)?.to_u64()?); @@ -470,7 +470,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "hypot" | "atan2" => { - check_abi(abi, Abi::C)?; + check_abi(abi, Abi::C { unwind: false })?; let &[ref f1, ref f2] = check_arg_count(args)?; // FIXME: Using host floats. let f1 = f64::from_bits(this.read_scalar(f1)?.to_u64()?); @@ -486,7 +486,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "ldexp" | "scalbn" => { - check_abi(abi, Abi::C)?; + check_abi(abi, Abi::C { unwind: false })?; let &[ref x, ref exp] = check_arg_count(args)?; // For radix-2 (binary) systems, `ldexp` and `scalbn` are the same. let x = this.read_scalar(x)?.to_f64()?; @@ -508,12 +508,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Architecture-specific shims "llvm.x86.sse2.pause" if this.tcx.sess.target.arch == "x86" || this.tcx.sess.target.arch == "x86_64" => { - check_abi(abi, Abi::C)?; + check_abi(abi, Abi::C { unwind: false })?; let &[] = check_arg_count(args)?; this.yield_active_thread(); } "llvm.aarch64.hint" if this.tcx.sess.target.arch == "aarch64" => { - check_abi(abi, Abi::C)?; + check_abi(abi, Abi::C { unwind: false })?; let &[ref hint] = check_arg_count(args)?; let hint = this.read_scalar(hint)?.to_i32()?; match hint { diff --git a/src/shims/posix/dlsym.rs b/src/shims/posix/dlsym.rs index e1eccc680883f..df9e945f29f75 100644 --- a/src/shims/posix/dlsym.rs +++ b/src/shims/posix/dlsym.rs @@ -35,7 +35,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - check_abi(abi, Abi::C)?; + check_abi(abi, Abi::C { unwind: false })?; match dlsym { Dlsym::Linux(dlsym) => linux::EvalContextExt::call_dlsym(this, dlsym, args, ret), diff --git a/src/shims/posix/foreign_items.rs b/src/shims/posix/foreign_items.rs index 21b5ed62bbb51..fdbe88cd7d612 100644 --- a/src/shims/posix/foreign_items.rs +++ b/src/shims/posix/foreign_items.rs @@ -22,7 +22,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, bool> { let this = self.eval_context_mut(); - check_abi(abi, Abi::C)?; + check_abi(abi, Abi::C { unwind: false })?; match link_name { // Environment related shims diff --git a/src/shims/windows/dlsym.rs b/src/shims/windows/dlsym.rs index 1f136060259a1..704b8872a4b03 100644 --- a/src/shims/windows/dlsym.rs +++ b/src/shims/windows/dlsym.rs @@ -32,7 +32,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let (_dest, _ret) = ret.expect("we don't support any diverging dlsym"); assert!(this.tcx.sess.target.os == "windows"); - check_abi(abi, Abi::System)?; + check_abi(abi, Abi::System { unwind: false })?; match dlsym {} } diff --git a/src/shims/windows/foreign_items.rs b/src/shims/windows/foreign_items.rs index f8d62f6b323bf..d9c5ce7896f66 100644 --- a/src/shims/windows/foreign_items.rs +++ b/src/shims/windows/foreign_items.rs @@ -20,7 +20,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, bool> { let this = self.eval_context_mut(); - check_abi(abi, Abi::System)?; + check_abi(abi, Abi::System { unwind: false })?; // Windows API stubs. // HANDLE = isize diff --git a/tests/compile-fail/concurrency/unwind_top_of_stack.rs b/tests/compile-fail/concurrency/unwind_top_of_stack.rs index 93b15202fc385..c13a2ac8bb046 100644 --- a/tests/compile-fail/concurrency/unwind_top_of_stack.rs +++ b/tests/compile-fail/concurrency/unwind_top_of_stack.rs @@ -3,13 +3,13 @@ //! Unwinding past the top frame of a stack is Undefined Behavior. -#![feature(rustc_private)] +#![feature(rustc_private, c_unwind)] extern crate libc; use std::{mem, ptr}; -extern "C" fn thread_start(_null: *mut libc::c_void) -> *mut libc::c_void { +extern "C-unwind" fn thread_start(_null: *mut libc::c_void) -> *mut libc::c_void { panic!() } @@ -18,6 +18,9 @@ fn main() { let mut native: libc::pthread_t = mem::zeroed(); let attr: libc::pthread_attr_t = mem::zeroed(); // assert_eq!(libc::pthread_attr_init(&mut attr), 0); FIXME: this function is not yet implemented. + // Cast to avoid inserting abort-on-unwind. + let thread_start: extern "C-unwind" fn(*mut libc::c_void) -> *mut libc::c_void = thread_start; + let thread_start: extern "C" fn(*mut libc::c_void) -> *mut libc::c_void = mem::transmute(thread_start); assert_eq!(libc::pthread_create(&mut native, &attr, thread_start, ptr::null_mut()), 0); assert_eq!(libc::pthread_join(native, ptr::null_mut()), 0); } From 893843fd455aa515a5d05cc8e70a970a84dab35d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 14 Mar 2021 15:30:37 +0100 Subject: [PATCH 2579/3747] when Miri calls a function ptr, make sure it has the right ABI --- src/eval.rs | 2 ++ src/helpers.rs | 6 ++++++ src/machine.rs | 1 + src/shims/panic.rs | 5 +++++ src/shims/posix/thread.rs | 2 ++ src/shims/tls.rs | 4 ++++ tests/compile-fail/concurrency/unwind_top_of_stack.rs | 5 ++++- 7 files changed, 24 insertions(+), 1 deletion(-) diff --git a/src/eval.rs b/src/eval.rs index 7a29d91d2d8ed..bd1aebe00de8f 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -8,6 +8,7 @@ use log::info; use rustc_hir::def_id::DefId; use rustc_middle::ty::{self, layout::LayoutCx, TyCtxt}; use rustc_target::abi::LayoutOf; +use rustc_target::spec::abi::Abi; use crate::*; @@ -189,6 +190,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( // Call start function. ecx.call_function( start_instance, + Abi::Rust, &[main_ptr.into(), argc.into(), argv.into()], Some(&ret_place.into()), StackPopCleanup::None { cleanup: true }, diff --git a/src/helpers.rs b/src/helpers.rs index e98488b9bf612..1f1c9922754c4 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -161,11 +161,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn call_function( &mut self, f: ty::Instance<'tcx>, + caller_abi: Abi, args: &[Immediate], dest: Option<&PlaceTy<'tcx, Tag>>, stack_pop: StackPopCleanup, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); + let param_env = ty::ParamEnv::reveal_all(); // in Miri this is always the param_env we use... and this.param_env is private. + let callee_abi = f.ty(*this.tcx, param_env).fn_sig(*this.tcx).abi(); + if callee_abi != caller_abi { + throw_ub_format!("calling a function with ABI {} using caller ABI {}", callee_abi.name(), caller_abi.name()) + } // Push frame. let mir = &*this.load_mir(f.def, None)?; diff --git a/src/machine.rs b/src/machine.rs index 1415f7506a4ec..99cb3bf2b29c0 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -430,6 +430,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { let malloc = ty::Instance::mono(ecx.tcx.tcx, malloc); ecx.call_function( malloc, + Abi::Rust, &[size.into(), align.into()], Some(dest), // Don't do anything when we are done. The `statement()` function will increment diff --git a/src/shims/panic.rs b/src/shims/panic.rs index abc7aa2ad1bdc..2c6d31549c353 100644 --- a/src/shims/panic.rs +++ b/src/shims/panic.rs @@ -15,6 +15,7 @@ use log::trace; use rustc_middle::{mir, ty}; use rustc_target::spec::PanicStrategy; +use rustc_target::spec::abi::Abi; use crate::*; use helpers::check_arg_count; @@ -94,6 +95,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let ret_place = MPlaceTy::dangling(this.machine.layouts.unit, this).into(); this.call_function( f_instance, + Abi::Rust, &[data.into()], Some(&ret_place), // Directly return to caller. @@ -145,6 +147,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let ret_place = MPlaceTy::dangling(this.machine.layouts.unit, this).into(); this.call_function( f_instance, + Abi::Rust, &[catch_unwind.data.into(), payload.into()], Some(&ret_place), // Directly return to caller of `try`. @@ -174,6 +177,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let panic = ty::Instance::mono(this.tcx.tcx, panic); this.call_function( panic, + Abi::Rust, &[msg.to_ref()], None, StackPopCleanup::Goto { ret: None, unwind }, @@ -202,6 +206,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let panic_bounds_check = ty::Instance::mono(this.tcx.tcx, panic_bounds_check); this.call_function( panic_bounds_check, + Abi::Rust, &[index.into(), len.into()], None, StackPopCleanup::Goto { ret: None, unwind }, diff --git a/src/shims/posix/thread.rs b/src/shims/posix/thread.rs index 40663326b4651..fb1c018fc34ba 100644 --- a/src/shims/posix/thread.rs +++ b/src/shims/posix/thread.rs @@ -2,6 +2,7 @@ use std::convert::TryInto; use crate::*; use rustc_target::abi::LayoutOf; +use rustc_target::spec::abi::Abi; impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { @@ -50,6 +51,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.call_function( instance, + Abi::C { unwind: false }, &[*func_arg], Some(&ret_place.into()), StackPopCleanup::None { cleanup: true }, diff --git a/src/shims/tls.rs b/src/shims/tls.rs index 36bae2af9cd03..ef77949efada5 100644 --- a/src/shims/tls.rs +++ b/src/shims/tls.rs @@ -9,6 +9,7 @@ use log::trace; use rustc_data_structures::fx::FxHashMap; use rustc_middle::ty; use rustc_target::abi::{Size, HasDataLayout}; +use rustc_target::spec::abi::Abi; use crate::*; @@ -244,6 +245,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let ret_place = MPlaceTy::dangling(this.machine.layouts.unit, this).into(); this.call_function( thread_callback, + Abi::System { unwind: false }, &[Scalar::null_ptr(this).into(), reason.into(), Scalar::null_ptr(this).into()], Some(&ret_place), StackPopCleanup::None { cleanup: true }, @@ -266,6 +268,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let ret_place = MPlaceTy::dangling(this.machine.layouts.unit, this).into(); this.call_function( instance, + Abi::C { unwind: false }, &[data.into()], Some(&ret_place), StackPopCleanup::None { cleanup: true }, @@ -306,6 +309,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let ret_place = MPlaceTy::dangling(this.machine.layouts.unit, this).into(); this.call_function( instance, + Abi::C { unwind: false }, &[ptr.into()], Some(&ret_place), StackPopCleanup::None { cleanup: true }, diff --git a/tests/compile-fail/concurrency/unwind_top_of_stack.rs b/tests/compile-fail/concurrency/unwind_top_of_stack.rs index c13a2ac8bb046..8f3bb17470b59 100644 --- a/tests/compile-fail/concurrency/unwind_top_of_stack.rs +++ b/tests/compile-fail/concurrency/unwind_top_of_stack.rs @@ -1,7 +1,10 @@ // ignore-windows: Concurrency on Windows is not supported yet. -// error-pattern: unwinding past the topmost frame of the stack +// error-pattern: calling a function with ABI C-unwind using caller ABI C //! Unwinding past the top frame of a stack is Undefined Behavior. +//! However, it is impossible to do that in pure Rust since one cannot write an unwinding +//! function with `C` ABI... so let's instead test that we are indeed correctly checking +//! the callee ABI in `pthread_create`. #![feature(rustc_private, c_unwind)] From d1dec9cd233bf28f2bab14126c3d9df93683ae17 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 14 Mar 2021 15:38:22 +0100 Subject: [PATCH 2580/3747] don't ICE when callee has the wrong number of arguments --- src/helpers.rs | 8 ++++-- .../compile-fail/concurrency/too_few_args.rs | 26 +++++++++++++++++++ .../compile-fail/concurrency/too_many_args.rs | 26 +++++++++++++++++++ 3 files changed, 58 insertions(+), 2 deletions(-) create mode 100644 tests/compile-fail/concurrency/too_few_args.rs create mode 100644 tests/compile-fail/concurrency/too_many_args.rs diff --git a/src/helpers.rs b/src/helpers.rs index 1f1c9922754c4..7fe0ae0a97c4c 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -181,11 +181,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let mut callee_args = this.frame().body.args_iter(); for arg in args { let callee_arg = this.local_place( - callee_args.next().expect("callee has fewer arguments than expected"), + callee_args.next().ok_or_else(|| + err_ub_format!("callee has fewer arguments than expected") + )? )?; this.write_immediate(*arg, &callee_arg)?; } - assert_eq!(callee_args.next(), None, "callee has more arguments than expected"); + if callee_args.next().is_some() { + throw_ub_format!("callee has more arguments than expected"); + } Ok(()) } diff --git a/tests/compile-fail/concurrency/too_few_args.rs b/tests/compile-fail/concurrency/too_few_args.rs new file mode 100644 index 0000000000000..e2dfa33af8989 --- /dev/null +++ b/tests/compile-fail/concurrency/too_few_args.rs @@ -0,0 +1,26 @@ +// ignore-windows: Concurrency on Windows is not supported yet. +// error-pattern: callee has fewer arguments than expected + +//! The thread function must have exactly one argument. + +#![feature(rustc_private)] + +extern crate libc; + +use std::{mem, ptr}; + +extern "C" fn thread_start() -> *mut libc::c_void { + panic!() +} + +fn main() { + unsafe { + let mut native: libc::pthread_t = mem::zeroed(); + let attr: libc::pthread_attr_t = mem::zeroed(); + // assert_eq!(libc::pthread_attr_init(&mut attr), 0); FIXME: this function is not yet implemented. + let thread_start: extern "C" fn() -> *mut libc::c_void = thread_start; + let thread_start: extern "C" fn(*mut libc::c_void) -> *mut libc::c_void = mem::transmute(thread_start); + assert_eq!(libc::pthread_create(&mut native, &attr, thread_start, ptr::null_mut()), 0); + assert_eq!(libc::pthread_join(native, ptr::null_mut()), 0); + } +} diff --git a/tests/compile-fail/concurrency/too_many_args.rs b/tests/compile-fail/concurrency/too_many_args.rs new file mode 100644 index 0000000000000..0ef12b07073fb --- /dev/null +++ b/tests/compile-fail/concurrency/too_many_args.rs @@ -0,0 +1,26 @@ +// ignore-windows: Concurrency on Windows is not supported yet. +// error-pattern: callee has more arguments than expected + +//! The thread function must have exactly one argument. + +#![feature(rustc_private)] + +extern crate libc; + +use std::{mem, ptr}; + +extern "C" fn thread_start(_null: *mut libc::c_void, _x: i32) -> *mut libc::c_void { + panic!() +} + +fn main() { + unsafe { + let mut native: libc::pthread_t = mem::zeroed(); + let attr: libc::pthread_attr_t = mem::zeroed(); + // assert_eq!(libc::pthread_attr_init(&mut attr), 0); FIXME: this function is not yet implemented. + let thread_start: extern "C" fn(*mut libc::c_void, i32) -> *mut libc::c_void = thread_start; + let thread_start: extern "C" fn(*mut libc::c_void) -> *mut libc::c_void = mem::transmute(thread_start); + assert_eq!(libc::pthread_create(&mut native, &attr, thread_start, ptr::null_mut()), 0); + assert_eq!(libc::pthread_join(native, ptr::null_mut()), 0); + } +} From c9ff02f549cf30cf9f3007b34fde89dcf0f46ac2 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 14 Mar 2021 17:03:20 +0100 Subject: [PATCH 2581/3747] ensure we catch incorrectly unwinding calls --- tests/compile-fail/panic/bad_unwind.rs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 tests/compile-fail/panic/bad_unwind.rs diff --git a/tests/compile-fail/panic/bad_unwind.rs b/tests/compile-fail/panic/bad_unwind.rs new file mode 100644 index 0000000000000..fde2c19af07d5 --- /dev/null +++ b/tests/compile-fail/panic/bad_unwind.rs @@ -0,0 +1,16 @@ +// error-pattern: calling a function with ABI C-unwind using caller ABI C +#![feature(c_unwind)] + +//! Unwinding when the caller ABI is "C" (without "-unwind") is UB. +//! Currently we detect the ABI mismatch; we could probably allow such calls in principle one day +//! but then we have to detect the unexpected unwinding. + +extern "C-unwind" fn unwind() { + panic!(); +} + +fn main() { + let unwind: extern "C-unwind" fn() = unwind; + let unwind: extern "C" fn() = unsafe { std::mem::transmute(unwind) }; + std::panic::catch_unwind(|| unwind()).unwrap_err(); +} From 15465a58812f7af4f5d27eb87da191b344d281b5 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 14 Mar 2021 17:10:45 +0100 Subject: [PATCH 2582/3747] don't ICE when we unwind despite panic=abort --- src/shims/panic.rs | 4 +++- tests/compile-fail/panic/unwind_panic_abort.rs | 11 +++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) create mode 100644 tests/compile-fail/panic/unwind_panic_abort.rs diff --git a/src/shims/panic.rs b/src/shims/panic.rs index abc7aa2ad1bdc..8f06e5276f527 100644 --- a/src/shims/panic.rs +++ b/src/shims/panic.rs @@ -45,7 +45,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx trace!("miri_start_panic: {:?}", this.frame().instance); // Make sure we only start unwinding when this matches our panic strategy. - assert_eq!(this.tcx.sess.panic_strategy(), PanicStrategy::Unwind); + if this.tcx.sess.panic_strategy() != PanicStrategy::Unwind { + throw_ub_format!("unwinding despite panic=abort"); + } // Get the raw pointer stored in arg[0] (the panic payload). let &[ref payload] = check_arg_count(args)?; diff --git a/tests/compile-fail/panic/unwind_panic_abort.rs b/tests/compile-fail/panic/unwind_panic_abort.rs new file mode 100644 index 0000000000000..05284eb770b22 --- /dev/null +++ b/tests/compile-fail/panic/unwind_panic_abort.rs @@ -0,0 +1,11 @@ +// compile-flags: -Cpanic=abort + +//! Unwinding despite `-C panic=abort` is an error. + +extern "Rust" { + fn miri_start_panic(payload: *mut u8) -> !; +} + +fn main() { + unsafe { miri_start_panic(&mut 0); } //~ ERROR unwinding despite panic=abort +} From 1c7d7471dae217810f48e594baca2e143a38da10 Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Wed, 17 Mar 2021 00:40:53 +0800 Subject: [PATCH 2583/3747] Don't duplicate `check_abi()` --- src/helpers.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index 7fe0ae0a97c4c..fe4766d87700a 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -169,9 +169,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); let param_env = ty::ParamEnv::reveal_all(); // in Miri this is always the param_env we use... and this.param_env is private. let callee_abi = f.ty(*this.tcx, param_env).fn_sig(*this.tcx).abi(); - if callee_abi != caller_abi { - throw_ub_format!("calling a function with ABI {} using caller ABI {}", callee_abi.name(), caller_abi.name()) - } + check_abi(caller_abi, callee_abi)?; // Push frame. let mir = &*this.load_mir(f.def, None)?; From bbc348539bce27627c60b4a27d6a822643f1c002 Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Wed, 17 Mar 2021 04:21:17 +0800 Subject: [PATCH 2584/3747] Unsupported foreign non-"C"/"system"-ABI function calls are not UB --- src/shims/foreign_items.rs | 30 +++++++++++++++++++ src/shims/posix/foreign_items.rs | 12 ++++---- src/shims/posix/linux/foreign_items.rs | 6 ++-- src/shims/posix/macos/foreign_items.rs | 8 +++-- src/shims/windows/foreign_items.rs | 8 ++--- .../unsupported_foreign_function.rs | 9 ++++++ tests/compile-fail/unsupported_posix_dlsym.rs | 14 +++++++++ .../compile-fail/unsupported_windows_dlsym.rs | 18 +++++++++++ 8 files changed, 88 insertions(+), 17 deletions(-) create mode 100644 tests/compile-fail/unsupported_foreign_function.rs create mode 100644 tests/compile-fail/unsupported_posix_dlsym.rs create mode 100644 tests/compile-fail/unsupported_windows_dlsym.rs diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 373d5299618d5..599d7268a3053 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -13,6 +13,36 @@ use crate::*; use super::backtrace::EvalContextExt as _; use helpers::{check_abi, check_arg_count}; +/// This macro behaves just like `match $link_name { ... }`, but inserts a +/// `$crate::helpers::check_abi($abi, $exp_abi)?` call at each match arm +/// except the wildcard one. +#[macro_export] +macro_rules! match_with_abi_check { + ($link_name:expr, $abi:expr, $exp_abi:expr, { + $(|)? $($pattern:pat)|+ $(if $guard:expr)? => $shim_impl:block + $($remaining:tt)+ + }) => { + match ($link_name, $abi, $exp_abi) { + ($($pattern)|+, abi, exp_abi) $(if $guard)? => { + $crate::helpers::check_abi(abi, exp_abi)?; + $shim_impl + } + (link_name, abi, exp_abi) => match_with_abi_check!( + link_name, + abi, + exp_abi, + { $($remaining)* } + ), + } + }; + ($link_name:ident, $abi:ident, $exp_abi:ident, { + _ => $fallback:expr $(,)? + }) => ({ + let _ = ($link_name, $abi, $exp_abi); + $fallback + }); +} + impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { /// Returns the minimum alignment for the target architecture for allocations of the given size. diff --git a/src/shims/posix/foreign_items.rs b/src/shims/posix/foreign_items.rs index fdbe88cd7d612..e773c8bcf360a 100644 --- a/src/shims/posix/foreign_items.rs +++ b/src/shims/posix/foreign_items.rs @@ -5,7 +5,7 @@ use rustc_target::abi::{Align, LayoutOf, Size}; use rustc_target::spec::abi::Abi; use crate::*; -use helpers::{check_abi, check_arg_count}; +use helpers::check_arg_count; use shims::posix::fs::EvalContextExt as _; use shims::posix::sync::EvalContextExt as _; use shims::posix::thread::EvalContextExt as _; @@ -22,9 +22,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, bool> { let this = self.eval_context_mut(); - check_abi(abi, Abi::C { unwind: false })?; - - match link_name { + match_with_abi_check!(link_name, abi, Abi::C { unwind: false }, { // Environment related shims "getenv" => { let &[ref name] = check_arg_count(args)?; @@ -458,12 +456,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Platform-specific shims _ => { match this.tcx.sess.target.os.as_str() { - "linux" => return shims::posix::linux::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, args, dest, ret), - "macos" => return shims::posix::macos::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, args, dest, ret), + "linux" => return shims::posix::linux::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, abi, args, dest, ret), + "macos" => return shims::posix::macos::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, abi, args, dest, ret), _ => unreachable!(), } } - }; + }); Ok(true) } diff --git a/src/shims/posix/linux/foreign_items.rs b/src/shims/posix/linux/foreign_items.rs index 2a3b512bcdb95..f61e37284e411 100644 --- a/src/shims/posix/linux/foreign_items.rs +++ b/src/shims/posix/linux/foreign_items.rs @@ -1,4 +1,5 @@ use rustc_middle::mir; +use rustc_target::spec::abi::Abi; use crate::*; use crate::helpers::check_arg_count; @@ -12,13 +13,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn emulate_foreign_item_by_name( &mut self, link_name: &str, + abi: Abi, args: &[OpTy<'tcx, Tag>], dest: &PlaceTy<'tcx, Tag>, _ret: mir::BasicBlock, ) -> InterpResult<'tcx, bool> { let this = self.eval_context_mut(); - match link_name { + match_with_abi_check!(link_name, abi, Abi::C { unwind: false }, { // errno "__errno_location" => { let &[] = check_arg_count(args)?; @@ -189,7 +191,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } _ => throw_unsup_format!("can't call foreign function: {}", link_name), - }; + }); Ok(true) } diff --git a/src/shims/posix/macos/foreign_items.rs b/src/shims/posix/macos/foreign_items.rs index 1ea12148303e2..cb57c4d2f6a14 100644 --- a/src/shims/posix/macos/foreign_items.rs +++ b/src/shims/posix/macos/foreign_items.rs @@ -1,4 +1,5 @@ use rustc_middle::mir; +use rustc_target::spec::abi::Abi; use crate::*; use helpers::check_arg_count; @@ -10,13 +11,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn emulate_foreign_item_by_name( &mut self, link_name: &str, + abi: Abi, args: &[OpTy<'tcx, Tag>], dest: &PlaceTy<'tcx, Tag>, _ret: mir::BasicBlock, ) -> InterpResult<'tcx, bool> { let this = self.eval_context_mut(); - match link_name { + match_with_abi_check!(link_name, abi, Abi::C { unwind: false }, { // errno "__error" => { let &[] = check_arg_count(args)?; @@ -83,7 +85,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let &[ref info] = check_arg_count(args)?; let result = this.mach_timebase_info(info)?; this.write_scalar(Scalar::from_i32(result), dest)?; - }, + } // Access to command-line arguments "_NSGetArgc" => { @@ -136,7 +138,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } _ => throw_unsup_format!("can't call foreign function: {}", link_name), - }; + }); Ok(true) } diff --git a/src/shims/windows/foreign_items.rs b/src/shims/windows/foreign_items.rs index d9c5ce7896f66..9e8e6b58985ee 100644 --- a/src/shims/windows/foreign_items.rs +++ b/src/shims/windows/foreign_items.rs @@ -5,7 +5,7 @@ use rustc_target::abi::Size; use rustc_target::spec::abi::Abi; use crate::*; -use helpers::{check_abi, check_arg_count}; +use helpers::check_arg_count; use shims::windows::sync::EvalContextExt as _; impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} @@ -20,14 +20,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, bool> { let this = self.eval_context_mut(); - check_abi(abi, Abi::System { unwind: false })?; - // Windows API stubs. // HANDLE = isize // DWORD = ULONG = u32 // BOOL = i32 // BOOLEAN = u8 - match link_name { + match_with_abi_check!(link_name, abi, Abi::System { unwind: false }, { // Environment related shims "GetEnvironmentVariableW" => { let &[ref name, ref buf, ref size] = check_arg_count(args)?; @@ -340,7 +338,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } _ => throw_unsup_format!("can't call foreign function: {}", link_name), - } + }); Ok(true) } diff --git a/tests/compile-fail/unsupported_foreign_function.rs b/tests/compile-fail/unsupported_foreign_function.rs new file mode 100644 index 0000000000000..b7f4d9038ec61 --- /dev/null +++ b/tests/compile-fail/unsupported_foreign_function.rs @@ -0,0 +1,9 @@ +fn main() { + extern "Rust" { + fn foo(); + } + + unsafe { + foo(); //~ ERROR unsupported operation: can't call foreign function: foo + } +} diff --git a/tests/compile-fail/unsupported_posix_dlsym.rs b/tests/compile-fail/unsupported_posix_dlsym.rs new file mode 100644 index 0000000000000..07859b311811e --- /dev/null +++ b/tests/compile-fail/unsupported_posix_dlsym.rs @@ -0,0 +1,14 @@ +// ignore-windows: No dlsym() on Windows + +#![feature(rustc_private)] + +extern crate libc; + +use std::ptr; + +fn main() { + unsafe { + libc::dlsym(ptr::null_mut(), b"foo\0".as_ptr().cast()); + //~^ ERROR unsupported operation: unsupported + } +} diff --git a/tests/compile-fail/unsupported_windows_dlsym.rs b/tests/compile-fail/unsupported_windows_dlsym.rs new file mode 100644 index 0000000000000..757eb815920e1 --- /dev/null +++ b/tests/compile-fail/unsupported_windows_dlsym.rs @@ -0,0 +1,18 @@ +// ignore-linux: GetProcAddress() is not available on Linux +// ignore-macos: GetProcAddress() is not available on macOS + +use std::{ffi::c_void, os::raw::c_char, ptr}; + +extern "system" { + fn GetProcAddress( + hModule: *mut c_void, + lpProcName: *const c_char, + ) -> extern "system" fn() -> isize; +} + +fn main() { + unsafe { + GetProcAddress(ptr::null_mut(), b"foo\0".as_ptr().cast()); + //~^ ERROR unsupported operation: unsupported Windows dlsym: foo + } +} From 3ee865461f3fa128835f3d79ea5f396e6ebdf6c1 Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Wed, 17 Mar 2021 21:51:07 +0800 Subject: [PATCH 2585/3747] Revert "Don't duplicate `check_abi()`" This reverts commit 1c7d7471dae217810f48e594baca2e143a38da10. --- src/helpers.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/helpers.rs b/src/helpers.rs index fe4766d87700a..7fe0ae0a97c4c 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -169,7 +169,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); let param_env = ty::ParamEnv::reveal_all(); // in Miri this is always the param_env we use... and this.param_env is private. let callee_abi = f.ty(*this.tcx, param_env).fn_sig(*this.tcx).abi(); - check_abi(caller_abi, callee_abi)?; + if callee_abi != caller_abi { + throw_ub_format!("calling a function with ABI {} using caller ABI {}", callee_abi.name(), caller_abi.name()) + } // Push frame. let mir = &*this.load_mir(f.def, None)?; From 633ac2a22226b27981b52ce6ed5af47fcc251746 Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Wed, 17 Mar 2021 21:55:45 +0800 Subject: [PATCH 2586/3747] Remove meaningless tests --- tests/compile-fail/unsupported_posix_dlsym.rs | 14 -------------- .../compile-fail/unsupported_windows_dlsym.rs | 18 ------------------ 2 files changed, 32 deletions(-) delete mode 100644 tests/compile-fail/unsupported_posix_dlsym.rs delete mode 100644 tests/compile-fail/unsupported_windows_dlsym.rs diff --git a/tests/compile-fail/unsupported_posix_dlsym.rs b/tests/compile-fail/unsupported_posix_dlsym.rs deleted file mode 100644 index 07859b311811e..0000000000000 --- a/tests/compile-fail/unsupported_posix_dlsym.rs +++ /dev/null @@ -1,14 +0,0 @@ -// ignore-windows: No dlsym() on Windows - -#![feature(rustc_private)] - -extern crate libc; - -use std::ptr; - -fn main() { - unsafe { - libc::dlsym(ptr::null_mut(), b"foo\0".as_ptr().cast()); - //~^ ERROR unsupported operation: unsupported - } -} diff --git a/tests/compile-fail/unsupported_windows_dlsym.rs b/tests/compile-fail/unsupported_windows_dlsym.rs deleted file mode 100644 index 757eb815920e1..0000000000000 --- a/tests/compile-fail/unsupported_windows_dlsym.rs +++ /dev/null @@ -1,18 +0,0 @@ -// ignore-linux: GetProcAddress() is not available on Linux -// ignore-macos: GetProcAddress() is not available on macOS - -use std::{ffi::c_void, os::raw::c_char, ptr}; - -extern "system" { - fn GetProcAddress( - hModule: *mut c_void, - lpProcName: *const c_char, - ) -> extern "system" fn() -> isize; -} - -fn main() { - unsafe { - GetProcAddress(ptr::null_mut(), b"foo\0".as_ptr().cast()); - //~^ ERROR unsupported operation: unsupported Windows dlsym: foo - } -} From 7ec919daa4c3e211dd2ef56014a11f967c583013 Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Wed, 17 Mar 2021 22:12:08 +0800 Subject: [PATCH 2587/3747] Remove the macro and expand it manually --- src/shims/foreign_items.rs | 30 ------------ src/shims/posix/foreign_items.rs | 67 ++++++++++++++++++++++++-- src/shims/posix/linux/foreign_items.rs | 22 +++++++-- src/shims/posix/macos/foreign_items.rs | 27 +++++++++-- src/shims/windows/foreign_items.rs | 45 +++++++++++++++-- 5 files changed, 148 insertions(+), 43 deletions(-) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 599d7268a3053..373d5299618d5 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -13,36 +13,6 @@ use crate::*; use super::backtrace::EvalContextExt as _; use helpers::{check_abi, check_arg_count}; -/// This macro behaves just like `match $link_name { ... }`, but inserts a -/// `$crate::helpers::check_abi($abi, $exp_abi)?` call at each match arm -/// except the wildcard one. -#[macro_export] -macro_rules! match_with_abi_check { - ($link_name:expr, $abi:expr, $exp_abi:expr, { - $(|)? $($pattern:pat)|+ $(if $guard:expr)? => $shim_impl:block - $($remaining:tt)+ - }) => { - match ($link_name, $abi, $exp_abi) { - ($($pattern)|+, abi, exp_abi) $(if $guard)? => { - $crate::helpers::check_abi(abi, exp_abi)?; - $shim_impl - } - (link_name, abi, exp_abi) => match_with_abi_check!( - link_name, - abi, - exp_abi, - { $($remaining)* } - ), - } - }; - ($link_name:ident, $abi:ident, $exp_abi:ident, { - _ => $fallback:expr $(,)? - }) => ({ - let _ = ($link_name, $abi, $exp_abi); - $fallback - }); -} - impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { /// Returns the minimum alignment for the target architecture for allocations of the given size. diff --git a/src/shims/posix/foreign_items.rs b/src/shims/posix/foreign_items.rs index e773c8bcf360a..b3d53cdc10ded 100644 --- a/src/shims/posix/foreign_items.rs +++ b/src/shims/posix/foreign_items.rs @@ -5,7 +5,7 @@ use rustc_target::abi::{Align, LayoutOf, Size}; use rustc_target::spec::abi::Abi; use crate::*; -use helpers::check_arg_count; +use helpers::{check_abi, check_arg_count}; use shims::posix::fs::EvalContextExt as _; use shims::posix::sync::EvalContextExt as _; use shims::posix::thread::EvalContextExt as _; @@ -22,30 +22,35 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, bool> { let this = self.eval_context_mut(); - match_with_abi_check!(link_name, abi, Abi::C { unwind: false }, { + match link_name { // Environment related shims "getenv" => { + check_abi(abi, Abi::C { unwind: false })?; let &[ref name] = check_arg_count(args)?; let result = this.getenv(name)?; this.write_scalar(result, dest)?; } "unsetenv" => { + check_abi(abi, Abi::C { unwind: false })?; let &[ref name] = check_arg_count(args)?; let result = this.unsetenv(name)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "setenv" => { + check_abi(abi, Abi::C { unwind: false })?; let &[ref name, ref value, ref overwrite] = check_arg_count(args)?; this.read_scalar(overwrite)?.to_i32()?; let result = this.setenv(name, value)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "getcwd" => { + check_abi(abi, Abi::C { unwind: false })?; let &[ref buf, ref size] = check_arg_count(args)?; let result = this.getcwd(buf, size)?; this.write_scalar(result, dest)?; } "chdir" => { + check_abi(abi, Abi::C { unwind: false })?; let &[ref path] = check_arg_count(args)?; let result = this.chdir(path)?; this.write_scalar(Scalar::from_i32(result), dest)?; @@ -53,15 +58,18 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // File related shims "open" | "open64" => { + check_abi(abi, Abi::C { unwind: false })?; let &[ref path, ref flag, ref mode] = check_arg_count(args)?; let result = this.open(path, flag, mode)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "fcntl" => { + check_abi(abi, Abi::C { unwind: false })?; let result = this.fcntl(args)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "read" => { + check_abi(abi, Abi::C { unwind: false })?; let &[ref fd, ref buf, ref count] = check_arg_count(args)?; let fd = this.read_scalar(fd)?.to_i32()?; let buf = this.read_scalar(buf)?.check_init()?; @@ -70,6 +78,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_machine_isize(result, this), dest)?; } "write" => { + check_abi(abi, Abi::C { unwind: false })?; let &[ref fd, ref buf, ref n] = check_arg_count(args)?; let fd = this.read_scalar(fd)?.to_i32()?; let buf = this.read_scalar(buf)?.check_init()?; @@ -80,52 +89,62 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_machine_isize(result, this), dest)?; } "unlink" => { + check_abi(abi, Abi::C { unwind: false })?; let &[ref path] = check_arg_count(args)?; let result = this.unlink(path)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "symlink" => { + check_abi(abi, Abi::C { unwind: false })?; let &[ref target, ref linkpath] = check_arg_count(args)?; let result = this.symlink(target, linkpath)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "rename" => { + check_abi(abi, Abi::C { unwind: false })?; let &[ref oldpath, ref newpath] = check_arg_count(args)?; let result = this.rename(oldpath, newpath)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "mkdir" => { + check_abi(abi, Abi::C { unwind: false })?; let &[ref path, ref mode] = check_arg_count(args)?; let result = this.mkdir(path, mode)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "rmdir" => { + check_abi(abi, Abi::C { unwind: false })?; let &[ref path] = check_arg_count(args)?; let result = this.rmdir(path)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "closedir" => { + check_abi(abi, Abi::C { unwind: false })?; let &[ref dirp] = check_arg_count(args)?; let result = this.closedir(dirp)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "lseek" | "lseek64" => { + check_abi(abi, Abi::C { unwind: false })?; let &[ref fd, ref offset, ref whence] = check_arg_count(args)?; let result = this.lseek64(fd, offset, whence)?; // "lseek" is only used on macOS which is 64bit-only, so `i64` always works. this.write_scalar(Scalar::from_i64(result), dest)?; } "fsync" => { + check_abi(abi, Abi::C { unwind: false })?; let &[ref fd] = check_arg_count(args)?; let result = this.fsync(fd)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "fdatasync" => { + check_abi(abi, Abi::C { unwind: false })?; let &[ref fd] = check_arg_count(args)?; let result = this.fdatasync(fd)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "readlink" => { + check_abi(abi, Abi::C { unwind: false })?; let &[ref pathname, ref buf, ref bufsize] = check_arg_count(args)?; let result = this.readlink(pathname, buf, bufsize)?; this.write_scalar(Scalar::from_machine_isize(result, this), dest)?; @@ -133,6 +152,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Allocation "posix_memalign" => { + check_abi(abi, Abi::C { unwind: false })?; let &[ref ret, ref align, ref size] = check_arg_count(args)?; let ret = this.deref_operand(ret)?; let align = this.read_scalar(align)?.to_machine_usize(this)?; @@ -163,6 +183,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Dynamic symbol loading "dlsym" => { + check_abi(abi, Abi::C { unwind: false })?; let &[ref handle, ref symbol] = check_arg_count(args)?; this.read_scalar(handle)?.to_machine_usize(this)?; let symbol = this.read_scalar(symbol)?.check_init()?; @@ -177,6 +198,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Querying system information "sysconf" => { + check_abi(abi, Abi::C { unwind: false })?; let &[ref name] = check_arg_count(args)?; let name = this.read_scalar(name)?.to_i32()?; @@ -202,6 +224,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Thread-local storage "pthread_key_create" => { + check_abi(abi, Abi::C { unwind: false })?; let &[ref key, ref dtor] = check_arg_count(args)?; let key_place = this.deref_operand(key)?; let dtor = this.read_scalar(dtor)?.check_init()?; @@ -230,6 +253,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_null(dest)?; } "pthread_key_delete" => { + check_abi(abi, Abi::C { unwind: false })?; let &[ref key] = check_arg_count(args)?; let key = this.force_bits(this.read_scalar(key)?.check_init()?, key.layout.size)?; this.machine.tls.delete_tls_key(key)?; @@ -237,6 +261,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_null(dest)?; } "pthread_getspecific" => { + check_abi(abi, Abi::C { unwind: false })?; let &[ref key] = check_arg_count(args)?; let key = this.force_bits(this.read_scalar(key)?.check_init()?, key.layout.size)?; let active_thread = this.get_active_thread(); @@ -244,6 +269,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(ptr, dest)?; } "pthread_setspecific" => { + check_abi(abi, Abi::C { unwind: false })?; let &[ref key, ref new_ptr] = check_arg_count(args)?; let key = this.force_bits(this.read_scalar(key)?.check_init()?, key.layout.size)?; let active_thread = this.get_active_thread(); @@ -256,110 +282,132 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Synchronization primitives "pthread_mutexattr_init" => { + check_abi(abi, Abi::C { unwind: false })?; let &[ref attr] = check_arg_count(args)?; let result = this.pthread_mutexattr_init(attr)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_mutexattr_settype" => { + check_abi(abi, Abi::C { unwind: false })?; let &[ref attr, ref kind] = check_arg_count(args)?; let result = this.pthread_mutexattr_settype(attr, kind)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_mutexattr_destroy" => { + check_abi(abi, Abi::C { unwind: false })?; let &[ref attr] = check_arg_count(args)?; let result = this.pthread_mutexattr_destroy(attr)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_mutex_init" => { + check_abi(abi, Abi::C { unwind: false })?; let &[ref mutex, ref attr] = check_arg_count(args)?; let result = this.pthread_mutex_init(mutex, attr)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_mutex_lock" => { + check_abi(abi, Abi::C { unwind: false })?; let &[ref mutex] = check_arg_count(args)?; let result = this.pthread_mutex_lock(mutex)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_mutex_trylock" => { + check_abi(abi, Abi::C { unwind: false })?; let &[ref mutex] = check_arg_count(args)?; let result = this.pthread_mutex_trylock(mutex)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_mutex_unlock" => { + check_abi(abi, Abi::C { unwind: false })?; let &[ref mutex] = check_arg_count(args)?; let result = this.pthread_mutex_unlock(mutex)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_mutex_destroy" => { + check_abi(abi, Abi::C { unwind: false })?; let &[ref mutex] = check_arg_count(args)?; let result = this.pthread_mutex_destroy(mutex)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_rwlock_rdlock" => { + check_abi(abi, Abi::C { unwind: false })?; let &[ref rwlock] = check_arg_count(args)?; let result = this.pthread_rwlock_rdlock(rwlock)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_rwlock_tryrdlock" => { + check_abi(abi, Abi::C { unwind: false })?; let &[ref rwlock] = check_arg_count(args)?; let result = this.pthread_rwlock_tryrdlock(rwlock)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_rwlock_wrlock" => { + check_abi(abi, Abi::C { unwind: false })?; let &[ref rwlock] = check_arg_count(args)?; let result = this.pthread_rwlock_wrlock(rwlock)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_rwlock_trywrlock" => { + check_abi(abi, Abi::C { unwind: false })?; let &[ref rwlock] = check_arg_count(args)?; let result = this.pthread_rwlock_trywrlock(rwlock)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_rwlock_unlock" => { + check_abi(abi, Abi::C { unwind: false })?; let &[ref rwlock] = check_arg_count(args)?; let result = this.pthread_rwlock_unlock(rwlock)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_rwlock_destroy" => { + check_abi(abi, Abi::C { unwind: false })?; let &[ref rwlock] = check_arg_count(args)?; let result = this.pthread_rwlock_destroy(rwlock)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_condattr_init" => { + check_abi(abi, Abi::C { unwind: false })?; let &[ref attr] = check_arg_count(args)?; let result = this.pthread_condattr_init(attr)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_condattr_destroy" => { + check_abi(abi, Abi::C { unwind: false })?; let &[ref attr] = check_arg_count(args)?; let result = this.pthread_condattr_destroy(attr)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_cond_init" => { + check_abi(abi, Abi::C { unwind: false })?; let &[ref cond, ref attr] = check_arg_count(args)?; let result = this.pthread_cond_init(cond, attr)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_cond_signal" => { + check_abi(abi, Abi::C { unwind: false })?; let &[ref cond] = check_arg_count(args)?; let result = this.pthread_cond_signal(cond)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_cond_broadcast" => { + check_abi(abi, Abi::C { unwind: false })?; let &[ref cond] = check_arg_count(args)?; let result = this.pthread_cond_broadcast(cond)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_cond_wait" => { + check_abi(abi, Abi::C { unwind: false })?; let &[ref cond, ref mutex] = check_arg_count(args)?; let result = this.pthread_cond_wait(cond, mutex)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_cond_timedwait" => { + check_abi(abi, Abi::C { unwind: false })?; let &[ref cond, ref mutex, ref abstime] = check_arg_count(args)?; this.pthread_cond_timedwait(cond, mutex, abstime, dest)?; } "pthread_cond_destroy" => { + check_abi(abi, Abi::C { unwind: false })?; let &[ref cond] = check_arg_count(args)?; let result = this.pthread_cond_destroy(cond)?; this.write_scalar(Scalar::from_i32(result), dest)?; @@ -367,30 +415,36 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Threading "pthread_create" => { + check_abi(abi, Abi::C { unwind: false })?; let &[ref thread, ref attr, ref start, ref arg] = check_arg_count(args)?; let result = this.pthread_create(thread, attr, start, arg)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_join" => { + check_abi(abi, Abi::C { unwind: false })?; let &[ref thread, ref retval] = check_arg_count(args)?; let result = this.pthread_join(thread, retval)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_detach" => { + check_abi(abi, Abi::C { unwind: false })?; let &[ref thread] = check_arg_count(args)?; let result = this.pthread_detach(thread)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_self" => { + check_abi(abi, Abi::C { unwind: false })?; let &[] = check_arg_count(args)?; this.pthread_self(dest)?; } "sched_yield" => { + check_abi(abi, Abi::C { unwind: false })?; let &[] = check_arg_count(args)?; let result = this.sched_yield()?; this.write_scalar(Scalar::from_i32(result), dest)?; } "nanosleep" => { + check_abi(abi, Abi::C { unwind: false })?; let &[ref req, ref rem] = check_arg_count(args)?; let result = this.nanosleep(req, rem)?; this.write_scalar(Scalar::from_i32(result), dest)?; @@ -398,6 +452,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Miscellaneous "isatty" => { + check_abi(abi, Abi::C { unwind: false })?; let &[ref fd] = check_arg_count(args)?; this.read_scalar(fd)?.to_i32()?; // "returns 1 if fd is an open file descriptor referring to a terminal; otherwise 0 is returned, and errno is set to indicate the error" @@ -407,6 +462,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_null(dest)?; } "pthread_atfork" => { + check_abi(abi, Abi::C { unwind: false })?; let &[ref prepare, ref parent, ref child] = check_arg_count(args)?; this.force_bits(this.read_scalar(prepare)?.check_init()?, this.memory.pointer_size())?; this.force_bits(this.read_scalar(parent)?.check_init()?, this.memory.pointer_size())?; @@ -419,6 +475,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // These shims are enabled only when the caller is in the standard library. "pthread_attr_getguardsize" if this.frame().instance.to_string().starts_with("std::sys::unix::") => { + check_abi(abi, Abi::C { unwind: false })?; let &[ref _attr, ref guard_size] = check_arg_count(args)?; let guard_size = this.deref_operand(guard_size)?; let guard_size_layout = this.libc_ty_layout("size_t")?; @@ -431,11 +488,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "pthread_attr_init" | "pthread_attr_destroy" if this.frame().instance.to_string().starts_with("std::sys::unix::") => { + check_abi(abi, Abi::C { unwind: false })?; let &[_] = check_arg_count(args)?; this.write_null(dest)?; } | "pthread_attr_setstacksize" if this.frame().instance.to_string().starts_with("std::sys::unix::") => { + check_abi(abi, Abi::C { unwind: false })?; let &[_, _] = check_arg_count(args)?; this.write_null(dest)?; } @@ -443,12 +502,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "signal" | "sigaltstack" if this.frame().instance.to_string().starts_with("std::sys::unix::") => { + check_abi(abi, Abi::C { unwind: false })?; let &[_, _] = check_arg_count(args)?; this.write_null(dest)?; } | "sigaction" | "mprotect" if this.frame().instance.to_string().starts_with("std::sys::unix::") => { + check_abi(abi, Abi::C { unwind: false })?; let &[_, _, _] = check_arg_count(args)?; this.write_null(dest)?; } @@ -461,7 +522,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx _ => unreachable!(), } } - }); + }; Ok(true) } diff --git a/src/shims/posix/linux/foreign_items.rs b/src/shims/posix/linux/foreign_items.rs index f61e37284e411..fe989b5924dfd 100644 --- a/src/shims/posix/linux/foreign_items.rs +++ b/src/shims/posix/linux/foreign_items.rs @@ -2,7 +2,7 @@ use rustc_middle::mir; use rustc_target::spec::abi::Abi; use crate::*; -use crate::helpers::check_arg_count; +use crate::helpers::{check_abi, check_arg_count}; use shims::posix::fs::EvalContextExt as _; use shims::posix::linux::sync::futex; use shims::posix::sync::EvalContextExt as _; @@ -20,9 +20,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, bool> { let this = self.eval_context_mut(); - match_with_abi_check!(link_name, abi, Abi::C { unwind: false }, { + match link_name { // errno "__errno_location" => { + check_abi(abi, Abi::C { unwind: false })?; let &[] = check_arg_count(args)?; let errno_place = this.last_error_place()?; this.write_scalar(errno_place.to_ref().to_scalar()?, dest)?; @@ -32,27 +33,32 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // These symbols have different names on Linux and macOS, which is the only reason they are not // in the `posix` module. "close" => { + check_abi(abi, Abi::C { unwind: false })?; let &[ref fd] = check_arg_count(args)?; let result = this.close(fd)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "opendir" => { + check_abi(abi, Abi::C { unwind: false })?; let &[ref name] = check_arg_count(args)?; let result = this.opendir(name)?; this.write_scalar(result, dest)?; } "readdir64_r" => { + check_abi(abi, Abi::C { unwind: false })?; let &[ref dirp, ref entry, ref result] = check_arg_count(args)?; let result = this.linux_readdir64_r(dirp, entry, result)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "ftruncate64" => { + check_abi(abi, Abi::C { unwind: false })?; let &[ref fd, ref length] = check_arg_count(args)?; let result = this.ftruncate64(fd, length)?; this.write_scalar(Scalar::from_i32(result), dest)?; } // Linux-only "posix_fadvise" => { + check_abi(abi, Abi::C { unwind: false })?; let &[ref fd, ref offset, ref len, ref advice] = check_arg_count(args)?; this.read_scalar(fd)?.to_i32()?; this.read_scalar(offset)?.to_machine_isize(this)?; @@ -62,6 +68,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_null(dest)?; } "sync_file_range" => { + check_abi(abi, Abi::C { unwind: false })?; let &[ref fd, ref offset, ref nbytes, ref flags] = check_arg_count(args)?; let result = this.sync_file_range(fd, offset, nbytes, flags)?; this.write_scalar(Scalar::from_i32(result), dest)?; @@ -69,6 +76,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Time related shims "clock_gettime" => { + check_abi(abi, Abi::C { unwind: false })?; // This is a POSIX function but it has only been tested on linux. let &[ref clk_id, ref tp] = check_arg_count(args)?; let result = this.clock_gettime(clk_id, tp)?; @@ -77,6 +85,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Querying system information "pthread_attr_getstack" => { + check_abi(abi, Abi::C { unwind: false })?; // We don't support "pthread_attr_setstack", so we just pretend all stacks have the same values here. let &[ref attr_place, ref addr_place, ref size_place] = check_arg_count(args)?; this.deref_operand(attr_place)?; @@ -98,16 +107,19 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Threading "prctl" => { + check_abi(abi, Abi::C { unwind: false })?; let &[ref option, ref arg2, ref arg3, ref arg4, ref arg5] = check_arg_count(args)?; let result = this.prctl(option, arg2, arg3, arg4, arg5)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_condattr_setclock" => { + check_abi(abi, Abi::C { unwind: false })?; let &[ref attr, ref clock_id] = check_arg_count(args)?; let result = this.pthread_condattr_setclock(attr, clock_id)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_condattr_getclock" => { + check_abi(abi, Abi::C { unwind: false })?; let &[ref attr, ref clock_id] = check_arg_count(args)?; let result = this.pthread_condattr_getclock(attr, clock_id)?; this.write_scalar(Scalar::from_i32(result), dest)?; @@ -115,6 +127,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Dynamically invoked syscalls "syscall" => { + check_abi(abi, Abi::C { unwind: false })?; // The syscall variadic function is legal to call with more arguments than needed, // extra arguments are simply ignored. However, all arguments need to be scalars; // other types might be treated differently by the calling convention. @@ -169,10 +182,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Miscelanneous "getrandom" => { + check_abi(abi, Abi::C { unwind: false })?; let &[ref ptr, ref len, ref flags] = check_arg_count(args)?; getrandom(this, ptr, len, flags, dest)?; } "sched_getaffinity" => { + check_abi(abi, Abi::C { unwind: false })?; let &[ref pid, ref cpusetsize, ref mask] = check_arg_count(args)?; this.read_scalar(pid)?.to_i32()?; this.read_scalar(cpusetsize)?.to_machine_usize(this)?; @@ -186,12 +201,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Incomplete shims that we "stub out" just to get pre-main initialization code to work. // These shims are enabled only when the caller is in the standard library. "pthread_getattr_np" if this.frame().instance.to_string().starts_with("std::sys::unix::") => { + check_abi(abi, Abi::C { unwind: false })?; let &[ref _thread, ref _attr] = check_arg_count(args)?; this.write_null(dest)?; } _ => throw_unsup_format!("can't call foreign function: {}", link_name), - }); + }; Ok(true) } diff --git a/src/shims/posix/macos/foreign_items.rs b/src/shims/posix/macos/foreign_items.rs index cb57c4d2f6a14..dce9eea668e63 100644 --- a/src/shims/posix/macos/foreign_items.rs +++ b/src/shims/posix/macos/foreign_items.rs @@ -2,7 +2,7 @@ use rustc_middle::mir; use rustc_target::spec::abi::Abi; use crate::*; -use helpers::check_arg_count; +use helpers::{check_abi, check_arg_count}; use shims::posix::fs::EvalContextExt as _; use shims::posix::thread::EvalContextExt as _; @@ -18,9 +18,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, bool> { let this = self.eval_context_mut(); - match_with_abi_check!(link_name, abi, Abi::C { unwind: false }, { + match link_name { // errno "__error" => { + check_abi(abi, Abi::C { unwind: false })?; let &[] = check_arg_count(args)?; let errno_place = this.last_error_place()?; this.write_scalar(errno_place.to_ref().to_scalar()?, dest)?; @@ -28,36 +29,43 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // File related shims "close" | "close$NOCANCEL" => { + check_abi(abi, Abi::C { unwind: false })?; let &[ref result] = check_arg_count(args)?; let result = this.close(result)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "stat" | "stat$INODE64" => { + check_abi(abi, Abi::C { unwind: false })?; let &[ref path, ref buf] = check_arg_count(args)?; let result = this.macos_stat(path, buf)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "lstat" | "lstat$INODE64" => { + check_abi(abi, Abi::C { unwind: false })?; let &[ref path, ref buf] = check_arg_count(args)?; let result = this.macos_lstat(path, buf)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "fstat" | "fstat$INODE64" => { + check_abi(abi, Abi::C { unwind: false })?; let &[ref fd, ref buf] = check_arg_count(args)?; let result = this.macos_fstat(fd, buf)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "opendir" | "opendir$INODE64" => { + check_abi(abi, Abi::C { unwind: false })?; let &[ref name] = check_arg_count(args)?; let result = this.opendir(name)?; this.write_scalar(result, dest)?; } "readdir_r" | "readdir_r$INODE64" => { + check_abi(abi, Abi::C { unwind: false })?; let &[ref dirp, ref entry, ref result] = check_arg_count(args)?; let result = this.macos_readdir_r(dirp, entry, result)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "ftruncate" => { + check_abi(abi, Abi::C { unwind: false })?; let &[ref fd, ref length] = check_arg_count(args)?; let result = this.ftruncate64(fd, length)?; this.write_scalar(Scalar::from_i32(result), dest)?; @@ -65,40 +73,47 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Environment related shims "_NSGetEnviron" => { + check_abi(abi, Abi::C { unwind: false })?; let &[] = check_arg_count(args)?; this.write_scalar(this.machine.env_vars.environ.unwrap().ptr, dest)?; } // Time related shims "gettimeofday" => { + check_abi(abi, Abi::C { unwind: false })?; let &[ref tv, ref tz] = check_arg_count(args)?; let result = this.gettimeofday(tv, tz)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "mach_absolute_time" => { + check_abi(abi, Abi::C { unwind: false })?; let &[] = check_arg_count(args)?; let result = this.mach_absolute_time()?; this.write_scalar(Scalar::from_u64(result), dest)?; } "mach_timebase_info" => { + check_abi(abi, Abi::C { unwind: false })?; let &[ref info] = check_arg_count(args)?; let result = this.mach_timebase_info(info)?; this.write_scalar(Scalar::from_i32(result), dest)?; - } + }, // Access to command-line arguments "_NSGetArgc" => { + check_abi(abi, Abi::C { unwind: false })?; let &[] = check_arg_count(args)?; this.write_scalar(this.machine.argc.expect("machine must be initialized"), dest)?; } "_NSGetArgv" => { + check_abi(abi, Abi::C { unwind: false })?; let &[] = check_arg_count(args)?; this.write_scalar(this.machine.argv.expect("machine must be initialized"), dest)?; } // Thread-local storage "_tlv_atexit" => { + check_abi(abi, Abi::C { unwind: false })?; let &[ref dtor, ref data] = check_arg_count(args)?; let dtor = this.read_scalar(dtor)?.check_init()?; let dtor = this.memory.get_fn(dtor)?.as_instance()?; @@ -109,12 +124,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Querying system information "pthread_get_stackaddr_np" => { + check_abi(abi, Abi::C { unwind: false })?; let &[ref thread] = check_arg_count(args)?; this.read_scalar(thread)?.to_machine_usize(this)?; let stack_addr = Scalar::from_uint(STACK_ADDR, this.pointer_size()); this.write_scalar(stack_addr, dest)?; } "pthread_get_stacksize_np" => { + check_abi(abi, Abi::C { unwind: false })?; let &[ref thread] = check_arg_count(args)?; this.read_scalar(thread)?.to_machine_usize(this)?; let stack_size = Scalar::from_uint(STACK_SIZE, this.pointer_size()); @@ -123,6 +140,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Threading "pthread_setname_np" => { + check_abi(abi, Abi::C { unwind: false })?; let &[ref name] = check_arg_count(args)?; let name = this.read_scalar(name)?.check_init()?; this.pthread_setname_np(name)?; @@ -131,6 +149,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Incomplete shims that we "stub out" just to get pre-main initialization code to work. // These shims are enabled only when the caller is in the standard library. "mmap" if this.frame().instance.to_string().starts_with("std::sys::unix::") => { + check_abi(abi, Abi::C { unwind: false })?; // This is a horrible hack, but since the guard page mechanism calls mmap and expects a particular return value, we just give it that value. let &[ref addr, _, _, _, _, _] = check_arg_count(args)?; let addr = this.read_scalar(addr)?.check_init()?; @@ -138,7 +157,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } _ => throw_unsup_format!("can't call foreign function: {}", link_name), - }); + }; Ok(true) } diff --git a/src/shims/windows/foreign_items.rs b/src/shims/windows/foreign_items.rs index 9e8e6b58985ee..72b776380b99a 100644 --- a/src/shims/windows/foreign_items.rs +++ b/src/shims/windows/foreign_items.rs @@ -5,7 +5,7 @@ use rustc_target::abi::Size; use rustc_target::spec::abi::Abi; use crate::*; -use helpers::check_arg_count; +use helpers::{check_abi, check_arg_count}; use shims::windows::sync::EvalContextExt as _; impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} @@ -25,34 +25,40 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // DWORD = ULONG = u32 // BOOL = i32 // BOOLEAN = u8 - match_with_abi_check!(link_name, abi, Abi::System { unwind: false }, { + match link_name { // Environment related shims "GetEnvironmentVariableW" => { + check_abi(abi, Abi::System { unwind: false })?; let &[ref name, ref buf, ref size] = check_arg_count(args)?; let result = this.GetEnvironmentVariableW(name, buf, size)?; this.write_scalar(Scalar::from_u32(result), dest)?; } "SetEnvironmentVariableW" => { + check_abi(abi, Abi::System { unwind: false })?; let &[ref name, ref value] = check_arg_count(args)?; let result = this.SetEnvironmentVariableW(name, value)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "GetEnvironmentStringsW" => { + check_abi(abi, Abi::System { unwind: false })?; let &[] = check_arg_count(args)?; let result = this.GetEnvironmentStringsW()?; this.write_scalar(result, dest)?; } "FreeEnvironmentStringsW" => { + check_abi(abi, Abi::System { unwind: false })?; let &[ref env_block] = check_arg_count(args)?; let result = this.FreeEnvironmentStringsW(env_block)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "GetCurrentDirectoryW" => { + check_abi(abi, Abi::System { unwind: false })?; let &[ref size, ref buf] = check_arg_count(args)?; let result = this.GetCurrentDirectoryW(size, buf)?; this.write_scalar(Scalar::from_u32(result), dest)?; } "SetCurrentDirectoryW" => { + check_abi(abi, Abi::System { unwind: false })?; let &[ref path] = check_arg_count(args)?; let result = this.SetCurrentDirectoryW(path)?; this.write_scalar(Scalar::from_i32(result), dest)?; @@ -60,6 +66,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // File related shims "GetStdHandle" => { + check_abi(abi, Abi::System { unwind: false })?; let &[ref which] = check_arg_count(args)?; let which = this.read_scalar(which)?.to_i32()?; // We just make this the identity function, so we know later in `WriteFile` @@ -67,6 +74,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_machine_isize(which.into(), this), dest)?; } "WriteFile" => { + check_abi(abi, Abi::System { unwind: false })?; let &[ref handle, ref buf, ref n, ref written_ptr, ref overlapped] = check_arg_count(args)?; this.read_scalar(overlapped)?.to_machine_usize(this)?; // this is a poiner, that we ignore let handle = this.read_scalar(handle)?.to_machine_isize(this)?; @@ -102,6 +110,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Allocation "HeapAlloc" => { + check_abi(abi, Abi::System { unwind: false })?; let &[ref handle, ref flags, ref size] = check_arg_count(args)?; this.read_scalar(handle)?.to_machine_isize(this)?; let flags = this.read_scalar(flags)?.to_u32()?; @@ -111,6 +120,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(res, dest)?; } "HeapFree" => { + check_abi(abi, Abi::System { unwind: false })?; let &[ref handle, ref flags, ref ptr] = check_arg_count(args)?; this.read_scalar(handle)?.to_machine_isize(this)?; this.read_scalar(flags)?.to_u32()?; @@ -119,6 +129,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_i32(1), dest)?; } "HeapReAlloc" => { + check_abi(abi, Abi::System { unwind: false })?; let &[ref handle, ref flags, ref ptr, ref size] = check_arg_count(args)?; this.read_scalar(handle)?.to_machine_isize(this)?; this.read_scalar(flags)?.to_u32()?; @@ -130,11 +141,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // errno "SetLastError" => { + check_abi(abi, Abi::System { unwind: false })?; let &[ref error] = check_arg_count(args)?; let error = this.read_scalar(error)?.check_init()?; this.set_last_error(error)?; } "GetLastError" => { + check_abi(abi, Abi::System { unwind: false })?; let &[] = check_arg_count(args)?; let last_error = this.get_last_error()?; this.write_scalar(last_error, dest)?; @@ -142,6 +155,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Querying system information "GetSystemInfo" => { + check_abi(abi, Abi::System { unwind: false })?; let &[ref system_info] = check_arg_count(args)?; let system_info = this.deref_operand(system_info)?; // Initialize with `0`. @@ -157,6 +171,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Thread-local storage "TlsAlloc" => { + check_abi(abi, Abi::System { unwind: false })?; // This just creates a key; Windows does not natively support TLS destructors. // Create key and return it. @@ -165,6 +180,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_uint(key, dest.layout.size), dest)?; } "TlsGetValue" => { + check_abi(abi, Abi::System { unwind: false })?; let &[ref key] = check_arg_count(args)?; let key = u128::from(this.read_scalar(key)?.to_u32()?); let active_thread = this.get_active_thread(); @@ -172,6 +188,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(ptr, dest)?; } "TlsSetValue" => { + check_abi(abi, Abi::System { unwind: false })?; let &[ref key, ref new_ptr] = check_arg_count(args)?; let key = u128::from(this.read_scalar(key)?.to_u32()?); let active_thread = this.get_active_thread(); @@ -184,6 +201,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Access to command-line arguments "GetCommandLineW" => { + check_abi(abi, Abi::System { unwind: false })?; let &[] = check_arg_count(args)?; this.write_scalar( this.machine.cmd_line.expect("machine must be initialized"), @@ -193,17 +211,20 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Time related shims "GetSystemTimeAsFileTime" => { + check_abi(abi, Abi::System { unwind: false })?; #[allow(non_snake_case)] let &[ref LPFILETIME] = check_arg_count(args)?; this.GetSystemTimeAsFileTime(LPFILETIME)?; } "QueryPerformanceCounter" => { + check_abi(abi, Abi::System { unwind: false })?; #[allow(non_snake_case)] let &[ref lpPerformanceCount] = check_arg_count(args)?; let result = this.QueryPerformanceCounter(lpPerformanceCount)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "QueryPerformanceFrequency" => { + check_abi(abi, Abi::System { unwind: false })?; #[allow(non_snake_case)] let &[ref lpFrequency] = check_arg_count(args)?; let result = this.QueryPerformanceFrequency(lpFrequency)?; @@ -212,27 +233,33 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Synchronization primitives "AcquireSRWLockExclusive" => { + check_abi(abi, Abi::System { unwind: false })?; let &[ref ptr] = check_arg_count(args)?; this.AcquireSRWLockExclusive(ptr)?; } "ReleaseSRWLockExclusive" => { + check_abi(abi, Abi::System { unwind: false })?; let &[ref ptr] = check_arg_count(args)?; this.ReleaseSRWLockExclusive(ptr)?; } "TryAcquireSRWLockExclusive" => { + check_abi(abi, Abi::System { unwind: false })?; let &[ref ptr] = check_arg_count(args)?; let ret = this.TryAcquireSRWLockExclusive(ptr)?; this.write_scalar(Scalar::from_u8(ret), dest)?; } "AcquireSRWLockShared" => { + check_abi(abi, Abi::System { unwind: false })?; let &[ref ptr] = check_arg_count(args)?; this.AcquireSRWLockShared(ptr)?; } "ReleaseSRWLockShared" => { + check_abi(abi, Abi::System { unwind: false })?; let &[ref ptr] = check_arg_count(args)?; this.ReleaseSRWLockShared(ptr)?; } "TryAcquireSRWLockShared" => { + check_abi(abi, Abi::System { unwind: false })?; let &[ref ptr] = check_arg_count(args)?; let ret = this.TryAcquireSRWLockShared(ptr)?; this.write_scalar(Scalar::from_u8(ret), dest)?; @@ -240,6 +267,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Dynamic symbol loading "GetProcAddress" => { + check_abi(abi, Abi::System { unwind: false })?; #[allow(non_snake_case)] let &[ref hModule, ref lpProcName] = check_arg_count(args)?; this.read_scalar(hModule)?.to_machine_isize(this)?; @@ -254,6 +282,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Miscellaneous "SystemFunction036" => { + check_abi(abi, Abi::System { unwind: false })?; // The actual name of 'RtlGenRandom' let &[ref ptr, ref len] = check_arg_count(args)?; let ptr = this.read_scalar(ptr)?.check_init()?; @@ -262,6 +291,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_bool(true), dest)?; } "GetConsoleScreenBufferInfo" => { + check_abi(abi, Abi::System { unwind: false })?; // `term` needs this, so we fake it. let &[ref console, ref buffer_info] = check_arg_count(args)?; this.read_scalar(console)?.to_machine_isize(this)?; @@ -271,6 +301,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_null(dest)?; } "GetConsoleMode" => { + check_abi(abi, Abi::System { unwind: false })?; // Windows "isatty" (in libtest) needs this, so we fake it. let &[ref console, ref mode] = check_arg_count(args)?; this.read_scalar(console)?.to_machine_isize(this)?; @@ -280,6 +311,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_null(dest)?; } "SwitchToThread" => { + check_abi(abi, Abi::System { unwind: false })?; let &[] = check_arg_count(args)?; // Note that once Miri supports concurrency, this will need to return a nonzero // value if this call does result in switching to another thread. @@ -288,29 +320,34 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Better error for attempts to create a thread "CreateThread" => { + check_abi(abi, Abi::System { unwind: false })?; throw_unsup_format!("Miri does not support concurrency on Windows"); } // Incomplete shims that we "stub out" just to get pre-main initialization code to work. // These shims are enabled only when the caller is in the standard library. "GetProcessHeap" if this.frame().instance.to_string().starts_with("std::sys::windows::") => { + check_abi(abi, Abi::System { unwind: false })?; let &[] = check_arg_count(args)?; // Just fake a HANDLE this.write_scalar(Scalar::from_machine_isize(1, this), dest)?; } "SetConsoleTextAttribute" if this.frame().instance.to_string().starts_with("std::sys::windows::") => { + check_abi(abi, Abi::System { unwind: false })?; #[allow(non_snake_case)] let &[ref _hConsoleOutput, ref _wAttribute] = check_arg_count(args)?; // Pretend these does not exist / nothing happened, by returning zero. this.write_null(dest)?; } "AddVectoredExceptionHandler" if this.frame().instance.to_string().starts_with("std::sys::windows::") => { + check_abi(abi, Abi::System { unwind: false })?; #[allow(non_snake_case)] let &[ref _First, ref _Handler] = check_arg_count(args)?; // Any non zero value works for the stdlib. This is just used for stack overflows anyway. this.write_scalar(Scalar::from_machine_usize(1, this), dest)?; } "SetThreadStackGuarantee" if this.frame().instance.to_string().starts_with("std::sys::windows::") => { + check_abi(abi, Abi::System { unwind: false })?; #[allow(non_snake_case)] let &[_StackSizeInBytes] = check_arg_count(args)?; // Any non zero value works for the stdlib. This is just used for stack overflows anyway. @@ -321,6 +358,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "LeaveCriticalSection" | "DeleteCriticalSection" if this.frame().instance.to_string().starts_with("std::sys::windows::") => { + check_abi(abi, Abi::System { unwind: false })?; #[allow(non_snake_case)] let &[ref _lpCriticalSection] = check_arg_count(args)?; assert_eq!(this.get_total_thread_count(), 1, "concurrency on Windows is not supported"); @@ -330,6 +368,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "TryEnterCriticalSection" if this.frame().instance.to_string().starts_with("std::sys::windows::") => { + check_abi(abi, Abi::System { unwind: false })?; #[allow(non_snake_case)] let &[ref _lpCriticalSection] = check_arg_count(args)?; assert_eq!(this.get_total_thread_count(), 1, "concurrency on Windows is not supported"); @@ -338,7 +377,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } _ => throw_unsup_format!("can't call foreign function: {}", link_name), - }); + } Ok(true) } From 4f899ce9acb3827cc45fd4a8672372b1ff64b8b2 Mon Sep 17 00:00:00 2001 From: bstrie <865233+bstrie@users.noreply.github.com> Date: Wed, 17 Mar 2021 18:34:44 -0400 Subject: [PATCH 2588/3747] Replace deprecated `collections::Bound` --- src/shims/tls.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shims/tls.rs b/src/shims/tls.rs index ef77949efada5..3339e3bee1999 100644 --- a/src/shims/tls.rs +++ b/src/shims/tls.rs @@ -174,7 +174,7 @@ impl<'tcx> TlsData<'tcx> { key: Option, thread_id: ThreadId, ) -> Option<(ty::Instance<'tcx>, Scalar, TlsKey)> { - use std::collections::Bound::*; + use std::ops::Bound::*; let thread_local = &mut self.keys; let start = match key { From fc88c6ccca6849b1e7909f8d10a8968e12bcbb29 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 18 Mar 2021 00:19:53 +0100 Subject: [PATCH 2589/3747] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index f064064db14c9..bd571f788acbd 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -b3ac52646f7591a811fa9bf55995b24fd17ece08 +36f1f04f18b89ba4a999bcfd6584663fd6fc1c5d From 263be25484b6df50e71702e46798881f1ccae5f6 Mon Sep 17 00:00:00 2001 From: Johnathan Van Why Date: Fri, 19 Mar 2021 09:27:36 -0700 Subject: [PATCH 2590/3747] Improvements to the README item on `-Zmiri-track-raw-pointers`. 1. The double quotes around are changed to backspaces, so will render correctly in markdown. 2. Clarify that -Zmiri-track-raw-pointers will never accept code that Miri would not have accepted without -Zmiri-track-raw-pointers. --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index ae70c80d5f0a1..59f7b970546ef 100644 --- a/README.md +++ b/README.md @@ -252,9 +252,10 @@ environment variable: * `-Zmiri-track-raw-pointers` makes Stacked Borrows track a pointer tag even for raw pointers. This can make valid code fail to pass the checks, but also can help identify latent aliasing issues in code that Miri accepts by default. You - can recognize false positives by "" occurring in the message -- this + can recognize false positives by `` occurring in the message -- this indicates a pointer that was cast from an integer, so Miri was unable to track - this pointer. + this pointer. It does not have false negatives; code that works with + `-Zmiri-track-raw-pointers` will work without `-Zmiri-track-raw-pointers`. Some native rustc `-Z` flags are also very relevant for Miri: From b4b048cc86efbb6c64b038fc8c943565aca76c4e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 22 Mar 2021 12:35:30 +0100 Subject: [PATCH 2591/3747] rustup; better comment in storage_dead_dangling test --- rust-version | 2 +- tests/compile-fail/storage_dead_dangling.rs | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/rust-version b/rust-version index bd571f788acbd..f2c3c6ff54627 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -36f1f04f18b89ba4a999bcfd6584663fd6fc1c5d +2b8fbe6b0b6db7960828bd2c9a50e52c9a5d0aef diff --git a/tests/compile-fail/storage_dead_dangling.rs b/tests/compile-fail/storage_dead_dangling.rs index ad8e05537e1af..4d91498eac168 100644 --- a/tests/compile-fail/storage_dead_dangling.rs +++ b/tests/compile-fail/storage_dead_dangling.rs @@ -18,5 +18,7 @@ fn main() { fill(&mut x); _y = x; } + // Now we use a pointer to `x` which is no longer in scope, and thus dead (even though the + // `main` stack frame still exists). evil(); } From 03be4138ed134370979aec04ff5fe23cab6bcf74 Mon Sep 17 00:00:00 2001 From: Johnathan Van Why Date: Mon, 22 Mar 2021 15:35:18 -0700 Subject: [PATCH 2592/3747] `-Zmiri-track-raw-pointers` doc correction: it is not strictly more restrictive than Stacked Borrows. This change is based on the following comment: https://github.com/rust-lang/miri/pull/1748#issuecomment-803279473 --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 59f7b970546ef..5e5b82b36547e 100644 --- a/README.md +++ b/README.md @@ -254,8 +254,9 @@ environment variable: help identify latent aliasing issues in code that Miri accepts by default. You can recognize false positives by `` occurring in the message -- this indicates a pointer that was cast from an integer, so Miri was unable to track - this pointer. It does not have false negatives; code that works with - `-Zmiri-track-raw-pointers` will work without `-Zmiri-track-raw-pointers`. + this pointer. Note that it is not currently guaranteed that code that works + with `-Zmiri-track-raw-pointers` also works without + `-Zmiri-track-raw-pointers`. Some native rustc `-Z` flags are also very relevant for Miri: From 4eed6107230fa14930bff8c8e091aa18bcc1e072 Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Tue, 23 Mar 2021 16:41:53 +0800 Subject: [PATCH 2593/3747] Remove `#![feature(or_patterns)]` --- src/lib.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 7fc080a937f00..6a5e7af237269 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,7 +2,6 @@ #![feature(map_first_last)] #![feature(map_try_insert)] #![feature(never_type)] -#![feature(or_patterns)] #![feature(try_blocks)] #![warn(rust_2018_idioms)] From 08aef5a8aa889a11e5ce36f795182082d9ba742e Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Tue, 23 Mar 2021 16:55:46 +0800 Subject: [PATCH 2594/3747] Update `rust-version` --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index f2c3c6ff54627..3b05153d81cb9 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -2b8fbe6b0b6db7960828bd2c9a50e52c9a5d0aef +5d04957a4b4714f71d38326fc96a0b0ef6dc5800 From 12005612ab7f2c84d4ceca8132dd7483bd892061 Mon Sep 17 00:00:00 2001 From: Johnathan Van Why Date: Wed, 24 Mar 2021 16:20:54 -0700 Subject: [PATCH 2595/3747] README.md: Apply RalfJung's suggestion `-Zmiri-track-raw-pointers` isn't *much* more restrictive than normal Stacked Borrows. Co-authored-by: Ralf Jung --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 5e5b82b36547e..8a0c5180e002d 100644 --- a/README.md +++ b/README.md @@ -256,7 +256,7 @@ environment variable: indicates a pointer that was cast from an integer, so Miri was unable to track this pointer. Note that it is not currently guaranteed that code that works with `-Zmiri-track-raw-pointers` also works without - `-Zmiri-track-raw-pointers`. + `-Zmiri-track-raw-pointers`, but for the vast majority of code, this will be the case. Some native rustc `-Z` flags are also very relevant for Miri: From 726495f48965b81ff5462e535bb1a5a4c2b0c0a5 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 25 Mar 2021 12:17:02 +0100 Subject: [PATCH 2596/3747] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 3b05153d81cb9..fe5d17a963bfd 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -5d04957a4b4714f71d38326fc96a0b0ef6dc5800 +372afcf93bf60e1a9334b107cc3d72f1b0a4b1f4 From 585e51aabdcab2ec0b43fabfdd169d4a81ff39fa Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 25 Mar 2021 12:44:30 +0100 Subject: [PATCH 2597/3747] disable MIR opts for ZST-related tests --- tests/compile-fail/dangling_pointers/dangling_zst_deref.rs | 3 ++- .../dangling_pointers/maybe_null_pointer_deref_zst.rs | 3 +++ .../dangling_pointers/maybe_null_pointer_write_zst.rs | 3 +++ tests/compile-fail/null_pointer_deref_zst.rs | 3 +++ tests/compile-fail/null_pointer_write_zst.rs | 3 +++ tests/compile-fail/unaligned_pointers/unaligned_ptr_zst.rs | 3 ++- tests/compile-fail/zst2.rs | 3 +++ tests/compile-fail/zst3.rs | 3 +++ 8 files changed, 22 insertions(+), 2 deletions(-) diff --git a/tests/compile-fail/dangling_pointers/dangling_zst_deref.rs b/tests/compile-fail/dangling_pointers/dangling_zst_deref.rs index f1b5149dabb41..01e864213df79 100644 --- a/tests/compile-fail/dangling_pointers/dangling_zst_deref.rs +++ b/tests/compile-fail/dangling_pointers/dangling_zst_deref.rs @@ -1,5 +1,6 @@ // Make sure we find these even with many checks disabled. -// compile-flags: -Zmiri-disable-alignment-check -Zmiri-disable-stacked-borrows -Zmiri-disable-validation +// Some optimizations remove ZST accesses, thus masking this UB. +// compile-flags: -Zmir-opt-level=0 -Zmiri-disable-alignment-check -Zmiri-disable-stacked-borrows -Zmiri-disable-validation fn main() { let p = { diff --git a/tests/compile-fail/dangling_pointers/maybe_null_pointer_deref_zst.rs b/tests/compile-fail/dangling_pointers/maybe_null_pointer_deref_zst.rs index d9f5ad4c696e1..9db8a7dcba982 100644 --- a/tests/compile-fail/dangling_pointers/maybe_null_pointer_deref_zst.rs +++ b/tests/compile-fail/dangling_pointers/maybe_null_pointer_deref_zst.rs @@ -1,3 +1,6 @@ +// Some optimizations remove ZST accesses, thus masking this UB. +// compile-flags: -Zmir-opt-level=0 + fn main() { // This pointer *could* be NULL so we cannot load from it, not even at ZST let ptr = (&0u8 as *const u8).wrapping_sub(0x800) as *const (); diff --git a/tests/compile-fail/dangling_pointers/maybe_null_pointer_write_zst.rs b/tests/compile-fail/dangling_pointers/maybe_null_pointer_write_zst.rs index ef46a469c3ad1..79eff2507ceb2 100644 --- a/tests/compile-fail/dangling_pointers/maybe_null_pointer_write_zst.rs +++ b/tests/compile-fail/dangling_pointers/maybe_null_pointer_write_zst.rs @@ -1,3 +1,6 @@ +// Some optimizations remove ZST accesses, thus masking this UB. +// compile-flags: -Zmir-opt-level=0 + fn main() { // This pointer *could* be NULL so we cannot load from it, not even at ZST. // Not using the () type here, as writes of that type do not even have MIR generated. diff --git a/tests/compile-fail/null_pointer_deref_zst.rs b/tests/compile-fail/null_pointer_deref_zst.rs index cfd3a75e3b8cf..d0f21a04d364e 100644 --- a/tests/compile-fail/null_pointer_deref_zst.rs +++ b/tests/compile-fail/null_pointer_deref_zst.rs @@ -1,3 +1,6 @@ +// Some optimizations remove ZST accesses, thus masking this UB. +// compile-flags: -Zmir-opt-level=0 + fn main() { let x: () = unsafe { *std::ptr::null() }; //~ ERROR memory access failed: 0x0 is not a valid pointer panic!("this should never print: {:?}", x); diff --git a/tests/compile-fail/null_pointer_write_zst.rs b/tests/compile-fail/null_pointer_write_zst.rs index 0f7244ba25ccf..1ee1a4b8a3035 100644 --- a/tests/compile-fail/null_pointer_write_zst.rs +++ b/tests/compile-fail/null_pointer_write_zst.rs @@ -1,3 +1,6 @@ +// Some optimizations remove ZST accesses, thus masking this UB. +// compile-flags: -Zmir-opt-level=0 + fn main() { // Not using the () type here, as writes of that type do not even have MIR generated. // Also not assigning directly as that's array initialization, not assignment. diff --git a/tests/compile-fail/unaligned_pointers/unaligned_ptr_zst.rs b/tests/compile-fail/unaligned_pointers/unaligned_ptr_zst.rs index a9db5ff7df39e..27403c11abc74 100644 --- a/tests/compile-fail/unaligned_pointers/unaligned_ptr_zst.rs +++ b/tests/compile-fail/unaligned_pointers/unaligned_ptr_zst.rs @@ -1,5 +1,6 @@ // This should fail even without validation -// compile-flags: -Zmiri-disable-validation +// Some optimizations remove ZST accesses, thus masking this UB. +// compile-flags: -Zmir-opt-level=0 -Zmiri-disable-validation fn main() { for i in 0..10 { // Try many times as this might work by chance. diff --git a/tests/compile-fail/zst2.rs b/tests/compile-fail/zst2.rs index 907337dcdb2b4..a602cb731e402 100644 --- a/tests/compile-fail/zst2.rs +++ b/tests/compile-fail/zst2.rs @@ -1,3 +1,6 @@ +// Some optimizations remove ZST accesses, thus masking this UB. +// compile-flags: -Zmir-opt-level=0 + fn main() { // Not using the () type here, as writes of that type do not even have MIR generated. // Also not assigning directly as that's array initialization, not assignment. diff --git a/tests/compile-fail/zst3.rs b/tests/compile-fail/zst3.rs index c94591174ec5c..734c4b8ac4b8f 100644 --- a/tests/compile-fail/zst3.rs +++ b/tests/compile-fail/zst3.rs @@ -1,3 +1,6 @@ +// Some optimizations remove ZST accesses, thus masking this UB. +// compile-flags: -Zmir-opt-level=0 + fn main() { // Not using the () type here, as writes of that type do not even have MIR generated. // Also not assigning directly as that's array initialization, not assignment. From de0f3f930b800ff672b373bd6ab0af9fba3b3a05 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 28 Mar 2021 01:36:41 +0100 Subject: [PATCH 2598/3747] rustup --- rust-version | 2 +- tests/compile-fail/unaligned_pointers/reference_to_packed.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/rust-version b/rust-version index fe5d17a963bfd..8fadf6f9a3b2c 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -372afcf93bf60e1a9334b107cc3d72f1b0a4b1f4 +9b0edb7fddacd6a60a380c1ce59159de597ab270 diff --git a/tests/compile-fail/unaligned_pointers/reference_to_packed.rs b/tests/compile-fail/unaligned_pointers/reference_to_packed.rs index 6fa9521185352..b376859d22c11 100644 --- a/tests/compile-fail/unaligned_pointers/reference_to_packed.rs +++ b/tests/compile-fail/unaligned_pointers/reference_to_packed.rs @@ -1,7 +1,7 @@ // This should fail even without validation/SB // compile-flags: -Zmiri-disable-validation -Zmiri-disable-stacked-borrows -#![allow(dead_code, unused_variables)] +#![allow(dead_code, unused_variables, unaligned_references)] #[repr(packed)] struct Foo { @@ -15,7 +15,7 @@ fn main() { x: 42, y: 99, }; - let p = unsafe { &foo.x }; + let p = &foo.x; let i = *p; //~ERROR alignment 4 is required } } From 650411492c138912e5972cee8d953331540ac457 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 4 Apr 2021 11:09:40 +0200 Subject: [PATCH 2599/3747] also test getrandom directly --- test-cargo-miri/Cargo.lock | 34 ++++++++++++++++++++++++++++++---- test-cargo-miri/Cargo.toml | 1 + test-cargo-miri/tests/test.rs | 4 ++++ 3 files changed, 35 insertions(+), 4 deletions(-) diff --git a/test-cargo-miri/Cargo.lock b/test-cargo-miri/Cargo.lock index 1f1541b92a563..3473d86c486b0 100644 --- a/test-cargo-miri/Cargo.lock +++ b/test-cargo-miri/Cargo.lock @@ -1,5 +1,7 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. +version = 3 + [[package]] name = "byteorder" version = "1.3.4" @@ -12,6 +14,7 @@ version = "0.1.0" dependencies = [ "byteorder", "cdylib", + "getrandom 0.2.2", "issue_1567", "issue_1691", "issue_1705", @@ -32,15 +35,32 @@ version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + [[package]] name = "getrandom" version = "0.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc587bc0ec293155d5bfa6b9891ec18a1e330c234f896ea47fbada4cadbe47e6" dependencies = [ - "cfg-if", + "cfg-if 0.1.10", "libc", - "wasi", + "wasi 0.9.0+wasi-snapshot-preview1", +] + +[[package]] +name = "getrandom" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9495705279e7140bf035dde1f6e750c162df8b625267cd52cc44e0b156732c8" +dependencies = [ + "cfg-if 1.0.0", + "libc", + "wasi 0.10.2+wasi-snapshot-preview1", ] [[package]] @@ -116,7 +136,7 @@ version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" dependencies = [ - "getrandom", + "getrandom 0.1.15", "libc", "rand_chacha", "rand_core", @@ -140,7 +160,7 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" dependencies = [ - "getrandom", + "getrandom 0.1.15", ] [[package]] @@ -201,3 +221,9 @@ name = "wasi" version = "0.9.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" + +[[package]] +name = "wasi" +version = "0.10.2+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" diff --git a/test-cargo-miri/Cargo.toml b/test-cargo-miri/Cargo.toml index 7ffe7d04ea475..c9619b6b4baa7 100644 --- a/test-cargo-miri/Cargo.toml +++ b/test-cargo-miri/Cargo.toml @@ -16,6 +16,7 @@ issue_1705 = { path = "issue-1705" } [dev-dependencies] rand = { version = "0.7", features = ["small_rng"] } +getrandom = { version = "0.2" } serde_derive = "1.0" # not actually used, but exercises some unique code path (`--extern` .so file) [lib] diff --git a/test-cargo-miri/tests/test.rs b/test-cargo-miri/tests/test.rs index 436e919e050d9..33b814eeeeeba 100644 --- a/test-cargo-miri/tests/test.rs +++ b/test-cargo-miri/tests/test.rs @@ -24,6 +24,10 @@ fn does_not_work_on_miri() { #[test] fn entropy_rng() { + // Test `getrandom` directly. + let mut data = vec![0; 16]; + getrandom::getrandom(&mut data).unwrap(); + // Try seeding with "real" entropy. let mut rng = SmallRng::from_entropy(); let _val = rng.gen::(); From 0f7c01527af7ee5b39c279c99cef437ab5715580 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 4 Apr 2021 11:11:19 +0200 Subject: [PATCH 2600/3747] 'cargo update' all the things --- Cargo.lock | 209 ++++++++++++++++++++++--------------- cargo-miri/Cargo.lock | 105 +++++++++++++------ test-cargo-miri/Cargo.lock | 46 ++++---- 3 files changed, 217 insertions(+), 143 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 102d29a804355..fdac5d4542e76 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,5 +1,7 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. +version = 3 + [[package]] name = "aho-corasick" version = "0.7.15" @@ -11,9 +13,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.35" +version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c0df63cb2955042487fad3aefd2c6e3ae7389ac5dc1beb28921de0b69f779d4" +checksum = "28b2cd92db5cbd74e8e5028f7e27dd7aa3090e89e4f2a197cc7c8dfb69c7063b" [[package]] name = "arrayref" @@ -50,6 +52,12 @@ version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" +[[package]] +name = "bitflags" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" + [[package]] name = "blake2b_simd" version = "0.5.11" @@ -114,9 +122,9 @@ checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" [[package]] name = "crossbeam-utils" -version = "0.8.1" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02d96d1e189ef58269ebe5b97953da3274d83a93af647c2ddd6f9dab28cedb8d" +checksum = "e7e9d99fa91428effe99c5c6d4634cdeba32b8cf784fc428a2a687f61a952c49" dependencies = [ "autocfg", "cfg-if 1.0.0", @@ -165,13 +173,13 @@ dependencies = [ [[package]] name = "filetime" -version = "0.2.13" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c122a393ea57648015bf06fbd3d372378992e86b9ff5a7a497b076a28c79efe" +checksum = "1d34cfa13a63ae058bfa601fe9e313bbdb3746427c1459185464ce0fcf62e1e8" dependencies = [ "cfg-if 1.0.0", "libc", - "redox_syscall", + "redox_syscall 0.2.5", "winapi", ] @@ -186,40 +194,40 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.1.15" +version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc587bc0ec293155d5bfa6b9891ec18a1e330c234f896ea47fbada4cadbe47e6" +checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" dependencies = [ - "cfg-if 0.1.10", + "cfg-if 1.0.0", "libc", - "wasi", + "wasi 0.9.0+wasi-snapshot-preview1", ] [[package]] name = "getrandom" -version = "0.2.0" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee8025cf36f917e6a52cce185b7c7177689b838b7ec138364e50cc2277a56cf4" +checksum = "c9495705279e7140bf035dde1f6e750c162df8b625267cd52cc44e0b156732c8" dependencies = [ - "cfg-if 0.1.10", + "cfg-if 1.0.0", "libc", - "wasi", + "wasi 0.10.2+wasi-snapshot-preview1", ] [[package]] name = "hermit-abi" -version = "0.1.17" +version = "0.1.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5aca5565f760fb5b220e499d72710ed156fdb74e631659e99377d9ebfbd13ae8" +checksum = "322f4de77956e22ed0e5032c359a0f1273f1f7f0d79bfa3b8ffbc730d7fbcc5c" dependencies = [ "libc", ] [[package]] name = "hex" -version = "0.4.2" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "644f9158b2f133fd50f5fb3242878846d9eb792e445c893805ff0e3824006e35" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" [[package]] name = "humantime" @@ -232,9 +240,9 @@ dependencies = [ [[package]] name = "itoa" -version = "0.4.6" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc6f3ad7b9d11a0c00842ff8de1b60ee58661048eb8049ed33c73594f359d7e6" +checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736" [[package]] name = "lazy_static" @@ -244,17 +252,17 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.81" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1482821306169ec4d07f6aca392a4681f66c75c9918aa49641a2595db64053cb" +checksum = "56d855069fafbb9b344c0f962150cd2c1187975cb1c22c1522c240d8c4986714" [[package]] name = "log" -version = "0.4.11" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fabed175da42fed1fa0746b0ea71f412aa9d35e76e95e59b192c64b9dc2bf8b" +checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" dependencies = [ - "cfg-if 0.1.10", + "cfg-if 1.0.0", ] [[package]] @@ -265,11 +273,10 @@ checksum = "0ee1c47aaa256ecabcaea351eae4a9b01ef39ed810004e298d2511ed284b1525" [[package]] name = "miow" -version = "0.3.6" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a33c1b55807fbed163481b5ba66db4b2fa6cde694a5027be10fb724206c5897" +checksum = "b9f1c5b025cda876f66ef43a113f91ebc9f4ccef34843000e0adf6ebbab84e21" dependencies = [ - "socket2", "winapi", ] @@ -280,11 +287,11 @@ dependencies = [ "colored", "compiletest_rs", "env_logger", - "getrandom 0.2.0", + "getrandom 0.2.2", "hex", "libc", "log", - "rand", + "rand 0.7.3", "rustc-workspace-hack", "rustc_version", "shell-escape", @@ -299,9 +306,9 @@ checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857" [[package]] name = "proc-macro2" -version = "1.0.24" +version = "1.0.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71" +checksum = "a152013215dca273577e18d2bf00fa862b89b24169fb78c4c95aeb07992c9cec" dependencies = [ "unicode-xid", ] @@ -314,9 +321,9 @@ checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" [[package]] name = "quote" -version = "1.0.7" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa563d17ecb180e500da1cfd2b028310ac758de548efdd203e18f283af693f37" +checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7" dependencies = [ "proc-macro2", ] @@ -327,11 +334,23 @@ version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" dependencies = [ - "getrandom 0.1.15", + "getrandom 0.1.16", "libc", - "rand_chacha", - "rand_core", - "rand_hc", + "rand_chacha 0.2.2", + "rand_core 0.5.1", + "rand_hc 0.2.0", +] + +[[package]] +name = "rand" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ef9e7e66b4468674bfcb0c81af8b7fa0bb154fa9f28eb840da5c447baeb8d7e" +dependencies = [ + "libc", + "rand_chacha 0.3.0", + "rand_core 0.6.2", + "rand_hc 0.3.0", ] [[package]] @@ -341,7 +360,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" dependencies = [ "ppv-lite86", - "rand_core", + "rand_core 0.5.1", +] + +[[package]] +name = "rand_chacha" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e12735cf05c9e10bf21534da50a147b924d555dc7a547c42e6bb2d5b6017ae0d" +dependencies = [ + "ppv-lite86", + "rand_core 0.6.2", ] [[package]] @@ -350,7 +379,16 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" dependencies = [ - "getrandom 0.1.15", + "getrandom 0.1.16", +] + +[[package]] +name = "rand_core" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34cf66eb183df1c5876e2dcf6b13d57340741e8dc255b48e40a26de954d06ae7" +dependencies = [ + "getrandom 0.2.2", ] [[package]] @@ -359,7 +397,16 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" dependencies = [ - "rand_core", + "rand_core 0.5.1", +] + +[[package]] +name = "rand_hc" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3190ef7066a446f2e7f42e239d161e905420ccab01eb967c9eb27d21b2322a73" +dependencies = [ + "rand_core 0.6.2", ] [[package]] @@ -368,34 +415,42 @@ version = "0.1.57" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce" +[[package]] +name = "redox_syscall" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94341e4e44e24f6b591b59e47a8a027df12e008d73fd5672dbea9cc22f4507d9" +dependencies = [ + "bitflags", +] + [[package]] name = "redox_users" version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "de0737333e7a9502c789a36d7c7fa6092a49895d4faa31ca5df163857ded2e9d" dependencies = [ - "getrandom 0.1.15", - "redox_syscall", + "getrandom 0.1.16", + "redox_syscall 0.1.57", "rust-argon2", ] [[package]] name = "regex" -version = "1.4.2" +version = "1.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38cf2c13ed4745de91a5eb834e11c00bcc3709e773173b2ce4c56c9fbde04b9c" +checksum = "957056ecddbeba1b26965114e191d2e8589ce74db242b6ea25fc4062427a5c19" dependencies = [ "aho-corasick", "memchr", "regex-syntax", - "thread_local", ] [[package]] name = "regex-syntax" -version = "0.6.21" +version = "0.6.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b181ba2dcf07aaccad5448e8ead58db5b742cf85dfe035e2227f137a539a189" +checksum = "24d5f089152e60f62d28b835fbff2cd2e8dc0baf1ac13343bef92ab7eed84548" [[package]] name = "remove_dir_all" @@ -468,18 +523,18 @@ checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" [[package]] name = "serde" -version = "1.0.118" +version = "1.0.125" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06c64263859d87aa2eb554587e2d23183398d617427327cf2b3d0ed8c69e4800" +checksum = "558dc50e1a5a5fa7112ca2ce4effcb321b0300c0d4ccf0776a9f60cd89031171" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.118" +version = "1.0.125" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c84d3526699cd55261af4b941e4e725444df67aa4f9e6a3564f18030d12672df" +checksum = "b093b7a2bb58203b5da3056c05b4ec1fed827dcfdb37347a8841695263b3d06d" dependencies = [ "proc-macro2", "quote", @@ -488,9 +543,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.60" +version = "1.0.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1500e84d27fe482ed1dc791a56eddc2f230046a040fa908c08bda1d9fb615779" +checksum = "799e97dc9fdae36a5c8b8f2cae9ce2ee9fdce2058c57a93e6099d919fd982f79" dependencies = [ "itoa", "ryu", @@ -505,26 +560,15 @@ checksum = "45bb67a18fa91266cc7807181f62f9178a6873bfad7dc788c42e6430db40184f" [[package]] name = "smallvec" -version = "1.5.1" +version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae524f056d7d770e174287294f562e95044c68e88dec909a00d2094805db9d75" - -[[package]] -name = "socket2" -version = "0.3.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97e0e9fd577458a4f61fb91fcb559ea2afecc54c934119421f9f5d3d5b1a1057" -dependencies = [ - "cfg-if 1.0.0", - "libc", - "winapi", -] +checksum = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e" [[package]] name = "syn" -version = "1.0.54" +version = "1.0.68" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a2af957a63d6bd42255c359c93d9bfdb97076bd3b820897ce55ffbfbf107f44" +checksum = "3ce15dd3ed8aa2f8eeac4716d6ef5ab58b6b9256db41d7e1a0224c2788e8fd87" dependencies = [ "proc-macro2", "quote", @@ -533,14 +577,14 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.1.0" +version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9" +checksum = "dac1c663cfc93810f88aed9b8941d48cabf856a1b111c29a40439018d870eb22" dependencies = [ - "cfg-if 0.1.10", + "cfg-if 1.0.0", "libc", - "rand", - "redox_syscall", + "rand 0.8.3", + "redox_syscall 0.2.5", "remove_dir_all", "winapi", ] @@ -575,15 +619,6 @@ dependencies = [ "term", ] -[[package]] -name = "thread_local" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d40c6d1b69745a6ec6fb1ca717914848da4b44ae29d9b3080cbee91d72a69b14" -dependencies = [ - "lazy_static", -] - [[package]] name = "unicode-width" version = "0.1.8" @@ -602,6 +637,12 @@ version = "0.9.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" +[[package]] +name = "wasi" +version = "0.10.2+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" + [[package]] name = "winapi" version = "0.3.9" diff --git a/cargo-miri/Cargo.lock b/cargo-miri/Cargo.lock index b6abfb1031e6d..36daae33d35bd 100644 --- a/cargo-miri/Cargo.lock +++ b/cargo-miri/Cargo.lock @@ -1,5 +1,7 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. +version = 3 + [[package]] name = "arrayref" version = "0.3.6" @@ -47,18 +49,12 @@ version = "0.1.0" dependencies = [ "directories", "rustc-workspace-hack", - "rustc_version", + "rustc_version 0.2.3", "serde", "serde_json", "vergen", ] -[[package]] -name = "cfg-if" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" - [[package]] name = "cfg-if" version = "1.0.0" @@ -86,12 +82,12 @@ checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" [[package]] name = "crossbeam-utils" -version = "0.8.1" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02d96d1e189ef58269ebe5b97953da3274d83a93af647c2ddd6f9dab28cedb8d" +checksum = "e7e9d99fa91428effe99c5c6d4634cdeba32b8cf784fc428a2a687f61a952c49" dependencies = [ "autocfg", - "cfg-if 1.0.0", + "cfg-if", "lazy_static", ] @@ -117,20 +113,20 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.1.15" +version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc587bc0ec293155d5bfa6b9891ec18a1e330c234f896ea47fbada4cadbe47e6" +checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" dependencies = [ - "cfg-if 0.1.10", + "cfg-if", "libc", "wasi 0.9.0+wasi-snapshot-preview1", ] [[package]] name = "itoa" -version = "0.4.6" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc6f3ad7b9d11a0c00842ff8de1b60ee58661048eb8049ed33c73594f359d7e6" +checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736" [[package]] name = "lazy_static" @@ -140,9 +136,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.81" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1482821306169ec4d07f6aca392a4681f66c75c9918aa49641a2595db64053cb" +checksum = "56d855069fafbb9b344c0f962150cd2c1187975cb1c22c1522c240d8c4986714" [[package]] name = "num-integer" @@ -163,20 +159,29 @@ dependencies = [ "autocfg", ] +[[package]] +name = "pest" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10f4872ae94d7b90ae48754df22fd42ad52ce740b8f370b03da4835417403e53" +dependencies = [ + "ucd-trie", +] + [[package]] name = "proc-macro2" -version = "1.0.24" +version = "1.0.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71" +checksum = "a152013215dca273577e18d2bf00fa862b89b24169fb78c4c95aeb07992c9cec" dependencies = [ "unicode-xid", ] [[package]] name = "quote" -version = "1.0.8" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "991431c3519a3f36861882da93630ce66b52918dcf1b8e2fd66b397fc96f28df" +checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7" dependencies = [ "proc-macro2", ] @@ -222,7 +227,16 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" dependencies = [ - "semver", + "semver 0.9.0", +] + +[[package]] +name = "rustc_version" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0dfe2087c51c460008730de8b57e6a320782fbfb312e1f4d520e6c6fae155ee" +dependencies = [ + "semver 0.11.0", ] [[package]] @@ -237,7 +251,16 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" dependencies = [ - "semver-parser", + "semver-parser 0.7.0", +] + +[[package]] +name = "semver" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f301af10236f6df4160f7c3f04eec6dbc70ace82d23326abad5edee88801c6b6" +dependencies = [ + "semver-parser 0.10.2", ] [[package]] @@ -246,20 +269,29 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" +[[package]] +name = "semver-parser" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0bef5b7f9e0df16536d3961cfb6e84331c065b4066afb39768d0e319411f7" +dependencies = [ + "pest", +] + [[package]] name = "serde" -version = "1.0.118" +version = "1.0.125" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06c64263859d87aa2eb554587e2d23183398d617427327cf2b3d0ed8c69e4800" +checksum = "558dc50e1a5a5fa7112ca2ce4effcb321b0300c0d4ccf0776a9f60cd89031171" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.118" +version = "1.0.125" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c84d3526699cd55261af4b941e4e725444df67aa4f9e6a3564f18030d12672df" +checksum = "b093b7a2bb58203b5da3056c05b4ec1fed827dcfdb37347a8841695263b3d06d" dependencies = [ "proc-macro2", "quote", @@ -268,9 +300,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.60" +version = "1.0.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1500e84d27fe482ed1dc791a56eddc2f230046a040fa908c08bda1d9fb615779" +checksum = "799e97dc9fdae36a5c8b8f2cae9ce2ee9fdce2058c57a93e6099d919fd982f79" dependencies = [ "itoa", "ryu", @@ -279,9 +311,9 @@ dependencies = [ [[package]] name = "syn" -version = "1.0.55" +version = "1.0.68" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a571a711dddd09019ccc628e1b17fe87c59b09d513c06c026877aa708334f37a" +checksum = "3ce15dd3ed8aa2f8eeac4716d6ef5ab58b6b9256db41d7e1a0224c2788e8fd87" dependencies = [ "proc-macro2", "quote", @@ -299,6 +331,12 @@ dependencies = [ "winapi", ] +[[package]] +name = "ucd-trie" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c" + [[package]] name = "unicode-xid" version = "0.2.1" @@ -307,12 +345,13 @@ checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" [[package]] name = "vergen" -version = "3.1.0" +version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ce50d8996df1f85af15f2cd8d33daae6e479575123ef4314a51a70a230739cb" +checksum = "e7141e445af09c8919f1d5f8a20dae0b20c3b57a45dee0d5823c6ed5d237f15a" dependencies = [ "bitflags", "chrono", + "rustc_version 0.3.3", ] [[package]] diff --git a/test-cargo-miri/Cargo.lock b/test-cargo-miri/Cargo.lock index 3473d86c486b0..e7d5949644986 100644 --- a/test-cargo-miri/Cargo.lock +++ b/test-cargo-miri/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "byteorder" -version = "1.3.4" +version = "1.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de" +checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" [[package]] name = "cargo-miri-test" @@ -29,12 +29,6 @@ dependencies = [ "byteorder", ] -[[package]] -name = "cfg-if" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" - [[package]] name = "cfg-if" version = "1.0.0" @@ -43,11 +37,11 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "getrandom" -version = "0.1.15" +version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc587bc0ec293155d5bfa6b9891ec18a1e330c234f896ea47fbada4cadbe47e6" +checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" dependencies = [ - "cfg-if 0.1.10", + "cfg-if", "libc", "wasi 0.9.0+wasi-snapshot-preview1", ] @@ -58,16 +52,16 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c9495705279e7140bf035dde1f6e750c162df8b625267cd52cc44e0b156732c8" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "libc", "wasi 0.10.2+wasi-snapshot-preview1", ] [[package]] name = "hermit-abi" -version = "0.1.17" +version = "0.1.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5aca5565f760fb5b220e499d72710ed156fdb74e631659e99377d9ebfbd13ae8" +checksum = "322f4de77956e22ed0e5032c359a0f1273f1f7f0d79bfa3b8ffbc730d7fbcc5c" dependencies = [ "libc", ] @@ -92,9 +86,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.81" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1482821306169ec4d07f6aca392a4681f66c75c9918aa49641a2595db64053cb" +checksum = "56d855069fafbb9b344c0f962150cd2c1187975cb1c22c1522c240d8c4986714" [[package]] name = "num_cpus" @@ -114,18 +108,18 @@ checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857" [[package]] name = "proc-macro2" -version = "1.0.24" +version = "1.0.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71" +checksum = "a152013215dca273577e18d2bf00fa862b89b24169fb78c4c95aeb07992c9cec" dependencies = [ "unicode-xid", ] [[package]] name = "quote" -version = "1.0.8" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "991431c3519a3f36861882da93630ce66b52918dcf1b8e2fd66b397fc96f28df" +checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7" dependencies = [ "proc-macro2", ] @@ -136,7 +130,7 @@ version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" dependencies = [ - "getrandom 0.1.15", + "getrandom 0.1.16", "libc", "rand_chacha", "rand_core", @@ -160,7 +154,7 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" dependencies = [ - "getrandom 0.1.15", + "getrandom 0.1.16", ] [[package]] @@ -183,9 +177,9 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.118" +version = "1.0.125" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c84d3526699cd55261af4b941e4e725444df67aa4f9e6a3564f18030d12672df" +checksum = "b093b7a2bb58203b5da3056c05b4ec1fed827dcfdb37347a8841695263b3d06d" dependencies = [ "proc-macro2", "quote", @@ -201,9 +195,9 @@ dependencies = [ [[package]] name = "syn" -version = "1.0.55" +version = "1.0.68" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a571a711dddd09019ccc628e1b17fe87c59b09d513c06c026877aa708334f37a" +checksum = "3ce15dd3ed8aa2f8eeac4716d6ef5ab58b6b9256db41d7e1a0224c2788e8fd87" dependencies = [ "proc-macro2", "quote", From 20e31dbdad67080eb83aa3b5330dfe2f116f9900 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 4 Apr 2021 11:41:04 +0200 Subject: [PATCH 2601/3747] fix newer getrandom on Windows --- src/shims/windows/foreign_items.rs | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/src/shims/windows/foreign_items.rs b/src/shims/windows/foreign_items.rs index 72b776380b99a..47f9544066bc4 100644 --- a/src/shims/windows/foreign_items.rs +++ b/src/shims/windows/foreign_items.rs @@ -282,14 +282,30 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Miscellaneous "SystemFunction036" => { + // This is really 'RtlGenRandom'. check_abi(abi, Abi::System { unwind: false })?; - // The actual name of 'RtlGenRandom' let &[ref ptr, ref len] = check_arg_count(args)?; let ptr = this.read_scalar(ptr)?.check_init()?; let len = this.read_scalar(len)?.to_u32()?; this.gen_random(ptr, len.into())?; this.write_scalar(Scalar::from_bool(true), dest)?; } + "BCryptGenRandom" => { + check_abi(abi, Abi::System { unwind: false })?; + let &[ref algorithm, ref ptr, ref len, ref flags] = check_arg_count(args)?; + let algorithm = this.read_scalar(algorithm)?; + let ptr = this.read_scalar(ptr)?.check_init()?; + let len = this.read_scalar(len)?.to_u32()?; + let flags = this.read_scalar(flags)?.to_u32()?; + if flags != 2 { // BCRYPT_USE_SYSTEM_PREFERRED_RNG + throw_unsup_format!("BCryptGenRandom is supported only with the BCRYPT_USE_SYSTEM_PREFERRED_RNG flag"); + } + if algorithm.to_machine_usize(this)? != 0 { + throw_unsup_format!("BCryptGenRandom algorithm must be NULL when the flag is BCRYPT_USE_SYSTEM_PREFERRED_RNG"); + } + this.gen_random(ptr, len.into())?; + this.write_null(dest)?; // STATUS_SUCCESS + } "GetConsoleScreenBufferInfo" => { check_abi(abi, Abi::System { unwind: false })?; // `term` needs this, so we fake it. From 31bd77c7d82dda48f7c77ecc2314bc15219969c9 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 4 Apr 2021 11:45:09 +0200 Subject: [PATCH 2602/3747] bump miri dependencies --- Cargo.lock | 272 +++++++++++++------------------------------ Cargo.toml | 8 +- src/intptrcast.rs | 2 +- tests/compiletest.rs | 2 +- 4 files changed, 89 insertions(+), 195 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index fdac5d4542e76..69cc1966a6f86 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17,18 +17,6 @@ version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "28b2cd92db5cbd74e8e5028f7e27dd7aa3090e89e4f2a197cc7c8dfb69c7063b" -[[package]] -name = "arrayref" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544" - -[[package]] -name = "arrayvec" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" - [[package]] name = "atty" version = "0.2.14" @@ -40,41 +28,12 @@ dependencies = [ "winapi", ] -[[package]] -name = "autocfg" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" - -[[package]] -name = "base64" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" - [[package]] name = "bitflags" version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" -[[package]] -name = "blake2b_simd" -version = "0.5.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afa748e348ad3be8263be728124b24a24f268266f6f5d58af9d75f6a40b5c587" -dependencies = [ - "arrayref", - "arrayvec", - "constant_time_eq", -] - -[[package]] -name = "cfg-if" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" - [[package]] name = "cfg-if" version = "1.0.0" @@ -94,13 +53,14 @@ dependencies = [ [[package]] name = "compiletest_rs" -version = "0.5.0" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f737835bfbbe29ed1ff82d5137520338d7ed5bf1a1d4b9c1c7c58bb45b8fa29" +checksum = "0086d6ad78cf409c3061618cd98e2789d5c9ce598fc9651611cf62eae0a599cb" dependencies = [ "diff", "filetime", "getopts", + "lazy_static", "libc", "log", "miow", @@ -114,23 +74,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "constant_time_eq" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" - -[[package]] -name = "crossbeam-utils" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7e9d99fa91428effe99c5c6d4634cdeba32b8cf784fc428a2a687f61a952c49" -dependencies = [ - "autocfg", - "cfg-if 1.0.0", - "lazy_static", -] - [[package]] name = "diff" version = "0.1.12" @@ -138,20 +81,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0e25ea47919b1560c4e3b7fe0aaab9becf5b84a10325ddf7db0f0ba5e1026499" [[package]] -name = "dirs" -version = "2.0.2" +name = "dirs-next" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13aea89a5c93364a98e9b37b2fa237effbb694d5cfe01c5b70941f7eb087d5e3" +checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1" dependencies = [ - "cfg-if 0.1.10", - "dirs-sys", + "cfg-if", + "dirs-sys-next", ] [[package]] -name = "dirs-sys" -version = "0.3.5" +name = "dirs-sys-next" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e93d7f5705de3e49895a2b5e0b8855a1c27f080192ae9c32a6432d50741a57a" +checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" dependencies = [ "libc", "redox_users", @@ -160,9 +103,9 @@ dependencies = [ [[package]] name = "env_logger" -version = "0.7.1" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44533bbbb3bb3c1fa17d9f2e4e38bbbaf8396ba82193c4cb1b6445d711445d36" +checksum = "17392a012ea30ef05a610aa97dfb49496e71c9f676b27879922ea5bdf60d9d3f" dependencies = [ "atty", "humantime", @@ -177,9 +120,9 @@ version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1d34cfa13a63ae058bfa601fe9e313bbdb3746427c1459185464ce0fcf62e1e8" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "libc", - "redox_syscall 0.2.5", + "redox_syscall", "winapi", ] @@ -192,26 +135,15 @@ dependencies = [ "unicode-width", ] -[[package]] -name = "getrandom" -version = "0.1.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" -dependencies = [ - "cfg-if 1.0.0", - "libc", - "wasi 0.9.0+wasi-snapshot-preview1", -] - [[package]] name = "getrandom" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c9495705279e7140bf035dde1f6e750c162df8b625267cd52cc44e0b156732c8" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "libc", - "wasi 0.10.2+wasi-snapshot-preview1", + "wasi", ] [[package]] @@ -231,12 +163,9 @@ checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" [[package]] name = "humantime" -version = "1.3.0" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f" -dependencies = [ - "quick-error", -] +checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" [[package]] name = "itoa" @@ -262,7 +191,7 @@ version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", ] [[package]] @@ -287,17 +216,36 @@ dependencies = [ "colored", "compiletest_rs", "env_logger", - "getrandom 0.2.2", + "getrandom", "hex", "libc", "log", - "rand 0.7.3", + "rand", "rustc-workspace-hack", "rustc_version", "shell-escape", "smallvec", ] +[[package]] +name = "num_cpus" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "pest" +version = "2.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10f4872ae94d7b90ae48754df22fd42ad52ce740b8f370b03da4835417403e53" +dependencies = [ + "ucd-trie", +] + [[package]] name = "ppv-lite86" version = "0.2.10" @@ -313,12 +261,6 @@ dependencies = [ "unicode-xid", ] -[[package]] -name = "quick-error" -version = "1.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" - [[package]] name = "quote" version = "1.0.9" @@ -328,19 +270,6 @@ dependencies = [ "proc-macro2", ] -[[package]] -name = "rand" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" -dependencies = [ - "getrandom 0.1.16", - "libc", - "rand_chacha 0.2.2", - "rand_core 0.5.1", - "rand_hc 0.2.0", -] - [[package]] name = "rand" version = "0.8.3" @@ -348,19 +277,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ef9e7e66b4468674bfcb0c81af8b7fa0bb154fa9f28eb840da5c447baeb8d7e" dependencies = [ "libc", - "rand_chacha 0.3.0", - "rand_core 0.6.2", - "rand_hc 0.3.0", -] - -[[package]] -name = "rand_chacha" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" -dependencies = [ - "ppv-lite86", - "rand_core 0.5.1", + "rand_chacha", + "rand_core", + "rand_hc", ] [[package]] @@ -370,16 +289,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e12735cf05c9e10bf21534da50a147b924d555dc7a547c42e6bb2d5b6017ae0d" dependencies = [ "ppv-lite86", - "rand_core 0.6.2", -] - -[[package]] -name = "rand_core" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" -dependencies = [ - "getrandom 0.1.16", + "rand_core", ] [[package]] @@ -388,16 +298,7 @@ version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34cf66eb183df1c5876e2dcf6b13d57340741e8dc255b48e40a26de954d06ae7" dependencies = [ - "getrandom 0.2.2", -] - -[[package]] -name = "rand_hc" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" -dependencies = [ - "rand_core 0.5.1", + "getrandom", ] [[package]] @@ -406,15 +307,9 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3190ef7066a446f2e7f42e239d161e905420ccab01eb967c9eb27d21b2322a73" dependencies = [ - "rand_core 0.6.2", + "rand_core", ] -[[package]] -name = "redox_syscall" -version = "0.1.57" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce" - [[package]] name = "redox_syscall" version = "0.2.5" @@ -426,13 +321,12 @@ dependencies = [ [[package]] name = "redox_users" -version = "0.3.5" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de0737333e7a9502c789a36d7c7fa6092a49895d4faa31ca5df163857ded2e9d" +checksum = "528532f3d801c87aec9def2add9ca802fe569e44a544afe633765267840abe64" dependencies = [ - "getrandom 0.1.16", - "redox_syscall 0.1.57", - "rust-argon2", + "getrandom", + "redox_syscall", ] [[package]] @@ -461,18 +355,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "rust-argon2" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b18820d944b33caa75a71378964ac46f58517c92b6ae5f762636247c09e78fb" -dependencies = [ - "base64", - "blake2b_simd", - "constant_time_eq", - "crossbeam-utils", -] - [[package]] name = "rustc-workspace-hack" version = "1.0.0" @@ -481,9 +363,9 @@ checksum = "fc71d2faa173b74b232dedc235e3ee1696581bb132fc116fa3626d6151a1a8fb" [[package]] name = "rustc_version" -version = "0.2.3" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" +checksum = "f0dfe2087c51c460008730de8b57e6a320782fbfb312e1f4d520e6c6fae155ee" dependencies = [ "semver", ] @@ -500,6 +382,12 @@ dependencies = [ "serde_json", ] +[[package]] +name = "rustversion" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb5d2a036dc6d2d8fd16fde3498b04306e29bd193bf306a57427019b823d5acd" + [[package]] name = "ryu" version = "1.0.5" @@ -508,18 +396,21 @@ checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" [[package]] name = "semver" -version = "0.9.0" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" +checksum = "f301af10236f6df4160f7c3f04eec6dbc70ace82d23326abad5edee88801c6b6" dependencies = [ "semver-parser", ] [[package]] name = "semver-parser" -version = "0.7.0" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" +checksum = "00b0bef5b7f9e0df16536d3961cfb6e84331c065b4066afb39768d0e319411f7" +dependencies = [ + "pest", +] [[package]] name = "serde" @@ -581,21 +472,22 @@ version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dac1c663cfc93810f88aed9b8941d48cabf856a1b111c29a40439018d870eb22" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "libc", - "rand 0.8.3", - "redox_syscall 0.2.5", + "rand", + "redox_syscall", "remove_dir_all", "winapi", ] [[package]] name = "term" -version = "0.6.1" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0863a3345e70f61d613eab32ee046ccd1bcc5f9105fe402c61fcd0c13eeb8b5" +checksum = "c59df8ac95d96ff9bede18eb7300b0fda5e5d8d90960e76f8e14ae765eedbf1f" dependencies = [ - "dirs", + "dirs-next", + "rustversion", "winapi", ] @@ -610,15 +502,23 @@ dependencies = [ [[package]] name = "tester" -version = "0.7.0" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee72ec31009a42b53de9a6b7d8f462b493ab3b1e4767bda1fcdbb52127f13b6c" +checksum = "0639d10d8f4615f223a57275cf40f9bdb7cfbb806bcb7f7cc56e3beb55a576eb" dependencies = [ + "cfg-if", "getopts", "libc", + "num_cpus", "term", ] +[[package]] +name = "ucd-trie" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c" + [[package]] name = "unicode-width" version = "0.1.8" @@ -631,12 +531,6 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" -[[package]] -name = "wasi" -version = "0.9.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" - [[package]] name = "wasi" version = "0.10.2+wasi-snapshot-preview1" diff --git a/Cargo.toml b/Cargo.toml index 5f9e93f2347ba..2483cb2c81293 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,11 +19,11 @@ doctest = false # and no doc tests [dependencies] getrandom = { version = "0.2", features = ["std"] } -env_logger = "0.7.1" +env_logger = "0.8" log = "0.4" shell-escape = "0.1.4" hex = "0.4.0" -rand = "0.7" +rand = "0.8" smallvec = "1.4.2" # A noop dependency that changes in the Rust repository, it's a bit of a hack. @@ -37,8 +37,8 @@ rustc-workspace-hack = "1.0.0" libc = "0.2" [dev-dependencies] -compiletest_rs = { version = "0.5", features = ["tmp"] } -rustc_version = "0.2.3" +compiletest_rs = { version = "0.6", features = ["tmp"] } +rustc_version = "0.3" colored = "2" [package.metadata.rust-analyzer] diff --git a/src/intptrcast.rs b/src/intptrcast.rs index 188ff94861bdd..0e6a9f69aebab 100644 --- a/src/intptrcast.rs +++ b/src/intptrcast.rs @@ -92,7 +92,7 @@ impl<'mir, 'tcx> GlobalState { let slack = { let mut rng = memory.extra.rng.borrow_mut(); // This means that `(global_state.next_base_addr + slack) % 16` is uniformly distributed. - rng.gen_range(0, 16) + rng.gen_range(0..16) }; // From next_base_addr + slack, round up to adjust for alignment. let base_addr = global_state.next_base_addr.checked_add(slack).unwrap(); diff --git a/tests/compiletest.rs b/tests/compiletest.rs index ac44c48d6214a..5de5dfb4c6756 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -42,7 +42,7 @@ fn run_tests(mode: &str, path: &str, target: &str) { config.run_lib_path = PathBuf::from(lib_path); config.compile_lib_path = PathBuf::from(lib_path); } - config.filter = env::args().nth(1); + config.filters = env::args().nth(1).into_iter().collect(); config.host = get_host(); config.src_base = PathBuf::from(path); config.target = target.to_owned(); From 8e661cc47e8ee50fdd60060f693ec9498fbc2a75 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 4 Apr 2021 12:01:32 +0200 Subject: [PATCH 2603/3747] bump cargo-miri dependencies --- cargo-miri/Cargo.lock | 288 +++++++++++++++++++++++++++++++++++++----- cargo-miri/Cargo.toml | 4 +- cargo-miri/bin.rs | 4 +- cargo-miri/build.rs | 8 +- 4 files changed, 268 insertions(+), 36 deletions(-) diff --git a/cargo-miri/Cargo.lock b/cargo-miri/Cargo.lock index 36daae33d35bd..cf536ecbb20f8 100644 --- a/cargo-miri/Cargo.lock +++ b/cargo-miri/Cargo.lock @@ -2,6 +2,12 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "anyhow" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28b2cd92db5cbd74e8e5028f7e27dd7aa3090e89e4f2a197cc7c8dfb69c7063b" + [[package]] name = "arrayref" version = "0.3.6" @@ -49,12 +55,21 @@ version = "0.1.0" dependencies = [ "directories", "rustc-workspace-hack", - "rustc_version 0.2.3", + "rustc_version", "serde", "serde_json", "vergen", ] +[[package]] +name = "cc" +version = "1.0.67" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3c69b077ad434294d3ce9f1f6143a2a4b89a8a2d54ef813d85003a4fd1137fd" +dependencies = [ + "jobserver", +] + [[package]] name = "cfg-if" version = "1.0.0" @@ -111,6 +126,36 @@ dependencies = [ "winapi", ] +[[package]] +name = "enum-iterator" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c79a6321a1197d7730510c7e3f6cb80432dfefecb32426de8cea0aa19b4bb8d7" +dependencies = [ + "enum-iterator-derive", +] + +[[package]] +name = "enum-iterator-derive" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e94aa31f7c0dc764f57896dc615ddd76fc13b0d5dca7eb6cc5e018a5a09ec06" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "form_urlencoded" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fc25a87fa4fd2094bffb06925852034d90a17f0d1e05197d4956d3555752191" +dependencies = [ + "matches", + "percent-encoding", +] + [[package]] name = "getrandom" version = "0.1.16" @@ -122,12 +167,57 @@ dependencies = [ "wasi 0.9.0+wasi-snapshot-preview1", ] +[[package]] +name = "getset" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24b328c01a4d71d2d8173daa93562a73ab0fe85616876f02500f53d82948c504" +dependencies = [ + "proc-macro-error", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "git2" +version = "0.13.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d250f5f82326884bd39c2853577e70a121775db76818ffa452ed1e80de12986" +dependencies = [ + "bitflags", + "libc", + "libgit2-sys", + "log", + "url", +] + +[[package]] +name = "idna" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89829a5d69c23d348314a7ac337fe39173b61149a9864deabd260983aed48c21" +dependencies = [ + "matches", + "unicode-bidi", + "unicode-normalization", +] + [[package]] name = "itoa" version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736" +[[package]] +name = "jobserver" +version = "0.1.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c71313ebb9439f74b00d9d2dcec36440beaf57a6aa0623068441dd7cd81a7f2" +dependencies = [ + "libc", +] + [[package]] name = "lazy_static" version = "1.4.0" @@ -140,6 +230,45 @@ version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "56d855069fafbb9b344c0f962150cd2c1187975cb1c22c1522c240d8c4986714" +[[package]] +name = "libgit2-sys" +version = "0.12.18+1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3da6a42da88fc37ee1ecda212ffa254c25713532980005d5f7c0b0fbe7e6e885" +dependencies = [ + "cc", + "libc", + "libz-sys", + "pkg-config", +] + +[[package]] +name = "libz-sys" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "602113192b08db8f38796c4e85c39e960c145965140e918018bcde1952429655" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "log" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "matches" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08" + [[package]] name = "num-integer" version = "0.1.44" @@ -159,6 +288,12 @@ dependencies = [ "autocfg", ] +[[package]] +name = "percent-encoding" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" + [[package]] name = "pest" version = "2.1.3" @@ -168,6 +303,36 @@ dependencies = [ "ucd-trie", ] +[[package]] +name = "pkg-config" +version = "0.3.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3831453b3449ceb48b6d9c7ad7c96d5ea673e9b470a1dc578c2ce6521230884c" + +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", +] + [[package]] name = "proc-macro2" version = "1.0.26" @@ -223,21 +388,18 @@ checksum = "fc71d2faa173b74b232dedc235e3ee1696581bb132fc116fa3626d6151a1a8fb" [[package]] name = "rustc_version" -version = "0.2.3" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" +checksum = "f0dfe2087c51c460008730de8b57e6a320782fbfb312e1f4d520e6c6fae155ee" dependencies = [ - "semver 0.9.0", + "semver", ] [[package]] -name = "rustc_version" -version = "0.3.3" +name = "rustversion" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0dfe2087c51c460008730de8b57e6a320782fbfb312e1f4d520e6c6fae155ee" -dependencies = [ - "semver 0.11.0", -] +checksum = "cb5d2a036dc6d2d8fd16fde3498b04306e29bd193bf306a57427019b823d5acd" [[package]] name = "ryu" @@ -245,30 +407,15 @@ version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" -[[package]] -name = "semver" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" -dependencies = [ - "semver-parser 0.7.0", -] - [[package]] name = "semver" version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f301af10236f6df4160f7c3f04eec6dbc70ace82d23326abad5edee88801c6b6" dependencies = [ - "semver-parser 0.10.2", + "semver-parser", ] -[[package]] -name = "semver-parser" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" - [[package]] name = "semver-parser" version = "0.10.2" @@ -320,6 +467,26 @@ dependencies = [ "unicode-xid", ] +[[package]] +name = "thiserror" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0f4a65597094d4483ddaed134f409b2cb7c1beccf25201a9f73c719254fa98e" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7765189610d8241a44529806d6fd1f2e0a08734313a35d5b3a556f92b381f3c0" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "time" version = "0.1.44" @@ -331,29 +498,90 @@ dependencies = [ "winapi", ] +[[package]] +name = "tinyvec" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "317cca572a0e89c3ce0ca1f1bdc9369547fe318a683418e42ac8f59d14701023" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" + [[package]] name = "ucd-trie" version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c" +[[package]] +name = "unicode-bidi" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5" +dependencies = [ + "matches", +] + +[[package]] +name = "unicode-normalization" +version = "0.1.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07fbfce1c8a97d547e8b5334978438d9d6ec8c20e38f56d4a4374d181493eaef" +dependencies = [ + "tinyvec", +] + [[package]] name = "unicode-xid" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" +[[package]] +name = "url" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ccd964113622c8e9322cfac19eb1004a07e636c545f325da085d5cdde6f1f8b" +dependencies = [ + "form_urlencoded", + "idna", + "matches", + "percent-encoding", +] + +[[package]] +name = "vcpkg" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b00bca6106a5e23f3eee943593759b7fcddb00554332e856d990c893966879fb" + [[package]] name = "vergen" -version = "3.2.0" +version = "5.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7141e445af09c8919f1d5f8a20dae0b20c3b57a45dee0d5823c6ed5d237f15a" +checksum = "dfbc87f9a7a9d61b15d51d1d3547284f67b6b4f1494ce3fc5814c101f35a5183" dependencies = [ - "bitflags", + "anyhow", "chrono", - "rustc_version 0.3.3", + "enum-iterator", + "getset", + "git2", + "rustversion", + "thiserror", ] +[[package]] +name = "version_check" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe" + [[package]] name = "wasi" version = "0.9.0+wasi-snapshot-preview1" diff --git a/cargo-miri/Cargo.toml b/cargo-miri/Cargo.toml index 8233c5c24f83a..f0ef30eabcf7d 100644 --- a/cargo-miri/Cargo.toml +++ b/cargo-miri/Cargo.toml @@ -15,7 +15,7 @@ doctest = false # and no doc tests [dependencies] directories = "3" -rustc_version = "0.2.3" +rustc_version = "0.3" serde_json = "1.0.40" # A noop dependency that changes in the Rust repository, it's a bit of a hack. @@ -28,4 +28,4 @@ rustc-workspace-hack = "1.0.0" serde = { version = "*", features = ["derive"] } [build-dependencies] -vergen = "3" +vergen = { version = "5", default_features = false, features = ["git"] } diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index 2cd0c0c972f55..af1dbad32a9ab 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -83,8 +83,8 @@ fn show_version() { println!( "miri {} ({} {})", env!("CARGO_PKG_VERSION"), - env!("VERGEN_SHA_SHORT"), - env!("VERGEN_COMMIT_DATE") + env!("VERGEN_GIT_SHA_SHORT"), + env!("VERGEN_GIT_COMMIT_DATE") ); } diff --git a/cargo-miri/build.rs b/cargo-miri/build.rs index 56956920e2e26..cff135fe49c04 100644 --- a/cargo-miri/build.rs +++ b/cargo-miri/build.rs @@ -1,7 +1,11 @@ +use vergen::vergen; + fn main() { // Don't rebuild miri when nothing changed. println!("cargo:rerun-if-changed=build.rs"); // vergen - vergen::generate_cargo_keys(vergen::ConstantsFlags::all()) - .expect("Unable to generate vergen keys!"); + let mut gen_config = vergen::Config::default(); + *gen_config.git_mut().sha_kind_mut() = vergen::ShaKind::Short; + *gen_config.git_mut().commit_timestamp_kind_mut() = vergen::TimestampKind::DateOnly; + vergen(gen_config).expect("Unable to generate vergen keys!"); } From 3d15e4744151b339afc38b1bc5c01caf8da2b943 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 4 Apr 2021 12:03:52 +0200 Subject: [PATCH 2604/3747] bump test-cargo-miri dependencies --- test-cargo-miri/Cargo.lock | 50 +++++++++----------------------------- test-cargo-miri/Cargo.toml | 2 +- 2 files changed, 12 insertions(+), 40 deletions(-) diff --git a/test-cargo-miri/Cargo.lock b/test-cargo-miri/Cargo.lock index e7d5949644986..c9e3126c4292b 100644 --- a/test-cargo-miri/Cargo.lock +++ b/test-cargo-miri/Cargo.lock @@ -14,7 +14,7 @@ version = "0.1.0" dependencies = [ "byteorder", "cdylib", - "getrandom 0.2.2", + "getrandom", "issue_1567", "issue_1691", "issue_1705", @@ -35,17 +35,6 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" -[[package]] -name = "getrandom" -version = "0.1.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" -dependencies = [ - "cfg-if", - "libc", - "wasi 0.9.0+wasi-snapshot-preview1", -] - [[package]] name = "getrandom" version = "0.2.2" @@ -54,7 +43,7 @@ checksum = "c9495705279e7140bf035dde1f6e750c162df8b625267cd52cc44e0b156732c8" dependencies = [ "cfg-if", "libc", - "wasi 0.10.2+wasi-snapshot-preview1", + "wasi", ] [[package]] @@ -126,23 +115,21 @@ dependencies = [ [[package]] name = "rand" -version = "0.7.3" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" +checksum = "0ef9e7e66b4468674bfcb0c81af8b7fa0bb154fa9f28eb840da5c447baeb8d7e" dependencies = [ - "getrandom 0.1.16", "libc", "rand_chacha", "rand_core", "rand_hc", - "rand_pcg", ] [[package]] name = "rand_chacha" -version = "0.2.2" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" +checksum = "e12735cf05c9e10bf21534da50a147b924d555dc7a547c42e6bb2d5b6017ae0d" dependencies = [ "ppv-lite86", "rand_core", @@ -150,27 +137,18 @@ dependencies = [ [[package]] name = "rand_core" -version = "0.5.1" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" +checksum = "34cf66eb183df1c5876e2dcf6b13d57340741e8dc255b48e40a26de954d06ae7" dependencies = [ - "getrandom 0.1.16", + "getrandom", ] [[package]] name = "rand_hc" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" -dependencies = [ - "rand_core", -] - -[[package]] -name = "rand_pcg" -version = "0.2.1" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16abd0c1b639e9eb4d7c50c0b8100b0d0f849be2349829c740fe8e6eb4816429" +checksum = "3190ef7066a446f2e7f42e239d161e905420ccab01eb967c9eb27d21b2322a73" dependencies = [ "rand_core", ] @@ -210,12 +188,6 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" -[[package]] -name = "wasi" -version = "0.9.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" - [[package]] name = "wasi" version = "0.10.2+wasi-snapshot-preview1" diff --git a/test-cargo-miri/Cargo.toml b/test-cargo-miri/Cargo.toml index c9619b6b4baa7..76d88bc0c7504 100644 --- a/test-cargo-miri/Cargo.toml +++ b/test-cargo-miri/Cargo.toml @@ -15,7 +15,7 @@ issue_1691 = { path = "issue-1691" } issue_1705 = { path = "issue-1705" } [dev-dependencies] -rand = { version = "0.7", features = ["small_rng"] } +rand = { version = "0.8", features = ["small_rng"] } getrandom = { version = "0.2" } serde_derive = "1.0" # not actually used, but exercises some unique code path (`--extern` .so file) From 84f44900f45e5572e1d3209f204a3a856f48b07c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 4 Apr 2021 15:35:19 +0200 Subject: [PATCH 2605/3747] also test old getrandom --- test-cargo-miri/Cargo.lock | 24 +++++++++++++++++++++--- test-cargo-miri/Cargo.toml | 3 ++- test-cargo-miri/tests/test.rs | 5 +++-- 3 files changed, 26 insertions(+), 6 deletions(-) diff --git a/test-cargo-miri/Cargo.lock b/test-cargo-miri/Cargo.lock index c9e3126c4292b..45ec195843dc8 100644 --- a/test-cargo-miri/Cargo.lock +++ b/test-cargo-miri/Cargo.lock @@ -14,7 +14,8 @@ version = "0.1.0" dependencies = [ "byteorder", "cdylib", - "getrandom", + "getrandom 0.1.16", + "getrandom 0.2.2", "issue_1567", "issue_1691", "issue_1705", @@ -35,6 +36,17 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "getrandom" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" +dependencies = [ + "cfg-if", + "libc", + "wasi 0.9.0+wasi-snapshot-preview1", +] + [[package]] name = "getrandom" version = "0.2.2" @@ -43,7 +55,7 @@ checksum = "c9495705279e7140bf035dde1f6e750c162df8b625267cd52cc44e0b156732c8" dependencies = [ "cfg-if", "libc", - "wasi", + "wasi 0.10.2+wasi-snapshot-preview1", ] [[package]] @@ -141,7 +153,7 @@ version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34cf66eb183df1c5876e2dcf6b13d57340741e8dc255b48e40a26de954d06ae7" dependencies = [ - "getrandom", + "getrandom 0.2.2", ] [[package]] @@ -188,6 +200,12 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" +[[package]] +name = "wasi" +version = "0.9.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" + [[package]] name = "wasi" version = "0.10.2+wasi-snapshot-preview1" diff --git a/test-cargo-miri/Cargo.toml b/test-cargo-miri/Cargo.toml index 76d88bc0c7504..08470539727ab 100644 --- a/test-cargo-miri/Cargo.toml +++ b/test-cargo-miri/Cargo.toml @@ -16,7 +16,8 @@ issue_1705 = { path = "issue-1705" } [dev-dependencies] rand = { version = "0.8", features = ["small_rng"] } -getrandom = { version = "0.2" } +getrandom_1 = { package = "getrandom", version = "0.1" } +getrandom_2 = { package = "getrandom", version = "0.2" } serde_derive = "1.0" # not actually used, but exercises some unique code path (`--extern` .so file) [lib] diff --git a/test-cargo-miri/tests/test.rs b/test-cargo-miri/tests/test.rs index 33b814eeeeeba..f0ff10ff6c0d8 100644 --- a/test-cargo-miri/tests/test.rs +++ b/test-cargo-miri/tests/test.rs @@ -24,9 +24,10 @@ fn does_not_work_on_miri() { #[test] fn entropy_rng() { - // Test `getrandom` directly. + // Test `getrandom` directly (in multiple different versions). let mut data = vec![0; 16]; - getrandom::getrandom(&mut data).unwrap(); + getrandom_1::getrandom(&mut data).unwrap(); + getrandom_2::getrandom(&mut data).unwrap(); // Try seeding with "real" entropy. let mut rng = SmallRng::from_entropy(); From 4fccde54acc986a7446ae487cb028fec59fadcb4 Mon Sep 17 00:00:00 2001 From: Tristan Dannenberg Date: Tue, 12 Jan 2021 22:16:48 +0100 Subject: [PATCH 2606/3747] make cargo-miri run doc-tests --- README.md | 4 + cargo-miri/bin.rs | 211 ++++++++++++++++-- test-cargo-miri/run-test.py | 19 +- test-cargo-miri/test.cross-target.stdout.ref | 10 + test-cargo-miri/test.default.stdout.ref | 6 + .../test.filter.cross-target.stdout.ref | 11 + test-cargo-miri/test.filter.stdout.ref | 5 + test-cargo-miri/test.stderr-rustdoc.ref | 1 - 8 files changed, 239 insertions(+), 28 deletions(-) create mode 100644 test-cargo-miri/test.cross-target.stdout.ref create mode 100644 test-cargo-miri/test.filter.cross-target.stdout.ref delete mode 100644 test-cargo-miri/test.stderr-rustdoc.ref diff --git a/README.md b/README.md index 8a0c5180e002d..8a80a57e2d9fc 100644 --- a/README.md +++ b/README.md @@ -290,6 +290,10 @@ different Miri binaries, and as such worth documenting: that the compiled `rlib`s are compatible with Miri. When set while running `cargo-miri`, it indicates that we are part of a sysroot build (for which some crates need special treatment). +* `MIRI_CALLED_FROM_RUSTDOC` when set to any value tells `cargo-miri` that it is + running as a child process of `rustdoc`, which invokes it twice for each doc-test + and requires special treatment, most notably a check-only build before interpretation. + This is set by `cargo-miri` itself when running as a `rustdoc`-wrapper. * `MIRI_CWD` when set to any value tells the Miri driver to change to the given directory after loading all the source files, but before commencing interpretation. This is useful if the interpreted program wants a different diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index af1dbad32a9ab..1f749b077ab9f 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -1,8 +1,8 @@ use std::env; use std::ffi::OsString; use std::fs::{self, File}; -use std::io::{self, BufRead, BufReader, BufWriter, Write}; use std::iter::TakeWhile; +use std::io::{self, BufRead, BufReader, BufWriter, Read, Write}; use std::ops::Not; use std::path::{Path, PathBuf}; use std::process::Command; @@ -46,6 +46,8 @@ struct CrateRunEnv { env: Vec<(OsString, OsString)>, /// The current working directory. current_dir: OsString, + /// The contents passed via standard input. + stdin: Vec, } /// The information Miri needs to run a crate. Stored as JSON when the crate is "compiled". @@ -63,7 +65,13 @@ impl CrateRunInfo { let args = args.collect(); let env = env::vars_os().collect(); let current_dir = env::current_dir().unwrap().into_os_string(); - Self::RunWith(CrateRunEnv { args, env, current_dir }) + + let mut stdin = Vec::new(); + if env::var_os("MIRI_CALLED_FROM_RUSTDOC").is_some() { + std::io::stdin().lock().read_to_end(&mut stdin).expect("cannot read stdin"); + } + + Self::RunWith(CrateRunEnv { args, env, current_dir, stdin }) } fn store(&self, filename: &Path) { @@ -190,6 +198,22 @@ fn exec(mut cmd: Command) { } } +/// Execute the command and pipe `input` into its stdin. +/// If it fails, fail this process with the same exit code. +/// Otherwise, continue. +fn exec_with_pipe(mut cmd: Command, input: &[u8]) { + cmd.stdin(std::process::Stdio::piped()); + let mut child = cmd.spawn().expect("failed to spawn process"); + { + let stdin = child.stdin.as_mut().expect("failed to open stdin"); + stdin.write_all(input).expect("failed to write out test source"); + } + let exit_status = child.wait().expect("failed to run command"); + if exit_status.success().not() { + std::process::exit(exit_status.code().unwrap_or(-1)) + } +} + fn xargo_version() -> Option<(u32, u32, u32)> { let out = xargo_check().arg("--version").output().ok()?; if !out.status.success() { @@ -591,24 +615,29 @@ fn phase_cargo_rustc(mut args: env::Args) { } fn out_filename(prefix: &str, suffix: &str) -> PathBuf { - let mut path = PathBuf::from(get_arg_flag_value("--out-dir").unwrap()); - path.push(format!( - "{}{}{}{}", - prefix, - get_arg_flag_value("--crate-name").unwrap(), - // This is technically a `-C` flag but the prefix seems unique enough... - // (and cargo passes this before the filename so it should be unique) - get_arg_flag_value("extra-filename").unwrap_or(String::new()), - suffix, - )); - path + if let Some(out_dir) = get_arg_flag_value("--out-dir") { + let mut path = PathBuf::from(out_dir); + path.push(format!( + "{}{}{}{}", + prefix, + get_arg_flag_value("--crate-name").unwrap(), + // This is technically a `-C` flag but the prefix seems unique enough... + // (and cargo passes this before the filename so it should be unique) + get_arg_flag_value("extra-filename").unwrap_or(String::new()), + suffix, + )); + path + } else { + let out_file = get_arg_flag_value("-o").unwrap(); + PathBuf::from(out_file) + } } let verbose = std::env::var_os("MIRI_VERBOSE").is_some(); let target_crate = is_target_crate(); let print = get_arg_flag_value("--print").is_some(); // whether this is cargo passing `--print` to get some infos - let store_json = |info: CrateRunInfo| { + let store_json = |info: &CrateRunInfo| { // Create a stub .d file to stop Cargo from "rebuilding" the crate: // https://github.com/rust-lang/miri/issues/1724#issuecomment-787115693 // As we store a JSON file instead of building the crate here, an empty file is fine. @@ -636,7 +665,47 @@ fn phase_cargo_rustc(mut args: env::Args) { // like we want them. // Instead of compiling, we write JSON into the output file with all the relevant command-line flags // and environment variables; this is used when cargo calls us again in the CARGO_TARGET_RUNNER phase. - store_json(CrateRunInfo::collect(args)); + let info = CrateRunInfo::collect(args); + store_json(&info); + + // Rustdoc expects us to exit with an error code if the test is marked as `compile_fail`, + // just creating the JSON file is not enough: we need to detect syntax errors, + // so we need to run Miri with `MIRI_BE_RUSTC` for a check-only build. + if std::env::var_os("MIRI_CALLED_FROM_RUSTDOC").is_some() { + let mut cmd = miri(); + let env = if let CrateRunInfo::RunWith(env) = info { + env + } else { + return; + }; + + // use our own sysroot + if !has_arg_flag("--sysroot") { + let sysroot = env::var_os("MIRI_SYSROOT") + .expect("the wrapper should have set MIRI_SYSROOT"); + cmd.arg("--sysroot").arg(sysroot); + } + + // ensure --emit argument for a check-only build is present + if let Some(i) = env.args.iter().position(|arg| arg.starts_with("--emit=")) { + // We need to make sure we're not producing a binary that overwrites the JSON file. + // rustdoc should only ever pass an --emit=metadata argument for tests marked as `no_run`: + assert_eq!(env.args[i], "--emit=metadata"); + } else { + cmd.arg("--emit=dep-info,metadata"); + } + + cmd.args(env.args); + cmd.env("MIRI_BE_RUSTC", "1"); + + if verbose { + eprintln!("[cargo-miri rustc] captured input:\n{}", std::str::from_utf8(&env.stdin).unwrap()); + eprintln!("[cargo-miri rustc] {:?}", cmd); + } + + exec_with_pipe(cmd, &env.stdin); + } + return; } @@ -644,7 +713,7 @@ fn phase_cargo_rustc(mut args: env::Args) { // This is a "runnable" `proc-macro` crate (unit tests). We do not support // interpreting that under Miri now, so we write a JSON file to (display a // helpful message and) skip it in the runner phase. - store_json(CrateRunInfo::SkipProcMacroTest); + store_json(&CrateRunInfo::SkipProcMacroTest); return; } @@ -715,6 +784,18 @@ fn phase_cargo_rustc(mut args: env::Args) { } } +fn forward_patched_extern_arg(args: &mut impl Iterator, cmd: &mut Command) { + cmd.arg("--extern"); // always forward flag, but adjust filename: + let path = args.next().expect("`--extern` should be followed by a filename"); + if let Some(lib) = path.strip_suffix(".rlib") { + // If this is an rlib, make it an rmeta. + cmd.arg(format!("{}.rmeta", lib)); + } else { + // Some other extern file (e.g. a `.so`). Forward unchanged. + cmd.arg(path); + } +} + fn phase_cargo_runner(binary: &Path, binary_args: env::Args) { let verbose = std::env::var_os("MIRI_VERBOSE").is_some(); @@ -801,6 +882,73 @@ fn phase_cargo_runner(binary: &Path, binary_args: env::Args) { if verbose { eprintln!("[cargo-miri runner] {:?}", cmd); } + + if std::env::var_os("MIRI_CALLED_FROM_RUSTDOC").is_some() { + exec_with_pipe(cmd, &info.stdin) + } else { + exec(cmd) + } +} + +fn phase_cargo_rustdoc(fst_arg: &str, mut args: env::Args) { + let verbose = std::env::var_os("MIRI_VERBOSE").is_some(); + + // phase_cargo_miri sets the RUSTDOC env var to ourselves, so we can't use that here; + // just default to a straight-forward invocation for now: + let mut cmd = Command::new(OsString::from("rustdoc")); + + // Because of the way the main function is structured, we have to take the first argument spearately + // from the rest; to simplify the following argument patching loop, we'll just skip that one. + // This is fine for now, because cargo will never pass --extern arguments in the first position, + // but we should defensively assert that this will work. + let extern_flag = "--extern"; + assert!(fst_arg != extern_flag); + cmd.arg(fst_arg); + + let runtool_flag = "--runtool"; + let mut crossmode = fst_arg == runtool_flag; + while let Some(arg) = args.next() { + if arg == extern_flag { + // Patch --extern arguments to use *.rmeta files, since phase_cargo_rustc only creates stub *.rlib files. + forward_patched_extern_arg(&mut args, &mut cmd); + } else if arg == runtool_flag { + // An existing --runtool flag indicates cargo is running in cross-target mode, which we don't support. + // Note that this is only passed when cargo is run with the unstable -Zdoctest-xcompile flag; + // otherwise, we won't be called as rustdoc at all. + crossmode = true; + break; + } else { + cmd.arg(arg); + } + } + + if crossmode { + eprintln!("Cross-interpreting doc-tests is not currently supported by Miri."); + return; + } + + // For each doc-test, rustdoc starts two child processes: first the test is compiled, + // then the produced executable is invoked. We want to reroute both of these to cargo-miri, + // such that the first time we'll enter phase_cargo_rustc, and phase_cargo_runner second. + // + // rustdoc invokes the test-builder by forwarding most of its own arguments, which makes + // it difficult to determine when phase_cargo_rustc should run instead of phase_cargo_rustdoc. + // Furthermore, the test code is passed via stdin, rather than a temporary file, so we need + // to let phase_cargo_rustc know to expect that. We'll use this environment variable as a flag: + cmd.env("MIRI_CALLED_FROM_RUSTDOC", "1"); + + // The `--test-builder` and `--runtool` arguments are unstable rustdoc features, + // which are disabled by default. We first need to enable them explicitly: + cmd.arg("-Z").arg("unstable-options"); + + let cargo_miri_path = std::env::current_exe().expect("current executable path invalid"); + cmd.arg("--test-builder").arg(&cargo_miri_path); // invoked by forwarding most arguments + cmd.arg("--runtool").arg(&cargo_miri_path); // invoked with just a single path argument + + if verbose { + eprintln!("[cargo-miri rustdoc] {:?}", cmd); + } + exec(cmd) } @@ -817,6 +965,30 @@ fn main() { return; } + // The way rustdoc invokes rustc is indistuingishable from the way cargo invokes rustdoc + // by the arguments alone, and we can't take from the args iterator in this case. + // phase_cargo_rustdoc sets this environment variable to let us disambiguate here + let invoked_by_rustdoc = env::var_os("MIRI_CALLED_FROM_RUSTDOC").is_some(); + if invoked_by_rustdoc { + // ...however, we then also see this variable when rustdoc invokes us as the testrunner! + // The runner is invoked as `$runtool ($runtool-arg)* output_file`; + // since we don't specify any runtool-args, and rustdoc supplies multiple arguments to + // the test-builder unconditionally, we can just check the number of remaining arguments: + if args.len() == 1 { + let arg = args.next().unwrap(); + let binary = Path::new(&arg); + if binary.exists() { + phase_cargo_runner(binary, args); + } else { + show_error(format!("`cargo-miri` called with non-existing path argument `{}` in rustdoc mode; please invoke this binary through `cargo miri`", arg)); + } + } else { + phase_cargo_rustc(args); + } + + return; + } + // Dispatch to `cargo-miri` phase. There are three phases: // - When we are called via `cargo miri`, we run as the frontend and invoke the underlying // cargo. We set RUSTC_WRAPPER and CARGO_TARGET_RUNNER to ourselves. @@ -829,16 +1001,15 @@ fn main() { Some("miri") => phase_cargo_miri(args), Some("rustc") => phase_cargo_rustc(args), Some(arg) => { - // We have to distinguish the "runner" and "rustfmt" cases. + // We have to distinguish the "runner" and "rustdoc" cases. // As runner, the first argument is the binary (a file that should exist, with an absolute path); - // as rustfmt, the first argument is a flag (`--something`). + // as rustdoc, the first argument is a flag (`--something`). let binary = Path::new(arg); if binary.exists() { assert!(!arg.starts_with("--")); // not a flag phase_cargo_runner(binary, args); } else if arg.starts_with("--") { - // We are rustdoc. - eprintln!("Running doctests is not currently supported by Miri.") + phase_cargo_rustdoc(arg, args); } else { show_error(format!("`cargo-miri` called with unexpected first argument `{}`; please only invoke this binary through `cargo miri`", arg)); } diff --git a/test-cargo-miri/run-test.py b/test-cargo-miri/run-test.py index 81f589705dc33..c8b85316bb645 100755 --- a/test-cargo-miri/run-test.py +++ b/test-cargo-miri/run-test.py @@ -5,7 +5,7 @@ and the working directory to contain the cargo-miri-test project. ''' -import sys, subprocess, os +import sys, subprocess, os, re CGREEN = '\33[32m' CBOLD = '\33[1m' @@ -23,6 +23,10 @@ def cargo_miri(cmd, quiet = True): args += ["--target", os.environ['MIRI_TEST_TARGET']] return args +def normalize_stdout(str): + str = str.replace("src\\", "src/") # normalize paths across platforms + return re.sub("finished in \d+\.\d\ds", "finished in $TIME", str) + def test(name, cmd, stdout_ref, stderr_ref, stdin=b'', env={}): print("Testing {}...".format(name)) ## Call `cargo miri`, capture all output @@ -38,7 +42,7 @@ def test(name, cmd, stdout_ref, stderr_ref, stdin=b'', env={}): (stdout, stderr) = p.communicate(input=stdin) stdout = stdout.decode("UTF-8") stderr = stderr.decode("UTF-8") - if p.returncode == 0 and stdout == open(stdout_ref).read() and stderr == open(stderr_ref).read(): + if p.returncode == 0 and normalize_stdout(stdout) == open(stdout_ref).read() and stderr == open(stderr_ref).read(): # All good! return # Show output @@ -101,26 +105,27 @@ def test_cargo_miri_run(): def test_cargo_miri_test(): # rustdoc is not run on foreign targets is_foreign = 'MIRI_TEST_TARGET' in os.environ - rustdoc_ref = "test.stderr-empty.ref" if is_foreign else "test.stderr-rustdoc.ref" + default_ref = "test.cross-target.stdout.ref" if is_foreign else "test.default.stdout.ref" + filter_ref = "test.filter.cross-target.stdout.ref" if is_foreign else "test.filter.stdout.ref" test("`cargo miri test`", cargo_miri("test"), - "test.default.stdout.ref", rustdoc_ref, + default_ref, "test.stderr-empty.ref", env={'MIRIFLAGS': "-Zmiri-seed=feed"}, ) test("`cargo miri test` (no isolation)", cargo_miri("test"), - "test.default.stdout.ref", rustdoc_ref, + default_ref, "test.stderr-empty.ref", env={'MIRIFLAGS': "-Zmiri-disable-isolation"}, ) test("`cargo miri test` (raw-ptr tracking)", cargo_miri("test"), - "test.default.stdout.ref", rustdoc_ref, + default_ref, "test.stderr-empty.ref", env={'MIRIFLAGS': "-Zmiri-track-raw-pointers"}, ) test("`cargo miri test` (with filter)", cargo_miri("test") + ["--", "--format=pretty", "le1"], - "test.filter.stdout.ref", rustdoc_ref, + filter_ref, "test.stderr-empty.ref", ) test("`cargo miri test` (test target)", cargo_miri("test") + ["--test", "test", "--", "--format=pretty"], diff --git a/test-cargo-miri/test.cross-target.stdout.ref b/test-cargo-miri/test.cross-target.stdout.ref new file mode 100644 index 0000000000000..7079798e42feb --- /dev/null +++ b/test-cargo-miri/test.cross-target.stdout.ref @@ -0,0 +1,10 @@ + +running 1 test +. +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out + + +running 7 tests +..i.... +test result: ok. 6 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out + diff --git a/test-cargo-miri/test.default.stdout.ref b/test-cargo-miri/test.default.stdout.ref index 7079798e42feb..7ed0b2dbaead8 100644 --- a/test-cargo-miri/test.default.stdout.ref +++ b/test-cargo-miri/test.default.stdout.ref @@ -8,3 +8,9 @@ running 7 tests ..i.... test result: ok. 6 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out + +running 1 test +test src/lib.rs - make_true (line 2) ... ok + +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME + diff --git a/test-cargo-miri/test.filter.cross-target.stdout.ref b/test-cargo-miri/test.filter.cross-target.stdout.ref new file mode 100644 index 0000000000000..37efb8c3ee896 --- /dev/null +++ b/test-cargo-miri/test.filter.cross-target.stdout.ref @@ -0,0 +1,11 @@ + +running 0 tests + +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 1 filtered out + + +running 1 test +test simple1 ... ok + +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 6 filtered out + diff --git a/test-cargo-miri/test.filter.stdout.ref b/test-cargo-miri/test.filter.stdout.ref index 37efb8c3ee896..18174cadd20d3 100644 --- a/test-cargo-miri/test.filter.stdout.ref +++ b/test-cargo-miri/test.filter.stdout.ref @@ -9,3 +9,8 @@ test simple1 ... ok test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 6 filtered out + +running 0 tests + +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 1 filtered out; finished in $TIME + diff --git a/test-cargo-miri/test.stderr-rustdoc.ref b/test-cargo-miri/test.stderr-rustdoc.ref deleted file mode 100644 index a310169e305ee..0000000000000 --- a/test-cargo-miri/test.stderr-rustdoc.ref +++ /dev/null @@ -1 +0,0 @@ -Running doctests is not currently supported by Miri. From dd393f21c7f6a6b997d241e82a8dc89ee42cd6e8 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 5 Apr 2021 11:46:20 +0200 Subject: [PATCH 2607/3747] make attempt to cross-interpret a hard error --- cargo-miri/bin.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index 1f749b077ab9f..f4f18929ba88a 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -923,8 +923,7 @@ fn phase_cargo_rustdoc(fst_arg: &str, mut args: env::Args) { } if crossmode { - eprintln!("Cross-interpreting doc-tests is not currently supported by Miri."); - return; + show_error(format!("cross-interpreting doc-tests is not currently supported by Miri.")); } // For each doc-test, rustdoc starts two child processes: first the test is compiled, From 9083e00b2c27145551a24dbd06d2ca40986b0592 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 5 Apr 2021 11:55:53 +0200 Subject: [PATCH 2608/3747] resolve semantic conflicts --- cargo-miri/bin.rs | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index f4f18929ba88a..bb6d4b8789cd3 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -572,7 +572,7 @@ fn phase_cargo_miri(mut args: env::Args) { // us in order to skip them. cmd.env(&host_runner_env_name, &cargo_miri_path); - // Set rustdoc to us as well, so we can make it do nothing (see issue #584). + // Set rustdoc to us as well, so we can run doctests. cmd.env("RUSTDOC", &cargo_miri_path); // Run cargo. @@ -784,18 +784,6 @@ fn phase_cargo_rustc(mut args: env::Args) { } } -fn forward_patched_extern_arg(args: &mut impl Iterator, cmd: &mut Command) { - cmd.arg("--extern"); // always forward flag, but adjust filename: - let path = args.next().expect("`--extern` should be followed by a filename"); - if let Some(lib) = path.strip_suffix(".rlib") { - // If this is an rlib, make it an rmeta. - cmd.arg(format!("{}.rmeta", lib)); - } else { - // Some other extern file (e.g. a `.so`). Forward unchanged. - cmd.arg(path); - } -} - fn phase_cargo_runner(binary: &Path, binary_args: env::Args) { let verbose = std::env::var_os("MIRI_VERBOSE").is_some(); From 65597951b7e51473dc27cdbc5699f8d165197d01 Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Sun, 14 Feb 2021 18:57:03 +0800 Subject: [PATCH 2609/3747] Fix sysroot for rustdoc --- cargo-miri/bin.rs | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index bb6d4b8789cd3..350efbf1826da 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -685,7 +685,7 @@ fn phase_cargo_rustc(mut args: env::Args) { .expect("the wrapper should have set MIRI_SYSROOT"); cmd.arg("--sysroot").arg(sysroot); } - + // ensure --emit argument for a check-only build is present if let Some(i) = env.args.iter().position(|arg| arg.starts_with("--emit=")) { // We need to make sure we're not producing a binary that overwrites the JSON file. @@ -702,7 +702,7 @@ fn phase_cargo_rustc(mut args: env::Args) { eprintln!("[cargo-miri rustc] captured input:\n{}", std::str::from_utf8(&env.stdin).unwrap()); eprintln!("[cargo-miri rustc] {:?}", cmd); } - + exec_with_pipe(cmd, &env.stdin); } @@ -841,11 +841,13 @@ fn phase_cargo_runner(binary: &Path, binary_args: env::Args) { cmd.arg(arg); } } - // Set sysroot. - let sysroot = - env::var_os("MIRI_SYSROOT").expect("the wrapper should have set MIRI_SYSROOT"); - cmd.arg("--sysroot"); - cmd.arg(sysroot); + if env::var_os("MIRI_CALLED_FROM_RUSTDOC").is_none() { + // Set sysroot. + let sysroot = + env::var_os("MIRI_SYSROOT").expect("the wrapper should have set MIRI_SYSROOT"); + cmd.arg("--sysroot"); + cmd.arg(sysroot); + } // Respect `MIRIFLAGS`. if let Ok(a) = env::var("MIRIFLAGS") { // This code is taken from `RUSTFLAGS` handling in cargo. @@ -892,7 +894,7 @@ fn phase_cargo_rustdoc(fst_arg: &str, mut args: env::Args) { let extern_flag = "--extern"; assert!(fst_arg != extern_flag); cmd.arg(fst_arg); - + let runtool_flag = "--runtool"; let mut crossmode = fst_arg == runtool_flag; while let Some(arg) = args.next() { @@ -917,21 +919,27 @@ fn phase_cargo_rustdoc(fst_arg: &str, mut args: env::Args) { // For each doc-test, rustdoc starts two child processes: first the test is compiled, // then the produced executable is invoked. We want to reroute both of these to cargo-miri, // such that the first time we'll enter phase_cargo_rustc, and phase_cargo_runner second. - // + // // rustdoc invokes the test-builder by forwarding most of its own arguments, which makes // it difficult to determine when phase_cargo_rustc should run instead of phase_cargo_rustdoc. // Furthermore, the test code is passed via stdin, rather than a temporary file, so we need // to let phase_cargo_rustc know to expect that. We'll use this environment variable as a flag: cmd.env("MIRI_CALLED_FROM_RUSTDOC", "1"); - + // The `--test-builder` and `--runtool` arguments are unstable rustdoc features, // which are disabled by default. We first need to enable them explicitly: cmd.arg("-Z").arg("unstable-options"); - + + // Use our custom sysroot. + let sysroot = + env::var_os("MIRI_SYSROOT").expect("the wrapper should have set MIRI_SYSROOT"); + cmd.arg("--sysroot"); + cmd.arg(sysroot); + let cargo_miri_path = std::env::current_exe().expect("current executable path invalid"); cmd.arg("--test-builder").arg(&cargo_miri_path); // invoked by forwarding most arguments cmd.arg("--runtool").arg(&cargo_miri_path); // invoked with just a single path argument - + if verbose { eprintln!("[cargo-miri rustdoc] {:?}", cmd); } From 29bc8a57b09f3259ae83b844c6c29e01f1ba00c6 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 5 Apr 2021 12:16:31 +0200 Subject: [PATCH 2610/3747] add test for compile_fail; de-duplicate sysroot forwarding --- cargo-miri/bin.rs | 34 ++++++++++--------------- test-cargo-miri/src/lib.rs | 3 +++ test-cargo-miri/test.default.stdout.ref | 5 ++-- 3 files changed, 19 insertions(+), 23 deletions(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index 350efbf1826da..1127cef593cc7 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -163,6 +163,13 @@ fn forward_patched_extern_arg(args: &mut impl Iterator, cmd: &mut } } +fn forward_miri_sysroot(cmd: &mut Command) { + let sysroot = + env::var_os("MIRI_SYSROOT").expect("the wrapper should have set MIRI_SYSROOT"); + cmd.arg("--sysroot"); + cmd.arg(sysroot); +} + /// Returns the path to the `miri` binary fn find_miri() -> PathBuf { if let Some(path) = env::var_os("MIRI") { @@ -679,13 +686,6 @@ fn phase_cargo_rustc(mut args: env::Args) { return; }; - // use our own sysroot - if !has_arg_flag("--sysroot") { - let sysroot = env::var_os("MIRI_SYSROOT") - .expect("the wrapper should have set MIRI_SYSROOT"); - cmd.arg("--sysroot").arg(sysroot); - } - // ensure --emit argument for a check-only build is present if let Some(i) = env.args.iter().position(|arg| arg.starts_with("--emit=")) { // We need to make sure we're not producing a binary that overwrites the JSON file. @@ -750,10 +750,7 @@ fn phase_cargo_rustc(mut args: env::Args) { } // Use our custom sysroot. - let sysroot = - env::var_os("MIRI_SYSROOT").expect("the wrapper should have set MIRI_SYSROOT"); - cmd.arg("--sysroot"); - cmd.arg(sysroot); + forward_miri_sysroot(&mut cmd); } else { // For host crates or when we are printing, just forward everything. cmd.args(args); @@ -842,11 +839,8 @@ fn phase_cargo_runner(binary: &Path, binary_args: env::Args) { } } if env::var_os("MIRI_CALLED_FROM_RUSTDOC").is_none() { - // Set sysroot. - let sysroot = - env::var_os("MIRI_SYSROOT").expect("the wrapper should have set MIRI_SYSROOT"); - cmd.arg("--sysroot"); - cmd.arg(sysroot); + // Set sysroot (if we are inside rustdoc, we already did that in `phase_cargo_rustdoc`). + forward_miri_sysroot(&mut cmd); } // Respect `MIRIFLAGS`. if let Ok(a) = env::var("MIRIFLAGS") { @@ -930,12 +924,10 @@ fn phase_cargo_rustdoc(fst_arg: &str, mut args: env::Args) { // which are disabled by default. We first need to enable them explicitly: cmd.arg("-Z").arg("unstable-options"); - // Use our custom sysroot. - let sysroot = - env::var_os("MIRI_SYSROOT").expect("the wrapper should have set MIRI_SYSROOT"); - cmd.arg("--sysroot"); - cmd.arg(sysroot); + // rustdoc needs to know the right sysroot. + forward_miri_sysroot(&mut cmd); + // Make rustdoc call us back. let cargo_miri_path = std::env::current_exe().expect("current executable path invalid"); cmd.arg("--test-builder").arg(&cargo_miri_path); // invoked by forwarding most arguments cmd.arg("--runtool").arg(&cargo_miri_path); // invoked with just a single path argument diff --git a/test-cargo-miri/src/lib.rs b/test-cargo-miri/src/lib.rs index 33bbd8c966e58..45973522f72f2 100644 --- a/test-cargo-miri/src/lib.rs +++ b/test-cargo-miri/src/lib.rs @@ -2,6 +2,9 @@ /// ```rust /// assert!(cargo_miri_test::make_true()); /// ``` +/// ```rust,compile_fail +/// assert!(cargo_miri_test::make_true() == 5); +/// ``` pub fn make_true() -> bool { issue_1567::use_the_dependency(); issue_1705::use_the_dependency(); diff --git a/test-cargo-miri/test.default.stdout.ref b/test-cargo-miri/test.default.stdout.ref index 7ed0b2dbaead8..893350ae6e628 100644 --- a/test-cargo-miri/test.default.stdout.ref +++ b/test-cargo-miri/test.default.stdout.ref @@ -9,8 +9,9 @@ running 7 tests test result: ok. 6 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out -running 1 test +running 2 tests +test src/lib.rs - make_true (line 5) ... ok test src/lib.rs - make_true (line 2) ... ok -test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME +test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME From e66a89c8afe8da0c784943502343c8620c156366 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 5 Apr 2021 12:26:27 +0200 Subject: [PATCH 2611/3747] avoid some dead code and test no_run tests --- cargo-miri/bin.rs | 50 ++++++++++++------------- test-cargo-miri/src/lib.rs | 3 ++ test-cargo-miri/test.default.stdout.ref | 5 ++- test-cargo-miri/test.filter.stdout.ref | 2 +- 4 files changed, 31 insertions(+), 29 deletions(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index 1127cef593cc7..5d2759deea3db 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -38,7 +38,7 @@ enum MiriCommand { } /// The information to run a crate with the given environment. -#[derive(Serialize, Deserialize)] +#[derive(Serialize, Deserialize, Clone)] struct CrateRunEnv { /// The command-line arguments. args: Vec, @@ -50,16 +50,7 @@ struct CrateRunEnv { stdin: Vec, } -/// The information Miri needs to run a crate. Stored as JSON when the crate is "compiled". -#[derive(Serialize, Deserialize)] -enum CrateRunInfo { - /// Run it with the given environment. - RunWith(CrateRunEnv), - /// Skip it as Miri does not support interpreting such kind of crates. - SkipProcMacroTest, -} - -impl CrateRunInfo { +impl CrateRunEnv { /// Gather all the information we need. fn collect(args: env::Args) -> Self { let args = args.collect(); @@ -71,9 +62,20 @@ impl CrateRunInfo { std::io::stdin().lock().read_to_end(&mut stdin).expect("cannot read stdin"); } - Self::RunWith(CrateRunEnv { args, env, current_dir, stdin }) + CrateRunEnv { args, env, current_dir, stdin } } +} +/// The information Miri needs to run a crate. Stored as JSON when the crate is "compiled". +#[derive(Serialize, Deserialize)] +enum CrateRunInfo { + /// Run it with the given environment. + RunWith(CrateRunEnv), + /// Skip it as Miri does not support interpreting such kind of crates. + SkipProcMacroTest, +} + +impl CrateRunInfo { fn store(&self, filename: &Path) { let file = File::create(filename) .unwrap_or_else(|_| show_error(format!("cannot create `{}`", filename.display()))); @@ -644,7 +646,7 @@ fn phase_cargo_rustc(mut args: env::Args) { let target_crate = is_target_crate(); let print = get_arg_flag_value("--print").is_some(); // whether this is cargo passing `--print` to get some infos - let store_json = |info: &CrateRunInfo| { + let store_json = |info: CrateRunInfo| { // Create a stub .d file to stop Cargo from "rebuilding" the crate: // https://github.com/rust-lang/miri/issues/1724#issuecomment-787115693 // As we store a JSON file instead of building the crate here, an empty file is fine. @@ -672,30 +674,24 @@ fn phase_cargo_rustc(mut args: env::Args) { // like we want them. // Instead of compiling, we write JSON into the output file with all the relevant command-line flags // and environment variables; this is used when cargo calls us again in the CARGO_TARGET_RUNNER phase. - let info = CrateRunInfo::collect(args); - store_json(&info); + let env = CrateRunEnv::collect(args); // Rustdoc expects us to exit with an error code if the test is marked as `compile_fail`, // just creating the JSON file is not enough: we need to detect syntax errors, // so we need to run Miri with `MIRI_BE_RUSTC` for a check-only build. if std::env::var_os("MIRI_CALLED_FROM_RUSTDOC").is_some() { let mut cmd = miri(); - let env = if let CrateRunInfo::RunWith(env) = info { - env - } else { - return; - }; - // ensure --emit argument for a check-only build is present + // Ensure --emit argument for a check-only build is present. if let Some(i) = env.args.iter().position(|arg| arg.starts_with("--emit=")) { - // We need to make sure we're not producing a binary that overwrites the JSON file. - // rustdoc should only ever pass an --emit=metadata argument for tests marked as `no_run`: + // For `no_run` tests, rustdoc passes a `--emit` flag; make sure it has the right shape. assert_eq!(env.args[i], "--emit=metadata"); } else { - cmd.arg("--emit=dep-info,metadata"); + // For all other kinds of tests, we can just add our flag. + cmd.arg("--emit=metadata"); } - cmd.args(env.args); + cmd.args(&env.args); cmd.env("MIRI_BE_RUSTC", "1"); if verbose { @@ -706,6 +702,8 @@ fn phase_cargo_rustc(mut args: env::Args) { exec_with_pipe(cmd, &env.stdin); } + store_json(CrateRunInfo::RunWith(env)); + return; } @@ -713,7 +711,7 @@ fn phase_cargo_rustc(mut args: env::Args) { // This is a "runnable" `proc-macro` crate (unit tests). We do not support // interpreting that under Miri now, so we write a JSON file to (display a // helpful message and) skip it in the runner phase. - store_json(&CrateRunInfo::SkipProcMacroTest); + store_json(CrateRunInfo::SkipProcMacroTest); return; } diff --git a/test-cargo-miri/src/lib.rs b/test-cargo-miri/src/lib.rs index 45973522f72f2..0c268a18f63c4 100644 --- a/test-cargo-miri/src/lib.rs +++ b/test-cargo-miri/src/lib.rs @@ -2,6 +2,9 @@ /// ```rust /// assert!(cargo_miri_test::make_true()); /// ``` +/// ```rust,no_run +/// assert!(cargo_miri_test::make_true()); +/// ``` /// ```rust,compile_fail /// assert!(cargo_miri_test::make_true() == 5); /// ``` diff --git a/test-cargo-miri/test.default.stdout.ref b/test-cargo-miri/test.default.stdout.ref index 893350ae6e628..72ae7e94a1462 100644 --- a/test-cargo-miri/test.default.stdout.ref +++ b/test-cargo-miri/test.default.stdout.ref @@ -9,9 +9,10 @@ running 7 tests test result: ok. 6 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out -running 2 tests +running 3 tests test src/lib.rs - make_true (line 5) ... ok +test src/lib.rs - make_true (line 8) ... ok test src/lib.rs - make_true (line 2) ... ok -test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME +test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME diff --git a/test-cargo-miri/test.filter.stdout.ref b/test-cargo-miri/test.filter.stdout.ref index 18174cadd20d3..11e47e8ff8165 100644 --- a/test-cargo-miri/test.filter.stdout.ref +++ b/test-cargo-miri/test.filter.stdout.ref @@ -12,5 +12,5 @@ test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 6 filtered out running 0 tests -test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 1 filtered out; finished in $TIME +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 3 filtered out; finished in $TIME From f9bd6b0756c12e9f33223bd0a8460cd1129160a6 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 5 Apr 2021 12:46:36 +0200 Subject: [PATCH 2612/3747] nits; test running no doctests --- cargo-miri/bin.rs | 9 +++++---- test-cargo-miri/run-test.py | 6 +++--- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index 5d2759deea3db..b9c46ff41cb5c 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -683,6 +683,7 @@ fn phase_cargo_rustc(mut args: env::Args) { let mut cmd = miri(); // Ensure --emit argument for a check-only build is present. + // We cannot use the usual helpers since we need to check specifically in `env.args`. if let Some(i) = env.args.iter().position(|arg| arg.starts_with("--emit=")) { // For `no_run` tests, rustdoc passes a `--emit` flag; make sure it has the right shape. assert_eq!(env.args[i], "--emit=metadata"); @@ -877,7 +878,7 @@ fn phase_cargo_rustdoc(fst_arg: &str, mut args: env::Args) { // phase_cargo_miri sets the RUSTDOC env var to ourselves, so we can't use that here; // just default to a straight-forward invocation for now: - let mut cmd = Command::new(OsString::from("rustdoc")); + let mut cmd = Command::new("rustdoc"); // Because of the way the main function is structured, we have to take the first argument spearately // from the rest; to simplify the following argument patching loop, we'll just skip that one. @@ -888,6 +889,7 @@ fn phase_cargo_rustdoc(fst_arg: &str, mut args: env::Args) { cmd.arg(fst_arg); let runtool_flag = "--runtool"; + // `crossmode` records if *any* argument matches `runtool_flag`; here we check the first one. let mut crossmode = fst_arg == runtool_flag; while let Some(arg) = args.next() { if arg == extern_flag { @@ -950,9 +952,8 @@ fn main() { return; } - // The way rustdoc invokes rustc is indistuingishable from the way cargo invokes rustdoc - // by the arguments alone, and we can't take from the args iterator in this case. - // phase_cargo_rustdoc sets this environment variable to let us disambiguate here + // The way rustdoc invokes rustc is indistuingishable from the way cargo invokes rustdoc by the + // arguments alone. `phase_cargo_rustdoc` sets this environment variable to let us disambiguate. let invoked_by_rustdoc = env::var_os("MIRI_CALLED_FROM_RUSTDOC").is_some(); if invoked_by_rustdoc { // ...however, we then also see this variable when rustdoc invokes us as the testrunner! diff --git a/test-cargo-miri/run-test.py b/test-cargo-miri/run-test.py index c8b85316bb645..84c4a129ad3e5 100755 --- a/test-cargo-miri/run-test.py +++ b/test-cargo-miri/run-test.py @@ -113,9 +113,9 @@ def test_cargo_miri_test(): default_ref, "test.stderr-empty.ref", env={'MIRIFLAGS': "-Zmiri-seed=feed"}, ) - test("`cargo miri test` (no isolation)", - cargo_miri("test"), - default_ref, "test.stderr-empty.ref", + test("`cargo miri test` (no isolation, no doctests)", + cargo_miri("test") + ["--bins", "--tests"], # no `--lib`, we disabled that in `Cargo.toml` + "test.cross-target.stdout.ref", "test.stderr-empty.ref", env={'MIRIFLAGS': "-Zmiri-disable-isolation"}, ) test("`cargo miri test` (raw-ptr tracking)", From 2f6dff6da81e4bf351f82c648b79fbfddd175b3e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 5 Apr 2021 13:18:59 +0200 Subject: [PATCH 2613/3747] nits and fix non-deterministic test output --- cargo-miri/bin.rs | 11 ++++++----- test-cargo-miri/run-test.py | 1 + test-cargo-miri/test.default.stdout.ref | 2 +- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index b9c46ff41cb5c..b70d95c604028 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -38,7 +38,7 @@ enum MiriCommand { } /// The information to run a crate with the given environment. -#[derive(Serialize, Deserialize, Clone)] +#[derive(Serialize, Deserialize)] struct CrateRunEnv { /// The command-line arguments. args: Vec, @@ -52,13 +52,13 @@ struct CrateRunEnv { impl CrateRunEnv { /// Gather all the information we need. - fn collect(args: env::Args) -> Self { + fn collect(args: env::Args, capture_stdin: bool) -> Self { let args = args.collect(); let env = env::vars_os().collect(); let current_dir = env::current_dir().unwrap().into_os_string(); let mut stdin = Vec::new(); - if env::var_os("MIRI_CALLED_FROM_RUSTDOC").is_some() { + if capture_stdin { std::io::stdin().lock().read_to_end(&mut stdin).expect("cannot read stdin"); } @@ -669,17 +669,18 @@ fn phase_cargo_rustc(mut args: env::Args) { let runnable_crate = !print && is_runnable_crate(); if runnable_crate && target_crate { + let inside_rustdoc = env::var_os("MIRI_CALLED_FROM_RUSTDOC").is_some(); // This is the binary or test crate that we want to interpret under Miri. // But we cannot run it here, as cargo invoked us as a compiler -- our stdin and stdout are not // like we want them. // Instead of compiling, we write JSON into the output file with all the relevant command-line flags // and environment variables; this is used when cargo calls us again in the CARGO_TARGET_RUNNER phase. - let env = CrateRunEnv::collect(args); + let env = CrateRunEnv::collect(args, inside_rustdoc); // Rustdoc expects us to exit with an error code if the test is marked as `compile_fail`, // just creating the JSON file is not enough: we need to detect syntax errors, // so we need to run Miri with `MIRI_BE_RUSTC` for a check-only build. - if std::env::var_os("MIRI_CALLED_FROM_RUSTDOC").is_some() { + if inside_rustdoc { let mut cmd = miri(); // Ensure --emit argument for a check-only build is present. diff --git a/test-cargo-miri/run-test.py b/test-cargo-miri/run-test.py index 84c4a129ad3e5..9185c2507b6fc 100755 --- a/test-cargo-miri/run-test.py +++ b/test-cargo-miri/run-test.py @@ -143,6 +143,7 @@ def test_cargo_miri_test(): os.chdir(os.path.dirname(os.path.realpath(__file__))) os.environ["RUST_TEST_NOCAPTURE"] = "0" # this affects test output, so make sure it is not set +os.environ["RUST_TEST_THREADS"] = "1" # avoid non-deterministic output due to concurrent test runs target_str = " for target {}".format(os.environ['MIRI_TEST_TARGET']) if 'MIRI_TEST_TARGET' in os.environ else "" print(CGREEN + CBOLD + "## Running `cargo miri` tests{}".format(target_str) + CEND) diff --git a/test-cargo-miri/test.default.stdout.ref b/test-cargo-miri/test.default.stdout.ref index 72ae7e94a1462..6e35c374e1920 100644 --- a/test-cargo-miri/test.default.stdout.ref +++ b/test-cargo-miri/test.default.stdout.ref @@ -10,9 +10,9 @@ test result: ok. 6 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out running 3 tests +test src/lib.rs - make_true (line 2) ... ok test src/lib.rs - make_true (line 5) ... ok test src/lib.rs - make_true (line 8) ... ok -test src/lib.rs - make_true (line 2) ... ok test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME From a760aab828c9279fbdc5615fd23e0c499fb1f549 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 7 Apr 2021 10:07:03 +0200 Subject: [PATCH 2614/3747] mention 'cargo miri test filter' in README --- README.md | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 8a80a57e2d9fc..fd6110aafa781 100644 --- a/README.md +++ b/README.md @@ -83,21 +83,24 @@ determine a nightly version that comes with Miri and install that using Now you can run your project in Miri: -1. Run `cargo clean` to eliminate any cached dependencies. Miri needs your +1. Run `cargo clean` to eliminate any cached dependencies. Miri needs your dependencies to be compiled the right way, that would not happen if they have previously already been compiled. 2. To run all tests in your project through Miri, use `cargo miri test`. 3. If you have a binary project, you can run it through Miri using `cargo miri run`. The first time you run Miri, it will perform some extra setup and install some -dependencies. It will ask you for confirmation before installing anything. +dependencies. It will ask you for confirmation before installing anything. -`cargo miri run/test` supports the exact same flags as `cargo run/test`. You -can pass arguments to Miri via `MIRIFLAGS`. For example, +`cargo miri run/test` supports the exact same flags as `cargo run/test`. For +example, `cargo miri test filter` only runs the tests containing `filter` in +their name. + +You can pass arguments to Miri via `MIRIFLAGS`. For example, `MIRIFLAGS="-Zmiri-disable-stacked-borrows" cargo miri run` runs the program without checking the aliasing of references. -When compiling code via `cargo miri`, the `cfg(miri)` config flag is set. You +When compiling code via `cargo miri`, the `cfg(miri)` config flag is set. You can use this to ignore test cases that fail under Miri because they do things Miri does not support: @@ -105,9 +108,7 @@ Miri does not support: #[test] #[cfg_attr(miri, ignore)] fn does_not_work_on_miri() { - std::thread::spawn(|| println!("Hello Thread!")) - .join() - .unwrap(); + tokio::run(futures::future::ok::<_, ()>(())); } ``` @@ -126,11 +127,11 @@ error: unsupported operation: can't call foreign function: bind Miri can not only run a binary or test suite for your host target, it can also perform cross-interpretation for arbitrary foreign targets: `cargo miri run --target x86_64-unknown-linux-gnu` will run your program as if it was a Linux -program, no matter your host OS. This is particularly useful if you are using +program, no matter your host OS. This is particularly useful if you are using Windows, as the Linux target is much better supported than Windows targets. You can also use this to test platforms with different properties than your host -platform. For example `cargo miri test --target mips64-unknown-linux-gnuabi64` +platform. For example `cargo miri test --target mips64-unknown-linux-gnuabi64` will run your test suite on a big-endian target, which is useful for testing endian-sensitive code. From 3dff1d4fcd29f9f4cc258cb1b971c95a38ee5924 Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Wed, 7 Apr 2021 20:46:20 +0800 Subject: [PATCH 2615/3747] Don't use `MIRI_DEFAULT_ARGS` to compile host crates --- README.md | 14 +++++++----- cargo-miri/bin.rs | 8 ++++--- src/bin/miri.rs | 33 +++++++++++++++++++++------ test-cargo-miri/Cargo.lock | 5 ++++ test-cargo-miri/Cargo.toml | 1 + test-cargo-miri/build.rs | 8 +++++++ test-cargo-miri/issue-1760/Cargo.toml | 8 +++++++ test-cargo-miri/issue-1760/build.rs | 10 ++++++++ test-cargo-miri/issue-1760/src/lib.rs | 9 ++++++++ test-cargo-miri/src/lib.rs | 1 + tests/run-pass/cfg_miri.rs | 3 +++ 11 files changed, 84 insertions(+), 16 deletions(-) create mode 100644 test-cargo-miri/issue-1760/Cargo.toml create mode 100644 test-cargo-miri/issue-1760/build.rs create mode 100644 test-cargo-miri/issue-1760/src/lib.rs create mode 100644 tests/run-pass/cfg_miri.rs diff --git a/README.md b/README.md index fd6110aafa781..11bb31dc74dc4 100644 --- a/README.md +++ b/README.md @@ -100,9 +100,9 @@ You can pass arguments to Miri via `MIRIFLAGS`. For example, `MIRIFLAGS="-Zmiri-disable-stacked-borrows" cargo miri run` runs the program without checking the aliasing of references. -When compiling code via `cargo miri`, the `cfg(miri)` config flag is set. You -can use this to ignore test cases that fail under Miri because they do things -Miri does not support: +When compiling code via `cargo miri`, the `cfg(miri)` config flag is set for code +that will be interpret under Miri. You can use this to ignore test cases that fail +under Miri because they do things Miri does not support: ```rust #[test] @@ -286,9 +286,11 @@ Moreover, Miri recognizes some environment variables: The following environment variables are internal, but used to communicate between different Miri binaries, and as such worth documenting: -* `MIRI_BE_RUSTC` when set to any value tells the Miri driver to actually not - interpret the code but compile it like rustc would. This is useful to be sure - that the compiled `rlib`s are compatible with Miri. +* `MIRI_BE_RUSTC` can be set to `host` or `target`. It tells the Miri driver to + actually not interpret the code but compile it like rustc would. With `target`, Miri sets + some compiler flags to prepare the code for interpretation; with `host`, this is not done. + This environment variable is useful to be sure that the compiled `rlib`s are compatible + with Miri. When set while running `cargo-miri`, it indicates that we are part of a sysroot build (for which some crates need special treatment). * `MIRI_CALLED_FROM_RUSTDOC` when set to any value tells `cargo-miri` that it is diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index b70d95c604028..bdf7e0052d190 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -420,7 +420,7 @@ path = "lib.rs" } else { command.env("RUSTC", &cargo_miri_path); } - command.env("MIRI_BE_RUSTC", "1"); + command.env("MIRI_BE_RUSTC", "target"); // Make sure there are no other wrappers or flags getting in our way // (Cc https://github.com/rust-lang/miri/issues/1421). // This is consistent with normal `cargo build` that does not apply `RUSTFLAGS` @@ -694,7 +694,7 @@ fn phase_cargo_rustc(mut args: env::Args) { } cmd.args(&env.args); - cmd.env("MIRI_BE_RUSTC", "1"); + cmd.env("MIRI_BE_RUSTC", "target"); if verbose { eprintln!("[cargo-miri rustc] captured input:\n{}", std::str::from_utf8(&env.stdin).unwrap()); @@ -758,7 +758,9 @@ fn phase_cargo_rustc(mut args: env::Args) { // We want to compile, not interpret. We still use Miri to make sure the compiler version etc // are the exact same as what is used for interpretation. - cmd.env("MIRI_BE_RUSTC", "1"); + // MIRI_DEFAULT_ARGS should not be used to build host crates, hence setting "target" or "host" + // as the value here to help Miri differentiate them. + cmd.env("MIRI_BE_RUSTC", if target_crate { "target" } else { "host" }); // Run it. if verbose { diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 8256bbd8f847e..23a58cf2d8c6c 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -135,7 +135,11 @@ fn compile_time_sysroot() -> Option { } /// Execute a compiler with the given CLI arguments and callbacks. -fn run_compiler(mut args: Vec, callbacks: &mut (dyn rustc_driver::Callbacks + Send)) -> ! { +fn run_compiler( + mut args: Vec, + callbacks: &mut (dyn rustc_driver::Callbacks + Send), + insert_default_args: bool, +) -> ! { // Make sure we use the right default sysroot. The default sysroot is wrong, // because `get_or_default_sysroot` in `librustc_session` bases that on `current_exe`. // @@ -151,9 +155,11 @@ fn run_compiler(mut args: Vec, callbacks: &mut (dyn rustc_driver::Callba } } - // Some options have different defaults in Miri than in plain rustc; apply those by making - // them the first arguments after the binary name (but later arguments can overwrite them). - args.splice(1..1, miri::MIRI_DEFAULT_ARGS.iter().map(ToString::to_string)); + if insert_default_args { + // Some options have different defaults in Miri than in plain rustc; apply those by making + // them the first arguments after the binary name (but later arguments can overwrite them). + args.splice(1..1, miri::MIRI_DEFAULT_ARGS.iter().map(ToString::to_string)); + } // Invoke compiler, and handle return code. let exit_code = rustc_driver::catch_with_exit_code(move || { @@ -166,11 +172,24 @@ fn main() { rustc_driver::install_ice_hook(); // If the environment asks us to actually be rustc, then do that. - if env::var_os("MIRI_BE_RUSTC").is_some() { + if let Some(crate_kind) = env::var_os("MIRI_BE_RUSTC") { rustc_driver::init_rustc_env_logger(); + + // Don't insert `MIRI_DEFAULT_ARGS`, in particular, `--cfg=miri`, if we are building a + // "host" crate. That may cause procedural macros (and probably build scripts) to depend + // on Miri-only symbols, such as `miri_resolve_frame`: + // https://github.com/rust-lang/miri/issues/1760 + let insert_default_args = if crate_kind == "target" { + true + } else if crate_kind == "host" { + false + } else { + panic!("invalid `MIRI_BE_RUSTC` value: {:?}", crate_kind) + }; + // We cannot use `rustc_driver::main` as we need to adjust the CLI arguments. let mut callbacks = rustc_driver::TimePassesCallbacks::default(); - run_compiler(env::args().collect(), &mut callbacks) + run_compiler(env::args().collect(), &mut callbacks, insert_default_args) } // Init loggers the Miri way. @@ -300,5 +319,5 @@ fn main() { debug!("rustc arguments: {:?}", rustc_args); debug!("crate arguments: {:?}", miri_config.args); - run_compiler(rustc_args, &mut MiriCompilerCalls { miri_config }) + run_compiler(rustc_args, &mut MiriCompilerCalls { miri_config }, /* insert_default_args: */ true) } diff --git a/test-cargo-miri/Cargo.lock b/test-cargo-miri/Cargo.lock index 45ec195843dc8..403b9327930ab 100644 --- a/test-cargo-miri/Cargo.lock +++ b/test-cargo-miri/Cargo.lock @@ -19,6 +19,7 @@ dependencies = [ "issue_1567", "issue_1691", "issue_1705", + "issue_1760", "rand", "serde_derive", ] @@ -85,6 +86,10 @@ dependencies = [ "byteorder", ] +[[package]] +name = "issue_1760" +version = "0.1.0" + [[package]] name = "libc" version = "0.2.92" diff --git a/test-cargo-miri/Cargo.toml b/test-cargo-miri/Cargo.toml index 08470539727ab..ae46ebc02a36e 100644 --- a/test-cargo-miri/Cargo.toml +++ b/test-cargo-miri/Cargo.toml @@ -13,6 +13,7 @@ cdylib = { path = "cdylib" } issue_1567 = { path = "issue-1567" } issue_1691 = { path = "issue-1691" } issue_1705 = { path = "issue-1705" } +issue_1760 = { path = "issue-1760" } [dev-dependencies] rand = { version = "0.8", features = ["small_rng"] } diff --git a/test-cargo-miri/build.rs b/test-cargo-miri/build.rs index 9851ccf39f3ff..3e84d69eec804 100644 --- a/test-cargo-miri/build.rs +++ b/test-cargo-miri/build.rs @@ -1,5 +1,10 @@ #![feature(llvm_asm)] +use std::env; + +#[cfg(miri)] +compile_error!("`miri` cfg should not be set in build script"); + fn not_in_miri() -> i32 { // Inline assembly definitely does not work in Miri. let dummy = 42; @@ -11,6 +16,9 @@ fn not_in_miri() -> i32 { fn main() { not_in_miri(); + // Cargo calls `miri --print=cfg` to populate the `CARGO_CFG_*` env vars. + // Make sure that the "miri" flag is set. + assert!(env::var_os("CARGO_CFG_MIRI").is_some()); println!("cargo:rerun-if-changed=build.rs"); println!("cargo:rerun-if-env-changed=MIRITESTVAR"); println!("cargo:rustc-env=MIRITESTVAR=testval"); diff --git a/test-cargo-miri/issue-1760/Cargo.toml b/test-cargo-miri/issue-1760/Cargo.toml new file mode 100644 index 0000000000000..80925c7474638 --- /dev/null +++ b/test-cargo-miri/issue-1760/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "issue_1760" +version = "0.1.0" +authors = ["Miri Team"] +edition = "2018" + +[lib] +proc-macro = true diff --git a/test-cargo-miri/issue-1760/build.rs b/test-cargo-miri/issue-1760/build.rs new file mode 100644 index 0000000000000..08427fd7164f1 --- /dev/null +++ b/test-cargo-miri/issue-1760/build.rs @@ -0,0 +1,10 @@ +use std::env; + +#[cfg(miri)] +compile_error!("`miri` cfg should not be set in build script"); + +fn main() { + // Cargo calls `miri --print=cfg` to populate the `CARGO_CFG_*` env vars. + // Make sure that the "miri" flag is not set since we are building a procedural macro crate. + assert!(env::var_os("CARGO_CFG_MIRI").is_none()); +} diff --git a/test-cargo-miri/issue-1760/src/lib.rs b/test-cargo-miri/issue-1760/src/lib.rs new file mode 100644 index 0000000000000..b4f6274af4448 --- /dev/null +++ b/test-cargo-miri/issue-1760/src/lib.rs @@ -0,0 +1,9 @@ +use proc_macro::TokenStream; + +#[cfg(miri)] +compile_error!("`miri` cfg should not be set in proc-macro"); + +#[proc_macro] +pub fn use_the_dependency(_: TokenStream) -> TokenStream { + TokenStream::new() +} diff --git a/test-cargo-miri/src/lib.rs b/test-cargo-miri/src/lib.rs index 0c268a18f63c4..b11a64da13b47 100644 --- a/test-cargo-miri/src/lib.rs +++ b/test-cargo-miri/src/lib.rs @@ -11,5 +11,6 @@ pub fn make_true() -> bool { issue_1567::use_the_dependency(); issue_1705::use_the_dependency(); + issue_1760::use_the_dependency!(); issue_1691::use_me() } diff --git a/tests/run-pass/cfg_miri.rs b/tests/run-pass/cfg_miri.rs new file mode 100644 index 0000000000000..558b9a4f50db9 --- /dev/null +++ b/tests/run-pass/cfg_miri.rs @@ -0,0 +1,3 @@ +fn main() { + assert!(cfg!(miri)); +} From 0a7a41f6ad5e782e5ea60bed6beae6dc025c5c06 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 9 Apr 2021 11:24:33 +0200 Subject: [PATCH 2616/3747] fix typo in README --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index fd6110aafa781..aa38a45529ac8 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ [actions-url]: https://github.com/rust-lang/miri/actions An experimental interpreter for [Rust][rust]'s -[mid-level intermediate representation][mir] (MIR). It can run binaries and +[mid-level intermediate representation][mir] (MIR). It can run binaries and test suites of cargo projects and detect certain classes of [undefined behavior](https://doc.rust-lang.org/reference/behavior-considered-undefined.html), for example: @@ -32,7 +32,7 @@ big-endian systems. See [cross-interpretation](#cross-interpretation-running-for-different-targets) below. -Miri has already discovered some [real-world bugs](#bugs-found-by-miri). If you +Miri has already discovered some [real-world bugs](#bugs-found-by-miri). If you found a bug with Miri, we'd appreciate if you tell us and we'll add it to the list! @@ -41,7 +41,7 @@ in your program, and cannot run all programs: * There are still plenty of open questions around the basic invariants for some types and when these invariants even have to hold. Miri tries to avoid false - positives here, so if you program runs fine in Miri right now that is by no + positives here, so if your program runs fine in Miri right now that is by no means a guarantee that it is UB-free when these questions get answered. In particular, Miri does currently not check that integers/floats are From aa3bc06f0f1f0c45ca5d84d030400bb052f51e73 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 10 Apr 2021 11:00:41 +0200 Subject: [PATCH 2617/3747] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 8fadf6f9a3b2c..00d749fbbfd7f 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -9b0edb7fddacd6a60a380c1ce59159de597ab270 +481598b26db6144c580dc113f4d78b4151b5a1bc From 21968aa53b9161969a9c28e9a4deac95e0d91cc2 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 10 Apr 2021 12:09:10 +0200 Subject: [PATCH 2618/3747] add test to detect dropped temporary --- .../dangling_pointers/stack_temporary.rs | 14 ++++++++++++++ .../storage_dead_dangling.rs | 0 2 files changed, 14 insertions(+) create mode 100644 tests/compile-fail/dangling_pointers/stack_temporary.rs rename tests/compile-fail/{ => dangling_pointers}/storage_dead_dangling.rs (100%) diff --git a/tests/compile-fail/dangling_pointers/stack_temporary.rs b/tests/compile-fail/dangling_pointers/stack_temporary.rs new file mode 100644 index 0000000000000..cbd788bbf414e --- /dev/null +++ b/tests/compile-fail/dangling_pointers/stack_temporary.rs @@ -0,0 +1,14 @@ +// This should fail even without validation, but some MIR opts mask the error +// compile-flags: -Zmiri-disable-validation -Zmir-opt-level=0 + +unsafe fn make_ref<'a>(x: *mut i32) -> &'a mut i32 { + &mut *x +} + +fn main() { + unsafe { + let x = make_ref(&mut 0); // The temporary storing "0" is deallocated at the ";"! + let val = *x; //~ ERROR dereferenced after this allocation got freed + println!("{}", val); + } +} diff --git a/tests/compile-fail/storage_dead_dangling.rs b/tests/compile-fail/dangling_pointers/storage_dead_dangling.rs similarity index 100% rename from tests/compile-fail/storage_dead_dangling.rs rename to tests/compile-fail/dangling_pointers/storage_dead_dangling.rs From 87882f2c6a2fa754e8c948145e17b5bafb6dec75 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 10 Apr 2021 12:33:18 +0200 Subject: [PATCH 2619/3747] add the bad doctests we found to the trophy case --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 168c4bc1a24d8..7e7966be46f1e 100644 --- a/README.md +++ b/README.md @@ -415,6 +415,7 @@ Definite bugs found: * [TiKV constructing out-of-bounds pointers (and overlapping mutable references)](https://github.com/tikv/tikv/pull/7751) * [`encoding_rs` doing out-of-bounds pointer arithmetic](https://github.com/hsivonen/encoding_rs/pull/53) * [TiKV using `Vec::from_raw_parts` incorrectly](https://github.com/tikv/agatedb/pull/24) +* Incorrect doctests for [`AtomicPtr`](https://github.com/rust-lang/rust/pull/84052) and [`Box::from_raw_in`](https://github.com/rust-lang/rust/pull/84053) Violations of [Stacked Borrows] found that are likely bugs (but Stacked Borrows is currently just an experiment): From eaba4b2d2a9faf4a9dfa9529913499c3a2ae03bb Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 10 Apr 2021 14:07:46 +0200 Subject: [PATCH 2620/3747] remove compatibility code for passing miri flags via cargo arguments --- cargo-miri/bin.rs | 42 ++---------------------------------------- 1 file changed, 2 insertions(+), 40 deletions(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index bdf7e0052d190..151c952c390ca 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -521,46 +521,8 @@ fn phase_cargo_miri(mut args: env::Args) { &host }; - // Forward all further arguments. We do some processing here because we want to - // detect people still using the old way of passing flags to Miri - // (`cargo miri -- -Zmiri-foo`). - while let Some(arg) = args.next() { - cmd.arg(&arg); - if arg == "--" { - // Check if the next argument starts with `-Zmiri`. If yes, we assume - // this is an old-style invocation. - if let Some(next_arg) = args.next() { - if next_arg.starts_with("-Zmiri") || next_arg == "--" { - eprintln!( - "WARNING: it seems like you are setting Miri's flags in `cargo miri` the old way,\n\ - i.e., by passing them after the first `--`. This style is deprecated; please set\n\ - the MIRIFLAGS environment variable instead. `cargo miri run/test` now interprets\n\ - arguments the exact same way as `cargo run/test`." - ); - // Old-style invocation. Turn these into MIRIFLAGS, if there are any. - if next_arg != "--" { - let mut miriflags = env::var("MIRIFLAGS").unwrap_or_default(); - miriflags.push(' '); - miriflags.push_str(&next_arg); - while let Some(further_arg) = args.next() { - if further_arg == "--" { - // End of the Miri flags! - break; - } - miriflags.push(' '); - miriflags.push_str(&further_arg); - } - env::set_var("MIRIFLAGS", miriflags); - } - // Pass the remaining flags to cargo. - cmd.args(args); - break; - } - // Not a Miri argument after all, make sure we pass it to cargo. - cmd.arg(next_arg); - } - } - } + // Forward all further arguments to cargo. + cmd.args(args); // Set `RUSTC_WRAPPER` to ourselves. Cargo will prepend that binary to its usual invocation, // i.e., the first argument is `rustc` -- which is what we use in `main` to distinguish From 2decc78db93fe88fc498bff17dc4a215ef92f9d7 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 10 Apr 2021 14:20:06 +0200 Subject: [PATCH 2621/3747] make sure that we truly do not run no_run doctests --- test-cargo-miri/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test-cargo-miri/src/lib.rs b/test-cargo-miri/src/lib.rs index b11a64da13b47..5b84c454c3624 100644 --- a/test-cargo-miri/src/lib.rs +++ b/test-cargo-miri/src/lib.rs @@ -3,7 +3,7 @@ /// assert!(cargo_miri_test::make_true()); /// ``` /// ```rust,no_run -/// assert!(cargo_miri_test::make_true()); +/// assert!(!cargo_miri_test::make_true()); /// ``` /// ```rust,compile_fail /// assert!(cargo_miri_test::make_true() == 5); From 72ca2a7a85dd7b87d1a0cad54ce5b513c7cde2d2 Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Sat, 10 Apr 2021 20:23:32 +0200 Subject: [PATCH 2622/3747] Attempt to fix #1763 by asking the scheduler to retry choosing an operation. --- src/thread.rs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/thread.rs b/src/thread.rs index 4fe44ef9d4a7d..e744ac519dd02 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -711,7 +711,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn run_timeout_callback(&mut self) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let (thread, callback) = - this.machine.threads.get_ready_callback().expect("no callback found"); + if let Some((thread, callback)) = this.machine.threads.get_ready_callback() { + (thread, callback) + } else { + // get_ready_callback can return None if the computer's clock was + // shifted after calling the scheduler and before the call + // to get_ready_callback. In this case, just do nothing, which + // effectively just returns to the scheduler. + return Ok(()); + }; // This back-and-forth with `set_active_thread` is here because of two // design decisions: // 1. Make the caller and not the callback responsible for changing From bda328e26ab638b54d8f11ff967becf7f574f98e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 11 Apr 2021 13:23:37 +0200 Subject: [PATCH 2623/3747] only check timeouts when a thread yields --- src/thread.rs | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/thread.rs b/src/thread.rs index 4fe44ef9d4a7d..0f373e4cd31eb 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -477,6 +477,7 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { if self.threads[self.active_thread].check_terminated() { return Ok(SchedulingAction::ExecuteDtors); } + // If we get here again and the thread is *still* terminated, there are no more dtors to run. if self.threads[MAIN_THREAD].state == ThreadState::Terminated { // The main thread terminated; stop the program. if self.threads.iter().any(|thread| thread.state != ThreadState::Terminated) { @@ -490,26 +491,25 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { } return Ok(SchedulingAction::Stop); } - // At least for `pthread_cond_timedwait` we need to report timeout when - // the function is called already after the specified time even if a - // signal is received before the thread gets scheduled. Therefore, we - // need to schedule all timeout callbacks before we continue regular - // execution. - // - // Documentation: - // https://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_cond_timedwait.html# - let potential_sleep_time = - self.timeout_callbacks.values().map(|info| info.call_time.get_wait_time()).min(); - if potential_sleep_time == Some(Duration::new(0, 0)) { - return Ok(SchedulingAction::ExecuteTimeoutCallback); - } - // No callbacks scheduled, pick a regular thread to execute. + // This thread and the program can keep going. if self.threads[self.active_thread].state == ThreadState::Enabled && !self.yield_active_thread { // The currently active thread is still enabled, just continue with it. return Ok(SchedulingAction::ExecuteStep); } + // The active thread yielded. Let's see if there are any timeouts to take care of. We do + // this *before* running any other thread, to ensure that timeouts "in the past" fire before + // any other thread can take an action. This ensures that for `pthread_cond_timedwait`, "an + // error is returned if [...] the absolute time specified by abstime has already been passed + // at the time of the call". + // + let potential_sleep_time = + self.timeout_callbacks.values().map(|info| info.call_time.get_wait_time()).min(); + if potential_sleep_time == Some(Duration::new(0, 0)) { + return Ok(SchedulingAction::ExecuteTimeoutCallback); + } + // No callbacks scheduled, pick a regular thread to execute. // We need to pick a new thread for execution. for (id, thread) in self.threads.iter_enumerated() { if thread.state == ThreadState::Enabled { From 50f68dce2182c9c53d3531e809ac5a0725a48c15 Mon Sep 17 00:00:00 2001 From: Vytautas Astrauskas Date: Sun, 11 Apr 2021 13:39:03 +0200 Subject: [PATCH 2624/3747] Reference issue 1763 in the comment. --- src/thread.rs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/thread.rs b/src/thread.rs index e744ac519dd02..0d4fcbd49ff66 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -714,10 +714,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if let Some((thread, callback)) = this.machine.threads.get_ready_callback() { (thread, callback) } else { - // get_ready_callback can return None if the computer's clock was - // shifted after calling the scheduler and before the call - // to get_ready_callback. In this case, just do nothing, which - // effectively just returns to the scheduler. + // get_ready_callback can return None if the computer's clock + // was shifted after calling the scheduler and before the call + // to get_ready_callback (see issue + // https://github.com/rust-lang/miri/issues/1763). In this case, + // just do nothing, which effectively just returns to the + // scheduler. return Ok(()); }; // This back-and-forth with `set_active_thread` is here because of two From 0674d439b620495480f126e96a4b97ae779d1ae7 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 11 Apr 2021 14:21:42 +0200 Subject: [PATCH 2625/3747] test calling pthread_cond_timedwait with an already elapsed timeout --- tests/run-pass/concurrency/libc_pthread_cond.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/run-pass/concurrency/libc_pthread_cond.rs b/tests/run-pass/concurrency/libc_pthread_cond.rs index d4e52bb3a97b0..a545c922db1ab 100644 --- a/tests/run-pass/concurrency/libc_pthread_cond.rs +++ b/tests/run-pass/concurrency/libc_pthread_cond.rs @@ -38,6 +38,12 @@ fn test_timed_wait_timeout(clock_id: i32) { let elapsed_time = current_time.elapsed().as_millis(); assert!(900 <= elapsed_time && elapsed_time <= 1300); + // Test calling `pthread_cond_timedwait` again with an already elapsed timeout. + assert_eq!( + libc::pthread_cond_timedwait(&mut cond as *mut _, &mut mutex as *mut _, &timeout), + libc::ETIMEDOUT + ); + // Test that invalid nanosecond values (above 10^9 or negative) are rejected with the // correct error code. let invalid_timeout_1 = libc::timespec { tv_sec: now.tv_sec + 1, tv_nsec: 1_000_000_000 }; From 67b8844628b47e132ffbebe75d259a430a5fbd82 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 12 Apr 2021 19:01:10 +0200 Subject: [PATCH 2626/3747] fix CONTRIBUTING example --- CONTRIBUTING.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index bbfcb7638f382..9edd63dae3157 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -74,7 +74,7 @@ You can get a trace of which MIR statements are being executed by setting the `MIRI_LOG` environment variable. For example: ```sh -MIRI_LOG=info ./miri run tests/run-pass/vecs.rs +MIRI_LOG=info ./miri run tests/run-pass/vec.rs ``` Setting `MIRI_LOG` like this will configure logging for Miri itself as well as @@ -83,7 +83,7 @@ can also do more targeted configuration, e.g. the following helps debug the stacked borrows implementation: ```sh -MIRI_LOG=rustc_mir::interpret=info,miri::stacked_borrows ./miri run tests/run-pass/vecs.rs +MIRI_LOG=rustc_mir::interpret=info,miri::stacked_borrows ./miri run tests/run-pass/vec.rs ``` In addition, you can set `MIRI_BACKTRACE=1` to get a backtrace of where an From 648638976af2f7331a61921997b0703edb2f4212 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ali=C3=A9nore=20Bouttefeux?= Date: Thu, 15 Apr 2021 10:00:39 +0200 Subject: [PATCH 2627/3747] allow deref of null ptr in test --- tests/compile-fail/null_pointer_deref.rs | 1 + tests/compile-fail/null_pointer_deref_zst.rs | 1 + tests/compile-fail/null_pointer_write.rs | 1 + tests/compile-fail/null_pointer_write_zst.rs | 1 + 4 files changed, 4 insertions(+) diff --git a/tests/compile-fail/null_pointer_deref.rs b/tests/compile-fail/null_pointer_deref.rs index bd4758f737e71..ab415d8746d18 100644 --- a/tests/compile-fail/null_pointer_deref.rs +++ b/tests/compile-fail/null_pointer_deref.rs @@ -1,3 +1,4 @@ +#[allow(deref_nullptr)] fn main() { let x: i32 = unsafe { *std::ptr::null() }; //~ ERROR inbounds test failed: 0x0 is not a valid pointer panic!("this should never print: {}", x); diff --git a/tests/compile-fail/null_pointer_deref_zst.rs b/tests/compile-fail/null_pointer_deref_zst.rs index d0f21a04d364e..45925f3586c48 100644 --- a/tests/compile-fail/null_pointer_deref_zst.rs +++ b/tests/compile-fail/null_pointer_deref_zst.rs @@ -1,6 +1,7 @@ // Some optimizations remove ZST accesses, thus masking this UB. // compile-flags: -Zmir-opt-level=0 +#[allow(deref_nullptr)] fn main() { let x: () = unsafe { *std::ptr::null() }; //~ ERROR memory access failed: 0x0 is not a valid pointer panic!("this should never print: {:?}", x); diff --git a/tests/compile-fail/null_pointer_write.rs b/tests/compile-fail/null_pointer_write.rs index 97c9ee8b1f52d..599d2ff7fd5b1 100644 --- a/tests/compile-fail/null_pointer_write.rs +++ b/tests/compile-fail/null_pointer_write.rs @@ -1,3 +1,4 @@ +#[allow(deref_nullptr)] fn main() { unsafe { *std::ptr::null_mut() = 0i32 }; //~ ERROR inbounds test failed: 0x0 is not a valid pointer } diff --git a/tests/compile-fail/null_pointer_write_zst.rs b/tests/compile-fail/null_pointer_write_zst.rs index 1ee1a4b8a3035..595011fcd6a7d 100644 --- a/tests/compile-fail/null_pointer_write_zst.rs +++ b/tests/compile-fail/null_pointer_write_zst.rs @@ -1,6 +1,7 @@ // Some optimizations remove ZST accesses, thus masking this UB. // compile-flags: -Zmir-opt-level=0 +#[allow(deref_nullptr)] fn main() { // Not using the () type here, as writes of that type do not even have MIR generated. // Also not assigning directly as that's array initialization, not assignment. From 64d07ea217d4c0a449afba904ed0d15545af7052 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ali=C3=A9nore=20Bouttefeux?= Date: Thu, 15 Apr 2021 10:17:54 +0200 Subject: [PATCH 2628/3747] change rust version to head --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 00d749fbbfd7f..0bfc150a4fc47 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -481598b26db6144c580dc113f4d78b4151b5a1bc +043d9160769a330df5d8a21e846785e2c89f357d From 85f7dd613183c8ee884053c6c5ace48bd8fc0579 Mon Sep 17 00:00:00 2001 From: Charles Lew Date: Fri, 16 Apr 2021 22:22:01 +0800 Subject: [PATCH 2629/3747] Remove `main_fn.rs` test. --- rust-version | 2 +- tests/run-pass/main_fn.rs | 5 ----- 2 files changed, 1 insertion(+), 6 deletions(-) delete mode 100644 tests/run-pass/main_fn.rs diff --git a/rust-version b/rust-version index 0bfc150a4fc47..46567849e07b4 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -043d9160769a330df5d8a21e846785e2c89f357d +3833636446b670ee905fba5f8d18881b1739814e diff --git a/tests/run-pass/main_fn.rs b/tests/run-pass/main_fn.rs deleted file mode 100644 index 91d183ee6af70..0000000000000 --- a/tests/run-pass/main_fn.rs +++ /dev/null @@ -1,5 +0,0 @@ -#![feature(main)] - -#[main] -fn foo() { -} From d512ba2ae244079f0d57f7032db06c12ee3b590c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 18 Apr 2021 10:57:56 +0200 Subject: [PATCH 2630/3747] test thread_local_const_init --- tests/run-pass/concurrency/tls_lib_drop.rs | 6 ++++++ tests/run-pass/concurrency/tls_lib_drop.stdout | 1 + tests/run-pass/concurrency/tls_lib_drop_single_thread.rs | 7 +++++++ .../run-pass/concurrency/tls_lib_drop_single_thread.stderr | 1 + .../tls_pthread_drop_order.rs} | 0 5 files changed, 15 insertions(+) rename tests/run-pass/{thread-local.rs => concurrency/tls_pthread_drop_order.rs} (100%) diff --git a/tests/run-pass/concurrency/tls_lib_drop.rs b/tests/run-pass/concurrency/tls_lib_drop.rs index 46f59ef6204f7..00a12599ce99a 100644 --- a/tests/run-pass/concurrency/tls_lib_drop.rs +++ b/tests/run-pass/concurrency/tls_lib_drop.rs @@ -1,4 +1,5 @@ // ignore-windows: Concurrency on Windows is not supported yet. +#![feature(thread_local_const_init)] use std::cell::RefCell; use std::thread; @@ -16,6 +17,7 @@ impl Drop for TestCell { thread_local! { static A: TestCell = TestCell { value: RefCell::new(0) }; + static A_CONST: TestCell = const { TestCell { value: RefCell::new(10) } }; } /// Check that destructors of the library thread locals are executed immediately @@ -26,6 +28,10 @@ fn check_destructors() { assert_eq!(*f.value.borrow(), 0); *f.value.borrow_mut() = 5; }); + A_CONST.with(|f| { + assert_eq!(*f.value.borrow(), 10); + *f.value.borrow_mut() = 15; + }); }) .join() .unwrap(); diff --git a/tests/run-pass/concurrency/tls_lib_drop.stdout b/tests/run-pass/concurrency/tls_lib_drop.stdout index 484979b04ca77..9cd7e049d1a0a 100644 --- a/tests/run-pass/concurrency/tls_lib_drop.stdout +++ b/tests/run-pass/concurrency/tls_lib_drop.stdout @@ -1,4 +1,5 @@ Dropping: 5 (should be before 'Continue main 1'). +Dropping: 15 (should be before 'Continue main 1'). Continue main 1. Joining: 7 (should be before 'Continue main 2'). Continue main 2. diff --git a/tests/run-pass/concurrency/tls_lib_drop_single_thread.rs b/tests/run-pass/concurrency/tls_lib_drop_single_thread.rs index f232cee5bdd10..7d8e84e33f160 100644 --- a/tests/run-pass/concurrency/tls_lib_drop_single_thread.rs +++ b/tests/run-pass/concurrency/tls_lib_drop_single_thread.rs @@ -1,4 +1,6 @@ +// compile-flags: -Zmiri-track-raw-pointers //! Check that destructors of the thread locals are executed on all OSes. +#![feature(thread_local_const_init)] use std::cell::RefCell; @@ -14,6 +16,7 @@ impl Drop for TestCell { thread_local! { static A: TestCell = TestCell { value: RefCell::new(0) }; + static A_CONST: TestCell = const { TestCell { value: RefCell::new(10) } }; } fn main() { @@ -21,5 +24,9 @@ fn main() { assert_eq!(*f.value.borrow(), 0); *f.value.borrow_mut() = 5; }); + A_CONST.with(|f| { + assert_eq!(*f.value.borrow(), 10); + *f.value.borrow_mut() = 15; + }); eprintln!("Continue main.") } diff --git a/tests/run-pass/concurrency/tls_lib_drop_single_thread.stderr b/tests/run-pass/concurrency/tls_lib_drop_single_thread.stderr index a9d705e5b9a22..e59dd284bd800 100644 --- a/tests/run-pass/concurrency/tls_lib_drop_single_thread.stderr +++ b/tests/run-pass/concurrency/tls_lib_drop_single_thread.stderr @@ -1,2 +1,3 @@ Continue main. Dropping: 5 +Dropping: 15 diff --git a/tests/run-pass/thread-local.rs b/tests/run-pass/concurrency/tls_pthread_drop_order.rs similarity index 100% rename from tests/run-pass/thread-local.rs rename to tests/run-pass/concurrency/tls_pthread_drop_order.rs From 6834944fd321deeb412838e9c8fedfb717b4f67c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 18 Apr 2021 12:29:31 +0200 Subject: [PATCH 2631/3747] fix MIRI_BE_RUSTC value during sysroot build --- README.md | 9 ++--- cargo-miri/bin.rs | 91 +++++++++++++++++++++++++++-------------------- 2 files changed, 57 insertions(+), 43 deletions(-) diff --git a/README.md b/README.md index 7e7966be46f1e..e0fbd9fafbb29 100644 --- a/README.md +++ b/README.md @@ -283,16 +283,17 @@ Moreover, Miri recognizes some environment variables: architecture to test against. `miri` and `cargo miri` accept the `--target` flag for the same purpose. -The following environment variables are internal, but used to communicate between -different Miri binaries, and as such worth documenting: +The following environment variables are *internal* and must not be used by +anyone but Miri itself. They are used to communicate between different Miri +binaries, and as such worth documenting: * `MIRI_BE_RUSTC` can be set to `host` or `target`. It tells the Miri driver to actually not interpret the code but compile it like rustc would. With `target`, Miri sets some compiler flags to prepare the code for interpretation; with `host`, this is not done. This environment variable is useful to be sure that the compiled `rlib`s are compatible with Miri. - When set while running `cargo-miri`, it indicates that we are part of a sysroot - build (for which some crates need special treatment). +* `MIRI_CALLED_FROM_XARGO` is set during the Miri-induced `xargo` sysroot build, + which will re-invoke `cargo-miri` as the `rustc` to use for this build. * `MIRI_CALLED_FROM_RUSTDOC` when set to any value tells `cargo-miri` that it is running as a child process of `rustdoc`, which invokes it twice for each doc-test and requires special treatment, most notably a check-only build before interpretation. diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index bdf7e0052d190..01b445ee7eb4c 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -413,14 +413,14 @@ path = "lib.rs" // for target crates. // We set ourselves (`cargo-miri`) instead of Miri directly to be able to patch the flags // for `libpanic_abort` (usually this is done by bootstrap but we have to do it ourselves). - // The `MIRI_BE_RUSTC` will mean we dispatch to `phase_setup_rustc`. + // The `MIRI_CALLED_FROM_XARGO` will mean we dispatch to `phase_setup_rustc`. let cargo_miri_path = std::env::current_exe().expect("current executable path invalid"); if env::var_os("RUSTC_STAGE").is_some() { command.env("RUSTC_REAL", &cargo_miri_path); } else { command.env("RUSTC", &cargo_miri_path); } - command.env("MIRI_BE_RUSTC", "target"); + command.env("MIRI_CALLED_FROM_XARGO", "1"); // Make sure there are no other wrappers or flags getting in our way // (Cc https://github.com/rust-lang/miri/issues/1421). // This is consistent with normal `cargo build` that does not apply `RUSTFLAGS` @@ -450,21 +450,6 @@ path = "lib.rs" } } -fn phase_setup_rustc(args: env::Args) { - // Mostly we just forward everything. - // `MIRI_BE_RUST` is already set. - let mut cmd = miri(); - cmd.args(args); - - // Patch the panic runtime for `libpanic_abort` (mirroring what bootstrap usually does). - if get_arg_flag_value("--crate-name").as_deref() == Some("panic_abort") { - cmd.arg("-C").arg("panic=abort"); - } - - // Run it! - exec(cmd); -} - fn phase_cargo_miri(mut args: env::Args) { // Check for version and help flags even when invoked as `cargo-miri`. if has_arg_flag("--help") || has_arg_flag("-h") { @@ -598,7 +583,17 @@ fn phase_cargo_miri(mut args: env::Args) { exec(cmd) } -fn phase_cargo_rustc(mut args: env::Args) { +#[derive(Debug, Copy, Clone, PartialEq)] +enum RustcPhase { + /// `rustc` called via `xargo` for sysroot build. + Setup, + /// `rustc` called by `cargo` for regular build. + Build, + /// `rustc` called by `rustdoc` for doctest. + Rustdoc, +} + +fn phase_rustc(mut args: env::Args, phase: RustcPhase) { /// Determines if we are being invoked (as rustc) to build a crate for /// the "target" architecture, in contrast to the "host" architecture. /// Host crates are for build scripts and proc macros and still need to @@ -644,7 +639,7 @@ fn phase_cargo_rustc(mut args: env::Args) { let verbose = std::env::var_os("MIRI_VERBOSE").is_some(); let target_crate = is_target_crate(); - let print = get_arg_flag_value("--print").is_some(); // whether this is cargo passing `--print` to get some infos + let print = get_arg_flag_value("--print").is_some() || has_arg_flag("-vV"); // whether this is cargo/xargo invoking rustc to get some infos let store_json = |info: CrateRunInfo| { // Create a stub .d file to stop Cargo from "rebuilding" the crate: @@ -669,7 +664,8 @@ fn phase_cargo_rustc(mut args: env::Args) { let runnable_crate = !print && is_runnable_crate(); if runnable_crate && target_crate { - let inside_rustdoc = env::var_os("MIRI_CALLED_FROM_RUSTDOC").is_some(); + assert!(phase != RustcPhase::Setup, "there should be no interpretation during sysroot build"); + let inside_rustdoc = phase == RustcPhase::Rustdoc; // This is the binary or test crate that we want to interpret under Miri. // But we cannot run it here, as cargo invoked us as a compiler -- our stdin and stdout are not // like we want them. @@ -749,8 +745,15 @@ fn phase_cargo_rustc(mut args: env::Args) { } } - // Use our custom sysroot. - forward_miri_sysroot(&mut cmd); + // Use our custom sysroot (but not if that is what we are currently building). + if phase != RustcPhase::Setup { + forward_miri_sysroot(&mut cmd); + } + + // During setup, patch the panic runtime for `libpanic_abort` (mirroring what bootstrap usually does). + if phase == RustcPhase::Setup && get_arg_flag_value("--crate-name").as_deref() == Some("panic_abort") { + cmd.arg("-C").arg("panic=abort"); + } } else { // For host crates or when we are printing, just forward everything. cmd.args(args); @@ -783,7 +786,15 @@ fn phase_cargo_rustc(mut args: env::Args) { } } -fn phase_cargo_runner(binary: &Path, binary_args: env::Args) { +#[derive(Debug, Copy, Clone, PartialEq)] +enum RunnerPhase { + /// `cargo` is running a binary + Cargo, + /// `rustdoc` is running a binary + Rustdoc, +} + +fn phase_runner(binary: &Path, binary_args: env::Args, phase: RunnerPhase) { let verbose = std::env::var_os("MIRI_VERBOSE").is_some(); let file = File::open(&binary) @@ -840,8 +851,8 @@ fn phase_cargo_runner(binary: &Path, binary_args: env::Args) { cmd.arg(arg); } } - if env::var_os("MIRI_CALLED_FROM_RUSTDOC").is_none() { - // Set sysroot (if we are inside rustdoc, we already did that in `phase_cargo_rustdoc`). + // Set sysroot (if we are inside rustdoc, we already did that in `phase_cargo_rustdoc`). + if phase != RunnerPhase::Rustdoc { forward_miri_sysroot(&mut cmd); } // Respect `MIRIFLAGS`. @@ -869,14 +880,17 @@ fn phase_cargo_runner(binary: &Path, binary_args: env::Args) { eprintln!("[cargo-miri runner] {:?}", cmd); } - if std::env::var_os("MIRI_CALLED_FROM_RUSTDOC").is_some() { - exec_with_pipe(cmd, &info.stdin) - } else { - exec(cmd) + match phase { + RunnerPhase::Rustdoc => { + exec_with_pipe(cmd, &info.stdin) + } + RunnerPhase::Cargo => { + exec(cmd) + } } } -fn phase_cargo_rustdoc(fst_arg: &str, mut args: env::Args) { +fn phase_rustdoc(fst_arg: &str, mut args: env::Args) { let verbose = std::env::var_os("MIRI_VERBOSE").is_some(); // phase_cargo_miri sets the RUSTDOC env var to ourselves, so we can't use that here; @@ -950,15 +964,14 @@ fn main() { args.next().unwrap(); // Dispatch running as part of sysroot compilation. - if env::var_os("MIRI_BE_RUSTC").is_some() { - phase_setup_rustc(args); + if env::var_os("MIRI_CALLED_FROM_XARGO").is_some() { + phase_rustc(args, RustcPhase::Setup); return; } // The way rustdoc invokes rustc is indistuingishable from the way cargo invokes rustdoc by the // arguments alone. `phase_cargo_rustdoc` sets this environment variable to let us disambiguate. - let invoked_by_rustdoc = env::var_os("MIRI_CALLED_FROM_RUSTDOC").is_some(); - if invoked_by_rustdoc { + if env::var_os("MIRI_CALLED_FROM_RUSTDOC").is_some() { // ...however, we then also see this variable when rustdoc invokes us as the testrunner! // The runner is invoked as `$runtool ($runtool-arg)* output_file`; // since we don't specify any runtool-args, and rustdoc supplies multiple arguments to @@ -967,12 +980,12 @@ fn main() { let arg = args.next().unwrap(); let binary = Path::new(&arg); if binary.exists() { - phase_cargo_runner(binary, args); + phase_runner(binary, args, RunnerPhase::Rustdoc); } else { show_error(format!("`cargo-miri` called with non-existing path argument `{}` in rustdoc mode; please invoke this binary through `cargo miri`", arg)); } } else { - phase_cargo_rustc(args); + phase_rustc(args, RustcPhase::Rustdoc); } return; @@ -988,7 +1001,7 @@ fn main() { // On top of that, we are also called as RUSTDOC, but that is just a stub currently. match args.next().as_deref() { Some("miri") => phase_cargo_miri(args), - Some("rustc") => phase_cargo_rustc(args), + Some("rustc") => phase_rustc(args, RustcPhase::Build), Some(arg) => { // We have to distinguish the "runner" and "rustdoc" cases. // As runner, the first argument is the binary (a file that should exist, with an absolute path); @@ -996,9 +1009,9 @@ fn main() { let binary = Path::new(arg); if binary.exists() { assert!(!arg.starts_with("--")); // not a flag - phase_cargo_runner(binary, args); + phase_runner(binary, args, RunnerPhase::Cargo); } else if arg.starts_with("--") { - phase_cargo_rustdoc(arg, args); + phase_rustdoc(arg, args); } else { show_error(format!("`cargo-miri` called with unexpected first argument `{}`; please only invoke this binary through `cargo miri`", arg)); } From f73cc11f3fcfa7f480297eb82a0fcd072a1d963d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 20 Apr 2021 09:40:18 +0200 Subject: [PATCH 2632/3747] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 46567849e07b4..29fc4efbeab81 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -3833636446b670ee905fba5f8d18881b1739814e +b2c20b51ed838368d3f2bdccb63f401bcddb7e1c From 2ae699c56db7366a14c5e0d517743084a184ffe1 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 20 Apr 2021 09:59:26 +0200 Subject: [PATCH 2633/3747] make TLS-drop-test more cross-platform --- tests/run-pass/concurrency/tls_lib_drop_single_thread.rs | 2 +- tests/run-pass/concurrency/tls_lib_drop_single_thread.stderr | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/run-pass/concurrency/tls_lib_drop_single_thread.rs b/tests/run-pass/concurrency/tls_lib_drop_single_thread.rs index 7d8e84e33f160..cd1bd6480bcfe 100644 --- a/tests/run-pass/concurrency/tls_lib_drop_single_thread.rs +++ b/tests/run-pass/concurrency/tls_lib_drop_single_thread.rs @@ -26,7 +26,7 @@ fn main() { }); A_CONST.with(|f| { assert_eq!(*f.value.borrow(), 10); - *f.value.borrow_mut() = 15; + *f.value.borrow_mut() = 5; // Same value as above since the drop order is different on different platforms }); eprintln!("Continue main.") } diff --git a/tests/run-pass/concurrency/tls_lib_drop_single_thread.stderr b/tests/run-pass/concurrency/tls_lib_drop_single_thread.stderr index e59dd284bd800..09ec1c3c2c511 100644 --- a/tests/run-pass/concurrency/tls_lib_drop_single_thread.stderr +++ b/tests/run-pass/concurrency/tls_lib_drop_single_thread.stderr @@ -1,3 +1,3 @@ Continue main. Dropping: 5 -Dropping: 15 +Dropping: 5 From 4c741e5fb2c6e73d654aa7485ab8985882d6bc05 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 25 Apr 2021 16:57:48 +0200 Subject: [PATCH 2634/3747] rustup --- rust-version | 2 +- tests/compile-fail/invalid_bool.rs | 2 +- tests/run-pass/float.rs | 2 +- tests/run-pass/u128.rs | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/rust-version b/rust-version index 29fc4efbeab81..d1505e9d8418c 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -b2c20b51ed838368d3f2bdccb63f401bcddb7e1c +06f0adb34570ba83fee391abeb0bec0eec28a234 diff --git a/tests/compile-fail/invalid_bool.rs b/tests/compile-fail/invalid_bool.rs index 796d8220dc196..22b9de5776fee 100644 --- a/tests/compile-fail/invalid_bool.rs +++ b/tests/compile-fail/invalid_bool.rs @@ -1,7 +1,7 @@ // Validation makes this fail in the wrong place // Make sure we find these even with many checks disabled. // compile-flags: -Zmiri-disable-alignment-check -Zmiri-disable-stacked-borrows -Zmiri-disable-validation -#![feature(test)] +#![feature(bench_black_box)] fn main() { let b = unsafe { std::mem::transmute::(2) }; diff --git a/tests/run-pass/float.rs b/tests/run-pass/float.rs index d9dba770dabd7..e40ea919dca16 100644 --- a/tests/run-pass/float.rs +++ b/tests/run-pass/float.rs @@ -1,4 +1,4 @@ -#![feature(stmt_expr_attributes, test)] +#![feature(stmt_expr_attributes, bench_black_box)] #![allow(arithmetic_overflow)] use std::fmt::Debug; use std::hint::black_box; diff --git a/tests/run-pass/u128.rs b/tests/run-pass/u128.rs index bbc667c5ddebb..fae73476275b3 100644 --- a/tests/run-pass/u128.rs +++ b/tests/run-pass/u128.rs @@ -1,4 +1,4 @@ -#![feature(test)] +#![feature(bench_black_box)] use std::hint::black_box as b; fn main() { From b30c5fef5b3654ada90856067240e7b451b8b973 Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Fri, 30 Apr 2021 18:50:40 +0800 Subject: [PATCH 2635/3747] Rustup for rust-lang/rust#84401 --- benches/helpers/miri_helper.rs | 2 +- rust-version | 2 +- src/bin/miri.rs | 2 +- test-cargo-miri/Cargo.toml | 4 ++++ test-cargo-miri/src/lib.rs | 4 ++++ test-cargo-miri/test.cross-target.stdout.ref | 1 + test-cargo-miri/test.default.stdout.ref | 1 + test-cargo-miri/test.filter.cross-target.stdout.ref | 1 + test-cargo-miri/test.filter.stdout.ref | 1 + test-cargo-miri/tests/main.rs | 3 +++ tests/run-pass/main_fn.rs | 7 +++++++ 11 files changed, 25 insertions(+), 3 deletions(-) create mode 100644 test-cargo-miri/tests/main.rs create mode 100644 tests/run-pass/main_fn.rs diff --git a/benches/helpers/miri_helper.rs b/benches/helpers/miri_helper.rs index 261be48aa0a3d..8397fde946c56 100644 --- a/benches/helpers/miri_helper.rs +++ b/benches/helpers/miri_helper.rs @@ -26,7 +26,7 @@ impl rustc_driver::Callbacks for MiriCompilerCalls<'_> { self.bencher.iter(|| { let config = miri::MiriConfig::default(); - miri::eval_main(tcx, entry_def_id.to_def_id(), config); + miri::eval_main(tcx, entry_def_id, config); }); }); diff --git a/rust-version b/rust-version index d1505e9d8418c..1f61617e119f4 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -06f0adb34570ba83fee391abeb0bec0eec28a234 +bcd696d722c04a0f8c34d884aa4ed2322f55cdd8 diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 23a58cf2d8c6c..41776090be443 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -50,7 +50,7 @@ impl rustc_driver::Callbacks for MiriCompilerCalls { env::set_current_dir(cwd).unwrap(); } - if let Some(return_code) = miri::eval_main(tcx, entry_def_id.to_def_id(), config) { + if let Some(return_code) = miri::eval_main(tcx, entry_def_id, config) { std::process::exit( i32::try_from(return_code).expect("Return value was too large!"), ); diff --git a/test-cargo-miri/Cargo.toml b/test-cargo-miri/Cargo.toml index ae46ebc02a36e..4dbe1aeff23a3 100644 --- a/test-cargo-miri/Cargo.toml +++ b/test-cargo-miri/Cargo.toml @@ -23,3 +23,7 @@ serde_derive = "1.0" # not actually used, but exercises some unique code path (` [lib] test = false # test that this is respected (will show in the output) + +[[test]] +name = "main" +harness = false diff --git a/test-cargo-miri/src/lib.rs b/test-cargo-miri/src/lib.rs index 5b84c454c3624..9d8eb067d6fa7 100644 --- a/test-cargo-miri/src/lib.rs +++ b/test-cargo-miri/src/lib.rs @@ -14,3 +14,7 @@ pub fn make_true() -> bool { issue_1760::use_the_dependency!(); issue_1691::use_me() } + +pub fn main() { + println!("imported main"); +} diff --git a/test-cargo-miri/test.cross-target.stdout.ref b/test-cargo-miri/test.cross-target.stdout.ref index 7079798e42feb..e36abd870663e 100644 --- a/test-cargo-miri/test.cross-target.stdout.ref +++ b/test-cargo-miri/test.cross-target.stdout.ref @@ -3,6 +3,7 @@ running 1 test . test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out +imported main running 7 tests ..i.... diff --git a/test-cargo-miri/test.default.stdout.ref b/test-cargo-miri/test.default.stdout.ref index 6e35c374e1920..470e5b36fc515 100644 --- a/test-cargo-miri/test.default.stdout.ref +++ b/test-cargo-miri/test.default.stdout.ref @@ -3,6 +3,7 @@ running 1 test . test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out +imported main running 7 tests ..i.... diff --git a/test-cargo-miri/test.filter.cross-target.stdout.ref b/test-cargo-miri/test.filter.cross-target.stdout.ref index 37efb8c3ee896..fb722c5e71239 100644 --- a/test-cargo-miri/test.filter.cross-target.stdout.ref +++ b/test-cargo-miri/test.filter.cross-target.stdout.ref @@ -3,6 +3,7 @@ running 0 tests test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 1 filtered out +imported main running 1 test test simple1 ... ok diff --git a/test-cargo-miri/test.filter.stdout.ref b/test-cargo-miri/test.filter.stdout.ref index 11e47e8ff8165..cf1b309a12786 100644 --- a/test-cargo-miri/test.filter.stdout.ref +++ b/test-cargo-miri/test.filter.stdout.ref @@ -3,6 +3,7 @@ running 0 tests test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 1 filtered out +imported main running 1 test test simple1 ... ok diff --git a/test-cargo-miri/tests/main.rs b/test-cargo-miri/tests/main.rs new file mode 100644 index 0000000000000..bb94c8f37876c --- /dev/null +++ b/test-cargo-miri/tests/main.rs @@ -0,0 +1,3 @@ +#![feature(imported_main)] + +use cargo_miri_test::main; diff --git a/tests/run-pass/main_fn.rs b/tests/run-pass/main_fn.rs new file mode 100644 index 0000000000000..3b84d1abe6f3d --- /dev/null +++ b/tests/run-pass/main_fn.rs @@ -0,0 +1,7 @@ +#![feature(imported_main)] + +mod foo { + pub(crate) fn bar() {} +} + +use foo::bar as main; From 2da6bedaec3f072daae18b7d59e45dd090d48428 Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Fri, 30 Apr 2021 17:22:24 +0800 Subject: [PATCH 2636/3747] Use `harness = false` instead of `#![feature(custom_test_frameworks)]` --- Cargo.toml | 4 ++++ tests/compiletest.rs | 6 +----- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 2483cb2c81293..ab7d88e66934a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -45,3 +45,7 @@ colored = "2" # This crate uses #[feature(rustc_private)]. # See https://github.com/rust-analyzer/rust-analyzer/pull/7891 rustc_private = true + +[[test]] +name = "compiletest" +harness = false diff --git a/tests/compiletest.rs b/tests/compiletest.rs index 5de5dfb4c6756..a0d49c9ddcf48 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -1,7 +1,3 @@ -#![feature(custom_test_frameworks)] -// Custom test runner, to avoid libtest being wrapped around compiletest which wraps libtest. -#![test_runner(test_runner)] - use std::env; use std::path::PathBuf; @@ -83,7 +79,7 @@ fn get_target() -> String { env::var("MIRI_TEST_TARGET").unwrap_or_else(|_| get_host()) } -fn test_runner(_tests: &[&()]) { +fn main() { // Add a test env var to do environment communication tests. env::set_var("MIRI_ENV_VAR_TEST", "0"); // Let the tests know where to store temp files (they might run for a different target, which can make this hard to find). From e591b83185ba60cec09225d5ed6b41325a7a331f Mon Sep 17 00:00:00 2001 From: Smitty Date: Sun, 2 May 2021 12:25:00 -0400 Subject: [PATCH 2637/3747] UB if f*_fast intrinsic called with nonfinite value --- src/shims/intrinsics.rs | 30 ++++++++++++++++++++++++++ tests/compile-fail/fast_math_both.rs | 7 ++++++ tests/compile-fail/fast_math_first.rs | 7 ++++++ tests/compile-fail/fast_math_second.rs | 7 ++++++ 4 files changed, 51 insertions(+) create mode 100644 tests/compile-fail/fast_math_both.rs create mode 100644 tests/compile-fail/fast_math_first.rs create mode 100644 tests/compile-fail/fast_math_second.rs diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 64c6e0a540f84..cae9c813c1797 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -173,6 +173,36 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "frem_fast" => mir::BinOp::Rem, _ => bug!(), }; + let a_valid = match a.layout.ty.kind() { + ty::Float(FloatTy::F32) => a.to_scalar()?.to_f32()?.is_finite(), + ty::Float(FloatTy::F64) => a.to_scalar()?.to_f64()?.is_finite(), + _ => bug!( + "`{}` called with non-float input type {:?}", + intrinsic_name, + a.layout.ty + ), + }; + if !a_valid { + throw_ub_format!( + "`{}` intrinsic called with non-finite value as first parameter", + intrinsic_name, + ); + } + let b_valid = match b.layout.ty.kind() { + ty::Float(FloatTy::F32) => b.to_scalar()?.to_f32()?.is_finite(), + ty::Float(FloatTy::F64) => b.to_scalar()?.to_f64()?.is_finite(), + _ => bug!( + "`{}` called with non-float input type {:?}", + intrinsic_name, + b.layout.ty + ), + }; + if !b_valid { + throw_ub_format!( + "`{}` intrinsic called with non-finite value as second parameter", + intrinsic_name, + ); + } this.binop_ignore_overflow(op, &a, &b, dest)?; } diff --git a/tests/compile-fail/fast_math_both.rs b/tests/compile-fail/fast_math_both.rs new file mode 100644 index 0000000000000..470ebe620050f --- /dev/null +++ b/tests/compile-fail/fast_math_both.rs @@ -0,0 +1,7 @@ +#![feature(core_intrinsics)] + +fn main() { + unsafe { + let _x: f32 = core::intrinsics::frem_fast(f32::NAN, 3.2); //~ ERROR `frem_fast` intrinsic called with non-finite value as first parameter + } +} diff --git a/tests/compile-fail/fast_math_first.rs b/tests/compile-fail/fast_math_first.rs new file mode 100644 index 0000000000000..184476a474171 --- /dev/null +++ b/tests/compile-fail/fast_math_first.rs @@ -0,0 +1,7 @@ +#![feature(core_intrinsics)] + +fn main() { + unsafe { + let _x: f32 = core::intrinsics::fsub_fast(f32::NAN, f32::NAN); //~ ERROR `fsub_fast` intrinsic called with non-finite value as first parameter + } +} diff --git a/tests/compile-fail/fast_math_second.rs b/tests/compile-fail/fast_math_second.rs new file mode 100644 index 0000000000000..114197d757932 --- /dev/null +++ b/tests/compile-fail/fast_math_second.rs @@ -0,0 +1,7 @@ +#![feature(core_intrinsics)] + +fn main() { + unsafe { + let _x: f32 = core::intrinsics::fmul_fast(3.4f32, f32::NAN); //~ ERROR `fmul_fast` intrinsic called with non-finite value as second parameter + } +} From aac6e2ad3e800153b6552d639e291b2b232881f4 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 3 May 2021 09:57:13 +0200 Subject: [PATCH 2638/3747] fix checking os_family --- rust-version | 2 +- src/helpers.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/rust-version b/rust-version index 1f61617e119f4..464ab46b924f3 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -bcd696d722c04a0f8c34d884aa4ed2322f55cdd8 +59f551a2dcf57c0d3d96ac5ef60e000524210469 diff --git a/src/helpers.rs b/src/helpers.rs index 7fe0ae0a97c4c..8a7657745b645 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -443,7 +443,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); let target = &this.tcx.sess.target; let target_os = &target.os; - let last_error = if target.os_family == Some("unix".to_owned()) { + let last_error = if target.families.contains(&"unix".to_owned()) { this.eval_libc(match e.kind() { ConnectionRefused => "ECONNREFUSED", ConnectionReset => "ECONNRESET", @@ -463,7 +463,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx throw_unsup_format!("io error {} cannot be transformed into a raw os error", e) } })? - } else if target_os == "windows" { + } else if target.families.contains(&"windows".to_owned()) { // FIXME: we have to finish implementing the Windows equivalent of this. this.eval_windows("c", match e.kind() { NotFound => "ERROR_FILE_NOT_FOUND", From c3ae8a6f90830fe01a2bdd43cbc5ea7161893e64 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 3 May 2021 11:25:05 +0200 Subject: [PATCH 2639/3747] adjust for different 'yield' hint on aarch64 --- src/shims/foreign_items.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 373d5299618d5..75a7505e73de5 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -512,16 +512,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let &[] = check_arg_count(args)?; this.yield_active_thread(); } - "llvm.aarch64.hint" if this.tcx.sess.target.arch == "aarch64" => { + "llvm.aarch64.isb" if this.tcx.sess.target.arch == "aarch64" => { check_abi(abi, Abi::C { unwind: false })?; - let &[ref hint] = check_arg_count(args)?; - let hint = this.read_scalar(hint)?.to_i32()?; - match hint { - 1 => { // HINT_YIELD + let &[ref arg] = check_arg_count(args)?; + let arg = this.read_scalar(arg)?.to_i32()?; + match arg { + 15 => { // SY ("full system scope") this.yield_active_thread(); } _ => { - throw_unsup_format!("unsupported llvm.aarch64.hint argument {}", hint); + throw_unsup_format!("unsupported llvm.aarch64.isb argument {}", arg); } } } From 68d29554a8bf100d1a6c95eefb4cd258b4fd1605 Mon Sep 17 00:00:00 2001 From: Smitty Date: Mon, 3 May 2021 09:56:51 -0400 Subject: [PATCH 2640/3747] test for infinite value in f*_fast --- tests/compile-fail/fast_math_second.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/compile-fail/fast_math_second.rs b/tests/compile-fail/fast_math_second.rs index 114197d757932..e8d70a4a79e7a 100644 --- a/tests/compile-fail/fast_math_second.rs +++ b/tests/compile-fail/fast_math_second.rs @@ -2,6 +2,6 @@ fn main() { unsafe { - let _x: f32 = core::intrinsics::fmul_fast(3.4f32, f32::NAN); //~ ERROR `fmul_fast` intrinsic called with non-finite value as second parameter + let _x: f32 = core::intrinsics::fmul_fast(3.4f32, f32::INFINITY); //~ ERROR `fmul_fast` intrinsic called with non-finite value as second parameter } } From e0e59f60205f08486225d0703e666c5cf896fd21 Mon Sep 17 00:00:00 2001 From: Smitty Date: Mon, 3 May 2021 10:08:42 -0400 Subject: [PATCH 2641/3747] Simplify finiteness checking --- src/shims/intrinsics.rs | 40 ++++++++++++--------------- tests/compile-fail/fast_math_both.rs | 2 +- tests/compile-fail/fast_math_first.rs | 2 +- 3 files changed, 20 insertions(+), 24 deletions(-) diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index cae9c813c1797..b33b9666f7129 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -173,35 +173,31 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "frem_fast" => mir::BinOp::Rem, _ => bug!(), }; - let a_valid = match a.layout.ty.kind() { - ty::Float(FloatTy::F32) => a.to_scalar()?.to_f32()?.is_finite(), - ty::Float(FloatTy::F64) => a.to_scalar()?.to_f64()?.is_finite(), - _ => bug!( - "`{}` called with non-float input type {:?}", + let float_finite = |x: ImmTy<'tcx, _>| -> InterpResult<'tcx, bool> { + Ok(match x.layout.ty.kind() { + ty::Float(FloatTy::F32) => x.to_scalar()?.to_f32()?.is_finite(), + ty::Float(FloatTy::F64) => x.to_scalar()?.to_f64()?.is_finite(), + _ => bug!( + "`{}` called with non-float input type {:?}", + intrinsic_name, + x.layout.ty + ), + }) + }; + match (float_finite(a)?, float_finite(b)?) { + (false, false) => throw_ub_format!( + "`{}` intrinsic called with non-finite value as both parameters", intrinsic_name, - a.layout.ty ), - }; - if !a_valid { - throw_ub_format!( + (false, _) => throw_ub_format!( "`{}` intrinsic called with non-finite value as first parameter", intrinsic_name, - ); - } - let b_valid = match b.layout.ty.kind() { - ty::Float(FloatTy::F32) => b.to_scalar()?.to_f32()?.is_finite(), - ty::Float(FloatTy::F64) => b.to_scalar()?.to_f64()?.is_finite(), - _ => bug!( - "`{}` called with non-float input type {:?}", - intrinsic_name, - b.layout.ty ), - }; - if !b_valid { - throw_ub_format!( + (_, false) => throw_ub_format!( "`{}` intrinsic called with non-finite value as second parameter", intrinsic_name, - ); + ), + _ => {} } this.binop_ignore_overflow(op, &a, &b, dest)?; } diff --git a/tests/compile-fail/fast_math_both.rs b/tests/compile-fail/fast_math_both.rs index 470ebe620050f..844e4e95211f9 100644 --- a/tests/compile-fail/fast_math_both.rs +++ b/tests/compile-fail/fast_math_both.rs @@ -2,6 +2,6 @@ fn main() { unsafe { - let _x: f32 = core::intrinsics::frem_fast(f32::NAN, 3.2); //~ ERROR `frem_fast` intrinsic called with non-finite value as first parameter + let _x: f32 = core::intrinsics::fsub_fast(f32::NAN, f32::NAN); //~ ERROR `fsub_fast` intrinsic called with non-finite value as both parameters } } diff --git a/tests/compile-fail/fast_math_first.rs b/tests/compile-fail/fast_math_first.rs index 184476a474171..470ebe620050f 100644 --- a/tests/compile-fail/fast_math_first.rs +++ b/tests/compile-fail/fast_math_first.rs @@ -2,6 +2,6 @@ fn main() { unsafe { - let _x: f32 = core::intrinsics::fsub_fast(f32::NAN, f32::NAN); //~ ERROR `fsub_fast` intrinsic called with non-finite value as first parameter + let _x: f32 = core::intrinsics::frem_fast(f32::NAN, 3.2); //~ ERROR `frem_fast` intrinsic called with non-finite value as first parameter } } From 67ec0a5ce371e997a4bd18b026e7e6a17f9770c8 Mon Sep 17 00:00:00 2001 From: Diana <5275194+DianaNites@users.noreply.github.com> Date: Mon, 3 May 2021 22:52:09 -0400 Subject: [PATCH 2642/3747] Fix dead self-link --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index e0fbd9fafbb29..547e2e15dadc4 100644 --- a/README.md +++ b/README.md @@ -164,7 +164,7 @@ doesn't expose any environment to the program, so running `RUST_BACKTRACE=1 cargo miri test` will not do what you expect. To get a backtrace, you need to disable isolation -[using `-Zmiri-disable-isolation`](#miri-flags): +[using `-Zmiri-disable-isolation`][miri-flags]: ```sh RUST_BACKTRACE=1 MIRIFLAGS="-Zmiri-disable-isolation" cargo miri test From 47c5b6eb087f4ff88d350da8e5901346e816e0ab Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Tue, 4 May 2021 15:53:19 +0800 Subject: [PATCH 2643/3747] `encountered a NULL reference` -> `encountered a null reference` --- rust-version | 2 +- tests/compile-fail/validity/cast_fn_ptr1.rs | 2 +- tests/compile-fail/validity/cast_fn_ptr2.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/rust-version b/rust-version index 464ab46b924f3..a6374bf120c9e 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -59f551a2dcf57c0d3d96ac5ef60e000524210469 +0309953232d9957aef4c7c5a24fcb30735b2066b diff --git a/tests/compile-fail/validity/cast_fn_ptr1.rs b/tests/compile-fail/validity/cast_fn_ptr1.rs index eb94ba256beb1..d755c163bba0e 100644 --- a/tests/compile-fail/validity/cast_fn_ptr1.rs +++ b/tests/compile-fail/validity/cast_fn_ptr1.rs @@ -7,5 +7,5 @@ fn main() { let g: fn(*const i32) = unsafe { std::mem::transmute(f as fn(&i32)) }; g(0usize as *const i32) - //~^ ERROR encountered a NULL reference + //~^ ERROR encountered a null reference } diff --git a/tests/compile-fail/validity/cast_fn_ptr2.rs b/tests/compile-fail/validity/cast_fn_ptr2.rs index a3faa84f1de0c..d78d56b5b6d6a 100644 --- a/tests/compile-fail/validity/cast_fn_ptr2.rs +++ b/tests/compile-fail/validity/cast_fn_ptr2.rs @@ -7,5 +7,5 @@ fn main() { let g: fn() -> &'static i32 = unsafe { std::mem::transmute(f as fn() -> *const i32) }; let _x = g(); - //~^ ERROR encountered a NULL reference + //~^ ERROR encountered a null reference } From a2b227f95aca2897c983df327932d0fbdf3c13c1 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 7 May 2021 09:24:33 +0200 Subject: [PATCH 2644/3747] stacked borrows: ensure array-to-elem casts behave correctly --- rust-version | 2 +- tests/run-pass/stacked-borrows/stacked-borrows.rs | 12 ++++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/rust-version b/rust-version index a6374bf120c9e..74b2e148f8399 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -0309953232d9957aef4c7c5a24fcb30735b2066b +1773f14a24c49356b384e45ebb45643bc9bef2c4 diff --git a/tests/run-pass/stacked-borrows/stacked-borrows.rs b/tests/run-pass/stacked-borrows/stacked-borrows.rs index f76d4e64c6c9a..0401a6640fd33 100644 --- a/tests/run-pass/stacked-borrows/stacked-borrows.rs +++ b/tests/run-pass/stacked-borrows/stacked-borrows.rs @@ -15,6 +15,7 @@ fn main() { shr_and_raw(); disjoint_mutable_subborrows(); raw_ref_to_part(); + array_casts(); } // Make sure that reading from an `&mut` does, like reborrowing to `&`, @@ -174,3 +175,14 @@ fn raw_ref_to_part() { assert!(typed.extra == 42); drop(unsafe { Box::from_raw(whole) }); } + +/// When casting an array reference to a raw element ptr, that should cover the whole array. +fn array_casts() { + let mut x: [usize; 2] = [0, 0]; + let p = &mut x as *mut usize; + unsafe { *p.add(1) = 1; } + + let x: [usize; 2] = [0, 1]; + let p = &x as *const usize; + assert_eq!(unsafe { *p.add(1) }, 1); +} From 1ab9fd50a4bbf6e8f7a3bf00579804aa5a6c4b38 Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Sat, 8 May 2021 15:33:27 +0800 Subject: [PATCH 2645/3747] Update pointer error messages --- rust-version | 2 +- tests/compile-fail/backtrace/bad-backtrace-ptr.rs | 2 +- tests/compile-fail/dangling_pointers/deref-invalid-ptr.rs | 2 +- tests/compile-fail/dangling_pointers/wild_pointer_deref.rs | 2 +- tests/compile-fail/function_pointers/cast_int_to_fn_ptr.rs | 2 +- tests/compile-fail/intrinsics/ptr_offset_0_plus_0.rs | 2 +- tests/compile-fail/intrinsics/ptr_offset_int_plus_int.rs | 2 +- tests/compile-fail/intrinsics/ptr_offset_int_plus_ptr.rs | 2 +- tests/compile-fail/null_pointer_deref.rs | 2 +- tests/compile-fail/null_pointer_write.rs | 2 +- tests/compile-fail/stacked_borrows/issue-miri-1050-2.rs | 2 +- 11 files changed, 11 insertions(+), 11 deletions(-) diff --git a/rust-version b/rust-version index 74b2e148f8399..e679a6c32287d 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -1773f14a24c49356b384e45ebb45643bc9bef2c4 +e002ac7e8a1eb04961a722c44b3ffbad575a6caa diff --git a/tests/compile-fail/backtrace/bad-backtrace-ptr.rs b/tests/compile-fail/backtrace/bad-backtrace-ptr.rs index 0c49a527bc161..c83bf1eb382e8 100644 --- a/tests/compile-fail/backtrace/bad-backtrace-ptr.rs +++ b/tests/compile-fail/backtrace/bad-backtrace-ptr.rs @@ -4,6 +4,6 @@ extern "Rust" { fn main() { unsafe { - miri_resolve_frame(0 as *mut _, 0); //~ ERROR 0x0 is not a valid pointer + miri_resolve_frame(0 as *mut _, 0); //~ ERROR null pointer is not a valid pointer for this operation } } diff --git a/tests/compile-fail/dangling_pointers/deref-invalid-ptr.rs b/tests/compile-fail/dangling_pointers/deref-invalid-ptr.rs index 6aa93e714721a..87071d8b4591d 100644 --- a/tests/compile-fail/dangling_pointers/deref-invalid-ptr.rs +++ b/tests/compile-fail/dangling_pointers/deref-invalid-ptr.rs @@ -3,5 +3,5 @@ fn main() { let x = 16usize as *const u32; - let _y = unsafe { &*x as *const u32 }; //~ ERROR inbounds test failed: 0x10 is not a valid pointer + let _y = unsafe { &*x as *const u32 }; //~ ERROR 0x10 is not a valid pointer } diff --git a/tests/compile-fail/dangling_pointers/wild_pointer_deref.rs b/tests/compile-fail/dangling_pointers/wild_pointer_deref.rs index 371e72d2822d0..2749ccfc0a021 100644 --- a/tests/compile-fail/dangling_pointers/wild_pointer_deref.rs +++ b/tests/compile-fail/dangling_pointers/wild_pointer_deref.rs @@ -1,5 +1,5 @@ fn main() { let p = 44 as *const i32; - let x = unsafe { *p }; //~ ERROR inbounds test failed: 0x2c is not a valid pointer + let x = unsafe { *p }; //~ ERROR 0x2c is not a valid pointer panic!("this should never print: {}", x); } diff --git a/tests/compile-fail/function_pointers/cast_int_to_fn_ptr.rs b/tests/compile-fail/function_pointers/cast_int_to_fn_ptr.rs index 94ff3327123b4..299fd5ae49e03 100644 --- a/tests/compile-fail/function_pointers/cast_int_to_fn_ptr.rs +++ b/tests/compile-fail/function_pointers/cast_int_to_fn_ptr.rs @@ -6,5 +6,5 @@ fn main() { std::mem::transmute::(42) }; - g(42) //~ ERROR inbounds test failed: 0x2a is not a valid pointer + g(42) //~ ERROR 0x2a is not a valid pointer } diff --git a/tests/compile-fail/intrinsics/ptr_offset_0_plus_0.rs b/tests/compile-fail/intrinsics/ptr_offset_0_plus_0.rs index d6cf3d65f296d..d8a8f66e7aeed 100644 --- a/tests/compile-fail/intrinsics/ptr_offset_0_plus_0.rs +++ b/tests/compile-fail/intrinsics/ptr_offset_0_plus_0.rs @@ -1,4 +1,4 @@ -// error-pattern: inbounds test failed: 0x0 is not a valid pointer +// error-pattern: pointer arithmetic failed: 0x0 is not a valid pointer fn main() { let x = 0 as *mut i32; diff --git a/tests/compile-fail/intrinsics/ptr_offset_int_plus_int.rs b/tests/compile-fail/intrinsics/ptr_offset_int_plus_int.rs index 4bee2fec6b7b0..ea6bef151e1c1 100644 --- a/tests/compile-fail/intrinsics/ptr_offset_int_plus_int.rs +++ b/tests/compile-fail/intrinsics/ptr_offset_int_plus_int.rs @@ -1,4 +1,4 @@ -// error-pattern: inbounds test failed: 0x1 is not a valid pointer +// error-pattern: 0x1 is not a valid pointer fn main() { // Can't offset an integer pointer by non-zero offset. diff --git a/tests/compile-fail/intrinsics/ptr_offset_int_plus_ptr.rs b/tests/compile-fail/intrinsics/ptr_offset_int_plus_ptr.rs index 892dbca1128fc..8ff5c3596ef63 100644 --- a/tests/compile-fail/intrinsics/ptr_offset_int_plus_ptr.rs +++ b/tests/compile-fail/intrinsics/ptr_offset_int_plus_ptr.rs @@ -1,4 +1,4 @@ -// error-pattern: inbounds test failed: 0x1 is not a valid pointer +// error-pattern: 0x1 is not a valid pointer fn main() { let ptr = Box::into_raw(Box::new(0u32)); diff --git a/tests/compile-fail/null_pointer_deref.rs b/tests/compile-fail/null_pointer_deref.rs index ab415d8746d18..076b2df609abd 100644 --- a/tests/compile-fail/null_pointer_deref.rs +++ b/tests/compile-fail/null_pointer_deref.rs @@ -1,5 +1,5 @@ #[allow(deref_nullptr)] fn main() { - let x: i32 = unsafe { *std::ptr::null() }; //~ ERROR inbounds test failed: 0x0 is not a valid pointer + let x: i32 = unsafe { *std::ptr::null() }; //~ ERROR null pointer is not a valid pointer for this operation panic!("this should never print: {}", x); } diff --git a/tests/compile-fail/null_pointer_write.rs b/tests/compile-fail/null_pointer_write.rs index 599d2ff7fd5b1..5294e60c025fb 100644 --- a/tests/compile-fail/null_pointer_write.rs +++ b/tests/compile-fail/null_pointer_write.rs @@ -1,4 +1,4 @@ #[allow(deref_nullptr)] fn main() { - unsafe { *std::ptr::null_mut() = 0i32 }; //~ ERROR inbounds test failed: 0x0 is not a valid pointer + unsafe { *std::ptr::null_mut() = 0i32 }; //~ ERROR null pointer is not a valid pointer for this operation } diff --git a/tests/compile-fail/stacked_borrows/issue-miri-1050-2.rs b/tests/compile-fail/stacked_borrows/issue-miri-1050-2.rs index c40d8de21dd7f..30cbf0b339a1d 100644 --- a/tests/compile-fail/stacked_borrows/issue-miri-1050-2.rs +++ b/tests/compile-fail/stacked_borrows/issue-miri-1050-2.rs @@ -1,4 +1,4 @@ -// error-pattern: inbounds test failed: 0x4 is not a valid pointer +// error-pattern: 0x4 is not a valid pointer use std::ptr::NonNull; fn main() { unsafe { From 7af7e9e4f3526eefedb0d7456b519b5f8d36c2f6 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 11 May 2021 15:32:05 +0200 Subject: [PATCH 2646/3747] rustup --- rust-version | 2 +- tests/run-pass/calls.rs | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/rust-version b/rust-version index e679a6c32287d..f543240677e51 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -e002ac7e8a1eb04961a722c44b3ffbad575a6caa +506e75cbf8cb5305e49a41326307004ca3976029 diff --git a/tests/run-pass/calls.rs b/tests/run-pass/calls.rs index c4ba4a9b701ff..4cbd7ada69e6f 100644 --- a/tests/run-pass/calls.rs +++ b/tests/run-pass/calls.rs @@ -1,5 +1,3 @@ -#![feature(const_fn)] - fn call() -> i32 { fn increment(x: i32) -> i32 { x + 1 From 0d2278c6c6c215f0268c15946cb89a3fe9284fd3 Mon Sep 17 00:00:00 2001 From: Andy Wang Date: Wed, 12 May 2021 14:38:50 +0100 Subject: [PATCH 2647/3747] Prefer remapped filename in backtrace to match rustc behaviour --- src/shims/backtrace.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shims/backtrace.rs b/src/shims/backtrace.rs index 159a0bc1f8cdf..224d8182b1591 100644 --- a/src/shims/backtrace.rs +++ b/src/shims/backtrace.rs @@ -108,7 +108,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let lo = tcx.sess.source_map().lookup_char_pos(pos); - let filename = lo.file.name.to_string(); + let filename = lo.file.name.prefer_remapped().to_string(); let lineno: u32 = lo.line as u32; // `lo.col` is 0-based - add 1 to make it 1-based for the caller. let colno: u32 = lo.col.0 as u32 + 1; From 5b88045bfa18dcfa17c9f4a4de2c1c7ad4b3ced9 Mon Sep 17 00:00:00 2001 From: Andy Wang Date: Wed, 12 May 2021 14:45:12 +0100 Subject: [PATCH 2648/3747] Update rust commit sha --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index f543240677e51..645e69c5163b3 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -506e75cbf8cb5305e49a41326307004ca3976029 +e1ff91f439bc09f566da211c6449821b4e949279 \ No newline at end of file From 64f128c45687d18d64fc6856a30fde585b007e00 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 15 May 2021 14:17:30 +0200 Subject: [PATCH 2649/3747] support building Miri outside a git repo --- cargo-miri/bin.rs | 14 ++++++++------ cargo-miri/build.rs | 2 +- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index e29bdc7717191..84447b3a1a204 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -6,6 +6,7 @@ use std::io::{self, BufRead, BufReader, BufWriter, Read, Write}; use std::ops::Not; use std::path::{Path, PathBuf}; use std::process::Command; +use std::fmt::{Write as _}; use serde::{Deserialize, Serialize}; @@ -90,12 +91,13 @@ fn show_help() { } fn show_version() { - println!( - "miri {} ({} {})", - env!("CARGO_PKG_VERSION"), - env!("VERGEN_GIT_SHA_SHORT"), - env!("VERGEN_GIT_COMMIT_DATE") - ); + let mut version = format!("miri {}", env!("CARGO_PKG_VERSION")); + // Only use `option_env` on vergen variables to ensure the build succeeds + // when vergen failed to find the git info. + if let Some(sha) = option_env!("VERGEN_GIT_SHA_SHORT") { + write!(&mut version, " ({} {})", sha, option_env!("VERGEN_GIT_COMMIT_DATE").unwrap()).unwrap(); + } + println!("{}", version); } fn show_error(msg: String) -> ! { diff --git a/cargo-miri/build.rs b/cargo-miri/build.rs index cff135fe49c04..ebd8e7003d5f7 100644 --- a/cargo-miri/build.rs +++ b/cargo-miri/build.rs @@ -7,5 +7,5 @@ fn main() { let mut gen_config = vergen::Config::default(); *gen_config.git_mut().sha_kind_mut() = vergen::ShaKind::Short; *gen_config.git_mut().commit_timestamp_kind_mut() = vergen::TimestampKind::DateOnly; - vergen(gen_config).expect("Unable to generate vergen keys!"); + vergen(gen_config).ok(); // Ignore failure (in case we are built outside a git repo) } From e824321aa4ecb973f93539c187c7e63b73230aa8 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 15 May 2021 15:14:19 +0200 Subject: [PATCH 2650/3747] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 645e69c5163b3..0495fc97f7f7e 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -e1ff91f439bc09f566da211c6449821b4e949279 \ No newline at end of file +c6dd87a6b4a62cf5d2cb6207b1dcea652ea1aa60 From 7b3566096c1013ac5e011b47d09298db8c838913 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 16 May 2021 11:10:27 +0200 Subject: [PATCH 2651/3747] configure rustfmt; fmt cargo-miri --- cargo-miri/bin.rs | 82 +++++++++++++++++++++++++++++------------------ rustfmt.toml | 3 +- 2 files changed, 53 insertions(+), 32 deletions(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index 84447b3a1a204..295acd6638a2a 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -1,12 +1,12 @@ use std::env; use std::ffi::OsString; +use std::fmt::Write as _; use std::fs::{self, File}; -use std::iter::TakeWhile; use std::io::{self, BufRead, BufReader, BufWriter, Read, Write}; +use std::iter::TakeWhile; use std::ops::Not; use std::path::{Path, PathBuf}; use std::process::Command; -use std::fmt::{Write as _}; use serde::{Deserialize, Serialize}; @@ -95,7 +95,8 @@ fn show_version() { // Only use `option_env` on vergen variables to ensure the build succeeds // when vergen failed to find the git info. if let Some(sha) = option_env!("VERGEN_GIT_SHA_SHORT") { - write!(&mut version, " ({} {})", sha, option_env!("VERGEN_GIT_COMMIT_DATE").unwrap()).unwrap(); + write!(&mut version, " ({} {})", sha, option_env!("VERGEN_GIT_COMMIT_DATE").unwrap()) + .unwrap(); } println!("{}", version); } @@ -168,8 +169,7 @@ fn forward_patched_extern_arg(args: &mut impl Iterator, cmd: &mut } fn forward_miri_sysroot(cmd: &mut Command) { - let sysroot = - env::var_os("MIRI_SYSROOT").expect("the wrapper should have set MIRI_SYSROOT"); + let sysroot = env::var_os("MIRI_SYSROOT").expect("the wrapper should have set MIRI_SYSROOT"); cmd.arg("--sysroot"); cmd.arg(sysroot); } @@ -471,7 +471,9 @@ fn phase_cargo_miri(mut args: env::Args) { Some("run") => MiriCommand::Run, Some("setup") => MiriCommand::Setup, // Invalid command. - _ => show_error(format!("`cargo miri` supports the following subcommands: `run`, `test`, and `setup`.")), + _ => show_error(format!( + "`cargo miri` supports the following subcommands: `run`, `test`, and `setup`." + )), }; let verbose = has_arg_flag("-v"); @@ -515,13 +517,14 @@ fn phase_cargo_miri(mut args: env::Args) { // i.e., the first argument is `rustc` -- which is what we use in `main` to distinguish // the two codepaths. (That extra argument is why we prefer this over setting `RUSTC`.) if env::var_os("RUSTC_WRAPPER").is_some() { - println!("WARNING: Ignoring `RUSTC_WRAPPER` environment variable, Miri does not support wrapping."); + println!( + "WARNING: Ignoring `RUSTC_WRAPPER` environment variable, Miri does not support wrapping." + ); } cmd.env("RUSTC_WRAPPER", &cargo_miri_path); - let runner_env_name = |triple: &str| { - format!("CARGO_TARGET_{}_RUNNER", triple.to_uppercase().replace('-', "_")) - }; + let runner_env_name = + |triple: &str| format!("CARGO_TARGET_{}_RUNNER", triple.to_uppercase().replace('-', "_")); let host_runner_env_name = runner_env_name(&host); let target_runner_env_name = runner_env_name(target); // Set the target runner to us, so we can interpret the binaries. @@ -628,7 +631,10 @@ fn phase_rustc(mut args: env::Args, phase: RustcPhase) { let runnable_crate = !print && is_runnable_crate(); if runnable_crate && target_crate { - assert!(phase != RustcPhase::Setup, "there should be no interpretation during sysroot build"); + assert!( + phase != RustcPhase::Setup, + "there should be no interpretation during sysroot build" + ); let inside_rustdoc = phase == RustcPhase::Rustdoc; // This is the binary or test crate that we want to interpret under Miri. // But we cannot run it here, as cargo invoked us as a compiler -- our stdin and stdout are not @@ -657,7 +663,10 @@ fn phase_rustc(mut args: env::Args, phase: RustcPhase) { cmd.env("MIRI_BE_RUSTC", "target"); if verbose { - eprintln!("[cargo-miri rustc] captured input:\n{}", std::str::from_utf8(&env.stdin).unwrap()); + eprintln!( + "[cargo-miri rustc] captured input:\n{}", + std::str::from_utf8(&env.stdin).unwrap() + ); eprintln!("[cargo-miri rustc] {:?}", cmd); } @@ -715,7 +724,9 @@ fn phase_rustc(mut args: env::Args, phase: RustcPhase) { } // During setup, patch the panic runtime for `libpanic_abort` (mirroring what bootstrap usually does). - if phase == RustcPhase::Setup && get_arg_flag_value("--crate-name").as_deref() == Some("panic_abort") { + if phase == RustcPhase::Setup + && get_arg_flag_value("--crate-name").as_deref() == Some("panic_abort") + { cmd.arg("-C").arg("panic=abort"); } } else { @@ -765,12 +776,18 @@ fn phase_runner(binary: &Path, binary_args: env::Args, phase: RunnerPhase) { .unwrap_or_else(|_| show_error(format!("file {:?} not found or `cargo-miri` invoked incorrectly; please only invoke this binary through `cargo miri`", binary))); let file = BufReader::new(file); - let info = serde_json::from_reader(file) - .unwrap_or_else(|_| show_error(format!("file {:?} contains outdated or invalid JSON; try `cargo clean`", binary))); + let info = serde_json::from_reader(file).unwrap_or_else(|_| { + show_error(format!( + "file {:?} contains outdated or invalid JSON; try `cargo clean`", + binary + )) + }); let info = match info { CrateRunInfo::RunWith(info) => info, CrateRunInfo::SkipProcMacroTest => { - eprintln!("Running unit tests of `proc-macro` crates is not currently supported by Miri."); + eprintln!( + "Running unit tests of `proc-macro` crates is not currently supported by Miri." + ); return; } }; @@ -783,7 +800,10 @@ fn phase_runner(binary: &Path, binary_args: env::Args, phase: RunnerPhase) { if verbose { if let Some(old_val) = env::var_os(&name) { if old_val != val { - eprintln!("[cargo-miri runner] Overwriting run-time env var {:?}={:?} with build-time value {:?}", name, old_val, val); + eprintln!( + "[cargo-miri runner] Overwriting run-time env var {:?}={:?} with build-time value {:?}", + name, old_val, val + ); } } } @@ -822,11 +842,7 @@ fn phase_runner(binary: &Path, binary_args: env::Args, phase: RunnerPhase) { // Respect `MIRIFLAGS`. if let Ok(a) = env::var("MIRIFLAGS") { // This code is taken from `RUSTFLAGS` handling in cargo. - let args = a - .split(' ') - .map(str::trim) - .filter(|s| !s.is_empty()) - .map(str::to_string); + let args = a.split(' ').map(str::trim).filter(|s| !s.is_empty()).map(str::to_string); cmd.args(args); } @@ -845,12 +861,8 @@ fn phase_runner(binary: &Path, binary_args: env::Args, phase: RunnerPhase) { } match phase { - RunnerPhase::Rustdoc => { - exec_with_pipe(cmd, &info.stdin) - } - RunnerPhase::Cargo => { - exec(cmd) - } + RunnerPhase::Rustdoc => exec_with_pipe(cmd, &info.stdin), + RunnerPhase::Cargo => exec(cmd), } } @@ -946,7 +958,10 @@ fn main() { if binary.exists() { phase_runner(binary, args, RunnerPhase::Rustdoc); } else { - show_error(format!("`cargo-miri` called with non-existing path argument `{}` in rustdoc mode; please invoke this binary through `cargo miri`", arg)); + show_error(format!( + "`cargo-miri` called with non-existing path argument `{}` in rustdoc mode; please invoke this binary through `cargo miri`", + arg + )); } } else { phase_rustc(args, RustcPhase::Rustdoc); @@ -977,9 +992,14 @@ fn main() { } else if arg.starts_with("--") { phase_rustdoc(arg, args); } else { - show_error(format!("`cargo-miri` called with unexpected first argument `{}`; please only invoke this binary through `cargo miri`", arg)); + show_error(format!( + "`cargo-miri` called with unexpected first argument `{}`; please only invoke this binary through `cargo miri`", + arg + )); } } - _ => show_error(format!("`cargo-miri` called without first argument; please only invoke this binary through `cargo miri`")), + _ => show_error(format!( + "`cargo-miri` called without first argument; please only invoke this binary through `cargo miri`" + )), } } diff --git a/rustfmt.toml b/rustfmt.toml index a0d494b335a88..373caafd106b1 100644 --- a/rustfmt.toml +++ b/rustfmt.toml @@ -1,3 +1,4 @@ -use_small_heuristics = "Max" version = "Two" +use_small_heuristics = "Max" match_arm_blocks = false +match_arm_leading_pipes = "Preserve" From 4e231bab5ef620073c3c29b9b1f507f4a8f8c448 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 16 May 2021 11:28:01 +0200 Subject: [PATCH 2652/3747] format much of Miri --- benches/helpers/miri_helper.rs | 2 +- src/bin/miri.rs | 76 ++++--- src/eval.rs | 14 +- src/helpers.rs | 79 ++++--- src/intptrcast.rs | 2 +- src/lib.rs | 22 +- src/machine.rs | 56 ++--- src/range_map.rs | 13 +- src/shims/backtrace.rs | 56 +++-- src/shims/dlsym.rs | 3 +- src/shims/env.rs | 105 ++++++--- src/shims/foreign_items.rs | 14 +- src/shims/mod.rs | 4 +- src/shims/os_str.rs | 14 +- src/shims/panic.rs | 21 +- src/shims/posix/fs.rs | 297 ++++++++++++++++--------- src/shims/posix/linux/dlsym.rs | 5 +- src/shims/posix/linux/foreign_items.rs | 40 ++-- src/shims/posix/linux/mod.rs | 2 +- src/shims/posix/linux/sync.rs | 31 ++- src/shims/posix/macos/foreign_items.rs | 3 +- src/shims/posix/macos/mod.rs | 2 +- src/shims/posix/mod.rs | 2 +- src/shims/posix/sync.rs | 49 ++-- src/shims/posix/thread.rs | 9 +- src/shims/time.rs | 40 +++- src/shims/tls.rs | 48 ++-- src/shims/windows/dlsym.rs | 3 +- src/shims/windows/foreign_items.rs | 58 +++-- src/shims/windows/mod.rs | 2 +- src/shims/windows/sync.rs | 38 +--- src/stacked_borrows.rs | 58 +++-- src/sync.rs | 47 ++-- src/thread.rs | 44 ++-- src/vector_clock.rs | 7 +- 35 files changed, 752 insertions(+), 514 deletions(-) diff --git a/benches/helpers/miri_helper.rs b/benches/helpers/miri_helper.rs index 8397fde946c56..7642018c08cbc 100644 --- a/benches/helpers/miri_helper.rs +++ b/benches/helpers/miri_helper.rs @@ -2,8 +2,8 @@ extern crate rustc_driver; extern crate rustc_hir; extern crate rustc_interface; -use rustc_hir::def_id::LOCAL_CRATE; use rustc_driver::Compilation; +use rustc_hir::def_id::LOCAL_CRATE; use rustc_interface::{interface, Queries}; use crate::test::Bencher; diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 41776090be443..0e9a6ffe80502 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -1,11 +1,11 @@ #![feature(rustc_private)] -extern crate rustc_middle; extern crate rustc_driver; +extern crate rustc_errors; extern crate rustc_hir; extern crate rustc_interface; +extern crate rustc_middle; extern crate rustc_session; -extern crate rustc_errors; use std::convert::TryFrom; use std::env; @@ -14,11 +14,11 @@ use std::str::FromStr; use hex::FromHexError; use log::debug; -use rustc_session::{CtfeBacktrace, config::ErrorOutputType}; -use rustc_errors::emitter::{HumanReadableErrorType, ColorConfig}; use rustc_driver::Compilation; +use rustc_errors::emitter::{ColorConfig, HumanReadableErrorType}; use rustc_hir::def_id::LOCAL_CRATE; use rustc_middle::ty::TyCtxt; +use rustc_session::{config::ErrorOutputType, CtfeBacktrace}; struct MiriCompilerCalls { miri_config: miri::MiriConfig, @@ -37,8 +37,13 @@ impl rustc_driver::Callbacks for MiriCompilerCalls { let (entry_def_id, _) = if let Some((entry_def, x)) = tcx.entry_fn(LOCAL_CRATE) { (entry_def, x) } else { - let output_ty = ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(ColorConfig::Auto)); - rustc_session::early_error(output_ty, "miri can only run programs that have a main function"); + let output_ty = ErrorOutputType::HumanReadable(HumanReadableErrorType::Default( + ColorConfig::Auto, + )); + rustc_session::early_error( + output_ty, + "miri can only run programs that have a main function", + ); }; let mut config = self.miri_config.clone(); @@ -249,10 +254,7 @@ fn main() { err => panic!("unknown error decoding -Zmiri-seed as hex: {:?}", err), }); if seed_raw.len() > 8 { - panic!( - "-Zmiri-seed must be at most 8 bytes, was {}", - seed_raw.len() - ); + panic!("-Zmiri-seed must be at most 8 bytes, was {}", seed_raw.len()); } let mut bytes = [0; 8]; @@ -260,17 +262,19 @@ fn main() { miri_config.seed = Some(u64::from_be_bytes(bytes)); } arg if arg.starts_with("-Zmiri-env-exclude=") => { - miri_config.excluded_env_vars + miri_config + .excluded_env_vars .push(arg.strip_prefix("-Zmiri-env-exclude=").unwrap().to_owned()); } arg if arg.starts_with("-Zmiri-track-pointer-tag=") => { - let id: u64 = match arg.strip_prefix("-Zmiri-track-pointer-tag=").unwrap().parse() { - Ok(id) => id, - Err(err) => panic!( - "-Zmiri-track-pointer-tag requires a valid `u64` argument: {}", - err - ), - }; + let id: u64 = + match arg.strip_prefix("-Zmiri-track-pointer-tag=").unwrap().parse() { + Ok(id) => id, + Err(err) => panic!( + "-Zmiri-track-pointer-tag requires a valid `u64` argument: {}", + err + ), + }; if let Some(id) = miri::PtrId::new(id) { miri_config.tracked_pointer_tag = Some(id); } else { @@ -280,10 +284,8 @@ fn main() { arg if arg.starts_with("-Zmiri-track-call-id=") => { let id: u64 = match arg.strip_prefix("-Zmiri-track-call-id=").unwrap().parse() { Ok(id) => id, - Err(err) => panic!( - "-Zmiri-track-call-id requires a valid `u64` argument: {}", - err - ), + Err(err) => + panic!("-Zmiri-track-call-id requires a valid `u64` argument: {}", err), }; if let Some(id) = miri::CallId::new(id) { miri_config.tracked_call_id = Some(id); @@ -292,20 +294,28 @@ fn main() { } } arg if arg.starts_with("-Zmiri-track-alloc-id=") => { - let id: u64 = match arg.strip_prefix("-Zmiri-track-alloc-id=").unwrap().parse() { + let id: u64 = match arg.strip_prefix("-Zmiri-track-alloc-id=").unwrap().parse() + { Ok(id) => id, - Err(err) => panic!( - "-Zmiri-track-alloc-id requires a valid `u64` argument: {}", - err - ), + Err(err) => + panic!("-Zmiri-track-alloc-id requires a valid `u64` argument: {}", err), }; miri_config.tracked_alloc_id = Some(miri::AllocId(id)); } arg if arg.starts_with("-Zmiri-compare-exchange-weak-failure-rate=") => { - let rate = match arg.strip_prefix("-Zmiri-compare-exchange-weak-failure-rate=").unwrap().parse::() { + let rate = match arg + .strip_prefix("-Zmiri-compare-exchange-weak-failure-rate=") + .unwrap() + .parse::() + { Ok(rate) if rate >= 0.0 && rate <= 1.0 => rate, - Ok(_) => panic!("-Zmiri-compare-exchange-weak-failure-rate must be between `0.0` and `1.0`"), - Err(err) => panic!("-Zmiri-compare-exchange-weak-failure-rate requires a `f64` between `0.0` and `1.0`: {}", err), + Ok(_) => panic!( + "-Zmiri-compare-exchange-weak-failure-rate must be between `0.0` and `1.0`" + ), + Err(err) => panic!( + "-Zmiri-compare-exchange-weak-failure-rate requires a `f64` between `0.0` and `1.0`: {}", + err + ), }; miri_config.cmpxchg_weak_failure_rate = rate; } @@ -319,5 +329,9 @@ fn main() { debug!("rustc arguments: {:?}", rustc_args); debug!("crate arguments: {:?}", miri_config.args); - run_compiler(rustc_args, &mut MiriCompilerCalls { miri_config }, /* insert_default_args: */ true) + run_compiler( + rustc_args, + &mut MiriCompilerCalls { miri_config }, + /* insert_default_args: */ true, + ) } diff --git a/src/eval.rs b/src/eval.rs index bd1aebe00de8f..1e46015f87a82 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -135,8 +135,9 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( argvs.push(arg_place.ptr); } // Make an array with all these pointers, in the Miri memory. - let argvs_layout = - ecx.layout_of(tcx.mk_array(tcx.mk_imm_ptr(tcx.types.u8), u64::try_from(argvs.len()).unwrap()))?; + let argvs_layout = ecx.layout_of( + tcx.mk_array(tcx.mk_imm_ptr(tcx.types.u8), u64::try_from(argvs.len()).unwrap()), + )?; let argvs_place = ecx.allocate(argvs_layout, MiriMemoryKind::Machine.into()); for (idx, arg) in argvs.into_iter().enumerate() { let place = ecx.mplace_field(&argvs_place, idx)?; @@ -224,9 +225,11 @@ pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) -> assert!(ecx.step()?, "a terminated thread was scheduled for execution"); } SchedulingAction::ExecuteTimeoutCallback => { - assert!(ecx.machine.communicate, + assert!( + ecx.machine.communicate, "scheduler callbacks require disabled isolation, but the code \ - that created the callback did not check it"); + that created the callback did not check it" + ); ecx.run_timeout_callback()?; } SchedulingAction::ExecuteDtors => { @@ -241,7 +244,8 @@ pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) -> } ecx.process_diagnostics(info); } - let return_code = ecx.read_scalar(&ret_place.into())?.check_init()?.to_machine_isize(&ecx)?; + let return_code = + ecx.read_scalar(&ret_place.into())?.check_init()?.to_machine_isize(&ecx)?; Ok(return_code) })(); diff --git a/src/helpers.rs b/src/helpers.rs index 8a7657745b645..7215cb4b0c7bd 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -5,10 +5,10 @@ use std::time::Duration; use log::trace; -use rustc_middle::mir; -use rustc_middle::ty::{self, List, TyCtxt, layout::TyAndLayout}; use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX}; -use rustc_target::abi::{LayoutOf, Size, FieldsShape, Variants}; +use rustc_middle::mir; +use rustc_middle::ty::{self, layout::TyAndLayout, List, TyCtxt}; +use rustc_target::abi::{FieldsShape, LayoutOf, Size, Variants}; use rustc_target::spec::abi::Abi; use rand::RngCore; @@ -19,10 +19,8 @@ impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mi /// Gets an instance for a path. fn try_resolve_did<'mir, 'tcx>(tcx: TyCtxt<'tcx>, path: &[&str]) -> Option { - tcx.crates() - .iter() - .find(|&&krate| tcx.original_crate_name(krate).as_str() == path[0]) - .and_then(|krate| { + tcx.crates().iter().find(|&&krate| tcx.original_crate_name(krate).as_str() == path[0]).and_then( + |krate| { let krate = DefId { krate: *krate, index: CRATE_DEF_INDEX }; let mut items = tcx.item_children(krate); let mut path_it = path.iter().skip(1).peekable(); @@ -40,7 +38,8 @@ fn try_resolve_did<'mir, 'tcx>(tcx: TyCtxt<'tcx>, path: &[&str]) -> Option: crate::MiriEvalContextExt<'mir, 'tcx> { @@ -53,10 +52,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// Evaluates the scalar at the specified path. Returns Some(val) /// if the path could be resolved, and None otherwise - fn eval_path_scalar( - &mut self, - path: &[&str], - ) -> InterpResult<'tcx, ScalarMaybeUninit> { + fn eval_path_scalar(&mut self, path: &[&str]) -> InterpResult<'tcx, ScalarMaybeUninit> { let this = self.eval_context_mut(); let instance = this.resolve_path(path); let cid = GlobalId { instance, promoted: None }; @@ -67,9 +63,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// Helper function to get a `libc` constant as a `Scalar`. fn eval_libc(&mut self, name: &str) -> InterpResult<'tcx, Scalar> { - self.eval_context_mut() - .eval_path_scalar(&["libc", name])? - .check_init() + self.eval_context_mut().eval_path_scalar(&["libc", name])?.check_init() } /// Helper function to get a `libc` constant as an `i32`. @@ -101,7 +95,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// Helper function to get the `TyAndLayout` of a `windows` type fn windows_ty_layout(&mut self, name: &str) -> InterpResult<'tcx, TyAndLayout<'tcx>> { let this = self.eval_context_mut(); - let ty = this.resolve_path(&["std", "sys", "windows", "c", name]).ty(*this.tcx, ty::ParamEnv::reveal_all()); + let ty = this + .resolve_path(&["std", "sys", "windows", "c", name]) + .ty(*this.tcx, ty::ParamEnv::reveal_all()); this.layout_of(ty) } @@ -170,7 +166,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let param_env = ty::ParamEnv::reveal_all(); // in Miri this is always the param_env we use... and this.param_env is private. let callee_abi = f.ty(*this.tcx, param_env).fn_sig(*this.tcx).abi(); if callee_abi != caller_abi { - throw_ub_format!("calling a function with ABI {} using caller ABI {}", callee_abi.name(), caller_abi.name()) + throw_ub_format!( + "calling a function with ABI {} using caller ABI {}", + callee_abi.name(), + caller_abi.name() + ) } // Push frame. @@ -181,9 +181,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let mut callee_args = this.frame().body.args_iter(); for arg in args { let callee_arg = this.local_place( - callee_args.next().ok_or_else(|| - err_ub_format!("callee has fewer arguments than expected") - )? + callee_args + .next() + .ok_or_else(|| err_ub_format!("callee has fewer arguments than expected"))?, )?; this.write_immediate(*arg, &callee_arg)?; } @@ -356,7 +356,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } - fn visit_union(&mut self, _v: &MPlaceTy<'tcx, Tag>, _fields: NonZeroUsize) -> InterpResult<'tcx> { + fn visit_union( + &mut self, + _v: &MPlaceTy<'tcx, Tag>, + _fields: NonZeroUsize, + ) -> InterpResult<'tcx> { bug!("we should have already handled unions in `visit_value`") } } @@ -465,12 +469,21 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx })? } else if target.families.contains(&"windows".to_owned()) { // FIXME: we have to finish implementing the Windows equivalent of this. - this.eval_windows("c", match e.kind() { - NotFound => "ERROR_FILE_NOT_FOUND", - _ => throw_unsup_format!("io error {} cannot be transformed into a raw os error", e) - })? + this.eval_windows( + "c", + match e.kind() { + NotFound => "ERROR_FILE_NOT_FOUND", + _ => throw_unsup_format!( + "io error {} cannot be transformed into a raw os error", + e + ), + }, + )? } else { - throw_unsup_format!("setting the last OS error from an io::Error is unsupported for {}.", target_os) + throw_unsup_format!( + "setting the last OS error from an io::Error is unsupported for {}.", + target_os + ) }; this.set_last_error(last_error) } @@ -556,8 +569,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } /// Check that the number of args is what we expect. -pub fn check_arg_count<'a, 'tcx, const N: usize>(args: &'a [OpTy<'tcx, Tag>]) -> InterpResult<'tcx, &'a [OpTy<'tcx, Tag>; N]> - where &'a [OpTy<'tcx, Tag>; N]: TryFrom<&'a [OpTy<'tcx, Tag>]> { +pub fn check_arg_count<'a, 'tcx, const N: usize>( + args: &'a [OpTy<'tcx, Tag>], +) -> InterpResult<'tcx, &'a [OpTy<'tcx, Tag>; N]> +where + &'a [OpTy<'tcx, Tag>; N]: TryFrom<&'a [OpTy<'tcx, Tag>]>, +{ if let Ok(ops) = args.try_into() { return Ok(ops); } @@ -569,7 +586,11 @@ pub fn check_abi<'a>(abi: Abi, exp_abi: Abi) -> InterpResult<'a, ()> { if abi == exp_abi { Ok(()) } else { - throw_ub_format!("calling a function with ABI {} using caller ABI {}", exp_abi.name(), abi.name()) + throw_ub_format!( + "calling a function with ABI {} using caller ABI {}", + exp_abi.name(), + abi.name() + ) } } diff --git a/src/intptrcast.rs b/src/intptrcast.rs index 0e6a9f69aebab..b5a77b08ff52d 100644 --- a/src/intptrcast.rs +++ b/src/intptrcast.rs @@ -6,7 +6,7 @@ use log::trace; use rand::Rng; use rustc_data_structures::fx::FxHashMap; -use rustc_target::abi::{Size, HasDataLayout}; +use rustc_target::abi::{HasDataLayout, Size}; use crate::*; diff --git a/src/lib.rs b/src/lib.rs index 6a5e7af237269..c9645d12fad16 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,13 +3,13 @@ #![feature(map_try_insert)] #![feature(never_type)] #![feature(try_blocks)] - #![warn(rust_2018_idioms)] #![allow(clippy::cast_lossless)] extern crate rustc_apfloat; extern crate rustc_ast; -#[macro_use] extern crate rustc_middle; +#[macro_use] +extern crate rustc_middle; extern crate rustc_data_structures; extern crate rustc_hir; extern crate rustc_index; @@ -44,18 +44,18 @@ pub use crate::shims::env::{EnvVars, EvalContextExt as _}; pub use crate::shims::foreign_items::EvalContextExt as _; pub use crate::shims::intrinsics::EvalContextExt as _; pub use crate::shims::os_str::EvalContextExt as _; -pub use crate::shims::time::EvalContextExt as _; pub use crate::shims::panic::{CatchUnwindData, EvalContextExt as _}; +pub use crate::shims::time::EvalContextExt as _; pub use crate::shims::tls::{EvalContextExt as _, TlsData}; pub use crate::shims::EvalContextExt as _; pub use crate::data_race::{ - AtomicReadOp, AtomicWriteOp, AtomicRwOp, AtomicFenceOp, - EvalContextExt as DataRaceEvalContextExt + AtomicFenceOp, AtomicReadOp, AtomicRwOp, AtomicWriteOp, + EvalContextExt as DataRaceEvalContextExt, }; pub use crate::diagnostics::{ register_diagnostic, report_error, EvalContextExt as DiagnosticsEvalContextExt, - TerminationInfo, NonHaltingDiagnostic, + NonHaltingDiagnostic, TerminationInfo, }; pub use crate::eval::{create_ecx, eval_main, AlignmentCheck, MiriConfig}; pub use crate::helpers::EvalContextExt as HelpersEvalContextExt; @@ -67,17 +67,13 @@ pub use crate::mono_hash_map::MonoHashMap; pub use crate::operator::EvalContextExt as OperatorEvalContextExt; pub use crate::range_map::RangeMap; pub use crate::stacked_borrows::{ - EvalContextExt as StackedBorEvalContextExt, Item, Permission, CallId, PtrId, Stack, Stacks, Tag, + CallId, EvalContextExt as StackedBorEvalContextExt, Item, Permission, PtrId, Stack, Stacks, Tag, }; +pub use crate::sync::{CondvarId, EvalContextExt as SyncEvalContextExt, MutexId, RwLockId}; pub use crate::thread::{ EvalContextExt as ThreadsEvalContextExt, SchedulingAction, ThreadId, ThreadManager, ThreadState, }; -pub use crate::sync::{ - EvalContextExt as SyncEvalContextExt, CondvarId, MutexId, RwLockId -}; -pub use crate::vector_clock::{ - VClock, VectorIdx, VTimestamp -}; +pub use crate::vector_clock::{VClock, VTimestamp, VectorIdx}; /// Insert rustc arguments at the beginning of the argument list that Miri wants to be /// set per default, for maximal validation power. diff --git a/src/machine.rs b/src/machine.rs index 99cb3bf2b29c0..635f3297b4e9c 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -3,10 +3,10 @@ use std::borrow::Cow; use std::cell::RefCell; +use std::fmt; use std::num::NonZeroU64; use std::rc::Rc; use std::time::Instant; -use std::fmt; use log::trace; use rand::rngs::StdRng; @@ -21,8 +21,8 @@ use rustc_middle::{ TyCtxt, }, }; -use rustc_span::symbol::{sym, Symbol}; use rustc_span::def_id::DefId; +use rustc_span::symbol::{sym, Symbol}; use rustc_target::abi::{LayoutOf, Size}; use rustc_target::spec::abi::Abi; @@ -100,7 +100,7 @@ impl fmt::Display for MiriMemoryKind { Env => write!(f, "environment variable"), Global => write!(f, "global (static or const)"), ExternStatic => write!(f, "extern static"), - Tls => write!(f, "thread-local static"), + Tls => write!(f, "thread-local static"), } } } @@ -176,11 +176,7 @@ impl MemoryExtra { ) { let ptr = ptr.assert_ptr(); assert_eq!(ptr.offset, Size::ZERO); - this.memory - .extra - .extern_statics - .try_insert(Symbol::intern(name), ptr.alloc_id) - .unwrap(); + this.memory.extra.extern_statics.try_insert(Symbol::intern(name), ptr.alloc_id).unwrap(); } /// Sets up the "extern statics" for this machine. @@ -196,7 +192,11 @@ impl MemoryExtra { this.write_scalar(Scalar::from_machine_usize(0, this), &place.into())?; Self::add_extern_static(this, "__cxa_thread_atexit_impl", place.ptr); // "environ" - Self::add_extern_static(this, "environ", this.machine.env_vars.environ.unwrap().ptr); + Self::add_extern_static( + this, + "environ", + this.machine.env_vars.environ.unwrap().ptr, + ); } "windows" => { // "_tls_used" @@ -282,8 +282,8 @@ impl<'mir, 'tcx> Evaluator<'mir, 'tcx> { validate: bool, layout_cx: LayoutCx<'tcx, TyCtxt<'tcx>>, ) -> Self { - let layouts = PrimitiveLayouts::new(layout_cx) - .expect("Couldn't get layouts of primitive types"); + let layouts = + PrimitiveLayouts::new(layout_cx).expect("Couldn't get layouts of primitive types"); Evaluator { // `env_vars` could be initialized properly here if `Memory` were available before // calling this method. @@ -476,15 +476,14 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { let kind = kind.expect("we set our STATIC_KIND so this cannot be None"); let alloc = alloc.into_owned(); - let (stacks, base_tag) = - if let Some(stacked_borrows) = &memory_extra.stacked_borrows { - let (stacks, base_tag) = - Stacks::new_allocation(id, alloc.size, Rc::clone(stacked_borrows), kind); - (Some(stacks), base_tag) - } else { - // No stacks, no tag. - (None, Tag::Untagged) - }; + let (stacks, base_tag) = if let Some(stacked_borrows) = &memory_extra.stacked_borrows { + let (stacks, base_tag) = + Stacks::new_allocation(id, alloc.size, Rc::clone(stacked_borrows), kind); + (Some(stacks), base_tag) + } else { + // No stacks, no tag. + (None, Tag::Untagged) + }; let race_alloc = if let Some(data_race) = &memory_extra.data_race { Some(data_race::AllocExtra::new_allocation(&data_race, alloc.size, kind)) } else { @@ -518,7 +517,6 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { Ok(()) } - fn after_static_mem_initialized( ecx: &mut InterpCx<'mir, 'tcx, Self>, ptr: Pointer, @@ -545,11 +543,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { kind: mir::RetagKind, place: &PlaceTy<'tcx, Tag>, ) -> InterpResult<'tcx> { - if ecx.memory.extra.stacked_borrows.is_some() { - ecx.retag(kind, place) - } else { - Ok(()) - } + if ecx.memory.extra.stacked_borrows.is_some() { ecx.retag(kind, place) } else { Ok(()) } } #[inline(always)] @@ -566,24 +560,20 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { } fn stack<'a>( - ecx: &'a InterpCx<'mir, 'tcx, Self> + ecx: &'a InterpCx<'mir, 'tcx, Self>, ) -> &'a [Frame<'mir, 'tcx, Self::PointerTag, Self::FrameExtra>] { ecx.active_thread_stack() } fn stack_mut<'a>( - ecx: &'a mut InterpCx<'mir, 'tcx, Self> + ecx: &'a mut InterpCx<'mir, 'tcx, Self>, ) -> &'a mut Vec> { ecx.active_thread_stack_mut() } #[inline(always)] fn after_stack_push(ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx> { - if ecx.memory.extra.stacked_borrows.is_some() { - ecx.retag_return_place() - } else { - Ok(()) - } + if ecx.memory.extra.stacked_borrows.is_some() { ecx.retag_return_place() } else { Ok(()) } } #[inline(always)] diff --git a/src/range_map.rs b/src/range_map.rs index 607c830530e1f..8b5a3af5bac5b 100644 --- a/src/range_map.rs +++ b/src/range_map.rs @@ -77,7 +77,10 @@ impl RangeMap { }; // The first offset that is not included any more. let end = offset + len; - slice.iter().take_while(move |elem| elem.range.start < end).map(|elem| (Size::from_bytes(elem.range.start), &elem.data)) + slice + .iter() + .take_while(move |elem| elem.range.start < end) + .map(|elem| (Size::from_bytes(elem.range.start), &elem.data)) } pub fn iter_mut_all<'a>(&'a mut self) -> impl Iterator + 'a { @@ -213,7 +216,9 @@ mod tests { fn to_vec(map: &RangeMap, offset: u64, len: u64) -> Vec { (offset..offset + len) .into_iter() - .map(|i| map.iter(Size::from_bytes(i), Size::from_bytes(1)).next().map(|(_, &t)| t).unwrap()) + .map(|i| { + map.iter(Size::from_bytes(i), Size::from_bytes(1)).next().map(|(_, &t)| t).unwrap() + }) .collect() } @@ -267,7 +272,9 @@ mod tests { assert_eq!(to_vec(&map, 10, 10), vec![23, 42, 23, 23, 23, 19, 19, 19, 19, 19]); // Should be seeing two blocks with 19. assert_eq!( - map.iter(Size::from_bytes(15), Size::from_bytes(2)).map(|(_, &t)| t).collect::>(), + map.iter(Size::from_bytes(15), Size::from_bytes(2)) + .map(|(_, &t)| t) + .collect::>(), vec![19, 19] ); diff --git a/src/shims/backtrace.rs b/src/shims/backtrace.rs index 224d8182b1591..f936913114c48 100644 --- a/src/shims/backtrace.rs +++ b/src/shims/backtrace.rs @@ -1,19 +1,18 @@ +use crate::rustc_target::abi::LayoutOf as _; use crate::*; use helpers::check_arg_count; -use rustc_middle::ty::{self, TypeAndMut}; use rustc_ast::ast::Mutability; +use rustc_middle::ty::{self, TypeAndMut}; use rustc_span::BytePos; use rustc_target::abi::Size; use std::convert::TryInto as _; -use crate::rustc_target::abi::LayoutOf as _; impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { - fn handle_miri_get_backtrace( &mut self, args: &[OpTy<'tcx, Tag>], - dest: &PlaceTy<'tcx, Tag> + dest: &PlaceTy<'tcx, Tag>, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let tcx = this.tcx; @@ -35,24 +34,24 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx data.push((frame.instance, span.lo())); } - let ptrs: Vec<_> = data.into_iter().map(|(instance, pos)| { - // We represent a frame pointer by using the `span.lo` value - // as an offset into the function's allocation. This gives us an - // opaque pointer that we can return to user code, and allows us - // to reconstruct the needed frame information in `handle_miri_resolve_frame`. - // Note that we never actually read or write anything from/to this pointer - - // all of the data is represented by the pointer value itself. - let mut fn_ptr = this.memory.create_fn_alloc(FnVal::Instance(instance)); - fn_ptr.offset = Size::from_bytes(pos.0); - Scalar::Ptr(fn_ptr) - }).collect(); + let ptrs: Vec<_> = data + .into_iter() + .map(|(instance, pos)| { + // We represent a frame pointer by using the `span.lo` value + // as an offset into the function's allocation. This gives us an + // opaque pointer that we can return to user code, and allows us + // to reconstruct the needed frame information in `handle_miri_resolve_frame`. + // Note that we never actually read or write anything from/to this pointer - + // all of the data is represented by the pointer value itself. + let mut fn_ptr = this.memory.create_fn_alloc(FnVal::Instance(instance)); + fn_ptr.offset = Size::from_bytes(pos.0); + Scalar::Ptr(fn_ptr) + }) + .collect(); let len = ptrs.len(); - let ptr_ty = tcx.mk_ptr(TypeAndMut { - ty: tcx.types.unit, - mutbl: Mutability::Mut - }); + let ptr_ty = tcx.mk_ptr(TypeAndMut { ty: tcx.types.unit, mutbl: Mutability::Mut }); let array_ty = tcx.mk_array(ptr_ty, ptrs.len().try_into().unwrap()); @@ -63,14 +62,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_immediate_to_mplace(ptr.into(), &place)?; } - this.write_immediate(Immediate::new_slice(alloc.ptr.into(), len.try_into().unwrap(), this), dest)?; + this.write_immediate( + Immediate::new_slice(alloc.ptr.into(), len.try_into().unwrap(), this), + dest, + )?; Ok(()) } fn handle_miri_resolve_frame( &mut self, args: &[OpTy<'tcx, Tag>], - dest: &PlaceTy<'tcx, Tag> + dest: &PlaceTy<'tcx, Tag>, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let tcx = this.tcx; @@ -83,7 +85,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let ptr = this.force_ptr(this.read_scalar(ptr)?.check_init()?)?; - let fn_instance = if let Some(GlobalAlloc::Function(instance)) = this.tcx.get_global_alloc(ptr.alloc_id) { + let fn_instance = if let Some(GlobalAlloc::Function(instance)) = + this.tcx.get_global_alloc(ptr.alloc_id) + { instance } else { throw_ub_format!("expected function pointer, found {:?}", ptr); @@ -100,7 +104,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if !(4..=5).contains(&num_fields) { // Always mention 5 fields, since the 4-field struct // is deprecated and slated for removal. - throw_ub_format!("bad declaration of miri_resolve_frame - should return a struct with 5 fields"); + throw_ub_format!( + "bad declaration of miri_resolve_frame - should return a struct with 5 fields" + ); } let pos = BytePos(ptr.offset.bytes().try_into().unwrap()); @@ -121,7 +127,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let dest = this.force_allocation(dest)?; if let ty::Adt(adt, _) = dest.layout.ty.kind() { if !adt.repr.c() { - throw_ub_format!("miri_resolve_frame must be declared with a `#[repr(C)]` return type"); + throw_ub_format!( + "miri_resolve_frame must be declared with a `#[repr(C)]` return type" + ); } } diff --git a/src/shims/dlsym.rs b/src/shims/dlsym.rs index e45556f9a1d13..1855d65d6c504 100644 --- a/src/shims/dlsym.rs +++ b/src/shims/dlsym.rs @@ -37,7 +37,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); match dlsym { Dlsym::Posix(dlsym) => posix::EvalContextExt::call_dlsym(this, dlsym, abi, args, ret), - Dlsym::Windows(dlsym) => windows::EvalContextExt::call_dlsym(this, dlsym, abi, args, ret), + Dlsym::Windows(dlsym) => + windows::EvalContextExt::call_dlsym(this, dlsym, abi, args, ret), } } } diff --git a/src/shims/env.rs b/src/shims/env.rs index 53770fd4f05ba..a091697532231 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -1,10 +1,10 @@ -use std::ffi::{OsString, OsStr}; -use std::env; use std::convert::TryFrom; +use std::env; +use std::ffi::{OsStr, OsString}; -use rustc_target::abi::{Size, LayoutOf}; use rustc_data_structures::fx::FxHashMap; use rustc_mir::interpret::Pointer; +use rustc_target::abi::{LayoutOf, Size}; use crate::*; @@ -49,9 +49,13 @@ impl<'tcx> EnvVars<'tcx> { for (name, value) in env::vars() { if !excluded_env_vars.contains(&name) { let var_ptr = match target_os { - "linux" | "macos" => alloc_env_var_as_c_str(name.as_ref(), value.as_ref(), ecx)?, + "linux" | "macos" => + alloc_env_var_as_c_str(name.as_ref(), value.as_ref(), ecx)?, "windows" => alloc_env_var_as_wide_str(name.as_ref(), value.as_ref(), ecx)?, - unsupported => throw_unsup_format!("environment support for target OS `{}` not yet available", unsupported), + unsupported => throw_unsup_format!( + "environment support for target OS `{}` not yet available", + unsupported + ), }; ecx.machine.env_vars.map.insert(OsString::from(name), var_ptr); } @@ -102,14 +106,20 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn getenv(&mut self, name_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); let target_os = &this.tcx.sess.target.os; - assert!(target_os == "linux" || target_os == "macos", "`getenv` is only available for the UNIX target family"); + assert!( + target_os == "linux" || target_os == "macos", + "`getenv` is only available for the UNIX target family" + ); let name_ptr = this.read_scalar(name_op)?.check_init()?; let name = this.read_os_str_from_c_str(name_ptr)?; Ok(match this.machine.env_vars.map.get(name) { Some(var_ptr) => { // The offset is used to strip the "{name}=" part of the string. - Scalar::from(var_ptr.offset(Size::from_bytes(u64::try_from(name.len()).unwrap().checked_add(1).unwrap()), this)?) + Scalar::from(var_ptr.offset( + Size::from_bytes(u64::try_from(name.len()).unwrap().checked_add(1).unwrap()), + this, + )?) } None => Scalar::null_ptr(&*this.tcx), }) @@ -118,10 +128,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx #[allow(non_snake_case)] fn GetEnvironmentVariableW( &mut self, - name_op: &OpTy<'tcx, Tag>, // LPCWSTR - buf_op: &OpTy<'tcx, Tag>, // LPWSTR - size_op: &OpTy<'tcx, Tag>, // DWORD - ) -> InterpResult<'tcx, u32> { // Returns DWORD (u32 in Windows) + name_op: &OpTy<'tcx, Tag>, // LPCWSTR + buf_op: &OpTy<'tcx, Tag>, // LPWSTR + size_op: &OpTy<'tcx, Tag>, // DWORD + ) -> InterpResult<'tcx, u32> { + // ^ Returns DWORD (u32 on Windows) + let this = self.eval_context_mut(); this.assert_target_os("windows", "GetEnvironmentVariableW"); @@ -130,9 +142,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(match this.machine.env_vars.map.get(&name) { Some(var_ptr) => { // The offset is used to strip the "{name}=" part of the string. - let name_offset_bytes = - u64::try_from(name.len()).unwrap().checked_add(1).unwrap().checked_mul(2).unwrap(); - let var_ptr = Scalar::from(var_ptr.offset(Size::from_bytes(name_offset_bytes), this)?); + #[rustfmt::skip] + let name_offset_bytes = u64::try_from(name.len()).unwrap() + .checked_add(1).unwrap() + .checked_mul(2).unwrap(); + let var_ptr = + Scalar::from(var_ptr.offset(Size::from_bytes(name_offset_bytes), this)?); let var = this.read_os_str_from_wide_str(var_ptr)?; let buf_ptr = this.read_scalar(buf_op)?.check_init()?; @@ -169,12 +184,19 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } #[allow(non_snake_case)] - fn FreeEnvironmentStringsW(&mut self, env_block_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + fn FreeEnvironmentStringsW( + &mut self, + env_block_op: &OpTy<'tcx, Tag>, + ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); this.assert_target_os("windows", "FreeEnvironmentStringsW"); let env_block_ptr = this.read_scalar(env_block_op)?.check_init()?; - let result = this.memory.deallocate(this.force_ptr(env_block_ptr)?, None, MiriMemoryKind::Env.into()); + let result = this.memory.deallocate( + this.force_ptr(env_block_ptr)?, + None, + MiriMemoryKind::Env.into(), + ); // If the function succeeds, the return value is nonzero. Ok(result.is_ok() as i32) } @@ -186,7 +208,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, i32> { let mut this = self.eval_context_mut(); let target_os = &this.tcx.sess.target.os; - assert!(target_os == "linux" || target_os == "macos", "`setenv` is only available for the UNIX target family"); + assert!( + target_os == "linux" || target_os == "macos", + "`setenv` is only available for the UNIX target family" + ); let name_ptr = this.read_scalar(name_op)?.check_init()?; let value_ptr = this.read_scalar(value_op)?.check_init()?; @@ -202,8 +227,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if let Some((name, value)) = new { let var_ptr = alloc_env_var_as_c_str(&name, &value, &mut this)?; if let Some(var) = this.machine.env_vars.map.insert(name, var_ptr) { - this.memory - .deallocate(var, None, MiriMemoryKind::Env.into())?; + this.memory.deallocate(var, None, MiriMemoryKind::Env.into())?; } this.update_environ()?; Ok(0) // return zero on success @@ -248,8 +272,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let value = this.read_os_str_from_wide_str(value_ptr)?; let var_ptr = alloc_env_var_as_wide_str(&name, &value, &mut this)?; if let Some(var) = this.machine.env_vars.map.insert(name, var_ptr) { - this.memory - .deallocate(var, None, MiriMemoryKind::Env.into())?; + this.memory.deallocate(var, None, MiriMemoryKind::Env.into())?; } this.update_environ()?; Ok(1) // return non-zero on success @@ -259,7 +282,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn unsetenv(&mut self, name_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); let target_os = &this.tcx.sess.target.os; - assert!(target_os == "linux" || target_os == "macos", "`unsetenv` is only available for the UNIX target family"); + assert!( + target_os == "linux" || target_os == "macos", + "`unsetenv` is only available for the UNIX target family" + ); let name_ptr = this.read_scalar(name_op)?.check_init()?; let mut success = None; @@ -271,8 +297,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } if let Some(old) = success { if let Some(var) = old { - this.memory - .deallocate(var, None, MiriMemoryKind::Env.into())?; + this.memory.deallocate(var, None, MiriMemoryKind::Env.into())?; } this.update_environ()?; Ok(0) @@ -291,7 +316,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); let target_os = &this.tcx.sess.target.os; - assert!(target_os == "linux" || target_os == "macos", "`getcwd` is only available for the UNIX target family"); + assert!( + target_os == "linux" || target_os == "macos", + "`getcwd` is only available for the UNIX target family" + ); this.check_no_isolation("`getcwd`")?; @@ -337,7 +365,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn chdir(&mut self, path_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); let target_os = &this.tcx.sess.target.os; - assert!(target_os == "linux" || target_os == "macos", "`getcwd` is only available for the UNIX target family"); + assert!( + target_os == "linux" || target_os == "macos", + "`getcwd` is only available for the UNIX target family" + ); this.check_no_isolation("`chdir`")?; @@ -353,10 +384,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } #[allow(non_snake_case)] - fn SetCurrentDirectoryW ( + fn SetCurrentDirectoryW( &mut self, - path_op: &OpTy<'tcx, Tag> // LPCTSTR - ) -> InterpResult<'tcx, i32> { // Returns BOOL (i32 in Windows) + path_op: &OpTy<'tcx, Tag>, // LPCTSTR + ) -> InterpResult<'tcx, i32> { + // ^ Returns BOOL (i32 on Windows) + let this = self.eval_context_mut(); this.assert_target_os("windows", "SetCurrentDirectoryW"); @@ -380,7 +413,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Deallocate the old environ list, if any. if let Some(environ) = this.machine.env_vars.environ { let old_vars_ptr = this.read_scalar(&environ.into())?.check_init()?; - this.memory.deallocate(this.force_ptr(old_vars_ptr)?, None, MiriMemoryKind::Env.into())?; + this.memory.deallocate( + this.force_ptr(old_vars_ptr)?, + None, + MiriMemoryKind::Env.into(), + )?; } else { // No `environ` allocated yet, let's do that. // This is memory backing an extern static, hence `ExternStatic`, not `Env`. @@ -390,7 +427,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // Collect all the pointers to each variable in a vector. - let mut vars: Vec> = this.machine.env_vars.map.values().map(|&ptr| ptr.into()).collect(); + let mut vars: Vec> = + this.machine.env_vars.map.values().map(|&ptr| ptr.into()).collect(); // Add the trailing null pointer. vars.push(Scalar::null_ptr(this)); // Make an array with all these pointers inside Miri. @@ -402,10 +440,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let place = this.mplace_field(&vars_place, idx)?; this.write_scalar(var, &place.into())?; } - this.write_scalar( - vars_place.ptr, - &this.machine.env_vars.environ.unwrap().into(), - )?; + this.write_scalar(vars_place.ptr, &this.machine.env_vars.environ.unwrap().into())?; Ok(()) } diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 75a7505e73de5..371a50f0e4b2e 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -1,16 +1,22 @@ -use std::{convert::{TryInto, TryFrom}, iter}; +use std::{ + convert::{TryFrom, TryInto}, + iter, +}; use log::trace; +use rustc_apfloat::Float; use rustc_hir::def_id::DefId; use rustc_middle::mir; -use rustc_target::{abi::{Align, Size}, spec::{PanicStrategy, abi::Abi}}; use rustc_middle::ty; -use rustc_apfloat::Float; use rustc_span::symbol::sym; +use rustc_target::{ + abi::{Align, Size}, + spec::{abi::Abi, PanicStrategy}, +}; -use crate::*; use super::backtrace::EvalContextExt as _; +use crate::*; use helpers::{check_abi, check_arg_count}; impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} diff --git a/src/shims/mod.rs b/src/shims/mod.rs index 1605ea2f6a894..13ea14b4b9d40 100644 --- a/src/shims/mod.rs +++ b/src/shims/mod.rs @@ -74,8 +74,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx return Ok(false); } - let req_align = this - .force_bits(this.read_scalar(align_op)?.check_init()?, this.pointer_size())?; + let req_align = + this.force_bits(this.read_scalar(align_op)?.check_init()?, this.pointer_size())?; // Stop if the alignment is not a power of two. if !req_align.is_power_of_two() { diff --git a/src/shims/os_str.rs b/src/shims/os_str.rs index 21b5a876463e9..22e3806ad3345 100644 --- a/src/shims/os_str.rs +++ b/src/shims/os_str.rs @@ -48,7 +48,6 @@ pub fn bytes_to_os_str<'a, 'tcx>(bytes: &'a [u8]) -> InterpResult<'tcx, &'a OsSt impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { - /// Helper function to read an OsString from a null-terminated sequence of bytes, which is what /// the Unix APIs usually handle. fn read_os_str_from_c_str<'a>(&'a self, scalar: Scalar) -> InterpResult<'tcx, &'a OsStr> @@ -94,7 +93,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx scalar: Scalar, size: u64, ) -> InterpResult<'tcx, (bool, u64)> { - let bytes = os_str_to_bytes(os_str)?; // If `size` is smaller or equal than `bytes.len()`, writing `bytes` plus the required null // terminator to memory using the `ptr` pointer would cause an out-of-bounds access. @@ -199,7 +197,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_ref(); let os_str = this.read_os_str_from_wide_str(scalar)?; - Ok(this.convert_path_separator(Cow::Owned(os_str), PathConversion::TargetToHost).into_owned().into()) + Ok(this + .convert_path_separator(Cow::Owned(os_str), PathConversion::TargetToHost) + .into_owned() + .into()) } /// Write a Path to the machine memory (as a null-terminated sequence of bytes), @@ -211,7 +212,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx size: u64, ) -> InterpResult<'tcx, (bool, u64)> { let this = self.eval_context_mut(); - let os_str = this.convert_path_separator(Cow::Borrowed(path.as_os_str()), PathConversion::HostToTarget); + let os_str = this + .convert_path_separator(Cow::Borrowed(path.as_os_str()), PathConversion::HostToTarget); this.write_os_str_to_c_str(&os_str, scalar, size) } @@ -224,7 +226,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx size: u64, ) -> InterpResult<'tcx, (bool, u64)> { let this = self.eval_context_mut(); - let os_str = this.convert_path_separator(Cow::Borrowed(path.as_os_str()), PathConversion::HostToTarget); + let os_str = this + .convert_path_separator(Cow::Borrowed(path.as_os_str()), PathConversion::HostToTarget); this.write_os_str_to_wide_str(&os_str, scalar, size) } @@ -270,4 +273,3 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx }; } } - diff --git a/src/shims/panic.rs b/src/shims/panic.rs index 3a43e5e3596f7..b60da058e2cbb 100644 --- a/src/shims/panic.rs +++ b/src/shims/panic.rs @@ -14,8 +14,8 @@ use log::trace; use rustc_middle::{mir, ty}; -use rustc_target::spec::PanicStrategy; use rustc_target::spec::abi::Abi; +use rustc_target::spec::PanicStrategy; use crate::*; use helpers::check_arg_count; @@ -54,10 +54,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let &[ref payload] = check_arg_count(args)?; let payload = this.read_scalar(payload)?.check_init()?; let thread = this.active_thread_mut(); - assert!( - thread.panic_payload.is_none(), - "the panic runtime should avoid double-panics" - ); + assert!(thread.panic_payload.is_none(), "the panic runtime should avoid double-panics"); thread.panic_payload = Some(payload); // Jump to the unwind block to begin unwinding. @@ -111,7 +108,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // This lets `handle_stack_pop` (below) know that we should stop unwinding // when we pop this frame. if this.tcx.sess.panic_strategy() == PanicStrategy::Unwind { - this.frame_mut().extra.catch_unwind = Some(CatchUnwindData { catch_fn, data, dest: *dest, ret }); + this.frame_mut().extra.catch_unwind = + Some(CatchUnwindData { catch_fn, data, dest: *dest, ret }); } return Ok(()); @@ -134,7 +132,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if let (true, Some(catch_unwind)) = (unwinding, extra.catch_unwind.take()) { // We've just popped a frame that was pushed by `try`, // and we are unwinding, so we should catch that. - trace!("unwinding: found catch_panic frame during unwinding: {:?}", this.frame().instance); + trace!( + "unwinding: found catch_panic frame during unwinding: {:?}", + this.frame().instance + ); // We set the return value of `try` to 1, since there was a panic. this.write_scalar(Scalar::from_i32(1), &catch_unwind.dest)?; @@ -164,11 +165,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } /// Starta a panic in the interpreter with the given message as payload. - fn start_panic( - &mut self, - msg: &str, - unwind: Option, - ) -> InterpResult<'tcx> { + fn start_panic(&mut self, msg: &str, unwind: Option) -> InterpResult<'tcx> { let this = self.eval_context_mut(); // First arg: message. diff --git a/src/shims/posix/fs.rs b/src/shims/posix/fs.rs index def2aca292a53..234f03ff462c1 100644 --- a/src/shims/posix/fs.rs +++ b/src/shims/posix/fs.rs @@ -1,21 +1,23 @@ +use std::borrow::Cow; use std::collections::BTreeMap; use std::convert::{TryFrom, TryInto}; -use std::fs::{read_dir, remove_dir, remove_file, rename, DirBuilder, File, FileType, OpenOptions, ReadDir}; +use std::fs::{ + read_dir, remove_dir, remove_file, rename, DirBuilder, File, FileType, OpenOptions, ReadDir, +}; use std::io::{self, Read, Seek, SeekFrom, Write}; use std::path::Path; use std::time::SystemTime; -use std::borrow::Cow; use log::trace; use rustc_data_structures::fx::FxHashMap; -use rustc_target::abi::{Align, LayoutOf, Size}; use rustc_middle::ty; +use rustc_target::abi::{Align, LayoutOf, Size}; use crate::*; -use stacked_borrows::Tag; use helpers::{check_arg_count, immty_from_int_checked, immty_from_uint_checked}; use shims::time::system_time_to_duration; +use stacked_borrows::Tag; #[derive(Debug)] struct FileHandle { @@ -23,13 +25,28 @@ struct FileHandle { writable: bool, } -trait FileDescriptor : std::fmt::Debug { +trait FileDescriptor: std::fmt::Debug { fn as_file_handle<'tcx>(&self) -> InterpResult<'tcx, &FileHandle>; - fn read<'tcx>(&mut self, communicate_allowed: bool, bytes: &mut [u8]) -> InterpResult<'tcx, io::Result>; - fn write<'tcx>(&mut self, communicate_allowed: bool, bytes: &[u8]) -> InterpResult<'tcx, io::Result>; - fn seek<'tcx>(&mut self, communicate_allowed: bool, offset: SeekFrom) -> InterpResult<'tcx, io::Result>; - fn close<'tcx>(self: Box, _communicate_allowed: bool) -> InterpResult<'tcx, io::Result>; + fn read<'tcx>( + &mut self, + communicate_allowed: bool, + bytes: &mut [u8], + ) -> InterpResult<'tcx, io::Result>; + fn write<'tcx>( + &mut self, + communicate_allowed: bool, + bytes: &[u8], + ) -> InterpResult<'tcx, io::Result>; + fn seek<'tcx>( + &mut self, + communicate_allowed: bool, + offset: SeekFrom, + ) -> InterpResult<'tcx, io::Result>; + fn close<'tcx>( + self: Box, + _communicate_allowed: bool, + ) -> InterpResult<'tcx, io::Result>; fn dup<'tcx>(&mut self) -> io::Result>; } @@ -39,22 +56,37 @@ impl FileDescriptor for FileHandle { Ok(&self) } - fn read<'tcx>(&mut self, communicate_allowed: bool, bytes: &mut [u8]) -> InterpResult<'tcx, io::Result> { + fn read<'tcx>( + &mut self, + communicate_allowed: bool, + bytes: &mut [u8], + ) -> InterpResult<'tcx, io::Result> { assert!(communicate_allowed, "isolation should have prevented even opening a file"); Ok(self.file.read(bytes)) } - fn write<'tcx>(&mut self, communicate_allowed: bool, bytes: &[u8]) -> InterpResult<'tcx, io::Result> { + fn write<'tcx>( + &mut self, + communicate_allowed: bool, + bytes: &[u8], + ) -> InterpResult<'tcx, io::Result> { assert!(communicate_allowed, "isolation should have prevented even opening a file"); Ok(self.file.write(bytes)) } - fn seek<'tcx>(&mut self, communicate_allowed: bool, offset: SeekFrom) -> InterpResult<'tcx, io::Result> { + fn seek<'tcx>( + &mut self, + communicate_allowed: bool, + offset: SeekFrom, + ) -> InterpResult<'tcx, io::Result> { assert!(communicate_allowed, "isolation should have prevented even opening a file"); Ok(self.file.seek(offset)) } - fn close<'tcx>(self: Box, communicate_allowed: bool) -> InterpResult<'tcx, io::Result> { + fn close<'tcx>( + self: Box, + communicate_allowed: bool, + ) -> InterpResult<'tcx, io::Result> { assert!(communicate_allowed, "isolation should have prevented even opening a file"); // We sync the file if it was opened in a mode different than read-only. if self.writable { @@ -88,7 +120,11 @@ impl FileDescriptor for io::Stdin { throw_unsup_format!("stdin cannot be used as FileHandle"); } - fn read<'tcx>(&mut self, communicate_allowed: bool, bytes: &mut [u8]) -> InterpResult<'tcx, io::Result> { + fn read<'tcx>( + &mut self, + communicate_allowed: bool, + bytes: &mut [u8], + ) -> InterpResult<'tcx, io::Result> { if !communicate_allowed { // We want isolation mode to be deterministic, so we have to disallow all reads, even stdin. helpers::isolation_error("`read` from stdin")?; @@ -96,15 +132,26 @@ impl FileDescriptor for io::Stdin { Ok(Read::read(self, bytes)) } - fn write<'tcx>(&mut self, _communicate_allowed: bool, _bytes: &[u8]) -> InterpResult<'tcx, io::Result> { + fn write<'tcx>( + &mut self, + _communicate_allowed: bool, + _bytes: &[u8], + ) -> InterpResult<'tcx, io::Result> { throw_unsup_format!("cannot write to stdin"); } - fn seek<'tcx>(&mut self, _communicate_allowed: bool, _offset: SeekFrom) -> InterpResult<'tcx, io::Result> { + fn seek<'tcx>( + &mut self, + _communicate_allowed: bool, + _offset: SeekFrom, + ) -> InterpResult<'tcx, io::Result> { throw_unsup_format!("cannot seek on stdin"); } - fn close<'tcx>(self: Box, _communicate_allowed: bool) -> InterpResult<'tcx, io::Result> { + fn close<'tcx>( + self: Box, + _communicate_allowed: bool, + ) -> InterpResult<'tcx, io::Result> { throw_unsup_format!("stdin cannot be closed"); } @@ -118,11 +165,19 @@ impl FileDescriptor for io::Stdout { throw_unsup_format!("stdout cannot be used as FileHandle"); } - fn read<'tcx>(&mut self, _communicate_allowed: bool, _bytes: &mut [u8]) -> InterpResult<'tcx, io::Result> { + fn read<'tcx>( + &mut self, + _communicate_allowed: bool, + _bytes: &mut [u8], + ) -> InterpResult<'tcx, io::Result> { throw_unsup_format!("cannot read from stdout"); } - fn write<'tcx>(&mut self, _communicate_allowed: bool, bytes: &[u8]) -> InterpResult<'tcx, io::Result> { + fn write<'tcx>( + &mut self, + _communicate_allowed: bool, + bytes: &[u8], + ) -> InterpResult<'tcx, io::Result> { // We allow writing to stderr even with isolation enabled. let result = Write::write(self, bytes); // Stdout is buffered, flush to make sure it appears on the @@ -135,11 +190,18 @@ impl FileDescriptor for io::Stdout { Ok(result) } - fn seek<'tcx>(&mut self, _communicate_allowed: bool, _offset: SeekFrom) -> InterpResult<'tcx, io::Result> { + fn seek<'tcx>( + &mut self, + _communicate_allowed: bool, + _offset: SeekFrom, + ) -> InterpResult<'tcx, io::Result> { throw_unsup_format!("cannot seek on stdout"); } - fn close<'tcx>(self: Box, _communicate_allowed: bool) -> InterpResult<'tcx, io::Result> { + fn close<'tcx>( + self: Box, + _communicate_allowed: bool, + ) -> InterpResult<'tcx, io::Result> { throw_unsup_format!("stdout cannot be closed"); } @@ -153,21 +215,36 @@ impl FileDescriptor for io::Stderr { throw_unsup_format!("stderr cannot be used as FileHandle"); } - fn read<'tcx>(&mut self, _communicate_allowed: bool, _bytes: &mut [u8]) -> InterpResult<'tcx, io::Result> { + fn read<'tcx>( + &mut self, + _communicate_allowed: bool, + _bytes: &mut [u8], + ) -> InterpResult<'tcx, io::Result> { throw_unsup_format!("cannot read from stderr"); } - fn write<'tcx>(&mut self, _communicate_allowed: bool, bytes: &[u8]) -> InterpResult<'tcx, io::Result> { + fn write<'tcx>( + &mut self, + _communicate_allowed: bool, + bytes: &[u8], + ) -> InterpResult<'tcx, io::Result> { // We allow writing to stderr even with isolation enabled. // No need to flush, stderr is not buffered. Ok(Write::write(self, bytes)) } - fn seek<'tcx>(&mut self, _communicate_allowed: bool, _offset: SeekFrom) -> InterpResult<'tcx, io::Result> { + fn seek<'tcx>( + &mut self, + _communicate_allowed: bool, + _offset: SeekFrom, + ) -> InterpResult<'tcx, io::Result> { throw_unsup_format!("cannot seek on stderr"); } - fn close<'tcx>(self: Box, _communicate_allowed: bool) -> InterpResult<'tcx, io::Result> { + fn close<'tcx>( + self: Box, + _communicate_allowed: bool, + ) -> InterpResult<'tcx, io::Result> { throw_unsup_format!("stderr cannot be closed"); } @@ -187,9 +264,7 @@ impl<'tcx> Default for FileHandler { handles.insert(0i32, Box::new(io::stdin())); handles.insert(1i32, Box::new(io::stdout())); handles.insert(2i32, Box::new(io::stderr())); - FileHandler { - handles - } + FileHandler { handles } } } @@ -203,11 +278,8 @@ impl<'tcx> FileHandler { // between used FDs, the find_map combinator will return it. If the first such unused FD // is after all other used FDs, the find_map combinator will return None, and we will use // the FD following the greatest FD thus far. - let candidate_new_fd = self - .handles - .range(min_fd..) - .zip(min_fd..) - .find_map(|((fd, _fh), counter)| { + let candidate_new_fd = + self.handles.range(min_fd..).zip(min_fd..).find_map(|((fd, _fh), counter)| { if *fd != counter { // There was a gap in the fds stored, return the first unused one // (note that this relies on BTreeMap iterating in key order) @@ -220,7 +292,10 @@ impl<'tcx> FileHandler { let new_fd = candidate_new_fd.unwrap_or_else(|| { // find_map ran out of BTreeMap entries before finding a free fd, use one plus the // maximum fd in the map - self.handles.last_key_value().map(|(fd, _)| fd.checked_add(1).unwrap()).unwrap_or(min_fd) + self.handles + .last_key_value() + .map(|(fd, _)| fd.checked_add(1).unwrap()) + .unwrap_or(min_fd) }); self.handles.try_insert(new_fd, file_handle).unwrap(); @@ -292,7 +367,7 @@ trait EvalContextExtPrivate<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, ' immty_from_uint_checked(modified_sec, time_t_layout)?, // st_mtime immty_from_uint_checked(modified_nsec, long_layout)?, // st_mtime_nsec immty_from_uint_checked(0u128, time_t_layout)?, // st_ctime - immty_from_uint_checked(0u128, long_layout)?, // st_ctime_nsec + immty_from_uint_checked(0u128, long_layout)?, // st_ctime_nsec immty_from_uint_checked(created_sec, time_t_layout)?, // st_birthtime immty_from_uint_checked(created_nsec, long_layout)?, // st_birthtime_nsec immty_from_uint_checked(metadata.size, off_t_layout)?, // st_size @@ -319,7 +394,10 @@ trait EvalContextExtPrivate<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, ' Ok((-1).into()) } - fn file_type_to_d_type(&mut self, file_type: std::io::Result) -> InterpResult<'tcx, i32> { + fn file_type_to_d_type( + &mut self, + file_type: std::io::Result, + ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); match file_type { Ok(file_type) => { @@ -353,10 +431,14 @@ trait EvalContextExtPrivate<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, ' Ok(this.eval_libc("DT_UNKNOWN")?.to_u8()?.into()) } } - Err(e) => return match e.raw_os_error() { - Some(error) => Ok(error), - None => throw_unsup_format!("the error {} couldn't be converted to a return value", e), - } + Err(e) => + return match e.raw_os_error() { + Some(error) => Ok(error), + None => throw_unsup_format!( + "the error {} couldn't be converted to a return value", + e + ), + }, } } } @@ -396,7 +478,11 @@ impl Default for DirHandler { } } -fn maybe_sync_file(file: &File, writable: bool, operation: fn(&File) -> std::io::Result<()>) -> std::io::Result { +fn maybe_sync_file( + file: &File, + writable: bool, + operation: fn(&File) -> std::io::Result<()>, +) -> std::io::Result { if !writable && cfg!(windows) { // sync_all() and sync_data() will return an error on Windows hosts if the file is not opened // for writing. (FlushFileBuffers requires that the file handle have the @@ -505,16 +591,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.try_unwrap_io_result(fd) } - fn fcntl( - &mut self, - args: &[OpTy<'tcx, Tag>], - ) -> InterpResult<'tcx, i32> { + fn fcntl(&mut self, args: &[OpTy<'tcx, Tag>]) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); this.check_no_isolation("`fcntl`")?; if args.len() < 2 { - throw_ub_format!("incorrect number of arguments for fcntl: got {}, expected at least 2", args.len()); + throw_ub_format!( + "incorrect number of arguments for fcntl: got {}, expected at least 2", + args.len() + ); } let fd = this.read_scalar(&args[0])?.to_i32()?; let cmd = this.read_scalar(&args[1])?.to_i32()?; @@ -552,12 +638,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(-1) } } - }, + } None => return this.handle_not_found(), } - } else if this.tcx.sess.target.os == "macos" - && cmd == this.eval_libc_i32("F_FULLFSYNC")? - { + } else if this.tcx.sess.target.os == "macos" && cmd == this.eval_libc_i32("F_FULLFSYNC")? { let &[_, _] = check_arg_count(args)?; if let Some(file_descriptor) = this.machine.file_handler.handles.get(&fd) { // FIXME: Support fullfsync for all FDs @@ -585,12 +669,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } - fn read( - &mut self, - fd: i32, - buf: Scalar, - count: u64, - ) -> InterpResult<'tcx, i64> { + fn read(&mut self, fd: i32, buf: Scalar, count: u64) -> InterpResult<'tcx, i64> { let this = self.eval_context_mut(); // Isolation check is done via `FileDescriptor` trait. @@ -637,12 +716,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } - fn write( - &mut self, - fd: i32, - buf: Scalar, - count: u64, - ) -> InterpResult<'tcx, i64> { + fn write(&mut self, fd: i32, buf: Scalar, count: u64) -> InterpResult<'tcx, i64> { let this = self.eval_context_mut(); // Isolation check is done via `FileDescriptor` trait. @@ -719,7 +793,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn symlink( &mut self, target_op: &OpTy<'tcx, Tag>, - linkpath_op: &OpTy<'tcx, Tag> + linkpath_op: &OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, i32> { #[cfg(unix)] fn create_link(src: &Path, dst: &Path) -> std::io::Result<()> { @@ -729,11 +803,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx #[cfg(windows)] fn create_link(src: &Path, dst: &Path) -> std::io::Result<()> { use std::os::windows::fs; - if src.is_dir() { - fs::symlink_dir(src, dst) - } else { - fs::symlink_file(src, dst) - } + if src.is_dir() { fs::symlink_dir(src, dst) } else { fs::symlink_file(src, dst) } } let this = self.eval_context_mut(); @@ -842,11 +912,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // set. // Other behaviors cannot be tested from `libstd` and thus are not implemented. If you // found this error, please open an issue reporting it. - if !( - path.is_absolute() || - dirfd == this.eval_libc_i32("AT_FDCWD")? || - (path.as_os_str().is_empty() && empty_path_flag) - ) { + if !(path.is_absolute() + || dirfd == this.eval_libc_i32("AT_FDCWD")? + || (path.as_os_str().is_empty() && empty_path_flag)) + { throw_unsup_format!( "using statx is only supported with absolute paths, relative paths with the file \ descriptor `AT_FDCWD`, and empty paths with the `AT_EMPTY_PATH` flag set and any \ @@ -889,20 +958,29 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // We need to set the corresponding bits of `mask` if the access, creation and modification // times were available. Otherwise we let them be zero. - let (access_sec, access_nsec) = metadata.accessed.map(|tup| { - mask |= this.eval_libc("STATX_ATIME")?.to_u32()?; - InterpResult::Ok(tup) - }).unwrap_or(Ok((0, 0)))?; - - let (created_sec, created_nsec) = metadata.created.map(|tup| { - mask |= this.eval_libc("STATX_BTIME")?.to_u32()?; - InterpResult::Ok(tup) - }).unwrap_or(Ok((0, 0)))?; - - let (modified_sec, modified_nsec) = metadata.modified.map(|tup| { - mask |= this.eval_libc("STATX_MTIME")?.to_u32()?; - InterpResult::Ok(tup) - }).unwrap_or(Ok((0, 0)))?; + let (access_sec, access_nsec) = metadata + .accessed + .map(|tup| { + mask |= this.eval_libc("STATX_ATIME")?.to_u32()?; + InterpResult::Ok(tup) + }) + .unwrap_or(Ok((0, 0)))?; + + let (created_sec, created_nsec) = metadata + .created + .map(|tup| { + mask |= this.eval_libc("STATX_BTIME")?.to_u32()?; + InterpResult::Ok(tup) + }) + .unwrap_or(Ok((0, 0)))?; + + let (modified_sec, modified_nsec) = metadata + .modified + .map(|tup| { + mask |= this.eval_libc("STATX_MTIME")?.to_u32()?; + InterpResult::Ok(tup) + }) + .unwrap_or(Ok((0, 0)))?; let __u32_layout = this.libc_ty_layout("__u32")?; let __u64_layout = this.libc_ty_layout("__u64")?; @@ -1006,10 +1084,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.try_unwrap_io_result(result) } - fn rmdir( - &mut self, - path_op: &OpTy<'tcx, Tag>, - ) -> InterpResult<'tcx, i32> { + fn rmdir(&mut self, path_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); this.check_no_isolation("`rmdir`")?; @@ -1087,7 +1162,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx name_place.layout.size.bytes(), )?; if !name_fits { - throw_unsup_format!("a directory entry had a name too large to fit in libc::dirent64"); + throw_unsup_format!( + "a directory entry had a name too large to fit in libc::dirent64" + ); } let entry_place = this.deref_operand(entry_op)?; @@ -1175,7 +1252,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx name_place.layout.size.bytes(), )?; if !name_fits { - throw_unsup_format!("a directory entry had a name too large to fit in libc::dirent"); + throw_unsup_format!( + "a directory entry had a name too large to fit in libc::dirent" + ); } let entry_place = this.deref_operand(entry_op)?; @@ -1194,8 +1273,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let file_type = this.file_type_to_d_type(dir_entry.file_type())?; let imms = [ - immty_from_uint_checked(ino, ino_t_layout)?, // d_ino - immty_from_uint_checked(0u128, off_t_layout)?, // d_seekoff + immty_from_uint_checked(ino, ino_t_layout)?, // d_ino + immty_from_uint_checked(0u128, off_t_layout)?, // d_seekoff immty_from_uint_checked(0u128, c_ushort_layout)?, // d_reclen immty_from_uint_checked(file_name_len, c_ushort_layout)?, // d_namlen immty_from_int_checked(file_type, c_uchar_layout)?, // d_type @@ -1352,7 +1431,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx &mut self, pathname_op: &OpTy<'tcx, Tag>, buf_op: &OpTy<'tcx, Tag>, - bufsize_op: &OpTy<'tcx, Tag> + bufsize_op: &OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, i64> { let this = self.eval_context_mut(); @@ -1365,7 +1444,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let result = std::fs::read_link(pathname); match result { Ok(resolved) => { - let resolved = this.convert_path_separator(Cow::Borrowed(resolved.as_ref()), crate::shims::os_str::PathConversion::HostToTarget); + let resolved = this.convert_path_separator( + Cow::Borrowed(resolved.as_ref()), + crate::shims::os_str::PathConversion::HostToTarget, + ); let mut path_bytes = crate::shims::os_str::os_str_to_bytes(resolved.as_ref())?; let bufsize: usize = bufsize.try_into().unwrap(); if path_bytes.len() > bufsize { @@ -1388,12 +1470,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// `time` is Ok. Returns `None` if `time` is an error. Fails if `time` happens before the unix /// epoch. fn extract_sec_and_nsec<'tcx>( - time: std::io::Result + time: std::io::Result, ) -> InterpResult<'tcx, Option<(u64, u32)>> { - time.ok().map(|time| { - let duration = system_time_to_duration(&time)?; - Ok((duration.as_secs(), duration.subsec_nanos())) - }).transpose() + time.ok() + .map(|time| { + let duration = system_time_to_duration(&time)?; + Ok((duration.as_secs(), duration.subsec_nanos())) + }) + .transpose() } /// Stores a file's metadata in order to avoid code duplication in the different metadata related @@ -1410,13 +1494,10 @@ impl FileMetadata { fn from_path<'tcx, 'mir>( ecx: &mut MiriEvalContext<'mir, 'tcx>, path: &Path, - follow_symlink: bool + follow_symlink: bool, ) -> InterpResult<'tcx, Option> { - let metadata = if follow_symlink { - std::fs::metadata(path) - } else { - std::fs::symlink_metadata(path) - }; + let metadata = + if follow_symlink { std::fs::metadata(path) } else { std::fs::symlink_metadata(path) }; FileMetadata::from_meta(ecx, metadata) } diff --git a/src/shims/posix/linux/dlsym.rs b/src/shims/posix/linux/dlsym.rs index e7ffb68ff2ec0..1b7ac2754af71 100644 --- a/src/shims/posix/linux/dlsym.rs +++ b/src/shims/posix/linux/dlsym.rs @@ -3,8 +3,7 @@ use rustc_middle::mir; use crate::*; #[derive(Debug, Copy, Clone)] -pub enum Dlsym { -} +pub enum Dlsym {} impl Dlsym { // Returns an error for unsupported symbols, and None if this symbol @@ -13,7 +12,7 @@ impl Dlsym { Ok(match &*name { "__pthread_get_minstack" => None, "getrandom" => None, // std falls back to syscall(SYS_getrandom, ...) when this is NULL. - "statx" => None, // std falls back to syscall(SYS_statx, ...) when this is NULL. + "statx" => None, // std falls back to syscall(SYS_statx, ...) when this is NULL. _ => throw_unsup_format!("unsupported Linux dlsym: {}", name), }) } diff --git a/src/shims/posix/linux/foreign_items.rs b/src/shims/posix/linux/foreign_items.rs index fe989b5924dfd..f7d7706e3f5e9 100644 --- a/src/shims/posix/linux/foreign_items.rs +++ b/src/shims/posix/linux/foreign_items.rs @@ -1,8 +1,8 @@ use rustc_middle::mir; use rustc_target::spec::abi::Abi; -use crate::*; use crate::helpers::{check_abi, check_arg_count}; +use crate::*; use shims::posix::fs::EvalContextExt as _; use shims::posix::linux::sync::futex; use shims::posix::sync::EvalContextExt as _; @@ -133,24 +133,23 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // other types might be treated differently by the calling convention. for arg in args { if !matches!(arg.layout.abi, rustc_target::abi::Abi::Scalar(_)) { - throw_ub_format!("`syscall` arguments must all have scalar layout, but {} does not", arg.layout.ty); + throw_ub_format!( + "`syscall` arguments must all have scalar layout, but {} does not", + arg.layout.ty + ); } } - let sys_getrandom = this - .eval_libc("SYS_getrandom")? - .to_machine_usize(this)?; + let sys_getrandom = this.eval_libc("SYS_getrandom")?.to_machine_usize(this)?; - let sys_statx = this - .eval_libc("SYS_statx")? - .to_machine_usize(this)?; + let sys_statx = this.eval_libc("SYS_statx")?.to_machine_usize(this)?; - let sys_futex = this - .eval_libc("SYS_futex")? - .to_machine_usize(this)?; + let sys_futex = this.eval_libc("SYS_futex")?.to_machine_usize(this)?; if args.is_empty() { - throw_ub_format!("incorrect number of arguments for syscall: got 0, expected at least 1"); + throw_ub_format!( + "incorrect number of arguments for syscall: got 0, expected at least 1" + ); } match this.read_scalar(&args[0])?.to_machine_usize(this)? { // `libc::syscall(NR_GETRANDOM, buf.as_mut_ptr(), buf.len(), GRND_NONBLOCK)` @@ -158,7 +157,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx id if id == sys_getrandom => { // The first argument is the syscall id, so skip over it. if args.len() < 4 { - throw_ub_format!("incorrect number of arguments for `getrandom` syscall: got {}, expected at least 4", args.len()); + throw_ub_format!( + "incorrect number of arguments for `getrandom` syscall: got {}, expected at least 4", + args.len() + ); } getrandom(this, &args[1], &args[2], &args[3], dest)?; } @@ -167,9 +169,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx id if id == sys_statx => { // The first argument is the syscall id, so skip over it. if args.len() < 6 { - throw_ub_format!("incorrect number of arguments for `statx` syscall: got {}, expected at least 6", args.len()); + throw_ub_format!( + "incorrect number of arguments for `statx` syscall: got {}, expected at least 6", + args.len() + ); } - let result = this.linux_statx(&args[1], &args[2], &args[3], &args[4], &args[5])?; + let result = + this.linux_statx(&args[1], &args[2], &args[3], &args[4], &args[5])?; this.write_scalar(Scalar::from_machine_isize(result.into(), this), dest)?; } // `futex` is used by some synchonization primitives. @@ -200,7 +206,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Incomplete shims that we "stub out" just to get pre-main initialization code to work. // These shims are enabled only when the caller is in the standard library. - "pthread_getattr_np" if this.frame().instance.to_string().starts_with("std::sys::unix::") => { + "pthread_getattr_np" + if this.frame().instance.to_string().starts_with("std::sys::unix::") => + { check_abi(abi, Abi::C { unwind: false })?; let &[ref _thread, ref _attr] = check_arg_count(args)?; this.write_null(dest)?; diff --git a/src/shims/posix/linux/mod.rs b/src/shims/posix/linux/mod.rs index eba4a517cf5dc..498eb57c57fe0 100644 --- a/src/shims/posix/linux/mod.rs +++ b/src/shims/posix/linux/mod.rs @@ -1,3 +1,3 @@ -pub mod foreign_items; pub mod dlsym; +pub mod foreign_items; pub mod sync; diff --git a/src/shims/posix/linux/sync.rs b/src/shims/posix/linux/sync.rs index fdd11fd73e408..c5101203eb46f 100644 --- a/src/shims/posix/linux/sync.rs +++ b/src/shims/posix/linux/sync.rs @@ -18,7 +18,10 @@ pub fn futex<'tcx>( // Therefore we don't use `check_arg_count` here, but only check for the // number of arguments to fall within a range. if args.len() < 4 { - throw_ub_format!("incorrect number of arguments for `futex` syscall: got {}, expected at least 4", args.len()); + throw_ub_format!( + "incorrect number of arguments for `futex` syscall: got {}, expected at least 4", + args.len() + ); } // The first three arguments (after the syscall number itself) are the same to all futex operations: @@ -49,13 +52,18 @@ pub fn futex<'tcx>( // or *timeout expires. `timeout == null` for an infinite timeout. op if op & !futex_realtime == futex_wait => { if args.len() < 5 { - throw_ub_format!("incorrect number of arguments for `futex` syscall with `op=FUTEX_WAIT`: got {}, expected at least 5", args.len()); + throw_ub_format!( + "incorrect number of arguments for `futex` syscall with `op=FUTEX_WAIT`: got {}, expected at least 5", + args.len() + ); } let timeout = &args[4]; let timeout_time = if this.is_null(this.read_scalar(timeout)?.check_init()?)? { None } else { - this.check_no_isolation("`futex` syscall with `op=FUTEX_WAIT` and non-null timeout")?; + this.check_no_isolation( + "`futex` syscall with `op=FUTEX_WAIT` and non-null timeout", + )?; let duration = match this.read_timespec(timeout)? { Some(duration) => duration, None => { @@ -74,7 +82,11 @@ pub fn futex<'tcx>( // Check the pointer for alignment and validity. // The API requires `addr` to be a 4-byte aligned pointer, and will // use the 4 bytes at the given address as an (atomic) i32. - this.memory.check_ptr_access(addr.to_scalar()?, Size::from_bytes(4), Align::from_bytes(4).unwrap())?; + this.memory.check_ptr_access( + addr.to_scalar()?, + Size::from_bytes(4), + Align::from_bytes(4).unwrap(), + )?; // Read an `i32` through the pointer, regardless of any wrapper types. // It's not uncommon for `addr` to be passed as another type than `*mut i32`, such as `*const AtomicI32`. // FIXME: this fails if `addr` is not a pointer type. @@ -87,9 +99,14 @@ pub fn futex<'tcx>( // operations on the same futex word." // SeqCst is total order over all operations. // FIXME: check if this should be changed when weak memory orders are added. - let futex_val = this.read_scalar_at_offset_atomic( - &addr.into(), 0, this.machine.layouts.i32, AtomicReadOp::SeqCst - )?.to_i32()?; + let futex_val = this + .read_scalar_at_offset_atomic( + &addr.into(), + 0, + this.machine.layouts.i32, + AtomicReadOp::SeqCst, + )? + .to_i32()?; if val == futex_val { // The value still matches, so we block the trait make it wait for FUTEX_WAKE. this.block_thread(thread); diff --git a/src/shims/posix/macos/foreign_items.rs b/src/shims/posix/macos/foreign_items.rs index dce9eea668e63..9a7d3be1eb9aa 100644 --- a/src/shims/posix/macos/foreign_items.rs +++ b/src/shims/posix/macos/foreign_items.rs @@ -97,7 +97,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let &[ref info] = check_arg_count(args)?; let result = this.mach_timebase_info(info)?; this.write_scalar(Scalar::from_i32(result), dest)?; - }, + } // Access to command-line arguments "_NSGetArgc" => { @@ -162,4 +162,3 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(true) } } - diff --git a/src/shims/posix/macos/mod.rs b/src/shims/posix/macos/mod.rs index cadd6a8ea384e..434f5f30b5a56 100644 --- a/src/shims/posix/macos/mod.rs +++ b/src/shims/posix/macos/mod.rs @@ -1,2 +1,2 @@ -pub mod foreign_items; pub mod dlsym; +pub mod foreign_items; diff --git a/src/shims/posix/mod.rs b/src/shims/posix/mod.rs index 9916c65be0fb8..f40dfaefb92ac 100644 --- a/src/shims/posix/mod.rs +++ b/src/shims/posix/mod.rs @@ -1,5 +1,5 @@ -pub mod foreign_items; pub mod dlsym; +pub mod foreign_items; mod fs; mod sync; diff --git a/src/shims/posix/sync.rs b/src/shims/posix/sync.rs index 0688614a383d6..3b68e4eee4405 100644 --- a/src/shims/posix/sync.rs +++ b/src/shims/posix/sync.rs @@ -63,8 +63,10 @@ fn mutex_get_kind<'mir, 'tcx: 'mir>( ) -> InterpResult<'tcx, ScalarMaybeUninit> { let offset = if ecx.pointer_size().bytes() == 8 { 16 } else { 12 }; ecx.read_scalar_at_offset_atomic( - mutex_op, offset, ecx.machine.layouts.i32, - AtomicReadOp::Relaxed + mutex_op, + offset, + ecx.machine.layouts.i32, + AtomicReadOp::Relaxed, ) } @@ -75,8 +77,11 @@ fn mutex_set_kind<'mir, 'tcx: 'mir>( ) -> InterpResult<'tcx, ()> { let offset = if ecx.pointer_size().bytes() == 8 { 16 } else { 12 }; ecx.write_scalar_at_offset_atomic( - mutex_op, offset, kind, ecx.machine.layouts.i32, - AtomicWriteOp::Relaxed + mutex_op, + offset, + kind, + ecx.machine.layouts.i32, + AtomicWriteOp::Relaxed, ) } @@ -84,10 +89,7 @@ fn mutex_get_id<'mir, 'tcx: 'mir>( ecx: &MiriEvalContext<'mir, 'tcx>, mutex_op: &OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, ScalarMaybeUninit> { - ecx.read_scalar_at_offset_atomic( - mutex_op, 4, ecx.machine.layouts.u32, - AtomicReadOp::Relaxed - ) + ecx.read_scalar_at_offset_atomic(mutex_op, 4, ecx.machine.layouts.u32, AtomicReadOp::Relaxed) } fn mutex_set_id<'mir, 'tcx: 'mir>( @@ -96,8 +98,11 @@ fn mutex_set_id<'mir, 'tcx: 'mir>( id: impl Into>, ) -> InterpResult<'tcx, ()> { ecx.write_scalar_at_offset_atomic( - mutex_op, 4, id, ecx.machine.layouts.u32, - AtomicWriteOp::Relaxed + mutex_op, + 4, + id, + ecx.machine.layouts.u32, + AtomicWriteOp::Relaxed, ) } @@ -128,10 +133,7 @@ fn rwlock_get_id<'mir, 'tcx: 'mir>( ecx: &MiriEvalContext<'mir, 'tcx>, rwlock_op: &OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, ScalarMaybeUninit> { - ecx.read_scalar_at_offset_atomic( - rwlock_op, 4, ecx.machine.layouts.u32, - AtomicReadOp::Relaxed - ) + ecx.read_scalar_at_offset_atomic(rwlock_op, 4, ecx.machine.layouts.u32, AtomicReadOp::Relaxed) } fn rwlock_set_id<'mir, 'tcx: 'mir>( @@ -140,8 +142,11 @@ fn rwlock_set_id<'mir, 'tcx: 'mir>( id: impl Into>, ) -> InterpResult<'tcx, ()> { ecx.write_scalar_at_offset_atomic( - rwlock_op, 4, id, ecx.machine.layouts.u32, - AtomicWriteOp::Relaxed + rwlock_op, + 4, + id, + ecx.machine.layouts.u32, + AtomicWriteOp::Relaxed, ) } @@ -195,10 +200,7 @@ fn cond_get_id<'mir, 'tcx: 'mir>( ecx: &MiriEvalContext<'mir, 'tcx>, cond_op: &OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, ScalarMaybeUninit> { - ecx.read_scalar_at_offset_atomic( - cond_op, 4, ecx.machine.layouts.u32, - AtomicReadOp::Relaxed - ) + ecx.read_scalar_at_offset_atomic(cond_op, 4, ecx.machine.layouts.u32, AtomicReadOp::Relaxed) } fn cond_set_id<'mir, 'tcx: 'mir>( @@ -207,8 +209,11 @@ fn cond_set_id<'mir, 'tcx: 'mir>( id: impl Into>, ) -> InterpResult<'tcx, ()> { ecx.write_scalar_at_offset_atomic( - cond_op, 4, id, ecx.machine.layouts.u32, - AtomicWriteOp::Relaxed + cond_op, + 4, + id, + ecx.machine.layouts.u32, + AtomicWriteOp::Relaxed, ) } diff --git a/src/shims/posix/thread.rs b/src/shims/posix/thread.rs index fb1c018fc34ba..214a2ce411d6c 100644 --- a/src/shims/posix/thread.rs +++ b/src/shims/posix/thread.rs @@ -16,7 +16,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); this.tcx.sess.warn( - "thread support is experimental and incomplete: weak memory effects are not emulated." + "thread support is experimental and incomplete: weak memory effects are not emulated.", ); // Create the new thread @@ -31,7 +31,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx )?; // Read the function argument that will be sent to the new thread - // before the thread starts executing since reading after the + // before the thread starts executing since reading after the // context switch will incorrectly report a data-race. let fn_ptr = this.read_scalar(start_routine)?.check_init()?; let func_arg = this.read_immediate(arg)?; @@ -130,10 +130,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(0) } - fn pthread_setname_np( - &mut self, - name: Scalar, - ) -> InterpResult<'tcx> { + fn pthread_setname_np(&mut self, name: Scalar) -> InterpResult<'tcx> { let this = self.eval_context_mut(); this.assert_target_os("macos", "pthread_setname_np"); diff --git a/src/shims/time.rs b/src/shims/time.rs index 5af2e5ab67e7f..d293e4d127744 100644 --- a/src/shims/time.rs +++ b/src/shims/time.rs @@ -1,5 +1,5 @@ -use std::time::{Duration, SystemTime, Instant}; use std::convert::TryFrom; +use std::time::{Duration, Instant, SystemTime}; use crate::stacked_borrows::Tag; use crate::*; @@ -99,7 +99,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let NANOS_PER_INTERVAL = NANOS_PER_SEC / INTERVALS_PER_SEC; let SECONDS_TO_UNIX_EPOCH = INTERVALS_TO_UNIX_EPOCH / INTERVALS_PER_SEC; - let duration = system_time_to_duration(&SystemTime::now())? + Duration::from_secs(SECONDS_TO_UNIX_EPOCH); + let duration = system_time_to_duration(&SystemTime::now())? + + Duration::from_secs(SECONDS_TO_UNIX_EPOCH); let duration_ticks = u64::try_from(duration.as_nanos() / u128::from(NANOS_PER_INTERVAL)) .map_err(|_| err_unsup_format!("programs running more than 2^64 Windows ticks after the Windows epoch are not supported"))?; @@ -115,7 +116,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } #[allow(non_snake_case)] - fn QueryPerformanceCounter(&mut self, lpPerformanceCount_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + fn QueryPerformanceCounter( + &mut self, + lpPerformanceCount_op: &OpTy<'tcx, Tag>, + ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); this.assert_target_os("windows", "QueryPerformanceCounter"); @@ -124,14 +128,21 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // QueryPerformanceCounter uses a hardware counter as its basis. // Miri will emulate a counter with a resolution of 1 nanosecond. let duration = Instant::now().duration_since(this.machine.time_anchor); - let qpc = i64::try_from(duration.as_nanos()) - .map_err(|_| err_unsup_format!("programs running longer than 2^63 nanoseconds are not supported"))?; - this.write_scalar(Scalar::from_i64(qpc), &this.deref_operand(lpPerformanceCount_op)?.into())?; + let qpc = i64::try_from(duration.as_nanos()).map_err(|_| { + err_unsup_format!("programs running longer than 2^63 nanoseconds are not supported") + })?; + this.write_scalar( + Scalar::from_i64(qpc), + &this.deref_operand(lpPerformanceCount_op)?.into(), + )?; Ok(-1) // return non-zero on success } #[allow(non_snake_case)] - fn QueryPerformanceFrequency(&mut self, lpFrequency_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + fn QueryPerformanceFrequency( + &mut self, + lpFrequency_op: &OpTy<'tcx, Tag>, + ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); this.assert_target_os("windows", "QueryPerformanceFrequency"); @@ -142,7 +153,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // is consistent across all processors. // Miri emulates a "hardware" performance counter with a resolution of 1ns, // and thus 10^9 counts per second. - this.write_scalar(Scalar::from_i64(1_000_000_000), &this.deref_operand(lpFrequency_op)?.into())?; + this.write_scalar( + Scalar::from_i64(1_000_000_000), + &this.deref_operand(lpFrequency_op)?.into(), + )?; Ok(-1) // Return non-zero on success } @@ -155,8 +169,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // This returns a u64, with time units determined dynamically by `mach_timebase_info`. // We return plain nanoseconds. let duration = Instant::now().duration_since(this.machine.time_anchor); - u64::try_from(duration.as_nanos()) - .map_err(|_| err_unsup_format!("programs running longer than 2^64 nanoseconds are not supported").into()) + u64::try_from(duration.as_nanos()).map_err(|_| { + err_unsup_format!("programs running longer than 2^64 nanoseconds are not supported") + .into() + }) } fn mach_timebase_info(&mut self, info_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { @@ -169,10 +185,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Since our emulated ticks in `mach_absolute_time` *are* nanoseconds, // no scaling needs to happen. - let (numer, denom) = (1,1); + let (numer, denom) = (1, 1); let imms = [ immty_from_int_checked(numer, this.machine.layouts.u32)?, - immty_from_int_checked(denom, this.machine.layouts.u32)? + immty_from_int_checked(denom, this.machine.layouts.u32)?, ]; this.write_packed_immediates(&info, &imms)?; diff --git a/src/shims/tls.rs b/src/shims/tls.rs index 3339e3bee1999..239364508e08f 100644 --- a/src/shims/tls.rs +++ b/src/shims/tls.rs @@ -1,14 +1,14 @@ //! Implement thread-local storage. -use std::collections::BTreeMap; use std::collections::btree_map::Entry as BTreeEntry; use std::collections::hash_map::Entry as HashMapEntry; +use std::collections::BTreeMap; use log::trace; use rustc_data_structures::fx::FxHashMap; use rustc_middle::ty; -use rustc_target::abi::{Size, HasDataLayout}; +use rustc_target::abi::{HasDataLayout, Size}; use rustc_target::spec::abi::Abi; use crate::*; @@ -63,7 +63,11 @@ impl<'tcx> Default for TlsData<'tcx> { impl<'tcx> TlsData<'tcx> { /// Generate a new TLS key with the given destructor. /// `max_size` determines the integer size the key has to fit in. - pub fn create_tls_key(&mut self, dtor: Option>, max_size: Size) -> InterpResult<'tcx, TlsKey> { + pub fn create_tls_key( + &mut self, + dtor: Option>, + max_size: Size, + ) -> InterpResult<'tcx, TlsKey> { let new_key = self.next_key; self.next_key += 1; self.keys.try_insert(new_key, TlsEntry { data: Default::default(), dtor }).unwrap(); @@ -105,7 +109,7 @@ impl<'tcx> TlsData<'tcx> { &mut self, key: TlsKey, thread_id: ThreadId, - new_data: Option> + new_data: Option>, ) -> InterpResult<'tcx> { match self.keys.get_mut(&key) { Some(TlsEntry { data, .. }) => { @@ -138,14 +142,18 @@ impl<'tcx> TlsData<'tcx> { &mut self, thread: ThreadId, dtor: ty::Instance<'tcx>, - data: Scalar + data: Scalar, ) -> InterpResult<'tcx> { if self.dtors_running.contains_key(&thread) { // UB, according to libstd docs. - throw_ub_format!("setting thread's local storage destructor while destructors are already running"); + throw_ub_format!( + "setting thread's local storage destructor while destructors are already running" + ); } if self.macos_thread_dtors.insert(thread, (dtor, data)).is_some() { - throw_unsup_format!("setting more than one thread local storage destructor for the same thread is not supported"); + throw_unsup_format!( + "setting more than one thread local storage destructor for the same thread is not supported" + ); } Ok(()) } @@ -181,9 +189,7 @@ impl<'tcx> TlsData<'tcx> { Some(key) => Excluded(key), None => Unbounded, }; - for (&key, TlsEntry { data, dtor }) in - thread_local.range_mut((start, Unbounded)) - { + for (&key, TlsEntry { data, dtor }) in thread_local.range_mut((start, Unbounded)) { match data.entry(thread_id) { BTreeEntry::Occupied(entry) => { if let Some(dtor) = dtor { @@ -237,7 +243,13 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // (that would be basically https://github.com/rust-lang/miri/issues/450), // we specifically look up the static in libstd that we know is placed // in that section. - let thread_callback = this.eval_path_scalar(&["std", "sys", "windows", "thread_local_key", "p_thread_callback"])?; + let thread_callback = this.eval_path_scalar(&[ + "std", + "sys", + "windows", + "thread_local_key", + "p_thread_callback", + ])?; let thread_callback = this.memory.get_fn(thread_callback.check_init()?)?.as_instance()?; // The signature of this function is `unsafe extern "system" fn(h: c::LPVOID, dwReason: c::DWORD, pv: c::LPVOID)`. @@ -297,12 +309,11 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let dtor = match this.machine.tls.fetch_tls_dtor(last_key, active_thread) { dtor @ Some(_) => dtor, // We ran each dtor once, start over from the beginning. - None => { - this.machine.tls.fetch_tls_dtor(None, active_thread) - } + None => this.machine.tls.fetch_tls_dtor(None, active_thread), }; if let Some((instance, ptr, key)) = dtor { - this.machine.tls.dtors_running.get_mut(&active_thread).unwrap().last_dtor_key = Some(key); + this.machine.tls.dtors_running.get_mut(&active_thread).unwrap().last_dtor_key = + Some(key); trace!("Running TLS dtor {:?} on {:?} at {:?}", instance, ptr, active_thread); assert!(!this.is_null(ptr).unwrap(), "data can't be NULL when dtor is called!"); @@ -326,7 +337,6 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { - /// Schedule an active thread's TLS destructor to run on the active thread. /// Note that this function does not run the destructors itself, it just /// schedules them one by one each time it is called and reenables the @@ -349,7 +359,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // relevant function, reenabling the thread, and going back to // the scheduler. this.schedule_windows_tls_dtors()?; - return Ok(()) + return Ok(()); } } // The remaining dtors make some progress each time around the scheduler loop, @@ -361,12 +371,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // We have scheduled a MacOS dtor to run on the thread. Execute it // to completion and come back here. Scheduling a destructor // destroys it, so we will not enter this branch again. - return Ok(()) + return Ok(()); } if this.schedule_next_pthread_tls_dtor()? { // We have scheduled a pthread destructor and removed it from the // destructors list. Run it to completion and come back here. - return Ok(()) + return Ok(()); } // All dtors done! diff --git a/src/shims/windows/dlsym.rs b/src/shims/windows/dlsym.rs index 704b8872a4b03..ace6c4674ae99 100644 --- a/src/shims/windows/dlsym.rs +++ b/src/shims/windows/dlsym.rs @@ -5,8 +5,7 @@ use crate::*; use helpers::check_abi; #[derive(Debug, Copy, Clone)] -pub enum Dlsym { -} +pub enum Dlsym {} impl Dlsym { // Returns an error for unsupported symbols, and None if this symbol diff --git a/src/shims/windows/foreign_items.rs b/src/shims/windows/foreign_items.rs index 47f9544066bc4..655f6b08c2c34 100644 --- a/src/shims/windows/foreign_items.rs +++ b/src/shims/windows/foreign_items.rs @@ -75,7 +75,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "WriteFile" => { check_abi(abi, Abi::System { unwind: false })?; - let &[ref handle, ref buf, ref n, ref written_ptr, ref overlapped] = check_arg_count(args)?; + let &[ref handle, ref buf, ref n, ref written_ptr, ref overlapped] = + check_arg_count(args)?; this.read_scalar(overlapped)?.to_machine_usize(this)?; // this is a poiner, that we ignore let handle = this.read_scalar(handle)?.to_machine_isize(this)?; let buf = this.read_scalar(buf)?.check_init()?; @@ -95,17 +96,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx }; res.ok().map(|n| n as u32) } else { - throw_unsup_format!("on Windows, writing to anything except stdout/stderr is not supported") + throw_unsup_format!( + "on Windows, writing to anything except stdout/stderr is not supported" + ) }; // If there was no error, write back how much was written. if let Some(n) = written { this.write_scalar(Scalar::from_u32(n), &written_place.into())?; } // Return whether this was a success. - this.write_scalar( - Scalar::from_i32(if written.is_some() { 1 } else { 0 }), - dest, - )?; + this.write_scalar(Scalar::from_i32(if written.is_some() { 1 } else { 0 }), dest)?; } // Allocation @@ -297,11 +297,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let ptr = this.read_scalar(ptr)?.check_init()?; let len = this.read_scalar(len)?.to_u32()?; let flags = this.read_scalar(flags)?.to_u32()?; - if flags != 2 { // BCRYPT_USE_SYSTEM_PREFERRED_RNG - throw_unsup_format!("BCryptGenRandom is supported only with the BCRYPT_USE_SYSTEM_PREFERRED_RNG flag"); + if flags != 2 { + // BCRYPT_USE_SYSTEM_PREFERRED_RNG + throw_unsup_format!( + "BCryptGenRandom is supported only with the BCRYPT_USE_SYSTEM_PREFERRED_RNG flag" + ); } if algorithm.to_machine_usize(this)? != 0 { - throw_unsup_format!("BCryptGenRandom algorithm must be NULL when the flag is BCRYPT_USE_SYSTEM_PREFERRED_RNG"); + throw_unsup_format!( + "BCryptGenRandom algorithm must be NULL when the flag is BCRYPT_USE_SYSTEM_PREFERRED_RNG" + ); } this.gen_random(ptr, len.into())?; this.write_null(dest)?; // STATUS_SUCCESS @@ -342,27 +347,35 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Incomplete shims that we "stub out" just to get pre-main initialization code to work. // These shims are enabled only when the caller is in the standard library. - "GetProcessHeap" if this.frame().instance.to_string().starts_with("std::sys::windows::") => { + "GetProcessHeap" + if this.frame().instance.to_string().starts_with("std::sys::windows::") => + { check_abi(abi, Abi::System { unwind: false })?; let &[] = check_arg_count(args)?; // Just fake a HANDLE this.write_scalar(Scalar::from_machine_isize(1, this), dest)?; } - "SetConsoleTextAttribute" if this.frame().instance.to_string().starts_with("std::sys::windows::") => { + "SetConsoleTextAttribute" + if this.frame().instance.to_string().starts_with("std::sys::windows::") => + { check_abi(abi, Abi::System { unwind: false })?; #[allow(non_snake_case)] let &[ref _hConsoleOutput, ref _wAttribute] = check_arg_count(args)?; // Pretend these does not exist / nothing happened, by returning zero. this.write_null(dest)?; } - "AddVectoredExceptionHandler" if this.frame().instance.to_string().starts_with("std::sys::windows::") => { + "AddVectoredExceptionHandler" + if this.frame().instance.to_string().starts_with("std::sys::windows::") => + { check_abi(abi, Abi::System { unwind: false })?; #[allow(non_snake_case)] let &[ref _First, ref _Handler] = check_arg_count(args)?; // Any non zero value works for the stdlib. This is just used for stack overflows anyway. this.write_scalar(Scalar::from_machine_usize(1, this), dest)?; } - "SetThreadStackGuarantee" if this.frame().instance.to_string().starts_with("std::sys::windows::") => { + "SetThreadStackGuarantee" + if this.frame().instance.to_string().starts_with("std::sys::windows::") => + { check_abi(abi, Abi::System { unwind: false })?; #[allow(non_snake_case)] let &[_StackSizeInBytes] = check_arg_count(args)?; @@ -373,21 +386,31 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "EnterCriticalSection" | "LeaveCriticalSection" | "DeleteCriticalSection" - if this.frame().instance.to_string().starts_with("std::sys::windows::") => { + if this.frame().instance.to_string().starts_with("std::sys::windows::") => + { check_abi(abi, Abi::System { unwind: false })?; #[allow(non_snake_case)] let &[ref _lpCriticalSection] = check_arg_count(args)?; - assert_eq!(this.get_total_thread_count(), 1, "concurrency on Windows is not supported"); + assert_eq!( + this.get_total_thread_count(), + 1, + "concurrency on Windows is not supported" + ); // Nothing to do, not even a return value. // (Windows locks are reentrant, and we have only 1 thread, // so not doing any futher checks here is at least not incorrect.) } "TryEnterCriticalSection" - if this.frame().instance.to_string().starts_with("std::sys::windows::") => { + if this.frame().instance.to_string().starts_with("std::sys::windows::") => + { check_abi(abi, Abi::System { unwind: false })?; #[allow(non_snake_case)] let &[ref _lpCriticalSection] = check_arg_count(args)?; - assert_eq!(this.get_total_thread_count(), 1, "concurrency on Windows is not supported"); + assert_eq!( + this.get_total_thread_count(), + 1, + "concurrency on Windows is not supported" + ); // There is only one thread, so this always succeeds and returns TRUE. this.write_scalar(Scalar::from_i32(1), dest)?; } @@ -398,4 +421,3 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(true) } } - diff --git a/src/shims/windows/mod.rs b/src/shims/windows/mod.rs index 04f9ace8e799b..668d69966bc4c 100644 --- a/src/shims/windows/mod.rs +++ b/src/shims/windows/mod.rs @@ -1,4 +1,4 @@ -pub mod foreign_items; pub mod dlsym; +pub mod foreign_items; mod sync; diff --git a/src/shims/windows/sync.rs b/src/shims/windows/sync.rs index caf8942afd930..78458dc6c9977 100644 --- a/src/shims/windows/sync.rs +++ b/src/shims/windows/sync.rs @@ -22,10 +22,7 @@ fn srwlock_get_or_create_id<'mir, 'tcx: 'mir>( impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { #[allow(non_snake_case)] - fn AcquireSRWLockExclusive( - &mut self, - lock_op: &OpTy<'tcx, Tag>, - ) -> InterpResult<'tcx> { + fn AcquireSRWLockExclusive(&mut self, lock_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let id = srwlock_get_or_create_id(this, lock_op)?; let active_thread = this.get_active_thread(); @@ -47,10 +44,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } #[allow(non_snake_case)] - fn TryAcquireSRWLockExclusive( - &mut self, - lock_op: &OpTy<'tcx, Tag>, - ) -> InterpResult<'tcx, u8> { + fn TryAcquireSRWLockExclusive(&mut self, lock_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, u8> { let this = self.eval_context_mut(); let id = srwlock_get_or_create_id(this, lock_op)?; let active_thread = this.get_active_thread(); @@ -65,27 +59,23 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } #[allow(non_snake_case)] - fn ReleaseSRWLockExclusive( - &mut self, - lock_op: &OpTy<'tcx, Tag>, - ) -> InterpResult<'tcx> { + fn ReleaseSRWLockExclusive(&mut self, lock_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let id = srwlock_get_or_create_id(this, lock_op)?; let active_thread = this.get_active_thread(); if !this.rwlock_writer_unlock(id, active_thread) { // The docs do not say anything about this case, but it seems better to not allow it. - throw_ub_format!("calling ReleaseSRWLockExclusive on an SRWLock that is not exclusively locked by the current thread"); + throw_ub_format!( + "calling ReleaseSRWLockExclusive on an SRWLock that is not exclusively locked by the current thread" + ); } Ok(()) } #[allow(non_snake_case)] - fn AcquireSRWLockShared( - &mut self, - lock_op: &OpTy<'tcx, Tag>, - ) -> InterpResult<'tcx> { + fn AcquireSRWLockShared(&mut self, lock_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let id = srwlock_get_or_create_id(this, lock_op)?; let active_thread = this.get_active_thread(); @@ -100,10 +90,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } #[allow(non_snake_case)] - fn TryAcquireSRWLockShared( - &mut self, - lock_op: &OpTy<'tcx, Tag>, - ) -> InterpResult<'tcx, u8> { + fn TryAcquireSRWLockShared(&mut self, lock_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, u8> { let this = self.eval_context_mut(); let id = srwlock_get_or_create_id(this, lock_op)?; let active_thread = this.get_active_thread(); @@ -117,17 +104,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } #[allow(non_snake_case)] - fn ReleaseSRWLockShared( - &mut self, - lock_op: &OpTy<'tcx, Tag>, - ) -> InterpResult<'tcx> { + fn ReleaseSRWLockShared(&mut self, lock_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let id = srwlock_get_or_create_id(this, lock_op)?; let active_thread = this.get_active_thread(); if !this.rwlock_reader_unlock(id, active_thread) { // The docs do not say anything about this case, but it seems better to not allow it. - throw_ub_format!("calling ReleaseSRWLockShared on an SRWLock that is not locked by the current thread"); + throw_ub_format!( + "calling ReleaseSRWLockShared on an SRWLock that is not locked by the current thread" + ); } Ok(()) diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index fbcd265baa113..88f42efd13cf0 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -9,10 +9,10 @@ use std::rc::Rc; use log::trace; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_hir::Mutability; use rustc_middle::mir::RetagKind; use rustc_middle::ty; use rustc_target::abi::{Align, LayoutOf, Size}; -use rustc_hir::Mutability; use crate::*; @@ -157,7 +157,11 @@ impl fmt::Display for RefKind { /// Utilities for initialization and ID generation impl GlobalState { - pub fn new(tracked_pointer_tag: Option, tracked_call_id: Option, track_raw: bool) -> Self { + pub fn new( + tracked_pointer_tag: Option, + tracked_call_id: Option, + track_raw: bool, + ) -> Self { GlobalState { next_ptr_id: NonZeroU64::new(1).unwrap(), base_ptr_ids: FxHashMap::default(), @@ -211,7 +215,9 @@ impl GlobalState { fn err_sb_ub(msg: String) -> InterpError<'static> { err_machine_stop!(TerminationInfo::ExperimentalUb { msg, - url: format!("https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md"), + url: format!( + "https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md" + ), }) } @@ -300,10 +306,7 @@ impl<'tcx> Stack { tag, item )))? } else { - Err(err_sb_ub(format!( - "deallocating while item is protected: {:?}", - item - )))? + Err(err_sb_ub(format!("deallocating while item is protected: {:?}", item)))? } } } @@ -312,14 +315,21 @@ impl<'tcx> Stack { /// Test if a memory `access` using pointer tagged `tag` is granted. /// If yes, return the index of the item that granted it. - fn access(&mut self, access: AccessKind, ptr: Pointer, global: &GlobalState) -> InterpResult<'tcx> { + fn access( + &mut self, + access: AccessKind, + ptr: Pointer, + global: &GlobalState, + ) -> InterpResult<'tcx> { // Two main steps: Find granting item, remove incompatible items above. // Step 1: Find granting item. let granting_idx = self.find_granting(access, ptr.tag).ok_or_else(|| { err_sb_ub(format!( "no item granting {} to tag {:?} at {} found in borrow stack.", - access, ptr.tag, ptr.erase_tag(), + access, + ptr.tag, + ptr.erase_tag(), )) })?; @@ -379,7 +389,12 @@ impl<'tcx> Stack { /// `weak` controls whether this operation is weak or strong: weak granting does not act as /// an access, and they add the new item directly on top of the one it is derived /// from instead of all the way at the top of the stack. - fn grant(&mut self, derived_from: Pointer, new: Item, global: &GlobalState) -> InterpResult<'tcx> { + fn grant( + &mut self, + derived_from: Pointer, + new: Item, + global: &GlobalState, + ) -> InterpResult<'tcx> { // Figure out which access `perm` corresponds to. let access = if new.perm.grants(AccessKind::Write) { AccessKind::Write } else { AccessKind::Read }; @@ -480,12 +495,17 @@ impl Stacks { // `ExternStatic` is used for extern statics, and thus must also be listed here. // `Env` we list because we can get away with precise tracking there. // The base pointer is not unique, so the base permission is `SharedReadWrite`. - MemoryKind::Machine(MiriMemoryKind::Global | MiriMemoryKind::ExternStatic | MiriMemoryKind::Tls | MiriMemoryKind::Env) => - (extra.borrow_mut().global_base_ptr(id), Permission::SharedReadWrite), + MemoryKind::Machine( + MiriMemoryKind::Global + | MiriMemoryKind::ExternStatic + | MiriMemoryKind::Tls + | MiriMemoryKind::Env, + ) => (extra.borrow_mut().global_base_ptr(id), Permission::SharedReadWrite), // Everything else we handle like raw pointers for now. _ => { let mut extra = extra.borrow_mut(); - let tag = if extra.track_raw { Tag::Tagged(extra.new_ptr()) } else { Tag::Untagged }; + let tag = + if extra.track_raw { Tag::Tagged(extra.new_ptr()) } else { Tag::Untagged }; (tag, Permission::SharedReadWrite) } }; @@ -584,9 +604,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); // We want a place for where the ptr *points to*, so we get one. let place = this.ref_to_mplace(val)?; - let size = this - .size_and_align_of_mplace(&place)? - .map(|(size, _)| size); + let size = this.size_and_align_of_mplace(&place)?.map(|(size, _)| size); // FIXME: If we cannot determine the size (because the unsized tail is an `extern type`), // bail out -- we cannot reasonably figure out which memory range to reborrow. // See https://github.com/rust-lang/unsafe-code-guidelines/issues/276. @@ -667,7 +685,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// After a stack frame got pushed, retag the return place so that we are sure /// it does not alias with anything. - /// + /// /// This is a HACK because there is nothing in MIR that would make the retag /// explicit. Also see https://github.com/rust-lang/rust/issues/71117. fn retag_return_place(&mut self) -> InterpResult<'tcx> { @@ -690,7 +708,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let ptr_layout = this.layout_of(this.tcx.mk_mut_ptr(return_place.layout.ty))?; let val = ImmTy::from_immediate(return_place.to_ref(), ptr_layout); // Reborrow it. - let val = this.retag_reference(&val, RefKind::Unique { two_phase: false }, /*protector*/ true)?; + let val = this.retag_reference( + &val, + RefKind::Unique { two_phase: false }, + /*protector*/ true, + )?; // And use reborrowed pointer for return place. let return_place = this.ref_to_mplace(&val)?; this.frame_mut().return_place = Some(return_place.into()); diff --git a/src/sync.rs b/src/sync.rs index 4d488565faf3e..b53af0aeb24ae 100644 --- a/src/sync.rs +++ b/src/sync.rs @@ -66,7 +66,7 @@ struct Mutex { /// released to during unlock and acquired from during /// locking, and therefore stores the clock of the last /// thread to release this mutex. - data_race: VClock + data_race: VClock, } declare_id!(RwLockId); @@ -98,7 +98,7 @@ struct RwLock { /// is stored to the main data_race variable once all /// readers are finished. /// Has to be stored separately since reader lock acquires - /// must load the clock of the last write and must not + /// must load the clock of the last write and must not /// add happens-before orderings between shared reader /// locks. data_race_reader: VClock, @@ -251,11 +251,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// count. If the lock count reaches 0, release the lock and potentially /// give to a new owner. If the lock was not locked by `expected_owner`, /// return `None`. - fn mutex_unlock( - &mut self, - id: MutexId, - expected_owner: ThreadId, - ) -> Option { + fn mutex_unlock(&mut self, id: MutexId, expected_owner: ThreadId) -> Option { let this = self.eval_context_mut(); let mutex = &mut this.machine.threads.sync.mutexes[id]; if let Some(current_owner) = mutex.owner { @@ -307,9 +303,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let rwlock = &this.machine.threads.sync.rwlocks[id]; trace!( "rwlock_is_locked: {:?} writer is {:?} and there are {} reader threads (some of which could hold multiple read locks)", - id, rwlock.writer, rwlock.readers.len(), + id, + rwlock.writer, + rwlock.readers.len(), ); - rwlock.writer.is_some()|| rwlock.readers.is_empty().not() + rwlock.writer.is_some() || rwlock.readers.is_empty().not() } #[inline] @@ -360,7 +358,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // The thread was a reader. If the lock is not held any more, give it to a writer. if this.rwlock_is_locked(id).not() { - // All the readers are finished, so set the writer data-race handle to the value // of the union of all reader data race handles, since the set of readers // happen-before the writers @@ -373,11 +370,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx #[inline] /// Put the reader in the queue waiting for the lock and block it. - fn rwlock_enqueue_and_block_reader( - &mut self, - id: RwLockId, - reader: ThreadId, - ) { + fn rwlock_enqueue_and_block_reader(&mut self, id: RwLockId, reader: ThreadId) { let this = self.eval_context_mut(); assert!(this.rwlock_is_write_locked(id), "read-queueing on not write locked rwlock"); this.machine.threads.sync.rwlocks[id].reader_queue.push_back(reader); @@ -437,11 +430,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx #[inline] /// Put the writer in the queue waiting for the lock. - fn rwlock_enqueue_and_block_writer( - &mut self, - id: RwLockId, - writer: ThreadId, - ) { + fn rwlock_enqueue_and_block_writer(&mut self, id: RwLockId, writer: ThreadId) { let this = self.eval_context_mut(); assert!(this.rwlock_is_locked(id), "write-queueing on unlocked rwlock"); this.machine.threads.sync.rwlocks[id].writer_queue.push_back(writer); @@ -482,14 +471,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if let Some(data_race) = data_race { data_race.validate_lock_release(&mut condvar.data_race, current_thread); } - condvar.waiters - .pop_front() - .map(|waiter| { - if let Some(data_race) = data_race { - data_race.validate_lock_acquire(&mut condvar.data_race, waiter.thread); - } - (waiter.thread, waiter.mutex) - }) + condvar.waiters.pop_front().map(|waiter| { + if let Some(data_race) = data_race { + data_race.validate_lock_acquire(&mut condvar.data_race, waiter.thread); + } + (waiter.thread, waiter.mutex) + }) } #[inline] @@ -511,7 +498,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); let current_thread = this.get_active_thread(); let futex = &mut this.machine.threads.sync.futexes.get_mut(&addr.erase_tag())?; - let data_race = &this.memory.extra.data_race; + let data_race = &this.memory.extra.data_race; // Each futex-wake happens-before the end of the futex wait if let Some(data_race) = data_race { @@ -519,7 +506,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } let res = futex.waiters.pop_front().map(|waiter| { if let Some(data_race) = data_race { - data_race.validate_lock_acquire(&futex.data_race, waiter.thread); + data_race.validate_lock_acquire(&futex.data_race, waiter.thread); } waiter.thread }); diff --git a/src/thread.rs b/src/thread.rs index 8b1787132cbcc..7d6fe8041e980 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -3,8 +3,8 @@ use std::cell::RefCell; use std::collections::hash_map::Entry; use std::convert::TryFrom; -use std::rc::Rc; use std::num::TryFromIntError; +use std::rc::Rc; use std::time::{Duration, Instant, SystemTime}; use log::trace; @@ -141,17 +141,19 @@ impl<'mir, 'tcx> Thread<'mir, 'tcx> { /// Get the name of the current thread, or `` if it was not set. fn thread_name(&self) -> &[u8] { - if let Some(ref thread_name) = self.thread_name { - thread_name - } else { - b"" - } + if let Some(ref thread_name) = self.thread_name { thread_name } else { b"" } } } impl<'mir, 'tcx> std::fmt::Debug for Thread<'mir, 'tcx> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{}({:?}, {:?})", String::from_utf8_lossy(self.thread_name()), self.state, self.join_status) + write!( + f, + "{}({:?}, {:?})", + String::from_utf8_lossy(self.thread_name()), + self.state, + self.join_status + ) } } @@ -328,7 +330,11 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { } /// Mark that the active thread tries to join the thread with `joined_thread_id`. - fn join_thread(&mut self, joined_thread_id: ThreadId, data_race: &Option>) -> InterpResult<'tcx> { + fn join_thread( + &mut self, + joined_thread_id: ThreadId, + data_race: &Option>, + ) -> InterpResult<'tcx> { if self.threads[joined_thread_id].join_status != ThreadJoinStatus::Joinable { throw_ub_format!("trying to join a detached or already joined thread"); } @@ -431,7 +437,10 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { /// Wakes up threads joining on the active one and deallocates thread-local statics. /// The `AllocId` that can now be freed is returned. - fn thread_terminated(&mut self, data_race: &Option>) -> Vec { + fn thread_terminated( + &mut self, + data_race: &Option>, + ) -> Vec { let mut free_tls_statics = Vec::new(); { let mut thread_local_statics = self.thread_local_alloc_ids.borrow_mut(); @@ -470,7 +479,10 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { /// used in stateless model checkers such as Loom: run the active thread as /// long as we can and switch only when we have to (the active thread was /// blocked, terminated, or has explicitly asked to be preempted). - fn schedule(&mut self, data_race: &Option>) -> InterpResult<'tcx, SchedulingAction> { + fn schedule( + &mut self, + data_race: &Option>, + ) -> InterpResult<'tcx, SchedulingAction> { // Check whether the thread has **just** terminated (`check_terminated` // checks whether the thread has popped all its stack and if yes, sets // the thread state to terminated). @@ -546,7 +558,10 @@ impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mi pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { /// Get a thread-specific allocation id for the given thread-local static. /// If needed, allocate a new one. - fn get_or_create_thread_local_alloc_id(&mut self, def_id: DefId) -> InterpResult<'tcx, AllocId> { + fn get_or_create_thread_local_alloc_id( + &mut self, + def_id: DefId, + ) -> InterpResult<'tcx, AllocId> { let this = self.eval_context_mut(); let tcx = this.tcx; if let Some(new_alloc_id) = this.machine.threads.get_thread_local_alloc_id(def_id) { @@ -562,7 +577,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } let allocation = tcx.eval_static_initializer(def_id)?; // Create a fresh allocation with this content. - let new_alloc_id = this.memory.allocate_with(allocation.clone(), MiriMemoryKind::Tls.into()).alloc_id; + let new_alloc_id = + this.memory.allocate_with(allocation.clone(), MiriMemoryKind::Tls.into()).alloc_id; this.machine.threads.set_thread_local_alloc_id(def_id, new_alloc_id); Ok(new_alloc_id) } @@ -654,9 +670,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); if let Some(data_race) = &this.memory.extra.data_race { if let Ok(string) = String::from_utf8(new_thread_name.clone()) { - data_race.thread_set_name( - this.machine.threads.active_thread, string - ); + data_race.thread_set_name(this.machine.threads.active_thread, string); } } this.machine.threads.set_thread_name(new_thread_name); diff --git a/src/vector_clock.rs b/src/vector_clock.rs index 1ce6511ee4aeb..a2e235858d83a 100644 --- a/src/vector_clock.rs +++ b/src/vector_clock.rs @@ -1,11 +1,6 @@ use rustc_index::vec::Idx; use smallvec::SmallVec; -use std::{ - cmp::Ordering, - convert::TryFrom, - fmt::Debug, - ops::Index, -}; +use std::{cmp::Ordering, convert::TryFrom, fmt::Debug, ops::Index}; /// A vector clock index, this is associated with a thread id /// but in some cases one vector index may be shared with From d6fdfaa0475833171756d4b4236114c2af066395 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 16 May 2021 11:48:08 +0200 Subject: [PATCH 2653/3747] hand-held formatting for remaining files --- src/diagnostics.rs | 70 +++--- src/shims/foreign_items.rs | 15 +- src/shims/intrinsics.rs | 436 +++++++++++++------------------------ 3 files changed, 201 insertions(+), 320 deletions(-) diff --git a/src/diagnostics.rs b/src/diagnostics.rs index 45c0996355bff..f074cfd4911bf 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -22,16 +22,11 @@ impl fmt::Display for TerminationInfo { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { use TerminationInfo::*; match self { - Exit(code) => - write!(f, "the evaluated program completed with exit code {}", code), - Abort(msg) => - write!(f, "{}", msg), - UnsupportedInIsolation(msg) => - write!(f, "{}", msg), - ExperimentalUb { msg, .. } => - write!(f, "{}", msg), - Deadlock => - write!(f, "the evaluated program deadlocked"), + Exit(code) => write!(f, "the evaluated program completed with exit code {}", code), + Abort(msg) => write!(f, "{}", msg), + UnsupportedInIsolation(msg) => write!(f, "{}", msg), + ExperimentalUb { msg, .. } => write!(f, "{}", msg), + Deadlock => write!(f, "the evaluated program deadlocked"), } } } @@ -60,14 +55,12 @@ pub fn report_error<'tcx, 'mir>( use TerminationInfo::*; let title = match info { Exit(code) => return Some(*code), - Abort(_) => - "abnormal termination", - UnsupportedInIsolation(_) => - "unsupported operation", - ExperimentalUb { .. } => - "Undefined Behavior", + Abort(_) => "abnormal termination", + UnsupportedInIsolation(_) => "unsupported operation", + ExperimentalUb { .. } => "Undefined Behavior", Deadlock => "deadlock", }; + #[rustfmt::skip] let helps = match info { UnsupportedInIsolation(_) => vec![format!("pass the flag `-Zmiri-disable-isolation` to disable isolation")], @@ -81,6 +74,7 @@ pub fn report_error<'tcx, 'mir>( (title, helps) } _ => { + #[rustfmt::skip] let title = match e.kind() { Unsupported(_) => "unsupported operation", @@ -93,6 +87,7 @@ pub fn report_error<'tcx, 'mir>( _ => bug!("This error should be impossible in Miri: {}", e), }; + #[rustfmt::skip] let helps = match e.kind() { Unsupported(UnsupportedOpInfo::NoMirFor(..)) => vec![format!("make sure to use a Miri sysroot, which you can prepare with `cargo miri setup`")], @@ -120,7 +115,14 @@ pub fn report_error<'tcx, 'mir>( e.print_backtrace(); let msg = e.to_string(); - report_msg(*ecx.tcx, /*error*/true, &format!("{}: {}", title, msg), msg, helps, &ecx.generate_stacktrace()); + report_msg( + *ecx.tcx, + /*error*/ true, + &format!("{}: {}", title, msg), + msg, + helps, + &ecx.generate_stacktrace(), + ); // Debug-dump all locals. for (i, frame) in ecx.active_thread_stack().iter().enumerate() { @@ -249,7 +251,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // Add popped frame back. if stacktrace.len() < info.stack_size { - assert!(stacktrace.len() == info.stack_size-1, "we should never pop more than one frame at once"); + assert!( + stacktrace.len() == info.stack_size - 1, + "we should never pop more than one frame at once" + ); let frame_info = FrameInfo { instance: info.instance.unwrap(), span: info.span, @@ -259,25 +264,30 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } else if let Some(instance) = info.instance { // Adjust topmost frame. stacktrace[0].span = info.span; - assert_eq!(stacktrace[0].instance, instance, "we should not pop and push a frame in one step"); + assert_eq!( + stacktrace[0].instance, instance, + "we should not pop and push a frame in one step" + ); } // Show diagnostics. for e in diagnostics.drain(..) { use NonHaltingDiagnostic::*; let msg = match e { - CreatedPointerTag(tag) => - format!("created tag {:?}", tag), - PoppedPointerTag(item) => - format!("popped tracked tag for item {:?}", item), - CreatedCallId(id) => - format!("function call with id {}", id), - CreatedAlloc(AllocId(id)) => - format!("created allocation with id {}", id), - FreedAlloc(AllocId(id)) => - format!("freed allocation with id {}", id), + CreatedPointerTag(tag) => format!("created tag {:?}", tag), + PoppedPointerTag(item) => format!("popped tracked tag for item {:?}", item), + CreatedCallId(id) => format!("function call with id {}", id), + CreatedAlloc(AllocId(id)) => format!("created allocation with id {}", id), + FreedAlloc(AllocId(id)) => format!("freed allocation with id {}", id), }; - report_msg(*this.tcx, /*error*/false, "tracking was triggered", msg, vec![], &stacktrace); + report_msg( + *this.tcx, + /*error*/ false, + "tracking was triggered", + msg, + vec![], + &stacktrace, + ); } }); } diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 371a50f0e4b2e..6867871794a8d 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -114,7 +114,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// by this function. /// Returns Ok(Some(body)) if processing the foreign item /// is delegated to another function. - #[rustfmt::skip] fn emulate_foreign_item( &mut self, def_id: DefId, @@ -149,6 +148,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let panic_impl_instance = ty::Instance::mono(tcx, panic_impl_id); return Ok(Some(&*this.load_mir(panic_impl_instance.def, None)?)); } + #[rustfmt::skip] | "exit" | "ExitProcess" => { @@ -160,7 +160,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "abort" => { check_abi(abi, Abi::C { unwind: false })?; - throw_machine_stop!(TerminationInfo::Abort("the program aborted execution".to_owned())) + throw_machine_stop!(TerminationInfo::Abort( + "the program aborted execution".to_owned() + )) } _ => throw_unsup_format!("can't call (diverging) foreign function: {}", link_name), }, @@ -175,7 +177,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // We forward this to the underlying *implementation* in the panic runtime crate. // Normally, this will be either `libpanic_unwind` or `libpanic_abort`, but it could // also be a custom user-provided implementation via `#![feature(panic_runtime)]` - "__rust_start_panic" | "__rust_panic_cleanup" => { + #[rustfmt::skip] + "__rust_start_panic" | + "__rust_panic_cleanup" => { check_abi(abi, Abi::C { unwind: false })?; // This replicates some of the logic in `inject_panic_runtime`. // FIXME: is there a way to reuse that logic? @@ -406,6 +410,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // math functions + #[rustfmt::skip] | "cbrtf" | "coshf" | "sinhf" @@ -430,6 +435,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx }; this.write_scalar(Scalar::from_u32(f.to_bits()), dest)?; } + #[rustfmt::skip] | "_hypotf" | "hypotf" | "atan2f" @@ -448,6 +454,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx }; this.write_scalar(Scalar::from_u32(n.to_bits()), dest)?; } + #[rustfmt::skip] | "cbrt" | "cosh" | "sinh" @@ -472,6 +479,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx }; this.write_scalar(Scalar::from_u64(f.to_bits()), dest)?; } + #[rustfmt::skip] | "_hypot" | "hypot" | "atan2" @@ -488,6 +496,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx }; this.write_scalar(Scalar::from_u64(n.to_bits()), dest)?; } + #[rustfmt::skip] | "_ldexp" | "ldexp" | "scalbn" diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index b33b9666f7129..ee0e833f9e5f1 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -330,312 +330,174 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "atomic_xchg_acqrel" => this.atomic_exchange(args, dest, AtomicRwOp::AcqRel)?, "atomic_xchg_relaxed" => this.atomic_exchange(args, dest, AtomicRwOp::Relaxed)?, + #[rustfmt::skip] "atomic_cxchg" => this.atomic_compare_exchange(args, dest, AtomicRwOp::SeqCst, AtomicReadOp::SeqCst)?, - "atomic_cxchg_acq" => this.atomic_compare_exchange( - args, - dest, - AtomicRwOp::Acquire, - AtomicReadOp::Acquire, - )?, - "atomic_cxchg_rel" => this.atomic_compare_exchange( - args, - dest, - AtomicRwOp::Release, - AtomicReadOp::Relaxed, - )?, + #[rustfmt::skip] + "atomic_cxchg_acq" => + this.atomic_compare_exchange(args, dest, AtomicRwOp::Acquire, AtomicReadOp::Acquire)?, + #[rustfmt::skip] + "atomic_cxchg_rel" => + this.atomic_compare_exchange(args, dest, AtomicRwOp::Release, AtomicReadOp::Relaxed)?, + #[rustfmt::skip] "atomic_cxchg_acqrel" => this.atomic_compare_exchange(args, dest, AtomicRwOp::AcqRel, AtomicReadOp::Acquire)?, - "atomic_cxchg_relaxed" => this.atomic_compare_exchange( - args, - dest, - AtomicRwOp::Relaxed, - AtomicReadOp::Relaxed, - )?, - "atomic_cxchg_acq_failrelaxed" => this.atomic_compare_exchange( - args, - dest, - AtomicRwOp::Acquire, - AtomicReadOp::Relaxed, - )?, + #[rustfmt::skip] + "atomic_cxchg_relaxed" => + this.atomic_compare_exchange(args, dest, AtomicRwOp::Relaxed, AtomicReadOp::Relaxed)?, + #[rustfmt::skip] + "atomic_cxchg_acq_failrelaxed" => + this.atomic_compare_exchange(args, dest, AtomicRwOp::Acquire, AtomicReadOp::Relaxed)?, + #[rustfmt::skip] "atomic_cxchg_acqrel_failrelaxed" => this.atomic_compare_exchange(args, dest, AtomicRwOp::AcqRel, AtomicReadOp::Relaxed)?, + #[rustfmt::skip] "atomic_cxchg_failrelaxed" => this.atomic_compare_exchange(args, dest, AtomicRwOp::SeqCst, AtomicReadOp::Relaxed)?, + #[rustfmt::skip] "atomic_cxchg_failacq" => this.atomic_compare_exchange(args, dest, AtomicRwOp::SeqCst, AtomicReadOp::Acquire)?, - "atomic_cxchgweak" => this.atomic_compare_exchange_weak( - args, - dest, - AtomicRwOp::SeqCst, - AtomicReadOp::SeqCst, - )?, - "atomic_cxchgweak_acq" => this.atomic_compare_exchange_weak( - args, - dest, - AtomicRwOp::Acquire, - AtomicReadOp::Acquire, - )?, - "atomic_cxchgweak_rel" => this.atomic_compare_exchange_weak( - args, - dest, - AtomicRwOp::Release, - AtomicReadOp::Relaxed, - )?, - "atomic_cxchgweak_acqrel" => this.atomic_compare_exchange_weak( - args, - dest, - AtomicRwOp::AcqRel, - AtomicReadOp::Acquire, - )?, - "atomic_cxchgweak_relaxed" => this.atomic_compare_exchange_weak( - args, - dest, - AtomicRwOp::Relaxed, - AtomicReadOp::Relaxed, - )?, - "atomic_cxchgweak_acq_failrelaxed" => this.atomic_compare_exchange_weak( - args, - dest, - AtomicRwOp::Acquire, - AtomicReadOp::Relaxed, - )?, - "atomic_cxchgweak_acqrel_failrelaxed" => this.atomic_compare_exchange_weak( - args, - dest, - AtomicRwOp::AcqRel, - AtomicReadOp::Relaxed, - )?, - "atomic_cxchgweak_failrelaxed" => this.atomic_compare_exchange_weak( - args, - dest, - AtomicRwOp::SeqCst, - AtomicReadOp::Relaxed, - )?, - "atomic_cxchgweak_failacq" => this.atomic_compare_exchange_weak( - args, - dest, - AtomicRwOp::SeqCst, - AtomicReadOp::Acquire, - )?, - - "atomic_or" => this.atomic_op( - args, - dest, - AtomicOp::MirOp(BinOp::BitOr, false), - AtomicRwOp::SeqCst, - )?, - "atomic_or_acq" => this.atomic_op( - args, - dest, - AtomicOp::MirOp(BinOp::BitOr, false), - AtomicRwOp::Acquire, - )?, - "atomic_or_rel" => this.atomic_op( - args, - dest, - AtomicOp::MirOp(BinOp::BitOr, false), - AtomicRwOp::Release, - )?, - "atomic_or_acqrel" => this.atomic_op( - args, - dest, - AtomicOp::MirOp(BinOp::BitOr, false), - AtomicRwOp::AcqRel, - )?, - "atomic_or_relaxed" => this.atomic_op( - args, - dest, - AtomicOp::MirOp(BinOp::BitOr, false), - AtomicRwOp::Relaxed, - )?, - "atomic_xor" => this.atomic_op( - args, - dest, - AtomicOp::MirOp(BinOp::BitXor, false), - AtomicRwOp::SeqCst, - )?, - "atomic_xor_acq" => this.atomic_op( - args, - dest, - AtomicOp::MirOp(BinOp::BitXor, false), - AtomicRwOp::Acquire, - )?, - "atomic_xor_rel" => this.atomic_op( - args, - dest, - AtomicOp::MirOp(BinOp::BitXor, false), - AtomicRwOp::Release, - )?, - "atomic_xor_acqrel" => this.atomic_op( - args, - dest, - AtomicOp::MirOp(BinOp::BitXor, false), - AtomicRwOp::AcqRel, - )?, - "atomic_xor_relaxed" => this.atomic_op( - args, - dest, - AtomicOp::MirOp(BinOp::BitXor, false), - AtomicRwOp::Relaxed, - )?, - "atomic_and" => this.atomic_op( - args, - dest, - AtomicOp::MirOp(BinOp::BitAnd, false), - AtomicRwOp::SeqCst, - )?, - "atomic_and_acq" => this.atomic_op( - args, - dest, - AtomicOp::MirOp(BinOp::BitAnd, false), - AtomicRwOp::Acquire, - )?, - "atomic_and_rel" => this.atomic_op( - args, - dest, - AtomicOp::MirOp(BinOp::BitAnd, false), - AtomicRwOp::Release, - )?, - "atomic_and_acqrel" => this.atomic_op( - args, - dest, - AtomicOp::MirOp(BinOp::BitAnd, false), - AtomicRwOp::AcqRel, - )?, - "atomic_and_relaxed" => this.atomic_op( - args, - dest, - AtomicOp::MirOp(BinOp::BitAnd, false), - AtomicRwOp::Relaxed, - )?, - "atomic_nand" => this.atomic_op( - args, - dest, - AtomicOp::MirOp(BinOp::BitAnd, true), - AtomicRwOp::SeqCst, - )?, - "atomic_nand_acq" => this.atomic_op( - args, - dest, - AtomicOp::MirOp(BinOp::BitAnd, true), - AtomicRwOp::Acquire, - )?, - "atomic_nand_rel" => this.atomic_op( - args, - dest, - AtomicOp::MirOp(BinOp::BitAnd, true), - AtomicRwOp::Release, - )?, - "atomic_nand_acqrel" => this.atomic_op( - args, - dest, - AtomicOp::MirOp(BinOp::BitAnd, true), - AtomicRwOp::AcqRel, - )?, - "atomic_nand_relaxed" => this.atomic_op( - args, - dest, - AtomicOp::MirOp(BinOp::BitAnd, true), - AtomicRwOp::Relaxed, - )?, - "atomic_xadd" => this.atomic_op( - args, - dest, - AtomicOp::MirOp(BinOp::Add, false), - AtomicRwOp::SeqCst, - )?, - "atomic_xadd_acq" => this.atomic_op( - args, - dest, - AtomicOp::MirOp(BinOp::Add, false), - AtomicRwOp::Acquire, - )?, - "atomic_xadd_rel" => this.atomic_op( - args, - dest, - AtomicOp::MirOp(BinOp::Add, false), - AtomicRwOp::Release, - )?, - "atomic_xadd_acqrel" => this.atomic_op( - args, - dest, - AtomicOp::MirOp(BinOp::Add, false), - AtomicRwOp::AcqRel, - )?, - "atomic_xadd_relaxed" => this.atomic_op( - args, - dest, - AtomicOp::MirOp(BinOp::Add, false), - AtomicRwOp::Relaxed, - )?, - "atomic_xsub" => this.atomic_op( - args, - dest, - AtomicOp::MirOp(BinOp::Sub, false), - AtomicRwOp::SeqCst, - )?, - "atomic_xsub_acq" => this.atomic_op( - args, - dest, - AtomicOp::MirOp(BinOp::Sub, false), - AtomicRwOp::Acquire, - )?, - "atomic_xsub_rel" => this.atomic_op( - args, - dest, - AtomicOp::MirOp(BinOp::Sub, false), - AtomicRwOp::Release, - )?, - "atomic_xsub_acqrel" => this.atomic_op( - args, - dest, - AtomicOp::MirOp(BinOp::Sub, false), - AtomicRwOp::AcqRel, - )?, - "atomic_xsub_relaxed" => this.atomic_op( - args, - dest, - AtomicOp::MirOp(BinOp::Sub, false), - AtomicRwOp::Relaxed, - )?, - "atomic_min" => - this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOp::SeqCst)?, - "atomic_min_acq" => - this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOp::Acquire)?, - "atomic_min_rel" => - this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOp::Release)?, - "atomic_min_acqrel" => - this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOp::AcqRel)?, + #[rustfmt::skip] + "atomic_cxchgweak" => + this.atomic_compare_exchange_weak(args, dest, AtomicRwOp::SeqCst, AtomicReadOp::SeqCst)?, + #[rustfmt::skip] + "atomic_cxchgweak_acq" => + this.atomic_compare_exchange_weak(args, dest, AtomicRwOp::Acquire, AtomicReadOp::Acquire)?, + #[rustfmt::skip] + "atomic_cxchgweak_rel" => + this.atomic_compare_exchange_weak(args, dest, AtomicRwOp::Release, AtomicReadOp::Relaxed)?, + #[rustfmt::skip] + "atomic_cxchgweak_acqrel" => + this.atomic_compare_exchange_weak(args, dest, AtomicRwOp::AcqRel, AtomicReadOp::Acquire)?, + #[rustfmt::skip] + "atomic_cxchgweak_relaxed" => + this.atomic_compare_exchange_weak(args, dest, AtomicRwOp::Relaxed, AtomicReadOp::Relaxed)?, + #[rustfmt::skip] + "atomic_cxchgweak_acq_failrelaxed" => + this.atomic_compare_exchange_weak(args, dest, AtomicRwOp::Acquire, AtomicReadOp::Relaxed)?, + #[rustfmt::skip] + "atomic_cxchgweak_acqrel_failrelaxed" => + this.atomic_compare_exchange_weak(args, dest, AtomicRwOp::AcqRel, AtomicReadOp::Relaxed)?, + #[rustfmt::skip] + "atomic_cxchgweak_failrelaxed" => + this.atomic_compare_exchange_weak(args, dest, AtomicRwOp::SeqCst, AtomicReadOp::Relaxed)?, + #[rustfmt::skip] + "atomic_cxchgweak_failacq" => + this.atomic_compare_exchange_weak(args, dest, AtomicRwOp::SeqCst, AtomicReadOp::Acquire)?, + + #[rustfmt::skip] + "atomic_or" => + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitOr, false), AtomicRwOp::SeqCst)?, + #[rustfmt::skip] + "atomic_or_acq" => + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitOr, false), AtomicRwOp::Acquire)?, + #[rustfmt::skip] + "atomic_or_rel" => + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitOr, false), AtomicRwOp::Release)?, + #[rustfmt::skip] + "atomic_or_acqrel" => + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitOr, false), AtomicRwOp::AcqRel)?, + #[rustfmt::skip] + "atomic_or_relaxed" => + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitOr, false), AtomicRwOp::Relaxed)?, + #[rustfmt::skip] + "atomic_xor" => + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitXor, false), AtomicRwOp::SeqCst)?, + #[rustfmt::skip] + "atomic_xor_acq" => + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitXor, false), AtomicRwOp::Acquire)?, + #[rustfmt::skip] + "atomic_xor_rel" => + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitXor, false), AtomicRwOp::Release)?, + #[rustfmt::skip] + "atomic_xor_acqrel" => + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitXor, false), AtomicRwOp::AcqRel)?, + #[rustfmt::skip] + "atomic_xor_relaxed" => + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitXor, false), AtomicRwOp::Relaxed)?, + #[rustfmt::skip] + "atomic_and" => + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitAnd, false), AtomicRwOp::SeqCst)?, + #[rustfmt::skip] + "atomic_and_acq" => + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitAnd, false), AtomicRwOp::Acquire)?, + #[rustfmt::skip] + "atomic_and_rel" => + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitAnd, false), AtomicRwOp::Release)?, + #[rustfmt::skip] + "atomic_and_acqrel" => + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitAnd, false), AtomicRwOp::AcqRel)?, + #[rustfmt::skip] + "atomic_and_relaxed" => + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitAnd, false), AtomicRwOp::Relaxed)?, + #[rustfmt::skip] + "atomic_nand" => + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitAnd, true), AtomicRwOp::SeqCst)?, + #[rustfmt::skip] + "atomic_nand_acq" => + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitAnd, true), AtomicRwOp::Acquire)?, + #[rustfmt::skip] + "atomic_nand_rel" => + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitAnd, true), AtomicRwOp::Release)?, + #[rustfmt::skip] + "atomic_nand_acqrel" => + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitAnd, true), AtomicRwOp::AcqRel)?, + #[rustfmt::skip] + "atomic_nand_relaxed" => + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitAnd, true), AtomicRwOp::Relaxed)?, + #[rustfmt::skip] + "atomic_xadd" => + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::Add, false), AtomicRwOp::SeqCst)?, + #[rustfmt::skip] + "atomic_xadd_acq" => + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::Add, false), AtomicRwOp::Acquire)?, + #[rustfmt::skip] + "atomic_xadd_rel" => + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::Add, false), AtomicRwOp::Release)?, + #[rustfmt::skip] + "atomic_xadd_acqrel" => + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::Add, false), AtomicRwOp::AcqRel)?, + #[rustfmt::skip] + "atomic_xadd_relaxed" => + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::Add, false), AtomicRwOp::Relaxed)?, + #[rustfmt::skip] + "atomic_xsub" => + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::Sub, false), AtomicRwOp::SeqCst)?, + #[rustfmt::skip] + "atomic_xsub_acq" => + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::Sub, false), AtomicRwOp::Acquire)?, + #[rustfmt::skip] + "atomic_xsub_rel" => + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::Sub, false), AtomicRwOp::Release)?, + #[rustfmt::skip] + "atomic_xsub_acqrel" => + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::Sub, false), AtomicRwOp::AcqRel)?, + #[rustfmt::skip] + "atomic_xsub_relaxed" => + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::Sub, false), AtomicRwOp::Relaxed)?, + "atomic_min" => this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOp::SeqCst)?, + "atomic_min_acq" => this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOp::Acquire)?, + "atomic_min_rel" => this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOp::Release)?, + "atomic_min_acqrel" => this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOp::AcqRel)?, "atomic_min_relaxed" => this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOp::Relaxed)?, - "atomic_max" => - this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOp::SeqCst)?, - "atomic_max_acq" => - this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOp::Acquire)?, - "atomic_max_rel" => - this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOp::Release)?, - "atomic_max_acqrel" => - this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOp::AcqRel)?, + "atomic_max" => this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOp::SeqCst)?, + "atomic_max_acq" => this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOp::Acquire)?, + "atomic_max_rel" => this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOp::Release)?, + "atomic_max_acqrel" => this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOp::AcqRel)?, "atomic_max_relaxed" => this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOp::Relaxed)?, - "atomic_umin" => - this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOp::SeqCst)?, - "atomic_umin_acq" => - this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOp::Acquire)?, - "atomic_umin_rel" => - this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOp::Release)?, + "atomic_umin" => this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOp::SeqCst)?, + "atomic_umin_acq" => this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOp::Acquire)?, + "atomic_umin_rel" => this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOp::Release)?, "atomic_umin_acqrel" => this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOp::AcqRel)?, "atomic_umin_relaxed" => this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOp::Relaxed)?, - "atomic_umax" => - this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOp::SeqCst)?, - "atomic_umax_acq" => - this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOp::Acquire)?, - "atomic_umax_rel" => - this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOp::Release)?, + "atomic_umax" => this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOp::SeqCst)?, + "atomic_umax_acq" => this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOp::Acquire)?, + "atomic_umax_rel" => this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOp::Release)?, "atomic_umax_acqrel" => this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOp::AcqRel)?, "atomic_umax_relaxed" => From cf3376e541bea322370a9b0c521d292551a00642 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 17 May 2021 09:34:39 +0200 Subject: [PATCH 2654/3747] rustup --- benches/helpers/miri_helper.rs | 3 +-- rust-version | 2 +- src/bin/miri.rs | 3 +-- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/benches/helpers/miri_helper.rs b/benches/helpers/miri_helper.rs index 7642018c08cbc..144ddc11968c7 100644 --- a/benches/helpers/miri_helper.rs +++ b/benches/helpers/miri_helper.rs @@ -3,7 +3,6 @@ extern crate rustc_hir; extern crate rustc_interface; use rustc_driver::Compilation; -use rustc_hir::def_id::LOCAL_CRATE; use rustc_interface::{interface, Queries}; use crate::test::Bencher; @@ -22,7 +21,7 @@ impl rustc_driver::Callbacks for MiriCompilerCalls<'_> { queries.global_ctxt().unwrap().peek_mut().enter(|tcx| { let (entry_def_id, _) = - tcx.entry_fn(LOCAL_CRATE).expect("no main or start function found"); + tcx.entry_fn(()).expect("no main or start function found"); self.bencher.iter(|| { let config = miri::MiriConfig::default(); diff --git a/rust-version b/rust-version index 0495fc97f7f7e..600ef9d5a6e34 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -c6dd87a6b4a62cf5d2cb6207b1dcea652ea1aa60 +3396a383bb1d1fdad8ceeb74f16cf08e0bd62a1b diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 0e9a6ffe80502..4a1ea3a542862 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -16,7 +16,6 @@ use log::debug; use rustc_driver::Compilation; use rustc_errors::emitter::{ColorConfig, HumanReadableErrorType}; -use rustc_hir::def_id::LOCAL_CRATE; use rustc_middle::ty::TyCtxt; use rustc_session::{config::ErrorOutputType, CtfeBacktrace}; @@ -34,7 +33,7 @@ impl rustc_driver::Callbacks for MiriCompilerCalls { queries.global_ctxt().unwrap().peek_mut().enter(|tcx| { init_late_loggers(tcx); - let (entry_def_id, _) = if let Some((entry_def, x)) = tcx.entry_fn(LOCAL_CRATE) { + let (entry_def_id, _) = if let Some((entry_def, x)) = tcx.entry_fn(()) { (entry_def, x) } else { let output_ty = ErrorOutputType::HumanReadable(HumanReadableErrorType::Default( From 78f74c69e340a93ed75b04619437cc02b5af0587 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 17 May 2021 10:57:21 +0200 Subject: [PATCH 2655/3747] fix rustfmt fallout --- src/shims/windows/foreign_items.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shims/windows/foreign_items.rs b/src/shims/windows/foreign_items.rs index 655f6b08c2c34..f29870ff7cb7f 100644 --- a/src/shims/windows/foreign_items.rs +++ b/src/shims/windows/foreign_items.rs @@ -298,7 +298,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let len = this.read_scalar(len)?.to_u32()?; let flags = this.read_scalar(flags)?.to_u32()?; if flags != 2 { - // BCRYPT_USE_SYSTEM_PREFERRED_RNG + // ^ BCRYPT_USE_SYSTEM_PREFERRED_RNG throw_unsup_format!( "BCryptGenRandom is supported only with the BCRYPT_USE_SYSTEM_PREFERRED_RNG flag" ); From 4f171d7fe3cc9e24adb5917f226b00f287466771 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 17 May 2021 14:31:59 +0200 Subject: [PATCH 2656/3747] stop relying on c_str/wide_str helpers in rustc --- src/helpers.rs | 45 +++++++++++++++++++++++++ src/shims/foreign_items.rs | 2 +- src/shims/os_str.rs | 54 ++++++++++++++++++------------ src/shims/posix/foreign_items.rs | 2 +- src/shims/posix/thread.rs | 4 +-- src/shims/windows/foreign_items.rs | 2 +- 6 files changed, 83 insertions(+), 26 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index 7215cb4b0c7bd..ef5ea9447808c 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -566,6 +566,51 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Duration::new(seconds, nanoseconds) }) } + + fn read_c_str<'a>(&'a self, sptr: Scalar) -> InterpResult<'tcx, &'a [u8]> + where + 'tcx: 'a, + 'mir: 'a, + { + let this = self.eval_context_ref(); + let size1 = Size::from_bytes(1); + let ptr = this.force_ptr(sptr)?; // We need to read at least 1 byte, so we can eagerly get a ptr. + + // Step 1: determine the length. + let alloc = this.memory.get_raw(ptr.alloc_id)?; + let mut len = Size::ZERO; + loop { + let byte = alloc.read_scalar(this, ptr.offset(len, this)?, size1)?.to_u8()?; + if byte == 0 { + break; + } else { + len = len + size1; + } + } + + // Step 2: get the bytes. + this.memory.read_bytes(ptr.into(), len) + } + + fn read_wide_str(&self, sptr: Scalar) -> InterpResult<'tcx, Vec> { + let this = self.eval_context_ref(); + let size2 = Size::from_bytes(2); + + let mut ptr = this.force_ptr(sptr)?; // We need to read at least 1 wchar, so we can eagerly get a ptr. + let mut wchars = Vec::new(); + let alloc = this.memory.get_raw(ptr.alloc_id)?; + loop { + let wchar = alloc.read_scalar(this, ptr, size2)?.to_u16()?; + if wchar == 0 { + break; + } else { + wchars.push(wchar); + ptr = ptr.offset(size2, this)?; + } + } + + Ok(wchars) + } } /// Check that the number of args is what we expect. diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 6867871794a8d..47d939e697226 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -405,7 +405,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx check_abi(abi, Abi::C { unwind: false })?; let &[ref ptr] = check_arg_count(args)?; let ptr = this.read_scalar(ptr)?.check_init()?; - let n = this.memory.read_c_str(ptr)?.len(); + let n = this.read_c_str(ptr)?.len(); this.write_scalar(Scalar::from_machine_usize(u64::try_from(n).unwrap(), this), dest)?; } diff --git a/src/shims/os_str.rs b/src/shims/os_str.rs index 22e3806ad3345..f1f14fa828f85 100644 --- a/src/shims/os_str.rs +++ b/src/shims/os_str.rs @@ -9,7 +9,7 @@ use std::os::unix::ffi::{OsStrExt, OsStringExt}; #[cfg(windows)] use std::os::windows::ffi::{OsStrExt, OsStringExt}; -use rustc_target::abi::LayoutOf; +use rustc_target::abi::{LayoutOf, Size}; use crate::*; @@ -50,19 +50,19 @@ impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mi pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { /// Helper function to read an OsString from a null-terminated sequence of bytes, which is what /// the Unix APIs usually handle. - fn read_os_str_from_c_str<'a>(&'a self, scalar: Scalar) -> InterpResult<'tcx, &'a OsStr> + fn read_os_str_from_c_str<'a>(&'a self, sptr: Scalar) -> InterpResult<'tcx, &'a OsStr> where 'tcx: 'a, 'mir: 'a, { let this = self.eval_context_ref(); - let bytes = this.memory.read_c_str(scalar)?; + let bytes = this.read_c_str(sptr)?; bytes_to_os_str(bytes) } /// Helper function to read an OsString from a 0x0000-terminated sequence of u16, /// which is what the Windows APIs usually handle. - fn read_os_str_from_wide_str<'a>(&'a self, scalar: Scalar) -> InterpResult<'tcx, OsString> + fn read_os_str_from_wide_str<'a>(&'a self, sptr: Scalar) -> InterpResult<'tcx, OsString> where 'tcx: 'a, 'mir: 'a, @@ -78,7 +78,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(s.into()) } - let u16_vec = self.eval_context_ref().memory.read_wide_str(scalar)?; + let u16_vec = self.eval_context_ref().read_wide_str(sptr)?; u16vec_to_osstring(u16_vec) } @@ -90,7 +90,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn write_os_str_to_c_str( &mut self, os_str: &OsStr, - scalar: Scalar, + sptr: Scalar, size: u64, ) -> InterpResult<'tcx, (bool, u64)> { let bytes = os_str_to_bytes(os_str)?; @@ -102,7 +102,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } self.eval_context_mut() .memory - .write_bytes(scalar, bytes.iter().copied().chain(iter::once(0u8)))?; + .write_bytes(sptr, bytes.iter().copied().chain(iter::once(0u8)))?; Ok((true, string_length)) } @@ -114,7 +114,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn write_os_str_to_wide_str( &mut self, os_str: &OsStr, - scalar: Scalar, + sptr: Scalar, size: u64, ) -> InterpResult<'tcx, (bool, u64)> { #[cfg(windows)] @@ -136,15 +136,27 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // If `size` is smaller or equal than `bytes.len()`, writing `bytes` plus the required // 0x0000 terminator to memory would cause an out-of-bounds access. let string_length = u64::try_from(u16_vec.len()).unwrap(); - if size <= string_length { + let string_length = string_length.checked_add(1).unwrap(); + if size < string_length { return Ok((false, string_length)); } // Store the UTF-16 string. - self.eval_context_mut() - .memory - .write_u16s(scalar, u16_vec.into_iter().chain(iter::once(0x0000)))?; - Ok((true, string_length)) + let size2 = Size::from_bytes(2); + let this = self.eval_context_mut(); + let tcx = &*this.tcx; + let ptr = this.force_ptr(sptr)?; // we need to write at least the 0 terminator + let alloc = this.memory.get_raw_mut(ptr.alloc_id)?; + for (offset, wchar) in u16_vec.into_iter().chain(iter::once(0x0000)).enumerate() { + let offset = u64::try_from(offset).unwrap(); + alloc.write_scalar( + tcx, + ptr.offset(size2 * offset, tcx)?, + Scalar::from_u16(wchar).into(), + size2, + )?; + } + Ok((true, string_length - 1)) } /// Allocate enough memory to store the given `OsStr` as a null-terminated sequence of bytes. @@ -178,13 +190,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } /// Read a null-terminated sequence of bytes, and perform path separator conversion if needed. - fn read_path_from_c_str<'a>(&'a self, scalar: Scalar) -> InterpResult<'tcx, Cow<'a, Path>> + fn read_path_from_c_str<'a>(&'a self, sptr: Scalar) -> InterpResult<'tcx, Cow<'a, Path>> where 'tcx: 'a, 'mir: 'a, { let this = self.eval_context_ref(); - let os_str = this.read_os_str_from_c_str(scalar)?; + let os_str = this.read_os_str_from_c_str(sptr)?; Ok(match this.convert_path_separator(Cow::Borrowed(os_str), PathConversion::TargetToHost) { Cow::Borrowed(x) => Cow::Borrowed(Path::new(x)), @@ -193,9 +205,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } /// Read a null-terminated sequence of `u16`s, and perform path separator conversion if needed. - fn read_path_from_wide_str(&self, scalar: Scalar) -> InterpResult<'tcx, PathBuf> { + fn read_path_from_wide_str(&self, sptr: Scalar) -> InterpResult<'tcx, PathBuf> { let this = self.eval_context_ref(); - let os_str = this.read_os_str_from_wide_str(scalar)?; + let os_str = this.read_os_str_from_wide_str(sptr)?; Ok(this .convert_path_separator(Cow::Owned(os_str), PathConversion::TargetToHost) @@ -208,13 +220,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn write_path_to_c_str( &mut self, path: &Path, - scalar: Scalar, + sptr: Scalar, size: u64, ) -> InterpResult<'tcx, (bool, u64)> { let this = self.eval_context_mut(); let os_str = this .convert_path_separator(Cow::Borrowed(path.as_os_str()), PathConversion::HostToTarget); - this.write_os_str_to_c_str(&os_str, scalar, size) + this.write_os_str_to_c_str(&os_str, sptr, size) } /// Write a Path to the machine memory (as a null-terminated sequence of `u16`s), @@ -222,13 +234,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn write_path_to_wide_str( &mut self, path: &Path, - scalar: Scalar, + sptr: Scalar, size: u64, ) -> InterpResult<'tcx, (bool, u64)> { let this = self.eval_context_mut(); let os_str = this .convert_path_separator(Cow::Borrowed(path.as_os_str()), PathConversion::HostToTarget); - this.write_os_str_to_wide_str(&os_str, scalar, size) + this.write_os_str_to_wide_str(&os_str, sptr, size) } fn convert_path_separator<'a>( diff --git a/src/shims/posix/foreign_items.rs b/src/shims/posix/foreign_items.rs index b3d53cdc10ded..52b41b49bd5e9 100644 --- a/src/shims/posix/foreign_items.rs +++ b/src/shims/posix/foreign_items.rs @@ -187,7 +187,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let &[ref handle, ref symbol] = check_arg_count(args)?; this.read_scalar(handle)?.to_machine_usize(this)?; let symbol = this.read_scalar(symbol)?.check_init()?; - let symbol_name = this.memory.read_c_str(symbol)?; + let symbol_name = this.read_c_str(symbol)?; if let Some(dlsym) = Dlsym::from_str(symbol_name, &this.tcx.sess.target.os)? { let ptr = this.memory.create_fn_alloc(FnVal::Other(dlsym)); this.write_scalar(Scalar::from(ptr), dest)?; diff --git a/src/shims/posix/thread.rs b/src/shims/posix/thread.rs index 214a2ce411d6c..1e4597848914b 100644 --- a/src/shims/posix/thread.rs +++ b/src/shims/posix/thread.rs @@ -111,7 +111,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let option = this.read_scalar(option)?.to_i32()?; if option == this.eval_libc_i32("PR_SET_NAME")? { let address = this.read_scalar(arg2)?.check_init()?; - let mut name = this.memory.read_c_str(address)?.to_owned(); + let mut name = this.read_c_str(address)?.to_owned(); // The name should be no more than 16 bytes, including the null // byte. Since `read_c_str` returns the string without the null // byte, we need to truncate to 15. @@ -134,7 +134,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); this.assert_target_os("macos", "pthread_setname_np"); - let name = this.memory.read_c_str(name)?.to_owned(); + let name = this.read_c_str(name)?.to_owned(); this.set_active_thread_name(name); Ok(()) diff --git a/src/shims/windows/foreign_items.rs b/src/shims/windows/foreign_items.rs index f29870ff7cb7f..b246ccc33cf72 100644 --- a/src/shims/windows/foreign_items.rs +++ b/src/shims/windows/foreign_items.rs @@ -271,7 +271,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx #[allow(non_snake_case)] let &[ref hModule, ref lpProcName] = check_arg_count(args)?; this.read_scalar(hModule)?.to_machine_isize(this)?; - let name = this.memory.read_c_str(this.read_scalar(lpProcName)?.check_init()?)?; + let name = this.read_c_str(this.read_scalar(lpProcName)?.check_init()?)?; if let Some(dlsym) = Dlsym::from_str(name, &this.tcx.sess.target.os)? { let ptr = this.memory.create_fn_alloc(FnVal::Other(dlsym)); this.write_scalar(Scalar::from(ptr), dest)?; From 1bfd9ac56cc19b7a5e91e47fb6685ea57d50e20e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 18 May 2021 00:11:05 +0200 Subject: [PATCH 2657/3747] rustup --- rust-version | 2 +- src/machine.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/rust-version b/rust-version index 600ef9d5a6e34..3482331f593ed 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -3396a383bb1d1fdad8ceeb74f16cf08e0bd62a1b +3e99439f4dacc8ba0d2ca48d221694362d587927 diff --git a/src/machine.rs b/src/machine.rs index 635f3297b4e9c..51e0d8f6a6fc7 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -478,14 +478,14 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { let alloc = alloc.into_owned(); let (stacks, base_tag) = if let Some(stacked_borrows) = &memory_extra.stacked_borrows { let (stacks, base_tag) = - Stacks::new_allocation(id, alloc.size, Rc::clone(stacked_borrows), kind); + Stacks::new_allocation(id, alloc.size(), Rc::clone(stacked_borrows), kind); (Some(stacks), base_tag) } else { // No stacks, no tag. (None, Tag::Untagged) }; let race_alloc = if let Some(data_race) = &memory_extra.data_race { - Some(data_race::AllocExtra::new_allocation(&data_race, alloc.size, kind)) + Some(data_race::AllocExtra::new_allocation(&data_race, alloc.size(), kind)) } else { None }; From 952066f545c67c2c384ac0197dbf815b551f3720 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 19 May 2021 10:47:17 +0200 Subject: [PATCH 2658/3747] add (bors-ignored) formatting check job --- .github/workflows/ci.yml | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index d3d5d65bb94ed..b99d8499d05d1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -92,11 +92,34 @@ jobs: - name: Test run: bash ./ci.sh + fmt: + name: Check formatting (ignored by bors) + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Install latest nightly + uses: actions-rs/toolchain@v1 + with: + toolchain: nightly + components: rustfmt + override: true + - name: Check formatting (miri) + uses: actions-rs/cargo@v1 + with: + command: fmt + args: --all -- --check + - name: Check formatting (cargo-miri) + uses: actions-rs/cargo@v1 + with: + command: fmt + args: --manifest-path cargo-miri/Cargo.toml --all -- --check + # These jobs doesn't actually test anything, but they're only used to tell # bors the build completed, as there is no practical way to detect when a # workflow is successful listening to webhooks only. # # ALL THE PREVIOUS JOBS NEED TO BE ADDED TO THE `needs` SECTION OF THIS JOB! + # (`fmt` is deliberately not listed, we want bors to ignore it.) end-success: name: bors build finished runs-on: ubuntu-latest From 6f3ad27416b45acc7c947962f4585665d56fda30 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 19 May 2021 10:50:51 +0200 Subject: [PATCH 2659/3747] fmt --- benches/helpers/miri_helper.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/benches/helpers/miri_helper.rs b/benches/helpers/miri_helper.rs index 144ddc11968c7..b26705cb704ff 100644 --- a/benches/helpers/miri_helper.rs +++ b/benches/helpers/miri_helper.rs @@ -20,8 +20,7 @@ impl rustc_driver::Callbacks for MiriCompilerCalls<'_> { compiler.session().abort_if_errors(); queries.global_ctxt().unwrap().peek_mut().enter(|tcx| { - let (entry_def_id, _) = - tcx.entry_fn(()).expect("no main or start function found"); + let (entry_def_id, _) = tcx.entry_fn(()).expect("no main or start function found"); self.bencher.iter(|| { let config = miri::MiriConfig::default(); From 74ae89e6caf72f604fbcdd9be7d09038a2120a44 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 19 May 2021 10:57:38 +0200 Subject: [PATCH 2660/3747] over 'default' instead of 'override' (consistent with main build job) --- .github/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b99d8499d05d1..889c584ba7c1f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -93,7 +93,7 @@ jobs: run: bash ./ci.sh fmt: - name: Check formatting (ignored by bors) + name: check formatting (ignored by bors) runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 @@ -102,7 +102,7 @@ jobs: with: toolchain: nightly components: rustfmt - override: true + default: true - name: Check formatting (miri) uses: actions-rs/cargo@v1 with: From 801a1744cd6e509fb5aed5517a38238b7e987573 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 17 May 2021 13:50:45 +0200 Subject: [PATCH 2661/3747] update for Memory API changes --- src/data_race.rs | 4 +- src/diagnostics.rs | 8 +- src/helpers.rs | 15 ++- src/machine.rs | 104 ++++++++---------- src/shims/intrinsics.rs | 11 +- src/shims/os_str.rs | 17 ++- src/shims/posix/fs.rs | 10 +- src/shims/posix/linux/sync.rs | 3 +- src/stacked_borrows.rs | 2 +- .../compile-fail/data_race/alloc_read_race.rs | 3 +- 10 files changed, 88 insertions(+), 89 deletions(-) diff --git a/src/data_race.rs b/src/data_race.rs index e8071845c7d76..bcc2e17654319 100644 --- a/src/data_race.rs +++ b/src/data_race.rs @@ -720,7 +720,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { if let Some(data_race) = &mut this.memory.extra.data_race { if data_race.multi_threaded.get() { let alloc_meta = - this.memory.get_raw_mut(ptr.alloc_id)?.extra.data_race.as_mut().unwrap(); + this.memory.get_alloc_extra_mut(ptr.alloc_id)?.data_race.as_mut().unwrap(); alloc_meta.reset_clocks(ptr.offset, size); } } @@ -1024,7 +1024,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { let place_ptr = place.ptr.assert_ptr(); let size = place.layout.size; let alloc_meta = - &this.memory.get_raw(place_ptr.alloc_id)?.extra.data_race.as_ref().unwrap(); + &this.memory.get_alloc_extra(place_ptr.alloc_id)?.data_race.as_ref().unwrap(); log::trace!( "Atomic op({}) with ordering {:?} on memory({:?}, offset={}, size={})", description, diff --git a/src/diagnostics.rs b/src/diagnostics.rs index f074cfd4911bf..ae50b50860227 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -136,13 +136,13 @@ pub fn report_error<'tcx, 'mir>( // Extra output to help debug specific issues. match e.kind() { - UndefinedBehavior(UndefinedBehaviorInfo::InvalidUninitBytes(Some(access))) => { + UndefinedBehavior(UndefinedBehaviorInfo::InvalidUninitBytes(Some((alloc_id, access)))) => { eprintln!( "Uninitialized read occurred at offsets 0x{:x}..0x{:x} into this allocation:", - access.uninit_ptr.offset.bytes(), - access.uninit_ptr.offset.bytes() + access.uninit_size.bytes(), + access.uninit_offset.bytes(), + access.uninit_offset.bytes() + access.uninit_size.bytes(), ); - eprintln!("{:?}", ecx.memory.dump_alloc(access.uninit_ptr.alloc_id)); + eprintln!("{:?}", ecx.memory.dump_alloc(*alloc_id)); } _ => {} } diff --git a/src/helpers.rs b/src/helpers.rs index ef5ea9447808c..45a5a8d4170bf 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -8,7 +8,7 @@ use log::trace; use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX}; use rustc_middle::mir; use rustc_middle::ty::{self, layout::TyAndLayout, List, TyCtxt}; -use rustc_target::abi::{FieldsShape, LayoutOf, Size, Variants}; +use rustc_target::abi::{Align, FieldsShape, LayoutOf, Size, Variants}; use rustc_target::spec::abi::Abi; use rand::RngCore; @@ -577,10 +577,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let ptr = this.force_ptr(sptr)?; // We need to read at least 1 byte, so we can eagerly get a ptr. // Step 1: determine the length. - let alloc = this.memory.get_raw(ptr.alloc_id)?; let mut len = Size::ZERO; loop { - let byte = alloc.read_scalar(this, ptr.offset(len, this)?, size1)?.to_u8()?; + // FIXME: We are re-getting the allocation each time around the loop. + // Would be nice if we could somehow "extend" an existing AllocRange. + let alloc = this.memory.get(ptr.offset(len, this)?.into(), size1, Align::ONE)?.unwrap(); // not a ZST, so we will get a result + let byte = alloc.read_scalar(alloc_range(Size::ZERO, size1))?.to_u8()?; if byte == 0 { break; } else { @@ -595,12 +597,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn read_wide_str(&self, sptr: Scalar) -> InterpResult<'tcx, Vec> { let this = self.eval_context_ref(); let size2 = Size::from_bytes(2); + let align2 = Align::from_bytes(2).unwrap(); let mut ptr = this.force_ptr(sptr)?; // We need to read at least 1 wchar, so we can eagerly get a ptr. let mut wchars = Vec::new(); - let alloc = this.memory.get_raw(ptr.alloc_id)?; loop { - let wchar = alloc.read_scalar(this, ptr, size2)?.to_u16()?; + // FIXME: We are re-getting the allocation each time around the loop. + // Would be nice if we could somehow "extend" an existing AllocRange. + let alloc = this.memory.get(ptr.into(), size2, align2)?.unwrap(); // not a ZST, so we will get a result + let wchar = alloc.read_scalar(alloc_range(Size::ZERO, size2))?.to_u16()?; if wchar == 0 { break; } else { diff --git a/src/machine.rs b/src/machine.rs index 51e0d8f6a6fc7..7ed8147753d27 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -506,15 +506,57 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { } #[inline(always)] - fn before_deallocation( - memory_extra: &mut Self::MemoryExtra, - id: AllocId, + fn memory_read( + _memory_extra: &Self::MemoryExtra, + alloc: &Allocation, + ptr: Pointer, + size: Size, ) -> InterpResult<'tcx> { - if Some(id) == memory_extra.tracked_alloc_id { - register_diagnostic(NonHaltingDiagnostic::FreedAlloc(id)); + if let Some(data_race) = &alloc.extra.data_race { + data_race.read(ptr, size)?; } + if let Some(stacked_borrows) = &alloc.extra.stacked_borrows { + stacked_borrows.memory_read(ptr, size) + } else { + Ok(()) + } + } - Ok(()) + #[inline(always)] + fn memory_written( + _memory_extra: &mut Self::MemoryExtra, + alloc: &mut Allocation, + ptr: Pointer, + size: Size, + ) -> InterpResult<'tcx> { + if let Some(data_race) = &mut alloc.extra.data_race { + data_race.write(ptr, size)?; + } + if let Some(stacked_borrows) = &mut alloc.extra.stacked_borrows { + stacked_borrows.memory_written(ptr, size) + } else { + Ok(()) + } + } + + #[inline(always)] + fn memory_deallocated( + memory_extra: &mut Self::MemoryExtra, + alloc: &mut Allocation, + ptr: Pointer, + ) -> InterpResult<'tcx> { + let size = alloc.size(); + if Some(ptr.alloc_id) == memory_extra.tracked_alloc_id { + register_diagnostic(NonHaltingDiagnostic::FreedAlloc(ptr.alloc_id)); + } + if let Some(data_race) = &mut alloc.extra.data_race { + data_race.deallocate(ptr, size)?; + } + if let Some(stacked_borrows) = &mut alloc.extra.stacked_borrows { + stacked_borrows.memory_deallocated(ptr, size) + } else { + Ok(()) + } } fn after_static_mem_initialized( @@ -601,53 +643,3 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { intptrcast::GlobalState::ptr_to_int(ptr, memory) } } - -impl AllocationExtra for AllocExtra { - #[inline(always)] - fn memory_read<'tcx>( - alloc: &Allocation, - ptr: Pointer, - size: Size, - ) -> InterpResult<'tcx> { - if let Some(data_race) = &alloc.extra.data_race { - data_race.read(ptr, size)?; - } - if let Some(stacked_borrows) = &alloc.extra.stacked_borrows { - stacked_borrows.memory_read(ptr, size) - } else { - Ok(()) - } - } - - #[inline(always)] - fn memory_written<'tcx>( - alloc: &mut Allocation, - ptr: Pointer, - size: Size, - ) -> InterpResult<'tcx> { - if let Some(data_race) = &mut alloc.extra.data_race { - data_race.write(ptr, size)?; - } - if let Some(stacked_borrows) = &mut alloc.extra.stacked_borrows { - stacked_borrows.memory_written(ptr, size) - } else { - Ok(()) - } - } - - #[inline(always)] - fn memory_deallocated<'tcx>( - alloc: &mut Allocation, - ptr: Pointer, - size: Size, - ) -> InterpResult<'tcx> { - if let Some(data_race) = &mut alloc.extra.data_race { - data_race.deallocate(ptr, size)?; - } - if let Some(stacked_borrows) = &mut alloc.extra.stacked_borrows { - stacked_borrows.memory_deallocated(ptr, size) - } else { - Ok(()) - } - } -} diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index ee0e833f9e5f1..3284d40bca621 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -574,7 +574,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // even if the type they wrap would be less aligned (e.g. AtomicU64 on 32bit must // be 8-aligned). let align = Align::from_bytes(place.layout.size.bytes()).unwrap(); - this.memory.check_ptr_access(place.ptr, place.layout.size, align)?; + this.memory.check_ptr_access_align(place.ptr, place.layout.size, align, CheckInAllocMsg::MemoryAccessTest)?; + // Perform regular access. this.write_scalar(val, dest)?; Ok(()) } @@ -594,7 +595,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // even if the type they wrap would be less aligned (e.g. AtomicU64 on 32bit must // be 8-aligned). let align = Align::from_bytes(place.layout.size.bytes()).unwrap(); - this.memory.check_ptr_access(place.ptr, place.layout.size, align)?; + this.memory.check_ptr_access_align(place.ptr, place.layout.size, align, CheckInAllocMsg::MemoryAccessTest)?; // Perform atomic store this.write_scalar_atomic(val, &place, atomic)?; @@ -644,7 +645,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // even if the type they wrap would be less aligned (e.g. AtomicU64 on 32bit must // be 8-aligned). let align = Align::from_bytes(place.layout.size.bytes()).unwrap(); - this.memory.check_ptr_access(place.ptr, place.layout.size, align)?; + this.memory.check_ptr_access_align(place.ptr, place.layout.size, align, CheckInAllocMsg::MemoryAccessTest)?; match atomic_op { AtomicOp::Min => { @@ -681,7 +682,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // even if the type they wrap would be less aligned (e.g. AtomicU64 on 32bit must // be 8-aligned). let align = Align::from_bytes(place.layout.size.bytes()).unwrap(); - this.memory.check_ptr_access(place.ptr, place.layout.size, align)?; + this.memory.check_ptr_access_align(place.ptr, place.layout.size, align, CheckInAllocMsg::MemoryAccessTest)?; let old = this.atomic_exchange_scalar(&place, new, atomic)?; this.write_scalar(old, dest)?; // old value is returned @@ -707,7 +708,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // even if the type they wrap would be less aligned (e.g. AtomicU64 on 32bit must // be 8-aligned). let align = Align::from_bytes(place.layout.size.bytes()).unwrap(); - this.memory.check_ptr_access(place.ptr, place.layout.size, align)?; + this.memory.check_ptr_access_align(place.ptr, place.layout.size, align, CheckInAllocMsg::MemoryAccessTest)?; let old = this.atomic_compare_exchange_scalar( &place, diff --git a/src/shims/os_str.rs b/src/shims/os_str.rs index f1f14fa828f85..efcdc7b473a49 100644 --- a/src/shims/os_str.rs +++ b/src/shims/os_str.rs @@ -9,7 +9,7 @@ use std::os::unix::ffi::{OsStrExt, OsStringExt}; #[cfg(windows)] use std::os::windows::ffi::{OsStrExt, OsStringExt}; -use rustc_target::abi::{LayoutOf, Size}; +use rustc_target::abi::{Align, LayoutOf, Size}; use crate::*; @@ -144,17 +144,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Store the UTF-16 string. let size2 = Size::from_bytes(2); let this = self.eval_context_mut(); - let tcx = &*this.tcx; - let ptr = this.force_ptr(sptr)?; // we need to write at least the 0 terminator - let alloc = this.memory.get_raw_mut(ptr.alloc_id)?; + let mut alloc = this + .memory + .get_mut(sptr, Size::from_bytes(string_length), Align::from_bytes(2).unwrap())? + .unwrap(); // not a ZST, so we will get a result for (offset, wchar) in u16_vec.into_iter().chain(iter::once(0x0000)).enumerate() { let offset = u64::try_from(offset).unwrap(); - alloc.write_scalar( - tcx, - ptr.offset(size2 * offset, tcx)?, - Scalar::from_u16(wchar).into(), - size2, - )?; + alloc + .write_scalar(alloc_range(size2 * offset, size2), Scalar::from_u16(wchar).into())?; } Ok((true, string_length - 1)) } diff --git a/src/shims/posix/fs.rs b/src/shims/posix/fs.rs index 234f03ff462c1..06594e5ca1d6a 100644 --- a/src/shims/posix/fs.rs +++ b/src/shims/posix/fs.rs @@ -677,10 +677,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx trace!("Reading from FD {}, size {}", fd, count); // Check that the *entire* buffer is actually valid memory. - this.memory.check_ptr_access( + this.memory.check_ptr_access_align( buf, Size::from_bytes(count), - Align::from_bytes(1).unwrap(), + Align::ONE, + CheckInAllocMsg::MemoryAccessTest, )?; // We cap the number of read bytes to the largest value that we are able to fit in both the @@ -722,10 +723,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Isolation check is done via `FileDescriptor` trait. // Check that the *entire* buffer is actually valid memory. - this.memory.check_ptr_access( + this.memory.check_ptr_access_align( buf, Size::from_bytes(count), - Align::from_bytes(1).unwrap(), + Align::ONE, + CheckInAllocMsg::MemoryAccessTest, )?; // We cap the number of written bytes to the largest value that we are able to fit in both the diff --git a/src/shims/posix/linux/sync.rs b/src/shims/posix/linux/sync.rs index c5101203eb46f..fda70d815de21 100644 --- a/src/shims/posix/linux/sync.rs +++ b/src/shims/posix/linux/sync.rs @@ -82,10 +82,11 @@ pub fn futex<'tcx>( // Check the pointer for alignment and validity. // The API requires `addr` to be a 4-byte aligned pointer, and will // use the 4 bytes at the given address as an (atomic) i32. - this.memory.check_ptr_access( + this.memory.check_ptr_access_align( addr.to_scalar()?, Size::from_bytes(4), Align::from_bytes(4).unwrap(), + CheckInAllocMsg::MemoryAccessTest, )?; // Read an `i32` through the pointer, regardless of any wrapper types. // It's not uncommon for `addr` to be passed as another type than `*mut i32`, such as `*const AtomicI32`. diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 88f42efd13cf0..1139e21e0f13a 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -561,7 +561,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ); // Get the allocation. It might not be mutable, so we cannot use `get_mut`. - let extra = &this.memory.get_raw(ptr.alloc_id)?.extra; + let extra = this.memory.get_alloc_extra(ptr.alloc_id)?; let stacked_borrows = extra.stacked_borrows.as_ref().expect("we should have Stacked Borrows data"); // Update the stacks. diff --git a/tests/compile-fail/data_race/alloc_read_race.rs b/tests/compile-fail/data_race/alloc_read_race.rs index fc1e9d30e637a..093c9024f202d 100644 --- a/tests/compile-fail/data_race/alloc_read_race.rs +++ b/tests/compile-fail/data_race/alloc_read_race.rs @@ -1,4 +1,5 @@ // ignore-windows: Concurrency on Windows is not supported yet. +#![feature(new_uninit)] use std::thread::spawn; use std::ptr::null_mut; @@ -29,7 +30,7 @@ pub fn main() { // Uses relaxed semantics to not generate // a release sequence. let pointer = &*ptr.0; - pointer.store(Box::into_raw(Box::new(MaybeUninit::uninit())), Ordering::Relaxed); + pointer.store(Box::into_raw(Box::new_uninit()), Ordering::Relaxed); }); let j2 = spawn(move || { From dd404cc92e5fe967064fb43360e26db247410734 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 17 May 2021 13:56:00 +0200 Subject: [PATCH 2662/3747] avoid importing C functions in alloc_write_race test --- tests/compile-fail/data_race/alloc_write_race.rs | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/tests/compile-fail/data_race/alloc_write_race.rs b/tests/compile-fail/data_race/alloc_write_race.rs index d9f5af396a2d8..becebe6a122a9 100644 --- a/tests/compile-fail/data_race/alloc_write_race.rs +++ b/tests/compile-fail/data_race/alloc_write_race.rs @@ -1,4 +1,5 @@ // ignore-windows: Concurrency on Windows is not supported yet. +#![feature(new_uninit)] use std::thread::spawn; use std::ptr::null_mut; @@ -10,11 +11,6 @@ struct EvilSend(pub T); unsafe impl Send for EvilSend {} unsafe impl Sync for EvilSend {} -extern "C" { - fn malloc(size: usize) -> *mut u8; - fn free(ptr: *mut u8); -} - pub fn main() { // Shared atomic pointer let pointer = AtomicPtr::new(null_mut::()); @@ -33,7 +29,7 @@ pub fn main() { // Uses relaxed semantics to not generate // a release sequence. let pointer = &*ptr.0; - pointer.store(malloc(std::mem::size_of::()) as *mut usize, Ordering::Relaxed); + pointer.store(Box::into_raw(Box::::new_uninit()) as *mut usize, Ordering::Relaxed); }); let j2 = spawn(move || { @@ -45,6 +41,6 @@ pub fn main() { j2.join().unwrap(); // Clean up memory, will never be executed - free(pointer.load(Ordering::Relaxed) as *mut _); + drop(Box::from_raw(pointer.load(Ordering::Relaxed))); } } From d1e5eeebdfdf92c9b5afe9552e7532624b1603da Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 19 May 2021 15:58:05 +0200 Subject: [PATCH 2663/3747] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 3482331f593ed..143d077e3c201 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -3e99439f4dacc8ba0d2ca48d221694362d587927 +3e827cc21e0734edd26170e8d1481f0d66a1426b From e4a27150cb201fbe5aedda3748b08d3428bba5e0 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 19 May 2021 16:10:28 +0200 Subject: [PATCH 2664/3747] fmt --- src/shims/intrinsics.rs | 35 ++++++++++++++++++++++++++++++----- 1 file changed, 30 insertions(+), 5 deletions(-) diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 3284d40bca621..f2979a3c69d80 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -574,7 +574,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // even if the type they wrap would be less aligned (e.g. AtomicU64 on 32bit must // be 8-aligned). let align = Align::from_bytes(place.layout.size.bytes()).unwrap(); - this.memory.check_ptr_access_align(place.ptr, place.layout.size, align, CheckInAllocMsg::MemoryAccessTest)?; + this.memory.check_ptr_access_align( + place.ptr, + place.layout.size, + align, + CheckInAllocMsg::MemoryAccessTest, + )?; // Perform regular access. this.write_scalar(val, dest)?; Ok(()) @@ -595,7 +600,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // even if the type they wrap would be less aligned (e.g. AtomicU64 on 32bit must // be 8-aligned). let align = Align::from_bytes(place.layout.size.bytes()).unwrap(); - this.memory.check_ptr_access_align(place.ptr, place.layout.size, align, CheckInAllocMsg::MemoryAccessTest)?; + this.memory.check_ptr_access_align( + place.ptr, + place.layout.size, + align, + CheckInAllocMsg::MemoryAccessTest, + )?; // Perform atomic store this.write_scalar_atomic(val, &place, atomic)?; @@ -645,7 +655,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // even if the type they wrap would be less aligned (e.g. AtomicU64 on 32bit must // be 8-aligned). let align = Align::from_bytes(place.layout.size.bytes()).unwrap(); - this.memory.check_ptr_access_align(place.ptr, place.layout.size, align, CheckInAllocMsg::MemoryAccessTest)?; + this.memory.check_ptr_access_align( + place.ptr, + place.layout.size, + align, + CheckInAllocMsg::MemoryAccessTest, + )?; match atomic_op { AtomicOp::Min => { @@ -682,7 +697,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // even if the type they wrap would be less aligned (e.g. AtomicU64 on 32bit must // be 8-aligned). let align = Align::from_bytes(place.layout.size.bytes()).unwrap(); - this.memory.check_ptr_access_align(place.ptr, place.layout.size, align, CheckInAllocMsg::MemoryAccessTest)?; + this.memory.check_ptr_access_align( + place.ptr, + place.layout.size, + align, + CheckInAllocMsg::MemoryAccessTest, + )?; let old = this.atomic_exchange_scalar(&place, new, atomic)?; this.write_scalar(old, dest)?; // old value is returned @@ -708,7 +728,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // even if the type they wrap would be less aligned (e.g. AtomicU64 on 32bit must // be 8-aligned). let align = Align::from_bytes(place.layout.size.bytes()).unwrap(); - this.memory.check_ptr_access_align(place.ptr, place.layout.size, align, CheckInAllocMsg::MemoryAccessTest)?; + this.memory.check_ptr_access_align( + place.ptr, + place.layout.size, + align, + CheckInAllocMsg::MemoryAccessTest, + )?; let old = this.atomic_compare_exchange_scalar( &place, From aba96b82b4a9600ea8d01934c799f0539def356b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 19 May 2021 16:34:14 +0200 Subject: [PATCH 2665/3747] fix write_os_str_to_wide_str --- src/shims/os_str.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shims/os_str.rs b/src/shims/os_str.rs index efcdc7b473a49..8a3f5677706ec 100644 --- a/src/shims/os_str.rs +++ b/src/shims/os_str.rs @@ -146,7 +146,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); let mut alloc = this .memory - .get_mut(sptr, Size::from_bytes(string_length), Align::from_bytes(2).unwrap())? + .get_mut(sptr, size2 * string_length, Align::from_bytes(2).unwrap())? .unwrap(); // not a ZST, so we will get a result for (offset, wchar) in u16_vec.into_iter().chain(iter::once(0x0000)).enumerate() { let offset = u64::try_from(offset).unwrap(); From c151af5cf597d66251d4ab56cffc67a2f0507365 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 20 May 2021 13:32:18 +0200 Subject: [PATCH 2666/3747] rustup --- rust-version | 2 +- src/machine.rs | 20 ++++++++++---------- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/rust-version b/rust-version index 143d077e3c201..7004235a38f05 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -3e827cc21e0734edd26170e8d1481f0d66a1426b +35bab923c8e5a1e8291735e7630539002eb80d7b diff --git a/src/machine.rs b/src/machine.rs index 7ed8147753d27..2f407dd09a915 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -508,14 +508,14 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { #[inline(always)] fn memory_read( _memory_extra: &Self::MemoryExtra, - alloc: &Allocation, + alloc_extra: &AllocExtra, ptr: Pointer, size: Size, ) -> InterpResult<'tcx> { - if let Some(data_race) = &alloc.extra.data_race { + if let Some(data_race) = &alloc_extra.data_race { data_race.read(ptr, size)?; } - if let Some(stacked_borrows) = &alloc.extra.stacked_borrows { + if let Some(stacked_borrows) = &alloc_extra.stacked_borrows { stacked_borrows.memory_read(ptr, size) } else { Ok(()) @@ -525,14 +525,14 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { #[inline(always)] fn memory_written( _memory_extra: &mut Self::MemoryExtra, - alloc: &mut Allocation, + alloc_extra: &mut AllocExtra, ptr: Pointer, size: Size, ) -> InterpResult<'tcx> { - if let Some(data_race) = &mut alloc.extra.data_race { + if let Some(data_race) = &mut alloc_extra.data_race { data_race.write(ptr, size)?; } - if let Some(stacked_borrows) = &mut alloc.extra.stacked_borrows { + if let Some(stacked_borrows) = &mut alloc_extra.stacked_borrows { stacked_borrows.memory_written(ptr, size) } else { Ok(()) @@ -542,17 +542,17 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { #[inline(always)] fn memory_deallocated( memory_extra: &mut Self::MemoryExtra, - alloc: &mut Allocation, + alloc_extra: &mut AllocExtra, ptr: Pointer, + size: Size, ) -> InterpResult<'tcx> { - let size = alloc.size(); if Some(ptr.alloc_id) == memory_extra.tracked_alloc_id { register_diagnostic(NonHaltingDiagnostic::FreedAlloc(ptr.alloc_id)); } - if let Some(data_race) = &mut alloc.extra.data_race { + if let Some(data_race) = &mut alloc_extra.data_race { data_race.deallocate(ptr, size)?; } - if let Some(stacked_borrows) = &mut alloc.extra.stacked_borrows { + if let Some(stacked_borrows) = &mut alloc_extra.stacked_borrows { stacked_borrows.memory_deallocated(ptr, size) } else { Ok(()) From ca7283d746012397faa266b39dee78609b74ed64 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 22 May 2021 13:24:08 +0200 Subject: [PATCH 2667/3747] get rid of Rc in Stacked Borrows --- src/machine.rs | 18 +++++++++--------- src/stacked_borrows.rs | 41 ++++++++++++++++++++--------------------- 2 files changed, 29 insertions(+), 30 deletions(-) diff --git a/src/machine.rs b/src/machine.rs index 2f407dd09a915..0e0f3ad1568bc 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -116,7 +116,7 @@ pub struct AllocExtra { } /// Extra global memory data -#[derive(Clone, Debug)] +#[derive(Debug)] pub struct MemoryExtra { pub stacked_borrows: Option, pub data_race: Option, @@ -144,11 +144,11 @@ impl MemoryExtra { pub fn new(config: &MiriConfig) -> Self { let rng = StdRng::seed_from_u64(config.seed.unwrap_or(0)); let stacked_borrows = if config.stacked_borrows { - Some(Rc::new(RefCell::new(stacked_borrows::GlobalState::new( + Some(RefCell::new(stacked_borrows::GlobalState::new( config.tracked_pointer_tag, config.tracked_call_id, config.track_raw, - )))) + ))) } else { None }; @@ -478,7 +478,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { let alloc = alloc.into_owned(); let (stacks, base_tag) = if let Some(stacked_borrows) = &memory_extra.stacked_borrows { let (stacks, base_tag) = - Stacks::new_allocation(id, alloc.size(), Rc::clone(stacked_borrows), kind); + Stacks::new_allocation(id, alloc.size(), stacked_borrows, kind); (Some(stacks), base_tag) } else { // No stacks, no tag. @@ -507,7 +507,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { #[inline(always)] fn memory_read( - _memory_extra: &Self::MemoryExtra, + memory_extra: &Self::MemoryExtra, alloc_extra: &AllocExtra, ptr: Pointer, size: Size, @@ -516,7 +516,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { data_race.read(ptr, size)?; } if let Some(stacked_borrows) = &alloc_extra.stacked_borrows { - stacked_borrows.memory_read(ptr, size) + stacked_borrows.memory_read(ptr, size, memory_extra.stacked_borrows.as_ref().unwrap()) } else { Ok(()) } @@ -524,7 +524,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { #[inline(always)] fn memory_written( - _memory_extra: &mut Self::MemoryExtra, + memory_extra: &mut Self::MemoryExtra, alloc_extra: &mut AllocExtra, ptr: Pointer, size: Size, @@ -533,7 +533,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { data_race.write(ptr, size)?; } if let Some(stacked_borrows) = &mut alloc_extra.stacked_borrows { - stacked_borrows.memory_written(ptr, size) + stacked_borrows.memory_written(ptr, size, memory_extra.stacked_borrows.as_mut().unwrap()) } else { Ok(()) } @@ -553,7 +553,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { data_race.deallocate(ptr, size)?; } if let Some(stacked_borrows) = &mut alloc_extra.stacked_borrows { - stacked_borrows.memory_deallocated(ptr, size) + stacked_borrows.memory_deallocated(ptr, size, memory_extra.stacked_borrows.as_mut().unwrap()) } else { Ok(()) } diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 1139e21e0f13a..87f8e4886933c 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -4,8 +4,6 @@ use std::cell::RefCell; use std::fmt; use std::num::NonZeroU64; -use std::rc::Rc; - use log::trace; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; @@ -87,8 +85,6 @@ pub struct Stack { pub struct Stacks { // Even reading memory can have effects on the stack, so we need a `RefCell` here. stacks: RefCell>, - // Pointer to global state - global: MemoryExtra, } /// Extra global state, available to the memory access hooks. @@ -112,7 +108,7 @@ pub struct GlobalState { track_raw: bool, } /// Memory extra state gives us interior mutable access to the global state. -pub type MemoryExtra = Rc>; +pub type MemoryExtra = RefCell; /// Indicates which kind of access is being performed. #[derive(Copy, Clone, Hash, PartialEq, Eq)] @@ -449,11 +445,11 @@ impl<'tcx> Stack { /// Map per-stack operations to higher-level per-location-range operations. impl<'tcx> Stacks { /// Creates new stack with initial tag. - fn new(size: Size, perm: Permission, tag: Tag, extra: MemoryExtra) -> Self { + fn new(size: Size, perm: Permission, tag: Tag) -> Self { let item = Item { perm, tag, protector: None }; let stack = Stack { borrows: vec![item] }; - Stacks { stacks: RefCell::new(RangeMap::new(size, stack)), global: extra } + Stacks { stacks: RefCell::new(RangeMap::new(size, stack)) } } /// Call `f` on every stack in the range. @@ -461,9 +457,9 @@ impl<'tcx> Stacks { &self, ptr: Pointer, size: Size, + global: &GlobalState, f: impl Fn(Pointer, &mut Stack, &GlobalState) -> InterpResult<'tcx>, ) -> InterpResult<'tcx> { - let global = self.global.borrow(); let mut stacks = self.stacks.borrow_mut(); for (offset, stack) in stacks.iter_mut(ptr.offset, size) { let mut cur_ptr = ptr; @@ -479,16 +475,17 @@ impl Stacks { pub fn new_allocation( id: AllocId, size: Size, - extra: MemoryExtra, + extra: &MemoryExtra, kind: MemoryKind, ) -> (Self, Tag) { + let mut extra = extra.borrow_mut(); let (tag, perm) = match kind { // New unique borrow. This tag is not accessible by the program, // so it will only ever be used when using the local directly (i.e., // not through a pointer). That is, whenever we directly write to a local, this will pop // everything else off the stack, invalidating all previous pointers, // and in particular, *all* raw pointers. - MemoryKind::Stack => (Tag::Tagged(extra.borrow_mut().new_ptr()), Permission::Unique), + MemoryKind::Stack => (Tag::Tagged(extra.new_ptr()), Permission::Unique), // `Global` memory can be referenced by global pointers from `tcx`. // Thus we call `global_base_ptr` such that the global pointers get the same tag // as what we use here. @@ -500,28 +497,27 @@ impl Stacks { | MiriMemoryKind::ExternStatic | MiriMemoryKind::Tls | MiriMemoryKind::Env, - ) => (extra.borrow_mut().global_base_ptr(id), Permission::SharedReadWrite), + ) => (extra.global_base_ptr(id), Permission::SharedReadWrite), // Everything else we handle like raw pointers for now. _ => { - let mut extra = extra.borrow_mut(); let tag = if extra.track_raw { Tag::Tagged(extra.new_ptr()) } else { Tag::Untagged }; (tag, Permission::SharedReadWrite) } }; - (Stacks::new(size, perm, tag, extra), tag) + (Stacks::new(size, perm, tag), tag) } #[inline(always)] - pub fn memory_read<'tcx>(&self, ptr: Pointer, size: Size) -> InterpResult<'tcx> { + pub fn memory_read<'tcx>(&self, ptr: Pointer, size: Size, extra: &MemoryExtra) -> InterpResult<'tcx> { trace!("read access with tag {:?}: {:?}, size {}", ptr.tag, ptr.erase_tag(), size.bytes()); - self.for_each(ptr, size, |ptr, stack, global| stack.access(AccessKind::Read, ptr, global)) + self.for_each(ptr, size, &*extra.borrow(), |ptr, stack, global| stack.access(AccessKind::Read, ptr, global)) } #[inline(always)] - pub fn memory_written<'tcx>(&mut self, ptr: Pointer, size: Size) -> InterpResult<'tcx> { + pub fn memory_written<'tcx>(&mut self, ptr: Pointer, size: Size, extra: &mut MemoryExtra) -> InterpResult<'tcx> { trace!("write access with tag {:?}: {:?}, size {}", ptr.tag, ptr.erase_tag(), size.bytes()); - self.for_each(ptr, size, |ptr, stack, global| stack.access(AccessKind::Write, ptr, global)) + self.for_each(ptr, size, extra.get_mut(), |ptr, stack, global| stack.access(AccessKind::Write, ptr, global)) } #[inline(always)] @@ -529,9 +525,10 @@ impl Stacks { &mut self, ptr: Pointer, size: Size, + extra: &mut MemoryExtra, ) -> InterpResult<'tcx> { trace!("deallocation with tag {:?}: {:?}, size {}", ptr.tag, ptr.erase_tag(), size.bytes()); - self.for_each(ptr, size, |ptr, stack, global| stack.dealloc(ptr, global)) + self.for_each(ptr, size, extra.get_mut(), |ptr, stack, global| stack.dealloc(ptr, global)) } } @@ -560,10 +557,12 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx size.bytes() ); - // Get the allocation. It might not be mutable, so we cannot use `get_mut`. + // Get the allocation. We need both the allocation and the MemoryExtra, so we cannot use `&mut`. + // FIXME: make `get_alloc_extra_mut` also return `&mut MemoryExtra`. let extra = this.memory.get_alloc_extra(ptr.alloc_id)?; let stacked_borrows = extra.stacked_borrows.as_ref().expect("we should have Stacked Borrows data"); + let global = this.memory.extra.stacked_borrows.as_ref().unwrap().borrow(); // Update the stacks. // Make sure that raw pointers and mutable shared references are reborrowed "weak": // There could be existing unique pointers reborrowed from them that should remain valid! @@ -583,14 +582,14 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Permission::SharedReadWrite }; let item = Item { perm, tag: new_tag, protector }; - stacked_borrows.for_each(cur_ptr, size, |cur_ptr, stack, global| { + stacked_borrows.for_each(cur_ptr, size, &*global, |cur_ptr, stack, global| { stack.grant(cur_ptr, item, global) }) }); } }; let item = Item { perm, tag: new_tag, protector }; - stacked_borrows.for_each(ptr, size, |ptr, stack, global| stack.grant(ptr, item, global)) + stacked_borrows.for_each(ptr, size, &*global, |ptr, stack, global| stack.grant(ptr, item, global)) } /// Retags an indidual pointer, returning the retagged version. From 1bbd6e609cb1fef17e7454bb6ced66a37f743ded Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 22 May 2021 14:47:14 +0200 Subject: [PATCH 2668/3747] get rid of Rc in data_race --- src/data_race.rs | 37 ++++++++++++++++--------------------- src/machine.rs | 9 ++++----- src/thread.rs | 7 +++---- 3 files changed, 23 insertions(+), 30 deletions(-) diff --git a/src/data_race.rs b/src/data_race.rs index bcc2e17654319..ff6c720740a11 100644 --- a/src/data_race.rs +++ b/src/data_race.rs @@ -65,7 +65,6 @@ use std::{ cell::{Cell, Ref, RefCell, RefMut}, fmt::Debug, mem, - rc::Rc, }; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; @@ -80,7 +79,7 @@ use crate::{ }; pub type AllocExtra = VClockAlloc; -pub type MemoryExtra = Rc; +pub type MemoryExtra = GlobalState; /// Valid atomic read-write operations, alias of atomic::Ordering (not non-exhaustive). #[derive(Copy, Clone, PartialEq, Eq, Debug)] @@ -488,7 +487,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { ) -> InterpResult<'tcx, ScalarMaybeUninit> { let this = self.eval_context_ref(); let scalar = this.allow_data_races_ref(move |this| this.read_scalar(&place.into()))?; - self.validate_atomic_load(place, atomic)?; + this.validate_atomic_load(place, atomic)?; Ok(scalar) } @@ -501,7 +500,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); this.allow_data_races_mut(move |this| this.write_scalar(val, &(*dest).into()))?; - self.validate_atomic_store(dest, atomic) + this.validate_atomic_store(dest, atomic) } /// Perform a atomic operation on a memory location. @@ -733,9 +732,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { pub struct VClockAlloc { /// Assigning each byte a MemoryCellClocks. alloc_ranges: RefCell>, - - /// Pointer to global state. - global: MemoryExtra, } impl VClockAlloc { @@ -767,7 +763,6 @@ impl VClockAlloc { | MemoryKind::Vtable => (0, VectorIdx::MAX_INDEX), }; VClockAlloc { - global: Rc::clone(global), alloc_ranges: RefCell::new(RangeMap::new( len, MemoryCellClocks::new(alloc_timestamp, alloc_index), @@ -888,15 +883,15 @@ impl VClockAlloc { /// being created or if it is temporarily disabled during a racy read or write /// operation for which data-race detection is handled separately, for example /// atomic read operations. - pub fn read<'tcx>(&self, pointer: Pointer, len: Size) -> InterpResult<'tcx> { - if self.global.multi_threaded.get() { - let (index, clocks) = self.global.current_thread_state(); + pub fn read<'tcx>(&self, pointer: Pointer, len: Size, global: &GlobalState) -> InterpResult<'tcx> { + if global.multi_threaded.get() { + let (index, clocks) = global.current_thread_state(); let mut alloc_ranges = self.alloc_ranges.borrow_mut(); for (_, range) in alloc_ranges.iter_mut(pointer.offset, len) { if let Err(DataRace) = range.read_race_detect(&*clocks, index) { // Report data-race. return Self::report_data_race( - &self.global, + global, range, "Read", false, @@ -917,14 +912,15 @@ impl VClockAlloc { pointer: Pointer, len: Size, write_type: WriteType, + global: &mut GlobalState, ) -> InterpResult<'tcx> { - if self.global.multi_threaded.get() { - let (index, clocks) = self.global.current_thread_state(); + if global.multi_threaded.get() { + let (index, clocks) = global.current_thread_state(); for (_, range) in self.alloc_ranges.get_mut().iter_mut(pointer.offset, len) { if let Err(DataRace) = range.write_race_detect(&*clocks, index, write_type) { // Report data-race return Self::report_data_race( - &self.global, + global, range, write_type.get_descriptor(), false, @@ -943,16 +939,16 @@ impl VClockAlloc { /// data-race threads if `multi-threaded` is false, either due to no threads /// being created or if it is temporarily disabled during a racy read or write /// operation - pub fn write<'tcx>(&mut self, pointer: Pointer, len: Size) -> InterpResult<'tcx> { - self.unique_access(pointer, len, WriteType::Write) + pub fn write<'tcx>(&mut self, pointer: Pointer, len: Size, global: &mut GlobalState) -> InterpResult<'tcx> { + self.unique_access(pointer, len, WriteType::Write, global) } /// Detect data-races for an unsynchronized deallocate operation, will not perform /// data-race threads if `multi-threaded` is false, either due to no threads /// being created or if it is temporarily disabled during a racy read or write /// operation - pub fn deallocate<'tcx>(&mut self, pointer: Pointer, len: Size) -> InterpResult<'tcx> { - self.unique_access(pointer, len, WriteType::Deallocate) + pub fn deallocate<'tcx>(&mut self, pointer: Pointer, len: Size, global: &mut GlobalState) -> InterpResult<'tcx> { + self.unique_access(pointer, len, WriteType::Deallocate, global) } } @@ -1035,7 +1031,6 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { ); // Perform the atomic operation. - let data_race = &alloc_meta.global; data_race.maybe_perform_sync_operation(|index, mut clocks| { for (_, range) in alloc_meta.alloc_ranges.borrow_mut().iter_mut(place_ptr.offset, size) @@ -1043,7 +1038,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { if let Err(DataRace) = op(range, &mut *clocks, index, atomic) { mem::drop(clocks); return VClockAlloc::report_data_race( - &alloc_meta.global, + data_race, range, description, true, diff --git a/src/machine.rs b/src/machine.rs index 0e0f3ad1568bc..ce4b96ad4a469 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -5,7 +5,6 @@ use std::borrow::Cow; use std::cell::RefCell; use std::fmt; use std::num::NonZeroU64; -use std::rc::Rc; use std::time::Instant; use log::trace; @@ -153,7 +152,7 @@ impl MemoryExtra { None }; let data_race = if config.data_race_detector { - Some(Rc::new(data_race::GlobalState::new())) + Some(data_race::GlobalState::new()) } else { None }; @@ -513,7 +512,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { size: Size, ) -> InterpResult<'tcx> { if let Some(data_race) = &alloc_extra.data_race { - data_race.read(ptr, size)?; + data_race.read(ptr, size, memory_extra.data_race.as_ref().unwrap())?; } if let Some(stacked_borrows) = &alloc_extra.stacked_borrows { stacked_borrows.memory_read(ptr, size, memory_extra.stacked_borrows.as_ref().unwrap()) @@ -530,7 +529,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { size: Size, ) -> InterpResult<'tcx> { if let Some(data_race) = &mut alloc_extra.data_race { - data_race.write(ptr, size)?; + data_race.write(ptr, size, memory_extra.data_race.as_mut().unwrap())?; } if let Some(stacked_borrows) = &mut alloc_extra.stacked_borrows { stacked_borrows.memory_written(ptr, size, memory_extra.stacked_borrows.as_mut().unwrap()) @@ -550,7 +549,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { register_diagnostic(NonHaltingDiagnostic::FreedAlloc(ptr.alloc_id)); } if let Some(data_race) = &mut alloc_extra.data_race { - data_race.deallocate(ptr, size)?; + data_race.deallocate(ptr, size, memory_extra.data_race.as_mut().unwrap())?; } if let Some(stacked_borrows) = &mut alloc_extra.stacked_borrows { stacked_borrows.memory_deallocated(ptr, size, memory_extra.stacked_borrows.as_mut().unwrap()) diff --git a/src/thread.rs b/src/thread.rs index 7d6fe8041e980..8aaeb7e349c62 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -4,7 +4,6 @@ use std::cell::RefCell; use std::collections::hash_map::Entry; use std::convert::TryFrom; use std::num::TryFromIntError; -use std::rc::Rc; use std::time::{Duration, Instant, SystemTime}; use log::trace; @@ -333,7 +332,7 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { fn join_thread( &mut self, joined_thread_id: ThreadId, - data_race: &Option>, + data_race: &Option, ) -> InterpResult<'tcx> { if self.threads[joined_thread_id].join_status != ThreadJoinStatus::Joinable { throw_ub_format!("trying to join a detached or already joined thread"); @@ -439,7 +438,7 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { /// The `AllocId` that can now be freed is returned. fn thread_terminated( &mut self, - data_race: &Option>, + data_race: &Option, ) -> Vec { let mut free_tls_statics = Vec::new(); { @@ -481,7 +480,7 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { /// blocked, terminated, or has explicitly asked to be preempted). fn schedule( &mut self, - data_race: &Option>, + data_race: &Option, ) -> InterpResult<'tcx, SchedulingAction> { // Check whether the thread has **just** terminated (`check_terminated` // checks whether the thread has popped all its stack and if yes, sets From c73f8b1097e9e5d01baa56df9bb4cd93f3828fd4 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 22 May 2021 14:55:33 +0200 Subject: [PATCH 2669/3747] fmt --- src/data_race.rs | 30 +++++++++++++++++++----------- src/machine.rs | 19 ++++++++++++------- src/stacked_borrows.rs | 27 +++++++++++++++++++++------ src/thread.rs | 5 +---- 4 files changed, 53 insertions(+), 28 deletions(-) diff --git a/src/data_race.rs b/src/data_race.rs index ff6c720740a11..16ab03ace2228 100644 --- a/src/data_race.rs +++ b/src/data_race.rs @@ -883,21 +883,19 @@ impl VClockAlloc { /// being created or if it is temporarily disabled during a racy read or write /// operation for which data-race detection is handled separately, for example /// atomic read operations. - pub fn read<'tcx>(&self, pointer: Pointer, len: Size, global: &GlobalState) -> InterpResult<'tcx> { + pub fn read<'tcx>( + &self, + pointer: Pointer, + len: Size, + global: &GlobalState, + ) -> InterpResult<'tcx> { if global.multi_threaded.get() { let (index, clocks) = global.current_thread_state(); let mut alloc_ranges = self.alloc_ranges.borrow_mut(); for (_, range) in alloc_ranges.iter_mut(pointer.offset, len) { if let Err(DataRace) = range.read_race_detect(&*clocks, index) { // Report data-race. - return Self::report_data_race( - global, - range, - "Read", - false, - pointer, - len, - ); + return Self::report_data_race(global, range, "Read", false, pointer, len); } } Ok(()) @@ -939,7 +937,12 @@ impl VClockAlloc { /// data-race threads if `multi-threaded` is false, either due to no threads /// being created or if it is temporarily disabled during a racy read or write /// operation - pub fn write<'tcx>(&mut self, pointer: Pointer, len: Size, global: &mut GlobalState) -> InterpResult<'tcx> { + pub fn write<'tcx>( + &mut self, + pointer: Pointer, + len: Size, + global: &mut GlobalState, + ) -> InterpResult<'tcx> { self.unique_access(pointer, len, WriteType::Write, global) } @@ -947,7 +950,12 @@ impl VClockAlloc { /// data-race threads if `multi-threaded` is false, either due to no threads /// being created or if it is temporarily disabled during a racy read or write /// operation - pub fn deallocate<'tcx>(&mut self, pointer: Pointer, len: Size, global: &mut GlobalState) -> InterpResult<'tcx> { + pub fn deallocate<'tcx>( + &mut self, + pointer: Pointer, + len: Size, + global: &mut GlobalState, + ) -> InterpResult<'tcx> { self.unique_access(pointer, len, WriteType::Deallocate, global) } } diff --git a/src/machine.rs b/src/machine.rs index ce4b96ad4a469..fb2d877c38039 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -151,11 +151,8 @@ impl MemoryExtra { } else { None }; - let data_race = if config.data_race_detector { - Some(data_race::GlobalState::new()) - } else { - None - }; + let data_race = + if config.data_race_detector { Some(data_race::GlobalState::new()) } else { None }; MemoryExtra { stacked_borrows, data_race, @@ -532,7 +529,11 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { data_race.write(ptr, size, memory_extra.data_race.as_mut().unwrap())?; } if let Some(stacked_borrows) = &mut alloc_extra.stacked_borrows { - stacked_borrows.memory_written(ptr, size, memory_extra.stacked_borrows.as_mut().unwrap()) + stacked_borrows.memory_written( + ptr, + size, + memory_extra.stacked_borrows.as_mut().unwrap(), + ) } else { Ok(()) } @@ -552,7 +553,11 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { data_race.deallocate(ptr, size, memory_extra.data_race.as_mut().unwrap())?; } if let Some(stacked_borrows) = &mut alloc_extra.stacked_borrows { - stacked_borrows.memory_deallocated(ptr, size, memory_extra.stacked_borrows.as_mut().unwrap()) + stacked_borrows.memory_deallocated( + ptr, + size, + memory_extra.stacked_borrows.as_mut().unwrap(), + ) } else { Ok(()) } diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 87f8e4886933c..a9c030c87de4e 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -1,10 +1,10 @@ //! Implements "Stacked Borrows". See //! for further information. +use log::trace; use std::cell::RefCell; use std::fmt; use std::num::NonZeroU64; -use log::trace; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_hir::Mutability; @@ -509,15 +509,29 @@ impl Stacks { } #[inline(always)] - pub fn memory_read<'tcx>(&self, ptr: Pointer, size: Size, extra: &MemoryExtra) -> InterpResult<'tcx> { + pub fn memory_read<'tcx>( + &self, + ptr: Pointer, + size: Size, + extra: &MemoryExtra, + ) -> InterpResult<'tcx> { trace!("read access with tag {:?}: {:?}, size {}", ptr.tag, ptr.erase_tag(), size.bytes()); - self.for_each(ptr, size, &*extra.borrow(), |ptr, stack, global| stack.access(AccessKind::Read, ptr, global)) + self.for_each(ptr, size, &*extra.borrow(), |ptr, stack, global| { + stack.access(AccessKind::Read, ptr, global) + }) } #[inline(always)] - pub fn memory_written<'tcx>(&mut self, ptr: Pointer, size: Size, extra: &mut MemoryExtra) -> InterpResult<'tcx> { + pub fn memory_written<'tcx>( + &mut self, + ptr: Pointer, + size: Size, + extra: &mut MemoryExtra, + ) -> InterpResult<'tcx> { trace!("write access with tag {:?}: {:?}, size {}", ptr.tag, ptr.erase_tag(), size.bytes()); - self.for_each(ptr, size, extra.get_mut(), |ptr, stack, global| stack.access(AccessKind::Write, ptr, global)) + self.for_each(ptr, size, extra.get_mut(), |ptr, stack, global| { + stack.access(AccessKind::Write, ptr, global) + }) } #[inline(always)] @@ -589,7 +603,8 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } }; let item = Item { perm, tag: new_tag, protector }; - stacked_borrows.for_each(ptr, size, &*global, |ptr, stack, global| stack.grant(ptr, item, global)) + stacked_borrows + .for_each(ptr, size, &*global, |ptr, stack, global| stack.grant(ptr, item, global)) } /// Retags an indidual pointer, returning the retagged version. diff --git a/src/thread.rs b/src/thread.rs index 8aaeb7e349c62..3418e8c7d2bfd 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -436,10 +436,7 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { /// Wakes up threads joining on the active one and deallocates thread-local statics. /// The `AllocId` that can now be freed is returned. - fn thread_terminated( - &mut self, - data_race: &Option, - ) -> Vec { + fn thread_terminated(&mut self, data_race: &Option) -> Vec { let mut free_tls_statics = Vec::new(); { let mut thread_local_statics = self.thread_local_alloc_ids.borrow_mut(); From d77d95d0a8ea90e87cbc872cacdd89540e11142c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 23 May 2021 12:39:27 +0200 Subject: [PATCH 2670/3747] rustup --- rust-version | 2 +- src/data_race.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/rust-version b/rust-version index 7004235a38f05..bc7ef53b30372 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -35bab923c8e5a1e8291735e7630539002eb80d7b +6e92fb409816c65cd0a78a1fbcc71e2fbabdf50a diff --git a/src/data_race.rs b/src/data_race.rs index 16ab03ace2228..fb6bf8f892952 100644 --- a/src/data_race.rs +++ b/src/data_race.rs @@ -719,7 +719,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { if let Some(data_race) = &mut this.memory.extra.data_race { if data_race.multi_threaded.get() { let alloc_meta = - this.memory.get_alloc_extra_mut(ptr.alloc_id)?.data_race.as_mut().unwrap(); + this.memory.get_alloc_extra_mut(ptr.alloc_id)?.0.data_race.as_mut().unwrap(); alloc_meta.reset_clocks(ptr.offset, size); } } From 543777acbd9797118c5992e308335ab21dcd1fbb Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 23 May 2021 10:47:29 +0200 Subject: [PATCH 2671/3747] avoid unnecessary RefCell calls in Stacked Borrows --- src/stacked_borrows.rs | 60 +++++++++++++++++++++++++++--------------- 1 file changed, 39 insertions(+), 21 deletions(-) diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index a9c030c87de4e..b1ab34b1f346b 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -457,14 +457,29 @@ impl<'tcx> Stacks { &self, ptr: Pointer, size: Size, - global: &GlobalState, - f: impl Fn(Pointer, &mut Stack, &GlobalState) -> InterpResult<'tcx>, + f: impl Fn(Pointer, &mut Stack) -> InterpResult<'tcx>, ) -> InterpResult<'tcx> { let mut stacks = self.stacks.borrow_mut(); for (offset, stack) in stacks.iter_mut(ptr.offset, size) { let mut cur_ptr = ptr; cur_ptr.offset = offset; - f(cur_ptr, stack, &*global)?; + f(cur_ptr, stack)?; + } + Ok(()) + } + + /// Call `f` on every stack in the range. + fn for_each_mut( + &mut self, + ptr: Pointer, + size: Size, + f: impl Fn(Pointer, &mut Stack) -> InterpResult<'tcx>, + ) -> InterpResult<'tcx> { + let stacks = self.stacks.get_mut(); + for (offset, stack) in stacks.iter_mut(ptr.offset, size) { + let mut cur_ptr = ptr; + cur_ptr.offset = offset; + f(cur_ptr, stack)?; } Ok(()) } @@ -516,9 +531,8 @@ impl Stacks { extra: &MemoryExtra, ) -> InterpResult<'tcx> { trace!("read access with tag {:?}: {:?}, size {}", ptr.tag, ptr.erase_tag(), size.bytes()); - self.for_each(ptr, size, &*extra.borrow(), |ptr, stack, global| { - stack.access(AccessKind::Read, ptr, global) - }) + let global = &*extra.borrow(); + self.for_each(ptr, size, move |ptr, stack| stack.access(AccessKind::Read, ptr, global)) } #[inline(always)] @@ -529,9 +543,8 @@ impl Stacks { extra: &mut MemoryExtra, ) -> InterpResult<'tcx> { trace!("write access with tag {:?}: {:?}, size {}", ptr.tag, ptr.erase_tag(), size.bytes()); - self.for_each(ptr, size, extra.get_mut(), |ptr, stack, global| { - stack.access(AccessKind::Write, ptr, global) - }) + let global = extra.get_mut(); + self.for_each_mut(ptr, size, move |ptr, stack| stack.access(AccessKind::Write, ptr, global)) } #[inline(always)] @@ -542,7 +555,8 @@ impl Stacks { extra: &mut MemoryExtra, ) -> InterpResult<'tcx> { trace!("deallocation with tag {:?}: {:?}, size {}", ptr.tag, ptr.erase_tag(), size.bytes()); - self.for_each(ptr, size, extra.get_mut(), |ptr, stack, global| stack.dealloc(ptr, global)) + let global = extra.get_mut(); + self.for_each_mut(ptr, size, move |ptr, stack| stack.dealloc(ptr, global)) } } @@ -571,12 +585,6 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx size.bytes() ); - // Get the allocation. We need both the allocation and the MemoryExtra, so we cannot use `&mut`. - // FIXME: make `get_alloc_extra_mut` also return `&mut MemoryExtra`. - let extra = this.memory.get_alloc_extra(ptr.alloc_id)?; - let stacked_borrows = - extra.stacked_borrows.as_ref().expect("we should have Stacked Borrows data"); - let global = this.memory.extra.stacked_borrows.as_ref().unwrap().borrow(); // Update the stacks. // Make sure that raw pointers and mutable shared references are reborrowed "weak": // There could be existing unique pointers reborrowed from them that should remain valid! @@ -588,6 +596,12 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Shared references and *const are a whole different kind of game, the // permission is not uniform across the entire range! // We need a frozen-sensitive reborrow. + // We have to use shared references to alloc/memory_extra here since + // `visit_freeze_sensitive` needs to access the global state. + let extra = this.memory.get_alloc_extra(ptr.alloc_id)?; + let stacked_borrows = + extra.stacked_borrows.as_ref().expect("we should have Stacked Borrows data"); + let global = this.memory.extra.stacked_borrows.as_ref().unwrap().borrow(); return this.visit_freeze_sensitive(place, size, |cur_ptr, size, frozen| { // We are only ever `SharedReadOnly` inside the frozen bits. let perm = if frozen { @@ -596,15 +610,19 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Permission::SharedReadWrite }; let item = Item { perm, tag: new_tag, protector }; - stacked_borrows.for_each(cur_ptr, size, &*global, |cur_ptr, stack, global| { - stack.grant(cur_ptr, item, global) + stacked_borrows.for_each(cur_ptr, size, |cur_ptr, stack| { + stack.grant(cur_ptr, item, &*global) }) }); } }; + // Here we can avoid `borrow()` calls because we have mutable references. + let (alloc_extra, memory_extra) = this.memory.get_alloc_extra_mut(ptr.alloc_id)?; + let stacked_borrows = + alloc_extra.stacked_borrows.as_mut().expect("we should have Stacked Borrows data"); + let global = memory_extra.stacked_borrows.as_mut().unwrap().get_mut(); let item = Item { perm, tag: new_tag, protector }; - stacked_borrows - .for_each(ptr, size, &*global, |ptr, stack, global| stack.grant(ptr, item, global)) + stacked_borrows.for_each_mut(ptr, size, |ptr, stack| stack.grant(ptr, item, global)) } /// Retags an indidual pointer, returning the retagged version. @@ -640,7 +658,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Compute new borrow. let new_tag = { - let mut mem_extra = this.memory.extra.stacked_borrows.as_ref().unwrap().borrow_mut(); + let mem_extra = this.memory.extra.stacked_borrows.as_mut().unwrap().get_mut(); match kind { // Give up tracking for raw pointers. RefKind::Raw { .. } if !mem_extra.track_raw => Tag::Untagged, From e09c571eec1fff99632f96eb1f74a7e177fcf2b0 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 23 May 2021 11:00:25 +0200 Subject: [PATCH 2672/3747] avoid some borrow_mut calls in data_race --- src/data_race.rs | 54 +++++++++++++++++++++-------------------- src/shims/posix/sync.rs | 2 +- src/thread.rs | 22 +++++++++-------- 3 files changed, 41 insertions(+), 37 deletions(-) diff --git a/src/data_race.rs b/src/data_race.rs index fb6bf8f892952..45159ef4c07c3 100644 --- a/src/data_race.rs +++ b/src/data_race.rs @@ -598,7 +598,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { // of the time, based on `rate`. let rate = this.memory.extra.cmpxchg_weak_failure_rate; let cmpxchg_success = eq.to_bool()? - && (!can_fail_spuriously || this.memory.extra.rng.borrow_mut().gen::() < rate); + && (!can_fail_spuriously || this.memory.extra.rng.get_mut().gen::() < rate); let res = Immediate::ScalarPair( old.to_scalar_or_uninit(), Scalar::from_bool(cmpxchg_success).into(), @@ -647,7 +647,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { place: &MPlaceTy<'tcx, Tag>, atomic: AtomicWriteOp, ) -> InterpResult<'tcx> { - let this = self.eval_context_ref(); + let this = self.eval_context_mut(); this.validate_atomic_op( place, atomic, @@ -672,7 +672,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { use AtomicRwOp::*; let acquire = matches!(atomic, Acquire | AcqRel | SeqCst); let release = matches!(atomic, Release | AcqRel | SeqCst); - let this = self.eval_context_ref(); + let this = self.eval_context_mut(); this.validate_atomic_op(place, atomic, "Atomic RMW", move |memory, clocks, index, _| { if acquire { memory.load_acquire(clocks, index)?; @@ -690,7 +690,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { /// Update the data-race detector for an atomic fence on the current thread. fn validate_atomic_fence(&mut self, atomic: AtomicFenceOp) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - if let Some(data_race) = &this.memory.extra.data_race { + if let Some(data_race) = &mut this.memory.extra.data_race { data_race.maybe_perform_sync_operation(move |index, mut clocks| { log::trace!("Atomic fence on {:?} with ordering {:?}", index, atomic); @@ -771,7 +771,7 @@ impl VClockAlloc { } fn reset_clocks(&mut self, offset: Size, len: Size) { - let mut alloc_ranges = self.alloc_ranges.borrow_mut(); + let alloc_ranges = self.alloc_ranges.get_mut(); for (_, range) in alloc_ranges.iter_mut(offset, len) { // Reset the portion of the range *range = MemoryCellClocks::new(0, VectorIdx::MAX_INDEX); @@ -1025,6 +1025,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { if let Some(data_race) = &this.memory.extra.data_race { if data_race.multi_threaded.get() { // Load and log the atomic operation. + // Note that atomic loads are possible even from read-only allocations, so `get_alloc_extra_mut` is not an option. let place_ptr = place.ptr.assert_ptr(); let size = place.layout.size; let alloc_meta = @@ -1105,6 +1106,7 @@ struct ThreadExtraState { /// Global data-race detection state, contains the currently /// executing thread as well as the vector-clocks associated /// with each of the threads. +// FIXME: it is probably better to have one large RefCell, than to have so many small ones. #[derive(Debug, Clone)] pub struct GlobalState { /// Set to true once the first additional @@ -1158,7 +1160,7 @@ impl GlobalState { /// Create a new global state, setup with just thread-id=0 /// advanced to timestamp = 1. pub fn new() -> Self { - let global_state = GlobalState { + let mut global_state = GlobalState { multi_threaded: Cell::new(false), vector_clocks: RefCell::new(IndexVec::new()), vector_info: RefCell::new(IndexVec::new()), @@ -1172,9 +1174,9 @@ impl GlobalState { // Setup the main-thread since it is not explicitly created: // uses vector index and thread-id 0, also the rust runtime gives // the main-thread a name of "main". - let index = global_state.vector_clocks.borrow_mut().push(ThreadClockSet::default()); - global_state.vector_info.borrow_mut().push(ThreadId::new(0)); - global_state.thread_info.borrow_mut().push(ThreadExtraState { + let index = global_state.vector_clocks.get_mut().push(ThreadClockSet::default()); + global_state.vector_info.get_mut().push(ThreadId::new(0)); + global_state.thread_info.get_mut().push(ThreadExtraState { vector_index: Some(index), thread_name: Some("main".to_string().into_boxed_str()), termination_vector_clock: None, @@ -1221,7 +1223,7 @@ impl GlobalState { // Hook for thread creation, enabled multi-threaded execution and marks // the current thread timestamp as happening-before the current thread. #[inline] - pub fn thread_created(&self, thread: ThreadId) { + pub fn thread_created(&mut self, thread: ThreadId) { let current_index = self.current_index(); // Increment the number of active threads. @@ -1241,12 +1243,12 @@ impl GlobalState { let created_index = if let Some(reuse_index) = self.find_vector_index_reuse_candidate() { // Now re-configure the re-use candidate, increment the clock // for the new sync use of the vector. - let mut vector_clocks = self.vector_clocks.borrow_mut(); + let vector_clocks = self.vector_clocks.get_mut(); vector_clocks[reuse_index].increment_clock(reuse_index); // Locate the old thread the vector was associated with and update // it to represent the new thread instead. - let mut vector_info = self.vector_info.borrow_mut(); + let vector_info = self.vector_info.get_mut(); let old_thread = vector_info[reuse_index]; vector_info[reuse_index] = thread; @@ -1258,7 +1260,7 @@ impl GlobalState { } else { // No vector re-use candidates available, instead create // a new vector index. - let mut vector_info = self.vector_info.borrow_mut(); + let vector_info = self.vector_info.get_mut(); vector_info.push(thread) }; @@ -1268,7 +1270,7 @@ impl GlobalState { thread_info[thread].vector_index = Some(created_index); // Create a thread clock set if applicable. - let mut vector_clocks = self.vector_clocks.borrow_mut(); + let vector_clocks = self.vector_clocks.get_mut(); if created_index == vector_clocks.next_index() { vector_clocks.push(ThreadClockSet::default()); } @@ -1289,9 +1291,9 @@ impl GlobalState { /// Hook on a thread join to update the implicit happens-before relation /// between the joined thread and the current thread. #[inline] - pub fn thread_joined(&self, current_thread: ThreadId, join_thread: ThreadId) { - let mut clocks_vec = self.vector_clocks.borrow_mut(); - let thread_info = self.thread_info.borrow(); + pub fn thread_joined(&mut self, current_thread: ThreadId, join_thread: ThreadId) { + let clocks_vec = self.vector_clocks.get_mut(); + let thread_info = self.thread_info.get_mut(); // Load the vector clock of the current thread. let current_index = thread_info[current_thread] @@ -1329,9 +1331,9 @@ impl GlobalState { // If the thread is marked as terminated but not joined // then move the thread to the re-use set. - let mut termination = self.terminated_threads.borrow_mut(); + let termination = self.terminated_threads.get_mut(); if let Some(index) = termination.remove(&join_thread) { - let mut reuse = self.reuse_candidates.borrow_mut(); + let reuse = self.reuse_candidates.get_mut(); reuse.insert(index); } } @@ -1344,28 +1346,28 @@ impl GlobalState { /// This should be called strictly before any calls to /// `thread_joined`. #[inline] - pub fn thread_terminated(&self) { + pub fn thread_terminated(&mut self) { let current_index = self.current_index(); // Increment the clock to a unique termination timestamp. - let mut vector_clocks = self.vector_clocks.borrow_mut(); + let vector_clocks = self.vector_clocks.get_mut(); let current_clocks = &mut vector_clocks[current_index]; current_clocks.increment_clock(current_index); // Load the current thread id for the executing vector. - let vector_info = self.vector_info.borrow(); + let vector_info = self.vector_info.get_mut(); let current_thread = vector_info[current_index]; // Load the current thread metadata, and move to a terminated // vector state. Setting up the vector clock all join operations // will use. - let mut thread_info = self.thread_info.borrow_mut(); + let thread_info = self.thread_info.get_mut(); let current = &mut thread_info[current_thread]; current.termination_vector_clock = Some(current_clocks.clock.clone()); // Add this thread as a candidate for re-use after a thread join // occurs. - let mut termination = self.terminated_threads.borrow_mut(); + let termination = self.terminated_threads.get_mut(); termination.insert(current_thread, current_index); // Reduce the number of active threads, now that a thread has @@ -1392,9 +1394,9 @@ impl GlobalState { /// the thread name is used for improved diagnostics /// during a data-race. #[inline] - pub fn thread_set_name(&self, thread: ThreadId, name: String) { + pub fn thread_set_name(&mut self, thread: ThreadId, name: String) { let name = name.into_boxed_str(); - let mut thread_info = self.thread_info.borrow_mut(); + let thread_info = self.thread_info.get_mut(); thread_info[thread].thread_name = Some(name); } diff --git a/src/shims/posix/sync.rs b/src/shims/posix/sync.rs index 3b68e4eee4405..4725cd9fc3c81 100644 --- a/src/shims/posix/sync.rs +++ b/src/shims/posix/sync.rs @@ -58,7 +58,7 @@ fn mutexattr_set_kind<'mir, 'tcx: 'mir>( // (the kind has to be at its offset for compatibility with static initializer macros) fn mutex_get_kind<'mir, 'tcx: 'mir>( - ecx: &mut MiriEvalContext<'mir, 'tcx>, + ecx: &MiriEvalContext<'mir, 'tcx>, mutex_op: &OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, ScalarMaybeUninit> { let offset = if ecx.pointer_size().bytes() == 8 { 16 } else { 12 }; diff --git a/src/thread.rs b/src/thread.rs index 3418e8c7d2bfd..7ee18bb7f80e2 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -332,7 +332,7 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { fn join_thread( &mut self, joined_thread_id: ThreadId, - data_race: &Option, + data_race: Option<&mut data_race::GlobalState>, ) -> InterpResult<'tcx> { if self.threads[joined_thread_id].join_status != ThreadJoinStatus::Joinable { throw_ub_format!("trying to join a detached or already joined thread"); @@ -436,7 +436,10 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { /// Wakes up threads joining on the active one and deallocates thread-local statics. /// The `AllocId` that can now be freed is returned. - fn thread_terminated(&mut self, data_race: &Option) -> Vec { + fn thread_terminated( + &mut self, + mut data_race: Option<&mut data_race::GlobalState>, + ) -> Vec { let mut free_tls_statics = Vec::new(); { let mut thread_local_statics = self.thread_local_alloc_ids.borrow_mut(); @@ -452,14 +455,14 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { }); } // Set the thread into a terminated state in the data-race detector - if let Some(data_race) = data_race { + if let Some(ref mut data_race) = data_race { data_race.thread_terminated(); } // Check if we need to unblock any threads. for (i, thread) in self.threads.iter_enumerated_mut() { if thread.state == ThreadState::BlockedOnJoin(self.active_thread) { // The thread has terminated, mark happens-before edge to joining thread - if let Some(data_race) = data_race { + if let Some(ref mut data_race) = data_race { data_race.thread_joined(i, self.active_thread); } trace!("unblocking {:?} because {:?} terminated", i, self.active_thread); @@ -584,7 +587,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn create_thread(&mut self) -> ThreadId { let this = self.eval_context_mut(); let id = this.machine.threads.create_thread(); - if let Some(data_race) = &this.memory.extra.data_race { + if let Some(data_race) = &mut this.memory.extra.data_race { data_race.thread_created(id); } id @@ -599,8 +602,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx #[inline] fn join_thread(&mut self, joined_thread_id: ThreadId) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - let data_race = &this.memory.extra.data_race; - this.machine.threads.join_thread(joined_thread_id, data_race)?; + this.machine.threads.join_thread(joined_thread_id, this.memory.extra.data_race.as_mut())?; Ok(()) } @@ -664,7 +666,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx #[inline] fn set_active_thread_name(&mut self, new_thread_name: Vec) { let this = self.eval_context_mut(); - if let Some(data_race) = &this.memory.extra.data_race { + if let Some(data_race) = &mut this.memory.extra.data_race { if let Ok(string) = String::from_utf8(new_thread_name.clone()) { data_race.thread_set_name(this.machine.threads.active_thread, string); } @@ -759,8 +761,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx #[inline] fn thread_terminated(&mut self) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - let data_race = &this.memory.extra.data_race; - for alloc_id in this.machine.threads.thread_terminated(data_race) { + for alloc_id in this.machine.threads.thread_terminated(this.memory.extra.data_race.as_mut()) + { let ptr = this.memory.global_base_pointer(alloc_id.into())?; this.memory.deallocate(ptr, None, MiriMemoryKind::Tls.into())?; } From 9e0e9386a64c4dfa9875a2f3e8be265eaae394f4 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 23 May 2021 11:52:41 +0200 Subject: [PATCH 2673/3747] better approach to skip ZST reborrows --- src/stacked_borrows.rs | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index b1ab34b1f346b..3e176d94b9902 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -572,6 +572,18 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx new_tag: Tag, protect: bool, ) -> InterpResult<'tcx> { + // Nothing to do for ZSTs. + if size == Size::ZERO { + trace!( + "reborrow of size 0: {} reference {:?} derived from {:?} (pointee {})", + kind, + new_tag, + place.ptr, + place.layout.ty, + ); + return Ok(()); + } + let this = self.eval_context_mut(); let protector = if protect { Some(this.frame().extra.call_id) } else { None }; let ptr = place.ptr.assert_ptr(); @@ -617,6 +629,8 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } }; // Here we can avoid `borrow()` calls because we have mutable references. + // Note that this asserts that the allocation is mutable -- but since we are creating a + // mutable pointer, that seems reasonable. let (alloc_extra, memory_extra) = this.memory.get_alloc_extra_mut(ptr.alloc_id)?; let stacked_borrows = alloc_extra.stacked_borrows.as_mut().expect("we should have Stacked Borrows data"); @@ -649,12 +663,6 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // We can see dangling ptrs in here e.g. after a Box's `Unique` was // updated using "self.0 = ..." (can happen in Box::from_raw) so we cannot ICE; see miri#1050. let place = this.mplace_access_checked(place, Some(Align::from_bytes(1).unwrap()))?; - // Nothing to do for ZSTs. We use `is_bits` here because we *do* need to retag even ZSTs - // when there actually is a tag (to avoid inheriting a tag that would let us access more - // than 0 bytes). - if size == Size::ZERO && place.ptr.is_bits() { - return Ok(*val); - } // Compute new borrow. let new_tag = { From c60efa0c69786cf6e7f05d83ebd1a94c65788c25 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 23 May 2021 12:26:37 +0200 Subject: [PATCH 2674/3747] allocate backtrace strings mutably --- src/shims/backtrace.rs | 6 ++++-- src/shims/panic.rs | 3 ++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/shims/backtrace.rs b/src/shims/backtrace.rs index f936913114c48..e866868d729fa 100644 --- a/src/shims/backtrace.rs +++ b/src/shims/backtrace.rs @@ -119,8 +119,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // `lo.col` is 0-based - add 1 to make it 1-based for the caller. let colno: u32 = lo.col.0 as u32 + 1; - let name_alloc = this.allocate_str(&name, MiriMemoryKind::Rust.into()); - let filename_alloc = this.allocate_str(&filename, MiriMemoryKind::Rust.into()); + // These are "mutable" allocations as we consider them to be owned by the callee. + let name_alloc = this.allocate_str(&name, MiriMemoryKind::Rust.into(), Mutability::Mut); + let filename_alloc = + this.allocate_str(&filename, MiriMemoryKind::Rust.into(), Mutability::Mut); let lineno_alloc = Scalar::from_u32(lineno); let colno_alloc = Scalar::from_u32(colno); diff --git a/src/shims/panic.rs b/src/shims/panic.rs index b60da058e2cbb..06a434727b5fc 100644 --- a/src/shims/panic.rs +++ b/src/shims/panic.rs @@ -13,6 +13,7 @@ use log::trace; +use rustc_ast::Mutability; use rustc_middle::{mir, ty}; use rustc_target::spec::abi::Abi; use rustc_target::spec::PanicStrategy; @@ -169,7 +170,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); // First arg: message. - let msg = this.allocate_str(msg, MiriMemoryKind::Machine.into()); + let msg = this.allocate_str(msg, MiriMemoryKind::Machine.into(), Mutability::Not); // Call the lang item. let panic = this.tcx.lang_items().panic_fn().unwrap(); From 393ce98b32ced200fc443ca411edcb3383bcdef9 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 23 May 2021 12:37:52 +0200 Subject: [PATCH 2675/3747] fix a Stacked Borrows test whose output changed --- .../compile-fail/stacked_borrows/static_memory_modification.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/compile-fail/stacked_borrows/static_memory_modification.rs b/tests/compile-fail/stacked_borrows/static_memory_modification.rs index 88ac164947660..55a7f816c0340 100644 --- a/tests/compile-fail/stacked_borrows/static_memory_modification.rs +++ b/tests/compile-fail/stacked_borrows/static_memory_modification.rs @@ -3,6 +3,6 @@ static X: usize = 5; #[allow(mutable_transmutes)] fn main() { let _x = unsafe { - std::mem::transmute::<&usize, &mut usize>(&X) //~ ERROR borrow stack + std::mem::transmute::<&usize, &mut usize>(&X) //~ ERROR writing to alloc0 which is read-only }; } From a03f700fc9380e881d95c62a1e5fd7b49f1dc743 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 23 May 2021 18:05:50 +0200 Subject: [PATCH 2676/3747] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index bc7ef53b30372..31d26ea43e46e 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -6e92fb409816c65cd0a78a1fbcc71e2fbabdf50a +0f8cd43ee8c3614e04b5c624dd8a45758d7023da From f42a6d1026fc2350766be9a755d124ab49e28138 Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Thu, 27 May 2021 06:40:47 +0800 Subject: [PATCH 2677/3747] Skip doctests of `proc-macro` crates --- cargo-miri/bin.rs | 7 +++++++ test-cargo-miri/run-test.py | 4 ++++ test-cargo-miri/subcrate/src/lib.rs | 3 +++ test-cargo-miri/test.stderr-proc-macro-doctest.ref | 1 + test-cargo-miri/test.stdout-empty.ref | 0 5 files changed, 15 insertions(+) create mode 100644 test-cargo-miri/test.stderr-proc-macro-doctest.ref create mode 100644 test-cargo-miri/test.stdout-empty.ref diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index 295acd6638a2a..19d235cf67d71 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -903,6 +903,13 @@ fn phase_rustdoc(fst_arg: &str, mut args: env::Args) { show_error(format!("cross-interpreting doc-tests is not currently supported by Miri.")); } + // Doc-tests of `proc-macro` crates (and their dependencies) are always built for the host, + // so we are not able to run them in Miri. + if ArgFlagValueIter::new("--crate-type").any(|crate_type| crate_type == "proc-macro") { + eprintln!("Running doc-tests of `proc-macro` crates is not currently supported by Miri."); + return; + } + // For each doc-test, rustdoc starts two child processes: first the test is compiled, // then the produced executable is invoked. We want to reroute both of these to cargo-miri, // such that the first time we'll enter phase_cargo_rustc, and phase_cargo_runner second. diff --git a/test-cargo-miri/run-test.py b/test-cargo-miri/run-test.py index 9185c2507b6fc..c850e7d145919 100755 --- a/test-cargo-miri/run-test.py +++ b/test-cargo-miri/run-test.py @@ -140,6 +140,10 @@ def test_cargo_miri_test(): "test.subcrate.stdout.ref", "test.stderr-proc-macro.ref", env={'MIRIFLAGS': "-Zmiri-disable-isolation"}, ) + test("`cargo miri test` (subcrate, doctests)", + cargo_miri("test") + ["-p", "subcrate", "--doc"], + "test.stdout-empty.ref", "test.stderr-proc-macro-doctest.ref", + ) os.chdir(os.path.dirname(os.path.realpath(__file__))) os.environ["RUST_TEST_NOCAPTURE"] = "0" # this affects test output, so make sure it is not set diff --git a/test-cargo-miri/subcrate/src/lib.rs b/test-cargo-miri/subcrate/src/lib.rs index 706e368017c0e..07ed1acb7a05b 100644 --- a/test-cargo-miri/subcrate/src/lib.rs +++ b/test-cargo-miri/subcrate/src/lib.rs @@ -1,2 +1,5 @@ +#[cfg(doctest)] +use num_cpus as _; + #[cfg(test)] compile_error!("Miri should not touch me"); diff --git a/test-cargo-miri/test.stderr-proc-macro-doctest.ref b/test-cargo-miri/test.stderr-proc-macro-doctest.ref new file mode 100644 index 0000000000000..55d0f7cf54afd --- /dev/null +++ b/test-cargo-miri/test.stderr-proc-macro-doctest.ref @@ -0,0 +1 @@ +Running doc-tests of `proc-macro` crates is not currently supported by Miri. diff --git a/test-cargo-miri/test.stdout-empty.ref b/test-cargo-miri/test.stdout-empty.ref new file mode 100644 index 0000000000000..e69de29bb2d1d From 97b2824ada1a6f7128ec1355b48376b0f43455ce Mon Sep 17 00:00:00 2001 From: scottmcm Date: Thu, 27 May 2021 00:14:13 +0000 Subject: [PATCH 2678/3747] Add `copy_within` to the SB trophy case --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 547e2e15dadc4..469263115dd77 100644 --- a/README.md +++ b/README.md @@ -436,6 +436,7 @@ Violations of [Stacked Borrows] found that are likely bugs (but Stacked Borrows * [Windows `Env` iterator using a raw pointer outside its valid memory area](https://github.com/rust-lang/rust/pull/70479) * [`VecDeque::iter_mut` creating overlapping mutable references](https://github.com/rust-lang/rust/issues/74029) * [Various standard library aliasing issues involving raw pointers](https://github.com/rust-lang/rust/pull/78602) +* [`<[T]>::copy_within` using a loan after invalidating it](https://github.com/rust-lang/rust/pull/85610) ## License From 773eb1e97094a1c0da6adae0bc537f60d5a6467d Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Thu, 27 May 2021 18:34:38 +0800 Subject: [PATCH 2679/3747] "doc-tests" -> "doctests" --- cargo-miri/bin.rs | 2 +- test-cargo-miri/test.stderr-proc-macro-doctest.ref | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index 19d235cf67d71..a43e028219c36 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -906,7 +906,7 @@ fn phase_rustdoc(fst_arg: &str, mut args: env::Args) { // Doc-tests of `proc-macro` crates (and their dependencies) are always built for the host, // so we are not able to run them in Miri. if ArgFlagValueIter::new("--crate-type").any(|crate_type| crate_type == "proc-macro") { - eprintln!("Running doc-tests of `proc-macro` crates is not currently supported by Miri."); + eprintln!("Running doctests of `proc-macro` crates is not currently supported by Miri."); return; } diff --git a/test-cargo-miri/test.stderr-proc-macro-doctest.ref b/test-cargo-miri/test.stderr-proc-macro-doctest.ref index 55d0f7cf54afd..ca5e3a2392db8 100644 --- a/test-cargo-miri/test.stderr-proc-macro-doctest.ref +++ b/test-cargo-miri/test.stderr-proc-macro-doctest.ref @@ -1 +1 @@ -Running doc-tests of `proc-macro` crates is not currently supported by Miri. +Running doctests of `proc-macro` crates is not currently supported by Miri. From ffff7ff8a6e0a54443e5bef3eb3c8f4b7aeaf1c6 Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Thu, 27 May 2021 19:22:42 +0800 Subject: [PATCH 2680/3747] Use `compile_error!` instead of `use num_cpus` --- test-cargo-miri/subcrate/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test-cargo-miri/subcrate/src/lib.rs b/test-cargo-miri/subcrate/src/lib.rs index 07ed1acb7a05b..2ccb6704b05e6 100644 --- a/test-cargo-miri/subcrate/src/lib.rs +++ b/test-cargo-miri/subcrate/src/lib.rs @@ -1,5 +1,5 @@ #[cfg(doctest)] -use num_cpus as _; +compile_error!("rustdoc should not touch me"); #[cfg(test)] compile_error!("Miri should not touch me"); From 43db2aa5a91778de579c271524f0fa1bad767072 Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Thu, 27 May 2021 19:44:48 +0800 Subject: [PATCH 2681/3747] Change "Doc-tests" in the comment to "Doctests" --- cargo-miri/bin.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index a43e028219c36..8eaf3d36c69d7 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -903,7 +903,7 @@ fn phase_rustdoc(fst_arg: &str, mut args: env::Args) { show_error(format!("cross-interpreting doc-tests is not currently supported by Miri.")); } - // Doc-tests of `proc-macro` crates (and their dependencies) are always built for the host, + // Doctests of `proc-macro` crates (and their dependencies) are always built for the host, // so we are not able to run them in Miri. if ArgFlagValueIter::new("--crate-type").any(|crate_type| crate_type == "proc-macro") { eprintln!("Running doctests of `proc-macro` crates is not currently supported by Miri."); From d1de0843ed56eb663f9df9668ede39e58da778ec Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Thu, 27 May 2021 19:48:07 +0800 Subject: [PATCH 2682/3747] Change preexisting "doc-test" to "doctest" --- cargo-miri/bin.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index 8eaf3d36c69d7..7836b26ea5f91 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -900,7 +900,7 @@ fn phase_rustdoc(fst_arg: &str, mut args: env::Args) { } if crossmode { - show_error(format!("cross-interpreting doc-tests is not currently supported by Miri.")); + show_error(format!("cross-interpreting doctests is not currently supported by Miri.")); } // Doctests of `proc-macro` crates (and their dependencies) are always built for the host, @@ -910,7 +910,7 @@ fn phase_rustdoc(fst_arg: &str, mut args: env::Args) { return; } - // For each doc-test, rustdoc starts two child processes: first the test is compiled, + // For each doctest, rustdoc starts two child processes: first the test is compiled, // then the produced executable is invoked. We want to reroute both of these to cargo-miri, // such that the first time we'll enter phase_cargo_rustc, and phase_cargo_runner second. // From 9b2d42587f1b12188c1430bd79c058f4590f0ded Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Sat, 22 May 2021 22:45:00 +0800 Subject: [PATCH 2683/3747] `unwind` is no longer `Option` --- rust-version | 2 +- src/machine.rs | 6 ++-- src/shims/foreign_items.rs | 2 +- src/shims/intrinsics.rs | 2 +- src/shims/mod.rs | 4 +-- src/shims/panic.rs | 30 ++++++++++++------- .../compile-fail/panic/unwind_panic_abort.rs | 2 +- 7 files changed, 28 insertions(+), 20 deletions(-) diff --git a/rust-version b/rust-version index 31d26ea43e46e..7fc12e477e284 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -0f8cd43ee8c3614e04b5c624dd8a45758d7023da +ce0d64e03ef9875e0935bb60e989542b7ec29579 diff --git a/src/machine.rs b/src/machine.rs index fb2d877c38039..467696e839764 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -356,7 +356,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { abi: Abi, args: &[OpTy<'tcx, Tag>], ret: Option<(&PlaceTy<'tcx, Tag>, mir::BasicBlock)>, - unwind: Option, + unwind: StackPopUnwind, ) -> InterpResult<'tcx, Option<&'mir mir::Body<'tcx>>> { ecx.find_mir_or_eval_fn(instance, abi, args, ret, unwind) } @@ -368,7 +368,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { abi: Abi, args: &[OpTy<'tcx, Tag>], ret: Option<(&PlaceTy<'tcx, Tag>, mir::BasicBlock)>, - _unwind: Option, + _unwind: StackPopUnwind, ) -> InterpResult<'tcx> { ecx.call_dlsym(fn_val, abi, args, ret) } @@ -379,7 +379,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { instance: ty::Instance<'tcx>, args: &[OpTy<'tcx, Tag>], ret: Option<(&PlaceTy<'tcx, Tag>, mir::BasicBlock)>, - unwind: Option, + unwind: StackPopUnwind, ) -> InterpResult<'tcx> { ecx.call_intrinsic(instance, args, ret, unwind) } diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 47d939e697226..4c96c99eeeaf2 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -120,7 +120,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx abi: Abi, args: &[OpTy<'tcx, Tag>], ret: Option<(&PlaceTy<'tcx, Tag>, mir::BasicBlock)>, - unwind: Option, + unwind: StackPopUnwind, ) -> InterpResult<'tcx, Option<&'mir mir::Body<'tcx>>> { let this = self.eval_context_mut(); let attrs = this.tcx.get_attrs(def_id); diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index f2979a3c69d80..c018dd8738108 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -23,7 +23,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx instance: ty::Instance<'tcx>, args: &[OpTy<'tcx, Tag>], ret: Option<(&PlaceTy<'tcx, Tag>, mir::BasicBlock)>, - _unwind: Option, + _unwind: StackPopUnwind, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); diff --git a/src/shims/mod.rs b/src/shims/mod.rs index 13ea14b4b9d40..bb8d0bb8db909 100644 --- a/src/shims/mod.rs +++ b/src/shims/mod.rs @@ -29,7 +29,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx abi: Abi, args: &[OpTy<'tcx, Tag>], ret: Option<(&PlaceTy<'tcx, Tag>, mir::BasicBlock)>, - unwind: Option, + unwind: StackPopUnwind, ) -> InterpResult<'tcx, Option<&'mir mir::Body<'tcx>>> { let this = self.eval_context_mut(); trace!("eval_fn_call: {:#?}, {:?}", instance, ret.map(|p| p.0)); @@ -64,7 +64,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ptr_op: &OpTy<'tcx, Tag>, align_op: &OpTy<'tcx, Tag>, ret: Option<(&PlaceTy<'tcx, Tag>, mir::BasicBlock)>, - unwind: Option, + unwind: StackPopUnwind, ) -> InterpResult<'tcx, bool> { let this = self.eval_context_mut(); let (dest, ret) = ret.unwrap(); diff --git a/src/shims/panic.rs b/src/shims/panic.rs index 06a434727b5fc..b1da7f340fce3 100644 --- a/src/shims/panic.rs +++ b/src/shims/panic.rs @@ -41,15 +41,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn handle_miri_start_panic( &mut self, args: &[OpTy<'tcx, Tag>], - unwind: Option, + unwind: StackPopUnwind, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); trace!("miri_start_panic: {:?}", this.frame().instance); - // Make sure we only start unwinding when this matches our panic strategy. - if this.tcx.sess.panic_strategy() != PanicStrategy::Unwind { - throw_ub_format!("unwinding despite panic=abort"); - } // Get the raw pointer stored in arg[0] (the panic payload). let &[ref payload] = check_arg_count(args)?; @@ -59,7 +55,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx thread.panic_payload = Some(payload); // Jump to the unwind block to begin unwinding. - this.unwind_to_block(unwind); + this.unwind_to_block(unwind)?; return Ok(()); } @@ -99,7 +95,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx &[data.into()], Some(&ret_place), // Directly return to caller. - StackPopCleanup::Goto { ret: Some(ret), unwind: None }, + StackPopCleanup::Goto { ret: Some(ret), unwind: StackPopUnwind::Skip }, )?; // We ourselves will return `0`, eventually (will be overwritten if we catch a panic). @@ -155,7 +151,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx &[catch_unwind.data.into(), payload.into()], Some(&ret_place), // Directly return to caller of `try`. - StackPopCleanup::Goto { ret: Some(catch_unwind.ret), unwind: None }, + StackPopCleanup::Goto { ret: Some(catch_unwind.ret), unwind: StackPopUnwind::Skip }, )?; // We pushed a new stack frame, the engine should not do any jumping now! @@ -166,7 +162,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } /// Starta a panic in the interpreter with the given message as payload. - fn start_panic(&mut self, msg: &str, unwind: Option) -> InterpResult<'tcx> { + fn start_panic(&mut self, msg: &str, unwind: StackPopUnwind) -> InterpResult<'tcx> { let this = self.eval_context_mut(); // First arg: message. @@ -209,12 +205,24 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Abi::Rust, &[index.into(), len.into()], None, - StackPopCleanup::Goto { ret: None, unwind }, + StackPopCleanup::Goto { + ret: None, + unwind: match unwind { + Some(cleanup) => StackPopUnwind::Cleanup(cleanup), + None => StackPopUnwind::Skip, + }, + }, )?; } _ => { // Forward everything else to `panic` lang item. - this.start_panic(msg.description(), unwind)?; + this.start_panic( + msg.description(), + match unwind { + Some(cleanup) => StackPopUnwind::Cleanup(cleanup), + None => StackPopUnwind::Skip, + }, + )?; } } Ok(()) diff --git a/tests/compile-fail/panic/unwind_panic_abort.rs b/tests/compile-fail/panic/unwind_panic_abort.rs index 05284eb770b22..a333a4b0ded8f 100644 --- a/tests/compile-fail/panic/unwind_panic_abort.rs +++ b/tests/compile-fail/panic/unwind_panic_abort.rs @@ -7,5 +7,5 @@ extern "Rust" { } fn main() { - unsafe { miri_start_panic(&mut 0); } //~ ERROR unwinding despite panic=abort + unsafe { miri_start_panic(&mut 0); } //~ ERROR unwinding past a stack frame that does not allow unwinding } From 7e9da8d30eb07093c09fd90276aeca4a469a0432 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Sat, 8 May 2021 12:20:51 -0400 Subject: [PATCH 2684/3747] Add `measureme` integration for profiling the interpreted program This PR uses the `measureme` crate to profile the call stack of the program being interpreted by Miri. This is accomplished by starting a measureme 'event' when we enter a function call, and ending the event when we exit the call. The `measureme` tooling can be used to produce a call stack from the generated profile data. Limitations: * We currently record every single entry/exit. This might generate very large profile outputs for programs with a large number of function calls. In follow-up work, we might want to explore sampling (e.g. only recording every N function calls). * This does not integrate very well with Miri's concurrency support. Each event we record starts when we push a frame, and ends when we pop a frame. As a result, switching between virtual threads will cause events from different threads to be interleaved. Additionally, the recorded for a particular frame will include all of the work Miri does before that frame completes, including executing another thread. The `measureme` integration is off by default, and must be enabled via `-Zmiri-measureme=` --- Cargo.lock | 87 ++++++++++++++++++++++++++++++++++++++++++++++ Cargo.toml | 1 + README.md | 4 +++ src/bin/miri.rs | 4 +++ src/eval.rs | 6 +++- src/machine.rs | 50 +++++++++++++++++++++----- src/shims/panic.rs | 1 - 7 files changed, 143 insertions(+), 10 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 69cc1966a6f86..3ae2700321805 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -167,6 +167,15 @@ version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" +[[package]] +name = "instant" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61124eeebbd69b8190558df225adf7e4caafce0d743919e5d6b19652314ec5ec" +dependencies = [ + "cfg-if", +] + [[package]] name = "itoa" version = "0.4.7" @@ -185,6 +194,15 @@ version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "56d855069fafbb9b344c0f962150cd2c1187975cb1c22c1522c240d8c4986714" +[[package]] +name = "lock_api" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a3c91c24eae6777794bb1997ad98bbb87daf92890acab859f7eaa4320333176" +dependencies = [ + "scopeguard", +] + [[package]] name = "log" version = "0.4.14" @@ -194,12 +212,34 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "measureme" +version = "9.1.1" +source = "git+https://github.com/rust-lang/measureme?rev=501d6a3c192beee5e633a6c5f79130bedfdadcb5#501d6a3c192beee5e633a6c5f79130bedfdadcb5" +dependencies = [ + "log", + "memmap2", + "parking_lot", + "perf-event-open-sys", + "rustc-hash", + "smallvec", +] + [[package]] name = "memchr" version = "2.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ee1c47aaa256ecabcaea351eae4a9b01ef39ed810004e298d2511ed284b1525" +[[package]] +name = "memmap2" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "397d1a6d6d0563c0f5462bbdae662cf6c784edf5e828e40c7257f85d82bf56dd" +dependencies = [ + "libc", +] + [[package]] name = "miow" version = "0.3.7" @@ -220,6 +260,7 @@ dependencies = [ "hex", "libc", "log", + "measureme", "rand", "rustc-workspace-hack", "rustc_version", @@ -237,6 +278,40 @@ dependencies = [ "libc", ] +[[package]] +name = "parking_lot" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d7744ac029df22dca6284efe4e898991d28e3085c706c972bcd7da4a27a15eb" +dependencies = [ + "instant", + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa7a782938e745763fe6907fc6ba86946d72f49fe7e21de074e08128a99fb018" +dependencies = [ + "cfg-if", + "instant", + "libc", + "redox_syscall", + "smallvec", + "winapi", +] + +[[package]] +name = "perf-event-open-sys" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce9bedf5da2c234fdf2391ede2b90fabf585355f33100689bc364a3ea558561a" +dependencies = [ + "libc", +] + [[package]] name = "pest" version = "2.1.3" @@ -355,6 +430,12 @@ dependencies = [ "winapi", ] +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + [[package]] name = "rustc-workspace-hack" version = "1.0.0" @@ -394,6 +475,12 @@ version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + [[package]] name = "semver" version = "0.11.0" diff --git a/Cargo.toml b/Cargo.toml index ab7d88e66934a..fd212e43047eb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,6 +18,7 @@ test = false # we have no unit tests doctest = false # and no doc tests [dependencies] +measureme = { git = "https://github.com/rust-lang/measureme", rev = "501d6a3c192beee5e633a6c5f79130bedfdadcb5" } getrandom = { version = "0.2", features = ["std"] } env_logger = "0.8" log = "0.4" diff --git a/README.md b/README.md index 469263115dd77..87f6b87c66269 100644 --- a/README.md +++ b/README.md @@ -258,6 +258,10 @@ environment variable: this pointer. Note that it is not currently guaranteed that code that works with `-Zmiri-track-raw-pointers` also works without `-Zmiri-track-raw-pointers`, but for the vast majority of code, this will be the case. +* `-Zmiri-measureme=` enables `measureme` profiling for the interpreted program. + This can be used to find which parts of your program are executing slowly under Miri. + The profile is written out to a file with the prefix ``, and can be processed + using the tools in the repository https://github.com/rust-lang/measureme Some native rustc `-Z` flags are also very relevant for Miri: diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 4a1ea3a542862..47cde5c353e13 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -318,6 +318,10 @@ fn main() { }; miri_config.cmpxchg_weak_failure_rate = rate; } + arg if arg.starts_with("-Zmiri-measureme=") => { + let measureme_out = arg.strip_prefix("-Zmiri-measureme=").unwrap(); + miri_config.measureme_out = Some(measureme_out.to_string()); + } _ => { // Forward to rustc. rustc_args.push(arg); diff --git a/src/eval.rs b/src/eval.rs index 1e46015f87a82..a5268b58a2d12 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -54,6 +54,9 @@ pub struct MiriConfig { /// Rate of spurious failures for compare_exchange_weak atomic operations, /// between 0.0 and 1.0, defaulting to 0.8 (80% chance of failure). pub cmpxchg_weak_failure_rate: f64, + /// If `Some`, enable the `measureme` profiler, writing results to the specified + /// directory. + pub measureme_out: Option, } impl Default for MiriConfig { @@ -73,6 +76,7 @@ impl Default for MiriConfig { track_raw: false, data_race_detector: true, cmpxchg_weak_failure_rate: 0.8, + measureme_out: None, } } } @@ -92,7 +96,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( tcx, rustc_span::source_map::DUMMY_SP, param_env, - Evaluator::new(config.communicate, config.validate, layout_cx), + Evaluator::new(&config, layout_cx), MemoryExtra::new(&config), ); // Complete initialization. diff --git a/src/machine.rs b/src/machine.rs index 467696e839764..77c606a83f47a 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -10,6 +10,8 @@ use std::time::Instant; use log::trace; use rand::rngs::StdRng; use rand::SeedableRng; +use std::collections::hash_map::Entry; +use measureme::{Profiler, StringId, EventId, DetachedTiming}; use rustc_data_structures::fx::FxHashMap; use rustc_middle::{ @@ -34,7 +36,6 @@ pub const STACK_SIZE: u64 = 16 * PAGE_SIZE; // whatever pub const NUM_CPUS: u64 = 1; /// Extra data stored with each stack frame -#[derive(Debug)] pub struct FrameData<'tcx> { /// Extra data for Stacked Borrows. pub call_id: stacked_borrows::CallId, @@ -43,6 +44,8 @@ pub struct FrameData<'tcx> { /// called by `try`). When this frame is popped during unwinding a panic, /// we stop unwinding, use the `CatchUnwindData` to handle catching. pub catch_unwind: Option>, + + pub timing: Option, } /// Extra memory kinds @@ -270,16 +273,21 @@ pub struct Evaluator<'mir, 'tcx> { /// Allocations that are considered roots of static memory (that may leak). pub(crate) static_roots: Vec, + + profiler: Option, + string_cache: FxHashMap, } impl<'mir, 'tcx> Evaluator<'mir, 'tcx> { pub(crate) fn new( - communicate: bool, - validate: bool, + config: &MiriConfig, layout_cx: LayoutCx<'tcx, TyCtxt<'tcx>>, ) -> Self { let layouts = PrimitiveLayouts::new(layout_cx).expect("Couldn't get layouts of primitive types"); + let profiler = config.measureme_out.as_ref().map(|out| { + Profiler::new(out).expect("Couldn't create `measureme` profiler") + }); Evaluator { // `env_vars` could be initialized properly here if `Memory` were available before // calling this method. @@ -288,14 +296,16 @@ impl<'mir, 'tcx> Evaluator<'mir, 'tcx> { argv: None, cmd_line: None, tls: TlsData::default(), - communicate, - validate, + communicate: config.communicate, + validate: config.validate, file_handler: Default::default(), dir_handler: Default::default(), time_anchor: Instant::now(), layouts, threads: ThreadManager::default(), static_roots: Vec::new(), + profiler, + string_cache: Default::default(), } } } @@ -601,7 +611,26 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { let call_id = stacked_borrows.map_or(NonZeroU64::new(1).unwrap(), |stacked_borrows| { stacked_borrows.borrow_mut().new_call() }); - let extra = FrameData { call_id, catch_unwind: None }; + let timing = if let Some(profiler) = ecx.machine.profiler.as_ref() { + let fn_name = frame.instance.to_string(); + let entry = ecx.machine.string_cache.entry(fn_name.clone()); + let name = match entry { + Entry::Occupied(e) => *e.get(), + Entry::Vacant(e) => { + *e.insert(profiler.alloc_string(&*fn_name)) + } + }; + + Some(profiler.start_recording_interval_event_detached( + name, + EventId::from_label(name), + 0 + )) + } else { + None + }; + + let extra = FrameData { call_id, catch_unwind: None, timing }; Ok(frame.with_extra(extra)) } @@ -625,10 +654,15 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { #[inline(always)] fn after_stack_pop( ecx: &mut InterpCx<'mir, 'tcx, Self>, - frame: Frame<'mir, 'tcx, Tag, FrameData<'tcx>>, + mut frame: Frame<'mir, 'tcx, Tag, FrameData<'tcx>>, unwinding: bool, ) -> InterpResult<'tcx, StackPopJump> { - ecx.handle_stack_pop(frame.extra, unwinding) + let timing = frame.extra.timing.take(); + let res = ecx.handle_stack_pop(frame.extra, unwinding); + if let Some(profiler) = ecx.machine.profiler.as_ref() { + profiler.finish_recording_interval_event(timing.unwrap()); + } + res } #[inline(always)] diff --git a/src/shims/panic.rs b/src/shims/panic.rs index b1da7f340fce3..6b08ee8e18404 100644 --- a/src/shims/panic.rs +++ b/src/shims/panic.rs @@ -119,7 +119,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, StackPopJump> { let this = self.eval_context_mut(); - trace!("handle_stack_pop(extra = {:?}, unwinding = {})", extra, unwinding); if let Some(stacked_borrows) = &this.memory.extra.stacked_borrows { stacked_borrows.borrow_mut().end_call(extra.call_id); } From 2166eaed90a9f94e5078bd470b5cd8cbdccc7543 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Sat, 8 May 2021 13:17:58 -0400 Subject: [PATCH 2685/3747] Use active thread id --- src/machine.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/machine.rs b/src/machine.rs index 77c606a83f47a..7a26a609bb6db 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -624,7 +624,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { Some(profiler.start_recording_interval_event_detached( name, EventId::from_label(name), - 0 + ecx.get_active_thread().to_u32() )) } else { None From 16f469280ee8dfea1ca4f24a272f44865896006e Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Sat, 29 May 2021 17:09:46 -0500 Subject: [PATCH 2686/3747] Address review comments --- Cargo.lock | 5 +++-- Cargo.toml | 2 +- README.md | 8 ++++---- src/eval.rs | 4 ++-- src/machine.rs | 33 +++++++++++++++++++-------------- 5 files changed, 29 insertions(+), 23 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 3ae2700321805..e728dc07b9286 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -214,8 +214,9 @@ dependencies = [ [[package]] name = "measureme" -version = "9.1.1" -source = "git+https://github.com/rust-lang/measureme?rev=501d6a3c192beee5e633a6c5f79130bedfdadcb5#501d6a3c192beee5e633a6c5f79130bedfdadcb5" +version = "9.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78f7a41bc6f856a2cf0e95094ad5121f82500e2d9a0f3c0171d98f6566d8117d" dependencies = [ "log", "memmap2", diff --git a/Cargo.toml b/Cargo.toml index fd212e43047eb..7ee96f7e99e68 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,7 +18,6 @@ test = false # we have no unit tests doctest = false # and no doc tests [dependencies] -measureme = { git = "https://github.com/rust-lang/measureme", rev = "501d6a3c192beee5e633a6c5f79130bedfdadcb5" } getrandom = { version = "0.2", features = ["std"] } env_logger = "0.8" log = "0.4" @@ -31,6 +30,7 @@ smallvec = "1.4.2" # See the `src/tools/rustc-workspace-hack/README.md` file in `rust-lang/rust` # for more information. rustc-workspace-hack = "1.0.0" +measureme = "9.1.2" # Enable some feature flags that dev-dependencies need but dependencies # do not. This makes `./miri install` after `./miri build` faster. diff --git a/README.md b/README.md index 87f6b87c66269..b214ab6d09c12 100644 --- a/README.md +++ b/README.md @@ -222,6 +222,10 @@ environment variable: times to exclude several variables. On Windows, the `TERM` environment variable is excluded by default. * `-Zmiri-ignore-leaks` disables the memory leak checker. +* `-Zmiri-measureme=` enables `measureme` profiling for the interpreted program. + This can be used to find which parts of your program are executing slowly under Miri. + The profile is written out to a file with the prefix ``, and can be processed + using the tools in the repository https://github.com/rust-lang/measureme. * `-Zmiri-seed=` configures the seed of the RNG that Miri uses to resolve non-determinism. This RNG is used to pick base addresses for allocations. When isolation is enabled (the default), this is also used to emulate system @@ -258,10 +262,6 @@ environment variable: this pointer. Note that it is not currently guaranteed that code that works with `-Zmiri-track-raw-pointers` also works without `-Zmiri-track-raw-pointers`, but for the vast majority of code, this will be the case. -* `-Zmiri-measureme=` enables `measureme` profiling for the interpreted program. - This can be used to find which parts of your program are executing slowly under Miri. - The profile is written out to a file with the prefix ``, and can be processed - using the tools in the repository https://github.com/rust-lang/measureme Some native rustc `-Z` flags are also very relevant for Miri: diff --git a/src/eval.rs b/src/eval.rs index a5268b58a2d12..52e554f57d7e1 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -54,8 +54,8 @@ pub struct MiriConfig { /// Rate of spurious failures for compare_exchange_weak atomic operations, /// between 0.0 and 1.0, defaulting to 0.8 (80% chance of failure). pub cmpxchg_weak_failure_rate: f64, - /// If `Some`, enable the `measureme` profiler, writing results to the specified - /// directory. + /// If `Some`, enable the `measureme` profiler, writing results to a file + /// with the specified prefix. pub measureme_out: Option, } diff --git a/src/machine.rs b/src/machine.rs index 7a26a609bb6db..4ed2fba43c142 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -10,7 +10,6 @@ use std::time::Instant; use log::trace; use rand::rngs::StdRng; use rand::SeedableRng; -use std::collections::hash_map::Entry; use measureme::{Profiler, StringId, EventId, DetachedTiming}; use rustc_data_structures::fx::FxHashMap; @@ -45,6 +44,9 @@ pub struct FrameData<'tcx> { /// we stop unwinding, use the `CatchUnwindData` to handle catching. pub catch_unwind: Option>, + /// If `measureme` profiling is enabled, holds timing information + /// for the start of this frame. When we finish executing this frame, + /// we use this to register a completed event with `measureme`. pub timing: Option, } @@ -274,7 +276,11 @@ pub struct Evaluator<'mir, 'tcx> { /// Allocations that are considered roots of static memory (that may leak). pub(crate) static_roots: Vec, + /// The `measureme` profiler used to record timing information about + /// the emulated program. profiler: Option, + /// Used with `profiler` to cache the `StringId`s for event names + /// uesd with `measureme`. string_cache: FxHashMap, } @@ -607,29 +613,28 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { ecx: &mut InterpCx<'mir, 'tcx, Self>, frame: Frame<'mir, 'tcx, Tag>, ) -> InterpResult<'tcx, Frame<'mir, 'tcx, Tag, FrameData<'tcx>>> { - let stacked_borrows = ecx.memory.extra.stacked_borrows.as_ref(); - let call_id = stacked_borrows.map_or(NonZeroU64::new(1).unwrap(), |stacked_borrows| { - stacked_borrows.borrow_mut().new_call() - }); + // Start recording our event before doing anything else let timing = if let Some(profiler) = ecx.machine.profiler.as_ref() { let fn_name = frame.instance.to_string(); let entry = ecx.machine.string_cache.entry(fn_name.clone()); - let name = match entry { - Entry::Occupied(e) => *e.get(), - Entry::Vacant(e) => { - *e.insert(profiler.alloc_string(&*fn_name)) - } - }; + let name = entry.or_insert_with(|| { + profiler.alloc_string(&*fn_name) + }); Some(profiler.start_recording_interval_event_detached( - name, - EventId::from_label(name), - ecx.get_active_thread().to_u32() + *name, + EventId::from_label(*name), + ecx.get_active_thread().to_u32(), )) } else { None }; + let stacked_borrows = ecx.memory.extra.stacked_borrows.as_ref(); + let call_id = stacked_borrows.map_or(NonZeroU64::new(1).unwrap(), |stacked_borrows| { + stacked_borrows.borrow_mut().new_call() + }); + let extra = FrameData { call_id, catch_unwind: None, timing }; Ok(frame.with_extra(extra)) } From 20f1b2a969f6d61f5f8bf4d7877d30c66e22e70f Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Sat, 29 May 2021 17:16:12 -0500 Subject: [PATCH 2687/3747] Run fmt --- src/machine.rs | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/src/machine.rs b/src/machine.rs index 4ed2fba43c142..1a01ece6c9a8d 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -8,9 +8,9 @@ use std::num::NonZeroU64; use std::time::Instant; use log::trace; +use measureme::{DetachedTiming, EventId, Profiler, StringId}; use rand::rngs::StdRng; use rand::SeedableRng; -use measureme::{Profiler, StringId, EventId, DetachedTiming}; use rustc_data_structures::fx::FxHashMap; use rustc_middle::{ @@ -285,15 +285,13 @@ pub struct Evaluator<'mir, 'tcx> { } impl<'mir, 'tcx> Evaluator<'mir, 'tcx> { - pub(crate) fn new( - config: &MiriConfig, - layout_cx: LayoutCx<'tcx, TyCtxt<'tcx>>, - ) -> Self { + pub(crate) fn new(config: &MiriConfig, layout_cx: LayoutCx<'tcx, TyCtxt<'tcx>>) -> Self { let layouts = PrimitiveLayouts::new(layout_cx).expect("Couldn't get layouts of primitive types"); - let profiler = config.measureme_out.as_ref().map(|out| { - Profiler::new(out).expect("Couldn't create `measureme` profiler") - }); + let profiler = config + .measureme_out + .as_ref() + .map(|out| Profiler::new(out).expect("Couldn't create `measureme` profiler")); Evaluator { // `env_vars` could be initialized properly here if `Memory` were available before // calling this method. @@ -617,9 +615,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { let timing = if let Some(profiler) = ecx.machine.profiler.as_ref() { let fn_name = frame.instance.to_string(); let entry = ecx.machine.string_cache.entry(fn_name.clone()); - let name = entry.or_insert_with(|| { - profiler.alloc_string(&*fn_name) - }); + let name = entry.or_insert_with(|| profiler.alloc_string(&*fn_name)); Some(profiler.start_recording_interval_event_detached( *name, From 0317e5bfd60246c224071303f0ffa6a12a2096ab Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Sun, 30 May 2021 10:04:57 -0500 Subject: [PATCH 2688/3747] Address more review comments --- src/machine.rs | 25 ++++++++++++++++--------- src/shims/panic.rs | 1 + 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/src/machine.rs b/src/machine.rs index 1a01ece6c9a8d..ed633b5e17f4b 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -8,7 +8,6 @@ use std::num::NonZeroU64; use std::time::Instant; use log::trace; -use measureme::{DetachedTiming, EventId, Profiler, StringId}; use rand::rngs::StdRng; use rand::SeedableRng; @@ -47,7 +46,16 @@ pub struct FrameData<'tcx> { /// If `measureme` profiling is enabled, holds timing information /// for the start of this frame. When we finish executing this frame, /// we use this to register a completed event with `measureme`. - pub timing: Option, + pub timing: Option, +} + +impl<'tcx> std::fmt::Debug for FrameData<'tcx> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("FrameData") + .field("call_id", &self.call_id) + .field("catch_unwind", &self.catch_unwind) + .finish() + } } /// Extra memory kinds @@ -278,20 +286,19 @@ pub struct Evaluator<'mir, 'tcx> { /// The `measureme` profiler used to record timing information about /// the emulated program. - profiler: Option, + profiler: Option, /// Used with `profiler` to cache the `StringId`s for event names /// uesd with `measureme`. - string_cache: FxHashMap, + string_cache: FxHashMap, } impl<'mir, 'tcx> Evaluator<'mir, 'tcx> { pub(crate) fn new(config: &MiriConfig, layout_cx: LayoutCx<'tcx, TyCtxt<'tcx>>) -> Self { let layouts = PrimitiveLayouts::new(layout_cx).expect("Couldn't get layouts of primitive types"); - let profiler = config - .measureme_out - .as_ref() - .map(|out| Profiler::new(out).expect("Couldn't create `measureme` profiler")); + let profiler = config.measureme_out.as_ref().map(|out| { + measureme::Profiler::new(out).expect("Couldn't create `measureme` profiler") + }); Evaluator { // `env_vars` could be initialized properly here if `Memory` were available before // calling this method. @@ -619,7 +626,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { Some(profiler.start_recording_interval_event_detached( *name, - EventId::from_label(*name), + measureme::EventId::from_label(*name), ecx.get_active_thread().to_u32(), )) } else { diff --git a/src/shims/panic.rs b/src/shims/panic.rs index 6b08ee8e18404..b1da7f340fce3 100644 --- a/src/shims/panic.rs +++ b/src/shims/panic.rs @@ -119,6 +119,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, StackPopJump> { let this = self.eval_context_mut(); + trace!("handle_stack_pop(extra = {:?}, unwinding = {})", extra, unwinding); if let Some(stacked_borrows) = &this.memory.extra.stacked_borrows { stacked_borrows.borrow_mut().end_call(extra.call_id); } From c89a5d62ee4100018d8422ebdcddb47ed6290fcd Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 30 May 2021 17:13:49 +0200 Subject: [PATCH 2689/3747] add comment to debug impl --- src/machine.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/machine.rs b/src/machine.rs index ed633b5e17f4b..4f643e7f50917 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -51,6 +51,7 @@ pub struct FrameData<'tcx> { impl<'tcx> std::fmt::Debug for FrameData<'tcx> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + // Omitting `timing`, it does not support `Debug`. f.debug_struct("FrameData") .field("call_id", &self.call_id) .field("catch_unwind", &self.catch_unwind) From 71f41405500cec42be22f0080bf3f83f97bfa768 Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Sun, 30 May 2021 01:36:06 +0800 Subject: [PATCH 2690/3747] Add `-Zmiri-disable-abi-check` --- README.md | 4 + src/bin/miri.rs | 3 + src/eval.rs | 3 + src/helpers.rs | 13 +- src/machine.rs | 9 ++ src/shims/foreign_items.rs | 54 ++++---- src/shims/posix/dlsym.rs | 2 +- src/shims/posix/foreign_items.rs | 122 +++++++++--------- src/shims/posix/linux/foreign_items.rs | 32 ++--- src/shims/posix/macos/foreign_items.rs | 38 +++--- src/shims/windows/dlsym.rs | 2 +- src/shims/windows/foreign_items.rs | 80 ++++++------ tests/compile-fail/check_callback_abi.rs | 15 +++ .../concurrency/unwind_top_of_stack.rs | 6 +- tests/compile-fail/panic/bad_unwind.rs | 2 + tests/run-pass/disable_abi_check.rs | 24 ++++ 16 files changed, 235 insertions(+), 174 deletions(-) create mode 100644 tests/compile-fail/check_callback_abi.rs create mode 100644 tests/run-pass/disable_abi_check.rs diff --git a/README.md b/README.md index b214ab6d09c12..f87a7e989d973 100644 --- a/README.md +++ b/README.md @@ -214,6 +214,8 @@ environment variable: as out-of-bounds accesses) first. Setting this flag means Miri can miss bugs in your program. However, this can also help to make Miri run faster. Using this flag is **unsound**. +* `-Zmiri-disable-abi-check` disables checking [function ABI]. Using this flag + is **unsound**. * `-Zmiri-disable-isolation` disables host isolation. As a consequence, the program has access to host resources such as environment variables, file systems, and randomness. @@ -263,6 +265,8 @@ environment variable: with `-Zmiri-track-raw-pointers` also works without `-Zmiri-track-raw-pointers`, but for the vast majority of code, this will be the case. +[function ABI]: https://doc.rust-lang.org/reference/items/functions.html#extern-function-qualifier + Some native rustc `-Z` flags are also very relevant for Miri: * `-Zmir-opt-level` controls how many MIR optimizations are performed. Miri diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 47cde5c353e13..e921407f63fb4 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -227,6 +227,9 @@ fn main() { "-Zmiri-symbolic-alignment-check" => { miri_config.check_alignment = miri::AlignmentCheck::Symbolic; } + "-Zmiri-disable-abi-check" => { + miri_config.check_abi = false; + } "-Zmiri-disable-isolation" => { miri_config.communicate = true; } diff --git a/src/eval.rs b/src/eval.rs index 52e554f57d7e1..6646783d349ca 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -31,6 +31,8 @@ pub struct MiriConfig { pub stacked_borrows: bool, /// Controls alignment checking. pub check_alignment: AlignmentCheck, + /// Controls function [ABI](Abi) checking. + pub check_abi: bool, /// Determines if communication with the host environment is enabled. pub communicate: bool, /// Determines if memory leaks should be ignored. @@ -65,6 +67,7 @@ impl Default for MiriConfig { validate: true, stacked_borrows: true, check_alignment: AlignmentCheck::Int, + check_abi: true, communicate: false, ignore_leaks: false, excluded_env_vars: vec![], diff --git a/src/helpers.rs b/src/helpers.rs index 45a5a8d4170bf..af6985ccebdbf 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -165,7 +165,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); let param_env = ty::ParamEnv::reveal_all(); // in Miri this is always the param_env we use... and this.param_env is private. let callee_abi = f.ty(*this.tcx, param_env).fn_sig(*this.tcx).abi(); - if callee_abi != caller_abi { + if this.machine.enforce_abi && callee_abi != caller_abi { throw_ub_format!( "calling a function with ABI {} using caller ABI {}", callee_abi.name(), @@ -632,16 +632,19 @@ where } /// Check that the ABI is what we expect. -pub fn check_abi<'a>(abi: Abi, exp_abi: Abi) -> InterpResult<'a, ()> { - if abi == exp_abi { - Ok(()) - } else { +pub fn check_abi<'a>( + this: &MiriEvalContext<'_, '_>, + abi: Abi, + exp_abi: Abi, +) -> InterpResult<'a, ()> { + if this.machine.enforce_abi && abi != exp_abi { throw_ub_format!( "calling a function with ABI {} using caller ABI {}", exp_abi.name(), abi.name() ) } + Ok(()) } pub fn isolation_error(name: &str) -> InterpResult<'static> { diff --git a/src/machine.rs b/src/machine.rs index 4f643e7f50917..175396ed119cc 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -270,6 +270,9 @@ pub struct Evaluator<'mir, 'tcx> { /// Whether to enforce the validity invariant. pub(crate) validate: bool, + /// Whether to enforce [ABI](Abi) of function calls. + pub(crate) enforce_abi: bool, + pub(crate) file_handler: shims::posix::FileHandler, pub(crate) dir_handler: shims::posix::DirHandler, @@ -310,6 +313,7 @@ impl<'mir, 'tcx> Evaluator<'mir, 'tcx> { tls: TlsData::default(), communicate: config.communicate, validate: config.validate, + enforce_abi: config.check_abi, file_handler: Default::default(), dir_handler: Default::default(), time_anchor: Instant::now(), @@ -371,6 +375,11 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { ecx.machine.validate } + #[inline(always)] + fn enforce_abi(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool { + ecx.machine.enforce_abi + } + #[inline(always)] fn find_mir_or_eval_fn( ecx: &mut InterpCx<'mir, 'tcx, Self>, diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 4c96c99eeeaf2..2afa1a8671289 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -136,14 +136,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let (dest, ret) = match ret { None => match link_name { "miri_start_panic" => { - check_abi(abi, Abi::Rust)?; + check_abi(this, abi, Abi::Rust)?; this.handle_miri_start_panic(args, unwind)?; return Ok(None); } // This matches calls to the foreign item `panic_impl`. // The implementation is provided by the function with the `#[panic_handler]` attribute. "panic_impl" => { - check_abi(abi, Abi::Rust)?; + check_abi(this, abi, Abi::Rust)?; let panic_impl_id = tcx.lang_items().panic_impl().unwrap(); let panic_impl_instance = ty::Instance::mono(tcx, panic_impl_id); return Ok(Some(&*this.load_mir(panic_impl_instance.def, None)?)); @@ -152,14 +152,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "exit" | "ExitProcess" => { - check_abi(abi, if link_name == "exit" { Abi::C { unwind: false } } else { Abi::System { unwind: false } })?; + check_abi(this, abi, if link_name == "exit" { Abi::C { unwind: false } } else { Abi::System { unwind: false } })?; let &[ref code] = check_arg_count(args)?; // it's really u32 for ExitProcess, but we have to put it into the `Exit` variant anyway let code = this.read_scalar(code)?.to_i32()?; throw_machine_stop!(TerminationInfo::Exit(code.into())); } "abort" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; throw_machine_stop!(TerminationInfo::Abort( "the program aborted execution".to_owned() )) @@ -180,7 +180,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx #[rustfmt::skip] "__rust_start_panic" | "__rust_panic_cleanup" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; // This replicates some of the logic in `inject_panic_runtime`. // FIXME: is there a way to reuse that logic? let panic_runtime = match this.tcx.sess.panic_strategy() { @@ -221,7 +221,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx match link_name { // Miri-specific extern functions "miri_static_root" => { - check_abi(abi, Abi::Rust)?; + check_abi(this, abi, Abi::Rust)?; let &[ref ptr] = check_arg_count(args)?; let ptr = this.read_scalar(ptr)?.check_init()?; let ptr = this.force_ptr(ptr)?; @@ -233,27 +233,27 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Obtains a Miri backtrace. See the README for details. "miri_get_backtrace" => { - check_abi(abi, Abi::Rust)?; + check_abi(this, abi, Abi::Rust)?; this.handle_miri_get_backtrace(args, dest)?; } // Resolves a Miri backtrace frame. See the README for details. "miri_resolve_frame" => { - check_abi(abi, Abi::Rust)?; + check_abi(this, abi, Abi::Rust)?; this.handle_miri_resolve_frame(args, dest)?; } // Standard C allocation "malloc" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref size] = check_arg_count(args)?; let size = this.read_scalar(size)?.to_machine_usize(this)?; let res = this.malloc(size, /*zero_init:*/ false, MiriMemoryKind::C); this.write_scalar(res, dest)?; } "calloc" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref items, ref len] = check_arg_count(args)?; let items = this.read_scalar(items)?.to_machine_usize(this)?; let len = this.read_scalar(len)?.to_machine_usize(this)?; @@ -263,13 +263,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(res, dest)?; } "free" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref ptr] = check_arg_count(args)?; let ptr = this.read_scalar(ptr)?.check_init()?; this.free(ptr, MiriMemoryKind::C)?; } "realloc" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref old_ptr, ref new_size] = check_arg_count(args)?; let old_ptr = this.read_scalar(old_ptr)?.check_init()?; let new_size = this.read_scalar(new_size)?.to_machine_usize(this)?; @@ -281,7 +281,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // (Usually these would be forwarded to to `#[global_allocator]`; we instead implement a generic // allocation that also checks that all conditions are met, such as not permitting zero-sized allocations.) "__rust_alloc" => { - check_abi(abi, Abi::Rust)?; + check_abi(this, abi, Abi::Rust)?; let &[ref size, ref align] = check_arg_count(args)?; let size = this.read_scalar(size)?.to_machine_usize(this)?; let align = this.read_scalar(align)?.to_machine_usize(this)?; @@ -294,7 +294,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(ptr, dest)?; } "__rust_alloc_zeroed" => { - check_abi(abi, Abi::Rust)?; + check_abi(this, abi, Abi::Rust)?; let &[ref size, ref align] = check_arg_count(args)?; let size = this.read_scalar(size)?.to_machine_usize(this)?; let align = this.read_scalar(align)?.to_machine_usize(this)?; @@ -309,7 +309,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(ptr, dest)?; } "__rust_dealloc" => { - check_abi(abi, Abi::Rust)?; + check_abi(this, abi, Abi::Rust)?; let &[ref ptr, ref old_size, ref align] = check_arg_count(args)?; let ptr = this.read_scalar(ptr)?.check_init()?; let old_size = this.read_scalar(old_size)?.to_machine_usize(this)?; @@ -323,7 +323,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx )?; } "__rust_realloc" => { - check_abi(abi, Abi::Rust)?; + check_abi(this, abi, Abi::Rust)?; let &[ref ptr, ref old_size, ref align, ref new_size] = check_arg_count(args)?; let ptr = this.force_ptr(this.read_scalar(ptr)?.check_init()?)?; let old_size = this.read_scalar(old_size)?.to_machine_usize(this)?; @@ -344,7 +344,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // C memory handling functions "memcmp" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref left, ref right, ref n] = check_arg_count(args)?; let left = this.read_scalar(left)?.check_init()?; let right = this.read_scalar(right)?.check_init()?; @@ -365,7 +365,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_i32(result), dest)?; } "memrchr" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref ptr, ref val, ref num] = check_arg_count(args)?; let ptr = this.read_scalar(ptr)?.check_init()?; let val = this.read_scalar(val)?.to_i32()? as u8; @@ -384,7 +384,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } "memchr" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref ptr, ref val, ref num] = check_arg_count(args)?; let ptr = this.read_scalar(ptr)?.check_init()?; let val = this.read_scalar(val)?.to_i32()? as u8; @@ -402,7 +402,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } "strlen" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref ptr] = check_arg_count(args)?; let ptr = this.read_scalar(ptr)?.check_init()?; let n = this.read_c_str(ptr)?.len(); @@ -419,7 +419,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "asinf" | "atanf" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref f] = check_arg_count(args)?; // FIXME: Using host floats. let f = f32::from_bits(this.read_scalar(f)?.to_u32()?); @@ -440,7 +440,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "hypotf" | "atan2f" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref f1, ref f2] = check_arg_count(args)?; // underscore case for windows, here and below // (see https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/floating-point-primitives?view=vs-2019) @@ -463,7 +463,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "asin" | "atan" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref f] = check_arg_count(args)?; // FIXME: Using host floats. let f = f64::from_bits(this.read_scalar(f)?.to_u64()?); @@ -484,7 +484,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "hypot" | "atan2" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref f1, ref f2] = check_arg_count(args)?; // FIXME: Using host floats. let f1 = f64::from_bits(this.read_scalar(f1)?.to_u64()?); @@ -501,7 +501,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "ldexp" | "scalbn" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref x, ref exp] = check_arg_count(args)?; // For radix-2 (binary) systems, `ldexp` and `scalbn` are the same. let x = this.read_scalar(x)?.to_f64()?; @@ -523,12 +523,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Architecture-specific shims "llvm.x86.sse2.pause" if this.tcx.sess.target.arch == "x86" || this.tcx.sess.target.arch == "x86_64" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[] = check_arg_count(args)?; this.yield_active_thread(); } "llvm.aarch64.isb" if this.tcx.sess.target.arch == "aarch64" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref arg] = check_arg_count(args)?; let arg = this.read_scalar(arg)?.to_i32()?; match arg { diff --git a/src/shims/posix/dlsym.rs b/src/shims/posix/dlsym.rs index df9e945f29f75..5f420ac5363bb 100644 --- a/src/shims/posix/dlsym.rs +++ b/src/shims/posix/dlsym.rs @@ -35,7 +35,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; match dlsym { Dlsym::Linux(dlsym) => linux::EvalContextExt::call_dlsym(this, dlsym, args, ret), diff --git a/src/shims/posix/foreign_items.rs b/src/shims/posix/foreign_items.rs index 52b41b49bd5e9..5eb731d09c864 100644 --- a/src/shims/posix/foreign_items.rs +++ b/src/shims/posix/foreign_items.rs @@ -25,32 +25,32 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx match link_name { // Environment related shims "getenv" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref name] = check_arg_count(args)?; let result = this.getenv(name)?; this.write_scalar(result, dest)?; } "unsetenv" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref name] = check_arg_count(args)?; let result = this.unsetenv(name)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "setenv" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref name, ref value, ref overwrite] = check_arg_count(args)?; this.read_scalar(overwrite)?.to_i32()?; let result = this.setenv(name, value)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "getcwd" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref buf, ref size] = check_arg_count(args)?; let result = this.getcwd(buf, size)?; this.write_scalar(result, dest)?; } "chdir" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref path] = check_arg_count(args)?; let result = this.chdir(path)?; this.write_scalar(Scalar::from_i32(result), dest)?; @@ -58,18 +58,18 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // File related shims "open" | "open64" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref path, ref flag, ref mode] = check_arg_count(args)?; let result = this.open(path, flag, mode)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "fcntl" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let result = this.fcntl(args)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "read" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref fd, ref buf, ref count] = check_arg_count(args)?; let fd = this.read_scalar(fd)?.to_i32()?; let buf = this.read_scalar(buf)?.check_init()?; @@ -78,7 +78,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_machine_isize(result, this), dest)?; } "write" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref fd, ref buf, ref n] = check_arg_count(args)?; let fd = this.read_scalar(fd)?.to_i32()?; let buf = this.read_scalar(buf)?.check_init()?; @@ -89,62 +89,62 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_machine_isize(result, this), dest)?; } "unlink" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref path] = check_arg_count(args)?; let result = this.unlink(path)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "symlink" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref target, ref linkpath] = check_arg_count(args)?; let result = this.symlink(target, linkpath)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "rename" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref oldpath, ref newpath] = check_arg_count(args)?; let result = this.rename(oldpath, newpath)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "mkdir" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref path, ref mode] = check_arg_count(args)?; let result = this.mkdir(path, mode)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "rmdir" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref path] = check_arg_count(args)?; let result = this.rmdir(path)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "closedir" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref dirp] = check_arg_count(args)?; let result = this.closedir(dirp)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "lseek" | "lseek64" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref fd, ref offset, ref whence] = check_arg_count(args)?; let result = this.lseek64(fd, offset, whence)?; // "lseek" is only used on macOS which is 64bit-only, so `i64` always works. this.write_scalar(Scalar::from_i64(result), dest)?; } "fsync" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref fd] = check_arg_count(args)?; let result = this.fsync(fd)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "fdatasync" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref fd] = check_arg_count(args)?; let result = this.fdatasync(fd)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "readlink" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref pathname, ref buf, ref bufsize] = check_arg_count(args)?; let result = this.readlink(pathname, buf, bufsize)?; this.write_scalar(Scalar::from_machine_isize(result, this), dest)?; @@ -152,7 +152,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Allocation "posix_memalign" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref ret, ref align, ref size] = check_arg_count(args)?; let ret = this.deref_operand(ret)?; let align = this.read_scalar(align)?.to_machine_usize(this)?; @@ -183,7 +183,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Dynamic symbol loading "dlsym" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref handle, ref symbol] = check_arg_count(args)?; this.read_scalar(handle)?.to_machine_usize(this)?; let symbol = this.read_scalar(symbol)?.check_init()?; @@ -198,7 +198,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Querying system information "sysconf" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref name] = check_arg_count(args)?; let name = this.read_scalar(name)?.to_i32()?; @@ -224,7 +224,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Thread-local storage "pthread_key_create" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref key, ref dtor] = check_arg_count(args)?; let key_place = this.deref_operand(key)?; let dtor = this.read_scalar(dtor)?.check_init()?; @@ -253,7 +253,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_null(dest)?; } "pthread_key_delete" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref key] = check_arg_count(args)?; let key = this.force_bits(this.read_scalar(key)?.check_init()?, key.layout.size)?; this.machine.tls.delete_tls_key(key)?; @@ -261,7 +261,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_null(dest)?; } "pthread_getspecific" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref key] = check_arg_count(args)?; let key = this.force_bits(this.read_scalar(key)?.check_init()?, key.layout.size)?; let active_thread = this.get_active_thread(); @@ -269,7 +269,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(ptr, dest)?; } "pthread_setspecific" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref key, ref new_ptr] = check_arg_count(args)?; let key = this.force_bits(this.read_scalar(key)?.check_init()?, key.layout.size)?; let active_thread = this.get_active_thread(); @@ -282,132 +282,132 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Synchronization primitives "pthread_mutexattr_init" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref attr] = check_arg_count(args)?; let result = this.pthread_mutexattr_init(attr)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_mutexattr_settype" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref attr, ref kind] = check_arg_count(args)?; let result = this.pthread_mutexattr_settype(attr, kind)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_mutexattr_destroy" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref attr] = check_arg_count(args)?; let result = this.pthread_mutexattr_destroy(attr)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_mutex_init" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref mutex, ref attr] = check_arg_count(args)?; let result = this.pthread_mutex_init(mutex, attr)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_mutex_lock" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref mutex] = check_arg_count(args)?; let result = this.pthread_mutex_lock(mutex)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_mutex_trylock" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref mutex] = check_arg_count(args)?; let result = this.pthread_mutex_trylock(mutex)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_mutex_unlock" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref mutex] = check_arg_count(args)?; let result = this.pthread_mutex_unlock(mutex)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_mutex_destroy" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref mutex] = check_arg_count(args)?; let result = this.pthread_mutex_destroy(mutex)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_rwlock_rdlock" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref rwlock] = check_arg_count(args)?; let result = this.pthread_rwlock_rdlock(rwlock)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_rwlock_tryrdlock" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref rwlock] = check_arg_count(args)?; let result = this.pthread_rwlock_tryrdlock(rwlock)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_rwlock_wrlock" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref rwlock] = check_arg_count(args)?; let result = this.pthread_rwlock_wrlock(rwlock)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_rwlock_trywrlock" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref rwlock] = check_arg_count(args)?; let result = this.pthread_rwlock_trywrlock(rwlock)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_rwlock_unlock" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref rwlock] = check_arg_count(args)?; let result = this.pthread_rwlock_unlock(rwlock)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_rwlock_destroy" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref rwlock] = check_arg_count(args)?; let result = this.pthread_rwlock_destroy(rwlock)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_condattr_init" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref attr] = check_arg_count(args)?; let result = this.pthread_condattr_init(attr)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_condattr_destroy" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref attr] = check_arg_count(args)?; let result = this.pthread_condattr_destroy(attr)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_cond_init" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref cond, ref attr] = check_arg_count(args)?; let result = this.pthread_cond_init(cond, attr)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_cond_signal" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref cond] = check_arg_count(args)?; let result = this.pthread_cond_signal(cond)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_cond_broadcast" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref cond] = check_arg_count(args)?; let result = this.pthread_cond_broadcast(cond)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_cond_wait" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref cond, ref mutex] = check_arg_count(args)?; let result = this.pthread_cond_wait(cond, mutex)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_cond_timedwait" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref cond, ref mutex, ref abstime] = check_arg_count(args)?; this.pthread_cond_timedwait(cond, mutex, abstime, dest)?; } "pthread_cond_destroy" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref cond] = check_arg_count(args)?; let result = this.pthread_cond_destroy(cond)?; this.write_scalar(Scalar::from_i32(result), dest)?; @@ -415,36 +415,36 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Threading "pthread_create" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref thread, ref attr, ref start, ref arg] = check_arg_count(args)?; let result = this.pthread_create(thread, attr, start, arg)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_join" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref thread, ref retval] = check_arg_count(args)?; let result = this.pthread_join(thread, retval)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_detach" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref thread] = check_arg_count(args)?; let result = this.pthread_detach(thread)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_self" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[] = check_arg_count(args)?; this.pthread_self(dest)?; } "sched_yield" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[] = check_arg_count(args)?; let result = this.sched_yield()?; this.write_scalar(Scalar::from_i32(result), dest)?; } "nanosleep" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref req, ref rem] = check_arg_count(args)?; let result = this.nanosleep(req, rem)?; this.write_scalar(Scalar::from_i32(result), dest)?; @@ -452,7 +452,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Miscellaneous "isatty" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref fd] = check_arg_count(args)?; this.read_scalar(fd)?.to_i32()?; // "returns 1 if fd is an open file descriptor referring to a terminal; otherwise 0 is returned, and errno is set to indicate the error" @@ -462,7 +462,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_null(dest)?; } "pthread_atfork" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref prepare, ref parent, ref child] = check_arg_count(args)?; this.force_bits(this.read_scalar(prepare)?.check_init()?, this.memory.pointer_size())?; this.force_bits(this.read_scalar(parent)?.check_init()?, this.memory.pointer_size())?; @@ -475,7 +475,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // These shims are enabled only when the caller is in the standard library. "pthread_attr_getguardsize" if this.frame().instance.to_string().starts_with("std::sys::unix::") => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref _attr, ref guard_size] = check_arg_count(args)?; let guard_size = this.deref_operand(guard_size)?; let guard_size_layout = this.libc_ty_layout("size_t")?; @@ -488,13 +488,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "pthread_attr_init" | "pthread_attr_destroy" if this.frame().instance.to_string().starts_with("std::sys::unix::") => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[_] = check_arg_count(args)?; this.write_null(dest)?; } | "pthread_attr_setstacksize" if this.frame().instance.to_string().starts_with("std::sys::unix::") => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[_, _] = check_arg_count(args)?; this.write_null(dest)?; } @@ -502,14 +502,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "signal" | "sigaltstack" if this.frame().instance.to_string().starts_with("std::sys::unix::") => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[_, _] = check_arg_count(args)?; this.write_null(dest)?; } | "sigaction" | "mprotect" if this.frame().instance.to_string().starts_with("std::sys::unix::") => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[_, _, _] = check_arg_count(args)?; this.write_null(dest)?; } diff --git a/src/shims/posix/linux/foreign_items.rs b/src/shims/posix/linux/foreign_items.rs index f7d7706e3f5e9..d16c740ffc547 100644 --- a/src/shims/posix/linux/foreign_items.rs +++ b/src/shims/posix/linux/foreign_items.rs @@ -23,7 +23,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx match link_name { // errno "__errno_location" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[] = check_arg_count(args)?; let errno_place = this.last_error_place()?; this.write_scalar(errno_place.to_ref().to_scalar()?, dest)?; @@ -33,32 +33,32 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // These symbols have different names on Linux and macOS, which is the only reason they are not // in the `posix` module. "close" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref fd] = check_arg_count(args)?; let result = this.close(fd)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "opendir" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref name] = check_arg_count(args)?; let result = this.opendir(name)?; this.write_scalar(result, dest)?; } "readdir64_r" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref dirp, ref entry, ref result] = check_arg_count(args)?; let result = this.linux_readdir64_r(dirp, entry, result)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "ftruncate64" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref fd, ref length] = check_arg_count(args)?; let result = this.ftruncate64(fd, length)?; this.write_scalar(Scalar::from_i32(result), dest)?; } // Linux-only "posix_fadvise" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref fd, ref offset, ref len, ref advice] = check_arg_count(args)?; this.read_scalar(fd)?.to_i32()?; this.read_scalar(offset)?.to_machine_isize(this)?; @@ -68,7 +68,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_null(dest)?; } "sync_file_range" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref fd, ref offset, ref nbytes, ref flags] = check_arg_count(args)?; let result = this.sync_file_range(fd, offset, nbytes, flags)?; this.write_scalar(Scalar::from_i32(result), dest)?; @@ -76,7 +76,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Time related shims "clock_gettime" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; // This is a POSIX function but it has only been tested on linux. let &[ref clk_id, ref tp] = check_arg_count(args)?; let result = this.clock_gettime(clk_id, tp)?; @@ -85,7 +85,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Querying system information "pthread_attr_getstack" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; // We don't support "pthread_attr_setstack", so we just pretend all stacks have the same values here. let &[ref attr_place, ref addr_place, ref size_place] = check_arg_count(args)?; this.deref_operand(attr_place)?; @@ -107,19 +107,19 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Threading "prctl" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref option, ref arg2, ref arg3, ref arg4, ref arg5] = check_arg_count(args)?; let result = this.prctl(option, arg2, arg3, arg4, arg5)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_condattr_setclock" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref attr, ref clock_id] = check_arg_count(args)?; let result = this.pthread_condattr_setclock(attr, clock_id)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_condattr_getclock" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref attr, ref clock_id] = check_arg_count(args)?; let result = this.pthread_condattr_getclock(attr, clock_id)?; this.write_scalar(Scalar::from_i32(result), dest)?; @@ -127,7 +127,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Dynamically invoked syscalls "syscall" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; // The syscall variadic function is legal to call with more arguments than needed, // extra arguments are simply ignored. However, all arguments need to be scalars; // other types might be treated differently by the calling convention. @@ -188,12 +188,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Miscelanneous "getrandom" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref ptr, ref len, ref flags] = check_arg_count(args)?; getrandom(this, ptr, len, flags, dest)?; } "sched_getaffinity" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref pid, ref cpusetsize, ref mask] = check_arg_count(args)?; this.read_scalar(pid)?.to_i32()?; this.read_scalar(cpusetsize)?.to_machine_usize(this)?; @@ -209,7 +209,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "pthread_getattr_np" if this.frame().instance.to_string().starts_with("std::sys::unix::") => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref _thread, ref _attr] = check_arg_count(args)?; this.write_null(dest)?; } diff --git a/src/shims/posix/macos/foreign_items.rs b/src/shims/posix/macos/foreign_items.rs index 9a7d3be1eb9aa..de4ed56633cbf 100644 --- a/src/shims/posix/macos/foreign_items.rs +++ b/src/shims/posix/macos/foreign_items.rs @@ -21,7 +21,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx match link_name { // errno "__error" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[] = check_arg_count(args)?; let errno_place = this.last_error_place()?; this.write_scalar(errno_place.to_ref().to_scalar()?, dest)?; @@ -29,43 +29,43 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // File related shims "close" | "close$NOCANCEL" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref result] = check_arg_count(args)?; let result = this.close(result)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "stat" | "stat$INODE64" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref path, ref buf] = check_arg_count(args)?; let result = this.macos_stat(path, buf)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "lstat" | "lstat$INODE64" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref path, ref buf] = check_arg_count(args)?; let result = this.macos_lstat(path, buf)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "fstat" | "fstat$INODE64" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref fd, ref buf] = check_arg_count(args)?; let result = this.macos_fstat(fd, buf)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "opendir" | "opendir$INODE64" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref name] = check_arg_count(args)?; let result = this.opendir(name)?; this.write_scalar(result, dest)?; } "readdir_r" | "readdir_r$INODE64" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref dirp, ref entry, ref result] = check_arg_count(args)?; let result = this.macos_readdir_r(dirp, entry, result)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "ftruncate" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref fd, ref length] = check_arg_count(args)?; let result = this.ftruncate64(fd, length)?; this.write_scalar(Scalar::from_i32(result), dest)?; @@ -73,27 +73,27 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Environment related shims "_NSGetEnviron" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[] = check_arg_count(args)?; this.write_scalar(this.machine.env_vars.environ.unwrap().ptr, dest)?; } // Time related shims "gettimeofday" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref tv, ref tz] = check_arg_count(args)?; let result = this.gettimeofday(tv, tz)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "mach_absolute_time" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[] = check_arg_count(args)?; let result = this.mach_absolute_time()?; this.write_scalar(Scalar::from_u64(result), dest)?; } "mach_timebase_info" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref info] = check_arg_count(args)?; let result = this.mach_timebase_info(info)?; this.write_scalar(Scalar::from_i32(result), dest)?; @@ -101,19 +101,19 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Access to command-line arguments "_NSGetArgc" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[] = check_arg_count(args)?; this.write_scalar(this.machine.argc.expect("machine must be initialized"), dest)?; } "_NSGetArgv" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[] = check_arg_count(args)?; this.write_scalar(this.machine.argv.expect("machine must be initialized"), dest)?; } // Thread-local storage "_tlv_atexit" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref dtor, ref data] = check_arg_count(args)?; let dtor = this.read_scalar(dtor)?.check_init()?; let dtor = this.memory.get_fn(dtor)?.as_instance()?; @@ -124,14 +124,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Querying system information "pthread_get_stackaddr_np" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref thread] = check_arg_count(args)?; this.read_scalar(thread)?.to_machine_usize(this)?; let stack_addr = Scalar::from_uint(STACK_ADDR, this.pointer_size()); this.write_scalar(stack_addr, dest)?; } "pthread_get_stacksize_np" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref thread] = check_arg_count(args)?; this.read_scalar(thread)?.to_machine_usize(this)?; let stack_size = Scalar::from_uint(STACK_SIZE, this.pointer_size()); @@ -140,7 +140,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Threading "pthread_setname_np" => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; let &[ref name] = check_arg_count(args)?; let name = this.read_scalar(name)?.check_init()?; this.pthread_setname_np(name)?; @@ -149,7 +149,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Incomplete shims that we "stub out" just to get pre-main initialization code to work. // These shims are enabled only when the caller is in the standard library. "mmap" if this.frame().instance.to_string().starts_with("std::sys::unix::") => { - check_abi(abi, Abi::C { unwind: false })?; + check_abi(this, abi, Abi::C { unwind: false })?; // This is a horrible hack, but since the guard page mechanism calls mmap and expects a particular return value, we just give it that value. let &[ref addr, _, _, _, _, _] = check_arg_count(args)?; let addr = this.read_scalar(addr)?.check_init()?; diff --git a/src/shims/windows/dlsym.rs b/src/shims/windows/dlsym.rs index ace6c4674ae99..18e2ed3db59b5 100644 --- a/src/shims/windows/dlsym.rs +++ b/src/shims/windows/dlsym.rs @@ -31,7 +31,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let (_dest, _ret) = ret.expect("we don't support any diverging dlsym"); assert!(this.tcx.sess.target.os == "windows"); - check_abi(abi, Abi::System { unwind: false })?; + check_abi(this, abi, Abi::System { unwind: false })?; match dlsym {} } diff --git a/src/shims/windows/foreign_items.rs b/src/shims/windows/foreign_items.rs index b246ccc33cf72..d7b86fff73274 100644 --- a/src/shims/windows/foreign_items.rs +++ b/src/shims/windows/foreign_items.rs @@ -28,37 +28,37 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx match link_name { // Environment related shims "GetEnvironmentVariableW" => { - check_abi(abi, Abi::System { unwind: false })?; + check_abi(this, abi, Abi::System { unwind: false })?; let &[ref name, ref buf, ref size] = check_arg_count(args)?; let result = this.GetEnvironmentVariableW(name, buf, size)?; this.write_scalar(Scalar::from_u32(result), dest)?; } "SetEnvironmentVariableW" => { - check_abi(abi, Abi::System { unwind: false })?; + check_abi(this, abi, Abi::System { unwind: false })?; let &[ref name, ref value] = check_arg_count(args)?; let result = this.SetEnvironmentVariableW(name, value)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "GetEnvironmentStringsW" => { - check_abi(abi, Abi::System { unwind: false })?; + check_abi(this, abi, Abi::System { unwind: false })?; let &[] = check_arg_count(args)?; let result = this.GetEnvironmentStringsW()?; this.write_scalar(result, dest)?; } "FreeEnvironmentStringsW" => { - check_abi(abi, Abi::System { unwind: false })?; + check_abi(this, abi, Abi::System { unwind: false })?; let &[ref env_block] = check_arg_count(args)?; let result = this.FreeEnvironmentStringsW(env_block)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "GetCurrentDirectoryW" => { - check_abi(abi, Abi::System { unwind: false })?; + check_abi(this, abi, Abi::System { unwind: false })?; let &[ref size, ref buf] = check_arg_count(args)?; let result = this.GetCurrentDirectoryW(size, buf)?; this.write_scalar(Scalar::from_u32(result), dest)?; } "SetCurrentDirectoryW" => { - check_abi(abi, Abi::System { unwind: false })?; + check_abi(this, abi, Abi::System { unwind: false })?; let &[ref path] = check_arg_count(args)?; let result = this.SetCurrentDirectoryW(path)?; this.write_scalar(Scalar::from_i32(result), dest)?; @@ -66,7 +66,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // File related shims "GetStdHandle" => { - check_abi(abi, Abi::System { unwind: false })?; + check_abi(this, abi, Abi::System { unwind: false })?; let &[ref which] = check_arg_count(args)?; let which = this.read_scalar(which)?.to_i32()?; // We just make this the identity function, so we know later in `WriteFile` @@ -74,7 +74,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_machine_isize(which.into(), this), dest)?; } "WriteFile" => { - check_abi(abi, Abi::System { unwind: false })?; + check_abi(this, abi, Abi::System { unwind: false })?; let &[ref handle, ref buf, ref n, ref written_ptr, ref overlapped] = check_arg_count(args)?; this.read_scalar(overlapped)?.to_machine_usize(this)?; // this is a poiner, that we ignore @@ -110,7 +110,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Allocation "HeapAlloc" => { - check_abi(abi, Abi::System { unwind: false })?; + check_abi(this, abi, Abi::System { unwind: false })?; let &[ref handle, ref flags, ref size] = check_arg_count(args)?; this.read_scalar(handle)?.to_machine_isize(this)?; let flags = this.read_scalar(flags)?.to_u32()?; @@ -120,7 +120,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(res, dest)?; } "HeapFree" => { - check_abi(abi, Abi::System { unwind: false })?; + check_abi(this, abi, Abi::System { unwind: false })?; let &[ref handle, ref flags, ref ptr] = check_arg_count(args)?; this.read_scalar(handle)?.to_machine_isize(this)?; this.read_scalar(flags)?.to_u32()?; @@ -129,7 +129,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_i32(1), dest)?; } "HeapReAlloc" => { - check_abi(abi, Abi::System { unwind: false })?; + check_abi(this, abi, Abi::System { unwind: false })?; let &[ref handle, ref flags, ref ptr, ref size] = check_arg_count(args)?; this.read_scalar(handle)?.to_machine_isize(this)?; this.read_scalar(flags)?.to_u32()?; @@ -141,13 +141,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // errno "SetLastError" => { - check_abi(abi, Abi::System { unwind: false })?; + check_abi(this, abi, Abi::System { unwind: false })?; let &[ref error] = check_arg_count(args)?; let error = this.read_scalar(error)?.check_init()?; this.set_last_error(error)?; } "GetLastError" => { - check_abi(abi, Abi::System { unwind: false })?; + check_abi(this, abi, Abi::System { unwind: false })?; let &[] = check_arg_count(args)?; let last_error = this.get_last_error()?; this.write_scalar(last_error, dest)?; @@ -155,7 +155,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Querying system information "GetSystemInfo" => { - check_abi(abi, Abi::System { unwind: false })?; + check_abi(this, abi, Abi::System { unwind: false })?; let &[ref system_info] = check_arg_count(args)?; let system_info = this.deref_operand(system_info)?; // Initialize with `0`. @@ -171,7 +171,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Thread-local storage "TlsAlloc" => { - check_abi(abi, Abi::System { unwind: false })?; + check_abi(this, abi, Abi::System { unwind: false })?; // This just creates a key; Windows does not natively support TLS destructors. // Create key and return it. @@ -180,7 +180,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_uint(key, dest.layout.size), dest)?; } "TlsGetValue" => { - check_abi(abi, Abi::System { unwind: false })?; + check_abi(this, abi, Abi::System { unwind: false })?; let &[ref key] = check_arg_count(args)?; let key = u128::from(this.read_scalar(key)?.to_u32()?); let active_thread = this.get_active_thread(); @@ -188,7 +188,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(ptr, dest)?; } "TlsSetValue" => { - check_abi(abi, Abi::System { unwind: false })?; + check_abi(this, abi, Abi::System { unwind: false })?; let &[ref key, ref new_ptr] = check_arg_count(args)?; let key = u128::from(this.read_scalar(key)?.to_u32()?); let active_thread = this.get_active_thread(); @@ -201,7 +201,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Access to command-line arguments "GetCommandLineW" => { - check_abi(abi, Abi::System { unwind: false })?; + check_abi(this, abi, Abi::System { unwind: false })?; let &[] = check_arg_count(args)?; this.write_scalar( this.machine.cmd_line.expect("machine must be initialized"), @@ -211,20 +211,20 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Time related shims "GetSystemTimeAsFileTime" => { - check_abi(abi, Abi::System { unwind: false })?; + check_abi(this, abi, Abi::System { unwind: false })?; #[allow(non_snake_case)] let &[ref LPFILETIME] = check_arg_count(args)?; this.GetSystemTimeAsFileTime(LPFILETIME)?; } "QueryPerformanceCounter" => { - check_abi(abi, Abi::System { unwind: false })?; + check_abi(this, abi, Abi::System { unwind: false })?; #[allow(non_snake_case)] let &[ref lpPerformanceCount] = check_arg_count(args)?; let result = this.QueryPerformanceCounter(lpPerformanceCount)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "QueryPerformanceFrequency" => { - check_abi(abi, Abi::System { unwind: false })?; + check_abi(this, abi, Abi::System { unwind: false })?; #[allow(non_snake_case)] let &[ref lpFrequency] = check_arg_count(args)?; let result = this.QueryPerformanceFrequency(lpFrequency)?; @@ -233,33 +233,33 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Synchronization primitives "AcquireSRWLockExclusive" => { - check_abi(abi, Abi::System { unwind: false })?; + check_abi(this, abi, Abi::System { unwind: false })?; let &[ref ptr] = check_arg_count(args)?; this.AcquireSRWLockExclusive(ptr)?; } "ReleaseSRWLockExclusive" => { - check_abi(abi, Abi::System { unwind: false })?; + check_abi(this, abi, Abi::System { unwind: false })?; let &[ref ptr] = check_arg_count(args)?; this.ReleaseSRWLockExclusive(ptr)?; } "TryAcquireSRWLockExclusive" => { - check_abi(abi, Abi::System { unwind: false })?; + check_abi(this, abi, Abi::System { unwind: false })?; let &[ref ptr] = check_arg_count(args)?; let ret = this.TryAcquireSRWLockExclusive(ptr)?; this.write_scalar(Scalar::from_u8(ret), dest)?; } "AcquireSRWLockShared" => { - check_abi(abi, Abi::System { unwind: false })?; + check_abi(this, abi, Abi::System { unwind: false })?; let &[ref ptr] = check_arg_count(args)?; this.AcquireSRWLockShared(ptr)?; } "ReleaseSRWLockShared" => { - check_abi(abi, Abi::System { unwind: false })?; + check_abi(this, abi, Abi::System { unwind: false })?; let &[ref ptr] = check_arg_count(args)?; this.ReleaseSRWLockShared(ptr)?; } "TryAcquireSRWLockShared" => { - check_abi(abi, Abi::System { unwind: false })?; + check_abi(this, abi, Abi::System { unwind: false })?; let &[ref ptr] = check_arg_count(args)?; let ret = this.TryAcquireSRWLockShared(ptr)?; this.write_scalar(Scalar::from_u8(ret), dest)?; @@ -267,7 +267,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Dynamic symbol loading "GetProcAddress" => { - check_abi(abi, Abi::System { unwind: false })?; + check_abi(this, abi, Abi::System { unwind: false })?; #[allow(non_snake_case)] let &[ref hModule, ref lpProcName] = check_arg_count(args)?; this.read_scalar(hModule)?.to_machine_isize(this)?; @@ -283,7 +283,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Miscellaneous "SystemFunction036" => { // This is really 'RtlGenRandom'. - check_abi(abi, Abi::System { unwind: false })?; + check_abi(this, abi, Abi::System { unwind: false })?; let &[ref ptr, ref len] = check_arg_count(args)?; let ptr = this.read_scalar(ptr)?.check_init()?; let len = this.read_scalar(len)?.to_u32()?; @@ -291,7 +291,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_bool(true), dest)?; } "BCryptGenRandom" => { - check_abi(abi, Abi::System { unwind: false })?; + check_abi(this, abi, Abi::System { unwind: false })?; let &[ref algorithm, ref ptr, ref len, ref flags] = check_arg_count(args)?; let algorithm = this.read_scalar(algorithm)?; let ptr = this.read_scalar(ptr)?.check_init()?; @@ -312,7 +312,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_null(dest)?; // STATUS_SUCCESS } "GetConsoleScreenBufferInfo" => { - check_abi(abi, Abi::System { unwind: false })?; + check_abi(this, abi, Abi::System { unwind: false })?; // `term` needs this, so we fake it. let &[ref console, ref buffer_info] = check_arg_count(args)?; this.read_scalar(console)?.to_machine_isize(this)?; @@ -322,7 +322,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_null(dest)?; } "GetConsoleMode" => { - check_abi(abi, Abi::System { unwind: false })?; + check_abi(this, abi, Abi::System { unwind: false })?; // Windows "isatty" (in libtest) needs this, so we fake it. let &[ref console, ref mode] = check_arg_count(args)?; this.read_scalar(console)?.to_machine_isize(this)?; @@ -332,7 +332,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_null(dest)?; } "SwitchToThread" => { - check_abi(abi, Abi::System { unwind: false })?; + check_abi(this, abi, Abi::System { unwind: false })?; let &[] = check_arg_count(args)?; // Note that once Miri supports concurrency, this will need to return a nonzero // value if this call does result in switching to another thread. @@ -341,7 +341,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Better error for attempts to create a thread "CreateThread" => { - check_abi(abi, Abi::System { unwind: false })?; + check_abi(this, abi, Abi::System { unwind: false })?; throw_unsup_format!("Miri does not support concurrency on Windows"); } @@ -350,7 +350,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "GetProcessHeap" if this.frame().instance.to_string().starts_with("std::sys::windows::") => { - check_abi(abi, Abi::System { unwind: false })?; + check_abi(this, abi, Abi::System { unwind: false })?; let &[] = check_arg_count(args)?; // Just fake a HANDLE this.write_scalar(Scalar::from_machine_isize(1, this), dest)?; @@ -358,7 +358,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "SetConsoleTextAttribute" if this.frame().instance.to_string().starts_with("std::sys::windows::") => { - check_abi(abi, Abi::System { unwind: false })?; + check_abi(this, abi, Abi::System { unwind: false })?; #[allow(non_snake_case)] let &[ref _hConsoleOutput, ref _wAttribute] = check_arg_count(args)?; // Pretend these does not exist / nothing happened, by returning zero. @@ -367,7 +367,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "AddVectoredExceptionHandler" if this.frame().instance.to_string().starts_with("std::sys::windows::") => { - check_abi(abi, Abi::System { unwind: false })?; + check_abi(this, abi, Abi::System { unwind: false })?; #[allow(non_snake_case)] let &[ref _First, ref _Handler] = check_arg_count(args)?; // Any non zero value works for the stdlib. This is just used for stack overflows anyway. @@ -376,7 +376,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "SetThreadStackGuarantee" if this.frame().instance.to_string().starts_with("std::sys::windows::") => { - check_abi(abi, Abi::System { unwind: false })?; + check_abi(this, abi, Abi::System { unwind: false })?; #[allow(non_snake_case)] let &[_StackSizeInBytes] = check_arg_count(args)?; // Any non zero value works for the stdlib. This is just used for stack overflows anyway. @@ -388,7 +388,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "DeleteCriticalSection" if this.frame().instance.to_string().starts_with("std::sys::windows::") => { - check_abi(abi, Abi::System { unwind: false })?; + check_abi(this, abi, Abi::System { unwind: false })?; #[allow(non_snake_case)] let &[ref _lpCriticalSection] = check_arg_count(args)?; assert_eq!( @@ -403,7 +403,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "TryEnterCriticalSection" if this.frame().instance.to_string().starts_with("std::sys::windows::") => { - check_abi(abi, Abi::System { unwind: false })?; + check_abi(this, abi, Abi::System { unwind: false })?; #[allow(non_snake_case)] let &[ref _lpCriticalSection] = check_arg_count(args)?; assert_eq!( diff --git a/tests/compile-fail/check_callback_abi.rs b/tests/compile-fail/check_callback_abi.rs new file mode 100644 index 0000000000000..69dfc03598313 --- /dev/null +++ b/tests/compile-fail/check_callback_abi.rs @@ -0,0 +1,15 @@ +#![feature(core_intrinsics)] + +extern "C" fn try_fn(_: *mut u8) { + unreachable!(); +} + +fn main() { + unsafe { + std::intrinsics::r#try( //~ ERROR calling a function with ABI C using caller ABI Rust + std::mem::transmute::(try_fn), + std::ptr::null_mut(), + |_, _| unreachable!(), + ); + } +} diff --git a/tests/compile-fail/concurrency/unwind_top_of_stack.rs b/tests/compile-fail/concurrency/unwind_top_of_stack.rs index 8f3bb17470b59..138a43d9d7310 100644 --- a/tests/compile-fail/concurrency/unwind_top_of_stack.rs +++ b/tests/compile-fail/concurrency/unwind_top_of_stack.rs @@ -1,10 +1,8 @@ // ignore-windows: Concurrency on Windows is not supported yet. -// error-pattern: calling a function with ABI C-unwind using caller ABI C +// compile-flags: -Zmiri-disable-abi-check +// error-pattern: unwinding past the topmost frame of the stack //! Unwinding past the top frame of a stack is Undefined Behavior. -//! However, it is impossible to do that in pure Rust since one cannot write an unwinding -//! function with `C` ABI... so let's instead test that we are indeed correctly checking -//! the callee ABI in `pthread_create`. #![feature(rustc_private, c_unwind)] diff --git a/tests/compile-fail/panic/bad_unwind.rs b/tests/compile-fail/panic/bad_unwind.rs index fde2c19af07d5..cfb109cb8b56a 100644 --- a/tests/compile-fail/panic/bad_unwind.rs +++ b/tests/compile-fail/panic/bad_unwind.rs @@ -4,6 +4,8 @@ //! Unwinding when the caller ABI is "C" (without "-unwind") is UB. //! Currently we detect the ABI mismatch; we could probably allow such calls in principle one day //! but then we have to detect the unexpected unwinding. +//! FIXME: `-Zmiri-disable-abi-check` does not work for this test because function pointers are +//! always allowed to unwind. extern "C-unwind" fn unwind() { panic!(); diff --git a/tests/run-pass/disable_abi_check.rs b/tests/run-pass/disable_abi_check.rs new file mode 100644 index 0000000000000..1f8554741376b --- /dev/null +++ b/tests/run-pass/disable_abi_check.rs @@ -0,0 +1,24 @@ +// compile-flags: -Zmiri-disable-abi-check +#![feature(core_intrinsics)] + +fn main() { + fn foo() {} + + extern "C" fn try_fn(ptr: *mut u8) { + assert!(ptr.is_null()); + } + + extern "Rust" { + fn malloc(size: usize) -> *mut std::ffi::c_void; + } + + unsafe { + let _ = malloc(0); + std::mem::transmute::(foo)(); + std::intrinsics::r#try( + std::mem::transmute::(try_fn), + std::ptr::null_mut(), + |_, _| unreachable!(), + ); + } +} From 41f33a64f878cb28567c2773906859ce8a0614e5 Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Fri, 16 Apr 2021 05:19:23 +0800 Subject: [PATCH 2691/3747] Implement calls to exported symbols --- src/bin/miri.rs | 80 +++++++-- src/diagnostics.rs | 64 ++++--- src/lib.rs | 2 + src/machine.rs | 6 +- src/shims/foreign_items.rs | 159 +++++++++++++----- src/shims/posix/foreign_items.rs | 5 +- src/shims/posix/linux/foreign_items.rs | 7 +- src/shims/posix/macos/foreign_items.rs | 7 +- src/shims/windows/foreign_items.rs | 7 +- test-cargo-miri/Cargo.lock | 12 ++ test-cargo-miri/Cargo.toml | 3 +- .../exported-symbol-dep/Cargo.toml | 5 + .../exported-symbol-dep/src/lib.rs | 4 + test-cargo-miri/exported-symbol/Cargo.toml | 11 ++ test-cargo-miri/exported-symbol/src/lib.rs | 1 + test-cargo-miri/src/lib.rs | 16 ++ test-cargo-miri/test.default.stdout.ref | 11 +- test-cargo-miri/test.filter.stdout.ref | 2 +- .../{ => function_calls}/check_arg_abi.rs | 0 .../check_arg_count_too_few_args.rs | 0 .../check_arg_count_too_many_args.rs | 0 .../check_callback_abi.rs | 0 .../exported_symbol_abi_mismatch.rs | 22 +++ .../exported_symbol_bad_unwind1.rs | 15 ++ .../exported_symbol_bad_unwind2.rs | 19 +++ .../exported_symbol_bad_unwind3.rs | 16 ++ .../exported_symbol_clashing.rs | 15 ++ .../exported_symbol_wrong_arguments.rs | 9 + .../exported_symbol_wrong_type.rs | 9 + .../panic/bad_miri_start_panic.rs | 10 ++ .../panic/rustc_allocator_nounwind.rs | 10 ++ .../{ => function_calls}/disable_abi_check.rs | 0 .../function_calls/exported_symbol.rs | 44 +++++ .../exported_symbol_good_unwind.rs | 49 ++++++ .../exported_symbol_good_unwind.stderr | 5 + .../exported_symbol_unwind_allowed.rs | 15 ++ .../exported_symbol_unwind_allowed.stderr | 2 + tests/run-pass/panic/good_unwind.rs | 27 +++ tests/run-pass/panic/good_unwind.stderr | 5 + 39 files changed, 584 insertions(+), 90 deletions(-) create mode 100644 test-cargo-miri/exported-symbol-dep/Cargo.toml create mode 100644 test-cargo-miri/exported-symbol-dep/src/lib.rs create mode 100644 test-cargo-miri/exported-symbol/Cargo.toml create mode 100644 test-cargo-miri/exported-symbol/src/lib.rs rename tests/compile-fail/{ => function_calls}/check_arg_abi.rs (100%) rename tests/compile-fail/{ => function_calls}/check_arg_count_too_few_args.rs (100%) rename tests/compile-fail/{ => function_calls}/check_arg_count_too_many_args.rs (100%) rename tests/compile-fail/{ => function_calls}/check_callback_abi.rs (100%) create mode 100644 tests/compile-fail/function_calls/exported_symbol_abi_mismatch.rs create mode 100644 tests/compile-fail/function_calls/exported_symbol_bad_unwind1.rs create mode 100644 tests/compile-fail/function_calls/exported_symbol_bad_unwind2.rs create mode 100644 tests/compile-fail/function_calls/exported_symbol_bad_unwind3.rs create mode 100644 tests/compile-fail/function_calls/exported_symbol_clashing.rs create mode 100644 tests/compile-fail/function_calls/exported_symbol_wrong_arguments.rs create mode 100644 tests/compile-fail/function_calls/exported_symbol_wrong_type.rs create mode 100644 tests/compile-fail/panic/bad_miri_start_panic.rs create mode 100644 tests/compile-fail/panic/rustc_allocator_nounwind.rs rename tests/run-pass/{ => function_calls}/disable_abi_check.rs (100%) create mode 100644 tests/run-pass/function_calls/exported_symbol.rs create mode 100644 tests/run-pass/function_calls/exported_symbol_good_unwind.rs create mode 100644 tests/run-pass/function_calls/exported_symbol_good_unwind.stderr create mode 100644 tests/run-pass/function_calls/exported_symbol_unwind_allowed.rs create mode 100644 tests/run-pass/function_calls/exported_symbol_unwind_allowed.stderr create mode 100644 tests/run-pass/panic/good_unwind.rs create mode 100644 tests/run-pass/panic/good_unwind.stderr diff --git a/src/bin/miri.rs b/src/bin/miri.rs index e921407f63fb4..7368d4b253bac 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -1,14 +1,17 @@ -#![feature(rustc_private)] +#![feature(rustc_private, bool_to_option, stmt_expr_attributes)] extern crate rustc_driver; extern crate rustc_errors; extern crate rustc_hir; extern crate rustc_interface; +extern crate rustc_metadata; extern crate rustc_middle; extern crate rustc_session; use std::convert::TryFrom; use std::env; +use std::path::PathBuf; +use std::rc::Rc; use std::str::FromStr; use hex::FromHexError; @@ -16,14 +19,34 @@ use log::debug; use rustc_driver::Compilation; use rustc_errors::emitter::{ColorConfig, HumanReadableErrorType}; -use rustc_middle::ty::TyCtxt; -use rustc_session::{config::ErrorOutputType, CtfeBacktrace}; +use rustc_hir::def_id::LOCAL_CRATE; +use rustc_interface::interface::Config; +use rustc_middle::{ + middle::exported_symbols::{ExportedSymbol, SymbolExportLevel}, + ty::{query::Providers, TyCtxt}, +}; +use rustc_session::{config::ErrorOutputType, search_paths::PathKind, CtfeBacktrace}; struct MiriCompilerCalls { miri_config: miri::MiriConfig, } impl rustc_driver::Callbacks for MiriCompilerCalls { + fn config(&mut self, config: &mut Config) { + config.override_queries = Some(|_, _, external_providers| { + external_providers.used_crate_source = |tcx, cnum| { + let mut providers = Providers::default(); + rustc_metadata::provide_extern(&mut providers); + let mut crate_source = (providers.used_crate_source)(tcx, cnum); + // HACK: rustc will emit "crate ... required to be available in rlib format, but + // was not found in this form" errors once we use `tcx.dependency_formats()` if + // there's no rlib provided, so setting a dummy path here to workaround those errors. + Rc::make_mut(&mut crate_source).rlib = Some((PathBuf::new(), PathKind::All)); + crate_source + }; + }); + } + fn after_analysis<'tcx>( &mut self, compiler: &rustc_interface::interface::Compiler, @@ -67,6 +90,39 @@ impl rustc_driver::Callbacks for MiriCompilerCalls { } } +struct MiriBeRustCompilerCalls { + target_crate: bool, +} + +impl rustc_driver::Callbacks for MiriBeRustCompilerCalls { + fn config(&mut self, config: &mut Config) { + if config.opts.prints.is_empty() && self.target_crate { + // Queries overriden here affects the data stored in `rmeta` files of dependencies, + // which will be used later in non-`MIRI_BE_RUSTC` mode. + config.override_queries = Some(|_, local_providers, _| { + // `exported_symbols()` provided by rustc always returns empty result if + // `tcx.sess.opts.output_types.should_codegen()` is false. + local_providers.exported_symbols = |tcx, cnum| { + assert_eq!(cnum, LOCAL_CRATE); + tcx.arena.alloc_from_iter( + // This is based on: + // https://github.com/rust-lang/rust/blob/2962e7c0089d5c136f4e9600b7abccfbbde4973d/compiler/rustc_codegen_ssa/src/back/symbol_export.rs#L62-L63 + // https://github.com/rust-lang/rust/blob/2962e7c0089d5c136f4e9600b7abccfbbde4973d/compiler/rustc_codegen_ssa/src/back/symbol_export.rs#L174 + tcx.reachable_set(()).iter().filter_map(|&local_def_id| { + tcx.codegen_fn_attrs(local_def_id) + .contains_extern_indicator() + .then_some(( + ExportedSymbol::NonGeneric(local_def_id.to_def_id()), + SymbolExportLevel::C, + )) + }), + ) + } + }); + } + } +} + fn init_early_loggers() { // Note that our `extern crate log` is *not* the same as rustc's; as a result, we have to // initialize them both, and we always initialize `miri`'s first. @@ -179,11 +235,7 @@ fn main() { if let Some(crate_kind) = env::var_os("MIRI_BE_RUSTC") { rustc_driver::init_rustc_env_logger(); - // Don't insert `MIRI_DEFAULT_ARGS`, in particular, `--cfg=miri`, if we are building a - // "host" crate. That may cause procedural macros (and probably build scripts) to depend - // on Miri-only symbols, such as `miri_resolve_frame`: - // https://github.com/rust-lang/miri/issues/1760 - let insert_default_args = if crate_kind == "target" { + let target_crate = if crate_kind == "target" { true } else if crate_kind == "host" { false @@ -192,8 +244,16 @@ fn main() { }; // We cannot use `rustc_driver::main` as we need to adjust the CLI arguments. - let mut callbacks = rustc_driver::TimePassesCallbacks::default(); - run_compiler(env::args().collect(), &mut callbacks, insert_default_args) + run_compiler( + env::args().collect(), + &mut MiriBeRustCompilerCalls { target_crate }, + // Don't insert `MIRI_DEFAULT_ARGS`, in particular, `--cfg=miri`, if we are building + // a "host" crate. That may cause procedural macros (and probably build scripts) to + // depend on Miri-only symbols, such as `miri_resolve_frame`: + // https://github.com/rust-lang/miri/issues/1760 + #[rustfmt::skip] + /* insert_default_args: */ target_crate, + ) } // Init loggers the Miri way. diff --git a/src/diagnostics.rs b/src/diagnostics.rs index ae50b50860227..55702fb3c96b6 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -5,7 +5,7 @@ use std::num::NonZeroU64; use log::trace; use rustc_middle::ty::{self, TyCtxt}; -use rustc_span::{source_map::DUMMY_SP, Span}; +use rustc_span::{source_map::DUMMY_SP, Span, SpanData, Symbol}; use crate::*; @@ -14,8 +14,18 @@ pub enum TerminationInfo { Exit(i64), Abort(String), UnsupportedInIsolation(String), - ExperimentalUb { msg: String, url: String }, + ExperimentalUb { + msg: String, + url: String, + }, Deadlock, + MultipleSymbolDefinitions { + link_name: Symbol, + first: SpanData, + first_crate: Symbol, + second: SpanData, + second_crate: Symbol, + }, } impl fmt::Display for TerminationInfo { @@ -27,6 +37,8 @@ impl fmt::Display for TerminationInfo { UnsupportedInIsolation(msg) => write!(f, "{}", msg), ExperimentalUb { msg, .. } => write!(f, "{}", msg), Deadlock => write!(f, "the evaluated program deadlocked"), + MultipleSymbolDefinitions { link_name, .. } => + write!(f, "multiple definitions of symbol `{}`", link_name), } } } @@ -55,19 +67,25 @@ pub fn report_error<'tcx, 'mir>( use TerminationInfo::*; let title = match info { Exit(code) => return Some(*code), - Abort(_) => "abnormal termination", - UnsupportedInIsolation(_) => "unsupported operation", - ExperimentalUb { .. } => "Undefined Behavior", - Deadlock => "deadlock", + Abort(_) => Some("abnormal termination"), + UnsupportedInIsolation(_) => Some("unsupported operation"), + ExperimentalUb { .. } => Some("Undefined Behavior"), + Deadlock => Some("deadlock"), + MultipleSymbolDefinitions { .. } => None, }; #[rustfmt::skip] let helps = match info { UnsupportedInIsolation(_) => - vec![format!("pass the flag `-Zmiri-disable-isolation` to disable isolation")], + vec![(None, format!("pass the flag `-Zmiri-disable-isolation` to disable isolation"))], ExperimentalUb { url, .. } => vec![ - format!("this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental"), - format!("see {} for further information", url), + (None, format!("this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental")), + (None, format!("see {} for further information", url)), + ], + MultipleSymbolDefinitions { first, first_crate, second, second_crate, .. } => + vec![ + (Some(*first), format!("it's first defined here, in crate `{}`", first_crate)), + (Some(*second), format!("then it's defined here again, in crate `{}`", second_crate)), ], _ => vec![], }; @@ -90,26 +108,26 @@ pub fn report_error<'tcx, 'mir>( #[rustfmt::skip] let helps = match e.kind() { Unsupported(UnsupportedOpInfo::NoMirFor(..)) => - vec![format!("make sure to use a Miri sysroot, which you can prepare with `cargo miri setup`")], + vec![(None, format!("make sure to use a Miri sysroot, which you can prepare with `cargo miri setup`"))], Unsupported(UnsupportedOpInfo::ReadBytesAsPointer | UnsupportedOpInfo::ThreadLocalStatic(_) | UnsupportedOpInfo::ReadExternStatic(_)) => panic!("Error should never be raised by Miri: {:?}", e.kind()), Unsupported(_) => - vec![format!("this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support")], + vec![(None, format!("this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support"))], UndefinedBehavior(UndefinedBehaviorInfo::AlignmentCheckFailed { .. }) if ecx.memory.extra.check_alignment == AlignmentCheck::Symbolic => vec![ - format!("this usually indicates that your program performed an invalid operation and caused Undefined Behavior"), - format!("but due to `-Zmiri-symbolic-alignment-check`, alignment errors can also be false positives"), + (None, format!("this usually indicates that your program performed an invalid operation and caused Undefined Behavior")), + (None, format!("but due to `-Zmiri-symbolic-alignment-check`, alignment errors can also be false positives")), ], UndefinedBehavior(_) => vec![ - format!("this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior"), - format!("see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information"), + (None, format!("this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior")), + (None, format!("see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information")), ], _ => vec![], }; - (title, helps) + (Some(title), helps) } }; @@ -118,7 +136,7 @@ pub fn report_error<'tcx, 'mir>( report_msg( *ecx.tcx, /*error*/ true, - &format!("{}: {}", title, msg), + &if let Some(title) = title { format!("{}: {}", title, msg) } else { msg.clone() }, msg, helps, &ecx.generate_stacktrace(), @@ -157,7 +175,7 @@ fn report_msg<'tcx>( error: bool, title: &str, span_msg: String, - mut helps: Vec, + mut helps: Vec<(Option, String)>, stacktrace: &[FrameInfo<'tcx>], ) { let span = stacktrace.first().map_or(DUMMY_SP, |fi| fi.span); @@ -177,9 +195,13 @@ fn report_msg<'tcx>( // Show help messages. if !helps.is_empty() { // Add visual separator before backtrace. - helps.last_mut().unwrap().push_str("\n"); - for help in helps { - err.help(&help); + helps.last_mut().unwrap().1.push_str("\n"); + for (span_data, help) in helps { + if let Some(span_data) = span_data { + err.span_help(span_data.span(), &help); + } else { + err.help(&help); + } } } // Add backtrace diff --git a/src/lib.rs b/src/lib.rs index c9645d12fad16..25806b472b603 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,6 +3,7 @@ #![feature(map_try_insert)] #![feature(never_type)] #![feature(try_blocks)] +#![feature(bool_to_option)] #![warn(rust_2018_idioms)] #![allow(clippy::cast_lossless)] @@ -14,6 +15,7 @@ extern crate rustc_data_structures; extern crate rustc_hir; extern crate rustc_index; extern crate rustc_mir; +extern crate rustc_session; extern crate rustc_span; extern crate rustc_target; diff --git a/src/machine.rs b/src/machine.rs index 175396ed119cc..9c49575ded324 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -17,7 +17,7 @@ use rustc_middle::{ ty::{ self, layout::{LayoutCx, LayoutError, TyAndLayout}, - TyCtxt, + Instance, TyCtxt, }, }; use rustc_span::def_id::DefId; @@ -294,6 +294,9 @@ pub struct Evaluator<'mir, 'tcx> { /// Used with `profiler` to cache the `StringId`s for event names /// uesd with `measureme`. string_cache: FxHashMap, + + /// Cache of `Instance` exported under the given `Symbol` name. + pub(crate) exported_symbols_cache: FxHashMap>, } impl<'mir, 'tcx> Evaluator<'mir, 'tcx> { @@ -322,6 +325,7 @@ impl<'mir, 'tcx> Evaluator<'mir, 'tcx> { static_roots: Vec::new(), profiler, string_cache: Default::default(), + exported_symbols_cache: FxHashMap::default(), } } } diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 2afa1a8671289..2269b41d576f9 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -6,19 +6,37 @@ use std::{ use log::trace; use rustc_apfloat::Float; -use rustc_hir::def_id::DefId; +use rustc_hir::{ + def::DefKind, + def_id::{CrateNum, DefId, LOCAL_CRATE}, +}; +use rustc_middle::middle::{ + codegen_fn_attrs::CodegenFnAttrFlags, dependency_format::Linkage, + exported_symbols::ExportedSymbol, +}; use rustc_middle::mir; use rustc_middle::ty; -use rustc_span::symbol::sym; +use rustc_session::config::CrateType; +use rustc_span::{symbol::sym, Symbol}; use rustc_target::{ abi::{Align, Size}, - spec::{abi::Abi, PanicStrategy}, + spec::abi::Abi, }; use super::backtrace::EvalContextExt as _; use crate::*; use helpers::{check_abi, check_arg_count}; +/// Returned by `emulate_foreign_item_by_name`. +pub enum EmulateByNameResult { + /// The caller is expected to jump to the return block. + NeedsJumping, + /// Jumping has already been taken care of. + AlreadyJumped, + /// The item is not supported. + NotSupported, +} + impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { /// Returns the minimum alignment for the target architecture for allocations of the given size. @@ -108,6 +126,76 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } + /// Lookup the body of a function that has `link_name` as the symbol name. + fn lookup_exported_symbol( + &mut self, + link_name: Symbol, + ) -> InterpResult<'tcx, Option<&'mir mir::Body<'tcx>>> { + let this = self.eval_context_mut(); + let tcx = this.tcx.tcx; + + // If the result was cached, just return it. + if let Some(instance) = this.machine.exported_symbols_cache.get(&link_name) { + return Ok(Some(this.load_mir(instance.def, None)?)); + } + + // Find it if it was not cached. + let mut instance_and_crate: Option<(ty::Instance<'_>, CrateNum)> = None; + // `dependency_formats` includes all the transitive informations needed to link a crate, + // which is what we need here since we need to dig out `exported_symbols` from all transitive + // dependencies. + let dependency_formats = tcx.dependency_formats(()); + let dependency_format = dependency_formats + .iter() + .find(|(crate_type, _)| *crate_type == CrateType::Executable) + .expect("interpreting a non-executable crate"); + for cnum in + iter::once(LOCAL_CRATE).chain(dependency_format.1.iter().enumerate().filter_map( + |(num, &linkage)| (linkage != Linkage::NotLinked).then_some(CrateNum::new(num + 1)), + )) + { + // FIXME: Do we need to check `SymbolExportLevel` (the `_` below)? + for &(symbol, _) in tcx.exported_symbols(cnum) { + if let ExportedSymbol::NonGeneric(def_id) = symbol { + let attrs = tcx.codegen_fn_attrs(def_id); + let symbol_name = if let Some(export_name) = attrs.export_name { + export_name + } else if attrs.flags.contains(CodegenFnAttrFlags::NO_MANGLE) { + tcx.item_name(def_id) + } else { + // Skip over items without an explicitly defined symbol name. + continue; + }; + if symbol_name == link_name { + if let Some((instance, original_cnum)) = instance_and_crate { + throw_machine_stop!(TerminationInfo::MultipleSymbolDefinitions { + link_name, + first: tcx.def_span(instance.def_id()).data(), + first_crate: tcx.crate_name(original_cnum), + second: tcx.def_span(def_id).data(), + second_crate: tcx.crate_name(cnum), + }); + } + if tcx.def_kind(def_id) != DefKind::Fn { + throw_ub_format!( + "attempt to call an exported symbol that is not defined as a function" + ); + } + instance_and_crate = Some((ty::Instance::mono(tcx, def_id), cnum)); + } + } + } + } + + // Cache it and load its MIR, if found. + instance_and_crate + .map(|(instance, _)| { + this.machine.exported_symbols_cache.insert(link_name, instance); + this.load_mir(instance.def, None) + }) + .transpose() + } + /// Emulates calling a foreign item, failing if the item is not supported. /// This function will handle `goto_block` if needed. /// Returns Ok(None) if the foreign item was completely handled @@ -124,10 +212,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, Option<&'mir mir::Body<'tcx>>> { let this = self.eval_context_mut(); let attrs = this.tcx.get_attrs(def_id); - let link_name = match this.tcx.sess.first_attr_value_str_by_name(&attrs, sym::link_name) { - Some(name) => name.as_str(), - None => this.tcx.item_name(def_id).as_str(), + let link_name_sym = match this.tcx.sess.first_attr_value_str_by_name(&attrs, sym::link_name) + { + Some(name) => name, + None => this.tcx.item_name(def_id), }; + let link_name = link_name_sym.as_str(); // Strip linker suffixes (seen on 32-bit macOS). let link_name = link_name.trim_end_matches("$UNIX2003"); let tcx = this.tcx.tcx; @@ -164,48 +254,35 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "the program aborted execution".to_owned() )) } - _ => throw_unsup_format!("can't call (diverging) foreign function: {}", link_name), + _ => { + if let Some(body) = this.lookup_exported_symbol(link_name_sym)? { + return Ok(Some(body)); + } + throw_unsup_format!("can't call (diverging) foreign function: {}", link_name); + } }, Some(p) => p, }; - // Second: some functions that we forward to MIR implementations. - match link_name { - // This matches calls to the foreign item `__rust_start_panic`, that is, - // calls to `extern "Rust" { fn __rust_start_panic(...) }` - // (and `__rust_panic_cleanup`, respectively). - // We forward this to the underlying *implementation* in the panic runtime crate. - // Normally, this will be either `libpanic_unwind` or `libpanic_abort`, but it could - // also be a custom user-provided implementation via `#![feature(panic_runtime)]` - #[rustfmt::skip] - "__rust_start_panic" | - "__rust_panic_cleanup" => { - check_abi(this, abi, Abi::C { unwind: false })?; - // This replicates some of the logic in `inject_panic_runtime`. - // FIXME: is there a way to reuse that logic? - let panic_runtime = match this.tcx.sess.panic_strategy() { - PanicStrategy::Unwind => sym::panic_unwind, - PanicStrategy::Abort => sym::panic_abort, - }; - let start_panic_instance = - this.resolve_path(&[&*panic_runtime.as_str(), link_name]); - return Ok(Some(&*this.load_mir(start_panic_instance.def, None)?)); + // Second: functions that return. + match this.emulate_foreign_item_by_name(link_name, abi, args, dest, ret)? { + EmulateByNameResult::NeedsJumping => { + trace!("{:?}", this.dump_place(**dest)); + this.go_to_block(ret); + } + EmulateByNameResult::AlreadyJumped => (), + EmulateByNameResult::NotSupported => { + if let Some(body) = this.lookup_exported_symbol(link_name_sym)? { + return Ok(Some(body)); + } + throw_unsup_format!("can't call foreign function: {}", link_name); } - _ => {} - } - - // Third: functions that return. - if this.emulate_foreign_item_by_name(link_name, abi, args, dest, ret)? { - trace!("{:?}", this.dump_place(**dest)); - this.go_to_block(ret); } Ok(None) } - /// Emulates calling a foreign item using its name, failing if the item is not supported. - /// Returns `true` if the caller is expected to jump to the return block, and `false` if - /// jumping has already been taken care of. + /// Emulates calling a foreign item using its name. fn emulate_foreign_item_by_name( &mut self, link_name: &str, @@ -213,7 +290,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx args: &[OpTy<'tcx, Tag>], dest: &PlaceTy<'tcx, Tag>, ret: mir::BasicBlock, - ) -> InterpResult<'tcx, bool> { + ) -> InterpResult<'tcx, EmulateByNameResult> { let this = self.eval_context_mut(); // Here we dispatch all the shims for foreign functions. If you have a platform specific @@ -549,7 +626,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } }; - Ok(true) + // We only fall through to here if we did *not* hit the `_` arm above, + // i.e., if we actually emulated the function. + Ok(EmulateByNameResult::NeedsJumping) } /// Check some basic requirements for this allocation request: diff --git a/src/shims/posix/foreign_items.rs b/src/shims/posix/foreign_items.rs index 5eb731d09c864..f153098cac85f 100644 --- a/src/shims/posix/foreign_items.rs +++ b/src/shims/posix/foreign_items.rs @@ -6,6 +6,7 @@ use rustc_target::spec::abi::Abi; use crate::*; use helpers::{check_abi, check_arg_count}; +use shims::foreign_items::EmulateByNameResult; use shims::posix::fs::EvalContextExt as _; use shims::posix::sync::EvalContextExt as _; use shims::posix::thread::EvalContextExt as _; @@ -19,7 +20,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx args: &[OpTy<'tcx, Tag>], dest: &PlaceTy<'tcx, Tag>, ret: mir::BasicBlock, - ) -> InterpResult<'tcx, bool> { + ) -> InterpResult<'tcx, EmulateByNameResult> { let this = self.eval_context_mut(); match link_name { @@ -524,6 +525,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } }; - Ok(true) + Ok(EmulateByNameResult::NeedsJumping) } } diff --git a/src/shims/posix/linux/foreign_items.rs b/src/shims/posix/linux/foreign_items.rs index d16c740ffc547..47ffad56d1222 100644 --- a/src/shims/posix/linux/foreign_items.rs +++ b/src/shims/posix/linux/foreign_items.rs @@ -3,6 +3,7 @@ use rustc_target::spec::abi::Abi; use crate::helpers::{check_abi, check_arg_count}; use crate::*; +use shims::foreign_items::EmulateByNameResult; use shims::posix::fs::EvalContextExt as _; use shims::posix::linux::sync::futex; use shims::posix::sync::EvalContextExt as _; @@ -17,7 +18,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx args: &[OpTy<'tcx, Tag>], dest: &PlaceTy<'tcx, Tag>, _ret: mir::BasicBlock, - ) -> InterpResult<'tcx, bool> { + ) -> InterpResult<'tcx, EmulateByNameResult> { let this = self.eval_context_mut(); match link_name { @@ -214,10 +215,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_null(dest)?; } - _ => throw_unsup_format!("can't call foreign function: {}", link_name), + _ => return Ok(EmulateByNameResult::NotSupported), }; - Ok(true) + Ok(EmulateByNameResult::NeedsJumping) } } diff --git a/src/shims/posix/macos/foreign_items.rs b/src/shims/posix/macos/foreign_items.rs index de4ed56633cbf..15a073dd04ef5 100644 --- a/src/shims/posix/macos/foreign_items.rs +++ b/src/shims/posix/macos/foreign_items.rs @@ -3,6 +3,7 @@ use rustc_target::spec::abi::Abi; use crate::*; use helpers::{check_abi, check_arg_count}; +use shims::foreign_items::EmulateByNameResult; use shims::posix::fs::EvalContextExt as _; use shims::posix::thread::EvalContextExt as _; @@ -15,7 +16,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx args: &[OpTy<'tcx, Tag>], dest: &PlaceTy<'tcx, Tag>, _ret: mir::BasicBlock, - ) -> InterpResult<'tcx, bool> { + ) -> InterpResult<'tcx, EmulateByNameResult> { let this = self.eval_context_mut(); match link_name { @@ -156,9 +157,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(addr, dest)?; } - _ => throw_unsup_format!("can't call foreign function: {}", link_name), + _ => return Ok(EmulateByNameResult::NotSupported), }; - Ok(true) + Ok(EmulateByNameResult::NeedsJumping) } } diff --git a/src/shims/windows/foreign_items.rs b/src/shims/windows/foreign_items.rs index d7b86fff73274..0f9e3899b85af 100644 --- a/src/shims/windows/foreign_items.rs +++ b/src/shims/windows/foreign_items.rs @@ -6,6 +6,7 @@ use rustc_target::spec::abi::Abi; use crate::*; use helpers::{check_abi, check_arg_count}; +use shims::foreign_items::EmulateByNameResult; use shims::windows::sync::EvalContextExt as _; impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} @@ -17,7 +18,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx args: &[OpTy<'tcx, Tag>], dest: &PlaceTy<'tcx, Tag>, _ret: mir::BasicBlock, - ) -> InterpResult<'tcx, bool> { + ) -> InterpResult<'tcx, EmulateByNameResult> { let this = self.eval_context_mut(); // Windows API stubs. @@ -415,9 +416,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_i32(1), dest)?; } - _ => throw_unsup_format!("can't call foreign function: {}", link_name), + _ => return Ok(EmulateByNameResult::NotSupported), } - Ok(true) + Ok(EmulateByNameResult::NeedsJumping) } } diff --git a/test-cargo-miri/Cargo.lock b/test-cargo-miri/Cargo.lock index 403b9327930ab..9a9fa4797bf26 100644 --- a/test-cargo-miri/Cargo.lock +++ b/test-cargo-miri/Cargo.lock @@ -14,6 +14,7 @@ version = "0.1.0" dependencies = [ "byteorder", "cdylib", + "exported_symbol", "getrandom 0.1.16", "getrandom 0.2.2", "issue_1567", @@ -37,6 +38,17 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "exported_symbol" +version = "0.1.0" +dependencies = [ + "exported_symbol_dep", +] + +[[package]] +name = "exported_symbol_dep" +version = "0.1.0" + [[package]] name = "getrandom" version = "0.1.16" diff --git a/test-cargo-miri/Cargo.toml b/test-cargo-miri/Cargo.toml index 4dbe1aeff23a3..cf557bd60ef39 100644 --- a/test-cargo-miri/Cargo.toml +++ b/test-cargo-miri/Cargo.toml @@ -1,5 +1,5 @@ [workspace] -members = ["subcrate", "issue-1567"] +members = ["subcrate", "issue-1567", "exported-symbol-dep"] [package] name = "cargo-miri-test" @@ -10,6 +10,7 @@ edition = "2018" [dependencies] byteorder = "1.0" cdylib = { path = "cdylib" } +exported_symbol = { path = "exported-symbol" } issue_1567 = { path = "issue-1567" } issue_1691 = { path = "issue-1691" } issue_1705 = { path = "issue-1705" } diff --git a/test-cargo-miri/exported-symbol-dep/Cargo.toml b/test-cargo-miri/exported-symbol-dep/Cargo.toml new file mode 100644 index 0000000000000..00c41172c3af2 --- /dev/null +++ b/test-cargo-miri/exported-symbol-dep/Cargo.toml @@ -0,0 +1,5 @@ +[package] +name = "exported_symbol_dep" +version = "0.1.0" +authors = ["Miri Team"] +edition = "2018" diff --git a/test-cargo-miri/exported-symbol-dep/src/lib.rs b/test-cargo-miri/exported-symbol-dep/src/lib.rs new file mode 100644 index 0000000000000..4cc18fb9b2fbc --- /dev/null +++ b/test-cargo-miri/exported-symbol-dep/src/lib.rs @@ -0,0 +1,4 @@ +#[no_mangle] +fn exported_symbol() -> i32 { + 123456 +} diff --git a/test-cargo-miri/exported-symbol/Cargo.toml b/test-cargo-miri/exported-symbol/Cargo.toml new file mode 100644 index 0000000000000..7c01be1a85f9c --- /dev/null +++ b/test-cargo-miri/exported-symbol/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "exported_symbol" +version = "0.1.0" +authors = ["Miri Team"] +edition = "2018" + +[dependencies] +# This will become a transitive dependency of doctests in `test-cargo-miri/src/lib.rs`, +# and the purpose of the test is to make sure Miri can find a `#[no_mangle]` function in a +# transitive dependency like `exported_symbol_dep`. +exported_symbol_dep = { path = "../exported-symbol-dep" } diff --git a/test-cargo-miri/exported-symbol/src/lib.rs b/test-cargo-miri/exported-symbol/src/lib.rs new file mode 100644 index 0000000000000..de55eb2a1a5a0 --- /dev/null +++ b/test-cargo-miri/exported-symbol/src/lib.rs @@ -0,0 +1 @@ +extern crate exported_symbol_dep; diff --git a/test-cargo-miri/src/lib.rs b/test-cargo-miri/src/lib.rs index 9d8eb067d6fa7..6397d072e89ef 100644 --- a/test-cargo-miri/src/lib.rs +++ b/test-cargo-miri/src/lib.rs @@ -1,6 +1,21 @@ +extern crate exported_symbol; + /// Doc-test test /// ```rust /// assert!(cargo_miri_test::make_true()); +/// // Repeat calls to make sure the `Instance` cache is not broken. +/// for _ in 0..3 { +/// extern "Rust" { +/// fn exported_symbol() -> i32; +/// fn make_true() -> bool; +/// } +/// assert_eq!(unsafe { exported_symbol() }, 123456); +/// assert!(unsafe { make_true() }); +/// } +/// ``` +/// ```compile_fail +/// // Make sure `exported_symbol_dep` is not a direct dependency for doctests. +/// use exported_symbol_dep; /// ``` /// ```rust,no_run /// assert!(!cargo_miri_test::make_true()); @@ -8,6 +23,7 @@ /// ```rust,compile_fail /// assert!(cargo_miri_test::make_true() == 5); /// ``` +#[no_mangle] pub fn make_true() -> bool { issue_1567::use_the_dependency(); issue_1705::use_the_dependency(); diff --git a/test-cargo-miri/test.default.stdout.ref b/test-cargo-miri/test.default.stdout.ref index 470e5b36fc515..e97119f217f7a 100644 --- a/test-cargo-miri/test.default.stdout.ref +++ b/test-cargo-miri/test.default.stdout.ref @@ -10,10 +10,11 @@ running 7 tests test result: ok. 6 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out -running 3 tests -test src/lib.rs - make_true (line 2) ... ok -test src/lib.rs - make_true (line 5) ... ok -test src/lib.rs - make_true (line 8) ... ok +running 4 tests +test src/lib.rs - make_true (line 16) ... ok +test src/lib.rs - make_true (line 20) ... ok +test src/lib.rs - make_true (line 23) ... ok +test src/lib.rs - make_true (line 4) ... ok -test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME +test result: ok. 4 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME diff --git a/test-cargo-miri/test.filter.stdout.ref b/test-cargo-miri/test.filter.stdout.ref index cf1b309a12786..61565a4c1e4a3 100644 --- a/test-cargo-miri/test.filter.stdout.ref +++ b/test-cargo-miri/test.filter.stdout.ref @@ -13,5 +13,5 @@ test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 6 filtered out running 0 tests -test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 3 filtered out; finished in $TIME +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 4 filtered out; finished in $TIME diff --git a/tests/compile-fail/check_arg_abi.rs b/tests/compile-fail/function_calls/check_arg_abi.rs similarity index 100% rename from tests/compile-fail/check_arg_abi.rs rename to tests/compile-fail/function_calls/check_arg_abi.rs diff --git a/tests/compile-fail/check_arg_count_too_few_args.rs b/tests/compile-fail/function_calls/check_arg_count_too_few_args.rs similarity index 100% rename from tests/compile-fail/check_arg_count_too_few_args.rs rename to tests/compile-fail/function_calls/check_arg_count_too_few_args.rs diff --git a/tests/compile-fail/check_arg_count_too_many_args.rs b/tests/compile-fail/function_calls/check_arg_count_too_many_args.rs similarity index 100% rename from tests/compile-fail/check_arg_count_too_many_args.rs rename to tests/compile-fail/function_calls/check_arg_count_too_many_args.rs diff --git a/tests/compile-fail/check_callback_abi.rs b/tests/compile-fail/function_calls/check_callback_abi.rs similarity index 100% rename from tests/compile-fail/check_callback_abi.rs rename to tests/compile-fail/function_calls/check_callback_abi.rs diff --git a/tests/compile-fail/function_calls/exported_symbol_abi_mismatch.rs b/tests/compile-fail/function_calls/exported_symbol_abi_mismatch.rs new file mode 100644 index 0000000000000..d62cb2e8b7ad9 --- /dev/null +++ b/tests/compile-fail/function_calls/exported_symbol_abi_mismatch.rs @@ -0,0 +1,22 @@ +// revisions: no_cache cache + +#[no_mangle] +fn foo() {} + +fn main() { + #[cfg(cache)] + { + // `Instance` caching should not suppress ABI check. + extern "Rust" { + fn foo(); + } + unsafe { foo() } + } + #[cfg_attr(cache, allow(clashing_extern_declarations))] + extern "C" { + fn foo(); + } + unsafe { foo() } + //[no_cache]~^ ERROR Undefined Behavior: calling a function with ABI Rust using caller ABI C + //[cache]~^^ ERROR Undefined Behavior: calling a function with ABI Rust using caller ABI C +} diff --git a/tests/compile-fail/function_calls/exported_symbol_bad_unwind1.rs b/tests/compile-fail/function_calls/exported_symbol_bad_unwind1.rs new file mode 100644 index 0000000000000..91b0e8fc03f22 --- /dev/null +++ b/tests/compile-fail/function_calls/exported_symbol_bad_unwind1.rs @@ -0,0 +1,15 @@ +// compile-flags: -Zmiri-disable-abi-check +#![feature(c_unwind)] + +#[no_mangle] +extern "C-unwind" fn unwind() { + panic!(); +} + +fn main() { + extern "C" { + fn unwind(); + } + unsafe { unwind() } + //~^ ERROR unwinding past a stack frame that does not allow unwinding +} diff --git a/tests/compile-fail/function_calls/exported_symbol_bad_unwind2.rs b/tests/compile-fail/function_calls/exported_symbol_bad_unwind2.rs new file mode 100644 index 0000000000000..85cca8f1a6bd3 --- /dev/null +++ b/tests/compile-fail/function_calls/exported_symbol_bad_unwind2.rs @@ -0,0 +1,19 @@ +// revisions: extern_block definition both +#![feature(rustc_attrs, c_unwind)] + +#[cfg_attr(any(definition, both), rustc_allocator_nounwind)] +#[no_mangle] +extern "C-unwind" fn nounwind() { + panic!(); +} + +fn main() { + extern "C-unwind" { + #[cfg_attr(any(extern_block, both), rustc_allocator_nounwind)] + fn nounwind(); + } + unsafe { nounwind() } + //[extern_block]~^ ERROR unwinding past a stack frame that does not allow unwinding + //[definition]~^^ ERROR unwinding past a stack frame that does not allow unwinding + //[both]~^^^ ERROR unwinding past a stack frame that does not allow unwinding +} diff --git a/tests/compile-fail/function_calls/exported_symbol_bad_unwind3.rs b/tests/compile-fail/function_calls/exported_symbol_bad_unwind3.rs new file mode 100644 index 0000000000000..dfb378cef5234 --- /dev/null +++ b/tests/compile-fail/function_calls/exported_symbol_bad_unwind3.rs @@ -0,0 +1,16 @@ +#![feature(unwind_attributes)] +#![feature(c_unwind)] // make sure it doesn't insert abort-on-unwind for the `#[unwind(allowed)]` function + +#[unwind(allowed)] +#[no_mangle] +extern "C" fn unwind() { + panic!(); +} + +fn main() { + extern "C" { + fn unwind(); + } + unsafe { unwind() } + //~^ ERROR unwinding past a stack frame that does not allow unwinding +} diff --git a/tests/compile-fail/function_calls/exported_symbol_clashing.rs b/tests/compile-fail/function_calls/exported_symbol_clashing.rs new file mode 100644 index 0000000000000..105d98fc10a97 --- /dev/null +++ b/tests/compile-fail/function_calls/exported_symbol_clashing.rs @@ -0,0 +1,15 @@ +#[no_mangle] +fn foo() {} +//~^ HELP then it's defined here again, in crate `exported_symbol_clashing` + +#[export_name = "foo"] +fn bar() {} +//~^ HELP it's first defined here, in crate `exported_symbol_clashing` + +fn main() { + extern "Rust" { + fn foo(); + } + unsafe { foo() } + //~^ ERROR multiple definitions of symbol `foo` +} diff --git a/tests/compile-fail/function_calls/exported_symbol_wrong_arguments.rs b/tests/compile-fail/function_calls/exported_symbol_wrong_arguments.rs new file mode 100644 index 0000000000000..8fb364bb9bd10 --- /dev/null +++ b/tests/compile-fail/function_calls/exported_symbol_wrong_arguments.rs @@ -0,0 +1,9 @@ +#[no_mangle] +fn foo() {} + +fn main() { + extern "Rust" { + fn foo(_: i32); + } + unsafe { foo(1) } //~ ERROR calling a function with more arguments than it expected +} diff --git a/tests/compile-fail/function_calls/exported_symbol_wrong_type.rs b/tests/compile-fail/function_calls/exported_symbol_wrong_type.rs new file mode 100644 index 0000000000000..3ffd506c94bb5 --- /dev/null +++ b/tests/compile-fail/function_calls/exported_symbol_wrong_type.rs @@ -0,0 +1,9 @@ +#[no_mangle] +static FOO: () = (); + +fn main() { + extern "C" { + fn FOO(); + } + unsafe { FOO() } //~ ERROR attempt to call an exported symbol that is not defined as a function +} diff --git a/tests/compile-fail/panic/bad_miri_start_panic.rs b/tests/compile-fail/panic/bad_miri_start_panic.rs new file mode 100644 index 0000000000000..f77f892abc1c1 --- /dev/null +++ b/tests/compile-fail/panic/bad_miri_start_panic.rs @@ -0,0 +1,10 @@ +// compile-flags: -Zmiri-disable-abi-check + +extern "C" { + fn miri_start_panic(payload: *mut u8) -> !; +} + +fn main() { + unsafe { miri_start_panic(&mut 0) } + //~^ ERROR unwinding past a stack frame that does not allow unwinding +} diff --git a/tests/compile-fail/panic/rustc_allocator_nounwind.rs b/tests/compile-fail/panic/rustc_allocator_nounwind.rs new file mode 100644 index 0000000000000..7261b6658753a --- /dev/null +++ b/tests/compile-fail/panic/rustc_allocator_nounwind.rs @@ -0,0 +1,10 @@ +#![feature(rustc_attrs, c_unwind)] + +#[rustc_allocator_nounwind] +extern "C-unwind" fn nounwind() { + panic!(); +} + +fn main() { + nounwind(); //~ ERROR unwinding past a stack frame that does not allow unwinding +} diff --git a/tests/run-pass/disable_abi_check.rs b/tests/run-pass/function_calls/disable_abi_check.rs similarity index 100% rename from tests/run-pass/disable_abi_check.rs rename to tests/run-pass/function_calls/disable_abi_check.rs diff --git a/tests/run-pass/function_calls/exported_symbol.rs b/tests/run-pass/function_calls/exported_symbol.rs new file mode 100644 index 0000000000000..7f359e80219fc --- /dev/null +++ b/tests/run-pass/function_calls/exported_symbol.rs @@ -0,0 +1,44 @@ +#![feature(rustc_attrs)] + +#[no_mangle] +extern "C" fn foo() -> i32 { + -1 +} + +#[export_name = "bar"] +fn bar() -> i32 { + -2 +} + +#[rustc_std_internal_symbol] +fn baz() -> i32 { + -3 +} + +// Make sure shims take precedence. +#[no_mangle] +extern "C" fn exit(_: i32) -> ! { + unreachable!() +} + +#[no_mangle] +extern "C" fn ExitProcess(_: u32) -> ! { + unreachable!() +} + +fn main() { + // Repeat calls to make sure the `Instance` cache is not broken. + for _ in 0..3 { + extern "C" { + fn foo() -> i32; + } + assert_eq!(unsafe { foo() }, -1); + assert_eq!(unsafe { foo() }, -1); + extern "Rust" { + fn bar() -> i32; + fn baz() -> i32; + } + assert_eq!(unsafe { bar() }, -2); + assert_eq!(unsafe { baz() }, -3); + } +} diff --git a/tests/run-pass/function_calls/exported_symbol_good_unwind.rs b/tests/run-pass/function_calls/exported_symbol_good_unwind.rs new file mode 100644 index 0000000000000..73192707f1e47 --- /dev/null +++ b/tests/run-pass/function_calls/exported_symbol_good_unwind.rs @@ -0,0 +1,49 @@ +// Make sure the workaround for "crate ... required to be available in rlib format, but was not +// found in this form" errors works without `-C prefer-dynamic` (`panic!` calls foreign function +// foreign function `__rust_start_panic`). +// no-prefer-dynamic +#![feature(c_unwind, unboxed_closures, unwind_attributes)] + +use std::panic; + +#[no_mangle] +#[unwind(allowed)] +extern "C" fn good_unwind_allowed() { + panic!(); +} + +#[no_mangle] +extern "C-unwind" fn good_unwind_c() { + panic!(); +} + +#[no_mangle] +fn good_unwind_rust() { + panic!(); +} + +// Diverging function calls are on a different code path. +#[no_mangle] +extern "rust-call" fn good_unwind_rust_call(_: ()) -> ! { + panic!(); +} + +fn main() -> ! { + extern "C" { + #[unwind(allowed)] + fn good_unwind_allowed(); + } + panic::catch_unwind(|| unsafe { good_unwind_allowed() }).unwrap_err(); + extern "C-unwind" { + fn good_unwind_c(); + } + panic::catch_unwind(|| unsafe { good_unwind_c() }).unwrap_err(); + extern "Rust" { + fn good_unwind_rust(); + } + panic::catch_unwind(|| unsafe { good_unwind_rust() }).unwrap_err(); + extern "rust-call" { + fn good_unwind_rust_call(_: ()) -> !; + } + unsafe { good_unwind_rust_call(()) } +} diff --git a/tests/run-pass/function_calls/exported_symbol_good_unwind.stderr b/tests/run-pass/function_calls/exported_symbol_good_unwind.stderr new file mode 100644 index 0000000000000..3347f00b65eab --- /dev/null +++ b/tests/run-pass/function_calls/exported_symbol_good_unwind.stderr @@ -0,0 +1,5 @@ +thread 'main' panicked at 'explicit panic', $DIR/exported_symbol_good_unwind.rs:12:5 +note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace +thread 'main' panicked at 'explicit panic', $DIR/exported_symbol_good_unwind.rs:17:5 +thread 'main' panicked at 'explicit panic', $DIR/exported_symbol_good_unwind.rs:22:5 +thread 'main' panicked at 'explicit panic', $DIR/exported_symbol_good_unwind.rs:28:5 diff --git a/tests/run-pass/function_calls/exported_symbol_unwind_allowed.rs b/tests/run-pass/function_calls/exported_symbol_unwind_allowed.rs new file mode 100644 index 0000000000000..0e4ec5739a8a0 --- /dev/null +++ b/tests/run-pass/function_calls/exported_symbol_unwind_allowed.rs @@ -0,0 +1,15 @@ +// compile-flags: -Zmiri-disable-abi-check +#![feature(unwind_attributes, c_unwind)] + +#[no_mangle] +extern "C-unwind" fn unwind() { + panic!(); +} + +fn main() { + extern "C" { + #[unwind(allowed)] + fn unwind(); + } + unsafe { unwind() } +} diff --git a/tests/run-pass/function_calls/exported_symbol_unwind_allowed.stderr b/tests/run-pass/function_calls/exported_symbol_unwind_allowed.stderr new file mode 100644 index 0000000000000..14ee43950cec7 --- /dev/null +++ b/tests/run-pass/function_calls/exported_symbol_unwind_allowed.stderr @@ -0,0 +1,2 @@ +thread 'main' panicked at 'explicit panic', $DIR/exported_symbol_unwind_allowed.rs:6:5 +note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace diff --git a/tests/run-pass/panic/good_unwind.rs b/tests/run-pass/panic/good_unwind.rs new file mode 100644 index 0000000000000..dbc1c1631f135 --- /dev/null +++ b/tests/run-pass/panic/good_unwind.rs @@ -0,0 +1,27 @@ +#![feature(c_unwind, unboxed_closures, unwind_attributes)] + +use std::panic; + +extern "C-unwind" fn good_unwind_c() { + panic!(); +} + +#[unwind(allowed)] +extern "C" fn good_unwind_allowed() { + panic!(); +} + +fn good_unwind_rust() { + panic!(); +} + +extern "rust-call" fn good_unwind_rust_call(_: ()) { + panic!(); +} + +fn main() { + panic::catch_unwind(|| good_unwind_c()).unwrap_err(); + panic::catch_unwind(|| good_unwind_allowed()).unwrap_err(); + panic::catch_unwind(|| good_unwind_rust()).unwrap_err(); + good_unwind_rust_call(()); +} diff --git a/tests/run-pass/panic/good_unwind.stderr b/tests/run-pass/panic/good_unwind.stderr new file mode 100644 index 0000000000000..1cd361790b661 --- /dev/null +++ b/tests/run-pass/panic/good_unwind.stderr @@ -0,0 +1,5 @@ +thread 'main' panicked at 'explicit panic', $DIR/good_unwind.rs:6:5 +note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace +thread 'main' panicked at 'explicit panic', $DIR/good_unwind.rs:11:5 +thread 'main' panicked at 'explicit panic', $DIR/good_unwind.rs:15:5 +thread 'main' panicked at 'explicit panic', $DIR/good_unwind.rs:19:5 From ddc2ee9db6d3d00528ab52f5fcf9a76338b35088 Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Sun, 30 May 2021 20:30:00 +0800 Subject: [PATCH 2692/3747] Move `-Zmiri-disable-abi-check` in README --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index f87a7e989d973..f0e14a9125c61 100644 --- a/README.md +++ b/README.md @@ -200,6 +200,8 @@ environment variable: `compare_exchange_weak` operations. The default is `0.8` (so 4 out of 5 weak ops will fail). You can change it to any value between `0.0` and `1.0`, where `1.0` means it will always fail and `0.0` means it will never fail. +* `-Zmiri-disable-abi-check` disables checking [function ABI]. Using this flag + is **unsound**. * `-Zmiri-disable-alignment-check` disables checking pointer alignment, so you can focus on other failures, but it means Miri can miss bugs in your program. Using this flag is **unsound**. @@ -214,8 +216,6 @@ environment variable: as out-of-bounds accesses) first. Setting this flag means Miri can miss bugs in your program. However, this can also help to make Miri run faster. Using this flag is **unsound**. -* `-Zmiri-disable-abi-check` disables checking [function ABI]. Using this flag - is **unsound**. * `-Zmiri-disable-isolation` disables host isolation. As a consequence, the program has access to host resources such as environment variables, file systems, and randomness. From 382295cd4745cdf2f52794a16fd7083fef01d0b8 Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Sun, 30 May 2021 20:38:52 +0800 Subject: [PATCH 2693/3747] Move `check_abi()` into `EvalContextExt` --- src/helpers.rs | 28 +++--- src/shims/foreign_items.rs | 54 +++++------ src/shims/posix/dlsym.rs | 3 +- src/shims/posix/foreign_items.rs | 124 ++++++++++++------------- src/shims/posix/linux/foreign_items.rs | 34 +++---- src/shims/posix/macos/foreign_items.rs | 40 ++++---- src/shims/windows/dlsym.rs | 3 +- src/shims/windows/foreign_items.rs | 82 ++++++++-------- 8 files changed, 181 insertions(+), 187 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index af6985ccebdbf..12d18799ebcdb 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -616,6 +616,18 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(wchars) } + + /// Check that the ABI is what we expect. + fn check_abi<'a>(&self, abi: Abi, exp_abi: Abi) -> InterpResult<'a, ()> { + if self.eval_context_ref().machine.enforce_abi && abi != exp_abi { + throw_ub_format!( + "calling a function with ABI {} using caller ABI {}", + exp_abi.name(), + abi.name() + ) + } + Ok(()) + } } /// Check that the number of args is what we expect. @@ -631,22 +643,6 @@ where throw_ub_format!("incorrect number of arguments: got {}, expected {}", args.len(), N) } -/// Check that the ABI is what we expect. -pub fn check_abi<'a>( - this: &MiriEvalContext<'_, '_>, - abi: Abi, - exp_abi: Abi, -) -> InterpResult<'a, ()> { - if this.machine.enforce_abi && abi != exp_abi { - throw_ub_format!( - "calling a function with ABI {} using caller ABI {}", - exp_abi.name(), - abi.name() - ) - } - Ok(()) -} - pub fn isolation_error(name: &str) -> InterpResult<'static> { throw_machine_stop!(TerminationInfo::UnsupportedInIsolation(format!( "{} not available when isolation is enabled", diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 2269b41d576f9..70de55c5be757 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -25,7 +25,7 @@ use rustc_target::{ use super::backtrace::EvalContextExt as _; use crate::*; -use helpers::{check_abi, check_arg_count}; +use helpers::check_arg_count; /// Returned by `emulate_foreign_item_by_name`. pub enum EmulateByNameResult { @@ -226,14 +226,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let (dest, ret) = match ret { None => match link_name { "miri_start_panic" => { - check_abi(this, abi, Abi::Rust)?; + this.check_abi(abi, Abi::Rust)?; this.handle_miri_start_panic(args, unwind)?; return Ok(None); } // This matches calls to the foreign item `panic_impl`. // The implementation is provided by the function with the `#[panic_handler]` attribute. "panic_impl" => { - check_abi(this, abi, Abi::Rust)?; + this.check_abi(abi, Abi::Rust)?; let panic_impl_id = tcx.lang_items().panic_impl().unwrap(); let panic_impl_instance = ty::Instance::mono(tcx, panic_impl_id); return Ok(Some(&*this.load_mir(panic_impl_instance.def, None)?)); @@ -242,14 +242,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "exit" | "ExitProcess" => { - check_abi(this, abi, if link_name == "exit" { Abi::C { unwind: false } } else { Abi::System { unwind: false } })?; + this.check_abi(abi, if link_name == "exit" { Abi::C { unwind: false } } else { Abi::System { unwind: false } })?; let &[ref code] = check_arg_count(args)?; // it's really u32 for ExitProcess, but we have to put it into the `Exit` variant anyway let code = this.read_scalar(code)?.to_i32()?; throw_machine_stop!(TerminationInfo::Exit(code.into())); } "abort" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; throw_machine_stop!(TerminationInfo::Abort( "the program aborted execution".to_owned() )) @@ -298,7 +298,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx match link_name { // Miri-specific extern functions "miri_static_root" => { - check_abi(this, abi, Abi::Rust)?; + this.check_abi(abi, Abi::Rust)?; let &[ref ptr] = check_arg_count(args)?; let ptr = this.read_scalar(ptr)?.check_init()?; let ptr = this.force_ptr(ptr)?; @@ -310,27 +310,27 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Obtains a Miri backtrace. See the README for details. "miri_get_backtrace" => { - check_abi(this, abi, Abi::Rust)?; + this.check_abi(abi, Abi::Rust)?; this.handle_miri_get_backtrace(args, dest)?; } // Resolves a Miri backtrace frame. See the README for details. "miri_resolve_frame" => { - check_abi(this, abi, Abi::Rust)?; + this.check_abi(abi, Abi::Rust)?; this.handle_miri_resolve_frame(args, dest)?; } // Standard C allocation "malloc" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref size] = check_arg_count(args)?; let size = this.read_scalar(size)?.to_machine_usize(this)?; let res = this.malloc(size, /*zero_init:*/ false, MiriMemoryKind::C); this.write_scalar(res, dest)?; } "calloc" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref items, ref len] = check_arg_count(args)?; let items = this.read_scalar(items)?.to_machine_usize(this)?; let len = this.read_scalar(len)?.to_machine_usize(this)?; @@ -340,13 +340,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(res, dest)?; } "free" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref ptr] = check_arg_count(args)?; let ptr = this.read_scalar(ptr)?.check_init()?; this.free(ptr, MiriMemoryKind::C)?; } "realloc" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref old_ptr, ref new_size] = check_arg_count(args)?; let old_ptr = this.read_scalar(old_ptr)?.check_init()?; let new_size = this.read_scalar(new_size)?.to_machine_usize(this)?; @@ -358,7 +358,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // (Usually these would be forwarded to to `#[global_allocator]`; we instead implement a generic // allocation that also checks that all conditions are met, such as not permitting zero-sized allocations.) "__rust_alloc" => { - check_abi(this, abi, Abi::Rust)?; + this.check_abi(abi, Abi::Rust)?; let &[ref size, ref align] = check_arg_count(args)?; let size = this.read_scalar(size)?.to_machine_usize(this)?; let align = this.read_scalar(align)?.to_machine_usize(this)?; @@ -371,7 +371,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(ptr, dest)?; } "__rust_alloc_zeroed" => { - check_abi(this, abi, Abi::Rust)?; + this.check_abi(abi, Abi::Rust)?; let &[ref size, ref align] = check_arg_count(args)?; let size = this.read_scalar(size)?.to_machine_usize(this)?; let align = this.read_scalar(align)?.to_machine_usize(this)?; @@ -386,7 +386,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(ptr, dest)?; } "__rust_dealloc" => { - check_abi(this, abi, Abi::Rust)?; + this.check_abi(abi, Abi::Rust)?; let &[ref ptr, ref old_size, ref align] = check_arg_count(args)?; let ptr = this.read_scalar(ptr)?.check_init()?; let old_size = this.read_scalar(old_size)?.to_machine_usize(this)?; @@ -400,7 +400,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx )?; } "__rust_realloc" => { - check_abi(this, abi, Abi::Rust)?; + this.check_abi(abi, Abi::Rust)?; let &[ref ptr, ref old_size, ref align, ref new_size] = check_arg_count(args)?; let ptr = this.force_ptr(this.read_scalar(ptr)?.check_init()?)?; let old_size = this.read_scalar(old_size)?.to_machine_usize(this)?; @@ -421,7 +421,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // C memory handling functions "memcmp" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref left, ref right, ref n] = check_arg_count(args)?; let left = this.read_scalar(left)?.check_init()?; let right = this.read_scalar(right)?.check_init()?; @@ -442,7 +442,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_i32(result), dest)?; } "memrchr" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref ptr, ref val, ref num] = check_arg_count(args)?; let ptr = this.read_scalar(ptr)?.check_init()?; let val = this.read_scalar(val)?.to_i32()? as u8; @@ -461,7 +461,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } "memchr" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref ptr, ref val, ref num] = check_arg_count(args)?; let ptr = this.read_scalar(ptr)?.check_init()?; let val = this.read_scalar(val)?.to_i32()? as u8; @@ -479,7 +479,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } "strlen" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref ptr] = check_arg_count(args)?; let ptr = this.read_scalar(ptr)?.check_init()?; let n = this.read_c_str(ptr)?.len(); @@ -496,7 +496,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "asinf" | "atanf" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref f] = check_arg_count(args)?; // FIXME: Using host floats. let f = f32::from_bits(this.read_scalar(f)?.to_u32()?); @@ -517,7 +517,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "hypotf" | "atan2f" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref f1, ref f2] = check_arg_count(args)?; // underscore case for windows, here and below // (see https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/floating-point-primitives?view=vs-2019) @@ -540,7 +540,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "asin" | "atan" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref f] = check_arg_count(args)?; // FIXME: Using host floats. let f = f64::from_bits(this.read_scalar(f)?.to_u64()?); @@ -561,7 +561,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "hypot" | "atan2" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref f1, ref f2] = check_arg_count(args)?; // FIXME: Using host floats. let f1 = f64::from_bits(this.read_scalar(f1)?.to_u64()?); @@ -578,7 +578,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "ldexp" | "scalbn" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref x, ref exp] = check_arg_count(args)?; // For radix-2 (binary) systems, `ldexp` and `scalbn` are the same. let x = this.read_scalar(x)?.to_f64()?; @@ -600,12 +600,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Architecture-specific shims "llvm.x86.sse2.pause" if this.tcx.sess.target.arch == "x86" || this.tcx.sess.target.arch == "x86_64" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[] = check_arg_count(args)?; this.yield_active_thread(); } "llvm.aarch64.isb" if this.tcx.sess.target.arch == "aarch64" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref arg] = check_arg_count(args)?; let arg = this.read_scalar(arg)?.to_i32()?; match arg { diff --git a/src/shims/posix/dlsym.rs b/src/shims/posix/dlsym.rs index 5f420ac5363bb..b07bf91a69a54 100644 --- a/src/shims/posix/dlsym.rs +++ b/src/shims/posix/dlsym.rs @@ -2,7 +2,6 @@ use rustc_middle::mir; use rustc_target::spec::abi::Abi; use crate::*; -use helpers::check_abi; use shims::posix::linux::dlsym as linux; use shims::posix::macos::dlsym as macos; @@ -35,7 +34,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; match dlsym { Dlsym::Linux(dlsym) => linux::EvalContextExt::call_dlsym(this, dlsym, args, ret), diff --git a/src/shims/posix/foreign_items.rs b/src/shims/posix/foreign_items.rs index f153098cac85f..a756256aab419 100644 --- a/src/shims/posix/foreign_items.rs +++ b/src/shims/posix/foreign_items.rs @@ -5,7 +5,7 @@ use rustc_target::abi::{Align, LayoutOf, Size}; use rustc_target::spec::abi::Abi; use crate::*; -use helpers::{check_abi, check_arg_count}; +use helpers::check_arg_count; use shims::foreign_items::EmulateByNameResult; use shims::posix::fs::EvalContextExt as _; use shims::posix::sync::EvalContextExt as _; @@ -26,32 +26,32 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx match link_name { // Environment related shims "getenv" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref name] = check_arg_count(args)?; let result = this.getenv(name)?; this.write_scalar(result, dest)?; } "unsetenv" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref name] = check_arg_count(args)?; let result = this.unsetenv(name)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "setenv" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref name, ref value, ref overwrite] = check_arg_count(args)?; this.read_scalar(overwrite)?.to_i32()?; let result = this.setenv(name, value)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "getcwd" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref buf, ref size] = check_arg_count(args)?; let result = this.getcwd(buf, size)?; this.write_scalar(result, dest)?; } "chdir" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref path] = check_arg_count(args)?; let result = this.chdir(path)?; this.write_scalar(Scalar::from_i32(result), dest)?; @@ -59,18 +59,18 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // File related shims "open" | "open64" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref path, ref flag, ref mode] = check_arg_count(args)?; let result = this.open(path, flag, mode)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "fcntl" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let result = this.fcntl(args)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "read" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref fd, ref buf, ref count] = check_arg_count(args)?; let fd = this.read_scalar(fd)?.to_i32()?; let buf = this.read_scalar(buf)?.check_init()?; @@ -79,7 +79,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_machine_isize(result, this), dest)?; } "write" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref fd, ref buf, ref n] = check_arg_count(args)?; let fd = this.read_scalar(fd)?.to_i32()?; let buf = this.read_scalar(buf)?.check_init()?; @@ -90,62 +90,62 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_machine_isize(result, this), dest)?; } "unlink" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref path] = check_arg_count(args)?; let result = this.unlink(path)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "symlink" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref target, ref linkpath] = check_arg_count(args)?; let result = this.symlink(target, linkpath)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "rename" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref oldpath, ref newpath] = check_arg_count(args)?; let result = this.rename(oldpath, newpath)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "mkdir" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref path, ref mode] = check_arg_count(args)?; let result = this.mkdir(path, mode)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "rmdir" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref path] = check_arg_count(args)?; let result = this.rmdir(path)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "closedir" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref dirp] = check_arg_count(args)?; let result = this.closedir(dirp)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "lseek" | "lseek64" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref fd, ref offset, ref whence] = check_arg_count(args)?; let result = this.lseek64(fd, offset, whence)?; // "lseek" is only used on macOS which is 64bit-only, so `i64` always works. this.write_scalar(Scalar::from_i64(result), dest)?; } "fsync" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref fd] = check_arg_count(args)?; let result = this.fsync(fd)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "fdatasync" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref fd] = check_arg_count(args)?; let result = this.fdatasync(fd)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "readlink" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref pathname, ref buf, ref bufsize] = check_arg_count(args)?; let result = this.readlink(pathname, buf, bufsize)?; this.write_scalar(Scalar::from_machine_isize(result, this), dest)?; @@ -153,7 +153,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Allocation "posix_memalign" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref ret, ref align, ref size] = check_arg_count(args)?; let ret = this.deref_operand(ret)?; let align = this.read_scalar(align)?.to_machine_usize(this)?; @@ -184,7 +184,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Dynamic symbol loading "dlsym" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref handle, ref symbol] = check_arg_count(args)?; this.read_scalar(handle)?.to_machine_usize(this)?; let symbol = this.read_scalar(symbol)?.check_init()?; @@ -199,7 +199,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Querying system information "sysconf" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref name] = check_arg_count(args)?; let name = this.read_scalar(name)?.to_i32()?; @@ -225,7 +225,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Thread-local storage "pthread_key_create" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref key, ref dtor] = check_arg_count(args)?; let key_place = this.deref_operand(key)?; let dtor = this.read_scalar(dtor)?.check_init()?; @@ -254,7 +254,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_null(dest)?; } "pthread_key_delete" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref key] = check_arg_count(args)?; let key = this.force_bits(this.read_scalar(key)?.check_init()?, key.layout.size)?; this.machine.tls.delete_tls_key(key)?; @@ -262,7 +262,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_null(dest)?; } "pthread_getspecific" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref key] = check_arg_count(args)?; let key = this.force_bits(this.read_scalar(key)?.check_init()?, key.layout.size)?; let active_thread = this.get_active_thread(); @@ -270,7 +270,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(ptr, dest)?; } "pthread_setspecific" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref key, ref new_ptr] = check_arg_count(args)?; let key = this.force_bits(this.read_scalar(key)?.check_init()?, key.layout.size)?; let active_thread = this.get_active_thread(); @@ -283,132 +283,132 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Synchronization primitives "pthread_mutexattr_init" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref attr] = check_arg_count(args)?; let result = this.pthread_mutexattr_init(attr)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_mutexattr_settype" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref attr, ref kind] = check_arg_count(args)?; let result = this.pthread_mutexattr_settype(attr, kind)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_mutexattr_destroy" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref attr] = check_arg_count(args)?; let result = this.pthread_mutexattr_destroy(attr)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_mutex_init" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref mutex, ref attr] = check_arg_count(args)?; let result = this.pthread_mutex_init(mutex, attr)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_mutex_lock" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref mutex] = check_arg_count(args)?; let result = this.pthread_mutex_lock(mutex)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_mutex_trylock" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref mutex] = check_arg_count(args)?; let result = this.pthread_mutex_trylock(mutex)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_mutex_unlock" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref mutex] = check_arg_count(args)?; let result = this.pthread_mutex_unlock(mutex)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_mutex_destroy" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref mutex] = check_arg_count(args)?; let result = this.pthread_mutex_destroy(mutex)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_rwlock_rdlock" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref rwlock] = check_arg_count(args)?; let result = this.pthread_rwlock_rdlock(rwlock)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_rwlock_tryrdlock" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref rwlock] = check_arg_count(args)?; let result = this.pthread_rwlock_tryrdlock(rwlock)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_rwlock_wrlock" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref rwlock] = check_arg_count(args)?; let result = this.pthread_rwlock_wrlock(rwlock)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_rwlock_trywrlock" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref rwlock] = check_arg_count(args)?; let result = this.pthread_rwlock_trywrlock(rwlock)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_rwlock_unlock" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref rwlock] = check_arg_count(args)?; let result = this.pthread_rwlock_unlock(rwlock)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_rwlock_destroy" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref rwlock] = check_arg_count(args)?; let result = this.pthread_rwlock_destroy(rwlock)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_condattr_init" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref attr] = check_arg_count(args)?; let result = this.pthread_condattr_init(attr)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_condattr_destroy" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref attr] = check_arg_count(args)?; let result = this.pthread_condattr_destroy(attr)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_cond_init" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref cond, ref attr] = check_arg_count(args)?; let result = this.pthread_cond_init(cond, attr)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_cond_signal" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref cond] = check_arg_count(args)?; let result = this.pthread_cond_signal(cond)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_cond_broadcast" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref cond] = check_arg_count(args)?; let result = this.pthread_cond_broadcast(cond)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_cond_wait" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref cond, ref mutex] = check_arg_count(args)?; let result = this.pthread_cond_wait(cond, mutex)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_cond_timedwait" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref cond, ref mutex, ref abstime] = check_arg_count(args)?; this.pthread_cond_timedwait(cond, mutex, abstime, dest)?; } "pthread_cond_destroy" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref cond] = check_arg_count(args)?; let result = this.pthread_cond_destroy(cond)?; this.write_scalar(Scalar::from_i32(result), dest)?; @@ -416,36 +416,36 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Threading "pthread_create" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref thread, ref attr, ref start, ref arg] = check_arg_count(args)?; let result = this.pthread_create(thread, attr, start, arg)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_join" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref thread, ref retval] = check_arg_count(args)?; let result = this.pthread_join(thread, retval)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_detach" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref thread] = check_arg_count(args)?; let result = this.pthread_detach(thread)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_self" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[] = check_arg_count(args)?; this.pthread_self(dest)?; } "sched_yield" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[] = check_arg_count(args)?; let result = this.sched_yield()?; this.write_scalar(Scalar::from_i32(result), dest)?; } "nanosleep" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref req, ref rem] = check_arg_count(args)?; let result = this.nanosleep(req, rem)?; this.write_scalar(Scalar::from_i32(result), dest)?; @@ -453,7 +453,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Miscellaneous "isatty" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref fd] = check_arg_count(args)?; this.read_scalar(fd)?.to_i32()?; // "returns 1 if fd is an open file descriptor referring to a terminal; otherwise 0 is returned, and errno is set to indicate the error" @@ -463,7 +463,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_null(dest)?; } "pthread_atfork" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref prepare, ref parent, ref child] = check_arg_count(args)?; this.force_bits(this.read_scalar(prepare)?.check_init()?, this.memory.pointer_size())?; this.force_bits(this.read_scalar(parent)?.check_init()?, this.memory.pointer_size())?; @@ -476,7 +476,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // These shims are enabled only when the caller is in the standard library. "pthread_attr_getguardsize" if this.frame().instance.to_string().starts_with("std::sys::unix::") => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref _attr, ref guard_size] = check_arg_count(args)?; let guard_size = this.deref_operand(guard_size)?; let guard_size_layout = this.libc_ty_layout("size_t")?; @@ -489,13 +489,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "pthread_attr_init" | "pthread_attr_destroy" if this.frame().instance.to_string().starts_with("std::sys::unix::") => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[_] = check_arg_count(args)?; this.write_null(dest)?; } | "pthread_attr_setstacksize" if this.frame().instance.to_string().starts_with("std::sys::unix::") => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[_, _] = check_arg_count(args)?; this.write_null(dest)?; } @@ -503,14 +503,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "signal" | "sigaltstack" if this.frame().instance.to_string().starts_with("std::sys::unix::") => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[_, _] = check_arg_count(args)?; this.write_null(dest)?; } | "sigaction" | "mprotect" if this.frame().instance.to_string().starts_with("std::sys::unix::") => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[_, _, _] = check_arg_count(args)?; this.write_null(dest)?; } diff --git a/src/shims/posix/linux/foreign_items.rs b/src/shims/posix/linux/foreign_items.rs index 47ffad56d1222..598d89fe1f343 100644 --- a/src/shims/posix/linux/foreign_items.rs +++ b/src/shims/posix/linux/foreign_items.rs @@ -1,7 +1,7 @@ use rustc_middle::mir; use rustc_target::spec::abi::Abi; -use crate::helpers::{check_abi, check_arg_count}; +use crate::helpers::check_arg_count; use crate::*; use shims::foreign_items::EmulateByNameResult; use shims::posix::fs::EvalContextExt as _; @@ -24,7 +24,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx match link_name { // errno "__errno_location" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[] = check_arg_count(args)?; let errno_place = this.last_error_place()?; this.write_scalar(errno_place.to_ref().to_scalar()?, dest)?; @@ -34,32 +34,32 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // These symbols have different names on Linux and macOS, which is the only reason they are not // in the `posix` module. "close" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref fd] = check_arg_count(args)?; let result = this.close(fd)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "opendir" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref name] = check_arg_count(args)?; let result = this.opendir(name)?; this.write_scalar(result, dest)?; } "readdir64_r" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref dirp, ref entry, ref result] = check_arg_count(args)?; let result = this.linux_readdir64_r(dirp, entry, result)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "ftruncate64" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref fd, ref length] = check_arg_count(args)?; let result = this.ftruncate64(fd, length)?; this.write_scalar(Scalar::from_i32(result), dest)?; } // Linux-only "posix_fadvise" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref fd, ref offset, ref len, ref advice] = check_arg_count(args)?; this.read_scalar(fd)?.to_i32()?; this.read_scalar(offset)?.to_machine_isize(this)?; @@ -69,7 +69,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_null(dest)?; } "sync_file_range" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref fd, ref offset, ref nbytes, ref flags] = check_arg_count(args)?; let result = this.sync_file_range(fd, offset, nbytes, flags)?; this.write_scalar(Scalar::from_i32(result), dest)?; @@ -77,7 +77,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Time related shims "clock_gettime" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; // This is a POSIX function but it has only been tested on linux. let &[ref clk_id, ref tp] = check_arg_count(args)?; let result = this.clock_gettime(clk_id, tp)?; @@ -86,7 +86,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Querying system information "pthread_attr_getstack" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; // We don't support "pthread_attr_setstack", so we just pretend all stacks have the same values here. let &[ref attr_place, ref addr_place, ref size_place] = check_arg_count(args)?; this.deref_operand(attr_place)?; @@ -108,19 +108,19 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Threading "prctl" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref option, ref arg2, ref arg3, ref arg4, ref arg5] = check_arg_count(args)?; let result = this.prctl(option, arg2, arg3, arg4, arg5)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_condattr_setclock" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref attr, ref clock_id] = check_arg_count(args)?; let result = this.pthread_condattr_setclock(attr, clock_id)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_condattr_getclock" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref attr, ref clock_id] = check_arg_count(args)?; let result = this.pthread_condattr_getclock(attr, clock_id)?; this.write_scalar(Scalar::from_i32(result), dest)?; @@ -128,7 +128,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Dynamically invoked syscalls "syscall" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; // The syscall variadic function is legal to call with more arguments than needed, // extra arguments are simply ignored. However, all arguments need to be scalars; // other types might be treated differently by the calling convention. @@ -189,12 +189,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Miscelanneous "getrandom" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref ptr, ref len, ref flags] = check_arg_count(args)?; getrandom(this, ptr, len, flags, dest)?; } "sched_getaffinity" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref pid, ref cpusetsize, ref mask] = check_arg_count(args)?; this.read_scalar(pid)?.to_i32()?; this.read_scalar(cpusetsize)?.to_machine_usize(this)?; @@ -210,7 +210,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "pthread_getattr_np" if this.frame().instance.to_string().starts_with("std::sys::unix::") => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref _thread, ref _attr] = check_arg_count(args)?; this.write_null(dest)?; } diff --git a/src/shims/posix/macos/foreign_items.rs b/src/shims/posix/macos/foreign_items.rs index 15a073dd04ef5..d54e1bfbe8195 100644 --- a/src/shims/posix/macos/foreign_items.rs +++ b/src/shims/posix/macos/foreign_items.rs @@ -2,7 +2,7 @@ use rustc_middle::mir; use rustc_target::spec::abi::Abi; use crate::*; -use helpers::{check_abi, check_arg_count}; +use helpers::check_arg_count; use shims::foreign_items::EmulateByNameResult; use shims::posix::fs::EvalContextExt as _; use shims::posix::thread::EvalContextExt as _; @@ -22,7 +22,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx match link_name { // errno "__error" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[] = check_arg_count(args)?; let errno_place = this.last_error_place()?; this.write_scalar(errno_place.to_ref().to_scalar()?, dest)?; @@ -30,43 +30,43 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // File related shims "close" | "close$NOCANCEL" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref result] = check_arg_count(args)?; let result = this.close(result)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "stat" | "stat$INODE64" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref path, ref buf] = check_arg_count(args)?; let result = this.macos_stat(path, buf)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "lstat" | "lstat$INODE64" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref path, ref buf] = check_arg_count(args)?; let result = this.macos_lstat(path, buf)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "fstat" | "fstat$INODE64" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref fd, ref buf] = check_arg_count(args)?; let result = this.macos_fstat(fd, buf)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "opendir" | "opendir$INODE64" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref name] = check_arg_count(args)?; let result = this.opendir(name)?; this.write_scalar(result, dest)?; } "readdir_r" | "readdir_r$INODE64" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref dirp, ref entry, ref result] = check_arg_count(args)?; let result = this.macos_readdir_r(dirp, entry, result)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "ftruncate" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref fd, ref length] = check_arg_count(args)?; let result = this.ftruncate64(fd, length)?; this.write_scalar(Scalar::from_i32(result), dest)?; @@ -74,27 +74,27 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Environment related shims "_NSGetEnviron" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[] = check_arg_count(args)?; this.write_scalar(this.machine.env_vars.environ.unwrap().ptr, dest)?; } // Time related shims "gettimeofday" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref tv, ref tz] = check_arg_count(args)?; let result = this.gettimeofday(tv, tz)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "mach_absolute_time" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[] = check_arg_count(args)?; let result = this.mach_absolute_time()?; this.write_scalar(Scalar::from_u64(result), dest)?; } "mach_timebase_info" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref info] = check_arg_count(args)?; let result = this.mach_timebase_info(info)?; this.write_scalar(Scalar::from_i32(result), dest)?; @@ -102,19 +102,19 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Access to command-line arguments "_NSGetArgc" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[] = check_arg_count(args)?; this.write_scalar(this.machine.argc.expect("machine must be initialized"), dest)?; } "_NSGetArgv" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[] = check_arg_count(args)?; this.write_scalar(this.machine.argv.expect("machine must be initialized"), dest)?; } // Thread-local storage "_tlv_atexit" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref dtor, ref data] = check_arg_count(args)?; let dtor = this.read_scalar(dtor)?.check_init()?; let dtor = this.memory.get_fn(dtor)?.as_instance()?; @@ -125,14 +125,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Querying system information "pthread_get_stackaddr_np" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref thread] = check_arg_count(args)?; this.read_scalar(thread)?.to_machine_usize(this)?; let stack_addr = Scalar::from_uint(STACK_ADDR, this.pointer_size()); this.write_scalar(stack_addr, dest)?; } "pthread_get_stacksize_np" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref thread] = check_arg_count(args)?; this.read_scalar(thread)?.to_machine_usize(this)?; let stack_size = Scalar::from_uint(STACK_SIZE, this.pointer_size()); @@ -141,7 +141,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Threading "pthread_setname_np" => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; let &[ref name] = check_arg_count(args)?; let name = this.read_scalar(name)?.check_init()?; this.pthread_setname_np(name)?; @@ -150,7 +150,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Incomplete shims that we "stub out" just to get pre-main initialization code to work. // These shims are enabled only when the caller is in the standard library. "mmap" if this.frame().instance.to_string().starts_with("std::sys::unix::") => { - check_abi(this, abi, Abi::C { unwind: false })?; + this.check_abi(abi, Abi::C { unwind: false })?; // This is a horrible hack, but since the guard page mechanism calls mmap and expects a particular return value, we just give it that value. let &[ref addr, _, _, _, _, _] = check_arg_count(args)?; let addr = this.read_scalar(addr)?.check_init()?; diff --git a/src/shims/windows/dlsym.rs b/src/shims/windows/dlsym.rs index 18e2ed3db59b5..325100bdb3a7d 100644 --- a/src/shims/windows/dlsym.rs +++ b/src/shims/windows/dlsym.rs @@ -2,7 +2,6 @@ use rustc_middle::mir; use rustc_target::spec::abi::Abi; use crate::*; -use helpers::check_abi; #[derive(Debug, Copy, Clone)] pub enum Dlsym {} @@ -31,7 +30,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let (_dest, _ret) = ret.expect("we don't support any diverging dlsym"); assert!(this.tcx.sess.target.os == "windows"); - check_abi(this, abi, Abi::System { unwind: false })?; + this.check_abi(abi, Abi::System { unwind: false })?; match dlsym {} } diff --git a/src/shims/windows/foreign_items.rs b/src/shims/windows/foreign_items.rs index 0f9e3899b85af..3c7451352dfd2 100644 --- a/src/shims/windows/foreign_items.rs +++ b/src/shims/windows/foreign_items.rs @@ -5,7 +5,7 @@ use rustc_target::abi::Size; use rustc_target::spec::abi::Abi; use crate::*; -use helpers::{check_abi, check_arg_count}; +use helpers::check_arg_count; use shims::foreign_items::EmulateByNameResult; use shims::windows::sync::EvalContextExt as _; @@ -29,37 +29,37 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx match link_name { // Environment related shims "GetEnvironmentVariableW" => { - check_abi(this, abi, Abi::System { unwind: false })?; + this.check_abi(abi, Abi::System { unwind: false })?; let &[ref name, ref buf, ref size] = check_arg_count(args)?; let result = this.GetEnvironmentVariableW(name, buf, size)?; this.write_scalar(Scalar::from_u32(result), dest)?; } "SetEnvironmentVariableW" => { - check_abi(this, abi, Abi::System { unwind: false })?; + this.check_abi(abi, Abi::System { unwind: false })?; let &[ref name, ref value] = check_arg_count(args)?; let result = this.SetEnvironmentVariableW(name, value)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "GetEnvironmentStringsW" => { - check_abi(this, abi, Abi::System { unwind: false })?; + this.check_abi(abi, Abi::System { unwind: false })?; let &[] = check_arg_count(args)?; let result = this.GetEnvironmentStringsW()?; this.write_scalar(result, dest)?; } "FreeEnvironmentStringsW" => { - check_abi(this, abi, Abi::System { unwind: false })?; + this.check_abi(abi, Abi::System { unwind: false })?; let &[ref env_block] = check_arg_count(args)?; let result = this.FreeEnvironmentStringsW(env_block)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "GetCurrentDirectoryW" => { - check_abi(this, abi, Abi::System { unwind: false })?; + this.check_abi(abi, Abi::System { unwind: false })?; let &[ref size, ref buf] = check_arg_count(args)?; let result = this.GetCurrentDirectoryW(size, buf)?; this.write_scalar(Scalar::from_u32(result), dest)?; } "SetCurrentDirectoryW" => { - check_abi(this, abi, Abi::System { unwind: false })?; + this.check_abi(abi, Abi::System { unwind: false })?; let &[ref path] = check_arg_count(args)?; let result = this.SetCurrentDirectoryW(path)?; this.write_scalar(Scalar::from_i32(result), dest)?; @@ -67,7 +67,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // File related shims "GetStdHandle" => { - check_abi(this, abi, Abi::System { unwind: false })?; + this.check_abi(abi, Abi::System { unwind: false })?; let &[ref which] = check_arg_count(args)?; let which = this.read_scalar(which)?.to_i32()?; // We just make this the identity function, so we know later in `WriteFile` @@ -75,7 +75,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_machine_isize(which.into(), this), dest)?; } "WriteFile" => { - check_abi(this, abi, Abi::System { unwind: false })?; + this.check_abi(abi, Abi::System { unwind: false })?; let &[ref handle, ref buf, ref n, ref written_ptr, ref overlapped] = check_arg_count(args)?; this.read_scalar(overlapped)?.to_machine_usize(this)?; // this is a poiner, that we ignore @@ -111,7 +111,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Allocation "HeapAlloc" => { - check_abi(this, abi, Abi::System { unwind: false })?; + this.check_abi(abi, Abi::System { unwind: false })?; let &[ref handle, ref flags, ref size] = check_arg_count(args)?; this.read_scalar(handle)?.to_machine_isize(this)?; let flags = this.read_scalar(flags)?.to_u32()?; @@ -121,7 +121,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(res, dest)?; } "HeapFree" => { - check_abi(this, abi, Abi::System { unwind: false })?; + this.check_abi(abi, Abi::System { unwind: false })?; let &[ref handle, ref flags, ref ptr] = check_arg_count(args)?; this.read_scalar(handle)?.to_machine_isize(this)?; this.read_scalar(flags)?.to_u32()?; @@ -130,7 +130,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_i32(1), dest)?; } "HeapReAlloc" => { - check_abi(this, abi, Abi::System { unwind: false })?; + this.check_abi(abi, Abi::System { unwind: false })?; let &[ref handle, ref flags, ref ptr, ref size] = check_arg_count(args)?; this.read_scalar(handle)?.to_machine_isize(this)?; this.read_scalar(flags)?.to_u32()?; @@ -142,13 +142,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // errno "SetLastError" => { - check_abi(this, abi, Abi::System { unwind: false })?; + this.check_abi(abi, Abi::System { unwind: false })?; let &[ref error] = check_arg_count(args)?; let error = this.read_scalar(error)?.check_init()?; this.set_last_error(error)?; } "GetLastError" => { - check_abi(this, abi, Abi::System { unwind: false })?; + this.check_abi(abi, Abi::System { unwind: false })?; let &[] = check_arg_count(args)?; let last_error = this.get_last_error()?; this.write_scalar(last_error, dest)?; @@ -156,7 +156,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Querying system information "GetSystemInfo" => { - check_abi(this, abi, Abi::System { unwind: false })?; + this.check_abi(abi, Abi::System { unwind: false })?; let &[ref system_info] = check_arg_count(args)?; let system_info = this.deref_operand(system_info)?; // Initialize with `0`. @@ -172,7 +172,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Thread-local storage "TlsAlloc" => { - check_abi(this, abi, Abi::System { unwind: false })?; + this.check_abi(abi, Abi::System { unwind: false })?; // This just creates a key; Windows does not natively support TLS destructors. // Create key and return it. @@ -181,7 +181,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_uint(key, dest.layout.size), dest)?; } "TlsGetValue" => { - check_abi(this, abi, Abi::System { unwind: false })?; + this.check_abi(abi, Abi::System { unwind: false })?; let &[ref key] = check_arg_count(args)?; let key = u128::from(this.read_scalar(key)?.to_u32()?); let active_thread = this.get_active_thread(); @@ -189,7 +189,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(ptr, dest)?; } "TlsSetValue" => { - check_abi(this, abi, Abi::System { unwind: false })?; + this.check_abi(abi, Abi::System { unwind: false })?; let &[ref key, ref new_ptr] = check_arg_count(args)?; let key = u128::from(this.read_scalar(key)?.to_u32()?); let active_thread = this.get_active_thread(); @@ -202,7 +202,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Access to command-line arguments "GetCommandLineW" => { - check_abi(this, abi, Abi::System { unwind: false })?; + this.check_abi(abi, Abi::System { unwind: false })?; let &[] = check_arg_count(args)?; this.write_scalar( this.machine.cmd_line.expect("machine must be initialized"), @@ -212,20 +212,20 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Time related shims "GetSystemTimeAsFileTime" => { - check_abi(this, abi, Abi::System { unwind: false })?; + this.check_abi(abi, Abi::System { unwind: false })?; #[allow(non_snake_case)] let &[ref LPFILETIME] = check_arg_count(args)?; this.GetSystemTimeAsFileTime(LPFILETIME)?; } "QueryPerformanceCounter" => { - check_abi(this, abi, Abi::System { unwind: false })?; + this.check_abi(abi, Abi::System { unwind: false })?; #[allow(non_snake_case)] let &[ref lpPerformanceCount] = check_arg_count(args)?; let result = this.QueryPerformanceCounter(lpPerformanceCount)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "QueryPerformanceFrequency" => { - check_abi(this, abi, Abi::System { unwind: false })?; + this.check_abi(abi, Abi::System { unwind: false })?; #[allow(non_snake_case)] let &[ref lpFrequency] = check_arg_count(args)?; let result = this.QueryPerformanceFrequency(lpFrequency)?; @@ -234,33 +234,33 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Synchronization primitives "AcquireSRWLockExclusive" => { - check_abi(this, abi, Abi::System { unwind: false })?; + this.check_abi(abi, Abi::System { unwind: false })?; let &[ref ptr] = check_arg_count(args)?; this.AcquireSRWLockExclusive(ptr)?; } "ReleaseSRWLockExclusive" => { - check_abi(this, abi, Abi::System { unwind: false })?; + this.check_abi(abi, Abi::System { unwind: false })?; let &[ref ptr] = check_arg_count(args)?; this.ReleaseSRWLockExclusive(ptr)?; } "TryAcquireSRWLockExclusive" => { - check_abi(this, abi, Abi::System { unwind: false })?; + this.check_abi(abi, Abi::System { unwind: false })?; let &[ref ptr] = check_arg_count(args)?; let ret = this.TryAcquireSRWLockExclusive(ptr)?; this.write_scalar(Scalar::from_u8(ret), dest)?; } "AcquireSRWLockShared" => { - check_abi(this, abi, Abi::System { unwind: false })?; + this.check_abi(abi, Abi::System { unwind: false })?; let &[ref ptr] = check_arg_count(args)?; this.AcquireSRWLockShared(ptr)?; } "ReleaseSRWLockShared" => { - check_abi(this, abi, Abi::System { unwind: false })?; + this.check_abi(abi, Abi::System { unwind: false })?; let &[ref ptr] = check_arg_count(args)?; this.ReleaseSRWLockShared(ptr)?; } "TryAcquireSRWLockShared" => { - check_abi(this, abi, Abi::System { unwind: false })?; + this.check_abi(abi, Abi::System { unwind: false })?; let &[ref ptr] = check_arg_count(args)?; let ret = this.TryAcquireSRWLockShared(ptr)?; this.write_scalar(Scalar::from_u8(ret), dest)?; @@ -268,7 +268,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Dynamic symbol loading "GetProcAddress" => { - check_abi(this, abi, Abi::System { unwind: false })?; + this.check_abi(abi, Abi::System { unwind: false })?; #[allow(non_snake_case)] let &[ref hModule, ref lpProcName] = check_arg_count(args)?; this.read_scalar(hModule)?.to_machine_isize(this)?; @@ -284,7 +284,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Miscellaneous "SystemFunction036" => { // This is really 'RtlGenRandom'. - check_abi(this, abi, Abi::System { unwind: false })?; + this.check_abi(abi, Abi::System { unwind: false })?; let &[ref ptr, ref len] = check_arg_count(args)?; let ptr = this.read_scalar(ptr)?.check_init()?; let len = this.read_scalar(len)?.to_u32()?; @@ -292,7 +292,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_bool(true), dest)?; } "BCryptGenRandom" => { - check_abi(this, abi, Abi::System { unwind: false })?; + this.check_abi(abi, Abi::System { unwind: false })?; let &[ref algorithm, ref ptr, ref len, ref flags] = check_arg_count(args)?; let algorithm = this.read_scalar(algorithm)?; let ptr = this.read_scalar(ptr)?.check_init()?; @@ -313,7 +313,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_null(dest)?; // STATUS_SUCCESS } "GetConsoleScreenBufferInfo" => { - check_abi(this, abi, Abi::System { unwind: false })?; + this.check_abi(abi, Abi::System { unwind: false })?; // `term` needs this, so we fake it. let &[ref console, ref buffer_info] = check_arg_count(args)?; this.read_scalar(console)?.to_machine_isize(this)?; @@ -323,7 +323,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_null(dest)?; } "GetConsoleMode" => { - check_abi(this, abi, Abi::System { unwind: false })?; + this.check_abi(abi, Abi::System { unwind: false })?; // Windows "isatty" (in libtest) needs this, so we fake it. let &[ref console, ref mode] = check_arg_count(args)?; this.read_scalar(console)?.to_machine_isize(this)?; @@ -333,7 +333,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_null(dest)?; } "SwitchToThread" => { - check_abi(this, abi, Abi::System { unwind: false })?; + this.check_abi(abi, Abi::System { unwind: false })?; let &[] = check_arg_count(args)?; // Note that once Miri supports concurrency, this will need to return a nonzero // value if this call does result in switching to another thread. @@ -342,7 +342,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Better error for attempts to create a thread "CreateThread" => { - check_abi(this, abi, Abi::System { unwind: false })?; + this.check_abi(abi, Abi::System { unwind: false })?; throw_unsup_format!("Miri does not support concurrency on Windows"); } @@ -351,7 +351,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "GetProcessHeap" if this.frame().instance.to_string().starts_with("std::sys::windows::") => { - check_abi(this, abi, Abi::System { unwind: false })?; + this.check_abi(abi, Abi::System { unwind: false })?; let &[] = check_arg_count(args)?; // Just fake a HANDLE this.write_scalar(Scalar::from_machine_isize(1, this), dest)?; @@ -359,7 +359,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "SetConsoleTextAttribute" if this.frame().instance.to_string().starts_with("std::sys::windows::") => { - check_abi(this, abi, Abi::System { unwind: false })?; + this.check_abi(abi, Abi::System { unwind: false })?; #[allow(non_snake_case)] let &[ref _hConsoleOutput, ref _wAttribute] = check_arg_count(args)?; // Pretend these does not exist / nothing happened, by returning zero. @@ -368,7 +368,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "AddVectoredExceptionHandler" if this.frame().instance.to_string().starts_with("std::sys::windows::") => { - check_abi(this, abi, Abi::System { unwind: false })?; + this.check_abi(abi, Abi::System { unwind: false })?; #[allow(non_snake_case)] let &[ref _First, ref _Handler] = check_arg_count(args)?; // Any non zero value works for the stdlib. This is just used for stack overflows anyway. @@ -377,7 +377,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "SetThreadStackGuarantee" if this.frame().instance.to_string().starts_with("std::sys::windows::") => { - check_abi(this, abi, Abi::System { unwind: false })?; + this.check_abi(abi, Abi::System { unwind: false })?; #[allow(non_snake_case)] let &[_StackSizeInBytes] = check_arg_count(args)?; // Any non zero value works for the stdlib. This is just used for stack overflows anyway. @@ -389,7 +389,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "DeleteCriticalSection" if this.frame().instance.to_string().starts_with("std::sys::windows::") => { - check_abi(this, abi, Abi::System { unwind: false })?; + this.check_abi(abi, Abi::System { unwind: false })?; #[allow(non_snake_case)] let &[ref _lpCriticalSection] = check_arg_count(args)?; assert_eq!( @@ -404,7 +404,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "TryEnterCriticalSection" if this.frame().instance.to_string().starts_with("std::sys::windows::") => { - check_abi(this, abi, Abi::System { unwind: false })?; + this.check_abi(abi, Abi::System { unwind: false })?; #[allow(non_snake_case)] let &[ref _lpCriticalSection] = check_arg_count(args)?; assert_eq!( From b054a19f9448c7a916b361b19d708c64df980edd Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Sun, 30 May 2021 20:49:44 +0800 Subject: [PATCH 2694/3747] We don't need to check `SymbolExportLevel` --- src/shims/foreign_items.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 70de55c5be757..27f4bafdb0cb1 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -154,8 +154,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx |(num, &linkage)| (linkage != Linkage::NotLinked).then_some(CrateNum::new(num + 1)), )) { - // FIXME: Do we need to check `SymbolExportLevel` (the `_` below)? - for &(symbol, _) in tcx.exported_symbols(cnum) { + // We can ignore `_export_level` here: we are a Rust crate, and everything is exported + // from a Rust crate. + for &(symbol, _export_level) in tcx.exported_symbols(cnum) { if let ExportedSymbol::NonGeneric(def_id) = symbol { let attrs = tcx.codegen_fn_attrs(def_id); let symbol_name = if let Some(export_name) = attrs.export_name { From e026ad584d99c88af335edef96b93d1a0d7a071c Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Sun, 30 May 2021 21:01:40 +0800 Subject: [PATCH 2695/3747] Use `unwrap_or_else()` --- src/shims/foreign_items.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 27f4bafdb0cb1..c838c136c3f41 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -213,11 +213,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, Option<&'mir mir::Body<'tcx>>> { let this = self.eval_context_mut(); let attrs = this.tcx.get_attrs(def_id); - let link_name_sym = match this.tcx.sess.first_attr_value_str_by_name(&attrs, sym::link_name) - { - Some(name) => name, - None => this.tcx.item_name(def_id), - }; + let link_name_sym = this + .tcx + .sess + .first_attr_value_str_by_name(&attrs, sym::link_name) + .unwrap_or_else(|| this.tcx.item_name(def_id)); let link_name = link_name_sym.as_str(); // Strip linker suffixes (seen on 32-bit macOS). let link_name = link_name.trim_end_matches("$UNIX2003"); From 45832d4031df76120bd8b7787c8c715a32b52653 Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Sun, 30 May 2021 21:06:40 +0800 Subject: [PATCH 2696/3747] Remove duplicated "foreign function" --- tests/run-pass/function_calls/exported_symbol_good_unwind.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/run-pass/function_calls/exported_symbol_good_unwind.rs b/tests/run-pass/function_calls/exported_symbol_good_unwind.rs index 73192707f1e47..3dd3b8f22de57 100644 --- a/tests/run-pass/function_calls/exported_symbol_good_unwind.rs +++ b/tests/run-pass/function_calls/exported_symbol_good_unwind.rs @@ -1,6 +1,6 @@ // Make sure the workaround for "crate ... required to be available in rlib format, but was not // found in this form" errors works without `-C prefer-dynamic` (`panic!` calls foreign function -// foreign function `__rust_start_panic`). +// `__rust_start_panic`). // no-prefer-dynamic #![feature(c_unwind, unboxed_closures, unwind_attributes)] From 160bc68cae213dc204037880c529125442557205 Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Mon, 31 May 2021 07:59:51 +0800 Subject: [PATCH 2697/3747] Move the test to `src/main.rs` --- test-cargo-miri/src/lib.rs | 15 --------------- test-cargo-miri/src/main.rs | 16 ++++++++++++++++ test-cargo-miri/test.bin-target.stdout.ref | 5 +++-- test-cargo-miri/test.cross-target.stdout.ref | 6 +++--- test-cargo-miri/test.default.stdout.ref | 17 ++++++++--------- .../test.filter.cross-target.stdout.ref | 2 +- test-cargo-miri/test.filter.stdout.ref | 4 ++-- 7 files changed, 33 insertions(+), 32 deletions(-) diff --git a/test-cargo-miri/src/lib.rs b/test-cargo-miri/src/lib.rs index 6397d072e89ef..6d9158c54ef4d 100644 --- a/test-cargo-miri/src/lib.rs +++ b/test-cargo-miri/src/lib.rs @@ -1,21 +1,6 @@ -extern crate exported_symbol; - /// Doc-test test /// ```rust /// assert!(cargo_miri_test::make_true()); -/// // Repeat calls to make sure the `Instance` cache is not broken. -/// for _ in 0..3 { -/// extern "Rust" { -/// fn exported_symbol() -> i32; -/// fn make_true() -> bool; -/// } -/// assert_eq!(unsafe { exported_symbol() }, 123456); -/// assert!(unsafe { make_true() }); -/// } -/// ``` -/// ```compile_fail -/// // Make sure `exported_symbol_dep` is not a direct dependency for doctests. -/// use exported_symbol_dep; /// ``` /// ```rust,no_run /// assert!(!cargo_miri_test::make_true()); diff --git a/test-cargo-miri/src/main.rs b/test-cargo-miri/src/main.rs index 16b173b287cae..a5669ef3087c5 100644 --- a/test-cargo-miri/src/main.rs +++ b/test-cargo-miri/src/main.rs @@ -57,4 +57,20 @@ mod test { assert_ne!(x as usize, y); assert_ne!(y as u128, z); } + + #[test] + fn exported_symbol() { + extern crate cargo_miri_test; + extern crate exported_symbol; + // Test calling exported symbols in (transitive) dependencies. + // Repeat calls to make sure the `Instance` cache is not broken. + for _ in 0..3 { + extern "Rust" { + fn exported_symbol() -> i32; + fn make_true() -> bool; + } + assert_eq!(unsafe { exported_symbol() }, 123456); + assert!(unsafe { make_true() }); + } + } } diff --git a/test-cargo-miri/test.bin-target.stdout.ref b/test-cargo-miri/test.bin-target.stdout.ref index 4caa30a7f0e50..62cfd1d37a172 100644 --- a/test-cargo-miri/test.bin-target.stdout.ref +++ b/test-cargo-miri/test.bin-target.stdout.ref @@ -1,6 +1,7 @@ -running 1 test +running 2 tests +test test::exported_symbol ... ok test test::rng ... ok -test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out +test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out diff --git a/test-cargo-miri/test.cross-target.stdout.ref b/test-cargo-miri/test.cross-target.stdout.ref index e36abd870663e..aa4a5839b1453 100644 --- a/test-cargo-miri/test.cross-target.stdout.ref +++ b/test-cargo-miri/test.cross-target.stdout.ref @@ -1,7 +1,7 @@ -running 1 test -. -test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out +running 2 tests +.. +test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out imported main diff --git a/test-cargo-miri/test.default.stdout.ref b/test-cargo-miri/test.default.stdout.ref index e97119f217f7a..6c7d284a84ac8 100644 --- a/test-cargo-miri/test.default.stdout.ref +++ b/test-cargo-miri/test.default.stdout.ref @@ -1,7 +1,7 @@ -running 1 test -. -test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out +running 2 tests +.. +test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out imported main @@ -10,11 +10,10 @@ running 7 tests test result: ok. 6 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out -running 4 tests -test src/lib.rs - make_true (line 16) ... ok -test src/lib.rs - make_true (line 20) ... ok -test src/lib.rs - make_true (line 23) ... ok -test src/lib.rs - make_true (line 4) ... ok +running 3 tests +test src/lib.rs - make_true (line 2) ... ok +test src/lib.rs - make_true (line 5) ... ok +test src/lib.rs - make_true (line 8) ... ok -test result: ok. 4 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME +test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME diff --git a/test-cargo-miri/test.filter.cross-target.stdout.ref b/test-cargo-miri/test.filter.cross-target.stdout.ref index fb722c5e71239..b38aac9aa868d 100644 --- a/test-cargo-miri/test.filter.cross-target.stdout.ref +++ b/test-cargo-miri/test.filter.cross-target.stdout.ref @@ -1,7 +1,7 @@ running 0 tests -test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 1 filtered out +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 2 filtered out imported main diff --git a/test-cargo-miri/test.filter.stdout.ref b/test-cargo-miri/test.filter.stdout.ref index 61565a4c1e4a3..6b26e17ff8bb9 100644 --- a/test-cargo-miri/test.filter.stdout.ref +++ b/test-cargo-miri/test.filter.stdout.ref @@ -1,7 +1,7 @@ running 0 tests -test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 1 filtered out +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 2 filtered out imported main @@ -13,5 +13,5 @@ test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 6 filtered out running 0 tests -test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 4 filtered out; finished in $TIME +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 3 filtered out; finished in $TIME From a952787163af999bbbcb4ed6de53a52563c23c28 Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Mon, 31 May 2021 11:05:04 +0800 Subject: [PATCH 2698/3747] Improve tests --- .../function_calls/check_callback_abi.rs | 2 ++ .../exported_symbol_abi_mismatch.rs | 27 ++++++++++------ .../exported_symbol_bad_unwind3.rs | 1 - .../function_calls/exported_symbol.rs | 31 ++++++++++++++++++- 4 files changed, 49 insertions(+), 12 deletions(-) diff --git a/tests/compile-fail/function_calls/check_callback_abi.rs b/tests/compile-fail/function_calls/check_callback_abi.rs index 69dfc03598313..e36bfe1c5783e 100644 --- a/tests/compile-fail/function_calls/check_callback_abi.rs +++ b/tests/compile-fail/function_calls/check_callback_abi.rs @@ -6,6 +6,8 @@ extern "C" fn try_fn(_: *mut u8) { fn main() { unsafe { + // Make sure we check the ABI when Miri itself invokes a function + // as part of a shim implementation. std::intrinsics::r#try( //~ ERROR calling a function with ABI C using caller ABI Rust std::mem::transmute::(try_fn), std::ptr::null_mut(), diff --git a/tests/compile-fail/function_calls/exported_symbol_abi_mismatch.rs b/tests/compile-fail/function_calls/exported_symbol_abi_mismatch.rs index d62cb2e8b7ad9..f92fae5d29355 100644 --- a/tests/compile-fail/function_calls/exported_symbol_abi_mismatch.rs +++ b/tests/compile-fail/function_calls/exported_symbol_abi_mismatch.rs @@ -1,22 +1,29 @@ -// revisions: no_cache cache +// revisions: no_cache cache fn_ptr #[no_mangle] fn foo() {} fn main() { + #[cfg(any(cache, fn_ptr))] + extern "Rust" { + fn foo(); + } + + #[cfg(fn_ptr)] + unsafe { std::mem::transmute::(foo)() } + //[fn_ptr]~^ ERROR calling a function with ABI Rust using caller ABI C + + // `Instance` caching should not suppress ABI check. #[cfg(cache)] + unsafe { foo() } + { - // `Instance` caching should not suppress ABI check. - extern "Rust" { + #[cfg_attr(any(cache, fn_ptr), allow(clashing_extern_declarations))] + extern "C" { fn foo(); } unsafe { foo() } + //[no_cache]~^ ERROR calling a function with ABI Rust using caller ABI C + //[cache]~^^ ERROR calling a function with ABI Rust using caller ABI C } - #[cfg_attr(cache, allow(clashing_extern_declarations))] - extern "C" { - fn foo(); - } - unsafe { foo() } - //[no_cache]~^ ERROR Undefined Behavior: calling a function with ABI Rust using caller ABI C - //[cache]~^^ ERROR Undefined Behavior: calling a function with ABI Rust using caller ABI C } diff --git a/tests/compile-fail/function_calls/exported_symbol_bad_unwind3.rs b/tests/compile-fail/function_calls/exported_symbol_bad_unwind3.rs index dfb378cef5234..bbbe677d3651e 100644 --- a/tests/compile-fail/function_calls/exported_symbol_bad_unwind3.rs +++ b/tests/compile-fail/function_calls/exported_symbol_bad_unwind3.rs @@ -1,5 +1,4 @@ #![feature(unwind_attributes)] -#![feature(c_unwind)] // make sure it doesn't insert abort-on-unwind for the `#[unwind(allowed)]` function #[unwind(allowed)] #[no_mangle] diff --git a/tests/run-pass/function_calls/exported_symbol.rs b/tests/run-pass/function_calls/exported_symbol.rs index 7f359e80219fc..96bf8170c6eb1 100644 --- a/tests/run-pass/function_calls/exported_symbol.rs +++ b/tests/run-pass/function_calls/exported_symbol.rs @@ -32,13 +32,42 @@ fn main() { extern "C" { fn foo() -> i32; } + assert_eq!(unsafe { foo() }, -1); - assert_eq!(unsafe { foo() }, -1); + extern "Rust" { fn bar() -> i32; fn baz() -> i32; } + assert_eq!(unsafe { bar() }, -2); assert_eq!(unsafe { baz() }, -3); + + #[allow(clashing_extern_declarations)] + { + extern "Rust" { + fn foo() -> i32; + } + + assert_eq!( + unsafe { + std::mem::transmute:: i32, unsafe extern "C" fn() -> i32>(foo)() + }, + -1 + ); + + extern "C" { + fn bar() -> i32; + fn baz() -> i32; + } + + unsafe { + let transmute = |f| { + std::mem::transmute:: i32, unsafe fn() -> i32>(f) + }; + assert_eq!(transmute(bar)(), -2); + assert_eq!(transmute(baz)(), -3); + } + } } } From 73700bc01c25c4bdf08a99803eee09ea4ca32fac Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Mon, 31 May 2021 10:50:25 -0500 Subject: [PATCH 2699/3747] Rustup for const_err changes --- rust-version | 2 +- src/diagnostics.rs | 6 ++++-- tests/compile-fail/erroneous_const.rs | 5 ++--- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/rust-version b/rust-version index 7fc12e477e284..089b4f55511b9 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -ce0d64e03ef9875e0935bb60e989542b7ec29579 +d9feaaa548ce380159a1de68f4f6e605db9a9fc5 diff --git a/src/diagnostics.rs b/src/diagnostics.rs index ae50b50860227..456b6fb4d419e 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -84,8 +84,10 @@ pub fn report_error<'tcx, 'mir>( "resource exhaustion", InvalidProgram(InvalidProgramInfo::ReferencedConstant) => "post-monomorphization error", - _ => - bug!("This error should be impossible in Miri: {}", e), + InvalidProgram(InvalidProgramInfo::AlreadyReported(_)) => + "error occurred", + kind => + bug!("This error should be impossible in Miri: {:?}", kind), }; #[rustfmt::skip] let helps = match e.kind() { diff --git a/tests/compile-fail/erroneous_const.rs b/tests/compile-fail/erroneous_const.rs index 49dcea62a2434..f193dee94ebc1 100644 --- a/tests/compile-fail/erroneous_const.rs +++ b/tests/compile-fail/erroneous_const.rs @@ -8,13 +8,12 @@ struct PrintName(T); impl PrintName { - const VOID: ! = panic!(); //~WARN any use of this value will cause an error - //~^ WARN this was previously accepted + const VOID: ! = panic!(); //~ERROR any use of this value will cause an error } fn no_codegen() { if false { - let _ = PrintName::::VOID; //~ERROR referenced constant has errors + let _ = PrintName::::VOID; //~ERROR error occurred: encountered constant } } fn main() { From b8aba11de3422b5b0ea7be727c2da2b856db3076 Mon Sep 17 00:00:00 2001 From: Pointerbender Date: Wed, 26 May 2021 21:30:43 +0200 Subject: [PATCH 2700/3747] regression tests for pointer invalidation in core library slice methods --- rust-version | 2 +- tests/run-pass/slices.rs | 54 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 55 insertions(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 089b4f55511b9..7b2fc1f00d674 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -d9feaaa548ce380159a1de68f4f6e605db9a9fc5 +d9feaaa548ce380159a1de68f4f6e605db9a9fc5 \ No newline at end of file diff --git a/tests/run-pass/slices.rs b/tests/run-pass/slices.rs index 41e7b2d36c7cf..113f3faa9ad2d 100644 --- a/tests/run-pass/slices.rs +++ b/tests/run-pass/slices.rs @@ -1,4 +1,6 @@ #![feature(new_uninit)] +#![feature(slice_as_chunks)] +#![feature(slice_partition_dedup)] use std::slice; @@ -186,8 +188,60 @@ fn uninit_slice() { assert_eq!(values.iter().map(|x| **x).collect::>(), vec![1, 2, 3]) } +/// Regression tests for slice methods in the Rust core library where raw pointers are obtained +/// from mutable references. +fn test_for_invalidated_pointers() { + let mut buffer = [0usize; 64]; + let len = buffer.len(); + + // These regression tests (indirectly) call every slice method which contains a `buffer.as_mut_ptr()`. + // `<[T]>::as_mut_ptr(&mut self)` takes a mutable reference (tagged Unique), which will invalidate all + // the other pointers that were previously derived from it according to the Stacked Borrows model. + // An example of where this could go wrong is a prior bug inside `<[T]>::copy_within`: + // + // unsafe { + // core::ptr::copy(self.as_ptr().add(src_start), self.as_mut_ptr().add(dest), count); + // } + // + // The arguments to `core::ptr::copy` are evaluated from left to right. `self.as_ptr()` creates + // an immutable reference (which is tagged as `SharedReadOnly` by Stacked Borrows) to the array + // and derives a valid `*const` pointer from it. When jumping to the next argument, + // `self.as_mut_ptr()` creates a mutable reference (tagged as `Unique`) to the array, which + // invalidates the existing `SharedReadOnly` reference and any pointers derived from it. + // The invalidated `*const` pointer (the first argument to `core::ptr::copy`) is then used + // after the fact when `core::ptr::copy` is called, which triggers undefined behavior. + + unsafe { assert_eq!(0, *buffer.as_mut_ptr_range().start ); } + // Check that the pointer range is in-bounds, while we're at it + let range = buffer.as_mut_ptr_range(); + unsafe { assert_eq!(*range.start, *range.end.sub(len)); } + + buffer.reverse(); + + // Calls `fn as_chunks_unchecked_mut` internally (requires unstable `#![feature(slice_as_chunks)]`): + assert_eq!(2, buffer.as_chunks_mut::<32>().0.len()); + + // Calls `fn split_at_mut_unchecked` internally: + let split_mut = buffer.split_at_mut(32); + assert_eq!(split_mut.0, split_mut.1); + + // Calls `fn partition_dedup_by` internally (requires unstable `#![feature(slice_partition_dedup)]`): + assert_eq!(1, buffer.partition_dedup().0.len()); + + buffer.rotate_left(8); + buffer.rotate_right(16); + + buffer.copy_from_slice(&[1usize; 64]); + buffer.swap_with_slice(&mut [2usize; 64]); + + assert_eq!(0, unsafe { buffer.align_to_mut::().1[1] }); + + buffer.copy_within(1.., 0); +} + fn main() { slice_of_zst(); test_iter_ref_consistency(); uninit_slice(); + test_for_invalidated_pointers(); } From c6dbe5cdcabaa3eb677519a7193b0d03254aa3b9 Mon Sep 17 00:00:00 2001 From: Pointerbender Date: Wed, 2 Jun 2021 15:31:50 +0200 Subject: [PATCH 2701/3747] use references so that potential aliasing bugs are triggered during regression test --- tests/run-pass/slices.rs | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/tests/run-pass/slices.rs b/tests/run-pass/slices.rs index 113f3faa9ad2d..83d9ff1151889 100644 --- a/tests/run-pass/slices.rs +++ b/tests/run-pass/slices.rs @@ -1,3 +1,4 @@ +// compile-flags: -Zmiri-track-raw-pointers #![feature(new_uninit)] #![feature(slice_as_chunks)] #![feature(slice_partition_dedup)] @@ -220,13 +221,23 @@ fn test_for_invalidated_pointers() { // Calls `fn as_chunks_unchecked_mut` internally (requires unstable `#![feature(slice_as_chunks)]`): assert_eq!(2, buffer.as_chunks_mut::<32>().0.len()); + for chunk in buffer.as_chunks_mut::<32>().0 { + for elem in chunk { + *elem += 1; + } + } // Calls `fn split_at_mut_unchecked` internally: let split_mut = buffer.split_at_mut(32); assert_eq!(split_mut.0, split_mut.1); // Calls `fn partition_dedup_by` internally (requires unstable `#![feature(slice_partition_dedup)]`): - assert_eq!(1, buffer.partition_dedup().0.len()); + let partition_dedup = buffer.partition_dedup(); + assert_eq!(1, partition_dedup.0.len()); + partition_dedup.0[0] += 1; + for elem in partition_dedup.1 { + *elem += 1; + } buffer.rotate_left(8); buffer.rotate_right(16); From e21dae71c8f331cc2c1cd29f90447508fb1caa2b Mon Sep 17 00:00:00 2001 From: Pointerbender Date: Wed, 2 Jun 2021 15:38:12 +0200 Subject: [PATCH 2702/3747] removed unintentional file change due to whitespace --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 7b2fc1f00d674..089b4f55511b9 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -d9feaaa548ce380159a1de68f4f6e605db9a9fc5 \ No newline at end of file +d9feaaa548ce380159a1de68f4f6e605db9a9fc5 From 647ee17b405cc137572e56894a348d97717b3491 Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Thu, 3 Jun 2021 10:22:31 +0800 Subject: [PATCH 2703/3747] `original_crate_name` -> `crate_name` --- rust-version | 2 +- src/helpers.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/rust-version b/rust-version index 089b4f55511b9..bc007cfbe3e2b 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -d9feaaa548ce380159a1de68f4f6e605db9a9fc5 +da865095cf378fbfd07145c25fe5837ea091efeb diff --git a/src/helpers.rs b/src/helpers.rs index 45a5a8d4170bf..29fde55d86ddf 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -19,7 +19,7 @@ impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mi /// Gets an instance for a path. fn try_resolve_did<'mir, 'tcx>(tcx: TyCtxt<'tcx>, path: &[&str]) -> Option { - tcx.crates().iter().find(|&&krate| tcx.original_crate_name(krate).as_str() == path[0]).and_then( + tcx.crates().iter().find(|&&krate| tcx.crate_name(krate).as_str() == path[0]).and_then( |krate| { let krate = DefId { krate: *krate, index: CRATE_DEF_INDEX }; let mut items = tcx.item_children(krate); From e4e6c25f678ac7aa70dcf61bb34beb59c95bb235 Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Thu, 3 Jun 2021 13:39:33 +0800 Subject: [PATCH 2704/3747] Remove FIXME in `tests/compile-fail/panic/bad_unwind.rs` --- tests/compile-fail/panic/bad_unwind.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/compile-fail/panic/bad_unwind.rs b/tests/compile-fail/panic/bad_unwind.rs index cfb109cb8b56a..fde2c19af07d5 100644 --- a/tests/compile-fail/panic/bad_unwind.rs +++ b/tests/compile-fail/panic/bad_unwind.rs @@ -4,8 +4,6 @@ //! Unwinding when the caller ABI is "C" (without "-unwind") is UB. //! Currently we detect the ABI mismatch; we could probably allow such calls in principle one day //! but then we have to detect the unexpected unwinding. -//! FIXME: `-Zmiri-disable-abi-check` does not work for this test because function pointers are -//! always allowed to unwind. extern "C-unwind" fn unwind() { panic!(); From ba3b11fa42467d0e8871a34a4a46edf04753acd6 Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Thu, 3 Jun 2021 14:16:58 +0800 Subject: [PATCH 2705/3747] Remove some tests --- .../panic/rustc_allocator_nounwind.rs | 10 ------- tests/run-pass/panic/good_unwind.rs | 27 ------------------- tests/run-pass/panic/good_unwind.stderr | 5 ---- 3 files changed, 42 deletions(-) delete mode 100644 tests/compile-fail/panic/rustc_allocator_nounwind.rs delete mode 100644 tests/run-pass/panic/good_unwind.rs delete mode 100644 tests/run-pass/panic/good_unwind.stderr diff --git a/tests/compile-fail/panic/rustc_allocator_nounwind.rs b/tests/compile-fail/panic/rustc_allocator_nounwind.rs deleted file mode 100644 index 7261b6658753a..0000000000000 --- a/tests/compile-fail/panic/rustc_allocator_nounwind.rs +++ /dev/null @@ -1,10 +0,0 @@ -#![feature(rustc_attrs, c_unwind)] - -#[rustc_allocator_nounwind] -extern "C-unwind" fn nounwind() { - panic!(); -} - -fn main() { - nounwind(); //~ ERROR unwinding past a stack frame that does not allow unwinding -} diff --git a/tests/run-pass/panic/good_unwind.rs b/tests/run-pass/panic/good_unwind.rs deleted file mode 100644 index dbc1c1631f135..0000000000000 --- a/tests/run-pass/panic/good_unwind.rs +++ /dev/null @@ -1,27 +0,0 @@ -#![feature(c_unwind, unboxed_closures, unwind_attributes)] - -use std::panic; - -extern "C-unwind" fn good_unwind_c() { - panic!(); -} - -#[unwind(allowed)] -extern "C" fn good_unwind_allowed() { - panic!(); -} - -fn good_unwind_rust() { - panic!(); -} - -extern "rust-call" fn good_unwind_rust_call(_: ()) { - panic!(); -} - -fn main() { - panic::catch_unwind(|| good_unwind_c()).unwrap_err(); - panic::catch_unwind(|| good_unwind_allowed()).unwrap_err(); - panic::catch_unwind(|| good_unwind_rust()).unwrap_err(); - good_unwind_rust_call(()); -} diff --git a/tests/run-pass/panic/good_unwind.stderr b/tests/run-pass/panic/good_unwind.stderr deleted file mode 100644 index 1cd361790b661..0000000000000 --- a/tests/run-pass/panic/good_unwind.stderr +++ /dev/null @@ -1,5 +0,0 @@ -thread 'main' panicked at 'explicit panic', $DIR/good_unwind.rs:6:5 -note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace -thread 'main' panicked at 'explicit panic', $DIR/good_unwind.rs:11:5 -thread 'main' panicked at 'explicit panic', $DIR/good_unwind.rs:15:5 -thread 'main' panicked at 'explicit panic', $DIR/good_unwind.rs:19:5 From 386863ac537d8f0cab87eff21ac7056c8935263e Mon Sep 17 00:00:00 2001 From: Pointerbender Date: Thu, 3 Jun 2021 17:24:10 +0200 Subject: [PATCH 2706/3747] added a strings.rs regression test case for potential future UB --- tests/run-pass/strings.rs | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/tests/run-pass/strings.rs b/tests/run-pass/strings.rs index fa692ba3de1be..b009e8bc6c4a4 100644 --- a/tests/run-pass/strings.rs +++ b/tests/run-pass/strings.rs @@ -1,3 +1,5 @@ +// compile-flags: -Zmiri-track-raw-pointers + fn empty() -> &'static str { "" } @@ -23,6 +25,32 @@ fn str_indexing() { let _v = &mut x[..3]; // Test IndexMut on String. } +fn unique_aliasing() { + // This is a regression test for the aliasing rules of a `Unique` pointer. + // At the time of writing this test case, Miri does not treat `Unique` + // pointers as a special case, these are treated like any other raw pointer. + // However, there are existing Github issues which may lead to `Unique` + // becoming a special case through asserting unique ownership over the pointee: + // - https://github.com/rust-lang/unsafe-code-guidelines/issues/258 + // - https://github.com/rust-lang/unsafe-code-guidelines/issues/262 + // Below, the calls to `String::remove` and `String::insert[_str]` follow + // code paths that would trigger undefined behavior in case `Unique` + // would ever assert semantic ownership over the pointee. Internally, + // these methods call `self.vec.as_ptr()` and `self.vec.as_mut_ptr()` on + // the vector of bytes that are backing the `String`. That `Vec` holds a + // `Unique` internally. The second call to `Vec::as_mut_ptr(&mut self)` + // would then invalidate the pointers derived from `Vec::as_ptr(&self)`. + // Note that as long as `Unique` is treated like any other raw pointer, + // this test case should pass. It is merely here as a canary test for + // potential future undefined behavior. + let mut x = String::from("Hello"); + assert_eq!(x.remove(0), 'H'); + x.insert(0, 'H'); + assert_eq!(x, "Hello"); + x.insert_str(x.len(), ", world!"); + assert_eq!(x, "Hello, world!"); +} + fn main() { assert_eq!(empty(), ""); assert_eq!(hello(), "Hello, world!"); @@ -31,4 +59,5 @@ fn main() { fat_pointer_on_32_bit(); // Should run without crashing. str_indexing(); + unique_aliasing(); } From 57e4f1d285c53d8826a6911c84230a46720c7498 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 3 Jun 2021 17:47:34 +0200 Subject: [PATCH 2707/3747] fix typo --- src/bin/miri.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 7368d4b253bac..514e5b0aebe94 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -97,7 +97,7 @@ struct MiriBeRustCompilerCalls { impl rustc_driver::Callbacks for MiriBeRustCompilerCalls { fn config(&mut self, config: &mut Config) { if config.opts.prints.is_empty() && self.target_crate { - // Queries overriden here affects the data stored in `rmeta` files of dependencies, + // Queries overriden here affect the data stored in `rmeta` files of dependencies, // which will be used later in non-`MIRI_BE_RUSTC` mode. config.override_queries = Some(|_, local_providers, _| { // `exported_symbols()` provided by rustc always returns empty result if From 879000b133aed8cc1893c84eb5319b491a4756d9 Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Thu, 3 Jun 2021 17:58:24 +0800 Subject: [PATCH 2708/3747] Detect `std` by checking if the crate defines `#[lang = "start"]` rather than string comparison --- src/helpers.rs | 6 +++ src/shims/posix/foreign_items.rs | 10 ++--- src/shims/posix/linux/foreign_items.rs | 4 +- src/shims/posix/macos/foreign_items.rs | 2 +- src/shims/windows/foreign_items.rs | 22 +++-------- .../unsupported_get_process_heap.rs | 12 ++++++ tests/compile-fail/unsupported_signal.rs | 12 ++++++ tests/run-pass/extern_crate_std_in_main.rs | 5 +++ tests/run-pass/rename_std.rs | 5 +++ tests/run-pass/std_only_foreign_function.rs | 39 +++++++++++++++++++ 10 files changed, 92 insertions(+), 25 deletions(-) create mode 100644 tests/compile-fail/unsupported_get_process_heap.rs create mode 100644 tests/compile-fail/unsupported_signal.rs create mode 100644 tests/run-pass/extern_crate_std_in_main.rs create mode 100644 tests/run-pass/rename_std.rs create mode 100644 tests/run-pass/std_only_foreign_function.rs diff --git a/src/helpers.rs b/src/helpers.rs index b71f830b2b10a..7f99aa1997068 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -628,6 +628,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } Ok(()) } + + fn in_std(&self) -> bool { + let this = self.eval_context_ref(); + this.tcx.def_path(this.frame().instance.def_id()).krate + == this.tcx.def_path(this.tcx.lang_items().start_fn().unwrap()).krate + } } /// Check that the number of args is what we expect. diff --git a/src/shims/posix/foreign_items.rs b/src/shims/posix/foreign_items.rs index a756256aab419..bbd46af52a9b7 100644 --- a/src/shims/posix/foreign_items.rs +++ b/src/shims/posix/foreign_items.rs @@ -475,7 +475,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Incomplete shims that we "stub out" just to get pre-main initialization code to work. // These shims are enabled only when the caller is in the standard library. "pthread_attr_getguardsize" - if this.frame().instance.to_string().starts_with("std::sys::unix::") => { + if this.in_std() => { this.check_abi(abi, Abi::C { unwind: false })?; let &[ref _attr, ref guard_size] = check_arg_count(args)?; let guard_size = this.deref_operand(guard_size)?; @@ -488,13 +488,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "pthread_attr_init" | "pthread_attr_destroy" - if this.frame().instance.to_string().starts_with("std::sys::unix::") => { + if this.in_std() => { this.check_abi(abi, Abi::C { unwind: false })?; let &[_] = check_arg_count(args)?; this.write_null(dest)?; } | "pthread_attr_setstacksize" - if this.frame().instance.to_string().starts_with("std::sys::unix::") => { + if this.in_std() => { this.check_abi(abi, Abi::C { unwind: false })?; let &[_, _] = check_arg_count(args)?; this.write_null(dest)?; @@ -502,14 +502,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "signal" | "sigaltstack" - if this.frame().instance.to_string().starts_with("std::sys::unix::") => { + if this.in_std() => { this.check_abi(abi, Abi::C { unwind: false })?; let &[_, _] = check_arg_count(args)?; this.write_null(dest)?; } | "sigaction" | "mprotect" - if this.frame().instance.to_string().starts_with("std::sys::unix::") => { + if this.in_std() => { this.check_abi(abi, Abi::C { unwind: false })?; let &[_, _, _] = check_arg_count(args)?; this.write_null(dest)?; diff --git a/src/shims/posix/linux/foreign_items.rs b/src/shims/posix/linux/foreign_items.rs index 598d89fe1f343..9b0576662f477 100644 --- a/src/shims/posix/linux/foreign_items.rs +++ b/src/shims/posix/linux/foreign_items.rs @@ -207,9 +207,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Incomplete shims that we "stub out" just to get pre-main initialization code to work. // These shims are enabled only when the caller is in the standard library. - "pthread_getattr_np" - if this.frame().instance.to_string().starts_with("std::sys::unix::") => - { + "pthread_getattr_np" if this.in_std() => { this.check_abi(abi, Abi::C { unwind: false })?; let &[ref _thread, ref _attr] = check_arg_count(args)?; this.write_null(dest)?; diff --git a/src/shims/posix/macos/foreign_items.rs b/src/shims/posix/macos/foreign_items.rs index d54e1bfbe8195..1467a95a0d3e2 100644 --- a/src/shims/posix/macos/foreign_items.rs +++ b/src/shims/posix/macos/foreign_items.rs @@ -149,7 +149,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Incomplete shims that we "stub out" just to get pre-main initialization code to work. // These shims are enabled only when the caller is in the standard library. - "mmap" if this.frame().instance.to_string().starts_with("std::sys::unix::") => { + "mmap" if this.in_std() => { this.check_abi(abi, Abi::C { unwind: false })?; // This is a horrible hack, but since the guard page mechanism calls mmap and expects a particular return value, we just give it that value. let &[ref addr, _, _, _, _, _] = check_arg_count(args)?; diff --git a/src/shims/windows/foreign_items.rs b/src/shims/windows/foreign_items.rs index 3c7451352dfd2..fd845cde31125 100644 --- a/src/shims/windows/foreign_items.rs +++ b/src/shims/windows/foreign_items.rs @@ -348,35 +348,27 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Incomplete shims that we "stub out" just to get pre-main initialization code to work. // These shims are enabled only when the caller is in the standard library. - "GetProcessHeap" - if this.frame().instance.to_string().starts_with("std::sys::windows::") => - { + "GetProcessHeap" if this.in_std() => { this.check_abi(abi, Abi::System { unwind: false })?; let &[] = check_arg_count(args)?; // Just fake a HANDLE this.write_scalar(Scalar::from_machine_isize(1, this), dest)?; } - "SetConsoleTextAttribute" - if this.frame().instance.to_string().starts_with("std::sys::windows::") => - { + "SetConsoleTextAttribute" if this.in_std() => { this.check_abi(abi, Abi::System { unwind: false })?; #[allow(non_snake_case)] let &[ref _hConsoleOutput, ref _wAttribute] = check_arg_count(args)?; // Pretend these does not exist / nothing happened, by returning zero. this.write_null(dest)?; } - "AddVectoredExceptionHandler" - if this.frame().instance.to_string().starts_with("std::sys::windows::") => - { + "AddVectoredExceptionHandler" if this.in_std() => { this.check_abi(abi, Abi::System { unwind: false })?; #[allow(non_snake_case)] let &[ref _First, ref _Handler] = check_arg_count(args)?; // Any non zero value works for the stdlib. This is just used for stack overflows anyway. this.write_scalar(Scalar::from_machine_usize(1, this), dest)?; } - "SetThreadStackGuarantee" - if this.frame().instance.to_string().starts_with("std::sys::windows::") => - { + "SetThreadStackGuarantee" if this.in_std() => { this.check_abi(abi, Abi::System { unwind: false })?; #[allow(non_snake_case)] let &[_StackSizeInBytes] = check_arg_count(args)?; @@ -387,7 +379,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "EnterCriticalSection" | "LeaveCriticalSection" | "DeleteCriticalSection" - if this.frame().instance.to_string().starts_with("std::sys::windows::") => + if this.in_std() => { this.check_abi(abi, Abi::System { unwind: false })?; #[allow(non_snake_case)] @@ -401,9 +393,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // (Windows locks are reentrant, and we have only 1 thread, // so not doing any futher checks here is at least not incorrect.) } - "TryEnterCriticalSection" - if this.frame().instance.to_string().starts_with("std::sys::windows::") => - { + "TryEnterCriticalSection" if this.in_std() => { this.check_abi(abi, Abi::System { unwind: false })?; #[allow(non_snake_case)] let &[ref _lpCriticalSection] = check_arg_count(args)?; diff --git a/tests/compile-fail/unsupported_get_process_heap.rs b/tests/compile-fail/unsupported_get_process_heap.rs new file mode 100644 index 0000000000000..4fd5f4b7d885f --- /dev/null +++ b/tests/compile-fail/unsupported_get_process_heap.rs @@ -0,0 +1,12 @@ +//! `GetProcessHeap()` is special on Windows that it's only supported within libstd. +//! (On Linux and macOS, it's just always unsupported.) + +fn main() { + extern "system" { + fn GetProcessHeap() -> *mut std::ffi::c_void; + } + unsafe { + GetProcessHeap(); + //~^ ERROR unsupported operation: can't call foreign function: GetProcessHeap + } +} diff --git a/tests/compile-fail/unsupported_signal.rs b/tests/compile-fail/unsupported_signal.rs new file mode 100644 index 0000000000000..7931747e0aa86 --- /dev/null +++ b/tests/compile-fail/unsupported_signal.rs @@ -0,0 +1,12 @@ +//! `signal()` is special on Linux and macOS that it's only supported within libstd. +// ignore-windows: No libc on Windows +#![feature(rustc_private)] + +extern crate libc; + +fn main() { + unsafe { + libc::signal(libc::SIGPIPE, libc::SIG_IGN); + //~^ ERROR unsupported operation: can't call foreign function: signal + } +} diff --git a/tests/run-pass/extern_crate_std_in_main.rs b/tests/run-pass/extern_crate_std_in_main.rs new file mode 100644 index 0000000000000..8f71e613375e3 --- /dev/null +++ b/tests/run-pass/extern_crate_std_in_main.rs @@ -0,0 +1,5 @@ +#![no_std] + +fn main() { + extern crate std; +} diff --git a/tests/run-pass/rename_std.rs b/tests/run-pass/rename_std.rs new file mode 100644 index 0000000000000..7e82e53e6be85 --- /dev/null +++ b/tests/run-pass/rename_std.rs @@ -0,0 +1,5 @@ +#![no_std] + +extern crate std as foo; + +fn main() {} diff --git a/tests/run-pass/std_only_foreign_function.rs b/tests/run-pass/std_only_foreign_function.rs new file mode 100644 index 0000000000000..959103ee5c8e7 --- /dev/null +++ b/tests/run-pass/std_only_foreign_function.rs @@ -0,0 +1,39 @@ +//! Make sure we can call foreign functions that are only allowed within libstd if we are "libstd" +//! (defining the `start` lang item). +#![feature(lang_items, rustc_private, core_intrinsics)] +#![no_std] + +use core::{intrinsics, panic::PanicInfo}; + +#[lang = "eh_personality"] +fn rust_eh_personality() {} + +#[panic_handler] +fn panic_handler(_: &PanicInfo<'_>) -> ! { + intrinsics::abort() +} + +#[lang = "start"] +fn start(main: fn(), _argc: isize, _argv: *const *const u8) -> isize { + main(); + 0 +} + +fn main() { + #[cfg(unix)] + unsafe { + extern crate libc; + assert_eq!(libc::signal(libc::SIGPIPE, libc::SIG_IGN), 0); + } + #[cfg(windows)] + unsafe { + extern "system" { + fn GetProcessHeap() -> *mut core::ffi::c_void; + fn ExitProcess(code: u32) -> !; + } + assert_eq!(GetProcessHeap() as usize, 1); + // Early exit to avoid the requirement of + // `std::sys::windows::thread_local_key::p_thread_callback`. + ExitProcess(0); + } +} From 545101040df050dcc412d714640c95f417194600 Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Thu, 3 Jun 2021 21:26:11 +0800 Subject: [PATCH 2709/3747] Don't `unwrap()` in `in_std()` --- src/helpers.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index 7f99aa1997068..a9cafd2a9e390 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -631,8 +631,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn in_std(&self) -> bool { let this = self.eval_context_ref(); - this.tcx.def_path(this.frame().instance.def_id()).krate - == this.tcx.def_path(this.tcx.lang_items().start_fn().unwrap()).krate + this.tcx.lang_items().start_fn().map_or(false, |start_fn| { + this.tcx.def_path(this.frame().instance.def_id()).krate + == this.tcx.def_path(start_fn).krate + }) } } From 3871c493b24b00c2b3d11af5aef8bb0045dd7469 Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Sun, 6 Jun 2021 11:21:20 +0800 Subject: [PATCH 2710/3747] `in_std` -> `frame_in_std` --- src/helpers.rs | 2 +- src/shims/posix/foreign_items.rs | 10 +++++----- src/shims/posix/linux/foreign_items.rs | 2 +- src/shims/posix/macos/foreign_items.rs | 2 +- src/shims/windows/foreign_items.rs | 12 ++++++------ 5 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index a9cafd2a9e390..52176342057e4 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -629,7 +629,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(()) } - fn in_std(&self) -> bool { + fn frame_in_std(&self) -> bool { let this = self.eval_context_ref(); this.tcx.lang_items().start_fn().map_or(false, |start_fn| { this.tcx.def_path(this.frame().instance.def_id()).krate diff --git a/src/shims/posix/foreign_items.rs b/src/shims/posix/foreign_items.rs index bbd46af52a9b7..2ecea4d9f41e5 100644 --- a/src/shims/posix/foreign_items.rs +++ b/src/shims/posix/foreign_items.rs @@ -475,7 +475,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Incomplete shims that we "stub out" just to get pre-main initialization code to work. // These shims are enabled only when the caller is in the standard library. "pthread_attr_getguardsize" - if this.in_std() => { + if this.frame_in_std() => { this.check_abi(abi, Abi::C { unwind: false })?; let &[ref _attr, ref guard_size] = check_arg_count(args)?; let guard_size = this.deref_operand(guard_size)?; @@ -488,13 +488,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "pthread_attr_init" | "pthread_attr_destroy" - if this.in_std() => { + if this.frame_in_std() => { this.check_abi(abi, Abi::C { unwind: false })?; let &[_] = check_arg_count(args)?; this.write_null(dest)?; } | "pthread_attr_setstacksize" - if this.in_std() => { + if this.frame_in_std() => { this.check_abi(abi, Abi::C { unwind: false })?; let &[_, _] = check_arg_count(args)?; this.write_null(dest)?; @@ -502,14 +502,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "signal" | "sigaltstack" - if this.in_std() => { + if this.frame_in_std() => { this.check_abi(abi, Abi::C { unwind: false })?; let &[_, _] = check_arg_count(args)?; this.write_null(dest)?; } | "sigaction" | "mprotect" - if this.in_std() => { + if this.frame_in_std() => { this.check_abi(abi, Abi::C { unwind: false })?; let &[_, _, _] = check_arg_count(args)?; this.write_null(dest)?; diff --git a/src/shims/posix/linux/foreign_items.rs b/src/shims/posix/linux/foreign_items.rs index 9b0576662f477..9017dc368b69c 100644 --- a/src/shims/posix/linux/foreign_items.rs +++ b/src/shims/posix/linux/foreign_items.rs @@ -207,7 +207,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Incomplete shims that we "stub out" just to get pre-main initialization code to work. // These shims are enabled only when the caller is in the standard library. - "pthread_getattr_np" if this.in_std() => { + "pthread_getattr_np" if this.frame_in_std() => { this.check_abi(abi, Abi::C { unwind: false })?; let &[ref _thread, ref _attr] = check_arg_count(args)?; this.write_null(dest)?; diff --git a/src/shims/posix/macos/foreign_items.rs b/src/shims/posix/macos/foreign_items.rs index 1467a95a0d3e2..313d38c80b6f5 100644 --- a/src/shims/posix/macos/foreign_items.rs +++ b/src/shims/posix/macos/foreign_items.rs @@ -149,7 +149,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Incomplete shims that we "stub out" just to get pre-main initialization code to work. // These shims are enabled only when the caller is in the standard library. - "mmap" if this.in_std() => { + "mmap" if this.frame_in_std() => { this.check_abi(abi, Abi::C { unwind: false })?; // This is a horrible hack, but since the guard page mechanism calls mmap and expects a particular return value, we just give it that value. let &[ref addr, _, _, _, _, _] = check_arg_count(args)?; diff --git a/src/shims/windows/foreign_items.rs b/src/shims/windows/foreign_items.rs index fd845cde31125..76657a535541a 100644 --- a/src/shims/windows/foreign_items.rs +++ b/src/shims/windows/foreign_items.rs @@ -348,27 +348,27 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Incomplete shims that we "stub out" just to get pre-main initialization code to work. // These shims are enabled only when the caller is in the standard library. - "GetProcessHeap" if this.in_std() => { + "GetProcessHeap" if this.frame_in_std() => { this.check_abi(abi, Abi::System { unwind: false })?; let &[] = check_arg_count(args)?; // Just fake a HANDLE this.write_scalar(Scalar::from_machine_isize(1, this), dest)?; } - "SetConsoleTextAttribute" if this.in_std() => { + "SetConsoleTextAttribute" if this.frame_in_std() => { this.check_abi(abi, Abi::System { unwind: false })?; #[allow(non_snake_case)] let &[ref _hConsoleOutput, ref _wAttribute] = check_arg_count(args)?; // Pretend these does not exist / nothing happened, by returning zero. this.write_null(dest)?; } - "AddVectoredExceptionHandler" if this.in_std() => { + "AddVectoredExceptionHandler" if this.frame_in_std() => { this.check_abi(abi, Abi::System { unwind: false })?; #[allow(non_snake_case)] let &[ref _First, ref _Handler] = check_arg_count(args)?; // Any non zero value works for the stdlib. This is just used for stack overflows anyway. this.write_scalar(Scalar::from_machine_usize(1, this), dest)?; } - "SetThreadStackGuarantee" if this.in_std() => { + "SetThreadStackGuarantee" if this.frame_in_std() => { this.check_abi(abi, Abi::System { unwind: false })?; #[allow(non_snake_case)] let &[_StackSizeInBytes] = check_arg_count(args)?; @@ -379,7 +379,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "EnterCriticalSection" | "LeaveCriticalSection" | "DeleteCriticalSection" - if this.in_std() => + if this.frame_in_std() => { this.check_abi(abi, Abi::System { unwind: false })?; #[allow(non_snake_case)] @@ -393,7 +393,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // (Windows locks are reentrant, and we have only 1 thread, // so not doing any futher checks here is at least not incorrect.) } - "TryEnterCriticalSection" if this.in_std() => { + "TryEnterCriticalSection" if this.frame_in_std() => { this.check_abi(abi, Abi::System { unwind: false })?; #[allow(non_snake_case)] let &[ref _lpCriticalSection] = check_arg_count(args)?; From d7aff960538bf3cadd66556ecedc87fa685492d5 Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Sun, 6 Jun 2021 11:22:25 +0800 Subject: [PATCH 2711/3747] Remove 2 tests --- .../unsupported_get_process_heap.rs | 12 ------ tests/run-pass/std_only_foreign_function.rs | 39 ------------------- 2 files changed, 51 deletions(-) delete mode 100644 tests/compile-fail/unsupported_get_process_heap.rs delete mode 100644 tests/run-pass/std_only_foreign_function.rs diff --git a/tests/compile-fail/unsupported_get_process_heap.rs b/tests/compile-fail/unsupported_get_process_heap.rs deleted file mode 100644 index 4fd5f4b7d885f..0000000000000 --- a/tests/compile-fail/unsupported_get_process_heap.rs +++ /dev/null @@ -1,12 +0,0 @@ -//! `GetProcessHeap()` is special on Windows that it's only supported within libstd. -//! (On Linux and macOS, it's just always unsupported.) - -fn main() { - extern "system" { - fn GetProcessHeap() -> *mut std::ffi::c_void; - } - unsafe { - GetProcessHeap(); - //~^ ERROR unsupported operation: can't call foreign function: GetProcessHeap - } -} diff --git a/tests/run-pass/std_only_foreign_function.rs b/tests/run-pass/std_only_foreign_function.rs deleted file mode 100644 index 959103ee5c8e7..0000000000000 --- a/tests/run-pass/std_only_foreign_function.rs +++ /dev/null @@ -1,39 +0,0 @@ -//! Make sure we can call foreign functions that are only allowed within libstd if we are "libstd" -//! (defining the `start` lang item). -#![feature(lang_items, rustc_private, core_intrinsics)] -#![no_std] - -use core::{intrinsics, panic::PanicInfo}; - -#[lang = "eh_personality"] -fn rust_eh_personality() {} - -#[panic_handler] -fn panic_handler(_: &PanicInfo<'_>) -> ! { - intrinsics::abort() -} - -#[lang = "start"] -fn start(main: fn(), _argc: isize, _argv: *const *const u8) -> isize { - main(); - 0 -} - -fn main() { - #[cfg(unix)] - unsafe { - extern crate libc; - assert_eq!(libc::signal(libc::SIGPIPE, libc::SIG_IGN), 0); - } - #[cfg(windows)] - unsafe { - extern "system" { - fn GetProcessHeap() -> *mut core::ffi::c_void; - fn ExitProcess(code: u32) -> !; - } - assert_eq!(GetProcessHeap() as usize, 1); - // Early exit to avoid the requirement of - // `std::sys::windows::thread_local_key::p_thread_callback`. - ExitProcess(0); - } -} From 0ece55d748a04aba9c4950937de226c259630719 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 6 Jun 2021 10:33:46 +0200 Subject: [PATCH 2712/3747] expand comment --- tests/compile-fail/unsupported_signal.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/compile-fail/unsupported_signal.rs b/tests/compile-fail/unsupported_signal.rs index 7931747e0aa86..3e76d1c3f3847 100644 --- a/tests/compile-fail/unsupported_signal.rs +++ b/tests/compile-fail/unsupported_signal.rs @@ -1,4 +1,5 @@ //! `signal()` is special on Linux and macOS that it's only supported within libstd. +//! The implementation is not complete enough to permit user code to call it. // ignore-windows: No libc on Windows #![feature(rustc_private)] From 9549faa81cc389ef2f05ea8bff5246388314f277 Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Mon, 7 Jun 2021 16:49:00 +0800 Subject: [PATCH 2713/3747] Update `cargo-miri` tests --- rust-version | 2 +- test-cargo-miri/test.default.stdout.ref | 4 ++-- test-cargo-miri/test.test-target.stdout.ref | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/rust-version b/rust-version index bc007cfbe3e2b..81334a8d5a08b 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -da865095cf378fbfd07145c25fe5837ea091efeb +cc9610bf5af1d5c54968db0dd899595ca12307a0 diff --git a/test-cargo-miri/test.default.stdout.ref b/test-cargo-miri/test.default.stdout.ref index 6c7d284a84ac8..4edcb7ba7d912 100644 --- a/test-cargo-miri/test.default.stdout.ref +++ b/test-cargo-miri/test.default.stdout.ref @@ -12,8 +12,8 @@ test result: ok. 6 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out running 3 tests test src/lib.rs - make_true (line 2) ... ok -test src/lib.rs - make_true (line 5) ... ok -test src/lib.rs - make_true (line 8) ... ok +test src/lib.rs - make_true (line 5) - compile ... ok +test src/lib.rs - make_true (line 8) - compile fail ... ok test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME diff --git a/test-cargo-miri/test.test-target.stdout.ref b/test-cargo-miri/test.test-target.stdout.ref index 893e52e87774d..6655eb8409290 100644 --- a/test-cargo-miri/test.test-target.stdout.ref +++ b/test-cargo-miri/test.test-target.stdout.ref @@ -1,10 +1,10 @@ running 7 tests test cargo_env ... ok -test do_panic ... ok +test do_panic - should panic ... ok test does_not_work_on_miri ... ignored test entropy_rng ... ok -test fail_index_check ... ok +test fail_index_check - should panic ... ok test simple1 ... ok test simple2 ... ok From ae237098f8af22bd44ee3808cce97f1782eb4e18 Mon Sep 17 00:00:00 2001 From: Lander Brandt Date: Wed, 26 May 2021 16:29:01 -0700 Subject: [PATCH 2714/3747] Add support for panicking in the emulated application when unsupported syscalls are encountered --- README.md | 5 +++++ src/bin/miri.rs | 3 +++ src/eval.rs | 3 +++ src/helpers.rs | 17 +++++++++++++++++ src/machine.rs | 6 ++++++ src/shims/foreign_items.rs | 10 ++++++++-- src/shims/panic.rs | 2 +- src/shims/posix/linux/foreign_items.rs | 5 ++++- src/shims/windows/foreign_items.rs | 4 +++- tests/compile-fail/concurrency/thread-spawn.rs | 2 +- .../panic/unsupported_foreign_function.rs | 11 +++++++++++ .../panic/unsupported_foreign_function.stderr | 2 ++ 12 files changed, 64 insertions(+), 6 deletions(-) create mode 100644 tests/run-pass/panic/unsupported_foreign_function.rs create mode 100644 tests/run-pass/panic/unsupported_foreign_function.stderr diff --git a/README.md b/README.md index f0e14a9125c61..2e24402450fd4 100644 --- a/README.md +++ b/README.md @@ -228,6 +228,11 @@ environment variable: This can be used to find which parts of your program are executing slowly under Miri. The profile is written out to a file with the prefix ``, and can be processed using the tools in the repository https://github.com/rust-lang/measureme. +* `-Zmiri-panic-on-unsupported` will makes some forms of unsupported functionality, + such as FFI and unsupported syscalls, panic within the context of the emulated + application instead of raising an error within the context of Miri (and halting + execution). Note that code might not expect these operations to ever panic, so + this flag can lead to strange (mis)behavior. * `-Zmiri-seed=` configures the seed of the RNG that Miri uses to resolve non-determinism. This RNG is used to pick base addresses for allocations. When isolation is enabled (the default), this is also used to emulate system diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 514e5b0aebe94..7fd6d85cffdea 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -296,6 +296,9 @@ fn main() { "-Zmiri-ignore-leaks" => { miri_config.ignore_leaks = true; } + "-Zmiri-panic-on-unsupported" => { + miri_config.panic_on_unsupported = true; + } "-Zmiri-track-raw-pointers" => { miri_config.track_raw = true; } diff --git a/src/eval.rs b/src/eval.rs index 6646783d349ca..8d5876d777183 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -59,6 +59,8 @@ pub struct MiriConfig { /// If `Some`, enable the `measureme` profiler, writing results to a file /// with the specified prefix. pub measureme_out: Option, + /// Panic when unsupported functionality is encountered + pub panic_on_unsupported: bool, } impl Default for MiriConfig { @@ -80,6 +82,7 @@ impl Default for MiriConfig { data_race_detector: true, cmpxchg_weak_failure_rate: 0.8, measureme_out: None, + panic_on_unsupported: false, } } } diff --git a/src/helpers.rs b/src/helpers.rs index 52176342057e4..c8e1d6c880223 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -636,6 +636,23 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx == this.tcx.def_path(start_fn).krate }) } + + /// Handler that should be called when unsupported functionality is encountered. + /// This function will either panic within the context of the emulated application + /// or return an error in the Miri process context + /// + /// Return value of `Ok(bool)` indicates whether execution should continue. + fn handle_unsupported>(&mut self, error_msg: S) -> InterpResult<'tcx, ()> { + let this = self.eval_context_mut(); + if this.machine.panic_on_unsupported { + // message is slightly different here to make automated analysis easier + let error_msg = format!("unsupported Miri functionality: {}", error_msg.as_ref()); + this.start_panic(error_msg.as_ref(), StackPopUnwind::Skip)?; + return Ok(()); + } else { + throw_unsup_format!("{}", error_msg.as_ref()); + } + } } /// Check that the number of args is what we expect. diff --git a/src/machine.rs b/src/machine.rs index 9c49575ded324..f25c1b9720dc8 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -297,6 +297,11 @@ pub struct Evaluator<'mir, 'tcx> { /// Cache of `Instance` exported under the given `Symbol` name. pub(crate) exported_symbols_cache: FxHashMap>, + + /// Whether to raise a panic in the context of the evaluated process when unsupported + /// functionality is encountered. If `false`, an error is propagated in the Miri application context + /// instead (default behavior) + pub(crate) panic_on_unsupported: bool, } impl<'mir, 'tcx> Evaluator<'mir, 'tcx> { @@ -326,6 +331,7 @@ impl<'mir, 'tcx> Evaluator<'mir, 'tcx> { profiler, string_cache: Default::default(), exported_symbols_cache: FxHashMap::default(), + panic_on_unsupported: config.panic_on_unsupported, } } } diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index c838c136c3f41..8f3dfdc4f81fa 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -259,7 +259,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if let Some(body) = this.lookup_exported_symbol(link_name_sym)? { return Ok(Some(body)); } - throw_unsup_format!("can't call (diverging) foreign function: {}", link_name); + this.handle_unsupported(format!( + "can't call (diverging) foreign function: {}", + link_name + ))?; + return Ok(None); } }, Some(p) => p, @@ -276,7 +280,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if let Some(body) = this.lookup_exported_symbol(link_name_sym)? { return Ok(Some(body)); } - throw_unsup_format!("can't call foreign function: {}", link_name); + + this.handle_unsupported(format!("can't call foreign function: {}", link_name))?; + return Ok(None); } } diff --git a/src/shims/panic.rs b/src/shims/panic.rs index b1da7f340fce3..15620c73f0dab 100644 --- a/src/shims/panic.rs +++ b/src/shims/panic.rs @@ -161,7 +161,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } - /// Starta a panic in the interpreter with the given message as payload. + /// Start a panic in the interpreter with the given message as payload. fn start_panic(&mut self, msg: &str, unwind: StackPopUnwind) -> InterpResult<'tcx> { let this = self.eval_context_mut(); diff --git a/src/shims/posix/linux/foreign_items.rs b/src/shims/posix/linux/foreign_items.rs index 9017dc368b69c..68ae704fb04f2 100644 --- a/src/shims/posix/linux/foreign_items.rs +++ b/src/shims/posix/linux/foreign_items.rs @@ -183,7 +183,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx id if id == sys_futex => { futex(this, args, dest)?; } - id => throw_unsup_format!("Miri does not support syscall ID {}", id), + id => { + this.handle_unsupported(format!("can't execute syscall with ID {}", id))?; + return Ok(EmulateByNameResult::NotSupported); + } } } diff --git a/src/shims/windows/foreign_items.rs b/src/shims/windows/foreign_items.rs index 76657a535541a..02f9bb8fff200 100644 --- a/src/shims/windows/foreign_items.rs +++ b/src/shims/windows/foreign_items.rs @@ -343,7 +343,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Better error for attempts to create a thread "CreateThread" => { this.check_abi(abi, Abi::System { unwind: false })?; - throw_unsup_format!("Miri does not support concurrency on Windows"); + + this.handle_unsupported("can't create threads on Windows")?; + return Ok(EmulateByNameResult::AlreadyJumped); } // Incomplete shims that we "stub out" just to get pre-main initialization code to work. diff --git a/tests/compile-fail/concurrency/thread-spawn.rs b/tests/compile-fail/concurrency/thread-spawn.rs index 27760eed8dba9..6f07d083a0e51 100644 --- a/tests/compile-fail/concurrency/thread-spawn.rs +++ b/tests/compile-fail/concurrency/thread-spawn.rs @@ -3,7 +3,7 @@ use std::thread; -// error-pattern: Miri does not support concurrency on Windows +// error-pattern: can't create threads on Windows fn main() { thread::spawn(|| {}); diff --git a/tests/run-pass/panic/unsupported_foreign_function.rs b/tests/run-pass/panic/unsupported_foreign_function.rs new file mode 100644 index 0000000000000..bc3d02c5f2795 --- /dev/null +++ b/tests/run-pass/panic/unsupported_foreign_function.rs @@ -0,0 +1,11 @@ +// compile-flags: -Zmiri-panic-on-unsupported + +fn main() { + extern "Rust" { + fn foo(); + } + + unsafe { + foo(); + } +} diff --git a/tests/run-pass/panic/unsupported_foreign_function.stderr b/tests/run-pass/panic/unsupported_foreign_function.stderr new file mode 100644 index 0000000000000..bd7f3490d809d --- /dev/null +++ b/tests/run-pass/panic/unsupported_foreign_function.stderr @@ -0,0 +1,2 @@ +thread 'main' panicked at 'unsupported Miri functionality: can't call foreign function: foo', $DIR/unsupported_foreign_function.rs:9:9 +note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace From 23c0495ebd64f91629a05eaabbd05f76259f7621 Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Tue, 8 Jun 2021 22:17:23 +0800 Subject: [PATCH 2715/3747] Update `Box` to `Box` in `catch_panic.stderr` --- rust-version | 2 +- tests/run-pass/panic/catch_panic.stderr | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/rust-version b/rust-version index 81334a8d5a08b..7d2e8afafacb7 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -cc9610bf5af1d5c54968db0dd899595ca12307a0 +a50d72158e08e02cfc051b863017bdbd2c45b637 diff --git a/tests/run-pass/panic/catch_panic.stderr b/tests/run-pass/panic/catch_panic.stderr index 696dbc1f81813..0f43ab2520a57 100644 --- a/tests/run-pass/panic/catch_panic.stderr +++ b/tests/run-pass/panic/catch_panic.stderr @@ -5,7 +5,7 @@ thread 'main' panicked at 'Hello from panic: 1', $DIR/catch_panic.rs:LL:26 Caught panic message (String): Hello from panic: 1 thread 'main' panicked at 'Hello from panic: 2', $DIR/catch_panic.rs:LL:26 Caught panic message (String): Hello from panic: 2 -thread 'main' panicked at 'Box', $DIR/catch_panic.rs:LL:27 +thread 'main' panicked at 'Box', $DIR/catch_panic.rs:LL:27 Failed to get caught panic message. thread 'main' panicked at 'Hello from panic: core', $DIR/catch_panic.rs:LL:27 Caught panic message (&str): Hello from panic: core From c6bcb4d3c02c3dd6d0f9570d60ca67b8d1fc12f5 Mon Sep 17 00:00:00 2001 From: Kitsu Date: Wed, 9 Jun 2021 10:48:43 +0300 Subject: [PATCH 2716/3747] Specify miri toolchain for CI example --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f0e14a9125c61..21ab49bc1f898 100644 --- a/README.md +++ b/README.md @@ -146,7 +146,7 @@ nightly that *does* come with Miri: MIRI_NIGHTLY=nightly-$(curl -s https://rust-lang.github.io/rustup-components-history/x86_64-unknown-linux-gnu/miri) echo "Installing latest nightly with Miri: $MIRI_NIGHTLY" rustup set profile minimal -rustup default "$MIRI_NIGHTLY" +rustup override set "$MIRI_NIGHTLY" rustup component add miri cargo miri test From 892f706ce55d38bf8a6c80fec5d08e785d2240ac Mon Sep 17 00:00:00 2001 From: Smit Soni Date: Thu, 13 May 2021 23:40:07 -0700 Subject: [PATCH 2717/3747] Add a support to execute isolated op without halting In user interface, added a new flag `-Zmiri-isolation-error` which takes one of the four values -- hide, warn, warn-nobacktrace, and abort. This option can be used to configure Miri to either abort or return an error code upon executing isolated op. If not aborted, Miri prints a warning, whose verbosity can be configured using this flag. In implementation, added a new enum `IsolatedOp` to capture all the settings related to ops requiring communication with the host. Old `communicate` flag in both miri configs and machine stats is replaced with a new helper function `communicate()` which checks `isolated_op` internally. Added a new helper function `reject_in_isolation` which can be called by shims to reject ops according to the reject_with settings. Use miri specific diagnostics function `report_msg` to print backtrace in the warning. Update it to take an enum value instead of a bool, indicating the level of diagnostics. Updated shims related to current dir to use the new APIs. Added a new test for current dir ops in isolation without halting machine. --- README.md | 7 ++++ src/bin/miri.rs | 35 +++++++++++++++- src/diagnostics.rs | 41 ++++++++++++------- src/eval.rs | 37 +++++++++++++++-- src/helpers.rs | 28 +++++++++++-- src/lib.rs | 4 +- src/machine.rs | 13 ++++-- src/shims/env.rs | 34 ++++++++++++--- src/shims/posix/fs.rs | 19 +++++---- tests/run-pass/current_dir_with_isolation.rs | 20 +++++++++ .../current_dir_with_isolation.stderr | 4 ++ 11 files changed, 199 insertions(+), 43 deletions(-) create mode 100644 tests/run-pass/current_dir_with_isolation.rs create mode 100644 tests/run-pass/current_dir_with_isolation.stderr diff --git a/README.md b/README.md index 21ab49bc1f898..f6b46ce3a95c5 100644 --- a/README.md +++ b/README.md @@ -219,6 +219,13 @@ environment variable: * `-Zmiri-disable-isolation` disables host isolation. As a consequence, the program has access to host resources such as environment variables, file systems, and randomness. +* `-Zmiri-isolation-error=` configures Miri's response to operations + requiring host access while isolation is enabled. `abort`, `hide`, `warn`, + and `warn-nobacktrace` are the supported actions. Default action is `abort` + which halts the machine. Rest of the actions configure it to return an error + code for the op and continue executing. `warn` prints backtrace that could + be used to trace the call. `warn-nobacktrace` is less verbose without + backtrace. `hide` hides the warning. * `-Zmiri-env-exclude=` keeps the `var` environment variable isolated from the host so that it cannot be accessed by the program. Can be used multiple times to exclude several variables. On Windows, the `TERM` environment diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 514e5b0aebe94..677836d7e9725 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -263,6 +263,9 @@ fn main() { let mut miri_config = miri::MiriConfig::default(); let mut rustc_args = vec![]; let mut after_dashdash = false; + + // If user has explicitly enabled/disabled isolation + let mut isolation_enabled: Option = None; for arg in env::args() { if rustc_args.is_empty() { // Very first arg: binary name. @@ -291,7 +294,37 @@ fn main() { miri_config.check_abi = false; } "-Zmiri-disable-isolation" => { - miri_config.communicate = true; + if matches!(isolation_enabled, Some(true)) { + panic!( + "-Zmiri-disable-isolation cannot be used along with -Zmiri-isolation-error" + ); + } else { + isolation_enabled = Some(false); + } + miri_config.isolated_op = miri::IsolatedOp::Allow; + } + arg if arg.starts_with("-Zmiri-isolation-error=") => { + if matches!(isolation_enabled, Some(false)) { + panic!( + "-Zmiri-isolation-error cannot be used along with -Zmiri-disable-isolation" + ); + } else { + isolation_enabled = Some(true); + } + + miri_config.isolated_op = match arg + .strip_prefix("-Zmiri-isolation-error=") + .unwrap() + { + "abort" => miri::IsolatedOp::Reject(miri::RejectOpWith::Abort), + "hide" => miri::IsolatedOp::Reject(miri::RejectOpWith::NoWarning), + "warn" => miri::IsolatedOp::Reject(miri::RejectOpWith::Warning), + "warn-nobacktrace" => + miri::IsolatedOp::Reject(miri::RejectOpWith::WarningWithoutBacktrace), + _ => panic!( + "-Zmiri-isolation-error must be `abort`, `hide`, `warn`, or `warn-nobacktrace`" + ), + }; } "-Zmiri-ignore-leaks" => { miri_config.ignore_leaks = true; diff --git a/src/diagnostics.rs b/src/diagnostics.rs index f273cf04203da..2b17e83bee698 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -52,6 +52,14 @@ pub enum NonHaltingDiagnostic { CreatedCallId(CallId), CreatedAlloc(AllocId), FreedAlloc(AllocId), + RejectedIsolatedOp(String), +} + +/// Level of Miri specific diagnostics +enum DiagLevel { + Error, + Warning, + Note, } /// Emit a custom diagnostic without going through the miri-engine machinery @@ -76,7 +84,7 @@ pub fn report_error<'tcx, 'mir>( #[rustfmt::skip] let helps = match info { UnsupportedInIsolation(_) => - vec![(None, format!("pass the flag `-Zmiri-disable-isolation` to disable isolation"))], + vec![(None, format!("pass the flag `-Zmiri-disable-isolation` to disable isolation; or pass `-Zmiri-isolation-error=warn to configure Miri to return an error code from isolated operations and continue with a warning"))], ExperimentalUb { url, .. } => vec![ (None, format!("this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental")), @@ -137,7 +145,7 @@ pub fn report_error<'tcx, 'mir>( let msg = e.to_string(); report_msg( *ecx.tcx, - /*error*/ true, + DiagLevel::Error, &if let Some(title) = title { format!("{}: {}", title, msg) } else { msg.clone() }, msg, helps, @@ -174,18 +182,19 @@ pub fn report_error<'tcx, 'mir>( /// Also emits a full stacktrace of the interpreter stack. fn report_msg<'tcx>( tcx: TyCtxt<'tcx>, - error: bool, + diag_level: DiagLevel, title: &str, span_msg: String, mut helps: Vec<(Option, String)>, stacktrace: &[FrameInfo<'tcx>], ) { let span = stacktrace.first().map_or(DUMMY_SP, |fi| fi.span); - let mut err = if error { - tcx.sess.struct_span_err(span, title) - } else { - tcx.sess.diagnostic().span_note_diag(span, title) + let mut err = match diag_level { + DiagLevel::Error => tcx.sess.struct_span_err(span, title), + DiagLevel::Warning => tcx.sess.struct_span_warn(span, title), + DiagLevel::Note => tcx.sess.diagnostic().span_note_diag(span, title), }; + // Show main message. if span != DUMMY_SP { err.span_label(span, span_msg); @@ -303,15 +312,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx CreatedCallId(id) => format!("function call with id {}", id), CreatedAlloc(AllocId(id)) => format!("created allocation with id {}", id), FreedAlloc(AllocId(id)) => format!("freed allocation with id {}", id), + RejectedIsolatedOp(ref op) => + format!("`{}` was made to return an error due to isolation", op), }; - report_msg( - *this.tcx, - /*error*/ false, - "tracking was triggered", - msg, - vec![], - &stacktrace, - ); + + let (title, diag_level) = match e { + RejectedIsolatedOp(_) => + ("operation rejected by isolation", DiagLevel::Warning), + _ => ("tracking was triggered", DiagLevel::Note), + }; + + report_msg(*this.tcx, diag_level, title, msg, vec![], &stacktrace); } }); } diff --git a/src/eval.rs b/src/eval.rs index 6646783d349ca..f1fbeafd3cd78 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -22,6 +22,35 @@ pub enum AlignmentCheck { Int, } +#[derive(Copy, Clone, Debug, PartialEq)] +pub enum RejectOpWith { + /// Isolated op is rejected with an abort of the machine. + Abort, + + /// If not Abort, miri returns an error for an isolated op. + /// Following options determine if user should be warned about such error. + /// Do not print warning about rejected isolated op. + NoWarning, + + /// Print a warning about rejected isolated op, with backtrace. + Warning, + + /// Print a warning about rejected isolated op, without backtrace. + WarningWithoutBacktrace, +} + +#[derive(Copy, Clone, Debug, PartialEq)] +pub enum IsolatedOp { + /// Reject an op requiring communication with the host. By + /// default, miri rejects the op with an abort. If not, it returns + /// an error code, and prints a warning about it. Warning levels + /// are controlled by `RejectOpWith` enum. + Reject(RejectOpWith), + + /// Execute op requiring communication with the host, i.e. disable isolation. + Allow, +} + /// Configuration needed to spawn a Miri instance. #[derive(Clone)] pub struct MiriConfig { @@ -33,8 +62,8 @@ pub struct MiriConfig { pub check_alignment: AlignmentCheck, /// Controls function [ABI](Abi) checking. pub check_abi: bool, - /// Determines if communication with the host environment is enabled. - pub communicate: bool, + /// Action for an op requiring communication with the host. + pub isolated_op: IsolatedOp, /// Determines if memory leaks should be ignored. pub ignore_leaks: bool, /// Environment variables that should always be isolated from the host. @@ -68,7 +97,7 @@ impl Default for MiriConfig { stacked_borrows: true, check_alignment: AlignmentCheck::Int, check_abi: true, - communicate: false, + isolated_op: IsolatedOp::Reject(RejectOpWith::Abort), ignore_leaks: false, excluded_env_vars: vec![], args: vec![], @@ -233,7 +262,7 @@ pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) -> } SchedulingAction::ExecuteTimeoutCallback => { assert!( - ecx.machine.communicate, + ecx.machine.communicate(), "scheduler callbacks require disabled isolation, but the code \ that created the callback did not check it" ); diff --git a/src/helpers.rs b/src/helpers.rs index 52176342057e4..e9bedd1a11870 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -140,7 +140,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let mut data = vec![0; usize::try_from(len).unwrap()]; - if this.machine.communicate { + if this.machine.communicate() { // Fill the buffer using the host's rng. getrandom::getrandom(&mut data) .map_err(|err| err_unsup_format!("host getrandom failed: {}", err))?; @@ -391,12 +391,32 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// disabled. It returns an error using the `name` of the foreign function if this is not the /// case. fn check_no_isolation(&self, name: &str) -> InterpResult<'tcx> { - if !self.eval_context_ref().machine.communicate { - isolation_error(name)?; + if !self.eval_context_ref().machine.communicate() { + self.reject_in_isolation(name, RejectOpWith::Abort)?; } Ok(()) } + /// Helper function used inside the shims of foreign functions which reject the op + /// when isolation is enabled. It is used to print a warning/backtrace about the rejection. + fn reject_in_isolation(&self, op_name: &str, reject_with: RejectOpWith) -> InterpResult<'tcx> { + let this = self.eval_context_ref(); + match reject_with { + RejectOpWith::Abort => isolation_abort_error(op_name), + RejectOpWith::WarningWithoutBacktrace => { + this.tcx + .sess + .warn(&format!("`{}` was made to return an error due to isolation", op_name)); + Ok(()) + } + RejectOpWith::Warning => { + register_diagnostic(NonHaltingDiagnostic::RejectedIsolatedOp(op_name.to_string())); + Ok(()) + } + RejectOpWith::NoWarning => Ok(()), // no warning + } + } + /// Helper function used inside the shims of foreign functions to assert that the target OS /// is `target_os`. It panics showing a message with the `name` of the foreign function /// if this is not the case. @@ -651,7 +671,7 @@ where throw_ub_format!("incorrect number of arguments: got {}, expected {}", args.len(), N) } -pub fn isolation_error(name: &str) -> InterpResult<'static> { +pub fn isolation_abort_error(name: &str) -> InterpResult<'static> { throw_machine_stop!(TerminationInfo::UnsupportedInIsolation(format!( "{} not available when isolation is enabled", name, diff --git a/src/lib.rs b/src/lib.rs index 25806b472b603..8c0a19b6dfbdc 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -59,7 +59,9 @@ pub use crate::diagnostics::{ register_diagnostic, report_error, EvalContextExt as DiagnosticsEvalContextExt, NonHaltingDiagnostic, TerminationInfo, }; -pub use crate::eval::{create_ecx, eval_main, AlignmentCheck, MiriConfig}; +pub use crate::eval::{ + create_ecx, eval_main, AlignmentCheck, IsolatedOp, MiriConfig, RejectOpWith, +}; pub use crate::helpers::EvalContextExt as HelpersEvalContextExt; pub use crate::machine::{ AllocExtra, Evaluator, FrameData, MemoryExtra, MiriEvalContext, MiriEvalContextExt, diff --git a/src/machine.rs b/src/machine.rs index 9c49575ded324..752d213448250 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -263,9 +263,10 @@ pub struct Evaluator<'mir, 'tcx> { /// TLS state. pub(crate) tls: TlsData<'tcx>, - /// If enabled, the `env_vars` field is populated with the host env vars during initialization - /// and random number generation is delegated to the host. - pub(crate) communicate: bool, + /// What should Miri do when an op requires communicating with the host, + /// such as accessing host env vars, random number generation, and + /// file system access. + pub(crate) isolated_op: IsolatedOp, /// Whether to enforce the validity invariant. pub(crate) validate: bool, @@ -314,7 +315,7 @@ impl<'mir, 'tcx> Evaluator<'mir, 'tcx> { argv: None, cmd_line: None, tls: TlsData::default(), - communicate: config.communicate, + isolated_op: config.isolated_op, validate: config.validate, enforce_abi: config.check_abi, file_handler: Default::default(), @@ -328,6 +329,10 @@ impl<'mir, 'tcx> Evaluator<'mir, 'tcx> { exported_symbols_cache: FxHashMap::default(), } } + + pub(crate) fn communicate(&self) -> bool { + self.isolated_op == IsolatedOp::Allow + } } /// A rustc InterpCx for Miri. diff --git a/src/shims/env.rs b/src/shims/env.rs index a091697532231..9a68cf7bd539a 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -1,6 +1,7 @@ use std::convert::TryFrom; use std::env; use std::ffi::{OsStr, OsString}; +use std::io::{Error, ErrorKind}; use rustc_data_structures::fx::FxHashMap; use rustc_mir::interpret::Pointer; @@ -45,7 +46,7 @@ impl<'tcx> EnvVars<'tcx> { excluded_env_vars.push("TERM".to_owned()); } - if ecx.machine.communicate { + if ecx.machine.communicate() { for (name, value) in env::vars() { if !excluded_env_vars.contains(&name) { let var_ptr = match target_os { @@ -321,7 +322,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "`getcwd` is only available for the UNIX target family" ); - this.check_no_isolation("`getcwd`")?; + if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { + this.reject_in_isolation("getcwd", reject_with)?; + let err = Error::new(ErrorKind::NotFound, "rejected due to isolation"); + this.set_last_error_from_io_error(err)?; + return Ok(Scalar::null_ptr(&*this.tcx)); + } let buf = this.read_scalar(&buf_op)?.check_init()?; let size = this.read_scalar(&size_op)?.to_machine_usize(&*this.tcx)?; @@ -336,6 +342,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } Err(e) => this.set_last_error_from_io_error(e)?, } + Ok(Scalar::null_ptr(&*this.tcx)) } @@ -348,7 +355,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); this.assert_target_os("windows", "GetCurrentDirectoryW"); - this.check_no_isolation("`GetCurrentDirectoryW`")?; + if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { + this.reject_in_isolation("GetCurrentDirectoryW", reject_with)?; + let err = Error::new(ErrorKind::NotFound, "rejected due to isolation"); + this.set_last_error_from_io_error(err)?; + return Ok(0); + } let size = u64::from(this.read_scalar(size_op)?.to_u32()?); let buf = this.read_scalar(buf_op)?.check_init()?; @@ -370,7 +382,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "`getcwd` is only available for the UNIX target family" ); - this.check_no_isolation("`chdir`")?; + if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { + this.reject_in_isolation("chdir", reject_with)?; + let err = Error::new(ErrorKind::NotFound, "rejected due to isolation"); + this.set_last_error_from_io_error(err)?; + + return Ok(-1); + } let path = this.read_path_from_c_str(this.read_scalar(path_op)?.check_init()?)?; @@ -393,7 +411,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); this.assert_target_os("windows", "SetCurrentDirectoryW"); - this.check_no_isolation("`SetCurrentDirectoryW`")?; + if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { + this.reject_in_isolation("SetCurrentDirectoryW", reject_with)?; + let err = Error::new(ErrorKind::NotFound, "rejected due to isolation"); + this.set_last_error_from_io_error(err)?; + + return Ok(0); + } let path = this.read_path_from_wide_str(this.read_scalar(path_op)?.check_init()?)?; diff --git a/src/shims/posix/fs.rs b/src/shims/posix/fs.rs index 06594e5ca1d6a..ca7a91a0f94e6 100644 --- a/src/shims/posix/fs.rs +++ b/src/shims/posix/fs.rs @@ -127,7 +127,7 @@ impl FileDescriptor for io::Stdin { ) -> InterpResult<'tcx, io::Result> { if !communicate_allowed { // We want isolation mode to be deterministic, so we have to disallow all reads, even stdin. - helpers::isolation_error("`read` from stdin")?; + helpers::isolation_abort_error("`read` from stdin")?; } Ok(Read::read(self, bytes)) } @@ -662,7 +662,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let fd = this.read_scalar(fd_op)?.to_i32()?; if let Some(file_descriptor) = this.machine.file_handler.handles.remove(&fd) { - let result = file_descriptor.close(this.machine.communicate)?; + let result = file_descriptor.close(this.machine.communicate())?; this.try_unwrap_io_result(result) } else { this.handle_not_found() @@ -687,6 +687,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // We cap the number of read bytes to the largest value that we are able to fit in both the // host's and target's `isize`. This saves us from having to handle overflows later. let count = count.min(this.machine_isize_max() as u64).min(isize::MAX as u64); + let communicate = this.machine.communicate(); if let Some(file_descriptor) = this.machine.file_handler.handles.get_mut(&fd) { trace!("read: FD mapped to {:?}", file_descriptor); @@ -696,9 +697,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let mut bytes = vec![0; count as usize]; // `File::read` never returns a value larger than `count`, // so this cannot fail. - let result = file_descriptor - .read(this.machine.communicate, &mut bytes)? - .map(|c| i64::try_from(c).unwrap()); + let result = + file_descriptor.read(communicate, &mut bytes)?.map(|c| i64::try_from(c).unwrap()); match result { Ok(read_bytes) => { @@ -733,12 +733,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // We cap the number of written bytes to the largest value that we are able to fit in both the // host's and target's `isize`. This saves us from having to handle overflows later. let count = count.min(this.machine_isize_max() as u64).min(isize::MAX as u64); + let communicate = this.machine.communicate(); if let Some(file_descriptor) = this.machine.file_handler.handles.get_mut(&fd) { let bytes = this.memory.read_bytes(buf, Size::from_bytes(count))?; - let result = file_descriptor - .write(this.machine.communicate, &bytes)? - .map(|c| i64::try_from(c).unwrap()); + let result = + file_descriptor.write(communicate, &bytes)?.map(|c| i64::try_from(c).unwrap()); this.try_unwrap_io_result(result) } else { this.handle_not_found() @@ -771,9 +771,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx return Ok(-1); }; + let communicate = this.machine.communicate(); if let Some(file_descriptor) = this.machine.file_handler.handles.get_mut(&fd) { let result = file_descriptor - .seek(this.machine.communicate, seek_from)? + .seek(communicate, seek_from)? .map(|offset| i64::try_from(offset).unwrap()); this.try_unwrap_io_result(result) } else { diff --git a/tests/run-pass/current_dir_with_isolation.rs b/tests/run-pass/current_dir_with_isolation.rs new file mode 100644 index 0000000000000..ea891c8998342 --- /dev/null +++ b/tests/run-pass/current_dir_with_isolation.rs @@ -0,0 +1,20 @@ +// compile-flags: -Zmiri-isolation-error=warn-nobacktrace +// normalize-stderr-test "(getcwd|GetCurrentDirectoryW)" -> "$$GET" +// normalize-stderr-test "(chdir|SetCurrentDirectoryW)" -> "$$SET" + +use std::env; +use std::io::ErrorKind; + +fn main() { + // Test that current dir operations return a proper error instead + // of stopping the machine in isolation mode + assert_eq!(env::current_dir().unwrap_err().kind(), ErrorKind::NotFound); + for _i in 0..3 { + assert_eq!(env::current_dir().unwrap_err().kind(), ErrorKind::NotFound); + } + + assert_eq!(env::set_current_dir("..").unwrap_err().kind(), ErrorKind::NotFound); + for _i in 0..3 { + assert_eq!(env::set_current_dir("..").unwrap_err().kind(), ErrorKind::NotFound); + } +} diff --git a/tests/run-pass/current_dir_with_isolation.stderr b/tests/run-pass/current_dir_with_isolation.stderr new file mode 100644 index 0000000000000..cc0975230de68 --- /dev/null +++ b/tests/run-pass/current_dir_with_isolation.stderr @@ -0,0 +1,4 @@ +warning: `$GET` was made to return an error due to isolation + +warning: `$SET` was made to return an error due to isolation + From ba64f485c881052c980648bed0b4ce29fb6dc19c Mon Sep 17 00:00:00 2001 From: Smit Soni Date: Wed, 9 Jun 2021 06:28:35 -0700 Subject: [PATCH 2718/3747] Fix parameter of io error helper function `set_last_error_from_io_error` works with only the error kind, and discards the payload. Fix its signature to make it explicit. --- src/helpers.rs | 19 +++++++++++-------- src/shims/env.rs | 22 +++++++++------------- src/shims/posix/fs.rs | 10 +++++----- 3 files changed, 25 insertions(+), 26 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index e9bedd1a11870..8bfc65111d492 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -460,15 +460,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.read_scalar(&errno_place.into())?.check_init() } - /// Sets the last OS error using a `std::io::Error`. This function tries to produce the most + /// Sets the last OS error using a `std::io::ErrorKind`. This function tries to produce the most /// similar OS error from the `std::io::ErrorKind` and sets it as the last OS error. - fn set_last_error_from_io_error(&mut self, e: std::io::Error) -> InterpResult<'tcx> { + fn set_last_error_from_io_error(&mut self, err_kind: std::io::ErrorKind) -> InterpResult<'tcx> { use std::io::ErrorKind::*; let this = self.eval_context_mut(); let target = &this.tcx.sess.target; let target_os = &target.os; let last_error = if target.families.contains(&"unix".to_owned()) { - this.eval_libc(match e.kind() { + this.eval_libc(match err_kind { ConnectionRefused => "ECONNREFUSED", ConnectionReset => "ECONNRESET", PermissionDenied => "EPERM", @@ -484,18 +484,21 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx AlreadyExists => "EEXIST", WouldBlock => "EWOULDBLOCK", _ => { - throw_unsup_format!("io error {} cannot be transformed into a raw os error", e) + throw_unsup_format!( + "io error {:?} cannot be transformed into a raw os error", + err_kind + ) } })? } else if target.families.contains(&"windows".to_owned()) { // FIXME: we have to finish implementing the Windows equivalent of this. this.eval_windows( "c", - match e.kind() { + match err_kind { NotFound => "ERROR_FILE_NOT_FOUND", _ => throw_unsup_format!( - "io error {} cannot be transformed into a raw os error", - e + "io error {:?} cannot be transformed into a raw os error", + err_kind ), }, )? @@ -521,7 +524,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx match result { Ok(ok) => Ok(ok), Err(e) => { - self.eval_context_mut().set_last_error_from_io_error(e)?; + self.eval_context_mut().set_last_error_from_io_error(e.kind())?; Ok((-1).into()) } } diff --git a/src/shims/env.rs b/src/shims/env.rs index 9a68cf7bd539a..2ce0fbfdc949c 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -1,7 +1,7 @@ use std::convert::TryFrom; use std::env; use std::ffi::{OsStr, OsString}; -use std::io::{Error, ErrorKind}; +use std::io::ErrorKind; use rustc_data_structures::fx::FxHashMap; use rustc_mir::interpret::Pointer; @@ -324,8 +324,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { this.reject_in_isolation("getcwd", reject_with)?; - let err = Error::new(ErrorKind::NotFound, "rejected due to isolation"); - this.set_last_error_from_io_error(err)?; + this.set_last_error_from_io_error(ErrorKind::NotFound)?; return Ok(Scalar::null_ptr(&*this.tcx)); } @@ -340,7 +339,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let erange = this.eval_libc("ERANGE")?; this.set_last_error(erange)?; } - Err(e) => this.set_last_error_from_io_error(e)?, + Err(e) => this.set_last_error_from_io_error(e.kind())?, } Ok(Scalar::null_ptr(&*this.tcx)) @@ -357,8 +356,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { this.reject_in_isolation("GetCurrentDirectoryW", reject_with)?; - let err = Error::new(ErrorKind::NotFound, "rejected due to isolation"); - this.set_last_error_from_io_error(err)?; + this.set_last_error_from_io_error(ErrorKind::NotFound)?; return Ok(0); } @@ -369,7 +367,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx match env::current_dir() { Ok(cwd) => return Ok(windows_check_buffer_size(this.write_path_to_wide_str(&cwd, buf, size)?)), - Err(e) => this.set_last_error_from_io_error(e)?, + Err(e) => this.set_last_error_from_io_error(e.kind())?, } Ok(0) } @@ -384,8 +382,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { this.reject_in_isolation("chdir", reject_with)?; - let err = Error::new(ErrorKind::NotFound, "rejected due to isolation"); - this.set_last_error_from_io_error(err)?; + this.set_last_error_from_io_error(ErrorKind::NotFound)?; return Ok(-1); } @@ -395,7 +392,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx match env::set_current_dir(path) { Ok(()) => Ok(0), Err(e) => { - this.set_last_error_from_io_error(e)?; + this.set_last_error_from_io_error(e.kind())?; Ok(-1) } } @@ -413,8 +410,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { this.reject_in_isolation("SetCurrentDirectoryW", reject_with)?; - let err = Error::new(ErrorKind::NotFound, "rejected due to isolation"); - this.set_last_error_from_io_error(err)?; + this.set_last_error_from_io_error(ErrorKind::NotFound)?; return Ok(0); } @@ -424,7 +420,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx match env::set_current_dir(path) { Ok(()) => Ok(1), Err(e) => { - this.set_last_error_from_io_error(e)?; + this.set_last_error_from_io_error(e.kind())?; Ok(0) } } diff --git a/src/shims/posix/fs.rs b/src/shims/posix/fs.rs index ca7a91a0f94e6..fbef9f3040713 100644 --- a/src/shims/posix/fs.rs +++ b/src/shims/posix/fs.rs @@ -634,7 +634,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx match dup_result { Ok(dup_fd) => Ok(fh.insert_fd_with_min_fd(dup_fd, start)), Err(e) => { - this.set_last_error_from_io_error(e)?; + this.set_last_error_from_io_error(e.kind())?; Ok(-1) } } @@ -707,7 +707,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(read_bytes) } Err(e) => { - this.set_last_error_from_io_error(e)?; + this.set_last_error_from_io_error(e.kind())?; Ok(-1) } } @@ -1118,7 +1118,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(Scalar::from_machine_usize(id, this)) } Err(e) => { - this.set_last_error_from_io_error(e)?; + this.set_last_error_from_io_error(e.kind())?; Ok(Scalar::null_ptr(this)) } } @@ -1462,7 +1462,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(path_bytes.len().try_into().unwrap()) } Err(e) => { - this.set_last_error_from_io_error(e)?; + this.set_last_error_from_io_error(e.kind())?; Ok(-1) } } @@ -1526,7 +1526,7 @@ impl FileMetadata { let metadata = match metadata { Ok(metadata) => metadata, Err(e) => { - ecx.set_last_error_from_io_error(e)?; + ecx.set_last_error_from_io_error(e.kind())?; return Ok(None); } }; From a38f02c44c56c2b6378e18ae238f4178db7eafd9 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 9 Jun 2021 18:21:23 +0200 Subject: [PATCH 2719/3747] isolated operations return EPERM; tweak isolation hint --- src/diagnostics.rs | 5 ++++- src/helpers.rs | 5 +++-- src/shims/env.rs | 8 ++++---- tests/run-pass/current_dir_with_isolation.rs | 13 +++++++------ tests/run-pass/current_dir_with_isolation.stderr | 4 ++-- 5 files changed, 20 insertions(+), 15 deletions(-) diff --git a/src/diagnostics.rs b/src/diagnostics.rs index 2b17e83bee698..1687297bde7c0 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -84,7 +84,10 @@ pub fn report_error<'tcx, 'mir>( #[rustfmt::skip] let helps = match info { UnsupportedInIsolation(_) => - vec![(None, format!("pass the flag `-Zmiri-disable-isolation` to disable isolation; or pass `-Zmiri-isolation-error=warn to configure Miri to return an error code from isolated operations and continue with a warning"))], + vec![ + (None, format!("pass the flag `-Zmiri-disable-isolation` to disable isolation;")), + (None, format!("or pass `-Zmiri-isolation-error=warn to configure Miri to return an error code from isolated operations (if supported for that operation) and continue with a warning")), + ], ExperimentalUb { url, .. } => vec![ (None, format!("this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental")), diff --git a/src/helpers.rs b/src/helpers.rs index 8bfc65111d492..8586d732dce6b 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -485,7 +485,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx WouldBlock => "EWOULDBLOCK", _ => { throw_unsup_format!( - "io error {:?} cannot be transformed into a raw os error", + "io error {:?} cannot be translated into a raw os error", err_kind ) } @@ -496,8 +496,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "c", match err_kind { NotFound => "ERROR_FILE_NOT_FOUND", + PermissionDenied => "ERROR_ACCESS_DENIED", _ => throw_unsup_format!( - "io error {:?} cannot be transformed into a raw os error", + "io error {:?} cannot be translated into a raw os error", err_kind ), }, diff --git a/src/shims/env.rs b/src/shims/env.rs index 2ce0fbfdc949c..0c42daa2446a0 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -324,7 +324,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { this.reject_in_isolation("getcwd", reject_with)?; - this.set_last_error_from_io_error(ErrorKind::NotFound)?; + this.set_last_error_from_io_error(ErrorKind::PermissionDenied)?; return Ok(Scalar::null_ptr(&*this.tcx)); } @@ -356,7 +356,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { this.reject_in_isolation("GetCurrentDirectoryW", reject_with)?; - this.set_last_error_from_io_error(ErrorKind::NotFound)?; + this.set_last_error_from_io_error(ErrorKind::PermissionDenied)?; return Ok(0); } @@ -382,7 +382,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { this.reject_in_isolation("chdir", reject_with)?; - this.set_last_error_from_io_error(ErrorKind::NotFound)?; + this.set_last_error_from_io_error(ErrorKind::PermissionDenied)?; return Ok(-1); } @@ -410,7 +410,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { this.reject_in_isolation("SetCurrentDirectoryW", reject_with)?; - this.set_last_error_from_io_error(ErrorKind::NotFound)?; + this.set_last_error_from_io_error(ErrorKind::PermissionDenied)?; return Ok(0); } diff --git a/tests/run-pass/current_dir_with_isolation.rs b/tests/run-pass/current_dir_with_isolation.rs index ea891c8998342..b5fe6114b2f3f 100644 --- a/tests/run-pass/current_dir_with_isolation.rs +++ b/tests/run-pass/current_dir_with_isolation.rs @@ -1,6 +1,6 @@ // compile-flags: -Zmiri-isolation-error=warn-nobacktrace -// normalize-stderr-test "(getcwd|GetCurrentDirectoryW)" -> "$$GET" -// normalize-stderr-test "(chdir|SetCurrentDirectoryW)" -> "$$SET" +// normalize-stderr-test "(getcwd|GetCurrentDirectoryW)" -> "$$GETCWD" +// normalize-stderr-test "(chdir|SetCurrentDirectoryW)" -> "$$SETCWD" use std::env; use std::io::ErrorKind; @@ -8,13 +8,14 @@ use std::io::ErrorKind; fn main() { // Test that current dir operations return a proper error instead // of stopping the machine in isolation mode - assert_eq!(env::current_dir().unwrap_err().kind(), ErrorKind::NotFound); + assert_eq!(env::current_dir().unwrap_err().kind(), ErrorKind::PermissionDenied); for _i in 0..3 { - assert_eq!(env::current_dir().unwrap_err().kind(), ErrorKind::NotFound); + // Ensure we get no repeated warnings when doing this multiple times. + assert_eq!(env::current_dir().unwrap_err().kind(), ErrorKind::PermissionDenied); } - assert_eq!(env::set_current_dir("..").unwrap_err().kind(), ErrorKind::NotFound); + assert_eq!(env::set_current_dir("..").unwrap_err().kind(), ErrorKind::PermissionDenied); for _i in 0..3 { - assert_eq!(env::set_current_dir("..").unwrap_err().kind(), ErrorKind::NotFound); + assert_eq!(env::set_current_dir("..").unwrap_err().kind(), ErrorKind::PermissionDenied); } } diff --git a/tests/run-pass/current_dir_with_isolation.stderr b/tests/run-pass/current_dir_with_isolation.stderr index cc0975230de68..589ca65a1e47e 100644 --- a/tests/run-pass/current_dir_with_isolation.stderr +++ b/tests/run-pass/current_dir_with_isolation.stderr @@ -1,4 +1,4 @@ -warning: `$GET` was made to return an error due to isolation +warning: `$GETCWD` was made to return an error due to isolation -warning: `$SET` was made to return an error due to isolation +warning: `$SETCWD` was made to return an error due to isolation From 87f2073c80c9cdec9e0b4c87ec54a531f2abb4df Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 9 Jun 2021 21:09:17 +0200 Subject: [PATCH 2720/3747] tweak isolation-error message in README --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index f6b46ce3a95c5..cf4689d08fb62 100644 --- a/README.md +++ b/README.md @@ -221,11 +221,11 @@ environment variable: systems, and randomness. * `-Zmiri-isolation-error=` configures Miri's response to operations requiring host access while isolation is enabled. `abort`, `hide`, `warn`, - and `warn-nobacktrace` are the supported actions. Default action is `abort` - which halts the machine. Rest of the actions configure it to return an error - code for the op and continue executing. `warn` prints backtrace that could - be used to trace the call. `warn-nobacktrace` is less verbose without - backtrace. `hide` hides the warning. + and `warn-nobacktrace` are the supported actions. The default is to `abort`, + which halts the machine. Some (but not all) operations also support continuing + execution with a "permission denied" error being returned to the program. + `warn` prints a full backtrace when that happen; `warn-nobacktrace` is less + verbose. `hide` hides the warning entirely. * `-Zmiri-env-exclude=` keeps the `var` environment variable isolated from the host so that it cannot be accessed by the program. Can be used multiple times to exclude several variables. On Windows, the `TERM` environment From 4f3718ef85199da1ce5016a5df382ee396552290 Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Fri, 11 Jun 2021 11:13:16 +0800 Subject: [PATCH 2721/3747] Fix the wrong `EmulateByNameResult::NotSupported` in `syscall` shim --- src/shims/posix/linux/foreign_items.rs | 2 +- tests/run-pass/panic/unsupported_syscall.rs | 12 ++++++++++++ tests/run-pass/panic/unsupported_syscall.stderr | 2 ++ 3 files changed, 15 insertions(+), 1 deletion(-) create mode 100644 tests/run-pass/panic/unsupported_syscall.rs create mode 100644 tests/run-pass/panic/unsupported_syscall.stderr diff --git a/src/shims/posix/linux/foreign_items.rs b/src/shims/posix/linux/foreign_items.rs index 68ae704fb04f2..178b82f613115 100644 --- a/src/shims/posix/linux/foreign_items.rs +++ b/src/shims/posix/linux/foreign_items.rs @@ -185,7 +185,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } id => { this.handle_unsupported(format!("can't execute syscall with ID {}", id))?; - return Ok(EmulateByNameResult::NotSupported); + return Ok(EmulateByNameResult::AlreadyJumped); } } } diff --git a/tests/run-pass/panic/unsupported_syscall.rs b/tests/run-pass/panic/unsupported_syscall.rs new file mode 100644 index 0000000000000..854f179392c41 --- /dev/null +++ b/tests/run-pass/panic/unsupported_syscall.rs @@ -0,0 +1,12 @@ +// ignore-windows: No libc on Windows +// ignore-macos: `syscall` is not supported on macOS +// compile-flags: -Zmiri-panic-on-unsupported +#![feature(rustc_private)] + +extern crate libc; + +fn main() { + unsafe { + libc::syscall(0); + } +} diff --git a/tests/run-pass/panic/unsupported_syscall.stderr b/tests/run-pass/panic/unsupported_syscall.stderr new file mode 100644 index 0000000000000..49796ee2021fe --- /dev/null +++ b/tests/run-pass/panic/unsupported_syscall.stderr @@ -0,0 +1,2 @@ +thread 'main' panicked at 'unsupported Miri functionality: can't execute syscall with ID 0', $DIR/unsupported_syscall.rs:10:9 +note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace From 6aef1d687d6330fedb468e77e28940a6ea6ddb8b Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Tue, 8 Jun 2021 20:36:21 +0800 Subject: [PATCH 2722/3747] Remove erroneous `exit()` and `ExitProcess()` in `tests/run-pass/function_calls/exported_symbol.rs` --- tests/run-pass/function_calls/exported_symbol.rs | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/tests/run-pass/function_calls/exported_symbol.rs b/tests/run-pass/function_calls/exported_symbol.rs index 96bf8170c6eb1..c141f557e1d79 100644 --- a/tests/run-pass/function_calls/exported_symbol.rs +++ b/tests/run-pass/function_calls/exported_symbol.rs @@ -15,17 +15,6 @@ fn baz() -> i32 { -3 } -// Make sure shims take precedence. -#[no_mangle] -extern "C" fn exit(_: i32) -> ! { - unreachable!() -} - -#[no_mangle] -extern "C" fn ExitProcess(_: u32) -> ! { - unreachable!() -} - fn main() { // Repeat calls to make sure the `Instance` cache is not broken. for _ in 0..3 { From ce7040075adea348beae45e9aa2af2a2f25dfc18 Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Sun, 6 Jun 2021 15:25:16 +0800 Subject: [PATCH 2723/3747] Disallow `#[no_mangle]`/`#[export_name = ...]` functions that have the same symbol name as built-in shims --- src/diagnostics.rs | 13 +- src/helpers.rs | 31 +++ src/shims/backtrace.rs | 13 +- src/shims/foreign_items.rs | 88 ++++---- src/shims/panic.rs | 5 +- src/shims/posix/foreign_items.rs | 189 ++++++------------ src/shims/posix/linux/foreign_items.rs | 64 +++--- src/shims/posix/macos/foreign_items.rs | 74 ++++--- src/shims/windows/foreign_items.rs | 164 +++++++-------- .../exported_symbol_shim_clashing.rs | 15 ++ 10 files changed, 320 insertions(+), 336 deletions(-) create mode 100644 tests/compile-fail/function_calls/exported_symbol_shim_clashing.rs diff --git a/src/diagnostics.rs b/src/diagnostics.rs index 1687297bde7c0..887b2ac4b378b 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -26,6 +26,10 @@ pub enum TerminationInfo { second: SpanData, second_crate: Symbol, }, + SymbolShimClashing { + link_name: Symbol, + span: SpanData, + }, } impl fmt::Display for TerminationInfo { @@ -39,6 +43,11 @@ impl fmt::Display for TerminationInfo { Deadlock => write!(f, "the evaluated program deadlocked"), MultipleSymbolDefinitions { link_name, .. } => write!(f, "multiple definitions of symbol `{}`", link_name), + SymbolShimClashing { link_name, .. } => write!( + f, + "found `{}` symbol definition that clashes with a built-in shim", + link_name + ), } } } @@ -79,7 +88,7 @@ pub fn report_error<'tcx, 'mir>( UnsupportedInIsolation(_) => Some("unsupported operation"), ExperimentalUb { .. } => Some("Undefined Behavior"), Deadlock => Some("deadlock"), - MultipleSymbolDefinitions { .. } => None, + MultipleSymbolDefinitions { .. } | SymbolShimClashing { .. } => None, }; #[rustfmt::skip] let helps = match info { @@ -98,6 +107,8 @@ pub fn report_error<'tcx, 'mir>( (Some(*first), format!("it's first defined here, in crate `{}`", first_crate)), (Some(*second), format!("then it's defined here again, in crate `{}`", second_crate)), ], + SymbolShimClashing { link_name, span } => + vec![(Some(*span), format!("the `{}` symbol is defined here", link_name))], _ => vec![], }; (title, helps) diff --git a/src/helpers.rs b/src/helpers.rs index e0f273be34351..b99a446577ac4 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -8,6 +8,7 @@ use log::trace; use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX}; use rustc_middle::mir; use rustc_middle::ty::{self, layout::TyAndLayout, List, TyCtxt}; +use rustc_span::Symbol; use rustc_target::abi::{Align, FieldsShape, LayoutOf, Size, Variants}; use rustc_target::spec::abi::Abi; @@ -677,6 +678,36 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx throw_unsup_format!("{}", error_msg.as_ref()); } } + + fn check_abi_and_shim_symbol_clash( + &mut self, + abi: Abi, + exp_abi: Abi, + link_name: Symbol, + ) -> InterpResult<'tcx, ()> { + self.check_abi(abi, exp_abi)?; + if let Some(body) = self.eval_context_mut().lookup_exported_symbol(link_name)? { + throw_machine_stop!(TerminationInfo::SymbolShimClashing { + link_name, + span: body.span.data(), + }) + } + Ok(()) + } + + fn check_shim<'a, const N: usize>( + &mut self, + abi: Abi, + exp_abi: Abi, + link_name: Symbol, + args: &'a [OpTy<'tcx, Tag>], + ) -> InterpResult<'tcx, &'a [OpTy<'tcx, Tag>; N]> + where + &'a [OpTy<'tcx, Tag>; N]: TryFrom<&'a [OpTy<'tcx, Tag>]>, + { + self.check_abi_and_shim_symbol_clash(abi, exp_abi, link_name)?; + check_arg_count(args) + } } /// Check that the number of args is what we expect. diff --git a/src/shims/backtrace.rs b/src/shims/backtrace.rs index e866868d729fa..4ea374344c0dd 100644 --- a/src/shims/backtrace.rs +++ b/src/shims/backtrace.rs @@ -1,22 +1,23 @@ use crate::rustc_target::abi::LayoutOf as _; use crate::*; -use helpers::check_arg_count; use rustc_ast::ast::Mutability; use rustc_middle::ty::{self, TypeAndMut}; -use rustc_span::BytePos; -use rustc_target::abi::Size; +use rustc_span::{BytePos, Symbol}; +use rustc_target::{abi::Size, spec::abi::Abi}; use std::convert::TryInto as _; impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { fn handle_miri_get_backtrace( &mut self, + abi: Abi, + link_name: Symbol, args: &[OpTy<'tcx, Tag>], dest: &PlaceTy<'tcx, Tag>, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let tcx = this.tcx; - let &[ref flags] = check_arg_count(args)?; + let &[ref flags] = this.check_shim(abi, Abi::Rust, link_name, args)?; let flags = this.read_scalar(flags)?.to_u64()?; if flags != 0 { @@ -71,12 +72,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn handle_miri_resolve_frame( &mut self, + abi: Abi, + link_name: Symbol, args: &[OpTy<'tcx, Tag>], dest: &PlaceTy<'tcx, Tag>, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let tcx = this.tcx; - let &[ref ptr, ref flags] = check_arg_count(args)?; + let &[ref ptr, ref flags] = this.check_shim(abi, Abi::Rust, link_name, args)?; let flags = this.read_scalar(flags)?.to_u64()?; if flags != 0 { diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 8f3dfdc4f81fa..f193751518e18 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -25,7 +25,6 @@ use rustc_target::{ use super::backtrace::EvalContextExt as _; use crate::*; -use helpers::check_arg_count; /// Returned by `emulate_foreign_item_by_name`. pub enum EmulateByNameResult { @@ -227,14 +226,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let (dest, ret) = match ret { None => match link_name { "miri_start_panic" => { - this.check_abi(abi, Abi::Rust)?; - this.handle_miri_start_panic(args, unwind)?; + this.handle_miri_start_panic(abi, link_name_sym, args, unwind)?; return Ok(None); } // This matches calls to the foreign item `panic_impl`. // The implementation is provided by the function with the `#[panic_handler]` attribute. "panic_impl" => { - this.check_abi(abi, Abi::Rust)?; + this.check_abi_and_shim_symbol_clash(abi, Abi::Rust, link_name_sym)?; let panic_impl_id = tcx.lang_items().panic_impl().unwrap(); let panic_impl_instance = ty::Instance::mono(tcx, panic_impl_id); return Ok(Some(&*this.load_mir(panic_impl_instance.def, None)?)); @@ -243,14 +241,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "exit" | "ExitProcess" => { - this.check_abi(abi, if link_name == "exit" { Abi::C { unwind: false } } else { Abi::System { unwind: false } })?; - let &[ref code] = check_arg_count(args)?; + let &[ref code] = this.check_shim(abi, if link_name == "exit" { Abi::C { unwind: false } } else { Abi::System { unwind: false } }, link_name_sym, args)?; // it's really u32 for ExitProcess, but we have to put it into the `Exit` variant anyway let code = this.read_scalar(code)?.to_i32()?; throw_machine_stop!(TerminationInfo::Exit(code.into())); } "abort" => { - this.check_abi(abi, Abi::C { unwind: false })?; + this.check_abi_and_shim_symbol_clash( + abi, + Abi::C { unwind: false }, + link_name_sym, + )?; throw_machine_stop!(TerminationInfo::Abort( "the program aborted execution".to_owned() )) @@ -270,7 +271,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx }; // Second: functions that return. - match this.emulate_foreign_item_by_name(link_name, abi, args, dest, ret)? { + match this.emulate_foreign_item_by_name(link_name, link_name_sym, abi, args, dest, ret)? { EmulateByNameResult::NeedsJumping => { trace!("{:?}", this.dump_place(**dest)); this.go_to_block(ret); @@ -293,6 +294,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn emulate_foreign_item_by_name( &mut self, link_name: &str, + link_name_sym: Symbol, abi: Abi, args: &[OpTy<'tcx, Tag>], dest: &PlaceTy<'tcx, Tag>, @@ -305,8 +307,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx match link_name { // Miri-specific extern functions "miri_static_root" => { - this.check_abi(abi, Abi::Rust)?; - let &[ref ptr] = check_arg_count(args)?; + let &[ref ptr] = this.check_shim(abi, Abi::Rust, link_name_sym, args)?; let ptr = this.read_scalar(ptr)?.check_init()?; let ptr = this.force_ptr(ptr)?; if ptr.offset != Size::ZERO { @@ -317,28 +318,24 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Obtains a Miri backtrace. See the README for details. "miri_get_backtrace" => { - this.check_abi(abi, Abi::Rust)?; - this.handle_miri_get_backtrace(args, dest)?; + this.handle_miri_get_backtrace(abi, link_name_sym, args, dest)?; } // Resolves a Miri backtrace frame. See the README for details. "miri_resolve_frame" => { - this.check_abi(abi, Abi::Rust)?; - this.handle_miri_resolve_frame(args, dest)?; + this.handle_miri_resolve_frame(abi, link_name_sym, args, dest)?; } // Standard C allocation "malloc" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref size] = check_arg_count(args)?; + let &[ref size] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let size = this.read_scalar(size)?.to_machine_usize(this)?; let res = this.malloc(size, /*zero_init:*/ false, MiriMemoryKind::C); this.write_scalar(res, dest)?; } "calloc" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref items, ref len] = check_arg_count(args)?; + let &[ref items, ref len] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let items = this.read_scalar(items)?.to_machine_usize(this)?; let len = this.read_scalar(len)?.to_machine_usize(this)?; let size = @@ -347,14 +344,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(res, dest)?; } "free" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref ptr] = check_arg_count(args)?; + let &[ref ptr] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let ptr = this.read_scalar(ptr)?.check_init()?; this.free(ptr, MiriMemoryKind::C)?; } "realloc" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref old_ptr, ref new_size] = check_arg_count(args)?; + let &[ref old_ptr, ref new_size] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let old_ptr = this.read_scalar(old_ptr)?.check_init()?; let new_size = this.read_scalar(new_size)?.to_machine_usize(this)?; let res = this.realloc(old_ptr, new_size, MiriMemoryKind::C)?; @@ -365,8 +360,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // (Usually these would be forwarded to to `#[global_allocator]`; we instead implement a generic // allocation that also checks that all conditions are met, such as not permitting zero-sized allocations.) "__rust_alloc" => { - this.check_abi(abi, Abi::Rust)?; - let &[ref size, ref align] = check_arg_count(args)?; + let &[ref size, ref align] = this.check_shim(abi, Abi::Rust, link_name_sym, args)?; let size = this.read_scalar(size)?.to_machine_usize(this)?; let align = this.read_scalar(align)?.to_machine_usize(this)?; Self::check_alloc_request(size, align)?; @@ -378,8 +372,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(ptr, dest)?; } "__rust_alloc_zeroed" => { - this.check_abi(abi, Abi::Rust)?; - let &[ref size, ref align] = check_arg_count(args)?; + let &[ref size, ref align] = this.check_shim(abi, Abi::Rust, link_name_sym, args)?; let size = this.read_scalar(size)?.to_machine_usize(this)?; let align = this.read_scalar(align)?.to_machine_usize(this)?; Self::check_alloc_request(size, align)?; @@ -393,8 +386,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(ptr, dest)?; } "__rust_dealloc" => { - this.check_abi(abi, Abi::Rust)?; - let &[ref ptr, ref old_size, ref align] = check_arg_count(args)?; + let &[ref ptr, ref old_size, ref align] = this.check_shim(abi, Abi::Rust, link_name_sym, args)?; let ptr = this.read_scalar(ptr)?.check_init()?; let old_size = this.read_scalar(old_size)?.to_machine_usize(this)?; let align = this.read_scalar(align)?.to_machine_usize(this)?; @@ -407,8 +399,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx )?; } "__rust_realloc" => { - this.check_abi(abi, Abi::Rust)?; - let &[ref ptr, ref old_size, ref align, ref new_size] = check_arg_count(args)?; + let &[ref ptr, ref old_size, ref align, ref new_size] = this.check_shim(abi, Abi::Rust, link_name_sym, args)?; let ptr = this.force_ptr(this.read_scalar(ptr)?.check_init()?)?; let old_size = this.read_scalar(old_size)?.to_machine_usize(this)?; let align = this.read_scalar(align)?.to_machine_usize(this)?; @@ -428,8 +419,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // C memory handling functions "memcmp" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref left, ref right, ref n] = check_arg_count(args)?; + let &[ref left, ref right, ref n] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let left = this.read_scalar(left)?.check_init()?; let right = this.read_scalar(right)?.check_init()?; let n = Size::from_bytes(this.read_scalar(n)?.to_machine_usize(this)?); @@ -449,8 +439,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_i32(result), dest)?; } "memrchr" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref ptr, ref val, ref num] = check_arg_count(args)?; + let &[ref ptr, ref val, ref num] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let ptr = this.read_scalar(ptr)?.check_init()?; let val = this.read_scalar(val)?.to_i32()? as u8; let num = this.read_scalar(num)?.to_machine_usize(this)?; @@ -468,8 +457,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } "memchr" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref ptr, ref val, ref num] = check_arg_count(args)?; + let &[ref ptr, ref val, ref num] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let ptr = this.read_scalar(ptr)?.check_init()?; let val = this.read_scalar(val)?.to_i32()? as u8; let num = this.read_scalar(num)?.to_machine_usize(this)?; @@ -486,8 +474,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } "strlen" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref ptr] = check_arg_count(args)?; + let &[ref ptr] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let ptr = this.read_scalar(ptr)?.check_init()?; let n = this.read_c_str(ptr)?.len(); this.write_scalar(Scalar::from_machine_usize(u64::try_from(n).unwrap(), this), dest)?; @@ -503,8 +490,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "asinf" | "atanf" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref f] = check_arg_count(args)?; + let &[ref f] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; // FIXME: Using host floats. let f = f32::from_bits(this.read_scalar(f)?.to_u32()?); let f = match link_name { @@ -524,8 +510,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "hypotf" | "atan2f" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref f1, ref f2] = check_arg_count(args)?; + let &[ref f1, ref f2] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; // underscore case for windows, here and below // (see https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/floating-point-primitives?view=vs-2019) // FIXME: Using host floats. @@ -547,8 +532,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "asin" | "atan" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref f] = check_arg_count(args)?; + let &[ref f] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; // FIXME: Using host floats. let f = f64::from_bits(this.read_scalar(f)?.to_u64()?); let f = match link_name { @@ -568,8 +552,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "hypot" | "atan2" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref f1, ref f2] = check_arg_count(args)?; + let &[ref f1, ref f2] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; // FIXME: Using host floats. let f1 = f64::from_bits(this.read_scalar(f1)?.to_u64()?); let f2 = f64::from_bits(this.read_scalar(f2)?.to_u64()?); @@ -585,8 +568,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "ldexp" | "scalbn" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref x, ref exp] = check_arg_count(args)?; + let &[ref x, ref exp] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; // For radix-2 (binary) systems, `ldexp` and `scalbn` are the same. let x = this.read_scalar(x)?.to_f64()?; let exp = this.read_scalar(exp)?.to_i32()?; @@ -607,13 +589,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Architecture-specific shims "llvm.x86.sse2.pause" if this.tcx.sess.target.arch == "x86" || this.tcx.sess.target.arch == "x86_64" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[] = check_arg_count(args)?; + let &[] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; this.yield_active_thread(); } "llvm.aarch64.isb" if this.tcx.sess.target.arch == "aarch64" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref arg] = check_arg_count(args)?; + let &[ref arg] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let arg = this.read_scalar(arg)?.to_i32()?; match arg { 15 => { // SY ("full system scope") @@ -627,8 +607,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Platform-specific shims _ => match this.tcx.sess.target.os.as_str() { - "linux" | "macos" => return shims::posix::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, abi, args, dest, ret), - "windows" => return shims::windows::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, abi, args, dest, ret), + "linux" | "macos" => return shims::posix::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, link_name_sym, abi, args, dest, ret), + "windows" => return shims::windows::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, link_name_sym, abi, args, dest, ret), target => throw_unsup_format!("the target `{}` is not supported", target), } }; diff --git a/src/shims/panic.rs b/src/shims/panic.rs index 15620c73f0dab..68b648f32718a 100644 --- a/src/shims/panic.rs +++ b/src/shims/panic.rs @@ -15,6 +15,7 @@ use log::trace; use rustc_ast::Mutability; use rustc_middle::{mir, ty}; +use rustc_span::Symbol; use rustc_target::spec::abi::Abi; use rustc_target::spec::PanicStrategy; @@ -40,6 +41,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// by libpanic_unwind to delegate the actual unwinding process to Miri. fn handle_miri_start_panic( &mut self, + abi: Abi, + link_name: Symbol, args: &[OpTy<'tcx, Tag>], unwind: StackPopUnwind, ) -> InterpResult<'tcx> { @@ -48,7 +51,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx trace!("miri_start_panic: {:?}", this.frame().instance); // Get the raw pointer stored in arg[0] (the panic payload). - let &[ref payload] = check_arg_count(args)?; + let &[ref payload] = this.check_shim(abi, Abi::Rust, link_name, args)?; let payload = this.read_scalar(payload)?.check_init()?; let thread = this.active_thread_mut(); assert!(thread.panic_payload.is_none(), "the panic runtime should avoid double-panics"); diff --git a/src/shims/posix/foreign_items.rs b/src/shims/posix/foreign_items.rs index 2ecea4d9f41e5..45e3d502a290f 100644 --- a/src/shims/posix/foreign_items.rs +++ b/src/shims/posix/foreign_items.rs @@ -1,11 +1,11 @@ use log::trace; use rustc_middle::mir; +use rustc_span::Symbol; use rustc_target::abi::{Align, LayoutOf, Size}; use rustc_target::spec::abi::Abi; use crate::*; -use helpers::check_arg_count; use shims::foreign_items::EmulateByNameResult; use shims::posix::fs::EvalContextExt as _; use shims::posix::sync::EvalContextExt as _; @@ -16,6 +16,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn emulate_foreign_item_by_name( &mut self, link_name: &str, + link_name_sym: Symbol, abi: Abi, args: &[OpTy<'tcx, Tag>], dest: &PlaceTy<'tcx, Tag>, @@ -26,52 +27,45 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx match link_name { // Environment related shims "getenv" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref name] = check_arg_count(args)?; + let &[ref name] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.getenv(name)?; this.write_scalar(result, dest)?; } "unsetenv" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref name] = check_arg_count(args)?; + let &[ref name] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.unsetenv(name)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "setenv" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref name, ref value, ref overwrite] = check_arg_count(args)?; + let &[ref name, ref value, ref overwrite] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; this.read_scalar(overwrite)?.to_i32()?; let result = this.setenv(name, value)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "getcwd" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref buf, ref size] = check_arg_count(args)?; + let &[ref buf, ref size] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.getcwd(buf, size)?; this.write_scalar(result, dest)?; } "chdir" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref path] = check_arg_count(args)?; + let &[ref path] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.chdir(path)?; this.write_scalar(Scalar::from_i32(result), dest)?; } // File related shims "open" | "open64" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref path, ref flag, ref mode] = check_arg_count(args)?; + let &[ref path, ref flag, ref mode] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.open(path, flag, mode)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "fcntl" => { - this.check_abi(abi, Abi::C { unwind: false })?; + this.check_abi_and_shim_symbol_clash(abi, Abi::C { unwind: false }, link_name_sym)?; let result = this.fcntl(args)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "read" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref fd, ref buf, ref count] = check_arg_count(args)?; + let &[ref fd, ref buf, ref count] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let fd = this.read_scalar(fd)?.to_i32()?; let buf = this.read_scalar(buf)?.check_init()?; let count = this.read_scalar(count)?.to_machine_usize(this)?; @@ -79,8 +73,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_machine_isize(result, this), dest)?; } "write" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref fd, ref buf, ref n] = check_arg_count(args)?; + let &[ref fd, ref buf, ref n] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let fd = this.read_scalar(fd)?.to_i32()?; let buf = this.read_scalar(buf)?.check_init()?; let count = this.read_scalar(n)?.to_machine_usize(this)?; @@ -90,71 +83,60 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_machine_isize(result, this), dest)?; } "unlink" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref path] = check_arg_count(args)?; + let &[ref path] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.unlink(path)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "symlink" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref target, ref linkpath] = check_arg_count(args)?; + let &[ref target, ref linkpath] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.symlink(target, linkpath)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "rename" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref oldpath, ref newpath] = check_arg_count(args)?; + let &[ref oldpath, ref newpath] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.rename(oldpath, newpath)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "mkdir" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref path, ref mode] = check_arg_count(args)?; + let &[ref path, ref mode] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.mkdir(path, mode)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "rmdir" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref path] = check_arg_count(args)?; + let &[ref path] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.rmdir(path)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "closedir" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref dirp] = check_arg_count(args)?; + let &[ref dirp] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.closedir(dirp)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "lseek" | "lseek64" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref fd, ref offset, ref whence] = check_arg_count(args)?; + let &[ref fd, ref offset, ref whence] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.lseek64(fd, offset, whence)?; // "lseek" is only used on macOS which is 64bit-only, so `i64` always works. this.write_scalar(Scalar::from_i64(result), dest)?; } "fsync" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref fd] = check_arg_count(args)?; + let &[ref fd] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.fsync(fd)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "fdatasync" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref fd] = check_arg_count(args)?; + let &[ref fd] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.fdatasync(fd)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "readlink" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref pathname, ref buf, ref bufsize] = check_arg_count(args)?; + let &[ref pathname, ref buf, ref bufsize] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.readlink(pathname, buf, bufsize)?; this.write_scalar(Scalar::from_machine_isize(result, this), dest)?; } // Allocation "posix_memalign" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref ret, ref align, ref size] = check_arg_count(args)?; + let &[ref ret, ref align, ref size] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let ret = this.deref_operand(ret)?; let align = this.read_scalar(align)?.to_machine_usize(this)?; let size = this.read_scalar(size)?.to_machine_usize(this)?; @@ -184,8 +166,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Dynamic symbol loading "dlsym" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref handle, ref symbol] = check_arg_count(args)?; + let &[ref handle, ref symbol] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; this.read_scalar(handle)?.to_machine_usize(this)?; let symbol = this.read_scalar(symbol)?.check_init()?; let symbol_name = this.read_c_str(symbol)?; @@ -199,8 +180,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Querying system information "sysconf" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref name] = check_arg_count(args)?; + let &[ref name] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let name = this.read_scalar(name)?.to_i32()?; let sysconfs = &[ @@ -225,8 +205,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Thread-local storage "pthread_key_create" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref key, ref dtor] = check_arg_count(args)?; + let &[ref key, ref dtor] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let key_place = this.deref_operand(key)?; let dtor = this.read_scalar(dtor)?.check_init()?; @@ -254,24 +233,21 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_null(dest)?; } "pthread_key_delete" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref key] = check_arg_count(args)?; + let &[ref key] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let key = this.force_bits(this.read_scalar(key)?.check_init()?, key.layout.size)?; this.machine.tls.delete_tls_key(key)?; // Return success (0) this.write_null(dest)?; } "pthread_getspecific" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref key] = check_arg_count(args)?; + let &[ref key] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let key = this.force_bits(this.read_scalar(key)?.check_init()?, key.layout.size)?; let active_thread = this.get_active_thread(); let ptr = this.machine.tls.load_tls(key, active_thread, this)?; this.write_scalar(ptr, dest)?; } "pthread_setspecific" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref key, ref new_ptr] = check_arg_count(args)?; + let &[ref key, ref new_ptr] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let key = this.force_bits(this.read_scalar(key)?.check_init()?, key.layout.size)?; let active_thread = this.get_active_thread(); let new_ptr = this.read_scalar(new_ptr)?.check_init()?; @@ -283,178 +259,149 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Synchronization primitives "pthread_mutexattr_init" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref attr] = check_arg_count(args)?; + let &[ref attr] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.pthread_mutexattr_init(attr)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_mutexattr_settype" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref attr, ref kind] = check_arg_count(args)?; + let &[ref attr, ref kind] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.pthread_mutexattr_settype(attr, kind)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_mutexattr_destroy" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref attr] = check_arg_count(args)?; + let &[ref attr] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.pthread_mutexattr_destroy(attr)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_mutex_init" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref mutex, ref attr] = check_arg_count(args)?; + let &[ref mutex, ref attr] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.pthread_mutex_init(mutex, attr)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_mutex_lock" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref mutex] = check_arg_count(args)?; + let &[ref mutex] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.pthread_mutex_lock(mutex)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_mutex_trylock" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref mutex] = check_arg_count(args)?; + let &[ref mutex] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.pthread_mutex_trylock(mutex)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_mutex_unlock" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref mutex] = check_arg_count(args)?; + let &[ref mutex] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.pthread_mutex_unlock(mutex)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_mutex_destroy" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref mutex] = check_arg_count(args)?; + let &[ref mutex] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.pthread_mutex_destroy(mutex)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_rwlock_rdlock" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref rwlock] = check_arg_count(args)?; + let &[ref rwlock] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.pthread_rwlock_rdlock(rwlock)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_rwlock_tryrdlock" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref rwlock] = check_arg_count(args)?; + let &[ref rwlock] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.pthread_rwlock_tryrdlock(rwlock)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_rwlock_wrlock" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref rwlock] = check_arg_count(args)?; + let &[ref rwlock] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.pthread_rwlock_wrlock(rwlock)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_rwlock_trywrlock" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref rwlock] = check_arg_count(args)?; + let &[ref rwlock] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.pthread_rwlock_trywrlock(rwlock)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_rwlock_unlock" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref rwlock] = check_arg_count(args)?; + let &[ref rwlock] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.pthread_rwlock_unlock(rwlock)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_rwlock_destroy" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref rwlock] = check_arg_count(args)?; + let &[ref rwlock] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.pthread_rwlock_destroy(rwlock)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_condattr_init" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref attr] = check_arg_count(args)?; + let &[ref attr] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.pthread_condattr_init(attr)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_condattr_destroy" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref attr] = check_arg_count(args)?; + let &[ref attr] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.pthread_condattr_destroy(attr)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_cond_init" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref cond, ref attr] = check_arg_count(args)?; + let &[ref cond, ref attr] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.pthread_cond_init(cond, attr)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_cond_signal" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref cond] = check_arg_count(args)?; + let &[ref cond] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.pthread_cond_signal(cond)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_cond_broadcast" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref cond] = check_arg_count(args)?; + let &[ref cond] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.pthread_cond_broadcast(cond)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_cond_wait" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref cond, ref mutex] = check_arg_count(args)?; + let &[ref cond, ref mutex] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.pthread_cond_wait(cond, mutex)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_cond_timedwait" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref cond, ref mutex, ref abstime] = check_arg_count(args)?; + let &[ref cond, ref mutex, ref abstime] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; this.pthread_cond_timedwait(cond, mutex, abstime, dest)?; } "pthread_cond_destroy" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref cond] = check_arg_count(args)?; + let &[ref cond] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.pthread_cond_destroy(cond)?; this.write_scalar(Scalar::from_i32(result), dest)?; } // Threading "pthread_create" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref thread, ref attr, ref start, ref arg] = check_arg_count(args)?; + let &[ref thread, ref attr, ref start, ref arg] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.pthread_create(thread, attr, start, arg)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_join" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref thread, ref retval] = check_arg_count(args)?; + let &[ref thread, ref retval] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.pthread_join(thread, retval)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_detach" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref thread] = check_arg_count(args)?; + let &[ref thread] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.pthread_detach(thread)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_self" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[] = check_arg_count(args)?; + let &[] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; this.pthread_self(dest)?; } "sched_yield" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[] = check_arg_count(args)?; + let &[] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.sched_yield()?; this.write_scalar(Scalar::from_i32(result), dest)?; } "nanosleep" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref req, ref rem] = check_arg_count(args)?; + let &[ref req, ref rem] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.nanosleep(req, rem)?; this.write_scalar(Scalar::from_i32(result), dest)?; } // Miscellaneous "isatty" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref fd] = check_arg_count(args)?; + let &[ref fd] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; this.read_scalar(fd)?.to_i32()?; // "returns 1 if fd is an open file descriptor referring to a terminal; otherwise 0 is returned, and errno is set to indicate the error" // FIXME: we just say nothing is a terminal. @@ -463,8 +410,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_null(dest)?; } "pthread_atfork" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref prepare, ref parent, ref child] = check_arg_count(args)?; + let &[ref prepare, ref parent, ref child] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; this.force_bits(this.read_scalar(prepare)?.check_init()?, this.memory.pointer_size())?; this.force_bits(this.read_scalar(parent)?.check_init()?, this.memory.pointer_size())?; this.force_bits(this.read_scalar(child)?.check_init()?, this.memory.pointer_size())?; @@ -476,8 +422,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // These shims are enabled only when the caller is in the standard library. "pthread_attr_getguardsize" if this.frame_in_std() => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref _attr, ref guard_size] = check_arg_count(args)?; + let &[ref _attr, ref guard_size] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let guard_size = this.deref_operand(guard_size)?; let guard_size_layout = this.libc_ty_layout("size_t")?; this.write_scalar(Scalar::from_uint(crate::PAGE_SIZE, guard_size_layout.size), &guard_size.into())?; @@ -489,37 +434,33 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "pthread_attr_init" | "pthread_attr_destroy" if this.frame_in_std() => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[_] = check_arg_count(args)?; + let &[_] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; this.write_null(dest)?; } | "pthread_attr_setstacksize" if this.frame_in_std() => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[_, _] = check_arg_count(args)?; + let &[_, _] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; this.write_null(dest)?; } | "signal" | "sigaltstack" if this.frame_in_std() => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[_, _] = check_arg_count(args)?; + let &[_, _] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; this.write_null(dest)?; } | "sigaction" | "mprotect" if this.frame_in_std() => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[_, _, _] = check_arg_count(args)?; + let &[_, _, _] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; this.write_null(dest)?; } // Platform-specific shims _ => { match this.tcx.sess.target.os.as_str() { - "linux" => return shims::posix::linux::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, abi, args, dest, ret), - "macos" => return shims::posix::macos::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, abi, args, dest, ret), + "linux" => return shims::posix::linux::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, link_name_sym, abi, args, dest, ret), + "macos" => return shims::posix::macos::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, link_name_sym, abi, args, dest, ret), _ => unreachable!(), } } diff --git a/src/shims/posix/linux/foreign_items.rs b/src/shims/posix/linux/foreign_items.rs index 68ae704fb04f2..9af97103e07e8 100644 --- a/src/shims/posix/linux/foreign_items.rs +++ b/src/shims/posix/linux/foreign_items.rs @@ -1,7 +1,7 @@ use rustc_middle::mir; +use rustc_span::Symbol; use rustc_target::spec::abi::Abi; -use crate::helpers::check_arg_count; use crate::*; use shims::foreign_items::EmulateByNameResult; use shims::posix::fs::EvalContextExt as _; @@ -14,6 +14,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn emulate_foreign_item_by_name( &mut self, link_name: &str, + link_name_sym: Symbol, abi: Abi, args: &[OpTy<'tcx, Tag>], dest: &PlaceTy<'tcx, Tag>, @@ -24,8 +25,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx match link_name { // errno "__errno_location" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[] = check_arg_count(args)?; + let &[] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let errno_place = this.last_error_place()?; this.write_scalar(errno_place.to_ref().to_scalar()?, dest)?; } @@ -34,33 +34,33 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // These symbols have different names on Linux and macOS, which is the only reason they are not // in the `posix` module. "close" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref fd] = check_arg_count(args)?; + let &[ref fd] = + this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.close(fd)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "opendir" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref name] = check_arg_count(args)?; + let &[ref name] = + this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.opendir(name)?; this.write_scalar(result, dest)?; } "readdir64_r" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref dirp, ref entry, ref result] = check_arg_count(args)?; + let &[ref dirp, ref entry, ref result] = + this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.linux_readdir64_r(dirp, entry, result)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "ftruncate64" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref fd, ref length] = check_arg_count(args)?; + let &[ref fd, ref length] = + this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.ftruncate64(fd, length)?; this.write_scalar(Scalar::from_i32(result), dest)?; } // Linux-only "posix_fadvise" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref fd, ref offset, ref len, ref advice] = check_arg_count(args)?; + let &[ref fd, ref offset, ref len, ref advice] = + this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; this.read_scalar(fd)?.to_i32()?; this.read_scalar(offset)?.to_machine_isize(this)?; this.read_scalar(len)?.to_machine_isize(this)?; @@ -69,26 +69,26 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_null(dest)?; } "sync_file_range" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref fd, ref offset, ref nbytes, ref flags] = check_arg_count(args)?; + let &[ref fd, ref offset, ref nbytes, ref flags] = + this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.sync_file_range(fd, offset, nbytes, flags)?; this.write_scalar(Scalar::from_i32(result), dest)?; } // Time related shims "clock_gettime" => { - this.check_abi(abi, Abi::C { unwind: false })?; // This is a POSIX function but it has only been tested on linux. - let &[ref clk_id, ref tp] = check_arg_count(args)?; + let &[ref clk_id, ref tp] = + this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.clock_gettime(clk_id, tp)?; this.write_scalar(Scalar::from_i32(result), dest)?; } // Querying system information "pthread_attr_getstack" => { - this.check_abi(abi, Abi::C { unwind: false })?; // We don't support "pthread_attr_setstack", so we just pretend all stacks have the same values here. - let &[ref attr_place, ref addr_place, ref size_place] = check_arg_count(args)?; + let &[ref attr_place, ref addr_place, ref size_place] = + this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; this.deref_operand(attr_place)?; let addr_place = this.deref_operand(addr_place)?; let size_place = this.deref_operand(size_place)?; @@ -108,27 +108,27 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Threading "prctl" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref option, ref arg2, ref arg3, ref arg4, ref arg5] = check_arg_count(args)?; + let &[ref option, ref arg2, ref arg3, ref arg4, ref arg5] = + this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.prctl(option, arg2, arg3, arg4, arg5)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_condattr_setclock" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref attr, ref clock_id] = check_arg_count(args)?; + let &[ref attr, ref clock_id] = + this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.pthread_condattr_setclock(attr, clock_id)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_condattr_getclock" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref attr, ref clock_id] = check_arg_count(args)?; + let &[ref attr, ref clock_id] = + this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.pthread_condattr_getclock(attr, clock_id)?; this.write_scalar(Scalar::from_i32(result), dest)?; } // Dynamically invoked syscalls "syscall" => { - this.check_abi(abi, Abi::C { unwind: false })?; + this.check_abi_and_shim_symbol_clash(abi, Abi::C { unwind: false }, link_name_sym)?; // The syscall variadic function is legal to call with more arguments than needed, // extra arguments are simply ignored. However, all arguments need to be scalars; // other types might be treated differently by the calling convention. @@ -192,13 +192,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Miscelanneous "getrandom" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref ptr, ref len, ref flags] = check_arg_count(args)?; + let &[ref ptr, ref len, ref flags] = + this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; getrandom(this, ptr, len, flags, dest)?; } "sched_getaffinity" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref pid, ref cpusetsize, ref mask] = check_arg_count(args)?; + let &[ref pid, ref cpusetsize, ref mask] = + this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; this.read_scalar(pid)?.to_i32()?; this.read_scalar(cpusetsize)?.to_machine_usize(this)?; this.deref_operand(mask)?; @@ -211,8 +211,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Incomplete shims that we "stub out" just to get pre-main initialization code to work. // These shims are enabled only when the caller is in the standard library. "pthread_getattr_np" if this.frame_in_std() => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref _thread, ref _attr] = check_arg_count(args)?; + let &[ref _thread, ref _attr] = + this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; this.write_null(dest)?; } diff --git a/src/shims/posix/macos/foreign_items.rs b/src/shims/posix/macos/foreign_items.rs index 313d38c80b6f5..37de757e9b8dc 100644 --- a/src/shims/posix/macos/foreign_items.rs +++ b/src/shims/posix/macos/foreign_items.rs @@ -1,8 +1,8 @@ use rustc_middle::mir; +use rustc_span::Symbol; use rustc_target::spec::abi::Abi; use crate::*; -use helpers::check_arg_count; use shims::foreign_items::EmulateByNameResult; use shims::posix::fs::EvalContextExt as _; use shims::posix::thread::EvalContextExt as _; @@ -12,6 +12,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn emulate_foreign_item_by_name( &mut self, link_name: &str, + link_name_sym: Symbol, abi: Abi, args: &[OpTy<'tcx, Tag>], dest: &PlaceTy<'tcx, Tag>, @@ -22,100 +23,95 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx match link_name { // errno "__error" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[] = check_arg_count(args)?; + let &[] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let errno_place = this.last_error_place()?; this.write_scalar(errno_place.to_ref().to_scalar()?, dest)?; } // File related shims "close" | "close$NOCANCEL" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref result] = check_arg_count(args)?; + let &[ref result] = + this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.close(result)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "stat" | "stat$INODE64" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref path, ref buf] = check_arg_count(args)?; + let &[ref path, ref buf] = + this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.macos_stat(path, buf)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "lstat" | "lstat$INODE64" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref path, ref buf] = check_arg_count(args)?; + let &[ref path, ref buf] = + this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.macos_lstat(path, buf)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "fstat" | "fstat$INODE64" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref fd, ref buf] = check_arg_count(args)?; + let &[ref fd, ref buf] = + this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.macos_fstat(fd, buf)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "opendir" | "opendir$INODE64" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref name] = check_arg_count(args)?; + let &[ref name] = + this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.opendir(name)?; this.write_scalar(result, dest)?; } "readdir_r" | "readdir_r$INODE64" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref dirp, ref entry, ref result] = check_arg_count(args)?; + let &[ref dirp, ref entry, ref result] = + this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.macos_readdir_r(dirp, entry, result)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "ftruncate" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref fd, ref length] = check_arg_count(args)?; + let &[ref fd, ref length] = + this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.ftruncate64(fd, length)?; this.write_scalar(Scalar::from_i32(result), dest)?; } // Environment related shims "_NSGetEnviron" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[] = check_arg_count(args)?; + let &[] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; this.write_scalar(this.machine.env_vars.environ.unwrap().ptr, dest)?; } // Time related shims "gettimeofday" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref tv, ref tz] = check_arg_count(args)?; + let &[ref tv, ref tz] = + this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.gettimeofday(tv, tz)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "mach_absolute_time" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[] = check_arg_count(args)?; + let &[] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.mach_absolute_time()?; this.write_scalar(Scalar::from_u64(result), dest)?; } "mach_timebase_info" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref info] = check_arg_count(args)?; + let &[ref info] = + this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let result = this.mach_timebase_info(info)?; this.write_scalar(Scalar::from_i32(result), dest)?; } // Access to command-line arguments "_NSGetArgc" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[] = check_arg_count(args)?; + let &[] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; this.write_scalar(this.machine.argc.expect("machine must be initialized"), dest)?; } "_NSGetArgv" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[] = check_arg_count(args)?; + let &[] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; this.write_scalar(this.machine.argv.expect("machine must be initialized"), dest)?; } // Thread-local storage "_tlv_atexit" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref dtor, ref data] = check_arg_count(args)?; + let &[ref dtor, ref data] = + this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let dtor = this.read_scalar(dtor)?.check_init()?; let dtor = this.memory.get_fn(dtor)?.as_instance()?; let data = this.read_scalar(data)?.check_init()?; @@ -125,15 +121,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Querying system information "pthread_get_stackaddr_np" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref thread] = check_arg_count(args)?; + let &[ref thread] = + this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; this.read_scalar(thread)?.to_machine_usize(this)?; let stack_addr = Scalar::from_uint(STACK_ADDR, this.pointer_size()); this.write_scalar(stack_addr, dest)?; } "pthread_get_stacksize_np" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref thread] = check_arg_count(args)?; + let &[ref thread] = + this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; this.read_scalar(thread)?.to_machine_usize(this)?; let stack_size = Scalar::from_uint(STACK_SIZE, this.pointer_size()); this.write_scalar(stack_size, dest)?; @@ -141,8 +137,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Threading "pthread_setname_np" => { - this.check_abi(abi, Abi::C { unwind: false })?; - let &[ref name] = check_arg_count(args)?; + let &[ref name] = + this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let name = this.read_scalar(name)?.check_init()?; this.pthread_setname_np(name)?; } @@ -150,9 +146,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Incomplete shims that we "stub out" just to get pre-main initialization code to work. // These shims are enabled only when the caller is in the standard library. "mmap" if this.frame_in_std() => { - this.check_abi(abi, Abi::C { unwind: false })?; // This is a horrible hack, but since the guard page mechanism calls mmap and expects a particular return value, we just give it that value. - let &[ref addr, _, _, _, _, _] = check_arg_count(args)?; + let &[ref addr, _, _, _, _, _] = + this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; let addr = this.read_scalar(addr)?.check_init()?; this.write_scalar(addr, dest)?; } diff --git a/src/shims/windows/foreign_items.rs b/src/shims/windows/foreign_items.rs index 02f9bb8fff200..eaf1136669f1b 100644 --- a/src/shims/windows/foreign_items.rs +++ b/src/shims/windows/foreign_items.rs @@ -1,11 +1,11 @@ use std::iter; use rustc_middle::mir; +use rustc_span::Symbol; use rustc_target::abi::Size; use rustc_target::spec::abi::Abi; use crate::*; -use helpers::check_arg_count; use shims::foreign_items::EmulateByNameResult; use shims::windows::sync::EvalContextExt as _; @@ -14,6 +14,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn emulate_foreign_item_by_name( &mut self, link_name: &str, + link_name_sym: Symbol, abi: Abi, args: &[OpTy<'tcx, Tag>], dest: &PlaceTy<'tcx, Tag>, @@ -29,55 +30,54 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx match link_name { // Environment related shims "GetEnvironmentVariableW" => { - this.check_abi(abi, Abi::System { unwind: false })?; - let &[ref name, ref buf, ref size] = check_arg_count(args)?; + let &[ref name, ref buf, ref size] = + this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; let result = this.GetEnvironmentVariableW(name, buf, size)?; this.write_scalar(Scalar::from_u32(result), dest)?; } "SetEnvironmentVariableW" => { - this.check_abi(abi, Abi::System { unwind: false })?; - let &[ref name, ref value] = check_arg_count(args)?; + let &[ref name, ref value] = + this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; let result = this.SetEnvironmentVariableW(name, value)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "GetEnvironmentStringsW" => { - this.check_abi(abi, Abi::System { unwind: false })?; - let &[] = check_arg_count(args)?; + let &[] = + this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; let result = this.GetEnvironmentStringsW()?; this.write_scalar(result, dest)?; } "FreeEnvironmentStringsW" => { - this.check_abi(abi, Abi::System { unwind: false })?; - let &[ref env_block] = check_arg_count(args)?; + let &[ref env_block] = + this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; let result = this.FreeEnvironmentStringsW(env_block)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "GetCurrentDirectoryW" => { - this.check_abi(abi, Abi::System { unwind: false })?; - let &[ref size, ref buf] = check_arg_count(args)?; + let &[ref size, ref buf] = + this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; let result = this.GetCurrentDirectoryW(size, buf)?; this.write_scalar(Scalar::from_u32(result), dest)?; } "SetCurrentDirectoryW" => { - this.check_abi(abi, Abi::System { unwind: false })?; - let &[ref path] = check_arg_count(args)?; + let &[ref path] = + this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; let result = this.SetCurrentDirectoryW(path)?; this.write_scalar(Scalar::from_i32(result), dest)?; } // File related shims "GetStdHandle" => { - this.check_abi(abi, Abi::System { unwind: false })?; - let &[ref which] = check_arg_count(args)?; + let &[ref which] = + this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; let which = this.read_scalar(which)?.to_i32()?; // We just make this the identity function, so we know later in `WriteFile` // which one it is. this.write_scalar(Scalar::from_machine_isize(which.into(), this), dest)?; } "WriteFile" => { - this.check_abi(abi, Abi::System { unwind: false })?; let &[ref handle, ref buf, ref n, ref written_ptr, ref overlapped] = - check_arg_count(args)?; + this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; this.read_scalar(overlapped)?.to_machine_usize(this)?; // this is a poiner, that we ignore let handle = this.read_scalar(handle)?.to_machine_isize(this)?; let buf = this.read_scalar(buf)?.check_init()?; @@ -111,8 +111,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Allocation "HeapAlloc" => { - this.check_abi(abi, Abi::System { unwind: false })?; - let &[ref handle, ref flags, ref size] = check_arg_count(args)?; + let &[ref handle, ref flags, ref size] = + this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; this.read_scalar(handle)?.to_machine_isize(this)?; let flags = this.read_scalar(flags)?.to_u32()?; let size = this.read_scalar(size)?.to_machine_usize(this)?; @@ -121,8 +121,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(res, dest)?; } "HeapFree" => { - this.check_abi(abi, Abi::System { unwind: false })?; - let &[ref handle, ref flags, ref ptr] = check_arg_count(args)?; + let &[ref handle, ref flags, ref ptr] = + this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; this.read_scalar(handle)?.to_machine_isize(this)?; this.read_scalar(flags)?.to_u32()?; let ptr = this.read_scalar(ptr)?.check_init()?; @@ -130,8 +130,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_i32(1), dest)?; } "HeapReAlloc" => { - this.check_abi(abi, Abi::System { unwind: false })?; - let &[ref handle, ref flags, ref ptr, ref size] = check_arg_count(args)?; + let &[ref handle, ref flags, ref ptr, ref size] = + this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; this.read_scalar(handle)?.to_machine_isize(this)?; this.read_scalar(flags)?.to_u32()?; let ptr = this.read_scalar(ptr)?.check_init()?; @@ -142,22 +142,22 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // errno "SetLastError" => { - this.check_abi(abi, Abi::System { unwind: false })?; - let &[ref error] = check_arg_count(args)?; + let &[ref error] = + this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; let error = this.read_scalar(error)?.check_init()?; this.set_last_error(error)?; } "GetLastError" => { - this.check_abi(abi, Abi::System { unwind: false })?; - let &[] = check_arg_count(args)?; + let &[] = + this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; let last_error = this.get_last_error()?; this.write_scalar(last_error, dest)?; } // Querying system information "GetSystemInfo" => { - this.check_abi(abi, Abi::System { unwind: false })?; - let &[ref system_info] = check_arg_count(args)?; + let &[ref system_info] = + this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; let system_info = this.deref_operand(system_info)?; // Initialize with `0`. this.memory.write_bytes( @@ -172,25 +172,25 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Thread-local storage "TlsAlloc" => { - this.check_abi(abi, Abi::System { unwind: false })?; // This just creates a key; Windows does not natively support TLS destructors. // Create key and return it. - let &[] = check_arg_count(args)?; + let &[] = + this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; let key = this.machine.tls.create_tls_key(None, dest.layout.size)?; this.write_scalar(Scalar::from_uint(key, dest.layout.size), dest)?; } "TlsGetValue" => { - this.check_abi(abi, Abi::System { unwind: false })?; - let &[ref key] = check_arg_count(args)?; + let &[ref key] = + this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; let key = u128::from(this.read_scalar(key)?.to_u32()?); let active_thread = this.get_active_thread(); let ptr = this.machine.tls.load_tls(key, active_thread, this)?; this.write_scalar(ptr, dest)?; } "TlsSetValue" => { - this.check_abi(abi, Abi::System { unwind: false })?; - let &[ref key, ref new_ptr] = check_arg_count(args)?; + let &[ref key, ref new_ptr] = + this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; let key = u128::from(this.read_scalar(key)?.to_u32()?); let active_thread = this.get_active_thread(); let new_ptr = this.read_scalar(new_ptr)?.check_init()?; @@ -202,8 +202,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Access to command-line arguments "GetCommandLineW" => { - this.check_abi(abi, Abi::System { unwind: false })?; - let &[] = check_arg_count(args)?; + let &[] = + this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; this.write_scalar( this.machine.cmd_line.expect("machine must be initialized"), dest, @@ -212,65 +212,65 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Time related shims "GetSystemTimeAsFileTime" => { - this.check_abi(abi, Abi::System { unwind: false })?; #[allow(non_snake_case)] - let &[ref LPFILETIME] = check_arg_count(args)?; + let &[ref LPFILETIME] = + this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; this.GetSystemTimeAsFileTime(LPFILETIME)?; } "QueryPerformanceCounter" => { - this.check_abi(abi, Abi::System { unwind: false })?; #[allow(non_snake_case)] - let &[ref lpPerformanceCount] = check_arg_count(args)?; + let &[ref lpPerformanceCount] = + this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; let result = this.QueryPerformanceCounter(lpPerformanceCount)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "QueryPerformanceFrequency" => { - this.check_abi(abi, Abi::System { unwind: false })?; #[allow(non_snake_case)] - let &[ref lpFrequency] = check_arg_count(args)?; + let &[ref lpFrequency] = + this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; let result = this.QueryPerformanceFrequency(lpFrequency)?; this.write_scalar(Scalar::from_i32(result), dest)?; } // Synchronization primitives "AcquireSRWLockExclusive" => { - this.check_abi(abi, Abi::System { unwind: false })?; - let &[ref ptr] = check_arg_count(args)?; + let &[ref ptr] = + this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; this.AcquireSRWLockExclusive(ptr)?; } "ReleaseSRWLockExclusive" => { - this.check_abi(abi, Abi::System { unwind: false })?; - let &[ref ptr] = check_arg_count(args)?; + let &[ref ptr] = + this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; this.ReleaseSRWLockExclusive(ptr)?; } "TryAcquireSRWLockExclusive" => { - this.check_abi(abi, Abi::System { unwind: false })?; - let &[ref ptr] = check_arg_count(args)?; + let &[ref ptr] = + this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; let ret = this.TryAcquireSRWLockExclusive(ptr)?; this.write_scalar(Scalar::from_u8(ret), dest)?; } "AcquireSRWLockShared" => { - this.check_abi(abi, Abi::System { unwind: false })?; - let &[ref ptr] = check_arg_count(args)?; + let &[ref ptr] = + this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; this.AcquireSRWLockShared(ptr)?; } "ReleaseSRWLockShared" => { - this.check_abi(abi, Abi::System { unwind: false })?; - let &[ref ptr] = check_arg_count(args)?; + let &[ref ptr] = + this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; this.ReleaseSRWLockShared(ptr)?; } "TryAcquireSRWLockShared" => { - this.check_abi(abi, Abi::System { unwind: false })?; - let &[ref ptr] = check_arg_count(args)?; + let &[ref ptr] = + this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; let ret = this.TryAcquireSRWLockShared(ptr)?; this.write_scalar(Scalar::from_u8(ret), dest)?; } // Dynamic symbol loading "GetProcAddress" => { - this.check_abi(abi, Abi::System { unwind: false })?; #[allow(non_snake_case)] - let &[ref hModule, ref lpProcName] = check_arg_count(args)?; + let &[ref hModule, ref lpProcName] = + this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; this.read_scalar(hModule)?.to_machine_isize(this)?; let name = this.read_c_str(this.read_scalar(lpProcName)?.check_init()?)?; if let Some(dlsym) = Dlsym::from_str(name, &this.tcx.sess.target.os)? { @@ -284,16 +284,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Miscellaneous "SystemFunction036" => { // This is really 'RtlGenRandom'. - this.check_abi(abi, Abi::System { unwind: false })?; - let &[ref ptr, ref len] = check_arg_count(args)?; + let &[ref ptr, ref len] = + this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; let ptr = this.read_scalar(ptr)?.check_init()?; let len = this.read_scalar(len)?.to_u32()?; this.gen_random(ptr, len.into())?; this.write_scalar(Scalar::from_bool(true), dest)?; } "BCryptGenRandom" => { - this.check_abi(abi, Abi::System { unwind: false })?; - let &[ref algorithm, ref ptr, ref len, ref flags] = check_arg_count(args)?; + let &[ref algorithm, ref ptr, ref len, ref flags] = + this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; let algorithm = this.read_scalar(algorithm)?; let ptr = this.read_scalar(ptr)?.check_init()?; let len = this.read_scalar(len)?.to_u32()?; @@ -313,9 +313,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_null(dest)?; // STATUS_SUCCESS } "GetConsoleScreenBufferInfo" => { - this.check_abi(abi, Abi::System { unwind: false })?; // `term` needs this, so we fake it. - let &[ref console, ref buffer_info] = check_arg_count(args)?; + let &[ref console, ref buffer_info] = + this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; this.read_scalar(console)?.to_machine_isize(this)?; this.deref_operand(buffer_info)?; // Indicate an error. @@ -323,9 +323,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_null(dest)?; } "GetConsoleMode" => { - this.check_abi(abi, Abi::System { unwind: false })?; // Windows "isatty" (in libtest) needs this, so we fake it. - let &[ref console, ref mode] = check_arg_count(args)?; + let &[ref console, ref mode] = + this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; this.read_scalar(console)?.to_machine_isize(this)?; this.deref_operand(mode)?; // Indicate an error. @@ -333,8 +333,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_null(dest)?; } "SwitchToThread" => { - this.check_abi(abi, Abi::System { unwind: false })?; - let &[] = check_arg_count(args)?; + let &[] = + this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; // Note that once Miri supports concurrency, this will need to return a nonzero // value if this call does result in switching to another thread. this.write_null(dest)?; @@ -342,7 +342,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Better error for attempts to create a thread "CreateThread" => { - this.check_abi(abi, Abi::System { unwind: false })?; + this.check_abi_and_shim_symbol_clash( + abi, + Abi::System { unwind: false }, + link_name_sym, + )?; this.handle_unsupported("can't create threads on Windows")?; return Ok(EmulateByNameResult::AlreadyJumped); @@ -351,29 +355,29 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Incomplete shims that we "stub out" just to get pre-main initialization code to work. // These shims are enabled only when the caller is in the standard library. "GetProcessHeap" if this.frame_in_std() => { - this.check_abi(abi, Abi::System { unwind: false })?; - let &[] = check_arg_count(args)?; + let &[] = + this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; // Just fake a HANDLE this.write_scalar(Scalar::from_machine_isize(1, this), dest)?; } "SetConsoleTextAttribute" if this.frame_in_std() => { - this.check_abi(abi, Abi::System { unwind: false })?; #[allow(non_snake_case)] - let &[ref _hConsoleOutput, ref _wAttribute] = check_arg_count(args)?; + let &[ref _hConsoleOutput, ref _wAttribute] = + this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; // Pretend these does not exist / nothing happened, by returning zero. this.write_null(dest)?; } "AddVectoredExceptionHandler" if this.frame_in_std() => { - this.check_abi(abi, Abi::System { unwind: false })?; #[allow(non_snake_case)] - let &[ref _First, ref _Handler] = check_arg_count(args)?; + let &[ref _First, ref _Handler] = + this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; // Any non zero value works for the stdlib. This is just used for stack overflows anyway. this.write_scalar(Scalar::from_machine_usize(1, this), dest)?; } "SetThreadStackGuarantee" if this.frame_in_std() => { - this.check_abi(abi, Abi::System { unwind: false })?; #[allow(non_snake_case)] - let &[_StackSizeInBytes] = check_arg_count(args)?; + let &[_StackSizeInBytes] = + this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; // Any non zero value works for the stdlib. This is just used for stack overflows anyway. this.write_scalar(Scalar::from_u32(1), dest)?; } @@ -383,9 +387,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "DeleteCriticalSection" if this.frame_in_std() => { - this.check_abi(abi, Abi::System { unwind: false })?; #[allow(non_snake_case)] - let &[ref _lpCriticalSection] = check_arg_count(args)?; + let &[ref _lpCriticalSection] = + this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; assert_eq!( this.get_total_thread_count(), 1, @@ -396,9 +400,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // so not doing any futher checks here is at least not incorrect.) } "TryEnterCriticalSection" if this.frame_in_std() => { - this.check_abi(abi, Abi::System { unwind: false })?; #[allow(non_snake_case)] - let &[ref _lpCriticalSection] = check_arg_count(args)?; + let &[ref _lpCriticalSection] = + this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; assert_eq!( this.get_total_thread_count(), 1, diff --git a/tests/compile-fail/function_calls/exported_symbol_shim_clashing.rs b/tests/compile-fail/function_calls/exported_symbol_shim_clashing.rs new file mode 100644 index 0000000000000..c46d57cee0dde --- /dev/null +++ b/tests/compile-fail/function_calls/exported_symbol_shim_clashing.rs @@ -0,0 +1,15 @@ +#[no_mangle] +extern "C" fn malloc(_: usize) -> *mut std::ffi::c_void { + //~^ HELP the `malloc` symbol is defined here + unreachable!() +} + +fn main() { + extern "C" { + fn malloc(_: usize) -> *mut std::ffi::c_void; + } + unsafe { + malloc(0); + //~^ ERROR found `malloc` symbol definition that clashes with a built-in shim + } +} From c822ec59aa817a5018b8058cc66c98e6effb7e9c Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Tue, 8 Jun 2021 20:36:57 +0800 Subject: [PATCH 2724/3747] Implement cache for not found symbols --- src/machine.rs | 3 ++- src/shims/foreign_items.rs | 11 ++++------- tests/run-pass/function_calls/exported_symbol.rs | 5 +++++ 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/src/machine.rs b/src/machine.rs index 61871e745894d..91a83a8acf403 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -297,7 +297,8 @@ pub struct Evaluator<'mir, 'tcx> { string_cache: FxHashMap, /// Cache of `Instance` exported under the given `Symbol` name. - pub(crate) exported_symbols_cache: FxHashMap>, + /// `None` means no `Instance` exported under the given name is found. + pub(crate) exported_symbols_cache: FxHashMap>>, /// Whether to raise a panic in the context of the evaluated process when unsupported /// functionality is encountered. If `false`, an error is propagated in the Miri application context diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index f193751518e18..380ddac6c86a6 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -135,7 +135,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // If the result was cached, just return it. if let Some(instance) = this.machine.exported_symbols_cache.get(&link_name) { - return Ok(Some(this.load_mir(instance.def, None)?)); + return instance.map(|instance| this.load_mir(instance.def, None)).transpose(); } // Find it if it was not cached. @@ -187,13 +187,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } + let instance = instance_and_crate.map(|ic| ic.0); // Cache it and load its MIR, if found. - instance_and_crate - .map(|(instance, _)| { - this.machine.exported_symbols_cache.insert(link_name, instance); - this.load_mir(instance.def, None) - }) - .transpose() + this.machine.exported_symbols_cache.insert(link_name, instance); + instance.map(|instance| this.load_mir(instance.def, None)).transpose() } /// Emulates calling a foreign item, failing if the item is not supported. diff --git a/tests/run-pass/function_calls/exported_symbol.rs b/tests/run-pass/function_calls/exported_symbol.rs index c141f557e1d79..58115542332f2 100644 --- a/tests/run-pass/function_calls/exported_symbol.rs +++ b/tests/run-pass/function_calls/exported_symbol.rs @@ -20,10 +20,15 @@ fn main() { for _ in 0..3 { extern "C" { fn foo() -> i32; + fn free(_: *mut std::ffi::c_void); } assert_eq!(unsafe { foo() }, -1); + // `free()` is a built-in shim, so calling it will add ("free", None) to the cache. + // Test that the cache is not broken with ("free", None). + unsafe { free(std::ptr::null_mut()) } + extern "Rust" { fn bar() -> i32; fn baz() -> i32; From e46aab5816e32316c33962939aa6e2bbcebd4c8c Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Fri, 11 Jun 2021 15:47:12 +0800 Subject: [PATCH 2725/3747] Use `check_shim()` for `abort` --- src/shims/foreign_items.rs | 7 ++----- .../function_calls/check_arg_count_abort.rs | 10 ++++++++++ 2 files changed, 12 insertions(+), 5 deletions(-) create mode 100644 tests/compile-fail/function_calls/check_arg_count_abort.rs diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 380ddac6c86a6..23824305c980d 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -244,11 +244,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx throw_machine_stop!(TerminationInfo::Exit(code.into())); } "abort" => { - this.check_abi_and_shim_symbol_clash( - abi, - Abi::C { unwind: false }, - link_name_sym, - )?; + let &[] = + this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; throw_machine_stop!(TerminationInfo::Abort( "the program aborted execution".to_owned() )) diff --git a/tests/compile-fail/function_calls/check_arg_count_abort.rs b/tests/compile-fail/function_calls/check_arg_count_abort.rs new file mode 100644 index 0000000000000..85e1b9deeb36f --- /dev/null +++ b/tests/compile-fail/function_calls/check_arg_count_abort.rs @@ -0,0 +1,10 @@ +fn main() { + extern "C" { + fn abort(_: i32) -> !; + } + + unsafe { + abort(1); + //~^ ERROR Undefined Behavior: incorrect number of arguments: got 1, expected 0 + } +} From 49a8f002a017a324bd3419950d26244cfe949e2f Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Fri, 11 Jun 2021 15:53:01 +0800 Subject: [PATCH 2726/3747] `let`-bind `exp_abi` of `"exit" | "ExitProcess"` --- src/shims/foreign_items.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 23824305c980d..96edfcc9cf748 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -238,7 +238,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "exit" | "ExitProcess" => { - let &[ref code] = this.check_shim(abi, if link_name == "exit" { Abi::C { unwind: false } } else { Abi::System { unwind: false } }, link_name_sym, args)?; + let exp_abi = if link_name == "exit" { + Abi::C { unwind: false } + } else { + Abi::System { unwind: false } + }; + let &[ref code] = this.check_shim(abi, exp_abi, link_name_sym, args)?; // it's really u32 for ExitProcess, but we have to put it into the `Exit` variant anyway let code = this.read_scalar(code)?.to_i32()?; throw_machine_stop!(TerminationInfo::Exit(code.into())); From 99467349f2eb730ee90fabf758bc8068720ef392 Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Sun, 13 Jun 2021 23:30:08 +0800 Subject: [PATCH 2727/3747] Do not return `DefId` that doesn't have exported symbol in `exported_symbols` --- src/bin/miri.rs | 29 ++++++++++++++++----- test-cargo-miri/Cargo.lock | 5 ++++ test-cargo-miri/Cargo.toml | 1 + test-cargo-miri/issue-rust-86261/Cargo.toml | 5 ++++ test-cargo-miri/issue-rust-86261/src/lib.rs | 23 ++++++++++++++++ 5 files changed, 56 insertions(+), 7 deletions(-) create mode 100644 test-cargo-miri/issue-rust-86261/Cargo.toml create mode 100644 test-cargo-miri/issue-rust-86261/src/lib.rs diff --git a/src/bin/miri.rs b/src/bin/miri.rs index fae45d9fc0ef4..d593f24c71ab4 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -19,7 +19,7 @@ use log::debug; use rustc_driver::Compilation; use rustc_errors::emitter::{ColorConfig, HumanReadableErrorType}; -use rustc_hir::def_id::LOCAL_CRATE; +use rustc_hir::{self as hir, def_id::LOCAL_CRATE, Node}; use rustc_interface::interface::Config; use rustc_middle::{ middle::exported_symbols::{ExportedSymbol, SymbolExportLevel}, @@ -109,12 +109,27 @@ impl rustc_driver::Callbacks for MiriBeRustCompilerCalls { // https://github.com/rust-lang/rust/blob/2962e7c0089d5c136f4e9600b7abccfbbde4973d/compiler/rustc_codegen_ssa/src/back/symbol_export.rs#L62-L63 // https://github.com/rust-lang/rust/blob/2962e7c0089d5c136f4e9600b7abccfbbde4973d/compiler/rustc_codegen_ssa/src/back/symbol_export.rs#L174 tcx.reachable_set(()).iter().filter_map(|&local_def_id| { - tcx.codegen_fn_attrs(local_def_id) - .contains_extern_indicator() - .then_some(( - ExportedSymbol::NonGeneric(local_def_id.to_def_id()), - SymbolExportLevel::C, - )) + // Do the same filtering that rustc does: + // https://github.com/rust-lang/rust/blob/2962e7c0089d5c136f4e9600b7abccfbbde4973d/compiler/rustc_codegen_ssa/src/back/symbol_export.rs#L84-L102 + // Otherwise it may cause unexpected behaviours and ICEs + // (https://github.com/rust-lang/rust/issues/86261). + let is_reachable_non_generic = matches!( + tcx.hir().get(tcx.hir().local_def_id_to_hir_id(local_def_id)), + Node::Item(&hir::Item { + kind: hir::ItemKind::Static(..) | hir::ItemKind::Fn(..), + .. + }) | Node::ImplItem(&hir::ImplItem { + kind: hir::ImplItemKind::Fn(..), + .. + }) + if !tcx.generics_of(local_def_id).requires_monomorphization(tcx) + ); + (is_reachable_non_generic + && tcx.codegen_fn_attrs(local_def_id).contains_extern_indicator()) + .then_some(( + ExportedSymbol::NonGeneric(local_def_id.to_def_id()), + SymbolExportLevel::C, + )) }), ) } diff --git a/test-cargo-miri/Cargo.lock b/test-cargo-miri/Cargo.lock index 9a9fa4797bf26..7f06fdf28dec5 100644 --- a/test-cargo-miri/Cargo.lock +++ b/test-cargo-miri/Cargo.lock @@ -21,6 +21,7 @@ dependencies = [ "issue_1691", "issue_1705", "issue_1760", + "issue_rust_86261", "rand", "serde_derive", ] @@ -102,6 +103,10 @@ dependencies = [ name = "issue_1760" version = "0.1.0" +[[package]] +name = "issue_rust_86261" +version = "0.1.0" + [[package]] name = "libc" version = "0.2.92" diff --git a/test-cargo-miri/Cargo.toml b/test-cargo-miri/Cargo.toml index cf557bd60ef39..39ce1757f0e42 100644 --- a/test-cargo-miri/Cargo.toml +++ b/test-cargo-miri/Cargo.toml @@ -15,6 +15,7 @@ issue_1567 = { path = "issue-1567" } issue_1691 = { path = "issue-1691" } issue_1705 = { path = "issue-1705" } issue_1760 = { path = "issue-1760" } +issue_rust_86261 = { path = "issue-rust-86261" } [dev-dependencies] rand = { version = "0.8", features = ["small_rng"] } diff --git a/test-cargo-miri/issue-rust-86261/Cargo.toml b/test-cargo-miri/issue-rust-86261/Cargo.toml new file mode 100644 index 0000000000000..a6b65ebb5318d --- /dev/null +++ b/test-cargo-miri/issue-rust-86261/Cargo.toml @@ -0,0 +1,5 @@ +[package] +name = "issue_rust_86261" +version = "0.1.0" +authors = ["Miri Team"] +edition = "2018" diff --git a/test-cargo-miri/issue-rust-86261/src/lib.rs b/test-cargo-miri/issue-rust-86261/src/lib.rs new file mode 100644 index 0000000000000..db725fdb64ed9 --- /dev/null +++ b/test-cargo-miri/issue-rust-86261/src/lib.rs @@ -0,0 +1,23 @@ +#![allow(unused_imports, unused_attributes, no_mangle_generic_items)] + +// Regression test for https://github.com/rust-lang/rust/issues/86261: +// `#[no_mangle]` on a `use` item. +#[no_mangle] +use std::{thread,panic, io, boxed, any, string}; + +// `#[no_mangle]` on a struct has a similar problem. +#[no_mangle] +pub struct NoMangleStruct; + +// If `#[no_mangle]` has effect on the `struct` above, calling `NoMangleStruct` will fail with +// "multiple definitions of symbol `NoMangleStruct`" error. +#[export_name = "NoMangleStruct"] +fn no_mangle_struct() {} + +// `#[no_mangle]` on a generic function can also cause ICEs. +#[no_mangle] +fn no_mangle_generic() {} + +// Same as `no_mangle_struct()` but for the `no_mangle_generic()` generic function. +#[export_name = "no_mangle_generic"] +fn no_mangle_generic2() {} From da2ed6f768452777c467a0d1e1a77fb92d9165c0 Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Mon, 14 Jun 2021 20:56:03 +0800 Subject: [PATCH 2728/3747] Don't report UB for `#[no_mangle]` on associated functions --- src/shims/foreign_items.rs | 2 +- test-cargo-miri/exported-symbol-dep/src/lib.rs | 9 +++++++++ test-cargo-miri/src/main.rs | 7 +++++++ 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 8f3dfdc4f81fa..bcb2d262e8589 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -177,7 +177,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx second_crate: tcx.crate_name(cnum), }); } - if tcx.def_kind(def_id) != DefKind::Fn { + if !matches!(tcx.def_kind(def_id), DefKind::Fn | DefKind::AssocFn) { throw_ub_format!( "attempt to call an exported symbol that is not defined as a function" ); diff --git a/test-cargo-miri/exported-symbol-dep/src/lib.rs b/test-cargo-miri/exported-symbol-dep/src/lib.rs index 4cc18fb9b2fbc..db257dcb22c47 100644 --- a/test-cargo-miri/exported-symbol-dep/src/lib.rs +++ b/test-cargo-miri/exported-symbol-dep/src/lib.rs @@ -2,3 +2,12 @@ fn exported_symbol() -> i32 { 123456 } + +pub struct AssocFn; + +impl AssocFn { + #[no_mangle] + pub fn assoc_fn_as_exported_symbol() -> i32 { + -123456 + } +} diff --git a/test-cargo-miri/src/main.rs b/test-cargo-miri/src/main.rs index a5669ef3087c5..cb1512d050209 100644 --- a/test-cargo-miri/src/main.rs +++ b/test-cargo-miri/src/main.rs @@ -62,15 +62,22 @@ mod test { fn exported_symbol() { extern crate cargo_miri_test; extern crate exported_symbol; + extern crate issue_rust_86261; // Test calling exported symbols in (transitive) dependencies. // Repeat calls to make sure the `Instance` cache is not broken. for _ in 0..3 { extern "Rust" { fn exported_symbol() -> i32; + fn assoc_fn_as_exported_symbol() -> i32; fn make_true() -> bool; + fn NoMangleStruct(); + fn no_mangle_generic(); } assert_eq!(unsafe { exported_symbol() }, 123456); + assert_eq!(unsafe { assoc_fn_as_exported_symbol() }, -123456); assert!(unsafe { make_true() }); + unsafe { NoMangleStruct() } + unsafe { no_mangle_generic() } } } } From 89c722ac325a440bdd5f34befe2d28e23ec29d25 Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Mon, 14 Jun 2021 22:53:17 +0800 Subject: [PATCH 2729/3747] Add some comments about `check_shim` --- src/shims/foreign_items.rs | 6 ++++++ src/shims/posix/foreign_items.rs | 2 ++ src/shims/posix/linux/foreign_items.rs | 2 ++ 3 files changed, 10 insertions(+) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 96edfcc9cf748..87906d877f8fb 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -223,12 +223,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let (dest, ret) = match ret { None => match link_name { "miri_start_panic" => { + // `check_shim` happens inside `handle_miri_start_panic`. this.handle_miri_start_panic(abi, link_name_sym, args, unwind)?; return Ok(None); } // This matches calls to the foreign item `panic_impl`. // The implementation is provided by the function with the `#[panic_handler]` attribute. "panic_impl" => { + // We don't use `check_shim` here because we are just forwarding to the lang + // item. Argument count checking will be performed when the returned `Body` is + // called. this.check_abi_and_shim_symbol_clash(abi, Abi::Rust, link_name_sym)?; let panic_impl_id = tcx.lang_items().panic_impl().unwrap(); let panic_impl_instance = ty::Instance::mono(tcx, panic_impl_id); @@ -317,11 +321,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Obtains a Miri backtrace. See the README for details. "miri_get_backtrace" => { + // `check_shim` happens inside `handle_miri_get_backtrace`. this.handle_miri_get_backtrace(abi, link_name_sym, args, dest)?; } // Resolves a Miri backtrace frame. See the README for details. "miri_resolve_frame" => { + // `check_shim` happens inside `handle_miri_resolve_frame`. this.handle_miri_resolve_frame(abi, link_name_sym, args, dest)?; } diff --git a/src/shims/posix/foreign_items.rs b/src/shims/posix/foreign_items.rs index 45e3d502a290f..2b8ea78bf3f11 100644 --- a/src/shims/posix/foreign_items.rs +++ b/src/shims/posix/foreign_items.rs @@ -60,6 +60,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_i32(result), dest)?; } "fcntl" => { + // `fcntl` is variadic. The argument count is checked based on the first argument + // in`this.fcntl()`, so we do not use `check_shim` here. this.check_abi_and_shim_symbol_clash(abi, Abi::C { unwind: false }, link_name_sym)?; let result = this.fcntl(args)?; this.write_scalar(Scalar::from_i32(result), dest)?; diff --git a/src/shims/posix/linux/foreign_items.rs b/src/shims/posix/linux/foreign_items.rs index 9af97103e07e8..07d764a68e913 100644 --- a/src/shims/posix/linux/foreign_items.rs +++ b/src/shims/posix/linux/foreign_items.rs @@ -128,6 +128,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Dynamically invoked syscalls "syscall" => { + // We do not use `check_shim` here because `syscall` is variadic. The argument + // count is checked bellow. this.check_abi_and_shim_symbol_clash(abi, Abi::C { unwind: false }, link_name_sym)?; // The syscall variadic function is legal to call with more arguments than needed, // extra arguments are simply ignored. However, all arguments need to be scalars; From d1e72d0854587f3175c1720cda8180fd7878b4d0 Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Mon, 14 Jun 2021 23:01:06 +0800 Subject: [PATCH 2730/3747] Check argument count for `CreateThread` --- src/shims/windows/foreign_items.rs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/src/shims/windows/foreign_items.rs b/src/shims/windows/foreign_items.rs index eaf1136669f1b..f12e4df8cdfe3 100644 --- a/src/shims/windows/foreign_items.rs +++ b/src/shims/windows/foreign_items.rs @@ -342,11 +342,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Better error for attempts to create a thread "CreateThread" => { - this.check_abi_and_shim_symbol_clash( - abi, - Abi::System { unwind: false }, - link_name_sym, - )?; + let &[_, _, _, _, _, _] = + this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; this.handle_unsupported("can't create threads on Windows")?; return Ok(EmulateByNameResult::AlreadyJumped); From 34603e586fc7fca3bb8e630be26e42350f758291 Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Mon, 14 Jun 2021 23:38:15 +0800 Subject: [PATCH 2731/3747] Add whitespace --- src/shims/posix/foreign_items.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shims/posix/foreign_items.rs b/src/shims/posix/foreign_items.rs index 2b8ea78bf3f11..ac26b39757a19 100644 --- a/src/shims/posix/foreign_items.rs +++ b/src/shims/posix/foreign_items.rs @@ -61,7 +61,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "fcntl" => { // `fcntl` is variadic. The argument count is checked based on the first argument - // in`this.fcntl()`, so we do not use `check_shim` here. + // in `this.fcntl()`, so we do not use `check_shim` here. this.check_abi_and_shim_symbol_clash(abi, Abi::C { unwind: false }, link_name_sym)?; let result = this.fcntl(args)?; this.write_scalar(Scalar::from_i32(result), dest)?; From a67a65359f812a6970fc381bdd794b8f7792ce56 Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Tue, 15 Jun 2021 00:43:15 +0800 Subject: [PATCH 2732/3747] Only pass `Symbol` to `emulate_foreign_item_by_name` --- src/helpers.rs | 5 + src/shims/foreign_items.rs | 69 ++++++------- src/shims/posix/foreign_items.rs | 132 ++++++++++++------------- src/shims/posix/linux/foreign_items.rs | 39 ++++---- src/shims/posix/macos/foreign_items.rs | 44 ++++----- src/shims/windows/foreign_items.rs | 92 ++++++++--------- 6 files changed, 190 insertions(+), 191 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index b99a446577ac4..1a12d19e124e8 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -723,6 +723,11 @@ where throw_ub_format!("incorrect number of arguments: got {}, expected {}", args.len(), N) } +/// Strip linker suffixes (seen on 32-bit macOS). +pub fn strip_linker_suffix(link_name: &str) -> &str { + link_name.trim_end_matches("$UNIX2003") +} + pub fn isolation_abort_error(name: &str) -> InterpResult<'static> { throw_machine_stop!(TerminationInfo::UnsupportedInIsolation(format!( "{} not available when isolation is enabled", diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 87906d877f8fb..36d075e32dff2 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -25,6 +25,7 @@ use rustc_target::{ use super::backtrace::EvalContextExt as _; use crate::*; +use helpers::strip_linker_suffix; /// Returned by `emulate_foreign_item_by_name`. pub enum EmulateByNameResult { @@ -215,8 +216,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx .first_attr_value_str_by_name(&attrs, sym::link_name) .unwrap_or_else(|| this.tcx.item_name(def_id)); let link_name = link_name_sym.as_str(); - // Strip linker suffixes (seen on 32-bit macOS). - let link_name = link_name.trim_end_matches("$UNIX2003"); + let link_name = strip_linker_suffix(&link_name); let tcx = this.tcx.tcx; // First: functions that diverge. @@ -274,7 +274,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx }; // Second: functions that return. - match this.emulate_foreign_item_by_name(link_name, link_name_sym, abi, args, dest, ret)? { + match this.emulate_foreign_item_by_name(link_name_sym, abi, args, dest, ret)? { EmulateByNameResult::NeedsJumping => { trace!("{:?}", this.dump_place(**dest)); this.go_to_block(ret); @@ -296,8 +296,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// Emulates calling a foreign item using its name. fn emulate_foreign_item_by_name( &mut self, - link_name: &str, - link_name_sym: Symbol, + link_name: Symbol, abi: Abi, args: &[OpTy<'tcx, Tag>], dest: &PlaceTy<'tcx, Tag>, @@ -307,10 +306,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Here we dispatch all the shims for foreign functions. If you have a platform specific // shim, add it to the corresponding submodule. - match link_name { + let shim_name = link_name.as_str(); + let shim_name = strip_linker_suffix(&shim_name); + match shim_name { // Miri-specific extern functions "miri_static_root" => { - let &[ref ptr] = this.check_shim(abi, Abi::Rust, link_name_sym, args)?; + let &[ref ptr] = this.check_shim(abi, Abi::Rust, link_name, args)?; let ptr = this.read_scalar(ptr)?.check_init()?; let ptr = this.force_ptr(ptr)?; if ptr.offset != Size::ZERO { @@ -322,25 +323,25 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Obtains a Miri backtrace. See the README for details. "miri_get_backtrace" => { // `check_shim` happens inside `handle_miri_get_backtrace`. - this.handle_miri_get_backtrace(abi, link_name_sym, args, dest)?; + this.handle_miri_get_backtrace(abi, link_name, args, dest)?; } // Resolves a Miri backtrace frame. See the README for details. "miri_resolve_frame" => { // `check_shim` happens inside `handle_miri_resolve_frame`. - this.handle_miri_resolve_frame(abi, link_name_sym, args, dest)?; + this.handle_miri_resolve_frame(abi, link_name, args, dest)?; } // Standard C allocation "malloc" => { - let &[ref size] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[ref size] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let size = this.read_scalar(size)?.to_machine_usize(this)?; let res = this.malloc(size, /*zero_init:*/ false, MiriMemoryKind::C); this.write_scalar(res, dest)?; } "calloc" => { - let &[ref items, ref len] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[ref items, ref len] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let items = this.read_scalar(items)?.to_machine_usize(this)?; let len = this.read_scalar(len)?.to_machine_usize(this)?; let size = @@ -349,12 +350,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(res, dest)?; } "free" => { - let &[ref ptr] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[ref ptr] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let ptr = this.read_scalar(ptr)?.check_init()?; this.free(ptr, MiriMemoryKind::C)?; } "realloc" => { - let &[ref old_ptr, ref new_size] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[ref old_ptr, ref new_size] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let old_ptr = this.read_scalar(old_ptr)?.check_init()?; let new_size = this.read_scalar(new_size)?.to_machine_usize(this)?; let res = this.realloc(old_ptr, new_size, MiriMemoryKind::C)?; @@ -365,7 +366,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // (Usually these would be forwarded to to `#[global_allocator]`; we instead implement a generic // allocation that also checks that all conditions are met, such as not permitting zero-sized allocations.) "__rust_alloc" => { - let &[ref size, ref align] = this.check_shim(abi, Abi::Rust, link_name_sym, args)?; + let &[ref size, ref align] = this.check_shim(abi, Abi::Rust, link_name, args)?; let size = this.read_scalar(size)?.to_machine_usize(this)?; let align = this.read_scalar(align)?.to_machine_usize(this)?; Self::check_alloc_request(size, align)?; @@ -377,7 +378,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(ptr, dest)?; } "__rust_alloc_zeroed" => { - let &[ref size, ref align] = this.check_shim(abi, Abi::Rust, link_name_sym, args)?; + let &[ref size, ref align] = this.check_shim(abi, Abi::Rust, link_name, args)?; let size = this.read_scalar(size)?.to_machine_usize(this)?; let align = this.read_scalar(align)?.to_machine_usize(this)?; Self::check_alloc_request(size, align)?; @@ -391,7 +392,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(ptr, dest)?; } "__rust_dealloc" => { - let &[ref ptr, ref old_size, ref align] = this.check_shim(abi, Abi::Rust, link_name_sym, args)?; + let &[ref ptr, ref old_size, ref align] = this.check_shim(abi, Abi::Rust, link_name, args)?; let ptr = this.read_scalar(ptr)?.check_init()?; let old_size = this.read_scalar(old_size)?.to_machine_usize(this)?; let align = this.read_scalar(align)?.to_machine_usize(this)?; @@ -404,7 +405,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx )?; } "__rust_realloc" => { - let &[ref ptr, ref old_size, ref align, ref new_size] = this.check_shim(abi, Abi::Rust, link_name_sym, args)?; + let &[ref ptr, ref old_size, ref align, ref new_size] = this.check_shim(abi, Abi::Rust, link_name, args)?; let ptr = this.force_ptr(this.read_scalar(ptr)?.check_init()?)?; let old_size = this.read_scalar(old_size)?.to_machine_usize(this)?; let align = this.read_scalar(align)?.to_machine_usize(this)?; @@ -424,7 +425,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // C memory handling functions "memcmp" => { - let &[ref left, ref right, ref n] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[ref left, ref right, ref n] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let left = this.read_scalar(left)?.check_init()?; let right = this.read_scalar(right)?.check_init()?; let n = Size::from_bytes(this.read_scalar(n)?.to_machine_usize(this)?); @@ -444,7 +445,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_i32(result), dest)?; } "memrchr" => { - let &[ref ptr, ref val, ref num] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[ref ptr, ref val, ref num] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let ptr = this.read_scalar(ptr)?.check_init()?; let val = this.read_scalar(val)?.to_i32()? as u8; let num = this.read_scalar(num)?.to_machine_usize(this)?; @@ -462,7 +463,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } "memchr" => { - let &[ref ptr, ref val, ref num] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[ref ptr, ref val, ref num] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let ptr = this.read_scalar(ptr)?.check_init()?; let val = this.read_scalar(val)?.to_i32()? as u8; let num = this.read_scalar(num)?.to_machine_usize(this)?; @@ -479,7 +480,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } "strlen" => { - let &[ref ptr] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[ref ptr] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let ptr = this.read_scalar(ptr)?.check_init()?; let n = this.read_c_str(ptr)?.len(); this.write_scalar(Scalar::from_machine_usize(u64::try_from(n).unwrap(), this), dest)?; @@ -495,10 +496,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "asinf" | "atanf" => { - let &[ref f] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[ref f] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; // FIXME: Using host floats. let f = f32::from_bits(this.read_scalar(f)?.to_u32()?); - let f = match link_name { + let f = match shim_name { "cbrtf" => f.cbrt(), "coshf" => f.cosh(), "sinhf" => f.sinh(), @@ -515,13 +516,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "hypotf" | "atan2f" => { - let &[ref f1, ref f2] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[ref f1, ref f2] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; // underscore case for windows, here and below // (see https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/floating-point-primitives?view=vs-2019) // FIXME: Using host floats. let f1 = f32::from_bits(this.read_scalar(f1)?.to_u32()?); let f2 = f32::from_bits(this.read_scalar(f2)?.to_u32()?); - let n = match link_name { + let n = match shim_name { "_hypotf" | "hypotf" => f1.hypot(f2), "atan2f" => f1.atan2(f2), _ => bug!(), @@ -537,10 +538,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "asin" | "atan" => { - let &[ref f] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[ref f] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; // FIXME: Using host floats. let f = f64::from_bits(this.read_scalar(f)?.to_u64()?); - let f = match link_name { + let f = match shim_name { "cbrt" => f.cbrt(), "cosh" => f.cosh(), "sinh" => f.sinh(), @@ -557,11 +558,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "hypot" | "atan2" => { - let &[ref f1, ref f2] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[ref f1, ref f2] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; // FIXME: Using host floats. let f1 = f64::from_bits(this.read_scalar(f1)?.to_u64()?); let f2 = f64::from_bits(this.read_scalar(f2)?.to_u64()?); - let n = match link_name { + let n = match shim_name { "_hypot" | "hypot" => f1.hypot(f2), "atan2" => f1.atan2(f2), _ => bug!(), @@ -573,7 +574,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "ldexp" | "scalbn" => { - let &[ref x, ref exp] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[ref x, ref exp] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; // For radix-2 (binary) systems, `ldexp` and `scalbn` are the same. let x = this.read_scalar(x)?.to_f64()?; let exp = this.read_scalar(exp)?.to_i32()?; @@ -594,11 +595,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Architecture-specific shims "llvm.x86.sse2.pause" if this.tcx.sess.target.arch == "x86" || this.tcx.sess.target.arch == "x86_64" => { - let &[] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; this.yield_active_thread(); } "llvm.aarch64.isb" if this.tcx.sess.target.arch == "aarch64" => { - let &[ref arg] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[ref arg] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let arg = this.read_scalar(arg)?.to_i32()?; match arg { 15 => { // SY ("full system scope") @@ -612,8 +613,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Platform-specific shims _ => match this.tcx.sess.target.os.as_str() { - "linux" | "macos" => return shims::posix::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, link_name_sym, abi, args, dest, ret), - "windows" => return shims::windows::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, link_name_sym, abi, args, dest, ret), + "linux" | "macos" => return shims::posix::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, abi, args, dest, ret), + "windows" => return shims::windows::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, abi, args, dest, ret), target => throw_unsup_format!("the target `{}` is not supported", target), } }; diff --git a/src/shims/posix/foreign_items.rs b/src/shims/posix/foreign_items.rs index ac26b39757a19..2585b562f2304 100644 --- a/src/shims/posix/foreign_items.rs +++ b/src/shims/posix/foreign_items.rs @@ -6,6 +6,7 @@ use rustc_target::abi::{Align, LayoutOf, Size}; use rustc_target::spec::abi::Abi; use crate::*; +use helpers::strip_linker_suffix; use shims::foreign_items::EmulateByNameResult; use shims::posix::fs::EvalContextExt as _; use shims::posix::sync::EvalContextExt as _; @@ -15,8 +16,7 @@ impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mi pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { fn emulate_foreign_item_by_name( &mut self, - link_name: &str, - link_name_sym: Symbol, + link_name: Symbol, abi: Abi, args: &[OpTy<'tcx, Tag>], dest: &PlaceTy<'tcx, Tag>, @@ -24,50 +24,50 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, EmulateByNameResult> { let this = self.eval_context_mut(); - match link_name { + match strip_linker_suffix(&link_name.as_str()) { // Environment related shims "getenv" => { - let &[ref name] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[ref name] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.getenv(name)?; this.write_scalar(result, dest)?; } "unsetenv" => { - let &[ref name] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[ref name] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.unsetenv(name)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "setenv" => { - let &[ref name, ref value, ref overwrite] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[ref name, ref value, ref overwrite] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; this.read_scalar(overwrite)?.to_i32()?; let result = this.setenv(name, value)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "getcwd" => { - let &[ref buf, ref size] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[ref buf, ref size] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.getcwd(buf, size)?; this.write_scalar(result, dest)?; } "chdir" => { - let &[ref path] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[ref path] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.chdir(path)?; this.write_scalar(Scalar::from_i32(result), dest)?; } // File related shims "open" | "open64" => { - let &[ref path, ref flag, ref mode] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[ref path, ref flag, ref mode] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.open(path, flag, mode)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "fcntl" => { // `fcntl` is variadic. The argument count is checked based on the first argument // in `this.fcntl()`, so we do not use `check_shim` here. - this.check_abi_and_shim_symbol_clash(abi, Abi::C { unwind: false }, link_name_sym)?; + this.check_abi_and_shim_symbol_clash(abi, Abi::C { unwind: false }, link_name)?; let result = this.fcntl(args)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "read" => { - let &[ref fd, ref buf, ref count] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[ref fd, ref buf, ref count] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let fd = this.read_scalar(fd)?.to_i32()?; let buf = this.read_scalar(buf)?.check_init()?; let count = this.read_scalar(count)?.to_machine_usize(this)?; @@ -75,7 +75,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_machine_isize(result, this), dest)?; } "write" => { - let &[ref fd, ref buf, ref n] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[ref fd, ref buf, ref n] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let fd = this.read_scalar(fd)?.to_i32()?; let buf = this.read_scalar(buf)?.check_init()?; let count = this.read_scalar(n)?.to_machine_usize(this)?; @@ -85,60 +85,60 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_machine_isize(result, this), dest)?; } "unlink" => { - let &[ref path] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[ref path] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.unlink(path)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "symlink" => { - let &[ref target, ref linkpath] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[ref target, ref linkpath] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.symlink(target, linkpath)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "rename" => { - let &[ref oldpath, ref newpath] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[ref oldpath, ref newpath] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.rename(oldpath, newpath)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "mkdir" => { - let &[ref path, ref mode] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[ref path, ref mode] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.mkdir(path, mode)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "rmdir" => { - let &[ref path] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[ref path] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.rmdir(path)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "closedir" => { - let &[ref dirp] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[ref dirp] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.closedir(dirp)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "lseek" | "lseek64" => { - let &[ref fd, ref offset, ref whence] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[ref fd, ref offset, ref whence] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.lseek64(fd, offset, whence)?; // "lseek" is only used on macOS which is 64bit-only, so `i64` always works. this.write_scalar(Scalar::from_i64(result), dest)?; } "fsync" => { - let &[ref fd] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[ref fd] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.fsync(fd)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "fdatasync" => { - let &[ref fd] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[ref fd] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.fdatasync(fd)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "readlink" => { - let &[ref pathname, ref buf, ref bufsize] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[ref pathname, ref buf, ref bufsize] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.readlink(pathname, buf, bufsize)?; this.write_scalar(Scalar::from_machine_isize(result, this), dest)?; } // Allocation "posix_memalign" => { - let &[ref ret, ref align, ref size] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[ref ret, ref align, ref size] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let ret = this.deref_operand(ret)?; let align = this.read_scalar(align)?.to_machine_usize(this)?; let size = this.read_scalar(size)?.to_machine_usize(this)?; @@ -168,7 +168,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Dynamic symbol loading "dlsym" => { - let &[ref handle, ref symbol] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[ref handle, ref symbol] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; this.read_scalar(handle)?.to_machine_usize(this)?; let symbol = this.read_scalar(symbol)?.check_init()?; let symbol_name = this.read_c_str(symbol)?; @@ -182,7 +182,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Querying system information "sysconf" => { - let &[ref name] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[ref name] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let name = this.read_scalar(name)?.to_i32()?; let sysconfs = &[ @@ -207,7 +207,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Thread-local storage "pthread_key_create" => { - let &[ref key, ref dtor] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[ref key, ref dtor] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let key_place = this.deref_operand(key)?; let dtor = this.read_scalar(dtor)?.check_init()?; @@ -235,21 +235,21 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_null(dest)?; } "pthread_key_delete" => { - let &[ref key] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[ref key] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let key = this.force_bits(this.read_scalar(key)?.check_init()?, key.layout.size)?; this.machine.tls.delete_tls_key(key)?; // Return success (0) this.write_null(dest)?; } "pthread_getspecific" => { - let &[ref key] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[ref key] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let key = this.force_bits(this.read_scalar(key)?.check_init()?, key.layout.size)?; let active_thread = this.get_active_thread(); let ptr = this.machine.tls.load_tls(key, active_thread, this)?; this.write_scalar(ptr, dest)?; } "pthread_setspecific" => { - let &[ref key, ref new_ptr] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[ref key, ref new_ptr] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let key = this.force_bits(this.read_scalar(key)?.check_init()?, key.layout.size)?; let active_thread = this.get_active_thread(); let new_ptr = this.read_scalar(new_ptr)?.check_init()?; @@ -261,149 +261,149 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Synchronization primitives "pthread_mutexattr_init" => { - let &[ref attr] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[ref attr] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.pthread_mutexattr_init(attr)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_mutexattr_settype" => { - let &[ref attr, ref kind] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[ref attr, ref kind] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.pthread_mutexattr_settype(attr, kind)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_mutexattr_destroy" => { - let &[ref attr] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[ref attr] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.pthread_mutexattr_destroy(attr)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_mutex_init" => { - let &[ref mutex, ref attr] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[ref mutex, ref attr] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.pthread_mutex_init(mutex, attr)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_mutex_lock" => { - let &[ref mutex] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[ref mutex] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.pthread_mutex_lock(mutex)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_mutex_trylock" => { - let &[ref mutex] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[ref mutex] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.pthread_mutex_trylock(mutex)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_mutex_unlock" => { - let &[ref mutex] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[ref mutex] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.pthread_mutex_unlock(mutex)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_mutex_destroy" => { - let &[ref mutex] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[ref mutex] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.pthread_mutex_destroy(mutex)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_rwlock_rdlock" => { - let &[ref rwlock] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[ref rwlock] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.pthread_rwlock_rdlock(rwlock)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_rwlock_tryrdlock" => { - let &[ref rwlock] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[ref rwlock] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.pthread_rwlock_tryrdlock(rwlock)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_rwlock_wrlock" => { - let &[ref rwlock] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[ref rwlock] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.pthread_rwlock_wrlock(rwlock)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_rwlock_trywrlock" => { - let &[ref rwlock] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[ref rwlock] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.pthread_rwlock_trywrlock(rwlock)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_rwlock_unlock" => { - let &[ref rwlock] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[ref rwlock] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.pthread_rwlock_unlock(rwlock)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_rwlock_destroy" => { - let &[ref rwlock] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[ref rwlock] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.pthread_rwlock_destroy(rwlock)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_condattr_init" => { - let &[ref attr] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[ref attr] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.pthread_condattr_init(attr)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_condattr_destroy" => { - let &[ref attr] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[ref attr] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.pthread_condattr_destroy(attr)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_cond_init" => { - let &[ref cond, ref attr] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[ref cond, ref attr] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.pthread_cond_init(cond, attr)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_cond_signal" => { - let &[ref cond] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[ref cond] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.pthread_cond_signal(cond)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_cond_broadcast" => { - let &[ref cond] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[ref cond] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.pthread_cond_broadcast(cond)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_cond_wait" => { - let &[ref cond, ref mutex] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[ref cond, ref mutex] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.pthread_cond_wait(cond, mutex)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_cond_timedwait" => { - let &[ref cond, ref mutex, ref abstime] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[ref cond, ref mutex, ref abstime] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; this.pthread_cond_timedwait(cond, mutex, abstime, dest)?; } "pthread_cond_destroy" => { - let &[ref cond] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[ref cond] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.pthread_cond_destroy(cond)?; this.write_scalar(Scalar::from_i32(result), dest)?; } // Threading "pthread_create" => { - let &[ref thread, ref attr, ref start, ref arg] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[ref thread, ref attr, ref start, ref arg] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.pthread_create(thread, attr, start, arg)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_join" => { - let &[ref thread, ref retval] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[ref thread, ref retval] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.pthread_join(thread, retval)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_detach" => { - let &[ref thread] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[ref thread] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.pthread_detach(thread)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_self" => { - let &[] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; this.pthread_self(dest)?; } "sched_yield" => { - let &[] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.sched_yield()?; this.write_scalar(Scalar::from_i32(result), dest)?; } "nanosleep" => { - let &[ref req, ref rem] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[ref req, ref rem] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.nanosleep(req, rem)?; this.write_scalar(Scalar::from_i32(result), dest)?; } // Miscellaneous "isatty" => { - let &[ref fd] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[ref fd] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; this.read_scalar(fd)?.to_i32()?; // "returns 1 if fd is an open file descriptor referring to a terminal; otherwise 0 is returned, and errno is set to indicate the error" // FIXME: we just say nothing is a terminal. @@ -412,7 +412,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_null(dest)?; } "pthread_atfork" => { - let &[ref prepare, ref parent, ref child] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[ref prepare, ref parent, ref child] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; this.force_bits(this.read_scalar(prepare)?.check_init()?, this.memory.pointer_size())?; this.force_bits(this.read_scalar(parent)?.check_init()?, this.memory.pointer_size())?; this.force_bits(this.read_scalar(child)?.check_init()?, this.memory.pointer_size())?; @@ -424,7 +424,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // These shims are enabled only when the caller is in the standard library. "pthread_attr_getguardsize" if this.frame_in_std() => { - let &[ref _attr, ref guard_size] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[ref _attr, ref guard_size] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let guard_size = this.deref_operand(guard_size)?; let guard_size_layout = this.libc_ty_layout("size_t")?; this.write_scalar(Scalar::from_uint(crate::PAGE_SIZE, guard_size_layout.size), &guard_size.into())?; @@ -436,33 +436,33 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "pthread_attr_init" | "pthread_attr_destroy" if this.frame_in_std() => { - let &[_] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[_] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; this.write_null(dest)?; } | "pthread_attr_setstacksize" if this.frame_in_std() => { - let &[_, _] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[_, _] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; this.write_null(dest)?; } | "signal" | "sigaltstack" if this.frame_in_std() => { - let &[_, _] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[_, _] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; this.write_null(dest)?; } | "sigaction" | "mprotect" if this.frame_in_std() => { - let &[_, _, _] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[_, _, _] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; this.write_null(dest)?; } // Platform-specific shims _ => { match this.tcx.sess.target.os.as_str() { - "linux" => return shims::posix::linux::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, link_name_sym, abi, args, dest, ret), - "macos" => return shims::posix::macos::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, link_name_sym, abi, args, dest, ret), + "linux" => return shims::posix::linux::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, abi, args, dest, ret), + "macos" => return shims::posix::macos::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, abi, args, dest, ret), _ => unreachable!(), } } diff --git a/src/shims/posix/linux/foreign_items.rs b/src/shims/posix/linux/foreign_items.rs index 07d764a68e913..160e27f395e5e 100644 --- a/src/shims/posix/linux/foreign_items.rs +++ b/src/shims/posix/linux/foreign_items.rs @@ -3,6 +3,7 @@ use rustc_span::Symbol; use rustc_target::spec::abi::Abi; use crate::*; +use helpers::strip_linker_suffix; use shims::foreign_items::EmulateByNameResult; use shims::posix::fs::EvalContextExt as _; use shims::posix::linux::sync::futex; @@ -13,8 +14,7 @@ impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mi pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { fn emulate_foreign_item_by_name( &mut self, - link_name: &str, - link_name_sym: Symbol, + link_name: Symbol, abi: Abi, args: &[OpTy<'tcx, Tag>], dest: &PlaceTy<'tcx, Tag>, @@ -22,10 +22,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, EmulateByNameResult> { let this = self.eval_context_mut(); - match link_name { + match strip_linker_suffix(&link_name.as_str()) { // errno "__errno_location" => { - let &[] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let errno_place = this.last_error_place()?; this.write_scalar(errno_place.to_ref().to_scalar()?, dest)?; } @@ -34,33 +34,32 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // These symbols have different names on Linux and macOS, which is the only reason they are not // in the `posix` module. "close" => { - let &[ref fd] = - this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[ref fd] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.close(fd)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "opendir" => { let &[ref name] = - this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.opendir(name)?; this.write_scalar(result, dest)?; } "readdir64_r" => { let &[ref dirp, ref entry, ref result] = - this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.linux_readdir64_r(dirp, entry, result)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "ftruncate64" => { let &[ref fd, ref length] = - this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.ftruncate64(fd, length)?; this.write_scalar(Scalar::from_i32(result), dest)?; } // Linux-only "posix_fadvise" => { let &[ref fd, ref offset, ref len, ref advice] = - this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; this.read_scalar(fd)?.to_i32()?; this.read_scalar(offset)?.to_machine_isize(this)?; this.read_scalar(len)?.to_machine_isize(this)?; @@ -70,7 +69,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "sync_file_range" => { let &[ref fd, ref offset, ref nbytes, ref flags] = - this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.sync_file_range(fd, offset, nbytes, flags)?; this.write_scalar(Scalar::from_i32(result), dest)?; } @@ -79,7 +78,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "clock_gettime" => { // This is a POSIX function but it has only been tested on linux. let &[ref clk_id, ref tp] = - this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.clock_gettime(clk_id, tp)?; this.write_scalar(Scalar::from_i32(result), dest)?; } @@ -88,7 +87,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "pthread_attr_getstack" => { // We don't support "pthread_attr_setstack", so we just pretend all stacks have the same values here. let &[ref attr_place, ref addr_place, ref size_place] = - this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; this.deref_operand(attr_place)?; let addr_place = this.deref_operand(addr_place)?; let size_place = this.deref_operand(size_place)?; @@ -109,19 +108,19 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Threading "prctl" => { let &[ref option, ref arg2, ref arg3, ref arg4, ref arg5] = - this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.prctl(option, arg2, arg3, arg4, arg5)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_condattr_setclock" => { let &[ref attr, ref clock_id] = - this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.pthread_condattr_setclock(attr, clock_id)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_condattr_getclock" => { let &[ref attr, ref clock_id] = - this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.pthread_condattr_getclock(attr, clock_id)?; this.write_scalar(Scalar::from_i32(result), dest)?; } @@ -130,7 +129,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "syscall" => { // We do not use `check_shim` here because `syscall` is variadic. The argument // count is checked bellow. - this.check_abi_and_shim_symbol_clash(abi, Abi::C { unwind: false }, link_name_sym)?; + this.check_abi_and_shim_symbol_clash(abi, Abi::C { unwind: false }, link_name)?; // The syscall variadic function is legal to call with more arguments than needed, // extra arguments are simply ignored. However, all arguments need to be scalars; // other types might be treated differently by the calling convention. @@ -195,12 +194,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Miscelanneous "getrandom" => { let &[ref ptr, ref len, ref flags] = - this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; getrandom(this, ptr, len, flags, dest)?; } "sched_getaffinity" => { let &[ref pid, ref cpusetsize, ref mask] = - this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; this.read_scalar(pid)?.to_i32()?; this.read_scalar(cpusetsize)?.to_machine_usize(this)?; this.deref_operand(mask)?; @@ -214,7 +213,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // These shims are enabled only when the caller is in the standard library. "pthread_getattr_np" if this.frame_in_std() => { let &[ref _thread, ref _attr] = - this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; this.write_null(dest)?; } diff --git a/src/shims/posix/macos/foreign_items.rs b/src/shims/posix/macos/foreign_items.rs index 37de757e9b8dc..45d6f5b449534 100644 --- a/src/shims/posix/macos/foreign_items.rs +++ b/src/shims/posix/macos/foreign_items.rs @@ -3,6 +3,7 @@ use rustc_span::Symbol; use rustc_target::spec::abi::Abi; use crate::*; +use helpers::strip_linker_suffix; use shims::foreign_items::EmulateByNameResult; use shims::posix::fs::EvalContextExt as _; use shims::posix::thread::EvalContextExt as _; @@ -11,8 +12,7 @@ impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mi pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { fn emulate_foreign_item_by_name( &mut self, - link_name: &str, - link_name_sym: Symbol, + link_name: Symbol, abi: Abi, args: &[OpTy<'tcx, Tag>], dest: &PlaceTy<'tcx, Tag>, @@ -20,10 +20,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, EmulateByNameResult> { let this = self.eval_context_mut(); - match link_name { + match strip_linker_suffix(&link_name.as_str()) { // errno "__error" => { - let &[] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let errno_place = this.last_error_place()?; this.write_scalar(errno_place.to_ref().to_scalar()?, dest)?; } @@ -31,87 +31,87 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // File related shims "close" | "close$NOCANCEL" => { let &[ref result] = - this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.close(result)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "stat" | "stat$INODE64" => { let &[ref path, ref buf] = - this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.macos_stat(path, buf)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "lstat" | "lstat$INODE64" => { let &[ref path, ref buf] = - this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.macos_lstat(path, buf)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "fstat" | "fstat$INODE64" => { let &[ref fd, ref buf] = - this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.macos_fstat(fd, buf)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "opendir" | "opendir$INODE64" => { let &[ref name] = - this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.opendir(name)?; this.write_scalar(result, dest)?; } "readdir_r" | "readdir_r$INODE64" => { let &[ref dirp, ref entry, ref result] = - this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.macos_readdir_r(dirp, entry, result)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "ftruncate" => { let &[ref fd, ref length] = - this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.ftruncate64(fd, length)?; this.write_scalar(Scalar::from_i32(result), dest)?; } // Environment related shims "_NSGetEnviron" => { - let &[] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; this.write_scalar(this.machine.env_vars.environ.unwrap().ptr, dest)?; } // Time related shims "gettimeofday" => { let &[ref tv, ref tz] = - this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.gettimeofday(tv, tz)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "mach_absolute_time" => { - let &[] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.mach_absolute_time()?; this.write_scalar(Scalar::from_u64(result), dest)?; } "mach_timebase_info" => { let &[ref info] = - this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.mach_timebase_info(info)?; this.write_scalar(Scalar::from_i32(result), dest)?; } // Access to command-line arguments "_NSGetArgc" => { - let &[] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; this.write_scalar(this.machine.argc.expect("machine must be initialized"), dest)?; } "_NSGetArgv" => { - let &[] = this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; this.write_scalar(this.machine.argv.expect("machine must be initialized"), dest)?; } // Thread-local storage "_tlv_atexit" => { let &[ref dtor, ref data] = - this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let dtor = this.read_scalar(dtor)?.check_init()?; let dtor = this.memory.get_fn(dtor)?.as_instance()?; let data = this.read_scalar(data)?.check_init()?; @@ -122,14 +122,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Querying system information "pthread_get_stackaddr_np" => { let &[ref thread] = - this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; this.read_scalar(thread)?.to_machine_usize(this)?; let stack_addr = Scalar::from_uint(STACK_ADDR, this.pointer_size()); this.write_scalar(stack_addr, dest)?; } "pthread_get_stacksize_np" => { let &[ref thread] = - this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; this.read_scalar(thread)?.to_machine_usize(this)?; let stack_size = Scalar::from_uint(STACK_SIZE, this.pointer_size()); this.write_scalar(stack_size, dest)?; @@ -138,7 +138,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Threading "pthread_setname_np" => { let &[ref name] = - this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let name = this.read_scalar(name)?.check_init()?; this.pthread_setname_np(name)?; } @@ -148,7 +148,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "mmap" if this.frame_in_std() => { // This is a horrible hack, but since the guard page mechanism calls mmap and expects a particular return value, we just give it that value. let &[ref addr, _, _, _, _, _] = - this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let addr = this.read_scalar(addr)?.check_init()?; this.write_scalar(addr, dest)?; } diff --git a/src/shims/windows/foreign_items.rs b/src/shims/windows/foreign_items.rs index f12e4df8cdfe3..77f8075361418 100644 --- a/src/shims/windows/foreign_items.rs +++ b/src/shims/windows/foreign_items.rs @@ -6,6 +6,7 @@ use rustc_target::abi::Size; use rustc_target::spec::abi::Abi; use crate::*; +use helpers::strip_linker_suffix; use shims::foreign_items::EmulateByNameResult; use shims::windows::sync::EvalContextExt as _; @@ -13,8 +14,7 @@ impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mi pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { fn emulate_foreign_item_by_name( &mut self, - link_name: &str, - link_name_sym: Symbol, + link_name: Symbol, abi: Abi, args: &[OpTy<'tcx, Tag>], dest: &PlaceTy<'tcx, Tag>, @@ -27,41 +27,40 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // DWORD = ULONG = u32 // BOOL = i32 // BOOLEAN = u8 - match link_name { + match strip_linker_suffix(&link_name.as_str()) { // Environment related shims "GetEnvironmentVariableW" => { let &[ref name, ref buf, ref size] = - this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; + this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; let result = this.GetEnvironmentVariableW(name, buf, size)?; this.write_scalar(Scalar::from_u32(result), dest)?; } "SetEnvironmentVariableW" => { let &[ref name, ref value] = - this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; + this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; let result = this.SetEnvironmentVariableW(name, value)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "GetEnvironmentStringsW" => { - let &[] = - this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; + let &[] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; let result = this.GetEnvironmentStringsW()?; this.write_scalar(result, dest)?; } "FreeEnvironmentStringsW" => { let &[ref env_block] = - this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; + this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; let result = this.FreeEnvironmentStringsW(env_block)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "GetCurrentDirectoryW" => { let &[ref size, ref buf] = - this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; + this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; let result = this.GetCurrentDirectoryW(size, buf)?; this.write_scalar(Scalar::from_u32(result), dest)?; } "SetCurrentDirectoryW" => { let &[ref path] = - this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; + this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; let result = this.SetCurrentDirectoryW(path)?; this.write_scalar(Scalar::from_i32(result), dest)?; } @@ -69,7 +68,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // File related shims "GetStdHandle" => { let &[ref which] = - this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; + this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; let which = this.read_scalar(which)?.to_i32()?; // We just make this the identity function, so we know later in `WriteFile` // which one it is. @@ -77,7 +76,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "WriteFile" => { let &[ref handle, ref buf, ref n, ref written_ptr, ref overlapped] = - this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; + this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; this.read_scalar(overlapped)?.to_machine_usize(this)?; // this is a poiner, that we ignore let handle = this.read_scalar(handle)?.to_machine_isize(this)?; let buf = this.read_scalar(buf)?.check_init()?; @@ -112,7 +111,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Allocation "HeapAlloc" => { let &[ref handle, ref flags, ref size] = - this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; + this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; this.read_scalar(handle)?.to_machine_isize(this)?; let flags = this.read_scalar(flags)?.to_u32()?; let size = this.read_scalar(size)?.to_machine_usize(this)?; @@ -122,7 +121,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "HeapFree" => { let &[ref handle, ref flags, ref ptr] = - this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; + this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; this.read_scalar(handle)?.to_machine_isize(this)?; this.read_scalar(flags)?.to_u32()?; let ptr = this.read_scalar(ptr)?.check_init()?; @@ -131,7 +130,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "HeapReAlloc" => { let &[ref handle, ref flags, ref ptr, ref size] = - this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; + this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; this.read_scalar(handle)?.to_machine_isize(this)?; this.read_scalar(flags)?.to_u32()?; let ptr = this.read_scalar(ptr)?.check_init()?; @@ -143,13 +142,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // errno "SetLastError" => { let &[ref error] = - this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; + this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; let error = this.read_scalar(error)?.check_init()?; this.set_last_error(error)?; } "GetLastError" => { - let &[] = - this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; + let &[] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; let last_error = this.get_last_error()?; this.write_scalar(last_error, dest)?; } @@ -157,7 +155,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Querying system information "GetSystemInfo" => { let &[ref system_info] = - this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; + this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; let system_info = this.deref_operand(system_info)?; // Initialize with `0`. this.memory.write_bytes( @@ -175,14 +173,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // This just creates a key; Windows does not natively support TLS destructors. // Create key and return it. - let &[] = - this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; + let &[] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; let key = this.machine.tls.create_tls_key(None, dest.layout.size)?; this.write_scalar(Scalar::from_uint(key, dest.layout.size), dest)?; } "TlsGetValue" => { let &[ref key] = - this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; + this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; let key = u128::from(this.read_scalar(key)?.to_u32()?); let active_thread = this.get_active_thread(); let ptr = this.machine.tls.load_tls(key, active_thread, this)?; @@ -190,7 +187,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "TlsSetValue" => { let &[ref key, ref new_ptr] = - this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; + this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; let key = u128::from(this.read_scalar(key)?.to_u32()?); let active_thread = this.get_active_thread(); let new_ptr = this.read_scalar(new_ptr)?.check_init()?; @@ -202,8 +199,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Access to command-line arguments "GetCommandLineW" => { - let &[] = - this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; + let &[] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; this.write_scalar( this.machine.cmd_line.expect("machine must be initialized"), dest, @@ -214,20 +210,20 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "GetSystemTimeAsFileTime" => { #[allow(non_snake_case)] let &[ref LPFILETIME] = - this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; + this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; this.GetSystemTimeAsFileTime(LPFILETIME)?; } "QueryPerformanceCounter" => { #[allow(non_snake_case)] let &[ref lpPerformanceCount] = - this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; + this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; let result = this.QueryPerformanceCounter(lpPerformanceCount)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "QueryPerformanceFrequency" => { #[allow(non_snake_case)] let &[ref lpFrequency] = - this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; + this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; let result = this.QueryPerformanceFrequency(lpFrequency)?; this.write_scalar(Scalar::from_i32(result), dest)?; } @@ -235,33 +231,33 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Synchronization primitives "AcquireSRWLockExclusive" => { let &[ref ptr] = - this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; + this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; this.AcquireSRWLockExclusive(ptr)?; } "ReleaseSRWLockExclusive" => { let &[ref ptr] = - this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; + this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; this.ReleaseSRWLockExclusive(ptr)?; } "TryAcquireSRWLockExclusive" => { let &[ref ptr] = - this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; + this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; let ret = this.TryAcquireSRWLockExclusive(ptr)?; this.write_scalar(Scalar::from_u8(ret), dest)?; } "AcquireSRWLockShared" => { let &[ref ptr] = - this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; + this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; this.AcquireSRWLockShared(ptr)?; } "ReleaseSRWLockShared" => { let &[ref ptr] = - this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; + this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; this.ReleaseSRWLockShared(ptr)?; } "TryAcquireSRWLockShared" => { let &[ref ptr] = - this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; + this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; let ret = this.TryAcquireSRWLockShared(ptr)?; this.write_scalar(Scalar::from_u8(ret), dest)?; } @@ -270,7 +266,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "GetProcAddress" => { #[allow(non_snake_case)] let &[ref hModule, ref lpProcName] = - this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; + this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; this.read_scalar(hModule)?.to_machine_isize(this)?; let name = this.read_c_str(this.read_scalar(lpProcName)?.check_init()?)?; if let Some(dlsym) = Dlsym::from_str(name, &this.tcx.sess.target.os)? { @@ -285,7 +281,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "SystemFunction036" => { // This is really 'RtlGenRandom'. let &[ref ptr, ref len] = - this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; + this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; let ptr = this.read_scalar(ptr)?.check_init()?; let len = this.read_scalar(len)?.to_u32()?; this.gen_random(ptr, len.into())?; @@ -293,7 +289,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "BCryptGenRandom" => { let &[ref algorithm, ref ptr, ref len, ref flags] = - this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; + this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; let algorithm = this.read_scalar(algorithm)?; let ptr = this.read_scalar(ptr)?.check_init()?; let len = this.read_scalar(len)?.to_u32()?; @@ -315,7 +311,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "GetConsoleScreenBufferInfo" => { // `term` needs this, so we fake it. let &[ref console, ref buffer_info] = - this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; + this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; this.read_scalar(console)?.to_machine_isize(this)?; this.deref_operand(buffer_info)?; // Indicate an error. @@ -325,7 +321,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "GetConsoleMode" => { // Windows "isatty" (in libtest) needs this, so we fake it. let &[ref console, ref mode] = - this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; + this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; this.read_scalar(console)?.to_machine_isize(this)?; this.deref_operand(mode)?; // Indicate an error. @@ -333,8 +329,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_null(dest)?; } "SwitchToThread" => { - let &[] = - this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; + let &[] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; // Note that once Miri supports concurrency, this will need to return a nonzero // value if this call does result in switching to another thread. this.write_null(dest)?; @@ -343,7 +338,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Better error for attempts to create a thread "CreateThread" => { let &[_, _, _, _, _, _] = - this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; + this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; this.handle_unsupported("can't create threads on Windows")?; return Ok(EmulateByNameResult::AlreadyJumped); @@ -352,29 +347,28 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Incomplete shims that we "stub out" just to get pre-main initialization code to work. // These shims are enabled only when the caller is in the standard library. "GetProcessHeap" if this.frame_in_std() => { - let &[] = - this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; + let &[] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; // Just fake a HANDLE this.write_scalar(Scalar::from_machine_isize(1, this), dest)?; } "SetConsoleTextAttribute" if this.frame_in_std() => { #[allow(non_snake_case)] let &[ref _hConsoleOutput, ref _wAttribute] = - this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; + this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; // Pretend these does not exist / nothing happened, by returning zero. this.write_null(dest)?; } "AddVectoredExceptionHandler" if this.frame_in_std() => { #[allow(non_snake_case)] let &[ref _First, ref _Handler] = - this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; + this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; // Any non zero value works for the stdlib. This is just used for stack overflows anyway. this.write_scalar(Scalar::from_machine_usize(1, this), dest)?; } "SetThreadStackGuarantee" if this.frame_in_std() => { #[allow(non_snake_case)] let &[_StackSizeInBytes] = - this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; + this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; // Any non zero value works for the stdlib. This is just used for stack overflows anyway. this.write_scalar(Scalar::from_u32(1), dest)?; } @@ -386,7 +380,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx { #[allow(non_snake_case)] let &[ref _lpCriticalSection] = - this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; + this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; assert_eq!( this.get_total_thread_count(), 1, @@ -399,7 +393,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "TryEnterCriticalSection" if this.frame_in_std() => { #[allow(non_snake_case)] let &[ref _lpCriticalSection] = - this.check_shim(abi, Abi::System { unwind: false }, link_name_sym, args)?; + this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; assert_eq!( this.get_total_thread_count(), 1, From 9011524454aff19110a3efc1cd3bb68657a0f8ee Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Tue, 15 Jun 2021 01:16:38 +0800 Subject: [PATCH 2733/3747] Remove `strip_linker_suffix` --- src/helpers.rs | 5 ----- src/shims/foreign_items.rs | 16 ++++++---------- src/shims/posix/foreign_items.rs | 3 +-- src/shims/posix/linux/foreign_items.rs | 3 +-- src/shims/posix/macos/foreign_items.rs | 3 +-- src/shims/windows/foreign_items.rs | 3 +-- 6 files changed, 10 insertions(+), 23 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index 1a12d19e124e8..b99a446577ac4 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -723,11 +723,6 @@ where throw_ub_format!("incorrect number of arguments: got {}, expected {}", args.len(), N) } -/// Strip linker suffixes (seen on 32-bit macOS). -pub fn strip_linker_suffix(link_name: &str) -> &str { - link_name.trim_end_matches("$UNIX2003") -} - pub fn isolation_abort_error(name: &str) -> InterpResult<'static> { throw_machine_stop!(TerminationInfo::UnsupportedInIsolation(format!( "{} not available when isolation is enabled", diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 36d075e32dff2..3745b8cf2fa1d 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -25,7 +25,6 @@ use rustc_target::{ use super::backtrace::EvalContextExt as _; use crate::*; -use helpers::strip_linker_suffix; /// Returned by `emulate_foreign_item_by_name`. pub enum EmulateByNameResult { @@ -216,12 +215,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx .first_attr_value_str_by_name(&attrs, sym::link_name) .unwrap_or_else(|| this.tcx.item_name(def_id)); let link_name = link_name_sym.as_str(); - let link_name = strip_linker_suffix(&link_name); let tcx = this.tcx.tcx; // First: functions that diverge. let (dest, ret) = match ret { - None => match link_name { + None => match &*link_name { "miri_start_panic" => { // `check_shim` happens inside `handle_miri_start_panic`. this.handle_miri_start_panic(abi, link_name_sym, args, unwind)?; @@ -306,9 +304,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Here we dispatch all the shims for foreign functions. If you have a platform specific // shim, add it to the corresponding submodule. - let shim_name = link_name.as_str(); - let shim_name = strip_linker_suffix(&shim_name); - match shim_name { + match &*link_name.as_str() { // Miri-specific extern functions "miri_static_root" => { let &[ref ptr] = this.check_shim(abi, Abi::Rust, link_name, args)?; @@ -499,7 +495,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let &[ref f] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; // FIXME: Using host floats. let f = f32::from_bits(this.read_scalar(f)?.to_u32()?); - let f = match shim_name { + let f = match &*link_name.as_str() { "cbrtf" => f.cbrt(), "coshf" => f.cosh(), "sinhf" => f.sinh(), @@ -522,7 +518,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // FIXME: Using host floats. let f1 = f32::from_bits(this.read_scalar(f1)?.to_u32()?); let f2 = f32::from_bits(this.read_scalar(f2)?.to_u32()?); - let n = match shim_name { + let n = match &*link_name.as_str() { "_hypotf" | "hypotf" => f1.hypot(f2), "atan2f" => f1.atan2(f2), _ => bug!(), @@ -541,7 +537,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let &[ref f] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; // FIXME: Using host floats. let f = f64::from_bits(this.read_scalar(f)?.to_u64()?); - let f = match shim_name { + let f = match &*link_name.as_str() { "cbrt" => f.cbrt(), "cosh" => f.cosh(), "sinh" => f.sinh(), @@ -562,7 +558,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // FIXME: Using host floats. let f1 = f64::from_bits(this.read_scalar(f1)?.to_u64()?); let f2 = f64::from_bits(this.read_scalar(f2)?.to_u64()?); - let n = match shim_name { + let n = match &*link_name.as_str() { "_hypot" | "hypot" => f1.hypot(f2), "atan2" => f1.atan2(f2), _ => bug!(), diff --git a/src/shims/posix/foreign_items.rs b/src/shims/posix/foreign_items.rs index 2585b562f2304..4035deff63ef0 100644 --- a/src/shims/posix/foreign_items.rs +++ b/src/shims/posix/foreign_items.rs @@ -6,7 +6,6 @@ use rustc_target::abi::{Align, LayoutOf, Size}; use rustc_target::spec::abi::Abi; use crate::*; -use helpers::strip_linker_suffix; use shims::foreign_items::EmulateByNameResult; use shims::posix::fs::EvalContextExt as _; use shims::posix::sync::EvalContextExt as _; @@ -24,7 +23,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, EmulateByNameResult> { let this = self.eval_context_mut(); - match strip_linker_suffix(&link_name.as_str()) { + match &*link_name.as_str() { // Environment related shims "getenv" => { let &[ref name] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; diff --git a/src/shims/posix/linux/foreign_items.rs b/src/shims/posix/linux/foreign_items.rs index 160e27f395e5e..33889963bc448 100644 --- a/src/shims/posix/linux/foreign_items.rs +++ b/src/shims/posix/linux/foreign_items.rs @@ -3,7 +3,6 @@ use rustc_span::Symbol; use rustc_target::spec::abi::Abi; use crate::*; -use helpers::strip_linker_suffix; use shims::foreign_items::EmulateByNameResult; use shims::posix::fs::EvalContextExt as _; use shims::posix::linux::sync::futex; @@ -22,7 +21,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, EmulateByNameResult> { let this = self.eval_context_mut(); - match strip_linker_suffix(&link_name.as_str()) { + match &*link_name.as_str() { // errno "__errno_location" => { let &[] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; diff --git a/src/shims/posix/macos/foreign_items.rs b/src/shims/posix/macos/foreign_items.rs index 45d6f5b449534..47a860b96a87a 100644 --- a/src/shims/posix/macos/foreign_items.rs +++ b/src/shims/posix/macos/foreign_items.rs @@ -3,7 +3,6 @@ use rustc_span::Symbol; use rustc_target::spec::abi::Abi; use crate::*; -use helpers::strip_linker_suffix; use shims::foreign_items::EmulateByNameResult; use shims::posix::fs::EvalContextExt as _; use shims::posix::thread::EvalContextExt as _; @@ -20,7 +19,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, EmulateByNameResult> { let this = self.eval_context_mut(); - match strip_linker_suffix(&link_name.as_str()) { + match &*link_name.as_str() { // errno "__error" => { let &[] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; diff --git a/src/shims/windows/foreign_items.rs b/src/shims/windows/foreign_items.rs index 77f8075361418..1921af3594239 100644 --- a/src/shims/windows/foreign_items.rs +++ b/src/shims/windows/foreign_items.rs @@ -6,7 +6,6 @@ use rustc_target::abi::Size; use rustc_target::spec::abi::Abi; use crate::*; -use helpers::strip_linker_suffix; use shims::foreign_items::EmulateByNameResult; use shims::windows::sync::EvalContextExt as _; @@ -27,7 +26,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // DWORD = ULONG = u32 // BOOL = i32 // BOOLEAN = u8 - match strip_linker_suffix(&link_name.as_str()) { + match &*link_name.as_str() { // Environment related shims "GetEnvironmentVariableW" => { let &[ref name, ref buf, ref size] = From aaaa142dc18ecae15bb357584b1de35395e3bdb8 Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Tue, 15 Jun 2021 01:24:09 +0800 Subject: [PATCH 2734/3747] Rename all `link_name_sym` to `link_name` and remove the only remaining `let link_name = link_name_sym.as_str()` --- src/shims/foreign_items.rs | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 3745b8cf2fa1d..596f6c33d6474 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -209,20 +209,19 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, Option<&'mir mir::Body<'tcx>>> { let this = self.eval_context_mut(); let attrs = this.tcx.get_attrs(def_id); - let link_name_sym = this + let link_name = this .tcx .sess .first_attr_value_str_by_name(&attrs, sym::link_name) .unwrap_or_else(|| this.tcx.item_name(def_id)); - let link_name = link_name_sym.as_str(); let tcx = this.tcx.tcx; // First: functions that diverge. let (dest, ret) = match ret { - None => match &*link_name { + None => match &*link_name.as_str() { "miri_start_panic" => { // `check_shim` happens inside `handle_miri_start_panic`. - this.handle_miri_start_panic(abi, link_name_sym, args, unwind)?; + this.handle_miri_start_panic(abi, link_name, args, unwind)?; return Ok(None); } // This matches calls to the foreign item `panic_impl`. @@ -231,7 +230,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // We don't use `check_shim` here because we are just forwarding to the lang // item. Argument count checking will be performed when the returned `Body` is // called. - this.check_abi_and_shim_symbol_clash(abi, Abi::Rust, link_name_sym)?; + this.check_abi_and_shim_symbol_clash(abi, Abi::Rust, link_name)?; let panic_impl_id = tcx.lang_items().panic_impl().unwrap(); let panic_impl_instance = ty::Instance::mono(tcx, panic_impl_id); return Ok(Some(&*this.load_mir(panic_impl_instance.def, None)?)); @@ -240,25 +239,24 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "exit" | "ExitProcess" => { - let exp_abi = if link_name == "exit" { + let exp_abi = if link_name.as_str() == "exit" { Abi::C { unwind: false } } else { Abi::System { unwind: false } }; - let &[ref code] = this.check_shim(abi, exp_abi, link_name_sym, args)?; + let &[ref code] = this.check_shim(abi, exp_abi, link_name, args)?; // it's really u32 for ExitProcess, but we have to put it into the `Exit` variant anyway let code = this.read_scalar(code)?.to_i32()?; throw_machine_stop!(TerminationInfo::Exit(code.into())); } "abort" => { - let &[] = - this.check_shim(abi, Abi::C { unwind: false }, link_name_sym, args)?; + let &[] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; throw_machine_stop!(TerminationInfo::Abort( "the program aborted execution".to_owned() )) } _ => { - if let Some(body) = this.lookup_exported_symbol(link_name_sym)? { + if let Some(body) = this.lookup_exported_symbol(link_name)? { return Ok(Some(body)); } this.handle_unsupported(format!( @@ -272,14 +270,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx }; // Second: functions that return. - match this.emulate_foreign_item_by_name(link_name_sym, abi, args, dest, ret)? { + match this.emulate_foreign_item_by_name(link_name, abi, args, dest, ret)? { EmulateByNameResult::NeedsJumping => { trace!("{:?}", this.dump_place(**dest)); this.go_to_block(ret); } EmulateByNameResult::AlreadyJumped => (), EmulateByNameResult::NotSupported => { - if let Some(body) = this.lookup_exported_symbol(link_name_sym)? { + if let Some(body) = this.lookup_exported_symbol(link_name)? { return Ok(Some(body)); } From dfd7a6d5aae8e03a0149eb5134f4b5dd763036d5 Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Tue, 15 Jun 2021 16:11:49 +0800 Subject: [PATCH 2735/3747] Rustup --- rust-version | 2 +- tests/compile-fail/validity/invalid_enum_tag.rs | 2 +- .../validity/invalid_enum_tag_256variants_uninit.rs | 2 +- tests/compile-fail/validity/transmute_through_ptr.rs | 2 +- tests/run-pass/stacked-borrows/interior_mutability.rs | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/rust-version b/rust-version index 7d2e8afafacb7..18cfda63a53ee 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -a50d72158e08e02cfc051b863017bdbd2c45b637 +d74b36ea2f814b720c39d7b60aecaefe512a056b diff --git a/tests/compile-fail/validity/invalid_enum_tag.rs b/tests/compile-fail/validity/invalid_enum_tag.rs index 39e8eed683a3b..d4ee3cc8a34a8 100644 --- a/tests/compile-fail/validity/invalid_enum_tag.rs +++ b/tests/compile-fail/validity/invalid_enum_tag.rs @@ -4,5 +4,5 @@ pub enum Foo { } fn main() { - let _f = unsafe { std::mem::transmute::(42) }; //~ ERROR encountered 0x0000002a at ., but expected a valid enum tag + let _f = unsafe { std::mem::transmute::(42) }; //~ ERROR type validation failed at .: encountered 0x0000002a, but expected a valid enum tag } diff --git a/tests/compile-fail/validity/invalid_enum_tag_256variants_uninit.rs b/tests/compile-fail/validity/invalid_enum_tag_256variants_uninit.rs index 74e24491e6108..ccf97b416c691 100644 --- a/tests/compile-fail/validity/invalid_enum_tag_256variants_uninit.rs +++ b/tests/compile-fail/validity/invalid_enum_tag_256variants_uninit.rs @@ -266,5 +266,5 @@ union MyUninit { } fn main() { - let _a = unsafe { MyUninit { init: () }.uninit }; //~ ERROR encountered uninitialized bytes at ., but expected a valid enum tag + let _a = unsafe { MyUninit { init: () }.uninit }; //~ ERROR type validation failed at .: encountered uninitialized bytes, but expected a valid enum tag } diff --git a/tests/compile-fail/validity/transmute_through_ptr.rs b/tests/compile-fail/validity/transmute_through_ptr.rs index 0ef69efb86e61..cd354eac4aef9 100644 --- a/tests/compile-fail/validity/transmute_through_ptr.rs +++ b/tests/compile-fail/validity/transmute_through_ptr.rs @@ -11,6 +11,6 @@ fn main() { let mut x = Bool::True; evil(&mut x); let y = x; // reading this ought to be enough to trigger validation - //~^ ERROR encountered 0x0000002c at ., but expected a valid enum tag + //~^ ERROR type validation failed at .: encountered 0x0000002c, but expected a valid enum tag println!("{:?}", y); // make sure it is used (and not optimized away) } diff --git a/tests/run-pass/stacked-borrows/interior_mutability.rs b/tests/run-pass/stacked-borrows/interior_mutability.rs index 17e628a09f23e..87624e520db10 100644 --- a/tests/run-pass/stacked-borrows/interior_mutability.rs +++ b/tests/run-pass/stacked-borrows/interior_mutability.rs @@ -1,4 +1,4 @@ -#![feature(maybe_uninit_extra, maybe_uninit_ref)] +#![feature(maybe_uninit_extra)] use std::mem::MaybeUninit; use std::cell::{Cell, RefCell, UnsafeCell}; From 7f3dd37f1e43e66162162bc6e2b51c9faa0daeae Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 17 Jun 2021 20:52:35 +0200 Subject: [PATCH 2736/3747] rustup --- rust-version | 2 +- tests/compile-fail/erroneous_const.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/rust-version b/rust-version index 18cfda63a53ee..33ad4403bb68c 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -d74b36ea2f814b720c39d7b60aecaefe512a056b +4d3ce2e7dac840d6ac7d658a5506eb31492fb3ef diff --git a/tests/compile-fail/erroneous_const.rs b/tests/compile-fail/erroneous_const.rs index f193dee94ebc1..199439ccbd2e7 100644 --- a/tests/compile-fail/erroneous_const.rs +++ b/tests/compile-fail/erroneous_const.rs @@ -8,7 +8,7 @@ struct PrintName(T); impl PrintName { - const VOID: ! = panic!(); //~ERROR any use of this value will cause an error + const VOID: ! = panic!(); //~ERROR evaluation of `PrintName::::VOID` failed } fn no_codegen() { From 26446470533320204e7b7eb0c1b12598fbe1d59f Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Sun, 20 Jun 2021 15:12:11 +0800 Subject: [PATCH 2737/3747] Update backtraces --- rust-version | 2 +- tests/run-pass/backtrace-api.stderr | 4 ++++ tests/run-pass/backtrace-std.stderr | 12 ++++++++++-- tests/run-pass/panic/panic1.stderr | 12 ++++++++++-- 4 files changed, 25 insertions(+), 5 deletions(-) diff --git a/rust-version b/rust-version index 33ad4403bb68c..128548fd922ba 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -4d3ce2e7dac840d6ac7d658a5506eb31492fb3ef +192920c22bc8433ab14706ee0829e707d119b74f diff --git a/tests/run-pass/backtrace-api.stderr b/tests/run-pass/backtrace-api.stderr index a5208221da405..bd5908ba29794 100644 --- a/tests/run-pass/backtrace-api.stderr +++ b/tests/run-pass/backtrace-api.stderr @@ -10,5 +10,9 @@ RUSTLIB/core/src/ops/function.rs:LL:COL (std::ops::function::impls::call_once) RUSTLIB/std/src/panicking.rs:LL:COL (std::panicking::r#try::do_call) RUSTLIB/std/src/panicking.rs:LL:COL (std::panicking::r#try) RUSTLIB/std/src/panic.rs:LL:COL (std::panic::catch_unwind) +RUSTLIB/std/src/rt.rs:LL:COL (std::rt::lang_start_internal::{closure#2}) +RUSTLIB/std/src/panicking.rs:LL:COL (std::panicking::r#try::do_call) +RUSTLIB/std/src/panicking.rs:LL:COL (std::panicking::r#try) +RUSTLIB/std/src/panic.rs:LL:COL (std::panic::catch_unwind) RUSTLIB/std/src/rt.rs:LL:COL (std::rt::lang_start_internal) RUSTLIB/std/src/rt.rs:LL:COL (std::rt::lang_start) diff --git a/tests/run-pass/backtrace-std.stderr b/tests/run-pass/backtrace-std.stderr index 09f035b9724ee..64386085c7756 100644 --- a/tests/run-pass/backtrace-std.stderr +++ b/tests/run-pass/backtrace-std.stderr @@ -22,7 +22,15 @@ at RUSTLIB/std/src/panicking.rs:LL:CC 11: std::panic::catch_unwind at RUSTLIB/std/src/panic.rs:LL:CC - 12: std::rt::lang_start_internal + 12: std::rt::lang_start_internal::{closure#2} at RUSTLIB/std/src/rt.rs:LL:CC - 13: std::rt::lang_start + 13: std::panicking::r#try::do_call + at RUSTLIB/std/src/panicking.rs:LL:CC + 14: std::panicking::r#try + at RUSTLIB/std/src/panicking.rs:LL:CC + 15: std::panic::catch_unwind + at RUSTLIB/std/src/panic.rs:LL:CC + 16: std::rt::lang_start_internal + at RUSTLIB/std/src/rt.rs:LL:CC + 17: std::rt::lang_start at RUSTLIB/std/src/rt.rs:LL:CC diff --git a/tests/run-pass/panic/panic1.stderr b/tests/run-pass/panic/panic1.stderr index e0f1aa5dad70b..0b59b2a523b34 100644 --- a/tests/run-pass/panic/panic1.stderr +++ b/tests/run-pass/panic/panic1.stderr @@ -16,8 +16,16 @@ stack backtrace: at RUSTLIB/$FILE:LL:COL 7: std::panic::catch_unwind at RUSTLIB/$FILE:LL:COL - 8: std::rt::lang_start_internal + 8: std::rt::lang_start_internal::{closure#2} at RUSTLIB/$FILE:LL:COL - 9: std::rt::lang_start + 9: std::panicking::r#try::do_call + at RUSTLIB/$FILE:LL:COL + 10: std::panicking::r#try + at RUSTLIB/$FILE:LL:COL + 11: std::panic::catch_unwind + at RUSTLIB/$FILE:LL:COL + 12: std::rt::lang_start_internal + at RUSTLIB/$FILE:LL:COL + 13: std::rt::lang_start at RUSTLIB/$FILE:LL:COL note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace. From 7b2d2cfa462fac0824faf9060848d4b423f70b19 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 20 Jun 2021 19:33:05 +0200 Subject: [PATCH 2738/3747] use exhaustive struct match for manual Debug impl --- src/machine.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/machine.rs b/src/machine.rs index 91a83a8acf403..7ec510d0506f2 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -52,9 +52,10 @@ pub struct FrameData<'tcx> { impl<'tcx> std::fmt::Debug for FrameData<'tcx> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { // Omitting `timing`, it does not support `Debug`. + let FrameData { call_id, catch_unwind, timing: _ } = self; f.debug_struct("FrameData") - .field("call_id", &self.call_id) - .field("catch_unwind", &self.catch_unwind) + .field("call_id", call_id) + .field("catch_unwind", catch_unwind) .finish() } } From 2d17b5a550fd204892ed3e757b044d5cbcb595dd Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Thu, 24 Jun 2021 02:35:08 +0800 Subject: [PATCH 2739/3747] Use `miri` inside the target directory used by rustc as Miri's target directory --- .github/workflows/ci.yml | 6 + cargo-miri/bin.rs | 107 +++++++++++++++--- test-cargo-miri/.gitignore | 3 + test-cargo-miri/run-test.py | 19 ++++ .../run.custom-target-dir.stderr.ref | 2 + 5 files changed, 119 insertions(+), 18 deletions(-) create mode 100644 test-cargo-miri/run.custom-target-dir.stderr.ref diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 889c584ba7c1f..28cab45be4057 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -83,6 +83,12 @@ jobs: --host ${{ matrix.host_target }} rustup default master + # We need a nightly Cargo to run tests that depend on unstable Cargo features. + - name: Install latest nightly + uses: actions-rs/toolchain@v1 + with: + toolchain: nightly + - name: Show Rust version run: | rustup show diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index 7836b26ea5f91..6195a917cb8db 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -6,7 +6,7 @@ use std::io::{self, BufRead, BufReader, BufWriter, Read, Write}; use std::iter::TakeWhile; use std::ops::Not; use std::path::{Path, PathBuf}; -use std::process::Command; +use std::process::{Command, Stdio}; use serde::{Deserialize, Serialize}; @@ -112,40 +112,60 @@ fn has_arg_flag(name: &str) -> bool { args.any(|val| val == name) } -/// Yields all values of command line flag `name`. -struct ArgFlagValueIter<'a> { - args: TakeWhile bool>, +/// Yields all values of command line flag `name` as `Ok(arg)`, and all other arguments except +/// the flag as `Err(arg)`. +struct ArgFlagValueWithOtherArgsIter<'a, I> { + args: TakeWhile bool>, name: &'a str, } -impl<'a> ArgFlagValueIter<'a> { - fn new(name: &'a str) -> Self { +impl<'a, I: Iterator> ArgFlagValueWithOtherArgsIter<'a, I> { + fn new(args: I, name: &'a str) -> Self { Self { // Stop searching at `--`. - args: env::args().take_while(|val| val != "--"), + args: args.take_while(|val| val != "--"), name, } } } -impl Iterator for ArgFlagValueIter<'_> { - type Item = String; +impl> Iterator for ArgFlagValueWithOtherArgsIter<'_, I> { + type Item = Result; fn next(&mut self) -> Option { - loop { - let arg = self.args.next()?; - if !arg.starts_with(self.name) { - continue; - } + let arg = self.args.next()?; + if arg.starts_with(self.name) { // Strip leading `name`. let suffix = &arg[self.name.len()..]; if suffix.is_empty() { // This argument is exactly `name`; the next one is the value. - return self.args.next(); + return self.args.next().map(Ok); } else if suffix.starts_with('=') { // This argument is `name=value`; get the value. // Strip leading `=`. - return Some(suffix[1..].to_owned()); + return Some(Ok(suffix[1..].to_owned())); + } + } + Some(Err(arg)) + } +} + +/// Yields all values of command line flag `name`. +struct ArgFlagValueIter<'a>(ArgFlagValueWithOtherArgsIter<'a, env::Args>); + +impl<'a> ArgFlagValueIter<'a> { + fn new(name: &'a str) -> Self { + Self(ArgFlagValueWithOtherArgsIter::new(env::args(), name)) + } +} + +impl Iterator for ArgFlagValueIter<'_> { + type Item = String; + + fn next(&mut self) -> Option { + loop { + if let Ok(value) = self.0.next()? { + return Some(value); } } } @@ -510,8 +530,59 @@ fn phase_cargo_miri(mut args: env::Args) { &host }; - // Forward all further arguments to cargo. - cmd.args(args); + let mut target_dir = None; + + // Forward all arguments before `--` other than `--target-dir` and its value to Cargo. + for arg in ArgFlagValueWithOtherArgsIter::new(&mut args, "--target-dir") { + match arg { + Ok(value) => target_dir = Some(value.into()), + Err(arg) => drop(cmd.arg(arg)), + } + } + + // Detect the target directory if it's not specified via `--target-dir`. + let target_dir = target_dir.get_or_insert_with(|| { + #[derive(Deserialize)] + struct Metadata { + target_directory: PathBuf, + } + let mut cmd = cargo(); + // `-Zunstable-options` is required by `--config`. + cmd.args(["metadata", "--no-deps", "--format-version=1", "-Zunstable-options"]); + // The `build.target-dir` config can by passed by `--config` flags, so forward them to + // `cargo metadata`. + let config_flag = "--config"; + for arg in ArgFlagValueWithOtherArgsIter::new( + env::args().skip(3), // skip the program name, "miri" and "run" / "test" + config_flag, + ) { + if let Ok(config) = arg { + cmd.arg(config_flag).arg(config); + } + } + let mut child = cmd + .stdin(Stdio::null()) + .stdout(Stdio::piped()) + .spawn() + .expect("failed ro run `cargo metadata`"); + // Check this `Result` after `status.success()` is checked, so we don't print the error + // to stderr if `cargo metadata` is also printing to stderr. + let metadata: Result = serde_json::from_reader(child.stdout.take().unwrap()); + let status = child.wait().expect("failed to wait `cargo metadata` to exit"); + if !status.success() { + std::process::exit(status.code().unwrap_or(-1)); + } + metadata + .unwrap_or_else(|e| show_error(format!("invalid `cargo metadata` output: {}", e))) + .target_directory + }); + + // Set `--target-dir` to `miri` inside the original target directory. + target_dir.push("miri"); + cmd.arg("--target-dir").arg(target_dir); + + // Forward all further arguments after `--` to cargo. + cmd.arg("--").args(args); // Set `RUSTC_WRAPPER` to ourselves. Cargo will prepend that binary to its usual invocation, // i.e., the first argument is `rustc` -- which is what we use in `main` to distinguish diff --git a/test-cargo-miri/.gitignore b/test-cargo-miri/.gitignore index 56f307a7fb133..af5854e0c3fd9 100644 --- a/test-cargo-miri/.gitignore +++ b/test-cargo-miri/.gitignore @@ -1 +1,4 @@ *.real +custom-run +custom-test +config-cli diff --git a/test-cargo-miri/run-test.py b/test-cargo-miri/run-test.py index c850e7d145919..369941787a14f 100755 --- a/test-cargo-miri/run-test.py +++ b/test-cargo-miri/run-test.py @@ -101,6 +101,11 @@ def test_cargo_miri_run(): "run.subcrate.stdout.ref", "run.subcrate.stderr.ref", env={'MIRIFLAGS': "-Zmiri-disable-isolation"}, ) + test("`cargo miri run` (custom target dir)", + # Attempt to confuse the argument parser. + cargo_miri("run") + ["--target-dir=custom-run", "--", "--target-dir=target/custom-run"], + "run.args.stdout.ref", "run.custom-target-dir.stderr.ref", + ) def test_cargo_miri_test(): # rustdoc is not run on foreign targets @@ -144,8 +149,18 @@ def test_cargo_miri_test(): cargo_miri("test") + ["-p", "subcrate", "--doc"], "test.stdout-empty.ref", "test.stderr-proc-macro-doctest.ref", ) + test("`cargo miri test` (custom target dir)", + cargo_miri("test") + ["--target-dir=custom-test"], + default_ref, "test.stderr-empty.ref", + ) + del os.environ["CARGO_TARGET_DIR"] # this overrides `build.target-dir` passed by `--config`, so unset it + test("`cargo miri test` (config-cli)", + cargo_miri("test") + ["--config=build.target-dir=\"config-cli\"", "-Zunstable-options"], + default_ref, "test.stderr-empty.ref", + ) os.chdir(os.path.dirname(os.path.realpath(__file__))) +os.environ["CARGO_TARGET_DIR"] = "target" # this affects the location of the target directory that we need to check os.environ["RUST_TEST_NOCAPTURE"] = "0" # this affects test output, so make sure it is not set os.environ["RUST_TEST_THREADS"] = "1" # avoid non-deterministic output due to concurrent test runs @@ -158,6 +173,10 @@ def test_cargo_miri_test(): subprocess.run(cargo_miri("setup"), check=True) test_cargo_miri_run() test_cargo_miri_test() +for target_dir in ["target", "custom-run", "custom-test", "config-cli"]: + if os.listdir(target_dir) != ["miri"]: + fail(f"`{target_dir}` contains unexpected files") + os.access(os.path.join(target_dir, "miri", "debug", "deps"), os.F_OK) print("\nTEST SUCCESSFUL!") sys.exit(0) diff --git a/test-cargo-miri/run.custom-target-dir.stderr.ref b/test-cargo-miri/run.custom-target-dir.stderr.ref new file mode 100644 index 0000000000000..4395ff8879b96 --- /dev/null +++ b/test-cargo-miri/run.custom-target-dir.stderr.ref @@ -0,0 +1,2 @@ +main +--target-dir=target/custom-run From c3ad18256dab981000bcade9ad21420c63d044f9 Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Sat, 26 Jun 2021 21:24:01 +0800 Subject: [PATCH 2740/3747] long closure -> function --- cargo-miri/bin.rs | 73 ++++++++++++++++++++++++----------------------- 1 file changed, 38 insertions(+), 35 deletions(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index 6195a917cb8db..c87325614bbef 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -472,6 +472,43 @@ path = "lib.rs" } } +/// Detect the target directory by calling `cargo metadata`. +fn detect_target_dir() -> PathBuf { + #[derive(Deserialize)] + struct Metadata { + target_directory: PathBuf, + } + let mut cmd = cargo(); + // `-Zunstable-options` is required by `--config`. + cmd.args(["metadata", "--no-deps", "--format-version=1", "-Zunstable-options"]); + // The `build.target-dir` config can by passed by `--config` flags, so forward them to + // `cargo metadata`. + let config_flag = "--config"; + for arg in ArgFlagValueWithOtherArgsIter::new( + env::args().skip(3), // skip the program name, "miri" and "run" / "test" + config_flag, + ) { + if let Ok(config) = arg { + cmd.arg(config_flag).arg(config); + } + } + let mut child = cmd + .stdin(Stdio::null()) + .stdout(Stdio::piped()) + .spawn() + .expect("failed ro run `cargo metadata`"); + // Check this `Result` after `status.success()` is checked, so we don't print the error + // to stderr if `cargo metadata` is also printing to stderr. + let metadata: Result = serde_json::from_reader(child.stdout.take().unwrap()); + let status = child.wait().expect("failed to wait `cargo metadata` to exit"); + if !status.success() { + std::process::exit(status.code().unwrap_or(-1)); + } + metadata + .unwrap_or_else(|e| show_error(format!("invalid `cargo metadata` output: {}", e))) + .target_directory +} + fn phase_cargo_miri(mut args: env::Args) { // Check for version and help flags even when invoked as `cargo-miri`. if has_arg_flag("--help") || has_arg_flag("-h") { @@ -541,41 +578,7 @@ fn phase_cargo_miri(mut args: env::Args) { } // Detect the target directory if it's not specified via `--target-dir`. - let target_dir = target_dir.get_or_insert_with(|| { - #[derive(Deserialize)] - struct Metadata { - target_directory: PathBuf, - } - let mut cmd = cargo(); - // `-Zunstable-options` is required by `--config`. - cmd.args(["metadata", "--no-deps", "--format-version=1", "-Zunstable-options"]); - // The `build.target-dir` config can by passed by `--config` flags, so forward them to - // `cargo metadata`. - let config_flag = "--config"; - for arg in ArgFlagValueWithOtherArgsIter::new( - env::args().skip(3), // skip the program name, "miri" and "run" / "test" - config_flag, - ) { - if let Ok(config) = arg { - cmd.arg(config_flag).arg(config); - } - } - let mut child = cmd - .stdin(Stdio::null()) - .stdout(Stdio::piped()) - .spawn() - .expect("failed ro run `cargo metadata`"); - // Check this `Result` after `status.success()` is checked, so we don't print the error - // to stderr if `cargo metadata` is also printing to stderr. - let metadata: Result = serde_json::from_reader(child.stdout.take().unwrap()); - let status = child.wait().expect("failed to wait `cargo metadata` to exit"); - if !status.success() { - std::process::exit(status.code().unwrap_or(-1)); - } - metadata - .unwrap_or_else(|e| show_error(format!("invalid `cargo metadata` output: {}", e))) - .target_directory - }); + let target_dir = target_dir.get_or_insert_with(detect_target_dir); // Set `--target-dir` to `miri` inside the original target directory. target_dir.push("miri"); From 59408b68dd79b54cda6b1d31dc6ef0b6048a6555 Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Sat, 26 Jun 2021 21:45:38 +0800 Subject: [PATCH 2741/3747] Add some comments in `test-cargo-miri/run-tests.py` --- test-cargo-miri/run-test.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test-cargo-miri/run-test.py b/test-cargo-miri/run-test.py index 369941787a14f..51433d98a2ed2 100755 --- a/test-cargo-miri/run-test.py +++ b/test-cargo-miri/run-test.py @@ -173,9 +173,11 @@ def test_cargo_miri_test(): subprocess.run(cargo_miri("setup"), check=True) test_cargo_miri_run() test_cargo_miri_test() +# Ensure we did not create anything outside the expected target dir. for target_dir in ["target", "custom-run", "custom-test", "config-cli"]: if os.listdir(target_dir) != ["miri"]: fail(f"`{target_dir}` contains unexpected files") + # Ensure something exists inside that target dir. os.access(os.path.join(target_dir, "miri", "debug", "deps"), os.F_OK) print("\nTEST SUCCESSFUL!") From 2ced7ecb9f54e2798989ff5e5946c73f4b740afe Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Sat, 26 Jun 2021 21:49:56 +0800 Subject: [PATCH 2742/3747] `ArgFlagValueWithOtherArgsIter` -> `ArgSplitFlagValue` --- cargo-miri/bin.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index c87325614bbef..939ea5ac507fc 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -114,12 +114,12 @@ fn has_arg_flag(name: &str) -> bool { /// Yields all values of command line flag `name` as `Ok(arg)`, and all other arguments except /// the flag as `Err(arg)`. -struct ArgFlagValueWithOtherArgsIter<'a, I> { +struct ArgSplitFlagValue<'a, I> { args: TakeWhile bool>, name: &'a str, } -impl<'a, I: Iterator> ArgFlagValueWithOtherArgsIter<'a, I> { +impl<'a, I: Iterator> ArgSplitFlagValue<'a, I> { fn new(args: I, name: &'a str) -> Self { Self { // Stop searching at `--`. @@ -129,7 +129,7 @@ impl<'a, I: Iterator> ArgFlagValueWithOtherArgsIter<'a, I> { } } -impl> Iterator for ArgFlagValueWithOtherArgsIter<'_, I> { +impl> Iterator for ArgSplitFlagValue<'_, I> { type Item = Result; fn next(&mut self) -> Option { @@ -151,11 +151,11 @@ impl> Iterator for ArgFlagValueWithOtherArgsIter<'_, } /// Yields all values of command line flag `name`. -struct ArgFlagValueIter<'a>(ArgFlagValueWithOtherArgsIter<'a, env::Args>); +struct ArgFlagValueIter<'a>(ArgSplitFlagValue<'a, env::Args>); impl<'a> ArgFlagValueIter<'a> { fn new(name: &'a str) -> Self { - Self(ArgFlagValueWithOtherArgsIter::new(env::args(), name)) + Self(ArgSplitFlagValue::new(env::args(), name)) } } @@ -484,7 +484,7 @@ fn detect_target_dir() -> PathBuf { // The `build.target-dir` config can by passed by `--config` flags, so forward them to // `cargo metadata`. let config_flag = "--config"; - for arg in ArgFlagValueWithOtherArgsIter::new( + for arg in ArgSplitFlagValue::new( env::args().skip(3), // skip the program name, "miri" and "run" / "test" config_flag, ) { @@ -570,7 +570,7 @@ fn phase_cargo_miri(mut args: env::Args) { let mut target_dir = None; // Forward all arguments before `--` other than `--target-dir` and its value to Cargo. - for arg in ArgFlagValueWithOtherArgsIter::new(&mut args, "--target-dir") { + for arg in ArgSplitFlagValue::new(&mut args, "--target-dir") { match arg { Ok(value) => target_dir = Some(value.into()), Err(arg) => drop(cmd.arg(arg)), From 8f87903ec91499f8e3f68ed3386b70c5d069cf8d Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Sat, 26 Jun 2021 22:22:40 +0800 Subject: [PATCH 2743/3747] Fix typo --- cargo-miri/bin.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index 939ea5ac507fc..e9596e56f7424 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -481,7 +481,7 @@ fn detect_target_dir() -> PathBuf { let mut cmd = cargo(); // `-Zunstable-options` is required by `--config`. cmd.args(["metadata", "--no-deps", "--format-version=1", "-Zunstable-options"]); - // The `build.target-dir` config can by passed by `--config` flags, so forward them to + // The `build.target-dir` config can be passed by `--config` flags, so forward them to // `cargo metadata`. let config_flag = "--config"; for arg in ArgSplitFlagValue::new( From 16929329667c5ada59e98543f55e188b611413d5 Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Sat, 26 Jun 2021 22:36:05 +0800 Subject: [PATCH 2744/3747] Show error if `--target-dir` is provided more than once --- cargo-miri/bin.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index e9596e56f7424..aac945d2d780a 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -572,7 +572,12 @@ fn phase_cargo_miri(mut args: env::Args) { // Forward all arguments before `--` other than `--target-dir` and its value to Cargo. for arg in ArgSplitFlagValue::new(&mut args, "--target-dir") { match arg { - Ok(value) => target_dir = Some(value.into()), + Ok(value) => { + if target_dir.is_some() { + show_error(format!("`--target-dir` is provided more than once")); + } + target_dir = Some(value.into()); + } Err(arg) => drop(cmd.arg(arg)), } } From 34217bdc8e088051e831de7baa33c377724af3e0 Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Sat, 26 Jun 2021 20:43:31 +0800 Subject: [PATCH 2745/3747] Use `rustup-toolchain-install-master` to install Cargo --- .github/workflows/ci.yml | 7 +------ rustup-toolchain | 2 +- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 28cab45be4057..487632136905d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -77,18 +77,13 @@ jobs: rustup-toolchain-install-master \ -f \ -n master "$RUSTC_HASH" \ + -c cargo \ -c rust-src \ -c rustc-dev \ -c llvm-tools \ --host ${{ matrix.host_target }} rustup default master - # We need a nightly Cargo to run tests that depend on unstable Cargo features. - - name: Install latest nightly - uses: actions-rs/toolchain@v1 - with: - toolchain: nightly - - name: Show Rust version run: | rustup show diff --git a/rustup-toolchain b/rustup-toolchain index 3fbebe1565f7e..5b7e8f7fcd636 100755 --- a/rustup-toolchain +++ b/rustup-toolchain @@ -39,7 +39,7 @@ fi # Install and setup new toolchain. rustup toolchain uninstall miri -rustup-toolchain-install-master -n miri -c rust-src -c rustc-dev -c llvm-tools -- "$NEW_COMMIT" +rustup-toolchain-install-master -n miri -c cargo -c rust-src -c rustc-dev -c llvm-tools -- "$NEW_COMMIT" rustup override set miri # Cleanup. From e751eeb1973424d831cbee2cad3f8f3258cedbb4 Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Sun, 27 Jun 2021 23:07:15 +0800 Subject: [PATCH 2746/3747] `drop(cmd.arg(arg))` -> `cmd.arg(arg);` --- cargo-miri/bin.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index aac945d2d780a..4f0ffacf96a3c 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -578,7 +578,9 @@ fn phase_cargo_miri(mut args: env::Args) { } target_dir = Some(value.into()); } - Err(arg) => drop(cmd.arg(arg)), + Err(arg) => { + cmd.arg(arg); + } } } From 7d310aa8365d27526182424ce23a6d3ee5f0b813 Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Sun, 27 Jun 2021 23:08:38 +0800 Subject: [PATCH 2747/3747] Fix `.expect()` message --- cargo-miri/bin.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index 4f0ffacf96a3c..d0ab82732427c 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -500,7 +500,7 @@ fn detect_target_dir() -> PathBuf { // Check this `Result` after `status.success()` is checked, so we don't print the error // to stderr if `cargo metadata` is also printing to stderr. let metadata: Result = serde_json::from_reader(child.stdout.take().unwrap()); - let status = child.wait().expect("failed to wait `cargo metadata` to exit"); + let status = child.wait().expect("failed to wait for `cargo metadata` to exit"); if !status.success() { std::process::exit(status.code().unwrap_or(-1)); } From 08236912a70c24dcf11d157fbe4dbc1e1ae00366 Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Sun, 27 Jun 2021 23:09:10 +0800 Subject: [PATCH 2748/3747] Improve doc comment --- cargo-miri/bin.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index d0ab82732427c..8d2065c8eeb4f 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -113,7 +113,7 @@ fn has_arg_flag(name: &str) -> bool { } /// Yields all values of command line flag `name` as `Ok(arg)`, and all other arguments except -/// the flag as `Err(arg)`. +/// the flag as `Err(arg)`. (The flag `name` itself is not yielded at all, only its values are.) struct ArgSplitFlagValue<'a, I> { args: TakeWhile bool>, name: &'a str, From e33bf695db921a08e89bf8efb7572a51a0c86917 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 29 Jun 2021 20:47:28 +0200 Subject: [PATCH 2749/3747] rustup --- rust-version | 2 +- src/data_race.rs | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/rust-version b/rust-version index 128548fd922ba..a8a75e9f046c4 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -192920c22bc8433ab14706ee0829e707d119b74f +e98897e5dc9898707bf4331c43b2e76ab7e282fe diff --git a/src/data_race.rs b/src/data_race.rs index 45159ef4c07c3..cb7b1fc6dbe0c 100644 --- a/src/data_race.rs +++ b/src/data_race.rs @@ -759,8 +759,7 @@ impl VClockAlloc { | MiriMemoryKind::ExternStatic | MiriMemoryKind::Tls, ) - | MemoryKind::CallerLocation - | MemoryKind::Vtable => (0, VectorIdx::MAX_INDEX), + | MemoryKind::CallerLocation => (0, VectorIdx::MAX_INDEX), }; VClockAlloc { alloc_ranges: RefCell::new(RangeMap::new( From 76fe48543cfbbed38567135093159f17b442dc0c Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Fri, 2 Jul 2021 16:08:27 +0800 Subject: [PATCH 2750/3747] Update for `TyCtxt::crates()` change --- rust-version | 2 +- src/helpers.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/rust-version b/rust-version index a8a75e9f046c4..9890818ee952b 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -e98897e5dc9898707bf4331c43b2e76ab7e282fe +46ae6ee65df19c6a3fb683499c1203e749975e60 diff --git a/src/helpers.rs b/src/helpers.rs index b99a446577ac4..d53b2969fb55e 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -20,7 +20,7 @@ impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mi /// Gets an instance for a path. fn try_resolve_did<'mir, 'tcx>(tcx: TyCtxt<'tcx>, path: &[&str]) -> Option { - tcx.crates().iter().find(|&&krate| tcx.crate_name(krate).as_str() == path[0]).and_then( + tcx.crates(()).iter().find(|&&krate| tcx.crate_name(krate).as_str() == path[0]).and_then( |krate| { let krate = DefId { krate: *krate, index: CRATE_DEF_INDEX }; let mut items = tcx.item_children(krate); From c504e3dee0f85e344dbe8e4cc268e317ef9ff3a2 Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Fri, 2 Jul 2021 16:20:55 +0800 Subject: [PATCH 2751/3747] Add a comment in `.github/workflows/ci.yml` --- .github/workflows/ci.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 487632136905d..ce13647fa586a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -74,6 +74,7 @@ jobs: else RUSTC_HASH=$(< rust-version) fi + # We need a nightly cargo for parts of the cargo miri test suite. rustup-toolchain-install-master \ -f \ -n master "$RUSTC_HASH" \ From e3fca9b3f13e14aa25634d7ffb818818e5720401 Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Fri, 2 Jul 2021 16:22:59 +0800 Subject: [PATCH 2752/3747] Import `std::process::self` --- cargo-miri/bin.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index 8d2065c8eeb4f..1a7552c5d9e05 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -6,7 +6,7 @@ use std::io::{self, BufRead, BufReader, BufWriter, Read, Write}; use std::iter::TakeWhile; use std::ops::Not; use std::path::{Path, PathBuf}; -use std::process::{Command, Stdio}; +use std::process::{self, Command}; use serde::{Deserialize, Serialize}; @@ -233,7 +233,7 @@ fn exec(mut cmd: Command) { /// If it fails, fail this process with the same exit code. /// Otherwise, continue. fn exec_with_pipe(mut cmd: Command, input: &[u8]) { - cmd.stdin(std::process::Stdio::piped()); + cmd.stdin(process::Stdio::piped()); let mut child = cmd.spawn().expect("failed to spawn process"); { let stdin = child.stdin.as_mut().expect("failed to open stdin"); @@ -493,8 +493,8 @@ fn detect_target_dir() -> PathBuf { } } let mut child = cmd - .stdin(Stdio::null()) - .stdout(Stdio::piped()) + .stdin(process::Stdio::null()) + .stdout(process::Stdio::piped()) .spawn() .expect("failed ro run `cargo metadata`"); // Check this `Result` after `status.success()` is checked, so we don't print the error From d19376985d84e54e452c8b26548d0f239dce9cc0 Mon Sep 17 00:00:00 2001 From: Smitty Date: Sun, 4 Jul 2021 09:59:55 -0400 Subject: [PATCH 2753/3747] Make work after mir-alloc-oom --- rust-version | 2 +- src/eval.rs | 14 ++++++++------ src/helpers.rs | 2 +- src/machine.rs | 6 ++++-- src/shims/backtrace.rs | 3 ++- src/shims/env.rs | 10 +++++----- src/shims/foreign_items.rs | 23 ++++++++++++++--------- src/shims/os_str.rs | 12 ++++++------ src/shims/posix/foreign_items.rs | 2 +- src/shims/posix/thread.rs | 2 +- src/shims/windows/foreign_items.rs | 2 +- 11 files changed, 44 insertions(+), 34 deletions(-) diff --git a/rust-version b/rust-version index 9890818ee952b..23819ebc24e42 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -46ae6ee65df19c6a3fb683499c1203e749975e60 +39e20f1ae5f13451eb35247808d6a2527cb7d060 diff --git a/src/eval.rs b/src/eval.rs index 95cdcb1b5a598..f728248c3a723 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -169,7 +169,8 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( // Make space for `0` terminator. let size = u64::try_from(arg.len()).unwrap().checked_add(1).unwrap(); let arg_type = tcx.mk_array(tcx.types.u8, size); - let arg_place = ecx.allocate(ecx.layout_of(arg_type)?, MiriMemoryKind::Machine.into()); + let arg_place = + ecx.allocate(ecx.layout_of(arg_type)?, MiriMemoryKind::Machine.into())?; ecx.write_os_str_to_c_str(OsStr::new(arg), arg_place.ptr, size)?; argvs.push(arg_place.ptr); } @@ -177,7 +178,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( let argvs_layout = ecx.layout_of( tcx.mk_array(tcx.mk_imm_ptr(tcx.types.u8), u64::try_from(argvs.len()).unwrap()), )?; - let argvs_place = ecx.allocate(argvs_layout, MiriMemoryKind::Machine.into()); + let argvs_place = ecx.allocate(argvs_layout, MiriMemoryKind::Machine.into())?; for (idx, arg) in argvs.into_iter().enumerate() { let place = ecx.mplace_field(&argvs_place, idx)?; ecx.write_scalar(arg, &place.into())?; @@ -188,14 +189,14 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( // Store `argc` and `argv` for macOS `_NSGetArg{c,v}`. { let argc_place = - ecx.allocate(ecx.machine.layouts.isize, MiriMemoryKind::Machine.into()); + ecx.allocate(ecx.machine.layouts.isize, MiriMemoryKind::Machine.into())?; ecx.write_scalar(argc, &argc_place.into())?; ecx.machine.argc = Some(argc_place.ptr); let argv_place = ecx.allocate( ecx.layout_of(tcx.mk_imm_ptr(tcx.types.unit))?, MiriMemoryKind::Machine.into(), - ); + )?; ecx.write_scalar(argv, &argv_place.into())?; ecx.machine.argv = Some(argv_place.ptr); } @@ -214,7 +215,8 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( let cmd_utf16: Vec = cmd.encode_utf16().collect(); let cmd_type = tcx.mk_array(tcx.types.u16, u64::try_from(cmd_utf16.len()).unwrap()); - let cmd_place = ecx.allocate(ecx.layout_of(cmd_type)?, MiriMemoryKind::Machine.into()); + let cmd_place = + ecx.allocate(ecx.layout_of(cmd_type)?, MiriMemoryKind::Machine.into())?; ecx.machine.cmd_line = Some(cmd_place.ptr); // Store the UTF-16 string. We just allocated so we know the bounds are fine. for (idx, &c) in cmd_utf16.iter().enumerate() { @@ -226,7 +228,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( }; // Return place (in static memory so that it does not count as leak). - let ret_place = ecx.allocate(ecx.machine.layouts.isize, MiriMemoryKind::Machine.into()); + let ret_place = ecx.allocate(ecx.machine.layouts.isize, MiriMemoryKind::Machine.into())?; // Call start function. ecx.call_function( start_instance, diff --git a/src/helpers.rs b/src/helpers.rs index d53b2969fb55e..a6e66c3dbd38e 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -440,7 +440,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } else { // Allocate new place, set initial value to 0. let errno_layout = this.machine.layouts.u32; - let errno_place = this.allocate(errno_layout, MiriMemoryKind::Machine.into()); + let errno_place = this.allocate(errno_layout, MiriMemoryKind::Machine.into())?; this.write_scalar(Scalar::from_u32(0), &errno_place.into())?; this.active_thread_mut().last_error = Some(errno_place); Ok(errno_place) diff --git a/src/machine.rs b/src/machine.rs index 7ec510d0506f2..999e21796d304 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -199,7 +199,7 @@ impl MemoryExtra { // "__cxa_thread_atexit_impl" // This should be all-zero, pointer-sized. let layout = this.machine.layouts.usize; - let place = this.allocate(layout, MiriMemoryKind::ExternStatic.into()); + let place = this.allocate(layout, MiriMemoryKind::ExternStatic.into())?; this.write_scalar(Scalar::from_machine_usize(0, this), &place.into())?; Self::add_extern_static(this, "__cxa_thread_atexit_impl", place.ptr); // "environ" @@ -213,7 +213,7 @@ impl MemoryExtra { // "_tls_used" // This is some obscure hack that is part of the Windows TLS story. It's a `u8`. let layout = this.machine.layouts.u8; - let place = this.allocate(layout, MiriMemoryKind::ExternStatic.into()); + let place = this.allocate(layout, MiriMemoryKind::ExternStatic.into())?; this.write_scalar(Scalar::from_u8(0), &place.into())?; Self::add_extern_static(this, "_tls_used", place.ptr); } @@ -377,6 +377,8 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { const GLOBAL_KIND: Option = Some(MiriMemoryKind::Global); + const PANIC_ON_ALLOC_FAIL: bool = false; + #[inline(always)] fn enforce_alignment(memory_extra: &MemoryExtra) -> bool { memory_extra.check_alignment != AlignmentCheck::None diff --git a/src/shims/backtrace.rs b/src/shims/backtrace.rs index 4ea374344c0dd..ec29fef6368fb 100644 --- a/src/shims/backtrace.rs +++ b/src/shims/backtrace.rs @@ -57,7 +57,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let array_ty = tcx.mk_array(ptr_ty, ptrs.len().try_into().unwrap()); // Write pointers into array - let alloc = this.allocate(this.layout_of(array_ty).unwrap(), MiriMemoryKind::Rust.into()); + let alloc = + this.allocate(this.layout_of(array_ty).unwrap(), MiriMemoryKind::Rust.into())?; for (i, ptr) in ptrs.into_iter().enumerate() { let place = this.mplace_index(&alloc, i as u64)?; this.write_immediate_to_mplace(ptr.into(), &place)?; diff --git a/src/shims/env.rs b/src/shims/env.rs index 0c42daa2446a0..d99ffb31b5cf5 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -88,7 +88,7 @@ fn alloc_env_var_as_c_str<'mir, 'tcx>( let mut name_osstring = name.to_os_string(); name_osstring.push("="); name_osstring.push(value); - Ok(ecx.alloc_os_str_as_c_str(name_osstring.as_os_str(), MiriMemoryKind::Env.into())) + ecx.alloc_os_str_as_c_str(name_osstring.as_os_str(), MiriMemoryKind::Env.into()) } fn alloc_env_var_as_wide_str<'mir, 'tcx>( @@ -99,7 +99,7 @@ fn alloc_env_var_as_wide_str<'mir, 'tcx>( let mut name_osstring = name.to_os_string(); name_osstring.push("="); name_osstring.push(value); - Ok(ecx.alloc_os_str_as_wide_str(name_osstring.as_os_str(), MiriMemoryKind::Env.into())) + ecx.alloc_os_str_as_wide_str(name_osstring.as_os_str(), MiriMemoryKind::Env.into()) } impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} @@ -179,7 +179,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // Allocate environment block & Store environment variables to environment block. // Final null terminator(block terminator) is added by `alloc_os_str_to_wide_str`. - let envblock_ptr = this.alloc_os_str_as_wide_str(&env_vars, MiriMemoryKind::Env.into()); + let envblock_ptr = this.alloc_os_str_as_wide_str(&env_vars, MiriMemoryKind::Env.into())?; // If the function succeeds, the return value is a pointer to the environment block of the current process. Ok(envblock_ptr.into()) } @@ -442,7 +442,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // No `environ` allocated yet, let's do that. // This is memory backing an extern static, hence `ExternStatic`, not `Env`. let layout = this.machine.layouts.usize; - let place = this.allocate(layout, MiriMemoryKind::ExternStatic.into()); + let place = this.allocate(layout, MiriMemoryKind::ExternStatic.into())?; this.machine.env_vars.environ = Some(place); } @@ -455,7 +455,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let tcx = this.tcx; let vars_layout = this.layout_of(tcx.mk_array(tcx.types.usize, u64::try_from(vars.len()).unwrap()))?; - let vars_place = this.allocate(vars_layout, MiriMemoryKind::Env.into()); + let vars_place = this.allocate(vars_layout, MiriMemoryKind::Env.into())?; for (idx, var) in vars.into_iter().enumerate() { let place = this.mplace_field(&vars_place, idx)?; this.write_scalar(var, &place.into())?; diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 5b241a2fb3c12..5d46f3c05c339 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -67,18 +67,23 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Align::from_bytes(prev_power_of_two(size)).unwrap() } - fn malloc(&mut self, size: u64, zero_init: bool, kind: MiriMemoryKind) -> Scalar { + fn malloc( + &mut self, + size: u64, + zero_init: bool, + kind: MiriMemoryKind, + ) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); if size == 0 { - Scalar::null_ptr(this) + Ok(Scalar::null_ptr(this)) } else { let align = this.min_align(size, kind); - let ptr = this.memory.allocate(Size::from_bytes(size), align, kind.into()); + let ptr = this.memory.allocate(Size::from_bytes(size), align, kind.into())?; if zero_init { // We just allocated this, the access is definitely in-bounds. this.memory.write_bytes(ptr.into(), iter::repeat(0u8).take(size as usize)).unwrap(); } - Scalar::Ptr(ptr) + Ok(Scalar::Ptr(ptr)) } } @@ -104,7 +109,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(Scalar::null_ptr(this)) } else { let new_ptr = - this.memory.allocate(Size::from_bytes(new_size), new_align, kind.into()); + this.memory.allocate(Size::from_bytes(new_size), new_align, kind.into())?; Ok(Scalar::Ptr(new_ptr)) } } else { @@ -331,7 +336,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "malloc" => { let &[ref size] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let size = this.read_scalar(size)?.to_machine_usize(this)?; - let res = this.malloc(size, /*zero_init:*/ false, MiriMemoryKind::C); + let res = this.malloc(size, /*zero_init:*/ false, MiriMemoryKind::C)?; this.write_scalar(res, dest)?; } "calloc" => { @@ -340,7 +345,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let len = this.read_scalar(len)?.to_machine_usize(this)?; let size = items.checked_mul(len).ok_or_else(|| err_ub_format!("overflow during calloc size computation"))?; - let res = this.malloc(size, /*zero_init:*/ true, MiriMemoryKind::C); + let res = this.malloc(size, /*zero_init:*/ true, MiriMemoryKind::C)?; this.write_scalar(res, dest)?; } "free" => { @@ -368,7 +373,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Size::from_bytes(size), Align::from_bytes(align).unwrap(), MiriMemoryKind::Rust.into(), - ); + )?; this.write_scalar(ptr, dest)?; } "__rust_alloc_zeroed" => { @@ -380,7 +385,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Size::from_bytes(size), Align::from_bytes(align).unwrap(), MiriMemoryKind::Rust.into(), - ); + )?; // We just allocated this, the access is definitely in-bounds. this.memory.write_bytes(ptr.into(), iter::repeat(0u8).take(usize::try_from(size).unwrap())).unwrap(); this.write_scalar(ptr, dest)?; diff --git a/src/shims/os_str.rs b/src/shims/os_str.rs index 8a3f5677706ec..ea99921c0b676 100644 --- a/src/shims/os_str.rs +++ b/src/shims/os_str.rs @@ -161,14 +161,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx &mut self, os_str: &OsStr, memkind: MemoryKind, - ) -> Pointer { + ) -> InterpResult<'tcx, Pointer> { let size = u64::try_from(os_str.len()).unwrap().checked_add(1).unwrap(); // Make space for `0` terminator. let this = self.eval_context_mut(); let arg_type = this.tcx.mk_array(this.tcx.types.u8, size); - let arg_place = this.allocate(this.layout_of(arg_type).unwrap(), memkind); + let arg_place = this.allocate(this.layout_of(arg_type).unwrap(), memkind)?; assert!(self.write_os_str_to_c_str(os_str, arg_place.ptr, size).unwrap().0); - arg_place.ptr.assert_ptr() + Ok(arg_place.ptr.assert_ptr()) } /// Allocate enough memory to store the given `OsStr` as a null-terminated sequence of `u16`. @@ -176,14 +176,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx &mut self, os_str: &OsStr, memkind: MemoryKind, - ) -> Pointer { + ) -> InterpResult<'tcx, Pointer> { let size = u64::try_from(os_str.len()).unwrap().checked_add(1).unwrap(); // Make space for `0x0000` terminator. let this = self.eval_context_mut(); let arg_type = this.tcx.mk_array(this.tcx.types.u16, size); - let arg_place = this.allocate(this.layout_of(arg_type).unwrap(), memkind); + let arg_place = this.allocate(this.layout_of(arg_type).unwrap(), memkind)?; assert!(self.write_os_str_to_wide_str(os_str, arg_place.ptr, size).unwrap().0); - arg_place.ptr.assert_ptr() + Ok(arg_place.ptr.assert_ptr()) } /// Read a null-terminated sequence of bytes, and perform path separator conversion if needed. diff --git a/src/shims/posix/foreign_items.rs b/src/shims/posix/foreign_items.rs index 4035deff63ef0..1cfc3f0a4e79f 100644 --- a/src/shims/posix/foreign_items.rs +++ b/src/shims/posix/foreign_items.rs @@ -159,7 +159,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Size::from_bytes(size), Align::from_bytes(align).unwrap(), MiriMemoryKind::C.into(), - ); + )?; this.write_scalar(ptr, &ret.into())?; } this.write_null(dest)?; diff --git a/src/shims/posix/thread.rs b/src/shims/posix/thread.rs index 1e4597848914b..ce1c817cf3ba0 100644 --- a/src/shims/posix/thread.rs +++ b/src/shims/posix/thread.rs @@ -47,7 +47,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // pthread_join below) because the Rust standard library does not use // it. let ret_place = - this.allocate(this.layout_of(this.tcx.types.usize)?, MiriMemoryKind::Machine.into()); + this.allocate(this.layout_of(this.tcx.types.usize)?, MiriMemoryKind::Machine.into())?; this.call_function( instance, diff --git a/src/shims/windows/foreign_items.rs b/src/shims/windows/foreign_items.rs index 1921af3594239..b5324576273c9 100644 --- a/src/shims/windows/foreign_items.rs +++ b/src/shims/windows/foreign_items.rs @@ -115,7 +115,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let flags = this.read_scalar(flags)?.to_u32()?; let size = this.read_scalar(size)?.to_machine_usize(this)?; let zero_init = (flags & 0x00000008) != 0; // HEAP_ZERO_MEMORY - let res = this.malloc(size, zero_init, MiriMemoryKind::WinHeap); + let res = this.malloc(size, zero_init, MiriMemoryKind::WinHeap)?; this.write_scalar(res, dest)?; } "HeapFree" => { From ca782dfc1c7b3865a40466a09dbcaab67fc148a6 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 5 Jul 2021 19:34:08 +0200 Subject: [PATCH 2754/3747] sync license files with rustc repo --- LICENSE-APACHE | 25 ------------------------- LICENSE-MIT | 2 -- 2 files changed, 27 deletions(-) diff --git a/LICENSE-APACHE b/LICENSE-APACHE index a32595fa70bc1..1b5ec8b78e237 100644 --- a/LICENSE-APACHE +++ b/LICENSE-APACHE @@ -174,28 +174,3 @@ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS - -APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - -Copyright 2016 The Miri Developers - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. diff --git a/LICENSE-MIT b/LICENSE-MIT index 1f9d89a5862b5..31aa79387f27e 100644 --- a/LICENSE-MIT +++ b/LICENSE-MIT @@ -1,5 +1,3 @@ -Copyright (c) 2016 The Miri Developers - Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the From efd582c6d8f14ffd730c5911101789e40eccec31 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 6 Jul 2021 10:04:16 +0200 Subject: [PATCH 2755/3747] explicitly list memory kinds for stacked borrows --- src/stacked_borrows.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 3e176d94b9902..32cecf855d499 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -513,8 +513,14 @@ impl Stacks { | MiriMemoryKind::Tls | MiriMemoryKind::Env, ) => (extra.global_base_ptr(id), Permission::SharedReadWrite), - // Everything else we handle like raw pointers for now. - _ => { + // Everything else we only track precisely when raw pointers are tagged, for now. + MemoryKind::CallerLocation + | MemoryKind::Machine( + MiriMemoryKind::Rust + | MiriMemoryKind::C + | MiriMemoryKind::WinHeap + | MiriMemoryKind::Machine, + ) => { let tag = if extra.track_raw { Tag::Tagged(extra.new_ptr()) } else { Tag::Untagged }; (tag, Permission::SharedReadWrite) From 9b57313a4d91d9b66d237151a852955a9e450160 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 6 Jul 2021 10:07:48 +0200 Subject: [PATCH 2756/3747] also treat CallerLocation and Machine memory as properly tagged --- src/stacked_borrows.rs | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 32cecf855d499..d5bd300959dfd 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -504,22 +504,23 @@ impl Stacks { // `Global` memory can be referenced by global pointers from `tcx`. // Thus we call `global_base_ptr` such that the global pointers get the same tag // as what we use here. - // `ExternStatic` is used for extern statics, and thus must also be listed here. - // `Env` we list because we can get away with precise tracking there. + // `ExternStatic` is used for extern statics, so the same reasoning applies. + // The others are various forms of machine-managed special global memory, and we can get + // away with precise tracking there. // The base pointer is not unique, so the base permission is `SharedReadWrite`. - MemoryKind::Machine( + MemoryKind::CallerLocation + | MemoryKind::Machine( MiriMemoryKind::Global | MiriMemoryKind::ExternStatic | MiriMemoryKind::Tls - | MiriMemoryKind::Env, + | MiriMemoryKind::Env + | MiriMemoryKind::Machine, ) => (extra.global_base_ptr(id), Permission::SharedReadWrite), - // Everything else we only track precisely when raw pointers are tagged, for now. - MemoryKind::CallerLocation - | MemoryKind::Machine( + // Heap allocations we only track precisely when raw pointers are tagged, for now. + MemoryKind::Machine( MiriMemoryKind::Rust | MiriMemoryKind::C - | MiriMemoryKind::WinHeap - | MiriMemoryKind::Machine, + | MiriMemoryKind::WinHeap, ) => { let tag = if extra.track_raw { Tag::Tagged(extra.new_ptr()) } else { Tag::Untagged }; From 340267525c9bfdd0b7bdca51f4a36e7857a05b25 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 6 Jul 2021 10:09:53 +0200 Subject: [PATCH 2757/3747] exported_symbols_cache: ensure we do not overwrite anything --- src/shims/foreign_items.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 5d46f3c05c339..2de0baf294747 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -194,7 +194,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let instance = instance_and_crate.map(|ic| ic.0); // Cache it and load its MIR, if found. - this.machine.exported_symbols_cache.insert(link_name, instance); + this.machine.exported_symbols_cache.try_insert(link_name, instance).unwrap(); instance.map(|instance| this.load_mir(instance.def, None)).transpose() } From 447f23c71b1bedc8ba363eeeb0c24affc79f89a0 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 6 Jul 2021 10:13:30 +0200 Subject: [PATCH 2758/3747] fmt --- src/stacked_borrows.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index d5bd300959dfd..0b92817c9728e 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -518,9 +518,7 @@ impl Stacks { ) => (extra.global_base_ptr(id), Permission::SharedReadWrite), // Heap allocations we only track precisely when raw pointers are tagged, for now. MemoryKind::Machine( - MiriMemoryKind::Rust - | MiriMemoryKind::C - | MiriMemoryKind::WinHeap, + MiriMemoryKind::Rust | MiriMemoryKind::C | MiriMemoryKind::WinHeap, ) => { let tag = if extra.track_raw { Tag::Tagged(extra.new_ptr()) } else { Tag::Untagged }; From 833dff994f68612cab173f159346c27b0dc0e247 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 7 Jul 2021 09:32:58 +0200 Subject: [PATCH 2759/3747] rustup --- rust-version | 2 +- tests/run-pass/panic/catch_panic.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/rust-version b/rust-version index 23819ebc24e42..8856f7d0852ca 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -39e20f1ae5f13451eb35247808d6a2527cb7d060 +c5e344f7747dbd7e7d4b209e3c480deb5979a56f diff --git a/tests/run-pass/panic/catch_panic.rs b/tests/run-pass/panic/catch_panic.rs index 9f9a2b493cef3..63a3c9a47648c 100644 --- a/tests/run-pass/panic/catch_panic.rs +++ b/tests/run-pass/panic/catch_panic.rs @@ -3,7 +3,7 @@ // We test the `align_offset` panic below, make sure we test the interpreter impl and not the "real" one. // compile-flags: -Zmiri-symbolic-alignment-check #![feature(never_type)] -#![allow(unconditional_panic, non_fmt_panic)] +#![allow(unconditional_panic, non_fmt_panics)] use std::panic::{catch_unwind, AssertUnwindSafe}; use std::cell::Cell; From 811423e76126c7c60651ced211241dd2cc796a05 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Sat, 10 Jul 2021 11:51:00 -0500 Subject: [PATCH 2760/3747] Rustup for `#[track_caller]` trait object changes Change test to assert that we get the correct location even through a trait object call. --- rust-version | 2 +- tests/run-pass/track-caller-attribute.rs | 24 ++++++++++++++++-------- 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/rust-version b/rust-version index 8856f7d0852ca..aee5d6ee3ba2e 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -c5e344f7747dbd7e7d4b209e3c480deb5979a56f +3982eb35cabe3a99194d768d34a92347967c3fa2 diff --git a/tests/run-pass/track-caller-attribute.rs b/tests/run-pass/track-caller-attribute.rs index a9cfd2e0ebded..d1115faa8f756 100644 --- a/tests/run-pass/track-caller-attribute.rs +++ b/tests/run-pass/track-caller-attribute.rs @@ -38,23 +38,31 @@ fn test_fn_ptr() { fn test_trait_obj() { trait Tracked { #[track_caller] - fn handle(&self) { // `fn` here is what the `location` should point at. - let location = std::panic::Location::caller(); - assert_eq!(location.file(), file!()); - // we only call this via trait object, so the def site should *always* be returned - assert_eq!(location.line(), line!() - 4); - assert_eq!(location.column(), 9); + fn handle(&self) -> &'static Location<'static> { + std::panic::Location::caller() } } impl Tracked for () {} impl Tracked for u8 {} + // Test that we get the correct location + // even with a call through a trait object + let tracked: &dyn Tracked = &5u8; - tracked.handle(); + let location = tracked.handle(); + let expected_line = line!() - 1; + assert_eq!(location.file(), file!()); + assert_eq!(location.line(), expected_line); + assert_eq!(location.column(), 28); const TRACKED: &dyn Tracked = &(); - TRACKED.handle(); + let location = TRACKED.handle(); + let expected_line = line!() - 1; + assert_eq!(location.file(), file!()); + assert_eq!(location.line(), expected_line); + assert_eq!(location.column(), 28); + } fn main() { From 0341b8ac846c2846fc2aa20aaabe161cb5a0bae9 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 11 Jul 2021 14:18:44 +0200 Subject: [PATCH 2761/3747] fmt: set force_multiline_blocks=true --- benches/helpers/miri_helper.rs | 7 +-- rustfmt.toml | 1 + src/bin/miri.rs | 41 +++++++++------ src/diagnostics.rs | 11 ++-- src/helpers.rs | 9 ++-- src/shims/env.rs | 9 ++-- src/shims/foreign_items.rs | 96 +++++++++++++++++----------------- src/shims/intrinsics.rs | 9 ++-- src/shims/posix/fs.rs | 45 +++++++++------- src/stacked_borrows.rs | 9 ++-- src/vector_clock.rs | 18 ++++--- 11 files changed, 141 insertions(+), 114 deletions(-) diff --git a/benches/helpers/miri_helper.rs b/benches/helpers/miri_helper.rs index b26705cb704ff..2d27616a3613f 100644 --- a/benches/helpers/miri_helper.rs +++ b/benches/helpers/miri_helper.rs @@ -40,9 +40,10 @@ fn find_sysroot() -> String { let toolchain = option_env!("RUSTUP_TOOLCHAIN").or(option_env!("MULTIRUST_TOOLCHAIN")); match (home, toolchain) { (Some(home), Some(toolchain)) => format!("{}/toolchains/{}", home, toolchain), - _ => option_env!("RUST_SYSROOT") - .expect("need to specify RUST_SYSROOT env var or use rustup or multirust") - .to_owned(), + _ => + option_env!("RUST_SYSROOT") + .expect("need to specify RUST_SYSROOT env var or use rustup or multirust") + .to_owned(), } } diff --git a/rustfmt.toml b/rustfmt.toml index 373caafd106b1..be5af7379eae7 100644 --- a/rustfmt.toml +++ b/rustfmt.toml @@ -2,3 +2,4 @@ version = "Two" use_small_heuristics = "Max" match_arm_blocks = false match_arm_leading_pipes = "Preserve" +force_multiline_blocks = true diff --git a/src/bin/miri.rs b/src/bin/miri.rs index d593f24c71ab4..9dbd5e24aeba9 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -203,9 +203,12 @@ fn compile_time_sysroot() -> Option { let toolchain = option_env!("RUSTUP_TOOLCHAIN").or(option_env!("MULTIRUST_TOOLCHAIN")); Some(match (home, toolchain) { (Some(home), Some(toolchain)) => format!("{}/toolchains/{}", home, toolchain), - _ => option_env!("RUST_SYSROOT") - .expect("To build Miri without rustup, set the `RUST_SYSROOT` env var at build time") - .to_owned(), + _ => + option_env!("RUST_SYSROOT") + .expect( + "To build Miri without rustup, set the `RUST_SYSROOT` env var at build time", + ) + .to_owned(), }) } @@ -336,9 +339,10 @@ fn main() { "warn" => miri::IsolatedOp::Reject(miri::RejectOpWith::Warning), "warn-nobacktrace" => miri::IsolatedOp::Reject(miri::RejectOpWith::WarningWithoutBacktrace), - _ => panic!( - "-Zmiri-isolation-error must be `abort`, `hide`, `warn`, or `warn-nobacktrace`" - ), + _ => + panic!( + "-Zmiri-isolation-error must be `abort`, `hide`, `warn`, or `warn-nobacktrace`" + ), }; } "-Zmiri-ignore-leaks" => { @@ -383,10 +387,11 @@ fn main() { let id: u64 = match arg.strip_prefix("-Zmiri-track-pointer-tag=").unwrap().parse() { Ok(id) => id, - Err(err) => panic!( - "-Zmiri-track-pointer-tag requires a valid `u64` argument: {}", - err - ), + Err(err) => + panic!( + "-Zmiri-track-pointer-tag requires a valid `u64` argument: {}", + err + ), }; if let Some(id) = miri::PtrId::new(id) { miri_config.tracked_pointer_tag = Some(id); @@ -422,13 +427,15 @@ fn main() { .parse::() { Ok(rate) if rate >= 0.0 && rate <= 1.0 => rate, - Ok(_) => panic!( - "-Zmiri-compare-exchange-weak-failure-rate must be between `0.0` and `1.0`" - ), - Err(err) => panic!( - "-Zmiri-compare-exchange-weak-failure-rate requires a `f64` between `0.0` and `1.0`: {}", - err - ), + Ok(_) => + panic!( + "-Zmiri-compare-exchange-weak-failure-rate must be between `0.0` and `1.0`" + ), + Err(err) => + panic!( + "-Zmiri-compare-exchange-weak-failure-rate requires a `f64` between `0.0` and `1.0`: {}", + err + ), }; miri_config.cmpxchg_weak_failure_rate = rate; } diff --git a/src/diagnostics.rs b/src/diagnostics.rs index 887b2ac4b378b..4476ce237ff49 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -43,11 +43,12 @@ impl fmt::Display for TerminationInfo { Deadlock => write!(f, "the evaluated program deadlocked"), MultipleSymbolDefinitions { link_name, .. } => write!(f, "multiple definitions of symbol `{}`", link_name), - SymbolShimClashing { link_name, .. } => write!( - f, - "found `{}` symbol definition that clashes with a built-in shim", - link_name - ), + SymbolShimClashing { link_name, .. } => + write!( + f, + "found `{}` symbol definition that clashes with a built-in shim", + link_name + ), } } } diff --git a/src/helpers.rs b/src/helpers.rs index a6e66c3dbd38e..057684562fdb2 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -498,10 +498,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx match err_kind { NotFound => "ERROR_FILE_NOT_FOUND", PermissionDenied => "ERROR_ACCESS_DENIED", - _ => throw_unsup_format!( - "io error {:?} cannot be translated into a raw os error", - err_kind - ), + _ => + throw_unsup_format!( + "io error {:?} cannot be translated into a raw os error", + err_kind + ), }, )? } else { diff --git a/src/shims/env.rs b/src/shims/env.rs index d99ffb31b5cf5..59322b91d6799 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -53,10 +53,11 @@ impl<'tcx> EnvVars<'tcx> { "linux" | "macos" => alloc_env_var_as_c_str(name.as_ref(), value.as_ref(), ecx)?, "windows" => alloc_env_var_as_wide_str(name.as_ref(), value.as_ref(), ecx)?, - unsupported => throw_unsup_format!( - "environment support for target OS `{}` not yet available", - unsupported - ), + unsupported => + throw_unsup_format!( + "environment support for target OS `{}` not yet available", + unsupported + ), }; ecx.machine.env_vars.map.insert(OsString::from(name), var_ptr); } diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 2de0baf294747..61dca93f0ed49 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -223,54 +223,56 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // First: functions that diverge. let (dest, ret) = match ret { - None => match &*link_name.as_str() { - "miri_start_panic" => { - // `check_shim` happens inside `handle_miri_start_panic`. - this.handle_miri_start_panic(abi, link_name, args, unwind)?; - return Ok(None); - } - // This matches calls to the foreign item `panic_impl`. - // The implementation is provided by the function with the `#[panic_handler]` attribute. - "panic_impl" => { - // We don't use `check_shim` here because we are just forwarding to the lang - // item. Argument count checking will be performed when the returned `Body` is - // called. - this.check_abi_and_shim_symbol_clash(abi, Abi::Rust, link_name)?; - let panic_impl_id = tcx.lang_items().panic_impl().unwrap(); - let panic_impl_instance = ty::Instance::mono(tcx, panic_impl_id); - return Ok(Some(&*this.load_mir(panic_impl_instance.def, None)?)); - } - #[rustfmt::skip] - | "exit" - | "ExitProcess" - => { - let exp_abi = if link_name.as_str() == "exit" { - Abi::C { unwind: false } - } else { - Abi::System { unwind: false } - }; - let &[ref code] = this.check_shim(abi, exp_abi, link_name, args)?; - // it's really u32 for ExitProcess, but we have to put it into the `Exit` variant anyway - let code = this.read_scalar(code)?.to_i32()?; - throw_machine_stop!(TerminationInfo::Exit(code.into())); - } - "abort" => { - let &[] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; - throw_machine_stop!(TerminationInfo::Abort( - "the program aborted execution".to_owned() - )) - } - _ => { - if let Some(body) = this.lookup_exported_symbol(link_name)? { - return Ok(Some(body)); + None => + match &*link_name.as_str() { + "miri_start_panic" => { + // `check_shim` happens inside `handle_miri_start_panic`. + this.handle_miri_start_panic(abi, link_name, args, unwind)?; + return Ok(None); } - this.handle_unsupported(format!( - "can't call (diverging) foreign function: {}", - link_name - ))?; - return Ok(None); - } - }, + // This matches calls to the foreign item `panic_impl`. + // The implementation is provided by the function with the `#[panic_handler]` attribute. + "panic_impl" => { + // We don't use `check_shim` here because we are just forwarding to the lang + // item. Argument count checking will be performed when the returned `Body` is + // called. + this.check_abi_and_shim_symbol_clash(abi, Abi::Rust, link_name)?; + let panic_impl_id = tcx.lang_items().panic_impl().unwrap(); + let panic_impl_instance = ty::Instance::mono(tcx, panic_impl_id); + return Ok(Some(&*this.load_mir(panic_impl_instance.def, None)?)); + } + #[rustfmt::skip] + | "exit" + | "ExitProcess" + => { + let exp_abi = if link_name.as_str() == "exit" { + Abi::C { unwind: false } + } else { + Abi::System { unwind: false } + }; + let &[ref code] = this.check_shim(abi, exp_abi, link_name, args)?; + // it's really u32 for ExitProcess, but we have to put it into the `Exit` variant anyway + let code = this.read_scalar(code)?.to_i32()?; + throw_machine_stop!(TerminationInfo::Exit(code.into())); + } + "abort" => { + let &[] = + this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + throw_machine_stop!(TerminationInfo::Abort( + "the program aborted execution".to_owned() + )) + } + _ => { + if let Some(body) = this.lookup_exported_symbol(link_name)? { + return Ok(Some(body)); + } + this.handle_unsupported(format!( + "can't call (diverging) foreign function: {}", + link_name + ))?; + return Ok(None); + } + }, Some(p) => p, }; diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index c018dd8738108..caef57df8dd28 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -295,10 +295,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.float_to_int_unchecked(val.to_scalar()?.to_f32()?, dest.layout.ty)?, ty::Float(FloatTy::F64) => this.float_to_int_unchecked(val.to_scalar()?.to_f64()?, dest.layout.ty)?, - _ => bug!( - "`float_to_int_unchecked` called with non-float input type {:?}", - val.layout.ty - ), + _ => + bug!( + "`float_to_int_unchecked` called with non-float input type {:?}", + val.layout.ty + ), }; this.write_scalar(res, dest)?; diff --git a/src/shims/posix/fs.rs b/src/shims/posix/fs.rs index fbef9f3040713..bfc6195b3af33 100644 --- a/src/shims/posix/fs.rs +++ b/src/shims/posix/fs.rs @@ -434,10 +434,11 @@ trait EvalContextExtPrivate<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, ' Err(e) => return match e.raw_os_error() { Some(error) => Ok(error), - None => throw_unsup_format!( - "the error {} couldn't be converted to a return value", - e - ), + None => + throw_unsup_format!( + "the error {} couldn't be converted to a return value", + e + ), }, } } @@ -1203,13 +1204,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_null(&this.deref_operand(result_op)?.into())?; Ok(0) } - Some(Err(e)) => match e.raw_os_error() { - // return positive error number on error - Some(error) => Ok(error), - None => { - throw_unsup_format!("the error {} couldn't be converted to a return value", e) - } - }, + Some(Err(e)) => + match e.raw_os_error() { + // return positive error number on error + Some(error) => Ok(error), + None => { + throw_unsup_format!( + "the error {} couldn't be converted to a return value", + e + ) + } + }, } } @@ -1294,13 +1299,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_null(&this.deref_operand(result_op)?.into())?; Ok(0) } - Some(Err(e)) => match e.raw_os_error() { - // return positive error number on error - Some(error) => Ok(error), - None => { - throw_unsup_format!("the error {} couldn't be converted to a return value", e) - } - }, + Some(Err(e)) => + match e.raw_os_error() { + // return positive error number on error + Some(error) => Ok(error), + None => { + throw_unsup_format!( + "the error {} couldn't be converted to a return value", + e + ) + } + }, } } diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 0b92817c9728e..0365e9ca00edd 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -699,10 +699,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn qualify(ty: ty::Ty<'_>, kind: RetagKind) -> Option<(RefKind, bool)> { match ty.kind() { // References are simple. - ty::Ref(_, _, Mutability::Mut) => Some(( - RefKind::Unique { two_phase: kind == RetagKind::TwoPhase }, - kind == RetagKind::FnEntry, - )), + ty::Ref(_, _, Mutability::Mut) => + Some(( + RefKind::Unique { two_phase: kind == RetagKind::TwoPhase }, + kind == RetagKind::FnEntry, + )), ty::Ref(_, _, Mutability::Not) => Some((RefKind::Shared, kind == RetagKind::FnEntry)), // Raw pointers need to be enabled. diff --git a/src/vector_clock.rs b/src/vector_clock.rs index a2e235858d83a..74180f25b3bbe 100644 --- a/src/vector_clock.rs +++ b/src/vector_clock.rs @@ -186,16 +186,18 @@ impl PartialOrd for VClock { Ordering::Equal => Some(order), // Right has at least 1 element > than the implicit 0, // so the only valid values are Ordering::Less or None. - Ordering::Less => match order { - Ordering::Less | Ordering::Equal => Some(Ordering::Less), - Ordering::Greater => None, - }, + Ordering::Less => + match order { + Ordering::Less | Ordering::Equal => Some(Ordering::Less), + Ordering::Greater => None, + }, // Left has at least 1 element > than the implicit 0, // so the only valid values are Ordering::Greater or None. - Ordering::Greater => match order { - Ordering::Greater | Ordering::Equal => Some(Ordering::Greater), - Ordering::Less => None, - }, + Ordering::Greater => + match order { + Ordering::Greater | Ordering::Equal => Some(Ordering::Greater), + Ordering::Less => None, + }, } } From cffa1d325c7c5a0d9e28f0419d05cf0afe1d3504 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 11 Jul 2021 14:27:07 +0200 Subject: [PATCH 2762/3747] fmt cargo-miri --- cargo-miri/bin.rs | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index 1a7552c5d9e05..23546988daa8f 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -528,9 +528,10 @@ fn phase_cargo_miri(mut args: env::Args) { Some("run") => MiriCommand::Run, Some("setup") => MiriCommand::Setup, // Invalid command. - _ => show_error(format!( - "`cargo miri` supports the following subcommands: `run`, `test`, and `setup`." - )), + _ => + show_error(format!( + "`cargo miri` supports the following subcommands: `run`, `test`, and `setup`." + )), }; let verbose = has_arg_flag("-v"); @@ -1086,8 +1087,9 @@ fn main() { )); } } - _ => show_error(format!( - "`cargo-miri` called without first argument; please only invoke this binary through `cargo miri`" - )), + _ => + show_error(format!( + "`cargo-miri` called without first argument; please only invoke this binary through `cargo miri`" + )), } } From a1233a721d0832071a2c1b1a95895cc0b924b553 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 15 Jul 2021 20:33:08 +0200 Subject: [PATCH 2763/3747] adjust Miri to Pointer type overhaul --- src/bin/miri.rs | 14 +- src/data_race.rs | 105 ++++----- src/diagnostics.rs | 2 +- src/eval.rs | 27 ++- src/helpers.rs | 98 ++++---- src/intptrcast.rs | 101 ++++---- src/lib.rs | 5 +- src/machine.rs | 199 ++++++++-------- src/mono_hash_map.rs | 24 +- src/operator.rs | 14 +- src/shims/backtrace.rs | 42 ++-- src/shims/env.rs | 102 ++++---- src/shims/foreign_items.rs | 73 +++--- src/shims/intrinsics.rs | 2 +- src/shims/mod.rs | 14 +- src/shims/os_str.rs | 49 ++-- src/shims/panic.rs | 11 +- src/shims/posix/foreign_items.rs | 39 ++-- src/shims/posix/fs.rs | 51 ++-- src/shims/posix/linux/foreign_items.rs | 4 +- src/shims/posix/linux/sync.rs | 23 +- src/shims/posix/macos/dlsym.rs | 2 +- src/shims/posix/macos/foreign_items.rs | 21 +- src/shims/posix/sync.rs | 11 +- src/shims/posix/thread.rs | 10 +- src/shims/time.rs | 7 +- src/shims/tls.rs | 33 +-- src/shims/windows/foreign_items.rs | 28 +-- src/stacked_borrows.rs | 217 +++++++++++------- src/sync.rs | 14 +- src/thread.rs | 36 ++- .../deref-partially-dangling.rs | 2 +- .../dangling_pointers/dyn_size.rs | 2 +- .../maybe_null_pointer_deref_zst.rs | 2 +- .../maybe_null_pointer_write_zst.rs | 2 +- .../dangling_pointers/out_of_bounds_read1.rs | 2 +- .../dangling_pointers/out_of_bounds_read2.rs | 2 +- .../intrinsics/out_of_bounds_ptr_1.rs | 2 +- .../intrinsics/out_of_bounds_ptr_2.rs | 2 +- .../intrinsics/ptr_offset_ptr_plus_0.rs | 2 +- tests/compile-fail/null_pointer_deref_zst.rs | 2 +- tests/compile-fail/null_pointer_write_zst.rs | 3 +- .../stacked_borrows/issue-miri-1050-1.rs | 2 +- .../static_memory_modification.rs | 2 +- tests/compile-fail/zst1.rs | 2 +- tests/compile-fail/zst3.rs | 2 +- 46 files changed, 750 insertions(+), 659 deletions(-) diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 9dbd5e24aeba9..5a8f07263f35b 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -10,6 +10,7 @@ extern crate rustc_session; use std::convert::TryFrom; use std::env; +use std::num::NonZeroU64; use std::path::PathBuf; use std::rc::Rc; use std::str::FromStr; @@ -412,11 +413,16 @@ fn main() { } } arg if arg.starts_with("-Zmiri-track-alloc-id=") => { - let id: u64 = match arg.strip_prefix("-Zmiri-track-alloc-id=").unwrap().parse() + let id = match arg + .strip_prefix("-Zmiri-track-alloc-id=") + .unwrap() + .parse() + .ok() + .and_then(NonZeroU64::new) { - Ok(id) => id, - Err(err) => - panic!("-Zmiri-track-alloc-id requires a valid `u64` argument: {}", err), + Some(id) => id, + None => + panic!("-Zmiri-track-alloc-id requires a valid non-zero `u64` argument"), }; miri_config.tracked_alloc_id = Some(miri::AllocId(id)); } diff --git a/src/data_race.rs b/src/data_race.rs index cb7b1fc6dbe0c..6a64c1cb69369 100644 --- a/src/data_race.rs +++ b/src/data_race.rs @@ -73,9 +73,9 @@ use rustc_middle::{mir, ty::layout::TyAndLayout}; use rustc_target::abi::Size; use crate::{ - ImmTy, Immediate, InterpResult, MPlaceTy, MemPlaceMeta, MemoryKind, MiriEvalContext, - MiriEvalContextExt, MiriMemoryKind, OpTy, Pointer, RangeMap, Scalar, ScalarMaybeUninit, Tag, - ThreadId, VClock, VTimestamp, VectorIdx, + AllocId, AllocRange, ImmTy, Immediate, InterpResult, MPlaceTy, MemPlaceMeta, MemoryKind, + MiriEvalContext, MiriEvalContextExt, MiriMemoryKind, OpTy, Pointer, RangeMap, Scalar, + ScalarMaybeUninit, Tag, ThreadId, VClock, VTimestamp, VectorIdx, }; pub type AllocExtra = VClockAlloc; @@ -561,7 +561,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { if lt { &rhs } else { &old } }; - this.allow_data_races_mut(|this| this.write_immediate_to_mplace(**new_val, place))?; + this.allow_data_races_mut(|this| this.write_immediate(**new_val, &(*place).into()))?; this.validate_atomic_rmw(&place, atomic)?; @@ -713,18 +713,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { Ok(()) } } - - fn reset_vector_clocks(&mut self, ptr: Pointer, size: Size) -> InterpResult<'tcx> { - let this = self.eval_context_mut(); - if let Some(data_race) = &mut this.memory.extra.data_race { - if data_race.multi_threaded.get() { - let alloc_meta = - this.memory.get_alloc_extra_mut(ptr.alloc_id)?.0.data_race.as_mut().unwrap(); - alloc_meta.reset_clocks(ptr.offset, size); - } - } - Ok(()) - } } /// Vector clock metadata for a logical memory allocation. @@ -769,14 +757,6 @@ impl VClockAlloc { } } - fn reset_clocks(&mut self, offset: Size, len: Size) { - let alloc_ranges = self.alloc_ranges.get_mut(); - for (_, range) in alloc_ranges.iter_mut(offset, len) { - // Reset the portion of the range - *range = MemoryCellClocks::new(0, VectorIdx::MAX_INDEX); - } - } - // Find an index, if one exists where the value // in `l` is greater than the value in `r`. fn find_gt_index(l: &VClock, r: &VClock) -> Option { @@ -820,8 +800,7 @@ impl VClockAlloc { range: &MemoryCellClocks, action: &str, is_atomic: bool, - pointer: Pointer, - len: Size, + ptr_dbg: Pointer, ) -> InterpResult<'tcx> { let (current_index, current_clocks) = global.current_thread_state(); let write_clock; @@ -863,15 +842,12 @@ impl VClockAlloc { // Throw the data-race detection. throw_ub_format!( - "Data race detected between {} on {} and {} on {}, memory({:?},offset={},size={})\ - \n(current vector clock = {:?}, conflicting timestamp = {:?})", + "Data race detected between {} on {} and {} on {} at {:?} (current vector clock = {:?}, conflicting timestamp = {:?})", action, current_thread_info, other_action, other_thread_info, - pointer.alloc_id, - pointer.offset.bytes(), - len.bytes(), + ptr_dbg, current_clocks.clock, other_clock ) @@ -884,17 +860,23 @@ impl VClockAlloc { /// atomic read operations. pub fn read<'tcx>( &self, - pointer: Pointer, - len: Size, + alloc_id: AllocId, + range: AllocRange, global: &GlobalState, ) -> InterpResult<'tcx> { if global.multi_threaded.get() { let (index, clocks) = global.current_thread_state(); let mut alloc_ranges = self.alloc_ranges.borrow_mut(); - for (_, range) in alloc_ranges.iter_mut(pointer.offset, len) { + for (offset, range) in alloc_ranges.iter_mut(range.start, range.size) { if let Err(DataRace) = range.read_race_detect(&*clocks, index) { // Report data-race. - return Self::report_data_race(global, range, "Read", false, pointer, len); + return Self::report_data_race( + global, + range, + "Read", + false, + Pointer::new(alloc_id, offset), + ); } } Ok(()) @@ -906,14 +888,14 @@ impl VClockAlloc { // Shared code for detecting data-races on unique access to a section of memory fn unique_access<'tcx>( &mut self, - pointer: Pointer, - len: Size, + alloc_id: AllocId, + range: AllocRange, write_type: WriteType, global: &mut GlobalState, ) -> InterpResult<'tcx> { if global.multi_threaded.get() { let (index, clocks) = global.current_thread_state(); - for (_, range) in self.alloc_ranges.get_mut().iter_mut(pointer.offset, len) { + for (offset, range) in self.alloc_ranges.get_mut().iter_mut(range.start, range.size) { if let Err(DataRace) = range.write_race_detect(&*clocks, index, write_type) { // Report data-race return Self::report_data_race( @@ -921,8 +903,7 @@ impl VClockAlloc { range, write_type.get_descriptor(), false, - pointer, - len, + Pointer::new(alloc_id, offset), ); } } @@ -938,11 +919,11 @@ impl VClockAlloc { /// operation pub fn write<'tcx>( &mut self, - pointer: Pointer, - len: Size, + alloc_id: AllocId, + range: AllocRange, global: &mut GlobalState, ) -> InterpResult<'tcx> { - self.unique_access(pointer, len, WriteType::Write, global) + self.unique_access(alloc_id, range, WriteType::Write, global) } /// Detect data-races for an unsynchronized deallocate operation, will not perform @@ -951,11 +932,11 @@ impl VClockAlloc { /// operation pub fn deallocate<'tcx>( &mut self, - pointer: Pointer, - len: Size, + alloc_id: AllocId, + range: AllocRange, global: &mut GlobalState, ) -> InterpResult<'tcx> { - self.unique_access(pointer, len, WriteType::Deallocate, global) + self.unique_access(alloc_id, range, WriteType::Deallocate, global) } } @@ -1002,12 +983,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { result } - /// Generic atomic operation implementation, - /// this accesses memory via get_raw instead of - /// get_raw_mut, due to issues calling get_raw_mut - /// for atomic loads from read-only memory. - /// FIXME: is this valid, or should get_raw_mut be used for - /// atomic-stores/atomic-rmw? + /// Generic atomic operation implementation fn validate_atomic_op( &self, place: &MPlaceTy<'tcx, Tag>, @@ -1023,25 +999,24 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { let this = self.eval_context_ref(); if let Some(data_race) = &this.memory.extra.data_race { if data_race.multi_threaded.get() { + let size = place.layout.size; + let (alloc_id, base_offset, ptr) = this.memory.ptr_get_alloc(place.ptr)?; // Load and log the atomic operation. // Note that atomic loads are possible even from read-only allocations, so `get_alloc_extra_mut` is not an option. - let place_ptr = place.ptr.assert_ptr(); - let size = place.layout.size; let alloc_meta = - &this.memory.get_alloc_extra(place_ptr.alloc_id)?.data_race.as_ref().unwrap(); + &this.memory.get_alloc_extra(alloc_id)?.data_race.as_ref().unwrap(); log::trace!( - "Atomic op({}) with ordering {:?} on memory({:?}, offset={}, size={})", + "Atomic op({}) with ordering {:?} on {:?} (size={})", description, &atomic, - place_ptr.alloc_id, - place_ptr.offset.bytes(), + ptr, size.bytes() ); // Perform the atomic operation. data_race.maybe_perform_sync_operation(|index, mut clocks| { - for (_, range) in - alloc_meta.alloc_ranges.borrow_mut().iter_mut(place_ptr.offset, size) + for (offset, range) in + alloc_meta.alloc_ranges.borrow_mut().iter_mut(base_offset, size) { if let Err(DataRace) = op(range, &mut *clocks, index, atomic) { mem::drop(clocks); @@ -1050,8 +1025,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { range, description, true, - place_ptr, - size, + Pointer::new(alloc_id, offset), ) .map(|_| true); } @@ -1063,12 +1037,11 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { // Log changes to atomic memory. if log::log_enabled!(log::Level::Trace) { - for (_, range) in alloc_meta.alloc_ranges.borrow().iter(place_ptr.offset, size) + for (_offset, range) in alloc_meta.alloc_ranges.borrow().iter(base_offset, size) { log::trace!( - "Updated atomic memory({:?}, offset={}, size={}) to {:#?}", - place.ptr.assert_ptr().alloc_id, - place_ptr.offset.bytes(), + "Updated atomic memory({:?}, size={}) to {:#?}", + ptr, size.bytes(), range.atomic_ops ); diff --git a/src/diagnostics.rs b/src/diagnostics.rs index 4476ce237ff49..b5b75a7fc3184 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -134,7 +134,7 @@ pub fn report_error<'tcx, 'mir>( let helps = match e.kind() { Unsupported(UnsupportedOpInfo::NoMirFor(..)) => vec![(None, format!("make sure to use a Miri sysroot, which you can prepare with `cargo miri setup`"))], - Unsupported(UnsupportedOpInfo::ReadBytesAsPointer | UnsupportedOpInfo::ThreadLocalStatic(_) | UnsupportedOpInfo::ReadExternStatic(_)) => + Unsupported(UnsupportedOpInfo::ThreadLocalStatic(_) | UnsupportedOpInfo::ReadExternStatic(_)) => panic!("Error should never be raised by Miri: {:?}", e.kind()), Unsupported(_) => vec![(None, format!("this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support"))], diff --git a/src/eval.rs b/src/eval.rs index f728248c3a723..ae9ff9c1f5a42 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -164,7 +164,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( // Third argument (`argv`): created from `config.args`. let argv = { // Put each argument in memory, collect pointers. - let mut argvs = Vec::>::new(); + let mut argvs = Vec::>::new(); for arg in config.args.iter() { // Make space for `0` terminator. let size = u64::try_from(arg.len()).unwrap().checked_add(1).unwrap(); @@ -172,7 +172,8 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( let arg_place = ecx.allocate(ecx.layout_of(arg_type)?, MiriMemoryKind::Machine.into())?; ecx.write_os_str_to_c_str(OsStr::new(arg), arg_place.ptr, size)?; - argvs.push(arg_place.ptr); + ecx.mark_immutable(&*arg_place); + argvs.push(arg_place.to_ref(&ecx)); } // Make an array with all these pointers, in the Miri memory. let argvs_layout = ecx.layout_of( @@ -181,24 +182,26 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( let argvs_place = ecx.allocate(argvs_layout, MiriMemoryKind::Machine.into())?; for (idx, arg) in argvs.into_iter().enumerate() { let place = ecx.mplace_field(&argvs_place, idx)?; - ecx.write_scalar(arg, &place.into())?; + ecx.write_immediate(arg, &place.into())?; } - ecx.memory.mark_immutable(argvs_place.ptr.assert_ptr().alloc_id)?; + ecx.mark_immutable(&*argvs_place); // A pointer to that place is the 3rd argument for main. - let argv = argvs_place.ptr; + let argv = argvs_place.to_ref(&ecx); // Store `argc` and `argv` for macOS `_NSGetArg{c,v}`. { let argc_place = ecx.allocate(ecx.machine.layouts.isize, MiriMemoryKind::Machine.into())?; ecx.write_scalar(argc, &argc_place.into())?; - ecx.machine.argc = Some(argc_place.ptr); + ecx.mark_immutable(&*argc_place); + ecx.machine.argc = Some(*argc_place); let argv_place = ecx.allocate( ecx.layout_of(tcx.mk_imm_ptr(tcx.types.unit))?, MiriMemoryKind::Machine.into(), )?; - ecx.write_scalar(argv, &argv_place.into())?; - ecx.machine.argv = Some(argv_place.ptr); + ecx.write_immediate(argv, &argv_place.into())?; + ecx.mark_immutable(&*argv_place); + ecx.machine.argv = Some(*argv_place); } // Store command line as UTF-16 for Windows `GetCommandLineW`. { @@ -217,12 +220,13 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( let cmd_type = tcx.mk_array(tcx.types.u16, u64::try_from(cmd_utf16.len()).unwrap()); let cmd_place = ecx.allocate(ecx.layout_of(cmd_type)?, MiriMemoryKind::Machine.into())?; - ecx.machine.cmd_line = Some(cmd_place.ptr); + ecx.machine.cmd_line = Some(*cmd_place); // Store the UTF-16 string. We just allocated so we know the bounds are fine. for (idx, &c) in cmd_utf16.iter().enumerate() { let place = ecx.mplace_field(&cmd_place, idx)?; ecx.write_scalar(Scalar::from_u16(c), &place.into())?; } + ecx.mark_immutable(&*cmd_place); } argv }; @@ -233,7 +237,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( ecx.call_function( start_instance, Abi::Rust, - &[main_ptr.into(), argc.into(), argv.into()], + &[Scalar::from_pointer(main_ptr, &ecx).into(), argc.into(), argv], Some(&ret_place.into()), StackPopCleanup::None { cleanup: true }, )?; @@ -285,8 +289,7 @@ pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) -> } ecx.process_diagnostics(info); } - let return_code = - ecx.read_scalar(&ret_place.into())?.check_init()?.to_machine_isize(&ecx)?; + let return_code = ecx.read_scalar(&ret_place.into())?.to_machine_isize(&ecx)?; Ok(return_code) })(); diff --git a/src/helpers.rs b/src/helpers.rs index 057684562fdb2..363aefa62d2f8 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -53,18 +53,18 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// Evaluates the scalar at the specified path. Returns Some(val) /// if the path could be resolved, and None otherwise - fn eval_path_scalar(&mut self, path: &[&str]) -> InterpResult<'tcx, ScalarMaybeUninit> { + fn eval_path_scalar(&mut self, path: &[&str]) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); let instance = this.resolve_path(path); let cid = GlobalId { instance, promoted: None }; let const_val = this.eval_to_allocation(cid)?; let const_val = this.read_scalar(&const_val.into())?; - return Ok(const_val); + return Ok(const_val.check_init()?); } /// Helper function to get a `libc` constant as a `Scalar`. fn eval_libc(&mut self, name: &str) -> InterpResult<'tcx, Scalar> { - self.eval_context_mut().eval_path_scalar(&["libc", name])?.check_init() + self.eval_context_mut().eval_path_scalar(&["libc", name]) } /// Helper function to get a `libc` constant as an `i32`. @@ -75,9 +75,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// Helper function to get a `windows` constant as a `Scalar`. fn eval_windows(&mut self, module: &str, name: &str) -> InterpResult<'tcx, Scalar> { - self.eval_context_mut() - .eval_path_scalar(&["std", "sys", "windows", module, name])? - .check_init() + self.eval_context_mut().eval_path_scalar(&["std", "sys", "windows", module, name]) } /// Helper function to get a `windows` constant as an `u64`. @@ -107,17 +105,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx self.eval_context_mut().write_scalar(Scalar::from_int(0, dest.layout.size), dest) } - /// Test if this immediate equals 0. - fn is_null(&self, val: Scalar) -> InterpResult<'tcx, bool> { + /// Test if this pointer equals 0. + fn ptr_is_null(&self, ptr: Pointer>) -> InterpResult<'tcx, bool> { let this = self.eval_context_ref(); let null = Scalar::null_ptr(this); - this.ptr_eq(val, null) - } - - /// Turn a Scalar into an Option - fn test_null(&self, val: Scalar) -> InterpResult<'tcx, Option>> { - let this = self.eval_context_ref(); - Ok(if this.is_null(val)? { None } else { Some(val) }) + this.ptr_eq(Scalar::from_maybe_pointer(ptr, this), null) } /// Get the `Place` for a local @@ -128,7 +120,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } /// Generate some random bytes, and write them to `dest`. - fn gen_random(&mut self, ptr: Scalar, len: u64) -> InterpResult<'tcx> { + fn gen_random(&mut self, ptr: Pointer>, len: u64) -> InterpResult<'tcx> { // Some programs pass in a null pointer and a length of 0 // to their platform's random-generation function (e.g. getrandom()) // on Linux. For compatibility with these programs, we don't perform @@ -195,13 +187,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(()) } - /// Visits the memory covered by `place`, sensitive to freezing: the 3rd parameter - /// will be true if this is frozen, false if this is in an `UnsafeCell`. + /// Visits the memory covered by `place`, sensitive to freezing: the 2nd parameter + /// of `action` will be true if this is frozen, false if this is in an `UnsafeCell`. + /// The range is relative to `place`. + /// + /// Assumes that the `place` has a proper pointer in it. fn visit_freeze_sensitive( &self, place: &MPlaceTy<'tcx, Tag>, size: Size, - mut action: impl FnMut(Pointer, Size, bool) -> InterpResult<'tcx>, + mut action: impl FnMut(AllocRange, bool) -> InterpResult<'tcx>, ) -> InterpResult<'tcx> { let this = self.eval_context_ref(); trace!("visit_frozen(place={:?}, size={:?})", *place, size); @@ -214,29 +209,33 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Store how far we proceeded into the place so far. Everything to the left of // this offset has already been handled, in the sense that the frozen parts // have had `action` called on them. - let mut end_ptr = place.ptr.assert_ptr(); + let ptr = place.ptr.into_pointer_or_addr().unwrap(); + let start_offset = ptr.into_parts().1 as Size; // we just compare offsets, the abs. value never matters + let mut cur_offset = start_offset; // Called when we detected an `UnsafeCell` at the given offset and size. - // Calls `action` and advances `end_ptr`. - let mut unsafe_cell_action = |unsafe_cell_ptr: Scalar, unsafe_cell_size: Size| { - let unsafe_cell_ptr = unsafe_cell_ptr.assert_ptr(); - debug_assert_eq!(unsafe_cell_ptr.alloc_id, end_ptr.alloc_id); - debug_assert_eq!(unsafe_cell_ptr.tag, end_ptr.tag); + // Calls `action` and advances `cur_ptr`. + let mut unsafe_cell_action = |unsafe_cell_ptr: Pointer>, + unsafe_cell_size: Size| { + let unsafe_cell_ptr = unsafe_cell_ptr.into_pointer_or_addr().unwrap(); + debug_assert_eq!(unsafe_cell_ptr.provenance, ptr.provenance); // We assume that we are given the fields in increasing offset order, // and nothing else changes. - let unsafe_cell_offset = unsafe_cell_ptr.offset; - let end_offset = end_ptr.offset; - assert!(unsafe_cell_offset >= end_offset); - let frozen_size = unsafe_cell_offset - end_offset; - // Everything between the end_ptr and this `UnsafeCell` is frozen. + let unsafe_cell_offset = unsafe_cell_ptr.into_parts().1 as Size; // we just compare offsets, the abs. value never matters + assert!(unsafe_cell_offset >= cur_offset); + let frozen_size = unsafe_cell_offset - cur_offset; + // Everything between the cur_ptr and this `UnsafeCell` is frozen. if frozen_size != Size::ZERO { - action(end_ptr, frozen_size, /*frozen*/ true)?; + action(alloc_range(cur_offset - start_offset, frozen_size), /*frozen*/ true)?; } + cur_offset += frozen_size; // This `UnsafeCell` is NOT frozen. if unsafe_cell_size != Size::ZERO { - action(unsafe_cell_ptr, unsafe_cell_size, /*frozen*/ false)?; + action( + alloc_range(cur_offset - start_offset, unsafe_cell_size), + /*frozen*/ false, + )?; } - // Update end end_ptr. - end_ptr = unsafe_cell_ptr.wrapping_offset(unsafe_cell_size, this); + cur_offset += unsafe_cell_size; // Done Ok(()) }; @@ -264,7 +263,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // The part between the end_ptr and the end of the place is also frozen. // So pretend there is a 0-sized `UnsafeCell` at the end. - unsafe_cell_action(place.ptr.ptr_wrapping_offset(size, this), Size::ZERO)?; + unsafe_cell_action(place.ptr.wrapping_offset(size, this), Size::ZERO)?; // Done! return Ok(()); @@ -347,7 +346,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Gather the subplaces and sort them before visiting. let mut places = fields.collect::>>>()?; - places.sort_by_key(|place| place.ptr.assert_ptr().offset); + // we just compare offsets, the abs. value never matters + places.sort_by_key(|place| { + place.ptr.into_pointer_or_addr().unwrap().into_parts().1 as Size + }); self.walk_aggregate(place, places.into_iter().map(Ok)) } FieldsShape::Union { .. } | FieldsShape::Primitive => { @@ -379,9 +381,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let mut offset = Size::from_bytes(0); for &imm in imms { - this.write_immediate_to_mplace( + this.write_immediate( *imm, - &place.offset(offset, MemPlaceMeta::None, imm.layout, &*this.tcx)?, + &place.offset(offset, MemPlaceMeta::None, imm.layout, &*this.tcx)?.into(), )?; offset += imm.layout.size; } @@ -567,12 +569,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// Parse a `timespec` struct and return it as a `std::time::Duration`. It returns `None` /// if the value in the `timespec` struct is invalid. Some libc functions will return /// `EINVAL` in this case. - fn read_timespec( - &mut self, - timespec_ptr_op: &OpTy<'tcx, Tag>, - ) -> InterpResult<'tcx, Option> { + fn read_timespec(&mut self, tp: &MPlaceTy<'tcx, Tag>) -> InterpResult<'tcx, Option> { let this = self.eval_context_mut(); - let tp = this.deref_operand(timespec_ptr_op)?; let seconds_place = this.mplace_field(&tp, 0)?; let seconds_scalar = this.read_scalar(&seconds_place.into())?; let seconds = seconds_scalar.to_machine_isize(this)?; @@ -593,14 +591,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx }) } - fn read_c_str<'a>(&'a self, sptr: Scalar) -> InterpResult<'tcx, &'a [u8]> + fn read_c_str<'a>(&'a self, ptr: Pointer>) -> InterpResult<'tcx, &'a [u8]> where 'tcx: 'a, 'mir: 'a, { let this = self.eval_context_ref(); let size1 = Size::from_bytes(1); - let ptr = this.force_ptr(sptr)?; // We need to read at least 1 byte, so we can eagerly get a ptr. // Step 1: determine the length. let mut len = Size::ZERO; @@ -620,12 +617,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.memory.read_bytes(ptr.into(), len) } - fn read_wide_str(&self, sptr: Scalar) -> InterpResult<'tcx, Vec> { + fn read_wide_str(&self, mut ptr: Pointer>) -> InterpResult<'tcx, Vec> { let this = self.eval_context_ref(); let size2 = Size::from_bytes(2); let align2 = Align::from_bytes(2).unwrap(); - let mut ptr = this.force_ptr(sptr)?; // We need to read at least 1 wchar, so we can eagerly get a ptr. let mut wchars = Vec::new(); loop { // FIXME: We are re-getting the allocation each time around the loop. @@ -709,6 +705,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx self.check_abi_and_shim_symbol_clash(abi, exp_abi, link_name)?; check_arg_count(args) } + + /// Mark a machine allocation that was just created as immutable. + fn mark_immutable(&mut self, mplace: &MemPlace) { + let this = self.eval_context_mut(); + this.memory + .mark_immutable(mplace.ptr.into_pointer_or_addr().unwrap().provenance.alloc_id) + .unwrap(); + } } /// Check that the number of args is what we expect. diff --git a/src/intptrcast.rs b/src/intptrcast.rs index b5a77b08ff52d..665a13418401d 100644 --- a/src/intptrcast.rs +++ b/src/intptrcast.rs @@ -38,55 +38,55 @@ impl Default for GlobalState { } impl<'mir, 'tcx> GlobalState { - pub fn int_to_ptr( - int: u64, + pub fn ptr_from_addr( + addr: u64, memory: &Memory<'mir, 'tcx, Evaluator<'mir, 'tcx>>, - ) -> InterpResult<'tcx, Pointer> { + ) -> Pointer> { + trace!("Casting 0x{:x} to a pointer", addr); let global_state = memory.extra.intptrcast.borrow(); - let pos = global_state.int_to_ptr_map.binary_search_by_key(&int, |(addr, _)| *addr); - - // The int must be in-bounds after being cast to a pointer, so we error - // with `CheckInAllocMsg::InboundsTest`. - Ok(match pos { - Ok(pos) => { - let (_, alloc_id) = global_state.int_to_ptr_map[pos]; - // `int` is equal to the starting address for an allocation, the offset should be - // zero. The pointer is untagged because it was created from a cast - Pointer::new_with_tag(alloc_id, Size::from_bytes(0), Tag::Untagged) - } - Err(0) => throw_ub!(DanglingIntPointer(int, CheckInAllocMsg::InboundsTest)), + let pos = global_state.int_to_ptr_map.binary_search_by_key(&addr, |(addr, _)| *addr); + + let alloc_id = match pos { + Ok(pos) => Some(global_state.int_to_ptr_map[pos].1), + Err(0) => None, Err(pos) => { // This is the largest of the adresses smaller than `int`, // i.e. the greatest lower bound (glb) let (glb, alloc_id) = global_state.int_to_ptr_map[pos - 1]; - // This never overflows because `int >= glb` - let offset = int - glb; - // If the offset exceeds the size of the allocation, this access is illegal - if offset <= memory.get_size_and_align(alloc_id, AllocCheck::MaybeDead)?.0.bytes() { - // This pointer is untagged because it was created from a cast - Pointer::new_with_tag(alloc_id, Size::from_bytes(offset), Tag::Untagged) + // This never overflows because `addr >= glb` + let offset = addr - glb; + // If the offset exceeds the size of the allocation, don't use this `alloc_id`. + if offset + <= memory.get_size_and_align(alloc_id, AllocCheck::MaybeDead).unwrap().0.bytes() + { + Some(alloc_id) } else { - throw_ub!(DanglingIntPointer(int, CheckInAllocMsg::InboundsTest)) + None } } - }) + }; + // Pointers created from integers are untagged. + Pointer::new( + alloc_id.map(|alloc_id| Tag { alloc_id, sb: SbTag::Untagged }), + Size::from_bytes(addr), + ) } - pub fn ptr_to_int( - ptr: Pointer, + fn alloc_base_addr( memory: &Memory<'mir, 'tcx, Evaluator<'mir, 'tcx>>, - ) -> InterpResult<'tcx, u64> { + alloc_id: AllocId, + ) -> u64 { let mut global_state = memory.extra.intptrcast.borrow_mut(); let global_state = &mut *global_state; - let id = ptr.alloc_id; - - // There is nothing wrong with a raw pointer being cast to an integer only after - // it became dangling. Hence `MaybeDead`. - let (size, align) = memory.get_size_and_align(id, AllocCheck::MaybeDead)?; - let base_addr = match global_state.base_addr.entry(id) { + match global_state.base_addr.entry(alloc_id) { Entry::Occupied(entry) => *entry.get(), Entry::Vacant(entry) => { + // There is nothing wrong with a raw pointer being cast to an integer only after + // it became dangling. Hence `MaybeDead`. + let (size, align) = + memory.get_size_and_align(alloc_id, AllocCheck::MaybeDead).unwrap(); + // This allocation does not have a base address yet, pick one. // Leave some space to the previous allocation, to give it some chance to be less aligned. let slack = { @@ -99,11 +99,12 @@ impl<'mir, 'tcx> GlobalState { let base_addr = Self::align_addr(base_addr, align.bytes()); entry.insert(base_addr); trace!( - "Assigning base address {:#x} to allocation {:?} (slack: {}, align: {})", + "Assigning base address {:#x} to allocation {:?} (size: {}, align: {}, slack: {})", base_addr, - id, - slack, + alloc_id, + size.bytes(), align.bytes(), + slack, ); // Remember next base address. If this allocation is zero-sized, leave a gap @@ -111,17 +112,37 @@ impl<'mir, 'tcx> GlobalState { global_state.next_base_addr = base_addr.checked_add(max(size.bytes(), 1)).unwrap(); // Given that `next_base_addr` increases in each allocation, pushing the // corresponding tuple keeps `int_to_ptr_map` sorted - global_state.int_to_ptr_map.push((base_addr, id)); + global_state.int_to_ptr_map.push((base_addr, alloc_id)); base_addr } - }; + } + } + + /// Convert a relative (tcx) pointer to an absolute address. + pub fn rel_ptr_to_addr( + memory: &Memory<'mir, 'tcx, Evaluator<'mir, 'tcx>>, + ptr: Pointer, + ) -> u64 { + let (alloc_id, offset) = ptr.into_parts(); // offset is relative + let base_addr = GlobalState::alloc_base_addr(memory, alloc_id); - // Sanity check that the base address is aligned. - debug_assert_eq!(base_addr % align.bytes(), 0); // Add offset with the right kind of pointer-overflowing arithmetic. let dl = memory.data_layout(); - Ok(dl.overflowing_offset(base_addr, ptr.offset.bytes()).0) + dl.overflowing_offset(base_addr, offset.bytes()).0 + } + + pub fn abs_ptr_to_rel( + memory: &Memory<'mir, 'tcx, Evaluator<'mir, 'tcx>>, + ptr: Pointer, + ) -> Size { + let (tag, addr) = ptr.into_parts(); // addr is absolute + let base_addr = GlobalState::alloc_base_addr(memory, tag.alloc_id); + + // Wrapping "addr - base_addr" + let dl = memory.data_layout(); + let neg_base_addr = (base_addr as i64).wrapping_neg(); + Size::from_bytes(dl.overflowing_signed_offset(addr.bytes(), neg_base_addr).0) } /// Shifts `addr` to make it aligned with `align` by rounding `addr` to the smallest multiple diff --git a/src/lib.rs b/src/lib.rs index 8c0a19b6dfbdc..f8d8aacce3c9e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -65,13 +65,14 @@ pub use crate::eval::{ pub use crate::helpers::EvalContextExt as HelpersEvalContextExt; pub use crate::machine::{ AllocExtra, Evaluator, FrameData, MemoryExtra, MiriEvalContext, MiriEvalContextExt, - MiriMemoryKind, NUM_CPUS, PAGE_SIZE, STACK_ADDR, STACK_SIZE, + MiriMemoryKind, Tag, NUM_CPUS, PAGE_SIZE, STACK_ADDR, STACK_SIZE, }; pub use crate::mono_hash_map::MonoHashMap; pub use crate::operator::EvalContextExt as OperatorEvalContextExt; pub use crate::range_map::RangeMap; pub use crate::stacked_borrows::{ - CallId, EvalContextExt as StackedBorEvalContextExt, Item, Permission, PtrId, Stack, Stacks, Tag, + CallId, EvalContextExt as StackedBorEvalContextExt, Item, Permission, PtrId, SbTag, Stack, + Stacks, }; pub use crate::sync::{CondvarId, EvalContextExt as SyncEvalContextExt, MutexId, RwLockId}; pub use crate::thread::{ diff --git a/src/machine.rs b/src/machine.rs index 999e21796d304..90e3d06aba99c 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -119,6 +119,35 @@ impl fmt::Display for MiriMemoryKind { } } +/// Pointer provenance (tag). +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct Tag { + pub alloc_id: AllocId, + // Stacked Borrows tag. + pub sb: SbTag, +} + +impl Provenance for Tag { + const OFFSET_IS_ADDR: bool = true; + + fn fmt(ptr: &Pointer, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let (tag, addr) = ptr.into_parts(); // address is absolute + write!(f, "0x{:x}", addr.bytes())?; + // Forward `alternate` flag to `alloc_id` printing. + if f.alternate() { + write!(f, "[{:#?}]", tag.alloc_id)?; + } else { + write!(f, "[{:?}]", tag.alloc_id)?; + } + // Print Stacked Borrows tag. + write!(f, "{:?}", tag.sb) + } + + fn get_alloc_id(self) -> AllocId { + self.alloc_id + } +} + /// Extra per-allocation data #[derive(Debug, Clone)] pub struct AllocExtra { @@ -136,8 +165,8 @@ pub struct MemoryExtra { pub data_race: Option, pub intptrcast: intptrcast::MemoryExtra, - /// Mapping extern static names to their canonical allocation. - extern_statics: FxHashMap, + /// Mapping extern static names to their base pointer. + extern_statics: FxHashMap>, /// The random number generator used for resolving non-determinism. /// Needs to be queried by ptr_to_int, hence needs interior mutability. @@ -183,11 +212,10 @@ impl MemoryExtra { fn add_extern_static<'tcx, 'mir>( this: &mut MiriEvalContext<'mir, 'tcx>, name: &str, - ptr: Scalar, + ptr: Pointer>, ) { - let ptr = ptr.assert_ptr(); - assert_eq!(ptr.offset, Size::ZERO); - this.memory.extra.extern_statics.try_insert(Symbol::intern(name), ptr.alloc_id).unwrap(); + let ptr = ptr.into_pointer_or_addr().unwrap(); + this.memory.extra.extern_statics.try_insert(Symbol::intern(name), ptr).unwrap(); } /// Sets up the "extern statics" for this machine. @@ -257,9 +285,9 @@ pub struct Evaluator<'mir, 'tcx> { /// Program arguments (`Option` because we can only initialize them after creating the ecx). /// These are *pointers* to argc/argv because macOS. /// We also need the full command line as one string because of Windows. - pub(crate) argc: Option>, - pub(crate) argv: Option>, - pub(crate) cmd_line: Option>, + pub(crate) argc: Option>, + pub(crate) argv: Option>, + pub(crate) cmd_line: Option>, /// TLS state. pub(crate) tls: TlsData<'tcx>, @@ -487,82 +515,107 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { Ok(()) } - fn thread_local_static_alloc_id( + fn thread_local_static_base_pointer( ecx: &mut InterpCx<'mir, 'tcx, Self>, def_id: DefId, - ) -> InterpResult<'tcx, AllocId> { - ecx.get_or_create_thread_local_alloc_id(def_id) + ) -> InterpResult<'tcx, Pointer> { + ecx.get_or_create_thread_local_alloc(def_id) } - fn extern_static_alloc_id( + fn extern_static_base_pointer( memory: &Memory<'mir, 'tcx, Self>, def_id: DefId, - ) -> InterpResult<'tcx, AllocId> { + ) -> InterpResult<'tcx, Pointer> { let attrs = memory.tcx.get_attrs(def_id); let link_name = match memory.tcx.sess.first_attr_value_str_by_name(&attrs, sym::link_name) { Some(name) => name, None => memory.tcx.item_name(def_id), }; - if let Some(&id) = memory.extra.extern_statics.get(&link_name) { - Ok(id) + if let Some(&ptr) = memory.extra.extern_statics.get(&link_name) { + Ok(ptr) } else { throw_unsup_format!("`extern` static {:?} is not supported by Miri", def_id) } } fn init_allocation_extra<'b>( - memory_extra: &MemoryExtra, + mem: &Memory<'mir, 'tcx, Self>, id: AllocId, alloc: Cow<'b, Allocation>, kind: Option>, - ) -> (Cow<'b, Allocation>, Self::PointerTag) { - if Some(id) == memory_extra.tracked_alloc_id { + ) -> Cow<'b, Allocation> { + if Some(id) == mem.extra.tracked_alloc_id { register_diagnostic(NonHaltingDiagnostic::CreatedAlloc(id)); } let kind = kind.expect("we set our STATIC_KIND so this cannot be None"); let alloc = alloc.into_owned(); - let (stacks, base_tag) = if let Some(stacked_borrows) = &memory_extra.stacked_borrows { - let (stacks, base_tag) = - Stacks::new_allocation(id, alloc.size(), stacked_borrows, kind); - (Some(stacks), base_tag) + let stacks = if let Some(stacked_borrows) = &mem.extra.stacked_borrows { + Some(Stacks::new_allocation(id, alloc.size(), stacked_borrows, kind)) } else { - // No stacks, no tag. - (None, Tag::Untagged) + None }; - let race_alloc = if let Some(data_race) = &memory_extra.data_race { + let race_alloc = if let Some(data_race) = &mem.extra.data_race { Some(data_race::AllocExtra::new_allocation(&data_race, alloc.size(), kind)) } else { None }; - let mut stacked_borrows = memory_extra.stacked_borrows.as_ref().map(|sb| sb.borrow_mut()); - let alloc: Allocation = alloc.with_tags_and_extra( - |alloc| { - if let Some(stacked_borrows) = &mut stacked_borrows { - // Only globals may already contain pointers at this point - assert_eq!(kind, MiriMemoryKind::Global.into()); - stacked_borrows.global_base_ptr(alloc) - } else { - Tag::Untagged - } - }, + let alloc: Allocation = alloc.convert_tag_add_extra( + &mem.tcx, AllocExtra { stacked_borrows: stacks, data_race: race_alloc }, + |ptr| Evaluator::tag_alloc_base_pointer(mem, ptr), ); - (Cow::Owned(alloc), base_tag) + Cow::Owned(alloc) + } + + fn tag_alloc_base_pointer( + mem: &Memory<'mir, 'tcx, Self>, + ptr: Pointer, + ) -> Pointer { + let absolute_addr = intptrcast::GlobalState::rel_ptr_to_addr(&mem, ptr); + let sb_tag = if let Some(stacked_borrows) = &mem.extra.stacked_borrows { + stacked_borrows.borrow_mut().base_tag(ptr.provenance) + } else { + SbTag::Untagged + }; + Pointer::new(Tag { alloc_id: ptr.provenance, sb: sb_tag }, Size::from_bytes(absolute_addr)) + } + + #[inline(always)] + fn ptr_from_addr( + mem: &Memory<'mir, 'tcx, Self>, + addr: u64, + ) -> Pointer> { + intptrcast::GlobalState::ptr_from_addr(addr, mem) + } + + /// Convert a pointer with provenance into an allocation-offset pair, + /// or a `None` with an absolute address if that conversion is not possible. + fn ptr_get_alloc( + mem: &Memory<'mir, 'tcx, Self>, + ptr: Pointer, + ) -> (AllocId, Size) { + let rel = intptrcast::GlobalState::abs_ptr_to_rel(mem, ptr); + (ptr.provenance.alloc_id, rel) } #[inline(always)] fn memory_read( memory_extra: &Self::MemoryExtra, alloc_extra: &AllocExtra, - ptr: Pointer, - size: Size, + tag: Tag, + range: AllocRange, ) -> InterpResult<'tcx> { if let Some(data_race) = &alloc_extra.data_race { - data_race.read(ptr, size, memory_extra.data_race.as_ref().unwrap())?; + data_race.read(tag.alloc_id, range, memory_extra.data_race.as_ref().unwrap())?; } if let Some(stacked_borrows) = &alloc_extra.stacked_borrows { - stacked_borrows.memory_read(ptr, size, memory_extra.stacked_borrows.as_ref().unwrap()) + stacked_borrows.memory_read( + tag.alloc_id, + tag.sb, + range, + memory_extra.stacked_borrows.as_ref().unwrap(), + ) } else { Ok(()) } @@ -572,16 +625,17 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { fn memory_written( memory_extra: &mut Self::MemoryExtra, alloc_extra: &mut AllocExtra, - ptr: Pointer, - size: Size, + tag: Tag, + range: AllocRange, ) -> InterpResult<'tcx> { if let Some(data_race) = &mut alloc_extra.data_race { - data_race.write(ptr, size, memory_extra.data_race.as_mut().unwrap())?; + data_race.write(tag.alloc_id, range, memory_extra.data_race.as_mut().unwrap())?; } if let Some(stacked_borrows) = &mut alloc_extra.stacked_borrows { stacked_borrows.memory_written( - ptr, - size, + tag.alloc_id, + tag.sb, + range, memory_extra.stacked_borrows.as_mut().unwrap(), ) } else { @@ -593,19 +647,20 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { fn memory_deallocated( memory_extra: &mut Self::MemoryExtra, alloc_extra: &mut AllocExtra, - ptr: Pointer, - size: Size, + tag: Tag, + range: AllocRange, ) -> InterpResult<'tcx> { - if Some(ptr.alloc_id) == memory_extra.tracked_alloc_id { - register_diagnostic(NonHaltingDiagnostic::FreedAlloc(ptr.alloc_id)); + if Some(tag.alloc_id) == memory_extra.tracked_alloc_id { + register_diagnostic(NonHaltingDiagnostic::FreedAlloc(tag.alloc_id)); } if let Some(data_race) = &mut alloc_extra.data_race { - data_race.deallocate(ptr, size, memory_extra.data_race.as_mut().unwrap())?; + data_race.deallocate(tag.alloc_id, range, memory_extra.data_race.as_mut().unwrap())?; } if let Some(stacked_borrows) = &mut alloc_extra.stacked_borrows { stacked_borrows.memory_deallocated( - ptr, - size, + tag.alloc_id, + tag.sb, + range, memory_extra.stacked_borrows.as_mut().unwrap(), ) } else { @@ -613,26 +668,6 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { } } - fn after_static_mem_initialized( - ecx: &mut InterpCx<'mir, 'tcx, Self>, - ptr: Pointer, - size: Size, - ) -> InterpResult<'tcx> { - if ecx.memory.extra.data_race.is_some() { - ecx.reset_vector_clocks(ptr, size)?; - } - Ok(()) - } - - #[inline(always)] - fn tag_global_base_pointer(memory_extra: &MemoryExtra, id: AllocId) -> Self::PointerTag { - if let Some(stacked_borrows) = &memory_extra.stacked_borrows { - stacked_borrows.borrow_mut().global_base_ptr(id) - } else { - Tag::Untagged - } - } - #[inline(always)] fn retag( ecx: &mut InterpCx<'mir, 'tcx, Self>, @@ -701,20 +736,4 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { } res } - - #[inline(always)] - fn int_to_ptr( - memory: &Memory<'mir, 'tcx, Self>, - int: u64, - ) -> InterpResult<'tcx, Pointer> { - intptrcast::GlobalState::int_to_ptr(int, memory) - } - - #[inline(always)] - fn ptr_to_int( - memory: &Memory<'mir, 'tcx, Self>, - ptr: Pointer, - ) -> InterpResult<'tcx, u64> { - intptrcast::GlobalState::ptr_to_int(ptr, memory) - } } diff --git a/src/mono_hash_map.rs b/src/mono_hash_map.rs index fb0169920ee28..1ae2083d5661c 100644 --- a/src/mono_hash_map.rs +++ b/src/mono_hash_map.rs @@ -72,15 +72,31 @@ impl AllocMap for MonoHashMap { /// returns owned data, that is put into the map and returned. #[inline(always)] fn get_or(&self, k: K, vacant: impl FnOnce() -> Result) -> Result<&V, E> { - let val: *const V = match self.0.borrow_mut().entry(k) { - Entry::Occupied(entry) => &**entry.get(), - Entry::Vacant(entry) => &**entry.insert(Box::new(vacant()?)), - }; + // We cannot hold borrow_mut while calling `vacant`, since that might have to do lookups in this very map. + if let Some(v) = self.0.borrow().get(&k) { + let val: *const V = &**v; + // This is safe because `val` points into a `Box`, that we know will not move and + // will also not be dropped as long as the shared reference `self` is live. + return unsafe { Ok(&*val) }; + } + let new_val = Box::new(vacant()?); + let val: *const V = &**self.0.borrow_mut().try_insert(k, new_val).ok().unwrap(); // This is safe because `val` points into a `Box`, that we know will not move and // will also not be dropped as long as the shared reference `self` is live. unsafe { Ok(&*val) } } + /// Read-only lookup (avoid read-acquiring the RefCell). + fn get(&self, k: K) -> Option<&V> { + let val: *const V = match self.0.borrow().get(&k) { + Some(v) => &**v, + None => return None, + }; + // This is safe because `val` points into a `Box`, that we know will not move and + // will also not be dropped as long as the shared reference `self` is live. + unsafe { Some(&*val) } + } + #[inline(always)] fn get_mut_or(&mut self, k: K, vacant: impl FnOnce() -> Result) -> Result<&mut V, E> { match self.0.get_mut().entry(k) { diff --git a/src/operator.rs b/src/operator.rs index cf92aed9ccb2c..59099469a3322 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -45,9 +45,8 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { Lt | Le | Gt | Ge => { // Just compare the integers. - // TODO: Do we really want to *always* do that, even when comparing two live in-bounds pointers? - let left = self.force_bits(left.to_scalar()?, left.layout.size)?; - let right = self.force_bits(right.to_scalar()?, right.layout.size)?; + let left = left.to_scalar()?.to_bits(left.layout.size)?; + let right = right.to_scalar()?.to_bits(right.layout.size)?; let res = match bin_op { Lt => left < right, Le => left <= right, @@ -62,11 +61,11 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { let pointee_ty = left.layout.ty.builtin_deref(true).expect("Offset called on non-ptr type").ty; let ptr = self.ptr_offset_inbounds( - left.to_scalar()?, + self.scalar_to_ptr(left.to_scalar()?), pointee_ty, right.to_scalar()?.to_machine_isize(self)?, )?; - (ptr, false, left.layout.ty) + (Scalar::from_maybe_pointer(ptr, self), false, left.layout.ty) } _ => bug!("Invalid operator on pointers: {:?}", bin_op), @@ -76,9 +75,8 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { fn ptr_eq(&self, left: Scalar, right: Scalar) -> InterpResult<'tcx, bool> { let size = self.pointer_size(); // Just compare the integers. - // TODO: Do we really want to *always* do that, even when comparing two live in-bounds pointers? - let left = self.force_bits(left, size)?; - let right = self.force_bits(right, size)?; + let left = left.to_bits(size)?; + let right = right.to_bits(size)?; Ok(left == right) } } diff --git a/src/shims/backtrace.rs b/src/shims/backtrace.rs index ec29fef6368fb..1ac3a22f7ed3d 100644 --- a/src/shims/backtrace.rs +++ b/src/shims/backtrace.rs @@ -44,9 +44,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // to reconstruct the needed frame information in `handle_miri_resolve_frame`. // Note that we never actually read or write anything from/to this pointer - // all of the data is represented by the pointer value itself. - let mut fn_ptr = this.memory.create_fn_alloc(FnVal::Instance(instance)); - fn_ptr.offset = Size::from_bytes(pos.0); - Scalar::Ptr(fn_ptr) + let fn_ptr = this.memory.create_fn_alloc(FnVal::Instance(instance)); + fn_ptr.wrapping_offset(Size::from_bytes(pos.0), this) }) .collect(); @@ -61,11 +60,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.allocate(this.layout_of(array_ty).unwrap(), MiriMemoryKind::Rust.into())?; for (i, ptr) in ptrs.into_iter().enumerate() { let place = this.mplace_index(&alloc, i as u64)?; - this.write_immediate_to_mplace(ptr.into(), &place)?; + this.write_pointer(ptr, &place.into())?; } this.write_immediate( - Immediate::new_slice(alloc.ptr.into(), len.try_into().unwrap(), this), + Immediate::new_slice( + Scalar::from_maybe_pointer(alloc.ptr, this), + len.try_into().unwrap(), + this, + ), dest, )?; Ok(()) @@ -87,21 +90,20 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx throw_unsup_format!("unknown `miri_resolve_frame` flags {}", flags); } - let ptr = this.force_ptr(this.read_scalar(ptr)?.check_init()?)?; + let ptr = this.read_pointer(ptr)?; + // Take apart the pointer, we need its pieces. + let (alloc_id, offset, ptr) = this.memory.ptr_get_alloc(ptr)?; - let fn_instance = if let Some(GlobalAlloc::Function(instance)) = - this.tcx.get_global_alloc(ptr.alloc_id) - { - instance - } else { - throw_ub_format!("expected function pointer, found {:?}", ptr); - }; + let fn_instance = + if let Some(GlobalAlloc::Function(instance)) = this.tcx.get_global_alloc(alloc_id) { + instance + } else { + throw_ub_format!("expected function pointer, found {:?}", ptr); + }; // Reconstruct the original function pointer, // which we pass to user code. - let mut fn_ptr = ptr; - fn_ptr.offset = Size::from_bytes(0); - let fn_ptr = Scalar::Ptr(fn_ptr); + let fn_ptr = this.memory.create_fn_alloc(FnVal::Instance(fn_instance)); let num_fields = dest.layout.layout.fields.count(); @@ -113,7 +115,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ); } - let pos = BytePos(ptr.offset.bytes().try_into().unwrap()); + let pos = BytePos(offset.bytes().try_into().unwrap()); let name = fn_instance.to_string(); let lo = tcx.sess.source_map().lookup_char_pos(pos); @@ -139,15 +141,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } - this.write_immediate(name_alloc.to_ref(), &this.mplace_field(&dest, 0)?.into())?; - this.write_immediate(filename_alloc.to_ref(), &this.mplace_field(&dest, 1)?.into())?; + this.write_immediate(name_alloc.to_ref(this), &this.mplace_field(&dest, 0)?.into())?; + this.write_immediate(filename_alloc.to_ref(this), &this.mplace_field(&dest, 1)?.into())?; this.write_scalar(lineno_alloc, &this.mplace_field(&dest, 2)?.into())?; this.write_scalar(colno_alloc, &this.mplace_field(&dest, 3)?.into())?; // Support a 4-field struct for now - this is deprecated // and slated for removal. if num_fields == 5 { - this.write_scalar(fn_ptr, &this.mplace_field(&dest, 4)?.into())?; + this.write_pointer(fn_ptr, &this.mplace_field(&dest, 4)?.into())?; } Ok(()) diff --git a/src/shims/env.rs b/src/shims/env.rs index 59322b91d6799..ddd2b61588981 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -28,7 +28,7 @@ fn windows_check_buffer_size((success, len): (bool, u64)) -> u32 { pub struct EnvVars<'tcx> { /// Stores pointers to the environment variables. These variables must be stored as /// null-terminated target strings (c_str or wide_str) with the `"{name}={value}"` format. - map: FxHashMap>, + map: FxHashMap>>, /// Place where the `environ` static is stored. Lazily initialized, but then never changes. pub(crate) environ: Option>, @@ -75,8 +75,8 @@ impl<'tcx> EnvVars<'tcx> { } // Deallocate environ var list. let environ = ecx.machine.env_vars.environ.unwrap(); - let old_vars_ptr = ecx.read_scalar(&environ.into())?.check_init()?; - ecx.memory.deallocate(ecx.force_ptr(old_vars_ptr)?, None, MiriMemoryKind::Env.into())?; + let old_vars_ptr = ecx.read_pointer(&environ.into())?; + ecx.memory.deallocate(old_vars_ptr, None, MiriMemoryKind::Env.into())?; Ok(()) } } @@ -85,7 +85,7 @@ fn alloc_env_var_as_c_str<'mir, 'tcx>( name: &OsStr, value: &OsStr, ecx: &mut InterpCx<'mir, 'tcx, Evaluator<'mir, 'tcx>>, -) -> InterpResult<'tcx, Pointer> { +) -> InterpResult<'tcx, Pointer>> { let mut name_osstring = name.to_os_string(); name_osstring.push("="); name_osstring.push(value); @@ -96,7 +96,7 @@ fn alloc_env_var_as_wide_str<'mir, 'tcx>( name: &OsStr, value: &OsStr, ecx: &mut InterpCx<'mir, 'tcx, Evaluator<'mir, 'tcx>>, -) -> InterpResult<'tcx, Pointer> { +) -> InterpResult<'tcx, Pointer>> { let mut name_osstring = name.to_os_string(); name_osstring.push("="); name_osstring.push(value); @@ -105,7 +105,7 @@ fn alloc_env_var_as_wide_str<'mir, 'tcx>( impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { - fn getenv(&mut self, name_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, Scalar> { + fn getenv(&mut self, name_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, Pointer>> { let this = self.eval_context_mut(); let target_os = &this.tcx.sess.target.os; assert!( @@ -113,17 +113,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "`getenv` is only available for the UNIX target family" ); - let name_ptr = this.read_scalar(name_op)?.check_init()?; + let name_ptr = this.read_pointer(name_op)?; let name = this.read_os_str_from_c_str(name_ptr)?; Ok(match this.machine.env_vars.map.get(name) { Some(var_ptr) => { // The offset is used to strip the "{name}=" part of the string. - Scalar::from(var_ptr.offset( + var_ptr.offset( Size::from_bytes(u64::try_from(name.len()).unwrap().checked_add(1).unwrap()), this, - )?) + )? } - None => Scalar::null_ptr(&*this.tcx), + None => Pointer::null(), }) } @@ -139,7 +139,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); this.assert_target_os("windows", "GetEnvironmentVariableW"); - let name_ptr = this.read_scalar(name_op)?.check_init()?; + let name_ptr = this.read_pointer(name_op)?; let name = this.read_os_str_from_wide_str(name_ptr)?; Ok(match this.machine.env_vars.map.get(&name) { Some(var_ptr) => { @@ -148,11 +148,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let name_offset_bytes = u64::try_from(name.len()).unwrap() .checked_add(1).unwrap() .checked_mul(2).unwrap(); - let var_ptr = - Scalar::from(var_ptr.offset(Size::from_bytes(name_offset_bytes), this)?); + let var_ptr = var_ptr.offset(Size::from_bytes(name_offset_bytes), this)?; let var = this.read_os_str_from_wide_str(var_ptr)?; - let buf_ptr = this.read_scalar(buf_op)?.check_init()?; + let buf_ptr = this.read_pointer(buf_op)?; // `buf_size` represents the size in characters. let buf_size = u64::from(this.read_scalar(size_op)?.to_u32()?); windows_check_buffer_size(this.write_os_str_to_wide_str(&var, buf_ptr, buf_size)?) @@ -166,7 +165,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } #[allow(non_snake_case)] - fn GetEnvironmentStringsW(&mut self) -> InterpResult<'tcx, Scalar> { + fn GetEnvironmentStringsW(&mut self) -> InterpResult<'tcx, Pointer>> { let this = self.eval_context_mut(); this.assert_target_os("windows", "GetEnvironmentStringsW"); @@ -174,7 +173,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // https://docs.microsoft.com/en-us/windows/win32/procthread/environment-variables let mut env_vars = std::ffi::OsString::new(); for &item in this.machine.env_vars.map.values() { - let env_var = this.read_os_str_from_wide_str(Scalar::from(item))?; + let env_var = this.read_os_str_from_wide_str(item)?; env_vars.push(env_var); env_vars.push("\0"); } @@ -182,7 +181,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Final null terminator(block terminator) is added by `alloc_os_str_to_wide_str`. let envblock_ptr = this.alloc_os_str_as_wide_str(&env_vars, MiriMemoryKind::Env.into())?; // If the function succeeds, the return value is a pointer to the environment block of the current process. - Ok(envblock_ptr.into()) + Ok(envblock_ptr) } #[allow(non_snake_case)] @@ -193,12 +192,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); this.assert_target_os("windows", "FreeEnvironmentStringsW"); - let env_block_ptr = this.read_scalar(env_block_op)?.check_init()?; - let result = this.memory.deallocate( - this.force_ptr(env_block_ptr)?, - None, - MiriMemoryKind::Env.into(), - ); + let env_block_ptr = this.read_pointer(env_block_op)?; + let result = this.memory.deallocate(env_block_ptr, None, MiriMemoryKind::Env.into()); // If the function succeeds, the return value is nonzero. Ok(result.is_ok() as i32) } @@ -215,11 +210,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "`setenv` is only available for the UNIX target family" ); - let name_ptr = this.read_scalar(name_op)?.check_init()?; - let value_ptr = this.read_scalar(value_op)?.check_init()?; + let name_ptr = this.read_pointer(name_op)?; + let value_ptr = this.read_pointer(value_op)?; let mut new = None; - if !this.is_null(name_ptr)? { + if !this.ptr_is_null(name_ptr)? { let name = this.read_os_str_from_c_str(name_ptr)?; if !name.is_empty() && !name.to_string_lossy().contains('=') { let value = this.read_os_str_from_c_str(value_ptr)?; @@ -250,10 +245,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let mut this = self.eval_context_mut(); this.assert_target_os("windows", "SetEnvironmentVariableW"); - let name_ptr = this.read_scalar(name_op)?.check_init()?; - let value_ptr = this.read_scalar(value_op)?.check_init()?; + let name_ptr = this.read_pointer(name_op)?; + let value_ptr = this.read_pointer(value_op)?; - if this.is_null(name_ptr)? { + if this.ptr_is_null(name_ptr)? { // ERROR CODE is not clearly explained in docs.. For now, throw UB instead. throw_ub_format!("pointer to environment variable name is NULL"); } @@ -263,7 +258,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx throw_unsup_format!("environment variable name is an empty string"); } else if name.to_string_lossy().contains('=') { throw_unsup_format!("environment variable name contains '='"); - } else if this.is_null(value_ptr)? { + } else if this.ptr_is_null(value_ptr)? { // Delete environment variable `{name}` if let Some(var) = this.machine.env_vars.map.remove(&name) { this.memory.deallocate(var, None, MiriMemoryKind::Env.into())?; @@ -289,9 +284,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "`unsetenv` is only available for the UNIX target family" ); - let name_ptr = this.read_scalar(name_op)?.check_init()?; + let name_ptr = this.read_pointer(name_op)?; let mut success = None; - if !this.is_null(name_ptr)? { + if !this.ptr_is_null(name_ptr)? { let name = this.read_os_str_from_c_str(name_ptr)?.to_owned(); if !name.is_empty() && !name.to_string_lossy().contains('=') { success = Some(this.machine.env_vars.map.remove(&name)); @@ -315,7 +310,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx &mut self, buf_op: &OpTy<'tcx, Tag>, size_op: &OpTy<'tcx, Tag>, - ) -> InterpResult<'tcx, Scalar> { + ) -> InterpResult<'tcx, Pointer>> { let this = self.eval_context_mut(); let target_os = &this.tcx.sess.target.os; assert!( @@ -323,14 +318,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "`getcwd` is only available for the UNIX target family" ); + let buf = this.read_pointer(&buf_op)?; + let size = this.read_scalar(&size_op)?.to_machine_usize(&*this.tcx)?; + if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { this.reject_in_isolation("getcwd", reject_with)?; this.set_last_error_from_io_error(ErrorKind::PermissionDenied)?; - return Ok(Scalar::null_ptr(&*this.tcx)); + return Ok(Pointer::null()); } - let buf = this.read_scalar(&buf_op)?.check_init()?; - let size = this.read_scalar(&size_op)?.to_machine_usize(&*this.tcx)?; // If we cannot get the current directory, we return null match env::current_dir() { Ok(cwd) => { @@ -343,7 +339,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Err(e) => this.set_last_error_from_io_error(e.kind())?, } - Ok(Scalar::null_ptr(&*this.tcx)) + Ok(Pointer::null()) } #[allow(non_snake_case)] @@ -355,15 +351,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); this.assert_target_os("windows", "GetCurrentDirectoryW"); + let size = u64::from(this.read_scalar(size_op)?.to_u32()?); + let buf = this.read_pointer(buf_op)?; + if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { this.reject_in_isolation("GetCurrentDirectoryW", reject_with)?; this.set_last_error_from_io_error(ErrorKind::PermissionDenied)?; return Ok(0); } - let size = u64::from(this.read_scalar(size_op)?.to_u32()?); - let buf = this.read_scalar(buf_op)?.check_init()?; - // If we cannot get the current directory, we return 0 match env::current_dir() { Ok(cwd) => @@ -381,6 +377,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "`getcwd` is only available for the UNIX target family" ); + let path = this.read_path_from_c_str(this.read_pointer(path_op)?)?; + if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { this.reject_in_isolation("chdir", reject_with)?; this.set_last_error_from_io_error(ErrorKind::PermissionDenied)?; @@ -388,8 +386,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx return Ok(-1); } - let path = this.read_path_from_c_str(this.read_scalar(path_op)?.check_init()?)?; - match env::set_current_dir(path) { Ok(()) => Ok(0), Err(e) => { @@ -409,6 +405,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); this.assert_target_os("windows", "SetCurrentDirectoryW"); + let path = this.read_path_from_wide_str(this.read_pointer(path_op)?)?; + if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { this.reject_in_isolation("SetCurrentDirectoryW", reject_with)?; this.set_last_error_from_io_error(ErrorKind::PermissionDenied)?; @@ -416,8 +414,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx return Ok(0); } - let path = this.read_path_from_wide_str(this.read_scalar(path_op)?.check_init()?)?; - match env::set_current_dir(path) { Ok(()) => Ok(1), Err(e) => { @@ -433,12 +429,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); // Deallocate the old environ list, if any. if let Some(environ) = this.machine.env_vars.environ { - let old_vars_ptr = this.read_scalar(&environ.into())?.check_init()?; - this.memory.deallocate( - this.force_ptr(old_vars_ptr)?, - None, - MiriMemoryKind::Env.into(), - )?; + let old_vars_ptr = this.read_pointer(&environ.into())?; + this.memory.deallocate(old_vars_ptr, None, MiriMemoryKind::Env.into())?; } else { // No `environ` allocated yet, let's do that. // This is memory backing an extern static, hence `ExternStatic`, not `Env`. @@ -448,10 +440,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // Collect all the pointers to each variable in a vector. - let mut vars: Vec> = - this.machine.env_vars.map.values().map(|&ptr| ptr.into()).collect(); + let mut vars: Vec>> = + this.machine.env_vars.map.values().copied().collect(); // Add the trailing null pointer. - vars.push(Scalar::null_ptr(this)); + vars.push(Pointer::null()); // Make an array with all these pointers inside Miri. let tcx = this.tcx; let vars_layout = @@ -459,9 +451,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let vars_place = this.allocate(vars_layout, MiriMemoryKind::Env.into())?; for (idx, var) in vars.into_iter().enumerate() { let place = this.mplace_field(&vars_place, idx)?; - this.write_scalar(var, &place.into())?; + this.write_pointer(var, &place.into())?; } - this.write_scalar(vars_place.ptr, &this.machine.env_vars.environ.unwrap().into())?; + this.write_pointer(vars_place.ptr, &this.machine.env_vars.environ.unwrap().into())?; Ok(()) } diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 61dca93f0ed49..35c151b72f60c 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -72,10 +72,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx size: u64, zero_init: bool, kind: MiriMemoryKind, - ) -> InterpResult<'tcx, Scalar> { + ) -> InterpResult<'tcx, Pointer>> { let this = self.eval_context_mut(); if size == 0 { - Ok(Scalar::null_ptr(this)) + Ok(Pointer::null()) } else { let align = this.min_align(size, kind); let ptr = this.memory.allocate(Size::from_bytes(size), align, kind.into())?; @@ -83,14 +83,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // We just allocated this, the access is definitely in-bounds. this.memory.write_bytes(ptr.into(), iter::repeat(0u8).take(size as usize)).unwrap(); } - Ok(Scalar::Ptr(ptr)) + Ok(ptr.into()) } } - fn free(&mut self, ptr: Scalar, kind: MiriMemoryKind) -> InterpResult<'tcx> { + fn free(&mut self, ptr: Pointer>, kind: MiriMemoryKind) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - if !this.is_null(ptr)? { - let ptr = this.force_ptr(ptr)?; + if !this.ptr_is_null(ptr)? { this.memory.deallocate(ptr, None, kind.into())?; } Ok(()) @@ -98,25 +97,24 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn realloc( &mut self, - old_ptr: Scalar, + old_ptr: Pointer>, new_size: u64, kind: MiriMemoryKind, - ) -> InterpResult<'tcx, Scalar> { + ) -> InterpResult<'tcx, Pointer>> { let this = self.eval_context_mut(); let new_align = this.min_align(new_size, kind); - if this.is_null(old_ptr)? { + if this.ptr_is_null(old_ptr)? { if new_size == 0 { - Ok(Scalar::null_ptr(this)) + Ok(Pointer::null()) } else { let new_ptr = this.memory.allocate(Size::from_bytes(new_size), new_align, kind.into())?; - Ok(Scalar::Ptr(new_ptr)) + Ok(new_ptr.into()) } } else { - let old_ptr = this.force_ptr(old_ptr)?; if new_size == 0 { this.memory.deallocate(old_ptr, None, kind.into())?; - Ok(Scalar::null_ptr(this)) + Ok(Pointer::null()) } else { let new_ptr = this.memory.reallocate( old_ptr, @@ -125,7 +123,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx new_align, kind.into(), )?; - Ok(Scalar::Ptr(new_ptr)) + Ok(new_ptr.into()) } } } @@ -313,12 +311,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Miri-specific extern functions "miri_static_root" => { let &[ref ptr] = this.check_shim(abi, Abi::Rust, link_name, args)?; - let ptr = this.read_scalar(ptr)?.check_init()?; - let ptr = this.force_ptr(ptr)?; - if ptr.offset != Size::ZERO { + let ptr = this.read_pointer(ptr)?; + let (alloc_id, offset, _) = this.memory.ptr_get_alloc(ptr)?; + if offset != Size::ZERO { throw_unsup_format!("pointer passed to miri_static_root must point to beginning of an allocated block"); } - this.machine.static_roots.push(ptr.alloc_id); + this.machine.static_roots.push(alloc_id); } // Obtains a Miri backtrace. See the README for details. @@ -339,7 +337,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let &[ref size] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let size = this.read_scalar(size)?.to_machine_usize(this)?; let res = this.malloc(size, /*zero_init:*/ false, MiriMemoryKind::C)?; - this.write_scalar(res, dest)?; + this.write_pointer(res, dest)?; } "calloc" => { let &[ref items, ref len] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; @@ -348,19 +346,19 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let size = items.checked_mul(len).ok_or_else(|| err_ub_format!("overflow during calloc size computation"))?; let res = this.malloc(size, /*zero_init:*/ true, MiriMemoryKind::C)?; - this.write_scalar(res, dest)?; + this.write_pointer(res, dest)?; } "free" => { let &[ref ptr] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; - let ptr = this.read_scalar(ptr)?.check_init()?; + let ptr = this.read_pointer(ptr)?; this.free(ptr, MiriMemoryKind::C)?; } "realloc" => { let &[ref old_ptr, ref new_size] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; - let old_ptr = this.read_scalar(old_ptr)?.check_init()?; + let old_ptr = this.read_pointer(old_ptr)?; let new_size = this.read_scalar(new_size)?.to_machine_usize(this)?; let res = this.realloc(old_ptr, new_size, MiriMemoryKind::C)?; - this.write_scalar(res, dest)?; + this.write_pointer(res, dest)?; } // Rust allocation @@ -376,7 +374,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Align::from_bytes(align).unwrap(), MiriMemoryKind::Rust.into(), )?; - this.write_scalar(ptr, dest)?; + this.write_pointer(ptr, dest)?; } "__rust_alloc_zeroed" => { let &[ref size, ref align] = this.check_shim(abi, Abi::Rust, link_name, args)?; @@ -390,15 +388,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx )?; // We just allocated this, the access is definitely in-bounds. this.memory.write_bytes(ptr.into(), iter::repeat(0u8).take(usize::try_from(size).unwrap())).unwrap(); - this.write_scalar(ptr, dest)?; + this.write_pointer(ptr, dest)?; } "__rust_dealloc" => { let &[ref ptr, ref old_size, ref align] = this.check_shim(abi, Abi::Rust, link_name, args)?; - let ptr = this.read_scalar(ptr)?.check_init()?; + let ptr = this.read_pointer(ptr)?; let old_size = this.read_scalar(old_size)?.to_machine_usize(this)?; let align = this.read_scalar(align)?.to_machine_usize(this)?; // No need to check old_size/align; we anyway check that they match the allocation. - let ptr = this.force_ptr(ptr)?; this.memory.deallocate( ptr, Some((Size::from_bytes(old_size), Align::from_bytes(align).unwrap())), @@ -407,7 +404,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "__rust_realloc" => { let &[ref ptr, ref old_size, ref align, ref new_size] = this.check_shim(abi, Abi::Rust, link_name, args)?; - let ptr = this.force_ptr(this.read_scalar(ptr)?.check_init()?)?; + let ptr = this.read_pointer(ptr)?; let old_size = this.read_scalar(old_size)?.to_machine_usize(this)?; let align = this.read_scalar(align)?.to_machine_usize(this)?; let new_size = this.read_scalar(new_size)?.to_machine_usize(this)?; @@ -421,14 +418,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx align, MiriMemoryKind::Rust.into(), )?; - this.write_scalar(new_ptr, dest)?; + this.write_pointer(new_ptr, dest)?; } // C memory handling functions "memcmp" => { let &[ref left, ref right, ref n] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; - let left = this.read_scalar(left)?.check_init()?; - let right = this.read_scalar(right)?.check_init()?; + let left = this.read_pointer(left)?; + let right = this.read_pointer(right)?; let n = Size::from_bytes(this.read_scalar(n)?.to_machine_usize(this)?); let result = { @@ -447,7 +444,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "memrchr" => { let &[ref ptr, ref val, ref num] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; - let ptr = this.read_scalar(ptr)?.check_init()?; + let ptr = this.read_pointer(ptr)?; let val = this.read_scalar(val)?.to_i32()? as u8; let num = this.read_scalar(num)?.to_machine_usize(this)?; if let Some(idx) = this @@ -457,15 +454,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx .rev() .position(|&c| c == val) { - let new_ptr = ptr.ptr_offset(Size::from_bytes(num - idx as u64 - 1), this)?; - this.write_scalar(new_ptr, dest)?; + let new_ptr = ptr.offset(Size::from_bytes(num - idx as u64 - 1), this)?; + this.write_pointer(new_ptr, dest)?; } else { this.write_null(dest)?; } } "memchr" => { let &[ref ptr, ref val, ref num] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; - let ptr = this.read_scalar(ptr)?.check_init()?; + let ptr = this.read_pointer(ptr)?; let val = this.read_scalar(val)?.to_i32()? as u8; let num = this.read_scalar(num)?.to_machine_usize(this)?; let idx = this @@ -474,15 +471,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx .iter() .position(|&c| c == val); if let Some(idx) = idx { - let new_ptr = ptr.ptr_offset(Size::from_bytes(idx as u64), this)?; - this.write_scalar(new_ptr, dest)?; + let new_ptr = ptr.offset(Size::from_bytes(idx as u64), this)?; + this.write_pointer(new_ptr, dest)?; } else { this.write_null(dest)?; } } "strlen" => { let &[ref ptr] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; - let ptr = this.read_scalar(ptr)?.check_init()?; + let ptr = this.read_pointer(ptr)?; let n = this.read_c_str(ptr)?.len(); this.write_scalar(Scalar::from_machine_usize(u64::try_from(n).unwrap(), this), dest)?; } diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index caef57df8dd28..5a3a782382dd5 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -71,7 +71,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let ty = instance.substs.type_at(0); let ty_layout = this.layout_of(ty)?; let val_byte = this.read_scalar(val_byte)?.to_u8()?; - let ptr = this.read_scalar(ptr)?.check_init()?; + let ptr = this.read_pointer(ptr)?; let count = this.read_scalar(count)?.to_machine_usize(this)?; let byte_count = ty_layout.size.checked_mul(count, this).ok_or_else(|| { err_ub_format!("overflow computing total size of `write_bytes`") diff --git a/src/shims/mod.rs b/src/shims/mod.rs index bb8d0bb8db909..b05fa76a934fc 100644 --- a/src/shims/mod.rs +++ b/src/shims/mod.rs @@ -74,8 +74,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx return Ok(false); } - let req_align = - this.force_bits(this.read_scalar(align_op)?.check_init()?, this.pointer_size())?; + let req_align = this.read_scalar(align_op)?.to_machine_usize(this)?; // Stop if the alignment is not a power of two. if !req_align.is_power_of_two() { @@ -83,13 +82,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx return Ok(true); // nothing left to do } - let ptr_scalar = this.read_scalar(ptr_op)?.check_init()?; - - if let Ok(ptr) = this.force_ptr(ptr_scalar) { + let ptr = this.read_pointer(ptr_op)?; + if let Ok(ptr) = ptr.into_pointer_or_addr() { // Only do anything if we can identify the allocation this goes to. - let cur_align = - this.memory.get_size_and_align(ptr.alloc_id, AllocCheck::MaybeDead)?.1.bytes(); - if u128::from(cur_align) >= req_align { + let (_, cur_align) = + this.memory.get_size_and_align(ptr.provenance.alloc_id, AllocCheck::MaybeDead)?; + if cur_align.bytes() >= req_align { // If the allocation alignment is at least the required alignment we use the // real implementation. return Ok(false); diff --git a/src/shims/os_str.rs b/src/shims/os_str.rs index ea99921c0b676..83bb344982c2a 100644 --- a/src/shims/os_str.rs +++ b/src/shims/os_str.rs @@ -50,19 +50,25 @@ impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mi pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { /// Helper function to read an OsString from a null-terminated sequence of bytes, which is what /// the Unix APIs usually handle. - fn read_os_str_from_c_str<'a>(&'a self, sptr: Scalar) -> InterpResult<'tcx, &'a OsStr> + fn read_os_str_from_c_str<'a>( + &'a self, + ptr: Pointer>, + ) -> InterpResult<'tcx, &'a OsStr> where 'tcx: 'a, 'mir: 'a, { let this = self.eval_context_ref(); - let bytes = this.read_c_str(sptr)?; + let bytes = this.read_c_str(ptr)?; bytes_to_os_str(bytes) } /// Helper function to read an OsString from a 0x0000-terminated sequence of u16, /// which is what the Windows APIs usually handle. - fn read_os_str_from_wide_str<'a>(&'a self, sptr: Scalar) -> InterpResult<'tcx, OsString> + fn read_os_str_from_wide_str<'a>( + &'a self, + ptr: Pointer>, + ) -> InterpResult<'tcx, OsString> where 'tcx: 'a, 'mir: 'a, @@ -78,7 +84,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(s.into()) } - let u16_vec = self.eval_context_ref().read_wide_str(sptr)?; + let u16_vec = self.eval_context_ref().read_wide_str(ptr)?; u16vec_to_osstring(u16_vec) } @@ -90,7 +96,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn write_os_str_to_c_str( &mut self, os_str: &OsStr, - sptr: Scalar, + ptr: Pointer>, size: u64, ) -> InterpResult<'tcx, (bool, u64)> { let bytes = os_str_to_bytes(os_str)?; @@ -102,7 +108,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } self.eval_context_mut() .memory - .write_bytes(sptr, bytes.iter().copied().chain(iter::once(0u8)))?; + .write_bytes(ptr, bytes.iter().copied().chain(iter::once(0u8)))?; Ok((true, string_length)) } @@ -114,7 +120,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn write_os_str_to_wide_str( &mut self, os_str: &OsStr, - sptr: Scalar, + ptr: Pointer>, size: u64, ) -> InterpResult<'tcx, (bool, u64)> { #[cfg(windows)] @@ -146,7 +152,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); let mut alloc = this .memory - .get_mut(sptr, size2 * string_length, Align::from_bytes(2).unwrap())? + .get_mut(ptr, size2 * string_length, Align::from_bytes(2).unwrap())? .unwrap(); // not a ZST, so we will get a result for (offset, wchar) in u16_vec.into_iter().chain(iter::once(0x0000)).enumerate() { let offset = u64::try_from(offset).unwrap(); @@ -161,14 +167,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx &mut self, os_str: &OsStr, memkind: MemoryKind, - ) -> InterpResult<'tcx, Pointer> { + ) -> InterpResult<'tcx, Pointer>> { let size = u64::try_from(os_str.len()).unwrap().checked_add(1).unwrap(); // Make space for `0` terminator. let this = self.eval_context_mut(); let arg_type = this.tcx.mk_array(this.tcx.types.u8, size); let arg_place = this.allocate(this.layout_of(arg_type).unwrap(), memkind)?; assert!(self.write_os_str_to_c_str(os_str, arg_place.ptr, size).unwrap().0); - Ok(arg_place.ptr.assert_ptr()) + Ok(arg_place.ptr) } /// Allocate enough memory to store the given `OsStr` as a null-terminated sequence of `u16`. @@ -176,24 +182,27 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx &mut self, os_str: &OsStr, memkind: MemoryKind, - ) -> InterpResult<'tcx, Pointer> { + ) -> InterpResult<'tcx, Pointer>> { let size = u64::try_from(os_str.len()).unwrap().checked_add(1).unwrap(); // Make space for `0x0000` terminator. let this = self.eval_context_mut(); let arg_type = this.tcx.mk_array(this.tcx.types.u16, size); let arg_place = this.allocate(this.layout_of(arg_type).unwrap(), memkind)?; assert!(self.write_os_str_to_wide_str(os_str, arg_place.ptr, size).unwrap().0); - Ok(arg_place.ptr.assert_ptr()) + Ok(arg_place.ptr) } /// Read a null-terminated sequence of bytes, and perform path separator conversion if needed. - fn read_path_from_c_str<'a>(&'a self, sptr: Scalar) -> InterpResult<'tcx, Cow<'a, Path>> + fn read_path_from_c_str<'a>( + &'a self, + ptr: Pointer>, + ) -> InterpResult<'tcx, Cow<'a, Path>> where 'tcx: 'a, 'mir: 'a, { let this = self.eval_context_ref(); - let os_str = this.read_os_str_from_c_str(sptr)?; + let os_str = this.read_os_str_from_c_str(ptr)?; Ok(match this.convert_path_separator(Cow::Borrowed(os_str), PathConversion::TargetToHost) { Cow::Borrowed(x) => Cow::Borrowed(Path::new(x)), @@ -202,9 +211,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } /// Read a null-terminated sequence of `u16`s, and perform path separator conversion if needed. - fn read_path_from_wide_str(&self, sptr: Scalar) -> InterpResult<'tcx, PathBuf> { + fn read_path_from_wide_str(&self, ptr: Pointer>) -> InterpResult<'tcx, PathBuf> { let this = self.eval_context_ref(); - let os_str = this.read_os_str_from_wide_str(sptr)?; + let os_str = this.read_os_str_from_wide_str(ptr)?; Ok(this .convert_path_separator(Cow::Owned(os_str), PathConversion::TargetToHost) @@ -217,13 +226,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn write_path_to_c_str( &mut self, path: &Path, - sptr: Scalar, + ptr: Pointer>, size: u64, ) -> InterpResult<'tcx, (bool, u64)> { let this = self.eval_context_mut(); let os_str = this .convert_path_separator(Cow::Borrowed(path.as_os_str()), PathConversion::HostToTarget); - this.write_os_str_to_c_str(&os_str, sptr, size) + this.write_os_str_to_c_str(&os_str, ptr, size) } /// Write a Path to the machine memory (as a null-terminated sequence of `u16`s), @@ -231,13 +240,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn write_path_to_wide_str( &mut self, path: &Path, - sptr: Scalar, + ptr: Pointer>, size: u64, ) -> InterpResult<'tcx, (bool, u64)> { let this = self.eval_context_mut(); let os_str = this .convert_path_separator(Cow::Borrowed(path.as_os_str()), PathConversion::HostToTarget); - this.write_os_str_to_wide_str(&os_str, sptr, size) + this.write_os_str_to_wide_str(&os_str, ptr, size) } fn convert_path_separator<'a>( diff --git a/src/shims/panic.rs b/src/shims/panic.rs index 68b648f32718a..04a8e9063f9ac 100644 --- a/src/shims/panic.rs +++ b/src/shims/panic.rs @@ -84,14 +84,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Get all the arguments. let &[ref try_fn, ref data, ref catch_fn] = check_arg_count(args)?; - let try_fn = this.read_scalar(try_fn)?.check_init()?; + let try_fn = this.read_pointer(try_fn)?; let data = this.read_scalar(data)?.check_init()?; let catch_fn = this.read_scalar(catch_fn)?.check_init()?; // Now we make a function call, and pass `data` as first and only argument. let f_instance = this.memory.get_fn(try_fn)?.as_instance()?; trace!("try_fn: {:?}", f_instance); - let ret_place = MPlaceTy::dangling(this.machine.layouts.unit, this).into(); + let ret_place = MPlaceTy::dangling(this.machine.layouts.unit).into(); this.call_function( f_instance, Abi::Rust, @@ -145,9 +145,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let payload = this.active_thread_mut().panic_payload.take().unwrap(); // Push the `catch_fn` stackframe. - let f_instance = this.memory.get_fn(catch_unwind.catch_fn)?.as_instance()?; + let f_instance = + this.memory.get_fn(this.scalar_to_ptr(catch_unwind.catch_fn))?.as_instance()?; trace!("catch_fn: {:?}", f_instance); - let ret_place = MPlaceTy::dangling(this.machine.layouts.unit, this).into(); + let ret_place = MPlaceTy::dangling(this.machine.layouts.unit).into(); this.call_function( f_instance, Abi::Rust, @@ -177,7 +178,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.call_function( panic, Abi::Rust, - &[msg.to_ref()], + &[msg.to_ref(this)], None, StackPopCleanup::Goto { ret: None, unwind }, ) diff --git a/src/shims/posix/foreign_items.rs b/src/shims/posix/foreign_items.rs index 1cfc3f0a4e79f..09dd7d9c7b869 100644 --- a/src/shims/posix/foreign_items.rs +++ b/src/shims/posix/foreign_items.rs @@ -28,7 +28,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "getenv" => { let &[ref name] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.getenv(name)?; - this.write_scalar(result, dest)?; + this.write_pointer(result, dest)?; } "unsetenv" => { let &[ref name] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; @@ -44,7 +44,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "getcwd" => { let &[ref buf, ref size] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.getcwd(buf, size)?; - this.write_scalar(result, dest)?; + this.write_pointer(result, dest)?; } "chdir" => { let &[ref path] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; @@ -68,7 +68,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "read" => { let &[ref fd, ref buf, ref count] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let fd = this.read_scalar(fd)?.to_i32()?; - let buf = this.read_scalar(buf)?.check_init()?; + let buf = this.read_pointer(buf)?; let count = this.read_scalar(count)?.to_machine_usize(this)?; let result = this.read(fd, buf, count)?; this.write_scalar(Scalar::from_machine_isize(result, this), dest)?; @@ -76,7 +76,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "write" => { let &[ref fd, ref buf, ref n] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let fd = this.read_scalar(fd)?.to_i32()?; - let buf = this.read_scalar(buf)?.check_init()?; + let buf = this.read_pointer(buf)?; let count = this.read_scalar(n)?.to_machine_usize(this)?; trace!("Called write({:?}, {:?}, {:?})", fd, buf, count); let result = this.write(fd, buf, count)?; @@ -160,7 +160,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Align::from_bytes(align).unwrap(), MiriMemoryKind::C.into(), )?; - this.write_scalar(ptr, &ret.into())?; + this.write_pointer(ptr, &ret.into())?; } this.write_null(dest)?; } @@ -169,11 +169,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "dlsym" => { let &[ref handle, ref symbol] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; this.read_scalar(handle)?.to_machine_usize(this)?; - let symbol = this.read_scalar(symbol)?.check_init()?; + let symbol = this.read_pointer(symbol)?; let symbol_name = this.read_c_str(symbol)?; if let Some(dlsym) = Dlsym::from_str(symbol_name, &this.tcx.sess.target.os)? { let ptr = this.memory.create_fn_alloc(FnVal::Other(dlsym)); - this.write_scalar(Scalar::from(ptr), dest)?; + this.write_pointer(ptr, dest)?; } else { this.write_null(dest)?; } @@ -208,12 +208,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "pthread_key_create" => { let &[ref key, ref dtor] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let key_place = this.deref_operand(key)?; - let dtor = this.read_scalar(dtor)?.check_init()?; + let dtor = this.read_pointer(dtor)?; // Extract the function type out of the signature (that seems easier than constructing it ourselves). - let dtor = match this.test_null(dtor)? { - Some(dtor_ptr) => Some(this.memory.get_fn(dtor_ptr)?.as_instance()?), - None => None, + let dtor = if !this.ptr_is_null(dtor)? { + Some(this.memory.get_fn(dtor)?.as_instance()?) + } else { + None }; // Figure out how large a pthread TLS key actually is. @@ -235,24 +236,24 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "pthread_key_delete" => { let &[ref key] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; - let key = this.force_bits(this.read_scalar(key)?.check_init()?, key.layout.size)?; + let key = this.read_scalar(key)?.check_init()?.to_bits(key.layout.size)?; this.machine.tls.delete_tls_key(key)?; // Return success (0) this.write_null(dest)?; } "pthread_getspecific" => { let &[ref key] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; - let key = this.force_bits(this.read_scalar(key)?.check_init()?, key.layout.size)?; + let key = this.read_scalar(key)?.check_init()?.to_bits(key.layout.size)?; let active_thread = this.get_active_thread(); let ptr = this.machine.tls.load_tls(key, active_thread, this)?; this.write_scalar(ptr, dest)?; } "pthread_setspecific" => { let &[ref key, ref new_ptr] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; - let key = this.force_bits(this.read_scalar(key)?.check_init()?, key.layout.size)?; + let key = this.read_scalar(key)?.check_init()?.to_bits(key.layout.size)?; let active_thread = this.get_active_thread(); - let new_ptr = this.read_scalar(new_ptr)?.check_init()?; - this.machine.tls.store_tls(key, active_thread, this.test_null(new_ptr)?)?; + let new_data = this.read_scalar(new_ptr)?; + this.machine.tls.store_tls(key, active_thread, new_data.check_init()?, &*this.tcx)?; // Return success (`0`). this.write_null(dest)?; @@ -412,9 +413,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "pthread_atfork" => { let &[ref prepare, ref parent, ref child] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; - this.force_bits(this.read_scalar(prepare)?.check_init()?, this.memory.pointer_size())?; - this.force_bits(this.read_scalar(parent)?.check_init()?, this.memory.pointer_size())?; - this.force_bits(this.read_scalar(child)?.check_init()?, this.memory.pointer_size())?; + this.read_pointer(prepare)?; + this.read_pointer(parent)?; + this.read_pointer(child)?; // We do not support forking, so there is nothing to do here. this.write_null(dest)?; } diff --git a/src/shims/posix/fs.rs b/src/shims/posix/fs.rs index bfc6195b3af33..a14a9c907eedc 100644 --- a/src/shims/posix/fs.rs +++ b/src/shims/posix/fs.rs @@ -17,7 +17,6 @@ use rustc_target::abi::{Align, LayoutOf, Size}; use crate::*; use helpers::{check_arg_count, immty_from_int_checked, immty_from_uint_checked}; use shims::time::system_time_to_duration; -use stacked_borrows::Tag; #[derive(Debug)] struct FileHandle { @@ -317,7 +316,7 @@ trait EvalContextExtPrivate<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, ' ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - let path_scalar = this.read_scalar(path_op)?.check_init()?; + let path_scalar = this.read_pointer(path_op)?; let path = this.read_path_from_c_str(path_scalar)?.into_owned(); let metadata = match FileMetadata::from_path(this, &path, follow_symlink)? { @@ -582,7 +581,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx throw_unsup_format!("unsupported flags {:#x}", flag & !mirror); } - let path = this.read_path_from_c_str(this.read_scalar(path_op)?.check_init()?)?; + let path = this.read_path_from_c_str(this.read_pointer(path_op)?)?; let fd = options.open(&path).map(|file| { let fh = &mut this.machine.file_handler; @@ -670,7 +669,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } - fn read(&mut self, fd: i32, buf: Scalar, count: u64) -> InterpResult<'tcx, i64> { + fn read(&mut self, fd: i32, buf: Pointer>, count: u64) -> InterpResult<'tcx, i64> { let this = self.eval_context_mut(); // Isolation check is done via `FileDescriptor` trait. @@ -718,7 +717,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } - fn write(&mut self, fd: i32, buf: Scalar, count: u64) -> InterpResult<'tcx, i64> { + fn write(&mut self, fd: i32, buf: Pointer>, count: u64) -> InterpResult<'tcx, i64> { let this = self.eval_context_mut(); // Isolation check is done via `FileDescriptor` trait. @@ -788,7 +787,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.check_no_isolation("`unlink`")?; - let path = this.read_path_from_c_str(this.read_scalar(path_op)?.check_init()?)?; + let path = this.read_path_from_c_str(this.read_pointer(path_op)?)?; let result = remove_file(path).map(|_| 0); this.try_unwrap_io_result(result) @@ -814,8 +813,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.check_no_isolation("`symlink`")?; - let target = this.read_path_from_c_str(this.read_scalar(target_op)?.check_init()?)?; - let linkpath = this.read_path_from_c_str(this.read_scalar(linkpath_op)?.check_init()?)?; + let target = this.read_path_from_c_str(this.read_pointer(target_op)?)?; + let linkpath = this.read_path_from_c_str(this.read_pointer(linkpath_op)?)?; let result = create_link(&target, &linkpath).map(|_| 0); this.try_unwrap_io_result(result) @@ -877,11 +876,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.assert_target_os("linux", "statx"); this.check_no_isolation("`statx`")?; - let statxbuf_scalar = this.read_scalar(statxbuf_op)?.check_init()?; - let pathname_scalar = this.read_scalar(pathname_op)?.check_init()?; + let statxbuf_ptr = this.read_pointer(statxbuf_op)?; + let pathname_ptr = this.read_pointer(pathname_op)?; // If the statxbuf or pathname pointers are null, the function fails with `EFAULT`. - if this.is_null(statxbuf_scalar)? || this.is_null(pathname_scalar)? { + if this.ptr_is_null(statxbuf_ptr)? || this.ptr_is_null(pathname_ptr)? { let efault = this.eval_libc("EFAULT")?; this.set_last_error(efault)?; return Ok(-1); @@ -898,13 +897,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let statx_ty = this .resolve_path(&["libc", "unix", "linux_like", "linux", "gnu", "statx"]) .ty(*this.tcx, ty::ParamEnv::reveal_all()); - let statxbuf_ty = this.tcx.mk_mut_ptr(statx_ty); - let statxbuf_layout = this.layout_of(statxbuf_ty)?; - let statxbuf_imm = ImmTy::from_scalar(statxbuf_scalar, statxbuf_layout); - this.ref_to_mplace(&statxbuf_imm)? + let statx_layout = this.layout_of(statx_ty)?; + MPlaceTy::from_aligned_ptr(statxbuf_ptr, statx_layout) }; - let path = this.read_path_from_c_str(pathname_scalar)?.into_owned(); + let path = this.read_path_from_c_str(pathname_ptr)?.into_owned(); // See for a discussion of argument sizes. let flags = this.read_scalar(flags_op)?.to_i32()?; let empty_path_flag = flags & this.eval_libc("AT_EMPTY_PATH")?.to_i32()? != 0; @@ -1037,17 +1034,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.check_no_isolation("`rename`")?; - let oldpath_scalar = this.read_scalar(oldpath_op)?.check_init()?; - let newpath_scalar = this.read_scalar(newpath_op)?.check_init()?; + let oldpath_ptr = this.read_pointer(oldpath_op)?; + let newpath_ptr = this.read_pointer(newpath_op)?; - if this.is_null(oldpath_scalar)? || this.is_null(newpath_scalar)? { + if this.ptr_is_null(oldpath_ptr)? || this.ptr_is_null(newpath_ptr)? { let efault = this.eval_libc("EFAULT")?; this.set_last_error(efault)?; return Ok(-1); } - let oldpath = this.read_path_from_c_str(oldpath_scalar)?; - let newpath = this.read_path_from_c_str(newpath_scalar)?; + let oldpath = this.read_path_from_c_str(oldpath_ptr)?; + let newpath = this.read_path_from_c_str(newpath_ptr)?; let result = rename(oldpath, newpath).map(|_| 0); @@ -1065,12 +1062,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx #[cfg_attr(not(unix), allow(unused_variables))] let mode = if this.tcx.sess.target.os == "macos" { - u32::from(this.read_scalar(mode_op)?.check_init()?.to_u16()?) + u32::from(this.read_scalar(mode_op)?.to_u16()?) } else { this.read_scalar(mode_op)?.to_u32()? }; - let path = this.read_path_from_c_str(this.read_scalar(path_op)?.check_init()?)?; + let path = this.read_path_from_c_str(this.read_pointer(path_op)?)?; #[cfg_attr(not(unix), allow(unused_mut))] let mut builder = DirBuilder::new(); @@ -1093,7 +1090,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.check_no_isolation("`rmdir`")?; - let path = this.read_path_from_c_str(this.read_scalar(path_op)?.check_init()?)?; + let path = this.read_path_from_c_str(this.read_pointer(path_op)?)?; let result = remove_dir(path).map(|_| 0i32); @@ -1105,7 +1102,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.check_no_isolation("`opendir`")?; - let name = this.read_path_from_c_str(this.read_scalar(name_op)?.check_init()?)?; + let name = this.read_path_from_c_str(this.read_pointer(name_op)?)?; let result = read_dir(name); @@ -1449,8 +1446,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.check_no_isolation("readlink")?; - let pathname = this.read_path_from_c_str(this.read_scalar(pathname_op)?.check_init()?)?; - let buf = this.read_scalar(buf_op)?.check_init()?; + let pathname = this.read_path_from_c_str(this.read_pointer(pathname_op)?)?; + let buf = this.read_pointer(buf_op)?; let bufsize = this.read_scalar(bufsize_op)?.to_machine_usize(this)?; let result = std::fs::read_link(pathname); diff --git a/src/shims/posix/linux/foreign_items.rs b/src/shims/posix/linux/foreign_items.rs index 1d551b9fa1ea7..0a9939fedd4cb 100644 --- a/src/shims/posix/linux/foreign_items.rs +++ b/src/shims/posix/linux/foreign_items.rs @@ -26,7 +26,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "__errno_location" => { let &[] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let errno_place = this.last_error_place()?; - this.write_scalar(errno_place.to_ref().to_scalar()?, dest)?; + this.write_scalar(errno_place.to_ref(this).to_scalar()?, dest)?; } // File related shims (but also see "syscall" below for statx) @@ -231,7 +231,7 @@ fn getrandom<'tcx>( flags: &OpTy<'tcx, Tag>, dest: &PlaceTy<'tcx, Tag>, ) -> InterpResult<'tcx> { - let ptr = this.read_scalar(ptr)?.check_init()?; + let ptr = this.read_pointer(ptr)?; let len = this.read_scalar(len)?.to_machine_usize(this)?; // The only supported flags are GRND_RANDOM and GRND_NONBLOCK, diff --git a/src/shims/posix/linux/sync.rs b/src/shims/posix/linux/sync.rs index fda70d815de21..17ddca879e684 100644 --- a/src/shims/posix/linux/sync.rs +++ b/src/shims/posix/linux/sync.rs @@ -31,13 +31,8 @@ pub fn futex<'tcx>( let op = this.read_scalar(&args[2])?.to_i32()?; let val = this.read_scalar(&args[3])?.to_i32()?; - // The raw pointer value is used to identify the mutex. - // Not all mutex operations actually read from this address or even require this address to exist. - // This will make FUTEX_WAKE fail on an integer cast to a pointer. But FUTEX_WAIT on - // such a pointer can never work anyway, so that seems fine. - let futex_ptr = this.force_ptr(addr.to_scalar()?)?; - let thread = this.get_active_thread(); + let addr_scalar = addr.to_scalar()?; let futex_private = this.eval_libc_i32("FUTEX_PRIVATE_FLAG")?; let futex_wait = this.eval_libc_i32("FUTEX_WAIT")?; @@ -57,14 +52,16 @@ pub fn futex<'tcx>( args.len() ); } - let timeout = &args[4]; - let timeout_time = if this.is_null(this.read_scalar(timeout)?.check_init()?)? { + + // `deref_operand` but not actually dereferencing the ptr yet (it might be NULL!). + let timeout = this.ref_to_mplace(&this.read_immediate(&args[4])?)?; + let timeout_time = if this.ptr_is_null(timeout.ptr)? { None } else { this.check_no_isolation( "`futex` syscall with `op=FUTEX_WAIT` and non-null timeout", )?; - let duration = match this.read_timespec(timeout)? { + let duration = match this.read_timespec(&timeout)? { Some(duration) => duration, None => { let einval = this.eval_libc("EINVAL")?; @@ -83,7 +80,7 @@ pub fn futex<'tcx>( // The API requires `addr` to be a 4-byte aligned pointer, and will // use the 4 bytes at the given address as an (atomic) i32. this.memory.check_ptr_access_align( - addr.to_scalar()?, + this.scalar_to_ptr(addr_scalar), Size::from_bytes(4), Align::from_bytes(4).unwrap(), CheckInAllocMsg::MemoryAccessTest, @@ -111,7 +108,7 @@ pub fn futex<'tcx>( if val == futex_val { // The value still matches, so we block the trait make it wait for FUTEX_WAKE. this.block_thread(thread); - this.futex_wait(futex_ptr, thread); + this.futex_wait(addr_scalar.to_machine_usize(this)?, thread); // Succesfully waking up from FUTEX_WAIT always returns zero. this.write_scalar(Scalar::from_machine_isize(0, this), dest)?; // Register a timeout callback if a timeout was specified. @@ -123,7 +120,7 @@ pub fn futex<'tcx>( timeout_time, Box::new(move |this| { this.unblock_thread(thread); - this.futex_remove_waiter(futex_ptr, thread); + this.futex_remove_waiter(addr_scalar.to_machine_usize(this)?, thread); let etimedout = this.eval_libc("ETIMEDOUT")?; this.set_last_error(etimedout)?; this.write_scalar(Scalar::from_machine_isize(-1, this), &dest)?; @@ -146,7 +143,7 @@ pub fn futex<'tcx>( op if op == futex_wake => { let mut n = 0; for _ in 0..val { - if let Some(thread) = this.futex_wake(futex_ptr) { + if let Some(thread) = this.futex_wake(addr_scalar.to_machine_usize(this)?) { this.unblock_thread(thread); this.unregister_timeout_callback_if_exists(thread); n += 1; diff --git a/src/shims/posix/macos/dlsym.rs b/src/shims/posix/macos/dlsym.rs index 7f3958797449c..d5996cc6a9ed1 100644 --- a/src/shims/posix/macos/dlsym.rs +++ b/src/shims/posix/macos/dlsym.rs @@ -37,7 +37,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx match dlsym { Dlsym::getentropy => { let &[ref ptr, ref len] = check_arg_count(args)?; - let ptr = this.read_scalar(ptr)?.check_init()?; + let ptr = this.read_pointer(ptr)?; let len = this.read_scalar(len)?.to_machine_usize(this)?; this.gen_random(ptr, len)?; this.write_null(dest)?; diff --git a/src/shims/posix/macos/foreign_items.rs b/src/shims/posix/macos/foreign_items.rs index 47a860b96a87a..2f79b337ce386 100644 --- a/src/shims/posix/macos/foreign_items.rs +++ b/src/shims/posix/macos/foreign_items.rs @@ -24,7 +24,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "__error" => { let &[] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let errno_place = this.last_error_place()?; - this.write_scalar(errno_place.to_ref().to_scalar()?, dest)?; + this.write_scalar(errno_place.to_ref(this).to_scalar()?, dest)?; } // File related shims @@ -74,7 +74,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Environment related shims "_NSGetEnviron" => { let &[] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; - this.write_scalar(this.machine.env_vars.environ.unwrap().ptr, dest)?; + this.write_pointer( + this.machine.env_vars.environ.expect("machine must be initialized").ptr, + dest, + )?; } // Time related shims @@ -100,18 +103,24 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Access to command-line arguments "_NSGetArgc" => { let &[] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; - this.write_scalar(this.machine.argc.expect("machine must be initialized"), dest)?; + this.write_pointer( + this.machine.argc.expect("machine must be initialized").ptr, + dest, + )?; } "_NSGetArgv" => { let &[] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; - this.write_scalar(this.machine.argv.expect("machine must be initialized"), dest)?; + this.write_pointer( + this.machine.argv.expect("machine must be initialized").ptr, + dest, + )?; } // Thread-local storage "_tlv_atexit" => { let &[ref dtor, ref data] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; - let dtor = this.read_scalar(dtor)?.check_init()?; + let dtor = this.read_pointer(dtor)?; let dtor = this.memory.get_fn(dtor)?.as_instance()?; let data = this.read_scalar(data)?.check_init()?; let active_thread = this.get_active_thread(); @@ -138,7 +147,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "pthread_setname_np" => { let &[ref name] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; - let name = this.read_scalar(name)?.check_init()?; + let name = this.read_pointer(name)?; this.pthread_setname_np(name)?; } diff --git a/src/shims/posix/sync.rs b/src/shims/posix/sync.rs index 4725cd9fc3c81..782765c7784bd 100644 --- a/src/shims/posix/sync.rs +++ b/src/shims/posix/sync.rs @@ -1,7 +1,6 @@ use std::time::SystemTime; use crate::*; -use stacked_borrows::Tag; use thread::Time; // pthread_mutexattr_t is either 4 or 8 bytes, depending on the platform. @@ -364,8 +363,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - let attr = this.read_scalar(attr_op)?.check_init()?; - let kind = if this.is_null(attr)? { + let attr = this.read_pointer(attr_op)?; + let kind = if this.ptr_is_null(attr)? { this.eval_libc("PTHREAD_MUTEX_DEFAULT")? } else { mutexattr_get_kind(this, attr_op)?.check_init()? @@ -657,8 +656,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - let attr = this.read_scalar(attr_op)?.check_init()?; - let clock_id = if this.is_null(attr)? { + let attr = this.read_pointer(attr_op)?; + let clock_id = if this.ptr_is_null(attr)? { this.eval_libc("CLOCK_REALTIME")? } else { condattr_get_clock_id(this, attr_op)?.check_init()? @@ -727,7 +726,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Extract the timeout. let clock_id = cond_get_clock_id(this, cond_op)?.to_i32()?; - let duration = match this.read_timespec(abstime_op)? { + let duration = match this.read_timespec(&this.deref_operand(abstime_op)?)? { Some(duration) => duration, None => { let einval = this.eval_libc("EINVAL")?; diff --git a/src/shims/posix/thread.rs b/src/shims/posix/thread.rs index ce1c817cf3ba0..9926c36c49ac4 100644 --- a/src/shims/posix/thread.rs +++ b/src/shims/posix/thread.rs @@ -33,7 +33,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Read the function argument that will be sent to the new thread // before the thread starts executing since reading after the // context switch will incorrectly report a data-race. - let fn_ptr = this.read_scalar(start_routine)?.check_init()?; + let fn_ptr = this.read_pointer(start_routine)?; let func_arg = this.read_immediate(arg)?; // Finally switch to new thread so that we can push the first stackframe. @@ -70,7 +70,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - if !this.is_null(this.read_scalar(retval)?.check_init()?)? { + if !this.ptr_is_null(this.read_pointer(retval)?)? { // FIXME: implement reading the thread function's return place. throw_unsup_format!("Miri supports pthread_join only with retval==NULL"); } @@ -110,7 +110,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let option = this.read_scalar(option)?.to_i32()?; if option == this.eval_libc_i32("PR_SET_NAME")? { - let address = this.read_scalar(arg2)?.check_init()?; + let address = this.read_pointer(arg2)?; let mut name = this.read_c_str(address)?.to_owned(); // The name should be no more than 16 bytes, including the null // byte. Since `read_c_str` returns the string without the null @@ -118,7 +118,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx name.truncate(15); this.set_active_thread_name(name); } else if option == this.eval_libc_i32("PR_GET_NAME")? { - let address = this.read_scalar(arg2)?.check_init()?; + let address = this.read_pointer(arg2)?; let mut name = this.get_active_thread_name().to_vec(); name.push(0u8); assert!(name.len() <= 16); @@ -130,7 +130,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(0) } - fn pthread_setname_np(&mut self, name: Scalar) -> InterpResult<'tcx> { + fn pthread_setname_np(&mut self, name: Pointer>) -> InterpResult<'tcx> { let this = self.eval_context_mut(); this.assert_target_os("macos", "pthread_setname_np"); diff --git a/src/shims/time.rs b/src/shims/time.rs index d293e4d127744..1db9d85debdc1 100644 --- a/src/shims/time.rs +++ b/src/shims/time.rs @@ -1,7 +1,6 @@ use std::convert::TryFrom; use std::time::{Duration, Instant, SystemTime}; -use crate::stacked_borrows::Tag; use crate::*; use helpers::{immty_from_int_checked, immty_from_uint_checked}; use thread::Time; @@ -63,8 +62,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.check_no_isolation("`gettimeofday`")?; // Using tz is obsolete and should always be null - let tz = this.read_scalar(tz_op)?.check_init()?; - if !this.is_null(tz)? { + let tz = this.read_pointer(tz_op)?; + if !this.ptr_is_null(tz)? { let einval = this.eval_libc("EINVAL")?; this.set_last_error(einval)?; return Ok(-1); @@ -206,7 +205,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.check_no_isolation("`nanosleep`")?; - let duration = match this.read_timespec(req_op)? { + let duration = match this.read_timespec(&this.deref_operand(req_op)?)? { Some(duration) => duration, None => { let einval = this.eval_libc("EINVAL")?; diff --git a/src/shims/tls.rs b/src/shims/tls.rs index 239364508e08f..cf8b8e3e1b887 100644 --- a/src/shims/tls.rs +++ b/src/shims/tls.rs @@ -109,19 +109,17 @@ impl<'tcx> TlsData<'tcx> { &mut self, key: TlsKey, thread_id: ThreadId, - new_data: Option>, + new_data: Scalar, + cx: &impl HasDataLayout, ) -> InterpResult<'tcx> { match self.keys.get_mut(&key) { Some(TlsEntry { data, .. }) => { - match new_data { - Some(scalar) => { - trace!("TLS key {} for thread {:?} stored: {:?}", key, thread_id, scalar); - data.insert(thread_id, scalar); - } - None => { - trace!("TLS key {} for thread {:?} removed", key, thread_id); - data.remove(&thread_id); - } + if new_data.to_machine_usize(cx)? != 0 { + trace!("TLS key {} for thread {:?} stored: {:?}", key, thread_id, new_data); + data.insert(thread_id, new_data); + } else { + trace!("TLS key {} for thread {:?} removed", key, thread_id); + data.remove(&thread_id); } Ok(()) } @@ -250,11 +248,12 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "thread_local_key", "p_thread_callback", ])?; - let thread_callback = this.memory.get_fn(thread_callback.check_init()?)?.as_instance()?; + let thread_callback = + this.memory.get_fn(this.scalar_to_ptr(thread_callback))?.as_instance()?; // The signature of this function is `unsafe extern "system" fn(h: c::LPVOID, dwReason: c::DWORD, pv: c::LPVOID)`. let reason = this.eval_path_scalar(&["std", "sys", "windows", "c", "DLL_THREAD_DETACH"])?; - let ret_place = MPlaceTy::dangling(this.machine.layouts.unit, this).into(); + let ret_place = MPlaceTy::dangling(this.machine.layouts.unit).into(); this.call_function( thread_callback, Abi::System { unwind: false }, @@ -277,7 +276,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if let Some((instance, data)) = this.machine.tls.macos_thread_dtors.remove(&thread_id) { trace!("Running macos dtor {:?} on {:?} at {:?}", instance, data, thread_id); - let ret_place = MPlaceTy::dangling(this.machine.layouts.unit, this).into(); + let ret_place = MPlaceTy::dangling(this.machine.layouts.unit).into(); this.call_function( instance, Abi::C { unwind: false }, @@ -315,9 +314,12 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.machine.tls.dtors_running.get_mut(&active_thread).unwrap().last_dtor_key = Some(key); trace!("Running TLS dtor {:?} on {:?} at {:?}", instance, ptr, active_thread); - assert!(!this.is_null(ptr).unwrap(), "data can't be NULL when dtor is called!"); + assert!( + !ptr.to_machine_usize(this).unwrap() != 0, + "data can't be NULL when dtor is called!" + ); - let ret_place = MPlaceTy::dangling(this.machine.layouts.unit, this).into(); + let ret_place = MPlaceTy::dangling(this.machine.layouts.unit).into(); this.call_function( instance, Abi::C { unwind: false }, @@ -349,6 +351,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn schedule_next_tls_dtor_for_active_thread(&mut self) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let active_thread = this.get_active_thread(); + trace!("schedule_next_tls_dtor_for_active_thread on thread {:?}", active_thread); if !this.machine.tls.set_dtors_running_for_thread(active_thread) { // This is the first time we got asked to schedule a destructor. The diff --git a/src/shims/windows/foreign_items.rs b/src/shims/windows/foreign_items.rs index b5324576273c9..0eebd6aca5bd4 100644 --- a/src/shims/windows/foreign_items.rs +++ b/src/shims/windows/foreign_items.rs @@ -43,7 +43,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "GetEnvironmentStringsW" => { let &[] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; let result = this.GetEnvironmentStringsW()?; - this.write_scalar(result, dest)?; + this.write_pointer(result, dest)?; } "FreeEnvironmentStringsW" => { let &[ref env_block] = @@ -78,7 +78,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; this.read_scalar(overlapped)?.to_machine_usize(this)?; // this is a poiner, that we ignore let handle = this.read_scalar(handle)?.to_machine_isize(this)?; - let buf = this.read_scalar(buf)?.check_init()?; + let buf = this.read_pointer(buf)?; let n = this.read_scalar(n)?.to_u32()?; let written_place = this.deref_operand(written_ptr)?; // Spec says to always write `0` first. @@ -116,14 +116,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let size = this.read_scalar(size)?.to_machine_usize(this)?; let zero_init = (flags & 0x00000008) != 0; // HEAP_ZERO_MEMORY let res = this.malloc(size, zero_init, MiriMemoryKind::WinHeap)?; - this.write_scalar(res, dest)?; + this.write_pointer(res, dest)?; } "HeapFree" => { let &[ref handle, ref flags, ref ptr] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; this.read_scalar(handle)?.to_machine_isize(this)?; this.read_scalar(flags)?.to_u32()?; - let ptr = this.read_scalar(ptr)?.check_init()?; + let ptr = this.read_pointer(ptr)?; this.free(ptr, MiriMemoryKind::WinHeap)?; this.write_scalar(Scalar::from_i32(1), dest)?; } @@ -132,10 +132,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; this.read_scalar(handle)?.to_machine_isize(this)?; this.read_scalar(flags)?.to_u32()?; - let ptr = this.read_scalar(ptr)?.check_init()?; + let ptr = this.read_pointer(ptr)?; let size = this.read_scalar(size)?.to_machine_usize(this)?; let res = this.realloc(ptr, size, MiriMemoryKind::WinHeap)?; - this.write_scalar(res, dest)?; + this.write_pointer(res, dest)?; } // errno @@ -189,8 +189,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; let key = u128::from(this.read_scalar(key)?.to_u32()?); let active_thread = this.get_active_thread(); - let new_ptr = this.read_scalar(new_ptr)?.check_init()?; - this.machine.tls.store_tls(key, active_thread, this.test_null(new_ptr)?)?; + let new_data = this.read_scalar(new_ptr)?.check_init()?; + this.machine.tls.store_tls(key, active_thread, new_data, &*this.tcx)?; // Return success (`1`). this.write_scalar(Scalar::from_i32(1), dest)?; @@ -199,8 +199,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Access to command-line arguments "GetCommandLineW" => { let &[] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; - this.write_scalar( - this.machine.cmd_line.expect("machine must be initialized"), + this.write_pointer( + this.machine.cmd_line.expect("machine must be initialized").ptr, dest, )?; } @@ -267,10 +267,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let &[ref hModule, ref lpProcName] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; this.read_scalar(hModule)?.to_machine_isize(this)?; - let name = this.read_c_str(this.read_scalar(lpProcName)?.check_init()?)?; + let name = this.read_c_str(this.read_pointer(lpProcName)?)?; if let Some(dlsym) = Dlsym::from_str(name, &this.tcx.sess.target.os)? { let ptr = this.memory.create_fn_alloc(FnVal::Other(dlsym)); - this.write_scalar(Scalar::from(ptr), dest)?; + this.write_pointer(ptr, dest)?; } else { this.write_null(dest)?; } @@ -281,7 +281,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // This is really 'RtlGenRandom'. let &[ref ptr, ref len] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; - let ptr = this.read_scalar(ptr)?.check_init()?; + let ptr = this.read_pointer(ptr)?; let len = this.read_scalar(len)?.to_u32()?; this.gen_random(ptr, len.into())?; this.write_scalar(Scalar::from_bool(true), dest)?; @@ -290,7 +290,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let &[ref algorithm, ref ptr, ref len, ref flags] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; let algorithm = this.read_scalar(algorithm)?; - let ptr = this.read_scalar(ptr)?.check_init()?; + let ptr = this.read_pointer(ptr)?; let len = this.read_scalar(len)?.to_u32()?; let flags = this.read_scalar(flags)?.to_u32()?; if flags != 2 { diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 0365e9ca00edd..ddfbfd426680a 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -10,7 +10,7 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_hir::Mutability; use rustc_middle::mir::RetagKind; use rustc_middle::ty; -use rustc_target::abi::{Align, LayoutOf, Size}; +use rustc_target::abi::{LayoutOf, Size}; use crate::*; @@ -20,16 +20,16 @@ pub type AllocExtra = Stacks; /// Tracking pointer provenance #[derive(Copy, Clone, Hash, PartialEq, Eq)] -pub enum Tag { +pub enum SbTag { Tagged(PtrId), Untagged, } -impl fmt::Debug for Tag { +impl fmt::Debug for SbTag { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { - Tag::Tagged(id) => write!(f, "<{}>", id), - Tag::Untagged => write!(f, ""), + SbTag::Tagged(id) => write!(f, "<{}>", id), + SbTag::Untagged => write!(f, ""), } } } @@ -54,7 +54,7 @@ pub struct Item { /// The permission this item grants. perm: Permission, /// The pointers the permission is granted to. - tag: Tag, + tag: SbTag, /// An optional protector, ensuring the item cannot get popped until `CallId` is over. protector: Option, } @@ -95,7 +95,7 @@ pub struct GlobalState { /// Table storing the "base" tag for each allocation. /// The base tag is the one used for the initial pointer. /// We need this in a separate table to handle cyclic statics. - base_ptr_ids: FxHashMap, + base_ptr_ids: FxHashMap, /// Next unused call ID (for protectors). next_call_id: CallId, /// Those call IDs corresponding to functions that are still running. @@ -197,14 +197,22 @@ impl GlobalState { self.active_calls.contains(&id) } - pub fn global_base_ptr(&mut self, id: AllocId) -> Tag { + pub fn base_tag(&mut self, id: AllocId) -> SbTag { self.base_ptr_ids.get(&id).copied().unwrap_or_else(|| { - let tag = Tag::Tagged(self.new_ptr()); + let tag = SbTag::Tagged(self.new_ptr()); trace!("New allocation {:?} has base tag {:?}", id, tag); self.base_ptr_ids.try_insert(id, tag).unwrap(); tag }) } + + pub fn base_tag_untagged(&mut self, id: AllocId) -> SbTag { + trace!("New allocation {:?} has no base tag (untagged)", id); + let tag = SbTag::Untagged; + // This must only be done on new allocations. + self.base_ptr_ids.try_insert(id, tag).unwrap(); + tag + } } /// Error reporting @@ -247,7 +255,7 @@ impl Permission { impl<'tcx> Stack { /// Find the item granting the given kind of access to the given tag, and return where /// it is on the stack. - fn find_granting(&self, access: AccessKind, tag: Tag) -> Option { + fn find_granting(&self, access: AccessKind, tag: SbTag) -> Option { self.borrows .iter() .enumerate() // we also need to know *where* in the stack @@ -288,8 +296,12 @@ impl<'tcx> Stack { } /// Check if the given item is protected. - fn check_protector(item: &Item, tag: Option, global: &GlobalState) -> InterpResult<'tcx> { - if let Tag::Tagged(id) = item.tag { + fn check_protector( + item: &Item, + tag: Option, + global: &GlobalState, + ) -> InterpResult<'tcx> { + if let SbTag::Tagged(id) = item.tag { if Some(id) == global.tracked_pointer_tag { register_diagnostic(NonHaltingDiagnostic::PoppedPointerTag(item.clone())); } @@ -314,18 +326,17 @@ impl<'tcx> Stack { fn access( &mut self, access: AccessKind, - ptr: Pointer, + tag: SbTag, + dbg_ptr: Pointer, // just for debug printing amd error messages global: &GlobalState, ) -> InterpResult<'tcx> { // Two main steps: Find granting item, remove incompatible items above. // Step 1: Find granting item. - let granting_idx = self.find_granting(access, ptr.tag).ok_or_else(|| { + let granting_idx = self.find_granting(access, tag).ok_or_else(|| { err_sb_ub(format!( - "no item granting {} to tag {:?} at {} found in borrow stack.", - access, - ptr.tag, - ptr.erase_tag(), + "no item granting {} to tag {:?} at {:?} found in borrow stack.", + access, tag, dbg_ptr, )) })?; @@ -337,7 +348,7 @@ impl<'tcx> Stack { let first_incompatible_idx = self.find_first_write_incompatible(granting_idx); for item in self.borrows.drain(first_incompatible_idx..).rev() { trace!("access: popping item {:?}", item); - Stack::check_protector(&item, Some(ptr.tag), global)?; + Stack::check_protector(&item, Some(tag), global)?; } } else { // On a read, *disable* all `Unique` above the granting item. This ensures U2 for read accesses. @@ -352,7 +363,7 @@ impl<'tcx> Stack { let item = &mut self.borrows[idx]; if item.perm == Permission::Unique { trace!("access: disabling item {:?}", item); - Stack::check_protector(item, Some(ptr.tag), global)?; + Stack::check_protector(item, Some(tag), global)?; item.perm = Permission::Disabled; } } @@ -364,12 +375,17 @@ impl<'tcx> Stack { /// Deallocate a location: Like a write access, but also there must be no /// active protectors at all because we will remove all items. - fn dealloc(&mut self, ptr: Pointer, global: &GlobalState) -> InterpResult<'tcx> { + fn dealloc( + &mut self, + tag: SbTag, + dbg_ptr: Pointer, // just for debug printing amd error messages + global: &GlobalState, + ) -> InterpResult<'tcx> { // Step 1: Find granting item. - self.find_granting(AccessKind::Write, ptr.tag).ok_or_else(|| { + self.find_granting(AccessKind::Write, tag).ok_or_else(|| { err_sb_ub(format!( - "no item granting write access for deallocation to tag {:?} at {} found in borrow stack", - ptr.tag, ptr.erase_tag(), + "no item granting write access for deallocation to tag {:?} at {:?} found in borrow stack", + tag, dbg_ptr, )) })?; @@ -387,8 +403,9 @@ impl<'tcx> Stack { /// from instead of all the way at the top of the stack. fn grant( &mut self, - derived_from: Pointer, + derived_from: SbTag, new: Item, + dbg_ptr: Pointer, global: &GlobalState, ) -> InterpResult<'tcx> { // Figure out which access `perm` corresponds to. @@ -396,10 +413,10 @@ impl<'tcx> Stack { if new.perm.grants(AccessKind::Write) { AccessKind::Write } else { AccessKind::Read }; // Now we figure out which item grants our parent (`derived_from`) this kind of access. // We use that to determine where to put the new item. - let granting_idx = self.find_granting(access, derived_from.tag) + let granting_idx = self.find_granting(access, derived_from) .ok_or_else(|| err_sb_ub(format!( - "trying to reborrow for {:?} at {}, but parent tag {:?} does not have an appropriate item in the borrow stack", - new.perm, derived_from.erase_tag(), derived_from.tag, + "trying to reborrow for {:?} at {:?}, but parent tag {:?} does not have an appropriate item in the borrow stack", + new.perm, dbg_ptr, derived_from, )))?; // Compute where to put the new item. @@ -419,7 +436,7 @@ impl<'tcx> Stack { // A "safe" reborrow for a pointer that actually expects some aliasing guarantees. // Here, creating a reference actually counts as an access. // This ensures F2b for `Unique`, by removing offending `SharedReadOnly`. - self.access(access, derived_from, global)?; + self.access(access, derived_from, dbg_ptr, global)?; // We insert "as far up as possible": We know only compatible items are remaining // on top of `derived_from`, and we want the new item at the top so that we @@ -445,7 +462,7 @@ impl<'tcx> Stack { /// Map per-stack operations to higher-level per-location-range operations. impl<'tcx> Stacks { /// Creates new stack with initial tag. - fn new(size: Size, perm: Permission, tag: Tag) -> Self { + fn new(size: Size, perm: Permission, tag: SbTag) -> Self { let item = Item { perm, tag, protector: None }; let stack = Stack { borrows: vec![item] }; @@ -455,15 +472,12 @@ impl<'tcx> Stacks { /// Call `f` on every stack in the range. fn for_each( &self, - ptr: Pointer, - size: Size, - f: impl Fn(Pointer, &mut Stack) -> InterpResult<'tcx>, + range: AllocRange, + f: impl Fn(Size, &mut Stack) -> InterpResult<'tcx>, ) -> InterpResult<'tcx> { let mut stacks = self.stacks.borrow_mut(); - for (offset, stack) in stacks.iter_mut(ptr.offset, size) { - let mut cur_ptr = ptr; - cur_ptr.offset = offset; - f(cur_ptr, stack)?; + for (offset, stack) in stacks.iter_mut(range.start, range.size) { + f(offset, stack)?; } Ok(()) } @@ -471,15 +485,12 @@ impl<'tcx> Stacks { /// Call `f` on every stack in the range. fn for_each_mut( &mut self, - ptr: Pointer, - size: Size, - f: impl Fn(Pointer, &mut Stack) -> InterpResult<'tcx>, + range: AllocRange, + f: impl Fn(Size, &mut Stack) -> InterpResult<'tcx>, ) -> InterpResult<'tcx> { let stacks = self.stacks.get_mut(); - for (offset, stack) in stacks.iter_mut(ptr.offset, size) { - let mut cur_ptr = ptr; - cur_ptr.offset = offset; - f(cur_ptr, stack)?; + for (offset, stack) in stacks.iter_mut(range.start, range.size) { + f(offset, stack)?; } Ok(()) } @@ -492,15 +503,15 @@ impl Stacks { size: Size, extra: &MemoryExtra, kind: MemoryKind, - ) -> (Self, Tag) { + ) -> Self { let mut extra = extra.borrow_mut(); - let (tag, perm) = match kind { + let (base_tag, perm) = match kind { // New unique borrow. This tag is not accessible by the program, // so it will only ever be used when using the local directly (i.e., // not through a pointer). That is, whenever we directly write to a local, this will pop // everything else off the stack, invalidating all previous pointers, // and in particular, *all* raw pointers. - MemoryKind::Stack => (Tag::Tagged(extra.new_ptr()), Permission::Unique), + MemoryKind::Stack => (extra.base_tag(id), Permission::Unique), // `Global` memory can be referenced by global pointers from `tcx`. // Thus we call `global_base_ptr` such that the global pointers get the same tag // as what we use here. @@ -515,53 +526,72 @@ impl Stacks { | MiriMemoryKind::Tls | MiriMemoryKind::Env | MiriMemoryKind::Machine, - ) => (extra.global_base_ptr(id), Permission::SharedReadWrite), + ) => (extra.base_tag(id), Permission::SharedReadWrite), // Heap allocations we only track precisely when raw pointers are tagged, for now. MemoryKind::Machine( MiriMemoryKind::Rust | MiriMemoryKind::C | MiriMemoryKind::WinHeap, ) => { let tag = - if extra.track_raw { Tag::Tagged(extra.new_ptr()) } else { Tag::Untagged }; + if extra.track_raw { extra.base_tag(id) } else { extra.base_tag_untagged(id) }; (tag, Permission::SharedReadWrite) } }; - (Stacks::new(size, perm, tag), tag) + Stacks::new(size, perm, base_tag) } #[inline(always)] pub fn memory_read<'tcx>( &self, - ptr: Pointer, - size: Size, + alloc_id: AllocId, + tag: SbTag, + range: AllocRange, extra: &MemoryExtra, ) -> InterpResult<'tcx> { - trace!("read access with tag {:?}: {:?}, size {}", ptr.tag, ptr.erase_tag(), size.bytes()); + trace!( + "read access with tag {:?}: {:?}, size {}", + tag, + Pointer::new(alloc_id, range.start), + range.size.bytes() + ); let global = &*extra.borrow(); - self.for_each(ptr, size, move |ptr, stack| stack.access(AccessKind::Read, ptr, global)) + self.for_each(range, move |offset, stack| { + stack.access(AccessKind::Read, tag, Pointer::new(alloc_id, offset), global) + }) } #[inline(always)] pub fn memory_written<'tcx>( &mut self, - ptr: Pointer, - size: Size, + alloc_id: AllocId, + tag: SbTag, + range: AllocRange, extra: &mut MemoryExtra, ) -> InterpResult<'tcx> { - trace!("write access with tag {:?}: {:?}, size {}", ptr.tag, ptr.erase_tag(), size.bytes()); + trace!( + "write access with tag {:?}: {:?}, size {}", + tag, + Pointer::new(alloc_id, range.start), + range.size.bytes() + ); let global = extra.get_mut(); - self.for_each_mut(ptr, size, move |ptr, stack| stack.access(AccessKind::Write, ptr, global)) + self.for_each_mut(range, move |offset, stack| { + stack.access(AccessKind::Write, tag, Pointer::new(alloc_id, offset), global) + }) } #[inline(always)] pub fn memory_deallocated<'tcx>( &mut self, - ptr: Pointer, - size: Size, + alloc_id: AllocId, + tag: SbTag, + range: AllocRange, extra: &mut MemoryExtra, ) -> InterpResult<'tcx> { - trace!("deallocation with tag {:?}: {:?}, size {}", ptr.tag, ptr.erase_tag(), size.bytes()); + trace!("deallocation with tag {:?}: {:?}, size {}", tag, alloc_id, range.size.bytes()); let global = extra.get_mut(); - self.for_each_mut(ptr, size, move |ptr, stack| stack.dealloc(ptr, global)) + self.for_each_mut(range, move |offset, stack| { + stack.dealloc(tag, Pointer::new(alloc_id, offset), global) + }) } } @@ -574,11 +604,12 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx place: &MPlaceTy<'tcx, Tag>, size: Size, kind: RefKind, - new_tag: Tag, + new_tag: SbTag, protect: bool, ) -> InterpResult<'tcx> { - // Nothing to do for ZSTs. + let this = self.eval_context_mut(); if size == Size::ZERO { + // Nothing to do for zero-sized accesses. trace!( "reborrow of size 0: {} reference {:?} derived from {:?} (pointee {})", kind, @@ -588,17 +619,30 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ); return Ok(()); } + let (alloc_id, base_offset, ptr) = this.memory.ptr_get_alloc(place.ptr)?; + let orig_tag = ptr.provenance.sb; + + // Ensure we bail out if the pointer goes out-of-bounds (see miri#1050). + let (allocation_size, _) = + this.memory.get_size_and_align(alloc_id, AllocCheck::Dereferenceable)?; + if base_offset + size > allocation_size { + throw_ub!(PointerOutOfBounds { + alloc_id, + offset: base_offset, + size, + allocation_size, + msg: CheckInAllocMsg::InboundsTest + }); + } - let this = self.eval_context_mut(); let protector = if protect { Some(this.frame().extra.call_id) } else { None }; - let ptr = place.ptr.assert_ptr(); trace!( "reborrow: {} reference {:?} derived from {:?} (pointee {}): {:?}, size {}", kind, new_tag, - ptr.tag, + orig_tag, place.layout.ty, - ptr.erase_tag(), + Pointer::new(alloc_id, base_offset), size.bytes() ); @@ -615,11 +659,13 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // We need a frozen-sensitive reborrow. // We have to use shared references to alloc/memory_extra here since // `visit_freeze_sensitive` needs to access the global state. - let extra = this.memory.get_alloc_extra(ptr.alloc_id)?; + let extra = this.memory.get_alloc_extra(alloc_id)?; let stacked_borrows = extra.stacked_borrows.as_ref().expect("we should have Stacked Borrows data"); let global = this.memory.extra.stacked_borrows.as_ref().unwrap().borrow(); - return this.visit_freeze_sensitive(place, size, |cur_ptr, size, frozen| { + this.visit_freeze_sensitive(place, size, |mut range, frozen| { + // Adjust range. + range.start += base_offset; // We are only ever `SharedReadOnly` inside the frozen bits. let perm = if frozen { Permission::SharedReadOnly @@ -627,21 +673,25 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Permission::SharedReadWrite }; let item = Item { perm, tag: new_tag, protector }; - stacked_borrows.for_each(cur_ptr, size, |cur_ptr, stack| { - stack.grant(cur_ptr, item, &*global) + stacked_borrows.for_each(range, |offset, stack| { + stack.grant(orig_tag, item, Pointer::new(alloc_id, offset), &*global) }) - }); + })?; + return Ok(()); } }; // Here we can avoid `borrow()` calls because we have mutable references. // Note that this asserts that the allocation is mutable -- but since we are creating a // mutable pointer, that seems reasonable. - let (alloc_extra, memory_extra) = this.memory.get_alloc_extra_mut(ptr.alloc_id)?; + let (alloc_extra, memory_extra) = this.memory.get_alloc_extra_mut(alloc_id)?; let stacked_borrows = alloc_extra.stacked_borrows.as_mut().expect("we should have Stacked Borrows data"); let global = memory_extra.stacked_borrows.as_mut().unwrap().get_mut(); let item = Item { perm, tag: new_tag, protector }; - stacked_borrows.for_each_mut(ptr, size, |ptr, stack| stack.grant(ptr, item, global)) + stacked_borrows.for_each_mut(alloc_range(base_offset, size), |offset, stack| { + stack.grant(orig_tag, item, Pointer::new(alloc_id, offset), global) + })?; + Ok(()) } /// Retags an indidual pointer, returning the retagged version. @@ -663,29 +713,26 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Some(size) => size, None => return Ok(*val), }; - // `reborrow` relies on getting a `Pointer` and everything being in-bounds, - // so let's ensure that. However, we do not care about alignment. - // We can see dangling ptrs in here e.g. after a Box's `Unique` was - // updated using "self.0 = ..." (can happen in Box::from_raw) so we cannot ICE; see miri#1050. - let place = this.mplace_access_checked(place, Some(Align::from_bytes(1).unwrap()))?; // Compute new borrow. let new_tag = { let mem_extra = this.memory.extra.stacked_borrows.as_mut().unwrap().get_mut(); match kind { // Give up tracking for raw pointers. - RefKind::Raw { .. } if !mem_extra.track_raw => Tag::Untagged, + RefKind::Raw { .. } if !mem_extra.track_raw => SbTag::Untagged, // All other pointers are properly tracked. - _ => Tag::Tagged(mem_extra.new_ptr()), + _ => SbTag::Tagged(mem_extra.new_ptr()), } }; // Reborrow. this.reborrow(&place, size, kind, new_tag, protect)?; - let new_place = place.replace_tag(new_tag); + + // Adjust pointer. + let new_place = place.map_provenance(|p| p.map(|t| Tag { sb: new_tag, ..t })); // Return new pointer. - Ok(ImmTy::from_immediate(new_place.to_ref(), val.layout)) + Ok(ImmTy::from_immediate(new_place.to_ref(this), val.layout)) } } @@ -752,7 +799,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // We have to turn the place into a pointer to use the existing code. // (The pointer type does not matter, so we use a raw pointer.) let ptr_layout = this.layout_of(this.tcx.mk_mut_ptr(return_place.layout.ty))?; - let val = ImmTy::from_immediate(return_place.to_ref(), ptr_layout); + let val = ImmTy::from_immediate(return_place.to_ref(this), ptr_layout); // Reborrow it. let val = this.retag_reference( &val, diff --git a/src/sync.rs b/src/sync.rs index b53af0aeb24ae..0e4e9695d81d5 100644 --- a/src/sync.rs +++ b/src/sync.rs @@ -152,7 +152,7 @@ pub(super) struct SynchronizationState { mutexes: IndexVec, rwlocks: IndexVec, condvars: IndexVec, - futexes: HashMap, + futexes: HashMap, } // Private extension trait for local helper methods @@ -486,18 +486,18 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.machine.threads.sync.condvars[id].waiters.retain(|waiter| waiter.thread != thread); } - fn futex_wait(&mut self, addr: Pointer, thread: ThreadId) { + fn futex_wait(&mut self, addr: u64, thread: ThreadId) { let this = self.eval_context_mut(); - let futex = &mut this.machine.threads.sync.futexes.entry(addr.erase_tag()).or_default(); + let futex = &mut this.machine.threads.sync.futexes.entry(addr).or_default(); let waiters = &mut futex.waiters; assert!(waiters.iter().all(|waiter| waiter.thread != thread), "thread is already waiting"); waiters.push_back(FutexWaiter { thread }); } - fn futex_wake(&mut self, addr: Pointer) -> Option { + fn futex_wake(&mut self, addr: u64) -> Option { let this = self.eval_context_mut(); let current_thread = this.get_active_thread(); - let futex = &mut this.machine.threads.sync.futexes.get_mut(&addr.erase_tag())?; + let futex = &mut this.machine.threads.sync.futexes.get_mut(&addr)?; let data_race = &this.memory.extra.data_race; // Each futex-wake happens-before the end of the futex wait @@ -513,9 +513,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx res } - fn futex_remove_waiter(&mut self, addr: Pointer, thread: ThreadId) { + fn futex_remove_waiter(&mut self, addr: u64, thread: ThreadId) { let this = self.eval_context_mut(); - if let Some(futex) = this.machine.threads.sync.futexes.get_mut(&addr.erase_tag()) { + if let Some(futex) = this.machine.threads.sync.futexes.get_mut(&addr) { futex.waiters.retain(|waiter| waiter.thread != thread); } } diff --git a/src/thread.rs b/src/thread.rs index 7ee18bb7f80e2..de8e41224b20f 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -218,7 +218,7 @@ pub struct ThreadManager<'mir, 'tcx> { pub(crate) sync: SynchronizationState, /// A mapping from a thread-local static to an allocation id of a thread /// specific allocation. - thread_local_alloc_ids: RefCell>, + thread_local_alloc_ids: RefCell>>, /// A flag that indicates that we should change the active thread. yield_active_thread: bool, /// Callbacks that are called once the specified time passes. @@ -247,18 +247,18 @@ impl<'mir, 'tcx> Default for ThreadManager<'mir, 'tcx> { impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { /// Check if we have an allocation for the given thread local static for the /// active thread. - fn get_thread_local_alloc_id(&self, def_id: DefId) -> Option { + fn get_thread_local_alloc_id(&self, def_id: DefId) -> Option> { self.thread_local_alloc_ids.borrow().get(&(def_id, self.active_thread)).cloned() } - /// Set the allocation id as the allocation id of the given thread local + /// Set the pointer for the allocation of the given thread local /// static for the active thread. /// /// Panics if a thread local is initialized twice for the same thread. - fn set_thread_local_alloc_id(&self, def_id: DefId, new_alloc_id: AllocId) { + fn set_thread_local_alloc(&self, def_id: DefId, ptr: Pointer) { self.thread_local_alloc_ids .borrow_mut() - .try_insert((def_id, self.active_thread), new_alloc_id) + .try_insert((def_id, self.active_thread), ptr) .unwrap(); } @@ -435,11 +435,11 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { } /// Wakes up threads joining on the active one and deallocates thread-local statics. - /// The `AllocId` that can now be freed is returned. + /// The `AllocId` that can now be freed are returned. fn thread_terminated( &mut self, mut data_race: Option<&mut data_race::GlobalState>, - ) -> Vec { + ) -> Vec> { let mut free_tls_statics = Vec::new(); { let mut thread_local_statics = self.thread_local_alloc_ids.borrow_mut(); @@ -557,16 +557,16 @@ impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mi pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { /// Get a thread-specific allocation id for the given thread-local static. /// If needed, allocate a new one. - fn get_or_create_thread_local_alloc_id( + fn get_or_create_thread_local_alloc( &mut self, def_id: DefId, - ) -> InterpResult<'tcx, AllocId> { + ) -> InterpResult<'tcx, Pointer> { let this = self.eval_context_mut(); let tcx = this.tcx; - if let Some(new_alloc_id) = this.machine.threads.get_thread_local_alloc_id(def_id) { + if let Some(old_alloc) = this.machine.threads.get_thread_local_alloc_id(def_id) { // We already have a thread-specific allocation id for this // thread-local static. - Ok(new_alloc_id) + Ok(old_alloc) } else { // We need to allocate a thread-specific allocation id for this // thread-local static. @@ -576,10 +576,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } let allocation = tcx.eval_static_initializer(def_id)?; // Create a fresh allocation with this content. - let new_alloc_id = - this.memory.allocate_with(allocation.clone(), MiriMemoryKind::Tls.into()).alloc_id; - this.machine.threads.set_thread_local_alloc_id(def_id, new_alloc_id); - Ok(new_alloc_id) + let new_alloc = + this.memory.allocate_with(allocation.clone(), MiriMemoryKind::Tls.into()); + this.machine.threads.set_thread_local_alloc(def_id, new_alloc); + Ok(new_alloc) } } @@ -761,10 +761,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx #[inline] fn thread_terminated(&mut self) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - for alloc_id in this.machine.threads.thread_terminated(this.memory.extra.data_race.as_mut()) - { - let ptr = this.memory.global_base_pointer(alloc_id.into())?; - this.memory.deallocate(ptr, None, MiriMemoryKind::Tls.into())?; + for ptr in this.machine.threads.thread_terminated(this.memory.extra.data_race.as_mut()) { + this.memory.deallocate(ptr.into(), None, MiriMemoryKind::Tls.into())?; } Ok(()) } diff --git a/tests/compile-fail/dangling_pointers/deref-partially-dangling.rs b/tests/compile-fail/dangling_pointers/deref-partially-dangling.rs index a6d3aae414de0..b7fcf4559e0ad 100644 --- a/tests/compile-fail/dangling_pointers/deref-partially-dangling.rs +++ b/tests/compile-fail/dangling_pointers/deref-partially-dangling.rs @@ -3,6 +3,6 @@ fn main() { let x = (1, 13); let xptr = &x as *const _ as *const (i32, i32, i32); - let val = unsafe { (*xptr).1 }; //~ ERROR pointer must be in-bounds at offset 12, but is outside bounds of alloc + let val = unsafe { (*xptr).1 }; //~ ERROR pointer to 12 bytes starting at offset 0 is out-of-bounds assert_eq!(val, 13); } diff --git a/tests/compile-fail/dangling_pointers/dyn_size.rs b/tests/compile-fail/dangling_pointers/dyn_size.rs index 39a091387c6c2..56de3970f1bb2 100644 --- a/tests/compile-fail/dangling_pointers/dyn_size.rs +++ b/tests/compile-fail/dangling_pointers/dyn_size.rs @@ -9,5 +9,5 @@ fn main() { // That should be UB, as the reference is not fully dereferencable. let ptr: *const SliceWithHead = unsafe { std::mem::transmute((&buf, 4usize)) }; // Re-borrow that. This should be UB. - let _ptr = unsafe { &*ptr }; //~ ERROR pointer must be in-bounds at offset 5 + let _ptr = unsafe { &*ptr }; //~ ERROR pointer to 5 bytes starting at offset 0 is out-of-bounds } diff --git a/tests/compile-fail/dangling_pointers/maybe_null_pointer_deref_zst.rs b/tests/compile-fail/dangling_pointers/maybe_null_pointer_deref_zst.rs index 9db8a7dcba982..357eadf91c7f0 100644 --- a/tests/compile-fail/dangling_pointers/maybe_null_pointer_deref_zst.rs +++ b/tests/compile-fail/dangling_pointers/maybe_null_pointer_deref_zst.rs @@ -4,5 +4,5 @@ fn main() { // This pointer *could* be NULL so we cannot load from it, not even at ZST let ptr = (&0u8 as *const u8).wrapping_sub(0x800) as *const (); - let _x: () = unsafe { *ptr }; //~ ERROR outside bounds + let _x: () = unsafe { *ptr }; //~ ERROR out-of-bounds } diff --git a/tests/compile-fail/dangling_pointers/maybe_null_pointer_write_zst.rs b/tests/compile-fail/dangling_pointers/maybe_null_pointer_write_zst.rs index 79eff2507ceb2..7f50b9827d94b 100644 --- a/tests/compile-fail/dangling_pointers/maybe_null_pointer_write_zst.rs +++ b/tests/compile-fail/dangling_pointers/maybe_null_pointer_write_zst.rs @@ -7,5 +7,5 @@ fn main() { // Also not assigning directly as that's array initialization, not assignment. let zst_val = [1u8; 0]; let ptr = (&0u8 as *const u8).wrapping_sub(0x800) as *mut [u8; 0]; - unsafe { *ptr = zst_val; } //~ ERROR outside bounds + unsafe { *ptr = zst_val; } //~ ERROR out-of-bounds } diff --git a/tests/compile-fail/dangling_pointers/out_of_bounds_read1.rs b/tests/compile-fail/dangling_pointers/out_of_bounds_read1.rs index 0c175af5266b8..ef5cdeec99677 100644 --- a/tests/compile-fail/dangling_pointers/out_of_bounds_read1.rs +++ b/tests/compile-fail/dangling_pointers/out_of_bounds_read1.rs @@ -1,5 +1,5 @@ fn main() { let v: Vec = vec![1, 2]; - let x = unsafe { *v.as_ptr().wrapping_offset(5) }; //~ ERROR outside bounds of alloc + let x = unsafe { *v.as_ptr().wrapping_offset(5) }; //~ ERROR out-of-bounds panic!("this should never print: {}", x); } diff --git a/tests/compile-fail/dangling_pointers/out_of_bounds_read2.rs b/tests/compile-fail/dangling_pointers/out_of_bounds_read2.rs index 0c175af5266b8..ef5cdeec99677 100644 --- a/tests/compile-fail/dangling_pointers/out_of_bounds_read2.rs +++ b/tests/compile-fail/dangling_pointers/out_of_bounds_read2.rs @@ -1,5 +1,5 @@ fn main() { let v: Vec = vec![1, 2]; - let x = unsafe { *v.as_ptr().wrapping_offset(5) }; //~ ERROR outside bounds of alloc + let x = unsafe { *v.as_ptr().wrapping_offset(5) }; //~ ERROR out-of-bounds panic!("this should never print: {}", x); } diff --git a/tests/compile-fail/intrinsics/out_of_bounds_ptr_1.rs b/tests/compile-fail/intrinsics/out_of_bounds_ptr_1.rs index 20bcc36f049d1..d200b3eb0297f 100644 --- a/tests/compile-fail/intrinsics/out_of_bounds_ptr_1.rs +++ b/tests/compile-fail/intrinsics/out_of_bounds_ptr_1.rs @@ -1,4 +1,4 @@ -// error-pattern: must be in-bounds at offset 5, but is outside bounds of alloc +// error-pattern: pointer to 5 bytes starting at offset 0 is out-of-bounds fn main() { let v = [0i8; 4]; let x = &v as *const i8; diff --git a/tests/compile-fail/intrinsics/out_of_bounds_ptr_2.rs b/tests/compile-fail/intrinsics/out_of_bounds_ptr_2.rs index 1e4759ddc46d0..52b385b8e3b48 100644 --- a/tests/compile-fail/intrinsics/out_of_bounds_ptr_2.rs +++ b/tests/compile-fail/intrinsics/out_of_bounds_ptr_2.rs @@ -2,6 +2,6 @@ fn main() { let v = [0i8; 4]; let x = &v as *const i8; - let x = unsafe { x.offset(-1) }; + let x = unsafe { x.offset(isize::MIN) }; panic!("this should never print: {:?}", x); } diff --git a/tests/compile-fail/intrinsics/ptr_offset_ptr_plus_0.rs b/tests/compile-fail/intrinsics/ptr_offset_ptr_plus_0.rs index d07ecc4dc7f31..8760345409c8e 100644 --- a/tests/compile-fail/intrinsics/ptr_offset_ptr_plus_0.rs +++ b/tests/compile-fail/intrinsics/ptr_offset_ptr_plus_0.rs @@ -1,4 +1,4 @@ -// error-pattern: outside bounds of alloc +// error-pattern: pointer at offset 32 is out-of-bounds fn main() { let x = Box::into_raw(Box::new(0u32)); diff --git a/tests/compile-fail/null_pointer_deref_zst.rs b/tests/compile-fail/null_pointer_deref_zst.rs index 45925f3586c48..04617c58f3cef 100644 --- a/tests/compile-fail/null_pointer_deref_zst.rs +++ b/tests/compile-fail/null_pointer_deref_zst.rs @@ -3,6 +3,6 @@ #[allow(deref_nullptr)] fn main() { - let x: () = unsafe { *std::ptr::null() }; //~ ERROR memory access failed: 0x0 is not a valid pointer + let x: () = unsafe { *std::ptr::null() }; //~ ERROR dereferencing pointer failed: 0x0 is not a valid pointer panic!("this should never print: {:?}", x); } diff --git a/tests/compile-fail/null_pointer_write_zst.rs b/tests/compile-fail/null_pointer_write_zst.rs index 595011fcd6a7d..46a8345b1b45a 100644 --- a/tests/compile-fail/null_pointer_write_zst.rs +++ b/tests/compile-fail/null_pointer_write_zst.rs @@ -1,10 +1,11 @@ // Some optimizations remove ZST accesses, thus masking this UB. // compile-flags: -Zmir-opt-level=0 +// error-pattern: memory access failed: 0x0 is not a valid pointer #[allow(deref_nullptr)] fn main() { // Not using the () type here, as writes of that type do not even have MIR generated. // Also not assigning directly as that's array initialization, not assignment. let zst_val = [1u8; 0]; - unsafe { *std::ptr::null_mut() = zst_val }; //~ ERROR memory access failed: 0x0 is not a valid pointer + unsafe { std::ptr::null_mut::<[u8; 0]>().write(zst_val) }; } diff --git a/tests/compile-fail/stacked_borrows/issue-miri-1050-1.rs b/tests/compile-fail/stacked_borrows/issue-miri-1050-1.rs index 24df70a8179f1..852eb69968ed7 100644 --- a/tests/compile-fail/stacked_borrows/issue-miri-1050-1.rs +++ b/tests/compile-fail/stacked_borrows/issue-miri-1050-1.rs @@ -1,4 +1,4 @@ -// error-pattern: pointer must be in-bounds +// error-pattern: pointer to 4 bytes starting at offset 0 is out-of-bounds fn main() { unsafe { let ptr = Box::into_raw(Box::new(0u16)); diff --git a/tests/compile-fail/stacked_borrows/static_memory_modification.rs b/tests/compile-fail/stacked_borrows/static_memory_modification.rs index 55a7f816c0340..417a03bb0335b 100644 --- a/tests/compile-fail/stacked_borrows/static_memory_modification.rs +++ b/tests/compile-fail/stacked_borrows/static_memory_modification.rs @@ -3,6 +3,6 @@ static X: usize = 5; #[allow(mutable_transmutes)] fn main() { let _x = unsafe { - std::mem::transmute::<&usize, &mut usize>(&X) //~ ERROR writing to alloc0 which is read-only + std::mem::transmute::<&usize, &mut usize>(&X) //~ ERROR writing to alloc1 which is read-only }; } diff --git a/tests/compile-fail/zst1.rs b/tests/compile-fail/zst1.rs index e4ce7b8ecdf8c..d400fba5d0c24 100644 --- a/tests/compile-fail/zst1.rs +++ b/tests/compile-fail/zst1.rs @@ -1,5 +1,5 @@ fn main() { // make sure ZST locals cannot be accessed let x = &() as *const () as *const i8; - let _val = unsafe { *x }; //~ ERROR pointer must be in-bounds + let _val = unsafe { *x }; //~ ERROR out-of-bounds } diff --git a/tests/compile-fail/zst3.rs b/tests/compile-fail/zst3.rs index 734c4b8ac4b8f..7ecb8c7dca9d5 100644 --- a/tests/compile-fail/zst3.rs +++ b/tests/compile-fail/zst3.rs @@ -14,5 +14,5 @@ fn main() { unsafe { *(x as *mut [u8; 0]) = zst_val; } // One byte further is OOB. let x = x.wrapping_offset(1); - unsafe { *(x as *mut [u8; 0]) = zst_val; } //~ ERROR pointer must be in-bounds + unsafe { *(x as *mut [u8; 0]) = zst_val; } //~ ERROR out-of-bounds } From bf8b2aa8dc201c25181992ae3e194b76dbb2e274 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 17 Jul 2021 13:59:58 +0200 Subject: [PATCH 2764/3747] add test for better ptr handling in enum niches --- tests/run-pass/enum_discriminant_ptr_value.rs | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 tests/run-pass/enum_discriminant_ptr_value.rs diff --git a/tests/run-pass/enum_discriminant_ptr_value.rs b/tests/run-pass/enum_discriminant_ptr_value.rs new file mode 100644 index 0000000000000..618d503cd5f21 --- /dev/null +++ b/tests/run-pass/enum_discriminant_ptr_value.rs @@ -0,0 +1,9 @@ +// A niche-optimized enum where the discriminant is a pointer value -- relies on ptr-to-int casts in +// the niche handling code. +// compile-flags: -Zmiri-disable-stacked-borrows -Zmiri-disable-validation + +fn main() { + let x = 42; + let val: Option<&i32> = unsafe { std::mem::transmute((&x as *const i32).wrapping_offset(2)) }; + assert!(val.is_some()); +} From 0d65d500c67f65a54ed7caeb907bfa1095d43e0f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 17 Jul 2021 20:24:57 +0200 Subject: [PATCH 2765/3747] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index aee5d6ee3ba2e..b5742bc7a004c 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -3982eb35cabe3a99194d768d34a92347967c3fa2 +c78ebb7bdcfc924a20fd069891ffe1364d6814e7 From 6ce77164c19dc42c5f58cd5f0fff001a2f2f23f4 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 20 Jul 2021 12:18:59 +0200 Subject: [PATCH 2766/3747] rustup --- rust-version | 2 +- tests/run-pass/dyn-lcsit.rs | 68 ------------------------------------- 2 files changed, 1 insertion(+), 69 deletions(-) delete mode 100644 tests/run-pass/dyn-lcsit.rs diff --git a/rust-version b/rust-version index b5742bc7a004c..dc2d4398c48af 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -c78ebb7bdcfc924a20fd069891ffe1364d6814e7 +a72c360a30f9a8160e4f40340cecc9b1ce979cd7 diff --git a/tests/run-pass/dyn-lcsit.rs b/tests/run-pass/dyn-lcsit.rs deleted file mode 100644 index e7a5f13923a8d..0000000000000 --- a/tests/run-pass/dyn-lcsit.rs +++ /dev/null @@ -1,68 +0,0 @@ -// Taken from the rustc test suite; this triggers an interesting case in unsizing. - -#![allow(non_upper_case_globals, incomplete_features)] -#![feature(associated_type_bounds)] -#![feature(impl_trait_in_bindings)] - -use std::ops::Add; - -trait Tr1 { type As1; fn mk(&self) -> Self::As1; } -trait Tr2<'a> { fn tr2(self) -> &'a Self; } - -fn assert_copy(x: T) { let _x = x; let _x = x; } -fn assert_static(_: T) {} -fn assert_forall_tr2 Tr2<'a>>(_: T) {} - -#[derive(Copy, Clone)] -struct S1; -#[derive(Copy, Clone)] -struct S2; -impl Tr1 for S1 { type As1 = S2; fn mk(&self) -> Self::As1 { S2 } } - -const cdef_et1: &dyn Tr1 = &S1; -const sdef_et1: &dyn Tr1 = &S1; -pub fn use_et1() { assert_copy(cdef_et1.mk()); assert_copy(sdef_et1.mk()); } - -const cdef_et2: &(dyn Tr1 + Sync) = &S1; -static sdef_et2: &(dyn Tr1 + Sync) = &S1; -pub fn use_et2() { assert_static(cdef_et2.mk()); assert_static(sdef_et2.mk()); } - -const cdef_et3: &dyn Tr1>>> = { - struct A; - impl Tr1 for A { - type As1 = core::ops::Range; - fn mk(&self) -> Self::As1 { 0..10 } - } - &A -}; -pub fn use_et3() { - let _0 = cdef_et3.mk().clone(); - let mut s = 0u8; - for _1 in _0 { - let _2 = _1 + 1u8; - s += _2.into(); - } - assert_eq!(s, (0..10).map(|x| x + 1).sum()); -} - -const cdef_et4: &(dyn Tr1 Tr2<'a>> + Sync) = { - #[derive(Copy, Clone)] - struct A; - impl Tr1 for A { - type As1 = A; - fn mk(&self) -> A { A } - } - impl<'a> Tr2<'a> for A { - fn tr2(self) -> &'a Self { &A } - } - &A -}; -static sdef_et4: &(dyn Tr1 Tr2<'a>> + Sync) = cdef_et4; -pub fn use_et4() { assert_forall_tr2(cdef_et4.mk()); assert_forall_tr2(sdef_et4.mk()); } - -fn main() { - let _ = use_et1(); - let _ = use_et2(); - let _ = use_et3(); - let _ = use_et4(); -} From 46ed39ec200a3bd0e402c994203a9d67d62b0c6c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 17 Jul 2021 14:43:23 +0200 Subject: [PATCH 2767/3747] adjust for PointerOutOfBounds change --- src/stacked_borrows.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index ddfbfd426680a..e04de65ac3fd5 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -623,14 +623,14 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let orig_tag = ptr.provenance.sb; // Ensure we bail out if the pointer goes out-of-bounds (see miri#1050). - let (allocation_size, _) = + let (alloc_size, _) = this.memory.get_size_and_align(alloc_id, AllocCheck::Dereferenceable)?; - if base_offset + size > allocation_size { + if base_offset + size > alloc_size { throw_ub!(PointerOutOfBounds { alloc_id, - offset: base_offset, - size, - allocation_size, + alloc_size, + ptr_offset: this.machine_usize_to_isize(base_offset.bytes()), + ptr_size: size, msg: CheckInAllocMsg::InboundsTest }); } From cf26458376f47c659c663b1735c395a94a475e5f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 17 Jul 2021 14:43:32 +0200 Subject: [PATCH 2768/3747] test for negative offsets --- tests/compile-fail/intrinsics/out_of_bounds_ptr_3.rs | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 tests/compile-fail/intrinsics/out_of_bounds_ptr_3.rs diff --git a/tests/compile-fail/intrinsics/out_of_bounds_ptr_3.rs b/tests/compile-fail/intrinsics/out_of_bounds_ptr_3.rs new file mode 100644 index 0000000000000..cd0861efe5d95 --- /dev/null +++ b/tests/compile-fail/intrinsics/out_of_bounds_ptr_3.rs @@ -0,0 +1,7 @@ +// error-pattern: pointer to 1 byte starting at offset -1 is out-of-bounds +fn main() { + let v = [0i8; 4]; + let x = &v as *const i8; + let x = unsafe { x.offset(-1) }; + panic!("this should never print: {:?}", x); +} From 63286771d32344fb1a6adc256c3291c84bea7a3c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 20 Jul 2021 13:38:52 +0200 Subject: [PATCH 2769/3747] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index dc2d4398c48af..fb2d0bf8f682d 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -a72c360a30f9a8160e4f40340cecc9b1ce979cd7 +718d53b0cb7dde93499cb92950d60b412f5a3d05 From a1cabac72707020e30a787f44740b855583fc341 Mon Sep 17 00:00:00 2001 From: Smit Soni Date: Tue, 15 Jun 2021 17:33:18 -0700 Subject: [PATCH 2770/3747] Fix use of deprecated `check_no_isolation` in posix fs ops Update posix fs shims to use new API `reject_in_isolation`, which allows rejection with error code instead of always forcing abort. Error code chosen for each op is the most appropriate one from the list in corresponding syscall's manual. Updated helper APIs to not use quotes (`) around input name while preparing the message. This allows callers to pass multi-word string like -- "`read` from stdin". --- src/diagnostics.rs | 2 +- src/helpers.rs | 2 +- src/shims/env.rs | 8 +-- src/shims/posix/fs.rs | 155 ++++++++++++++++++++++++++++++++++++------ 4 files changed, 140 insertions(+), 27 deletions(-) diff --git a/src/diagnostics.rs b/src/diagnostics.rs index b5b75a7fc3184..f66f66e0088ff 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -328,7 +328,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx CreatedAlloc(AllocId(id)) => format!("created allocation with id {}", id), FreedAlloc(AllocId(id)) => format!("freed allocation with id {}", id), RejectedIsolatedOp(ref op) => - format!("`{}` was made to return an error due to isolation", op), + format!("{} was made to return an error due to isolation", op), }; let (title, diag_level) = match e { diff --git a/src/helpers.rs b/src/helpers.rs index 363aefa62d2f8..e09ef2865fb2b 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -409,7 +409,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx RejectOpWith::WarningWithoutBacktrace => { this.tcx .sess - .warn(&format!("`{}` was made to return an error due to isolation", op_name)); + .warn(&format!("{} was made to return an error due to isolation", op_name)); Ok(()) } RejectOpWith::Warning => { diff --git a/src/shims/env.rs b/src/shims/env.rs index ddd2b61588981..9290ec022b57f 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -322,7 +322,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let size = this.read_scalar(&size_op)?.to_machine_usize(&*this.tcx)?; if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { - this.reject_in_isolation("getcwd", reject_with)?; + this.reject_in_isolation("`getcwd`", reject_with)?; this.set_last_error_from_io_error(ErrorKind::PermissionDenied)?; return Ok(Pointer::null()); } @@ -355,7 +355,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let buf = this.read_pointer(buf_op)?; if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { - this.reject_in_isolation("GetCurrentDirectoryW", reject_with)?; + this.reject_in_isolation("`GetCurrentDirectoryW`", reject_with)?; this.set_last_error_from_io_error(ErrorKind::PermissionDenied)?; return Ok(0); } @@ -380,7 +380,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let path = this.read_path_from_c_str(this.read_pointer(path_op)?)?; if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { - this.reject_in_isolation("chdir", reject_with)?; + this.reject_in_isolation("`chdir`", reject_with)?; this.set_last_error_from_io_error(ErrorKind::PermissionDenied)?; return Ok(-1); @@ -408,7 +408,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let path = this.read_path_from_wide_str(this.read_pointer(path_op)?)?; if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { - this.reject_in_isolation("SetCurrentDirectoryW", reject_with)?; + this.reject_in_isolation("`SetCurrentDirectoryW`", reject_with)?; this.set_last_error_from_io_error(ErrorKind::PermissionDenied)?; return Ok(0); diff --git a/src/shims/posix/fs.rs b/src/shims/posix/fs.rs index a14a9c907eedc..3653fc43ebb1c 100644 --- a/src/shims/posix/fs.rs +++ b/src/shims/posix/fs.rs @@ -4,7 +4,7 @@ use std::convert::{TryFrom, TryInto}; use std::fs::{ read_dir, remove_dir, remove_file, rename, DirBuilder, File, FileType, OpenOptions, ReadDir, }; -use std::io::{self, Read, Seek, SeekFrom, Write}; +use std::io::{self, ErrorKind, Read, Seek, SeekFrom, Write}; use std::path::Path; use std::time::SystemTime; @@ -504,7 +504,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - this.check_no_isolation("`open`")?; + // Reject if isolation is enabled. + if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { + this.reject_in_isolation("`open`", reject_with)?; + this.set_last_error_from_io_error(ErrorKind::PermissionDenied)?; + return Ok(-1); + } let flag = this.read_scalar(flag_op)?.to_i32()?; @@ -594,7 +599,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn fcntl(&mut self, args: &[OpTy<'tcx, Tag>]) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - this.check_no_isolation("`fcntl`")?; + // Reject if isolation is enabled. + if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { + this.reject_in_isolation("`fcntl`", reject_with)?; + this.set_last_error_from_io_error(ErrorKind::PermissionDenied)?; + return Ok(-1); + } if args.len() < 2 { throw_ub_format!( @@ -785,7 +795,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn unlink(&mut self, path_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - this.check_no_isolation("`unlink`")?; + // Reject if isolation is enabled. + if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { + this.reject_in_isolation("`unlink`", reject_with)?; + this.set_last_error_from_io_error(ErrorKind::PermissionDenied)?; + return Ok(-1); + } let path = this.read_path_from_c_str(this.read_pointer(path_op)?)?; @@ -811,7 +826,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); - this.check_no_isolation("`symlink`")?; + // Reject if isolation is enabled. + if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { + this.reject_in_isolation("`symlink`", reject_with)?; + this.set_last_error_from_io_error(ErrorKind::PermissionDenied)?; + return Ok(-1); + } let target = this.read_path_from_c_str(this.read_pointer(target_op)?)?; let linkpath = this.read_path_from_c_str(this.read_pointer(linkpath_op)?)?; @@ -827,7 +847,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); this.assert_target_os("macos", "stat"); - this.check_no_isolation("`stat`")?; + + // Reject if isolation is enabled. + if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { + this.reject_in_isolation("`stat`", reject_with)?; + // macos stat never sets "EPERM". Set error code "ENOENT". + this.set_last_error_from_io_error(ErrorKind::NotFound)?; + return Ok(-1); + } + // `stat` always follows symlinks. this.macos_stat_or_lstat(true, path_op, buf_op) } @@ -840,7 +868,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); this.assert_target_os("macos", "lstat"); - this.check_no_isolation("`lstat`")?; + + // Reject if isolation is enabled. + if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { + this.reject_in_isolation("`lstat`", reject_with)?; + // macos lstat never sets "EPERM". Set error code "ENOENT". + this.set_last_error_from_io_error(ErrorKind::NotFound)?; + return Ok(-1); + } + this.macos_stat_or_lstat(false, path_op, buf_op) } @@ -852,7 +888,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); this.assert_target_os("macos", "fstat"); - this.check_no_isolation("`fstat`")?; + + // Reject if isolation is enabled. + if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { + this.reject_in_isolation("`fstat`", reject_with)?; + // Set error code as "EBADF" (bad fd) + return this.handle_not_found(); + } let fd = this.read_scalar(fd_op)?.to_i32()?; @@ -874,7 +916,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); this.assert_target_os("linux", "statx"); - this.check_no_isolation("`statx`")?; + + // Reject if isolation is enabled. + if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { + this.reject_in_isolation("`statx`", reject_with)?; + // statx never sets "EPERM". Set error code "ENOENT". + this.set_last_error_from_io_error(ErrorKind::NotFound)?; + return Ok(-1); + } let statxbuf_ptr = this.read_pointer(statxbuf_op)?; let pathname_ptr = this.read_pointer(pathname_op)?; @@ -1032,7 +1081,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - this.check_no_isolation("`rename`")?; + // Reject if isolation is enabled. + if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { + this.reject_in_isolation("`rename`", reject_with)?; + this.set_last_error_from_io_error(ErrorKind::PermissionDenied)?; + return Ok(-1); + } let oldpath_ptr = this.read_pointer(oldpath_op)?; let newpath_ptr = this.read_pointer(newpath_op)?; @@ -1058,7 +1112,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - this.check_no_isolation("`mkdir`")?; + // Reject if isolation is enabled. + if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { + this.reject_in_isolation("`mkdir`", reject_with)?; + this.set_last_error_from_io_error(ErrorKind::PermissionDenied)?; + return Ok(-1); + } #[cfg_attr(not(unix), allow(unused_variables))] let mode = if this.tcx.sess.target.os == "macos" { @@ -1088,7 +1147,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn rmdir(&mut self, path_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - this.check_no_isolation("`rmdir`")?; + // Reject if isolation is enabled. + if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { + this.reject_in_isolation("`rmdir`", reject_with)?; + this.set_last_error_from_io_error(ErrorKind::PermissionDenied)?; + return Ok(-1); + } let path = this.read_path_from_c_str(this.read_pointer(path_op)?)?; @@ -1100,7 +1164,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn opendir(&mut self, name_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); - this.check_no_isolation("`opendir`")?; + // Reject if isolation is enabled. + if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { + this.reject_in_isolation("`opendir`", reject_with)?; + // opendir function never sets "EPERM". Set "ENOENT". + this.set_last_error_from_io_error(ErrorKind::NotFound)?; + return Ok(Scalar::null_ptr(this)); + } let name = this.read_path_from_c_str(this.read_pointer(name_op)?)?; @@ -1131,7 +1201,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); this.assert_target_os("linux", "readdir64_r"); - this.check_no_isolation("`readdir64_r`")?; + + // Reject if isolation is enabled. + if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { + this.reject_in_isolation("`readdir64_r`", reject_with)?; + // Set error code as "EBADF" (bad fd) + return this.handle_not_found(); + } let dirp = this.read_scalar(dirp_op)?.to_machine_usize(this)?; @@ -1224,7 +1300,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); this.assert_target_os("macos", "readdir_r"); - this.check_no_isolation("`readdir_r`")?; + + // Reject if isolation is enabled. + if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { + this.reject_in_isolation("`readdir_r`", reject_with)?; + // Set error code as "EBADF" (bad fd) + return this.handle_not_found(); + } let dirp = this.read_scalar(dirp_op)?.to_machine_usize(this)?; @@ -1313,7 +1395,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn closedir(&mut self, dirp_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - this.check_no_isolation("`closedir`")?; + // Reject if isolation is enabled. + if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { + this.reject_in_isolation("`closedir`", reject_with)?; + // Set error code as "EBADF" (bad fd) + return this.handle_not_found(); + } let dirp = this.read_scalar(dirp_op)?.to_machine_usize(this)?; @@ -1332,7 +1419,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - this.check_no_isolation("`ftruncate64`")?; + // Reject if isolation is enabled. + if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { + this.reject_in_isolation("`ftruncate64`", reject_with)?; + this.set_last_error_from_io_error(ErrorKind::PermissionDenied)?; + return Ok(-1); + } let fd = this.read_scalar(fd_op)?.to_i32()?; let length = this.read_scalar(length_op)?.to_i64()?; @@ -1367,7 +1459,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); - this.check_no_isolation("`fsync`")?; + // Reject if isolation is enabled. + if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { + this.reject_in_isolation("`fsync`", reject_with)?; + // Set error code as "EBADF" (bad fd) + return this.handle_not_found(); + } let fd = this.read_scalar(fd_op)?.to_i32()?; if let Some(file_descriptor) = this.machine.file_handler.handles.get(&fd) { @@ -1383,7 +1480,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn fdatasync(&mut self, fd_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - this.check_no_isolation("`fdatasync`")?; + // Reject if isolation is enabled. + if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { + this.reject_in_isolation("`fdatasync`", reject_with)?; + // Set error code as "EBADF" (bad fd) + return this.handle_not_found(); + } let fd = this.read_scalar(fd_op)?.to_i32()?; if let Some(file_descriptor) = this.machine.file_handler.handles.get(&fd) { @@ -1405,7 +1507,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - this.check_no_isolation("`sync_file_range`")?; + // Reject if isolation is enabled. + if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { + this.reject_in_isolation("`sync_file_range`", reject_with)?; + // Set error code as "EBADF" (bad fd) + return this.handle_not_found(); + } let fd = this.read_scalar(fd_op)?.to_i32()?; let offset = this.read_scalar(offset_op)?.to_i64()?; @@ -1444,7 +1551,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, i64> { let this = self.eval_context_mut(); - this.check_no_isolation("readlink")?; + // Reject if isolation is enabled. + if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { + this.reject_in_isolation("`readlink`", reject_with)?; + // readlink never sets "EPERM". Set "ENOENT". + this.set_last_error_from_io_error(ErrorKind::NotFound)?; + return Ok(-1); + } let pathname = this.read_path_from_c_str(this.read_pointer(pathname_op)?)?; let buf = this.read_pointer(buf_op)?; From da6880427ac6bf2735019e34448c43900a5fc6df Mon Sep 17 00:00:00 2001 From: Smit Soni Date: Sun, 18 Jul 2021 14:40:59 -0700 Subject: [PATCH 2771/3747] Update error code for fs ops in isolation Change the code to either `EACCES` (if the op is performed on the path), or `EBADF` (if the op is performed the fd) Updated ops: `stat`, `opendir`, `ftruncate64`, and `readlink` Add a new test for fs ops in isolation. --- src/shims/posix/fs.rs | 44 +++++++++++--------- tests/run-pass/fs_with_isolation.rs | 54 +++++++++++++++++++++++++ tests/run-pass/fs_with_isolation.stderr | 20 +++++++++ 3 files changed, 100 insertions(+), 18 deletions(-) create mode 100644 tests/run-pass/fs_with_isolation.rs create mode 100644 tests/run-pass/fs_with_isolation.stderr diff --git a/src/shims/posix/fs.rs b/src/shims/posix/fs.rs index 3653fc43ebb1c..2693dc0962860 100644 --- a/src/shims/posix/fs.rs +++ b/src/shims/posix/fs.rs @@ -851,8 +851,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Reject if isolation is enabled. if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { this.reject_in_isolation("`stat`", reject_with)?; - // macos stat never sets "EPERM". Set error code "ENOENT". - this.set_last_error_from_io_error(ErrorKind::NotFound)?; + let eacc = this.eval_libc("EACCES")?; + this.set_last_error(eacc)?; return Ok(-1); } @@ -872,8 +872,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Reject if isolation is enabled. if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { this.reject_in_isolation("`lstat`", reject_with)?; - // macos lstat never sets "EPERM". Set error code "ENOENT". - this.set_last_error_from_io_error(ErrorKind::NotFound)?; + let eacc = this.eval_libc("EACCES")?; + this.set_last_error(eacc)?; return Ok(-1); } @@ -917,14 +917,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.assert_target_os("linux", "statx"); - // Reject if isolation is enabled. - if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { - this.reject_in_isolation("`statx`", reject_with)?; - // statx never sets "EPERM". Set error code "ENOENT". - this.set_last_error_from_io_error(ErrorKind::NotFound)?; - return Ok(-1); - } - let statxbuf_ptr = this.read_pointer(statxbuf_op)?; let pathname_ptr = this.read_pointer(pathname_op)?; @@ -973,6 +965,22 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) } + // Reject if isolation is enabled. + if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { + this.reject_in_isolation("`statx`", reject_with)?; + let ecode = if path.is_absolute() || dirfd == this.eval_libc_i32("AT_FDCWD")? { + // since `path` is provided, either absolute or + // relative to CWD, `EACCES` is the most relevant. + this.eval_libc("EACCES")? + } else { + // `dirfd` is set to target file, and `path` is + // empty. `EACCES` would violate the spec. + this.eval_libc("EBADF")? + }; + this.set_last_error(ecode)?; + return Ok(-1); + } + // the `_mask_op` paramter specifies the file information that the caller requested. // However `statx` is allowed to return information that was not requested or to not // return information that was requested. This `mask` represents the information we can @@ -1167,8 +1175,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Reject if isolation is enabled. if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { this.reject_in_isolation("`opendir`", reject_with)?; - // opendir function never sets "EPERM". Set "ENOENT". - this.set_last_error_from_io_error(ErrorKind::NotFound)?; + let eacc = this.eval_libc("EACCES")?; + this.set_last_error(eacc)?; return Ok(Scalar::null_ptr(this)); } @@ -1422,8 +1430,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Reject if isolation is enabled. if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { this.reject_in_isolation("`ftruncate64`", reject_with)?; - this.set_last_error_from_io_error(ErrorKind::PermissionDenied)?; - return Ok(-1); + // Set error code as "EBADF" (bad fd) + return this.handle_not_found(); } let fd = this.read_scalar(fd_op)?.to_i32()?; @@ -1554,8 +1562,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Reject if isolation is enabled. if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { this.reject_in_isolation("`readlink`", reject_with)?; - // readlink never sets "EPERM". Set "ENOENT". - this.set_last_error_from_io_error(ErrorKind::NotFound)?; + let eacc = this.eval_libc("EACCES")?; + this.set_last_error(eacc)?; return Ok(-1); } diff --git a/tests/run-pass/fs_with_isolation.rs b/tests/run-pass/fs_with_isolation.rs new file mode 100644 index 0000000000000..a9e1e5094fa52 --- /dev/null +++ b/tests/run-pass/fs_with_isolation.rs @@ -0,0 +1,54 @@ +// ignore-windows: File handling is not implemented yet +// compile-flags: -Zmiri-isolation-error=warn-nobacktrace +// normalize-stderr-test "(stat(x)?)" -> "$$STAT" + +#![feature(rustc_private)] + +extern crate libc; + +use std::ffi::CString; +use std::os::unix; +use std::fs::{self, File}; +use std::io::{Error, ErrorKind}; + +fn main() { + // test `open` + assert_eq!(File::create("foo.txt").unwrap_err().kind(), ErrorKind::PermissionDenied); + + // test `fcntl` + unsafe { + assert_eq!(libc::fcntl(1, libc::F_DUPFD, 0), -1); + assert_eq!(Error::last_os_error().raw_os_error(), Some(libc::EPERM)); + } + + // test `unlink` + assert_eq!(fs::remove_file("foo.txt").unwrap_err().kind(), ErrorKind::PermissionDenied); + + // test `symlink` + assert_eq!(unix::fs::symlink("foo.txt", "foo_link.txt").unwrap_err().kind(), ErrorKind::PermissionDenied); + + // test `readlink` + let symlink_c_str = CString::new("foo.txt").unwrap(); + let mut buf = vec![0; "foo_link.txt".len() + 1]; + unsafe { + assert_eq!(libc::readlink(symlink_c_str.as_ptr(), buf.as_mut_ptr(), buf.len()), -1); + assert_eq!(Error::last_os_error().raw_os_error(), Some(libc::EACCES)); + } + + // test `stat` + assert_eq!(fs::metadata("foo.txt").unwrap_err().kind(), ErrorKind::PermissionDenied); + assert_eq!(Error::last_os_error().raw_os_error(), Some(libc::EACCES)); + + // test `rename` + assert_eq!(fs::rename("a.txt", "b.txt").unwrap_err().kind(), ErrorKind::PermissionDenied); + + // test `mkdir` + assert_eq!(fs::create_dir("foo/bar").unwrap_err().kind(), ErrorKind::PermissionDenied); + + // test `rmdir` + assert_eq!(fs::remove_dir("foo/bar").unwrap_err().kind(), ErrorKind::PermissionDenied); + + // test `opendir` + assert_eq!(fs::read_dir("foo/bar").unwrap_err().kind(), ErrorKind::PermissionDenied); + assert_eq!(Error::last_os_error().raw_os_error(), Some(libc::EACCES)); +} diff --git a/tests/run-pass/fs_with_isolation.stderr b/tests/run-pass/fs_with_isolation.stderr new file mode 100644 index 0000000000000..ad75e42831b0a --- /dev/null +++ b/tests/run-pass/fs_with_isolation.stderr @@ -0,0 +1,20 @@ +warning: `open` was made to return an error due to isolation + +warning: `fcntl` was made to return an error due to isolation + +warning: `unlink` was made to return an error due to isolation + +warning: `symlink` was made to return an error due to isolation + +warning: `readlink` was made to return an error due to isolation + +warning: `$STAT` was made to return an error due to isolation + +warning: `rename` was made to return an error due to isolation + +warning: `mkdir` was made to return an error due to isolation + +warning: `rmdir` was made to return an error due to isolation + +warning: `opendir` was made to return an error due to isolation + From 46d31f92303c3dd8905aef1b71150acbd46e88c1 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 24 Jul 2021 14:02:09 +0200 Subject: [PATCH 2772/3747] show proper error when using a sysroot without MIR --- src/diagnostics.rs | 2 -- src/eval.rs | 6 ++++++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/diagnostics.rs b/src/diagnostics.rs index b5b75a7fc3184..cad08a2831a36 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -132,8 +132,6 @@ pub fn report_error<'tcx, 'mir>( }; #[rustfmt::skip] let helps = match e.kind() { - Unsupported(UnsupportedOpInfo::NoMirFor(..)) => - vec![(None, format!("make sure to use a Miri sysroot, which you can prepare with `cargo miri setup`"))], Unsupported(UnsupportedOpInfo::ThreadLocalStatic(_) | UnsupportedOpInfo::ReadExternStatic(_)) => panic!("Error should never be raised by Miri: {:?}", e.kind()), Unsupported(_) => diff --git a/src/eval.rs b/src/eval.rs index ae9ff9c1f5a42..02feae4a3503c 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -138,6 +138,12 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( EnvVars::init(&mut ecx, config.excluded_env_vars)?; MemoryExtra::init_extern_statics(&mut ecx)?; + // Make sure we have MIR. We check MIR for some stable monomorphic function in libcore. + let sentinel = ecx.resolve_path(&["core", "ascii", "escape_default"]); + if !tcx.is_mir_available(sentinel.def.def_id()) { + tcx.sess.fatal("the current sysroot was built without `-Zalways-encode-mir`. Use `cargo miri setup` to prepare a sysroot that is suitable for Miri."); + } + // Setup first stack-frame let main_instance = ty::Instance::mono(tcx, main_id); let main_mir = ecx.load_mir(main_instance.def, None)?; From 20d0f2ee2607a1eecf095223250ca07307b9dbb0 Mon Sep 17 00:00:00 2001 From: Smit Soni Date: Tue, 20 Jul 2021 22:27:33 -0700 Subject: [PATCH 2773/3747] Move shim argument checks before isolation check This allows catching extremely incorrect arguments before rejecting due to isolation. --- src/shims/posix/fs.rs | 171 +++++++++++++++++++++--------------------- 1 file changed, 85 insertions(+), 86 deletions(-) diff --git a/src/shims/posix/fs.rs b/src/shims/posix/fs.rs index 2693dc0962860..ac6e878da962e 100644 --- a/src/shims/posix/fs.rs +++ b/src/shims/posix/fs.rs @@ -304,28 +304,6 @@ impl<'tcx> FileHandler { impl<'mir, 'tcx: 'mir> EvalContextExtPrivate<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} trait EvalContextExtPrivate<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { - /// Emulate `stat` or `lstat` on `macos`. This function is not intended to be - /// called directly from `emulate_foreign_item_by_name`, so it does not check if isolation is - /// disabled or if the target OS is the correct one. Please use `macos_stat` or - /// `macos_lstat` instead. - fn macos_stat_or_lstat( - &mut self, - follow_symlink: bool, - path_op: &OpTy<'tcx, Tag>, - buf_op: &OpTy<'tcx, Tag>, - ) -> InterpResult<'tcx, i32> { - let this = self.eval_context_mut(); - - let path_scalar = this.read_pointer(path_op)?; - let path = this.read_path_from_c_str(path_scalar)?.into_owned(); - - let metadata = match FileMetadata::from_path(this, &path, follow_symlink)? { - Some(metadata) => metadata, - None => return Ok(-1), - }; - this.macos_stat_write_buf(metadata, buf_op) - } - fn macos_stat_write_buf( &mut self, metadata: FileMetadata, @@ -504,13 +482,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - // Reject if isolation is enabled. - if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { - this.reject_in_isolation("`open`", reject_with)?; - this.set_last_error_from_io_error(ErrorKind::PermissionDenied)?; - return Ok(-1); - } - let flag = this.read_scalar(flag_op)?.to_i32()?; // Get the mode. On macOS, the argument type `mode_t` is actually `u16`, but @@ -588,6 +559,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let path = this.read_path_from_c_str(this.read_pointer(path_op)?)?; + // Reject if isolation is enabled. + if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { + this.reject_in_isolation("`open`", reject_with)?; + this.set_last_error_from_io_error(ErrorKind::PermissionDenied)?; + return Ok(-1); + } + let fd = options.open(&path).map(|file| { let fh = &mut this.machine.file_handler; fh.insert_fd(Box::new(FileHandle { file, writable })) @@ -599,13 +577,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn fcntl(&mut self, args: &[OpTy<'tcx, Tag>]) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - // Reject if isolation is enabled. - if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { - this.reject_in_isolation("`fcntl`", reject_with)?; - this.set_last_error_from_io_error(ErrorKind::PermissionDenied)?; - return Ok(-1); - } - if args.len() < 2 { throw_ub_format!( "incorrect number of arguments for fcntl: got {}, expected at least 2", @@ -614,6 +585,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } let fd = this.read_scalar(&args[0])?.to_i32()?; let cmd = this.read_scalar(&args[1])?.to_i32()?; + + // Reject if isolation is enabled. + if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { + this.reject_in_isolation("`fcntl`", reject_with)?; + this.set_last_error_from_io_error(ErrorKind::PermissionDenied)?; + return Ok(-1); + } + // We only support getting the flags for a descriptor. if cmd == this.eval_libc_i32("F_GETFD")? { // Currently this is the only flag that `F_GETFD` returns. It is OK to just return the @@ -795,6 +774,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn unlink(&mut self, path_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); + let path = this.read_path_from_c_str(this.read_pointer(path_op)?)?; + // Reject if isolation is enabled. if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { this.reject_in_isolation("`unlink`", reject_with)?; @@ -802,8 +783,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx return Ok(-1); } - let path = this.read_path_from_c_str(this.read_pointer(path_op)?)?; - let result = remove_file(path).map(|_| 0); this.try_unwrap_io_result(result) } @@ -825,6 +804,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } let this = self.eval_context_mut(); + let target = this.read_path_from_c_str(this.read_pointer(target_op)?)?; + let linkpath = this.read_path_from_c_str(this.read_pointer(linkpath_op)?)?; // Reject if isolation is enabled. if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { @@ -833,9 +814,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx return Ok(-1); } - let target = this.read_path_from_c_str(this.read_pointer(target_op)?)?; - let linkpath = this.read_path_from_c_str(this.read_pointer(linkpath_op)?)?; - let result = create_link(&target, &linkpath).map(|_| 0); this.try_unwrap_io_result(result) } @@ -848,6 +826,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); this.assert_target_os("macos", "stat"); + let path_scalar = this.read_pointer(path_op)?; + let path = this.read_path_from_c_str(path_scalar)?.into_owned(); + // Reject if isolation is enabled. if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { this.reject_in_isolation("`stat`", reject_with)?; @@ -857,7 +838,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // `stat` always follows symlinks. - this.macos_stat_or_lstat(true, path_op, buf_op) + let metadata = match FileMetadata::from_path(this, &path, true)? { + Some(metadata) => metadata, + None => return Ok(-1), + }; + + this.macos_stat_write_buf(metadata, buf_op) } // `lstat` is used to get symlink metadata. @@ -869,6 +855,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); this.assert_target_os("macos", "lstat"); + let path_scalar = this.read_pointer(path_op)?; + let path = this.read_path_from_c_str(path_scalar)?.into_owned(); + // Reject if isolation is enabled. if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { this.reject_in_isolation("`lstat`", reject_with)?; @@ -877,7 +866,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx return Ok(-1); } - this.macos_stat_or_lstat(false, path_op, buf_op) + let metadata = match FileMetadata::from_path(this, &path, false)? { + Some(metadata) => metadata, + None => return Ok(-1), + }; + + this.macos_stat_write_buf(metadata, buf_op) } fn macos_fstat( @@ -889,6 +883,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.assert_target_os("macos", "fstat"); + let fd = this.read_scalar(fd_op)?.to_i32()?; + // Reject if isolation is enabled. if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { this.reject_in_isolation("`fstat`", reject_with)?; @@ -896,8 +892,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx return this.handle_not_found(); } - let fd = this.read_scalar(fd_op)?.to_i32()?; - let metadata = match FileMetadata::from_fd(this, fd)? { Some(metadata) => metadata, None => return Ok(-1), @@ -973,8 +967,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // relative to CWD, `EACCES` is the most relevant. this.eval_libc("EACCES")? } else { - // `dirfd` is set to target file, and `path` is - // empty. `EACCES` would violate the spec. + // `dirfd` is set to target file, and `path` is empty + // (or we would have hit the `throw_unsup_format` + // above). `EACCES` would violate the spec. + assert!(empty_path_flag); this.eval_libc("EBADF")? }; this.set_last_error(ecode)?; @@ -1089,13 +1085,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - // Reject if isolation is enabled. - if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { - this.reject_in_isolation("`rename`", reject_with)?; - this.set_last_error_from_io_error(ErrorKind::PermissionDenied)?; - return Ok(-1); - } - let oldpath_ptr = this.read_pointer(oldpath_op)?; let newpath_ptr = this.read_pointer(newpath_op)?; @@ -1108,6 +1097,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let oldpath = this.read_path_from_c_str(oldpath_ptr)?; let newpath = this.read_path_from_c_str(newpath_ptr)?; + // Reject if isolation is enabled. + if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { + this.reject_in_isolation("`rename`", reject_with)?; + this.set_last_error_from_io_error(ErrorKind::PermissionDenied)?; + return Ok(-1); + } + let result = rename(oldpath, newpath).map(|_| 0); this.try_unwrap_io_result(result) @@ -1120,13 +1116,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - // Reject if isolation is enabled. - if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { - this.reject_in_isolation("`mkdir`", reject_with)?; - this.set_last_error_from_io_error(ErrorKind::PermissionDenied)?; - return Ok(-1); - } - #[cfg_attr(not(unix), allow(unused_variables))] let mode = if this.tcx.sess.target.os == "macos" { u32::from(this.read_scalar(mode_op)?.to_u16()?) @@ -1136,6 +1125,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let path = this.read_path_from_c_str(this.read_pointer(path_op)?)?; + // Reject if isolation is enabled. + if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { + this.reject_in_isolation("`mkdir`", reject_with)?; + this.set_last_error_from_io_error(ErrorKind::PermissionDenied)?; + return Ok(-1); + } + #[cfg_attr(not(unix), allow(unused_mut))] let mut builder = DirBuilder::new(); @@ -1155,6 +1151,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn rmdir(&mut self, path_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); + let path = this.read_path_from_c_str(this.read_pointer(path_op)?)?; + // Reject if isolation is enabled. if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { this.reject_in_isolation("`rmdir`", reject_with)?; @@ -1162,8 +1160,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx return Ok(-1); } - let path = this.read_path_from_c_str(this.read_pointer(path_op)?)?; - let result = remove_dir(path).map(|_| 0i32); this.try_unwrap_io_result(result) @@ -1172,6 +1168,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn opendir(&mut self, name_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); + let name = this.read_path_from_c_str(this.read_pointer(name_op)?)?; + // Reject if isolation is enabled. if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { this.reject_in_isolation("`opendir`", reject_with)?; @@ -1180,8 +1178,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx return Ok(Scalar::null_ptr(this)); } - let name = this.read_path_from_c_str(this.read_pointer(name_op)?)?; - let result = read_dir(name); match result { @@ -1210,6 +1206,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.assert_target_os("linux", "readdir64_r"); + let dirp = this.read_scalar(dirp_op)?.to_machine_usize(this)?; + // Reject if isolation is enabled. if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { this.reject_in_isolation("`readdir64_r`", reject_with)?; @@ -1217,8 +1215,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx return this.handle_not_found(); } - let dirp = this.read_scalar(dirp_op)?.to_machine_usize(this)?; - let dir_iter = this.machine.dir_handler.streams.get_mut(&dirp).ok_or_else(|| { err_unsup_format!("the DIR pointer passed to readdir64_r did not come from opendir") })?; @@ -1309,6 +1305,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.assert_target_os("macos", "readdir_r"); + let dirp = this.read_scalar(dirp_op)?.to_machine_usize(this)?; + // Reject if isolation is enabled. if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { this.reject_in_isolation("`readdir_r`", reject_with)?; @@ -1316,8 +1314,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx return this.handle_not_found(); } - let dirp = this.read_scalar(dirp_op)?.to_machine_usize(this)?; - let dir_iter = this.machine.dir_handler.streams.get_mut(&dirp).ok_or_else(|| { err_unsup_format!("the DIR pointer passed to readdir_r did not come from opendir") })?; @@ -1403,6 +1399,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn closedir(&mut self, dirp_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); + let dirp = this.read_scalar(dirp_op)?.to_machine_usize(this)?; + // Reject if isolation is enabled. if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { this.reject_in_isolation("`closedir`", reject_with)?; @@ -1410,8 +1408,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx return this.handle_not_found(); } - let dirp = this.read_scalar(dirp_op)?.to_machine_usize(this)?; - if let Some(dir_iter) = this.machine.dir_handler.streams.remove(&dirp) { drop(dir_iter); Ok(0) @@ -1427,6 +1423,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); + let fd = this.read_scalar(fd_op)?.to_i32()?; + let length = this.read_scalar(length_op)?.to_i64()?; + // Reject if isolation is enabled. if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { this.reject_in_isolation("`ftruncate64`", reject_with)?; @@ -1434,8 +1433,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx return this.handle_not_found(); } - let fd = this.read_scalar(fd_op)?.to_i32()?; - let length = this.read_scalar(length_op)?.to_i64()?; if let Some(file_descriptor) = this.machine.file_handler.handles.get_mut(&fd) { // FIXME: Support ftruncate64 for all FDs let FileHandle { file, writable } = file_descriptor.as_file_handle()?; @@ -1467,6 +1464,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); + let fd = this.read_scalar(fd_op)?.to_i32()?; + // Reject if isolation is enabled. if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { this.reject_in_isolation("`fsync`", reject_with)?; @@ -1474,7 +1473,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx return this.handle_not_found(); } - let fd = this.read_scalar(fd_op)?.to_i32()?; if let Some(file_descriptor) = this.machine.file_handler.handles.get(&fd) { // FIXME: Support fsync for all FDs let FileHandle { file, writable } = file_descriptor.as_file_handle()?; @@ -1488,6 +1486,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn fdatasync(&mut self, fd_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); + let fd = this.read_scalar(fd_op)?.to_i32()?; + // Reject if isolation is enabled. if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { this.reject_in_isolation("`fdatasync`", reject_with)?; @@ -1495,7 +1495,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx return this.handle_not_found(); } - let fd = this.read_scalar(fd_op)?.to_i32()?; if let Some(file_descriptor) = this.machine.file_handler.handles.get(&fd) { // FIXME: Support fdatasync for all FDs let FileHandle { file, writable } = file_descriptor.as_file_handle()?; @@ -1515,13 +1514,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - // Reject if isolation is enabled. - if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { - this.reject_in_isolation("`sync_file_range`", reject_with)?; - // Set error code as "EBADF" (bad fd) - return this.handle_not_found(); - } - let fd = this.read_scalar(fd_op)?.to_i32()?; let offset = this.read_scalar(offset_op)?.to_i64()?; let nbytes = this.read_scalar(nbytes_op)?.to_i64()?; @@ -1541,6 +1533,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx return Ok(-1); } + // Reject if isolation is enabled. + if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { + this.reject_in_isolation("`sync_file_range`", reject_with)?; + // Set error code as "EBADF" (bad fd) + return this.handle_not_found(); + } + if let Some(file_descriptor) = this.machine.file_handler.handles.get(&fd) { // FIXME: Support sync_data_range for all FDs let FileHandle { file, writable } = file_descriptor.as_file_handle()?; @@ -1559,6 +1558,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, i64> { let this = self.eval_context_mut(); + let pathname = this.read_path_from_c_str(this.read_pointer(pathname_op)?)?; + let buf = this.read_pointer(buf_op)?; + let bufsize = this.read_scalar(bufsize_op)?.to_machine_usize(this)?; + // Reject if isolation is enabled. if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { this.reject_in_isolation("`readlink`", reject_with)?; @@ -1567,10 +1570,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx return Ok(-1); } - let pathname = this.read_path_from_c_str(this.read_pointer(pathname_op)?)?; - let buf = this.read_pointer(buf_op)?; - let bufsize = this.read_scalar(bufsize_op)?.to_machine_usize(this)?; - let result = std::fs::read_link(pathname); match result { Ok(resolved) => { From 71efd950d17faabc4025acb460c4000bf97978f7 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 25 Jul 2021 14:08:12 +0200 Subject: [PATCH 2774/3747] also ignore 'thread leaks' with -Zmiri-ignore-leaks --- README.md | 3 ++- src/eval.rs | 6 +++++ src/thread.rs | 21 +++++++++------- .../libc_pthread_create_main_terminate.rs | 4 ++-- tests/run-pass/threadleak_ignored.rs | 24 +++++++++++++++++++ tests/run-pass/threadleak_ignored.stderr | 3 +++ 6 files changed, 49 insertions(+), 12 deletions(-) create mode 100644 tests/run-pass/threadleak_ignored.rs create mode 100644 tests/run-pass/threadleak_ignored.stderr diff --git a/README.md b/README.md index cbac48db5ea85..7cd802762bff2 100644 --- a/README.md +++ b/README.md @@ -230,7 +230,8 @@ environment variable: the host so that it cannot be accessed by the program. Can be used multiple times to exclude several variables. On Windows, the `TERM` environment variable is excluded by default. -* `-Zmiri-ignore-leaks` disables the memory leak checker. +* `-Zmiri-ignore-leaks` disables the memory leak checker, and also allows some + remaining threads to exist when the main thread exits. * `-Zmiri-measureme=` enables `measureme` profiling for the interpreted program. This can be used to find which parts of your program are executing slowly under Miri. The profile is written out to a file with the prefix ``, and can be processed diff --git a/src/eval.rs b/src/eval.rs index ae9ff9c1f5a42..9531a2d78aba6 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -300,6 +300,12 @@ pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) -> match res { Ok(return_code) => { if !ignore_leaks { + // Check for thread leaks. + if !ecx.have_all_terminated() { + tcx.sess.err("the main thread terminated without waiting for all remaining threads"); + return None; + } + // Check for memory leaks. info!("Additonal static roots: {:?}", ecx.machine.static_roots); let leaks = ecx.memory.leak_report(&ecx.machine.static_roots); if leaks != 0 { diff --git a/src/thread.rs b/src/thread.rs index de8e41224b20f..a5deceb6e71dc 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -302,6 +302,11 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { self.threads[thread_id].state == ThreadState::Terminated } + /// Have all threads terminated? + fn have_all_terminated(&self) -> bool { + self.threads.iter().all(|thread| thread.state == ThreadState::Terminated) + } + /// Enable the thread for execution. The thread must be terminated. fn enable_thread(&mut self, thread_id: ThreadId) { assert!(self.has_terminated(thread_id)); @@ -491,15 +496,7 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { // If we get here again and the thread is *still* terminated, there are no more dtors to run. if self.threads[MAIN_THREAD].state == ThreadState::Terminated { // The main thread terminated; stop the program. - if self.threads.iter().any(|thread| thread.state != ThreadState::Terminated) { - // FIXME: This check should be either configurable or just emit - // a warning. For example, it seems normal for a program to - // terminate without waiting for its detached threads to - // terminate. However, this case is not trivial to support - // because we also probably do not want to consider the memory - // owned by these threads as leaked. - throw_unsup_format!("the main thread terminated without waiting for other threads"); - } + // We do *not* run TLS dtors of remaining threads, which seems to match rustc behavior. return Ok(SchedulingAction::Stop); } // This thread and the program can keep going. @@ -645,6 +642,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.machine.threads.has_terminated(thread_id) } + #[inline] + fn have_all_terminated(&self) -> bool { + let this = self.eval_context_ref(); + this.machine.threads.have_all_terminated() + } + #[inline] fn enable_thread(&mut self, thread_id: ThreadId) { let this = self.eval_context_mut(); diff --git a/tests/compile-fail/concurrency/libc_pthread_create_main_terminate.rs b/tests/compile-fail/concurrency/libc_pthread_create_main_terminate.rs index 35ee03242d116..9b576bbb0868d 100644 --- a/tests/compile-fail/concurrency/libc_pthread_create_main_terminate.rs +++ b/tests/compile-fail/concurrency/libc_pthread_create_main_terminate.rs @@ -1,5 +1,5 @@ // ignore-windows: No libc on Windows -// error-pattern: unsupported operation: the main thread terminated without waiting for other threads +// error-pattern: the main thread terminated without waiting for all remaining threads // Check that we terminate the program when the main thread terminates. @@ -10,7 +10,7 @@ extern crate libc; use std::{mem, ptr}; extern "C" fn thread_start(_null: *mut libc::c_void) -> *mut libc::c_void { - ptr::null_mut() + loop {} } fn main() { diff --git a/tests/run-pass/threadleak_ignored.rs b/tests/run-pass/threadleak_ignored.rs new file mode 100644 index 0000000000000..14a7449f3392a --- /dev/null +++ b/tests/run-pass/threadleak_ignored.rs @@ -0,0 +1,24 @@ +// compile-flags: -Zmiri-ignore-leaks + +//! Test that leaking threads works, and that their destructors are not executed. + +use std::cell::RefCell; + +struct LoudDrop(i32); +impl Drop for LoudDrop { + fn drop(&mut self) { + eprintln!("Dropping {}", self.0); + } +} + +thread_local! { + static X: RefCell> = RefCell::new(None); +} + +fn main() { + X.with(|x| *x.borrow_mut() = Some(LoudDrop(0))); + + let _detached = std::thread::spawn(|| { + X.with(|x| *x.borrow_mut() = Some(LoudDrop(1))); + }); +} diff --git a/tests/run-pass/threadleak_ignored.stderr b/tests/run-pass/threadleak_ignored.stderr new file mode 100644 index 0000000000000..aa037511853b2 --- /dev/null +++ b/tests/run-pass/threadleak_ignored.stderr @@ -0,0 +1,3 @@ +warning: thread support is experimental and incomplete: weak memory effects are not emulated. + +Dropping 0 From df9d481989dee1dcbe9a3f886dcbb030deb2144b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 25 Jul 2021 14:19:57 +0200 Subject: [PATCH 2775/3747] tell users how to disable the leak check --- src/eval.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/eval.rs b/src/eval.rs index 9531a2d78aba6..e559dfedf933b 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -302,7 +302,10 @@ pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) -> if !ignore_leaks { // Check for thread leaks. if !ecx.have_all_terminated() { - tcx.sess.err("the main thread terminated without waiting for all remaining threads"); + tcx.sess.err( + "the main thread terminated without waiting for all remaining threads", + ); + tcx.sess.note_without_error("pass `-Zmiri-ignore-leaks` to disable this check"); return None; } // Check for memory leaks. @@ -310,6 +313,7 @@ pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) -> let leaks = ecx.memory.leak_report(&ecx.machine.static_roots); if leaks != 0 { tcx.sess.err("the evaluated program leaked memory"); + tcx.sess.note_without_error("pass `-Zmiri-ignore-leaks` to disable this check"); // Ignore the provided return code - let the reported error // determine the return code. return None; From 24fa9deddc8d5bf940ee89672cb819e802b39d43 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 25 Jul 2021 14:33:41 +0200 Subject: [PATCH 2776/3747] add test for mixing up System and Global memory --- tests/compile-fail/alloc/global_system_mixup.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 tests/compile-fail/alloc/global_system_mixup.rs diff --git a/tests/compile-fail/alloc/global_system_mixup.rs b/tests/compile-fail/alloc/global_system_mixup.rs new file mode 100644 index 0000000000000..afe9d5cc82540 --- /dev/null +++ b/tests/compile-fail/alloc/global_system_mixup.rs @@ -0,0 +1,13 @@ +// Make sure we detect when the `Global` and `System` allocators are mixed +// (even when the default `Global` uses `System`). +// error-pattern: which is Rust heap memory, using + +#![feature(allocator_api, slice_ptr_get)] + +use std::alloc::{Allocator, Global, System, Layout}; + +fn main() { + let l = Layout::from_size_align(1, 1).unwrap(); + let ptr = Global.allocate(l).unwrap().as_non_null_ptr(); + unsafe { System.deallocate(ptr, l); } +} From 679d10f98b765294aefbce61b525de407fc2cea4 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 25 Jul 2021 14:38:02 +0200 Subject: [PATCH 2777/3747] no concurrency on windows --- tests/run-pass/threadleak_ignored.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/run-pass/threadleak_ignored.rs b/tests/run-pass/threadleak_ignored.rs index 14a7449f3392a..840fbc1ebcbcb 100644 --- a/tests/run-pass/threadleak_ignored.rs +++ b/tests/run-pass/threadleak_ignored.rs @@ -1,3 +1,4 @@ +// ignore-windows: Concurrency on Windows is not supported yet. // compile-flags: -Zmiri-ignore-leaks //! Test that leaking threads works, and that their destructors are not executed. From 66aa3d0247fd47051077f005d2d1462316c83fe1 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 26 Jul 2021 21:54:28 +0200 Subject: [PATCH 2778/3747] make the loop infinite --- tests/run-pass/threadleak_ignored.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/run-pass/threadleak_ignored.rs b/tests/run-pass/threadleak_ignored.rs index 840fbc1ebcbcb..4fc52cdb8d7de 100644 --- a/tests/run-pass/threadleak_ignored.rs +++ b/tests/run-pass/threadleak_ignored.rs @@ -21,5 +21,6 @@ fn main() { let _detached = std::thread::spawn(|| { X.with(|x| *x.borrow_mut() = Some(LoudDrop(1))); + loop {} }); } From 78bcd12b17ae32fb74815cb2908a5149d5713415 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 27 Jul 2021 14:05:37 +0200 Subject: [PATCH 2779/3747] make sure we only terminate main thread once TLS is initialized --- tests/run-pass/threadleak_ignored.rs | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/tests/run-pass/threadleak_ignored.rs b/tests/run-pass/threadleak_ignored.rs index 4fc52cdb8d7de..7bb51d2dea61f 100644 --- a/tests/run-pass/threadleak_ignored.rs +++ b/tests/run-pass/threadleak_ignored.rs @@ -18,9 +18,20 @@ thread_local! { fn main() { X.with(|x| *x.borrow_mut() = Some(LoudDrop(0))); + + // Set up a channel so that we can learn when the other thread initialized `X` + // (so that we are sure there is something to drop). + let (send, recv) = std::sync::mpsc::channel::<()>(); - let _detached = std::thread::spawn(|| { + let _detached = std::thread::spawn(move || { X.with(|x| *x.borrow_mut() = Some(LoudDrop(1))); + send.send(()).unwrap(); + std::thread::yield_now(); loop {} }); + + std::thread::yield_now(); + + // Wait until child thread has initialized its `X`. + let () = recv.recv().unwrap(); } From c76fa2138e82eb5d93ac843102c5eea6e37830f0 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 27 Jul 2021 18:38:35 +0200 Subject: [PATCH 2780/3747] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index fb2d0bf8f682d..9b74f391bc9e2 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -718d53b0cb7dde93499cb92950d60b412f5a3d05 +3bc9dd0dd293ab82945e35888ed6d7ab802761ef From a789b49e4c0e7d742cc39713484596293d844537 Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Fri, 30 Jul 2021 21:28:34 +0800 Subject: [PATCH 2781/3747] Use `Lrc` instead of `Rc` in `MiriCompilerCalls::config()` --- src/bin/miri.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 5a8f07263f35b..18c393815ca5e 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -1,5 +1,6 @@ #![feature(rustc_private, bool_to_option, stmt_expr_attributes)] +extern crate rustc_data_structures; extern crate rustc_driver; extern crate rustc_errors; extern crate rustc_hir; @@ -12,12 +13,12 @@ use std::convert::TryFrom; use std::env; use std::num::NonZeroU64; use std::path::PathBuf; -use std::rc::Rc; use std::str::FromStr; use hex::FromHexError; use log::debug; +use rustc_data_structures::sync::Lrc; use rustc_driver::Compilation; use rustc_errors::emitter::{ColorConfig, HumanReadableErrorType}; use rustc_hir::{self as hir, def_id::LOCAL_CRATE, Node}; @@ -42,7 +43,7 @@ impl rustc_driver::Callbacks for MiriCompilerCalls { // HACK: rustc will emit "crate ... required to be available in rlib format, but // was not found in this form" errors once we use `tcx.dependency_formats()` if // there's no rlib provided, so setting a dummy path here to workaround those errors. - Rc::make_mut(&mut crate_source).rlib = Some((PathBuf::new(), PathKind::All)); + Lrc::make_mut(&mut crate_source).rlib = Some((PathBuf::new(), PathKind::All)); crate_source }; }); From 5338a16018878f27ac15bb353a7d1d719b3ddcd6 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 18 Jul 2021 12:47:04 +0200 Subject: [PATCH 2782/3747] adjust for ERR_ON_PARTIAL_PTR_OVERWRITE --- src/machine.rs | 4 ++++ ..._makes_the_rest_uninit.rs => pointer_partial_overwrite.rs} | 3 +++ .../{pointer_byte_read.rs => pointer_partial_read.rs} | 2 ++ 3 files changed, 9 insertions(+) rename tests/compile-fail/{overwriting_part_of_relocation_makes_the_rest_uninit.rs => pointer_partial_overwrite.rs} (82%) rename tests/compile-fail/{pointer_byte_read.rs => pointer_partial_read.rs} (67%) diff --git a/src/machine.rs b/src/machine.rs index 90e3d06aba99c..03f53033b798d 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -128,8 +128,12 @@ pub struct Tag { } impl Provenance for Tag { + // We use absolute addresses in the `offset` of a `Pointer`. const OFFSET_IS_ADDR: bool = true; + // We cannot err on partial overwrites, it happens too often in practice (due to unions). + const ERR_ON_PARTIAL_PTR_OVERWRITE: bool = false; + fn fmt(ptr: &Pointer, f: &mut fmt::Formatter<'_>) -> fmt::Result { let (tag, addr) = ptr.into_parts(); // address is absolute write!(f, "0x{:x}", addr.bytes())?; diff --git a/tests/compile-fail/overwriting_part_of_relocation_makes_the_rest_uninit.rs b/tests/compile-fail/pointer_partial_overwrite.rs similarity index 82% rename from tests/compile-fail/overwriting_part_of_relocation_makes_the_rest_uninit.rs rename to tests/compile-fail/pointer_partial_overwrite.rs index 3eab4c0f3d5eb..8bee58d20a59b 100644 --- a/tests/compile-fail/overwriting_part_of_relocation_makes_the_rest_uninit.rs +++ b/tests/compile-fail/pointer_partial_overwrite.rs @@ -1,6 +1,9 @@ // Make sure we find these even with many checks disabled. // compile-flags: -Zmiri-disable-alignment-check -Zmiri-disable-stacked-borrows -Zmiri-disable-validation +// Test what happens when we overwrite parts of a pointer. +// Also see . + fn main() { let mut p = &42; unsafe { diff --git a/tests/compile-fail/pointer_byte_read.rs b/tests/compile-fail/pointer_partial_read.rs similarity index 67% rename from tests/compile-fail/pointer_byte_read.rs rename to tests/compile-fail/pointer_partial_read.rs index dcb0fd3fb9066..a4a5071f5da09 100644 --- a/tests/compile-fail/pointer_byte_read.rs +++ b/tests/compile-fail/pointer_partial_read.rs @@ -1,3 +1,5 @@ +// Test what happens when we read parts of a pointer. +// Related to . fn main() { let x = 13; let y = &x; From 257e9cef66666cfce885fb44ca8f1edad2c79ac6 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 18 Jul 2021 15:22:09 +0200 Subject: [PATCH 2783/3747] docify some comments --- src/machine.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/machine.rs b/src/machine.rs index 03f53033b798d..62c1a93079cb0 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -123,15 +123,15 @@ impl fmt::Display for MiriMemoryKind { #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct Tag { pub alloc_id: AllocId, - // Stacked Borrows tag. + /// Stacked Borrows tag. pub sb: SbTag, } impl Provenance for Tag { - // We use absolute addresses in the `offset` of a `Pointer`. + /// We use absolute addresses in the `offset` of a `Pointer`. const OFFSET_IS_ADDR: bool = true; - // We cannot err on partial overwrites, it happens too often in practice (due to unions). + /// We cannot err on partial overwrites, it happens too often in practice (due to unions). const ERR_ON_PARTIAL_PTR_OVERWRITE: bool = false; fn fmt(ptr: &Pointer, f: &mut fmt::Formatter<'_>) -> fmt::Result { From 3a922286e31801a03ed52a31151f7b5f9f8ae4aa Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 2 Aug 2021 17:59:48 +0200 Subject: [PATCH 2784/3747] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 9b74f391bc9e2..ebcec429d18e5 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -3bc9dd0dd293ab82945e35888ed6d7ab802761ef +3227e35765bab6d02c581928e26ad1d34bacf394 From dced6b8518485aa8b6b069c09878d39bbb0ae22b Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Wed, 4 Aug 2021 16:46:11 +0800 Subject: [PATCH 2785/3747] Update cargo-miri test --- rust-version | 2 +- test-cargo-miri/test.default.stdout.ref | 5 +---- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/rust-version b/rust-version index ebcec429d18e5..c8725ea022520 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -3227e35765bab6d02c581928e26ad1d34bacf394 +71ff9b41e9ebd3e336019513917a7a8868d1cc66 diff --git a/test-cargo-miri/test.default.stdout.ref b/test-cargo-miri/test.default.stdout.ref index 4edcb7ba7d912..d2f94bb5950d8 100644 --- a/test-cargo-miri/test.default.stdout.ref +++ b/test-cargo-miri/test.default.stdout.ref @@ -11,9 +11,6 @@ test result: ok. 6 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out running 3 tests -test src/lib.rs - make_true (line 2) ... ok -test src/lib.rs - make_true (line 5) - compile ... ok -test src/lib.rs - make_true (line 8) - compile fail ... ok - +... test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME From d12d4050aeaff674457f111c67a21d37e8911b40 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 4 Aug 2021 11:25:33 +0200 Subject: [PATCH 2786/3747] improve test-cargo-miri output --- test-cargo-miri/run-test.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/test-cargo-miri/run-test.py b/test-cargo-miri/run-test.py index 51433d98a2ed2..81a1b1b3f8a7d 100755 --- a/test-cargo-miri/run-test.py +++ b/test-cargo-miri/run-test.py @@ -46,12 +46,13 @@ def test(name, cmd, stdout_ref, stderr_ref, stdin=b'', env={}): # All good! return # Show output - print("--- BEGIN stdout ---") + print("Test stdout or stderr did not match reference!") + print("--- BEGIN test stdout ---") print(stdout, end="") - print("--- END stdout ---") - print("--- BEGIN stderr ---") + print("--- END test stdout ---") + print("--- BEGIN test stderr ---") print(stderr, end="") - print("--- END stderr ---") + print("--- END test stderr ---") fail("exit code was {}".format(p.returncode)) def test_no_rebuild(name, cmd, env={}): From af7eb369b1eef147032e570d81dfc5c4e341b0ea Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Thu, 5 Aug 2021 17:10:30 +0800 Subject: [PATCH 2787/3747] Fix tests for `C-unwind` ABI changes --- rust-version | 2 +- tests/compile-fail/abort-terminator.rs | 5 ++--- .../function_calls/exported_symbol_bad_unwind2.rs | 4 ++-- .../function_calls/exported_symbol_bad_unwind3.rs | 15 --------------- tests/compile-fail/panic/bad_miri_start_panic.rs | 2 ++ .../function_calls/exported_symbol_good_unwind.rs | 13 +------------ .../exported_symbol_good_unwind.stderr | 5 ++--- .../exported_symbol_unwind_allowed.rs | 15 --------------- .../exported_symbol_unwind_allowed.stderr | 2 -- 9 files changed, 10 insertions(+), 53 deletions(-) delete mode 100644 tests/compile-fail/function_calls/exported_symbol_bad_unwind3.rs delete mode 100644 tests/run-pass/function_calls/exported_symbol_unwind_allowed.rs delete mode 100644 tests/run-pass/function_calls/exported_symbol_unwind_allowed.stderr diff --git a/rust-version b/rust-version index c8725ea022520..e40ae69e2877a 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -71ff9b41e9ebd3e336019513917a7a8868d1cc66 +996ff2e0a0f911f52bb1de6bdd0cfd5704de1fc9 diff --git a/tests/compile-fail/abort-terminator.rs b/tests/compile-fail/abort-terminator.rs index 73286a1759baf..8e6e2a766007e 100644 --- a/tests/compile-fail/abort-terminator.rs +++ b/tests/compile-fail/abort-terminator.rs @@ -1,8 +1,7 @@ // error-pattern: the program aborted -#![feature(unwind_attributes)] +#![feature(c_unwind)] -#[unwind(aborts)] -fn panic_abort() { panic!() } +extern "C" fn panic_abort() { panic!() } fn main() { panic_abort(); diff --git a/tests/compile-fail/function_calls/exported_symbol_bad_unwind2.rs b/tests/compile-fail/function_calls/exported_symbol_bad_unwind2.rs index 85cca8f1a6bd3..e80a79d1028dd 100644 --- a/tests/compile-fail/function_calls/exported_symbol_bad_unwind2.rs +++ b/tests/compile-fail/function_calls/exported_symbol_bad_unwind2.rs @@ -4,6 +4,8 @@ #[cfg_attr(any(definition, both), rustc_allocator_nounwind)] #[no_mangle] extern "C-unwind" fn nounwind() { + //[definition]~^ ERROR abnormal termination: the program aborted execution + //[both]~^^ ERROR abnormal termination: the program aborted execution panic!(); } @@ -14,6 +16,4 @@ fn main() { } unsafe { nounwind() } //[extern_block]~^ ERROR unwinding past a stack frame that does not allow unwinding - //[definition]~^^ ERROR unwinding past a stack frame that does not allow unwinding - //[both]~^^^ ERROR unwinding past a stack frame that does not allow unwinding } diff --git a/tests/compile-fail/function_calls/exported_symbol_bad_unwind3.rs b/tests/compile-fail/function_calls/exported_symbol_bad_unwind3.rs deleted file mode 100644 index bbbe677d3651e..0000000000000 --- a/tests/compile-fail/function_calls/exported_symbol_bad_unwind3.rs +++ /dev/null @@ -1,15 +0,0 @@ -#![feature(unwind_attributes)] - -#[unwind(allowed)] -#[no_mangle] -extern "C" fn unwind() { - panic!(); -} - -fn main() { - extern "C" { - fn unwind(); - } - unsafe { unwind() } - //~^ ERROR unwinding past a stack frame that does not allow unwinding -} diff --git a/tests/compile-fail/panic/bad_miri_start_panic.rs b/tests/compile-fail/panic/bad_miri_start_panic.rs index f77f892abc1c1..089cd86f1b8f8 100644 --- a/tests/compile-fail/panic/bad_miri_start_panic.rs +++ b/tests/compile-fail/panic/bad_miri_start_panic.rs @@ -1,4 +1,6 @@ // compile-flags: -Zmiri-disable-abi-check +// This feature is required to trigger the error using the "C" ABI. +#![feature(c_unwind)] extern "C" { fn miri_start_panic(payload: *mut u8) -> !; diff --git a/tests/run-pass/function_calls/exported_symbol_good_unwind.rs b/tests/run-pass/function_calls/exported_symbol_good_unwind.rs index 3dd3b8f22de57..71b799a1f12ba 100644 --- a/tests/run-pass/function_calls/exported_symbol_good_unwind.rs +++ b/tests/run-pass/function_calls/exported_symbol_good_unwind.rs @@ -2,16 +2,10 @@ // found in this form" errors works without `-C prefer-dynamic` (`panic!` calls foreign function // `__rust_start_panic`). // no-prefer-dynamic -#![feature(c_unwind, unboxed_closures, unwind_attributes)] +#![feature(c_unwind, unboxed_closures)] use std::panic; -#[no_mangle] -#[unwind(allowed)] -extern "C" fn good_unwind_allowed() { - panic!(); -} - #[no_mangle] extern "C-unwind" fn good_unwind_c() { panic!(); @@ -29,11 +23,6 @@ extern "rust-call" fn good_unwind_rust_call(_: ()) -> ! { } fn main() -> ! { - extern "C" { - #[unwind(allowed)] - fn good_unwind_allowed(); - } - panic::catch_unwind(|| unsafe { good_unwind_allowed() }).unwrap_err(); extern "C-unwind" { fn good_unwind_c(); } diff --git a/tests/run-pass/function_calls/exported_symbol_good_unwind.stderr b/tests/run-pass/function_calls/exported_symbol_good_unwind.stderr index 3347f00b65eab..40a8f39509fa7 100644 --- a/tests/run-pass/function_calls/exported_symbol_good_unwind.stderr +++ b/tests/run-pass/function_calls/exported_symbol_good_unwind.stderr @@ -1,5 +1,4 @@ -thread 'main' panicked at 'explicit panic', $DIR/exported_symbol_good_unwind.rs:12:5 +thread 'main' panicked at 'explicit panic', $DIR/exported_symbol_good_unwind.rs:11:5 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace -thread 'main' panicked at 'explicit panic', $DIR/exported_symbol_good_unwind.rs:17:5 +thread 'main' panicked at 'explicit panic', $DIR/exported_symbol_good_unwind.rs:16:5 thread 'main' panicked at 'explicit panic', $DIR/exported_symbol_good_unwind.rs:22:5 -thread 'main' panicked at 'explicit panic', $DIR/exported_symbol_good_unwind.rs:28:5 diff --git a/tests/run-pass/function_calls/exported_symbol_unwind_allowed.rs b/tests/run-pass/function_calls/exported_symbol_unwind_allowed.rs deleted file mode 100644 index 0e4ec5739a8a0..0000000000000 --- a/tests/run-pass/function_calls/exported_symbol_unwind_allowed.rs +++ /dev/null @@ -1,15 +0,0 @@ -// compile-flags: -Zmiri-disable-abi-check -#![feature(unwind_attributes, c_unwind)] - -#[no_mangle] -extern "C-unwind" fn unwind() { - panic!(); -} - -fn main() { - extern "C" { - #[unwind(allowed)] - fn unwind(); - } - unsafe { unwind() } -} diff --git a/tests/run-pass/function_calls/exported_symbol_unwind_allowed.stderr b/tests/run-pass/function_calls/exported_symbol_unwind_allowed.stderr deleted file mode 100644 index 14ee43950cec7..0000000000000 --- a/tests/run-pass/function_calls/exported_symbol_unwind_allowed.stderr +++ /dev/null @@ -1,2 +0,0 @@ -thread 'main' panicked at 'explicit panic', $DIR/exported_symbol_unwind_allowed.rs:6:5 -note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace From 78b4c7bf79cec9f2cef04a5dbb35609f83c8286c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 14 Aug 2021 14:47:57 +0200 Subject: [PATCH 2788/3747] rustup --- rust-version | 2 +- tests/compile-fail/function_calls/exported_symbol_wrong_type.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/rust-version b/rust-version index e40ae69e2877a..1cf2fb4b0ff9a 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -996ff2e0a0f911f52bb1de6bdd0cfd5704de1fc9 +fa2692990c05652c7823c8d2afae501a00a69050 diff --git a/tests/compile-fail/function_calls/exported_symbol_wrong_type.rs b/tests/compile-fail/function_calls/exported_symbol_wrong_type.rs index 3ffd506c94bb5..0a493e35a7ce6 100644 --- a/tests/compile-fail/function_calls/exported_symbol_wrong_type.rs +++ b/tests/compile-fail/function_calls/exported_symbol_wrong_type.rs @@ -5,5 +5,5 @@ fn main() { extern "C" { fn FOO(); } - unsafe { FOO() } //~ ERROR attempt to call an exported symbol that is not defined as a function + unsafe { FOO() } //~ ERROR unsupported operation: can't call foreign function: FOO } From 838ed1d75412f8c4ccb3750da6e67687af427520 Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Sun, 15 Aug 2021 17:18:00 +0800 Subject: [PATCH 2789/3747] Update tests for `#[no_mangle]` associated functions --- test-cargo-miri/exported-symbol-dep/src/lib.rs | 4 ++-- tests/run-pass/function_calls/exported_symbol.rs | 14 ++++++++++++++ 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/test-cargo-miri/exported-symbol-dep/src/lib.rs b/test-cargo-miri/exported-symbol-dep/src/lib.rs index db257dcb22c47..5b8a314ae7324 100644 --- a/test-cargo-miri/exported-symbol-dep/src/lib.rs +++ b/test-cargo-miri/exported-symbol-dep/src/lib.rs @@ -3,11 +3,11 @@ fn exported_symbol() -> i32 { 123456 } -pub struct AssocFn; +struct AssocFn; impl AssocFn { #[no_mangle] - pub fn assoc_fn_as_exported_symbol() -> i32 { + fn assoc_fn_as_exported_symbol() -> i32 { -123456 } } diff --git a/tests/run-pass/function_calls/exported_symbol.rs b/tests/run-pass/function_calls/exported_symbol.rs index 58115542332f2..ff56bb78a2187 100644 --- a/tests/run-pass/function_calls/exported_symbol.rs +++ b/tests/run-pass/function_calls/exported_symbol.rs @@ -15,6 +15,16 @@ fn baz() -> i32 { -3 } +struct AssocFn; + +impl AssocFn { + #[no_mangle] + fn qux() -> i32 { + -4 + } +} + + fn main() { // Repeat calls to make sure the `Instance` cache is not broken. for _ in 0..3 { @@ -32,10 +42,12 @@ fn main() { extern "Rust" { fn bar() -> i32; fn baz() -> i32; + fn qux() -> i32; } assert_eq!(unsafe { bar() }, -2); assert_eq!(unsafe { baz() }, -3); + assert_eq!(unsafe { qux() }, -4); #[allow(clashing_extern_declarations)] { @@ -53,6 +65,7 @@ fn main() { extern "C" { fn bar() -> i32; fn baz() -> i32; + fn qux() -> i32; } unsafe { @@ -61,6 +74,7 @@ fn main() { }; assert_eq!(transmute(bar)(), -2); assert_eq!(transmute(baz)(), -3); + assert_eq!(transmute(qux)(), -4); } } } From 9a6a5119fc3d6b40eeca8b6ec869af665fbe8ade Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 16 Aug 2021 17:09:21 +0200 Subject: [PATCH 2790/3747] rustup --- rust-version | 2 +- tests/compile-fail/function_calls/exported_symbol_wrong_type.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/rust-version b/rust-version index 1cf2fb4b0ff9a..6b176cc97bdbb 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -fa2692990c05652c7823c8d2afae501a00a69050 +73d96b090bb68065cd3a469b27cbd568e39bf0e7 diff --git a/tests/compile-fail/function_calls/exported_symbol_wrong_type.rs b/tests/compile-fail/function_calls/exported_symbol_wrong_type.rs index 0a493e35a7ce6..3ffd506c94bb5 100644 --- a/tests/compile-fail/function_calls/exported_symbol_wrong_type.rs +++ b/tests/compile-fail/function_calls/exported_symbol_wrong_type.rs @@ -5,5 +5,5 @@ fn main() { extern "C" { fn FOO(); } - unsafe { FOO() } //~ ERROR unsupported operation: can't call foreign function: FOO + unsafe { FOO() } //~ ERROR attempt to call an exported symbol that is not defined as a function } From 2c14bab76f8779fd629bec1ffa737f68ea19115f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 16 Aug 2021 17:34:48 +0200 Subject: [PATCH 2791/3747] =?UTF-8?q?llvm=5Fasm=20=E2=86=92=20asm?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- test-cargo-miri/build.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test-cargo-miri/build.rs b/test-cargo-miri/build.rs index 3e84d69eec804..31d251bc67894 100644 --- a/test-cargo-miri/build.rs +++ b/test-cargo-miri/build.rs @@ -1,4 +1,4 @@ -#![feature(llvm_asm)] +#![feature(asm)] use std::env; @@ -7,9 +7,9 @@ compile_error!("`miri` cfg should not be set in build script"); fn not_in_miri() -> i32 { // Inline assembly definitely does not work in Miri. - let dummy = 42; + let mut dummy = 42; unsafe { - llvm_asm!("" : : "r"(&dummy)); + asm!("/* {} */", in(reg) &mut dummy); } return dummy; } From a0d4372ff9bf773a64c9dc7c51ef0392817c27ee Mon Sep 17 00:00:00 2001 From: Frank Steffahn Date: Sun, 22 Aug 2021 14:28:05 +0200 Subject: [PATCH 2792/3747] =?UTF-8?q?Fix=20typos=20=E2=80=9Ca=E2=80=9D?= =?UTF-8?q?=E2=86=92=E2=80=9Can=E2=80=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/data_race.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/data_race.rs b/src/data_race.rs index 6a64c1cb69369..9e5dfd9dbaf0d 100644 --- a/src/data_race.rs +++ b/src/data_race.rs @@ -42,7 +42,7 @@ //! order exists in which all threads observe all modifications in the same //! order (see Sequentially-consistent ordering below) " //! So in the absence of weak memory effects a seq-cst load & a seq-cst store is identical -//! to a acquire load and a release store given the global sequentially consistent order +//! to an acquire load and a release store given the global sequentially consistent order //! of the schedule. //! //! The timestamps used in the data-race detector assign each sequence of non-atomic operations @@ -142,7 +142,7 @@ impl ThreadClockSet { self.fence_release.clone_from(&self.clock); } - /// Apply the effects of a acquire fence to this + /// Apply the effects of an acquire fence to this /// set of thread vector clocks. #[inline] fn apply_acquire_fence(&mut self) { @@ -503,7 +503,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { this.validate_atomic_store(dest, atomic) } - /// Perform a atomic operation on a memory location. + /// Perform an atomic operation on a memory location. fn atomic_op_immediate( &mut self, place: &MPlaceTy<'tcx, Tag>, @@ -695,7 +695,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { log::trace!("Atomic fence on {:?} with ordering {:?}", index, atomic); // Apply data-race detection for the current fences - // this treats AcqRel and SeqCst as the same as a acquire + // this treats AcqRel and SeqCst as the same as an acquire // and release fence applied in the same timestamp. if atomic != AtomicFenceOp::Release { // Either Acquire | AcqRel | SeqCst From 32c2df87be28205eb87a12362b085917a2a58dc5 Mon Sep 17 00:00:00 2001 From: niluxv Date: Sun, 22 Aug 2021 17:48:31 +0200 Subject: [PATCH 2793/3747] Add support for the `volatile_set_memory` intrinsic Runtime behaviour and soundness requirements are identical to `write_bytes`. --- src/shims/intrinsics.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 5a3a782382dd5..317bba8592958 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -66,7 +66,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.copy_op(dest, &place.into())?; } - "write_bytes" => { + "write_bytes" | "volatile_set_memory" => { let &[ref ptr, ref val_byte, ref count] = check_arg_count(args)?; let ty = instance.substs.type_at(0); let ty_layout = this.layout_of(ty)?; @@ -74,7 +74,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let ptr = this.read_pointer(ptr)?; let count = this.read_scalar(count)?.to_machine_usize(this)?; let byte_count = ty_layout.size.checked_mul(count, this).ok_or_else(|| { - err_ub_format!("overflow computing total size of `write_bytes`") + err_ub_format!("overflow computing total size of `{}`", intrinsic_name) })?; this.memory .write_bytes(ptr, iter::repeat(val_byte).take(byte_count.bytes() as usize))?; From c79f6dd5a0769aa753bf04442cf70e1af98f0962 Mon Sep 17 00:00:00 2001 From: Frank Steffahn Date: Sun, 22 Aug 2021 18:07:01 +0200 Subject: [PATCH 2794/3747] =?UTF-8?q?Fix=20a=20typo=20=E2=80=9Can=E2=80=9D?= =?UTF-8?q?=E2=86=92=E2=80=9Ca=E2=80=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/helpers.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/helpers.rs b/src/helpers.rs index e09ef2865fb2b..1b68316902356 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -78,7 +78,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx self.eval_context_mut().eval_path_scalar(&["std", "sys", "windows", module, name]) } - /// Helper function to get a `windows` constant as an `u64`. + /// Helper function to get a `windows` constant as a `u64`. fn eval_windows_u64(&mut self, module: &str, name: &str) -> InterpResult<'tcx, u64> { // TODO: Cache the result. self.eval_windows(module, name)?.to_u64() From 083e5e604c304d8743a942ef33def704fa4b6012 Mon Sep 17 00:00:00 2001 From: niluxv Date: Mon, 23 Aug 2021 12:42:13 +0200 Subject: [PATCH 2795/3747] Add test for `volatile_set_memory` --- tests/run-pass/write-bytes.rs | 40 +++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/tests/run-pass/write-bytes.rs b/tests/run-pass/write-bytes.rs index 7c9a38fca696d..b2050c5393e22 100644 --- a/tests/run-pass/write-bytes.rs +++ b/tests/run-pass/write-bytes.rs @@ -1,3 +1,5 @@ +#![feature(core_intrinsics)] // for `volatile_set_memory` + #[repr(C)] #[derive(Copy, Clone)] struct Foo { @@ -42,4 +44,42 @@ fn main() { assert_eq!(w[idx].b, 0xcdcdcdcdcdcdcdcd); assert_eq!(w[idx].c, 0xcdcdcdcdcdcdcdcd); } + + // ----- + // `std::intrinsics::volatile_set_memory` should behave identically + + let mut v: [u64; LENGTH] = [0; LENGTH]; + + for idx in 0..LENGTH { + assert_eq!(v[idx], 0); + } + + unsafe { + let p = v.as_mut_ptr(); + ::std::intrinsics::volatile_set_memory(p, 0xab, LENGTH); + } + + for idx in 0..LENGTH { + assert_eq!(v[idx], 0xabababababababab); + } + + // ----- + + let mut w: [Foo; LENGTH] = [Foo { a: 0, b: 0, c: 0 }; LENGTH]; + for idx in 0..LENGTH { + assert_eq!(w[idx].a, 0); + assert_eq!(w[idx].b, 0); + assert_eq!(w[idx].c, 0); + } + + unsafe { + let p = w.as_mut_ptr(); + ::std::intrinsics::volatile_set_memory(p, 0xcd, LENGTH); + } + + for idx in 0..LENGTH { + assert_eq!(w[idx].a, 0xcdcdcdcdcdcdcdcd); + assert_eq!(w[idx].b, 0xcdcdcdcdcdcdcdcd); + assert_eq!(w[idx].c, 0xcdcdcdcdcdcdcdcd); + } } From 33a67c6b33e91b5de01b9421a59a2f92233643a0 Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Tue, 24 Aug 2021 18:42:43 +0800 Subject: [PATCH 2796/3747] Add `#[allow(unreachable_code)]` to `drop(x)` in `tests/run-pass/generator.rs` --- rust-version | 2 +- tests/run-pass/generator.rs | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 6b176cc97bdbb..2805654a75e32 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -73d96b090bb68065cd3a469b27cbd568e39bf0e7 +f66e825f73d2bd7f8a763b723983850f891985b0 diff --git a/tests/run-pass/generator.rs b/tests/run-pass/generator.rs index 18eaf5e55c15d..b2039e555f514 100644 --- a/tests/run-pass/generator.rs +++ b/tests/run-pass/generator.rs @@ -94,6 +94,7 @@ fn basic() { #[allow(unused)] let x = never(); yield 2; + #[allow(unreachable_code)] drop(x); }); From 450e110b5088cf7f48f8301732ccdeda8dc1b315 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Tue, 24 Aug 2021 15:03:36 +0000 Subject: [PATCH 2797/3747] Try out gitpod --- .gitpod.yml | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 .gitpod.yml diff --git a/.gitpod.yml b/.gitpod.yml new file mode 100644 index 0000000000000..36bd991740a82 --- /dev/null +++ b/.gitpod.yml @@ -0,0 +1,9 @@ +image: ubuntu:latest + +tasks: + - before: echo "..." + init: | + cargo install rustup-toolchain-install-master + ./rustup-toolchain + ./miri build + command: echo "Run tests with ./miri test" \ No newline at end of file From 7301fe118a35ad52e23cb217ce4e12e207e9ec31 Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Thu, 26 Aug 2021 16:16:43 +0800 Subject: [PATCH 2798/3747] Move `#[allow(unreachable_code)]` in `tests/run-pass/generator.rs` --- rust-version | 2 +- tests/run-pass/generator.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/rust-version b/rust-version index 2805654a75e32..2cce8290c913b 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -f66e825f73d2bd7f8a763b723983850f891985b0 +c4be230b4a30eb74e3a3908455731ebc2f731d3d diff --git a/tests/run-pass/generator.rs b/tests/run-pass/generator.rs index b2039e555f514..9d786edc5ae2c 100644 --- a/tests/run-pass/generator.rs +++ b/tests/run-pass/generator.rs @@ -93,8 +93,8 @@ fn basic() { if b { return; } #[allow(unused)] let x = never(); - yield 2; #[allow(unreachable_code)] + yield 2; drop(x); }); From 35b64447f385b1908b1de2eb7dc673f1fd3817ba Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 30 Aug 2021 10:35:34 -0400 Subject: [PATCH 2799/3747] rustup --- rust-version | 2 +- src/shims/intrinsics.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/rust-version b/rust-version index 2cce8290c913b..4dab723fbddc3 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -c4be230b4a30eb74e3a3908455731ebc2f731d3d +6cfa773583bb5123e630668f5bfe466716225546 diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 317bba8592958..fd1a3f3e598ba 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -518,7 +518,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ))) } if intrinsic_name == "assert_zero_valid" - && !layout.might_permit_raw_init(this, /*zero:*/ true).unwrap() + && !layout.might_permit_raw_init(this, /*zero:*/ true) { throw_machine_stop!(TerminationInfo::Abort(format!( "aborted execution: attempted to zero-initialize type `{}`, which is invalid", @@ -526,7 +526,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ))) } if intrinsic_name == "assert_uninit_valid" - && !layout.might_permit_raw_init(this, /*zero:*/ false).unwrap() + && !layout.might_permit_raw_init(this, /*zero:*/ false) { throw_machine_stop!(TerminationInfo::Abort(format!( "aborted execution: attempted to leave type `{}` uninitialized, which is invalid", From 8d797fb15481b467d721de9222b0cfa35ce0b14a Mon Sep 17 00:00:00 2001 From: "Samuel E. Moelius III" Date: Wed, 1 Sep 2021 08:53:51 -0400 Subject: [PATCH 2800/3747] Update compiletest_rs dependency --- Cargo.lock | 4 ++-- Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index e728dc07b9286..0dbd1b8656897 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -53,9 +53,9 @@ dependencies = [ [[package]] name = "compiletest_rs" -version = "0.6.0" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0086d6ad78cf409c3061618cd98e2789d5c9ce598fc9651611cf62eae0a599cb" +checksum = "64698e5e2435db061a85e6320af12c30c5fd88eb84b35d2c1e03ce4f143255ca" dependencies = [ "diff", "filetime", diff --git a/Cargo.toml b/Cargo.toml index 7ee96f7e99e68..82962c6b98aa0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -38,7 +38,7 @@ measureme = "9.1.2" libc = "0.2" [dev-dependencies] -compiletest_rs = { version = "0.6", features = ["tmp"] } +compiletest_rs = { version = "0.7", features = ["tmp"] } rustc_version = "0.3" colored = "2" From 84b058ac47e2ea5f29887a4ed5ae286e37b22194 Mon Sep 17 00:00:00 2001 From: DrMeepster <19316085+DrMeepster@users.noreply.github.com> Date: Thu, 2 Sep 2021 15:41:10 -0700 Subject: [PATCH 2801/3747] add support for #[start] --- benches/helpers/miri_helper.rs | 5 +- src/bin/miri.rs | 6 +-- src/eval.rs | 92 +++++++++++++++++++++++----------- src/lib.rs | 2 +- tests/run-pass/start.rs | 8 +++ tests/run-pass/start.stdout | 1 + 6 files changed, 79 insertions(+), 35 deletions(-) create mode 100644 tests/run-pass/start.rs create mode 100644 tests/run-pass/start.stdout diff --git a/benches/helpers/miri_helper.rs b/benches/helpers/miri_helper.rs index 2d27616a3613f..be542c2bc0a6a 100644 --- a/benches/helpers/miri_helper.rs +++ b/benches/helpers/miri_helper.rs @@ -20,11 +20,12 @@ impl rustc_driver::Callbacks for MiriCompilerCalls<'_> { compiler.session().abort_if_errors(); queries.global_ctxt().unwrap().peek_mut().enter(|tcx| { - let (entry_def_id, _) = tcx.entry_fn(()).expect("no main or start function found"); + let (entry_def_id, entry_type) = + tcx.entry_fn(()).expect("no main or start function found"); self.bencher.iter(|| { let config = miri::MiriConfig::default(); - miri::eval_main(tcx, entry_def_id, config); + miri::eval_entry(tcx, entry_def_id, entry_type, config); }); }); diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 18c393815ca5e..fbc87148ec7b7 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -58,8 +58,8 @@ impl rustc_driver::Callbacks for MiriCompilerCalls { queries.global_ctxt().unwrap().peek_mut().enter(|tcx| { init_late_loggers(tcx); - let (entry_def_id, _) = if let Some((entry_def, x)) = tcx.entry_fn(()) { - (entry_def, x) + let (entry_def_id, entry_type) = if let Some(entry_def) = tcx.entry_fn(()) { + entry_def } else { let output_ty = ErrorOutputType::HumanReadable(HumanReadableErrorType::Default( ColorConfig::Auto, @@ -79,7 +79,7 @@ impl rustc_driver::Callbacks for MiriCompilerCalls { env::set_current_dir(cwd).unwrap(); } - if let Some(return_code) = miri::eval_main(tcx, entry_def_id, config) { + if let Some(return_code) = miri::eval_entry(tcx, entry_def_id, entry_type, config) { std::process::exit( i32::try_from(return_code).expect("Return value was too large!"), ); diff --git a/src/eval.rs b/src/eval.rs index 2b8fc0f5adee2..f90a77fafd5a1 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -10,6 +10,8 @@ use rustc_middle::ty::{self, layout::LayoutCx, TyCtxt}; use rustc_target::abi::LayoutOf; use rustc_target::spec::abi::Abi; +use rustc_session::config::EntryFnType; + use crate::*; #[derive(Copy, Clone, Debug, PartialEq)] @@ -117,12 +119,13 @@ impl Default for MiriConfig { } /// Returns a freshly created `InterpCx`, along with an `MPlaceTy` representing -/// the location where the return value of the `start` lang item will be +/// the location where the return value of the `start` function will be /// written to. /// Public because this is also used by `priroda`. pub fn create_ecx<'mir, 'tcx: 'mir>( tcx: TyCtxt<'tcx>, - main_id: DefId, + entry_id: DefId, + entry_type: EntryFnType, config: MiriConfig, ) -> InterpResult<'tcx, (InterpCx<'mir, 'tcx, Evaluator<'mir, 'tcx>>, MPlaceTy<'tcx, Tag>)> { let param_env = ty::ParamEnv::reveal_all(); @@ -145,26 +148,14 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( } // Setup first stack-frame - let main_instance = ty::Instance::mono(tcx, main_id); - let main_mir = ecx.load_mir(main_instance.def, None)?; + let entry_instance = ty::Instance::mono(tcx, entry_id); + /*let entry_mir = ecx.load_mir(entry_instance.def, None)?; if main_mir.arg_count != 0 { bug!("main function must not take any arguments"); - } + }*/ + + // First argument is constructed later, because its skipped if the entry function uses #[start] - let start_id = tcx.lang_items().start_fn().unwrap(); - let main_ret_ty = tcx.fn_sig(main_id).output(); - let main_ret_ty = main_ret_ty.no_bound_vars().unwrap(); - let start_instance = ty::Instance::resolve( - tcx, - ty::ParamEnv::reveal_all(), - start_id, - tcx.mk_substs(::std::iter::once(ty::subst::GenericArg::from(main_ret_ty))), - ) - .unwrap() - .unwrap(); - - // First argument: pointer to `main()`. - let main_ptr = ecx.memory.create_fn_alloc(FnVal::Instance(main_instance)); // Second argument (argc): length of `config.args`. let argc = Scalar::from_machine_usize(u64::try_from(config.args.len()).unwrap(), &ecx); // Third argument (`argv`): created from `config.args`. @@ -237,28 +228,71 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( argv }; + /*let args: &[_] = match entry_type { + EntryFnType::Main => { + // First argument: pointer to `main()`. + let main_ptr = ecx.memory.create_fn_alloc(FnVal::Instance(main_instance)); + + &[Scalar::from_pointer(main_ptr, &ecx).into(), argc.into(), argv] + } + EntryFnType::Start => &[argc.into(), argv], + };*/ + // Return place (in static memory so that it does not count as leak). let ret_place = ecx.allocate(ecx.machine.layouts.isize, MiriMemoryKind::Machine.into())?; // Call start function. - ecx.call_function( - start_instance, - Abi::Rust, - &[Scalar::from_pointer(main_ptr, &ecx).into(), argc.into(), argv], - Some(&ret_place.into()), - StackPopCleanup::None { cleanup: true }, - )?; + + match entry_type { + EntryFnType::Main => { + let start_id = tcx.lang_items().start_fn().unwrap(); + let main_ret_ty = tcx.fn_sig(entry_id).output(); + let main_ret_ty = main_ret_ty.no_bound_vars().unwrap(); + let start_instance = ty::Instance::resolve( + tcx, + ty::ParamEnv::reveal_all(), + start_id, + tcx.mk_substs(::std::iter::once(ty::subst::GenericArg::from(main_ret_ty))), + ) + .unwrap() + .unwrap(); + + let main_ptr = ecx.memory.create_fn_alloc(FnVal::Instance(entry_instance)); + + ecx.call_function( + start_instance, + Abi::Rust, + &[Scalar::from_pointer(main_ptr, &ecx).into(), argc.into(), argv], + Some(&ret_place.into()), + StackPopCleanup::None { cleanup: true }, + )?; + } + EntryFnType::Start => { + ecx.call_function( + entry_instance, + Abi::Rust, + &[argc.into(), argv], + Some(&ret_place.into()), + StackPopCleanup::None { cleanup: true }, + )?; + } + } Ok((ecx, ret_place)) } -/// Evaluates the main function specified by `main_id`. +/// Evaluates the entry function specified by `entry_id`. /// Returns `Some(return_code)` if program executed completed. /// Returns `None` if an evaluation error occured. -pub fn eval_main<'tcx>(tcx: TyCtxt<'tcx>, main_id: DefId, config: MiriConfig) -> Option { +pub fn eval_entry<'tcx>( + tcx: TyCtxt<'tcx>, + entry_id: DefId, + entry_type: EntryFnType, + config: MiriConfig, +) -> Option { // Copy setting before we move `config`. let ignore_leaks = config.ignore_leaks; - let (mut ecx, ret_place) = match create_ecx(tcx, main_id, config) { + let (mut ecx, ret_place) = match create_ecx(tcx, entry_id, entry_type, config) { Ok(v) => v, Err(err) => { err.print_backtrace(); diff --git a/src/lib.rs b/src/lib.rs index f8d8aacce3c9e..7ed915b6d1d4b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -60,7 +60,7 @@ pub use crate::diagnostics::{ NonHaltingDiagnostic, TerminationInfo, }; pub use crate::eval::{ - create_ecx, eval_main, AlignmentCheck, IsolatedOp, MiriConfig, RejectOpWith, + create_ecx, eval_entry, AlignmentCheck, IsolatedOp, MiriConfig, RejectOpWith, }; pub use crate::helpers::EvalContextExt as HelpersEvalContextExt; pub use crate::machine::{ diff --git a/tests/run-pass/start.rs b/tests/run-pass/start.rs new file mode 100644 index 0000000000000..f25d62fa8c335 --- /dev/null +++ b/tests/run-pass/start.rs @@ -0,0 +1,8 @@ +#![feature(start)] + +#[start] +fn start(_: isize, _: *const *const u8) -> isize { + println!("Hello from start!"); + + 0 +} diff --git a/tests/run-pass/start.stdout b/tests/run-pass/start.stdout new file mode 100644 index 0000000000000..d7f627d237c3e --- /dev/null +++ b/tests/run-pass/start.stdout @@ -0,0 +1 @@ +Hello from start! From 1ec28f78f3c9c68a850ac943a6d2100266782dc1 Mon Sep 17 00:00:00 2001 From: DrMeepster <19316085+DrMeepster@users.noreply.github.com> Date: Thu, 2 Sep 2021 15:45:52 -0700 Subject: [PATCH 2802/3747] remove commented out code --- src/eval.rs | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/src/eval.rs b/src/eval.rs index f90a77fafd5a1..151243f29a92f 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -149,10 +149,6 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( // Setup first stack-frame let entry_instance = ty::Instance::mono(tcx, entry_id); - /*let entry_mir = ecx.load_mir(entry_instance.def, None)?; - if main_mir.arg_count != 0 { - bug!("main function must not take any arguments"); - }*/ // First argument is constructed later, because its skipped if the entry function uses #[start] @@ -228,16 +224,6 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( argv }; - /*let args: &[_] = match entry_type { - EntryFnType::Main => { - // First argument: pointer to `main()`. - let main_ptr = ecx.memory.create_fn_alloc(FnVal::Instance(main_instance)); - - &[Scalar::from_pointer(main_ptr, &ecx).into(), argc.into(), argv] - } - EntryFnType::Start => &[argc.into(), argv], - };*/ - // Return place (in static memory so that it does not count as leak). let ret_place = ecx.allocate(ecx.machine.layouts.isize, MiriMemoryKind::Machine.into())?; // Call start function. From 78c031204d2602916fafd0012c240556cd0ee296 Mon Sep 17 00:00:00 2001 From: Noah Lev Date: Sun, 5 Sep 2021 10:05:43 -0700 Subject: [PATCH 2803/3747] Stage 2 seems to be required after all Reverts most of bb59980b2da10437ce1ee4d53bdb3feb1f4a9c5f. --- CONTRIBUTING.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 9edd63dae3157..eea97863d3e24 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -148,15 +148,15 @@ cd rustc ./x.py setup compiler # Now edit `config.toml` and under `[rust]` set `debug-assertions = true`. -# Build a stage 1 rustc, and build the rustc libraries with that rustc. +# Build a stage 2 rustc, and build the rustc libraries with that rustc. # This step can take 30 minutes or more. -./x.py build --stage 1 compiler/rustc +./x.py build --stage 2 compiler/rustc # If you change something, you can get a faster rebuild by doing -./x.py build --keep-stage 0 --stage 1 compiler/rustc +./x.py build --keep-stage 0 --stage 2 compiler/rustc # You may have to change the architecture in the next command -rustup toolchain link stage1 build/x86_64-unknown-linux-gnu/stage1 +rustup toolchain link stage2 build/x86_64-unknown-linux-gnu/stage2 # Now cd to your Miri directory, then configure rustup -rustup override set stage1 +rustup override set stage2 ``` For more information about building and configuring a local compiler, From 3fedc7b249fd5f9450b6c2d2df28a5b828166ac9 Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Mon, 6 Sep 2021 23:05:48 +0800 Subject: [PATCH 2804/3747] `rustc_target::abi::LayoutOf` -> `rustc_middle::ty::layout::LayoutOf` --- rust-version | 2 +- src/eval.rs | 7 +++++-- src/helpers.rs | 8 ++++++-- src/machine.rs | 4 ++-- src/shims/backtrace.rs | 2 +- src/shims/env.rs | 3 ++- src/shims/intrinsics.rs | 4 ++-- src/shims/os_str.rs | 3 ++- src/shims/posix/foreign_items.rs | 3 ++- src/shims/posix/fs.rs | 4 ++-- src/shims/posix/thread.rs | 2 +- src/stacked_borrows.rs | 4 ++-- 12 files changed, 28 insertions(+), 18 deletions(-) diff --git a/rust-version b/rust-version index 4dab723fbddc3..33be6b9182b89 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -6cfa773583bb5123e630668f5bfe466716225546 +1c858ba5bf7bd06c1a970efbf77053c8380b3151 diff --git a/src/eval.rs b/src/eval.rs index 2b8fc0f5adee2..f6adbd48cd5c4 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -6,8 +6,11 @@ use std::ffi::OsStr; use log::info; use rustc_hir::def_id::DefId; -use rustc_middle::ty::{self, layout::LayoutCx, TyCtxt}; -use rustc_target::abi::LayoutOf; +use rustc_middle::ty::{ + self, + layout::{LayoutCx, LayoutOf}, + TyCtxt, +}; use rustc_target::spec::abi::Abi; use crate::*; diff --git a/src/helpers.rs b/src/helpers.rs index 1b68316902356..081712dddc838 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -7,9 +7,13 @@ use log::trace; use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX}; use rustc_middle::mir; -use rustc_middle::ty::{self, layout::TyAndLayout, List, TyCtxt}; +use rustc_middle::ty::{ + self, + layout::{LayoutOf, TyAndLayout}, + List, TyCtxt, +}; use rustc_span::Symbol; -use rustc_target::abi::{Align, FieldsShape, LayoutOf, Size, Variants}; +use rustc_target::abi::{Align, FieldsShape, Size, Variants}; use rustc_target::spec::abi::Abi; use rand::RngCore; diff --git a/src/machine.rs b/src/machine.rs index 62c1a93079cb0..fb39503b53858 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -16,13 +16,13 @@ use rustc_middle::{ mir, ty::{ self, - layout::{LayoutCx, LayoutError, TyAndLayout}, + layout::{LayoutCx, LayoutError, LayoutOf, TyAndLayout}, Instance, TyCtxt, }, }; use rustc_span::def_id::DefId; use rustc_span::symbol::{sym, Symbol}; -use rustc_target::abi::{LayoutOf, Size}; +use rustc_target::abi::Size; use rustc_target::spec::abi::Abi; use crate::*; diff --git a/src/shims/backtrace.rs b/src/shims/backtrace.rs index 1ac3a22f7ed3d..eb25cfd9935ff 100644 --- a/src/shims/backtrace.rs +++ b/src/shims/backtrace.rs @@ -1,6 +1,6 @@ -use crate::rustc_target::abi::LayoutOf as _; use crate::*; use rustc_ast::ast::Mutability; +use rustc_middle::ty::layout::LayoutOf as _; use rustc_middle::ty::{self, TypeAndMut}; use rustc_span::{BytePos, Symbol}; use rustc_target::{abi::Size, spec::abi::Abi}; diff --git a/src/shims/env.rs b/src/shims/env.rs index 9290ec022b57f..74c0b56e467bb 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -4,8 +4,9 @@ use std::ffi::{OsStr, OsString}; use std::io::ErrorKind; use rustc_data_structures::fx::FxHashMap; +use rustc_middle::ty::layout::LayoutOf; use rustc_mir::interpret::Pointer; -use rustc_target::abi::{LayoutOf, Size}; +use rustc_target::abi::Size; use crate::*; diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index fd1a3f3e598ba..f2f046a3ada13 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -3,9 +3,9 @@ use std::iter; use log::trace; use rustc_apfloat::{Float, Round}; -use rustc_middle::ty::layout::IntegerExt; +use rustc_middle::ty::layout::{IntegerExt, LayoutOf}; use rustc_middle::{mir, mir::BinOp, ty, ty::FloatTy}; -use rustc_target::abi::{Align, Integer, LayoutOf}; +use rustc_target::abi::{Align, Integer}; use crate::*; use helpers::check_arg_count; diff --git a/src/shims/os_str.rs b/src/shims/os_str.rs index 83bb344982c2a..ede29d04d6bc9 100644 --- a/src/shims/os_str.rs +++ b/src/shims/os_str.rs @@ -9,7 +9,8 @@ use std::os::unix::ffi::{OsStrExt, OsStringExt}; #[cfg(windows)] use std::os::windows::ffi::{OsStrExt, OsStringExt}; -use rustc_target::abi::{Align, LayoutOf, Size}; +use rustc_middle::ty::layout::LayoutOf; +use rustc_target::abi::{Align, Size}; use crate::*; diff --git a/src/shims/posix/foreign_items.rs b/src/shims/posix/foreign_items.rs index 09dd7d9c7b869..6d417fd09671c 100644 --- a/src/shims/posix/foreign_items.rs +++ b/src/shims/posix/foreign_items.rs @@ -1,8 +1,9 @@ use log::trace; use rustc_middle::mir; +use rustc_middle::ty::layout::LayoutOf; use rustc_span::Symbol; -use rustc_target::abi::{Align, LayoutOf, Size}; +use rustc_target::abi::{Align, Size}; use rustc_target::spec::abi::Abi; use crate::*; diff --git a/src/shims/posix/fs.rs b/src/shims/posix/fs.rs index ac6e878da962e..36c076037708d 100644 --- a/src/shims/posix/fs.rs +++ b/src/shims/posix/fs.rs @@ -11,8 +11,8 @@ use std::time::SystemTime; use log::trace; use rustc_data_structures::fx::FxHashMap; -use rustc_middle::ty; -use rustc_target::abi::{Align, LayoutOf, Size}; +use rustc_middle::ty::{self, layout::LayoutOf}; +use rustc_target::abi::{Align, Size}; use crate::*; use helpers::{check_arg_count, immty_from_int_checked, immty_from_uint_checked}; diff --git a/src/shims/posix/thread.rs b/src/shims/posix/thread.rs index 9926c36c49ac4..e64ef3b23c6f2 100644 --- a/src/shims/posix/thread.rs +++ b/src/shims/posix/thread.rs @@ -1,7 +1,7 @@ use std::convert::TryInto; use crate::*; -use rustc_target::abi::LayoutOf; +use rustc_middle::ty::layout::LayoutOf; use rustc_target::spec::abi::Abi; impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index e04de65ac3fd5..65678b6f01fe1 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -9,8 +9,8 @@ use std::num::NonZeroU64; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_hir::Mutability; use rustc_middle::mir::RetagKind; -use rustc_middle::ty; -use rustc_target::abi::{LayoutOf, Size}; +use rustc_middle::ty::{self, layout::LayoutOf}; +use rustc_target::abi::Size; use crate::*; From 9c62b6454e46b440eaf704213738ab8e819ecced Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Thu, 9 Sep 2021 17:36:39 +0800 Subject: [PATCH 2805/3747] `rustc_mir` -> `rustc_const_eval` --- rust-version | 2 +- src/bin/miri.rs | 7 +++++-- src/lib.rs | 6 +++--- src/machine.rs | 4 ++-- src/shims/env.rs | 2 +- 5 files changed, 12 insertions(+), 9 deletions(-) diff --git a/rust-version b/rust-version index 33be6b9182b89..c3b3aed9a4264 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -1c858ba5bf7bd06c1a970efbf77053c8380b3151 +c5cbf7852a7692c7c51df64c09a59e7838b55202 diff --git a/src/bin/miri.rs b/src/bin/miri.rs index fbc87148ec7b7..36e7f1bfddaad 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -164,11 +164,14 @@ fn init_late_loggers(tcx: TyCtxt<'_>) { // used for everything, we only apply it to the parts of rustc that are // CTFE-related. Otherwise, we use it verbatim for `RUSTC_LOG`. // This way, if you set `MIRI_LOG=trace`, you get only the right parts of - // rustc traced, but you can also do `MIRI_LOG=miri=trace,rustc_mir::interpret=debug`. + // rustc traced, but you can also do `MIRI_LOG=miri=trace,rustc_const_eval::interpret=debug`. if log::Level::from_str(&var).is_ok() { env::set_var( "RUSTC_LOG", - &format!("rustc_middle::mir::interpret={0},rustc_mir::interpret={0}", var), + &format!( + "rustc_middle::mir::interpret={0},rustc_const_eval::interpret={0}", + var + ), ); } else { env::set_var("RUSTC_LOG", &var); diff --git a/src/lib.rs b/src/lib.rs index 7ed915b6d1d4b..c786487d4a146 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -11,10 +11,10 @@ extern crate rustc_apfloat; extern crate rustc_ast; #[macro_use] extern crate rustc_middle; +extern crate rustc_const_eval; extern crate rustc_data_structures; extern crate rustc_hir; extern crate rustc_index; -extern crate rustc_mir; extern crate rustc_session; extern crate rustc_span; extern crate rustc_target; @@ -37,9 +37,9 @@ mod vector_clock; // Establish a "crate-wide prelude": we often import `crate::*`. // Make all those symbols available in the same place as our own. -pub use rustc_mir::interpret::*; +pub use rustc_const_eval::interpret::*; // Resolve ambiguity. -pub use rustc_mir::interpret::{self, AllocMap, PlaceTy}; +pub use rustc_const_eval::interpret::{self, AllocMap, PlaceTy}; pub use crate::shims::dlsym::{Dlsym, EvalContextExt as _}; pub use crate::shims::env::{EnvVars, EvalContextExt as _}; diff --git a/src/machine.rs b/src/machine.rs index fb39503b53858..23278a4891fb7 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -457,7 +457,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { #[inline(always)] fn call_intrinsic( - ecx: &mut rustc_mir::interpret::InterpCx<'mir, 'tcx, Self>, + ecx: &mut rustc_const_eval::interpret::InterpCx<'mir, 'tcx, Self>, instance: ty::Instance<'tcx>, args: &[OpTy<'tcx, Tag>], ret: Option<(&PlaceTy<'tcx, Tag>, mir::BasicBlock)>, @@ -482,7 +482,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { #[inline(always)] fn binary_ptr_op( - ecx: &rustc_mir::interpret::InterpCx<'mir, 'tcx, Self>, + ecx: &rustc_const_eval::interpret::InterpCx<'mir, 'tcx, Self>, bin_op: mir::BinOp, left: &ImmTy<'tcx, Tag>, right: &ImmTy<'tcx, Tag>, diff --git a/src/shims/env.rs b/src/shims/env.rs index 74c0b56e467bb..4d297fd935d53 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -3,9 +3,9 @@ use std::env; use std::ffi::{OsStr, OsString}; use std::io::ErrorKind; +use rustc_const_eval::interpret::Pointer; use rustc_data_structures::fx::FxHashMap; use rustc_middle::ty::layout::LayoutOf; -use rustc_mir::interpret::Pointer; use rustc_target::abi::Size; use crate::*; From 9a877b80fe46671cca93582856c6b6867c10770b Mon Sep 17 00:00:00 2001 From: hyd-dev Date: Sat, 11 Sep 2021 18:58:57 +0800 Subject: [PATCH 2806/3747] Add `#[allow(dead_code)]` in some tests --- rust-version | 2 +- tests/compile-fail/validity/invalid_wide_raw.rs | 1 + tests/run-pass/issue-3794.rs | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/rust-version b/rust-version index c3b3aed9a4264..26d88f5b07b5f 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -c5cbf7852a7692c7c51df64c09a59e7838b55202 +4e880f8cbc191374ce7db335962489f41d6d4e3e diff --git a/tests/compile-fail/validity/invalid_wide_raw.rs b/tests/compile-fail/validity/invalid_wide_raw.rs index 6e0809b15ca43..ac2d79b5a92ad 100644 --- a/tests/compile-fail/validity/invalid_wide_raw.rs +++ b/tests/compile-fail/validity/invalid_wide_raw.rs @@ -4,6 +4,7 @@ fn main() { trait T { } #[derive(Debug)] struct S { + #[allow(dead_code)] x: * mut dyn T } dbg!(S { x: unsafe { std::mem::transmute((0usize, 0usize)) } }); //~ ERROR: encountered dangling vtable pointer in wide pointer diff --git a/tests/run-pass/issue-3794.rs b/tests/run-pass/issue-3794.rs index fb1c19b04e998..5b5b22b54948d 100644 --- a/tests/run-pass/issue-3794.rs +++ b/tests/run-pass/issue-3794.rs @@ -6,6 +6,7 @@ trait T { #[derive(Debug)] struct S { + #[allow(dead_code)] s: isize, } From 5aecd2811e65f3d238e68ced6bf9fddac7bb25c2 Mon Sep 17 00:00:00 2001 From: Smitty Date: Sat, 11 Sep 2021 12:00:59 -0400 Subject: [PATCH 2807/3747] One character aliases for cargo-miri run/test The main `cargo` command supports `cargo r` as an alias for `cargo run`, and `cargo t` as an alias for `cargo test`. This adds support to them in cargo-miri for consistency. --- cargo-miri/bin.rs | 8 ++++---- test-cargo-miri/run-test.py | 10 ++++++++++ 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index 23546988daa8f..21f53a45e41f6 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -20,8 +20,8 @@ Usage: cargo miri [subcommand] [...] [--] [...] Subcommands: - run Run binaries - test Run tests + run, r Run binaries + test, t Run tests setup Only perform automatic setup, but without asking questions (for getting a proper libstd) The cargo options are exactly the same as for `cargo run` and `cargo test`, respectively. @@ -524,8 +524,8 @@ fn phase_cargo_miri(mut args: env::Args) { // We cannot know which of those flags take arguments and which do not, // so we cannot detect subcommands later. let subcommand = match args.next().as_deref() { - Some("test") => MiriCommand::Test, - Some("run") => MiriCommand::Run, + Some("test" | "t") => MiriCommand::Test, + Some("run" | "r") => MiriCommand::Run, Some("setup") => MiriCommand::Setup, // Invalid command. _ => diff --git a/test-cargo-miri/run-test.py b/test-cargo-miri/run-test.py index 81a1b1b3f8a7d..db8f6049900eb 100755 --- a/test-cargo-miri/run-test.py +++ b/test-cargo-miri/run-test.py @@ -102,6 +102,11 @@ def test_cargo_miri_run(): "run.subcrate.stdout.ref", "run.subcrate.stderr.ref", env={'MIRIFLAGS': "-Zmiri-disable-isolation"}, ) + test("`cargo miri r` (subcrate, no ioslation)", + cargo_miri("r") + ["-p", "subcrate"], + "run.subcrate.stdout.ref", "run.subcrate.stderr.ref", + env={'MIRIFLAGS': "-Zmiri-disable-isolation"}, + ) test("`cargo miri run` (custom target dir)", # Attempt to confuse the argument parser. cargo_miri("run") + ["--target-dir=custom-run", "--", "--target-dir=target/custom-run"], @@ -146,6 +151,11 @@ def test_cargo_miri_test(): "test.subcrate.stdout.ref", "test.stderr-proc-macro.ref", env={'MIRIFLAGS': "-Zmiri-disable-isolation"}, ) + test("`cargo miri t` (subcrate, no isolation)", + cargo_miri("t") + ["-p", "subcrate"], + "test.subcrate.stdout.ref", "test.stderr-proc-macro.ref", + env={'MIRIFLAGS': "-Zmiri-disable-isolation"}, + ) test("`cargo miri test` (subcrate, doctests)", cargo_miri("test") + ["-p", "subcrate", "--doc"], "test.stdout-empty.ref", "test.stderr-proc-macro-doctest.ref", From 4df931405aa754c55a5a48eca116f82ba48f75d1 Mon Sep 17 00:00:00 2001 From: Smitty Date: Mon, 13 Sep 2021 18:05:01 -0400 Subject: [PATCH 2808/3747] Don't use seperate alias test --- test-cargo-miri/run-test.py | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/test-cargo-miri/run-test.py b/test-cargo-miri/run-test.py index db8f6049900eb..3bc37b236b349 100755 --- a/test-cargo-miri/run-test.py +++ b/test-cargo-miri/run-test.py @@ -97,12 +97,7 @@ def test_cargo_miri_run(): cargo_miri("run") + ["--bin", "cargo-miri-test", "--", "hello world", '"hello world"'], "run.args.stdout.ref", "run.args.stderr.ref", ) - test("`cargo miri run` (subcrate, no ioslation)", - cargo_miri("run") + ["-p", "subcrate"], - "run.subcrate.stdout.ref", "run.subcrate.stderr.ref", - env={'MIRIFLAGS': "-Zmiri-disable-isolation"}, - ) - test("`cargo miri r` (subcrate, no ioslation)", + test("`cargo miri r` (subcrate, no isolation)", cargo_miri("r") + ["-p", "subcrate"], "run.subcrate.stdout.ref", "run.subcrate.stderr.ref", env={'MIRIFLAGS': "-Zmiri-disable-isolation"}, @@ -146,11 +141,6 @@ def test_cargo_miri_test(): cargo_miri("test") + ["--bin", "cargo-miri-test", "--", "--format=pretty"], "test.bin-target.stdout.ref", "test.stderr-empty.ref", ) - test("`cargo miri test` (subcrate, no isolation)", - cargo_miri("test") + ["-p", "subcrate"], - "test.subcrate.stdout.ref", "test.stderr-proc-macro.ref", - env={'MIRIFLAGS': "-Zmiri-disable-isolation"}, - ) test("`cargo miri t` (subcrate, no isolation)", cargo_miri("t") + ["-p", "subcrate"], "test.subcrate.stdout.ref", "test.stderr-proc-macro.ref", From f6cedbc744155b168e51b63a873fff98790757f6 Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Sat, 18 Sep 2021 16:57:31 +0100 Subject: [PATCH 2809/3747] Correct Windows argument handling Previously the command line string would have been incorrectly constructed if argv[0] contained a doublequote (`"`) or ended in a trailing backslash (`\`). This is a very rare edge case because, by convention, argv[0] is the path to the application and Windows file names cannot contain doublequotes. Fixes #1881 --- src/eval.rs | 85 ++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 75 insertions(+), 10 deletions(-) diff --git a/src/eval.rs b/src/eval.rs index 311b930cd9dd8..e389ac7ed488e 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -2,6 +2,7 @@ use std::convert::TryFrom; use std::ffi::OsStr; +use std::iter; use log::info; @@ -202,17 +203,8 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( // Store command line as UTF-16 for Windows `GetCommandLineW`. { // Construct a command string with all the aguments. - let mut cmd = String::new(); - for arg in config.args.iter() { - if !cmd.is_empty() { - cmd.push(' '); - } - cmd.push_str(&*shell_escape::windows::escape(arg.as_str().into())); - } - // Don't forget `0` terminator. - cmd.push(std::char::from_u32(0).unwrap()); + let cmd_utf16: Vec = args_to_utf16_command_string(config.args.iter()); - let cmd_utf16: Vec = cmd.encode_utf16().collect(); let cmd_type = tcx.mk_array(tcx.types.u16, u64::try_from(cmd_utf16.len()).unwrap()); let cmd_place = ecx.allocate(ecx.layout_of(cmd_type)?, MiriMemoryKind::Machine.into())?; @@ -353,3 +345,76 @@ pub fn eval_entry<'tcx>( Err(e) => report_error(&ecx, e), } } + +/// Turns an array of arguments into a Windows command line string. +/// +/// The string will be UTF-16 encoded and NUL terminated. +/// +/// Panics if the zeroth argument contains the `"` character because doublequotes +/// in argv[0] cannot be encoded using the standard command line parsing rules. +fn args_to_utf16_command_string(mut args: I) -> Vec +where + I: Iterator, + T: AsRef, +{ + // Parse argv[0]. Slashes aren't escaped. Literal double quotes are not allowed. + let mut cmd = if let Some(arg0) = args.next() { + let arg0 = arg0.as_ref(); + if arg0.is_empty() { + "\"\"".into() + } else if arg0.contains('"') { + panic!("argv[0] cannot contain a doublequote (\") character"); + } else { + // Always surround argv[0] with quotes. + let mut s = String::new(); + s.push('"'); + s.push_str(arg0); + s.push('"'); + s + } + } else { + return vec![0]; + }; + + // Build the other arguments. + for arg in args { + let arg = arg.as_ref(); + cmd.push(' '); + if arg.is_empty() { + cmd.push_str("\"\""); + } else if !arg.bytes().any(|c| matches!(c, b'"' | b'\t' | b' ')) { + cmd.push_str(arg); + } else { + cmd.push('"'); + let mut chars = arg.chars().peekable(); + loop { + let mut nslashes = 0; + while let Some(&'\\') = chars.peek() { + chars.next(); + nslashes += 1; + } + + match chars.next() { + Some('"') => { + cmd.extend(iter::repeat('\\').take(nslashes * 2 + 1)); + cmd.push('"'); + } + Some(c) => { + cmd.extend(iter::repeat('\\').take(nslashes)); + cmd.push(c); + } + None => { + cmd.extend(iter::repeat('\\').take(nslashes * 2)); + break; + } + } + } + cmd.push('"'); + } + } + + if cmd.contains('\0') { + panic!("interior null in command line arguments"); + } + cmd.encode_utf16().chain(iter::once(0)).collect() +} From cfd1316e60c901bd61f5ccc1006e32d75f3f7ab2 Mon Sep 17 00:00:00 2001 From: Chris Denton Date: Wed, 22 Sep 2021 20:46:20 +0100 Subject: [PATCH 2810/3747] Apply review changes --- src/eval.rs | 42 ++++++++++++++++++++++++++++++++++++------ 1 file changed, 36 insertions(+), 6 deletions(-) diff --git a/src/eval.rs b/src/eval.rs index e389ac7ed488e..c7ce51a83f4cc 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -352,17 +352,24 @@ pub fn eval_entry<'tcx>( /// /// Panics if the zeroth argument contains the `"` character because doublequotes /// in argv[0] cannot be encoded using the standard command line parsing rules. +/// +/// Further reading: +/// * [Parsing C++ command-line arguments](https://docs.microsoft.com/en-us/cpp/cpp/main-function-command-line-args?view=msvc-160#parsing-c-command-line-arguments) +/// * [The C/C++ Parameter Parsing Rules](https://daviddeley.com/autohotkey/parameters/parameters.htm#WINCRULES) fn args_to_utf16_command_string(mut args: I) -> Vec where I: Iterator, T: AsRef, { // Parse argv[0]. Slashes aren't escaped. Literal double quotes are not allowed. - let mut cmd = if let Some(arg0) = args.next() { + let mut cmd = { + let arg0 = if let Some(arg0) = args.next() { + arg0 + } else { + return vec![0]; + }; let arg0 = arg0.as_ref(); - if arg0.is_empty() { - "\"\"".into() - } else if arg0.contains('"') { + if arg0.contains('"') { panic!("argv[0] cannot contain a doublequote (\") character"); } else { // Always surround argv[0] with quotes. @@ -372,8 +379,6 @@ where s.push('"'); s } - } else { - return vec![0]; }; // Build the other arguments. @@ -383,8 +388,15 @@ where if arg.is_empty() { cmd.push_str("\"\""); } else if !arg.bytes().any(|c| matches!(c, b'"' | b'\t' | b' ')) { + // No quote, tab, or space -- no escaping required. cmd.push_str(arg); } else { + // Spaces and tabs are escaped by surrounding them in quotes. + // Quotes are themselves escaped by using backslashes when in a + // quoted block. + // Backslashes only need to be escaped when one or more are directly + // followed by a quote. Otherwise they are taken literally. + cmd.push('"'); let mut chars = arg.chars().peekable(); loop { @@ -418,3 +430,21 @@ where } cmd.encode_utf16().chain(iter::once(0)).collect() } + +#[cfg(test)] +mod tests { + use super::*; + #[test] + #[should_panic(expected = "argv[0] cannot contain a doublequote (\") character")] + fn windows_argv0_panic_on_quote() { + args_to_utf16_command_string(["\""].iter()); + } + #[test] + fn windows_argv0_no_escape() { + // Ensure that a trailing backslash in argv[0] is not escaped. + let cmd = String::from_utf16_lossy(&args_to_utf16_command_string( + [r"C:\Program Files\", "arg1"].iter(), + )); + assert_eq!(cmd.trim_end_matches("\0"), r#""C:\Program Files\" arg1"#); + } +} From 405de0217d9775e2f343373c65b722ecfa291c28 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 24 Sep 2021 10:13:29 -0400 Subject: [PATCH 2811/3747] some more Windows argument passing tests --- src/eval.rs | 4 ++-- test-cargo-miri/run-test.py | 2 +- test-cargo-miri/run.args.stderr.ref | 1 + 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/eval.rs b/src/eval.rs index c7ce51a83f4cc..5d8d332fcd9c1 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -443,8 +443,8 @@ mod tests { fn windows_argv0_no_escape() { // Ensure that a trailing backslash in argv[0] is not escaped. let cmd = String::from_utf16_lossy(&args_to_utf16_command_string( - [r"C:\Program Files\", "arg1"].iter(), + [r"C:\Program Files\", "arg1", "arg 2", "arg \" 3"].iter(), )); - assert_eq!(cmd.trim_end_matches("\0"), r#""C:\Program Files\" arg1"#); + assert_eq!(cmd.trim_end_matches("\0"), r#""C:\Program Files\" arg1 "arg 2" "arg \" 3""#); } } diff --git a/test-cargo-miri/run-test.py b/test-cargo-miri/run-test.py index 3bc37b236b349..18671b2e29da1 100755 --- a/test-cargo-miri/run-test.py +++ b/test-cargo-miri/run-test.py @@ -94,7 +94,7 @@ def test_cargo_miri_run(): # so keep it set ) test("`cargo miri run` (with arguments and target)", - cargo_miri("run") + ["--bin", "cargo-miri-test", "--", "hello world", '"hello world"'], + cargo_miri("run") + ["--bin", "cargo-miri-test", "--", "hello world", '"hello world"', r'he\\llo\"world'], "run.args.stdout.ref", "run.args.stderr.ref", ) test("`cargo miri r` (subcrate, no isolation)", diff --git a/test-cargo-miri/run.args.stderr.ref b/test-cargo-miri/run.args.stderr.ref index 8226b1b7cdec7..01bb8952322b6 100644 --- a/test-cargo-miri/run.args.stderr.ref +++ b/test-cargo-miri/run.args.stderr.ref @@ -1,3 +1,4 @@ main hello world "hello world" +he\\llo\"world From 5f825ae895adbd2cfeff2fb0fc1a2e411bcac91a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 27 Sep 2021 15:59:18 -0400 Subject: [PATCH 2812/3747] rustup --- rust-version | 2 +- src/shims/foreign_items.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/rust-version b/rust-version index 26d88f5b07b5f..65591aa7ebd9d 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -4e880f8cbc191374ce7db335962489f41d6d4e3e +2b6ed3b675475abc01ce7e68bb75b457f0c85684 diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 35c151b72f60c..6dfdc316ac47e 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -597,7 +597,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.yield_active_thread(); } "llvm.aarch64.isb" if this.tcx.sess.target.arch == "aarch64" => { - let &[ref arg] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let &[ref arg] = this.check_shim(abi, Abi::Unadjusted, link_name, args)?; let arg = this.read_scalar(arg)?.to_i32()?; match arg { 15 => { // SY ("full system scope") From e6a27a68fa8a919ff7e4d18f2cd0e256a749b85a Mon Sep 17 00:00:00 2001 From: DrMeepster <19316085+DrMeepster@users.noreply.github.com> Date: Thu, 2 Sep 2021 20:43:56 -0700 Subject: [PATCH 2813/3747] implement `#[global_allocator]` --- src/shims/foreign_items.rs | 121 ++++++++++++------ src/shims/posix/foreign_items.rs | 2 +- src/shims/posix/linux/foreign_items.rs | 2 +- src/shims/posix/macos/foreign_items.rs | 2 +- src/shims/windows/foreign_items.rs | 2 +- .../compile-fail/alloc/no_global_allocator.rs | 25 ++++ tests/run-pass/global_allocator.rs | 41 ++++++ tests/run-pass/global_allocator.stdout | 2 + 8 files changed, 157 insertions(+), 40 deletions(-) create mode 100644 tests/compile-fail/alloc/no_global_allocator.rs create mode 100644 tests/run-pass/global_allocator.rs create mode 100644 tests/run-pass/global_allocator.stdout diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 35c151b72f60c..1b577688c33b2 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -6,6 +6,7 @@ use std::{ use log::trace; use rustc_apfloat::Float; +use rustc_ast::expand::allocator::AllocatorKind; use rustc_hir::{ def::DefKind, def_id::{CrateNum, DefId, LOCAL_CRATE}, @@ -27,11 +28,13 @@ use super::backtrace::EvalContextExt as _; use crate::*; /// Returned by `emulate_foreign_item_by_name`. -pub enum EmulateByNameResult { +pub enum EmulateByNameResult<'mir, 'tcx> { /// The caller is expected to jump to the return block. NeedsJumping, /// Jumping has already been taken care of. AlreadyJumped, + /// A MIR body has been found for the function + MirBody(&'mir mir::Body<'tcx>), /// The item is not supported. NotSupported, } @@ -281,6 +284,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.go_to_block(ret); } EmulateByNameResult::AlreadyJumped => (), + EmulateByNameResult::MirBody(mir) => return Ok(Some(mir)), EmulateByNameResult::NotSupported => { if let Some(body) = this.lookup_exported_symbol(link_name)? { return Ok(Some(body)); @@ -294,6 +298,36 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(None) } + /// Emulates calling the internal __rust_* allocator functions + fn emulate_allocator( + &mut self, + symbol: Symbol, + default: impl FnOnce(&mut MiriEvalContext<'mir, 'tcx>) -> InterpResult<'tcx>, + ) -> InterpResult<'tcx, EmulateByNameResult<'mir, 'tcx>> { + let this = self.eval_context_mut(); + + let allocator_kind = if let Some(allocator_kind) = this.tcx.allocator_kind(()) { + allocator_kind + } else { + // in real code, this symbol does not exist without an allocator + return Ok(EmulateByNameResult::NotSupported); + }; + + match allocator_kind { + AllocatorKind::Global => { + let body = this + .lookup_exported_symbol(symbol)? + .expect("symbol should be present if there is a global allocator"); + + Ok(EmulateByNameResult::MirBody(body)) + } + AllocatorKind::Default => { + default(this)?; + Ok(EmulateByNameResult::NeedsJumping) + } + } + } + /// Emulates calling a foreign item using its name. fn emulate_foreign_item_by_name( &mut self, @@ -302,7 +336,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx args: &[OpTy<'tcx, Tag>], dest: &PlaceTy<'tcx, Tag>, ret: mir::BasicBlock, - ) -> InterpResult<'tcx, EmulateByNameResult> { + ) -> InterpResult<'tcx, EmulateByNameResult<'mir, 'tcx>> { let this = self.eval_context_mut(); // Here we dispatch all the shims for foreign functions. If you have a platform specific @@ -362,45 +396,56 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // Rust allocation - // (Usually these would be forwarded to to `#[global_allocator]`; we instead implement a generic - // allocation that also checks that all conditions are met, such as not permitting zero-sized allocations.) "__rust_alloc" => { let &[ref size, ref align] = this.check_shim(abi, Abi::Rust, link_name, args)?; let size = this.read_scalar(size)?.to_machine_usize(this)?; let align = this.read_scalar(align)?.to_machine_usize(this)?; - Self::check_alloc_request(size, align)?; - let ptr = this.memory.allocate( - Size::from_bytes(size), - Align::from_bytes(align).unwrap(), - MiriMemoryKind::Rust.into(), - )?; - this.write_pointer(ptr, dest)?; + + return this.emulate_allocator(Symbol::intern("__rg_alloc"), |this| { + Self::check_alloc_request(size, align)?; + + let ptr = this.memory.allocate( + Size::from_bytes(size), + Align::from_bytes(align).unwrap(), + MiriMemoryKind::Rust.into(), + )?; + + this.write_pointer(ptr, dest) + }); } "__rust_alloc_zeroed" => { let &[ref size, ref align] = this.check_shim(abi, Abi::Rust, link_name, args)?; let size = this.read_scalar(size)?.to_machine_usize(this)?; let align = this.read_scalar(align)?.to_machine_usize(this)?; - Self::check_alloc_request(size, align)?; - let ptr = this.memory.allocate( - Size::from_bytes(size), - Align::from_bytes(align).unwrap(), - MiriMemoryKind::Rust.into(), - )?; - // We just allocated this, the access is definitely in-bounds. - this.memory.write_bytes(ptr.into(), iter::repeat(0u8).take(usize::try_from(size).unwrap())).unwrap(); - this.write_pointer(ptr, dest)?; + + return this.emulate_allocator(Symbol::intern("__rg_alloc_zeroed"), |this| { + Self::check_alloc_request(size, align)?; + + let ptr = this.memory.allocate( + Size::from_bytes(size), + Align::from_bytes(align).unwrap(), + MiriMemoryKind::Rust.into(), + )?; + + // We just allocated this, the access is definitely in-bounds. + this.memory.write_bytes(ptr.into(), iter::repeat(0u8).take(usize::try_from(size).unwrap())).unwrap(); + this.write_pointer(ptr, dest) + }); } "__rust_dealloc" => { let &[ref ptr, ref old_size, ref align] = this.check_shim(abi, Abi::Rust, link_name, args)?; let ptr = this.read_pointer(ptr)?; let old_size = this.read_scalar(old_size)?.to_machine_usize(this)?; let align = this.read_scalar(align)?.to_machine_usize(this)?; - // No need to check old_size/align; we anyway check that they match the allocation. - this.memory.deallocate( - ptr, - Some((Size::from_bytes(old_size), Align::from_bytes(align).unwrap())), - MiriMemoryKind::Rust.into(), - )?; + + return this.emulate_allocator(Symbol::intern("__rg_dealloc"), |this| { + // No need to check old_size/align; we anyway check that they match the allocation. + this.memory.deallocate( + ptr, + Some((Size::from_bytes(old_size), Align::from_bytes(align).unwrap())), + MiriMemoryKind::Rust.into(), + ) + }); } "__rust_realloc" => { let &[ref ptr, ref old_size, ref align, ref new_size] = this.check_shim(abi, Abi::Rust, link_name, args)?; @@ -408,17 +453,21 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let old_size = this.read_scalar(old_size)?.to_machine_usize(this)?; let align = this.read_scalar(align)?.to_machine_usize(this)?; let new_size = this.read_scalar(new_size)?.to_machine_usize(this)?; - Self::check_alloc_request(new_size, align)?; // No need to check old_size; we anyway check that they match the allocation. - let align = Align::from_bytes(align).unwrap(); - let new_ptr = this.memory.reallocate( - ptr, - Some((Size::from_bytes(old_size), align)), - Size::from_bytes(new_size), - align, - MiriMemoryKind::Rust.into(), - )?; - this.write_pointer(new_ptr, dest)?; + + return this.emulate_allocator(Symbol::intern("__rg_realloc"), |this| { + Self::check_alloc_request(new_size, align)?; + + let align = Align::from_bytes(align).unwrap(); + let new_ptr = this.memory.reallocate( + ptr, + Some((Size::from_bytes(old_size), align)), + Size::from_bytes(new_size), + align, + MiriMemoryKind::Rust.into(), + )?; + this.write_pointer(new_ptr, dest) + }); } // C memory handling functions diff --git a/src/shims/posix/foreign_items.rs b/src/shims/posix/foreign_items.rs index 6d417fd09671c..83b4032cd98a5 100644 --- a/src/shims/posix/foreign_items.rs +++ b/src/shims/posix/foreign_items.rs @@ -21,7 +21,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx args: &[OpTy<'tcx, Tag>], dest: &PlaceTy<'tcx, Tag>, ret: mir::BasicBlock, - ) -> InterpResult<'tcx, EmulateByNameResult> { + ) -> InterpResult<'tcx, EmulateByNameResult<'mir, 'tcx>> { let this = self.eval_context_mut(); match &*link_name.as_str() { diff --git a/src/shims/posix/linux/foreign_items.rs b/src/shims/posix/linux/foreign_items.rs index 0a9939fedd4cb..8d0f8487f5e13 100644 --- a/src/shims/posix/linux/foreign_items.rs +++ b/src/shims/posix/linux/foreign_items.rs @@ -18,7 +18,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx args: &[OpTy<'tcx, Tag>], dest: &PlaceTy<'tcx, Tag>, _ret: mir::BasicBlock, - ) -> InterpResult<'tcx, EmulateByNameResult> { + ) -> InterpResult<'tcx, EmulateByNameResult<'mir, 'tcx>> { let this = self.eval_context_mut(); match &*link_name.as_str() { diff --git a/src/shims/posix/macos/foreign_items.rs b/src/shims/posix/macos/foreign_items.rs index 2f79b337ce386..8147b1442907d 100644 --- a/src/shims/posix/macos/foreign_items.rs +++ b/src/shims/posix/macos/foreign_items.rs @@ -16,7 +16,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx args: &[OpTy<'tcx, Tag>], dest: &PlaceTy<'tcx, Tag>, _ret: mir::BasicBlock, - ) -> InterpResult<'tcx, EmulateByNameResult> { + ) -> InterpResult<'tcx, EmulateByNameResult<'mir, 'tcx>> { let this = self.eval_context_mut(); match &*link_name.as_str() { diff --git a/src/shims/windows/foreign_items.rs b/src/shims/windows/foreign_items.rs index 0eebd6aca5bd4..61a1759ffee55 100644 --- a/src/shims/windows/foreign_items.rs +++ b/src/shims/windows/foreign_items.rs @@ -18,7 +18,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx args: &[OpTy<'tcx, Tag>], dest: &PlaceTy<'tcx, Tag>, _ret: mir::BasicBlock, - ) -> InterpResult<'tcx, EmulateByNameResult> { + ) -> InterpResult<'tcx, EmulateByNameResult<'mir, 'tcx>> { let this = self.eval_context_mut(); // Windows API stubs. diff --git a/tests/compile-fail/alloc/no_global_allocator.rs b/tests/compile-fail/alloc/no_global_allocator.rs new file mode 100644 index 0000000000000..fb0e7986bb5e6 --- /dev/null +++ b/tests/compile-fail/alloc/no_global_allocator.rs @@ -0,0 +1,25 @@ +// Make sure we pretend the allocation symbols don't exist when there is no allocator + +#![feature(lang_items, start)] +#![no_std] + +extern "Rust" { + fn __rust_alloc(size: usize, align: usize) -> *mut u8; +} + +#[start] +fn start(_: isize, _: *const *const u8) -> isize { + unsafe { + __rust_alloc(1, 1); //~ERROR: unsupported operation: can't call foreign function: __rust_alloc + } + + 0 +} + +#[panic_handler] +fn panic_handler(_: &core::panic::PanicInfo) -> ! { + loop {} +} + +#[lang = "eh_personality"] +fn eh_personality() {} diff --git a/tests/run-pass/global_allocator.rs b/tests/run-pass/global_allocator.rs new file mode 100644 index 0000000000000..24a56c663f060 --- /dev/null +++ b/tests/run-pass/global_allocator.rs @@ -0,0 +1,41 @@ +#![feature(allocator_api, slice_ptr_get)] + +use std::alloc::{Allocator as _, Global, GlobalAlloc, Layout, System}; + +#[global_allocator] +static ALLOCATOR: Allocator = Allocator; + +struct Allocator; + +unsafe impl GlobalAlloc for Allocator { + unsafe fn alloc(&self, layout: Layout) -> *mut u8 { + // use specific size to avoid getting triggered by rt + if layout.size() == 123 { + println!("Allocated!") + } + + System.alloc(layout) + } + + unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) { + if layout.size() == 123 { + println!("Dellocated!") + } + + System.dealloc(ptr, layout) + } +} + +fn main() { + // Only okay because we explicitly set a global allocator that uses the system allocator! + let l = Layout::from_size_align(123, 1).unwrap(); + let ptr = Global.allocate(l).unwrap().as_non_null_ptr(); // allocating with Global... + unsafe { + System.deallocate(ptr, l); + } // ... and deallocating with System. + + let ptr = System.allocate(l).unwrap().as_non_null_ptr(); // allocating with System... + unsafe { + Global.deallocate(ptr, l); + } // ... and deallocating with Global. +} diff --git a/tests/run-pass/global_allocator.stdout b/tests/run-pass/global_allocator.stdout new file mode 100644 index 0000000000000..411a4cdd1467e --- /dev/null +++ b/tests/run-pass/global_allocator.stdout @@ -0,0 +1,2 @@ +Allocated! +Dellocated! From 0424554080ac1be93e572ed73ab1278e3762ee3e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Beno=C3=AEt=20du=20Garreau?= Date: Fri, 1 Oct 2021 23:08:58 +0200 Subject: [PATCH 2814/3747] Update dependencies --- Cargo.lock | 43 ++++++++----------------------------------- Cargo.toml | 6 +++--- 2 files changed, 11 insertions(+), 38 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0dbd1b8656897..24593d3332840 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -103,9 +103,9 @@ dependencies = [ [[package]] name = "env_logger" -version = "0.8.3" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17392a012ea30ef05a610aa97dfb49496e71c9f676b27879922ea5bdf60d9d3f" +checksum = "0b2cf0344971ee6c64c31be0d530793fba457d322dfec2810c453d0ef228f9c3" dependencies = [ "atty", "humantime", @@ -313,15 +313,6 @@ dependencies = [ "libc", ] -[[package]] -name = "pest" -version = "2.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10f4872ae94d7b90ae48754df22fd42ad52ce740b8f370b03da4835417403e53" -dependencies = [ - "ucd-trie", -] - [[package]] name = "ppv-lite86" version = "0.2.10" @@ -445,9 +436,9 @@ checksum = "fc71d2faa173b74b232dedc235e3ee1696581bb132fc116fa3626d6151a1a8fb" [[package]] name = "rustc_version" -version = "0.3.3" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0dfe2087c51c460008730de8b57e6a320782fbfb312e1f4d520e6c6fae155ee" +checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" dependencies = [ "semver", ] @@ -484,21 +475,9 @@ checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" [[package]] name = "semver" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f301af10236f6df4160f7c3f04eec6dbc70ace82d23326abad5edee88801c6b6" -dependencies = [ - "semver-parser", -] - -[[package]] -name = "semver-parser" -version = "0.10.2" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00b0bef5b7f9e0df16536d3961cfb6e84331c065b4066afb39768d0e319411f7" -dependencies = [ - "pest", -] +checksum = "568a8e6258aa33c13358f81fd834adb854c6f7c9468520910a9b1e8fac068012" [[package]] name = "serde" @@ -539,9 +518,9 @@ checksum = "45bb67a18fa91266cc7807181f62f9178a6873bfad7dc788c42e6430db40184f" [[package]] name = "smallvec" -version = "1.6.1" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e" +checksum = "1ecab6c735a6bb4139c0caafd0cc3635748bbb3acf4550e8138122099251f309" [[package]] name = "syn" @@ -601,12 +580,6 @@ dependencies = [ "term", ] -[[package]] -name = "ucd-trie" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c" - [[package]] name = "unicode-width" version = "0.1.8" diff --git a/Cargo.toml b/Cargo.toml index 82962c6b98aa0..a4d85e39e65d7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,12 +19,12 @@ doctest = false # and no doc tests [dependencies] getrandom = { version = "0.2", features = ["std"] } -env_logger = "0.8" +env_logger = "0.9" log = "0.4" shell-escape = "0.1.4" hex = "0.4.0" rand = "0.8" -smallvec = "1.4.2" +smallvec = "1.7" # A noop dependency that changes in the Rust repository, it's a bit of a hack. # See the `src/tools/rustc-workspace-hack/README.md` file in `rust-lang/rust` @@ -39,7 +39,7 @@ libc = "0.2" [dev-dependencies] compiletest_rs = { version = "0.7", features = ["tmp"] } -rustc_version = "0.3" +rustc_version = "0.4" colored = "2" [package.metadata.rust-analyzer] From 9af75a824f0d1d07e111ef68c3198568a2b6a513 Mon Sep 17 00:00:00 2001 From: Noah Lev Date: Tue, 5 Oct 2021 13:13:06 -0700 Subject: [PATCH 2815/3747] rustup Update to the `HEAD` commit of rust-lang/rust and fix test failure. --- rust-version | 2 +- tests/compile-fail/erroneous_const.rs | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/rust-version b/rust-version index 65591aa7ebd9d..0423627269b26 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -2b6ed3b675475abc01ce7e68bb75b457f0c85684 +25ec8273855fde2d72ae877b397e054de5300e10 diff --git a/tests/compile-fail/erroneous_const.rs b/tests/compile-fail/erroneous_const.rs index 199439ccbd2e7..2592483fe65a4 100644 --- a/tests/compile-fail/erroneous_const.rs +++ b/tests/compile-fail/erroneous_const.rs @@ -2,7 +2,6 @@ //! (https://github.com/rust-lang/miri/issues/1382) // Inlining changes the error location // compile-flags: -Zmir-opt-level=0 -#![feature(const_panic)] #![feature(never_type)] #![warn(warnings, const_err)] From e751c7b04e2378a1055278c12ddf7ac44634042a Mon Sep 17 00:00:00 2001 From: Noah Lev Date: Thu, 7 Oct 2021 11:52:11 -0700 Subject: [PATCH 2816/3747] rustup --- rust-version | 2 +- tests/run-pass/available-concurrency.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/rust-version b/rust-version index 0423627269b26..fdd83d7081424 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -25ec8273855fde2d72ae877b397e054de5300e10 +0157cc977fd71297ce73e2f249321f5ba2555d42 diff --git a/tests/run-pass/available-concurrency.rs b/tests/run-pass/available-concurrency.rs index 5f3121ca8a63e..422046c62d620 100644 --- a/tests/run-pass/available-concurrency.rs +++ b/tests/run-pass/available-concurrency.rs @@ -1,5 +1,5 @@ -#![feature(available_concurrency)] +#![feature(available_parallelism)] fn main() { - assert_eq!(std::thread::available_concurrency().unwrap().get(), 1); + assert_eq!(std::thread::available_parallelism().unwrap().get(), 1); } From 0309de73dca88009d67993d0f59f9c5c958ae823 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Habov=C5=A1tiak?= Date: Sat, 9 Oct 2021 22:19:14 +0200 Subject: [PATCH 2817/3747] Document threading support a bit more This adds a few known limitations around threading to the README and suggests the users to look into GitHub issues to learn more. --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index 7cd802762bff2..49a0c3c1f507a 100644 --- a/README.md +++ b/README.md @@ -59,6 +59,11 @@ in your program, and cannot run all programs: has no access to most platform-specific APIs or FFI. A few APIs have been implemented (such as printing to stdout) but most have not: for example, Miri currently does not support SIMD or networking. +* Threading support is not finished yet. E.g. weak memory effects are not + emulated and spin loops (without syscalls) just loop forever. There's no + threading support on Windows. + +Consider looking into GitHub isues for more information about the limitations. [rust]: https://www.rust-lang.org/ [mir]: https://github.com/rust-lang/rfcs/blob/master/text/1211-mir.md From 31ed3a7120d3d64389d9e0835ca25d6e1076db43 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Habov=C5=A1tiak?= Date: Tue, 12 Oct 2021 11:09:43 +0200 Subject: [PATCH 2818/3747] Typo fixes Co-authored-by: Ralf Jung --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 49a0c3c1f507a..aa016fc079345 100644 --- a/README.md +++ b/README.md @@ -59,8 +59,8 @@ in your program, and cannot run all programs: has no access to most platform-specific APIs or FFI. A few APIs have been implemented (such as printing to stdout) but most have not: for example, Miri currently does not support SIMD or networking. -* Threading support is not finished yet. E.g. weak memory effects are not - emulated and spin loops (without syscalls) just loop forever. There's no +* Threading support is not finished yet. E.g., weak memory effects are not + emulated and spin loops (without syscalls) just loop forever. There is no threading support on Windows. Consider looking into GitHub isues for more information about the limitations. From f040413af8a8e25deb245bd752a47281284a993e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 12 Oct 2021 11:39:06 -0400 Subject: [PATCH 2819/3747] rustup --- rust-version | 2 +- tests/run-pass/too-large-primval-write-problem.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/rust-version b/rust-version index fdd83d7081424..a51e57fd461be 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -0157cc977fd71297ce73e2f249321f5ba2555d42 +9475e609b8458fff9e444934a6017d2e590642cf diff --git a/tests/run-pass/too-large-primval-write-problem.rs b/tests/run-pass/too-large-primval-write-problem.rs index ebd6dbb61ee4e..f4c418bd78a99 100644 --- a/tests/run-pass/too-large-primval-write-problem.rs +++ b/tests/run-pass/too-large-primval-write-problem.rs @@ -16,7 +16,7 @@ fn main() { let bad = unsafe { transmute::(-x) }; // Force it through the Memory::write_primval code. - Box::new(bad); + drop(Box::new(bad)); } #[cfg(not(target_pointer_width = "32"))] From 782085adcd9d3434db20e59585ee20d86e703211 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Habov=C5=A1tiak?= Date: Tue, 12 Oct 2021 18:46:23 +0200 Subject: [PATCH 2820/3747] Remove vague statement from README Addresses https://github.com/rust-lang/miri/pull/1898#discussion_r727274293 --- README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/README.md b/README.md index aa016fc079345..0c5b591e72d50 100644 --- a/README.md +++ b/README.md @@ -63,8 +63,6 @@ in your program, and cannot run all programs: emulated and spin loops (without syscalls) just loop forever. There is no threading support on Windows. -Consider looking into GitHub isues for more information about the limitations. - [rust]: https://www.rust-lang.org/ [mir]: https://github.com/rust-lang/rfcs/blob/master/text/1211-mir.md [`unreachable_unchecked`]: https://doc.rust-lang.org/stable/std/hint/fn.unreachable_unchecked.html From 4a44c33976f8d8037b761c1182c3be9fcd895b61 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 13 Oct 2021 14:04:14 -0400 Subject: [PATCH 2821/3747] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index a51e57fd461be..faba8395d1477 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -9475e609b8458fff9e444934a6017d2e590642cf +81117ff930fbf3792b4f9504e3c6bccc87b10823 From a6b12c229b6f81716f30e8f6ba7b1a6e5485a1cd Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 21 Oct 2021 09:49:19 -0400 Subject: [PATCH 2822/3747] rustup; add swap_remove test --- rust-version | 2 +- tests/run-pass/vec.rs | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/rust-version b/rust-version index faba8395d1477..7fb789d83db80 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -81117ff930fbf3792b4f9504e3c6bccc87b10823 +e015ef5b2633960e7653b744d7a1c3d1d336313a diff --git a/tests/run-pass/vec.rs b/tests/run-pass/vec.rs index 5676f9b676bfc..8ed81a5e343ff 100644 --- a/tests/run-pass/vec.rs +++ b/tests/run-pass/vec.rs @@ -140,6 +140,14 @@ fn swap() { v.swap(2, 2); } +fn swap_remove() { + let mut a = 0; + let mut b = 1; + let mut vec = vec![&mut a, &mut b]; + + vec.swap_remove(1); +} + fn main() { assert_eq!(vec_reallocate().len(), 5); @@ -167,4 +175,5 @@ fn main() { sort(); swap(); + swap_remove(); } From 9944a2daf3ec5714becc61ad9694578663b37784 Mon Sep 17 00:00:00 2001 From: bjorn3 Date: Tue, 26 Oct 2021 13:42:03 +0200 Subject: [PATCH 2823/3747] rustup --- rust-version | 2 +- src/bin/miri.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/rust-version b/rust-version index 7fb789d83db80..b5e272cc4dd13 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -e015ef5b2633960e7653b744d7a1c3d1d336313a +c7a30c8b6860d1f3459086f7a91074db1b54bc37 diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 36e7f1bfddaad..84e66db2a7d9f 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -25,7 +25,7 @@ use rustc_hir::{self as hir, def_id::LOCAL_CRATE, Node}; use rustc_interface::interface::Config; use rustc_middle::{ middle::exported_symbols::{ExportedSymbol, SymbolExportLevel}, - ty::{query::Providers, TyCtxt}, + ty::{query::ExternProviders, TyCtxt}, }; use rustc_session::{config::ErrorOutputType, search_paths::PathKind, CtfeBacktrace}; @@ -37,7 +37,7 @@ impl rustc_driver::Callbacks for MiriCompilerCalls { fn config(&mut self, config: &mut Config) { config.override_queries = Some(|_, _, external_providers| { external_providers.used_crate_source = |tcx, cnum| { - let mut providers = Providers::default(); + let mut providers = ExternProviders::default(); rustc_metadata::provide_extern(&mut providers); let mut crate_source = (providers.used_crate_source)(tcx, cnum); // HACK: rustc will emit "crate ... required to be available in rlib format, but From 141bf38f23d2737bde70a38a23bbe90fa062c450 Mon Sep 17 00:00:00 2001 From: Noah Lev Date: Mon, 25 Oct 2021 18:55:40 -0700 Subject: [PATCH 2824/3747] Add instructions for using rust-analyzer for Miri development --- CONTRIBUTING.md | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index eea97863d3e24..caed6e3226d85 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -107,6 +107,41 @@ There's a test for the cargo wrapper in the `test-cargo-miri` directory; run `./run-test.py` in there to execute it. Like `./miri test`, this respects the `MIRI_TEST_TARGET` environment variable to execute the test for another target. +## Configuring `rust-analyzer` + +To configure `rust-analyzer` and VS Code for working on Miri, save the following +to `.vscode/settings.json` in your local Miri clone: + +```json +{ + "rust-analyzer.checkOnSave.overrideCommand": [ + "./miri", + "check", + "--message-format=json" + ], + "rust-analyzer.rustfmt.extraArgs": [ + "+nightly" + ], + "rust-analyzer.rustcSource": "discover", + "rust-analyzer.linkedProjects": [ + "./Cargo.toml", + "./cargo-miri/Cargo.toml" + ] +} +``` + +> #### Note +> +> If you are [building Miri with a locally built rustc][], set +> `rust-analyzer.rustcSource` to the relative path from your Miri clone to the +> root `Cargo.toml` of the locally built rustc. For example, the path might look +> like `../rust/Cargo.toml`. + +See the rustc-dev-guide's docs on ["Configuring `rust-analyzer` for `rustc`"][rdg-r-a] +for more information about configuring VS Code and `rust-analyzer`. + +[rdg-r-a]: https://rustc-dev-guide.rust-lang.org/building/suggested.html#configuring-rust-analyzer-for-rustc + ## Advanced topic: other build environments We described above the simplest way to get a working build environment for Miri, @@ -132,6 +167,8 @@ rustc. This avoids blocking all Miri development on landing a big PR. ### Building Miri with a locally built rustc +[building Miri with a locally built rustc]: #building-miri-with-a-locally-built-rustc + A big part of the Miri driver lives in rustc, so working on Miri will sometimes require using a locally built rustc. The bug you want to fix may actually be on the rustc side, or you just need to get more detailed trace of the execution From 6d1d8c69a094a6d64d26a2a15c5a2fb250ce17c1 Mon Sep 17 00:00:00 2001 From: Noah Lev Date: Mon, 1 Nov 2021 15:31:37 -0700 Subject: [PATCH 2825/3747] rustup --- rust-version | 2 +- tests/compile-fail/alloc/reallocate-bad-size.rs | 2 +- tests/compile-fail/alloc/reallocate-change-alloc.rs | 2 +- tests/compile-fail/alloc/reallocate-dangling.rs | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/rust-version b/rust-version index b5e272cc4dd13..fd8c69e11238b 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -c7a30c8b6860d1f3459086f7a91074db1b54bc37 +db062de72b0a064f45b6f86894cbdc7c0ec68844 diff --git a/tests/compile-fail/alloc/reallocate-bad-size.rs b/tests/compile-fail/alloc/reallocate-bad-size.rs index 80239015dc1d0..d6a27c930a28b 100644 --- a/tests/compile-fail/alloc/reallocate-bad-size.rs +++ b/tests/compile-fail/alloc/reallocate-bad-size.rs @@ -5,6 +5,6 @@ use std::alloc::{alloc, realloc, Layout}; fn main() { unsafe { let x = alloc(Layout::from_size_align_unchecked(1, 1)); - realloc(x, Layout::from_size_align_unchecked(2, 1), 1); + let _y = realloc(x, Layout::from_size_align_unchecked(2, 1), 1); } } diff --git a/tests/compile-fail/alloc/reallocate-change-alloc.rs b/tests/compile-fail/alloc/reallocate-change-alloc.rs index 297029676962b..14d05e7457512 100644 --- a/tests/compile-fail/alloc/reallocate-change-alloc.rs +++ b/tests/compile-fail/alloc/reallocate-change-alloc.rs @@ -3,7 +3,7 @@ use std::alloc::{alloc, realloc, Layout}; fn main() { unsafe { let x = alloc(Layout::from_size_align_unchecked(1, 1)); - realloc(x, Layout::from_size_align_unchecked(1, 1), 1); + let _y = realloc(x, Layout::from_size_align_unchecked(1, 1), 1); let _z = *x; //~ ERROR dereferenced after this allocation got freed } } diff --git a/tests/compile-fail/alloc/reallocate-dangling.rs b/tests/compile-fail/alloc/reallocate-dangling.rs index 702ddc0724a33..62eb7582a2f70 100644 --- a/tests/compile-fail/alloc/reallocate-dangling.rs +++ b/tests/compile-fail/alloc/reallocate-dangling.rs @@ -6,6 +6,6 @@ fn main() { unsafe { let x = alloc(Layout::from_size_align_unchecked(1, 1)); dealloc(x, Layout::from_size_align_unchecked(1, 1)); - realloc(x, Layout::from_size_align_unchecked(1, 1), 1); + let _z = realloc(x, Layout::from_size_align_unchecked(1, 1), 1); } } From e6a9b2ce6878f7944f8b414d511afdb5240965b0 Mon Sep 17 00:00:00 2001 From: Noah Lev Date: Sun, 3 Oct 2021 16:28:41 -0700 Subject: [PATCH 2826/3747] Update Miri for detecting uninitialized numbers This commit adds a `-Zmiri-check-number-initialization` flag to check that integers and floats are initialized. This commit also changes some shims to write at type `MaybeUninit<...>` in order to prevent spurious errors from the uninit check. --- src/bin/miri.rs | 3 +++ src/eval.rs | 3 +++ src/machine.rs | 9 +++++++++ src/shims/posix/sync.rs | 29 +++++++++++++++++++++++------ 4 files changed, 38 insertions(+), 6 deletions(-) diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 84e66db2a7d9f..cf32e63322690 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -313,6 +313,9 @@ fn main() { "-Zmiri-symbolic-alignment-check" => { miri_config.check_alignment = miri::AlignmentCheck::Symbolic; } + "-Zmiri-check-number-validity" => { + miri_config.check_number_validity = true; + } "-Zmiri-disable-abi-check" => { miri_config.check_abi = false; } diff --git a/src/eval.rs b/src/eval.rs index 5d8d332fcd9c1..ac32af30c1de3 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -66,6 +66,8 @@ pub struct MiriConfig { pub stacked_borrows: bool, /// Controls alignment checking. pub check_alignment: AlignmentCheck, + /// Controls integer and float validity (e.g., initialization) checking. + pub check_number_validity: bool, /// Controls function [ABI](Abi) checking. pub check_abi: bool, /// Action for an op requiring communication with the host. @@ -104,6 +106,7 @@ impl Default for MiriConfig { validate: true, stacked_borrows: true, check_alignment: AlignmentCheck::Int, + check_number_validity: false, check_abi: true, isolated_op: IsolatedOp::Reject(RejectOpWith::Abort), ignore_leaks: false, diff --git a/src/machine.rs b/src/machine.rs index 23278a4891fb7..0ead28b36c75c 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -304,6 +304,9 @@ pub struct Evaluator<'mir, 'tcx> { /// Whether to enforce the validity invariant. pub(crate) validate: bool, + /// Whether to enforce validity (e.g., initialization) of integers and floats. + pub(crate) enforce_number_validity: bool, + /// Whether to enforce [ABI](Abi) of function calls. pub(crate) enforce_abi: bool, @@ -356,6 +359,7 @@ impl<'mir, 'tcx> Evaluator<'mir, 'tcx> { tls: TlsData::default(), isolated_op: config.isolated_op, validate: config.validate, + enforce_number_validity: config.check_number_validity, enforce_abi: config.check_abi, file_handler: Default::default(), dir_handler: Default::default(), @@ -426,6 +430,11 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { ecx.machine.validate } + #[inline(always)] + fn enforce_number_validity(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool { + ecx.machine.enforce_number_validity + } + #[inline(always)] fn enforce_abi(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool { ecx.machine.enforce_abi diff --git a/src/shims/posix/sync.rs b/src/shims/posix/sync.rs index 782765c7784bd..606f58a207e56 100644 --- a/src/shims/posix/sync.rs +++ b/src/shims/posix/sync.rs @@ -1,5 +1,8 @@ use std::time::SystemTime; +use rustc_hir::LangItem; +use rustc_middle::ty::{layout::TyAndLayout, query::TyCtxtAt, subst::Subst, Ty}; + use crate::*; use thread::Time; @@ -44,7 +47,7 @@ fn mutexattr_set_kind<'mir, 'tcx: 'mir>( attr_op: &OpTy<'tcx, Tag>, kind: impl Into>, ) -> InterpResult<'tcx, ()> { - ecx.write_scalar_at_offset(attr_op, 0, kind, ecx.machine.layouts.i32) + ecx.write_scalar_at_offset(attr_op, 0, kind, layout_of_maybe_uninit(ecx.tcx, ecx.tcx.types.i32)) } // pthread_mutex_t is between 24 and 48 bytes, depending on the platform. @@ -79,7 +82,7 @@ fn mutex_set_kind<'mir, 'tcx: 'mir>( mutex_op, offset, kind, - ecx.machine.layouts.i32, + layout_of_maybe_uninit(ecx.tcx, ecx.tcx.types.i32), AtomicWriteOp::Relaxed, ) } @@ -100,7 +103,7 @@ fn mutex_set_id<'mir, 'tcx: 'mir>( mutex_op, 4, id, - ecx.machine.layouts.u32, + layout_of_maybe_uninit(ecx.tcx, ecx.tcx.types.u32), AtomicWriteOp::Relaxed, ) } @@ -144,7 +147,7 @@ fn rwlock_set_id<'mir, 'tcx: 'mir>( rwlock_op, 4, id, - ecx.machine.layouts.u32, + layout_of_maybe_uninit(ecx.tcx, ecx.tcx.types.u32), AtomicWriteOp::Relaxed, ) } @@ -211,7 +214,7 @@ fn cond_set_id<'mir, 'tcx: 'mir>( cond_op, 4, id, - ecx.machine.layouts.u32, + layout_of_maybe_uninit(ecx.tcx, ecx.tcx.types.u32), AtomicWriteOp::Relaxed, ) } @@ -244,7 +247,12 @@ fn cond_set_clock_id<'mir, 'tcx: 'mir>( cond_op: &OpTy<'tcx, Tag>, clock_id: impl Into>, ) -> InterpResult<'tcx, ()> { - ecx.write_scalar_at_offset(cond_op, 8, clock_id, ecx.machine.layouts.i32) + ecx.write_scalar_at_offset( + cond_op, + 8, + clock_id, + layout_of_maybe_uninit(ecx.tcx, ecx.tcx.types.i32), + ) } /// Try to reacquire the mutex associated with the condition variable after we @@ -788,3 +796,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(0) } } + +fn layout_of_maybe_uninit<'tcx>(tcx: TyCtxtAt<'tcx>, param: Ty<'tcx>) -> TyAndLayout<'tcx> { + let def_id = tcx.require_lang_item(LangItem::MaybeUninit, None); + let def_ty = tcx.type_of(def_id); + let ty = def_ty.subst(*tcx, &[param.into()]); + + let param_env = tcx.param_env(def_id); + tcx.layout_of(param_env.and(ty)).unwrap() +} From 1659ef42069c53595dc41a530839a5fc04c5988b Mon Sep 17 00:00:00 2001 From: Noah Lev Date: Fri, 29 Oct 2021 16:36:41 -0700 Subject: [PATCH 2827/3747] Add docs for `-Zmiri-check-number-validity` --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 0c5b591e72d50..504759eabd247 100644 --- a/README.md +++ b/README.md @@ -199,6 +199,10 @@ up the sysroot. If you are using `miri` (the Miri driver) directly, see the Miri adds its own set of `-Z` flags, which are usually set via the `MIRIFLAGS` environment variable: +* `-Zmiri-check-number-validity` enables checking of integer and float validity + (e.g., they must be initialized and not carry pointer provenance) as part of + enforcing validity invariants. This has no effect when + `-Zmiri-disable-validation` is present. * `-Zmiri-compare-exchange-weak-failure-rate=` changes the failure rate of `compare_exchange_weak` operations. The default is `0.8` (so 4 out of 5 weak ops will fail). You can change it to any value between `0.0` and `1.0`, where `1.0` means it From b3be6b44b6a19b36ea7c579f757fb5764e83663b Mon Sep 17 00:00:00 2001 From: Noah Lev Date: Sun, 24 Oct 2021 13:43:47 -0700 Subject: [PATCH 2828/3747] Add tests for `-Zmiri-check-number-validity` --- tests/compile-fail/uninit_float.rs | 8 ++++++++ tests/compile-fail/uninit_integer.rs | 8 ++++++++ tests/compile-fail/uninit_integer_signed.rs | 8 ++++++++ tests/run-pass/uninit_number_ignored.rs | 8 ++++++++ 4 files changed, 32 insertions(+) create mode 100644 tests/compile-fail/uninit_float.rs create mode 100644 tests/compile-fail/uninit_integer.rs create mode 100644 tests/compile-fail/uninit_integer_signed.rs create mode 100644 tests/run-pass/uninit_number_ignored.rs diff --git a/tests/compile-fail/uninit_float.rs b/tests/compile-fail/uninit_float.rs new file mode 100644 index 0000000000000..06953e1ced966 --- /dev/null +++ b/tests/compile-fail/uninit_float.rs @@ -0,0 +1,8 @@ +// compile-flags: -Zmiri-check-number-validity + +// This test is adapted from https://github.com/rust-lang/miri/issues/1340#issue-600900312. + +fn main() { + let _val = unsafe { std::mem::MaybeUninit::::uninit().assume_init() }; + //~^ ERROR type validation failed at .value: encountered uninitialized bytes, but expected initialized plain (non-pointer) bytes +} diff --git a/tests/compile-fail/uninit_integer.rs b/tests/compile-fail/uninit_integer.rs new file mode 100644 index 0000000000000..757f69c050fe5 --- /dev/null +++ b/tests/compile-fail/uninit_integer.rs @@ -0,0 +1,8 @@ +// compile-flags: -Zmiri-check-number-validity + +// This test is from https://github.com/rust-lang/miri/issues/1340#issue-600900312. + +fn main() { + let _val = unsafe { std::mem::MaybeUninit::::uninit().assume_init() }; + //~^ ERROR type validation failed at .value: encountered uninitialized bytes, but expected initialized plain (non-pointer) bytes +} diff --git a/tests/compile-fail/uninit_integer_signed.rs b/tests/compile-fail/uninit_integer_signed.rs new file mode 100644 index 0000000000000..bb5d7314a7c1f --- /dev/null +++ b/tests/compile-fail/uninit_integer_signed.rs @@ -0,0 +1,8 @@ +// compile-flags: -Zmiri-check-number-validity + +// This test is adapted from https://github.com/rust-lang/miri/issues/1340#issue-600900312. + +fn main() { + let _val = unsafe { std::mem::MaybeUninit::::uninit().assume_init() }; + //~^ ERROR type validation failed at .value: encountered uninitialized bytes, but expected initialized plain (non-pointer) bytes +} diff --git a/tests/run-pass/uninit_number_ignored.rs b/tests/run-pass/uninit_number_ignored.rs new file mode 100644 index 0000000000000..77d6af6e99cf7 --- /dev/null +++ b/tests/run-pass/uninit_number_ignored.rs @@ -0,0 +1,8 @@ +// This test is adapted from https://github.com/rust-lang/miri/issues/1340#issue-600900312. +// This test passes because -Zmiri-check-number-validity is not passed. + +fn main() { + let _val1 = unsafe { std::mem::MaybeUninit::::uninit().assume_init() }; + let _val2 = unsafe { std::mem::MaybeUninit::::uninit().assume_init() }; + let _val3 = unsafe { std::mem::MaybeUninit::::uninit().assume_init() }; +} From 1cca2acf9553e0993a79e0e1a5443cac3ead6a03 Mon Sep 17 00:00:00 2001 From: Noah Lev Date: Fri, 29 Oct 2021 16:40:20 -0700 Subject: [PATCH 2829/3747] Add test for uninit raw ptrs --- tests/compile-fail/uninit_raw_ptr.rs | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 tests/compile-fail/uninit_raw_ptr.rs diff --git a/tests/compile-fail/uninit_raw_ptr.rs b/tests/compile-fail/uninit_raw_ptr.rs new file mode 100644 index 0000000000000..beb9ad1270941 --- /dev/null +++ b/tests/compile-fail/uninit_raw_ptr.rs @@ -0,0 +1,4 @@ +fn main() { + let _val = unsafe { std::mem::MaybeUninit::<*const u8>::uninit().assume_init() }; + //~^ ERROR type validation failed at .value: encountered uninitialized raw pointer +} From 6dd10820dd207d392f58b36ff919b8b17cfa1261 Mon Sep 17 00:00:00 2001 From: Noah Lev Date: Wed, 10 Nov 2021 11:38:35 -0800 Subject: [PATCH 2830/3747] rustup So that we get rust-lang/rust#88670. --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index fd8c69e11238b..d43b9e8197bba 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -db062de72b0a064f45b6f86894cbdc7c0ec68844 +68ca579406f2fa9ec62710e4a4d5d3e07a168d3c From d8bee92aee3394d2fd9a0b83516651ee7141b032 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 13 Nov 2021 15:40:26 -0500 Subject: [PATCH 2831/3747] rename track-raw-pointers flag to tag-raw-pointers --- README.md | 15 +++++++-------- src/bin/miri.rs | 8 +++++++- src/eval.rs | 4 ++-- src/machine.rs | 2 +- src/stacked_borrows.rs | 10 +++++----- test-cargo-miri/run-test.py | 2 +- tests/compile-fail/box-cell-alias.rs | 2 +- .../compile-fail/stacked_borrows/raw_tracking.rs | 2 +- tests/compile-fail/stacked_borrows/zst_slice.rs | 2 +- tests/run-pass/btreemap.rs | 2 +- .../concurrency/tls_lib_drop_single_thread.rs | 2 +- tests/run-pass/rc.rs | 2 +- tests/run-pass/slices.rs | 2 +- tests/run-pass/stacked-borrows/stacked-borrows.rs | 2 +- tests/run-pass/strings.rs | 2 +- tests/run-pass/vec.rs | 2 +- tests/run-pass/vecdeque.rs | 2 +- 17 files changed, 34 insertions(+), 29 deletions(-) diff --git a/README.md b/README.md index 504759eabd247..487f8aeb2baf0 100644 --- a/README.md +++ b/README.md @@ -276,14 +276,13 @@ environment variable: is popped from a borrow stack (which is where the tag becomes invalid and any future use of it will error). This helps you in finding out why UB is happening and where in your code would be a good place to look for it. -* `-Zmiri-track-raw-pointers` makes Stacked Borrows track a pointer tag even for - raw pointers. This can make valid code fail to pass the checks, but also can - help identify latent aliasing issues in code that Miri accepts by default. You - can recognize false positives by `` occurring in the message -- this - indicates a pointer that was cast from an integer, so Miri was unable to track - this pointer. Note that it is not currently guaranteed that code that works - with `-Zmiri-track-raw-pointers` also works without - `-Zmiri-track-raw-pointers`, but for the vast majority of code, this will be the case. +* `-Zmiri-tag-raw-pointers` makes Stacked Borrows assign proper tags even for raw pointers. This can + make valid code using int-to-ptr casts fail to pass the checks, but also can help identify latent + aliasing issues in code that Miri accepts by default. You can recognize false positives by + `` occurring in the message -- this indicates a pointer that was cast from an integer, + so Miri was unable to track this pointer. Note that it is not currently guaranteed that code that + works with `-Zmiri-tag-raw-pointers` also works without `-Zmiri-tag-raw-pointers`, but for the + vast majority of code, this will be the case. [function ABI]: https://doc.rust-lang.org/reference/items/functions.html#extern-function-qualifier diff --git a/src/bin/miri.rs b/src/bin/miri.rs index cf32e63322690..672c7e8c9675c 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -359,8 +359,14 @@ fn main() { "-Zmiri-panic-on-unsupported" => { miri_config.panic_on_unsupported = true; } + "-Zmiri-tag-raw-pointers" => { + miri_config.tag_raw = true; + } "-Zmiri-track-raw-pointers" => { - miri_config.track_raw = true; + eprintln!( + "WARNING: -Zmiri-track-raw-pointers has been renamed to -Zmiri-tag-raw-pointers, the old name is deprecated." + ); + miri_config.tag_raw = true; } "--" => { after_dashdash = true; diff --git a/src/eval.rs b/src/eval.rs index ac32af30c1de3..e3f252b50a928 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -87,7 +87,7 @@ pub struct MiriConfig { /// The allocation id to report about. pub tracked_alloc_id: Option, /// Whether to track raw pointers in stacked borrows. - pub track_raw: bool, + pub tag_raw: bool, /// Determine if data race detection should be enabled pub data_race_detector: bool, /// Rate of spurious failures for compare_exchange_weak atomic operations, @@ -116,7 +116,7 @@ impl Default for MiriConfig { tracked_pointer_tag: None, tracked_call_id: None, tracked_alloc_id: None, - track_raw: false, + tag_raw: false, data_race_detector: true, cmpxchg_weak_failure_rate: 0.8, measureme_out: None, diff --git a/src/machine.rs b/src/machine.rs index 0ead28b36c75c..201854e76fa46 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -194,7 +194,7 @@ impl MemoryExtra { Some(RefCell::new(stacked_borrows::GlobalState::new( config.tracked_pointer_tag, config.tracked_call_id, - config.track_raw, + config.tag_raw, ))) } else { None diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 65678b6f01fe1..57c09ea40b68b 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -105,7 +105,7 @@ pub struct GlobalState { /// The call id to trace tracked_call_id: Option, /// Whether to track raw pointers. - track_raw: bool, + tag_raw: bool, } /// Memory extra state gives us interior mutable access to the global state. pub type MemoryExtra = RefCell; @@ -156,7 +156,7 @@ impl GlobalState { pub fn new( tracked_pointer_tag: Option, tracked_call_id: Option, - track_raw: bool, + tag_raw: bool, ) -> Self { GlobalState { next_ptr_id: NonZeroU64::new(1).unwrap(), @@ -165,7 +165,7 @@ impl GlobalState { active_calls: FxHashSet::default(), tracked_pointer_tag, tracked_call_id, - track_raw, + tag_raw, } } @@ -532,7 +532,7 @@ impl Stacks { MiriMemoryKind::Rust | MiriMemoryKind::C | MiriMemoryKind::WinHeap, ) => { let tag = - if extra.track_raw { extra.base_tag(id) } else { extra.base_tag_untagged(id) }; + if extra.tag_raw { extra.base_tag(id) } else { extra.base_tag_untagged(id) }; (tag, Permission::SharedReadWrite) } }; @@ -719,7 +719,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let mem_extra = this.memory.extra.stacked_borrows.as_mut().unwrap().get_mut(); match kind { // Give up tracking for raw pointers. - RefKind::Raw { .. } if !mem_extra.track_raw => SbTag::Untagged, + RefKind::Raw { .. } if !mem_extra.tag_raw => SbTag::Untagged, // All other pointers are properly tracked. _ => SbTag::Tagged(mem_extra.new_ptr()), } diff --git a/test-cargo-miri/run-test.py b/test-cargo-miri/run-test.py index 18671b2e29da1..19965639489bf 100755 --- a/test-cargo-miri/run-test.py +++ b/test-cargo-miri/run-test.py @@ -127,7 +127,7 @@ def test_cargo_miri_test(): test("`cargo miri test` (raw-ptr tracking)", cargo_miri("test"), default_ref, "test.stderr-empty.ref", - env={'MIRIFLAGS': "-Zmiri-track-raw-pointers"}, + env={'MIRIFLAGS': "-Zmiri-tag-raw-pointers"}, ) test("`cargo miri test` (with filter)", cargo_miri("test") + ["--", "--format=pretty", "le1"], diff --git a/tests/compile-fail/box-cell-alias.rs b/tests/compile-fail/box-cell-alias.rs index 5d63fc1d44a5b..58fc3530d7bfe 100644 --- a/tests/compile-fail/box-cell-alias.rs +++ b/tests/compile-fail/box-cell-alias.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-track-raw-pointers +// compile-flags: -Zmiri-tag-raw-pointers // Taken from . diff --git a/tests/compile-fail/stacked_borrows/raw_tracking.rs b/tests/compile-fail/stacked_borrows/raw_tracking.rs index 975aec945c7f5..0d6d0198fbe9c 100644 --- a/tests/compile-fail/stacked_borrows/raw_tracking.rs +++ b/tests/compile-fail/stacked_borrows/raw_tracking.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-track-raw-pointers +// compile-flags: -Zmiri-tag-raw-pointers //! This demonstrates a provenance problem that requires tracking of raw pointers to be detected. fn main() { diff --git a/tests/compile-fail/stacked_borrows/zst_slice.rs b/tests/compile-fail/stacked_borrows/zst_slice.rs index 0804f7303082d..14d5d77a2bb69 100644 --- a/tests/compile-fail/stacked_borrows/zst_slice.rs +++ b/tests/compile-fail/stacked_borrows/zst_slice.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-track-raw-pointers +// compile-flags: -Zmiri-tag-raw-pointers // error-pattern: does not have an appropriate item in the borrow stack fn main() { diff --git a/tests/run-pass/btreemap.rs b/tests/run-pass/btreemap.rs index b704b89fd0507..842ba0f4a8741 100644 --- a/tests/run-pass/btreemap.rs +++ b/tests/run-pass/btreemap.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-track-raw-pointers +// compile-flags: -Zmiri-tag-raw-pointers #![feature(btree_drain_filter)] use std::collections::{BTreeMap, BTreeSet}; use std::mem; diff --git a/tests/run-pass/concurrency/tls_lib_drop_single_thread.rs b/tests/run-pass/concurrency/tls_lib_drop_single_thread.rs index cd1bd6480bcfe..16ca8a0d2eff2 100644 --- a/tests/run-pass/concurrency/tls_lib_drop_single_thread.rs +++ b/tests/run-pass/concurrency/tls_lib_drop_single_thread.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-track-raw-pointers +// compile-flags: -Zmiri-tag-raw-pointers //! Check that destructors of the thread locals are executed on all OSes. #![feature(thread_local_const_init)] diff --git a/tests/run-pass/rc.rs b/tests/run-pass/rc.rs index 91de20ae2b7f3..e00d9df32eec7 100644 --- a/tests/run-pass/rc.rs +++ b/tests/run-pass/rc.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-track-raw-pointers +// compile-flags: -Zmiri-tag-raw-pointers #![feature(new_uninit)] #![feature(get_mut_unchecked)] diff --git a/tests/run-pass/slices.rs b/tests/run-pass/slices.rs index 83d9ff1151889..9d98c44741b44 100644 --- a/tests/run-pass/slices.rs +++ b/tests/run-pass/slices.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-track-raw-pointers +// compile-flags: -Zmiri-tag-raw-pointers #![feature(new_uninit)] #![feature(slice_as_chunks)] #![feature(slice_partition_dedup)] diff --git a/tests/run-pass/stacked-borrows/stacked-borrows.rs b/tests/run-pass/stacked-borrows/stacked-borrows.rs index 0401a6640fd33..8aea945f90939 100644 --- a/tests/run-pass/stacked-borrows/stacked-borrows.rs +++ b/tests/run-pass/stacked-borrows/stacked-borrows.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-track-raw-pointers +// compile-flags: -Zmiri-tag-raw-pointers use std::ptr; // Test various stacked-borrows-related things. diff --git a/tests/run-pass/strings.rs b/tests/run-pass/strings.rs index b009e8bc6c4a4..6998ec6e59b9b 100644 --- a/tests/run-pass/strings.rs +++ b/tests/run-pass/strings.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-track-raw-pointers +// compile-flags: -Zmiri-tag-raw-pointers fn empty() -> &'static str { "" diff --git a/tests/run-pass/vec.rs b/tests/run-pass/vec.rs index 8ed81a5e343ff..c0cf42134527c 100644 --- a/tests/run-pass/vec.rs +++ b/tests/run-pass/vec.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-track-raw-pointers +// compile-flags: -Zmiri-tag-raw-pointers // Gather all references from a mutable iterator and make sure Miri notices if // using them is dangerous. fn test_all_refs<'a, T: 'a>(dummy: &mut T, iter: impl Iterator) { diff --git a/tests/run-pass/vecdeque.rs b/tests/run-pass/vecdeque.rs index 54aeb89ec83ff..f45c21d20781d 100644 --- a/tests/run-pass/vecdeque.rs +++ b/tests/run-pass/vecdeque.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-track-raw-pointers +// compile-flags: -Zmiri-tag-raw-pointers use std::collections::VecDeque; fn test_all_refs<'a, T: 'a>(dummy: &mut T, iter: impl Iterator) { From a15539e9111e4e30c0229c63c99cdba1627a6e5f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 14 Nov 2021 12:16:03 -0500 Subject: [PATCH 2832/3747] run rustdoc with the miri cfg flag --- cargo-miri/bin.rs | 2 ++ test-cargo-miri/src/lib.rs | 6 ++++++ test-cargo-miri/test.default.stdout.ref | 6 +++--- test-cargo-miri/test.filter.stdout.ref | 2 +- 4 files changed, 12 insertions(+), 4 deletions(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index 21f53a45e41f6..9ac1a7086b826 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -1008,6 +1008,8 @@ fn phase_rustdoc(fst_arg: &str, mut args: env::Args) { // rustdoc needs to know the right sysroot. forward_miri_sysroot(&mut cmd); + // make sure the 'miri' flag is set for rustdoc + cmd.arg("--cfg").arg("miri"); // Make rustdoc call us back. let cargo_miri_path = std::env::current_exe().expect("current executable path invalid"); diff --git a/test-cargo-miri/src/lib.rs b/test-cargo-miri/src/lib.rs index 6d9158c54ef4d..66c8aa2eac57e 100644 --- a/test-cargo-miri/src/lib.rs +++ b/test-cargo-miri/src/lib.rs @@ -16,6 +16,12 @@ pub fn make_true() -> bool { issue_1691::use_me() } +/// ```rust +/// cargo_miri_test::miri_only_fn(); +/// ``` +#[cfg(miri)] +pub fn miri_only_fn() {} + pub fn main() { println!("imported main"); } diff --git a/test-cargo-miri/test.default.stdout.ref b/test-cargo-miri/test.default.stdout.ref index d2f94bb5950d8..ee8625357509a 100644 --- a/test-cargo-miri/test.default.stdout.ref +++ b/test-cargo-miri/test.default.stdout.ref @@ -10,7 +10,7 @@ running 7 tests test result: ok. 6 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out -running 3 tests -... -test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME +running 4 tests +.... +test result: ok. 4 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in $TIME diff --git a/test-cargo-miri/test.filter.stdout.ref b/test-cargo-miri/test.filter.stdout.ref index 6b26e17ff8bb9..d14bb8796e850 100644 --- a/test-cargo-miri/test.filter.stdout.ref +++ b/test-cargo-miri/test.filter.stdout.ref @@ -13,5 +13,5 @@ test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 6 filtered out running 0 tests -test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 3 filtered out; finished in $TIME +test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 4 filtered out; finished in $TIME From 77095f8557f241aa0d8dade370f714c4af224cb3 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 17 Nov 2021 10:34:32 -0500 Subject: [PATCH 2833/3747] tweak cron job time --- .github/workflows/ci.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ce13647fa586a..94b9dd6fe55f7 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -10,8 +10,7 @@ on: branches: - 'master' schedule: - # Use to conveniently edit cron schedule. - - cron: '0 7 * * *' # At 07:00 UTC every day. + - cron: '5 15 * * *' # At 15:05 UTC every day. jobs: build: From 1593f38401cbf3230bd736d874bb6f6fdc15a368 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 17 Nov 2021 21:12:45 -0500 Subject: [PATCH 2834/3747] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index d43b9e8197bba..45cd53ac6c143 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -68ca579406f2fa9ec62710e4a4d5d3e07a168d3c +c9c4b5d7276297679387189d96a952f2b760e7ad From 0766da6fbeba2e4cd3183f181e10bbc7ba69ade8 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 18 Nov 2021 09:36:01 -0500 Subject: [PATCH 2835/3747] implement simd_add --- src/shims/intrinsics.rs | 18 ++++++++++++++++++ tests/run-pass/portable-simd.rs | 8 ++++++++ 2 files changed, 26 insertions(+) create mode 100644 tests/run-pass/portable-simd.rs diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index f2f046a3ada13..9f44f5bac6ce8 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -305,6 +305,24 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(res, dest)?; } + // SIMD operations + "simd_add" => { + let &[ref left, ref right] = check_arg_count(args)?; + let (left, left_len) = this.operand_to_simd(left)?; + let (right, right_len) = this.operand_to_simd(right)?; + let (dest, dest_len) = this.place_to_simd(dest)?; + + assert_eq!(dest_len, left_len); + assert_eq!(dest_len, right_len); + + for i in 0..dest_len { + let left = this.read_immediate(&this.mplace_index(&left, i)?.into())?; + let right = this.read_immediate(&this.mplace_index(&right, i)?.into())?; + let dest = this.mplace_index(&dest, i)?.into(); + this.binop_ignore_overflow(mir::BinOp::Add, &left, &right, &dest)?; + } + } + // Atomic operations "atomic_load" => this.atomic_load(args, dest, AtomicReadOp::SeqCst)?, "atomic_load_relaxed" => this.atomic_load(args, dest, AtomicReadOp::Relaxed)?, diff --git a/tests/run-pass/portable-simd.rs b/tests/run-pass/portable-simd.rs new file mode 100644 index 0000000000000..1ea7931aed321 --- /dev/null +++ b/tests/run-pass/portable-simd.rs @@ -0,0 +1,8 @@ +#![feature(portable_simd)] +use std::simd::*; + +fn main() { + let a = f32x4::splat(10.0); + let b = f32x4::from_array([1.0, 2.0, 3.0, 4.0]); + assert_eq!(a + b, f32x4::from_array([11.0, 12.0, 13.0, 14.0])); +} From b816cb94e79f7f23e12b567e7f412125fe1ef8b7 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 18 Nov 2021 09:42:30 -0500 Subject: [PATCH 2836/3747] implement SIMD sub, mul, div; also test i32 binops --- src/shims/intrinsics.rs | 12 ++++++++++-- tests/run-pass/portable-simd.rs | 21 ++++++++++++++++++++- 2 files changed, 30 insertions(+), 3 deletions(-) diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 9f44f5bac6ce8..d684b41ed81d9 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -306,7 +306,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // SIMD operations - "simd_add" => { + "simd_add" | "simd_sub" | "simd_mul" | "simd_div" => { let &[ref left, ref right] = check_arg_count(args)?; let (left, left_len) = this.operand_to_simd(left)?; let (right, right_len) = this.operand_to_simd(right)?; @@ -315,11 +315,19 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx assert_eq!(dest_len, left_len); assert_eq!(dest_len, right_len); + let op = match intrinsic_name { + "simd_add" => mir::BinOp::Add, + "simd_sub" => mir::BinOp::Sub, + "simd_mul" => mir::BinOp::Mul, + "simd_div" => mir::BinOp::Div, + _ => unreachable!(), + }; + for i in 0..dest_len { let left = this.read_immediate(&this.mplace_index(&left, i)?.into())?; let right = this.read_immediate(&this.mplace_index(&right, i)?.into())?; let dest = this.mplace_index(&dest, i)?.into(); - this.binop_ignore_overflow(mir::BinOp::Add, &left, &right, &dest)?; + this.binop_ignore_overflow(op, &left, &right, &dest)?; } } diff --git a/tests/run-pass/portable-simd.rs b/tests/run-pass/portable-simd.rs index 1ea7931aed321..42a6befd868be 100644 --- a/tests/run-pass/portable-simd.rs +++ b/tests/run-pass/portable-simd.rs @@ -1,8 +1,27 @@ #![feature(portable_simd)] use std::simd::*; -fn main() { +fn simd_ops_f32() { let a = f32x4::splat(10.0); let b = f32x4::from_array([1.0, 2.0, 3.0, 4.0]); assert_eq!(a + b, f32x4::from_array([11.0, 12.0, 13.0, 14.0])); + assert_eq!(a - b, f32x4::from_array([9.0, 8.0, 7.0, 6.0])); + assert_eq!(a * b, f32x4::from_array([10.0, 20.0, 30.0, 40.0])); + assert_eq!(b / a, f32x4::from_array([0.1, 0.2, 0.3, 0.4])); + assert_eq!(a / 2.0, f32x4::splat(5.0)); +} + +fn simd_ops_i32() { + let a = i32x4::splat(10); + let b = i32x4::from_array([1, 2, 3, 4]); + assert_eq!(a + b, i32x4::from_array([11, 12, 13, 14])); + assert_eq!(a - b, i32x4::from_array([9, 8, 7, 6])); + assert_eq!(a * b, i32x4::from_array([10, 20, 30, 40])); + assert_eq!(a / b, i32x4::from_array([10, 5, 3, 2])); + assert_eq!(a / 2, i32x4::splat(5)); +} + +fn main() { + simd_ops_f32(); + simd_ops_i32(); } From 84027dcd228848e29ce3fa552caa615a9b7d5de5 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 20 Nov 2021 22:39:22 -0500 Subject: [PATCH 2837/3747] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 45cd53ac6c143..e7e504a38a7c7 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -c9c4b5d7276297679387189d96a952f2b760e7ad +5bc98076f37dd8c1476de4bbe0515c55a65332b7 From 7dd1f0571cde175af95b62ad805ba7381680a048 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 23 Nov 2021 13:53:02 -0500 Subject: [PATCH 2838/3747] test for overflow-checks=off --- tests/run-pass/overflow_checks_off.rs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 tests/run-pass/overflow_checks_off.rs diff --git a/tests/run-pass/overflow_checks_off.rs b/tests/run-pass/overflow_checks_off.rs new file mode 100644 index 0000000000000..d6c6971e49521 --- /dev/null +++ b/tests/run-pass/overflow_checks_off.rs @@ -0,0 +1,18 @@ +// compile-flags: -C overflow-checks=off + +// Check that we correctly implement the intended behavior of these operators +// when they are not being overflow-checked. + +// FIXME: if we call the functions in `std::ops`, we still get the panics. +// Miri does not implement the codegen-time hack that backs `#[rustc_inherit_overflow_checks]`. +// use std::ops::*; + +fn main() { + assert_eq!(-{-0x80i8}, -0x80); + + assert_eq!(0xffu8 + 1, 0_u8); + assert_eq!(0u8 - 1, 0xff_u8); + assert_eq!(0xffu8 * 2, 0xfe_u8); + assert_eq!(1u8 << 9, 2_u8); + assert_eq!(2u8 >> 9, 1_u8); +} From c4502cbbe80b691a28de18373fba0d508370177f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 23 Nov 2021 14:32:03 -0500 Subject: [PATCH 2839/3747] async-fn test: make run_fut more general and entirely safe --- tests/run-pass/async-fn.rs | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/tests/run-pass/async-fn.rs b/tests/run-pass/async-fn.rs index d03c2cf282b8d..414d5aaf5cc7c 100644 --- a/tests/run-pass/async-fn.rs +++ b/tests/run-pass/async-fn.rs @@ -1,8 +1,6 @@ #![feature(never_type)] -use std::{future::Future, pin::Pin, task::Poll}; -use std::task::{Wake, Waker, Context}; -use std::sync::Arc; +use std::future::Future; // See if we can run a basic `async fn` pub async fn foo(x: &u32, y: u32) -> u32 { @@ -47,7 +45,10 @@ async fn partial_init(x: u32) -> u32 { let _x: (String, !) = (String::new(), return async { x + x }.await); } -fn run_fut(mut fut: impl Future, output: u32) { +fn run_fut(fut: impl Future) -> T { + use std::sync::Arc; + use std::task::{Context, Poll, Wake, Waker}; + struct MyWaker; impl Wake for MyWaker { fn wake(self: Arc) { @@ -57,16 +58,20 @@ fn run_fut(mut fut: impl Future, output: u32) { let waker = Waker::from(Arc::new(MyWaker)); let mut context = Context::from_waker(&waker); - assert_eq!(unsafe { Pin::new_unchecked(&mut fut) }.poll(&mut context), Poll::Ready(output)); + + let mut pinned = Box::pin(fut); + loop { + match pinned.as_mut().poll(&mut context) { + Poll::Pending => continue, + Poll::Ready(v) => return v, + } + } } fn main() { let x = 5; - run_fut(foo(&x, 7), 31); - - run_fut(build_aggregate(1, 2, 3, 4), 10); - - run_fut(includes_never(false, 4), 16); - - run_fut(partial_init(4), 8); + assert_eq!(run_fut(foo(&x, 7)), 31); + assert_eq!(run_fut(build_aggregate(1, 2, 3, 4)), 10); + assert_eq!(run_fut(includes_never(false, 4)), 16); + assert_eq!(run_fut(partial_init(4)), 8); } From a534bbbf8aeb14d2ee1c2d167e6e6073a114bf69 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 25 Nov 2021 17:13:16 -0500 Subject: [PATCH 2840/3747] portable SIMD: add rem intrinsic; test div and rem intrinsic UB --- src/shims/intrinsics.rs | 3 ++- .../{div-by-zero-1.rs => div-by-zero.rs} | 0 .../{div-by-zero-2.rs => rem-by-zero.rs} | 0 tests/compile-fail/intrinsics/simd-div-by-zero.rs | 15 +++++++++++++++ tests/compile-fail/intrinsics/simd-rem-by-zero.rs | 15 +++++++++++++++ tests/run-pass/portable-simd.rs | 2 ++ 6 files changed, 34 insertions(+), 1 deletion(-) rename tests/compile-fail/intrinsics/{div-by-zero-1.rs => div-by-zero.rs} (100%) rename tests/compile-fail/intrinsics/{div-by-zero-2.rs => rem-by-zero.rs} (100%) create mode 100644 tests/compile-fail/intrinsics/simd-div-by-zero.rs create mode 100644 tests/compile-fail/intrinsics/simd-rem-by-zero.rs diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index d684b41ed81d9..547f23f620d2b 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -306,7 +306,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // SIMD operations - "simd_add" | "simd_sub" | "simd_mul" | "simd_div" => { + "simd_add" | "simd_sub" | "simd_mul" | "simd_div" | "simd_rem" => { let &[ref left, ref right] = check_arg_count(args)?; let (left, left_len) = this.operand_to_simd(left)?; let (right, right_len) = this.operand_to_simd(right)?; @@ -320,6 +320,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "simd_sub" => mir::BinOp::Sub, "simd_mul" => mir::BinOp::Mul, "simd_div" => mir::BinOp::Div, + "simd_rem" => mir::BinOp::Rem, _ => unreachable!(), }; diff --git a/tests/compile-fail/intrinsics/div-by-zero-1.rs b/tests/compile-fail/intrinsics/div-by-zero.rs similarity index 100% rename from tests/compile-fail/intrinsics/div-by-zero-1.rs rename to tests/compile-fail/intrinsics/div-by-zero.rs diff --git a/tests/compile-fail/intrinsics/div-by-zero-2.rs b/tests/compile-fail/intrinsics/rem-by-zero.rs similarity index 100% rename from tests/compile-fail/intrinsics/div-by-zero-2.rs rename to tests/compile-fail/intrinsics/rem-by-zero.rs diff --git a/tests/compile-fail/intrinsics/simd-div-by-zero.rs b/tests/compile-fail/intrinsics/simd-div-by-zero.rs new file mode 100644 index 0000000000000..4244e63d23e5d --- /dev/null +++ b/tests/compile-fail/intrinsics/simd-div-by-zero.rs @@ -0,0 +1,15 @@ +#![feature(platform_intrinsics, repr_simd)] + +extern "platform-intrinsic" { + pub(crate) fn simd_div(x: T, y: T) -> T; +} + +#[repr(simd)] +#[allow(non_camel_case_types)] +struct i32x2(i32, i32); + +fn main() { unsafe { + let x = i32x2(1, 1); + let y = i32x2(1, 0); + simd_div(x, y); //~ERROR Undefined Behavior: dividing by zero +} } diff --git a/tests/compile-fail/intrinsics/simd-rem-by-zero.rs b/tests/compile-fail/intrinsics/simd-rem-by-zero.rs new file mode 100644 index 0000000000000..bc3128b5fb5f1 --- /dev/null +++ b/tests/compile-fail/intrinsics/simd-rem-by-zero.rs @@ -0,0 +1,15 @@ +#![feature(platform_intrinsics, repr_simd)] + +extern "platform-intrinsic" { + pub(crate) fn simd_rem(x: T, y: T) -> T; +} + +#[repr(simd)] +#[allow(non_camel_case_types)] +struct i32x2(i32, i32); + +fn main() { unsafe { + let x = i32x2(1, 1); + let y = i32x2(1, 0); + simd_rem(x, y); //~ERROR Undefined Behavior: calculating the remainder with a divisor of zero +} } diff --git a/tests/run-pass/portable-simd.rs b/tests/run-pass/portable-simd.rs index 42a6befd868be..2d94c87ff0428 100644 --- a/tests/run-pass/portable-simd.rs +++ b/tests/run-pass/portable-simd.rs @@ -9,6 +9,7 @@ fn simd_ops_f32() { assert_eq!(a * b, f32x4::from_array([10.0, 20.0, 30.0, 40.0])); assert_eq!(b / a, f32x4::from_array([0.1, 0.2, 0.3, 0.4])); assert_eq!(a / 2.0, f32x4::splat(5.0)); + assert_eq!(a % b, f32x4::from_array([0.0, 0.0, 1.0, 2.0])); } fn simd_ops_i32() { @@ -19,6 +20,7 @@ fn simd_ops_i32() { assert_eq!(a * b, i32x4::from_array([10, 20, 30, 40])); assert_eq!(a / b, i32x4::from_array([10, 5, 3, 2])); assert_eq!(a / 2, i32x4::splat(5)); + assert_eq!(a % b, i32x4::from_array([0, 0, 1, 2])); } fn main() { From 4414d963233ab37f2c3941e7b5dde043a77d37f8 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 25 Nov 2021 17:24:47 -0500 Subject: [PATCH 2841/3747] implement shl and shr SIMD intrinsics --- src/shims/intrinsics.rs | 25 ++++++++++++++++--- .../intrinsics/simd-shl-too-far.rs | 15 +++++++++++ .../intrinsics/simd-shr-too-far.rs | 15 +++++++++++ tests/run-pass/portable-simd.rs | 2 ++ 4 files changed, 54 insertions(+), 3 deletions(-) create mode 100644 tests/compile-fail/intrinsics/simd-shl-too-far.rs create mode 100644 tests/compile-fail/intrinsics/simd-shr-too-far.rs diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 547f23f620d2b..f80062668f3eb 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -306,7 +306,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // SIMD operations - "simd_add" | "simd_sub" | "simd_mul" | "simd_div" | "simd_rem" => { + #[rustfmt::skip] + | "simd_add" + | "simd_sub" + | "simd_mul" + | "simd_div" + | "simd_rem" + | "simd_shl" + | "simd_shr" => { let &[ref left, ref right] = check_arg_count(args)?; let (left, left_len) = this.operand_to_simd(left)?; let (right, right_len) = this.operand_to_simd(right)?; @@ -321,14 +328,26 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "simd_mul" => mir::BinOp::Mul, "simd_div" => mir::BinOp::Div, "simd_rem" => mir::BinOp::Rem, + "simd_shl" => mir::BinOp::Shl, + "simd_shr" => mir::BinOp::Shr, _ => unreachable!(), }; for i in 0..dest_len { let left = this.read_immediate(&this.mplace_index(&left, i)?.into())?; let right = this.read_immediate(&this.mplace_index(&right, i)?.into())?; - let dest = this.mplace_index(&dest, i)?.into(); - this.binop_ignore_overflow(op, &left, &right, &dest)?; + let dest = this.mplace_index(&dest, i)?; + let (val, overflowed, ty) = this.overflowing_binary_op(op, &left, &right)?; + assert_eq!(ty, dest.layout.ty); + if matches!(op, mir::BinOp::Shl | mir::BinOp::Shr) { + // Shifts have extra UB as SIMD operations that the MIR binop does not have. + // See . + if overflowed { + let r_val = right.to_scalar()?.to_bits(right.layout.size)?; + throw_ub_format!("overflowing shift by {} in `{}` in SIMD lane {}", r_val, intrinsic_name, i); + } + } + this.write_scalar(val, &dest.into())?; } } diff --git a/tests/compile-fail/intrinsics/simd-shl-too-far.rs b/tests/compile-fail/intrinsics/simd-shl-too-far.rs new file mode 100644 index 0000000000000..b973386f1b5c8 --- /dev/null +++ b/tests/compile-fail/intrinsics/simd-shl-too-far.rs @@ -0,0 +1,15 @@ +#![feature(platform_intrinsics, repr_simd)] + +extern "platform-intrinsic" { + pub(crate) fn simd_shl(x: T, y: T) -> T; +} + +#[repr(simd)] +#[allow(non_camel_case_types)] +struct i32x2(i32, i32); + +fn main() { unsafe { + let x = i32x2(1, 1); + let y = i32x2(100, 0); + simd_shl(x, y); //~ERROR overflowing shift by 100 in `simd_shl` in SIMD lane 0 +} } diff --git a/tests/compile-fail/intrinsics/simd-shr-too-far.rs b/tests/compile-fail/intrinsics/simd-shr-too-far.rs new file mode 100644 index 0000000000000..0b4eb8c116797 --- /dev/null +++ b/tests/compile-fail/intrinsics/simd-shr-too-far.rs @@ -0,0 +1,15 @@ +#![feature(platform_intrinsics, repr_simd)] + +extern "platform-intrinsic" { + pub(crate) fn simd_shr(x: T, y: T) -> T; +} + +#[repr(simd)] +#[allow(non_camel_case_types)] +struct i32x2(i32, i32); + +fn main() { unsafe { + let x = i32x2(1, 1); + let y = i32x2(20, 40); + simd_shr(x, y); //~ERROR overflowing shift by 40 in `simd_shr` in SIMD lane 1 +} } diff --git a/tests/run-pass/portable-simd.rs b/tests/run-pass/portable-simd.rs index 2d94c87ff0428..5d33376618780 100644 --- a/tests/run-pass/portable-simd.rs +++ b/tests/run-pass/portable-simd.rs @@ -21,6 +21,8 @@ fn simd_ops_i32() { assert_eq!(a / b, i32x4::from_array([10, 5, 3, 2])); assert_eq!(a / 2, i32x4::splat(5)); assert_eq!(a % b, i32x4::from_array([0, 0, 1, 2])); + assert_eq!(b << 2, i32x4::from_array([4, 8, 12, 16])); + assert_eq!(b >> 1, i32x4::from_array([0, 1, 1, 2])); } fn main() { From 5d71528e4dc614be312e5f9565bbe67d3292efc7 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 25 Nov 2021 17:35:14 -0500 Subject: [PATCH 2842/3747] hack to work around RA quirk --- cargo-miri/miri | 3 +++ miri | 5 +++-- 2 files changed, 6 insertions(+), 2 deletions(-) create mode 100755 cargo-miri/miri diff --git a/cargo-miri/miri b/cargo-miri/miri new file mode 100755 index 0000000000000..ed8c80b33fd06 --- /dev/null +++ b/cargo-miri/miri @@ -0,0 +1,3 @@ +#!/bin/sh +# Hack to work around https://github.com/rust-analyzer/rust-analyzer/issues/10793. +exec "$(dirname "$0")"/../miri "$@" diff --git a/miri b/miri index 337b2a496de87..4be1d5bc78f83 100755 --- a/miri +++ b/miri @@ -39,10 +39,11 @@ EOF TARGET=$(rustc --version --verbose | grep "^host:" | cut -d ' ' -f 2) SYSROOT=$(rustc --print sysroot) LIBDIR=$SYSROOT/lib/rustlib/$TARGET/lib -MIRIDIR=$(dirname "$0") if readlink -e . &>/dev/null; then # This platform supports `readlink -e`. - MIRIDIR=$(readlink -e "$MIRIDIR") + MIRIDIR=$(dirname "$(readlink -e "$0")") +else + MIRIDIR=$(dirname "$0") fi if ! test -d "$LIBDIR"; then echo "Something went wrong determining the library dir." From d800d1e2cbe86540a500d1d1cbea5e4a7a207e53 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 27 Nov 2021 17:15:14 -0500 Subject: [PATCH 2843/3747] rustup; stub support for some extern statics used for weak symbols --- rust-version | 2 +- src/machine.rs | 16 ++++++++++------ 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/rust-version b/rust-version index e7e504a38a7c7..0844897398bf3 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -5bc98076f37dd8c1476de4bbe0515c55a65332b7 +686e313a9aa14107c8631ffe48fa09110a7692db diff --git a/src/machine.rs b/src/machine.rs index 201854e76fa46..b1998ccccaa46 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -228,18 +228,22 @@ impl MemoryExtra { ) -> InterpResult<'tcx> { match this.tcx.sess.target.os.as_str() { "linux" => { - // "__cxa_thread_atexit_impl" - // This should be all-zero, pointer-sized. - let layout = this.machine.layouts.usize; - let place = this.allocate(layout, MiriMemoryKind::ExternStatic.into())?; - this.write_scalar(Scalar::from_machine_usize(0, this), &place.into())?; - Self::add_extern_static(this, "__cxa_thread_atexit_impl", place.ptr); // "environ" Self::add_extern_static( this, "environ", this.machine.env_vars.environ.unwrap().ptr, ); + // A couple zero-initialized pointer-sized extern statics. + // Most of them are for weak symbols, which we all set to null (indicating that the + // symbol is not supported, and triggering fallback code which ends up calling a + // syscall that we do support). + for name in &["__cxa_thread_atexit_impl", "getrandom", "statx"] { + let layout = this.machine.layouts.usize; + let place = this.allocate(layout, MiriMemoryKind::ExternStatic.into())?; + this.write_scalar(Scalar::from_machine_usize(0, this), &place.into())?; + Self::add_extern_static(this, name, place.ptr); + } } "windows" => { // "_tls_used" From ee666d8987f29a86a8bd37a85aecc9608ba2d2eb Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 28 Nov 2021 10:07:31 -0500 Subject: [PATCH 2844/3747] add tests for alignment on array initialization --- rust-version | 2 +- tests/run-pass/async-fn.rs | 13 ++++++++++++ tests/run-pass/issue-miri-1925.rs | 33 +++++++++++++++++++++++++++++++ 3 files changed, 47 insertions(+), 1 deletion(-) create mode 100644 tests/run-pass/issue-miri-1925.rs diff --git a/rust-version b/rust-version index 0844897398bf3..cc01c7ccb4a88 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -686e313a9aa14107c8631ffe48fa09110a7692db +58f9efd36de5669ab731ec7ebf565999ff17b159 diff --git a/tests/run-pass/async-fn.rs b/tests/run-pass/async-fn.rs index 414d5aaf5cc7c..1602b5638e903 100644 --- a/tests/run-pass/async-fn.rs +++ b/tests/run-pass/async-fn.rs @@ -45,6 +45,18 @@ async fn partial_init(x: u32) -> u32 { let _x: (String, !) = (String::new(), return async { x + x }.await); } +async fn read_exact(_from: &mut &[u8], _to: &mut [u8]) -> Option<()> { + Some(()) +} + +async fn hello_world() { + let data = [0u8; 1]; + let mut reader = &data[..]; + + let mut marker = [0u8; 1]; + read_exact(&mut reader, &mut marker).await.unwrap(); +} + fn run_fut(fut: impl Future) -> T { use std::sync::Arc; use std::task::{Context, Poll, Wake, Waker}; @@ -74,4 +86,5 @@ fn main() { assert_eq!(run_fut(build_aggregate(1, 2, 3, 4)), 10); assert_eq!(run_fut(includes_never(false, 4)), 16); assert_eq!(run_fut(partial_init(4)), 8); + run_fut(hello_world()); } diff --git a/tests/run-pass/issue-miri-1925.rs b/tests/run-pass/issue-miri-1925.rs new file mode 100644 index 0000000000000..262889f56eaee --- /dev/null +++ b/tests/run-pass/issue-miri-1925.rs @@ -0,0 +1,33 @@ +// compile-flags: -Zmiri-symbolic-alignment-check + +use std::mem::size_of; + +fn main() { + let mut a = Params::new(); + a.key_block = [0; BLOCKBYTES]; +} + +#[repr(C)] +#[derive(Clone)] +#[allow(unused)] +pub struct Params { + hash_length: u8, + key_length: u8, + key_block: [u8; BLOCKBYTES], + max_leaf_length: u32, +} + +pub const OUTBYTES: usize = 8 * size_of::(); +pub const KEYBYTES: usize = 8 * size_of::(); +pub const BLOCKBYTES: usize = 16 * size_of::(); + +impl Params { + pub fn new() -> Self { + Self { + hash_length: OUTBYTES as u8, + key_length: 0, + key_block: [0; BLOCKBYTES], + max_leaf_length: 0, + } + } +} From 70dd979a44c5a2c79400285821f7ac0a06eaee55 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 30 Nov 2021 11:44:19 -0500 Subject: [PATCH 2845/3747] rustup --- rust-version | 2 +- src/shims/intrinsics.rs | 31 ------------------------------- 2 files changed, 1 insertion(+), 32 deletions(-) diff --git a/rust-version b/rust-version index cc01c7ccb4a88..6de6fe762036c 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -58f9efd36de5669ab731ec7ebf565999ff17b159 +1c0287830e0fb3c4007afea2819ba03766da6e9c diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index f80062668f3eb..39ed5ada0aa99 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -550,37 +550,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "atomic_umax_relaxed" => this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOp::Relaxed)?, - // Query type information - "assert_zero_valid" | "assert_uninit_valid" => { - let &[] = check_arg_count(args)?; - let ty = instance.substs.type_at(0); - let layout = this.layout_of(ty)?; - // Abort here because the caller might not be panic safe. - if layout.abi.is_uninhabited() { - // Use this message even for the other intrinsics, as that's what codegen does - throw_machine_stop!(TerminationInfo::Abort(format!( - "aborted execution: attempted to instantiate uninhabited type `{}`", - ty - ))) - } - if intrinsic_name == "assert_zero_valid" - && !layout.might_permit_raw_init(this, /*zero:*/ true) - { - throw_machine_stop!(TerminationInfo::Abort(format!( - "aborted execution: attempted to zero-initialize type `{}`, which is invalid", - ty - ))) - } - if intrinsic_name == "assert_uninit_valid" - && !layout.might_permit_raw_init(this, /*zero:*/ false) - { - throw_machine_stop!(TerminationInfo::Abort(format!( - "aborted execution: attempted to leave type `{}` uninitialized, which is invalid", - ty - ))) - } - } - // Other "exact_div" => { let &[ref num, ref denom] = check_arg_count(args)?; From b0a463334c866ed479609adce1ee30911bf30cea Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Fri, 3 Dec 2021 15:57:37 -0500 Subject: [PATCH 2846/3747] intptrcast: Never allocate two objects directly adjecent When two objects directly follow each other in memory, what is the provenance of an integer cast to a pointer that points directly between them? For a zero-size region, it could point into the end of the first object, or the start of the second. We can avoid answering this difficult question by simply never allocating two objects directly beside each other. This fixes some of the false positives from #1866. --- src/intptrcast.rs | 9 +++++---- tests/run-pass/adjacent-allocs.rs | 21 +++++++++++++++++++++ 2 files changed, 26 insertions(+), 4 deletions(-) create mode 100644 tests/run-pass/adjacent-allocs.rs diff --git a/src/intptrcast.rs b/src/intptrcast.rs index 665a13418401d..91fd26ed75b38 100644 --- a/src/intptrcast.rs +++ b/src/intptrcast.rs @@ -1,5 +1,4 @@ use std::cell::RefCell; -use std::cmp::max; use std::collections::hash_map::Entry; use log::trace; @@ -107,9 +106,11 @@ impl<'mir, 'tcx> GlobalState { slack, ); - // Remember next base address. If this allocation is zero-sized, leave a gap - // of at least 1 to avoid two allocations having the same base address. - global_state.next_base_addr = base_addr.checked_add(max(size.bytes(), 1)).unwrap(); + // Remember next base address. Leave a gap of at least 1 to avoid two zero-sized allocations + // having the same base address, and to avoid ambiguous provenance for the address between two + // allocations. + let bytes = size.bytes().checked_add(1).unwrap(); + global_state.next_base_addr = base_addr.checked_add(bytes).unwrap(); // Given that `next_base_addr` increases in each allocation, pushing the // corresponding tuple keeps `int_to_ptr_map` sorted global_state.int_to_ptr_map.push((base_addr, alloc_id)); diff --git a/tests/run-pass/adjacent-allocs.rs b/tests/run-pass/adjacent-allocs.rs new file mode 100644 index 0000000000000..812dfcc66c29c --- /dev/null +++ b/tests/run-pass/adjacent-allocs.rs @@ -0,0 +1,21 @@ +fn main() { + // The slack between allocations is random. + // Loop a few times to hit the zero-slack case. + for _ in 0..1024 { + let n = 0u64; + let ptr: *const u64 = &n; + + // Allocate a new stack variable whose lifetime quickly ends. + // If there's a chance that &m == ptr.add(1), then an int-to-ptr cast of + // that value will have ambiguous provenance between n and m. + // See https://github.com/rust-lang/miri/issues/1866#issuecomment-985770125 + { + let m = 0u64; + let _ = &m as *const u64; + } + + let iptr = ptr as usize; + let zst = (iptr + 8) as *const (); + unsafe { *zst } + } +} From d537ed401d323182e178aa496871604c50f4600a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 5 Dec 2021 11:02:20 -0500 Subject: [PATCH 2847/3747] rustup --- rust-version | 2 +- tests/run-pass/concurrency/tls_lib_drop.rs | 1 - tests/run-pass/concurrency/tls_lib_drop_single_thread.rs | 1 - 3 files changed, 1 insertion(+), 3 deletions(-) diff --git a/rust-version b/rust-version index 6de6fe762036c..1de7877db7fbb 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -1c0287830e0fb3c4007afea2819ba03766da6e9c +1597728ef5820d3ffcb9d3f0c890ef7802398751 diff --git a/tests/run-pass/concurrency/tls_lib_drop.rs b/tests/run-pass/concurrency/tls_lib_drop.rs index 00a12599ce99a..3220aa43148d4 100644 --- a/tests/run-pass/concurrency/tls_lib_drop.rs +++ b/tests/run-pass/concurrency/tls_lib_drop.rs @@ -1,5 +1,4 @@ // ignore-windows: Concurrency on Windows is not supported yet. -#![feature(thread_local_const_init)] use std::cell::RefCell; use std::thread; diff --git a/tests/run-pass/concurrency/tls_lib_drop_single_thread.rs b/tests/run-pass/concurrency/tls_lib_drop_single_thread.rs index 16ca8a0d2eff2..c8be1273bd14f 100644 --- a/tests/run-pass/concurrency/tls_lib_drop_single_thread.rs +++ b/tests/run-pass/concurrency/tls_lib_drop_single_thread.rs @@ -1,6 +1,5 @@ // compile-flags: -Zmiri-tag-raw-pointers //! Check that destructors of the thread locals are executed on all OSes. -#![feature(thread_local_const_init)] use std::cell::RefCell; From eadeedde425e5a8027cf745da233bf3de58419a9 Mon Sep 17 00:00:00 2001 From: 5225225 <5225225@mailbox.org> Date: Sun, 5 Dec 2021 13:54:25 +0000 Subject: [PATCH 2848/3747] Handle uninit data in pthread_condattr_destroy --- src/shims/posix/sync.rs | 12 ++++++++++- .../libc_pthread_condattr_double_destroy.rs | 19 ++++++++++++++++++ .../concurrency/pthread_condattr_init.rs | 20 +++++++++++++++++++ 3 files changed, 50 insertions(+), 1 deletion(-) create mode 100644 tests/compile-fail/sync/libc_pthread_condattr_double_destroy.rs create mode 100644 tests/run-pass/concurrency/pthread_condattr_init.rs diff --git a/src/shims/posix/sync.rs b/src/shims/posix/sync.rs index 606f58a207e56..abf52a94e7e7d 100644 --- a/src/shims/posix/sync.rs +++ b/src/shims/posix/sync.rs @@ -189,6 +189,14 @@ fn condattr_set_clock_id<'mir, 'tcx: 'mir>( ecx.write_scalar_at_offset(attr_op, 0, clock_id, ecx.machine.layouts.i32) } +fn condattr_deinit_clock_id<'mir, 'tcx: 'mir>( + ecx: &mut MiriEvalContext<'mir, 'tcx>, + attr_op: &OpTy<'tcx, Tag>, +) -> InterpResult<'tcx, ()> { + let layout = layout_of_maybe_uninit(ecx.tcx, ecx.machine.layouts.i32.ty); + ecx.write_scalar_at_offset(attr_op, 0, ScalarMaybeUninit::Uninit, layout) +} + // pthread_cond_t // Our chosen memory layout for the emulated conditional variable (does not have @@ -652,7 +660,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn pthread_condattr_destroy(&mut self, attr_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - condattr_set_clock_id(this, attr_op, ScalarMaybeUninit::Uninit)?; + condattr_get_clock_id(this, attr_op)?.check_init()?; + + condattr_deinit_clock_id(this, attr_op)?; Ok(0) } diff --git a/tests/compile-fail/sync/libc_pthread_condattr_double_destroy.rs b/tests/compile-fail/sync/libc_pthread_condattr_double_destroy.rs new file mode 100644 index 0000000000000..44af51a3e8711 --- /dev/null +++ b/tests/compile-fail/sync/libc_pthread_condattr_double_destroy.rs @@ -0,0 +1,19 @@ +// ignore-windows: No libc on Windows +#![feature(rustc_private)] + +/// Test that destroying a pthread_condattr twice fails, even without a check for number validity +extern crate libc; + +fn main() { + unsafe { + use core::mem::MaybeUninit; + let mut attr = MaybeUninit::::uninit(); + + libc::pthread_condattr_init(attr.as_mut_ptr()); + + libc::pthread_condattr_destroy(attr.as_mut_ptr()); + + libc::pthread_condattr_destroy(attr.as_mut_ptr()); + //~^ Undefined Behavior: using uninitialized data, but this operation requires initialized memory + } +} diff --git a/tests/run-pass/concurrency/pthread_condattr_init.rs b/tests/run-pass/concurrency/pthread_condattr_init.rs new file mode 100644 index 0000000000000..285c6014e2d93 --- /dev/null +++ b/tests/run-pass/concurrency/pthread_condattr_init.rs @@ -0,0 +1,20 @@ +// ignore-windows: No libc on Windows +// compile-flags: -Zmiri-check-number-validity + +#![feature(rustc_private)] + +/// Test that pthread_condattr_destroy doesn't trigger a number validity error. +extern crate libc; + +fn main() { + unsafe { + use core::mem::MaybeUninit; + let mut attr = MaybeUninit::::uninit(); + + let r = libc::pthread_condattr_init(attr.as_mut_ptr()); + assert_eq!(r, 0); + + let r = libc::pthread_condattr_destroy(attr.as_mut_ptr()); + assert_eq!(r, 0); + } +} From 6a98c64c8b684ad12ae1a11fc7ad55a176b45bfe Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 5 Dec 2021 20:33:20 -0500 Subject: [PATCH 2849/3747] final tweaks --- src/intptrcast.rs | 6 +++--- tests/run-pass/adjacent-allocs.rs | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/intptrcast.rs b/src/intptrcast.rs index 91fd26ed75b38..6f4169e950a94 100644 --- a/src/intptrcast.rs +++ b/src/intptrcast.rs @@ -108,9 +108,9 @@ impl<'mir, 'tcx> GlobalState { // Remember next base address. Leave a gap of at least 1 to avoid two zero-sized allocations // having the same base address, and to avoid ambiguous provenance for the address between two - // allocations. - let bytes = size.bytes().checked_add(1).unwrap(); - global_state.next_base_addr = base_addr.checked_add(bytes).unwrap(); + // allocations (also see https://github.com/rust-lang/unsafe-code-guidelines/issues/313). + let size_plus_1 = size.bytes().checked_add(1).unwrap(); + global_state.next_base_addr = base_addr.checked_add(size_plus_1).unwrap(); // Given that `next_base_addr` increases in each allocation, pushing the // corresponding tuple keeps `int_to_ptr_map` sorted global_state.int_to_ptr_map.push((base_addr, alloc_id)); diff --git a/tests/run-pass/adjacent-allocs.rs b/tests/run-pass/adjacent-allocs.rs index 812dfcc66c29c..509965fe4fa97 100644 --- a/tests/run-pass/adjacent-allocs.rs +++ b/tests/run-pass/adjacent-allocs.rs @@ -16,6 +16,7 @@ fn main() { let iptr = ptr as usize; let zst = (iptr + 8) as *const (); + // This is a ZST ptr just at the end of `n`, so it should be valid to deref. unsafe { *zst } } } From ae120563cc4ee0ac2f0b687c6ccc1d2d68c6f892 Mon Sep 17 00:00:00 2001 From: 5225225 <5225225@mailbox.org> Date: Mon, 6 Dec 2021 19:26:13 +0000 Subject: [PATCH 2850/3747] Destroying any uninit posix_ object is UB --- src/shims/posix/sync.rs | 33 +++++++++++++++++++++++---------- 1 file changed, 23 insertions(+), 10 deletions(-) diff --git a/src/shims/posix/sync.rs b/src/shims/posix/sync.rs index abf52a94e7e7d..29bca11f831e3 100644 --- a/src/shims/posix/sync.rs +++ b/src/shims/posix/sync.rs @@ -186,15 +186,12 @@ fn condattr_set_clock_id<'mir, 'tcx: 'mir>( attr_op: &OpTy<'tcx, Tag>, clock_id: impl Into>, ) -> InterpResult<'tcx, ()> { - ecx.write_scalar_at_offset(attr_op, 0, clock_id, ecx.machine.layouts.i32) -} - -fn condattr_deinit_clock_id<'mir, 'tcx: 'mir>( - ecx: &mut MiriEvalContext<'mir, 'tcx>, - attr_op: &OpTy<'tcx, Tag>, -) -> InterpResult<'tcx, ()> { - let layout = layout_of_maybe_uninit(ecx.tcx, ecx.machine.layouts.i32.ty); - ecx.write_scalar_at_offset(attr_op, 0, ScalarMaybeUninit::Uninit, layout) + ecx.write_scalar_at_offset( + attr_op, + 0, + clock_id, + layout_of_maybe_uninit(ecx.tcx, ecx.machine.layouts.i32.ty), + ) } // pthread_cond_t @@ -367,6 +364,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn pthread_mutexattr_destroy(&mut self, attr_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); + // Destroying an uninit pthread_mutexattr is UB, so check to make sure it's not uninit. + mutexattr_get_kind(this, attr_op)?.check_init()?; + mutexattr_set_kind(this, attr_op, ScalarMaybeUninit::Uninit)?; Ok(0) @@ -505,6 +505,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx throw_ub_format!("destroyed a locked mutex"); } + // Destroying an uninit pthread_mutex is UB, so check to make sure it's not uninit. + mutex_get_kind(this, mutex_op)?.check_init()?; + mutex_get_id(this, mutex_op)?.check_init()?; + mutex_set_kind(this, mutex_op, ScalarMaybeUninit::Uninit)?; mutex_set_id(this, mutex_op, ScalarMaybeUninit::Uninit)?; // FIXME: delete interpreter state associated with this mutex. @@ -606,6 +610,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx throw_ub_format!("destroyed a locked rwlock"); } + // Destroying an uninit pthread_rwlock is UB, so check to make sure it's not uninit. + rwlock_get_id(this, rwlock_op)?.check_init()?; + rwlock_set_id(this, rwlock_op, ScalarMaybeUninit::Uninit)?; // FIXME: delete interpreter state associated with this rwlock. @@ -660,9 +667,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn pthread_condattr_destroy(&mut self, attr_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); + // Destroying an uninit pthread_condattr is UB, so check to make sure it's not uninit. condattr_get_clock_id(this, attr_op)?.check_init()?; - condattr_deinit_clock_id(this, attr_op)?; + condattr_set_clock_id(this, attr_op, ScalarMaybeUninit::Uninit)?; Ok(0) } @@ -799,6 +807,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if this.condvar_is_awaited(id) { throw_ub_format!("destroying an awaited conditional variable"); } + + // Destroying an uninit pthread_cond is UB, so check to make sure it's not uninit. + cond_get_id(this, cond_op)?.check_init()?; + cond_get_clock_id(this, cond_op)?.check_init()?; + cond_set_id(this, cond_op, ScalarMaybeUninit::Uninit)?; cond_set_clock_id(this, cond_op, ScalarMaybeUninit::Uninit)?; // FIXME: delete interpreter state associated with this condvar. From f0d915703ca8130367d6089cb79369f67888c9ad Mon Sep 17 00:00:00 2001 From: 5225225 <5225225@mailbox.org> Date: Mon, 6 Dec 2021 21:15:02 +0000 Subject: [PATCH 2851/3747] Add tests for double destroying various pthread items --- .../sync/libc_pthread_cond_double_destroy.rs | 22 ++++++++++++++++++ .../sync/libc_pthread_mutex_double_destroy.rs | 23 +++++++++++++++++++ .../libc_pthread_mutexattr_double_destroy.rs | 19 +++++++++++++++ .../libc_pthread_rwlock_double_destroy.rs | 16 +++++++++++++ 4 files changed, 80 insertions(+) create mode 100644 tests/compile-fail/sync/libc_pthread_cond_double_destroy.rs create mode 100644 tests/compile-fail/sync/libc_pthread_mutex_double_destroy.rs create mode 100644 tests/compile-fail/sync/libc_pthread_mutexattr_double_destroy.rs create mode 100644 tests/compile-fail/sync/libc_pthread_rwlock_double_destroy.rs diff --git a/tests/compile-fail/sync/libc_pthread_cond_double_destroy.rs b/tests/compile-fail/sync/libc_pthread_cond_double_destroy.rs new file mode 100644 index 0000000000000..c376618357d27 --- /dev/null +++ b/tests/compile-fail/sync/libc_pthread_cond_double_destroy.rs @@ -0,0 +1,22 @@ +// ignore-windows: No libc on Windows +#![feature(rustc_private)] + +/// Test that destroying a pthread_cond twice fails, even without a check for number validity +extern crate libc; + +fn main() { + unsafe { + use core::mem::MaybeUninit; + let mut attr = MaybeUninit::::uninit(); + libc::pthread_condattr_init(attr.as_mut_ptr()); + + let mut cond = MaybeUninit::::uninit(); + + libc::pthread_cond_init(cond.as_mut_ptr(), attr.as_ptr()); + + libc::pthread_cond_destroy(cond.as_mut_ptr()); + + libc::pthread_cond_destroy(cond.as_mut_ptr()); + //~^ Undefined Behavior: using uninitialized data, but this operation requires initialized memory + } +} diff --git a/tests/compile-fail/sync/libc_pthread_mutex_double_destroy.rs b/tests/compile-fail/sync/libc_pthread_mutex_double_destroy.rs new file mode 100644 index 0000000000000..08abc0ca12c5b --- /dev/null +++ b/tests/compile-fail/sync/libc_pthread_mutex_double_destroy.rs @@ -0,0 +1,23 @@ +// ignore-windows: No libc on Windows +#![feature(rustc_private)] + +/// Test that destroying a pthread_mutex twice fails, even without a check for number validity +extern crate libc; + +fn main() { + unsafe { + use core::mem::MaybeUninit; + + let mut attr = MaybeUninit::::uninit(); + libc::pthread_mutexattr_init(attr.as_mut_ptr()); + + let mut mutex = MaybeUninit::::uninit(); + + libc::pthread_mutex_init(mutex.as_mut_ptr(), attr.as_ptr()); + + libc::pthread_mutex_destroy(mutex.as_mut_ptr()); + + libc::pthread_mutex_destroy(mutex.as_mut_ptr()); + //~^ Undefined Behavior: using uninitialized data, but this operation requires initialized memory + } +} diff --git a/tests/compile-fail/sync/libc_pthread_mutexattr_double_destroy.rs b/tests/compile-fail/sync/libc_pthread_mutexattr_double_destroy.rs new file mode 100644 index 0000000000000..69ca3ad512fa2 --- /dev/null +++ b/tests/compile-fail/sync/libc_pthread_mutexattr_double_destroy.rs @@ -0,0 +1,19 @@ +// ignore-windows: No libc on Windows +#![feature(rustc_private)] + +/// Test that destroying a pthread_mutexattr twice fails, even without a check for number validity +extern crate libc; + +fn main() { + unsafe { + use core::mem::MaybeUninit; + let mut attr = MaybeUninit::::uninit(); + + libc::pthread_mutexattr_init(attr.as_mut_ptr()); + + libc::pthread_mutexattr_destroy(attr.as_mut_ptr()); + + libc::pthread_mutexattr_destroy(attr.as_mut_ptr()); + //~^ Undefined Behavior: using uninitialized data, but this operation requires initialized memory + } +} diff --git a/tests/compile-fail/sync/libc_pthread_rwlock_double_destroy.rs b/tests/compile-fail/sync/libc_pthread_rwlock_double_destroy.rs new file mode 100644 index 0000000000000..d20c78155fd2c --- /dev/null +++ b/tests/compile-fail/sync/libc_pthread_rwlock_double_destroy.rs @@ -0,0 +1,16 @@ +// ignore-windows: No libc on Windows +#![feature(rustc_private)] + +/// Test that destroying a pthread_rwlock twice fails, even without a check for number validity +extern crate libc; + +fn main() { + unsafe { + let mut lock = libc::PTHREAD_RWLOCK_INITIALIZER; + + libc::pthread_rwlock_destroy(&mut lock); + + libc::pthread_rwlock_destroy(&mut lock); + //~^ Undefined Behavior: using uninitialized data, but this operation requires initialized memory + } +} From a4b2fc0c5a3acd6ab737aa1f4c29df8dbd621a80 Mon Sep 17 00:00:00 2001 From: 5225225 <5225225@mailbox.org> Date: Mon, 6 Dec 2021 21:50:14 +0000 Subject: [PATCH 2852/3747] Adjust pthread tests --- .../run-pass/concurrency/libc_pthread_cond.rs | 35 ++++++++++--------- .../concurrency/pthread_condattr_init.rs | 20 ----------- tests/run-pass/concurrency/sync.rs | 7 +++- 3 files changed, 24 insertions(+), 38 deletions(-) delete mode 100644 tests/run-pass/concurrency/pthread_condattr_init.rs diff --git a/tests/run-pass/concurrency/libc_pthread_cond.rs b/tests/run-pass/concurrency/libc_pthread_cond.rs index a545c922db1ab..0e09ec9126a54 100644 --- a/tests/run-pass/concurrency/libc_pthread_cond.rs +++ b/tests/run-pass/concurrency/libc_pthread_cond.rs @@ -1,6 +1,6 @@ // ignore-windows: No libc on Windows // ignore-macos: pthread_condattr_setclock is not supported on MacOS. -// compile-flags: -Zmiri-disable-isolation +// compile-flags: -Zmiri-disable-isolation -Zmiri-check-number-validity #![feature(rustc_private)] @@ -8,23 +8,24 @@ /// monotonic and system clocks. extern crate libc; -use std::mem; +use std::mem::MaybeUninit; use std::time::Instant; fn test_timed_wait_timeout(clock_id: i32) { unsafe { - let mut attr: libc::pthread_condattr_t = mem::zeroed(); - assert_eq!(libc::pthread_condattr_init(&mut attr as *mut _), 0); - assert_eq!(libc::pthread_condattr_setclock(&mut attr as *mut _, clock_id), 0); + let mut attr: MaybeUninit = MaybeUninit::uninit(); + assert_eq!(libc::pthread_condattr_init(attr.as_mut_ptr()), 0); + assert_eq!(libc::pthread_condattr_setclock(attr.as_mut_ptr(), clock_id), 0); - let mut cond: libc::pthread_cond_t = mem::zeroed(); - assert_eq!(libc::pthread_cond_init(&mut cond as *mut _, &attr as *const _), 0); - assert_eq!(libc::pthread_condattr_destroy(&mut attr as *mut _), 0); + let mut cond: MaybeUninit = MaybeUninit::uninit(); + assert_eq!(libc::pthread_cond_init(cond.as_mut_ptr(), attr.as_ptr()), 0); + assert_eq!(libc::pthread_condattr_destroy(attr.as_mut_ptr()), 0); - let mut mutex: libc::pthread_mutex_t = mem::zeroed(); + let mut mutex: libc::pthread_mutex_t = libc::PTHREAD_MUTEX_INITIALIZER; - let mut now: libc::timespec = mem::zeroed(); - assert_eq!(libc::clock_gettime(clock_id, &mut now), 0); + let mut now_mu: MaybeUninit = MaybeUninit::uninit(); + assert_eq!(libc::clock_gettime(clock_id, now_mu.as_mut_ptr()), 0); + let now = now_mu.assume_init(); // Waiting for a second... mostly because waiting less requires mich more tricky arithmetic. // FIXME: wait less. let timeout = libc::timespec { tv_sec: now.tv_sec + 1, tv_nsec: now.tv_nsec }; @@ -32,7 +33,7 @@ fn test_timed_wait_timeout(clock_id: i32) { assert_eq!(libc::pthread_mutex_lock(&mut mutex as *mut _), 0); let current_time = Instant::now(); assert_eq!( - libc::pthread_cond_timedwait(&mut cond as *mut _, &mut mutex as *mut _, &timeout), + libc::pthread_cond_timedwait(cond.as_mut_ptr(), &mut mutex as *mut _, &timeout), libc::ETIMEDOUT ); let elapsed_time = current_time.elapsed().as_millis(); @@ -40,7 +41,7 @@ fn test_timed_wait_timeout(clock_id: i32) { // Test calling `pthread_cond_timedwait` again with an already elapsed timeout. assert_eq!( - libc::pthread_cond_timedwait(&mut cond as *mut _, &mut mutex as *mut _, &timeout), + libc::pthread_cond_timedwait(cond.as_mut_ptr(), &mut mutex as *mut _, &timeout), libc::ETIMEDOUT ); @@ -49,7 +50,7 @@ fn test_timed_wait_timeout(clock_id: i32) { let invalid_timeout_1 = libc::timespec { tv_sec: now.tv_sec + 1, tv_nsec: 1_000_000_000 }; assert_eq!( libc::pthread_cond_timedwait( - &mut cond as *mut _, + cond.as_mut_ptr(), &mut mutex as *mut _, &invalid_timeout_1 ), @@ -58,7 +59,7 @@ fn test_timed_wait_timeout(clock_id: i32) { let invalid_timeout_2 = libc::timespec { tv_sec: now.tv_sec + 1, tv_nsec: -1 }; assert_eq!( libc::pthread_cond_timedwait( - &mut cond as *mut _, + cond.as_mut_ptr(), &mut mutex as *mut _, &invalid_timeout_2 ), @@ -68,7 +69,7 @@ fn test_timed_wait_timeout(clock_id: i32) { let invalid_timeout_3 = libc::timespec { tv_sec: -1, tv_nsec: 0 }; assert_eq!( libc::pthread_cond_timedwait( - &mut cond as *mut _, + cond.as_mut_ptr(), &mut mutex as *mut _, &invalid_timeout_3 ), @@ -77,7 +78,7 @@ fn test_timed_wait_timeout(clock_id: i32) { assert_eq!(libc::pthread_mutex_unlock(&mut mutex as *mut _), 0); assert_eq!(libc::pthread_mutex_destroy(&mut mutex as *mut _), 0); - assert_eq!(libc::pthread_cond_destroy(&mut cond as *mut _), 0); + assert_eq!(libc::pthread_cond_destroy(cond.as_mut_ptr()), 0); } } diff --git a/tests/run-pass/concurrency/pthread_condattr_init.rs b/tests/run-pass/concurrency/pthread_condattr_init.rs deleted file mode 100644 index 285c6014e2d93..0000000000000 --- a/tests/run-pass/concurrency/pthread_condattr_init.rs +++ /dev/null @@ -1,20 +0,0 @@ -// ignore-windows: No libc on Windows -// compile-flags: -Zmiri-check-number-validity - -#![feature(rustc_private)] - -/// Test that pthread_condattr_destroy doesn't trigger a number validity error. -extern crate libc; - -fn main() { - unsafe { - use core::mem::MaybeUninit; - let mut attr = MaybeUninit::::uninit(); - - let r = libc::pthread_condattr_init(attr.as_mut_ptr()); - assert_eq!(r, 0); - - let r = libc::pthread_condattr_destroy(attr.as_mut_ptr()); - assert_eq!(r, 0); - } -} diff --git a/tests/run-pass/concurrency/sync.rs b/tests/run-pass/concurrency/sync.rs index 88187d64e604a..da6f6f25ec1cd 100644 --- a/tests/run-pass/concurrency/sync.rs +++ b/tests/run-pass/concurrency/sync.rs @@ -1,5 +1,5 @@ // ignore-windows: Concurrency on Windows is not supported yet. -// compile-flags: -Zmiri-disable-isolation +// compile-flags: -Zmiri-disable-isolation -Zmiri-check-number-validity use std::sync::mpsc::{channel, sync_channel}; use std::sync::{Arc, Barrier, Condvar, Mutex, Once, RwLock}; @@ -340,6 +340,10 @@ fn park_unpark() { assert!((200..1000).contains(&start.elapsed().as_millis())); } +fn check_condvar() { + let _ = std::sync::Condvar::new(); +} + fn main() { check_barriers(); check_conditional_variables_notify_one(); @@ -357,4 +361,5 @@ fn main() { check_rwlock_unlock_bug2(); park_timeout(); park_unpark(); + check_condvar(); } From 250d450593633dcb40b5ba515b492afbe6d01c99 Mon Sep 17 00:00:00 2001 From: 5225225 <5225225@mailbox.org> Date: Tue, 7 Dec 2021 08:26:46 +0000 Subject: [PATCH 2853/3747] Add comment explaining false positives in _destroy --- src/shims/posix/sync.rs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/shims/posix/sync.rs b/src/shims/posix/sync.rs index 29bca11f831e3..1d0483e49d515 100644 --- a/src/shims/posix/sync.rs +++ b/src/shims/posix/sync.rs @@ -367,6 +367,18 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Destroying an uninit pthread_mutexattr is UB, so check to make sure it's not uninit. mutexattr_get_kind(this, attr_op)?.check_init()?; + // This is technically not right and might lead to false positives. For example, the below + // code is *likely* sound, even assuming uninit numbers are UB, but miri with + // -Zmiri-check-number-validity complains + // + // let mut x: MaybeUninit = MaybeUninit::zeroed(); + // libc::pthread_mutexattr_init(x.as_mut_ptr()); + // libc::pthread_mutexattr_destroy(x.as_mut_ptr()); + // x.assume_init(); + // + // This can always be revisited to have some external state to catch double-destroys + // but not complain about the above code. See https://github.com/rust-lang/miri/pull/1933 + mutexattr_set_kind(this, attr_op, ScalarMaybeUninit::Uninit)?; Ok(0) @@ -509,6 +521,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx mutex_get_kind(this, mutex_op)?.check_init()?; mutex_get_id(this, mutex_op)?.check_init()?; + // This might lead to false positives, see comment in pthread_mutexattr_destroy mutex_set_kind(this, mutex_op, ScalarMaybeUninit::Uninit)?; mutex_set_id(this, mutex_op, ScalarMaybeUninit::Uninit)?; // FIXME: delete interpreter state associated with this mutex. @@ -613,6 +626,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Destroying an uninit pthread_rwlock is UB, so check to make sure it's not uninit. rwlock_get_id(this, rwlock_op)?.check_init()?; + // This might lead to false positives, see comment in pthread_mutexattr_destroy rwlock_set_id(this, rwlock_op, ScalarMaybeUninit::Uninit)?; // FIXME: delete interpreter state associated with this rwlock. @@ -670,6 +684,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Destroying an uninit pthread_condattr is UB, so check to make sure it's not uninit. condattr_get_clock_id(this, attr_op)?.check_init()?; + // This might lead to false positives, see comment in pthread_mutexattr_destroy condattr_set_clock_id(this, attr_op, ScalarMaybeUninit::Uninit)?; Ok(0) @@ -812,6 +827,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx cond_get_id(this, cond_op)?.check_init()?; cond_get_clock_id(this, cond_op)?.check_init()?; + // This might lead to false positives, see comment in pthread_mutexattr_destroy cond_set_id(this, cond_op, ScalarMaybeUninit::Uninit)?; cond_set_clock_id(this, cond_op, ScalarMaybeUninit::Uninit)?; // FIXME: delete interpreter state associated with this condvar. From fd830e7b278063c93c57028b9469875fb36718a6 Mon Sep 17 00:00:00 2001 From: 5225225 <5225225@mailbox.org> Date: Tue, 7 Dec 2021 17:25:28 +0000 Subject: [PATCH 2854/3747] Code comment changes from code review Co-authored-by: Ralf Jung --- src/shims/posix/sync.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/shims/posix/sync.rs b/src/shims/posix/sync.rs index 1d0483e49d515..ea940df1c6e89 100644 --- a/src/shims/posix/sync.rs +++ b/src/shims/posix/sync.rs @@ -367,6 +367,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Destroying an uninit pthread_mutexattr is UB, so check to make sure it's not uninit. mutexattr_get_kind(this, attr_op)?.check_init()?; + // To catch double-destroys, we de-initialize the mutexattr. // This is technically not right and might lead to false positives. For example, the below // code is *likely* sound, even assuming uninit numbers are UB, but miri with // -Zmiri-check-number-validity complains @@ -376,6 +377,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // libc::pthread_mutexattr_destroy(x.as_mut_ptr()); // x.assume_init(); // + // However, the way libstd uses the pthread APIs works in our favor here, so we can get away with this. // This can always be revisited to have some external state to catch double-destroys // but not complain about the above code. See https://github.com/rust-lang/miri/pull/1933 From 50b9b701ab7b6775a1f00be24d9298489198e14e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 8 Dec 2021 10:01:51 -0500 Subject: [PATCH 2855/3747] rustup --- rust-version | 2 +- tests/run-pass/portable-simd.rs | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/rust-version b/rust-version index 1de7877db7fbb..1f57a0197e0ec 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -1597728ef5820d3ffcb9d3f0c890ef7802398751 +4459e720bee5a741b962cfcd6f0593b32dc19009 diff --git a/tests/run-pass/portable-simd.rs b/tests/run-pass/portable-simd.rs index 5d33376618780..beb0504e0e4f4 100644 --- a/tests/run-pass/portable-simd.rs +++ b/tests/run-pass/portable-simd.rs @@ -8,7 +8,7 @@ fn simd_ops_f32() { assert_eq!(a - b, f32x4::from_array([9.0, 8.0, 7.0, 6.0])); assert_eq!(a * b, f32x4::from_array([10.0, 20.0, 30.0, 40.0])); assert_eq!(b / a, f32x4::from_array([0.1, 0.2, 0.3, 0.4])); - assert_eq!(a / 2.0, f32x4::splat(5.0)); + assert_eq!(a / f32x4::splat(2.0), f32x4::splat(5.0)); assert_eq!(a % b, f32x4::from_array([0.0, 0.0, 1.0, 2.0])); } @@ -19,10 +19,10 @@ fn simd_ops_i32() { assert_eq!(a - b, i32x4::from_array([9, 8, 7, 6])); assert_eq!(a * b, i32x4::from_array([10, 20, 30, 40])); assert_eq!(a / b, i32x4::from_array([10, 5, 3, 2])); - assert_eq!(a / 2, i32x4::splat(5)); + assert_eq!(a / i32x4::splat(2), i32x4::splat(5)); assert_eq!(a % b, i32x4::from_array([0, 0, 1, 2])); - assert_eq!(b << 2, i32x4::from_array([4, 8, 12, 16])); - assert_eq!(b >> 1, i32x4::from_array([0, 1, 1, 2])); + assert_eq!(b << i32x4::splat(2), i32x4::from_array([4, 8, 12, 16])); + assert_eq!(b >> i32x4::splat(1), i32x4::from_array([0, 1, 1, 2])); } fn main() { From 7670a5657a5deacf35687d690e352605388ef2b9 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 14 Dec 2021 18:14:17 +0100 Subject: [PATCH 2856/3747] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 1f57a0197e0ec..3f00e3abe9145 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -4459e720bee5a741b962cfcd6f0593b32dc19009 +404c8471aba60c2d837fa728e7c729a0f52d5830 From 6dcb5389cda597d9ab09d4390c574e3cdb866240 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 14 Dec 2021 18:20:03 +0100 Subject: [PATCH 2857/3747] update lockfile --- Cargo.lock | 132 +++++++++++------------ cargo-miri/Cargo.lock | 237 +++++++++++++++--------------------------- 2 files changed, 149 insertions(+), 220 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 24593d3332840..674ce8a2b1ea7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,18 +4,18 @@ version = 3 [[package]] name = "aho-corasick" -version = "0.7.15" +version = "0.7.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7404febffaa47dac81aa44dba71523c9d069b1bdc50a77db41195149e17f68e5" +checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f" dependencies = [ "memchr", ] [[package]] name = "anyhow" -version = "1.0.40" +version = "1.0.51" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28b2cd92db5cbd74e8e5028f7e27dd7aa3090e89e4f2a197cc7c8dfb69c7063b" +checksum = "8b26702f315f53b6071259e15dd9d64528213b44d61de1ec926eca7715d62203" [[package]] name = "atty" @@ -30,9 +30,9 @@ dependencies = [ [[package]] name = "bitflags" -version = "1.2.1" +version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "cfg-if" @@ -53,9 +53,9 @@ dependencies = [ [[package]] name = "compiletest_rs" -version = "0.7.0" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64698e5e2435db061a85e6320af12c30c5fd88eb84b35d2c1e03ce4f143255ca" +checksum = "29843cb8d351febf86557681d049d1e1652b81a086a190fa1173c07fd17fbf83" dependencies = [ "diff", "filetime", @@ -116,9 +116,9 @@ dependencies = [ [[package]] name = "filetime" -version = "0.2.14" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d34cfa13a63ae058bfa601fe9e313bbdb3746427c1459185464ce0fcf62e1e8" +checksum = "975ccf83d8d9d0d84682850a38c8169027be83368805971cc4f238c2b245bc98" dependencies = [ "cfg-if", "libc", @@ -137,9 +137,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9495705279e7140bf035dde1f6e750c162df8b625267cd52cc44e0b156732c8" +checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753" dependencies = [ "cfg-if", "libc", @@ -148,9 +148,9 @@ dependencies = [ [[package]] name = "hermit-abi" -version = "0.1.18" +version = "0.1.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "322f4de77956e22ed0e5032c359a0f1273f1f7f0d79bfa3b8ffbc730d7fbcc5c" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" dependencies = [ "libc", ] @@ -169,18 +169,18 @@ checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" [[package]] name = "instant" -version = "0.1.9" +version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61124eeebbd69b8190558df225adf7e4caafce0d743919e5d6b19652314ec5ec" +checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" dependencies = [ "cfg-if", ] [[package]] name = "itoa" -version = "0.4.7" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736" +checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35" [[package]] name = "lazy_static" @@ -190,15 +190,15 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.92" +version = "0.2.112" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56d855069fafbb9b344c0f962150cd2c1187975cb1c22c1522c240d8c4986714" +checksum = "1b03d17f364a3a042d5e5d46b053bbbf82c92c9430c592dd4c064dc6ee997125" [[package]] name = "lock_api" -version = "0.4.3" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a3c91c24eae6777794bb1997ad98bbb87daf92890acab859f7eaa4320333176" +checksum = "712a4d093c9976e24e7dbca41db895dabcbac38eb5f4045393d17a95bdfb1109" dependencies = [ "scopeguard", ] @@ -228,15 +228,15 @@ dependencies = [ [[package]] name = "memchr" -version = "2.3.4" +version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ee1c47aaa256ecabcaea351eae4a9b01ef39ed810004e298d2511ed284b1525" +checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" [[package]] name = "memmap2" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "397d1a6d6d0563c0f5462bbdae662cf6c784edf5e828e40c7257f85d82bf56dd" +checksum = "723e3ebdcdc5c023db1df315364573789f8857c11b631a2fdfad7c00f5c046b4" dependencies = [ "libc", ] @@ -281,9 +281,9 @@ dependencies = [ [[package]] name = "parking_lot" -version = "0.11.1" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d7744ac029df22dca6284efe4e898991d28e3085c706c972bcd7da4a27a15eb" +checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" dependencies = [ "instant", "lock_api", @@ -292,9 +292,9 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.8.3" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa7a782938e745763fe6907fc6ba86946d72f49fe7e21de074e08128a99fb018" +checksum = "d76e8e1493bcac0d2766c42737f34458f1c8c50c0d23bcb24ea953affb273216" dependencies = [ "cfg-if", "instant", @@ -315,33 +315,33 @@ dependencies = [ [[package]] name = "ppv-lite86" -version = "0.2.10" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857" +checksum = "ed0cfbc8191465bed66e1718596ee0b0b35d5ee1f41c5df2189d0fe8bde535ba" [[package]] name = "proc-macro2" -version = "1.0.26" +version = "1.0.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a152013215dca273577e18d2bf00fa862b89b24169fb78c4c95aeb07992c9cec" +checksum = "fb37d2df5df740e582f28f8560cf425f52bb267d872fe58358eadb554909f07a" dependencies = [ "unicode-xid", ] [[package]] name = "quote" -version = "1.0.9" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7" +checksum = "38bc8cc6a5f2e3655e0899c1b848643b2562f853f114bfec7be120678e3ace05" dependencies = [ "proc-macro2", ] [[package]] name = "rand" -version = "0.8.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ef9e7e66b4468674bfcb0c81af8b7fa0bb154fa9f28eb840da5c447baeb8d7e" +checksum = "2e7573632e6454cf6b99d7aac4ccca54be06da05aca2ef7423d22d27d4d4bcd8" dependencies = [ "libc", "rand_chacha", @@ -351,9 +351,9 @@ dependencies = [ [[package]] name = "rand_chacha" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e12735cf05c9e10bf21534da50a147b924d555dc7a547c42e6bb2d5b6017ae0d" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" dependencies = [ "ppv-lite86", "rand_core", @@ -361,27 +361,27 @@ dependencies = [ [[package]] name = "rand_core" -version = "0.6.2" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34cf66eb183df1c5876e2dcf6b13d57340741e8dc255b48e40a26de954d06ae7" +checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7" dependencies = [ "getrandom", ] [[package]] name = "rand_hc" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3190ef7066a446f2e7f42e239d161e905420ccab01eb967c9eb27d21b2322a73" +checksum = "d51e9f596de227fda2ea6c84607f5558e196eeaf43c986b724ba4fb8fdf497e7" dependencies = [ "rand_core", ] [[package]] name = "redox_syscall" -version = "0.2.5" +version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94341e4e44e24f6b591b59e47a8a027df12e008d73fd5672dbea9cc22f4507d9" +checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff" dependencies = [ "bitflags", ] @@ -398,9 +398,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.4.5" +version = "1.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "957056ecddbeba1b26965114e191d2e8589ce74db242b6ea25fc4062427a5c19" +checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461" dependencies = [ "aho-corasick", "memchr", @@ -409,9 +409,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.6.23" +version = "0.6.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24d5f089152e60f62d28b835fbff2cd2e8dc0baf1ac13343bef92ab7eed84548" +checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" [[package]] name = "remove_dir_all" @@ -457,15 +457,15 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.4" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb5d2a036dc6d2d8fd16fde3498b04306e29bd193bf306a57427019b823d5acd" +checksum = "f2cc38e8fa666e2de3c4aba7edeb5ffc5246c1c2ed0e3d17e560aeeba736b23f" [[package]] name = "ryu" -version = "1.0.5" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" +checksum = "73b4b750c782965c211b42f022f59af1fbceabdd026623714f104152f1ec149f" [[package]] name = "scopeguard" @@ -481,18 +481,18 @@ checksum = "568a8e6258aa33c13358f81fd834adb854c6f7c9468520910a9b1e8fac068012" [[package]] name = "serde" -version = "1.0.125" +version = "1.0.131" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "558dc50e1a5a5fa7112ca2ce4effcb321b0300c0d4ccf0776a9f60cd89031171" +checksum = "b4ad69dfbd3e45369132cc64e6748c2d65cdfb001a2b1c232d128b4ad60561c1" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.125" +version = "1.0.131" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b093b7a2bb58203b5da3056c05b4ec1fed827dcfdb37347a8841695263b3d06d" +checksum = "b710a83c4e0dff6a3d511946b95274ad9ca9e5d3ae497b63fda866ac955358d2" dependencies = [ "proc-macro2", "quote", @@ -501,9 +501,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.64" +version = "1.0.73" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "799e97dc9fdae36a5c8b8f2cae9ce2ee9fdce2058c57a93e6099d919fd982f79" +checksum = "bcbd0344bc6533bc7ec56df11d42fb70f1b912351c0825ccb7211b59d8af7cf5" dependencies = [ "itoa", "ryu", @@ -524,9 +524,9 @@ checksum = "1ecab6c735a6bb4139c0caafd0cc3635748bbb3acf4550e8138122099251f309" [[package]] name = "syn" -version = "1.0.68" +version = "1.0.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ce15dd3ed8aa2f8eeac4716d6ef5ab58b6b9256db41d7e1a0224c2788e8fd87" +checksum = "8daf5dd0bb60cbd4137b1b587d2fc0ae729bc07cf01cd70b36a1ed5ade3b9d59" dependencies = [ "proc-macro2", "quote", @@ -582,15 +582,15 @@ dependencies = [ [[package]] name = "unicode-width" -version = "0.1.8" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3" +checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973" [[package]] name = "unicode-xid" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" +checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" [[package]] name = "wasi" diff --git a/cargo-miri/Cargo.lock b/cargo-miri/Cargo.lock index cf536ecbb20f8..c6a7f8b9c13f4 100644 --- a/cargo-miri/Cargo.lock +++ b/cargo-miri/Cargo.lock @@ -4,21 +4,9 @@ version = 3 [[package]] name = "anyhow" -version = "1.0.40" +version = "1.0.51" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28b2cd92db5cbd74e8e5028f7e27dd7aa3090e89e4f2a197cc7c8dfb69c7063b" - -[[package]] -name = "arrayref" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544" - -[[package]] -name = "arrayvec" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" +checksum = "8b26702f315f53b6071259e15dd9d64528213b44d61de1ec926eca7715d62203" [[package]] name = "autocfg" @@ -26,28 +14,11 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" -[[package]] -name = "base64" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" - [[package]] name = "bitflags" -version = "1.2.1" +version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" - -[[package]] -name = "blake2b_simd" -version = "0.5.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afa748e348ad3be8263be728124b24a24f268266f6f5d58af9d75f6a40b5c587" -dependencies = [ - "arrayref", - "arrayvec", - "constant_time_eq", -] +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "cargo-miri" @@ -63,9 +34,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.0.67" +version = "1.0.72" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3c69b077ad434294d3ce9f1f6143a2a4b89a8a2d54ef813d85003a4fd1137fd" +checksum = "22a9137b95ea06864e018375b72adfb7db6e6f68cfc8df5a04d00288050485ee" dependencies = [ "jobserver", ] @@ -89,37 +60,20 @@ dependencies = [ "winapi", ] -[[package]] -name = "constant_time_eq" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" - -[[package]] -name = "crossbeam-utils" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7e9d99fa91428effe99c5c6d4634cdeba32b8cf784fc428a2a687f61a952c49" -dependencies = [ - "autocfg", - "cfg-if", - "lazy_static", -] - [[package]] name = "directories" -version = "3.0.1" +version = "3.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8fed639d60b58d0f53498ab13d26f621fd77569cc6edb031f4cc36a2ad9da0f" +checksum = "e69600ff1703123957937708eb27f7a564e48885c537782722ed0ba3189ce1d7" dependencies = [ "dirs-sys", ] [[package]] name = "dirs-sys" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e93d7f5705de3e49895a2b5e0b8855a1c27f080192ae9c32a6432d50741a57a" +checksum = "03d86534ed367a67548dc68113a0f5db55432fdfbb6e6f9d77704397d95d5780" dependencies = [ "libc", "redox_users", @@ -128,18 +82,18 @@ dependencies = [ [[package]] name = "enum-iterator" -version = "0.6.0" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c79a6321a1197d7730510c7e3f6cb80432dfefecb32426de8cea0aa19b4bb8d7" +checksum = "4eeac5c5edb79e4e39fe8439ef35207780a11f69c52cbe424ce3dfad4cb78de6" dependencies = [ "enum-iterator-derive", ] [[package]] name = "enum-iterator-derive" -version = "0.6.0" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e94aa31f7c0dc764f57896dc615ddd76fc13b0d5dca7eb6cc5e018a5a09ec06" +checksum = "c134c37760b27a871ba422106eedbb8247da973a09e82558bf26d619c882b159" dependencies = [ "proc-macro2", "quote", @@ -158,20 +112,20 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.1.16" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" +checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753" dependencies = [ "cfg-if", "libc", - "wasi 0.9.0+wasi-snapshot-preview1", + "wasi", ] [[package]] name = "getset" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24b328c01a4d71d2d8173daa93562a73ab0fe85616876f02500f53d82948c504" +checksum = "e45727250e75cc04ff2846a66397da8ef2b3db8e40e0cef4df67950a07621eb9" dependencies = [ "proc-macro-error", "proc-macro2", @@ -181,9 +135,9 @@ dependencies = [ [[package]] name = "git2" -version = "0.13.17" +version = "0.13.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d250f5f82326884bd39c2853577e70a121775db76818ffa452ed1e80de12986" +checksum = "f29229cc1b24c0e6062f6e742aa3e256492a5323365e5ed3413599f8a5eff7d6" dependencies = [ "bitflags", "libc", @@ -194,9 +148,9 @@ dependencies = [ [[package]] name = "idna" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89829a5d69c23d348314a7ac337fe39173b61149a9864deabd260983aed48c21" +checksum = "418a0a6fab821475f634efe3ccc45c013f742efe03d853e8d3355d5cb850ecf8" dependencies = [ "matches", "unicode-bidi", @@ -205,36 +159,30 @@ dependencies = [ [[package]] name = "itoa" -version = "0.4.7" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736" +checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35" [[package]] name = "jobserver" -version = "0.1.21" +version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c71313ebb9439f74b00d9d2dcec36440beaf57a6aa0623068441dd7cd81a7f2" +checksum = "af25a77299a7f711a01975c35a6a424eb6862092cc2d6c72c4ed6cbc56dfc1fa" dependencies = [ "libc", ] -[[package]] -name = "lazy_static" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" - [[package]] name = "libc" -version = "0.2.92" +version = "0.2.112" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56d855069fafbb9b344c0f962150cd2c1187975cb1c22c1522c240d8c4986714" +checksum = "1b03d17f364a3a042d5e5d46b053bbbf82c92c9430c592dd4c064dc6ee997125" [[package]] name = "libgit2-sys" -version = "0.12.18+1.1.0" +version = "0.12.26+1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3da6a42da88fc37ee1ecda212ffa254c25713532980005d5f7c0b0fbe7e6e885" +checksum = "19e1c899248e606fbfe68dcb31d8b0176ebab833b103824af31bddf4b7457494" dependencies = [ "cc", "libc", @@ -244,9 +192,9 @@ dependencies = [ [[package]] name = "libz-sys" -version = "1.1.2" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "602113192b08db8f38796c4e85c39e960c145965140e918018bcde1952429655" +checksum = "de5435b8549c16d423ed0c03dbaafe57cf6c3344744f1242520d59c9d8ecec66" dependencies = [ "cc", "libc", @@ -265,9 +213,9 @@ dependencies = [ [[package]] name = "matches" -version = "0.1.8" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08" +checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f" [[package]] name = "num-integer" @@ -305,9 +253,9 @@ dependencies = [ [[package]] name = "pkg-config" -version = "0.3.19" +version = "0.3.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3831453b3449ceb48b6d9c7ad7c96d5ea673e9b470a1dc578c2ce6521230884c" +checksum = "58893f751c9b0412871a09abd62ecd2a00298c6c83befa223ef98c52aef40cbe" [[package]] name = "proc-macro-error" @@ -335,49 +283,39 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.26" +version = "1.0.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a152013215dca273577e18d2bf00fa862b89b24169fb78c4c95aeb07992c9cec" +checksum = "fb37d2df5df740e582f28f8560cf425f52bb267d872fe58358eadb554909f07a" dependencies = [ "unicode-xid", ] [[package]] name = "quote" -version = "1.0.9" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7" +checksum = "38bc8cc6a5f2e3655e0899c1b848643b2562f853f114bfec7be120678e3ace05" dependencies = [ "proc-macro2", ] [[package]] name = "redox_syscall" -version = "0.1.57" +version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce" +checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff" +dependencies = [ + "bitflags", +] [[package]] name = "redox_users" -version = "0.3.5" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de0737333e7a9502c789a36d7c7fa6092a49895d4faa31ca5df163857ded2e9d" +checksum = "528532f3d801c87aec9def2add9ca802fe569e44a544afe633765267840abe64" dependencies = [ "getrandom", "redox_syscall", - "rust-argon2", -] - -[[package]] -name = "rust-argon2" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b18820d944b33caa75a71378964ac46f58517c92b6ae5f762636247c09e78fb" -dependencies = [ - "base64", - "blake2b_simd", - "constant_time_eq", - "crossbeam-utils", ] [[package]] @@ -397,15 +335,15 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.4" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb5d2a036dc6d2d8fd16fde3498b04306e29bd193bf306a57427019b823d5acd" +checksum = "f2cc38e8fa666e2de3c4aba7edeb5ffc5246c1c2ed0e3d17e560aeeba736b23f" [[package]] name = "ryu" -version = "1.0.5" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" +checksum = "73b4b750c782965c211b42f022f59af1fbceabdd026623714f104152f1ec149f" [[package]] name = "semver" @@ -427,18 +365,18 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.125" +version = "1.0.131" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "558dc50e1a5a5fa7112ca2ce4effcb321b0300c0d4ccf0776a9f60cd89031171" +checksum = "b4ad69dfbd3e45369132cc64e6748c2d65cdfb001a2b1c232d128b4ad60561c1" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.125" +version = "1.0.131" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b093b7a2bb58203b5da3056c05b4ec1fed827dcfdb37347a8841695263b3d06d" +checksum = "b710a83c4e0dff6a3d511946b95274ad9ca9e5d3ae497b63fda866ac955358d2" dependencies = [ "proc-macro2", "quote", @@ -447,9 +385,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.64" +version = "1.0.73" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "799e97dc9fdae36a5c8b8f2cae9ce2ee9fdce2058c57a93e6099d919fd982f79" +checksum = "bcbd0344bc6533bc7ec56df11d42fb70f1b912351c0825ccb7211b59d8af7cf5" dependencies = [ "itoa", "ryu", @@ -458,9 +396,9 @@ dependencies = [ [[package]] name = "syn" -version = "1.0.68" +version = "1.0.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ce15dd3ed8aa2f8eeac4716d6ef5ab58b6b9256db41d7e1a0224c2788e8fd87" +checksum = "8daf5dd0bb60cbd4137b1b587d2fc0ae729bc07cf01cd70b36a1ed5ade3b9d59" dependencies = [ "proc-macro2", "quote", @@ -469,18 +407,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.24" +version = "1.0.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0f4a65597094d4483ddaed134f409b2cb7c1beccf25201a9f73c719254fa98e" +checksum = "854babe52e4df1653706b98fcfc05843010039b406875930a70e4d9644e5c417" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.24" +version = "1.0.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7765189610d8241a44529806d6fd1f2e0a08734313a35d5b3a556f92b381f3c0" +checksum = "aa32fd3f627f367fe16f893e2597ae3c05020f8bba2666a4e6ea73d377e5714b" dependencies = [ "proc-macro2", "quote", @@ -489,20 +427,19 @@ dependencies = [ [[package]] name = "time" -version = "0.1.44" +version = "0.1.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255" +checksum = "ca8a50ef2360fbd1eeb0ecd46795a87a19024eb4b53c5dc916ca1fd95fe62438" dependencies = [ "libc", - "wasi 0.10.0+wasi-snapshot-preview1", "winapi", ] [[package]] name = "tinyvec" -version = "1.1.1" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "317cca572a0e89c3ce0ca1f1bdc9369547fe318a683418e42ac8f59d14701023" +checksum = "2c1c1d5a42b6245520c249549ec267180beaffcc0615401ac8e31853d4b6d8d2" dependencies = [ "tinyvec_macros", ] @@ -521,33 +458,30 @@ checksum = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c" [[package]] name = "unicode-bidi" -version = "0.3.4" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5" -dependencies = [ - "matches", -] +checksum = "1a01404663e3db436ed2746d9fefef640d868edae3cceb81c3b8d5732fda678f" [[package]] name = "unicode-normalization" -version = "0.1.17" +version = "0.1.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07fbfce1c8a97d547e8b5334978438d9d6ec8c20e38f56d4a4374d181493eaef" +checksum = "d54590932941a9e9266f0832deed84ebe1bf2e4c9e4a3554d393d18f5e854bf9" dependencies = [ "tinyvec", ] [[package]] name = "unicode-xid" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" +checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" [[package]] name = "url" -version = "2.2.1" +version = "2.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ccd964113622c8e9322cfac19eb1004a07e636c545f325da085d5cdde6f1f8b" +checksum = "a507c383b2d33b5fc35d1861e77e6b383d158b2da5e14fe51b83dfedf6fd578c" dependencies = [ "form_urlencoded", "idna", @@ -557,17 +491,18 @@ dependencies = [ [[package]] name = "vcpkg" -version = "0.2.11" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b00bca6106a5e23f3eee943593759b7fcddb00554332e856d990c893966879fb" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" [[package]] name = "vergen" -version = "5.1.0" +version = "5.1.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfbc87f9a7a9d61b15d51d1d3547284f67b6b4f1494ce3fc5814c101f35a5183" +checksum = "6cf88d94e969e7956d924ba70741316796177fa0c79a2c9f4ab04998d96e966e" dependencies = [ "anyhow", + "cfg-if", "chrono", "enum-iterator", "getset", @@ -584,15 +519,9 @@ checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe" [[package]] name = "wasi" -version = "0.9.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" - -[[package]] -name = "wasi" -version = "0.10.0+wasi-snapshot-preview1" +version = "0.10.2+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" +checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" [[package]] name = "winapi" From 44cad75069fd3b8f2945d57c478b4e567da73440 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 15 Dec 2021 16:51:40 +0100 Subject: [PATCH 2858/3747] fix iteration-order-dependent output --- src/shims/foreign_items.rs | 29 ++++++++++++++----- .../exported_symbol_clashing.rs | 4 +-- 2 files changed, 23 insertions(+), 10 deletions(-) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 18f1673235c65..4ec422cf1f86e 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -173,14 +173,27 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx continue; }; if symbol_name == link_name { - if let Some((instance, original_cnum)) = instance_and_crate { - throw_machine_stop!(TerminationInfo::MultipleSymbolDefinitions { - link_name, - first: tcx.def_span(instance.def_id()).data(), - first_crate: tcx.crate_name(original_cnum), - second: tcx.def_span(def_id).data(), - second_crate: tcx.crate_name(cnum), - }); + if let Some((original_instance, original_cnum)) = instance_and_crate { + // Make sure we are consistent wrt what is 'first' and 'second'. + let original_span = tcx.def_span(original_instance.def_id()).data(); + let span = tcx.def_span(def_id).data(); + if original_span < span { + throw_machine_stop!(TerminationInfo::MultipleSymbolDefinitions { + link_name, + first: original_span, + first_crate: tcx.crate_name(original_cnum), + second: span, + second_crate: tcx.crate_name(cnum), + }); + } else { + throw_machine_stop!(TerminationInfo::MultipleSymbolDefinitions { + link_name, + first: span, + first_crate: tcx.crate_name(cnum), + second: original_span, + second_crate: tcx.crate_name(original_cnum), + }); + } } if !matches!(tcx.def_kind(def_id), DefKind::Fn | DefKind::AssocFn) { throw_ub_format!( diff --git a/tests/compile-fail/function_calls/exported_symbol_clashing.rs b/tests/compile-fail/function_calls/exported_symbol_clashing.rs index 105d98fc10a97..0e64778d8909f 100644 --- a/tests/compile-fail/function_calls/exported_symbol_clashing.rs +++ b/tests/compile-fail/function_calls/exported_symbol_clashing.rs @@ -1,10 +1,10 @@ #[no_mangle] fn foo() {} -//~^ HELP then it's defined here again, in crate `exported_symbol_clashing` +//~^ HELP it's first defined here, in crate `exported_symbol_clashing` #[export_name = "foo"] fn bar() {} -//~^ HELP it's first defined here, in crate `exported_symbol_clashing` +//~^ HELP then it's defined here again, in crate `exported_symbol_clashing` fn main() { extern "Rust" { From d8f7b831e72a421ffb60c60cb318342d4c409b62 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 15 Dec 2021 18:41:41 +0100 Subject: [PATCH 2859/3747] add regression test --- rust-version | 2 +- src/shims/foreign_items.rs | 2 +- tests/run-pass/issue-91636.rs | 20 ++++++++++++++++++++ 3 files changed, 22 insertions(+), 2 deletions(-) create mode 100644 tests/run-pass/issue-91636.rs diff --git a/rust-version b/rust-version index 3f00e3abe9145..b517ff5b95caa 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -404c8471aba60c2d837fa728e7c729a0f52d5830 +c5ecc157043ba413568b09292001a4a74b541a4e diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 4ec422cf1f86e..42d7958b260ff 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -176,7 +176,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if let Some((original_instance, original_cnum)) = instance_and_crate { // Make sure we are consistent wrt what is 'first' and 'second'. let original_span = tcx.def_span(original_instance.def_id()).data(); - let span = tcx.def_span(def_id).data(); + let span = tcx.def_span(def_id).data(); if original_span < span { throw_machine_stop!(TerminationInfo::MultipleSymbolDefinitions { link_name, diff --git a/tests/run-pass/issue-91636.rs b/tests/run-pass/issue-91636.rs new file mode 100644 index 0000000000000..21000bb68d2bc --- /dev/null +++ b/tests/run-pass/issue-91636.rs @@ -0,0 +1,20 @@ +type BuiltIn = for<'a> fn(&str); + +struct Function { + inner: BuiltIn, +} + +impl Function { + fn new(subr: BuiltIn) -> Self { + Self { inner: subr } + } +} + +fn dummy(_: &str) {} + +fn main() { + let func1 = Function::new(dummy); + let func2 = Function::new(dummy); + let inner: fn(&'static _) -> _ = func1.inner; + assert!(inner == func2.inner); +} From 4da38299fa9e6483642bce23204ca0445a0fc086 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 15 Dec 2021 18:58:28 +0100 Subject: [PATCH 2860/3747] looks like the asm macro is stable :D --- test-cargo-miri/build.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/test-cargo-miri/build.rs b/test-cargo-miri/build.rs index 31d251bc67894..72a4ee0de30ba 100644 --- a/test-cargo-miri/build.rs +++ b/test-cargo-miri/build.rs @@ -1,5 +1,3 @@ -#![feature(asm)] - use std::env; #[cfg(miri)] @@ -9,7 +7,7 @@ fn not_in_miri() -> i32 { // Inline assembly definitely does not work in Miri. let mut dummy = 42; unsafe { - asm!("/* {} */", in(reg) &mut dummy); + std::arch::asm!("/* {} */", in(reg) &mut dummy); } return dummy; } From b44f7ea079270e675e487dd723201027ac37de55 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 16 Dec 2021 15:20:58 +0100 Subject: [PATCH 2861/3747] require xargo 0.3.23 --- cargo-miri/bin.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index 9ac1a7086b826..183ce25b35555 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -12,7 +12,7 @@ use serde::{Deserialize, Serialize}; use rustc_version::VersionMeta; -const XARGO_MIN_VERSION: (u32, u32, u32) = (0, 3, 22); +const XARGO_MIN_VERSION: (u32, u32, u32) = (0, 3, 23); const CARGO_MIRI_HELP: &str = r#"Runs binary crates and tests in Miri From db74c1c030ba913e15b0c8bb86c50dc794f647b2 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 19 Dec 2021 17:46:17 +0100 Subject: [PATCH 2862/3747] readme: be more explicit about the toolchain --- README.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 487f8aeb2baf0..76764f8b07731 100644 --- a/README.md +++ b/README.md @@ -81,8 +81,11 @@ rustup +nightly component add miri If `rustup` says the `miri` component is unavailable, that's because not all nightly releases come with all tools. Check out [this website](https://rust-lang.github.io/rustup-components-history) to -determine a nightly version that comes with Miri and install that using -`rustup toolchain install nightly-YYYY-MM-DD`. +determine a nightly version that comes with Miri and install that using `rustup +toolchain install nightly-YYYY-MM-DD`. Either way, all of the following commands +assume the right toolchain is pinned via `rustup override set nightly` or +`rustup override set nightly-YYYY-MM-DD`. (Alternatively, use `cargo ++nightly`/`cargo +nightly-YYYY-MM-DD` for each of the following commands.) Now you can run your project in Miri: From c0f1670e47ac00c08afcf953cdf3060554b231ed Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 19 Dec 2021 19:49:05 +0100 Subject: [PATCH 2863/3747] rustup --- rust-version | 2 +- src/shims/intrinsics.rs | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/rust-version b/rust-version index b517ff5b95caa..dc73dadf90b70 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -c5ecc157043ba413568b09292001a4a74b541a4e +41c3017c82bbc16842cc3bc1afa904e6910e293c diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 39ed5ada0aa99..c2978ae34b358 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -32,7 +32,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // All supported intrinsics have a return place. - let intrinsic_name = &*this.tcx.item_name(instance.def_id()).as_str(); + let intrinsic_name = this.tcx.item_name(instance.def_id()); + let intrinsic_name = intrinsic_name.as_str(); let (dest, ret) = match ret { None => throw_unsup_format!("unimplemented (diverging) intrinsic: {}", intrinsic_name), Some(p) => p, From a9dd9b9571c5ef88632f84d239872da9509f8aba Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 20 Dec 2021 23:14:17 +0100 Subject: [PATCH 2864/3747] macOS-compatible realpath --- miri | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/miri b/miri index 4be1d5bc78f83..0ba7e536abe50 100755 --- a/miri +++ b/miri @@ -39,12 +39,8 @@ EOF TARGET=$(rustc --version --verbose | grep "^host:" | cut -d ' ' -f 2) SYSROOT=$(rustc --print sysroot) LIBDIR=$SYSROOT/lib/rustlib/$TARGET/lib -if readlink -e . &>/dev/null; then - # This platform supports `readlink -e`. - MIRIDIR=$(dirname "$(readlink -e "$0")") -else - MIRIDIR=$(dirname "$0") -fi +# macOS does not have a useful readlink/realpath so we have to use Python instead... +MIRIDIR=$(dirname "$(python -c 'import os, sys; print(os.path.realpath(sys.argv[1]))' "$0")") if ! test -d "$LIBDIR"; then echo "Something went wrong determining the library dir." echo "I got $LIBDIR but that does not exist." From cd6921923c107781abd815f3e5ed6f9540a3ab73 Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Sun, 19 Dec 2021 18:45:56 -0500 Subject: [PATCH 2865/3747] Provide better notes when tracking a pointer tag --- src/diagnostics.rs | 20 ++++++++++++++++++-- src/stacked_borrows.rs | 19 +++++++++++++------ 2 files changed, 31 insertions(+), 8 deletions(-) diff --git a/src/diagnostics.rs b/src/diagnostics.rs index 0d91f5246151f..a28418e749056 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -7,6 +7,7 @@ use log::trace; use rustc_middle::ty::{self, TyCtxt}; use rustc_span::{source_map::DUMMY_SP, Span, SpanData, Symbol}; +use crate::stacked_borrows::{AccessKind, SbTag}; use crate::*; /// Details of premature program termination. @@ -58,7 +59,9 @@ impl MachineStopType for TerminationInfo {} /// Miri specific diagnostics pub enum NonHaltingDiagnostic { CreatedPointerTag(NonZeroU64), - PoppedPointerTag(Item), + /// This `Item` was popped from the borrow stack, either due to a grant of + /// `AccessKind` to `SbTag` or a deallocation when the second argument is `None`. + PoppedPointerTag(Item, Option<(SbTag, AccessKind)>), CreatedCallId(CallId), CreatedAlloc(AllocId), FreedAlloc(AllocId), @@ -321,7 +324,20 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx use NonHaltingDiagnostic::*; let msg = match e { CreatedPointerTag(tag) => format!("created tag {:?}", tag), - PoppedPointerTag(item) => format!("popped tracked tag for item {:?}", item), + PoppedPointerTag(item, tag) => + match tag { + None => + format!( + "popped tracked tag for item {:?} due to deallocation", + item + ), + Some((tag, access)) => { + format!( + "popped tracked tag for item {:?} due to {:?} access for {:?}", + item, access, tag + ) + } + }, CreatedCallId(id) => format!("function call with id {}", id), CreatedAlloc(AllocId(id)) => format!("created allocation with id {}", id), FreedAlloc(AllocId(id)) => format!("freed allocation with id {}", id), diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 57c09ea40b68b..2919ce919aa47 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -111,7 +111,7 @@ pub struct GlobalState { pub type MemoryExtra = RefCell; /// Indicates which kind of access is being performed. -#[derive(Copy, Clone, Hash, PartialEq, Eq)] +#[derive(Copy, Clone, Hash, PartialEq, Eq, Debug)] pub enum AccessKind { Read, Write, @@ -296,19 +296,26 @@ impl<'tcx> Stack { } /// Check if the given item is protected. + /// + /// The `provoking_access` argument is only used to produce diagnostics. + /// It is `Some` when we are granting the contained access for said tag, and it is + /// `None` during a deallocation. fn check_protector( item: &Item, - tag: Option, + provoking_access: Option<(SbTag, AccessKind)>, global: &GlobalState, ) -> InterpResult<'tcx> { if let SbTag::Tagged(id) = item.tag { if Some(id) == global.tracked_pointer_tag { - register_diagnostic(NonHaltingDiagnostic::PoppedPointerTag(item.clone())); + register_diagnostic(NonHaltingDiagnostic::PoppedPointerTag( + item.clone(), + provoking_access, + )); } } if let Some(call) = item.protector { if global.is_active(call) { - if let Some(tag) = tag { + if let Some((tag, _)) = provoking_access { Err(err_sb_ub(format!( "not granting access to tag {:?} because incompatible item is protected: {:?}", tag, item @@ -348,7 +355,7 @@ impl<'tcx> Stack { let first_incompatible_idx = self.find_first_write_incompatible(granting_idx); for item in self.borrows.drain(first_incompatible_idx..).rev() { trace!("access: popping item {:?}", item); - Stack::check_protector(&item, Some(tag), global)?; + Stack::check_protector(&item, Some((tag, access)), global)?; } } else { // On a read, *disable* all `Unique` above the granting item. This ensures U2 for read accesses. @@ -363,7 +370,7 @@ impl<'tcx> Stack { let item = &mut self.borrows[idx]; if item.perm == Permission::Unique { trace!("access: disabling item {:?}", item); - Stack::check_protector(item, Some(tag), global)?; + Stack::check_protector(item, Some((tag, access)), global)?; item.perm = Permission::Disabled; } } From e51810df2c11e2a58de77d4b304f78d93851fca9 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 23 Dec 2021 15:57:39 +0100 Subject: [PATCH 2866/3747] add and document MIRI_LIB_SRC env var to set the source from which Miri builds the standard library --- CONTRIBUTING.md | 10 ++++++++++ README.md | 6 ++++++ cargo-miri/bin.rs | 16 +++++++++++++--- 3 files changed, 29 insertions(+), 3 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index caed6e3226d85..359378504343f 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -107,6 +107,16 @@ There's a test for the cargo wrapper in the `test-cargo-miri` directory; run `./run-test.py` in there to execute it. Like `./miri test`, this respects the `MIRI_TEST_TARGET` environment variable to execute the test for another target. +### Using a modified standard library + +Miri re-builds the standard library into a custom sysroot, so it is fairly easy +to test Miri against a modified standard library -- you do not even have to +build Miri yourself, the Miri shipped by `rustup` will work. All you have to do +is set the `MIRI_LIB_SRC` environment variable to the `library` folder of a +`rust-lang/rust` repository checkout. Note that changing files in that directory +does not automatically trigger a re-build of the standard library; you have to +clear the Miri build cache manually (on Linux, `rm -rf ~/.cache/miri`). + ## Configuring `rust-analyzer` To configure `rust-analyzer` and VS Code for working on Miri, save the following diff --git a/README.md b/README.md index 76764f8b07731..fb9a556699030 100644 --- a/README.md +++ b/README.md @@ -306,6 +306,12 @@ Moreover, Miri recognizes some environment variables: Miri executions, also [see "Testing the Miri driver" in `CONTRIBUTING.md`][testing-miri]. * `MIRIFLAGS` (recognized by `cargo miri` and the test suite) defines extra flags to be passed to Miri. +* `MIRI_LIB_SRC` defines the directory where Miri expects the sources of the + standard library that it will build and use for interpretation. This directory + must point to the `library` subdirectory of a `rust-lang/rust` repository + checkout. Note that changing files in that directory does not automatically + trigger a re-build of the standard library; you have to clear the Miri build + cache manually (on Linux, `rm -rf ~/.cache/miri`). * `MIRI_SYSROOT` (recognized by `cargo miri` and the test suite) indicates the sysroot to use. To do the same thing with `miri` directly, use the `--sysroot` flag. diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index 183ce25b35555..a946f79888338 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -1,5 +1,5 @@ use std::env; -use std::ffi::OsString; +use std::ffi::{OsStr, OsString}; use std::fmt::Write as _; use std::fs::{self, File}; use std::io::{self, BufRead, BufReader, BufWriter, Read, Write}; @@ -341,8 +341,11 @@ fn setup(subcommand: MiriCommand) { ask_to_run(cmd, ask_user, "install a recent enough xargo"); } - // Determine where the rust sources are located. `XARGO_RUST_SRC` env var trumps everything. - let rust_src = match std::env::var_os("XARGO_RUST_SRC") { + // Determine where the rust sources are located. The env vars manually setting the source + // (`MIRI_LIB_SRC`, `XARGO_RUST_SRC`) trump auto-detection. + let rust_src_env_var = + std::env::var_os("MIRI_LIB_SRC").or_else(|| std::env::var_os("XARGO_RUST_SRC")); + let rust_src = match rust_src_env_var { Some(path) => { let path = PathBuf::from(path); // Make path absolute if possible. @@ -376,6 +379,13 @@ fn setup(subcommand: MiriCommand) { if !rust_src.exists() { show_error(format!("given Rust source directory `{}` does not exist.", rust_src.display())); } + if rust_src.file_name().and_then(OsStr::to_str) != Some("library") { + show_error(format!( + "given Rust source directory `{}` does not seem to be the `library` subdirectory of \ + a Rust source checkout.", + rust_src.display() + )); + } // Next, we need our own libstd. Prepare a xargo project for that purpose. // We will do this work in whatever is a good cache dir for this platform. From a31229797388920eafe18796bf9e2c27cf86c895 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 29 Nov 2021 12:48:04 -0500 Subject: [PATCH 2867/3747] adjust for FnAbi changes --- rust-version | 2 +- src/helpers.rs | 2 +- src/machine.rs | 2 +- src/shims/foreign_items.rs | 154 ++++++++++++++++++++----------------- src/shims/mod.rs | 4 +- 5 files changed, 89 insertions(+), 75 deletions(-) diff --git a/rust-version b/rust-version index dc73dadf90b70..1ff2a14b5baae 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -41c3017c82bbc16842cc3bc1afa904e6910e293c +59337cddd41880f8075b07860a99be4dc402ddb1 diff --git a/src/helpers.rs b/src/helpers.rs index 081712dddc838..0cc6138ca702a 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -687,7 +687,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx link_name: Symbol, ) -> InterpResult<'tcx, ()> { self.check_abi(abi, exp_abi)?; - if let Some(body) = self.eval_context_mut().lookup_exported_symbol(link_name)? { + if let Some((body, _)) = self.eval_context_mut().lookup_exported_symbol(link_name)? { throw_machine_stop!(TerminationInfo::SymbolShimClashing { link_name, span: body.span.data(), diff --git a/src/machine.rs b/src/machine.rs index b1998ccccaa46..7cde8a8df681b 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -452,7 +452,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { args: &[OpTy<'tcx, Tag>], ret: Option<(&PlaceTy<'tcx, Tag>, mir::BasicBlock)>, unwind: StackPopUnwind, - ) -> InterpResult<'tcx, Option<&'mir mir::Body<'tcx>>> { + ) -> InterpResult<'tcx, Option<(&'mir mir::Body<'tcx>, ty::Instance<'tcx>)>> { ecx.find_mir_or_eval_fn(instance, abi, args, ret, unwind) } diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 42d7958b260ff..b07db9535129f 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -1,4 +1,5 @@ use std::{ + collections::hash_map::Entry, convert::{TryFrom, TryInto}, iter, }; @@ -34,7 +35,7 @@ pub enum EmulateByNameResult<'mir, 'tcx> { /// Jumping has already been taken care of. AlreadyJumped, /// A MIR body has been found for the function - MirBody(&'mir mir::Body<'tcx>), + MirBody(&'mir mir::Body<'tcx>, ty::Instance<'tcx>), /// The item is not supported. NotSupported, } @@ -135,81 +136,91 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn lookup_exported_symbol( &mut self, link_name: Symbol, - ) -> InterpResult<'tcx, Option<&'mir mir::Body<'tcx>>> { + ) -> InterpResult<'tcx, Option<(&'mir mir::Body<'tcx>, ty::Instance<'tcx>)>> { let this = self.eval_context_mut(); let tcx = this.tcx.tcx; // If the result was cached, just return it. - if let Some(instance) = this.machine.exported_symbols_cache.get(&link_name) { - return instance.map(|instance| this.load_mir(instance.def, None)).transpose(); - } - - // Find it if it was not cached. - let mut instance_and_crate: Option<(ty::Instance<'_>, CrateNum)> = None; - // `dependency_formats` includes all the transitive informations needed to link a crate, - // which is what we need here since we need to dig out `exported_symbols` from all transitive - // dependencies. - let dependency_formats = tcx.dependency_formats(()); - let dependency_format = dependency_formats - .iter() - .find(|(crate_type, _)| *crate_type == CrateType::Executable) - .expect("interpreting a non-executable crate"); - for cnum in - iter::once(LOCAL_CRATE).chain(dependency_format.1.iter().enumerate().filter_map( - |(num, &linkage)| (linkage != Linkage::NotLinked).then_some(CrateNum::new(num + 1)), - )) - { - // We can ignore `_export_level` here: we are a Rust crate, and everything is exported - // from a Rust crate. - for &(symbol, _export_level) in tcx.exported_symbols(cnum) { - if let ExportedSymbol::NonGeneric(def_id) = symbol { - let attrs = tcx.codegen_fn_attrs(def_id); - let symbol_name = if let Some(export_name) = attrs.export_name { - export_name - } else if attrs.flags.contains(CodegenFnAttrFlags::NO_MANGLE) { - tcx.item_name(def_id) - } else { - // Skip over items without an explicitly defined symbol name. - continue; - }; - if symbol_name == link_name { - if let Some((original_instance, original_cnum)) = instance_and_crate { - // Make sure we are consistent wrt what is 'first' and 'second'. - let original_span = tcx.def_span(original_instance.def_id()).data(); - let span = tcx.def_span(def_id).data(); - if original_span < span { - throw_machine_stop!(TerminationInfo::MultipleSymbolDefinitions { - link_name, - first: original_span, - first_crate: tcx.crate_name(original_cnum), - second: span, - second_crate: tcx.crate_name(cnum), - }); + // (Cannot use `or_insert` since the code below might have to throw an error.) + let entry = this.machine.exported_symbols_cache.entry(link_name); + let instance = *match entry { + Entry::Occupied(e) => e.into_mut(), + Entry::Vacant(e) => { + // Find it if it was not cached. + let mut instance_and_crate: Option<(ty::Instance<'_>, CrateNum)> = None; + // `dependency_formats` includes all the transitive informations needed to link a crate, + // which is what we need here since we need to dig out `exported_symbols` from all transitive + // dependencies. + let dependency_formats = tcx.dependency_formats(()); + let dependency_format = dependency_formats + .iter() + .find(|(crate_type, _)| *crate_type == CrateType::Executable) + .expect("interpreting a non-executable crate"); + for cnum in iter::once(LOCAL_CRATE).chain( + dependency_format.1.iter().enumerate().filter_map(|(num, &linkage)| { + (linkage != Linkage::NotLinked).then_some(CrateNum::new(num + 1)) + }), + ) { + // We can ignore `_export_level` here: we are a Rust crate, and everything is exported + // from a Rust crate. + for &(symbol, _export_level) in tcx.exported_symbols(cnum) { + if let ExportedSymbol::NonGeneric(def_id) = symbol { + let attrs = tcx.codegen_fn_attrs(def_id); + let symbol_name = if let Some(export_name) = attrs.export_name { + export_name + } else if attrs.flags.contains(CodegenFnAttrFlags::NO_MANGLE) { + tcx.item_name(def_id) } else { - throw_machine_stop!(TerminationInfo::MultipleSymbolDefinitions { - link_name, - first: span, - first_crate: tcx.crate_name(cnum), - second: original_span, - second_crate: tcx.crate_name(original_cnum), - }); + // Skip over items without an explicitly defined symbol name. + continue; + }; + if symbol_name == link_name { + if let Some((original_instance, original_cnum)) = instance_and_crate + { + // Make sure we are consistent wrt what is 'first' and 'second'. + let original_span = + tcx.def_span(original_instance.def_id()).data(); + let span = tcx.def_span(def_id).data(); + if original_span < span { + throw_machine_stop!( + TerminationInfo::MultipleSymbolDefinitions { + link_name, + first: original_span, + first_crate: tcx.crate_name(original_cnum), + second: span, + second_crate: tcx.crate_name(cnum), + } + ); + } else { + throw_machine_stop!( + TerminationInfo::MultipleSymbolDefinitions { + link_name, + first: span, + first_crate: tcx.crate_name(cnum), + second: original_span, + second_crate: tcx.crate_name(original_cnum), + } + ); + } + } + if !matches!(tcx.def_kind(def_id), DefKind::Fn | DefKind::AssocFn) { + throw_ub_format!( + "attempt to call an exported symbol that is not defined as a function" + ); + } + instance_and_crate = Some((ty::Instance::mono(tcx, def_id), cnum)); } } - if !matches!(tcx.def_kind(def_id), DefKind::Fn | DefKind::AssocFn) { - throw_ub_format!( - "attempt to call an exported symbol that is not defined as a function" - ); - } - instance_and_crate = Some((ty::Instance::mono(tcx, def_id), cnum)); } } + + e.insert(instance_and_crate.map(|ic| ic.0)) } + }; + match instance { + None => Ok(None), // no symbol with this name + Some(instance) => Ok(Some((this.load_mir(instance.def, None)?, instance))), } - - let instance = instance_and_crate.map(|ic| ic.0); - // Cache it and load its MIR, if found. - this.machine.exported_symbols_cache.try_insert(link_name, instance).unwrap(); - instance.map(|instance| this.load_mir(instance.def, None)).transpose() } /// Emulates calling a foreign item, failing if the item is not supported. @@ -225,7 +236,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx args: &[OpTy<'tcx, Tag>], ret: Option<(&PlaceTy<'tcx, Tag>, mir::BasicBlock)>, unwind: StackPopUnwind, - ) -> InterpResult<'tcx, Option<&'mir mir::Body<'tcx>>> { + ) -> InterpResult<'tcx, Option<(&'mir mir::Body<'tcx>, ty::Instance<'tcx>)>> { let this = self.eval_context_mut(); let attrs = this.tcx.get_attrs(def_id); let link_name = this @@ -253,7 +264,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.check_abi_and_shim_symbol_clash(abi, Abi::Rust, link_name)?; let panic_impl_id = tcx.lang_items().panic_impl().unwrap(); let panic_impl_instance = ty::Instance::mono(tcx, panic_impl_id); - return Ok(Some(&*this.load_mir(panic_impl_instance.def, None)?)); + return Ok(Some(( + &*this.load_mir(panic_impl_instance.def, None)?, + panic_impl_instance, + ))); } #[rustfmt::skip] | "exit" @@ -297,7 +311,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.go_to_block(ret); } EmulateByNameResult::AlreadyJumped => (), - EmulateByNameResult::MirBody(mir) => return Ok(Some(mir)), + EmulateByNameResult::MirBody(mir, instance) => return Ok(Some((mir, instance))), EmulateByNameResult::NotSupported => { if let Some(body) = this.lookup_exported_symbol(link_name)? { return Ok(Some(body)); @@ -328,11 +342,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx match allocator_kind { AllocatorKind::Global => { - let body = this + let (body, instance) = this .lookup_exported_symbol(symbol)? .expect("symbol should be present if there is a global allocator"); - Ok(EmulateByNameResult::MirBody(body)) + Ok(EmulateByNameResult::MirBody(body, instance)) } AllocatorKind::Default => { default(this)?; diff --git a/src/shims/mod.rs b/src/shims/mod.rs index b05fa76a934fc..66f673d241d36 100644 --- a/src/shims/mod.rs +++ b/src/shims/mod.rs @@ -30,7 +30,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx args: &[OpTy<'tcx, Tag>], ret: Option<(&PlaceTy<'tcx, Tag>, mir::BasicBlock)>, unwind: StackPopUnwind, - ) -> InterpResult<'tcx, Option<&'mir mir::Body<'tcx>>> { + ) -> InterpResult<'tcx, Option<(&'mir mir::Body<'tcx>, ty::Instance<'tcx>)>> { let this = self.eval_context_mut(); trace!("eval_fn_call: {:#?}, {:?}", instance, ret.map(|p| p.0)); @@ -54,7 +54,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // Otherwise, load the MIR. - Ok(Some(&*this.load_mir(instance.def, None)?)) + Ok(Some((&*this.load_mir(instance.def, None)?, instance))) } /// Returns `true` if the computation was performed, and `false` if we should just evaluate From 5ab0ea67f20e723d4d297fe332255a1c1c641a6c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 1 Dec 2021 21:37:06 -0500 Subject: [PATCH 2868/3747] adjust output for calling convention check --- .../function_calls/exported_symbol_abi_mismatch.rs | 6 +++--- tests/compile-fail/panic/bad_unwind.rs | 4 +--- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/tests/compile-fail/function_calls/exported_symbol_abi_mismatch.rs b/tests/compile-fail/function_calls/exported_symbol_abi_mismatch.rs index f92fae5d29355..7dbda584e8d4c 100644 --- a/tests/compile-fail/function_calls/exported_symbol_abi_mismatch.rs +++ b/tests/compile-fail/function_calls/exported_symbol_abi_mismatch.rs @@ -11,7 +11,7 @@ fn main() { #[cfg(fn_ptr)] unsafe { std::mem::transmute::(foo)() } - //[fn_ptr]~^ ERROR calling a function with ABI Rust using caller ABI C + //[fn_ptr]~^ ERROR calling a function with calling convention Rust using calling convention C // `Instance` caching should not suppress ABI check. #[cfg(cache)] @@ -23,7 +23,7 @@ fn main() { fn foo(); } unsafe { foo() } - //[no_cache]~^ ERROR calling a function with ABI Rust using caller ABI C - //[cache]~^^ ERROR calling a function with ABI Rust using caller ABI C + //[no_cache]~^ ERROR calling a function with calling convention Rust using calling convention C + //[cache]~^^ ERROR calling a function with calling convention Rust using calling convention C } } diff --git a/tests/compile-fail/panic/bad_unwind.rs b/tests/compile-fail/panic/bad_unwind.rs index fde2c19af07d5..1feee9a12ae04 100644 --- a/tests/compile-fail/panic/bad_unwind.rs +++ b/tests/compile-fail/panic/bad_unwind.rs @@ -1,9 +1,7 @@ -// error-pattern: calling a function with ABI C-unwind using caller ABI C +// error-pattern: unwinding past a stack frame that does not allow unwinding #![feature(c_unwind)] //! Unwinding when the caller ABI is "C" (without "-unwind") is UB. -//! Currently we detect the ABI mismatch; we could probably allow such calls in principle one day -//! but then we have to detect the unexpected unwinding. extern "C-unwind" fn unwind() { panic!(); From a58d43cf31f445ff2b36e1c762640d7a725ec5bc Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 1 Jan 2022 18:52:45 +0100 Subject: [PATCH 2869/3747] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 1ff2a14b5baae..cada8fabde572 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -59337cddd41880f8075b07860a99be4dc402ddb1 +4f49627c6fe2a32d1fed6310466bb0e1c535c0c0 From 77cec811b44ff5931251b5fcaf5594b63dae0afa Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 1 Jan 2022 19:01:46 +0100 Subject: [PATCH 2870/3747] exclude mutable references to !Unpin types from uniqueness guarantees --- src/stacked_borrows.rs | 18 ++++++++-- .../generators-self-referential.rs | 34 +++++++++++++++++++ 2 files changed, 49 insertions(+), 3 deletions(-) create mode 100644 tests/run-pass/stacked-borrows/generators-self-referential.rs diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 2919ce919aa47..37ecb749a4877 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -9,7 +9,11 @@ use std::num::NonZeroU64; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_hir::Mutability; use rustc_middle::mir::RetagKind; -use rustc_middle::ty::{self, layout::LayoutOf}; +use rustc_middle::ty::{ + self, + layout::{HasParamEnv, LayoutOf}, +}; +use rustc_span::DUMMY_SP; use rustc_target::abi::Size; use crate::*; @@ -657,8 +661,16 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Make sure that raw pointers and mutable shared references are reborrowed "weak": // There could be existing unique pointers reborrowed from them that should remain valid! let perm = match kind { - RefKind::Unique { two_phase: false } => Permission::Unique, - RefKind::Unique { two_phase: true } => Permission::SharedReadWrite, + RefKind::Unique { two_phase: false } + if place.layout.ty.is_unpin(this.tcx.at(DUMMY_SP), this.param_env()) => + { + // Only if the type is unpin do we actually enforce uniqueness + Permission::Unique + } + RefKind::Unique { .. } => { + // Two-phase references and !Unpin references are treated as SharedReadWrite + Permission::SharedReadWrite + } RefKind::Raw { mutable: true } => Permission::SharedReadWrite, RefKind::Shared | RefKind::Raw { mutable: false } => { // Shared references and *const are a whole different kind of game, the diff --git a/tests/run-pass/stacked-borrows/generators-self-referential.rs b/tests/run-pass/stacked-borrows/generators-self-referential.rs new file mode 100644 index 0000000000000..01ce8a61418cf --- /dev/null +++ b/tests/run-pass/stacked-borrows/generators-self-referential.rs @@ -0,0 +1,34 @@ +// See https://github.com/rust-lang/unsafe-code-guidelines/issues/148: +// this fails when Stacked Borrows is strictly applied even to `!Unpin` types. +#![feature(generators, generator_trait)] + +use std::{ + ops::{Generator, GeneratorState}, + pin::Pin, +}; + +fn firstn() -> impl Generator { + static move || { + let mut num = 0; + let num = &mut num; + + yield *num; + *num += 1; //~ ERROR: borrow stack + + yield *num; + *num += 1; + + yield *num; + *num += 1; + } +} + +fn main() { + let mut generator_iterator = firstn(); + let mut pin = unsafe { Pin::new_unchecked(&mut generator_iterator) }; + let mut sum = 0; + while let GeneratorState::Yielded(x) = pin.as_mut().resume(()) { + sum += x; + } + assert_eq!(sum, 3); +} From 45442c80b8075a67f7e9f3d1e71f62cb160b310c Mon Sep 17 00:00:00 2001 From: klensy Date: Mon, 3 Jan 2022 02:47:42 +0300 Subject: [PATCH 2871/3747] update crate rustc_version 0.3 -> 0.4 to remove some deps --- cargo-miri/Cargo.lock | 35 ++++------------------------------- cargo-miri/Cargo.toml | 2 +- 2 files changed, 5 insertions(+), 32 deletions(-) diff --git a/cargo-miri/Cargo.lock b/cargo-miri/Cargo.lock index c6a7f8b9c13f4..abb60080b786e 100644 --- a/cargo-miri/Cargo.lock +++ b/cargo-miri/Cargo.lock @@ -242,15 +242,6 @@ version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" -[[package]] -name = "pest" -version = "2.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10f4872ae94d7b90ae48754df22fd42ad52ce740b8f370b03da4835417403e53" -dependencies = [ - "ucd-trie", -] - [[package]] name = "pkg-config" version = "0.3.24" @@ -326,9 +317,9 @@ checksum = "fc71d2faa173b74b232dedc235e3ee1696581bb132fc116fa3626d6151a1a8fb" [[package]] name = "rustc_version" -version = "0.3.3" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0dfe2087c51c460008730de8b57e6a320782fbfb312e1f4d520e6c6fae155ee" +checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" dependencies = [ "semver", ] @@ -347,21 +338,9 @@ checksum = "73b4b750c782965c211b42f022f59af1fbceabdd026623714f104152f1ec149f" [[package]] name = "semver" -version = "0.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f301af10236f6df4160f7c3f04eec6dbc70ace82d23326abad5edee88801c6b6" -dependencies = [ - "semver-parser", -] - -[[package]] -name = "semver-parser" -version = "0.10.2" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00b0bef5b7f9e0df16536d3961cfb6e84331c065b4066afb39768d0e319411f7" -dependencies = [ - "pest", -] +checksum = "568a8e6258aa33c13358f81fd834adb854c6f7c9468520910a9b1e8fac068012" [[package]] name = "serde" @@ -450,12 +429,6 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" -[[package]] -name = "ucd-trie" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c" - [[package]] name = "unicode-bidi" version = "0.3.7" diff --git a/cargo-miri/Cargo.toml b/cargo-miri/Cargo.toml index f0ef30eabcf7d..15c46569232a8 100644 --- a/cargo-miri/Cargo.toml +++ b/cargo-miri/Cargo.toml @@ -15,7 +15,7 @@ doctest = false # and no doc tests [dependencies] directories = "3" -rustc_version = "0.3" +rustc_version = "0.4" serde_json = "1.0.40" # A noop dependency that changes in the Rust repository, it's a bit of a hack. From 808f7941151c7cbb5dc8c84479d3e0fa7fbbba74 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 3 Jan 2022 22:54:58 +0100 Subject: [PATCH 2872/3747] rustup --- rust-version | 2 +- src/machine.rs | 30 ------------------------------ 2 files changed, 1 insertion(+), 31 deletions(-) diff --git a/rust-version b/rust-version index cada8fabde572..cb81868b2aec0 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -4f49627c6fe2a32d1fed6310466bb0e1c535c0c0 +ddabe0775c5f5b551d5eb54e3c4366fb8bec0c92 diff --git a/src/machine.rs b/src/machine.rs index 7cde8a8df681b..3ca07db921a9e 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -7,7 +7,6 @@ use std::fmt; use std::num::NonZeroU64; use std::time::Instant; -use log::trace; use rand::rngs::StdRng; use rand::SeedableRng; @@ -503,35 +502,6 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { ecx.binary_ptr_op(bin_op, left, right) } - fn box_alloc( - ecx: &mut InterpCx<'mir, 'tcx, Self>, - dest: &PlaceTy<'tcx, Tag>, - ) -> InterpResult<'tcx> { - trace!("box_alloc for {:?}", dest.layout.ty); - let layout = ecx.layout_of(dest.layout.ty.builtin_deref(false).unwrap().ty)?; - // First argument: `size`. - // (`0` is allowed here -- this is expected to be handled by the lang item). - let size = Scalar::from_machine_usize(layout.size.bytes(), ecx); - - // Second argument: `align`. - let align = Scalar::from_machine_usize(layout.align.abi.bytes(), ecx); - - // Call the `exchange_malloc` lang item. - let malloc = ecx.tcx.lang_items().exchange_malloc_fn().unwrap(); - let malloc = ty::Instance::mono(ecx.tcx.tcx, malloc); - ecx.call_function( - malloc, - Abi::Rust, - &[size.into(), align.into()], - Some(dest), - // Don't do anything when we are done. The `statement()` function will increment - // the old stack frame's stmt counter to the next statement, which means that when - // `exchange_malloc` returns, we go on evaluating exactly where we want to be. - StackPopCleanup::None { cleanup: true }, - )?; - Ok(()) - } - fn thread_local_static_base_pointer( ecx: &mut InterpCx<'mir, 'tcx, Self>, def_id: DefId, From 81751a2a00f40fb21ab220cc2ab422121be4e79d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 4 Jan 2022 11:14:50 +0100 Subject: [PATCH 2873/3747] adjust for StackPopCleanup::None rename --- src/eval.rs | 4 ++-- src/shims/posix/thread.rs | 2 +- src/shims/tls.rs | 6 +++--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/eval.rs b/src/eval.rs index e3f252b50a928..9cd3a9a56466b 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -247,7 +247,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( Abi::Rust, &[Scalar::from_pointer(main_ptr, &ecx).into(), argc.into(), argv], Some(&ret_place.into()), - StackPopCleanup::None { cleanup: true }, + StackPopCleanup::Root { cleanup: true }, )?; } EntryFnType::Start => { @@ -256,7 +256,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( Abi::Rust, &[argc.into(), argv], Some(&ret_place.into()), - StackPopCleanup::None { cleanup: true }, + StackPopCleanup::Root { cleanup: true }, )?; } } diff --git a/src/shims/posix/thread.rs b/src/shims/posix/thread.rs index e64ef3b23c6f2..b49817e88511d 100644 --- a/src/shims/posix/thread.rs +++ b/src/shims/posix/thread.rs @@ -54,7 +54,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Abi::C { unwind: false }, &[*func_arg], Some(&ret_place.into()), - StackPopCleanup::None { cleanup: true }, + StackPopCleanup::Root { cleanup: true }, )?; // Restore the old active thread frame. diff --git a/src/shims/tls.rs b/src/shims/tls.rs index cf8b8e3e1b887..32bea8dde4754 100644 --- a/src/shims/tls.rs +++ b/src/shims/tls.rs @@ -259,7 +259,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Abi::System { unwind: false }, &[Scalar::null_ptr(this).into(), reason.into(), Scalar::null_ptr(this).into()], Some(&ret_place), - StackPopCleanup::None { cleanup: true }, + StackPopCleanup::Root { cleanup: true }, )?; this.enable_thread(active_thread); @@ -282,7 +282,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Abi::C { unwind: false }, &[data.into()], Some(&ret_place), - StackPopCleanup::None { cleanup: true }, + StackPopCleanup::Root { cleanup: true }, )?; // Enable the thread so that it steps through the destructor which @@ -325,7 +325,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Abi::C { unwind: false }, &[ptr.into()], Some(&ret_place), - StackPopCleanup::None { cleanup: true }, + StackPopCleanup::Root { cleanup: true }, )?; this.enable_thread(active_thread); From 522f40b0867ecc63c39d644e09968c65fb859f55 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 5 Jan 2022 09:55:29 +0100 Subject: [PATCH 2874/3747] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index cb81868b2aec0..4c43ab08421ae 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -ddabe0775c5f5b551d5eb54e3c4366fb8bec0c92 +26c9b0046f96403cdf959e4e1f874ec25f9dbf6f From 9376bf5d4df99d76c7457a159b7ce7d7dfb8f251 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 8 Jan 2022 17:27:48 +0100 Subject: [PATCH 2875/3747] rustup --- rust-version | 2 +- tests/run-pass/available-concurrency.rs | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/rust-version b/rust-version index 4c43ab08421ae..391c95bfc14cb 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -26c9b0046f96403cdf959e4e1f874ec25f9dbf6f +66f64a441a05cee8d5d701477b43ed851f778f3a diff --git a/tests/run-pass/available-concurrency.rs b/tests/run-pass/available-concurrency.rs index 422046c62d620..eb4d09b1f5495 100644 --- a/tests/run-pass/available-concurrency.rs +++ b/tests/run-pass/available-concurrency.rs @@ -1,5 +1,3 @@ -#![feature(available_parallelism)] - fn main() { assert_eq!(std::thread::available_parallelism().unwrap().get(), 1); } From ee6198fb98f1a2137ef3c0a8040b2e216a0c48fd Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 9 Jan 2022 14:50:03 +0100 Subject: [PATCH 2876/3747] rustup --- rust-version | 2 +- src/helpers.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/rust-version b/rust-version index 391c95bfc14cb..87b2fe72105a6 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -66f64a441a05cee8d5d701477b43ed851f778f3a +e19ca1d946269f7b7eb13171531caf2e16f42076 diff --git a/src/helpers.rs b/src/helpers.rs index 0cc6138ca702a..0c4e0c4e969e5 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -27,7 +27,7 @@ fn try_resolve_did<'mir, 'tcx>(tcx: TyCtxt<'tcx>, path: &[&str]) -> Option(tcx: TyCtxt<'tcx>, path: &[&str]) -> Option Date: Tue, 11 Jan 2022 16:17:39 +0100 Subject: [PATCH 2877/3747] Remove spurious `maybe_uninit_extra` Signed-off-by: Miguel Ojeda --- tests/run-pass/stacked-borrows/interior_mutability.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/run-pass/stacked-borrows/interior_mutability.rs b/tests/run-pass/stacked-borrows/interior_mutability.rs index 87624e520db10..23d82b8e435b8 100644 --- a/tests/run-pass/stacked-borrows/interior_mutability.rs +++ b/tests/run-pass/stacked-borrows/interior_mutability.rs @@ -1,4 +1,3 @@ -#![feature(maybe_uninit_extra)] use std::mem::MaybeUninit; use std::cell::{Cell, RefCell, UnsafeCell}; From 42b144ee8c1ce99ed03972f9658d101059b6dfbc Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 26 Jan 2022 10:54:55 -0500 Subject: [PATCH 2878/3747] rustup --- rust-version | 2 +- src/shims/posix/macos/dlsym.rs | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 87b2fe72105a6..09474d264038e 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -e19ca1d946269f7b7eb13171531caf2e16f42076 +a7f375789bab1a4e4a291c963081a8ca7d2b6bd7 diff --git a/src/shims/posix/macos/dlsym.rs b/src/shims/posix/macos/dlsym.rs index d5996cc6a9ed1..9994bfd53dc5d 100644 --- a/src/shims/posix/macos/dlsym.rs +++ b/src/shims/posix/macos/dlsym.rs @@ -17,6 +17,7 @@ impl Dlsym { pub fn from_str(name: &str) -> InterpResult<'static, Option> { Ok(match name { "getentropy" => Some(Dlsym::getentropy), + "openat" => None, // std has a fallback for this _ => throw_unsup_format!("unsupported macOS dlsym: {}", name), }) } From 3d5eb52cbd7d3f9c036da7e6548865d38d1db1ed Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 4 Feb 2022 17:17:28 +0100 Subject: [PATCH 2879/3747] rustup: disable read_dir test for now --- rust-version | 2 +- tests/run-pass/fs.rs | 10 ++++++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/rust-version b/rust-version index 09474d264038e..8b9c2e479e356 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -a7f375789bab1a4e4a291c963081a8ca7d2b6bd7 +009c1d02484dcc18e1596a33b3d8989a90361c89 diff --git a/tests/run-pass/fs.rs b/tests/run-pass/fs.rs index 1261dbf1768d6..568b7ab4e3b7a 100644 --- a/tests/run-pass/fs.rs +++ b/tests/run-pass/fs.rs @@ -6,7 +6,7 @@ extern crate libc; use std::fs::{ - File, create_dir, OpenOptions, read_dir, remove_dir, remove_dir_all, remove_file, rename, + File, create_dir, OpenOptions, remove_dir, remove_dir_all, remove_file, rename, }; use std::ffi::CString; use std::io::{Read, Write, Error, ErrorKind, Result, Seek, SeekFrom}; @@ -331,17 +331,19 @@ fn test_directory() { let path_2 = dir_path.join("test_file_2"); drop(File::create(&path_2).unwrap()); // Test that the files are present inside the directory + /* FIXME(1966) disabled due to missing readdir support let dir_iter = read_dir(&dir_path).unwrap(); let mut file_names = dir_iter.map(|e| e.unwrap().file_name()).collect::>(); file_names.sort_unstable(); - assert_eq!(file_names, vec!["test_file_1", "test_file_2"]); + assert_eq!(file_names, vec!["test_file_1", "test_file_2"]); */ // Clean up the files in the directory remove_file(&path_1).unwrap(); remove_file(&path_2).unwrap(); // Now there should be nothing left in the directory. - let dir_iter = read_dir(&dir_path).unwrap(); + /* FIXME(1966) disabled due to missing readdir support + dir_iter = read_dir(&dir_path).unwrap(); let file_names = dir_iter.map(|e| e.unwrap().file_name()).collect::>(); - assert!(file_names.is_empty()); + assert!(file_names.is_empty());*/ // Deleting the directory should succeed. remove_dir(&dir_path).unwrap(); From 6b8baee33978eaa526fec909f2de24754089acae Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 4 Feb 2022 17:55:53 +0100 Subject: [PATCH 2880/3747] rustup; implement simd_and/or --- rust-version | 2 +- src/shims/intrinsics.rs | 6 +++++- tests/run-pass/portable-simd.rs | 8 +++++--- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/rust-version b/rust-version index 8b9c2e479e356..5343cde310d42 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -009c1d02484dcc18e1596a33b3d8989a90361c89 +4e8fb743ccbec27344b2dd42de7057f41d4ebfdd diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index c2978ae34b358..0dabaaa700693 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -314,7 +314,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "simd_div" | "simd_rem" | "simd_shl" - | "simd_shr" => { + | "simd_shr" + | "simd_and" + | "simd_or" => { let &[ref left, ref right] = check_arg_count(args)?; let (left, left_len) = this.operand_to_simd(left)?; let (right, right_len) = this.operand_to_simd(right)?; @@ -331,6 +333,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "simd_rem" => mir::BinOp::Rem, "simd_shl" => mir::BinOp::Shl, "simd_shr" => mir::BinOp::Shr, + "simd_and" => mir::BinOp::BitAnd, + "simd_or" => mir::BinOp::BitOr, _ => unreachable!(), }; diff --git a/tests/run-pass/portable-simd.rs b/tests/run-pass/portable-simd.rs index beb0504e0e4f4..28999577308b5 100644 --- a/tests/run-pass/portable-simd.rs +++ b/tests/run-pass/portable-simd.rs @@ -18,11 +18,13 @@ fn simd_ops_i32() { assert_eq!(a + b, i32x4::from_array([11, 12, 13, 14])); assert_eq!(a - b, i32x4::from_array([9, 8, 7, 6])); assert_eq!(a * b, i32x4::from_array([10, 20, 30, 40])); - assert_eq!(a / b, i32x4::from_array([10, 5, 3, 2])); - assert_eq!(a / i32x4::splat(2), i32x4::splat(5)); - assert_eq!(a % b, i32x4::from_array([0, 0, 1, 2])); + //assert_eq!(a / b, i32x4::from_array([10, 5, 3, 2])); + //assert_eq!(a / i32x4::splat(2), i32x4::splat(5)); + //assert_eq!(a % b, i32x4::from_array([0, 0, 1, 2])); assert_eq!(b << i32x4::splat(2), i32x4::from_array([4, 8, 12, 16])); assert_eq!(b >> i32x4::splat(1), i32x4::from_array([0, 1, 1, 2])); + assert_eq!(b & i32x4::splat(2), i32x4::from_array([0, 2, 2, 0])); + assert_eq!(b | i32x4::splat(2), i32x4::from_array([3, 2, 3, 6])); } fn main() { From dfa0a3b3c7fc430f3ab7595d39bd45b712e5dd94 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 12 Feb 2022 11:53:51 +0100 Subject: [PATCH 2881/3747] implement const_allocate intrinsic --- rust-version | 2 +- src/shims/intrinsics.rs | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 5343cde310d42..0c82628c569af 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -4e8fb743ccbec27344b2dd42de7057f41d4ebfdd +78450d2d602b06d9b94349aaf8cece1a4acaf3a8 diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 0dabaaa700693..d0d35dc45817d 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -54,6 +54,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let right = this.read_immediate(right)?; this.binop_ignore_overflow(mir::BinOp::Ne, &left, &right, dest)?; } + "const_allocate" => { + // For now, for compatibility with the run-time implementation of this, we just return null. + // See . + this.write_null(dest)?; + } // Raw memory accesses "volatile_load" => { From ec66d2934be8496ca75c72d6baf0cfaf923632bd Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 12 Feb 2022 12:17:37 +0100 Subject: [PATCH 2882/3747] implement const_deallocate as a NOP --- src/shims/intrinsics.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index d0d35dc45817d..df41a88aeeb61 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -59,6 +59,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // See . this.write_null(dest)?; } + "const_deallocate" => { + // complete NOP + } // Raw memory accesses "volatile_load" => { From a21c98a896e7a748b361e2d615b0d098a3751939 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 20 Feb 2022 21:41:37 -0500 Subject: [PATCH 2883/3747] another for the trophy case --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index fb9a556699030..3f300db83643d 100644 --- a/README.md +++ b/README.md @@ -453,6 +453,7 @@ Definite bugs found: * [`encoding_rs` doing out-of-bounds pointer arithmetic](https://github.com/hsivonen/encoding_rs/pull/53) * [TiKV using `Vec::from_raw_parts` incorrectly](https://github.com/tikv/agatedb/pull/24) * Incorrect doctests for [`AtomicPtr`](https://github.com/rust-lang/rust/pull/84052) and [`Box::from_raw_in`](https://github.com/rust-lang/rust/pull/84053) +* [Insufficient alignment in `ThinVec`](https://github.com/Gankra/thin-vec/pull/27) Violations of [Stacked Borrows] found that are likely bugs (but Stacked Borrows is currently just an experiment): From c8fff51825a495a3803b0abf3ab09e31b00345f3 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 21 Feb 2022 21:34:05 -0500 Subject: [PATCH 2884/3747] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 0c82628c569af..d64c1095494d5 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -78450d2d602b06d9b94349aaf8cece1a4acaf3a8 +b8967b0d52a2ba5f0c9da0da03e78ccba5534e4a From 1ac1e55f3b0903f8088d9da77e8da889c97477f6 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 21 Feb 2022 21:41:52 -0500 Subject: [PATCH 2885/3747] implement simd_eq and simd_reduce_any --- src/shims/intrinsics.rs | 39 +++++++++++++++++-- .../intrinsics/simd-reduce-invalid-bool.rs | 14 +++++++ tests/run-pass/portable-simd.rs | 27 +++++++++++-- 3 files changed, 73 insertions(+), 7 deletions(-) create mode 100644 tests/compile-fail/intrinsics/simd-reduce-invalid-bool.rs diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index df41a88aeeb61..a75367b82c12f 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -324,7 +324,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "simd_shl" | "simd_shr" | "simd_and" - | "simd_or" => { + | "simd_or" + | "simd_eq" => { let &[ref left, ref right] = check_arg_count(args)?; let (left, left_len) = this.operand_to_simd(left)?; let (right, right_len) = this.operand_to_simd(right)?; @@ -343,6 +344,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "simd_shr" => mir::BinOp::Shr, "simd_and" => mir::BinOp::BitAnd, "simd_or" => mir::BinOp::BitOr, + "simd_eq" => mir::BinOp::Eq, _ => unreachable!(), }; @@ -351,7 +353,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let right = this.read_immediate(&this.mplace_index(&right, i)?.into())?; let dest = this.mplace_index(&dest, i)?; let (val, overflowed, ty) = this.overflowing_binary_op(op, &left, &right)?; - assert_eq!(ty, dest.layout.ty); if matches!(op, mir::BinOp::Shl | mir::BinOp::Shr) { // Shifts have extra UB as SIMD operations that the MIR binop does not have. // See . @@ -360,8 +361,40 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx throw_ub_format!("overflowing shift by {} in `{}` in SIMD lane {}", r_val, intrinsic_name, i); } } - this.write_scalar(val, &dest.into())?; + if matches!(op, mir::BinOp::Eq) { + // Special handling for boolean-returning operations + assert_eq!(ty, this.tcx.types.bool); + let val = val.to_bool().unwrap(); + let val = if val { -1 } else { 0 }; // SIMD uses all-1 as pattern for "true" + let val = Scalar::from_int(val, dest.layout.size); + this.write_scalar(val, &dest.into())?; + } else { + assert_eq!(ty, dest.layout.ty); + this.write_scalar(val, &dest.into())?; + } + } + } + "simd_reduce_any" => { + let &[ref arg] = check_arg_count(args)?; + let (arg, arg_len) = this.operand_to_simd(arg)?; + + let mut res = false; // the neutral element + for i in 0..arg_len { + let op = this.read_immediate(&this.mplace_index(&arg, i)?.into())?; + // We convert it to a *signed* integer and expect either 0 or -1 (the latter means all bits were set). + let val = op.to_scalar()?.to_int(op.layout.size)?; + let val = match val { + 0 => false, + -1 => true, + _ => + throw_ub_format!( + "each element of a simd_reduce_any operand must be all-0-bits or all-1-bits" + ), + }; + res = res | val; } + + this.write_scalar(Scalar::from_bool(res), dest)?; } // Atomic operations diff --git a/tests/compile-fail/intrinsics/simd-reduce-invalid-bool.rs b/tests/compile-fail/intrinsics/simd-reduce-invalid-bool.rs new file mode 100644 index 0000000000000..41dd7d74f4ec4 --- /dev/null +++ b/tests/compile-fail/intrinsics/simd-reduce-invalid-bool.rs @@ -0,0 +1,14 @@ +#![feature(platform_intrinsics, repr_simd)] + +extern "platform-intrinsic" { + pub(crate) fn simd_reduce_any(x: T) -> bool; +} + +#[repr(simd)] +#[allow(non_camel_case_types)] +struct i32x2(i32, i32); + +fn main() { unsafe { + let x = i32x2(0, 1); + simd_reduce_any(x); //~ERROR must be all-0-bits or all-1-bits +} } diff --git a/tests/run-pass/portable-simd.rs b/tests/run-pass/portable-simd.rs index 28999577308b5..17fea5916675e 100644 --- a/tests/run-pass/portable-simd.rs +++ b/tests/run-pass/portable-simd.rs @@ -1,4 +1,4 @@ -#![feature(portable_simd)] +#![feature(portable_simd, platform_intrinsics)] use std::simd::*; fn simd_ops_f32() { @@ -18,16 +18,35 @@ fn simd_ops_i32() { assert_eq!(a + b, i32x4::from_array([11, 12, 13, 14])); assert_eq!(a - b, i32x4::from_array([9, 8, 7, 6])); assert_eq!(a * b, i32x4::from_array([10, 20, 30, 40])); - //assert_eq!(a / b, i32x4::from_array([10, 5, 3, 2])); - //assert_eq!(a / i32x4::splat(2), i32x4::splat(5)); - //assert_eq!(a % b, i32x4::from_array([0, 0, 1, 2])); + assert_eq!(a / b, i32x4::from_array([10, 5, 3, 2])); + assert_eq!(a / i32x4::splat(2), i32x4::splat(5)); + assert_eq!(a % b, i32x4::from_array([0, 0, 1, 2])); assert_eq!(b << i32x4::splat(2), i32x4::from_array([4, 8, 12, 16])); assert_eq!(b >> i32x4::splat(1), i32x4::from_array([0, 1, 1, 2])); assert_eq!(b & i32x4::splat(2), i32x4::from_array([0, 2, 2, 0])); assert_eq!(b | i32x4::splat(2), i32x4::from_array([3, 2, 3, 6])); } +fn simd_intrinsics() { + extern "platform-intrinsic" { + pub(crate) fn simd_eq(x: T, y: T) -> U; + pub(crate) fn simd_reduce_any(x: T) -> bool; + } + + // Make sure simd_eq returns all-1 for `true` + let a = i32x4::splat(10); + let b = i32x4::from_array([1, 2, 10, 4]); + let c: i32x4 = unsafe { simd_eq(a, b) }; + assert_eq!(c, i32x4::from_array([0, 0, -1, 0])); + + unsafe { + assert!(!simd_reduce_any(i32x4::splat(0))); + assert!(simd_reduce_any(i32x4::splat(-1))); + } +} + fn main() { simd_ops_f32(); simd_ops_i32(); + simd_intrinsics(); } From 19ecd130b5854ea29c50de9bd985f56e00c6718e Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Sun, 20 Feb 2022 11:55:39 -0500 Subject: [PATCH 2886/3747] Prune backtraces similar to RUST_BACKTRACE=1 logic Previously, Miri would always print a backtrace including all frames when encountering an error. This adds -Zmiri-backtrace which defaults to 1, internally called BacktraceStyle::Short. By default, backtraces are pruned to start at __rust_begin_short_backtrace, similar to std. Then we also remove non-local frames from the bottom of the trace. This cleans up the last one or two shims outside main or a test. Users can opt out of pruning by setting -Zmiri-backtrace=full, and will be automatically opted out if there are no local frames because that means the reported error is likely in the Rust runtime, which this pruning is crafted to remove. --- src/bin/miri.rs | 10 ++++++++++ src/diagnostics.rs | 50 +++++++++++++++++++++++++++++++++++++++++++++- src/eval.rs | 12 +++++++++++ src/lib.rs | 2 +- src/machine.rs | 4 ++++ 5 files changed, 76 insertions(+), 2 deletions(-) diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 672c7e8c9675c..333ff6af889f6 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -29,6 +29,8 @@ use rustc_middle::{ }; use rustc_session::{config::ErrorOutputType, search_paths::PathKind, CtfeBacktrace}; +use miri::BacktraceStyle; + struct MiriCompilerCalls { miri_config: miri::MiriConfig, } @@ -462,6 +464,14 @@ fn main() { let measureme_out = arg.strip_prefix("-Zmiri-measureme=").unwrap(); miri_config.measureme_out = Some(measureme_out.to_string()); } + arg if arg.starts_with("-Zmiri-backtrace=") => { + miri_config.backtrace_style = match arg.strip_prefix("-Zmiri-backtrace=") { + Some("0") => BacktraceStyle::Off, + Some("1") => BacktraceStyle::Short, + Some("full") => BacktraceStyle::Full, + _ => panic!("-Zmiri-backtrace may only be 0, 1, or full"), + }; + } _ => { // Forward to rustc. rustc_args.push(arg); diff --git a/src/diagnostics.rs b/src/diagnostics.rs index a28418e749056..718148060749f 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -157,6 +157,46 @@ pub fn report_error<'tcx, 'mir>( } }; + let mut stacktrace = ecx.generate_stacktrace(); + let has_local_frame = stacktrace.iter().any(|frame| frame.instance.def_id().is_local()); + match ecx.machine.backtrace_style { + BacktraceStyle::Off => { + // Retain one frame so that we can print a span for the error itself + stacktrace.truncate(1); + } + BacktraceStyle::Short => { + // Only prune frames if there is at least one local frame. This check ensures that if + // we get a backtrace that never makes it to the user code because it has detected a + // bug in the Rust runtime, we don't prune away every frame. + if has_local_frame { + // This is part of the logic that `std` uses to select the relevant part of a + // backtrace. But here, we only look for __rust_begin_short_backtrace, not + // __rust_end_short_backtrace because the end symbol comes from a call to the default + // panic handler. + stacktrace = stacktrace + .into_iter() + .take_while(|frame| { + let def_id = frame.instance.def_id(); + let path = ecx.tcx.tcx.def_path_str(def_id); + !path.contains("__rust_begin_short_backtrace") + }) + .collect::>(); + + // After we prune frames from the bottom, there are a few left that are part of the + // Rust runtime. So we remove frames until we get to a local symbol, which should be + // main or a test. + // This len check ensures that we don't somehow remove every frame, as doing so breaks + // the primary error message. + while stacktrace.len() > 1 + && stacktrace.last().map_or(false, |e| !e.instance.def_id().is_local()) + { + stacktrace.pop(); + } + } + } + BacktraceStyle::Full => {} + } + e.print_backtrace(); let msg = e.to_string(); report_msg( @@ -165,9 +205,17 @@ pub fn report_error<'tcx, 'mir>( &if let Some(title) = title { format!("{}: {}", title, msg) } else { msg.clone() }, msg, helps, - &ecx.generate_stacktrace(), + &stacktrace, ); + // Include a note like `std` does for short backtraces, but since we are opt-out not opt-in, we + // do not include a note when backtraces are off. + if ecx.machine.backtrace_style == BacktraceStyle::Short && has_local_frame { + ecx.tcx.sess.diagnostic().note_without_error( + "some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace", + ); + } + // Debug-dump all locals. for (i, frame) in ecx.active_thread_stack().iter().enumerate() { trace!("-------------------"); diff --git a/src/eval.rs b/src/eval.rs index 9cd3a9a56466b..e2e85e3e75721 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -57,6 +57,16 @@ pub enum IsolatedOp { Allow, } +#[derive(Copy, Clone, PartialEq, Eq)] +pub enum BacktraceStyle { + /// Prints a terser backtrace which ideally only contains relevant information. + Short, + /// Prints a backtrace with all possible information. + Full, + /// Prints only the frame that the error occurs in. + Off, +} + /// Configuration needed to spawn a Miri instance. #[derive(Clone)] pub struct MiriConfig { @@ -98,6 +108,7 @@ pub struct MiriConfig { pub measureme_out: Option, /// Panic when unsupported functionality is encountered pub panic_on_unsupported: bool, + pub backtrace_style: BacktraceStyle, } impl Default for MiriConfig { @@ -121,6 +132,7 @@ impl Default for MiriConfig { cmpxchg_weak_failure_rate: 0.8, measureme_out: None, panic_on_unsupported: false, + backtrace_style: BacktraceStyle::Short, } } } diff --git a/src/lib.rs b/src/lib.rs index c786487d4a146..006eedde4b6f5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -60,7 +60,7 @@ pub use crate::diagnostics::{ NonHaltingDiagnostic, TerminationInfo, }; pub use crate::eval::{ - create_ecx, eval_entry, AlignmentCheck, IsolatedOp, MiriConfig, RejectOpWith, + create_ecx, eval_entry, AlignmentCheck, BacktraceStyle, IsolatedOp, MiriConfig, RejectOpWith, }; pub use crate::helpers::EvalContextExt as HelpersEvalContextExt; pub use crate::machine::{ diff --git a/src/machine.rs b/src/machine.rs index 3ca07db921a9e..a75ac844902fc 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -343,6 +343,9 @@ pub struct Evaluator<'mir, 'tcx> { /// functionality is encountered. If `false`, an error is propagated in the Miri application context /// instead (default behavior) pub(crate) panic_on_unsupported: bool, + + /// Equivalent setting as RUST_BACKTRACE on encountering an error. + pub(crate) backtrace_style: BacktraceStyle, } impl<'mir, 'tcx> Evaluator<'mir, 'tcx> { @@ -374,6 +377,7 @@ impl<'mir, 'tcx> Evaluator<'mir, 'tcx> { string_cache: Default::default(), exported_symbols_cache: FxHashMap::default(), panic_on_unsupported: config.panic_on_unsupported, + backtrace_style: config.backtrace_style, } } From a20d1f1889dbefcfec00d7050eaed751bd6983b8 Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Tue, 22 Feb 2022 21:09:30 -0500 Subject: [PATCH 2887/3747] Add crossbeam-epoch and integer-encoding to the trophy case --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 3f300db83643d..cc2965a716b77 100644 --- a/README.md +++ b/README.md @@ -454,6 +454,8 @@ Definite bugs found: * [TiKV using `Vec::from_raw_parts` incorrectly](https://github.com/tikv/agatedb/pull/24) * Incorrect doctests for [`AtomicPtr`](https://github.com/rust-lang/rust/pull/84052) and [`Box::from_raw_in`](https://github.com/rust-lang/rust/pull/84053) * [Insufficient alignment in `ThinVec`](https://github.com/Gankra/thin-vec/pull/27) +* [`crossbeam-epoch` calling `assume_init` on a partly-initialized `MaybeUninit`](https://github.com/crossbeam-rs/crossbeam/pull/779) +* [`integer-encoding` dereferencing a misaligned pointer](https://github.com/dermesser/integer-encoding-rs/pull/23) Violations of [Stacked Borrows] found that are likely bugs (but Stacked Borrows is currently just an experiment): From 444396d62056eada5dd6bf6e360aaa7377278754 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 24 Feb 2022 10:55:40 -0500 Subject: [PATCH 2888/3747] rustup --- rust-version | 2 +- tests/compile-fail/validity/execute_memory.rs | 8 -------- tests/compile-fail/validity/fn_ptr_offset.rs | 2 +- tests/compile-fail/validity/invalid_fnptr_null.rs | 5 +++++ tests/compile-fail/validity/invalid_fnptr_uninit.rs | 2 +- tests/run-pass/function_pointers.rs | 11 +++++++++++ 6 files changed, 19 insertions(+), 11 deletions(-) delete mode 100644 tests/compile-fail/validity/execute_memory.rs create mode 100644 tests/compile-fail/validity/invalid_fnptr_null.rs diff --git a/rust-version b/rust-version index d64c1095494d5..903f326d3fbdd 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -b8967b0d52a2ba5f0c9da0da03e78ccba5534e4a +3d127e2040b57157936f5f24e114a8b4c9a505ef diff --git a/tests/compile-fail/validity/execute_memory.rs b/tests/compile-fail/validity/execute_memory.rs deleted file mode 100644 index 5230e7fdf5297..0000000000000 --- a/tests/compile-fail/validity/execute_memory.rs +++ /dev/null @@ -1,8 +0,0 @@ -#![feature(box_syntax)] - -fn main() { - let x = box 42; - unsafe { - let _f = std::mem::transmute::, fn()>(x); //~ ERROR expected a function pointer - } -} diff --git a/tests/compile-fail/validity/fn_ptr_offset.rs b/tests/compile-fail/validity/fn_ptr_offset.rs index c651fbe070fba..27d8c830ce904 100644 --- a/tests/compile-fail/validity/fn_ptr_offset.rs +++ b/tests/compile-fail/validity/fn_ptr_offset.rs @@ -6,5 +6,5 @@ fn main() { let x : fn() = f; let y : *mut u8 = unsafe { mem::transmute(x) }; let y = y.wrapping_offset(1); - let _x : fn() = unsafe { mem::transmute(y) }; //~ ERROR expected a function pointer + let _x : fn() = unsafe { mem::transmute(y) }; //~ ERROR encountered a potentially null function pointer } diff --git a/tests/compile-fail/validity/invalid_fnptr_null.rs b/tests/compile-fail/validity/invalid_fnptr_null.rs new file mode 100644 index 0000000000000..2270740fe1495 --- /dev/null +++ b/tests/compile-fail/validity/invalid_fnptr_null.rs @@ -0,0 +1,5 @@ +#![allow(invalid_value)] + +fn main() { + let _b: fn() = unsafe { std::mem::transmute(0usize) }; //~ ERROR encountered a potentially null function pointer +} diff --git a/tests/compile-fail/validity/invalid_fnptr_uninit.rs b/tests/compile-fail/validity/invalid_fnptr_uninit.rs index dbd6711dc65a4..2d479dd319f3d 100644 --- a/tests/compile-fail/validity/invalid_fnptr_uninit.rs +++ b/tests/compile-fail/validity/invalid_fnptr_uninit.rs @@ -6,5 +6,5 @@ union MyUninit { } fn main() { - let _b = unsafe { MyUninit { init: () }.uninit }; //~ ERROR encountered uninitialized bytes, but expected a function pointer + let _b = unsafe { MyUninit { init: () }.uninit }; //~ ERROR encountered uninitialized bytes } diff --git a/tests/run-pass/function_pointers.rs b/tests/run-pass/function_pointers.rs index 26a2d5a6c2a9e..dcef1fa221dcb 100644 --- a/tests/run-pass/function_pointers.rs +++ b/tests/run-pass/function_pointers.rs @@ -1,3 +1,5 @@ +use std::mem; + trait Answer { fn answer() -> Self; } @@ -56,4 +58,13 @@ fn main() { assert!(return_fn_ptr(g) == g); assert!(return_fn_ptr(g) as unsafe fn() -> i32 == g as fn() -> i32 as unsafe fn() -> i32); assert!(return_fn_ptr(f) != f); + + // Any non-null value is okay for function pointers. + unsafe { + let _x: fn() = mem::transmute(1usize); + let mut b = Box::new(42); + let ptr = &mut *b as *mut _; + drop(b); + let _x: fn() = mem::transmute(ptr); + } } From ddd3e3c4e016677613fe04d5ef3995f362f4a93d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 25 Feb 2022 12:05:59 -0500 Subject: [PATCH 2889/3747] rustup --- rust-version | 2 +- src/diagnostics.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/rust-version b/rust-version index 903f326d3fbdd..ab902204cd3b0 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -3d127e2040b57157936f5f24e114a8b4c9a505ef +d4de1f230ca30b7ce08fbf453daebf8b2e7ffcc9 diff --git a/src/diagnostics.rs b/src/diagnostics.rs index 718148060749f..d651aabb86cfa 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -254,7 +254,7 @@ fn report_msg<'tcx>( ) { let span = stacktrace.first().map_or(DUMMY_SP, |fi| fi.span); let mut err = match diag_level { - DiagLevel::Error => tcx.sess.struct_span_err(span, title), + DiagLevel::Error => tcx.sess.struct_span_err(span, title).forget_guarantee(), DiagLevel::Warning => tcx.sess.struct_span_warn(span, title), DiagLevel::Note => tcx.sess.diagnostic().span_note_diag(span, title), }; From e9b140b4a5aa71b16a3c89be483b6fecd600379e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 24 Feb 2022 19:41:11 -0500 Subject: [PATCH 2890/3747] update fn ptr tests --- tests/compile-fail/validity/fn_ptr_offset.rs | 10 ---------- tests/compile-fail/validity/invalid_fnptr_null.rs | 2 +- tests/run-pass/function_pointers.rs | 5 +++-- 3 files changed, 4 insertions(+), 13 deletions(-) delete mode 100644 tests/compile-fail/validity/fn_ptr_offset.rs diff --git a/tests/compile-fail/validity/fn_ptr_offset.rs b/tests/compile-fail/validity/fn_ptr_offset.rs deleted file mode 100644 index 27d8c830ce904..0000000000000 --- a/tests/compile-fail/validity/fn_ptr_offset.rs +++ /dev/null @@ -1,10 +0,0 @@ -use std::mem; - -fn f() {} - -fn main() { - let x : fn() = f; - let y : *mut u8 = unsafe { mem::transmute(x) }; - let y = y.wrapping_offset(1); - let _x : fn() = unsafe { mem::transmute(y) }; //~ ERROR encountered a potentially null function pointer -} diff --git a/tests/compile-fail/validity/invalid_fnptr_null.rs b/tests/compile-fail/validity/invalid_fnptr_null.rs index 2270740fe1495..0634fba36a330 100644 --- a/tests/compile-fail/validity/invalid_fnptr_null.rs +++ b/tests/compile-fail/validity/invalid_fnptr_null.rs @@ -1,5 +1,5 @@ #![allow(invalid_value)] fn main() { - let _b: fn() = unsafe { std::mem::transmute(0usize) }; //~ ERROR encountered a potentially null function pointer + let _b: fn() = unsafe { std::mem::transmute(0usize) }; //~ ERROR encountered a null function pointer } diff --git a/tests/run-pass/function_pointers.rs b/tests/run-pass/function_pointers.rs index dcef1fa221dcb..e7d9b2ddd98ca 100644 --- a/tests/run-pass/function_pointers.rs +++ b/tests/run-pass/function_pointers.rs @@ -62,9 +62,10 @@ fn main() { // Any non-null value is okay for function pointers. unsafe { let _x: fn() = mem::transmute(1usize); - let mut b = Box::new(42); - let ptr = &mut *b as *mut _; + let mut b = Box::new(42u8); + let ptr = &mut *b as *mut u8; drop(b); let _x: fn() = mem::transmute(ptr); + let _x: fn() = mem::transmute(ptr.wrapping_offset(1)); } } From d2bb231954190da64d0b10c275beeb87833d87b2 Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Fri, 25 Feb 2022 19:18:05 -0500 Subject: [PATCH 2891/3747] Prune stacktraces for tag-tracking diagnostics too --- src/diagnostics.rs | 94 ++++++++++++++++++++++++++-------------------- 1 file changed, 53 insertions(+), 41 deletions(-) diff --git a/src/diagnostics.rs b/src/diagnostics.rs index 718148060749f..8494f8a8ef0fa 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -75,6 +75,54 @@ enum DiagLevel { Note, } +fn has_local_frame(stacktrace: &[FrameInfo<'_>]) -> bool { + stacktrace.iter().any(|frame| frame.instance.def_id().is_local()) +} + +fn prune_stacktrace<'mir, 'tcx>( + ecx: &InterpCx<'mir, 'tcx, Evaluator<'mir, 'tcx>>, + mut stacktrace: Vec>, +) -> Vec> { + match ecx.machine.backtrace_style { + BacktraceStyle::Off => { + // Retain one frame so that we can print a span for the error itself + stacktrace.truncate(1); + } + BacktraceStyle::Short => { + // Only prune frames if there is at least one local frame. This check ensures that if + // we get a backtrace that never makes it to the user code because it has detected a + // bug in the Rust runtime, we don't prune away every frame. + if has_local_frame(&stacktrace) { + // This is part of the logic that `std` uses to select the relevant part of a + // backtrace. But here, we only look for __rust_begin_short_backtrace, not + // __rust_end_short_backtrace because the end symbol comes from a call to the default + // panic handler. + stacktrace = stacktrace + .into_iter() + .take_while(|frame| { + let def_id = frame.instance.def_id(); + let path = ecx.tcx.tcx.def_path_str(def_id); + !path.contains("__rust_begin_short_backtrace") + }) + .collect::>(); + + // After we prune frames from the bottom, there are a few left that are part of the + // Rust runtime. So we remove frames until we get to a local symbol, which should be + // main or a test. + // This len check ensures that we don't somehow remove every frame, as doing so breaks + // the primary error message. + while stacktrace.len() > 1 + && stacktrace.last().map_or(false, |e| !e.instance.def_id().is_local()) + { + stacktrace.pop(); + } + } + } + BacktraceStyle::Full => {} + } + stacktrace +} + /// Emit a custom diagnostic without going through the miri-engine machinery pub fn report_error<'tcx, 'mir>( ecx: &InterpCx<'mir, 'tcx, Evaluator<'mir, 'tcx>>, @@ -157,46 +205,8 @@ pub fn report_error<'tcx, 'mir>( } }; - let mut stacktrace = ecx.generate_stacktrace(); - let has_local_frame = stacktrace.iter().any(|frame| frame.instance.def_id().is_local()); - match ecx.machine.backtrace_style { - BacktraceStyle::Off => { - // Retain one frame so that we can print a span for the error itself - stacktrace.truncate(1); - } - BacktraceStyle::Short => { - // Only prune frames if there is at least one local frame. This check ensures that if - // we get a backtrace that never makes it to the user code because it has detected a - // bug in the Rust runtime, we don't prune away every frame. - if has_local_frame { - // This is part of the logic that `std` uses to select the relevant part of a - // backtrace. But here, we only look for __rust_begin_short_backtrace, not - // __rust_end_short_backtrace because the end symbol comes from a call to the default - // panic handler. - stacktrace = stacktrace - .into_iter() - .take_while(|frame| { - let def_id = frame.instance.def_id(); - let path = ecx.tcx.tcx.def_path_str(def_id); - !path.contains("__rust_begin_short_backtrace") - }) - .collect::>(); - - // After we prune frames from the bottom, there are a few left that are part of the - // Rust runtime. So we remove frames until we get to a local symbol, which should be - // main or a test. - // This len check ensures that we don't somehow remove every frame, as doing so breaks - // the primary error message. - while stacktrace.len() > 1 - && stacktrace.last().map_or(false, |e| !e.instance.def_id().is_local()) - { - stacktrace.pop(); - } - } - } - BacktraceStyle::Full => {} - } - + let stacktrace = ecx.generate_stacktrace(); + let stacktrace = prune_stacktrace(ecx, stacktrace); e.print_backtrace(); let msg = e.to_string(); report_msg( @@ -210,7 +220,7 @@ pub fn report_error<'tcx, 'mir>( // Include a note like `std` does for short backtraces, but since we are opt-out not opt-in, we // do not include a note when backtraces are off. - if ecx.machine.backtrace_style == BacktraceStyle::Short && has_local_frame { + if ecx.machine.backtrace_style == BacktraceStyle::Short && has_local_frame(&stacktrace) { ecx.tcx.sess.diagnostic().note_without_error( "some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace", ); @@ -367,6 +377,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ); } + let stacktrace = prune_stacktrace(this, stacktrace); + // Show diagnostics. for e in diagnostics.drain(..) { use NonHaltingDiagnostic::*; From f1c649890b517997b0bab3b303415e2f6ceea476 Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Sat, 26 Feb 2022 17:02:17 -0500 Subject: [PATCH 2892/3747] Only print the pruning note if the trace was definitely pruned --- src/diagnostics.rs | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/src/diagnostics.rs b/src/diagnostics.rs index 8494f8a8ef0fa..2b210a6de6910 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -75,24 +75,26 @@ enum DiagLevel { Note, } -fn has_local_frame(stacktrace: &[FrameInfo<'_>]) -> bool { - stacktrace.iter().any(|frame| frame.instance.def_id().is_local()) -} - +/// Attempts to prune a stacktrace to omit the Rust runtime, and returns a bool indicating if any +/// frames were pruned. If the stacktrace does not have any local frames, we conclude that it must +/// be pointing to a problem in the Rust runtime itself, and do not prune it at all. fn prune_stacktrace<'mir, 'tcx>( ecx: &InterpCx<'mir, 'tcx, Evaluator<'mir, 'tcx>>, mut stacktrace: Vec>, -) -> Vec> { +) -> (Vec>, bool) { match ecx.machine.backtrace_style { BacktraceStyle::Off => { // Retain one frame so that we can print a span for the error itself stacktrace.truncate(1); + (stacktrace, false) } BacktraceStyle::Short => { + let original_len = stacktrace.len(); // Only prune frames if there is at least one local frame. This check ensures that if // we get a backtrace that never makes it to the user code because it has detected a // bug in the Rust runtime, we don't prune away every frame. - if has_local_frame(&stacktrace) { + let has_local_frame = stacktrace.iter().any(|frame| frame.instance.def_id().is_local()); + if has_local_frame { // This is part of the logic that `std` uses to select the relevant part of a // backtrace. But here, we only look for __rust_begin_short_backtrace, not // __rust_end_short_backtrace because the end symbol comes from a call to the default @@ -117,10 +119,11 @@ fn prune_stacktrace<'mir, 'tcx>( stacktrace.pop(); } } + let was_pruned = stacktrace.len() != original_len; + (stacktrace, was_pruned) } - BacktraceStyle::Full => {} + BacktraceStyle::Full => (stacktrace, false), } - stacktrace } /// Emit a custom diagnostic without going through the miri-engine machinery @@ -206,7 +209,7 @@ pub fn report_error<'tcx, 'mir>( }; let stacktrace = ecx.generate_stacktrace(); - let stacktrace = prune_stacktrace(ecx, stacktrace); + let (stacktrace, was_pruned) = prune_stacktrace(ecx, stacktrace); e.print_backtrace(); let msg = e.to_string(); report_msg( @@ -218,9 +221,8 @@ pub fn report_error<'tcx, 'mir>( &stacktrace, ); - // Include a note like `std` does for short backtraces, but since we are opt-out not opt-in, we - // do not include a note when backtraces are off. - if ecx.machine.backtrace_style == BacktraceStyle::Short && has_local_frame(&stacktrace) { + // Include a note like `std` does when we omit frames from a backtrace + if was_pruned { ecx.tcx.sess.diagnostic().note_without_error( "some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace", ); @@ -377,7 +379,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ); } - let stacktrace = prune_stacktrace(this, stacktrace); + let (stacktrace, _was_pruned) = prune_stacktrace(this, stacktrace); // Show diagnostics. for e in diagnostics.drain(..) { From 71075672f5af74aa3e119892ffe57fee2a336e1e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 27 Feb 2022 15:22:49 -0500 Subject: [PATCH 2893/3747] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index ab902204cd3b0..ba41809f0749b 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -d4de1f230ca30b7ce08fbf453daebf8b2e7ffcc9 +6a705566166debf5eff88c57140df607fa409aaa From c347b04e8280f09fd3f5d5f28020b6c50505895c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 27 Feb 2022 15:27:34 -0500 Subject: [PATCH 2894/3747] add test for rust issue 94371 --- tests/run-pass/issue-94371.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 tests/run-pass/issue-94371.rs diff --git a/tests/run-pass/issue-94371.rs b/tests/run-pass/issue-94371.rs new file mode 100644 index 0000000000000..1336348efb17a --- /dev/null +++ b/tests/run-pass/issue-94371.rs @@ -0,0 +1,13 @@ +#[repr(C)] +struct Demo(u64, bool, u64, u32, u64, u64, u64); + +fn test() -> (Demo, Demo) { + let mut x = Demo(1, true, 3, 4, 5, 6, 7); + let mut y = Demo(10, false, 12, 13, 14, 15, 16); + std::mem::swap(&mut x, &mut y); + (x, y) +} + +fn main() { + drop(test()); +} From f672282bf25db5670f5809f78b1cd701037cc2dc Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 1 Mar 2022 18:15:39 -0500 Subject: [PATCH 2895/3747] factor SIMD bool handling into helper functions --- src/helpers.rs | 15 +++++++++++++++ src/shims/intrinsics.rs | 16 +++------------- 2 files changed, 18 insertions(+), 13 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index 0c4e0c4e969e5..2f1c74a0587ec 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -758,3 +758,18 @@ pub fn immty_from_uint_checked<'tcx>( err_unsup_format!("unsigned value {:#x} does not fit in {} bits", int, layout.size.bits()) })?) } + +pub fn bool_to_simd_element(b: bool, size: Size) -> Scalar { + // SIMD uses all-1 as pattern for "true" + let val = if b { -1 } else { 0 }; + Scalar::from_int(val, size) +} + +pub fn simd_element_to_bool<'tcx>(elem: ImmTy<'tcx, Tag>) -> InterpResult<'tcx, bool> { + let val = elem.to_scalar()?.to_int(elem.layout.size)?; + Ok(match val { + 0 => false, + -1 => true, + _ => throw_ub_format!("each element of a SIMD mask must be all-0-bits or all-1-bits"), + }) +} diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index a75367b82c12f..74914963f74c2 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -8,7 +8,7 @@ use rustc_middle::{mir, mir::BinOp, ty, ty::FloatTy}; use rustc_target::abi::{Align, Integer}; use crate::*; -use helpers::check_arg_count; +use helpers::{bool_to_simd_element, check_arg_count, simd_element_to_bool}; pub enum AtomicOp { MirOp(mir::BinOp, bool), @@ -365,8 +365,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Special handling for boolean-returning operations assert_eq!(ty, this.tcx.types.bool); let val = val.to_bool().unwrap(); - let val = if val { -1 } else { 0 }; // SIMD uses all-1 as pattern for "true" - let val = Scalar::from_int(val, dest.layout.size); + let val = bool_to_simd_element(val, dest.layout.size); this.write_scalar(val, &dest.into())?; } else { assert_eq!(ty, dest.layout.ty); @@ -381,16 +380,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let mut res = false; // the neutral element for i in 0..arg_len { let op = this.read_immediate(&this.mplace_index(&arg, i)?.into())?; - // We convert it to a *signed* integer and expect either 0 or -1 (the latter means all bits were set). - let val = op.to_scalar()?.to_int(op.layout.size)?; - let val = match val { - 0 => false, - -1 => true, - _ => - throw_ub_format!( - "each element of a simd_reduce_any operand must be all-0-bits or all-1-bits" - ), - }; + let val = simd_element_to_bool(op)?; res = res | val; } From aa4f82ea4887bb9e0847bb2de287ef968b6b27f4 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 1 Mar 2022 18:40:40 -0500 Subject: [PATCH 2896/3747] implement simd_select --- rust-version | 2 +- src/shims/intrinsics.rs | 22 ++++++++++++++++++++++ tests/run-pass/portable-simd.rs | 21 ++++++++++++--------- 3 files changed, 35 insertions(+), 10 deletions(-) diff --git a/rust-version b/rust-version index ba41809f0749b..cab2da408db43 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -6a705566166debf5eff88c57140df607fa409aaa +f0c4da49983aa699f715caf681e3154b445fb60b diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 74914963f74c2..e84923314186c 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -386,6 +386,28 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_bool(res), dest)?; } + "simd_select" => { + let &[ref mask, ref yes, ref no] = check_arg_count(args)?; + let (mask, mask_len) = this.operand_to_simd(mask)?; + let (yes, yes_len) = this.operand_to_simd(yes)?; + let (no, no_len) = this.operand_to_simd(no)?; + let (dest, dest_len) = this.place_to_simd(dest)?; + + assert_eq!(dest_len, mask_len); + assert_eq!(dest_len, yes_len); + assert_eq!(dest_len, no_len); + + for i in 0..dest_len { + let mask = this.read_immediate(&this.mplace_index(&mask, i)?.into())?; + let yes = this.read_immediate(&this.mplace_index(&yes, i)?.into())?; + let no = this.read_immediate(&this.mplace_index(&no, i)?.into())?; + let dest = this.mplace_index(&dest, i)?; + + let mask = simd_element_to_bool(mask)?; + let val = if mask { yes } else { no }; + this.write_immediate(*val, &dest.into())?; + } + } // Atomic operations "atomic_load" => this.atomic_load(args, dest, AtomicReadOp::SeqCst)?, diff --git a/tests/run-pass/portable-simd.rs b/tests/run-pass/portable-simd.rs index 17fea5916675e..3c1437f0e0fcc 100644 --- a/tests/run-pass/portable-simd.rs +++ b/tests/run-pass/portable-simd.rs @@ -29,19 +29,22 @@ fn simd_ops_i32() { fn simd_intrinsics() { extern "platform-intrinsic" { - pub(crate) fn simd_eq(x: T, y: T) -> U; - pub(crate) fn simd_reduce_any(x: T) -> bool; + fn simd_eq(x: T, y: T) -> U; + fn simd_reduce_any(x: T) -> bool; + fn simd_select(m: M, yes: T, no: T) -> T; } - - // Make sure simd_eq returns all-1 for `true` - let a = i32x4::splat(10); - let b = i32x4::from_array([1, 2, 10, 4]); - let c: i32x4 = unsafe { simd_eq(a, b) }; - assert_eq!(c, i32x4::from_array([0, 0, -1, 0])); - unsafe { + // Make sure simd_eq returns all-1 for `true` + let a = i32x4::splat(10); + let b = i32x4::from_array([1, 2, 10, 4]); + let c: i32x4 = simd_eq(a, b); + assert_eq!(c, i32x4::from_array([0, 0, -1, 0])); + assert!(!simd_reduce_any(i32x4::splat(0))); assert!(simd_reduce_any(i32x4::splat(-1))); + + assert_eq!(simd_select(i8x4::from_array([0, -1, -1, 0]), a, b), i32x4::from_array([1, 10, 10, 4])); + assert_eq!(simd_select(i8x4::from_array([0, -1, -1, 0]), b, a), i32x4::from_array([10, 2, 10, 10])); } } From 363236e2d493b8a29d6ed7e849279ecf22c732ce Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 1 Mar 2022 18:44:37 -0500 Subject: [PATCH 2897/3747] test overflowing Div/Rem --- tests/run-pass/portable-simd.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/run-pass/portable-simd.rs b/tests/run-pass/portable-simd.rs index 3c1437f0e0fcc..98d5b65e3e68c 100644 --- a/tests/run-pass/portable-simd.rs +++ b/tests/run-pass/portable-simd.rs @@ -20,7 +20,9 @@ fn simd_ops_i32() { assert_eq!(a * b, i32x4::from_array([10, 20, 30, 40])); assert_eq!(a / b, i32x4::from_array([10, 5, 3, 2])); assert_eq!(a / i32x4::splat(2), i32x4::splat(5)); + assert_eq!(i32x2::splat(i32::MIN) / i32x2::splat(-1), i32x2::splat(i32::MIN)); assert_eq!(a % b, i32x4::from_array([0, 0, 1, 2])); + assert_eq!(i32x2::splat(i32::MIN) % i32x2::splat(-1), i32x2::splat(0)); assert_eq!(b << i32x4::splat(2), i32x4::from_array([4, 8, 12, 16])); assert_eq!(b >> i32x4::splat(1), i32x4::from_array([0, 1, 1, 2])); assert_eq!(b & i32x4::splat(2), i32x4::from_array([0, 2, 2, 0])); From 798dc5a78ac9b0016c9b5c193bf8c7dea73ef908 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 2 Mar 2022 13:06:28 -0500 Subject: [PATCH 2898/3747] Make sure we notice when a u16 is loaded at offset 1 into a u8 allocation --- .../unaligned_pointers/unaligned_ptr4.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 tests/compile-fail/unaligned_pointers/unaligned_ptr4.rs diff --git a/tests/compile-fail/unaligned_pointers/unaligned_ptr4.rs b/tests/compile-fail/unaligned_pointers/unaligned_ptr4.rs new file mode 100644 index 0000000000000..10766746bd42d --- /dev/null +++ b/tests/compile-fail/unaligned_pointers/unaligned_ptr4.rs @@ -0,0 +1,12 @@ +// This should fail even without validation or Stacked Borrows. +// compile-flags: -Zmiri-disable-validation -Zmiri-disable-stacked-borrows + +fn main() { + // Make sure we notice when a u16 is loaded at offset 1 into a u8 allocation. + // (This would be missed if u8 allocations are *always* at odd addresses.) + for _ in 0..10 { // Try many times as this might work by chance. + let x = [0u8; 4]; + let ptr = x.as_ptr().wrapping_offset(1).cast::(); + let _val = unsafe { *ptr }; //~ERROR but alignment + } +} From 97ddcf1f6b1183f3187a74f29f0feb0a4ff4887c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 1 Mar 2022 20:37:46 -0500 Subject: [PATCH 2899/3747] adjust for div/rem overflow being UB --- tests/compile-fail/intrinsics/exact_div4.rs | 2 +- tests/compile-fail/intrinsics/unchecked_div1.rs | 2 +- tests/run-pass/integer-ops.rs | 3 +++ 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/tests/compile-fail/intrinsics/exact_div4.rs b/tests/compile-fail/intrinsics/exact_div4.rs index c241b2df660e4..2831795de82ea 100644 --- a/tests/compile-fail/intrinsics/exact_div4.rs +++ b/tests/compile-fail/intrinsics/exact_div4.rs @@ -1,5 +1,5 @@ #![feature(core_intrinsics)] fn main() { // divison of MIN by -1 - unsafe { std::intrinsics::exact_div(i64::MIN, -1); } //~ ERROR result of dividing MIN by -1 cannot be represented + unsafe { std::intrinsics::exact_div(i64::MIN, -1); } //~ ERROR overflow in signed remainder (dividing MIN by -1) } diff --git a/tests/compile-fail/intrinsics/unchecked_div1.rs b/tests/compile-fail/intrinsics/unchecked_div1.rs index 53d80007646de..08b654da3ed75 100644 --- a/tests/compile-fail/intrinsics/unchecked_div1.rs +++ b/tests/compile-fail/intrinsics/unchecked_div1.rs @@ -1,5 +1,5 @@ #![feature(core_intrinsics)] fn main() { // MIN/-1 cannot be represented - unsafe { std::intrinsics::unchecked_div(i16::MIN, -1); } //~ ERROR overflow executing `unchecked_div` + unsafe { std::intrinsics::unchecked_div(i16::MIN, -1); } //~ ERROR overflow in signed division (dividing MIN by -1) } diff --git a/tests/run-pass/integer-ops.rs b/tests/run-pass/integer-ops.rs index 36bd5797177a2..fde220d8f35e8 100644 --- a/tests/run-pass/integer-ops.rs +++ b/tests/run-pass/integer-ops.rs @@ -116,6 +116,9 @@ pub fn main() { assert_eq!(100i8.wrapping_rem(10), 0); assert_eq!((-128i8).wrapping_rem(-1), 0); + assert_eq!(i32::MIN.wrapping_div(-1), i32::MIN); + assert_eq!(i32::MIN.wrapping_rem(-1), 0); + assert_eq!(100i8.wrapping_neg(), -100); assert_eq!((-128i8).wrapping_neg(), -128); From d7c7fc0fa2c00ece9680daae137fedbb17923cee Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 3 Mar 2022 12:26:42 -0500 Subject: [PATCH 2900/3747] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index cab2da408db43..56281423c5279 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -f0c4da49983aa699f715caf681e3154b445fb60b +45660949132222ba7ec0905649b2affd68e0e13c From c0f72510550529ca8ddaaffd94709bec457debff Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 3 Mar 2022 12:32:42 -0500 Subject: [PATCH 2901/3747] add test for simd division overflow UB --- .../compile-fail/intrinsics/simd-div-overflow.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 tests/compile-fail/intrinsics/simd-div-overflow.rs diff --git a/tests/compile-fail/intrinsics/simd-div-overflow.rs b/tests/compile-fail/intrinsics/simd-div-overflow.rs new file mode 100644 index 0000000000000..277b9e807baac --- /dev/null +++ b/tests/compile-fail/intrinsics/simd-div-overflow.rs @@ -0,0 +1,15 @@ +#![feature(platform_intrinsics, repr_simd)] + +extern "platform-intrinsic" { + pub(crate) fn simd_div(x: T, y: T) -> T; +} + +#[repr(simd)] +#[allow(non_camel_case_types)] +struct i32x2(i32, i32); + +fn main() { unsafe { + let x = i32x2(1, i32::MIN); + let y = i32x2(1, -1); + simd_div(x, y); //~ERROR Undefined Behavior: overflow in signed division +} } From 0bd83245edb4a420bdf89edea5f6e50f70c78475 Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Thu, 3 Mar 2022 13:10:05 -0500 Subject: [PATCH 2902/3747] rkyv deallocation alignment issue --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index cc2965a716b77..f073cde7764ea 100644 --- a/README.md +++ b/README.md @@ -456,6 +456,7 @@ Definite bugs found: * [Insufficient alignment in `ThinVec`](https://github.com/Gankra/thin-vec/pull/27) * [`crossbeam-epoch` calling `assume_init` on a partly-initialized `MaybeUninit`](https://github.com/crossbeam-rs/crossbeam/pull/779) * [`integer-encoding` dereferencing a misaligned pointer](https://github.com/dermesser/integer-encoding-rs/pull/23) +* [`rkyv` constructing a `Box<[u8]>` from an overaligned allocation](https://github.com/rkyv/rkyv/commit/a9417193a34757e12e24263178be8b2eebb72456) Violations of [Stacked Borrows] found that are likely bugs (but Stacked Borrows is currently just an experiment): From 0147b88ce59cb44cd854c7033a5663e43479e612 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 3 Mar 2022 14:44:50 -0500 Subject: [PATCH 2903/3747] use binary_op over overflowing_binary_op --- src/data_race.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/data_race.rs b/src/data_race.rs index 9e5dfd9dbaf0d..a6ef56a0c2045 100644 --- a/src/data_race.rs +++ b/src/data_race.rs @@ -553,7 +553,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { let this = self.eval_context_mut(); let old = this.allow_data_races_mut(|this| this.read_immediate(&place.into()))?; - let lt = this.overflowing_binary_op(mir::BinOp::Lt, &old, &rhs)?.0.to_bool()?; + let lt = this.binary_op(mir::BinOp::Lt, &old, &rhs)?.to_scalar()?.to_bool()?; let new_val = if min { if lt { &old } else { &rhs } @@ -593,11 +593,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { // Read as immediate for the sake of `binary_op()` let old = this.allow_data_races_mut(|this| this.read_immediate(&(place.into())))?; // `binary_op` will bail if either of them is not a scalar. - let eq = this.overflowing_binary_op(mir::BinOp::Eq, &old, expect_old)?.0; + let eq = this.binary_op(mir::BinOp::Eq, &old, expect_old)?; // If the operation would succeed, but is "weak", fail some portion // of the time, based on `rate`. let rate = this.memory.extra.cmpxchg_weak_failure_rate; - let cmpxchg_success = eq.to_bool()? + let cmpxchg_success = eq.to_scalar()?.to_bool()? && (!can_fail_spuriously || this.memory.extra.rng.get_mut().gen::() < rate); let res = Immediate::ScalarPair( old.to_scalar_or_uninit(), From 0d4902f12f2630ababe056b167ad20eb0633bb01 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 3 Mar 2022 14:54:54 -0500 Subject: [PATCH 2904/3747] implement simd_neg and simd_fabs --- src/lib.rs | 1 + src/shims/intrinsics.rs | 39 +++++++++++++++++++++++++++++---- tests/run-pass/portable-simd.rs | 27 ++++++++++++++++++----- 3 files changed, 58 insertions(+), 9 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 006eedde4b6f5..9542fb9b96355 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,6 +3,7 @@ #![feature(map_try_insert)] #![feature(never_type)] #![feature(try_blocks)] +#![feature(let_else)] #![feature(bool_to_option)] #![warn(rust_2018_idioms)] #![allow(clippy::cast_lossless)] diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index e84923314186c..f713721f58409 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -316,6 +316,37 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // SIMD operations #[rustfmt::skip] + | "simd_neg" + | "simd_fabs" => { + let &[ref op] = check_arg_count(args)?; + let (op, op_len) = this.operand_to_simd(op)?; + let (dest, dest_len) = this.place_to_simd(dest)?; + + assert_eq!(dest_len, op_len); + + for i in 0..dest_len { + let op = this.read_immediate(&this.mplace_index(&op, i)?.into())?; + let dest = this.mplace_index(&dest, i)?; + let val = match intrinsic_name { + "simd_neg" => this.unary_op(mir::UnOp::Neg, &op)?.to_scalar()?, + "simd_fabs" => { + // Works for f32 and f64. + let ty::Float(float_ty) = op.layout.ty.kind() else { + bug!("simd_fabs operand is not a float") + }; + let op = op.to_scalar()?; + // FIXME: Using host floats. + match float_ty { + FloatTy::F32 => Scalar::from_f32(op.to_f32()?.abs()), + FloatTy::F64 => Scalar::from_f64(op.to_f64()?.abs()), + } + } + _ => bug!(), + }; + this.write_scalar(val, &dest.into())?; + } + } + #[rustfmt::skip] | "simd_add" | "simd_sub" | "simd_mul" @@ -374,12 +405,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } "simd_reduce_any" => { - let &[ref arg] = check_arg_count(args)?; - let (arg, arg_len) = this.operand_to_simd(arg)?; + let &[ref op] = check_arg_count(args)?; + let (op, op_len) = this.operand_to_simd(op)?; let mut res = false; // the neutral element - for i in 0..arg_len { - let op = this.read_immediate(&this.mplace_index(&arg, i)?.into())?; + for i in 0..op_len { + let op = this.read_immediate(&this.mplace_index(&op, i)?.into())?; let val = simd_element_to_bool(op)?; res = res | val; } diff --git a/tests/run-pass/portable-simd.rs b/tests/run-pass/portable-simd.rs index 98d5b65e3e68c..c0c1ecd0235aa 100644 --- a/tests/run-pass/portable-simd.rs +++ b/tests/run-pass/portable-simd.rs @@ -3,18 +3,34 @@ use std::simd::*; fn simd_ops_f32() { let a = f32x4::splat(10.0); - let b = f32x4::from_array([1.0, 2.0, 3.0, 4.0]); - assert_eq!(a + b, f32x4::from_array([11.0, 12.0, 13.0, 14.0])); - assert_eq!(a - b, f32x4::from_array([9.0, 8.0, 7.0, 6.0])); - assert_eq!(a * b, f32x4::from_array([10.0, 20.0, 30.0, 40.0])); - assert_eq!(b / a, f32x4::from_array([0.1, 0.2, 0.3, 0.4])); + let b = f32x4::from_array([1.0, 2.0, 3.0, -4.0]); + assert_eq!(-b, f32x4::from_array([-1.0, -2.0, -3.0, 4.0])); + assert_eq!(a + b, f32x4::from_array([11.0, 12.0, 13.0, 6.0])); + assert_eq!(a - b, f32x4::from_array([9.0, 8.0, 7.0, 14.0])); + assert_eq!(a * b, f32x4::from_array([10.0, 20.0, 30.0, -40.0])); + assert_eq!(b / a, f32x4::from_array([0.1, 0.2, 0.3, -0.4])); assert_eq!(a / f32x4::splat(2.0), f32x4::splat(5.0)); assert_eq!(a % b, f32x4::from_array([0.0, 0.0, 1.0, 2.0])); + assert_eq!(b.abs(), f32x4::from_array([1.0, 2.0, 3.0, 4.0])); +} + +fn simd_ops_f64() { + let a = f64x4::splat(10.0); + let b = f64x4::from_array([1.0, 2.0, 3.0, -4.0]); + assert_eq!(-b, f64x4::from_array([-1.0, -2.0, -3.0, 4.0])); + assert_eq!(a + b, f64x4::from_array([11.0, 12.0, 13.0, 6.0])); + assert_eq!(a - b, f64x4::from_array([9.0, 8.0, 7.0, 14.0])); + assert_eq!(a * b, f64x4::from_array([10.0, 20.0, 30.0, -40.0])); + assert_eq!(b / a, f64x4::from_array([0.1, 0.2, 0.3, -0.4])); + assert_eq!(a / f64x4::splat(2.0), f64x4::splat(5.0)); + assert_eq!(a % b, f64x4::from_array([0.0, 0.0, 1.0, 2.0])); + assert_eq!(b.abs(), f64x4::from_array([1.0, 2.0, 3.0, 4.0])); } fn simd_ops_i32() { let a = i32x4::splat(10); let b = i32x4::from_array([1, 2, 3, 4]); + assert_eq!(-b, i32x4::from_array([-1, -2, -3, -4])); assert_eq!(a + b, i32x4::from_array([11, 12, 13, 14])); assert_eq!(a - b, i32x4::from_array([9, 8, 7, 6])); assert_eq!(a * b, i32x4::from_array([10, 20, 30, 40])); @@ -52,6 +68,7 @@ fn simd_intrinsics() { fn main() { simd_ops_f32(); + simd_ops_f64(); simd_ops_i32(); simd_intrinsics(); } From 3adc203c1cb9185ac546285c32e302a7f834bf11 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 5 Mar 2022 11:09:50 -0500 Subject: [PATCH 2905/3747] add flag to forward specific env vars (while isolation remains enabled) --- README.md | 11 +++++++---- src/bin/miri.rs | 5 +++++ src/eval.rs | 5 ++++- src/shims/env.rs | 10 ++++++++-- tests/run-pass/env-forward.rs | 5 +++++ 5 files changed, 29 insertions(+), 7 deletions(-) create mode 100644 tests/run-pass/env-forward.rs diff --git a/README.md b/README.md index f073cde7764ea..3c5af59d3f079 100644 --- a/README.md +++ b/README.md @@ -236,10 +236,13 @@ environment variable: execution with a "permission denied" error being returned to the program. `warn` prints a full backtrace when that happen; `warn-nobacktrace` is less verbose. `hide` hides the warning entirely. -* `-Zmiri-env-exclude=` keeps the `var` environment variable isolated from - the host so that it cannot be accessed by the program. Can be used multiple - times to exclude several variables. On Windows, the `TERM` environment - variable is excluded by default. +* `-Zmiri-env-exclude=` keeps the `var` environment variable isolated from the host so that it + cannot be accessed by the program. Can be used multiple times to exclude several variables. On + Windows, the `TERM` environment variable is excluded by default. This has no effect unless + `-Zmiri-disable-validation` is also set. +* `-Zmiri-env-forward=` forwards the `var` environment variable to the interpreted program. Can + be used multiple times to forward several variables. This has no effect if + `-Zmiri-disable-validation` is set. * `-Zmiri-ignore-leaks` disables the memory leak checker, and also allows some remaining threads to exist when the main thread exits. * `-Zmiri-measureme=` enables `measureme` profiling for the interpreted program. diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 333ff6af889f6..dd7b0b54f4882 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -399,6 +399,11 @@ fn main() { .excluded_env_vars .push(arg.strip_prefix("-Zmiri-env-exclude=").unwrap().to_owned()); } + arg if arg.starts_with("-Zmiri-env-forward=") => { + miri_config + .forwarded_env_vars + .push(arg.strip_prefix("-Zmiri-env-forward=").unwrap().to_owned()); + } arg if arg.starts_with("-Zmiri-track-pointer-tag=") => { let id: u64 = match arg.strip_prefix("-Zmiri-track-pointer-tag=").unwrap().parse() { diff --git a/src/eval.rs b/src/eval.rs index e2e85e3e75721..97856d92020b2 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -86,6 +86,8 @@ pub struct MiriConfig { pub ignore_leaks: bool, /// Environment variables that should always be isolated from the host. pub excluded_env_vars: Vec, + /// Environment variables that should always be forwarded from the host. + pub forwarded_env_vars: Vec, /// Command-line arguments passed to the interpreted program. pub args: Vec, /// The seed to use when non-determinism or randomness are required (e.g. ptr-to-int cast, `getrandom()`). @@ -122,6 +124,7 @@ impl Default for MiriConfig { isolated_op: IsolatedOp::Reject(RejectOpWith::Abort), ignore_leaks: false, excluded_env_vars: vec![], + forwarded_env_vars: vec![], args: vec![], seed: None, tracked_pointer_tag: None, @@ -157,7 +160,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( MemoryExtra::new(&config), ); // Complete initialization. - EnvVars::init(&mut ecx, config.excluded_env_vars)?; + EnvVars::init(&mut ecx, config.excluded_env_vars, config.forwarded_env_vars)?; MemoryExtra::init_extern_statics(&mut ecx)?; // Make sure we have MIR. We check MIR for some stable monomorphic function in libcore. diff --git a/src/shims/env.rs b/src/shims/env.rs index 4d297fd935d53..59fd16912a22c 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -39,6 +39,7 @@ impl<'tcx> EnvVars<'tcx> { pub(crate) fn init<'mir>( ecx: &mut InterpCx<'mir, 'tcx, Evaluator<'mir, 'tcx>>, mut excluded_env_vars: Vec, + forwarded_env_vars: Vec, ) -> InterpResult<'tcx> { let target_os = ecx.tcx.sess.target.os.as_str(); if target_os == "windows" { @@ -47,9 +48,14 @@ impl<'tcx> EnvVars<'tcx> { excluded_env_vars.push("TERM".to_owned()); } - if ecx.machine.communicate() { + // Skip the loop entirely if we don't want to forward anything. + if ecx.machine.communicate() || !forwarded_env_vars.is_empty() { for (name, value) in env::vars() { - if !excluded_env_vars.contains(&name) { + let forward = match ecx.machine.communicate() { + true => !excluded_env_vars.contains(&name), + false => forwarded_env_vars.contains(&name), + }; + if forward { let var_ptr = match target_os { "linux" | "macos" => alloc_env_var_as_c_str(name.as_ref(), value.as_ref(), ecx)?, diff --git a/tests/run-pass/env-forward.rs b/tests/run-pass/env-forward.rs new file mode 100644 index 0000000000000..8eebc45f55a71 --- /dev/null +++ b/tests/run-pass/env-forward.rs @@ -0,0 +1,5 @@ +// compile-flags: -Zmiri-env-forward=MIRI_ENV_VAR_TEST + +fn main() { + assert_eq!(std::env::var("MIRI_ENV_VAR_TEST"), Ok("0".to_owned())); +} From ceec2b3cebab9072beccd65c678b5bc51f830b5d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 5 Mar 2022 11:13:32 -0500 Subject: [PATCH 2906/3747] avoid env var forwarding logic panicking for non-UTF-8 env vars --- src/shims/env.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/shims/env.rs b/src/shims/env.rs index 59fd16912a22c..dfd1ef207d96a 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -50,10 +50,10 @@ impl<'tcx> EnvVars<'tcx> { // Skip the loop entirely if we don't want to forward anything. if ecx.machine.communicate() || !forwarded_env_vars.is_empty() { - for (name, value) in env::vars() { + for (name, value) in env::vars_os() { let forward = match ecx.machine.communicate() { - true => !excluded_env_vars.contains(&name), - false => forwarded_env_vars.contains(&name), + true => !excluded_env_vars.iter().any(|v| v.as_str() == &name), + false => forwarded_env_vars.iter().any(|v| v.as_str() == &name), }; if forward { let var_ptr = match target_os { From 90207a548481b1abac9fc28c8f8f03897789e6fa Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 5 Mar 2022 13:30:16 -0500 Subject: [PATCH 2907/3747] implement missing SIMD comparison operators, simd_xor, and simd_reduce_all --- src/shims/intrinsics.rs | 57 ++++++++++++++++++++++++--------- tests/run-pass/portable-simd.rs | 48 +++++++++++++++++++++------ 2 files changed, 80 insertions(+), 25 deletions(-) diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index f713721f58409..5bebc52b78285 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -356,7 +356,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "simd_shr" | "simd_and" | "simd_or" - | "simd_eq" => { + | "simd_xor" + | "simd_eq" + | "simd_ne" + | "simd_lt" + | "simd_le" + | "simd_gt" + | "simd_ge" => { + use mir::BinOp; + let &[ref left, ref right] = check_arg_count(args)?; let (left, left_len) = this.operand_to_simd(left)?; let (right, right_len) = this.operand_to_simd(right)?; @@ -366,16 +374,22 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx assert_eq!(dest_len, right_len); let op = match intrinsic_name { - "simd_add" => mir::BinOp::Add, - "simd_sub" => mir::BinOp::Sub, - "simd_mul" => mir::BinOp::Mul, - "simd_div" => mir::BinOp::Div, - "simd_rem" => mir::BinOp::Rem, - "simd_shl" => mir::BinOp::Shl, - "simd_shr" => mir::BinOp::Shr, - "simd_and" => mir::BinOp::BitAnd, - "simd_or" => mir::BinOp::BitOr, - "simd_eq" => mir::BinOp::Eq, + "simd_add" => BinOp::Add, + "simd_sub" => BinOp::Sub, + "simd_mul" => BinOp::Mul, + "simd_div" => BinOp::Div, + "simd_rem" => BinOp::Rem, + "simd_shl" => BinOp::Shl, + "simd_shr" => BinOp::Shr, + "simd_and" => BinOp::BitAnd, + "simd_or" => BinOp::BitOr, + "simd_xor" => BinOp::BitXor, + "simd_eq" => BinOp::Eq, + "simd_ne" => BinOp::Ne, + "simd_lt" => BinOp::Lt, + "simd_le" => BinOp::Le, + "simd_gt" => BinOp::Gt, + "simd_ge" => BinOp::Ge, _ => unreachable!(), }; @@ -384,7 +398,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let right = this.read_immediate(&this.mplace_index(&right, i)?.into())?; let dest = this.mplace_index(&dest, i)?; let (val, overflowed, ty) = this.overflowing_binary_op(op, &left, &right)?; - if matches!(op, mir::BinOp::Shl | mir::BinOp::Shr) { + if matches!(op, BinOp::Shl | BinOp::Shr) { // Shifts have extra UB as SIMD operations that the MIR binop does not have. // See . if overflowed { @@ -392,27 +406,38 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx throw_ub_format!("overflowing shift by {} in `{}` in SIMD lane {}", r_val, intrinsic_name, i); } } - if matches!(op, mir::BinOp::Eq) { + if matches!(op, BinOp::Eq | BinOp::Ne | BinOp::Lt | BinOp::Le | BinOp::Gt | BinOp::Ge) { // Special handling for boolean-returning operations assert_eq!(ty, this.tcx.types.bool); let val = val.to_bool().unwrap(); let val = bool_to_simd_element(val, dest.layout.size); this.write_scalar(val, &dest.into())?; } else { + assert_ne!(ty, this.tcx.types.bool); assert_eq!(ty, dest.layout.ty); this.write_scalar(val, &dest.into())?; } } } - "simd_reduce_any" => { + "simd_reduce_any" | "simd_reduce_all" => { let &[ref op] = check_arg_count(args)?; let (op, op_len) = this.operand_to_simd(op)?; - let mut res = false; // the neutral element + // the neutral element + let mut res = match intrinsic_name { + "simd_reduce_any" => false, + "simd_reduce_all" => true, + _ => bug!(), + }; + for i in 0..op_len { let op = this.read_immediate(&this.mplace_index(&op, i)?.into())?; let val = simd_element_to_bool(op)?; - res = res | val; + res = match intrinsic_name { + "simd_reduce_any" => res | val, + "simd_reduce_all" => res & val, + _ => bug!(), + }; } this.write_scalar(Scalar::from_bool(res), dest)?; diff --git a/tests/run-pass/portable-simd.rs b/tests/run-pass/portable-simd.rs index c0c1ecd0235aa..d43e7be8b1921 100644 --- a/tests/run-pass/portable-simd.rs +++ b/tests/run-pass/portable-simd.rs @@ -12,6 +12,14 @@ fn simd_ops_f32() { assert_eq!(a / f32x4::splat(2.0), f32x4::splat(5.0)); assert_eq!(a % b, f32x4::from_array([0.0, 0.0, 1.0, 2.0])); assert_eq!(b.abs(), f32x4::from_array([1.0, 2.0, 3.0, 4.0])); + + // FIXME use Mask::from_array once simd_cast is implemented. + assert_eq!(a.lanes_eq(f32x4::splat(5.0)*b), Mask::from_int(i32x4::from_array([0, -1, 0, 0]))); + assert_eq!(a.lanes_ne(f32x4::splat(5.0)*b), Mask::from_int(i32x4::from_array([-1, 0, -1, -1]))); + assert_eq!(a.lanes_le(f32x4::splat(5.0)*b), Mask::from_int(i32x4::from_array([0, -1, -1, 0]))); + assert_eq!(a.lanes_lt(f32x4::splat(5.0)*b), Mask::from_int(i32x4::from_array([0, 0, -1, 0]))); + assert_eq!(a.lanes_ge(f32x4::splat(5.0)*b), Mask::from_int(i32x4::from_array([-1, -1, 0, -1]))); + assert_eq!(a.lanes_gt(f32x4::splat(5.0)*b), Mask::from_int(i32x4::from_array([-1, 0, 0, -1]))); } fn simd_ops_f64() { @@ -25,30 +33,48 @@ fn simd_ops_f64() { assert_eq!(a / f64x4::splat(2.0), f64x4::splat(5.0)); assert_eq!(a % b, f64x4::from_array([0.0, 0.0, 1.0, 2.0])); assert_eq!(b.abs(), f64x4::from_array([1.0, 2.0, 3.0, 4.0])); + + // FIXME use Mask::from_array once simd_cast is implemented. + assert_eq!(a.lanes_eq(f64x4::splat(5.0)*b), Mask::from_int(i64x4::from_array([0, -1, 0, 0]))); + assert_eq!(a.lanes_ne(f64x4::splat(5.0)*b), Mask::from_int(i64x4::from_array([-1, 0, -1, -1]))); + assert_eq!(a.lanes_le(f64x4::splat(5.0)*b), Mask::from_int(i64x4::from_array([0, -1, -1, 0]))); + assert_eq!(a.lanes_lt(f64x4::splat(5.0)*b), Mask::from_int(i64x4::from_array([0, 0, -1, 0]))); + assert_eq!(a.lanes_ge(f64x4::splat(5.0)*b), Mask::from_int(i64x4::from_array([-1, -1, 0, -1]))); + assert_eq!(a.lanes_gt(f64x4::splat(5.0)*b), Mask::from_int(i64x4::from_array([-1, 0, 0, -1]))); } fn simd_ops_i32() { let a = i32x4::splat(10); - let b = i32x4::from_array([1, 2, 3, 4]); - assert_eq!(-b, i32x4::from_array([-1, -2, -3, -4])); - assert_eq!(a + b, i32x4::from_array([11, 12, 13, 14])); - assert_eq!(a - b, i32x4::from_array([9, 8, 7, 6])); - assert_eq!(a * b, i32x4::from_array([10, 20, 30, 40])); - assert_eq!(a / b, i32x4::from_array([10, 5, 3, 2])); + let b = i32x4::from_array([1, 2, 3, -4]); + assert_eq!(-b, i32x4::from_array([-1, -2, -3, 4])); + assert_eq!(a + b, i32x4::from_array([11, 12, 13, 6])); + assert_eq!(a - b, i32x4::from_array([9, 8, 7, 14])); + assert_eq!(a * b, i32x4::from_array([10, 20, 30, -40])); + assert_eq!(a / b, i32x4::from_array([10, 5, 3, -2])); assert_eq!(a / i32x4::splat(2), i32x4::splat(5)); assert_eq!(i32x2::splat(i32::MIN) / i32x2::splat(-1), i32x2::splat(i32::MIN)); assert_eq!(a % b, i32x4::from_array([0, 0, 1, 2])); assert_eq!(i32x2::splat(i32::MIN) % i32x2::splat(-1), i32x2::splat(0)); - assert_eq!(b << i32x4::splat(2), i32x4::from_array([4, 8, 12, 16])); - assert_eq!(b >> i32x4::splat(1), i32x4::from_array([0, 1, 1, 2])); + assert_eq!(b << i32x4::splat(2), i32x4::from_array([4, 8, 12, -16])); + assert_eq!(b >> i32x4::splat(1), i32x4::from_array([0, 1, 1, -2])); assert_eq!(b & i32x4::splat(2), i32x4::from_array([0, 2, 2, 0])); - assert_eq!(b | i32x4::splat(2), i32x4::from_array([3, 2, 3, 6])); + assert_eq!(b | i32x4::splat(2), i32x4::from_array([3, 2, 3, -2])); + assert_eq!(b ^ i32x4::splat(2), i32x4::from_array([3, 0, 1, -2])); + + // FIXME use Mask::from_array once simd_cast is implemented. + assert_eq!(a.lanes_eq(i32x4::splat(5)*b), Mask::from_int(i32x4::from_array([0, -1, 0, 0]))); + assert_eq!(a.lanes_ne(i32x4::splat(5)*b), Mask::from_int(i32x4::from_array([-1, 0, -1, -1]))); + assert_eq!(a.lanes_le(i32x4::splat(5)*b), Mask::from_int(i32x4::from_array([0, -1, -1, 0]))); + assert_eq!(a.lanes_lt(i32x4::splat(5)*b), Mask::from_int(i32x4::from_array([0, 0, -1, 0]))); + assert_eq!(a.lanes_ge(i32x4::splat(5)*b), Mask::from_int(i32x4::from_array([-1, -1, 0, -1]))); + assert_eq!(a.lanes_gt(i32x4::splat(5)*b), Mask::from_int(i32x4::from_array([-1, 0, 0, -1]))); } fn simd_intrinsics() { extern "platform-intrinsic" { fn simd_eq(x: T, y: T) -> U; fn simd_reduce_any(x: T) -> bool; + fn simd_reduce_all(x: T) -> bool; fn simd_select(m: M, yes: T, no: T) -> T; } unsafe { @@ -60,6 +86,10 @@ fn simd_intrinsics() { assert!(!simd_reduce_any(i32x4::splat(0))); assert!(simd_reduce_any(i32x4::splat(-1))); + assert!(simd_reduce_any(i32x2::from_array([0, -1]))); + assert!(!simd_reduce_all(i32x4::splat(0))); + assert!(simd_reduce_all(i32x4::splat(-1))); + assert!(!simd_reduce_all(i32x2::from_array([0, -1]))); assert_eq!(simd_select(i8x4::from_array([0, -1, -1, 0]), a, b), i32x4::from_array([1, 10, 10, 4])); assert_eq!(simd_select(i8x4::from_array([0, -1, -1, 0]), b, a), i32x4::from_array([10, 2, 10, 10])); From ec0e513c6433db787cff2b1b2f09886e9cfa7e76 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 5 Mar 2022 17:26:32 -0500 Subject: [PATCH 2908/3747] rustup --- rust-version | 2 +- .../{available-concurrency.rs => available-parallelism.rs} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename tests/run-pass/{available-concurrency.rs => available-parallelism.rs} (100%) diff --git a/rust-version b/rust-version index 56281423c5279..0742c61789582 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -45660949132222ba7ec0905649b2affd68e0e13c +c274e4969f058b1c644243181ece9f829efa7594 diff --git a/tests/run-pass/available-concurrency.rs b/tests/run-pass/available-parallelism.rs similarity index 100% rename from tests/run-pass/available-concurrency.rs rename to tests/run-pass/available-parallelism.rs From 8e97599af47ba3a1e4ed2185b8d0dddd9c69f0dd Mon Sep 17 00:00:00 2001 From: asquared31415 <34665709+asquared31415@users.noreply.github.com> Date: Sat, 5 Feb 2022 20:41:29 -0500 Subject: [PATCH 2909/3747] allow varargs for libc::open when it is allowed by the second argument --- src/shims/posix/foreign_items.rs | 5 +- src/shims/posix/fs.rs | 41 +++++++---- .../fs/unix_open_missing_required_mode.rs | 16 +++++ .../fs/unix_open_too_many_args.rs | 16 +++++ tests/run-pass/fs.rs | 69 +++++++++++++++---- 5 files changed, 117 insertions(+), 30 deletions(-) create mode 100644 tests/compile-fail/fs/unix_open_missing_required_mode.rs create mode 100644 tests/compile-fail/fs/unix_open_too_many_args.rs diff --git a/src/shims/posix/foreign_items.rs b/src/shims/posix/foreign_items.rs index 83b4032cd98a5..02fb7089c34db 100644 --- a/src/shims/posix/foreign_items.rs +++ b/src/shims/posix/foreign_items.rs @@ -55,8 +55,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // File related shims "open" | "open64" => { - let &[ref path, ref flag, ref mode] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; - let result = this.open(path, flag, mode)?; + // `open` is variadic, the third argument is only present when the second argument has O_CREAT (or on linux O_TMPFILE, but miri doesn't support that) set + this.check_abi_and_shim_symbol_clash(abi, Abi::C { unwind: false }, link_name)?; + let result = this.open(args)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "fcntl" => { diff --git a/src/shims/posix/fs.rs b/src/shims/posix/fs.rs index 36c076037708d..7956cfe4dcef3 100644 --- a/src/shims/posix/fs.rs +++ b/src/shims/posix/fs.rs @@ -474,23 +474,18 @@ fn maybe_sync_file( impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { - fn open( - &mut self, - path_op: &OpTy<'tcx, Tag>, - flag_op: &OpTy<'tcx, Tag>, - mode_op: &OpTy<'tcx, Tag>, - ) -> InterpResult<'tcx, i32> { - let this = self.eval_context_mut(); + fn open(&mut self, args: &[OpTy<'tcx, Tag>]) -> InterpResult<'tcx, i32> { + if args.len() < 2 || args.len() > 3 { + throw_ub_format!( + "incorrect number of arguments for `open`: got {}, expected 2 or 3", + args.len() + ); + } - let flag = this.read_scalar(flag_op)?.to_i32()?; + let this = self.eval_context_mut(); - // Get the mode. On macOS, the argument type `mode_t` is actually `u16`, but - // C integer promotion rules mean that on the ABI level, it gets passed as `u32` - // (see https://github.com/rust-lang/rust/issues/71915). - let mode = this.read_scalar(mode_op)?.to_u32()?; - if mode != 0o666 { - throw_unsup_format!("non-default mode 0o{:o} is not supported", mode); - } + let path_op = &args[0]; + let flag = this.read_scalar(&args[1])?.to_i32()?; let mut options = OpenOptions::new(); @@ -535,6 +530,22 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } let o_creat = this.eval_libc_i32("O_CREAT")?; if flag & o_creat != 0 { + // Get the mode. On macOS, the argument type `mode_t` is actually `u16`, but + // C integer promotion rules mean that on the ABI level, it gets passed as `u32` + // (see https://github.com/rust-lang/rust/issues/71915). + let mode = if let Some(arg) = args.get(2) { + this.read_scalar(arg)?.to_u32()? + } else { + throw_ub_format!( + "incorrect number of arguments for `open` with `O_CREAT`: got {}, expected 3", + args.len() + ); + }; + + if mode != 0o666 { + throw_unsup_format!("non-default mode 0o{:o} is not supported", mode); + } + mirror |= o_creat; let o_excl = this.eval_libc_i32("O_EXCL")?; diff --git a/tests/compile-fail/fs/unix_open_missing_required_mode.rs b/tests/compile-fail/fs/unix_open_missing_required_mode.rs new file mode 100644 index 0000000000000..2bac72912544a --- /dev/null +++ b/tests/compile-fail/fs/unix_open_missing_required_mode.rs @@ -0,0 +1,16 @@ +// ignore-windows: No libc on Windows +// compile-flags: -Zmiri-disable-isolation + +#![feature(rustc_private)] + +extern crate libc; + +fn main() { + test_file_open_missing_needed_mode(); +} + +fn test_file_open_missing_needed_mode() { + let name = b"missing_arg.txt\0"; + let name_ptr = name.as_ptr().cast::(); + let _fd = unsafe { libc::open(name_ptr, libc::O_CREAT) }; //~ ERROR Undefined Behavior: incorrect number of arguments for `open` with `O_CREAT`: got 2, expected 3 +} diff --git a/tests/compile-fail/fs/unix_open_too_many_args.rs b/tests/compile-fail/fs/unix_open_too_many_args.rs new file mode 100644 index 0000000000000..9df7415d3133a --- /dev/null +++ b/tests/compile-fail/fs/unix_open_too_many_args.rs @@ -0,0 +1,16 @@ +// ignore-windows: No libc on Windows +// compile-flags: -Zmiri-disable-isolation + +#![feature(rustc_private)] + +extern crate libc; + +fn main() { + test_open_too_many_args(); +} + +fn test_open_too_many_args() { + let name = b"too_many_args.txt\0"; + let name_ptr = name.as_ptr().cast::(); + let _fd = unsafe { libc::open(name_ptr, libc::O_RDONLY, 0, 0) }; //~ ERROR Undefined Behavior: incorrect number of arguments for `open`: got 4, expected 2 or 3 +} diff --git a/tests/run-pass/fs.rs b/tests/run-pass/fs.rs index 568b7ab4e3b7a..9ab1d4c033839 100644 --- a/tests/run-pass/fs.rs +++ b/tests/run-pass/fs.rs @@ -5,13 +5,10 @@ extern crate libc; -use std::fs::{ - File, create_dir, OpenOptions, remove_dir, remove_dir_all, remove_file, rename, -}; use std::ffi::CString; -use std::io::{Read, Write, Error, ErrorKind, Result, Seek, SeekFrom}; -use std::path::{PathBuf, Path}; - +use std::fs::{create_dir, remove_dir, remove_dir_all, remove_file, rename, File, OpenOptions}; +use std::io::{Error, ErrorKind, Read, Result, Seek, SeekFrom, Write}; +use std::path::{Path, PathBuf}; fn main() { test_file(); @@ -26,6 +23,11 @@ fn main() { test_rename(); test_directory(); test_dup_stdout_stderr(); + + // These all require unix, if the test is changed to no longer `ignore-windows`, move these to a unix test + test_file_open_unix_allow_two_args(); + test_file_open_unix_needs_three_args(); + test_file_open_unix_extra_third_arg(); } fn tmp() -> PathBuf { @@ -41,7 +43,8 @@ fn tmp() -> PathBuf { #[cfg(not(windows))] return PathBuf::from(tmp.replace("\\", "/")); - }).unwrap_or_else(|_| std::env::temp_dir()) + }) + .unwrap_or_else(|_| std::env::temp_dir()) } /// Prepare: compute filename and make sure the file does not exist. @@ -93,6 +96,39 @@ fn test_file() { remove_file(&path).unwrap(); } +fn test_file_open_unix_allow_two_args() { + use std::os::unix::ffi::OsStrExt; + + let path = prepare_with_content("test_file_open_unix_allow_two_args.txt", &[]); + + let mut name = path.into_os_string(); + name.push("\0"); + let name_ptr = name.as_bytes().as_ptr().cast::(); + let _fd = unsafe { libc::open(name_ptr, libc::O_RDONLY) }; +} + +fn test_file_open_unix_needs_three_args() { + use std::os::unix::ffi::OsStrExt; + + let path = prepare_with_content("test_file_open_unix_needs_three_args.txt", &[]); + + let mut name = path.into_os_string(); + name.push("\0"); + let name_ptr = name.as_bytes().as_ptr().cast::(); + let _fd = unsafe { libc::open(name_ptr, libc::O_CREAT, 0o666) }; +} + +fn test_file_open_unix_extra_third_arg() { + use std::os::unix::ffi::OsStrExt; + + let path = prepare_with_content("test_file_open_unix_extra_third_arg.txt", &[]); + + let mut name = path.into_os_string(); + name.push("\0"); + let name_ptr = name.as_bytes().as_ptr().cast::(); + let _fd = unsafe { libc::open(name_ptr, libc::O_RDONLY, 42) }; +} + fn test_file_clone() { let bytes = b"Hello, World!\n"; let path = prepare_with_content("miri_test_fs_file_clone.txt", bytes); @@ -115,7 +151,10 @@ fn test_file_create_new() { // Creating a new file that doesn't yet exist should succeed. OpenOptions::new().write(true).create_new(true).open(&path).unwrap(); // Creating a new file that already exists should fail. - assert_eq!(ErrorKind::AlreadyExists, OpenOptions::new().write(true).create_new(true).open(&path).unwrap_err().kind()); + assert_eq!( + ErrorKind::AlreadyExists, + OpenOptions::new().write(true).create_new(true).open(&path).unwrap_err().kind() + ); // Optionally creating a new file that already exists should succeed. OpenOptions::new().write(true).create(true).open(&path).unwrap(); @@ -235,7 +274,6 @@ fn test_symlink() { symlink_file.read_to_end(&mut contents).unwrap(); assert_eq!(bytes, contents.as_slice()); - #[cfg(unix)] { use std::os::unix::ffi::OsStrExt; @@ -250,7 +288,9 @@ fn test_symlink() { // Make the buf one byte larger than it needs to be, // and check that the last byte is not overwritten. let mut large_buf = vec![0xFF; expected_path.len() + 1]; - let res = unsafe { libc::readlink(symlink_c_ptr, large_buf.as_mut_ptr().cast(), large_buf.len()) }; + let res = unsafe { + libc::readlink(symlink_c_ptr, large_buf.as_mut_ptr().cast(), large_buf.len()) + }; // Check that the resovled path was properly written into the buf. assert_eq!(&large_buf[..(large_buf.len() - 1)], expected_path); assert_eq!(large_buf.last(), Some(&0xFF)); @@ -259,18 +299,21 @@ fn test_symlink() { // Test that the resolved path is truncated if the provided buffer // is too small. let mut small_buf = [0u8; 2]; - let res = unsafe { libc::readlink(symlink_c_ptr, small_buf.as_mut_ptr().cast(), small_buf.len()) }; + let res = unsafe { + libc::readlink(symlink_c_ptr, small_buf.as_mut_ptr().cast(), small_buf.len()) + }; assert_eq!(small_buf, &expected_path[..small_buf.len()]); assert_eq!(res, small_buf.len() as isize); // Test that we report a proper error for a missing path. let bad_path = CString::new("MIRI_MISSING_FILE_NAME").unwrap(); - let res = unsafe { libc::readlink(bad_path.as_ptr(), small_buf.as_mut_ptr().cast(), small_buf.len()) }; + let res = unsafe { + libc::readlink(bad_path.as_ptr(), small_buf.as_mut_ptr().cast(), small_buf.len()) + }; assert_eq!(res, -1); assert_eq!(Error::last_os_error().kind(), ErrorKind::NotFound); } - // Test that metadata of a symbolic link is correct. check_metadata(bytes, &symlink_path).unwrap(); // Test that the metadata of a symbolic link is correct when not following it. From 3ed8ad4423684a006e8db194c91f585798b500ab Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 5 Mar 2022 18:46:14 -0500 Subject: [PATCH 2910/3747] avoid repeated string matching, and add more simd_reduce intrinsics --- src/machine.rs | 2 ++ src/shims/intrinsics.rs | 62 ++++++++++++++++++++++++--------- tests/run-pass/portable-simd.rs | 7 ++++ 3 files changed, 55 insertions(+), 16 deletions(-) diff --git a/src/machine.rs b/src/machine.rs index a75ac844902fc..481808dc78197 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -267,6 +267,7 @@ pub struct PrimitiveLayouts<'tcx> { pub u8: TyAndLayout<'tcx>, pub u32: TyAndLayout<'tcx>, pub usize: TyAndLayout<'tcx>, + pub bool: TyAndLayout<'tcx>, } impl<'mir, 'tcx: 'mir> PrimitiveLayouts<'tcx> { @@ -279,6 +280,7 @@ impl<'mir, 'tcx: 'mir> PrimitiveLayouts<'tcx> { u8: layout_cx.layout_of(layout_cx.tcx.types.u8)?, u32: layout_cx.layout_of(layout_cx.tcx.types.u32)?, usize: layout_cx.layout_of(layout_cx.tcx.types.usize)?, + bool: layout_cx.layout_of(layout_cx.tcx.types.bool)?, }) } } diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 5bebc52b78285..532eb08b191b0 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -324,12 +324,22 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx assert_eq!(dest_len, op_len); + enum Op { + MirOp(mir::UnOp), + Abs, + } + let which = match intrinsic_name { + "simd_neg" => Op::MirOp(mir::UnOp::Neg), + "simd_fabs" => Op::Abs, + _ => unreachable!(), + }; + for i in 0..dest_len { let op = this.read_immediate(&this.mplace_index(&op, i)?.into())?; let dest = this.mplace_index(&dest, i)?; - let val = match intrinsic_name { - "simd_neg" => this.unary_op(mir::UnOp::Neg, &op)?.to_scalar()?, - "simd_fabs" => { + let val = match which { + Op::MirOp(mir_op) => this.unary_op(mir_op, &op)?.to_scalar()?, + Op::Abs => { // Works for f32 and f64. let ty::Float(float_ty) = op.layout.ty.kind() else { bug!("simd_fabs operand is not a float") @@ -341,7 +351,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx FloatTy::F64 => Scalar::from_f64(op.to_f64()?.abs()), } } - _ => bug!(), }; this.write_scalar(val, &dest.into())?; } @@ -419,28 +428,49 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } } - "simd_reduce_any" | "simd_reduce_all" => { + #[rustfmt::skip] + | "simd_reduce_and" + | "simd_reduce_or" + | "simd_reduce_xor" + | "simd_reduce_any" + | "simd_reduce_all" => { + use mir::BinOp; + let &[ref op] = check_arg_count(args)?; let (op, op_len) = this.operand_to_simd(op)?; - // the neutral element - let mut res = match intrinsic_name { - "simd_reduce_any" => false, - "simd_reduce_all" => true, - _ => bug!(), + let imm_from_bool = + |b| ImmTy::from_scalar(Scalar::from_bool(b), this.machine.layouts.bool); + + enum Op { + MirOp(BinOp), + MirOpBool(BinOp), + } + // The initial value is the neutral element. + let (which, init) = match intrinsic_name { + "simd_reduce_and" => (Op::MirOp(BinOp::BitAnd), ImmTy::from_int(-1, dest.layout)), + "simd_reduce_or" => (Op::MirOp(BinOp::BitOr), ImmTy::from_int(0, dest.layout)), + "simd_reduce_xor" => (Op::MirOp(BinOp::BitXor), ImmTy::from_int(0, dest.layout)), + "simd_reduce_any" => (Op::MirOpBool(BinOp::BitOr), imm_from_bool(false)), + "simd_reduce_all" => (Op::MirOpBool(BinOp::BitAnd), imm_from_bool(true)), + _ => unreachable!(), }; + let mut res = init; for i in 0..op_len { let op = this.read_immediate(&this.mplace_index(&op, i)?.into())?; - let val = simd_element_to_bool(op)?; - res = match intrinsic_name { - "simd_reduce_any" => res | val, - "simd_reduce_all" => res & val, - _ => bug!(), + res = match which { + Op::MirOp(mir_op) => { + this.binary_op(mir_op, &res, &op)? + } + Op::MirOpBool(mir_op) => { + let op = imm_from_bool(simd_element_to_bool(op)?); + this.binary_op(mir_op, &res, &op)? + } }; } - this.write_scalar(Scalar::from_bool(res), dest)?; + this.write_immediate(*res, dest)?; } "simd_select" => { let &[ref mask, ref yes, ref no] = check_arg_count(args)?; diff --git a/tests/run-pass/portable-simd.rs b/tests/run-pass/portable-simd.rs index d43e7be8b1921..ef8a5752b7cc7 100644 --- a/tests/run-pass/portable-simd.rs +++ b/tests/run-pass/portable-simd.rs @@ -68,6 +68,13 @@ fn simd_ops_i32() { assert_eq!(a.lanes_lt(i32x4::splat(5)*b), Mask::from_int(i32x4::from_array([0, 0, -1, 0]))); assert_eq!(a.lanes_ge(i32x4::splat(5)*b), Mask::from_int(i32x4::from_array([-1, -1, 0, -1]))); assert_eq!(a.lanes_gt(i32x4::splat(5)*b), Mask::from_int(i32x4::from_array([-1, 0, 0, -1]))); + + assert_eq!(a.horizontal_and(), 10); + assert_eq!(b.horizontal_and(), 0); + assert_eq!(a.horizontal_or(), 10); + assert_eq!(b.horizontal_or(), -1); + assert_eq!(a.horizontal_xor(), 0); + assert_eq!(b.horizontal_xor(), -4); } fn simd_intrinsics() { From b491b72673e0b6ae43ce7e14195082537749cc24 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 5 Mar 2022 19:02:00 -0500 Subject: [PATCH 2911/3747] implement simd_reduce_{add,mul} --- src/shims/intrinsics.rs | 29 +++++++++++++++++++++++++---- tests/run-pass/portable-simd.rs | 4 ++++ 2 files changed, 29 insertions(+), 4 deletions(-) diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 532eb08b191b0..670e3cb1b8acb 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -382,7 +382,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx assert_eq!(dest_len, left_len); assert_eq!(dest_len, right_len); - let op = match intrinsic_name { + let mir_op = match intrinsic_name { "simd_add" => BinOp::Add, "simd_sub" => BinOp::Sub, "simd_mul" => BinOp::Mul, @@ -406,8 +406,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let left = this.read_immediate(&this.mplace_index(&left, i)?.into())?; let right = this.read_immediate(&this.mplace_index(&right, i)?.into())?; let dest = this.mplace_index(&dest, i)?; - let (val, overflowed, ty) = this.overflowing_binary_op(op, &left, &right)?; - if matches!(op, BinOp::Shl | BinOp::Shr) { + let (val, overflowed, ty) = this.overflowing_binary_op(mir_op, &left, &right)?; + if matches!(mir_op, BinOp::Shl | BinOp::Shr) { // Shifts have extra UB as SIMD operations that the MIR binop does not have. // See . if overflowed { @@ -415,7 +415,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx throw_ub_format!("overflowing shift by {} in `{}` in SIMD lane {}", r_val, intrinsic_name, i); } } - if matches!(op, BinOp::Eq | BinOp::Ne | BinOp::Lt | BinOp::Le | BinOp::Gt | BinOp::Ge) { + if matches!(mir_op, BinOp::Eq | BinOp::Ne | BinOp::Lt | BinOp::Le | BinOp::Gt | BinOp::Ge) { // Special handling for boolean-returning operations assert_eq!(ty, this.tcx.types.bool); let val = val.to_bool().unwrap(); @@ -469,7 +469,28 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } }; } + this.write_immediate(*res, dest)?; + } + #[rustfmt::skip] + | "simd_reduce_add_ordered" + | "simd_reduce_mul_ordered" => { + use mir::BinOp; + + let &[ref op, ref init] = check_arg_count(args)?; + let (op, op_len) = this.operand_to_simd(op)?; + let init = this.read_immediate(init)?; + let mir_op = match intrinsic_name { + "simd_reduce_add_ordered" => BinOp::Add, + "simd_reduce_mul_ordered" => BinOp::Mul, + _ => unreachable!(), + }; + + let mut res = init; + for i in 0..op_len { + let op = this.read_immediate(&this.mplace_index(&op, i)?.into())?; + res = this.binary_op(mir_op, &res, &op)?; + } this.write_immediate(*res, dest)?; } "simd_select" => { diff --git a/tests/run-pass/portable-simd.rs b/tests/run-pass/portable-simd.rs index ef8a5752b7cc7..9d1ca12a9f10e 100644 --- a/tests/run-pass/portable-simd.rs +++ b/tests/run-pass/portable-simd.rs @@ -75,6 +75,10 @@ fn simd_ops_i32() { assert_eq!(b.horizontal_or(), -1); assert_eq!(a.horizontal_xor(), 0); assert_eq!(b.horizontal_xor(), -4); + assert_eq!(a.horizontal_sum(), 40); + assert_eq!(b.horizontal_sum(), 2); + assert_eq!(a.horizontal_product(), 100*100); + assert_eq!(b.horizontal_product(), 6*-4); } fn simd_intrinsics() { From 9810a147a777e1cea91dd01a946fa6a0baf97e62 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 5 Mar 2022 22:59:23 -0500 Subject: [PATCH 2912/3747] add extra tests for shifts with negative offsets --- tests/run-pass/integer-ops.rs | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/tests/run-pass/integer-ops.rs b/tests/run-pass/integer-ops.rs index fde220d8f35e8..f5c1a7a5ff212 100644 --- a/tests/run-pass/integer-ops.rs +++ b/tests/run-pass/integer-ops.rs @@ -1,13 +1,24 @@ +// compile-flags: -Coverflow-checks=off #![allow(arithmetic_overflow)] pub fn main() { - // This tests that do (not) do sign extension properly when loading integers + // This tests that we do (not) do sign extension properly when loading integers assert_eq!(u32::MAX as i64, 4294967295); assert_eq!(i32::MIN as i64, -2147483648); assert_eq!(i8::MAX, 127); assert_eq!(i8::MIN, -128); + // Shifts with negative offsets are subtle. + assert_eq!(13 << -2i8, 13 << 254); + assert_eq!(13 << i8::MIN, 13); + assert_eq!(13 << -1i16, 13 << u16::MAX); + assert_eq!(13 << i16::MIN, 13); + assert_eq!(13i128 << -2i8, 13i128 << 254); + assert_eq!(13i128 << i8::MIN, 13); + assert_eq!(13i128 << -1i16, 13i128 << u16::MAX); + assert_eq!(13i128 << i16::MIN, 13); + assert_eq!(i32::from_str_radix("A", 16), Ok(10)); let n = -0b1000_0000i8; From 21d36ffd04b0472aebebd7cf447cac74c90d8b47 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 5 Mar 2022 23:03:14 -0500 Subject: [PATCH 2913/3747] also test f32/f64 simd_reduce --- tests/run-pass/portable-simd.rs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/tests/run-pass/portable-simd.rs b/tests/run-pass/portable-simd.rs index 9d1ca12a9f10e..5d7420604bb7a 100644 --- a/tests/run-pass/portable-simd.rs +++ b/tests/run-pass/portable-simd.rs @@ -20,6 +20,11 @@ fn simd_ops_f32() { assert_eq!(a.lanes_lt(f32x4::splat(5.0)*b), Mask::from_int(i32x4::from_array([0, 0, -1, 0]))); assert_eq!(a.lanes_ge(f32x4::splat(5.0)*b), Mask::from_int(i32x4::from_array([-1, -1, 0, -1]))); assert_eq!(a.lanes_gt(f32x4::splat(5.0)*b), Mask::from_int(i32x4::from_array([-1, 0, 0, -1]))); + + assert_eq!(a.horizontal_sum(), 40.0); + assert_eq!(b.horizontal_sum(), 2.0); + assert_eq!(a.horizontal_product(), 100.0*100.0); + assert_eq!(b.horizontal_product(), -24.0); } fn simd_ops_f64() { @@ -41,6 +46,11 @@ fn simd_ops_f64() { assert_eq!(a.lanes_lt(f64x4::splat(5.0)*b), Mask::from_int(i64x4::from_array([0, 0, -1, 0]))); assert_eq!(a.lanes_ge(f64x4::splat(5.0)*b), Mask::from_int(i64x4::from_array([-1, -1, 0, -1]))); assert_eq!(a.lanes_gt(f64x4::splat(5.0)*b), Mask::from_int(i64x4::from_array([-1, 0, 0, -1]))); + + assert_eq!(a.horizontal_sum(), 40.0); + assert_eq!(b.horizontal_sum(), 2.0); + assert_eq!(a.horizontal_product(), 100.0*100.0); + assert_eq!(b.horizontal_product(), -24.0); } fn simd_ops_i32() { @@ -78,7 +88,7 @@ fn simd_ops_i32() { assert_eq!(a.horizontal_sum(), 40); assert_eq!(b.horizontal_sum(), 2); assert_eq!(a.horizontal_product(), 100*100); - assert_eq!(b.horizontal_product(), 6*-4); + assert_eq!(b.horizontal_product(), -24); } fn simd_intrinsics() { From 594a70a28901efa14c8119242c5692027dbd8eb9 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 7 Mar 2022 09:39:32 -0500 Subject: [PATCH 2914/3747] rustup --- rust-version | 2 +- src/thread.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/rust-version b/rust-version index 0742c61789582..109a8080b07f5 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -c274e4969f058b1c644243181ece9f829efa7594 +8876ca3dd46b99fe7e6ad937f11493d37996231e diff --git a/src/thread.rs b/src/thread.rs index a5deceb6e71dc..b2f2a8098de23 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -574,7 +574,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let allocation = tcx.eval_static_initializer(def_id)?; // Create a fresh allocation with this content. let new_alloc = - this.memory.allocate_with(allocation.clone(), MiriMemoryKind::Tls.into()); + this.memory.allocate_with(allocation.inner().clone(), MiriMemoryKind::Tls.into()); this.machine.threads.set_thread_local_alloc(def_id, new_alloc); Ok(new_alloc) } From db06d4998fa8e64c290a7ae439fb2f8aefb2223e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 6 Mar 2022 13:58:41 -0500 Subject: [PATCH 2915/3747] implement simd_cast, simd_as --- src/shims/intrinsics.rs | 39 +++++ .../intrinsics/simd-float-to-int.rs | 7 + tests/run-pass/portable-simd.rs | 141 ++++++++++++++---- 3 files changed, 161 insertions(+), 26 deletions(-) create mode 100644 tests/compile-fail/intrinsics/simd-float-to-int.rs diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 670e3cb1b8acb..2f29ec4553d48 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -515,6 +515,45 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_immediate(*val, &dest.into())?; } } + #[rustfmt::skip] + "simd_cast" | "simd_as" => { + let &[ref op] = check_arg_count(args)?; + let (op, op_len) = this.operand_to_simd(op)?; + let (dest, dest_len) = this.place_to_simd(dest)?; + + assert_eq!(dest_len, op_len); + + let safe_cast = intrinsic_name == "simd_as"; + + for i in 0..dest_len { + let op = this.read_immediate(&this.mplace_index(&op, i)?.into())?; + let dest = this.mplace_index(&dest, i)?; + + let val = match (op.layout.ty.kind(), dest.layout.ty.kind()) { + // Int-to-(int|float): always safe + (ty::Int(_) | ty::Uint(_), ty::Int(_) | ty::Uint(_) | ty::Float(_)) => + this.misc_cast(&op, dest.layout.ty)?, + // Float-to-float: always safe + (ty::Float(_), ty::Float(_)) => + this.misc_cast(&op, dest.layout.ty)?, + // Float-to-int in safe mode + (ty::Float(_), ty::Int(_) | ty::Uint(_)) if safe_cast => + this.misc_cast(&op, dest.layout.ty)?, + // Float-to-int in unchecked mode + (ty::Float(FloatTy::F32), ty::Int(_) | ty::Uint(_)) if !safe_cast => + this.float_to_int_unchecked(op.to_scalar()?.to_f32()?, dest.layout.ty)?.into(), + (ty::Float(FloatTy::F64), ty::Int(_) | ty::Uint(_)) if !safe_cast => + this.float_to_int_unchecked(op.to_scalar()?.to_f64()?, dest.layout.ty)?.into(), + _ => + throw_unsup_format!( + "Unsupported SIMD cast from element type {} to {}", + op.layout.ty, + dest.layout.ty + ), + }; + this.write_immediate(val, &dest.into())?; + } + } // Atomic operations "atomic_load" => this.atomic_load(args, dest, AtomicReadOp::SeqCst)?, diff --git a/tests/compile-fail/intrinsics/simd-float-to-int.rs b/tests/compile-fail/intrinsics/simd-float-to-int.rs new file mode 100644 index 0000000000000..88d5a7a466f02 --- /dev/null +++ b/tests/compile-fail/intrinsics/simd-float-to-int.rs @@ -0,0 +1,7 @@ +// error-pattern: cannot be represented in target type `i32` +#![feature(portable_simd)] +use std::simd::*; + +fn main() { unsafe { + let _x : i32x2 = f32x2::from_array([f32::MAX, f32::MIN]).to_int_unchecked(); +} } diff --git a/tests/run-pass/portable-simd.rs b/tests/run-pass/portable-simd.rs index 5d7420604bb7a..022e8c91f970d 100644 --- a/tests/run-pass/portable-simd.rs +++ b/tests/run-pass/portable-simd.rs @@ -13,17 +13,16 @@ fn simd_ops_f32() { assert_eq!(a % b, f32x4::from_array([0.0, 0.0, 1.0, 2.0])); assert_eq!(b.abs(), f32x4::from_array([1.0, 2.0, 3.0, 4.0])); - // FIXME use Mask::from_array once simd_cast is implemented. - assert_eq!(a.lanes_eq(f32x4::splat(5.0)*b), Mask::from_int(i32x4::from_array([0, -1, 0, 0]))); - assert_eq!(a.lanes_ne(f32x4::splat(5.0)*b), Mask::from_int(i32x4::from_array([-1, 0, -1, -1]))); - assert_eq!(a.lanes_le(f32x4::splat(5.0)*b), Mask::from_int(i32x4::from_array([0, -1, -1, 0]))); - assert_eq!(a.lanes_lt(f32x4::splat(5.0)*b), Mask::from_int(i32x4::from_array([0, 0, -1, 0]))); - assert_eq!(a.lanes_ge(f32x4::splat(5.0)*b), Mask::from_int(i32x4::from_array([-1, -1, 0, -1]))); - assert_eq!(a.lanes_gt(f32x4::splat(5.0)*b), Mask::from_int(i32x4::from_array([-1, 0, 0, -1]))); + assert_eq!(a.lanes_eq(f32x4::splat(5.0) * b), Mask::from_array([false, true, false, false])); + assert_eq!(a.lanes_ne(f32x4::splat(5.0) * b), Mask::from_array([true, false, true, true])); + assert_eq!(a.lanes_le(f32x4::splat(5.0) * b), Mask::from_array([false, true, true, false])); + assert_eq!(a.lanes_lt(f32x4::splat(5.0) * b), Mask::from_array([false, false, true, false])); + assert_eq!(a.lanes_ge(f32x4::splat(5.0) * b), Mask::from_array([true, true, false, true])); + assert_eq!(a.lanes_gt(f32x4::splat(5.0) * b), Mask::from_array([true, false, false, true])); assert_eq!(a.horizontal_sum(), 40.0); assert_eq!(b.horizontal_sum(), 2.0); - assert_eq!(a.horizontal_product(), 100.0*100.0); + assert_eq!(a.horizontal_product(), 100.0 * 100.0); assert_eq!(b.horizontal_product(), -24.0); } @@ -39,17 +38,16 @@ fn simd_ops_f64() { assert_eq!(a % b, f64x4::from_array([0.0, 0.0, 1.0, 2.0])); assert_eq!(b.abs(), f64x4::from_array([1.0, 2.0, 3.0, 4.0])); - // FIXME use Mask::from_array once simd_cast is implemented. - assert_eq!(a.lanes_eq(f64x4::splat(5.0)*b), Mask::from_int(i64x4::from_array([0, -1, 0, 0]))); - assert_eq!(a.lanes_ne(f64x4::splat(5.0)*b), Mask::from_int(i64x4::from_array([-1, 0, -1, -1]))); - assert_eq!(a.lanes_le(f64x4::splat(5.0)*b), Mask::from_int(i64x4::from_array([0, -1, -1, 0]))); - assert_eq!(a.lanes_lt(f64x4::splat(5.0)*b), Mask::from_int(i64x4::from_array([0, 0, -1, 0]))); - assert_eq!(a.lanes_ge(f64x4::splat(5.0)*b), Mask::from_int(i64x4::from_array([-1, -1, 0, -1]))); - assert_eq!(a.lanes_gt(f64x4::splat(5.0)*b), Mask::from_int(i64x4::from_array([-1, 0, 0, -1]))); + assert_eq!(a.lanes_eq(f64x4::splat(5.0) * b), Mask::from_array([false, true, false, false])); + assert_eq!(a.lanes_ne(f64x4::splat(5.0) * b), Mask::from_array([true, false, true, true])); + assert_eq!(a.lanes_le(f64x4::splat(5.0) * b), Mask::from_array([false, true, true, false])); + assert_eq!(a.lanes_lt(f64x4::splat(5.0) * b), Mask::from_array([false, false, true, false])); + assert_eq!(a.lanes_ge(f64x4::splat(5.0) * b), Mask::from_array([true, true, false, true])); + assert_eq!(a.lanes_gt(f64x4::splat(5.0) * b), Mask::from_array([true, false, false, true])); assert_eq!(a.horizontal_sum(), 40.0); assert_eq!(b.horizontal_sum(), 2.0); - assert_eq!(a.horizontal_product(), 100.0*100.0); + assert_eq!(a.horizontal_product(), 100.0 * 100.0); assert_eq!(b.horizontal_product(), -24.0); } @@ -71,13 +69,12 @@ fn simd_ops_i32() { assert_eq!(b | i32x4::splat(2), i32x4::from_array([3, 2, 3, -2])); assert_eq!(b ^ i32x4::splat(2), i32x4::from_array([3, 0, 1, -2])); - // FIXME use Mask::from_array once simd_cast is implemented. - assert_eq!(a.lanes_eq(i32x4::splat(5)*b), Mask::from_int(i32x4::from_array([0, -1, 0, 0]))); - assert_eq!(a.lanes_ne(i32x4::splat(5)*b), Mask::from_int(i32x4::from_array([-1, 0, -1, -1]))); - assert_eq!(a.lanes_le(i32x4::splat(5)*b), Mask::from_int(i32x4::from_array([0, -1, -1, 0]))); - assert_eq!(a.lanes_lt(i32x4::splat(5)*b), Mask::from_int(i32x4::from_array([0, 0, -1, 0]))); - assert_eq!(a.lanes_ge(i32x4::splat(5)*b), Mask::from_int(i32x4::from_array([-1, -1, 0, -1]))); - assert_eq!(a.lanes_gt(i32x4::splat(5)*b), Mask::from_int(i32x4::from_array([-1, 0, 0, -1]))); + assert_eq!(a.lanes_eq(i32x4::splat(5) * b), Mask::from_array([false, true, false, false])); + assert_eq!(a.lanes_ne(i32x4::splat(5) * b), Mask::from_array([true, false, true, true])); + assert_eq!(a.lanes_le(i32x4::splat(5) * b), Mask::from_array([false, true, true, false])); + assert_eq!(a.lanes_lt(i32x4::splat(5) * b), Mask::from_array([false, false, true, false])); + assert_eq!(a.lanes_ge(i32x4::splat(5) * b), Mask::from_array([true, true, false, true])); + assert_eq!(a.lanes_gt(i32x4::splat(5) * b), Mask::from_array([true, false, false, true])); assert_eq!(a.horizontal_and(), 10); assert_eq!(b.horizontal_and(), 0); @@ -87,10 +84,94 @@ fn simd_ops_i32() { assert_eq!(b.horizontal_xor(), -4); assert_eq!(a.horizontal_sum(), 40); assert_eq!(b.horizontal_sum(), 2); - assert_eq!(a.horizontal_product(), 100*100); + assert_eq!(a.horizontal_product(), 100 * 100); assert_eq!(b.horizontal_product(), -24); } +fn simd_mask() { + let intmask = Mask::from_int(i32x4::from_array([0, -1, 0, 0])); + assert_eq!(intmask, Mask::from_array([false, true, false, false])); + assert_eq!(intmask.to_array(), [false, true, false, false]); +} + +fn simd_cast() { + // between integer types + assert_eq!(i32x4::from_array([1, 2, 3, -4]), i16x4::from_array([1, 2, 3, -4]).cast()); + assert_eq!(i16x4::from_array([1, 2, 3, -4]), i32x4::from_array([1, 2, 3, -4]).cast()); + assert_eq!(i32x4::from_array([1, -1, 3, 4]), u64x4::from_array([1, u64::MAX, 3, 4]).cast()); + + // float -> int + assert_eq!( + i8x4::from_array([127, -128, 127, -128]), + f32x4::from_array([127.99, -128.99, 999.0, -999.0]).cast() + ); + assert_eq!( + i32x4::from_array([0, 1, -1, 2147483520]), + f32x4::from_array([ + -0.0, + /*0x1.19999ap+0*/ f32::from_bits(0x3f8ccccd), + /*-0x1.19999ap+0*/ f32::from_bits(0xbf8ccccd), + 2147483520.0 + ]) + .cast() + ); + assert_eq!( + i32x8::from_array([i32::MAX, i32::MIN, i32::MAX, i32::MIN, i32::MAX, i32::MIN, 0, 0]), + f32x8::from_array([ + 2147483648.0f32, + -2147483904.0f32, + f32::MAX, + f32::MIN, + f32::INFINITY, + f32::NEG_INFINITY, + f32::NAN, + -f32::NAN, + ]) + .cast() + ); + + // int -> float + assert_eq!( + f32x4::from_array([ + -2147483648.0, + /*0x1.26580cp+30*/ f32::from_bits(0x4e932c06), + 16777220.0, + -16777220.0, + ]), + i32x4::from_array([-2147483647i32, 1234567890i32, 16777219i32, -16777219i32]).cast() + ); + + // float -> float + assert_eq!( + f32x4::from_array([f32::INFINITY, f32::INFINITY, f32::NEG_INFINITY, f32::NEG_INFINITY]), + f64x4::from_array([f64::MAX, f64::INFINITY, f64::MIN, f64::NEG_INFINITY]).cast() + ); + + // unchecked casts + unsafe { + assert_eq!( + i32x4::from_array([0, 1, -1, 2147483520]), + f32x4::from_array([ + -0.0, + /*0x1.19999ap+0*/ f32::from_bits(0x3f8ccccd), + /*-0x1.19999ap+0*/ f32::from_bits(0xbf8ccccd), + 2147483520.0 + ]) + .to_int_unchecked() + ); + assert_eq!( + u64x4::from_array([0, 10000000000000000, u64::MAX - 2047, 9223372036854775808]), + f64x4::from_array([ + -0.99999999999, + 1e16, + (u64::MAX - 1024) as f64, + 9223372036854775808.0 + ]) + .to_int_unchecked() + ); + } +} + fn simd_intrinsics() { extern "platform-intrinsic" { fn simd_eq(x: T, y: T) -> U; @@ -112,14 +193,22 @@ fn simd_intrinsics() { assert!(simd_reduce_all(i32x4::splat(-1))); assert!(!simd_reduce_all(i32x2::from_array([0, -1]))); - assert_eq!(simd_select(i8x4::from_array([0, -1, -1, 0]), a, b), i32x4::from_array([1, 10, 10, 4])); - assert_eq!(simd_select(i8x4::from_array([0, -1, -1, 0]), b, a), i32x4::from_array([10, 2, 10, 10])); + assert_eq!( + simd_select(i8x4::from_array([0, -1, -1, 0]), a, b), + i32x4::from_array([1, 10, 10, 4]) + ); + assert_eq!( + simd_select(i8x4::from_array([0, -1, -1, 0]), b, a), + i32x4::from_array([10, 2, 10, 10]) + ); } } fn main() { + simd_mask(); simd_ops_f32(); simd_ops_f64(); simd_ops_i32(); + simd_cast(); simd_intrinsics(); } From 9851b743c1a4a1fdb62579c2c8bb6d6f543a7028 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 6 Mar 2022 14:31:45 -0500 Subject: [PATCH 2916/3747] implement simd_reduce_min/max --- src/shims/intrinsics.rs | 50 ++++++++++++++++++++++++++------- tests/run-pass/portable-simd.rs | 12 ++++++++ 2 files changed, 52 insertions(+), 10 deletions(-) diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 2f29ec4553d48..6f16853698035 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -433,7 +433,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "simd_reduce_or" | "simd_reduce_xor" | "simd_reduce_any" - | "simd_reduce_all" => { + | "simd_reduce_all" + | "simd_reduce_max" + | "simd_reduce_min" => { use mir::BinOp; let &[ref op] = check_arg_count(args)?; @@ -445,19 +447,27 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx enum Op { MirOp(BinOp), MirOpBool(BinOp), + Max, + Min, } - // The initial value is the neutral element. - let (which, init) = match intrinsic_name { - "simd_reduce_and" => (Op::MirOp(BinOp::BitAnd), ImmTy::from_int(-1, dest.layout)), - "simd_reduce_or" => (Op::MirOp(BinOp::BitOr), ImmTy::from_int(0, dest.layout)), - "simd_reduce_xor" => (Op::MirOp(BinOp::BitXor), ImmTy::from_int(0, dest.layout)), - "simd_reduce_any" => (Op::MirOpBool(BinOp::BitOr), imm_from_bool(false)), - "simd_reduce_all" => (Op::MirOpBool(BinOp::BitAnd), imm_from_bool(true)), + let which = match intrinsic_name { + "simd_reduce_and" => Op::MirOp(BinOp::BitAnd), + "simd_reduce_or" => Op::MirOp(BinOp::BitOr), + "simd_reduce_xor" => Op::MirOp(BinOp::BitXor), + "simd_reduce_any" => Op::MirOpBool(BinOp::BitOr), + "simd_reduce_all" => Op::MirOpBool(BinOp::BitAnd), + "simd_reduce_max" => Op::Max, + "simd_reduce_min" => Op::Min, _ => unreachable!(), }; - let mut res = init; - for i in 0..op_len { + // Initialize with first lane, then proceed with the rest. + let mut res = this.read_immediate(&this.mplace_index(&op, 0)?.into())?; + if matches!(which, Op::MirOpBool(_)) { + // Convert to `bool` scalar. + res = imm_from_bool(simd_element_to_bool(res)?); + } + for i in 1..op_len { let op = this.read_immediate(&this.mplace_index(&op, i)?.into())?; res = match which { Op::MirOp(mir_op) => { @@ -467,6 +477,26 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let op = imm_from_bool(simd_element_to_bool(op)?); this.binary_op(mir_op, &res, &op)? } + Op::Max => { + // if `op > res`... + if this.binary_op(BinOp::Gt, &op, &res)?.to_scalar()?.to_bool()? { + // update accumulator + op + } else { + // no change + res + } + } + Op::Min => { + // if `op < res`... + if this.binary_op(BinOp::Lt, &op, &res)?.to_scalar()?.to_bool()? { + // update accumulator + op + } else { + // no change + res + } + } }; } this.write_immediate(*res, dest)?; diff --git a/tests/run-pass/portable-simd.rs b/tests/run-pass/portable-simd.rs index 022e8c91f970d..ccedf61a38109 100644 --- a/tests/run-pass/portable-simd.rs +++ b/tests/run-pass/portable-simd.rs @@ -24,6 +24,10 @@ fn simd_ops_f32() { assert_eq!(b.horizontal_sum(), 2.0); assert_eq!(a.horizontal_product(), 100.0 * 100.0); assert_eq!(b.horizontal_product(), -24.0); + assert_eq!(a.horizontal_max(), 10.0); + assert_eq!(b.horizontal_max(), 3.0); + assert_eq!(a.horizontal_min(), 10.0); + assert_eq!(b.horizontal_min(), -4.0); } fn simd_ops_f64() { @@ -49,6 +53,10 @@ fn simd_ops_f64() { assert_eq!(b.horizontal_sum(), 2.0); assert_eq!(a.horizontal_product(), 100.0 * 100.0); assert_eq!(b.horizontal_product(), -24.0); + assert_eq!(a.horizontal_max(), 10.0); + assert_eq!(b.horizontal_max(), 3.0); + assert_eq!(a.horizontal_min(), 10.0); + assert_eq!(b.horizontal_min(), -4.0); } fn simd_ops_i32() { @@ -86,6 +94,10 @@ fn simd_ops_i32() { assert_eq!(b.horizontal_sum(), 2); assert_eq!(a.horizontal_product(), 100 * 100); assert_eq!(b.horizontal_product(), -24); + assert_eq!(a.horizontal_max(), 10); + assert_eq!(b.horizontal_max(), 3); + assert_eq!(a.horizontal_min(), 10); + assert_eq!(b.horizontal_min(), -4); } fn simd_mask() { From 2f97eb68a0f77d3829151bc57855d42535465a6d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 6 Mar 2022 15:26:15 -0500 Subject: [PATCH 2917/3747] implement simd_fmax/fmin --- src/shims/intrinsics.rs | 139 ++++++++++++++++++++------------ tests/run-pass/portable-simd.rs | 23 ++++-- 2 files changed, 103 insertions(+), 59 deletions(-) diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 6f16853698035..7dc4a000d1e8e 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -371,7 +371,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "simd_lt" | "simd_le" | "simd_gt" - | "simd_ge" => { + | "simd_ge" + | "simd_fmax" + | "simd_fmin" => { use mir::BinOp; let &[ref left, ref right] = check_arg_count(args)?; @@ -382,23 +384,30 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx assert_eq!(dest_len, left_len); assert_eq!(dest_len, right_len); - let mir_op = match intrinsic_name { - "simd_add" => BinOp::Add, - "simd_sub" => BinOp::Sub, - "simd_mul" => BinOp::Mul, - "simd_div" => BinOp::Div, - "simd_rem" => BinOp::Rem, - "simd_shl" => BinOp::Shl, - "simd_shr" => BinOp::Shr, - "simd_and" => BinOp::BitAnd, - "simd_or" => BinOp::BitOr, - "simd_xor" => BinOp::BitXor, - "simd_eq" => BinOp::Eq, - "simd_ne" => BinOp::Ne, - "simd_lt" => BinOp::Lt, - "simd_le" => BinOp::Le, - "simd_gt" => BinOp::Gt, - "simd_ge" => BinOp::Ge, + enum Op { + MirOp(BinOp), + FMax, + FMin, + } + let which = match intrinsic_name { + "simd_add" => Op::MirOp(BinOp::Add), + "simd_sub" => Op::MirOp(BinOp::Sub), + "simd_mul" => Op::MirOp(BinOp::Mul), + "simd_div" => Op::MirOp(BinOp::Div), + "simd_rem" => Op::MirOp(BinOp::Rem), + "simd_shl" => Op::MirOp(BinOp::Shl), + "simd_shr" => Op::MirOp(BinOp::Shr), + "simd_and" => Op::MirOp(BinOp::BitAnd), + "simd_or" => Op::MirOp(BinOp::BitOr), + "simd_xor" => Op::MirOp(BinOp::BitXor), + "simd_eq" => Op::MirOp(BinOp::Eq), + "simd_ne" => Op::MirOp(BinOp::Ne), + "simd_lt" => Op::MirOp(BinOp::Lt), + "simd_le" => Op::MirOp(BinOp::Le), + "simd_gt" => Op::MirOp(BinOp::Gt), + "simd_ge" => Op::MirOp(BinOp::Ge), + "simd_fmax" => Op::FMax, + "simd_fmin" => Op::FMin, _ => unreachable!(), }; @@ -406,26 +415,38 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let left = this.read_immediate(&this.mplace_index(&left, i)?.into())?; let right = this.read_immediate(&this.mplace_index(&right, i)?.into())?; let dest = this.mplace_index(&dest, i)?; - let (val, overflowed, ty) = this.overflowing_binary_op(mir_op, &left, &right)?; - if matches!(mir_op, BinOp::Shl | BinOp::Shr) { - // Shifts have extra UB as SIMD operations that the MIR binop does not have. - // See . - if overflowed { - let r_val = right.to_scalar()?.to_bits(right.layout.size)?; - throw_ub_format!("overflowing shift by {} in `{}` in SIMD lane {}", r_val, intrinsic_name, i); + let val = match which { + Op::MirOp(mir_op) => { + let (val, overflowed, ty) = this.overflowing_binary_op(mir_op, &left, &right)?; + if matches!(mir_op, BinOp::Shl | BinOp::Shr) { + // Shifts have extra UB as SIMD operations that the MIR binop does not have. + // See . + if overflowed { + let r_val = right.to_scalar()?.to_bits(right.layout.size)?; + throw_ub_format!("overflowing shift by {} in `{}` in SIMD lane {}", r_val, intrinsic_name, i); + } + } + if matches!(mir_op, BinOp::Eq | BinOp::Ne | BinOp::Lt | BinOp::Le | BinOp::Gt | BinOp::Ge) { + // Special handling for boolean-returning operations + assert_eq!(ty, this.tcx.types.bool); + let val = val.to_bool().unwrap(); + bool_to_simd_element(val, dest.layout.size) + } else { + assert_ne!(ty, this.tcx.types.bool); + assert_eq!(ty, dest.layout.ty); + val + } + } + Op::FMax => { + assert!(matches!(dest.layout.ty.kind(), ty::Float(_))); + this.max_op(&left, &right)?.to_scalar()? } - } - if matches!(mir_op, BinOp::Eq | BinOp::Ne | BinOp::Lt | BinOp::Le | BinOp::Gt | BinOp::Ge) { - // Special handling for boolean-returning operations - assert_eq!(ty, this.tcx.types.bool); - let val = val.to_bool().unwrap(); - let val = bool_to_simd_element(val, dest.layout.size); - this.write_scalar(val, &dest.into())?; - } else { - assert_ne!(ty, this.tcx.types.bool); - assert_eq!(ty, dest.layout.ty); - this.write_scalar(val, &dest.into())?; - } + Op::FMin => { + assert!(matches!(dest.layout.ty.kind(), ty::Float(_))); + this.min_op(&left, &right)?.to_scalar()? + } + }; + this.write_scalar(val, &dest.into())?; } } #[rustfmt::skip] @@ -478,24 +499,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.binary_op(mir_op, &res, &op)? } Op::Max => { - // if `op > res`... - if this.binary_op(BinOp::Gt, &op, &res)?.to_scalar()?.to_bool()? { - // update accumulator - op - } else { - // no change - res - } + this.max_op(&res, &op)? } Op::Min => { - // if `op < res`... - if this.binary_op(BinOp::Lt, &op, &res)?.to_scalar()?.to_bool()? { - // update accumulator - op - } else { - // no change - res - } + this.min_op(&res, &op)? } }; } @@ -1071,4 +1078,30 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx _ => bug!("`float_to_int_unchecked` called with non-int output type {:?}", dest_ty), }) } + + fn max_op( + &self, + left: &ImmTy<'tcx, Tag>, + right: &ImmTy<'tcx, Tag>, + ) -> InterpResult<'tcx, ImmTy<'tcx, Tag>> { + let this = self.eval_context_ref(); + Ok(if this.binary_op(BinOp::Gt, left, right)?.to_scalar()?.to_bool()? { + *left + } else { + *right + }) + } + + fn min_op( + &self, + left: &ImmTy<'tcx, Tag>, + right: &ImmTy<'tcx, Tag>, + ) -> InterpResult<'tcx, ImmTy<'tcx, Tag>> { + let this = self.eval_context_ref(); + Ok(if this.binary_op(BinOp::Lt, left, right)?.to_scalar()?.to_bool()? { + *left + } else { + *right + }) + } } diff --git a/tests/run-pass/portable-simd.rs b/tests/run-pass/portable-simd.rs index ccedf61a38109..817d18a45d4b7 100644 --- a/tests/run-pass/portable-simd.rs +++ b/tests/run-pass/portable-simd.rs @@ -12,6 +12,8 @@ fn simd_ops_f32() { assert_eq!(a / f32x4::splat(2.0), f32x4::splat(5.0)); assert_eq!(a % b, f32x4::from_array([0.0, 0.0, 1.0, 2.0])); assert_eq!(b.abs(), f32x4::from_array([1.0, 2.0, 3.0, 4.0])); + assert_eq!(a.max(b * f32x4::splat(4.0)), f32x4::from_array([10.0, 10.0, 12.0, 10.0])); + assert_eq!(a.min(b * f32x4::splat(4.0)), f32x4::from_array([4.0, 8.0, 10.0, -16.0])); assert_eq!(a.lanes_eq(f32x4::splat(5.0) * b), Mask::from_array([false, true, false, false])); assert_eq!(a.lanes_ne(f32x4::splat(5.0) * b), Mask::from_array([true, false, true, true])); @@ -41,6 +43,8 @@ fn simd_ops_f64() { assert_eq!(a / f64x4::splat(2.0), f64x4::splat(5.0)); assert_eq!(a % b, f64x4::from_array([0.0, 0.0, 1.0, 2.0])); assert_eq!(b.abs(), f64x4::from_array([1.0, 2.0, 3.0, 4.0])); + assert_eq!(a.max(b * f64x4::splat(4.0)), f64x4::from_array([10.0, 10.0, 12.0, 10.0])); + assert_eq!(a.min(b * f64x4::splat(4.0)), f64x4::from_array([4.0, 8.0, 10.0, -16.0])); assert_eq!(a.lanes_eq(f64x4::splat(5.0) * b), Mask::from_array([false, true, false, false])); assert_eq!(a.lanes_ne(f64x4::splat(5.0) * b), Mask::from_array([true, false, true, true])); @@ -71,6 +75,12 @@ fn simd_ops_i32() { assert_eq!(i32x2::splat(i32::MIN) / i32x2::splat(-1), i32x2::splat(i32::MIN)); assert_eq!(a % b, i32x4::from_array([0, 0, 1, 2])); assert_eq!(i32x2::splat(i32::MIN) % i32x2::splat(-1), i32x2::splat(0)); + assert_eq!(b.abs(), i32x4::from_array([1, 2, 3, 4])); + // FIXME not a per-lane method (https://github.com/rust-lang/rust/issues/94682) + // assert_eq!(a.max(b * i32x4::splat(4)), i32x4::from_array([10, 10, 12, 10])); + // assert_eq!(a.min(b * i32x4::splat(4)), i32x4::from_array([4, 8, 10, -16])); + + assert_eq!(!b, i32x4::from_array([!1, !2, !3, !-4])); assert_eq!(b << i32x4::splat(2), i32x4::from_array([4, 8, 12, -16])); assert_eq!(b >> i32x4::splat(1), i32x4::from_array([0, 1, 1, -2])); assert_eq!(b & i32x4::splat(2), i32x4::from_array([0, 2, 2, 0])); @@ -84,12 +94,6 @@ fn simd_ops_i32() { assert_eq!(a.lanes_ge(i32x4::splat(5) * b), Mask::from_array([true, true, false, true])); assert_eq!(a.lanes_gt(i32x4::splat(5) * b), Mask::from_array([true, false, false, true])); - assert_eq!(a.horizontal_and(), 10); - assert_eq!(b.horizontal_and(), 0); - assert_eq!(a.horizontal_or(), 10); - assert_eq!(b.horizontal_or(), -1); - assert_eq!(a.horizontal_xor(), 0); - assert_eq!(b.horizontal_xor(), -4); assert_eq!(a.horizontal_sum(), 40); assert_eq!(b.horizontal_sum(), 2); assert_eq!(a.horizontal_product(), 100 * 100); @@ -98,6 +102,13 @@ fn simd_ops_i32() { assert_eq!(b.horizontal_max(), 3); assert_eq!(a.horizontal_min(), 10); assert_eq!(b.horizontal_min(), -4); + + assert_eq!(a.horizontal_and(), 10); + assert_eq!(b.horizontal_and(), 0); + assert_eq!(a.horizontal_or(), 10); + assert_eq!(b.horizontal_or(), -1); + assert_eq!(a.horizontal_xor(), 0); + assert_eq!(b.horizontal_xor(), -4); } fn simd_mask() { From b87a9c90e1ca983eb81778d79b23db8c52eace54 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 6 Mar 2022 16:54:51 -0500 Subject: [PATCH 2918/3747] fix handling of NaNs in simd max/min --- rust-version | 2 +- src/shims/intrinsics.rs | 83 +++++++++++++++++++++------------ tests/run-pass/portable-simd.rs | 26 +++++++++++ 3 files changed, 79 insertions(+), 32 deletions(-) diff --git a/rust-version b/rust-version index 109a8080b07f5..a769188204f5a 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -8876ca3dd46b99fe7e6ad937f11493d37996231e +297273c45b205820a4c055082c71677197a40b55 diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 7dc4a000d1e8e..897ebe4ae79fa 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -345,7 +345,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx bug!("simd_fabs operand is not a float") }; let op = op.to_scalar()?; - // FIXME: Using host floats. match float_ty { FloatTy::F32 => Scalar::from_f32(op.to_f32()?.abs()), FloatTy::F64 => Scalar::from_f64(op.to_f64()?.abs()), @@ -438,12 +437,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } Op::FMax => { - assert!(matches!(dest.layout.ty.kind(), ty::Float(_))); - this.max_op(&left, &right)?.to_scalar()? + fmax_op(&left, &right)? } Op::FMin => { - assert!(matches!(dest.layout.ty.kind(), ty::Float(_))); - this.min_op(&left, &right)?.to_scalar()? + fmin_op(&left, &right)? } }; this.write_scalar(val, &dest.into())?; @@ -499,10 +496,28 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.binary_op(mir_op, &res, &op)? } Op::Max => { - this.max_op(&res, &op)? + if matches!(res.layout.ty.kind(), ty::Float(_)) { + ImmTy::from_scalar(fmax_op(&res, &op)?, res.layout) + } else { + // Just boring integers, so NaNs to worry about + if this.binary_op(BinOp::Ge, &res, &op)?.to_scalar()?.to_bool()? { + res + } else { + op + } + } } Op::Min => { - this.min_op(&res, &op)? + if matches!(res.layout.ty.kind(), ty::Float(_)) { + ImmTy::from_scalar(fmin_op(&res, &op)?, res.layout) + } else { + // Just boring integers, so NaNs to worry about + if this.binary_op(BinOp::Le, &res, &op)?.to_scalar()?.to_bool()? { + res + } else { + op + } + } } }; } @@ -1078,30 +1093,36 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx _ => bug!("`float_to_int_unchecked` called with non-int output type {:?}", dest_ty), }) } +} - fn max_op( - &self, - left: &ImmTy<'tcx, Tag>, - right: &ImmTy<'tcx, Tag>, - ) -> InterpResult<'tcx, ImmTy<'tcx, Tag>> { - let this = self.eval_context_ref(); - Ok(if this.binary_op(BinOp::Gt, left, right)?.to_scalar()?.to_bool()? { - *left - } else { - *right - }) - } +fn fmax_op<'tcx>( + left: &ImmTy<'tcx, Tag>, + right: &ImmTy<'tcx, Tag>, +) -> InterpResult<'tcx, Scalar> { + assert_eq!(left.layout.ty, right.layout.ty); + let ty::Float(float_ty) = left.layout.ty.kind() else { + bug!("fmax operand is not a float") + }; + let left = left.to_scalar()?; + let right = right.to_scalar()?; + Ok(match float_ty { + FloatTy::F32 => Scalar::from_f32(left.to_f32()?.max(right.to_f32()?)), + FloatTy::F64 => Scalar::from_f64(left.to_f64()?.max(right.to_f64()?)), + }) +} - fn min_op( - &self, - left: &ImmTy<'tcx, Tag>, - right: &ImmTy<'tcx, Tag>, - ) -> InterpResult<'tcx, ImmTy<'tcx, Tag>> { - let this = self.eval_context_ref(); - Ok(if this.binary_op(BinOp::Lt, left, right)?.to_scalar()?.to_bool()? { - *left - } else { - *right - }) - } +fn fmin_op<'tcx>( + left: &ImmTy<'tcx, Tag>, + right: &ImmTy<'tcx, Tag>, +) -> InterpResult<'tcx, Scalar> { + assert_eq!(left.layout.ty, right.layout.ty); + let ty::Float(float_ty) = left.layout.ty.kind() else { + bug!("fmin operand is not a float") + }; + let left = left.to_scalar()?; + let right = right.to_scalar()?; + Ok(match float_ty { + FloatTy::F32 => Scalar::from_f32(left.to_f32()?.min(right.to_f32()?)), + FloatTy::F64 => Scalar::from_f64(left.to_f64()?.min(right.to_f64()?)), + }) } diff --git a/tests/run-pass/portable-simd.rs b/tests/run-pass/portable-simd.rs index 817d18a45d4b7..48297ee4e6901 100644 --- a/tests/run-pass/portable-simd.rs +++ b/tests/run-pass/portable-simd.rs @@ -30,6 +30,19 @@ fn simd_ops_f32() { assert_eq!(b.horizontal_max(), 3.0); assert_eq!(a.horizontal_min(), 10.0); assert_eq!(b.horizontal_min(), -4.0); + + assert_eq!( + f32x2::from_array([0.0, f32::NAN]).max(f32x2::from_array([f32::NAN, 0.0])), + f32x2::from_array([0.0, 0.0]) + ); + assert_eq!(f32x2::from_array([0.0, f32::NAN]).horizontal_max(), 0.0); + assert_eq!(f32x2::from_array([f32::NAN, 0.0]).horizontal_max(), 0.0); + assert_eq!( + f32x2::from_array([0.0, f32::NAN]).min(f32x2::from_array([f32::NAN, 0.0])), + f32x2::from_array([0.0, 0.0]) + ); + assert_eq!(f32x2::from_array([0.0, f32::NAN]).horizontal_min(), 0.0); + assert_eq!(f32x2::from_array([f32::NAN, 0.0]).horizontal_min(), 0.0); } fn simd_ops_f64() { @@ -61,6 +74,19 @@ fn simd_ops_f64() { assert_eq!(b.horizontal_max(), 3.0); assert_eq!(a.horizontal_min(), 10.0); assert_eq!(b.horizontal_min(), -4.0); + + assert_eq!( + f64x2::from_array([0.0, f64::NAN]).max(f64x2::from_array([f64::NAN, 0.0])), + f64x2::from_array([0.0, 0.0]) + ); + assert_eq!(f64x2::from_array([0.0, f64::NAN]).horizontal_max(), 0.0); + assert_eq!(f64x2::from_array([f64::NAN, 0.0]).horizontal_max(), 0.0); + assert_eq!( + f64x2::from_array([0.0, f64::NAN]).min(f64x2::from_array([f64::NAN, 0.0])), + f64x2::from_array([0.0, 0.0]) + ); + assert_eq!(f64x2::from_array([0.0, f64::NAN]).horizontal_min(), 0.0); + assert_eq!(f64x2::from_array([f64::NAN, 0.0]).horizontal_min(), 0.0); } fn simd_ops_i32() { From c03575275a56112edacd1c5cd26a8eb2d4763b74 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 7 Mar 2022 12:00:27 -0500 Subject: [PATCH 2919/3747] update recommended CI snippet, add GHA example --- README.md | 33 +++++++++++++++++++++++++-------- 1 file changed, 25 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 3c5af59d3f079..55154356c9da8 100644 --- a/README.md +++ b/README.md @@ -144,20 +144,37 @@ endian-sensitive code. ### Running Miri on CI To run Miri on CI, make sure that you handle the case where the latest nightly -does not ship the Miri component because it currently does not build. For -example, you can use the following snippet to always test with the latest -nightly that *does* come with Miri: +does not ship the Miri component because it currently does not build. `rustup +toolchain install --component` knows how to handle this situation, so the +following snippet should always work: ```sh -MIRI_NIGHTLY=nightly-$(curl -s https://rust-lang.github.io/rustup-components-history/x86_64-unknown-linux-gnu/miri) -echo "Installing latest nightly with Miri: $MIRI_NIGHTLY" -rustup set profile minimal -rustup override set "$MIRI_NIGHTLY" -rustup component add miri +rustup toolchain install nightly --component miri +rustup override set nightly cargo miri test ``` +Here is an example job for GitHub Actions: + +```yaml + miri: + name: "Miri" + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Install Miri + run: | + rustup toolchain install nightly --component miri + rustup override set nightly + cargo miri setup + - name: Test with Miri + run: cargo miri test +``` + +The explicit `cargo miri setup` helps to keep the output of the actual test step +clean. + ### Common Problems When using the above instructions, you may encounter a number of confusing compiler From 735bee273690940e9944291c70ab808cbc1062c1 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 7 Mar 2022 14:12:59 -0500 Subject: [PATCH 2920/3747] implement simd_saturating intrinsics --- rust-version | 2 +- src/shims/intrinsics.rs | 10 +++++++++- tests/run-pass/portable-simd.rs | 19 ++++++++++++++++++- 3 files changed, 28 insertions(+), 3 deletions(-) diff --git a/rust-version b/rust-version index a769188204f5a..dcc365ef0ad9b 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -297273c45b205820a4c055082c71677197a40b55 +d137c3a7bd3b180317044f8ccb9a8b4b3bb07db3 diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 897ebe4ae79fa..49c9c0fb0d965 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -372,7 +372,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "simd_gt" | "simd_ge" | "simd_fmax" - | "simd_fmin" => { + | "simd_fmin" + | "simd_saturating_add" + | "simd_saturating_sub" => { use mir::BinOp; let &[ref left, ref right] = check_arg_count(args)?; @@ -385,6 +387,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx enum Op { MirOp(BinOp), + SaturatingOp(BinOp), FMax, FMin, } @@ -407,6 +410,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "simd_ge" => Op::MirOp(BinOp::Ge), "simd_fmax" => Op::FMax, "simd_fmin" => Op::FMin, + "simd_saturating_add" => Op::SaturatingOp(BinOp::Add), + "simd_saturating_sub" => Op::SaturatingOp(BinOp::Sub), _ => unreachable!(), }; @@ -442,6 +447,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Op::FMin => { fmin_op(&left, &right)? } + Op::SaturatingOp(mir_op) => { + this.saturating_arith(mir_op, &left, &right)? + } }; this.write_scalar(val, &dest.into())?; } diff --git a/tests/run-pass/portable-simd.rs b/tests/run-pass/portable-simd.rs index 48297ee4e6901..b87bd4fd6ad2a 100644 --- a/tests/run-pass/portable-simd.rs +++ b/tests/run-pass/portable-simd.rs @@ -102,10 +102,27 @@ fn simd_ops_i32() { assert_eq!(a % b, i32x4::from_array([0, 0, 1, 2])); assert_eq!(i32x2::splat(i32::MIN) % i32x2::splat(-1), i32x2::splat(0)); assert_eq!(b.abs(), i32x4::from_array([1, 2, 3, 4])); - // FIXME not a per-lane method (https://github.com/rust-lang/rust/issues/94682) + // FIXME not a per-lane method (https://github.com/rust-lang/portable-simd/issues/247) // assert_eq!(a.max(b * i32x4::splat(4)), i32x4::from_array([10, 10, 12, 10])); // assert_eq!(a.min(b * i32x4::splat(4)), i32x4::from_array([4, 8, 10, -16])); + assert_eq!( + i8x4::from_array([i8::MAX, -23, 23, i8::MIN]).saturating_add(i8x4::from_array([1, i8::MIN, i8::MAX, 28])), + i8x4::from_array([i8::MAX, i8::MIN, i8::MAX, -100]) + ); + assert_eq!( + i8x4::from_array([i8::MAX, -28, 27, 42]).saturating_sub(i8x4::from_array([1, i8::MAX, i8::MAX, -80])), + i8x4::from_array([126, i8::MIN, -100, 122]) + ); + assert_eq!( + u8x4::from_array([u8::MAX, 0, 23, 42]).saturating_add(u8x4::from_array([1, 1, u8::MAX, 200])), + u8x4::from_array([u8::MAX, 1, u8::MAX, 242]) + ); + assert_eq!( + u8x4::from_array([u8::MAX, 0, 23, 42]).saturating_sub(u8x4::from_array([1, 1, u8::MAX, 200])), + u8x4::from_array([254, 0, 0, 0]) + ); + assert_eq!(!b, i32x4::from_array([!1, !2, !3, !-4])); assert_eq!(b << i32x4::splat(2), i32x4::from_array([4, 8, 12, -16])); assert_eq!(b >> i32x4::splat(1), i32x4::from_array([0, 1, 1, -2])); From 0088715411c2fcb3ea36cdbb969fb9966d722320 Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Mon, 7 Mar 2022 12:46:53 -0500 Subject: [PATCH 2921/3747] Rename MiriMemoryKind::Env to Runtime In preparation to use it for other runtime-internal allocations. --- src/data_race.rs | 2 +- src/machine.rs | 9 +++++---- src/shims/env.rs | 25 +++++++++++++------------ src/stacked_borrows.rs | 2 +- 4 files changed, 20 insertions(+), 18 deletions(-) diff --git a/src/data_race.rs b/src/data_race.rs index a6ef56a0c2045..1e91c66b859ed 100644 --- a/src/data_race.rs +++ b/src/data_race.rs @@ -743,7 +743,7 @@ impl VClockAlloc { MemoryKind::Machine( MiriMemoryKind::Global | MiriMemoryKind::Machine - | MiriMemoryKind::Env + | MiriMemoryKind::Runtime | MiriMemoryKind::ExternStatic | MiriMemoryKind::Tls, ) diff --git a/src/machine.rs b/src/machine.rs index 481808dc78197..bb43cb95507c5 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -71,8 +71,9 @@ pub enum MiriMemoryKind { /// Memory for args, errno, and other parts of the machine-managed environment. /// This memory may leak. Machine, - /// Memory for env vars. Separate from `Machine` because we clean it up and leak-check it. - Env, + /// Memory allocated by the runtime (e.g. env vars). Separate from `Machine` + /// because we clean it up and leak-check it. + Runtime, /// Globals copied from `tcx`. /// This memory may leak. Global, @@ -96,7 +97,7 @@ impl MayLeak for MiriMemoryKind { fn may_leak(self) -> bool { use self::MiriMemoryKind::*; match self { - Rust | C | WinHeap | Env => false, + Rust | C | WinHeap | Runtime => false, Machine | Global | ExternStatic | Tls => true, } } @@ -110,7 +111,7 @@ impl fmt::Display for MiriMemoryKind { C => write!(f, "C heap"), WinHeap => write!(f, "Windows heap"), Machine => write!(f, "machine-managed memory"), - Env => write!(f, "environment variable"), + Runtime => write!(f, "language runtime memory"), Global => write!(f, "global (static or const)"), ExternStatic => write!(f, "extern static"), Tls => write!(f, "thread-local static"), diff --git a/src/shims/env.rs b/src/shims/env.rs index dfd1ef207d96a..fd77286885809 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -78,12 +78,12 @@ impl<'tcx> EnvVars<'tcx> { ) -> InterpResult<'tcx> { // Deallocate individual env vars. for (_name, ptr) in ecx.machine.env_vars.map.drain() { - ecx.memory.deallocate(ptr, None, MiriMemoryKind::Env.into())?; + ecx.memory.deallocate(ptr, None, MiriMemoryKind::Runtime.into())?; } // Deallocate environ var list. let environ = ecx.machine.env_vars.environ.unwrap(); let old_vars_ptr = ecx.read_pointer(&environ.into())?; - ecx.memory.deallocate(old_vars_ptr, None, MiriMemoryKind::Env.into())?; + ecx.memory.deallocate(old_vars_ptr, None, MiriMemoryKind::Runtime.into())?; Ok(()) } } @@ -96,7 +96,7 @@ fn alloc_env_var_as_c_str<'mir, 'tcx>( let mut name_osstring = name.to_os_string(); name_osstring.push("="); name_osstring.push(value); - ecx.alloc_os_str_as_c_str(name_osstring.as_os_str(), MiriMemoryKind::Env.into()) + ecx.alloc_os_str_as_c_str(name_osstring.as_os_str(), MiriMemoryKind::Runtime.into()) } fn alloc_env_var_as_wide_str<'mir, 'tcx>( @@ -107,7 +107,7 @@ fn alloc_env_var_as_wide_str<'mir, 'tcx>( let mut name_osstring = name.to_os_string(); name_osstring.push("="); name_osstring.push(value); - ecx.alloc_os_str_as_wide_str(name_osstring.as_os_str(), MiriMemoryKind::Env.into()) + ecx.alloc_os_str_as_wide_str(name_osstring.as_os_str(), MiriMemoryKind::Runtime.into()) } impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} @@ -186,7 +186,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // Allocate environment block & Store environment variables to environment block. // Final null terminator(block terminator) is added by `alloc_os_str_to_wide_str`. - let envblock_ptr = this.alloc_os_str_as_wide_str(&env_vars, MiriMemoryKind::Env.into())?; + let envblock_ptr = + this.alloc_os_str_as_wide_str(&env_vars, MiriMemoryKind::Runtime.into())?; // If the function succeeds, the return value is a pointer to the environment block of the current process. Ok(envblock_ptr) } @@ -200,7 +201,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.assert_target_os("windows", "FreeEnvironmentStringsW"); let env_block_ptr = this.read_pointer(env_block_op)?; - let result = this.memory.deallocate(env_block_ptr, None, MiriMemoryKind::Env.into()); + let result = this.memory.deallocate(env_block_ptr, None, MiriMemoryKind::Runtime.into()); // If the function succeeds, the return value is nonzero. Ok(result.is_ok() as i32) } @@ -231,7 +232,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if let Some((name, value)) = new { let var_ptr = alloc_env_var_as_c_str(&name, &value, &mut this)?; if let Some(var) = this.machine.env_vars.map.insert(name, var_ptr) { - this.memory.deallocate(var, None, MiriMemoryKind::Env.into())?; + this.memory.deallocate(var, None, MiriMemoryKind::Runtime.into())?; } this.update_environ()?; Ok(0) // return zero on success @@ -268,7 +269,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } else if this.ptr_is_null(value_ptr)? { // Delete environment variable `{name}` if let Some(var) = this.machine.env_vars.map.remove(&name) { - this.memory.deallocate(var, None, MiriMemoryKind::Env.into())?; + this.memory.deallocate(var, None, MiriMemoryKind::Runtime.into())?; this.update_environ()?; } Ok(1) // return non-zero on success @@ -276,7 +277,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let value = this.read_os_str_from_wide_str(value_ptr)?; let var_ptr = alloc_env_var_as_wide_str(&name, &value, &mut this)?; if let Some(var) = this.machine.env_vars.map.insert(name, var_ptr) { - this.memory.deallocate(var, None, MiriMemoryKind::Env.into())?; + this.memory.deallocate(var, None, MiriMemoryKind::Runtime.into())?; } this.update_environ()?; Ok(1) // return non-zero on success @@ -301,7 +302,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } if let Some(old) = success { if let Some(var) = old { - this.memory.deallocate(var, None, MiriMemoryKind::Env.into())?; + this.memory.deallocate(var, None, MiriMemoryKind::Runtime.into())?; } this.update_environ()?; Ok(0) @@ -437,7 +438,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Deallocate the old environ list, if any. if let Some(environ) = this.machine.env_vars.environ { let old_vars_ptr = this.read_pointer(&environ.into())?; - this.memory.deallocate(old_vars_ptr, None, MiriMemoryKind::Env.into())?; + this.memory.deallocate(old_vars_ptr, None, MiriMemoryKind::Runtime.into())?; } else { // No `environ` allocated yet, let's do that. // This is memory backing an extern static, hence `ExternStatic`, not `Env`. @@ -455,7 +456,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let tcx = this.tcx; let vars_layout = this.layout_of(tcx.mk_array(tcx.types.usize, u64::try_from(vars.len()).unwrap()))?; - let vars_place = this.allocate(vars_layout, MiriMemoryKind::Env.into())?; + let vars_place = this.allocate(vars_layout, MiriMemoryKind::Runtime.into())?; for (idx, var) in vars.into_iter().enumerate() { let place = this.mplace_field(&vars_place, idx)?; this.write_pointer(var, &place.into())?; diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 37ecb749a4877..0e47a9e1c3b07 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -535,7 +535,7 @@ impl Stacks { MiriMemoryKind::Global | MiriMemoryKind::ExternStatic | MiriMemoryKind::Tls - | MiriMemoryKind::Env + | MiriMemoryKind::Runtime | MiriMemoryKind::Machine, ) => (extra.base_tag(id), Permission::SharedReadWrite), // Heap allocations we only track precisely when raw pointers are tagged, for now. From 0886419524c5baf61d6f3980e81ba4e0429ac402 Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Tue, 22 Feb 2022 17:06:05 -0500 Subject: [PATCH 2922/3747] Implement a readdir64() shim for Linux Partial fix for #1966. --- src/shims/posix/fs.rs | 120 ++++++++++++++----------- src/shims/posix/linux/foreign_items.rs | 8 +- tests/run-pass/fs.rs | 12 +-- 3 files changed, 76 insertions(+), 64 deletions(-) diff --git a/src/shims/posix/fs.rs b/src/shims/posix/fs.rs index 7956cfe4dcef3..300e3c514b375 100644 --- a/src/shims/posix/fs.rs +++ b/src/shims/posix/fs.rs @@ -16,6 +16,7 @@ use rustc_target::abi::{Align, Size}; use crate::*; use helpers::{check_arg_count, immty_from_int_checked, immty_from_uint_checked}; +use shims::os_str::os_str_to_bytes; use shims::time::system_time_to_duration; #[derive(Debug)] @@ -421,6 +422,22 @@ trait EvalContextExtPrivate<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, ' } } +/// An open directory, tracked by DirHandler. +#[derive(Debug)] +pub struct OpenDir { + /// The directory reader on the host. + read_dir: ReadDir, + /// The most recent entry returned by readdir() + entry: Pointer>, +} + +impl OpenDir { + fn new(read_dir: ReadDir) -> Self { + // We rely on `free` being a NOP on null pointers. + Self { read_dir, entry: Pointer::null() } + } +} + #[derive(Debug)] pub struct DirHandler { /// Directory iterators used to emulate libc "directory streams", as used in opendir, readdir, @@ -432,7 +449,7 @@ pub struct DirHandler { /// the corresponding ReadDir iterator from this map, and information from the next /// directory entry is returned. When closedir is called, the ReadDir iterator is removed from /// the map. - streams: FxHashMap, + streams: FxHashMap, /// ID number to be used by the next call to opendir next_id: u64, } @@ -441,7 +458,7 @@ impl DirHandler { fn insert_new(&mut self, read_dir: ReadDir) -> u64 { let id = self.next_id; self.next_id += 1; - self.streams.try_insert(id, read_dir).unwrap(); + self.streams.try_insert(id, OpenDir::new(read_dir)).unwrap(); id } } @@ -1207,32 +1224,29 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } - fn linux_readdir64_r( - &mut self, - dirp_op: &OpTy<'tcx, Tag>, - entry_op: &OpTy<'tcx, Tag>, - result_op: &OpTy<'tcx, Tag>, - ) -> InterpResult<'tcx, i32> { + fn linux_readdir64(&mut self, dirp_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); - this.assert_target_os("linux", "readdir64_r"); + this.assert_target_os("linux", "readdir64"); let dirp = this.read_scalar(dirp_op)?.to_machine_usize(this)?; // Reject if isolation is enabled. if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { - this.reject_in_isolation("`readdir64_r`", reject_with)?; - // Set error code as "EBADF" (bad fd) - return this.handle_not_found(); + this.reject_in_isolation("`readdir`", reject_with)?; + let eacc = this.eval_libc("EBADF")?; + this.set_last_error(eacc)?; + return Ok(Scalar::null_ptr(this)); } - let dir_iter = this.machine.dir_handler.streams.get_mut(&dirp).ok_or_else(|| { - err_unsup_format!("the DIR pointer passed to readdir64_r did not come from opendir") + let open_dir = this.machine.dir_handler.streams.get_mut(&dirp).ok_or_else(|| { + err_unsup_format!("the DIR pointer passed to readdir64 did not come from opendir") })?; - match dir_iter.next() { + + let entry = match open_dir.read_dir.next() { Some(Ok(dir_entry)) => { - // Write into entry, write pointer to result, return 0 on success. - // The name is written with write_os_str_to_c_str, while the rest of the + // Write the directory entry into a newly allocated buffer. + // The name is written with write_bytes, while the rest of the // dirent64 struct is written using write_packed_immediates. // For reference: @@ -1244,22 +1258,19 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // pub d_name: [c_char; 256], // } - let entry_place = this.deref_operand(entry_op)?; - let name_place = this.mplace_field(&entry_place, 4)?; + let mut name = dir_entry.file_name(); // not a Path as there are no separators! + name.push("\0"); // Add a NUL terminator + let name_bytes = os_str_to_bytes(&name)?; + let name_len = u64::try_from(name_bytes.len()).unwrap(); - let file_name = dir_entry.file_name(); // not a Path as there are no separators! - let (name_fits, _) = this.write_os_str_to_c_str( - &file_name, - name_place.ptr, - name_place.layout.size.bytes(), - )?; - if !name_fits { - throw_unsup_format!( - "a directory entry had a name too large to fit in libc::dirent64" - ); - } + let dirent64_layout = this.libc_ty_layout("dirent64")?; + let d_name_offset = dirent64_layout.fields.offset(4 /* d_name */).bytes(); + let size = d_name_offset.checked_add(name_len).unwrap(); - let entry_place = this.deref_operand(entry_op)?; + let entry = + this.malloc(size, /*zero_init:*/ false, MiriMemoryKind::Runtime)?; + + // FIXME: make use of dirent64_layout let ino64_t_layout = this.libc_ty_layout("ino64_t")?; let off64_t_layout = this.libc_ty_layout("off64_t")?; let c_ushort_layout = this.libc_ty_layout("c_ushort")?; @@ -1277,33 +1288,33 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let imms = [ immty_from_uint_checked(ino, ino64_t_layout)?, // d_ino immty_from_uint_checked(0u128, off64_t_layout)?, // d_off - immty_from_uint_checked(0u128, c_ushort_layout)?, // d_reclen + immty_from_uint_checked(size, c_ushort_layout)?, // d_reclen immty_from_int_checked(file_type, c_uchar_layout)?, // d_type ]; + let entry_layout = this.layout_of(this.tcx.mk_array(this.tcx.types.u8, size))?; + let entry_place = MPlaceTy::from_aligned_ptr(entry, entry_layout); this.write_packed_immediates(&entry_place, &imms)?; - let result_place = this.deref_operand(result_op)?; - this.write_scalar(this.read_scalar(entry_op)?, &result_place.into())?; + let name_ptr = entry.offset(Size::from_bytes(d_name_offset), this)?; + this.memory.write_bytes(name_ptr, name_bytes.iter().copied())?; - Ok(0) + entry } None => { - // end of stream: return 0, assign *result=NULL - this.write_null(&this.deref_operand(result_op)?.into())?; - Ok(0) + // end of stream: return NULL + Pointer::null() } - Some(Err(e)) => - match e.raw_os_error() { - // return positive error number on error - Some(error) => Ok(error), - None => { - throw_unsup_format!( - "the error {} couldn't be converted to a return value", - e - ) - } - }, - } + Some(Err(e)) => { + this.set_last_error_from_io_error(e.kind())?; + Pointer::null() + } + }; + + let open_dir = this.machine.dir_handler.streams.get_mut(&dirp).unwrap(); + let old_entry = std::mem::replace(&mut open_dir.entry, entry); + this.free(old_entry, MiriMemoryKind::Runtime)?; + + Ok(Scalar::from_maybe_pointer(entry, this)) } fn macos_readdir_r( @@ -1325,10 +1336,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx return this.handle_not_found(); } - let dir_iter = this.machine.dir_handler.streams.get_mut(&dirp).ok_or_else(|| { + let open_dir = this.machine.dir_handler.streams.get_mut(&dirp).ok_or_else(|| { err_unsup_format!("the DIR pointer passed to readdir_r did not come from opendir") })?; - match dir_iter.next() { + match open_dir.read_dir.next() { Some(Ok(dir_entry)) => { // Write into entry, write pointer to result, return 0 on success. // The name is written with write_os_str_to_c_str, while the rest of the @@ -1419,8 +1430,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx return this.handle_not_found(); } - if let Some(dir_iter) = this.machine.dir_handler.streams.remove(&dirp) { - drop(dir_iter); + if let Some(open_dir) = this.machine.dir_handler.streams.remove(&dirp) { + this.free(open_dir.entry, MiriMemoryKind::Runtime)?; + drop(open_dir); Ok(0) } else { this.handle_not_found() diff --git a/src/shims/posix/linux/foreign_items.rs b/src/shims/posix/linux/foreign_items.rs index 8d0f8487f5e13..280f24e9ea496 100644 --- a/src/shims/posix/linux/foreign_items.rs +++ b/src/shims/posix/linux/foreign_items.rs @@ -43,11 +43,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let result = this.opendir(name)?; this.write_scalar(result, dest)?; } - "readdir64_r" => { - let &[ref dirp, ref entry, ref result] = + "readdir64" => { + let &[ref dirp] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; - let result = this.linux_readdir64_r(dirp, entry, result)?; - this.write_scalar(Scalar::from_i32(result), dest)?; + let result = this.linux_readdir64(dirp)?; + this.write_scalar(result, dest)?; } "ftruncate64" => { let &[ref fd, ref length] = diff --git a/tests/run-pass/fs.rs b/tests/run-pass/fs.rs index 9ab1d4c033839..be680131f84ab 100644 --- a/tests/run-pass/fs.rs +++ b/tests/run-pass/fs.rs @@ -6,7 +6,9 @@ extern crate libc; use std::ffi::CString; -use std::fs::{create_dir, remove_dir, remove_dir_all, remove_file, rename, File, OpenOptions}; +use std::fs::{ + create_dir, read_dir, remove_dir, remove_dir_all, remove_file, rename, File, OpenOptions, +}; use std::io::{Error, ErrorKind, Read, Result, Seek, SeekFrom, Write}; use std::path::{Path, PathBuf}; @@ -374,19 +376,17 @@ fn test_directory() { let path_2 = dir_path.join("test_file_2"); drop(File::create(&path_2).unwrap()); // Test that the files are present inside the directory - /* FIXME(1966) disabled due to missing readdir support let dir_iter = read_dir(&dir_path).unwrap(); let mut file_names = dir_iter.map(|e| e.unwrap().file_name()).collect::>(); file_names.sort_unstable(); - assert_eq!(file_names, vec!["test_file_1", "test_file_2"]); */ + assert_eq!(file_names, vec!["test_file_1", "test_file_2"]); // Clean up the files in the directory remove_file(&path_1).unwrap(); remove_file(&path_2).unwrap(); // Now there should be nothing left in the directory. - /* FIXME(1966) disabled due to missing readdir support - dir_iter = read_dir(&dir_path).unwrap(); + let dir_iter = read_dir(&dir_path).unwrap(); let file_names = dir_iter.map(|e| e.unwrap().file_name()).collect::>(); - assert!(file_names.is_empty());*/ + assert!(file_names.is_empty()); // Deleting the directory should succeed. remove_dir(&dir_path).unwrap(); From 6d3506adef3537c2f3b28f4121cf694971fb0b91 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 7 Mar 2022 18:30:12 -0500 Subject: [PATCH 2923/3747] fs: add and test for DirectoryNotEmpty error variant --- src/helpers.rs | 1 + src/lib.rs | 1 + tests/run-pass/fs.rs | 3 +++ 3 files changed, 5 insertions(+) diff --git a/src/helpers.rs b/src/helpers.rs index 2f1c74a0587ec..cae8f5ddb4484 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -490,6 +490,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx TimedOut => "ETIMEDOUT", AlreadyExists => "EEXIST", WouldBlock => "EWOULDBLOCK", + DirectoryNotEmpty => "ENOTEMPTY", _ => { throw_unsup_format!( "io error {:?} cannot be translated into a raw os error", diff --git a/src/lib.rs b/src/lib.rs index 9542fb9b96355..6c9b8ee0b8f98 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -5,6 +5,7 @@ #![feature(try_blocks)] #![feature(let_else)] #![feature(bool_to_option)] +#![feature(io_error_more)] #![warn(rust_2018_idioms)] #![allow(clippy::cast_lossless)] diff --git a/tests/run-pass/fs.rs b/tests/run-pass/fs.rs index be680131f84ab..7f5553e2f2cb9 100644 --- a/tests/run-pass/fs.rs +++ b/tests/run-pass/fs.rs @@ -2,6 +2,7 @@ // compile-flags: -Zmiri-disable-isolation #![feature(rustc_private)] +#![feature(io_error_more)] extern crate libc; @@ -380,6 +381,8 @@ fn test_directory() { let mut file_names = dir_iter.map(|e| e.unwrap().file_name()).collect::>(); file_names.sort_unstable(); assert_eq!(file_names, vec!["test_file_1", "test_file_2"]); + // Deleting the directory should fail, since it is not empty. + assert_eq!(ErrorKind::DirectoryNotEmpty, remove_dir(&dir_path).unwrap_err().kind()); // Clean up the files in the directory remove_file(&path_1).unwrap(); remove_file(&path_2).unwrap(); From d54c5fb66824246a836f36e6bcf43ce41e356805 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 7 Mar 2022 19:57:44 -0500 Subject: [PATCH 2924/3747] rustup --- rust-version | 2 +- src/shims/backtrace.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/rust-version b/rust-version index dcc365ef0ad9b..de3e19e6b04d9 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -d137c3a7bd3b180317044f8ccb9a8b4b3bb07db3 +89adcc636f94d34a6fc90fa117e28ddf6be7b983 diff --git a/src/shims/backtrace.rs b/src/shims/backtrace.rs index eb25cfd9935ff..a73c78b627286 100644 --- a/src/shims/backtrace.rs +++ b/src/shims/backtrace.rs @@ -105,7 +105,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // which we pass to user code. let fn_ptr = this.memory.create_fn_alloc(FnVal::Instance(fn_instance)); - let num_fields = dest.layout.layout.fields.count(); + let num_fields = dest.layout.fields.count(); if !(4..=5).contains(&num_fields) { // Always mention 5 fields, since the 4-field struct From 3eba7fcf7336c7cebdea4b2c2140c947b6bac67c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 9 Mar 2022 18:48:31 -0500 Subject: [PATCH 2925/3747] implement simd_shuffle --- src/shims/intrinsics.rs | 41 ++++++++++++++++++++++++++++++++- tests/run-pass/portable-simd.rs | 12 ++++++++++ 2 files changed, 52 insertions(+), 1 deletion(-) diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 49c9c0fb0d965..43c61091b9e4d 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -3,7 +3,7 @@ use std::iter; use log::trace; use rustc_apfloat::{Float, Round}; -use rustc_middle::ty::layout::{IntegerExt, LayoutOf}; +use rustc_middle::ty::layout::{HasParamEnv, IntegerExt, LayoutOf}; use rustc_middle::{mir, mir::BinOp, ty, ty::FloatTy}; use rustc_target::abi::{Align, Integer}; @@ -614,6 +614,45 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_immediate(val, &dest.into())?; } } + "simd_shuffle" => { + let &[ref left, ref right, ref index] = check_arg_count(args)?; + let (left, left_len) = this.operand_to_simd(left)?; + let (right, right_len) = this.operand_to_simd(right)?; + let (dest, dest_len) = this.place_to_simd(dest)?; + + // `index` is an array, not a SIMD type + let ty::Array(_, index_len) = index.layout.ty.kind() else { + bug!("simd_shuffle index argument has non-array type {}", index.layout.ty) + }; + let index_len = index_len.eval_usize(*this.tcx, this.param_env()); + + assert_eq!(left_len, right_len); + assert_eq!(index_len, dest_len); + + for i in 0..dest_len { + let src_index: u64 = this + .read_immediate(&this.operand_index(&index, i)?.into())? + .to_scalar()? + .to_u32()? + .into(); + let dest = this.mplace_index(&dest, i)?; + + let val = if src_index < left_len { + this.read_immediate(&this.mplace_index(&left, src_index)?.into())? + } else if src_index < left_len.checked_add(right_len).unwrap() { + this.read_immediate( + &this.mplace_index(&right, src_index - left_len)?.into(), + )? + } else { + bug!( + "simd_shuffle index {} is out of bounds for 2 vectors of size {}", + src_index, + left_len + ); + }; + this.write_immediate(*val, &dest.into())?; + } + } // Atomic operations "atomic_load" => this.atomic_load(args, dest, AtomicReadOp::SeqCst)?, diff --git a/tests/run-pass/portable-simd.rs b/tests/run-pass/portable-simd.rs index b87bd4fd6ad2a..67e4e52a7849e 100644 --- a/tests/run-pass/portable-simd.rs +++ b/tests/run-pass/portable-simd.rs @@ -238,6 +238,17 @@ fn simd_cast() { } } +fn simd_swizzle() { + use Which::*; + + let a = f32x4::splat(10.0); + let b = f32x4::from_array([1.0, 2.0, 3.0, -4.0]); + + assert_eq!(simd_swizzle!(b, [3, 0, 0, 2]), f32x4::from_array([-4.0, 1.0, 1.0, 3.0])); + assert_eq!(simd_swizzle!(b, [1, 2]), f32x2::from_array([2.0, 3.0])); + assert_eq!(simd_swizzle!(b, a, [First(3), Second(0)]), f32x2::from_array([-4.0, 10.0])); +} + fn simd_intrinsics() { extern "platform-intrinsic" { fn simd_eq(x: T, y: T) -> U; @@ -276,5 +287,6 @@ fn main() { simd_ops_f64(); simd_ops_i32(); simd_cast(); + simd_swizzle(); simd_intrinsics(); } From 576e2bbed5cfa26fdab2af62e1372d1f8fa581d1 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 9 Mar 2022 19:18:07 -0500 Subject: [PATCH 2926/3747] implement gather --- src/shims/intrinsics.rs | 27 ++++++++++++++++++++ tests/compile-fail/intrinsics/simd-gather.rs | 9 +++++++ tests/run-pass/portable-simd.rs | 8 ++++++ 3 files changed, 44 insertions(+) create mode 100644 tests/compile-fail/intrinsics/simd-gather.rs diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 43c61091b9e4d..54e7118b25936 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -653,6 +653,33 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_immediate(*val, &dest.into())?; } } + "simd_gather" => { + let &[ref passthru, ref ptrs, ref mask] = check_arg_count(args)?; + let (passthru, passthru_len) = this.operand_to_simd(passthru)?; + let (ptrs, ptrs_len) = this.operand_to_simd(ptrs)?; + let (mask, mask_len) = this.operand_to_simd(mask)?; + let (dest, dest_len) = this.place_to_simd(dest)?; + + assert_eq!(dest_len, passthru_len); + assert_eq!(dest_len, ptrs_len); + assert_eq!(dest_len, mask_len); + + for i in 0..dest_len { + let passthru = this.read_immediate(&this.mplace_index(&passthru, i)?.into())?; + let ptr = this.read_immediate(&this.mplace_index(&ptrs, i)?.into())?; + let mask = this.read_immediate(&this.mplace_index(&mask, i)?.into())?; + let dest = this.mplace_index(&dest, i)?; + + let mask = simd_element_to_bool(mask)?; + let val = if mask { + let place = this.deref_operand(&ptr.into())?; + this.read_immediate(&place.into())? + } else { + passthru + }; + this.write_immediate(*val, &dest.into())?; + } + } // Atomic operations "atomic_load" => this.atomic_load(args, dest, AtomicReadOp::SeqCst)?, diff --git a/tests/compile-fail/intrinsics/simd-gather.rs b/tests/compile-fail/intrinsics/simd-gather.rs new file mode 100644 index 0000000000000..2fb5da01f1067 --- /dev/null +++ b/tests/compile-fail/intrinsics/simd-gather.rs @@ -0,0 +1,9 @@ +// error-pattern: out-of-bounds +#![feature(portable_simd)] +use std::simd::*; + +fn main() { unsafe { + let vec: &[i16] = &[10, 11, 12, 13, 14, 15, 16, 17, 18]; + let idxs = Simd::from_array([9, 3, 0, 17]); + let _result = Simd::gather_select_unchecked(&vec, Mask::splat(true), idxs, Simd::splat(0)); +} } diff --git a/tests/run-pass/portable-simd.rs b/tests/run-pass/portable-simd.rs index 67e4e52a7849e..ad9dafea4bada 100644 --- a/tests/run-pass/portable-simd.rs +++ b/tests/run-pass/portable-simd.rs @@ -249,6 +249,13 @@ fn simd_swizzle() { assert_eq!(simd_swizzle!(b, a, [First(3), Second(0)]), f32x2::from_array([-4.0, 10.0])); } +fn simd_gather_scatter() { + let vec: &[i16] = &[10, 11, 12, 13, 14, 15, 16, 17, 18]; + let idxs = Simd::from_array([9, 3, 0, 17]); + let result = Simd::gather_or_default(&vec, idxs); // Note the lane that is out-of-bounds. + assert_eq!(result, Simd::from_array([0, 13, 10, 0])); +} + fn simd_intrinsics() { extern "platform-intrinsic" { fn simd_eq(x: T, y: T) -> U; @@ -288,5 +295,6 @@ fn main() { simd_ops_i32(); simd_cast(); simd_swizzle(); + simd_gather_scatter(); simd_intrinsics(); } From 41ffce1145efd87e23878ce0802a52557b24d852 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 9 Mar 2022 19:26:40 -0500 Subject: [PATCH 2927/3747] implement simd_scatter --- src/shims/intrinsics.rs | 26 ++++++++++++++++--- tests/compile-fail/intrinsics/simd-gather.rs | 4 +-- tests/compile-fail/intrinsics/simd-scatter.rs | 9 +++++++ tests/run-pass/portable-simd.rs | 6 ++++- 4 files changed, 38 insertions(+), 7 deletions(-) create mode 100644 tests/compile-fail/intrinsics/simd-scatter.rs diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 54e7118b25936..b4416bfa98598 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -570,8 +570,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let no = this.read_immediate(&this.mplace_index(&no, i)?.into())?; let dest = this.mplace_index(&dest, i)?; - let mask = simd_element_to_bool(mask)?; - let val = if mask { yes } else { no }; + let val = if simd_element_to_bool(mask)? { yes } else { no }; this.write_immediate(*val, &dest.into())?; } } @@ -670,8 +669,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let mask = this.read_immediate(&this.mplace_index(&mask, i)?.into())?; let dest = this.mplace_index(&dest, i)?; - let mask = simd_element_to_bool(mask)?; - let val = if mask { + let val = if simd_element_to_bool(mask)? { let place = this.deref_operand(&ptr.into())?; this.read_immediate(&place.into())? } else { @@ -680,6 +678,26 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_immediate(*val, &dest.into())?; } } + "simd_scatter" => { + let &[ref value, ref ptrs, ref mask] = check_arg_count(args)?; + let (value, value_len) = this.operand_to_simd(value)?; + let (ptrs, ptrs_len) = this.operand_to_simd(ptrs)?; + let (mask, mask_len) = this.operand_to_simd(mask)?; + + assert_eq!(ptrs_len, value_len); + assert_eq!(ptrs_len, mask_len); + + for i in 0..ptrs_len { + let value = this.read_immediate(&this.mplace_index(&value, i)?.into())?; + let ptr = this.read_immediate(&this.mplace_index(&ptrs, i)?.into())?; + let mask = this.read_immediate(&this.mplace_index(&mask, i)?.into())?; + + if simd_element_to_bool(mask)? { + let place = this.deref_operand(&ptr.into())?; + this.write_immediate(*value, &place.into())?; + } + } + } // Atomic operations "atomic_load" => this.atomic_load(args, dest, AtomicReadOp::SeqCst)?, diff --git a/tests/compile-fail/intrinsics/simd-gather.rs b/tests/compile-fail/intrinsics/simd-gather.rs index 2fb5da01f1067..ae6f048226ddb 100644 --- a/tests/compile-fail/intrinsics/simd-gather.rs +++ b/tests/compile-fail/intrinsics/simd-gather.rs @@ -1,9 +1,9 @@ -// error-pattern: out-of-bounds +// error-pattern: pointer to 1 byte starting at offset 9 is out-of-bounds #![feature(portable_simd)] use std::simd::*; fn main() { unsafe { - let vec: &[i16] = &[10, 11, 12, 13, 14, 15, 16, 17, 18]; + let vec: &[i8] = &[10, 11, 12, 13, 14, 15, 16, 17, 18]; let idxs = Simd::from_array([9, 3, 0, 17]); let _result = Simd::gather_select_unchecked(&vec, Mask::splat(true), idxs, Simd::splat(0)); } } diff --git a/tests/compile-fail/intrinsics/simd-scatter.rs b/tests/compile-fail/intrinsics/simd-scatter.rs new file mode 100644 index 0000000000000..f46e4f0d4f6a8 --- /dev/null +++ b/tests/compile-fail/intrinsics/simd-scatter.rs @@ -0,0 +1,9 @@ +// error-pattern: pointer to 1 byte starting at offset 9 is out-of-bounds +#![feature(portable_simd)] +use std::simd::*; + +fn main() { unsafe { + let mut vec: Vec = vec![10, 11, 12, 13, 14, 15, 16, 17, 18]; + let idxs = Simd::from_array([9, 3, 0, 17]); + Simd::from_array([-27, 82, -41, 124]).scatter_select_unchecked(&mut vec, Mask::splat(true), idxs); +} } diff --git a/tests/run-pass/portable-simd.rs b/tests/run-pass/portable-simd.rs index ad9dafea4bada..c046af0bcf52a 100644 --- a/tests/run-pass/portable-simd.rs +++ b/tests/run-pass/portable-simd.rs @@ -250,10 +250,14 @@ fn simd_swizzle() { } fn simd_gather_scatter() { - let vec: &[i16] = &[10, 11, 12, 13, 14, 15, 16, 17, 18]; + let mut vec: Vec = vec![10, 11, 12, 13, 14, 15, 16, 17, 18]; let idxs = Simd::from_array([9, 3, 0, 17]); let result = Simd::gather_or_default(&vec, idxs); // Note the lane that is out-of-bounds. assert_eq!(result, Simd::from_array([0, 13, 10, 0])); + + let idxs = Simd::from_array([9, 3, 0, 0]); + Simd::from_array([-27, 82, -41, 124]).scatter(&mut vec, idxs); + assert_eq!(vec, vec![124, 11, 12, 82, 14, 15, 16, 17, 18]); } fn simd_intrinsics() { From bae720c75b10faf78ebe387bb51c2547daebd34b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 10 Mar 2022 18:56:19 -0500 Subject: [PATCH 2928/3747] add ptr_offset_from OOB test, and update test errors --- tests/compile-fail/intrinsics/copy_null.rs | 2 +- tests/compile-fail/intrinsics/ptr_offset_0_plus_0.rs | 2 +- tests/compile-fail/intrinsics/ptr_offset_from_oob.rs | 11 +++++++++++ tests/compile-fail/intrinsics/write_bytes_null.rs | 2 +- tests/compile-fail/null_pointer_deref_zst.rs | 2 +- tests/compile-fail/null_pointer_write_zst.rs | 2 +- 6 files changed, 16 insertions(+), 5 deletions(-) create mode 100644 tests/compile-fail/intrinsics/ptr_offset_from_oob.rs diff --git a/tests/compile-fail/intrinsics/copy_null.rs b/tests/compile-fail/intrinsics/copy_null.rs index 60cb7e4eff513..8f32ad1a760ff 100644 --- a/tests/compile-fail/intrinsics/copy_null.rs +++ b/tests/compile-fail/intrinsics/copy_null.rs @@ -9,5 +9,5 @@ fn main() { let mut data = [0u16; 4]; let ptr = &mut data[0] as *mut u16; // Even copying 0 elements from NULL should error. - unsafe { copy_nonoverlapping(std::ptr::null(), ptr, 0); } //~ ERROR: memory access failed: 0x0 is not a valid pointer + unsafe { copy_nonoverlapping(std::ptr::null(), ptr, 0); } //~ ERROR: memory access failed: null pointer is not a valid pointer } diff --git a/tests/compile-fail/intrinsics/ptr_offset_0_plus_0.rs b/tests/compile-fail/intrinsics/ptr_offset_0_plus_0.rs index d8a8f66e7aeed..248d85d65e24b 100644 --- a/tests/compile-fail/intrinsics/ptr_offset_0_plus_0.rs +++ b/tests/compile-fail/intrinsics/ptr_offset_0_plus_0.rs @@ -1,4 +1,4 @@ -// error-pattern: pointer arithmetic failed: 0x0 is not a valid pointer +// error-pattern: pointer arithmetic failed: null pointer is not a valid pointer fn main() { let x = 0 as *mut i32; diff --git a/tests/compile-fail/intrinsics/ptr_offset_from_oob.rs b/tests/compile-fail/intrinsics/ptr_offset_from_oob.rs new file mode 100644 index 0000000000000..ef1ca1e2729d6 --- /dev/null +++ b/tests/compile-fail/intrinsics/ptr_offset_from_oob.rs @@ -0,0 +1,11 @@ +#![feature(core_intrinsics)] + +use std::intrinsics::ptr_offset_from; + +fn main() { + let start_ptr = &4 as *const _ as *const u8; + let length = 10; + let end_ptr = start_ptr.wrapping_add(length); + // Even if the offset is 0, a dangling OOB pointer is not allowed. + unsafe { ptr_offset_from(end_ptr, end_ptr) }; //~ERROR pointer at offset 10 is out-of-bounds +} diff --git a/tests/compile-fail/intrinsics/write_bytes_null.rs b/tests/compile-fail/intrinsics/write_bytes_null.rs index c3f77b27b4ff0..60966f0a94c0d 100644 --- a/tests/compile-fail/intrinsics/write_bytes_null.rs +++ b/tests/compile-fail/intrinsics/write_bytes_null.rs @@ -6,5 +6,5 @@ extern "rust-intrinsic" { } fn main() { - unsafe { write_bytes::(std::ptr::null_mut(), 0, 0) }; //~ ERROR memory access failed: 0x0 is not a valid pointer + unsafe { write_bytes::(std::ptr::null_mut(), 0, 0) }; //~ ERROR memory access failed: null pointer is not a valid pointer } diff --git a/tests/compile-fail/null_pointer_deref_zst.rs b/tests/compile-fail/null_pointer_deref_zst.rs index 04617c58f3cef..f3830c078e5e7 100644 --- a/tests/compile-fail/null_pointer_deref_zst.rs +++ b/tests/compile-fail/null_pointer_deref_zst.rs @@ -3,6 +3,6 @@ #[allow(deref_nullptr)] fn main() { - let x: () = unsafe { *std::ptr::null() }; //~ ERROR dereferencing pointer failed: 0x0 is not a valid pointer + let x: () = unsafe { *std::ptr::null() }; //~ ERROR dereferencing pointer failed: null pointer is not a valid pointer panic!("this should never print: {:?}", x); } diff --git a/tests/compile-fail/null_pointer_write_zst.rs b/tests/compile-fail/null_pointer_write_zst.rs index 46a8345b1b45a..63474d9651756 100644 --- a/tests/compile-fail/null_pointer_write_zst.rs +++ b/tests/compile-fail/null_pointer_write_zst.rs @@ -1,6 +1,6 @@ // Some optimizations remove ZST accesses, thus masking this UB. // compile-flags: -Zmir-opt-level=0 -// error-pattern: memory access failed: 0x0 is not a valid pointer +// error-pattern: memory access failed: null pointer is not a valid pointer #[allow(deref_nullptr)] fn main() { From 21ff2f9fcab1baf240fd46a56806c8598246799a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 11 Mar 2022 22:07:43 -0500 Subject: [PATCH 2929/3747] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index de3e19e6b04d9..a4c6cd44182c1 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -89adcc636f94d34a6fc90fa117e28ddf6be7b983 +2c6a29af35a81e20f8af4c32bf1b55c59b89eccd From 27d5b846eed9f92990f4fc47f0e35f514cfc66f0 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 12 Mar 2022 09:46:10 -0500 Subject: [PATCH 2930/3747] rustup --- rust-version | 2 +- src/helpers.rs | 2 +- src/shims/backtrace.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/rust-version b/rust-version index a4c6cd44182c1..9885aba102934 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -2c6a29af35a81e20f8af4c32bf1b55c59b89eccd +258256697b8550860be0f6194dec532ac616c2c1 diff --git a/src/helpers.rs b/src/helpers.rs index cae8f5ddb4484..e733ea8062dcd 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -298,7 +298,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx trace!("UnsafeCellVisitor: {:?} {:?}", *v, v.layout.ty); let is_unsafe_cell = match v.layout.ty.kind() { ty::Adt(adt, _) => - Some(adt.did) == self.ecx.tcx.lang_items().unsafe_cell_type(), + Some(adt.did()) == self.ecx.tcx.lang_items().unsafe_cell_type(), _ => false, }; if is_unsafe_cell { diff --git a/src/shims/backtrace.rs b/src/shims/backtrace.rs index a73c78b627286..7d069611e2684 100644 --- a/src/shims/backtrace.rs +++ b/src/shims/backtrace.rs @@ -134,7 +134,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let dest = this.force_allocation(dest)?; if let ty::Adt(adt, _) = dest.layout.ty.kind() { - if !adt.repr.c() { + if !adt.repr().c() { throw_ub_format!( "miri_resolve_frame must be declared with a `#[repr(C)]` return type" ); From 9a6450af95dd63c6e4f5ca43feff49313692885c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 12 Mar 2022 10:09:15 -0500 Subject: [PATCH 2931/3747] also accept odd number of hex digits; add README section on randomized alignment testing --- Cargo.lock | 7 ------- Cargo.toml | 1 - README.md | 18 +++++++++++++++++- src/bin/miri.rs | 22 +++++----------------- 4 files changed, 22 insertions(+), 26 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 674ce8a2b1ea7..35e45800c0ed6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -155,12 +155,6 @@ dependencies = [ "libc", ] -[[package]] -name = "hex" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" - [[package]] name = "humantime" version = "2.1.0" @@ -258,7 +252,6 @@ dependencies = [ "compiletest_rs", "env_logger", "getrandom", - "hex", "libc", "log", "measureme", diff --git a/Cargo.toml b/Cargo.toml index a4d85e39e65d7..356f6822fa182 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,7 +22,6 @@ getrandom = { version = "0.2", features = ["std"] } env_logger = "0.9" log = "0.4" shell-escape = "0.1.4" -hex = "0.4.0" rand = "0.8" smallvec = "1.7" diff --git a/README.md b/README.md index 55154356c9da8..8e8670f377517 100644 --- a/README.md +++ b/README.md @@ -175,12 +175,28 @@ Here is an example job for GitHub Actions: The explicit `cargo miri setup` helps to keep the output of the actual test step clean. +### Testing for alignment issues + +Miri can sometimes miss misaligned accesses since allocations can "happen to be" +aligned just right. You can use `-Zmiri-symbolic-alignment-check` to definitely +catch all such issues, but that flag will also cause false positives when code +does manual pointer arithmetic to account for alignment. Another alternative is +to call Miri with various values for `-Zmiri-seed`; that will alter the +randomness that is used to determine allocation base addresses. The following +snippet calls Miri in a loop with different values for the seed: + +``` +for seed in $({ echo obase=16; seq 255; } | bc); do + MIRIFLAGS=-Zmiri-seed=$seed cargo miri test || { echo "Last seed: $seed"; break; }; +done +``` + ### Common Problems When using the above instructions, you may encounter a number of confusing compiler errors. -### "note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace" +#### "note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace" You may see this when trying to get Miri to display a backtrace. By default, Miri doesn't expose any environment to the program, so running diff --git a/src/bin/miri.rs b/src/bin/miri.rs index dd7b0b54f4882..a1f7c617f0af1 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -15,7 +15,6 @@ use std::num::NonZeroU64; use std::path::PathBuf; use std::str::FromStr; -use hex::FromHexError; use log::debug; use rustc_data_structures::sync::Lrc; @@ -377,22 +376,11 @@ fn main() { if miri_config.seed.is_some() { panic!("Cannot specify -Zmiri-seed multiple times!"); } - let seed_raw = hex::decode(arg.strip_prefix("-Zmiri-seed=").unwrap()) - .unwrap_or_else(|err| match err { - FromHexError::InvalidHexCharacter { .. } => panic!( - "-Zmiri-seed should only contain valid hex digits [0-9a-fA-F]" - ), - FromHexError::OddLength => - panic!("-Zmiri-seed should have an even number of digits"), - err => panic!("unknown error decoding -Zmiri-seed as hex: {:?}", err), - }); - if seed_raw.len() > 8 { - panic!("-Zmiri-seed must be at most 8 bytes, was {}", seed_raw.len()); - } - - let mut bytes = [0; 8]; - bytes[..seed_raw.len()].copy_from_slice(&seed_raw); - miri_config.seed = Some(u64::from_be_bytes(bytes)); + let seed = u64::from_str_radix(arg.strip_prefix("-Zmiri-seed=").unwrap(), 16) + .unwrap_or_else(|_| panic!( + "-Zmiri-seed should only contain valid hex digits [0-9a-fA-F] and fit into a u64 (max 16 characters)" + )); + miri_config.seed = Some(seed); } arg if arg.starts_with("-Zmiri-env-exclude=") => { miri_config From 3c5cb89f638af28b8f645fb73a3210fb66bc725f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 12 Mar 2022 10:14:07 -0500 Subject: [PATCH 2932/3747] exclude TERM by default --- README.md | 5 +++-- src/shims/env.rs | 8 +++----- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 55154356c9da8..9c8efbec27673 100644 --- a/README.md +++ b/README.md @@ -254,8 +254,9 @@ environment variable: `warn` prints a full backtrace when that happen; `warn-nobacktrace` is less verbose. `hide` hides the warning entirely. * `-Zmiri-env-exclude=` keeps the `var` environment variable isolated from the host so that it - cannot be accessed by the program. Can be used multiple times to exclude several variables. On - Windows, the `TERM` environment variable is excluded by default. This has no effect unless + cannot be accessed by the program. Can be used multiple times to exclude several variables. The + `TERM` environment variable is excluded by default to [speed up the test + harness](https://github.com/rust-lang/miri/issues/1702). This has no effect unless `-Zmiri-disable-validation` is also set. * `-Zmiri-env-forward=` forwards the `var` environment variable to the interpreted program. Can be used multiple times to forward several variables. This has no effect if diff --git a/src/shims/env.rs b/src/shims/env.rs index fd77286885809..1916d7d70a41e 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -42,11 +42,9 @@ impl<'tcx> EnvVars<'tcx> { forwarded_env_vars: Vec, ) -> InterpResult<'tcx> { let target_os = ecx.tcx.sess.target.os.as_str(); - if target_os == "windows" { - // Temporary hack: Exclude `TERM` var to avoid terminfo trying to open the termcap file. - // Can be removed once https://github.com/rust-lang/miri/issues/1013 is resolved. - excluded_env_vars.push("TERM".to_owned()); - } + // HACK: Exclude `TERM` var to avoid terminfo trying to open the termcap file. + // This is (a) very slow and (b) does not work on Windows. + excluded_env_vars.push("TERM".to_owned()); // Skip the loop entirely if we don't want to forward anything. if ecx.machine.communicate() || !forwarded_env_vars.is_empty() { From 4bd6bc90986987c65f5f3e183032ce0a78fc716b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 12 Mar 2022 10:34:54 -0500 Subject: [PATCH 2933/3747] use dirent64_layout and field projections for writing dirent info --- src/helpers.rs | 12 +++++++++++- src/shims/posix/fs.rs | 20 +++++--------------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index e733ea8062dcd..84792c2394e37 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -104,9 +104,19 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.layout_of(ty) } + /// Write a uint of the appropriate size to `dest`. + fn write_uint(&mut self, i: impl Into, dest: &PlaceTy<'tcx, Tag>) -> InterpResult<'tcx> { + self.eval_context_mut().write_scalar(Scalar::from_uint(i, dest.layout.size), dest) + } + + /// Write an int of the appropriate size to `dest`. + fn write_int(&mut self, i: impl Into, dest: &PlaceTy<'tcx, Tag>) -> InterpResult<'tcx> { + self.eval_context_mut().write_scalar(Scalar::from_int(i, dest.layout.size), dest) + } + /// Write a 0 of the appropriate size to `dest`. fn write_null(&mut self, dest: &PlaceTy<'tcx, Tag>) -> InterpResult<'tcx> { - self.eval_context_mut().write_scalar(Scalar::from_int(0, dest.layout.size), dest) + self.write_int(0, dest) } /// Test if this pointer equals 0. diff --git a/src/shims/posix/fs.rs b/src/shims/posix/fs.rs index 300e3c514b375..efb11b3bee9f6 100644 --- a/src/shims/posix/fs.rs +++ b/src/shims/posix/fs.rs @@ -1270,12 +1270,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let entry = this.malloc(size, /*zero_init:*/ false, MiriMemoryKind::Runtime)?; - // FIXME: make use of dirent64_layout - let ino64_t_layout = this.libc_ty_layout("ino64_t")?; - let off64_t_layout = this.libc_ty_layout("off64_t")?; - let c_ushort_layout = this.libc_ty_layout("c_ushort")?; - let c_uchar_layout = this.libc_ty_layout("c_uchar")?; - // If the host is a Unix system, fill in the inode number with its real value. // If not, use 0 as a fallback value. #[cfg(unix)] @@ -1285,15 +1279,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let file_type = this.file_type_to_d_type(dir_entry.file_type())?; - let imms = [ - immty_from_uint_checked(ino, ino64_t_layout)?, // d_ino - immty_from_uint_checked(0u128, off64_t_layout)?, // d_off - immty_from_uint_checked(size, c_ushort_layout)?, // d_reclen - immty_from_int_checked(file_type, c_uchar_layout)?, // d_type - ]; - let entry_layout = this.layout_of(this.tcx.mk_array(this.tcx.types.u8, size))?; - let entry_place = MPlaceTy::from_aligned_ptr(entry, entry_layout); - this.write_packed_immediates(&entry_place, &imms)?; + let entry_place = MPlaceTy::from_aligned_ptr(entry, dirent64_layout); + this.write_uint(ino, &this.mplace_field(&entry_place, 0)?.into())?; // d_ino + this.write_uint(0u128, &this.mplace_field(&entry_place, 1)?.into())?; // d_off + this.write_uint(size, &this.mplace_field(&entry_place, 2)?.into())?; // d_reclen + this.write_int(file_type, &this.mplace_field(&entry_place, 3)?.into())?; // d_type let name_ptr = entry.offset(Size::from_bytes(d_name_offset), this)?; this.memory.write_bytes(name_ptr, name_bytes.iter().copied())?; From 47f8218d0dfcd9f31185f2628d07a993ba6780f5 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 12 Mar 2022 11:21:45 -0500 Subject: [PATCH 2934/3747] add write_int_fields to replace write_packed_immediates for stat, lookup fields by name --- src/helpers.rs | 122 +++++++++++++------------- src/shims/posix/fs.rs | 194 +++++++++++++++++++++--------------------- src/shims/time.rs | 35 ++------ 3 files changed, 169 insertions(+), 182 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index 84792c2394e37..ba12e0a7e394e 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -57,8 +57,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// Evaluates the scalar at the specified path. Returns Some(val) /// if the path could be resolved, and None otherwise - fn eval_path_scalar(&mut self, path: &[&str]) -> InterpResult<'tcx, Scalar> { - let this = self.eval_context_mut(); + fn eval_path_scalar(&self, path: &[&str]) -> InterpResult<'tcx, Scalar> { + let this = self.eval_context_ref(); let instance = this.resolve_path(path); let cid = GlobalId { instance, promoted: None }; let const_val = this.eval_to_allocation(cid)?; @@ -67,51 +67,98 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } /// Helper function to get a `libc` constant as a `Scalar`. - fn eval_libc(&mut self, name: &str) -> InterpResult<'tcx, Scalar> { - self.eval_context_mut().eval_path_scalar(&["libc", name]) + fn eval_libc(&self, name: &str) -> InterpResult<'tcx, Scalar> { + self.eval_path_scalar(&["libc", name]) } /// Helper function to get a `libc` constant as an `i32`. - fn eval_libc_i32(&mut self, name: &str) -> InterpResult<'tcx, i32> { + fn eval_libc_i32(&self, name: &str) -> InterpResult<'tcx, i32> { // TODO: Cache the result. self.eval_libc(name)?.to_i32() } /// Helper function to get a `windows` constant as a `Scalar`. - fn eval_windows(&mut self, module: &str, name: &str) -> InterpResult<'tcx, Scalar> { - self.eval_context_mut().eval_path_scalar(&["std", "sys", "windows", module, name]) + fn eval_windows(&self, module: &str, name: &str) -> InterpResult<'tcx, Scalar> { + self.eval_context_ref().eval_path_scalar(&["std", "sys", "windows", module, name]) } /// Helper function to get a `windows` constant as a `u64`. - fn eval_windows_u64(&mut self, module: &str, name: &str) -> InterpResult<'tcx, u64> { + fn eval_windows_u64(&self, module: &str, name: &str) -> InterpResult<'tcx, u64> { // TODO: Cache the result. self.eval_windows(module, name)?.to_u64() } /// Helper function to get the `TyAndLayout` of a `libc` type - fn libc_ty_layout(&mut self, name: &str) -> InterpResult<'tcx, TyAndLayout<'tcx>> { - let this = self.eval_context_mut(); + fn libc_ty_layout(&self, name: &str) -> InterpResult<'tcx, TyAndLayout<'tcx>> { + let this = self.eval_context_ref(); let ty = this.resolve_path(&["libc", name]).ty(*this.tcx, ty::ParamEnv::reveal_all()); this.layout_of(ty) } /// Helper function to get the `TyAndLayout` of a `windows` type - fn windows_ty_layout(&mut self, name: &str) -> InterpResult<'tcx, TyAndLayout<'tcx>> { - let this = self.eval_context_mut(); + fn windows_ty_layout(&self, name: &str) -> InterpResult<'tcx, TyAndLayout<'tcx>> { + let this = self.eval_context_ref(); let ty = this .resolve_path(&["std", "sys", "windows", "c", name]) .ty(*this.tcx, ty::ParamEnv::reveal_all()); this.layout_of(ty) } - /// Write a uint of the appropriate size to `dest`. - fn write_uint(&mut self, i: impl Into, dest: &PlaceTy<'tcx, Tag>) -> InterpResult<'tcx> { - self.eval_context_mut().write_scalar(Scalar::from_uint(i, dest.layout.size), dest) + /// Project to the given *named* field of the mplace (which must be a struct or union type). + fn mplace_field_named( + &self, + mplace: &MPlaceTy<'tcx, Tag>, + name: &str, + ) -> InterpResult<'tcx, MPlaceTy<'tcx, Tag>> { + let this = self.eval_context_ref(); + let adt = mplace.layout.ty.ty_adt_def().unwrap(); + for (idx, field) in adt.non_enum_variant().fields.iter().enumerate() { + if field.name.as_str() == name { + return this.mplace_field(mplace, idx); + } + } + bug!("No field named {} in type {}", name, mplace.layout.ty); } - /// Write an int of the appropriate size to `dest`. + /// Write an int of the appropriate size to `dest`. The target type may be signed or unsigned, + /// we try to do the right thing anyway. `i128` can fit all integer types except for `u128` so + /// this method is fine for almost all integer types. fn write_int(&mut self, i: impl Into, dest: &PlaceTy<'tcx, Tag>) -> InterpResult<'tcx> { - self.eval_context_mut().write_scalar(Scalar::from_int(i, dest.layout.size), dest) + assert!(dest.layout.abi.is_scalar(), "write_int on non-scalar type {}", dest.layout.ty); + let val = if dest.layout.abi.is_signed() { + Scalar::from_int(i, dest.layout.size) + } else { + Scalar::from_uint(u64::try_from(i.into()).unwrap(), dest.layout.size) + }; + self.eval_context_mut().write_scalar(val, dest) + } + + /// Write the first N fields of the given place. + fn write_int_fields( + &mut self, + values: &[i128], + dest: &MPlaceTy<'tcx, Tag>, + ) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + for (idx, &val) in values.iter().enumerate() { + let field = this.mplace_field(dest, idx)?; + this.write_int(val, &field.into())?; + } + Ok(()) + } + + /// Write the given fields of the given place. + fn write_int_fields_named( + &mut self, + values: &[(&str, i128)], + dest: &MPlaceTy<'tcx, Tag>, + ) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + for &(name, val) in values.iter() { + let field = this.mplace_field_named(dest, name)?; + this.write_int(val, &field.into())?; + } + Ok(()) } /// Write a 0 of the appropriate size to `dest`. @@ -383,27 +430,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } - // Writes several `ImmTy`s contiguously into memory. This is useful when you have to pack - // different values into a struct. - fn write_packed_immediates( - &mut self, - place: &MPlaceTy<'tcx, Tag>, - imms: &[ImmTy<'tcx, Tag>], - ) -> InterpResult<'tcx> { - let this = self.eval_context_mut(); - - let mut offset = Size::from_bytes(0); - - for &imm in imms { - this.write_immediate( - *imm, - &place.offset(offset, MemPlaceMeta::None, imm.layout, &*this.tcx)?.into(), - )?; - offset += imm.layout.size; - } - Ok(()) - } - /// Helper function used inside the shims of foreign functions to check that isolation is /// disabled. It returns an error using the `name` of the foreign function if this is not the /// case. @@ -750,26 +776,6 @@ pub fn isolation_abort_error(name: &str) -> InterpResult<'static> { ))) } -pub fn immty_from_int_checked<'tcx>( - int: impl Into, - layout: TyAndLayout<'tcx>, -) -> InterpResult<'tcx, ImmTy<'tcx, Tag>> { - let int = int.into(); - Ok(ImmTy::try_from_int(int, layout).ok_or_else(|| { - err_unsup_format!("signed value {:#x} does not fit in {} bits", int, layout.size.bits()) - })?) -} - -pub fn immty_from_uint_checked<'tcx>( - int: impl Into, - layout: TyAndLayout<'tcx>, -) -> InterpResult<'tcx, ImmTy<'tcx, Tag>> { - let int = int.into(); - Ok(ImmTy::try_from_uint(int, layout).ok_or_else(|| { - err_unsup_format!("unsigned value {:#x} does not fit in {} bits", int, layout.size.bits()) - })?) -} - pub fn bool_to_simd_element(b: bool, size: Size) -> Scalar { // SIMD uses all-1 as pattern for "true" let val = if b { -1 } else { 0 }; diff --git a/src/shims/posix/fs.rs b/src/shims/posix/fs.rs index efb11b3bee9f6..b71f53cce566e 100644 --- a/src/shims/posix/fs.rs +++ b/src/shims/posix/fs.rs @@ -15,7 +15,7 @@ use rustc_middle::ty::{self, layout::LayoutOf}; use rustc_target::abi::{Align, Size}; use crate::*; -use helpers::{check_arg_count, immty_from_int_checked, immty_from_uint_checked}; +use helpers::check_arg_count; use shims::os_str::os_str_to_bytes; use shims::time::system_time_to_duration; @@ -318,45 +318,32 @@ trait EvalContextExtPrivate<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, ' let (created_sec, created_nsec) = metadata.created.unwrap_or((0, 0)); let (modified_sec, modified_nsec) = metadata.modified.unwrap_or((0, 0)); - let dev_t_layout = this.libc_ty_layout("dev_t")?; - let mode_t_layout = this.libc_ty_layout("mode_t")?; - let nlink_t_layout = this.libc_ty_layout("nlink_t")?; - let ino_t_layout = this.libc_ty_layout("ino_t")?; - let uid_t_layout = this.libc_ty_layout("uid_t")?; - let gid_t_layout = this.libc_ty_layout("gid_t")?; - let time_t_layout = this.libc_ty_layout("time_t")?; - let long_layout = this.libc_ty_layout("c_long")?; - let off_t_layout = this.libc_ty_layout("off_t")?; - let blkcnt_t_layout = this.libc_ty_layout("blkcnt_t")?; - let blksize_t_layout = this.libc_ty_layout("blksize_t")?; - let uint32_t_layout = this.libc_ty_layout("uint32_t")?; - - let imms = [ - immty_from_uint_checked(0u128, dev_t_layout)?, // st_dev - immty_from_uint_checked(mode, mode_t_layout)?, // st_mode - immty_from_uint_checked(0u128, nlink_t_layout)?, // st_nlink - immty_from_uint_checked(0u128, ino_t_layout)?, // st_ino - immty_from_uint_checked(0u128, uid_t_layout)?, // st_uid - immty_from_uint_checked(0u128, gid_t_layout)?, // st_gid - immty_from_uint_checked(0u128, dev_t_layout)?, // st_rdev - immty_from_uint_checked(0u128, uint32_t_layout)?, // padding - immty_from_uint_checked(access_sec, time_t_layout)?, // st_atime - immty_from_uint_checked(access_nsec, long_layout)?, // st_atime_nsec - immty_from_uint_checked(modified_sec, time_t_layout)?, // st_mtime - immty_from_uint_checked(modified_nsec, long_layout)?, // st_mtime_nsec - immty_from_uint_checked(0u128, time_t_layout)?, // st_ctime - immty_from_uint_checked(0u128, long_layout)?, // st_ctime_nsec - immty_from_uint_checked(created_sec, time_t_layout)?, // st_birthtime - immty_from_uint_checked(created_nsec, long_layout)?, // st_birthtime_nsec - immty_from_uint_checked(metadata.size, off_t_layout)?, // st_size - immty_from_uint_checked(0u128, blkcnt_t_layout)?, // st_blocks - immty_from_uint_checked(0u128, blksize_t_layout)?, // st_blksize - immty_from_uint_checked(0u128, uint32_t_layout)?, // st_flags - immty_from_uint_checked(0u128, uint32_t_layout)?, // st_gen - ]; - let buf = this.deref_operand(buf_op)?; - this.write_packed_immediates(&buf, &imms)?; + this.write_int_fields_named( + &[ + ("st_dev", 0), + ("st_mode", mode.into()), + ("st_nlink", 0), + ("st_ino", 0), + ("st_uid", 0), + ("st_gid", 0), + ("st_rdev", 0), + ("st_atime", access_sec.into()), + ("st_atime_nsec", access_nsec.into()), + ("st_mtime", modified_sec.into()), + ("st_mtime_nsec", modified_nsec.into()), + ("st_ctime", 0), + ("st_ctime_nsec", 0), + ("st_birthtime", created_sec.into()), + ("st_birthtime_nsec", created_nsec.into()), + ("st_size", metadata.size.into()), + ("st_blocks", 0), + ("st_blksize", 0), + ("st_flags", 0), + ("st_gen", 0), + ], + &buf, + )?; Ok(0) } @@ -954,7 +941,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // `syscall` function is untyped. This means that all the `statx` parameters are provided // as `isize`s instead of having the proper types. Thus, we have to recover the layout of // `statxbuf_op` by using the `libc::statx` struct type. - let statxbuf_place = { + let statxbuf = { // FIXME: This long path is required because `libc::statx` is an struct and also a // function and `resolve_path` is returning the latter. let statx_ty = this @@ -1064,44 +1051,55 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx }) .unwrap_or(Ok((0, 0)))?; - let __u32_layout = this.libc_ty_layout("__u32")?; - let __u64_layout = this.libc_ty_layout("__u64")?; - let __u16_layout = this.libc_ty_layout("__u16")?; - - // Now we transform all this fields into `ImmTy`s and write them to `statxbuf`. We write a - // zero for the unavailable fields. - let imms = [ - immty_from_uint_checked(mask, __u32_layout)?, // stx_mask - immty_from_uint_checked(0u128, __u32_layout)?, // stx_blksize - immty_from_uint_checked(0u128, __u64_layout)?, // stx_attributes - immty_from_uint_checked(0u128, __u32_layout)?, // stx_nlink - immty_from_uint_checked(0u128, __u32_layout)?, // stx_uid - immty_from_uint_checked(0u128, __u32_layout)?, // stx_gid - immty_from_uint_checked(mode, __u16_layout)?, // stx_mode - immty_from_uint_checked(0u128, __u16_layout)?, // statx padding - immty_from_uint_checked(0u128, __u64_layout)?, // stx_ino - immty_from_uint_checked(metadata.size, __u64_layout)?, // stx_size - immty_from_uint_checked(0u128, __u64_layout)?, // stx_blocks - immty_from_uint_checked(0u128, __u64_layout)?, // stx_attributes - immty_from_uint_checked(access_sec, __u64_layout)?, // stx_atime.tv_sec - immty_from_uint_checked(access_nsec, __u32_layout)?, // stx_atime.tv_nsec - immty_from_uint_checked(0u128, __u32_layout)?, // statx_timestamp padding - immty_from_uint_checked(created_sec, __u64_layout)?, // stx_btime.tv_sec - immty_from_uint_checked(created_nsec, __u32_layout)?, // stx_btime.tv_nsec - immty_from_uint_checked(0u128, __u32_layout)?, // statx_timestamp padding - immty_from_uint_checked(0u128, __u64_layout)?, // stx_ctime.tv_sec - immty_from_uint_checked(0u128, __u32_layout)?, // stx_ctime.tv_nsec - immty_from_uint_checked(0u128, __u32_layout)?, // statx_timestamp padding - immty_from_uint_checked(modified_sec, __u64_layout)?, // stx_mtime.tv_sec - immty_from_uint_checked(modified_nsec, __u32_layout)?, // stx_mtime.tv_nsec - immty_from_uint_checked(0u128, __u32_layout)?, // statx_timestamp padding - immty_from_uint_checked(0u128, __u64_layout)?, // stx_rdev_major - immty_from_uint_checked(0u128, __u64_layout)?, // stx_rdev_minor - immty_from_uint_checked(0u128, __u64_layout)?, // stx_dev_major - immty_from_uint_checked(0u128, __u64_layout)?, // stx_dev_minor - ]; - - this.write_packed_immediates(&statxbuf_place, &imms)?; + // Now we write everything to `statxbuf`. We write a zero for the unavailable fields. + this.write_int_fields_named( + &[ + ("stx_mask", mask.into()), + ("stx_blksize", 0), + ("stx_attributes", 0), + ("stx_nlink", 0), + ("stx_uid", 0), + ("stx_gid", 0), + ("stx_mode", mode.into()), + ("stx_ino", 0), + ("stx_size", metadata.size.into()), + ("stx_blocks", 0), + ("stx_attributes_mask", 0), + ("stx_rdev_major", 0), + ("stx_rdev_minor", 0), + ("stx_dev_major", 0), + ("stx_dev_minor", 0), + ], + &statxbuf, + )?; + this.write_int_fields( + &[ + access_sec.into(), // stx_atime.tv_sec + access_nsec.into(), // stx_atime.tv_nsec + ], + &this.mplace_field_named(&statxbuf, "stx_atime")?, + )?; + this.write_int_fields( + &[ + created_sec.into(), // stx_btime.tv_sec + created_nsec.into(), // stx_btime.tv_nsec + ], + &this.mplace_field_named(&statxbuf, "stx_btime")?, + )?; + this.write_int_fields( + &[ + 0.into(), // stx_ctime.tv_sec + 0.into(), // stx_ctime.tv_nsec + ], + &this.mplace_field_named(&statxbuf, "stx_ctime")?, + )?; + this.write_int_fields( + &[ + modified_sec.into(), // stx_mtime.tv_sec + modified_nsec.into(), // stx_mtime.tv_nsec + ], + &this.mplace_field_named(&statxbuf, "stx_mtime")?, + )?; Ok(0) } @@ -1247,7 +1245,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Some(Ok(dir_entry)) => { // Write the directory entry into a newly allocated buffer. // The name is written with write_bytes, while the rest of the - // dirent64 struct is written using write_packed_immediates. + // dirent64 struct is written using write_int_fields. // For reference: // pub struct dirent64 { @@ -1279,11 +1277,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let file_type = this.file_type_to_d_type(dir_entry.file_type())?; - let entry_place = MPlaceTy::from_aligned_ptr(entry, dirent64_layout); - this.write_uint(ino, &this.mplace_field(&entry_place, 0)?.into())?; // d_ino - this.write_uint(0u128, &this.mplace_field(&entry_place, 1)?.into())?; // d_off - this.write_uint(size, &this.mplace_field(&entry_place, 2)?.into())?; // d_reclen - this.write_int(file_type, &this.mplace_field(&entry_place, 3)?.into())?; // d_type + this.write_int_fields( + &[ + ino.into(), // d_ino + 0, // d_off + size.into(), // d_reclen + file_type.into(), // d_type + ], + &MPlaceTy::from_aligned_ptr(entry, dirent64_layout), + )?; let name_ptr = entry.offset(Size::from_bytes(d_name_offset), this)?; this.memory.write_bytes(name_ptr, name_bytes.iter().copied())?; @@ -1333,7 +1335,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Some(Ok(dir_entry)) => { // Write into entry, write pointer to result, return 0 on success. // The name is written with write_os_str_to_c_str, while the rest of the - // dirent struct is written using write_packed_Immediates. + // dirent struct is written using write_int_fields. // For reference: // pub struct dirent { @@ -1361,10 +1363,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } let entry_place = this.deref_operand(entry_op)?; - let ino_t_layout = this.libc_ty_layout("ino_t")?; - let off_t_layout = this.libc_ty_layout("off_t")?; - let c_ushort_layout = this.libc_ty_layout("c_ushort")?; - let c_uchar_layout = this.libc_ty_layout("c_uchar")?; // If the host is a Unix system, fill in the inode number with its real value. // If not, use 0 as a fallback value. @@ -1375,14 +1373,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let file_type = this.file_type_to_d_type(dir_entry.file_type())?; - let imms = [ - immty_from_uint_checked(ino, ino_t_layout)?, // d_ino - immty_from_uint_checked(0u128, off_t_layout)?, // d_seekoff - immty_from_uint_checked(0u128, c_ushort_layout)?, // d_reclen - immty_from_uint_checked(file_name_len, c_ushort_layout)?, // d_namlen - immty_from_int_checked(file_type, c_uchar_layout)?, // d_type - ]; - this.write_packed_immediates(&entry_place, &imms)?; + this.write_int_fields( + &[ + ino.into(), // d_ino + 0, // d_seekoff + 0, // d_reclen + file_name_len.into(), // d_namlen + file_type.into(), // d_type + ], + &entry_place, + )?; let result_place = this.deref_operand(result_op)?; this.write_scalar(this.read_scalar(entry_op)?, &result_place.into())?; diff --git a/src/shims/time.rs b/src/shims/time.rs index 1db9d85debdc1..0acd697fa4050 100644 --- a/src/shims/time.rs +++ b/src/shims/time.rs @@ -2,7 +2,6 @@ use std::convert::TryFrom; use std::time::{Duration, Instant, SystemTime}; use crate::*; -use helpers::{immty_from_int_checked, immty_from_uint_checked}; use thread::Time; /// Returns the time elapsed between the provided time and the unix epoch as a `Duration`. @@ -24,7 +23,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.check_no_isolation("`clock_gettime`")?; let clk_id = this.read_scalar(clk_id_op)?.to_i32()?; - let tp = this.deref_operand(tp_op)?; let duration = if clk_id == this.eval_libc_i32("CLOCK_REALTIME")? { system_time_to_duration(&SystemTime::now())? @@ -41,12 +39,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let tv_sec = duration.as_secs(); let tv_nsec = duration.subsec_nanos(); - let imms = [ - immty_from_int_checked(tv_sec, this.libc_ty_layout("time_t")?)?, - immty_from_int_checked(tv_nsec, this.libc_ty_layout("c_long")?)?, - ]; - - this.write_packed_immediates(&tp, &imms)?; + this.write_int_fields(&[tv_sec.into(), tv_nsec.into()], &this.deref_operand(tp_op)?)?; Ok(0) } @@ -69,18 +62,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx return Ok(-1); } - let tv = this.deref_operand(tv_op)?; - let duration = system_time_to_duration(&SystemTime::now())?; let tv_sec = duration.as_secs(); let tv_usec = duration.subsec_micros(); - let imms = [ - immty_from_int_checked(tv_sec, this.libc_ty_layout("time_t")?)?, - immty_from_int_checked(tv_usec, this.libc_ty_layout("suseconds_t")?)?, - ]; - - this.write_packed_immediates(&tv, &imms)?; + this.write_int_fields(&[tv_sec.into(), tv_usec.into()], &this.deref_operand(tv_op)?)?; Ok(0) } @@ -105,12 +91,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let dwLowDateTime = u32::try_from(duration_ticks & 0x00000000FFFFFFFF).unwrap(); let dwHighDateTime = u32::try_from((duration_ticks & 0xFFFFFFFF00000000) >> 32).unwrap(); - let DWORD_tylayout = this.machine.layouts.u32; - let imms = [ - immty_from_uint_checked(dwLowDateTime, DWORD_tylayout)?, - immty_from_uint_checked(dwHighDateTime, DWORD_tylayout)?, - ]; - this.write_packed_immediates(&this.deref_operand(LPFILETIME_op)?, &imms)?; + this.write_int_fields( + &[dwLowDateTime.into(), dwHighDateTime.into()], + &this.deref_operand(LPFILETIME_op)?, + )?; + Ok(()) } @@ -185,12 +170,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Since our emulated ticks in `mach_absolute_time` *are* nanoseconds, // no scaling needs to happen. let (numer, denom) = (1, 1); - let imms = [ - immty_from_int_checked(numer, this.machine.layouts.u32)?, - immty_from_int_checked(denom, this.machine.layouts.u32)?, - ]; + this.write_int_fields(&[numer.into(), denom.into()], &info)?; - this.write_packed_immediates(&info, &imms)?; Ok(0) // KERN_SUCCESS } From 61bfa8afe828a94aaaa7ebb0dac110fd91644bb4 Mon Sep 17 00:00:00 2001 From: Jubilee Young Date: Sun, 13 Mar 2022 18:02:22 -0700 Subject: [PATCH 2935/3747] Fixup renamed fn for Simd --- rust-version | 2 +- tests/run-pass/portable-simd.rs | 76 ++++++++++++++++----------------- 2 files changed, 39 insertions(+), 39 deletions(-) diff --git a/rust-version b/rust-version index 9885aba102934..5306a4d186284 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -258256697b8550860be0f6194dec532ac616c2c1 +e95b10ba4ac4564ed25f7eef143e3182c33b3902 diff --git a/tests/run-pass/portable-simd.rs b/tests/run-pass/portable-simd.rs index c046af0bcf52a..eca8e8f377d6d 100644 --- a/tests/run-pass/portable-simd.rs +++ b/tests/run-pass/portable-simd.rs @@ -22,27 +22,27 @@ fn simd_ops_f32() { assert_eq!(a.lanes_ge(f32x4::splat(5.0) * b), Mask::from_array([true, true, false, true])); assert_eq!(a.lanes_gt(f32x4::splat(5.0) * b), Mask::from_array([true, false, false, true])); - assert_eq!(a.horizontal_sum(), 40.0); - assert_eq!(b.horizontal_sum(), 2.0); - assert_eq!(a.horizontal_product(), 100.0 * 100.0); - assert_eq!(b.horizontal_product(), -24.0); - assert_eq!(a.horizontal_max(), 10.0); - assert_eq!(b.horizontal_max(), 3.0); - assert_eq!(a.horizontal_min(), 10.0); - assert_eq!(b.horizontal_min(), -4.0); + assert_eq!(a.reduce_sum(), 40.0); + assert_eq!(b.reduce_sum(), 2.0); + assert_eq!(a.reduce_product(), 100.0 * 100.0); + assert_eq!(b.reduce_product(), -24.0); + assert_eq!(a.reduce_max(), 10.0); + assert_eq!(b.reduce_max(), 3.0); + assert_eq!(a.reduce_min(), 10.0); + assert_eq!(b.reduce_min(), -4.0); assert_eq!( f32x2::from_array([0.0, f32::NAN]).max(f32x2::from_array([f32::NAN, 0.0])), f32x2::from_array([0.0, 0.0]) ); - assert_eq!(f32x2::from_array([0.0, f32::NAN]).horizontal_max(), 0.0); - assert_eq!(f32x2::from_array([f32::NAN, 0.0]).horizontal_max(), 0.0); + assert_eq!(f32x2::from_array([0.0, f32::NAN]).reduce_max(), 0.0); + assert_eq!(f32x2::from_array([f32::NAN, 0.0]).reduce_max(), 0.0); assert_eq!( f32x2::from_array([0.0, f32::NAN]).min(f32x2::from_array([f32::NAN, 0.0])), f32x2::from_array([0.0, 0.0]) ); - assert_eq!(f32x2::from_array([0.0, f32::NAN]).horizontal_min(), 0.0); - assert_eq!(f32x2::from_array([f32::NAN, 0.0]).horizontal_min(), 0.0); + assert_eq!(f32x2::from_array([0.0, f32::NAN]).reduce_min(), 0.0); + assert_eq!(f32x2::from_array([f32::NAN, 0.0]).reduce_min(), 0.0); } fn simd_ops_f64() { @@ -66,27 +66,27 @@ fn simd_ops_f64() { assert_eq!(a.lanes_ge(f64x4::splat(5.0) * b), Mask::from_array([true, true, false, true])); assert_eq!(a.lanes_gt(f64x4::splat(5.0) * b), Mask::from_array([true, false, false, true])); - assert_eq!(a.horizontal_sum(), 40.0); - assert_eq!(b.horizontal_sum(), 2.0); - assert_eq!(a.horizontal_product(), 100.0 * 100.0); - assert_eq!(b.horizontal_product(), -24.0); - assert_eq!(a.horizontal_max(), 10.0); - assert_eq!(b.horizontal_max(), 3.0); - assert_eq!(a.horizontal_min(), 10.0); - assert_eq!(b.horizontal_min(), -4.0); + assert_eq!(a.reduce_sum(), 40.0); + assert_eq!(b.reduce_sum(), 2.0); + assert_eq!(a.reduce_product(), 100.0 * 100.0); + assert_eq!(b.reduce_product(), -24.0); + assert_eq!(a.reduce_max(), 10.0); + assert_eq!(b.reduce_max(), 3.0); + assert_eq!(a.reduce_min(), 10.0); + assert_eq!(b.reduce_min(), -4.0); assert_eq!( f64x2::from_array([0.0, f64::NAN]).max(f64x2::from_array([f64::NAN, 0.0])), f64x2::from_array([0.0, 0.0]) ); - assert_eq!(f64x2::from_array([0.0, f64::NAN]).horizontal_max(), 0.0); - assert_eq!(f64x2::from_array([f64::NAN, 0.0]).horizontal_max(), 0.0); + assert_eq!(f64x2::from_array([0.0, f64::NAN]).reduce_max(), 0.0); + assert_eq!(f64x2::from_array([f64::NAN, 0.0]).reduce_max(), 0.0); assert_eq!( f64x2::from_array([0.0, f64::NAN]).min(f64x2::from_array([f64::NAN, 0.0])), f64x2::from_array([0.0, 0.0]) ); - assert_eq!(f64x2::from_array([0.0, f64::NAN]).horizontal_min(), 0.0); - assert_eq!(f64x2::from_array([f64::NAN, 0.0]).horizontal_min(), 0.0); + assert_eq!(f64x2::from_array([0.0, f64::NAN]).reduce_min(), 0.0); + assert_eq!(f64x2::from_array([f64::NAN, 0.0]).reduce_min(), 0.0); } fn simd_ops_i32() { @@ -137,21 +137,21 @@ fn simd_ops_i32() { assert_eq!(a.lanes_ge(i32x4::splat(5) * b), Mask::from_array([true, true, false, true])); assert_eq!(a.lanes_gt(i32x4::splat(5) * b), Mask::from_array([true, false, false, true])); - assert_eq!(a.horizontal_sum(), 40); - assert_eq!(b.horizontal_sum(), 2); - assert_eq!(a.horizontal_product(), 100 * 100); - assert_eq!(b.horizontal_product(), -24); - assert_eq!(a.horizontal_max(), 10); - assert_eq!(b.horizontal_max(), 3); - assert_eq!(a.horizontal_min(), 10); - assert_eq!(b.horizontal_min(), -4); + assert_eq!(a.reduce_sum(), 40); + assert_eq!(b.reduce_sum(), 2); + assert_eq!(a.reduce_product(), 100 * 100); + assert_eq!(b.reduce_product(), -24); + assert_eq!(a.reduce_max(), 10); + assert_eq!(b.reduce_max(), 3); + assert_eq!(a.reduce_min(), 10); + assert_eq!(b.reduce_min(), -4); - assert_eq!(a.horizontal_and(), 10); - assert_eq!(b.horizontal_and(), 0); - assert_eq!(a.horizontal_or(), 10); - assert_eq!(b.horizontal_or(), -1); - assert_eq!(a.horizontal_xor(), 0); - assert_eq!(b.horizontal_xor(), -4); + assert_eq!(a.reduce_and(), 10); + assert_eq!(b.reduce_and(), 0); + assert_eq!(a.reduce_or(), 10); + assert_eq!(b.reduce_or(), -1); + assert_eq!(a.reduce_xor(), 0); + assert_eq!(b.reduce_xor(), -4); } fn simd_mask() { From f338b0229b16cabe6e8b02664d15aee2ed83603d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 12 Mar 2022 14:42:06 -0500 Subject: [PATCH 2936/3747] test integer SIMD min/max --- tests/run-pass/portable-simd.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/tests/run-pass/portable-simd.rs b/tests/run-pass/portable-simd.rs index eca8e8f377d6d..28b9a1b03d94c 100644 --- a/tests/run-pass/portable-simd.rs +++ b/tests/run-pass/portable-simd.rs @@ -102,9 +102,8 @@ fn simd_ops_i32() { assert_eq!(a % b, i32x4::from_array([0, 0, 1, 2])); assert_eq!(i32x2::splat(i32::MIN) % i32x2::splat(-1), i32x2::splat(0)); assert_eq!(b.abs(), i32x4::from_array([1, 2, 3, 4])); - // FIXME not a per-lane method (https://github.com/rust-lang/portable-simd/issues/247) - // assert_eq!(a.max(b * i32x4::splat(4)), i32x4::from_array([10, 10, 12, 10])); - // assert_eq!(a.min(b * i32x4::splat(4)), i32x4::from_array([4, 8, 10, -16])); + assert_eq!(a.max(b * i32x4::splat(4)), i32x4::from_array([10, 10, 12, 10])); + assert_eq!(a.min(b * i32x4::splat(4)), i32x4::from_array([4, 8, 10, -16])); assert_eq!( i8x4::from_array([i8::MAX, -23, 23, i8::MIN]).saturating_add(i8x4::from_array([1, i8::MIN, i8::MAX, 28])), From 559e4951953f9139cfd6fb4c614882ab99232676 Mon Sep 17 00:00:00 2001 From: Jake Vossen Date: Wed, 16 Mar 2022 10:18:51 -0600 Subject: [PATCH 2937/3747] missing backtick on miri-isolation warning help --- src/diagnostics.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/diagnostics.rs b/src/diagnostics.rs index 3bf8c7bc17bba..1ccf3c5dba732 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -150,7 +150,7 @@ pub fn report_error<'tcx, 'mir>( UnsupportedInIsolation(_) => vec![ (None, format!("pass the flag `-Zmiri-disable-isolation` to disable isolation;")), - (None, format!("or pass `-Zmiri-isolation-error=warn to configure Miri to return an error code from isolated operations (if supported for that operation) and continue with a warning")), + (None, format!("or pass `-Zmiri-isolation-error=warn` to configure Miri to return an error code from isolated operations (if supported for that operation) and continue with a warning")), ], ExperimentalUb { url, .. } => vec![ From 202964127b0874ac9aa0e10e7baa7ae4ef576908 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 16 Mar 2022 18:33:59 -0400 Subject: [PATCH 2938/3747] implement fabs using soft floats --- src/shims/intrinsics.rs | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index b4416bfa98598..24aeb448912b4 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -90,9 +90,20 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // Floating-point operations + "fabsf32" => { + let &[ref f] = check_arg_count(args)?; + let f = this.read_scalar(f)?.to_f32()?; + // Can be implemented in soft-floats. + this.write_scalar(Scalar::from_f32(f.abs()), dest)?; + } + "fabsf64" => { + let &[ref f] = check_arg_count(args)?; + let f = this.read_scalar(f)?.to_f64()?; + // Can be implemented in soft-floats. + this.write_scalar(Scalar::from_f64(f.abs()), dest)?; + } #[rustfmt::skip] | "sinf32" - | "fabsf32" | "cosf32" | "sqrtf32" | "expf32" @@ -110,7 +121,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let f = f32::from_bits(this.read_scalar(f)?.to_u32()?); let f = match intrinsic_name { "sinf32" => f.sin(), - "fabsf32" => f.abs(), "cosf32" => f.cos(), "sqrtf32" => f.sqrt(), "expf32" => f.exp(), @@ -129,7 +139,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx #[rustfmt::skip] | "sinf64" - | "fabsf64" | "cosf64" | "sqrtf64" | "expf64" @@ -147,7 +156,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let f = f64::from_bits(this.read_scalar(f)?.to_u64()?); let f = match intrinsic_name { "sinf64" => f.sin(), - "fabsf64" => f.abs(), "cosf64" => f.cos(), "sqrtf64" => f.sqrt(), "expf64" => f.exp(), From 1f237b3b7dc905b7095d540ee91a3a23617a5792 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 16 Mar 2022 18:51:34 -0400 Subject: [PATCH 2939/3747] implement SIMD float rounding functions --- src/shims/intrinsics.rs | 50 ++++++++++++++++++++++++- tests/run-pass/portable-simd.rs | 65 +++++++++++++++++++++++++++++++-- 2 files changed, 109 insertions(+), 6 deletions(-) diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 24aeb448912b4..9b6df483b92a8 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -325,20 +325,37 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // SIMD operations #[rustfmt::skip] | "simd_neg" - | "simd_fabs" => { + | "simd_fabs" + | "simd_ceil" + | "simd_floor" + | "simd_round" + | "simd_trunc" => { let &[ref op] = check_arg_count(args)?; let (op, op_len) = this.operand_to_simd(op)?; let (dest, dest_len) = this.place_to_simd(dest)?; assert_eq!(dest_len, op_len); + #[derive(Copy, Clone)] + enum HostFloatOp { + Ceil, + Floor, + Round, + Trunc, + } + #[derive(Copy, Clone)] enum Op { MirOp(mir::UnOp), Abs, + HostOp(HostFloatOp), } let which = match intrinsic_name { "simd_neg" => Op::MirOp(mir::UnOp::Neg), "simd_fabs" => Op::Abs, + "simd_ceil" => Op::HostOp(HostFloatOp::Ceil), + "simd_floor" => Op::HostOp(HostFloatOp::Floor), + "simd_round" => Op::HostOp(HostFloatOp::Round), + "simd_trunc" => Op::HostOp(HostFloatOp::Trunc), _ => unreachable!(), }; @@ -350,7 +367,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Op::Abs => { // Works for f32 and f64. let ty::Float(float_ty) = op.layout.ty.kind() else { - bug!("simd_fabs operand is not a float") + bug!("{} operand is not a float", intrinsic_name) }; let op = op.to_scalar()?; match float_ty { @@ -358,6 +375,35 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx FloatTy::F64 => Scalar::from_f64(op.to_f64()?.abs()), } } + Op::HostOp(host_op) => { + let ty::Float(float_ty) = op.layout.ty.kind() else { + bug!("{} operand is not a float", intrinsic_name) + }; + // FIXME using host floats + match float_ty { + FloatTy::F32 => { + let f = f32::from_bits(op.to_scalar()?.to_u32()?); + let res = match host_op { + HostFloatOp::Ceil => f.ceil(), + HostFloatOp::Floor => f.floor(), + HostFloatOp::Round => f.round(), + HostFloatOp::Trunc => f.trunc(), + }; + Scalar::from_u32(res.to_bits()) + } + FloatTy::F64 => { + let f = f64::from_bits(op.to_scalar()?.to_u64()?); + let res = match host_op { + HostFloatOp::Ceil => f.ceil(), + HostFloatOp::Floor => f.floor(), + HostFloatOp::Round => f.round(), + HostFloatOp::Trunc => f.trunc(), + }; + Scalar::from_u64(res.to_bits()) + } + } + + } }; this.write_scalar(val, &dest.into())?; } diff --git a/tests/run-pass/portable-simd.rs b/tests/run-pass/portable-simd.rs index 28b9a1b03d94c..a15a0a3b1e003 100644 --- a/tests/run-pass/portable-simd.rs +++ b/tests/run-pass/portable-simd.rs @@ -106,19 +106,39 @@ fn simd_ops_i32() { assert_eq!(a.min(b * i32x4::splat(4)), i32x4::from_array([4, 8, 10, -16])); assert_eq!( - i8x4::from_array([i8::MAX, -23, 23, i8::MIN]).saturating_add(i8x4::from_array([1, i8::MIN, i8::MAX, 28])), + i8x4::from_array([i8::MAX, -23, 23, i8::MIN]).saturating_add(i8x4::from_array([ + 1, + i8::MIN, + i8::MAX, + 28 + ])), i8x4::from_array([i8::MAX, i8::MIN, i8::MAX, -100]) ); assert_eq!( - i8x4::from_array([i8::MAX, -28, 27, 42]).saturating_sub(i8x4::from_array([1, i8::MAX, i8::MAX, -80])), + i8x4::from_array([i8::MAX, -28, 27, 42]).saturating_sub(i8x4::from_array([ + 1, + i8::MAX, + i8::MAX, + -80 + ])), i8x4::from_array([126, i8::MIN, -100, 122]) ); assert_eq!( - u8x4::from_array([u8::MAX, 0, 23, 42]).saturating_add(u8x4::from_array([1, 1, u8::MAX, 200])), + u8x4::from_array([u8::MAX, 0, 23, 42]).saturating_add(u8x4::from_array([ + 1, + 1, + u8::MAX, + 200 + ])), u8x4::from_array([u8::MAX, 1, u8::MAX, 242]) ); assert_eq!( - u8x4::from_array([u8::MAX, 0, 23, 42]).saturating_sub(u8x4::from_array([1, 1, u8::MAX, 200])), + u8x4::from_array([u8::MAX, 0, 23, 42]).saturating_sub(u8x4::from_array([ + 1, + 1, + u8::MAX, + 200 + ])), u8x4::from_array([254, 0, 0, 0]) ); @@ -259,6 +279,42 @@ fn simd_gather_scatter() { assert_eq!(vec, vec![124, 11, 12, 82, 14, 15, 16, 17, 18]); } +fn simd_round() { + assert_eq!( + f32x4::from_array([0.9, 1.001, 2.0, -4.5]).ceil(), + f32x4::from_array([1.0, 2.0, 2.0, -4.0]) + ); + assert_eq!( + f32x4::from_array([0.9, 1.001, 2.0, -4.5]).floor(), + f32x4::from_array([0.0, 1.0, 2.0, -5.0]) + ); + assert_eq!( + f32x4::from_array([0.9, 1.001, 2.0, -4.5]).round(), + f32x4::from_array([1.0, 1.0, 2.0, -5.0]) + ); + assert_eq!( + f32x4::from_array([0.9, 1.001, 2.0, -4.5]).trunc(), + f32x4::from_array([0.0, 1.0, 2.0, -4.0]) + ); + + assert_eq!( + f64x4::from_array([0.9, 1.001, 2.0, -4.5]).ceil(), + f64x4::from_array([1.0, 2.0, 2.0, -4.0]) + ); + assert_eq!( + f64x4::from_array([0.9, 1.001, 2.0, -4.5]).floor(), + f64x4::from_array([0.0, 1.0, 2.0, -5.0]) + ); + assert_eq!( + f64x4::from_array([0.9, 1.001, 2.0, -4.5]).round(), + f64x4::from_array([1.0, 1.0, 2.0, -5.0]) + ); + assert_eq!( + f64x4::from_array([0.9, 1.001, 2.0, -4.5]).trunc(), + f64x4::from_array([0.0, 1.0, 2.0, -4.0]) + ); +} + fn simd_intrinsics() { extern "platform-intrinsic" { fn simd_eq(x: T, y: T) -> U; @@ -299,5 +355,6 @@ fn main() { simd_cast(); simd_swizzle(); simd_gather_scatter(); + simd_round(); simd_intrinsics(); } From 730cd272481427149d8d4a1e471d983a73f77105 Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Sat, 5 Feb 2022 19:44:56 -0500 Subject: [PATCH 2940/3747] Print more in SB error diagnostics This tries to clarify exactly why an access is not valid by printing what memory range the access was over, which in combination with tag-tracking may help a user figure out the source of the problem. --- src/diagnostics.rs | 31 +++-- src/stacked_borrows.rs | 125 ++++++++++++++---- tests/compile-fail/box-cell-alias.rs | 2 +- .../stacked_borrows/illegal_write3.rs | 2 +- .../stacked_borrows/raw_tracking.rs | 2 +- .../stacked_borrows/shr_frozen_violation1.rs | 2 +- .../compile-fail/stacked_borrows/zst_slice.rs | 2 +- 7 files changed, 126 insertions(+), 40 deletions(-) diff --git a/src/diagnostics.rs b/src/diagnostics.rs index 1ccf3c5dba732..fbcb2e0d0ff78 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -17,6 +17,7 @@ pub enum TerminationInfo { UnsupportedInIsolation(String), ExperimentalUb { msg: String, + help: Option, url: String, }, Deadlock, @@ -133,6 +134,8 @@ pub fn report_error<'tcx, 'mir>( ) -> Option { use InterpError::*; + let mut msg = vec![]; + let (title, helps) = match &e.kind() { MachineStop(info) => { let info = info.downcast_ref::().expect("invalid MachineStop payload"); @@ -152,11 +155,13 @@ pub fn report_error<'tcx, 'mir>( (None, format!("pass the flag `-Zmiri-disable-isolation` to disable isolation;")), (None, format!("or pass `-Zmiri-isolation-error=warn` to configure Miri to return an error code from isolated operations (if supported for that operation) and continue with a warning")), ], - ExperimentalUb { url, .. } => + ExperimentalUb { url, help, .. } => { + msg.extend(help.clone()); vec![ (None, format!("this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental")), - (None, format!("see {} for further information", url)), - ], + (None, format!("see {} for further information", url)) + ] + } MultipleSymbolDefinitions { first, first_crate, second, second_crate, .. } => vec![ (Some(*first), format!("it's first defined here, in crate `{}`", first_crate)), @@ -211,11 +216,11 @@ pub fn report_error<'tcx, 'mir>( let stacktrace = ecx.generate_stacktrace(); let (stacktrace, was_pruned) = prune_stacktrace(ecx, stacktrace); e.print_backtrace(); - let msg = e.to_string(); + msg.insert(0, e.to_string()); report_msg( *ecx.tcx, DiagLevel::Error, - &if let Some(title) = title { format!("{}: {}", title, msg) } else { msg.clone() }, + &if let Some(title) = title { format!("{}: {}", title, msg[0]) } else { msg[0].clone() }, msg, helps, &stacktrace, @@ -256,11 +261,14 @@ pub fn report_error<'tcx, 'mir>( /// Report an error or note (depending on the `error` argument) with the given stacktrace. /// Also emits a full stacktrace of the interpreter stack. +/// We want to present a multi-line span message for some errors. Diagnostics do not support this +/// directly, so we pass the lines as a `Vec` and display each line after the first with an +/// additional `span_label` or `note` call. fn report_msg<'tcx>( tcx: TyCtxt<'tcx>, diag_level: DiagLevel, title: &str, - span_msg: String, + span_msg: Vec, mut helps: Vec<(Option, String)>, stacktrace: &[FrameInfo<'tcx>], ) { @@ -273,12 +281,17 @@ fn report_msg<'tcx>( // Show main message. if span != DUMMY_SP { - err.span_label(span, span_msg); + for line in span_msg { + err.span_label(span, line); + } } else { // Make sure we show the message even when it is a dummy span. - err.note(&span_msg); + for line in span_msg { + err.note(&line); + } err.note("(no span available)"); } + // Show help messages. if !helps.is_empty() { // Add visual separator before backtrace. @@ -413,7 +426,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx _ => ("tracking was triggered", DiagLevel::Note), }; - report_msg(*this.tcx, diag_level, title, msg, vec![], &stacktrace); + report_msg(*this.tcx, diag_level, title, vec![msg], vec![], &stacktrace); } }); } diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 0e47a9e1c3b07..777b8e9331ee2 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -220,9 +220,10 @@ impl GlobalState { } /// Error reporting -fn err_sb_ub(msg: String) -> InterpError<'static> { +fn err_sb_ub(msg: String, help: Option) -> InterpError<'static> { err_machine_stop!(TerminationInfo::ExperimentalUb { msg, + help, url: format!( "https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md" ), @@ -320,12 +321,18 @@ impl<'tcx> Stack { if let Some(call) = item.protector { if global.is_active(call) { if let Some((tag, _)) = provoking_access { - Err(err_sb_ub(format!( - "not granting access to tag {:?} because incompatible item is protected: {:?}", - tag, item - )))? + Err(err_sb_ub( + format!( + "not granting access to tag {:?} because incompatible item is protected: {:?}", + tag, item + ), + None, + ))? } else { - Err(err_sb_ub(format!("deallocating while item is protected: {:?}", item)))? + Err(err_sb_ub( + format!("deallocating while item is protected: {:?}", item), + None, + ))? } } } @@ -334,22 +341,21 @@ impl<'tcx> Stack { /// Test if a memory `access` using pointer tagged `tag` is granted. /// If yes, return the index of the item that granted it. + /// `range` refers the entire operation, and `offset` refers to the specific offset into the + /// allocation that we are currently checking. fn access( &mut self, access: AccessKind, tag: SbTag, - dbg_ptr: Pointer, // just for debug printing amd error messages + (alloc_id, range, offset): (AllocId, AllocRange, Size), // just for debug printing and error messages global: &GlobalState, ) -> InterpResult<'tcx> { // Two main steps: Find granting item, remove incompatible items above. // Step 1: Find granting item. - let granting_idx = self.find_granting(access, tag).ok_or_else(|| { - err_sb_ub(format!( - "no item granting {} to tag {:?} at {:?} found in borrow stack.", - access, tag, dbg_ptr, - )) - })?; + let granting_idx = self + .find_granting(access, tag) + .ok_or_else(|| self.access_error(access, tag, alloc_id, range, offset))?; // Step 2: Remove incompatible items above them. Make sure we do not remove protected // items. Behavior differs for reads and writes. @@ -389,7 +395,7 @@ impl<'tcx> Stack { fn dealloc( &mut self, tag: SbTag, - dbg_ptr: Pointer, // just for debug printing amd error messages + dbg_ptr: Pointer, // just for debug printing and error messages global: &GlobalState, ) -> InterpResult<'tcx> { // Step 1: Find granting item. @@ -397,7 +403,7 @@ impl<'tcx> Stack { err_sb_ub(format!( "no item granting write access for deallocation to tag {:?} at {:?} found in borrow stack", tag, dbg_ptr, - )) + ), None) })?; // Step 2: Remove all items. Also checks for protectors. @@ -412,11 +418,13 @@ impl<'tcx> Stack { /// `weak` controls whether this operation is weak or strong: weak granting does not act as /// an access, and they add the new item directly on top of the one it is derived /// from instead of all the way at the top of the stack. + /// `range` refers the entire operation, and `offset` refers to the specific location in + /// `range` that we are currently checking. fn grant( &mut self, derived_from: SbTag, new: Item, - dbg_ptr: Pointer, + (alloc_id, alloc_range, offset): (AllocId, AllocRange, Size), // just for debug printing and error messages global: &GlobalState, ) -> InterpResult<'tcx> { // Figure out which access `perm` corresponds to. @@ -424,11 +432,9 @@ impl<'tcx> Stack { if new.perm.grants(AccessKind::Write) { AccessKind::Write } else { AccessKind::Read }; // Now we figure out which item grants our parent (`derived_from`) this kind of access. // We use that to determine where to put the new item. - let granting_idx = self.find_granting(access, derived_from) - .ok_or_else(|| err_sb_ub(format!( - "trying to reborrow for {:?} at {:?}, but parent tag {:?} does not have an appropriate item in the borrow stack", - new.perm, dbg_ptr, derived_from, - )))?; + let granting_idx = self + .find_granting(access, derived_from) + .ok_or_else(|| self.grant_error(derived_from, new, alloc_id, alloc_range, offset))?; // Compute where to put the new item. // Either way, we ensure that we insert the new item in a way such that between @@ -447,7 +453,7 @@ impl<'tcx> Stack { // A "safe" reborrow for a pointer that actually expects some aliasing guarantees. // Here, creating a reference actually counts as an access. // This ensures F2b for `Unique`, by removing offending `SharedReadOnly`. - self.access(access, derived_from, dbg_ptr, global)?; + self.access(access, derived_from, (alloc_id, alloc_range, offset), global)?; // We insert "as far up as possible": We know only compatible items are remaining // on top of `derived_from`, and we want the new item at the top so that we @@ -467,6 +473,72 @@ impl<'tcx> Stack { Ok(()) } + + /// Report a descriptive error when `new` could not be granted from `derived_from`. + fn grant_error( + &self, + derived_from: SbTag, + new: Item, + alloc_id: AllocId, + alloc_range: AllocRange, + error_offset: Size, + ) -> InterpError<'static> { + let action = format!( + "trying to reborrow {:?} for {:?} permission at {}[{:#x}]", + derived_from, + new.perm, + alloc_id, + error_offset.bytes(), + ); + err_sb_ub( + format!("{}{}", action, self.error_cause(derived_from)), + Some(Self::operation_summary("a reborrow", alloc_id, alloc_range)), + ) + } + + /// Report a descriptive error when `access` is not permitted based on `tag`. + fn access_error( + &self, + access: AccessKind, + tag: SbTag, + alloc_id: AllocId, + alloc_range: AllocRange, + error_offset: Size, + ) -> InterpError<'static> { + let action = format!( + "attempting a {} using {:?} at {}[{:#x}]", + access, + tag, + alloc_id, + error_offset.bytes(), + ); + err_sb_ub( + format!("{}{}", action, self.error_cause(tag)), + Some(Self::operation_summary("an access", alloc_id, alloc_range)), + ) + } + + fn operation_summary( + operation: &'static str, + alloc_id: AllocId, + alloc_range: AllocRange, + ) -> String { + format!( + "this error occurs as part of {} at {:?}[{:#x}..{:#x}]", + operation, + alloc_id, + alloc_range.start.bytes(), + alloc_range.end().bytes() + ) + } + + fn error_cause(&self, tag: SbTag) -> &'static str { + if self.borrows.iter().any(|item| item.tag == tag && item.perm != Permission::Disabled) { + ", but that tag only grants SharedReadOnly permission for this location" + } else { + ", but that tag does not exist in the borrow stack for this location" + } + } } // # Stacked Borrows Core End @@ -566,7 +638,7 @@ impl Stacks { ); let global = &*extra.borrow(); self.for_each(range, move |offset, stack| { - stack.access(AccessKind::Read, tag, Pointer::new(alloc_id, offset), global) + stack.access(AccessKind::Read, tag, (alloc_id, range, offset), global) }) } @@ -586,7 +658,7 @@ impl Stacks { ); let global = extra.get_mut(); self.for_each_mut(range, move |offset, stack| { - stack.access(AccessKind::Write, tag, Pointer::new(alloc_id, offset), global) + stack.access(AccessKind::Write, tag, (alloc_id, range, offset), global) }) } @@ -693,7 +765,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx }; let item = Item { perm, tag: new_tag, protector }; stacked_borrows.for_each(range, |offset, stack| { - stack.grant(orig_tag, item, Pointer::new(alloc_id, offset), &*global) + stack.grant(orig_tag, item, (alloc_id, range, offset), &*global) }) })?; return Ok(()); @@ -707,8 +779,9 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx alloc_extra.stacked_borrows.as_mut().expect("we should have Stacked Borrows data"); let global = memory_extra.stacked_borrows.as_mut().unwrap().get_mut(); let item = Item { perm, tag: new_tag, protector }; + let range = alloc_range(base_offset, size); stacked_borrows.for_each_mut(alloc_range(base_offset, size), |offset, stack| { - stack.grant(orig_tag, item, Pointer::new(alloc_id, offset), global) + stack.grant(orig_tag, item, (alloc_id, range, offset), global) })?; Ok(()) } diff --git a/tests/compile-fail/box-cell-alias.rs b/tests/compile-fail/box-cell-alias.rs index 58fc3530d7bfe..5b9614f79fde9 100644 --- a/tests/compile-fail/box-cell-alias.rs +++ b/tests/compile-fail/box-cell-alias.rs @@ -6,7 +6,7 @@ use std::cell::Cell; fn helper(val: Box>, ptr: *const Cell) -> u8 { val.set(10); - unsafe { (*ptr).set(20); } //~ ERROR does not have an appropriate item in the borrow stack + unsafe { (*ptr).set(20); } //~ ERROR does not exist in the borrow stack val.get() } diff --git a/tests/compile-fail/stacked_borrows/illegal_write3.rs b/tests/compile-fail/stacked_borrows/illegal_write3.rs index d2d8528d90786..7851eeb02690a 100644 --- a/tests/compile-fail/stacked_borrows/illegal_write3.rs +++ b/tests/compile-fail/stacked_borrows/illegal_write3.rs @@ -3,6 +3,6 @@ fn main() { // Make sure raw ptr with raw tag cannot mutate frozen location without breaking the shared ref. let r#ref = ⌖ // freeze let ptr = r#ref as *const _ as *mut _; // raw ptr, with raw tag - unsafe { *ptr = 42; } //~ ERROR borrow stack + unsafe { *ptr = 42; } //~ ERROR only grants SharedReadOnly permission let _val = *r#ref; } diff --git a/tests/compile-fail/stacked_borrows/raw_tracking.rs b/tests/compile-fail/stacked_borrows/raw_tracking.rs index 0d6d0198fbe9c..a8e1d806cbbb2 100644 --- a/tests/compile-fail/stacked_borrows/raw_tracking.rs +++ b/tests/compile-fail/stacked_borrows/raw_tracking.rs @@ -7,6 +7,6 @@ fn main() { let raw2 = &mut l as *mut _; // invalidates raw1 // Without raw pointer tracking, Stacked Borrows cannot distinguish raw1 and raw2, and thus // fails to realize that raw1 should not be used any more. - unsafe { *raw1 = 13; } //~ ERROR no item granting write access to tag + unsafe { *raw1 = 13; } //~ ERROR does not exist in the borrow stack unsafe { *raw2 = 13; } } diff --git a/tests/compile-fail/stacked_borrows/shr_frozen_violation1.rs b/tests/compile-fail/stacked_borrows/shr_frozen_violation1.rs index 5031210c547b1..1ea96086d3e46 100644 --- a/tests/compile-fail/stacked_borrows/shr_frozen_violation1.rs +++ b/tests/compile-fail/stacked_borrows/shr_frozen_violation1.rs @@ -9,5 +9,5 @@ fn main() { } fn unknown_code(x: &i32) { - unsafe { *(x as *const i32 as *mut i32) = 7; } //~ ERROR borrow stack + unsafe { *(x as *const i32 as *mut i32) = 7; } //~ ERROR only grants SharedReadOnly permission } diff --git a/tests/compile-fail/stacked_borrows/zst_slice.rs b/tests/compile-fail/stacked_borrows/zst_slice.rs index 14d5d77a2bb69..065bf77d04ae2 100644 --- a/tests/compile-fail/stacked_borrows/zst_slice.rs +++ b/tests/compile-fail/stacked_borrows/zst_slice.rs @@ -1,5 +1,5 @@ // compile-flags: -Zmiri-tag-raw-pointers -// error-pattern: does not have an appropriate item in the borrow stack +// error-pattern: does not exist in the borrow stack fn main() { unsafe { From 4fd5dca27c1ec311ee11844f3b9e2f53ddb454df Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 16 Mar 2022 22:12:39 -0400 Subject: [PATCH 2941/3747] implement SIMD sqrt and fma --- src/shims/intrinsics.rs | 37 ++++++++++++++++++++++++++++++++- tests/run-pass/portable-simd.rs | 10 +++++++++ 2 files changed, 46 insertions(+), 1 deletion(-) diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 9b6df483b92a8..726e6b6b96193 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -329,7 +329,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "simd_ceil" | "simd_floor" | "simd_round" - | "simd_trunc" => { + | "simd_trunc" + | "simd_fsqrt" => { let &[ref op] = check_arg_count(args)?; let (op, op_len) = this.operand_to_simd(op)?; let (dest, dest_len) = this.place_to_simd(dest)?; @@ -342,6 +343,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Floor, Round, Trunc, + Sqrt, } #[derive(Copy, Clone)] enum Op { @@ -356,6 +358,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "simd_floor" => Op::HostOp(HostFloatOp::Floor), "simd_round" => Op::HostOp(HostFloatOp::Round), "simd_trunc" => Op::HostOp(HostFloatOp::Trunc), + "simd_fsqrt" => Op::HostOp(HostFloatOp::Sqrt), _ => unreachable!(), }; @@ -388,6 +391,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx HostFloatOp::Floor => f.floor(), HostFloatOp::Round => f.round(), HostFloatOp::Trunc => f.trunc(), + HostFloatOp::Sqrt => f.sqrt(), }; Scalar::from_u32(res.to_bits()) } @@ -398,6 +402,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx HostFloatOp::Floor => f.floor(), HostFloatOp::Round => f.round(), HostFloatOp::Trunc => f.trunc(), + HostFloatOp::Sqrt => f.sqrt(), }; Scalar::from_u64(res.to_bits()) } @@ -508,6 +513,36 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(val, &dest.into())?; } } + "simd_fma" => { + let &[ref a, ref b, ref c] = check_arg_count(args)?; + let (a, a_len) = this.operand_to_simd(a)?; + let (b, b_len) = this.operand_to_simd(b)?; + let (c, c_len) = this.operand_to_simd(c)?; + let (dest, dest_len) = this.place_to_simd(dest)?; + + assert_eq!(dest_len, a_len); + assert_eq!(dest_len, b_len); + assert_eq!(dest_len, c_len); + + for i in 0..dest_len { + let a = this.read_immediate(&this.mplace_index(&a, i)?.into())?.to_scalar()?; + let b = this.read_immediate(&this.mplace_index(&b, i)?.into())?.to_scalar()?; + let c = this.read_immediate(&this.mplace_index(&c, i)?.into())?.to_scalar()?; + let dest = this.mplace_index(&dest, i)?; + + // Works for f32 and f64. + let ty::Float(float_ty) = dest.layout.ty.kind() else { + bug!("{} operand is not a float", intrinsic_name) + }; + let val = match float_ty { + FloatTy::F32 => + Scalar::from_f32(a.to_f32()?.mul_add(b.to_f32()?, c.to_f32()?).value), + FloatTy::F64 => + Scalar::from_f64(a.to_f64()?.mul_add(b.to_f64()?, c.to_f64()?).value), + }; + this.write_scalar(val, &dest.into())?; + } + } #[rustfmt::skip] | "simd_reduce_and" | "simd_reduce_or" diff --git a/tests/run-pass/portable-simd.rs b/tests/run-pass/portable-simd.rs index a15a0a3b1e003..80b0b4556c6e7 100644 --- a/tests/run-pass/portable-simd.rs +++ b/tests/run-pass/portable-simd.rs @@ -15,6 +15,11 @@ fn simd_ops_f32() { assert_eq!(a.max(b * f32x4::splat(4.0)), f32x4::from_array([10.0, 10.0, 12.0, 10.0])); assert_eq!(a.min(b * f32x4::splat(4.0)), f32x4::from_array([4.0, 8.0, 10.0, -16.0])); + assert_eq!(a.mul_add(b, a), (a*b)+a); + assert_eq!(b.mul_add(b, a), (b*b)+a); + assert_eq!((a*a).sqrt(), a); + assert_eq!((b*b).sqrt(), b.abs()); + assert_eq!(a.lanes_eq(f32x4::splat(5.0) * b), Mask::from_array([false, true, false, false])); assert_eq!(a.lanes_ne(f32x4::splat(5.0) * b), Mask::from_array([true, false, true, true])); assert_eq!(a.lanes_le(f32x4::splat(5.0) * b), Mask::from_array([false, true, true, false])); @@ -59,6 +64,11 @@ fn simd_ops_f64() { assert_eq!(a.max(b * f64x4::splat(4.0)), f64x4::from_array([10.0, 10.0, 12.0, 10.0])); assert_eq!(a.min(b * f64x4::splat(4.0)), f64x4::from_array([4.0, 8.0, 10.0, -16.0])); + assert_eq!(a.mul_add(b, a), (a*b)+a); + assert_eq!(b.mul_add(b, a), (b*b)+a); + assert_eq!((a*a).sqrt(), a); + assert_eq!((b*b).sqrt(), b.abs()); + assert_eq!(a.lanes_eq(f64x4::splat(5.0) * b), Mask::from_array([false, true, false, false])); assert_eq!(a.lanes_ne(f64x4::splat(5.0) * b), Mask::from_array([true, false, true, true])); assert_eq!(a.lanes_le(f64x4::splat(5.0) * b), Mask::from_array([false, true, true, false])); From bfed3c4f0d285df97c0e9cbe342665b8b37b7a96 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 16 Mar 2022 20:33:54 -0400 Subject: [PATCH 2942/3747] implement simd bitmask intrinsics --- src/helpers.rs | 15 ------- src/shims/intrinsics.rs | 74 ++++++++++++++++++++++++++++++++- tests/run-pass/portable-simd.rs | 15 +++++++ 3 files changed, 87 insertions(+), 17 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index ba12e0a7e394e..fe2f33ffd33e5 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -775,18 +775,3 @@ pub fn isolation_abort_error(name: &str) -> InterpResult<'static> { name, ))) } - -pub fn bool_to_simd_element(b: bool, size: Size) -> Scalar { - // SIMD uses all-1 as pattern for "true" - let val = if b { -1 } else { 0 }; - Scalar::from_int(val, size) -} - -pub fn simd_element_to_bool<'tcx>(elem: ImmTy<'tcx, Tag>) -> InterpResult<'tcx, bool> { - let val = elem.to_scalar()?.to_int(elem.layout.size)?; - Ok(match val { - 0 => false, - -1 => true, - _ => throw_ub_format!("each element of a SIMD mask must be all-0-bits or all-1-bits"), - }) -} diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 726e6b6b96193..b704004e16c0f 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -1,3 +1,4 @@ +use std::convert::TryInto; use std::iter; use log::trace; @@ -5,10 +6,10 @@ use log::trace; use rustc_apfloat::{Float, Round}; use rustc_middle::ty::layout::{HasParamEnv, IntegerExt, LayoutOf}; use rustc_middle::{mir, mir::BinOp, ty, ty::FloatTy}; -use rustc_target::abi::{Align, Integer}; +use rustc_target::abi::{Align, Endian, HasDataLayout, Integer, Size}; use crate::*; -use helpers::{bool_to_simd_element, check_arg_count, simd_element_to_bool}; +use helpers::check_arg_count; pub enum AtomicOp { MirOp(mir::BinOp, bool), @@ -663,6 +664,35 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_immediate(*val, &dest.into())?; } } + "simd_select_bitmask" => { + let &[ref mask, ref yes, ref no] = check_arg_count(args)?; + let (yes, yes_len) = this.operand_to_simd(yes)?; + let (no, no_len) = this.operand_to_simd(no)?; + let (dest, dest_len) = this.place_to_simd(dest)?; + + assert!(mask.layout.ty.is_integral()); + assert_eq!(dest_len.max(8), mask.layout.size.bits()); + assert!(dest_len <= 64); + assert_eq!(dest_len, yes_len); + assert_eq!(dest_len, no_len); + + let mask: u64 = this + .read_scalar(mask)? + .check_init()? + .to_bits(mask.layout.size)? + .try_into() + .unwrap(); + for i in 0..dest_len { + let mask = + mask & (1 << simd_bitmask_index(i, dest_len, this.data_layout().endian)); + let yes = this.read_immediate(&this.mplace_index(&yes, i)?.into())?; + let no = this.read_immediate(&this.mplace_index(&no, i)?.into())?; + let dest = this.mplace_index(&dest, i)?; + + let val = if mask != 0 { yes } else { no }; + this.write_immediate(*val, &dest.into())?; + } + } #[rustfmt::skip] "simd_cast" | "simd_as" => { let &[ref op] = check_arg_count(args)?; @@ -787,6 +817,23 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } } + "simd_bitmask" => { + let &[ref op] = check_arg_count(args)?; + let (op, op_len) = this.operand_to_simd(op)?; + + assert!(dest.layout.ty.is_integral()); + assert_eq!(op_len.max(8), dest.layout.size.bits()); + assert!(op_len <= 64); + + let mut res = 0u64; + for i in 0..op_len { + let op = this.read_immediate(&this.mplace_index(&op, i)?.into())?; + if simd_element_to_bool(op)? { + res |= 1 << simd_bitmask_index(i, op_len, this.data_layout().endian); + } + } + this.write_int(res, dest)?; + } // Atomic operations "atomic_load" => this.atomic_load(args, dest, AtomicReadOp::SeqCst)?, @@ -1307,3 +1354,26 @@ fn fmin_op<'tcx>( FloatTy::F64 => Scalar::from_f64(left.to_f64()?.min(right.to_f64()?)), }) } + +fn bool_to_simd_element(b: bool, size: Size) -> Scalar { + // SIMD uses all-1 as pattern for "true" + let val = if b { -1 } else { 0 }; + Scalar::from_int(val, size) +} + +fn simd_element_to_bool<'tcx>(elem: ImmTy<'tcx, Tag>) -> InterpResult<'tcx, bool> { + let val = elem.to_scalar()?.to_int(elem.layout.size)?; + Ok(match val { + 0 => false, + -1 => true, + _ => throw_ub_format!("each element of a SIMD mask must be all-0-bits or all-1-bits"), + }) +} + +fn simd_bitmask_index(idx: u64, len: u64, endianess: Endian) -> u64 { + assert!(idx < len); + match endianess { + Endian::Little => idx, + Endian::Big => len.max(8) - 1 - idx, // reverse order of bits + } +} diff --git a/tests/run-pass/portable-simd.rs b/tests/run-pass/portable-simd.rs index 80b0b4556c6e7..a74559b72be4b 100644 --- a/tests/run-pass/portable-simd.rs +++ b/tests/run-pass/portable-simd.rs @@ -187,6 +187,21 @@ fn simd_mask() { let intmask = Mask::from_int(i32x4::from_array([0, -1, 0, 0])); assert_eq!(intmask, Mask::from_array([false, true, false, false])); assert_eq!(intmask.to_array(), [false, true, false, false]); + + let values = [ + true, false, false, true, false, false, true, false, true, true, false, false, false, true, + false, true, + ]; + let mask = Mask::::from_array(values); + let bitmask = mask.to_bitmask(); + assert_eq!(bitmask, 0b1010001101001001); + assert_eq!(Mask::::from_bitmask(bitmask), mask); + + let values = [false, false, false, true]; + let mask = Mask::::from_array(values); + let bitmask = mask.to_bitmask(); + assert_eq!(bitmask, 0b1000); + assert_eq!(Mask::::from_bitmask(bitmask), mask); } fn simd_cast() { From b5d3a25b49f97301bfeaa632d1cf432b3c0e8a71 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 16 Mar 2022 20:52:01 -0400 Subject: [PATCH 2943/3747] detect when unused bits of a SIMD bitmask are non-0 --- src/shims/intrinsics.rs | 30 +++++++++++++------ .../intrinsics/simd-select-bitmask-invalid.rs | 15 ++++++++++ .../intrinsics/simd-select-invalid-bool.rs | 15 ++++++++++ 3 files changed, 51 insertions(+), 9 deletions(-) create mode 100644 tests/compile-fail/intrinsics/simd-select-bitmask-invalid.rs create mode 100644 tests/compile-fail/intrinsics/simd-select-invalid-bool.rs diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index b704004e16c0f..495ad93951fec 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -669,10 +669,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let (yes, yes_len) = this.operand_to_simd(yes)?; let (no, no_len) = this.operand_to_simd(no)?; let (dest, dest_len) = this.place_to_simd(dest)?; + let bitmask_len = dest_len.max(8); assert!(mask.layout.ty.is_integral()); - assert_eq!(dest_len.max(8), mask.layout.size.bits()); - assert!(dest_len <= 64); + assert!(bitmask_len <= 64); + assert_eq!(bitmask_len, mask.layout.size.bits()); assert_eq!(dest_len, yes_len); assert_eq!(dest_len, no_len); @@ -684,7 +685,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx .unwrap(); for i in 0..dest_len { let mask = - mask & (1 << simd_bitmask_index(i, dest_len, this.data_layout().endian)); + mask & (1 << simd_bitmask_index(i, bitmask_len, this.data_layout().endian)); let yes = this.read_immediate(&this.mplace_index(&yes, i)?.into())?; let no = this.read_immediate(&this.mplace_index(&no, i)?.into())?; let dest = this.mplace_index(&dest, i)?; @@ -692,6 +693,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let val = if mask != 0 { yes } else { no }; this.write_immediate(*val, &dest.into())?; } + for i in dest_len..bitmask_len { + // If the mask is "padded", ensure that padding is all-zero. + let mask = + mask & (1 << simd_bitmask_index(i, bitmask_len, this.data_layout().endian)); + if mask != 0 { + throw_ub_format!( + "a SIMD bitmask less than 8 bits long must be filled with 0s for the remaining bits" + ); + } + } } #[rustfmt::skip] "simd_cast" | "simd_as" => { @@ -820,16 +831,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "simd_bitmask" => { let &[ref op] = check_arg_count(args)?; let (op, op_len) = this.operand_to_simd(op)?; + let bitmask_len = op_len.max(8); assert!(dest.layout.ty.is_integral()); - assert_eq!(op_len.max(8), dest.layout.size.bits()); - assert!(op_len <= 64); + assert!(bitmask_len <= 64); + assert_eq!(bitmask_len, dest.layout.size.bits()); let mut res = 0u64; for i in 0..op_len { let op = this.read_immediate(&this.mplace_index(&op, i)?.into())?; if simd_element_to_bool(op)? { - res |= 1 << simd_bitmask_index(i, op_len, this.data_layout().endian); + res |= 1 << simd_bitmask_index(i, bitmask_len, this.data_layout().endian); } } this.write_int(res, dest)?; @@ -1370,10 +1382,10 @@ fn simd_element_to_bool<'tcx>(elem: ImmTy<'tcx, Tag>) -> InterpResult<'tcx, bool }) } -fn simd_bitmask_index(idx: u64, len: u64, endianess: Endian) -> u64 { - assert!(idx < len); +fn simd_bitmask_index(idx: u64, bitmask_len: u64, endianess: Endian) -> u64 { + assert!(idx < bitmask_len); match endianess { Endian::Little => idx, - Endian::Big => len.max(8) - 1 - idx, // reverse order of bits + Endian::Big => bitmask_len - 1 - idx, // reverse order of bits } } diff --git a/tests/compile-fail/intrinsics/simd-select-bitmask-invalid.rs b/tests/compile-fail/intrinsics/simd-select-bitmask-invalid.rs new file mode 100644 index 0000000000000..ab69072c30976 --- /dev/null +++ b/tests/compile-fail/intrinsics/simd-select-bitmask-invalid.rs @@ -0,0 +1,15 @@ +#![feature(platform_intrinsics, repr_simd)] + +extern "platform-intrinsic" { + fn simd_select_bitmask(m: M, yes: T, no: T) -> T; +} + +#[repr(simd)] +#[allow(non_camel_case_types)] +#[derive(Copy, Clone)] +struct i32x2(i32, i32); + +fn main() { unsafe { + let x = i32x2(0, 1); + simd_select_bitmask(0b11111111u8, x, x); //~ERROR bitmask less than 8 bits long must be filled with 0s for the remaining bits +} } diff --git a/tests/compile-fail/intrinsics/simd-select-invalid-bool.rs b/tests/compile-fail/intrinsics/simd-select-invalid-bool.rs new file mode 100644 index 0000000000000..98f67cfcd7e13 --- /dev/null +++ b/tests/compile-fail/intrinsics/simd-select-invalid-bool.rs @@ -0,0 +1,15 @@ +#![feature(platform_intrinsics, repr_simd)] + +extern "platform-intrinsic" { + fn simd_select(m: M, yes: T, no: T) -> T; +} + +#[repr(simd)] +#[allow(non_camel_case_types)] +#[derive(Copy, Clone)] +struct i32x2(i32, i32); + +fn main() { unsafe { + let x = i32x2(0, 1); + simd_select(x, x, x); //~ERROR must be all-0-bits or all-1-bits +} } From 1b1321a685f4d5e362786c1876dbcc9e2de866ba Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 17 Mar 2022 13:14:16 -0400 Subject: [PATCH 2944/3747] fix simd_bitmask shorter than a byte on big-endian --- src/shims/intrinsics.rs | 13 ++++++------- tests/run-pass/portable-simd.rs | 2 +- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 495ad93951fec..c344d0ff9c34d 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -685,7 +685,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx .unwrap(); for i in 0..dest_len { let mask = - mask & (1 << simd_bitmask_index(i, bitmask_len, this.data_layout().endian)); + mask & (1 << simd_bitmask_index(i, dest_len, this.data_layout().endian)); let yes = this.read_immediate(&this.mplace_index(&yes, i)?.into())?; let no = this.read_immediate(&this.mplace_index(&no, i)?.into())?; let dest = this.mplace_index(&dest, i)?; @@ -695,8 +695,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } for i in dest_len..bitmask_len { // If the mask is "padded", ensure that padding is all-zero. - let mask = - mask & (1 << simd_bitmask_index(i, bitmask_len, this.data_layout().endian)); + let mask = mask & (1 << i); if mask != 0 { throw_ub_format!( "a SIMD bitmask less than 8 bits long must be filled with 0s for the remaining bits" @@ -841,7 +840,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx for i in 0..op_len { let op = this.read_immediate(&this.mplace_index(&op, i)?.into())?; if simd_element_to_bool(op)? { - res |= 1 << simd_bitmask_index(i, bitmask_len, this.data_layout().endian); + res |= 1 << simd_bitmask_index(i, op_len, this.data_layout().endian); } } this.write_int(res, dest)?; @@ -1382,10 +1381,10 @@ fn simd_element_to_bool<'tcx>(elem: ImmTy<'tcx, Tag>) -> InterpResult<'tcx, bool }) } -fn simd_bitmask_index(idx: u64, bitmask_len: u64, endianess: Endian) -> u64 { - assert!(idx < bitmask_len); +fn simd_bitmask_index(idx: u64, vec_len: u64, endianess: Endian) -> u64 { + assert!(idx < vec_len); match endianess { Endian::Little => idx, - Endian::Big => bitmask_len - 1 - idx, // reverse order of bits + Endian::Big => vec_len - 1 - idx, // reverse order of bits } } diff --git a/tests/run-pass/portable-simd.rs b/tests/run-pass/portable-simd.rs index a74559b72be4b..99a64ea370f6b 100644 --- a/tests/run-pass/portable-simd.rs +++ b/tests/run-pass/portable-simd.rs @@ -200,7 +200,7 @@ fn simd_mask() { let values = [false, false, false, true]; let mask = Mask::::from_array(values); let bitmask = mask.to_bitmask(); - assert_eq!(bitmask, 0b1000); + // FIXME fails until https://github.com/rust-lang/portable-simd/pull/267 lands: assert_eq!(bitmask, 0b1000); assert_eq!(Mask::::from_bitmask(bitmask), mask); } From 65125df1cd31b467dba2a71c03d6c4343e2a05b8 Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Sat, 12 Mar 2022 17:23:22 -0500 Subject: [PATCH 2945/3747] Consider the cargo workspace when checking if a frame is local --- README.md | 5 ++++- cargo-miri/bin.rs | 41 +++++++++++++++++++++++++++++++---------- src/diagnostics.rs | 23 ++++++++++++----------- src/helpers.rs | 21 ++++++++++++++++++++- src/machine.rs | 13 ++++++++++++- 5 files changed, 79 insertions(+), 24 deletions(-) diff --git a/README.md b/README.md index 0af25ccbff2c9..fb999d85a192c 100644 --- a/README.md +++ b/README.md @@ -375,9 +375,12 @@ binaries, and as such worth documenting: directory after loading all the source files, but before commencing interpretation. This is useful if the interpreted program wants a different working directory at run-time than at build-time. +* `MIRI_LOCAL_CRATES` is set by `cargo-miri` to tell the Miri driver which + crates should be given special treatment in diagnostics, in addition to the + crate currently being compiled. * `MIRI_VERBOSE` when set to any value tells the various `cargo-miri` phases to perform verbose logging. - + [testing-miri]: CONTRIBUTING.md#testing-the-miri-driver ## Miri `extern` functions diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index a946f79888338..373c63647c35a 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -482,12 +482,13 @@ path = "lib.rs" } } -/// Detect the target directory by calling `cargo metadata`. -fn detect_target_dir() -> PathBuf { - #[derive(Deserialize)] - struct Metadata { - target_directory: PathBuf, - } +#[derive(Deserialize)] +struct Metadata { + target_directory: PathBuf, + workspace_members: Vec, +} + +fn get_cargo_metadata() -> Metadata { let mut cmd = cargo(); // `-Zunstable-options` is required by `--config`. cmd.args(["metadata", "--no-deps", "--format-version=1", "-Zunstable-options"]); @@ -514,9 +515,25 @@ fn detect_target_dir() -> PathBuf { if !status.success() { std::process::exit(status.code().unwrap_or(-1)); } - metadata - .unwrap_or_else(|e| show_error(format!("invalid `cargo metadata` output: {}", e))) - .target_directory + metadata.unwrap_or_else(|e| show_error(format!("invalid `cargo metadata` output: {}", e))) +} + +/// Pulls all the crates in this workspace from the cargo metadata. +/// Workspace members are emitted like "miri 0.1.0 (path+file:///path/to/miri)" +/// Additionally, somewhere between cargo metadata and TyCtxt, '-' gets replaced with '_' so we +/// make that same transformation here. +fn local_crates(metadata: &Metadata) -> String { + assert!(metadata.workspace_members.len() > 0); + let mut local_crates = String::new(); + for member in &metadata.workspace_members { + let name = member.split(" ").nth(0).unwrap(); + let name = name.replace("-", "_"); + local_crates.push_str(&name); + local_crates.push(','); + } + local_crates.pop(); // Remove the trailing ',' + + local_crates } fn phase_cargo_miri(mut args: env::Args) { @@ -595,8 +612,10 @@ fn phase_cargo_miri(mut args: env::Args) { } } + let metadata = get_cargo_metadata(); + // Detect the target directory if it's not specified via `--target-dir`. - let target_dir = target_dir.get_or_insert_with(detect_target_dir); + let target_dir = target_dir.get_or_insert_with(|| metadata.target_directory.clone()); // Set `--target-dir` to `miri` inside the original target directory. target_dir.push("miri"); @@ -628,6 +647,8 @@ fn phase_cargo_miri(mut args: env::Args) { // Set rustdoc to us as well, so we can run doctests. cmd.env("RUSTDOC", &cargo_miri_path); + cmd.env("MIRI_LOCAL_CRATES", local_crates(&metadata)); + // Run cargo. if verbose { eprintln!("[cargo-miri miri] RUSTC_WRAPPER={:?}", cargo_miri_path); diff --git a/src/diagnostics.rs b/src/diagnostics.rs index fbcb2e0d0ff78..0815d73d9bcb7 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -4,7 +4,7 @@ use std::num::NonZeroU64; use log::trace; -use rustc_middle::ty::{self, TyCtxt}; +use rustc_middle::ty; use rustc_span::{source_map::DUMMY_SP, Span, SpanData, Symbol}; use crate::stacked_borrows::{AccessKind, SbTag}; @@ -94,7 +94,7 @@ fn prune_stacktrace<'mir, 'tcx>( // Only prune frames if there is at least one local frame. This check ensures that if // we get a backtrace that never makes it to the user code because it has detected a // bug in the Rust runtime, we don't prune away every frame. - let has_local_frame = stacktrace.iter().any(|frame| frame.instance.def_id().is_local()); + let has_local_frame = stacktrace.iter().any(|frame| ecx.machine.is_local(frame)); if has_local_frame { // This is part of the logic that `std` uses to select the relevant part of a // backtrace. But here, we only look for __rust_begin_short_backtrace, not @@ -115,7 +115,7 @@ fn prune_stacktrace<'mir, 'tcx>( // This len check ensures that we don't somehow remove every frame, as doing so breaks // the primary error message. while stacktrace.len() > 1 - && stacktrace.last().map_or(false, |e| !e.instance.def_id().is_local()) + && stacktrace.last().map_or(false, |frame| !ecx.machine.is_local(frame)) { stacktrace.pop(); } @@ -218,7 +218,7 @@ pub fn report_error<'tcx, 'mir>( e.print_backtrace(); msg.insert(0, e.to_string()); report_msg( - *ecx.tcx, + ecx, DiagLevel::Error, &if let Some(title) = title { format!("{}: {}", title, msg[0]) } else { msg[0].clone() }, msg, @@ -264,8 +264,8 @@ pub fn report_error<'tcx, 'mir>( /// We want to present a multi-line span message for some errors. Diagnostics do not support this /// directly, so we pass the lines as a `Vec` and display each line after the first with an /// additional `span_label` or `note` call. -fn report_msg<'tcx>( - tcx: TyCtxt<'tcx>, +fn report_msg<'mir, 'tcx>( + ecx: &InterpCx<'mir, 'tcx, Evaluator<'mir, 'tcx>>, diag_level: DiagLevel, title: &str, span_msg: Vec, @@ -273,10 +273,11 @@ fn report_msg<'tcx>( stacktrace: &[FrameInfo<'tcx>], ) { let span = stacktrace.first().map_or(DUMMY_SP, |fi| fi.span); + let sess = ecx.tcx.sess; let mut err = match diag_level { - DiagLevel::Error => tcx.sess.struct_span_err(span, title).forget_guarantee(), - DiagLevel::Warning => tcx.sess.struct_span_warn(span, title), - DiagLevel::Note => tcx.sess.diagnostic().span_note_diag(span, title), + DiagLevel::Error => sess.struct_span_err(span, title).forget_guarantee(), + DiagLevel::Warning => sess.struct_span_warn(span, title), + DiagLevel::Note => sess.diagnostic().span_note_diag(span, title), }; // Show main message. @@ -306,7 +307,7 @@ fn report_msg<'tcx>( } // Add backtrace for (idx, frame_info) in stacktrace.iter().enumerate() { - let is_local = frame_info.instance.def_id().is_local(); + let is_local = ecx.machine.is_local(frame_info); // No span for non-local frames and the first frame (which is the error site). if is_local && idx > 0 { err.span_note(frame_info.span, &frame_info.to_string()); @@ -426,7 +427,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx _ => ("tracking was triggered", DiagLevel::Note), }; - report_msg(*this.tcx, diag_level, title, vec![msg], vec![], &stacktrace); + report_msg(this, diag_level, title, vec![msg], vec![], &stacktrace); } }); } diff --git a/src/helpers.rs b/src/helpers.rs index fe2f33ffd33e5..3ffb983aa69ec 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -12,7 +12,7 @@ use rustc_middle::ty::{ layout::{LayoutOf, TyAndLayout}, List, TyCtxt, }; -use rustc_span::Symbol; +use rustc_span::{def_id::CrateNum, Symbol}; use rustc_target::abi::{Align, FieldsShape, Size, Variants}; use rustc_target::spec::abi::Abi; @@ -775,3 +775,22 @@ pub fn isolation_abort_error(name: &str) -> InterpResult<'static> { name, ))) } + +/// Retrieve the list of local crates that should have been passed by cargo-miri in +/// MIRI_LOCAL_CRATES and turn them into `CrateNum`s. +pub fn get_local_crates(tcx: &TyCtxt<'_>) -> Vec { + // Convert the local crate names from the passed-in config into CrateNums so that they can + // be looked up quickly during execution + let local_crate_names = std::env::var("MIRI_LOCAL_CRATES") + .map(|crates| crates.split(",").map(|krate| krate.to_string()).collect::>()) + .unwrap_or_default(); + let mut local_crates = Vec::new(); + for &crate_num in tcx.crates(()) { + let name = tcx.crate_name(crate_num); + let name = name.as_str(); + if local_crate_names.iter().any(|local_name| local_name == name) { + local_crates.push(crate_num); + } + } + local_crates +} diff --git a/src/machine.rs b/src/machine.rs index bb43cb95507c5..2cf7cd0fae0e2 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -19,7 +19,7 @@ use rustc_middle::{ Instance, TyCtxt, }, }; -use rustc_span::def_id::DefId; +use rustc_span::def_id::{CrateNum, DefId}; use rustc_span::symbol::{sym, Symbol}; use rustc_target::abi::Size; use rustc_target::spec::abi::Abi; @@ -349,10 +349,14 @@ pub struct Evaluator<'mir, 'tcx> { /// Equivalent setting as RUST_BACKTRACE on encountering an error. pub(crate) backtrace_style: BacktraceStyle, + + /// Crates which are considered local for the purposes of error reporting. + pub(crate) local_crates: Vec, } impl<'mir, 'tcx> Evaluator<'mir, 'tcx> { pub(crate) fn new(config: &MiriConfig, layout_cx: LayoutCx<'tcx, TyCtxt<'tcx>>) -> Self { + let local_crates = helpers::get_local_crates(&layout_cx.tcx); let layouts = PrimitiveLayouts::new(layout_cx).expect("Couldn't get layouts of primitive types"); let profiler = config.measureme_out.as_ref().map(|out| { @@ -381,12 +385,19 @@ impl<'mir, 'tcx> Evaluator<'mir, 'tcx> { exported_symbols_cache: FxHashMap::default(), panic_on_unsupported: config.panic_on_unsupported, backtrace_style: config.backtrace_style, + local_crates, } } pub(crate) fn communicate(&self) -> bool { self.isolated_op == IsolatedOp::Allow } + + /// Check whether the stack frame that this `FrameInfo` refers to is part of a local crate. + pub(crate) fn is_local(&self, frame: &FrameInfo<'_>) -> bool { + let def_id = frame.instance.def_id(); + def_id.is_local() || self.local_crates.contains(&def_id.krate) + } } /// A rustc InterpCx for Miri. From 2c670b10dfcfd23ff95ce32ba9bbc9d3ead14f05 Mon Sep 17 00:00:00 2001 From: DrMeepster <19316085+DrMeepster@users.noreply.github.com> Date: Thu, 24 Feb 2022 22:11:20 -0800 Subject: [PATCH 2946/3747] add new version of backtrace api using flags=1 --- README.md | 28 ++- src/shims/backtrace.rs | 200 +++++++++++++----- src/shims/foreign_items.rs | 9 + .../backtrace/bad-backtrace-flags.rs | 9 + .../backtrace/bad-backtrace-resolve-flags.rs | 25 +++ .../bad-backtrace-resolve-names-flags.rs | 16 ++ .../backtrace/bad-backtrace-size-flags.rs | 9 + .../backtrace/bad-backtrace-version.rs | 9 - .../{backtrace-api.rs => backtrace-api-v0.rs} | 0 ...ace-api.stderr => backtrace-api-v0.stderr} | 10 +- tests/run-pass/backtrace-api-v0.stdout | 5 + tests/run-pass/backtrace-api-v1.rs | 65 ++++++ tests/run-pass/backtrace-api-v1.stderr | 18 ++ tests/run-pass/backtrace-api-v1.stdout | 5 + tests/run-pass/backtrace-api.stdout | 5 - 15 files changed, 333 insertions(+), 80 deletions(-) create mode 100644 tests/compile-fail/backtrace/bad-backtrace-flags.rs create mode 100644 tests/compile-fail/backtrace/bad-backtrace-resolve-flags.rs create mode 100644 tests/compile-fail/backtrace/bad-backtrace-resolve-names-flags.rs create mode 100644 tests/compile-fail/backtrace/bad-backtrace-size-flags.rs delete mode 100644 tests/compile-fail/backtrace/bad-backtrace-version.rs rename tests/run-pass/{backtrace-api.rs => backtrace-api-v0.rs} (100%) rename tests/run-pass/{backtrace-api.stderr => backtrace-api-v0.stderr} (82%) create mode 100644 tests/run-pass/backtrace-api-v0.stdout create mode 100644 tests/run-pass/backtrace-api-v1.rs create mode 100644 tests/run-pass/backtrace-api-v1.stderr create mode 100644 tests/run-pass/backtrace-api-v1.stdout delete mode 100644 tests/run-pass/backtrace-api.stdout diff --git a/README.md b/README.md index fb9a556699030..086ed1b0efa8e 100644 --- a/README.md +++ b/README.md @@ -358,23 +358,28 @@ extern "Rust" { /// `ptr` has to point to the beginning of an allocated block. fn miri_static_root(ptr: *const u8); + // Miri-provided extern function to get the amount of frames in the current backtrace. + // The `flags` argument must be `0`. + fn miri_backtrace_size(flags: u64) -> usize; + /// Miri-provided extern function to obtain a backtrace of the current call stack. - /// This returns a boxed slice of pointers - each pointer is an opaque value - /// that is only useful when passed to `miri_resolve_frame` - /// The `flags` argument must be `0`. - fn miri_get_backtrace(flags: u64) -> Box<[*mut ()]>; + /// This writes a slice of pointers into `buf` - each pointer is an opaque value + /// that is only useful when passed to `miri_resolve_frame`. + /// `buf` must have `miri_backtrace_size(0) * pointer_size` bytes of space. + /// The `flags` argument must be `1`. + fn miri_get_backtrace(flags: u64, buf: *mut *mut ()); /// Miri-provided extern function to resolve a frame pointer obtained - /// from `miri_get_backtrace`. The `flags` argument must be `0`, + /// from `miri_get_backtrace`. The `flags` argument must be `1`, /// and `MiriFrame` should be declared as follows: /// /// ```rust /// #[repr(C)] /// struct MiriFrame { - /// // The name of the function being executed, encoded in UTF-8 - /// name: Box<[u8]>, - /// // The filename of the function being executed, encoded in UTF-8 - /// filename: Box<[u8]>, + /// // The size of the name of the function being executed, encoded in UTF-8 + /// name_len: usize, + /// // The size of filename of the function being executed, encoded in UTF-8 + /// filename_len: usize, /// // The line number currently being executed in `filename`, starting from '1'. /// lineno: u32, /// // The column number currently being executed in `filename`, starting from '1'. @@ -390,6 +395,11 @@ extern "Rust" { /// This function can be called on any thread (not just the one which obtained `frame`). fn miri_resolve_frame(frame: *mut (), flags: u64) -> MiriFrame; + /// Miri-provided extern function to get the name and filename of the frame provided by `miri_resolve_frame`. + /// `name_buf` and `filename_buf` should be allocated with the `name_len` and `filename_len` fields of `MiriFrame`. + /// The flags argument must be `0`. + fn miri_resolve_frame_names(ptr: *mut (), flags: u64, name_buf: *mut u8, filename_buf: *mut u8); + /// Miri-provided extern function to begin unwinding with the given payload. /// /// This is internal and unstable and should not be used; we give it here diff --git a/src/shims/backtrace.rs b/src/shims/backtrace.rs index eb25cfd9935ff..52a8ac98f2de9 100644 --- a/src/shims/backtrace.rs +++ b/src/shims/backtrace.rs @@ -1,14 +1,14 @@ use crate::*; use rustc_ast::ast::Mutability; use rustc_middle::ty::layout::LayoutOf as _; -use rustc_middle::ty::{self, TypeAndMut}; -use rustc_span::{BytePos, Symbol}; +use rustc_middle::ty::{self, Instance, TypeAndMut}; +use rustc_span::{BytePos, Loc, Symbol}; use rustc_target::{abi::Size, spec::abi::Abi}; use std::convert::TryInto as _; impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { - fn handle_miri_get_backtrace( + fn handle_miri_backtrace_size( &mut self, abi: Abi, link_name: Symbol, @@ -16,14 +16,34 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx dest: &PlaceTy<'tcx, Tag>, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - let tcx = this.tcx; let &[ref flags] = this.check_shim(abi, Abi::Rust, link_name, args)?; let flags = this.read_scalar(flags)?.to_u64()?; if flags != 0 { - throw_unsup_format!("unknown `miri_get_backtrace` flags {}", flags); + throw_unsup_format!("unknown `miri_backtrace_size` flags {}", flags); } + let frame_count = this.active_thread_stack().len(); + + this.write_scalar(Scalar::from_machine_usize(frame_count.try_into().unwrap(), this), dest) + } + + fn handle_miri_get_backtrace( + &mut self, + abi: Abi, + link_name: Symbol, + args: &[OpTy<'tcx, Tag>], + dest: &PlaceTy<'tcx, Tag>, + ) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + let tcx = this.tcx; + + let flags = if let Some(flags_op) = args.get(0) { + this.read_scalar(flags_op)?.to_u64()? + } else { + throw_ub_format!("expected at least 1 argument") + }; + let mut data = Vec::new(); for frame in this.active_thread_stack().iter().rev() { let mut span = frame.current_span(); @@ -49,46 +69,60 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx }) .collect(); - let len = ptrs.len(); + let len: u64 = ptrs.len().try_into().unwrap(); let ptr_ty = tcx.mk_ptr(TypeAndMut { ty: tcx.types.unit, mutbl: Mutability::Mut }); - let array_ty = tcx.mk_array(ptr_ty, ptrs.len().try_into().unwrap()); + let array_layout = this.layout_of(tcx.mk_array(ptr_ty, len)).unwrap(); - // Write pointers into array - let alloc = - this.allocate(this.layout_of(array_ty).unwrap(), MiriMemoryKind::Rust.into())?; - for (i, ptr) in ptrs.into_iter().enumerate() { - let place = this.mplace_index(&alloc, i as u64)?; - this.write_pointer(ptr, &place.into())?; - } + match flags { + // storage for pointers is allocated by miri + // deallocating the slice is undefined behavior with a custom global allocator + 0 => { + let &[_flags] = this.check_shim(abi, Abi::Rust, link_name, args)?; + + let alloc = this.allocate(array_layout, MiriMemoryKind::Rust.into())?; + + // Write pointers into array + for (i, ptr) in ptrs.into_iter().enumerate() { + let place = this.mplace_index(&alloc, i as u64)?; + + this.write_pointer(ptr, &place.into())?; + } + + this.write_immediate( + Immediate::new_slice(Scalar::from_maybe_pointer(alloc.ptr, this), len, this), + dest, + )?; + } + // storage for pointers is allocated by the caller + 1 => { + let &[_flags, ref buf] = this.check_shim(abi, Abi::Rust, link_name, args)?; + + let buf_place = this.deref_operand(buf)?; + + let ptr_layout = this.layout_of(ptr_ty)?; + + for (i, ptr) in ptrs.into_iter().enumerate() { + let offset = ptr_layout.size * i.try_into().unwrap(); + + let op_place = + buf_place.offset(offset, MemPlaceMeta::None, ptr_layout, this)?; + + this.write_pointer(ptr, &op_place.into())?; + } + } + _ => throw_unsup_format!("unknown `miri_get_backtrace` flags {}", flags), + }; - this.write_immediate( - Immediate::new_slice( - Scalar::from_maybe_pointer(alloc.ptr, this), - len.try_into().unwrap(), - this, - ), - dest, - )?; Ok(()) } - fn handle_miri_resolve_frame( + fn resolve_frame_pointer( &mut self, - abi: Abi, - link_name: Symbol, - args: &[OpTy<'tcx, Tag>], - dest: &PlaceTy<'tcx, Tag>, - ) -> InterpResult<'tcx> { + ptr: &OpTy<'tcx, Tag>, + ) -> InterpResult<'tcx, (Instance<'tcx>, Loc, String, String)> { let this = self.eval_context_mut(); - let tcx = this.tcx; - let &[ref ptr, ref flags] = this.check_shim(abi, Abi::Rust, link_name, args)?; - - let flags = this.read_scalar(flags)?.to_u64()?; - if flags != 0 { - throw_unsup_format!("unknown `miri_resolve_frame` flags {}", flags); - } let ptr = this.read_pointer(ptr)?; // Take apart the pointer, we need its pieces. @@ -101,6 +135,29 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx throw_ub_format!("expected function pointer, found {:?}", ptr); }; + let lo = + this.tcx.sess.source_map().lookup_char_pos(BytePos(offset.bytes().try_into().unwrap())); + + let name = fn_instance.to_string(); + let filename = lo.file.name.prefer_remapped().to_string(); + + Ok((fn_instance, lo, name, filename)) + } + + fn handle_miri_resolve_frame( + &mut self, + abi: Abi, + link_name: Symbol, + args: &[OpTy<'tcx, Tag>], + dest: &PlaceTy<'tcx, Tag>, + ) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + let &[ref ptr, ref flags] = this.check_shim(abi, Abi::Rust, link_name, args)?; + + let flags = this.read_scalar(flags)?.to_u64()?; + + let (fn_instance, lo, name, filename) = this.resolve_frame_pointer(ptr)?; + // Reconstruct the original function pointer, // which we pass to user code. let fn_ptr = this.memory.create_fn_alloc(FnVal::Instance(fn_instance)); @@ -115,23 +172,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ); } - let pos = BytePos(offset.bytes().try_into().unwrap()); - let name = fn_instance.to_string(); - - let lo = tcx.sess.source_map().lookup_char_pos(pos); - - let filename = lo.file.name.prefer_remapped().to_string(); let lineno: u32 = lo.line as u32; // `lo.col` is 0-based - add 1 to make it 1-based for the caller. let colno: u32 = lo.col.0 as u32 + 1; - // These are "mutable" allocations as we consider them to be owned by the callee. - let name_alloc = this.allocate_str(&name, MiriMemoryKind::Rust.into(), Mutability::Mut); - let filename_alloc = - this.allocate_str(&filename, MiriMemoryKind::Rust.into(), Mutability::Mut); - let lineno_alloc = Scalar::from_u32(lineno); - let colno_alloc = Scalar::from_u32(colno); - let dest = this.force_allocation(dest)?; if let ty::Adt(adt, _) = dest.layout.ty.kind() { if !adt.repr.c() { @@ -141,10 +185,38 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } - this.write_immediate(name_alloc.to_ref(this), &this.mplace_field(&dest, 0)?.into())?; - this.write_immediate(filename_alloc.to_ref(this), &this.mplace_field(&dest, 1)?.into())?; - this.write_scalar(lineno_alloc, &this.mplace_field(&dest, 2)?.into())?; - this.write_scalar(colno_alloc, &this.mplace_field(&dest, 3)?.into())?; + match flags { + 0 => { + // These are "mutable" allocations as we consider them to be owned by the callee. + let name_alloc = + this.allocate_str(&name, MiriMemoryKind::Rust.into(), Mutability::Mut); + let filename_alloc = + this.allocate_str(&filename, MiriMemoryKind::Rust.into(), Mutability::Mut); + + this.write_immediate( + name_alloc.to_ref(this), + &this.mplace_field(&dest, 0)?.into(), + )?; + this.write_immediate( + filename_alloc.to_ref(this), + &this.mplace_field(&dest, 1)?.into(), + )?; + } + 1 => { + this.write_scalar( + Scalar::from_machine_usize(name.len().try_into().unwrap(), this), + &this.mplace_field(&dest, 0)?.into(), + )?; + this.write_scalar( + Scalar::from_machine_usize(filename.len().try_into().unwrap(), this), + &this.mplace_field(&dest, 1)?.into(), + )?; + } + _ => throw_unsup_format!("unknown `miri_resolve_frame` flags {}", flags), + } + + this.write_scalar(Scalar::from_u32(lineno), &this.mplace_field(&dest, 2)?.into())?; + this.write_scalar(Scalar::from_u32(colno), &this.mplace_field(&dest, 3)?.into())?; // Support a 4-field struct for now - this is deprecated // and slated for removal. @@ -154,4 +226,28 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(()) } + + fn handle_miri_resolve_frame_names( + &mut self, + abi: Abi, + link_name: Symbol, + args: &[OpTy<'tcx, Tag>], + ) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + + let &[ref ptr, ref flags, ref name_ptr, ref filename_ptr] = + this.check_shim(abi, Abi::Rust, link_name, args)?; + + let flags = this.read_scalar(flags)?.to_u64()?; + if flags != 0 { + throw_unsup_format!("unknown `miri_resolve_frame_names` flags {}", flags); + } + + let (_, _, name, filename) = this.resolve_frame_pointer(ptr)?; + + this.memory.write_bytes(this.read_pointer(name_ptr)?, name.bytes())?; + this.memory.write_bytes(this.read_pointer(filename_ptr)?, filename.bytes())?; + + Ok(()) + } } diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index b07db9535129f..ecffd310de569 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -380,6 +380,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.machine.static_roots.push(alloc_id); } + // Obtains the size of a Miri backtrace. See the README for details. + "miri_backtrace_size" => { + this.handle_miri_backtrace_size(abi, link_name, args, dest)?; + } + // Obtains a Miri backtrace. See the README for details. "miri_get_backtrace" => { // `check_shim` happens inside `handle_miri_get_backtrace`. @@ -392,6 +397,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.handle_miri_resolve_frame(abi, link_name, args, dest)?; } + // Writes the function and file names of a Miri backtrace frame into a user provided buffer. See the README for details. + "miri_resolve_frame_names" => { + this.handle_miri_resolve_frame_names(abi, link_name, args)?; + } // Standard C allocation "malloc" => { diff --git a/tests/compile-fail/backtrace/bad-backtrace-flags.rs b/tests/compile-fail/backtrace/bad-backtrace-flags.rs new file mode 100644 index 0000000000000..5f30513e931ef --- /dev/null +++ b/tests/compile-fail/backtrace/bad-backtrace-flags.rs @@ -0,0 +1,9 @@ +extern "Rust" { + fn miri_get_backtrace(flags: u64, buf: *mut *mut ()); +} + +fn main() { + unsafe { + miri_get_backtrace(2, 0 as *mut _); //~ ERROR unsupported operation: unknown `miri_get_backtrace` flags 2 + } +} diff --git a/tests/compile-fail/backtrace/bad-backtrace-resolve-flags.rs b/tests/compile-fail/backtrace/bad-backtrace-resolve-flags.rs new file mode 100644 index 0000000000000..5a30253a893b8 --- /dev/null +++ b/tests/compile-fail/backtrace/bad-backtrace-resolve-flags.rs @@ -0,0 +1,25 @@ +#[repr(C)] +struct MiriFrame { + name_len: usize, + filename_len: usize, + lineno: u32, + colno: u32, + fn_ptr: *mut (), +} + +extern "Rust" { + fn miri_backtrace_size(flags: u64) -> usize; + fn miri_get_backtrace(flags: u64, buf: *mut *mut ()); + fn miri_resolve_frame(ptr: *mut (), flags: u64) -> MiriFrame; +} + +fn main() { + unsafe { + let mut buf = vec![0 as *mut _; miri_backtrace_size(0)]; + + miri_get_backtrace(1, buf.as_mut_ptr()); + + // miri_resolve_frame will error from an invalid backtrace before it will from invalid flags + miri_resolve_frame(buf[0], 2); //~ ERROR unsupported operation: unknown `miri_resolve_frame` flags 2 + } +} diff --git a/tests/compile-fail/backtrace/bad-backtrace-resolve-names-flags.rs b/tests/compile-fail/backtrace/bad-backtrace-resolve-names-flags.rs new file mode 100644 index 0000000000000..8e69a275753f1 --- /dev/null +++ b/tests/compile-fail/backtrace/bad-backtrace-resolve-names-flags.rs @@ -0,0 +1,16 @@ +extern "Rust" { + fn miri_backtrace_size(flags: u64) -> usize; + fn miri_get_backtrace(flags: u64, buf: *mut *mut ()); + fn miri_resolve_frame_names(ptr: *mut (), flags: u64, name_buf: *mut u8, filename_buf: *mut u8); +} + +fn main() { + unsafe { + let mut buf = vec![0 as *mut _; miri_backtrace_size(0)]; + + miri_get_backtrace(1, buf.as_mut_ptr()); + + // miri_resolve_frame_names will error from an invalid backtrace before it will from invalid flags + miri_resolve_frame_names(buf[0], 2, 0 as *mut _, 0 as *mut _); //~ ERROR unsupported operation: unknown `miri_resolve_frame_names` flags 2 + } +} diff --git a/tests/compile-fail/backtrace/bad-backtrace-size-flags.rs b/tests/compile-fail/backtrace/bad-backtrace-size-flags.rs new file mode 100644 index 0000000000000..25eded9e48df7 --- /dev/null +++ b/tests/compile-fail/backtrace/bad-backtrace-size-flags.rs @@ -0,0 +1,9 @@ +extern "Rust" { + fn miri_backtrace_size(flags: u64) -> usize; +} + +fn main() { + unsafe { + miri_backtrace_size(2); //~ ERROR unsupported operation: unknown `miri_backtrace_size` flags 2 + } +} diff --git a/tests/compile-fail/backtrace/bad-backtrace-version.rs b/tests/compile-fail/backtrace/bad-backtrace-version.rs deleted file mode 100644 index 4579b5d0ade89..0000000000000 --- a/tests/compile-fail/backtrace/bad-backtrace-version.rs +++ /dev/null @@ -1,9 +0,0 @@ -extern "Rust" { - fn miri_resolve_frame(ptr: *mut (), flags: u64); -} - -fn main() { - unsafe { - miri_resolve_frame(0 as *mut _, 1); //~ ERROR unsupported operation: unknown `miri_resolve_frame` flags 1 - } -} diff --git a/tests/run-pass/backtrace-api.rs b/tests/run-pass/backtrace-api-v0.rs similarity index 100% rename from tests/run-pass/backtrace-api.rs rename to tests/run-pass/backtrace-api-v0.rs diff --git a/tests/run-pass/backtrace-api.stderr b/tests/run-pass/backtrace-api-v0.stderr similarity index 82% rename from tests/run-pass/backtrace-api.stderr rename to tests/run-pass/backtrace-api-v0.stderr index bd5908ba29794..8a697a44ea9dc 100644 --- a/tests/run-pass/backtrace-api.stderr +++ b/tests/run-pass/backtrace-api-v0.stderr @@ -1,8 +1,8 @@ -$DIR/backtrace-api.rs:13:59 (func_d) -$DIR/backtrace-api.rs:12:50 (func_c) -$DIR/backtrace-api.rs:6:53 (func_b) -$DIR/backtrace-api.rs:5:50 (func_a) -$DIR/backtrace-api.rs:17:18 (main) +$DIR/backtrace-api-v0.rs:13:59 (func_d) +$DIR/backtrace-api-v0.rs:12:50 (func_c) +$DIR/backtrace-api-v0.rs:6:53 (func_b) +$DIR/backtrace-api-v0.rs:5:50 (func_a) +$DIR/backtrace-api-v0.rs:17:18 (main) RUSTLIB/core/src/ops/function.rs:LL:COL (>::call_once - shim(fn())) RUSTLIB/std/src/sys_common/backtrace.rs:LL:COL (std::sys_common::backtrace::__rust_begin_short_backtrace) RUSTLIB/std/src/rt.rs:LL:COL (std::rt::lang_start::{closure#0}) diff --git a/tests/run-pass/backtrace-api-v0.stdout b/tests/run-pass/backtrace-api-v0.stdout new file mode 100644 index 0000000000000..c80a3f3bbcab6 --- /dev/null +++ b/tests/run-pass/backtrace-api-v0.stdout @@ -0,0 +1,5 @@ +$DIR/backtrace-api-v0.rs:13:59 (func_d) +$DIR/backtrace-api-v0.rs:12:50 (func_c) +$DIR/backtrace-api-v0.rs:6:53 (func_b::) +$DIR/backtrace-api-v0.rs:5:50 (func_a) +$DIR/backtrace-api-v0.rs:17:18 (main) diff --git a/tests/run-pass/backtrace-api-v1.rs b/tests/run-pass/backtrace-api-v1.rs new file mode 100644 index 0000000000000..7b72c85812eb0 --- /dev/null +++ b/tests/run-pass/backtrace-api-v1.rs @@ -0,0 +1,65 @@ +// normalize-stderr-test ".*/(rust[^/]*|checkout)/library/" -> "RUSTLIB/" +// normalize-stderr-test "RUSTLIB/(.*):\d+:\d+ "-> "RUSTLIB/$1:LL:COL " +// normalize-stderr-test "::<.*>" -> "" + +#[inline(never)] fn func_a() -> Box<[*mut ()]> { func_b::() } +#[inline(never)] fn func_b() -> Box<[*mut ()]> { func_c() } + +macro_rules! invoke_func_d { + () => { func_d() } +} + +#[inline(never)] fn func_c() -> Box<[*mut ()]> { invoke_func_d!() } +#[inline(never)] fn func_d() -> Box<[*mut ()]> { unsafe { let count = miri_backtrace_size(0); let mut buf = vec![std::ptr::null_mut(); count]; miri_get_backtrace(1, buf.as_mut_ptr()); buf.into() } } + +fn main() { + let mut seen_main = false; + let frames = func_a(); + for frame in frames.into_iter() { + let miri_frame = unsafe { miri_resolve_frame(*frame, 1) }; + + let mut name = vec![0; miri_frame.name_len]; + let mut filename = vec![0; miri_frame.filename_len]; + + unsafe { + miri_resolve_frame_names(*frame, 0, name.as_mut_ptr(), filename.as_mut_ptr()); + } + + let name = String::from_utf8(name).unwrap(); + let filename = String::from_utf8(filename).unwrap(); + + if name == "func_a" { + assert_eq!(func_a as *mut (), miri_frame.fn_ptr); + } + + // Print every frame to stderr. + let out = format!("{}:{}:{} ({})", filename, miri_frame.lineno, miri_frame.colno, name); + eprintln!("{}", out); + // Print the 'main' frame (and everything before it) to stdout, skipping + // the printing of internal (and possibly fragile) libstd frames. + if !seen_main { + println!("{}", out); + seen_main = name == "main"; + } + } +} + +// This goes at the bottom of the file so that we can change it +// without disturbing line numbers of the functions in the backtrace. + +extern "Rust" { + fn miri_backtrace_size(flags: u64) -> usize; + fn miri_get_backtrace(flags: u64, buf: *mut *mut ()); + fn miri_resolve_frame(ptr: *mut (), flags: u64) -> MiriFrame; + fn miri_resolve_frame_names(ptr: *mut (), flags: u64, name_buf: *mut u8, filename_buf: *mut u8); +} + +#[derive(Debug)] +#[repr(C)] +struct MiriFrame { + name_len: usize, + filename_len: usize, + lineno: u32, + colno: u32, + fn_ptr: *mut (), +} \ No newline at end of file diff --git a/tests/run-pass/backtrace-api-v1.stderr b/tests/run-pass/backtrace-api-v1.stderr new file mode 100644 index 0000000000000..806a1c60f5a04 --- /dev/null +++ b/tests/run-pass/backtrace-api-v1.stderr @@ -0,0 +1,18 @@ +$DIR/backtrace-api-v1.rs:13:144 (func_d) +$DIR/backtrace-api-v1.rs:12:50 (func_c) +$DIR/backtrace-api-v1.rs:6:53 (func_b) +$DIR/backtrace-api-v1.rs:5:50 (func_a) +$DIR/backtrace-api-v1.rs:17:18 (main) +RUSTLIB/core/src/ops/function.rs:LL:COL (>::call_once - shim(fn())) +RUSTLIB/std/src/sys_common/backtrace.rs:LL:COL (std::sys_common::backtrace::__rust_begin_short_backtrace) +RUSTLIB/std/src/rt.rs:LL:COL (std::rt::lang_start::{closure#0}) +RUSTLIB/core/src/ops/function.rs:LL:COL (std::ops::function::impls::call_once) +RUSTLIB/std/src/panicking.rs:LL:COL (std::panicking::r#try::do_call) +RUSTLIB/std/src/panicking.rs:LL:COL (std::panicking::r#try) +RUSTLIB/std/src/panic.rs:LL:COL (std::panic::catch_unwind) +RUSTLIB/std/src/rt.rs:LL:COL (std::rt::lang_start_internal::{closure#2}) +RUSTLIB/std/src/panicking.rs:LL:COL (std::panicking::r#try::do_call) +RUSTLIB/std/src/panicking.rs:LL:COL (std::panicking::r#try) +RUSTLIB/std/src/panic.rs:LL:COL (std::panic::catch_unwind) +RUSTLIB/std/src/rt.rs:LL:COL (std::rt::lang_start_internal) +RUSTLIB/std/src/rt.rs:LL:COL (std::rt::lang_start) diff --git a/tests/run-pass/backtrace-api-v1.stdout b/tests/run-pass/backtrace-api-v1.stdout new file mode 100644 index 0000000000000..2670d560eb193 --- /dev/null +++ b/tests/run-pass/backtrace-api-v1.stdout @@ -0,0 +1,5 @@ +$DIR/backtrace-api-v1.rs:13:144 (func_d) +$DIR/backtrace-api-v1.rs:12:50 (func_c) +$DIR/backtrace-api-v1.rs:6:53 (func_b::) +$DIR/backtrace-api-v1.rs:5:50 (func_a) +$DIR/backtrace-api-v1.rs:17:18 (main) diff --git a/tests/run-pass/backtrace-api.stdout b/tests/run-pass/backtrace-api.stdout deleted file mode 100644 index 175ff3b829461..0000000000000 --- a/tests/run-pass/backtrace-api.stdout +++ /dev/null @@ -1,5 +0,0 @@ -$DIR/backtrace-api.rs:13:59 (func_d) -$DIR/backtrace-api.rs:12:50 (func_c) -$DIR/backtrace-api.rs:6:53 (func_b::) -$DIR/backtrace-api.rs:5:50 (func_a) -$DIR/backtrace-api.rs:17:18 (main) From 65469fe85bd1ca30ee5f890e49799d6a67688006 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 12 Mar 2022 13:37:46 -0500 Subject: [PATCH 2947/3747] test remove_dir_all --- src/shims/posix/macos/dlsym.rs | 1 - tests/run-pass/fs.rs | 6 ++++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/shims/posix/macos/dlsym.rs b/src/shims/posix/macos/dlsym.rs index 9994bfd53dc5d..d5996cc6a9ed1 100644 --- a/src/shims/posix/macos/dlsym.rs +++ b/src/shims/posix/macos/dlsym.rs @@ -17,7 +17,6 @@ impl Dlsym { pub fn from_str(name: &str) -> InterpResult<'static, Option> { Ok(match name { "getentropy" => Some(Dlsym::getentropy), - "openat" => None, // std has a fallback for this _ => throw_unsup_format!("unsupported macOS dlsym: {}", name), }) } diff --git a/tests/run-pass/fs.rs b/tests/run-pass/fs.rs index 7f5553e2f2cb9..67817e3e2c856 100644 --- a/tests/run-pass/fs.rs +++ b/tests/run-pass/fs.rs @@ -395,6 +395,12 @@ fn test_directory() { remove_dir(&dir_path).unwrap(); // Reading the metadata of a non-existent directory should fail with a "not found" error. assert_eq!(ErrorKind::NotFound, check_metadata(&[], &dir_path).unwrap_err().kind()); + + // To test remove_dir_all, re-create the directory with a file and a directory in it. + create_dir(&dir_path).unwrap(); + drop(File::create(&path_1).unwrap()); + create_dir(&path_2).unwrap(); + remove_dir_all(&dir_path).unwrap(); } fn test_dup_stdout_stderr() { From 1cda05e174b9860f6c683a55167ab577988c999e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 20 Mar 2022 10:36:44 -0400 Subject: [PATCH 2948/3747] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 5306a4d186284..249d5ad47eb81 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -e95b10ba4ac4564ed25f7eef143e3182c33b3902 +c7ce69faf2a7ea16c15d922985ca27ba70da30ee From aafc0694fc002c744b4aa7aa77186bcd0a58622f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 18 Mar 2022 08:50:49 -0400 Subject: [PATCH 2949/3747] test arbitrary-self dyn receivers --- tests/run-pass/dyn-arbitrary-self.rs | 134 +++++++++++++++++++++++++++ 1 file changed, 134 insertions(+) create mode 100644 tests/run-pass/dyn-arbitrary-self.rs diff --git a/tests/run-pass/dyn-arbitrary-self.rs b/tests/run-pass/dyn-arbitrary-self.rs new file mode 100644 index 0000000000000..9003c478990b2 --- /dev/null +++ b/tests/run-pass/dyn-arbitrary-self.rs @@ -0,0 +1,134 @@ +#![feature(arbitrary_self_types, unsize, coerce_unsized, dispatch_from_dyn)] +#![feature(rustc_attrs)] + +fn pin_box_dyn() { + use std::pin::Pin; + + trait Foo { + fn bar(self: Pin<&mut Self>) -> bool; + } + + impl Foo for &'static str { + fn bar(self: Pin<&mut Self>) -> bool { + true + } + } + + let mut test: Pin> = Box::pin("foo"); + test.as_mut().bar(); +} + +fn stdlib_pointers() { + use std::{ + rc::Rc, + sync::Arc, + pin::Pin, + }; + + trait Trait { + fn by_rc(self: Rc) -> i64; + fn by_arc(self: Arc) -> i64; + fn by_pin_mut(self: Pin<&mut Self>) -> i64; + fn by_pin_box(self: Pin>) -> i64; + } + + impl Trait for i64 { + fn by_rc(self: Rc) -> i64 { + *self + } + fn by_arc(self: Arc) -> i64 { + *self + } + fn by_pin_mut(self: Pin<&mut Self>) -> i64 { + *self + } + fn by_pin_box(self: Pin>) -> i64 { + *self + } + } + + let rc = Rc::new(1i64) as Rc; + assert_eq!(1, rc.by_rc()); + + let arc = Arc::new(2i64) as Arc; + assert_eq!(2, arc.by_arc()); + + let mut value = 3i64; + let pin_mut = Pin::new(&mut value) as Pin<&mut dyn Trait>; + assert_eq!(3, pin_mut.by_pin_mut()); + + let pin_box = Into::>>::into(Box::new(4i64)) as Pin>; + assert_eq!(4, pin_box.by_pin_box()); +} + +fn pointers_and_wrappers() { + use std::{ + ops::{Deref, CoerceUnsized, DispatchFromDyn}, + marker::Unsize, + }; + + struct Ptr(Box); + + impl Deref for Ptr { + type Target = T; + + fn deref(&self) -> &T { + &*self.0 + } + } + + impl + ?Sized, U: ?Sized> CoerceUnsized> for Ptr {} + impl + ?Sized, U: ?Sized> DispatchFromDyn> for Ptr {} + + struct Wrapper(T); + + impl Deref for Wrapper { + type Target = T; + + fn deref(&self) -> &T { + &self.0 + } + } + + impl, U> CoerceUnsized> for Wrapper {} + impl, U> DispatchFromDyn> for Wrapper {} + + + trait Trait { + // This method isn't object-safe yet. Unsized by-value `self` is object-safe (but not callable + // without unsized_locals), but wrappers arond `Self` currently are not. + // FIXME (mikeyhew) uncomment this when unsized rvalues object-safety is implemented + // fn wrapper(self: Wrapper) -> i32; + fn ptr_wrapper(self: Ptr>) -> i32; + fn wrapper_ptr(self: Wrapper>) -> i32; + fn wrapper_ptr_wrapper(self: Wrapper>>) -> i32; + } + + impl Trait for i32 { + fn ptr_wrapper(self: Ptr>) -> i32 { + **self + } + fn wrapper_ptr(self: Wrapper>) -> i32 { + **self + } + fn wrapper_ptr_wrapper(self: Wrapper>>) -> i32 { + ***self + } + } + + let pw = Ptr(Box::new(Wrapper(5))) as Ptr>; + assert_eq!(pw.ptr_wrapper(), 5); + + let wp = Wrapper(Ptr(Box::new(6))) as Wrapper>; + assert_eq!(wp.wrapper_ptr(), 6); + + let wpw = Wrapper(Ptr(Box::new(Wrapper(7)))) as Wrapper>>; + assert_eq!(wpw.wrapper_ptr_wrapper(), 7); +} + + +fn main() { + pin_box_dyn(); + stdlib_pointers(); + pointers_and_wrappers(); +} From b066856f34240fdb8789c1ddd0c732a50a27b0f8 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 20 Mar 2022 14:04:05 -0400 Subject: [PATCH 2950/3747] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 249d5ad47eb81..561d020f1200f 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -c7ce69faf2a7ea16c15d922985ca27ba70da30ee +9bd53718e2537d95d8c092609618c2dcd6f05127 From 694846f8b462739ecefc476e7b2a9662ead3759d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 22 Mar 2022 14:26:40 -0400 Subject: [PATCH 2951/3747] vec test: check number validity --- tests/run-pass/vec.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/run-pass/vec.rs b/tests/run-pass/vec.rs index c0cf42134527c..44e25387fff47 100644 --- a/tests/run-pass/vec.rs +++ b/tests/run-pass/vec.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-tag-raw-pointers +// compile-flags: -Zmiri-tag-raw-pointers -Zmiri-check-number-validity // Gather all references from a mutable iterator and make sure Miri notices if // using them is dangerous. fn test_all_refs<'a, T: 'a>(dummy: &mut T, iter: impl Iterator) { From 951ac65f265022a30e9538c4123862728f0816b1 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 22 Mar 2022 14:28:36 -0400 Subject: [PATCH 2952/3747] regression test for reverse() unsoundness --- tests/run-pass/vec.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/tests/run-pass/vec.rs b/tests/run-pass/vec.rs index 44e25387fff47..102396f4b91f7 100644 --- a/tests/run-pass/vec.rs +++ b/tests/run-pass/vec.rs @@ -148,6 +148,16 @@ fn swap_remove() { vec.swap_remove(1); } +fn reverse() { + #[repr(align(2))] + #[derive(Debug)] + struct Foo(u8); + + let mut v: Vec<_> = (0..50).map(Foo).collect(); + v.reverse(); + assert!(v[0].0 == 49); +} + fn main() { assert_eq!(vec_reallocate().len(), 5); @@ -176,4 +186,5 @@ fn main() { sort(); swap(); swap_remove(); + reverse(); } From 3275df31ea91d638fd75cc5f627c211de8bd8f71 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 24 Mar 2022 10:06:33 -0400 Subject: [PATCH 2953/3747] rustup --- rust-version | 2 +- tests/compile-fail/null_pointer_deref.rs | 2 +- tests/compile-fail/null_pointer_write.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/rust-version b/rust-version index 561d020f1200f..7c9e50da5cebd 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -9bd53718e2537d95d8c092609618c2dcd6f05127 +d2df372bca13bb60979c909660e69f2451630e81 diff --git a/tests/compile-fail/null_pointer_deref.rs b/tests/compile-fail/null_pointer_deref.rs index 076b2df609abd..92c45b183c0c7 100644 --- a/tests/compile-fail/null_pointer_deref.rs +++ b/tests/compile-fail/null_pointer_deref.rs @@ -1,5 +1,5 @@ #[allow(deref_nullptr)] fn main() { - let x: i32 = unsafe { *std::ptr::null() }; //~ ERROR null pointer is not a valid pointer for this operation + let x: i32 = unsafe { *std::ptr::null() }; //~ ERROR null pointer is not a valid pointer panic!("this should never print: {}", x); } diff --git a/tests/compile-fail/null_pointer_write.rs b/tests/compile-fail/null_pointer_write.rs index 5294e60c025fb..f8dca6882c2d5 100644 --- a/tests/compile-fail/null_pointer_write.rs +++ b/tests/compile-fail/null_pointer_write.rs @@ -1,4 +1,4 @@ #[allow(deref_nullptr)] fn main() { - unsafe { *std::ptr::null_mut() = 0i32 }; //~ ERROR null pointer is not a valid pointer for this operation + unsafe { *std::ptr::null_mut() = 0i32 }; //~ ERROR null pointer is not a valid pointer } From 9772c85ebc9620050eec48a322d96d7474ab97f5 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 26 Mar 2022 10:44:30 -0400 Subject: [PATCH 2954/3747] another test for too big type --- .../{slice-too-big.rs => too-big-slice.rs} | 0 tests/compile-fail/too-big-unsized.rs | 18 ++++++++++++++++++ 2 files changed, 18 insertions(+) rename tests/compile-fail/{slice-too-big.rs => too-big-slice.rs} (100%) create mode 100644 tests/compile-fail/too-big-unsized.rs diff --git a/tests/compile-fail/slice-too-big.rs b/tests/compile-fail/too-big-slice.rs similarity index 100% rename from tests/compile-fail/slice-too-big.rs rename to tests/compile-fail/too-big-slice.rs diff --git a/tests/compile-fail/too-big-unsized.rs b/tests/compile-fail/too-big-unsized.rs new file mode 100644 index 0000000000000..ad7bc6e938acb --- /dev/null +++ b/tests/compile-fail/too-big-unsized.rs @@ -0,0 +1,18 @@ +use std::mem; + +#[allow(unused)] +struct MySlice { + prefix: u64, + tail: [u8], +} + +#[cfg(target_pointer_width = "64")] +const TOO_BIG: usize = 1usize << 47; +#[cfg(target_pointer_width = "32")] +const TOO_BIG: usize = 1usize << 31; + +fn main() { unsafe { + let ptr = Box::into_raw(Box::new(0u8)); + // The slice part is actually not "too big", but together with the `prefix` field it is. + let _x: &MySlice = mem::transmute((ptr, TOO_BIG-1)); //~ ERROR: invalid reference metadata: total size is bigger than largest supported object +} } From ede470e1fcb8b6e488f39c48a84cde0f639adcc9 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 26 Mar 2022 13:10:20 -0400 Subject: [PATCH 2955/3747] ensure that -Zmiri-check-number-validity detects integers with provenance --- tests/compile-fail/ptr_integer_array_transmute.rs | 6 ++++++ tests/compile-fail/ptr_integer_transmute.rs | 6 ++++++ 2 files changed, 12 insertions(+) create mode 100644 tests/compile-fail/ptr_integer_array_transmute.rs create mode 100644 tests/compile-fail/ptr_integer_transmute.rs diff --git a/tests/compile-fail/ptr_integer_array_transmute.rs b/tests/compile-fail/ptr_integer_array_transmute.rs new file mode 100644 index 0000000000000..7a1ae2f3c9a11 --- /dev/null +++ b/tests/compile-fail/ptr_integer_array_transmute.rs @@ -0,0 +1,6 @@ +// compile-flags: -Zmiri-check-number-validity + +fn main() { + let r = &mut 42; + let _i: [usize; 1] = unsafe { std::mem::transmute(r) }; //~ ERROR encountered a pointer, but expected plain (non-pointer) bytes +} diff --git a/tests/compile-fail/ptr_integer_transmute.rs b/tests/compile-fail/ptr_integer_transmute.rs new file mode 100644 index 0000000000000..e15a157637575 --- /dev/null +++ b/tests/compile-fail/ptr_integer_transmute.rs @@ -0,0 +1,6 @@ +// compile-flags: -Zmiri-check-number-validity + +fn main() { + let r = &mut 42; + let _i: usize = unsafe { std::mem::transmute(r) }; //~ ERROR expected initialized plain (non-pointer) bytes +} From 552b77e3b9841f697d954f2ab341711dbff8d029 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 26 Mar 2022 14:29:58 -0400 Subject: [PATCH 2956/3747] fix types in env shim to avoid ptr-int transmutes --- src/machine.rs | 23 ++++++++++++++--------- src/shims/backtrace.rs | 5 ++--- src/shims/env.rs | 7 ++++--- 3 files changed, 20 insertions(+), 15 deletions(-) diff --git a/src/machine.rs b/src/machine.rs index 2cf7cd0fae0e2..9c763149ffa21 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -10,13 +10,14 @@ use std::time::Instant; use rand::rngs::StdRng; use rand::SeedableRng; +use rustc_ast::ast::Mutability; use rustc_data_structures::fx::FxHashMap; use rustc_middle::{ mir, ty::{ self, layout::{LayoutCx, LayoutError, LayoutOf, TyAndLayout}, - Instance, TyCtxt, + Instance, TyCtxt, TypeAndMut, }, }; use rustc_span::def_id::{CrateNum, DefId}; @@ -269,19 +270,23 @@ pub struct PrimitiveLayouts<'tcx> { pub u32: TyAndLayout<'tcx>, pub usize: TyAndLayout<'tcx>, pub bool: TyAndLayout<'tcx>, + pub mut_raw_ptr: TyAndLayout<'tcx>, } impl<'mir, 'tcx: 'mir> PrimitiveLayouts<'tcx> { fn new(layout_cx: LayoutCx<'tcx, TyCtxt<'tcx>>) -> Result> { + let tcx = layout_cx.tcx; + let mut_raw_ptr = tcx.mk_ptr(TypeAndMut { ty: tcx.types.unit, mutbl: Mutability::Mut }); Ok(Self { - unit: layout_cx.layout_of(layout_cx.tcx.mk_unit())?, - i8: layout_cx.layout_of(layout_cx.tcx.types.i8)?, - i32: layout_cx.layout_of(layout_cx.tcx.types.i32)?, - isize: layout_cx.layout_of(layout_cx.tcx.types.isize)?, - u8: layout_cx.layout_of(layout_cx.tcx.types.u8)?, - u32: layout_cx.layout_of(layout_cx.tcx.types.u32)?, - usize: layout_cx.layout_of(layout_cx.tcx.types.usize)?, - bool: layout_cx.layout_of(layout_cx.tcx.types.bool)?, + unit: layout_cx.layout_of(tcx.mk_unit())?, + i8: layout_cx.layout_of(tcx.types.i8)?, + i32: layout_cx.layout_of(tcx.types.i32)?, + isize: layout_cx.layout_of(tcx.types.isize)?, + u8: layout_cx.layout_of(tcx.types.u8)?, + u32: layout_cx.layout_of(tcx.types.u32)?, + usize: layout_cx.layout_of(tcx.types.usize)?, + bool: layout_cx.layout_of(tcx.types.bool)?, + mut_raw_ptr: layout_cx.layout_of(mut_raw_ptr)?, }) } } diff --git a/src/shims/backtrace.rs b/src/shims/backtrace.rs index 541cec8e84743..6a8a9553e9363 100644 --- a/src/shims/backtrace.rs +++ b/src/shims/backtrace.rs @@ -1,7 +1,7 @@ use crate::*; use rustc_ast::ast::Mutability; use rustc_middle::ty::layout::LayoutOf as _; -use rustc_middle::ty::{self, Instance, TypeAndMut}; +use rustc_middle::ty::{self, Instance}; use rustc_span::{BytePos, Loc, Symbol}; use rustc_target::{abi::Size, spec::abi::Abi}; use std::convert::TryInto as _; @@ -71,8 +71,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let len: u64 = ptrs.len().try_into().unwrap(); - let ptr_ty = tcx.mk_ptr(TypeAndMut { ty: tcx.types.unit, mutbl: Mutability::Mut }); - + let ptr_ty = this.machine.layouts.mut_raw_ptr.ty; let array_layout = this.layout_of(tcx.mk_array(ptr_ty, len)).unwrap(); match flags { diff --git a/src/shims/env.rs b/src/shims/env.rs index 1916d7d70a41e..c2050647abca2 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -440,7 +440,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } else { // No `environ` allocated yet, let's do that. // This is memory backing an extern static, hence `ExternStatic`, not `Env`. - let layout = this.machine.layouts.usize; + let layout = this.machine.layouts.mut_raw_ptr; let place = this.allocate(layout, MiriMemoryKind::ExternStatic.into())?; this.machine.env_vars.environ = Some(place); } @@ -452,8 +452,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx vars.push(Pointer::null()); // Make an array with all these pointers inside Miri. let tcx = this.tcx; - let vars_layout = - this.layout_of(tcx.mk_array(tcx.types.usize, u64::try_from(vars.len()).unwrap()))?; + let vars_layout = this.layout_of( + tcx.mk_array(this.machine.layouts.mut_raw_ptr.ty, u64::try_from(vars.len()).unwrap()), + )?; let vars_place = this.allocate(vars_layout, MiriMemoryKind::Runtime.into())?; for (idx, var) in vars.into_iter().enumerate() { let place = this.mplace_field(&vars_place, idx)?; From 5d7c495de5d4ed870fe9c4fc2337c5ce0c96dec9 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 26 Mar 2022 14:33:17 -0400 Subject: [PATCH 2957/3747] channels do ptr-int transmutes so move them to non-check-number-validity test --- tests/run-pass/concurrency/channels.rs | 57 +++++++++++++++++++++ tests/run-pass/concurrency/channels.stderr | 2 + tests/run-pass/concurrency/simple.rs | 1 + tests/run-pass/concurrency/simple.stderr | 4 +- tests/run-pass/concurrency/sync.rs | 50 ------------------ tests/run-pass/concurrency/thread_locals.rs | 1 + 6 files changed, 63 insertions(+), 52 deletions(-) create mode 100644 tests/run-pass/concurrency/channels.rs create mode 100644 tests/run-pass/concurrency/channels.stderr diff --git a/tests/run-pass/concurrency/channels.rs b/tests/run-pass/concurrency/channels.rs new file mode 100644 index 0000000000000..58d073c85acc5 --- /dev/null +++ b/tests/run-pass/concurrency/channels.rs @@ -0,0 +1,57 @@ +// ignore-windows: Concurrency on Windows is not supported yet. +// compile-flags: -Zmiri-disable-isolation + +use std::sync::mpsc::{channel, sync_channel}; +use std::thread; + +// Check if channels are working. + +/// The test taken from the Rust documentation. +fn simple_send() { + let (tx, rx) = channel(); + thread::spawn(move || { + tx.send(10).unwrap(); + }); + assert_eq!(rx.recv().unwrap(), 10); +} + +/// The test taken from the Rust documentation. +fn multiple_send() { + let (tx, rx) = channel(); + for i in 0..10 { + let tx = tx.clone(); + thread::spawn(move || { + tx.send(i).unwrap(); + }); + } + + let mut sum = 0; + for _ in 0..10 { + let j = rx.recv().unwrap(); + assert!(0 <= j && j < 10); + sum += j; + } + assert_eq!(sum, 45); +} + +/// The test taken from the Rust documentation. +fn send_on_sync() { + let (sender, receiver) = sync_channel(1); + + // this returns immediately + sender.send(1).unwrap(); + + thread::spawn(move || { + // this will block until the previous message has been received + sender.send(2).unwrap(); + }); + + assert_eq!(receiver.recv().unwrap(), 1); + assert_eq!(receiver.recv().unwrap(), 2); +} + +fn main() { + simple_send(); + multiple_send(); + send_on_sync(); +} diff --git a/tests/run-pass/concurrency/channels.stderr b/tests/run-pass/concurrency/channels.stderr new file mode 100644 index 0000000000000..03676519d4f1c --- /dev/null +++ b/tests/run-pass/concurrency/channels.stderr @@ -0,0 +1,2 @@ +warning: thread support is experimental and incomplete: weak memory effects are not emulated. + diff --git a/tests/run-pass/concurrency/simple.rs b/tests/run-pass/concurrency/simple.rs index c22506821f548..c659cfbc3fdc2 100644 --- a/tests/run-pass/concurrency/simple.rs +++ b/tests/run-pass/concurrency/simple.rs @@ -1,4 +1,5 @@ // ignore-windows: Concurrency on Windows is not supported yet. +// compile-flags: -Zmiri-check-number-validity use std::thread; diff --git a/tests/run-pass/concurrency/simple.stderr b/tests/run-pass/concurrency/simple.stderr index f46b1442d749f..35f5f10274c95 100644 --- a/tests/run-pass/concurrency/simple.stderr +++ b/tests/run-pass/concurrency/simple.stderr @@ -1,5 +1,5 @@ warning: thread support is experimental and incomplete: weak memory effects are not emulated. -thread '' panicked at 'Hello!', $DIR/simple.rs:54:9 +thread '' panicked at 'Hello!', $DIR/simple.rs:55:9 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace -thread 'childthread' panicked at 'Hello, world!', $DIR/simple.rs:64:9 +thread 'childthread' panicked at 'Hello, world!', $DIR/simple.rs:65:9 diff --git a/tests/run-pass/concurrency/sync.rs b/tests/run-pass/concurrency/sync.rs index da6f6f25ec1cd..d47aa2a8d234a 100644 --- a/tests/run-pass/concurrency/sync.rs +++ b/tests/run-pass/concurrency/sync.rs @@ -1,7 +1,6 @@ // ignore-windows: Concurrency on Windows is not supported yet. // compile-flags: -Zmiri-disable-isolation -Zmiri-check-number-validity -use std::sync::mpsc::{channel, sync_channel}; use std::sync::{Arc, Barrier, Condvar, Mutex, Once, RwLock}; use std::thread; use std::time::{Duration, Instant}; @@ -181,52 +180,6 @@ fn check_rwlock_read_no_deadlock() { handle.join().unwrap(); } -// Check if channels are working. - -/// The test taken from the Rust documentation. -fn simple_send() { - let (tx, rx) = channel(); - thread::spawn(move || { - tx.send(10).unwrap(); - }); - assert_eq!(rx.recv().unwrap(), 10); -} - -/// The test taken from the Rust documentation. -fn multiple_send() { - let (tx, rx) = channel(); - for i in 0..10 { - let tx = tx.clone(); - thread::spawn(move || { - tx.send(i).unwrap(); - }); - } - - let mut sum = 0; - for _ in 0..10 { - let j = rx.recv().unwrap(); - assert!(0 <= j && j < 10); - sum += j; - } - assert_eq!(sum, 45); -} - -/// The test taken from the Rust documentation. -fn send_on_sync() { - let (sender, receiver) = sync_channel(1); - - // this returns immediately - sender.send(1).unwrap(); - - thread::spawn(move || { - // this will block until the previous message has been received - sender.send(2).unwrap(); - }); - - assert_eq!(receiver.recv().unwrap(), 1); - assert_eq!(receiver.recv().unwrap(), 2); -} - // Check if Rust once statics are working. static mut VAL: usize = 0; @@ -353,9 +306,6 @@ fn main() { check_mutex(); check_rwlock_write(); check_rwlock_read_no_deadlock(); - simple_send(); - multiple_send(); - send_on_sync(); check_once(); check_rwlock_unlock_bug1(); check_rwlock_unlock_bug2(); diff --git a/tests/run-pass/concurrency/thread_locals.rs b/tests/run-pass/concurrency/thread_locals.rs index 384c2ac9155b2..0fd4a9f1372dc 100644 --- a/tests/run-pass/concurrency/thread_locals.rs +++ b/tests/run-pass/concurrency/thread_locals.rs @@ -1,4 +1,5 @@ // ignore-windows: Concurrency on Windows is not supported yet. +// compile-flags: -Zmiri-check-number-validity //! The main purpose of this test is to check that if we take a pointer to //! thread's `t1` thread-local `A` and send it to another thread `t2`, From 0beb318b04d6733d4811390b2c96be06231b7bb8 Mon Sep 17 00:00:00 2001 From: Takayuki Maeda Date: Sun, 27 Mar 2022 18:41:40 +0900 Subject: [PATCH 2958/3747] add .vscode to .gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 389565791c00f..b84a1cfe9f533 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ target tex/*/out *.dot *.rs.bk +.vscode From f3c35d51050a1d89da252734ff5fc8b9ba0b9937 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 27 Mar 2022 09:40:46 -0400 Subject: [PATCH 2959/3747] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 7c9e50da5cebd..2497974aa7ea1 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -d2df372bca13bb60979c909660e69f2451630e81 +100f12d17026fccfc5d80527b5976dd66b228b13 From 811e6dd71dbbf5c4aee5b4ea1cc7c51f266e717a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 31 Mar 2022 11:18:56 -0400 Subject: [PATCH 2960/3747] test int_log functions --- rust-version | 2 +- tests/run-pass/integer-ops.rs | 29 +++++++++++++++++++++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 2497974aa7ea1..bed83f84eedfc 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -100f12d17026fccfc5d80527b5976dd66b228b13 +df20355fa9fa5e9fb89be4e4bfee8a643bb7a23e diff --git a/tests/run-pass/integer-ops.rs b/tests/run-pass/integer-ops.rs index f5c1a7a5ff212..764b2dca82caa 100644 --- a/tests/run-pass/integer-ops.rs +++ b/tests/run-pass/integer-ops.rs @@ -1,4 +1,5 @@ // compile-flags: -Coverflow-checks=off +#![feature(int_log)] #![allow(arithmetic_overflow)] pub fn main() { @@ -171,4 +172,32 @@ pub fn main() { assert_eq!(10i8.overflowing_abs(), (10,false)); assert_eq!((-10i8).overflowing_abs(), (10,false)); assert_eq!((-128i8).overflowing_abs(), (-128,true)); + + // Logarithms + macro_rules! test_log { + ($type:ident, $max_log2:expr, $max_log10:expr) => { + assert_eq!($type::MIN.checked_log2(), None); + assert_eq!($type::MIN.checked_log10(), None); + assert_eq!($type::MAX.checked_log2(), Some($max_log2)); + assert_eq!($type::MAX.checked_log10(), Some($max_log10)); + } + } + + test_log!(i8, 6, 2); + test_log!(u8, 7, 2); + test_log!(i16, 14, 4); + test_log!(u16, 15, 4); + test_log!(i32, 30, 9); + test_log!(u32, 31, 9); + test_log!(i64, 62, 18); + test_log!(u64, 63, 19); + test_log!(i128, 126, 38); + test_log!(u128, 127, 38); + + for i in (1..=i16::MAX).step_by(i8::MAX as usize) { + assert_eq!(i.checked_log(13), Some((i as f32).log(13.0) as u32)); + } + for i in (1..=u16::MAX).step_by(i8::MAX as usize) { + assert_eq!(i.checked_log(13), Some((i as f32).log(13.0) as u32)); + } } From 9af03bf342708f591f5596916b08d5d5d784245e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 1 Apr 2022 14:10:24 -0400 Subject: [PATCH 2961/3747] add -Zmiri-strict-provenance --- README.md | 4 ++++ src/bin/miri.rs | 4 ++++ src/eval.rs | 7 ++++++- src/intptrcast.rs | 20 +++++++++++++------ src/machine.rs | 2 +- tests/compile-fail/box-cell-alias.rs | 2 +- .../compile-fail/stacked_borrows/zst_slice.rs | 2 +- .../compile-fail/strict-provenance-offset.rs | 9 +++++++++ tests/run-pass/btreemap.rs | 2 +- tests/run-pass/concurrency/channels.rs | 1 - tests/run-pass/concurrency/sync.rs | 2 +- tests/run-pass/concurrency/thread_locals.rs | 2 +- .../concurrency/tls_lib_drop_single_thread.rs | 1 - tests/run-pass/rc.rs | 2 +- tests/run-pass/slices.rs | 2 +- tests/run-pass/strings.rs | 2 +- tests/run-pass/vec.rs | 2 +- tests/run-pass/vecdeque.rs | 2 +- 18 files changed, 48 insertions(+), 20 deletions(-) create mode 100644 tests/compile-fail/strict-provenance-offset.rs diff --git a/README.md b/README.md index 5d8b9034f3ad5..2203a0643a905 100644 --- a/README.md +++ b/README.md @@ -294,6 +294,10 @@ environment variable: entropy. The default seed is 0. **NOTE**: This entropy is not good enough for cryptographic use! Do not generate secret keys in Miri or perform other kinds of cryptographic operations that rely on proper random numbers. +* `-Zmiri-strict-provenance` enables [strict + provenance](https://github.com/rust-lang/rust/issues/95228) checking in Miri. This means that + casting an integer to a pointer yields a result with 'invalid' provenance, i.e., with provenance + that cannot be used for any memory access. Also implies `-Zmiri-tag-raw-pointers`. * `-Zmiri-symbolic-alignment-check` makes the alignment check more strict. By default, alignment is checked by casting the pointer to an integer, and making sure that is a multiple of the alignment. This can lead to cases where a diff --git a/src/bin/miri.rs b/src/bin/miri.rs index a1f7c617f0af1..5a9c96ef99b48 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -363,6 +363,10 @@ fn main() { "-Zmiri-tag-raw-pointers" => { miri_config.tag_raw = true; } + "-Zmiri-strict-provenance" => { + miri_config.strict_provenance = true; + miri_config.tag_raw = true; + } "-Zmiri-track-raw-pointers" => { eprintln!( "WARNING: -Zmiri-track-raw-pointers has been renamed to -Zmiri-tag-raw-pointers, the old name is deprecated." diff --git a/src/eval.rs b/src/eval.rs index 97856d92020b2..788e30c9e78ec 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -108,9 +108,13 @@ pub struct MiriConfig { /// If `Some`, enable the `measureme` profiler, writing results to a file /// with the specified prefix. pub measureme_out: Option, - /// Panic when unsupported functionality is encountered + /// Panic when unsupported functionality is encountered. pub panic_on_unsupported: bool, + /// Which style to use for printing backtraces. pub backtrace_style: BacktraceStyle, + /// Whether to enforce "strict provenance" rules. Enabling this means int2ptr casts return + /// pointers with an invalid provenance, i.e., not valid for any memory access. + pub strict_provenance: bool, } impl Default for MiriConfig { @@ -136,6 +140,7 @@ impl Default for MiriConfig { measureme_out: None, panic_on_unsupported: false, backtrace_style: BacktraceStyle::Short, + strict_provenance: false, } } } diff --git a/src/intptrcast.rs b/src/intptrcast.rs index 6f4169e950a94..9333536c9c5fc 100644 --- a/src/intptrcast.rs +++ b/src/intptrcast.rs @@ -15,23 +15,27 @@ pub type MemoryExtra = RefCell; pub struct GlobalState { /// This is used as a map between the address of each allocation and its `AllocId`. /// It is always sorted - pub int_to_ptr_map: Vec<(u64, AllocId)>, + int_to_ptr_map: Vec<(u64, AllocId)>, /// The base address for each allocation. We cannot put that into /// `AllocExtra` because function pointers also have a base address, and /// they do not have an `AllocExtra`. /// This is the inverse of `int_to_ptr_map`. - pub base_addr: FxHashMap, + base_addr: FxHashMap, /// This is used as a memory address when a new pointer is casted to an integer. It /// is always larger than any address that was previously made part of a block. - pub next_base_addr: u64, + next_base_addr: u64, + /// Whether to enforce "strict provenance" rules. Enabling this means int2ptr casts return + /// pointers with an invalid provenance, i.e., not valid for any memory access. + strict_provenance: bool, } -impl Default for GlobalState { - fn default() -> Self { +impl GlobalState { + pub fn new(config: &MiriConfig) -> Self { GlobalState { int_to_ptr_map: Vec::default(), base_addr: FxHashMap::default(), next_base_addr: STACK_ADDR, + strict_provenance: config.strict_provenance, } } } @@ -43,8 +47,12 @@ impl<'mir, 'tcx> GlobalState { ) -> Pointer> { trace!("Casting 0x{:x} to a pointer", addr); let global_state = memory.extra.intptrcast.borrow(); - let pos = global_state.int_to_ptr_map.binary_search_by_key(&addr, |(addr, _)| *addr); + if global_state.strict_provenance { + return Pointer::new(None, Size::from_bytes(addr)); + } + + let pos = global_state.int_to_ptr_map.binary_search_by_key(&addr, |(addr, _)| *addr); let alloc_id = match pos { Ok(pos) => Some(global_state.int_to_ptr_map[pos].1), Err(0) => None, diff --git a/src/machine.rs b/src/machine.rs index 9c763149ffa21..e9ed50724426f 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -205,7 +205,7 @@ impl MemoryExtra { MemoryExtra { stacked_borrows, data_race, - intptrcast: Default::default(), + intptrcast: RefCell::new(intptrcast::GlobalState::new(config)), extern_statics: FxHashMap::default(), rng: RefCell::new(rng), tracked_alloc_id: config.tracked_alloc_id, diff --git a/tests/compile-fail/box-cell-alias.rs b/tests/compile-fail/box-cell-alias.rs index 5b9614f79fde9..49cce2750784a 100644 --- a/tests/compile-fail/box-cell-alias.rs +++ b/tests/compile-fail/box-cell-alias.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-tag-raw-pointers +// compile-flags: -Zmiri-strict-provenance // Taken from . diff --git a/tests/compile-fail/stacked_borrows/zst_slice.rs b/tests/compile-fail/stacked_borrows/zst_slice.rs index 065bf77d04ae2..d45b3dcac087b 100644 --- a/tests/compile-fail/stacked_borrows/zst_slice.rs +++ b/tests/compile-fail/stacked_borrows/zst_slice.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-tag-raw-pointers +// compile-flags: -Zmiri-strict-provenance // error-pattern: does not exist in the borrow stack fn main() { diff --git a/tests/compile-fail/strict-provenance-offset.rs b/tests/compile-fail/strict-provenance-offset.rs new file mode 100644 index 0000000000000..6955d0243a9af --- /dev/null +++ b/tests/compile-fail/strict-provenance-offset.rs @@ -0,0 +1,9 @@ +// compile-flags: -Zmiri-strict-provenance +// error-pattern: not a valid pointer + +fn main() { + let x = 22; + let ptr = &x as *const _ as *const u8; + let roundtrip = ptr as usize as *const u8; + let _ = unsafe { roundtrip.offset(1) }; +} diff --git a/tests/run-pass/btreemap.rs b/tests/run-pass/btreemap.rs index 842ba0f4a8741..4e11aa5917e31 100644 --- a/tests/run-pass/btreemap.rs +++ b/tests/run-pass/btreemap.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-tag-raw-pointers +// compile-flags: -Zmiri-strict-provenance -Zmiri-check-number-validity #![feature(btree_drain_filter)] use std::collections::{BTreeMap, BTreeSet}; use std::mem; diff --git a/tests/run-pass/concurrency/channels.rs b/tests/run-pass/concurrency/channels.rs index 58d073c85acc5..7d28cd726d0e2 100644 --- a/tests/run-pass/concurrency/channels.rs +++ b/tests/run-pass/concurrency/channels.rs @@ -1,5 +1,4 @@ // ignore-windows: Concurrency on Windows is not supported yet. -// compile-flags: -Zmiri-disable-isolation use std::sync::mpsc::{channel, sync_channel}; use std::thread; diff --git a/tests/run-pass/concurrency/sync.rs b/tests/run-pass/concurrency/sync.rs index d47aa2a8d234a..95ede8e6c02d9 100644 --- a/tests/run-pass/concurrency/sync.rs +++ b/tests/run-pass/concurrency/sync.rs @@ -1,5 +1,5 @@ // ignore-windows: Concurrency on Windows is not supported yet. -// compile-flags: -Zmiri-disable-isolation -Zmiri-check-number-validity +// compile-flags: -Zmiri-disable-isolation -Zmiri-strict-provenance -Zmiri-check-number-validity use std::sync::{Arc, Barrier, Condvar, Mutex, Once, RwLock}; use std::thread; diff --git a/tests/run-pass/concurrency/thread_locals.rs b/tests/run-pass/concurrency/thread_locals.rs index 0fd4a9f1372dc..8b4f2a6f79d36 100644 --- a/tests/run-pass/concurrency/thread_locals.rs +++ b/tests/run-pass/concurrency/thread_locals.rs @@ -1,5 +1,5 @@ // ignore-windows: Concurrency on Windows is not supported yet. -// compile-flags: -Zmiri-check-number-validity +// compile-flags: -Zmiri-strict-provenance -Zmiri-check-number-validity //! The main purpose of this test is to check that if we take a pointer to //! thread's `t1` thread-local `A` and send it to another thread `t2`, diff --git a/tests/run-pass/concurrency/tls_lib_drop_single_thread.rs b/tests/run-pass/concurrency/tls_lib_drop_single_thread.rs index c8be1273bd14f..ef8b2c02ed928 100644 --- a/tests/run-pass/concurrency/tls_lib_drop_single_thread.rs +++ b/tests/run-pass/concurrency/tls_lib_drop_single_thread.rs @@ -1,4 +1,3 @@ -// compile-flags: -Zmiri-tag-raw-pointers //! Check that destructors of the thread locals are executed on all OSes. use std::cell::RefCell; diff --git a/tests/run-pass/rc.rs b/tests/run-pass/rc.rs index e00d9df32eec7..fcc5156de89a7 100644 --- a/tests/run-pass/rc.rs +++ b/tests/run-pass/rc.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-tag-raw-pointers +// compile-flags: -Zmiri-strict-provenance -Zmiri-check-number-validity #![feature(new_uninit)] #![feature(get_mut_unchecked)] diff --git a/tests/run-pass/slices.rs b/tests/run-pass/slices.rs index 9d98c44741b44..1b3bef5e07b5e 100644 --- a/tests/run-pass/slices.rs +++ b/tests/run-pass/slices.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-tag-raw-pointers +// compile-flags: -Zmiri-strict-provenance -Zmiri-check-number-validity #![feature(new_uninit)] #![feature(slice_as_chunks)] #![feature(slice_partition_dedup)] diff --git a/tests/run-pass/strings.rs b/tests/run-pass/strings.rs index 6998ec6e59b9b..5c36168a6ea3e 100644 --- a/tests/run-pass/strings.rs +++ b/tests/run-pass/strings.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-tag-raw-pointers +// compile-flags: -Zmiri-strict-provenance -Zmiri-check-number-validity fn empty() -> &'static str { "" diff --git a/tests/run-pass/vec.rs b/tests/run-pass/vec.rs index 102396f4b91f7..0d4c8016cdb61 100644 --- a/tests/run-pass/vec.rs +++ b/tests/run-pass/vec.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-tag-raw-pointers -Zmiri-check-number-validity +// compile-flags: -Zmiri-strict-provenance -Zmiri-check-number-validity // Gather all references from a mutable iterator and make sure Miri notices if // using them is dangerous. fn test_all_refs<'a, T: 'a>(dummy: &mut T, iter: impl Iterator) { diff --git a/tests/run-pass/vecdeque.rs b/tests/run-pass/vecdeque.rs index f45c21d20781d..8e8b395cbd9ae 100644 --- a/tests/run-pass/vecdeque.rs +++ b/tests/run-pass/vecdeque.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-tag-raw-pointers +// compile-flags: -Zmiri-strict-provenance -Zmiri-check-number-validity use std::collections::VecDeque; fn test_all_refs<'a, T: 'a>(dummy: &mut T, iter: impl Iterator) { From aa04dc1eeb53e90ee8473648610945a08232e56f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 27 Mar 2022 20:01:04 -0400 Subject: [PATCH 2962/3747] Rust values can be up to isize::MAX in size --- src/shims/intrinsics.rs | 2 ++ tests/compile-fail/too-big-unsized.rs | 7 +------ tests/run-pass/slices.rs | 9 +++++++++ 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index c344d0ff9c34d..7e2068e4657bb 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -83,6 +83,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let val_byte = this.read_scalar(val_byte)?.to_u8()?; let ptr = this.read_pointer(ptr)?; let count = this.read_scalar(count)?.to_machine_usize(this)?; + // `checked_mul` enforces a too small bound (the correct one would probably be machine_isize_max), + // but no actual allocation can be big enough for the difference to be noticeable. let byte_count = ty_layout.size.checked_mul(count, this).ok_or_else(|| { err_ub_format!("overflow computing total size of `{}`", intrinsic_name) })?; diff --git a/tests/compile-fail/too-big-unsized.rs b/tests/compile-fail/too-big-unsized.rs index ad7bc6e938acb..824190a66eebf 100644 --- a/tests/compile-fail/too-big-unsized.rs +++ b/tests/compile-fail/too-big-unsized.rs @@ -6,13 +6,8 @@ struct MySlice { tail: [u8], } -#[cfg(target_pointer_width = "64")] -const TOO_BIG: usize = 1usize << 47; -#[cfg(target_pointer_width = "32")] -const TOO_BIG: usize = 1usize << 31; - fn main() { unsafe { let ptr = Box::into_raw(Box::new(0u8)); // The slice part is actually not "too big", but together with the `prefix` field it is. - let _x: &MySlice = mem::transmute((ptr, TOO_BIG-1)); //~ ERROR: invalid reference metadata: total size is bigger than largest supported object + let _x: &MySlice = mem::transmute((ptr, isize::MAX as usize)); //~ ERROR: invalid reference metadata: total size is bigger than largest supported object } } diff --git a/tests/run-pass/slices.rs b/tests/run-pass/slices.rs index 9d98c44741b44..bf3585f74e952 100644 --- a/tests/run-pass/slices.rs +++ b/tests/run-pass/slices.rs @@ -2,6 +2,7 @@ #![feature(new_uninit)] #![feature(slice_as_chunks)] #![feature(slice_partition_dedup)] +#![feature(layout_for_ptr)] use std::slice; @@ -250,9 +251,17 @@ fn test_for_invalidated_pointers() { buffer.copy_within(1.., 0); } +fn large_raw_slice() { + let size = isize::MAX as usize; + // Creating a raw slice of size isize::MAX and asking for its size is okay. + let s = std::ptr::slice_from_raw_parts(1usize as *const u8, size); + assert_eq!(size, unsafe { std::mem::size_of_val_raw(s) }); +} + fn main() { slice_of_zst(); test_iter_ref_consistency(); uninit_slice(); test_for_invalidated_pointers(); + large_raw_slice(); } From e13668092ce69bcedf00f02668a43ecf88e76b22 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 1 Apr 2022 17:22:11 -0400 Subject: [PATCH 2963/3747] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index bed83f84eedfc..38c99cc0b5397 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -df20355fa9fa5e9fb89be4e4bfee8a643bb7a23e +297a8018b525c28ef10ee6a91d61954839b508b9 From 1d79b60a1eed7fd1b176de1cbe2fa44ee158cc0d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 1 Apr 2022 23:59:16 -0400 Subject: [PATCH 2964/3747] make strict-provenance imply check-number-validity --- README.md | 3 ++- src/bin/miri.rs | 1 + tests/run-pass/btreemap.rs | 2 +- tests/run-pass/concurrency/sync.rs | 2 +- tests/run-pass/concurrency/thread_locals.rs | 2 +- tests/run-pass/rc.rs | 2 +- tests/run-pass/slices.rs | 2 +- tests/run-pass/strings.rs | 2 +- tests/run-pass/vec.rs | 2 +- tests/run-pass/vecdeque.rs | 2 +- 10 files changed, 11 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 2203a0643a905..d394eb3cfbe95 100644 --- a/README.md +++ b/README.md @@ -297,7 +297,8 @@ environment variable: * `-Zmiri-strict-provenance` enables [strict provenance](https://github.com/rust-lang/rust/issues/95228) checking in Miri. This means that casting an integer to a pointer yields a result with 'invalid' provenance, i.e., with provenance - that cannot be used for any memory access. Also implies `-Zmiri-tag-raw-pointers`. + that cannot be used for any memory access. Also implies `-Zmiri-tag-raw-pointers` and + `-Zmiri-check-number-validity`. * `-Zmiri-symbolic-alignment-check` makes the alignment check more strict. By default, alignment is checked by casting the pointer to an integer, and making sure that is a multiple of the alignment. This can lead to cases where a diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 5a9c96ef99b48..be4776f459cd4 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -366,6 +366,7 @@ fn main() { "-Zmiri-strict-provenance" => { miri_config.strict_provenance = true; miri_config.tag_raw = true; + miri_config.check_number_validity = true; } "-Zmiri-track-raw-pointers" => { eprintln!( diff --git a/tests/run-pass/btreemap.rs b/tests/run-pass/btreemap.rs index 4e11aa5917e31..413d7ef53d1cd 100644 --- a/tests/run-pass/btreemap.rs +++ b/tests/run-pass/btreemap.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-strict-provenance -Zmiri-check-number-validity +// compile-flags: -Zmiri-strict-provenance #![feature(btree_drain_filter)] use std::collections::{BTreeMap, BTreeSet}; use std::mem; diff --git a/tests/run-pass/concurrency/sync.rs b/tests/run-pass/concurrency/sync.rs index 95ede8e6c02d9..5e43fea968641 100644 --- a/tests/run-pass/concurrency/sync.rs +++ b/tests/run-pass/concurrency/sync.rs @@ -1,5 +1,5 @@ // ignore-windows: Concurrency on Windows is not supported yet. -// compile-flags: -Zmiri-disable-isolation -Zmiri-strict-provenance -Zmiri-check-number-validity +// compile-flags: -Zmiri-disable-isolation -Zmiri-strict-provenance use std::sync::{Arc, Barrier, Condvar, Mutex, Once, RwLock}; use std::thread; diff --git a/tests/run-pass/concurrency/thread_locals.rs b/tests/run-pass/concurrency/thread_locals.rs index 8b4f2a6f79d36..7938284bd6343 100644 --- a/tests/run-pass/concurrency/thread_locals.rs +++ b/tests/run-pass/concurrency/thread_locals.rs @@ -1,5 +1,5 @@ // ignore-windows: Concurrency on Windows is not supported yet. -// compile-flags: -Zmiri-strict-provenance -Zmiri-check-number-validity +// compile-flags: -Zmiri-strict-provenance //! The main purpose of this test is to check that if we take a pointer to //! thread's `t1` thread-local `A` and send it to another thread `t2`, diff --git a/tests/run-pass/rc.rs b/tests/run-pass/rc.rs index fcc5156de89a7..6d51825fc0df2 100644 --- a/tests/run-pass/rc.rs +++ b/tests/run-pass/rc.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-strict-provenance -Zmiri-check-number-validity +// compile-flags: -Zmiri-strict-provenance #![feature(new_uninit)] #![feature(get_mut_unchecked)] diff --git a/tests/run-pass/slices.rs b/tests/run-pass/slices.rs index f9d0b4eb8eaed..b6537b4f1b4de 100644 --- a/tests/run-pass/slices.rs +++ b/tests/run-pass/slices.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-strict-provenance -Zmiri-check-number-validity +// compile-flags: -Zmiri-strict-provenance #![feature(new_uninit)] #![feature(slice_as_chunks)] #![feature(slice_partition_dedup)] diff --git a/tests/run-pass/strings.rs b/tests/run-pass/strings.rs index 5c36168a6ea3e..77ecaed4fe9b8 100644 --- a/tests/run-pass/strings.rs +++ b/tests/run-pass/strings.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-strict-provenance -Zmiri-check-number-validity +// compile-flags: -Zmiri-strict-provenance fn empty() -> &'static str { "" diff --git a/tests/run-pass/vec.rs b/tests/run-pass/vec.rs index 0d4c8016cdb61..788f05ce97741 100644 --- a/tests/run-pass/vec.rs +++ b/tests/run-pass/vec.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-strict-provenance -Zmiri-check-number-validity +// compile-flags: -Zmiri-strict-provenance // Gather all references from a mutable iterator and make sure Miri notices if // using them is dangerous. fn test_all_refs<'a, T: 'a>(dummy: &mut T, iter: impl Iterator) { diff --git a/tests/run-pass/vecdeque.rs b/tests/run-pass/vecdeque.rs index 8e8b395cbd9ae..0cba0165cae16 100644 --- a/tests/run-pass/vecdeque.rs +++ b/tests/run-pass/vecdeque.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-strict-provenance -Zmiri-check-number-validity +// compile-flags: -Zmiri-strict-provenance use std::collections::VecDeque; fn test_all_refs<'a, T: 'a>(dummy: &mut T, iter: impl Iterator) { From 3dcba56349ebc41b20948e982dc61a9ed9305f59 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 2 Apr 2022 00:05:27 -0400 Subject: [PATCH 2965/3747] add test for nasty example --- .../strict_provenance_transmute.rs | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 tests/compile-fail/strict_provenance_transmute.rs diff --git a/tests/compile-fail/strict_provenance_transmute.rs b/tests/compile-fail/strict_provenance_transmute.rs new file mode 100644 index 0000000000000..0fc64295f94ce --- /dev/null +++ b/tests/compile-fail/strict_provenance_transmute.rs @@ -0,0 +1,27 @@ +// compile-flags: -Zmiri-strict-provenance +#![feature(strict_provenance)] + +use std::mem; + +// This is the example from +// . + +unsafe fn deref(left: *const u8, right: *const u8) { + let left_int: usize = mem::transmute(left); //~ERROR expected initialized plain (non-pointer) bytes + let right_int: usize = mem::transmute(right); + if left_int == right_int { + // The compiler is allowed to replace `left_int` by `right_int` here... + let left_ptr: *const u8 = mem::transmute(left_int); + // ...which however means here it could be dereferencing the wrong pointer. + let _val = *left_ptr; + } +} + +fn main() { + let ptr1 = &0u8 as *const u8; + let ptr2 = &1u8 as *const u8; + unsafe { + // Two pointers with the same address but different provenance. + deref(ptr1, ptr2.with_addr(ptr1.addr())); + } +} From 830cc58f8a10598f4caa337ca97be51741945499 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 3 Apr 2022 20:00:03 -0400 Subject: [PATCH 2966/3747] rustup --- rust-version | 2 +- src/helpers.rs | 4 ++-- src/machine.rs | 2 +- src/shims/env.rs | 2 +- src/shims/foreign_items.rs | 4 ++-- src/shims/posix/foreign_items.rs | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/rust-version b/rust-version index 38c99cc0b5397..8e4cdeddfccb5 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -297a8018b525c28ef10ee6a91d61954839b508b9 +6af09d2505f38e4f1df291df56d497fb2ad935ed diff --git a/src/helpers.rs b/src/helpers.rs index 3ffb983aa69ec..7a63bb03dfe7f 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -510,7 +510,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); let target = &this.tcx.sess.target; let target_os = &target.os; - let last_error = if target.families.contains(&"unix".to_owned()) { + let last_error = if target.families.iter().any(|f| f == "unix") { this.eval_libc(match err_kind { ConnectionRefused => "ECONNREFUSED", ConnectionReset => "ECONNRESET", @@ -534,7 +534,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) } })? - } else if target.families.contains(&"windows".to_owned()) { + } else if target.families.iter().any(|f| f == "windows") { // FIXME: we have to finish implementing the Windows equivalent of this. this.eval_windows( "c", diff --git a/src/machine.rs b/src/machine.rs index e9ed50724426f..b4b07a61a8b49 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -227,7 +227,7 @@ impl MemoryExtra { pub fn init_extern_statics<'tcx, 'mir>( this: &mut MiriEvalContext<'mir, 'tcx>, ) -> InterpResult<'tcx> { - match this.tcx.sess.target.os.as_str() { + match this.tcx.sess.target.os.as_ref() { "linux" => { // "environ" Self::add_extern_static( diff --git a/src/shims/env.rs b/src/shims/env.rs index c2050647abca2..822bef56ce682 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -41,7 +41,7 @@ impl<'tcx> EnvVars<'tcx> { mut excluded_env_vars: Vec, forwarded_env_vars: Vec, ) -> InterpResult<'tcx> { - let target_os = ecx.tcx.sess.target.os.as_str(); + let target_os = ecx.tcx.sess.target.os.as_ref(); // HACK: Exclude `TERM` var to avoid terminfo trying to open the termcap file. // This is (a) very slow and (b) does not work on Windows. excluded_env_vars.push("TERM".to_owned()); diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index ecffd310de569..d9e4d9382246c 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -46,7 +46,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn min_align(&self, size: u64, kind: MiriMemoryKind) -> Align { let this = self.eval_context_ref(); // List taken from `libstd/sys_common/alloc.rs`. - let min_align = match this.tcx.sess.target.arch.as_str() { + let min_align = match this.tcx.sess.target.arch.as_ref() { "x86" | "arm" | "mips" | "powerpc" | "powerpc64" | "asmjs" | "wasm32" => 8, "x86_64" | "aarch64" | "mips64" | "s390x" | "sparc64" => 16, arch => bug!("Unsupported target architecture: {}", arch), @@ -695,7 +695,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // Platform-specific shims - _ => match this.tcx.sess.target.os.as_str() { + _ => match this.tcx.sess.target.os.as_ref() { "linux" | "macos" => return shims::posix::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, abi, args, dest, ret), "windows" => return shims::windows::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, abi, args, dest, ret), target => throw_unsup_format!("the target `{}` is not supported", target), diff --git a/src/shims/posix/foreign_items.rs b/src/shims/posix/foreign_items.rs index 02fb7089c34db..36bf530599299 100644 --- a/src/shims/posix/foreign_items.rs +++ b/src/shims/posix/foreign_items.rs @@ -462,7 +462,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Platform-specific shims _ => { - match this.tcx.sess.target.os.as_str() { + match this.tcx.sess.target.os.as_ref() { "linux" => return shims::posix::linux::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, abi, args, dest, ret), "macos" => return shims::posix::macos::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, abi, args, dest, ret), _ => unreachable!(), From 79a1001b3946a0816a4199ad033657da6411a4f4 Mon Sep 17 00:00:00 2001 From: Alex Touchet Date: Mon, 4 Apr 2022 15:52:09 -0700 Subject: [PATCH 2967/3747] Use SPDX license format --- Cargo.toml | 2 +- cargo-miri/Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 356f6822fa182..540eeabebb7a3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Miri Team"] description = "An experimental interpreter for Rust MIR (core driver)." -license = "MIT/Apache-2.0" +license = "MIT OR Apache-2.0" name = "miri" repository = "https://github.com/rust-lang/miri" version = "0.1.0" diff --git a/cargo-miri/Cargo.toml b/cargo-miri/Cargo.toml index 15c46569232a8..7789a8a89594a 100644 --- a/cargo-miri/Cargo.toml +++ b/cargo-miri/Cargo.toml @@ -1,7 +1,7 @@ [package] authors = ["Miri Team"] description = "An experimental interpreter for Rust MIR (cargo wrapper)." -license = "MIT/Apache-2.0" +license = "MIT OR Apache-2.0" name = "cargo-miri" repository = "https://github.com/rust-lang/miri" version = "0.1.0" From 6e1f3cd8ff080b85f6ba71b3f90300aca194a434 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 3 Apr 2022 16:12:52 -0400 Subject: [PATCH 2968/3747] adjust for MemoryExtra being merged into Machine --- src/data_race.rs | 26 ++- src/diagnostics.rs | 4 +- src/eval.rs | 16 +- src/helpers.rs | 14 +- src/intptrcast.rs | 56 +++-- src/lib.rs | 4 +- src/machine.rs | 284 ++++++++++++------------- src/shims/backtrace.rs | 10 +- src/shims/env.rs | 28 +-- src/shims/foreign_items.rs | 34 ++- src/shims/intrinsics.rs | 16 +- src/shims/mod.rs | 4 +- src/shims/os_str.rs | 6 +- src/shims/panic.rs | 6 +- src/shims/posix/foreign_items.rs | 6 +- src/shims/posix/fs.rs | 30 +-- src/shims/posix/linux/sync.rs | 2 +- src/shims/posix/macos/foreign_items.rs | 2 +- src/shims/posix/thread.rs | 4 +- src/shims/tls.rs | 2 +- src/shims/windows/foreign_items.rs | 6 +- src/stacked_borrows.rs | 46 ++-- src/sync.rs | 16 +- src/thread.rs | 16 +- 24 files changed, 310 insertions(+), 328 deletions(-) diff --git a/src/data_race.rs b/src/data_race.rs index 1e91c66b859ed..4a79d9e990479 100644 --- a/src/data_race.rs +++ b/src/data_race.rs @@ -79,7 +79,6 @@ use crate::{ }; pub type AllocExtra = VClockAlloc; -pub type MemoryExtra = GlobalState; /// Valid atomic read-write operations, alias of atomic::Ordering (not non-exhaustive). #[derive(Copy, Clone, PartialEq, Eq, Debug)] @@ -596,9 +595,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { let eq = this.binary_op(mir::BinOp::Eq, &old, expect_old)?; // If the operation would succeed, but is "weak", fail some portion // of the time, based on `rate`. - let rate = this.memory.extra.cmpxchg_weak_failure_rate; + let rate = this.machine.cmpxchg_weak_failure_rate; let cmpxchg_success = eq.to_scalar()?.to_bool()? - && (!can_fail_spuriously || this.memory.extra.rng.get_mut().gen::() < rate); + && (!can_fail_spuriously || this.machine.rng.get_mut().gen::() < rate); let res = Immediate::ScalarPair( old.to_scalar_or_uninit(), Scalar::from_bool(cmpxchg_success).into(), @@ -690,7 +689,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { /// Update the data-race detector for an atomic fence on the current thread. fn validate_atomic_fence(&mut self, atomic: AtomicFenceOp) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - if let Some(data_race) = &mut this.memory.extra.data_race { + if let Some(data_race) = &mut this.machine.data_race { data_race.maybe_perform_sync_operation(move |index, mut clocks| { log::trace!("Atomic fence on {:?} with ordering {:?}", index, atomic); @@ -725,7 +724,7 @@ pub struct VClockAlloc { impl VClockAlloc { /// Create a new data-race detector for newly allocated memory. pub fn new_allocation( - global: &MemoryExtra, + global: &GlobalState, len: Size, kind: MemoryKind, ) -> VClockAlloc { @@ -796,7 +795,7 @@ impl VClockAlloc { #[cold] #[inline(never)] fn report_data_race<'tcx>( - global: &MemoryExtra, + global: &GlobalState, range: &MemoryCellClocks, action: &str, is_atomic: bool, @@ -950,13 +949,13 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { #[inline] fn allow_data_races_ref(&self, op: impl FnOnce(&MiriEvalContext<'mir, 'tcx>) -> R) -> R { let this = self.eval_context_ref(); - let old = if let Some(data_race) = &this.memory.extra.data_race { + let old = if let Some(data_race) = &this.machine.data_race { data_race.multi_threaded.replace(false) } else { false }; let result = op(this); - if let Some(data_race) = &this.memory.extra.data_race { + if let Some(data_race) = &this.machine.data_race { data_race.multi_threaded.set(old); } result @@ -971,13 +970,13 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { op: impl FnOnce(&mut MiriEvalContext<'mir, 'tcx>) -> R, ) -> R { let this = self.eval_context_mut(); - let old = if let Some(data_race) = &this.memory.extra.data_race { + let old = if let Some(data_race) = &this.machine.data_race { data_race.multi_threaded.replace(false) } else { false }; let result = op(this); - if let Some(data_race) = &this.memory.extra.data_race { + if let Some(data_race) = &this.machine.data_race { data_race.multi_threaded.set(old); } result @@ -997,14 +996,13 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { ) -> Result<(), DataRace>, ) -> InterpResult<'tcx> { let this = self.eval_context_ref(); - if let Some(data_race) = &this.memory.extra.data_race { + if let Some(data_race) = &this.machine.data_race { if data_race.multi_threaded.get() { let size = place.layout.size; - let (alloc_id, base_offset, ptr) = this.memory.ptr_get_alloc(place.ptr)?; + let (alloc_id, base_offset, ptr) = this.ptr_get_alloc_id(place.ptr)?; // Load and log the atomic operation. // Note that atomic loads are possible even from read-only allocations, so `get_alloc_extra_mut` is not an option. - let alloc_meta = - &this.memory.get_alloc_extra(alloc_id)?.data_race.as_ref().unwrap(); + let alloc_meta = &this.get_alloc_extra(alloc_id)?.data_race.as_ref().unwrap(); log::trace!( "Atomic op({}) with ordering {:?} on {:?} (size={})", description, diff --git a/src/diagnostics.rs b/src/diagnostics.rs index 0815d73d9bcb7..e1a2e3184ebfa 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -196,7 +196,7 @@ pub fn report_error<'tcx, 'mir>( Unsupported(_) => vec![(None, format!("this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support"))], UndefinedBehavior(UndefinedBehaviorInfo::AlignmentCheckFailed { .. }) - if ecx.memory.extra.check_alignment == AlignmentCheck::Symbolic + if ecx.machine.check_alignment == AlignmentCheck::Symbolic => vec![ (None, format!("this usually indicates that your program performed an invalid operation and caused Undefined Behavior")), @@ -251,7 +251,7 @@ pub fn report_error<'tcx, 'mir>( access.uninit_offset.bytes(), access.uninit_offset.bytes() + access.uninit_size.bytes(), ); - eprintln!("{:?}", ecx.memory.dump_alloc(*alloc_id)); + eprintln!("{:?}", ecx.dump_alloc(*alloc_id)); } _ => {} } diff --git a/src/eval.rs b/src/eval.rs index 788e30c9e78ec..4c006867e1772 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -153,7 +153,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( tcx: TyCtxt<'tcx>, entry_id: DefId, entry_type: EntryFnType, - config: MiriConfig, + config: &MiriConfig, ) -> InterpResult<'tcx, (InterpCx<'mir, 'tcx, Evaluator<'mir, 'tcx>>, MPlaceTy<'tcx, Tag>)> { let param_env = ty::ParamEnv::reveal_all(); let layout_cx = LayoutCx { tcx, param_env }; @@ -161,12 +161,10 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( tcx, rustc_span::source_map::DUMMY_SP, param_env, - Evaluator::new(&config, layout_cx), - MemoryExtra::new(&config), + Evaluator::new(config, layout_cx), ); - // Complete initialization. - EnvVars::init(&mut ecx, config.excluded_env_vars, config.forwarded_env_vars)?; - MemoryExtra::init_extern_statics(&mut ecx)?; + // Some parts of initialization require a full `InterpCx`. + Evaluator::late_init(&mut ecx, config)?; // Make sure we have MIR. We check MIR for some stable monomorphic function in libcore. let sentinel = ecx.resolve_path(&["core", "ascii", "escape_default"]); @@ -260,7 +258,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( .unwrap() .unwrap(); - let main_ptr = ecx.memory.create_fn_alloc(FnVal::Instance(entry_instance)); + let main_ptr = ecx.create_fn_alloc_ptr(FnVal::Instance(entry_instance)); ecx.call_function( start_instance, @@ -296,7 +294,7 @@ pub fn eval_entry<'tcx>( // Copy setting before we move `config`. let ignore_leaks = config.ignore_leaks; - let (mut ecx, ret_place) = match create_ecx(tcx, entry_id, entry_type, config) { + let (mut ecx, ret_place) = match create_ecx(tcx, entry_id, entry_type, &config) { Ok(v) => v, Err(err) => { err.print_backtrace(); @@ -354,7 +352,7 @@ pub fn eval_entry<'tcx>( } // Check for memory leaks. info!("Additonal static roots: {:?}", ecx.machine.static_roots); - let leaks = ecx.memory.leak_report(&ecx.machine.static_roots); + let leaks = ecx.leak_report(&ecx.machine.static_roots); if leaks != 0 { tcx.sess.err("the evaluated program leaked memory"); tcx.sess.note_without_error("pass `-Zmiri-ignore-leaks` to disable this check"); diff --git a/src/helpers.rs b/src/helpers.rs index 7a63bb03dfe7f..9e4527d592b37 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -199,11 +199,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx getrandom::getrandom(&mut data) .map_err(|err| err_unsup_format!("host getrandom failed: {}", err))?; } else { - let rng = this.memory.extra.rng.get_mut(); + let rng = this.machine.rng.get_mut(); rng.fill_bytes(&mut data); } - this.memory.write_bytes(ptr, data.iter().copied()) + this.write_bytes_ptr(ptr, data.iter().copied()) } /// Call a function: Push the stack frame and pass the arguments. @@ -645,7 +645,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx loop { // FIXME: We are re-getting the allocation each time around the loop. // Would be nice if we could somehow "extend" an existing AllocRange. - let alloc = this.memory.get(ptr.offset(len, this)?.into(), size1, Align::ONE)?.unwrap(); // not a ZST, so we will get a result + let alloc = + this.get_ptr_alloc(ptr.offset(len, this)?.into(), size1, Align::ONE)?.unwrap(); // not a ZST, so we will get a result let byte = alloc.read_scalar(alloc_range(Size::ZERO, size1))?.to_u8()?; if byte == 0 { break; @@ -655,7 +656,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // Step 2: get the bytes. - this.memory.read_bytes(ptr.into(), len) + this.read_bytes_ptr(ptr.into(), len) } fn read_wide_str(&self, mut ptr: Pointer>) -> InterpResult<'tcx, Vec> { @@ -667,7 +668,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx loop { // FIXME: We are re-getting the allocation each time around the loop. // Would be nice if we could somehow "extend" an existing AllocRange. - let alloc = this.memory.get(ptr.into(), size2, align2)?.unwrap(); // not a ZST, so we will get a result + let alloc = this.get_ptr_alloc(ptr.into(), size2, align2)?.unwrap(); // not a ZST, so we will get a result let wchar = alloc.read_scalar(alloc_range(Size::ZERO, size2))?.to_u16()?; if wchar == 0 { break; @@ -750,8 +751,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// Mark a machine allocation that was just created as immutable. fn mark_immutable(&mut self, mplace: &MemPlace) { let this = self.eval_context_mut(); - this.memory - .mark_immutable(mplace.ptr.into_pointer_or_addr().unwrap().provenance.alloc_id) + this.alloc_mark_immutable(mplace.ptr.into_pointer_or_addr().unwrap().provenance.alloc_id) .unwrap(); } } diff --git a/src/intptrcast.rs b/src/intptrcast.rs index 9333536c9c5fc..b1c96c7f1e7c5 100644 --- a/src/intptrcast.rs +++ b/src/intptrcast.rs @@ -9,10 +9,10 @@ use rustc_target::abi::{HasDataLayout, Size}; use crate::*; -pub type MemoryExtra = RefCell; +pub type GlobalState = RefCell; #[derive(Clone, Debug)] -pub struct GlobalState { +pub struct GlobalStateInner { /// This is used as a map between the address of each allocation and its `AllocId`. /// It is always sorted int_to_ptr_map: Vec<(u64, AllocId)>, @@ -29,9 +29,9 @@ pub struct GlobalState { strict_provenance: bool, } -impl GlobalState { +impl GlobalStateInner { pub fn new(config: &MiriConfig) -> Self { - GlobalState { + GlobalStateInner { int_to_ptr_map: Vec::default(), base_addr: FxHashMap::default(), next_base_addr: STACK_ADDR, @@ -40,13 +40,10 @@ impl GlobalState { } } -impl<'mir, 'tcx> GlobalState { - pub fn ptr_from_addr( - addr: u64, - memory: &Memory<'mir, 'tcx, Evaluator<'mir, 'tcx>>, - ) -> Pointer> { +impl<'mir, 'tcx> GlobalStateInner { + pub fn ptr_from_addr(addr: u64, ecx: &MiriEvalContext<'mir, 'tcx>) -> Pointer> { trace!("Casting 0x{:x} to a pointer", addr); - let global_state = memory.extra.intptrcast.borrow(); + let global_state = ecx.machine.intptrcast.borrow(); if global_state.strict_provenance { return Pointer::new(None, Size::from_bytes(addr)); @@ -64,7 +61,11 @@ impl<'mir, 'tcx> GlobalState { let offset = addr - glb; // If the offset exceeds the size of the allocation, don't use this `alloc_id`. if offset - <= memory.get_size_and_align(alloc_id, AllocCheck::MaybeDead).unwrap().0.bytes() + <= ecx + .get_alloc_size_and_align(alloc_id, AllocCheck::MaybeDead) + .unwrap() + .0 + .bytes() { Some(alloc_id) } else { @@ -79,11 +80,8 @@ impl<'mir, 'tcx> GlobalState { ) } - fn alloc_base_addr( - memory: &Memory<'mir, 'tcx, Evaluator<'mir, 'tcx>>, - alloc_id: AllocId, - ) -> u64 { - let mut global_state = memory.extra.intptrcast.borrow_mut(); + fn alloc_base_addr(ecx: &MiriEvalContext<'mir, 'tcx>, alloc_id: AllocId) -> u64 { + let mut global_state = ecx.machine.intptrcast.borrow_mut(); let global_state = &mut *global_state; match global_state.base_addr.entry(alloc_id) { @@ -92,12 +90,12 @@ impl<'mir, 'tcx> GlobalState { // There is nothing wrong with a raw pointer being cast to an integer only after // it became dangling. Hence `MaybeDead`. let (size, align) = - memory.get_size_and_align(alloc_id, AllocCheck::MaybeDead).unwrap(); + ecx.get_alloc_size_and_align(alloc_id, AllocCheck::MaybeDead).unwrap(); // This allocation does not have a base address yet, pick one. // Leave some space to the previous allocation, to give it some chance to be less aligned. let slack = { - let mut rng = memory.extra.rng.borrow_mut(); + let mut rng = ecx.machine.rng.borrow_mut(); // This means that `(global_state.next_base_addr + slack) % 16` is uniformly distributed. rng.gen_range(0..16) }; @@ -129,27 +127,21 @@ impl<'mir, 'tcx> GlobalState { } /// Convert a relative (tcx) pointer to an absolute address. - pub fn rel_ptr_to_addr( - memory: &Memory<'mir, 'tcx, Evaluator<'mir, 'tcx>>, - ptr: Pointer, - ) -> u64 { + pub fn rel_ptr_to_addr(ecx: &MiriEvalContext<'mir, 'tcx>, ptr: Pointer) -> u64 { let (alloc_id, offset) = ptr.into_parts(); // offset is relative - let base_addr = GlobalState::alloc_base_addr(memory, alloc_id); + let base_addr = GlobalStateInner::alloc_base_addr(ecx, alloc_id); // Add offset with the right kind of pointer-overflowing arithmetic. - let dl = memory.data_layout(); + let dl = ecx.data_layout(); dl.overflowing_offset(base_addr, offset.bytes()).0 } - pub fn abs_ptr_to_rel( - memory: &Memory<'mir, 'tcx, Evaluator<'mir, 'tcx>>, - ptr: Pointer, - ) -> Size { + pub fn abs_ptr_to_rel(ecx: &MiriEvalContext<'mir, 'tcx>, ptr: Pointer) -> Size { let (tag, addr) = ptr.into_parts(); // addr is absolute - let base_addr = GlobalState::alloc_base_addr(memory, tag.alloc_id); + let base_addr = GlobalStateInner::alloc_base_addr(ecx, tag.alloc_id); // Wrapping "addr - base_addr" - let dl = memory.data_layout(); + let dl = ecx.data_layout(); let neg_base_addr = (base_addr as i64).wrapping_neg(); Size::from_bytes(dl.overflowing_signed_offset(addr.bytes(), neg_base_addr).0) } @@ -170,7 +162,7 @@ mod tests { #[test] fn test_align_addr() { - assert_eq!(GlobalState::align_addr(37, 4), 40); - assert_eq!(GlobalState::align_addr(44, 4), 44); + assert_eq!(GlobalStateInner::align_addr(37, 4), 40); + assert_eq!(GlobalStateInner::align_addr(44, 4), 44); } } diff --git a/src/lib.rs b/src/lib.rs index 6c9b8ee0b8f98..f14120ae4ccc1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -66,8 +66,8 @@ pub use crate::eval::{ }; pub use crate::helpers::EvalContextExt as HelpersEvalContextExt; pub use crate::machine::{ - AllocExtra, Evaluator, FrameData, MemoryExtra, MiriEvalContext, MiriEvalContextExt, - MiriMemoryKind, Tag, NUM_CPUS, PAGE_SIZE, STACK_ADDR, STACK_SIZE, + AllocExtra, Evaluator, FrameData, MiriEvalContext, MiriEvalContextExt, MiriMemoryKind, Tag, + NUM_CPUS, PAGE_SIZE, STACK_ADDR, STACK_SIZE, }; pub use crate::mono_hash_map::MonoHashMap; pub use crate::operator::EvalContextExt as OperatorEvalContextExt; diff --git a/src/machine.rs b/src/machine.rs index b4b07a61a8b49..9108f4f166631 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -163,103 +163,6 @@ pub struct AllocExtra { pub data_race: Option, } -/// Extra global memory data -#[derive(Debug)] -pub struct MemoryExtra { - pub stacked_borrows: Option, - pub data_race: Option, - pub intptrcast: intptrcast::MemoryExtra, - - /// Mapping extern static names to their base pointer. - extern_statics: FxHashMap>, - - /// The random number generator used for resolving non-determinism. - /// Needs to be queried by ptr_to_int, hence needs interior mutability. - pub(crate) rng: RefCell, - - /// An allocation ID to report when it is being allocated - /// (helps for debugging memory leaks and use after free bugs). - tracked_alloc_id: Option, - - /// Controls whether alignment of memory accesses is being checked. - pub(crate) check_alignment: AlignmentCheck, - - /// Failure rate of compare_exchange_weak, between 0.0 and 1.0 - pub(crate) cmpxchg_weak_failure_rate: f64, -} - -impl MemoryExtra { - pub fn new(config: &MiriConfig) -> Self { - let rng = StdRng::seed_from_u64(config.seed.unwrap_or(0)); - let stacked_borrows = if config.stacked_borrows { - Some(RefCell::new(stacked_borrows::GlobalState::new( - config.tracked_pointer_tag, - config.tracked_call_id, - config.tag_raw, - ))) - } else { - None - }; - let data_race = - if config.data_race_detector { Some(data_race::GlobalState::new()) } else { None }; - MemoryExtra { - stacked_borrows, - data_race, - intptrcast: RefCell::new(intptrcast::GlobalState::new(config)), - extern_statics: FxHashMap::default(), - rng: RefCell::new(rng), - tracked_alloc_id: config.tracked_alloc_id, - check_alignment: config.check_alignment, - cmpxchg_weak_failure_rate: config.cmpxchg_weak_failure_rate, - } - } - - fn add_extern_static<'tcx, 'mir>( - this: &mut MiriEvalContext<'mir, 'tcx>, - name: &str, - ptr: Pointer>, - ) { - let ptr = ptr.into_pointer_or_addr().unwrap(); - this.memory.extra.extern_statics.try_insert(Symbol::intern(name), ptr).unwrap(); - } - - /// Sets up the "extern statics" for this machine. - pub fn init_extern_statics<'tcx, 'mir>( - this: &mut MiriEvalContext<'mir, 'tcx>, - ) -> InterpResult<'tcx> { - match this.tcx.sess.target.os.as_ref() { - "linux" => { - // "environ" - Self::add_extern_static( - this, - "environ", - this.machine.env_vars.environ.unwrap().ptr, - ); - // A couple zero-initialized pointer-sized extern statics. - // Most of them are for weak symbols, which we all set to null (indicating that the - // symbol is not supported, and triggering fallback code which ends up calling a - // syscall that we do support). - for name in &["__cxa_thread_atexit_impl", "getrandom", "statx"] { - let layout = this.machine.layouts.usize; - let place = this.allocate(layout, MiriMemoryKind::ExternStatic.into())?; - this.write_scalar(Scalar::from_machine_usize(0, this), &place.into())?; - Self::add_extern_static(this, name, place.ptr); - } - } - "windows" => { - // "_tls_used" - // This is some obscure hack that is part of the Windows TLS story. It's a `u8`. - let layout = this.machine.layouts.u8; - let place = this.allocate(layout, MiriMemoryKind::ExternStatic.into())?; - this.write_scalar(Scalar::from_u8(0), &place.into())?; - Self::add_extern_static(this, "_tls_used", place.ptr); - } - _ => {} // No "extern statics" supported on this target - } - Ok(()) - } -} - /// Precomputed layouts of primitive types pub struct PrimitiveLayouts<'tcx> { pub unit: TyAndLayout<'tcx>, @@ -293,6 +196,10 @@ impl<'mir, 'tcx: 'mir> PrimitiveLayouts<'tcx> { /// The machine itself. pub struct Evaluator<'mir, 'tcx> { + pub stacked_borrows: Option, + pub data_race: Option, + pub intptrcast: intptrcast::GlobalState, + /// Environment variables set by `setenv`. /// Miri does not expose env vars from the host to the emulated program. pub(crate) env_vars: EnvVars<'tcx>, @@ -357,6 +264,23 @@ pub struct Evaluator<'mir, 'tcx> { /// Crates which are considered local for the purposes of error reporting. pub(crate) local_crates: Vec, + + /// Mapping extern static names to their base pointer. + extern_statics: FxHashMap>, + + /// The random number generator used for resolving non-determinism. + /// Needs to be queried by ptr_to_int, hence needs interior mutability. + pub(crate) rng: RefCell, + + /// An allocation ID to report when it is being allocated + /// (helps for debugging memory leaks and use after free bugs). + tracked_alloc_id: Option, + + /// Controls whether alignment of memory accesses is being checked. + pub(crate) check_alignment: AlignmentCheck, + + /// Failure rate of compare_exchange_weak, between 0.0 and 1.0 + pub(crate) cmpxchg_weak_failure_rate: f64, } impl<'mir, 'tcx> Evaluator<'mir, 'tcx> { @@ -367,9 +291,23 @@ impl<'mir, 'tcx> Evaluator<'mir, 'tcx> { let profiler = config.measureme_out.as_ref().map(|out| { measureme::Profiler::new(out).expect("Couldn't create `measureme` profiler") }); + let rng = StdRng::seed_from_u64(config.seed.unwrap_or(0)); + let stacked_borrows = if config.stacked_borrows { + Some(RefCell::new(stacked_borrows::GlobalStateInner::new( + config.tracked_pointer_tag, + config.tracked_call_id, + config.tag_raw, + ))) + } else { + None + }; + let data_race = + if config.data_race_detector { Some(data_race::GlobalState::new()) } else { None }; Evaluator { - // `env_vars` could be initialized properly here if `Memory` were available before - // calling this method. + stacked_borrows, + data_race, + intptrcast: RefCell::new(intptrcast::GlobalStateInner::new(config)), + // `env_vars` depends on a full interpreter so we cannot properly initialize it yet. env_vars: EnvVars::default(), argc: None, argv: None, @@ -391,7 +329,64 @@ impl<'mir, 'tcx> Evaluator<'mir, 'tcx> { panic_on_unsupported: config.panic_on_unsupported, backtrace_style: config.backtrace_style, local_crates, + extern_statics: FxHashMap::default(), + rng: RefCell::new(rng), + tracked_alloc_id: config.tracked_alloc_id, + check_alignment: config.check_alignment, + cmpxchg_weak_failure_rate: config.cmpxchg_weak_failure_rate, + } + } + + pub(crate) fn late_init( + this: &mut MiriEvalContext<'mir, 'tcx>, + config: &MiriConfig, + ) -> InterpResult<'tcx> { + EnvVars::init(this, config)?; + Evaluator::init_extern_statics(this)?; + Ok(()) + } + + fn add_extern_static( + this: &mut MiriEvalContext<'mir, 'tcx>, + name: &str, + ptr: Pointer>, + ) { + let ptr = ptr.into_pointer_or_addr().unwrap(); + this.machine.extern_statics.try_insert(Symbol::intern(name), ptr).unwrap(); + } + + /// Sets up the "extern statics" for this machine. + fn init_extern_statics(this: &mut MiriEvalContext<'mir, 'tcx>) -> InterpResult<'tcx> { + match this.tcx.sess.target.os.as_ref() { + "linux" => { + // "environ" + Self::add_extern_static( + this, + "environ", + this.machine.env_vars.environ.unwrap().ptr, + ); + // A couple zero-initialized pointer-sized extern statics. + // Most of them are for weak symbols, which we all set to null (indicating that the + // symbol is not supported, and triggering fallback code which ends up calling a + // syscall that we do support). + for name in &["__cxa_thread_atexit_impl", "getrandom", "statx"] { + let layout = this.machine.layouts.usize; + let place = this.allocate(layout, MiriMemoryKind::ExternStatic.into())?; + this.write_scalar(Scalar::from_machine_usize(0, this), &place.into())?; + Self::add_extern_static(this, name, place.ptr); + } + } + "windows" => { + // "_tls_used" + // This is some obscure hack that is part of the Windows TLS story. It's a `u8`. + let layout = this.machine.layouts.u8; + let place = this.allocate(layout, MiriMemoryKind::ExternStatic.into())?; + this.write_scalar(Scalar::from_u8(0), &place.into())?; + Self::add_extern_static(this, "_tls_used", place.ptr); + } + _ => {} // No "extern statics" supported on this target } + Ok(()) } pub(crate) fn communicate(&self) -> bool { @@ -429,7 +424,6 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { type MemoryKind = MiriMemoryKind; type FrameExtra = FrameData<'tcx>; - type MemoryExtra = MemoryExtra; type AllocExtra = AllocExtra; type PointerTag = Tag; type ExtraFnVal = Dlsym; @@ -442,33 +436,33 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { const PANIC_ON_ALLOC_FAIL: bool = false; #[inline(always)] - fn enforce_alignment(memory_extra: &MemoryExtra) -> bool { - memory_extra.check_alignment != AlignmentCheck::None + fn enforce_alignment(ecx: &MiriEvalContext<'mir, 'tcx>) -> bool { + ecx.machine.check_alignment != AlignmentCheck::None } #[inline(always)] - fn force_int_for_alignment_check(memory_extra: &Self::MemoryExtra) -> bool { - memory_extra.check_alignment == AlignmentCheck::Int + fn force_int_for_alignment_check(ecx: &MiriEvalContext<'mir, 'tcx>) -> bool { + ecx.machine.check_alignment == AlignmentCheck::Int } #[inline(always)] - fn enforce_validity(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool { + fn enforce_validity(ecx: &MiriEvalContext<'mir, 'tcx>) -> bool { ecx.machine.validate } #[inline(always)] - fn enforce_number_validity(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool { + fn enforce_number_validity(ecx: &MiriEvalContext<'mir, 'tcx>) -> bool { ecx.machine.enforce_number_validity } #[inline(always)] - fn enforce_abi(ecx: &InterpCx<'mir, 'tcx, Self>) -> bool { + fn enforce_abi(ecx: &MiriEvalContext<'mir, 'tcx>) -> bool { ecx.machine.enforce_abi } #[inline(always)] fn find_mir_or_eval_fn( - ecx: &mut InterpCx<'mir, 'tcx, Self>, + ecx: &mut MiriEvalContext<'mir, 'tcx>, instance: ty::Instance<'tcx>, abi: Abi, args: &[OpTy<'tcx, Tag>], @@ -480,7 +474,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { #[inline(always)] fn call_extra_fn( - ecx: &mut InterpCx<'mir, 'tcx, Self>, + ecx: &mut MiriEvalContext<'mir, 'tcx>, fn_val: Dlsym, abi: Abi, args: &[OpTy<'tcx, Tag>], @@ -492,7 +486,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { #[inline(always)] fn call_intrinsic( - ecx: &mut rustc_const_eval::interpret::InterpCx<'mir, 'tcx, Self>, + ecx: &mut MiriEvalContext<'mir, 'tcx>, instance: ty::Instance<'tcx>, args: &[OpTy<'tcx, Tag>], ret: Option<(&PlaceTy<'tcx, Tag>, mir::BasicBlock)>, @@ -503,7 +497,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { #[inline(always)] fn assert_panic( - ecx: &mut InterpCx<'mir, 'tcx, Self>, + ecx: &mut MiriEvalContext<'mir, 'tcx>, msg: &mir::AssertMessage<'tcx>, unwind: Option, ) -> InterpResult<'tcx> { @@ -511,13 +505,13 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { } #[inline(always)] - fn abort(_ecx: &mut InterpCx<'mir, 'tcx, Self>, msg: String) -> InterpResult<'tcx, !> { + fn abort(_ecx: &mut MiriEvalContext<'mir, 'tcx>, msg: String) -> InterpResult<'tcx, !> { throw_machine_stop!(TerminationInfo::Abort(msg)) } #[inline(always)] fn binary_ptr_op( - ecx: &rustc_const_eval::interpret::InterpCx<'mir, 'tcx, Self>, + ecx: &MiriEvalContext<'mir, 'tcx>, bin_op: mir::BinOp, left: &ImmTy<'tcx, Tag>, right: &ImmTy<'tcx, Tag>, @@ -526,22 +520,22 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { } fn thread_local_static_base_pointer( - ecx: &mut InterpCx<'mir, 'tcx, Self>, + ecx: &mut MiriEvalContext<'mir, 'tcx>, def_id: DefId, ) -> InterpResult<'tcx, Pointer> { ecx.get_or_create_thread_local_alloc(def_id) } fn extern_static_base_pointer( - memory: &Memory<'mir, 'tcx, Self>, + ecx: &MiriEvalContext<'mir, 'tcx>, def_id: DefId, ) -> InterpResult<'tcx, Pointer> { - let attrs = memory.tcx.get_attrs(def_id); - let link_name = match memory.tcx.sess.first_attr_value_str_by_name(&attrs, sym::link_name) { + let attrs = ecx.tcx.get_attrs(def_id); + let link_name = match ecx.tcx.sess.first_attr_value_str_by_name(&attrs, sym::link_name) { Some(name) => name, - None => memory.tcx.item_name(def_id), + None => ecx.tcx.item_name(def_id), }; - if let Some(&ptr) = memory.extra.extern_statics.get(&link_name) { + if let Some(&ptr) = ecx.machine.extern_statics.get(&link_name) { Ok(ptr) } else { throw_unsup_format!("`extern` static {:?} is not supported by Miri", def_id) @@ -549,41 +543,41 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { } fn init_allocation_extra<'b>( - mem: &Memory<'mir, 'tcx, Self>, + ecx: &MiriEvalContext<'mir, 'tcx>, id: AllocId, alloc: Cow<'b, Allocation>, kind: Option>, ) -> Cow<'b, Allocation> { - if Some(id) == mem.extra.tracked_alloc_id { + if Some(id) == ecx.machine.tracked_alloc_id { register_diagnostic(NonHaltingDiagnostic::CreatedAlloc(id)); } let kind = kind.expect("we set our STATIC_KIND so this cannot be None"); let alloc = alloc.into_owned(); - let stacks = if let Some(stacked_borrows) = &mem.extra.stacked_borrows { + let stacks = if let Some(stacked_borrows) = &ecx.machine.stacked_borrows { Some(Stacks::new_allocation(id, alloc.size(), stacked_borrows, kind)) } else { None }; - let race_alloc = if let Some(data_race) = &mem.extra.data_race { + let race_alloc = if let Some(data_race) = &ecx.machine.data_race { Some(data_race::AllocExtra::new_allocation(&data_race, alloc.size(), kind)) } else { None }; let alloc: Allocation = alloc.convert_tag_add_extra( - &mem.tcx, + &ecx.tcx, AllocExtra { stacked_borrows: stacks, data_race: race_alloc }, - |ptr| Evaluator::tag_alloc_base_pointer(mem, ptr), + |ptr| Evaluator::tag_alloc_base_pointer(ecx, ptr), ); Cow::Owned(alloc) } fn tag_alloc_base_pointer( - mem: &Memory<'mir, 'tcx, Self>, + ecx: &MiriEvalContext<'mir, 'tcx>, ptr: Pointer, ) -> Pointer { - let absolute_addr = intptrcast::GlobalState::rel_ptr_to_addr(&mem, ptr); - let sb_tag = if let Some(stacked_borrows) = &mem.extra.stacked_borrows { + let absolute_addr = intptrcast::GlobalStateInner::rel_ptr_to_addr(ecx, ptr); + let sb_tag = if let Some(stacked_borrows) = &ecx.machine.stacked_borrows { stacked_borrows.borrow_mut().base_tag(ptr.provenance) } else { SbTag::Untagged @@ -593,38 +587,38 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { #[inline(always)] fn ptr_from_addr( - mem: &Memory<'mir, 'tcx, Self>, + ecx: &MiriEvalContext<'mir, 'tcx>, addr: u64, ) -> Pointer> { - intptrcast::GlobalState::ptr_from_addr(addr, mem) + intptrcast::GlobalStateInner::ptr_from_addr(addr, ecx) } /// Convert a pointer with provenance into an allocation-offset pair, /// or a `None` with an absolute address if that conversion is not possible. fn ptr_get_alloc( - mem: &Memory<'mir, 'tcx, Self>, + ecx: &MiriEvalContext<'mir, 'tcx>, ptr: Pointer, ) -> (AllocId, Size) { - let rel = intptrcast::GlobalState::abs_ptr_to_rel(mem, ptr); + let rel = intptrcast::GlobalStateInner::abs_ptr_to_rel(ecx, ptr); (ptr.provenance.alloc_id, rel) } #[inline(always)] fn memory_read( - memory_extra: &Self::MemoryExtra, + machine: &Self, alloc_extra: &AllocExtra, tag: Tag, range: AllocRange, ) -> InterpResult<'tcx> { if let Some(data_race) = &alloc_extra.data_race { - data_race.read(tag.alloc_id, range, memory_extra.data_race.as_ref().unwrap())?; + data_race.read(tag.alloc_id, range, machine.data_race.as_ref().unwrap())?; } if let Some(stacked_borrows) = &alloc_extra.stacked_borrows { stacked_borrows.memory_read( tag.alloc_id, tag.sb, range, - memory_extra.stacked_borrows.as_ref().unwrap(), + machine.stacked_borrows.as_ref().unwrap(), ) } else { Ok(()) @@ -633,20 +627,20 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { #[inline(always)] fn memory_written( - memory_extra: &mut Self::MemoryExtra, + machine: &mut Self, alloc_extra: &mut AllocExtra, tag: Tag, range: AllocRange, ) -> InterpResult<'tcx> { if let Some(data_race) = &mut alloc_extra.data_race { - data_race.write(tag.alloc_id, range, memory_extra.data_race.as_mut().unwrap())?; + data_race.write(tag.alloc_id, range, machine.data_race.as_mut().unwrap())?; } if let Some(stacked_borrows) = &mut alloc_extra.stacked_borrows { stacked_borrows.memory_written( tag.alloc_id, tag.sb, range, - memory_extra.stacked_borrows.as_mut().unwrap(), + machine.stacked_borrows.as_mut().unwrap(), ) } else { Ok(()) @@ -655,23 +649,23 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { #[inline(always)] fn memory_deallocated( - memory_extra: &mut Self::MemoryExtra, + machine: &mut Self, alloc_extra: &mut AllocExtra, tag: Tag, range: AllocRange, ) -> InterpResult<'tcx> { - if Some(tag.alloc_id) == memory_extra.tracked_alloc_id { + if Some(tag.alloc_id) == machine.tracked_alloc_id { register_diagnostic(NonHaltingDiagnostic::FreedAlloc(tag.alloc_id)); } if let Some(data_race) = &mut alloc_extra.data_race { - data_race.deallocate(tag.alloc_id, range, memory_extra.data_race.as_mut().unwrap())?; + data_race.deallocate(tag.alloc_id, range, machine.data_race.as_mut().unwrap())?; } if let Some(stacked_borrows) = &mut alloc_extra.stacked_borrows { stacked_borrows.memory_deallocated( tag.alloc_id, tag.sb, range, - memory_extra.stacked_borrows.as_mut().unwrap(), + machine.stacked_borrows.as_mut().unwrap(), ) } else { Ok(()) @@ -684,7 +678,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { kind: mir::RetagKind, place: &PlaceTy<'tcx, Tag>, ) -> InterpResult<'tcx> { - if ecx.memory.extra.stacked_borrows.is_some() { ecx.retag(kind, place) } else { Ok(()) } + if ecx.machine.stacked_borrows.is_some() { ecx.retag(kind, place) } else { Ok(()) } } #[inline(always)] @@ -707,7 +701,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { None }; - let stacked_borrows = ecx.memory.extra.stacked_borrows.as_ref(); + let stacked_borrows = ecx.machine.stacked_borrows.as_ref(); let call_id = stacked_borrows.map_or(NonZeroU64::new(1).unwrap(), |stacked_borrows| { stacked_borrows.borrow_mut().new_call() }); @@ -730,7 +724,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { #[inline(always)] fn after_stack_push(ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx> { - if ecx.memory.extra.stacked_borrows.is_some() { ecx.retag_return_place() } else { Ok(()) } + if ecx.machine.stacked_borrows.is_some() { ecx.retag_return_place() } else { Ok(()) } } #[inline(always)] diff --git a/src/shims/backtrace.rs b/src/shims/backtrace.rs index 6a8a9553e9363..32fbbffc63f8e 100644 --- a/src/shims/backtrace.rs +++ b/src/shims/backtrace.rs @@ -64,7 +64,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // to reconstruct the needed frame information in `handle_miri_resolve_frame`. // Note that we never actually read or write anything from/to this pointer - // all of the data is represented by the pointer value itself. - let fn_ptr = this.memory.create_fn_alloc(FnVal::Instance(instance)); + let fn_ptr = this.create_fn_alloc_ptr(FnVal::Instance(instance)); fn_ptr.wrapping_offset(Size::from_bytes(pos.0), this) }) .collect(); @@ -125,7 +125,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let ptr = this.read_pointer(ptr)?; // Take apart the pointer, we need its pieces. - let (alloc_id, offset, ptr) = this.memory.ptr_get_alloc(ptr)?; + let (alloc_id, offset, ptr) = this.ptr_get_alloc_id(ptr)?; let fn_instance = if let Some(GlobalAlloc::Function(instance)) = this.tcx.get_global_alloc(alloc_id) { @@ -159,7 +159,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Reconstruct the original function pointer, // which we pass to user code. - let fn_ptr = this.memory.create_fn_alloc(FnVal::Instance(fn_instance)); + let fn_ptr = this.create_fn_alloc_ptr(FnVal::Instance(fn_instance)); let num_fields = dest.layout.fields.count(); @@ -244,8 +244,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let (_, _, name, filename) = this.resolve_frame_pointer(ptr)?; - this.memory.write_bytes(this.read_pointer(name_ptr)?, name.bytes())?; - this.memory.write_bytes(this.read_pointer(filename_ptr)?, filename.bytes())?; + this.write_bytes_ptr(this.read_pointer(name_ptr)?, name.bytes())?; + this.write_bytes_ptr(this.read_pointer(filename_ptr)?, filename.bytes())?; Ok(()) } diff --git a/src/shims/env.rs b/src/shims/env.rs index 822bef56ce682..7be26de45916a 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -2,6 +2,7 @@ use std::convert::TryFrom; use std::env; use std::ffi::{OsStr, OsString}; use std::io::ErrorKind; +use std::mem; use rustc_const_eval::interpret::Pointer; use rustc_data_structures::fx::FxHashMap; @@ -38,20 +39,20 @@ pub struct EnvVars<'tcx> { impl<'tcx> EnvVars<'tcx> { pub(crate) fn init<'mir>( ecx: &mut InterpCx<'mir, 'tcx, Evaluator<'mir, 'tcx>>, - mut excluded_env_vars: Vec, - forwarded_env_vars: Vec, + config: &MiriConfig, ) -> InterpResult<'tcx> { let target_os = ecx.tcx.sess.target.os.as_ref(); // HACK: Exclude `TERM` var to avoid terminfo trying to open the termcap file. // This is (a) very slow and (b) does not work on Windows. + let mut excluded_env_vars = config.excluded_env_vars.clone(); excluded_env_vars.push("TERM".to_owned()); // Skip the loop entirely if we don't want to forward anything. - if ecx.machine.communicate() || !forwarded_env_vars.is_empty() { + if ecx.machine.communicate() || !config.forwarded_env_vars.is_empty() { for (name, value) in env::vars_os() { let forward = match ecx.machine.communicate() { true => !excluded_env_vars.iter().any(|v| v.as_str() == &name), - false => forwarded_env_vars.iter().any(|v| v.as_str() == &name), + false => config.forwarded_env_vars.iter().any(|v| v.as_str() == &name), }; if forward { let var_ptr = match target_os { @@ -75,13 +76,14 @@ impl<'tcx> EnvVars<'tcx> { ecx: &mut InterpCx<'mir, 'tcx, Evaluator<'mir, 'tcx>>, ) -> InterpResult<'tcx> { // Deallocate individual env vars. - for (_name, ptr) in ecx.machine.env_vars.map.drain() { - ecx.memory.deallocate(ptr, None, MiriMemoryKind::Runtime.into())?; + let env_vars = mem::take(&mut ecx.machine.env_vars.map); + for (_name, ptr) in env_vars { + ecx.deallocate_ptr(ptr, None, MiriMemoryKind::Runtime.into())?; } // Deallocate environ var list. let environ = ecx.machine.env_vars.environ.unwrap(); let old_vars_ptr = ecx.read_pointer(&environ.into())?; - ecx.memory.deallocate(old_vars_ptr, None, MiriMemoryKind::Runtime.into())?; + ecx.deallocate_ptr(old_vars_ptr, None, MiriMemoryKind::Runtime.into())?; Ok(()) } } @@ -199,7 +201,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.assert_target_os("windows", "FreeEnvironmentStringsW"); let env_block_ptr = this.read_pointer(env_block_op)?; - let result = this.memory.deallocate(env_block_ptr, None, MiriMemoryKind::Runtime.into()); + let result = this.deallocate_ptr(env_block_ptr, None, MiriMemoryKind::Runtime.into()); // If the function succeeds, the return value is nonzero. Ok(result.is_ok() as i32) } @@ -230,7 +232,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if let Some((name, value)) = new { let var_ptr = alloc_env_var_as_c_str(&name, &value, &mut this)?; if let Some(var) = this.machine.env_vars.map.insert(name, var_ptr) { - this.memory.deallocate(var, None, MiriMemoryKind::Runtime.into())?; + this.deallocate_ptr(var, None, MiriMemoryKind::Runtime.into())?; } this.update_environ()?; Ok(0) // return zero on success @@ -267,7 +269,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } else if this.ptr_is_null(value_ptr)? { // Delete environment variable `{name}` if let Some(var) = this.machine.env_vars.map.remove(&name) { - this.memory.deallocate(var, None, MiriMemoryKind::Runtime.into())?; + this.deallocate_ptr(var, None, MiriMemoryKind::Runtime.into())?; this.update_environ()?; } Ok(1) // return non-zero on success @@ -275,7 +277,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let value = this.read_os_str_from_wide_str(value_ptr)?; let var_ptr = alloc_env_var_as_wide_str(&name, &value, &mut this)?; if let Some(var) = this.machine.env_vars.map.insert(name, var_ptr) { - this.memory.deallocate(var, None, MiriMemoryKind::Runtime.into())?; + this.deallocate_ptr(var, None, MiriMemoryKind::Runtime.into())?; } this.update_environ()?; Ok(1) // return non-zero on success @@ -300,7 +302,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } if let Some(old) = success { if let Some(var) = old { - this.memory.deallocate(var, None, MiriMemoryKind::Runtime.into())?; + this.deallocate_ptr(var, None, MiriMemoryKind::Runtime.into())?; } this.update_environ()?; Ok(0) @@ -436,7 +438,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Deallocate the old environ list, if any. if let Some(environ) = this.machine.env_vars.environ { let old_vars_ptr = this.read_pointer(&environ.into())?; - this.memory.deallocate(old_vars_ptr, None, MiriMemoryKind::Runtime.into())?; + this.deallocate_ptr(old_vars_ptr, None, MiriMemoryKind::Runtime.into())?; } else { // No `environ` allocated yet, let's do that. // This is memory backing an extern static, hence `ExternStatic`, not `Env`. diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index d9e4d9382246c..77567e9bcae59 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -82,10 +82,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(Pointer::null()) } else { let align = this.min_align(size, kind); - let ptr = this.memory.allocate(Size::from_bytes(size), align, kind.into())?; + let ptr = this.allocate_ptr(Size::from_bytes(size), align, kind.into())?; if zero_init { // We just allocated this, the access is definitely in-bounds. - this.memory.write_bytes(ptr.into(), iter::repeat(0u8).take(size as usize)).unwrap(); + this.write_bytes_ptr(ptr.into(), iter::repeat(0u8).take(size as usize)).unwrap(); } Ok(ptr.into()) } @@ -94,7 +94,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn free(&mut self, ptr: Pointer>, kind: MiriMemoryKind) -> InterpResult<'tcx> { let this = self.eval_context_mut(); if !this.ptr_is_null(ptr)? { - this.memory.deallocate(ptr, None, kind.into())?; + this.deallocate_ptr(ptr, None, kind.into())?; } Ok(()) } @@ -112,15 +112,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(Pointer::null()) } else { let new_ptr = - this.memory.allocate(Size::from_bytes(new_size), new_align, kind.into())?; + this.allocate_ptr(Size::from_bytes(new_size), new_align, kind.into())?; Ok(new_ptr.into()) } } else { if new_size == 0 { - this.memory.deallocate(old_ptr, None, kind.into())?; + this.deallocate_ptr(old_ptr, None, kind.into())?; Ok(Pointer::null()) } else { - let new_ptr = this.memory.reallocate( + let new_ptr = this.reallocate_ptr( old_ptr, None, Size::from_bytes(new_size), @@ -373,7 +373,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "miri_static_root" => { let &[ref ptr] = this.check_shim(abi, Abi::Rust, link_name, args)?; let ptr = this.read_pointer(ptr)?; - let (alloc_id, offset, _) = this.memory.ptr_get_alloc(ptr)?; + let (alloc_id, offset, _) = this.ptr_get_alloc_id(ptr)?; if offset != Size::ZERO { throw_unsup_format!("pointer passed to miri_static_root must point to beginning of an allocated block"); } @@ -440,7 +440,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx return this.emulate_allocator(Symbol::intern("__rg_alloc"), |this| { Self::check_alloc_request(size, align)?; - let ptr = this.memory.allocate( + let ptr = this.allocate_ptr( Size::from_bytes(size), Align::from_bytes(align).unwrap(), MiriMemoryKind::Rust.into(), @@ -457,14 +457,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx return this.emulate_allocator(Symbol::intern("__rg_alloc_zeroed"), |this| { Self::check_alloc_request(size, align)?; - let ptr = this.memory.allocate( + let ptr = this.allocate_ptr( Size::from_bytes(size), Align::from_bytes(align).unwrap(), MiriMemoryKind::Rust.into(), )?; // We just allocated this, the access is definitely in-bounds. - this.memory.write_bytes(ptr.into(), iter::repeat(0u8).take(usize::try_from(size).unwrap())).unwrap(); + this.write_bytes_ptr(ptr.into(), iter::repeat(0u8).take(usize::try_from(size).unwrap())).unwrap(); this.write_pointer(ptr, dest) }); } @@ -476,7 +476,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx return this.emulate_allocator(Symbol::intern("__rg_dealloc"), |this| { // No need to check old_size/align; we anyway check that they match the allocation. - this.memory.deallocate( + this.deallocate_ptr( ptr, Some((Size::from_bytes(old_size), Align::from_bytes(align).unwrap())), MiriMemoryKind::Rust.into(), @@ -495,7 +495,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Self::check_alloc_request(new_size, align)?; let align = Align::from_bytes(align).unwrap(); - let new_ptr = this.memory.reallocate( + let new_ptr = this.reallocate_ptr( ptr, Some((Size::from_bytes(old_size), align)), Size::from_bytes(new_size), @@ -514,8 +514,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let n = Size::from_bytes(this.read_scalar(n)?.to_machine_usize(this)?); let result = { - let left_bytes = this.memory.read_bytes(left, n)?; - let right_bytes = this.memory.read_bytes(right, n)?; + let left_bytes = this.read_bytes_ptr(left, n)?; + let right_bytes = this.read_bytes_ptr(right, n)?; use std::cmp::Ordering::*; match left_bytes.cmp(right_bytes) { @@ -533,8 +533,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let val = this.read_scalar(val)?.to_i32()? as u8; let num = this.read_scalar(num)?.to_machine_usize(this)?; if let Some(idx) = this - .memory - .read_bytes(ptr, Size::from_bytes(num))? + .read_bytes_ptr(ptr, Size::from_bytes(num))? .iter() .rev() .position(|&c| c == val) @@ -551,8 +550,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let val = this.read_scalar(val)?.to_i32()? as u8; let num = this.read_scalar(num)?.to_machine_usize(this)?; let idx = this - .memory - .read_bytes(ptr, Size::from_bytes(num))? + .read_bytes_ptr(ptr, Size::from_bytes(num))? .iter() .position(|&c| c == val); if let Some(idx) = idx { diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 7e2068e4657bb..9101cbcf05ff4 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -88,8 +88,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let byte_count = ty_layout.size.checked_mul(count, this).ok_or_else(|| { err_ub_format!("overflow computing total size of `{}`", intrinsic_name) })?; - this.memory - .write_bytes(ptr, iter::repeat(val_byte).take(byte_count.bytes() as usize))?; + this.write_bytes_ptr( + ptr, + iter::repeat(val_byte).take(byte_count.bytes() as usize), + )?; } // Floating-point operations @@ -1087,7 +1089,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // even if the type they wrap would be less aligned (e.g. AtomicU64 on 32bit must // be 8-aligned). let align = Align::from_bytes(place.layout.size.bytes()).unwrap(); - this.memory.check_ptr_access_align( + this.check_ptr_access_align( place.ptr, place.layout.size, align, @@ -1113,7 +1115,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // even if the type they wrap would be less aligned (e.g. AtomicU64 on 32bit must // be 8-aligned). let align = Align::from_bytes(place.layout.size.bytes()).unwrap(); - this.memory.check_ptr_access_align( + this.check_ptr_access_align( place.ptr, place.layout.size, align, @@ -1168,7 +1170,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // even if the type they wrap would be less aligned (e.g. AtomicU64 on 32bit must // be 8-aligned). let align = Align::from_bytes(place.layout.size.bytes()).unwrap(); - this.memory.check_ptr_access_align( + this.check_ptr_access_align( place.ptr, place.layout.size, align, @@ -1210,7 +1212,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // even if the type they wrap would be less aligned (e.g. AtomicU64 on 32bit must // be 8-aligned). let align = Align::from_bytes(place.layout.size.bytes()).unwrap(); - this.memory.check_ptr_access_align( + this.check_ptr_access_align( place.ptr, place.layout.size, align, @@ -1241,7 +1243,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // even if the type they wrap would be less aligned (e.g. AtomicU64 on 32bit must // be 8-aligned). let align = Align::from_bytes(place.layout.size.bytes()).unwrap(); - this.memory.check_ptr_access_align( + this.check_ptr_access_align( place.ptr, place.layout.size, align, diff --git a/src/shims/mod.rs b/src/shims/mod.rs index 66f673d241d36..83bc6b6ae1bab 100644 --- a/src/shims/mod.rs +++ b/src/shims/mod.rs @@ -69,7 +69,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); let (dest, ret) = ret.unwrap(); - if this.memory.extra.check_alignment != AlignmentCheck::Symbolic { + if this.machine.check_alignment != AlignmentCheck::Symbolic { // Just use actual implementation. return Ok(false); } @@ -86,7 +86,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if let Ok(ptr) = ptr.into_pointer_or_addr() { // Only do anything if we can identify the allocation this goes to. let (_, cur_align) = - this.memory.get_size_and_align(ptr.provenance.alloc_id, AllocCheck::MaybeDead)?; + this.get_alloc_size_and_align(ptr.provenance.alloc_id, AllocCheck::MaybeDead)?; if cur_align.bytes() >= req_align { // If the allocation alignment is at least the required alignment we use the // real implementation. diff --git a/src/shims/os_str.rs b/src/shims/os_str.rs index ede29d04d6bc9..c03f7ad79be73 100644 --- a/src/shims/os_str.rs +++ b/src/shims/os_str.rs @@ -108,8 +108,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx return Ok((false, string_length)); } self.eval_context_mut() - .memory - .write_bytes(ptr, bytes.iter().copied().chain(iter::once(0u8)))?; + .write_bytes_ptr(ptr, bytes.iter().copied().chain(iter::once(0u8)))?; Ok((true, string_length)) } @@ -152,8 +151,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let size2 = Size::from_bytes(2); let this = self.eval_context_mut(); let mut alloc = this - .memory - .get_mut(ptr, size2 * string_length, Align::from_bytes(2).unwrap())? + .get_ptr_alloc_mut(ptr, size2 * string_length, Align::from_bytes(2).unwrap())? .unwrap(); // not a ZST, so we will get a result for (offset, wchar) in u16_vec.into_iter().chain(iter::once(0x0000)).enumerate() { let offset = u64::try_from(offset).unwrap(); diff --git a/src/shims/panic.rs b/src/shims/panic.rs index 04a8e9063f9ac..4190cccae6d0c 100644 --- a/src/shims/panic.rs +++ b/src/shims/panic.rs @@ -89,7 +89,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let catch_fn = this.read_scalar(catch_fn)?.check_init()?; // Now we make a function call, and pass `data` as first and only argument. - let f_instance = this.memory.get_fn(try_fn)?.as_instance()?; + let f_instance = this.get_ptr_fn(try_fn)?.as_instance()?; trace!("try_fn: {:?}", f_instance); let ret_place = MPlaceTy::dangling(this.machine.layouts.unit).into(); this.call_function( @@ -123,7 +123,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); trace!("handle_stack_pop(extra = {:?}, unwinding = {})", extra, unwinding); - if let Some(stacked_borrows) = &this.memory.extra.stacked_borrows { + if let Some(stacked_borrows) = &this.machine.stacked_borrows { stacked_borrows.borrow_mut().end_call(extra.call_id); } @@ -146,7 +146,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Push the `catch_fn` stackframe. let f_instance = - this.memory.get_fn(this.scalar_to_ptr(catch_unwind.catch_fn))?.as_instance()?; + this.get_ptr_fn(this.scalar_to_ptr(catch_unwind.catch_fn))?.as_instance()?; trace!("catch_fn: {:?}", f_instance); let ret_place = MPlaceTy::dangling(this.machine.layouts.unit).into(); this.call_function( diff --git a/src/shims/posix/foreign_items.rs b/src/shims/posix/foreign_items.rs index 36bf530599299..4bf0bbc26212d 100644 --- a/src/shims/posix/foreign_items.rs +++ b/src/shims/posix/foreign_items.rs @@ -157,7 +157,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if size == 0 { this.write_null(&ret.into())?; } else { - let ptr = this.memory.allocate( + let ptr = this.allocate_ptr( Size::from_bytes(size), Align::from_bytes(align).unwrap(), MiriMemoryKind::C.into(), @@ -174,7 +174,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let symbol = this.read_pointer(symbol)?; let symbol_name = this.read_c_str(symbol)?; if let Some(dlsym) = Dlsym::from_str(symbol_name, &this.tcx.sess.target.os)? { - let ptr = this.memory.create_fn_alloc(FnVal::Other(dlsym)); + let ptr = this.create_fn_alloc_ptr(FnVal::Other(dlsym)); this.write_pointer(ptr, dest)?; } else { this.write_null(dest)?; @@ -214,7 +214,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Extract the function type out of the signature (that seems easier than constructing it ourselves). let dtor = if !this.ptr_is_null(dtor)? { - Some(this.memory.get_fn(dtor)?.as_instance()?) + Some(this.get_ptr_fn(dtor)?.as_instance()?) } else { None }; diff --git a/src/shims/posix/fs.rs b/src/shims/posix/fs.rs index b71f53cce566e..288935576e0dd 100644 --- a/src/shims/posix/fs.rs +++ b/src/shims/posix/fs.rs @@ -34,7 +34,7 @@ trait FileDescriptor: std::fmt::Debug { bytes: &mut [u8], ) -> InterpResult<'tcx, io::Result>; fn write<'tcx>( - &mut self, + &self, communicate_allowed: bool, bytes: &[u8], ) -> InterpResult<'tcx, io::Result>; @@ -66,12 +66,12 @@ impl FileDescriptor for FileHandle { } fn write<'tcx>( - &mut self, + &self, communicate_allowed: bool, bytes: &[u8], ) -> InterpResult<'tcx, io::Result> { assert!(communicate_allowed, "isolation should have prevented even opening a file"); - Ok(self.file.write(bytes)) + Ok((&mut &self.file).write(bytes)) } fn seek<'tcx>( @@ -133,7 +133,7 @@ impl FileDescriptor for io::Stdin { } fn write<'tcx>( - &mut self, + &self, _communicate_allowed: bool, _bytes: &[u8], ) -> InterpResult<'tcx, io::Result> { @@ -174,12 +174,12 @@ impl FileDescriptor for io::Stdout { } fn write<'tcx>( - &mut self, + &self, _communicate_allowed: bool, bytes: &[u8], ) -> InterpResult<'tcx, io::Result> { // We allow writing to stderr even with isolation enabled. - let result = Write::write(self, bytes); + let result = Write::write(&mut { self }, bytes); // Stdout is buffered, flush to make sure it appears on the // screen. This is the write() syscall of the interpreted // program, we want it to correspond to a write() syscall on @@ -224,13 +224,13 @@ impl FileDescriptor for io::Stderr { } fn write<'tcx>( - &mut self, + &self, _communicate_allowed: bool, bytes: &[u8], ) -> InterpResult<'tcx, io::Result> { // We allow writing to stderr even with isolation enabled. // No need to flush, stderr is not buffered. - Ok(Write::write(self, bytes)) + Ok(Write::write(&mut { self }, bytes)) } fn seek<'tcx>( @@ -681,7 +681,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx trace!("Reading from FD {}, size {}", fd, count); // Check that the *entire* buffer is actually valid memory. - this.memory.check_ptr_access_align( + this.check_ptr_access_align( buf, Size::from_bytes(count), Align::ONE, @@ -707,7 +707,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx match result { Ok(read_bytes) => { // If reading to `bytes` did not fail, we write those bytes to the buffer. - this.memory.write_bytes(buf, bytes)?; + this.write_bytes_ptr(buf, bytes)?; Ok(read_bytes) } Err(e) => { @@ -727,7 +727,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Isolation check is done via `FileDescriptor` trait. // Check that the *entire* buffer is actually valid memory. - this.memory.check_ptr_access_align( + this.check_ptr_access_align( buf, Size::from_bytes(count), Align::ONE, @@ -739,8 +739,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let count = count.min(this.machine_isize_max() as u64).min(isize::MAX as u64); let communicate = this.machine.communicate(); - if let Some(file_descriptor) = this.machine.file_handler.handles.get_mut(&fd) { - let bytes = this.memory.read_bytes(buf, Size::from_bytes(count))?; + if let Some(file_descriptor) = this.machine.file_handler.handles.get(&fd) { + let bytes = this.read_bytes_ptr(buf, Size::from_bytes(count))?; let result = file_descriptor.write(communicate, &bytes)?.map(|c| i64::try_from(c).unwrap()); this.try_unwrap_io_result(result) @@ -1288,7 +1288,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx )?; let name_ptr = entry.offset(Size::from_bytes(d_name_offset), this)?; - this.memory.write_bytes(name_ptr, name_bytes.iter().copied())?; + this.write_bytes_ptr(name_ptr, name_bytes.iter().copied())?; entry } @@ -1597,7 +1597,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // 'readlink' truncates the resolved path if // the provided buffer is not large enough. - this.memory.write_bytes(buf, path_bytes.iter().copied())?; + this.write_bytes_ptr(buf, path_bytes.iter().copied())?; Ok(path_bytes.len().try_into().unwrap()) } Err(e) => { diff --git a/src/shims/posix/linux/sync.rs b/src/shims/posix/linux/sync.rs index 17ddca879e684..60c0c2d7c1016 100644 --- a/src/shims/posix/linux/sync.rs +++ b/src/shims/posix/linux/sync.rs @@ -79,7 +79,7 @@ pub fn futex<'tcx>( // Check the pointer for alignment and validity. // The API requires `addr` to be a 4-byte aligned pointer, and will // use the 4 bytes at the given address as an (atomic) i32. - this.memory.check_ptr_access_align( + this.check_ptr_access_align( this.scalar_to_ptr(addr_scalar), Size::from_bytes(4), Align::from_bytes(4).unwrap(), diff --git a/src/shims/posix/macos/foreign_items.rs b/src/shims/posix/macos/foreign_items.rs index 8147b1442907d..18646b70130e4 100644 --- a/src/shims/posix/macos/foreign_items.rs +++ b/src/shims/posix/macos/foreign_items.rs @@ -121,7 +121,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let &[ref dtor, ref data] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let dtor = this.read_pointer(dtor)?; - let dtor = this.memory.get_fn(dtor)?.as_instance()?; + let dtor = this.get_ptr_fn(dtor)?.as_instance()?; let data = this.read_scalar(data)?.check_init()?; let active_thread = this.get_active_thread(); this.machine.tls.set_macos_thread_dtor(active_thread, dtor, data)?; diff --git a/src/shims/posix/thread.rs b/src/shims/posix/thread.rs index b49817e88511d..58d48028f62cb 100644 --- a/src/shims/posix/thread.rs +++ b/src/shims/posix/thread.rs @@ -41,7 +41,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let old_thread_id = this.set_active_thread(new_thread_id); // Perform the function pointer load in the new thread frame. - let instance = this.memory.get_fn(fn_ptr)?.as_instance()?; + let instance = this.get_ptr_fn(fn_ptr)?.as_instance()?; // Note: the returned value is currently ignored (see the FIXME in // pthread_join below) because the Rust standard library does not use @@ -122,7 +122,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let mut name = this.get_active_thread_name().to_vec(); name.push(0u8); assert!(name.len() <= 16); - this.memory.write_bytes(address, name)?; + this.write_bytes_ptr(address, name)?; } else { throw_unsup_format!("unsupported prctl option {}", option); } diff --git a/src/shims/tls.rs b/src/shims/tls.rs index 32bea8dde4754..297d0c1228a48 100644 --- a/src/shims/tls.rs +++ b/src/shims/tls.rs @@ -249,7 +249,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "p_thread_callback", ])?; let thread_callback = - this.memory.get_fn(this.scalar_to_ptr(thread_callback))?.as_instance()?; + this.get_ptr_fn(this.scalar_to_ptr(thread_callback))?.as_instance()?; // The signature of this function is `unsafe extern "system" fn(h: c::LPVOID, dwReason: c::DWORD, pv: c::LPVOID)`. let reason = this.eval_path_scalar(&["std", "sys", "windows", "c", "DLL_THREAD_DETACH"])?; diff --git a/src/shims/windows/foreign_items.rs b/src/shims/windows/foreign_items.rs index 61a1759ffee55..82ac5c5d75c43 100644 --- a/src/shims/windows/foreign_items.rs +++ b/src/shims/windows/foreign_items.rs @@ -87,7 +87,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // stdout/stderr use std::io::{self, Write}; - let buf_cont = this.memory.read_bytes(buf, Size::from_bytes(u64::from(n)))?; + let buf_cont = this.read_bytes_ptr(buf, Size::from_bytes(u64::from(n)))?; let res = if handle == -11 { io::stdout().write(buf_cont) } else { @@ -157,7 +157,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; let system_info = this.deref_operand(system_info)?; // Initialize with `0`. - this.memory.write_bytes( + this.write_bytes_ptr( system_info.ptr, iter::repeat(0u8).take(system_info.layout.size.bytes() as usize), )?; @@ -269,7 +269,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.read_scalar(hModule)?.to_machine_isize(this)?; let name = this.read_c_str(this.read_pointer(lpProcName)?)?; if let Some(dlsym) = Dlsym::from_str(name, &this.tcx.sess.target.os)? { - let ptr = this.memory.create_fn_alloc(FnVal::Other(dlsym)); + let ptr = this.create_fn_alloc_ptr(FnVal::Other(dlsym)); this.write_pointer(ptr, dest)?; } else { this.write_null(dest)?; diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 777b8e9331ee2..a365d909981bf 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -93,7 +93,7 @@ pub struct Stacks { /// Extra global state, available to the memory access hooks. #[derive(Debug)] -pub struct GlobalState { +pub struct GlobalStateInner { /// Next unused pointer ID (tag). next_ptr_id: PtrId, /// Table storing the "base" tag for each allocation. @@ -111,8 +111,8 @@ pub struct GlobalState { /// Whether to track raw pointers. tag_raw: bool, } -/// Memory extra state gives us interior mutable access to the global state. -pub type MemoryExtra = RefCell; +/// We need interior mutable access to the global state. +pub type GlobalState = RefCell; /// Indicates which kind of access is being performed. #[derive(Copy, Clone, Hash, PartialEq, Eq, Debug)] @@ -156,13 +156,13 @@ impl fmt::Display for RefKind { } /// Utilities for initialization and ID generation -impl GlobalState { +impl GlobalStateInner { pub fn new( tracked_pointer_tag: Option, tracked_call_id: Option, tag_raw: bool, ) -> Self { - GlobalState { + GlobalStateInner { next_ptr_id: NonZeroU64::new(1).unwrap(), base_ptr_ids: FxHashMap::default(), next_call_id: NonZeroU64::new(1).unwrap(), @@ -308,7 +308,7 @@ impl<'tcx> Stack { fn check_protector( item: &Item, provoking_access: Option<(SbTag, AccessKind)>, - global: &GlobalState, + global: &GlobalStateInner, ) -> InterpResult<'tcx> { if let SbTag::Tagged(id) = item.tag { if Some(id) == global.tracked_pointer_tag { @@ -348,7 +348,7 @@ impl<'tcx> Stack { access: AccessKind, tag: SbTag, (alloc_id, range, offset): (AllocId, AllocRange, Size), // just for debug printing and error messages - global: &GlobalState, + global: &GlobalStateInner, ) -> InterpResult<'tcx> { // Two main steps: Find granting item, remove incompatible items above. @@ -396,7 +396,7 @@ impl<'tcx> Stack { &mut self, tag: SbTag, dbg_ptr: Pointer, // just for debug printing and error messages - global: &GlobalState, + global: &GlobalStateInner, ) -> InterpResult<'tcx> { // Step 1: Find granting item. self.find_granting(AccessKind::Write, tag).ok_or_else(|| { @@ -425,7 +425,7 @@ impl<'tcx> Stack { derived_from: SbTag, new: Item, (alloc_id, alloc_range, offset): (AllocId, AllocRange, Size), // just for debug printing and error messages - global: &GlobalState, + global: &GlobalStateInner, ) -> InterpResult<'tcx> { // Figure out which access `perm` corresponds to. let access = @@ -584,10 +584,10 @@ impl Stacks { pub fn new_allocation( id: AllocId, size: Size, - extra: &MemoryExtra, + state: &GlobalState, kind: MemoryKind, ) -> Self { - let mut extra = extra.borrow_mut(); + let mut extra = state.borrow_mut(); let (base_tag, perm) = match kind { // New unique borrow. This tag is not accessible by the program, // so it will only ever be used when using the local directly (i.e., @@ -628,7 +628,7 @@ impl Stacks { alloc_id: AllocId, tag: SbTag, range: AllocRange, - extra: &MemoryExtra, + state: &GlobalState, ) -> InterpResult<'tcx> { trace!( "read access with tag {:?}: {:?}, size {}", @@ -636,7 +636,7 @@ impl Stacks { Pointer::new(alloc_id, range.start), range.size.bytes() ); - let global = &*extra.borrow(); + let global = &*state.borrow(); self.for_each(range, move |offset, stack| { stack.access(AccessKind::Read, tag, (alloc_id, range, offset), global) }) @@ -648,7 +648,7 @@ impl Stacks { alloc_id: AllocId, tag: SbTag, range: AllocRange, - extra: &mut MemoryExtra, + state: &mut GlobalState, ) -> InterpResult<'tcx> { trace!( "write access with tag {:?}: {:?}, size {}", @@ -656,7 +656,7 @@ impl Stacks { Pointer::new(alloc_id, range.start), range.size.bytes() ); - let global = extra.get_mut(); + let global = state.get_mut(); self.for_each_mut(range, move |offset, stack| { stack.access(AccessKind::Write, tag, (alloc_id, range, offset), global) }) @@ -668,10 +668,10 @@ impl Stacks { alloc_id: AllocId, tag: SbTag, range: AllocRange, - extra: &mut MemoryExtra, + state: &mut GlobalState, ) -> InterpResult<'tcx> { trace!("deallocation with tag {:?}: {:?}, size {}", tag, alloc_id, range.size.bytes()); - let global = extra.get_mut(); + let global = state.get_mut(); self.for_each_mut(range, move |offset, stack| { stack.dealloc(tag, Pointer::new(alloc_id, offset), global) }) @@ -702,12 +702,12 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ); return Ok(()); } - let (alloc_id, base_offset, ptr) = this.memory.ptr_get_alloc(place.ptr)?; + let (alloc_id, base_offset, ptr) = this.ptr_get_alloc_id(place.ptr)?; let orig_tag = ptr.provenance.sb; // Ensure we bail out if the pointer goes out-of-bounds (see miri#1050). let (alloc_size, _) = - this.memory.get_size_and_align(alloc_id, AllocCheck::Dereferenceable)?; + this.get_alloc_size_and_align(alloc_id, AllocCheck::Dereferenceable)?; if base_offset + size > alloc_size { throw_ub!(PointerOutOfBounds { alloc_id, @@ -750,10 +750,10 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // We need a frozen-sensitive reborrow. // We have to use shared references to alloc/memory_extra here since // `visit_freeze_sensitive` needs to access the global state. - let extra = this.memory.get_alloc_extra(alloc_id)?; + let extra = this.get_alloc_extra(alloc_id)?; let stacked_borrows = extra.stacked_borrows.as_ref().expect("we should have Stacked Borrows data"); - let global = this.memory.extra.stacked_borrows.as_ref().unwrap().borrow(); + let global = this.machine.stacked_borrows.as_ref().unwrap().borrow(); this.visit_freeze_sensitive(place, size, |mut range, frozen| { // Adjust range. range.start += base_offset; @@ -774,7 +774,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Here we can avoid `borrow()` calls because we have mutable references. // Note that this asserts that the allocation is mutable -- but since we are creating a // mutable pointer, that seems reasonable. - let (alloc_extra, memory_extra) = this.memory.get_alloc_extra_mut(alloc_id)?; + let (alloc_extra, memory_extra) = this.get_alloc_extra_mut(alloc_id)?; let stacked_borrows = alloc_extra.stacked_borrows.as_mut().expect("we should have Stacked Borrows data"); let global = memory_extra.stacked_borrows.as_mut().unwrap().get_mut(); @@ -808,7 +808,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Compute new borrow. let new_tag = { - let mem_extra = this.memory.extra.stacked_borrows.as_mut().unwrap().get_mut(); + let mem_extra = this.machine.stacked_borrows.as_mut().unwrap().get_mut(); match kind { // Give up tracking for raw pointers. RefKind::Raw { .. } if !mem_extra.tag_raw => SbTag::Untagged, diff --git a/src/sync.rs b/src/sync.rs index 0e4e9695d81d5..44ea18f4055da 100644 --- a/src/sync.rs +++ b/src/sync.rs @@ -242,7 +242,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx mutex.owner = Some(thread); } mutex.lock_count = mutex.lock_count.checked_add(1).unwrap(); - if let Some(data_race) = &this.memory.extra.data_race { + if let Some(data_race) = &this.machine.data_race { data_race.validate_lock_acquire(&mutex.data_race, thread); } } @@ -268,7 +268,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx mutex.owner = None; // The mutex is completely unlocked. Try transfering ownership // to another thread. - if let Some(data_race) = &this.memory.extra.data_race { + if let Some(data_race) = &this.machine.data_race { data_race.validate_lock_release(&mut mutex.data_race, current_owner); } this.mutex_dequeue_and_lock(id); @@ -328,7 +328,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let rwlock = &mut this.machine.threads.sync.rwlocks[id]; let count = rwlock.readers.entry(reader).or_insert(0); *count = count.checked_add(1).expect("the reader counter overflowed"); - if let Some(data_race) = &this.memory.extra.data_race { + if let Some(data_race) = &this.machine.data_race { data_race.validate_lock_acquire(&rwlock.data_race, reader); } } @@ -352,7 +352,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } Entry::Vacant(_) => return false, // we did not even own this lock } - if let Some(data_race) = &this.memory.extra.data_race { + if let Some(data_race) = &this.machine.data_race { data_race.validate_lock_release_shared(&mut rwlock.data_race_reader, reader); } @@ -385,7 +385,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx trace!("rwlock_writer_lock: {:?} now held by {:?}", id, writer); let rwlock = &mut this.machine.threads.sync.rwlocks[id]; rwlock.writer = Some(writer); - if let Some(data_race) = &this.memory.extra.data_race { + if let Some(data_race) = &this.machine.data_race { data_race.validate_lock_acquire(&rwlock.data_race, writer); } } @@ -405,7 +405,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Release memory to both reader and writer vector clocks // since this writer happens-before both the union of readers once they are finished // and the next writer - if let Some(data_race) = &this.memory.extra.data_race { + if let Some(data_race) = &this.machine.data_race { data_race.validate_lock_release(&mut rwlock.data_race, current_writer); data_race.validate_lock_release(&mut rwlock.data_race_reader, current_writer); } @@ -465,7 +465,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); let current_thread = this.get_active_thread(); let condvar = &mut this.machine.threads.sync.condvars[id]; - let data_race = &this.memory.extra.data_race; + let data_race = &this.machine.data_race; // Each condvar signal happens-before the end of the condvar wake if let Some(data_race) = data_race { @@ -498,7 +498,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); let current_thread = this.get_active_thread(); let futex = &mut this.machine.threads.sync.futexes.get_mut(&addr)?; - let data_race = &this.memory.extra.data_race; + let data_race = &this.machine.data_race; // Each futex-wake happens-before the end of the futex wait if let Some(data_race) = data_race { diff --git a/src/thread.rs b/src/thread.rs index b2f2a8098de23..2c5f6c2391f05 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -574,7 +574,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let allocation = tcx.eval_static_initializer(def_id)?; // Create a fresh allocation with this content. let new_alloc = - this.memory.allocate_with(allocation.inner().clone(), MiriMemoryKind::Tls.into()); + this.allocate_raw_ptr(allocation.inner().clone(), MiriMemoryKind::Tls.into()); this.machine.threads.set_thread_local_alloc(def_id, new_alloc); Ok(new_alloc) } @@ -584,7 +584,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn create_thread(&mut self) -> ThreadId { let this = self.eval_context_mut(); let id = this.machine.threads.create_thread(); - if let Some(data_race) = &mut this.memory.extra.data_race { + if let Some(data_race) = &mut this.machine.data_race { data_race.thread_created(id); } id @@ -599,14 +599,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx #[inline] fn join_thread(&mut self, joined_thread_id: ThreadId) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - this.machine.threads.join_thread(joined_thread_id, this.memory.extra.data_race.as_mut())?; + this.machine.threads.join_thread(joined_thread_id, this.machine.data_race.as_mut())?; Ok(()) } #[inline] fn set_active_thread(&mut self, thread_id: ThreadId) -> ThreadId { let this = self.eval_context_mut(); - if let Some(data_race) = &this.memory.extra.data_race { + if let Some(data_race) = &this.machine.data_race { data_race.thread_set_active(thread_id); } this.machine.threads.set_active_thread_id(thread_id) @@ -669,7 +669,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx #[inline] fn set_active_thread_name(&mut self, new_thread_name: Vec) { let this = self.eval_context_mut(); - if let Some(data_race) = &mut this.memory.extra.data_race { + if let Some(data_race) = &mut this.machine.data_race { if let Ok(string) = String::from_utf8(new_thread_name.clone()) { data_race.thread_set_name(this.machine.threads.active_thread, string); } @@ -753,7 +753,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx #[inline] fn schedule(&mut self) -> InterpResult<'tcx, SchedulingAction> { let this = self.eval_context_mut(); - let data_race = &this.memory.extra.data_race; + let data_race = &this.machine.data_race; this.machine.threads.schedule(data_race) } @@ -764,8 +764,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx #[inline] fn thread_terminated(&mut self) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - for ptr in this.machine.threads.thread_terminated(this.memory.extra.data_race.as_mut()) { - this.memory.deallocate(ptr.into(), None, MiriMemoryKind::Tls.into())?; + for ptr in this.machine.threads.thread_terminated(this.machine.data_race.as_mut()) { + this.deallocate_ptr(ptr.into(), None, MiriMemoryKind::Tls.into())?; } Ok(()) } From 0512b2a376c7d984e94367bf578c1f98c88654f2 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 5 Apr 2022 11:10:21 -0400 Subject: [PATCH 2969/3747] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 8e4cdeddfccb5..3007bc068a248 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -6af09d2505f38e4f1df291df56d497fb2ad935ed +634770c0a7f8598164ab825cfe419cc8b03c36e5 From 46ff257b4e3e417b145b13fbbbb0fb45fde08b15 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 5 Apr 2022 18:29:17 -0400 Subject: [PATCH 2970/3747] test that partially uninit MaybeUninit works correctly --- rust-version | 2 +- tests/run-pass/partially-uninit.rs | 15 +++++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) create mode 100644 tests/run-pass/partially-uninit.rs diff --git a/rust-version b/rust-version index 3007bc068a248..c84d46fa5142f 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -634770c0a7f8598164ab825cfe419cc8b03c36e5 +f262ca12aac76152c4b46cefcf8300f0249a5eb2 diff --git a/tests/run-pass/partially-uninit.rs b/tests/run-pass/partially-uninit.rs new file mode 100644 index 0000000000000..1de5308428279 --- /dev/null +++ b/tests/run-pass/partially-uninit.rs @@ -0,0 +1,15 @@ +// compile-flags: -Zmiri-check-number-validity + +use std::mem::{self, MaybeUninit}; + +#[repr(C)] +#[derive(Copy, Clone, Debug, PartialEq)] +struct Demo(bool, u16); + +fn main() { unsafe { + // Transmute-round-trip through a type with Scalar layout is lossless. + // This is tricky because that 'scalar' is *partially* uninitialized. + let x = Demo(true, 3); + let y: MaybeUninit = mem::transmute(x); + assert_eq!(x, mem::transmute(y)); +} } From 37cefa32d2badcb6eebd6851104108f1e02d3c3c Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Wed, 6 Apr 2022 23:03:52 +0200 Subject: [PATCH 2971/3747] Add support for FUTEX_WAIT_BITSET(bitset=MAX). --- src/shims/posix/linux/sync.rs | 49 ++++++++++++++++++++++++++++------- 1 file changed, 40 insertions(+), 9 deletions(-) diff --git a/src/shims/posix/linux/sync.rs b/src/shims/posix/linux/sync.rs index 60c0c2d7c1016..a4097bcd75fa4 100644 --- a/src/shims/posix/linux/sync.rs +++ b/src/shims/posix/linux/sync.rs @@ -36,6 +36,7 @@ pub fn futex<'tcx>( let futex_private = this.eval_libc_i32("FUTEX_PRIVATE_FLAG")?; let futex_wait = this.eval_libc_i32("FUTEX_WAIT")?; + let futex_wait_bitset = this.eval_libc_i32("FUTEX_WAIT_BITSET")?; let futex_wake = this.eval_libc_i32("FUTEX_WAKE")?; let futex_realtime = this.eval_libc_i32("FUTEX_CLOCK_REALTIME")?; @@ -45,12 +46,32 @@ pub fn futex<'tcx>( // FUTEX_WAIT: (int *addr, int op = FUTEX_WAIT, int val, const timespec *timeout) // Blocks the thread if *addr still equals val. Wakes up when FUTEX_WAKE is called on the same address, // or *timeout expires. `timeout == null` for an infinite timeout. - op if op & !futex_realtime == futex_wait => { - if args.len() < 5 { - throw_ub_format!( - "incorrect number of arguments for `futex` syscall with `op=FUTEX_WAIT`: got {}, expected at least 5", - args.len() - ); + // + // FUTEX_WAIT_BITSET: (int *addr, int op = FUTEX_WAIT_BITSET, int val, const timespec *timeout, int *_ignored, unsigned int bitset) + // When bitset is u32::MAX, this is identical to FUTEX_WAIT, except the timeout is absolute rather than relative. + op if op & !futex_realtime == futex_wait || op & !futex_realtime == futex_wait_bitset => { + let wait_bitset = op & !futex_realtime == futex_wait_bitset; + + if wait_bitset { + if args.len() != 7 { + throw_ub_format!( + "incorrect number of arguments for `futex` syscall with `op=FUTEX_WAIT_BITSET`: got {}, expected 7", + args.len() + ); + } + + let bitset = this.read_scalar(&args[6])?.to_u32()?; + + if bitset != u32::MAX { + throw_unsup_format!("Miri does not support `futex` syscall with `op=FUTEX_WAIT_BITSET` with a bitset other than UINT_MAX"); + } + } else { + if args.len() < 5 { + throw_ub_format!( + "incorrect number of arguments for `futex` syscall with `op=FUTEX_WAIT`: got {}, expected at least 5", + args.len() + ); + } } // `deref_operand` but not actually dereferencing the ptr yet (it might be NULL!). @@ -70,10 +91,20 @@ pub fn futex<'tcx>( return Ok(()); } }; - Some(if op & futex_realtime != 0 { - Time::RealTime(SystemTime::now().checked_add(duration).unwrap()) + Some(if wait_bitset { + // FUTEX_WAIT_BITSET uses an absolute timestamp. + if op & futex_realtime != 0 { + Time::RealTime(SystemTime::UNIX_EPOCH.checked_add(duration).unwrap()) + } else { + Time::Monotonic(this.machine.time_anchor.checked_add(duration).unwrap()) + } } else { - Time::Monotonic(Instant::now().checked_add(duration).unwrap()) + // FUTEX_WAIT uses a relative timestamp. + if op & futex_realtime != 0 { + Time::RealTime(SystemTime::now().checked_add(duration).unwrap()) + } else { + Time::Monotonic(Instant::now().checked_add(duration).unwrap()) + } }) }; // Check the pointer for alignment and validity. From a72a929b19875eaa459b79c398b7fff234e8b6ad Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Wed, 6 Apr 2022 23:04:15 +0200 Subject: [PATCH 2972/3747] Add test for FUTEX_WAIT_BITSET. --- tests/run-pass/concurrency/linux-futex.rs | 38 +++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/tests/run-pass/concurrency/linux-futex.rs b/tests/run-pass/concurrency/linux-futex.rs index 0f2a0236326b1..7ffe59e7a1bb4 100644 --- a/tests/run-pass/concurrency/linux-futex.rs +++ b/tests/run-pass/concurrency/linux-futex.rs @@ -7,6 +7,7 @@ #![feature(rustc_private)] extern crate libc; +use std::mem::MaybeUninit; use std::ptr; use std::thread; use std::time::{Duration, Instant}; @@ -93,6 +94,42 @@ fn wait_timeout() { assert!((200..1000).contains(&start.elapsed().as_millis())); } +fn wait_absolute_timeout() { + let start = Instant::now(); + + // Get the current monotonic timestamp as timespec. + let mut timeout = unsafe { + let mut now: MaybeUninit = MaybeUninit::uninit(); + assert_eq!(libc::clock_gettime(libc::CLOCK_MONOTONIC, now.as_mut_ptr()), 0); + now.assume_init() + }; + + // Add 200ms. + timeout.tv_nsec += 200_000_000; + if timeout.tv_nsec > 1_000_000_000 { + timeout.tv_nsec -= 1_000_000_000; + timeout.tv_sec += 1; + } + + let futex: i32 = 123; + + // Wait for 200ms from now, with nobody waking us up early. + unsafe { + assert_eq!(libc::syscall( + libc::SYS_futex, + &futex as *const i32, + libc::FUTEX_WAIT_BITSET, + 123, + &timeout, + 0, + u32::MAX, + ), -1); + assert_eq!(*libc::__errno_location(), libc::ETIMEDOUT); + } + + assert!((200..1000).contains(&start.elapsed().as_millis())); +} + fn wait_wake() { let start = Instant::now(); @@ -128,5 +165,6 @@ fn main() { wake_dangling(); wait_wrong_val(); wait_timeout(); + wait_absolute_timeout(); wait_wake(); } From 12c88886b0a2a112de8ab802447bdd2b48fdb795 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Wed, 6 Apr 2022 23:13:47 +0200 Subject: [PATCH 2973/3747] Formatting. --- src/shims/posix/linux/sync.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/shims/posix/linux/sync.rs b/src/shims/posix/linux/sync.rs index a4097bcd75fa4..cb1a9d74fa460 100644 --- a/src/shims/posix/linux/sync.rs +++ b/src/shims/posix/linux/sync.rs @@ -63,7 +63,9 @@ pub fn futex<'tcx>( let bitset = this.read_scalar(&args[6])?.to_u32()?; if bitset != u32::MAX { - throw_unsup_format!("Miri does not support `futex` syscall with `op=FUTEX_WAIT_BITSET` with a bitset other than UINT_MAX"); + throw_unsup_format!( + "Miri does not support `futex` syscall with `op=FUTEX_WAIT_BITSET` with a bitset other than UINT_MAX" + ); } } else { if args.len() < 5 { From 53ed500c92d95b0f7c5ab974573b0e7ca283d45e Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Wed, 6 Apr 2022 23:48:14 +0200 Subject: [PATCH 2974/3747] Fully support FUTEX_*_BITSET. --- src/shims/posix/linux/sync.rs | 50 ++++++++++++++++++++++++++--------- src/sync.rs | 16 ++++++----- 2 files changed, 48 insertions(+), 18 deletions(-) diff --git a/src/shims/posix/linux/sync.rs b/src/shims/posix/linux/sync.rs index cb1a9d74fa460..b0db9dd51f4fa 100644 --- a/src/shims/posix/linux/sync.rs +++ b/src/shims/posix/linux/sync.rs @@ -38,6 +38,7 @@ pub fn futex<'tcx>( let futex_wait = this.eval_libc_i32("FUTEX_WAIT")?; let futex_wait_bitset = this.eval_libc_i32("FUTEX_WAIT_BITSET")?; let futex_wake = this.eval_libc_i32("FUTEX_WAKE")?; + let futex_wake_bitset = this.eval_libc_i32("FUTEX_WAKE_BITSET")?; let futex_realtime = this.eval_libc_i32("FUTEX_CLOCK_REALTIME")?; // FUTEX_PRIVATE enables an optimization that stops it from working across processes. @@ -48,10 +49,14 @@ pub fn futex<'tcx>( // or *timeout expires. `timeout == null` for an infinite timeout. // // FUTEX_WAIT_BITSET: (int *addr, int op = FUTEX_WAIT_BITSET, int val, const timespec *timeout, int *_ignored, unsigned int bitset) - // When bitset is u32::MAX, this is identical to FUTEX_WAIT, except the timeout is absolute rather than relative. + // This is identical to FUTEX_WAIT, except: + // - The timeout is absolute rather than relative. + // - You can specify the bitset to selecting what WAKE operations to respond to. op if op & !futex_realtime == futex_wait || op & !futex_realtime == futex_wait_bitset => { let wait_bitset = op & !futex_realtime == futex_wait_bitset; + let bitset; + if wait_bitset { if args.len() != 7 { throw_ub_format!( @@ -59,14 +64,7 @@ pub fn futex<'tcx>( args.len() ); } - - let bitset = this.read_scalar(&args[6])?.to_u32()?; - - if bitset != u32::MAX { - throw_unsup_format!( - "Miri does not support `futex` syscall with `op=FUTEX_WAIT_BITSET` with a bitset other than UINT_MAX" - ); - } + bitset = this.read_scalar(&args[6])?.to_u32()?; } else { if args.len() < 5 { throw_ub_format!( @@ -74,6 +72,14 @@ pub fn futex<'tcx>( args.len() ); } + bitset = u32::MAX; + } + + if bitset == 0 { + let einval = this.eval_libc("EINVAL")?; + this.set_last_error(einval)?; + this.write_scalar(Scalar::from_machine_isize(-1, this), dest)?; + return Ok(()); } // `deref_operand` but not actually dereferencing the ptr yet (it might be NULL!). @@ -141,7 +147,7 @@ pub fn futex<'tcx>( if val == futex_val { // The value still matches, so we block the trait make it wait for FUTEX_WAKE. this.block_thread(thread); - this.futex_wait(addr_scalar.to_machine_usize(this)?, thread); + this.futex_wait(addr_scalar.to_machine_usize(this)?, thread, bitset); // Succesfully waking up from FUTEX_WAIT always returns zero. this.write_scalar(Scalar::from_machine_isize(0, this), dest)?; // Register a timeout callback if a timeout was specified. @@ -173,10 +179,30 @@ pub fn futex<'tcx>( // Wakes at most `val` threads waiting on the futex at `addr`. // Returns the amount of threads woken up. // Does not access the futex value at *addr. - op if op == futex_wake => { + // FUTEX_WAKE_BITSET: (int *addr, int op = FUTEX_WAKE, int val, const timespect *_unused, int *_unused, unsigned int bitset) + // Same as FUTEX_WAKE, but allows you to specify a bitset to select which threads to wake up. + op if op == futex_wake || op == futex_wake_bitset => { + let bitset; + if op == futex_wake_bitset { + if args.len() != 7 { + throw_ub_format!( + "incorrect number of arguments for `futex` syscall with `op=FUTEX_WAKE_BITSET`: got {}, expected 7", + args.len() + ); + } + bitset = this.read_scalar(&args[6])?.to_u32()?; + } else { + bitset = u32::MAX; + } + if bitset == 0 { + let einval = this.eval_libc("EINVAL")?; + this.set_last_error(einval)?; + this.write_scalar(Scalar::from_machine_isize(-1, this), dest)?; + return Ok(()); + } let mut n = 0; for _ in 0..val { - if let Some(thread) = this.futex_wake(addr_scalar.to_machine_usize(this)?) { + if let Some(thread) = this.futex_wake(addr_scalar.to_machine_usize(this)?, bitset) { this.unblock_thread(thread); this.unregister_timeout_callback_if_exists(thread); n += 1; diff --git a/src/sync.rs b/src/sync.rs index 44ea18f4055da..9007f25ce5c70 100644 --- a/src/sync.rs +++ b/src/sync.rs @@ -144,6 +144,8 @@ struct Futex { struct FutexWaiter { /// The thread that is waiting on this futex. thread: ThreadId, + /// The bitset used by FUTEX_*_BITSET, or u32::MAX for other operations. + bitset: u32, } /// The state of all synchronization variables. @@ -486,15 +488,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.machine.threads.sync.condvars[id].waiters.retain(|waiter| waiter.thread != thread); } - fn futex_wait(&mut self, addr: u64, thread: ThreadId) { + fn futex_wait(&mut self, addr: u64, thread: ThreadId, bitset: u32) { let this = self.eval_context_mut(); let futex = &mut this.machine.threads.sync.futexes.entry(addr).or_default(); let waiters = &mut futex.waiters; assert!(waiters.iter().all(|waiter| waiter.thread != thread), "thread is already waiting"); - waiters.push_back(FutexWaiter { thread }); + waiters.push_back(FutexWaiter { thread, bitset }); } - fn futex_wake(&mut self, addr: u64) -> Option { + fn futex_wake(&mut self, addr: u64, bitset: u32) -> Option { let this = self.eval_context_mut(); let current_thread = this.get_active_thread(); let futex = &mut this.machine.threads.sync.futexes.get_mut(&addr)?; @@ -504,13 +506,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if let Some(data_race) = data_race { data_race.validate_lock_release(&mut futex.data_race, current_thread); } - let res = futex.waiters.pop_front().map(|waiter| { + + // Wake up the first thread in the queue that matches any of the bits in the bitset. + futex.waiters.iter().position(|w| w.bitset & bitset != 0).map(|i| { + let waiter = futex.waiters.remove(i).unwrap(); if let Some(data_race) = data_race { data_race.validate_lock_acquire(&futex.data_race, waiter.thread); } waiter.thread - }); - res + }) } fn futex_remove_waiter(&mut self, addr: u64, thread: ThreadId) { From 5581e338067c5af7937f41d0b6ee55cfc8319cc0 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Wed, 6 Apr 2022 23:48:26 +0200 Subject: [PATCH 2975/3747] Add test for FUTEX_*_BITSET. --- tests/run-pass/concurrency/linux-futex.rs | 48 +++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/tests/run-pass/concurrency/linux-futex.rs b/tests/run-pass/concurrency/linux-futex.rs index 7ffe59e7a1bb4..fb7c022929bd7 100644 --- a/tests/run-pass/concurrency/linux-futex.rs +++ b/tests/run-pass/concurrency/linux-futex.rs @@ -160,6 +160,53 @@ fn wait_wake() { assert!((200..1000).contains(&start.elapsed().as_millis())); } +fn wait_wake_bitset() { + let start = Instant::now(); + + static FUTEX: i32 = 0; + + thread::spawn(move || { + thread::sleep(Duration::from_millis(200)); + unsafe { + assert_eq!(libc::syscall( + libc::SYS_futex, + &FUTEX as *const i32, + libc::FUTEX_WAKE_BITSET, + 10, // Wake up at most 10 threads. + 0, + 0, + 0b1001, // bitset + ), 0); // Didn't match any thread. + } + thread::sleep(Duration::from_millis(200)); + unsafe { + assert_eq!(libc::syscall( + libc::SYS_futex, + &FUTEX as *const i32, + libc::FUTEX_WAKE_BITSET, + 10, // Wake up at most 10 threads. + 0, + 0, + 0b0110, // bitset + ), 1); // Woken up one thread. + } + }); + + unsafe { + assert_eq!(libc::syscall( + libc::SYS_futex, + &FUTEX as *const i32, + libc::FUTEX_WAIT_BITSET, + 0, + ptr::null::(), + 0, + 0b0100, // bitset + ), 0); + } + + assert!((400..1000).contains(&start.elapsed().as_millis())); +} + fn main() { wake_nobody(); wake_dangling(); @@ -167,4 +214,5 @@ fn main() { wait_timeout(); wait_absolute_timeout(); wait_wake(); + wait_wake_bitset(); } From 03417de176f5f3811c5ba7782b9b547fe5be89a5 Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Wed, 6 Apr 2022 23:55:02 +0200 Subject: [PATCH 2976/3747] Use `let = if;` instead of `let; if`. --- src/shims/posix/linux/sync.rs | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/src/shims/posix/linux/sync.rs b/src/shims/posix/linux/sync.rs index b0db9dd51f4fa..9350ad6ba94d4 100644 --- a/src/shims/posix/linux/sync.rs +++ b/src/shims/posix/linux/sync.rs @@ -55,16 +55,14 @@ pub fn futex<'tcx>( op if op & !futex_realtime == futex_wait || op & !futex_realtime == futex_wait_bitset => { let wait_bitset = op & !futex_realtime == futex_wait_bitset; - let bitset; - - if wait_bitset { + let bitset = if wait_bitset { if args.len() != 7 { throw_ub_format!( "incorrect number of arguments for `futex` syscall with `op=FUTEX_WAIT_BITSET`: got {}, expected 7", args.len() ); } - bitset = this.read_scalar(&args[6])?.to_u32()?; + this.read_scalar(&args[6])?.to_u32()? } else { if args.len() < 5 { throw_ub_format!( @@ -72,8 +70,8 @@ pub fn futex<'tcx>( args.len() ); } - bitset = u32::MAX; - } + u32::MAX + }; if bitset == 0 { let einval = this.eval_libc("EINVAL")?; @@ -182,18 +180,17 @@ pub fn futex<'tcx>( // FUTEX_WAKE_BITSET: (int *addr, int op = FUTEX_WAKE, int val, const timespect *_unused, int *_unused, unsigned int bitset) // Same as FUTEX_WAKE, but allows you to specify a bitset to select which threads to wake up. op if op == futex_wake || op == futex_wake_bitset => { - let bitset; - if op == futex_wake_bitset { + let bitset = if op == futex_wake_bitset { if args.len() != 7 { throw_ub_format!( "incorrect number of arguments for `futex` syscall with `op=FUTEX_WAKE_BITSET`: got {}, expected 7", args.len() ); } - bitset = this.read_scalar(&args[6])?.to_u32()?; + this.read_scalar(&args[6])?.to_u32()? } else { - bitset = u32::MAX; - } + u32::MAX + }; if bitset == 0 { let einval = this.eval_libc("EINVAL")?; this.set_last_error(einval)?; From 4fdda315cc1d2175a1c49617eb342cdffe8c351f Mon Sep 17 00:00:00 2001 From: Mara Bos Date: Thu, 7 Apr 2022 00:02:20 +0200 Subject: [PATCH 2977/3747] Put 306ba8357fb36212b7d30efb9eb9e41659ac1445 in rust-version. --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index c84d46fa5142f..60b8609f73b46 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -f262ca12aac76152c4b46cefcf8300f0249a5eb2 +306ba8357fb36212b7d30efb9eb9e41659ac1445 From f2cfc928a52429e4be51565876ed5c2b6625ecc4 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 7 Apr 2022 08:35:29 -0400 Subject: [PATCH 2978/3747] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 60b8609f73b46..f08a8228d45fc 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -306ba8357fb36212b7d30efb9eb9e41659ac1445 +bbe9d27b8ff36da56638aa43d6d0cdfdf89a4e57 From e1556c857692b9595357a35bcd567f6761c2abc4 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 6 Apr 2022 18:30:25 -0400 Subject: [PATCH 2979/3747] add machine hook tcx parameters --- src/machine.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/machine.rs b/src/machine.rs index 9108f4f166631..9e0cb69f28d80 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -605,6 +605,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { #[inline(always)] fn memory_read( + _tcx: TyCtxt<'tcx>, machine: &Self, alloc_extra: &AllocExtra, tag: Tag, @@ -627,6 +628,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { #[inline(always)] fn memory_written( + _tcx: TyCtxt<'tcx>, machine: &mut Self, alloc_extra: &mut AllocExtra, tag: Tag, @@ -649,6 +651,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { #[inline(always)] fn memory_deallocated( + _tcx: TyCtxt<'tcx>, machine: &mut Self, alloc_extra: &mut AllocExtra, tag: Tag, From 59ee672fef55dda91c912286e614cd3dd2c82899 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 7 Apr 2022 15:27:57 -0400 Subject: [PATCH 2980/3747] for variadic functions, accept arbitrary trailing arguments but make sure we check all leading arguments --- src/shims/posix/fs.rs | 31 ++++++++++-------- src/shims/posix/linux/foreign_items.rs | 15 +++------ src/shims/posix/linux/sync.rs | 40 +++++++++++++---------- tests/run-pass/concurrency/linux-futex.rs | 16 ++++----- 4 files changed, 52 insertions(+), 50 deletions(-) diff --git a/src/shims/posix/fs.rs b/src/shims/posix/fs.rs index 288935576e0dd..11b9082da64d7 100644 --- a/src/shims/posix/fs.rs +++ b/src/shims/posix/fs.rs @@ -15,7 +15,6 @@ use rustc_middle::ty::{self, layout::LayoutOf}; use rustc_target::abi::{Align, Size}; use crate::*; -use helpers::check_arg_count; use shims::os_str::os_str_to_bytes; use shims::time::system_time_to_duration; @@ -479,16 +478,16 @@ fn maybe_sync_file( impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { fn open(&mut self, args: &[OpTy<'tcx, Tag>]) -> InterpResult<'tcx, i32> { - if args.len() < 2 || args.len() > 3 { + if args.len() < 2 { throw_ub_format!( - "incorrect number of arguments for `open`: got {}, expected 2 or 3", + "incorrect number of arguments for `open`: got {}, expected at least 2", args.len() ); } let this = self.eval_context_mut(); - let path_op = &args[0]; + let path = this.read_pointer(&args[0])?; let flag = this.read_scalar(&args[1])?.to_i32()?; let mut options = OpenOptions::new(); @@ -541,7 +540,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.read_scalar(arg)?.to_u32()? } else { throw_ub_format!( - "incorrect number of arguments for `open` with `O_CREAT`: got {}, expected 3", + "incorrect number of arguments for `open` with `O_CREAT`: got {}, expected at least 3", args.len() ); }; @@ -572,7 +571,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx throw_unsup_format!("unsupported flags {:#x}", flag & !mirror); } - let path = this.read_path_from_c_str(this.read_pointer(path_op)?)?; + let path = this.read_path_from_c_str(path)?; // Reject if isolation is enabled. if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { @@ -614,7 +613,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // `FD_CLOEXEC` value without checking if the flag is set for the file because `std` // always sets this flag when opening a file. However we still need to check that the // file itself is open. - let &[_, _] = check_arg_count(args)?; if this.machine.file_handler.handles.contains_key(&fd) { Ok(this.eval_libc_i32("FD_CLOEXEC")?) } else { @@ -627,8 +625,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // because exec() isn't supported. The F_DUPFD and F_DUPFD_CLOEXEC commands only // differ in whether the FD_CLOEXEC flag is pre-set on the new file descriptor, // thus they can share the same implementation here. - let &[_, _, ref start] = check_arg_count(args)?; - let start = this.read_scalar(start)?.to_i32()?; + if args.len() < 3 { + throw_ub_format!( + "incorrect number of arguments for fcntl with cmd=`F_DUPFD`/`F_DUPFD_CLOEXEC`: got {}, expected at least 3", + args.len() + ); + } + let start = this.read_scalar(&args[2])?.to_i32()?; let fh = &mut this.machine.file_handler; @@ -646,7 +649,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx None => return this.handle_not_found(), } } else if this.tcx.sess.target.os == "macos" && cmd == this.eval_libc_i32("F_FULLFSYNC")? { - let &[_, _] = check_arg_count(args)?; if let Some(file_descriptor) = this.machine.file_handler.handles.get(&fd) { // FIXME: Support fullfsync for all FDs let FileHandle { file, writable } = file_descriptor.as_file_handle()?; @@ -919,15 +921,18 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx dirfd_op: &OpTy<'tcx, Tag>, // Should be an `int` pathname_op: &OpTy<'tcx, Tag>, // Should be a `const char *` flags_op: &OpTy<'tcx, Tag>, // Should be an `int` - _mask_op: &OpTy<'tcx, Tag>, // Should be an `unsigned int` + mask_op: &OpTy<'tcx, Tag>, // Should be an `unsigned int` statxbuf_op: &OpTy<'tcx, Tag>, // Should be a `struct statx *` ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); this.assert_target_os("linux", "statx"); - let statxbuf_ptr = this.read_pointer(statxbuf_op)?; + let dirfd = this.read_scalar(dirfd_op)?.to_i32()?; let pathname_ptr = this.read_pointer(pathname_op)?; + let flags = this.read_scalar(flags_op)?.to_i32()?; + let _mask = this.read_scalar(mask_op)?.to_u32()?; + let statxbuf_ptr = this.read_pointer(statxbuf_op)?; // If the statxbuf or pathname pointers are null, the function fails with `EFAULT`. if this.ptr_is_null(statxbuf_ptr)? || this.ptr_is_null(pathname_ptr)? { @@ -953,9 +958,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let path = this.read_path_from_c_str(pathname_ptr)?.into_owned(); // See for a discussion of argument sizes. - let flags = this.read_scalar(flags_op)?.to_i32()?; let empty_path_flag = flags & this.eval_libc("AT_EMPTY_PATH")?.to_i32()? != 0; - let dirfd = this.read_scalar(dirfd_op)?.to_i32()?; // We only support: // * interpreting `path` as an absolute directory, // * interpreting `path` as a path relative to `dirfd` when the latter is `AT_FDCWD`, or diff --git a/src/shims/posix/linux/foreign_items.rs b/src/shims/posix/linux/foreign_items.rs index 280f24e9ea496..453c77f1b5342 100644 --- a/src/shims/posix/linux/foreign_items.rs +++ b/src/shims/posix/linux/foreign_items.rs @@ -130,16 +130,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // count is checked bellow. this.check_abi_and_shim_symbol_clash(abi, Abi::C { unwind: false }, link_name)?; // The syscall variadic function is legal to call with more arguments than needed, - // extra arguments are simply ignored. However, all arguments need to be scalars; - // other types might be treated differently by the calling convention. - for arg in args { - if !matches!(arg.layout.abi, rustc_target::abi::Abi::Scalar(_)) { - throw_ub_format!( - "`syscall` arguments must all have scalar layout, but {} does not", - arg.layout.ty - ); - } - } + // extra arguments are simply ignored. The important check is that when we use an + // argument, we have to also check all arguments *before* it to ensure that they + // have the right type. let sys_getrandom = this.eval_libc("SYS_getrandom")?.to_machine_usize(this)?; @@ -181,7 +174,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // `futex` is used by some synchonization primitives. id if id == sys_futex => { - futex(this, args, dest)?; + futex(this, &args[1..], dest)?; } id => { this.handle_unsupported(format!("can't execute syscall with ID {}", id))?; diff --git a/src/shims/posix/linux/sync.rs b/src/shims/posix/linux/sync.rs index 9350ad6ba94d4..362373bb7d3b3 100644 --- a/src/shims/posix/linux/sync.rs +++ b/src/shims/posix/linux/sync.rs @@ -4,6 +4,7 @@ use rustc_target::abi::{Align, Size}; use std::time::{Instant, SystemTime}; /// Implementation of the SYS_futex syscall. +/// `args` is the arguments *after* the syscall number. pub fn futex<'tcx>( this: &mut MiriEvalContext<'_, 'tcx>, args: &[OpTy<'tcx, Tag>], @@ -17,9 +18,9 @@ pub fn futex<'tcx>( // may or may not be left out from the `syscall()` call. // Therefore we don't use `check_arg_count` here, but only check for the // number of arguments to fall within a range. - if args.len() < 4 { + if args.len() < 3 { throw_ub_format!( - "incorrect number of arguments for `futex` syscall: got {}, expected at least 4", + "incorrect number of arguments for `futex` syscall: got {}, expected at least 3", args.len() ); } @@ -27,12 +28,13 @@ pub fn futex<'tcx>( // The first three arguments (after the syscall number itself) are the same to all futex operations: // (int *addr, int op, int val). // We checked above that these definitely exist. - let addr = this.read_immediate(&args[1])?; - let op = this.read_scalar(&args[2])?.to_i32()?; - let val = this.read_scalar(&args[3])?.to_i32()?; + let addr = this.read_immediate(&args[0])?; + let op = this.read_scalar(&args[1])?.to_i32()?; + let val = this.read_scalar(&args[2])?.to_i32()?; let thread = this.get_active_thread(); let addr_scalar = addr.to_scalar()?; + let addr_usize = addr_scalar.to_machine_usize(this)?; let futex_private = this.eval_libc_i32("FUTEX_PRIVATE_FLAG")?; let futex_wait = this.eval_libc_i32("FUTEX_WAIT")?; @@ -56,17 +58,19 @@ pub fn futex<'tcx>( let wait_bitset = op & !futex_realtime == futex_wait_bitset; let bitset = if wait_bitset { - if args.len() != 7 { + if args.len() < 6 { throw_ub_format!( - "incorrect number of arguments for `futex` syscall with `op=FUTEX_WAIT_BITSET`: got {}, expected 7", + "incorrect number of arguments for `futex` syscall with `op=FUTEX_WAIT_BITSET`: got {}, expected at least 6", args.len() ); } - this.read_scalar(&args[6])?.to_u32()? + let _timeout = this.read_pointer(&args[3])?; + let _uaddr2 = this.read_pointer(&args[4])?; + this.read_scalar(&args[5])?.to_u32()? } else { - if args.len() < 5 { + if args.len() < 4 { throw_ub_format!( - "incorrect number of arguments for `futex` syscall with `op=FUTEX_WAIT`: got {}, expected at least 5", + "incorrect number of arguments for `futex` syscall with `op=FUTEX_WAIT`: got {}, expected at least 4", args.len() ); } @@ -81,7 +85,7 @@ pub fn futex<'tcx>( } // `deref_operand` but not actually dereferencing the ptr yet (it might be NULL!). - let timeout = this.ref_to_mplace(&this.read_immediate(&args[4])?)?; + let timeout = this.ref_to_mplace(&this.read_immediate(&args[3])?)?; let timeout_time = if this.ptr_is_null(timeout.ptr)? { None } else { @@ -145,7 +149,7 @@ pub fn futex<'tcx>( if val == futex_val { // The value still matches, so we block the trait make it wait for FUTEX_WAKE. this.block_thread(thread); - this.futex_wait(addr_scalar.to_machine_usize(this)?, thread, bitset); + this.futex_wait(addr_usize, thread, bitset); // Succesfully waking up from FUTEX_WAIT always returns zero. this.write_scalar(Scalar::from_machine_isize(0, this), dest)?; // Register a timeout callback if a timeout was specified. @@ -157,7 +161,7 @@ pub fn futex<'tcx>( timeout_time, Box::new(move |this| { this.unblock_thread(thread); - this.futex_remove_waiter(addr_scalar.to_machine_usize(this)?, thread); + this.futex_remove_waiter(addr_usize, thread); let etimedout = this.eval_libc("ETIMEDOUT")?; this.set_last_error(etimedout)?; this.write_scalar(Scalar::from_machine_isize(-1, this), &dest)?; @@ -181,13 +185,15 @@ pub fn futex<'tcx>( // Same as FUTEX_WAKE, but allows you to specify a bitset to select which threads to wake up. op if op == futex_wake || op == futex_wake_bitset => { let bitset = if op == futex_wake_bitset { - if args.len() != 7 { + if args.len() < 6 { throw_ub_format!( - "incorrect number of arguments for `futex` syscall with `op=FUTEX_WAKE_BITSET`: got {}, expected 7", + "incorrect number of arguments for `futex` syscall with `op=FUTEX_WAKE_BITSET`: got {}, expected at least 6", args.len() ); } - this.read_scalar(&args[6])?.to_u32()? + let _timeout = this.read_pointer(&args[3])?; + let _uaddr2 = this.read_pointer(&args[4])?; + this.read_scalar(&args[5])?.to_u32()? } else { u32::MAX }; @@ -199,7 +205,7 @@ pub fn futex<'tcx>( } let mut n = 0; for _ in 0..val { - if let Some(thread) = this.futex_wake(addr_scalar.to_machine_usize(this)?, bitset) { + if let Some(thread) = this.futex_wake(addr_usize, bitset) { this.unblock_thread(thread); this.unregister_timeout_callback_if_exists(thread); n += 1; diff --git a/tests/run-pass/concurrency/linux-futex.rs b/tests/run-pass/concurrency/linux-futex.rs index fb7c022929bd7..4ac928398e238 100644 --- a/tests/run-pass/concurrency/linux-futex.rs +++ b/tests/run-pass/concurrency/linux-futex.rs @@ -32,8 +32,8 @@ fn wake_nobody() { &futex as *const i32, libc::FUTEX_WAKE, 1, - 0, - 0, + ptr::null::(), + 0usize, 0, ), 0); } @@ -121,7 +121,7 @@ fn wait_absolute_timeout() { libc::FUTEX_WAIT_BITSET, 123, &timeout, - 0, + 0usize, u32::MAX, ), -1); assert_eq!(*libc::__errno_location(), libc::ETIMEDOUT); @@ -173,8 +173,8 @@ fn wait_wake_bitset() { &FUTEX as *const i32, libc::FUTEX_WAKE_BITSET, 10, // Wake up at most 10 threads. - 0, - 0, + ptr::null::(), + 0usize, 0b1001, // bitset ), 0); // Didn't match any thread. } @@ -185,8 +185,8 @@ fn wait_wake_bitset() { &FUTEX as *const i32, libc::FUTEX_WAKE_BITSET, 10, // Wake up at most 10 threads. - 0, - 0, + ptr::null::(), + 0usize, 0b0110, // bitset ), 1); // Woken up one thread. } @@ -199,7 +199,7 @@ fn wait_wake_bitset() { libc::FUTEX_WAIT_BITSET, 0, ptr::null::(), - 0, + 0usize, 0b0100, // bitset ), 0); } From cac48dd734434ff3f9a53f78b54eebd9020f2a18 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 7 Apr 2022 16:14:50 -0400 Subject: [PATCH 2981/3747] treat prctl like a variadic function --- src/shims/posix/fs.rs | 2 +- src/shims/posix/linux/foreign_items.rs | 6 ++-- src/shims/posix/thread.rs | 36 +++++++++++++------ .../fs/unix_open_missing_required_mode.rs | 2 +- .../fs/unix_open_too_many_args.rs | 16 --------- 5 files changed, 30 insertions(+), 32 deletions(-) delete mode 100644 tests/compile-fail/fs/unix_open_too_many_args.rs diff --git a/src/shims/posix/fs.rs b/src/shims/posix/fs.rs index 11b9082da64d7..5395d0f0bf112 100644 --- a/src/shims/posix/fs.rs +++ b/src/shims/posix/fs.rs @@ -921,7 +921,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx dirfd_op: &OpTy<'tcx, Tag>, // Should be an `int` pathname_op: &OpTy<'tcx, Tag>, // Should be a `const char *` flags_op: &OpTy<'tcx, Tag>, // Should be an `int` - mask_op: &OpTy<'tcx, Tag>, // Should be an `unsigned int` + mask_op: &OpTy<'tcx, Tag>, // Should be an `unsigned int` statxbuf_op: &OpTy<'tcx, Tag>, // Should be a `struct statx *` ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); diff --git a/src/shims/posix/linux/foreign_items.rs b/src/shims/posix/linux/foreign_items.rs index 453c77f1b5342..339fb04dae337 100644 --- a/src/shims/posix/linux/foreign_items.rs +++ b/src/shims/posix/linux/foreign_items.rs @@ -106,9 +106,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Threading "prctl" => { - let &[ref option, ref arg2, ref arg3, ref arg4, ref arg5] = - this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; - let result = this.prctl(option, arg2, arg3, arg4, arg5)?; + // prctl is variadic. (It is not documented like that in the manpage, but defined like that in the libc crate.) + this.check_abi_and_shim_symbol_clash(abi, Abi::C { unwind: false }, link_name)?; + let result = this.prctl(args)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_condattr_setclock" => { diff --git a/src/shims/posix/thread.rs b/src/shims/posix/thread.rs index 58d48028f62cb..69875a9ffc44b 100644 --- a/src/shims/posix/thread.rs +++ b/src/shims/posix/thread.rs @@ -97,20 +97,27 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_uint(thread_id.to_u32(), dest.layout.size), dest) } - fn prctl( - &mut self, - option: &OpTy<'tcx, Tag>, - arg2: &OpTy<'tcx, Tag>, - _arg3: &OpTy<'tcx, Tag>, - _arg4: &OpTy<'tcx, Tag>, - _arg5: &OpTy<'tcx, Tag>, - ) -> InterpResult<'tcx, i32> { + fn prctl(&mut self, args: &[OpTy<'tcx, Tag>]) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); this.assert_target_os("linux", "prctl"); - let option = this.read_scalar(option)?.to_i32()?; + if args.len() < 1 { + throw_ub_format!( + "incorrect number of arguments for `prctl`: got {}, expected at least 1", + args.len() + ); + } + + let option = this.read_scalar(&args[0])?.to_i32()?; if option == this.eval_libc_i32("PR_SET_NAME")? { - let address = this.read_pointer(arg2)?; + if args.len() < 2 { + throw_ub_format!( + "incorrect number of arguments for `prctl` with `PR_SET_NAME`: got {}, expected at least 2", + args.len() + ); + } + + let address = this.read_pointer(&args[1])?; let mut name = this.read_c_str(address)?.to_owned(); // The name should be no more than 16 bytes, including the null // byte. Since `read_c_str` returns the string without the null @@ -118,7 +125,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx name.truncate(15); this.set_active_thread_name(name); } else if option == this.eval_libc_i32("PR_GET_NAME")? { - let address = this.read_pointer(arg2)?; + if args.len() < 2 { + throw_ub_format!( + "incorrect number of arguments for `prctl` with `PR_SET_NAME`: got {}, expected at least 2", + args.len() + ); + } + + let address = this.read_pointer(&args[1])?; let mut name = this.get_active_thread_name().to_vec(); name.push(0u8); assert!(name.len() <= 16); diff --git a/tests/compile-fail/fs/unix_open_missing_required_mode.rs b/tests/compile-fail/fs/unix_open_missing_required_mode.rs index 2bac72912544a..bd2ae6094be18 100644 --- a/tests/compile-fail/fs/unix_open_missing_required_mode.rs +++ b/tests/compile-fail/fs/unix_open_missing_required_mode.rs @@ -12,5 +12,5 @@ fn main() { fn test_file_open_missing_needed_mode() { let name = b"missing_arg.txt\0"; let name_ptr = name.as_ptr().cast::(); - let _fd = unsafe { libc::open(name_ptr, libc::O_CREAT) }; //~ ERROR Undefined Behavior: incorrect number of arguments for `open` with `O_CREAT`: got 2, expected 3 + let _fd = unsafe { libc::open(name_ptr, libc::O_CREAT) }; //~ ERROR Undefined Behavior: incorrect number of arguments for `open` with `O_CREAT`: got 2, expected at least 3 } diff --git a/tests/compile-fail/fs/unix_open_too_many_args.rs b/tests/compile-fail/fs/unix_open_too_many_args.rs deleted file mode 100644 index 9df7415d3133a..0000000000000 --- a/tests/compile-fail/fs/unix_open_too_many_args.rs +++ /dev/null @@ -1,16 +0,0 @@ -// ignore-windows: No libc on Windows -// compile-flags: -Zmiri-disable-isolation - -#![feature(rustc_private)] - -extern crate libc; - -fn main() { - test_open_too_many_args(); -} - -fn test_open_too_many_args() { - let name = b"too_many_args.txt\0"; - let name_ptr = name.as_ptr().cast::(); - let _fd = unsafe { libc::open(name_ptr, libc::O_RDONLY, 0, 0) }; //~ ERROR Undefined Behavior: incorrect number of arguments for `open`: got 4, expected 2 or 3 -} From c8553d8162709879bd215e8444335f0a58f8b085 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 7 Apr 2022 15:03:57 -0400 Subject: [PATCH 2982/3747] fix Windows stdout/stderr --- src/shims/windows/dlsym.rs | 82 ++++++++++++++++++++++++++++-- src/shims/windows/foreign_items.rs | 60 +++++++--------------- tests/run-pass/vecdeque.rs | 2 +- 3 files changed, 96 insertions(+), 48 deletions(-) diff --git a/src/shims/windows/dlsym.rs b/src/shims/windows/dlsym.rs index 325100bdb3a7d..ac9e085b5d7c9 100644 --- a/src/shims/windows/dlsym.rs +++ b/src/shims/windows/dlsym.rs @@ -1,10 +1,16 @@ use rustc_middle::mir; +use rustc_target::abi::Size; use rustc_target::spec::abi::Abi; +use log::trace; + +use crate::helpers::check_arg_count; use crate::*; #[derive(Debug, Copy, Clone)] -pub enum Dlsym {} +pub enum Dlsym { + NtWriteFile, +} impl Dlsym { // Returns an error for unsupported symbols, and None if this symbol @@ -12,6 +18,7 @@ impl Dlsym { pub fn from_str(name: &str) -> InterpResult<'static, Option> { Ok(match name { "GetSystemTimePreciseAsFileTime" => None, + "NtWriteFile" => Some(Dlsym::NtWriteFile), _ => throw_unsup_format!("unsupported Windows dlsym: {}", name), }) } @@ -23,15 +30,82 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx &mut self, dlsym: Dlsym, abi: Abi, - _args: &[OpTy<'tcx, Tag>], + args: &[OpTy<'tcx, Tag>], ret: Option<(&PlaceTy<'tcx, Tag>, mir::BasicBlock)>, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - let (_dest, _ret) = ret.expect("we don't support any diverging dlsym"); + let (dest, ret) = ret.expect("we don't support any diverging dlsym"); assert!(this.tcx.sess.target.os == "windows"); this.check_abi(abi, Abi::System { unwind: false })?; - match dlsym {} + match dlsym { + Dlsym::NtWriteFile => { + if !this.frame_in_std() { + throw_unsup_format!( + "NtWriteFile support is crude and just enough for stdout to work" + ); + } + + let &[ + ref handle, + ref _event, + ref _apc_routine, + ref _apc_context, + ref io_status_block, + ref buf, + ref n, + ref byte_offset, + ref _key, + ] = check_arg_count(args)?; + let handle = this.read_scalar(handle)?.to_machine_isize(this)?; + let buf = this.read_pointer(buf)?; + let n = this.read_scalar(n)?.to_u32()?; + let byte_offset = this.read_scalar(byte_offset)?.to_machine_usize(this)?; // is actually a pointer + let io_status_block = this.deref_operand(io_status_block)?; + + if byte_offset != 0 { + throw_unsup_format!( + "NtWriteFile ByteOffset paremeter is non-null, which is unsupported" + ); + } + + let written = if handle == -11 || handle == -12 { + // stdout/stderr + use std::io::{self, Write}; + + let buf_cont = this.read_bytes_ptr(buf, Size::from_bytes(u64::from(n)))?; + let res = if handle == -11 { + io::stdout().write(buf_cont) + } else { + io::stderr().write(buf_cont) + }; + res.ok().map(|n| n as u32) + } else { + throw_unsup_format!( + "on Windows, writing to anything except stdout/stderr is not supported" + ) + }; + // We have to put the result into io_status_block. + if let Some(n) = written { + let io_status_information = + this.mplace_field_named(&io_status_block, "Information")?; + this.write_scalar( + Scalar::from_machine_usize(n.into(), this), + &io_status_information.into(), + )?; + } + // Return whether this was a success. >= 0 is success. + // For the error code we arbitrarily pick 0xC0000185, STATUS_IO_DEVICE_ERROR. + this.write_scalar( + Scalar::from_i32(if written.is_some() { 0 } else { 0xC0000185u32 as i32 }), + dest, + )?; + } + } + + trace!("{:?}", this.dump_place(**dest)); + this.go_to_block(ret); + Ok(()) } } diff --git a/src/shims/windows/foreign_items.rs b/src/shims/windows/foreign_items.rs index 82ac5c5d75c43..d72302794318e 100644 --- a/src/shims/windows/foreign_items.rs +++ b/src/shims/windows/foreign_items.rs @@ -23,6 +23,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Windows API stubs. // HANDLE = isize + // NTSTATUS = LONH = i32 // DWORD = ULONG = u32 // BOOL = i32 // BOOLEAN = u8 @@ -64,49 +65,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_i32(result), dest)?; } - // File related shims - "GetStdHandle" => { - let &[ref which] = - this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; - let which = this.read_scalar(which)?.to_i32()?; - // We just make this the identity function, so we know later in `WriteFile` - // which one it is. - this.write_scalar(Scalar::from_machine_isize(which.into(), this), dest)?; - } - "WriteFile" => { - let &[ref handle, ref buf, ref n, ref written_ptr, ref overlapped] = - this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; - this.read_scalar(overlapped)?.to_machine_usize(this)?; // this is a poiner, that we ignore - let handle = this.read_scalar(handle)?.to_machine_isize(this)?; - let buf = this.read_pointer(buf)?; - let n = this.read_scalar(n)?.to_u32()?; - let written_place = this.deref_operand(written_ptr)?; - // Spec says to always write `0` first. - this.write_null(&written_place.into())?; - let written = if handle == -11 || handle == -12 { - // stdout/stderr - use std::io::{self, Write}; - - let buf_cont = this.read_bytes_ptr(buf, Size::from_bytes(u64::from(n)))?; - let res = if handle == -11 { - io::stdout().write(buf_cont) - } else { - io::stderr().write(buf_cont) - }; - res.ok().map(|n| n as u32) - } else { - throw_unsup_format!( - "on Windows, writing to anything except stdout/stderr is not supported" - ) - }; - // If there was no error, write back how much was written. - if let Some(n) = written { - this.write_scalar(Scalar::from_u32(n), &written_place.into())?; - } - // Return whether this was a success. - this.write_scalar(Scalar::from_i32(if written.is_some() { 1 } else { 0 }), dest)?; - } - // Allocation "HeapAlloc" => { let &[ref handle, ref flags, ref size] = @@ -333,6 +291,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // value if this call does result in switching to another thread. this.write_null(dest)?; } + "GetStdHandle" => { + let &[ref which] = + this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; + let which = this.read_scalar(which)?.to_i32()?; + // We just make this the identity function, so we know later in `NtWriteFile` which + // one it is. This is very fake, but libtest needs it so we cannot make it a + // std-only shim. + this.write_scalar(Scalar::from_machine_isize(which.into(), this), dest)?; + } // Better error for attempts to create a thread "CreateThread" => { @@ -350,6 +317,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Just fake a HANDLE this.write_scalar(Scalar::from_machine_isize(1, this), dest)?; } + "GetModuleHandleA" if this.frame_in_std() => { + #[allow(non_snake_case)] + let &[_lpModuleName] = + this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; + // We need to return something non-null here to make `compat_fn!` work. + this.write_scalar(Scalar::from_machine_isize(1, this), dest)?; + } "SetConsoleTextAttribute" if this.frame_in_std() => { #[allow(non_snake_case)] let &[ref _hConsoleOutput, ref _wAttribute] = diff --git a/tests/run-pass/vecdeque.rs b/tests/run-pass/vecdeque.rs index 0cba0165cae16..fa6707632dc76 100644 --- a/tests/run-pass/vecdeque.rs +++ b/tests/run-pass/vecdeque.rs @@ -26,7 +26,7 @@ fn main() { assert_eq!(**a, 2); } - // Regression test for Debug and Diaplay impl's + // Regression test for Debug impl's println!("{:?} {:?}", dst, dst.iter()); println!("{:?}", VecDeque::::new().iter()); From 363f8ab745e4dc1db105a6e7513fb77dd8ad3550 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 7 Apr 2022 16:39:18 -0400 Subject: [PATCH 2983/3747] thread name setting works with strict provenance now :) --- tests/run-pass/concurrency/simple.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/run-pass/concurrency/simple.rs b/tests/run-pass/concurrency/simple.rs index c659cfbc3fdc2..40d8802472aca 100644 --- a/tests/run-pass/concurrency/simple.rs +++ b/tests/run-pass/concurrency/simple.rs @@ -1,5 +1,5 @@ // ignore-windows: Concurrency on Windows is not supported yet. -// compile-flags: -Zmiri-check-number-validity +// compile-flags: -Zmiri-strict-provenance use std::thread; From 3a59a15af718339675273b397b822ef1e3f4290b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 8 Apr 2022 08:01:19 -0400 Subject: [PATCH 2984/3747] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index f08a8228d45fc..1f717dbd6ed54 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -bbe9d27b8ff36da56638aa43d6d0cdfdf89a4e57 +1a4b9a85634c17a60e8802307510c300a35a4b9b From d2cb11cc152056b6fa682c9925972600c4606d54 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 9 Apr 2022 09:41:29 -0400 Subject: [PATCH 2985/3747] rustup --- rust-version | 2 +- src/operator.rs | 2 +- src/shims/panic.rs | 2 +- src/shims/posix/linux/sync.rs | 2 +- src/shims/tls.rs | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/rust-version b/rust-version index 1f717dbd6ed54..0866489745acd 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -1a4b9a85634c17a60e8802307510c300a35a4b9b +fbdb10f9fabe47eb763cb4b52b5721740cc63783 diff --git a/src/operator.rs b/src/operator.rs index 59099469a3322..61c72270e9f7e 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -61,7 +61,7 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { let pointee_ty = left.layout.ty.builtin_deref(true).expect("Offset called on non-ptr type").ty; let ptr = self.ptr_offset_inbounds( - self.scalar_to_ptr(left.to_scalar()?), + self.scalar_to_ptr(left.to_scalar()?)?, pointee_ty, right.to_scalar()?.to_machine_isize(self)?, )?; diff --git a/src/shims/panic.rs b/src/shims/panic.rs index 4190cccae6d0c..8f4e3f578ee94 100644 --- a/src/shims/panic.rs +++ b/src/shims/panic.rs @@ -146,7 +146,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Push the `catch_fn` stackframe. let f_instance = - this.get_ptr_fn(this.scalar_to_ptr(catch_unwind.catch_fn))?.as_instance()?; + this.get_ptr_fn(this.scalar_to_ptr(catch_unwind.catch_fn)?)?.as_instance()?; trace!("catch_fn: {:?}", f_instance); let ret_place = MPlaceTy::dangling(this.machine.layouts.unit).into(); this.call_function( diff --git a/src/shims/posix/linux/sync.rs b/src/shims/posix/linux/sync.rs index 362373bb7d3b3..72898baa4b0a4 100644 --- a/src/shims/posix/linux/sync.rs +++ b/src/shims/posix/linux/sync.rs @@ -121,7 +121,7 @@ pub fn futex<'tcx>( // The API requires `addr` to be a 4-byte aligned pointer, and will // use the 4 bytes at the given address as an (atomic) i32. this.check_ptr_access_align( - this.scalar_to_ptr(addr_scalar), + this.scalar_to_ptr(addr_scalar)?, Size::from_bytes(4), Align::from_bytes(4).unwrap(), CheckInAllocMsg::MemoryAccessTest, diff --git a/src/shims/tls.rs b/src/shims/tls.rs index 297d0c1228a48..ceed123c7ac43 100644 --- a/src/shims/tls.rs +++ b/src/shims/tls.rs @@ -249,7 +249,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "p_thread_callback", ])?; let thread_callback = - this.get_ptr_fn(this.scalar_to_ptr(thread_callback))?.as_instance()?; + this.get_ptr_fn(this.scalar_to_ptr(thread_callback)?)?.as_instance()?; // The signature of this function is `unsafe extern "system" fn(h: c::LPVOID, dwReason: c::DWORD, pv: c::LPVOID)`. let reason = this.eval_path_scalar(&["std", "sys", "windows", "c", "DLL_THREAD_DETACH"])?; From af3f683ba64c4ef3caf9b43a79a8125f2d72b24d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 9 Apr 2022 11:16:50 -0400 Subject: [PATCH 2986/3747] port Miri to edition 2021 --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 540eeabebb7a3..4956a8dffd497 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,7 +6,7 @@ name = "miri" repository = "https://github.com/rust-lang/miri" version = "0.1.0" default-run = "miri" -edition = "2018" +edition = "2021" [lib] test = true # we have unit tests From a57c30118a001678295396852fe044ce7b0031eb Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 9 Apr 2022 11:17:16 -0400 Subject: [PATCH 2987/3747] port cargo-miri to edition 2021 --- cargo-miri/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cargo-miri/Cargo.toml b/cargo-miri/Cargo.toml index 7789a8a89594a..eb926525305c3 100644 --- a/cargo-miri/Cargo.toml +++ b/cargo-miri/Cargo.toml @@ -5,7 +5,7 @@ license = "MIT OR Apache-2.0" name = "cargo-miri" repository = "https://github.com/rust-lang/miri" version = "0.1.0" -edition = "2018" +edition = "2021" [[bin]] name = "cargo-miri" From 855af088b8567bc20805e544b8e38f67b409702a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 9 Apr 2022 11:20:32 -0400 Subject: [PATCH 2988/3747] remove no longer needed imports --- src/bin/miri.rs | 1 - src/eval.rs | 1 - src/helpers.rs | 1 - src/shims/backtrace.rs | 1 - src/shims/env.rs | 1 - src/shims/foreign_items.rs | 6 +----- src/shims/intrinsics.rs | 1 - src/shims/os_str.rs | 1 - src/shims/posix/fs.rs | 1 - src/shims/posix/thread.rs | 2 -- src/shims/time.rs | 1 - src/sync.rs | 1 - src/thread.rs | 1 - src/vector_clock.rs | 2 +- 14 files changed, 2 insertions(+), 19 deletions(-) diff --git a/src/bin/miri.rs b/src/bin/miri.rs index be4776f459cd4..727e0b717b11e 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -9,7 +9,6 @@ extern crate rustc_metadata; extern crate rustc_middle; extern crate rustc_session; -use std::convert::TryFrom; use std::env; use std::num::NonZeroU64; use std::path::PathBuf; diff --git a/src/eval.rs b/src/eval.rs index 4c006867e1772..5f829525cc572 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -1,6 +1,5 @@ //! Main evaluator loop and setting up the initial stack frame. -use std::convert::TryFrom; use std::ffi::OsStr; use std::iter; diff --git a/src/helpers.rs b/src/helpers.rs index 9e4527d592b37..5b6e616400b42 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -1,4 +1,3 @@ -use std::convert::{TryFrom, TryInto}; use std::mem; use std::num::NonZeroUsize; use std::time::Duration; diff --git a/src/shims/backtrace.rs b/src/shims/backtrace.rs index 32fbbffc63f8e..2ec4bbb32e029 100644 --- a/src/shims/backtrace.rs +++ b/src/shims/backtrace.rs @@ -4,7 +4,6 @@ use rustc_middle::ty::layout::LayoutOf as _; use rustc_middle::ty::{self, Instance}; use rustc_span::{BytePos, Loc, Symbol}; use rustc_target::{abi::Size, spec::abi::Abi}; -use std::convert::TryInto as _; impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { diff --git a/src/shims/env.rs b/src/shims/env.rs index 7be26de45916a..3b1b1f011e3e7 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -1,4 +1,3 @@ -use std::convert::TryFrom; use std::env; use std::ffi::{OsStr, OsString}; use std::io::ErrorKind; diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 77567e9bcae59..7b457e9ed79a8 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -1,8 +1,4 @@ -use std::{ - collections::hash_map::Entry, - convert::{TryFrom, TryInto}, - iter, -}; +use std::{collections::hash_map::Entry, iter}; use log::trace; diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 9101cbcf05ff4..58e546d6b0b01 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -1,4 +1,3 @@ -use std::convert::TryInto; use std::iter; use log::trace; diff --git a/src/shims/os_str.rs b/src/shims/os_str.rs index c03f7ad79be73..8db75fed4a5f3 100644 --- a/src/shims/os_str.rs +++ b/src/shims/os_str.rs @@ -1,5 +1,4 @@ use std::borrow::Cow; -use std::convert::TryFrom; use std::ffi::{OsStr, OsString}; use std::iter; use std::path::{Path, PathBuf}; diff --git a/src/shims/posix/fs.rs b/src/shims/posix/fs.rs index 5395d0f0bf112..73e21dd57dc40 100644 --- a/src/shims/posix/fs.rs +++ b/src/shims/posix/fs.rs @@ -1,6 +1,5 @@ use std::borrow::Cow; use std::collections::BTreeMap; -use std::convert::{TryFrom, TryInto}; use std::fs::{ read_dir, remove_dir, remove_file, rename, DirBuilder, File, FileType, OpenOptions, ReadDir, }; diff --git a/src/shims/posix/thread.rs b/src/shims/posix/thread.rs index 69875a9ffc44b..7840a1e1e9708 100644 --- a/src/shims/posix/thread.rs +++ b/src/shims/posix/thread.rs @@ -1,5 +1,3 @@ -use std::convert::TryInto; - use crate::*; use rustc_middle::ty::layout::LayoutOf; use rustc_target::spec::abi::Abi; diff --git a/src/shims/time.rs b/src/shims/time.rs index 0acd697fa4050..78bf6f59b3499 100644 --- a/src/shims/time.rs +++ b/src/shims/time.rs @@ -1,4 +1,3 @@ -use std::convert::TryFrom; use std::time::{Duration, Instant, SystemTime}; use crate::*; diff --git a/src/sync.rs b/src/sync.rs index 9007f25ce5c70..bbcd39333c780 100644 --- a/src/sync.rs +++ b/src/sync.rs @@ -1,5 +1,4 @@ use std::collections::{hash_map::Entry, HashMap, VecDeque}; -use std::convert::TryFrom; use std::num::NonZeroU32; use std::ops::Not; diff --git a/src/thread.rs b/src/thread.rs index 2c5f6c2391f05..96131dba3ca6a 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -2,7 +2,6 @@ use std::cell::RefCell; use std::collections::hash_map::Entry; -use std::convert::TryFrom; use std::num::TryFromIntError; use std::time::{Duration, Instant, SystemTime}; diff --git a/src/vector_clock.rs b/src/vector_clock.rs index 74180f25b3bbe..e13e9c39fc69c 100644 --- a/src/vector_clock.rs +++ b/src/vector_clock.rs @@ -1,6 +1,6 @@ use rustc_index::vec::Idx; use smallvec::SmallVec; -use std::{cmp::Ordering, convert::TryFrom, fmt::Debug, ops::Index}; +use std::{cmp::Ordering, fmt::Debug, ops::Index}; /// A vector clock index, this is associated with a thread id /// but in some cases one vector index may be shared with From 507c09f45f0e32b7868b2bf38a3a046d93311e38 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 9 Apr 2022 11:22:18 -0400 Subject: [PATCH 2989/3747] use new format string syntax in some places --- src/diagnostics.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/diagnostics.rs b/src/diagnostics.rs index e1a2e3184ebfa..ce66dea5e746f 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -414,11 +414,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) } }, - CreatedCallId(id) => format!("function call with id {}", id), - CreatedAlloc(AllocId(id)) => format!("created allocation with id {}", id), - FreedAlloc(AllocId(id)) => format!("freed allocation with id {}", id), + CreatedCallId(id) => format!("function call with id {id}"), + CreatedAlloc(AllocId(id)) => format!("created allocation with id {id}"), + FreedAlloc(AllocId(id)) => format!("freed allocation with id {id}"), RejectedIsolatedOp(ref op) => - format!("{} was made to return an error due to isolation", op), + format!("{op} was made to return an error due to isolation"), }; let (title, diag_level) = match e { From ebb70da4c66dba4a0e036377b3cc19cc41f92e9a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 10 Apr 2022 09:36:30 -0400 Subject: [PATCH 2990/3747] rustup --- rust-version | 2 +- tests/run-pass/concurrency/channels.rs | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 0866489745acd..34bc4a8038788 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -fbdb10f9fabe47eb763cb4b52b5721740cc63783 +7af93292c27cd8b4a14f0f35bcb4c7e7ca9c287a diff --git a/tests/run-pass/concurrency/channels.rs b/tests/run-pass/concurrency/channels.rs index 7d28cd726d0e2..b0c095b2d3598 100644 --- a/tests/run-pass/concurrency/channels.rs +++ b/tests/run-pass/concurrency/channels.rs @@ -1,4 +1,5 @@ // ignore-windows: Concurrency on Windows is not supported yet. +// compile-flags: -Zmiri-strict-provenance use std::sync::mpsc::{channel, sync_channel}; use std::thread; From 3f1d3aedcdddd26a07d436e8db870f868075b55a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 10 Apr 2022 11:23:56 -0400 Subject: [PATCH 2991/3747] increase slack for timeout test --- tests/run-pass/concurrency/sync.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/run-pass/concurrency/sync.rs b/tests/run-pass/concurrency/sync.rs index 5e43fea968641..303d49e3c33fe 100644 --- a/tests/run-pass/concurrency/sync.rs +++ b/tests/run-pass/concurrency/sync.rs @@ -91,7 +91,7 @@ fn check_conditional_variables_timed_wait_timeout() { let (_guard, timeout) = cvar.wait_timeout(guard, Duration::from_millis(100)).unwrap(); assert!(timeout.timed_out()); let elapsed_time = now.elapsed().as_millis(); - assert!(100 <= elapsed_time && elapsed_time <= 500); + assert!(100 <= elapsed_time && elapsed_time <= 800); } /// Test that signaling a conditional variable when waiting with a timeout works From 0669b227596969c1c2f6b6315d1d05e1f4c6a60d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 16 Apr 2022 08:41:34 -0400 Subject: [PATCH 2992/3747] rustup --- rust-version | 2 +- src/shims/intrinsics.rs | 21 +++++++++++++++++---- tests/run-pass/portable-simd.rs | 1 + 3 files changed, 19 insertions(+), 5 deletions(-) diff --git a/rust-version b/rust-version index 34bc4a8038788..d476da0baaf87 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -7af93292c27cd8b4a14f0f35bcb4c7e7ca9c287a +c8422403f775126c40d558838d321c063554c822 diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 58e546d6b0b01..1b69be5153b06 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -437,7 +437,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "simd_fmax" | "simd_fmin" | "simd_saturating_add" - | "simd_saturating_sub" => { + | "simd_saturating_sub" + | "simd_arith_offset" => { use mir::BinOp; let &[ref left, ref right] = check_arg_count(args)?; @@ -453,6 +454,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx SaturatingOp(BinOp), FMax, FMin, + WrappingOffset, } let which = match intrinsic_name { "simd_add" => Op::MirOp(BinOp::Add), @@ -475,6 +477,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "simd_fmin" => Op::FMin, "simd_saturating_add" => Op::SaturatingOp(BinOp::Add), "simd_saturating_sub" => Op::SaturatingOp(BinOp::Sub), + "simd_arith_offset" => Op::WrappingOffset, _ => unreachable!(), }; @@ -504,15 +507,25 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx val } } + Op::SaturatingOp(mir_op) => { + this.saturating_arith(mir_op, &left, &right)? + } + Op::WrappingOffset => { + let ptr = this.scalar_to_ptr(left.to_scalar()?)?; + let offset_count = right.to_scalar()?.to_machine_isize(this)?; + let pointee_ty = left.layout.ty.builtin_deref(true).unwrap().ty; + + let pointee_size = i64::try_from(this.layout_of(pointee_ty)?.size.bytes()).unwrap(); + let offset_bytes = offset_count.wrapping_mul(pointee_size); + let offset_ptr = ptr.wrapping_signed_offset(offset_bytes, this); + Scalar::from_maybe_pointer(offset_ptr, this) + } Op::FMax => { fmax_op(&left, &right)? } Op::FMin => { fmin_op(&left, &right)? } - Op::SaturatingOp(mir_op) => { - this.saturating_arith(mir_op, &left, &right)? - } }; this.write_scalar(val, &dest.into())?; } diff --git a/tests/run-pass/portable-simd.rs b/tests/run-pass/portable-simd.rs index 99a64ea370f6b..3e43595c94aee 100644 --- a/tests/run-pass/portable-simd.rs +++ b/tests/run-pass/portable-simd.rs @@ -1,3 +1,4 @@ +// compile-flags: -Zmiri-strict-provenance #![feature(portable_simd, platform_intrinsics)] use std::simd::*; From efe871f20850b89f5ff18a7fa6a4fabdc6ae2887 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 16 Apr 2022 09:13:40 -0400 Subject: [PATCH 2993/3747] readme --- README.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index d394eb3cfbe95..0a507016e5714 100644 --- a/README.md +++ b/README.md @@ -57,8 +57,11 @@ in your program, and cannot run all programs: executions. * Miri runs the program as a platform-independent interpreter, so the program has no access to most platform-specific APIs or FFI. A few APIs have been - implemented (such as printing to stdout) but most have not: for example, Miri - currently does not support SIMD or networking. + implemented (such as printing to stdout, accessing environment variables, and + basic file system access) but most have not: for example, Miri currently does + not support networking. System API support varies between targets; if you run + on Windows it is a good idea to use `--target x86_64-unknown-linux-gnu` to get + better support. * Threading support is not finished yet. E.g., weak memory effects are not emulated and spin loops (without syscalls) just loop forever. There is no threading support on Windows. From db2c4b6dfa765582d8f184ec09ee17643e183725 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 16 Apr 2022 22:50:46 -0400 Subject: [PATCH 2994/3747] implement strerror_r --- src/helpers.rs | 95 ++++++++++++++++++++------------ src/shims/posix/foreign_items.rs | 14 +++++ tests/run-pass/fs.rs | 2 + 3 files changed, 77 insertions(+), 34 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index 5b6e616400b42..b052463bb022d 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -21,6 +21,27 @@ use crate::*; impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} +const UNIX_IO_ERROR_TABLE: &[(std::io::ErrorKind, &str)] = { + use std::io::ErrorKind::*; + &[ + (ConnectionRefused, "ECONNREFUSED"), + (ConnectionReset, "ECONNRESET"), + (PermissionDenied, "EPERM"), + (BrokenPipe, "EPIPE"), + (NotConnected, "ENOTCONN"), + (ConnectionAborted, "ECONNABORTED"), + (AddrNotAvailable, "EADDRNOTAVAIL"), + (AddrInUse, "EADDRINUSE"), + (NotFound, "ENOENT"), + (Interrupted, "EINTR"), + (InvalidInput, "EINVAL"), + (TimedOut, "ETIMEDOUT"), + (AlreadyExists, "EEXIST"), + (WouldBlock, "EWOULDBLOCK"), + (DirectoryNotEmpty, "ENOTEMPTY"), + ] +}; + /// Gets an instance for a path. fn try_resolve_did<'mir, 'tcx>(tcx: TyCtxt<'tcx>, path: &[&str]) -> Option { tcx.crates(()).iter().find(|&&krate| tcx.crate_name(krate).as_str() == path[0]).and_then( @@ -502,39 +523,21 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.read_scalar(&errno_place.into())?.check_init() } - /// Sets the last OS error using a `std::io::ErrorKind`. This function tries to produce the most - /// similar OS error from the `std::io::ErrorKind` and sets it as the last OS error. - fn set_last_error_from_io_error(&mut self, err_kind: std::io::ErrorKind) -> InterpResult<'tcx> { - use std::io::ErrorKind::*; - let this = self.eval_context_mut(); + /// This function tries to produce the most similar OS error from the `std::io::ErrorKind` + /// as a platform-specific errnum. + fn io_error_to_errnum(&self, err_kind: std::io::ErrorKind) -> InterpResult<'tcx, Scalar> { + let this = self.eval_context_ref(); let target = &this.tcx.sess.target; - let target_os = &target.os; - let last_error = if target.families.iter().any(|f| f == "unix") { - this.eval_libc(match err_kind { - ConnectionRefused => "ECONNREFUSED", - ConnectionReset => "ECONNRESET", - PermissionDenied => "EPERM", - BrokenPipe => "EPIPE", - NotConnected => "ENOTCONN", - ConnectionAborted => "ECONNABORTED", - AddrNotAvailable => "EADDRNOTAVAIL", - AddrInUse => "EADDRINUSE", - NotFound => "ENOENT", - Interrupted => "EINTR", - InvalidInput => "EINVAL", - TimedOut => "ETIMEDOUT", - AlreadyExists => "EEXIST", - WouldBlock => "EWOULDBLOCK", - DirectoryNotEmpty => "ENOTEMPTY", - _ => { - throw_unsup_format!( - "io error {:?} cannot be translated into a raw os error", - err_kind - ) + if target.families.iter().any(|f| f == "unix") { + for &(kind, name) in UNIX_IO_ERROR_TABLE { + if err_kind == kind { + return this.eval_libc(name); } - })? + } + throw_unsup_format!("io error {:?} cannot be translated into a raw os error", err_kind) } else if target.families.iter().any(|f| f == "windows") { // FIXME: we have to finish implementing the Windows equivalent of this. + use std::io::ErrorKind::*; this.eval_windows( "c", match err_kind { @@ -546,14 +549,38 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx err_kind ), }, - )? + ) } else { throw_unsup_format!( - "setting the last OS error from an io::Error is unsupported for {}.", - target_os + "converting io::Error into errnum is unsupported for OS {}", + target.os ) - }; - this.set_last_error(last_error) + } + } + + /// The inverse of `io_error_to_errnum`. + fn errnum_to_io_error(&self, errnum: Scalar) -> InterpResult<'tcx, std::io::ErrorKind> { + let this = self.eval_context_ref(); + let target = &this.tcx.sess.target; + if target.families.iter().any(|f| f == "unix") { + let errnum = errnum.to_i32()?; + for &(kind, name) in UNIX_IO_ERROR_TABLE { + if errnum == this.eval_libc_i32(name)? { + return Ok(kind); + } + } + throw_unsup_format!("raw errnum {:?} cannot be translated into io::Error", errnum) + } else { + throw_unsup_format!( + "converting errnum into io::Error is unsupported for OS {}", + target.os + ) + } + } + + /// Sets the last OS error using a `std::io::ErrorKind`. + fn set_last_error_from_io_error(&mut self, err_kind: std::io::ErrorKind) -> InterpResult<'tcx> { + self.set_last_error(self.io_error_to_errnum(err_kind)?) } /// Helper function that consumes an `std::io::Result` and returns an diff --git a/src/shims/posix/foreign_items.rs b/src/shims/posix/foreign_items.rs index 4bf0bbc26212d..16619d4aeb771 100644 --- a/src/shims/posix/foreign_items.rs +++ b/src/shims/posix/foreign_items.rs @@ -1,3 +1,5 @@ +use std::ffi::OsStr; + use log::trace; use rustc_middle::mir; @@ -421,6 +423,18 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // We do not support forking, so there is nothing to do here. this.write_null(dest)?; } + "strerror_r" | "__xpg_strerror_r" => { + let &[ref errnum, ref buf, ref buflen] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let errnum = this.read_scalar(errnum)?.check_init()?; + let buf = this.read_pointer(buf)?; + let buflen = this.read_scalar(buflen)?.to_machine_usize(this)?; + + let error = this.errnum_to_io_error(errnum)?; + let formatted = error.to_string(); + let (complete, _) = this.write_os_str_to_c_str(OsStr::new(&formatted), buf, buflen)?; + let ret = if complete { 0 } else { this.eval_libc_i32("ERANGE")? }; + this.write_int(ret, dest)?; + } // Incomplete shims that we "stub out" just to get pre-main initialization code to work. // These shims are enabled only when the caller is in the standard library. diff --git a/tests/run-pass/fs.rs b/tests/run-pass/fs.rs index 67817e3e2c856..bc78cb560f00a 100644 --- a/tests/run-pass/fs.rs +++ b/tests/run-pass/fs.rs @@ -335,6 +335,8 @@ fn test_errors() { // The following tests also check that the `__errno_location()` shim is working properly. // Opening a non-existing file should fail with a "not found" error. assert_eq!(ErrorKind::NotFound, File::open(&path).unwrap_err().kind()); + // Make sure we can also format this. + format!("{0:?}: {0}", File::open(&path).unwrap_err()); // Removing a non-existing file should fail with a "not found" error. assert_eq!(ErrorKind::NotFound, remove_file(&path).unwrap_err().kind()); // Reading the metadata of a non-existing file should fail with a "not found" error. From 5a3ec3780ea1345dc2745ce9935c92fdd43402db Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 17 Apr 2022 21:46:42 -0400 Subject: [PATCH 2995/3747] add size assertions for some core types --- src/machine.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/machine.rs b/src/machine.rs index 9e0cb69f28d80..532aeeece07e6 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -12,6 +12,8 @@ use rand::SeedableRng; use rustc_ast::ast::Mutability; use rustc_data_structures::fx::FxHashMap; +#[allow(unused)] +use rustc_data_structures::static_assert_size; use rustc_middle::{ mir, ty::{ @@ -128,6 +130,13 @@ pub struct Tag { pub sb: SbTag, } +#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] +static_assert_size!(Pointer, 24); +#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] +static_assert_size!(Pointer>, 24); +#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] +static_assert_size!(ScalarMaybeUninit, 32); + impl Provenance for Tag { /// We use absolute addresses in the `offset` of a `Pointer`. const OFFSET_IS_ADDR: bool = true; From 763ff1c49fd6671d64709fe269c2d3a130dce4a6 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 19 Apr 2022 14:56:07 -0400 Subject: [PATCH 2996/3747] do not consider thread-local allocations read-only --- src/thread.rs | 7 +++++-- tests/run-pass/concurrency/thread_locals.rs | 6 ++++++ 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/thread.rs b/src/thread.rs index 96131dba3ca6a..27bc9566d8fdc 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -10,6 +10,7 @@ use log::trace; use rustc_data_structures::fx::FxHashMap; use rustc_hir::def_id::DefId; use rustc_index::vec::{Idx, IndexVec}; +use rustc_middle::mir::Mutability; use crate::sync::SynchronizationState; use crate::*; @@ -571,9 +572,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx throw_unsup_format!("foreign thread-local statics are not supported"); } let allocation = tcx.eval_static_initializer(def_id)?; + let mut allocation = allocation.inner().clone(); + // This allocation will be deallocated when the thread dies, so it is not in read-only memory. + allocation.mutability = Mutability::Mut; // Create a fresh allocation with this content. - let new_alloc = - this.allocate_raw_ptr(allocation.inner().clone(), MiriMemoryKind::Tls.into()); + let new_alloc = this.allocate_raw_ptr(allocation, MiriMemoryKind::Tls.into()); this.machine.threads.set_thread_local_alloc(def_id, new_alloc); Ok(new_alloc) } diff --git a/tests/run-pass/concurrency/thread_locals.rs b/tests/run-pass/concurrency/thread_locals.rs index 7938284bd6343..5b11539f7f119 100644 --- a/tests/run-pass/concurrency/thread_locals.rs +++ b/tests/run-pass/concurrency/thread_locals.rs @@ -16,6 +16,10 @@ static mut A: u8 = 0; static mut B: u8 = 0; static mut C: u8 = 0; +// Regression test for https://github.com/rust-lang/rust/issues/96191. +#[thread_local] +static READ_ONLY: u8 = 42; + unsafe fn get_a_ref() -> *mut u8 { &mut A } @@ -25,6 +29,8 @@ struct Sender(*mut u8); unsafe impl Send for Sender {} fn main() { + let _val = READ_ONLY; + let ptr = unsafe { let x = get_a_ref(); *x = 5; From ec1dc749a344522b080ec8162b9fd24fce0c507e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 18 Apr 2022 10:20:11 -0400 Subject: [PATCH 2997/3747] adjust for provenance cleanup --- src/data_race.rs | 6 +++--- src/machine.rs | 36 +++++++++++++++++++----------------- src/shims/backtrace.rs | 2 +- src/stacked_borrows.rs | 3 +-- 4 files changed, 24 insertions(+), 23 deletions(-) diff --git a/src/data_race.rs b/src/data_race.rs index 4a79d9e990479..7625763a3bb4f 100644 --- a/src/data_race.rs +++ b/src/data_race.rs @@ -999,7 +999,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { if let Some(data_race) = &this.machine.data_race { if data_race.multi_threaded.get() { let size = place.layout.size; - let (alloc_id, base_offset, ptr) = this.ptr_get_alloc_id(place.ptr)?; + let (alloc_id, base_offset, _tag) = this.ptr_get_alloc_id(place.ptr)?; // Load and log the atomic operation. // Note that atomic loads are possible even from read-only allocations, so `get_alloc_extra_mut` is not an option. let alloc_meta = &this.get_alloc_extra(alloc_id)?.data_race.as_ref().unwrap(); @@ -1007,7 +1007,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { "Atomic op({}) with ordering {:?} on {:?} (size={})", description, &atomic, - ptr, + place.ptr, size.bytes() ); @@ -1039,7 +1039,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { { log::trace!( "Updated atomic memory({:?}, size={}) to {:#?}", - ptr, + place.ptr, size.bytes(), range.atomic_ops ); diff --git a/src/machine.rs b/src/machine.rs index 532aeeece07e6..df53d90b05c50 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -431,11 +431,13 @@ impl<'mir, 'tcx> MiriEvalContextExt<'mir, 'tcx> for MiriEvalContext<'mir, 'tcx> /// Machine hook implementations. impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { type MemoryKind = MiriMemoryKind; + type ExtraFnVal = Dlsym; type FrameExtra = FrameData<'tcx>; type AllocExtra = AllocExtra; + type PointerTag = Tag; - type ExtraFnVal = Dlsym; + type TagExtra = SbTag; type MemoryMap = MonoHashMap, Allocation)>; @@ -607,9 +609,9 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { fn ptr_get_alloc( ecx: &MiriEvalContext<'mir, 'tcx>, ptr: Pointer, - ) -> (AllocId, Size) { + ) -> (AllocId, Size, Self::TagExtra) { let rel = intptrcast::GlobalStateInner::abs_ptr_to_rel(ecx, ptr); - (ptr.provenance.alloc_id, rel) + (ptr.provenance.alloc_id, rel, ptr.provenance.sb) } #[inline(always)] @@ -617,16 +619,16 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { _tcx: TyCtxt<'tcx>, machine: &Self, alloc_extra: &AllocExtra, - tag: Tag, + (alloc_id, tag): (AllocId, Self::TagExtra), range: AllocRange, ) -> InterpResult<'tcx> { if let Some(data_race) = &alloc_extra.data_race { - data_race.read(tag.alloc_id, range, machine.data_race.as_ref().unwrap())?; + data_race.read(alloc_id, range, machine.data_race.as_ref().unwrap())?; } if let Some(stacked_borrows) = &alloc_extra.stacked_borrows { stacked_borrows.memory_read( - tag.alloc_id, - tag.sb, + alloc_id, + tag, range, machine.stacked_borrows.as_ref().unwrap(), ) @@ -640,16 +642,16 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { _tcx: TyCtxt<'tcx>, machine: &mut Self, alloc_extra: &mut AllocExtra, - tag: Tag, + (alloc_id, tag): (AllocId, Self::TagExtra), range: AllocRange, ) -> InterpResult<'tcx> { if let Some(data_race) = &mut alloc_extra.data_race { - data_race.write(tag.alloc_id, range, machine.data_race.as_mut().unwrap())?; + data_race.write(alloc_id, range, machine.data_race.as_mut().unwrap())?; } if let Some(stacked_borrows) = &mut alloc_extra.stacked_borrows { stacked_borrows.memory_written( - tag.alloc_id, - tag.sb, + alloc_id, + tag, range, machine.stacked_borrows.as_mut().unwrap(), ) @@ -663,19 +665,19 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { _tcx: TyCtxt<'tcx>, machine: &mut Self, alloc_extra: &mut AllocExtra, - tag: Tag, + (alloc_id, tag): (AllocId, Self::TagExtra), range: AllocRange, ) -> InterpResult<'tcx> { - if Some(tag.alloc_id) == machine.tracked_alloc_id { - register_diagnostic(NonHaltingDiagnostic::FreedAlloc(tag.alloc_id)); + if Some(alloc_id) == machine.tracked_alloc_id { + register_diagnostic(NonHaltingDiagnostic::FreedAlloc(alloc_id)); } if let Some(data_race) = &mut alloc_extra.data_race { - data_race.deallocate(tag.alloc_id, range, machine.data_race.as_mut().unwrap())?; + data_race.deallocate(alloc_id, range, machine.data_race.as_mut().unwrap())?; } if let Some(stacked_borrows) = &mut alloc_extra.stacked_borrows { stacked_borrows.memory_deallocated( - tag.alloc_id, - tag.sb, + alloc_id, + tag, range, machine.stacked_borrows.as_mut().unwrap(), ) diff --git a/src/shims/backtrace.rs b/src/shims/backtrace.rs index 2ec4bbb32e029..3ada61abbd296 100644 --- a/src/shims/backtrace.rs +++ b/src/shims/backtrace.rs @@ -124,7 +124,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let ptr = this.read_pointer(ptr)?; // Take apart the pointer, we need its pieces. - let (alloc_id, offset, ptr) = this.ptr_get_alloc_id(ptr)?; + let (alloc_id, offset, _tag) = this.ptr_get_alloc_id(ptr)?; let fn_instance = if let Some(GlobalAlloc::Function(instance)) = this.tcx.get_global_alloc(alloc_id) { diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index a365d909981bf..0029de3b5a9c1 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -702,8 +702,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ); return Ok(()); } - let (alloc_id, base_offset, ptr) = this.ptr_get_alloc_id(place.ptr)?; - let orig_tag = ptr.provenance.sb; + let (alloc_id, base_offset, orig_tag) = this.ptr_get_alloc_id(place.ptr)?; // Ensure we bail out if the pointer goes out-of-bounds (see miri#1050). let (alloc_size, _) = From f1023fbdc9aafc8c78c7a6967d0dc4daa741c2a1 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 18 Apr 2022 12:38:26 -0400 Subject: [PATCH 2998/3747] avoid into_pointer_or_addr and into_parts in visit_freeze_sensitive --- src/helpers.rs | 34 ++++++++++++++-------------------- src/intptrcast.rs | 4 ++-- src/machine.rs | 1 + src/shims/mod.rs | 5 ++--- 4 files changed, 19 insertions(+), 25 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index b052463bb022d..9d387b0659386 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -271,8 +271,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// Visits the memory covered by `place`, sensitive to freezing: the 2nd parameter /// of `action` will be true if this is frozen, false if this is in an `UnsafeCell`. /// The range is relative to `place`. - /// - /// Assumes that the `place` has a proper pointer in it. fn visit_freeze_sensitive( &self, place: &MPlaceTy<'tcx, Tag>, @@ -290,33 +288,30 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Store how far we proceeded into the place so far. Everything to the left of // this offset has already been handled, in the sense that the frozen parts // have had `action` called on them. - let ptr = place.ptr.into_pointer_or_addr().unwrap(); - let start_offset = ptr.into_parts().1 as Size; // we just compare offsets, the abs. value never matters - let mut cur_offset = start_offset; + let start_addr = place.ptr.addr(); + let mut cur_addr = start_addr; // Called when we detected an `UnsafeCell` at the given offset and size. // Calls `action` and advances `cur_ptr`. - let mut unsafe_cell_action = |unsafe_cell_ptr: Pointer>, + let mut unsafe_cell_action = |unsafe_cell_ptr: &Pointer>, unsafe_cell_size: Size| { - let unsafe_cell_ptr = unsafe_cell_ptr.into_pointer_or_addr().unwrap(); - debug_assert_eq!(unsafe_cell_ptr.provenance, ptr.provenance); // We assume that we are given the fields in increasing offset order, // and nothing else changes. - let unsafe_cell_offset = unsafe_cell_ptr.into_parts().1 as Size; // we just compare offsets, the abs. value never matters - assert!(unsafe_cell_offset >= cur_offset); - let frozen_size = unsafe_cell_offset - cur_offset; + let unsafe_cell_addr = unsafe_cell_ptr.addr(); + assert!(unsafe_cell_addr >= cur_addr); + let frozen_size = unsafe_cell_addr - cur_addr; // Everything between the cur_ptr and this `UnsafeCell` is frozen. if frozen_size != Size::ZERO { - action(alloc_range(cur_offset - start_offset, frozen_size), /*frozen*/ true)?; + action(alloc_range(cur_addr - start_addr, frozen_size), /*frozen*/ true)?; } - cur_offset += frozen_size; + cur_addr += frozen_size; // This `UnsafeCell` is NOT frozen. if unsafe_cell_size != Size::ZERO { action( - alloc_range(cur_offset - start_offset, unsafe_cell_size), + alloc_range(cur_addr - start_addr, unsafe_cell_size), /*frozen*/ false, )?; } - cur_offset += unsafe_cell_size; + cur_addr += unsafe_cell_size; // Done Ok(()) }; @@ -334,7 +329,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx .unwrap_or_else(|| place.layout.size); // Now handle this `UnsafeCell`, unless it is empty. if unsafe_cell_size != Size::ZERO { - unsafe_cell_action(place.ptr, unsafe_cell_size) + unsafe_cell_action(&place.ptr, unsafe_cell_size) } else { Ok(()) } @@ -344,7 +339,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // The part between the end_ptr and the end of the place is also frozen. // So pretend there is a 0-sized `UnsafeCell` at the end. - unsafe_cell_action(place.ptr.wrapping_offset(size, this), Size::ZERO)?; + unsafe_cell_action(&place.ptr.offset(size, this)?, Size::ZERO)?; // Done! return Ok(()); @@ -428,9 +423,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let mut places = fields.collect::>>>()?; // we just compare offsets, the abs. value never matters - places.sort_by_key(|place| { - place.ptr.into_pointer_or_addr().unwrap().into_parts().1 as Size - }); + places.sort_by_key(|place| place.ptr.addr()); self.walk_aggregate(place, places.into_iter().map(Ok)) } FieldsShape::Union { .. } | FieldsShape::Primitive => { @@ -777,6 +770,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// Mark a machine allocation that was just created as immutable. fn mark_immutable(&mut self, mplace: &MemPlace) { let this = self.eval_context_mut(); + // This got just allocated, so there definitely is a pointer here. this.alloc_mark_immutable(mplace.ptr.into_pointer_or_addr().unwrap().provenance.alloc_id) .unwrap(); } diff --git a/src/intptrcast.rs b/src/intptrcast.rs index b1c96c7f1e7c5..895241bcc326d 100644 --- a/src/intptrcast.rs +++ b/src/intptrcast.rs @@ -128,7 +128,7 @@ impl<'mir, 'tcx> GlobalStateInner { /// Convert a relative (tcx) pointer to an absolute address. pub fn rel_ptr_to_addr(ecx: &MiriEvalContext<'mir, 'tcx>, ptr: Pointer) -> u64 { - let (alloc_id, offset) = ptr.into_parts(); // offset is relative + let (alloc_id, offset) = ptr.into_parts(); // offset is relative (AllocId provenance) let base_addr = GlobalStateInner::alloc_base_addr(ecx, alloc_id); // Add offset with the right kind of pointer-overflowing arithmetic. @@ -137,7 +137,7 @@ impl<'mir, 'tcx> GlobalStateInner { } pub fn abs_ptr_to_rel(ecx: &MiriEvalContext<'mir, 'tcx>, ptr: Pointer) -> Size { - let (tag, addr) = ptr.into_parts(); // addr is absolute + let (tag, addr) = ptr.into_parts(); // addr is absolute (Tag provenance) let base_addr = GlobalStateInner::alloc_base_addr(ecx, tag.alloc_id); // Wrapping "addr - base_addr" diff --git a/src/machine.rs b/src/machine.rs index df53d90b05c50..66854921a33e8 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -360,6 +360,7 @@ impl<'mir, 'tcx> Evaluator<'mir, 'tcx> { name: &str, ptr: Pointer>, ) { + // This got just allocated, so there definitely is a pointer here. let ptr = ptr.into_pointer_or_addr().unwrap(); this.machine.extern_statics.try_insert(Symbol::intern(name), ptr).unwrap(); } diff --git a/src/shims/mod.rs b/src/shims/mod.rs index 83bc6b6ae1bab..af6064925f043 100644 --- a/src/shims/mod.rs +++ b/src/shims/mod.rs @@ -83,10 +83,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } let ptr = this.read_pointer(ptr_op)?; - if let Ok(ptr) = ptr.into_pointer_or_addr() { + if let Ok((alloc_id, _offset, _)) = this.ptr_try_get_alloc_id(ptr) { // Only do anything if we can identify the allocation this goes to. - let (_, cur_align) = - this.get_alloc_size_and_align(ptr.provenance.alloc_id, AllocCheck::MaybeDead)?; + let (_, cur_align) = this.get_alloc_size_and_align(alloc_id, AllocCheck::MaybeDead)?; if cur_align.bytes() >= req_align { // If the allocation alignment is at least the required alignment we use the // real implementation. From dd968a89bf13a739655cc8a379976bd93dc9bc58 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 20 Apr 2022 08:44:06 -0400 Subject: [PATCH 2999/3747] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index d476da0baaf87..fa9ce8aca882e 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -c8422403f775126c40d558838d321c063554c822 +27af5175497936ea3413bef5816e7c0172514b9c From b5a76c7ff075b96415d5941c95854b217e294d9d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 20 Apr 2022 08:44:10 -0400 Subject: [PATCH 3000/3747] add test for https://github.com/rust-lang/miri/issues/2068 --- tests/run-pass/issue-miri-2068.rs | 48 +++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 tests/run-pass/issue-miri-2068.rs diff --git a/tests/run-pass/issue-miri-2068.rs b/tests/run-pass/issue-miri-2068.rs new file mode 100644 index 0000000000000..7576ba78f607d --- /dev/null +++ b/tests/run-pass/issue-miri-2068.rs @@ -0,0 +1,48 @@ +#![feature(pin_macro)] + +use core::future::Future; +use core::pin::Pin; +use core::task::{Context, Poll}; + +use std::sync::Arc; + +struct NopWaker; + +impl std::task::Wake for NopWaker { + fn wake(self: Arc) {} +} + +pub fn fuzzing_block_on>(fut: F) -> O { + let mut fut = std::pin::pin!(fut); + let waker = std::task::Waker::from(Arc::new(NopWaker)); + let mut context = std::task::Context::from_waker(&waker); + loop { + match fut.as_mut().poll(&mut context) { + Poll::Ready(v) => return v, + Poll::Pending => {} + } + } +} + +pub struct LastFuture { + last: S, +} + +impl Future for LastFuture +where + Self: Unpin, + S: Unpin + Copy, +{ + type Output = S; + + fn poll(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll { + return Poll::Ready(self.last); + } +} + +fn main() { + fuzzing_block_on(async { + LastFuture { last: &0u32 }.await; + LastFuture { last: Option::::None }.await; + }); +} From d4a85f6305a41df2118f15cd77953cea366dea1b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 20 Apr 2022 10:39:17 -0400 Subject: [PATCH 3001/3747] add another test for #2068 --- tests/run-pass/issue-miri-2068-2.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 tests/run-pass/issue-miri-2068-2.rs diff --git a/tests/run-pass/issue-miri-2068-2.rs b/tests/run-pass/issue-miri-2068-2.rs new file mode 100644 index 0000000000000..45b2004e33538 --- /dev/null +++ b/tests/run-pass/issue-miri-2068-2.rs @@ -0,0 +1,14 @@ +// compile-flags: -Zmiri-disable-validation + +use std::mem::MaybeUninit; + +fn main() { unsafe { + let mut x = MaybeUninit::::uninit(); + // Put in a ptr. + x.as_mut_ptr().cast::<&i32>().write_unaligned(&0); + // Overwrite parts of that pointer with 'uninit' through a Scalar. + let ptr = x.as_mut_ptr().cast::(); + *ptr = MaybeUninit::uninit().assume_init(); + // Reading this back should hence work fine. + let _c = *ptr; +} } From e214e6db98badf837e95db89d7a9905294569cd6 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 20 Apr 2022 10:47:22 -0400 Subject: [PATCH 3002/3747] add mut_below_shr test --- tests/run-pass/stacked-borrows/stacked-borrows.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tests/run-pass/stacked-borrows/stacked-borrows.rs b/tests/run-pass/stacked-borrows/stacked-borrows.rs index 8aea945f90939..b63f9addb0f6c 100644 --- a/tests/run-pass/stacked-borrows/stacked-borrows.rs +++ b/tests/run-pass/stacked-borrows/stacked-borrows.rs @@ -16,6 +16,7 @@ fn main() { disjoint_mutable_subborrows(); raw_ref_to_part(); array_casts(); + mut_below_shr(); } // Make sure that reading from an `&mut` does, like reborrowing to `&`, @@ -186,3 +187,12 @@ fn array_casts() { let p = &x as *const usize; assert_eq!(unsafe { *p.add(1) }, 1); } + +/// Transmuting &&i32 to &&mut i32 is fine. +fn mut_below_shr() { + let x = 0; + let y = &x; + let p = unsafe { core::mem::transmute::<&&i32,&&mut i32>(&y) }; + let r = &**p; + let _val = *r; +} From 432015d1f64d3a8065464c29e5af7396fc666c94 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 20 Apr 2022 17:41:09 -0400 Subject: [PATCH 3003/3747] rustup --- rust-version | 2 +- tests/compile-fail/never_transmute_void.rs | 15 +++++++++------ tests/run-pass/async-fn.rs | 2 +- 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/rust-version b/rust-version index fa9ce8aca882e..7cc913cf8679b 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -27af5175497936ea3413bef5816e7c0172514b9c +51ea9bb29b07d76c5a7167d054b54f4eb7f5b44e diff --git a/tests/compile-fail/never_transmute_void.rs b/tests/compile-fail/never_transmute_void.rs index 5e9e2ac204ea1..e5aa04dfec1af 100644 --- a/tests/compile-fail/never_transmute_void.rs +++ b/tests/compile-fail/never_transmute_void.rs @@ -4,15 +4,18 @@ #![feature(never_type)] #![allow(unused, invalid_value)] -enum Void {} +mod m { + enum VoidI {} + pub struct Void(VoidI); -fn f(v: Void) -> ! { - match v {} //~ ERROR entering unreachable code + pub fn f(v: Void) -> ! { + match v.0 {} //~ ERROR entering unreachable code + } } fn main() { - let v: Void = unsafe { - std::mem::transmute::<(), Void>(()) + let v = unsafe { + std::mem::transmute::<(), m::Void>(()) }; - f(v); //~ inside `main` + m::f(v); //~ inside `main` } diff --git a/tests/run-pass/async-fn.rs b/tests/run-pass/async-fn.rs index 1602b5638e903..1d5d9a27cc8a5 100644 --- a/tests/run-pass/async-fn.rs +++ b/tests/run-pass/async-fn.rs @@ -29,7 +29,7 @@ fn never() -> Never { } async fn includes_never(crash: bool, x: u32) -> u32 { - let mut result = async { x * x }.await; + let result = async { x * x }.await; if !crash { return result; } From bf17dbebc9ee9bbc2b5e38f92ccc1a8b51bfa167 Mon Sep 17 00:00:00 2001 From: y86-dev <94611769+y86-dev@users.noreply.github.com> Date: Wed, 20 Apr 2022 11:10:59 +0200 Subject: [PATCH 3004/3747] Added support for multiple tracked pointers, allocs and calls - Changed arg parsing to handle comma seperated list of `u64`'s. - Changed type and field names of config, executor and global state to hold a set of tracked ids. - Adjusted Readme: - explained list format - arguments do not overwrite, instead append - no effect on duplication - Created a parsing function for comma separated lists - Added error printing to alloc_id parsing --- README.md | 14 +++++--- src/bin/miri.rs | 78 +++++++++++++++++++++++++----------------- src/eval.rs | 20 ++++++----- src/machine.rs | 15 ++++---- src/stacked_borrows.rs | 23 +++++++------ 5 files changed, 87 insertions(+), 63 deletions(-) diff --git a/README.md b/README.md index 0a507016e5714..ca14f02d86aef 100644 --- a/README.md +++ b/README.md @@ -314,16 +314,20 @@ environment variable: ensure alignment. (The standard library `align_to` method works fine in both modes; under symbolic alignment it only fills the middle slice when the allocation guarantees sufficient alignment.) -* `-Zmiri-track-alloc-id=` shows a backtrace when the given allocation is +* `-Zmiri-track-alloc-id=,,...` shows a backtrace when the given allocations are being allocated or freed. This helps in debugging memory leaks and - use after free bugs. -* `-Zmiri-track-call-id=` shows a backtrace when the given call id is + use after free bugs. Specifying this argument multiple times does not overwrite the previous + values, instead it appends its values to the list. Listing an id multiple times has no effect. +* `-Zmiri-track-call-id=,,...` shows a backtrace when the given call ids are assigned to a stack frame. This helps in debugging UB related to Stacked - Borrows "protectors". -* `-Zmiri-track-pointer-tag=` shows a backtrace when the given pointer tag + Borrows "protectors". Specifying this argument multiple times does not overwrite the previous + values, instead it appends its values to the list. Listing an id multiple times has no effect. +* `-Zmiri-track-pointer-tag=,,...` shows a backtrace when a given pointer tag is popped from a borrow stack (which is where the tag becomes invalid and any future use of it will error). This helps you in finding out why UB is happening and where in your code would be a good place to look for it. + Specifying this argument multiple times does not overwrite the previous + values, instead it appends its values to the list. Listing a tag multiple times has no effect. * `-Zmiri-tag-raw-pointers` makes Stacked Borrows assign proper tags even for raw pointers. This can make valid code using int-to-ptr casts fail to pass the checks, but also can help identify latent aliasing issues in code that Miri accepts by default. You can recognize false positives by diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 727e0b717b11e..e4d0af4313129 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -251,6 +251,13 @@ fn run_compiler( std::process::exit(exit_code) } +/// Parses a comma separated list of `T` from the given string: +/// +/// `,,,...` +fn parse_comma_list(input: &str) -> Result, T::Err> { + input.split(',').map(str::parse::).collect() +} + fn main() { rustc_driver::install_ice_hook(); @@ -397,46 +404,55 @@ fn main() { .push(arg.strip_prefix("-Zmiri-env-forward=").unwrap().to_owned()); } arg if arg.starts_with("-Zmiri-track-pointer-tag=") => { - let id: u64 = - match arg.strip_prefix("-Zmiri-track-pointer-tag=").unwrap().parse() { - Ok(id) => id, - Err(err) => - panic!( - "-Zmiri-track-pointer-tag requires a valid `u64` argument: {}", - err - ), - }; - if let Some(id) = miri::PtrId::new(id) { - miri_config.tracked_pointer_tag = Some(id); - } else { - panic!("-Zmiri-track-pointer-tag requires a nonzero argument"); + let ids: Vec = match parse_comma_list( + arg.strip_prefix("-Zmiri-track-pointer-tag=").unwrap(), + ) { + Ok(ids) => ids, + Err(err) => + panic!( + "-Zmiri-track-pointer-tag requires a comma separated list of valid `u64` arguments: {}", + err + ), + }; + for id in ids.into_iter().map(miri::PtrId::new) { + if let Some(id) = id { + miri_config.tracked_pointer_tags.insert(id); + } else { + panic!("-Zmiri-track-pointer-tag requires nonzero arguments"); + } } } arg if arg.starts_with("-Zmiri-track-call-id=") => { - let id: u64 = match arg.strip_prefix("-Zmiri-track-call-id=").unwrap().parse() { - Ok(id) => id, + let ids: Vec = match parse_comma_list( + arg.strip_prefix("-Zmiri-track-call-id=").unwrap(), + ) { + Ok(ids) => ids, Err(err) => - panic!("-Zmiri-track-call-id requires a valid `u64` argument: {}", err), + panic!( + "-Zmiri-track-call-id requires a comma separated list of valid `u64` arguments: {}", + err + ), }; - if let Some(id) = miri::CallId::new(id) { - miri_config.tracked_call_id = Some(id); - } else { - panic!("-Zmiri-track-call-id requires a nonzero argument"); + for id in ids.into_iter().map(miri::CallId::new) { + if let Some(id) = id { + miri_config.tracked_call_ids.insert(id); + } else { + panic!("-Zmiri-track-call-id requires a nonzero argument"); + } } } arg if arg.starts_with("-Zmiri-track-alloc-id=") => { - let id = match arg - .strip_prefix("-Zmiri-track-alloc-id=") - .unwrap() - .parse() - .ok() - .and_then(NonZeroU64::new) - { - Some(id) => id, - None => - panic!("-Zmiri-track-alloc-id requires a valid non-zero `u64` argument"), + let ids: Vec = match parse_comma_list::( + arg.strip_prefix("-Zmiri-track-alloc-id=").unwrap(), + ) { + Ok(ids) => ids.into_iter().map(miri::AllocId).collect(), + Err(err) => + panic!( + "-Zmiri-track-alloc-id requires a comma separated list of valid non-zero `u64` arguments: {}", + err + ), }; - miri_config.tracked_alloc_id = Some(miri::AllocId(id)); + miri_config.tracked_alloc_ids.extend(ids); } arg if arg.starts_with("-Zmiri-compare-exchange-weak-failure-rate=") => { let rate = match arg diff --git a/src/eval.rs b/src/eval.rs index 5f829525cc572..24a0fc8ef1617 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -15,6 +15,8 @@ use rustc_target::spec::abi::Abi; use rustc_session::config::EntryFnType; +use std::collections::HashSet; + use crate::*; #[derive(Copy, Clone, Debug, PartialEq)] @@ -91,12 +93,12 @@ pub struct MiriConfig { pub args: Vec, /// The seed to use when non-determinism or randomness are required (e.g. ptr-to-int cast, `getrandom()`). pub seed: Option, - /// The stacked borrows pointer id to report about - pub tracked_pointer_tag: Option, - /// The stacked borrows call ID to report about - pub tracked_call_id: Option, - /// The allocation id to report about. - pub tracked_alloc_id: Option, + /// The stacked borrows pointer ids to report about + pub tracked_pointer_tags: HashSet, + /// The stacked borrows call IDs to report about + pub tracked_call_ids: HashSet, + /// The allocation ids to report about. + pub tracked_alloc_ids: HashSet, /// Whether to track raw pointers in stacked borrows. pub tag_raw: bool, /// Determine if data race detection should be enabled @@ -130,9 +132,9 @@ impl Default for MiriConfig { forwarded_env_vars: vec![], args: vec![], seed: None, - tracked_pointer_tag: None, - tracked_call_id: None, - tracked_alloc_id: None, + tracked_pointer_tags: Default::default(), + tracked_call_ids: Default::default(), + tracked_alloc_ids: Default::default(), tag_raw: false, data_race_detector: true, cmpxchg_weak_failure_rate: 0.8, diff --git a/src/machine.rs b/src/machine.rs index 66854921a33e8..c0f833f17610a 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -3,6 +3,7 @@ use std::borrow::Cow; use std::cell::RefCell; +use std::collections::HashSet; use std::fmt; use std::num::NonZeroU64; use std::time::Instant; @@ -281,9 +282,9 @@ pub struct Evaluator<'mir, 'tcx> { /// Needs to be queried by ptr_to_int, hence needs interior mutability. pub(crate) rng: RefCell, - /// An allocation ID to report when it is being allocated + /// The allocation IDs to report when they are being allocated /// (helps for debugging memory leaks and use after free bugs). - tracked_alloc_id: Option, + tracked_alloc_ids: HashSet, /// Controls whether alignment of memory accesses is being checked. pub(crate) check_alignment: AlignmentCheck, @@ -303,8 +304,8 @@ impl<'mir, 'tcx> Evaluator<'mir, 'tcx> { let rng = StdRng::seed_from_u64(config.seed.unwrap_or(0)); let stacked_borrows = if config.stacked_borrows { Some(RefCell::new(stacked_borrows::GlobalStateInner::new( - config.tracked_pointer_tag, - config.tracked_call_id, + config.tracked_pointer_tags.clone(), + config.tracked_call_ids.clone(), config.tag_raw, ))) } else { @@ -340,7 +341,7 @@ impl<'mir, 'tcx> Evaluator<'mir, 'tcx> { local_crates, extern_statics: FxHashMap::default(), rng: RefCell::new(rng), - tracked_alloc_id: config.tracked_alloc_id, + tracked_alloc_ids: config.tracked_alloc_ids.clone(), check_alignment: config.check_alignment, cmpxchg_weak_failure_rate: config.cmpxchg_weak_failure_rate, } @@ -560,7 +561,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { alloc: Cow<'b, Allocation>, kind: Option>, ) -> Cow<'b, Allocation> { - if Some(id) == ecx.machine.tracked_alloc_id { + if ecx.machine.tracked_alloc_ids.contains(&id) { register_diagnostic(NonHaltingDiagnostic::CreatedAlloc(id)); } @@ -669,7 +670,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { (alloc_id, tag): (AllocId, Self::TagExtra), range: AllocRange, ) -> InterpResult<'tcx> { - if Some(alloc_id) == machine.tracked_alloc_id { + if machine.tracked_alloc_ids.contains(&alloc_id) { register_diagnostic(NonHaltingDiagnostic::FreedAlloc(alloc_id)); } if let Some(data_race) = &mut alloc_extra.data_race { diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 0029de3b5a9c1..9d175e9c4d167 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -15,6 +15,7 @@ use rustc_middle::ty::{ }; use rustc_span::DUMMY_SP; use rustc_target::abi::Size; +use std::collections::HashSet; use crate::*; @@ -104,10 +105,10 @@ pub struct GlobalStateInner { next_call_id: CallId, /// Those call IDs corresponding to functions that are still running. active_calls: FxHashSet, - /// The pointer id to trace - tracked_pointer_tag: Option, - /// The call id to trace - tracked_call_id: Option, + /// The pointer ids to trace + tracked_pointer_tags: HashSet, + /// The call ids to trace + tracked_call_ids: HashSet, /// Whether to track raw pointers. tag_raw: bool, } @@ -158,8 +159,8 @@ impl fmt::Display for RefKind { /// Utilities for initialization and ID generation impl GlobalStateInner { pub fn new( - tracked_pointer_tag: Option, - tracked_call_id: Option, + tracked_pointer_tags: HashSet, + tracked_call_ids: HashSet, tag_raw: bool, ) -> Self { GlobalStateInner { @@ -167,15 +168,15 @@ impl GlobalStateInner { base_ptr_ids: FxHashMap::default(), next_call_id: NonZeroU64::new(1).unwrap(), active_calls: FxHashSet::default(), - tracked_pointer_tag, - tracked_call_id, + tracked_pointer_tags, + tracked_call_ids, tag_raw, } } fn new_ptr(&mut self) -> PtrId { let id = self.next_ptr_id; - if Some(id) == self.tracked_pointer_tag { + if self.tracked_pointer_tags.contains(&id) { register_diagnostic(NonHaltingDiagnostic::CreatedPointerTag(id)); } self.next_ptr_id = NonZeroU64::new(id.get() + 1).unwrap(); @@ -185,7 +186,7 @@ impl GlobalStateInner { pub fn new_call(&mut self) -> CallId { let id = self.next_call_id; trace!("new_call: Assigning ID {}", id); - if Some(id) == self.tracked_call_id { + if self.tracked_call_ids.contains(&id) { register_diagnostic(NonHaltingDiagnostic::CreatedCallId(id)); } assert!(self.active_calls.insert(id)); @@ -311,7 +312,7 @@ impl<'tcx> Stack { global: &GlobalStateInner, ) -> InterpResult<'tcx> { if let SbTag::Tagged(id) = item.tag { - if Some(id) == global.tracked_pointer_tag { + if global.tracked_pointer_tags.contains(&id) { register_diagnostic(NonHaltingDiagnostic::PoppedPointerTag( item.clone(), provoking_access, From 3ca59d2fbf7b60b83ab79bf98e951ef54ff1ffad Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 21 Apr 2022 16:09:35 +0200 Subject: [PATCH 3005/3747] make sure 2-phase borows work even with raw ptr tagging --- tests/run-pass/stacked-borrows/2phase.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/run-pass/stacked-borrows/2phase.rs b/tests/run-pass/stacked-borrows/2phase.rs index 97f435472e300..948da140477eb 100644 --- a/tests/run-pass/stacked-borrows/2phase.rs +++ b/tests/run-pass/stacked-borrows/2phase.rs @@ -1,3 +1,4 @@ +// compile-flags: -Zmiri-tag-raw-pointers #![allow(mutable_borrow_reservation_conflict)] trait S: Sized { From b472ef5bd808a38e808a3ed66f4cf67391829448 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 21 Apr 2022 16:19:28 +0200 Subject: [PATCH 3006/3747] be explicit about types --- src/eval.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/eval.rs b/src/eval.rs index 24a0fc8ef1617..f8d23cb8279cd 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -132,9 +132,9 @@ impl Default for MiriConfig { forwarded_env_vars: vec![], args: vec![], seed: None, - tracked_pointer_tags: Default::default(), - tracked_call_ids: Default::default(), - tracked_alloc_ids: Default::default(), + tracked_pointer_tags: HashSet::default(), + tracked_call_ids: HashSet::default(), + tracked_alloc_ids: HashSet::default(), tag_raw: false, data_race_detector: true, cmpxchg_weak_failure_rate: 0.8, From 4d4855c7620696fa4e0e1d8171385b69912e02a8 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Mon, 25 Apr 2022 13:12:55 +0000 Subject: [PATCH 3007/3747] Add a command line flag to avoid printing to stdout and stderr --- src/bin/miri.rs | 3 ++ src/eval.rs | 4 +++ src/machine.rs | 4 +-- src/shims/posix/fs.rs | 60 +++++++++++++++++++++++++++++++---- tests/run-pass/hide_stdout.rs | 5 +++ 5 files changed, 68 insertions(+), 8 deletions(-) create mode 100644 tests/run-pass/hide_stdout.rs diff --git a/src/bin/miri.rs b/src/bin/miri.rs index e4d0af4313129..b55b6f8d5589d 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -374,6 +374,9 @@ fn main() { miri_config.tag_raw = true; miri_config.check_number_validity = true; } + "-Zmiri-drop-stdout-stderr" => { + miri_config.drop_stdout_stderr = true; + } "-Zmiri-track-raw-pointers" => { eprintln!( "WARNING: -Zmiri-track-raw-pointers has been renamed to -Zmiri-tag-raw-pointers, the old name is deprecated." diff --git a/src/eval.rs b/src/eval.rs index f8d23cb8279cd..f1cbb00942bb5 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -116,6 +116,9 @@ pub struct MiriConfig { /// Whether to enforce "strict provenance" rules. Enabling this means int2ptr casts return /// pointers with an invalid provenance, i.e., not valid for any memory access. pub strict_provenance: bool, + /// Whether to ignore any output by the program. This is helpful when debugging miri + /// as its messages don't get intermingled with the program messages. + pub drop_stdout_stderr: bool, } impl Default for MiriConfig { @@ -142,6 +145,7 @@ impl Default for MiriConfig { panic_on_unsupported: false, backtrace_style: BacktraceStyle::Short, strict_provenance: false, + drop_stdout_stderr: false, } } } diff --git a/src/machine.rs b/src/machine.rs index c0f833f17610a..1fdc398dd9f03 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -28,7 +28,7 @@ use rustc_span::symbol::{sym, Symbol}; use rustc_target::abi::Size; use rustc_target::spec::abi::Abi; -use crate::*; +use crate::{*, shims::posix::FileHandler}; // Some global facts about the emulated machine. pub const PAGE_SIZE: u64 = 4 * 1024; // FIXME: adjust to target architecture @@ -327,7 +327,7 @@ impl<'mir, 'tcx> Evaluator<'mir, 'tcx> { validate: config.validate, enforce_number_validity: config.check_number_validity, enforce_abi: config.check_abi, - file_handler: Default::default(), + file_handler: FileHandler::new(config.drop_stdout_stderr), dir_handler: Default::default(), time_anchor: Instant::now(), layouts, diff --git a/src/shims/posix/fs.rs b/src/shims/posix/fs.rs index 73e21dd57dc40..78d0e958e2a02 100644 --- a/src/shims/posix/fs.rs +++ b/src/shims/posix/fs.rs @@ -251,22 +251,70 @@ impl FileDescriptor for io::Stderr { } } +#[derive(Debug)] +struct DevNull; + +impl FileDescriptor for DevNull { + fn as_file_handle<'tcx>(&self) -> InterpResult<'tcx, &FileHandle> { + throw_unsup_format!("/dev/null cannot be used as FileHandle"); + } + + fn read<'tcx>( + &mut self, + _communicate_allowed: bool, + _bytes: &mut [u8], + ) -> InterpResult<'tcx, io::Result> { + throw_unsup_format!("cannot read from /dev/null"); + } + + fn write<'tcx>( + &self, + _communicate_allowed: bool, + bytes: &[u8], + ) -> InterpResult<'tcx, io::Result> { + // We just don't write anything + Ok(Ok(bytes.len())) + } + + fn seek<'tcx>( + &mut self, + _communicate_allowed: bool, + _offset: SeekFrom, + ) -> InterpResult<'tcx, io::Result> { + throw_unsup_format!("cannot seek on /dev/null"); + } + + fn close<'tcx>( + self: Box, + _communicate_allowed: bool, + ) -> InterpResult<'tcx, io::Result> { + throw_unsup_format!("/dev/null cannot be closed"); + } + + fn dup<'tcx>(&mut self) -> io::Result> { + Ok(Box::new(DevNull)) + } +} + #[derive(Debug)] pub struct FileHandler { handles: BTreeMap>, } -impl<'tcx> Default for FileHandler { - fn default() -> Self { +impl<'tcx> FileHandler { + pub(crate) fn new(drop_stdout_stderr: bool) -> FileHandler { let mut handles: BTreeMap<_, Box> = BTreeMap::new(); - handles.insert(0i32, Box::new(io::stdin())); - handles.insert(1i32, Box::new(io::stdout())); + if drop_stdout_stderr { + handles.insert(0i32, Box::new(DevNull)); + handles.insert(1i32, Box::new(DevNull)); + } else { + handles.insert(0i32, Box::new(io::stdin())); + handles.insert(1i32, Box::new(io::stdout())); + } handles.insert(2i32, Box::new(io::stderr())); FileHandler { handles } } -} -impl<'tcx> FileHandler { fn insert_fd(&mut self, file_handle: Box) -> i32 { self.insert_fd_with_min_fd(file_handle, 0) } diff --git a/tests/run-pass/hide_stdout.rs b/tests/run-pass/hide_stdout.rs new file mode 100644 index 0000000000000..04a4ef9df174d --- /dev/null +++ b/tests/run-pass/hide_stdout.rs @@ -0,0 +1,5 @@ +// compile-flags: -Zmiri-drop-stdout-stderr + +fn main() { + println!("cake"); +} From 1d0fe1b6bbf373190465f115777a2d98bb2741bd Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Mon, 25 Apr 2022 14:22:55 +0000 Subject: [PATCH 3008/3747] Implement the output dropping for windows, too --- src/machine.rs | 4 ++++ src/shims/windows/dlsym.rs | 4 +++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/machine.rs b/src/machine.rs index 1fdc398dd9f03..6cce1a5db2524 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -291,6 +291,9 @@ pub struct Evaluator<'mir, 'tcx> { /// Failure rate of compare_exchange_weak, between 0.0 and 1.0 pub(crate) cmpxchg_weak_failure_rate: f64, + + /// Corresponds to -Zmiri-drop-stdout-stderr and doesn't write the output but acts as if it succeeded. + pub(crate) drop_stdout_stderr: bool, } impl<'mir, 'tcx> Evaluator<'mir, 'tcx> { @@ -344,6 +347,7 @@ impl<'mir, 'tcx> Evaluator<'mir, 'tcx> { tracked_alloc_ids: config.tracked_alloc_ids.clone(), check_alignment: config.check_alignment, cmpxchg_weak_failure_rate: config.cmpxchg_weak_failure_rate, + drop_stdout_stderr: config.drop_stdout_stderr, } } diff --git a/src/shims/windows/dlsym.rs b/src/shims/windows/dlsym.rs index ac9e085b5d7c9..05230531d917c 100644 --- a/src/shims/windows/dlsym.rs +++ b/src/shims/windows/dlsym.rs @@ -75,7 +75,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx use std::io::{self, Write}; let buf_cont = this.read_bytes_ptr(buf, Size::from_bytes(u64::from(n)))?; - let res = if handle == -11 { + let res = if this.machine.drop_stdout_stderr { + Ok(buf_cont.len()) + } else if handle == -11 { io::stdout().write(buf_cont) } else { io::stderr().write(buf_cont) From f8f776fee9ad540c117f71aed62c5648a4927bf1 Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Mon, 25 Apr 2022 21:34:40 +0100 Subject: [PATCH 3009/3747] Update export_symbols --- rust-version | 2 +- src/bin/miri.rs | 13 +++++++++++-- src/shims/foreign_items.rs | 4 ++-- 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/rust-version b/rust-version index 7cc913cf8679b..685628ac99d53 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -51ea9bb29b07d76c5a7167d054b54f4eb7f5b44e +18b53cefdf7456bf68937b08e377b7e622a115c2 diff --git a/src/bin/miri.rs b/src/bin/miri.rs index e4d0af4313129..8a89d7f6410a7 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -22,7 +22,9 @@ use rustc_errors::emitter::{ColorConfig, HumanReadableErrorType}; use rustc_hir::{self as hir, def_id::LOCAL_CRATE, Node}; use rustc_interface::interface::Config; use rustc_middle::{ - middle::exported_symbols::{ExportedSymbol, SymbolExportLevel}, + middle::exported_symbols::{ + ExportedSymbol, SymbolExportInfo, SymbolExportKind, SymbolExportLevel, + }, ty::{query::ExternProviders, TyCtxt}, }; use rustc_session::{config::ErrorOutputType, search_paths::PathKind, CtfeBacktrace}; @@ -130,7 +132,14 @@ impl rustc_driver::Callbacks for MiriBeRustCompilerCalls { && tcx.codegen_fn_attrs(local_def_id).contains_extern_indicator()) .then_some(( ExportedSymbol::NonGeneric(local_def_id.to_def_id()), - SymbolExportLevel::C, + // Some dummy `SymbolExportInfo` here. We only use + // `exported_symbols` in shims/foreign_items.rs and the export info + // is ignored. + SymbolExportInfo { + level: SymbolExportLevel::C, + kind: SymbolExportKind::Text, + used: false, + }, )) }), ) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 7b457e9ed79a8..ef88c550ecb2e 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -157,9 +157,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx (linkage != Linkage::NotLinked).then_some(CrateNum::new(num + 1)) }), ) { - // We can ignore `_export_level` here: we are a Rust crate, and everything is exported + // We can ignore `_export_info` here: we are a Rust crate, and everything is exported // from a Rust crate. - for &(symbol, _export_level) in tcx.exported_symbols(cnum) { + for &(symbol, _export_info) in tcx.exported_symbols(cnum) { if let ExportedSymbol::NonGeneric(def_id) = symbol { let attrs = tcx.codegen_fn_attrs(def_id); let symbol_name = if let Some(export_name) = attrs.export_name { From a192a199a8761a8c2b71ba2ca8202091b248716e Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Tue, 26 Apr 2022 09:33:20 +0000 Subject: [PATCH 3010/3747] Rename flag, datastructure and messaging around muting stdout and stderr --- src/bin/miri.rs | 4 ++-- src/eval.rs | 4 ++-- src/machine.rs | 8 ++++---- src/shims/posix/fs.rs | 24 ++++++++++++------------ src/shims/windows/dlsym.rs | 2 +- tests/run-pass/hide_stdout.rs | 2 +- 6 files changed, 22 insertions(+), 22 deletions(-) diff --git a/src/bin/miri.rs b/src/bin/miri.rs index b55b6f8d5589d..2fa045b574622 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -374,8 +374,8 @@ fn main() { miri_config.tag_raw = true; miri_config.check_number_validity = true; } - "-Zmiri-drop-stdout-stderr" => { - miri_config.drop_stdout_stderr = true; + "-Zmiri-mute-stdout-stderr" => { + miri_config.mute_stdout_stderr = true; } "-Zmiri-track-raw-pointers" => { eprintln!( diff --git a/src/eval.rs b/src/eval.rs index f1cbb00942bb5..028c9b97abb37 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -118,7 +118,7 @@ pub struct MiriConfig { pub strict_provenance: bool, /// Whether to ignore any output by the program. This is helpful when debugging miri /// as its messages don't get intermingled with the program messages. - pub drop_stdout_stderr: bool, + pub mute_stdout_stderr: bool, } impl Default for MiriConfig { @@ -145,7 +145,7 @@ impl Default for MiriConfig { panic_on_unsupported: false, backtrace_style: BacktraceStyle::Short, strict_provenance: false, - drop_stdout_stderr: false, + mute_stdout_stderr: false, } } } diff --git a/src/machine.rs b/src/machine.rs index 6cce1a5db2524..1c916220c8c54 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -292,8 +292,8 @@ pub struct Evaluator<'mir, 'tcx> { /// Failure rate of compare_exchange_weak, between 0.0 and 1.0 pub(crate) cmpxchg_weak_failure_rate: f64, - /// Corresponds to -Zmiri-drop-stdout-stderr and doesn't write the output but acts as if it succeeded. - pub(crate) drop_stdout_stderr: bool, + /// Corresponds to -Zmiri-mute-stdout-stderr and doesn't write the output but acts as if it succeeded. + pub(crate) mute_stdout_stderr: bool, } impl<'mir, 'tcx> Evaluator<'mir, 'tcx> { @@ -330,7 +330,7 @@ impl<'mir, 'tcx> Evaluator<'mir, 'tcx> { validate: config.validate, enforce_number_validity: config.check_number_validity, enforce_abi: config.check_abi, - file_handler: FileHandler::new(config.drop_stdout_stderr), + file_handler: FileHandler::new(config.mute_stdout_stderr), dir_handler: Default::default(), time_anchor: Instant::now(), layouts, @@ -347,7 +347,7 @@ impl<'mir, 'tcx> Evaluator<'mir, 'tcx> { tracked_alloc_ids: config.tracked_alloc_ids.clone(), check_alignment: config.check_alignment, cmpxchg_weak_failure_rate: config.cmpxchg_weak_failure_rate, - drop_stdout_stderr: config.drop_stdout_stderr, + mute_stdout_stderr: config.mute_stdout_stderr, } } diff --git a/src/shims/posix/fs.rs b/src/shims/posix/fs.rs index 78d0e958e2a02..1b0a94e0ffc91 100644 --- a/src/shims/posix/fs.rs +++ b/src/shims/posix/fs.rs @@ -252,11 +252,11 @@ impl FileDescriptor for io::Stderr { } #[derive(Debug)] -struct DevNull; +struct DummyOutput; -impl FileDescriptor for DevNull { +impl FileDescriptor for DummyOutput { fn as_file_handle<'tcx>(&self) -> InterpResult<'tcx, &FileHandle> { - throw_unsup_format!("/dev/null cannot be used as FileHandle"); + throw_unsup_format!("stderr and stdout cannot be used as FileHandle"); } fn read<'tcx>( @@ -264,7 +264,7 @@ impl FileDescriptor for DevNull { _communicate_allowed: bool, _bytes: &mut [u8], ) -> InterpResult<'tcx, io::Result> { - throw_unsup_format!("cannot read from /dev/null"); + throw_unsup_format!("cannot read from stderr or stdout"); } fn write<'tcx>( @@ -272,7 +272,7 @@ impl FileDescriptor for DevNull { _communicate_allowed: bool, bytes: &[u8], ) -> InterpResult<'tcx, io::Result> { - // We just don't write anything + // We just don't write anything, but report to the user that we did. Ok(Ok(bytes.len())) } @@ -281,18 +281,18 @@ impl FileDescriptor for DevNull { _communicate_allowed: bool, _offset: SeekFrom, ) -> InterpResult<'tcx, io::Result> { - throw_unsup_format!("cannot seek on /dev/null"); + throw_unsup_format!("cannot seek on stderr or stdout"); } fn close<'tcx>( self: Box, _communicate_allowed: bool, ) -> InterpResult<'tcx, io::Result> { - throw_unsup_format!("/dev/null cannot be closed"); + throw_unsup_format!("stderr and stdout cannot be closed"); } fn dup<'tcx>(&mut self) -> io::Result> { - Ok(Box::new(DevNull)) + Ok(Box::new(DummyOutput)) } } @@ -302,11 +302,11 @@ pub struct FileHandler { } impl<'tcx> FileHandler { - pub(crate) fn new(drop_stdout_stderr: bool) -> FileHandler { + pub(crate) fn new(mute_stdout_stderr: bool) -> FileHandler { let mut handles: BTreeMap<_, Box> = BTreeMap::new(); - if drop_stdout_stderr { - handles.insert(0i32, Box::new(DevNull)); - handles.insert(1i32, Box::new(DevNull)); + if mute_stdout_stderr { + handles.insert(0i32, Box::new(DummyOutput)); + handles.insert(1i32, Box::new(DummyOutput)); } else { handles.insert(0i32, Box::new(io::stdin())); handles.insert(1i32, Box::new(io::stdout())); diff --git a/src/shims/windows/dlsym.rs b/src/shims/windows/dlsym.rs index 05230531d917c..ddbad8c5affa1 100644 --- a/src/shims/windows/dlsym.rs +++ b/src/shims/windows/dlsym.rs @@ -75,7 +75,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx use std::io::{self, Write}; let buf_cont = this.read_bytes_ptr(buf, Size::from_bytes(u64::from(n)))?; - let res = if this.machine.drop_stdout_stderr { + let res = if this.machine.mute_stdout_stderr { Ok(buf_cont.len()) } else if handle == -11 { io::stdout().write(buf_cont) diff --git a/tests/run-pass/hide_stdout.rs b/tests/run-pass/hide_stdout.rs index 04a4ef9df174d..849fce913862e 100644 --- a/tests/run-pass/hide_stdout.rs +++ b/tests/run-pass/hide_stdout.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-drop-stdout-stderr +// compile-flags: -Zmiri-mute-stdout-stderr fn main() { println!("cake"); From 5e26cdaf3a574efa8e88b31b9df4d120e0805d7d Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Tue, 26 Apr 2022 09:36:02 +0000 Subject: [PATCH 3011/3747] Add readme entry --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index ca14f02d86aef..4cb03ed7b0b2c 100644 --- a/README.md +++ b/README.md @@ -265,6 +265,10 @@ environment variable: * `-Zmiri-disable-isolation` disables host isolation. As a consequence, the program has access to host resources such as environment variables, file systems, and randomness. +* `-Zmiri-mute-stdout-stderr` silently ignores all writes to stdout and stderr, + but reports to the program that it did actually write. This is useful when you + are not interested in the actual program's messages, but only want to see miri's + errors and warnings. * `-Zmiri-isolation-error=` configures Miri's response to operations requiring host access while isolation is enabled. `abort`, `hide`, `warn`, and `warn-nobacktrace` are the supported actions. The default is to `abort`, From b0a51720c69198ccfe0467b43cd2658d9341bd76 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Fri, 29 Apr 2022 15:25:10 -0700 Subject: [PATCH 3012/3747] Suppress all currently triggered clippy lints --- src/bin/miri.rs | 1 + src/lib.rs | 30 ++++++++++++++++++++++++++++++ 2 files changed, 31 insertions(+) diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 8a89d7f6410a7..0030c24b19e6d 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -1,4 +1,5 @@ #![feature(rustc_private, bool_to_option, stmt_expr_attributes)] +#![allow(clippy::manual_range_contains)] extern crate rustc_data_structures; extern crate rustc_driver; diff --git a/src/lib.rs b/src/lib.rs index f14120ae4ccc1..285e8d10e5623 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -8,6 +8,36 @@ #![feature(io_error_more)] #![warn(rust_2018_idioms)] #![allow(clippy::cast_lossless)] +// TODO: Uncategorized. Some of these we'll want to fix, some keep ignored. +#![allow( + clippy::assign_op_pattern, + clippy::clone_on_copy, + clippy::collapsible_else_if, + clippy::collapsible_if, + clippy::comparison_chain, + clippy::enum_variant_names, + clippy::extra_unused_lifetimes, + clippy::field_reassign_with_default, + clippy::from_over_into, + clippy::if_same_then_else, + clippy::len_zero, + clippy::manual_map, + clippy::mem_replace_with_default, + clippy::needless_borrow, + clippy::needless_lifetimes, + clippy::needless_question_mark, + clippy::needless_return, + clippy::new_without_default, + clippy::op_ref, + clippy::redundant_closure, + clippy::redundant_field_names, + clippy::single_char_add_str, + clippy::single_char_pattern, + clippy::single_match, + clippy::unnecessary_mut_passed, + clippy::useless_conversion, + clippy::useless_format +)] extern crate rustc_apfloat; extern crate rustc_ast; From 03897452039a749c717b8bf3b7f9bb030035e88d Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Fri, 29 Apr 2022 15:25:38 -0700 Subject: [PATCH 3013/3747] Resolve clippy::assign_op_pattern error: manual implementation of an assign operation --> src/helpers.rs:673:17 | 673 | len = len + size1; | ^^^^^^^^^^^^^^^^^ help: replace it with: `len += size1` | = note: `-D clippy::assign-op-pattern` implied by `-D clippy::all` = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#assign_op_pattern --- src/helpers.rs | 2 +- src/lib.rs | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index 9d387b0659386..c995a926d63f5 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -670,7 +670,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if byte == 0 { break; } else { - len = len + size1; + len += size1; } } diff --git a/src/lib.rs b/src/lib.rs index 285e8d10e5623..8dca869aa84b0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -10,7 +10,6 @@ #![allow(clippy::cast_lossless)] // TODO: Uncategorized. Some of these we'll want to fix, some keep ignored. #![allow( - clippy::assign_op_pattern, clippy::clone_on_copy, clippy::collapsible_else_if, clippy::collapsible_if, From 9125cc1c280ca9c13ae341a4cf12eee30c52f76d Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Fri, 29 Apr 2022 15:26:28 -0700 Subject: [PATCH 3014/3747] Resolve clippy::clone_on_copy error: using `clone` on type `std::option::Option` which implements the `Copy` trait --> src/shims/tls.rs:307:24 | 307 | let last_key = this.machine.tls.dtors_running[&active_thread].last_dtor_key.clone(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try removing the `clone` call: `this.machine.tls.dtors_running[&active_thread].last_dtor_key` | = note: `-D clippy::clone-on-copy` implied by `-D clippy::all` = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#clone_on_copy error: using `clone` on type `stacked_borrows::Item` which implements the `Copy` trait --> src/stacked_borrows.rs:317:21 | 317 | item.clone(), | ^^^^^^^^^^^^ help: try dereferencing it: `*item` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#clone_on_copy --- src/lib.rs | 1 - src/shims/tls.rs | 2 +- src/stacked_borrows.rs | 2 +- 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 8dca869aa84b0..083dff0e61e8a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -10,7 +10,6 @@ #![allow(clippy::cast_lossless)] // TODO: Uncategorized. Some of these we'll want to fix, some keep ignored. #![allow( - clippy::clone_on_copy, clippy::collapsible_else_if, clippy::collapsible_if, clippy::comparison_chain, diff --git a/src/shims/tls.rs b/src/shims/tls.rs index ceed123c7ac43..31a3e12b41bd2 100644 --- a/src/shims/tls.rs +++ b/src/shims/tls.rs @@ -304,7 +304,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx assert!(this.has_terminated(active_thread), "running TLS dtors for non-terminated thread"); // Fetch next dtor after `key`. - let last_key = this.machine.tls.dtors_running[&active_thread].last_dtor_key.clone(); + let last_key = this.machine.tls.dtors_running[&active_thread].last_dtor_key; let dtor = match this.machine.tls.fetch_tls_dtor(last_key, active_thread) { dtor @ Some(_) => dtor, // We ran each dtor once, start over from the beginning. diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 9d175e9c4d167..d6caba81713cf 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -314,7 +314,7 @@ impl<'tcx> Stack { if let SbTag::Tagged(id) = item.tag { if global.tracked_pointer_tags.contains(&id) { register_diagnostic(NonHaltingDiagnostic::PoppedPointerTag( - item.clone(), + *item, provoking_access, )); } From 1fa63f1e9b490fb33ff38781a7af57c36987a392 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Fri, 29 Apr 2022 15:29:01 -0700 Subject: [PATCH 3015/3747] Resolve clippy::extra_unused_lifetimes error: this lifetime isn't used in the function definition --> src/helpers.rs:46:20 | 46 | fn try_resolve_did<'mir, 'tcx>(tcx: TyCtxt<'tcx>, path: &[&str]) -> Option { | ^^^^ | = note: `-D clippy::extra-unused-lifetimes` implied by `-D clippy::all` = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#extra_unused_lifetimes error: this lifetime isn't used in the function definition --> src/shims/posix/fs.rs:49:12 | 49 | fn dup<'tcx>(&mut self) -> io::Result>; | ^^^^ | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#extra_unused_lifetimes error: this lifetime isn't used in the function definition --> src/shims/os_str.rs:81:41 | 81 | pub fn u16vec_to_osstring<'tcx, 'a>(u16_vec: Vec) -> InterpResult<'tcx, OsString> { | ^^ | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#extra_unused_lifetimes error: this lifetime isn't used in the function definition --> src/thread.rs:72:26 | 72 | pub fn to_u32_scalar<'tcx>(&self) -> Scalar { | ^^^^ | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#extra_unused_lifetimes --- src/helpers.rs | 2 +- src/lib.rs | 1 - src/shims/os_str.rs | 2 +- src/shims/posix/fs.rs | 10 +++++----- src/thread.rs | 2 +- 5 files changed, 8 insertions(+), 9 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index c995a926d63f5..a2073066fac0e 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -43,7 +43,7 @@ const UNIX_IO_ERROR_TABLE: &[(std::io::ErrorKind, &str)] = { }; /// Gets an instance for a path. -fn try_resolve_did<'mir, 'tcx>(tcx: TyCtxt<'tcx>, path: &[&str]) -> Option { +fn try_resolve_did<'tcx>(tcx: TyCtxt<'tcx>, path: &[&str]) -> Option { tcx.crates(()).iter().find(|&&krate| tcx.crate_name(krate).as_str() == path[0]).and_then( |krate| { let krate = DefId { krate: *krate, index: CRATE_DEF_INDEX }; diff --git a/src/lib.rs b/src/lib.rs index 083dff0e61e8a..0063753418b83 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -14,7 +14,6 @@ clippy::collapsible_if, clippy::comparison_chain, clippy::enum_variant_names, - clippy::extra_unused_lifetimes, clippy::field_reassign_with_default, clippy::from_over_into, clippy::if_same_then_else, diff --git a/src/shims/os_str.rs b/src/shims/os_str.rs index 8db75fed4a5f3..d6669b21a731a 100644 --- a/src/shims/os_str.rs +++ b/src/shims/os_str.rs @@ -78,7 +78,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(OsString::from_wide(&u16_vec[..])) } #[cfg(not(windows))] - pub fn u16vec_to_osstring<'tcx, 'a>(u16_vec: Vec) -> InterpResult<'tcx, OsString> { + pub fn u16vec_to_osstring<'tcx>(u16_vec: Vec) -> InterpResult<'tcx, OsString> { let s = String::from_utf16(&u16_vec[..]) .map_err(|_| err_unsup_format!("{:?} is not a valid utf-16 string", u16_vec))?; Ok(s.into()) diff --git a/src/shims/posix/fs.rs b/src/shims/posix/fs.rs index 73e21dd57dc40..93ca3c80198b4 100644 --- a/src/shims/posix/fs.rs +++ b/src/shims/posix/fs.rs @@ -46,7 +46,7 @@ trait FileDescriptor: std::fmt::Debug { _communicate_allowed: bool, ) -> InterpResult<'tcx, io::Result>; - fn dup<'tcx>(&mut self) -> io::Result>; + fn dup(&mut self) -> io::Result>; } impl FileDescriptor for FileHandle { @@ -107,7 +107,7 @@ impl FileDescriptor for FileHandle { } } - fn dup<'tcx>(&mut self) -> io::Result> { + fn dup(&mut self) -> io::Result> { let duplicated = self.file.try_clone()?; Ok(Box::new(FileHandle { file: duplicated, writable: self.writable })) } @@ -153,7 +153,7 @@ impl FileDescriptor for io::Stdin { throw_unsup_format!("stdin cannot be closed"); } - fn dup<'tcx>(&mut self) -> io::Result> { + fn dup(&mut self) -> io::Result> { Ok(Box::new(io::stdin())) } } @@ -203,7 +203,7 @@ impl FileDescriptor for io::Stdout { throw_unsup_format!("stdout cannot be closed"); } - fn dup<'tcx>(&mut self) -> io::Result> { + fn dup(&mut self) -> io::Result> { Ok(Box::new(io::stdout())) } } @@ -246,7 +246,7 @@ impl FileDescriptor for io::Stderr { throw_unsup_format!("stderr cannot be closed"); } - fn dup<'tcx>(&mut self) -> io::Result> { + fn dup(&mut self) -> io::Result> { Ok(Box::new(io::stderr())) } } diff --git a/src/thread.rs b/src/thread.rs index 27bc9566d8fdc..fc2c9ed779b6c 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -69,7 +69,7 @@ impl From for ThreadId { } impl ThreadId { - pub fn to_u32_scalar<'tcx>(&self) -> Scalar { + pub fn to_u32_scalar(&self) -> Scalar { Scalar::from_u32(u32::try_from(self.0).unwrap()) } } From 168e87682f1a99cb267bae1eea9d2ee6bcfc3276 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Fri, 29 Apr 2022 15:33:45 -0700 Subject: [PATCH 3016/3747] Resolve clippy::len_zero error: length comparison to one --> src/shims/posix/thread.rs:102:12 | 102 | if args.len() < 1 { | ^^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `args.is_empty()` | = note: `-D clippy::len-zero` implied by `-D clippy::all` = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#len_zero --- src/lib.rs | 1 - src/shims/posix/thread.rs | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 0063753418b83..9fbc3f8a33b6e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -17,7 +17,6 @@ clippy::field_reassign_with_default, clippy::from_over_into, clippy::if_same_then_else, - clippy::len_zero, clippy::manual_map, clippy::mem_replace_with_default, clippy::needless_borrow, diff --git a/src/shims/posix/thread.rs b/src/shims/posix/thread.rs index 7840a1e1e9708..0b8684d39eb21 100644 --- a/src/shims/posix/thread.rs +++ b/src/shims/posix/thread.rs @@ -99,7 +99,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); this.assert_target_os("linux", "prctl"); - if args.len() < 1 { + if args.is_empty() { throw_ub_format!( "incorrect number of arguments for `prctl`: got {}, expected at least 1", args.len() From 16c2400737d5f919235b9c00efaf9137bc3fd75c Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Fri, 29 Apr 2022 15:39:51 -0700 Subject: [PATCH 3017/3747] Resolve clippy::mem_replace_with_default error: replacing a value of type `T` with `T::default()` is better expressed using `std::mem::take` --> src/helpers.rs:54:29 | 54 | for item in mem::replace(&mut items, Default::default()).iter() { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `std::mem::take(&mut items)` | = note: `-D clippy::mem-replace-with-default` implied by `-D clippy::all` = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#mem_replace_with_default --- src/helpers.rs | 2 +- src/lib.rs | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index a2073066fac0e..10dbd373786af 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -51,7 +51,7 @@ fn try_resolve_did<'tcx>(tcx: TyCtxt<'tcx>, path: &[&str]) -> Option { let mut path_it = path.iter().skip(1).peekable(); while let Some(segment) = path_it.next() { - for item in mem::replace(&mut items, Default::default()).iter() { + for item in mem::take(&mut items).iter() { if item.ident.name.as_str() == *segment { if path_it.peek().is_none() { return Some(item.res.def_id()); diff --git a/src/lib.rs b/src/lib.rs index 9fbc3f8a33b6e..5d2faac57d835 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -18,7 +18,6 @@ clippy::from_over_into, clippy::if_same_then_else, clippy::manual_map, - clippy::mem_replace_with_default, clippy::needless_borrow, clippy::needless_lifetimes, clippy::needless_question_mark, From 2ca7f3b45df176295d276ce50f7f32845c7f614d Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Fri, 29 Apr 2022 15:40:28 -0700 Subject: [PATCH 3018/3747] Resolve clippy::needless_borrow error: this expression creates a reference which is immediately dereferenced by the compiler --> src/data_race.rs:565:34 | 565 | this.validate_atomic_rmw(&place, atomic)?; | ^^^^^^ help: change this to: `place` | = note: `-D clippy::needless-borrow` implied by `-D clippy::all` = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_borrow error: this expression creates a reference which is immediately dereferenced by the compiler --> src/data_race.rs:1413:27 | 1413 | clocks.clock.join(&lock); | ^^^^^ help: change this to: `lock` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_borrow error: this expression creates a reference which is immediately dereferenced by the compiler --> src/helpers.rs:326:51 | 326 | .size_and_align_of_mplace(&place)? | ^^^^^^ help: change this to: `place` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_borrow error: this expression creates a reference which is immediately dereferenced by the compiler --> src/helpers.rs:365:17 | 365 | &self.ecx | ^^^^^^^^^ help: change this to: `self.ecx` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_borrow error: this expression creates a reference which is immediately dereferenced by the compiler --> src/helpers.rs:634:47 | 634 | let seconds_place = this.mplace_field(&tp, 0)?; | ^^^ help: change this to: `tp` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_borrow error: this expression creates a reference which is immediately dereferenced by the compiler --> src/helpers.rs:637:51 | 637 | let nanoseconds_place = this.mplace_field(&tp, 1)?; | ^^^ help: change this to: `tp` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_borrow error: this expression creates a reference which is immediately dereferenced by the compiler --> src/machine.rs:547:73 | 547 | let link_name = match ecx.tcx.sess.first_attr_value_str_by_name(&attrs, sym::link_name) { | ^^^^^^ help: change this to: `attrs` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_borrow error: this expression creates a reference which is immediately dereferenced by the compiler --> src/machine.rs:576:56 | 576 | Some(data_race::AllocExtra::new_allocation(&data_race, alloc.size(), kind)) | ^^^^^^^^^^ help: change this to: `data_race` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_borrow error: this expression creates a reference which is immediately dereferenced by the compiler --> src/shims/foreign_items.rs:241:43 | 241 | .first_attr_value_str_by_name(&attrs, sym::link_name) | ^^^^^^ help: change this to: `attrs` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_borrow error: this expression creates a reference which is immediately dereferenced by the compiler --> src/shims/intrinsics.rs:778:61 | 778 | .read_immediate(&this.operand_index(&index, i)?.into())? | ^^^^^^ help: change this to: `index` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_borrow error: this expression creates a reference which is immediately dereferenced by the compiler --> src/shims/intrinsics.rs:1195:44 | 1195 | this.write_immediate(*old, &dest)?; // old value is returned | ^^^^^ help: change this to: `dest` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_borrow error: this expression creates a reference which is immediately dereferenced by the compiler --> src/shims/intrinsics.rs:1200:44 | 1200 | this.write_immediate(*old, &dest)?; // old value is returned | ^^^^^ help: change this to: `dest` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_borrow error: this expression creates a reference which is immediately dereferenced by the compiler --> src/shims/posix/fs.rs:54:12 | 54 | Ok(&self) | ^^^^^ help: change this to: `self` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_borrow error: this expression creates a reference which is immediately dereferenced by the compiler --> src/shims/posix/fs.rs:654:49 | 654 | let io_result = maybe_sync_file(&file, *writable, File::sync_all); | ^^^^^ help: change this to: `file` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_borrow error: this expression creates a reference which is immediately dereferenced by the compiler --> src/shims/posix/fs.rs:746:52 | 746 | file_descriptor.write(communicate, &bytes)?.map(|c| i64::try_from(c).unwrap()); | ^^^^^^ help: change this to: `bytes` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_borrow error: this expression creates a reference which is immediately dereferenced by the compiler --> src/shims/posix/fs.rs:1494:45 | 1494 | let io_result = maybe_sync_file(&file, *writable, File::sync_all); | ^^^^^ help: change this to: `file` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_borrow error: this expression creates a reference which is immediately dereferenced by the compiler --> src/shims/posix/fs.rs:1516:45 | 1516 | let io_result = maybe_sync_file(&file, *writable, File::sync_data); | ^^^^^ help: change this to: `file` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_borrow error: this expression creates a reference which is immediately dereferenced by the compiler --> src/shims/posix/fs.rs:1561:45 | 1561 | let io_result = maybe_sync_file(&file, *writable, File::sync_data); | ^^^^^ help: change this to: `file` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_borrow error: this expression creates a reference which is immediately dereferenced by the compiler --> src/shims/env.rs:232:65 | 232 | let var_ptr = alloc_env_var_as_c_str(&name, &value, &mut this)?; | ^^^^^^^^^ help: change this to: `this` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_borrow error: this expression creates a reference which is immediately dereferenced by the compiler --> src/shims/env.rs:277:68 | 277 | let var_ptr = alloc_env_var_as_wide_str(&name, &value, &mut this)?; | ^^^^^^^^^ help: change this to: `this` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_borrow error: this expression creates a reference which is immediately dereferenced by the compiler --> src/shims/env.rs:328:37 | 328 | let buf = this.read_pointer(&buf_op)?; | ^^^^^^^ help: change this to: `buf_op` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_borrow error: this expression creates a reference which is immediately dereferenced by the compiler --> src/shims/env.rs:329:37 | 329 | let size = this.read_scalar(&size_op)?.to_machine_usize(&*this.tcx)?; | ^^^^^^^^ help: change this to: `size_op` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_borrow --- src/data_race.rs | 4 ++-- src/helpers.rs | 8 ++++---- src/lib.rs | 1 - src/machine.rs | 4 ++-- src/shims/env.rs | 12 ++++++------ src/shims/foreign_items.rs | 2 +- src/shims/intrinsics.rs | 6 +++--- src/shims/posix/fs.rs | 12 ++++++------ 8 files changed, 24 insertions(+), 25 deletions(-) diff --git a/src/data_race.rs b/src/data_race.rs index 7625763a3bb4f..b2bd29c5cb19a 100644 --- a/src/data_race.rs +++ b/src/data_race.rs @@ -562,7 +562,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { this.allow_data_races_mut(|this| this.write_immediate(**new_val, &(*place).into()))?; - this.validate_atomic_rmw(&place, atomic)?; + this.validate_atomic_rmw(place, atomic)?; // Return the old value. Ok(old) @@ -1410,7 +1410,7 @@ impl GlobalState { /// incremented. pub fn validate_lock_acquire(&self, lock: &VClock, thread: ThreadId) { let (_, mut clocks) = self.load_thread_state_mut(thread); - clocks.clock.join(&lock); + clocks.clock.join(lock); } /// Release a lock handle, express that this happens-before diff --git a/src/helpers.rs b/src/helpers.rs index 10dbd373786af..1d84b3fdf16ef 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -323,7 +323,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx trace!("unsafe_cell_action on {:?}", place.ptr); // We need a size to go on. let unsafe_cell_size = this - .size_and_align_of_mplace(&place)? + .size_and_align_of_mplace(place)? .map(|(size, _)| size) // for extern types, just cover what we can .unwrap_or_else(|| place.layout.size); @@ -362,7 +362,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx #[inline(always)] fn ecx(&self) -> &MiriEvalContext<'mir, 'tcx> { - &self.ecx + self.ecx } // Hook to detect `UnsafeCell`. @@ -631,10 +631,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// `EINVAL` in this case. fn read_timespec(&mut self, tp: &MPlaceTy<'tcx, Tag>) -> InterpResult<'tcx, Option> { let this = self.eval_context_mut(); - let seconds_place = this.mplace_field(&tp, 0)?; + let seconds_place = this.mplace_field(tp, 0)?; let seconds_scalar = this.read_scalar(&seconds_place.into())?; let seconds = seconds_scalar.to_machine_isize(this)?; - let nanoseconds_place = this.mplace_field(&tp, 1)?; + let nanoseconds_place = this.mplace_field(tp, 1)?; let nanoseconds_scalar = this.read_scalar(&nanoseconds_place.into())?; let nanoseconds = nanoseconds_scalar.to_machine_isize(this)?; diff --git a/src/lib.rs b/src/lib.rs index 5d2faac57d835..598d9cc96ae6f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -18,7 +18,6 @@ clippy::from_over_into, clippy::if_same_then_else, clippy::manual_map, - clippy::needless_borrow, clippy::needless_lifetimes, clippy::needless_question_mark, clippy::needless_return, diff --git a/src/machine.rs b/src/machine.rs index c0f833f17610a..0a8a229c8aa2c 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -544,7 +544,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { def_id: DefId, ) -> InterpResult<'tcx, Pointer> { let attrs = ecx.tcx.get_attrs(def_id); - let link_name = match ecx.tcx.sess.first_attr_value_str_by_name(&attrs, sym::link_name) { + let link_name = match ecx.tcx.sess.first_attr_value_str_by_name(attrs, sym::link_name) { Some(name) => name, None => ecx.tcx.item_name(def_id), }; @@ -573,7 +573,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { None }; let race_alloc = if let Some(data_race) = &ecx.machine.data_race { - Some(data_race::AllocExtra::new_allocation(&data_race, alloc.size(), kind)) + Some(data_race::AllocExtra::new_allocation(data_race, alloc.size(), kind)) } else { None }; diff --git a/src/shims/env.rs b/src/shims/env.rs index 3b1b1f011e3e7..915decc28725d 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -210,7 +210,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx name_op: &OpTy<'tcx, Tag>, value_op: &OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, i32> { - let mut this = self.eval_context_mut(); + let this = self.eval_context_mut(); let target_os = &this.tcx.sess.target.os; assert!( target_os == "linux" || target_os == "macos", @@ -229,7 +229,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } if let Some((name, value)) = new { - let var_ptr = alloc_env_var_as_c_str(&name, &value, &mut this)?; + let var_ptr = alloc_env_var_as_c_str(&name, &value, this)?; if let Some(var) = this.machine.env_vars.map.insert(name, var_ptr) { this.deallocate_ptr(var, None, MiriMemoryKind::Runtime.into())?; } @@ -249,7 +249,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx name_op: &OpTy<'tcx, Tag>, // LPCWSTR value_op: &OpTy<'tcx, Tag>, // LPCWSTR ) -> InterpResult<'tcx, i32> { - let mut this = self.eval_context_mut(); + let this = self.eval_context_mut(); this.assert_target_os("windows", "SetEnvironmentVariableW"); let name_ptr = this.read_pointer(name_op)?; @@ -274,7 +274,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(1) // return non-zero on success } else { let value = this.read_os_str_from_wide_str(value_ptr)?; - let var_ptr = alloc_env_var_as_wide_str(&name, &value, &mut this)?; + let var_ptr = alloc_env_var_as_wide_str(&name, &value, this)?; if let Some(var) = this.machine.env_vars.map.insert(name, var_ptr) { this.deallocate_ptr(var, None, MiriMemoryKind::Runtime.into())?; } @@ -325,8 +325,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "`getcwd` is only available for the UNIX target family" ); - let buf = this.read_pointer(&buf_op)?; - let size = this.read_scalar(&size_op)?.to_machine_usize(&*this.tcx)?; + let buf = this.read_pointer(buf_op)?; + let size = this.read_scalar(size_op)?.to_machine_usize(&*this.tcx)?; if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { this.reject_in_isolation("`getcwd`", reject_with)?; diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index ef88c550ecb2e..9256013fb157f 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -238,7 +238,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let link_name = this .tcx .sess - .first_attr_value_str_by_name(&attrs, sym::link_name) + .first_attr_value_str_by_name(attrs, sym::link_name) .unwrap_or_else(|| this.tcx.item_name(def_id)); let tcx = this.tcx.tcx; diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 1b69be5153b06..06537b5d333bf 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -775,7 +775,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx for i in 0..dest_len { let src_index: u64 = this - .read_immediate(&this.operand_index(&index, i)?.into())? + .read_immediate(&this.operand_index(index, i)?.into())? .to_scalar()? .to_u32()? .into(); @@ -1192,12 +1192,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx match atomic_op { AtomicOp::Min => { let old = this.atomic_min_max_scalar(&place, rhs, true, atomic)?; - this.write_immediate(*old, &dest)?; // old value is returned + this.write_immediate(*old, dest)?; // old value is returned Ok(()) } AtomicOp::Max => { let old = this.atomic_min_max_scalar(&place, rhs, false, atomic)?; - this.write_immediate(*old, &dest)?; // old value is returned + this.write_immediate(*old, dest)?; // old value is returned Ok(()) } AtomicOp::MirOp(op, neg) => { diff --git a/src/shims/posix/fs.rs b/src/shims/posix/fs.rs index 93ca3c80198b4..7957edf5c65eb 100644 --- a/src/shims/posix/fs.rs +++ b/src/shims/posix/fs.rs @@ -51,7 +51,7 @@ trait FileDescriptor: std::fmt::Debug { impl FileDescriptor for FileHandle { fn as_file_handle<'tcx>(&self) -> InterpResult<'tcx, &FileHandle> { - Ok(&self) + Ok(self) } fn read<'tcx>( @@ -651,7 +651,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if let Some(file_descriptor) = this.machine.file_handler.handles.get(&fd) { // FIXME: Support fullfsync for all FDs let FileHandle { file, writable } = file_descriptor.as_file_handle()?; - let io_result = maybe_sync_file(&file, *writable, File::sync_all); + let io_result = maybe_sync_file(file, *writable, File::sync_all); this.try_unwrap_io_result(io_result) } else { this.handle_not_found() @@ -743,7 +743,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if let Some(file_descriptor) = this.machine.file_handler.handles.get(&fd) { let bytes = this.read_bytes_ptr(buf, Size::from_bytes(count))?; let result = - file_descriptor.write(communicate, &bytes)?.map(|c| i64::try_from(c).unwrap()); + file_descriptor.write(communicate, bytes)?.map(|c| i64::try_from(c).unwrap()); this.try_unwrap_io_result(result) } else { this.handle_not_found() @@ -1491,7 +1491,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if let Some(file_descriptor) = this.machine.file_handler.handles.get(&fd) { // FIXME: Support fsync for all FDs let FileHandle { file, writable } = file_descriptor.as_file_handle()?; - let io_result = maybe_sync_file(&file, *writable, File::sync_all); + let io_result = maybe_sync_file(file, *writable, File::sync_all); this.try_unwrap_io_result(io_result) } else { this.handle_not_found() @@ -1513,7 +1513,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if let Some(file_descriptor) = this.machine.file_handler.handles.get(&fd) { // FIXME: Support fdatasync for all FDs let FileHandle { file, writable } = file_descriptor.as_file_handle()?; - let io_result = maybe_sync_file(&file, *writable, File::sync_data); + let io_result = maybe_sync_file(file, *writable, File::sync_data); this.try_unwrap_io_result(io_result) } else { this.handle_not_found() @@ -1558,7 +1558,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if let Some(file_descriptor) = this.machine.file_handler.handles.get(&fd) { // FIXME: Support sync_data_range for all FDs let FileHandle { file, writable } = file_descriptor.as_file_handle()?; - let io_result = maybe_sync_file(&file, *writable, File::sync_data); + let io_result = maybe_sync_file(file, *writable, File::sync_data); this.try_unwrap_io_result(io_result) } else { this.handle_not_found() From c6bd81bbf30bc5d36aae8bf6e5613737f139a7ac Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Fri, 29 Apr 2022 15:43:36 -0700 Subject: [PATCH 3019/3747] Resolve clippy::needless_lifetimes error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) --> src/range_map.rs:66:5 | 66 | pub fn iter<'a>(&'a self, offset: Size, len: Size) -> impl Iterator + 'a { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::needless-lifetimes` implied by `-D clippy::all` = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_lifetimes error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) --> src/range_map.rs:86:5 | 86 | pub fn iter_mut_all<'a>(&'a mut self) -> impl Iterator + 'a { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_lifetimes error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) --> src/range_map.rs:122:5 | 122 | / pub fn iter_mut<'a>( 123 | | &'a mut self, 124 | | offset: Size, 125 | | len: Size, 126 | | ) -> impl Iterator + 'a | |_____________________________________________________^ | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_lifetimes error: explicit lifetimes given in parameter types where they could be elided (or replaced with `'_` if needed by type declaration) --> src/shims/intrinsics.rs:1391:1 | 1391 | fn simd_element_to_bool<'tcx>(elem: ImmTy<'tcx, Tag>) -> InterpResult<'tcx, bool> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_lifetimes --- src/range_map.rs | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/range_map.rs b/src/range_map.rs index 8b5a3af5bac5b..f0507ffabad0c 100644 --- a/src/range_map.rs +++ b/src/range_map.rs @@ -63,7 +63,7 @@ impl RangeMap { /// through interior mutability. /// /// The iterator also provides the offset of the given element. - pub fn iter<'a>(&'a self, offset: Size, len: Size) -> impl Iterator + 'a { + pub fn iter(&self, offset: Size, len: Size) -> impl Iterator { let offset = offset.bytes(); let len = len.bytes(); // Compute a slice starting with the elements we care about. @@ -83,7 +83,7 @@ impl RangeMap { .map(|elem| (Size::from_bytes(elem.range.start), &elem.data)) } - pub fn iter_mut_all<'a>(&'a mut self) -> impl Iterator + 'a { + pub fn iter_mut_all(&mut self) -> impl Iterator { self.v.iter_mut().map(|elem| &mut elem.data) } @@ -119,11 +119,7 @@ impl RangeMap { /// Moreover, this will opportunistically merge neighbouring equal blocks. /// /// The iterator also provides the offset of the given element. - pub fn iter_mut<'a>( - &'a mut self, - offset: Size, - len: Size, - ) -> impl Iterator + 'a + pub fn iter_mut(&mut self, offset: Size, len: Size) -> impl Iterator where T: Clone + PartialEq, { From 6e2297fde014ea5a89765bde4ade220b8f50fd7d Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Fri, 29 Apr 2022 15:47:57 -0700 Subject: [PATCH 3020/3747] Resolve clippy::needless_question_mark error: question mark operator is useless here --> src/helpers.rs:86:16 | 86 | return Ok(const_val.check_init()?); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try removing question mark and `Ok()`: `const_val.check_init()` | = note: `-D clippy::needless-question-mark` implied by `-D clippy::all` = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_question_mark --- src/helpers.rs | 2 +- src/lib.rs | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index 1d84b3fdf16ef..b9ac4afff36d8 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -83,7 +83,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let cid = GlobalId { instance, promoted: None }; let const_val = this.eval_to_allocation(cid)?; let const_val = this.read_scalar(&const_val.into())?; - return Ok(const_val.check_init()?); + const_val.check_init() } /// Helper function to get a `libc` constant as a `Scalar`. diff --git a/src/lib.rs b/src/lib.rs index 598d9cc96ae6f..cd40fa419763b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -19,7 +19,6 @@ clippy::if_same_then_else, clippy::manual_map, clippy::needless_lifetimes, - clippy::needless_question_mark, clippy::needless_return, clippy::new_without_default, clippy::op_ref, From a893618854b3c22fbe54a9b771ade85edada4143 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Fri, 29 Apr 2022 14:37:54 -0700 Subject: [PATCH 3021/3747] Implement llvm.x86.addcarry.64 --- src/shims/foreign_items.rs | 15 +++++++++++++++ tests/run-pass/intrinsics-x86.rs | 22 ++++++++++++++++++++++ 2 files changed, 37 insertions(+) create mode 100644 tests/run-pass/intrinsics-x86.rs diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index ef88c550ecb2e..807fca8170169 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -671,6 +671,21 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // Architecture-specific shims + "llvm.x86.addcarry.64" if this.tcx.sess.target.arch == "x86_64" => { + // Computes u8+u64+u64, returning tuple (u8,u64) comprising the output carry and truncated sum. + let &[ref c_in, ref a, ref b] = this.check_shim(abi, Abi::Unadjusted, link_name, args)?; + let c_in = this.read_scalar(c_in)?.to_u8()?; + let a = this.read_scalar(a)?.to_u64()?; + let b = this.read_scalar(b)?.to_u64()?; + + let wide_sum = c_in as u128 + a as u128 + b as u128; + let (c_out, sum) = ((wide_sum >> 64) as u8, wide_sum as u64); + + let c_out_field = this.place_field(dest, 0)?; + this.write_scalar(Scalar::from_u8(c_out), &c_out_field)?; + let sum_field = this.place_field(dest, 1)?; + this.write_scalar(Scalar::from_u64(sum), &sum_field)?; + } "llvm.x86.sse2.pause" if this.tcx.sess.target.arch == "x86" || this.tcx.sess.target.arch == "x86_64" => { let &[] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; this.yield_active_thread(); diff --git a/tests/run-pass/intrinsics-x86.rs b/tests/run-pass/intrinsics-x86.rs new file mode 100644 index 0000000000000..88cd782e70a46 --- /dev/null +++ b/tests/run-pass/intrinsics-x86.rs @@ -0,0 +1,22 @@ +#[cfg(target_arch = "x86_64")] +mod x86_64 { + use core::arch::x86_64 as arch; + + fn adc(c_in: u8, a: u64, b: u64) -> (u8, u64) { + let mut sum = 0; + // SAFETY: There are no safety requirements for calling `_addcarry_u64`. + // It's just unsafe for API consistency with other intrinsics. + let c_out = unsafe { arch::_addcarry_u64(c_in, a, b, &mut sum) }; + (c_out, sum) + } + + pub fn main() { + assert_eq!(adc(1, 1, 1), (0, 3)); + assert_eq!(adc(3, u64::MAX, u64::MAX), (2, 1)); + } +} + +fn main() { + #[cfg(target_arch = "x86_64")] + x86_64::main(); +} From 519755a82356895545a8e383c6aa27aba20eabd6 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Fri, 29 Apr 2022 15:48:24 -0700 Subject: [PATCH 3022/3747] Resolve clippy::needless_return error: unneeded `return` statement --> src/helpers.rs:734:13 | 734 | return Ok(()); | ^^^^^^^^^^^^^^ help: remove `return`: `Ok(())` | = note: `-D clippy::needless-return` implied by `-D clippy::all` = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_return error: unneeded `return` statement --> src/range_map.rs:113:9 | 113 | return true; | ^^^^^^^^^^^^ help: remove `return`: `true` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_return error: unneeded `return` statement --> src/shims/posix/fs.rs:648:25 | 648 | None => return this.handle_not_found(), | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove `return`: `this.handle_not_found()` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_return error: unneeded `return` statement --> src/shims/panic.rs:62:9 | 62 | return Ok(()); | ^^^^^^^^^^^^^^ help: remove `return`: `Ok(())` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_return error: unneeded `return` statement --> src/shims/panic.rs:115:9 | 115 | return Ok(()); | ^^^^^^^^^^^^^^ help: remove `return`: `Ok(())` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_return error: unneeded `return` statement --> src/thread.rs:477:9 | 477 | return free_tls_statics; | ^^^^^^^^^^^^^^^^^^^^^^^^ help: remove `return`: `free_tls_statics` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_return error: unneeded `return` statement --> src/thread.rs:459:17 | 459 | return false; | ^^^^^^^^^^^^^ help: remove `return`: `false` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#needless_return --- src/helpers.rs | 2 +- src/lib.rs | 1 - src/range_map.rs | 2 +- src/shims/panic.rs | 4 ++-- src/shims/posix/fs.rs | 2 +- src/thread.rs | 4 ++-- 6 files changed, 7 insertions(+), 8 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index b9ac4afff36d8..76a65bcbb76ea 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -731,7 +731,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // message is slightly different here to make automated analysis easier let error_msg = format!("unsupported Miri functionality: {}", error_msg.as_ref()); this.start_panic(error_msg.as_ref(), StackPopUnwind::Skip)?; - return Ok(()); + Ok(()) } else { throw_unsup_format!("{}", error_msg.as_ref()); } diff --git a/src/lib.rs b/src/lib.rs index cd40fa419763b..50d6a09eb8917 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -19,7 +19,6 @@ clippy::if_same_then_else, clippy::manual_map, clippy::needless_lifetimes, - clippy::needless_return, clippy::new_without_default, clippy::op_ref, clippy::redundant_closure, diff --git a/src/range_map.rs b/src/range_map.rs index f0507ffabad0c..474ad9dcccd93 100644 --- a/src/range_map.rs +++ b/src/range_map.rs @@ -110,7 +110,7 @@ impl RangeMap { // Copy the data, and insert second element. let second = Elem { range: second_range, data: elem.data.clone() }; self.v.insert(index + 1, second); - return true; + true } /// Provides mutable iteration over everything in the given range. As a side-effect, diff --git a/src/shims/panic.rs b/src/shims/panic.rs index 8f4e3f578ee94..96d3b7c9f891e 100644 --- a/src/shims/panic.rs +++ b/src/shims/panic.rs @@ -59,7 +59,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Jump to the unwind block to begin unwinding. this.unwind_to_block(unwind)?; - return Ok(()); + Ok(()) } /// Handles the `try` intrinsic, the underlying implementation of `std::panicking::try`. @@ -112,7 +112,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Some(CatchUnwindData { catch_fn, data, dest: *dest, ret }); } - return Ok(()); + Ok(()) } fn handle_stack_pop( diff --git a/src/shims/posix/fs.rs b/src/shims/posix/fs.rs index 7957edf5c65eb..f224a1461f93d 100644 --- a/src/shims/posix/fs.rs +++ b/src/shims/posix/fs.rs @@ -645,7 +645,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } } - None => return this.handle_not_found(), + None => this.handle_not_found(), } } else if this.tcx.sess.target.os == "macos" && cmd == this.eval_libc_i32("F_FULLFSYNC")? { if let Some(file_descriptor) = this.machine.file_handler.handles.get(&fd) { diff --git a/src/thread.rs b/src/thread.rs index fc2c9ed779b6c..2ed8b3a7ce1cc 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -456,7 +456,7 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { // Delete this static from the map and from memory. // We cannot free directly here as we cannot use `?` in this context. free_tls_statics.push(alloc_id); - return false; + false }); } // Set the thread into a terminated state in the data-race detector @@ -474,7 +474,7 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { thread.state = ThreadState::Enabled; } } - return free_tls_statics; + free_tls_statics } /// Decide which action to take next and on which thread. From 95510587ff5d827cf2fd9aea130f2f0113d09e20 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Fri, 29 Apr 2022 15:54:09 -0700 Subject: [PATCH 3023/3747] Resolve clippy::op_ref error: taken reference of right operand --> src/shims/env.rs:53:63 | 53 | true => !excluded_env_vars.iter().any(|v| v.as_str() == &name), | ^^^^^^^^^^^^^^----- | | | help: use the right value directly: `name` | = note: `-D clippy::op-ref` implied by `-D clippy::all` = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#op_ref error: taken reference of right operand --> src/shims/env.rs:54:71 | 54 | false => config.forwarded_env_vars.iter().any(|v| v.as_str() == &name), | ^^^^^^^^^^^^^^----- | | | help: use the right value directly: `name` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#op_ref --- src/lib.rs | 1 - src/shims/env.rs | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 50d6a09eb8917..cd62c0c1f3fe9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -20,7 +20,6 @@ clippy::manual_map, clippy::needless_lifetimes, clippy::new_without_default, - clippy::op_ref, clippy::redundant_closure, clippy::redundant_field_names, clippy::single_char_add_str, diff --git a/src/shims/env.rs b/src/shims/env.rs index 915decc28725d..34a716f08ab2f 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -50,8 +50,8 @@ impl<'tcx> EnvVars<'tcx> { if ecx.machine.communicate() || !config.forwarded_env_vars.is_empty() { for (name, value) in env::vars_os() { let forward = match ecx.machine.communicate() { - true => !excluded_env_vars.iter().any(|v| v.as_str() == &name), - false => config.forwarded_env_vars.iter().any(|v| v.as_str() == &name), + true => !excluded_env_vars.iter().any(|v| **v == name), + false => config.forwarded_env_vars.iter().any(|v| **v == name), }; if forward { let var_ptr = match target_os { From 48f4f2734d221f06990613ad364e1065608463f4 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Fri, 29 Apr 2022 15:55:55 -0700 Subject: [PATCH 3024/3747] Resolve clippy::redundant_closure error: redundant closure --> src/data_race.rs:787:18 | 787 | .map(|idx| VectorIdx::new(idx)) | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace the closure with the function itself: `VectorIdx::new` | = note: `-D clippy::redundant-closure` implied by `-D clippy::all` = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#redundant_closure error: redundant closure --> src/thread.rs:61:31 | 61 | u32::try_from(id).map(|id_u32| Self(id_u32)) | ^^^^^^^^^^^^^^^^^^^^^ help: replace the closure with the function itself: `Self` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#redundant_closure --- src/data_race.rs | 2 +- src/lib.rs | 1 - src/thread.rs | 2 +- 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/data_race.rs b/src/data_race.rs index b2bd29c5cb19a..d249d28d03f54 100644 --- a/src/data_race.rs +++ b/src/data_race.rs @@ -784,7 +784,7 @@ impl VClockAlloc { None } }) - .map(|idx| VectorIdx::new(idx)) + .map(VectorIdx::new) } /// Report a data-race found in the program. diff --git a/src/lib.rs b/src/lib.rs index cd62c0c1f3fe9..262c4e2e28989 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -20,7 +20,6 @@ clippy::manual_map, clippy::needless_lifetimes, clippy::new_without_default, - clippy::redundant_closure, clippy::redundant_field_names, clippy::single_char_add_str, clippy::single_char_pattern, diff --git a/src/thread.rs b/src/thread.rs index 2ed8b3a7ce1cc..0d15f60c23bfe 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -58,7 +58,7 @@ impl Idx for ThreadId { impl TryFrom for ThreadId { type Error = TryFromIntError; fn try_from(id: u64) -> Result { - u32::try_from(id).map(|id_u32| Self(id_u32)) + u32::try_from(id).map(Self) } } From 2f32221fe4d3508e1823514b8638a2ee872c2fa5 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Fri, 29 Apr 2022 15:56:46 -0700 Subject: [PATCH 3025/3747] Resolve clippy::redundant_field_names error: redundant field names in struct initialization --> src/helpers.rs:199:34 | 199 | let place = mir::Place { local: local, projection: List::empty() }; | ^^^^^^^^^^^^ help: replace it with: `local` | = note: `-D clippy::redundant-field-names` implied by `-D clippy::all` = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#redundant_field_names error: redundant field names in struct initialization --> src/thread.rs:238:13 | 238 | threads: threads, | ^^^^^^^^^^^^^^^^ help: replace it with: `threads` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#redundant_field_names --- src/helpers.rs | 2 +- src/lib.rs | 1 - src/thread.rs | 2 +- 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index 76a65bcbb76ea..57c85575942bb 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -196,7 +196,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// Get the `Place` for a local fn local_place(&mut self, local: mir::Local) -> InterpResult<'tcx, PlaceTy<'tcx, Tag>> { let this = self.eval_context_mut(); - let place = mir::Place { local: local, projection: List::empty() }; + let place = mir::Place { local, projection: List::empty() }; this.eval_place(place) } diff --git a/src/lib.rs b/src/lib.rs index 262c4e2e28989..5095fc6914306 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -20,7 +20,6 @@ clippy::manual_map, clippy::needless_lifetimes, clippy::new_without_default, - clippy::redundant_field_names, clippy::single_char_add_str, clippy::single_char_pattern, clippy::single_match, diff --git a/src/thread.rs b/src/thread.rs index 0d15f60c23bfe..031463f8ea74f 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -235,7 +235,7 @@ impl<'mir, 'tcx> Default for ThreadManager<'mir, 'tcx> { threads.push(main_thread); Self { active_thread: ThreadId::new(0), - threads: threads, + threads, sync: SynchronizationState::default(), thread_local_alloc_ids: Default::default(), yield_active_thread: false, From 277d0b53a7a0b8f3112baaeb2d5f31ee76bba646 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Fri, 29 Apr 2022 15:57:35 -0700 Subject: [PATCH 3026/3747] Resolve clippy::single_char_add_str error: calling `push_str()` using a single-character string literal --> src/diagnostics.rs:299:9 | 299 | helps.last_mut().unwrap().1.push_str("\n"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `push` with a character literal: `helps.last_mut().unwrap().1.push('\n')` | = note: `-D clippy::single-char-add-str` implied by `-D clippy::all` = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#single_char_add_str --- src/diagnostics.rs | 2 +- src/lib.rs | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/diagnostics.rs b/src/diagnostics.rs index ce66dea5e746f..1a39a1ff332e9 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -296,7 +296,7 @@ fn report_msg<'mir, 'tcx>( // Show help messages. if !helps.is_empty() { // Add visual separator before backtrace. - helps.last_mut().unwrap().1.push_str("\n"); + helps.last_mut().unwrap().1.push('\n'); for (span_data, help) in helps { if let Some(span_data) = span_data { err.span_help(span_data.span(), &help); diff --git a/src/lib.rs b/src/lib.rs index 5095fc6914306..536fc957a3f16 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -20,7 +20,6 @@ clippy::manual_map, clippy::needless_lifetimes, clippy::new_without_default, - clippy::single_char_add_str, clippy::single_char_pattern, clippy::single_match, clippy::unnecessary_mut_passed, From 1986f90c6ae95f2c1f49f4c11390abb9a5eb4876 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Fri, 29 Apr 2022 15:58:13 -0700 Subject: [PATCH 3027/3747] Resolve clippy::single_char_pattern error: single-character string constant used as pattern --> src/helpers.rs:805:36 | 805 | .map(|crates| crates.split(",").map(|krate| krate.to_string()).collect::>()) | ^^^ help: try using a `char` instead: `','` | = note: `-D clippy::single-char-pattern` implied by `-D clippy::all` = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#single_char_pattern --- src/helpers.rs | 2 +- src/lib.rs | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index 57c85575942bb..34156c54b43d8 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -802,7 +802,7 @@ pub fn get_local_crates(tcx: &TyCtxt<'_>) -> Vec { // Convert the local crate names from the passed-in config into CrateNums so that they can // be looked up quickly during execution let local_crate_names = std::env::var("MIRI_LOCAL_CRATES") - .map(|crates| crates.split(",").map(|krate| krate.to_string()).collect::>()) + .map(|crates| crates.split(',').map(|krate| krate.to_string()).collect::>()) .unwrap_or_default(); let mut local_crates = Vec::new(); for &crate_num in tcx.crates(()) { diff --git a/src/lib.rs b/src/lib.rs index 536fc957a3f16..e67f161e863b5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -20,7 +20,6 @@ clippy::manual_map, clippy::needless_lifetimes, clippy::new_without_default, - clippy::single_char_pattern, clippy::single_match, clippy::unnecessary_mut_passed, clippy::useless_conversion, From 4b523fce18e91dff63722f5de70d48a6d5dd1b83 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Fri, 29 Apr 2022 15:59:03 -0700 Subject: [PATCH 3028/3747] Resolve clippy::unnecessary_mut_passed error: the method `validate_lock_acquire` doesn't need a mutable reference --> src/sync.rs:477:49 | 477 | data_race.validate_lock_acquire(&mut condvar.data_race, waiter.thread); | ^^^^^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::unnecessary-mut-passed` implied by `-D clippy::all` = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_mut_passed --- src/lib.rs | 1 - src/sync.rs | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index e67f161e863b5..8e21294fd8dca 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -21,7 +21,6 @@ clippy::needless_lifetimes, clippy::new_without_default, clippy::single_match, - clippy::unnecessary_mut_passed, clippy::useless_conversion, clippy::useless_format )] diff --git a/src/sync.rs b/src/sync.rs index bbcd39333c780..ac1687a22e305 100644 --- a/src/sync.rs +++ b/src/sync.rs @@ -474,7 +474,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } condvar.waiters.pop_front().map(|waiter| { if let Some(data_race) = data_race { - data_race.validate_lock_acquire(&mut condvar.data_race, waiter.thread); + data_race.validate_lock_acquire(&condvar.data_race, waiter.thread); } (waiter.thread, waiter.mutex) }) From d35c82f79f343fa0d0c0c352e9f43a74c2b6513e Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Fri, 29 Apr 2022 15:59:42 -0700 Subject: [PATCH 3029/3747] Resolve clippy::useless_conversion error: useless conversion to the same type: `rustc_const_eval::interpret::Pointer>` --> src/helpers.rs:668:36 | 668 | this.get_ptr_alloc(ptr.offset(len, this)?.into(), size1, Align::ONE)?.unwrap(); // not a ZST, so we will get a result | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into()`: `ptr.offset(len, this)?` | = note: `-D clippy::useless-conversion` implied by `-D clippy::all` = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#useless_conversion error: useless conversion to the same type: `rustc_const_eval::interpret::Pointer>` --> src/helpers.rs:678:29 | 678 | this.read_bytes_ptr(ptr.into(), len) | ^^^^^^^^^^ help: consider removing `.into()`: `ptr` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#useless_conversion error: useless conversion to the same type: `rustc_const_eval::interpret::Pointer>` --> src/helpers.rs:690:44 | 690 | let alloc = this.get_ptr_alloc(ptr.into(), size2, align2)?.unwrap(); // not a ZST, so we will get a result | ^^^^^^^^^^ help: consider removing `.into()`: `ptr` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#useless_conversion error: useless conversion to the same type: `rustc_const_eval::interpret::OpTy` --> src/shims/intrinsics.rs:778:42 | 778 | .read_immediate(&this.operand_index(index, i)?.into())? | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into()`: `this.operand_index(index, i)?` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#useless_conversion error: useless conversion to the same type: `u32` --> src/shims/posix/fs.rs:1171:26 | 1171 | builder.mode(mode.into()); | ^^^^^^^^^^^ help: consider removing `.into()`: `mode` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#useless_conversion error: useless conversion to the same type: `std::ffi::OsString` --> src/shims/env.rs:67:53 | 67 | ecx.machine.env_vars.map.insert(OsString::from(name), var_ptr); | ^^^^^^^^^^^^^^^^^^^^ help: consider removing `OsString::from()`: `name` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#useless_conversion error: useless conversion to the same type: `rustc_const_eval::interpret::Scalar` --> src/shims/tls.rs:102:44 | 102 | Ok(value.unwrap_or_else(|| Scalar::null_ptr(cx).into())) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into()`: `Scalar::null_ptr(cx)` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#useless_conversion error: useless conversion to the same type: `u32` --> src/thread.rs:73:26 | 73 | Scalar::from_u32(u32::try_from(self.0).unwrap()) | ^^^^^^^^^^^^^^^^^^^^^ | = help: consider removing `u32::try_from()` = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#useless_conversion --- src/helpers.rs | 7 +++---- src/lib.rs | 1 - src/shims/env.rs | 2 +- src/shims/intrinsics.rs | 2 +- src/shims/posix/fs.rs | 2 +- src/shims/tls.rs | 2 +- src/thread.rs | 2 +- 7 files changed, 8 insertions(+), 10 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index 34156c54b43d8..107a2551995ad 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -664,8 +664,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx loop { // FIXME: We are re-getting the allocation each time around the loop. // Would be nice if we could somehow "extend" an existing AllocRange. - let alloc = - this.get_ptr_alloc(ptr.offset(len, this)?.into(), size1, Align::ONE)?.unwrap(); // not a ZST, so we will get a result + let alloc = this.get_ptr_alloc(ptr.offset(len, this)?, size1, Align::ONE)?.unwrap(); // not a ZST, so we will get a result let byte = alloc.read_scalar(alloc_range(Size::ZERO, size1))?.to_u8()?; if byte == 0 { break; @@ -675,7 +674,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // Step 2: get the bytes. - this.read_bytes_ptr(ptr.into(), len) + this.read_bytes_ptr(ptr, len) } fn read_wide_str(&self, mut ptr: Pointer>) -> InterpResult<'tcx, Vec> { @@ -687,7 +686,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx loop { // FIXME: We are re-getting the allocation each time around the loop. // Would be nice if we could somehow "extend" an existing AllocRange. - let alloc = this.get_ptr_alloc(ptr.into(), size2, align2)?.unwrap(); // not a ZST, so we will get a result + let alloc = this.get_ptr_alloc(ptr, size2, align2)?.unwrap(); // not a ZST, so we will get a result let wchar = alloc.read_scalar(alloc_range(Size::ZERO, size2))?.to_u16()?; if wchar == 0 { break; diff --git a/src/lib.rs b/src/lib.rs index 8e21294fd8dca..0699dfba4b7b4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -21,7 +21,6 @@ clippy::needless_lifetimes, clippy::new_without_default, clippy::single_match, - clippy::useless_conversion, clippy::useless_format )] diff --git a/src/shims/env.rs b/src/shims/env.rs index 34a716f08ab2f..ae9b8c75145f7 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -64,7 +64,7 @@ impl<'tcx> EnvVars<'tcx> { unsupported ), }; - ecx.machine.env_vars.map.insert(OsString::from(name), var_ptr); + ecx.machine.env_vars.map.insert(name, var_ptr); } } } diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 06537b5d333bf..b2c31f1c140b1 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -775,7 +775,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx for i in 0..dest_len { let src_index: u64 = this - .read_immediate(&this.operand_index(index, i)?.into())? + .read_immediate(&this.operand_index(index, i)?)? .to_scalar()? .to_u32()? .into(); diff --git a/src/shims/posix/fs.rs b/src/shims/posix/fs.rs index f224a1461f93d..a63b2ad80c278 100644 --- a/src/shims/posix/fs.rs +++ b/src/shims/posix/fs.rs @@ -1168,7 +1168,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx #[cfg(unix)] { use std::os::unix::fs::DirBuilderExt; - builder.mode(mode.into()); + builder.mode(mode); } let result = builder.create(path).map(|_| 0i32); diff --git a/src/shims/tls.rs b/src/shims/tls.rs index 31a3e12b41bd2..3de739a8d048b 100644 --- a/src/shims/tls.rs +++ b/src/shims/tls.rs @@ -99,7 +99,7 @@ impl<'tcx> TlsData<'tcx> { Some(TlsEntry { data, .. }) => { let value = data.get(&thread_id).copied(); trace!("TLS key {} for thread {:?} loaded: {:?}", key, thread_id, value); - Ok(value.unwrap_or_else(|| Scalar::null_ptr(cx).into())) + Ok(value.unwrap_or_else(|| Scalar::null_ptr(cx))) } None => throw_ub_format!("loading from a non-existing TLS key: {}", key), } diff --git a/src/thread.rs b/src/thread.rs index 031463f8ea74f..8edd6672a7478 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -70,7 +70,7 @@ impl From for ThreadId { impl ThreadId { pub fn to_u32_scalar(&self) -> Scalar { - Scalar::from_u32(u32::try_from(self.0).unwrap()) + Scalar::from_u32(self.0) } } From 96036c65bfa1251c4ba2bcf1ebd2f00bfe9b4e2e Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Fri, 29 Apr 2022 16:03:38 -0700 Subject: [PATCH 3030/3747] Keep remaining clippy ignores --- src/lib.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 0699dfba4b7b4..3f1ba574ce069 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -7,9 +7,8 @@ #![feature(bool_to_option)] #![feature(io_error_more)] #![warn(rust_2018_idioms)] -#![allow(clippy::cast_lossless)] -// TODO: Uncategorized. Some of these we'll want to fix, some keep ignored. #![allow( + clippy::cast_lossless, clippy::collapsible_else_if, clippy::collapsible_if, clippy::comparison_chain, From 0bdf91ddc73d80fcd5359bc9ba4882941529d928 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Fri, 29 Apr 2022 20:25:04 -0700 Subject: [PATCH 3031/3747] Update GitHub Actions actions/checkout@v2 to v3 The v2 implementation uses Node 12, which is end-of-life on April 30, 2022. See https://nodejs.org/en/about/releases/. Update to v3, which is based on Node 16 whose support lasts until April 30, 2024. --- .github/workflows/ci.yml | 4 ++-- README.md | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 94b9dd6fe55f7..0904afc82020b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -32,7 +32,7 @@ jobs: os: windows-latest host_target: i686-pc-windows-msvc steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 # We install gnu-tar because BSD tar is buggy on macOS builders of GHA. # See . @@ -97,7 +97,7 @@ jobs: name: check formatting (ignored by bors) runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Install latest nightly uses: actions-rs/toolchain@v1 with: diff --git a/README.md b/README.md index ca14f02d86aef..6d5ee30e498d7 100644 --- a/README.md +++ b/README.md @@ -165,7 +165,7 @@ Here is an example job for GitHub Actions: name: "Miri" runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Install Miri run: | rustup toolchain install nightly --component miri From f3f7e083dc92aba7a4c1818e56464fcb79f22f19 Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Sat, 12 Mar 2022 17:23:22 -0500 Subject: [PATCH 3032/3747] Print spans where tags are created and invalidated --- src/diagnostics.rs | 46 +++++- src/eval.rs | 21 +++ src/helpers.rs | 9 ++ src/machine.rs | 6 +- src/stacked_borrows.rs | 311 +++++++++++++++++++++++++++++++++++------ 5 files changed, 341 insertions(+), 52 deletions(-) diff --git a/src/diagnostics.rs b/src/diagnostics.rs index 1a39a1ff332e9..c6b6c3388cab9 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -7,7 +7,8 @@ use log::trace; use rustc_middle::ty; use rustc_span::{source_map::DUMMY_SP, Span, SpanData, Symbol}; -use crate::stacked_borrows::{AccessKind, SbTag}; +use crate::helpers::HexRange; +use crate::stacked_borrows::{AccessKind, SbTag, TagHistory}; use crate::*; /// Details of premature program termination. @@ -19,6 +20,7 @@ pub enum TerminationInfo { msg: String, help: Option, url: String, + history: Option, }, Deadlock, MultipleSymbolDefinitions { @@ -155,12 +157,46 @@ pub fn report_error<'tcx, 'mir>( (None, format!("pass the flag `-Zmiri-disable-isolation` to disable isolation;")), (None, format!("or pass `-Zmiri-isolation-error=warn` to configure Miri to return an error code from isolated operations (if supported for that operation) and continue with a warning")), ], - ExperimentalUb { url, help, .. } => { + ExperimentalUb { url, help, history, .. } => { msg.extend(help.clone()); - vec![ + let mut helps = vec![ (None, format!("this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental")), - (None, format!("see {} for further information", url)) - ] + (None, format!("see {} for further information", url)), + ]; + match history { + Some(TagHistory::Tagged {tag, created: (created_range, created_span), invalidated, protected }) => { + let msg = format!("{:?} was created due to a retag at offsets {}", tag, HexRange(*created_range)); + helps.push((Some(created_span.clone()), msg)); + if let Some((invalidated_range, invalidated_span)) = invalidated { + let msg = format!("{:?} was later invalidated due to a retag at offsets {}", tag, HexRange(*invalidated_range)); + helps.push((Some(invalidated_span.clone()), msg)); + } + if let Some((protecting_tag, protecting_tag_span, protection_span)) = protected { + helps.push((Some(protecting_tag_span.clone()), format!("{:?} was protected due to {:?} which was created here", tag, protecting_tag))); + helps.push((Some(protection_span.clone()), "this protector is live for this call".to_string())); + } + } + Some(TagHistory::Untagged{ recently_created, recently_invalidated, matching_created, protected }) => { + if let Some((range, span)) = recently_created { + let msg = format!("tag was most recently created at offsets {}", HexRange(*range)); + helps.push((Some(span.clone()), msg)); + } + if let Some((range, span)) = recently_invalidated { + let msg = format!("tag was later invalidated at offsets {}", HexRange(*range)); + helps.push((Some(span.clone()), msg)); + } + if let Some((range, span)) = matching_created { + let msg = format!("this tag was also created here at offsets {}", HexRange(*range)); + helps.push((Some(span.clone()), msg)); + } + if let Some((protecting_tag, protecting_tag_span, protection_span)) = protected { + helps.push((Some(protecting_tag_span.clone()), format!("{:?} was protected due to a tag which was created here", protecting_tag))); + helps.push((Some(protection_span.clone()), "this protector is live for this call".to_string())); + } + } + None => {} + } + helps } MultipleSymbolDefinitions { first, first_crate, second, second_crate, .. } => vec![ diff --git a/src/eval.rs b/src/eval.rs index f8d23cb8279cd..8b964ba90f046 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -283,6 +283,24 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( Ok((ecx, ret_place)) } +// This is potentially a performance hazard. +// Factoring it into its own function lets us keep an eye on how much it shows up in a profile. +fn set_current_span<'mir, 'tcx: 'mir>(ecx: &mut MiriEvalContext<'mir, 'tcx>) { + let current_span = Machine::stack(&ecx) + .into_iter() + .rev() + .find(|frame| { + let info = + FrameInfo { instance: frame.instance, span: frame.current_span(), lint_root: None }; + ecx.machine.is_local(&info) + }) + .map(|frame| frame.current_span()) + .unwrap_or(rustc_span::DUMMY_SP); + if let Some(sb) = ecx.machine.stacked_borrows.as_mut() { + sb.get_mut().current_span = current_span; + } +} + /// Evaluates the entry function specified by `entry_id`. /// Returns `Some(return_code)` if program executed completed. /// Returns `None` if an evaluation error occured. @@ -310,6 +328,9 @@ pub fn eval_entry<'tcx>( let info = ecx.preprocess_diagnostics(); match ecx.schedule()? { SchedulingAction::ExecuteStep => { + if ecx.machine.stacked_borrows.is_some() { + set_current_span(&mut ecx); + } assert!(ecx.step()?, "a terminated thread was scheduled for execution"); } SchedulingAction::ExecuteTimeoutCallback => { diff --git a/src/helpers.rs b/src/helpers.rs index 107a2551995ad..8d7147fff7a4b 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -813,3 +813,12 @@ pub fn get_local_crates(tcx: &TyCtxt<'_>) -> Vec { } local_crates } + +/// Formats an AllocRange like [0x1..0x3], for use in diagnostics. +pub struct HexRange(pub AllocRange); + +impl std::fmt::Display for HexRange { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "[{:#x}..{:#x}]", self.0.start.bytes(), self.0.end().bytes()) + } +} diff --git a/src/machine.rs b/src/machine.rs index 0a8a229c8aa2c..5f25fd2988652 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -632,7 +632,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { alloc_id, tag, range, - machine.stacked_borrows.as_ref().unwrap(), + machine.stacked_borrows.as_ref().unwrap(), ) } else { Ok(()) @@ -655,7 +655,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { alloc_id, tag, range, - machine.stacked_borrows.as_mut().unwrap(), + machine.stacked_borrows.as_ref().unwrap(), ) } else { Ok(()) @@ -681,7 +681,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { alloc_id, tag, range, - machine.stacked_borrows.as_mut().unwrap(), + machine.stacked_borrows.as_ref().unwrap(), ) } else { Ok(()) diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index d6caba81713cf..225407a7bbfa4 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -3,6 +3,7 @@ use log::trace; use std::cell::RefCell; +use std::collections::HashMap; use std::fmt; use std::num::NonZeroU64; @@ -14,9 +15,11 @@ use rustc_middle::ty::{ layout::{HasParamEnv, LayoutOf}, }; use rustc_span::DUMMY_SP; +use rustc_span::{Span, SpanData}; use rustc_target::abi::Size; use std::collections::HashSet; +use crate::helpers::HexRange; use crate::*; pub type PtrId = NonZeroU64; @@ -111,7 +114,53 @@ pub struct GlobalStateInner { tracked_call_ids: HashSet, /// Whether to track raw pointers. tag_raw: bool, + /// Extra per-allocation information + extras: HashMap, + /// Current span + pub(crate) current_span: Span, } + +#[derive(Debug, Default)] +struct AllocHistory { + // The time tags can be compressed down to one bit per event, by just storing a Vec + // where each bit is set to indicate if the event was a creation or a retag + current_time: usize, + creations: Vec, + invalidations: Vec, + protectors: Vec, +} + +#[derive(Debug)] +struct Protection { + orig_tag: SbTag, + tag: SbTag, + span: Span, +} + +#[derive(Debug)] +struct Event { + time: usize, + parent: Option, + tag: SbTag, + range: AllocRange, + span: Span, +} + +pub enum TagHistory { + Tagged { + tag: SbTag, + created: (AllocRange, SpanData), + invalidated: Option<(AllocRange, SpanData)>, + protected: Option<(SbTag, SpanData, SpanData)>, + }, + Untagged { + recently_created: Option<(AllocRange, SpanData)>, + recently_invalidated: Option<(AllocRange, SpanData)>, + matching_created: Option<(AllocRange, SpanData)>, + protected: Option<(SbTag, SpanData, SpanData)>, + }, +} + /// We need interior mutable access to the global state. pub type GlobalState = RefCell; @@ -171,6 +220,8 @@ impl GlobalStateInner { tracked_pointer_tags, tracked_call_ids, tag_raw, + extras: HashMap::new(), + current_span: DUMMY_SP, } } @@ -218,16 +269,155 @@ impl GlobalStateInner { self.base_ptr_ids.try_insert(id, tag).unwrap(); tag } + + fn add_creation( + &mut self, + parent: Option, + tag: SbTag, + alloc: AllocId, + range: AllocRange, + ) { + let extras = self.extras.entry(alloc).or_default(); + extras.creations.push(Event { + parent, + tag, + range, + span: self.current_span, + time: extras.current_time, + }); + extras.current_time += 1; + } + + fn add_invalidation(&mut self, tag: SbTag, alloc: AllocId, range: AllocRange) { + let extras = self.extras.entry(alloc).or_default(); + extras.invalidations.push(Event { + parent: None, + tag, + range, + span: self.current_span, + time: extras.current_time, + }); + extras.current_time += 1; + } + + fn add_protector(&mut self, orig_tag: SbTag, tag: SbTag, alloc: AllocId) { + let extras = self.extras.entry(alloc).or_default(); + extras.protectors.push(Protection { orig_tag, tag, span: self.current_span }); + extras.current_time += 1; + } + + fn get_stack_history( + &self, + tag: SbTag, + alloc: AllocId, + alloc_range: AllocRange, + offset: Size, + protector_tag: Option, + ) -> Option { + let extras = self.extras.get(&alloc)?; + let protected = protector_tag + .and_then(|protector| { + extras.protectors.iter().find_map(|protection| { + if protection.tag == protector { + Some((protection.orig_tag, protection.span.data())) + } else { + None + } + }) + }) + .and_then(|(tag, call_span)| { + extras.creations.iter().rev().find_map(|event| { + if event.tag == tag { + Some((event.parent?, event.span.data(), call_span)) + } else { + None + } + }) + }); + if let SbTag::Tagged(_) = tag { + let get_matching = |events: &[Event]| { + events.iter().rev().find_map(|event| { + if event.tag == tag { Some((event.range, event.span.data())) } else { None } + }) + }; + Some(TagHistory::Tagged { + tag, + created: get_matching(&extras.creations)?, + invalidated: get_matching(&extras.invalidations), + protected, + }) + } else { + let mut created_time = 0; + // Find the most recently created tag that satsfies this offset + let recently_created = extras.creations.iter().rev().find_map(|event| { + if event.tag == tag && offset >= event.range.start && offset < event.range.end() { + created_time = event.time; + Some((event.range, event.span.data())) + } else { + None + } + }); + + // Find a different recently created tag that satisfies this whole operation, predates + // the recently created tag, and has a different span. + // We're trying to make a guess at which span the user wanted to provide the tag that + // they're using. + let matching_created = if let Some((_created_range, created_span)) = recently_created { + extras.creations.iter().rev().find_map(|event| { + if event.tag == tag + && alloc_range.start >= event.range.start + && alloc_range.end() <= event.range.end() + && event.span.data() != created_span + && event.time != created_time + { + Some((event.range, event.span.data())) + } else { + None + } + }) + } else { + None + }; + + let recently_invalidated = if recently_created.is_some() { + // Find the most recent invalidation of this tag which post-dates the creation + let mut found = None; + for event in extras.invalidations.iter().rev() { + if event.time < created_time { + break; + } + if event.tag == tag && offset >= event.range.start && offset < event.range.end() + { + found = Some((event.range, event.span.data())) + } + } + found + } else { + None + }; + Some(TagHistory::Untagged { + recently_created, + matching_created, + recently_invalidated, + protected, + }) + } + } } /// Error reporting -fn err_sb_ub(msg: String, help: Option) -> InterpError<'static> { +fn err_sb_ub( + msg: String, + help: Option, + history: Option, +) -> InterpError<'static> { err_machine_stop!(TerminationInfo::ExperimentalUb { msg, help, url: format!( "https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md" ), + history }) } @@ -308,31 +498,39 @@ impl<'tcx> Stack { /// `None` during a deallocation. fn check_protector( item: &Item, - provoking_access: Option<(SbTag, AccessKind)>, + provoking_access: Option<(SbTag, AllocId, AllocRange, Size)>, // just for debug printing amd error messages global: &GlobalStateInner, ) -> InterpResult<'tcx> { if let SbTag::Tagged(id) = item.tag { if global.tracked_pointer_tags.contains(&id) { register_diagnostic(NonHaltingDiagnostic::PoppedPointerTag( *item, - provoking_access, + None, )); } } if let Some(call) = item.protector { if global.is_active(call) { - if let Some((tag, _)) = provoking_access { + if let Some((tag, alloc_id, alloc_range, offset)) = provoking_access { Err(err_sb_ub( format!( "not granting access to tag {:?} because incompatible item is protected: {:?}", tag, item ), None, + global.get_stack_history( + tag, + alloc_id, + alloc_range, + offset, + Some(item.tag), + ), ))? } else { Err(err_sb_ub( format!("deallocating while item is protected: {:?}", item), None, + None, ))? } } @@ -348,15 +546,15 @@ impl<'tcx> Stack { &mut self, access: AccessKind, tag: SbTag, - (alloc_id, range, offset): (AllocId, AllocRange, Size), // just for debug printing and error messages - global: &GlobalStateInner, + (alloc_id, alloc_range, offset): (AllocId, AllocRange, Size), // just for debug printing and error messages + global: &mut GlobalStateInner, ) -> InterpResult<'tcx> { // Two main steps: Find granting item, remove incompatible items above. // Step 1: Find granting item. - let granting_idx = self - .find_granting(access, tag) - .ok_or_else(|| self.access_error(access, tag, alloc_id, range, offset))?; + let granting_idx = self.find_granting(access, tag).ok_or_else(|| { + self.access_error(access, tag, alloc_id, alloc_range, offset, global) + })?; // Step 2: Remove incompatible items above them. Make sure we do not remove protected // items. Behavior differs for reads and writes. @@ -366,7 +564,8 @@ impl<'tcx> Stack { let first_incompatible_idx = self.find_first_write_incompatible(granting_idx); for item in self.borrows.drain(first_incompatible_idx..).rev() { trace!("access: popping item {:?}", item); - Stack::check_protector(&item, Some((tag, access)), global)?; + Stack::check_protector(&item, Some((tag, alloc_id, alloc_range, offset)), global)?; + global.add_invalidation(item.tag, alloc_id, alloc_range); } } else { // On a read, *disable* all `Unique` above the granting item. This ensures U2 for read accesses. @@ -381,8 +580,13 @@ impl<'tcx> Stack { let item = &mut self.borrows[idx]; if item.perm == Permission::Unique { trace!("access: disabling item {:?}", item); - Stack::check_protector(item, Some((tag, access)), global)?; + Stack::check_protector( + item, + Some((tag, alloc_id, alloc_range, offset)), + global, + )?; item.perm = Permission::Disabled; + global.add_invalidation(item.tag, alloc_id, alloc_range); } } } @@ -396,15 +600,18 @@ impl<'tcx> Stack { fn dealloc( &mut self, tag: SbTag, - dbg_ptr: Pointer, // just for debug printing and error messages + (alloc_id, alloc_range, offset): (AllocId, AllocRange, Size), // just for debug printing amd error messages global: &GlobalStateInner, ) -> InterpResult<'tcx> { // Step 1: Find granting item. self.find_granting(AccessKind::Write, tag).ok_or_else(|| { err_sb_ub(format!( "no item granting write access for deallocation to tag {:?} at {:?} found in borrow stack", - tag, dbg_ptr, - ), None) + tag, alloc_id, + ), + None, + global.get_stack_history(tag, alloc_id, alloc_range, offset, None), + ) })?; // Step 2: Remove all items. Also checks for protectors. @@ -426,16 +633,16 @@ impl<'tcx> Stack { derived_from: SbTag, new: Item, (alloc_id, alloc_range, offset): (AllocId, AllocRange, Size), // just for debug printing and error messages - global: &GlobalStateInner, + global: &mut GlobalStateInner, ) -> InterpResult<'tcx> { // Figure out which access `perm` corresponds to. let access = if new.perm.grants(AccessKind::Write) { AccessKind::Write } else { AccessKind::Read }; // Now we figure out which item grants our parent (`derived_from`) this kind of access. // We use that to determine where to put the new item. - let granting_idx = self - .find_granting(access, derived_from) - .ok_or_else(|| self.grant_error(derived_from, new, alloc_id, alloc_range, offset))?; + let granting_idx = self.find_granting(access, derived_from).ok_or_else(|| { + self.grant_error(derived_from, new, alloc_id, alloc_range, offset, global) + })?; // Compute where to put the new item. // Either way, we ensure that we insert the new item in a way such that between @@ -483,6 +690,7 @@ impl<'tcx> Stack { alloc_id: AllocId, alloc_range: AllocRange, error_offset: Size, + global: &GlobalStateInner, ) -> InterpError<'static> { let action = format!( "trying to reborrow {:?} for {:?} permission at {}[{:#x}]", @@ -494,6 +702,7 @@ impl<'tcx> Stack { err_sb_ub( format!("{}{}", action, self.error_cause(derived_from)), Some(Self::operation_summary("a reborrow", alloc_id, alloc_range)), + global.get_stack_history(derived_from, alloc_id, alloc_range, error_offset, None), ) } @@ -505,6 +714,7 @@ impl<'tcx> Stack { alloc_id: AllocId, alloc_range: AllocRange, error_offset: Size, + global: &GlobalStateInner, ) -> InterpError<'static> { let action = format!( "attempting a {} using {:?} at {}[{:#x}]", @@ -516,6 +726,7 @@ impl<'tcx> Stack { err_sb_ub( format!("{}{}", action, self.error_cause(tag)), Some(Self::operation_summary("an access", alloc_id, alloc_range)), + global.get_stack_history(tag, alloc_id, alloc_range, error_offset, None), ) } @@ -525,11 +736,10 @@ impl<'tcx> Stack { alloc_range: AllocRange, ) -> String { format!( - "this error occurs as part of {} at {:?}[{:#x}..{:#x}]", + "this error occurs as part of {} at {:?}{}", operation, alloc_id, - alloc_range.start.bytes(), - alloc_range.end().bytes() + HexRange(alloc_range) ) } @@ -620,6 +830,7 @@ impl Stacks { (tag, Permission::SharedReadWrite) } }; + extra.add_creation(None, base_tag, id, alloc_range(Size::ZERO, size)); Stacks::new(size, perm, base_tag) } @@ -637,11 +848,11 @@ impl Stacks { Pointer::new(alloc_id, range.start), range.size.bytes() ); - let global = &*state.borrow(); self.for_each(range, move |offset, stack| { - stack.access(AccessKind::Read, tag, (alloc_id, range, offset), global) + let mut state = state.borrow_mut(); + stack.access(AccessKind::Read, tag, (alloc_id, range, offset), &mut state) }) - } + } #[inline(always)] pub fn memory_written<'tcx>( @@ -649,7 +860,7 @@ impl Stacks { alloc_id: AllocId, tag: SbTag, range: AllocRange, - state: &mut GlobalState, + state: &GlobalState, ) -> InterpResult<'tcx> { trace!( "write access with tag {:?}: {:?}, size {}", @@ -657,9 +868,9 @@ impl Stacks { Pointer::new(alloc_id, range.start), range.size.bytes() ); - let global = state.get_mut(); self.for_each_mut(range, move |offset, stack| { - stack.access(AccessKind::Write, tag, (alloc_id, range, offset), global) + let mut state = state.borrow_mut(); + stack.access(AccessKind::Write, tag, (alloc_id, range, offset), &mut state) }) } @@ -669,13 +880,15 @@ impl Stacks { alloc_id: AllocId, tag: SbTag, range: AllocRange, - state: &mut GlobalState, + state: &GlobalState, ) -> InterpResult<'tcx> { trace!("deallocation with tag {:?}: {:?}, size {}", tag, alloc_id, range.size.bytes()); - let global = state.get_mut(); self.for_each_mut(range, move |offset, stack| { - stack.dealloc(tag, Pointer::new(alloc_id, offset), global) - }) + let mut state = state.borrow_mut(); + stack.dealloc(tag, (alloc_id, range, offset), &mut state) + })?; + state.borrow_mut().extras.remove(&alloc_id); + Ok(()) } } @@ -705,6 +918,17 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } let (alloc_id, base_offset, orig_tag) = this.ptr_get_alloc_id(place.ptr)?; + let mem_extra = this.machine.stacked_borrows.as_mut().unwrap().get_mut(); + mem_extra.add_creation( + Some(orig_tag), + new_tag, + alloc_id, + alloc_range(base_offset, base_offset + size), + ); + if protect { + mem_extra.add_protector(orig_tag, new_tag, alloc_id); + } + // Ensure we bail out if the pointer goes out-of-bounds (see miri#1050). let (alloc_size, _) = this.get_alloc_size_and_align(alloc_id, AllocCheck::Dereferenceable)?; @@ -753,7 +977,6 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let extra = this.get_alloc_extra(alloc_id)?; let stacked_borrows = extra.stacked_borrows.as_ref().expect("we should have Stacked Borrows data"); - let global = this.machine.stacked_borrows.as_ref().unwrap().borrow(); this.visit_freeze_sensitive(place, size, |mut range, frozen| { // Adjust range. range.start += base_offset; @@ -765,7 +988,9 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx }; let item = Item { perm, tag: new_tag, protector }; stacked_borrows.for_each(range, |offset, stack| { - stack.grant(orig_tag, item, (alloc_id, range, offset), &*global) + let mut global = + this.machine.stacked_borrows.as_ref().unwrap().borrow_mut(); + stack.grant(orig_tag, item, (alloc_id, range, offset), &mut *global) }) })?; return Ok(()); @@ -777,11 +1002,11 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let (alloc_extra, memory_extra) = this.get_alloc_extra_mut(alloc_id)?; let stacked_borrows = alloc_extra.stacked_borrows.as_mut().expect("we should have Stacked Borrows data"); - let global = memory_extra.stacked_borrows.as_mut().unwrap().get_mut(); let item = Item { perm, tag: new_tag, protector }; let range = alloc_range(base_offset, size); - stacked_borrows.for_each_mut(alloc_range(base_offset, size), |offset, stack| { - stack.grant(orig_tag, item, (alloc_id, range, offset), global) + stacked_borrows.for_each_mut(range, |offset, stack| { + let mut global = memory_extra.stacked_borrows.as_ref().unwrap().borrow_mut(); + stack.grant(orig_tag, item, (alloc_id, range, offset), &mut *global) })?; Ok(()) } @@ -807,14 +1032,12 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx }; // Compute new borrow. - let new_tag = { - let mem_extra = this.machine.stacked_borrows.as_mut().unwrap().get_mut(); - match kind { - // Give up tracking for raw pointers. - RefKind::Raw { .. } if !mem_extra.tag_raw => SbTag::Untagged, - // All other pointers are properly tracked. - _ => SbTag::Tagged(mem_extra.new_ptr()), - } + let mem_extra = this.machine.stacked_borrows.as_mut().unwrap().get_mut(); + let new_tag = match kind { + // Give up tracking for raw pointers. + RefKind::Raw { .. } if !mem_extra.tag_raw => SbTag::Untagged, + // All other pointers are properly tracked. + _ => SbTag::Tagged(mem_extra.new_ptr()), }; // Reborrow. From 5861d137b25997a7f4947fe6046003d2d0facde2 Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Fri, 15 Apr 2022 23:04:07 -0400 Subject: [PATCH 3033/3747] Set the current span (somewhat) lazily --- src/diagnostics.rs | 4 ++-- src/eval.rs | 23 +++----------------- src/machine.rs | 48 +++++++++++++++++++++++++++++++++++++++--- src/stacked_borrows.rs | 14 ++++++------ src/thread.rs | 2 +- 5 files changed, 58 insertions(+), 33 deletions(-) diff --git a/src/diagnostics.rs b/src/diagnostics.rs index c6b6c3388cab9..bba1989e2d58e 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -165,10 +165,10 @@ pub fn report_error<'tcx, 'mir>( ]; match history { Some(TagHistory::Tagged {tag, created: (created_range, created_span), invalidated, protected }) => { - let msg = format!("{:?} was created due to a retag at offsets {}", tag, HexRange(*created_range)); + let msg = format!("{:?} was created by a retag at offsets {}", tag, HexRange(*created_range)); helps.push((Some(created_span.clone()), msg)); if let Some((invalidated_range, invalidated_span)) = invalidated { - let msg = format!("{:?} was later invalidated due to a retag at offsets {}", tag, HexRange(*invalidated_range)); + let msg = format!("{:?} was later invalidated at offsets {}", tag, HexRange(*invalidated_range)); helps.push((Some(invalidated_span.clone()), msg)); } if let Some((protecting_tag, protecting_tag_span, protection_span)) = protected { diff --git a/src/eval.rs b/src/eval.rs index 8b964ba90f046..80738d33e0b9e 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -16,6 +16,7 @@ use rustc_target::spec::abi::Abi; use rustc_session::config::EntryFnType; use std::collections::HashSet; +use rustc_span::DUMMY_SP; use crate::*; @@ -283,24 +284,6 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( Ok((ecx, ret_place)) } -// This is potentially a performance hazard. -// Factoring it into its own function lets us keep an eye on how much it shows up in a profile. -fn set_current_span<'mir, 'tcx: 'mir>(ecx: &mut MiriEvalContext<'mir, 'tcx>) { - let current_span = Machine::stack(&ecx) - .into_iter() - .rev() - .find(|frame| { - let info = - FrameInfo { instance: frame.instance, span: frame.current_span(), lint_root: None }; - ecx.machine.is_local(&info) - }) - .map(|frame| frame.current_span()) - .unwrap_or(rustc_span::DUMMY_SP); - if let Some(sb) = ecx.machine.stacked_borrows.as_mut() { - sb.get_mut().current_span = current_span; - } -} - /// Evaluates the entry function specified by `entry_id`. /// Returns `Some(return_code)` if program executed completed. /// Returns `None` if an evaluation error occured. @@ -328,8 +311,8 @@ pub fn eval_entry<'tcx>( let info = ecx.preprocess_diagnostics(); match ecx.schedule()? { SchedulingAction::ExecuteStep => { - if ecx.machine.stacked_borrows.is_some() { - set_current_span(&mut ecx); + if let Some(sb) = ecx.machine.stacked_borrows.as_mut() { + sb.get_mut().current_span = DUMMY_SP; } assert!(ecx.step()?, "a terminated thread was scheduled for execution"); } diff --git a/src/machine.rs b/src/machine.rs index 5f25fd2988652..de9aaa2859d8e 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -25,6 +25,7 @@ use rustc_middle::{ }; use rustc_span::def_id::{CrateNum, DefId}; use rustc_span::symbol::{sym, Symbol}; +use rustc_span::DUMMY_SP; use rustc_target::abi::Size; use rustc_target::spec::abi::Abi; @@ -561,6 +562,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { alloc: Cow<'b, Allocation>, kind: Option>, ) -> Cow<'b, Allocation> { + set_current_span(&ecx.machine); if ecx.machine.tracked_alloc_ids.contains(&id) { register_diagnostic(NonHaltingDiagnostic::CreatedAlloc(id)); } @@ -589,6 +591,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { ecx: &MiriEvalContext<'mir, 'tcx>, ptr: Pointer, ) -> Pointer { + set_current_span(&ecx.machine); let absolute_addr = intptrcast::GlobalStateInner::rel_ptr_to_addr(ecx, ptr); let sb_tag = if let Some(stacked_borrows) = &ecx.machine.stacked_borrows { stacked_borrows.borrow_mut().base_tag(ptr.provenance) @@ -624,6 +627,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { (alloc_id, tag): (AllocId, Self::TagExtra), range: AllocRange, ) -> InterpResult<'tcx> { + set_current_span(&machine); if let Some(data_race) = &alloc_extra.data_race { data_race.read(alloc_id, range, machine.data_race.as_ref().unwrap())?; } @@ -632,7 +636,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { alloc_id, tag, range, - machine.stacked_borrows.as_ref().unwrap(), + machine.stacked_borrows.as_ref().unwrap(), ) } else { Ok(()) @@ -647,6 +651,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { (alloc_id, tag): (AllocId, Self::TagExtra), range: AllocRange, ) -> InterpResult<'tcx> { + set_current_span(&machine); if let Some(data_race) = &mut alloc_extra.data_race { data_race.write(alloc_id, range, machine.data_race.as_mut().unwrap())?; } @@ -670,6 +675,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { (alloc_id, tag): (AllocId, Self::TagExtra), range: AllocRange, ) -> InterpResult<'tcx> { + set_current_span(&machine); if machine.tracked_alloc_ids.contains(&alloc_id) { register_diagnostic(NonHaltingDiagnostic::FreedAlloc(alloc_id)); } @@ -694,7 +700,12 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { kind: mir::RetagKind, place: &PlaceTy<'tcx, Tag>, ) -> InterpResult<'tcx> { - if ecx.machine.stacked_borrows.is_some() { ecx.retag(kind, place) } else { Ok(()) } + if ecx.machine.stacked_borrows.is_some() { + set_current_span(&ecx.machine); + ecx.retag(kind, place) + } else { + Ok(()) + } } #[inline(always)] @@ -740,7 +751,12 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { #[inline(always)] fn after_stack_push(ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx> { - if ecx.machine.stacked_borrows.is_some() { ecx.retag_return_place() } else { Ok(()) } + if ecx.machine.stacked_borrows.is_some() { + set_current_span(&ecx.machine); + ecx.retag_return_place() + } else { + Ok(()) + } } #[inline(always)] @@ -757,3 +773,29 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { res } } + +// This is potentially a performance hazard. +// Factoring it into its own function lets us keep an eye on how much it shows up in a profile. +fn set_current_span<'mir, 'tcx: 'mir>(machine: &Evaluator<'mir, 'tcx>) { + if let Some(sb) = machine.stacked_borrows.as_ref() { + if sb.borrow().current_span != DUMMY_SP { + return; + } + let current_span = machine + .threads + .active_thread_stack() + .into_iter() + .rev() + .find(|frame| { + let info = FrameInfo { + instance: frame.instance, + span: frame.current_span(), + lint_root: None, + }; + machine.is_local(&info) + }) + .map(|frame| frame.current_span()) + .unwrap_or(rustc_span::DUMMY_SP); + sb.borrow_mut().current_span = current_span; + } +} diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 225407a7bbfa4..fcb702ea6ba80 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -125,9 +125,9 @@ struct AllocHistory { // The time tags can be compressed down to one bit per event, by just storing a Vec // where each bit is set to indicate if the event was a creation or a retag current_time: usize, - creations: Vec, - invalidations: Vec, - protectors: Vec, + creations: smallvec::SmallVec<[Event; 2]>, + invalidations: smallvec::SmallVec<[Event; 1]>, + protectors: smallvec::SmallVec<[Protection; 1]>, } #[derive(Debug)] @@ -552,9 +552,9 @@ impl<'tcx> Stack { // Two main steps: Find granting item, remove incompatible items above. // Step 1: Find granting item. - let granting_idx = self.find_granting(access, tag).ok_or_else(|| { - self.access_error(access, tag, alloc_id, alloc_range, offset, global) - })?; + let granting_idx = self + .find_granting(access, tag) + .ok_or_else(|| self.access_error(access, tag, alloc_id, alloc_range, offset, global))?; // Step 2: Remove incompatible items above them. Make sure we do not remove protected // items. Behavior differs for reads and writes. @@ -852,7 +852,7 @@ impl Stacks { let mut state = state.borrow_mut(); stack.access(AccessKind::Read, tag, (alloc_id, range, offset), &mut state) }) - } + } #[inline(always)] pub fn memory_written<'tcx>( diff --git a/src/thread.rs b/src/thread.rs index 8edd6672a7478..5673af048fc53 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -263,7 +263,7 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { } /// Borrow the stack of the active thread. - fn active_thread_stack(&self) -> &[Frame<'mir, 'tcx, Tag, FrameData<'tcx>>] { + pub fn active_thread_stack(&self) -> &[Frame<'mir, 'tcx, Tag, FrameData<'tcx>>] { &self.threads[self.active_thread].stack } From cddd85e2f30fb185de55209f5843a235cdc79a88 Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Mon, 25 Apr 2022 14:18:52 -0400 Subject: [PATCH 3034/3747] Move SB diagnostics to a module --- src/diagnostics.rs | 2 +- src/eval.rs | 2 +- src/machine.rs | 1 + src/stacked_borrows.rs | 258 +------------------------ src/stacked_borrows/diagnostics.rs | 299 +++++++++++++++++++++++++++++ 5 files changed, 311 insertions(+), 251 deletions(-) create mode 100644 src/stacked_borrows/diagnostics.rs diff --git a/src/diagnostics.rs b/src/diagnostics.rs index bba1989e2d58e..56cd3bb83def1 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -8,7 +8,7 @@ use rustc_middle::ty; use rustc_span::{source_map::DUMMY_SP, Span, SpanData, Symbol}; use crate::helpers::HexRange; -use crate::stacked_borrows::{AccessKind, SbTag, TagHistory}; +use crate::stacked_borrows::{diagnostics::TagHistory, AccessKind, SbTag}; use crate::*; /// Details of premature program termination. diff --git a/src/eval.rs b/src/eval.rs index 80738d33e0b9e..a3228f763a8e1 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -15,8 +15,8 @@ use rustc_target::spec::abi::Abi; use rustc_session::config::EntryFnType; -use std::collections::HashSet; use rustc_span::DUMMY_SP; +use std::collections::HashSet; use crate::*; diff --git a/src/machine.rs b/src/machine.rs index de9aaa2859d8e..2fb5dca6dd68f 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -776,6 +776,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { // This is potentially a performance hazard. // Factoring it into its own function lets us keep an eye on how much it shows up in a profile. +/// fn set_current_span<'mir, 'tcx: 'mir>(machine: &Evaluator<'mir, 'tcx>) { if let Some(sb) = machine.stacked_borrows.as_ref() { if sb.borrow().current_span != DUMMY_SP { diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index fcb702ea6ba80..6ffa89087e869 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -14,14 +14,18 @@ use rustc_middle::ty::{ self, layout::{HasParamEnv, LayoutOf}, }; +use rustc_span::Span; use rustc_span::DUMMY_SP; -use rustc_span::{Span, SpanData}; use rustc_target::abi::Size; use std::collections::HashSet; -use crate::helpers::HexRange; use crate::*; +pub mod diagnostics; +use diagnostics::{AllocHistory, GlobalStateExt, StackExt}; + +use diagnostics::TagHistory; + pub type PtrId = NonZeroU64; pub type CallId = NonZeroU64; pub type AllocExtra = Stacks; @@ -120,47 +124,6 @@ pub struct GlobalStateInner { pub(crate) current_span: Span, } -#[derive(Debug, Default)] -struct AllocHistory { - // The time tags can be compressed down to one bit per event, by just storing a Vec - // where each bit is set to indicate if the event was a creation or a retag - current_time: usize, - creations: smallvec::SmallVec<[Event; 2]>, - invalidations: smallvec::SmallVec<[Event; 1]>, - protectors: smallvec::SmallVec<[Protection; 1]>, -} - -#[derive(Debug)] -struct Protection { - orig_tag: SbTag, - tag: SbTag, - span: Span, -} - -#[derive(Debug)] -struct Event { - time: usize, - parent: Option, - tag: SbTag, - range: AllocRange, - span: Span, -} - -pub enum TagHistory { - Tagged { - tag: SbTag, - created: (AllocRange, SpanData), - invalidated: Option<(AllocRange, SpanData)>, - protected: Option<(SbTag, SpanData, SpanData)>, - }, - Untagged { - recently_created: Option<(AllocRange, SpanData)>, - recently_invalidated: Option<(AllocRange, SpanData)>, - matching_created: Option<(AllocRange, SpanData)>, - protected: Option<(SbTag, SpanData, SpanData)>, - }, -} - /// We need interior mutable access to the global state. pub type GlobalState = RefCell; @@ -269,144 +232,10 @@ impl GlobalStateInner { self.base_ptr_ids.try_insert(id, tag).unwrap(); tag } - - fn add_creation( - &mut self, - parent: Option, - tag: SbTag, - alloc: AllocId, - range: AllocRange, - ) { - let extras = self.extras.entry(alloc).or_default(); - extras.creations.push(Event { - parent, - tag, - range, - span: self.current_span, - time: extras.current_time, - }); - extras.current_time += 1; - } - - fn add_invalidation(&mut self, tag: SbTag, alloc: AllocId, range: AllocRange) { - let extras = self.extras.entry(alloc).or_default(); - extras.invalidations.push(Event { - parent: None, - tag, - range, - span: self.current_span, - time: extras.current_time, - }); - extras.current_time += 1; - } - - fn add_protector(&mut self, orig_tag: SbTag, tag: SbTag, alloc: AllocId) { - let extras = self.extras.entry(alloc).or_default(); - extras.protectors.push(Protection { orig_tag, tag, span: self.current_span }); - extras.current_time += 1; - } - - fn get_stack_history( - &self, - tag: SbTag, - alloc: AllocId, - alloc_range: AllocRange, - offset: Size, - protector_tag: Option, - ) -> Option { - let extras = self.extras.get(&alloc)?; - let protected = protector_tag - .and_then(|protector| { - extras.protectors.iter().find_map(|protection| { - if protection.tag == protector { - Some((protection.orig_tag, protection.span.data())) - } else { - None - } - }) - }) - .and_then(|(tag, call_span)| { - extras.creations.iter().rev().find_map(|event| { - if event.tag == tag { - Some((event.parent?, event.span.data(), call_span)) - } else { - None - } - }) - }); - if let SbTag::Tagged(_) = tag { - let get_matching = |events: &[Event]| { - events.iter().rev().find_map(|event| { - if event.tag == tag { Some((event.range, event.span.data())) } else { None } - }) - }; - Some(TagHistory::Tagged { - tag, - created: get_matching(&extras.creations)?, - invalidated: get_matching(&extras.invalidations), - protected, - }) - } else { - let mut created_time = 0; - // Find the most recently created tag that satsfies this offset - let recently_created = extras.creations.iter().rev().find_map(|event| { - if event.tag == tag && offset >= event.range.start && offset < event.range.end() { - created_time = event.time; - Some((event.range, event.span.data())) - } else { - None - } - }); - - // Find a different recently created tag that satisfies this whole operation, predates - // the recently created tag, and has a different span. - // We're trying to make a guess at which span the user wanted to provide the tag that - // they're using. - let matching_created = if let Some((_created_range, created_span)) = recently_created { - extras.creations.iter().rev().find_map(|event| { - if event.tag == tag - && alloc_range.start >= event.range.start - && alloc_range.end() <= event.range.end() - && event.span.data() != created_span - && event.time != created_time - { - Some((event.range, event.span.data())) - } else { - None - } - }) - } else { - None - }; - - let recently_invalidated = if recently_created.is_some() { - // Find the most recent invalidation of this tag which post-dates the creation - let mut found = None; - for event in extras.invalidations.iter().rev() { - if event.time < created_time { - break; - } - if event.tag == tag && offset >= event.range.start && offset < event.range.end() - { - found = Some((event.range, event.span.data())) - } - } - found - } else { - None - }; - Some(TagHistory::Untagged { - recently_created, - matching_created, - recently_invalidated, - protected, - }) - } - } } /// Error reporting -fn err_sb_ub( +pub fn err_sb_ub( msg: String, help: Option, history: Option, @@ -498,7 +327,7 @@ impl<'tcx> Stack { /// `None` during a deallocation. fn check_protector( item: &Item, - provoking_access: Option<(SbTag, AllocId, AllocRange, Size)>, // just for debug printing amd error messages + provoking_access: Option<(SbTag, AllocId, AllocRange, Size)>, // just for debug printing and error messages global: &GlobalStateInner, ) -> InterpResult<'tcx> { if let SbTag::Tagged(id) = item.tag { @@ -600,7 +429,7 @@ impl<'tcx> Stack { fn dealloc( &mut self, tag: SbTag, - (alloc_id, alloc_range, offset): (AllocId, AllocRange, Size), // just for debug printing amd error messages + (alloc_id, alloc_range, offset): (AllocId, AllocRange, Size), // just for debug printing and error messages global: &GlobalStateInner, ) -> InterpResult<'tcx> { // Step 1: Find granting item. @@ -681,75 +510,6 @@ impl<'tcx> Stack { Ok(()) } - - /// Report a descriptive error when `new` could not be granted from `derived_from`. - fn grant_error( - &self, - derived_from: SbTag, - new: Item, - alloc_id: AllocId, - alloc_range: AllocRange, - error_offset: Size, - global: &GlobalStateInner, - ) -> InterpError<'static> { - let action = format!( - "trying to reborrow {:?} for {:?} permission at {}[{:#x}]", - derived_from, - new.perm, - alloc_id, - error_offset.bytes(), - ); - err_sb_ub( - format!("{}{}", action, self.error_cause(derived_from)), - Some(Self::operation_summary("a reborrow", alloc_id, alloc_range)), - global.get_stack_history(derived_from, alloc_id, alloc_range, error_offset, None), - ) - } - - /// Report a descriptive error when `access` is not permitted based on `tag`. - fn access_error( - &self, - access: AccessKind, - tag: SbTag, - alloc_id: AllocId, - alloc_range: AllocRange, - error_offset: Size, - global: &GlobalStateInner, - ) -> InterpError<'static> { - let action = format!( - "attempting a {} using {:?} at {}[{:#x}]", - access, - tag, - alloc_id, - error_offset.bytes(), - ); - err_sb_ub( - format!("{}{}", action, self.error_cause(tag)), - Some(Self::operation_summary("an access", alloc_id, alloc_range)), - global.get_stack_history(tag, alloc_id, alloc_range, error_offset, None), - ) - } - - fn operation_summary( - operation: &'static str, - alloc_id: AllocId, - alloc_range: AllocRange, - ) -> String { - format!( - "this error occurs as part of {} at {:?}{}", - operation, - alloc_id, - HexRange(alloc_range) - ) - } - - fn error_cause(&self, tag: SbTag) -> &'static str { - if self.borrows.iter().any(|item| item.tag == tag && item.perm != Permission::Disabled) { - ", but that tag only grants SharedReadOnly permission for this location" - } else { - ", but that tag does not exist in the borrow stack for this location" - } - } } // # Stacked Borrows Core End diff --git a/src/stacked_borrows/diagnostics.rs b/src/stacked_borrows/diagnostics.rs new file mode 100644 index 0000000000000..d5a65825bc2c5 --- /dev/null +++ b/src/stacked_borrows/diagnostics.rs @@ -0,0 +1,299 @@ +use rustc_middle::mir::interpret::{AllocId, AllocRange}; +use rustc_span::{Span, SpanData}; +use rustc_target::abi::Size; + +use crate::helpers::HexRange; +use crate::stacked_borrows::{err_sb_ub, AccessKind, GlobalStateInner, Permission}; +use crate::Item; +use crate::SbTag; +use crate::Stack; + +use rustc_middle::mir::interpret::InterpError; + +#[derive(Debug, Default)] +pub struct AllocHistory { + // The time tags can be compressed down to one bit per event, by just storing a Vec + // where each bit is set to indicate if the event was a creation or a retag + current_time: usize, + creations: smallvec::SmallVec<[Event; 2]>, + invalidations: smallvec::SmallVec<[Event; 1]>, + protectors: smallvec::SmallVec<[Protection; 1]>, +} + +#[derive(Debug)] +struct Protection { + orig_tag: SbTag, + tag: SbTag, + span: Span, +} + +#[derive(Debug)] +struct Event { + time: usize, + parent: Option, + tag: SbTag, + range: AllocRange, + span: Span, +} + +pub enum TagHistory { + Tagged { + tag: SbTag, + created: (AllocRange, SpanData), + invalidated: Option<(AllocRange, SpanData)>, + protected: Option<(SbTag, SpanData, SpanData)>, + }, + Untagged { + recently_created: Option<(AllocRange, SpanData)>, + recently_invalidated: Option<(AllocRange, SpanData)>, + matching_created: Option<(AllocRange, SpanData)>, + protected: Option<(SbTag, SpanData, SpanData)>, + }, +} + +pub trait GlobalStateExt { + fn add_creation( + &mut self, + parent: Option, + tag: SbTag, + alloc: AllocId, + range: AllocRange, + ); + + fn add_invalidation(&mut self, tag: SbTag, alloc: AllocId, range: AllocRange); + + fn add_protector(&mut self, orig_tag: SbTag, tag: SbTag, alloc: AllocId); + + fn get_stack_history( + &self, + tag: SbTag, + alloc: AllocId, + alloc_range: AllocRange, + offset: Size, + protector_tag: Option, + ) -> Option; +} + +impl GlobalStateExt for GlobalStateInner { + fn add_creation( + &mut self, + parent: Option, + tag: SbTag, + alloc: AllocId, + range: AllocRange, + ) { + let extras = self.extras.entry(alloc).or_default(); + extras.creations.push(Event { + parent, + tag, + range, + span: self.current_span, + time: extras.current_time, + }); + extras.current_time += 1; + } + + fn add_invalidation(&mut self, tag: SbTag, alloc: AllocId, range: AllocRange) { + let extras = self.extras.entry(alloc).or_default(); + extras.invalidations.push(Event { + parent: None, + tag, + range, + span: self.current_span, + time: extras.current_time, + }); + extras.current_time += 1; + } + + fn add_protector(&mut self, orig_tag: SbTag, tag: SbTag, alloc: AllocId) { + let extras = self.extras.entry(alloc).or_default(); + extras.protectors.push(Protection { orig_tag, tag, span: self.current_span }); + extras.current_time += 1; + } + + fn get_stack_history( + &self, + tag: SbTag, + alloc: AllocId, + alloc_range: AllocRange, + offset: Size, + protector_tag: Option, + ) -> Option { + let extras = self.extras.get(&alloc)?; + let protected = protector_tag + .and_then(|protector| { + extras.protectors.iter().find_map(|protection| { + if protection.tag == protector { + Some((protection.orig_tag, protection.span.data())) + } else { + None + } + }) + }) + .and_then(|(tag, call_span)| { + extras.creations.iter().rev().find_map(|event| { + if event.tag == tag { + Some((event.parent?, event.span.data(), call_span)) + } else { + None + } + }) + }); + if let SbTag::Tagged(_) = tag { + let get_matching = |events: &[Event]| { + events.iter().rev().find_map(|event| { + if event.tag == tag { Some((event.range, event.span.data())) } else { None } + }) + }; + Some(TagHistory::Tagged { + tag, + created: get_matching(&extras.creations)?, + invalidated: get_matching(&extras.invalidations), + protected, + }) + } else { + let mut created_time = 0; + // Find the most recently created tag that satsfies this offset + let recently_created = extras.creations.iter().rev().find_map(|event| { + if event.tag == tag && offset >= event.range.start && offset < event.range.end() { + created_time = event.time; + Some((event.range, event.span.data())) + } else { + None + } + }); + + // Find a different recently created tag that satisfies this whole operation, predates + // the recently created tag, and has a different span. + // We're trying to make a guess at which span the user wanted to provide the tag that + // they're using. + let matching_created = if let Some((_created_range, created_span)) = recently_created { + extras.creations.iter().rev().find_map(|event| { + if event.tag == tag + && alloc_range.start >= event.range.start + && alloc_range.end() <= event.range.end() + && event.span.data() != created_span + && event.time != created_time + { + Some((event.range, event.span.data())) + } else { + None + } + }) + } else { + None + }; + + let recently_invalidated = if recently_created.is_some() { + // Find the most recent invalidation of this tag which post-dates the creation + let mut found = None; + for event in extras.invalidations.iter().rev() { + if event.time < created_time { + break; + } + if event.tag == tag && offset >= event.range.start && offset < event.range.end() + { + found = Some((event.range, event.span.data())) + } + } + found + } else { + None + }; + Some(TagHistory::Untagged { + recently_created, + matching_created, + recently_invalidated, + protected, + }) + } + } +} + +pub trait StackExt { + fn grant_error( + &self, + derived_from: SbTag, + new: Item, + alloc_id: AllocId, + alloc_range: AllocRange, + error_offset: Size, + global: &GlobalStateInner, + ) -> InterpError<'static>; + + fn access_error( + &self, + access: AccessKind, + tag: SbTag, + alloc_id: AllocId, + alloc_range: AllocRange, + error_offset: Size, + global: &GlobalStateInner, + ) -> InterpError<'static>; +} + +impl StackExt for Stack { + /// Report a descriptive error when `new` could not be granted from `derived_from`. + fn grant_error( + &self, + derived_from: SbTag, + new: Item, + alloc_id: AllocId, + alloc_range: AllocRange, + error_offset: Size, + global: &GlobalStateInner, + ) -> InterpError<'static> { + let action = format!( + "trying to reborrow {:?} for {:?} permission at {}[{:#x}]", + derived_from, + new.perm, + alloc_id, + error_offset.bytes(), + ); + err_sb_ub( + format!("{}{}", action, error_cause(self, derived_from)), + Some(operation_summary("a reborrow", alloc_id, alloc_range)), + global.get_stack_history(derived_from, alloc_id, alloc_range, error_offset, None), + ) + } + + /// Report a descriptive error when `access` is not permitted based on `tag`. + fn access_error( + &self, + access: AccessKind, + tag: SbTag, + alloc_id: AllocId, + alloc_range: AllocRange, + error_offset: Size, + global: &GlobalStateInner, + ) -> InterpError<'static> { + let action = format!( + "attempting a {} using {:?} at {}[{:#x}]", + access, + tag, + alloc_id, + error_offset.bytes(), + ); + err_sb_ub( + format!("{}{}", action, error_cause(self, tag)), + Some(operation_summary("an access", alloc_id, alloc_range)), + global.get_stack_history(tag, alloc_id, alloc_range, error_offset, None), + ) + } +} + +fn operation_summary( + operation: &'static str, + alloc_id: AllocId, + alloc_range: AllocRange, +) -> String { + format!("this error occurs as part of {} at {:?}{}", operation, alloc_id, HexRange(alloc_range)) +} + +fn error_cause(stack: &Stack, tag: SbTag) -> &'static str { + if stack.borrows.iter().any(|item| item.tag == tag && item.perm != Permission::Disabled) { + ", but that tag only grants SharedReadOnly permission for this location" + } else { + ", but that tag does not exist in the borrow stack for this location" + } +} From a0ac13d8a16af1fa24f43d7f6cb39a9f78ba91fe Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 30 Apr 2022 17:06:50 +0200 Subject: [PATCH 3035/3747] gracefully handle type-too-large layout errors --- src/diagnostics.rs | 4 +--- tests/compile-fail/erroneous_const.rs | 2 +- tests/compile-fail/type-too-large.rs | 6 ++++++ 3 files changed, 8 insertions(+), 4 deletions(-) create mode 100644 tests/compile-fail/type-too-large.rs diff --git a/src/diagnostics.rs b/src/diagnostics.rs index 1a39a1ff332e9..5d20cc6ff6bae 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -182,10 +182,8 @@ pub fn report_error<'tcx, 'mir>( "Undefined Behavior", ResourceExhaustion(_) => "resource exhaustion", - InvalidProgram(InvalidProgramInfo::ReferencedConstant) => + InvalidProgram(InvalidProgramInfo::AlreadyReported(_) | InvalidProgramInfo::Layout(..)) => "post-monomorphization error", - InvalidProgram(InvalidProgramInfo::AlreadyReported(_)) => - "error occurred", kind => bug!("This error should be impossible in Miri: {:?}", kind), }; diff --git a/tests/compile-fail/erroneous_const.rs b/tests/compile-fail/erroneous_const.rs index 2592483fe65a4..8975694f51cc3 100644 --- a/tests/compile-fail/erroneous_const.rs +++ b/tests/compile-fail/erroneous_const.rs @@ -12,7 +12,7 @@ impl PrintName { fn no_codegen() { if false { - let _ = PrintName::::VOID; //~ERROR error occurred: encountered constant + let _ = PrintName::::VOID; //~ERROR post-monomorphization error } } fn main() { diff --git a/tests/compile-fail/type-too-large.rs b/tests/compile-fail/type-too-large.rs new file mode 100644 index 0000000000000..2c4ff7013a460 --- /dev/null +++ b/tests/compile-fail/type-too-large.rs @@ -0,0 +1,6 @@ +// ignore-32bit + +fn main() { + let _fat: [u8; (1<<61)+(1<<31)] = + [0; (1u64<<61) as usize +(1u64<<31) as usize]; //~ ERROR post-monomorphization error +} From 1d9e91ed507155c86299125239b993761b110fb1 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sat, 30 Apr 2022 10:14:24 -0700 Subject: [PATCH 3036/3747] Replace unneeded use of `ref` in favor of "match ergonomics" --- src/shims/backtrace.rs | 10 +-- src/shims/foreign_items.rs | 47 +++++----- src/shims/intrinsics.rs | 80 ++++++++--------- src/shims/mod.rs | 2 +- src/shims/panic.rs | 4 +- src/shims/posix/foreign_items.rs | 120 ++++++++++++------------- src/shims/posix/linux/foreign_items.rs | 30 +++---- src/shims/posix/macos/dlsym.rs | 2 +- src/shims/posix/macos/foreign_items.rs | 46 ++++------ src/shims/windows/dlsym.rs | 20 ++--- src/shims/windows/foreign_items.rs | 87 +++++++++--------- tests/run-pass/vec-matching-fold.rs | 8 +- 12 files changed, 219 insertions(+), 237 deletions(-) diff --git a/src/shims/backtrace.rs b/src/shims/backtrace.rs index 3ada61abbd296..339aa4d57e220 100644 --- a/src/shims/backtrace.rs +++ b/src/shims/backtrace.rs @@ -15,7 +15,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx dest: &PlaceTy<'tcx, Tag>, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - let &[ref flags] = this.check_shim(abi, Abi::Rust, link_name, args)?; + let [flags] = this.check_shim(abi, Abi::Rust, link_name, args)?; let flags = this.read_scalar(flags)?.to_u64()?; if flags != 0 { @@ -77,7 +77,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // storage for pointers is allocated by miri // deallocating the slice is undefined behavior with a custom global allocator 0 => { - let &[_flags] = this.check_shim(abi, Abi::Rust, link_name, args)?; + let [_flags] = this.check_shim(abi, Abi::Rust, link_name, args)?; let alloc = this.allocate(array_layout, MiriMemoryKind::Rust.into())?; @@ -95,7 +95,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // storage for pointers is allocated by the caller 1 => { - let &[_flags, ref buf] = this.check_shim(abi, Abi::Rust, link_name, args)?; + let [_flags, buf] = this.check_shim(abi, Abi::Rust, link_name, args)?; let buf_place = this.deref_operand(buf)?; @@ -150,7 +150,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx dest: &PlaceTy<'tcx, Tag>, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - let &[ref ptr, ref flags] = this.check_shim(abi, Abi::Rust, link_name, args)?; + let [ptr, flags] = this.check_shim(abi, Abi::Rust, link_name, args)?; let flags = this.read_scalar(flags)?.to_u64()?; @@ -233,7 +233,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - let &[ref ptr, ref flags, ref name_ptr, ref filename_ptr] = + let [ptr, flags, name_ptr, filename_ptr] = this.check_shim(abi, Abi::Rust, link_name, args)?; let flags = this.read_scalar(flags)?.to_u64()?; diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 8a79ed03162e3..ba4e384846be4 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -274,14 +274,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } else { Abi::System { unwind: false } }; - let &[ref code] = this.check_shim(abi, exp_abi, link_name, args)?; + let [code] = this.check_shim(abi, exp_abi, link_name, args)?; // it's really u32 for ExitProcess, but we have to put it into the `Exit` variant anyway let code = this.read_scalar(code)?.to_i32()?; throw_machine_stop!(TerminationInfo::Exit(code.into())); } "abort" => { - let &[] = - this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; throw_machine_stop!(TerminationInfo::Abort( "the program aborted execution".to_owned() )) @@ -367,7 +366,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx match &*link_name.as_str() { // Miri-specific extern functions "miri_static_root" => { - let &[ref ptr] = this.check_shim(abi, Abi::Rust, link_name, args)?; + let [ptr] = this.check_shim(abi, Abi::Rust, link_name, args)?; let ptr = this.read_pointer(ptr)?; let (alloc_id, offset, _) = this.ptr_get_alloc_id(ptr)?; if offset != Size::ZERO { @@ -400,13 +399,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Standard C allocation "malloc" => { - let &[ref size] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [size] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let size = this.read_scalar(size)?.to_machine_usize(this)?; let res = this.malloc(size, /*zero_init:*/ false, MiriMemoryKind::C)?; this.write_pointer(res, dest)?; } "calloc" => { - let &[ref items, ref len] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [items, len] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let items = this.read_scalar(items)?.to_machine_usize(this)?; let len = this.read_scalar(len)?.to_machine_usize(this)?; let size = @@ -415,12 +414,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_pointer(res, dest)?; } "free" => { - let &[ref ptr] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [ptr] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let ptr = this.read_pointer(ptr)?; this.free(ptr, MiriMemoryKind::C)?; } "realloc" => { - let &[ref old_ptr, ref new_size] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [old_ptr, new_size] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let old_ptr = this.read_pointer(old_ptr)?; let new_size = this.read_scalar(new_size)?.to_machine_usize(this)?; let res = this.realloc(old_ptr, new_size, MiriMemoryKind::C)?; @@ -429,7 +428,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Rust allocation "__rust_alloc" => { - let &[ref size, ref align] = this.check_shim(abi, Abi::Rust, link_name, args)?; + let [size, align] = this.check_shim(abi, Abi::Rust, link_name, args)?; let size = this.read_scalar(size)?.to_machine_usize(this)?; let align = this.read_scalar(align)?.to_machine_usize(this)?; @@ -446,7 +445,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx }); } "__rust_alloc_zeroed" => { - let &[ref size, ref align] = this.check_shim(abi, Abi::Rust, link_name, args)?; + let [size, align] = this.check_shim(abi, Abi::Rust, link_name, args)?; let size = this.read_scalar(size)?.to_machine_usize(this)?; let align = this.read_scalar(align)?.to_machine_usize(this)?; @@ -465,7 +464,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx }); } "__rust_dealloc" => { - let &[ref ptr, ref old_size, ref align] = this.check_shim(abi, Abi::Rust, link_name, args)?; + let [ptr, old_size, align] = this.check_shim(abi, Abi::Rust, link_name, args)?; let ptr = this.read_pointer(ptr)?; let old_size = this.read_scalar(old_size)?.to_machine_usize(this)?; let align = this.read_scalar(align)?.to_machine_usize(this)?; @@ -480,7 +479,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx }); } "__rust_realloc" => { - let &[ref ptr, ref old_size, ref align, ref new_size] = this.check_shim(abi, Abi::Rust, link_name, args)?; + let [ptr, old_size, align, new_size] = this.check_shim(abi, Abi::Rust, link_name, args)?; let ptr = this.read_pointer(ptr)?; let old_size = this.read_scalar(old_size)?.to_machine_usize(this)?; let align = this.read_scalar(align)?.to_machine_usize(this)?; @@ -504,7 +503,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // C memory handling functions "memcmp" => { - let &[ref left, ref right, ref n] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [left, right, n] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let left = this.read_pointer(left)?; let right = this.read_pointer(right)?; let n = Size::from_bytes(this.read_scalar(n)?.to_machine_usize(this)?); @@ -524,7 +523,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_i32(result), dest)?; } "memrchr" => { - let &[ref ptr, ref val, ref num] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [ptr, val, num] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let ptr = this.read_pointer(ptr)?; let val = this.read_scalar(val)?.to_i32()? as u8; let num = this.read_scalar(num)?.to_machine_usize(this)?; @@ -541,7 +540,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } "memchr" => { - let &[ref ptr, ref val, ref num] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [ptr, val, num] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let ptr = this.read_pointer(ptr)?; let val = this.read_scalar(val)?.to_i32()? as u8; let num = this.read_scalar(num)?.to_machine_usize(this)?; @@ -557,7 +556,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } "strlen" => { - let &[ref ptr] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [ptr] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let ptr = this.read_pointer(ptr)?; let n = this.read_c_str(ptr)?.len(); this.write_scalar(Scalar::from_machine_usize(u64::try_from(n).unwrap(), this), dest)?; @@ -573,7 +572,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "asinf" | "atanf" => { - let &[ref f] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [f] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; // FIXME: Using host floats. let f = f32::from_bits(this.read_scalar(f)?.to_u32()?); let f = match &*link_name.as_str() { @@ -593,7 +592,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "hypotf" | "atan2f" => { - let &[ref f1, ref f2] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [f1, f2] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; // underscore case for windows, here and below // (see https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/floating-point-primitives?view=vs-2019) // FIXME: Using host floats. @@ -615,7 +614,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "asin" | "atan" => { - let &[ref f] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [f] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; // FIXME: Using host floats. let f = f64::from_bits(this.read_scalar(f)?.to_u64()?); let f = match &*link_name.as_str() { @@ -635,7 +634,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "hypot" | "atan2" => { - let &[ref f1, ref f2] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [f1, f2] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; // FIXME: Using host floats. let f1 = f64::from_bits(this.read_scalar(f1)?.to_u64()?); let f2 = f64::from_bits(this.read_scalar(f2)?.to_u64()?); @@ -651,7 +650,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "ldexp" | "scalbn" => { - let &[ref x, ref exp] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [x, exp] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; // For radix-2 (binary) systems, `ldexp` and `scalbn` are the same. let x = this.read_scalar(x)?.to_f64()?; let exp = this.read_scalar(exp)?.to_i32()?; @@ -673,7 +672,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Architecture-specific shims "llvm.x86.addcarry.64" if this.tcx.sess.target.arch == "x86_64" => { // Computes u8+u64+u64, returning tuple (u8,u64) comprising the output carry and truncated sum. - let &[ref c_in, ref a, ref b] = this.check_shim(abi, Abi::Unadjusted, link_name, args)?; + let [c_in, a, b] = this.check_shim(abi, Abi::Unadjusted, link_name, args)?; let c_in = this.read_scalar(c_in)?.to_u8()?; let a = this.read_scalar(a)?.to_u64()?; let b = this.read_scalar(b)?.to_u64()?; @@ -687,11 +686,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_u64(sum), &sum_field)?; } "llvm.x86.sse2.pause" if this.tcx.sess.target.arch == "x86" || this.tcx.sess.target.arch == "x86_64" => { - let &[] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; this.yield_active_thread(); } "llvm.aarch64.isb" if this.tcx.sess.target.arch == "aarch64" => { - let &[ref arg] = this.check_shim(abi, Abi::Unadjusted, link_name, args)?; + let [arg] = this.check_shim(abi, Abi::Unadjusted, link_name, args)?; let arg = this.read_scalar(arg)?.to_i32()?; match arg { 15 => { // SY ("full system scope") diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index b2c31f1c140b1..a6f818c493e66 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -43,13 +43,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx match intrinsic_name { // Miri overwriting CTFE intrinsics. "ptr_guaranteed_eq" => { - let &[ref left, ref right] = check_arg_count(args)?; + let [left, right] = check_arg_count(args)?; let left = this.read_immediate(left)?; let right = this.read_immediate(right)?; this.binop_ignore_overflow(mir::BinOp::Eq, &left, &right, dest)?; } "ptr_guaranteed_ne" => { - let &[ref left, ref right] = check_arg_count(args)?; + let [left, right] = check_arg_count(args)?; let left = this.read_immediate(left)?; let right = this.read_immediate(right)?; this.binop_ignore_overflow(mir::BinOp::Ne, &left, &right, dest)?; @@ -65,18 +65,18 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Raw memory accesses "volatile_load" => { - let &[ref place] = check_arg_count(args)?; + let [place] = check_arg_count(args)?; let place = this.deref_operand(place)?; this.copy_op(&place.into(), dest)?; } "volatile_store" => { - let &[ref place, ref dest] = check_arg_count(args)?; + let [place, dest] = check_arg_count(args)?; let place = this.deref_operand(place)?; this.copy_op(dest, &place.into())?; } "write_bytes" | "volatile_set_memory" => { - let &[ref ptr, ref val_byte, ref count] = check_arg_count(args)?; + let [ptr, val_byte, count] = check_arg_count(args)?; let ty = instance.substs.type_at(0); let ty_layout = this.layout_of(ty)?; let val_byte = this.read_scalar(val_byte)?.to_u8()?; @@ -95,13 +95,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Floating-point operations "fabsf32" => { - let &[ref f] = check_arg_count(args)?; + let [f] = check_arg_count(args)?; let f = this.read_scalar(f)?.to_f32()?; // Can be implemented in soft-floats. this.write_scalar(Scalar::from_f32(f.abs()), dest)?; } "fabsf64" => { - let &[ref f] = check_arg_count(args)?; + let [f] = check_arg_count(args)?; let f = this.read_scalar(f)?.to_f64()?; // Can be implemented in soft-floats. this.write_scalar(Scalar::from_f64(f.abs()), dest)?; @@ -120,7 +120,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "truncf32" | "roundf32" => { - let &[ref f] = check_arg_count(args)?; + let [f] = check_arg_count(args)?; // FIXME: Using host floats. let f = f32::from_bits(this.read_scalar(f)?.to_u32()?); let f = match intrinsic_name { @@ -155,7 +155,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "truncf64" | "roundf64" => { - let &[ref f] = check_arg_count(args)?; + let [f] = check_arg_count(args)?; // FIXME: Using host floats. let f = f64::from_bits(this.read_scalar(f)?.to_u64()?); let f = match intrinsic_name { @@ -183,7 +183,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "fdiv_fast" | "frem_fast" => { - let &[ref a, ref b] = check_arg_count(args)?; + let [a, b] = check_arg_count(args)?; let a = this.read_immediate(a)?; let b = this.read_immediate(b)?; let op = match intrinsic_name { @@ -228,7 +228,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "maxnumf32" | "copysignf32" => { - let &[ref a, ref b] = check_arg_count(args)?; + let [a, b] = check_arg_count(args)?; let a = this.read_scalar(a)?.to_f32()?; let b = this.read_scalar(b)?.to_f32()?; let res = match intrinsic_name { @@ -245,7 +245,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "maxnumf64" | "copysignf64" => { - let &[ref a, ref b] = check_arg_count(args)?; + let [a, b] = check_arg_count(args)?; let a = this.read_scalar(a)?.to_f64()?; let b = this.read_scalar(b)?.to_f64()?; let res = match intrinsic_name { @@ -258,7 +258,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "powf32" => { - let &[ref f, ref f2] = check_arg_count(args)?; + let [f, f2] = check_arg_count(args)?; // FIXME: Using host floats. let f = f32::from_bits(this.read_scalar(f)?.to_u32()?); let f2 = f32::from_bits(this.read_scalar(f2)?.to_u32()?); @@ -266,7 +266,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "powf64" => { - let &[ref f, ref f2] = check_arg_count(args)?; + let [f, f2] = check_arg_count(args)?; // FIXME: Using host floats. let f = f64::from_bits(this.read_scalar(f)?.to_u64()?); let f2 = f64::from_bits(this.read_scalar(f2)?.to_u64()?); @@ -274,7 +274,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "fmaf32" => { - let &[ref a, ref b, ref c] = check_arg_count(args)?; + let [a, b, c] = check_arg_count(args)?; let a = this.read_scalar(a)?.to_f32()?; let b = this.read_scalar(b)?.to_f32()?; let c = this.read_scalar(c)?.to_f32()?; @@ -283,7 +283,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "fmaf64" => { - let &[ref a, ref b, ref c] = check_arg_count(args)?; + let [a, b, c] = check_arg_count(args)?; let a = this.read_scalar(a)?.to_f64()?; let b = this.read_scalar(b)?.to_f64()?; let c = this.read_scalar(c)?.to_f64()?; @@ -292,7 +292,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "powif32" => { - let &[ref f, ref i] = check_arg_count(args)?; + let [f, i] = check_arg_count(args)?; // FIXME: Using host floats. let f = f32::from_bits(this.read_scalar(f)?.to_u32()?); let i = this.read_scalar(i)?.to_i32()?; @@ -300,7 +300,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "powif64" => { - let &[ref f, ref i] = check_arg_count(args)?; + let [f, i] = check_arg_count(args)?; // FIXME: Using host floats. let f = f64::from_bits(this.read_scalar(f)?.to_u64()?); let i = this.read_scalar(i)?.to_i32()?; @@ -308,7 +308,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "float_to_int_unchecked" => { - let &[ref val] = check_arg_count(args)?; + let [val] = check_arg_count(args)?; let val = this.read_immediate(val)?; let res = match val.layout.ty.kind() { @@ -335,7 +335,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "simd_round" | "simd_trunc" | "simd_fsqrt" => { - let &[ref op] = check_arg_count(args)?; + let [op] = check_arg_count(args)?; let (op, op_len) = this.operand_to_simd(op)?; let (dest, dest_len) = this.place_to_simd(dest)?; @@ -441,7 +441,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "simd_arith_offset" => { use mir::BinOp; - let &[ref left, ref right] = check_arg_count(args)?; + let [left, right] = check_arg_count(args)?; let (left, left_len) = this.operand_to_simd(left)?; let (right, right_len) = this.operand_to_simd(right)?; let (dest, dest_len) = this.place_to_simd(dest)?; @@ -531,7 +531,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } "simd_fma" => { - let &[ref a, ref b, ref c] = check_arg_count(args)?; + let [a, b, c] = check_arg_count(args)?; let (a, a_len) = this.operand_to_simd(a)?; let (b, b_len) = this.operand_to_simd(b)?; let (c, c_len) = this.operand_to_simd(c)?; @@ -570,7 +570,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "simd_reduce_min" => { use mir::BinOp; - let &[ref op] = check_arg_count(args)?; + let [op] = check_arg_count(args)?; let (op, op_len) = this.operand_to_simd(op)?; let imm_from_bool = @@ -642,7 +642,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "simd_reduce_mul_ordered" => { use mir::BinOp; - let &[ref op, ref init] = check_arg_count(args)?; + let [op, init] = check_arg_count(args)?; let (op, op_len) = this.operand_to_simd(op)?; let init = this.read_immediate(init)?; @@ -660,7 +660,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_immediate(*res, dest)?; } "simd_select" => { - let &[ref mask, ref yes, ref no] = check_arg_count(args)?; + let [mask, yes, no] = check_arg_count(args)?; let (mask, mask_len) = this.operand_to_simd(mask)?; let (yes, yes_len) = this.operand_to_simd(yes)?; let (no, no_len) = this.operand_to_simd(no)?; @@ -681,7 +681,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } "simd_select_bitmask" => { - let &[ref mask, ref yes, ref no] = check_arg_count(args)?; + let [mask, yes, no] = check_arg_count(args)?; let (yes, yes_len) = this.operand_to_simd(yes)?; let (no, no_len) = this.operand_to_simd(no)?; let (dest, dest_len) = this.place_to_simd(dest)?; @@ -721,7 +721,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } #[rustfmt::skip] "simd_cast" | "simd_as" => { - let &[ref op] = check_arg_count(args)?; + let [op] = check_arg_count(args)?; let (op, op_len) = this.operand_to_simd(op)?; let (dest, dest_len) = this.place_to_simd(dest)?; @@ -759,7 +759,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } "simd_shuffle" => { - let &[ref left, ref right, ref index] = check_arg_count(args)?; + let [left, right, index] = check_arg_count(args)?; let (left, left_len) = this.operand_to_simd(left)?; let (right, right_len) = this.operand_to_simd(right)?; let (dest, dest_len) = this.place_to_simd(dest)?; @@ -798,7 +798,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } "simd_gather" => { - let &[ref passthru, ref ptrs, ref mask] = check_arg_count(args)?; + let [passthru, ptrs, mask] = check_arg_count(args)?; let (passthru, passthru_len) = this.operand_to_simd(passthru)?; let (ptrs, ptrs_len) = this.operand_to_simd(ptrs)?; let (mask, mask_len) = this.operand_to_simd(mask)?; @@ -824,7 +824,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } "simd_scatter" => { - let &[ref value, ref ptrs, ref mask] = check_arg_count(args)?; + let [value, ptrs, mask] = check_arg_count(args)?; let (value, value_len) = this.operand_to_simd(value)?; let (ptrs, ptrs_len) = this.operand_to_simd(ptrs)?; let (mask, mask_len) = this.operand_to_simd(mask)?; @@ -844,7 +844,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } "simd_bitmask" => { - let &[ref op] = check_arg_count(args)?; + let [op] = check_arg_count(args)?; let (op, op_len) = this.operand_to_simd(op)?; let bitmask_len = op_len.max(8); @@ -1063,14 +1063,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Other "exact_div" => { - let &[ref num, ref denom] = check_arg_count(args)?; + let [num, denom] = check_arg_count(args)?; this.exact_div(&this.read_immediate(num)?, &this.read_immediate(denom)?, dest)?; } "try" => return this.handle_try(args, dest, ret), "breakpoint" => { - let &[] = check_arg_count(args)?; + let [] = check_arg_count(args)?; // normally this would raise a SIGTRAP, which aborts if no debugger is connected throw_machine_stop!(TerminationInfo::Abort("Trace/breakpoint trap".to_string())) } @@ -1091,7 +1091,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - let &[ref place] = check_arg_count(args)?; + let [place] = check_arg_count(args)?; let place = this.deref_operand(place)?; // make sure it fits into a scalar; otherwise it cannot be atomic @@ -1119,7 +1119,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - let &[ref place, ref val] = check_arg_count(args)?; + let [place, val] = check_arg_count(args)?; let place = this.deref_operand(place)?; let val = this.read_scalar(val)?; // make sure it fits into a scalar; otherwise it cannot be atomic @@ -1144,7 +1144,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx args: &[OpTy<'tcx, Tag>], atomic: AtomicFenceOp, ) -> InterpResult<'tcx> { - let &[] = check_arg_count(args)?; + let [] = check_arg_count(args)?; let _ = atomic; //FIXME: compiler fences are currently ignored Ok(()) @@ -1156,7 +1156,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx atomic: AtomicFenceOp, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - let &[] = check_arg_count(args)?; + let [] = check_arg_count(args)?; this.validate_atomic_fence(atomic)?; Ok(()) } @@ -1170,7 +1170,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - let &[ref place, ref rhs] = check_arg_count(args)?; + let [place, rhs] = check_arg_count(args)?; let place = this.deref_operand(place)?; if !place.layout.ty.is_integral() { @@ -1216,7 +1216,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - let &[ref place, ref new] = check_arg_count(args)?; + let [place, new] = check_arg_count(args)?; let place = this.deref_operand(place)?; let new = this.read_scalar(new)?; @@ -1246,7 +1246,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - let &[ref place, ref expect_old, ref new] = check_arg_count(args)?; + let [place, expect_old, new] = check_arg_count(args)?; let place = this.deref_operand(place)?; let expect_old = this.read_immediate(expect_old)?; // read as immediate for the sake of `binary_op()` let new = this.read_scalar(new)?; diff --git a/src/shims/mod.rs b/src/shims/mod.rs index af6064925f043..f003552434fe9 100644 --- a/src/shims/mod.rs +++ b/src/shims/mod.rs @@ -36,7 +36,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // There are some more lang items we want to hook that CTFE does not hook (yet). if this.tcx.lang_items().align_offset_fn() == Some(instance.def.def_id()) { - let &[ref ptr, ref align] = check_arg_count(args)?; + let [ptr, align] = check_arg_count(args)?; if this.align_offset(ptr, align, ret, unwind)? { return Ok(None); } diff --git a/src/shims/panic.rs b/src/shims/panic.rs index 96d3b7c9f891e..f92e39048bc86 100644 --- a/src/shims/panic.rs +++ b/src/shims/panic.rs @@ -51,7 +51,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx trace!("miri_start_panic: {:?}", this.frame().instance); // Get the raw pointer stored in arg[0] (the panic payload). - let &[ref payload] = this.check_shim(abi, Abi::Rust, link_name, args)?; + let [payload] = this.check_shim(abi, Abi::Rust, link_name, args)?; let payload = this.read_scalar(payload)?.check_init()?; let thread = this.active_thread_mut(); assert!(thread.panic_payload.is_none(), "the panic runtime should avoid double-panics"); @@ -83,7 +83,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // a pointer to `Box`. // Get all the arguments. - let &[ref try_fn, ref data, ref catch_fn] = check_arg_count(args)?; + let [try_fn, data, catch_fn] = check_arg_count(args)?; let try_fn = this.read_pointer(try_fn)?; let data = this.read_scalar(data)?.check_init()?; let catch_fn = this.read_scalar(catch_fn)?.check_init()?; diff --git a/src/shims/posix/foreign_items.rs b/src/shims/posix/foreign_items.rs index 16619d4aeb771..566befb0efd0a 100644 --- a/src/shims/posix/foreign_items.rs +++ b/src/shims/posix/foreign_items.rs @@ -29,28 +29,28 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx match &*link_name.as_str() { // Environment related shims "getenv" => { - let &[ref name] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [name] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.getenv(name)?; this.write_pointer(result, dest)?; } "unsetenv" => { - let &[ref name] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [name] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.unsetenv(name)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "setenv" => { - let &[ref name, ref value, ref overwrite] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [name, value, overwrite] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; this.read_scalar(overwrite)?.to_i32()?; let result = this.setenv(name, value)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "getcwd" => { - let &[ref buf, ref size] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [buf, size] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.getcwd(buf, size)?; this.write_pointer(result, dest)?; } "chdir" => { - let &[ref path] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [path] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.chdir(path)?; this.write_scalar(Scalar::from_i32(result), dest)?; } @@ -70,7 +70,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_i32(result), dest)?; } "read" => { - let &[ref fd, ref buf, ref count] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [fd, buf, count] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let fd = this.read_scalar(fd)?.to_i32()?; let buf = this.read_pointer(buf)?; let count = this.read_scalar(count)?.to_machine_usize(this)?; @@ -78,7 +78,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_machine_isize(result, this), dest)?; } "write" => { - let &[ref fd, ref buf, ref n] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [fd, buf, n] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let fd = this.read_scalar(fd)?.to_i32()?; let buf = this.read_pointer(buf)?; let count = this.read_scalar(n)?.to_machine_usize(this)?; @@ -88,60 +88,60 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_machine_isize(result, this), dest)?; } "unlink" => { - let &[ref path] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [path] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.unlink(path)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "symlink" => { - let &[ref target, ref linkpath] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [target, linkpath] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.symlink(target, linkpath)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "rename" => { - let &[ref oldpath, ref newpath] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [oldpath, newpath] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.rename(oldpath, newpath)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "mkdir" => { - let &[ref path, ref mode] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [path, mode] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.mkdir(path, mode)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "rmdir" => { - let &[ref path] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [path] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.rmdir(path)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "closedir" => { - let &[ref dirp] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [dirp] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.closedir(dirp)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "lseek" | "lseek64" => { - let &[ref fd, ref offset, ref whence] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [fd, offset, whence] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.lseek64(fd, offset, whence)?; // "lseek" is only used on macOS which is 64bit-only, so `i64` always works. this.write_scalar(Scalar::from_i64(result), dest)?; } "fsync" => { - let &[ref fd] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [fd] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.fsync(fd)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "fdatasync" => { - let &[ref fd] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [fd] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.fdatasync(fd)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "readlink" => { - let &[ref pathname, ref buf, ref bufsize] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [pathname, buf, bufsize] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.readlink(pathname, buf, bufsize)?; this.write_scalar(Scalar::from_machine_isize(result, this), dest)?; } // Allocation "posix_memalign" => { - let &[ref ret, ref align, ref size] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [ret, align, size] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let ret = this.deref_operand(ret)?; let align = this.read_scalar(align)?.to_machine_usize(this)?; let size = this.read_scalar(size)?.to_machine_usize(this)?; @@ -171,7 +171,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Dynamic symbol loading "dlsym" => { - let &[ref handle, ref symbol] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [handle, symbol] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; this.read_scalar(handle)?.to_machine_usize(this)?; let symbol = this.read_pointer(symbol)?; let symbol_name = this.read_c_str(symbol)?; @@ -185,7 +185,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Querying system information "sysconf" => { - let &[ref name] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [name] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let name = this.read_scalar(name)?.to_i32()?; let sysconfs = &[ @@ -210,7 +210,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Thread-local storage "pthread_key_create" => { - let &[ref key, ref dtor] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [key, dtor] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let key_place = this.deref_operand(key)?; let dtor = this.read_pointer(dtor)?; @@ -239,21 +239,21 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_null(dest)?; } "pthread_key_delete" => { - let &[ref key] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [key] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let key = this.read_scalar(key)?.check_init()?.to_bits(key.layout.size)?; this.machine.tls.delete_tls_key(key)?; // Return success (0) this.write_null(dest)?; } "pthread_getspecific" => { - let &[ref key] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [key] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let key = this.read_scalar(key)?.check_init()?.to_bits(key.layout.size)?; let active_thread = this.get_active_thread(); let ptr = this.machine.tls.load_tls(key, active_thread, this)?; this.write_scalar(ptr, dest)?; } "pthread_setspecific" => { - let &[ref key, ref new_ptr] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [key, new_ptr] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let key = this.read_scalar(key)?.check_init()?.to_bits(key.layout.size)?; let active_thread = this.get_active_thread(); let new_data = this.read_scalar(new_ptr)?; @@ -265,149 +265,149 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Synchronization primitives "pthread_mutexattr_init" => { - let &[ref attr] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [attr] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.pthread_mutexattr_init(attr)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_mutexattr_settype" => { - let &[ref attr, ref kind] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [attr, kind] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.pthread_mutexattr_settype(attr, kind)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_mutexattr_destroy" => { - let &[ref attr] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [attr] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.pthread_mutexattr_destroy(attr)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_mutex_init" => { - let &[ref mutex, ref attr] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [mutex, attr] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.pthread_mutex_init(mutex, attr)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_mutex_lock" => { - let &[ref mutex] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [mutex] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.pthread_mutex_lock(mutex)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_mutex_trylock" => { - let &[ref mutex] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [mutex] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.pthread_mutex_trylock(mutex)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_mutex_unlock" => { - let &[ref mutex] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [mutex] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.pthread_mutex_unlock(mutex)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_mutex_destroy" => { - let &[ref mutex] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [mutex] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.pthread_mutex_destroy(mutex)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_rwlock_rdlock" => { - let &[ref rwlock] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [rwlock] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.pthread_rwlock_rdlock(rwlock)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_rwlock_tryrdlock" => { - let &[ref rwlock] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [rwlock] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.pthread_rwlock_tryrdlock(rwlock)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_rwlock_wrlock" => { - let &[ref rwlock] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [rwlock] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.pthread_rwlock_wrlock(rwlock)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_rwlock_trywrlock" => { - let &[ref rwlock] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [rwlock] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.pthread_rwlock_trywrlock(rwlock)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_rwlock_unlock" => { - let &[ref rwlock] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [rwlock] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.pthread_rwlock_unlock(rwlock)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_rwlock_destroy" => { - let &[ref rwlock] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [rwlock] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.pthread_rwlock_destroy(rwlock)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_condattr_init" => { - let &[ref attr] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [attr] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.pthread_condattr_init(attr)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_condattr_destroy" => { - let &[ref attr] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [attr] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.pthread_condattr_destroy(attr)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_cond_init" => { - let &[ref cond, ref attr] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [cond, attr] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.pthread_cond_init(cond, attr)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_cond_signal" => { - let &[ref cond] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [cond] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.pthread_cond_signal(cond)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_cond_broadcast" => { - let &[ref cond] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [cond] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.pthread_cond_broadcast(cond)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_cond_wait" => { - let &[ref cond, ref mutex] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [cond, mutex] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.pthread_cond_wait(cond, mutex)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_cond_timedwait" => { - let &[ref cond, ref mutex, ref abstime] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [cond, mutex, abstime] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; this.pthread_cond_timedwait(cond, mutex, abstime, dest)?; } "pthread_cond_destroy" => { - let &[ref cond] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [cond] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.pthread_cond_destroy(cond)?; this.write_scalar(Scalar::from_i32(result), dest)?; } // Threading "pthread_create" => { - let &[ref thread, ref attr, ref start, ref arg] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [thread, attr, start, arg] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.pthread_create(thread, attr, start, arg)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_join" => { - let &[ref thread, ref retval] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [thread, retval] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.pthread_join(thread, retval)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_detach" => { - let &[ref thread] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [thread] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.pthread_detach(thread)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_self" => { - let &[] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; this.pthread_self(dest)?; } "sched_yield" => { - let &[] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.sched_yield()?; this.write_scalar(Scalar::from_i32(result), dest)?; } "nanosleep" => { - let &[ref req, ref rem] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [req, rem] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.nanosleep(req, rem)?; this.write_scalar(Scalar::from_i32(result), dest)?; } // Miscellaneous "isatty" => { - let &[ref fd] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [fd] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; this.read_scalar(fd)?.to_i32()?; // "returns 1 if fd is an open file descriptor referring to a terminal; otherwise 0 is returned, and errno is set to indicate the error" // FIXME: we just say nothing is a terminal. @@ -416,7 +416,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_null(dest)?; } "pthread_atfork" => { - let &[ref prepare, ref parent, ref child] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [prepare, parent, child] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; this.read_pointer(prepare)?; this.read_pointer(parent)?; this.read_pointer(child)?; @@ -424,7 +424,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_null(dest)?; } "strerror_r" | "__xpg_strerror_r" => { - let &[ref errnum, ref buf, ref buflen] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [errnum, buf, buflen] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let errnum = this.read_scalar(errnum)?.check_init()?; let buf = this.read_pointer(buf)?; let buflen = this.read_scalar(buflen)?.to_machine_usize(this)?; @@ -440,7 +440,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // These shims are enabled only when the caller is in the standard library. "pthread_attr_getguardsize" if this.frame_in_std() => { - let &[ref _attr, ref guard_size] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [_attr, guard_size] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let guard_size = this.deref_operand(guard_size)?; let guard_size_layout = this.libc_ty_layout("size_t")?; this.write_scalar(Scalar::from_uint(crate::PAGE_SIZE, guard_size_layout.size), &guard_size.into())?; @@ -452,25 +452,25 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "pthread_attr_init" | "pthread_attr_destroy" if this.frame_in_std() => { - let &[_] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [_] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; this.write_null(dest)?; } | "pthread_attr_setstacksize" if this.frame_in_std() => { - let &[_, _] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [_, _] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; this.write_null(dest)?; } | "signal" | "sigaltstack" if this.frame_in_std() => { - let &[_, _] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [_, _] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; this.write_null(dest)?; } | "sigaction" | "mprotect" if this.frame_in_std() => { - let &[_, _, _] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [_, _, _] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; this.write_null(dest)?; } diff --git a/src/shims/posix/linux/foreign_items.rs b/src/shims/posix/linux/foreign_items.rs index 339fb04dae337..f966c63b72399 100644 --- a/src/shims/posix/linux/foreign_items.rs +++ b/src/shims/posix/linux/foreign_items.rs @@ -24,7 +24,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx match &*link_name.as_str() { // errno "__errno_location" => { - let &[] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let errno_place = this.last_error_place()?; this.write_scalar(errno_place.to_ref(this).to_scalar()?, dest)?; } @@ -33,31 +33,29 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // These symbols have different names on Linux and macOS, which is the only reason they are not // in the `posix` module. "close" => { - let &[ref fd] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [fd] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.close(fd)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "opendir" => { - let &[ref name] = - this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [name] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.opendir(name)?; this.write_scalar(result, dest)?; } "readdir64" => { - let &[ref dirp] = - this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [dirp] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.linux_readdir64(dirp)?; this.write_scalar(result, dest)?; } "ftruncate64" => { - let &[ref fd, ref length] = + let [fd, length] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.ftruncate64(fd, length)?; this.write_scalar(Scalar::from_i32(result), dest)?; } // Linux-only "posix_fadvise" => { - let &[ref fd, ref offset, ref len, ref advice] = + let [fd, offset, len, advice] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; this.read_scalar(fd)?.to_i32()?; this.read_scalar(offset)?.to_machine_isize(this)?; @@ -67,7 +65,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_null(dest)?; } "sync_file_range" => { - let &[ref fd, ref offset, ref nbytes, ref flags] = + let [fd, offset, nbytes, flags] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.sync_file_range(fd, offset, nbytes, flags)?; this.write_scalar(Scalar::from_i32(result), dest)?; @@ -76,7 +74,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Time related shims "clock_gettime" => { // This is a POSIX function but it has only been tested on linux. - let &[ref clk_id, ref tp] = + let [clk_id, tp] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.clock_gettime(clk_id, tp)?; this.write_scalar(Scalar::from_i32(result), dest)?; @@ -85,7 +83,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Querying system information "pthread_attr_getstack" => { // We don't support "pthread_attr_setstack", so we just pretend all stacks have the same values here. - let &[ref attr_place, ref addr_place, ref size_place] = + let [attr_place, addr_place, size_place] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; this.deref_operand(attr_place)?; let addr_place = this.deref_operand(addr_place)?; @@ -112,13 +110,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_condattr_setclock" => { - let &[ref attr, ref clock_id] = + let [attr, clock_id] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.pthread_condattr_setclock(attr, clock_id)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_condattr_getclock" => { - let &[ref attr, ref clock_id] = + let [attr, clock_id] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.pthread_condattr_getclock(attr, clock_id)?; this.write_scalar(Scalar::from_i32(result), dest)?; @@ -185,12 +183,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Miscelanneous "getrandom" => { - let &[ref ptr, ref len, ref flags] = + let [ptr, len, flags] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; getrandom(this, ptr, len, flags, dest)?; } "sched_getaffinity" => { - let &[ref pid, ref cpusetsize, ref mask] = + let [pid, cpusetsize, mask] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; this.read_scalar(pid)?.to_i32()?; this.read_scalar(cpusetsize)?.to_machine_usize(this)?; @@ -204,7 +202,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Incomplete shims that we "stub out" just to get pre-main initialization code to work. // These shims are enabled only when the caller is in the standard library. "pthread_getattr_np" if this.frame_in_std() => { - let &[ref _thread, ref _attr] = + let [_thread, _attr] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; this.write_null(dest)?; } diff --git a/src/shims/posix/macos/dlsym.rs b/src/shims/posix/macos/dlsym.rs index d5996cc6a9ed1..8ce56d35da653 100644 --- a/src/shims/posix/macos/dlsym.rs +++ b/src/shims/posix/macos/dlsym.rs @@ -36,7 +36,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx match dlsym { Dlsym::getentropy => { - let &[ref ptr, ref len] = check_arg_count(args)?; + let [ptr, len] = check_arg_count(args)?; let ptr = this.read_pointer(ptr)?; let len = this.read_scalar(len)?.to_machine_usize(this)?; this.gen_random(ptr, len)?; diff --git a/src/shims/posix/macos/foreign_items.rs b/src/shims/posix/macos/foreign_items.rs index 18646b70130e4..7f6393fd30f10 100644 --- a/src/shims/posix/macos/foreign_items.rs +++ b/src/shims/posix/macos/foreign_items.rs @@ -22,50 +22,47 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx match &*link_name.as_str() { // errno "__error" => { - let &[] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let errno_place = this.last_error_place()?; this.write_scalar(errno_place.to_ref(this).to_scalar()?, dest)?; } // File related shims "close" | "close$NOCANCEL" => { - let &[ref result] = - this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [result] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.close(result)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "stat" | "stat$INODE64" => { - let &[ref path, ref buf] = + let [path, buf] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.macos_stat(path, buf)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "lstat" | "lstat$INODE64" => { - let &[ref path, ref buf] = + let [path, buf] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.macos_lstat(path, buf)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "fstat" | "fstat$INODE64" => { - let &[ref fd, ref buf] = - this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [fd, buf] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.macos_fstat(fd, buf)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "opendir" | "opendir$INODE64" => { - let &[ref name] = - this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [name] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.opendir(name)?; this.write_scalar(result, dest)?; } "readdir_r" | "readdir_r$INODE64" => { - let &[ref dirp, ref entry, ref result] = + let [dirp, entry, result] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.macos_readdir_r(dirp, entry, result)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "ftruncate" => { - let &[ref fd, ref length] = + let [fd, length] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.ftruncate64(fd, length)?; this.write_scalar(Scalar::from_i32(result), dest)?; @@ -73,7 +70,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Environment related shims "_NSGetEnviron" => { - let &[] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; this.write_pointer( this.machine.env_vars.environ.expect("machine must be initialized").ptr, dest, @@ -82,34 +79,32 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Time related shims "gettimeofday" => { - let &[ref tv, ref tz] = - this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [tv, tz] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.gettimeofday(tv, tz)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "mach_absolute_time" => { - let &[] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.mach_absolute_time()?; this.write_scalar(Scalar::from_u64(result), dest)?; } "mach_timebase_info" => { - let &[ref info] = - this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [info] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.mach_timebase_info(info)?; this.write_scalar(Scalar::from_i32(result), dest)?; } // Access to command-line arguments "_NSGetArgc" => { - let &[] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; this.write_pointer( this.machine.argc.expect("machine must be initialized").ptr, dest, )?; } "_NSGetArgv" => { - let &[] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; this.write_pointer( this.machine.argv.expect("machine must be initialized").ptr, dest, @@ -118,7 +113,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Thread-local storage "_tlv_atexit" => { - let &[ref dtor, ref data] = + let [dtor, data] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let dtor = this.read_pointer(dtor)?; let dtor = this.get_ptr_fn(dtor)?.as_instance()?; @@ -129,15 +124,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Querying system information "pthread_get_stackaddr_np" => { - let &[ref thread] = - this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [thread] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; this.read_scalar(thread)?.to_machine_usize(this)?; let stack_addr = Scalar::from_uint(STACK_ADDR, this.pointer_size()); this.write_scalar(stack_addr, dest)?; } "pthread_get_stacksize_np" => { - let &[ref thread] = - this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [thread] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; this.read_scalar(thread)?.to_machine_usize(this)?; let stack_size = Scalar::from_uint(STACK_SIZE, this.pointer_size()); this.write_scalar(stack_size, dest)?; @@ -145,8 +138,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Threading "pthread_setname_np" => { - let &[ref name] = - this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let [name] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let name = this.read_pointer(name)?; this.pthread_setname_np(name)?; } @@ -155,7 +147,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // These shims are enabled only when the caller is in the standard library. "mmap" if this.frame_in_std() => { // This is a horrible hack, but since the guard page mechanism calls mmap and expects a particular return value, we just give it that value. - let &[ref addr, _, _, _, _, _] = + let [addr, _, _, _, _, _] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let addr = this.read_scalar(addr)?.check_init()?; this.write_scalar(addr, dest)?; diff --git a/src/shims/windows/dlsym.rs b/src/shims/windows/dlsym.rs index ac9e085b5d7c9..5583e3a25895f 100644 --- a/src/shims/windows/dlsym.rs +++ b/src/shims/windows/dlsym.rs @@ -47,16 +47,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ); } - let &[ - ref handle, - ref _event, - ref _apc_routine, - ref _apc_context, - ref io_status_block, - ref buf, - ref n, - ref byte_offset, - ref _key, + let [ + handle, + _event, + _apc_routine, + _apc_context, + io_status_block, + buf, + n, + byte_offset, + _key, ] = check_arg_count(args)?; let handle = this.read_scalar(handle)?.to_machine_isize(this)?; let buf = this.read_pointer(buf)?; diff --git a/src/shims/windows/foreign_items.rs b/src/shims/windows/foreign_items.rs index d72302794318e..c49362d52b311 100644 --- a/src/shims/windows/foreign_items.rs +++ b/src/shims/windows/foreign_items.rs @@ -30,36 +30,36 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx match &*link_name.as_str() { // Environment related shims "GetEnvironmentVariableW" => { - let &[ref name, ref buf, ref size] = + let [name, buf, size] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; let result = this.GetEnvironmentVariableW(name, buf, size)?; this.write_scalar(Scalar::from_u32(result), dest)?; } "SetEnvironmentVariableW" => { - let &[ref name, ref value] = + let [name, value] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; let result = this.SetEnvironmentVariableW(name, value)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "GetEnvironmentStringsW" => { - let &[] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; + let [] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; let result = this.GetEnvironmentStringsW()?; this.write_pointer(result, dest)?; } "FreeEnvironmentStringsW" => { - let &[ref env_block] = + let [env_block] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; let result = this.FreeEnvironmentStringsW(env_block)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "GetCurrentDirectoryW" => { - let &[ref size, ref buf] = + let [size, buf] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; let result = this.GetCurrentDirectoryW(size, buf)?; this.write_scalar(Scalar::from_u32(result), dest)?; } "SetCurrentDirectoryW" => { - let &[ref path] = + let [path] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; let result = this.SetCurrentDirectoryW(path)?; this.write_scalar(Scalar::from_i32(result), dest)?; @@ -67,7 +67,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Allocation "HeapAlloc" => { - let &[ref handle, ref flags, ref size] = + let [handle, flags, size] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; this.read_scalar(handle)?.to_machine_isize(this)?; let flags = this.read_scalar(flags)?.to_u32()?; @@ -77,7 +77,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_pointer(res, dest)?; } "HeapFree" => { - let &[ref handle, ref flags, ref ptr] = + let [handle, flags, ptr] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; this.read_scalar(handle)?.to_machine_isize(this)?; this.read_scalar(flags)?.to_u32()?; @@ -86,7 +86,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_i32(1), dest)?; } "HeapReAlloc" => { - let &[ref handle, ref flags, ref ptr, ref size] = + let [handle, flags, ptr, size] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; this.read_scalar(handle)?.to_machine_isize(this)?; this.read_scalar(flags)?.to_u32()?; @@ -98,20 +98,20 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // errno "SetLastError" => { - let &[ref error] = + let [error] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; let error = this.read_scalar(error)?.check_init()?; this.set_last_error(error)?; } "GetLastError" => { - let &[] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; + let [] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; let last_error = this.get_last_error()?; this.write_scalar(last_error, dest)?; } // Querying system information "GetSystemInfo" => { - let &[ref system_info] = + let [system_info] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; let system_info = this.deref_operand(system_info)?; // Initialize with `0`. @@ -130,20 +130,19 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // This just creates a key; Windows does not natively support TLS destructors. // Create key and return it. - let &[] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; + let [] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; let key = this.machine.tls.create_tls_key(None, dest.layout.size)?; this.write_scalar(Scalar::from_uint(key, dest.layout.size), dest)?; } "TlsGetValue" => { - let &[ref key] = - this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; + let [key] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; let key = u128::from(this.read_scalar(key)?.to_u32()?); let active_thread = this.get_active_thread(); let ptr = this.machine.tls.load_tls(key, active_thread, this)?; this.write_scalar(ptr, dest)?; } "TlsSetValue" => { - let &[ref key, ref new_ptr] = + let [key, new_ptr] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; let key = u128::from(this.read_scalar(key)?.to_u32()?); let active_thread = this.get_active_thread(); @@ -156,7 +155,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Access to command-line arguments "GetCommandLineW" => { - let &[] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; + let [] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; this.write_pointer( this.machine.cmd_line.expect("machine must be initialized").ptr, dest, @@ -166,20 +165,20 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Time related shims "GetSystemTimeAsFileTime" => { #[allow(non_snake_case)] - let &[ref LPFILETIME] = + let [LPFILETIME] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; this.GetSystemTimeAsFileTime(LPFILETIME)?; } "QueryPerformanceCounter" => { #[allow(non_snake_case)] - let &[ref lpPerformanceCount] = + let [lpPerformanceCount] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; let result = this.QueryPerformanceCounter(lpPerformanceCount)?; this.write_scalar(Scalar::from_i32(result), dest)?; } "QueryPerformanceFrequency" => { #[allow(non_snake_case)] - let &[ref lpFrequency] = + let [lpFrequency] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; let result = this.QueryPerformanceFrequency(lpFrequency)?; this.write_scalar(Scalar::from_i32(result), dest)?; @@ -187,34 +186,28 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Synchronization primitives "AcquireSRWLockExclusive" => { - let &[ref ptr] = - this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; + let [ptr] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; this.AcquireSRWLockExclusive(ptr)?; } "ReleaseSRWLockExclusive" => { - let &[ref ptr] = - this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; + let [ptr] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; this.ReleaseSRWLockExclusive(ptr)?; } "TryAcquireSRWLockExclusive" => { - let &[ref ptr] = - this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; + let [ptr] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; let ret = this.TryAcquireSRWLockExclusive(ptr)?; this.write_scalar(Scalar::from_u8(ret), dest)?; } "AcquireSRWLockShared" => { - let &[ref ptr] = - this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; + let [ptr] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; this.AcquireSRWLockShared(ptr)?; } "ReleaseSRWLockShared" => { - let &[ref ptr] = - this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; + let [ptr] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; this.ReleaseSRWLockShared(ptr)?; } "TryAcquireSRWLockShared" => { - let &[ref ptr] = - this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; + let [ptr] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; let ret = this.TryAcquireSRWLockShared(ptr)?; this.write_scalar(Scalar::from_u8(ret), dest)?; } @@ -222,7 +215,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Dynamic symbol loading "GetProcAddress" => { #[allow(non_snake_case)] - let &[ref hModule, ref lpProcName] = + let [hModule, lpProcName] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; this.read_scalar(hModule)?.to_machine_isize(this)?; let name = this.read_c_str(this.read_pointer(lpProcName)?)?; @@ -237,7 +230,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Miscellaneous "SystemFunction036" => { // This is really 'RtlGenRandom'. - let &[ref ptr, ref len] = + let [ptr, len] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; let ptr = this.read_pointer(ptr)?; let len = this.read_scalar(len)?.to_u32()?; @@ -245,7 +238,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_bool(true), dest)?; } "BCryptGenRandom" => { - let &[ref algorithm, ref ptr, ref len, ref flags] = + let [algorithm, ptr, len, flags] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; let algorithm = this.read_scalar(algorithm)?; let ptr = this.read_pointer(ptr)?; @@ -267,7 +260,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "GetConsoleScreenBufferInfo" => { // `term` needs this, so we fake it. - let &[ref console, ref buffer_info] = + let [console, buffer_info] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; this.read_scalar(console)?.to_machine_isize(this)?; this.deref_operand(buffer_info)?; @@ -277,7 +270,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "GetConsoleMode" => { // Windows "isatty" (in libtest) needs this, so we fake it. - let &[ref console, ref mode] = + let [console, mode] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; this.read_scalar(console)?.to_machine_isize(this)?; this.deref_operand(mode)?; @@ -286,13 +279,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_null(dest)?; } "SwitchToThread" => { - let &[] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; + let [] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; // Note that once Miri supports concurrency, this will need to return a nonzero // value if this call does result in switching to another thread. this.write_null(dest)?; } "GetStdHandle" => { - let &[ref which] = + let [which] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; let which = this.read_scalar(which)?.to_i32()?; // We just make this the identity function, so we know later in `NtWriteFile` which @@ -303,7 +296,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Better error for attempts to create a thread "CreateThread" => { - let &[_, _, _, _, _, _] = + let [_, _, _, _, _, _] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; this.handle_unsupported("can't create threads on Windows")?; @@ -313,34 +306,34 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Incomplete shims that we "stub out" just to get pre-main initialization code to work. // These shims are enabled only when the caller is in the standard library. "GetProcessHeap" if this.frame_in_std() => { - let &[] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; + let [] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; // Just fake a HANDLE this.write_scalar(Scalar::from_machine_isize(1, this), dest)?; } "GetModuleHandleA" if this.frame_in_std() => { #[allow(non_snake_case)] - let &[_lpModuleName] = + let [_lpModuleName] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; // We need to return something non-null here to make `compat_fn!` work. this.write_scalar(Scalar::from_machine_isize(1, this), dest)?; } "SetConsoleTextAttribute" if this.frame_in_std() => { #[allow(non_snake_case)] - let &[ref _hConsoleOutput, ref _wAttribute] = + let [_hConsoleOutput, _wAttribute] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; // Pretend these does not exist / nothing happened, by returning zero. this.write_null(dest)?; } "AddVectoredExceptionHandler" if this.frame_in_std() => { #[allow(non_snake_case)] - let &[ref _First, ref _Handler] = + let [_First, _Handler] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; // Any non zero value works for the stdlib. This is just used for stack overflows anyway. this.write_scalar(Scalar::from_machine_usize(1, this), dest)?; } "SetThreadStackGuarantee" if this.frame_in_std() => { #[allow(non_snake_case)] - let &[_StackSizeInBytes] = + let [_StackSizeInBytes] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; // Any non zero value works for the stdlib. This is just used for stack overflows anyway. this.write_scalar(Scalar::from_u32(1), dest)?; @@ -352,7 +345,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if this.frame_in_std() => { #[allow(non_snake_case)] - let &[ref _lpCriticalSection] = + let [_lpCriticalSection] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; assert_eq!( this.get_total_thread_count(), @@ -365,7 +358,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "TryEnterCriticalSection" if this.frame_in_std() => { #[allow(non_snake_case)] - let &[ref _lpCriticalSection] = + let [_lpCriticalSection] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; assert_eq!( this.get_total_thread_count(), diff --git a/tests/run-pass/vec-matching-fold.rs b/tests/run-pass/vec-matching-fold.rs index 8fd36253b57f3..749f93fc0fd2c 100644 --- a/tests/run-pass/vec-matching-fold.rs +++ b/tests/run-pass/vec-matching-fold.rs @@ -7,9 +7,9 @@ fn foldl(values: &[T], U: Clone+Debug, T:Debug, F: FnMut(U, &T) -> U, { match values { - &[ref head, ref tail @ ..] => + [head, tail @ ..] => foldl(tail, function(initial, head), function), - &[] => { + [] => { let res = initial.clone(); res } } @@ -23,9 +23,9 @@ fn foldr(values: &[T], F: FnMut(&T, U) -> U, { match values { - &[ref head @ .., ref tail] => + [head @ .., tail] => foldr(head, function(tail, initial), function), - &[] => { + [] => { let res = initial.clone(); res } } From 8d42a7cfdf1eda2584c223354aaa76dd8dde7021 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sat, 30 Apr 2022 10:06:19 -0700 Subject: [PATCH 3037/3747] Replace `as` casts in llvm.x86.addcarry.64 implementation --- src/helpers.rs | 2 ++ src/helpers/convert.rs | 49 ++++++++++++++++++++++++++++++++++++++ src/shims/foreign_items.rs | 5 ++-- 3 files changed, 54 insertions(+), 2 deletions(-) create mode 100644 src/helpers/convert.rs diff --git a/src/helpers.rs b/src/helpers.rs index 107a2551995ad..5b820218a9dd7 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -1,3 +1,5 @@ +pub mod convert; + use std::mem; use std::num::NonZeroUsize; use std::time::Duration; diff --git a/src/helpers/convert.rs b/src/helpers/convert.rs new file mode 100644 index 0000000000000..4506fe47495d0 --- /dev/null +++ b/src/helpers/convert.rs @@ -0,0 +1,49 @@ +use implementations::NarrowerThan; + +/// Replacement for `as` casts going from wide integer to narrower integer. +/// +/// # Example +/// +/// ```ignore +/// let x = 99_u64; +/// let lo = x.truncate::(); +/// // lo is of type u16, equivalent to `x as u16`. +/// ``` +pub(crate) trait Truncate: Sized { + fn truncate(self) -> To + where + To: NarrowerThan, + { + NarrowerThan::truncate_from(self) + } +} + +impl Truncate for u16 {} +impl Truncate for u32 {} +impl Truncate for u64 {} +impl Truncate for u128 {} + +mod implementations { + pub(crate) trait NarrowerThan { + fn truncate_from(wide: T) -> Self; + } + + macro_rules! impl_narrower_than { + ($(NarrowerThan<{$($ty:ty),*}> for $self:ty)*) => { + $($( + impl NarrowerThan<$ty> for $self { + fn truncate_from(wide: $ty) -> Self { + wide as Self + } + } + )*)* + }; + } + + impl_narrower_than! { + NarrowerThan<{u128, u64, u32, u16}> for u8 + NarrowerThan<{u128, u64, u32}> for u16 + NarrowerThan<{u128, u64}> for u32 + NarrowerThan<{u128}> for u64 + } +} diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 8a79ed03162e3..5ff70e41518af 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -22,6 +22,7 @@ use rustc_target::{ }; use super::backtrace::EvalContextExt as _; +use crate::helpers::convert::Truncate; use crate::*; /// Returned by `emulate_foreign_item_by_name`. @@ -678,8 +679,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let a = this.read_scalar(a)?.to_u64()?; let b = this.read_scalar(b)?.to_u64()?; - let wide_sum = c_in as u128 + a as u128 + b as u128; - let (c_out, sum) = ((wide_sum >> 64) as u8, wide_sum as u64); + let wide_sum = u128::from(c_in) + u128::from(a) + u128::from(b); + let (c_out, sum) = ((wide_sum >> 64).truncate::(), wide_sum.truncate::()); let c_out_field = this.place_field(dest, 0)?; this.write_scalar(Scalar::from_u8(c_out), &c_out_field)?; From b99414871488682bd2010d7314c9a7496717ffbb Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sat, 30 Apr 2022 10:40:35 -0700 Subject: [PATCH 3038/3747] Clean up all trailing whitespace --- Cargo.toml | 2 +- bench-cargo-miri/mse/src/main.rs | 2 +- rustup-toolchain | 4 +-- .../data_race/dangling_thread_async_race.rs | 2 +- .../data_race/dealloc_read_race2.rs | 2 +- .../data_race/read_write_race_stack.rs | 2 +- .../data_race/write_write_race_stack.rs | 4 +-- tests/compile-fail/panic/double_panic.rs | 2 +- tests/compile-fail/rc_as_ptr.rs | 2 +- tests/run-pass/backtrace-api-v1.rs | 4 +-- tests/run-pass/concurrency/data_race.rs | 6 ++-- tests/run-pass/dyn-arbitrary-self.rs | 30 +++++++++---------- tests/run-pass/ptr_offset.rs | 2 +- .../stacked-borrows/stacked-borrows.rs | 2 +- tests/run-pass/threadleak_ignored.rs | 2 +- 15 files changed, 34 insertions(+), 34 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 4956a8dffd497..6d65ab6e1e469 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -42,7 +42,7 @@ rustc_version = "0.4" colored = "2" [package.metadata.rust-analyzer] -# This crate uses #[feature(rustc_private)]. +# This crate uses #[feature(rustc_private)]. # See https://github.com/rust-analyzer/rust-analyzer/pull/7891 rustc_private = true diff --git a/bench-cargo-miri/mse/src/main.rs b/bench-cargo-miri/mse/src/main.rs index 57e2860710556..b182f6cec65a8 100644 --- a/bench-cargo-miri/mse/src/main.rs +++ b/bench-cargo-miri/mse/src/main.rs @@ -4,7 +4,7 @@ static PCM: &[i16] = &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, fn main() { #[cfg(increase_thread_usage)] let thread = std::thread::spawn(|| 4); - + for _ in 0..2 { mse(PCM.len(), PCM, EXPECTED); } diff --git a/rustup-toolchain b/rustup-toolchain index 5b7e8f7fcd636..421db2b3d79f0 100755 --- a/rustup-toolchain +++ b/rustup-toolchain @@ -8,9 +8,9 @@ set -e # USAGE: # # ./rustup-toolchain: Update "miri" toolchain to match `rust-version` (the known-good version for this commit). -# +# # ./rustup-toolchain HEAD: Update "miri" toolchain and `rust-version` file to latest rustc HEAD. -# +# # ./rustup-toolchain $COMMIT: Update "miri" toolchain and `rust-version` file to match that commit. # Make sure rustup-toolchain-install-master is installed. diff --git a/tests/compile-fail/data_race/dangling_thread_async_race.rs b/tests/compile-fail/data_race/dangling_thread_async_race.rs index ad539ec5b0839..6aa5a469be3ba 100644 --- a/tests/compile-fail/data_race/dangling_thread_async_race.rs +++ b/tests/compile-fail/data_race/dangling_thread_async_race.rs @@ -36,7 +36,7 @@ fn main() { let join2 = unsafe { spawn(move || { - *c.0 = 64; //~ ERROR Data race detected between Write on Thread(id = 3) and Write on Thread(id = 1) + *c.0 = 64; //~ ERROR Data race detected between Write on Thread(id = 3) and Write on Thread(id = 1) }) }; diff --git a/tests/compile-fail/data_race/dealloc_read_race2.rs b/tests/compile-fail/data_race/dealloc_read_race2.rs index a4bf210ef439f..9f9dbfc77ed50 100644 --- a/tests/compile-fail/data_race/dealloc_read_race2.rs +++ b/tests/compile-fail/data_race/dealloc_read_race2.rs @@ -23,7 +23,7 @@ pub fn main() { }); let j2 = spawn(move || { - // Also an error of the form: Data race detected between Read on Thread(id = 2) and Deallocate on Thread(id = 1) + // Also an error of the form: Data race detected between Read on Thread(id = 2) and Deallocate on Thread(id = 1) // but the invalid allocation is detected first. *ptr.0 //~ ERROR dereferenced after this allocation got freed }); diff --git a/tests/compile-fail/data_race/read_write_race_stack.rs b/tests/compile-fail/data_race/read_write_race_stack.rs index 0cf915cdef2b1..5a1c0a4b6d6da 100644 --- a/tests/compile-fail/data_race/read_write_race_stack.rs +++ b/tests/compile-fail/data_race/read_write_race_stack.rs @@ -40,7 +40,7 @@ pub fn main() { let mut stack_var = 0usize; pointer.store(&mut stack_var as *mut _, Ordering::Release); - + sleep(Duration::from_millis(200)); stack_var //~ ERROR Data race detected between Read on Thread(id = 1) and Write on Thread(id = 2) diff --git a/tests/compile-fail/data_race/write_write_race_stack.rs b/tests/compile-fail/data_race/write_write_race_stack.rs index aa1428f8a74b7..bfe1464cb5728 100644 --- a/tests/compile-fail/data_race/write_write_race_stack.rs +++ b/tests/compile-fail/data_race/write_write_race_stack.rs @@ -37,11 +37,11 @@ pub fn main() { let mut stack_var = 0usize; pointer.store(&mut stack_var as *mut _, Ordering::Release); - + sleep(Duration::from_millis(200)); stack_var = 1usize; //~ ERROR Data race detected between Write on Thread(id = 1) and Write on Thread(id = 2) - + // read to silence errors stack_var }); diff --git a/tests/compile-fail/panic/double_panic.rs b/tests/compile-fail/panic/double_panic.rs index b42c1aff10324..670c037988c2b 100644 --- a/tests/compile-fail/panic/double_panic.rs +++ b/tests/compile-fail/panic/double_panic.rs @@ -8,5 +8,5 @@ impl Drop for Foo { } fn main() { let _foo = Foo; - panic!("first"); + panic!("first"); } diff --git a/tests/compile-fail/rc_as_ptr.rs b/tests/compile-fail/rc_as_ptr.rs index 1a9c322ac8d06..dc4e099982f80 100644 --- a/tests/compile-fail/rc_as_ptr.rs +++ b/tests/compile-fail/rc_as_ptr.rs @@ -12,7 +12,7 @@ fn main() { assert!(ptr::eq(&*strong, Weak::as_ptr(&weak))); // The strong here keeps it alive, so we can still access the object. assert_eq!(42, **unsafe { &*Weak::as_ptr(&weak) }); - + drop(strong); // But not any more. We can do Weak::as_raw(&weak), but accessing the pointer would lead to // undefined behaviour. diff --git a/tests/run-pass/backtrace-api-v1.rs b/tests/run-pass/backtrace-api-v1.rs index 7b72c85812eb0..58ed63eaf395c 100644 --- a/tests/run-pass/backtrace-api-v1.rs +++ b/tests/run-pass/backtrace-api-v1.rs @@ -24,7 +24,7 @@ fn main() { unsafe { miri_resolve_frame_names(*frame, 0, name.as_mut_ptr(), filename.as_mut_ptr()); } - + let name = String::from_utf8(name).unwrap(); let filename = String::from_utf8(filename).unwrap(); @@ -62,4 +62,4 @@ struct MiriFrame { lineno: u32, colno: u32, fn_ptr: *mut (), -} \ No newline at end of file +} diff --git a/tests/run-pass/concurrency/data_race.rs b/tests/run-pass/concurrency/data_race.rs index b53acc2691ff6..2dc0ee3f8f1ae 100644 --- a/tests/run-pass/concurrency/data_race.rs +++ b/tests/run-pass/concurrency/data_race.rs @@ -16,12 +16,12 @@ fn test_fence_sync() { let mut var = 0u32; let ptr = &mut var as *mut u32; let evil_ptr = EvilSend(ptr); - - + + let j1 = spawn(move || { unsafe { *evil_ptr.0 = 1; } fence(Ordering::Release); - SYNC.store(1, Ordering::Relaxed) + SYNC.store(1, Ordering::Relaxed) }); let j2 = spawn(move || { diff --git a/tests/run-pass/dyn-arbitrary-self.rs b/tests/run-pass/dyn-arbitrary-self.rs index 9003c478990b2..5c19c260dd956 100644 --- a/tests/run-pass/dyn-arbitrary-self.rs +++ b/tests/run-pass/dyn-arbitrary-self.rs @@ -24,14 +24,14 @@ fn stdlib_pointers() { sync::Arc, pin::Pin, }; - + trait Trait { fn by_rc(self: Rc) -> i64; fn by_arc(self: Arc) -> i64; fn by_pin_mut(self: Pin<&mut Self>) -> i64; fn by_pin_box(self: Pin>) -> i64; } - + impl Trait for i64 { fn by_rc(self: Rc) -> i64 { *self @@ -46,7 +46,7 @@ fn stdlib_pointers() { *self } } - + let rc = Rc::new(1i64) as Rc; assert_eq!(1, rc.by_rc()); @@ -66,34 +66,34 @@ fn pointers_and_wrappers() { ops::{Deref, CoerceUnsized, DispatchFromDyn}, marker::Unsize, }; - + struct Ptr(Box); - + impl Deref for Ptr { type Target = T; - + fn deref(&self) -> &T { &*self.0 } } - + impl + ?Sized, U: ?Sized> CoerceUnsized> for Ptr {} impl + ?Sized, U: ?Sized> DispatchFromDyn> for Ptr {} - + struct Wrapper(T); - + impl Deref for Wrapper { type Target = T; - + fn deref(&self) -> &T { &self.0 } } - + impl, U> CoerceUnsized> for Wrapper {} impl, U> DispatchFromDyn> for Wrapper {} - - + + trait Trait { // This method isn't object-safe yet. Unsized by-value `self` is object-safe (but not callable // without unsized_locals), but wrappers arond `Self` currently are not. @@ -103,7 +103,7 @@ fn pointers_and_wrappers() { fn wrapper_ptr(self: Wrapper>) -> i32; fn wrapper_ptr_wrapper(self: Wrapper>>) -> i32; } - + impl Trait for i32 { fn ptr_wrapper(self: Ptr>) -> i32 { **self @@ -115,7 +115,7 @@ fn pointers_and_wrappers() { ***self } } - + let pw = Ptr(Box::new(Wrapper(5))) as Ptr>; assert_eq!(pw.ptr_wrapper(), 5); diff --git a/tests/run-pass/ptr_offset.rs b/tests/run-pass/ptr_offset.rs index 71d057b8c9ced..6af3e28854ab5 100644 --- a/tests/run-pass/ptr_offset.rs +++ b/tests/run-pass/ptr_offset.rs @@ -18,7 +18,7 @@ fn test_offset_from() { unsafe { assert_eq!(x.offset_from(y), -12); assert_eq!((y as *const u32).offset_from(x as *const u32), 12/4); assert_eq!((x as *const u32).offset_from(y as *const u32), -12/4); - + let x = (((x as usize) * 2) / 2) as *const u8; assert_eq!(y.offset_from(x), 12); assert_eq!(x.offset_from(y), -12); diff --git a/tests/run-pass/stacked-borrows/stacked-borrows.rs b/tests/run-pass/stacked-borrows/stacked-borrows.rs index b63f9addb0f6c..80bab726a8f15 100644 --- a/tests/run-pass/stacked-borrows/stacked-borrows.rs +++ b/tests/run-pass/stacked-borrows/stacked-borrows.rs @@ -1,6 +1,6 @@ // compile-flags: -Zmiri-tag-raw-pointers use std::ptr; - + // Test various stacked-borrows-related things. fn main() { read_does_not_invalidate1(); diff --git a/tests/run-pass/threadleak_ignored.rs b/tests/run-pass/threadleak_ignored.rs index 7bb51d2dea61f..cbdc7c6e91068 100644 --- a/tests/run-pass/threadleak_ignored.rs +++ b/tests/run-pass/threadleak_ignored.rs @@ -22,7 +22,7 @@ fn main() { // Set up a channel so that we can learn when the other thread initialized `X` // (so that we are sure there is something to drop). let (send, recv) = std::sync::mpsc::channel::<()>(); - + let _detached = std::thread::spawn(move || { X.with(|x| *x.borrow_mut() = Some(LoudDrop(1))); send.send(()).unwrap(); From 68ab457aa04090d52b7b1a91058957afd56ecc52 Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Sat, 30 Apr 2022 13:50:35 -0400 Subject: [PATCH 3039/3747] Pass AccessKind to check_protector --- src/stacked_borrows.rs | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 6ffa89087e869..fa7d72222ed09 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -327,20 +327,21 @@ impl<'tcx> Stack { /// `None` during a deallocation. fn check_protector( item: &Item, - provoking_access: Option<(SbTag, AllocId, AllocRange, Size)>, // just for debug printing and error messages + provoking_access: Option<(SbTag, AllocId, AllocRange, Size, AccessKind)>, // just for debug printing and error messages global: &GlobalStateInner, ) -> InterpResult<'tcx> { if let SbTag::Tagged(id) = item.tag { if global.tracked_pointer_tags.contains(&id) { register_diagnostic(NonHaltingDiagnostic::PoppedPointerTag( *item, - None, + provoking_access + .map(|(tag, _alloc_id, _alloc_range, _size, access)| (tag, access)), )); } } if let Some(call) = item.protector { if global.is_active(call) { - if let Some((tag, alloc_id, alloc_range, offset)) = provoking_access { + if let Some((tag, alloc_id, alloc_range, offset, _access)) = provoking_access { Err(err_sb_ub( format!( "not granting access to tag {:?} because incompatible item is protected: {:?}", @@ -393,7 +394,11 @@ impl<'tcx> Stack { let first_incompatible_idx = self.find_first_write_incompatible(granting_idx); for item in self.borrows.drain(first_incompatible_idx..).rev() { trace!("access: popping item {:?}", item); - Stack::check_protector(&item, Some((tag, alloc_id, alloc_range, offset)), global)?; + Stack::check_protector( + &item, + Some((tag, alloc_id, alloc_range, offset, access)), + global, + )?; global.add_invalidation(item.tag, alloc_id, alloc_range); } } else { @@ -411,7 +416,7 @@ impl<'tcx> Stack { trace!("access: disabling item {:?}", item); Stack::check_protector( item, - Some((tag, alloc_id, alloc_range, offset)), + Some((tag, alloc_id, alloc_range, offset, access)), global, )?; item.perm = Permission::Disabled; From 1e49078a54a31af65900d0a72ee6d695676eba84 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 1 May 2022 13:44:12 +0200 Subject: [PATCH 3040/3747] mention some papers that use Miri --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index 6d5ee30e498d7..cc7164db18530 100644 --- a/README.md +++ b/README.md @@ -540,6 +540,12 @@ Violations of [Stacked Borrows] found that are likely bugs (but Stacked Borrows * [Various standard library aliasing issues involving raw pointers](https://github.com/rust-lang/rust/pull/78602) * [`<[T]>::copy_within` using a loan after invalidating it](https://github.com/rust-lang/rust/pull/85610) +## Scientific papers employing Miri + +* [Stacked Borrows: An Aliasing Model for Rust](https://plv.mpi-sws.org/rustbelt/stacked-borrows/) +* [Using Lightweight Formal Methods to Validate a Key-Value Storage Node in Amazon S3](https://www.amazon.science/publications/using-lightweight-formal-methods-to-validate-a-key-value-storage-node-in-amazon-s3) +* [SyRust: Automatic Testing of Rust Libraries with Semantic-Aware Program Synthesis](https://dl.acm.org/doi/10.1145/3453483.3454084) + ## License Licensed under either of From 9bb4410d3a3594e969dd6dfb9e601a9651699093 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 5 May 2022 10:28:40 +0200 Subject: [PATCH 3041/3747] tweak MIRI_SYSROOT docs --- README.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index cc7164db18530..9b05d3420e61d 100644 --- a/README.md +++ b/README.md @@ -361,9 +361,10 @@ Moreover, Miri recognizes some environment variables: checkout. Note that changing files in that directory does not automatically trigger a re-build of the standard library; you have to clear the Miri build cache manually (on Linux, `rm -rf ~/.cache/miri`). -* `MIRI_SYSROOT` (recognized by `cargo miri` and the test suite) - indicates the sysroot to use. To do the same thing with `miri` - directly, use the `--sysroot` flag. +* `MIRI_SYSROOT` (recognized by `cargo miri` and the test suite) indicates the + sysroot to use. Only set this if you do not want to use the automatically + created sysroot. (The `miri` driver sysroot is controlled via the `--sysroot` + flag instead.) * `MIRI_TEST_TARGET` (recognized by the test suite) indicates which target architecture to test against. `miri` and `cargo miri` accept the `--target` flag for the same purpose. From 9605ae807d4db775a63d2a1c8da2719d478c2906 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 6 May 2022 17:28:01 +0200 Subject: [PATCH 3042/3747] rustup --- rust-version | 2 +- src/bin/miri.rs | 2 +- src/lib.rs | 1 - tests/run-pass/stacked-borrows/2phase.rs | 1 - 4 files changed, 2 insertions(+), 4 deletions(-) diff --git a/rust-version b/rust-version index 685628ac99d53..5a3074f09a4b5 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -18b53cefdf7456bf68937b08e377b7e622a115c2 +9a251644fa2adde5f46eea8d342b7e60e4716039 diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 0030c24b19e6d..3fac07a41a6bc 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -1,4 +1,4 @@ -#![feature(rustc_private, bool_to_option, stmt_expr_attributes)] +#![feature(rustc_private, stmt_expr_attributes)] #![allow(clippy::manual_range_contains)] extern crate rustc_data_structures; diff --git a/src/lib.rs b/src/lib.rs index 3f1ba574ce069..ee7a3bcdc5cbf 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -4,7 +4,6 @@ #![feature(never_type)] #![feature(try_blocks)] #![feature(let_else)] -#![feature(bool_to_option)] #![feature(io_error_more)] #![warn(rust_2018_idioms)] #![allow( diff --git a/tests/run-pass/stacked-borrows/2phase.rs b/tests/run-pass/stacked-borrows/2phase.rs index 948da140477eb..065c76913a71e 100644 --- a/tests/run-pass/stacked-borrows/2phase.rs +++ b/tests/run-pass/stacked-borrows/2phase.rs @@ -1,5 +1,4 @@ // compile-flags: -Zmiri-tag-raw-pointers -#![allow(mutable_borrow_reservation_conflict)] trait S: Sized { fn tpb(&mut self, _s: Self) {} From d585b92fe3f48eae65c85cea4f1203cde644f8d3 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 8 May 2022 17:56:09 +0200 Subject: [PATCH 3043/3747] test for "erroneous constant used" post-monomorphization error --- src/diagnostics.rs | 6 +++++- tests/compile-fail/erroneous_const2.rs | 12 ++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) create mode 100644 tests/compile-fail/erroneous_const2.rs diff --git a/src/diagnostics.rs b/src/diagnostics.rs index 5d20cc6ff6bae..2be61c5025989 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -182,7 +182,11 @@ pub fn report_error<'tcx, 'mir>( "Undefined Behavior", ResourceExhaustion(_) => "resource exhaustion", - InvalidProgram(InvalidProgramInfo::AlreadyReported(_) | InvalidProgramInfo::Layout(..)) => + InvalidProgram( + InvalidProgramInfo::AlreadyReported(_) | + InvalidProgramInfo::Layout(..) | + InvalidProgramInfo::ReferencedConstant + ) => "post-monomorphization error", kind => bug!("This error should be impossible in Miri: {:?}", kind), diff --git a/tests/compile-fail/erroneous_const2.rs b/tests/compile-fail/erroneous_const2.rs new file mode 100644 index 0000000000000..cdec2ec4f0953 --- /dev/null +++ b/tests/compile-fail/erroneous_const2.rs @@ -0,0 +1,12 @@ +const X: u32 = 5; +const Y: u32 = 6; +const FOO: u32 = [X - Y, Y - X][(X < Y) as usize]; +//~^ERROR any use of this value +//~|WARN previously accepted + +fn main() { + println!("{}", FOO); //~ERROR post-monomorphization error + //~|ERROR evaluation of constant value failed + //~|ERROR erroneous constant used + //~|WARN previously accepted +} From 5a6c4a60fedf354f10309047455420edb1dc9968 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 9 May 2022 10:21:15 +0200 Subject: [PATCH 3044/3747] rustup --- rust-version | 2 +- src/machine.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/rust-version b/rust-version index 5a3074f09a4b5..8a247d5ab69bd 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -9a251644fa2adde5f46eea8d342b7e60e4716039 +8fbd92d0b95d847c68948d8dbbfaccb470db4f92 diff --git a/src/machine.rs b/src/machine.rs index 0a8a229c8aa2c..8b077fa815b1d 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -380,7 +380,7 @@ impl<'mir, 'tcx> Evaluator<'mir, 'tcx> { // Most of them are for weak symbols, which we all set to null (indicating that the // symbol is not supported, and triggering fallback code which ends up calling a // syscall that we do support). - for name in &["__cxa_thread_atexit_impl", "getrandom", "statx"] { + for name in &["__cxa_thread_atexit_impl", "getrandom", "statx", "__clock_gettime64"] { let layout = this.machine.layouts.usize; let place = this.allocate(layout, MiriMemoryKind::ExternStatic.into())?; this.write_scalar(Scalar::from_machine_usize(0, this), &place.into())?; From 8dbe1d02cdaaf533f91eeaf22e7627ffd8007022 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 9 May 2022 11:17:48 +0200 Subject: [PATCH 3045/3747] rustfmt --- src/machine.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/machine.rs b/src/machine.rs index 8b077fa815b1d..2d8f5855330f5 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -380,7 +380,8 @@ impl<'mir, 'tcx> Evaluator<'mir, 'tcx> { // Most of them are for weak symbols, which we all set to null (indicating that the // symbol is not supported, and triggering fallback code which ends up calling a // syscall that we do support). - for name in &["__cxa_thread_atexit_impl", "getrandom", "statx", "__clock_gettime64"] { + for name in &["__cxa_thread_atexit_impl", "getrandom", "statx", "__clock_gettime64"] + { let layout = this.machine.layouts.usize; let place = this.allocate(layout, MiriMemoryKind::ExternStatic.into())?; this.write_scalar(Scalar::from_machine_usize(0, this), &place.into())?; From c8b947a5edb209c55c2ec2d6c4c1075db5d4d4ce Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Tue, 10 May 2022 07:23:03 +0000 Subject: [PATCH 3046/3747] Use alphabetical order for miri flags --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 4cb03ed7b0b2c..291c01dd4cfd8 100644 --- a/README.md +++ b/README.md @@ -265,10 +265,6 @@ environment variable: * `-Zmiri-disable-isolation` disables host isolation. As a consequence, the program has access to host resources such as environment variables, file systems, and randomness. -* `-Zmiri-mute-stdout-stderr` silently ignores all writes to stdout and stderr, - but reports to the program that it did actually write. This is useful when you - are not interested in the actual program's messages, but only want to see miri's - errors and warnings. * `-Zmiri-isolation-error=` configures Miri's response to operations requiring host access while isolation is enabled. `abort`, `hide`, `warn`, and `warn-nobacktrace` are the supported actions. The default is to `abort`, @@ -290,6 +286,10 @@ environment variable: This can be used to find which parts of your program are executing slowly under Miri. The profile is written out to a file with the prefix ``, and can be processed using the tools in the repository https://github.com/rust-lang/measureme. +* `-Zmiri-mute-stdout-stderr` silently ignores all writes to stdout and stderr, + but reports to the program that it did actually write. This is useful when you + are not interested in the actual program's messages, but only want to see miri's + errors and warnings. * `-Zmiri-panic-on-unsupported` will makes some forms of unsupported functionality, such as FFI and unsupported syscalls, panic within the context of the emulated application instead of raising an error within the context of Miri (and halting From 6dc6256413a242a3917b01ac28059024dc6bef45 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Tue, 10 May 2022 07:23:50 +0000 Subject: [PATCH 3047/3747] Wording nit --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 291c01dd4cfd8..127206e11544d 100644 --- a/README.md +++ b/README.md @@ -288,7 +288,7 @@ environment variable: using the tools in the repository https://github.com/rust-lang/measureme. * `-Zmiri-mute-stdout-stderr` silently ignores all writes to stdout and stderr, but reports to the program that it did actually write. This is useful when you - are not interested in the actual program's messages, but only want to see miri's + are not interested in the actual program's output, but only want to see miri's errors and warnings. * `-Zmiri-panic-on-unsupported` will makes some forms of unsupported functionality, such as FFI and unsupported syscalls, panic within the context of the emulated From 82411c5840dc4e06f20c14a81767b48ef4fb19be Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 10 May 2022 12:14:47 +0200 Subject: [PATCH 3048/3747] stop relying on python being in the PATH --- miri | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/miri b/miri index 0ba7e536abe50..56ae119cd1bcc 100755 --- a/miri +++ b/miri @@ -40,7 +40,7 @@ TARGET=$(rustc --version --verbose | grep "^host:" | cut -d ' ' -f 2) SYSROOT=$(rustc --print sysroot) LIBDIR=$SYSROOT/lib/rustlib/$TARGET/lib # macOS does not have a useful readlink/realpath so we have to use Python instead... -MIRIDIR=$(dirname "$(python -c 'import os, sys; print(os.path.realpath(sys.argv[1]))' "$0")") +MIRIDIR=$(dirname "$(python3 -c 'import os, sys; print(os.path.realpath(sys.argv[1]))' "$0")") if ! test -d "$LIBDIR"; then echo "Something went wrong determining the library dir." echo "I got $LIBDIR but that does not exist." From a2f683757449657911d130c650cb0eba5b81563b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 10 May 2022 12:21:01 +0200 Subject: [PATCH 3049/3747] rustfmt --- src/machine.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/machine.rs b/src/machine.rs index 1f1caa866118f..2ecb583abb2c4 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -28,7 +28,7 @@ use rustc_span::symbol::{sym, Symbol}; use rustc_target::abi::Size; use rustc_target::spec::abi::Abi; -use crate::{*, shims::posix::FileHandler}; +use crate::{shims::posix::FileHandler, *}; // Some global facts about the emulated machine. pub const PAGE_SIZE: u64 = 4 * 1024; // FIXME: adjust to target architecture From b25d7b0e34fd488558e1665da1b2aa2397bfaaeb Mon Sep 17 00:00:00 2001 From: y86-dev <94611769+y86-dev@users.noreply.github.com> Date: Tue, 10 May 2022 20:46:12 +0200 Subject: [PATCH 3050/3747] Clarified issues when building miri with a custom rustc Co-authored-by: Ralf Jung --- CONTRIBUTING.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 359378504343f..054ff433d3ed8 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -206,6 +206,13 @@ rustup toolchain link stage2 build/x86_64-unknown-linux-gnu/stage2 rustup override set stage2 ``` +Important: You need to delete the miri cache (located at `~/.cache/miri` on Linux; the exact location is printed after the library build: "A libstd for Miri is now available in ...") when +you change the stdlib, otherwise the old, chached version will be used. + +Note: `./x.py --stage 2 compiler/rustc` currently errors with `thread 'main' +panicked at 'fs::read(stamp) failed with No such file or directory (os error 2)`, +you can simply ignore that error; Miri will build anyway. + For more information about building and configuring a local compiler, see . From 4632b2c6897ed8bfd4da39d45999a8b0a5b875f5 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 10 May 2022 21:38:32 +0200 Subject: [PATCH 3051/3747] tweak wording --- CONTRIBUTING.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 054ff433d3ed8..996164b93e8b6 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -206,8 +206,9 @@ rustup toolchain link stage2 build/x86_64-unknown-linux-gnu/stage2 rustup override set stage2 ``` -Important: You need to delete the miri cache (located at `~/.cache/miri` on Linux; the exact location is printed after the library build: "A libstd for Miri is now available in ...") when -you change the stdlib, otherwise the old, chached version will be used. +Important: You need to delete the Miri cache when you change the stdlib; otherwise the +old, chached version will be used. On Linux, the cache is located at `~/.cache/miri`; the exact +location is printed after the library build: "A libstd for Miri is now available in ...". Note: `./x.py --stage 2 compiler/rustc` currently errors with `thread 'main' panicked at 'fs::read(stamp) failed with No such file or directory (os error 2)`, From c15845bf2951991ce47ec047666a2cbe75759e9d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 11 May 2022 10:03:56 +0200 Subject: [PATCH 3052/3747] when MIRI_LOG is set, set RUSTC_LOG_ENTRY_EXIT --- src/bin/miri.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/bin/miri.rs b/src/bin/miri.rs index b1c2872513e47..0aa8755573a6b 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -155,6 +155,10 @@ fn init_early_loggers() { // initialize them both, and we always initialize `miri`'s first. let env = env_logger::Env::new().filter("MIRI_LOG").write_style("MIRI_LOG_STYLE"); env_logger::init_from_env(env); + // Enable verbose entry/exit logging by default if MIRI_LOG is set. + if env::var_os("MIRI_LOG").is_some() && env::var_os("RUSTC_LOG_ENTRY_EXIT").is_none() { + env::set_var("RUSTC_LOG_ENTRY_EXIT", "1"); + } // We only initialize `rustc` if the env var is set (so the user asked for it). // If it is not set, we avoid initializing now so that we can initialize // later with our custom settings, and *not* log anything for what happens before From 1a7f6d504a12f826b59c2cee3067fe02701aef04 Mon Sep 17 00:00:00 2001 From: Andy Wang Date: Sat, 7 May 2022 21:30:15 +0100 Subject: [PATCH 3053/3747] Use proper atomic rmw for {mutex, rwlock, cond, srwlock}_get_or_create_id --- src/data_race.rs | 29 ++++++++++++------- src/shims/posix/sync.rs | 61 +++++++++++++++++++++++++++------------ src/shims/windows/sync.rs | 21 ++++++++++---- src/sync.rs | 21 ++++++++++++++ 4 files changed, 97 insertions(+), 35 deletions(-) diff --git a/src/data_race.rs b/src/data_race.rs index d249d28d03f54..b7ccaa35305e7 100644 --- a/src/data_race.rs +++ b/src/data_race.rs @@ -441,21 +441,33 @@ impl MemoryCellClocks { /// Evaluation context extensions. impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { - /// Atomic variant of read_scalar_at_offset. - fn read_scalar_at_offset_atomic( + /// Calculates the MPlaceTy given the offset and layout of an access on an operand + fn offset_and_layout_to_place( &self, op: &OpTy<'tcx, Tag>, offset: u64, layout: TyAndLayout<'tcx>, - atomic: AtomicReadOp, - ) -> InterpResult<'tcx, ScalarMaybeUninit> { + ) -> InterpResult<'tcx, MPlaceTy<'tcx, Tag>> { let this = self.eval_context_ref(); let op_place = this.deref_operand(op)?; let offset = Size::from_bytes(offset); - // Ensure that the following read at an offset is within bounds. + // Ensure that the access is within bounds. assert!(op_place.layout.size >= offset + layout.size); let value_place = op_place.offset(offset, MemPlaceMeta::None, layout, this)?; + Ok(value_place) + } + + /// Atomic variant of read_scalar_at_offset. + fn read_scalar_at_offset_atomic( + &self, + op: &OpTy<'tcx, Tag>, + offset: u64, + layout: TyAndLayout<'tcx>, + atomic: AtomicReadOp, + ) -> InterpResult<'tcx, ScalarMaybeUninit> { + let this = self.eval_context_ref(); + let value_place = this.offset_and_layout_to_place(op, offset, layout)?; this.read_scalar_atomic(&value_place, atomic) } @@ -469,12 +481,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { atomic: AtomicWriteOp, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - let op_place = this.deref_operand(op)?; - let offset = Size::from_bytes(offset); - - // Ensure that the following read at an offset is within bounds. - assert!(op_place.layout.size >= offset + layout.size); - let value_place = op_place.offset(offset, MemPlaceMeta::None, layout, this)?; + let value_place = this.offset_and_layout_to_place(op, offset, layout)?; this.write_scalar_atomic(value.into(), &value_place, atomic) } diff --git a/src/shims/posix/sync.rs b/src/shims/posix/sync.rs index ea940df1c6e89..f8c680c0e828b 100644 --- a/src/shims/posix/sync.rs +++ b/src/shims/posix/sync.rs @@ -112,15 +112,23 @@ fn mutex_get_or_create_id<'mir, 'tcx: 'mir>( ecx: &mut MiriEvalContext<'mir, 'tcx>, mutex_op: &OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, MutexId> { - let id = mutex_get_id(ecx, mutex_op)?.to_u32()?; - if id == 0 { - // 0 is a default value and also not a valid mutex id. Need to allocate - // a new mutex. + let value_place = ecx.offset_and_layout_to_place(mutex_op, 4, ecx.machine.layouts.u32)?; + let (old, success) = ecx + .atomic_compare_exchange_scalar( + &value_place, + &ImmTy::from_uint(0u32, ecx.machine.layouts.u32), + ecx.mutex_next_id().to_u32_scalar().into(), + AtomicRwOp::Relaxed, + AtomicReadOp::Relaxed, + false, + )? + .to_scalar_pair()?; + + if success.to_bool().expect("compare_exchange's second return value is a bool") { let id = ecx.mutex_create(); - mutex_set_id(ecx, mutex_op, id.to_u32_scalar())?; Ok(id) } else { - Ok(MutexId::from_u32(id)) + Ok(MutexId::from_u32(old.to_u32().expect("layout is u32"))) } } @@ -156,15 +164,23 @@ fn rwlock_get_or_create_id<'mir, 'tcx: 'mir>( ecx: &mut MiriEvalContext<'mir, 'tcx>, rwlock_op: &OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, RwLockId> { - let id = rwlock_get_id(ecx, rwlock_op)?.to_u32()?; - if id == 0 { - // 0 is a default value and also not a valid rwlock id. Need to allocate - // a new read-write lock. + let value_place = ecx.offset_and_layout_to_place(rwlock_op, 4, ecx.machine.layouts.u32)?; + let (old, success) = ecx + .atomic_compare_exchange_scalar( + &value_place, + &ImmTy::from_uint(0u32, ecx.machine.layouts.u32), + ecx.rwlock_next_id().to_u32_scalar().into(), + AtomicRwOp::Relaxed, + AtomicReadOp::Relaxed, + false, + )? + .to_scalar_pair()?; + + if success.to_bool().expect("compare_exchange's second return value is a bool") { let id = ecx.rwlock_create(); - rwlock_set_id(ecx, rwlock_op, id.to_u32_scalar())?; Ok(id) } else { - Ok(RwLockId::from_u32(id)) + Ok(RwLockId::from_u32(old.to_u32().expect("layout is u32"))) } } @@ -228,15 +244,24 @@ fn cond_get_or_create_id<'mir, 'tcx: 'mir>( ecx: &mut MiriEvalContext<'mir, 'tcx>, cond_op: &OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, CondvarId> { - let id = cond_get_id(ecx, cond_op)?.to_u32()?; - if id == 0 { - // 0 is a default value and also not a valid conditional variable id. - // Need to allocate a new id. + let value_place = ecx.offset_and_layout_to_place(cond_op, 4, ecx.machine.layouts.u32)?; + + let (old, success) = ecx + .atomic_compare_exchange_scalar( + &value_place, + &ImmTy::from_uint(0u32, ecx.machine.layouts.u32), + ecx.condvar_next_id().to_u32_scalar().into(), + AtomicRwOp::Relaxed, + AtomicReadOp::Relaxed, + false, + )? + .to_scalar_pair()?; + + if success.to_bool().expect("compare_exchange's second return value is a bool") { let id = ecx.condvar_create(); - cond_set_id(ecx, cond_op, id.to_u32_scalar())?; Ok(id) } else { - Ok(CondvarId::from_u32(id)) + Ok(CondvarId::from_u32(old.to_u32().expect("layout is u32"))) } } diff --git a/src/shims/windows/sync.rs b/src/shims/windows/sync.rs index 78458dc6c9977..ccd65aac900fa 100644 --- a/src/shims/windows/sync.rs +++ b/src/shims/windows/sync.rs @@ -7,15 +7,24 @@ fn srwlock_get_or_create_id<'mir, 'tcx: 'mir>( ecx: &mut MiriEvalContext<'mir, 'tcx>, lock_op: &OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, RwLockId> { - let id = ecx.read_scalar_at_offset(lock_op, 0, ecx.machine.layouts.u32)?.to_u32()?; - if id == 0 { - // 0 is a default value and also not a valid rwlock id. Need to allocate - // a new rwlock. + let value_place = ecx.offset_and_layout_to_place(lock_op, 0, ecx.machine.layouts.u32)?; + + let (old, success) = ecx + .atomic_compare_exchange_scalar( + &value_place, + &ImmTy::from_uint(0u32, ecx.machine.layouts.u32), + ecx.rwlock_next_id().to_u32_scalar().into(), + AtomicRwOp::AcqRel, + AtomicReadOp::Acquire, + false, + )? + .to_scalar_pair()?; + + if success.to_bool().expect("compare_exchange's second return value is a bool") { let id = ecx.rwlock_create(); - ecx.write_scalar_at_offset(lock_op, 0, id.to_u32_scalar(), ecx.machine.layouts.u32)?; Ok(id) } else { - Ok(RwLockId::from_u32(id)) + Ok(RwLockId::from_u32(old.to_u32().expect("layout is u32"))) } } diff --git a/src/sync.rs b/src/sync.rs index ac1687a22e305..8c5b8ebfec753 100644 --- a/src/sync.rs +++ b/src/sync.rs @@ -208,6 +208,13 @@ trait EvalContextExtPriv<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // situations. impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { + #[inline] + /// Peek the id of the next mutex + fn mutex_next_id(&self) -> MutexId { + let this = self.eval_context_ref(); + this.machine.threads.sync.mutexes.next_index() + } + #[inline] /// Create state for a new mutex. fn mutex_create(&mut self) -> MutexId { @@ -290,6 +297,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.block_thread(thread); } + #[inline] + /// Peek the id of the next read write lock + fn rwlock_next_id(&self) -> RwLockId { + let this = self.eval_context_ref(); + this.machine.threads.sync.rwlocks.next_index() + } + #[inline] /// Create state for a new read write lock. fn rwlock_create(&mut self) -> RwLockId { @@ -438,6 +452,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.block_thread(writer); } + #[inline] + /// Peek the id of the next Condvar + fn condvar_next_id(&self) -> CondvarId { + let this = self.eval_context_ref(); + this.machine.threads.sync.condvars.next_index() + } + #[inline] /// Create state for a new conditional variable. fn condvar_create(&mut self) -> CondvarId { From 972b3b340ad99553618e551937d93bf28e2d2f5c Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Wed, 11 May 2022 19:13:00 -0400 Subject: [PATCH 3054/3747] Cleanup/Refactoring from review * Pass a ThreadInfo down to grant/access to get the current span lazily * Rename add_* to log_* for clarity * Hoist borrow_mut calls out of loops by tweaking the for_each signature * Explain the parameters of check_protector a bit more --- src/eval.rs | 4 -- src/machine.rs | 58 +++++---------------- src/stacked_borrows.rs | 84 ++++++++++++++++++------------ src/stacked_borrows/diagnostics.rs | 69 ++++++++++++++++++------ 4 files changed, 117 insertions(+), 98 deletions(-) diff --git a/src/eval.rs b/src/eval.rs index a3228f763a8e1..f8d23cb8279cd 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -15,7 +15,6 @@ use rustc_target::spec::abi::Abi; use rustc_session::config::EntryFnType; -use rustc_span::DUMMY_SP; use std::collections::HashSet; use crate::*; @@ -311,9 +310,6 @@ pub fn eval_entry<'tcx>( let info = ecx.preprocess_diagnostics(); match ecx.schedule()? { SchedulingAction::ExecuteStep => { - if let Some(sb) = ecx.machine.stacked_borrows.as_mut() { - sb.get_mut().current_span = DUMMY_SP; - } assert!(ecx.step()?, "a terminated thread was scheduled for execution"); } SchedulingAction::ExecuteTimeoutCallback => { diff --git a/src/machine.rs b/src/machine.rs index 2fb5dca6dd68f..7cb08066a6c3b 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -25,7 +25,6 @@ use rustc_middle::{ }; use rustc_span::def_id::{CrateNum, DefId}; use rustc_span::symbol::{sym, Symbol}; -use rustc_span::DUMMY_SP; use rustc_target::abi::Size; use rustc_target::spec::abi::Abi; @@ -308,6 +307,7 @@ impl<'mir, 'tcx> Evaluator<'mir, 'tcx> { config.tracked_pointer_tags.clone(), config.tracked_call_ids.clone(), config.tag_raw, + local_crates.clone(), ))) } else { None @@ -562,7 +562,6 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { alloc: Cow<'b, Allocation>, kind: Option>, ) -> Cow<'b, Allocation> { - set_current_span(&ecx.machine); if ecx.machine.tracked_alloc_ids.contains(&id) { register_diagnostic(NonHaltingDiagnostic::CreatedAlloc(id)); } @@ -570,7 +569,13 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { let kind = kind.expect("we set our STATIC_KIND so this cannot be None"); let alloc = alloc.into_owned(); let stacks = if let Some(stacked_borrows) = &ecx.machine.stacked_borrows { - Some(Stacks::new_allocation(id, alloc.size(), stacked_borrows, kind)) + Some(Stacks::new_allocation( + id, + alloc.size(), + stacked_borrows, + kind, + &ecx.machine.threads, + )) } else { None }; @@ -591,7 +596,6 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { ecx: &MiriEvalContext<'mir, 'tcx>, ptr: Pointer, ) -> Pointer { - set_current_span(&ecx.machine); let absolute_addr = intptrcast::GlobalStateInner::rel_ptr_to_addr(ecx, ptr); let sb_tag = if let Some(stacked_borrows) = &ecx.machine.stacked_borrows { stacked_borrows.borrow_mut().base_tag(ptr.provenance) @@ -627,7 +631,6 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { (alloc_id, tag): (AllocId, Self::TagExtra), range: AllocRange, ) -> InterpResult<'tcx> { - set_current_span(&machine); if let Some(data_race) = &alloc_extra.data_race { data_race.read(alloc_id, range, machine.data_race.as_ref().unwrap())?; } @@ -637,6 +640,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { tag, range, machine.stacked_borrows.as_ref().unwrap(), + &machine.threads, ) } else { Ok(()) @@ -651,7 +655,6 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { (alloc_id, tag): (AllocId, Self::TagExtra), range: AllocRange, ) -> InterpResult<'tcx> { - set_current_span(&machine); if let Some(data_race) = &mut alloc_extra.data_race { data_race.write(alloc_id, range, machine.data_race.as_mut().unwrap())?; } @@ -661,6 +664,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { tag, range, machine.stacked_borrows.as_ref().unwrap(), + &machine.threads, ) } else { Ok(()) @@ -675,7 +679,6 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { (alloc_id, tag): (AllocId, Self::TagExtra), range: AllocRange, ) -> InterpResult<'tcx> { - set_current_span(&machine); if machine.tracked_alloc_ids.contains(&alloc_id) { register_diagnostic(NonHaltingDiagnostic::FreedAlloc(alloc_id)); } @@ -700,12 +703,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { kind: mir::RetagKind, place: &PlaceTy<'tcx, Tag>, ) -> InterpResult<'tcx> { - if ecx.machine.stacked_borrows.is_some() { - set_current_span(&ecx.machine); - ecx.retag(kind, place) - } else { - Ok(()) - } + if ecx.machine.stacked_borrows.is_some() { ecx.retag(kind, place) } else { Ok(()) } } #[inline(always)] @@ -751,12 +749,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { #[inline(always)] fn after_stack_push(ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx> { - if ecx.machine.stacked_borrows.is_some() { - set_current_span(&ecx.machine); - ecx.retag_return_place() - } else { - Ok(()) - } + if ecx.machine.stacked_borrows.is_some() { ecx.retag_return_place() } else { Ok(()) } } #[inline(always)] @@ -773,30 +766,3 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { res } } - -// This is potentially a performance hazard. -// Factoring it into its own function lets us keep an eye on how much it shows up in a profile. -/// -fn set_current_span<'mir, 'tcx: 'mir>(machine: &Evaluator<'mir, 'tcx>) { - if let Some(sb) = machine.stacked_borrows.as_ref() { - if sb.borrow().current_span != DUMMY_SP { - return; - } - let current_span = machine - .threads - .active_thread_stack() - .into_iter() - .rev() - .find(|frame| { - let info = FrameInfo { - instance: frame.instance, - span: frame.current_span(), - lint_root: None, - }; - machine.is_local(&info) - }) - .map(|frame| frame.current_span()) - .unwrap_or(rustc_span::DUMMY_SP); - sb.borrow_mut().current_span = current_span; - } -} diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index fa7d72222ed09..1aec3c0e5eab9 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -14,7 +14,7 @@ use rustc_middle::ty::{ self, layout::{HasParamEnv, LayoutOf}, }; -use rustc_span::Span; +use rustc_span::def_id::CrateNum; use rustc_span::DUMMY_SP; use rustc_target::abi::Size; use std::collections::HashSet; @@ -118,10 +118,10 @@ pub struct GlobalStateInner { tracked_call_ids: HashSet, /// Whether to track raw pointers. tag_raw: bool, + /// Crates which are considered local for the purposes of error reporting. + local_crates: Vec, /// Extra per-allocation information extras: HashMap, - /// Current span - pub(crate) current_span: Span, } /// We need interior mutable access to the global state. @@ -174,6 +174,7 @@ impl GlobalStateInner { tracked_pointer_tags: HashSet, tracked_call_ids: HashSet, tag_raw: bool, + local_crates: Vec, ) -> Self { GlobalStateInner { next_ptr_id: NonZeroU64::new(1).unwrap(), @@ -183,8 +184,8 @@ impl GlobalStateInner { tracked_pointer_tags, tracked_call_ids, tag_raw, + local_crates, extras: HashMap::new(), - current_span: DUMMY_SP, } } @@ -325,6 +326,9 @@ impl<'tcx> Stack { /// The `provoking_access` argument is only used to produce diagnostics. /// It is `Some` when we are granting the contained access for said tag, and it is /// `None` during a deallocation. + /// Within `provoking_access, the `AllocRange` refers the entire operation, and + /// the `Size` refers to the specific location in the `AllocRange` that we are + /// currently checking. fn check_protector( item: &Item, provoking_access: Option<(SbTag, AllocId, AllocRange, Size, AccessKind)>, // just for debug printing and error messages @@ -378,6 +382,7 @@ impl<'tcx> Stack { tag: SbTag, (alloc_id, alloc_range, offset): (AllocId, AllocRange, Size), // just for debug printing and error messages global: &mut GlobalStateInner, + threads: &ThreadManager<'_, 'tcx>, ) -> InterpResult<'tcx> { // Two main steps: Find granting item, remove incompatible items above. @@ -399,7 +404,7 @@ impl<'tcx> Stack { Some((tag, alloc_id, alloc_range, offset, access)), global, )?; - global.add_invalidation(item.tag, alloc_id, alloc_range); + global.log_invalidation(item.tag, alloc_id, alloc_range, threads); } } else { // On a read, *disable* all `Unique` above the granting item. This ensures U2 for read accesses. @@ -420,7 +425,7 @@ impl<'tcx> Stack { global, )?; item.perm = Permission::Disabled; - global.add_invalidation(item.tag, alloc_id, alloc_range); + global.log_invalidation(item.tag, alloc_id, alloc_range, threads); } } } @@ -468,6 +473,7 @@ impl<'tcx> Stack { new: Item, (alloc_id, alloc_range, offset): (AllocId, AllocRange, Size), // just for debug printing and error messages global: &mut GlobalStateInner, + threads: &ThreadManager<'_, 'tcx>, ) -> InterpResult<'tcx> { // Figure out which access `perm` corresponds to. let access = @@ -495,7 +501,7 @@ impl<'tcx> Stack { // A "safe" reborrow for a pointer that actually expects some aliasing guarantees. // Here, creating a reference actually counts as an access. // This ensures F2b for `Unique`, by removing offending `SharedReadOnly`. - self.access(access, derived_from, (alloc_id, alloc_range, offset), global)?; + self.access(access, derived_from, (alloc_id, alloc_range, offset), global, threads)?; // We insert "as far up as possible": We know only compatible items are remaining // on top of `derived_from`, and we want the new item at the top so that we @@ -532,7 +538,7 @@ impl<'tcx> Stacks { fn for_each( &self, range: AllocRange, - f: impl Fn(Size, &mut Stack) -> InterpResult<'tcx>, + mut f: impl FnMut(Size, &mut Stack) -> InterpResult<'tcx>, ) -> InterpResult<'tcx> { let mut stacks = self.stacks.borrow_mut(); for (offset, stack) in stacks.iter_mut(range.start, range.size) { @@ -545,7 +551,7 @@ impl<'tcx> Stacks { fn for_each_mut( &mut self, range: AllocRange, - f: impl Fn(Size, &mut Stack) -> InterpResult<'tcx>, + mut f: impl FnMut(Size, &mut Stack) -> InterpResult<'tcx>, ) -> InterpResult<'tcx> { let stacks = self.stacks.get_mut(); for (offset, stack) in stacks.iter_mut(range.start, range.size) { @@ -562,6 +568,7 @@ impl Stacks { size: Size, state: &GlobalState, kind: MemoryKind, + threads: &ThreadManager<'_, '_>, ) -> Self { let mut extra = state.borrow_mut(); let (base_tag, perm) = match kind { @@ -595,7 +602,7 @@ impl Stacks { (tag, Permission::SharedReadWrite) } }; - extra.add_creation(None, base_tag, id, alloc_range(Size::ZERO, size)); + extra.log_creation(None, base_tag, id, alloc_range(Size::ZERO, size), threads); Stacks::new(size, perm, base_tag) } @@ -606,6 +613,7 @@ impl Stacks { tag: SbTag, range: AllocRange, state: &GlobalState, + threads: &ThreadManager<'_, 'tcx>, ) -> InterpResult<'tcx> { trace!( "read access with tag {:?}: {:?}, size {}", @@ -613,9 +621,9 @@ impl Stacks { Pointer::new(alloc_id, range.start), range.size.bytes() ); - self.for_each(range, move |offset, stack| { - let mut state = state.borrow_mut(); - stack.access(AccessKind::Read, tag, (alloc_id, range, offset), &mut state) + let mut state = state.borrow_mut(); + self.for_each(range, |offset, stack| { + stack.access(AccessKind::Read, tag, (alloc_id, range, offset), &mut state, threads) }) } @@ -626,6 +634,7 @@ impl Stacks { tag: SbTag, range: AllocRange, state: &GlobalState, + threads: &ThreadManager<'_, 'tcx>, ) -> InterpResult<'tcx> { trace!( "write access with tag {:?}: {:?}, size {}", @@ -633,9 +642,9 @@ impl Stacks { Pointer::new(alloc_id, range.start), range.size.bytes() ); - self.for_each_mut(range, move |offset, stack| { - let mut state = state.borrow_mut(); - stack.access(AccessKind::Write, tag, (alloc_id, range, offset), &mut state) + let mut state = state.borrow_mut(); + self.for_each_mut(range, |offset, stack| { + stack.access(AccessKind::Write, tag, (alloc_id, range, offset), &mut state, threads) }) } @@ -648,11 +657,11 @@ impl Stacks { state: &GlobalState, ) -> InterpResult<'tcx> { trace!("deallocation with tag {:?}: {:?}, size {}", tag, alloc_id, range.size.bytes()); - self.for_each_mut(range, move |offset, stack| { - let mut state = state.borrow_mut(); + let mut state = state.borrow_mut(); + self.for_each_mut(range, |offset, stack| { stack.dealloc(tag, (alloc_id, range, offset), &mut state) })?; - state.borrow_mut().extras.remove(&alloc_id); + state.extras.remove(&alloc_id); Ok(()) } } @@ -684,14 +693,15 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let (alloc_id, base_offset, orig_tag) = this.ptr_get_alloc_id(place.ptr)?; let mem_extra = this.machine.stacked_borrows.as_mut().unwrap().get_mut(); - mem_extra.add_creation( + mem_extra.log_creation( Some(orig_tag), new_tag, alloc_id, alloc_range(base_offset, base_offset + size), + &this.machine.threads, ); if protect { - mem_extra.add_protector(orig_tag, new_tag, alloc_id); + mem_extra.log_protector(orig_tag, new_tag, alloc_id, &this.machine.threads); } // Ensure we bail out if the pointer goes out-of-bounds (see miri#1050). @@ -752,10 +762,15 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Permission::SharedReadWrite }; let item = Item { perm, tag: new_tag, protector }; + let mut global = this.machine.stacked_borrows.as_ref().unwrap().borrow_mut(); stacked_borrows.for_each(range, |offset, stack| { - let mut global = - this.machine.stacked_borrows.as_ref().unwrap().borrow_mut(); - stack.grant(orig_tag, item, (alloc_id, range, offset), &mut *global) + stack.grant( + orig_tag, + item, + (alloc_id, range, offset), + &mut *global, + &this.machine.threads, + ) }) })?; return Ok(()); @@ -764,15 +779,16 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Here we can avoid `borrow()` calls because we have mutable references. // Note that this asserts that the allocation is mutable -- but since we are creating a // mutable pointer, that seems reasonable. - let (alloc_extra, memory_extra) = this.get_alloc_extra_mut(alloc_id)?; + let (alloc_extra, machine) = this.get_alloc_extra_mut(alloc_id)?; let stacked_borrows = alloc_extra.stacked_borrows.as_mut().expect("we should have Stacked Borrows data"); let item = Item { perm, tag: new_tag, protector }; let range = alloc_range(base_offset, size); + let mut global = machine.stacked_borrows.as_ref().unwrap().borrow_mut(); stacked_borrows.for_each_mut(range, |offset, stack| { - let mut global = memory_extra.stacked_borrows.as_ref().unwrap().borrow_mut(); - stack.grant(orig_tag, item, (alloc_id, range, offset), &mut *global) + stack.grant(orig_tag, item, (alloc_id, range, offset), &mut global, &machine.threads) })?; + Ok(()) } @@ -797,12 +813,14 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx }; // Compute new borrow. - let mem_extra = this.machine.stacked_borrows.as_mut().unwrap().get_mut(); - let new_tag = match kind { - // Give up tracking for raw pointers. - RefKind::Raw { .. } if !mem_extra.tag_raw => SbTag::Untagged, - // All other pointers are properly tracked. - _ => SbTag::Tagged(mem_extra.new_ptr()), + let new_tag = { + let mem_extra = this.machine.stacked_borrows.as_mut().unwrap().get_mut(); + match kind { + // Give up tracking for raw pointers. + RefKind::Raw { .. } if !mem_extra.tag_raw => SbTag::Untagged, + // All other pointers are properly tracked. + _ => SbTag::Tagged(mem_extra.new_ptr()), + } }; // Reborrow. diff --git a/src/stacked_borrows/diagnostics.rs b/src/stacked_borrows/diagnostics.rs index d5a65825bc2c5..f657a926c0a54 100644 --- a/src/stacked_borrows/diagnostics.rs +++ b/src/stacked_borrows/diagnostics.rs @@ -7,6 +7,7 @@ use crate::stacked_borrows::{err_sb_ub, AccessKind, GlobalStateInner, Permission use crate::Item; use crate::SbTag; use crate::Stack; +use crate::ThreadManager; use rustc_middle::mir::interpret::InterpError; @@ -52,17 +53,32 @@ pub enum TagHistory { } pub trait GlobalStateExt { - fn add_creation( + fn current_span(&self, threads: &ThreadManager<'_, '_>) -> Span; + + fn log_creation( &mut self, parent: Option, tag: SbTag, alloc: AllocId, range: AllocRange, + threads: &ThreadManager<'_, '_>, ); - fn add_invalidation(&mut self, tag: SbTag, alloc: AllocId, range: AllocRange); + fn log_invalidation( + &mut self, + tag: SbTag, + alloc: AllocId, + range: AllocRange, + threads: &ThreadManager<'_, '_>, + ); - fn add_protector(&mut self, orig_tag: SbTag, tag: SbTag, alloc: AllocId); + fn log_protector( + &mut self, + orig_tag: SbTag, + tag: SbTag, + alloc: AllocId, + threads: &ThreadManager<'_, '_>, + ); fn get_stack_history( &self, @@ -75,39 +91,62 @@ pub trait GlobalStateExt { } impl GlobalStateExt for GlobalStateInner { - fn add_creation( + fn current_span(&self, threads: &ThreadManager<'_, '_>) -> Span { + threads + .active_thread_stack() + .into_iter() + .rev() + .find(|frame| { + let def_id = frame.instance.def_id(); + def_id.is_local() || self.local_crates.contains(&def_id.krate) + }) + .map(|frame| frame.current_span()) + .unwrap_or(rustc_span::DUMMY_SP) + } + + fn log_creation( &mut self, parent: Option, tag: SbTag, alloc: AllocId, range: AllocRange, + threads: &ThreadManager<'_, '_>, ) { + let span = self.current_span(threads); let extras = self.extras.entry(alloc).or_default(); - extras.creations.push(Event { - parent, - tag, - range, - span: self.current_span, - time: extras.current_time, - }); + extras.creations.push(Event { parent, tag, range, span, time: extras.current_time }); extras.current_time += 1; } - fn add_invalidation(&mut self, tag: SbTag, alloc: AllocId, range: AllocRange) { + fn log_invalidation( + &mut self, + tag: SbTag, + alloc: AllocId, + range: AllocRange, + threads: &ThreadManager<'_, '_>, + ) { + let span = self.current_span(threads); let extras = self.extras.entry(alloc).or_default(); extras.invalidations.push(Event { parent: None, tag, range, - span: self.current_span, + span, time: extras.current_time, }); extras.current_time += 1; } - fn add_protector(&mut self, orig_tag: SbTag, tag: SbTag, alloc: AllocId) { + fn log_protector( + &mut self, + orig_tag: SbTag, + tag: SbTag, + alloc: AllocId, + threads: &ThreadManager<'_, '_>, + ) { + let span = self.current_span(threads); let extras = self.extras.entry(alloc).or_default(); - extras.protectors.push(Protection { orig_tag, tag, span: self.current_span }); + extras.protectors.push(Protection { orig_tag, tag, span }); extras.current_time += 1; } From 0ee9d3d047ab3c23c1f87e5c58a0a3e64a3dfe66 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Thu, 12 May 2022 10:42:53 +0000 Subject: [PATCH 3055/3747] Update a path to libstd source in our comments --- src/shims/foreign_items.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index e9845c5376637..66ba793b98ccb 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -42,7 +42,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// Returns the minimum alignment for the target architecture for allocations of the given size. fn min_align(&self, size: u64, kind: MiriMemoryKind) -> Align { let this = self.eval_context_ref(); - // List taken from `libstd/sys_common/alloc.rs`. + // List taken from `library/std/src/sys/common/alloc.rs`. + // This list should be kept in sync with the one from libstd. let min_align = match this.tcx.sess.target.arch.as_ref() { "x86" | "arm" | "mips" | "powerpc" | "powerpc64" | "asmjs" | "wasm32" => 8, "x86_64" | "aarch64" | "mips64" | "s390x" | "sparc64" => 16, From 19e1c72a778d3f9762d08e90fb41b0afe04a7214 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 12 May 2022 19:01:04 +0200 Subject: [PATCH 3056/3747] rustup --- rust-version | 2 +- src/helpers.rs | 10 +++++++++- src/machine.rs | 8 ++------ src/shims/foreign_items.rs | 9 ++------- 4 files changed, 14 insertions(+), 15 deletions(-) diff --git a/rust-version b/rust-version index 8a247d5ab69bd..630aee6793f38 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -8fbd92d0b95d847c68948d8dbbfaccb470db4f92 +481db40311cdd241ae4d33f34f2f75732e44d8e8 diff --git a/src/helpers.rs b/src/helpers.rs index 5b820218a9dd7..30fb284362988 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -13,7 +13,7 @@ use rustc_middle::ty::{ layout::{LayoutOf, TyAndLayout}, List, TyCtxt, }; -use rustc_span::{def_id::CrateNum, Symbol}; +use rustc_span::{def_id::CrateNum, sym, Symbol}; use rustc_target::abi::{Align, FieldsShape, Size, Variants}; use rustc_target::spec::abi::Abi; @@ -775,6 +775,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.alloc_mark_immutable(mplace.ptr.into_pointer_or_addr().unwrap().provenance.alloc_id) .unwrap(); } + + fn item_link_name(&self, def_id: DefId) -> Symbol { + let tcx = self.eval_context_ref().tcx; + match tcx.get_attrs(def_id, sym::link_name).filter_map(|a| a.value_str()).next() { + Some(name) => name, + None => tcx.item_name(def_id), + } + } } /// Check that the number of args is what we expect. diff --git a/src/machine.rs b/src/machine.rs index 2ecb583abb2c4..5facc5327d3fd 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -24,7 +24,7 @@ use rustc_middle::{ }, }; use rustc_span::def_id::{CrateNum, DefId}; -use rustc_span::symbol::{sym, Symbol}; +use rustc_span::Symbol; use rustc_target::abi::Size; use rustc_target::spec::abi::Abi; @@ -548,11 +548,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { ecx: &MiriEvalContext<'mir, 'tcx>, def_id: DefId, ) -> InterpResult<'tcx, Pointer> { - let attrs = ecx.tcx.get_attrs(def_id); - let link_name = match ecx.tcx.sess.first_attr_value_str_by_name(attrs, sym::link_name) { - Some(name) => name, - None => ecx.tcx.item_name(def_id), - }; + let link_name = ecx.item_link_name(def_id); if let Some(&ptr) = ecx.machine.extern_statics.get(&link_name) { Ok(ptr) } else { diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index e9845c5376637..bebe77a02194c 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -15,7 +15,7 @@ use rustc_middle::middle::{ use rustc_middle::mir; use rustc_middle::ty; use rustc_session::config::CrateType; -use rustc_span::{symbol::sym, Symbol}; +use rustc_span::Symbol; use rustc_target::{ abi::{Align, Size}, spec::abi::Abi, @@ -235,12 +235,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx unwind: StackPopUnwind, ) -> InterpResult<'tcx, Option<(&'mir mir::Body<'tcx>, ty::Instance<'tcx>)>> { let this = self.eval_context_mut(); - let attrs = this.tcx.get_attrs(def_id); - let link_name = this - .tcx - .sess - .first_attr_value_str_by_name(attrs, sym::link_name) - .unwrap_or_else(|| this.tcx.item_name(def_id)); + let link_name = this.item_link_name(def_id); let tcx = this.tcx.tcx; // First: functions that diverge. From a5db2c32e5f0b29c730451a80efc0b4751ca208e Mon Sep 17 00:00:00 2001 From: Andy Wang Date: Thu, 12 May 2022 20:31:40 +0100 Subject: [PATCH 3057/3747] Refactor to hide *_next_id functions --- src/shims/posix/sync.rs | 113 +++++++++++++++++++++----------------- src/shims/windows/sync.rs | 37 +++++++------ src/sync.rs | 72 +++++++++++++++++------- 3 files changed, 133 insertions(+), 89 deletions(-) diff --git a/src/shims/posix/sync.rs b/src/shims/posix/sync.rs index f8c680c0e828b..2e5da5b537982 100644 --- a/src/shims/posix/sync.rs +++ b/src/shims/posix/sync.rs @@ -113,23 +113,27 @@ fn mutex_get_or_create_id<'mir, 'tcx: 'mir>( mutex_op: &OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, MutexId> { let value_place = ecx.offset_and_layout_to_place(mutex_op, 4, ecx.machine.layouts.u32)?; - let (old, success) = ecx - .atomic_compare_exchange_scalar( - &value_place, - &ImmTy::from_uint(0u32, ecx.machine.layouts.u32), - ecx.mutex_next_id().to_u32_scalar().into(), - AtomicRwOp::Relaxed, - AtomicReadOp::Relaxed, - false, - )? - .to_scalar_pair()?; - - if success.to_bool().expect("compare_exchange's second return value is a bool") { - let id = ecx.mutex_create(); - Ok(id) - } else { - Ok(MutexId::from_u32(old.to_u32().expect("layout is u32"))) - } + + ecx.mutex_get_or_create(|ecx, next_id| { + let (old, success) = ecx + .atomic_compare_exchange_scalar( + &value_place, + &ImmTy::from_uint(0u32, ecx.machine.layouts.u32), + next_id.to_u32_scalar().into(), + AtomicRwOp::Relaxed, + AtomicReadOp::Relaxed, + false, + )? + .to_scalar_pair() + .expect("compare_exchange returns a scalar pair"); + + Ok(if success.to_bool().expect("compare_exchange's second return value is a bool") { + // Caller of the closure needs to allocate next_id + None + } else { + Some(MutexId::from_u32(old.to_u32().expect("layout is u32"))) + }) + }) } // pthread_rwlock_t is between 32 and 56 bytes, depending on the platform. @@ -165,23 +169,27 @@ fn rwlock_get_or_create_id<'mir, 'tcx: 'mir>( rwlock_op: &OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, RwLockId> { let value_place = ecx.offset_and_layout_to_place(rwlock_op, 4, ecx.machine.layouts.u32)?; - let (old, success) = ecx - .atomic_compare_exchange_scalar( - &value_place, - &ImmTy::from_uint(0u32, ecx.machine.layouts.u32), - ecx.rwlock_next_id().to_u32_scalar().into(), - AtomicRwOp::Relaxed, - AtomicReadOp::Relaxed, - false, - )? - .to_scalar_pair()?; - - if success.to_bool().expect("compare_exchange's second return value is a bool") { - let id = ecx.rwlock_create(); - Ok(id) - } else { - Ok(RwLockId::from_u32(old.to_u32().expect("layout is u32"))) - } + + ecx.rwlock_get_or_create(|ecx, next_id| { + let (old, success) = ecx + .atomic_compare_exchange_scalar( + &value_place, + &ImmTy::from_uint(0u32, ecx.machine.layouts.u32), + next_id.to_u32_scalar().into(), + AtomicRwOp::Relaxed, + AtomicReadOp::Relaxed, + false, + )? + .to_scalar_pair() + .expect("compare_exchange returns a scalar pair"); + + Ok(if success.to_bool().expect("compare_exchange's second return value is a bool") { + // Caller of the closure needs to allocate next_id + None + } else { + Some(RwLockId::from_u32(old.to_u32().expect("layout is u32"))) + }) + }) } // pthread_condattr_t @@ -246,23 +254,26 @@ fn cond_get_or_create_id<'mir, 'tcx: 'mir>( ) -> InterpResult<'tcx, CondvarId> { let value_place = ecx.offset_and_layout_to_place(cond_op, 4, ecx.machine.layouts.u32)?; - let (old, success) = ecx - .atomic_compare_exchange_scalar( - &value_place, - &ImmTy::from_uint(0u32, ecx.machine.layouts.u32), - ecx.condvar_next_id().to_u32_scalar().into(), - AtomicRwOp::Relaxed, - AtomicReadOp::Relaxed, - false, - )? - .to_scalar_pair()?; - - if success.to_bool().expect("compare_exchange's second return value is a bool") { - let id = ecx.condvar_create(); - Ok(id) - } else { - Ok(CondvarId::from_u32(old.to_u32().expect("layout is u32"))) - } + ecx.condvar_get_or_create(|ecx, next_id| { + let (old, success) = ecx + .atomic_compare_exchange_scalar( + &value_place, + &ImmTy::from_uint(0u32, ecx.machine.layouts.u32), + next_id.to_u32_scalar().into(), + AtomicRwOp::Relaxed, + AtomicReadOp::Relaxed, + false, + )? + .to_scalar_pair() + .expect("compare_exchange returns a scalar pair"); + + Ok(if success.to_bool().expect("compare_exchange's second return value is a bool") { + // Caller of the closure needs to allocate next_id + None + } else { + Some(CondvarId::from_u32(old.to_u32().expect("layout is u32"))) + }) + }) } fn cond_get_clock_id<'mir, 'tcx: 'mir>( diff --git a/src/shims/windows/sync.rs b/src/shims/windows/sync.rs index ccd65aac900fa..ff10b3b6aafeb 100644 --- a/src/shims/windows/sync.rs +++ b/src/shims/windows/sync.rs @@ -9,23 +9,26 @@ fn srwlock_get_or_create_id<'mir, 'tcx: 'mir>( ) -> InterpResult<'tcx, RwLockId> { let value_place = ecx.offset_and_layout_to_place(lock_op, 0, ecx.machine.layouts.u32)?; - let (old, success) = ecx - .atomic_compare_exchange_scalar( - &value_place, - &ImmTy::from_uint(0u32, ecx.machine.layouts.u32), - ecx.rwlock_next_id().to_u32_scalar().into(), - AtomicRwOp::AcqRel, - AtomicReadOp::Acquire, - false, - )? - .to_scalar_pair()?; - - if success.to_bool().expect("compare_exchange's second return value is a bool") { - let id = ecx.rwlock_create(); - Ok(id) - } else { - Ok(RwLockId::from_u32(old.to_u32().expect("layout is u32"))) - } + ecx.rwlock_get_or_create(|ecx, next_id| { + let (old, success) = ecx + .atomic_compare_exchange_scalar( + &value_place, + &ImmTy::from_uint(0u32, ecx.machine.layouts.u32), + next_id.to_u32_scalar().into(), + AtomicRwOp::Relaxed, + AtomicReadOp::Relaxed, + false, + )? + .to_scalar_pair() + .expect("compare_exchange returns a scalar pair"); + + Ok(if success.to_bool().expect("compare_exchange's second return value is a bool") { + // Caller of the closure needs to allocate next_id + None + } else { + Some(RwLockId::from_u32(old.to_u32().expect("layout is u32"))) + }) + }) } impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} diff --git a/src/sync.rs b/src/sync.rs index 8c5b8ebfec753..fb69c67eccd9f 100644 --- a/src/sync.rs +++ b/src/sync.rs @@ -208,13 +208,6 @@ trait EvalContextExtPriv<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // situations. impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { - #[inline] - /// Peek the id of the next mutex - fn mutex_next_id(&self) -> MutexId { - let this = self.eval_context_ref(); - this.machine.threads.sync.mutexes.next_index() - } - #[inline] /// Create state for a new mutex. fn mutex_create(&mut self) -> MutexId { @@ -222,6 +215,21 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.machine.threads.sync.mutexes.push(Default::default()) } + #[inline] + /// Provides the closure with the next MutexId. Creates that mutex if the closure returns None, + /// otherwise returns the value from the closure + fn mutex_get_or_create(&mut self, existing: F) -> InterpResult<'tcx, MutexId> + where + F: FnOnce(&mut MiriEvalContext<'mir, 'tcx>, MutexId) -> InterpResult<'tcx, Option>, + { + let this = self.eval_context_mut(); + if let Some(old) = existing(this, this.machine.threads.sync.mutexes.next_index())? { + Ok(old) + } else { + Ok(self.mutex_create()) + } + } + #[inline] /// Get the id of the thread that currently owns this lock. fn mutex_get_owner(&mut self, id: MutexId) -> ThreadId { @@ -297,13 +305,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.block_thread(thread); } - #[inline] - /// Peek the id of the next read write lock - fn rwlock_next_id(&self) -> RwLockId { - let this = self.eval_context_ref(); - this.machine.threads.sync.rwlocks.next_index() - } - #[inline] /// Create state for a new read write lock. fn rwlock_create(&mut self) -> RwLockId { @@ -311,6 +312,24 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.machine.threads.sync.rwlocks.push(Default::default()) } + #[inline] + /// Provides the closure with the next RwLockId. Creates that RwLock if the closure returns None, + /// otherwise returns the value from the closure + fn rwlock_get_or_create(&mut self, existing: F) -> InterpResult<'tcx, RwLockId> + where + F: FnOnce( + &mut MiriEvalContext<'mir, 'tcx>, + RwLockId, + ) -> InterpResult<'tcx, Option>, + { + let this = self.eval_context_mut(); + if let Some(old) = existing(this, this.machine.threads.sync.rwlocks.next_index())? { + Ok(old) + } else { + Ok(self.rwlock_create()) + } + } + #[inline] /// Check if locked. fn rwlock_is_locked(&self, id: RwLockId) -> bool { @@ -452,13 +471,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.block_thread(writer); } - #[inline] - /// Peek the id of the next Condvar - fn condvar_next_id(&self) -> CondvarId { - let this = self.eval_context_ref(); - this.machine.threads.sync.condvars.next_index() - } - #[inline] /// Create state for a new conditional variable. fn condvar_create(&mut self) -> CondvarId { @@ -466,6 +478,24 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.machine.threads.sync.condvars.push(Default::default()) } + #[inline] + /// Provides the closure with the next CondvarId. Creates that Condvar if the closure returns None, + /// otherwise returns the value from the closure + fn condvar_get_or_create(&mut self, existing: F) -> InterpResult<'tcx, CondvarId> + where + F: FnOnce( + &mut MiriEvalContext<'mir, 'tcx>, + CondvarId, + ) -> InterpResult<'tcx, Option>, + { + let this = self.eval_context_mut(); + if let Some(old) = existing(this, this.machine.threads.sync.condvars.next_index())? { + Ok(old) + } else { + Ok(self.condvar_create()) + } + } + #[inline] /// Is the conditional variable awaited? fn condvar_is_awaited(&mut self, id: CondvarId) -> bool { From 10d978c180217f09c576822a312bc7353adfc17c Mon Sep 17 00:00:00 2001 From: Andy Wang Date: Thu, 12 May 2022 21:06:17 +0100 Subject: [PATCH 3058/3747] Inline _create() calls and add assertions --- src/sync.rs | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/src/sync.rs b/src/sync.rs index fb69c67eccd9f..0eebe4f654e4c 100644 --- a/src/sync.rs +++ b/src/sync.rs @@ -223,10 +223,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx F: FnOnce(&mut MiriEvalContext<'mir, 'tcx>, MutexId) -> InterpResult<'tcx, Option>, { let this = self.eval_context_mut(); - if let Some(old) = existing(this, this.machine.threads.sync.mutexes.next_index())? { + let next_index = this.machine.threads.sync.mutexes.next_index(); + if let Some(old) = existing(this, next_index)? { Ok(old) } else { - Ok(self.mutex_create()) + let new_index = this.machine.threads.sync.mutexes.push(Default::default()); + assert_eq!(next_index, new_index); + Ok(new_index) } } @@ -323,10 +326,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, Option>, { let this = self.eval_context_mut(); - if let Some(old) = existing(this, this.machine.threads.sync.rwlocks.next_index())? { + let next_index = this.machine.threads.sync.rwlocks.next_index(); + if let Some(old) = existing(this, next_index)? { Ok(old) } else { - Ok(self.rwlock_create()) + let new_index = this.machine.threads.sync.rwlocks.push(Default::default()); + assert_eq!(next_index, new_index); + Ok(new_index) } } @@ -489,10 +495,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, Option>, { let this = self.eval_context_mut(); - if let Some(old) = existing(this, this.machine.threads.sync.condvars.next_index())? { + let next_index = this.machine.threads.sync.condvars.next_index(); + if let Some(old) = existing(this, next_index)? { Ok(old) } else { - Ok(self.condvar_create()) + let new_index = this.machine.threads.sync.condvars.push(Default::default()); + assert_eq!(next_index, new_index); + Ok(new_index) } } From 9e38dc4d499a6c405e0685d71235495699a34209 Mon Sep 17 00:00:00 2001 From: Andy Wang Date: Fri, 13 May 2022 18:42:53 +0100 Subject: [PATCH 3059/3747] Move and rename offset_and_layout_to_place to deref_operand_and_offset --- src/data_race.rs | 27 +++++---------------------- src/helpers.rs | 25 +++++++++++++++++-------- src/shims/posix/sync.rs | 6 +++--- src/shims/windows/sync.rs | 2 +- 4 files changed, 26 insertions(+), 34 deletions(-) diff --git a/src/data_race.rs b/src/data_race.rs index b7ccaa35305e7..b8656627e6f97 100644 --- a/src/data_race.rs +++ b/src/data_race.rs @@ -73,9 +73,9 @@ use rustc_middle::{mir, ty::layout::TyAndLayout}; use rustc_target::abi::Size; use crate::{ - AllocId, AllocRange, ImmTy, Immediate, InterpResult, MPlaceTy, MemPlaceMeta, MemoryKind, - MiriEvalContext, MiriEvalContextExt, MiriMemoryKind, OpTy, Pointer, RangeMap, Scalar, - ScalarMaybeUninit, Tag, ThreadId, VClock, VTimestamp, VectorIdx, + AllocId, AllocRange, HelpersEvalContextExt, ImmTy, Immediate, InterpResult, MPlaceTy, + MemoryKind, MiriEvalContext, MiriEvalContextExt, MiriMemoryKind, OpTy, Pointer, RangeMap, + Scalar, ScalarMaybeUninit, Tag, ThreadId, VClock, VTimestamp, VectorIdx, }; pub type AllocExtra = VClockAlloc; @@ -441,23 +441,6 @@ impl MemoryCellClocks { /// Evaluation context extensions. impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { - /// Calculates the MPlaceTy given the offset and layout of an access on an operand - fn offset_and_layout_to_place( - &self, - op: &OpTy<'tcx, Tag>, - offset: u64, - layout: TyAndLayout<'tcx>, - ) -> InterpResult<'tcx, MPlaceTy<'tcx, Tag>> { - let this = self.eval_context_ref(); - let op_place = this.deref_operand(op)?; - let offset = Size::from_bytes(offset); - - // Ensure that the access is within bounds. - assert!(op_place.layout.size >= offset + layout.size); - let value_place = op_place.offset(offset, MemPlaceMeta::None, layout, this)?; - Ok(value_place) - } - /// Atomic variant of read_scalar_at_offset. fn read_scalar_at_offset_atomic( &self, @@ -467,7 +450,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { atomic: AtomicReadOp, ) -> InterpResult<'tcx, ScalarMaybeUninit> { let this = self.eval_context_ref(); - let value_place = this.offset_and_layout_to_place(op, offset, layout)?; + let value_place = this.deref_operand_and_offset(op, offset, layout)?; this.read_scalar_atomic(&value_place, atomic) } @@ -481,7 +464,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { atomic: AtomicWriteOp, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - let value_place = this.offset_and_layout_to_place(op, offset, layout)?; + let value_place = this.deref_operand_and_offset(op, offset, layout)?; this.write_scalar_atomic(value.into(), &value_place, atomic) } diff --git a/src/helpers.rs b/src/helpers.rs index 5b820218a9dd7..ba5ebd3026c47 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -597,18 +597,31 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } - fn read_scalar_at_offset( + /// Calculates the MPlaceTy given the offset and layout of an access on an operand + fn deref_operand_and_offset( &self, op: &OpTy<'tcx, Tag>, offset: u64, layout: TyAndLayout<'tcx>, - ) -> InterpResult<'tcx, ScalarMaybeUninit> { + ) -> InterpResult<'tcx, MPlaceTy<'tcx, Tag>> { let this = self.eval_context_ref(); let op_place = this.deref_operand(op)?; let offset = Size::from_bytes(offset); - // Ensure that the following read at an offset is within bounds + + // Ensure that the access is within bounds. assert!(op_place.layout.size >= offset + layout.size); let value_place = op_place.offset(offset, MemPlaceMeta::None, layout, this)?; + Ok(value_place) + } + + fn read_scalar_at_offset( + &self, + op: &OpTy<'tcx, Tag>, + offset: u64, + layout: TyAndLayout<'tcx>, + ) -> InterpResult<'tcx, ScalarMaybeUninit> { + let this = self.eval_context_ref(); + let value_place = this.deref_operand_and_offset(op, offset, layout)?; this.read_scalar(&value_place.into()) } @@ -620,11 +633,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx layout: TyAndLayout<'tcx>, ) -> InterpResult<'tcx, ()> { let this = self.eval_context_mut(); - let op_place = this.deref_operand(op)?; - let offset = Size::from_bytes(offset); - // Ensure that the following read at an offset is within bounds - assert!(op_place.layout.size >= offset + layout.size); - let value_place = op_place.offset(offset, MemPlaceMeta::None, layout, this)?; + let value_place = this.deref_operand_and_offset(op, offset, layout)?; this.write_scalar(value, &value_place.into()) } diff --git a/src/shims/posix/sync.rs b/src/shims/posix/sync.rs index 2e5da5b537982..56d496984757b 100644 --- a/src/shims/posix/sync.rs +++ b/src/shims/posix/sync.rs @@ -112,7 +112,7 @@ fn mutex_get_or_create_id<'mir, 'tcx: 'mir>( ecx: &mut MiriEvalContext<'mir, 'tcx>, mutex_op: &OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, MutexId> { - let value_place = ecx.offset_and_layout_to_place(mutex_op, 4, ecx.machine.layouts.u32)?; + let value_place = ecx.deref_operand_and_offset(mutex_op, 4, ecx.machine.layouts.u32)?; ecx.mutex_get_or_create(|ecx, next_id| { let (old, success) = ecx @@ -168,7 +168,7 @@ fn rwlock_get_or_create_id<'mir, 'tcx: 'mir>( ecx: &mut MiriEvalContext<'mir, 'tcx>, rwlock_op: &OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, RwLockId> { - let value_place = ecx.offset_and_layout_to_place(rwlock_op, 4, ecx.machine.layouts.u32)?; + let value_place = ecx.deref_operand_and_offset(rwlock_op, 4, ecx.machine.layouts.u32)?; ecx.rwlock_get_or_create(|ecx, next_id| { let (old, success) = ecx @@ -252,7 +252,7 @@ fn cond_get_or_create_id<'mir, 'tcx: 'mir>( ecx: &mut MiriEvalContext<'mir, 'tcx>, cond_op: &OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, CondvarId> { - let value_place = ecx.offset_and_layout_to_place(cond_op, 4, ecx.machine.layouts.u32)?; + let value_place = ecx.deref_operand_and_offset(cond_op, 4, ecx.machine.layouts.u32)?; ecx.condvar_get_or_create(|ecx, next_id| { let (old, success) = ecx diff --git a/src/shims/windows/sync.rs b/src/shims/windows/sync.rs index ff10b3b6aafeb..6a6b2269e62a0 100644 --- a/src/shims/windows/sync.rs +++ b/src/shims/windows/sync.rs @@ -7,7 +7,7 @@ fn srwlock_get_or_create_id<'mir, 'tcx: 'mir>( ecx: &mut MiriEvalContext<'mir, 'tcx>, lock_op: &OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, RwLockId> { - let value_place = ecx.offset_and_layout_to_place(lock_op, 0, ecx.machine.layouts.u32)?; + let value_place = ecx.deref_operand_and_offset(lock_op, 0, ecx.machine.layouts.u32)?; ecx.rwlock_get_or_create(|ecx, next_id| { let (old, success) = ecx From fde022007b82d67c0fe655fe32c80a93b6715bb2 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 13 May 2022 23:19:17 +0200 Subject: [PATCH 3060/3747] data_race: use glob import like most files --- src/data_race.rs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/data_race.rs b/src/data_race.rs index b8656627e6f97..ba7300374562e 100644 --- a/src/data_race.rs +++ b/src/data_race.rs @@ -72,11 +72,7 @@ use rustc_index::vec::{Idx, IndexVec}; use rustc_middle::{mir, ty::layout::TyAndLayout}; use rustc_target::abi::Size; -use crate::{ - AllocId, AllocRange, HelpersEvalContextExt, ImmTy, Immediate, InterpResult, MPlaceTy, - MemoryKind, MiriEvalContext, MiriEvalContextExt, MiriMemoryKind, OpTy, Pointer, RangeMap, - Scalar, ScalarMaybeUninit, Tag, ThreadId, VClock, VTimestamp, VectorIdx, -}; +use crate::*; pub type AllocExtra = VClockAlloc; From 8ff0aac06c73d75d5eebea173889fb2ca94c0c75 Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Fri, 13 May 2022 19:04:51 -0400 Subject: [PATCH 3061/3747] More review feedback * Store the local crates in an Rc<[CrateNum]> * Move all the allocation history into Stacks * Clean up the implementation of get_logs_relevant_to a bit --- src/helpers.rs | 5 +- src/machine.rs | 5 +- src/stacked_borrows.rs | 151 ++++++++++++++-------- src/stacked_borrows/diagnostics.rs | 194 ++++++++++------------------- 4 files changed, 168 insertions(+), 187 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index 8d7147fff7a4b..2198bba4fe238 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -1,5 +1,6 @@ use std::mem; use std::num::NonZeroUsize; +use std::rc::Rc; use std::time::Duration; use log::trace; @@ -797,7 +798,7 @@ pub fn isolation_abort_error(name: &str) -> InterpResult<'static> { /// Retrieve the list of local crates that should have been passed by cargo-miri in /// MIRI_LOCAL_CRATES and turn them into `CrateNum`s. -pub fn get_local_crates(tcx: &TyCtxt<'_>) -> Vec { +pub fn get_local_crates(tcx: &TyCtxt<'_>) -> Rc<[CrateNum]> { // Convert the local crate names from the passed-in config into CrateNums so that they can // be looked up quickly during execution let local_crate_names = std::env::var("MIRI_LOCAL_CRATES") @@ -811,7 +812,7 @@ pub fn get_local_crates(tcx: &TyCtxt<'_>) -> Vec { local_crates.push(crate_num); } } - local_crates + Rc::from(local_crates.as_slice()) } /// Formats an AllocRange like [0x1..0x3], for use in diagnostics. diff --git a/src/machine.rs b/src/machine.rs index 7cb08066a6c3b..f215f465c00df 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -6,6 +6,7 @@ use std::cell::RefCell; use std::collections::HashSet; use std::fmt; use std::num::NonZeroU64; +use std::rc::Rc; use std::time::Instant; use rand::rngs::StdRng; @@ -273,7 +274,7 @@ pub struct Evaluator<'mir, 'tcx> { pub(crate) backtrace_style: BacktraceStyle, /// Crates which are considered local for the purposes of error reporting. - pub(crate) local_crates: Vec, + pub(crate) local_crates: Rc<[CrateNum]>, /// Mapping extern static names to their base pointer. extern_statics: FxHashMap>, @@ -307,7 +308,6 @@ impl<'mir, 'tcx> Evaluator<'mir, 'tcx> { config.tracked_pointer_tags.clone(), config.tracked_call_ids.clone(), config.tag_raw, - local_crates.clone(), ))) } else { None @@ -575,6 +575,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { stacked_borrows, kind, &ecx.machine.threads, + ecx.machine.local_crates.clone(), )) } else { None diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 1aec3c0e5eab9..8dda4a9e22a0e 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -3,9 +3,9 @@ use log::trace; use std::cell::RefCell; -use std::collections::HashMap; use std::fmt; use std::num::NonZeroU64; +use std::rc::Rc; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_hir::Mutability; @@ -22,7 +22,7 @@ use std::collections::HashSet; use crate::*; pub mod diagnostics; -use diagnostics::{AllocHistory, GlobalStateExt, StackExt}; +use diagnostics::AllocHistory; use diagnostics::TagHistory; @@ -97,6 +97,8 @@ pub struct Stack { pub struct Stacks { // Even reading memory can have effects on the stack, so we need a `RefCell` here. stacks: RefCell>, + /// Stores past operations on this allocation + history: RefCell, } /// Extra global state, available to the memory access hooks. @@ -118,10 +120,6 @@ pub struct GlobalStateInner { tracked_call_ids: HashSet, /// Whether to track raw pointers. tag_raw: bool, - /// Crates which are considered local for the purposes of error reporting. - local_crates: Vec, - /// Extra per-allocation information - extras: HashMap, } /// We need interior mutable access to the global state. @@ -174,7 +172,6 @@ impl GlobalStateInner { tracked_pointer_tags: HashSet, tracked_call_ids: HashSet, tag_raw: bool, - local_crates: Vec, ) -> Self { GlobalStateInner { next_ptr_id: NonZeroU64::new(1).unwrap(), @@ -184,8 +181,6 @@ impl GlobalStateInner { tracked_pointer_tags, tracked_call_ids, tag_raw, - local_crates, - extras: HashMap::new(), } } @@ -331,30 +326,29 @@ impl<'tcx> Stack { /// currently checking. fn check_protector( item: &Item, - provoking_access: Option<(SbTag, AllocId, AllocRange, Size, AccessKind)>, // just for debug printing and error messages + provoking_access: Option<(SbTag, AllocRange, Size, AccessKind)>, // just for debug printing and error messages global: &GlobalStateInner, + alloc_history: &mut AllocHistory, ) -> InterpResult<'tcx> { if let SbTag::Tagged(id) = item.tag { if global.tracked_pointer_tags.contains(&id) { register_diagnostic(NonHaltingDiagnostic::PoppedPointerTag( *item, - provoking_access - .map(|(tag, _alloc_id, _alloc_range, _size, access)| (tag, access)), + provoking_access.map(|(tag, _alloc_range, _size, access)| (tag, access)), )); } } if let Some(call) = item.protector { if global.is_active(call) { - if let Some((tag, alloc_id, alloc_range, offset, _access)) = provoking_access { + if let Some((tag, alloc_range, offset, _access)) = provoking_access { Err(err_sb_ub( format!( "not granting access to tag {:?} because incompatible item is protected: {:?}", tag, item ), None, - global.get_stack_history( + alloc_history.get_logs_relevant_to( tag, - alloc_id, alloc_range, offset, Some(item.tag), @@ -383,13 +377,14 @@ impl<'tcx> Stack { (alloc_id, alloc_range, offset): (AllocId, AllocRange, Size), // just for debug printing and error messages global: &mut GlobalStateInner, threads: &ThreadManager<'_, 'tcx>, + alloc_history: &mut AllocHistory, ) -> InterpResult<'tcx> { // Two main steps: Find granting item, remove incompatible items above. // Step 1: Find granting item. - let granting_idx = self - .find_granting(access, tag) - .ok_or_else(|| self.access_error(access, tag, alloc_id, alloc_range, offset, global))?; + let granting_idx = self.find_granting(access, tag).ok_or_else(|| { + alloc_history.access_error(access, tag, alloc_id, alloc_range, offset, self) + })?; // Step 2: Remove incompatible items above them. Make sure we do not remove protected // items. Behavior differs for reads and writes. @@ -401,10 +396,11 @@ impl<'tcx> Stack { trace!("access: popping item {:?}", item); Stack::check_protector( &item, - Some((tag, alloc_id, alloc_range, offset, access)), + Some((tag, alloc_range, offset, access)), global, + alloc_history, )?; - global.log_invalidation(item.tag, alloc_id, alloc_range, threads); + alloc_history.log_invalidation(item.tag, alloc_range, threads); } } else { // On a read, *disable* all `Unique` above the granting item. This ensures U2 for read accesses. @@ -421,11 +417,12 @@ impl<'tcx> Stack { trace!("access: disabling item {:?}", item); Stack::check_protector( item, - Some((tag, alloc_id, alloc_range, offset, access)), + Some((tag, alloc_range, offset, access)), global, + alloc_history, )?; item.perm = Permission::Disabled; - global.log_invalidation(item.tag, alloc_id, alloc_range, threads); + alloc_history.log_invalidation(item.tag, alloc_range, threads); } } } @@ -441,6 +438,7 @@ impl<'tcx> Stack { tag: SbTag, (alloc_id, alloc_range, offset): (AllocId, AllocRange, Size), // just for debug printing and error messages global: &GlobalStateInner, + alloc_history: &mut AllocHistory, ) -> InterpResult<'tcx> { // Step 1: Find granting item. self.find_granting(AccessKind::Write, tag).ok_or_else(|| { @@ -449,13 +447,13 @@ impl<'tcx> Stack { tag, alloc_id, ), None, - global.get_stack_history(tag, alloc_id, alloc_range, offset, None), + alloc_history.get_logs_relevant_to(tag, alloc_range, offset, None), ) })?; // Step 2: Remove all items. Also checks for protectors. for item in self.borrows.drain(..).rev() { - Stack::check_protector(&item, None, global)?; + Stack::check_protector(&item, None, global, alloc_history)?; } Ok(()) @@ -474,6 +472,7 @@ impl<'tcx> Stack { (alloc_id, alloc_range, offset): (AllocId, AllocRange, Size), // just for debug printing and error messages global: &mut GlobalStateInner, threads: &ThreadManager<'_, 'tcx>, + alloc_history: &mut AllocHistory, ) -> InterpResult<'tcx> { // Figure out which access `perm` corresponds to. let access = @@ -481,7 +480,7 @@ impl<'tcx> Stack { // Now we figure out which item grants our parent (`derived_from`) this kind of access. // We use that to determine where to put the new item. let granting_idx = self.find_granting(access, derived_from).ok_or_else(|| { - self.grant_error(derived_from, new, alloc_id, alloc_range, offset, global) + alloc_history.grant_error(derived_from, new, alloc_id, alloc_range, offset, self) })?; // Compute where to put the new item. @@ -501,7 +500,14 @@ impl<'tcx> Stack { // A "safe" reborrow for a pointer that actually expects some aliasing guarantees. // Here, creating a reference actually counts as an access. // This ensures F2b for `Unique`, by removing offending `SharedReadOnly`. - self.access(access, derived_from, (alloc_id, alloc_range, offset), global, threads)?; + self.access( + access, + derived_from, + (alloc_id, alloc_range, offset), + global, + threads, + alloc_history, + )?; // We insert "as far up as possible": We know only compatible items are remaining // on top of `derived_from`, and we want the new item at the top so that we @@ -527,22 +533,26 @@ impl<'tcx> Stack { /// Map per-stack operations to higher-level per-location-range operations. impl<'tcx> Stacks { /// Creates new stack with initial tag. - fn new(size: Size, perm: Permission, tag: SbTag) -> Self { + fn new(size: Size, perm: Permission, tag: SbTag, local_crates: Rc<[CrateNum]>) -> Self { let item = Item { perm, tag, protector: None }; let stack = Stack { borrows: vec![item] }; - Stacks { stacks: RefCell::new(RangeMap::new(size, stack)) } + Stacks { + stacks: RefCell::new(RangeMap::new(size, stack)), + history: RefCell::new(AllocHistory::new(local_crates)), + } } /// Call `f` on every stack in the range. fn for_each( &self, range: AllocRange, - mut f: impl FnMut(Size, &mut Stack) -> InterpResult<'tcx>, + mut f: impl FnMut(Size, &mut Stack, &mut AllocHistory) -> InterpResult<'tcx>, ) -> InterpResult<'tcx> { let mut stacks = self.stacks.borrow_mut(); + let history = &mut *self.history.borrow_mut(); for (offset, stack) in stacks.iter_mut(range.start, range.size) { - f(offset, stack)?; + f(offset, stack, history)?; } Ok(()) } @@ -551,11 +561,12 @@ impl<'tcx> Stacks { fn for_each_mut( &mut self, range: AllocRange, - mut f: impl FnMut(Size, &mut Stack) -> InterpResult<'tcx>, + mut f: impl FnMut(Size, &mut Stack, &mut AllocHistory) -> InterpResult<'tcx>, ) -> InterpResult<'tcx> { let stacks = self.stacks.get_mut(); + let history = &mut *self.history.borrow_mut(); for (offset, stack) in stacks.iter_mut(range.start, range.size) { - f(offset, stack)?; + f(offset, stack, history)?; } Ok(()) } @@ -569,6 +580,7 @@ impl Stacks { state: &GlobalState, kind: MemoryKind, threads: &ThreadManager<'_, '_>, + local_crates: Rc<[CrateNum]>, ) -> Self { let mut extra = state.borrow_mut(); let (base_tag, perm) = match kind { @@ -602,8 +614,14 @@ impl Stacks { (tag, Permission::SharedReadWrite) } }; - extra.log_creation(None, base_tag, id, alloc_range(Size::ZERO, size), threads); - Stacks::new(size, perm, base_tag) + let stacks = Stacks::new(size, perm, base_tag, local_crates); + stacks.history.borrow_mut().log_creation( + None, + base_tag, + alloc_range(Size::ZERO, size), + threads, + ); + stacks } #[inline(always)] @@ -622,8 +640,15 @@ impl Stacks { range.size.bytes() ); let mut state = state.borrow_mut(); - self.for_each(range, |offset, stack| { - stack.access(AccessKind::Read, tag, (alloc_id, range, offset), &mut state, threads) + self.for_each(range, |offset, stack, history| { + stack.access( + AccessKind::Read, + tag, + (alloc_id, range, offset), + &mut state, + threads, + history, + ) }) } @@ -643,8 +668,15 @@ impl Stacks { range.size.bytes() ); let mut state = state.borrow_mut(); - self.for_each_mut(range, |offset, stack| { - stack.access(AccessKind::Write, tag, (alloc_id, range, offset), &mut state, threads) + self.for_each_mut(range, |offset, stack, history| { + stack.access( + AccessKind::Write, + tag, + (alloc_id, range, offset), + &mut state, + threads, + history, + ) }) } @@ -658,10 +690,9 @@ impl Stacks { ) -> InterpResult<'tcx> { trace!("deallocation with tag {:?}: {:?}, size {}", tag, alloc_id, range.size.bytes()); let mut state = state.borrow_mut(); - self.for_each_mut(range, |offset, stack| { - stack.dealloc(tag, (alloc_id, range, offset), &mut state) + self.for_each_mut(range, |offset, stack, history| { + stack.dealloc(tag, (alloc_id, range, offset), &mut state, history) })?; - state.extras.remove(&alloc_id); Ok(()) } } @@ -692,16 +723,20 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } let (alloc_id, base_offset, orig_tag) = this.ptr_get_alloc_id(place.ptr)?; - let mem_extra = this.machine.stacked_borrows.as_mut().unwrap().get_mut(); - mem_extra.log_creation( - Some(orig_tag), - new_tag, - alloc_id, - alloc_range(base_offset, base_offset + size), - &this.machine.threads, - ); - if protect { - mem_extra.log_protector(orig_tag, new_tag, alloc_id, &this.machine.threads); + { + let extra = this.get_alloc_extra(alloc_id)?; + let stacked_borrows = + extra.stacked_borrows.as_ref().expect("we should have Stacked Borrows data"); + let mut alloc_history = stacked_borrows.history.borrow_mut(); + alloc_history.log_creation( + Some(orig_tag), + new_tag, + alloc_range(base_offset, base_offset + size), + &this.machine.threads, + ); + if protect { + alloc_history.log_protector(orig_tag, new_tag, &this.machine.threads); + } } // Ensure we bail out if the pointer goes out-of-bounds (see miri#1050). @@ -763,13 +798,14 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx }; let item = Item { perm, tag: new_tag, protector }; let mut global = this.machine.stacked_borrows.as_ref().unwrap().borrow_mut(); - stacked_borrows.for_each(range, |offset, stack| { + stacked_borrows.for_each(range, |offset, stack, history| { stack.grant( orig_tag, item, (alloc_id, range, offset), &mut *global, &this.machine.threads, + history, ) }) })?; @@ -785,8 +821,15 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let item = Item { perm, tag: new_tag, protector }; let range = alloc_range(base_offset, size); let mut global = machine.stacked_borrows.as_ref().unwrap().borrow_mut(); - stacked_borrows.for_each_mut(range, |offset, stack| { - stack.grant(orig_tag, item, (alloc_id, range, offset), &mut global, &machine.threads) + stacked_borrows.for_each_mut(range, |offset, stack, history| { + stack.grant( + orig_tag, + item, + (alloc_id, range, offset), + &mut global, + &machine.threads, + history, + ) })?; Ok(()) diff --git a/src/stacked_borrows/diagnostics.rs b/src/stacked_borrows/diagnostics.rs index f657a926c0a54..734c3a14e3b3b 100644 --- a/src/stacked_borrows/diagnostics.rs +++ b/src/stacked_borrows/diagnostics.rs @@ -1,9 +1,13 @@ +use smallvec::SmallVec; +use std::rc::Rc; + use rustc_middle::mir::interpret::{AllocId, AllocRange}; +use rustc_span::def_id::CrateNum; use rustc_span::{Span, SpanData}; use rustc_target::abi::Size; use crate::helpers::HexRange; -use crate::stacked_borrows::{err_sb_ub, AccessKind, GlobalStateInner, Permission}; +use crate::stacked_borrows::{err_sb_ub, AccessKind, Permission}; use crate::Item; use crate::SbTag; use crate::Stack; @@ -11,7 +15,7 @@ use crate::ThreadManager; use rustc_middle::mir::interpret::InterpError; -#[derive(Debug, Default)] +#[derive(Clone, Debug)] pub struct AllocHistory { // The time tags can be compressed down to one bit per event, by just storing a Vec // where each bit is set to indicate if the event was a creation or a retag @@ -19,16 +23,18 @@ pub struct AllocHistory { creations: smallvec::SmallVec<[Event; 2]>, invalidations: smallvec::SmallVec<[Event; 1]>, protectors: smallvec::SmallVec<[Protection; 1]>, + /// This field is a clone of the `local_crates` field on `Evaluator`. + local_crates: Rc<[CrateNum]>, } -#[derive(Debug)] +#[derive(Clone, Debug)] struct Protection { orig_tag: SbTag, tag: SbTag, span: Span, } -#[derive(Debug)] +#[derive(Clone, Debug)] struct Event { time: usize, parent: Option, @@ -52,45 +58,17 @@ pub enum TagHistory { }, } -pub trait GlobalStateExt { - fn current_span(&self, threads: &ThreadManager<'_, '_>) -> Span; - - fn log_creation( - &mut self, - parent: Option, - tag: SbTag, - alloc: AllocId, - range: AllocRange, - threads: &ThreadManager<'_, '_>, - ); - - fn log_invalidation( - &mut self, - tag: SbTag, - alloc: AllocId, - range: AllocRange, - threads: &ThreadManager<'_, '_>, - ); - - fn log_protector( - &mut self, - orig_tag: SbTag, - tag: SbTag, - alloc: AllocId, - threads: &ThreadManager<'_, '_>, - ); - - fn get_stack_history( - &self, - tag: SbTag, - alloc: AllocId, - alloc_range: AllocRange, - offset: Size, - protector_tag: Option, - ) -> Option; -} +impl AllocHistory { + pub fn new(local_crates: Rc<[CrateNum]>) -> Self { + Self { + current_time: 0, + creations: SmallVec::new(), + invalidations: SmallVec::new(), + protectors: SmallVec::new(), + local_crates, + } + } -impl GlobalStateExt for GlobalStateInner { fn current_span(&self, threads: &ThreadManager<'_, '_>) -> Span { threads .active_thread_stack() @@ -104,64 +82,45 @@ impl GlobalStateExt for GlobalStateInner { .unwrap_or(rustc_span::DUMMY_SP) } - fn log_creation( + pub fn log_creation( &mut self, parent: Option, tag: SbTag, - alloc: AllocId, range: AllocRange, threads: &ThreadManager<'_, '_>, ) { let span = self.current_span(threads); - let extras = self.extras.entry(alloc).or_default(); - extras.creations.push(Event { parent, tag, range, span, time: extras.current_time }); - extras.current_time += 1; + self.creations.push(Event { parent, tag, range, span, time: self.current_time }); + self.current_time += 1; } - fn log_invalidation( + pub fn log_invalidation( &mut self, tag: SbTag, - alloc: AllocId, range: AllocRange, threads: &ThreadManager<'_, '_>, ) { let span = self.current_span(threads); - let extras = self.extras.entry(alloc).or_default(); - extras.invalidations.push(Event { - parent: None, - tag, - range, - span, - time: extras.current_time, - }); - extras.current_time += 1; + self.invalidations.push(Event { parent: None, tag, range, span, time: self.current_time }); + self.current_time += 1; } - fn log_protector( - &mut self, - orig_tag: SbTag, - tag: SbTag, - alloc: AllocId, - threads: &ThreadManager<'_, '_>, - ) { + pub fn log_protector(&mut self, orig_tag: SbTag, tag: SbTag, threads: &ThreadManager<'_, '_>) { let span = self.current_span(threads); - let extras = self.extras.entry(alloc).or_default(); - extras.protectors.push(Protection { orig_tag, tag, span }); - extras.current_time += 1; + self.protectors.push(Protection { orig_tag, tag, span }); + self.current_time += 1; } - fn get_stack_history( + pub fn get_logs_relevant_to( &self, tag: SbTag, - alloc: AllocId, alloc_range: AllocRange, offset: Size, protector_tag: Option, ) -> Option { - let extras = self.extras.get(&alloc)?; let protected = protector_tag .and_then(|protector| { - extras.protectors.iter().find_map(|protection| { + self.protectors.iter().find_map(|protection| { if protection.tag == protector { Some((protection.orig_tag, protection.span.data())) } else { @@ -170,7 +129,7 @@ impl GlobalStateExt for GlobalStateInner { }) }) .and_then(|(tag, call_span)| { - extras.creations.iter().rev().find_map(|event| { + self.creations.iter().rev().find_map(|event| { if event.tag == tag { Some((event.parent?, event.span.data(), call_span)) } else { @@ -178,6 +137,7 @@ impl GlobalStateExt for GlobalStateInner { } }) }); + if let SbTag::Tagged(_) = tag { let get_matching = |events: &[Event]| { events.iter().rev().find_map(|event| { @@ -186,14 +146,14 @@ impl GlobalStateExt for GlobalStateInner { }; Some(TagHistory::Tagged { tag, - created: get_matching(&extras.creations)?, - invalidated: get_matching(&extras.invalidations), + created: get_matching(&self.creations)?, + invalidated: get_matching(&self.invalidations), protected, }) } else { let mut created_time = 0; // Find the most recently created tag that satsfies this offset - let recently_created = extras.creations.iter().rev().find_map(|event| { + let recently_created = self.creations.iter().rev().find_map(|event| { if event.tag == tag && offset >= event.range.start && offset < event.range.end() { created_time = event.time; Some((event.range, event.span.data())) @@ -206,8 +166,8 @@ impl GlobalStateExt for GlobalStateInner { // the recently created tag, and has a different span. // We're trying to make a guess at which span the user wanted to provide the tag that // they're using. - let matching_created = if let Some((_created_range, created_span)) = recently_created { - extras.creations.iter().rev().find_map(|event| { + let matching_created = recently_created.and_then(|(_created_range, created_span)| { + self.creations.iter().rev().find_map(|event| { if event.tag == tag && alloc_range.start >= event.range.start && alloc_range.end() <= event.range.end() @@ -219,26 +179,26 @@ impl GlobalStateExt for GlobalStateInner { None } }) - } else { - None - }; + }); + + // Find the most recent invalidation of this tag which post-dates the creation + let recently_invalidated = recently_created.and_then(|_| { + self.invalidations + .iter() + .rev() + .take_while(|event| event.time > created_time) + .find_map(|event| { + if event.tag == tag + && offset >= event.range.start + && offset < event.range.end() + { + Some((event.range, event.span.data())) + } else { + None + } + }) + }); - let recently_invalidated = if recently_created.is_some() { - // Find the most recent invalidation of this tag which post-dates the creation - let mut found = None; - for event in extras.invalidations.iter().rev() { - if event.time < created_time { - break; - } - if event.tag == tag && offset >= event.range.start && offset < event.range.end() - { - found = Some((event.range, event.span.data())) - } - } - found - } else { - None - }; Some(TagHistory::Untagged { recently_created, matching_created, @@ -247,40 +207,16 @@ impl GlobalStateExt for GlobalStateInner { }) } } -} - -pub trait StackExt { - fn grant_error( - &self, - derived_from: SbTag, - new: Item, - alloc_id: AllocId, - alloc_range: AllocRange, - error_offset: Size, - global: &GlobalStateInner, - ) -> InterpError<'static>; - - fn access_error( - &self, - access: AccessKind, - tag: SbTag, - alloc_id: AllocId, - alloc_range: AllocRange, - error_offset: Size, - global: &GlobalStateInner, - ) -> InterpError<'static>; -} -impl StackExt for Stack { /// Report a descriptive error when `new` could not be granted from `derived_from`. - fn grant_error( + pub fn grant_error( &self, derived_from: SbTag, new: Item, alloc_id: AllocId, alloc_range: AllocRange, error_offset: Size, - global: &GlobalStateInner, + stack: &Stack, ) -> InterpError<'static> { let action = format!( "trying to reborrow {:?} for {:?} permission at {}[{:#x}]", @@ -290,21 +226,21 @@ impl StackExt for Stack { error_offset.bytes(), ); err_sb_ub( - format!("{}{}", action, error_cause(self, derived_from)), + format!("{}{}", action, error_cause(stack, derived_from)), Some(operation_summary("a reborrow", alloc_id, alloc_range)), - global.get_stack_history(derived_from, alloc_id, alloc_range, error_offset, None), + self.get_logs_relevant_to(derived_from, alloc_range, error_offset, None), ) } /// Report a descriptive error when `access` is not permitted based on `tag`. - fn access_error( + pub fn access_error( &self, access: AccessKind, tag: SbTag, alloc_id: AllocId, alloc_range: AllocRange, error_offset: Size, - global: &GlobalStateInner, + stack: &Stack, ) -> InterpError<'static> { let action = format!( "attempting a {} using {:?} at {}[{:#x}]", @@ -314,9 +250,9 @@ impl StackExt for Stack { error_offset.bytes(), ); err_sb_ub( - format!("{}{}", action, error_cause(self, tag)), + format!("{}{}", action, error_cause(stack, tag)), Some(operation_summary("an access", alloc_id, alloc_range)), - global.get_stack_history(tag, alloc_id, alloc_range, error_offset, None), + self.get_logs_relevant_to(tag, alloc_range, error_offset, None), ) } } From f8478df6dcdf92192f0df550145283673c494a73 Mon Sep 17 00:00:00 2001 From: carbotaniuman <41451839+carbotaniuman@users.noreply.github.com> Date: Sat, 14 May 2022 13:03:47 -0500 Subject: [PATCH 3062/3747] Bump rustc for permissive provenance --- rust-version | 2 +- src/machine.rs | 26 +++++++++++++++++++++----- 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/rust-version b/rust-version index 630aee6793f38..1c54dc72ba4b0 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -481db40311cdd241ae4d33f34f2f75732e44d8e8 +2d691170885b32502b391b8b1a0d54d2419a5653 diff --git a/src/machine.rs b/src/machine.rs index 5facc5327d3fd..035f5df70723b 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -158,8 +158,8 @@ impl Provenance for Tag { write!(f, "{:?}", tag.sb) } - fn get_alloc_id(self) -> AllocId { - self.alloc_id + fn get_alloc_id(self) -> Option { + Some(self.alloc_id) } } @@ -600,21 +600,37 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { } #[inline(always)] - fn ptr_from_addr( + fn ptr_from_addr_cast( ecx: &MiriEvalContext<'mir, 'tcx>, addr: u64, ) -> Pointer> { intptrcast::GlobalStateInner::ptr_from_addr(addr, ecx) } + #[inline(always)] + fn ptr_from_addr_transmute( + ecx: &MiriEvalContext<'mir, 'tcx>, + addr: u64, + ) -> Pointer> { + Self::ptr_from_addr_cast(ecx, addr) + } + + #[inline(always)] + fn expose_ptr( + _ecx: &mut InterpCx<'mir, 'tcx, Self>, + _ptr: Pointer, + ) -> InterpResult<'tcx> { + Ok(()) + } + /// Convert a pointer with provenance into an allocation-offset pair, /// or a `None` with an absolute address if that conversion is not possible. fn ptr_get_alloc( ecx: &MiriEvalContext<'mir, 'tcx>, ptr: Pointer, - ) -> (AllocId, Size, Self::TagExtra) { + ) -> Option<(AllocId, Size, Self::TagExtra)> { let rel = intptrcast::GlobalStateInner::abs_ptr_to_rel(ecx, ptr); - (ptr.provenance.alloc_id, rel, ptr.provenance.sb) + Some((ptr.provenance.alloc_id, rel, ptr.provenance.sb)) } #[inline(always)] From 90a190e03b56b9efd5f431caee9b9f7ebc17371d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 15 May 2022 10:26:47 +0200 Subject: [PATCH 3063/3747] don't ICE when libcore is missing --- src/eval.rs | 13 ++++++++----- src/helpers.rs | 11 ++++++++--- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/src/eval.rs b/src/eval.rs index 028c9b97abb37..5f6348fe0bde5 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -172,15 +172,18 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( Evaluator::late_init(&mut ecx, config)?; // Make sure we have MIR. We check MIR for some stable monomorphic function in libcore. - let sentinel = ecx.resolve_path(&["core", "ascii", "escape_default"]); - if !tcx.is_mir_available(sentinel.def.def_id()) { - tcx.sess.fatal("the current sysroot was built without `-Zalways-encode-mir`. Use `cargo miri setup` to prepare a sysroot that is suitable for Miri."); + let sentinel = ecx.try_resolve_path(&["core", "ascii", "escape_default"]); + if !matches!(sentinel, Some(s) if tcx.is_mir_available(s.def.def_id())) { + tcx.sess.fatal( + "the current sysroot was built without `-Zalways-encode-mir`, or libcore seems missing. \ + Use `cargo miri setup` to prepare a sysroot that is suitable for Miri." + ); } - // Setup first stack-frame + // Setup first stack frame. let entry_instance = ty::Instance::mono(tcx, entry_id); - // First argument is constructed later, because its skipped if the entry function uses #[start] + // First argument is constructed later, because it's skipped if the entry function uses #[start]. // Second argument (argc): length of `config.args`. let argc = Scalar::from_machine_usize(u64::try_from(config.args.len()).unwrap(), &ecx); diff --git a/src/helpers.rs b/src/helpers.rs index 0341c78802352..6beb3f8c3bb09 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -71,11 +71,16 @@ fn try_resolve_did<'tcx>(tcx: TyCtxt<'tcx>, path: &[&str]) -> Option { } pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { + /// Gets an instance for a path; fails gracefully if the path does not exist. + fn try_resolve_path(&self, path: &[&str]) -> Option> { + let did = try_resolve_did(self.eval_context_ref().tcx.tcx, path)?; + Some(ty::Instance::mono(self.eval_context_ref().tcx.tcx, did)) + } + /// Gets an instance for a path. fn resolve_path(&self, path: &[&str]) -> ty::Instance<'tcx> { - let did = try_resolve_did(self.eval_context_ref().tcx.tcx, path) - .unwrap_or_else(|| panic!("failed to find required Rust item: {:?}", path)); - ty::Instance::mono(self.eval_context_ref().tcx.tcx, did) + self.try_resolve_path(path) + .unwrap_or_else(|| panic!("failed to find required Rust item: {:?}", path)) } /// Evaluates the scalar at the specified path. Returns Some(val) From ea63a695c8ba0f4322f21074f7646e0ea9f43001 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 15 May 2022 12:56:39 +0200 Subject: [PATCH 3064/3747] rustup --- rust-version | 2 +- src/shims/posix/sync.rs | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/rust-version b/rust-version index 1c54dc72ba4b0..dd746e9e2ae4e 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -2d691170885b32502b391b8b1a0d54d2419a5653 +e1ec3260d79497080ca86540562d410ba67d2a95 diff --git a/src/shims/posix/sync.rs b/src/shims/posix/sync.rs index 56d496984757b..1b6112a3311f7 100644 --- a/src/shims/posix/sync.rs +++ b/src/shims/posix/sync.rs @@ -876,8 +876,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn layout_of_maybe_uninit<'tcx>(tcx: TyCtxtAt<'tcx>, param: Ty<'tcx>) -> TyAndLayout<'tcx> { let def_id = tcx.require_lang_item(LangItem::MaybeUninit, None); - let def_ty = tcx.type_of(def_id); - let ty = def_ty.subst(*tcx, &[param.into()]); + let ty = tcx.bound_type_of(def_id).subst(*tcx, &[param.into()]); let param_env = tcx.param_env(def_id); tcx.layout_of(param_env.and(ty)).unwrap() From 3406829bb3dec61b913d449d02f22e79614d14d7 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 17 May 2022 15:36:59 +0200 Subject: [PATCH 3065/3747] rustup-toolchain: also prepare toolchain for vscode --- rustup-toolchain | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/rustup-toolchain b/rustup-toolchain index 421db2b3d79f0..7fdcdabcee143 100755 --- a/rustup-toolchain +++ b/rustup-toolchain @@ -44,3 +44,7 @@ rustup override set miri # Cleanup. cargo clean + +# Call 'cargo metadata' on the sources in case that changes the lockfile +# (which fails under soem setups when it is done from inside vscode). +cargo metadata --format-version 1 --manifest-path "$(rustc --print sysroot)/lib/rustlib/rustc-src/rust/compiler/rustc/Cargo.toml" >/dev/null From 6b6f92d4bc50dfcfa62010122182b91f1ca40530 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 17 May 2022 18:59:27 +0200 Subject: [PATCH 3066/3747] I cannot type --- rustup-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rustup-toolchain b/rustup-toolchain index 7fdcdabcee143..59ce6f85a0856 100755 --- a/rustup-toolchain +++ b/rustup-toolchain @@ -46,5 +46,5 @@ rustup override set miri cargo clean # Call 'cargo metadata' on the sources in case that changes the lockfile -# (which fails under soem setups when it is done from inside vscode). +# (which fails under some setups when it is done from inside vscode). cargo metadata --format-version 1 --manifest-path "$(rustc --print sysroot)/lib/rustlib/rustc-src/rust/compiler/rustc/Cargo.toml" >/dev/null From 30548bb57e3a848568280a72878c3de8b8101d36 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 17 May 2022 17:36:34 +0200 Subject: [PATCH 3067/3747] test for validity of references pointing to uninhabited types --- tests/compile-fail/validity/ref_to_uninhabited1.rs | 6 ++++++ tests/compile-fail/validity/ref_to_uninhabited2.rs | 7 +++++++ 2 files changed, 13 insertions(+) create mode 100644 tests/compile-fail/validity/ref_to_uninhabited1.rs create mode 100644 tests/compile-fail/validity/ref_to_uninhabited2.rs diff --git a/tests/compile-fail/validity/ref_to_uninhabited1.rs b/tests/compile-fail/validity/ref_to_uninhabited1.rs new file mode 100644 index 0000000000000..e5522ccaeab51 --- /dev/null +++ b/tests/compile-fail/validity/ref_to_uninhabited1.rs @@ -0,0 +1,6 @@ +#![feature(never_type)] +use std::mem::transmute; + +fn main() { unsafe { + let _x: &! = transmute(&42); //~ERROR encountered a reference pointing to uninhabited type ! +} } diff --git a/tests/compile-fail/validity/ref_to_uninhabited2.rs b/tests/compile-fail/validity/ref_to_uninhabited2.rs new file mode 100644 index 0000000000000..3778719dc58ce --- /dev/null +++ b/tests/compile-fail/validity/ref_to_uninhabited2.rs @@ -0,0 +1,7 @@ +use std::mem::transmute; + +enum Void {} + +fn main() { unsafe { + let _x: &(i32, Void) = transmute(&42); //~ERROR encountered a reference pointing to uninhabited type (i32, Void) +} } From 092c2b9d9239fce273d1268289da0a1f454a01c2 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 18 May 2022 08:32:08 +0200 Subject: [PATCH 3068/3747] change one of the ref-to-uninhbaited tests to Box --- tests/compile-fail/validity/ref_to_uninhabited1.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/compile-fail/validity/ref_to_uninhabited1.rs b/tests/compile-fail/validity/ref_to_uninhabited1.rs index e5522ccaeab51..51a3279ffae97 100644 --- a/tests/compile-fail/validity/ref_to_uninhabited1.rs +++ b/tests/compile-fail/validity/ref_to_uninhabited1.rs @@ -1,6 +1,7 @@ #![feature(never_type)] -use std::mem::transmute; +use std::mem::{transmute, forget}; fn main() { unsafe { - let _x: &! = transmute(&42); //~ERROR encountered a reference pointing to uninhabited type ! + let x: Box = transmute(&mut 42); //~ERROR encountered a box pointing to uninhabited type ! + forget(x); } } From 439f861101f72b6e6298b87151f23fa3cfcda7f7 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 18 May 2022 08:33:10 +0200 Subject: [PATCH 3069/3747] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index dd746e9e2ae4e..8788a013aca72 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -e1ec3260d79497080ca86540562d410ba67d2a95 +77972d2d0134fb597249b3b64dcf9510a790c34e From ada864f387d5425076159a3cdf1c33fcc371838b Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Thu, 19 May 2022 09:29:08 -0400 Subject: [PATCH 3070/3747] Pass the correct size to the AllocRange for log_creation --- src/stacked_borrows.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 8dda4a9e22a0e..d7c2139323245 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -731,7 +731,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx alloc_history.log_creation( Some(orig_tag), new_tag, - alloc_range(base_offset, base_offset + size), + alloc_range(base_offset, size), &this.machine.threads, ); if protect { From a941af81614825db21a4b0b59d9c4ff6c5edd547 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 20 May 2022 08:08:11 +0200 Subject: [PATCH 3071/3747] rustup --- rust-version | 2 +- tests/run-pass/concurrency/tls_lib_drop.rs | 2 +- tests/run-pass/concurrency/tls_lib_drop_single_thread.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/rust-version b/rust-version index 8788a013aca72..e6bd4b95a8bd6 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -77972d2d0134fb597249b3b64dcf9510a790c34e +f24ef2e296ec6fc6fd2e24d7e4bfec3f4cb0577a diff --git a/tests/run-pass/concurrency/tls_lib_drop.rs b/tests/run-pass/concurrency/tls_lib_drop.rs index 3220aa43148d4..86f03bac34f61 100644 --- a/tests/run-pass/concurrency/tls_lib_drop.rs +++ b/tests/run-pass/concurrency/tls_lib_drop.rs @@ -10,7 +10,7 @@ struct TestCell { impl Drop for TestCell { fn drop(&mut self) { for _ in 0..10 { thread::yield_now(); } - println!("Dropping: {} (should be before 'Continue main 1').", self.value.borrow()) + println!("Dropping: {} (should be before 'Continue main 1').", *self.value.borrow()) } } diff --git a/tests/run-pass/concurrency/tls_lib_drop_single_thread.rs b/tests/run-pass/concurrency/tls_lib_drop_single_thread.rs index ef8b2c02ed928..2766ba36d12b6 100644 --- a/tests/run-pass/concurrency/tls_lib_drop_single_thread.rs +++ b/tests/run-pass/concurrency/tls_lib_drop_single_thread.rs @@ -8,7 +8,7 @@ struct TestCell { impl Drop for TestCell { fn drop(&mut self) { - eprintln!("Dropping: {}", self.value.borrow()) + eprintln!("Dropping: {}", *self.value.borrow()) } } From 8b4d613cc81c8cc2b52485149e4aa1c8bae3394d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 20 May 2022 18:11:31 +0200 Subject: [PATCH 3072/3747] rustup --- rust-version | 2 +- src/machine.rs | 7 ++++++- tests/compile-fail/ptr_integer_transmute.rs | 2 +- tests/compile-fail/strict_provenance_transmute.rs | 2 +- tests/compile-fail/uninit_float.rs | 2 +- tests/compile-fail/uninit_integer.rs | 2 +- tests/compile-fail/uninit_integer_signed.rs | 2 +- 7 files changed, 12 insertions(+), 7 deletions(-) diff --git a/rust-version b/rust-version index e6bd4b95a8bd6..5526a13d5fc77 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -f24ef2e296ec6fc6fd2e24d7e4bfec3f4cb0577a +22ee39504a702f75485582d02060495a01254de1 diff --git a/src/machine.rs b/src/machine.rs index 3d97bed7ae256..7ab15b9f9ceb6 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -470,7 +470,12 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { } #[inline(always)] - fn enforce_number_validity(ecx: &MiriEvalContext<'mir, 'tcx>) -> bool { + fn enforce_number_init(ecx: &MiriEvalContext<'mir, 'tcx>) -> bool { + ecx.machine.enforce_number_validity + } + + #[inline(always)] + fn enforce_number_no_provenance(ecx: &MiriEvalContext<'mir, 'tcx>) -> bool { ecx.machine.enforce_number_validity } diff --git a/tests/compile-fail/ptr_integer_transmute.rs b/tests/compile-fail/ptr_integer_transmute.rs index e15a157637575..bb9e8e1e220f4 100644 --- a/tests/compile-fail/ptr_integer_transmute.rs +++ b/tests/compile-fail/ptr_integer_transmute.rs @@ -2,5 +2,5 @@ fn main() { let r = &mut 42; - let _i: usize = unsafe { std::mem::transmute(r) }; //~ ERROR expected initialized plain (non-pointer) bytes + let _i: usize = unsafe { std::mem::transmute(r) }; //~ ERROR expected plain (non-pointer) bytes } diff --git a/tests/compile-fail/strict_provenance_transmute.rs b/tests/compile-fail/strict_provenance_transmute.rs index 0fc64295f94ce..a684d65b2ce11 100644 --- a/tests/compile-fail/strict_provenance_transmute.rs +++ b/tests/compile-fail/strict_provenance_transmute.rs @@ -7,7 +7,7 @@ use std::mem; // . unsafe fn deref(left: *const u8, right: *const u8) { - let left_int: usize = mem::transmute(left); //~ERROR expected initialized plain (non-pointer) bytes + let left_int: usize = mem::transmute(left); //~ERROR expected plain (non-pointer) bytes let right_int: usize = mem::transmute(right); if left_int == right_int { // The compiler is allowed to replace `left_int` by `right_int` here... diff --git a/tests/compile-fail/uninit_float.rs b/tests/compile-fail/uninit_float.rs index 06953e1ced966..1cb687f9b008a 100644 --- a/tests/compile-fail/uninit_float.rs +++ b/tests/compile-fail/uninit_float.rs @@ -4,5 +4,5 @@ fn main() { let _val = unsafe { std::mem::MaybeUninit::::uninit().assume_init() }; - //~^ ERROR type validation failed at .value: encountered uninitialized bytes, but expected initialized plain (non-pointer) bytes + //~^ ERROR type validation failed at .value: encountered uninitialized bytes, but expected initialized bytes } diff --git a/tests/compile-fail/uninit_integer.rs b/tests/compile-fail/uninit_integer.rs index 757f69c050fe5..c700f1f46d993 100644 --- a/tests/compile-fail/uninit_integer.rs +++ b/tests/compile-fail/uninit_integer.rs @@ -4,5 +4,5 @@ fn main() { let _val = unsafe { std::mem::MaybeUninit::::uninit().assume_init() }; - //~^ ERROR type validation failed at .value: encountered uninitialized bytes, but expected initialized plain (non-pointer) bytes + //~^ ERROR type validation failed at .value: encountered uninitialized bytes, but expected initialized bytes } diff --git a/tests/compile-fail/uninit_integer_signed.rs b/tests/compile-fail/uninit_integer_signed.rs index bb5d7314a7c1f..28bca0b19a780 100644 --- a/tests/compile-fail/uninit_integer_signed.rs +++ b/tests/compile-fail/uninit_integer_signed.rs @@ -4,5 +4,5 @@ fn main() { let _val = unsafe { std::mem::MaybeUninit::::uninit().assume_init() }; - //~^ ERROR type validation failed at .value: encountered uninitialized bytes, but expected initialized plain (non-pointer) bytes + //~^ ERROR type validation failed at .value: encountered uninitialized bytes, but expected initialized bytes } From 3b73eb4456e97a13f139cd8045f19319503f6a0b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 20 May 2022 23:35:31 +0200 Subject: [PATCH 3073/3747] explain what we mean by 'unsound' --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 5b97ca95d93f3..1897a4fd46399 100644 --- a/README.md +++ b/README.md @@ -236,7 +236,8 @@ up the sysroot. If you are using `miri` (the Miri driver) directly, see the [miri-flags]: #miri--z-flags-and-environment-variables Miri adds its own set of `-Z` flags, which are usually set via the `MIRIFLAGS` -environment variable: +environment variable. Some of these are **unsound**, which means they can lead +to Miri failing to detect cases of undefined behavior in a program. * `-Zmiri-check-number-validity` enables checking of integer and float validity (e.g., they must be initialized and not carry pointer provenance) as part of From 58fdd55a8026f9526e75c41aca082aba62c50362 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 20 May 2022 23:35:42 +0200 Subject: [PATCH 3074/3747] the Windows CI runner takes a lot longer than the others; let it do less work x86_64-apple-darwin is also used as the host OS for the macOS runner, so no need to test it twice. --- ci.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/ci.sh b/ci.sh index a86c5ca490a40..c19aceb641e3d 100755 --- a/ci.sh +++ b/ci.sh @@ -55,7 +55,6 @@ case $HOST_TARGET in ;; i686-pc-windows-msvc) MIRI_TEST_TARGET=x86_64-unknown-linux-gnu run_tests - MIRI_TEST_TARGET=x86_64-apple-darwin run_tests ;; *) echo "FATAL: unknown OS" From aadbe8fd4583a61c83b785571a1c05dd978b0d56 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 20 May 2022 23:36:35 +0200 Subject: [PATCH 3075/3747] explain which targets we support to what extent --- README.md | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/README.md b/README.md index 1897a4fd46399..abcfd3e6d050e 100644 --- a/README.md +++ b/README.md @@ -194,6 +194,28 @@ for seed in $({ echo obase=16; seq 255; } | bc); do done ``` +### Supported targets + +Miri does not support all targets supported by Rust. The good news, however, is +that no matter your host OS/platform, it is easy to run code for *any* target +using `--target`! + +The following targets are tested on CI and thus should always work (to the +degree documented below): + +- The best-supported target is `x86_64-unknown-linux-gnu`. Miri releases are + blocked on things working with this target. Most other Linux targets should + also work well; we do run the test suite on `i686-unknown-linux-gnu` as a + 32bit target and `mips64-unknown-linux-gnuabi64` as a big-endian target. +- `x86_64-apple-darwin` should work basically as well as Linux. We also test + `aarch64-apple-darwin`. However, we might ship Miri with a nightly even when + some features on these targets regress. +- `x86_64-pc-windows-msvc` works, but supports fewer features than the Linux and + Apple targets. For example, file system access and concurrency are not + supported on Windows. We also test `i686-pc-windows-msvc`, with the same + reduced feature set. We might ship Miri with a nightly even when some features + on these targets regress. + ### Common Problems When using the above instructions, you may encounter a number of confusing compiler From b4089a77abbfa19b674ebf1343a8ef974c10e67c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 21 May 2022 09:33:47 +0200 Subject: [PATCH 3076/3747] refresh our GHA caches --- .github/workflows/ci.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0904afc82020b..edf74603b6e10 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -56,7 +56,8 @@ jobs: ~/.cargo/git/db # contains package information of crates installed via `cargo install`. ~/.cargo/.crates.toml - key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }} + ~/.cargo/.crates2.json + key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}-xargo0.3.25 restore-keys: ${{ runner.os }}-cargo - name: Install rustup-toolchain-install-master and xargo From e932ea50ba21b355b08a5572a20cb53d2c74aacb Mon Sep 17 00:00:00 2001 From: Mateusz Gienieczko Date: Sat, 21 May 2022 16:10:08 +0200 Subject: [PATCH 3077/3747] Add failing page_size test. --- test-cargo-miri/Cargo.lock | 33 +++++++++++++++++++ test-cargo-miri/Cargo.toml | 1 + test-cargo-miri/test.cross-target.stdout.ref | 6 ++-- test-cargo-miri/test.default.stdout.ref | 6 ++-- .../test.filter.cross-target.stdout.ref | 2 +- test-cargo-miri/test.filter.stdout.ref | 2 +- test-cargo-miri/test.test-target.stdout.ref | 5 +-- test-cargo-miri/tests/test.rs | 20 ++++++++--- 8 files changed, 61 insertions(+), 14 deletions(-) diff --git a/test-cargo-miri/Cargo.lock b/test-cargo-miri/Cargo.lock index 7f06fdf28dec5..4bece389dc87f 100644 --- a/test-cargo-miri/Cargo.lock +++ b/test-cargo-miri/Cargo.lock @@ -22,6 +22,7 @@ dependencies = [ "issue_1705", "issue_1760", "issue_rust_86261", + "page_size", "rand", "serde_derive", ] @@ -123,6 +124,16 @@ dependencies = [ "libc", ] +[[package]] +name = "page_size" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eebde548fbbf1ea81a99b128872779c437752fb99f217c45245e1a61dcd9edcd" +dependencies = [ + "libc", + "winapi", +] + [[package]] name = "ppv-lite86" version = "0.2.10" @@ -233,3 +244,25 @@ name = "wasi" version = "0.10.2+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/test-cargo-miri/Cargo.toml b/test-cargo-miri/Cargo.toml index 39ce1757f0e42..2193d354d5d21 100644 --- a/test-cargo-miri/Cargo.toml +++ b/test-cargo-miri/Cargo.toml @@ -22,6 +22,7 @@ rand = { version = "0.8", features = ["small_rng"] } getrandom_1 = { package = "getrandom", version = "0.1" } getrandom_2 = { package = "getrandom", version = "0.2" } serde_derive = "1.0" # not actually used, but exercises some unique code path (`--extern` .so file) +page_size = "0.4.1" [lib] test = false # test that this is respected (will show in the output) diff --git a/test-cargo-miri/test.cross-target.stdout.ref b/test-cargo-miri/test.cross-target.stdout.ref index aa4a5839b1453..3673e5549d8c2 100644 --- a/test-cargo-miri/test.cross-target.stdout.ref +++ b/test-cargo-miri/test.cross-target.stdout.ref @@ -5,7 +5,7 @@ test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out imported main -running 7 tests -..i.... -test result: ok. 6 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out +running 8 tests +..i..... +test result: ok. 7 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out diff --git a/test-cargo-miri/test.default.stdout.ref b/test-cargo-miri/test.default.stdout.ref index ee8625357509a..a59108efb3323 100644 --- a/test-cargo-miri/test.default.stdout.ref +++ b/test-cargo-miri/test.default.stdout.ref @@ -5,9 +5,9 @@ test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out imported main -running 7 tests -..i.... -test result: ok. 6 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out +running 8 tests +..i..... +test result: ok. 7 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out running 4 tests diff --git a/test-cargo-miri/test.filter.cross-target.stdout.ref b/test-cargo-miri/test.filter.cross-target.stdout.ref index b38aac9aa868d..9fb7670d06495 100644 --- a/test-cargo-miri/test.filter.cross-target.stdout.ref +++ b/test-cargo-miri/test.filter.cross-target.stdout.ref @@ -8,5 +8,5 @@ imported main running 1 test test simple1 ... ok -test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 6 filtered out +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 7 filtered out diff --git a/test-cargo-miri/test.filter.stdout.ref b/test-cargo-miri/test.filter.stdout.ref index d14bb8796e850..4b598960a0963 100644 --- a/test-cargo-miri/test.filter.stdout.ref +++ b/test-cargo-miri/test.filter.stdout.ref @@ -8,7 +8,7 @@ imported main running 1 test test simple1 ... ok -test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 6 filtered out +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 7 filtered out running 0 tests diff --git a/test-cargo-miri/test.test-target.stdout.ref b/test-cargo-miri/test.test-target.stdout.ref index 6655eb8409290..ca069b702eba4 100644 --- a/test-cargo-miri/test.test-target.stdout.ref +++ b/test-cargo-miri/test.test-target.stdout.ref @@ -1,12 +1,13 @@ -running 7 tests +running 8 tests test cargo_env ... ok test do_panic - should panic ... ok test does_not_work_on_miri ... ignored test entropy_rng ... ok test fail_index_check - should panic ... ok +test page_size ... ok test simple1 ... ok test simple2 ... ok -test result: ok. 6 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out +test result: ok. 7 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out diff --git a/test-cargo-miri/tests/test.rs b/test-cargo-miri/tests/test.rs index f0ff10ff6c0d8..6758e99703cce 100644 --- a/test-cargo-miri/tests/test.rs +++ b/test-cargo-miri/tests/test.rs @@ -1,4 +1,4 @@ -use rand::{SeedableRng, Rng, rngs::SmallRng}; +use rand::{rngs::SmallRng, Rng, SeedableRng}; // Having more than 1 test does seem to make a difference // (i.e., this calls ptr::swap which having just one test does not). @@ -49,14 +49,26 @@ fn cargo_env() { } #[test] -#[should_panic(expected="Explicit panic")] -fn do_panic() { // In large, friendly letters :) +#[should_panic(expected = "Explicit panic")] +fn do_panic() { + // In large, friendly letters :) panic!("Explicit panic from test!"); } #[test] #[allow(unconditional_panic)] -#[should_panic(expected="the len is 0 but the index is 42")] +#[should_panic(expected = "the len is 0 but the index is 42")] fn fail_index_check() { [][42] } + +#[test] +fn page_size() { + let page_size = page_size::get(); + + assert!( + page_size.next_power_of_two() == page_size, + "page size not a power of two: {}", + page_size + ); +} From c4ee368acb065b783f3bc094077b4a5cdd1d7a27 Mon Sep 17 00:00:00 2001 From: Mateusz Gienieczko Date: Sat, 21 May 2022 18:17:25 +0200 Subject: [PATCH 3078/3747] Set page size in GetSystemInfo. --- src/shims/windows/foreign_items.rs | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/shims/windows/foreign_items.rs b/src/shims/windows/foreign_items.rs index c49362d52b311..8fc599dd2d0b1 100644 --- a/src/shims/windows/foreign_items.rs +++ b/src/shims/windows/foreign_items.rs @@ -119,9 +119,20 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx system_info.ptr, iter::repeat(0u8).take(system_info.layout.size.bytes() as usize), )?; - // Set number of processors. let dword_size = Size::from_bytes(4); - let num_cpus = this.mplace_field(&system_info, 6)?; + + // In WinApi SYSTEM_INFO's first field is a 4-byte union, but num_cpus + // inlines it as two 2-byte fields. In num_cpus case all fields are offset by 1 + // compared to WinApi. See https://github.com/rust-lang/miri/issues/2136#issuecomment-1133661262. + let first_field = this.mplace_field(&system_info, 0)?; + let offset = if first_field.layout.size.bytes() == 2 { 1 } else { 0 }; + + let page_size = this.mplace_field(&system_info, 1 + offset)?; + let num_cpus = this.mplace_field(&system_info, 5 + offset)?; + + // Set page size. + this.write_scalar(Scalar::from_int(PAGE_SIZE, dword_size), &page_size.into())?; + // Set number of processors. this.write_scalar(Scalar::from_int(NUM_CPUS, dword_size), &num_cpus.into())?; } From 63e98aee0cc005c27431a0eca317fecf6706b072 Mon Sep 17 00:00:00 2001 From: Mateusz Gienieczko Date: Sat, 21 May 2022 19:44:12 +0200 Subject: [PATCH 3079/3747] Change GetSystemInfo to explicit offset. --- src/shims/windows/foreign_items.rs | 35 +++++++++++++++++++----------- 1 file changed, 22 insertions(+), 13 deletions(-) diff --git a/src/shims/windows/foreign_items.rs b/src/shims/windows/foreign_items.rs index 8fc599dd2d0b1..f9cf755c5b4f5 100644 --- a/src/shims/windows/foreign_items.rs +++ b/src/shims/windows/foreign_items.rs @@ -111,6 +111,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Querying system information "GetSystemInfo" => { + use crate::rustc_middle::ty::{layout::LayoutOf, TyKind, UintTy}; + let [system_info] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; let system_info = this.deref_operand(system_info)?; @@ -119,21 +121,28 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx system_info.ptr, iter::repeat(0u8).take(system_info.layout.size.bytes() as usize), )?; - let dword_size = Size::from_bytes(4); - - // In WinApi SYSTEM_INFO's first field is a 4-byte union, but num_cpus - // inlines it as two 2-byte fields. In num_cpus case all fields are offset by 1 - // compared to WinApi. See https://github.com/rust-lang/miri/issues/2136#issuecomment-1133661262. - let first_field = this.mplace_field(&system_info, 0)?; - let offset = if first_field.layout.size.bytes() == 2 { 1 } else { 0 }; - - let page_size = this.mplace_field(&system_info, 1 + offset)?; - let num_cpus = this.mplace_field(&system_info, 5 + offset)?; - + // Set selected fields. + let dword_ty = this.tcx.mk_ty(TyKind::Uint(UintTy::U32)); + let dword_layout = this.layout_of(dword_ty)?; // Set page size. - this.write_scalar(Scalar::from_int(PAGE_SIZE, dword_size), &page_size.into())?; + let page_size = system_info.offset( + Size::from_bytes(4), + MemPlaceMeta::None, + dword_layout, + &this.tcx, + )?; + this.write_scalar( + Scalar::from_int(PAGE_SIZE, dword_layout.size), + &page_size.into(), + )?; // Set number of processors. - this.write_scalar(Scalar::from_int(NUM_CPUS, dword_size), &num_cpus.into())?; + let num_cpus = system_info.offset( + Size::from_bytes(32), + MemPlaceMeta::None, + dword_layout, + &this.tcx, + )?; + this.write_scalar(Scalar::from_int(NUM_CPUS, dword_layout.size), &num_cpus.into())?; } // Thread-local storage From 3cfce6ffb23d8ea83593b4956212954a0459d372 Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Sat, 21 May 2022 13:37:41 -0400 Subject: [PATCH 3080/3747] Make allow_data_races_* public to silence data races during cleanup --- src/data_race.rs | 84 +++++++++++++++++++++++++----------------------- src/eval.rs | 7 +++- 2 files changed, 49 insertions(+), 42 deletions(-) diff --git a/src/data_race.rs b/src/data_race.rs index ba7300374562e..5a6dd1d81d061 100644 --- a/src/data_race.rs +++ b/src/data_race.rs @@ -437,6 +437,49 @@ impl MemoryCellClocks { /// Evaluation context extensions. impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { + /// Temporarily allow data-races to occur. This should only be used in + /// one of these cases: + /// - One of the appropriate `validate_atomic` functions will be called to + /// to treat a memory access as atomic. + /// - The memory being accessed should be treated as internal state, that + /// cannot be accessed by the interpreted program. + /// - Execution of the interpreted program execution has halted. + #[inline] + fn allow_data_races_ref(&self, op: impl FnOnce(&MiriEvalContext<'mir, 'tcx>) -> R) -> R { + let this = self.eval_context_ref(); + let old = if let Some(data_race) = &this.machine.data_race { + data_race.multi_threaded.replace(false) + } else { + false + }; + let result = op(this); + if let Some(data_race) = &this.machine.data_race { + data_race.multi_threaded.set(old); + } + result + } + + /// Same as `allow_data_races_ref`, this temporarily disables any data-race detection and + /// so should only be used for atomic operations or internal state that the program cannot + /// access. + #[inline] + fn allow_data_races_mut( + &mut self, + op: impl FnOnce(&mut MiriEvalContext<'mir, 'tcx>) -> R, + ) -> R { + let this = self.eval_context_mut(); + let old = if let Some(data_race) = &this.machine.data_race { + data_race.multi_threaded.replace(false) + } else { + false + }; + let result = op(this); + if let Some(data_race) = &this.machine.data_race { + data_race.multi_threaded.set(old); + } + result + } + /// Atomic variant of read_scalar_at_offset. fn read_scalar_at_offset_atomic( &self, @@ -927,47 +970,6 @@ impl VClockAlloc { impl<'mir, 'tcx: 'mir> EvalContextPrivExt<'mir, 'tcx> for MiriEvalContext<'mir, 'tcx> {} trait EvalContextPrivExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { - // Temporarily allow data-races to occur, this should only be - // used if either one of the appropriate `validate_atomic` functions - // will be called to treat a memory access as atomic or if the memory - // being accessed should be treated as internal state, that cannot be - // accessed by the interpreted program. - #[inline] - fn allow_data_races_ref(&self, op: impl FnOnce(&MiriEvalContext<'mir, 'tcx>) -> R) -> R { - let this = self.eval_context_ref(); - let old = if let Some(data_race) = &this.machine.data_race { - data_race.multi_threaded.replace(false) - } else { - false - }; - let result = op(this); - if let Some(data_race) = &this.machine.data_race { - data_race.multi_threaded.set(old); - } - result - } - - /// Same as `allow_data_races_ref`, this temporarily disables any data-race detection and - /// so should only be used for atomic operations or internal state that the program cannot - /// access. - #[inline] - fn allow_data_races_mut( - &mut self, - op: impl FnOnce(&mut MiriEvalContext<'mir, 'tcx>) -> R, - ) -> R { - let this = self.eval_context_mut(); - let old = if let Some(data_race) = &this.machine.data_race { - data_race.multi_threaded.replace(false) - } else { - false - }; - let result = op(this); - if let Some(data_race) = &this.machine.data_race { - data_race.multi_threaded.set(old); - } - result - } - /// Generic atomic operation implementation fn validate_atomic_op( &self, diff --git a/src/eval.rs b/src/eval.rs index 5f6348fe0bde5..c4d58eb77143b 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -344,7 +344,12 @@ pub fn eval_entry<'tcx>( })(); // Machine cleanup. - EnvVars::cleanup(&mut ecx).unwrap(); + // Execution of the program has halted so any memory access we do here + // cannot produce a real data race. If we do not do something to disable + // data race detection here, some uncommon combination of errors will + // cause a data race to be detected: + // https://github.com/rust-lang/miri/issues/2020 + ecx.allow_data_races_mut(|ecx| EnvVars::cleanup(ecx).unwrap()); // Process the result. match res { From 2fa53c03857095945b1e6ebfeec94cb39077297b Mon Sep 17 00:00:00 2001 From: Mateusz Gienieczko Date: Sat, 21 May 2022 21:42:25 +0200 Subject: [PATCH 3081/3747] Dynamic offset calculation in GetSystemInfo. --- src/shims/windows/foreign_items.rs | 36 ++++++++++++++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-) diff --git a/src/shims/windows/foreign_items.rs b/src/shims/windows/foreign_items.rs index f9cf755c5b4f5..f2852d6bcca09 100644 --- a/src/shims/windows/foreign_items.rs +++ b/src/shims/windows/foreign_items.rs @@ -8,6 +8,7 @@ use rustc_target::spec::abi::Abi; use crate::*; use shims::foreign_items::EmulateByNameResult; use shims::windows::sync::EvalContextExt as _; +use smallvec::SmallVec; impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { @@ -122,11 +123,42 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx iter::repeat(0u8).take(system_info.layout.size.bytes() as usize), )?; // Set selected fields. + let word_ty = this.tcx.mk_ty(TyKind::Uint(UintTy::U16)); let dword_ty = this.tcx.mk_ty(TyKind::Uint(UintTy::U32)); + let usize_ty = this.tcx.mk_ty(TyKind::Uint(UintTy::Usize)); + let word_layout = this.layout_of(word_ty)?; let dword_layout = this.layout_of(dword_ty)?; + let usize_layout = this.layout_of(usize_ty)?; + + // Using `mplace_field` is error-prone, see: https://github.com/rust-lang/miri/issues/2136. + // Pointer fields have different sizes on different targets. + // To avoid all these issue we calculate the offsets dynamically. + let field_sizes = [ + word_layout.size, // 0, wProcessorArchitecture : WORD + word_layout.size, // 1, wReserved : WORD + dword_layout.size, // 2, dwPageSize : DWORD + usize_layout.size, // 3, lpMinimumApplicationAddress : LPVOID + usize_layout.size, // 4, lpMaximumApplicationAddress : LPVOID + usize_layout.size, // 5, dwActiveProcessorMask : DWORD_PTR + dword_layout.size, // 6, dwNumberOfProcessors : DWORD + dword_layout.size, // 7, dwProcessorType : DWORD + dword_layout.size, // 8, dwAllocationGranularity : DWORD + word_layout.size, // 9, wProcessorLevel : WORD + word_layout.size, // 10, wProcessorRevision : WORD + ]; + let field_offsets: SmallVec<[Size; 11]> = field_sizes + .iter() + .copied() + .scan(Size::ZERO, |a, x| { + let res = Some(*a); + *a += x; + res + }) + .collect(); + // Set page size. let page_size = system_info.offset( - Size::from_bytes(4), + field_offsets[2], MemPlaceMeta::None, dword_layout, &this.tcx, @@ -137,7 +169,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx )?; // Set number of processors. let num_cpus = system_info.offset( - Size::from_bytes(32), + field_offsets[6], MemPlaceMeta::None, dword_layout, &this.tcx, From b7d032c2199ec09a89b7aeafd7ad3b7e82cac7e7 Mon Sep 17 00:00:00 2001 From: Mateusz Gienieczko Date: Sun, 22 May 2022 00:59:49 +0200 Subject: [PATCH 3082/3747] Fix comment formatting. --- test-cargo-miri/tests/test.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test-cargo-miri/tests/test.rs b/test-cargo-miri/tests/test.rs index 6758e99703cce..ba027381fa5bb 100644 --- a/test-cargo-miri/tests/test.rs +++ b/test-cargo-miri/tests/test.rs @@ -50,8 +50,8 @@ fn cargo_env() { #[test] #[should_panic(expected = "Explicit panic")] -fn do_panic() { - // In large, friendly letters :) +fn do_panic() // In large, friendly letters :) +{ panic!("Explicit panic from test!"); } From a40ff562a0c20f8588c9a47816515d2ed3dc2284 Mon Sep 17 00:00:00 2001 From: Mateusz Gienieczko Date: Sun, 22 May 2022 01:00:59 +0200 Subject: [PATCH 3083/3747] Add `i16` and `u16` primitive layout. --- src/machine.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/machine.rs b/src/machine.rs index 7ab15b9f9ceb6..9e95c632c7f41 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -178,9 +178,11 @@ pub struct AllocExtra { pub struct PrimitiveLayouts<'tcx> { pub unit: TyAndLayout<'tcx>, pub i8: TyAndLayout<'tcx>, + pub i16: TyAndLayout<'tcx>, pub i32: TyAndLayout<'tcx>, pub isize: TyAndLayout<'tcx>, pub u8: TyAndLayout<'tcx>, + pub u16: TyAndLayout<'tcx>, pub u32: TyAndLayout<'tcx>, pub usize: TyAndLayout<'tcx>, pub bool: TyAndLayout<'tcx>, @@ -194,9 +196,11 @@ impl<'mir, 'tcx: 'mir> PrimitiveLayouts<'tcx> { Ok(Self { unit: layout_cx.layout_of(tcx.mk_unit())?, i8: layout_cx.layout_of(tcx.types.i8)?, + i16: layout_cx.layout_of(tcx.types.i16)?, i32: layout_cx.layout_of(tcx.types.i32)?, isize: layout_cx.layout_of(tcx.types.isize)?, u8: layout_cx.layout_of(tcx.types.u8)?, + u16: layout_cx.layout_of(tcx.types.u16)?, u32: layout_cx.layout_of(tcx.types.u32)?, usize: layout_cx.layout_of(tcx.types.usize)?, bool: layout_cx.layout_of(tcx.types.bool)?, From bd731508d46e232cb674cef93c41dbcaf391ae45 Mon Sep 17 00:00:00 2001 From: Mateusz Gienieczko Date: Sun, 22 May 2022 01:01:12 +0200 Subject: [PATCH 3084/3747] Use precomputed layouts. --- src/shims/windows/foreign_items.rs | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/src/shims/windows/foreign_items.rs b/src/shims/windows/foreign_items.rs index f2852d6bcca09..1a9b2300f723c 100644 --- a/src/shims/windows/foreign_items.rs +++ b/src/shims/windows/foreign_items.rs @@ -112,8 +112,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Querying system information "GetSystemInfo" => { - use crate::rustc_middle::ty::{layout::LayoutOf, TyKind, UintTy}; - let [system_info] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; let system_info = this.deref_operand(system_info)?; @@ -123,16 +121,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx iter::repeat(0u8).take(system_info.layout.size.bytes() as usize), )?; // Set selected fields. - let word_ty = this.tcx.mk_ty(TyKind::Uint(UintTy::U16)); - let dword_ty = this.tcx.mk_ty(TyKind::Uint(UintTy::U32)); - let usize_ty = this.tcx.mk_ty(TyKind::Uint(UintTy::Usize)); - let word_layout = this.layout_of(word_ty)?; - let dword_layout = this.layout_of(dword_ty)?; - let usize_layout = this.layout_of(usize_ty)?; + let word_layout = this.machine.layouts.u16; + let dword_layout = this.machine.layouts.u32; + let usize_layout = this.machine.layouts.usize; // Using `mplace_field` is error-prone, see: https://github.com/rust-lang/miri/issues/2136. // Pointer fields have different sizes on different targets. - // To avoid all these issue we calculate the offsets dynamically. + // To avoid all these issue we calculate the offsets ourselves. let field_sizes = [ word_layout.size, // 0, wProcessorArchitecture : WORD word_layout.size, // 1, wReserved : WORD From 9a5c9a54817804e2cd9ca49a83be8dad85111412 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 22 May 2022 07:59:18 +0200 Subject: [PATCH 3085/3747] comment on test --- test-cargo-miri/tests/test.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/test-cargo-miri/tests/test.rs b/test-cargo-miri/tests/test.rs index ba027381fa5bb..1a8b3c72565d3 100644 --- a/test-cargo-miri/tests/test.rs +++ b/test-cargo-miri/tests/test.rs @@ -66,6 +66,7 @@ fn fail_index_check() { fn page_size() { let page_size = page_size::get(); + // In particular, this checks that it is not 0. assert!( page_size.next_power_of_two() == page_size, "page size not a power of two: {}", From 486a7699357e6a6d7b58a6a8f49a9852a0a37e84 Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Sat, 21 May 2022 12:14:17 -0400 Subject: [PATCH 3086/3747] Handle diagnotics emitted in runtime initialization --- src/eval.rs | 10 ++++++++++ tests/run-pass/track-alloc-1.rs | 5 +++++ tests/run-pass/track-alloc-1.stderr | 5 +++++ 3 files changed, 20 insertions(+) create mode 100644 tests/run-pass/track-alloc-1.rs create mode 100644 tests/run-pass/track-alloc-1.stderr diff --git a/src/eval.rs b/src/eval.rs index 5f6348fe0bde5..0255368b20f27 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -168,6 +168,12 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( param_env, Evaluator::new(config, layout_cx), ); + + // Capture the current interpreter stack state (which should be empty) so that we can emit + // allocation-tracking and tag-tracking diagnostics for allocations which are part of the + // runtime. + let info = ecx.preprocess_diagnostics(); + // Some parts of initialization require a full `InterpCx`. Evaluator::late_init(&mut ecx, config)?; @@ -287,6 +293,10 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( } } + // Emit any diagnostics related to the setup process for the runtime, so that when the + // interpreter loop starts there are no unprocessed diagnostics. + ecx.process_diagnostics(info); + Ok((ecx, ret_place)) } diff --git a/tests/run-pass/track-alloc-1.rs b/tests/run-pass/track-alloc-1.rs new file mode 100644 index 0000000000000..7bb217309f944 --- /dev/null +++ b/tests/run-pass/track-alloc-1.rs @@ -0,0 +1,5 @@ +// Ensure that tracking early allocations doesn't ICE Miri. +// Early allocations are probably part of the runtime and therefore uninteresting, but they +// shouldn't cause a crash. +// compile-flags: -Zmiri-track-alloc-id=1 +fn main() {} diff --git a/tests/run-pass/track-alloc-1.stderr b/tests/run-pass/track-alloc-1.stderr new file mode 100644 index 0000000000000..3c5a55d986e3e --- /dev/null +++ b/tests/run-pass/track-alloc-1.stderr @@ -0,0 +1,5 @@ +note: tracking was triggered + | + = note: created allocation with id 1 + = note: (no span available) + From 73534a678dedc9f68d4dfdd8532eec664bdb1e3c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 22 May 2022 18:16:59 +0200 Subject: [PATCH 3087/3747] tweak comment --- src/eval.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/eval.rs b/src/eval.rs index 0255368b20f27..a8279e8d60e25 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -171,7 +171,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( // Capture the current interpreter stack state (which should be empty) so that we can emit // allocation-tracking and tag-tracking diagnostics for allocations which are part of the - // runtime. + // early runtime setup. let info = ecx.preprocess_diagnostics(); // Some parts of initialization require a full `InterpCx`. From d7d7a9a1627fd75d49ae9516a531154726d6190d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Kr=C3=BCger?= Date: Sun, 22 May 2022 21:47:44 +0200 Subject: [PATCH 3088/3747] [NFC] shims: fs: fmt --- src/shims/posix/fs.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/shims/posix/fs.rs b/src/shims/posix/fs.rs index dec1e97816807..3fcbbb803eaf5 100644 --- a/src/shims/posix/fs.rs +++ b/src/shims/posix/fs.rs @@ -31,16 +31,19 @@ trait FileDescriptor: std::fmt::Debug { communicate_allowed: bool, bytes: &mut [u8], ) -> InterpResult<'tcx, io::Result>; + fn write<'tcx>( &self, communicate_allowed: bool, bytes: &[u8], ) -> InterpResult<'tcx, io::Result>; + fn seek<'tcx>( &mut self, communicate_allowed: bool, offset: SeekFrom, ) -> InterpResult<'tcx, io::Result>; + fn close<'tcx>( self: Box, _communicate_allowed: bool, From 89da571b5d7d35220dd65c670caf66e25c10a892 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Kr=C3=BCger?= Date: Sun, 22 May 2022 21:54:00 +0200 Subject: [PATCH 3089/3747] shims: fs: silence stderr instead of stdout. Fixes #2143 --- src/shims/posix/fs.rs | 6 +++--- tests/run-pass/hide_stdout.rs | 3 ++- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/shims/posix/fs.rs b/src/shims/posix/fs.rs index 3fcbbb803eaf5..79539fd9c49e3 100644 --- a/src/shims/posix/fs.rs +++ b/src/shims/posix/fs.rs @@ -307,14 +307,14 @@ pub struct FileHandler { impl<'tcx> FileHandler { pub(crate) fn new(mute_stdout_stderr: bool) -> FileHandler { let mut handles: BTreeMap<_, Box> = BTreeMap::new(); + handles.insert(0i32, Box::new(io::stdin())); if mute_stdout_stderr { - handles.insert(0i32, Box::new(DummyOutput)); handles.insert(1i32, Box::new(DummyOutput)); + handles.insert(2i32, Box::new(DummyOutput)); } else { - handles.insert(0i32, Box::new(io::stdin())); handles.insert(1i32, Box::new(io::stdout())); + handles.insert(2i32, Box::new(io::stderr())); } - handles.insert(2i32, Box::new(io::stderr())); FileHandler { handles } } diff --git a/tests/run-pass/hide_stdout.rs b/tests/run-pass/hide_stdout.rs index 849fce913862e..3ee68d01f43d3 100644 --- a/tests/run-pass/hide_stdout.rs +++ b/tests/run-pass/hide_stdout.rs @@ -1,5 +1,6 @@ // compile-flags: -Zmiri-mute-stdout-stderr fn main() { - println!("cake"); + println!("print to stdout"); + eprintln!("print to stderr"); } From b20c6cfd81b8df20e0714e3bc8a6054be682d5f1 Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Tue, 7 Dec 2021 22:05:13 -0500 Subject: [PATCH 3090/3747] Factor current-span logic into a lazy caching handle --- src/helpers.rs | 44 ++++++++++++++++++++++++++--- src/lib.rs | 2 +- src/machine.rs | 10 +++---- src/stacked_borrows.rs | 45 ++++++++++++++---------------- src/stacked_borrows/diagnostics.rs | 40 +++++++++----------------- 5 files changed, 79 insertions(+), 62 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index 6beb3f8c3bb09..2d1fffc6a125f 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -2,7 +2,6 @@ pub mod convert; use std::mem; use std::num::NonZeroUsize; -use std::rc::Rc; use std::time::Duration; use log::trace; @@ -14,7 +13,7 @@ use rustc_middle::ty::{ layout::{LayoutOf, TyAndLayout}, List, TyCtxt, }; -use rustc_span::{def_id::CrateNum, sym, Symbol}; +use rustc_span::{def_id::CrateNum, sym, Span, Symbol}; use rustc_target::abi::{Align, FieldsShape, Size, Variants}; use rustc_target::spec::abi::Abi; @@ -800,6 +799,43 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } +impl<'mir, 'tcx> Evaluator<'mir, 'tcx> { + pub fn current_span(&self) -> CurrentSpan<'_, 'mir, 'tcx> { + CurrentSpan { span: None, machine: self } + } +} + +/// A `CurrentSpan` should be created infrequently (ideally once) per interpreter step. It does +/// nothing on creation, but when `CurrentSpan::get` is called, searches the current stack for the +/// topmost frame which corresponds to a local crate, and returns the current span in that frame. +/// The result of that search is cached so that later calls are approximately free. +#[derive(Clone)] +pub struct CurrentSpan<'a, 'tcx, 'mir> { + span: Option, + machine: &'a Evaluator<'tcx, 'mir>, +} + +impl<'a, 'tcx, 'mir> CurrentSpan<'a, 'tcx, 'mir> { + pub fn get(&mut self) -> Span { + *self.span.get_or_insert_with(|| Self::current_span(&self.machine)) + } + + #[inline(never)] + fn current_span(machine: &Evaluator<'_, '_>) -> Span { + machine + .threads + .active_thread_stack() + .into_iter() + .rev() + .find(|frame| { + let def_id = frame.instance.def_id(); + def_id.is_local() || machine.local_crates.contains(&def_id.krate) + }) + .map(|frame| frame.current_span()) + .unwrap_or(rustc_span::DUMMY_SP) + } +} + /// Check that the number of args is what we expect. pub fn check_arg_count<'a, 'tcx, const N: usize>( args: &'a [OpTy<'tcx, Tag>], @@ -822,7 +858,7 @@ pub fn isolation_abort_error(name: &str) -> InterpResult<'static> { /// Retrieve the list of local crates that should have been passed by cargo-miri in /// MIRI_LOCAL_CRATES and turn them into `CrateNum`s. -pub fn get_local_crates(tcx: &TyCtxt<'_>) -> Rc<[CrateNum]> { +pub fn get_local_crates(tcx: &TyCtxt<'_>) -> Vec { // Convert the local crate names from the passed-in config into CrateNums so that they can // be looked up quickly during execution let local_crate_names = std::env::var("MIRI_LOCAL_CRATES") @@ -836,7 +872,7 @@ pub fn get_local_crates(tcx: &TyCtxt<'_>) -> Rc<[CrateNum]> { local_crates.push(crate_num); } } - Rc::from(local_crates.as_slice()) + local_crates } /// Formats an AllocRange like [0x1..0x3], for use in diagnostics. diff --git a/src/lib.rs b/src/lib.rs index ee7a3bcdc5cbf..9fa2c61fd831a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -77,7 +77,7 @@ pub use crate::diagnostics::{ pub use crate::eval::{ create_ecx, eval_entry, AlignmentCheck, BacktraceStyle, IsolatedOp, MiriConfig, RejectOpWith, }; -pub use crate::helpers::EvalContextExt as HelpersEvalContextExt; +pub use crate::helpers::{CurrentSpan, EvalContextExt as HelpersEvalContextExt}; pub use crate::machine::{ AllocExtra, Evaluator, FrameData, MiriEvalContext, MiriEvalContextExt, MiriMemoryKind, Tag, NUM_CPUS, PAGE_SIZE, STACK_ADDR, STACK_SIZE, diff --git a/src/machine.rs b/src/machine.rs index 9e95c632c7f41..d78b0135e94fb 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -6,7 +6,6 @@ use std::cell::RefCell; use std::collections::HashSet; use std::fmt; use std::num::NonZeroU64; -use std::rc::Rc; use std::time::Instant; use rand::rngs::StdRng; @@ -278,7 +277,7 @@ pub struct Evaluator<'mir, 'tcx> { pub(crate) backtrace_style: BacktraceStyle, /// Crates which are considered local for the purposes of error reporting. - pub(crate) local_crates: Rc<[CrateNum]>, + pub(crate) local_crates: Vec, /// Mapping extern static names to their base pointer. extern_statics: FxHashMap>, @@ -584,8 +583,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { alloc.size(), stacked_borrows, kind, - &ecx.machine.threads, - ecx.machine.local_crates.clone(), + ecx.machine.current_span(), )) } else { None @@ -667,7 +665,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { tag, range, machine.stacked_borrows.as_ref().unwrap(), - &machine.threads, + machine.current_span(), ) } else { Ok(()) @@ -691,7 +689,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { tag, range, machine.stacked_borrows.as_ref().unwrap(), - &machine.threads, + machine.current_span(), ) } else { Ok(()) diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index d7c2139323245..625ffb2c5d202 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -5,7 +5,6 @@ use log::trace; use std::cell::RefCell; use std::fmt; use std::num::NonZeroU64; -use std::rc::Rc; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_hir::Mutability; @@ -14,7 +13,6 @@ use rustc_middle::ty::{ self, layout::{HasParamEnv, LayoutOf}, }; -use rustc_span::def_id::CrateNum; use rustc_span::DUMMY_SP; use rustc_target::abi::Size; use std::collections::HashSet; @@ -22,9 +20,7 @@ use std::collections::HashSet; use crate::*; pub mod diagnostics; -use diagnostics::AllocHistory; - -use diagnostics::TagHistory; +use diagnostics::{AllocHistory, TagHistory}; pub type PtrId = NonZeroU64; pub type CallId = NonZeroU64; @@ -376,7 +372,7 @@ impl<'tcx> Stack { tag: SbTag, (alloc_id, alloc_range, offset): (AllocId, AllocRange, Size), // just for debug printing and error messages global: &mut GlobalStateInner, - threads: &ThreadManager<'_, 'tcx>, + current_span: &mut CurrentSpan<'_, '_, 'tcx>, alloc_history: &mut AllocHistory, ) -> InterpResult<'tcx> { // Two main steps: Find granting item, remove incompatible items above. @@ -400,7 +396,7 @@ impl<'tcx> Stack { global, alloc_history, )?; - alloc_history.log_invalidation(item.tag, alloc_range, threads); + alloc_history.log_invalidation(item.tag, alloc_range, current_span); } } else { // On a read, *disable* all `Unique` above the granting item. This ensures U2 for read accesses. @@ -422,7 +418,7 @@ impl<'tcx> Stack { alloc_history, )?; item.perm = Permission::Disabled; - alloc_history.log_invalidation(item.tag, alloc_range, threads); + alloc_history.log_invalidation(item.tag, alloc_range, current_span); } } } @@ -471,7 +467,7 @@ impl<'tcx> Stack { new: Item, (alloc_id, alloc_range, offset): (AllocId, AllocRange, Size), // just for debug printing and error messages global: &mut GlobalStateInner, - threads: &ThreadManager<'_, 'tcx>, + current_span: &mut CurrentSpan<'_, '_, 'tcx>, alloc_history: &mut AllocHistory, ) -> InterpResult<'tcx> { // Figure out which access `perm` corresponds to. @@ -505,7 +501,7 @@ impl<'tcx> Stack { derived_from, (alloc_id, alloc_range, offset), global, - threads, + current_span, alloc_history, )?; @@ -533,13 +529,13 @@ impl<'tcx> Stack { /// Map per-stack operations to higher-level per-location-range operations. impl<'tcx> Stacks { /// Creates new stack with initial tag. - fn new(size: Size, perm: Permission, tag: SbTag, local_crates: Rc<[CrateNum]>) -> Self { + fn new(size: Size, perm: Permission, tag: SbTag) -> Self { let item = Item { perm, tag, protector: None }; let stack = Stack { borrows: vec![item] }; Stacks { stacks: RefCell::new(RangeMap::new(size, stack)), - history: RefCell::new(AllocHistory::new(local_crates)), + history: RefCell::new(AllocHistory::new()), } } @@ -579,8 +575,7 @@ impl Stacks { size: Size, state: &GlobalState, kind: MemoryKind, - threads: &ThreadManager<'_, '_>, - local_crates: Rc<[CrateNum]>, + mut current_span: CurrentSpan<'_, '_, '_>, ) -> Self { let mut extra = state.borrow_mut(); let (base_tag, perm) = match kind { @@ -614,12 +609,12 @@ impl Stacks { (tag, Permission::SharedReadWrite) } }; - let stacks = Stacks::new(size, perm, base_tag, local_crates); + let stacks = Stacks::new(size, perm, base_tag); stacks.history.borrow_mut().log_creation( None, base_tag, alloc_range(Size::ZERO, size), - threads, + &mut current_span, ); stacks } @@ -631,7 +626,7 @@ impl Stacks { tag: SbTag, range: AllocRange, state: &GlobalState, - threads: &ThreadManager<'_, 'tcx>, + mut current_span: CurrentSpan<'_, '_, 'tcx>, ) -> InterpResult<'tcx> { trace!( "read access with tag {:?}: {:?}, size {}", @@ -646,7 +641,7 @@ impl Stacks { tag, (alloc_id, range, offset), &mut state, - threads, + &mut current_span, history, ) }) @@ -659,7 +654,7 @@ impl Stacks { tag: SbTag, range: AllocRange, state: &GlobalState, - threads: &ThreadManager<'_, 'tcx>, + mut current_span: CurrentSpan<'_, '_, 'tcx>, ) -> InterpResult<'tcx> { trace!( "write access with tag {:?}: {:?}, size {}", @@ -674,7 +669,7 @@ impl Stacks { tag, (alloc_id, range, offset), &mut state, - threads, + &mut current_span, history, ) }) @@ -723,6 +718,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } let (alloc_id, base_offset, orig_tag) = this.ptr_get_alloc_id(place.ptr)?; + let mut current_span = this.machine.current_span(); { let extra = this.get_alloc_extra(alloc_id)?; let stacked_borrows = @@ -732,10 +728,10 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Some(orig_tag), new_tag, alloc_range(base_offset, size), - &this.machine.threads, + &mut current_span, ); if protect { - alloc_history.log_protector(orig_tag, new_tag, &this.machine.threads); + alloc_history.log_protector(orig_tag, new_tag, &mut current_span); } } @@ -804,7 +800,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx item, (alloc_id, range, offset), &mut *global, - &this.machine.threads, + &mut current_span, history, ) }) @@ -821,13 +817,14 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let item = Item { perm, tag: new_tag, protector }; let range = alloc_range(base_offset, size); let mut global = machine.stacked_borrows.as_ref().unwrap().borrow_mut(); + let mut current_span = machine.current_span(); stacked_borrows.for_each_mut(range, |offset, stack, history| { stack.grant( orig_tag, item, (alloc_id, range, offset), &mut global, - &machine.threads, + &mut current_span, history, ) })?; diff --git a/src/stacked_borrows/diagnostics.rs b/src/stacked_borrows/diagnostics.rs index 734c3a14e3b3b..f3692cdeeb043 100644 --- a/src/stacked_borrows/diagnostics.rs +++ b/src/stacked_borrows/diagnostics.rs @@ -1,17 +1,14 @@ use smallvec::SmallVec; -use std::rc::Rc; use rustc_middle::mir::interpret::{AllocId, AllocRange}; -use rustc_span::def_id::CrateNum; use rustc_span::{Span, SpanData}; use rustc_target::abi::Size; -use crate::helpers::HexRange; +use crate::helpers::{CurrentSpan, HexRange}; use crate::stacked_borrows::{err_sb_ub, AccessKind, Permission}; use crate::Item; use crate::SbTag; use crate::Stack; -use crate::ThreadManager; use rustc_middle::mir::interpret::InterpError; @@ -23,8 +20,6 @@ pub struct AllocHistory { creations: smallvec::SmallVec<[Event; 2]>, invalidations: smallvec::SmallVec<[Event; 1]>, protectors: smallvec::SmallVec<[Protection; 1]>, - /// This field is a clone of the `local_crates` field on `Evaluator`. - local_crates: Rc<[CrateNum]>, } #[derive(Clone, Debug)] @@ -59,37 +54,23 @@ pub enum TagHistory { } impl AllocHistory { - pub fn new(local_crates: Rc<[CrateNum]>) -> Self { + pub fn new() -> Self { Self { current_time: 0, creations: SmallVec::new(), invalidations: SmallVec::new(), protectors: SmallVec::new(), - local_crates, } } - fn current_span(&self, threads: &ThreadManager<'_, '_>) -> Span { - threads - .active_thread_stack() - .into_iter() - .rev() - .find(|frame| { - let def_id = frame.instance.def_id(); - def_id.is_local() || self.local_crates.contains(&def_id.krate) - }) - .map(|frame| frame.current_span()) - .unwrap_or(rustc_span::DUMMY_SP) - } - pub fn log_creation( &mut self, parent: Option, tag: SbTag, range: AllocRange, - threads: &ThreadManager<'_, '_>, + current_span: &mut CurrentSpan<'_, '_, '_>, ) { - let span = self.current_span(threads); + let span = current_span.get(); self.creations.push(Event { parent, tag, range, span, time: self.current_time }); self.current_time += 1; } @@ -98,15 +79,20 @@ impl AllocHistory { &mut self, tag: SbTag, range: AllocRange, - threads: &ThreadManager<'_, '_>, + current_span: &mut CurrentSpan<'_, '_, '_>, ) { - let span = self.current_span(threads); + let span = current_span.get(); self.invalidations.push(Event { parent: None, tag, range, span, time: self.current_time }); self.current_time += 1; } - pub fn log_protector(&mut self, orig_tag: SbTag, tag: SbTag, threads: &ThreadManager<'_, '_>) { - let span = self.current_span(threads); + pub fn log_protector( + &mut self, + orig_tag: SbTag, + tag: SbTag, + current_span: &mut CurrentSpan<'_, '_, '_>, + ) { + let span = current_span.get(); self.protectors.push(Protection { orig_tag, tag, span }); self.current_time += 1; } From fdfbd7a658b58f1f579ad677a73a516668b35ed6 Mon Sep 17 00:00:00 2001 From: Thom Chiovoloni Date: Sat, 7 May 2022 10:37:20 -0700 Subject: [PATCH 3091/3747] Fix backwards `cmpxchg_weak_failure_rate` check --- src/data_race.rs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/data_race.rs b/src/data_race.rs index 5a6dd1d81d061..c52b840184661 100644 --- a/src/data_race.rs +++ b/src/data_race.rs @@ -623,10 +623,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { // `binary_op` will bail if either of them is not a scalar. let eq = this.binary_op(mir::BinOp::Eq, &old, expect_old)?; // If the operation would succeed, but is "weak", fail some portion - // of the time, based on `rate`. - let rate = this.machine.cmpxchg_weak_failure_rate; + // of the time, based on `success_rate`. + let success_rate = 1.0 - this.machine.cmpxchg_weak_failure_rate; let cmpxchg_success = eq.to_scalar()?.to_bool()? - && (!can_fail_spuriously || this.machine.rng.get_mut().gen::() < rate); + && if can_fail_spuriously { + this.machine.rng.get_mut().gen_bool(success_rate) + } else { + true + }; let res = Immediate::ScalarPair( old.to_scalar_or_uninit(), Scalar::from_bool(cmpxchg_success).into(), From f7bc441fd342783ad42b8a9fbb2a1595e80044ad Mon Sep 17 00:00:00 2001 From: carbotaniuman <41451839+carbotaniuman@users.noreply.github.com> Date: Sun, 22 May 2022 15:22:05 -0500 Subject: [PATCH 3092/3747] Initial work on permissive provenance --- src/bin/miri.rs | 8 +- src/eval.rs | 7 +- src/helpers.rs | 4 +- src/intptrcast.rs | 123 +++++++++++++++--- src/lib.rs | 5 +- src/machine.rs | 70 +++++++--- src/stacked_borrows.rs | 11 +- tests/compile-fail/ptr_int_unexposed.rs | 12 ++ tests/compile-fail/ptr_legacy_provenance.rs | 21 +++ .../run-pass/ptr_int_permissive_provenance.rs | 62 +++++++++ 10 files changed, 275 insertions(+), 48 deletions(-) create mode 100644 tests/compile-fail/ptr_int_unexposed.rs create mode 100644 tests/compile-fail/ptr_legacy_provenance.rs create mode 100644 tests/run-pass/ptr_int_permissive_provenance.rs diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 0aa8755573a6b..784f0da8a30dd 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -30,7 +30,7 @@ use rustc_middle::{ }; use rustc_session::{config::ErrorOutputType, search_paths::PathKind, CtfeBacktrace}; -use miri::BacktraceStyle; +use miri::{BacktraceStyle, ProvenanceMode}; struct MiriCompilerCalls { miri_config: miri::MiriConfig, @@ -384,10 +384,14 @@ fn main() { miri_config.tag_raw = true; } "-Zmiri-strict-provenance" => { - miri_config.strict_provenance = true; + miri_config.provenance_mode = ProvenanceMode::Strict; miri_config.tag_raw = true; miri_config.check_number_validity = true; } + "-Zmiri-permissive-provenance" => { + miri_config.provenance_mode = ProvenanceMode::Permissive; + miri_config.tag_raw = true; + } "-Zmiri-mute-stdout-stderr" => { miri_config.mute_stdout_stderr = true; } diff --git a/src/eval.rs b/src/eval.rs index 13dff22ea3cc5..430ff06cf15ad 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -113,9 +113,8 @@ pub struct MiriConfig { pub panic_on_unsupported: bool, /// Which style to use for printing backtraces. pub backtrace_style: BacktraceStyle, - /// Whether to enforce "strict provenance" rules. Enabling this means int2ptr casts return - /// pointers with an invalid provenance, i.e., not valid for any memory access. - pub strict_provenance: bool, + /// Which provenance to use for int2ptr casts + pub provenance_mode: ProvenanceMode, /// Whether to ignore any output by the program. This is helpful when debugging miri /// as its messages don't get intermingled with the program messages. pub mute_stdout_stderr: bool, @@ -144,7 +143,7 @@ impl Default for MiriConfig { measureme_out: None, panic_on_unsupported: false, backtrace_style: BacktraceStyle::Short, - strict_provenance: false, + provenance_mode: ProvenanceMode::Legacy, mute_stdout_stderr: false, } } diff --git a/src/helpers.rs b/src/helpers.rs index 2d1fffc6a125f..08b2fa98a2300 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -786,8 +786,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn mark_immutable(&mut self, mplace: &MemPlace) { let this = self.eval_context_mut(); // This got just allocated, so there definitely is a pointer here. - this.alloc_mark_immutable(mplace.ptr.into_pointer_or_addr().unwrap().provenance.alloc_id) - .unwrap(); + let provenance = mplace.ptr.into_pointer_or_addr().unwrap().provenance; + this.alloc_mark_immutable(provenance.get_alloc_id().unwrap()).unwrap(); } fn item_link_name(&self, def_id: DefId) -> Symbol { diff --git a/src/intptrcast.rs b/src/intptrcast.rs index 895241bcc326d..8395cdc2733d2 100644 --- a/src/intptrcast.rs +++ b/src/intptrcast.rs @@ -4,11 +4,25 @@ use std::collections::hash_map::Entry; use log::trace; use rand::Rng; -use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_target::abi::{HasDataLayout, Size}; use crate::*; +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub enum ProvenanceMode { + /// Int2ptr casts return pointers with "wildcard" provenance + /// that basically matches that of all exposed pointers + /// (and SB tags, if enabled). + Permissive, + /// Int2ptr casts return pointers with an invalid provenance, + /// i.e., not valid for any memory access. + Strict, + /// Int2ptr casts determine the allocation they point to at cast time. + /// All allocations are considered exposed. + Legacy, +} + pub type GlobalState = RefCell; #[derive(Clone, Debug)] @@ -21,12 +35,14 @@ pub struct GlobalStateInner { /// they do not have an `AllocExtra`. /// This is the inverse of `int_to_ptr_map`. base_addr: FxHashMap, + /// Whether an allocation has been exposed or not. This cannot be put + /// into `AllocExtra` for the same reason as `base_addr`. + exposed: FxHashSet, /// This is used as a memory address when a new pointer is casted to an integer. It /// is always larger than any address that was previously made part of a block. next_base_addr: u64, - /// Whether to enforce "strict provenance" rules. Enabling this means int2ptr casts return - /// pointers with an invalid provenance, i.e., not valid for any memory access. - strict_provenance: bool, + /// The provenance to use for int2ptr casts + provenance_mode: ProvenanceMode, } impl GlobalStateInner { @@ -34,22 +50,22 @@ impl GlobalStateInner { GlobalStateInner { int_to_ptr_map: Vec::default(), base_addr: FxHashMap::default(), + exposed: FxHashSet::default(), next_base_addr: STACK_ADDR, - strict_provenance: config.strict_provenance, + provenance_mode: config.provenance_mode, } } } impl<'mir, 'tcx> GlobalStateInner { - pub fn ptr_from_addr(addr: u64, ecx: &MiriEvalContext<'mir, 'tcx>) -> Pointer> { - trace!("Casting 0x{:x} to a pointer", addr); + // Returns the exposed `AllocId` that corresponds to the specified addr, + // or `None` if the addr is out of bounds + fn alloc_id_from_addr(ecx: &MiriEvalContext<'mir, 'tcx>, addr: u64) -> Option { let global_state = ecx.machine.intptrcast.borrow(); - - if global_state.strict_provenance { - return Pointer::new(None, Size::from_bytes(addr)); - } + assert!(global_state.provenance_mode != ProvenanceMode::Strict); let pos = global_state.int_to_ptr_map.binary_search_by_key(&addr, |(addr, _)| *addr); + let alloc_id = match pos { Ok(pos) => Some(global_state.int_to_ptr_map[pos].1), Err(0) => None, @@ -60,6 +76,7 @@ impl<'mir, 'tcx> GlobalStateInner { // This never overflows because `addr >= glb` let offset = addr - glb; // If the offset exceeds the size of the allocation, don't use this `alloc_id`. + if offset <= ecx .get_alloc_size_and_align(alloc_id, AllocCheck::MaybeDead) @@ -72,12 +89,65 @@ impl<'mir, 'tcx> GlobalStateInner { None } } - }; - // Pointers created from integers are untagged. - Pointer::new( - alloc_id.map(|alloc_id| Tag { alloc_id, sb: SbTag::Untagged }), - Size::from_bytes(addr), - ) + }?; + + // In legacy mode, we consider all allocations exposed. + if global_state.provenance_mode == ProvenanceMode::Legacy + || global_state.exposed.contains(&alloc_id) + { + Some(alloc_id) + } else { + None + } + } + + pub fn expose_addr(ecx: &MiriEvalContext<'mir, 'tcx>, alloc_id: AllocId) { + trace!("Exposing allocation id {:?}", alloc_id); + + let mut global_state = ecx.machine.intptrcast.borrow_mut(); + if global_state.provenance_mode == ProvenanceMode::Permissive { + global_state.exposed.insert(alloc_id); + } + } + + pub fn ptr_from_addr_transmute( + ecx: &MiriEvalContext<'mir, 'tcx>, + addr: u64, + ) -> Pointer> { + trace!("Transmuting 0x{:x} to a pointer", addr); + + let global_state = ecx.machine.intptrcast.borrow(); + + // In legacy mode, we have to support int2ptr transmutes, + // so just pretend they do the same thing as a cast. + if global_state.provenance_mode == ProvenanceMode::Legacy { + Self::ptr_from_addr_cast(ecx, addr) + } else { + Pointer::new(None, Size::from_bytes(addr)) + } + } + + pub fn ptr_from_addr_cast( + ecx: &MiriEvalContext<'mir, 'tcx>, + addr: u64, + ) -> Pointer> { + trace!("Casting 0x{:x} to a pointer", addr); + + let global_state = ecx.machine.intptrcast.borrow(); + + if global_state.provenance_mode == ProvenanceMode::Strict { + Pointer::new(None, Size::from_bytes(addr)) + } else if global_state.provenance_mode == ProvenanceMode::Legacy { + let alloc_id = Self::alloc_id_from_addr(ecx, addr); + + Pointer::new( + alloc_id + .map(|alloc_id| Tag::Concrete(ConcreteTag { alloc_id, sb: SbTag::Untagged })), + Size::from_bytes(addr), + ) + } else { + Pointer::new(Some(Tag::Wildcard), Size::from_bytes(addr)) + } } fn alloc_base_addr(ecx: &MiriEvalContext<'mir, 'tcx>, alloc_id: AllocId) -> u64 { @@ -136,14 +206,27 @@ impl<'mir, 'tcx> GlobalStateInner { dl.overflowing_offset(base_addr, offset.bytes()).0 } - pub fn abs_ptr_to_rel(ecx: &MiriEvalContext<'mir, 'tcx>, ptr: Pointer) -> Size { + pub fn abs_ptr_to_rel( + ecx: &MiriEvalContext<'mir, 'tcx>, + ptr: Pointer, + ) -> Option<(AllocId, Size)> { let (tag, addr) = ptr.into_parts(); // addr is absolute (Tag provenance) - let base_addr = GlobalStateInner::alloc_base_addr(ecx, tag.alloc_id); + + let alloc_id = if let Tag::Concrete(concrete) = tag { + concrete.alloc_id + } else { + GlobalStateInner::alloc_id_from_addr(ecx, addr.bytes())? + }; + + let base_addr = GlobalStateInner::alloc_base_addr(ecx, alloc_id); // Wrapping "addr - base_addr" let dl = ecx.data_layout(); let neg_base_addr = (base_addr as i64).wrapping_neg(); - Size::from_bytes(dl.overflowing_signed_offset(addr.bytes(), neg_base_addr).0) + Some(( + alloc_id, + Size::from_bytes(dl.overflowing_signed_offset(addr.bytes(), neg_base_addr).0), + )) } /// Shifts `addr` to make it aligned with `align` by rounding `addr` to the smallest multiple diff --git a/src/lib.rs b/src/lib.rs index 9fa2c61fd831a..e571c8a001029 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -78,9 +78,10 @@ pub use crate::eval::{ create_ecx, eval_entry, AlignmentCheck, BacktraceStyle, IsolatedOp, MiriConfig, RejectOpWith, }; pub use crate::helpers::{CurrentSpan, EvalContextExt as HelpersEvalContextExt}; +pub use crate::intptrcast::ProvenanceMode; pub use crate::machine::{ - AllocExtra, Evaluator, FrameData, MiriEvalContext, MiriEvalContextExt, MiriMemoryKind, Tag, - NUM_CPUS, PAGE_SIZE, STACK_ADDR, STACK_SIZE, + AllocExtra, ConcreteTag, Evaluator, FrameData, MiriEvalContext, MiriEvalContextExt, + MiriMemoryKind, Tag, NUM_CPUS, PAGE_SIZE, STACK_ADDR, STACK_SIZE, }; pub use crate::mono_hash_map::MonoHashMap; pub use crate::operator::EvalContextExt as OperatorEvalContextExt; diff --git a/src/machine.rs b/src/machine.rs index d78b0135e94fb..12a32d81b5c93 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -125,7 +125,13 @@ impl fmt::Display for MiriMemoryKind { /// Pointer provenance (tag). #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub struct Tag { +pub enum Tag { + Concrete(ConcreteTag), + Wildcard, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct ConcreteTag { pub alloc_id: AllocId, /// Stacked Borrows tag. pub sb: SbTag, @@ -133,8 +139,8 @@ pub struct Tag { #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] static_assert_size!(Pointer, 24); -#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] -static_assert_size!(Pointer>, 24); +// #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] +// static_assert_size!(Pointer>, 24); #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] static_assert_size!(ScalarMaybeUninit, 32); @@ -148,18 +154,31 @@ impl Provenance for Tag { fn fmt(ptr: &Pointer, f: &mut fmt::Formatter<'_>) -> fmt::Result { let (tag, addr) = ptr.into_parts(); // address is absolute write!(f, "0x{:x}", addr.bytes())?; - // Forward `alternate` flag to `alloc_id` printing. - if f.alternate() { - write!(f, "[{:#?}]", tag.alloc_id)?; - } else { - write!(f, "[{:?}]", tag.alloc_id)?; + + match tag { + Tag::Concrete(tag) => { + // Forward `alternate` flag to `alloc_id` printing. + if f.alternate() { + write!(f, "[{:#?}]", tag.alloc_id)?; + } else { + write!(f, "[{:?}]", tag.alloc_id)?; + } + // Print Stacked Borrows tag. + write!(f, "{:?}", tag.sb)?; + } + Tag::Wildcard => { + write!(f, "[Wildcard]")?; + } } - // Print Stacked Borrows tag. - write!(f, "{:?}", tag.sb) + + Ok(()) } fn get_alloc_id(self) -> Option { - Some(self.alloc_id) + match self { + Tag::Concrete(concrete) => Some(concrete.alloc_id), + Tag::Wildcard => None, + } } } @@ -611,7 +630,10 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { } else { SbTag::Untagged }; - Pointer::new(Tag { alloc_id: ptr.provenance, sb: sb_tag }, Size::from_bytes(absolute_addr)) + Pointer::new( + Tag::Concrete(ConcreteTag { alloc_id: ptr.provenance, sb: sb_tag }), + Size::from_bytes(absolute_addr), + ) } #[inline(always)] @@ -619,7 +641,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { ecx: &MiriEvalContext<'mir, 'tcx>, addr: u64, ) -> Pointer> { - intptrcast::GlobalStateInner::ptr_from_addr(addr, ecx) + intptrcast::GlobalStateInner::ptr_from_addr_cast(ecx, addr) } #[inline(always)] @@ -627,14 +649,22 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { ecx: &MiriEvalContext<'mir, 'tcx>, addr: u64, ) -> Pointer> { - Self::ptr_from_addr_cast(ecx, addr) + intptrcast::GlobalStateInner::ptr_from_addr_transmute(ecx, addr) } #[inline(always)] fn expose_ptr( - _ecx: &mut InterpCx<'mir, 'tcx, Self>, - _ptr: Pointer, + ecx: &mut InterpCx<'mir, 'tcx, Self>, + ptr: Pointer, ) -> InterpResult<'tcx> { + let tag = ptr.provenance; + + if let Tag::Concrete(concrete) = tag { + intptrcast::GlobalStateInner::expose_addr(ecx, concrete.alloc_id); + } + + // No need to do anything for wildcard pointers as + // their provenances have already been previously exposed. Ok(()) } @@ -645,7 +675,13 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { ptr: Pointer, ) -> Option<(AllocId, Size, Self::TagExtra)> { let rel = intptrcast::GlobalStateInner::abs_ptr_to_rel(ecx, ptr); - Some((ptr.provenance.alloc_id, rel, ptr.provenance.sb)) + + let sb = match ptr.provenance { + Tag::Concrete(ConcreteTag { sb, .. }) => sb, + Tag::Wildcard => SbTag::Untagged, + }; + + rel.map(|(alloc_id, size)| (alloc_id, size, sb)) } #[inline(always)] diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 625ffb2c5d202..f137b861342a0 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -867,7 +867,16 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.reborrow(&place, size, kind, new_tag, protect)?; // Adjust pointer. - let new_place = place.map_provenance(|p| p.map(|t| Tag { sb: new_tag, ..t })); + let new_place = place.map_provenance(|p| { + p.map(|t| { + // TODO: Fix this eventually + if let Tag::Concrete(t) = t { + Tag::Concrete(ConcreteTag { sb: new_tag, ..t }) + } else { + t + } + }) + }); // Return new pointer. Ok(ImmTy::from_immediate(new_place.to_ref(this), val.layout)) diff --git a/tests/compile-fail/ptr_int_unexposed.rs b/tests/compile-fail/ptr_int_unexposed.rs new file mode 100644 index 0000000000000..2aecb68b8b647 --- /dev/null +++ b/tests/compile-fail/ptr_int_unexposed.rs @@ -0,0 +1,12 @@ +// compile-flags: -Zmiri-permissive-provenance -Zmiri-disable-stacked-borrows + +fn main() { + let x: i32 = 3; + let x_ptr = &x as *const i32; + + // TODO: switch this to addr() once we intrinsify it + let x_usize: usize = unsafe { std::mem::transmute(x_ptr) }; + // Cast back a pointer that did *not* get exposed. + let ptr = x_usize as *const i32; + assert_eq!(unsafe { *ptr }, 3); //~ ERROR Undefined Behavior: dereferencing pointer failed +} diff --git a/tests/compile-fail/ptr_legacy_provenance.rs b/tests/compile-fail/ptr_legacy_provenance.rs new file mode 100644 index 0000000000000..aecc1460e0853 --- /dev/null +++ b/tests/compile-fail/ptr_legacy_provenance.rs @@ -0,0 +1,21 @@ +// compile-flags: -Zmiri-disable-stacked-borrows +#![feature(strict_provenance)] + +use std::ptr; + +// Make sure that with legacy provenance, the allocation id of +// a casted pointer is determined at cast-time +fn main() { + let x: i32 = 0; + let y: i32 = 1; + + let x_ptr = &x as *const i32; + let y_ptr = &y as *const i32; + + let x_usize = x_ptr.expose_addr(); + let y_usize = y_ptr.expose_addr(); + + let ptr = ptr::from_exposed_addr::(y_usize); + let ptr = ptr.with_addr(x_usize); + assert_eq!(unsafe { *ptr }, 0); //~ ERROR is out-of-bounds +} diff --git a/tests/run-pass/ptr_int_permissive_provenance.rs b/tests/run-pass/ptr_int_permissive_provenance.rs new file mode 100644 index 0000000000000..e025cf921313a --- /dev/null +++ b/tests/run-pass/ptr_int_permissive_provenance.rs @@ -0,0 +1,62 @@ +// compile-flags: -Zmiri-permissive-provenance -Zmiri-disable-stacked-borrows +#![feature(strict_provenance)] + +use std::ptr; + +/// Ensure we can expose the address of a pointer that is out-of-bounds +fn ptr_roundtrip_out_of_bounds() { + let x: i32 = 3; + let x_ptr = &x as *const i32; + + let x_usize = x_ptr.wrapping_offset(128).expose_addr(); + + let ptr = ptr::from_exposed_addr::(x_usize).wrapping_offset(-128); + assert_eq!(unsafe { *ptr }, 3); +} + +/// Ensure that we can move between allocations after casting back to a ptr +fn ptr_roundtrip_confusion() { + let x: i32 = 0; + let y: i32 = 1; + + let x_ptr = &x as *const i32; + let y_ptr = &y as *const i32; + + let x_usize = x_ptr.expose_addr(); + let y_usize = y_ptr.expose_addr(); + + let ptr = ptr::from_exposed_addr::(y_usize); + let ptr = ptr.with_addr(x_usize); + assert_eq!(unsafe { *ptr }, 0); +} + +/// Ensure we can cast back a different integer than the one we got when exposing. +fn ptr_roundtrip_imperfect() { + let x: u8 = 3; + let x_ptr = &x as *const u8; + + let x_usize = x_ptr.expose_addr() + 128; + + let ptr = ptr::from_exposed_addr::(x_usize).wrapping_offset(-128); + assert_eq!(unsafe { *ptr }, 3); +} + +/// Ensure that we can roundtrip through a pointer with an address of 0 +fn ptr_roundtrip_null() { + let x = &42; + let x_ptr = x as *const i32; + let x_null_ptr = x_ptr.with_addr(0); // addr 0, but still the provenance of x + let null = x_null_ptr.expose_addr(); + assert_eq!(null, 0); + + let x_null_ptr_copy = ptr::from_exposed_addr::(null); // just a roundtrip, so has provenance of x (angelically) + let x_ptr_copy = x_null_ptr_copy.with_addr(x_ptr.addr()); // addr of x and provenance of x + assert_eq!(unsafe { *x_ptr_copy }, 42); +} + +fn main() { + ptr_roundtrip_out_of_bounds(); + ptr_roundtrip_confusion(); + ptr_roundtrip_imperfect(); + ptr_roundtrip_null(); +} From f8f2255a91f316da6c25906c7f1f9edb353b66ba Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 23 May 2022 09:03:06 +0200 Subject: [PATCH 3093/3747] readme: document permissive-provenance flag --- README.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/README.md b/README.md index abcfd3e6d050e..235b81173b5fb 100644 --- a/README.md +++ b/README.md @@ -318,6 +318,17 @@ to Miri failing to detect cases of undefined behavior in a program. application instead of raising an error within the context of Miri (and halting execution). Note that code might not expect these operations to ever panic, so this flag can lead to strange (mis)behavior. +* `-Zmiri-permissive-provenance` is **experimental**. This will make Miri do a + best-effort attempt to implement the semantics of + [`expose_addr`](https://doc.rust-lang.org/nightly/std/primitive.pointer.html#method.expose_addr) + and + [`ptr::from_exposed_addr`](https://doc.rust-lang.org/nightly/std/ptr/fn.from_exposed_addr.html) + for pointer-to-int and int-to-pointer casts, respectively. This will + necessarily miss some bugs as those semantics are not efficiently + implementable in a sanitizer, but it will only miss bugs that concerns + memory/pointers which is subject to these operations. Also note that this flag + is currently incompatible with Stacked Borrows, so you will have to also pass + `-Zmiri-disable-stacked-borrows` to use this. * `-Zmiri-seed=` configures the seed of the RNG that Miri uses to resolve non-determinism. This RNG is used to pick base addresses for allocations. When isolation is enabled (the default), this is also used to emulate system From 697dca2e0e62ff7717f991dbcf3a6c6fd952f3a1 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 23 May 2022 09:17:04 +0200 Subject: [PATCH 3094/3747] clean up int2ptr code a bit --- src/intptrcast.rs | 53 +++++++++++++++++++++++++++++++---------------- src/machine.rs | 28 ++++++++++++------------- 2 files changed, 49 insertions(+), 32 deletions(-) diff --git a/src/intptrcast.rs b/src/intptrcast.rs index 8395cdc2733d2..4850945b4eeb9 100644 --- a/src/intptrcast.rs +++ b/src/intptrcast.rs @@ -105,6 +105,8 @@ impl<'mir, 'tcx> GlobalStateInner { trace!("Exposing allocation id {:?}", alloc_id); let mut global_state = ecx.machine.intptrcast.borrow_mut(); + // In legacy and strict mode, we don't need this, so we can save some cycles + // by not tracking it. if global_state.provenance_mode == ProvenanceMode::Permissive { global_state.exposed.insert(alloc_id); } @@ -118,12 +120,17 @@ impl<'mir, 'tcx> GlobalStateInner { let global_state = ecx.machine.intptrcast.borrow(); - // In legacy mode, we have to support int2ptr transmutes, - // so just pretend they do the same thing as a cast. - if global_state.provenance_mode == ProvenanceMode::Legacy { - Self::ptr_from_addr_cast(ecx, addr) - } else { - Pointer::new(None, Size::from_bytes(addr)) + match global_state.provenance_mode { + ProvenanceMode::Legacy => { + // In legacy mode, we have to support int2ptr transmutes, + // so just pretend they do the same thing as a cast. + Self::ptr_from_addr_cast(ecx, addr) + } + ProvenanceMode::Permissive | ProvenanceMode::Strict => { + // Both of these modes consider transmuted pointers to be "invalid" (`None` + // provenance). + Pointer::new(None, Size::from_bytes(addr)) + } } } @@ -135,18 +142,26 @@ impl<'mir, 'tcx> GlobalStateInner { let global_state = ecx.machine.intptrcast.borrow(); - if global_state.provenance_mode == ProvenanceMode::Strict { - Pointer::new(None, Size::from_bytes(addr)) - } else if global_state.provenance_mode == ProvenanceMode::Legacy { - let alloc_id = Self::alloc_id_from_addr(ecx, addr); - - Pointer::new( - alloc_id - .map(|alloc_id| Tag::Concrete(ConcreteTag { alloc_id, sb: SbTag::Untagged })), - Size::from_bytes(addr), - ) - } else { - Pointer::new(Some(Tag::Wildcard), Size::from_bytes(addr)) + match global_state.provenance_mode { + ProvenanceMode::Legacy => { + // Determine the allocation this points to at cast time. + let alloc_id = Self::alloc_id_from_addr(ecx, addr); + Pointer::new( + alloc_id.map(|alloc_id| { + Tag::Concrete(ConcreteTag { alloc_id, sb: SbTag::Untagged }) + }), + Size::from_bytes(addr), + ) + } + ProvenanceMode::Strict => { + // We don't support int2ptr casts in this mode (i.e., we treat them like + // transmutes). + Pointer::new(None, Size::from_bytes(addr)) + } + ProvenanceMode::Permissive => { + // This is how wildcard pointers are born. + Pointer::new(Some(Tag::Wildcard), Size::from_bytes(addr)) + } } } @@ -215,6 +230,8 @@ impl<'mir, 'tcx> GlobalStateInner { let alloc_id = if let Tag::Concrete(concrete) = tag { concrete.alloc_id } else { + // A wildcard pointer. + assert_eq!(ecx.machine.intptrcast.borrow().provenance_mode, ProvenanceMode::Permissive); GlobalStateInner::alloc_id_from_addr(ecx, addr.bytes())? }; diff --git a/src/machine.rs b/src/machine.rs index 12a32d81b5c93..0972699e72886 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -652,19 +652,18 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { intptrcast::GlobalStateInner::ptr_from_addr_transmute(ecx, addr) } - #[inline(always)] fn expose_ptr( ecx: &mut InterpCx<'mir, 'tcx, Self>, ptr: Pointer, ) -> InterpResult<'tcx> { - let tag = ptr.provenance; - - if let Tag::Concrete(concrete) = tag { - intptrcast::GlobalStateInner::expose_addr(ecx, concrete.alloc_id); + match ptr.provenance { + Tag::Concrete(concrete) => + intptrcast::GlobalStateInner::expose_addr(ecx, concrete.alloc_id), + Tag::Wildcard => { + // No need to do anything for wildcard pointers as + // their provenances have already been previously exposed. + } } - - // No need to do anything for wildcard pointers as - // their provenances have already been previously exposed. Ok(()) } @@ -676,12 +675,13 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { ) -> Option<(AllocId, Size, Self::TagExtra)> { let rel = intptrcast::GlobalStateInner::abs_ptr_to_rel(ecx, ptr); - let sb = match ptr.provenance { - Tag::Concrete(ConcreteTag { sb, .. }) => sb, - Tag::Wildcard => SbTag::Untagged, - }; - - rel.map(|(alloc_id, size)| (alloc_id, size, sb)) + rel.map(|(alloc_id, size)| { + let sb = match ptr.provenance { + Tag::Concrete(ConcreteTag { sb, .. }) => sb, + Tag::Wildcard => SbTag::Untagged, + }; + (alloc_id, size, sb) + }) } #[inline(always)] From a3a2a474cb85cebb487b148860bcbd88b4c7a735 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 23 May 2022 10:15:34 +0200 Subject: [PATCH 3095/3747] split flag section into common and advanced flags --- README.md | 72 ++++++++++++++++++++++++++++++------------------------- 1 file changed, 39 insertions(+), 33 deletions(-) diff --git a/README.md b/README.md index 235b81173b5fb..876b2fcf972ae 100644 --- a/README.md +++ b/README.md @@ -258,33 +258,12 @@ up the sysroot. If you are using `miri` (the Miri driver) directly, see the [miri-flags]: #miri--z-flags-and-environment-variables Miri adds its own set of `-Z` flags, which are usually set via the `MIRIFLAGS` -environment variable. Some of these are **unsound**, which means they can lead -to Miri failing to detect cases of undefined behavior in a program. +environment variable. We first document the most relevant and most commonly used flags: -* `-Zmiri-check-number-validity` enables checking of integer and float validity - (e.g., they must be initialized and not carry pointer provenance) as part of - enforcing validity invariants. This has no effect when - `-Zmiri-disable-validation` is present. * `-Zmiri-compare-exchange-weak-failure-rate=` changes the failure rate of `compare_exchange_weak` operations. The default is `0.8` (so 4 out of 5 weak ops will fail). You can change it to any value between `0.0` and `1.0`, where `1.0` means it will always fail and `0.0` means it will never fail. -* `-Zmiri-disable-abi-check` disables checking [function ABI]. Using this flag - is **unsound**. -* `-Zmiri-disable-alignment-check` disables checking pointer alignment, so you - can focus on other failures, but it means Miri can miss bugs in your program. - Using this flag is **unsound**. -* `-Zmiri-disable-data-race-detector` disables checking for data races. Using - this flag is **unsound**. -* `-Zmiri-disable-stacked-borrows` disables checking the experimental - [Stacked Borrows] aliasing rules. This can make Miri run faster, but it also - means no aliasing violations will be detected. Using this flag is **unsound** - (but the affected soundness rules are experimental). -* `-Zmiri-disable-validation` disables enforcing validity invariants, which are - enforced by default. This is mostly useful to focus on other failures (such - as out-of-bounds accesses) first. Setting this flag means Miri can miss bugs - in your program. However, this can also help to make Miri run faster. Using - this flag is **unsound**. * `-Zmiri-disable-isolation` disables host isolation. As a consequence, the program has access to host resources such as environment variables, file systems, and randomness. @@ -305,6 +284,44 @@ to Miri failing to detect cases of undefined behavior in a program. `-Zmiri-disable-validation` is set. * `-Zmiri-ignore-leaks` disables the memory leak checker, and also allows some remaining threads to exist when the main thread exits. +* `-Zmiri-seed=` configures the seed of the RNG that Miri uses to resolve + non-determinism. This RNG is used to pick base addresses for allocations. When + isolation is enabled (the default), this is also used to emulate system + entropy. The default seed is 0. You can increase test coverage by running Miri + multiple times with different seeds. + **NOTE**: This entropy is not good enough for cryptographic use! Do not + generate secret keys in Miri or perform other kinds of cryptographic + operations that rely on proper random numbers. +* `-Zmiri-strict-provenance` enables [strict + provenance](https://github.com/rust-lang/rust/issues/95228) checking in Miri. This means that + casting an integer to a pointer yields a result with 'invalid' provenance, i.e., with provenance + that cannot be used for any memory access. Also implies `-Zmiri-tag-raw-pointers` and + `-Zmiri-check-number-validity`. + +The remaining flags are for advanced use only, and more likely to change or be removed. +Some of these are **unsound**, which means they can lead +to Miri failing to detect cases of undefined behavior in a program. + +* `-Zmiri-check-number-validity` enables checking of integer and float validity + (e.g., they must be initialized and not carry pointer provenance) as part of + enforcing validity invariants. This has no effect when + `-Zmiri-disable-validation` is present. +* `-Zmiri-disable-abi-check` disables checking [function ABI]. Using this flag + is **unsound**. +* `-Zmiri-disable-alignment-check` disables checking pointer alignment, so you + can focus on other failures, but it means Miri can miss bugs in your program. + Using this flag is **unsound**. +* `-Zmiri-disable-data-race-detector` disables checking for data races. Using + this flag is **unsound**. +* `-Zmiri-disable-stacked-borrows` disables checking the experimental + [Stacked Borrows] aliasing rules. This can make Miri run faster, but it also + means no aliasing violations will be detected. Using this flag is **unsound** + (but the affected soundness rules are experimental). +* `-Zmiri-disable-validation` disables enforcing validity invariants, which are + enforced by default. This is mostly useful to focus on other failures (such + as out-of-bounds accesses) first. Setting this flag means Miri can miss bugs + in your program. However, this can also help to make Miri run faster. Using + this flag is **unsound**. * `-Zmiri-measureme=` enables `measureme` profiling for the interpreted program. This can be used to find which parts of your program are executing slowly under Miri. The profile is written out to a file with the prefix ``, and can be processed @@ -329,17 +346,6 @@ to Miri failing to detect cases of undefined behavior in a program. memory/pointers which is subject to these operations. Also note that this flag is currently incompatible with Stacked Borrows, so you will have to also pass `-Zmiri-disable-stacked-borrows` to use this. -* `-Zmiri-seed=` configures the seed of the RNG that Miri uses to resolve - non-determinism. This RNG is used to pick base addresses for allocations. - When isolation is enabled (the default), this is also used to emulate system - entropy. The default seed is 0. **NOTE**: This entropy is not good enough - for cryptographic use! Do not generate secret keys in Miri or perform other - kinds of cryptographic operations that rely on proper random numbers. -* `-Zmiri-strict-provenance` enables [strict - provenance](https://github.com/rust-lang/rust/issues/95228) checking in Miri. This means that - casting an integer to a pointer yields a result with 'invalid' provenance, i.e., with provenance - that cannot be used for any memory access. Also implies `-Zmiri-tag-raw-pointers` and - `-Zmiri-check-number-validity`. * `-Zmiri-symbolic-alignment-check` makes the alignment check more strict. By default, alignment is checked by casting the pointer to an integer, and making sure that is a multiple of the alignment. This can lead to cases where a From 5ed22b32a21101b3e4b33684e5e895e3bd441a5e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 23 May 2022 10:28:46 +0200 Subject: [PATCH 3096/3747] test that compare-exchange-weak-failure-rate=0.0 means what it says --- .../atomic-compare-exchange-weak-never-fail.rs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 tests/run-pass/atomic-compare-exchange-weak-never-fail.rs diff --git a/tests/run-pass/atomic-compare-exchange-weak-never-fail.rs b/tests/run-pass/atomic-compare-exchange-weak-never-fail.rs new file mode 100644 index 0000000000000..2c2d4e61d9f5e --- /dev/null +++ b/tests/run-pass/atomic-compare-exchange-weak-never-fail.rs @@ -0,0 +1,17 @@ +// compile-flags: -Zmiri-compare-exchange-weak-failure-rate=0.0 +use std::sync::atomic::{AtomicBool, Ordering::*}; + +// Ensure that compare_exchange_weak never fails. +fn main() { + let atomic = AtomicBool::new(false); + let tries = 100; + for _ in 0..tries { + let cur = atomic.load(Relaxed); + // Try (weakly) to flip the flag. + if atomic.compare_exchange_weak(cur, !cur, Relaxed, Relaxed).is_err() { + // We failed. Avoid panic machinery as that uses atomics/locks. + eprintln!("compare_exchange_weak failed"); + std::process::abort(); + } + } +} From 4d9eafe19a1e63b76fc7f04c4194e05133e27668 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 23 May 2022 11:24:08 +0200 Subject: [PATCH 3097/3747] fix some old typos --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 876b2fcf972ae..0f6c5007ba6cd 100644 --- a/README.md +++ b/README.md @@ -278,10 +278,10 @@ environment variable. We first document the most relevant and most commonly used cannot be accessed by the program. Can be used multiple times to exclude several variables. The `TERM` environment variable is excluded by default to [speed up the test harness](https://github.com/rust-lang/miri/issues/1702). This has no effect unless - `-Zmiri-disable-validation` is also set. + `-Zmiri-disable-isolation` is also set. * `-Zmiri-env-forward=` forwards the `var` environment variable to the interpreted program. Can be used multiple times to forward several variables. This has no effect if - `-Zmiri-disable-validation` is set. + `-Zmiri-disable-isolation` is set. * `-Zmiri-ignore-leaks` disables the memory leak checker, and also allows some remaining threads to exist when the main thread exits. * `-Zmiri-seed=` configures the seed of the RNG that Miri uses to resolve From 6e7a8c017abaea2d3dacf21b50d27c33f7e8bfde Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 23 May 2022 11:27:20 +0200 Subject: [PATCH 3098/3747] move some compile-fail tests to a more appropriate location --- tests/compile-fail/{ => validity}/ptr_integer_transmute.rs | 0 tests/compile-fail/{ => validity}/uninit_float.rs | 0 tests/compile-fail/{ => validity}/uninit_integer.rs | 0 tests/compile-fail/{ => validity}/uninit_integer_signed.rs | 0 4 files changed, 0 insertions(+), 0 deletions(-) rename tests/compile-fail/{ => validity}/ptr_integer_transmute.rs (100%) rename tests/compile-fail/{ => validity}/uninit_float.rs (100%) rename tests/compile-fail/{ => validity}/uninit_integer.rs (100%) rename tests/compile-fail/{ => validity}/uninit_integer_signed.rs (100%) diff --git a/tests/compile-fail/ptr_integer_transmute.rs b/tests/compile-fail/validity/ptr_integer_transmute.rs similarity index 100% rename from tests/compile-fail/ptr_integer_transmute.rs rename to tests/compile-fail/validity/ptr_integer_transmute.rs diff --git a/tests/compile-fail/uninit_float.rs b/tests/compile-fail/validity/uninit_float.rs similarity index 100% rename from tests/compile-fail/uninit_float.rs rename to tests/compile-fail/validity/uninit_float.rs diff --git a/tests/compile-fail/uninit_integer.rs b/tests/compile-fail/validity/uninit_integer.rs similarity index 100% rename from tests/compile-fail/uninit_integer.rs rename to tests/compile-fail/validity/uninit_integer.rs diff --git a/tests/compile-fail/uninit_integer_signed.rs b/tests/compile-fail/validity/uninit_integer_signed.rs similarity index 100% rename from tests/compile-fail/uninit_integer_signed.rs rename to tests/compile-fail/validity/uninit_integer_signed.rs From 42d5e5bf96327970810c018af59eff65554fc53a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 23 May 2022 12:19:42 +0200 Subject: [PATCH 3099/3747] move some tests to more suitable locations --- tests/compile-fail/{ => dangling_pointers}/null_pointer_deref.rs | 0 .../{ => dangling_pointers}/null_pointer_deref_zst.rs | 0 tests/compile-fail/{ => dangling_pointers}/null_pointer_write.rs | 0 .../{ => dangling_pointers}/null_pointer_write_zst.rs | 0 tests/compile-fail/{ => provenance}/ptr_int_unexposed.rs | 0 tests/compile-fail/{ => provenance}/ptr_legacy_provenance.rs | 0 tests/compile-fail/{ => provenance}/strict-provenance-offset.rs | 0 .../compile-fail/{ => provenance}/strict_provenance_transmute.rs | 0 tests/compile-fail/{ => validity}/ptr_integer_array_transmute.rs | 0 tests/compile-fail/{ => validity}/too-big-slice.rs | 0 tests/compile-fail/{ => validity}/too-big-unsized.rs | 0 11 files changed, 0 insertions(+), 0 deletions(-) rename tests/compile-fail/{ => dangling_pointers}/null_pointer_deref.rs (100%) rename tests/compile-fail/{ => dangling_pointers}/null_pointer_deref_zst.rs (100%) rename tests/compile-fail/{ => dangling_pointers}/null_pointer_write.rs (100%) rename tests/compile-fail/{ => dangling_pointers}/null_pointer_write_zst.rs (100%) rename tests/compile-fail/{ => provenance}/ptr_int_unexposed.rs (100%) rename tests/compile-fail/{ => provenance}/ptr_legacy_provenance.rs (100%) rename tests/compile-fail/{ => provenance}/strict-provenance-offset.rs (100%) rename tests/compile-fail/{ => provenance}/strict_provenance_transmute.rs (100%) rename tests/compile-fail/{ => validity}/ptr_integer_array_transmute.rs (100%) rename tests/compile-fail/{ => validity}/too-big-slice.rs (100%) rename tests/compile-fail/{ => validity}/too-big-unsized.rs (100%) diff --git a/tests/compile-fail/null_pointer_deref.rs b/tests/compile-fail/dangling_pointers/null_pointer_deref.rs similarity index 100% rename from tests/compile-fail/null_pointer_deref.rs rename to tests/compile-fail/dangling_pointers/null_pointer_deref.rs diff --git a/tests/compile-fail/null_pointer_deref_zst.rs b/tests/compile-fail/dangling_pointers/null_pointer_deref_zst.rs similarity index 100% rename from tests/compile-fail/null_pointer_deref_zst.rs rename to tests/compile-fail/dangling_pointers/null_pointer_deref_zst.rs diff --git a/tests/compile-fail/null_pointer_write.rs b/tests/compile-fail/dangling_pointers/null_pointer_write.rs similarity index 100% rename from tests/compile-fail/null_pointer_write.rs rename to tests/compile-fail/dangling_pointers/null_pointer_write.rs diff --git a/tests/compile-fail/null_pointer_write_zst.rs b/tests/compile-fail/dangling_pointers/null_pointer_write_zst.rs similarity index 100% rename from tests/compile-fail/null_pointer_write_zst.rs rename to tests/compile-fail/dangling_pointers/null_pointer_write_zst.rs diff --git a/tests/compile-fail/ptr_int_unexposed.rs b/tests/compile-fail/provenance/ptr_int_unexposed.rs similarity index 100% rename from tests/compile-fail/ptr_int_unexposed.rs rename to tests/compile-fail/provenance/ptr_int_unexposed.rs diff --git a/tests/compile-fail/ptr_legacy_provenance.rs b/tests/compile-fail/provenance/ptr_legacy_provenance.rs similarity index 100% rename from tests/compile-fail/ptr_legacy_provenance.rs rename to tests/compile-fail/provenance/ptr_legacy_provenance.rs diff --git a/tests/compile-fail/strict-provenance-offset.rs b/tests/compile-fail/provenance/strict-provenance-offset.rs similarity index 100% rename from tests/compile-fail/strict-provenance-offset.rs rename to tests/compile-fail/provenance/strict-provenance-offset.rs diff --git a/tests/compile-fail/strict_provenance_transmute.rs b/tests/compile-fail/provenance/strict_provenance_transmute.rs similarity index 100% rename from tests/compile-fail/strict_provenance_transmute.rs rename to tests/compile-fail/provenance/strict_provenance_transmute.rs diff --git a/tests/compile-fail/ptr_integer_array_transmute.rs b/tests/compile-fail/validity/ptr_integer_array_transmute.rs similarity index 100% rename from tests/compile-fail/ptr_integer_array_transmute.rs rename to tests/compile-fail/validity/ptr_integer_array_transmute.rs diff --git a/tests/compile-fail/too-big-slice.rs b/tests/compile-fail/validity/too-big-slice.rs similarity index 100% rename from tests/compile-fail/too-big-slice.rs rename to tests/compile-fail/validity/too-big-slice.rs diff --git a/tests/compile-fail/too-big-unsized.rs b/tests/compile-fail/validity/too-big-unsized.rs similarity index 100% rename from tests/compile-fail/too-big-unsized.rs rename to tests/compile-fail/validity/too-big-unsized.rs From 460a0137ccb41e242b221332232e6a21cdcd7606 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 23 May 2022 12:37:48 +0200 Subject: [PATCH 3100/3747] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 5526a13d5fc77..b3496efafdd28 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -22ee39504a702f75485582d02060495a01254de1 +9e2f65586366b731f13a10021c5191a664f4adc2 From f0921bd5dc0de7dddebdd9a08d3636473ae980cf Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 23 May 2022 17:35:36 +0200 Subject: [PATCH 3101/3747] rustup --- rust-version | 2 +- tests/run-pass/concurrency/sync.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/rust-version b/rust-version index b3496efafdd28..983b23fe22883 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -9e2f65586366b731f13a10021c5191a664f4adc2 +32c8c5df06c025441ad04791d7982d65c79a60e4 diff --git a/tests/run-pass/concurrency/sync.rs b/tests/run-pass/concurrency/sync.rs index 303d49e3c33fe..6889aad91cf26 100644 --- a/tests/run-pass/concurrency/sync.rs +++ b/tests/run-pass/concurrency/sync.rs @@ -91,7 +91,7 @@ fn check_conditional_variables_timed_wait_timeout() { let (_guard, timeout) = cvar.wait_timeout(guard, Duration::from_millis(100)).unwrap(); assert!(timeout.timed_out()); let elapsed_time = now.elapsed().as_millis(); - assert!(100 <= elapsed_time && elapsed_time <= 800); + assert!(100 <= elapsed_time && elapsed_time <= 1000); } /// Test that signaling a conditional variable when waiting with a timeout works From 168c83a0b78588ecbe30d0adf7d7d794f62e4312 Mon Sep 17 00:00:00 2001 From: Jakob Degen Date: Fri, 20 May 2022 23:08:32 -0400 Subject: [PATCH 3102/3747] Adjust Miri to also require return places everywhere --- src/diagnostics.rs | 2 +- src/eval.rs | 4 ++-- src/helpers.rs | 2 +- src/machine.rs | 15 +++++++++------ src/shims/dlsym.rs | 8 +++++--- src/shims/foreign_items.rs | 5 +++-- src/shims/intrinsics.rs | 7 ++++--- src/shims/mod.rs | 14 ++++++++------ src/shims/panic.rs | 8 ++++---- src/shims/posix/dlsym.rs | 7 ++++--- src/shims/posix/linux/dlsym.rs | 5 +++-- src/shims/posix/macos/dlsym.rs | 5 +++-- src/shims/posix/thread.rs | 2 +- src/shims/tls.rs | 6 +++--- src/shims/windows/dlsym.rs | 5 +++-- src/stacked_borrows.rs | 9 ++------- 16 files changed, 56 insertions(+), 48 deletions(-) diff --git a/src/diagnostics.rs b/src/diagnostics.rs index 8afcf851ba4e9..527ff032d6703 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -275,7 +275,7 @@ pub fn report_error<'tcx, 'mir>( for (i, frame) in ecx.active_thread_stack().iter().enumerate() { trace!("-------------------"); trace!("Frame {}", i); - trace!(" return: {:?}", frame.return_place.map(|p| *p)); + trace!(" return: {:?}", *frame.return_place); for (i, local) in frame.locals.iter().enumerate() { trace!(" local {}: {:?}", i, local.value); } diff --git a/src/eval.rs b/src/eval.rs index 430ff06cf15ad..badda8f3bc393 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -277,7 +277,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( start_instance, Abi::Rust, &[Scalar::from_pointer(main_ptr, &ecx).into(), argc.into(), argv], - Some(&ret_place.into()), + &ret_place.into(), StackPopCleanup::Root { cleanup: true }, )?; } @@ -286,7 +286,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( entry_instance, Abi::Rust, &[argc.into(), argv], - Some(&ret_place.into()), + &ret_place.into(), StackPopCleanup::Root { cleanup: true }, )?; } diff --git a/src/helpers.rs b/src/helpers.rs index 08b2fa98a2300..24c471a8b0ba8 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -240,7 +240,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx f: ty::Instance<'tcx>, caller_abi: Abi, args: &[Immediate], - dest: Option<&PlaceTy<'tcx, Tag>>, + dest: &PlaceTy<'tcx, Tag>, stack_pop: StackPopCleanup, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); diff --git a/src/machine.rs b/src/machine.rs index 0972699e72886..c5c884e8d7a04 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -512,10 +512,11 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { instance: ty::Instance<'tcx>, abi: Abi, args: &[OpTy<'tcx, Tag>], - ret: Option<(&PlaceTy<'tcx, Tag>, mir::BasicBlock)>, + dest: &PlaceTy<'tcx, Tag>, + ret: Option, unwind: StackPopUnwind, ) -> InterpResult<'tcx, Option<(&'mir mir::Body<'tcx>, ty::Instance<'tcx>)>> { - ecx.find_mir_or_eval_fn(instance, abi, args, ret, unwind) + ecx.find_mir_or_eval_fn(instance, abi, args, dest, ret, unwind) } #[inline(always)] @@ -524,10 +525,11 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { fn_val: Dlsym, abi: Abi, args: &[OpTy<'tcx, Tag>], - ret: Option<(&PlaceTy<'tcx, Tag>, mir::BasicBlock)>, + dest: &PlaceTy<'tcx, Tag>, + ret: Option, _unwind: StackPopUnwind, ) -> InterpResult<'tcx> { - ecx.call_dlsym(fn_val, abi, args, ret) + ecx.call_dlsym(fn_val, abi, args, dest, ret) } #[inline(always)] @@ -535,10 +537,11 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { ecx: &mut MiriEvalContext<'mir, 'tcx>, instance: ty::Instance<'tcx>, args: &[OpTy<'tcx, Tag>], - ret: Option<(&PlaceTy<'tcx, Tag>, mir::BasicBlock)>, + dest: &PlaceTy<'tcx, Tag>, + ret: Option, unwind: StackPopUnwind, ) -> InterpResult<'tcx> { - ecx.call_intrinsic(instance, args, ret, unwind) + ecx.call_intrinsic(instance, args, dest, ret, unwind) } #[inline(always)] diff --git a/src/shims/dlsym.rs b/src/shims/dlsym.rs index 1855d65d6c504..d83a309c3e1f7 100644 --- a/src/shims/dlsym.rs +++ b/src/shims/dlsym.rs @@ -32,13 +32,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx dlsym: Dlsym, abi: Abi, args: &[OpTy<'tcx, Tag>], - ret: Option<(&PlaceTy<'tcx, Tag>, mir::BasicBlock)>, + dest: &PlaceTy<'tcx, Tag>, + ret: Option, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); match dlsym { - Dlsym::Posix(dlsym) => posix::EvalContextExt::call_dlsym(this, dlsym, abi, args, ret), + Dlsym::Posix(dlsym) => + posix::EvalContextExt::call_dlsym(this, dlsym, abi, args, dest, ret), Dlsym::Windows(dlsym) => - windows::EvalContextExt::call_dlsym(this, dlsym, abi, args, ret), + windows::EvalContextExt::call_dlsym(this, dlsym, abi, args, dest, ret), } } } diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 44bf4ba7e3696..e978391801f1e 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -232,7 +232,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx def_id: DefId, abi: Abi, args: &[OpTy<'tcx, Tag>], - ret: Option<(&PlaceTy<'tcx, Tag>, mir::BasicBlock)>, + dest: &PlaceTy<'tcx, Tag>, + ret: Option, unwind: StackPopUnwind, ) -> InterpResult<'tcx, Option<(&'mir mir::Body<'tcx>, ty::Instance<'tcx>)>> { let this = self.eval_context_mut(); @@ -240,7 +241,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let tcx = this.tcx.tcx; // First: functions that diverge. - let (dest, ret) = match ret { + let ret = match ret { None => match &*link_name.as_str() { "miri_start_panic" => { diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index a6f818c493e66..1f06971a3e70d 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -22,19 +22,20 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx &mut self, instance: ty::Instance<'tcx>, args: &[OpTy<'tcx, Tag>], - ret: Option<(&PlaceTy<'tcx, Tag>, mir::BasicBlock)>, + dest: &PlaceTy<'tcx, Tag>, + ret: Option, _unwind: StackPopUnwind, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - if this.emulate_intrinsic(instance, args, ret)? { + if this.emulate_intrinsic(instance, args, dest, ret)? { return Ok(()); } // All supported intrinsics have a return place. let intrinsic_name = this.tcx.item_name(instance.def_id()); let intrinsic_name = intrinsic_name.as_str(); - let (dest, ret) = match ret { + let ret = match ret { None => throw_unsup_format!("unimplemented (diverging) intrinsic: {}", intrinsic_name), Some(p) => p, }; diff --git a/src/shims/mod.rs b/src/shims/mod.rs index f003552434fe9..926fcd5d040b8 100644 --- a/src/shims/mod.rs +++ b/src/shims/mod.rs @@ -28,16 +28,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx instance: ty::Instance<'tcx>, abi: Abi, args: &[OpTy<'tcx, Tag>], - ret: Option<(&PlaceTy<'tcx, Tag>, mir::BasicBlock)>, + dest: &PlaceTy<'tcx, Tag>, + ret: Option, unwind: StackPopUnwind, ) -> InterpResult<'tcx, Option<(&'mir mir::Body<'tcx>, ty::Instance<'tcx>)>> { let this = self.eval_context_mut(); - trace!("eval_fn_call: {:#?}, {:?}", instance, ret.map(|p| p.0)); + trace!("eval_fn_call: {:#?}, {:?}", instance, dest); // There are some more lang items we want to hook that CTFE does not hook (yet). if this.tcx.lang_items().align_offset_fn() == Some(instance.def.def_id()) { let [ptr, align] = check_arg_count(args)?; - if this.align_offset(ptr, align, ret, unwind)? { + if this.align_offset(ptr, align, dest, ret, unwind)? { return Ok(None); } } @@ -50,7 +51,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // to run extra MIR), and Ok(Some(body)) if we found MIR to run for the // foreign function // Any needed call to `goto_block` will be performed by `emulate_foreign_item`. - return this.emulate_foreign_item(instance.def_id(), abi, args, ret, unwind); + return this.emulate_foreign_item(instance.def_id(), abi, args, dest, ret, unwind); } // Otherwise, load the MIR. @@ -63,11 +64,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx &mut self, ptr_op: &OpTy<'tcx, Tag>, align_op: &OpTy<'tcx, Tag>, - ret: Option<(&PlaceTy<'tcx, Tag>, mir::BasicBlock)>, + dest: &PlaceTy<'tcx, Tag>, + ret: Option, unwind: StackPopUnwind, ) -> InterpResult<'tcx, bool> { let this = self.eval_context_mut(); - let (dest, ret) = ret.unwrap(); + let ret = ret.unwrap(); if this.machine.check_alignment != AlignmentCheck::Symbolic { // Just use actual implementation. diff --git a/src/shims/panic.rs b/src/shims/panic.rs index f92e39048bc86..ed6e72591dd00 100644 --- a/src/shims/panic.rs +++ b/src/shims/panic.rs @@ -96,7 +96,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx f_instance, Abi::Rust, &[data.into()], - Some(&ret_place), + &ret_place, // Directly return to caller. StackPopCleanup::Goto { ret: Some(ret), unwind: StackPopUnwind::Skip }, )?; @@ -153,7 +153,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx f_instance, Abi::Rust, &[catch_unwind.data.into(), payload.into()], - Some(&ret_place), + &ret_place, // Directly return to caller of `try`. StackPopCleanup::Goto { ret: Some(catch_unwind.ret), unwind: StackPopUnwind::Skip }, )?; @@ -179,7 +179,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx panic, Abi::Rust, &[msg.to_ref(this)], - None, + &MPlaceTy::dangling(this.machine.layouts.unit).into(), StackPopCleanup::Goto { ret: None, unwind }, ) } @@ -208,7 +208,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx panic_bounds_check, Abi::Rust, &[index.into(), len.into()], - None, + &MPlaceTy::dangling(this.machine.layouts.unit).into(), StackPopCleanup::Goto { ret: None, unwind: match unwind { diff --git a/src/shims/posix/dlsym.rs b/src/shims/posix/dlsym.rs index b07bf91a69a54..0ea441e00e9ae 100644 --- a/src/shims/posix/dlsym.rs +++ b/src/shims/posix/dlsym.rs @@ -30,15 +30,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx dlsym: Dlsym, abi: Abi, args: &[OpTy<'tcx, Tag>], - ret: Option<(&PlaceTy<'tcx, Tag>, mir::BasicBlock)>, + dest: &PlaceTy<'tcx, Tag>, + ret: Option, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); this.check_abi(abi, Abi::C { unwind: false })?; match dlsym { - Dlsym::Linux(dlsym) => linux::EvalContextExt::call_dlsym(this, dlsym, args, ret), - Dlsym::MacOs(dlsym) => macos::EvalContextExt::call_dlsym(this, dlsym, args, ret), + Dlsym::Linux(dlsym) => linux::EvalContextExt::call_dlsym(this, dlsym, args, dest, ret), + Dlsym::MacOs(dlsym) => macos::EvalContextExt::call_dlsym(this, dlsym, args, dest, ret), } } } diff --git a/src/shims/posix/linux/dlsym.rs b/src/shims/posix/linux/dlsym.rs index 1b7ac2754af71..a2d6570fe8d64 100644 --- a/src/shims/posix/linux/dlsym.rs +++ b/src/shims/posix/linux/dlsym.rs @@ -24,10 +24,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx &mut self, dlsym: Dlsym, _args: &[OpTy<'tcx, Tag>], - ret: Option<(&PlaceTy<'tcx, Tag>, mir::BasicBlock)>, + _dest: &PlaceTy<'tcx, Tag>, + ret: Option, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - let (_dest, _ret) = ret.expect("we don't support any diverging dlsym"); + let _ret = ret.expect("we don't support any diverging dlsym"); assert!(this.tcx.sess.target.os == "linux"); match dlsym {} diff --git a/src/shims/posix/macos/dlsym.rs b/src/shims/posix/macos/dlsym.rs index 8ce56d35da653..9369548992e53 100644 --- a/src/shims/posix/macos/dlsym.rs +++ b/src/shims/posix/macos/dlsym.rs @@ -28,10 +28,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx &mut self, dlsym: Dlsym, args: &[OpTy<'tcx, Tag>], - ret: Option<(&PlaceTy<'tcx, Tag>, mir::BasicBlock)>, + dest: &PlaceTy<'tcx, Tag>, + ret: Option, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - let (dest, ret) = ret.expect("we don't support any diverging dlsym"); + let ret = ret.expect("we don't support any diverging dlsym"); assert!(this.tcx.sess.target.os == "macos"); match dlsym { diff --git a/src/shims/posix/thread.rs b/src/shims/posix/thread.rs index 0b8684d39eb21..88c3fb0bc8eab 100644 --- a/src/shims/posix/thread.rs +++ b/src/shims/posix/thread.rs @@ -51,7 +51,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx instance, Abi::C { unwind: false }, &[*func_arg], - Some(&ret_place.into()), + &ret_place.into(), StackPopCleanup::Root { cleanup: true }, )?; diff --git a/src/shims/tls.rs b/src/shims/tls.rs index 3de739a8d048b..87c8d7eadc3bb 100644 --- a/src/shims/tls.rs +++ b/src/shims/tls.rs @@ -258,7 +258,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx thread_callback, Abi::System { unwind: false }, &[Scalar::null_ptr(this).into(), reason.into(), Scalar::null_ptr(this).into()], - Some(&ret_place), + &ret_place, StackPopCleanup::Root { cleanup: true }, )?; @@ -281,7 +281,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx instance, Abi::C { unwind: false }, &[data.into()], - Some(&ret_place), + &ret_place, StackPopCleanup::Root { cleanup: true }, )?; @@ -324,7 +324,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx instance, Abi::C { unwind: false }, &[ptr.into()], - Some(&ret_place), + &ret_place, StackPopCleanup::Root { cleanup: true }, )?; diff --git a/src/shims/windows/dlsym.rs b/src/shims/windows/dlsym.rs index 865c01386045b..b5408e492ce9c 100644 --- a/src/shims/windows/dlsym.rs +++ b/src/shims/windows/dlsym.rs @@ -31,10 +31,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx dlsym: Dlsym, abi: Abi, args: &[OpTy<'tcx, Tag>], - ret: Option<(&PlaceTy<'tcx, Tag>, mir::BasicBlock)>, + dest: &PlaceTy<'tcx, Tag>, + ret: Option, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - let (dest, ret) = ret.expect("we don't support any diverging dlsym"); + let ret = ret.expect("we don't support any diverging dlsym"); assert!(this.tcx.sess.target.os == "windows"); this.check_abi(abi, Abi::System { unwind: false })?; diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index f137b861342a0..30a9cc265dce2 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -930,12 +930,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// explicit. Also see https://github.com/rust-lang/rust/issues/71117. fn retag_return_place(&mut self) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - let return_place = if let Some(return_place) = this.frame_mut().return_place { - return_place - } else { - // No return place, nothing to do. - return Ok(()); - }; + let return_place = this.frame_mut().return_place; if return_place.layout.is_zst() { // There may not be any memory here, nothing to do. return Ok(()); @@ -955,7 +950,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx )?; // And use reborrowed pointer for return place. let return_place = this.ref_to_mplace(&val)?; - this.frame_mut().return_place = Some(return_place.into()); + this.frame_mut().return_place = return_place.into(); Ok(()) } From e428d29d93423fd68991bbc7bce68a991ea743e9 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 24 May 2022 17:16:03 +0200 Subject: [PATCH 3103/3747] rustp --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 983b23fe22883..f4df767fc22f4 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -32c8c5df06c025441ad04791d7982d65c79a60e4 +b2eba058e6e1c698723e47074561a30b50b5fa7a From fcf3bc2335331e7c79e7e7ae78265e2db4637748 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 24 May 2022 17:49:11 +0200 Subject: [PATCH 3104/3747] with permissive-provenance set, we already treat ptr::invalid correctly --- tests/compile-fail/provenance/ptr_invalid.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 tests/compile-fail/provenance/ptr_invalid.rs diff --git a/tests/compile-fail/provenance/ptr_invalid.rs b/tests/compile-fail/provenance/ptr_invalid.rs new file mode 100644 index 0000000000000..b371103e6b665 --- /dev/null +++ b/tests/compile-fail/provenance/ptr_invalid.rs @@ -0,0 +1,10 @@ +// compile-flags: -Zmiri-permissive-provenance +#![feature(strict_provenance)] + +// Ensure that a `ptr::invalid` ptr is truly invalid. +fn main() { + let x = 42; + let xptr = &x as *const i32; + let xptr_invalid = std::ptr::invalid::(xptr.expose_addr()); + let _val = unsafe { *xptr_invalid }; //~ ERROR is not a valid pointer +} From f1756c3ddd06f8d82fa20fb9d738708f84382a33 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Thu, 17 Mar 2022 13:49:10 +0000 Subject: [PATCH 3105/3747] Add a custom ui test runner and move all tests to it --- CONTRIBUTING.md | 20 +- Cargo.lock | 319 ++++++-------- Cargo.toml | 5 +- README.md | 17 +- cargo-miri/bin.rs | 7 +- ci.sh | 3 +- miri | 7 +- src/machine.rs | 6 +- tests/compile-fail/abort-terminator.stderr | 19 + .../alloc/deallocate-bad-alignment.stderr | 16 + .../alloc/deallocate-bad-size.stderr | 16 + .../alloc/deallocate-twice.stderr | 16 + .../compile-fail/alloc/global_system_mixup.rs | 2 + .../alloc/global_system_mixup.stderr | 17 + .../alloc/no_global_allocator.stderr | 12 + .../alloc/reallocate-bad-size.stderr | 16 + .../alloc/reallocate-change-alloc.stderr | 15 + .../alloc/reallocate-dangling.stderr | 16 + tests/compile-fail/alloc/stack_free.stderr | 20 + .../backtrace/bad-backtrace-decl.stderr | 15 + .../backtrace/bad-backtrace-flags.stderr | 14 + .../backtrace/bad-backtrace-ptr.stderr | 15 + .../bad-backtrace-resolve-flags.stderr | 14 + .../bad-backtrace-resolve-names-flags.stderr | 14 + .../backtrace/bad-backtrace-size-flags.stderr | 14 + .../backtrace/bad-backtrace-version.stderr | 14 + tests/compile-fail/box-cell-alias.stderr | 32 ++ .../branchless-select-i128-pointer.stderr | 15 + tests/compile-fail/breakpoint.stderr | 12 + .../libc_pthread_create_main_terminate.stderr | 8 + .../libc_pthread_join_detached.stderr | 17 + .../libc_pthread_join_joined.stderr | 17 + .../concurrency/libc_pthread_join_main.stderr | 17 + .../libc_pthread_join_multiple.stderr | 17 + .../concurrency/libc_pthread_join_self.stderr | 17 + .../compile-fail/concurrency/thread-spawn.rs | 3 +- .../thread_local_static_dealloc.stderr | 17 + .../concurrency/too_few_args.stderr | 16 + .../concurrency/too_many_args.stderr | 16 + .../concurrency/unwind_top_of_stack.stderr | 19 + .../dangling_pointer_addr_of.stderr | 16 + .../dangling_pointer_deref.stderr | 15 + .../dangling_zst_deref.stderr | 15 + .../dangling_pointers/deref-invalid-ptr.rs | 2 +- .../deref-invalid-ptr.stderr | 15 + .../deref-partially-dangling.stderr | 15 + .../dangling_pointers/dyn_size.stderr | 15 + .../maybe_null_pointer_deref_zst.stderr | 15 + .../maybe_null_pointer_write_zst.stderr | 15 + .../null_pointer_deref.stderr | 15 + .../null_pointer_deref_zst.stderr | 15 + .../null_pointer_write.stderr | 15 + .../null_pointer_write_zst.stderr | 17 + .../out_of_bounds_read1.stderr | 15 + .../out_of_bounds_read2.stderr | 15 + .../dangling_pointers/stack_temporary.stderr | 15 + .../storage_dead_dangling.stderr | 20 + .../dangling_pointers/wild_pointer_deref.rs | 2 +- .../wild_pointer_deref.stderr | 15 + .../data_race/alloc_read_race.stderr | 17 + .../data_race/alloc_write_race.stderr | 17 + .../atomic_read_na_write_race1.stderr | 17 + .../atomic_read_na_write_race2.stderr | 17 + .../atomic_write_na_read_race1.stderr | 17 + .../atomic_write_na_read_race2.stderr | 17 + .../atomic_write_na_write_race1.stderr | 17 + .../atomic_write_na_write_race2.stderr | 17 + .../dangling_thread_async_race.stderr | 17 + .../data_race/dangling_thread_race.stderr | 17 + .../data_race/dealloc_read_race1.stderr | 17 + .../data_race/dealloc_read_race2.stderr | 17 + .../data_race/dealloc_read_race_stack.stderr | 17 + .../data_race/dealloc_write_race1.stderr | 17 + .../data_race/dealloc_write_race2.stderr | 17 + .../data_race/dealloc_write_race_stack.stderr | 17 + .../enable_after_join_to_main.stderr | 17 + .../data_race/read_write_race.stderr | 17 + .../data_race/read_write_race_stack.stderr | 17 + .../data_race/relax_acquire_race.stderr | 17 + .../data_race/release_seq_race.stderr | 17 + .../release_seq_race_same_thread.stderr | 17 + tests/compile-fail/data_race/rmw_race.stderr | 17 + .../data_race/write_write_race.stderr | 17 + .../data_race/write_write_race_stack.stderr | 17 + .../environ-gets-deallocated.stderr | 15 + tests/compile-fail/erroneous_const.stderr | 26 ++ tests/compile-fail/erroneous_const2.stderr | 41 ++ tests/compile-fail/extern_static.stderr | 14 + tests/compile-fail/fast_math_both.stderr | 15 + tests/compile-fail/fast_math_first.stderr | 15 + tests/compile-fail/fast_math_second.stderr | 15 + tests/compile-fail/fs/close_stdout.stderr | 14 + tests/compile-fail/fs/isolated_file.stderr | 22 + tests/compile-fail/fs/isolated_stdin.stderr | 15 + tests/compile-fail/fs/read_from_stdout.stderr | 14 + .../fs/unix_open_missing_required_mode.stderr | 20 + .../fs/unix_open_too_many_args.stderr | 20 + tests/compile-fail/fs/write_to_stdin.stderr | 14 + .../function_calls/check_arg_abi.stderr | 15 + .../check_arg_count_abort.stderr | 15 + .../check_arg_count_too_few_args.stderr | 15 + .../check_arg_count_too_many_args.stderr | 15 + .../function_calls/check_callback_abi.stderr | 19 + .../exported_symbol_abi_mismatch.cache.stderr | 15 + ...exported_symbol_abi_mismatch.fn_ptr.stderr | 15 + ...ported_symbol_abi_mismatch.no_cache.stderr | 15 + .../exported_symbol_bad_unwind1.stderr | 17 + .../exported_symbol_bad_unwind2.both.stderr | 23 + ...orted_symbol_bad_unwind2.definition.stderr | 23 + ...ted_symbol_bad_unwind2.extern_block.stderr | 17 + .../exported_symbol_clashing.stderr | 22 + .../exported_symbol_shim_clashing.stderr | 20 + .../exported_symbol_wrong_arguments.stderr | 15 + .../exported_symbol_wrong_type.stderr | 15 + .../cast_box_int_to_fn_ptr.stderr | 15 + .../function_pointers/cast_fn_ptr1.stderr | 15 + .../function_pointers/cast_fn_ptr2.stderr | 15 + .../function_pointers/cast_fn_ptr3.stderr | 15 + .../function_pointers/cast_fn_ptr4.stderr | 15 + .../function_pointers/cast_fn_ptr5.stderr | 15 + .../function_pointers/cast_int_to_fn_ptr.rs | 2 +- .../cast_int_to_fn_ptr.stderr | 15 + .../function_pointers/deref_fn_ptr.stderr | 15 + .../function_pointers/execute_memory.stderr | 15 + .../function_pointers/fn_ptr_offset.stderr | 15 + .../generator-pinned-moved.stderr | 26 ++ tests/compile-fail/intrinsics/assume.stderr | 15 + .../compile-fail/intrinsics/copy_null.stderr | 15 + .../intrinsics/copy_overflow.stderr | 17 + .../intrinsics/copy_overlapping.stderr | 15 + .../compile-fail/intrinsics/copy_unaligned.rs | 2 +- .../intrinsics/copy_unaligned.stderr | 15 + .../intrinsics/ctlz_nonzero.stderr | 15 + .../intrinsics/cttz_nonzero.stderr | 15 + .../intrinsics/div-by-zero.stderr | 15 + .../compile-fail/intrinsics/exact_div1.stderr | 15 + .../compile-fail/intrinsics/exact_div2.stderr | 15 + .../compile-fail/intrinsics/exact_div3.stderr | 15 + .../compile-fail/intrinsics/exact_div4.stderr | 15 + .../intrinsics/float_to_int_32_inf1.stderr | 15 + .../intrinsics/float_to_int_32_infneg1.stderr | 15 + .../intrinsics/float_to_int_32_nan.stderr | 15 + .../intrinsics/float_to_int_32_nanneg.stderr | 15 + .../intrinsics/float_to_int_32_neg.stderr | 15 + .../float_to_int_32_too_big1.stderr | 15 + .../float_to_int_32_too_big2.stderr | 15 + .../float_to_int_32_too_small1.stderr | 15 + .../intrinsics/float_to_int_64_inf1.stderr | 15 + .../intrinsics/float_to_int_64_infneg1.stderr | 15 + .../intrinsics/float_to_int_64_infneg2.stderr | 15 + .../intrinsics/float_to_int_64_nan.stderr | 15 + .../intrinsics/float_to_int_64_neg.stderr | 15 + .../float_to_int_64_too_big1.stderr | 15 + .../float_to_int_64_too_big2.stderr | 15 + .../float_to_int_64_too_big3.stderr | 15 + .../float_to_int_64_too_big4.stderr | 15 + .../float_to_int_64_too_big5.stderr | 15 + .../float_to_int_64_too_big6.stderr | 15 + .../float_to_int_64_too_big7.stderr | 15 + .../float_to_int_64_too_small1.stderr | 15 + .../float_to_int_64_too_small2.stderr | 15 + .../float_to_int_64_too_small3.stderr | 15 + .../intrinsics/out_of_bounds_ptr_1.stderr | 16 + .../intrinsics/out_of_bounds_ptr_2.stderr | 16 + .../intrinsics/out_of_bounds_ptr_3.stderr | 16 + .../intrinsics/overflowing-unchecked-rsh.rs | 2 +- .../overflowing-unchecked-rsh.stderr | 15 + .../intrinsics/ptr_offset_0_plus_0.stderr | 16 + .../intrinsics/ptr_offset_from_oob.stderr | 15 + .../intrinsics/ptr_offset_int_plus_int.rs | 2 +- .../intrinsics/ptr_offset_int_plus_int.stderr | 16 + .../intrinsics/ptr_offset_int_plus_ptr.rs | 2 +- .../intrinsics/ptr_offset_int_plus_ptr.stderr | 16 + .../intrinsics/ptr_offset_overflow.rs | 2 +- .../intrinsics/ptr_offset_overflow.stderr | 16 + .../intrinsics/ptr_offset_ptr_plus_0.stderr | 16 + .../intrinsics/rem-by-zero.stderr | 15 + .../intrinsics/simd-div-by-zero.stderr | 15 + .../intrinsics/simd-div-overflow.stderr | 15 + .../intrinsics/simd-float-to-int.stderr | 17 + .../intrinsics/simd-gather.stderr | 16 + .../simd-reduce-invalid-bool.stderr | 15 + .../intrinsics/simd-rem-by-zero.stderr | 15 + .../intrinsics/simd-scatter.stderr | 16 + .../simd-select-bitmask-invalid.stderr | 15 + .../simd-select-invalid-bool.stderr | 15 + .../intrinsics/simd-shl-too-far.stderr | 15 + .../intrinsics/simd-shr-too-far.stderr | 15 + .../intrinsics/unchecked_add1.stderr | 15 + .../intrinsics/unchecked_add2.stderr | 15 + .../intrinsics/unchecked_div1.stderr | 15 + .../intrinsics/unchecked_mul1.stderr | 15 + .../intrinsics/unchecked_mul2.stderr | 15 + .../intrinsics/unchecked_sub1.stderr | 15 + .../intrinsics/unchecked_sub2.stderr | 15 + .../intrinsics/uninit_uninhabited_type.stderr | 12 + .../intrinsics/write_bytes_null.stderr | 15 + .../intrinsics/write_bytes_overflow.stderr | 17 + .../intrinsics/zero_fn_ptr.stderr | 12 + tests/compile-fail/invalid_bool.rs | 2 +- tests/compile-fail/invalid_bool.stderr | 15 + tests/compile-fail/invalid_char.rs | 2 +- tests/compile-fail/invalid_char.stderr | 15 + tests/compile-fail/invalid_enum_tag.rs | 2 +- tests/compile-fail/invalid_enum_tag.stderr | 16 + tests/compile-fail/invalid_int.stderr | 15 + tests/compile-fail/issue-miri-1112.stderr | 20 + tests/compile-fail/memleak.rs | 3 +- tests/compile-fail/memleak.stderr | 10 + tests/compile-fail/memleak_rc.32bit.stderr | 10 + tests/compile-fail/memleak_rc.64bit.stderr | 11 + tests/compile-fail/memleak_rc.rs | 4 +- tests/compile-fail/modifying_constants.stderr | 15 + tests/compile-fail/never_say_never.stderr | 15 + .../never_transmute_humans.stderr | 15 + .../compile-fail/never_transmute_void.stderr | 20 + tests/compile-fail/no_main.stderr | 2 + tests/compile-fail/null_pointer_deref.stderr | 15 + .../null_pointer_deref_zst.stderr | 15 + tests/compile-fail/null_pointer_write.stderr | 15 + .../null_pointer_write_zst.stderr | 17 + .../panic/bad_miri_start_panic.stderr | 15 + tests/compile-fail/panic/bad_unwind.stderr | 25 ++ tests/compile-fail/panic/double_panic.stderr | 91 ++++ tests/compile-fail/panic/panic_abort1.stderr | 22 + tests/compile-fail/panic/panic_abort2.stderr | 23 + tests/compile-fail/panic/panic_abort3.stderr | 24 + tests/compile-fail/panic/panic_abort4.stderr | 23 + .../panic/unwind_panic_abort.stderr | 15 + .../pointer_partial_overwrite.stderr | 15 + .../compile-fail/pointer_partial_read.stderr | 14 + .../provenance/ptr_int_unexposed.stderr | 15 + .../provenance/ptr_invalid.stderr | 15 + .../provenance/ptr_legacy_provenance.rs | 1 + .../provenance/ptr_legacy_provenance.stderr | 15 + .../strict-provenance-offset.stderr | 16 + .../strict_provenance_transmute.stderr | 20 + .../ptr_integer_array_transmute.stderr | 15 + .../compile-fail/ptr_integer_transmute.stderr | 15 + tests/compile-fail/rc_as_ptr.stderr | 16 + .../reading_half_a_pointer.stderr | 14 + tests/compile-fail/rustc-error.stderr | 14 + tests/compile-fail/shim_arg_size.32bit.stderr | 15 + tests/compile-fail/shim_arg_size.64bit.stderr | 15 + tests/compile-fail/shim_arg_size.rs | 2 + tests/compile-fail/slice-too-big.stderr | 15 + .../alias_through_mutation.stderr | 27 ++ .../stacked_borrows/aliasing_mut1.stderr | 34 ++ .../stacked_borrows/aliasing_mut2.stderr | 34 ++ .../stacked_borrows/aliasing_mut3.stderr | 32 ++ .../stacked_borrows/aliasing_mut4.stderr | 34 ++ .../box_exclusive_violation1.stderr | 38 ++ .../stacked_borrows/buggy_as_mut_slice.stderr | 27 ++ .../stacked_borrows/buggy_split_at_mut.stderr | 27 ++ .../deallocate_against_barrier1.stderr | 34 ++ .../deallocate_against_barrier2.stderr | 34 ++ .../stacked_borrows/illegal_read1.stderr | 27 ++ .../stacked_borrows/illegal_read2.stderr | 27 ++ .../stacked_borrows/illegal_read3.stderr | 27 ++ .../stacked_borrows/illegal_read4.stderr | 27 ++ .../stacked_borrows/illegal_read5.rs | 1 + .../stacked_borrows/illegal_read5.stderr | 27 ++ .../stacked_borrows/illegal_read6.stderr | 27 ++ .../stacked_borrows/illegal_read7.stderr | 27 ++ .../stacked_borrows/illegal_read8.stderr | 27 ++ .../stacked_borrows/illegal_write1.stderr | 27 ++ .../stacked_borrows/illegal_write2.stderr | 27 ++ .../stacked_borrows/illegal_write3.stderr | 22 + .../stacked_borrows/illegal_write4.stderr | 27 ++ .../stacked_borrows/illegal_write5.stderr | 27 ++ .../stacked_borrows/illegal_write6.stderr | 39 ++ .../stacked_borrows/interior_mut1.stderr | 27 ++ .../stacked_borrows/interior_mut2.stderr | 27 ++ .../invalidate_against_barrier1.stderr | 39 ++ .../invalidate_against_barrier2.stderr | 39 ++ .../stacked_borrows/issue-miri-1050-1.stderr | 17 + .../stacked_borrows/issue-miri-1050-2.rs | 2 +- .../stacked_borrows/issue-miri-1050-2.stderr | 17 + .../stacked_borrows/load_invalid_mut.stderr | 27 ++ .../stacked_borrows/load_invalid_shr.stderr | 27 ++ .../mut_exclusive_violation1.stderr | 37 ++ .../mut_exclusive_violation2.stderr | 27 ++ .../stacked_borrows/outdated_local.stderr | 27 ++ .../stacked_borrows/pass_invalid_mut.stderr | 27 ++ .../stacked_borrows/pass_invalid_shr.stderr | 27 ++ .../stacked_borrows/pointer_smuggling.stderr | 32 ++ .../stacked_borrows/raw_tracking.stderr | 27 ++ .../stacked_borrows/return_invalid_mut.stderr | 32 ++ .../return_invalid_mut_option.stderr | 27 ++ .../return_invalid_mut_tuple.stderr | 27 ++ .../stacked_borrows/return_invalid_shr.stderr | 32 ++ .../return_invalid_shr_option.stderr | 27 ++ .../return_invalid_shr_tuple.stderr | 27 ++ .../shared_rw_borrows_are_weak1.stderr | 27 ++ .../shared_rw_borrows_are_weak2.rs | 1 + .../shared_rw_borrows_are_weak2.stderr | 27 ++ .../shr_frozen_violation1.stderr | 32 ++ .../static_memory_modification.rs | 2 +- .../static_memory_modification.stderr | 15 + .../transmute-is-no-escape.stderr | 18 + .../stacked_borrows/unescaped_local.stderr | 27 ++ .../stacked_borrows/unescaped_static.stderr | 18 + .../stacked_borrows/zst_slice.stderr | 16 + .../static_memory_modification1.stderr | 15 + .../static_memory_modification2.stderr | 15 + .../static_memory_modification3.stderr | 15 + .../strict-provenance-offset.stderr | 16 + .../strict_provenance_transmute.stderr | 20 + .../libc_pthread_cond_double_destroy.stderr | 15 + ...ibc_pthread_condattr_double_destroy.stderr | 15 + .../libc_pthread_mutex_NULL_deadlock.stderr | 15 + .../sync/libc_pthread_mutex_deadlock.stderr | 14 + ...libc_pthread_mutex_default_deadlock.stderr | 15 + .../libc_pthread_mutex_destroy_locked.stderr | 15 + .../libc_pthread_mutex_double_destroy.stderr | 15 + .../libc_pthread_mutex_normal_deadlock.stderr | 12 + ...thread_mutex_normal_unlock_unlocked.stderr | 15 + .../libc_pthread_mutex_wrong_owner.stderr | 17 + ...bc_pthread_mutexattr_double_destroy.stderr | 15 + ..._pthread_rwlock_destroy_read_locked.stderr | 15 + ...pthread_rwlock_destroy_write_locked.stderr | 15 + .../libc_pthread_rwlock_double_destroy.stderr | 15 + ...k_read_write_deadlock_single_thread.stderr | 12 + ...ibc_pthread_rwlock_read_wrong_owner.stderr | 17 + ...libc_pthread_rwlock_unlock_unlocked.stderr | 15 + ..._pthread_rwlock_write_read_deadlock.stderr | 14 + ...k_write_read_deadlock_single_thread.stderr | 12 + ...pthread_rwlock_write_write_deadlock.stderr | 14 + ..._write_write_deadlock_single_thread.stderr | 12 + ...bc_pthread_rwlock_write_wrong_owner.stderr | 17 + tests/compile-fail/too-big-slice.stderr | 15 + tests/compile-fail/too-big-unsized.stderr | 15 + .../compile-fail/transmute-pair-uninit.stderr | 15 + tests/compile-fail/transmute_fat1.stderr | 14 + tests/compile-fail/type-too-large.stderr | 12 + .../unaligned_pointers/alignment.rs | 3 +- .../unaligned_pointers/alignment.stderr | 15 + .../atomic_unaligned.stderr | 15 + .../unaligned_pointers/dyn_alignment.rs | 2 +- .../unaligned_pointers/dyn_alignment.stderr | 15 + .../intptrcast_alignment_check.rs | 2 +- .../intptrcast_alignment_check.stderr | 15 + .../unaligned_pointers/reference_to_packed.rs | 2 +- .../reference_to_packed.stderr | 15 + .../unaligned_pointers/unaligned_ptr1.rs | 2 +- .../unaligned_pointers/unaligned_ptr1.stderr | 15 + .../unaligned_pointers/unaligned_ptr2.rs | 2 +- .../unaligned_pointers/unaligned_ptr2.stderr | 15 + .../unaligned_pointers/unaligned_ptr3.stderr | 15 + .../unaligned_pointers/unaligned_ptr4.stderr | 15 + .../unaligned_ptr_addr_of.rs | 2 +- .../unaligned_ptr_addr_of.stderr | 16 + .../unaligned_pointers/unaligned_ptr_zst.rs | 2 +- .../unaligned_ptr_zst.stderr | 15 + tests/compile-fail/uninit_buffer.stderr | 23 + tests/compile-fail/uninit_byte_read.stderr | 15 + tests/compile-fail/uninit_float.stderr | 15 + tests/compile-fail/uninit_integer.stderr | 15 + .../compile-fail/uninit_integer_signed.stderr | 15 + tests/compile-fail/uninit_raw_ptr.stderr | 15 + tests/compile-fail/unreachable.stderr | 16 + .../unsupported_foreign_function.stderr | 14 + tests/compile-fail/unsupported_signal.stderr | 14 + .../compile-fail/validity/cast_fn_ptr1.stderr | 15 + .../compile-fail/validity/cast_fn_ptr2.stderr | 15 + tests/compile-fail/validity/dangling_ref1.rs | 2 +- .../validity/dangling_ref1.stderr | 15 + .../validity/dangling_ref2.stderr | 15 + .../validity/dangling_ref3.stderr | 15 + tests/compile-fail/validity/invalid_bool.rs | 2 +- .../compile-fail/validity/invalid_bool.stderr | 15 + .../validity/invalid_bool_uninit.stderr | 15 + tests/compile-fail/validity/invalid_char.rs | 2 +- .../compile-fail/validity/invalid_char.stderr | 15 + .../validity/invalid_char_uninit.rs | 2 +- .../validity/invalid_char_uninit.stderr | 15 + .../validity/invalid_enum_tag.stderr | 15 + ...invalid_enum_tag_256variants_uninit.stderr | 15 + .../validity/invalid_fnptr_null.stderr | 15 + .../validity/invalid_fnptr_uninit.stderr | 15 + .../validity/invalid_wide_raw.stderr | 15 + tests/compile-fail/validity/nonzero.stderr | 15 + .../ptr_integer_array_transmute.stderr | 15 + .../validity/ptr_integer_transmute.stderr | 15 + .../validity/ref_to_uninhabited1.stderr | 15 + .../validity/ref_to_uninhabited2.stderr | 15 + .../validity/too-big-slice.stderr | 15 + .../validity/too-big-unsized.stderr | 15 + .../validity/transmute_through_ptr.stderr | 15 + .../compile-fail/validity/uninit_float.stderr | 15 + .../validity/uninit_integer.stderr | 15 + .../validity/uninit_integer_signed.stderr | 15 + tests/compile-fail/zst1.stderr | 15 + tests/compile-fail/zst2.stderr | 15 + tests/compile-fail/zst3.stderr | 15 + tests/compiletest.rs | 149 ++++--- .../exported_symbol_good_unwind.rs | 0 .../exported_symbol_good_unwind.stderr | 6 +- .../panic/div-by-zero-2.rs | 0 .../panic/div-by-zero-2.stderr | 2 +- .../panic/overflowing-lsh-neg.rs | 0 .../panic/overflowing-lsh-neg.stderr | 2 +- .../panic/overflowing-rsh-1.rs | 0 .../panic/overflowing-rsh-1.stderr | 2 +- .../panic/overflowing-rsh-2.rs | 0 .../panic/overflowing-rsh-2.stderr | 2 +- tests/run-fail/panic/panic1.rs | 7 + .../panic/panic1.stderr | 30 +- tests/{run-pass => run-fail}/panic/panic2.rs | 0 .../panic/panic2.stderr | 2 +- tests/{run-pass => run-fail}/panic/panic3.rs | 0 .../panic/panic3.stderr | 2 +- tests/{run-pass => run-fail}/panic/panic4.rs | 0 .../panic/panic4.stderr | 2 +- .../panic/unsupported_foreign_function.rs | 0 .../panic/unsupported_foreign_function.stderr | 2 +- .../panic/unsupported_syscall.rs | 2 +- .../panic/unsupported_syscall.stderr | 2 +- .../{run-pass => run-fail}/transmute_fat2.rs | 0 .../transmute_fat2.stderr | 2 +- tests/run-pass/backtrace-api-v0.rs | 4 +- tests/run-pass/backtrace-api-v0.stderr | 36 +- tests/run-pass/backtrace-api-v0.stdout | 10 +- tests/run-pass/backtrace-api-v1.rs | 4 +- tests/run-pass/backtrace-api-v1.stderr | 36 +- tests/run-pass/backtrace-api-v1.stdout | 10 +- tests/run-pass/backtrace-std.rs | 3 - tests/run-pass/backtrace-std.stderr | 36 +- .../concurrency/disable_data_race_detector.rs | 2 +- .../run-pass/concurrency/libc_pthread_cond.rs | 2 +- tests/run-pass/concurrency/linux-futex.rs | 5 +- tests/run-pass/concurrency/simple.stderr | 4 +- tests/run-pass/current_dir_with_isolation.rs | 4 +- tests/run-pass/fs_with_isolation.rs | 2 +- .../linux-getrandom-without-isolation.rs | 5 +- tests/run-pass/linux-getrandom.rs | 5 +- tests/run-pass/panic/catch_panic.rs | 2 - tests/run-pass/panic/catch_panic.stderr | 24 +- tests/run-pass/panic/concurrent-panic.stderr | 4 +- tests/run-pass/panic/panic1.rs | 9 - .../generators-self-referential.rs | 2 +- tests/run-pass/track-alloc-1.stderr | 6 +- tests/run-pass/wtf8.rs | 3 +- ui_test/Cargo.toml | 14 + ui_test/README.md | 30 ++ ui_test/src/comments.rs | 111 +++++ ui_test/src/lib.rs | 410 ++++++++++++++++++ 447 files changed, 7306 insertions(+), 447 deletions(-) create mode 100644 tests/compile-fail/abort-terminator.stderr create mode 100644 tests/compile-fail/alloc/deallocate-bad-alignment.stderr create mode 100644 tests/compile-fail/alloc/deallocate-bad-size.stderr create mode 100644 tests/compile-fail/alloc/deallocate-twice.stderr create mode 100644 tests/compile-fail/alloc/global_system_mixup.stderr create mode 100644 tests/compile-fail/alloc/no_global_allocator.stderr create mode 100644 tests/compile-fail/alloc/reallocate-bad-size.stderr create mode 100644 tests/compile-fail/alloc/reallocate-change-alloc.stderr create mode 100644 tests/compile-fail/alloc/reallocate-dangling.stderr create mode 100644 tests/compile-fail/alloc/stack_free.stderr create mode 100644 tests/compile-fail/backtrace/bad-backtrace-decl.stderr create mode 100644 tests/compile-fail/backtrace/bad-backtrace-flags.stderr create mode 100644 tests/compile-fail/backtrace/bad-backtrace-ptr.stderr create mode 100644 tests/compile-fail/backtrace/bad-backtrace-resolve-flags.stderr create mode 100644 tests/compile-fail/backtrace/bad-backtrace-resolve-names-flags.stderr create mode 100644 tests/compile-fail/backtrace/bad-backtrace-size-flags.stderr create mode 100644 tests/compile-fail/backtrace/bad-backtrace-version.stderr create mode 100644 tests/compile-fail/box-cell-alias.stderr create mode 100644 tests/compile-fail/branchless-select-i128-pointer.stderr create mode 100644 tests/compile-fail/breakpoint.stderr create mode 100644 tests/compile-fail/concurrency/libc_pthread_create_main_terminate.stderr create mode 100644 tests/compile-fail/concurrency/libc_pthread_join_detached.stderr create mode 100644 tests/compile-fail/concurrency/libc_pthread_join_joined.stderr create mode 100644 tests/compile-fail/concurrency/libc_pthread_join_main.stderr create mode 100644 tests/compile-fail/concurrency/libc_pthread_join_multiple.stderr create mode 100644 tests/compile-fail/concurrency/libc_pthread_join_self.stderr create mode 100644 tests/compile-fail/concurrency/thread_local_static_dealloc.stderr create mode 100644 tests/compile-fail/concurrency/too_few_args.stderr create mode 100644 tests/compile-fail/concurrency/too_many_args.stderr create mode 100644 tests/compile-fail/concurrency/unwind_top_of_stack.stderr create mode 100644 tests/compile-fail/dangling_pointers/dangling_pointer_addr_of.stderr create mode 100644 tests/compile-fail/dangling_pointers/dangling_pointer_deref.stderr create mode 100644 tests/compile-fail/dangling_pointers/dangling_zst_deref.stderr create mode 100644 tests/compile-fail/dangling_pointers/deref-invalid-ptr.stderr create mode 100644 tests/compile-fail/dangling_pointers/deref-partially-dangling.stderr create mode 100644 tests/compile-fail/dangling_pointers/dyn_size.stderr create mode 100644 tests/compile-fail/dangling_pointers/maybe_null_pointer_deref_zst.stderr create mode 100644 tests/compile-fail/dangling_pointers/maybe_null_pointer_write_zst.stderr create mode 100644 tests/compile-fail/dangling_pointers/null_pointer_deref.stderr create mode 100644 tests/compile-fail/dangling_pointers/null_pointer_deref_zst.stderr create mode 100644 tests/compile-fail/dangling_pointers/null_pointer_write.stderr create mode 100644 tests/compile-fail/dangling_pointers/null_pointer_write_zst.stderr create mode 100644 tests/compile-fail/dangling_pointers/out_of_bounds_read1.stderr create mode 100644 tests/compile-fail/dangling_pointers/out_of_bounds_read2.stderr create mode 100644 tests/compile-fail/dangling_pointers/stack_temporary.stderr create mode 100644 tests/compile-fail/dangling_pointers/storage_dead_dangling.stderr create mode 100644 tests/compile-fail/dangling_pointers/wild_pointer_deref.stderr create mode 100644 tests/compile-fail/data_race/alloc_read_race.stderr create mode 100644 tests/compile-fail/data_race/alloc_write_race.stderr create mode 100644 tests/compile-fail/data_race/atomic_read_na_write_race1.stderr create mode 100644 tests/compile-fail/data_race/atomic_read_na_write_race2.stderr create mode 100644 tests/compile-fail/data_race/atomic_write_na_read_race1.stderr create mode 100644 tests/compile-fail/data_race/atomic_write_na_read_race2.stderr create mode 100644 tests/compile-fail/data_race/atomic_write_na_write_race1.stderr create mode 100644 tests/compile-fail/data_race/atomic_write_na_write_race2.stderr create mode 100644 tests/compile-fail/data_race/dangling_thread_async_race.stderr create mode 100644 tests/compile-fail/data_race/dangling_thread_race.stderr create mode 100644 tests/compile-fail/data_race/dealloc_read_race1.stderr create mode 100644 tests/compile-fail/data_race/dealloc_read_race2.stderr create mode 100644 tests/compile-fail/data_race/dealloc_read_race_stack.stderr create mode 100644 tests/compile-fail/data_race/dealloc_write_race1.stderr create mode 100644 tests/compile-fail/data_race/dealloc_write_race2.stderr create mode 100644 tests/compile-fail/data_race/dealloc_write_race_stack.stderr create mode 100644 tests/compile-fail/data_race/enable_after_join_to_main.stderr create mode 100644 tests/compile-fail/data_race/read_write_race.stderr create mode 100644 tests/compile-fail/data_race/read_write_race_stack.stderr create mode 100644 tests/compile-fail/data_race/relax_acquire_race.stderr create mode 100644 tests/compile-fail/data_race/release_seq_race.stderr create mode 100644 tests/compile-fail/data_race/release_seq_race_same_thread.stderr create mode 100644 tests/compile-fail/data_race/rmw_race.stderr create mode 100644 tests/compile-fail/data_race/write_write_race.stderr create mode 100644 tests/compile-fail/data_race/write_write_race_stack.stderr create mode 100644 tests/compile-fail/environ-gets-deallocated.stderr create mode 100644 tests/compile-fail/erroneous_const.stderr create mode 100644 tests/compile-fail/erroneous_const2.stderr create mode 100644 tests/compile-fail/extern_static.stderr create mode 100644 tests/compile-fail/fast_math_both.stderr create mode 100644 tests/compile-fail/fast_math_first.stderr create mode 100644 tests/compile-fail/fast_math_second.stderr create mode 100644 tests/compile-fail/fs/close_stdout.stderr create mode 100644 tests/compile-fail/fs/isolated_file.stderr create mode 100644 tests/compile-fail/fs/isolated_stdin.stderr create mode 100644 tests/compile-fail/fs/read_from_stdout.stderr create mode 100644 tests/compile-fail/fs/unix_open_missing_required_mode.stderr create mode 100644 tests/compile-fail/fs/unix_open_too_many_args.stderr create mode 100644 tests/compile-fail/fs/write_to_stdin.stderr create mode 100644 tests/compile-fail/function_calls/check_arg_abi.stderr create mode 100644 tests/compile-fail/function_calls/check_arg_count_abort.stderr create mode 100644 tests/compile-fail/function_calls/check_arg_count_too_few_args.stderr create mode 100644 tests/compile-fail/function_calls/check_arg_count_too_many_args.stderr create mode 100644 tests/compile-fail/function_calls/check_callback_abi.stderr create mode 100644 tests/compile-fail/function_calls/exported_symbol_abi_mismatch.cache.stderr create mode 100644 tests/compile-fail/function_calls/exported_symbol_abi_mismatch.fn_ptr.stderr create mode 100644 tests/compile-fail/function_calls/exported_symbol_abi_mismatch.no_cache.stderr create mode 100644 tests/compile-fail/function_calls/exported_symbol_bad_unwind1.stderr create mode 100644 tests/compile-fail/function_calls/exported_symbol_bad_unwind2.both.stderr create mode 100644 tests/compile-fail/function_calls/exported_symbol_bad_unwind2.definition.stderr create mode 100644 tests/compile-fail/function_calls/exported_symbol_bad_unwind2.extern_block.stderr create mode 100644 tests/compile-fail/function_calls/exported_symbol_clashing.stderr create mode 100644 tests/compile-fail/function_calls/exported_symbol_shim_clashing.stderr create mode 100644 tests/compile-fail/function_calls/exported_symbol_wrong_arguments.stderr create mode 100644 tests/compile-fail/function_calls/exported_symbol_wrong_type.stderr create mode 100644 tests/compile-fail/function_pointers/cast_box_int_to_fn_ptr.stderr create mode 100644 tests/compile-fail/function_pointers/cast_fn_ptr1.stderr create mode 100644 tests/compile-fail/function_pointers/cast_fn_ptr2.stderr create mode 100644 tests/compile-fail/function_pointers/cast_fn_ptr3.stderr create mode 100644 tests/compile-fail/function_pointers/cast_fn_ptr4.stderr create mode 100644 tests/compile-fail/function_pointers/cast_fn_ptr5.stderr create mode 100644 tests/compile-fail/function_pointers/cast_int_to_fn_ptr.stderr create mode 100644 tests/compile-fail/function_pointers/deref_fn_ptr.stderr create mode 100644 tests/compile-fail/function_pointers/execute_memory.stderr create mode 100644 tests/compile-fail/function_pointers/fn_ptr_offset.stderr create mode 100644 tests/compile-fail/generator-pinned-moved.stderr create mode 100644 tests/compile-fail/intrinsics/assume.stderr create mode 100644 tests/compile-fail/intrinsics/copy_null.stderr create mode 100644 tests/compile-fail/intrinsics/copy_overflow.stderr create mode 100644 tests/compile-fail/intrinsics/copy_overlapping.stderr create mode 100644 tests/compile-fail/intrinsics/copy_unaligned.stderr create mode 100644 tests/compile-fail/intrinsics/ctlz_nonzero.stderr create mode 100644 tests/compile-fail/intrinsics/cttz_nonzero.stderr create mode 100644 tests/compile-fail/intrinsics/div-by-zero.stderr create mode 100644 tests/compile-fail/intrinsics/exact_div1.stderr create mode 100644 tests/compile-fail/intrinsics/exact_div2.stderr create mode 100644 tests/compile-fail/intrinsics/exact_div3.stderr create mode 100644 tests/compile-fail/intrinsics/exact_div4.stderr create mode 100644 tests/compile-fail/intrinsics/float_to_int_32_inf1.stderr create mode 100644 tests/compile-fail/intrinsics/float_to_int_32_infneg1.stderr create mode 100644 tests/compile-fail/intrinsics/float_to_int_32_nan.stderr create mode 100644 tests/compile-fail/intrinsics/float_to_int_32_nanneg.stderr create mode 100644 tests/compile-fail/intrinsics/float_to_int_32_neg.stderr create mode 100644 tests/compile-fail/intrinsics/float_to_int_32_too_big1.stderr create mode 100644 tests/compile-fail/intrinsics/float_to_int_32_too_big2.stderr create mode 100644 tests/compile-fail/intrinsics/float_to_int_32_too_small1.stderr create mode 100644 tests/compile-fail/intrinsics/float_to_int_64_inf1.stderr create mode 100644 tests/compile-fail/intrinsics/float_to_int_64_infneg1.stderr create mode 100644 tests/compile-fail/intrinsics/float_to_int_64_infneg2.stderr create mode 100644 tests/compile-fail/intrinsics/float_to_int_64_nan.stderr create mode 100644 tests/compile-fail/intrinsics/float_to_int_64_neg.stderr create mode 100644 tests/compile-fail/intrinsics/float_to_int_64_too_big1.stderr create mode 100644 tests/compile-fail/intrinsics/float_to_int_64_too_big2.stderr create mode 100644 tests/compile-fail/intrinsics/float_to_int_64_too_big3.stderr create mode 100644 tests/compile-fail/intrinsics/float_to_int_64_too_big4.stderr create mode 100644 tests/compile-fail/intrinsics/float_to_int_64_too_big5.stderr create mode 100644 tests/compile-fail/intrinsics/float_to_int_64_too_big6.stderr create mode 100644 tests/compile-fail/intrinsics/float_to_int_64_too_big7.stderr create mode 100644 tests/compile-fail/intrinsics/float_to_int_64_too_small1.stderr create mode 100644 tests/compile-fail/intrinsics/float_to_int_64_too_small2.stderr create mode 100644 tests/compile-fail/intrinsics/float_to_int_64_too_small3.stderr create mode 100644 tests/compile-fail/intrinsics/out_of_bounds_ptr_1.stderr create mode 100644 tests/compile-fail/intrinsics/out_of_bounds_ptr_2.stderr create mode 100644 tests/compile-fail/intrinsics/out_of_bounds_ptr_3.stderr create mode 100644 tests/compile-fail/intrinsics/overflowing-unchecked-rsh.stderr create mode 100644 tests/compile-fail/intrinsics/ptr_offset_0_plus_0.stderr create mode 100644 tests/compile-fail/intrinsics/ptr_offset_from_oob.stderr create mode 100644 tests/compile-fail/intrinsics/ptr_offset_int_plus_int.stderr create mode 100644 tests/compile-fail/intrinsics/ptr_offset_int_plus_ptr.stderr create mode 100644 tests/compile-fail/intrinsics/ptr_offset_overflow.stderr create mode 100644 tests/compile-fail/intrinsics/ptr_offset_ptr_plus_0.stderr create mode 100644 tests/compile-fail/intrinsics/rem-by-zero.stderr create mode 100644 tests/compile-fail/intrinsics/simd-div-by-zero.stderr create mode 100644 tests/compile-fail/intrinsics/simd-div-overflow.stderr create mode 100644 tests/compile-fail/intrinsics/simd-float-to-int.stderr create mode 100644 tests/compile-fail/intrinsics/simd-gather.stderr create mode 100644 tests/compile-fail/intrinsics/simd-reduce-invalid-bool.stderr create mode 100644 tests/compile-fail/intrinsics/simd-rem-by-zero.stderr create mode 100644 tests/compile-fail/intrinsics/simd-scatter.stderr create mode 100644 tests/compile-fail/intrinsics/simd-select-bitmask-invalid.stderr create mode 100644 tests/compile-fail/intrinsics/simd-select-invalid-bool.stderr create mode 100644 tests/compile-fail/intrinsics/simd-shl-too-far.stderr create mode 100644 tests/compile-fail/intrinsics/simd-shr-too-far.stderr create mode 100644 tests/compile-fail/intrinsics/unchecked_add1.stderr create mode 100644 tests/compile-fail/intrinsics/unchecked_add2.stderr create mode 100644 tests/compile-fail/intrinsics/unchecked_div1.stderr create mode 100644 tests/compile-fail/intrinsics/unchecked_mul1.stderr create mode 100644 tests/compile-fail/intrinsics/unchecked_mul2.stderr create mode 100644 tests/compile-fail/intrinsics/unchecked_sub1.stderr create mode 100644 tests/compile-fail/intrinsics/unchecked_sub2.stderr create mode 100644 tests/compile-fail/intrinsics/uninit_uninhabited_type.stderr create mode 100644 tests/compile-fail/intrinsics/write_bytes_null.stderr create mode 100644 tests/compile-fail/intrinsics/write_bytes_overflow.stderr create mode 100644 tests/compile-fail/intrinsics/zero_fn_ptr.stderr create mode 100644 tests/compile-fail/invalid_bool.stderr create mode 100644 tests/compile-fail/invalid_char.stderr create mode 100644 tests/compile-fail/invalid_enum_tag.stderr create mode 100644 tests/compile-fail/invalid_int.stderr create mode 100644 tests/compile-fail/issue-miri-1112.stderr create mode 100644 tests/compile-fail/memleak.stderr create mode 100644 tests/compile-fail/memleak_rc.32bit.stderr create mode 100644 tests/compile-fail/memleak_rc.64bit.stderr create mode 100644 tests/compile-fail/modifying_constants.stderr create mode 100644 tests/compile-fail/never_say_never.stderr create mode 100644 tests/compile-fail/never_transmute_humans.stderr create mode 100644 tests/compile-fail/never_transmute_void.stderr create mode 100644 tests/compile-fail/no_main.stderr create mode 100644 tests/compile-fail/null_pointer_deref.stderr create mode 100644 tests/compile-fail/null_pointer_deref_zst.stderr create mode 100644 tests/compile-fail/null_pointer_write.stderr create mode 100644 tests/compile-fail/null_pointer_write_zst.stderr create mode 100644 tests/compile-fail/panic/bad_miri_start_panic.stderr create mode 100644 tests/compile-fail/panic/bad_unwind.stderr create mode 100644 tests/compile-fail/panic/double_panic.stderr create mode 100644 tests/compile-fail/panic/panic_abort1.stderr create mode 100644 tests/compile-fail/panic/panic_abort2.stderr create mode 100644 tests/compile-fail/panic/panic_abort3.stderr create mode 100644 tests/compile-fail/panic/panic_abort4.stderr create mode 100644 tests/compile-fail/panic/unwind_panic_abort.stderr create mode 100644 tests/compile-fail/pointer_partial_overwrite.stderr create mode 100644 tests/compile-fail/pointer_partial_read.stderr create mode 100644 tests/compile-fail/provenance/ptr_int_unexposed.stderr create mode 100644 tests/compile-fail/provenance/ptr_invalid.stderr create mode 100644 tests/compile-fail/provenance/ptr_legacy_provenance.stderr create mode 100644 tests/compile-fail/provenance/strict-provenance-offset.stderr create mode 100644 tests/compile-fail/provenance/strict_provenance_transmute.stderr create mode 100644 tests/compile-fail/ptr_integer_array_transmute.stderr create mode 100644 tests/compile-fail/ptr_integer_transmute.stderr create mode 100644 tests/compile-fail/rc_as_ptr.stderr create mode 100644 tests/compile-fail/reading_half_a_pointer.stderr create mode 100644 tests/compile-fail/rustc-error.stderr create mode 100644 tests/compile-fail/shim_arg_size.32bit.stderr create mode 100644 tests/compile-fail/shim_arg_size.64bit.stderr create mode 100644 tests/compile-fail/slice-too-big.stderr create mode 100644 tests/compile-fail/stacked_borrows/alias_through_mutation.stderr create mode 100644 tests/compile-fail/stacked_borrows/aliasing_mut1.stderr create mode 100644 tests/compile-fail/stacked_borrows/aliasing_mut2.stderr create mode 100644 tests/compile-fail/stacked_borrows/aliasing_mut3.stderr create mode 100644 tests/compile-fail/stacked_borrows/aliasing_mut4.stderr create mode 100644 tests/compile-fail/stacked_borrows/box_exclusive_violation1.stderr create mode 100644 tests/compile-fail/stacked_borrows/buggy_as_mut_slice.stderr create mode 100644 tests/compile-fail/stacked_borrows/buggy_split_at_mut.stderr create mode 100644 tests/compile-fail/stacked_borrows/deallocate_against_barrier1.stderr create mode 100644 tests/compile-fail/stacked_borrows/deallocate_against_barrier2.stderr create mode 100644 tests/compile-fail/stacked_borrows/illegal_read1.stderr create mode 100644 tests/compile-fail/stacked_borrows/illegal_read2.stderr create mode 100644 tests/compile-fail/stacked_borrows/illegal_read3.stderr create mode 100644 tests/compile-fail/stacked_borrows/illegal_read4.stderr create mode 100644 tests/compile-fail/stacked_borrows/illegal_read5.stderr create mode 100644 tests/compile-fail/stacked_borrows/illegal_read6.stderr create mode 100644 tests/compile-fail/stacked_borrows/illegal_read7.stderr create mode 100644 tests/compile-fail/stacked_borrows/illegal_read8.stderr create mode 100644 tests/compile-fail/stacked_borrows/illegal_write1.stderr create mode 100644 tests/compile-fail/stacked_borrows/illegal_write2.stderr create mode 100644 tests/compile-fail/stacked_borrows/illegal_write3.stderr create mode 100644 tests/compile-fail/stacked_borrows/illegal_write4.stderr create mode 100644 tests/compile-fail/stacked_borrows/illegal_write5.stderr create mode 100644 tests/compile-fail/stacked_borrows/illegal_write6.stderr create mode 100644 tests/compile-fail/stacked_borrows/interior_mut1.stderr create mode 100644 tests/compile-fail/stacked_borrows/interior_mut2.stderr create mode 100644 tests/compile-fail/stacked_borrows/invalidate_against_barrier1.stderr create mode 100644 tests/compile-fail/stacked_borrows/invalidate_against_barrier2.stderr create mode 100644 tests/compile-fail/stacked_borrows/issue-miri-1050-1.stderr create mode 100644 tests/compile-fail/stacked_borrows/issue-miri-1050-2.stderr create mode 100644 tests/compile-fail/stacked_borrows/load_invalid_mut.stderr create mode 100644 tests/compile-fail/stacked_borrows/load_invalid_shr.stderr create mode 100644 tests/compile-fail/stacked_borrows/mut_exclusive_violation1.stderr create mode 100644 tests/compile-fail/stacked_borrows/mut_exclusive_violation2.stderr create mode 100644 tests/compile-fail/stacked_borrows/outdated_local.stderr create mode 100644 tests/compile-fail/stacked_borrows/pass_invalid_mut.stderr create mode 100644 tests/compile-fail/stacked_borrows/pass_invalid_shr.stderr create mode 100644 tests/compile-fail/stacked_borrows/pointer_smuggling.stderr create mode 100644 tests/compile-fail/stacked_borrows/raw_tracking.stderr create mode 100644 tests/compile-fail/stacked_borrows/return_invalid_mut.stderr create mode 100644 tests/compile-fail/stacked_borrows/return_invalid_mut_option.stderr create mode 100644 tests/compile-fail/stacked_borrows/return_invalid_mut_tuple.stderr create mode 100644 tests/compile-fail/stacked_borrows/return_invalid_shr.stderr create mode 100644 tests/compile-fail/stacked_borrows/return_invalid_shr_option.stderr create mode 100644 tests/compile-fail/stacked_borrows/return_invalid_shr_tuple.stderr create mode 100644 tests/compile-fail/stacked_borrows/shared_rw_borrows_are_weak1.stderr create mode 100644 tests/compile-fail/stacked_borrows/shared_rw_borrows_are_weak2.stderr create mode 100644 tests/compile-fail/stacked_borrows/shr_frozen_violation1.stderr create mode 100644 tests/compile-fail/stacked_borrows/static_memory_modification.stderr create mode 100644 tests/compile-fail/stacked_borrows/transmute-is-no-escape.stderr create mode 100644 tests/compile-fail/stacked_borrows/unescaped_local.stderr create mode 100644 tests/compile-fail/stacked_borrows/unescaped_static.stderr create mode 100644 tests/compile-fail/stacked_borrows/zst_slice.stderr create mode 100644 tests/compile-fail/static_memory_modification1.stderr create mode 100644 tests/compile-fail/static_memory_modification2.stderr create mode 100644 tests/compile-fail/static_memory_modification3.stderr create mode 100644 tests/compile-fail/strict-provenance-offset.stderr create mode 100644 tests/compile-fail/strict_provenance_transmute.stderr create mode 100644 tests/compile-fail/sync/libc_pthread_cond_double_destroy.stderr create mode 100644 tests/compile-fail/sync/libc_pthread_condattr_double_destroy.stderr create mode 100644 tests/compile-fail/sync/libc_pthread_mutex_NULL_deadlock.stderr create mode 100644 tests/compile-fail/sync/libc_pthread_mutex_deadlock.stderr create mode 100644 tests/compile-fail/sync/libc_pthread_mutex_default_deadlock.stderr create mode 100644 tests/compile-fail/sync/libc_pthread_mutex_destroy_locked.stderr create mode 100644 tests/compile-fail/sync/libc_pthread_mutex_double_destroy.stderr create mode 100644 tests/compile-fail/sync/libc_pthread_mutex_normal_deadlock.stderr create mode 100644 tests/compile-fail/sync/libc_pthread_mutex_normal_unlock_unlocked.stderr create mode 100644 tests/compile-fail/sync/libc_pthread_mutex_wrong_owner.stderr create mode 100644 tests/compile-fail/sync/libc_pthread_mutexattr_double_destroy.stderr create mode 100644 tests/compile-fail/sync/libc_pthread_rwlock_destroy_read_locked.stderr create mode 100644 tests/compile-fail/sync/libc_pthread_rwlock_destroy_write_locked.stderr create mode 100644 tests/compile-fail/sync/libc_pthread_rwlock_double_destroy.stderr create mode 100644 tests/compile-fail/sync/libc_pthread_rwlock_read_write_deadlock_single_thread.stderr create mode 100644 tests/compile-fail/sync/libc_pthread_rwlock_read_wrong_owner.stderr create mode 100644 tests/compile-fail/sync/libc_pthread_rwlock_unlock_unlocked.stderr create mode 100644 tests/compile-fail/sync/libc_pthread_rwlock_write_read_deadlock.stderr create mode 100644 tests/compile-fail/sync/libc_pthread_rwlock_write_read_deadlock_single_thread.stderr create mode 100644 tests/compile-fail/sync/libc_pthread_rwlock_write_write_deadlock.stderr create mode 100644 tests/compile-fail/sync/libc_pthread_rwlock_write_write_deadlock_single_thread.stderr create mode 100644 tests/compile-fail/sync/libc_pthread_rwlock_write_wrong_owner.stderr create mode 100644 tests/compile-fail/too-big-slice.stderr create mode 100644 tests/compile-fail/too-big-unsized.stderr create mode 100644 tests/compile-fail/transmute-pair-uninit.stderr create mode 100644 tests/compile-fail/transmute_fat1.stderr create mode 100644 tests/compile-fail/type-too-large.stderr create mode 100644 tests/compile-fail/unaligned_pointers/alignment.stderr create mode 100644 tests/compile-fail/unaligned_pointers/atomic_unaligned.stderr create mode 100644 tests/compile-fail/unaligned_pointers/dyn_alignment.stderr create mode 100644 tests/compile-fail/unaligned_pointers/intptrcast_alignment_check.stderr create mode 100644 tests/compile-fail/unaligned_pointers/reference_to_packed.stderr create mode 100644 tests/compile-fail/unaligned_pointers/unaligned_ptr1.stderr create mode 100644 tests/compile-fail/unaligned_pointers/unaligned_ptr2.stderr create mode 100644 tests/compile-fail/unaligned_pointers/unaligned_ptr3.stderr create mode 100644 tests/compile-fail/unaligned_pointers/unaligned_ptr4.stderr create mode 100644 tests/compile-fail/unaligned_pointers/unaligned_ptr_addr_of.stderr create mode 100644 tests/compile-fail/unaligned_pointers/unaligned_ptr_zst.stderr create mode 100644 tests/compile-fail/uninit_buffer.stderr create mode 100644 tests/compile-fail/uninit_byte_read.stderr create mode 100644 tests/compile-fail/uninit_float.stderr create mode 100644 tests/compile-fail/uninit_integer.stderr create mode 100644 tests/compile-fail/uninit_integer_signed.stderr create mode 100644 tests/compile-fail/uninit_raw_ptr.stderr create mode 100644 tests/compile-fail/unreachable.stderr create mode 100644 tests/compile-fail/unsupported_foreign_function.stderr create mode 100644 tests/compile-fail/unsupported_signal.stderr create mode 100644 tests/compile-fail/validity/cast_fn_ptr1.stderr create mode 100644 tests/compile-fail/validity/cast_fn_ptr2.stderr create mode 100644 tests/compile-fail/validity/dangling_ref1.stderr create mode 100644 tests/compile-fail/validity/dangling_ref2.stderr create mode 100644 tests/compile-fail/validity/dangling_ref3.stderr create mode 100644 tests/compile-fail/validity/invalid_bool.stderr create mode 100644 tests/compile-fail/validity/invalid_bool_uninit.stderr create mode 100644 tests/compile-fail/validity/invalid_char.stderr create mode 100644 tests/compile-fail/validity/invalid_char_uninit.stderr create mode 100644 tests/compile-fail/validity/invalid_enum_tag.stderr create mode 100644 tests/compile-fail/validity/invalid_enum_tag_256variants_uninit.stderr create mode 100644 tests/compile-fail/validity/invalid_fnptr_null.stderr create mode 100644 tests/compile-fail/validity/invalid_fnptr_uninit.stderr create mode 100644 tests/compile-fail/validity/invalid_wide_raw.stderr create mode 100644 tests/compile-fail/validity/nonzero.stderr create mode 100644 tests/compile-fail/validity/ptr_integer_array_transmute.stderr create mode 100644 tests/compile-fail/validity/ptr_integer_transmute.stderr create mode 100644 tests/compile-fail/validity/ref_to_uninhabited1.stderr create mode 100644 tests/compile-fail/validity/ref_to_uninhabited2.stderr create mode 100644 tests/compile-fail/validity/too-big-slice.stderr create mode 100644 tests/compile-fail/validity/too-big-unsized.stderr create mode 100644 tests/compile-fail/validity/transmute_through_ptr.stderr create mode 100644 tests/compile-fail/validity/uninit_float.stderr create mode 100644 tests/compile-fail/validity/uninit_integer.stderr create mode 100644 tests/compile-fail/validity/uninit_integer_signed.stderr create mode 100644 tests/compile-fail/zst1.stderr create mode 100644 tests/compile-fail/zst2.stderr create mode 100644 tests/compile-fail/zst3.stderr rename tests/{run-pass => run-fail}/function_calls/exported_symbol_good_unwind.rs (100%) rename tests/{run-pass => run-fail}/function_calls/exported_symbol_good_unwind.stderr (80%) rename tests/{run-pass => run-fail}/panic/div-by-zero-2.rs (100%) rename tests/{run-pass => run-fail}/panic/div-by-zero-2.stderr (88%) rename tests/{run-pass => run-fail}/panic/overflowing-lsh-neg.rs (100%) rename tests/{run-pass => run-fail}/panic/overflowing-lsh-neg.stderr (80%) rename tests/{run-pass => run-fail}/panic/overflowing-rsh-1.rs (100%) rename tests/{run-pass => run-fail}/panic/overflowing-rsh-1.stderr (80%) rename tests/{run-pass => run-fail}/panic/overflowing-rsh-2.rs (100%) rename tests/{run-pass => run-fail}/panic/overflowing-rsh-2.stderr (80%) create mode 100644 tests/run-fail/panic/panic1.rs rename tests/{run-pass => run-fail}/panic/panic1.stderr (55%) rename tests/{run-pass => run-fail}/panic/panic2.rs (100%) rename tests/{run-pass => run-fail}/panic/panic2.stderr (92%) rename tests/{run-pass => run-fail}/panic/panic3.rs (100%) rename tests/{run-pass => run-fail}/panic/panic3.stderr (94%) rename tests/{run-pass => run-fail}/panic/panic4.rs (100%) rename tests/{run-pass => run-fail}/panic/panic4.stderr (92%) rename tests/{run-pass => run-fail}/panic/unsupported_foreign_function.rs (100%) rename tests/{run-pass => run-fail}/panic/unsupported_foreign_function.stderr (95%) rename tests/{run-pass => run-fail}/panic/unsupported_syscall.rs (78%) rename tests/{run-pass => run-fail}/panic/unsupported_syscall.stderr (69%) rename tests/{run-pass => run-fail}/transmute_fat2.rs (100%) rename tests/{run-pass => run-fail}/transmute_fat2.stderr (75%) delete mode 100644 tests/run-pass/panic/panic1.rs create mode 100644 ui_test/Cargo.toml create mode 100644 ui_test/README.md create mode 100644 ui_test/src/comments.rs create mode 100644 ui_test/src/lib.rs diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 996164b93e8b6..b74444fbc6e4e 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,6 +1,6 @@ # Contribution Guide -If you want to hack on miri yourself, great! Here are some resources you might +If you want to hack on Miri yourself, great! Here are some resources you might find useful. ## Getting started @@ -89,6 +89,20 @@ MIRI_LOG=rustc_mir::interpret=info,miri::stacked_borrows ./miri run tests/run-pa In addition, you can set `MIRI_BACKTRACE=1` to get a backtrace of where an evaluation error was originally raised. +#### UI testing + +We use ui-testing in Miri, meaning we generate `.stderr` and `.stdout` files for the output +produced by Miri. You can use `./miri bless` to automatically (re)generate these files when +you add new tests or change how Miri presents certain output. + +Note that when you also use `MIRIFLAGS` to change optimizations and similar, the ui output +will change in unexpected ways. In order to still be able +to run the other checks while ignoring the ui output, use `MIRI_SKIP_UI_CHECKS=1 ./miri test`. + +For more info on how to configure ui tests see [the documentation on the ui test crate][ui_test] + +[ui_test]: ui_test/README.md + ### Testing `cargo miri` Working with the driver directly gives you full control, but you also lose all @@ -183,7 +197,7 @@ A big part of the Miri driver lives in rustc, so working on Miri will sometimes require using a locally built rustc. The bug you want to fix may actually be on the rustc side, or you just need to get more detailed trace of the execution than what is possible with release builds -- in both cases, you should develop -miri against a rustc you compiled yourself, with debug assertions (and hence +Miri against a rustc you compiled yourself, with debug assertions (and hence tracing) enabled. The setup for a local rustc works as follows: @@ -191,7 +205,7 @@ The setup for a local rustc works as follows: # Clone the rust-lang/rust repo. git clone https://github.com/rust-lang/rust rustc cd rustc -# Create a config.toml with defaults for working on miri. +# Create a config.toml with defaults for working on Miri. ./x.py setup compiler # Now edit `config.toml` and under `[rust]` set `debug-assertions = true`. diff --git a/Cargo.lock b/Cargo.lock index 35e45800c0ed6..5377f9420b7c8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -12,10 +12,13 @@ dependencies = [ ] [[package]] -name = "anyhow" -version = "1.0.51" +name = "ansi_term" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b26702f315f53b6071259e15dd9d64528213b44d61de1ec926eca7715d62203" +checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2" +dependencies = [ + "winapi", +] [[package]] name = "atty" @@ -28,6 +31,12 @@ dependencies = [ "winapi", ] +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + [[package]] name = "bitflags" version = "1.3.2" @@ -52,87 +61,101 @@ dependencies = [ ] [[package]] -name = "compiletest_rs" -version = "0.7.1" +name = "crossbeam" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29843cb8d351febf86557681d049d1e1652b81a086a190fa1173c07fd17fbf83" +checksum = "4ae5588f6b3c3cb05239e90bd110f257254aecd01e4635400391aeae07497845" dependencies = [ - "diff", - "filetime", - "getopts", - "lazy_static", - "libc", - "log", - "miow", - "regex", - "rustfix", - "serde", - "serde_derive", - "serde_json", - "tempfile", - "tester", - "winapi", + "cfg-if", + "crossbeam-channel", + "crossbeam-deque", + "crossbeam-epoch", + "crossbeam-queue", + "crossbeam-utils", ] [[package]] -name = "diff" -version = "0.1.12" +name = "crossbeam-channel" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e25ea47919b1560c4e3b7fe0aaab9becf5b84a10325ddf7db0f0ba5e1026499" +checksum = "5aaa7bd5fb665c6864b5f963dd9097905c54125909c7aa94c9e18507cdbe6c53" +dependencies = [ + "cfg-if", + "crossbeam-utils", +] [[package]] -name = "dirs-next" -version = "2.0.0" +name = "crossbeam-deque" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1" +checksum = "6455c0ca19f0d2fbf751b908d5c55c1f5cbc65e03c4225427254b46890bdde1e" dependencies = [ "cfg-if", - "dirs-sys-next", + "crossbeam-epoch", + "crossbeam-utils", ] [[package]] -name = "dirs-sys-next" -version = "0.1.2" +name = "crossbeam-epoch" +version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" +checksum = "1145cf131a2c6ba0615079ab6a638f7e1973ac9c2634fcbeaaad6114246efe8c" dependencies = [ - "libc", - "redox_users", - "winapi", + "autocfg", + "cfg-if", + "crossbeam-utils", + "lazy_static", + "memoffset", + "scopeguard", ] [[package]] -name = "env_logger" -version = "0.9.0" +name = "crossbeam-queue" +version = "0.3.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b2cf0344971ee6c64c31be0d530793fba457d322dfec2810c453d0ef228f9c3" +checksum = "1f25d8400f4a7a5778f0e4e52384a48cbd9b5c495d110786187fc750075277a2" dependencies = [ - "atty", - "humantime", - "log", - "regex", - "termcolor", + "cfg-if", + "crossbeam-utils", ] [[package]] -name = "filetime" -version = "0.2.15" +name = "crossbeam-utils" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "975ccf83d8d9d0d84682850a38c8169027be83368805971cc4f238c2b245bc98" +checksum = "0bf124c720b7686e3c2663cf54062ab0f68a88af2fb6a030e87e30bf721fcb38" dependencies = [ "cfg-if", - "libc", - "redox_syscall", - "winapi", + "lazy_static", ] [[package]] -name = "getopts" -version = "0.2.21" +name = "ctor" +version = "0.1.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14dbbfd5c71d70241ecf9e6f13737f7b5ce823821063188d7e46c41d371eebd5" +checksum = "f877be4f7c9f246b183111634f75baa039715e3f46ce860677d3b19a69fb229c" dependencies = [ - "unicode-width", + "quote", + "syn", +] + +[[package]] +name = "diff" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e25ea47919b1560c4e3b7fe0aaab9becf5b84a10325ddf7db0f0ba5e1026499" + +[[package]] +name = "env_logger" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b2cf0344971ee6c64c31be0d530793fba457d322dfec2810c453d0ef228f9c3" +dependencies = [ + "atty", + "humantime", + "log", + "regex", + "termcolor", ] [[package]] @@ -170,12 +193,6 @@ dependencies = [ "cfg-if", ] -[[package]] -name = "itoa" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35" - [[package]] name = "lazy_static" version = "1.4.0" @@ -236,12 +253,12 @@ dependencies = [ ] [[package]] -name = "miow" -version = "0.3.7" +name = "memoffset" +version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9f1c5b025cda876f66ef43a113f91ebc9f4ccef34843000e0adf6ebbab84e21" +checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce" dependencies = [ - "winapi", + "autocfg", ] [[package]] @@ -249,27 +266,27 @@ name = "miri" version = "0.1.0" dependencies = [ "colored", - "compiletest_rs", "env_logger", "getrandom", + "lazy_static", "libc", "log", "measureme", "rand", + "regex", "rustc-workspace-hack", - "rustc_version", "shell-escape", "smallvec", + "ui_test", ] [[package]] -name = "num_cpus" -version = "1.13.0" +name = "output_vt100" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3" +checksum = "628223faebab4e3e40667ee0b2336d34a5b960ff60ea743ddfdbcf7770bcfb66" dependencies = [ - "hermit-abi", - "libc", + "winapi", ] [[package]] @@ -312,20 +329,32 @@ version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed0cfbc8191465bed66e1718596ee0b0b35d5ee1f41c5df2189d0fe8bde535ba" +[[package]] +name = "pretty_assertions" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c89f989ac94207d048d92db058e4f6ec7342b0971fc58d1271ca148b799b3563" +dependencies = [ + "ansi_term", + "ctor", + "diff", + "output_vt100", +] + [[package]] name = "proc-macro2" -version = "1.0.33" +version = "1.0.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb37d2df5df740e582f28f8560cf425f52bb267d872fe58358eadb554909f07a" +checksum = "c54b25569025b7fc9651de43004ae593a75ad88543b17178aa5e1b9c4f15f56f" dependencies = [ - "unicode-xid", + "unicode-ident", ] [[package]] name = "quote" -version = "1.0.10" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38bc8cc6a5f2e3655e0899c1b848643b2562f853f114bfec7be120678e3ace05" +checksum = "a1feb54ed693b93a84e14094943b84b7c4eae204c512b7ccb95ab0c66d278ad1" dependencies = [ "proc-macro2", ] @@ -379,21 +408,11 @@ dependencies = [ "bitflags", ] -[[package]] -name = "redox_users" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "528532f3d801c87aec9def2add9ca802fe569e44a544afe633765267840abe64" -dependencies = [ - "getrandom", - "redox_syscall", -] - [[package]] name = "regex" -version = "1.5.4" +version = "1.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461" +checksum = "1a11647b6b25ff05a515cb92c365cec08801e83423a235b51e231e1808747286" dependencies = [ "aho-corasick", "memchr", @@ -406,15 +425,6 @@ version = "0.6.25" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" -[[package]] -name = "remove_dir_all" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" -dependencies = [ - "winapi", -] - [[package]] name = "rustc-hash" version = "1.1.0" @@ -436,30 +446,6 @@ dependencies = [ "semver", ] -[[package]] -name = "rustfix" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2c50b74badcddeb8f7652fa8323ce440b95286f8e4b64ebfd871c609672704e" -dependencies = [ - "anyhow", - "log", - "serde", - "serde_json", -] - -[[package]] -name = "rustversion" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2cc38e8fa666e2de3c4aba7edeb5ffc5246c1c2ed0e3d17e560aeeba736b23f" - -[[package]] -name = "ryu" -version = "1.0.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73b4b750c782965c211b42f022f59af1fbceabdd026623714f104152f1ec149f" - [[package]] name = "scopeguard" version = "1.1.0" @@ -468,40 +454,9 @@ checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" [[package]] name = "semver" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "568a8e6258aa33c13358f81fd834adb854c6f7c9468520910a9b1e8fac068012" - -[[package]] -name = "serde" -version = "1.0.131" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4ad69dfbd3e45369132cc64e6748c2d65cdfb001a2b1c232d128b4ad60561c1" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_derive" -version = "1.0.131" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b710a83c4e0dff6a3d511946b95274ad9ca9e5d3ae497b63fda866ac955358d2" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "serde_json" -version = "1.0.73" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcbd0344bc6533bc7ec56df11d42fb70f1b912351c0825ccb7211b59d8af7cf5" -dependencies = [ - "itoa", - "ryu", - "serde", -] +checksum = "8cb243bdfdb5936c8dc3c45762a19d12ab4550cdc753bc247637d4ec35a040fd" [[package]] name = "shell-escape" @@ -517,38 +472,13 @@ checksum = "1ecab6c735a6bb4139c0caafd0cc3635748bbb3acf4550e8138122099251f309" [[package]] name = "syn" -version = "1.0.82" +version = "1.0.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8daf5dd0bb60cbd4137b1b587d2fc0ae729bc07cf01cd70b36a1ed5ade3b9d59" +checksum = "fbaf6116ab8924f39d52792136fb74fd60a80194cf1b1c6ffa6453eef1c3f942" dependencies = [ "proc-macro2", "quote", - "unicode-xid", -] - -[[package]] -name = "tempfile" -version = "3.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dac1c663cfc93810f88aed9b8941d48cabf856a1b111c29a40439018d870eb22" -dependencies = [ - "cfg-if", - "libc", - "rand", - "redox_syscall", - "remove_dir_all", - "winapi", -] - -[[package]] -name = "term" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c59df8ac95d96ff9bede18eb7300b0fda5e5d8d90960e76f8e14ae765eedbf1f" -dependencies = [ - "dirs-next", - "rustversion", - "winapi", + "unicode-ident", ] [[package]] @@ -561,29 +491,22 @@ dependencies = [ ] [[package]] -name = "tester" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0639d10d8f4615f223a57275cf40f9bdb7cfbb806bcb7f7cc56e3beb55a576eb" +name = "ui_test" +version = "0.1.0" dependencies = [ - "cfg-if", - "getopts", - "libc", - "num_cpus", - "term", + "colored", + "crossbeam", + "lazy_static", + "pretty_assertions", + "regex", + "rustc_version", ] [[package]] -name = "unicode-width" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973" - -[[package]] -name = "unicode-xid" -version = "0.2.2" +name = "unicode-ident" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" +checksum = "d22af068fba1eb5edcb4aea19d382b2a3deb4c8f9d475c589b6ada9e0fd493ee" [[package]] name = "wasi" diff --git a/Cargo.toml b/Cargo.toml index 6d65ab6e1e469..cf6f4c8b2ee96 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -37,9 +37,10 @@ measureme = "9.1.2" libc = "0.2" [dev-dependencies] -compiletest_rs = { version = "0.7", features = ["tmp"] } -rustc_version = "0.4" colored = "2" +ui_test = { path = "ui_test" } +regex = "1.5.5" +lazy_static = "1.4.0" [package.metadata.rust-analyzer] # This crate uses #[feature(rustc_private)]. diff --git a/README.md b/README.md index 0f6c5007ba6cd..afee8a8bfa053 100644 --- a/README.md +++ b/README.md @@ -328,7 +328,7 @@ to Miri failing to detect cases of undefined behavior in a program. using the tools in the repository https://github.com/rust-lang/measureme. * `-Zmiri-mute-stdout-stderr` silently ignores all writes to stdout and stderr, but reports to the program that it did actually write. This is useful when you - are not interested in the actual program's output, but only want to see miri's + are not interested in the actual program's output, but only want to see Miri's errors and warnings. * `-Zmiri-panic-on-unsupported` will makes some forms of unsupported functionality, such as FFI and unsupported syscalls, panic within the context of the emulated @@ -412,6 +412,11 @@ Moreover, Miri recognizes some environment variables: * `MIRI_TEST_TARGET` (recognized by the test suite) indicates which target architecture to test against. `miri` and `cargo miri` accept the `--target` flag for the same purpose. +* `MIRI_BLESS` (recognized by the test suite) overwrite all `stderr` and `stdout` files + instead of checking whether the output matches. +* `MIRI_SKIP_UI_CHECKS` (recognized by the test suite) don't check whether the + `stderr` or `stdout` files match the actual output. Useful for the rustc test suite + which has subtle differences that we don't care about. The following environment variables are *internal* and must not be used by anyone but Miri itself. They are used to communicate between different Miri @@ -519,15 +524,15 @@ GitHub or use the [Miri stream on the Rust Zulip][zulip]. This project began as part of an undergraduate research course in 2015 by @solson at the [University of Saskatchewan][usask]. There are [slides] and a -[report] available from that project. In 2016, @oli-obk joined to prepare miri +[report] available from that project. In 2016, @oli-obk joined to prepare Miri for eventually being used as const evaluator in the Rust compiler itself (basically, for `const` and `static` stuff), replacing the old evaluator that worked directly on the AST. In 2017, @RalfJung did an internship with Mozilla -and began developing miri towards a tool for detecting undefined behavior, and -also using miri as a way to explore the consequences of various possible -definitions for undefined behavior in Rust. @oli-obk's move of the miri engine +and began developing Miri towards a tool for detecting undefined behavior, and +also using Miri as a way to explore the consequences of various possible +definitions for undefined behavior in Rust. @oli-obk's move of the Miri engine into the compiler finally came to completion in early 2018. Meanwhile, later -that year, @RalfJung did a second internship, developing miri further with +that year, @RalfJung did a second internship, developing Miri further with support for checking basic type invariants and verifying that references are used according to their aliasing restrictions. diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index 373c63647c35a..e08cb8c88c00e 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -461,7 +461,12 @@ path = "lib.rs" command.env_remove("RUSTFLAGS"); // Disable debug assertions in the standard library -- Miri is already slow enough. // But keep the overflow checks, they are cheap. - command.env("RUSTFLAGS", "-Cdebug-assertions=off -Coverflow-checks=on"); + // Also remap the current directory to something that is stable across different + // machines. Otherwise ui output would contain the current directory. + command.env( + "RUSTFLAGS", + "-Cdebug-assertions=off -Coverflow-checks=on -Zremap-cwd-prefix=rustc_src", + ); // Finally run it! if command.status().expect("failed to run xargo").success().not() { show_error(format!("failed to run xargo")); diff --git a/ci.sh b/ci.sh index c19aceb641e3d..d435e0e2a210b 100755 --- a/ci.sh +++ b/ci.sh @@ -24,7 +24,8 @@ function run_tests { if [ -z "${MIRI_TEST_TARGET+exists}" ]; then # Only for host architecture: tests with optimizations (`-O` is what cargo passes, but crank MIR # optimizations up all the way). - MIRIFLAGS="-O -Zmir-opt-level=4" ./miri test --locked + # Optimizations change diagnostics (mostly backtraces), so we don't check them + MIRIFLAGS="-O -Zmir-opt-level=4" MIRI_SKIP_UI_CHECKS=1 ./miri test --locked fi # On Windows, there is always "python", not "python3" or "python2". diff --git a/miri b/miri index 56ae119cd1bcc..6a809b74356a3 100755 --- a/miri +++ b/miri @@ -123,10 +123,15 @@ build|build-debug) cargo build $CARGO_BUILD_FLAGS --manifest-path "$MIRIDIR"/Cargo.toml "$@" cargo build $CARGO_BUILD_FLAGS --manifest-path "$MIRIDIR"/cargo-miri/Cargo.toml "$@" ;; -test|test-debug) +test|test-debug|bless|bless-debug) # First build and get a sysroot. cargo build $CARGO_BUILD_FLAGS find_sysroot + case "$COMMAND" in + bless|bless-debug) + export MIRI_BLESS="Gesundheit" + ;; + esac # Then test, and let caller control flags. # Only in root project as `cargo-miri` has no tests. exec cargo test $CARGO_BUILD_FLAGS "$@" diff --git a/src/machine.rs b/src/machine.rs index c5c884e8d7a04..249b578b1214a 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -583,7 +583,11 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { if let Some(&ptr) = ecx.machine.extern_statics.get(&link_name) { Ok(ptr) } else { - throw_unsup_format!("`extern` static {:?} is not supported by Miri", def_id) + throw_unsup_format!( + "`extern` static `{}` from crate `{}` is not supported by Miri", + ecx.tcx.def_path_str(def_id), + ecx.tcx.crate_name(def_id.krate), + ) } } diff --git a/tests/compile-fail/abort-terminator.stderr b/tests/compile-fail/abort-terminator.stderr new file mode 100644 index 0000000000000..76501ca074fdd --- /dev/null +++ b/tests/compile-fail/abort-terminator.stderr @@ -0,0 +1,19 @@ +thread 'main' panicked at 'explicit panic', $DIR/abort-terminator.rs:LL:CC +note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace +error: abnormal termination: the program aborted execution + --> $DIR/abort-terminator.rs:LL:CC + | +LL | extern "C" fn panic_abort() { panic!() } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the program aborted execution + | + = note: inside `panic_abort` at $DIR/abort-terminator.rs:LL:CC +note: inside `main` at $DIR/abort-terminator.rs:LL:CC + --> $DIR/abort-terminator.rs:LL:CC + | +LL | panic_abort(); + | ^^^^^^^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/alloc/deallocate-bad-alignment.stderr b/tests/compile-fail/alloc/deallocate-bad-alignment.stderr new file mode 100644 index 0000000000000..e03704b118a67 --- /dev/null +++ b/tests/compile-fail/alloc/deallocate-bad-alignment.stderr @@ -0,0 +1,16 @@ +error: Undefined Behavior: incorrect layout on deallocation: ALLOC has size 1 and alignment ALIGN, but gave size 1 and alignment ALIGN + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `std::alloc::dealloc` at rustc_src/src/alloc.rs:LL:CC +note: inside `main` at $DIR/deallocate-bad-alignment.rs:LL:CC + --> $DIR/deallocate-bad-alignment.rs:LL:CC + | +LL | dealloc(x, Layout::from_size_align_unchecked(1, 2)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/alloc/deallocate-bad-size.stderr b/tests/compile-fail/alloc/deallocate-bad-size.stderr new file mode 100644 index 0000000000000..3ab15094daeb8 --- /dev/null +++ b/tests/compile-fail/alloc/deallocate-bad-size.stderr @@ -0,0 +1,16 @@ +error: Undefined Behavior: incorrect layout on deallocation: ALLOC has size 1 and alignment ALIGN, but gave size 2 and alignment ALIGN + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `std::alloc::dealloc` at rustc_src/src/alloc.rs:LL:CC +note: inside `main` at $DIR/deallocate-bad-size.rs:LL:CC + --> $DIR/deallocate-bad-size.rs:LL:CC + | +LL | dealloc(x, Layout::from_size_align_unchecked(2, 1)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/alloc/deallocate-twice.stderr b/tests/compile-fail/alloc/deallocate-twice.stderr new file mode 100644 index 0000000000000..dfd14c397865e --- /dev/null +++ b/tests/compile-fail/alloc/deallocate-twice.stderr @@ -0,0 +1,16 @@ +error: Undefined Behavior: pointer to ALLOC was dereferenced after this allocation got freed + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `std::alloc::dealloc` at rustc_src/src/alloc.rs:LL:CC +note: inside `main` at $DIR/deallocate-twice.rs:LL:CC + --> $DIR/deallocate-twice.rs:LL:CC + | +LL | dealloc(x, Layout::from_size_align_unchecked(1, 1)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/alloc/global_system_mixup.rs b/tests/compile-fail/alloc/global_system_mixup.rs index afe9d5cc82540..3f58de4d6fb0a 100644 --- a/tests/compile-fail/alloc/global_system_mixup.rs +++ b/tests/compile-fail/alloc/global_system_mixup.rs @@ -2,6 +2,8 @@ // (even when the default `Global` uses `System`). // error-pattern: which is Rust heap memory, using +// normalize-stderr-test: "using [A-Za-z]+ heap deallocation operation" -> "using PLATFORM heap deallocation operation" + #![feature(allocator_api, slice_ptr_get)] use std::alloc::{Allocator, Global, System, Layout}; diff --git a/tests/compile-fail/alloc/global_system_mixup.stderr b/tests/compile-fail/alloc/global_system_mixup.stderr new file mode 100644 index 0000000000000..93598be134f77 --- /dev/null +++ b/tests/compile-fail/alloc/global_system_mixup.stderr @@ -0,0 +1,17 @@ +error: Undefined Behavior: deallocating ALLOC, which is Rust heap memory, using PLATFORM heap deallocation operation + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `std::sys::PLATFORM::alloc::::dealloc` at rustc_src/src/sys/PLATFORM/alloc.rs:LL:CC + = note: inside `::deallocate` at rustc_src/src/alloc.rs:LL:CC +note: inside `main` at $DIR/global_system_mixup.rs:LL:CC + --> $DIR/global_system_mixup.rs:LL:CC + | +LL | unsafe { System.deallocate(ptr, l); } + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/alloc/no_global_allocator.stderr b/tests/compile-fail/alloc/no_global_allocator.stderr new file mode 100644 index 0000000000000..2a9840ee83c4c --- /dev/null +++ b/tests/compile-fail/alloc/no_global_allocator.stderr @@ -0,0 +1,12 @@ +error: unsupported operation: can't call foreign function: __rust_alloc + --> $DIR/no_global_allocator.rs:LL:CC + | +LL | __rust_alloc(1, 1); + | ^^^^^^^^^^^^^^^^^^ can't call foreign function: __rust_alloc + | + = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support + + = note: inside `start` at $DIR/no_global_allocator.rs:LL:CC + +error: aborting due to previous error + diff --git a/tests/compile-fail/alloc/reallocate-bad-size.stderr b/tests/compile-fail/alloc/reallocate-bad-size.stderr new file mode 100644 index 0000000000000..f2692b1c343f9 --- /dev/null +++ b/tests/compile-fail/alloc/reallocate-bad-size.stderr @@ -0,0 +1,16 @@ +error: Undefined Behavior: incorrect layout on deallocation: ALLOC has size 1 and alignment ALIGN, but gave size 2 and alignment ALIGN + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `std::alloc::realloc` at rustc_src/src/alloc.rs:LL:CC +note: inside `main` at $DIR/reallocate-bad-size.rs:LL:CC + --> $DIR/reallocate-bad-size.rs:LL:CC + | +LL | let _y = realloc(x, Layout::from_size_align_unchecked(2, 1), 1); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/alloc/reallocate-change-alloc.stderr b/tests/compile-fail/alloc/reallocate-change-alloc.stderr new file mode 100644 index 0000000000000..d400931379b06 --- /dev/null +++ b/tests/compile-fail/alloc/reallocate-change-alloc.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: pointer to ALLOC was dereferenced after this allocation got freed + --> $DIR/reallocate-change-alloc.rs:LL:CC + | +LL | let _z = *x; + | ^^ pointer to ALLOC was dereferenced after this allocation got freed + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/reallocate-change-alloc.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/alloc/reallocate-dangling.stderr b/tests/compile-fail/alloc/reallocate-dangling.stderr new file mode 100644 index 0000000000000..d813fb0db9026 --- /dev/null +++ b/tests/compile-fail/alloc/reallocate-dangling.stderr @@ -0,0 +1,16 @@ +error: Undefined Behavior: pointer to ALLOC was dereferenced after this allocation got freed + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `std::alloc::realloc` at rustc_src/src/alloc.rs:LL:CC +note: inside `main` at $DIR/reallocate-dangling.rs:LL:CC + --> $DIR/reallocate-dangling.rs:LL:CC + | +LL | let _z = realloc(x, Layout::from_size_align_unchecked(1, 1), 1); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/alloc/stack_free.stderr b/tests/compile-fail/alloc/stack_free.stderr new file mode 100644 index 0000000000000..9df85d6eab7f5 --- /dev/null +++ b/tests/compile-fail/alloc/stack_free.stderr @@ -0,0 +1,20 @@ +error: Undefined Behavior: deallocating ALLOC, which is stack variable memory, using Rust heap deallocation operation + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `std::alloc::dealloc` at rustc_src/src/alloc.rs:LL:CC + = note: inside `::deallocate` at rustc_src/src/alloc.rs:LL:CC + = note: inside `alloc::alloc::box_free::` at rustc_src/src/alloc.rs:LL:CC + = note: inside `std::ptr::drop_in_place::> - shim(Some(std::boxed::Box))` at rustc_src/src/ptr/mod.rs:LL:CC + = note: inside `std::mem::drop::>` at rustc_src/src/mem/mod.rs:LL:CC +note: inside `main` at $DIR/stack_free.rs:LL:CC + --> $DIR/stack_free.rs:LL:CC + | +LL | drop(bad_box); + | ^^^^^^^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/backtrace/bad-backtrace-decl.stderr b/tests/compile-fail/backtrace/bad-backtrace-decl.stderr new file mode 100644 index 0000000000000..007ef96f72a95 --- /dev/null +++ b/tests/compile-fail/backtrace/bad-backtrace-decl.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: bad declaration of miri_resolve_frame - should return a struct with 5 fields + --> $DIR/bad-backtrace-decl.rs:LL:CC + | +LL | ... miri_resolve_frame(*frame, 0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ bad declaration of miri_resolve_frame - should return a struct with 5 fields + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/bad-backtrace-decl.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/backtrace/bad-backtrace-flags.stderr b/tests/compile-fail/backtrace/bad-backtrace-flags.stderr new file mode 100644 index 0000000000000..f6ffe3c93c891 --- /dev/null +++ b/tests/compile-fail/backtrace/bad-backtrace-flags.stderr @@ -0,0 +1,14 @@ +error: unsupported operation: unknown `miri_get_backtrace` flags 2 + --> $DIR/bad-backtrace-flags.rs:LL:CC + | +LL | miri_get_backtrace(2, 0 as *mut _); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unknown `miri_get_backtrace` flags 2 + | + = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support + + = note: inside `main` at $DIR/bad-backtrace-flags.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/backtrace/bad-backtrace-ptr.stderr b/tests/compile-fail/backtrace/bad-backtrace-ptr.stderr new file mode 100644 index 0000000000000..ed726a5dcdc22 --- /dev/null +++ b/tests/compile-fail/backtrace/bad-backtrace-ptr.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: null pointer is not a valid pointer for this operation + --> $DIR/bad-backtrace-ptr.rs:LL:CC + | +LL | miri_resolve_frame(0 as *mut _, 0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ null pointer is not a valid pointer for this operation + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/bad-backtrace-ptr.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/backtrace/bad-backtrace-resolve-flags.stderr b/tests/compile-fail/backtrace/bad-backtrace-resolve-flags.stderr new file mode 100644 index 0000000000000..49495651dfec4 --- /dev/null +++ b/tests/compile-fail/backtrace/bad-backtrace-resolve-flags.stderr @@ -0,0 +1,14 @@ +error: unsupported operation: unknown `miri_resolve_frame` flags 2 + --> $DIR/bad-backtrace-resolve-flags.rs:LL:CC + | +LL | miri_resolve_frame(buf[0], 2); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unknown `miri_resolve_frame` flags 2 + | + = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support + + = note: inside `main` at $DIR/bad-backtrace-resolve-flags.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/backtrace/bad-backtrace-resolve-names-flags.stderr b/tests/compile-fail/backtrace/bad-backtrace-resolve-names-flags.stderr new file mode 100644 index 0000000000000..d575caa4ff4ed --- /dev/null +++ b/tests/compile-fail/backtrace/bad-backtrace-resolve-names-flags.stderr @@ -0,0 +1,14 @@ +error: unsupported operation: unknown `miri_resolve_frame_names` flags 2 + --> $DIR/bad-backtrace-resolve-names-flags.rs:LL:CC + | +LL | ... miri_resolve_frame_names(buf[0], 2, 0 as *mut _, 0 as *mut _); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unknown `miri_resolve_frame_names` flags 2 + | + = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support + + = note: inside `main` at $DIR/bad-backtrace-resolve-names-flags.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/backtrace/bad-backtrace-size-flags.stderr b/tests/compile-fail/backtrace/bad-backtrace-size-flags.stderr new file mode 100644 index 0000000000000..09f22b74b9c34 --- /dev/null +++ b/tests/compile-fail/backtrace/bad-backtrace-size-flags.stderr @@ -0,0 +1,14 @@ +error: unsupported operation: unknown `miri_backtrace_size` flags 2 + --> $DIR/bad-backtrace-size-flags.rs:LL:CC + | +LL | miri_backtrace_size(2); + | ^^^^^^^^^^^^^^^^^^^^^^ unknown `miri_backtrace_size` flags 2 + | + = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support + + = note: inside `main` at $DIR/bad-backtrace-size-flags.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/backtrace/bad-backtrace-version.stderr b/tests/compile-fail/backtrace/bad-backtrace-version.stderr new file mode 100644 index 0000000000000..4e7292732754b --- /dev/null +++ b/tests/compile-fail/backtrace/bad-backtrace-version.stderr @@ -0,0 +1,14 @@ +error: unsupported operation: unknown `miri_resolve_frame` flags 1 + --> $DIR/bad-backtrace-version.rs:7:9 + | +LL | miri_resolve_frame(0 as *mut _, 1); //~ ERROR unsupported operation: unknown `miri_resolve_frame` flags 1 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unknown `miri_resolve_frame` flags 1 + | + = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support + + = note: inside `main` at $DIR/bad-backtrace-version.rs:7:9 + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/box-cell-alias.stderr b/tests/compile-fail/box-cell-alias.stderr new file mode 100644 index 0000000000000..a4eaec93a8fb2 --- /dev/null +++ b/tests/compile-fail/box-cell-alias.stderr @@ -0,0 +1,32 @@ +error: Undefined Behavior: trying to reborrow for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + --> $DIR/box-cell-alias.rs:LL:CC + | +LL | unsafe { (*ptr).set(20); } + | ^^^^^^^^^^^^^^ + | | + | trying to reborrow for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | this error occurs as part of a reborrow at ALLOC[0x0..0x1] + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information +help: was created by a retag at offsets [0x0..0x1] + --> $DIR/box-cell-alias.rs:LL:CC + | +LL | let ptr: *const Cell = &*val; + | ^^^^^ +help: was later invalidated at offsets [0x0..0x1] + --> $DIR/box-cell-alias.rs:LL:CC + | +LL | let res = helper(val, ptr); + | ^^^ + = note: inside `helper` at $DIR/box-cell-alias.rs:LL:CC +note: inside `main` at $DIR/box-cell-alias.rs:LL:CC + --> $DIR/box-cell-alias.rs:LL:CC + | +LL | let res = helper(val, ptr); + | ^^^^^^^^^^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/branchless-select-i128-pointer.stderr b/tests/compile-fail/branchless-select-i128-pointer.stderr new file mode 100644 index 0000000000000..2e0f813983031 --- /dev/null +++ b/tests/compile-fail/branchless-select-i128-pointer.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: type validation failed: encountered (potentially part of) a pointer, but expected plain (non-pointer) bytes + --> $DIR/branchless-select-i128-pointer.rs:LL:CC + | +LL | !mask & transmute::<_, TwoPtrs>("false !") | mask & transmute::<_, TwoPtrs>("true !"), + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered (potentially part of) a pointer, but expected plain (non-pointer) bytes + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/branchless-select-i128-pointer.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/breakpoint.stderr b/tests/compile-fail/breakpoint.stderr new file mode 100644 index 0000000000000..7b9bbdb382895 --- /dev/null +++ b/tests/compile-fail/breakpoint.stderr @@ -0,0 +1,12 @@ +error: abnormal termination: Trace/breakpoint trap + --> $DIR/breakpoint.rs:LL:CC + | +LL | core::intrinsics::breakpoint() + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Trace/breakpoint trap + | + = note: inside `main` at $DIR/breakpoint.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/concurrency/libc_pthread_create_main_terminate.stderr b/tests/compile-fail/concurrency/libc_pthread_create_main_terminate.stderr new file mode 100644 index 0000000000000..0f7fbefe0af08 --- /dev/null +++ b/tests/compile-fail/concurrency/libc_pthread_create_main_terminate.stderr @@ -0,0 +1,8 @@ +warning: thread support is experimental and incomplete: weak memory effects are not emulated. + +error: the main thread terminated without waiting for all remaining threads + +note: pass `-Zmiri-ignore-leaks` to disable this check + +error: aborting due to previous error; 1 warning emitted + diff --git a/tests/compile-fail/concurrency/libc_pthread_join_detached.stderr b/tests/compile-fail/concurrency/libc_pthread_join_detached.stderr new file mode 100644 index 0000000000000..688f61a98b904 --- /dev/null +++ b/tests/compile-fail/concurrency/libc_pthread_join_detached.stderr @@ -0,0 +1,17 @@ +warning: thread support is experimental and incomplete: weak memory effects are not emulated. + +error: Undefined Behavior: trying to join a detached or already joined thread + --> $DIR/libc_pthread_join_detached.rs:LL:CC + | +LL | ... assert_eq!(libc::pthread_join(native, ptr::null_mut()), 0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trying to join a detached or already joined thread + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/libc_pthread_join_detached.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error; 1 warning emitted + diff --git a/tests/compile-fail/concurrency/libc_pthread_join_joined.stderr b/tests/compile-fail/concurrency/libc_pthread_join_joined.stderr new file mode 100644 index 0000000000000..518f72de5bef8 --- /dev/null +++ b/tests/compile-fail/concurrency/libc_pthread_join_joined.stderr @@ -0,0 +1,17 @@ +warning: thread support is experimental and incomplete: weak memory effects are not emulated. + +error: Undefined Behavior: trying to join a detached or already joined thread + --> $DIR/libc_pthread_join_joined.rs:LL:CC + | +LL | ... assert_eq!(libc::pthread_join(native, ptr::null_mut()), 0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trying to join a detached or already joined thread + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/libc_pthread_join_joined.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error; 1 warning emitted + diff --git a/tests/compile-fail/concurrency/libc_pthread_join_main.stderr b/tests/compile-fail/concurrency/libc_pthread_join_main.stderr new file mode 100644 index 0000000000000..5d9ec148e0797 --- /dev/null +++ b/tests/compile-fail/concurrency/libc_pthread_join_main.stderr @@ -0,0 +1,17 @@ +warning: thread support is experimental and incomplete: weak memory effects are not emulated. + +error: Undefined Behavior: trying to join a detached or already joined thread + --> $DIR/libc_pthread_join_main.rs:LL:CC + | +LL | ... assert_eq!(libc::pthread_join(thread_id, ptr::null_mut()), 0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trying to join a detached or already joined thread + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside closure at $DIR/libc_pthread_join_main.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error; 1 warning emitted + diff --git a/tests/compile-fail/concurrency/libc_pthread_join_multiple.stderr b/tests/compile-fail/concurrency/libc_pthread_join_multiple.stderr new file mode 100644 index 0000000000000..57126a14ae2ff --- /dev/null +++ b/tests/compile-fail/concurrency/libc_pthread_join_multiple.stderr @@ -0,0 +1,17 @@ +warning: thread support is experimental and incomplete: weak memory effects are not emulated. + +error: Undefined Behavior: trying to join a detached or already joined thread + --> $DIR/libc_pthread_join_multiple.rs:LL:CC + | +LL | ... assert_eq!(libc::pthread_join(native_copy, ptr::null_mut()), 0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trying to join a detached or already joined thread + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside closure at $DIR/libc_pthread_join_multiple.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error; 1 warning emitted + diff --git a/tests/compile-fail/concurrency/libc_pthread_join_self.stderr b/tests/compile-fail/concurrency/libc_pthread_join_self.stderr new file mode 100644 index 0000000000000..d638d089398ae --- /dev/null +++ b/tests/compile-fail/concurrency/libc_pthread_join_self.stderr @@ -0,0 +1,17 @@ +warning: thread support is experimental and incomplete: weak memory effects are not emulated. + +error: Undefined Behavior: trying to join itself + --> $DIR/libc_pthread_join_self.rs:LL:CC + | +LL | assert_eq!(libc::pthread_join(native, ptr::null_mut()), 0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trying to join itself + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside closure at $DIR/libc_pthread_join_self.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error; 1 warning emitted + diff --git a/tests/compile-fail/concurrency/thread-spawn.rs b/tests/compile-fail/concurrency/thread-spawn.rs index 6f07d083a0e51..948ce946d8948 100644 --- a/tests/compile-fail/concurrency/thread-spawn.rs +++ b/tests/compile-fail/concurrency/thread-spawn.rs @@ -1,5 +1,4 @@ -// ignore-linux: Only Windows is not supported. -// ignore-macos: Only Windows is not supported. +// only-windows: Only Windows is not supported. use std::thread; diff --git a/tests/compile-fail/concurrency/thread_local_static_dealloc.stderr b/tests/compile-fail/concurrency/thread_local_static_dealloc.stderr new file mode 100644 index 0000000000000..cdeb22fb31759 --- /dev/null +++ b/tests/compile-fail/concurrency/thread_local_static_dealloc.stderr @@ -0,0 +1,17 @@ +warning: thread support is experimental and incomplete: weak memory effects are not emulated. + +error: Undefined Behavior: pointer to ALLOC was dereferenced after this allocation got freed + --> $DIR/thread_local_static_dealloc.rs:LL:CC + | +LL | let _val = *(dangling_ptr as *const u8); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pointer to ALLOC was dereferenced after this allocation got freed + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/thread_local_static_dealloc.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error; 1 warning emitted + diff --git a/tests/compile-fail/concurrency/too_few_args.stderr b/tests/compile-fail/concurrency/too_few_args.stderr new file mode 100644 index 0000000000000..753b5e9ea7eb2 --- /dev/null +++ b/tests/compile-fail/concurrency/too_few_args.stderr @@ -0,0 +1,16 @@ +warning: thread support is experimental and incomplete: weak memory effects are not emulated. + +error: Undefined Behavior: callee has fewer arguments than expected + --> $DIR/too_few_args.rs:LL:CC + | +LL | panic!() + | ^^^^^^^^ callee has fewer arguments than expected + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `thread_start` at rustc_src/src/panic.rs:LL:CC + = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to previous error; 1 warning emitted + diff --git a/tests/compile-fail/concurrency/too_many_args.stderr b/tests/compile-fail/concurrency/too_many_args.stderr new file mode 100644 index 0000000000000..483b032a9b173 --- /dev/null +++ b/tests/compile-fail/concurrency/too_many_args.stderr @@ -0,0 +1,16 @@ +warning: thread support is experimental and incomplete: weak memory effects are not emulated. + +error: Undefined Behavior: callee has more arguments than expected + --> $DIR/too_many_args.rs:LL:CC + | +LL | panic!() + | ^^^^^^^^ callee has more arguments than expected + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `thread_start` at rustc_src/src/panic.rs:LL:CC + = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to previous error; 1 warning emitted + diff --git a/tests/compile-fail/concurrency/unwind_top_of_stack.stderr b/tests/compile-fail/concurrency/unwind_top_of_stack.stderr new file mode 100644 index 0000000000000..600b8443d2c79 --- /dev/null +++ b/tests/compile-fail/concurrency/unwind_top_of_stack.stderr @@ -0,0 +1,19 @@ +warning: thread support is experimental and incomplete: weak memory effects are not emulated. + +thread '' panicked at 'explicit panic', $DIR/unwind_top_of_stack.rs:LL:CC +note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace +error: Undefined Behavior: unwinding past the topmost frame of the stack + --> $DIR/unwind_top_of_stack.rs:LL:CC + | +LL | / extern "C-unwind" fn thread_start(_null: *mut libc::c_void) -> *mut libc::c_void { +LL | | panic!() +LL | | } + | |_^ unwinding past the topmost frame of the stack + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `thread_start` at $DIR/unwind_top_of_stack.rs:LL:CC + +error: aborting due to previous error; 1 warning emitted + diff --git a/tests/compile-fail/dangling_pointers/dangling_pointer_addr_of.stderr b/tests/compile-fail/dangling_pointers/dangling_pointer_addr_of.stderr new file mode 100644 index 0000000000000..6638be3758cfe --- /dev/null +++ b/tests/compile-fail/dangling_pointers/dangling_pointer_addr_of.stderr @@ -0,0 +1,16 @@ +error: Undefined Behavior: pointer to ALLOC was dereferenced after this allocation got freed + --> $DIR/dangling_pointer_addr_of.rs:LL:CC + | +LL | let x = unsafe { ptr::addr_of!(*p) }; + | ^^^^^^^^^^^^^^^^^ pointer to ALLOC was dereferenced after this allocation got freed + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at rustc_src/src/ptr/mod.rs:LL:CC + = note: this error originates in the macro `ptr::addr_of` (in Nightly builds, run with -Z macro-backtrace for more info) + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/dangling_pointers/dangling_pointer_deref.stderr b/tests/compile-fail/dangling_pointers/dangling_pointer_deref.stderr new file mode 100644 index 0000000000000..69e7af74857a2 --- /dev/null +++ b/tests/compile-fail/dangling_pointers/dangling_pointer_deref.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: pointer to ALLOC was dereferenced after this allocation got freed + --> $DIR/dangling_pointer_deref.rs:LL:CC + | +LL | let x = unsafe { *p }; + | ^^ pointer to ALLOC was dereferenced after this allocation got freed + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/dangling_pointer_deref.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/dangling_pointers/dangling_zst_deref.stderr b/tests/compile-fail/dangling_pointers/dangling_zst_deref.stderr new file mode 100644 index 0000000000000..658635433c7a8 --- /dev/null +++ b/tests/compile-fail/dangling_pointers/dangling_zst_deref.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: pointer to ALLOC was dereferenced after this allocation got freed + --> $DIR/dangling_zst_deref.rs:LL:CC + | +LL | let _x = unsafe { *p }; + | ^^ pointer to ALLOC was dereferenced after this allocation got freed + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/dangling_zst_deref.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/dangling_pointers/deref-invalid-ptr.rs b/tests/compile-fail/dangling_pointers/deref-invalid-ptr.rs index 87071d8b4591d..56830e97caa37 100644 --- a/tests/compile-fail/dangling_pointers/deref-invalid-ptr.rs +++ b/tests/compile-fail/dangling_pointers/deref-invalid-ptr.rs @@ -3,5 +3,5 @@ fn main() { let x = 16usize as *const u32; - let _y = unsafe { &*x as *const u32 }; //~ ERROR 0x10 is not a valid pointer + let _y = unsafe { &*x as *const u32 }; //~ ERROR is not a valid pointer } diff --git a/tests/compile-fail/dangling_pointers/deref-invalid-ptr.stderr b/tests/compile-fail/dangling_pointers/deref-invalid-ptr.stderr new file mode 100644 index 0000000000000..f4361d9fefa95 --- /dev/null +++ b/tests/compile-fail/dangling_pointers/deref-invalid-ptr.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: dereferencing pointer failed: 0x10 is not a valid pointer + --> $DIR/deref-invalid-ptr.rs:LL:CC + | +LL | let _y = unsafe { &*x as *const u32 }; + | ^^^ dereferencing pointer failed: 0x10 is not a valid pointer + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/deref-invalid-ptr.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/dangling_pointers/deref-partially-dangling.stderr b/tests/compile-fail/dangling_pointers/deref-partially-dangling.stderr new file mode 100644 index 0000000000000..dc51eae71a3a3 --- /dev/null +++ b/tests/compile-fail/dangling_pointers/deref-partially-dangling.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: dereferencing pointer failed: ALLOC has size 8, so pointer to 12 bytes starting at offset 0 is out-of-bounds + --> $DIR/deref-partially-dangling.rs:LL:CC + | +LL | let val = unsafe { (*xptr).1 }; + | ^^^^^^^^^ dereferencing pointer failed: ALLOC has size 8, so pointer to 12 bytes starting at offset 0 is out-of-bounds + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/deref-partially-dangling.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/dangling_pointers/dyn_size.stderr b/tests/compile-fail/dangling_pointers/dyn_size.stderr new file mode 100644 index 0000000000000..6048a3b4434d6 --- /dev/null +++ b/tests/compile-fail/dangling_pointers/dyn_size.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: dereferencing pointer failed: ALLOC has size 4, so pointer to 5 bytes starting at offset 0 is out-of-bounds + --> $DIR/dyn_size.rs:LL:CC + | +LL | let _ptr = unsafe { &*ptr }; + | ^^^^^ dereferencing pointer failed: ALLOC has size 4, so pointer to 5 bytes starting at offset 0 is out-of-bounds + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/dyn_size.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/dangling_pointers/maybe_null_pointer_deref_zst.stderr b/tests/compile-fail/dangling_pointers/maybe_null_pointer_deref_zst.stderr new file mode 100644 index 0000000000000..b4da315a55427 --- /dev/null +++ b/tests/compile-fail/dangling_pointers/maybe_null_pointer_deref_zst.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: dereferencing pointer failed: ALLOC has size 1, so pointer at offset -2048 is out-of-bounds + --> $DIR/maybe_null_pointer_deref_zst.rs:LL:CC + | +LL | let _x: () = unsafe { *ptr }; + | ^^^^ dereferencing pointer failed: ALLOC has size 1, so pointer at offset -2048 is out-of-bounds + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/maybe_null_pointer_deref_zst.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/dangling_pointers/maybe_null_pointer_write_zst.stderr b/tests/compile-fail/dangling_pointers/maybe_null_pointer_write_zst.stderr new file mode 100644 index 0000000000000..dc810424abc6c --- /dev/null +++ b/tests/compile-fail/dangling_pointers/maybe_null_pointer_write_zst.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: dereferencing pointer failed: ALLOC has size 1, so pointer at offset -2048 is out-of-bounds + --> $DIR/maybe_null_pointer_write_zst.rs:LL:CC + | +LL | unsafe { *ptr = zst_val; } + | ^^^^^^^^^^^^^^ dereferencing pointer failed: ALLOC has size 1, so pointer at offset -2048 is out-of-bounds + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/maybe_null_pointer_write_zst.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/dangling_pointers/null_pointer_deref.stderr b/tests/compile-fail/dangling_pointers/null_pointer_deref.stderr new file mode 100644 index 0000000000000..0930160023f1b --- /dev/null +++ b/tests/compile-fail/dangling_pointers/null_pointer_deref.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: dereferencing pointer failed: null pointer is not a valid pointer + --> $DIR/null_pointer_deref.rs:LL:CC + | +LL | let x: i32 = unsafe { *std::ptr::null() }; + | ^^^^^^^^^^^^^^^^^ dereferencing pointer failed: null pointer is not a valid pointer + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/null_pointer_deref.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/dangling_pointers/null_pointer_deref_zst.stderr b/tests/compile-fail/dangling_pointers/null_pointer_deref_zst.stderr new file mode 100644 index 0000000000000..25fea50b15af1 --- /dev/null +++ b/tests/compile-fail/dangling_pointers/null_pointer_deref_zst.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: dereferencing pointer failed: null pointer is not a valid pointer + --> $DIR/null_pointer_deref_zst.rs:LL:CC + | +LL | let x: () = unsafe { *std::ptr::null() }; + | ^^^^^^^^^^^^^^^^^ dereferencing pointer failed: null pointer is not a valid pointer + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/null_pointer_deref_zst.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/dangling_pointers/null_pointer_write.stderr b/tests/compile-fail/dangling_pointers/null_pointer_write.stderr new file mode 100644 index 0000000000000..5ac8cc7c20fdf --- /dev/null +++ b/tests/compile-fail/dangling_pointers/null_pointer_write.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: dereferencing pointer failed: null pointer is not a valid pointer + --> $DIR/null_pointer_write.rs:LL:CC + | +LL | unsafe { *std::ptr::null_mut() = 0i32 }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ dereferencing pointer failed: null pointer is not a valid pointer + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/null_pointer_write.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/dangling_pointers/null_pointer_write_zst.stderr b/tests/compile-fail/dangling_pointers/null_pointer_write_zst.stderr new file mode 100644 index 0000000000000..b40a9154f1826 --- /dev/null +++ b/tests/compile-fail/dangling_pointers/null_pointer_write_zst.stderr @@ -0,0 +1,17 @@ +error: Undefined Behavior: memory access failed: null pointer is not a valid pointer + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `std::ptr::write::<[u8; 0]>` at rustc_src/src/ptr/mod.rs:LL:CC + = note: inside `std::ptr::mut_ptr::::write` at rustc_src/src/ptr/mut_ptr.rs:LL:CC +note: inside `main` at $DIR/null_pointer_write_zst.rs:LL:CC + --> $DIR/null_pointer_write_zst.rs:LL:CC + | +LL | unsafe { std::ptr::null_mut::<[u8; 0]>().write(zst_val) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/dangling_pointers/out_of_bounds_read1.stderr b/tests/compile-fail/dangling_pointers/out_of_bounds_read1.stderr new file mode 100644 index 0000000000000..1982b07066b1c --- /dev/null +++ b/tests/compile-fail/dangling_pointers/out_of_bounds_read1.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: dereferencing pointer failed: ALLOC has size 2, so pointer to 1 byte starting at offset 5 is out-of-bounds + --> $DIR/out_of_bounds_read1.rs:LL:CC + | +LL | let x = unsafe { *v.as_ptr().wrapping_offset(5) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ dereferencing pointer failed: ALLOC has size 2, so pointer to 1 byte starting at offset 5 is out-of-bounds + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/out_of_bounds_read1.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/dangling_pointers/out_of_bounds_read2.stderr b/tests/compile-fail/dangling_pointers/out_of_bounds_read2.stderr new file mode 100644 index 0000000000000..b70ce44c48a08 --- /dev/null +++ b/tests/compile-fail/dangling_pointers/out_of_bounds_read2.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: dereferencing pointer failed: ALLOC has size 2, so pointer to 1 byte starting at offset 5 is out-of-bounds + --> $DIR/out_of_bounds_read2.rs:LL:CC + | +LL | let x = unsafe { *v.as_ptr().wrapping_offset(5) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ dereferencing pointer failed: ALLOC has size 2, so pointer to 1 byte starting at offset 5 is out-of-bounds + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/out_of_bounds_read2.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/dangling_pointers/stack_temporary.stderr b/tests/compile-fail/dangling_pointers/stack_temporary.stderr new file mode 100644 index 0000000000000..f4f84765be54b --- /dev/null +++ b/tests/compile-fail/dangling_pointers/stack_temporary.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: pointer to ALLOC was dereferenced after this allocation got freed + --> $DIR/stack_temporary.rs:LL:CC + | +LL | let val = *x; + | ^^ pointer to ALLOC was dereferenced after this allocation got freed + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/stack_temporary.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/dangling_pointers/storage_dead_dangling.stderr b/tests/compile-fail/dangling_pointers/storage_dead_dangling.stderr new file mode 100644 index 0000000000000..aed14105ad077 --- /dev/null +++ b/tests/compile-fail/dangling_pointers/storage_dead_dangling.stderr @@ -0,0 +1,20 @@ +error: Undefined Behavior: pointer to ALLOC was dereferenced after this allocation got freed + --> $DIR/storage_dead_dangling.rs:LL:CC + | +LL | unsafe { &mut *(LEAK as *mut i32) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^ pointer to ALLOC was dereferenced after this allocation got freed + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `evil` at $DIR/storage_dead_dangling.rs:LL:CC +note: inside `main` at $DIR/storage_dead_dangling.rs:LL:CC + --> $DIR/storage_dead_dangling.rs:LL:CC + | +LL | evil(); + | ^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/dangling_pointers/wild_pointer_deref.rs b/tests/compile-fail/dangling_pointers/wild_pointer_deref.rs index 2749ccfc0a021..eebaea48ba67d 100644 --- a/tests/compile-fail/dangling_pointers/wild_pointer_deref.rs +++ b/tests/compile-fail/dangling_pointers/wild_pointer_deref.rs @@ -1,5 +1,5 @@ fn main() { let p = 44 as *const i32; - let x = unsafe { *p }; //~ ERROR 0x2c is not a valid pointer + let x = unsafe { *p }; //~ ERROR is not a valid pointer panic!("this should never print: {}", x); } diff --git a/tests/compile-fail/dangling_pointers/wild_pointer_deref.stderr b/tests/compile-fail/dangling_pointers/wild_pointer_deref.stderr new file mode 100644 index 0000000000000..b20f310da083b --- /dev/null +++ b/tests/compile-fail/dangling_pointers/wild_pointer_deref.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: dereferencing pointer failed: 0x2c is not a valid pointer + --> $DIR/wild_pointer_deref.rs:LL:CC + | +LL | let x = unsafe { *p }; + | ^^ dereferencing pointer failed: 0x2c is not a valid pointer + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/wild_pointer_deref.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/data_race/alloc_read_race.stderr b/tests/compile-fail/data_race/alloc_read_race.stderr new file mode 100644 index 0000000000000..9d9006966b335 --- /dev/null +++ b/tests/compile-fail/data_race/alloc_read_race.stderr @@ -0,0 +1,17 @@ +warning: thread support is experimental and incomplete: weak memory effects are not emulated. + +error: Undefined Behavior: Data race detected between Read on Thread(id = 2) and Allocate on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) + --> $DIR/alloc_read_race.rs:LL:CC + | +LL | *pointer.load(Ordering::Relaxed) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Data race detected between Read on Thread(id = 2) and Allocate on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside closure at $DIR/alloc_read_race.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error; 1 warning emitted + diff --git a/tests/compile-fail/data_race/alloc_write_race.stderr b/tests/compile-fail/data_race/alloc_write_race.stderr new file mode 100644 index 0000000000000..318895cae6b06 --- /dev/null +++ b/tests/compile-fail/data_race/alloc_write_race.stderr @@ -0,0 +1,17 @@ +warning: thread support is experimental and incomplete: weak memory effects are not emulated. + +error: Undefined Behavior: Data race detected between Write on Thread(id = 2) and Allocate on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) + --> $DIR/alloc_write_race.rs:LL:CC + | +LL | *pointer.load(Ordering::Relaxed) = 2; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Data race detected between Write on Thread(id = 2) and Allocate on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside closure at $DIR/alloc_write_race.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error; 1 warning emitted + diff --git a/tests/compile-fail/data_race/atomic_read_na_write_race1.stderr b/tests/compile-fail/data_race/atomic_read_na_write_race1.stderr new file mode 100644 index 0000000000000..09d7accb05431 --- /dev/null +++ b/tests/compile-fail/data_race/atomic_read_na_write_race1.stderr @@ -0,0 +1,17 @@ +warning: thread support is experimental and incomplete: weak memory effects are not emulated. + +error: Undefined Behavior: Data race detected between Atomic Load on Thread(id = 2) and Write on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) + --> $DIR/atomic_read_na_write_race1.rs:LL:CC + | +LL | atomic_load(c.0 as *mut usize) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Data race detected between Atomic Load on Thread(id = 2) and Write on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside closure at $DIR/atomic_read_na_write_race1.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error; 1 warning emitted + diff --git a/tests/compile-fail/data_race/atomic_read_na_write_race2.stderr b/tests/compile-fail/data_race/atomic_read_na_write_race2.stderr new file mode 100644 index 0000000000000..739ce83d0b072 --- /dev/null +++ b/tests/compile-fail/data_race/atomic_read_na_write_race2.stderr @@ -0,0 +1,17 @@ +warning: thread support is experimental and incomplete: weak memory effects are not emulated. + +error: Undefined Behavior: Data race detected between Write on Thread(id = 2) and Atomic Load on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) + --> $DIR/atomic_read_na_write_race2.rs:LL:CC + | +LL | *atomic_ref.get_mut() = 32; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ Data race detected between Write on Thread(id = 2) and Atomic Load on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside closure at $DIR/atomic_read_na_write_race2.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error; 1 warning emitted + diff --git a/tests/compile-fail/data_race/atomic_write_na_read_race1.stderr b/tests/compile-fail/data_race/atomic_write_na_read_race1.stderr new file mode 100644 index 0000000000000..6d67f58aaee41 --- /dev/null +++ b/tests/compile-fail/data_race/atomic_write_na_read_race1.stderr @@ -0,0 +1,17 @@ +warning: thread support is experimental and incomplete: weak memory effects are not emulated. + +error: Undefined Behavior: Data race detected between Read on Thread(id = 2) and Atomic Store on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) + --> $DIR/atomic_write_na_read_race1.rs:LL:CC + | +LL | *atomic_ref.get_mut() + | ^^^^^^^^^^^^^^^^^^^^^ Data race detected between Read on Thread(id = 2) and Atomic Store on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside closure at $DIR/atomic_write_na_read_race1.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error; 1 warning emitted + diff --git a/tests/compile-fail/data_race/atomic_write_na_read_race2.stderr b/tests/compile-fail/data_race/atomic_write_na_read_race2.stderr new file mode 100644 index 0000000000000..d9950ebcb75ba --- /dev/null +++ b/tests/compile-fail/data_race/atomic_write_na_read_race2.stderr @@ -0,0 +1,17 @@ +warning: thread support is experimental and incomplete: weak memory effects are not emulated. + +error: Undefined Behavior: Data race detected between Atomic Store on Thread(id = 2) and Read on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) + --> $DIR/atomic_write_na_read_race2.rs:LL:CC + | +LL | atomic_store(c.0 as *mut usize, 32); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Data race detected between Atomic Store on Thread(id = 2) and Read on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside closure at $DIR/atomic_write_na_read_race2.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error; 1 warning emitted + diff --git a/tests/compile-fail/data_race/atomic_write_na_write_race1.stderr b/tests/compile-fail/data_race/atomic_write_na_write_race1.stderr new file mode 100644 index 0000000000000..29ccf7021253e --- /dev/null +++ b/tests/compile-fail/data_race/atomic_write_na_write_race1.stderr @@ -0,0 +1,17 @@ +warning: thread support is experimental and incomplete: weak memory effects are not emulated. + +error: Undefined Behavior: Data race detected between Atomic Store on Thread(id = 2) and Write on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) + --> $DIR/atomic_write_na_write_race1.rs:LL:CC + | +LL | atomic_store(c.0 as *mut usize, 64); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Data race detected between Atomic Store on Thread(id = 2) and Write on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside closure at $DIR/atomic_write_na_write_race1.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error; 1 warning emitted + diff --git a/tests/compile-fail/data_race/atomic_write_na_write_race2.stderr b/tests/compile-fail/data_race/atomic_write_na_write_race2.stderr new file mode 100644 index 0000000000000..5488f05de031e --- /dev/null +++ b/tests/compile-fail/data_race/atomic_write_na_write_race2.stderr @@ -0,0 +1,17 @@ +warning: thread support is experimental and incomplete: weak memory effects are not emulated. + +error: Undefined Behavior: Data race detected between Write on Thread(id = 2) and Atomic Store on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) + --> $DIR/atomic_write_na_write_race2.rs:LL:CC + | +LL | *atomic_ref.get_mut() = 32; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ Data race detected between Write on Thread(id = 2) and Atomic Store on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside closure at $DIR/atomic_write_na_write_race2.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error; 1 warning emitted + diff --git a/tests/compile-fail/data_race/dangling_thread_async_race.stderr b/tests/compile-fail/data_race/dangling_thread_async_race.stderr new file mode 100644 index 0000000000000..eccc243d696ef --- /dev/null +++ b/tests/compile-fail/data_race/dangling_thread_async_race.stderr @@ -0,0 +1,17 @@ +warning: thread support is experimental and incomplete: weak memory effects are not emulated. + +error: Undefined Behavior: Data race detected between Write on Thread(id = 3) and Write on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) + --> $DIR/dangling_thread_async_race.rs:LL:CC + | +LL | *c.0 = 64; + | ^^^^^^^^^ Data race detected between Write on Thread(id = 3) and Write on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside closure at $DIR/dangling_thread_async_race.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error; 1 warning emitted + diff --git a/tests/compile-fail/data_race/dangling_thread_race.stderr b/tests/compile-fail/data_race/dangling_thread_race.stderr new file mode 100644 index 0000000000000..4dffeb14233a1 --- /dev/null +++ b/tests/compile-fail/data_race/dangling_thread_race.stderr @@ -0,0 +1,17 @@ +warning: thread support is experimental and incomplete: weak memory effects are not emulated. + +error: Undefined Behavior: Data race detected between Write on Thread(id = 0, name = "main") and Write on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) + --> $DIR/dangling_thread_race.rs:LL:CC + | +LL | *c.0 = 64; + | ^^^^^^^^^ Data race detected between Write on Thread(id = 0, name = "main") and Write on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/dangling_thread_race.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error; 1 warning emitted + diff --git a/tests/compile-fail/data_race/dealloc_read_race1.stderr b/tests/compile-fail/data_race/dealloc_read_race1.stderr new file mode 100644 index 0000000000000..37196021ead93 --- /dev/null +++ b/tests/compile-fail/data_race/dealloc_read_race1.stderr @@ -0,0 +1,17 @@ +warning: thread support is experimental and incomplete: weak memory effects are not emulated. + +error: Undefined Behavior: Data race detected between Deallocate on Thread(id = 2) and Read on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) + --> $DIR/dealloc_read_race1.rs:LL:CC + | +LL | __rust_dealloc(ptr.0 as *mut _, std::mem::size_of::(), std::mem::align_of::()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Data race detected between Deallocate on Thread(id = 2) and Read on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside closure at $DIR/dealloc_read_race1.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error; 1 warning emitted + diff --git a/tests/compile-fail/data_race/dealloc_read_race2.stderr b/tests/compile-fail/data_race/dealloc_read_race2.stderr new file mode 100644 index 0000000000000..03fb5dbea90d5 --- /dev/null +++ b/tests/compile-fail/data_race/dealloc_read_race2.stderr @@ -0,0 +1,17 @@ +warning: thread support is experimental and incomplete: weak memory effects are not emulated. + +error: Undefined Behavior: pointer to ALLOC was dereferenced after this allocation got freed + --> $DIR/dealloc_read_race2.rs:LL:CC + | +LL | *ptr.0 + | ^^^^^^ pointer to ALLOC was dereferenced after this allocation got freed + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside closure at $DIR/dealloc_read_race2.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error; 1 warning emitted + diff --git a/tests/compile-fail/data_race/dealloc_read_race_stack.stderr b/tests/compile-fail/data_race/dealloc_read_race_stack.stderr new file mode 100644 index 0000000000000..055724fe29794 --- /dev/null +++ b/tests/compile-fail/data_race/dealloc_read_race_stack.stderr @@ -0,0 +1,17 @@ +warning: thread support is experimental and incomplete: weak memory effects are not emulated. + +error: Undefined Behavior: Data race detected between Deallocate on Thread(id = 1) and Read on Thread(id = 2) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) + --> $DIR/dealloc_read_race_stack.rs:LL:CC + | +LL | } + | ^ Data race detected between Deallocate on Thread(id = 1) and Read on Thread(id = 2) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside closure at $DIR/dealloc_read_race_stack.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error; 1 warning emitted + diff --git a/tests/compile-fail/data_race/dealloc_write_race1.stderr b/tests/compile-fail/data_race/dealloc_write_race1.stderr new file mode 100644 index 0000000000000..7160f49af697d --- /dev/null +++ b/tests/compile-fail/data_race/dealloc_write_race1.stderr @@ -0,0 +1,17 @@ +warning: thread support is experimental and incomplete: weak memory effects are not emulated. + +error: Undefined Behavior: Data race detected between Deallocate on Thread(id = 2) and Write on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) + --> $DIR/dealloc_write_race1.rs:LL:CC + | +LL | __rust_dealloc(ptr.0 as *mut _, std::mem::size_of::(), std::mem::align_of::()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Data race detected between Deallocate on Thread(id = 2) and Write on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside closure at $DIR/dealloc_write_race1.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error; 1 warning emitted + diff --git a/tests/compile-fail/data_race/dealloc_write_race2.stderr b/tests/compile-fail/data_race/dealloc_write_race2.stderr new file mode 100644 index 0000000000000..cb0d0af8672b3 --- /dev/null +++ b/tests/compile-fail/data_race/dealloc_write_race2.stderr @@ -0,0 +1,17 @@ +warning: thread support is experimental and incomplete: weak memory effects are not emulated. + +error: Undefined Behavior: pointer to ALLOC was dereferenced after this allocation got freed + --> $DIR/dealloc_write_race2.rs:LL:CC + | +LL | *ptr.0 = 2; + | ^^^^^^^^^^ pointer to ALLOC was dereferenced after this allocation got freed + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside closure at $DIR/dealloc_write_race2.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error; 1 warning emitted + diff --git a/tests/compile-fail/data_race/dealloc_write_race_stack.stderr b/tests/compile-fail/data_race/dealloc_write_race_stack.stderr new file mode 100644 index 0000000000000..05a8e1a8b7e21 --- /dev/null +++ b/tests/compile-fail/data_race/dealloc_write_race_stack.stderr @@ -0,0 +1,17 @@ +warning: thread support is experimental and incomplete: weak memory effects are not emulated. + +error: Undefined Behavior: Data race detected between Deallocate on Thread(id = 1) and Write on Thread(id = 2) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) + --> $DIR/dealloc_write_race_stack.rs:LL:CC + | +LL | } + | ^ Data race detected between Deallocate on Thread(id = 1) and Write on Thread(id = 2) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside closure at $DIR/dealloc_write_race_stack.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error; 1 warning emitted + diff --git a/tests/compile-fail/data_race/enable_after_join_to_main.stderr b/tests/compile-fail/data_race/enable_after_join_to_main.stderr new file mode 100644 index 0000000000000..e612e08ade4ff --- /dev/null +++ b/tests/compile-fail/data_race/enable_after_join_to_main.stderr @@ -0,0 +1,17 @@ +warning: thread support is experimental and incomplete: weak memory effects are not emulated. + +error: Undefined Behavior: Data race detected between Write on Thread(id = 6) and Write on Thread(id = 5) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) + --> $DIR/enable_after_join_to_main.rs:LL:CC + | +LL | *c.0 = 64; + | ^^^^^^^^^ Data race detected between Write on Thread(id = 6) and Write on Thread(id = 5) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside closure at $DIR/enable_after_join_to_main.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error; 1 warning emitted + diff --git a/tests/compile-fail/data_race/read_write_race.stderr b/tests/compile-fail/data_race/read_write_race.stderr new file mode 100644 index 0000000000000..fc04141830bff --- /dev/null +++ b/tests/compile-fail/data_race/read_write_race.stderr @@ -0,0 +1,17 @@ +warning: thread support is experimental and incomplete: weak memory effects are not emulated. + +error: Undefined Behavior: Data race detected between Write on Thread(id = 2) and Read on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) + --> $DIR/read_write_race.rs:LL:CC + | +LL | *c.0 = 64; + | ^^^^^^^^^ Data race detected between Write on Thread(id = 2) and Read on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside closure at $DIR/read_write_race.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error; 1 warning emitted + diff --git a/tests/compile-fail/data_race/read_write_race_stack.stderr b/tests/compile-fail/data_race/read_write_race_stack.stderr new file mode 100644 index 0000000000000..aad63731ca050 --- /dev/null +++ b/tests/compile-fail/data_race/read_write_race_stack.stderr @@ -0,0 +1,17 @@ +warning: thread support is experimental and incomplete: weak memory effects are not emulated. + +error: Undefined Behavior: Data race detected between Read on Thread(id = 1) and Write on Thread(id = 2) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) + --> $DIR/read_write_race_stack.rs:LL:CC + | +LL | stack_var + | ^^^^^^^^^ Data race detected between Read on Thread(id = 1) and Write on Thread(id = 2) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside closure at $DIR/read_write_race_stack.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error; 1 warning emitted + diff --git a/tests/compile-fail/data_race/relax_acquire_race.stderr b/tests/compile-fail/data_race/relax_acquire_race.stderr new file mode 100644 index 0000000000000..a437120c891d7 --- /dev/null +++ b/tests/compile-fail/data_race/relax_acquire_race.stderr @@ -0,0 +1,17 @@ +warning: thread support is experimental and incomplete: weak memory effects are not emulated. + +error: Undefined Behavior: Data race detected between Read on Thread(id = 3) and Write on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) + --> $DIR/relax_acquire_race.rs:LL:CC + | +LL | *c.0 + | ^^^^ Data race detected between Read on Thread(id = 3) and Write on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside closure at $DIR/relax_acquire_race.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error; 1 warning emitted + diff --git a/tests/compile-fail/data_race/release_seq_race.stderr b/tests/compile-fail/data_race/release_seq_race.stderr new file mode 100644 index 0000000000000..1a1c7ac64f78e --- /dev/null +++ b/tests/compile-fail/data_race/release_seq_race.stderr @@ -0,0 +1,17 @@ +warning: thread support is experimental and incomplete: weak memory effects are not emulated. + +error: Undefined Behavior: Data race detected between Read on Thread(id = 3) and Write on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) + --> $DIR/release_seq_race.rs:LL:CC + | +LL | *c.0 + | ^^^^ Data race detected between Read on Thread(id = 3) and Write on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside closure at $DIR/release_seq_race.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error; 1 warning emitted + diff --git a/tests/compile-fail/data_race/release_seq_race_same_thread.stderr b/tests/compile-fail/data_race/release_seq_race_same_thread.stderr new file mode 100644 index 0000000000000..f357c0647d4df --- /dev/null +++ b/tests/compile-fail/data_race/release_seq_race_same_thread.stderr @@ -0,0 +1,17 @@ +warning: thread support is experimental and incomplete: weak memory effects are not emulated. + +error: Undefined Behavior: Data race detected between Read on Thread(id = 2) and Write on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) + --> $DIR/release_seq_race_same_thread.rs:LL:CC + | +LL | *c.0 + | ^^^^ Data race detected between Read on Thread(id = 2) and Write on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside closure at $DIR/release_seq_race_same_thread.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error; 1 warning emitted + diff --git a/tests/compile-fail/data_race/rmw_race.stderr b/tests/compile-fail/data_race/rmw_race.stderr new file mode 100644 index 0000000000000..dd3692c6dcc87 --- /dev/null +++ b/tests/compile-fail/data_race/rmw_race.stderr @@ -0,0 +1,17 @@ +warning: thread support is experimental and incomplete: weak memory effects are not emulated. + +error: Undefined Behavior: Data race detected between Read on Thread(id = 3) and Write on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) + --> $DIR/rmw_race.rs:LL:CC + | +LL | *c.0 + | ^^^^ Data race detected between Read on Thread(id = 3) and Write on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside closure at $DIR/rmw_race.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error; 1 warning emitted + diff --git a/tests/compile-fail/data_race/write_write_race.stderr b/tests/compile-fail/data_race/write_write_race.stderr new file mode 100644 index 0000000000000..dafee7dbf8cf4 --- /dev/null +++ b/tests/compile-fail/data_race/write_write_race.stderr @@ -0,0 +1,17 @@ +warning: thread support is experimental and incomplete: weak memory effects are not emulated. + +error: Undefined Behavior: Data race detected between Write on Thread(id = 2) and Write on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) + --> $DIR/write_write_race.rs:LL:CC + | +LL | *c.0 = 64; + | ^^^^^^^^^ Data race detected between Write on Thread(id = 2) and Write on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside closure at $DIR/write_write_race.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error; 1 warning emitted + diff --git a/tests/compile-fail/data_race/write_write_race_stack.stderr b/tests/compile-fail/data_race/write_write_race_stack.stderr new file mode 100644 index 0000000000000..8d113673ac156 --- /dev/null +++ b/tests/compile-fail/data_race/write_write_race_stack.stderr @@ -0,0 +1,17 @@ +warning: thread support is experimental and incomplete: weak memory effects are not emulated. + +error: Undefined Behavior: Data race detected between Write on Thread(id = 1) and Write on Thread(id = 2) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) + --> $DIR/write_write_race_stack.rs:LL:CC + | +LL | stack_var = 1usize; + | ^^^^^^^^^^^^^^^^^^ Data race detected between Write on Thread(id = 1) and Write on Thread(id = 2) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside closure at $DIR/write_write_race_stack.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error; 1 warning emitted + diff --git a/tests/compile-fail/environ-gets-deallocated.stderr b/tests/compile-fail/environ-gets-deallocated.stderr new file mode 100644 index 0000000000000..640d953a811d2 --- /dev/null +++ b/tests/compile-fail/environ-gets-deallocated.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: pointer to ALLOC was dereferenced after this allocation got freed + --> $DIR/environ-gets-deallocated.rs:LL:CC + | +LL | let _y = unsafe { *pointer }; + | ^^^^^^^^ pointer to ALLOC was dereferenced after this allocation got freed + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/environ-gets-deallocated.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/erroneous_const.stderr b/tests/compile-fail/erroneous_const.stderr new file mode 100644 index 0000000000000..e1758ad657de7 --- /dev/null +++ b/tests/compile-fail/erroneous_const.stderr @@ -0,0 +1,26 @@ +error[E0080]: evaluation of `PrintName::::VOID` failed + --> $DIR/erroneous_const.rs:LL:CC + | +LL | const VOID: ! = panic!(); + | ^^^^^^^^ the evaluated program panicked at 'explicit panic', $DIR/erroneous_const.rs:LL:CC + | + = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: post-monomorphization error: encountered constants with type errors, stopping evaluation + --> $DIR/erroneous_const.rs:LL:CC + | +LL | let _ = PrintName::::VOID; + | ^^^^^^^^^^^^^^^^^^^^ encountered constants with type errors, stopping evaluation + | + = note: inside `no_codegen::` at $DIR/erroneous_const.rs:LL:CC +note: inside `main` at $DIR/erroneous_const.rs:LL:CC + --> $DIR/erroneous_const.rs:LL:CC + | +LL | no_codegen::(); + | ^^^^^^^^^^^^^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/compile-fail/erroneous_const2.stderr b/tests/compile-fail/erroneous_const2.stderr new file mode 100644 index 0000000000000..d5c89a8e82bf3 --- /dev/null +++ b/tests/compile-fail/erroneous_const2.stderr @@ -0,0 +1,41 @@ +error: any use of this value will cause an error + --> $DIR/erroneous_const2.rs:LL:CC + | +LL | const FOO: u32 = [X - Y, Y - X][(X < Y) as usize]; + | ------------------^^^^^--------------------------- + | | + | attempt to compute `5_u32 - 6_u32`, which would overflow + | + = note: `#[deny(const_err)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 + +error[E0080]: evaluation of constant value failed + --> $DIR/erroneous_const2.rs:LL:CC + | +LL | println!("{}", FOO); + | ^^^ referenced constant has errors + +error: erroneous constant used + --> $DIR/erroneous_const2.rs:LL:CC + | +LL | println!("{}", FOO); + | ^^^ referenced constant has errors + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #71800 + = note: this error originates in the macro `$crate::format_args_nl` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: post-monomorphization error: referenced constant has errors + --> $DIR/erroneous_const2.rs:LL:CC + | +LL | println!("{}", FOO); + | ^^^ referenced constant has errors + | + = note: inside `main` at $DIR/erroneous_const2.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0080`. diff --git a/tests/compile-fail/extern_static.stderr b/tests/compile-fail/extern_static.stderr new file mode 100644 index 0000000000000..e673d074bc84c --- /dev/null +++ b/tests/compile-fail/extern_static.stderr @@ -0,0 +1,14 @@ +error: unsupported operation: `extern` static `FOO` from crate `extern_static` is not supported by Miri + --> $DIR/extern_static.rs:LL:CC + | +LL | let _val = unsafe { std::ptr::addr_of!(FOO) }; + | ^^^ `extern` static `FOO` from crate `extern_static` is not supported by Miri + | + = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support + + = note: inside `main` at $DIR/extern_static.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/fast_math_both.stderr b/tests/compile-fail/fast_math_both.stderr new file mode 100644 index 0000000000000..542044df4d9cb --- /dev/null +++ b/tests/compile-fail/fast_math_both.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: `fsub_fast` intrinsic called with non-finite value as both parameters + --> $DIR/fast_math_both.rs:LL:CC + | +LL | ...: f32 = core::intrinsics::fsub_fast(f32::NAN, f32::NAN); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `fsub_fast` intrinsic called with non-finite value as both parameters + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/fast_math_both.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/fast_math_first.stderr b/tests/compile-fail/fast_math_first.stderr new file mode 100644 index 0000000000000..74ba08dc87878 --- /dev/null +++ b/tests/compile-fail/fast_math_first.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: `frem_fast` intrinsic called with non-finite value as first parameter + --> $DIR/fast_math_first.rs:LL:CC + | +LL | ... let _x: f32 = core::intrinsics::frem_fast(f32::NAN, 3.2); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `frem_fast` intrinsic called with non-finite value as first parameter + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/fast_math_first.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/fast_math_second.stderr b/tests/compile-fail/fast_math_second.stderr new file mode 100644 index 0000000000000..cbb059a07f682 --- /dev/null +++ b/tests/compile-fail/fast_math_second.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: `fmul_fast` intrinsic called with non-finite value as second parameter + --> $DIR/fast_math_second.rs:LL:CC + | +LL | ...f32 = core::intrinsics::fmul_fast(3.4f32, f32::INFINITY); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `fmul_fast` intrinsic called with non-finite value as second parameter + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/fast_math_second.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/fs/close_stdout.stderr b/tests/compile-fail/fs/close_stdout.stderr new file mode 100644 index 0000000000000..79fa0458b4bd5 --- /dev/null +++ b/tests/compile-fail/fs/close_stdout.stderr @@ -0,0 +1,14 @@ +error: unsupported operation: stdout cannot be closed + --> $DIR/close_stdout.rs:LL:CC + | +LL | libc::close(1); + | ^^^^^^^^^^^^^^ stdout cannot be closed + | + = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support + + = note: inside `main` at $DIR/close_stdout.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/fs/isolated_file.stderr b/tests/compile-fail/fs/isolated_file.stderr new file mode 100644 index 0000000000000..056a67259c1a7 --- /dev/null +++ b/tests/compile-fail/fs/isolated_file.stderr @@ -0,0 +1,22 @@ +error: unsupported operation: `open` not available when isolation is enabled + | + = help: pass the flag `-Zmiri-disable-isolation` to disable isolation; + = help: or pass `-Zmiri-isolation-error=warn` to configure Miri to return an error code from isolated operations (if supported for that operation) and continue with a warning + + = note: inside closure at rustc_src/src/sys/PLATFORM/fs.rs:LL:CC + = note: inside `std::sys::PLATFORM::cvt_r::` at rustc_src/src/sys/PLATFORM/mod.rs:LL:CC + = note: inside `std::sys::PLATFORM::fs::File::open_c` at rustc_src/src/sys/PLATFORM/fs.rs:LL:CC + = note: inside `std::sys::PLATFORM::fs::File::open` at rustc_src/src/sys/PLATFORM/fs.rs:LL:CC + = note: inside `std::fs::OpenOptions::_open` at rustc_src/src/fs.rs:LL:CC + = note: inside `std::fs::OpenOptions::open::<&std::path::Path>` at rustc_src/src/fs.rs:LL:CC + = note: inside `std::fs::File::open::<&str>` at rustc_src/src/fs.rs:LL:CC +note: inside `main` at $DIR/isolated_file.rs:LL:CC + --> $DIR/isolated_file.rs:LL:CC + | +LL | let _file = std::fs::File::open("file.txt").unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/fs/isolated_stdin.stderr b/tests/compile-fail/fs/isolated_stdin.stderr new file mode 100644 index 0000000000000..4fbd11e7cd9b1 --- /dev/null +++ b/tests/compile-fail/fs/isolated_stdin.stderr @@ -0,0 +1,15 @@ +error: unsupported operation: `read` from stdin not available when isolation is enabled + --> $DIR/isolated_stdin.rs:LL:CC + | +LL | libc::read(0, bytes.as_mut_ptr() as *mut libc::c_void, 512); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `read` from stdin not available when isolation is enabled + | + = help: pass the flag `-Zmiri-disable-isolation` to disable isolation; + = help: or pass `-Zmiri-isolation-error=warn` to configure Miri to return an error code from isolated operations (if supported for that operation) and continue with a warning + + = note: inside `main` at $DIR/isolated_stdin.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/fs/read_from_stdout.stderr b/tests/compile-fail/fs/read_from_stdout.stderr new file mode 100644 index 0000000000000..45573c471e2ad --- /dev/null +++ b/tests/compile-fail/fs/read_from_stdout.stderr @@ -0,0 +1,14 @@ +error: unsupported operation: cannot read from stdout + --> $DIR/read_from_stdout.rs:LL:CC + | +LL | libc::read(1, bytes.as_mut_ptr() as *mut libc::c_void, 512); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot read from stdout + | + = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support + + = note: inside `main` at $DIR/read_from_stdout.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/fs/unix_open_missing_required_mode.stderr b/tests/compile-fail/fs/unix_open_missing_required_mode.stderr new file mode 100644 index 0000000000000..7003234331242 --- /dev/null +++ b/tests/compile-fail/fs/unix_open_missing_required_mode.stderr @@ -0,0 +1,20 @@ +error: Undefined Behavior: incorrect number of arguments for `open` with `O_CREAT`: got 2, expected at least 3 + --> $DIR/unix_open_missing_required_mode.rs:LL:CC + | +LL | ...safe { libc::open(name_ptr, libc::O_CREAT) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ incorrect number of arguments for `open` with `O_CREAT`: got 2, expected at least 3 + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `test_file_open_missing_needed_mode` at $DIR/unix_open_missing_required_mode.rs:LL:CC +note: inside `main` at $DIR/unix_open_missing_required_mode.rs:LL:CC + --> $DIR/unix_open_missing_required_mode.rs:LL:CC + | +LL | test_file_open_missing_needed_mode(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/fs/unix_open_too_many_args.stderr b/tests/compile-fail/fs/unix_open_too_many_args.stderr new file mode 100644 index 0000000000000..f71a44d34daba --- /dev/null +++ b/tests/compile-fail/fs/unix_open_too_many_args.stderr @@ -0,0 +1,20 @@ +error: Undefined Behavior: incorrect number of arguments for `open`: got 4, expected 2 or 3 + --> $DIR/unix_open_too_many_args.rs:15:24 + | +LL | let _fd = unsafe { libc::open(name_ptr, libc::O_RDONLY, 0, 0) }; //~ ERROR Undefined Behavior: incorrect number of arguments for `ope... + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ incorrect number of arguments for `open`: got 4, expected 2 or 3 + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `test_open_too_many_args` at $DIR/unix_open_too_many_args.rs:15:24 +note: inside `main` at $DIR/unix_open_too_many_args.rs:9:5 + --> $DIR/unix_open_too_many_args.rs:9:5 + | +LL | test_open_too_many_args(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/fs/write_to_stdin.stderr b/tests/compile-fail/fs/write_to_stdin.stderr new file mode 100644 index 0000000000000..1cbc3eef66ae9 --- /dev/null +++ b/tests/compile-fail/fs/write_to_stdin.stderr @@ -0,0 +1,14 @@ +error: unsupported operation: cannot write to stdin + --> $DIR/write_to_stdin.rs:LL:CC + | +LL | libc::write(0, bytes.as_ptr() as *const libc::c_void, 5); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot write to stdin + | + = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support + + = note: inside `main` at $DIR/write_to_stdin.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/function_calls/check_arg_abi.stderr b/tests/compile-fail/function_calls/check_arg_abi.stderr new file mode 100644 index 0000000000000..9ee7d301b19ff --- /dev/null +++ b/tests/compile-fail/function_calls/check_arg_abi.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: calling a function with ABI C using caller ABI Rust + --> $DIR/check_arg_abi.rs:LL:CC + | +LL | let _ = malloc(0); + | ^^^^^^^^^ calling a function with ABI C using caller ABI Rust + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/check_arg_abi.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/function_calls/check_arg_count_abort.stderr b/tests/compile-fail/function_calls/check_arg_count_abort.stderr new file mode 100644 index 0000000000000..c7682578f99b8 --- /dev/null +++ b/tests/compile-fail/function_calls/check_arg_count_abort.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: incorrect number of arguments: got 1, expected 0 + --> $DIR/check_arg_count_abort.rs:LL:CC + | +LL | abort(1); + | ^^^^^^^^ incorrect number of arguments: got 1, expected 0 + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/check_arg_count_abort.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/function_calls/check_arg_count_too_few_args.stderr b/tests/compile-fail/function_calls/check_arg_count_too_few_args.stderr new file mode 100644 index 0000000000000..b7d6bbfd5719b --- /dev/null +++ b/tests/compile-fail/function_calls/check_arg_count_too_few_args.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: incorrect number of arguments: got 0, expected 1 + --> $DIR/check_arg_count_too_few_args.rs:LL:CC + | +LL | let _ = malloc(); + | ^^^^^^^^ incorrect number of arguments: got 0, expected 1 + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/check_arg_count_too_few_args.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/function_calls/check_arg_count_too_many_args.stderr b/tests/compile-fail/function_calls/check_arg_count_too_many_args.stderr new file mode 100644 index 0000000000000..33cc5750b890e --- /dev/null +++ b/tests/compile-fail/function_calls/check_arg_count_too_many_args.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: incorrect number of arguments: got 2, expected 1 + --> $DIR/check_arg_count_too_many_args.rs:LL:CC + | +LL | let _ = malloc(1, 2); + | ^^^^^^^^^^^^ incorrect number of arguments: got 2, expected 1 + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/check_arg_count_too_many_args.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/function_calls/check_callback_abi.stderr b/tests/compile-fail/function_calls/check_callback_abi.stderr new file mode 100644 index 0000000000000..ea7c2bb6b4ae4 --- /dev/null +++ b/tests/compile-fail/function_calls/check_callback_abi.stderr @@ -0,0 +1,19 @@ +error: Undefined Behavior: calling a function with ABI C using caller ABI Rust + --> $DIR/check_callback_abi.rs:LL:CC + | +LL | / std::intrinsics::r#try( +LL | | std::mem::transmute::(try_fn), +LL | | std::ptr::null_mut(), +LL | | |_, _| unreachable!(), +LL | | ); + | |_________^ calling a function with ABI C using caller ABI Rust + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/check_callback_abi.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/function_calls/exported_symbol_abi_mismatch.cache.stderr b/tests/compile-fail/function_calls/exported_symbol_abi_mismatch.cache.stderr new file mode 100644 index 0000000000000..bf0d27d91576a --- /dev/null +++ b/tests/compile-fail/function_calls/exported_symbol_abi_mismatch.cache.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: calling a function with calling convention Rust using calling convention C + --> $DIR/exported_symbol_abi_mismatch.rs:LL:CC + | +LL | unsafe { foo() } + | ^^^^^ calling a function with calling convention Rust using calling convention C + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/exported_symbol_abi_mismatch.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/function_calls/exported_symbol_abi_mismatch.fn_ptr.stderr b/tests/compile-fail/function_calls/exported_symbol_abi_mismatch.fn_ptr.stderr new file mode 100644 index 0000000000000..ee810af315fc0 --- /dev/null +++ b/tests/compile-fail/function_calls/exported_symbol_abi_mismatch.fn_ptr.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: calling a function with calling convention Rust using calling convention C + --> $DIR/exported_symbol_abi_mismatch.rs:LL:CC + | +LL | unsafe { std::mem::transmute::(foo)() } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ calling a function with calling convention Rust using calling convention C + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/exported_symbol_abi_mismatch.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/function_calls/exported_symbol_abi_mismatch.no_cache.stderr b/tests/compile-fail/function_calls/exported_symbol_abi_mismatch.no_cache.stderr new file mode 100644 index 0000000000000..bf0d27d91576a --- /dev/null +++ b/tests/compile-fail/function_calls/exported_symbol_abi_mismatch.no_cache.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: calling a function with calling convention Rust using calling convention C + --> $DIR/exported_symbol_abi_mismatch.rs:LL:CC + | +LL | unsafe { foo() } + | ^^^^^ calling a function with calling convention Rust using calling convention C + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/exported_symbol_abi_mismatch.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/function_calls/exported_symbol_bad_unwind1.stderr b/tests/compile-fail/function_calls/exported_symbol_bad_unwind1.stderr new file mode 100644 index 0000000000000..8cd74f1fd86df --- /dev/null +++ b/tests/compile-fail/function_calls/exported_symbol_bad_unwind1.stderr @@ -0,0 +1,17 @@ +thread 'main' panicked at 'explicit panic', $DIR/exported_symbol_bad_unwind1.rs:LL:CC +note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace +error: Undefined Behavior: unwinding past a stack frame that does not allow unwinding + --> $DIR/exported_symbol_bad_unwind1.rs:LL:CC + | +LL | unsafe { unwind() } + | ^^^^^^^^ unwinding past a stack frame that does not allow unwinding + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/exported_symbol_bad_unwind1.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/function_calls/exported_symbol_bad_unwind2.both.stderr b/tests/compile-fail/function_calls/exported_symbol_bad_unwind2.both.stderr new file mode 100644 index 0000000000000..48df075ba622b --- /dev/null +++ b/tests/compile-fail/function_calls/exported_symbol_bad_unwind2.both.stderr @@ -0,0 +1,23 @@ +thread 'main' panicked at 'explicit panic', $DIR/exported_symbol_bad_unwind2.rs:LL:CC +note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace +error: abnormal termination: the program aborted execution + --> $DIR/exported_symbol_bad_unwind2.rs:LL:CC + | +LL | / extern "C-unwind" fn nounwind() { +LL | | //[definition]~^ ERROR abnormal termination: the program aborted execution +LL | | //[both]~^^ ERROR abnormal termination: the program aborted execution +LL | | panic!(); +LL | | } + | |_^ the program aborted execution + | + = note: inside `nounwind` at $DIR/exported_symbol_bad_unwind2.rs:LL:CC +note: inside `main` at $DIR/exported_symbol_bad_unwind2.rs:LL:CC + --> $DIR/exported_symbol_bad_unwind2.rs:LL:CC + | +LL | unsafe { nounwind() } + | ^^^^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/function_calls/exported_symbol_bad_unwind2.definition.stderr b/tests/compile-fail/function_calls/exported_symbol_bad_unwind2.definition.stderr new file mode 100644 index 0000000000000..48df075ba622b --- /dev/null +++ b/tests/compile-fail/function_calls/exported_symbol_bad_unwind2.definition.stderr @@ -0,0 +1,23 @@ +thread 'main' panicked at 'explicit panic', $DIR/exported_symbol_bad_unwind2.rs:LL:CC +note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace +error: abnormal termination: the program aborted execution + --> $DIR/exported_symbol_bad_unwind2.rs:LL:CC + | +LL | / extern "C-unwind" fn nounwind() { +LL | | //[definition]~^ ERROR abnormal termination: the program aborted execution +LL | | //[both]~^^ ERROR abnormal termination: the program aborted execution +LL | | panic!(); +LL | | } + | |_^ the program aborted execution + | + = note: inside `nounwind` at $DIR/exported_symbol_bad_unwind2.rs:LL:CC +note: inside `main` at $DIR/exported_symbol_bad_unwind2.rs:LL:CC + --> $DIR/exported_symbol_bad_unwind2.rs:LL:CC + | +LL | unsafe { nounwind() } + | ^^^^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/function_calls/exported_symbol_bad_unwind2.extern_block.stderr b/tests/compile-fail/function_calls/exported_symbol_bad_unwind2.extern_block.stderr new file mode 100644 index 0000000000000..fac42bf66ae4b --- /dev/null +++ b/tests/compile-fail/function_calls/exported_symbol_bad_unwind2.extern_block.stderr @@ -0,0 +1,17 @@ +thread 'main' panicked at 'explicit panic', $DIR/exported_symbol_bad_unwind2.rs:LL:CC +note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace +error: Undefined Behavior: unwinding past a stack frame that does not allow unwinding + --> $DIR/exported_symbol_bad_unwind2.rs:LL:CC + | +LL | unsafe { nounwind() } + | ^^^^^^^^^^ unwinding past a stack frame that does not allow unwinding + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/exported_symbol_bad_unwind2.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/function_calls/exported_symbol_clashing.stderr b/tests/compile-fail/function_calls/exported_symbol_clashing.stderr new file mode 100644 index 0000000000000..1ddd882c4cb3b --- /dev/null +++ b/tests/compile-fail/function_calls/exported_symbol_clashing.stderr @@ -0,0 +1,22 @@ +error: multiple definitions of symbol `foo` + --> $DIR/exported_symbol_clashing.rs:LL:CC + | +LL | unsafe { foo() } + | ^^^^^ multiple definitions of symbol `foo` + | +help: it's first defined here, in crate `exported_symbol_clashing` + --> $DIR/exported_symbol_clashing.rs:LL:CC + | +LL | fn foo() {} + | ^^^^^^^^ +help: then it's defined here again, in crate `exported_symbol_clashing` + --> $DIR/exported_symbol_clashing.rs:LL:CC + | +LL | fn bar() {} + | ^^^^^^^^ + = note: inside `main` at $DIR/exported_symbol_clashing.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/function_calls/exported_symbol_shim_clashing.stderr b/tests/compile-fail/function_calls/exported_symbol_shim_clashing.stderr new file mode 100644 index 0000000000000..fa25b4e3f3472 --- /dev/null +++ b/tests/compile-fail/function_calls/exported_symbol_shim_clashing.stderr @@ -0,0 +1,20 @@ +error: found `malloc` symbol definition that clashes with a built-in shim + --> $DIR/exported_symbol_shim_clashing.rs:LL:CC + | +LL | malloc(0); + | ^^^^^^^^^ found `malloc` symbol definition that clashes with a built-in shim + | +help: the `malloc` symbol is defined here + --> $DIR/exported_symbol_shim_clashing.rs:LL:CC + | +LL | / extern "C" fn malloc(_: usize) -> *mut std::ffi::c_void { +LL | | +LL | | unreachable!() +LL | | } + | |_^ + = note: inside `main` at $DIR/exported_symbol_shim_clashing.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/function_calls/exported_symbol_wrong_arguments.stderr b/tests/compile-fail/function_calls/exported_symbol_wrong_arguments.stderr new file mode 100644 index 0000000000000..fe5498c85d7fb --- /dev/null +++ b/tests/compile-fail/function_calls/exported_symbol_wrong_arguments.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: calling a function with more arguments than it expected + --> $DIR/exported_symbol_wrong_arguments.rs:LL:CC + | +LL | unsafe { foo(1) } + | ^^^^^^ calling a function with more arguments than it expected + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/exported_symbol_wrong_arguments.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/function_calls/exported_symbol_wrong_type.stderr b/tests/compile-fail/function_calls/exported_symbol_wrong_type.stderr new file mode 100644 index 0000000000000..f402704908712 --- /dev/null +++ b/tests/compile-fail/function_calls/exported_symbol_wrong_type.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: attempt to call an exported symbol that is not defined as a function + --> $DIR/exported_symbol_wrong_type.rs:LL:CC + | +LL | unsafe { FOO() } + | ^^^^^ attempt to call an exported symbol that is not defined as a function + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/exported_symbol_wrong_type.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/function_pointers/cast_box_int_to_fn_ptr.stderr b/tests/compile-fail/function_pointers/cast_box_int_to_fn_ptr.stderr new file mode 100644 index 0000000000000..13f8ef3782439 --- /dev/null +++ b/tests/compile-fail/function_pointers/cast_box_int_to_fn_ptr.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: using ALLOC as function pointer but it does not point to a function + --> $DIR/cast_box_int_to_fn_ptr.rs:LL:CC + | +LL | (*g)(42) + | ^^^^^^^^ using ALLOC as function pointer but it does not point to a function + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/cast_box_int_to_fn_ptr.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/function_pointers/cast_fn_ptr1.stderr b/tests/compile-fail/function_pointers/cast_fn_ptr1.stderr new file mode 100644 index 0000000000000..765dbb6578ab1 --- /dev/null +++ b/tests/compile-fail/function_pointers/cast_fn_ptr1.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: calling a function with more arguments than it expected + --> $DIR/cast_fn_ptr1.rs:LL:CC + | +LL | g(42) + | ^^^^^ calling a function with more arguments than it expected + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/cast_fn_ptr1.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/function_pointers/cast_fn_ptr2.stderr b/tests/compile-fail/function_pointers/cast_fn_ptr2.stderr new file mode 100644 index 0000000000000..123d0e1b0bb6e --- /dev/null +++ b/tests/compile-fail/function_pointers/cast_fn_ptr2.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: calling a function with argument of type (i32, i32) passing data of type i32 + --> $DIR/cast_fn_ptr2.rs:LL:CC + | +LL | g(42) + | ^^^^^ calling a function with argument of type (i32, i32) passing data of type i32 + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/cast_fn_ptr2.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/function_pointers/cast_fn_ptr3.stderr b/tests/compile-fail/function_pointers/cast_fn_ptr3.stderr new file mode 100644 index 0000000000000..51f6ca0713d72 --- /dev/null +++ b/tests/compile-fail/function_pointers/cast_fn_ptr3.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: calling a function with fewer arguments than it requires + --> $DIR/cast_fn_ptr3.rs:LL:CC + | +LL | g() + | ^^^ calling a function with fewer arguments than it requires + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/cast_fn_ptr3.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/function_pointers/cast_fn_ptr4.stderr b/tests/compile-fail/function_pointers/cast_fn_ptr4.stderr new file mode 100644 index 0000000000000..515f00ec3929f --- /dev/null +++ b/tests/compile-fail/function_pointers/cast_fn_ptr4.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: calling a function with argument of type *const [i32] passing data of type *const i32 + --> $DIR/cast_fn_ptr4.rs:LL:CC + | +LL | g(&42 as *const i32) + | ^^^^^^^^^^^^^^^^^^^^ calling a function with argument of type *const [i32] passing data of type *const i32 + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/cast_fn_ptr4.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/function_pointers/cast_fn_ptr5.stderr b/tests/compile-fail/function_pointers/cast_fn_ptr5.stderr new file mode 100644 index 0000000000000..2978866c92905 --- /dev/null +++ b/tests/compile-fail/function_pointers/cast_fn_ptr5.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: calling a function with return type u32 passing return place of type () + --> $DIR/cast_fn_ptr5.rs:LL:CC + | +LL | g() + | ^^^ calling a function with return type u32 passing return place of type () + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/cast_fn_ptr5.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/function_pointers/cast_int_to_fn_ptr.rs b/tests/compile-fail/function_pointers/cast_int_to_fn_ptr.rs index 299fd5ae49e03..b206cb9ab3601 100644 --- a/tests/compile-fail/function_pointers/cast_int_to_fn_ptr.rs +++ b/tests/compile-fail/function_pointers/cast_int_to_fn_ptr.rs @@ -6,5 +6,5 @@ fn main() { std::mem::transmute::(42) }; - g(42) //~ ERROR 0x2a is not a valid pointer + g(42) //~ ERROR not a valid pointer } diff --git a/tests/compile-fail/function_pointers/cast_int_to_fn_ptr.stderr b/tests/compile-fail/function_pointers/cast_int_to_fn_ptr.stderr new file mode 100644 index 0000000000000..25501e74913d4 --- /dev/null +++ b/tests/compile-fail/function_pointers/cast_int_to_fn_ptr.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: 0x2a is not a valid pointer + --> $DIR/cast_int_to_fn_ptr.rs:LL:CC + | +LL | g(42) + | ^^^^^ 0x2a is not a valid pointer + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/cast_int_to_fn_ptr.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/function_pointers/deref_fn_ptr.stderr b/tests/compile-fail/function_pointers/deref_fn_ptr.stderr new file mode 100644 index 0000000000000..1e3da2726d4b8 --- /dev/null +++ b/tests/compile-fail/function_pointers/deref_fn_ptr.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: accessing ALLOC which contains a function + --> $DIR/deref_fn_ptr.rs:LL:CC + | +LL | *std::mem::transmute::(f) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ accessing ALLOC which contains a function + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/deref_fn_ptr.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/function_pointers/execute_memory.stderr b/tests/compile-fail/function_pointers/execute_memory.stderr new file mode 100644 index 0000000000000..daa6277b85e41 --- /dev/null +++ b/tests/compile-fail/function_pointers/execute_memory.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: using ALLOC as function pointer but it does not point to a function + --> $DIR/execute_memory.rs:LL:CC + | +LL | f() + | ^^^ using ALLOC as function pointer but it does not point to a function + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/execute_memory.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/function_pointers/fn_ptr_offset.stderr b/tests/compile-fail/function_pointers/fn_ptr_offset.stderr new file mode 100644 index 0000000000000..0f3baab1b512a --- /dev/null +++ b/tests/compile-fail/function_pointers/fn_ptr_offset.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: using ALLOC+0x1 as function pointer but it does not point to a function + --> $DIR/fn_ptr_offset.rs:LL:CC + | +LL | x(); + | ^^^ using ALLOC+0x1 as function pointer but it does not point to a function + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/fn_ptr_offset.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/generator-pinned-moved.stderr b/tests/compile-fail/generator-pinned-moved.stderr new file mode 100644 index 0000000000000..98ccf3097c298 --- /dev/null +++ b/tests/compile-fail/generator-pinned-moved.stderr @@ -0,0 +1,26 @@ +error: Undefined Behavior: pointer to ALLOC was dereferenced after this allocation got freed + --> $DIR/generator-pinned-moved.rs:LL:CC + | +LL | *num += 1; + | ^^^^^^^^^ pointer to ALLOC was dereferenced after this allocation got freed + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside closure at $DIR/generator-pinned-moved.rs:LL:CC +note: inside ` as std::iter::Iterator>::next` at $DIR/generator-pinned-moved.rs:LL:CC + --> $DIR/generator-pinned-moved.rs:LL:CC + | +LL | match me.resume(()) { + | ^^^^^^^^^^^^^ + = note: inside `> as std::iter::Iterator>::next` at rustc_src/src/boxed.rs:LL:CC +note: inside `main` at $DIR/generator-pinned-moved.rs:LL:CC + --> $DIR/generator-pinned-moved.rs:LL:CC + | +LL | generator_iterator_2.next(); // and use moved value + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/intrinsics/assume.stderr b/tests/compile-fail/intrinsics/assume.stderr new file mode 100644 index 0000000000000..e5059a699b103 --- /dev/null +++ b/tests/compile-fail/intrinsics/assume.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: `assume` intrinsic called with `false` + --> $DIR/assume.rs:LL:CC + | +LL | std::intrinsics::assume(x > 42); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `assume` intrinsic called with `false` + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/assume.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/intrinsics/copy_null.stderr b/tests/compile-fail/intrinsics/copy_null.stderr new file mode 100644 index 0000000000000..461f529fa85d5 --- /dev/null +++ b/tests/compile-fail/intrinsics/copy_null.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: memory access failed: null pointer is not a valid pointer + --> $DIR/copy_null.rs:LL:CC + | +LL | unsafe { copy_nonoverlapping(std::ptr::null(), ptr, 0); } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: null pointer is not a valid pointer + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/copy_null.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/intrinsics/copy_overflow.stderr b/tests/compile-fail/intrinsics/copy_overflow.stderr new file mode 100644 index 0000000000000..512184a36c18e --- /dev/null +++ b/tests/compile-fail/intrinsics/copy_overflow.stderr @@ -0,0 +1,17 @@ +error: Undefined Behavior: overflow computing total size of `copy` + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `std::intrinsics::copy::` at rustc_src/src/intrinsics.rs:LL:CC + = note: inside `std::ptr::mut_ptr::::copy_from` at rustc_src/src/ptr/mut_ptr.rs:LL:CC +note: inside `main` at $DIR/copy_overflow.rs:LL:CC + --> $DIR/copy_overflow.rs:LL:CC + | +LL | (&mut y as *mut i32).copy_from(&x, 1usize << (mem::size_of::() * 8 - 1)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/intrinsics/copy_overlapping.stderr b/tests/compile-fail/intrinsics/copy_overlapping.stderr new file mode 100644 index 0000000000000..cba08d9b5c823 --- /dev/null +++ b/tests/compile-fail/intrinsics/copy_overlapping.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: copy_nonoverlapping called on overlapping ranges + --> $DIR/copy_overlapping.rs:LL:CC + | +LL | copy_nonoverlapping(a, b, 2); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ copy_nonoverlapping called on overlapping ranges + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/copy_overlapping.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/intrinsics/copy_unaligned.rs b/tests/compile-fail/intrinsics/copy_unaligned.rs index 84f4de93461e7..7aff0adc407a2 100644 --- a/tests/compile-fail/intrinsics/copy_unaligned.rs +++ b/tests/compile-fail/intrinsics/copy_unaligned.rs @@ -9,5 +9,5 @@ fn main() { let mut data = [0u16; 8]; let ptr = (&mut data[0] as *mut u16 as *mut u8).wrapping_add(1) as *mut u16; // Even copying 0 elements to something unaligned should error - unsafe { copy_nonoverlapping(&data[5], ptr, 0); } //~ ERROR accessing memory with alignment 1, but alignment 2 is required + unsafe { copy_nonoverlapping(&data[5], ptr, 0); } //~ ERROR accessing memory with alignment ALIGN, but alignment ALIGN is required } diff --git a/tests/compile-fail/intrinsics/copy_unaligned.stderr b/tests/compile-fail/intrinsics/copy_unaligned.stderr new file mode 100644 index 0000000000000..b99588698d22d --- /dev/null +++ b/tests/compile-fail/intrinsics/copy_unaligned.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: accessing memory with alignment ALIGN, but alignment ALIGN is required + --> $DIR/copy_unaligned.rs:LL:CC + | +LL | unsafe { copy_nonoverlapping(&data[5], ptr, 0); } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ accessing memory with alignment ALIGN, but alignment ALIGN is required + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/copy_unaligned.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/intrinsics/ctlz_nonzero.stderr b/tests/compile-fail/intrinsics/ctlz_nonzero.stderr new file mode 100644 index 0000000000000..0c895cf138e95 --- /dev/null +++ b/tests/compile-fail/intrinsics/ctlz_nonzero.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: `ctlz_nonzero` called on 0 + --> $DIR/ctlz_nonzero.rs:LL:CC + | +LL | ctlz_nonzero(0u8); + | ^^^^^^^^^^^^^^^^^ `ctlz_nonzero` called on 0 + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/ctlz_nonzero.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/intrinsics/cttz_nonzero.stderr b/tests/compile-fail/intrinsics/cttz_nonzero.stderr new file mode 100644 index 0000000000000..5257668d53e9d --- /dev/null +++ b/tests/compile-fail/intrinsics/cttz_nonzero.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: `cttz_nonzero` called on 0 + --> $DIR/cttz_nonzero.rs:LL:CC + | +LL | cttz_nonzero(0u8); + | ^^^^^^^^^^^^^^^^^ `cttz_nonzero` called on 0 + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/cttz_nonzero.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/intrinsics/div-by-zero.stderr b/tests/compile-fail/intrinsics/div-by-zero.stderr new file mode 100644 index 0000000000000..388f4aef7fa96 --- /dev/null +++ b/tests/compile-fail/intrinsics/div-by-zero.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: dividing by zero + --> $DIR/div-by-zero.rs:LL:CC + | +LL | let _n = unchecked_div(1i64, 0); + | ^^^^^^^^^^^^^^^^^^^^^^ dividing by zero + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/div-by-zero.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/intrinsics/exact_div1.stderr b/tests/compile-fail/intrinsics/exact_div1.stderr new file mode 100644 index 0000000000000..a0f03b201a8de --- /dev/null +++ b/tests/compile-fail/intrinsics/exact_div1.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: calculating the remainder with a divisor of zero + --> $DIR/exact_div1.rs:LL:CC + | +LL | unsafe { std::intrinsics::exact_div(2, 0); } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ calculating the remainder with a divisor of zero + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/exact_div1.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/intrinsics/exact_div2.stderr b/tests/compile-fail/intrinsics/exact_div2.stderr new file mode 100644 index 0000000000000..78a85c9caac6b --- /dev/null +++ b/tests/compile-fail/intrinsics/exact_div2.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: exact_div: 2_u16 cannot be divided by 3_u16 without remainder + --> $DIR/exact_div2.rs:LL:CC + | +LL | unsafe { std::intrinsics::exact_div(2u16, 3); } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ exact_div: 2_u16 cannot be divided by 3_u16 without remainder + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/exact_div2.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/intrinsics/exact_div3.stderr b/tests/compile-fail/intrinsics/exact_div3.stderr new file mode 100644 index 0000000000000..3062b60d468e9 --- /dev/null +++ b/tests/compile-fail/intrinsics/exact_div3.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: exact_div: -19_i8 cannot be divided by 2_i8 without remainder + --> $DIR/exact_div3.rs:LL:CC + | +LL | unsafe { std::intrinsics::exact_div(-19i8, 2); } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ exact_div: -19_i8 cannot be divided by 2_i8 without remainder + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/exact_div3.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/intrinsics/exact_div4.stderr b/tests/compile-fail/intrinsics/exact_div4.stderr new file mode 100644 index 0000000000000..1ae67ad87a5da --- /dev/null +++ b/tests/compile-fail/intrinsics/exact_div4.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: overflow in signed remainder (dividing MIN by -1) + --> $DIR/exact_div4.rs:LL:CC + | +LL | unsafe { std::intrinsics::exact_div(i64::MIN, -1); } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflow in signed remainder (dividing MIN by -1) + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/exact_div4.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/intrinsics/float_to_int_32_inf1.stderr b/tests/compile-fail/intrinsics/float_to_int_32_inf1.stderr new file mode 100644 index 0000000000000..cdf232d93eb21 --- /dev/null +++ b/tests/compile-fail/intrinsics/float_to_int_32_inf1.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on +Inf which cannot be represented in target type `i32` + --> $DIR/float_to_int_32_inf1.rs:LL:CC + | +LL | unsafe { float_to_int_unchecked::(f32::INFINITY); } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on +Inf which cannot be represented in target type `i32` + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/float_to_int_32_inf1.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/intrinsics/float_to_int_32_infneg1.stderr b/tests/compile-fail/intrinsics/float_to_int_32_infneg1.stderr new file mode 100644 index 0000000000000..ae7301193682b --- /dev/null +++ b/tests/compile-fail/intrinsics/float_to_int_32_infneg1.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on -Inf which cannot be represented in target type `i32` + --> $DIR/float_to_int_32_infneg1.rs:LL:CC + | +LL | unsafe { float_to_int_unchecked::(f32::NEG_INFINITY); } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on -Inf which cannot be represented in target type `i32` + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/float_to_int_32_infneg1.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/intrinsics/float_to_int_32_nan.stderr b/tests/compile-fail/intrinsics/float_to_int_32_nan.stderr new file mode 100644 index 0000000000000..9c20abef78df9 --- /dev/null +++ b/tests/compile-fail/intrinsics/float_to_int_32_nan.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on NaN which cannot be represented in target type `u32` + --> $DIR/float_to_int_32_nan.rs:LL:CC + | +LL | unsafe { float_to_int_unchecked::(f32::NAN); } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on NaN which cannot be represented in target type `u32` + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/float_to_int_32_nan.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/intrinsics/float_to_int_32_nanneg.stderr b/tests/compile-fail/intrinsics/float_to_int_32_nanneg.stderr new file mode 100644 index 0000000000000..f5675fd654dda --- /dev/null +++ b/tests/compile-fail/intrinsics/float_to_int_32_nanneg.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on NaN which cannot be represented in target type `u32` + --> $DIR/float_to_int_32_nanneg.rs:LL:CC + | +LL | unsafe { float_to_int_unchecked::(-f32::NAN); } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on NaN which cannot be represented in target type `u32` + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/float_to_int_32_nanneg.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/intrinsics/float_to_int_32_neg.stderr b/tests/compile-fail/intrinsics/float_to_int_32_neg.stderr new file mode 100644 index 0000000000000..3b7c755af6544 --- /dev/null +++ b/tests/compile-fail/intrinsics/float_to_int_32_neg.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on -1 which cannot be represented in target type `u32` + --> $DIR/float_to_int_32_neg.rs:LL:CC + | +LL | unsafe { float_to_int_unchecked::(-1.000000001f32); } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on -1 which cannot be represented in target type `u32` + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/float_to_int_32_neg.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/intrinsics/float_to_int_32_too_big1.stderr b/tests/compile-fail/intrinsics/float_to_int_32_too_big1.stderr new file mode 100644 index 0000000000000..abfda9eef0af4 --- /dev/null +++ b/tests/compile-fail/intrinsics/float_to_int_32_too_big1.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on 2.14748365E+9 which cannot be represented in target type `i32` + --> $DIR/float_to_int_32_too_big1.rs:LL:CC + | +LL | unsafe { float_to_int_unchecked::(2147483648.0f32); } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on 2.14748365E+9 which cannot be represented in target type `i32` + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/float_to_int_32_too_big1.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/intrinsics/float_to_int_32_too_big2.stderr b/tests/compile-fail/intrinsics/float_to_int_32_too_big2.stderr new file mode 100644 index 0000000000000..2680d0c9908c9 --- /dev/null +++ b/tests/compile-fail/intrinsics/float_to_int_32_too_big2.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on 4.2949673E+9 which cannot be represented in target type `u32` + --> $DIR/float_to_int_32_too_big2.rs:LL:CC + | +LL | unsafe { float_to_int_unchecked::((u32::MAX-127) as f32); } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on 4.2949673E+9 which cannot be represented in target type `u32` + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/float_to_int_32_too_big2.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/intrinsics/float_to_int_32_too_small1.stderr b/tests/compile-fail/intrinsics/float_to_int_32_too_small1.stderr new file mode 100644 index 0000000000000..b03bd380df47c --- /dev/null +++ b/tests/compile-fail/intrinsics/float_to_int_32_too_small1.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on -2.1474839E+9 which cannot be represented in target type `i32` + --> $DIR/float_to_int_32_too_small1.rs:LL:CC + | +LL | unsafe { float_to_int_unchecked::(-2147483904.0f32); } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on -2.1474839E+9 which cannot be represented in target type `i32` + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/float_to_int_32_too_small1.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/intrinsics/float_to_int_64_inf1.stderr b/tests/compile-fail/intrinsics/float_to_int_64_inf1.stderr new file mode 100644 index 0000000000000..7509844cfd41b --- /dev/null +++ b/tests/compile-fail/intrinsics/float_to_int_64_inf1.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on +Inf which cannot be represented in target type `u128` + --> $DIR/float_to_int_64_inf1.rs:LL:CC + | +LL | unsafe { float_to_int_unchecked::(f64::INFINITY); } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on +Inf which cannot be represented in target type `u128` + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/float_to_int_64_inf1.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/intrinsics/float_to_int_64_infneg1.stderr b/tests/compile-fail/intrinsics/float_to_int_64_infneg1.stderr new file mode 100644 index 0000000000000..539cd52d83d0e --- /dev/null +++ b/tests/compile-fail/intrinsics/float_to_int_64_infneg1.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on -Inf which cannot be represented in target type `u128` + --> $DIR/float_to_int_64_infneg1.rs:LL:CC + | +LL | unsafe { float_to_int_unchecked::(f64::NEG_INFINITY); } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on -Inf which cannot be represented in target type `u128` + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/float_to_int_64_infneg1.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/intrinsics/float_to_int_64_infneg2.stderr b/tests/compile-fail/intrinsics/float_to_int_64_infneg2.stderr new file mode 100644 index 0000000000000..ceb18c3f4121c --- /dev/null +++ b/tests/compile-fail/intrinsics/float_to_int_64_infneg2.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on -Inf which cannot be represented in target type `i128` + --> $DIR/float_to_int_64_infneg2.rs:LL:CC + | +LL | unsafe { float_to_int_unchecked::(f64::NEG_INFINITY); } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on -Inf which cannot be represented in target type `i128` + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/float_to_int_64_infneg2.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/intrinsics/float_to_int_64_nan.stderr b/tests/compile-fail/intrinsics/float_to_int_64_nan.stderr new file mode 100644 index 0000000000000..eee8d2fac0b31 --- /dev/null +++ b/tests/compile-fail/intrinsics/float_to_int_64_nan.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on NaN which cannot be represented in target type `u32` + --> $DIR/float_to_int_64_nan.rs:LL:CC + | +LL | unsafe { float_to_int_unchecked::(f64::NAN); } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on NaN which cannot be represented in target type `u32` + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/float_to_int_64_nan.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/intrinsics/float_to_int_64_neg.stderr b/tests/compile-fail/intrinsics/float_to_int_64_neg.stderr new file mode 100644 index 0000000000000..384c0232465a8 --- /dev/null +++ b/tests/compile-fail/intrinsics/float_to_int_64_neg.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on -1 which cannot be represented in target type `u128` + --> $DIR/float_to_int_64_neg.rs:LL:CC + | +LL | unsafe { float_to_int_unchecked::(-1.0000000000001f64); } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on -1 which cannot be represented in target type `u128` + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/float_to_int_64_neg.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/intrinsics/float_to_int_64_too_big1.stderr b/tests/compile-fail/intrinsics/float_to_int_64_too_big1.stderr new file mode 100644 index 0000000000000..bb5b10a2710f8 --- /dev/null +++ b/tests/compile-fail/intrinsics/float_to_int_64_too_big1.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on 2147483648 which cannot be represented in target type `i32` + --> $DIR/float_to_int_64_too_big1.rs:LL:CC + | +LL | unsafe { float_to_int_unchecked::(2147483648.0f64); } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on 2147483648 which cannot be represented in target type `i32` + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/float_to_int_64_too_big1.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/intrinsics/float_to_int_64_too_big2.stderr b/tests/compile-fail/intrinsics/float_to_int_64_too_big2.stderr new file mode 100644 index 0000000000000..a4d57c2f5ceeb --- /dev/null +++ b/tests/compile-fail/intrinsics/float_to_int_64_too_big2.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on 9.2233720368547758E+18 which cannot be represented in target type `i64` + --> $DIR/float_to_int_64_too_big2.rs:LL:CC + | +LL | unsafe { float_to_int_unchecked::(9223372036854775808.0f64); } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on 9.2233720368547758E+18 which cannot be represented in target type `i64` + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/float_to_int_64_too_big2.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/intrinsics/float_to_int_64_too_big3.stderr b/tests/compile-fail/intrinsics/float_to_int_64_too_big3.stderr new file mode 100644 index 0000000000000..2b7379fcbd387 --- /dev/null +++ b/tests/compile-fail/intrinsics/float_to_int_64_too_big3.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on 1.8446744073709552E+19 which cannot be represented in target type `u64` + --> $DIR/float_to_int_64_too_big3.rs:LL:CC + | +LL | unsafe { float_to_int_unchecked::(18446744073709551616.0f64); } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on 1.8446744073709552E+19 which cannot be represented in target type `u64` + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/float_to_int_64_too_big3.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/intrinsics/float_to_int_64_too_big4.stderr b/tests/compile-fail/intrinsics/float_to_int_64_too_big4.stderr new file mode 100644 index 0000000000000..d30817607b9f0 --- /dev/null +++ b/tests/compile-fail/intrinsics/float_to_int_64_too_big4.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on 3.4028236692093846E+38 which cannot be represented in target type `u128` + --> $DIR/float_to_int_64_too_big4.rs:LL:CC + | +LL | unsafe { float_to_int_unchecked::(u128::MAX as f64); } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on 3.4028236692093846E+38 which cannot be represented in target type `u128` + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/float_to_int_64_too_big4.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/intrinsics/float_to_int_64_too_big5.stderr b/tests/compile-fail/intrinsics/float_to_int_64_too_big5.stderr new file mode 100644 index 0000000000000..f6b0c0a3527f5 --- /dev/null +++ b/tests/compile-fail/intrinsics/float_to_int_64_too_big5.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on 2.4028236692093845E+38 which cannot be represented in target type `i128` + --> $DIR/float_to_int_64_too_big5.rs:LL:CC + | +LL | unsafe { float_to_int_unchecked::(240282366920938463463374607431768211455.0f64); } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on 2.4028236692093845E+38 which cannot be represented in target type `i128` + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/float_to_int_64_too_big5.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/intrinsics/float_to_int_64_too_big6.stderr b/tests/compile-fail/intrinsics/float_to_int_64_too_big6.stderr new file mode 100644 index 0000000000000..e0eab8148b07c --- /dev/null +++ b/tests/compile-fail/intrinsics/float_to_int_64_too_big6.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on 1.7976931348623157E+308 which cannot be represented in target type `u128` + --> $DIR/float_to_int_64_too_big6.rs:LL:CC + | +LL | unsafe { float_to_int_unchecked::(f64::MAX); } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on 1.7976931348623157E+308 which cannot be represented in target type `u128` + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/float_to_int_64_too_big6.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/intrinsics/float_to_int_64_too_big7.stderr b/tests/compile-fail/intrinsics/float_to_int_64_too_big7.stderr new file mode 100644 index 0000000000000..a291b21c7aad5 --- /dev/null +++ b/tests/compile-fail/intrinsics/float_to_int_64_too_big7.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on -1.7976931348623157E+308 which cannot be represented in target type `i128` + --> $DIR/float_to_int_64_too_big7.rs:LL:CC + | +LL | unsafe { float_to_int_unchecked::(f64::MIN); } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on -1.7976931348623157E+308 which cannot be represented in target type `i128` + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/float_to_int_64_too_big7.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/intrinsics/float_to_int_64_too_small1.stderr b/tests/compile-fail/intrinsics/float_to_int_64_too_small1.stderr new file mode 100644 index 0000000000000..81ca218505dd4 --- /dev/null +++ b/tests/compile-fail/intrinsics/float_to_int_64_too_small1.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on -2147483649 which cannot be represented in target type `i32` + --> $DIR/float_to_int_64_too_small1.rs:LL:CC + | +LL | unsafe { float_to_int_unchecked::(-2147483649.0f64); } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on -2147483649 which cannot be represented in target type `i32` + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/float_to_int_64_too_small1.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/intrinsics/float_to_int_64_too_small2.stderr b/tests/compile-fail/intrinsics/float_to_int_64_too_small2.stderr new file mode 100644 index 0000000000000..245f5cf0238cb --- /dev/null +++ b/tests/compile-fail/intrinsics/float_to_int_64_too_small2.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on -9.2233720368547778E+18 which cannot be represented in target type `i64` + --> $DIR/float_to_int_64_too_small2.rs:LL:CC + | +LL | unsafe { float_to_int_unchecked::(-9223372036854777856.0f64); } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on -9.2233720368547778E+18 which cannot be represented in target type `i64` + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/float_to_int_64_too_small2.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/intrinsics/float_to_int_64_too_small3.stderr b/tests/compile-fail/intrinsics/float_to_int_64_too_small3.stderr new file mode 100644 index 0000000000000..f684ed2cde987 --- /dev/null +++ b/tests/compile-fail/intrinsics/float_to_int_64_too_small3.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on -2.4028236692093845E+38 which cannot be represented in target type `i128` + --> $DIR/float_to_int_64_too_small3.rs:LL:CC + | +LL | unsafe { float_to_int_unchecked::(-240282366920938463463374607431768211455.0f64); } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on -2.4028236692093845E+38 which cannot be represented in target type `i128` + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/float_to_int_64_too_small3.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/intrinsics/out_of_bounds_ptr_1.stderr b/tests/compile-fail/intrinsics/out_of_bounds_ptr_1.stderr new file mode 100644 index 0000000000000..2b00876297faa --- /dev/null +++ b/tests/compile-fail/intrinsics/out_of_bounds_ptr_1.stderr @@ -0,0 +1,16 @@ +error: Undefined Behavior: pointer arithmetic failed: ALLOC has size 4, so pointer to 5 bytes starting at offset 0 is out-of-bounds + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `std::ptr::const_ptr::::offset` at rustc_src/src/ptr/const_ptr.rs:LL:CC +note: inside `main` at $DIR/out_of_bounds_ptr_1.rs:LL:CC + --> $DIR/out_of_bounds_ptr_1.rs:LL:CC + | +LL | let x = unsafe { x.offset(5) }; + | ^^^^^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/intrinsics/out_of_bounds_ptr_2.stderr b/tests/compile-fail/intrinsics/out_of_bounds_ptr_2.stderr new file mode 100644 index 0000000000000..32ac570f7231b --- /dev/null +++ b/tests/compile-fail/intrinsics/out_of_bounds_ptr_2.stderr @@ -0,0 +1,16 @@ +error: Undefined Behavior: overflowing in-bounds pointer arithmetic + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `std::ptr::const_ptr::::offset` at rustc_src/src/ptr/const_ptr.rs:LL:CC +note: inside `main` at $DIR/out_of_bounds_ptr_2.rs:LL:CC + --> $DIR/out_of_bounds_ptr_2.rs:LL:CC + | +LL | let x = unsafe { x.offset(isize::MIN) }; + | ^^^^^^^^^^^^^^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/intrinsics/out_of_bounds_ptr_3.stderr b/tests/compile-fail/intrinsics/out_of_bounds_ptr_3.stderr new file mode 100644 index 0000000000000..cd48112cb4304 --- /dev/null +++ b/tests/compile-fail/intrinsics/out_of_bounds_ptr_3.stderr @@ -0,0 +1,16 @@ +error: Undefined Behavior: pointer arithmetic failed: ALLOC has size 4, so pointer to 1 byte starting at offset -1 is out-of-bounds + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `std::ptr::const_ptr::::offset` at rustc_src/src/ptr/const_ptr.rs:LL:CC +note: inside `main` at $DIR/out_of_bounds_ptr_3.rs:LL:CC + --> $DIR/out_of_bounds_ptr_3.rs:LL:CC + | +LL | let x = unsafe { x.offset(-1) }; + | ^^^^^^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/intrinsics/overflowing-unchecked-rsh.rs b/tests/compile-fail/intrinsics/overflowing-unchecked-rsh.rs index 730d01597f4d0..6402f4bb74c6a 100644 --- a/tests/compile-fail/intrinsics/overflowing-unchecked-rsh.rs +++ b/tests/compile-fail/intrinsics/overflowing-unchecked-rsh.rs @@ -2,7 +2,7 @@ use std::intrinsics::*; -//error-pattern: overflowing shift by 64 in `unchecked_shr` +// error-pattern: overflowing shift by 64 in `unchecked_shr` fn main() { unsafe { diff --git a/tests/compile-fail/intrinsics/overflowing-unchecked-rsh.stderr b/tests/compile-fail/intrinsics/overflowing-unchecked-rsh.stderr new file mode 100644 index 0000000000000..0d22b166b2678 --- /dev/null +++ b/tests/compile-fail/intrinsics/overflowing-unchecked-rsh.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: overflowing shift by 64 in `unchecked_shr` + --> $DIR/overflowing-unchecked-rsh.rs:LL:CC + | +LL | let _n = unchecked_shr(1i64, 64); + | ^^^^^^^^^^^^^^^^^^^^^^^ overflowing shift by 64 in `unchecked_shr` + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/overflowing-unchecked-rsh.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/intrinsics/ptr_offset_0_plus_0.stderr b/tests/compile-fail/intrinsics/ptr_offset_0_plus_0.stderr new file mode 100644 index 0000000000000..d3e2fe4013f44 --- /dev/null +++ b/tests/compile-fail/intrinsics/ptr_offset_0_plus_0.stderr @@ -0,0 +1,16 @@ +error: Undefined Behavior: pointer arithmetic failed: null pointer is not a valid pointer + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `std::ptr::mut_ptr::::offset` at rustc_src/src/ptr/mut_ptr.rs:LL:CC +note: inside `main` at $DIR/ptr_offset_0_plus_0.rs:LL:CC + --> $DIR/ptr_offset_0_plus_0.rs:LL:CC + | +LL | let _x = unsafe { x.offset(0) }; // UB despite offset 0, NULL is never inbounds + | ^^^^^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/intrinsics/ptr_offset_from_oob.stderr b/tests/compile-fail/intrinsics/ptr_offset_from_oob.stderr new file mode 100644 index 0000000000000..0e723a5ee3951 --- /dev/null +++ b/tests/compile-fail/intrinsics/ptr_offset_from_oob.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: out-of-bounds offset_from: ALLOC has size 4, so pointer at offset 10 is out-of-bounds + --> $DIR/ptr_offset_from_oob.rs:LL:CC + | +LL | unsafe { ptr_offset_from(end_ptr, end_ptr) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds offset_from: ALLOC has size 4, so pointer at offset 10 is out-of-bounds + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/ptr_offset_from_oob.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/intrinsics/ptr_offset_int_plus_int.rs b/tests/compile-fail/intrinsics/ptr_offset_int_plus_int.rs index ea6bef151e1c1..e332a9dc624a0 100644 --- a/tests/compile-fail/intrinsics/ptr_offset_int_plus_int.rs +++ b/tests/compile-fail/intrinsics/ptr_offset_int_plus_int.rs @@ -1,4 +1,4 @@ -// error-pattern: 0x1 is not a valid pointer +// error-pattern: is not a valid pointer fn main() { // Can't offset an integer pointer by non-zero offset. diff --git a/tests/compile-fail/intrinsics/ptr_offset_int_plus_int.stderr b/tests/compile-fail/intrinsics/ptr_offset_int_plus_int.stderr new file mode 100644 index 0000000000000..a47ed4719d90a --- /dev/null +++ b/tests/compile-fail/intrinsics/ptr_offset_int_plus_int.stderr @@ -0,0 +1,16 @@ +error: Undefined Behavior: pointer arithmetic failed: 0x1 is not a valid pointer + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `std::ptr::mut_ptr::::offset` at rustc_src/src/ptr/mut_ptr.rs:LL:CC +note: inside `main` at $DIR/ptr_offset_int_plus_int.rs:LL:CC + --> $DIR/ptr_offset_int_plus_int.rs:LL:CC + | +LL | let _val = (1 as *mut u8).offset(1); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/intrinsics/ptr_offset_int_plus_ptr.rs b/tests/compile-fail/intrinsics/ptr_offset_int_plus_ptr.rs index 8ff5c3596ef63..2d27e25a7af1f 100644 --- a/tests/compile-fail/intrinsics/ptr_offset_int_plus_ptr.rs +++ b/tests/compile-fail/intrinsics/ptr_offset_int_plus_ptr.rs @@ -1,4 +1,4 @@ -// error-pattern: 0x1 is not a valid pointer +// error-pattern: is not a valid pointer fn main() { let ptr = Box::into_raw(Box::new(0u32)); diff --git a/tests/compile-fail/intrinsics/ptr_offset_int_plus_ptr.stderr b/tests/compile-fail/intrinsics/ptr_offset_int_plus_ptr.stderr new file mode 100644 index 0000000000000..58b33e706d3ee --- /dev/null +++ b/tests/compile-fail/intrinsics/ptr_offset_int_plus_ptr.stderr @@ -0,0 +1,16 @@ +error: Undefined Behavior: pointer arithmetic failed: 0x1 is not a valid pointer + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `std::ptr::mut_ptr::::offset` at rustc_src/src/ptr/mut_ptr.rs:LL:CC +note: inside `main` at $DIR/ptr_offset_int_plus_ptr.rs:LL:CC + --> $DIR/ptr_offset_int_plus_ptr.rs:LL:CC + | +LL | let _val = (1 as *mut u8).offset(ptr as isize); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/intrinsics/ptr_offset_overflow.rs b/tests/compile-fail/intrinsics/ptr_offset_overflow.rs index 452bf341c9e20..734547b6013b0 100644 --- a/tests/compile-fail/intrinsics/ptr_offset_overflow.rs +++ b/tests/compile-fail/intrinsics/ptr_offset_overflow.rs @@ -1,4 +1,4 @@ -//error-pattern: overflowing in-bounds pointer arithmetic +// error-pattern: overflowing in-bounds pointer arithmetic fn main() { let v = [1i8, 2]; let x = &v[1] as *const i8; diff --git a/tests/compile-fail/intrinsics/ptr_offset_overflow.stderr b/tests/compile-fail/intrinsics/ptr_offset_overflow.stderr new file mode 100644 index 0000000000000..81ff87168c121 --- /dev/null +++ b/tests/compile-fail/intrinsics/ptr_offset_overflow.stderr @@ -0,0 +1,16 @@ +error: Undefined Behavior: overflowing in-bounds pointer arithmetic + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `std::ptr::const_ptr::::offset` at rustc_src/src/ptr/const_ptr.rs:LL:CC +note: inside `main` at $DIR/ptr_offset_overflow.rs:LL:CC + --> $DIR/ptr_offset_overflow.rs:LL:CC + | +LL | let _val = unsafe { x.offset(isize::MIN) }; + | ^^^^^^^^^^^^^^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/intrinsics/ptr_offset_ptr_plus_0.stderr b/tests/compile-fail/intrinsics/ptr_offset_ptr_plus_0.stderr new file mode 100644 index 0000000000000..686ab17966479 --- /dev/null +++ b/tests/compile-fail/intrinsics/ptr_offset_ptr_plus_0.stderr @@ -0,0 +1,16 @@ +error: Undefined Behavior: pointer arithmetic failed: ALLOC has size 4, so pointer at offset 32 is out-of-bounds + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `std::ptr::mut_ptr::::offset` at rustc_src/src/ptr/mut_ptr.rs:LL:CC +note: inside `main` at $DIR/ptr_offset_ptr_plus_0.rs:LL:CC + --> $DIR/ptr_offset_ptr_plus_0.rs:LL:CC + | +LL | let _x = unsafe { x.offset(0) }; // UB despite offset 0, the pointer is not inbounds of the only object it can point to + | ^^^^^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/intrinsics/rem-by-zero.stderr b/tests/compile-fail/intrinsics/rem-by-zero.stderr new file mode 100644 index 0000000000000..7501aca7b247f --- /dev/null +++ b/tests/compile-fail/intrinsics/rem-by-zero.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: calculating the remainder with a divisor of zero + --> $DIR/rem-by-zero.rs:LL:CC + | +LL | let _n = unchecked_rem(3u32, 0); + | ^^^^^^^^^^^^^^^^^^^^^^ calculating the remainder with a divisor of zero + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/rem-by-zero.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/intrinsics/simd-div-by-zero.stderr b/tests/compile-fail/intrinsics/simd-div-by-zero.stderr new file mode 100644 index 0000000000000..77c12de8d81a0 --- /dev/null +++ b/tests/compile-fail/intrinsics/simd-div-by-zero.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: dividing by zero + --> $DIR/simd-div-by-zero.rs:LL:CC + | +LL | simd_div(x, y); + | ^^^^^^^^^^^^^^ dividing by zero + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/simd-div-by-zero.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/intrinsics/simd-div-overflow.stderr b/tests/compile-fail/intrinsics/simd-div-overflow.stderr new file mode 100644 index 0000000000000..53479a738b7b3 --- /dev/null +++ b/tests/compile-fail/intrinsics/simd-div-overflow.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: overflow in signed division (dividing MIN by -1) + --> $DIR/simd-div-overflow.rs:LL:CC + | +LL | simd_div(x, y); + | ^^^^^^^^^^^^^^ overflow in signed division (dividing MIN by -1) + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/simd-div-overflow.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/intrinsics/simd-float-to-int.stderr b/tests/compile-fail/intrinsics/simd-float-to-int.stderr new file mode 100644 index 0000000000000..378c2b48bb935 --- /dev/null +++ b/tests/compile-fail/intrinsics/simd-float-to-int.stderr @@ -0,0 +1,17 @@ +error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on 3.40282347E+38 which cannot be represented in target type `i32` + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `core::core_simd::round::>::to_int_unchecked::` at rustc_src/src/../../portable-simd/crates/core_simd/src/round.rs:LL:CC +note: inside `main` at $DIR/simd-float-to-int.rs:LL:CC + --> $DIR/simd-float-to-int.rs:LL:CC + | +LL | let _x : i32x2 = f32x2::from_array([f32::MAX, f32::MIN]).to_int_unchecked(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: this error originates in the macro `implement` (in Nightly builds, run with -Z macro-backtrace for more info) + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/intrinsics/simd-gather.stderr b/tests/compile-fail/intrinsics/simd-gather.stderr new file mode 100644 index 0000000000000..3da14e1fe3756 --- /dev/null +++ b/tests/compile-fail/intrinsics/simd-gather.stderr @@ -0,0 +1,16 @@ +error: Undefined Behavior: dereferencing pointer failed: ALLOC has size 9, so pointer to 1 byte starting at offset 9 is out-of-bounds + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `std::simd::Simd::::gather_select_unchecked` at rustc_src/src/../../portable-simd/crates/core_simd/src/vector.rs:LL:CC +note: inside `main` at $DIR/simd-gather.rs:LL:CC + --> $DIR/simd-gather.rs:LL:CC + | +LL | let _result = Simd::gather_select_unchecked(&vec, Mask::splat(true), idxs, Simd::splat(0)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/intrinsics/simd-reduce-invalid-bool.stderr b/tests/compile-fail/intrinsics/simd-reduce-invalid-bool.stderr new file mode 100644 index 0000000000000..a2404b174e880 --- /dev/null +++ b/tests/compile-fail/intrinsics/simd-reduce-invalid-bool.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: each element of a SIMD mask must be all-0-bits or all-1-bits + --> $DIR/simd-reduce-invalid-bool.rs:LL:CC + | +LL | simd_reduce_any(x); + | ^^^^^^^^^^^^^^^^^^ each element of a SIMD mask must be all-0-bits or all-1-bits + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/simd-reduce-invalid-bool.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/intrinsics/simd-rem-by-zero.stderr b/tests/compile-fail/intrinsics/simd-rem-by-zero.stderr new file mode 100644 index 0000000000000..98e5ca2079721 --- /dev/null +++ b/tests/compile-fail/intrinsics/simd-rem-by-zero.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: calculating the remainder with a divisor of zero + --> $DIR/simd-rem-by-zero.rs:LL:CC + | +LL | simd_rem(x, y); + | ^^^^^^^^^^^^^^ calculating the remainder with a divisor of zero + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/simd-rem-by-zero.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/intrinsics/simd-scatter.stderr b/tests/compile-fail/intrinsics/simd-scatter.stderr new file mode 100644 index 0000000000000..2d2cc2972ab3d --- /dev/null +++ b/tests/compile-fail/intrinsics/simd-scatter.stderr @@ -0,0 +1,16 @@ +error: Undefined Behavior: dereferencing pointer failed: ALLOC has size 9, so pointer to 1 byte starting at offset 9 is out-of-bounds + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `std::simd::Simd::::scatter_select_unchecked` at rustc_src/src/../../portable-simd/crates/core_simd/src/vector.rs:LL:CC +note: inside `main` at $DIR/simd-scatter.rs:LL:CC + --> $DIR/simd-scatter.rs:LL:CC + | +LL | Simd::from_array([-27, 82, -41, 124]).scatter_select_unchecked(&mut vec, Mask::splat(true), idxs); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/intrinsics/simd-select-bitmask-invalid.stderr b/tests/compile-fail/intrinsics/simd-select-bitmask-invalid.stderr new file mode 100644 index 0000000000000..e5fe3c886cb84 --- /dev/null +++ b/tests/compile-fail/intrinsics/simd-select-bitmask-invalid.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: a SIMD bitmask less than 8 bits long must be filled with 0s for the remaining bits + --> $DIR/simd-select-bitmask-invalid.rs:LL:CC + | +LL | simd_select_bitmask(0b11111111u8, x, x); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ a SIMD bitmask less than 8 bits long must be filled with 0s for the remaining bits + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/simd-select-bitmask-invalid.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/intrinsics/simd-select-invalid-bool.stderr b/tests/compile-fail/intrinsics/simd-select-invalid-bool.stderr new file mode 100644 index 0000000000000..f0a1282edac46 --- /dev/null +++ b/tests/compile-fail/intrinsics/simd-select-invalid-bool.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: each element of a SIMD mask must be all-0-bits or all-1-bits + --> $DIR/simd-select-invalid-bool.rs:LL:CC + | +LL | simd_select(x, x, x); + | ^^^^^^^^^^^^^^^^^^^^ each element of a SIMD mask must be all-0-bits or all-1-bits + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/simd-select-invalid-bool.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/intrinsics/simd-shl-too-far.stderr b/tests/compile-fail/intrinsics/simd-shl-too-far.stderr new file mode 100644 index 0000000000000..dcd38d6f01140 --- /dev/null +++ b/tests/compile-fail/intrinsics/simd-shl-too-far.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: overflowing shift by 100 in `simd_shl` in SIMD lane 0 + --> $DIR/simd-shl-too-far.rs:LL:CC + | +LL | simd_shl(x, y); + | ^^^^^^^^^^^^^^ overflowing shift by 100 in `simd_shl` in SIMD lane 0 + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/simd-shl-too-far.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/intrinsics/simd-shr-too-far.stderr b/tests/compile-fail/intrinsics/simd-shr-too-far.stderr new file mode 100644 index 0000000000000..c2c2850522f5a --- /dev/null +++ b/tests/compile-fail/intrinsics/simd-shr-too-far.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: overflowing shift by 40 in `simd_shr` in SIMD lane 1 + --> $DIR/simd-shr-too-far.rs:LL:CC + | +LL | simd_shr(x, y); + | ^^^^^^^^^^^^^^ overflowing shift by 40 in `simd_shr` in SIMD lane 1 + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/simd-shr-too-far.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/intrinsics/unchecked_add1.stderr b/tests/compile-fail/intrinsics/unchecked_add1.stderr new file mode 100644 index 0000000000000..b967b46ac9bac --- /dev/null +++ b/tests/compile-fail/intrinsics/unchecked_add1.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: overflow executing `unchecked_add` + --> $DIR/unchecked_add1.rs:LL:CC + | +LL | unsafe { std::intrinsics::unchecked_add(40000u16, 30000); } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflow executing `unchecked_add` + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/unchecked_add1.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/intrinsics/unchecked_add2.stderr b/tests/compile-fail/intrinsics/unchecked_add2.stderr new file mode 100644 index 0000000000000..18a116b7da96b --- /dev/null +++ b/tests/compile-fail/intrinsics/unchecked_add2.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: overflow executing `unchecked_add` + --> $DIR/unchecked_add2.rs:LL:CC + | +LL | unsafe { std::intrinsics::unchecked_add(-30000i16, -8000); } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflow executing `unchecked_add` + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/unchecked_add2.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/intrinsics/unchecked_div1.stderr b/tests/compile-fail/intrinsics/unchecked_div1.stderr new file mode 100644 index 0000000000000..f153e4efd984b --- /dev/null +++ b/tests/compile-fail/intrinsics/unchecked_div1.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: overflow in signed division (dividing MIN by -1) + --> $DIR/unchecked_div1.rs:LL:CC + | +LL | unsafe { std::intrinsics::unchecked_div(i16::MIN, -1); } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflow in signed division (dividing MIN by -1) + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/unchecked_div1.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/intrinsics/unchecked_mul1.stderr b/tests/compile-fail/intrinsics/unchecked_mul1.stderr new file mode 100644 index 0000000000000..5372ba9933a25 --- /dev/null +++ b/tests/compile-fail/intrinsics/unchecked_mul1.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: overflow executing `unchecked_mul` + --> $DIR/unchecked_mul1.rs:LL:CC + | +LL | unsafe { std::intrinsics::unchecked_mul(300u16, 250u16); } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflow executing `unchecked_mul` + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/unchecked_mul1.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/intrinsics/unchecked_mul2.stderr b/tests/compile-fail/intrinsics/unchecked_mul2.stderr new file mode 100644 index 0000000000000..20a44d2422ae9 --- /dev/null +++ b/tests/compile-fail/intrinsics/unchecked_mul2.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: overflow executing `unchecked_mul` + --> $DIR/unchecked_mul2.rs:LL:CC + | +LL | unsafe { std::intrinsics::unchecked_mul(1_000_000_000i32, -4); } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflow executing `unchecked_mul` + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/unchecked_mul2.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/intrinsics/unchecked_sub1.stderr b/tests/compile-fail/intrinsics/unchecked_sub1.stderr new file mode 100644 index 0000000000000..12abfed8ff73a --- /dev/null +++ b/tests/compile-fail/intrinsics/unchecked_sub1.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: overflow executing `unchecked_sub` + --> $DIR/unchecked_sub1.rs:LL:CC + | +LL | unsafe { std::intrinsics::unchecked_sub(14u32, 22); } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflow executing `unchecked_sub` + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/unchecked_sub1.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/intrinsics/unchecked_sub2.stderr b/tests/compile-fail/intrinsics/unchecked_sub2.stderr new file mode 100644 index 0000000000000..d62d2de2f930d --- /dev/null +++ b/tests/compile-fail/intrinsics/unchecked_sub2.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: overflow executing `unchecked_sub` + --> $DIR/unchecked_sub2.rs:LL:CC + | +LL | unsafe { std::intrinsics::unchecked_sub(30000i16, -7000); } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflow executing `unchecked_sub` + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/unchecked_sub2.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/intrinsics/uninit_uninhabited_type.stderr b/tests/compile-fail/intrinsics/uninit_uninhabited_type.stderr new file mode 100644 index 0000000000000..150128ba2a41c --- /dev/null +++ b/tests/compile-fail/intrinsics/uninit_uninhabited_type.stderr @@ -0,0 +1,12 @@ +error: abnormal termination: aborted execution: attempted to instantiate uninhabited type `!` + --> $DIR/uninit_uninhabited_type.rs:LL:CC + | +LL | unsafe { std::mem::uninitialized::() }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ aborted execution: attempted to instantiate uninhabited type `!` + | + = note: inside `main` at $DIR/uninit_uninhabited_type.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/intrinsics/write_bytes_null.stderr b/tests/compile-fail/intrinsics/write_bytes_null.stderr new file mode 100644 index 0000000000000..77f675e8fb629 --- /dev/null +++ b/tests/compile-fail/intrinsics/write_bytes_null.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: memory access failed: null pointer is not a valid pointer + --> $DIR/write_bytes_null.rs:LL:CC + | +LL | unsafe { write_bytes::(std::ptr::null_mut(), 0, 0) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: null pointer is not a valid pointer + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/write_bytes_null.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/intrinsics/write_bytes_overflow.stderr b/tests/compile-fail/intrinsics/write_bytes_overflow.stderr new file mode 100644 index 0000000000000..018ba83f53fb6 --- /dev/null +++ b/tests/compile-fail/intrinsics/write_bytes_overflow.stderr @@ -0,0 +1,17 @@ +error: Undefined Behavior: overflow computing total size of `write_bytes` + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `std::intrinsics::write_bytes::` at rustc_src/src/intrinsics.rs:LL:CC + = note: inside `std::ptr::mut_ptr::::write_bytes` at rustc_src/src/ptr/mut_ptr.rs:LL:CC +note: inside `main` at $DIR/write_bytes_overflow.rs:LL:CC + --> $DIR/write_bytes_overflow.rs:LL:CC + | +LL | (&mut y as *mut i32).write_bytes(0u8, 1usize << (mem::size_of::() * 8 - 1)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/intrinsics/zero_fn_ptr.stderr b/tests/compile-fail/intrinsics/zero_fn_ptr.stderr new file mode 100644 index 0000000000000..9d44ba9f746ad --- /dev/null +++ b/tests/compile-fail/intrinsics/zero_fn_ptr.stderr @@ -0,0 +1,12 @@ +error: abnormal termination: aborted execution: attempted to zero-initialize type `fn()`, which is invalid + --> $DIR/zero_fn_ptr.rs:LL:CC + | +LL | unsafe { std::mem::zeroed::() }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ aborted execution: attempted to zero-initialize type `fn()`, which is invalid + | + = note: inside `main` at $DIR/zero_fn_ptr.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/invalid_bool.rs b/tests/compile-fail/invalid_bool.rs index 22b9de5776fee..c0c982b8ca21d 100644 --- a/tests/compile-fail/invalid_bool.rs +++ b/tests/compile-fail/invalid_bool.rs @@ -5,5 +5,5 @@ fn main() { let b = unsafe { std::mem::transmute::(2) }; - let _x = b == std::hint::black_box(true); //~ ERROR interpreting an invalid 8-bit value as a bool: 0x02 + let _x = b == std::hint::black_box(true); //~ ERROR interpreting an invalid 8-bit value as a bool } diff --git a/tests/compile-fail/invalid_bool.stderr b/tests/compile-fail/invalid_bool.stderr new file mode 100644 index 0000000000000..23c5365618b8d --- /dev/null +++ b/tests/compile-fail/invalid_bool.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: interpreting an invalid 8-bit value as a bool: 0x02 + --> $DIR/invalid_bool.rs:LL:CC + | +LL | let _x = b == std::hint::black_box(true); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ interpreting an invalid 8-bit value as a bool: 0x02 + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/invalid_bool.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/invalid_char.rs b/tests/compile-fail/invalid_char.rs index b240cb22ebe93..9d485b73f2469 100644 --- a/tests/compile-fail/invalid_char.rs +++ b/tests/compile-fail/invalid_char.rs @@ -6,5 +6,5 @@ fn main() { let c = 0xFFFFFFu32; assert!(std::char::from_u32(c).is_none()); let c = unsafe { std::mem::transmute::(c) }; - let _x = c == 'x'; //~ ERROR interpreting an invalid 32-bit value as a char: 0x00ffffff + let _x = c == 'x'; //~ ERROR interpreting an invalid 32-bit value as a char } diff --git a/tests/compile-fail/invalid_char.stderr b/tests/compile-fail/invalid_char.stderr new file mode 100644 index 0000000000000..69f3ef1f4a6da --- /dev/null +++ b/tests/compile-fail/invalid_char.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: interpreting an invalid 32-bit value as a char: $HEX + --> $DIR/invalid_char.rs:LL:CC + | +LL | let _x = c == 'x'; + | ^^^^^^^^ interpreting an invalid 32-bit value as a char: $HEX + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/invalid_char.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/invalid_enum_tag.rs b/tests/compile-fail/invalid_enum_tag.rs index 762a70d803a41..63b6003f3d89e 100644 --- a/tests/compile-fail/invalid_enum_tag.rs +++ b/tests/compile-fail/invalid_enum_tag.rs @@ -2,7 +2,7 @@ // Make sure we find these even with many checks disabled. // compile-flags: -Zmiri-disable-alignment-check -Zmiri-disable-stacked-borrows -Zmiri-disable-validation -// error-pattern: enum value has invalid tag: 0x0000002a +// error-pattern: enum value has invalid tag use std::mem; diff --git a/tests/compile-fail/invalid_enum_tag.stderr b/tests/compile-fail/invalid_enum_tag.stderr new file mode 100644 index 0000000000000..a602204cf46bc --- /dev/null +++ b/tests/compile-fail/invalid_enum_tag.stderr @@ -0,0 +1,16 @@ +error: Undefined Behavior: enum value has invalid tag: $HEX + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `std::mem::discriminant::` at rustc_src/src/mem/mod.rs:LL:CC +note: inside `main` at $DIR/invalid_enum_tag.rs:LL:CC + --> $DIR/invalid_enum_tag.rs:LL:CC + | +LL | let _val = mem::discriminant(&f); + | ^^^^^^^^^^^^^^^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/invalid_int.stderr b/tests/compile-fail/invalid_int.stderr new file mode 100644 index 0000000000000..cd7919444f0a9 --- /dev/null +++ b/tests/compile-fail/invalid_int.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory + --> $DIR/invalid_int.rs:LL:CC + | +LL | let _x = i + 0; + | ^^^^^ using uninitialized data, but this operation requires initialized memory + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/invalid_int.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/issue-miri-1112.stderr b/tests/compile-fail/issue-miri-1112.stderr new file mode 100644 index 0000000000000..1dfcad0c147b4 --- /dev/null +++ b/tests/compile-fail/issue-miri-1112.stderr @@ -0,0 +1,20 @@ +error: Undefined Behavior: type validation failed: encountered invalid drop function pointer in vtable (function has incompatible signature) + --> $DIR/issue-miri-1112.rs:LL:CC + | +LL | let obj = std::mem::transmute::(obj); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered invalid drop function pointer in vtable (function has incompatible signature) + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `FunnyPointer::from_data_ptr` at $DIR/issue-miri-1112.rs:LL:CC +note: inside `main` at $DIR/issue-miri-1112.rs:LL:CC + --> $DIR/issue-miri-1112.rs:LL:CC + | +LL | let _raw: &FunnyPointer = FunnyPointer::from_data_ptr(&hello, &meta as *const _); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/memleak.rs b/tests/compile-fail/memleak.rs index 71b4e2f442f31..7dee9ddf1c988 100644 --- a/tests/compile-fail/memleak.rs +++ b/tests/compile-fail/memleak.rs @@ -1,4 +1,5 @@ -//error-pattern: the evaluated program leaked memory +// error-pattern: the evaluated program leaked memory +// normalize-stderr-test: ".*│.*" -> "$$stripped$$" fn main() { std::mem::forget(Box::new(42)); diff --git a/tests/compile-fail/memleak.stderr b/tests/compile-fail/memleak.stderr new file mode 100644 index 0000000000000..f8b62af3eb857 --- /dev/null +++ b/tests/compile-fail/memleak.stderr @@ -0,0 +1,10 @@ +The following memory was leaked: ALLOC (Rust heap, size: 4, align: 4) { +$stripped$ +} + +error: the evaluated program leaked memory + +note: pass `-Zmiri-ignore-leaks` to disable this check + +error: aborting due to previous error + diff --git a/tests/compile-fail/memleak_rc.32bit.stderr b/tests/compile-fail/memleak_rc.32bit.stderr new file mode 100644 index 0000000000000..da222609091ab --- /dev/null +++ b/tests/compile-fail/memleak_rc.32bit.stderr @@ -0,0 +1,10 @@ +The following memory was leaked: ALLOC (Rust heap, size: 16, align: 4) { +$stripped$ +} + +error: the evaluated program leaked memory + +note: pass `-Zmiri-ignore-leaks` to disable this check + +error: aborting due to previous error + diff --git a/tests/compile-fail/memleak_rc.64bit.stderr b/tests/compile-fail/memleak_rc.64bit.stderr new file mode 100644 index 0000000000000..8c24bbc779bd6 --- /dev/null +++ b/tests/compile-fail/memleak_rc.64bit.stderr @@ -0,0 +1,11 @@ +The following memory was leaked: ALLOC (Rust heap, size: 32, align: 8) { +$stripped$ +$stripped$ +} + +error: the evaluated program leaked memory + +note: pass `-Zmiri-ignore-leaks` to disable this check + +error: aborting due to previous error + diff --git a/tests/compile-fail/memleak_rc.rs b/tests/compile-fail/memleak_rc.rs index b2bc6722afb04..17bcb36f36106 100644 --- a/tests/compile-fail/memleak_rc.rs +++ b/tests/compile-fail/memleak_rc.rs @@ -1,4 +1,6 @@ -//error-pattern: the evaluated program leaked memory +// error-pattern: the evaluated program leaked memory +// stderr-per-bitwidth +// normalize-stderr-test: ".*│.*" -> "$$stripped$$" use std::rc::Rc; use std::cell::RefCell; diff --git a/tests/compile-fail/modifying_constants.stderr b/tests/compile-fail/modifying_constants.stderr new file mode 100644 index 0000000000000..995011482323d --- /dev/null +++ b/tests/compile-fail/modifying_constants.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: writing to ALLOC which is read-only + --> $DIR/modifying_constants.rs:LL:CC + | +LL | *y = 42; + | ^^^^^^^ writing to ALLOC which is read-only + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/modifying_constants.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/never_say_never.stderr b/tests/compile-fail/never_say_never.stderr new file mode 100644 index 0000000000000..22ad10f131035 --- /dev/null +++ b/tests/compile-fail/never_say_never.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: entering unreachable code + --> $DIR/never_say_never.rs:LL:CC + | +LL | *(y as *const _ as *const !) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ entering unreachable code + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/never_say_never.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/never_transmute_humans.stderr b/tests/compile-fail/never_transmute_humans.stderr new file mode 100644 index 0000000000000..6d8fa37e98ef9 --- /dev/null +++ b/tests/compile-fail/never_transmute_humans.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: transmuting to uninhabited type + --> $DIR/never_transmute_humans.rs:LL:CC + | +LL | std::mem::transmute::(Human) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ transmuting to uninhabited type + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/never_transmute_humans.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/never_transmute_void.stderr b/tests/compile-fail/never_transmute_void.stderr new file mode 100644 index 0000000000000..8d8a4d0e832f9 --- /dev/null +++ b/tests/compile-fail/never_transmute_void.stderr @@ -0,0 +1,20 @@ +error: Undefined Behavior: entering unreachable code + --> $DIR/never_transmute_void.rs:LL:CC + | +LL | match v.0 {} + | ^^^ entering unreachable code + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `m::f` at $DIR/never_transmute_void.rs:LL:CC +note: inside `main` at $DIR/never_transmute_void.rs:LL:CC + --> $DIR/never_transmute_void.rs:LL:CC + | +LL | m::f(v); + | ^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/no_main.stderr b/tests/compile-fail/no_main.stderr new file mode 100644 index 0000000000000..52591a8d6da31 --- /dev/null +++ b/tests/compile-fail/no_main.stderr @@ -0,0 +1,2 @@ +error: miri can only run programs that have a main function + diff --git a/tests/compile-fail/null_pointer_deref.stderr b/tests/compile-fail/null_pointer_deref.stderr new file mode 100644 index 0000000000000..0930160023f1b --- /dev/null +++ b/tests/compile-fail/null_pointer_deref.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: dereferencing pointer failed: null pointer is not a valid pointer + --> $DIR/null_pointer_deref.rs:LL:CC + | +LL | let x: i32 = unsafe { *std::ptr::null() }; + | ^^^^^^^^^^^^^^^^^ dereferencing pointer failed: null pointer is not a valid pointer + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/null_pointer_deref.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/null_pointer_deref_zst.stderr b/tests/compile-fail/null_pointer_deref_zst.stderr new file mode 100644 index 0000000000000..25fea50b15af1 --- /dev/null +++ b/tests/compile-fail/null_pointer_deref_zst.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: dereferencing pointer failed: null pointer is not a valid pointer + --> $DIR/null_pointer_deref_zst.rs:LL:CC + | +LL | let x: () = unsafe { *std::ptr::null() }; + | ^^^^^^^^^^^^^^^^^ dereferencing pointer failed: null pointer is not a valid pointer + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/null_pointer_deref_zst.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/null_pointer_write.stderr b/tests/compile-fail/null_pointer_write.stderr new file mode 100644 index 0000000000000..5ac8cc7c20fdf --- /dev/null +++ b/tests/compile-fail/null_pointer_write.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: dereferencing pointer failed: null pointer is not a valid pointer + --> $DIR/null_pointer_write.rs:LL:CC + | +LL | unsafe { *std::ptr::null_mut() = 0i32 }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ dereferencing pointer failed: null pointer is not a valid pointer + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/null_pointer_write.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/null_pointer_write_zst.stderr b/tests/compile-fail/null_pointer_write_zst.stderr new file mode 100644 index 0000000000000..b40a9154f1826 --- /dev/null +++ b/tests/compile-fail/null_pointer_write_zst.stderr @@ -0,0 +1,17 @@ +error: Undefined Behavior: memory access failed: null pointer is not a valid pointer + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `std::ptr::write::<[u8; 0]>` at rustc_src/src/ptr/mod.rs:LL:CC + = note: inside `std::ptr::mut_ptr::::write` at rustc_src/src/ptr/mut_ptr.rs:LL:CC +note: inside `main` at $DIR/null_pointer_write_zst.rs:LL:CC + --> $DIR/null_pointer_write_zst.rs:LL:CC + | +LL | unsafe { std::ptr::null_mut::<[u8; 0]>().write(zst_val) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/panic/bad_miri_start_panic.stderr b/tests/compile-fail/panic/bad_miri_start_panic.stderr new file mode 100644 index 0000000000000..dca5d39b7665e --- /dev/null +++ b/tests/compile-fail/panic/bad_miri_start_panic.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: unwinding past a stack frame that does not allow unwinding + --> $DIR/bad_miri_start_panic.rs:LL:CC + | +LL | unsafe { miri_start_panic(&mut 0) } + | ^^^^^^^^^^^^^^^^^^^^^^^^ unwinding past a stack frame that does not allow unwinding + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/bad_miri_start_panic.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/panic/bad_unwind.stderr b/tests/compile-fail/panic/bad_unwind.stderr new file mode 100644 index 0000000000000..529f4179a8f7e --- /dev/null +++ b/tests/compile-fail/panic/bad_unwind.stderr @@ -0,0 +1,25 @@ +thread 'main' panicked at 'explicit panic', $DIR/bad_unwind.rs:LL:CC +note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace +error: Undefined Behavior: unwinding past a stack frame that does not allow unwinding + --> $DIR/bad_unwind.rs:LL:CC + | +LL | std::panic::catch_unwind(|| unwind()).unwrap_err(); + | ^^^^^^^^ unwinding past a stack frame that does not allow unwinding + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside closure at $DIR/bad_unwind.rs:LL:CC + = note: inside `std::panicking::r#try::do_call::<[closure@$DIR/bad_unwind.rs:LL:CC: 13:41], ()>` at rustc_src/src/panicking.rs:LL:CC + = note: inside `std::panicking::r#try::<(), [closure@$DIR/bad_unwind.rs:LL:CC: 13:41]>` at rustc_src/src/panicking.rs:LL:CC + = note: inside `std::panic::catch_unwind::<[closure@$DIR/bad_unwind.rs:LL:CC: 13:41], ()>` at rustc_src/src/panic.rs:LL:CC +note: inside `main` at $DIR/bad_unwind.rs:LL:CC + --> $DIR/bad_unwind.rs:LL:CC + | +LL | std::panic::catch_unwind(|| unwind()).unwrap_err(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/panic/double_panic.stderr b/tests/compile-fail/panic/double_panic.stderr new file mode 100644 index 0000000000000..b854a6b721589 --- /dev/null +++ b/tests/compile-fail/panic/double_panic.stderr @@ -0,0 +1,91 @@ +thread 'main' panicked at 'first', $DIR/double_panic.rs:LL:CC +note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace +thread 'main' panicked at 'second', $DIR/double_panic.rs:LL:CC +stack backtrace: + 0: std::backtrace_rs::backtrace::miri::trace_unsynchronized + at rustc_src/src/../../backtrace/src/backtrace/miri.rs:LL:CC + 1: std::backtrace_rs::backtrace::miri::trace + at rustc_src/src/../../backtrace/src/backtrace/miri.rs:LL:CC + 2: std::backtrace_rs::backtrace::trace_unsynchronized + at rustc_src/src/../../backtrace/src/backtrace/mod.rs:LL:CC + 3: std::sys_common::backtrace::_print_fmt + at rustc_src/src/sys_common/backtrace.rs:LL:CC + 4: ::fmt + at rustc_src/src/sys_common/backtrace.rs:LL:CC + 5: std::fmt::write + at rustc_src/src/fmt/mod.rs:LL:CC + 6: ::write_fmt + at rustc_src/src/io/mod.rs:LL:CC + 7: std::sys_common::backtrace::_print + at rustc_src/src/sys_common/backtrace.rs:LL:CC + 8: std::sys_common::backtrace::print + at rustc_src/src/sys_common/backtrace.rs:LL:CC + 9: std::panicking::default_hook::{closure#1} + at rustc_src/src/panicking.rs:LL:CC + 10: std::panicking::default_hook + at rustc_src/src/panicking.rs:LL:CC + 11: std::panicking::rust_panic_with_hook + at rustc_src/src/panicking.rs:LL:CC + 12: std::rt::begin_panic::{closure#0} + at rustc_src/src/panicking.rs:LL:CC + 13: std::sys_common::backtrace::__rust_end_short_backtrace + at rustc_src/src/sys_common/backtrace.rs:LL:CC + 14: std::rt::begin_panic + at rustc_src/src/panicking.rs:LL:CC + 15: ::drop + at $DIR/double_panic.rs:LL:CC + 16: std::ptr::drop_in_place - shim(Some(Foo)) + at rustc_src/src/ptr/mod.rs:LL:CC + 17: main + at $DIR/double_panic.rs:LL:CC + 18: >::call_once - shim(fn()) + at rustc_src/src/ops/function.rs:LL:CC + 19: std::sys_common::backtrace::__rust_begin_short_backtrace + at rustc_src/src/sys_common/backtrace.rs:LL:CC + 20: std::rt::lang_start::{closure#0} + at rustc_src/src/rt.rs:LL:CC + 21: std::ops::function::impls::call_once + at rustc_src/src/ops/function.rs:LL:CC + 22: std::panicking::r#try::do_call + at rustc_src/src/panicking.rs:LL:CC + 23: std::panicking::r#try + at rustc_src/src/panicking.rs:LL:CC + 24: std::panic::catch_unwind + at rustc_src/src/panic.rs:LL:CC + 25: std::rt::lang_start_internal::{closure#2} + at rustc_src/src/rt.rs:LL:CC + 26: std::panicking::r#try::do_call + at rustc_src/src/panicking.rs:LL:CC + 27: std::panicking::r#try + at rustc_src/src/panicking.rs:LL:CC + 28: std::panic::catch_unwind + at rustc_src/src/panic.rs:LL:CC + 29: std::rt::lang_start_internal + at rustc_src/src/rt.rs:LL:CC + 30: std::rt::lang_start + at rustc_src/src/rt.rs:LL:CC +thread panicked while panicking. aborting. +error: abnormal termination: the program aborted execution + | + = note: inside `std::sys::PLATFORM::abort_internal` at rustc_src/src/sys/PLATFORM/mod.rs:LL:CC + = note: inside `std::panicking::rust_panic_with_hook` at rustc_src/src/panicking.rs:LL:CC + = note: inside closure at rustc_src/src/panicking.rs:LL:CC + = note: inside `std::sys_common::backtrace::__rust_end_short_backtrace::<[closure@std::rt::begin_panic<&str>::{closure#0}], !>` at rustc_src/src/sys_common/backtrace.rs:LL:CC + = note: inside `std::rt::begin_panic::<&str>` at rustc_src/src/panicking.rs:LL:CC +note: inside `::drop` at rustc_src/src/panic.rs:LL:CC + --> $DIR/double_panic.rs:LL:CC + | +LL | panic!("second"); + | ^^^^^^^^^^^^^^^^ + = note: inside `std::ptr::drop_in_place:: - shim(Some(Foo))` at rustc_src/src/ptr/mod.rs:LL:CC +note: inside `main` at $DIR/double_panic.rs:LL:CC + --> $DIR/double_panic.rs:LL:CC + | +LL | } + | ^ + = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/panic/panic_abort1.stderr b/tests/compile-fail/panic/panic_abort1.stderr new file mode 100644 index 0000000000000..93f48bb89e3bc --- /dev/null +++ b/tests/compile-fail/panic/panic_abort1.stderr @@ -0,0 +1,22 @@ +thread 'main' panicked at 'panicking from libstd', $DIR/panic_abort1.rs:LL:CC +note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace +error: abnormal termination: the program aborted execution + | + = note: inside `panic_abort::__rust_start_panic::abort` at rustc_src/src/lib.rs:LL:CC + = note: inside `panic_abort::__rust_start_panic` at rustc_src/src/lib.rs:LL:CC + = note: inside `std::panicking::rust_panic` at rustc_src/src/panicking.rs:LL:CC + = note: inside `std::panicking::rust_panic_with_hook` at rustc_src/src/panicking.rs:LL:CC + = note: inside closure at rustc_src/src/panicking.rs:LL:CC + = note: inside `std::sys_common::backtrace::__rust_end_short_backtrace::<[closure@std::rt::begin_panic<&str>::{closure#0}], !>` at rustc_src/src/sys_common/backtrace.rs:LL:CC + = note: inside `std::rt::begin_panic::<&str>` at rustc_src/src/panicking.rs:LL:CC +note: inside `main` at rustc_src/src/panic.rs:LL:CC + --> $DIR/panic_abort1.rs:LL:CC + | +LL | std::panic!("panicking from libstd"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/panic/panic_abort2.stderr b/tests/compile-fail/panic/panic_abort2.stderr new file mode 100644 index 0000000000000..bb4b96fd0aebd --- /dev/null +++ b/tests/compile-fail/panic/panic_abort2.stderr @@ -0,0 +1,23 @@ +thread 'main' panicked at '42-panicking from libstd', $DIR/panic_abort2.rs:LL:CC +note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace +error: abnormal termination: the program aborted execution + | + = note: inside `panic_abort::__rust_start_panic::abort` at rustc_src/src/lib.rs:LL:CC + = note: inside `panic_abort::__rust_start_panic` at rustc_src/src/lib.rs:LL:CC + = note: inside `std::panicking::rust_panic` at rustc_src/src/panicking.rs:LL:CC + = note: inside `std::panicking::rust_panic_with_hook` at rustc_src/src/panicking.rs:LL:CC + = note: inside closure at rustc_src/src/panicking.rs:LL:CC + = note: inside `std::sys_common::backtrace::__rust_end_short_backtrace::<[closure@std::panicking::begin_panic_handler::{closure#0}], !>` at rustc_src/src/sys_common/backtrace.rs:LL:CC + = note: inside `std::panicking::begin_panic_handler` at rustc_src/src/panicking.rs:LL:CC + = note: inside `std::rt::panic_fmt` at rustc_src/src/panicking.rs:LL:CC +note: inside `main` at rustc_src/src/panic.rs:LL:CC + --> $DIR/panic_abort2.rs:LL:CC + | +LL | std::panic!("{}-panicking from libstd", 42); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/panic/panic_abort3.stderr b/tests/compile-fail/panic/panic_abort3.stderr new file mode 100644 index 0000000000000..a799ce4b4de9f --- /dev/null +++ b/tests/compile-fail/panic/panic_abort3.stderr @@ -0,0 +1,24 @@ +thread 'main' panicked at 'panicking from libcore', $DIR/panic_abort3.rs:LL:CC +note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace +error: abnormal termination: the program aborted execution + | + = note: inside `panic_abort::__rust_start_panic::abort` at rustc_src/src/lib.rs:LL:CC + = note: inside `panic_abort::__rust_start_panic` at rustc_src/src/lib.rs:LL:CC + = note: inside `std::panicking::rust_panic` at rustc_src/src/panicking.rs:LL:CC + = note: inside `std::panicking::rust_panic_with_hook` at rustc_src/src/panicking.rs:LL:CC + = note: inside closure at rustc_src/src/panicking.rs:LL:CC + = note: inside `std::sys_common::backtrace::__rust_end_short_backtrace::<[closure@std::panicking::begin_panic_handler::{closure#0}], !>` at rustc_src/src/sys_common/backtrace.rs:LL:CC + = note: inside `std::panicking::begin_panic_handler` at rustc_src/src/panicking.rs:LL:CC + = note: inside `std::rt::panic_fmt` at rustc_src/src/panicking.rs:LL:CC + = note: inside `core::panicking::panic` at rustc_src/src/panicking.rs:LL:CC +note: inside `main` at rustc_src/src/panic.rs:LL:CC + --> $DIR/panic_abort3.rs:LL:CC + | +LL | core::panic!("panicking from libcore"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/panic/panic_abort4.stderr b/tests/compile-fail/panic/panic_abort4.stderr new file mode 100644 index 0000000000000..a24d0948d1cf6 --- /dev/null +++ b/tests/compile-fail/panic/panic_abort4.stderr @@ -0,0 +1,23 @@ +thread 'main' panicked at '42-panicking from libcore', $DIR/panic_abort4.rs:LL:CC +note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace +error: abnormal termination: the program aborted execution + | + = note: inside `panic_abort::__rust_start_panic::abort` at rustc_src/src/lib.rs:LL:CC + = note: inside `panic_abort::__rust_start_panic` at rustc_src/src/lib.rs:LL:CC + = note: inside `std::panicking::rust_panic` at rustc_src/src/panicking.rs:LL:CC + = note: inside `std::panicking::rust_panic_with_hook` at rustc_src/src/panicking.rs:LL:CC + = note: inside closure at rustc_src/src/panicking.rs:LL:CC + = note: inside `std::sys_common::backtrace::__rust_end_short_backtrace::<[closure@std::panicking::begin_panic_handler::{closure#0}], !>` at rustc_src/src/sys_common/backtrace.rs:LL:CC + = note: inside `std::panicking::begin_panic_handler` at rustc_src/src/panicking.rs:LL:CC + = note: inside `std::rt::panic_fmt` at rustc_src/src/panicking.rs:LL:CC +note: inside `main` at rustc_src/src/panic.rs:LL:CC + --> $DIR/panic_abort4.rs:LL:CC + | +LL | core::panic!("{}-panicking from libcore", 42); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/panic/unwind_panic_abort.stderr b/tests/compile-fail/panic/unwind_panic_abort.stderr new file mode 100644 index 0000000000000..7ae965156f007 --- /dev/null +++ b/tests/compile-fail/panic/unwind_panic_abort.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: unwinding past a stack frame that does not allow unwinding + --> $DIR/unwind_panic_abort.rs:LL:CC + | +LL | unsafe { miri_start_panic(&mut 0); } + | ^^^^^^^^^^^^^^^^^^^^^^^^ unwinding past a stack frame that does not allow unwinding + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/unwind_panic_abort.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/pointer_partial_overwrite.stderr b/tests/compile-fail/pointer_partial_overwrite.stderr new file mode 100644 index 0000000000000..6779df99c3fbf --- /dev/null +++ b/tests/compile-fail/pointer_partial_overwrite.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory + --> $DIR/pointer_partial_overwrite.rs:LL:CC + | +LL | let x = *p; + | ^^ using uninitialized data, but this operation requires initialized memory + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/pointer_partial_overwrite.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/pointer_partial_read.stderr b/tests/compile-fail/pointer_partial_read.stderr new file mode 100644 index 0000000000000..dc35f7e109a54 --- /dev/null +++ b/tests/compile-fail/pointer_partial_read.stderr @@ -0,0 +1,14 @@ +error: unsupported operation: unable to turn pointer into raw bytes + --> $DIR/pointer_partial_read.rs:LL:CC + | +LL | let _val = unsafe { *z }; + | ^^ unable to turn pointer into raw bytes + | + = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support + + = note: inside `main` at $DIR/pointer_partial_read.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/provenance/ptr_int_unexposed.stderr b/tests/compile-fail/provenance/ptr_int_unexposed.stderr new file mode 100644 index 0000000000000..cdd25d0e638ef --- /dev/null +++ b/tests/compile-fail/provenance/ptr_int_unexposed.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: dereferencing pointer failed: $HEX is not a valid pointer + --> $DIR/ptr_int_unexposed.rs:LL:CC + | +LL | assert_eq!(unsafe { *ptr }, 3); + | ^^^^ dereferencing pointer failed: $HEX is not a valid pointer + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/ptr_int_unexposed.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/provenance/ptr_invalid.stderr b/tests/compile-fail/provenance/ptr_invalid.stderr new file mode 100644 index 0000000000000..76a40765eb2ff --- /dev/null +++ b/tests/compile-fail/provenance/ptr_invalid.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: dereferencing pointer failed: $HEX is not a valid pointer + --> $DIR/ptr_invalid.rs:LL:CC + | +LL | let _val = unsafe { *xptr_invalid }; + | ^^^^^^^^^^^^^ dereferencing pointer failed: $HEX is not a valid pointer + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/ptr_invalid.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/provenance/ptr_legacy_provenance.rs b/tests/compile-fail/provenance/ptr_legacy_provenance.rs index aecc1460e0853..538ec4484edb9 100644 --- a/tests/compile-fail/provenance/ptr_legacy_provenance.rs +++ b/tests/compile-fail/provenance/ptr_legacy_provenance.rs @@ -1,4 +1,5 @@ // compile-flags: -Zmiri-disable-stacked-borrows +// normalize-stderr-test: "offset -[0-9]+" -> "offset -XX" #![feature(strict_provenance)] use std::ptr; diff --git a/tests/compile-fail/provenance/ptr_legacy_provenance.stderr b/tests/compile-fail/provenance/ptr_legacy_provenance.stderr new file mode 100644 index 0000000000000..4552be08145d4 --- /dev/null +++ b/tests/compile-fail/provenance/ptr_legacy_provenance.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: dereferencing pointer failed: ALLOC has size 4, so pointer to 4 bytes starting at offset -XX is out-of-bounds + --> $DIR/ptr_legacy_provenance.rs:LL:CC + | +LL | assert_eq!(unsafe { *ptr }, 0); + | ^^^^ dereferencing pointer failed: ALLOC has size 4, so pointer to 4 bytes starting at offset -XX is out-of-bounds + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/ptr_legacy_provenance.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/provenance/strict-provenance-offset.stderr b/tests/compile-fail/provenance/strict-provenance-offset.stderr new file mode 100644 index 0000000000000..482b7a404c513 --- /dev/null +++ b/tests/compile-fail/provenance/strict-provenance-offset.stderr @@ -0,0 +1,16 @@ +error: Undefined Behavior: pointer arithmetic failed: $HEX is not a valid pointer + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `std::ptr::const_ptr::::offset` at rustc_src/src/ptr/const_ptr.rs:LL:CC +note: inside `main` at $DIR/strict-provenance-offset.rs:LL:CC + --> $DIR/strict-provenance-offset.rs:LL:CC + | +LL | let _ = unsafe { roundtrip.offset(1) }; + | ^^^^^^^^^^^^^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/provenance/strict_provenance_transmute.stderr b/tests/compile-fail/provenance/strict_provenance_transmute.stderr new file mode 100644 index 0000000000000..544431815c1bc --- /dev/null +++ b/tests/compile-fail/provenance/strict_provenance_transmute.stderr @@ -0,0 +1,20 @@ +error: Undefined Behavior: type validation failed: encountered pointer to $HEX[ALLOC], but expected plain (non-pointer) bytes + --> $DIR/strict_provenance_transmute.rs:LL:CC + | +LL | let left_int: usize = mem::transmute(left); + | ^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to $HEX[ALLOC], but expected plain (non-pointer) bytes + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `deref` at $DIR/strict_provenance_transmute.rs:LL:CC +note: inside `main` at $DIR/strict_provenance_transmute.rs:LL:CC + --> $DIR/strict_provenance_transmute.rs:LL:CC + | +LL | deref(ptr1, ptr2.with_addr(ptr1.addr())); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/ptr_integer_array_transmute.stderr b/tests/compile-fail/ptr_integer_array_transmute.stderr new file mode 100644 index 0000000000000..bc2ca54438ff9 --- /dev/null +++ b/tests/compile-fail/ptr_integer_array_transmute.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: type validation failed: encountered a pointer, but expected plain (non-pointer) bytes + --> $DIR/ptr_integer_array_transmute.rs:LL:CC + | +LL | let _i: [usize; 1] = unsafe { std::mem::transmute(r) }; + | ^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected plain (non-pointer) bytes + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/ptr_integer_array_transmute.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/ptr_integer_transmute.stderr b/tests/compile-fail/ptr_integer_transmute.stderr new file mode 100644 index 0000000000000..de9ebf4eb06b4 --- /dev/null +++ b/tests/compile-fail/ptr_integer_transmute.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: type validation failed: encountered pointer to $HEX[ALLOC], but expected initialized plain (non-pointer) bytes + --> $DIR/ptr_integer_transmute.rs:LL:CC + | +LL | let _i: usize = unsafe { std::mem::transmute(r) }; + | ^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to $HEX[ALLOC], but expected initialized plain (non-pointer) bytes + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/ptr_integer_transmute.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/rc_as_ptr.stderr b/tests/compile-fail/rc_as_ptr.stderr new file mode 100644 index 0000000000000..3d745b7dc5c94 --- /dev/null +++ b/tests/compile-fail/rc_as_ptr.stderr @@ -0,0 +1,16 @@ +error: Undefined Behavior: pointer to ALLOC was dereferenced after this allocation got freed + --> $DIR/rc_as_ptr.rs:LL:CC + | +LL | assert_eq!(42, **unsafe { &*Weak::as_ptr(&weak) }); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pointer to ALLOC was dereferenced after this allocation got freed + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at rustc_src/src/macros/mod.rs:LL:CC + = note: this error originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info) + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/reading_half_a_pointer.stderr b/tests/compile-fail/reading_half_a_pointer.stderr new file mode 100644 index 0000000000000..505c8deafb6d5 --- /dev/null +++ b/tests/compile-fail/reading_half_a_pointer.stderr @@ -0,0 +1,14 @@ +error: unsupported operation: unable to turn pointer into raw bytes + --> $DIR/reading_half_a_pointer.rs:LL:CC + | +LL | let _x = *d_alias; + | ^^^^^^^^ unable to turn pointer into raw bytes + | + = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support + + = note: inside `main` at $DIR/reading_half_a_pointer.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/rustc-error.stderr b/tests/compile-fail/rustc-error.stderr new file mode 100644 index 0000000000000..09d0f7a6df955 --- /dev/null +++ b/tests/compile-fail/rustc-error.stderr @@ -0,0 +1,14 @@ +error[E0423]: expected function, found macro `println` + --> $DIR/rustc-error.rs:LL:CC + | +LL | println("Hello, world!"); + | ^^^^^^^ not a function + | +help: use `!` to invoke the macro + | +LL | println!("Hello, world!"); + | + + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0423`. diff --git a/tests/compile-fail/shim_arg_size.32bit.stderr b/tests/compile-fail/shim_arg_size.32bit.stderr new file mode 100644 index 0000000000000..3b54a5b512481 --- /dev/null +++ b/tests/compile-fail/shim_arg_size.32bit.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: scalar size mismatch: expected 4 bytes but got 2 bytes instead + --> $DIR/shim_arg_size.rs:LL:CC + | +LL | let _p1 = malloc(42); + | ^^^^^^^^^^ scalar size mismatch: expected 4 bytes but got 2 bytes instead + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/shim_arg_size.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/shim_arg_size.64bit.stderr b/tests/compile-fail/shim_arg_size.64bit.stderr new file mode 100644 index 0000000000000..5e33604c121d6 --- /dev/null +++ b/tests/compile-fail/shim_arg_size.64bit.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: scalar size mismatch: expected 8 bytes but got 4 bytes instead + --> $DIR/shim_arg_size.rs:LL:CC + | +LL | let _p1 = malloc(42); + | ^^^^^^^^^^ scalar size mismatch: expected 8 bytes but got 4 bytes instead + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/shim_arg_size.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/shim_arg_size.rs b/tests/compile-fail/shim_arg_size.rs index 556195d6e9050..1297e5ed070f6 100644 --- a/tests/compile-fail/shim_arg_size.rs +++ b/tests/compile-fail/shim_arg_size.rs @@ -1,3 +1,5 @@ +// stderr-per-bitwidth + fn main() { extern "C" { // Use the wrong type(ie. not the pointer width) for the `size` diff --git a/tests/compile-fail/slice-too-big.stderr b/tests/compile-fail/slice-too-big.stderr new file mode 100644 index 0000000000000..13239506c633f --- /dev/null +++ b/tests/compile-fail/slice-too-big.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: type validation failed: encountered invalid reference metadata: slice is bigger than largest supported object + --> $DIR/slice-too-big.rs:5:21 + | +LL | let _x: &[u8] = mem::transmute((ptr, usize::MAX)); //~ ERROR: invalid reference metadata: slice is bigger than largest supported object + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered invalid reference metadata: slice is bigger than largest supported object + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/slice-too-big.rs:5:21 + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/stacked_borrows/alias_through_mutation.stderr b/tests/compile-fail/stacked_borrows/alias_through_mutation.stderr new file mode 100644 index 0000000000000..6862a67faec26 --- /dev/null +++ b/tests/compile-fail/stacked_borrows/alias_through_mutation.stderr @@ -0,0 +1,27 @@ +error: Undefined Behavior: attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + --> $DIR/alias_through_mutation.rs:LL:CC + | +LL | let _val = *target_alias; + | ^^^^^^^^^^^^^ + | | + | attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | this error occurs as part of an access at ALLOC[0x0..0x4] + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information +help: was created by a retag at offsets [0x0..0x4] + --> $DIR/alias_through_mutation.rs:LL:CC + | +LL | unsafe { *x = &mut *(target as *mut _); } + | ^^^^^^^^^^^^^^^^^^^^^^^^ +help: was later invalidated at offsets [0x0..0x4] + --> $DIR/alias_through_mutation.rs:LL:CC + | +LL | *target = 13; + | ^^^^^^^^^^^^ + = note: inside `main` at $DIR/alias_through_mutation.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/stacked_borrows/aliasing_mut1.stderr b/tests/compile-fail/stacked_borrows/aliasing_mut1.stderr new file mode 100644 index 0000000000000..5f2e5cbbad36f --- /dev/null +++ b/tests/compile-fail/stacked_borrows/aliasing_mut1.stderr @@ -0,0 +1,34 @@ +error: Undefined Behavior: not granting access to tag because incompatible item is protected: [Unique for (call ID)] + --> $DIR/aliasing_mut1.rs:LL:CC + | +LL | pub fn safe(_x: &mut i32, _y: &mut i32) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not granting access to tag because incompatible item is protected: [Unique for (call ID)] + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information +help: was created by a retag at offsets [0x0..0x4] + --> $DIR/aliasing_mut1.rs:LL:CC + | +LL | let xraw: *mut i32 = unsafe { mem::transmute(&mut x) }; + | ^^^^^^ +help: was protected due to which was created here + --> $DIR/aliasing_mut1.rs:LL:CC + | +LL | let xraw: *mut i32 = unsafe { mem::transmute(&mut x) }; + | ^^^^^^ +help: this protector is live for this call + --> $DIR/aliasing_mut1.rs:LL:CC + | +LL | pub fn safe(_x: &mut i32, _y: &mut i32) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: inside `safe` at $DIR/aliasing_mut1.rs:LL:CC +note: inside `main` at $DIR/aliasing_mut1.rs:LL:CC + --> $DIR/aliasing_mut1.rs:LL:CC + | +LL | safe_raw(xraw, xraw); + | ^^^^^^^^^^^^^^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/stacked_borrows/aliasing_mut2.stderr b/tests/compile-fail/stacked_borrows/aliasing_mut2.stderr new file mode 100644 index 0000000000000..bb82252e78d42 --- /dev/null +++ b/tests/compile-fail/stacked_borrows/aliasing_mut2.stderr @@ -0,0 +1,34 @@ +error: Undefined Behavior: not granting access to tag because incompatible item is protected: [SharedReadOnly for (call ID)] + --> $DIR/aliasing_mut2.rs:LL:CC + | +LL | pub fn safe(_x: &i32, _y: &mut i32) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not granting access to tag because incompatible item is protected: [SharedReadOnly for (call ID)] + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information +help: was created by a retag at offsets [0x0..0x4] + --> $DIR/aliasing_mut2.rs:LL:CC + | +LL | let xref = &mut x; + | ^^^^^^ +help: was protected due to which was created here + --> $DIR/aliasing_mut2.rs:LL:CC + | +LL | safe_raw(xshr, xraw); + | ^^^^ +help: this protector is live for this call + --> $DIR/aliasing_mut2.rs:LL:CC + | +LL | pub fn safe(_x: &i32, _y: &mut i32) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: inside `safe` at $DIR/aliasing_mut2.rs:LL:CC +note: inside `main` at $DIR/aliasing_mut2.rs:LL:CC + --> $DIR/aliasing_mut2.rs:LL:CC + | +LL | safe_raw(xshr, xraw); + | ^^^^^^^^^^^^^^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/stacked_borrows/aliasing_mut3.stderr b/tests/compile-fail/stacked_borrows/aliasing_mut3.stderr new file mode 100644 index 0000000000000..0cfddcac84868 --- /dev/null +++ b/tests/compile-fail/stacked_borrows/aliasing_mut3.stderr @@ -0,0 +1,32 @@ +error: Undefined Behavior: trying to reborrow for SharedReadOnly permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + --> $DIR/aliasing_mut3.rs:LL:CC + | +LL | pub fn safe(_x: &mut i32, _y: &i32) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | trying to reborrow for SharedReadOnly permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | this error occurs as part of a reborrow at ALLOC[0x0..0x4] + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information +help: tag was most recently created at offsets [0x0..0x4] + --> $DIR/aliasing_mut3.rs:LL:CC + | +LL | safe_raw(xraw, xshr); + | ^^^^ +help: tag was later invalidated at offsets [0x0..0x4] + --> $DIR/aliasing_mut3.rs:LL:CC + | +LL | pub fn safe(_x: &mut i32, _y: &i32) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: inside `safe` at $DIR/aliasing_mut3.rs:LL:CC +note: inside `main` at $DIR/aliasing_mut3.rs:LL:CC + --> $DIR/aliasing_mut3.rs:LL:CC + | +LL | safe_raw(xraw, xshr); + | ^^^^^^^^^^^^^^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/stacked_borrows/aliasing_mut4.stderr b/tests/compile-fail/stacked_borrows/aliasing_mut4.stderr new file mode 100644 index 0000000000000..13b589b94754f --- /dev/null +++ b/tests/compile-fail/stacked_borrows/aliasing_mut4.stderr @@ -0,0 +1,34 @@ +error: Undefined Behavior: not granting access to tag because incompatible item is protected: [SharedReadOnly for (call ID)] + --> $DIR/aliasing_mut4.rs:LL:CC + | +LL | pub fn safe(_x: &i32, _y: &mut Cell) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not granting access to tag because incompatible item is protected: [SharedReadOnly for (call ID)] + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information +help: was created by a retag at offsets [0x0..0x4] + --> $DIR/aliasing_mut4.rs:LL:CC + | +LL | let xref = &mut x; + | ^^^^^^ +help: was protected due to which was created here + --> $DIR/aliasing_mut4.rs:LL:CC + | +LL | safe_raw(xshr, xraw as *mut _); + | ^^^^ +help: this protector is live for this call + --> $DIR/aliasing_mut4.rs:LL:CC + | +LL | pub fn safe(_x: &i32, _y: &mut Cell) {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: inside `safe` at $DIR/aliasing_mut4.rs:LL:CC +note: inside `main` at $DIR/aliasing_mut4.rs:LL:CC + --> $DIR/aliasing_mut4.rs:LL:CC + | +LL | safe_raw(xshr, xraw as *mut _); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/stacked_borrows/box_exclusive_violation1.stderr b/tests/compile-fail/stacked_borrows/box_exclusive_violation1.stderr new file mode 100644 index 0000000000000..94d4509553484 --- /dev/null +++ b/tests/compile-fail/stacked_borrows/box_exclusive_violation1.stderr @@ -0,0 +1,38 @@ +error: Undefined Behavior: attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + --> $DIR/box_exclusive_violation1.rs:LL:CC + | +LL | *our + | ^^^^ + | | + | attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | this error occurs as part of an access at ALLOC[0x0..0x4] + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information +help: was created by a retag at offsets [0x0..0x4] + --> $DIR/box_exclusive_violation1.rs:LL:CC + | +LL | / fn demo_mut_advanced_unique(mut our: Box) -> i32 { +LL | | unknown_code_1(&*our); +LL | | +LL | | // This "re-asserts" uniqueness of the reference: After writing, we know +... | +LL | | *our +LL | | } + | |_^ +help: was later invalidated at offsets [0x0..0x4] + --> $DIR/box_exclusive_violation1.rs:LL:CC + | +LL | *LEAK = 7; + | ^^^^^^^^^ + = note: inside `demo_mut_advanced_unique` at $DIR/box_exclusive_violation1.rs:LL:CC +note: inside `main` at $DIR/box_exclusive_violation1.rs:LL:CC + --> $DIR/box_exclusive_violation1.rs:LL:CC + | +LL | demo_mut_advanced_unique(Box::new(0)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/stacked_borrows/buggy_as_mut_slice.stderr b/tests/compile-fail/stacked_borrows/buggy_as_mut_slice.stderr new file mode 100644 index 0000000000000..8eed3732a0cb0 --- /dev/null +++ b/tests/compile-fail/stacked_borrows/buggy_as_mut_slice.stderr @@ -0,0 +1,27 @@ +error: Undefined Behavior: attempting a write access using at ALLOC[0x4], but that tag does not exist in the borrow stack for this location + --> $DIR/buggy_as_mut_slice.rs:LL:CC + | +LL | v1[1] = 5; + | ^^^^^^^^^ + | | + | attempting a write access using at ALLOC[0x4], but that tag does not exist in the borrow stack for this location + | this error occurs as part of an access at ALLOC[0x4..0x8] + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information +help: was created by a retag at offsets [0x0..0xc] + --> $DIR/buggy_as_mut_slice.rs:LL:CC + | +LL | let v1 = safe::as_mut_slice(&v); + | ^^^^^^^^^^^^^^^^^^^^^^ +help: was later invalidated at offsets [0x0..0xc] + --> $DIR/buggy_as_mut_slice.rs:LL:CC + | +LL | from_raw_parts_mut(self_.as_ptr() as *mut T, self_.len()) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: inside `main` at $DIR/buggy_as_mut_slice.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/stacked_borrows/buggy_split_at_mut.stderr b/tests/compile-fail/stacked_borrows/buggy_split_at_mut.stderr new file mode 100644 index 0000000000000..d1d8d1f6aa3c9 --- /dev/null +++ b/tests/compile-fail/stacked_borrows/buggy_split_at_mut.stderr @@ -0,0 +1,27 @@ +error: Undefined Behavior: trying to reborrow for Unique permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + --> $DIR/buggy_split_at_mut.rs:LL:CC + | +LL | let (a, b) = safe::split_at_mut(&mut array, 0); + | ^ + | | + | trying to reborrow for Unique permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | this error occurs as part of a reborrow at ALLOC[0x0..0x10] + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information +help: was created by a retag at offsets [0x0..0x10] + --> $DIR/buggy_split_at_mut.rs:LL:CC + | +LL | (from_raw_parts_mut(ptr, len - mid), // BUG: should be "mid" instead of "len - mid" + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: was later invalidated at offsets [0x0..0x10] + --> $DIR/buggy_split_at_mut.rs:LL:CC + | +LL | from_raw_parts_mut(ptr.offset(mid as isize), len - mid)) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: inside `main` at $DIR/buggy_split_at_mut.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/stacked_borrows/deallocate_against_barrier1.stderr b/tests/compile-fail/stacked_borrows/deallocate_against_barrier1.stderr new file mode 100644 index 0000000000000..593419fe9b377 --- /dev/null +++ b/tests/compile-fail/stacked_borrows/deallocate_against_barrier1.stderr @@ -0,0 +1,34 @@ +error: Undefined Behavior: deallocating while item is protected: [Unique for (call ID)] + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information + + = note: inside `std::alloc::dealloc` at rustc_src/src/alloc.rs:LL:CC + = note: inside `::deallocate` at rustc_src/src/alloc.rs:LL:CC + = note: inside `alloc::alloc::box_free::` at rustc_src/src/alloc.rs:LL:CC + = note: inside `std::ptr::drop_in_place::> - shim(Some(std::boxed::Box))` at rustc_src/src/ptr/mod.rs:LL:CC + = note: inside `std::mem::drop::>` at rustc_src/src/mem/mod.rs:LL:CC +note: inside closure at $DIR/deallocate_against_barrier1.rs:LL:CC + --> $DIR/deallocate_against_barrier1.rs:LL:CC + | +LL | drop(unsafe { Box::from_raw(raw) }); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: inside `<[closure@$DIR/deallocate_against_barrier1.rs:LL:CC: 12:6] as std::ops::FnOnce<(&mut i32,)>>::call_once - shim` at rustc_src/src/ops/function.rs:LL:CC +note: inside `inner` at $DIR/deallocate_against_barrier1.rs:LL:CC + --> $DIR/deallocate_against_barrier1.rs:LL:CC + | +LL | f(x) + | ^^^^ +note: inside `main` at $DIR/deallocate_against_barrier1.rs:LL:CC + --> $DIR/deallocate_against_barrier1.rs:LL:CC + | +LL | / inner(Box::leak(Box::new(0)), |x| { +LL | | let raw = x as *mut _; +LL | | drop(unsafe { Box::from_raw(raw) }); +LL | | }); + | |______^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/stacked_borrows/deallocate_against_barrier2.stderr b/tests/compile-fail/stacked_borrows/deallocate_against_barrier2.stderr new file mode 100644 index 0000000000000..f6734db715880 --- /dev/null +++ b/tests/compile-fail/stacked_borrows/deallocate_against_barrier2.stderr @@ -0,0 +1,34 @@ +error: Undefined Behavior: deallocating while item is protected: [SharedReadWrite for (call ID)] + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information + + = note: inside `std::alloc::dealloc` at rustc_src/src/alloc.rs:LL:CC + = note: inside `::deallocate` at rustc_src/src/alloc.rs:LL:CC + = note: inside `alloc::alloc::box_free::, std::alloc::Global>` at rustc_src/src/alloc.rs:LL:CC + = note: inside `std::ptr::drop_in_place::>> - shim(Some(std::boxed::Box>))` at rustc_src/src/ptr/mod.rs:LL:CC + = note: inside `std::mem::drop::>>` at rustc_src/src/mem/mod.rs:LL:CC +note: inside closure at $DIR/deallocate_against_barrier2.rs:LL:CC + --> $DIR/deallocate_against_barrier2.rs:LL:CC + | +LL | drop(unsafe { Box::from_raw(raw) }); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: inside `<[closure@$DIR/deallocate_against_barrier2.rs:LL:CC: 16:6] as std::ops::FnOnce<(&std::cell::Cell,)>>::call_once - shim` at rustc_src/src/ops/function.rs:LL:CC +note: inside `inner` at $DIR/deallocate_against_barrier2.rs:LL:CC + --> $DIR/deallocate_against_barrier2.rs:LL:CC + | +LL | f(x) + | ^^^^ +note: inside `main` at $DIR/deallocate_against_barrier2.rs:LL:CC + --> $DIR/deallocate_against_barrier2.rs:LL:CC + | +LL | / inner(Box::leak(Box::new(Cell::new(0))), |x| { +LL | | let raw = x as *const _ as *mut Cell; +LL | | drop(unsafe { Box::from_raw(raw) }); +LL | | }); + | |______^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/stacked_borrows/illegal_read1.stderr b/tests/compile-fail/stacked_borrows/illegal_read1.stderr new file mode 100644 index 0000000000000..ca3147e6221ec --- /dev/null +++ b/tests/compile-fail/stacked_borrows/illegal_read1.stderr @@ -0,0 +1,27 @@ +error: Undefined Behavior: attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + --> $DIR/illegal_read1.rs:LL:CC + | +LL | let _val = *xref; // ...but any use of raw will invalidate our ref. + | ^^^^^ + | | + | attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | this error occurs as part of an access at ALLOC[0x0..0x4] + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information +help: was created by a retag at offsets [0x0..0x4] + --> $DIR/illegal_read1.rs:LL:CC + | +LL | let xref = unsafe { &mut *xraw }; // derived from raw, so using raw is still ok... + | ^^^^^^^^^^ +help: was later invalidated at offsets [0x0..0x4] + --> $DIR/illegal_read1.rs:LL:CC + | +LL | let _val = unsafe { *xraw }; + | ^^^^^ + = note: inside `main` at $DIR/illegal_read1.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/stacked_borrows/illegal_read2.stderr b/tests/compile-fail/stacked_borrows/illegal_read2.stderr new file mode 100644 index 0000000000000..b6343ddd30b64 --- /dev/null +++ b/tests/compile-fail/stacked_borrows/illegal_read2.stderr @@ -0,0 +1,27 @@ +error: Undefined Behavior: attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + --> $DIR/illegal_read2.rs:LL:CC + | +LL | let _val = *xref; // ...but any use of raw will invalidate our ref. + | ^^^^^ + | | + | attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | this error occurs as part of an access at ALLOC[0x0..0x4] + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information +help: was created by a retag at offsets [0x0..0x4] + --> $DIR/illegal_read2.rs:LL:CC + | +LL | let xref = unsafe { &mut *xraw }; // derived from raw, so using raw is still ok... + | ^^^^^^^^^^ +help: was later invalidated at offsets [0x0..0x4] + --> $DIR/illegal_read2.rs:LL:CC + | +LL | let shr = unsafe { &*xraw }; + | ^^^^^^ + = note: inside `main` at $DIR/illegal_read2.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/stacked_borrows/illegal_read3.stderr b/tests/compile-fail/stacked_borrows/illegal_read3.stderr new file mode 100644 index 0000000000000..ab26696a765c6 --- /dev/null +++ b/tests/compile-fail/stacked_borrows/illegal_read3.stderr @@ -0,0 +1,27 @@ +error: Undefined Behavior: attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + --> $DIR/illegal_read3.rs:LL:CC + | +LL | let _val = *xref2; + | ^^^^^^ + | | + | attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | this error occurs as part of an access at ALLOC[0x0..0x4] + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information +help: was created by a retag at offsets [0x0..0x4] + --> $DIR/illegal_read3.rs:LL:CC + | +LL | let xref2 = &mut *xref1; + | ^^^^^^^^^^^ +help: was later invalidated at offsets [0x0..0x4] + --> $DIR/illegal_read3.rs:LL:CC + | +LL | let _val = unsafe { *xref1.to }; + | ^^^^^^^^^ + = note: inside `main` at $DIR/illegal_read3.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/stacked_borrows/illegal_read4.stderr b/tests/compile-fail/stacked_borrows/illegal_read4.stderr new file mode 100644 index 0000000000000..968c31ba23af7 --- /dev/null +++ b/tests/compile-fail/stacked_borrows/illegal_read4.stderr @@ -0,0 +1,27 @@ +error: Undefined Behavior: attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + --> $DIR/illegal_read4.rs:LL:CC + | +LL | let _illegal = *xref2; + | ^^^^^^ + | | + | attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | this error occurs as part of an access at ALLOC[0x0..0x4] + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information +help: was created by a retag at offsets [0x0..0x4] + --> $DIR/illegal_read4.rs:LL:CC + | +LL | let xref2 = unsafe { &mut *xraw }; + | ^^^^^^^^^^ +help: was later invalidated at offsets [0x0..0x4] + --> $DIR/illegal_read4.rs:LL:CC + | +LL | let _val = unsafe { *xraw }; // use the raw again, this invalidates xref2 *even* with the special read except for uniq refs + | ^^^^^ + = note: inside `main` at $DIR/illegal_read4.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/stacked_borrows/illegal_read5.rs b/tests/compile-fail/stacked_borrows/illegal_read5.rs index d6120cd64ad00..58f506251de2c 100644 --- a/tests/compile-fail/stacked_borrows/illegal_read5.rs +++ b/tests/compile-fail/stacked_borrows/illegal_read5.rs @@ -1,5 +1,6 @@ // We *can* have aliasing &RefCell and &mut T, but we cannot read through the former. // Else we couldn't optimize based on the assumption that `xref` below is truly unique. +// normalize-stderr-test: "0x[0-9a-fA-F]+" -> "$$HEX" use std::cell::RefCell; use std::{mem, ptr}; diff --git a/tests/compile-fail/stacked_borrows/illegal_read5.stderr b/tests/compile-fail/stacked_borrows/illegal_read5.stderr new file mode 100644 index 0000000000000..df6f0a1c68862 --- /dev/null +++ b/tests/compile-fail/stacked_borrows/illegal_read5.stderr @@ -0,0 +1,27 @@ +error: Undefined Behavior: attempting a read access using at ALLOC[$HEX], but that tag does not exist in the borrow stack for this location + --> $DIR/illegal_read5.rs:LL:CC + | +LL | let _val = *xref; // the mutable one is dead and gone + | ^^^^^ + | | + | attempting a read access using at ALLOC[$HEX], but that tag does not exist in the borrow stack for this location + | this error occurs as part of an access at ALLOC[$HEX..$HEX] + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information +help: was created by a retag at offsets [$HEX..$HEX] + --> $DIR/illegal_read5.rs:LL:CC + | +LL | let xref: &mut i32 = &mut *refmut; + | ^^^^^^^^^^^^ +help: was later invalidated at offsets [$HEX..$HEX] + --> $DIR/illegal_read5.rs:LL:CC + | +LL | mem::forget(unsafe { ptr::read(xshr) }); // but after reading through the shared ref + | ^^^^^^^^^^^^^^^ + = note: inside `main` at $DIR/illegal_read5.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/stacked_borrows/illegal_read6.stderr b/tests/compile-fail/stacked_borrows/illegal_read6.stderr new file mode 100644 index 0000000000000..c2be5bb370c5a --- /dev/null +++ b/tests/compile-fail/stacked_borrows/illegal_read6.stderr @@ -0,0 +1,27 @@ +error: Undefined Behavior: attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + --> $DIR/illegal_read6.rs:LL:CC + | +LL | let _val = *raw; + | ^^^^ + | | + | attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | this error occurs as part of an access at ALLOC[0x0..0x4] + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information +help: tag was most recently created at offsets [0x0..0x4] + --> $DIR/illegal_read6.rs:LL:CC + | +LL | let raw = x as *mut _; + | ^ +help: tag was later invalidated at offsets [0x0..0x4] + --> $DIR/illegal_read6.rs:LL:CC + | +LL | let x = &mut *x; // kill `raw` + | ^^^^^^^ + = note: inside `main` at $DIR/illegal_read6.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/stacked_borrows/illegal_read7.stderr b/tests/compile-fail/stacked_borrows/illegal_read7.stderr new file mode 100644 index 0000000000000..921d8872b70b8 --- /dev/null +++ b/tests/compile-fail/stacked_borrows/illegal_read7.stderr @@ -0,0 +1,27 @@ +error: Undefined Behavior: trying to reborrow for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + --> $DIR/illegal_read7.rs:LL:CC + | +LL | let _val = *x.get_mut(); + | ^^^^^^^^^^^ + | | + | trying to reborrow for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | this error occurs as part of a reborrow at ALLOC[0x0..0x4] + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information +help: was created by a retag at offsets [0x0..0x4] + --> $DIR/illegal_read7.rs:LL:CC + | +LL | let x = &mut *raw; + | ^^^^^^^^^ +help: was later invalidated at offsets [0x0..0x4] + --> $DIR/illegal_read7.rs:LL:CC + | +LL | let _val = ptr::read(raw); + | ^^^^^^^^^^^^^^ + = note: inside `main` at $DIR/illegal_read7.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/stacked_borrows/illegal_read8.stderr b/tests/compile-fail/stacked_borrows/illegal_read8.stderr new file mode 100644 index 0000000000000..6c6168032b246 --- /dev/null +++ b/tests/compile-fail/stacked_borrows/illegal_read8.stderr @@ -0,0 +1,27 @@ +error: Undefined Behavior: attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + --> $DIR/illegal_read8.rs:LL:CC + | +LL | let _fail = *y1; + | ^^^ + | | + | attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | this error occurs as part of an access at ALLOC[0x0..0x4] + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information +help: was created by a retag at offsets [0x0..0x4] + --> $DIR/illegal_read8.rs:LL:CC + | +LL | let y1: &i32 = mem::transmute(&*x); // launder lifetimes + | ^^^^^^^^^^^^^^^^^^^ +help: was later invalidated at offsets [0x0..0x4] + --> $DIR/illegal_read8.rs:LL:CC + | +LL | *y2 += 1; + | ^^^^^^^^ + = note: inside `main` at $DIR/illegal_read8.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/stacked_borrows/illegal_write1.stderr b/tests/compile-fail/stacked_borrows/illegal_write1.stderr new file mode 100644 index 0000000000000..08fa05ff9f1ff --- /dev/null +++ b/tests/compile-fail/stacked_borrows/illegal_write1.stderr @@ -0,0 +1,27 @@ +error: Undefined Behavior: attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + --> $DIR/illegal_write1.rs:LL:CC + | +LL | let _x = *xref; + | ^^^^^ + | | + | attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | this error occurs as part of an access at ALLOC[0x0..0x4] + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information +help: was created by a retag at offsets [0x0..0x4] + --> $DIR/illegal_write1.rs:LL:CC + | +LL | let xref = &*target; + | ^^^^^^^^ +help: was later invalidated at offsets [0x0..0x4] + --> $DIR/illegal_write1.rs:LL:CC + | +LL | unsafe { *x = 42; } // invalidates shared ref, activates raw + | ^^^^^^^ + = note: inside `main` at $DIR/illegal_write1.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/stacked_borrows/illegal_write2.stderr b/tests/compile-fail/stacked_borrows/illegal_write2.stderr new file mode 100644 index 0000000000000..13f41eea91539 --- /dev/null +++ b/tests/compile-fail/stacked_borrows/illegal_write2.stderr @@ -0,0 +1,27 @@ +error: Undefined Behavior: attempting a write access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + --> $DIR/illegal_write2.rs:LL:CC + | +LL | unsafe { *target2 = 13; } + | ^^^^^^^^^^^^^ + | | + | attempting a write access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | this error occurs as part of an access at ALLOC[0x0..0x4] + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information +help: tag was most recently created at offsets [0x0..0x4] + --> $DIR/illegal_write2.rs:LL:CC + | +LL | let target2 = target as *mut _; + | ^^^^^^ +help: tag was later invalidated at offsets [0x0..0x4] + --> $DIR/illegal_write2.rs:LL:CC + | +LL | drop(&mut *target); // reborrow + | ^^^^^^^^^^^^ + = note: inside `main` at $DIR/illegal_write2.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/stacked_borrows/illegal_write3.stderr b/tests/compile-fail/stacked_borrows/illegal_write3.stderr new file mode 100644 index 0000000000000..b37caee5ef203 --- /dev/null +++ b/tests/compile-fail/stacked_borrows/illegal_write3.stderr @@ -0,0 +1,22 @@ +error: Undefined Behavior: attempting a write access using at ALLOC[0x0], but that tag only grants SharedReadOnly permission for this location + --> $DIR/illegal_write3.rs:LL:CC + | +LL | unsafe { *ptr = 42; } + | ^^^^^^^^^ + | | + | attempting a write access using at ALLOC[0x0], but that tag only grants SharedReadOnly permission for this location + | this error occurs as part of an access at ALLOC[0x0..0x4] + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information +help: tag was most recently created at offsets [0x0..0x4] + --> $DIR/illegal_write3.rs:LL:CC + | +LL | let ptr = r#ref as *const _ as *mut _; // raw ptr, with raw tag + | ^^^^^ + = note: inside `main` at $DIR/illegal_write3.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/stacked_borrows/illegal_write4.stderr b/tests/compile-fail/stacked_borrows/illegal_write4.stderr new file mode 100644 index 0000000000000..5c0b4ec868e2e --- /dev/null +++ b/tests/compile-fail/stacked_borrows/illegal_write4.stderr @@ -0,0 +1,27 @@ +error: Undefined Behavior: attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + --> $DIR/illegal_write4.rs:LL:CC + | +LL | let _val = *reference; + | ^^^^^^^^^^ + | | + | attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | this error occurs as part of an access at ALLOC[0x0..0x4] + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information +help: was created by a retag at offsets [0x0..0x4] + --> $DIR/illegal_write4.rs:LL:CC + | +LL | let reference = unsafe { &*raw }; // freeze + | ^^^^^ +help: was later invalidated at offsets [0x0..0x4] + --> $DIR/illegal_write4.rs:LL:CC + | +LL | let _mut_ref: &mut i32 = unsafe { mem::transmute(ptr) }; // &mut, with raw tag + | ^^^^^^^^^^^^^^^^^^^ + = note: inside `main` at $DIR/illegal_write4.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/stacked_borrows/illegal_write5.stderr b/tests/compile-fail/stacked_borrows/illegal_write5.stderr new file mode 100644 index 0000000000000..f9a4dcfd8d21d --- /dev/null +++ b/tests/compile-fail/stacked_borrows/illegal_write5.stderr @@ -0,0 +1,27 @@ +error: Undefined Behavior: attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + --> $DIR/illegal_write5.rs:LL:CC + | +LL | let _val = *xref; + | ^^^^^ + | | + | attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | this error occurs as part of an access at ALLOC[0x0..0x4] + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information +help: was created by a retag at offsets [0x0..0x4] + --> $DIR/illegal_write5.rs:LL:CC + | +LL | let xref = unsafe { &mut *xraw }; + | ^^^^^^^^^^ +help: was later invalidated at offsets [0x0..0x4] + --> $DIR/illegal_write5.rs:LL:CC + | +LL | unsafe { *xraw = 15 }; + | ^^^^^^^^^^ + = note: inside `main` at $DIR/illegal_write5.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/stacked_borrows/illegal_write6.stderr b/tests/compile-fail/stacked_borrows/illegal_write6.stderr new file mode 100644 index 0000000000000..5861aeefaf46c --- /dev/null +++ b/tests/compile-fail/stacked_borrows/illegal_write6.stderr @@ -0,0 +1,39 @@ +error: Undefined Behavior: not granting access to tag because incompatible item is protected: [Unique for (call ID)] + --> $DIR/illegal_write6.rs:LL:CC + | +LL | unsafe { *y = 2; } + | ^^^^^^ not granting access to tag because incompatible item is protected: [Unique for (call ID)] + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information +help: tag was most recently created at offsets [0x0..0x4] + --> $DIR/illegal_write6.rs:LL:CC + | +LL | let p = x as *mut u32; + | ^ +help: was protected due to a tag which was created here + --> $DIR/illegal_write6.rs:LL:CC + | +LL | foo(x, p); + | ^ +help: this protector is live for this call + --> $DIR/illegal_write6.rs:LL:CC + | +LL | / fn foo(a: &mut u32, y: *mut u32) -> u32 { +LL | | *a = 1; +LL | | let _b = &*a; +LL | | unsafe { *y = 2; } +LL | | return *a; +LL | | } + | |_^ + = note: inside `foo` at $DIR/illegal_write6.rs:LL:CC +note: inside `main` at $DIR/illegal_write6.rs:LL:CC + --> $DIR/illegal_write6.rs:LL:CC + | +LL | foo(x, p); + | ^^^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/stacked_borrows/interior_mut1.stderr b/tests/compile-fail/stacked_borrows/interior_mut1.stderr new file mode 100644 index 0000000000000..af4163c93605e --- /dev/null +++ b/tests/compile-fail/stacked_borrows/interior_mut1.stderr @@ -0,0 +1,27 @@ +error: Undefined Behavior: trying to reborrow for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + --> $DIR/interior_mut1.rs:LL:CC + | +LL | let _val = *inner_shr.get(); + | ^^^^^^^^^^^^^^^ + | | + | trying to reborrow for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | this error occurs as part of a reborrow at ALLOC[0x0..0x4] + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information +help: was created by a retag at offsets [0x0..0x4] + --> $DIR/interior_mut1.rs:LL:CC + | +LL | let inner_shr = &*inner_uniq; // adds a SharedReadWrite + | ^^^^^^^^^^^^ +help: was later invalidated at offsets [0x0..0x4] + --> $DIR/interior_mut1.rs:LL:CC + | +LL | *c.get() = UnsafeCell::new(1); // invalidates inner_shr + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: inside `main` at $DIR/interior_mut1.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/stacked_borrows/interior_mut2.stderr b/tests/compile-fail/stacked_borrows/interior_mut2.stderr new file mode 100644 index 0000000000000..5a4ddf381e715 --- /dev/null +++ b/tests/compile-fail/stacked_borrows/interior_mut2.stderr @@ -0,0 +1,27 @@ +error: Undefined Behavior: trying to reborrow for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + --> $DIR/interior_mut2.rs:LL:CC + | +LL | let _val = *inner_shr.get(); + | ^^^^^^^^^^^^^^^ + | | + | trying to reborrow for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | this error occurs as part of a reborrow at ALLOC[0x0..0x4] + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information +help: was created by a retag at offsets [0x0..0x4] + --> $DIR/interior_mut2.rs:LL:CC + | +LL | let inner_shr = &*inner_uniq; + | ^^^^^^^^^^^^ +help: was later invalidated at offsets [0x0..0x4] + --> $DIR/interior_mut2.rs:LL:CC + | +LL | *c.get() = UnsafeCell::new(0); // now inner_shr gets invalidated + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: inside `main` at $DIR/interior_mut2.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/stacked_borrows/invalidate_against_barrier1.stderr b/tests/compile-fail/stacked_borrows/invalidate_against_barrier1.stderr new file mode 100644 index 0000000000000..47f7a06a85851 --- /dev/null +++ b/tests/compile-fail/stacked_borrows/invalidate_against_barrier1.stderr @@ -0,0 +1,39 @@ +error: Undefined Behavior: not granting access to tag because incompatible item is protected: [Unique for (call ID)] + --> $DIR/invalidate_against_barrier1.rs:LL:CC + | +LL | let _val = unsafe { *x }; + | ^^ not granting access to tag because incompatible item is protected: [Unique for (call ID)] + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information +help: tag was most recently created at offsets [0x0..0x4] + --> $DIR/invalidate_against_barrier1.rs:LL:CC + | +LL | let xraw = &mut x as *mut _; + | ^^^^^^ +help: was protected due to a tag which was created here + --> $DIR/invalidate_against_barrier1.rs:LL:CC + | +LL | inner(xraw, xref); + | ^^^^ +help: this protector is live for this call + --> $DIR/invalidate_against_barrier1.rs:LL:CC + | +LL | / fn inner(x: *mut i32, _y: &mut i32) { +LL | | // If `x` and `y` alias, retagging is fine with this... but we really +LL | | // shouldn't be allowed to use `x` at all because `y` was assumed to be +LL | | // unique for the duration of this call. +LL | | let _val = unsafe { *x }; +LL | | } + | |_^ + = note: inside `inner` at $DIR/invalidate_against_barrier1.rs:LL:CC +note: inside `main` at $DIR/invalidate_against_barrier1.rs:LL:CC + --> $DIR/invalidate_against_barrier1.rs:LL:CC + | +LL | inner(xraw, xref); + | ^^^^^^^^^^^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/stacked_borrows/invalidate_against_barrier2.stderr b/tests/compile-fail/stacked_borrows/invalidate_against_barrier2.stderr new file mode 100644 index 0000000000000..fa2e6aa05a2b8 --- /dev/null +++ b/tests/compile-fail/stacked_borrows/invalidate_against_barrier2.stderr @@ -0,0 +1,39 @@ +error: Undefined Behavior: not granting access to tag because incompatible item is protected: [SharedReadOnly for (call ID)] + --> $DIR/invalidate_against_barrier2.rs:LL:CC + | +LL | unsafe { *x = 0 }; + | ^^^^^^ not granting access to tag because incompatible item is protected: [SharedReadOnly for (call ID)] + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information +help: tag was most recently created at offsets [0x0..0x4] + --> $DIR/invalidate_against_barrier2.rs:LL:CC + | +LL | let xraw = &mut x as *mut _; + | ^^^^^^ +help: was protected due to a tag which was created here + --> $DIR/invalidate_against_barrier2.rs:LL:CC + | +LL | inner(xraw, xref); + | ^^^^ +help: this protector is live for this call + --> $DIR/invalidate_against_barrier2.rs:LL:CC + | +LL | / fn inner(x: *mut i32, _y: &i32) { +LL | | // If `x` and `y` alias, retagging is fine with this... but we really +LL | | // shouldn't be allowed to write to `x` at all because `y` was assumed to be +LL | | // immutable for the duration of this call. +LL | | unsafe { *x = 0 }; +LL | | } + | |_^ + = note: inside `inner` at $DIR/invalidate_against_barrier2.rs:LL:CC +note: inside `main` at $DIR/invalidate_against_barrier2.rs:LL:CC + --> $DIR/invalidate_against_barrier2.rs:LL:CC + | +LL | inner(xraw, xref); + | ^^^^^^^^^^^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/stacked_borrows/issue-miri-1050-1.stderr b/tests/compile-fail/stacked_borrows/issue-miri-1050-1.stderr new file mode 100644 index 0000000000000..70c774818bcec --- /dev/null +++ b/tests/compile-fail/stacked_borrows/issue-miri-1050-1.stderr @@ -0,0 +1,17 @@ +error: Undefined Behavior: ALLOC has size 2, so pointer to 4 bytes starting at offset 0 is out-of-bounds + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `std::boxed::Box::::from_raw_in` at rustc_src/src/boxed.rs:LL:CC + = note: inside `std::boxed::Box::::from_raw` at rustc_src/src/boxed.rs:LL:CC +note: inside `main` at $DIR/issue-miri-1050-1.rs:LL:CC + --> $DIR/issue-miri-1050-1.rs:LL:CC + | +LL | Box::from_raw(ptr as *mut u32); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/stacked_borrows/issue-miri-1050-2.rs b/tests/compile-fail/stacked_borrows/issue-miri-1050-2.rs index 30cbf0b339a1d..8f0b475016046 100644 --- a/tests/compile-fail/stacked_borrows/issue-miri-1050-2.rs +++ b/tests/compile-fail/stacked_borrows/issue-miri-1050-2.rs @@ -1,4 +1,4 @@ -// error-pattern: 0x4 is not a valid pointer +// error-pattern: is not a valid pointer use std::ptr::NonNull; fn main() { unsafe { diff --git a/tests/compile-fail/stacked_borrows/issue-miri-1050-2.stderr b/tests/compile-fail/stacked_borrows/issue-miri-1050-2.stderr new file mode 100644 index 0000000000000..579f728b2b07e --- /dev/null +++ b/tests/compile-fail/stacked_borrows/issue-miri-1050-2.stderr @@ -0,0 +1,17 @@ +error: Undefined Behavior: 0x4 is not a valid pointer + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `std::boxed::Box::::from_raw_in` at rustc_src/src/boxed.rs:LL:CC + = note: inside `std::boxed::Box::::from_raw` at rustc_src/src/boxed.rs:LL:CC +note: inside `main` at $DIR/issue-miri-1050-2.rs:LL:CC + --> $DIR/issue-miri-1050-2.rs:LL:CC + | +LL | Box::from_raw(ptr.as_ptr()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/stacked_borrows/load_invalid_mut.stderr b/tests/compile-fail/stacked_borrows/load_invalid_mut.stderr new file mode 100644 index 0000000000000..00eda4fe5a316 --- /dev/null +++ b/tests/compile-fail/stacked_borrows/load_invalid_mut.stderr @@ -0,0 +1,27 @@ +error: Undefined Behavior: trying to reborrow for Unique permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + --> $DIR/load_invalid_mut.rs:LL:CC + | +LL | let _val = *xref_in_mem; + | ^^^^^^^^^^^^ + | | + | trying to reborrow for Unique permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | this error occurs as part of a reborrow at ALLOC[0x0..0x4] + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information +help: was created by a retag at offsets [0x0..0x4] + --> $DIR/load_invalid_mut.rs:LL:CC + | +LL | let xref_in_mem = Box::new(xref); + | ^^^^^^^^^^^^^^ +help: was later invalidated at offsets [0x0..0x4] + --> $DIR/load_invalid_mut.rs:LL:CC + | +LL | let _val = unsafe { *xraw }; // invalidate xref + | ^^^^^ + = note: inside `main` at $DIR/load_invalid_mut.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/stacked_borrows/load_invalid_shr.stderr b/tests/compile-fail/stacked_borrows/load_invalid_shr.stderr new file mode 100644 index 0000000000000..eb61b4762f846 --- /dev/null +++ b/tests/compile-fail/stacked_borrows/load_invalid_shr.stderr @@ -0,0 +1,27 @@ +error: Undefined Behavior: trying to reborrow for SharedReadOnly permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + --> $DIR/load_invalid_shr.rs:LL:CC + | +LL | let _val = *xref_in_mem; + | ^^^^^^^^^^^^ + | | + | trying to reborrow for SharedReadOnly permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | this error occurs as part of a reborrow at ALLOC[0x0..0x4] + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information +help: was created by a retag at offsets [0x0..0x4] + --> $DIR/load_invalid_shr.rs:LL:CC + | +LL | let xref_in_mem = Box::new(xref); + | ^^^^^^^^^^^^^^ +help: was later invalidated at offsets [0x0..0x4] + --> $DIR/load_invalid_shr.rs:LL:CC + | +LL | unsafe { *xraw = 42 }; // unfreeze + | ^^^^^^^^^^ + = note: inside `main` at $DIR/load_invalid_shr.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/stacked_borrows/mut_exclusive_violation1.stderr b/tests/compile-fail/stacked_borrows/mut_exclusive_violation1.stderr new file mode 100644 index 0000000000000..2d8ef7c1a4eb4 --- /dev/null +++ b/tests/compile-fail/stacked_borrows/mut_exclusive_violation1.stderr @@ -0,0 +1,37 @@ +error: Undefined Behavior: attempting a write access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + --> $DIR/mut_exclusive_violation1.rs:LL:CC + | +LL | *LEAK = 7; + | ^^^^^^^^^ + | | + | attempting a write access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | this error occurs as part of an access at ALLOC[0x0..0x4] + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information +help: tag was most recently created at offsets [0x0..0x4] + --> $DIR/mut_exclusive_violation1.rs:LL:CC + | +LL | LEAK = x as *const _ as *mut _; + | ^ +help: tag was later invalidated at offsets [0x0..0x4] + --> $DIR/mut_exclusive_violation1.rs:LL:CC + | +LL | *our = 5; + | ^^^^^^^^ + = note: inside `unknown_code_2` at $DIR/mut_exclusive_violation1.rs:LL:CC +note: inside `demo_mut_advanced_unique` at $DIR/mut_exclusive_violation1.rs:LL:CC + --> $DIR/mut_exclusive_violation1.rs:LL:CC + | +LL | unknown_code_2(); + | ^^^^^^^^^^^^^^^^ +note: inside `main` at $DIR/mut_exclusive_violation1.rs:LL:CC + --> $DIR/mut_exclusive_violation1.rs:LL:CC + | +LL | demo_mut_advanced_unique(&mut 0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/stacked_borrows/mut_exclusive_violation2.stderr b/tests/compile-fail/stacked_borrows/mut_exclusive_violation2.stderr new file mode 100644 index 0000000000000..ae0eab467bf60 --- /dev/null +++ b/tests/compile-fail/stacked_borrows/mut_exclusive_violation2.stderr @@ -0,0 +1,27 @@ +error: Undefined Behavior: attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + --> $DIR/mut_exclusive_violation2.rs:LL:CC + | +LL | let _val = *raw1; + | ^^^^^ + | | + | attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | this error occurs as part of an access at ALLOC[0x0..0x4] + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information +help: was created by a retag at offsets [0x0..0x4] + --> $DIR/mut_exclusive_violation2.rs:LL:CC + | +LL | let raw1 = ptr1.as_mut(); + | ^^^^^^^^^^^^^ +help: was later invalidated at offsets [0x0..0x4] + --> $DIR/mut_exclusive_violation2.rs:LL:CC + | +LL | let _raw2 = ptr2.as_mut(); + | ^^^^^^^^^^^^^ + = note: inside `main` at $DIR/mut_exclusive_violation2.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/stacked_borrows/outdated_local.stderr b/tests/compile-fail/stacked_borrows/outdated_local.stderr new file mode 100644 index 0000000000000..1c1deac2317f3 --- /dev/null +++ b/tests/compile-fail/stacked_borrows/outdated_local.stderr @@ -0,0 +1,27 @@ +error: Undefined Behavior: attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + --> $DIR/outdated_local.rs:LL:CC + | +LL | assert_eq!(unsafe { *y }, 1); + | ^^ + | | + | attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | this error occurs as part of an access at ALLOC[0x0..0x4] + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information +help: tag was most recently created at offsets [0x0..0x4] + --> $DIR/outdated_local.rs:LL:CC + | +LL | let y: *const i32 = &x; + | ^^ +help: tag was later invalidated at offsets [0x0..0x4] + --> $DIR/outdated_local.rs:LL:CC + | +LL | x = 1; // this invalidates y by reactivating the lowermost uniq borrow for this local + | ^^^^^ + = note: inside `main` at $DIR/outdated_local.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/stacked_borrows/pass_invalid_mut.stderr b/tests/compile-fail/stacked_borrows/pass_invalid_mut.stderr new file mode 100644 index 0000000000000..280e51693a5c0 --- /dev/null +++ b/tests/compile-fail/stacked_borrows/pass_invalid_mut.stderr @@ -0,0 +1,27 @@ +error: Undefined Behavior: trying to reborrow for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + --> $DIR/pass_invalid_mut.rs:LL:CC + | +LL | foo(xref); + | ^^^^ + | | + | trying to reborrow for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | this error occurs as part of a reborrow at ALLOC[0x0..0x4] + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information +help: was created by a retag at offsets [0x0..0x4] + --> $DIR/pass_invalid_mut.rs:LL:CC + | +LL | let xref = unsafe { &mut *xraw }; + | ^^^^^^^^^^ +help: was later invalidated at offsets [0x0..0x4] + --> $DIR/pass_invalid_mut.rs:LL:CC + | +LL | let _val = unsafe { *xraw }; // invalidate xref + | ^^^^^ + = note: inside `main` at $DIR/pass_invalid_mut.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/stacked_borrows/pass_invalid_shr.stderr b/tests/compile-fail/stacked_borrows/pass_invalid_shr.stderr new file mode 100644 index 0000000000000..b111832193b9c --- /dev/null +++ b/tests/compile-fail/stacked_borrows/pass_invalid_shr.stderr @@ -0,0 +1,27 @@ +error: Undefined Behavior: trying to reborrow for SharedReadOnly permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + --> $DIR/pass_invalid_shr.rs:LL:CC + | +LL | foo(xref); + | ^^^^ + | | + | trying to reborrow for SharedReadOnly permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | this error occurs as part of a reborrow at ALLOC[0x0..0x4] + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information +help: was created by a retag at offsets [0x0..0x4] + --> $DIR/pass_invalid_shr.rs:LL:CC + | +LL | let xref = unsafe { &*xraw }; + | ^^^^^^ +help: was later invalidated at offsets [0x0..0x4] + --> $DIR/pass_invalid_shr.rs:LL:CC + | +LL | unsafe { *xraw = 42 }; // unfreeze + | ^^^^^^^^^^ + = note: inside `main` at $DIR/pass_invalid_shr.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/stacked_borrows/pointer_smuggling.stderr b/tests/compile-fail/stacked_borrows/pointer_smuggling.stderr new file mode 100644 index 0000000000000..097de439f79df --- /dev/null +++ b/tests/compile-fail/stacked_borrows/pointer_smuggling.stderr @@ -0,0 +1,32 @@ +error: Undefined Behavior: attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + --> $DIR/pointer_smuggling.rs:LL:CC + | +LL | let _x = unsafe { *PTR }; + | ^^^^ + | | + | attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | this error occurs as part of an access at ALLOC[0x0..0x1] + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information +help: tag was most recently created at offsets [0x0..0x1] + --> $DIR/pointer_smuggling.rs:LL:CC + | +LL | PTR = x; + | ^ +help: tag was later invalidated at offsets [0x0..0x1] + --> $DIR/pointer_smuggling.rs:LL:CC + | +LL | *val = 2; // this invalidates any raw ptrs `fun1` might have created. + | ^^^^^^^^ + = note: inside `fun2` at $DIR/pointer_smuggling.rs:LL:CC +note: inside `main` at $DIR/pointer_smuggling.rs:LL:CC + --> $DIR/pointer_smuggling.rs:LL:CC + | +LL | fun2(); // if they now use a raw ptr they break our reference + | ^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/stacked_borrows/raw_tracking.stderr b/tests/compile-fail/stacked_borrows/raw_tracking.stderr new file mode 100644 index 0000000000000..a03d55a90486a --- /dev/null +++ b/tests/compile-fail/stacked_borrows/raw_tracking.stderr @@ -0,0 +1,27 @@ +error: Undefined Behavior: attempting a write access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + --> $DIR/raw_tracking.rs:LL:CC + | +LL | unsafe { *raw1 = 13; } + | ^^^^^^^^^^ + | | + | attempting a write access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | this error occurs as part of an access at ALLOC[0x0..0x4] + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information +help: was created by a retag at offsets [0x0..0x4] + --> $DIR/raw_tracking.rs:LL:CC + | +LL | let raw1 = &mut l as *mut _; + | ^^^^^^ +help: was later invalidated at offsets [0x0..0x4] + --> $DIR/raw_tracking.rs:LL:CC + | +LL | let raw2 = &mut l as *mut _; // invalidates raw1 + | ^^^^^^ + = note: inside `main` at $DIR/raw_tracking.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/stacked_borrows/return_invalid_mut.stderr b/tests/compile-fail/stacked_borrows/return_invalid_mut.stderr new file mode 100644 index 0000000000000..6de657b829808 --- /dev/null +++ b/tests/compile-fail/stacked_borrows/return_invalid_mut.stderr @@ -0,0 +1,32 @@ +error: Undefined Behavior: trying to reborrow for Unique permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location + --> $DIR/return_invalid_mut.rs:LL:CC + | +LL | ret + | ^^^ + | | + | trying to reborrow for Unique permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location + | this error occurs as part of a reborrow at ALLOC[0x4..0x8] + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information +help: was created by a retag at offsets [0x4..0x8] + --> $DIR/return_invalid_mut.rs:LL:CC + | +LL | let ret = unsafe { &mut (*xraw).1 }; + | ^^^^^^^^^^^^^^ +help: was later invalidated at offsets [0x0..0x8] + --> $DIR/return_invalid_mut.rs:LL:CC + | +LL | let _val = unsafe { *xraw }; // invalidate xref + | ^^^^^ + = note: inside `foo` at $DIR/return_invalid_mut.rs:LL:CC +note: inside `main` at $DIR/return_invalid_mut.rs:LL:CC + --> $DIR/return_invalid_mut.rs:LL:CC + | +LL | foo(&mut (1, 2)); + | ^^^^^^^^^^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/stacked_borrows/return_invalid_mut_option.stderr b/tests/compile-fail/stacked_borrows/return_invalid_mut_option.stderr new file mode 100644 index 0000000000000..8b95765dcc460 --- /dev/null +++ b/tests/compile-fail/stacked_borrows/return_invalid_mut_option.stderr @@ -0,0 +1,27 @@ +error: Undefined Behavior: trying to reborrow for Unique permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location + --> $DIR/return_invalid_mut_option.rs:LL:CC + | +LL | Some(_x) => {}, + | ^^ + | | + | trying to reborrow for Unique permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location + | this error occurs as part of a reborrow at ALLOC[0x4..0x8] + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information +help: was created by a retag at offsets [0x4..0x8] + --> $DIR/return_invalid_mut_option.rs:LL:CC + | +LL | let ret = Some(ret); + | ^^^ +help: was later invalidated at offsets [0x0..0x8] + --> $DIR/return_invalid_mut_option.rs:LL:CC + | +LL | let _val = unsafe { *xraw }; // invalidate xref + | ^^^^^ + = note: inside `main` at $DIR/return_invalid_mut_option.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/stacked_borrows/return_invalid_mut_tuple.stderr b/tests/compile-fail/stacked_borrows/return_invalid_mut_tuple.stderr new file mode 100644 index 0000000000000..f9e6d65c78e66 --- /dev/null +++ b/tests/compile-fail/stacked_borrows/return_invalid_mut_tuple.stderr @@ -0,0 +1,27 @@ +error: Undefined Behavior: trying to reborrow for Unique permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location + --> $DIR/return_invalid_mut_tuple.rs:LL:CC + | +LL | foo(&mut (1, 2)).0; + | ^^^^^^^^^^^^^^^^^^ + | | + | trying to reborrow for Unique permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location + | this error occurs as part of a reborrow at ALLOC[0x4..0x8] + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information +help: was created by a retag at offsets [0x4..0x8] + --> $DIR/return_invalid_mut_tuple.rs:LL:CC + | +LL | let ret = (unsafe { &mut (*xraw).1 },); + | ^^^^^^^^^^^^^^ +help: was later invalidated at offsets [0x0..0x8] + --> $DIR/return_invalid_mut_tuple.rs:LL:CC + | +LL | let _val = unsafe { *xraw }; // invalidate xref + | ^^^^^ + = note: inside `main` at $DIR/return_invalid_mut_tuple.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/stacked_borrows/return_invalid_shr.stderr b/tests/compile-fail/stacked_borrows/return_invalid_shr.stderr new file mode 100644 index 0000000000000..20dcb8e93c2cf --- /dev/null +++ b/tests/compile-fail/stacked_borrows/return_invalid_shr.stderr @@ -0,0 +1,32 @@ +error: Undefined Behavior: trying to reborrow for SharedReadOnly permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location + --> $DIR/return_invalid_shr.rs:LL:CC + | +LL | ret + | ^^^ + | | + | trying to reborrow for SharedReadOnly permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location + | this error occurs as part of a reborrow at ALLOC[0x4..0x8] + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information +help: was created by a retag at offsets [0x4..0x8] + --> $DIR/return_invalid_shr.rs:LL:CC + | +LL | let ret = unsafe { &(*xraw).1 }; + | ^^^^^^^^^^ +help: was later invalidated at offsets [0x0..0x8] + --> $DIR/return_invalid_shr.rs:LL:CC + | +LL | unsafe { *xraw = (42, 23) }; // unfreeze + | ^^^^^^^^^^^^^^^^ + = note: inside `foo` at $DIR/return_invalid_shr.rs:LL:CC +note: inside `main` at $DIR/return_invalid_shr.rs:LL:CC + --> $DIR/return_invalid_shr.rs:LL:CC + | +LL | foo(&mut (1, 2)); + | ^^^^^^^^^^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/stacked_borrows/return_invalid_shr_option.stderr b/tests/compile-fail/stacked_borrows/return_invalid_shr_option.stderr new file mode 100644 index 0000000000000..0c41a10a3f97c --- /dev/null +++ b/tests/compile-fail/stacked_borrows/return_invalid_shr_option.stderr @@ -0,0 +1,27 @@ +error: Undefined Behavior: trying to reborrow for SharedReadOnly permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location + --> $DIR/return_invalid_shr_option.rs:LL:CC + | +LL | Some(_x) => {}, + | ^^ + | | + | trying to reborrow for SharedReadOnly permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location + | this error occurs as part of a reborrow at ALLOC[0x4..0x8] + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information +help: was created by a retag at offsets [0x4..0x8] + --> $DIR/return_invalid_shr_option.rs:LL:CC + | +LL | let ret = Some(unsafe { &(*xraw).1 }); + | ^^^^^^^^^^ +help: was later invalidated at offsets [0x0..0x8] + --> $DIR/return_invalid_shr_option.rs:LL:CC + | +LL | unsafe { *xraw = (42, 23) }; // unfreeze + | ^^^^^^^^^^^^^^^^ + = note: inside `main` at $DIR/return_invalid_shr_option.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/stacked_borrows/return_invalid_shr_tuple.stderr b/tests/compile-fail/stacked_borrows/return_invalid_shr_tuple.stderr new file mode 100644 index 0000000000000..9e7be7ad01388 --- /dev/null +++ b/tests/compile-fail/stacked_borrows/return_invalid_shr_tuple.stderr @@ -0,0 +1,27 @@ +error: Undefined Behavior: trying to reborrow for SharedReadOnly permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location + --> $DIR/return_invalid_shr_tuple.rs:LL:CC + | +LL | foo(&mut (1, 2)).0; + | ^^^^^^^^^^^^^^^^^^ + | | + | trying to reborrow for SharedReadOnly permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location + | this error occurs as part of a reborrow at ALLOC[0x4..0x8] + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information +help: was created by a retag at offsets [0x4..0x8] + --> $DIR/return_invalid_shr_tuple.rs:LL:CC + | +LL | let ret = (unsafe { &(*xraw).1 },); + | ^^^^^^^^^^ +help: was later invalidated at offsets [0x0..0x8] + --> $DIR/return_invalid_shr_tuple.rs:LL:CC + | +LL | unsafe { *xraw = (42, 23) }; // unfreeze + | ^^^^^^^^^^^^^^^^ + = note: inside `main` at $DIR/return_invalid_shr_tuple.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/stacked_borrows/shared_rw_borrows_are_weak1.stderr b/tests/compile-fail/stacked_borrows/shared_rw_borrows_are_weak1.stderr new file mode 100644 index 0000000000000..576a21bbf6d41 --- /dev/null +++ b/tests/compile-fail/stacked_borrows/shared_rw_borrows_are_weak1.stderr @@ -0,0 +1,27 @@ +error: Undefined Behavior: trying to reborrow for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + --> $DIR/shared_rw_borrows_are_weak1.rs:LL:CC + | +LL | y.get_mut(); + | ^^^^^^^^^^^ + | | + | trying to reborrow for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | this error occurs as part of a reborrow at ALLOC[0x0..0x4] + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information +help: was created by a retag at offsets [0x0..0x4] + --> $DIR/shared_rw_borrows_are_weak1.rs:LL:CC + | +LL | let y: &mut Cell = mem::transmute(&mut *x); // launder lifetime + | ^^^^^^^^^^^^^^^^^^^^^^^ +help: was later invalidated at offsets [0x0..0x4] + --> $DIR/shared_rw_borrows_are_weak1.rs:LL:CC + | +LL | shr_rw.set(1); + | ^^^^^^^^^^^^^ + = note: inside `main` at $DIR/shared_rw_borrows_are_weak1.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/stacked_borrows/shared_rw_borrows_are_weak2.rs b/tests/compile-fail/stacked_borrows/shared_rw_borrows_are_weak2.rs index 942bb503db027..d4aef74dff6ba 100644 --- a/tests/compile-fail/stacked_borrows/shared_rw_borrows_are_weak2.rs +++ b/tests/compile-fail/stacked_borrows/shared_rw_borrows_are_weak2.rs @@ -1,6 +1,7 @@ // We want to test that granting a SharedReadWrite will be added // *below* an already granted SharedReadWrite -- so writing to // the SharedReadWrite will invalidate the SharedReadWrite. +// normalize-stderr-test: "0x[0-9a-fA-F]+" -> "$$HEX" use std::mem; use std::cell::RefCell; diff --git a/tests/compile-fail/stacked_borrows/shared_rw_borrows_are_weak2.stderr b/tests/compile-fail/stacked_borrows/shared_rw_borrows_are_weak2.stderr new file mode 100644 index 0000000000000..e2159ed5892f8 --- /dev/null +++ b/tests/compile-fail/stacked_borrows/shared_rw_borrows_are_weak2.stderr @@ -0,0 +1,27 @@ +error: Undefined Behavior: attempting a read access using at ALLOC[$HEX], but that tag does not exist in the borrow stack for this location + --> $DIR/shared_rw_borrows_are_weak2.rs:LL:CC + | +LL | let _val = *y; + | ^^ + | | + | attempting a read access using at ALLOC[$HEX], but that tag does not exist in the borrow stack for this location + | this error occurs as part of an access at ALLOC[$HEX..$HEX] + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information +help: was created by a retag at offsets [$HEX..$HEX] + --> $DIR/shared_rw_borrows_are_weak2.rs:LL:CC + | +LL | let y: &i32 = mem::transmute(&*x.borrow()); // launder lifetime + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: was later invalidated at offsets [$HEX..$HEX] + --> $DIR/shared_rw_borrows_are_weak2.rs:LL:CC + | +LL | shr_rw.replace(1); + | ^^^^^^^^^^^^^^^^^ + = note: inside `main` at $DIR/shared_rw_borrows_are_weak2.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/stacked_borrows/shr_frozen_violation1.stderr b/tests/compile-fail/stacked_borrows/shr_frozen_violation1.stderr new file mode 100644 index 0000000000000..689ad1c6b6684 --- /dev/null +++ b/tests/compile-fail/stacked_borrows/shr_frozen_violation1.stderr @@ -0,0 +1,32 @@ +error: Undefined Behavior: attempting a write access using at ALLOC[0x0], but that tag only grants SharedReadOnly permission for this location + --> $DIR/shr_frozen_violation1.rs:LL:CC + | +LL | unsafe { *(x as *const i32 as *mut i32) = 7; } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | attempting a write access using at ALLOC[0x0], but that tag only grants SharedReadOnly permission for this location + | this error occurs as part of an access at ALLOC[0x0..0x4] + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information +help: tag was most recently created at offsets [0x0..0x4] + --> $DIR/shr_frozen_violation1.rs:LL:CC + | +LL | unsafe { *(x as *const i32 as *mut i32) = 7; } + | ^ + = note: inside `unknown_code` at $DIR/shr_frozen_violation1.rs:LL:CC +note: inside `foo` at $DIR/shr_frozen_violation1.rs:LL:CC + --> $DIR/shr_frozen_violation1.rs:LL:CC + | +LL | unknown_code(&*x); + | ^^^^^^^^^^^^^^^^^ +note: inside `main` at $DIR/shr_frozen_violation1.rs:LL:CC + --> $DIR/shr_frozen_violation1.rs:LL:CC + | +LL | println!("{}", foo(&mut 0)); + | ^^^^^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/stacked_borrows/static_memory_modification.rs b/tests/compile-fail/stacked_borrows/static_memory_modification.rs index 417a03bb0335b..72e2ed9381240 100644 --- a/tests/compile-fail/stacked_borrows/static_memory_modification.rs +++ b/tests/compile-fail/stacked_borrows/static_memory_modification.rs @@ -3,6 +3,6 @@ static X: usize = 5; #[allow(mutable_transmutes)] fn main() { let _x = unsafe { - std::mem::transmute::<&usize, &mut usize>(&X) //~ ERROR writing to alloc1 which is read-only + std::mem::transmute::<&usize, &mut usize>(&X) //~ ERROR writing to ALLOC which is read-only }; } diff --git a/tests/compile-fail/stacked_borrows/static_memory_modification.stderr b/tests/compile-fail/stacked_borrows/static_memory_modification.stderr new file mode 100644 index 0000000000000..091eb29f64d7a --- /dev/null +++ b/tests/compile-fail/stacked_borrows/static_memory_modification.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: writing to ALLOC which is read-only + --> $DIR/static_memory_modification.rs:LL:CC + | +LL | std::mem::transmute::<&usize, &mut usize>(&X) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ writing to ALLOC which is read-only + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/static_memory_modification.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/stacked_borrows/transmute-is-no-escape.stderr b/tests/compile-fail/stacked_borrows/transmute-is-no-escape.stderr new file mode 100644 index 0000000000000..f2ea4f919c676 --- /dev/null +++ b/tests/compile-fail/stacked_borrows/transmute-is-no-escape.stderr @@ -0,0 +1,18 @@ +error: Undefined Behavior: attempting a write access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + --> $DIR/transmute-is-no-escape.rs:LL:CC + | +LL | unsafe { *raw = 13; } + | ^^^^^^^^^ + | | + | attempting a write access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | this error occurs as part of an access at ALLOC[0x0..0x4] + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information + + = note: inside `main` at $DIR/transmute-is-no-escape.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/stacked_borrows/unescaped_local.stderr b/tests/compile-fail/stacked_borrows/unescaped_local.stderr new file mode 100644 index 0000000000000..a8d869549a9a7 --- /dev/null +++ b/tests/compile-fail/stacked_borrows/unescaped_local.stderr @@ -0,0 +1,27 @@ +error: Undefined Behavior: attempting a write access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + --> $DIR/unescaped_local.rs:LL:CC + | +LL | unsafe { *raw = 13; } + | ^^^^^^^^^ + | | + | attempting a write access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | this error occurs as part of an access at ALLOC[0x0..0x4] + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information +help: tag was most recently created at offsets [0x0..0x4] + --> $DIR/unescaped_local.rs:LL:CC + | +LL | let raw = &mut x as *mut i32 as usize as *mut i32; + | ^^^^^^ +help: tag was later invalidated at offsets [0x0..0x4] + --> $DIR/unescaped_local.rs:LL:CC + | +LL | let _ptr = &mut x; + | ^^^^^^ + = note: inside `main` at $DIR/unescaped_local.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/stacked_borrows/unescaped_static.stderr b/tests/compile-fail/stacked_borrows/unescaped_static.stderr new file mode 100644 index 0000000000000..b191855644c2e --- /dev/null +++ b/tests/compile-fail/stacked_borrows/unescaped_static.stderr @@ -0,0 +1,18 @@ +error: Undefined Behavior: attempting a read access using at ALLOC[0x1], but that tag does not exist in the borrow stack for this location + --> $DIR/unescaped_static.rs:LL:CC + | +LL | let _val = unsafe { *ptr_to_first.add(1) }; + | ^^^^^^^^^^^^^^^^^^^^ + | | + | attempting a read access using at ALLOC[0x1], but that tag does not exist in the borrow stack for this location + | this error occurs as part of an access at ALLOC[0x1..0x2] + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information + + = note: inside `main` at $DIR/unescaped_static.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/stacked_borrows/zst_slice.stderr b/tests/compile-fail/stacked_borrows/zst_slice.stderr new file mode 100644 index 0000000000000..f9d8b024e9861 --- /dev/null +++ b/tests/compile-fail/stacked_borrows/zst_slice.stderr @@ -0,0 +1,16 @@ +error: Undefined Behavior: trying to reborrow for SharedReadOnly permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information + + = note: inside `core::slice::::get_unchecked::` at rustc_src/src/slice/mod.rs:LL:CC +note: inside `main` at $DIR/zst_slice.rs:LL:CC + --> $DIR/zst_slice.rs:LL:CC + | +LL | assert_eq!(*s.get_unchecked(1), 2); + | ^^^^^^^^^^^^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/static_memory_modification1.stderr b/tests/compile-fail/static_memory_modification1.stderr new file mode 100644 index 0000000000000..a37a79fa56f90 --- /dev/null +++ b/tests/compile-fail/static_memory_modification1.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: writing to ALLOC which is read-only + --> $DIR/static_memory_modification1.rs:LL:CC + | +LL | *std::mem::transmute::<&usize, &mut usize>(&X) = 6; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ writing to ALLOC which is read-only + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/static_memory_modification1.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/static_memory_modification2.stderr b/tests/compile-fail/static_memory_modification2.stderr new file mode 100644 index 0000000000000..d38f3f6342c34 --- /dev/null +++ b/tests/compile-fail/static_memory_modification2.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: writing to ALLOC which is read-only + --> $DIR/static_memory_modification2.rs:LL:CC + | +LL | transmute::<&[u8], &mut [u8]>(s.as_bytes())[4] = 42; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ writing to ALLOC which is read-only + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/static_memory_modification2.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/static_memory_modification3.stderr b/tests/compile-fail/static_memory_modification3.stderr new file mode 100644 index 0000000000000..96e3877c54fba --- /dev/null +++ b/tests/compile-fail/static_memory_modification3.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: writing to ALLOC which is read-only + --> $DIR/static_memory_modification3.rs:LL:CC + | +LL | transmute::<&[u8], &mut [u8]>(bs)[4] = 42; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ writing to ALLOC which is read-only + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/static_memory_modification3.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/strict-provenance-offset.stderr b/tests/compile-fail/strict-provenance-offset.stderr new file mode 100644 index 0000000000000..482b7a404c513 --- /dev/null +++ b/tests/compile-fail/strict-provenance-offset.stderr @@ -0,0 +1,16 @@ +error: Undefined Behavior: pointer arithmetic failed: $HEX is not a valid pointer + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `std::ptr::const_ptr::::offset` at rustc_src/src/ptr/const_ptr.rs:LL:CC +note: inside `main` at $DIR/strict-provenance-offset.rs:LL:CC + --> $DIR/strict-provenance-offset.rs:LL:CC + | +LL | let _ = unsafe { roundtrip.offset(1) }; + | ^^^^^^^^^^^^^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/strict_provenance_transmute.stderr b/tests/compile-fail/strict_provenance_transmute.stderr new file mode 100644 index 0000000000000..c2140b9786ca5 --- /dev/null +++ b/tests/compile-fail/strict_provenance_transmute.stderr @@ -0,0 +1,20 @@ +error: Undefined Behavior: type validation failed: encountered pointer to $HEX[ALLOC], but expected initialized plain (non-pointer) bytes + --> $DIR/strict_provenance_transmute.rs:LL:CC + | +LL | let left_int: usize = mem::transmute(left); + | ^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to $HEX[ALLOC], but expected initialized plain (non-pointer) bytes + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `deref` at $DIR/strict_provenance_transmute.rs:LL:CC +note: inside `main` at $DIR/strict_provenance_transmute.rs:LL:CC + --> $DIR/strict_provenance_transmute.rs:LL:CC + | +LL | deref(ptr1, ptr2.with_addr(ptr1.addr())); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/sync/libc_pthread_cond_double_destroy.stderr b/tests/compile-fail/sync/libc_pthread_cond_double_destroy.stderr new file mode 100644 index 0000000000000..362952678139a --- /dev/null +++ b/tests/compile-fail/sync/libc_pthread_cond_double_destroy.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory + --> $DIR/libc_pthread_cond_double_destroy.rs:LL:CC + | +LL | libc::pthread_cond_destroy(cond.as_mut_ptr()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/libc_pthread_cond_double_destroy.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/sync/libc_pthread_condattr_double_destroy.stderr b/tests/compile-fail/sync/libc_pthread_condattr_double_destroy.stderr new file mode 100644 index 0000000000000..14439445e727d --- /dev/null +++ b/tests/compile-fail/sync/libc_pthread_condattr_double_destroy.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory + --> $DIR/libc_pthread_condattr_double_destroy.rs:LL:CC + | +LL | libc::pthread_condattr_destroy(attr.as_mut_ptr()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/libc_pthread_condattr_double_destroy.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/sync/libc_pthread_mutex_NULL_deadlock.stderr b/tests/compile-fail/sync/libc_pthread_mutex_NULL_deadlock.stderr new file mode 100644 index 0000000000000..d42174b9fb743 --- /dev/null +++ b/tests/compile-fail/sync/libc_pthread_mutex_NULL_deadlock.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: trying to acquire already locked default mutex + --> $DIR/libc_pthread_mutex_NULL_deadlock.rs:LL:CC + | +LL | libc::pthread_mutex_lock(&mut mutex as *mut _); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trying to acquire already locked default mutex + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/libc_pthread_mutex_NULL_deadlock.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/sync/libc_pthread_mutex_deadlock.stderr b/tests/compile-fail/sync/libc_pthread_mutex_deadlock.stderr new file mode 100644 index 0000000000000..ac37096ad80d4 --- /dev/null +++ b/tests/compile-fail/sync/libc_pthread_mutex_deadlock.stderr @@ -0,0 +1,14 @@ +warning: thread support is experimental and incomplete: weak memory effects are not emulated. + +error: deadlock: the evaluated program deadlocked + --> $DIR/libc_pthread_mutex_deadlock.rs:LL:CC + | +LL | assert_eq!(libc::pthread_mutex_lock(lock_copy.0.get() as *mut _), 0); + | ^ the evaluated program deadlocked + | + = note: inside closure at $DIR/libc_pthread_mutex_deadlock.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error; 1 warning emitted + diff --git a/tests/compile-fail/sync/libc_pthread_mutex_default_deadlock.stderr b/tests/compile-fail/sync/libc_pthread_mutex_default_deadlock.stderr new file mode 100644 index 0000000000000..cb5daef68cbeb --- /dev/null +++ b/tests/compile-fail/sync/libc_pthread_mutex_default_deadlock.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: trying to acquire already locked default mutex + --> $DIR/libc_pthread_mutex_default_deadlock.rs:LL:CC + | +LL | libc::pthread_mutex_lock(&mut mutex as *mut _); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trying to acquire already locked default mutex + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/libc_pthread_mutex_default_deadlock.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/sync/libc_pthread_mutex_destroy_locked.stderr b/tests/compile-fail/sync/libc_pthread_mutex_destroy_locked.stderr new file mode 100644 index 0000000000000..96a3c645ab630 --- /dev/null +++ b/tests/compile-fail/sync/libc_pthread_mutex_destroy_locked.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: destroyed a locked mutex + --> $DIR/libc_pthread_mutex_destroy_locked.rs:LL:CC + | +LL | libc::pthread_mutex_destroy(&mut mutex as *mut _); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ destroyed a locked mutex + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/libc_pthread_mutex_destroy_locked.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/sync/libc_pthread_mutex_double_destroy.stderr b/tests/compile-fail/sync/libc_pthread_mutex_double_destroy.stderr new file mode 100644 index 0000000000000..9df2dd32b8041 --- /dev/null +++ b/tests/compile-fail/sync/libc_pthread_mutex_double_destroy.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory + --> $DIR/libc_pthread_mutex_double_destroy.rs:LL:CC + | +LL | libc::pthread_mutex_destroy(mutex.as_mut_ptr()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/libc_pthread_mutex_double_destroy.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/sync/libc_pthread_mutex_normal_deadlock.stderr b/tests/compile-fail/sync/libc_pthread_mutex_normal_deadlock.stderr new file mode 100644 index 0000000000000..b7877d3aa397d --- /dev/null +++ b/tests/compile-fail/sync/libc_pthread_mutex_normal_deadlock.stderr @@ -0,0 +1,12 @@ +error: deadlock: the evaluated program deadlocked + --> $DIR/libc_pthread_mutex_normal_deadlock.rs:LL:CC + | +LL | libc::pthread_mutex_lock(&mut mutex as *mut _); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the evaluated program deadlocked + | + = note: inside `main` at $DIR/libc_pthread_mutex_normal_deadlock.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/sync/libc_pthread_mutex_normal_unlock_unlocked.stderr b/tests/compile-fail/sync/libc_pthread_mutex_normal_unlock_unlocked.stderr new file mode 100644 index 0000000000000..b0858374cd9fb --- /dev/null +++ b/tests/compile-fail/sync/libc_pthread_mutex_normal_unlock_unlocked.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: unlocked a PTHREAD_MUTEX_NORMAL mutex that was not locked by the current thread + --> $DIR/libc_pthread_mutex_normal_unlock_unlocked.rs:LL:CC + | +LL | libc::pthread_mutex_unlock(&mut mutex as *mut _); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unlocked a PTHREAD_MUTEX_NORMAL mutex that was not locked by the current thread + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/libc_pthread_mutex_normal_unlock_unlocked.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/sync/libc_pthread_mutex_wrong_owner.stderr b/tests/compile-fail/sync/libc_pthread_mutex_wrong_owner.stderr new file mode 100644 index 0000000000000..6603b264d9b48 --- /dev/null +++ b/tests/compile-fail/sync/libc_pthread_mutex_wrong_owner.stderr @@ -0,0 +1,17 @@ +warning: thread support is experimental and incomplete: weak memory effects are not emulated. + +error: Undefined Behavior: unlocked a default mutex that was not locked by the current thread + --> $DIR/libc_pthread_mutex_wrong_owner.rs:LL:CC + | +LL | ...t_eq!(libc::pthread_mutex_unlock(lock_copy.0.get() as *mut _), 0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unlocked a default mutex that was not locked by the current thread + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside closure at $DIR/libc_pthread_mutex_wrong_owner.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error; 1 warning emitted + diff --git a/tests/compile-fail/sync/libc_pthread_mutexattr_double_destroy.stderr b/tests/compile-fail/sync/libc_pthread_mutexattr_double_destroy.stderr new file mode 100644 index 0000000000000..21adfa61d115d --- /dev/null +++ b/tests/compile-fail/sync/libc_pthread_mutexattr_double_destroy.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory + --> $DIR/libc_pthread_mutexattr_double_destroy.rs:LL:CC + | +LL | libc::pthread_mutexattr_destroy(attr.as_mut_ptr()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/libc_pthread_mutexattr_double_destroy.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/sync/libc_pthread_rwlock_destroy_read_locked.stderr b/tests/compile-fail/sync/libc_pthread_rwlock_destroy_read_locked.stderr new file mode 100644 index 0000000000000..80a88a773e5ca --- /dev/null +++ b/tests/compile-fail/sync/libc_pthread_rwlock_destroy_read_locked.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: destroyed a locked rwlock + --> $DIR/libc_pthread_rwlock_destroy_read_locked.rs:LL:CC + | +LL | libc::pthread_rwlock_destroy(rw.get()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ destroyed a locked rwlock + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/libc_pthread_rwlock_destroy_read_locked.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/sync/libc_pthread_rwlock_destroy_write_locked.stderr b/tests/compile-fail/sync/libc_pthread_rwlock_destroy_write_locked.stderr new file mode 100644 index 0000000000000..0fd49a63306c2 --- /dev/null +++ b/tests/compile-fail/sync/libc_pthread_rwlock_destroy_write_locked.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: destroyed a locked rwlock + --> $DIR/libc_pthread_rwlock_destroy_write_locked.rs:LL:CC + | +LL | libc::pthread_rwlock_destroy(rw.get()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ destroyed a locked rwlock + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/libc_pthread_rwlock_destroy_write_locked.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/sync/libc_pthread_rwlock_double_destroy.stderr b/tests/compile-fail/sync/libc_pthread_rwlock_double_destroy.stderr new file mode 100644 index 0000000000000..d60afc67c85b5 --- /dev/null +++ b/tests/compile-fail/sync/libc_pthread_rwlock_double_destroy.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory + --> $DIR/libc_pthread_rwlock_double_destroy.rs:LL:CC + | +LL | libc::pthread_rwlock_destroy(&mut lock); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/libc_pthread_rwlock_double_destroy.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/sync/libc_pthread_rwlock_read_write_deadlock_single_thread.stderr b/tests/compile-fail/sync/libc_pthread_rwlock_read_write_deadlock_single_thread.stderr new file mode 100644 index 0000000000000..075c8f0ef529c --- /dev/null +++ b/tests/compile-fail/sync/libc_pthread_rwlock_read_write_deadlock_single_thread.stderr @@ -0,0 +1,12 @@ +error: deadlock: the evaluated program deadlocked + --> $DIR/libc_pthread_rwlock_read_write_deadlock_single_thread.rs:LL:CC + | +LL | libc::pthread_rwlock_wrlock(rw.get()); + | ^ the evaluated program deadlocked + | + = note: inside `main` at $DIR/libc_pthread_rwlock_read_write_deadlock_single_thread.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/sync/libc_pthread_rwlock_read_wrong_owner.stderr b/tests/compile-fail/sync/libc_pthread_rwlock_read_wrong_owner.stderr new file mode 100644 index 0000000000000..d3820f0dcb742 --- /dev/null +++ b/tests/compile-fail/sync/libc_pthread_rwlock_read_wrong_owner.stderr @@ -0,0 +1,17 @@ +warning: thread support is experimental and incomplete: weak memory effects are not emulated. + +error: Undefined Behavior: unlocked an rwlock that was not locked by the active thread + --> $DIR/libc_pthread_rwlock_read_wrong_owner.rs:LL:CC + | +LL | ... assert_eq!(libc::pthread_rwlock_unlock(lock_copy.0.get() as *mut _), 0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unlocked an rwlock that was not locked by the active thread + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside closure at $DIR/libc_pthread_rwlock_read_wrong_owner.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error; 1 warning emitted + diff --git a/tests/compile-fail/sync/libc_pthread_rwlock_unlock_unlocked.stderr b/tests/compile-fail/sync/libc_pthread_rwlock_unlock_unlocked.stderr new file mode 100644 index 0000000000000..f8454d05587fc --- /dev/null +++ b/tests/compile-fail/sync/libc_pthread_rwlock_unlock_unlocked.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: unlocked an rwlock that was not locked by the active thread + --> $DIR/libc_pthread_rwlock_unlock_unlocked.rs:LL:CC + | +LL | libc::pthread_rwlock_unlock(rw.get()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unlocked an rwlock that was not locked by the active thread + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/libc_pthread_rwlock_unlock_unlocked.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/sync/libc_pthread_rwlock_write_read_deadlock.stderr b/tests/compile-fail/sync/libc_pthread_rwlock_write_read_deadlock.stderr new file mode 100644 index 0000000000000..748a363a27a4d --- /dev/null +++ b/tests/compile-fail/sync/libc_pthread_rwlock_write_read_deadlock.stderr @@ -0,0 +1,14 @@ +warning: thread support is experimental and incomplete: weak memory effects are not emulated. + +error: deadlock: the evaluated program deadlocked + --> $DIR/libc_pthread_rwlock_write_read_deadlock.rs:LL:CC + | +LL | assert_eq!(libc::pthread_rwlock_wrlock(lock_copy.0.get() as *mut _), 0); + | ^ the evaluated program deadlocked + | + = note: inside closure at $DIR/libc_pthread_rwlock_write_read_deadlock.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error; 1 warning emitted + diff --git a/tests/compile-fail/sync/libc_pthread_rwlock_write_read_deadlock_single_thread.stderr b/tests/compile-fail/sync/libc_pthread_rwlock_write_read_deadlock_single_thread.stderr new file mode 100644 index 0000000000000..caab19a782f97 --- /dev/null +++ b/tests/compile-fail/sync/libc_pthread_rwlock_write_read_deadlock_single_thread.stderr @@ -0,0 +1,12 @@ +error: deadlock: the evaluated program deadlocked + --> $DIR/libc_pthread_rwlock_write_read_deadlock_single_thread.rs:LL:CC + | +LL | libc::pthread_rwlock_rdlock(rw.get()); + | ^ the evaluated program deadlocked + | + = note: inside `main` at $DIR/libc_pthread_rwlock_write_read_deadlock_single_thread.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/sync/libc_pthread_rwlock_write_write_deadlock.stderr b/tests/compile-fail/sync/libc_pthread_rwlock_write_write_deadlock.stderr new file mode 100644 index 0000000000000..c6a03ff9afb82 --- /dev/null +++ b/tests/compile-fail/sync/libc_pthread_rwlock_write_write_deadlock.stderr @@ -0,0 +1,14 @@ +warning: thread support is experimental and incomplete: weak memory effects are not emulated. + +error: deadlock: the evaluated program deadlocked + --> $DIR/libc_pthread_rwlock_write_write_deadlock.rs:LL:CC + | +LL | assert_eq!(libc::pthread_rwlock_wrlock(lock_copy.0.get() as *mut _), 0); + | ^ the evaluated program deadlocked + | + = note: inside closure at $DIR/libc_pthread_rwlock_write_write_deadlock.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error; 1 warning emitted + diff --git a/tests/compile-fail/sync/libc_pthread_rwlock_write_write_deadlock_single_thread.stderr b/tests/compile-fail/sync/libc_pthread_rwlock_write_write_deadlock_single_thread.stderr new file mode 100644 index 0000000000000..30f5f447c717c --- /dev/null +++ b/tests/compile-fail/sync/libc_pthread_rwlock_write_write_deadlock_single_thread.stderr @@ -0,0 +1,12 @@ +error: deadlock: the evaluated program deadlocked + --> $DIR/libc_pthread_rwlock_write_write_deadlock_single_thread.rs:LL:CC + | +LL | libc::pthread_rwlock_wrlock(rw.get()); + | ^ the evaluated program deadlocked + | + = note: inside `main` at $DIR/libc_pthread_rwlock_write_write_deadlock_single_thread.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/sync/libc_pthread_rwlock_write_wrong_owner.stderr b/tests/compile-fail/sync/libc_pthread_rwlock_write_wrong_owner.stderr new file mode 100644 index 0000000000000..02a6cf11c0a20 --- /dev/null +++ b/tests/compile-fail/sync/libc_pthread_rwlock_write_wrong_owner.stderr @@ -0,0 +1,17 @@ +warning: thread support is experimental and incomplete: weak memory effects are not emulated. + +error: Undefined Behavior: unlocked an rwlock that was not locked by the active thread + --> $DIR/libc_pthread_rwlock_write_wrong_owner.rs:LL:CC + | +LL | ... assert_eq!(libc::pthread_rwlock_unlock(lock_copy.0.get() as *mut _), 0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unlocked an rwlock that was not locked by the active thread + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside closure at $DIR/libc_pthread_rwlock_write_wrong_owner.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error; 1 warning emitted + diff --git a/tests/compile-fail/too-big-slice.stderr b/tests/compile-fail/too-big-slice.stderr new file mode 100644 index 0000000000000..11d20d3e623b0 --- /dev/null +++ b/tests/compile-fail/too-big-slice.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: type validation failed: encountered invalid reference metadata: slice is bigger than largest supported object + --> $DIR/too-big-slice.rs:LL:CC + | +LL | let _x: &[u8] = mem::transmute((ptr, usize::MAX)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered invalid reference metadata: slice is bigger than largest supported object + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/too-big-slice.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/too-big-unsized.stderr b/tests/compile-fail/too-big-unsized.stderr new file mode 100644 index 0000000000000..0c7b7b23246ef --- /dev/null +++ b/tests/compile-fail/too-big-unsized.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: type validation failed: encountered invalid reference metadata: total size is bigger than largest supported object + --> $DIR/too-big-unsized.rs:LL:CC + | +LL | let _x: &MySlice = mem::transmute((ptr, isize::MAX as usize)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered invalid reference metadata: total size is bigger than largest supported object + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/too-big-unsized.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/transmute-pair-uninit.stderr b/tests/compile-fail/transmute-pair-uninit.stderr new file mode 100644 index 0000000000000..f574e97402825 --- /dev/null +++ b/tests/compile-fail/transmute-pair-uninit.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory + --> $DIR/transmute-pair-uninit.rs:LL:CC + | +LL | if v == 0 { println!("it is zero"); } + | ^^^^^^ using uninitialized data, but this operation requires initialized memory + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/transmute-pair-uninit.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/transmute_fat1.stderr b/tests/compile-fail/transmute_fat1.stderr new file mode 100644 index 0000000000000..2966f042001c3 --- /dev/null +++ b/tests/compile-fail/transmute_fat1.stderr @@ -0,0 +1,14 @@ +error: unsupported operation: unable to turn pointer into raw bytes + --> $DIR/transmute_fat1.rs:LL:CC + | +LL | let _val = bad[0] + bad[bad.len()-1]; + | ^^^^^^ unable to turn pointer into raw bytes + | + = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support + + = note: inside `main` at $DIR/transmute_fat1.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/type-too-large.stderr b/tests/compile-fail/type-too-large.stderr new file mode 100644 index 0000000000000..3d555da40cc3e --- /dev/null +++ b/tests/compile-fail/type-too-large.stderr @@ -0,0 +1,12 @@ +error: post-monomorphization error: values of the type `[u8; 2305843011361177600]` are too big for the current architecture + --> $DIR/type-too-large.rs:LL:CC + | +LL | [0; (1u64<<61) as usize +(1u64<<31) as usize]; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ values of the type `[u8; 2305843011361177600]` are too big for the current architecture + | + = note: inside `main` at $DIR/type-too-large.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/unaligned_pointers/alignment.rs b/tests/compile-fail/unaligned_pointers/alignment.rs index ff31fc6c293e9..b77f0eef82dd1 100644 --- a/tests/compile-fail/unaligned_pointers/alignment.rs +++ b/tests/compile-fail/unaligned_pointers/alignment.rs @@ -1,4 +1,5 @@ // error-pattern: but alignment 4 is required +// normalize-stderr-test: "\.add\(1\)" -> " " fn main() { // No retry needed, this fails reliably. @@ -7,7 +8,7 @@ fn main() { let x_ptr: *mut u8 = x.as_mut_ptr(); // At least one of these is definitely unaligned. unsafe { - *(x_ptr as *mut u32) = 42; + *(x_ptr as *mut u32) = 42; *(x_ptr.add(1) as *mut u32) = 42; } } diff --git a/tests/compile-fail/unaligned_pointers/alignment.stderr b/tests/compile-fail/unaligned_pointers/alignment.stderr new file mode 100644 index 0000000000000..c21e2ed2ec674 --- /dev/null +++ b/tests/compile-fail/unaligned_pointers/alignment.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: accessing memory with alignment ALIGN, but alignment ALIGN is required + --> $DIR/alignment.rs:LL:CC + | +LL | *(x_ptr as *mut u32) = 42; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ accessing memory with alignment ALIGN, but alignment ALIGN is required + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/alignment.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/unaligned_pointers/atomic_unaligned.stderr b/tests/compile-fail/unaligned_pointers/atomic_unaligned.stderr new file mode 100644 index 0000000000000..f56e6612fb32f --- /dev/null +++ b/tests/compile-fail/unaligned_pointers/atomic_unaligned.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: accessing memory with alignment ALIGN, but alignment ALIGN is required + --> $DIR/atomic_unaligned.rs:LL:CC + | +LL | ::std::intrinsics::atomic_load(zptr); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ accessing memory with alignment ALIGN, but alignment ALIGN is required + | + = help: this usually indicates that your program performed an invalid operation and caused Undefined Behavior + = help: but due to `-Zmiri-symbolic-alignment-check`, alignment errors can also be false positives + + = note: inside `main` at $DIR/atomic_unaligned.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/unaligned_pointers/dyn_alignment.rs b/tests/compile-fail/unaligned_pointers/dyn_alignment.rs index 91d9ec475b1fe..9d8829fe1ee0c 100644 --- a/tests/compile-fail/unaligned_pointers/dyn_alignment.rs +++ b/tests/compile-fail/unaligned_pointers/dyn_alignment.rs @@ -16,6 +16,6 @@ fn main() { // Overwrite the data part of `ptr` so it points to `buf`. unsafe { (&mut ptr as *mut _ as *mut *const u8).write(&buf as *const _ as *const u8); } // Re-borrow that. This should be UB. - let _ptr = &*ptr; //~ERROR alignment 256 is required + let _ptr = &*ptr; //~ERROR alignment ALIGN is required } } diff --git a/tests/compile-fail/unaligned_pointers/dyn_alignment.stderr b/tests/compile-fail/unaligned_pointers/dyn_alignment.stderr new file mode 100644 index 0000000000000..6c64f0e365e7c --- /dev/null +++ b/tests/compile-fail/unaligned_pointers/dyn_alignment.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: accessing memory with alignment ALIGN, but alignment ALIGN is required + --> $DIR/dyn_alignment.rs:LL:CC + | +LL | let _ptr = &*ptr; + | ^^^^^ accessing memory with alignment ALIGN, but alignment ALIGN is required + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/dyn_alignment.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/unaligned_pointers/intptrcast_alignment_check.rs b/tests/compile-fail/unaligned_pointers/intptrcast_alignment_check.rs index 9872a493c02a9..a8d0b5afbb89d 100644 --- a/tests/compile-fail/unaligned_pointers/intptrcast_alignment_check.rs +++ b/tests/compile-fail/unaligned_pointers/intptrcast_alignment_check.rs @@ -12,6 +12,6 @@ fn main() { // Manually make sure the pointer is properly aligned. let base_addr_aligned = if base_addr % 2 == 0 { base_addr } else { base_addr+1 }; let u16_ptr = base_addr_aligned as *mut u16; - unsafe { *u16_ptr = 2; } //~ERROR memory with alignment 1, but alignment 2 is required + unsafe { *u16_ptr = 2; } //~ERROR memory with alignment ALIGN, but alignment ALIGN is required println!("{:?}", x); } diff --git a/tests/compile-fail/unaligned_pointers/intptrcast_alignment_check.stderr b/tests/compile-fail/unaligned_pointers/intptrcast_alignment_check.stderr new file mode 100644 index 0000000000000..8e0986c453356 --- /dev/null +++ b/tests/compile-fail/unaligned_pointers/intptrcast_alignment_check.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: accessing memory with alignment ALIGN, but alignment ALIGN is required + --> $DIR/intptrcast_alignment_check.rs:LL:CC + | +LL | unsafe { *u16_ptr = 2; } + | ^^^^^^^^^^^^ accessing memory with alignment ALIGN, but alignment ALIGN is required + | + = help: this usually indicates that your program performed an invalid operation and caused Undefined Behavior + = help: but due to `-Zmiri-symbolic-alignment-check`, alignment errors can also be false positives + + = note: inside `main` at $DIR/intptrcast_alignment_check.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/unaligned_pointers/reference_to_packed.rs b/tests/compile-fail/unaligned_pointers/reference_to_packed.rs index b376859d22c11..60d2524040a26 100644 --- a/tests/compile-fail/unaligned_pointers/reference_to_packed.rs +++ b/tests/compile-fail/unaligned_pointers/reference_to_packed.rs @@ -16,6 +16,6 @@ fn main() { y: 99, }; let p = &foo.x; - let i = *p; //~ERROR alignment 4 is required + let i = *p; //~ERROR alignment ALIGN is required } } diff --git a/tests/compile-fail/unaligned_pointers/reference_to_packed.stderr b/tests/compile-fail/unaligned_pointers/reference_to_packed.stderr new file mode 100644 index 0000000000000..3dbc47f71d7b4 --- /dev/null +++ b/tests/compile-fail/unaligned_pointers/reference_to_packed.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: accessing memory with alignment ALIGN, but alignment ALIGN is required + --> $DIR/reference_to_packed.rs:LL:CC + | +LL | let i = *p; + | ^^ accessing memory with alignment ALIGN, but alignment ALIGN is required + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/reference_to_packed.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/unaligned_pointers/unaligned_ptr1.rs b/tests/compile-fail/unaligned_pointers/unaligned_ptr1.rs index 1d72e5170b7c2..fe46e7b8addb3 100644 --- a/tests/compile-fail/unaligned_pointers/unaligned_ptr1.rs +++ b/tests/compile-fail/unaligned_pointers/unaligned_ptr1.rs @@ -6,6 +6,6 @@ fn main() { let x = [2u16, 3, 4]; // Make it big enough so we don't get an out-of-bounds error. let x = &x[0] as *const _ as *const u32; // This must fail because alignment is violated: the allocation's base is not sufficiently aligned. - let _x = unsafe { *x }; //~ERROR memory with alignment 2, but alignment 4 is required + let _x = unsafe { *x }; //~ERROR memory with alignment ALIGN, but alignment ALIGN is required } } diff --git a/tests/compile-fail/unaligned_pointers/unaligned_ptr1.stderr b/tests/compile-fail/unaligned_pointers/unaligned_ptr1.stderr new file mode 100644 index 0000000000000..afc458e9ccb12 --- /dev/null +++ b/tests/compile-fail/unaligned_pointers/unaligned_ptr1.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: accessing memory with alignment ALIGN, but alignment ALIGN is required + --> $DIR/unaligned_ptr1.rs:LL:CC + | +LL | let _x = unsafe { *x }; + | ^^ accessing memory with alignment ALIGN, but alignment ALIGN is required + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/unaligned_ptr1.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/unaligned_pointers/unaligned_ptr2.rs b/tests/compile-fail/unaligned_pointers/unaligned_ptr2.rs index 49612e2b8a096..1d1e7fad05c94 100644 --- a/tests/compile-fail/unaligned_pointers/unaligned_ptr2.rs +++ b/tests/compile-fail/unaligned_pointers/unaligned_ptr2.rs @@ -8,5 +8,5 @@ fn main() { let x = (x.as_ptr() as *const u8).wrapping_offset(3) as *const u32; // This must fail because alignment is violated: the offset is not sufficiently aligned. // Also make the offset not a power of 2, that used to ICE. - let _x = unsafe { *x }; //~ERROR memory with alignment 1, but alignment 4 is required + let _x = unsafe { *x }; //~ERROR memory with alignment ALIGN, but alignment ALIGN is required } diff --git a/tests/compile-fail/unaligned_pointers/unaligned_ptr2.stderr b/tests/compile-fail/unaligned_pointers/unaligned_ptr2.stderr new file mode 100644 index 0000000000000..ac1ef5c381211 --- /dev/null +++ b/tests/compile-fail/unaligned_pointers/unaligned_ptr2.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: accessing memory with alignment ALIGN, but alignment ALIGN is required + --> $DIR/unaligned_ptr2.rs:LL:CC + | +LL | let _x = unsafe { *x }; + | ^^ accessing memory with alignment ALIGN, but alignment ALIGN is required + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/unaligned_ptr2.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/unaligned_pointers/unaligned_ptr3.stderr b/tests/compile-fail/unaligned_pointers/unaligned_ptr3.stderr new file mode 100644 index 0000000000000..7075bb4c7b4b5 --- /dev/null +++ b/tests/compile-fail/unaligned_pointers/unaligned_ptr3.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: accessing memory with alignment ALIGN, but alignment ALIGN is required + --> $DIR/unaligned_ptr3.rs:LL:CC + | +LL | let _x = unsafe { *x }; + | ^^ accessing memory with alignment ALIGN, but alignment ALIGN is required + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/unaligned_ptr3.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/unaligned_pointers/unaligned_ptr4.stderr b/tests/compile-fail/unaligned_pointers/unaligned_ptr4.stderr new file mode 100644 index 0000000000000..e72f28682fd7d --- /dev/null +++ b/tests/compile-fail/unaligned_pointers/unaligned_ptr4.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: accessing memory with alignment ALIGN, but alignment ALIGN is required + --> $DIR/unaligned_ptr4.rs:LL:CC + | +LL | let _val = unsafe { *ptr }; + | ^^^^ accessing memory with alignment ALIGN, but alignment ALIGN is required + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/unaligned_ptr4.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/unaligned_pointers/unaligned_ptr_addr_of.rs b/tests/compile-fail/unaligned_pointers/unaligned_ptr_addr_of.rs index e33f3c8598f33..d97306b3cb815 100644 --- a/tests/compile-fail/unaligned_pointers/unaligned_ptr_addr_of.rs +++ b/tests/compile-fail/unaligned_pointers/unaligned_ptr_addr_of.rs @@ -8,6 +8,6 @@ fn main() { let x = &x[0] as *const _ as *const u32; // This must fail because alignment is violated: the allocation's base is not sufficiently aligned. // The deref is UB even if we just put the result into a raw pointer. - let _x = unsafe { ptr::addr_of!(*x) }; //~ ERROR memory with alignment 2, but alignment 4 is required + let _x = unsafe { ptr::addr_of!(*x) }; //~ ERROR memory with alignment ALIGN, but alignment ALIGN is required } } diff --git a/tests/compile-fail/unaligned_pointers/unaligned_ptr_addr_of.stderr b/tests/compile-fail/unaligned_pointers/unaligned_ptr_addr_of.stderr new file mode 100644 index 0000000000000..b858a291dea83 --- /dev/null +++ b/tests/compile-fail/unaligned_pointers/unaligned_ptr_addr_of.stderr @@ -0,0 +1,16 @@ +error: Undefined Behavior: accessing memory with alignment ALIGN, but alignment ALIGN is required + --> $DIR/unaligned_ptr_addr_of.rs:LL:CC + | +LL | let _x = unsafe { ptr::addr_of!(*x) }; + | ^^^^^^^^^^^^^^^^^ accessing memory with alignment ALIGN, but alignment ALIGN is required + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at rustc_src/src/ptr/mod.rs:LL:CC + = note: this error originates in the macro `ptr::addr_of` (in Nightly builds, run with -Z macro-backtrace for more info) + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/unaligned_pointers/unaligned_ptr_zst.rs b/tests/compile-fail/unaligned_pointers/unaligned_ptr_zst.rs index 27403c11abc74..c549688c262e9 100644 --- a/tests/compile-fail/unaligned_pointers/unaligned_ptr_zst.rs +++ b/tests/compile-fail/unaligned_pointers/unaligned_ptr_zst.rs @@ -7,6 +7,6 @@ fn main() { let x = i as u8; let x = &x as *const _ as *const [u32; 0]; // This must fail because alignment is violated. Test specifically for loading ZST. - let _x = unsafe { *x }; //~ERROR alignment 4 is required + let _x = unsafe { *x }; //~ERROR alignment ALIGN is required } } diff --git a/tests/compile-fail/unaligned_pointers/unaligned_ptr_zst.stderr b/tests/compile-fail/unaligned_pointers/unaligned_ptr_zst.stderr new file mode 100644 index 0000000000000..7ee9a949cc717 --- /dev/null +++ b/tests/compile-fail/unaligned_pointers/unaligned_ptr_zst.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: accessing memory with alignment ALIGN, but alignment ALIGN is required + --> $DIR/unaligned_ptr_zst.rs:LL:CC + | +LL | let _x = unsafe { *x }; + | ^^ accessing memory with alignment ALIGN, but alignment ALIGN is required + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/unaligned_ptr_zst.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/uninit_buffer.stderr b/tests/compile-fail/uninit_buffer.stderr new file mode 100644 index 0000000000000..903a1deee3fef --- /dev/null +++ b/tests/compile-fail/uninit_buffer.stderr @@ -0,0 +1,23 @@ +error: Undefined Behavior: reading 16 bytes of memory starting at ALLOC, but 12 bytes are uninitialized starting at ALLOC+0x4, and this operation requires initialized memory + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `::compare` at rustc_src/src/slice/cmp.rs:LL:CC + = note: inside `core::slice::cmp::::cmp` at rustc_src/src/slice/cmp.rs:LL:CC +note: inside `main` at $DIR/uninit_buffer.rs:LL:CC + --> $DIR/uninit_buffer.rs:LL:CC + | +LL | drop(slice1.cmp(slice2)); + | ^^^^^^^^^^^^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +Uninitialized read occurred at offsets 0x4..0x10 into this allocation: +ALLOC (Rust heap, size: 32, align: 8) { + 0x00 │ 41 42 43 44 __ __ __ __ __ __ __ __ __ __ __ __ │ ABCD░░░░░░░░░░░░ + 0x10 │ 00 __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ │ .░░░░░░░░░░░░░░░ +} + +error: aborting due to previous error + diff --git a/tests/compile-fail/uninit_byte_read.stderr b/tests/compile-fail/uninit_byte_read.stderr new file mode 100644 index 0000000000000..b07473f95b9e4 --- /dev/null +++ b/tests/compile-fail/uninit_byte_read.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory + --> $DIR/uninit_byte_read.rs:LL:CC + | +LL | let x = undef + 1; + | ^^^^^^^^^ using uninitialized data, but this operation requires initialized memory + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/uninit_byte_read.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/uninit_float.stderr b/tests/compile-fail/uninit_float.stderr new file mode 100644 index 0000000000000..90cdc3ba0fae5 --- /dev/null +++ b/tests/compile-fail/uninit_float.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: type validation failed at .value: encountered uninitialized bytes, but expected initialized plain (non-pointer) bytes + --> $DIR/uninit_float.rs:LL:CC + | +LL | let _val = unsafe { std::mem::MaybeUninit::::uninit().assume_init() }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .value: encountered uninitialized bytes, but expected initialized plain (non-pointer) bytes + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/uninit_float.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/uninit_integer.stderr b/tests/compile-fail/uninit_integer.stderr new file mode 100644 index 0000000000000..88b57c1d279a0 --- /dev/null +++ b/tests/compile-fail/uninit_integer.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: type validation failed at .value: encountered uninitialized bytes, but expected initialized plain (non-pointer) bytes + --> $DIR/uninit_integer.rs:LL:CC + | +LL | let _val = unsafe { std::mem::MaybeUninit::::uninit().assume_init() }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .value: encountered uninitialized bytes, but expected initialized plain (non-pointer) bytes + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/uninit_integer.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/uninit_integer_signed.stderr b/tests/compile-fail/uninit_integer_signed.stderr new file mode 100644 index 0000000000000..fc15462280a61 --- /dev/null +++ b/tests/compile-fail/uninit_integer_signed.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: type validation failed at .value: encountered uninitialized bytes, but expected initialized plain (non-pointer) bytes + --> $DIR/uninit_integer_signed.rs:LL:CC + | +LL | let _val = unsafe { std::mem::MaybeUninit::::uninit().assume_init() }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .value: encountered uninitialized bytes, but expected initialized plain (non-pointer) bytes + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/uninit_integer_signed.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/uninit_raw_ptr.stderr b/tests/compile-fail/uninit_raw_ptr.stderr new file mode 100644 index 0000000000000..96074fc1e7890 --- /dev/null +++ b/tests/compile-fail/uninit_raw_ptr.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: type validation failed at .value: encountered uninitialized raw pointer + --> $DIR/uninit_raw_ptr.rs:LL:CC + | +LL | let _val = unsafe { std::mem::MaybeUninit::<*const u8>::uninit().assume_init() }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .value: encountered uninitialized raw pointer + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/uninit_raw_ptr.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/unreachable.stderr b/tests/compile-fail/unreachable.stderr new file mode 100644 index 0000000000000..59ab843319552 --- /dev/null +++ b/tests/compile-fail/unreachable.stderr @@ -0,0 +1,16 @@ +error: Undefined Behavior: entering unreachable code + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `std::hint::unreachable_unchecked` at rustc_src/src/hint.rs:LL:CC +note: inside `main` at $DIR/unreachable.rs:LL:CC + --> $DIR/unreachable.rs:LL:CC + | +LL | unsafe { std::hint::unreachable_unchecked() } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/unsupported_foreign_function.stderr b/tests/compile-fail/unsupported_foreign_function.stderr new file mode 100644 index 0000000000000..b8b1925d2cccf --- /dev/null +++ b/tests/compile-fail/unsupported_foreign_function.stderr @@ -0,0 +1,14 @@ +error: unsupported operation: can't call foreign function: foo + --> $DIR/unsupported_foreign_function.rs:LL:CC + | +LL | foo(); + | ^^^^^ can't call foreign function: foo + | + = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support + + = note: inside `main` at $DIR/unsupported_foreign_function.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/unsupported_signal.stderr b/tests/compile-fail/unsupported_signal.stderr new file mode 100644 index 0000000000000..8fcbc7fb47395 --- /dev/null +++ b/tests/compile-fail/unsupported_signal.stderr @@ -0,0 +1,14 @@ +error: unsupported operation: can't call foreign function: signal + --> $DIR/unsupported_signal.rs:LL:CC + | +LL | libc::signal(libc::SIGPIPE, libc::SIG_IGN); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't call foreign function: signal + | + = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support + + = note: inside `main` at $DIR/unsupported_signal.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/validity/cast_fn_ptr1.stderr b/tests/compile-fail/validity/cast_fn_ptr1.stderr new file mode 100644 index 0000000000000..d048377a7793d --- /dev/null +++ b/tests/compile-fail/validity/cast_fn_ptr1.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: type validation failed: encountered a null reference + --> $DIR/cast_fn_ptr1.rs:LL:CC + | +LL | g(0usize as *const i32) + | ^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a null reference + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/cast_fn_ptr1.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/validity/cast_fn_ptr2.stderr b/tests/compile-fail/validity/cast_fn_ptr2.stderr new file mode 100644 index 0000000000000..10b9b9b8602b6 --- /dev/null +++ b/tests/compile-fail/validity/cast_fn_ptr2.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: type validation failed: encountered a null reference + --> $DIR/cast_fn_ptr2.rs:LL:CC + | +LL | let _x = g(); + | ^^^ type validation failed: encountered a null reference + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/cast_fn_ptr2.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/validity/dangling_ref1.rs b/tests/compile-fail/validity/dangling_ref1.rs index 78425cde4a8aa..3243eee06eb67 100644 --- a/tests/compile-fail/validity/dangling_ref1.rs +++ b/tests/compile-fail/validity/dangling_ref1.rs @@ -3,5 +3,5 @@ use std::mem; fn main() { - let _x: &i32 = unsafe { mem::transmute(16usize) }; //~ ERROR encountered a dangling reference (address 0x10 is unallocated) + let _x: &i32 = unsafe { mem::transmute(16usize) }; //~ ERROR encountered a dangling reference (address $HEX is unallocated) } diff --git a/tests/compile-fail/validity/dangling_ref1.stderr b/tests/compile-fail/validity/dangling_ref1.stderr new file mode 100644 index 0000000000000..0d358fd7f7f96 --- /dev/null +++ b/tests/compile-fail/validity/dangling_ref1.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: type validation failed: encountered a dangling reference (address 0x10 is unallocated) + --> $DIR/dangling_ref1.rs:LL:CC + | +LL | let _x: &i32 = unsafe { mem::transmute(16usize) }; + | ^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a dangling reference (address 0x10 is unallocated) + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/dangling_ref1.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/validity/dangling_ref2.stderr b/tests/compile-fail/validity/dangling_ref2.stderr new file mode 100644 index 0000000000000..e3bbb72fdcf1e --- /dev/null +++ b/tests/compile-fail/validity/dangling_ref2.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: type validation failed: encountered a dangling reference (going beyond the bounds of its allocation) + --> $DIR/dangling_ref2.rs:LL:CC + | +LL | let _x: &i32 = unsafe { mem::transmute(ptr) }; + | ^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a dangling reference (going beyond the bounds of its allocation) + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/dangling_ref2.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/validity/dangling_ref3.stderr b/tests/compile-fail/validity/dangling_ref3.stderr new file mode 100644 index 0000000000000..5842eca9fc8ea --- /dev/null +++ b/tests/compile-fail/validity/dangling_ref3.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: type validation failed: encountered a dangling reference (use-after-free) + --> $DIR/dangling_ref3.rs:LL:CC + | +LL | let _x: &i32 = unsafe { mem::transmute(dangling()) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a dangling reference (use-after-free) + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/dangling_ref3.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/validity/invalid_bool.rs b/tests/compile-fail/validity/invalid_bool.rs index 0b2d648d02adc..df6c19df7f231 100644 --- a/tests/compile-fail/validity/invalid_bool.rs +++ b/tests/compile-fail/validity/invalid_bool.rs @@ -1,3 +1,3 @@ fn main() { - let _b = unsafe { std::mem::transmute::(2) }; //~ ERROR encountered 0x02, but expected a boolean + let _b = unsafe { std::mem::transmute::(2) }; //~ ERROR expected a boolean } diff --git a/tests/compile-fail/validity/invalid_bool.stderr b/tests/compile-fail/validity/invalid_bool.stderr new file mode 100644 index 0000000000000..d17319d2dce8c --- /dev/null +++ b/tests/compile-fail/validity/invalid_bool.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: type validation failed: encountered 0x02, but expected a boolean + --> $DIR/invalid_bool.rs:LL:CC + | +LL | let _b = unsafe { std::mem::transmute::(2) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0x02, but expected a boolean + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/invalid_bool.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/validity/invalid_bool_uninit.stderr b/tests/compile-fail/validity/invalid_bool_uninit.stderr new file mode 100644 index 0000000000000..e262e69dc6968 --- /dev/null +++ b/tests/compile-fail/validity/invalid_bool_uninit.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: type validation failed: encountered uninitialized bytes, but expected a boolean + --> $DIR/invalid_bool_uninit.rs:LL:CC + | +LL | let _b = unsafe { MyUninit { init: () }.uninit }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized bytes, but expected a boolean + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/invalid_bool_uninit.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/validity/invalid_char.rs b/tests/compile-fail/validity/invalid_char.rs index 079823f894a86..d9a55f241c00b 100644 --- a/tests/compile-fail/validity/invalid_char.rs +++ b/tests/compile-fail/validity/invalid_char.rs @@ -1,6 +1,6 @@ fn main() { assert!(std::char::from_u32(-1_i32 as u32).is_none()); - let _val = match unsafe { std::mem::transmute::(-1) } { //~ ERROR encountered 0xffffffff, but expected a valid unicode scalar value + let _val = match unsafe { std::mem::transmute::(-1) } { //~ ERROR encountered $HEX, but expected a valid unicode scalar value 'a' => {true}, 'b' => {false}, _ => {true}, diff --git a/tests/compile-fail/validity/invalid_char.stderr b/tests/compile-fail/validity/invalid_char.stderr new file mode 100644 index 0000000000000..99f5ce0bb2118 --- /dev/null +++ b/tests/compile-fail/validity/invalid_char.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: type validation failed: encountered $HEX, but expected a valid unicode scalar value (in `0..=$HEX` but not in `$HEX..=$HEX`) + --> $DIR/invalid_char.rs:LL:CC + | +LL | let _val = match unsafe { std::mem::transmute::(-1) } { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered $HEX, but expected a valid unicode scalar value (in `0..=$HEX` but not in `$HEX..=$HEX`) + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/invalid_char.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/validity/invalid_char_uninit.rs b/tests/compile-fail/validity/invalid_char_uninit.rs index 34798dfbc6595..cb885d001cff0 100644 --- a/tests/compile-fail/validity/invalid_char_uninit.rs +++ b/tests/compile-fail/validity/invalid_char_uninit.rs @@ -6,5 +6,5 @@ union MyUninit { } fn main() { - let _b = unsafe { MyUninit { init: () }.uninit }; //~ ERROR encountered uninitialized bytes, but expected a valid unicode scalar value (in `0..=0x10FFFF` but not in `0xD800..=0xDFFF`) + let _b = unsafe { MyUninit { init: () }.uninit }; //~ ERROR encountered uninitialized bytes, but expected a valid unicode scalar value } diff --git a/tests/compile-fail/validity/invalid_char_uninit.stderr b/tests/compile-fail/validity/invalid_char_uninit.stderr new file mode 100644 index 0000000000000..b27c9b2bb69ca --- /dev/null +++ b/tests/compile-fail/validity/invalid_char_uninit.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: type validation failed: encountered uninitialized bytes, but expected a valid unicode scalar value (in `0..=$HEX` but not in `$HEX..=$HEX`) + --> $DIR/invalid_char_uninit.rs:LL:CC + | +LL | let _b = unsafe { MyUninit { init: () }.uninit }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized bytes, but expected a valid unicode scalar value (in `0..=$HEX` but not in `$HEX..=$HEX`) + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/invalid_char_uninit.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/validity/invalid_enum_tag.stderr b/tests/compile-fail/validity/invalid_enum_tag.stderr new file mode 100644 index 0000000000000..c6d862ae1b026 --- /dev/null +++ b/tests/compile-fail/validity/invalid_enum_tag.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: type validation failed at .: encountered $HEX, but expected a valid enum tag + --> $DIR/invalid_enum_tag.rs:LL:CC + | +LL | ... { std::mem::transmute::(42) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .: encountered $HEX, but expected a valid enum tag + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/invalid_enum_tag.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/validity/invalid_enum_tag_256variants_uninit.stderr b/tests/compile-fail/validity/invalid_enum_tag_256variants_uninit.stderr new file mode 100644 index 0000000000000..1a6039c477d6e --- /dev/null +++ b/tests/compile-fail/validity/invalid_enum_tag_256variants_uninit.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: type validation failed at .: encountered uninitialized bytes, but expected a valid enum tag + --> $DIR/invalid_enum_tag_256variants_uninit.rs:LL:CC + | +LL | let _a = unsafe { MyUninit { init: () }.uninit }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .: encountered uninitialized bytes, but expected a valid enum tag + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/invalid_enum_tag_256variants_uninit.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/validity/invalid_fnptr_null.stderr b/tests/compile-fail/validity/invalid_fnptr_null.stderr new file mode 100644 index 0000000000000..e3cea40e0c338 --- /dev/null +++ b/tests/compile-fail/validity/invalid_fnptr_null.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: type validation failed: encountered a null function pointer + --> $DIR/invalid_fnptr_null.rs:LL:CC + | +LL | let _b: fn() = unsafe { std::mem::transmute(0usize) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a null function pointer + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/invalid_fnptr_null.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/validity/invalid_fnptr_uninit.stderr b/tests/compile-fail/validity/invalid_fnptr_uninit.stderr new file mode 100644 index 0000000000000..84a5657e78709 --- /dev/null +++ b/tests/compile-fail/validity/invalid_fnptr_uninit.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: type validation failed: encountered uninitialized bytes, but expected a proper pointer or integer value + --> $DIR/invalid_fnptr_uninit.rs:LL:CC + | +LL | let _b = unsafe { MyUninit { init: () }.uninit }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized bytes, but expected a proper pointer or integer value + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/invalid_fnptr_uninit.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/validity/invalid_wide_raw.stderr b/tests/compile-fail/validity/invalid_wide_raw.stderr new file mode 100644 index 0000000000000..f64b824d6ba6e --- /dev/null +++ b/tests/compile-fail/validity/invalid_wide_raw.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: type validation failed: encountered dangling vtable pointer in wide pointer + --> $DIR/invalid_wide_raw.rs:LL:CC + | +LL | dbg!(S { x: unsafe { std::mem::transmute((0usize, 0usize)) } }); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered dangling vtable pointer in wide pointer + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/invalid_wide_raw.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/validity/nonzero.stderr b/tests/compile-fail/validity/nonzero.stderr new file mode 100644 index 0000000000000..ba01acb6a1694 --- /dev/null +++ b/tests/compile-fail/validity/nonzero.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: type validation failed: encountered 0, but expected something greater or equal to 1 + --> $DIR/nonzero.rs:LL:CC + | +LL | let _x = Some(unsafe { NonZero(0) }); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0, but expected something greater or equal to 1 + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/nonzero.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/validity/ptr_integer_array_transmute.stderr b/tests/compile-fail/validity/ptr_integer_array_transmute.stderr new file mode 100644 index 0000000000000..bc2ca54438ff9 --- /dev/null +++ b/tests/compile-fail/validity/ptr_integer_array_transmute.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: type validation failed: encountered a pointer, but expected plain (non-pointer) bytes + --> $DIR/ptr_integer_array_transmute.rs:LL:CC + | +LL | let _i: [usize; 1] = unsafe { std::mem::transmute(r) }; + | ^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected plain (non-pointer) bytes + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/ptr_integer_array_transmute.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/validity/ptr_integer_transmute.stderr b/tests/compile-fail/validity/ptr_integer_transmute.stderr new file mode 100644 index 0000000000000..cad53d71f4d9d --- /dev/null +++ b/tests/compile-fail/validity/ptr_integer_transmute.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: type validation failed: encountered pointer to $HEX[ALLOC], but expected plain (non-pointer) bytes + --> $DIR/ptr_integer_transmute.rs:LL:CC + | +LL | let _i: usize = unsafe { std::mem::transmute(r) }; + | ^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to $HEX[ALLOC], but expected plain (non-pointer) bytes + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/ptr_integer_transmute.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/validity/ref_to_uninhabited1.stderr b/tests/compile-fail/validity/ref_to_uninhabited1.stderr new file mode 100644 index 0000000000000..de41944944e3a --- /dev/null +++ b/tests/compile-fail/validity/ref_to_uninhabited1.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: type validation failed: encountered a box pointing to uninhabited type ! + --> $DIR/ref_to_uninhabited1.rs:LL:CC + | +LL | let x: Box = transmute(&mut 42); + | ^^^^^^^^^^^^^^^^^^ type validation failed: encountered a box pointing to uninhabited type ! + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/ref_to_uninhabited1.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/validity/ref_to_uninhabited2.stderr b/tests/compile-fail/validity/ref_to_uninhabited2.stderr new file mode 100644 index 0000000000000..754c39e78901c --- /dev/null +++ b/tests/compile-fail/validity/ref_to_uninhabited2.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: type validation failed: encountered a reference pointing to uninhabited type (i32, Void) + --> $DIR/ref_to_uninhabited2.rs:LL:CC + | +LL | let _x: &(i32, Void) = transmute(&42); + | ^^^^^^^^^^^^^^ type validation failed: encountered a reference pointing to uninhabited type (i32, Void) + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/ref_to_uninhabited2.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/validity/too-big-slice.stderr b/tests/compile-fail/validity/too-big-slice.stderr new file mode 100644 index 0000000000000..11d20d3e623b0 --- /dev/null +++ b/tests/compile-fail/validity/too-big-slice.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: type validation failed: encountered invalid reference metadata: slice is bigger than largest supported object + --> $DIR/too-big-slice.rs:LL:CC + | +LL | let _x: &[u8] = mem::transmute((ptr, usize::MAX)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered invalid reference metadata: slice is bigger than largest supported object + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/too-big-slice.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/validity/too-big-unsized.stderr b/tests/compile-fail/validity/too-big-unsized.stderr new file mode 100644 index 0000000000000..0c7b7b23246ef --- /dev/null +++ b/tests/compile-fail/validity/too-big-unsized.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: type validation failed: encountered invalid reference metadata: total size is bigger than largest supported object + --> $DIR/too-big-unsized.rs:LL:CC + | +LL | let _x: &MySlice = mem::transmute((ptr, isize::MAX as usize)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered invalid reference metadata: total size is bigger than largest supported object + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/too-big-unsized.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/validity/transmute_through_ptr.stderr b/tests/compile-fail/validity/transmute_through_ptr.stderr new file mode 100644 index 0000000000000..d06dbe3194f5f --- /dev/null +++ b/tests/compile-fail/validity/transmute_through_ptr.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: type validation failed at .: encountered $HEX, but expected a valid enum tag + --> $DIR/transmute_through_ptr.rs:LL:CC + | +LL | let y = x; // reading this ought to be enough to trigger validation + | ^ type validation failed at .: encountered $HEX, but expected a valid enum tag + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/transmute_through_ptr.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/validity/uninit_float.stderr b/tests/compile-fail/validity/uninit_float.stderr new file mode 100644 index 0000000000000..3f244adbabed0 --- /dev/null +++ b/tests/compile-fail/validity/uninit_float.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: type validation failed at .value: encountered uninitialized bytes, but expected initialized bytes + --> $DIR/uninit_float.rs:LL:CC + | +LL | let _val = unsafe { std::mem::MaybeUninit::::uninit().assume_init() }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .value: encountered uninitialized bytes, but expected initialized bytes + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/uninit_float.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/validity/uninit_integer.stderr b/tests/compile-fail/validity/uninit_integer.stderr new file mode 100644 index 0000000000000..e3e2f0a178526 --- /dev/null +++ b/tests/compile-fail/validity/uninit_integer.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: type validation failed at .value: encountered uninitialized bytes, but expected initialized bytes + --> $DIR/uninit_integer.rs:LL:CC + | +LL | let _val = unsafe { std::mem::MaybeUninit::::uninit().assume_init() }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .value: encountered uninitialized bytes, but expected initialized bytes + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/uninit_integer.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/validity/uninit_integer_signed.stderr b/tests/compile-fail/validity/uninit_integer_signed.stderr new file mode 100644 index 0000000000000..e6d9b51e40e40 --- /dev/null +++ b/tests/compile-fail/validity/uninit_integer_signed.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: type validation failed at .value: encountered uninitialized bytes, but expected initialized bytes + --> $DIR/uninit_integer_signed.rs:LL:CC + | +LL | let _val = unsafe { std::mem::MaybeUninit::::uninit().assume_init() }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .value: encountered uninitialized bytes, but expected initialized bytes + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/uninit_integer_signed.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/zst1.stderr b/tests/compile-fail/zst1.stderr new file mode 100644 index 0000000000000..ba13c9d7e52af --- /dev/null +++ b/tests/compile-fail/zst1.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: dereferencing pointer failed: ALLOC has size 0, so pointer to 1 byte starting at offset 0 is out-of-bounds + --> $DIR/zst1.rs:LL:CC + | +LL | let _val = unsafe { *x }; + | ^^ dereferencing pointer failed: ALLOC has size 0, so pointer to 1 byte starting at offset 0 is out-of-bounds + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/zst1.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/zst2.stderr b/tests/compile-fail/zst2.stderr new file mode 100644 index 0000000000000..088bb2a1ccf0c --- /dev/null +++ b/tests/compile-fail/zst2.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: pointer to ALLOC was dereferenced after this allocation got freed + --> $DIR/zst2.rs:LL:CC + | +LL | unsafe { *x = zst_val; } + | ^^^^^^^^^^^^ pointer to ALLOC was dereferenced after this allocation got freed + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/zst2.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compile-fail/zst3.stderr b/tests/compile-fail/zst3.stderr new file mode 100644 index 0000000000000..a7d84dcaad590 --- /dev/null +++ b/tests/compile-fail/zst3.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: dereferencing pointer failed: ALLOC has size 1, so pointer at offset 2 is out-of-bounds + --> $DIR/zst3.rs:LL:CC + | +LL | unsafe { *(x as *mut [u8; 0]) = zst_val; } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ dereferencing pointer failed: ALLOC has size 1, so pointer at offset 2 is out-of-bounds + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/zst3.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/compiletest.rs b/tests/compiletest.rs index a0d49c9ddcf48..92a8bd6291e29 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -1,82 +1,127 @@ +use colored::*; +use regex::Regex; use std::env; use std::path::PathBuf; - -use colored::*; -use compiletest_rs as compiletest; +use ui_test::{Config, Mode, OutputConflictHandling}; fn miri_path() -> PathBuf { PathBuf::from(option_env!("MIRI").unwrap_or(env!("CARGO_BIN_EXE_miri"))) } -fn run_tests(mode: &str, path: &str, target: &str) { +fn run_tests(mode: Mode, path: &str, target: Option) { let in_rustc_test_suite = option_env!("RUSTC_STAGE").is_some(); + // Add some flags we always want. let mut flags = Vec::new(); - flags.push("--edition 2018".to_owned()); + flags.push("--edition".to_owned()); + flags.push("2018".to_owned()); if in_rustc_test_suite { // Less aggressive warnings to make the rustc toolstate management less painful. // (We often get warnings when e.g. a feature gets stabilized or some lint gets added/improved.) flags.push("-Astable-features".to_owned()); } else { - flags.push("-Dwarnings -Dunused".to_owned()); // overwrite the -Aunused in compiletest-rs + flags.push("-Dwarnings".to_owned()); + flags.push("-Dunused".to_owned()); // overwrite the -Aunused in compiletest-rs } if let Ok(sysroot) = env::var("MIRI_SYSROOT") { - flags.push(format!("--sysroot {}", sysroot)); + flags.push("--sysroot".to_string()); + flags.push(sysroot); } if let Ok(extra_flags) = env::var("MIRIFLAGS") { - flags.push(extra_flags); + for flag in extra_flags.split_whitespace() { + flags.push(flag.to_string()); + } + } + flags.push("-Zui-testing".to_string()); + if let Some(target) = &target { + flags.push("--target".to_string()); + flags.push(target.clone()); } - let flags = flags.join(" "); - eprintln!(" Compiler flags: {}", flags); + let skip_ui_checks = in_rustc_test_suite || env::var_os("MIRI_SKIP_UI_CHECKS").is_some(); - // The rest of the configuration. - let mut config = compiletest::Config::default().tempdir(); - config.mode = mode.parse().expect("Invalid mode"); - config.rustc_path = miri_path(); - if let Some(lib_path) = option_env!("RUSTC_LIB_PATH") { - config.run_lib_path = PathBuf::from(lib_path); - config.compile_lib_path = PathBuf::from(lib_path); - } - config.filters = env::args().nth(1).into_iter().collect(); - config.host = get_host(); - config.src_base = PathBuf::from(path); - config.target = target.to_owned(); - config.target_rustcflags = Some(flags); - compiletest::run_tests(&config); -} + let output_conflict_handling = match (env::var_os("MIRI_BLESS").is_some(), skip_ui_checks) { + (false, false) => OutputConflictHandling::Error, + (true, false) => OutputConflictHandling::Bless, + (false, true) => OutputConflictHandling::Ignore, + (true, true) => panic!("cannot use MIRI_BLESS and MIRI_SKIP_UI_CHECKS at the same time"), + }; -fn compile_fail(path: &str, target: &str) { - eprintln!( - "{}", - format!("## Running compile-fail tests in {} against miri for target {}", path, target) - .green() - .bold() - ); + let config = Config { + args: flags, + target, + stderr_filters: STDERR.clone(), + stdout_filters: STDOUT.clone(), + root_dir: PathBuf::from(path), + mode, + program: miri_path(), + output_conflict_handling, + }; + ui_test::run_tests(config) +} - run_tests("compile-fail", path, target); +macro_rules! regexes { + ($name:ident: $($regex:expr => $replacement:expr,)*) => {lazy_static::lazy_static! { + static ref $name: Vec<(Regex, &'static str)> = vec![ + $((Regex::new($regex).unwrap(), $replacement),)* + ]; + }}; } -fn miri_pass(path: &str, target: &str) { - eprintln!( - "{}", - format!("## Running run-pass tests in {} against miri for target {}", path, target) - .green() - .bold() - ); +regexes! { + STDOUT: + // Windows file paths + r"\\" => "/", +} - run_tests("ui", path, target); +regexes! { + STDERR: + // erase line and column info + r"\.rs:[0-9]+:[0-9]+" => ".rs:LL:CC", + // erase alloc ids + "alloc[0-9]+" => "ALLOC", + // erase Stacked Borrows tags + "<[0-9]+>" => "", + // erase whitespace that differs between platforms + r" +at (.*\.rs)" => " at $1", + // erase generics in backtraces + "([0-9]+: .*)::<.*>" => "$1", + // erase addresses in backtraces + "([0-9]+: ) +0x[0-9a-f]+ - (.*)" => "$1$2", + // erase long hexadecimals + r"0x[0-9a-fA-F]+[0-9a-fA-F]{2,2}" => "$$HEX", + // erase clocks + r"VClock\(\[[^\]]+\]\)" => "VClock", + // erase specific alignments + "alignment [0-9]+" => "alignment ALIGN", + // erase thread caller ids + r"\(call [0-9]+\)" => "(call ID)", + // erase platform module paths + "sys::[a-z]+::" => "sys::PLATFORM::", + // Windows file paths + r"\\" => "/", + // erase platform file paths + "sys/[a-z]+/" => "sys/PLATFORM/", + // erase error annotations in tests + r"\s*//~.*" => "", } -fn get_host() -> String { - let version_meta = - rustc_version::VersionMeta::for_command(std::process::Command::new(miri_path())) - .expect("failed to parse rustc version info"); - version_meta.host +fn ui(mode: Mode, path: &str) { + let target = get_target(); + + eprint!("{}", format!("## Running ui tests in {path} against miri for ").green().bold()); + + if let Some(target) = &target { + eprintln!("{target}"); + } else { + eprintln!("host"); + } + + run_tests(mode, path, target); } -fn get_target() -> String { - env::var("MIRI_TEST_TARGET").unwrap_or_else(|_| get_host()) +fn get_target() -> Option { + env::var("MIRI_TEST_TARGET").ok() } fn main() { @@ -84,10 +129,8 @@ fn main() { env::set_var("MIRI_ENV_VAR_TEST", "0"); // Let the tests know where to store temp files (they might run for a different target, which can make this hard to find). env::set_var("MIRI_TEMP", env::temp_dir()); - // Panic tests expect backtraces to be printed. - env::set_var("RUST_BACKTRACE", "1"); - let target = get_target(); - miri_pass("tests/run-pass", &target); - compile_fail("tests/compile-fail", &target); + ui(Mode::Pass, "tests/run-pass"); + ui(Mode::Panic, "tests/run-fail"); + ui(Mode::Fail, "tests/compile-fail"); } diff --git a/tests/run-pass/function_calls/exported_symbol_good_unwind.rs b/tests/run-fail/function_calls/exported_symbol_good_unwind.rs similarity index 100% rename from tests/run-pass/function_calls/exported_symbol_good_unwind.rs rename to tests/run-fail/function_calls/exported_symbol_good_unwind.rs diff --git a/tests/run-pass/function_calls/exported_symbol_good_unwind.stderr b/tests/run-fail/function_calls/exported_symbol_good_unwind.stderr similarity index 80% rename from tests/run-pass/function_calls/exported_symbol_good_unwind.stderr rename to tests/run-fail/function_calls/exported_symbol_good_unwind.stderr index 40a8f39509fa7..bff897775e8f6 100644 --- a/tests/run-pass/function_calls/exported_symbol_good_unwind.stderr +++ b/tests/run-fail/function_calls/exported_symbol_good_unwind.stderr @@ -1,4 +1,4 @@ -thread 'main' panicked at 'explicit panic', $DIR/exported_symbol_good_unwind.rs:11:5 +thread 'main' panicked at 'explicit panic', $DIR/exported_symbol_good_unwind.rs:LL:CC note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace -thread 'main' panicked at 'explicit panic', $DIR/exported_symbol_good_unwind.rs:16:5 -thread 'main' panicked at 'explicit panic', $DIR/exported_symbol_good_unwind.rs:22:5 +thread 'main' panicked at 'explicit panic', $DIR/exported_symbol_good_unwind.rs:LL:CC +thread 'main' panicked at 'explicit panic', $DIR/exported_symbol_good_unwind.rs:LL:CC diff --git a/tests/run-pass/panic/div-by-zero-2.rs b/tests/run-fail/panic/div-by-zero-2.rs similarity index 100% rename from tests/run-pass/panic/div-by-zero-2.rs rename to tests/run-fail/panic/div-by-zero-2.rs diff --git a/tests/run-pass/panic/div-by-zero-2.stderr b/tests/run-fail/panic/div-by-zero-2.stderr similarity index 88% rename from tests/run-pass/panic/div-by-zero-2.stderr rename to tests/run-fail/panic/div-by-zero-2.stderr index 60ff33c8bfcd3..538d87113654d 100644 --- a/tests/run-pass/panic/div-by-zero-2.stderr +++ b/tests/run-fail/panic/div-by-zero-2.stderr @@ -1,2 +1,2 @@ -thread 'main' panicked at 'attempt to divide by zero', $DIR/div-by-zero-2.rs:4:14 +thread 'main' panicked at 'attempt to divide by zero', $DIR/div-by-zero-2.rs:LL:CC note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace diff --git a/tests/run-pass/panic/overflowing-lsh-neg.rs b/tests/run-fail/panic/overflowing-lsh-neg.rs similarity index 100% rename from tests/run-pass/panic/overflowing-lsh-neg.rs rename to tests/run-fail/panic/overflowing-lsh-neg.rs diff --git a/tests/run-pass/panic/overflowing-lsh-neg.stderr b/tests/run-fail/panic/overflowing-lsh-neg.stderr similarity index 80% rename from tests/run-pass/panic/overflowing-lsh-neg.stderr rename to tests/run-fail/panic/overflowing-lsh-neg.stderr index 64959da0faea7..21e434d873f7b 100644 --- a/tests/run-pass/panic/overflowing-lsh-neg.stderr +++ b/tests/run-fail/panic/overflowing-lsh-neg.stderr @@ -1,2 +1,2 @@ -thread 'main' panicked at 'attempt to shift left with overflow', $DIR/overflowing-lsh-neg.rs:4:14 +thread 'main' panicked at 'attempt to shift left with overflow', $DIR/overflowing-lsh-neg.rs:LL:CC note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace diff --git a/tests/run-pass/panic/overflowing-rsh-1.rs b/tests/run-fail/panic/overflowing-rsh-1.rs similarity index 100% rename from tests/run-pass/panic/overflowing-rsh-1.rs rename to tests/run-fail/panic/overflowing-rsh-1.rs diff --git a/tests/run-pass/panic/overflowing-rsh-1.stderr b/tests/run-fail/panic/overflowing-rsh-1.stderr similarity index 80% rename from tests/run-pass/panic/overflowing-rsh-1.stderr rename to tests/run-fail/panic/overflowing-rsh-1.stderr index bd8843f8d6039..fd04bf1bd4ec3 100644 --- a/tests/run-pass/panic/overflowing-rsh-1.stderr +++ b/tests/run-fail/panic/overflowing-rsh-1.stderr @@ -1,2 +1,2 @@ -thread 'main' panicked at 'attempt to shift right with overflow', $DIR/overflowing-rsh-1.rs:4:14 +thread 'main' panicked at 'attempt to shift right with overflow', $DIR/overflowing-rsh-1.rs:LL:CC note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace diff --git a/tests/run-pass/panic/overflowing-rsh-2.rs b/tests/run-fail/panic/overflowing-rsh-2.rs similarity index 100% rename from tests/run-pass/panic/overflowing-rsh-2.rs rename to tests/run-fail/panic/overflowing-rsh-2.rs diff --git a/tests/run-pass/panic/overflowing-rsh-2.stderr b/tests/run-fail/panic/overflowing-rsh-2.stderr similarity index 80% rename from tests/run-pass/panic/overflowing-rsh-2.stderr rename to tests/run-fail/panic/overflowing-rsh-2.stderr index c43090ea70371..eb568e4d742bc 100644 --- a/tests/run-pass/panic/overflowing-rsh-2.stderr +++ b/tests/run-fail/panic/overflowing-rsh-2.stderr @@ -1,2 +1,2 @@ -thread 'main' panicked at 'attempt to shift right with overflow', $DIR/overflowing-rsh-2.rs:5:14 +thread 'main' panicked at 'attempt to shift right with overflow', $DIR/overflowing-rsh-2.rs:LL:CC note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace diff --git a/tests/run-fail/panic/panic1.rs b/tests/run-fail/panic/panic1.rs new file mode 100644 index 0000000000000..cfaa642beb8e2 --- /dev/null +++ b/tests/run-fail/panic/panic1.rs @@ -0,0 +1,7 @@ +// rustc-env: RUST_BACKTRACE=1 +// compile-flags: -Zmiri-disable-isolation + + +fn main() { + std::panic!("panicking from libstd"); +} diff --git a/tests/run-pass/panic/panic1.stderr b/tests/run-fail/panic/panic1.stderr similarity index 55% rename from tests/run-pass/panic/panic1.stderr rename to tests/run-fail/panic/panic1.stderr index 0b59b2a523b34..d4dcfc47a8392 100644 --- a/tests/run-pass/panic/panic1.stderr +++ b/tests/run-fail/panic/panic1.stderr @@ -1,31 +1,31 @@ -thread 'main' panicked at 'panicking from libstd', $DIR/panic1.rs:8:5 +thread 'main' panicked at 'panicking from libstd', $DIR/panic1.rs:LL:CC stack backtrace: 0: std::rt::begin_panic - at RUSTLIB/$FILE:LL:COL + at rustc_src/src/panicking.rs:LL:CC 1: main - at $DIR/panic1.rs:8:5 + at $DIR/panic1.rs:LL:CC 2: >::call_once - shim(fn()) - at RUSTLIB/$FILE:LL:COL + at rustc_src/src/ops/function.rs:LL:CC 3: std::rt::lang_start::{closure#0} - at RUSTLIB/$FILE:LL:COL + at rustc_src/src/rt.rs:LL:CC 4: std::ops::function::impls::call_once - at RUSTLIB/$FILE:LL:COL + at rustc_src/src/ops/function.rs:LL:CC 5: std::panicking::r#try::do_call - at RUSTLIB/$FILE:LL:COL + at rustc_src/src/panicking.rs:LL:CC 6: std::panicking::r#try - at RUSTLIB/$FILE:LL:COL + at rustc_src/src/panicking.rs:LL:CC 7: std::panic::catch_unwind - at RUSTLIB/$FILE:LL:COL + at rustc_src/src/panic.rs:LL:CC 8: std::rt::lang_start_internal::{closure#2} - at RUSTLIB/$FILE:LL:COL + at rustc_src/src/rt.rs:LL:CC 9: std::panicking::r#try::do_call - at RUSTLIB/$FILE:LL:COL + at rustc_src/src/panicking.rs:LL:CC 10: std::panicking::r#try - at RUSTLIB/$FILE:LL:COL + at rustc_src/src/panicking.rs:LL:CC 11: std::panic::catch_unwind - at RUSTLIB/$FILE:LL:COL + at rustc_src/src/panic.rs:LL:CC 12: std::rt::lang_start_internal - at RUSTLIB/$FILE:LL:COL + at rustc_src/src/rt.rs:LL:CC 13: std::rt::lang_start - at RUSTLIB/$FILE:LL:COL + at rustc_src/src/rt.rs:LL:CC note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace. diff --git a/tests/run-pass/panic/panic2.rs b/tests/run-fail/panic/panic2.rs similarity index 100% rename from tests/run-pass/panic/panic2.rs rename to tests/run-fail/panic/panic2.rs diff --git a/tests/run-pass/panic/panic2.stderr b/tests/run-fail/panic/panic2.stderr similarity index 92% rename from tests/run-pass/panic/panic2.stderr rename to tests/run-fail/panic/panic2.stderr index c0415b4e70f07..c192ca3f64c36 100644 --- a/tests/run-pass/panic/panic2.stderr +++ b/tests/run-fail/panic/panic2.stderr @@ -1,2 +1,2 @@ -thread 'main' panicked at '42-panicking from libstd', $DIR/panic2.rs:2:5 +thread 'main' panicked at '42-panicking from libstd', $DIR/panic2.rs:LL:CC note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace diff --git a/tests/run-pass/panic/panic3.rs b/tests/run-fail/panic/panic3.rs similarity index 100% rename from tests/run-pass/panic/panic3.rs rename to tests/run-fail/panic/panic3.rs diff --git a/tests/run-pass/panic/panic3.stderr b/tests/run-fail/panic/panic3.stderr similarity index 94% rename from tests/run-pass/panic/panic3.stderr rename to tests/run-fail/panic/panic3.stderr index 8aa8761aebf77..0ce4a37fd5197 100644 --- a/tests/run-pass/panic/panic3.stderr +++ b/tests/run-fail/panic/panic3.stderr @@ -1,2 +1,2 @@ -thread 'main' panicked at 'panicking from libcore', $DIR/panic3.rs:2:5 +thread 'main' panicked at 'panicking from libcore', $DIR/panic3.rs:LL:CC note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace diff --git a/tests/run-pass/panic/panic4.rs b/tests/run-fail/panic/panic4.rs similarity index 100% rename from tests/run-pass/panic/panic4.rs rename to tests/run-fail/panic/panic4.rs diff --git a/tests/run-pass/panic/panic4.stderr b/tests/run-fail/panic/panic4.stderr similarity index 92% rename from tests/run-pass/panic/panic4.stderr rename to tests/run-fail/panic/panic4.stderr index a71d25b74c435..82df953b61c03 100644 --- a/tests/run-pass/panic/panic4.stderr +++ b/tests/run-fail/panic/panic4.stderr @@ -1,2 +1,2 @@ -thread 'main' panicked at '42-panicking from libcore', $DIR/panic4.rs:2:5 +thread 'main' panicked at '42-panicking from libcore', $DIR/panic4.rs:LL:CC note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace diff --git a/tests/run-pass/panic/unsupported_foreign_function.rs b/tests/run-fail/panic/unsupported_foreign_function.rs similarity index 100% rename from tests/run-pass/panic/unsupported_foreign_function.rs rename to tests/run-fail/panic/unsupported_foreign_function.rs diff --git a/tests/run-pass/panic/unsupported_foreign_function.stderr b/tests/run-fail/panic/unsupported_foreign_function.stderr similarity index 95% rename from tests/run-pass/panic/unsupported_foreign_function.stderr rename to tests/run-fail/panic/unsupported_foreign_function.stderr index bd7f3490d809d..9af3e48655f38 100644 --- a/tests/run-pass/panic/unsupported_foreign_function.stderr +++ b/tests/run-fail/panic/unsupported_foreign_function.stderr @@ -1,2 +1,2 @@ -thread 'main' panicked at 'unsupported Miri functionality: can't call foreign function: foo', $DIR/unsupported_foreign_function.rs:9:9 +thread 'main' panicked at 'unsupported Miri functionality: can't call foreign function: foo', $DIR/unsupported_foreign_function.rs:LL:CC note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace diff --git a/tests/run-pass/panic/unsupported_syscall.rs b/tests/run-fail/panic/unsupported_syscall.rs similarity index 78% rename from tests/run-pass/panic/unsupported_syscall.rs rename to tests/run-fail/panic/unsupported_syscall.rs index 854f179392c41..2e62a5d8ae8d2 100644 --- a/tests/run-pass/panic/unsupported_syscall.rs +++ b/tests/run-fail/panic/unsupported_syscall.rs @@ -1,5 +1,5 @@ // ignore-windows: No libc on Windows -// ignore-macos: `syscall` is not supported on macOS +// ignore-apple: `syscall` is not supported on macOS // compile-flags: -Zmiri-panic-on-unsupported #![feature(rustc_private)] diff --git a/tests/run-pass/panic/unsupported_syscall.stderr b/tests/run-fail/panic/unsupported_syscall.stderr similarity index 69% rename from tests/run-pass/panic/unsupported_syscall.stderr rename to tests/run-fail/panic/unsupported_syscall.stderr index 49796ee2021fe..90aa5a9073638 100644 --- a/tests/run-pass/panic/unsupported_syscall.stderr +++ b/tests/run-fail/panic/unsupported_syscall.stderr @@ -1,2 +1,2 @@ -thread 'main' panicked at 'unsupported Miri functionality: can't execute syscall with ID 0', $DIR/unsupported_syscall.rs:10:9 +thread 'main' panicked at 'unsupported Miri functionality: can't execute syscall with ID 0', $DIR/unsupported_syscall.rs:LL:CC note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace diff --git a/tests/run-pass/transmute_fat2.rs b/tests/run-fail/transmute_fat2.rs similarity index 100% rename from tests/run-pass/transmute_fat2.rs rename to tests/run-fail/transmute_fat2.rs diff --git a/tests/run-pass/transmute_fat2.stderr b/tests/run-fail/transmute_fat2.stderr similarity index 75% rename from tests/run-pass/transmute_fat2.stderr rename to tests/run-fail/transmute_fat2.stderr index 54ccdfb5e4656..f497ab672550f 100644 --- a/tests/run-pass/transmute_fat2.stderr +++ b/tests/run-fail/transmute_fat2.stderr @@ -1,2 +1,2 @@ -thread 'main' panicked at 'index out of bounds: the len is 0 but the index is 0', $DIR/transmute_fat2.rs:15:5 +thread 'main' panicked at 'index out of bounds: the len is 0 but the index is 0', $DIR/transmute_fat2.rs:LL:CC note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace diff --git a/tests/run-pass/backtrace-api-v0.rs b/tests/run-pass/backtrace-api-v0.rs index cb3706e9f5132..62702c088dd67 100644 --- a/tests/run-pass/backtrace-api-v0.rs +++ b/tests/run-pass/backtrace-api-v0.rs @@ -1,6 +1,4 @@ -// normalize-stderr-test ".*/(rust[^/]*|checkout)/library/" -> "RUSTLIB/" -// normalize-stderr-test "RUSTLIB/(.*):\d+:\d+ "-> "RUSTLIB/$1:LL:COL " -// normalize-stderr-test "::<.*>" -> "" +// normalize-stderr-test: "::<.*>" -> "" #[inline(never)] fn func_a() -> Box<[*mut ()]> { func_b::() } #[inline(never)] fn func_b() -> Box<[*mut ()]> { func_c() } diff --git a/tests/run-pass/backtrace-api-v0.stderr b/tests/run-pass/backtrace-api-v0.stderr index 8a697a44ea9dc..d81f5ad1d6266 100644 --- a/tests/run-pass/backtrace-api-v0.stderr +++ b/tests/run-pass/backtrace-api-v0.stderr @@ -1,18 +1,18 @@ -$DIR/backtrace-api-v0.rs:13:59 (func_d) -$DIR/backtrace-api-v0.rs:12:50 (func_c) -$DIR/backtrace-api-v0.rs:6:53 (func_b) -$DIR/backtrace-api-v0.rs:5:50 (func_a) -$DIR/backtrace-api-v0.rs:17:18 (main) -RUSTLIB/core/src/ops/function.rs:LL:COL (>::call_once - shim(fn())) -RUSTLIB/std/src/sys_common/backtrace.rs:LL:COL (std::sys_common::backtrace::__rust_begin_short_backtrace) -RUSTLIB/std/src/rt.rs:LL:COL (std::rt::lang_start::{closure#0}) -RUSTLIB/core/src/ops/function.rs:LL:COL (std::ops::function::impls::call_once) -RUSTLIB/std/src/panicking.rs:LL:COL (std::panicking::r#try::do_call) -RUSTLIB/std/src/panicking.rs:LL:COL (std::panicking::r#try) -RUSTLIB/std/src/panic.rs:LL:COL (std::panic::catch_unwind) -RUSTLIB/std/src/rt.rs:LL:COL (std::rt::lang_start_internal::{closure#2}) -RUSTLIB/std/src/panicking.rs:LL:COL (std::panicking::r#try::do_call) -RUSTLIB/std/src/panicking.rs:LL:COL (std::panicking::r#try) -RUSTLIB/std/src/panic.rs:LL:COL (std::panic::catch_unwind) -RUSTLIB/std/src/rt.rs:LL:COL (std::rt::lang_start_internal) -RUSTLIB/std/src/rt.rs:LL:COL (std::rt::lang_start) +$DIR/backtrace-api-v0.rs:LL:CC (func_d) +$DIR/backtrace-api-v0.rs:LL:CC (func_c) +$DIR/backtrace-api-v0.rs:LL:CC (func_b) +$DIR/backtrace-api-v0.rs:LL:CC (func_a) +$DIR/backtrace-api-v0.rs:LL:CC (main) +rustc_src/src/ops/function.rs:LL:CC (>::call_once - shim(fn())) +rustc_src/src/sys_common/backtrace.rs:LL:CC (std::sys_common::backtrace::__rust_begin_short_backtrace) +rustc_src/src/rt.rs:LL:CC (std::rt::lang_start::{closure#0}) +rustc_src/src/ops/function.rs:LL:CC (std::ops::function::impls::call_once) +rustc_src/src/panicking.rs:LL:CC (std::panicking::r#try::do_call) +rustc_src/src/panicking.rs:LL:CC (std::panicking::r#try) +rustc_src/src/panic.rs:LL:CC (std::panic::catch_unwind) +rustc_src/src/rt.rs:LL:CC (std::rt::lang_start_internal::{closure#2}) +rustc_src/src/panicking.rs:LL:CC (std::panicking::r#try::do_call) +rustc_src/src/panicking.rs:LL:CC (std::panicking::r#try) +rustc_src/src/panic.rs:LL:CC (std::panic::catch_unwind) +rustc_src/src/rt.rs:LL:CC (std::rt::lang_start_internal) +rustc_src/src/rt.rs:LL:CC (std::rt::lang_start) diff --git a/tests/run-pass/backtrace-api-v0.stdout b/tests/run-pass/backtrace-api-v0.stdout index c80a3f3bbcab6..9de1d034bb73b 100644 --- a/tests/run-pass/backtrace-api-v0.stdout +++ b/tests/run-pass/backtrace-api-v0.stdout @@ -1,5 +1,5 @@ -$DIR/backtrace-api-v0.rs:13:59 (func_d) -$DIR/backtrace-api-v0.rs:12:50 (func_c) -$DIR/backtrace-api-v0.rs:6:53 (func_b::) -$DIR/backtrace-api-v0.rs:5:50 (func_a) -$DIR/backtrace-api-v0.rs:17:18 (main) +$DIR/backtrace-api-v0.rs:11:59 (func_d) +$DIR/backtrace-api-v0.rs:10:50 (func_c) +$DIR/backtrace-api-v0.rs:4:53 (func_b) +$DIR/backtrace-api-v0.rs:3:50 (func_a) +$DIR/backtrace-api-v0.rs:15:18 (main) diff --git a/tests/run-pass/backtrace-api-v1.rs b/tests/run-pass/backtrace-api-v1.rs index 58ed63eaf395c..6d4a29c954e9e 100644 --- a/tests/run-pass/backtrace-api-v1.rs +++ b/tests/run-pass/backtrace-api-v1.rs @@ -1,6 +1,4 @@ -// normalize-stderr-test ".*/(rust[^/]*|checkout)/library/" -> "RUSTLIB/" -// normalize-stderr-test "RUSTLIB/(.*):\d+:\d+ "-> "RUSTLIB/$1:LL:COL " -// normalize-stderr-test "::<.*>" -> "" +// normalize-stderr-test: "::<.*>" -> "" #[inline(never)] fn func_a() -> Box<[*mut ()]> { func_b::() } #[inline(never)] fn func_b() -> Box<[*mut ()]> { func_c() } diff --git a/tests/run-pass/backtrace-api-v1.stderr b/tests/run-pass/backtrace-api-v1.stderr index 806a1c60f5a04..87c59f4269685 100644 --- a/tests/run-pass/backtrace-api-v1.stderr +++ b/tests/run-pass/backtrace-api-v1.stderr @@ -1,18 +1,18 @@ -$DIR/backtrace-api-v1.rs:13:144 (func_d) -$DIR/backtrace-api-v1.rs:12:50 (func_c) -$DIR/backtrace-api-v1.rs:6:53 (func_b) -$DIR/backtrace-api-v1.rs:5:50 (func_a) -$DIR/backtrace-api-v1.rs:17:18 (main) -RUSTLIB/core/src/ops/function.rs:LL:COL (>::call_once - shim(fn())) -RUSTLIB/std/src/sys_common/backtrace.rs:LL:COL (std::sys_common::backtrace::__rust_begin_short_backtrace) -RUSTLIB/std/src/rt.rs:LL:COL (std::rt::lang_start::{closure#0}) -RUSTLIB/core/src/ops/function.rs:LL:COL (std::ops::function::impls::call_once) -RUSTLIB/std/src/panicking.rs:LL:COL (std::panicking::r#try::do_call) -RUSTLIB/std/src/panicking.rs:LL:COL (std::panicking::r#try) -RUSTLIB/std/src/panic.rs:LL:COL (std::panic::catch_unwind) -RUSTLIB/std/src/rt.rs:LL:COL (std::rt::lang_start_internal::{closure#2}) -RUSTLIB/std/src/panicking.rs:LL:COL (std::panicking::r#try::do_call) -RUSTLIB/std/src/panicking.rs:LL:COL (std::panicking::r#try) -RUSTLIB/std/src/panic.rs:LL:COL (std::panic::catch_unwind) -RUSTLIB/std/src/rt.rs:LL:COL (std::rt::lang_start_internal) -RUSTLIB/std/src/rt.rs:LL:COL (std::rt::lang_start) +$DIR/backtrace-api-v1.rs:LL:CC (func_d) +$DIR/backtrace-api-v1.rs:LL:CC (func_c) +$DIR/backtrace-api-v1.rs:LL:CC (func_b) +$DIR/backtrace-api-v1.rs:LL:CC (func_a) +$DIR/backtrace-api-v1.rs:LL:CC (main) +rustc_src/src/ops/function.rs:LL:CC (>::call_once - shim(fn())) +rustc_src/src/sys_common/backtrace.rs:LL:CC (std::sys_common::backtrace::__rust_begin_short_backtrace) +rustc_src/src/rt.rs:LL:CC (std::rt::lang_start::{closure#0}) +rustc_src/src/ops/function.rs:LL:CC (std::ops::function::impls::call_once) +rustc_src/src/panicking.rs:LL:CC (std::panicking::r#try::do_call) +rustc_src/src/panicking.rs:LL:CC (std::panicking::r#try) +rustc_src/src/panic.rs:LL:CC (std::panic::catch_unwind) +rustc_src/src/rt.rs:LL:CC (std::rt::lang_start_internal::{closure#2}) +rustc_src/src/panicking.rs:LL:CC (std::panicking::r#try::do_call) +rustc_src/src/panicking.rs:LL:CC (std::panicking::r#try) +rustc_src/src/panic.rs:LL:CC (std::panic::catch_unwind) +rustc_src/src/rt.rs:LL:CC (std::rt::lang_start_internal) +rustc_src/src/rt.rs:LL:CC (std::rt::lang_start) diff --git a/tests/run-pass/backtrace-api-v1.stdout b/tests/run-pass/backtrace-api-v1.stdout index 2670d560eb193..b820a1be0a199 100644 --- a/tests/run-pass/backtrace-api-v1.stdout +++ b/tests/run-pass/backtrace-api-v1.stdout @@ -1,5 +1,5 @@ -$DIR/backtrace-api-v1.rs:13:144 (func_d) -$DIR/backtrace-api-v1.rs:12:50 (func_c) -$DIR/backtrace-api-v1.rs:6:53 (func_b::) -$DIR/backtrace-api-v1.rs:5:50 (func_a) -$DIR/backtrace-api-v1.rs:17:18 (main) +$DIR/backtrace-api-v1.rs:11:144 (func_d) +$DIR/backtrace-api-v1.rs:10:50 (func_c) +$DIR/backtrace-api-v1.rs:4:53 (func_b) +$DIR/backtrace-api-v1.rs:3:50 (func_a) +$DIR/backtrace-api-v1.rs:15:18 (main) diff --git a/tests/run-pass/backtrace-std.rs b/tests/run-pass/backtrace-std.rs index 9b61aabab3b23..64b7e7293b194 100644 --- a/tests/run-pass/backtrace-std.rs +++ b/tests/run-pass/backtrace-std.rs @@ -1,6 +1,3 @@ -// normalize-stderr-test "at .*/(rust[^/]*|checkout)/library/" -> "at RUSTLIB/" -// normalize-stderr-test "RUSTLIB/([^:]*):\d+:\d+"-> "RUSTLIB/$1:LL:CC" -// normalize-stderr-test "::<.*>" -> "" // compile-flags: -Zmiri-disable-isolation #![feature(backtrace)] diff --git a/tests/run-pass/backtrace-std.stderr b/tests/run-pass/backtrace-std.stderr index 64386085c7756..848ccaea1b622 100644 --- a/tests/run-pass/backtrace-std.stderr +++ b/tests/run-pass/backtrace-std.stderr @@ -1,36 +1,36 @@ 0: func_d - at $DIR/backtrace-std.rs:18:45 + at $DIR/backtrace-std.rs:LL:CC 1: func_c - at $DIR/backtrace-std.rs:17:45 + at $DIR/backtrace-std.rs:LL:CC 2: func_b - at $DIR/backtrace-std.rs:11:48 + at $DIR/backtrace-std.rs:LL:CC 3: func_a - at $DIR/backtrace-std.rs:10:45 + at $DIR/backtrace-std.rs:LL:CC 4: main - at $DIR/backtrace-std.rs:21:19 + at $DIR/backtrace-std.rs:LL:CC 5: >::call_once - shim(fn()) - at RUSTLIB/core/src/ops/function.rs:LL:CC + at rustc_src/src/ops/function.rs:LL:CC 6: std::sys_common::backtrace::__rust_begin_short_backtrace - at RUSTLIB/std/src/sys_common/backtrace.rs:LL:CC + at rustc_src/src/sys_common/backtrace.rs:LL:CC 7: std::rt::lang_start::{closure#0} - at RUSTLIB/std/src/rt.rs:LL:CC + at rustc_src/src/rt.rs:LL:CC 8: std::ops::function::impls::call_once - at RUSTLIB/core/src/ops/function.rs:LL:CC + at rustc_src/src/ops/function.rs:LL:CC 9: std::panicking::r#try::do_call - at RUSTLIB/std/src/panicking.rs:LL:CC + at rustc_src/src/panicking.rs:LL:CC 10: std::panicking::r#try - at RUSTLIB/std/src/panicking.rs:LL:CC + at rustc_src/src/panicking.rs:LL:CC 11: std::panic::catch_unwind - at RUSTLIB/std/src/panic.rs:LL:CC + at rustc_src/src/panic.rs:LL:CC 12: std::rt::lang_start_internal::{closure#2} - at RUSTLIB/std/src/rt.rs:LL:CC + at rustc_src/src/rt.rs:LL:CC 13: std::panicking::r#try::do_call - at RUSTLIB/std/src/panicking.rs:LL:CC + at rustc_src/src/panicking.rs:LL:CC 14: std::panicking::r#try - at RUSTLIB/std/src/panicking.rs:LL:CC + at rustc_src/src/panicking.rs:LL:CC 15: std::panic::catch_unwind - at RUSTLIB/std/src/panic.rs:LL:CC + at rustc_src/src/panic.rs:LL:CC 16: std::rt::lang_start_internal - at RUSTLIB/std/src/rt.rs:LL:CC + at rustc_src/src/rt.rs:LL:CC 17: std::rt::lang_start - at RUSTLIB/std/src/rt.rs:LL:CC + at rustc_src/src/rt.rs:LL:CC diff --git a/tests/run-pass/concurrency/disable_data_race_detector.rs b/tests/run-pass/concurrency/disable_data_race_detector.rs index 8b2d180f11d4a..14e2d5651de0e 100644 --- a/tests/run-pass/concurrency/disable_data_race_detector.rs +++ b/tests/run-pass/concurrency/disable_data_race_detector.rs @@ -19,7 +19,7 @@ pub fn main() { }); let j2 = spawn(move || { - *c.0 = 64; //~ ERROR Data race (but not detected as the detector is disabled) + *c.0 = 64; // Data race (but not detected as the detector is disabled) }); j1.join().unwrap(); diff --git a/tests/run-pass/concurrency/libc_pthread_cond.rs b/tests/run-pass/concurrency/libc_pthread_cond.rs index 0e09ec9126a54..631675aaaf54b 100644 --- a/tests/run-pass/concurrency/libc_pthread_cond.rs +++ b/tests/run-pass/concurrency/libc_pthread_cond.rs @@ -1,5 +1,5 @@ // ignore-windows: No libc on Windows -// ignore-macos: pthread_condattr_setclock is not supported on MacOS. +// ignore-apple: pthread_condattr_setclock is not supported on MacOS. // compile-flags: -Zmiri-disable-isolation -Zmiri-check-number-validity #![feature(rustc_private)] diff --git a/tests/run-pass/concurrency/linux-futex.rs b/tests/run-pass/concurrency/linux-futex.rs index 4ac928398e238..8a67e0b525a98 100644 --- a/tests/run-pass/concurrency/linux-futex.rs +++ b/tests/run-pass/concurrency/linux-futex.rs @@ -1,7 +1,4 @@ -// Unfortunately, the test framework does not support 'only-linux', -// so we need to ignore Windows and macOS instead. -// ignore-macos: Uses Linux-only APIs -// ignore-windows: Uses Linux-only APIs +// only-linux // compile-flags: -Zmiri-disable-isolation #![feature(rustc_private)] diff --git a/tests/run-pass/concurrency/simple.stderr b/tests/run-pass/concurrency/simple.stderr index 35f5f10274c95..bb60638bd6834 100644 --- a/tests/run-pass/concurrency/simple.stderr +++ b/tests/run-pass/concurrency/simple.stderr @@ -1,5 +1,5 @@ warning: thread support is experimental and incomplete: weak memory effects are not emulated. -thread '' panicked at 'Hello!', $DIR/simple.rs:55:9 +thread '' panicked at 'Hello!', $DIR/simple.rs:LL:CC note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace -thread 'childthread' panicked at 'Hello, world!', $DIR/simple.rs:65:9 +thread 'childthread' panicked at 'Hello, world!', $DIR/simple.rs:LL:CC diff --git a/tests/run-pass/current_dir_with_isolation.rs b/tests/run-pass/current_dir_with_isolation.rs index b5fe6114b2f3f..98c44d57b65ad 100644 --- a/tests/run-pass/current_dir_with_isolation.rs +++ b/tests/run-pass/current_dir_with_isolation.rs @@ -1,6 +1,6 @@ // compile-flags: -Zmiri-isolation-error=warn-nobacktrace -// normalize-stderr-test "(getcwd|GetCurrentDirectoryW)" -> "$$GETCWD" -// normalize-stderr-test "(chdir|SetCurrentDirectoryW)" -> "$$SETCWD" +// normalize-stderr-test: "(getcwd|GetCurrentDirectoryW)" -> "$$GETCWD" +// normalize-stderr-test: "(chdir|SetCurrentDirectoryW)" -> "$$SETCWD" use std::env; use std::io::ErrorKind; diff --git a/tests/run-pass/fs_with_isolation.rs b/tests/run-pass/fs_with_isolation.rs index a9e1e5094fa52..cd91cd9be30e7 100644 --- a/tests/run-pass/fs_with_isolation.rs +++ b/tests/run-pass/fs_with_isolation.rs @@ -1,6 +1,6 @@ // ignore-windows: File handling is not implemented yet // compile-flags: -Zmiri-isolation-error=warn-nobacktrace -// normalize-stderr-test "(stat(x)?)" -> "$$STAT" +// normalize-stderr-test: "(stat(x)?)" -> "$$STAT" #![feature(rustc_private)] diff --git a/tests/run-pass/linux-getrandom-without-isolation.rs b/tests/run-pass/linux-getrandom-without-isolation.rs index ce9ff8b6c3f95..e08d4466a7bf7 100644 --- a/tests/run-pass/linux-getrandom-without-isolation.rs +++ b/tests/run-pass/linux-getrandom-without-isolation.rs @@ -1,7 +1,4 @@ -// Unfortunately, compiletest_rs does not support 'only-linux', -// so we need to ignore Windows and macOS instead. -// ignore-macos: Uses Linux-only APIs -// ignore-windows: Uses Linux-only APIs +// only-linux // compile-flags: -Zmiri-disable-isolation #![feature(rustc_private)] extern crate libc; diff --git a/tests/run-pass/linux-getrandom.rs b/tests/run-pass/linux-getrandom.rs index f582a282c59b4..762e754f8127d 100644 --- a/tests/run-pass/linux-getrandom.rs +++ b/tests/run-pass/linux-getrandom.rs @@ -1,7 +1,4 @@ -// Unfortunately, compiletest_rs does not support 'only-linux', -// so we need to ignore Windows and macOS instead. -// ignore-macos: Uses Linux-only APIs -// ignore-windows: Uses Linux-only APIs +// only-linux #![feature(rustc_private)] extern crate libc; diff --git a/tests/run-pass/panic/catch_panic.rs b/tests/run-pass/panic/catch_panic.rs index 63a3c9a47648c..80881948c03c8 100644 --- a/tests/run-pass/panic/catch_panic.rs +++ b/tests/run-pass/panic/catch_panic.rs @@ -1,5 +1,3 @@ -// normalize-stderr-test "[^ ]*core/[a-z_/]+.rs[0-9:]*" -> "$$LOC" -// normalize-stderr-test "catch_panic\.rs:[0-9]{2}" -> "catch_panic.rs:LL" // We test the `align_offset` panic below, make sure we test the interpreter impl and not the "real" one. // compile-flags: -Zmiri-symbolic-alignment-check #![feature(never_type)] diff --git a/tests/run-pass/panic/catch_panic.stderr b/tests/run-pass/panic/catch_panic.stderr index 0f43ab2520a57..36a7818d27661 100644 --- a/tests/run-pass/panic/catch_panic.stderr +++ b/tests/run-pass/panic/catch_panic.stderr @@ -1,26 +1,26 @@ -thread 'main' panicked at 'Hello from panic: std', $DIR/catch_panic.rs:LL:27 +thread 'main' panicked at 'Hello from panic: std', $DIR/catch_panic.rs:LL:CC note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace Caught panic message (&str): Hello from panic: std -thread 'main' panicked at 'Hello from panic: 1', $DIR/catch_panic.rs:LL:26 +thread 'main' panicked at 'Hello from panic: 1', $DIR/catch_panic.rs:LL:CC Caught panic message (String): Hello from panic: 1 -thread 'main' panicked at 'Hello from panic: 2', $DIR/catch_panic.rs:LL:26 +thread 'main' panicked at 'Hello from panic: 2', $DIR/catch_panic.rs:LL:CC Caught panic message (String): Hello from panic: 2 -thread 'main' panicked at 'Box', $DIR/catch_panic.rs:LL:27 +thread 'main' panicked at 'Box', $DIR/catch_panic.rs:LL:CC Failed to get caught panic message. -thread 'main' panicked at 'Hello from panic: core', $DIR/catch_panic.rs:LL:27 +thread 'main' panicked at 'Hello from panic: core', $DIR/catch_panic.rs:LL:CC Caught panic message (&str): Hello from panic: core -thread 'main' panicked at 'Hello from panic: 5', $DIR/catch_panic.rs:LL:26 +thread 'main' panicked at 'Hello from panic: 5', $DIR/catch_panic.rs:LL:CC Caught panic message (String): Hello from panic: 5 -thread 'main' panicked at 'Hello from panic: 6', $DIR/catch_panic.rs:LL:26 +thread 'main' panicked at 'Hello from panic: 6', $DIR/catch_panic.rs:LL:CC Caught panic message (String): Hello from panic: 6 -thread 'main' panicked at 'index out of bounds: the len is 3 but the index is 4', $DIR/catch_panic.rs:LL:33 +thread 'main' panicked at 'index out of bounds: the len is 3 but the index is 4', $DIR/catch_panic.rs:LL:CC Caught panic message (String): index out of bounds: the len is 3 but the index is 4 -thread 'main' panicked at 'attempt to divide by zero', $DIR/catch_panic.rs:LL:33 +thread 'main' panicked at 'attempt to divide by zero', $DIR/catch_panic.rs:LL:CC Caught panic message (&str): attempt to divide by zero -thread 'main' panicked at 'align_offset: align is not a power-of-two', $LOC +thread 'main' panicked at 'align_offset: align is not a power-of-two', rustc_src/src/ptr/const_ptr.rs:LL:CC Caught panic message (&str): align_offset: align is not a power-of-two -thread 'main' panicked at 'assertion failed: false', $DIR/catch_panic.rs:LL:29 +thread 'main' panicked at 'assertion failed: false', $DIR/catch_panic.rs:LL:CC Caught panic message (&str): assertion failed: false -thread 'main' panicked at 'assertion failed: false', $DIR/catch_panic.rs:LL:29 +thread 'main' panicked at 'assertion failed: false', $DIR/catch_panic.rs:LL:CC Caught panic message (&str): assertion failed: false Success! diff --git a/tests/run-pass/panic/concurrent-panic.stderr b/tests/run-pass/panic/concurrent-panic.stderr index 1ee688c1d32cc..ae132c9ee3483 100644 --- a/tests/run-pass/panic/concurrent-panic.stderr +++ b/tests/run-pass/panic/concurrent-panic.stderr @@ -2,11 +2,11 @@ warning: thread support is experimental and incomplete: weak memory effects are Thread 1 starting, will block on mutex Thread 1 reported it has started -thread '' panicked at 'panic in thread 2', $DIR/concurrent-panic.rs:65:13 +thread '' panicked at 'panic in thread 2', $DIR/concurrent-panic.rs:LL:CC note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace Thread 2 blocking on thread 1 Thread 2 reported it has started Unlocking mutex -thread '' panicked at 'panic in thread 1', $DIR/concurrent-panic.rs:42:13 +thread '' panicked at 'panic in thread 1', $DIR/concurrent-panic.rs:LL:CC Thread 1 has exited Thread 2 has exited diff --git a/tests/run-pass/panic/panic1.rs b/tests/run-pass/panic/panic1.rs deleted file mode 100644 index da300ecb59f60..0000000000000 --- a/tests/run-pass/panic/panic1.rs +++ /dev/null @@ -1,9 +0,0 @@ -// rustc-env: RUST_BACKTRACE=1 -// compile-flags: -Zmiri-disable-isolation -// normalize-stderr-test "at .*/(rust[^/]*|checkout)/library/.*" -> "at RUSTLIB/$$FILE:LL:COL" -// normalize-stderr-test "::<.*>" -> "" - - -fn main() { - std::panic!("panicking from libstd"); -} diff --git a/tests/run-pass/stacked-borrows/generators-self-referential.rs b/tests/run-pass/stacked-borrows/generators-self-referential.rs index 01ce8a61418cf..b71912882dd2a 100644 --- a/tests/run-pass/stacked-borrows/generators-self-referential.rs +++ b/tests/run-pass/stacked-borrows/generators-self-referential.rs @@ -13,7 +13,7 @@ fn firstn() -> impl Generator { let num = &mut num; yield *num; - *num += 1; //~ ERROR: borrow stack + *num += 1; // would fail here yield *num; *num += 1; diff --git a/tests/run-pass/track-alloc-1.stderr b/tests/run-pass/track-alloc-1.stderr index 3c5a55d986e3e..be96b729838d6 100644 --- a/tests/run-pass/track-alloc-1.stderr +++ b/tests/run-pass/track-alloc-1.stderr @@ -1,5 +1,5 @@ note: tracking was triggered - | - = note: created allocation with id 1 - = note: (no span available) + | + = note: created allocation with id 1 + = note: (no span available) diff --git a/tests/run-pass/wtf8.rs b/tests/run-pass/wtf8.rs index 2b4da785f2ee3..5a58150680817 100644 --- a/tests/run-pass/wtf8.rs +++ b/tests/run-pass/wtf8.rs @@ -1,5 +1,4 @@ -// ignore-linux: tests Windows-only APIs -// ignore-macos: tests Windows-only APIs +// only-windows use std::os::windows::ffi::{OsStrExt, OsStringExt}; use std::ffi::{OsStr, OsString}; diff --git a/ui_test/Cargo.toml b/ui_test/Cargo.toml new file mode 100644 index 0000000000000..66d35fdd2228a --- /dev/null +++ b/ui_test/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "ui_test" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +rustc_version = "0.4" +colored = "2" +regex = "1.5.5" +pretty_assertions = "1.2.1" +crossbeam = "0.8.1" +lazy_static = "1.4.0" diff --git a/ui_test/README.md b/ui_test/README.md new file mode 100644 index 0000000000000..fdd94a74823e2 --- /dev/null +++ b/ui_test/README.md @@ -0,0 +1,30 @@ +A smaller version of compiletest-rs + +## Supported magic comment annotations + +Note that the space after `//`, when it is present, is *not* optional -- it must be exactly one. + +* `// ignore-XXX` avoids running the test on targets whose triple contains `XXX` + * `XXX` can also be one of `64bit`, `32bit` or `16bit` +* `// only-XXX` avoids running the test on targets whose triple **does not** contain `XXX` + * `XXX` can also be one of `64bit`, `32bit` or `16bit` +* `// stderr-per-bitwidth` produces one stderr file per bitwidth, as they may differ significantly sometimes +* `// error-pattern: XXX` make sure the stderr output contains `XXX` +* `//~ ERROR: XXX` make sure the stderr output contains `XXX` for an error in the line where this comment is written + * NOTE: it is not checked at present that it is actually in the line where the error occurred, or that it is truly an ERROR/WARNING/HELP/NOTE, but you should treat it as such until that becomes true. + * Also supports `HELP` or `WARN` for different kind of message + * if the all caps note is left out, any message is matched + * This checks the output *before* normalization, so you can check things that get normalized away, but need to + be careful not to accidentally have a pattern that differs between platforms. +* `// revisions: XXX YYY` runs the test once for each space separated name in the list + * emits one stderr file per revision + * `//~` comments can be restricted to specific revisions by adding the revision name before the `~` in square brackets: `//[XXX]~` +* `// compile-flags: XXX` appends `XXX` to the command line arguments passed to the rustc driver +* `// rustc-env: XXX=YYY` sets the env var `XXX` to `YYY` for the rustc driver execution. + * for Miri these env vars are used during compilation via rustc and during the emulation of the program +* `// normalize-stderr-test: "REGEX" -> "REPLACEMENT"` replaces all matches of `REGEX` in the stderr with `REPLACEMENT`. The replacement may specify `$1` and similar backreferences to paste captures. + +## Significant differences to compiletest-rs + +* `ignore-*` and `only-*` opereate solely on the triple, instead of supporting things like `macos` +* only `//~` comments can be individualized per revision diff --git a/ui_test/src/comments.rs b/ui_test/src/comments.rs new file mode 100644 index 0000000000000..14566d2feccf5 --- /dev/null +++ b/ui_test/src/comments.rs @@ -0,0 +1,111 @@ +use std::path::Path; + +use regex::Regex; + +/// This crate supports various magic comments that get parsed as file-specific +/// configuration values. This struct parses them all in one go and then they +/// get processed by their respective use sites. +#[derive(Default)] +pub struct Comments { + /// List of revision names to execute. Can only be speicified once + pub revisions: Option>, + /// Don't run this test if any of these filters apply + pub ignore: Vec, + /// Only run this test if all of these filters apply + pub only: Vec, + /// Generate one .stderr file per bit width, by prepending with `.64bit` and similar + pub stderr_per_bitwidth: bool, + /// Additional flags to pass to the executable + pub compile_flags: Vec, + /// Additional env vars to set for the executable + pub env_vars: Vec<(String, String)>, + /// Normalizations to apply to the stderr output before emitting it to disk + pub normalize_stderr: Vec<(Regex, String)>, + /// An arbitrary pattern to look for in the stderr. + pub error_pattern: Option<(String, usize)>, + pub error_matches: Vec, +} + +pub struct ErrorMatch { + pub matched: String, + pub revision: Option, + pub definition_line: usize, +} + +impl Comments { + pub fn parse(path: &Path) -> Self { + let mut this = Self::default(); + let content = std::fs::read_to_string(path).unwrap(); + let error_pattern_regex = + Regex::new(r"//(\[(?P[^\]]+)\])?~[|^]*\s*(ERROR|HELP|WARN)?:?(?P.*)") + .unwrap(); + for (l, line) in content.lines().enumerate() { + if let Some(revisions) = line.strip_prefix("// revisions:") { + assert_eq!( + this.revisions, + None, + "{}:{l}, cannot specifiy revisions twice", + path.display() + ); + this.revisions = + Some(revisions.trim().split_whitespace().map(|s| s.to_string()).collect()); + } + if let Some(s) = line.strip_prefix("// ignore-") { + let s = s + .split_once(|c: char| c == ':' || c.is_whitespace()) + .map(|(s, _)| s) + .unwrap_or(s); + this.ignore.push(s.to_owned()); + } + if let Some(s) = line.strip_prefix("// only-") { + let s = s + .split_once(|c: char| c == ':' || c.is_whitespace()) + .map(|(s, _)| s) + .unwrap_or(s); + this.only.push(s.to_owned()); + } + if line.starts_with("// stderr-per-bitwidth") { + assert!( + !this.stderr_per_bitwidth, + "{}:{l}, cannot specifiy stderr-per-bitwidth twice", + path.display() + ); + this.stderr_per_bitwidth = true; + } + if let Some(s) = line.strip_prefix("// compile-flags:") { + this.compile_flags.extend(s.split_whitespace().map(|s| s.to_string())); + } + if let Some(s) = line.strip_prefix("// rustc-env:") { + for env in s.split_whitespace() { + if let Some((k, v)) = env.split_once('=') { + this.env_vars.push((k.to_string(), v.to_string())); + } + } + } + if let Some(s) = line.strip_prefix("// normalize-stderr-test:") { + let (from, to) = s.split_once("->").expect("normalize-stderr-test needs a `->`"); + let from = from.trim().trim_matches('"'); + let to = to.trim().trim_matches('"'); + let from = Regex::new(from).unwrap(); + this.normalize_stderr.push((from, to.to_string())); + } + if let Some(s) = line.strip_prefix("// error-pattern:") { + assert_eq!( + this.error_pattern, + None, + "{}:{l}, cannot specifiy error_pattern twice", + path.display() + ); + this.error_pattern = Some((s.trim().to_string(), l)); + } + if let Some(captures) = error_pattern_regex.captures(line) { + // FIXME: check that the error happens on the marked line + let matched = captures["text"].trim().to_string(); + + let revision = captures.name("revision").map(|rev| rev.as_str().to_string()); + this.error_matches.push(ErrorMatch { matched, revision, definition_line: l }); + } + } + this + } +} diff --git a/ui_test/src/lib.rs b/ui_test/src/lib.rs new file mode 100644 index 0000000000000..95ae3a51b235d --- /dev/null +++ b/ui_test/src/lib.rs @@ -0,0 +1,410 @@ +use std::fmt::Write; +use std::path::{Path, PathBuf}; +use std::process::{Command, ExitStatus}; +use std::sync::atomic::{AtomicUsize, Ordering}; +use std::sync::Mutex; + +use colored::*; +use comments::ErrorMatch; +use crossbeam::queue::SegQueue; +use regex::Regex; + +use crate::comments::Comments; + +mod comments; + +#[derive(Debug)] +pub struct Config { + /// Arguments passed to the binary that is executed. + pub args: Vec, + /// `None` to run on the host, otherwise a target triple + pub target: Option, + /// Filters applied to stderr output before processing it + pub stderr_filters: Filter, + /// Filters applied to stdout output before processing it + pub stdout_filters: Filter, + /// The folder in which to start searching for .rs files + pub root_dir: PathBuf, + pub mode: Mode, + pub program: PathBuf, + pub output_conflict_handling: OutputConflictHandling, +} + +#[derive(Debug)] +pub enum OutputConflictHandling { + /// The default: emit a diff of the expected/actual output. + Error, + /// Ignore mismatches in the stderr/stdout files. + Ignore, + /// Instead of erroring if the stderr/stdout differs from the expected + /// automatically replace it with the found output (after applying filters). + Bless, +} + +pub type Filter = Vec<(Regex, &'static str)>; + +pub fn run_tests(config: Config) { + eprintln!(" Compiler flags: {:?}", config.args); + + // Get the triple with which to run the tests + let target = config.target.clone().unwrap_or_else(|| config.get_host()); + + // A queue for files or folders to process + let todo = SegQueue::new(); + todo.push(config.root_dir.clone()); + + // Some statistics and failure reports. + let failures = Mutex::new(vec![]); + let succeeded = AtomicUsize::default(); + let skipped = AtomicUsize::default(); + + crossbeam::scope(|s| { + for _ in 0..std::thread::available_parallelism().unwrap().get() { + s.spawn(|_| { + while let Some(path) = todo.pop() { + // Collect everything inside directories + if path.is_dir() { + for entry in std::fs::read_dir(path).unwrap() { + todo.push(entry.unwrap().path()); + } + continue; + } + // Only look at .rs files + if !path.extension().map(|ext| ext == "rs").unwrap_or(false) { + continue; + } + let comments = Comments::parse(&path); + // Skip file if only/skip rules do (not) apply + if ignore_file(&comments, &target) { + skipped.fetch_add(1, Ordering::Relaxed); + eprintln!("{} .. {}", path.display(), "skipped".yellow()); + continue; + } + // Run the test for all revisions + for revision in + comments.revisions.clone().unwrap_or_else(|| vec![String::new()]) + { + let (m, errors) = run_test(&path, &config, &target, &revision, &comments); + + // Using `format` to prevent messages from threads from getting intermingled. + let mut msg = format!("{} ", path.display()); + if !revision.is_empty() { + write!(msg, "(revision `{revision}`) ").unwrap(); + } + write!(msg, " .. ").unwrap(); + if errors.is_empty() { + eprintln!("{msg}{}", "ok".green()); + succeeded.fetch_add(1, Ordering::Relaxed); + } else { + eprintln!("{msg}{}", "FAILED".red().bold()); + failures.lock().unwrap().push((path.clone(), m, revision, errors)); + } + } + } + }); + } + }) + .unwrap(); + + // Print all errors in a single thread to show reliable output + let failures = failures.into_inner().unwrap(); + let succeeded = succeeded.load(Ordering::Relaxed); + let skipped = skipped.load(Ordering::Relaxed); + if !failures.is_empty() { + for (path, miri, revision, errors) in &failures { + eprintln!(); + eprint!("{}", path.display().to_string().underline()); + if !revision.is_empty() { + eprint!(" (revision `{}`)", revision); + } + eprint!("{}", " FAILED".red()); + eprintln!(); + eprintln!("command: {:?}", miri); + eprintln!(); + let mut dump_stderr = None; + for error in errors { + match error { + Error::ExitStatus(mode, exit_status) => eprintln!("{mode:?} got {exit_status}"), + Error::PatternNotFound { stderr, pattern, definition_line } => { + eprintln!("`{pattern}` {} in stderr output", "not found".red()); + eprintln!( + "expected because of pattern here: {}:{definition_line}", + path.display() + ); + dump_stderr = Some(stderr.clone()) + } + Error::NoPatternsFound => + eprintln!("{}", "no error patterns found in failure test".red()), + Error::PatternFoundInPassTest => + eprintln!("{}", "error pattern found in success test".red()), + Error::OutputDiffers { path, actual, expected } => { + dump_stderr = None; + eprintln!("actual output differed from expected {}", path.display()); + eprintln!("{}", pretty_assertions::StrComparison::new(expected, actual)); + eprintln!() + } + } + eprintln!(); + } + if let Some(stderr) = dump_stderr { + eprintln!("actual stderr:"); + eprintln!("{}", stderr); + eprintln!(); + } + } + eprintln!( + "{} tests failed, {} tests passed, {} skipped", + failures.len().to_string().red().bold(), + succeeded.to_string().green(), + skipped.to_string().yellow() + ); + std::process::exit(1); + } + eprintln!(); + eprintln!( + "{} tests passed, {} skipped", + succeeded.to_string().green(), + skipped.to_string().yellow() + ); +} + +#[derive(Debug)] +enum Error { + /// Got an invalid exit status for the given mode. + ExitStatus(Mode, ExitStatus), + PatternNotFound { + stderr: String, + pattern: String, + definition_line: usize, + }, + /// A ui test checking for failure does not have any failure patterns + NoPatternsFound, + /// A ui test checking for success has failure patterns + PatternFoundInPassTest, + /// Stderr/Stdout differed from the `.stderr`/`.stdout` file present. + OutputDiffers { + path: PathBuf, + actual: String, + expected: String, + }, +} + +type Errors = Vec; + +fn run_test( + path: &Path, + config: &Config, + target: &str, + revision: &str, + comments: &Comments, +) -> (Command, Errors) { + // Run miri + let mut miri = Command::new(&config.program); + miri.args(config.args.iter()); + miri.arg(path); + if !revision.is_empty() { + miri.arg(format!("--cfg={revision}")); + } + for arg in &comments.compile_flags { + miri.arg(arg); + } + for (k, v) in &comments.env_vars { + miri.env(k, v); + } + let output = miri.output().expect("could not execute miri"); + let mut errors = config.mode.ok(output.status); + // Check output files (if any) + let revised = |extension: &str| { + if revision.is_empty() { + extension.to_string() + } else { + format!("{}.{}", revision, extension) + } + }; + // Check output files against actual output + check_output( + &output.stderr, + path, + &mut errors, + revised("stderr"), + target, + &config.stderr_filters, + &config, + comments, + ); + check_output( + &output.stdout, + path, + &mut errors, + revised("stdout"), + target, + &config.stdout_filters, + &config, + comments, + ); + // Check error annotations in the source against output + check_annotations(&output.stderr, &mut errors, config, revision, comments); + (miri, errors) +} + +fn check_annotations( + unnormalized_stderr: &[u8], + errors: &mut Errors, + config: &Config, + revision: &str, + comments: &Comments, +) { + let unnormalized_stderr = std::str::from_utf8(unnormalized_stderr).unwrap(); + let mut found_annotation = false; + if let Some((ref error_pattern, definition_line)) = comments.error_pattern { + if !unnormalized_stderr.contains(error_pattern) { + errors.push(Error::PatternNotFound { + stderr: unnormalized_stderr.to_string(), + pattern: error_pattern.to_string(), + definition_line, + }); + } + found_annotation = true; + } + for &ErrorMatch { ref matched, revision: ref rev, definition_line } in &comments.error_matches { + // FIXME: check that the error happens on the marked line + + if let Some(rev) = rev { + if rev != revision { + continue; + } + } + + if !unnormalized_stderr.contains(matched) { + errors.push(Error::PatternNotFound { + stderr: unnormalized_stderr.to_string(), + pattern: matched.to_string(), + definition_line, + }); + } + found_annotation = true; + } + match (config.mode, found_annotation) { + (Mode::Pass, true) | (Mode::Panic, true) => errors.push(Error::PatternFoundInPassTest), + (Mode::Fail, false) => errors.push(Error::NoPatternsFound), + _ => {} + }; +} + +fn check_output( + output: &[u8], + path: &Path, + errors: &mut Errors, + kind: String, + target: &str, + filters: &Filter, + config: &Config, + comments: &Comments, +) { + let output = std::str::from_utf8(&output).unwrap(); + let output = normalize(path, output, filters, comments); + let path = output_path(path, comments, kind, target); + match config.output_conflict_handling { + OutputConflictHandling::Bless => + if output.is_empty() { + let _ = std::fs::remove_file(path); + } else { + std::fs::write(path, &output).unwrap(); + }, + OutputConflictHandling::Error => { + let expected_output = std::fs::read_to_string(&path).unwrap_or_default(); + if output != expected_output { + errors.push(Error::OutputDiffers { + path, + actual: output, + expected: expected_output, + }); + } + } + OutputConflictHandling::Ignore => {} + } +} + +fn output_path(path: &Path, comments: &Comments, kind: String, target: &str) -> PathBuf { + if comments.stderr_per_bitwidth { + return path.with_extension(format!("{}.{kind}", get_pointer_width(target))); + } + path.with_extension(kind) +} + +fn ignore_file(comments: &Comments, target: &str) -> bool { + for s in &comments.ignore { + if target.contains(s) { + return true; + } + if get_pointer_width(target) == s { + return true; + } + } + for s in &comments.only { + if !target.contains(s) { + return true; + } + if get_pointer_width(target) != s { + return true; + } + } + false +} + +// Taken 1:1 from compiletest-rs +fn get_pointer_width(triple: &str) -> &'static str { + if (triple.contains("64") && !triple.ends_with("gnux32") && !triple.ends_with("gnu_ilp32")) + || triple.starts_with("s390x") + { + "64bit" + } else if triple.starts_with("avr") { + "16bit" + } else { + "32bit" + } +} + +fn normalize(path: &Path, text: &str, filters: &Filter, comments: &Comments) -> String { + // Useless paths + let mut text = text.replace(&path.parent().unwrap().display().to_string(), "$DIR"); + if let Some(lib_path) = option_env!("RUSTC_LIB_PATH") { + text = text.replace(lib_path, "RUSTLIB"); + } + + for (regex, replacement) in filters.iter() { + text = regex.replace_all(&text, *replacement).to_string(); + } + + for (from, to) in &comments.normalize_stderr { + text = from.replace_all(&text, to).to_string(); + } + text +} + +impl Config { + fn get_host(&self) -> String { + rustc_version::VersionMeta::for_command(std::process::Command::new(&self.program)) + .expect("failed to parse rustc version info") + .host + } +} + +#[derive(Copy, Clone, Debug)] +pub enum Mode { + // The test passes a full execution of the rustc driver + Pass, + // The rustc driver panicked + Panic, + // The rustc driver emitted an error + Fail, +} + +impl Mode { + fn ok(self, status: ExitStatus) -> Errors { + match (status.code().unwrap(), self) { + (1, Mode::Fail) | (101, Mode::Panic) | (0, Mode::Pass) => vec![], + _ => vec![Error::ExitStatus(self, status)], + } + } +} From 8c42ef1dee4143c3ba8a2c31558b75edb179b517 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 23 May 2022 15:44:27 +0200 Subject: [PATCH 3106/3747] enable number validity checking and ptr::invalid checking by default --- README.md | 14 +++++--- src/bin/miri.rs | 12 +++++-- src/eval.rs | 9 +++-- src/intptrcast.rs | 19 ++++------ src/machine.rs | 17 ++++++--- src/shims/posix/sync.rs | 3 +- .../provenance/ptr_int_unexposed.rs | 2 +- tests/compile-fail/provenance/ptr_invalid.rs | 1 - .../stacked_borrows/illegal_read3.rs | 1 + tests/compile-fail/transmute-pair-uninit.rs | 1 + tests/compile-fail/uninit_byte_read.rs | 1 + .../invalid_enum_tag_256variants_uninit.rs | 1 + .../validity/ptr_integer_array_transmute.rs | 2 -- .../validity/ptr_integer_transmute.rs | 2 -- tests/compile-fail/validity/uninit_float.rs | 2 -- tests/compile-fail/validity/uninit_integer.rs | 2 -- .../validity/uninit_integer_signed.rs | 2 -- tests/run-pass/bitop-beyond-alignment.rs | 36 ------------------- .../run-pass/concurrency/libc_pthread_cond.rs | 2 +- tests/run-pass/intptrcast.rs | 2 ++ tests/run-pass/libc.rs | 10 +++--- tests/run-pass/move-uninit-primval.rs | 1 + tests/run-pass/partially-uninit.rs | 2 -- tests/run-pass/ptr_offset.rs | 4 ++- tests/run-pass/tag-align-dyn-u64.rs | 3 +- tests/run-pass/transmute_fat.rs | 5 +-- tests/run-pass/uninit_number_ignored.rs | 2 +- 27 files changed, 67 insertions(+), 91 deletions(-) delete mode 100644 tests/run-pass/bitop-beyond-alignment.rs diff --git a/README.md b/README.md index afee8a8bfa053..9248576b3c2af 100644 --- a/README.md +++ b/README.md @@ -44,8 +44,7 @@ in your program, and cannot run all programs: positives here, so if your program runs fine in Miri right now that is by no means a guarantee that it is UB-free when these questions get answered. - In particular, Miri does currently not check that integers/floats are - initialized or that references point to valid data. + In particular, Miri does currently not check that references point to valid data. * If the program relies on unspecified details of how data is laid out, it will still run fine in Miri -- but might break (including causing UB) on different compiler versions or different platforms. @@ -302,10 +301,15 @@ The remaining flags are for advanced use only, and more likely to change or be r Some of these are **unsound**, which means they can lead to Miri failing to detect cases of undefined behavior in a program. -* `-Zmiri-check-number-validity` enables checking of integer and float validity - (e.g., they must be initialized and not carry pointer provenance) as part of - enforcing validity invariants. This has no effect when +* `-Zmiri-allow-uninit-numbers` disables the check to ensure that number types (integer and float + types) always hold initialized data. (They must still be initialized when any actual operation, + such as arithmetic, is performed.) Using this flag is **unsound**. This has no effect when `-Zmiri-disable-validation` is present. +* `-Zmiri-allow-ptr-int-transmute` makes Miri more accepting of transmutation between pointers and + integers via `mem::transmute` or union/pointer type punning. This has two effects: it disables the + check against integers storing a pointer (i.e., data with provenance), thus allowing + pointer-to-integer transmutation, and it treats integer-to-pointer transmutation as equivalent to + a cast. Using this flag is **unsound**. * `-Zmiri-disable-abi-check` disables checking [function ABI]. Using this flag is **unsound**. * `-Zmiri-disable-alignment-check` disables checking pointer alignment, so you diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 784f0da8a30dd..9c4cd0684c610 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -335,7 +335,16 @@ fn main() { miri_config.check_alignment = miri::AlignmentCheck::Symbolic; } "-Zmiri-check-number-validity" => { - miri_config.check_number_validity = true; + eprintln!( + "WARNING: the flag `-Zmiri-check-number-validity` no longer has any effect \ + since it is now enabled by default" + ); + } + "-Zmiri-allow-uninit-numbers" => { + miri_config.allow_uninit_numbers = true; + } + "-Zmiri-allow-ptr-int-transmute" => { + miri_config.allow_ptr_int_transmute = true; } "-Zmiri-disable-abi-check" => { miri_config.check_abi = false; @@ -386,7 +395,6 @@ fn main() { "-Zmiri-strict-provenance" => { miri_config.provenance_mode = ProvenanceMode::Strict; miri_config.tag_raw = true; - miri_config.check_number_validity = true; } "-Zmiri-permissive-provenance" => { miri_config.provenance_mode = ProvenanceMode::Permissive; diff --git a/src/eval.rs b/src/eval.rs index badda8f3bc393..39fccb0924334 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -77,8 +77,10 @@ pub struct MiriConfig { pub stacked_borrows: bool, /// Controls alignment checking. pub check_alignment: AlignmentCheck, - /// Controls integer and float validity (e.g., initialization) checking. - pub check_number_validity: bool, + /// Controls integer and float validity initialization checking. + pub allow_uninit_numbers: bool, + /// Controls how we treat ptr2int and int2ptr transmutes. + pub allow_ptr_int_transmute: bool, /// Controls function [ABI](Abi) checking. pub check_abi: bool, /// Action for an op requiring communication with the host. @@ -126,7 +128,8 @@ impl Default for MiriConfig { validate: true, stacked_borrows: true, check_alignment: AlignmentCheck::Int, - check_number_validity: false, + allow_uninit_numbers: false, + allow_ptr_int_transmute: false, check_abi: true, isolated_op: IsolatedOp::Reject(RejectOpWith::Abort), ignore_leaks: false, diff --git a/src/intptrcast.rs b/src/intptrcast.rs index 4850945b4eeb9..4a86490ed09a9 100644 --- a/src/intptrcast.rs +++ b/src/intptrcast.rs @@ -118,19 +118,12 @@ impl<'mir, 'tcx> GlobalStateInner { ) -> Pointer> { trace!("Transmuting 0x{:x} to a pointer", addr); - let global_state = ecx.machine.intptrcast.borrow(); - - match global_state.provenance_mode { - ProvenanceMode::Legacy => { - // In legacy mode, we have to support int2ptr transmutes, - // so just pretend they do the same thing as a cast. - Self::ptr_from_addr_cast(ecx, addr) - } - ProvenanceMode::Permissive | ProvenanceMode::Strict => { - // Both of these modes consider transmuted pointers to be "invalid" (`None` - // provenance). - Pointer::new(None, Size::from_bytes(addr)) - } + if ecx.machine.allow_ptr_int_transmute { + // When we allow transmutes, treat them like casts. + Self::ptr_from_addr_cast(ecx, addr) + } else { + // We consider transmuted pointers to be "invalid" (`None` provenance). + Pointer::new(None, Size::from_bytes(addr)) } } diff --git a/src/machine.rs b/src/machine.rs index 249b578b1214a..1cb815706195b 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -255,13 +255,19 @@ pub struct Evaluator<'mir, 'tcx> { /// Whether to enforce the validity invariant. pub(crate) validate: bool, - /// Whether to enforce validity (e.g., initialization) of integers and floats. - pub(crate) enforce_number_validity: bool, + /// Whether to allow uninitialized numbers (integers and floats). + pub(crate) allow_uninit_numbers: bool, + + /// Whether to allow ptr2int transmutes, and whether to allow *dereferencing* the result of an + /// int2ptr transmute. + pub(crate) allow_ptr_int_transmute: bool, /// Whether to enforce [ABI](Abi) of function calls. pub(crate) enforce_abi: bool, + /// The table of file descriptors. pub(crate) file_handler: shims::posix::FileHandler, + /// The table of directory descriptors. pub(crate) dir_handler: shims::posix::DirHandler, /// The "time anchor" for this machine's monotone clock (for `Instant` simulation). @@ -351,7 +357,8 @@ impl<'mir, 'tcx> Evaluator<'mir, 'tcx> { tls: TlsData::default(), isolated_op: config.isolated_op, validate: config.validate, - enforce_number_validity: config.check_number_validity, + allow_uninit_numbers: config.allow_uninit_numbers, + allow_ptr_int_transmute: config.allow_ptr_int_transmute, enforce_abi: config.check_abi, file_handler: FileHandler::new(config.mute_stdout_stderr), dir_handler: Default::default(), @@ -493,12 +500,12 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { #[inline(always)] fn enforce_number_init(ecx: &MiriEvalContext<'mir, 'tcx>) -> bool { - ecx.machine.enforce_number_validity + !ecx.machine.allow_uninit_numbers } #[inline(always)] fn enforce_number_no_provenance(ecx: &MiriEvalContext<'mir, 'tcx>) -> bool { - ecx.machine.enforce_number_validity + !ecx.machine.allow_ptr_int_transmute } #[inline(always)] diff --git a/src/shims/posix/sync.rs b/src/shims/posix/sync.rs index 1b6112a3311f7..f56a309bf0789 100644 --- a/src/shims/posix/sync.rs +++ b/src/shims/posix/sync.rs @@ -405,8 +405,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // To catch double-destroys, we de-initialize the mutexattr. // This is technically not right and might lead to false positives. For example, the below - // code is *likely* sound, even assuming uninit numbers are UB, but miri with - // -Zmiri-check-number-validity complains + // code is *likely* sound, even assuming uninit numbers are UB, but Miri complains. // // let mut x: MaybeUninit = MaybeUninit::zeroed(); // libc::pthread_mutexattr_init(x.as_mut_ptr()); diff --git a/tests/compile-fail/provenance/ptr_int_unexposed.rs b/tests/compile-fail/provenance/ptr_int_unexposed.rs index 2aecb68b8b647..8a336e43ba18f 100644 --- a/tests/compile-fail/provenance/ptr_int_unexposed.rs +++ b/tests/compile-fail/provenance/ptr_int_unexposed.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-permissive-provenance -Zmiri-disable-stacked-borrows +// compile-flags: -Zmiri-permissive-provenance -Zmiri-disable-stacked-borrows -Zmiri-allow-ptr-int-transmute fn main() { let x: i32 = 3; diff --git a/tests/compile-fail/provenance/ptr_invalid.rs b/tests/compile-fail/provenance/ptr_invalid.rs index b371103e6b665..f4f3ed5afa5c4 100644 --- a/tests/compile-fail/provenance/ptr_invalid.rs +++ b/tests/compile-fail/provenance/ptr_invalid.rs @@ -1,4 +1,3 @@ -// compile-flags: -Zmiri-permissive-provenance #![feature(strict_provenance)] // Ensure that a `ptr::invalid` ptr is truly invalid. diff --git a/tests/compile-fail/stacked_borrows/illegal_read3.rs b/tests/compile-fail/stacked_borrows/illegal_read3.rs index 09fd5d534cf7d..672c200861c68 100644 --- a/tests/compile-fail/stacked_borrows/illegal_read3.rs +++ b/tests/compile-fail/stacked_borrows/illegal_read3.rs @@ -1,3 +1,4 @@ +// compile-flags: -Zmiri-allow-ptr-int-transmute // A callee may not read the destination of our `&mut` without us noticing. // Thise code got carefully checked to not introduce any reborrows // that are not explicit in the source. Let's hope the compiler does not break this later! diff --git a/tests/compile-fail/transmute-pair-uninit.rs b/tests/compile-fail/transmute-pair-uninit.rs index 42aa7a9692788..18c80ac42ac8e 100644 --- a/tests/compile-fail/transmute-pair-uninit.rs +++ b/tests/compile-fail/transmute-pair-uninit.rs @@ -1,3 +1,4 @@ +// compile-flags: -Zmiri-allow-uninit-numbers #![feature(core_intrinsics)] use std::mem; diff --git a/tests/compile-fail/uninit_byte_read.rs b/tests/compile-fail/uninit_byte_read.rs index 36c14137bdc16..9a1f8df94d60f 100644 --- a/tests/compile-fail/uninit_byte_read.rs +++ b/tests/compile-fail/uninit_byte_read.rs @@ -1,3 +1,4 @@ +// compile-flags: -Zmiri-allow-uninit-numbers fn main() { let v: Vec = Vec::with_capacity(10); let undef = unsafe { *v.get_unchecked(5) }; diff --git a/tests/compile-fail/validity/invalid_enum_tag_256variants_uninit.rs b/tests/compile-fail/validity/invalid_enum_tag_256variants_uninit.rs index ccf97b416c691..c36685ab2f467 100644 --- a/tests/compile-fail/validity/invalid_enum_tag_256variants_uninit.rs +++ b/tests/compile-fail/validity/invalid_enum_tag_256variants_uninit.rs @@ -1,3 +1,4 @@ +// compile-flags: -Zmiri-allow-uninit-numbers #![allow(unused, deprecated, invalid_value)] #[derive(Copy, Clone)] diff --git a/tests/compile-fail/validity/ptr_integer_array_transmute.rs b/tests/compile-fail/validity/ptr_integer_array_transmute.rs index 7a1ae2f3c9a11..92c635ff22181 100644 --- a/tests/compile-fail/validity/ptr_integer_array_transmute.rs +++ b/tests/compile-fail/validity/ptr_integer_array_transmute.rs @@ -1,5 +1,3 @@ -// compile-flags: -Zmiri-check-number-validity - fn main() { let r = &mut 42; let _i: [usize; 1] = unsafe { std::mem::transmute(r) }; //~ ERROR encountered a pointer, but expected plain (non-pointer) bytes diff --git a/tests/compile-fail/validity/ptr_integer_transmute.rs b/tests/compile-fail/validity/ptr_integer_transmute.rs index bb9e8e1e220f4..b23ccbbb1b033 100644 --- a/tests/compile-fail/validity/ptr_integer_transmute.rs +++ b/tests/compile-fail/validity/ptr_integer_transmute.rs @@ -1,5 +1,3 @@ -// compile-flags: -Zmiri-check-number-validity - fn main() { let r = &mut 42; let _i: usize = unsafe { std::mem::transmute(r) }; //~ ERROR expected plain (non-pointer) bytes diff --git a/tests/compile-fail/validity/uninit_float.rs b/tests/compile-fail/validity/uninit_float.rs index 1cb687f9b008a..e79cbb45f9848 100644 --- a/tests/compile-fail/validity/uninit_float.rs +++ b/tests/compile-fail/validity/uninit_float.rs @@ -1,5 +1,3 @@ -// compile-flags: -Zmiri-check-number-validity - // This test is adapted from https://github.com/rust-lang/miri/issues/1340#issue-600900312. fn main() { diff --git a/tests/compile-fail/validity/uninit_integer.rs b/tests/compile-fail/validity/uninit_integer.rs index c700f1f46d993..bfa25d6ef356d 100644 --- a/tests/compile-fail/validity/uninit_integer.rs +++ b/tests/compile-fail/validity/uninit_integer.rs @@ -1,5 +1,3 @@ -// compile-flags: -Zmiri-check-number-validity - // This test is from https://github.com/rust-lang/miri/issues/1340#issue-600900312. fn main() { diff --git a/tests/compile-fail/validity/uninit_integer_signed.rs b/tests/compile-fail/validity/uninit_integer_signed.rs index 28bca0b19a780..1764120805c42 100644 --- a/tests/compile-fail/validity/uninit_integer_signed.rs +++ b/tests/compile-fail/validity/uninit_integer_signed.rs @@ -1,5 +1,3 @@ -// compile-flags: -Zmiri-check-number-validity - // This test is adapted from https://github.com/rust-lang/miri/issues/1340#issue-600900312. fn main() { diff --git a/tests/run-pass/bitop-beyond-alignment.rs b/tests/run-pass/bitop-beyond-alignment.rs deleted file mode 100644 index e540a2a4b723f..0000000000000 --- a/tests/run-pass/bitop-beyond-alignment.rs +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -use std::mem; - -enum Tag { - Tag2(A) -} - -#[allow(dead_code)] -struct Rec { - c8: u8, - t: Tag -} - -fn mk_rec() -> Rec { - return Rec { c8:0, t:Tag::Tag2(0) }; -} - -fn is_u64_aligned(u: &Tag) -> bool { - let p: usize = unsafe { mem::transmute(u) }; - let u64_align = std::mem::align_of::(); - return (p & (u64_align + 1)) == 0; -} - -pub fn main() { - let x = mk_rec(); - is_u64_aligned(&x.t); // the result of this is non-deterministic (even with a fixed seed, results vary between targets) -} diff --git a/tests/run-pass/concurrency/libc_pthread_cond.rs b/tests/run-pass/concurrency/libc_pthread_cond.rs index 631675aaaf54b..1f6f46cbeb517 100644 --- a/tests/run-pass/concurrency/libc_pthread_cond.rs +++ b/tests/run-pass/concurrency/libc_pthread_cond.rs @@ -1,6 +1,6 @@ // ignore-windows: No libc on Windows // ignore-apple: pthread_condattr_setclock is not supported on MacOS. -// compile-flags: -Zmiri-disable-isolation -Zmiri-check-number-validity +// compile-flags: -Zmiri-disable-isolation #![feature(rustc_private)] diff --git a/tests/run-pass/intptrcast.rs b/tests/run-pass/intptrcast.rs index 6e72d30d41235..573bdbae704a4 100644 --- a/tests/run-pass/intptrcast.rs +++ b/tests/run-pass/intptrcast.rs @@ -1,3 +1,5 @@ +// compile-flags: -Zmiri-allow-ptr-int-transmute + // This returns a miri pointer at type usize, if the argument is a proper pointer fn transmute_ptr_to_int(x: *const T) -> usize { unsafe { std::mem::transmute(x) } diff --git a/tests/run-pass/libc.rs b/tests/run-pass/libc.rs index ab9a690fe1d77..fd3625639bfde 100644 --- a/tests/run-pass/libc.rs +++ b/tests/run-pass/libc.rs @@ -197,17 +197,17 @@ fn test_prctl_thread_name() { use libc::c_long; unsafe { let mut buf = [255; 10]; - assert_eq!(libc::prctl(libc::PR_GET_NAME, buf.as_mut_ptr() as c_long, 0 as c_long, 0 as c_long, 0 as c_long), 0); + assert_eq!(libc::prctl(libc::PR_GET_NAME, buf.as_mut_ptr(), 0 as c_long, 0 as c_long, 0 as c_long), 0); assert_eq!(b"\0", &buf); let thread_name = CString::new("hello").expect("CString::new failed"); - assert_eq!(libc::prctl(libc::PR_SET_NAME, thread_name.as_ptr() as c_long, 0 as c_long, 0 as c_long, 0 as c_long), 0); + assert_eq!(libc::prctl(libc::PR_SET_NAME, thread_name.as_ptr(), 0 as c_long, 0 as c_long, 0 as c_long), 0); let mut buf = [255; 6]; - assert_eq!(libc::prctl(libc::PR_GET_NAME, buf.as_mut_ptr() as c_long, 0 as c_long, 0 as c_long, 0 as c_long), 0); + assert_eq!(libc::prctl(libc::PR_GET_NAME, buf.as_mut_ptr(), 0 as c_long, 0 as c_long, 0 as c_long), 0); assert_eq!(b"hello\0", &buf); let long_thread_name = CString::new("01234567890123456789").expect("CString::new failed"); - assert_eq!(libc::prctl(libc::PR_SET_NAME, long_thread_name.as_ptr() as c_long, 0 as c_long, 0 as c_long, 0 as c_long), 0); + assert_eq!(libc::prctl(libc::PR_SET_NAME, long_thread_name.as_ptr(), 0 as c_long, 0 as c_long, 0 as c_long), 0); let mut buf = [255; 16]; - assert_eq!(libc::prctl(libc::PR_GET_NAME, buf.as_mut_ptr() as c_long, 0 as c_long, 0 as c_long, 0 as c_long), 0); + assert_eq!(libc::prctl(libc::PR_GET_NAME, buf.as_mut_ptr(), 0 as c_long, 0 as c_long, 0 as c_long), 0); assert_eq!(b"012345678901234\0", &buf); } } diff --git a/tests/run-pass/move-uninit-primval.rs b/tests/run-pass/move-uninit-primval.rs index b8bd869b48c97..0edc3c9e6cd84 100644 --- a/tests/run-pass/move-uninit-primval.rs +++ b/tests/run-pass/move-uninit-primval.rs @@ -1,3 +1,4 @@ +// compile-flags: -Zmiri-allow-uninit-numbers #![allow(deprecated)] struct Foo { diff --git a/tests/run-pass/partially-uninit.rs b/tests/run-pass/partially-uninit.rs index 1de5308428279..5ee9abbcb95bb 100644 --- a/tests/run-pass/partially-uninit.rs +++ b/tests/run-pass/partially-uninit.rs @@ -1,5 +1,3 @@ -// compile-flags: -Zmiri-check-number-validity - use std::mem::{self, MaybeUninit}; #[repr(C)] diff --git a/tests/run-pass/ptr_offset.rs b/tests/run-pass/ptr_offset.rs index 6af3e28854ab5..4c6341813f5b7 100644 --- a/tests/run-pass/ptr_offset.rs +++ b/tests/run-pass/ptr_offset.rs @@ -61,7 +61,9 @@ fn ptr_offset() { unsafe { let p = f as fn() -> i32 as usize; let x = (p as *mut u32).offset(0) as usize; - let f: fn() -> i32 = mem::transmute(x); + // *cast* to ptr, then transmute to fn ptr. + // (transmuting int to [fn]ptr causes trouble.) + let f: fn() -> i32 = mem::transmute(x as *const ()); assert_eq!(f(), 42); } } diff --git a/tests/run-pass/tag-align-dyn-u64.rs b/tests/run-pass/tag-align-dyn-u64.rs index 8a97758fbb594..460c2b25594af 100644 --- a/tests/run-pass/tag-align-dyn-u64.rs +++ b/tests/run-pass/tag-align-dyn-u64.rs @@ -25,7 +25,8 @@ fn mk_rec() -> Rec { } fn is_u64_aligned(u: &Tag) -> bool { - let p: usize = unsafe { mem::transmute(u) }; + let p: *const () = unsafe { mem::transmute(u) }; + let p = p as usize; let u64_align = std::mem::align_of::(); return (p & (u64_align - 1)) == 0; } diff --git a/tests/run-pass/transmute_fat.rs b/tests/run-pass/transmute_fat.rs index 238122de8d4c0..8a6e15031cb4d 100644 --- a/tests/run-pass/transmute_fat.rs +++ b/tests/run-pass/transmute_fat.rs @@ -1,5 +1,5 @@ // Stacked Borrows disallows this becuase the reference is never cast to a raw pointer. -// compile-flags: -Zmiri-disable-stacked-borrows +// compile-flags: -Zmiri-disable-stacked-borrows -Zmiri-allow-ptr-int-transmute fn main() { // If we are careful, we can exploit data layout... @@ -7,7 +7,8 @@ fn main() { std::mem::transmute::<&[u8], [usize; 2]>(&[42]) }; let ptr = raw[0] + raw[1]; - let ptr = ptr as *const u8; + // We transmute both ways, to really test allow-ptr-int-transmute. + let ptr: *const u8 = unsafe { std::mem::transmute(ptr) }; // The pointer is one-past-the end, but we decrement it into bounds before using it assert_eq!(unsafe { *ptr.offset(-1) }, 42); } diff --git a/tests/run-pass/uninit_number_ignored.rs b/tests/run-pass/uninit_number_ignored.rs index 77d6af6e99cf7..13aac61ba84cc 100644 --- a/tests/run-pass/uninit_number_ignored.rs +++ b/tests/run-pass/uninit_number_ignored.rs @@ -1,5 +1,5 @@ +// compile-flags: -Zmiri-allow-uninit-numbers // This test is adapted from https://github.com/rust-lang/miri/issues/1340#issue-600900312. -// This test passes because -Zmiri-check-number-validity is not passed. fn main() { let _val1 = unsafe { std::mem::MaybeUninit::::uninit().assume_init() }; From a6b5b0e4ff911c5e36e544fc2aed80e8d4ed912b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 25 May 2022 18:12:54 +0200 Subject: [PATCH 3107/3747] tweak new test suite output --- tests/compiletest.rs | 12 +++++------- ui_test/src/lib.rs | 24 +++++++++++++----------- 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/tests/compiletest.rs b/tests/compiletest.rs index 92a8bd6291e29..9ffc4744eb858 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -109,13 +109,11 @@ regexes! { fn ui(mode: Mode, path: &str) { let target = get_target(); - eprint!("{}", format!("## Running ui tests in {path} against miri for ").green().bold()); - - if let Some(target) = &target { - eprintln!("{target}"); - } else { - eprintln!("host"); - } + let msg = format!( + "## Running ui tests in {path} against miri for {}", + target.as_deref().unwrap_or("host") + ); + eprintln!("{}", msg.green().bold()); run_tests(mode, path, target); } diff --git a/ui_test/src/lib.rs b/ui_test/src/lib.rs index 95ae3a51b235d..b779d6844a970 100644 --- a/ui_test/src/lib.rs +++ b/ui_test/src/lib.rs @@ -56,7 +56,7 @@ pub fn run_tests(config: Config) { // Some statistics and failure reports. let failures = Mutex::new(vec![]); let succeeded = AtomicUsize::default(); - let skipped = AtomicUsize::default(); + let ignored = AtomicUsize::default(); crossbeam::scope(|s| { for _ in 0..std::thread::available_parallelism().unwrap().get() { @@ -74,10 +74,10 @@ pub fn run_tests(config: Config) { continue; } let comments = Comments::parse(&path); - // Skip file if only/skip rules do (not) apply + // Ignore file if only/ignore rules do (not) apply if ignore_file(&comments, &target) { - skipped.fetch_add(1, Ordering::Relaxed); - eprintln!("{} .. {}", path.display(), "skipped".yellow()); + ignored.fetch_add(1, Ordering::Relaxed); + eprintln!("{} .. {}", path.display(), "ignored".yellow()); continue; } // Run the test for all revisions @@ -91,7 +91,7 @@ pub fn run_tests(config: Config) { if !revision.is_empty() { write!(msg, "(revision `{revision}`) ").unwrap(); } - write!(msg, " .. ").unwrap(); + write!(msg, "... ").unwrap(); if errors.is_empty() { eprintln!("{msg}{}", "ok".green()); succeeded.fetch_add(1, Ordering::Relaxed); @@ -109,7 +109,7 @@ pub fn run_tests(config: Config) { // Print all errors in a single thread to show reliable output let failures = failures.into_inner().unwrap(); let succeeded = succeeded.load(Ordering::Relaxed); - let skipped = skipped.load(Ordering::Relaxed); + let ignored = ignored.load(Ordering::Relaxed); if !failures.is_empty() { for (path, miri, revision, errors) in &failures { eprintln!(); @@ -117,7 +117,7 @@ pub fn run_tests(config: Config) { if !revision.is_empty() { eprint!(" (revision `{}`)", revision); } - eprint!("{}", " FAILED".red()); + eprint!(" {}", "FAILED".red()); eprintln!(); eprintln!("command: {:?}", miri); eprintln!(); @@ -153,19 +153,21 @@ pub fn run_tests(config: Config) { } } eprintln!( - "{} tests failed, {} tests passed, {} skipped", + "{} tests failed, {} tests passed, {} ignored", failures.len().to_string().red().bold(), succeeded.to_string().green(), - skipped.to_string().yellow() + ignored.to_string().yellow() ); std::process::exit(1); } eprintln!(); eprintln!( - "{} tests passed, {} skipped", + "test result: {}. {} tests passed, {} ignored", + "ok".green(), succeeded.to_string().green(), - skipped.to_string().yellow() + ignored.to_string().yellow() ); + eprintln!(); } #[derive(Debug)] From 23bbe2bce72c4674ef46507a2db1e4e5e55ff3ff Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 25 May 2022 16:08:41 +0000 Subject: [PATCH 3108/3747] Reproduce #2156 --- ui_test/.gitignore | 1 + ui_test/src/comments.rs | 11 +++++-- ui_test/src/lib.rs | 10 +++--- ui_test/tests/check_annotations.rs | 49 ++++++++++++++++++++++++++++++ ui_test/tests/comment_parser.rs | 22 ++++++++++++++ 5 files changed, 85 insertions(+), 8 deletions(-) create mode 100644 ui_test/.gitignore create mode 100644 ui_test/tests/check_annotations.rs create mode 100644 ui_test/tests/comment_parser.rs diff --git a/ui_test/.gitignore b/ui_test/.gitignore new file mode 100644 index 0000000000000..03314f77b5aa4 --- /dev/null +++ b/ui_test/.gitignore @@ -0,0 +1 @@ +Cargo.lock diff --git a/ui_test/src/comments.rs b/ui_test/src/comments.rs index 14566d2feccf5..193cda68b9aaa 100644 --- a/ui_test/src/comments.rs +++ b/ui_test/src/comments.rs @@ -5,7 +5,7 @@ use regex::Regex; /// This crate supports various magic comments that get parsed as file-specific /// configuration values. This struct parses them all in one go and then they /// get processed by their respective use sites. -#[derive(Default)] +#[derive(Default, Debug)] pub struct Comments { /// List of revision names to execute. Can only be speicified once pub revisions: Option>, @@ -26,6 +26,7 @@ pub struct Comments { pub error_matches: Vec, } +#[derive(Debug)] pub struct ErrorMatch { pub matched: String, pub revision: Option, @@ -33,9 +34,13 @@ pub struct ErrorMatch { } impl Comments { - pub fn parse(path: &Path) -> Self { - let mut this = Self::default(); + pub fn parse_file(path: &Path) -> Self { let content = std::fs::read_to_string(path).unwrap(); + Self::parse(path, &content) + } + + pub fn parse(path: &Path, content: &str) -> Self { + let mut this = Self::default(); let error_pattern_regex = Regex::new(r"//(\[(?P[^\]]+)\])?~[|^]*\s*(ERROR|HELP|WARN)?:?(?P.*)") .unwrap(); diff --git a/ui_test/src/lib.rs b/ui_test/src/lib.rs index b779d6844a970..4f7e55fdce8db 100644 --- a/ui_test/src/lib.rs +++ b/ui_test/src/lib.rs @@ -9,7 +9,7 @@ use comments::ErrorMatch; use crossbeam::queue::SegQueue; use regex::Regex; -use crate::comments::Comments; +pub use crate::comments::Comments; mod comments; @@ -73,7 +73,7 @@ pub fn run_tests(config: Config) { if !path.extension().map(|ext| ext == "rs").unwrap_or(false) { continue; } - let comments = Comments::parse(&path); + let comments = Comments::parse_file(&path); // Ignore file if only/ignore rules do (not) apply if ignore_file(&comments, &target) { ignored.fetch_add(1, Ordering::Relaxed); @@ -171,7 +171,7 @@ pub fn run_tests(config: Config) { } #[derive(Debug)] -enum Error { +pub enum Error { /// Got an invalid exit status for the given mode. ExitStatus(Mode, ExitStatus), PatternNotFound { @@ -191,7 +191,7 @@ enum Error { }, } -type Errors = Vec; +pub type Errors = Vec; fn run_test( path: &Path, @@ -249,7 +249,7 @@ fn run_test( (miri, errors) } -fn check_annotations( +pub fn check_annotations( unnormalized_stderr: &[u8], errors: &mut Errors, config: &Config, diff --git a/ui_test/tests/check_annotations.rs b/ui_test/tests/check_annotations.rs new file mode 100644 index 0000000000000..4735fe1fa0493 --- /dev/null +++ b/ui_test/tests/check_annotations.rs @@ -0,0 +1,49 @@ +use std::path::{Path, PathBuf}; + +use ui_test::{check_annotations, Comments, Config, Error, Mode, OutputConflictHandling}; + +fn config() -> Config { + Config { + args: vec![], + target: None, + stderr_filters: vec![], + stdout_filters: vec![], + root_dir: PathBuf::from("."), + mode: Mode::Fail, + program: PathBuf::from("cake"), + output_conflict_handling: OutputConflictHandling::Error, + } +} + +#[test] +fn issue_2156() { + let s = r" +use std::mem; + +fn main() { + let _x: &i32 = unsafe { mem::transmute(16usize) }; //~ ERROR encountered a dangling reference (address $HEX is unallocated) +} + "; + let comments = Comments::parse(Path::new(""), s); + let mut errors = vec![]; + let config = config(); + let unnormalized_stderr = r" +error: Undefined Behavior: type validation failed: encountered a dangling reference (address 0x10 is unallocated) + --> tests/compile-fail/validity/dangling_ref1.rs:6:29 + | +LL | let _x: &i32 = unsafe { mem::transmute(16usize) }; //~ ERROR encountered a dangling reference (address $HEX is unallocated) + | ^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a dangling reference (address 0x10 is unallocated) + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at tests/compile-fail/validity/dangling_ref1.rs:6:29 +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace +error: aborting due to previous error + "; + check_annotations(unnormalized_stderr.as_bytes(), &mut errors, &config, "", &comments); + match &errors[..] { + [Error::PatternNotFound { .. }] => {} + _ => panic!("{:#?}", errors), + } +} diff --git a/ui_test/tests/comment_parser.rs b/ui_test/tests/comment_parser.rs new file mode 100644 index 0000000000000..ee1382a6c7886 --- /dev/null +++ b/ui_test/tests/comment_parser.rs @@ -0,0 +1,22 @@ +use std::path::Path; + +use ui_test::Comments; + +#[test] +fn issue_2156() { + let s = r" +use std::mem; + +fn main() { + let _x: &i32 = unsafe { mem::transmute(16usize) }; //~ ERROR encountered a dangling reference (address $HEX is unallocated) +} + "; + let comments = Comments::parse(Path::new(""), s); + println!("{:#?}", comments); + assert_eq!(comments.error_matches[0].definition_line, 4); + assert_eq!(comments.error_matches[0].revision, None); + assert_eq!( + comments.error_matches[0].matched, + "encountered a dangling reference (address $HEX is unallocated)" + ); +} From 21795f3ce4eabfce2fd5d36e0d9852bde9d52158 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 25 May 2022 16:11:37 +0000 Subject: [PATCH 3109/3747] Fix annotations matching themselves --- ui_test/src/lib.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ui_test/src/lib.rs b/ui_test/src/lib.rs index 4f7e55fdce8db..f657be4ea65c7 100644 --- a/ui_test/src/lib.rs +++ b/ui_test/src/lib.rs @@ -257,6 +257,9 @@ pub fn check_annotations( comments: &Comments, ) { let unnormalized_stderr = std::str::from_utf8(unnormalized_stderr).unwrap(); + // erase annotations from the stderr so they don't match themselves + let annotations = Regex::new(r"\s*//~.*").unwrap(); + let unnormalized_stderr = annotations.replace(unnormalized_stderr, ""); let mut found_annotation = false; if let Some((ref error_pattern, definition_line)) = comments.error_pattern { if !unnormalized_stderr.contains(error_pattern) { From b64a1c46c67c58e2da05c67ef1b2d73dd756549c Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 25 May 2022 16:15:31 +0000 Subject: [PATCH 3110/3747] Make the file path of the failure more visible to be able to click it faster --- ui_test/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui_test/src/lib.rs b/ui_test/src/lib.rs index f657be4ea65c7..ba1f874413d80 100644 --- a/ui_test/src/lib.rs +++ b/ui_test/src/lib.rs @@ -129,7 +129,7 @@ pub fn run_tests(config: Config) { eprintln!("`{pattern}` {} in stderr output", "not found".red()); eprintln!( "expected because of pattern here: {}:{definition_line}", - path.display() + path.display().to_string().bold() ); dump_stderr = Some(stderr.clone()) } From 8acfbc3b3332ed7f5364bc38c947c6c083ef99df Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 25 May 2022 16:15:37 +0000 Subject: [PATCH 3111/3747] Update all tests --- tests/compile-fail/intrinsics/copy_unaligned.rs | 2 +- .../compile-fail/stacked_borrows/static_memory_modification.rs | 2 +- tests/compile-fail/unaligned_pointers/dyn_alignment.rs | 2 +- .../unaligned_pointers/intptrcast_alignment_check.rs | 2 +- tests/compile-fail/unaligned_pointers/reference_to_packed.rs | 2 +- tests/compile-fail/unaligned_pointers/unaligned_ptr1.rs | 2 +- tests/compile-fail/unaligned_pointers/unaligned_ptr2.rs | 2 +- tests/compile-fail/unaligned_pointers/unaligned_ptr_addr_of.rs | 2 +- tests/compile-fail/unaligned_pointers/unaligned_ptr_zst.rs | 2 +- tests/compile-fail/validity/dangling_ref1.rs | 2 +- tests/compile-fail/validity/invalid_char.rs | 2 +- 11 files changed, 11 insertions(+), 11 deletions(-) diff --git a/tests/compile-fail/intrinsics/copy_unaligned.rs b/tests/compile-fail/intrinsics/copy_unaligned.rs index 7aff0adc407a2..84f4de93461e7 100644 --- a/tests/compile-fail/intrinsics/copy_unaligned.rs +++ b/tests/compile-fail/intrinsics/copy_unaligned.rs @@ -9,5 +9,5 @@ fn main() { let mut data = [0u16; 8]; let ptr = (&mut data[0] as *mut u16 as *mut u8).wrapping_add(1) as *mut u16; // Even copying 0 elements to something unaligned should error - unsafe { copy_nonoverlapping(&data[5], ptr, 0); } //~ ERROR accessing memory with alignment ALIGN, but alignment ALIGN is required + unsafe { copy_nonoverlapping(&data[5], ptr, 0); } //~ ERROR accessing memory with alignment 1, but alignment 2 is required } diff --git a/tests/compile-fail/stacked_borrows/static_memory_modification.rs b/tests/compile-fail/stacked_borrows/static_memory_modification.rs index 72e2ed9381240..417a03bb0335b 100644 --- a/tests/compile-fail/stacked_borrows/static_memory_modification.rs +++ b/tests/compile-fail/stacked_borrows/static_memory_modification.rs @@ -3,6 +3,6 @@ static X: usize = 5; #[allow(mutable_transmutes)] fn main() { let _x = unsafe { - std::mem::transmute::<&usize, &mut usize>(&X) //~ ERROR writing to ALLOC which is read-only + std::mem::transmute::<&usize, &mut usize>(&X) //~ ERROR writing to alloc1 which is read-only }; } diff --git a/tests/compile-fail/unaligned_pointers/dyn_alignment.rs b/tests/compile-fail/unaligned_pointers/dyn_alignment.rs index 9d8829fe1ee0c..91d9ec475b1fe 100644 --- a/tests/compile-fail/unaligned_pointers/dyn_alignment.rs +++ b/tests/compile-fail/unaligned_pointers/dyn_alignment.rs @@ -16,6 +16,6 @@ fn main() { // Overwrite the data part of `ptr` so it points to `buf`. unsafe { (&mut ptr as *mut _ as *mut *const u8).write(&buf as *const _ as *const u8); } // Re-borrow that. This should be UB. - let _ptr = &*ptr; //~ERROR alignment ALIGN is required + let _ptr = &*ptr; //~ERROR alignment 256 is required } } diff --git a/tests/compile-fail/unaligned_pointers/intptrcast_alignment_check.rs b/tests/compile-fail/unaligned_pointers/intptrcast_alignment_check.rs index a8d0b5afbb89d..9872a493c02a9 100644 --- a/tests/compile-fail/unaligned_pointers/intptrcast_alignment_check.rs +++ b/tests/compile-fail/unaligned_pointers/intptrcast_alignment_check.rs @@ -12,6 +12,6 @@ fn main() { // Manually make sure the pointer is properly aligned. let base_addr_aligned = if base_addr % 2 == 0 { base_addr } else { base_addr+1 }; let u16_ptr = base_addr_aligned as *mut u16; - unsafe { *u16_ptr = 2; } //~ERROR memory with alignment ALIGN, but alignment ALIGN is required + unsafe { *u16_ptr = 2; } //~ERROR memory with alignment 1, but alignment 2 is required println!("{:?}", x); } diff --git a/tests/compile-fail/unaligned_pointers/reference_to_packed.rs b/tests/compile-fail/unaligned_pointers/reference_to_packed.rs index 60d2524040a26..b376859d22c11 100644 --- a/tests/compile-fail/unaligned_pointers/reference_to_packed.rs +++ b/tests/compile-fail/unaligned_pointers/reference_to_packed.rs @@ -16,6 +16,6 @@ fn main() { y: 99, }; let p = &foo.x; - let i = *p; //~ERROR alignment ALIGN is required + let i = *p; //~ERROR alignment 4 is required } } diff --git a/tests/compile-fail/unaligned_pointers/unaligned_ptr1.rs b/tests/compile-fail/unaligned_pointers/unaligned_ptr1.rs index fe46e7b8addb3..1d72e5170b7c2 100644 --- a/tests/compile-fail/unaligned_pointers/unaligned_ptr1.rs +++ b/tests/compile-fail/unaligned_pointers/unaligned_ptr1.rs @@ -6,6 +6,6 @@ fn main() { let x = [2u16, 3, 4]; // Make it big enough so we don't get an out-of-bounds error. let x = &x[0] as *const _ as *const u32; // This must fail because alignment is violated: the allocation's base is not sufficiently aligned. - let _x = unsafe { *x }; //~ERROR memory with alignment ALIGN, but alignment ALIGN is required + let _x = unsafe { *x }; //~ERROR memory with alignment 2, but alignment 4 is required } } diff --git a/tests/compile-fail/unaligned_pointers/unaligned_ptr2.rs b/tests/compile-fail/unaligned_pointers/unaligned_ptr2.rs index 1d1e7fad05c94..49612e2b8a096 100644 --- a/tests/compile-fail/unaligned_pointers/unaligned_ptr2.rs +++ b/tests/compile-fail/unaligned_pointers/unaligned_ptr2.rs @@ -8,5 +8,5 @@ fn main() { let x = (x.as_ptr() as *const u8).wrapping_offset(3) as *const u32; // This must fail because alignment is violated: the offset is not sufficiently aligned. // Also make the offset not a power of 2, that used to ICE. - let _x = unsafe { *x }; //~ERROR memory with alignment ALIGN, but alignment ALIGN is required + let _x = unsafe { *x }; //~ERROR memory with alignment 1, but alignment 4 is required } diff --git a/tests/compile-fail/unaligned_pointers/unaligned_ptr_addr_of.rs b/tests/compile-fail/unaligned_pointers/unaligned_ptr_addr_of.rs index d97306b3cb815..e33f3c8598f33 100644 --- a/tests/compile-fail/unaligned_pointers/unaligned_ptr_addr_of.rs +++ b/tests/compile-fail/unaligned_pointers/unaligned_ptr_addr_of.rs @@ -8,6 +8,6 @@ fn main() { let x = &x[0] as *const _ as *const u32; // This must fail because alignment is violated: the allocation's base is not sufficiently aligned. // The deref is UB even if we just put the result into a raw pointer. - let _x = unsafe { ptr::addr_of!(*x) }; //~ ERROR memory with alignment ALIGN, but alignment ALIGN is required + let _x = unsafe { ptr::addr_of!(*x) }; //~ ERROR memory with alignment 2, but alignment 4 is required } } diff --git a/tests/compile-fail/unaligned_pointers/unaligned_ptr_zst.rs b/tests/compile-fail/unaligned_pointers/unaligned_ptr_zst.rs index c549688c262e9..27403c11abc74 100644 --- a/tests/compile-fail/unaligned_pointers/unaligned_ptr_zst.rs +++ b/tests/compile-fail/unaligned_pointers/unaligned_ptr_zst.rs @@ -7,6 +7,6 @@ fn main() { let x = i as u8; let x = &x as *const _ as *const [u32; 0]; // This must fail because alignment is violated. Test specifically for loading ZST. - let _x = unsafe { *x }; //~ERROR alignment ALIGN is required + let _x = unsafe { *x }; //~ERROR alignment 4 is required } } diff --git a/tests/compile-fail/validity/dangling_ref1.rs b/tests/compile-fail/validity/dangling_ref1.rs index 3243eee06eb67..78425cde4a8aa 100644 --- a/tests/compile-fail/validity/dangling_ref1.rs +++ b/tests/compile-fail/validity/dangling_ref1.rs @@ -3,5 +3,5 @@ use std::mem; fn main() { - let _x: &i32 = unsafe { mem::transmute(16usize) }; //~ ERROR encountered a dangling reference (address $HEX is unallocated) + let _x: &i32 = unsafe { mem::transmute(16usize) }; //~ ERROR encountered a dangling reference (address 0x10 is unallocated) } diff --git a/tests/compile-fail/validity/invalid_char.rs b/tests/compile-fail/validity/invalid_char.rs index d9a55f241c00b..079823f894a86 100644 --- a/tests/compile-fail/validity/invalid_char.rs +++ b/tests/compile-fail/validity/invalid_char.rs @@ -1,6 +1,6 @@ fn main() { assert!(std::char::from_u32(-1_i32 as u32).is_none()); - let _val = match unsafe { std::mem::transmute::(-1) } { //~ ERROR encountered $HEX, but expected a valid unicode scalar value + let _val = match unsafe { std::mem::transmute::(-1) } { //~ ERROR encountered 0xffffffff, but expected a valid unicode scalar value 'a' => {true}, 'b' => {false}, _ => {true}, From e4d6c00aa2cc1ad794f57cdae4eeee9878f14f0a Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 25 May 2022 17:48:03 +0000 Subject: [PATCH 3112/3747] Run tests for ui_test together with miri test --- miri | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/miri b/miri index 6a809b74356a3..3846eb795a4f3 100755 --- a/miri +++ b/miri @@ -134,7 +134,8 @@ test|test-debug|bless|bless-debug) esac # Then test, and let caller control flags. # Only in root project as `cargo-miri` has no tests. - exec cargo test $CARGO_BUILD_FLAGS "$@" + cargo test $CARGO_BUILD_FLAGS "$@" + cargo test --manifest-path ui_test/Cargo.toml ;; run|run-debug) # Scan for "--target" to set the "MIRI_TEST_TARGET" env var so From d466eb8f664a4436e5913a387fc26446f161c22a Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 25 May 2022 17:53:39 +0000 Subject: [PATCH 3113/3747] Explain `Comments::parse` arguments --- ui_test/src/comments.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ui_test/src/comments.rs b/ui_test/src/comments.rs index 193cda68b9aaa..64f999f541010 100644 --- a/ui_test/src/comments.rs +++ b/ui_test/src/comments.rs @@ -39,6 +39,8 @@ impl Comments { Self::parse(path, &content) } + /// Parse comments in `content`. + /// `path` is only used to emit diagnostics if parsing fails. pub fn parse(path: &Path, content: &str) -> Self { let mut this = Self::default(); let error_pattern_regex = From 25b7a12625f65229b924adb9f4a9b431da873ed1 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 25 May 2022 17:58:45 +0000 Subject: [PATCH 3114/3747] Properly name a test --- ui_test/tests/comment_parser.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui_test/tests/comment_parser.rs b/ui_test/tests/comment_parser.rs index ee1382a6c7886..a9e19cbb9c5ac 100644 --- a/ui_test/tests/comment_parser.rs +++ b/ui_test/tests/comment_parser.rs @@ -3,7 +3,7 @@ use std::path::Path; use ui_test::Comments; #[test] -fn issue_2156() { +fn parse_simple_comment() { let s = r" use std::mem; From a51ae9fb2c9bbfa6abb5eafb66d393afd00933e7 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 25 May 2022 18:24:55 +0000 Subject: [PATCH 3115/3747] Use unit tests to keep private things private --- ui_test/src/comments.rs | 3 +++ .../{tests/comment_parser.rs => src/comments/tests.rs} | 2 +- ui_test/src/lib.rs | 8 +++++--- ui_test/{tests/check_annotations.rs => src/tests.rs} | 2 +- 4 files changed, 10 insertions(+), 5 deletions(-) rename ui_test/{tests/comment_parser.rs => src/comments/tests.rs} (96%) rename ui_test/{tests/check_annotations.rs => src/tests.rs} (95%) diff --git a/ui_test/src/comments.rs b/ui_test/src/comments.rs index 64f999f541010..e83e84b22a145 100644 --- a/ui_test/src/comments.rs +++ b/ui_test/src/comments.rs @@ -2,6 +2,9 @@ use std::path::Path; use regex::Regex; +#[cfg(test)] +mod tests; + /// This crate supports various magic comments that get parsed as file-specific /// configuration values. This struct parses them all in one go and then they /// get processed by their respective use sites. diff --git a/ui_test/tests/comment_parser.rs b/ui_test/src/comments/tests.rs similarity index 96% rename from ui_test/tests/comment_parser.rs rename to ui_test/src/comments/tests.rs index a9e19cbb9c5ac..2bcaaa70a4296 100644 --- a/ui_test/tests/comment_parser.rs +++ b/ui_test/src/comments/tests.rs @@ -1,6 +1,6 @@ use std::path::Path; -use ui_test::Comments; +use super::Comments; #[test] fn parse_simple_comment() { diff --git a/ui_test/src/lib.rs b/ui_test/src/lib.rs index ba1f874413d80..4a3014713b2ae 100644 --- a/ui_test/src/lib.rs +++ b/ui_test/src/lib.rs @@ -12,6 +12,8 @@ use regex::Regex; pub use crate::comments::Comments; mod comments; +#[cfg(test)] +mod tests; #[derive(Debug)] pub struct Config { @@ -171,7 +173,7 @@ pub fn run_tests(config: Config) { } #[derive(Debug)] -pub enum Error { +enum Error { /// Got an invalid exit status for the given mode. ExitStatus(Mode, ExitStatus), PatternNotFound { @@ -191,7 +193,7 @@ pub enum Error { }, } -pub type Errors = Vec; +type Errors = Vec; fn run_test( path: &Path, @@ -249,7 +251,7 @@ fn run_test( (miri, errors) } -pub fn check_annotations( +fn check_annotations( unnormalized_stderr: &[u8], errors: &mut Errors, config: &Config, diff --git a/ui_test/tests/check_annotations.rs b/ui_test/src/tests.rs similarity index 95% rename from ui_test/tests/check_annotations.rs rename to ui_test/src/tests.rs index 4735fe1fa0493..841f790b95b56 100644 --- a/ui_test/tests/check_annotations.rs +++ b/ui_test/src/tests.rs @@ -1,6 +1,6 @@ use std::path::{Path, PathBuf}; -use ui_test::{check_annotations, Comments, Config, Error, Mode, OutputConflictHandling}; +use super::{check_annotations, Comments, Config, Error, Mode, OutputConflictHandling}; fn config() -> Config { Config { From 6b18cf0e20607cda3716be299965f202898d1437 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 25 May 2022 18:25:45 +0000 Subject: [PATCH 3116/3747] Self-descriptive verbosity --- ui_test/src/comments/tests.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui_test/src/comments/tests.rs b/ui_test/src/comments/tests.rs index 2bcaaa70a4296..0140fdf4a9c6e 100644 --- a/ui_test/src/comments/tests.rs +++ b/ui_test/src/comments/tests.rs @@ -12,7 +12,7 @@ fn main() { } "; let comments = Comments::parse(Path::new(""), s); - println!("{:#?}", comments); + println!("parsed comments: {:#?}", comments); assert_eq!(comments.error_matches[0].definition_line, 4); assert_eq!(comments.error_matches[0].revision, None); assert_eq!( From 10e06be15a3524e30eb1b8c896b748c0e94b74ff Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Fri, 27 May 2022 11:35:26 +0000 Subject: [PATCH 3117/3747] Don't export private things --- ui_test/src/comments.rs | 8 ++++---- ui_test/src/lib.rs | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/ui_test/src/comments.rs b/ui_test/src/comments.rs index e83e84b22a145..e6e45de4160e0 100644 --- a/ui_test/src/comments.rs +++ b/ui_test/src/comments.rs @@ -9,7 +9,7 @@ mod tests; /// configuration values. This struct parses them all in one go and then they /// get processed by their respective use sites. #[derive(Default, Debug)] -pub struct Comments { +pub(crate) struct Comments { /// List of revision names to execute. Can only be speicified once pub revisions: Option>, /// Don't run this test if any of these filters apply @@ -30,21 +30,21 @@ pub struct Comments { } #[derive(Debug)] -pub struct ErrorMatch { +pub(crate) struct ErrorMatch { pub matched: String, pub revision: Option, pub definition_line: usize, } impl Comments { - pub fn parse_file(path: &Path) -> Self { + pub(crate) fn parse_file(path: &Path) -> Self { let content = std::fs::read_to_string(path).unwrap(); Self::parse(path, &content) } /// Parse comments in `content`. /// `path` is only used to emit diagnostics if parsing fails. - pub fn parse(path: &Path, content: &str) -> Self { + pub(crate) fn parse(path: &Path, content: &str) -> Self { let mut this = Self::default(); let error_pattern_regex = Regex::new(r"//(\[(?P[^\]]+)\])?~[|^]*\s*(ERROR|HELP|WARN)?:?(?P.*)") diff --git a/ui_test/src/lib.rs b/ui_test/src/lib.rs index 4a3014713b2ae..dd5a1d062434f 100644 --- a/ui_test/src/lib.rs +++ b/ui_test/src/lib.rs @@ -9,7 +9,7 @@ use comments::ErrorMatch; use crossbeam::queue::SegQueue; use regex::Regex; -pub use crate::comments::Comments; +use crate::comments::Comments; mod comments; #[cfg(test)] From 1b7e278922267792a8a99067e7e9d387f45c0e3f Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Fri, 27 May 2022 11:43:14 +0000 Subject: [PATCH 3118/3747] Reintroduce path filters --- miri | 4 ++-- tests/compiletest.rs | 3 +++ ui_test/src/lib.rs | 13 +++++++++++++ ui_test/src/tests.rs | 1 + 4 files changed, 19 insertions(+), 2 deletions(-) diff --git a/miri b/miri index 3846eb795a4f3..9c4eeb527580d 100755 --- a/miri +++ b/miri @@ -133,9 +133,9 @@ test|test-debug|bless|bless-debug) ;; esac # Then test, and let caller control flags. - # Only in root project as `cargo-miri` has no tests. + # Only in root project and ui_test as `cargo-miri` has no tests. cargo test $CARGO_BUILD_FLAGS "$@" - cargo test --manifest-path ui_test/Cargo.toml + cargo test --manifest-path ui_test/Cargo.toml "$@" ;; run|run-debug) # Scan for "--target" to set the "MIRI_TEST_TARGET" env var so diff --git a/tests/compiletest.rs b/tests/compiletest.rs index 9ffc4744eb858..4be658e86cba4 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -47,6 +47,8 @@ fn run_tests(mode: Mode, path: &str, target: Option) { (true, true) => panic!("cannot use MIRI_BLESS and MIRI_SKIP_UI_CHECKS at the same time"), }; + let path_filter = std::env::args().skip(1).next(); + let config = Config { args: flags, target, @@ -54,6 +56,7 @@ fn run_tests(mode: Mode, path: &str, target: Option) { stdout_filters: STDOUT.clone(), root_dir: PathBuf::from(path), mode, + path_filter, program: miri_path(), output_conflict_handling, }; diff --git a/ui_test/src/lib.rs b/ui_test/src/lib.rs index dd5a1d062434f..81560db6dff76 100644 --- a/ui_test/src/lib.rs +++ b/ui_test/src/lib.rs @@ -30,6 +30,8 @@ pub struct Config { pub mode: Mode, pub program: PathBuf, pub output_conflict_handling: OutputConflictHandling, + /// Only run tests with this string in their path/name + pub path_filter: Option, } #[derive(Debug)] @@ -75,6 +77,17 @@ pub fn run_tests(config: Config) { if !path.extension().map(|ext| ext == "rs").unwrap_or(false) { continue; } + if let Some(path_filter) = &config.path_filter { + if !path.display().to_string().contains(path_filter) { + ignored.fetch_add(1, Ordering::Relaxed); + eprintln!( + "{} .. {}", + path.display(), + "ignored (command line filter)".yellow() + ); + continue; + } + } let comments = Comments::parse_file(&path); // Ignore file if only/ignore rules do (not) apply if ignore_file(&comments, &target) { diff --git a/ui_test/src/tests.rs b/ui_test/src/tests.rs index 841f790b95b56..5485e6b4f26b3 100644 --- a/ui_test/src/tests.rs +++ b/ui_test/src/tests.rs @@ -10,6 +10,7 @@ fn config() -> Config { stdout_filters: vec![], root_dir: PathBuf::from("."), mode: Mode::Fail, + path_filter: None, program: PathBuf::from("cake"), output_conflict_handling: OutputConflictHandling::Error, } From 740574206b1a9d494ec8cff4fc37621944e472f5 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Fri, 27 May 2022 14:24:38 +0000 Subject: [PATCH 3119/3747] Commit our ui test crate's cargo lockfile --- ui_test/.gitignore | 1 - ui_test/Cargo.lock | 304 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 304 insertions(+), 1 deletion(-) delete mode 100644 ui_test/.gitignore create mode 100644 ui_test/Cargo.lock diff --git a/ui_test/.gitignore b/ui_test/.gitignore deleted file mode 100644 index 03314f77b5aa4..0000000000000 --- a/ui_test/.gitignore +++ /dev/null @@ -1 +0,0 @@ -Cargo.lock diff --git a/ui_test/Cargo.lock b/ui_test/Cargo.lock new file mode 100644 index 0000000000000..185af43ac0b41 --- /dev/null +++ b/ui_test/Cargo.lock @@ -0,0 +1,304 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "aho-corasick" +version = "0.7.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f" +dependencies = [ + "memchr", +] + +[[package]] +name = "ansi_term" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2" +dependencies = [ + "winapi", +] + +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi", + "libc", + "winapi", +] + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "colored" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3616f750b84d8f0de8a58bda93e08e2a81ad3f523089b05f1dffecab48c6cbd" +dependencies = [ + "atty", + "lazy_static", + "winapi", +] + +[[package]] +name = "crossbeam" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ae5588f6b3c3cb05239e90bd110f257254aecd01e4635400391aeae07497845" +dependencies = [ + "cfg-if", + "crossbeam-channel", + "crossbeam-deque", + "crossbeam-epoch", + "crossbeam-queue", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-channel" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5aaa7bd5fb665c6864b5f963dd9097905c54125909c7aa94c9e18507cdbe6c53" +dependencies = [ + "cfg-if", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6455c0ca19f0d2fbf751b908d5c55c1f5cbc65e03c4225427254b46890bdde1e" +dependencies = [ + "cfg-if", + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1145cf131a2c6ba0615079ab6a638f7e1973ac9c2634fcbeaaad6114246efe8c" +dependencies = [ + "autocfg", + "cfg-if", + "crossbeam-utils", + "lazy_static", + "memoffset", + "scopeguard", +] + +[[package]] +name = "crossbeam-queue" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f25d8400f4a7a5778f0e4e52384a48cbd9b5c495d110786187fc750075277a2" +dependencies = [ + "cfg-if", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bf124c720b7686e3c2663cf54062ab0f68a88af2fb6a030e87e30bf721fcb38" +dependencies = [ + "cfg-if", + "lazy_static", +] + +[[package]] +name = "ctor" +version = "0.1.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f877be4f7c9f246b183111634f75baa039715e3f46ce860677d3b19a69fb229c" +dependencies = [ + "quote", + "syn", +] + +[[package]] +name = "diff" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e25ea47919b1560c4e3b7fe0aaab9becf5b84a10325ddf7db0f0ba5e1026499" + +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "libc" +version = "0.2.126" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836" + +[[package]] +name = "memchr" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" + +[[package]] +name = "memoffset" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce" +dependencies = [ + "autocfg", +] + +[[package]] +name = "output_vt100" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "628223faebab4e3e40667ee0b2336d34a5b960ff60ea743ddfdbcf7770bcfb66" +dependencies = [ + "winapi", +] + +[[package]] +name = "pretty_assertions" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c89f989ac94207d048d92db058e4f6ec7342b0971fc58d1271ca148b799b3563" +dependencies = [ + "ansi_term", + "ctor", + "diff", + "output_vt100", +] + +[[package]] +name = "proc-macro2" +version = "1.0.39" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c54b25569025b7fc9651de43004ae593a75ad88543b17178aa5e1b9c4f15f56f" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1feb54ed693b93a84e14094943b84b7c4eae204c512b7ccb95ab0c66d278ad1" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "regex" +version = "1.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d83f127d94bdbcda4c8cc2e50f6f84f4b611f69c902699ca385a39c3a75f9ff1" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.6.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49b3de9ec5dc0a3417da371aab17d729997c15010e7fd24ff707773a33bddb64" + +[[package]] +name = "rustc_version" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +dependencies = [ + "semver", +] + +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + +[[package]] +name = "semver" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8cb243bdfdb5936c8dc3c45762a19d12ab4550cdc753bc247637d4ec35a040fd" + +[[package]] +name = "syn" +version = "1.0.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbaf6116ab8924f39d52792136fb74fd60a80194cf1b1c6ffa6453eef1c3f942" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "ui_test" +version = "0.1.0" +dependencies = [ + "colored", + "crossbeam", + "lazy_static", + "pretty_assertions", + "regex", + "rustc_version", +] + +[[package]] +name = "unicode-ident" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d22af068fba1eb5edcb4aea19d382b2a3deb4c8f9d475c589b6ada9e0fd493ee" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" From 12261474140d20f6b07613de7c3a3b4210fd5a2e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 28 May 2022 18:08:13 +0200 Subject: [PATCH 3120/3747] rustup --- README.md | 4 +++- rust-version | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 9248576b3c2af..824a8d3e328a4 100644 --- a/README.md +++ b/README.md @@ -262,7 +262,9 @@ environment variable. We first document the most relevant and most commonly used * `-Zmiri-compare-exchange-weak-failure-rate=` changes the failure rate of `compare_exchange_weak` operations. The default is `0.8` (so 4 out of 5 weak ops will fail). You can change it to any value between `0.0` and `1.0`, where `1.0` means it - will always fail and `0.0` means it will never fail. + will always fail and `0.0` means it will never fail. Note than setting it to + `1.0` will likely cause hangs, since it means programs using + `compare_exchange_weak` cannot make progress. * `-Zmiri-disable-isolation` disables host isolation. As a consequence, the program has access to host resources such as environment variables, file systems, and randomness. diff --git a/rust-version b/rust-version index f4df767fc22f4..0024b676d7751 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -b2eba058e6e1c698723e47074561a30b50b5fa7a +68314177e70017c08f6cdf295631bb508f9f85bc From 424841817a47030191cd64f1177e242d8c450983 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 29 May 2022 08:25:36 +0200 Subject: [PATCH 3121/3747] disable optimized tests for now --- ci.sh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ci.sh b/ci.sh index d435e0e2a210b..bdca26fd04913 100755 --- a/ci.sh +++ b/ci.sh @@ -25,7 +25,9 @@ function run_tests { # Only for host architecture: tests with optimizations (`-O` is what cargo passes, but crank MIR # optimizations up all the way). # Optimizations change diagnostics (mostly backtraces), so we don't check them - MIRIFLAGS="-O -Zmir-opt-level=4" MIRI_SKIP_UI_CHECKS=1 ./miri test --locked + #FIXME(#2155): we want to only run the pass and panic tests here, not the fail tests. + #MIRIFLAGS="-O -Zmir-opt-level=4" MIRI_SKIP_UI_CHECKS=1 ./miri test --locked + true fi # On Windows, there is always "python", not "python3" or "python2". From 7cd5fc3de327b9db96918cc895676f2d94c0a44d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 29 May 2022 14:06:35 +0200 Subject: [PATCH 3122/3747] rustup --- rust-version | 2 +- src/helpers.rs | 2 +- src/shims/dlsym.rs | 2 +- src/shims/posix/dlsym.rs | 2 +- src/shims/posix/linux/dlsym.rs | 2 +- src/shims/posix/macos/dlsym.rs | 2 +- src/shims/windows/dlsym.rs | 2 +- src/stacked_borrows.rs | 4 ++-- src/stacked_borrows/diagnostics.rs | 8 ++++---- 9 files changed, 13 insertions(+), 13 deletions(-) diff --git a/rust-version b/rust-version index 0024b676d7751..8da4cbec7ff28 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -68314177e70017c08f6cdf295631bb508f9f85bc +0f06824013761ed6829887019033f1001e68f623 diff --git a/src/helpers.rs b/src/helpers.rs index 24c471a8b0ba8..5a76e15465c46 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -849,7 +849,7 @@ where throw_ub_format!("incorrect number of arguments: got {}, expected {}", args.len(), N) } -pub fn isolation_abort_error(name: &str) -> InterpResult<'static> { +pub fn isolation_abort_error<'tcx>(name: &str) -> InterpResult<'tcx> { throw_machine_stop!(TerminationInfo::UnsupportedInIsolation(format!( "{} not available when isolation is enabled", name, diff --git a/src/shims/dlsym.rs b/src/shims/dlsym.rs index d83a309c3e1f7..05296d3a4eb70 100644 --- a/src/shims/dlsym.rs +++ b/src/shims/dlsym.rs @@ -15,7 +15,7 @@ pub enum Dlsym { impl Dlsym { // Returns an error for unsupported symbols, and None if this symbol // should become a NULL pointer (pretend it does not exist). - pub fn from_str(name: &[u8], target_os: &str) -> InterpResult<'static, Option> { + pub fn from_str<'tcx>(name: &[u8], target_os: &str) -> InterpResult<'tcx, Option> { let name = &*String::from_utf8_lossy(name); Ok(match target_os { "linux" | "macos" => posix::Dlsym::from_str(name, target_os)?.map(Dlsym::Posix), diff --git a/src/shims/posix/dlsym.rs b/src/shims/posix/dlsym.rs index 0ea441e00e9ae..339110467c73e 100644 --- a/src/shims/posix/dlsym.rs +++ b/src/shims/posix/dlsym.rs @@ -14,7 +14,7 @@ pub enum Dlsym { impl Dlsym { // Returns an error for unsupported symbols, and None if this symbol // should become a NULL pointer (pretend it does not exist). - pub fn from_str(name: &str, target_os: &str) -> InterpResult<'static, Option> { + pub fn from_str<'tcx>(name: &str, target_os: &str) -> InterpResult<'tcx, Option> { Ok(match target_os { "linux" => linux::Dlsym::from_str(name)?.map(Dlsym::Linux), "macos" => macos::Dlsym::from_str(name)?.map(Dlsym::MacOs), diff --git a/src/shims/posix/linux/dlsym.rs b/src/shims/posix/linux/dlsym.rs index a2d6570fe8d64..72e8c7f16f853 100644 --- a/src/shims/posix/linux/dlsym.rs +++ b/src/shims/posix/linux/dlsym.rs @@ -8,7 +8,7 @@ pub enum Dlsym {} impl Dlsym { // Returns an error for unsupported symbols, and None if this symbol // should become a NULL pointer (pretend it does not exist). - pub fn from_str(name: &str) -> InterpResult<'static, Option> { + pub fn from_str<'tcx>(name: &str) -> InterpResult<'tcx, Option> { Ok(match &*name { "__pthread_get_minstack" => None, "getrandom" => None, // std falls back to syscall(SYS_getrandom, ...) when this is NULL. diff --git a/src/shims/posix/macos/dlsym.rs b/src/shims/posix/macos/dlsym.rs index 9369548992e53..2e97b7918e96b 100644 --- a/src/shims/posix/macos/dlsym.rs +++ b/src/shims/posix/macos/dlsym.rs @@ -14,7 +14,7 @@ pub enum Dlsym { impl Dlsym { // Returns an error for unsupported symbols, and None if this symbol // should become a NULL pointer (pretend it does not exist). - pub fn from_str(name: &str) -> InterpResult<'static, Option> { + pub fn from_str<'tcx>(name: &str) -> InterpResult<'tcx, Option> { Ok(match name { "getentropy" => Some(Dlsym::getentropy), _ => throw_unsup_format!("unsupported macOS dlsym: {}", name), diff --git a/src/shims/windows/dlsym.rs b/src/shims/windows/dlsym.rs index b5408e492ce9c..fb0c334b3d938 100644 --- a/src/shims/windows/dlsym.rs +++ b/src/shims/windows/dlsym.rs @@ -15,7 +15,7 @@ pub enum Dlsym { impl Dlsym { // Returns an error for unsupported symbols, and None if this symbol // should become a NULL pointer (pretend it does not exist). - pub fn from_str(name: &str) -> InterpResult<'static, Option> { + pub fn from_str<'tcx>(name: &str) -> InterpResult<'tcx, Option> { Ok(match name { "GetSystemTimePreciseAsFileTime" => None, "NtWriteFile" => Some(Dlsym::NtWriteFile), diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 30a9cc265dce2..d492a565a728f 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -227,11 +227,11 @@ impl GlobalStateInner { } /// Error reporting -pub fn err_sb_ub( +pub fn err_sb_ub<'tcx>( msg: String, help: Option, history: Option, -) -> InterpError<'static> { +) -> InterpError<'tcx> { err_machine_stop!(TerminationInfo::ExperimentalUb { msg, help, diff --git a/src/stacked_borrows/diagnostics.rs b/src/stacked_borrows/diagnostics.rs index f3692cdeeb043..5400e9abe5038 100644 --- a/src/stacked_borrows/diagnostics.rs +++ b/src/stacked_borrows/diagnostics.rs @@ -195,7 +195,7 @@ impl AllocHistory { } /// Report a descriptive error when `new` could not be granted from `derived_from`. - pub fn grant_error( + pub fn grant_error<'tcx>( &self, derived_from: SbTag, new: Item, @@ -203,7 +203,7 @@ impl AllocHistory { alloc_range: AllocRange, error_offset: Size, stack: &Stack, - ) -> InterpError<'static> { + ) -> InterpError<'tcx> { let action = format!( "trying to reborrow {:?} for {:?} permission at {}[{:#x}]", derived_from, @@ -219,7 +219,7 @@ impl AllocHistory { } /// Report a descriptive error when `access` is not permitted based on `tag`. - pub fn access_error( + pub fn access_error<'tcx>( &self, access: AccessKind, tag: SbTag, @@ -227,7 +227,7 @@ impl AllocHistory { alloc_range: AllocRange, error_offset: Size, stack: &Stack, - ) -> InterpError<'static> { + ) -> InterpError<'tcx> { let action = format!( "attempting a {} using {:?} at {}[{:#x}]", access, From 9a1475dbe2f19eb01eaa9a02b4fd93063713b648 Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Sun, 22 May 2022 19:39:09 -0400 Subject: [PATCH 3123/3747] Save a created event for zero-size reborrows --- src/stacked_borrows.rs | 21 ++++++++++++++++++- .../stacked_borrows/zst_slice.stderr | 6 +++++- 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index d492a565a728f..2eba35118388e 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -706,7 +706,26 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); if size == Size::ZERO { - // Nothing to do for zero-sized accesses. + // Don't update any stacks for a zero-sized access; borrow stacks are per-byte and this + // touches no bytes so there is no stack to put this tag in. + // However, if the pointer for this operation points at a real allocation we still + // record where it was created so that we can issue a helpful diagnostic if there is an + // attempt to use it for a non-zero-sized access. + // Dangling slices are a common case here; it's valid to get their length but with raw + // pointer tagging for example all calls to get_unchecked on them are invalid. + if let Ok((alloc_id, base_offset, orig_tag)) = this.ptr_try_get_alloc_id(place.ptr) { + let extra = this.get_alloc_extra(alloc_id)?; + let stacked_borrows = + extra.stacked_borrows.as_ref().expect("we should have Stacked Borrows data"); + let mut alloc_history = stacked_borrows.history.borrow_mut(); + alloc_history.log_creation( + Some(orig_tag), + new_tag, + alloc_range(base_offset, Size::ZERO), + &mut this.machine.current_span(), + ); + } + trace!( "reborrow of size 0: {} reference {:?} derived from {:?} (pointee {})", kind, diff --git a/tests/compile-fail/stacked_borrows/zst_slice.stderr b/tests/compile-fail/stacked_borrows/zst_slice.stderr index f9d8b024e9861..c6b4dc16b797b 100644 --- a/tests/compile-fail/stacked_borrows/zst_slice.stderr +++ b/tests/compile-fail/stacked_borrows/zst_slice.stderr @@ -2,7 +2,11 @@ error: Undefined Behavior: trying to reborrow for SharedReadOnly permissio | = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information - +help: was created by a retag at offsets [0x0..0x0] + --> $DIR/zst_slice.rs:LL:CC + | +LL | assert_eq!(*s.get_unchecked(1), 2); + | ^^^^^^^^^^^^^^^^^^ = note: inside `core::slice::::get_unchecked::` at rustc_src/src/slice/mod.rs:LL:CC note: inside `main` at $DIR/zst_slice.rs:LL:CC --> $DIR/zst_slice.rs:LL:CC From 3832227734d2ac87254a7cd057f4280f443563e5 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Mon, 30 May 2022 07:26:47 +0000 Subject: [PATCH 3124/3747] Forward CARGO_BUILD_FLAGS to ui_test test suite --- miri | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/miri b/miri index 9c4eeb527580d..352aed530b191 100755 --- a/miri +++ b/miri @@ -135,7 +135,7 @@ test|test-debug|bless|bless-debug) # Then test, and let caller control flags. # Only in root project and ui_test as `cargo-miri` has no tests. cargo test $CARGO_BUILD_FLAGS "$@" - cargo test --manifest-path ui_test/Cargo.toml "$@" + cargo test $CARGO_BUILD_FLAGS --manifest-path ui_test/Cargo.toml "$@" ;; run|run-debug) # Scan for "--target" to set the "MIRI_TEST_TARGET" env var so From e37dfa6d91f65f4b97232bea1d587591cb2982e5 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 30 May 2022 10:27:41 +0200 Subject: [PATCH 3125/3747] ui_test: support multiple filters --- tests/compiletest.rs | 5 +++-- ui_test/src/lib.rs | 11 ++++++----- ui_test/src/tests.rs | 2 +- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/tests/compiletest.rs b/tests/compiletest.rs index 4be658e86cba4..307272264275f 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -47,7 +47,8 @@ fn run_tests(mode: Mode, path: &str, target: Option) { (true, true) => panic!("cannot use MIRI_BLESS and MIRI_SKIP_UI_CHECKS at the same time"), }; - let path_filter = std::env::args().skip(1).next(); + // Pass on all arguments as filters. + let path_filter = std::env::args().skip(1); let config = Config { args: flags, @@ -56,7 +57,7 @@ fn run_tests(mode: Mode, path: &str, target: Option) { stdout_filters: STDOUT.clone(), root_dir: PathBuf::from(path), mode, - path_filter, + path_filter: path_filter.collect(), program: miri_path(), output_conflict_handling, }; diff --git a/ui_test/src/lib.rs b/ui_test/src/lib.rs index 81560db6dff76..866a9fe46ace7 100644 --- a/ui_test/src/lib.rs +++ b/ui_test/src/lib.rs @@ -30,8 +30,8 @@ pub struct Config { pub mode: Mode, pub program: PathBuf, pub output_conflict_handling: OutputConflictHandling, - /// Only run tests with this string in their path/name - pub path_filter: Option, + /// Only run tests with one of these strings in their path/name + pub path_filter: Vec, } #[derive(Debug)] @@ -77,12 +77,13 @@ pub fn run_tests(config: Config) { if !path.extension().map(|ext| ext == "rs").unwrap_or(false) { continue; } - if let Some(path_filter) = &config.path_filter { - if !path.display().to_string().contains(path_filter) { + if !config.path_filter.is_empty() { + let path_display = path.display().to_string(); + if !config.path_filter.iter().any(|filter| path_display.contains(filter)) { ignored.fetch_add(1, Ordering::Relaxed); eprintln!( "{} .. {}", - path.display(), + path_display, "ignored (command line filter)".yellow() ); continue; diff --git a/ui_test/src/tests.rs b/ui_test/src/tests.rs index 5485e6b4f26b3..b2544e68ada10 100644 --- a/ui_test/src/tests.rs +++ b/ui_test/src/tests.rs @@ -10,7 +10,7 @@ fn config() -> Config { stdout_filters: vec![], root_dir: PathBuf::from("."), mode: Mode::Fail, - path_filter: None, + path_filter: vec![], program: PathBuf::from("cake"), output_conflict_handling: OutputConflictHandling::Error, } From 8694e656bee538fb3d1db0bf4fb6625943cd4087 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 30 May 2022 10:28:07 +0200 Subject: [PATCH 3126/3747] test mir-opt-level=4 again on run tests --- ci.sh | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/ci.sh b/ci.sh index bdca26fd04913..080bd9204db54 100755 --- a/ci.sh +++ b/ci.sh @@ -26,8 +26,7 @@ function run_tests { # optimizations up all the way). # Optimizations change diagnostics (mostly backtraces), so we don't check them #FIXME(#2155): we want to only run the pass and panic tests here, not the fail tests. - #MIRIFLAGS="-O -Zmir-opt-level=4" MIRI_SKIP_UI_CHECKS=1 ./miri test --locked - true + MIRIFLAGS="-O -Zmir-opt-level=4" MIRI_SKIP_UI_CHECKS=1 ./miri test --locked -- tests/{run-pass,run-fail} fi # On Windows, there is always "python", not "python3" or "python2". From 4e91c2e368c7e96b85c12cef61363eb9eccac621 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 30 May 2022 10:29:02 +0200 Subject: [PATCH 3127/3747] ui_test: printing more consistent with compiletest distinguish "ignored" from "filtered out" --- ui_test/src/lib.rs | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/ui_test/src/lib.rs b/ui_test/src/lib.rs index 866a9fe46ace7..b7488d817a6c3 100644 --- a/ui_test/src/lib.rs +++ b/ui_test/src/lib.rs @@ -61,6 +61,7 @@ pub fn run_tests(config: Config) { let failures = Mutex::new(vec![]); let succeeded = AtomicUsize::default(); let ignored = AtomicUsize::default(); + let filtered = AtomicUsize::default(); crossbeam::scope(|s| { for _ in 0..std::thread::available_parallelism().unwrap().get() { @@ -80,12 +81,7 @@ pub fn run_tests(config: Config) { if !config.path_filter.is_empty() { let path_display = path.display().to_string(); if !config.path_filter.iter().any(|filter| path_display.contains(filter)) { - ignored.fetch_add(1, Ordering::Relaxed); - eprintln!( - "{} .. {}", - path_display, - "ignored (command line filter)".yellow() - ); + filtered.fetch_add(1, Ordering::Relaxed); continue; } } @@ -93,7 +89,7 @@ pub fn run_tests(config: Config) { // Ignore file if only/ignore rules do (not) apply if ignore_file(&comments, &target) { ignored.fetch_add(1, Ordering::Relaxed); - eprintln!("{} .. {}", path.display(), "ignored".yellow()); + eprintln!("{} ... {}", path.display(), "ignored".yellow()); continue; } // Run the test for all revisions @@ -126,6 +122,7 @@ pub fn run_tests(config: Config) { let failures = failures.into_inner().unwrap(); let succeeded = succeeded.load(Ordering::Relaxed); let ignored = ignored.load(Ordering::Relaxed); + let filtered = filtered.load(Ordering::Relaxed); if !failures.is_empty() { for (path, miri, revision, errors) in &failures { eprintln!(); @@ -169,19 +166,22 @@ pub fn run_tests(config: Config) { } } eprintln!( - "{} tests failed, {} tests passed, {} ignored", + "test result: {}. {} tests failed, {} tests passed, {} ignored, {} filtered out", + "FAIL".red(), failures.len().to_string().red().bold(), succeeded.to_string().green(), - ignored.to_string().yellow() + ignored.to_string().yellow(), + filtered.to_string().yellow(), ); std::process::exit(1); } eprintln!(); eprintln!( - "test result: {}. {} tests passed, {} ignored", + "test result: {}. {} tests passed, {} ignored, {} filtered out", "ok".green(), succeeded.to_string().green(), - ignored.to_string().yellow() + ignored.to_string().yellow(), + filtered.to_string().yellow(), ); eprintln!(); } From 86e53f41b099f48e25fe53aa2d13101f17fae049 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 30 May 2022 10:31:12 +0200 Subject: [PATCH 3128/3747] print reason for ignoring --- ui_test/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui_test/src/lib.rs b/ui_test/src/lib.rs index b7488d817a6c3..305b4721e9649 100644 --- a/ui_test/src/lib.rs +++ b/ui_test/src/lib.rs @@ -89,7 +89,7 @@ pub fn run_tests(config: Config) { // Ignore file if only/ignore rules do (not) apply if ignore_file(&comments, &target) { ignored.fetch_add(1, Ordering::Relaxed); - eprintln!("{} ... {}", path.display(), "ignored".yellow()); + eprintln!("{} ... {}", path.display(), "ignored (in-test comment)".yellow()); continue; } // Run the test for all revisions From b9d79a25baa9e2fefa5ee56a93517a7f96904c9c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 30 May 2022 12:20:12 +0200 Subject: [PATCH 3129/3747] also 'check' the test suite --- miri | 2 +- ui_test/src/lib.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/miri b/miri index 352aed530b191..5c9cb81885c92 100755 --- a/miri +++ b/miri @@ -115,7 +115,7 @@ install|install-debug) ;; check|check-debug) # Check, and let caller control flags. - cargo check $CARGO_BUILD_FLAGS --manifest-path "$MIRIDIR"/Cargo.toml "$@" + cargo check $CARGO_BUILD_FLAGS --manifest-path "$MIRIDIR"/Cargo.toml --all-targets "$@" cargo check $CARGO_BUILD_FLAGS --manifest-path "$MIRIDIR"/cargo-miri/Cargo.toml "$@" ;; build|build-debug) diff --git a/ui_test/src/lib.rs b/ui_test/src/lib.rs index 305b4721e9649..90c475d4bed5f 100644 --- a/ui_test/src/lib.rs +++ b/ui_test/src/lib.rs @@ -98,7 +98,7 @@ pub fn run_tests(config: Config) { { let (m, errors) = run_test(&path, &config, &target, &revision, &comments); - // Using `format` to prevent messages from threads from getting intermingled. + // Using a single `eprintln!` to prevent messages from threads from getting intermingled. let mut msg = format!("{} ", path.display()); if !revision.is_empty() { write!(msg, "(revision `{revision}`) ").unwrap(); From 80bf204848eb2c97effa717e8e4f876f6545d55f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 30 May 2022 12:28:13 +0200 Subject: [PATCH 3130/3747] don't configure the same regex twice --- tests/compiletest.rs | 2 -- ui_test/src/lib.rs | 20 ++++++++++---------- ui_test/src/tests.rs | 4 ++-- 3 files changed, 12 insertions(+), 14 deletions(-) diff --git a/tests/compiletest.rs b/tests/compiletest.rs index 307272264275f..937ae0d9d7de2 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -106,8 +106,6 @@ regexes! { r"\\" => "/", // erase platform file paths "sys/[a-z]+/" => "sys/PLATFORM/", - // erase error annotations in tests - r"\s*//~.*" => "", } fn ui(mode: Mode, path: &str) { diff --git a/ui_test/src/lib.rs b/ui_test/src/lib.rs index 90c475d4bed5f..648efb1f47146 100644 --- a/ui_test/src/lib.rs +++ b/ui_test/src/lib.rs @@ -231,6 +231,11 @@ fn run_test( } let output = miri.output().expect("could not execute miri"); let mut errors = config.mode.ok(output.status); + // Always remove annotation comments from stderr. + let annotations = Regex::new(r"\s*//~.*").unwrap(); + let stderr = std::str::from_utf8(&output.stderr).unwrap(); + let stderr = annotations.replace_all(stderr, ""); + let stdout = std::str::from_utf8(&output.stdout).unwrap(); // Check output files (if any) let revised = |extension: &str| { if revision.is_empty() { @@ -241,7 +246,7 @@ fn run_test( }; // Check output files against actual output check_output( - &output.stderr, + &stderr, path, &mut errors, revised("stderr"), @@ -251,7 +256,7 @@ fn run_test( comments, ); check_output( - &output.stdout, + &stdout, path, &mut errors, revised("stdout"), @@ -261,21 +266,17 @@ fn run_test( comments, ); // Check error annotations in the source against output - check_annotations(&output.stderr, &mut errors, config, revision, comments); + check_annotations(&stderr, &mut errors, config, revision, comments); (miri, errors) } fn check_annotations( - unnormalized_stderr: &[u8], + unnormalized_stderr: &str, errors: &mut Errors, config: &Config, revision: &str, comments: &Comments, ) { - let unnormalized_stderr = std::str::from_utf8(unnormalized_stderr).unwrap(); - // erase annotations from the stderr so they don't match themselves - let annotations = Regex::new(r"\s*//~.*").unwrap(); - let unnormalized_stderr = annotations.replace(unnormalized_stderr, ""); let mut found_annotation = false; if let Some((ref error_pattern, definition_line)) = comments.error_pattern { if !unnormalized_stderr.contains(error_pattern) { @@ -313,7 +314,7 @@ fn check_annotations( } fn check_output( - output: &[u8], + output: &str, path: &Path, errors: &mut Errors, kind: String, @@ -322,7 +323,6 @@ fn check_output( config: &Config, comments: &Comments, ) { - let output = std::str::from_utf8(&output).unwrap(); let output = normalize(path, output, filters, comments); let path = output_path(path, comments, kind, target); match config.output_conflict_handling { diff --git a/ui_test/src/tests.rs b/ui_test/src/tests.rs index b2544e68ada10..7b25eaeeafe99 100644 --- a/ui_test/src/tests.rs +++ b/ui_test/src/tests.rs @@ -42,9 +42,9 @@ LL | let _x: &i32 = unsafe { mem::transmute(16usize) }; //~ ERROR encountere note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace error: aborting due to previous error "; - check_annotations(unnormalized_stderr.as_bytes(), &mut errors, &config, "", &comments); + check_annotations(unnormalized_stderr, &mut errors, &config, "", &comments); match &errors[..] { [Error::PatternNotFound { .. }] => {} - _ => panic!("{:#?}", errors), + _ => panic!("not the expected error: {:#?}", errors), } } From 4d80880854b2ae832d9e490f0d761bbc5170c3bb Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 30 May 2022 12:32:49 +0200 Subject: [PATCH 3131/3747] fmt --- ui_test/src/lib.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/ui_test/src/lib.rs b/ui_test/src/lib.rs index 648efb1f47146..37af27dcfb1d7 100644 --- a/ui_test/src/lib.rs +++ b/ui_test/src/lib.rs @@ -89,7 +89,11 @@ pub fn run_tests(config: Config) { // Ignore file if only/ignore rules do (not) apply if ignore_file(&comments, &target) { ignored.fetch_add(1, Ordering::Relaxed); - eprintln!("{} ... {}", path.display(), "ignored (in-test comment)".yellow()); + eprintln!( + "{} ... {}", + path.display(), + "ignored (in-test comment)".yellow() + ); continue; } // Run the test for all revisions From 962957f11f456949395535037b45b98d18bbcf19 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 30 May 2022 12:56:34 +0200 Subject: [PATCH 3132/3747] make it possible to test more of ui_test --- ui_test/src/lib.rs | 34 ++++++++++++++++++++++++++++------ ui_test/src/tests.rs | 15 +++++++++------ 2 files changed, 37 insertions(+), 12 deletions(-) diff --git a/ui_test/src/lib.rs b/ui_test/src/lib.rs index 37af27dcfb1d7..6052efe02e06a 100644 --- a/ui_test/src/lib.rs +++ b/ui_test/src/lib.rs @@ -235,11 +235,34 @@ fn run_test( } let output = miri.output().expect("could not execute miri"); let mut errors = config.mode.ok(output.status); + check_test_result( + path, + config, + target, + revision, + comments, + &mut errors, + &output.stdout, + &output.stderr, + ); + (miri, errors) +} + +fn check_test_result( + path: &Path, + config: &Config, + target: &str, + revision: &str, + comments: &Comments, + errors: &mut Errors, + stdout: &[u8], + stderr: &[u8], +) { // Always remove annotation comments from stderr. let annotations = Regex::new(r"\s*//~.*").unwrap(); - let stderr = std::str::from_utf8(&output.stderr).unwrap(); + let stderr = std::str::from_utf8(stderr).unwrap(); let stderr = annotations.replace_all(stderr, ""); - let stdout = std::str::from_utf8(&output.stdout).unwrap(); + let stdout = std::str::from_utf8(stdout).unwrap(); // Check output files (if any) let revised = |extension: &str| { if revision.is_empty() { @@ -252,7 +275,7 @@ fn run_test( check_output( &stderr, path, - &mut errors, + errors, revised("stderr"), target, &config.stderr_filters, @@ -262,7 +285,7 @@ fn run_test( check_output( &stdout, path, - &mut errors, + errors, revised("stdout"), target, &config.stdout_filters, @@ -270,8 +293,7 @@ fn run_test( comments, ); // Check error annotations in the source against output - check_annotations(&stderr, &mut errors, config, revision, comments); - (miri, errors) + check_annotations(&stderr, errors, config, revision, comments); } fn check_annotations( diff --git a/ui_test/src/tests.rs b/ui_test/src/tests.rs index 7b25eaeeafe99..d0ef1195d888a 100644 --- a/ui_test/src/tests.rs +++ b/ui_test/src/tests.rs @@ -1,6 +1,6 @@ use std::path::{Path, PathBuf}; -use super::{check_annotations, Comments, Config, Error, Mode, OutputConflictHandling}; +use super::*; fn config() -> Config { Config { @@ -8,7 +8,7 @@ fn config() -> Config { target: None, stderr_filters: vec![], stdout_filters: vec![], - root_dir: PathBuf::from("."), + root_dir: PathBuf::from("$RUSTROOT"), mode: Mode::Fail, path_filter: vec![], program: PathBuf::from("cake"), @@ -25,10 +25,12 @@ fn main() { let _x: &i32 = unsafe { mem::transmute(16usize) }; //~ ERROR encountered a dangling reference (address $HEX is unallocated) } "; - let comments = Comments::parse(Path::new(""), s); + let path = Path::new("$DIR/"); + let comments = Comments::parse(&path, s); let mut errors = vec![]; let config = config(); - let unnormalized_stderr = r" + // Crucially, the intended error string *does* appear in this output, as a quote of the comment itself. + let stderr = br" error: Undefined Behavior: type validation failed: encountered a dangling reference (address 0x10 is unallocated) --> tests/compile-fail/validity/dangling_ref1.rs:6:29 | @@ -42,9 +44,10 @@ LL | let _x: &i32 = unsafe { mem::transmute(16usize) }; //~ ERROR encountere note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace error: aborting due to previous error "; - check_annotations(unnormalized_stderr, &mut errors, &config, "", &comments); + check_test_result(&path, &config, "", "", &comments, &mut errors, /*stdout*/ br"", stderr); + // The "OutputDiffers" is because we cannot open the .rs file match &errors[..] { - [Error::PatternNotFound { .. }] => {} + [Error::OutputDiffers { .. }, Error::PatternNotFound { .. }] => {} _ => panic!("not the expected error: {:#?}", errors), } } From ba9391334e8d23261eb09ce7162015993f7c2aa3 Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Sun, 29 May 2022 18:00:06 -0400 Subject: [PATCH 3133/3747] Add support for _COARSE clocks, spruce up comments --- src/shims/time.rs | 22 ++++++++++++++++++---- tests/run-pass/libc.rs | 25 +++++++++++++++++++++++++ 2 files changed, 43 insertions(+), 4 deletions(-) diff --git a/src/shims/time.rs b/src/shims/time.rs index 78bf6f59b3499..be453a429ec51 100644 --- a/src/shims/time.rs +++ b/src/shims/time.rs @@ -16,6 +16,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx clk_id_op: &OpTy<'tcx, Tag>, tp_op: &OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, i32> { + // This clock support is deliberately minimal because a lot of clock types have fiddly + // properties (is it possible for Miri to be suspended independently of the host?). If you + // have a use for another clock type, please open an issue. + let this = self.eval_context_mut(); this.assert_target_os("linux", "clock_gettime"); @@ -23,11 +27,21 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let clk_id = this.read_scalar(clk_id_op)?.to_i32()?; - let duration = if clk_id == this.eval_libc_i32("CLOCK_REALTIME")? { + // Linux has two main kinds of clocks. REALTIME clocks return the actual time since the + // Unix epoch, including effects which may cause time to move backwards such as NTP. + // Linux further distinguishes regular and "coarse" clocks, but the "coarse" version + // is just specified to be "faster and less precise", so we implement both the same way. + let absolute_clocks = + [this.eval_libc_i32("CLOCK_REALTIME")?, this.eval_libc_i32("CLOCK_REALTIME_COARSE")?]; + // The second kind is MONOTONIC clocks for which 0 is an arbitrary time point, but they are + // never allowed to go backwards. We don't need to do any additonal monotonicity + // enforcement because std::time::Instant already guarantees that it is monotonic. + let relative_clocks = + [this.eval_libc_i32("CLOCK_MONOTONIC")?, this.eval_libc_i32("CLOCK_MONOTONIC_COARSE")?]; + + let duration = if absolute_clocks.contains(&clk_id) { system_time_to_duration(&SystemTime::now())? - } else if clk_id == this.eval_libc_i32("CLOCK_MONOTONIC")? { - // Absolute time does not matter, only relative time does, so we can just - // use our own time anchor here. + } else if relative_clocks.contains(&clk_id) { Instant::now().duration_since(this.machine.time_anchor) } else { let einval = this.eval_libc("EINVAL")?; diff --git a/tests/run-pass/libc.rs b/tests/run-pass/libc.rs index fd3625639bfde..bf5ae98290118 100644 --- a/tests/run-pass/libc.rs +++ b/tests/run-pass/libc.rs @@ -230,6 +230,28 @@ fn test_thread_local_errno() { } } +/// Tests whether clock support exists at all +#[cfg(target_os = "linux")] +fn test_clocks() { + let mut tp = std::mem::MaybeUninit::::uninit(); + let is_error = unsafe { + libc::clock_gettime(libc::CLOCK_REALTIME, tp.as_mut_ptr()) + }; + assert_eq!(is_error, 0); + let is_error = unsafe { + libc::clock_gettime(libc::CLOCK_REALTIME_COARSE, tp.as_mut_ptr()) + }; + assert_eq!(is_error, 0); + let is_error = unsafe { + libc::clock_gettime(libc::CLOCK_MONOTONIC, tp.as_mut_ptr()) + }; + assert_eq!(is_error, 0); + let is_error = unsafe { + libc::clock_gettime(libc::CLOCK_MONOTONIC_COARSE, tp.as_mut_ptr()) + }; + assert_eq!(is_error, 0); +} + fn main() { #[cfg(target_os = "linux")] test_posix_fadvise(); @@ -249,4 +271,7 @@ fn main() { test_prctl_thread_name(); test_thread_local_errno(); + + #[cfg(target_os = "linux")] + test_clocks(); } From a8e457fad1fd295068bb58e43a36cfb0e996ec4e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 30 May 2022 17:47:16 -0400 Subject: [PATCH 3134/3747] use is_power_of_two where appropriate --- test-cargo-miri/tests/test.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test-cargo-miri/tests/test.rs b/test-cargo-miri/tests/test.rs index 1a8b3c72565d3..545c79db2760b 100644 --- a/test-cargo-miri/tests/test.rs +++ b/test-cargo-miri/tests/test.rs @@ -68,7 +68,7 @@ fn page_size() { // In particular, this checks that it is not 0. assert!( - page_size.next_power_of_two() == page_size, + page_size.is_power_of_two(), "page size not a power of two: {}", page_size ); From d455421edcb0c0084207d44b206ee1032913e580 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 30 May 2022 19:19:39 -0400 Subject: [PATCH 3135/3747] rustup --- rust-version | 2 +- tests/compile-fail/generator-pinned-moved.rs | 1 + tests/compile-fail/generator-pinned-moved.stderr | 4 ++-- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/rust-version b/rust-version index 8da4cbec7ff28..09a847a94fbe6 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -0f06824013761ed6829887019033f1001e68f623 +c35035cefc709abddabfb28ecc6a326458d46ce2 diff --git a/tests/compile-fail/generator-pinned-moved.rs b/tests/compile-fail/generator-pinned-moved.rs index e0ce5cb7333a2..8c8e828470043 100644 --- a/tests/compile-fail/generator-pinned-moved.rs +++ b/tests/compile-fail/generator-pinned-moved.rs @@ -1,3 +1,4 @@ +// compile-flags: -Zmiri-disable-validation #![feature(generators, generator_trait)] use std::{ diff --git a/tests/compile-fail/generator-pinned-moved.stderr b/tests/compile-fail/generator-pinned-moved.stderr index 98ccf3097c298..0ac4f8caa0788 100644 --- a/tests/compile-fail/generator-pinned-moved.stderr +++ b/tests/compile-fail/generator-pinned-moved.stderr @@ -8,12 +8,12 @@ LL | *num += 1; = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: inside closure at $DIR/generator-pinned-moved.rs:LL:CC -note: inside ` as std::iter::Iterator>::next` at $DIR/generator-pinned-moved.rs:LL:CC +note: inside ` as std::iter::Iterator>::next` at $DIR/generator-pinned-moved.rs:LL:CC --> $DIR/generator-pinned-moved.rs:LL:CC | LL | match me.resume(()) { | ^^^^^^^^^^^^^ - = note: inside `> as std::iter::Iterator>::next` at rustc_src/src/boxed.rs:LL:CC + = note: inside `> as std::iter::Iterator>::next` at rustc_src/src/boxed.rs:LL:CC note: inside `main` at $DIR/generator-pinned-moved.rs:LL:CC --> $DIR/generator-pinned-moved.rs:LL:CC | From 7fb5110160b0d931814fcc1176ac440cd19af4a8 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 30 May 2022 19:21:22 -0400 Subject: [PATCH 3136/3747] normalize away some more line numbers --- tests/compile-fail/generator-pinned-moved.stderr | 4 ++-- tests/compile-fail/panic/bad_unwind.stderr | 6 +++--- .../stacked_borrows/deallocate_against_barrier1.stderr | 2 +- .../stacked_borrows/deallocate_against_barrier2.stderr | 2 +- tests/compiletest.rs | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/tests/compile-fail/generator-pinned-moved.stderr b/tests/compile-fail/generator-pinned-moved.stderr index 0ac4f8caa0788..56bfc6092b7eb 100644 --- a/tests/compile-fail/generator-pinned-moved.stderr +++ b/tests/compile-fail/generator-pinned-moved.stderr @@ -8,12 +8,12 @@ LL | *num += 1; = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: inside closure at $DIR/generator-pinned-moved.rs:LL:CC -note: inside ` as std::iter::Iterator>::next` at $DIR/generator-pinned-moved.rs:LL:CC +note: inside ` as std::iter::Iterator>::next` at $DIR/generator-pinned-moved.rs:LL:CC --> $DIR/generator-pinned-moved.rs:LL:CC | LL | match me.resume(()) { | ^^^^^^^^^^^^^ - = note: inside `> as std::iter::Iterator>::next` at rustc_src/src/boxed.rs:LL:CC + = note: inside `> as std::iter::Iterator>::next` at rustc_src/src/boxed.rs:LL:CC note: inside `main` at $DIR/generator-pinned-moved.rs:LL:CC --> $DIR/generator-pinned-moved.rs:LL:CC | diff --git a/tests/compile-fail/panic/bad_unwind.stderr b/tests/compile-fail/panic/bad_unwind.stderr index 529f4179a8f7e..5030391bc6eae 100644 --- a/tests/compile-fail/panic/bad_unwind.stderr +++ b/tests/compile-fail/panic/bad_unwind.stderr @@ -10,9 +10,9 @@ LL | std::panic::catch_unwind(|| unwind()).unwrap_err(); = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: inside closure at $DIR/bad_unwind.rs:LL:CC - = note: inside `std::panicking::r#try::do_call::<[closure@$DIR/bad_unwind.rs:LL:CC: 13:41], ()>` at rustc_src/src/panicking.rs:LL:CC - = note: inside `std::panicking::r#try::<(), [closure@$DIR/bad_unwind.rs:LL:CC: 13:41]>` at rustc_src/src/panicking.rs:LL:CC - = note: inside `std::panic::catch_unwind::<[closure@$DIR/bad_unwind.rs:LL:CC: 13:41], ()>` at rustc_src/src/panic.rs:LL:CC + = note: inside `std::panicking::r#try::do_call::<[closure@$DIR/bad_unwind.rs:LL:CC], ()>` at rustc_src/src/panicking.rs:LL:CC + = note: inside `std::panicking::r#try::<(), [closure@$DIR/bad_unwind.rs:LL:CC]>` at rustc_src/src/panicking.rs:LL:CC + = note: inside `std::panic::catch_unwind::<[closure@$DIR/bad_unwind.rs:LL:CC], ()>` at rustc_src/src/panic.rs:LL:CC note: inside `main` at $DIR/bad_unwind.rs:LL:CC --> $DIR/bad_unwind.rs:LL:CC | diff --git a/tests/compile-fail/stacked_borrows/deallocate_against_barrier1.stderr b/tests/compile-fail/stacked_borrows/deallocate_against_barrier1.stderr index 593419fe9b377..804bb0f92af84 100644 --- a/tests/compile-fail/stacked_borrows/deallocate_against_barrier1.stderr +++ b/tests/compile-fail/stacked_borrows/deallocate_against_barrier1.stderr @@ -13,7 +13,7 @@ note: inside closure at $DIR/deallocate_against_barrier1.rs:LL:CC | LL | drop(unsafe { Box::from_raw(raw) }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: inside `<[closure@$DIR/deallocate_against_barrier1.rs:LL:CC: 12:6] as std::ops::FnOnce<(&mut i32,)>>::call_once - shim` at rustc_src/src/ops/function.rs:LL:CC + = note: inside `<[closure@$DIR/deallocate_against_barrier1.rs:LL:CC] as std::ops::FnOnce<(&mut i32,)>>::call_once - shim` at rustc_src/src/ops/function.rs:LL:CC note: inside `inner` at $DIR/deallocate_against_barrier1.rs:LL:CC --> $DIR/deallocate_against_barrier1.rs:LL:CC | diff --git a/tests/compile-fail/stacked_borrows/deallocate_against_barrier2.stderr b/tests/compile-fail/stacked_borrows/deallocate_against_barrier2.stderr index f6734db715880..41a32a6280a7a 100644 --- a/tests/compile-fail/stacked_borrows/deallocate_against_barrier2.stderr +++ b/tests/compile-fail/stacked_borrows/deallocate_against_barrier2.stderr @@ -13,7 +13,7 @@ note: inside closure at $DIR/deallocate_against_barrier2.rs:LL:CC | LL | drop(unsafe { Box::from_raw(raw) }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: inside `<[closure@$DIR/deallocate_against_barrier2.rs:LL:CC: 16:6] as std::ops::FnOnce<(&std::cell::Cell,)>>::call_once - shim` at rustc_src/src/ops/function.rs:LL:CC + = note: inside `<[closure@$DIR/deallocate_against_barrier2.rs:LL:CC] as std::ops::FnOnce<(&std::cell::Cell,)>>::call_once - shim` at rustc_src/src/ops/function.rs:LL:CC note: inside `inner` at $DIR/deallocate_against_barrier2.rs:LL:CC --> $DIR/deallocate_against_barrier2.rs:LL:CC | diff --git a/tests/compiletest.rs b/tests/compiletest.rs index 4be658e86cba4..cf053fccb478b 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -80,7 +80,7 @@ regexes! { regexes! { STDERR: // erase line and column info - r"\.rs:[0-9]+:[0-9]+" => ".rs:LL:CC", + r"\.rs:[0-9]+:[0-9]+(: [0-9]+:[0-9]+)?" => ".rs:LL:CC", // erase alloc ids "alloc[0-9]+" => "ALLOC", // erase Stacked Borrows tags From eb6d4cdac0dd2151a910109161588ffa52556dbb Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 31 May 2022 08:42:22 -0400 Subject: [PATCH 3137/3747] reduce some code duplication --- src/stacked_borrows.rs | 59 +++++++++++++++++++++--------------------- 1 file changed, 29 insertions(+), 30 deletions(-) diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 2eba35118388e..e2e63f8a52a29 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -705,6 +705,30 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx protect: bool, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); + let current_span = &mut this.machine.current_span(); + + let log_creation = |this: &MiriEvalContext<'mir, 'tcx>, + current_span: &mut CurrentSpan<'_, '_, '_>, + alloc_id, + base_offset, + orig_tag| + -> InterpResult<'tcx> { + let extra = this.get_alloc_extra(alloc_id)?; + let stacked_borrows = + extra.stacked_borrows.as_ref().expect("we should have Stacked Borrows data"); + let mut alloc_history = stacked_borrows.history.borrow_mut(); + alloc_history.log_creation( + Some(orig_tag), + new_tag, + alloc_range(base_offset, size), + current_span, + ); + if protect { + alloc_history.log_protector(orig_tag, new_tag, current_span); + } + Ok(()) + }; + if size == Size::ZERO { // Don't update any stacks for a zero-sized access; borrow stacks are per-byte and this // touches no bytes so there is no stack to put this tag in. @@ -714,16 +738,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Dangling slices are a common case here; it's valid to get their length but with raw // pointer tagging for example all calls to get_unchecked on them are invalid. if let Ok((alloc_id, base_offset, orig_tag)) = this.ptr_try_get_alloc_id(place.ptr) { - let extra = this.get_alloc_extra(alloc_id)?; - let stacked_borrows = - extra.stacked_borrows.as_ref().expect("we should have Stacked Borrows data"); - let mut alloc_history = stacked_borrows.history.borrow_mut(); - alloc_history.log_creation( - Some(orig_tag), - new_tag, - alloc_range(base_offset, Size::ZERO), - &mut this.machine.current_span(), - ); + log_creation(this, current_span, alloc_id, base_offset, orig_tag)?; } trace!( @@ -736,23 +751,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx return Ok(()); } let (alloc_id, base_offset, orig_tag) = this.ptr_get_alloc_id(place.ptr)?; - - let mut current_span = this.machine.current_span(); - { - let extra = this.get_alloc_extra(alloc_id)?; - let stacked_borrows = - extra.stacked_borrows.as_ref().expect("we should have Stacked Borrows data"); - let mut alloc_history = stacked_borrows.history.borrow_mut(); - alloc_history.log_creation( - Some(orig_tag), - new_tag, - alloc_range(base_offset, size), - &mut current_span, - ); - if protect { - alloc_history.log_protector(orig_tag, new_tag, &mut current_span); - } - } + log_creation(this, current_span, alloc_id, base_offset, orig_tag)?; // Ensure we bail out if the pointer goes out-of-bounds (see miri#1050). let (alloc_size, _) = @@ -819,7 +818,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx item, (alloc_id, range, offset), &mut *global, - &mut current_span, + current_span, history, ) }) @@ -836,14 +835,14 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let item = Item { perm, tag: new_tag, protector }; let range = alloc_range(base_offset, size); let mut global = machine.stacked_borrows.as_ref().unwrap().borrow_mut(); - let mut current_span = machine.current_span(); + let current_span = &mut machine.current_span(); // `get_alloc_extra_mut` invalidated our old `current_span` stacked_borrows.for_each_mut(range, |offset, stack, history| { stack.grant( orig_tag, item, (alloc_id, range, offset), &mut global, - &mut current_span, + current_span, history, ) })?; From 62c48b29987cd0e01d0140fcd01185fd02a57795 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 31 May 2022 08:44:48 -0400 Subject: [PATCH 3138/3747] fix some lifetime names --- src/helpers.rs | 6 +++--- src/stacked_borrows.rs | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index 5a76e15465c46..d9a7edcc11350 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -810,12 +810,12 @@ impl<'mir, 'tcx> Evaluator<'mir, 'tcx> { /// topmost frame which corresponds to a local crate, and returns the current span in that frame. /// The result of that search is cached so that later calls are approximately free. #[derive(Clone)] -pub struct CurrentSpan<'a, 'tcx, 'mir> { +pub struct CurrentSpan<'a, 'mir, 'tcx> { span: Option, - machine: &'a Evaluator<'tcx, 'mir>, + machine: &'a Evaluator<'mir, 'tcx>, } -impl<'a, 'tcx, 'mir> CurrentSpan<'a, 'tcx, 'mir> { +impl<'a, 'mir, 'tcx> CurrentSpan<'a, 'mir, 'tcx> { pub fn get(&mut self) -> Span { *self.span.get_or_insert_with(|| Self::current_span(&self.machine)) } diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index e2e63f8a52a29..6cb71f43118ca 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -708,7 +708,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let current_span = &mut this.machine.current_span(); let log_creation = |this: &MiriEvalContext<'mir, 'tcx>, - current_span: &mut CurrentSpan<'_, '_, '_>, + current_span: &mut CurrentSpan<'_, 'mir, 'tcx>, alloc_id, base_offset, orig_tag| From 9a448744a2b4f90c135f9425df0437970aa9d5fa Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 31 May 2022 18:23:47 -0400 Subject: [PATCH 3139/3747] different strategy for normalizing Rust stdlib path --- cargo-miri/bin.rs | 7 +- .../alloc/deallocate-bad-alignment.stderr | 6 +- .../alloc/deallocate-bad-size.stderr | 6 +- .../alloc/deallocate-twice.stderr | 6 +- .../alloc/global_system_mixup.stderr | 8 +- .../alloc/reallocate-bad-size.stderr | 6 +- .../alloc/reallocate-dangling.stderr | 6 +- tests/compile-fail/alloc/stack_free.stderr | 14 ++-- .../concurrency/too_few_args.stderr | 2 +- .../concurrency/too_many_args.stderr | 2 +- .../dangling_pointer_addr_of.stderr | 2 +- .../null_pointer_write_zst.stderr | 8 +- tests/compile-fail/fs/isolated_file.stderr | 18 +++-- .../generator-pinned-moved.stderr | 2 +- .../intrinsics/copy_overflow.stderr | 8 +- .../intrinsics/out_of_bounds_ptr_1.stderr | 6 +- .../intrinsics/out_of_bounds_ptr_2.stderr | 6 +- .../intrinsics/out_of_bounds_ptr_3.stderr | 6 +- .../intrinsics/ptr_offset_0_plus_0.stderr | 6 +- .../intrinsics/ptr_offset_int_plus_int.stderr | 6 +- .../intrinsics/ptr_offset_int_plus_ptr.stderr | 6 +- .../intrinsics/ptr_offset_overflow.stderr | 6 +- .../intrinsics/ptr_offset_ptr_plus_0.stderr | 6 +- .../intrinsics/simd-float-to-int.stderr | 6 +- .../intrinsics/simd-gather.stderr | 6 +- .../intrinsics/simd-scatter.stderr | 6 +- .../intrinsics/write_bytes_overflow.stderr | 8 +- tests/compile-fail/invalid_enum_tag.stderr | 6 +- tests/compile-fail/panic/bad_unwind.stderr | 6 +- tests/compile-fail/panic/double_panic.stderr | 76 ++++++++++--------- tests/compile-fail/panic/panic_abort1.stderr | 20 +++-- tests/compile-fail/panic/panic_abort2.stderr | 22 +++--- tests/compile-fail/panic/panic_abort3.stderr | 24 +++--- tests/compile-fail/panic/panic_abort4.stderr | 22 +++--- .../strict-provenance-offset.stderr | 6 +- tests/compile-fail/rc_as_ptr.stderr | 2 +- .../deallocate_against_barrier1.stderr | 16 ++-- .../deallocate_against_barrier2.stderr | 16 ++-- .../stacked_borrows/issue-miri-1050-1.stderr | 8 +- .../stacked_borrows/issue-miri-1050-2.stderr | 8 +- .../stacked_borrows/zst_slice.stderr | 9 ++- .../unaligned_ptr_addr_of.stderr | 2 +- tests/compile-fail/uninit_buffer.stderr | 8 +- tests/compile-fail/unreachable.stderr | 6 +- tests/compiletest.rs | 2 + tests/run-fail/panic/panic1.stderr | 26 +++---- tests/run-pass/backtrace-api-v0.stderr | 15 +--- tests/run-pass/backtrace-api-v1.stderr | 15 +--- tests/run-pass/backtrace-std.stderr | 26 +++---- tests/run-pass/panic/catch_panic.stderr | 2 +- 50 files changed, 318 insertions(+), 200 deletions(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index e08cb8c88c00e..373c63647c35a 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -461,12 +461,7 @@ path = "lib.rs" command.env_remove("RUSTFLAGS"); // Disable debug assertions in the standard library -- Miri is already slow enough. // But keep the overflow checks, they are cheap. - // Also remap the current directory to something that is stable across different - // machines. Otherwise ui output would contain the current directory. - command.env( - "RUSTFLAGS", - "-Cdebug-assertions=off -Coverflow-checks=on -Zremap-cwd-prefix=rustc_src", - ); + command.env("RUSTFLAGS", "-Cdebug-assertions=off -Coverflow-checks=on"); // Finally run it! if command.status().expect("failed to run xargo").success().not() { show_error(format!("failed to run xargo")); diff --git a/tests/compile-fail/alloc/deallocate-bad-alignment.stderr b/tests/compile-fail/alloc/deallocate-bad-alignment.stderr index e03704b118a67..52c0310cabaa8 100644 --- a/tests/compile-fail/alloc/deallocate-bad-alignment.stderr +++ b/tests/compile-fail/alloc/deallocate-bad-alignment.stderr @@ -1,9 +1,13 @@ error: Undefined Behavior: incorrect layout on deallocation: ALLOC has size 1 and alignment ALIGN, but gave size 1 and alignment ALIGN + --> RUSTLIB/alloc/src/alloc.rs:LL:CC + | +LL | unsafe { __rust_dealloc(ptr, layout.size(), layout.align()) } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ incorrect layout on deallocation: ALLOC has size 1 and alignment ALIGN, but gave size 1 and alignment ALIGN | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: inside `std::alloc::dealloc` at rustc_src/src/alloc.rs:LL:CC + = note: inside `std::alloc::dealloc` at RUSTLIB/alloc/src/alloc.rs:LL:CC note: inside `main` at $DIR/deallocate-bad-alignment.rs:LL:CC --> $DIR/deallocate-bad-alignment.rs:LL:CC | diff --git a/tests/compile-fail/alloc/deallocate-bad-size.stderr b/tests/compile-fail/alloc/deallocate-bad-size.stderr index 3ab15094daeb8..fe0a5130eb544 100644 --- a/tests/compile-fail/alloc/deallocate-bad-size.stderr +++ b/tests/compile-fail/alloc/deallocate-bad-size.stderr @@ -1,9 +1,13 @@ error: Undefined Behavior: incorrect layout on deallocation: ALLOC has size 1 and alignment ALIGN, but gave size 2 and alignment ALIGN + --> RUSTLIB/alloc/src/alloc.rs:LL:CC + | +LL | unsafe { __rust_dealloc(ptr, layout.size(), layout.align()) } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ incorrect layout on deallocation: ALLOC has size 1 and alignment ALIGN, but gave size 2 and alignment ALIGN | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: inside `std::alloc::dealloc` at rustc_src/src/alloc.rs:LL:CC + = note: inside `std::alloc::dealloc` at RUSTLIB/alloc/src/alloc.rs:LL:CC note: inside `main` at $DIR/deallocate-bad-size.rs:LL:CC --> $DIR/deallocate-bad-size.rs:LL:CC | diff --git a/tests/compile-fail/alloc/deallocate-twice.stderr b/tests/compile-fail/alloc/deallocate-twice.stderr index dfd14c397865e..cca20be6e661a 100644 --- a/tests/compile-fail/alloc/deallocate-twice.stderr +++ b/tests/compile-fail/alloc/deallocate-twice.stderr @@ -1,9 +1,13 @@ error: Undefined Behavior: pointer to ALLOC was dereferenced after this allocation got freed + --> RUSTLIB/alloc/src/alloc.rs:LL:CC + | +LL | unsafe { __rust_dealloc(ptr, layout.size(), layout.align()) } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pointer to ALLOC was dereferenced after this allocation got freed | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: inside `std::alloc::dealloc` at rustc_src/src/alloc.rs:LL:CC + = note: inside `std::alloc::dealloc` at RUSTLIB/alloc/src/alloc.rs:LL:CC note: inside `main` at $DIR/deallocate-twice.rs:LL:CC --> $DIR/deallocate-twice.rs:LL:CC | diff --git a/tests/compile-fail/alloc/global_system_mixup.stderr b/tests/compile-fail/alloc/global_system_mixup.stderr index 93598be134f77..84d68be78cd16 100644 --- a/tests/compile-fail/alloc/global_system_mixup.stderr +++ b/tests/compile-fail/alloc/global_system_mixup.stderr @@ -1,10 +1,14 @@ error: Undefined Behavior: deallocating ALLOC, which is Rust heap memory, using PLATFORM heap deallocation operation + --> RUSTLIB/std/src/sys/PLATFORM/alloc.rs:LL:CC + | +LL | libc::free(ptr as *mut libc::c_void) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ deallocating ALLOC, which is Rust heap memory, using PLATFORM heap deallocation operation | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: inside `std::sys::PLATFORM::alloc::::dealloc` at rustc_src/src/sys/PLATFORM/alloc.rs:LL:CC - = note: inside `::deallocate` at rustc_src/src/alloc.rs:LL:CC + = note: inside `std::sys::PLATFORM::alloc::::dealloc` at RUSTLIB/std/src/sys/PLATFORM/alloc.rs:LL:CC + = note: inside `::deallocate` at RUSTLIB/std/src/alloc.rs:LL:CC note: inside `main` at $DIR/global_system_mixup.rs:LL:CC --> $DIR/global_system_mixup.rs:LL:CC | diff --git a/tests/compile-fail/alloc/reallocate-bad-size.stderr b/tests/compile-fail/alloc/reallocate-bad-size.stderr index f2692b1c343f9..04dce05e78f54 100644 --- a/tests/compile-fail/alloc/reallocate-bad-size.stderr +++ b/tests/compile-fail/alloc/reallocate-bad-size.stderr @@ -1,9 +1,13 @@ error: Undefined Behavior: incorrect layout on deallocation: ALLOC has size 1 and alignment ALIGN, but gave size 2 and alignment ALIGN + --> RUSTLIB/alloc/src/alloc.rs:LL:CC + | +LL | unsafe { __rust_realloc(ptr, layout.size(), layout.align(), new_size) } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ incorrect layout on deallocation: ALLOC has size 1 and alignment ALIGN, but gave size 2 and alignment ALIGN | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: inside `std::alloc::realloc` at rustc_src/src/alloc.rs:LL:CC + = note: inside `std::alloc::realloc` at RUSTLIB/alloc/src/alloc.rs:LL:CC note: inside `main` at $DIR/reallocate-bad-size.rs:LL:CC --> $DIR/reallocate-bad-size.rs:LL:CC | diff --git a/tests/compile-fail/alloc/reallocate-dangling.stderr b/tests/compile-fail/alloc/reallocate-dangling.stderr index d813fb0db9026..84e7b934202ae 100644 --- a/tests/compile-fail/alloc/reallocate-dangling.stderr +++ b/tests/compile-fail/alloc/reallocate-dangling.stderr @@ -1,9 +1,13 @@ error: Undefined Behavior: pointer to ALLOC was dereferenced after this allocation got freed + --> RUSTLIB/alloc/src/alloc.rs:LL:CC + | +LL | unsafe { __rust_realloc(ptr, layout.size(), layout.align(), new_size) } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pointer to ALLOC was dereferenced after this allocation got freed | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: inside `std::alloc::realloc` at rustc_src/src/alloc.rs:LL:CC + = note: inside `std::alloc::realloc` at RUSTLIB/alloc/src/alloc.rs:LL:CC note: inside `main` at $DIR/reallocate-dangling.rs:LL:CC --> $DIR/reallocate-dangling.rs:LL:CC | diff --git a/tests/compile-fail/alloc/stack_free.stderr b/tests/compile-fail/alloc/stack_free.stderr index 9df85d6eab7f5..073510a6080da 100644 --- a/tests/compile-fail/alloc/stack_free.stderr +++ b/tests/compile-fail/alloc/stack_free.stderr @@ -1,13 +1,17 @@ error: Undefined Behavior: deallocating ALLOC, which is stack variable memory, using Rust heap deallocation operation + --> RUSTLIB/alloc/src/alloc.rs:LL:CC + | +LL | unsafe { __rust_dealloc(ptr, layout.size(), layout.align()) } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ deallocating ALLOC, which is stack variable memory, using Rust heap deallocation operation | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: inside `std::alloc::dealloc` at rustc_src/src/alloc.rs:LL:CC - = note: inside `::deallocate` at rustc_src/src/alloc.rs:LL:CC - = note: inside `alloc::alloc::box_free::` at rustc_src/src/alloc.rs:LL:CC - = note: inside `std::ptr::drop_in_place::> - shim(Some(std::boxed::Box))` at rustc_src/src/ptr/mod.rs:LL:CC - = note: inside `std::mem::drop::>` at rustc_src/src/mem/mod.rs:LL:CC + = note: inside `std::alloc::dealloc` at RUSTLIB/alloc/src/alloc.rs:LL:CC + = note: inside `::deallocate` at RUSTLIB/alloc/src/alloc.rs:LL:CC + = note: inside `alloc::alloc::box_free::` at RUSTLIB/alloc/src/alloc.rs:LL:CC + = note: inside `std::ptr::drop_in_place::> - shim(Some(std::boxed::Box))` at RUSTLIB/core/src/ptr/mod.rs:LL:CC + = note: inside `std::mem::drop::>` at RUSTLIB/core/src/mem/mod.rs:LL:CC note: inside `main` at $DIR/stack_free.rs:LL:CC --> $DIR/stack_free.rs:LL:CC | diff --git a/tests/compile-fail/concurrency/too_few_args.stderr b/tests/compile-fail/concurrency/too_few_args.stderr index 753b5e9ea7eb2..7401b2902ead8 100644 --- a/tests/compile-fail/concurrency/too_few_args.stderr +++ b/tests/compile-fail/concurrency/too_few_args.stderr @@ -9,7 +9,7 @@ LL | panic!() = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: inside `thread_start` at rustc_src/src/panic.rs:LL:CC + = note: inside `thread_start` at RUSTLIB/std/src/panic.rs:LL:CC = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to previous error; 1 warning emitted diff --git a/tests/compile-fail/concurrency/too_many_args.stderr b/tests/compile-fail/concurrency/too_many_args.stderr index 483b032a9b173..951b76317f250 100644 --- a/tests/compile-fail/concurrency/too_many_args.stderr +++ b/tests/compile-fail/concurrency/too_many_args.stderr @@ -9,7 +9,7 @@ LL | panic!() = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: inside `thread_start` at rustc_src/src/panic.rs:LL:CC + = note: inside `thread_start` at RUSTLIB/std/src/panic.rs:LL:CC = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to previous error; 1 warning emitted diff --git a/tests/compile-fail/dangling_pointers/dangling_pointer_addr_of.stderr b/tests/compile-fail/dangling_pointers/dangling_pointer_addr_of.stderr index 6638be3758cfe..1e793f549acd3 100644 --- a/tests/compile-fail/dangling_pointers/dangling_pointer_addr_of.stderr +++ b/tests/compile-fail/dangling_pointers/dangling_pointer_addr_of.stderr @@ -7,7 +7,7 @@ LL | let x = unsafe { ptr::addr_of!(*p) }; = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: inside `main` at rustc_src/src/ptr/mod.rs:LL:CC + = note: inside `main` at RUSTLIB/core/src/ptr/mod.rs:LL:CC = note: this error originates in the macro `ptr::addr_of` (in Nightly builds, run with -Z macro-backtrace for more info) note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/compile-fail/dangling_pointers/null_pointer_write_zst.stderr b/tests/compile-fail/dangling_pointers/null_pointer_write_zst.stderr index b40a9154f1826..ee8afcfb7d904 100644 --- a/tests/compile-fail/dangling_pointers/null_pointer_write_zst.stderr +++ b/tests/compile-fail/dangling_pointers/null_pointer_write_zst.stderr @@ -1,10 +1,14 @@ error: Undefined Behavior: memory access failed: null pointer is not a valid pointer + --> RUSTLIB/core/src/ptr/mod.rs:LL:CC + | +LL | copy_nonoverlapping(&src as *const T, dst, 1); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: null pointer is not a valid pointer | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: inside `std::ptr::write::<[u8; 0]>` at rustc_src/src/ptr/mod.rs:LL:CC - = note: inside `std::ptr::mut_ptr::::write` at rustc_src/src/ptr/mut_ptr.rs:LL:CC + = note: inside `std::ptr::write::<[u8; 0]>` at RUSTLIB/core/src/ptr/mod.rs:LL:CC + = note: inside `std::ptr::mut_ptr::::write` at RUSTLIB/core/src/ptr/mut_ptr.rs:LL:CC note: inside `main` at $DIR/null_pointer_write_zst.rs:LL:CC --> $DIR/null_pointer_write_zst.rs:LL:CC | diff --git a/tests/compile-fail/fs/isolated_file.stderr b/tests/compile-fail/fs/isolated_file.stderr index 056a67259c1a7..d06698c940dd6 100644 --- a/tests/compile-fail/fs/isolated_file.stderr +++ b/tests/compile-fail/fs/isolated_file.stderr @@ -1,15 +1,19 @@ error: unsupported operation: `open` not available when isolation is enabled + --> RUSTLIB/std/src/sys/PLATFORM/fs.rs:LL:CC + | +LL | let fd = cvt_r(|| unsafe { open64(path.as_ptr(), flags, opts.mode as c_int) })?; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `open` not available when isolation is enabled | = help: pass the flag `-Zmiri-disable-isolation` to disable isolation; = help: or pass `-Zmiri-isolation-error=warn` to configure Miri to return an error code from isolated operations (if supported for that operation) and continue with a warning - = note: inside closure at rustc_src/src/sys/PLATFORM/fs.rs:LL:CC - = note: inside `std::sys::PLATFORM::cvt_r::` at rustc_src/src/sys/PLATFORM/mod.rs:LL:CC - = note: inside `std::sys::PLATFORM::fs::File::open_c` at rustc_src/src/sys/PLATFORM/fs.rs:LL:CC - = note: inside `std::sys::PLATFORM::fs::File::open` at rustc_src/src/sys/PLATFORM/fs.rs:LL:CC - = note: inside `std::fs::OpenOptions::_open` at rustc_src/src/fs.rs:LL:CC - = note: inside `std::fs::OpenOptions::open::<&std::path::Path>` at rustc_src/src/fs.rs:LL:CC - = note: inside `std::fs::File::open::<&str>` at rustc_src/src/fs.rs:LL:CC + = note: inside closure at RUSTLIB/std/src/sys/PLATFORM/fs.rs:LL:CC + = note: inside `std::sys::PLATFORM::cvt_r::` at RUSTLIB/std/src/sys/PLATFORM/mod.rs:LL:CC + = note: inside `std::sys::PLATFORM::fs::File::open_c` at RUSTLIB/std/src/sys/PLATFORM/fs.rs:LL:CC + = note: inside `std::sys::PLATFORM::fs::File::open` at RUSTLIB/std/src/sys/PLATFORM/fs.rs:LL:CC + = note: inside `std::fs::OpenOptions::_open` at RUSTLIB/std/src/fs.rs:LL:CC + = note: inside `std::fs::OpenOptions::open::<&std::path::Path>` at RUSTLIB/std/src/fs.rs:LL:CC + = note: inside `std::fs::File::open::<&str>` at RUSTLIB/std/src/fs.rs:LL:CC note: inside `main` at $DIR/isolated_file.rs:LL:CC --> $DIR/isolated_file.rs:LL:CC | diff --git a/tests/compile-fail/generator-pinned-moved.stderr b/tests/compile-fail/generator-pinned-moved.stderr index 56bfc6092b7eb..0ccf3091cde73 100644 --- a/tests/compile-fail/generator-pinned-moved.stderr +++ b/tests/compile-fail/generator-pinned-moved.stderr @@ -13,7 +13,7 @@ note: inside `> as std::iter::Iterator>::next` at rustc_src/src/boxed.rs:LL:CC + = note: inside `> as std::iter::Iterator>::next` at RUSTLIB/alloc/src/boxed.rs:LL:CC note: inside `main` at $DIR/generator-pinned-moved.rs:LL:CC --> $DIR/generator-pinned-moved.rs:LL:CC | diff --git a/tests/compile-fail/intrinsics/copy_overflow.stderr b/tests/compile-fail/intrinsics/copy_overflow.stderr index 512184a36c18e..897ea5ffec5e2 100644 --- a/tests/compile-fail/intrinsics/copy_overflow.stderr +++ b/tests/compile-fail/intrinsics/copy_overflow.stderr @@ -1,10 +1,14 @@ error: Undefined Behavior: overflow computing total size of `copy` + --> RUSTLIB/core/src/intrinsics.rs:LL:CC + | +LL | copy(src, dst, count) + | ^^^^^^^^^^^^^^^^^^^^^ overflow computing total size of `copy` | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: inside `std::intrinsics::copy::` at rustc_src/src/intrinsics.rs:LL:CC - = note: inside `std::ptr::mut_ptr::::copy_from` at rustc_src/src/ptr/mut_ptr.rs:LL:CC + = note: inside `std::intrinsics::copy::` at RUSTLIB/core/src/intrinsics.rs:LL:CC + = note: inside `std::ptr::mut_ptr::::copy_from` at RUSTLIB/core/src/ptr/mut_ptr.rs:LL:CC note: inside `main` at $DIR/copy_overflow.rs:LL:CC --> $DIR/copy_overflow.rs:LL:CC | diff --git a/tests/compile-fail/intrinsics/out_of_bounds_ptr_1.stderr b/tests/compile-fail/intrinsics/out_of_bounds_ptr_1.stderr index 2b00876297faa..8a7da324ef897 100644 --- a/tests/compile-fail/intrinsics/out_of_bounds_ptr_1.stderr +++ b/tests/compile-fail/intrinsics/out_of_bounds_ptr_1.stderr @@ -1,9 +1,13 @@ error: Undefined Behavior: pointer arithmetic failed: ALLOC has size 4, so pointer to 5 bytes starting at offset 0 is out-of-bounds + --> RUSTLIB/core/src/ptr/const_ptr.rs:LL:CC + | +LL | unsafe { intrinsics::offset(self, count) } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pointer arithmetic failed: ALLOC has size 4, so pointer to 5 bytes starting at offset 0 is out-of-bounds | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: inside `std::ptr::const_ptr::::offset` at rustc_src/src/ptr/const_ptr.rs:LL:CC + = note: inside `std::ptr::const_ptr::::offset` at RUSTLIB/core/src/ptr/const_ptr.rs:LL:CC note: inside `main` at $DIR/out_of_bounds_ptr_1.rs:LL:CC --> $DIR/out_of_bounds_ptr_1.rs:LL:CC | diff --git a/tests/compile-fail/intrinsics/out_of_bounds_ptr_2.stderr b/tests/compile-fail/intrinsics/out_of_bounds_ptr_2.stderr index 32ac570f7231b..78a17a2ab7b5a 100644 --- a/tests/compile-fail/intrinsics/out_of_bounds_ptr_2.stderr +++ b/tests/compile-fail/intrinsics/out_of_bounds_ptr_2.stderr @@ -1,9 +1,13 @@ error: Undefined Behavior: overflowing in-bounds pointer arithmetic + --> RUSTLIB/core/src/ptr/const_ptr.rs:LL:CC + | +LL | unsafe { intrinsics::offset(self, count) } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflowing in-bounds pointer arithmetic | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: inside `std::ptr::const_ptr::::offset` at rustc_src/src/ptr/const_ptr.rs:LL:CC + = note: inside `std::ptr::const_ptr::::offset` at RUSTLIB/core/src/ptr/const_ptr.rs:LL:CC note: inside `main` at $DIR/out_of_bounds_ptr_2.rs:LL:CC --> $DIR/out_of_bounds_ptr_2.rs:LL:CC | diff --git a/tests/compile-fail/intrinsics/out_of_bounds_ptr_3.stderr b/tests/compile-fail/intrinsics/out_of_bounds_ptr_3.stderr index cd48112cb4304..9866529eeeb55 100644 --- a/tests/compile-fail/intrinsics/out_of_bounds_ptr_3.stderr +++ b/tests/compile-fail/intrinsics/out_of_bounds_ptr_3.stderr @@ -1,9 +1,13 @@ error: Undefined Behavior: pointer arithmetic failed: ALLOC has size 4, so pointer to 1 byte starting at offset -1 is out-of-bounds + --> RUSTLIB/core/src/ptr/const_ptr.rs:LL:CC + | +LL | unsafe { intrinsics::offset(self, count) } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pointer arithmetic failed: ALLOC has size 4, so pointer to 1 byte starting at offset -1 is out-of-bounds | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: inside `std::ptr::const_ptr::::offset` at rustc_src/src/ptr/const_ptr.rs:LL:CC + = note: inside `std::ptr::const_ptr::::offset` at RUSTLIB/core/src/ptr/const_ptr.rs:LL:CC note: inside `main` at $DIR/out_of_bounds_ptr_3.rs:LL:CC --> $DIR/out_of_bounds_ptr_3.rs:LL:CC | diff --git a/tests/compile-fail/intrinsics/ptr_offset_0_plus_0.stderr b/tests/compile-fail/intrinsics/ptr_offset_0_plus_0.stderr index d3e2fe4013f44..741314ea8a680 100644 --- a/tests/compile-fail/intrinsics/ptr_offset_0_plus_0.stderr +++ b/tests/compile-fail/intrinsics/ptr_offset_0_plus_0.stderr @@ -1,9 +1,13 @@ error: Undefined Behavior: pointer arithmetic failed: null pointer is not a valid pointer + --> RUSTLIB/core/src/ptr/mut_ptr.rs:LL:CC + | +LL | unsafe { intrinsics::offset(self, count) as *mut T } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pointer arithmetic failed: null pointer is not a valid pointer | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: inside `std::ptr::mut_ptr::::offset` at rustc_src/src/ptr/mut_ptr.rs:LL:CC + = note: inside `std::ptr::mut_ptr::::offset` at RUSTLIB/core/src/ptr/mut_ptr.rs:LL:CC note: inside `main` at $DIR/ptr_offset_0_plus_0.rs:LL:CC --> $DIR/ptr_offset_0_plus_0.rs:LL:CC | diff --git a/tests/compile-fail/intrinsics/ptr_offset_int_plus_int.stderr b/tests/compile-fail/intrinsics/ptr_offset_int_plus_int.stderr index a47ed4719d90a..e6b8f102f3946 100644 --- a/tests/compile-fail/intrinsics/ptr_offset_int_plus_int.stderr +++ b/tests/compile-fail/intrinsics/ptr_offset_int_plus_int.stderr @@ -1,9 +1,13 @@ error: Undefined Behavior: pointer arithmetic failed: 0x1 is not a valid pointer + --> RUSTLIB/core/src/ptr/mut_ptr.rs:LL:CC + | +LL | unsafe { intrinsics::offset(self, count) as *mut T } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pointer arithmetic failed: 0x1 is not a valid pointer | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: inside `std::ptr::mut_ptr::::offset` at rustc_src/src/ptr/mut_ptr.rs:LL:CC + = note: inside `std::ptr::mut_ptr::::offset` at RUSTLIB/core/src/ptr/mut_ptr.rs:LL:CC note: inside `main` at $DIR/ptr_offset_int_plus_int.rs:LL:CC --> $DIR/ptr_offset_int_plus_int.rs:LL:CC | diff --git a/tests/compile-fail/intrinsics/ptr_offset_int_plus_ptr.stderr b/tests/compile-fail/intrinsics/ptr_offset_int_plus_ptr.stderr index 58b33e706d3ee..f88ad758d438d 100644 --- a/tests/compile-fail/intrinsics/ptr_offset_int_plus_ptr.stderr +++ b/tests/compile-fail/intrinsics/ptr_offset_int_plus_ptr.stderr @@ -1,9 +1,13 @@ error: Undefined Behavior: pointer arithmetic failed: 0x1 is not a valid pointer + --> RUSTLIB/core/src/ptr/mut_ptr.rs:LL:CC + | +LL | unsafe { intrinsics::offset(self, count) as *mut T } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pointer arithmetic failed: 0x1 is not a valid pointer | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: inside `std::ptr::mut_ptr::::offset` at rustc_src/src/ptr/mut_ptr.rs:LL:CC + = note: inside `std::ptr::mut_ptr::::offset` at RUSTLIB/core/src/ptr/mut_ptr.rs:LL:CC note: inside `main` at $DIR/ptr_offset_int_plus_ptr.rs:LL:CC --> $DIR/ptr_offset_int_plus_ptr.rs:LL:CC | diff --git a/tests/compile-fail/intrinsics/ptr_offset_overflow.stderr b/tests/compile-fail/intrinsics/ptr_offset_overflow.stderr index 81ff87168c121..a144141c3c381 100644 --- a/tests/compile-fail/intrinsics/ptr_offset_overflow.stderr +++ b/tests/compile-fail/intrinsics/ptr_offset_overflow.stderr @@ -1,9 +1,13 @@ error: Undefined Behavior: overflowing in-bounds pointer arithmetic + --> RUSTLIB/core/src/ptr/const_ptr.rs:LL:CC + | +LL | unsafe { intrinsics::offset(self, count) } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflowing in-bounds pointer arithmetic | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: inside `std::ptr::const_ptr::::offset` at rustc_src/src/ptr/const_ptr.rs:LL:CC + = note: inside `std::ptr::const_ptr::::offset` at RUSTLIB/core/src/ptr/const_ptr.rs:LL:CC note: inside `main` at $DIR/ptr_offset_overflow.rs:LL:CC --> $DIR/ptr_offset_overflow.rs:LL:CC | diff --git a/tests/compile-fail/intrinsics/ptr_offset_ptr_plus_0.stderr b/tests/compile-fail/intrinsics/ptr_offset_ptr_plus_0.stderr index 686ab17966479..15e21ee676f7c 100644 --- a/tests/compile-fail/intrinsics/ptr_offset_ptr_plus_0.stderr +++ b/tests/compile-fail/intrinsics/ptr_offset_ptr_plus_0.stderr @@ -1,9 +1,13 @@ error: Undefined Behavior: pointer arithmetic failed: ALLOC has size 4, so pointer at offset 32 is out-of-bounds + --> RUSTLIB/core/src/ptr/mut_ptr.rs:LL:CC + | +LL | unsafe { intrinsics::offset(self, count) as *mut T } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pointer arithmetic failed: ALLOC has size 4, so pointer at offset 32 is out-of-bounds | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: inside `std::ptr::mut_ptr::::offset` at rustc_src/src/ptr/mut_ptr.rs:LL:CC + = note: inside `std::ptr::mut_ptr::::offset` at RUSTLIB/core/src/ptr/mut_ptr.rs:LL:CC note: inside `main` at $DIR/ptr_offset_ptr_plus_0.rs:LL:CC --> $DIR/ptr_offset_ptr_plus_0.rs:LL:CC | diff --git a/tests/compile-fail/intrinsics/simd-float-to-int.stderr b/tests/compile-fail/intrinsics/simd-float-to-int.stderr index 378c2b48bb935..6e6a136c39af9 100644 --- a/tests/compile-fail/intrinsics/simd-float-to-int.stderr +++ b/tests/compile-fail/intrinsics/simd-float-to-int.stderr @@ -1,9 +1,13 @@ error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on 3.40282347E+38 which cannot be represented in target type `i32` + --> RUSTLIB/core/src/../../portable-simd/crates/core_simd/src/round.rs:LL:CC + | +LL | implement! { f32 } + | ^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on 3.40282347E+38 which cannot be represented in target type `i32` | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: inside `core::core_simd::round::>::to_int_unchecked::` at rustc_src/src/../../portable-simd/crates/core_simd/src/round.rs:LL:CC + = note: inside `core::core_simd::round::>::to_int_unchecked::` at RUSTLIB/core/src/../../portable-simd/crates/core_simd/src/round.rs:LL:CC note: inside `main` at $DIR/simd-float-to-int.rs:LL:CC --> $DIR/simd-float-to-int.rs:LL:CC | diff --git a/tests/compile-fail/intrinsics/simd-gather.stderr b/tests/compile-fail/intrinsics/simd-gather.stderr index 3da14e1fe3756..8021077a92d37 100644 --- a/tests/compile-fail/intrinsics/simd-gather.stderr +++ b/tests/compile-fail/intrinsics/simd-gather.stderr @@ -1,9 +1,13 @@ error: Undefined Behavior: dereferencing pointer failed: ALLOC has size 9, so pointer to 1 byte starting at offset 9 is out-of-bounds + --> RUSTLIB/core/src/../../portable-simd/crates/core_simd/src/vector.rs:LL:CC + | +LL | unsafe { intrinsics::simd_gather(or, ptrs, enable.to_int()) } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ dereferencing pointer failed: ALLOC has size 9, so pointer to 1 byte starting at offset 9 is out-of-bounds | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: inside `std::simd::Simd::::gather_select_unchecked` at rustc_src/src/../../portable-simd/crates/core_simd/src/vector.rs:LL:CC + = note: inside `std::simd::Simd::::gather_select_unchecked` at RUSTLIB/core/src/../../portable-simd/crates/core_simd/src/vector.rs:LL:CC note: inside `main` at $DIR/simd-gather.rs:LL:CC --> $DIR/simd-gather.rs:LL:CC | diff --git a/tests/compile-fail/intrinsics/simd-scatter.stderr b/tests/compile-fail/intrinsics/simd-scatter.stderr index 2d2cc2972ab3d..08536c6112555 100644 --- a/tests/compile-fail/intrinsics/simd-scatter.stderr +++ b/tests/compile-fail/intrinsics/simd-scatter.stderr @@ -1,9 +1,13 @@ error: Undefined Behavior: dereferencing pointer failed: ALLOC has size 9, so pointer to 1 byte starting at offset 9 is out-of-bounds + --> RUSTLIB/core/src/../../portable-simd/crates/core_simd/src/vector.rs:LL:CC + | +LL | intrinsics::simd_scatter(self, ptrs, enable.to_int()) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ dereferencing pointer failed: ALLOC has size 9, so pointer to 1 byte starting at offset 9 is out-of-bounds | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: inside `std::simd::Simd::::scatter_select_unchecked` at rustc_src/src/../../portable-simd/crates/core_simd/src/vector.rs:LL:CC + = note: inside `std::simd::Simd::::scatter_select_unchecked` at RUSTLIB/core/src/../../portable-simd/crates/core_simd/src/vector.rs:LL:CC note: inside `main` at $DIR/simd-scatter.rs:LL:CC --> $DIR/simd-scatter.rs:LL:CC | diff --git a/tests/compile-fail/intrinsics/write_bytes_overflow.stderr b/tests/compile-fail/intrinsics/write_bytes_overflow.stderr index 018ba83f53fb6..0d5259dce2f4c 100644 --- a/tests/compile-fail/intrinsics/write_bytes_overflow.stderr +++ b/tests/compile-fail/intrinsics/write_bytes_overflow.stderr @@ -1,10 +1,14 @@ error: Undefined Behavior: overflow computing total size of `write_bytes` + --> RUSTLIB/core/src/intrinsics.rs:LL:CC + | +LL | write_bytes(dst, val, count) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflow computing total size of `write_bytes` | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: inside `std::intrinsics::write_bytes::` at rustc_src/src/intrinsics.rs:LL:CC - = note: inside `std::ptr::mut_ptr::::write_bytes` at rustc_src/src/ptr/mut_ptr.rs:LL:CC + = note: inside `std::intrinsics::write_bytes::` at RUSTLIB/core/src/intrinsics.rs:LL:CC + = note: inside `std::ptr::mut_ptr::::write_bytes` at RUSTLIB/core/src/ptr/mut_ptr.rs:LL:CC note: inside `main` at $DIR/write_bytes_overflow.rs:LL:CC --> $DIR/write_bytes_overflow.rs:LL:CC | diff --git a/tests/compile-fail/invalid_enum_tag.stderr b/tests/compile-fail/invalid_enum_tag.stderr index a602204cf46bc..b5e93d320a861 100644 --- a/tests/compile-fail/invalid_enum_tag.stderr +++ b/tests/compile-fail/invalid_enum_tag.stderr @@ -1,9 +1,13 @@ error: Undefined Behavior: enum value has invalid tag: $HEX + --> RUSTLIB/core/src/mem/mod.rs:LL:CC + | +LL | Discriminant(intrinsics::discriminant_value(v)) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ enum value has invalid tag: $HEX | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: inside `std::mem::discriminant::` at rustc_src/src/mem/mod.rs:LL:CC + = note: inside `std::mem::discriminant::` at RUSTLIB/core/src/mem/mod.rs:LL:CC note: inside `main` at $DIR/invalid_enum_tag.rs:LL:CC --> $DIR/invalid_enum_tag.rs:LL:CC | diff --git a/tests/compile-fail/panic/bad_unwind.stderr b/tests/compile-fail/panic/bad_unwind.stderr index 5030391bc6eae..745cef8be702c 100644 --- a/tests/compile-fail/panic/bad_unwind.stderr +++ b/tests/compile-fail/panic/bad_unwind.stderr @@ -10,9 +10,9 @@ LL | std::panic::catch_unwind(|| unwind()).unwrap_err(); = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: inside closure at $DIR/bad_unwind.rs:LL:CC - = note: inside `std::panicking::r#try::do_call::<[closure@$DIR/bad_unwind.rs:LL:CC], ()>` at rustc_src/src/panicking.rs:LL:CC - = note: inside `std::panicking::r#try::<(), [closure@$DIR/bad_unwind.rs:LL:CC]>` at rustc_src/src/panicking.rs:LL:CC - = note: inside `std::panic::catch_unwind::<[closure@$DIR/bad_unwind.rs:LL:CC], ()>` at rustc_src/src/panic.rs:LL:CC + = note: inside `std::panicking::r#try::do_call::<[closure@$DIR/bad_unwind.rs:LL:CC], ()>` at RUSTLIB/std/src/panicking.rs:LL:CC + = note: inside `std::panicking::r#try::<(), [closure@$DIR/bad_unwind.rs:LL:CC]>` at RUSTLIB/std/src/panicking.rs:LL:CC + = note: inside `std::panic::catch_unwind::<[closure@$DIR/bad_unwind.rs:LL:CC], ()>` at RUSTLIB/std/src/panic.rs:LL:CC note: inside `main` at $DIR/bad_unwind.rs:LL:CC --> $DIR/bad_unwind.rs:LL:CC | diff --git a/tests/compile-fail/panic/double_panic.stderr b/tests/compile-fail/panic/double_panic.stderr index b854a6b721589..9cdba65c0a826 100644 --- a/tests/compile-fail/panic/double_panic.stderr +++ b/tests/compile-fail/panic/double_panic.stderr @@ -3,81 +3,85 @@ note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace thread 'main' panicked at 'second', $DIR/double_panic.rs:LL:CC stack backtrace: 0: std::backtrace_rs::backtrace::miri::trace_unsynchronized - at rustc_src/src/../../backtrace/src/backtrace/miri.rs:LL:CC + at RUSTLIB/std/src/../../backtrace/src/backtrace/miri.rs:LL:CC 1: std::backtrace_rs::backtrace::miri::trace - at rustc_src/src/../../backtrace/src/backtrace/miri.rs:LL:CC + at RUSTLIB/std/src/../../backtrace/src/backtrace/miri.rs:LL:CC 2: std::backtrace_rs::backtrace::trace_unsynchronized - at rustc_src/src/../../backtrace/src/backtrace/mod.rs:LL:CC + at RUSTLIB/std/src/../../backtrace/src/backtrace/mod.rs:LL:CC 3: std::sys_common::backtrace::_print_fmt - at rustc_src/src/sys_common/backtrace.rs:LL:CC + at RUSTLIB/std/src/sys_common/backtrace.rs:LL:CC 4: ::fmt - at rustc_src/src/sys_common/backtrace.rs:LL:CC + at RUSTLIB/std/src/sys_common/backtrace.rs:LL:CC 5: std::fmt::write - at rustc_src/src/fmt/mod.rs:LL:CC + at RUSTLIB/core/src/fmt/mod.rs:LL:CC 6: ::write_fmt - at rustc_src/src/io/mod.rs:LL:CC + at RUSTLIB/std/src/io/mod.rs:LL:CC 7: std::sys_common::backtrace::_print - at rustc_src/src/sys_common/backtrace.rs:LL:CC + at RUSTLIB/std/src/sys_common/backtrace.rs:LL:CC 8: std::sys_common::backtrace::print - at rustc_src/src/sys_common/backtrace.rs:LL:CC + at RUSTLIB/std/src/sys_common/backtrace.rs:LL:CC 9: std::panicking::default_hook::{closure#1} - at rustc_src/src/panicking.rs:LL:CC + at RUSTLIB/std/src/panicking.rs:LL:CC 10: std::panicking::default_hook - at rustc_src/src/panicking.rs:LL:CC + at RUSTLIB/std/src/panicking.rs:LL:CC 11: std::panicking::rust_panic_with_hook - at rustc_src/src/panicking.rs:LL:CC + at RUSTLIB/std/src/panicking.rs:LL:CC 12: std::rt::begin_panic::{closure#0} - at rustc_src/src/panicking.rs:LL:CC + at RUSTLIB/std/src/panicking.rs:LL:CC 13: std::sys_common::backtrace::__rust_end_short_backtrace - at rustc_src/src/sys_common/backtrace.rs:LL:CC + at RUSTLIB/std/src/sys_common/backtrace.rs:LL:CC 14: std::rt::begin_panic - at rustc_src/src/panicking.rs:LL:CC + at RUSTLIB/std/src/panicking.rs:LL:CC 15: ::drop at $DIR/double_panic.rs:LL:CC 16: std::ptr::drop_in_place - shim(Some(Foo)) - at rustc_src/src/ptr/mod.rs:LL:CC + at RUSTLIB/core/src/ptr/mod.rs:LL:CC 17: main at $DIR/double_panic.rs:LL:CC 18: >::call_once - shim(fn()) - at rustc_src/src/ops/function.rs:LL:CC + at RUSTLIB/core/src/ops/function.rs:LL:CC 19: std::sys_common::backtrace::__rust_begin_short_backtrace - at rustc_src/src/sys_common/backtrace.rs:LL:CC + at RUSTLIB/std/src/sys_common/backtrace.rs:LL:CC 20: std::rt::lang_start::{closure#0} - at rustc_src/src/rt.rs:LL:CC + at RUSTLIB/std/src/rt.rs:LL:CC 21: std::ops::function::impls::call_once - at rustc_src/src/ops/function.rs:LL:CC + at RUSTLIB/core/src/ops/function.rs:LL:CC 22: std::panicking::r#try::do_call - at rustc_src/src/panicking.rs:LL:CC + at RUSTLIB/std/src/panicking.rs:LL:CC 23: std::panicking::r#try - at rustc_src/src/panicking.rs:LL:CC + at RUSTLIB/std/src/panicking.rs:LL:CC 24: std::panic::catch_unwind - at rustc_src/src/panic.rs:LL:CC + at RUSTLIB/std/src/panic.rs:LL:CC 25: std::rt::lang_start_internal::{closure#2} - at rustc_src/src/rt.rs:LL:CC + at RUSTLIB/std/src/rt.rs:LL:CC 26: std::panicking::r#try::do_call - at rustc_src/src/panicking.rs:LL:CC + at RUSTLIB/std/src/panicking.rs:LL:CC 27: std::panicking::r#try - at rustc_src/src/panicking.rs:LL:CC + at RUSTLIB/std/src/panicking.rs:LL:CC 28: std::panic::catch_unwind - at rustc_src/src/panic.rs:LL:CC + at RUSTLIB/std/src/panic.rs:LL:CC 29: std::rt::lang_start_internal - at rustc_src/src/rt.rs:LL:CC + at RUSTLIB/std/src/rt.rs:LL:CC 30: std::rt::lang_start - at rustc_src/src/rt.rs:LL:CC + at RUSTLIB/std/src/rt.rs:LL:CC thread panicked while panicking. aborting. error: abnormal termination: the program aborted execution + --> RUSTLIB/std/src/sys/PLATFORM/mod.rs:LL:CC | - = note: inside `std::sys::PLATFORM::abort_internal` at rustc_src/src/sys/PLATFORM/mod.rs:LL:CC - = note: inside `std::panicking::rust_panic_with_hook` at rustc_src/src/panicking.rs:LL:CC - = note: inside closure at rustc_src/src/panicking.rs:LL:CC - = note: inside `std::sys_common::backtrace::__rust_end_short_backtrace::<[closure@std::rt::begin_panic<&str>::{closure#0}], !>` at rustc_src/src/sys_common/backtrace.rs:LL:CC - = note: inside `std::rt::begin_panic::<&str>` at rustc_src/src/panicking.rs:LL:CC -note: inside `::drop` at rustc_src/src/panic.rs:LL:CC +LL | unsafe { libc::abort() } + | ^^^^^^^^^^^^^ the program aborted execution + | + = note: inside `std::sys::PLATFORM::abort_internal` at RUSTLIB/std/src/sys/PLATFORM/mod.rs:LL:CC + = note: inside `std::panicking::rust_panic_with_hook` at RUSTLIB/std/src/panicking.rs:LL:CC + = note: inside closure at RUSTLIB/std/src/panicking.rs:LL:CC + = note: inside `std::sys_common::backtrace::__rust_end_short_backtrace::<[closure@std::rt::begin_panic<&str>::{closure#0}], !>` at RUSTLIB/std/src/sys_common/backtrace.rs:LL:CC + = note: inside `std::rt::begin_panic::<&str>` at RUSTLIB/std/src/panicking.rs:LL:CC +note: inside `::drop` at RUSTLIB/std/src/panic.rs:LL:CC --> $DIR/double_panic.rs:LL:CC | LL | panic!("second"); | ^^^^^^^^^^^^^^^^ - = note: inside `std::ptr::drop_in_place:: - shim(Some(Foo))` at rustc_src/src/ptr/mod.rs:LL:CC + = note: inside `std::ptr::drop_in_place:: - shim(Some(Foo))` at RUSTLIB/core/src/ptr/mod.rs:LL:CC note: inside `main` at $DIR/double_panic.rs:LL:CC --> $DIR/double_panic.rs:LL:CC | diff --git a/tests/compile-fail/panic/panic_abort1.stderr b/tests/compile-fail/panic/panic_abort1.stderr index 93f48bb89e3bc..79e1f29ef8aa2 100644 --- a/tests/compile-fail/panic/panic_abort1.stderr +++ b/tests/compile-fail/panic/panic_abort1.stderr @@ -1,15 +1,19 @@ thread 'main' panicked at 'panicking from libstd', $DIR/panic_abort1.rs:LL:CC note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace error: abnormal termination: the program aborted execution + --> RUSTLIB/panic_abort/src/lib.rs:LL:CC | - = note: inside `panic_abort::__rust_start_panic::abort` at rustc_src/src/lib.rs:LL:CC - = note: inside `panic_abort::__rust_start_panic` at rustc_src/src/lib.rs:LL:CC - = note: inside `std::panicking::rust_panic` at rustc_src/src/panicking.rs:LL:CC - = note: inside `std::panicking::rust_panic_with_hook` at rustc_src/src/panicking.rs:LL:CC - = note: inside closure at rustc_src/src/panicking.rs:LL:CC - = note: inside `std::sys_common::backtrace::__rust_end_short_backtrace::<[closure@std::rt::begin_panic<&str>::{closure#0}], !>` at rustc_src/src/sys_common/backtrace.rs:LL:CC - = note: inside `std::rt::begin_panic::<&str>` at rustc_src/src/panicking.rs:LL:CC -note: inside `main` at rustc_src/src/panic.rs:LL:CC +LL | libc::abort(); + | ^^^^^^^^^^^^^ the program aborted execution + | + = note: inside `panic_abort::__rust_start_panic::abort` at RUSTLIB/panic_abort/src/lib.rs:LL:CC + = note: inside `panic_abort::__rust_start_panic` at RUSTLIB/panic_abort/src/lib.rs:LL:CC + = note: inside `std::panicking::rust_panic` at RUSTLIB/std/src/panicking.rs:LL:CC + = note: inside `std::panicking::rust_panic_with_hook` at RUSTLIB/std/src/panicking.rs:LL:CC + = note: inside closure at RUSTLIB/std/src/panicking.rs:LL:CC + = note: inside `std::sys_common::backtrace::__rust_end_short_backtrace::<[closure@std::rt::begin_panic<&str>::{closure#0}], !>` at RUSTLIB/std/src/sys_common/backtrace.rs:LL:CC + = note: inside `std::rt::begin_panic::<&str>` at RUSTLIB/std/src/panicking.rs:LL:CC +note: inside `main` at RUSTLIB/std/src/panic.rs:LL:CC --> $DIR/panic_abort1.rs:LL:CC | LL | std::panic!("panicking from libstd"); diff --git a/tests/compile-fail/panic/panic_abort2.stderr b/tests/compile-fail/panic/panic_abort2.stderr index bb4b96fd0aebd..3cd08ab645e8c 100644 --- a/tests/compile-fail/panic/panic_abort2.stderr +++ b/tests/compile-fail/panic/panic_abort2.stderr @@ -1,16 +1,20 @@ thread 'main' panicked at '42-panicking from libstd', $DIR/panic_abort2.rs:LL:CC note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace error: abnormal termination: the program aborted execution + --> RUSTLIB/panic_abort/src/lib.rs:LL:CC | - = note: inside `panic_abort::__rust_start_panic::abort` at rustc_src/src/lib.rs:LL:CC - = note: inside `panic_abort::__rust_start_panic` at rustc_src/src/lib.rs:LL:CC - = note: inside `std::panicking::rust_panic` at rustc_src/src/panicking.rs:LL:CC - = note: inside `std::panicking::rust_panic_with_hook` at rustc_src/src/panicking.rs:LL:CC - = note: inside closure at rustc_src/src/panicking.rs:LL:CC - = note: inside `std::sys_common::backtrace::__rust_end_short_backtrace::<[closure@std::panicking::begin_panic_handler::{closure#0}], !>` at rustc_src/src/sys_common/backtrace.rs:LL:CC - = note: inside `std::panicking::begin_panic_handler` at rustc_src/src/panicking.rs:LL:CC - = note: inside `std::rt::panic_fmt` at rustc_src/src/panicking.rs:LL:CC -note: inside `main` at rustc_src/src/panic.rs:LL:CC +LL | libc::abort(); + | ^^^^^^^^^^^^^ the program aborted execution + | + = note: inside `panic_abort::__rust_start_panic::abort` at RUSTLIB/panic_abort/src/lib.rs:LL:CC + = note: inside `panic_abort::__rust_start_panic` at RUSTLIB/panic_abort/src/lib.rs:LL:CC + = note: inside `std::panicking::rust_panic` at RUSTLIB/std/src/panicking.rs:LL:CC + = note: inside `std::panicking::rust_panic_with_hook` at RUSTLIB/std/src/panicking.rs:LL:CC + = note: inside closure at RUSTLIB/std/src/panicking.rs:LL:CC + = note: inside `std::sys_common::backtrace::__rust_end_short_backtrace::<[closure@std::panicking::begin_panic_handler::{closure#0}], !>` at RUSTLIB/std/src/sys_common/backtrace.rs:LL:CC + = note: inside `std::panicking::begin_panic_handler` at RUSTLIB/std/src/panicking.rs:LL:CC + = note: inside `std::rt::panic_fmt` at RUSTLIB/core/src/panicking.rs:LL:CC +note: inside `main` at RUSTLIB/std/src/panic.rs:LL:CC --> $DIR/panic_abort2.rs:LL:CC | LL | std::panic!("{}-panicking from libstd", 42); diff --git a/tests/compile-fail/panic/panic_abort3.stderr b/tests/compile-fail/panic/panic_abort3.stderr index a799ce4b4de9f..f6e8b16df961d 100644 --- a/tests/compile-fail/panic/panic_abort3.stderr +++ b/tests/compile-fail/panic/panic_abort3.stderr @@ -1,17 +1,21 @@ thread 'main' panicked at 'panicking from libcore', $DIR/panic_abort3.rs:LL:CC note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace error: abnormal termination: the program aborted execution + --> RUSTLIB/panic_abort/src/lib.rs:LL:CC | - = note: inside `panic_abort::__rust_start_panic::abort` at rustc_src/src/lib.rs:LL:CC - = note: inside `panic_abort::__rust_start_panic` at rustc_src/src/lib.rs:LL:CC - = note: inside `std::panicking::rust_panic` at rustc_src/src/panicking.rs:LL:CC - = note: inside `std::panicking::rust_panic_with_hook` at rustc_src/src/panicking.rs:LL:CC - = note: inside closure at rustc_src/src/panicking.rs:LL:CC - = note: inside `std::sys_common::backtrace::__rust_end_short_backtrace::<[closure@std::panicking::begin_panic_handler::{closure#0}], !>` at rustc_src/src/sys_common/backtrace.rs:LL:CC - = note: inside `std::panicking::begin_panic_handler` at rustc_src/src/panicking.rs:LL:CC - = note: inside `std::rt::panic_fmt` at rustc_src/src/panicking.rs:LL:CC - = note: inside `core::panicking::panic` at rustc_src/src/panicking.rs:LL:CC -note: inside `main` at rustc_src/src/panic.rs:LL:CC +LL | libc::abort(); + | ^^^^^^^^^^^^^ the program aborted execution + | + = note: inside `panic_abort::__rust_start_panic::abort` at RUSTLIB/panic_abort/src/lib.rs:LL:CC + = note: inside `panic_abort::__rust_start_panic` at RUSTLIB/panic_abort/src/lib.rs:LL:CC + = note: inside `std::panicking::rust_panic` at RUSTLIB/std/src/panicking.rs:LL:CC + = note: inside `std::panicking::rust_panic_with_hook` at RUSTLIB/std/src/panicking.rs:LL:CC + = note: inside closure at RUSTLIB/std/src/panicking.rs:LL:CC + = note: inside `std::sys_common::backtrace::__rust_end_short_backtrace::<[closure@std::panicking::begin_panic_handler::{closure#0}], !>` at RUSTLIB/std/src/sys_common/backtrace.rs:LL:CC + = note: inside `std::panicking::begin_panic_handler` at RUSTLIB/std/src/panicking.rs:LL:CC + = note: inside `std::rt::panic_fmt` at RUSTLIB/core/src/panicking.rs:LL:CC + = note: inside `core::panicking::panic` at RUSTLIB/core/src/panicking.rs:LL:CC +note: inside `main` at RUSTLIB/core/src/panic.rs:LL:CC --> $DIR/panic_abort3.rs:LL:CC | LL | core::panic!("panicking from libcore"); diff --git a/tests/compile-fail/panic/panic_abort4.stderr b/tests/compile-fail/panic/panic_abort4.stderr index a24d0948d1cf6..39fe03a2e0272 100644 --- a/tests/compile-fail/panic/panic_abort4.stderr +++ b/tests/compile-fail/panic/panic_abort4.stderr @@ -1,16 +1,20 @@ thread 'main' panicked at '42-panicking from libcore', $DIR/panic_abort4.rs:LL:CC note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace error: abnormal termination: the program aborted execution + --> RUSTLIB/panic_abort/src/lib.rs:LL:CC | - = note: inside `panic_abort::__rust_start_panic::abort` at rustc_src/src/lib.rs:LL:CC - = note: inside `panic_abort::__rust_start_panic` at rustc_src/src/lib.rs:LL:CC - = note: inside `std::panicking::rust_panic` at rustc_src/src/panicking.rs:LL:CC - = note: inside `std::panicking::rust_panic_with_hook` at rustc_src/src/panicking.rs:LL:CC - = note: inside closure at rustc_src/src/panicking.rs:LL:CC - = note: inside `std::sys_common::backtrace::__rust_end_short_backtrace::<[closure@std::panicking::begin_panic_handler::{closure#0}], !>` at rustc_src/src/sys_common/backtrace.rs:LL:CC - = note: inside `std::panicking::begin_panic_handler` at rustc_src/src/panicking.rs:LL:CC - = note: inside `std::rt::panic_fmt` at rustc_src/src/panicking.rs:LL:CC -note: inside `main` at rustc_src/src/panic.rs:LL:CC +LL | libc::abort(); + | ^^^^^^^^^^^^^ the program aborted execution + | + = note: inside `panic_abort::__rust_start_panic::abort` at RUSTLIB/panic_abort/src/lib.rs:LL:CC + = note: inside `panic_abort::__rust_start_panic` at RUSTLIB/panic_abort/src/lib.rs:LL:CC + = note: inside `std::panicking::rust_panic` at RUSTLIB/std/src/panicking.rs:LL:CC + = note: inside `std::panicking::rust_panic_with_hook` at RUSTLIB/std/src/panicking.rs:LL:CC + = note: inside closure at RUSTLIB/std/src/panicking.rs:LL:CC + = note: inside `std::sys_common::backtrace::__rust_end_short_backtrace::<[closure@std::panicking::begin_panic_handler::{closure#0}], !>` at RUSTLIB/std/src/sys_common/backtrace.rs:LL:CC + = note: inside `std::panicking::begin_panic_handler` at RUSTLIB/std/src/panicking.rs:LL:CC + = note: inside `std::rt::panic_fmt` at RUSTLIB/core/src/panicking.rs:LL:CC +note: inside `main` at RUSTLIB/core/src/panic.rs:LL:CC --> $DIR/panic_abort4.rs:LL:CC | LL | core::panic!("{}-panicking from libcore", 42); diff --git a/tests/compile-fail/provenance/strict-provenance-offset.stderr b/tests/compile-fail/provenance/strict-provenance-offset.stderr index 482b7a404c513..8e3daca939dba 100644 --- a/tests/compile-fail/provenance/strict-provenance-offset.stderr +++ b/tests/compile-fail/provenance/strict-provenance-offset.stderr @@ -1,9 +1,13 @@ error: Undefined Behavior: pointer arithmetic failed: $HEX is not a valid pointer + --> RUSTLIB/core/src/ptr/const_ptr.rs:LL:CC + | +LL | unsafe { intrinsics::offset(self, count) } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pointer arithmetic failed: $HEX is not a valid pointer | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: inside `std::ptr::const_ptr::::offset` at rustc_src/src/ptr/const_ptr.rs:LL:CC + = note: inside `std::ptr::const_ptr::::offset` at RUSTLIB/core/src/ptr/const_ptr.rs:LL:CC note: inside `main` at $DIR/strict-provenance-offset.rs:LL:CC --> $DIR/strict-provenance-offset.rs:LL:CC | diff --git a/tests/compile-fail/rc_as_ptr.stderr b/tests/compile-fail/rc_as_ptr.stderr index 3d745b7dc5c94..d4864da04e41f 100644 --- a/tests/compile-fail/rc_as_ptr.stderr +++ b/tests/compile-fail/rc_as_ptr.stderr @@ -7,7 +7,7 @@ LL | assert_eq!(42, **unsafe { &*Weak::as_ptr(&weak) }); = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: inside `main` at rustc_src/src/macros/mod.rs:LL:CC + = note: inside `main` at RUSTLIB/core/src/macros/mod.rs:LL:CC = note: this error originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info) note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/compile-fail/stacked_borrows/deallocate_against_barrier1.stderr b/tests/compile-fail/stacked_borrows/deallocate_against_barrier1.stderr index 804bb0f92af84..38b84e638be4d 100644 --- a/tests/compile-fail/stacked_borrows/deallocate_against_barrier1.stderr +++ b/tests/compile-fail/stacked_borrows/deallocate_against_barrier1.stderr @@ -1,19 +1,23 @@ error: Undefined Behavior: deallocating while item is protected: [Unique for (call ID)] + --> RUSTLIB/alloc/src/alloc.rs:LL:CC + | +LL | unsafe { __rust_dealloc(ptr, layout.size(), layout.align()) } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ deallocating while item is protected: [Unique for (call ID)] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information - = note: inside `std::alloc::dealloc` at rustc_src/src/alloc.rs:LL:CC - = note: inside `::deallocate` at rustc_src/src/alloc.rs:LL:CC - = note: inside `alloc::alloc::box_free::` at rustc_src/src/alloc.rs:LL:CC - = note: inside `std::ptr::drop_in_place::> - shim(Some(std::boxed::Box))` at rustc_src/src/ptr/mod.rs:LL:CC - = note: inside `std::mem::drop::>` at rustc_src/src/mem/mod.rs:LL:CC + = note: inside `std::alloc::dealloc` at RUSTLIB/alloc/src/alloc.rs:LL:CC + = note: inside `::deallocate` at RUSTLIB/alloc/src/alloc.rs:LL:CC + = note: inside `alloc::alloc::box_free::` at RUSTLIB/alloc/src/alloc.rs:LL:CC + = note: inside `std::ptr::drop_in_place::> - shim(Some(std::boxed::Box))` at RUSTLIB/core/src/ptr/mod.rs:LL:CC + = note: inside `std::mem::drop::>` at RUSTLIB/core/src/mem/mod.rs:LL:CC note: inside closure at $DIR/deallocate_against_barrier1.rs:LL:CC --> $DIR/deallocate_against_barrier1.rs:LL:CC | LL | drop(unsafe { Box::from_raw(raw) }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: inside `<[closure@$DIR/deallocate_against_barrier1.rs:LL:CC] as std::ops::FnOnce<(&mut i32,)>>::call_once - shim` at rustc_src/src/ops/function.rs:LL:CC + = note: inside `<[closure@$DIR/deallocate_against_barrier1.rs:LL:CC] as std::ops::FnOnce<(&mut i32,)>>::call_once - shim` at RUSTLIB/core/src/ops/function.rs:LL:CC note: inside `inner` at $DIR/deallocate_against_barrier1.rs:LL:CC --> $DIR/deallocate_against_barrier1.rs:LL:CC | diff --git a/tests/compile-fail/stacked_borrows/deallocate_against_barrier2.stderr b/tests/compile-fail/stacked_borrows/deallocate_against_barrier2.stderr index 41a32a6280a7a..72e6814b8e14d 100644 --- a/tests/compile-fail/stacked_borrows/deallocate_against_barrier2.stderr +++ b/tests/compile-fail/stacked_borrows/deallocate_against_barrier2.stderr @@ -1,19 +1,23 @@ error: Undefined Behavior: deallocating while item is protected: [SharedReadWrite for (call ID)] + --> RUSTLIB/alloc/src/alloc.rs:LL:CC + | +LL | unsafe { __rust_dealloc(ptr, layout.size(), layout.align()) } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ deallocating while item is protected: [SharedReadWrite for (call ID)] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information - = note: inside `std::alloc::dealloc` at rustc_src/src/alloc.rs:LL:CC - = note: inside `::deallocate` at rustc_src/src/alloc.rs:LL:CC - = note: inside `alloc::alloc::box_free::, std::alloc::Global>` at rustc_src/src/alloc.rs:LL:CC - = note: inside `std::ptr::drop_in_place::>> - shim(Some(std::boxed::Box>))` at rustc_src/src/ptr/mod.rs:LL:CC - = note: inside `std::mem::drop::>>` at rustc_src/src/mem/mod.rs:LL:CC + = note: inside `std::alloc::dealloc` at RUSTLIB/alloc/src/alloc.rs:LL:CC + = note: inside `::deallocate` at RUSTLIB/alloc/src/alloc.rs:LL:CC + = note: inside `alloc::alloc::box_free::, std::alloc::Global>` at RUSTLIB/alloc/src/alloc.rs:LL:CC + = note: inside `std::ptr::drop_in_place::>> - shim(Some(std::boxed::Box>))` at RUSTLIB/core/src/ptr/mod.rs:LL:CC + = note: inside `std::mem::drop::>>` at RUSTLIB/core/src/mem/mod.rs:LL:CC note: inside closure at $DIR/deallocate_against_barrier2.rs:LL:CC --> $DIR/deallocate_against_barrier2.rs:LL:CC | LL | drop(unsafe { Box::from_raw(raw) }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: inside `<[closure@$DIR/deallocate_against_barrier2.rs:LL:CC] as std::ops::FnOnce<(&std::cell::Cell,)>>::call_once - shim` at rustc_src/src/ops/function.rs:LL:CC + = note: inside `<[closure@$DIR/deallocate_against_barrier2.rs:LL:CC] as std::ops::FnOnce<(&std::cell::Cell,)>>::call_once - shim` at RUSTLIB/core/src/ops/function.rs:LL:CC note: inside `inner` at $DIR/deallocate_against_barrier2.rs:LL:CC --> $DIR/deallocate_against_barrier2.rs:LL:CC | diff --git a/tests/compile-fail/stacked_borrows/issue-miri-1050-1.stderr b/tests/compile-fail/stacked_borrows/issue-miri-1050-1.stderr index 70c774818bcec..b4953f95181a4 100644 --- a/tests/compile-fail/stacked_borrows/issue-miri-1050-1.stderr +++ b/tests/compile-fail/stacked_borrows/issue-miri-1050-1.stderr @@ -1,10 +1,14 @@ error: Undefined Behavior: ALLOC has size 2, so pointer to 4 bytes starting at offset 0 is out-of-bounds + --> RUSTLIB/alloc/src/boxed.rs:LL:CC + | +LL | Box(unsafe { Unique::new_unchecked(raw) }, alloc) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ALLOC has size 2, so pointer to 4 bytes starting at offset 0 is out-of-bounds | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: inside `std::boxed::Box::::from_raw_in` at rustc_src/src/boxed.rs:LL:CC - = note: inside `std::boxed::Box::::from_raw` at rustc_src/src/boxed.rs:LL:CC + = note: inside `std::boxed::Box::::from_raw_in` at RUSTLIB/alloc/src/boxed.rs:LL:CC + = note: inside `std::boxed::Box::::from_raw` at RUSTLIB/alloc/src/boxed.rs:LL:CC note: inside `main` at $DIR/issue-miri-1050-1.rs:LL:CC --> $DIR/issue-miri-1050-1.rs:LL:CC | diff --git a/tests/compile-fail/stacked_borrows/issue-miri-1050-2.stderr b/tests/compile-fail/stacked_borrows/issue-miri-1050-2.stderr index 579f728b2b07e..cd6cfc0ecc3ae 100644 --- a/tests/compile-fail/stacked_borrows/issue-miri-1050-2.stderr +++ b/tests/compile-fail/stacked_borrows/issue-miri-1050-2.stderr @@ -1,10 +1,14 @@ error: Undefined Behavior: 0x4 is not a valid pointer + --> RUSTLIB/alloc/src/boxed.rs:LL:CC + | +LL | Box(unsafe { Unique::new_unchecked(raw) }, alloc) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 0x4 is not a valid pointer | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: inside `std::boxed::Box::::from_raw_in` at rustc_src/src/boxed.rs:LL:CC - = note: inside `std::boxed::Box::::from_raw` at rustc_src/src/boxed.rs:LL:CC + = note: inside `std::boxed::Box::::from_raw_in` at RUSTLIB/alloc/src/boxed.rs:LL:CC + = note: inside `std::boxed::Box::::from_raw` at RUSTLIB/alloc/src/boxed.rs:LL:CC note: inside `main` at $DIR/issue-miri-1050-2.rs:LL:CC --> $DIR/issue-miri-1050-2.rs:LL:CC | diff --git a/tests/compile-fail/stacked_borrows/zst_slice.stderr b/tests/compile-fail/stacked_borrows/zst_slice.stderr index c6b4dc16b797b..6809aa3d25fbd 100644 --- a/tests/compile-fail/stacked_borrows/zst_slice.stderr +++ b/tests/compile-fail/stacked_borrows/zst_slice.stderr @@ -1,4 +1,11 @@ error: Undefined Behavior: trying to reborrow for SharedReadOnly permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location + --> RUSTLIB/core/src/slice/mod.rs:LL:CC + | +LL | unsafe { &*index.get_unchecked(self) } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | trying to reborrow for SharedReadOnly permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location + | this error occurs as part of a reborrow at ALLOC[0x4..0x8] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information @@ -7,7 +14,7 @@ help: was created by a retag at offsets [0x0..0x0] | LL | assert_eq!(*s.get_unchecked(1), 2); | ^^^^^^^^^^^^^^^^^^ - = note: inside `core::slice::::get_unchecked::` at rustc_src/src/slice/mod.rs:LL:CC + = note: inside `core::slice::::get_unchecked::` at RUSTLIB/core/src/slice/mod.rs:LL:CC note: inside `main` at $DIR/zst_slice.rs:LL:CC --> $DIR/zst_slice.rs:LL:CC | diff --git a/tests/compile-fail/unaligned_pointers/unaligned_ptr_addr_of.stderr b/tests/compile-fail/unaligned_pointers/unaligned_ptr_addr_of.stderr index b858a291dea83..31f9163b3cf05 100644 --- a/tests/compile-fail/unaligned_pointers/unaligned_ptr_addr_of.stderr +++ b/tests/compile-fail/unaligned_pointers/unaligned_ptr_addr_of.stderr @@ -7,7 +7,7 @@ LL | let _x = unsafe { ptr::addr_of!(*x) }; = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: inside `main` at rustc_src/src/ptr/mod.rs:LL:CC + = note: inside `main` at RUSTLIB/core/src/ptr/mod.rs:LL:CC = note: this error originates in the macro `ptr::addr_of` (in Nightly builds, run with -Z macro-backtrace for more info) note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/compile-fail/uninit_buffer.stderr b/tests/compile-fail/uninit_buffer.stderr index 903a1deee3fef..02e4bcb90be63 100644 --- a/tests/compile-fail/uninit_buffer.stderr +++ b/tests/compile-fail/uninit_buffer.stderr @@ -1,10 +1,14 @@ error: Undefined Behavior: reading 16 bytes of memory starting at ALLOC, but 12 bytes are uninitialized starting at ALLOC+0x4, and this operation requires initialized memory + --> RUSTLIB/core/src/slice/cmp.rs:LL:CC + | +LL | let mut order = unsafe { memcmp(left.as_ptr(), right.as_ptr(), len) as isize }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ reading 16 bytes of memory starting at ALLOC, but 12 bytes are uninitialized starting at ALLOC+0x4, and this operation requires initialized memory | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: inside `::compare` at rustc_src/src/slice/cmp.rs:LL:CC - = note: inside `core::slice::cmp::::cmp` at rustc_src/src/slice/cmp.rs:LL:CC + = note: inside `::compare` at RUSTLIB/core/src/slice/cmp.rs:LL:CC + = note: inside `core::slice::cmp::::cmp` at RUSTLIB/core/src/slice/cmp.rs:LL:CC note: inside `main` at $DIR/uninit_buffer.rs:LL:CC --> $DIR/uninit_buffer.rs:LL:CC | diff --git a/tests/compile-fail/unreachable.stderr b/tests/compile-fail/unreachable.stderr index 59ab843319552..1cad7dd901b74 100644 --- a/tests/compile-fail/unreachable.stderr +++ b/tests/compile-fail/unreachable.stderr @@ -1,9 +1,13 @@ error: Undefined Behavior: entering unreachable code + --> RUSTLIB/core/src/hint.rs:LL:CC + | +LL | unsafe { intrinsics::unreachable() } + | ^^^^^^^^^^^^^^^^^^^^^^^^^ entering unreachable code | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: inside `std::hint::unreachable_unchecked` at rustc_src/src/hint.rs:LL:CC + = note: inside `std::hint::unreachable_unchecked` at RUSTLIB/core/src/hint.rs:LL:CC note: inside `main` at $DIR/unreachable.rs:LL:CC --> $DIR/unreachable.rs:LL:CC | diff --git a/tests/compiletest.rs b/tests/compiletest.rs index 3830b1c1bd548..3b6cf6a6d1fda 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -104,6 +104,8 @@ regexes! { "sys::[a-z]+::" => "sys::PLATFORM::", // Windows file paths r"\\" => "/", + // erase Rust stdlib path + "[^ `]*/(rust[^/]*|checkout)/library/" => "RUSTLIB/", // erase platform file paths "sys/[a-z]+/" => "sys/PLATFORM/", } diff --git a/tests/run-fail/panic/panic1.stderr b/tests/run-fail/panic/panic1.stderr index d4dcfc47a8392..f86ce187b2c9b 100644 --- a/tests/run-fail/panic/panic1.stderr +++ b/tests/run-fail/panic/panic1.stderr @@ -1,31 +1,31 @@ thread 'main' panicked at 'panicking from libstd', $DIR/panic1.rs:LL:CC stack backtrace: 0: std::rt::begin_panic - at rustc_src/src/panicking.rs:LL:CC + at RUSTLIB/std/src/panicking.rs:LL:CC 1: main at $DIR/panic1.rs:LL:CC 2: >::call_once - shim(fn()) - at rustc_src/src/ops/function.rs:LL:CC + at RUSTLIB/core/src/ops/function.rs:LL:CC 3: std::rt::lang_start::{closure#0} - at rustc_src/src/rt.rs:LL:CC + at RUSTLIB/std/src/rt.rs:LL:CC 4: std::ops::function::impls::call_once - at rustc_src/src/ops/function.rs:LL:CC + at RUSTLIB/core/src/ops/function.rs:LL:CC 5: std::panicking::r#try::do_call - at rustc_src/src/panicking.rs:LL:CC + at RUSTLIB/std/src/panicking.rs:LL:CC 6: std::panicking::r#try - at rustc_src/src/panicking.rs:LL:CC + at RUSTLIB/std/src/panicking.rs:LL:CC 7: std::panic::catch_unwind - at rustc_src/src/panic.rs:LL:CC + at RUSTLIB/std/src/panic.rs:LL:CC 8: std::rt::lang_start_internal::{closure#2} - at rustc_src/src/rt.rs:LL:CC + at RUSTLIB/std/src/rt.rs:LL:CC 9: std::panicking::r#try::do_call - at rustc_src/src/panicking.rs:LL:CC + at RUSTLIB/std/src/panicking.rs:LL:CC 10: std::panicking::r#try - at rustc_src/src/panicking.rs:LL:CC + at RUSTLIB/std/src/panicking.rs:LL:CC 11: std::panic::catch_unwind - at rustc_src/src/panic.rs:LL:CC + at RUSTLIB/std/src/panic.rs:LL:CC 12: std::rt::lang_start_internal - at rustc_src/src/rt.rs:LL:CC + at RUSTLIB/std/src/rt.rs:LL:CC 13: std::rt::lang_start - at rustc_src/src/rt.rs:LL:CC + at RUSTLIB/std/src/rt.rs:LL:CC note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace. diff --git a/tests/run-pass/backtrace-api-v0.stderr b/tests/run-pass/backtrace-api-v0.stderr index d81f5ad1d6266..ee556b3e4a05a 100644 --- a/tests/run-pass/backtrace-api-v0.stderr +++ b/tests/run-pass/backtrace-api-v0.stderr @@ -2,17 +2,4 @@ $DIR/backtrace-api-v0.rs:LL:CC (func_d) $DIR/backtrace-api-v0.rs:LL:CC (func_c) $DIR/backtrace-api-v0.rs:LL:CC (func_b) $DIR/backtrace-api-v0.rs:LL:CC (func_a) -$DIR/backtrace-api-v0.rs:LL:CC (main) -rustc_src/src/ops/function.rs:LL:CC (>::call_once - shim(fn())) -rustc_src/src/sys_common/backtrace.rs:LL:CC (std::sys_common::backtrace::__rust_begin_short_backtrace) -rustc_src/src/rt.rs:LL:CC (std::rt::lang_start::{closure#0}) -rustc_src/src/ops/function.rs:LL:CC (std::ops::function::impls::call_once) -rustc_src/src/panicking.rs:LL:CC (std::panicking::r#try::do_call) -rustc_src/src/panicking.rs:LL:CC (std::panicking::r#try) -rustc_src/src/panic.rs:LL:CC (std::panic::catch_unwind) -rustc_src/src/rt.rs:LL:CC (std::rt::lang_start_internal::{closure#2}) -rustc_src/src/panicking.rs:LL:CC (std::panicking::r#try::do_call) -rustc_src/src/panicking.rs:LL:CC (std::panicking::r#try) -rustc_src/src/panic.rs:LL:CC (std::panic::catch_unwind) -rustc_src/src/rt.rs:LL:CC (std::rt::lang_start_internal) -rustc_src/src/rt.rs:LL:CC (std::rt::lang_start) +$DIR/backtrace-api-v0.rs:LL:CC RUSTLIB/core/src/ops/function.rs:LL:CC (>::call_once - RUSTLIB/std/src/sys_common/backtrace.rs:LL:CC (std::sys_common::backtrace::__rust_begin_short_backtrace) diff --git a/tests/run-pass/backtrace-api-v1.stderr b/tests/run-pass/backtrace-api-v1.stderr index 87c59f4269685..7dc281af31ddc 100644 --- a/tests/run-pass/backtrace-api-v1.stderr +++ b/tests/run-pass/backtrace-api-v1.stderr @@ -2,17 +2,4 @@ $DIR/backtrace-api-v1.rs:LL:CC (func_d) $DIR/backtrace-api-v1.rs:LL:CC (func_c) $DIR/backtrace-api-v1.rs:LL:CC (func_b) $DIR/backtrace-api-v1.rs:LL:CC (func_a) -$DIR/backtrace-api-v1.rs:LL:CC (main) -rustc_src/src/ops/function.rs:LL:CC (>::call_once - shim(fn())) -rustc_src/src/sys_common/backtrace.rs:LL:CC (std::sys_common::backtrace::__rust_begin_short_backtrace) -rustc_src/src/rt.rs:LL:CC (std::rt::lang_start::{closure#0}) -rustc_src/src/ops/function.rs:LL:CC (std::ops::function::impls::call_once) -rustc_src/src/panicking.rs:LL:CC (std::panicking::r#try::do_call) -rustc_src/src/panicking.rs:LL:CC (std::panicking::r#try) -rustc_src/src/panic.rs:LL:CC (std::panic::catch_unwind) -rustc_src/src/rt.rs:LL:CC (std::rt::lang_start_internal::{closure#2}) -rustc_src/src/panicking.rs:LL:CC (std::panicking::r#try::do_call) -rustc_src/src/panicking.rs:LL:CC (std::panicking::r#try) -rustc_src/src/panic.rs:LL:CC (std::panic::catch_unwind) -rustc_src/src/rt.rs:LL:CC (std::rt::lang_start_internal) -rustc_src/src/rt.rs:LL:CC (std::rt::lang_start) +$DIR/backtrace-api-v1.rs:LL:CC RUSTLIB/core/src/ops/function.rs:LL:CC (>::call_once - RUSTLIB/std/src/sys_common/backtrace.rs:LL:CC (std::sys_common::backtrace::__rust_begin_short_backtrace) diff --git a/tests/run-pass/backtrace-std.stderr b/tests/run-pass/backtrace-std.stderr index 848ccaea1b622..4596cadb958d8 100644 --- a/tests/run-pass/backtrace-std.stderr +++ b/tests/run-pass/backtrace-std.stderr @@ -9,28 +9,28 @@ 4: main at $DIR/backtrace-std.rs:LL:CC 5: >::call_once - shim(fn()) - at rustc_src/src/ops/function.rs:LL:CC + at RUSTLIB/core/src/ops/function.rs:LL:CC 6: std::sys_common::backtrace::__rust_begin_short_backtrace - at rustc_src/src/sys_common/backtrace.rs:LL:CC + at RUSTLIB/std/src/sys_common/backtrace.rs:LL:CC 7: std::rt::lang_start::{closure#0} - at rustc_src/src/rt.rs:LL:CC + at RUSTLIB/std/src/rt.rs:LL:CC 8: std::ops::function::impls::call_once - at rustc_src/src/ops/function.rs:LL:CC + at RUSTLIB/core/src/ops/function.rs:LL:CC 9: std::panicking::r#try::do_call - at rustc_src/src/panicking.rs:LL:CC + at RUSTLIB/std/src/panicking.rs:LL:CC 10: std::panicking::r#try - at rustc_src/src/panicking.rs:LL:CC + at RUSTLIB/std/src/panicking.rs:LL:CC 11: std::panic::catch_unwind - at rustc_src/src/panic.rs:LL:CC + at RUSTLIB/std/src/panic.rs:LL:CC 12: std::rt::lang_start_internal::{closure#2} - at rustc_src/src/rt.rs:LL:CC + at RUSTLIB/std/src/rt.rs:LL:CC 13: std::panicking::r#try::do_call - at rustc_src/src/panicking.rs:LL:CC + at RUSTLIB/std/src/panicking.rs:LL:CC 14: std::panicking::r#try - at rustc_src/src/panicking.rs:LL:CC + at RUSTLIB/std/src/panicking.rs:LL:CC 15: std::panic::catch_unwind - at rustc_src/src/panic.rs:LL:CC + at RUSTLIB/std/src/panic.rs:LL:CC 16: std::rt::lang_start_internal - at rustc_src/src/rt.rs:LL:CC + at RUSTLIB/std/src/rt.rs:LL:CC 17: std::rt::lang_start - at rustc_src/src/rt.rs:LL:CC + at RUSTLIB/std/src/rt.rs:LL:CC diff --git a/tests/run-pass/panic/catch_panic.stderr b/tests/run-pass/panic/catch_panic.stderr index 36a7818d27661..0ced5588cc12c 100644 --- a/tests/run-pass/panic/catch_panic.stderr +++ b/tests/run-pass/panic/catch_panic.stderr @@ -17,7 +17,7 @@ thread 'main' panicked at 'index out of bounds: the len is 3 but the index is 4' Caught panic message (String): index out of bounds: the len is 3 but the index is 4 thread 'main' panicked at 'attempt to divide by zero', $DIR/catch_panic.rs:LL:CC Caught panic message (&str): attempt to divide by zero -thread 'main' panicked at 'align_offset: align is not a power-of-two', rustc_src/src/ptr/const_ptr.rs:LL:CC +thread 'main' panicked at 'align_offset: align is not a power-of-two', RUSTLIB/core/src/ptr/const_ptr.rs:LL:CC Caught panic message (&str): align_offset: align is not a power-of-two thread 'main' panicked at 'assertion failed: false', $DIR/catch_panic.rs:LL:CC Caught panic message (&str): assertion failed: false From 8997db2ec99d980e827f8bb4ed212dce1d5e7e02 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 31 May 2022 19:00:14 -0400 Subject: [PATCH 3140/3747] paper over platform differences --- tests/compile-fail/alloc/global_system_mixup.rs | 2 ++ tests/compile-fail/alloc/global_system_mixup.stderr | 6 +++--- tests/compile-fail/panic/double_panic.rs | 2 ++ tests/compile-fail/panic/double_panic.stderr | 6 +++--- tests/compile-fail/panic/panic_abort1.rs | 2 ++ tests/compile-fail/panic/panic_abort1.stderr | 6 +++--- tests/compile-fail/panic/panic_abort2.rs | 2 ++ tests/compile-fail/panic/panic_abort2.stderr | 6 +++--- tests/compile-fail/panic/panic_abort3.rs | 2 ++ tests/compile-fail/panic/panic_abort3.stderr | 6 +++--- tests/compile-fail/panic/panic_abort4.rs | 2 ++ tests/compile-fail/panic/panic_abort4.stderr | 6 +++--- 12 files changed, 30 insertions(+), 18 deletions(-) diff --git a/tests/compile-fail/alloc/global_system_mixup.rs b/tests/compile-fail/alloc/global_system_mixup.rs index 3f58de4d6fb0a..bb87b132f3227 100644 --- a/tests/compile-fail/alloc/global_system_mixup.rs +++ b/tests/compile-fail/alloc/global_system_mixup.rs @@ -3,6 +3,8 @@ // error-pattern: which is Rust heap memory, using // normalize-stderr-test: "using [A-Za-z]+ heap deallocation operation" -> "using PLATFORM heap deallocation operation" +// normalize-stderr-test: "\| +\^+" -> "| ^" +// normalize-stderr-test: "libc::free\([^()]*\)|unsafe \{ HeapFree\([^()]*\) \};" -> "FREE();" #![feature(allocator_api, slice_ptr_get)] diff --git a/tests/compile-fail/alloc/global_system_mixup.stderr b/tests/compile-fail/alloc/global_system_mixup.stderr index 84d68be78cd16..a3b9009e30354 100644 --- a/tests/compile-fail/alloc/global_system_mixup.stderr +++ b/tests/compile-fail/alloc/global_system_mixup.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: deallocating ALLOC, which is Rust heap memory, using PLATFORM heap deallocation operation --> RUSTLIB/std/src/sys/PLATFORM/alloc.rs:LL:CC | -LL | libc::free(ptr as *mut libc::c_void) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ deallocating ALLOC, which is Rust heap memory, using PLATFORM heap deallocation operation +LL | FREE(); + | ^ deallocating ALLOC, which is Rust heap memory, using PLATFORM heap deallocation operation | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information @@ -13,7 +13,7 @@ note: inside `main` at $DIR/global_system_mixup.rs:LL:CC --> $DIR/global_system_mixup.rs:LL:CC | LL | unsafe { System.deallocate(ptr, l); } - | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^ note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/compile-fail/panic/double_panic.rs b/tests/compile-fail/panic/double_panic.rs index 670c037988c2b..f3af66a79abc4 100644 --- a/tests/compile-fail/panic/double_panic.rs +++ b/tests/compile-fail/panic/double_panic.rs @@ -1,4 +1,6 @@ // error-pattern: the program aborted +// normalize-stderr-test: "\| +\^+" -> "| ^" +// normalize-stderr-test: "unsafe \{ libc::abort\(\) \}|crate::intrinsics::abort\(\);" -> "ABORT();" struct Foo; impl Drop for Foo { diff --git a/tests/compile-fail/panic/double_panic.stderr b/tests/compile-fail/panic/double_panic.stderr index 9cdba65c0a826..0dbd68c0984f9 100644 --- a/tests/compile-fail/panic/double_panic.stderr +++ b/tests/compile-fail/panic/double_panic.stderr @@ -68,8 +68,8 @@ thread panicked while panicking. aborting. error: abnormal termination: the program aborted execution --> RUSTLIB/std/src/sys/PLATFORM/mod.rs:LL:CC | -LL | unsafe { libc::abort() } - | ^^^^^^^^^^^^^ the program aborted execution +LL | ABORT(); + | ^ the program aborted execution | = note: inside `std::sys::PLATFORM::abort_internal` at RUSTLIB/std/src/sys/PLATFORM/mod.rs:LL:CC = note: inside `std::panicking::rust_panic_with_hook` at RUSTLIB/std/src/panicking.rs:LL:CC @@ -80,7 +80,7 @@ note: inside `::drop` at RUSTLIB/std/src/panic.rs:LL:CC --> $DIR/double_panic.rs:LL:CC | LL | panic!("second"); - | ^^^^^^^^^^^^^^^^ + | ^ = note: inside `std::ptr::drop_in_place:: - shim(Some(Foo))` at RUSTLIB/core/src/ptr/mod.rs:LL:CC note: inside `main` at $DIR/double_panic.rs:LL:CC --> $DIR/double_panic.rs:LL:CC diff --git a/tests/compile-fail/panic/panic_abort1.rs b/tests/compile-fail/panic/panic_abort1.rs index 095d9e3d75b02..9c094c659837a 100644 --- a/tests/compile-fail/panic/panic_abort1.rs +++ b/tests/compile-fail/panic/panic_abort1.rs @@ -1,4 +1,6 @@ // error-pattern: the program aborted execution +// normalize-stderr-test: "\| +\^+" -> "| ^" +// normalize-stderr-test: "libc::abort\(\);|core::intrinsics::abort\(\);" -> "ABORT();" // compile-flags: -C panic=abort fn main() { diff --git a/tests/compile-fail/panic/panic_abort1.stderr b/tests/compile-fail/panic/panic_abort1.stderr index 79e1f29ef8aa2..9610a161280a0 100644 --- a/tests/compile-fail/panic/panic_abort1.stderr +++ b/tests/compile-fail/panic/panic_abort1.stderr @@ -3,8 +3,8 @@ note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace error: abnormal termination: the program aborted execution --> RUSTLIB/panic_abort/src/lib.rs:LL:CC | -LL | libc::abort(); - | ^^^^^^^^^^^^^ the program aborted execution +LL | ABORT(); + | ^ the program aborted execution | = note: inside `panic_abort::__rust_start_panic::abort` at RUSTLIB/panic_abort/src/lib.rs:LL:CC = note: inside `panic_abort::__rust_start_panic` at RUSTLIB/panic_abort/src/lib.rs:LL:CC @@ -17,7 +17,7 @@ note: inside `main` at RUSTLIB/std/src/panic.rs:LL:CC --> $DIR/panic_abort1.rs:LL:CC | LL | std::panic!("panicking from libstd"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^ = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/compile-fail/panic/panic_abort2.rs b/tests/compile-fail/panic/panic_abort2.rs index de177bc4e7167..7eb9a3c24aa24 100644 --- a/tests/compile-fail/panic/panic_abort2.rs +++ b/tests/compile-fail/panic/panic_abort2.rs @@ -1,4 +1,6 @@ // error-pattern: the program aborted execution +// normalize-stderr-test: "\| +\^+" -> "| ^" +// normalize-stderr-test: "libc::abort\(\);|core::intrinsics::abort\(\);" -> "ABORT();" // compile-flags: -C panic=abort fn main() { diff --git a/tests/compile-fail/panic/panic_abort2.stderr b/tests/compile-fail/panic/panic_abort2.stderr index 3cd08ab645e8c..0c446323a7791 100644 --- a/tests/compile-fail/panic/panic_abort2.stderr +++ b/tests/compile-fail/panic/panic_abort2.stderr @@ -3,8 +3,8 @@ note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace error: abnormal termination: the program aborted execution --> RUSTLIB/panic_abort/src/lib.rs:LL:CC | -LL | libc::abort(); - | ^^^^^^^^^^^^^ the program aborted execution +LL | ABORT(); + | ^ the program aborted execution | = note: inside `panic_abort::__rust_start_panic::abort` at RUSTLIB/panic_abort/src/lib.rs:LL:CC = note: inside `panic_abort::__rust_start_panic` at RUSTLIB/panic_abort/src/lib.rs:LL:CC @@ -18,7 +18,7 @@ note: inside `main` at RUSTLIB/std/src/panic.rs:LL:CC --> $DIR/panic_abort2.rs:LL:CC | LL | std::panic!("{}-panicking from libstd", 42); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^ = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/compile-fail/panic/panic_abort3.rs b/tests/compile-fail/panic/panic_abort3.rs index 2d65da4fe3416..1940b48bad78d 100644 --- a/tests/compile-fail/panic/panic_abort3.rs +++ b/tests/compile-fail/panic/panic_abort3.rs @@ -1,4 +1,6 @@ // error-pattern: the program aborted execution +// normalize-stderr-test: "\| +\^+" -> "| ^" +// normalize-stderr-test: "libc::abort\(\);|core::intrinsics::abort\(\);" -> "ABORT();" // compile-flags: -C panic=abort fn main() { diff --git a/tests/compile-fail/panic/panic_abort3.stderr b/tests/compile-fail/panic/panic_abort3.stderr index f6e8b16df961d..2d7b576372e08 100644 --- a/tests/compile-fail/panic/panic_abort3.stderr +++ b/tests/compile-fail/panic/panic_abort3.stderr @@ -3,8 +3,8 @@ note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace error: abnormal termination: the program aborted execution --> RUSTLIB/panic_abort/src/lib.rs:LL:CC | -LL | libc::abort(); - | ^^^^^^^^^^^^^ the program aborted execution +LL | ABORT(); + | ^ the program aborted execution | = note: inside `panic_abort::__rust_start_panic::abort` at RUSTLIB/panic_abort/src/lib.rs:LL:CC = note: inside `panic_abort::__rust_start_panic` at RUSTLIB/panic_abort/src/lib.rs:LL:CC @@ -19,7 +19,7 @@ note: inside `main` at RUSTLIB/core/src/panic.rs:LL:CC --> $DIR/panic_abort3.rs:LL:CC | LL | core::panic!("panicking from libcore"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^ = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/compile-fail/panic/panic_abort4.rs b/tests/compile-fail/panic/panic_abort4.rs index 41d32a604fede..e5190ea0765d1 100644 --- a/tests/compile-fail/panic/panic_abort4.rs +++ b/tests/compile-fail/panic/panic_abort4.rs @@ -1,4 +1,6 @@ // error-pattern: the program aborted execution +// normalize-stderr-test: "\| +\^+" -> "| ^" +// normalize-stderr-test: "libc::abort\(\);|core::intrinsics::abort\(\);" -> "ABORT();" // compile-flags: -C panic=abort fn main() { diff --git a/tests/compile-fail/panic/panic_abort4.stderr b/tests/compile-fail/panic/panic_abort4.stderr index 39fe03a2e0272..b0b11248104d9 100644 --- a/tests/compile-fail/panic/panic_abort4.stderr +++ b/tests/compile-fail/panic/panic_abort4.stderr @@ -3,8 +3,8 @@ note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace error: abnormal termination: the program aborted execution --> RUSTLIB/panic_abort/src/lib.rs:LL:CC | -LL | libc::abort(); - | ^^^^^^^^^^^^^ the program aborted execution +LL | ABORT(); + | ^ the program aborted execution | = note: inside `panic_abort::__rust_start_panic::abort` at RUSTLIB/panic_abort/src/lib.rs:LL:CC = note: inside `panic_abort::__rust_start_panic` at RUSTLIB/panic_abort/src/lib.rs:LL:CC @@ -18,7 +18,7 @@ note: inside `main` at RUSTLIB/core/src/panic.rs:LL:CC --> $DIR/panic_abort4.rs:LL:CC | LL | core::panic!("{}-panicking from libcore", 42); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^ = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace From 81d661f1341905b7c012c0d2ec97697ec0bfc821 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 1 Jun 2022 06:28:27 -0400 Subject: [PATCH 3141/3747] bump xargo version, and tweak xargo caching --- .github/workflows/ci.yml | 5 +++-- cargo-miri/bin.rs | 5 +++-- cargo-miri/version.rs | 2 ++ 3 files changed, 8 insertions(+), 4 deletions(-) create mode 100644 cargo-miri/version.rs diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index edf74603b6e10..84bf54246e1d0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -57,14 +57,15 @@ jobs: # contains package information of crates installed via `cargo install`. ~/.cargo/.crates.toml ~/.cargo/.crates2.json - key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}-xargo0.3.25 + key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock', 'cargo-miri/version.rs') }} restore-keys: ${{ runner.os }}-cargo - name: Install rustup-toolchain-install-master and xargo shell: bash run: | cargo install rustup-toolchain-install-master - cargo install xargo + # Only install xargo if we don't have it cached + if ! which xargo; then cargo install xargo; fi - name: Install "master" toolchain shell: bash diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index 373c63647c35a..fd4af14e7ded4 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -1,3 +1,5 @@ +mod version; + use std::env; use std::ffi::{OsStr, OsString}; use std::fmt::Write as _; @@ -9,10 +11,9 @@ use std::path::{Path, PathBuf}; use std::process::{self, Command}; use serde::{Deserialize, Serialize}; - use rustc_version::VersionMeta; -const XARGO_MIN_VERSION: (u32, u32, u32) = (0, 3, 23); +use version::*; const CARGO_MIRI_HELP: &str = r#"Runs binary crates and tests in Miri diff --git a/cargo-miri/version.rs b/cargo-miri/version.rs new file mode 100644 index 0000000000000..366e90df17983 --- /dev/null +++ b/cargo-miri/version.rs @@ -0,0 +1,2 @@ +// We put this in a separate file so that it can be hashed for GHA caching. +pub const XARGO_MIN_VERSION: (u32, u32, u32) = (0, 3, 26); From 1571571e38a10c69d3fb43b88bfc84b5a3eeb62e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 1 Jun 2022 06:31:08 -0400 Subject: [PATCH 3142/3747] also avoid rebuilding cached RTIM --- .github/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 84bf54246e1d0..8eeb3491d95ea 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -63,8 +63,8 @@ jobs: - name: Install rustup-toolchain-install-master and xargo shell: bash run: | - cargo install rustup-toolchain-install-master - # Only install xargo if we don't have it cached + # Only install tools if we don't have them cached + if ! which rustup-toolchain-install-master; then cargo install rustup-toolchain-install-master; fi if ! which xargo; then cargo install xargo; fi - name: Install "master" toolchain From 61265f5f19d1537ba184bd13bd5d83c533bf30cd Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 1 Jun 2022 06:42:11 -0400 Subject: [PATCH 3143/3747] fmt --- cargo-miri/bin.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index fd4af14e7ded4..34904279e94f1 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -10,8 +10,8 @@ use std::ops::Not; use std::path::{Path, PathBuf}; use std::process::{self, Command}; -use serde::{Deserialize, Serialize}; use rustc_version::VersionMeta; +use serde::{Deserialize, Serialize}; use version::*; From 4f700938053eb582f1812a804dabe30c65d7f546 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 1 Jun 2022 06:45:09 -0400 Subject: [PATCH 3144/3747] advanced GHA --- .github/workflows/ci.yml | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8eeb3491d95ea..f34e92571ff02 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -46,7 +46,8 @@ jobs: # we cannot reuse anyway when the nightly changes (and it grows quite large # over time). - name: Add cache for cargo - uses: actions/cache@v2 + id: cache + uses: actions/cache@v3 with: path: | # Taken from . @@ -61,11 +62,11 @@ jobs: restore-keys: ${{ runner.os }}-cargo - name: Install rustup-toolchain-install-master and xargo + if: ${{ steps.cache.outputs.cache-hit == 'false' }} shell: bash run: | - # Only install tools if we don't have them cached - if ! which rustup-toolchain-install-master; then cargo install rustup-toolchain-install-master; fi - if ! which xargo; then cargo install xargo; fi + cargo install rustup-toolchain-install-master + cargo install xargo - name: Install "master" toolchain shell: bash From 4b100a1b58767a4fd5884355072e27a42892babc Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Mon, 30 May 2022 12:17:36 +0000 Subject: [PATCH 3145/3747] Check that diagnostics happen in the line that they are annotated for --- Cargo.lock | 45 +++ src/bin/miri.rs | 11 +- tests/compile-fail/intrinsics/assume.rs | 2 +- tests/compile-fail/no_main.stderr | 2 + .../sync/libc_pthread_cond_double_destroy.rs | 2 +- .../libc_pthread_condattr_double_destroy.rs | 2 +- .../sync/libc_pthread_mutex_double_destroy.rs | 2 +- .../libc_pthread_mutexattr_double_destroy.rs | 2 +- .../libc_pthread_rwlock_double_destroy.rs | 2 +- ui_test/Cargo.lock | 45 +++ ui_test/Cargo.toml | 2 + ui_test/README.md | 6 +- ui_test/src/comments.rs | 36 ++- ui_test/src/comments/tests.rs | 2 +- ui_test/src/lib.rs | 189 +++++++++-- ui_test/src/rustc_stderr.rs | 152 +++++++++ ui_test/src/tests.rs | 306 ++++++++++++++++-- 17 files changed, 734 insertions(+), 74 deletions(-) create mode 100644 ui_test/src/rustc_stderr.rs diff --git a/Cargo.lock b/Cargo.lock index 5377f9420b7c8..29b7e0bec26ad 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -193,6 +193,12 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "itoa" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "112c678d4050afce233f4f2852bb2eb519230b3cf12f33585275537d7e41578d" + [[package]] name = "lazy_static" version = "1.4.0" @@ -446,6 +452,12 @@ dependencies = [ "semver", ] +[[package]] +name = "ryu" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3f6f92acf49d1b98f7a81226834412ada05458b7364277387724a237f062695" + [[package]] name = "scopeguard" version = "1.1.0" @@ -458,6 +470,37 @@ version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8cb243bdfdb5936c8dc3c45762a19d12ab4550cdc753bc247637d4ec35a040fd" +[[package]] +name = "serde" +version = "1.0.137" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61ea8d54c77f8315140a05f4c7237403bf38b72704d031543aa1d16abbf517d1" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.137" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f26faba0c3959972377d3b2d306ee9f71faee9714294e41bb777f83f88578be" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.81" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b7ce2b32a1aed03c558dc61a5cd328f15aff2dbc17daad8fb8af04d2100e15c" +dependencies = [ + "itoa", + "ryu", + "serde", +] + [[package]] name = "shell-escape" version = "0.1.5" @@ -500,6 +543,8 @@ dependencies = [ "pretty_assertions", "regex", "rustc_version", + "serde", + "serde_json", ] [[package]] diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 9c4cd0684c610..2cf5bc644dbff 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -19,7 +19,6 @@ use log::debug; use rustc_data_structures::sync::Lrc; use rustc_driver::Compilation; -use rustc_errors::emitter::{ColorConfig, HumanReadableErrorType}; use rustc_hir::{self as hir, def_id::LOCAL_CRATE, Node}; use rustc_interface::interface::Config; use rustc_middle::{ @@ -28,7 +27,7 @@ use rustc_middle::{ }, ty::{query::ExternProviders, TyCtxt}, }; -use rustc_session::{config::ErrorOutputType, search_paths::PathKind, CtfeBacktrace}; +use rustc_session::{search_paths::PathKind, CtfeBacktrace}; use miri::{BacktraceStyle, ProvenanceMode}; @@ -64,13 +63,7 @@ impl rustc_driver::Callbacks for MiriCompilerCalls { let (entry_def_id, entry_type) = if let Some(entry_def) = tcx.entry_fn(()) { entry_def } else { - let output_ty = ErrorOutputType::HumanReadable(HumanReadableErrorType::Default( - ColorConfig::Auto, - )); - rustc_session::early_error( - output_ty, - "miri can only run programs that have a main function", - ); + tcx.sess.fatal("miri can only run programs that have a main function"); }; let mut config = self.miri_config.clone(); diff --git a/tests/compile-fail/intrinsics/assume.rs b/tests/compile-fail/intrinsics/assume.rs index 7b18cab798057..ad193d8499181 100644 --- a/tests/compile-fail/intrinsics/assume.rs +++ b/tests/compile-fail/intrinsics/assume.rs @@ -5,6 +5,6 @@ fn main() { unsafe { std::intrinsics::assume(x < 10); std::intrinsics::assume(x > 1); - std::intrinsics::assume(x > 42); //~ `assume` intrinsic called with `false` + std::intrinsics::assume(x > 42); //~ ERROR `assume` intrinsic called with `false` } } diff --git a/tests/compile-fail/no_main.stderr b/tests/compile-fail/no_main.stderr index 52591a8d6da31..88bdfb4e387cf 100644 --- a/tests/compile-fail/no_main.stderr +++ b/tests/compile-fail/no_main.stderr @@ -1,2 +1,4 @@ error: miri can only run programs that have a main function +error: aborting due to previous error + diff --git a/tests/compile-fail/sync/libc_pthread_cond_double_destroy.rs b/tests/compile-fail/sync/libc_pthread_cond_double_destroy.rs index c376618357d27..18be75b308cf0 100644 --- a/tests/compile-fail/sync/libc_pthread_cond_double_destroy.rs +++ b/tests/compile-fail/sync/libc_pthread_cond_double_destroy.rs @@ -17,6 +17,6 @@ fn main() { libc::pthread_cond_destroy(cond.as_mut_ptr()); libc::pthread_cond_destroy(cond.as_mut_ptr()); - //~^ Undefined Behavior: using uninitialized data, but this operation requires initialized memory + //~^ ERROR Undefined Behavior: using uninitialized data, but this operation requires initialized memory } } diff --git a/tests/compile-fail/sync/libc_pthread_condattr_double_destroy.rs b/tests/compile-fail/sync/libc_pthread_condattr_double_destroy.rs index 44af51a3e8711..1543a5841ad28 100644 --- a/tests/compile-fail/sync/libc_pthread_condattr_double_destroy.rs +++ b/tests/compile-fail/sync/libc_pthread_condattr_double_destroy.rs @@ -14,6 +14,6 @@ fn main() { libc::pthread_condattr_destroy(attr.as_mut_ptr()); libc::pthread_condattr_destroy(attr.as_mut_ptr()); - //~^ Undefined Behavior: using uninitialized data, but this operation requires initialized memory + //~^ ERROR Undefined Behavior: using uninitialized data, but this operation requires initialized memory } } diff --git a/tests/compile-fail/sync/libc_pthread_mutex_double_destroy.rs b/tests/compile-fail/sync/libc_pthread_mutex_double_destroy.rs index 08abc0ca12c5b..3710810cd2c33 100644 --- a/tests/compile-fail/sync/libc_pthread_mutex_double_destroy.rs +++ b/tests/compile-fail/sync/libc_pthread_mutex_double_destroy.rs @@ -18,6 +18,6 @@ fn main() { libc::pthread_mutex_destroy(mutex.as_mut_ptr()); libc::pthread_mutex_destroy(mutex.as_mut_ptr()); - //~^ Undefined Behavior: using uninitialized data, but this operation requires initialized memory + //~^ ERROR Undefined Behavior: using uninitialized data, but this operation requires initialized memory } } diff --git a/tests/compile-fail/sync/libc_pthread_mutexattr_double_destroy.rs b/tests/compile-fail/sync/libc_pthread_mutexattr_double_destroy.rs index 69ca3ad512fa2..c232780ee2ea3 100644 --- a/tests/compile-fail/sync/libc_pthread_mutexattr_double_destroy.rs +++ b/tests/compile-fail/sync/libc_pthread_mutexattr_double_destroy.rs @@ -14,6 +14,6 @@ fn main() { libc::pthread_mutexattr_destroy(attr.as_mut_ptr()); libc::pthread_mutexattr_destroy(attr.as_mut_ptr()); - //~^ Undefined Behavior: using uninitialized data, but this operation requires initialized memory + //~^ ERROR Undefined Behavior: using uninitialized data, but this operation requires initialized memory } } diff --git a/tests/compile-fail/sync/libc_pthread_rwlock_double_destroy.rs b/tests/compile-fail/sync/libc_pthread_rwlock_double_destroy.rs index d20c78155fd2c..055bb1af489f4 100644 --- a/tests/compile-fail/sync/libc_pthread_rwlock_double_destroy.rs +++ b/tests/compile-fail/sync/libc_pthread_rwlock_double_destroy.rs @@ -11,6 +11,6 @@ fn main() { libc::pthread_rwlock_destroy(&mut lock); libc::pthread_rwlock_destroy(&mut lock); - //~^ Undefined Behavior: using uninitialized data, but this operation requires initialized memory + //~^ ERROR Undefined Behavior: using uninitialized data, but this operation requires initialized memory } } diff --git a/ui_test/Cargo.lock b/ui_test/Cargo.lock index 185af43ac0b41..5a4cdb892713e 100644 --- a/ui_test/Cargo.lock +++ b/ui_test/Cargo.lock @@ -148,6 +148,12 @@ dependencies = [ "libc", ] +[[package]] +name = "itoa" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "112c678d4050afce233f4f2852bb2eb519230b3cf12f33585275537d7e41578d" + [[package]] name = "lazy_static" version = "1.4.0" @@ -240,6 +246,12 @@ dependencies = [ "semver", ] +[[package]] +name = "ryu" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3f6f92acf49d1b98f7a81226834412ada05458b7364277387724a237f062695" + [[package]] name = "scopeguard" version = "1.1.0" @@ -252,6 +264,37 @@ version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8cb243bdfdb5936c8dc3c45762a19d12ab4550cdc753bc247637d4ec35a040fd" +[[package]] +name = "serde" +version = "1.0.137" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61ea8d54c77f8315140a05f4c7237403bf38b72704d031543aa1d16abbf517d1" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.137" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f26faba0c3959972377d3b2d306ee9f71faee9714294e41bb777f83f88578be" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.81" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b7ce2b32a1aed03c558dc61a5cd328f15aff2dbc17daad8fb8af04d2100e15c" +dependencies = [ + "itoa", + "ryu", + "serde", +] + [[package]] name = "syn" version = "1.0.95" @@ -273,6 +316,8 @@ dependencies = [ "pretty_assertions", "regex", "rustc_version", + "serde", + "serde_json", ] [[package]] diff --git a/ui_test/Cargo.toml b/ui_test/Cargo.toml index 66d35fdd2228a..92c00915cbfeb 100644 --- a/ui_test/Cargo.toml +++ b/ui_test/Cargo.toml @@ -12,3 +12,5 @@ regex = "1.5.5" pretty_assertions = "1.2.1" crossbeam = "0.8.1" lazy_static = "1.4.0" +serde = { version = "1.0", features = ["derive"] } +serde_json = "1.0" diff --git a/ui_test/README.md b/ui_test/README.md index fdd94a74823e2..b3c9a3378cf30 100644 --- a/ui_test/README.md +++ b/ui_test/README.md @@ -11,9 +11,9 @@ Note that the space after `//`, when it is present, is *not* optional -- it must * `// stderr-per-bitwidth` produces one stderr file per bitwidth, as they may differ significantly sometimes * `// error-pattern: XXX` make sure the stderr output contains `XXX` * `//~ ERROR: XXX` make sure the stderr output contains `XXX` for an error in the line where this comment is written - * NOTE: it is not checked at present that it is actually in the line where the error occurred, or that it is truly an ERROR/WARNING/HELP/NOTE, but you should treat it as such until that becomes true. - * Also supports `HELP` or `WARN` for different kind of message - * if the all caps note is left out, any message is matched + * Also supports `HELP`, `WARN` or `NOTE` for different kind of message + * if one of those levels is specified explicitly, *all* diagnostics of this level or higher need an annotation. If you want to avoid this, just leave out the all caps level note entirely. + * If the all caps note is left out, a message of any level is matched. Leaving it out is not allowed for `ERROR` levels. * This checks the output *before* normalization, so you can check things that get normalized away, but need to be careful not to accidentally have a pattern that differs between platforms. * `// revisions: XXX YYY` runs the test once for each space separated name in the list diff --git a/ui_test/src/comments.rs b/ui_test/src/comments.rs index e6e45de4160e0..cc9870a63be4b 100644 --- a/ui_test/src/comments.rs +++ b/ui_test/src/comments.rs @@ -2,6 +2,8 @@ use std::path::Path; use regex::Regex; +use crate::rustc_stderr::Level; + #[cfg(test)] mod tests; @@ -33,7 +35,11 @@ pub(crate) struct Comments { pub(crate) struct ErrorMatch { pub matched: String, pub revision: Option, + pub level: Option, + /// The line where the message was defined, for reporting issues with it (e.g. in case it wasn't found). pub definition_line: usize, + /// The line this pattern is expecting to find a message in. + pub line: usize, } impl Comments { @@ -47,9 +53,13 @@ impl Comments { pub(crate) fn parse(path: &Path, content: &str) -> Self { let mut this = Self::default(); let error_pattern_regex = - Regex::new(r"//(\[(?P[^\]]+)\])?~[|^]*\s*(ERROR|HELP|WARN)?:?(?P.*)") + Regex::new(r"//(\[(?P[^\]]+)\])?~(?P\||[\^]+)?\s*(?PERROR|HELP|WARN|NOTE)?:?(?P.*)") .unwrap(); + + // The line that a `|` will refer to + let mut fallthrough_to = None; for (l, line) in content.lines().enumerate() { + let l = l + 1; // enumerate starts at 0, but line numbers start at 1 if let Some(revisions) = line.strip_prefix("// revisions:") { assert_eq!( this.revisions, @@ -113,7 +123,29 @@ impl Comments { let matched = captures["text"].trim().to_string(); let revision = captures.name("revision").map(|rev| rev.as_str().to_string()); - this.error_matches.push(ErrorMatch { matched, revision, definition_line: l }); + + let level = captures.name("level").map(|rev| rev.as_str().parse().unwrap()); + + let match_line = match captures.name("offset").map(|rev| rev.as_str()) { + Some("|") => fallthrough_to.expect("`//~|` pattern without preceding line"), + Some(pat) => { + debug_assert!(pat.chars().all(|c| c == '^')); + l - pat.len() + } + None => l, + }; + + fallthrough_to = Some(match_line); + + this.error_matches.push(ErrorMatch { + matched, + revision, + level, + definition_line: l, + line: match_line, + }); + } else { + fallthrough_to = None; } } this diff --git a/ui_test/src/comments/tests.rs b/ui_test/src/comments/tests.rs index 0140fdf4a9c6e..ef9662241424a 100644 --- a/ui_test/src/comments/tests.rs +++ b/ui_test/src/comments/tests.rs @@ -13,7 +13,7 @@ fn main() { "; let comments = Comments::parse(Path::new(""), s); println!("parsed comments: {:#?}", comments); - assert_eq!(comments.error_matches[0].definition_line, 4); + assert_eq!(comments.error_matches[0].definition_line, 5); assert_eq!(comments.error_matches[0].revision, None); assert_eq!( comments.error_matches[0].matched, diff --git a/ui_test/src/lib.rs b/ui_test/src/lib.rs index 6052efe02e06a..4a9cdd386ac27 100644 --- a/ui_test/src/lib.rs +++ b/ui_test/src/lib.rs @@ -8,10 +8,12 @@ use colored::*; use comments::ErrorMatch; use crossbeam::queue::SegQueue; use regex::Regex; +use rustc_stderr::{Level, Message}; use crate::comments::Comments; mod comments; +mod rustc_stderr; #[cfg(test)] mod tests; @@ -100,7 +102,8 @@ pub fn run_tests(config: Config) { for revision in comments.revisions.clone().unwrap_or_else(|| vec![String::new()]) { - let (m, errors) = run_test(&path, &config, &target, &revision, &comments); + let (m, errors, stderr) = + run_test(&path, &config, &target, &revision, &comments); // Using a single `eprintln!` to prevent messages from threads from getting intermingled. let mut msg = format!("{} ", path.display()); @@ -113,7 +116,13 @@ pub fn run_tests(config: Config) { succeeded.fetch_add(1, Ordering::Relaxed); } else { eprintln!("{msg}{}", "FAILED".red().bold()); - failures.lock().unwrap().push((path.clone(), m, revision, errors)); + failures.lock().unwrap().push(( + path.clone(), + m, + revision, + errors, + stderr, + )); } } } @@ -128,7 +137,7 @@ pub fn run_tests(config: Config) { let ignored = ignored.load(Ordering::Relaxed); let filtered = filtered.load(Ordering::Relaxed); if !failures.is_empty() { - for (path, miri, revision, errors) in &failures { + for (path, miri, revision, errors, stderr) in &failures { eprintln!(); eprint!("{}", path.display().to_string().underline()); if !revision.is_empty() { @@ -138,32 +147,63 @@ pub fn run_tests(config: Config) { eprintln!(); eprintln!("command: {:?}", miri); eprintln!(); - let mut dump_stderr = None; + // `None` means never dump, as we already dumped it for an `OutputDiffers` + // `Some(false)` means there's no reason to dump, as all errors are independent of the stderr + // `Some(true)` means that there was a pattern in the .rs file that was not found in the output. + let mut dump_stderr = Some(false); for error in errors { match error { Error::ExitStatus(mode, exit_status) => eprintln!("{mode:?} got {exit_status}"), - Error::PatternNotFound { stderr, pattern, definition_line } => { + Error::PatternNotFound { pattern, definition_line } => { eprintln!("`{pattern}` {} in stderr output", "not found".red()); eprintln!( "expected because of pattern here: {}:{definition_line}", path.display().to_string().bold() ); - dump_stderr = Some(stderr.clone()) + dump_stderr = dump_stderr.map(|_| true); + } + Error::NoPatternsFound => { + eprintln!("{}", "no error patterns found in failure test".red()); } - Error::NoPatternsFound => - eprintln!("{}", "no error patterns found in failure test".red()), Error::PatternFoundInPassTest => eprintln!("{}", "error pattern found in success test".red()), Error::OutputDiffers { path, actual, expected } => { - dump_stderr = None; + if path.extension().unwrap() == "stderr" { + dump_stderr = None; + } eprintln!("actual output differed from expected {}", path.display()); eprintln!("{}", pretty_assertions::StrComparison::new(expected, actual)); eprintln!() } + Error::ErrorsWithoutPattern { path: None, msgs } => { + eprintln!( + "There were {} unmatched diagnostics that occurred outside the testfile and had not pattern", + msgs.len(), + ); + for Message { level, message } in msgs { + eprintln!(" {level:?}: {message}") + } + } + Error::ErrorsWithoutPattern { path: Some((path, line)), msgs } => { + eprintln!( + "There were {} unmatched diagnostics at {}:{line}", + msgs.len(), + path.display() + ); + for Message { level, message } in msgs { + eprintln!(" {level:?}: {message}") + } + } + Error::ErrorPatternWithoutErrorAnnotation(path, line) => { + eprintln!( + "Annotation at {}:{line} matched an error diagnostic but did not have `ERROR` before its message", + path.display() + ); + } } eprintln!(); } - if let Some(stderr) = dump_stderr { + if let Some(true) = dump_stderr { eprintln!("actual stderr:"); eprintln!("{}", stderr); eprintln!(); @@ -195,7 +235,6 @@ enum Error { /// Got an invalid exit status for the given mode. ExitStatus(Mode, ExitStatus), PatternNotFound { - stderr: String, pattern: String, definition_line: usize, }, @@ -209,6 +248,11 @@ enum Error { actual: String, expected: String, }, + ErrorsWithoutPattern { + msgs: Vec, + path: Option<(PathBuf, usize)>, + }, + ErrorPatternWithoutErrorAnnotation(PathBuf, usize), } type Errors = Vec; @@ -219,7 +263,7 @@ fn run_test( target: &str, revision: &str, comments: &Comments, -) -> (Command, Errors) { +) -> (Command, Errors, String) { // Run miri let mut miri = Command::new(&config.program); miri.args(config.args.iter()); @@ -227,6 +271,7 @@ fn run_test( if !revision.is_empty() { miri.arg(format!("--cfg={revision}")); } + miri.arg("--error-format=json"); for arg in &comments.compile_flags { miri.arg(arg); } @@ -235,7 +280,7 @@ fn run_test( } let output = miri.output().expect("could not execute miri"); let mut errors = config.mode.ok(output.status); - check_test_result( + let stderr = check_test_result( path, config, target, @@ -245,7 +290,7 @@ fn run_test( &output.stdout, &output.stderr, ); - (miri, errors) + (miri, errors, stderr) } fn check_test_result( @@ -257,11 +302,9 @@ fn check_test_result( errors: &mut Errors, stdout: &[u8], stderr: &[u8], -) { +) -> String { // Always remove annotation comments from stderr. - let annotations = Regex::new(r"\s*//~.*").unwrap(); - let stderr = std::str::from_utf8(stderr).unwrap(); - let stderr = annotations.replace_all(stderr, ""); + let diagnostics = rustc_stderr::process(path, stderr); let stdout = std::str::from_utf8(stdout).unwrap(); // Check output files (if any) let revised = |extension: &str| { @@ -273,7 +316,7 @@ fn check_test_result( }; // Check output files against actual output check_output( - &stderr, + &diagnostics.rendered, path, errors, revised("stderr"), @@ -293,50 +336,126 @@ fn check_test_result( comments, ); // Check error annotations in the source against output - check_annotations(&stderr, errors, config, revision, comments); + check_annotations( + diagnostics.messages, + diagnostics.messages_from_unknown_file_or_line, + path, + errors, + config, + revision, + comments, + ); + diagnostics.rendered } fn check_annotations( - unnormalized_stderr: &str, + mut messages: Vec>, + mut messages_from_unknown_file_or_line: Vec, + path: &Path, errors: &mut Errors, config: &Config, revision: &str, comments: &Comments, ) { - let mut found_annotation = false; if let Some((ref error_pattern, definition_line)) = comments.error_pattern { - if !unnormalized_stderr.contains(error_pattern) { + let mut found = false; + + // first check the diagnostics messages outside of our file. We check this first, so that + // you can mix in-file annotations with // error-pattern annotations, even if there is overlap + // in the messages. + if let Some(i) = messages_from_unknown_file_or_line + .iter() + .position(|msg| msg.message.contains(error_pattern)) + { + messages_from_unknown_file_or_line.remove(i); + found = true; + } + + // if nothing was found, check the ones inside our file. We permit this because some tests may have + // flaky line numbers for their messages. + if !found { + for line in &mut messages { + if let Some(i) = line.iter().position(|msg| msg.message.contains(error_pattern)) { + line.remove(i); + found = true; + break; + } + } + } + + if !found { errors.push(Error::PatternNotFound { - stderr: unnormalized_stderr.to_string(), pattern: error_pattern.to_string(), definition_line, }); } - found_annotation = true; } - for &ErrorMatch { ref matched, revision: ref rev, definition_line } in &comments.error_matches { - // FIXME: check that the error happens on the marked line + // The order on `Level` is such that `Error` is the highest level. + // We will ensure that *all* diagnostics of level at least `lowest_annotation_level` + // are matched. + let mut lowest_annotation_level = Level::Error; + for &ErrorMatch { ref matched, revision: ref rev, definition_line, line, level } in + &comments.error_matches + { if let Some(rev) = rev { if rev != revision { continue; } } + if let Some(level) = level { + // If we found a diagnostic with a level annotation, make sure that all + // diagnostics of that level have annotations, even if we don't end up finding a matching diagnostic + // for this pattern. + lowest_annotation_level = std::cmp::min(lowest_annotation_level, level); + } - if !unnormalized_stderr.contains(matched) { - errors.push(Error::PatternNotFound { - stderr: unnormalized_stderr.to_string(), - pattern: matched.to_string(), - definition_line, + if let Some(msgs) = messages.get_mut(line) { + let found = msgs.iter().position(|msg| { + msg.message.contains(matched) + // in case there is no level on the annotation, match any level. + && level.map_or(true, |level| { + msg.level == level + }) }); + if let Some(found) = found { + let msg = msgs.remove(found); + if msg.level == Level::Error && level.is_none() { + errors + .push(Error::ErrorPatternWithoutErrorAnnotation(path.to_path_buf(), line)); + } + continue; + } } - found_annotation = true; + + errors.push(Error::PatternNotFound { pattern: matched.to_string(), definition_line }); + } + + let filter = |msgs: Vec| -> Vec<_> { + msgs.into_iter().filter(|msg| msg.level >= lowest_annotation_level).collect() + }; + + let messages_from_unknown_file_or_line = filter(messages_from_unknown_file_or_line); + if !messages_from_unknown_file_or_line.is_empty() { + errors.push(Error::ErrorsWithoutPattern { + path: None, + msgs: messages_from_unknown_file_or_line, + }); } - match (config.mode, found_annotation) { + + for (line, msgs) in messages.into_iter().enumerate() { + let msgs = filter(msgs); + if !msgs.is_empty() { + errors + .push(Error::ErrorsWithoutPattern { path: Some((path.to_path_buf(), line)), msgs }); + } + } + + match (config.mode, comments.error_pattern.is_some() || !comments.error_matches.is_empty()) { (Mode::Pass, true) | (Mode::Panic, true) => errors.push(Error::PatternFoundInPassTest), (Mode::Fail, false) => errors.push(Error::NoPatternsFound), _ => {} - }; + } } fn check_output( diff --git a/ui_test/src/rustc_stderr.rs b/ui_test/src/rustc_stderr.rs new file mode 100644 index 0000000000000..ac76a78a3cbcb --- /dev/null +++ b/ui_test/src/rustc_stderr.rs @@ -0,0 +1,152 @@ +use std::{ + fmt::Write, + path::{Path, PathBuf}, +}; + +use regex::Regex; + +#[derive(serde::Deserialize, Debug)] +struct RustcMessage { + rendered: Option, + spans: Vec, + level: String, + message: String, + children: Vec, +} + +#[derive(Copy, Clone, Debug, PartialOrd, Ord, PartialEq, Eq)] +pub(crate) enum Level { + Error = 4, + Warn = 3, + Help = 2, + Note = 1, + /// Only used for "For more information about this error, try `rustc --explain EXXXX`". + FailureNote = 0, +} + +#[derive(Debug)] +pub(crate) struct Message { + pub(crate) level: Level, + pub(crate) message: String, +} + +/// Information about macro expansion. +#[derive(serde::Deserialize, Debug)] +struct Expansion { + span: Span, +} + +#[derive(serde::Deserialize, Debug)] +struct Span { + line_start: usize, + file_name: PathBuf, + expansion: Option>, +} + +impl std::str::FromStr for Level { + type Err = String; + fn from_str(s: &str) -> Result { + match s { + "ERROR" | "error" => Ok(Self::Error), + "WARN" | "warning" => Ok(Self::Warn), + "HELP" | "help" => Ok(Self::Help), + "NOTE" | "note" => Ok(Self::Note), + "failure-note" => Ok(Self::FailureNote), + _ => Err(format!("unknown level `{s}`")), + } + } +} + +#[derive(Debug)] +pub(crate) struct Diagnostics { + /// Rendered and concatenated version of all diagnostics. + /// This is equivalent to non-json diagnostics. + pub rendered: String, + /// Per line, a list of messages for that line. + pub messages: Vec>, + /// Messages not on any line (usually because they are from libstd) + pub messages_from_unknown_file_or_line: Vec, +} + +impl RustcMessage { + fn line(&self, file: &Path) -> Option { + self.spans.iter().find_map(|span| span.line(file)) + } + + /// Put the message and its children into the line-indexed list. + fn insert_recursive( + self, + file: &Path, + messages: &mut Vec>, + messages_from_unknown_file_or_line: &mut Vec, + line: Option, + ) { + let line = self.line(file).or(line); + let msg = Message { level: self.level.parse().unwrap(), message: self.message }; + if let Some(line) = line { + if messages.len() <= line { + messages.resize_with(line + 1, Vec::new); + } + messages[line].push(msg); + // All other messages go into the general bin, unless they are specifically of the + // "aborting due to X previous errors" variety, as we never want to match those. They + // only count the number of errors and provide no useful information about the tests. + } else if !(msg.message.starts_with("aborting due to") + && msg.message.contains("previous error")) + { + messages_from_unknown_file_or_line.push(msg); + } + for child in self.children { + child.insert_recursive(file, messages, messages_from_unknown_file_or_line, line) + } + } +} + +impl Span { + /// Returns a line number *in the given file*, if possible. + fn line(&self, file: &Path) -> Option { + if self.file_name == file { + Some(self.line_start) + } else { + self.expansion.as_ref()?.span.line(file) + } + } +} + +pub(crate) fn filter_annotations_from_rendered(rendered: &str) -> std::borrow::Cow<'_, str> { + let annotations = Regex::new(r"\s*//~.*").unwrap(); + annotations.replace_all(&rendered, "") +} + +pub(crate) fn process(file: &Path, stderr: &[u8]) -> Diagnostics { + let stderr = std::str::from_utf8(&stderr).unwrap(); + let mut rendered = String::new(); + let mut messages = vec![]; + let mut messages_from_unknown_file_or_line = vec![]; + for line in stderr.lines() { + if line.starts_with("{") { + match serde_json::from_str::(line) { + Ok(msg) => { + write!( + rendered, + "{}", + filter_annotations_from_rendered(msg.rendered.as_ref().unwrap()) + ) + .unwrap(); + msg.insert_recursive( + file, + &mut messages, + &mut messages_from_unknown_file_or_line, + None, + ); + } + Err(err) => + panic!("failed to parse rustc JSON output at line: {}\nerr:{}", line, err), + } + } else { + // FIXME: do we want to throw interpreter stderr into a separate file? + writeln!(rendered, "{}", line).unwrap(); + } + } + Diagnostics { rendered, messages, messages_from_unknown_file_or_line } +} diff --git a/ui_test/src/tests.rs b/ui_test/src/tests.rs index d0ef1195d888a..7e08a68be7b9a 100644 --- a/ui_test/src/tests.rs +++ b/ui_test/src/tests.rs @@ -1,5 +1,8 @@ use std::path::{Path, PathBuf}; +use crate::rustc_stderr::Level; +use crate::rustc_stderr::Message; + use super::*; fn config() -> Config { @@ -29,25 +32,292 @@ fn main() { let comments = Comments::parse(&path, s); let mut errors = vec![]; let config = config(); - // Crucially, the intended error string *does* appear in this output, as a quote of the comment itself. - let stderr = br" -error: Undefined Behavior: type validation failed: encountered a dangling reference (address 0x10 is unallocated) - --> tests/compile-fail/validity/dangling_ref1.rs:6:29 - | -LL | let _x: &i32 = unsafe { mem::transmute(16usize) }; //~ ERROR encountered a dangling reference (address $HEX is unallocated) - | ^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a dangling reference (address 0x10 is unallocated) - | - = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior - = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - - = note: inside `main` at tests/compile-fail/validity/dangling_ref1.rs:6:29 -note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace -error: aborting due to previous error + let messages = vec![ + vec![], vec![], vec![], vec![], vec![], + vec![ + Message { + message:"Undefined Behavior: type validation failed: encountered a dangling reference (address 0x10 is unallocated)".to_string(), + level: Level::Error, + } + ] + ]; + check_annotations(messages, vec![], Path::new("moobar"), &mut errors, &config, "", &comments); + match &errors[..] { + [ + Error::PatternNotFound { definition_line: 5, .. }, + Error::ErrorsWithoutPattern { path: Some((_, 5)), .. }, + ] => {} + _ => panic!("{:#?}", errors), + } +} + +#[test] +fn find_pattern() { + let s = r" +use std::mem; + +fn main() { + let _x: &i32 = unsafe { mem::transmute(16usize) }; //~ ERROR encountered a dangling reference (address 0x10 is unallocated) +} + "; + let comments = Comments::parse(Path::new(""), s); + let config = config(); + { + let messages = vec![vec![], vec![], vec![], vec![], vec![], vec![ + Message { + message: "Undefined Behavior: type validation failed: encountered a dangling reference (address 0x10 is unallocated)".to_string(), + level: Level::Error, + } + ] + ]; + let mut errors = vec![]; + check_annotations( + messages, + vec![], + Path::new("moobar"), + &mut errors, + &config, + "", + &comments, + ); + match &errors[..] { + [] => {} + _ => panic!("{:#?}", errors), + } + } + + // only difference to above is a wrong line number + { + let messages = vec![vec![], vec![], vec![], vec![], vec![ + Message { + message: "Undefined Behavior: type validation failed: encountered a dangling reference (address 0x10 is unallocated)".to_string(), + level: Level::Error, + } + ] + ]; + let mut errors = vec![]; + check_annotations( + messages, + vec![], + Path::new("moobar"), + &mut errors, + &config, + "", + &comments, + ); + match &errors[..] { + [ + Error::PatternNotFound { definition_line: 5, .. }, + Error::ErrorsWithoutPattern { path: Some((_, 4)), .. }, + ] => {} + _ => panic!("not the expected error: {:#?}", errors), + } + } + + // only difference to first is a wrong level + { + let messages = vec![ + vec![], vec![], vec![], vec![], vec![], + vec![ + Message { + message: "Undefined Behavior: type validation failed: encountered a dangling reference (address 0x10 is unallocated)".to_string(), + level: Level::Note, + } + ] + ]; + let mut errors = vec![]; + check_annotations( + messages, + vec![], + Path::new("moobar"), + &mut errors, + &config, + "", + &comments, + ); + match &errors[..] { + // Note no `ErrorsWithoutPattern`, because there are no `//~NOTE` in the test file, so we ignore them + [Error::PatternNotFound { definition_line: 5, .. }] => {} + _ => panic!("not the expected error: {:#?}", errors), + } + } +} + +#[test] +fn duplicate_pattern() { + let s = r" +use std::mem; + +fn main() { + let _x: &i32 = unsafe { mem::transmute(16usize) }; //~ ERROR encountered a dangling reference (address 0x10 is unallocated) + //~^ ERROR encountered a dangling reference (address 0x10 is unallocated) +} + "; + let comments = Comments::parse(Path::new(""), s); + let config = config(); + let messages = vec![ + vec![], vec![], vec![], vec![], vec![], + vec![ + Message { + message: "Undefined Behavior: type validation failed: encountered a dangling reference (address 0x10 is unallocated)".to_string(), + level: Level::Error, + } + ] + ]; + let mut errors = vec![]; + check_annotations(messages, vec![], Path::new("moobar"), &mut errors, &config, "", &comments); + match &errors[..] { + [Error::PatternNotFound { definition_line: 6, .. }] => {} + _ => panic!("{:#?}", errors), + } +} + +#[test] +fn missing_pattern() { + let s = r" +use std::mem; + +fn main() { + let _x: &i32 = unsafe { mem::transmute(16usize) }; //~ ERROR encountered a dangling reference (address 0x10 is unallocated) +} + "; + let comments = Comments::parse(Path::new(""), s); + let config = config(); + let messages = vec![ + vec![], vec![], vec![], vec![], vec![], + vec![ + Message { + message: "Undefined Behavior: type validation failed: encountered a dangling reference (address 0x10 is unallocated)".to_string(), + level: Level::Error, + }, + Message { + message: "Undefined Behavior: type validation failed: encountered a dangling reference (address 0x10 is unallocated)".to_string(), + level: Level::Error, + } + ] + ]; + let mut errors = vec![]; + check_annotations(messages, vec![], Path::new("moobar"), &mut errors, &config, "", &comments); + match &errors[..] { + [Error::ErrorsWithoutPattern { path: Some((_, 5)), .. }] => {} + _ => panic!("{:#?}", errors), + } +} + +#[test] +fn missing_warn_pattern() { + let s = r" +use std::mem; + +fn main() { + let _x: &i32 = unsafe { mem::transmute(16usize) }; //~ ERROR encountered a dangling reference (address 0x10 is unallocated) + //~^ WARN cake +} + "; + let comments = Comments::parse(Path::new(""), s); + let config = config(); + let messages= vec![ + vec![], + vec![], + vec![], + vec![], + vec![], + vec![ + Message { + message: "Undefined Behavior: type validation failed: encountered a dangling reference (address 0x10 is unallocated)".to_string(), + level: Level::Error, + }, + Message { + message: "kaboom".to_string(), + level: Level::Warn, + }, + Message { + message: "cake".to_string(), + level: Level::Warn, + }, + ], + ]; + let mut errors = vec![]; + check_annotations(messages, vec![], Path::new("moobar"), &mut errors, &config, "", &comments); + match &errors[..] { + [Error::ErrorsWithoutPattern { path: Some((_, 5)), msgs, .. }] => + match &msgs[..] { + [Message { message, level: Level::Warn }] if message == "kaboom" => {} + _ => panic!("{:#?}", msgs), + }, + _ => panic!("{:#?}", errors), + } +} + +#[test] +fn missing_implicit_warn_pattern() { + let s = r" +use std::mem; + +fn main() { + let _x: &i32 = unsafe { mem::transmute(16usize) }; //~ ERROR encountered a dangling reference (address 0x10 is unallocated) + //~^ cake +} + "; + let comments = Comments::parse(Path::new(""), s); + let config = config(); + let messages = vec![ + vec![], + vec![], + vec![], + vec![], + vec![], + vec![ + Message { + message: "Undefined Behavior: type validation failed: encountered a dangling reference (address 0x10 is unallocated)".to_string(), + level: Level::Error, + }, + Message { + message: "kaboom".to_string(), + level: Level::Warn, + }, + Message { + message: "cake".to_string(), + level: Level::Warn, + }, + ], + ]; + let mut errors = vec![]; + check_annotations(messages, vec![], Path::new("moobar"), &mut errors, &config, "", &comments); + match &errors[..] { + [] => {} + _ => panic!("{:#?}", errors), + } +} + +#[test] +fn implicit_err_pattern() { + let s = r" +use std::mem; + +fn main() { + let _x: &i32 = unsafe { mem::transmute(16usize) }; //~ encountered a dangling reference (address 0x10 is unallocated) +} "; - check_test_result(&path, &config, "", "", &comments, &mut errors, /*stdout*/ br"", stderr); - // The "OutputDiffers" is because we cannot open the .rs file + let comments = Comments::parse(Path::new(""), s); + let config = config(); + let messages = vec![ + vec![], + vec![], + vec![], + vec![], + vec![], + vec![ + Message { + message: "Undefined Behavior: type validation failed: encountered a dangling reference (address 0x10 is unallocated)".to_string(), + level: Level::Error, + }, + ], + ]; + let mut errors = vec![]; + check_annotations(messages, vec![], Path::new("moobar"), &mut errors, &config, "", &comments); match &errors[..] { - [Error::OutputDiffers { .. }, Error::PatternNotFound { .. }] => {} - _ => panic!("not the expected error: {:#?}", errors), + [Error::ErrorPatternWithoutErrorAnnotation(_, 5)] => {} + _ => panic!("{:#?}", errors), } } From 9b9edc7440ee0c417403cc7c40f2aa3f72734fc7 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 1 Jun 2022 06:14:59 -0400 Subject: [PATCH 3146/3747] print list of failed tests in summary --- ui_test/src/lib.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/ui_test/src/lib.rs b/ui_test/src/lib.rs index 4a9cdd386ac27..0b076a5f51ec2 100644 --- a/ui_test/src/lib.rs +++ b/ui_test/src/lib.rs @@ -209,6 +209,11 @@ pub fn run_tests(config: Config) { eprintln!(); } } + eprintln!("{}", "failures:".red().underline()); + for (path, _miri, _revision, _errors, _stderr) in &failures { + eprintln!(" {}", path.display()); + } + eprintln!(); eprintln!( "test result: {}. {} tests failed, {} tests passed, {} ignored, {} filtered out", "FAIL".red(), From 3d634c975c7d7faf92a46d7d9a1a0267bd48e86a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 1 Jun 2022 10:53:38 -0400 Subject: [PATCH 3147/3747] rename test suite directories --- ci.sh | 2 +- tests/compiletest.rs | 6 +++--- tests/{compile-fail => fail}/abort-terminator.rs | 0 tests/{compile-fail => fail}/abort-terminator.stderr | 0 .../alloc/deallocate-bad-alignment.rs | 0 .../alloc/deallocate-bad-alignment.stderr | 0 tests/{compile-fail => fail}/alloc/deallocate-bad-size.rs | 0 .../{compile-fail => fail}/alloc/deallocate-bad-size.stderr | 0 tests/{compile-fail => fail}/alloc/deallocate-twice.rs | 0 tests/{compile-fail => fail}/alloc/deallocate-twice.stderr | 0 tests/{compile-fail => fail}/alloc/global_system_mixup.rs | 0 .../{compile-fail => fail}/alloc/global_system_mixup.stderr | 0 tests/{compile-fail => fail}/alloc/no_global_allocator.rs | 0 .../{compile-fail => fail}/alloc/no_global_allocator.stderr | 0 tests/{compile-fail => fail}/alloc/reallocate-bad-size.rs | 0 .../{compile-fail => fail}/alloc/reallocate-bad-size.stderr | 0 .../{compile-fail => fail}/alloc/reallocate-change-alloc.rs | 0 .../alloc/reallocate-change-alloc.stderr | 0 tests/{compile-fail => fail}/alloc/reallocate-dangling.rs | 0 .../{compile-fail => fail}/alloc/reallocate-dangling.stderr | 0 tests/{compile-fail => fail}/alloc/stack_free.rs | 0 tests/{compile-fail => fail}/alloc/stack_free.stderr | 0 .../{compile-fail => fail}/backtrace/bad-backtrace-decl.rs | 0 .../backtrace/bad-backtrace-decl.stderr | 0 .../{compile-fail => fail}/backtrace/bad-backtrace-flags.rs | 0 .../backtrace/bad-backtrace-flags.stderr | 0 tests/{compile-fail => fail}/backtrace/bad-backtrace-ptr.rs | 0 .../backtrace/bad-backtrace-ptr.stderr | 0 .../backtrace/bad-backtrace-resolve-flags.rs | 0 .../backtrace/bad-backtrace-resolve-flags.stderr | 0 .../backtrace/bad-backtrace-resolve-names-flags.rs | 0 .../backtrace/bad-backtrace-resolve-names-flags.stderr | 0 .../backtrace/bad-backtrace-size-flags.rs | 0 .../backtrace/bad-backtrace-size-flags.stderr | 0 .../backtrace/bad-backtrace-version.stderr | 0 tests/{compile-fail => fail}/box-cell-alias.rs | 0 tests/{compile-fail => fail}/box-cell-alias.stderr | 0 .../branchless-select-i128-pointer.rs | 0 .../branchless-select-i128-pointer.stderr | 0 tests/{compile-fail => fail}/breakpoint.rs | 0 tests/{compile-fail => fail}/breakpoint.stderr | 0 .../concurrency/libc_pthread_create_main_terminate.rs | 0 .../concurrency/libc_pthread_create_main_terminate.stderr | 0 .../concurrency/libc_pthread_join_detached.rs | 0 .../concurrency/libc_pthread_join_detached.stderr | 0 .../concurrency/libc_pthread_join_joined.rs | 0 .../concurrency/libc_pthread_join_joined.stderr | 0 .../concurrency/libc_pthread_join_main.rs | 0 .../concurrency/libc_pthread_join_main.stderr | 0 .../concurrency/libc_pthread_join_multiple.rs | 0 .../concurrency/libc_pthread_join_multiple.stderr | 0 .../concurrency/libc_pthread_join_self.rs | 0 .../concurrency/libc_pthread_join_self.stderr | 0 tests/{compile-fail => fail}/concurrency/thread-spawn.rs | 0 .../concurrency/thread_local_static_dealloc.rs | 0 .../concurrency/thread_local_static_dealloc.stderr | 0 tests/{compile-fail => fail}/concurrency/too_few_args.rs | 0 .../{compile-fail => fail}/concurrency/too_few_args.stderr | 0 tests/{compile-fail => fail}/concurrency/too_many_args.rs | 0 .../{compile-fail => fail}/concurrency/too_many_args.stderr | 0 .../concurrency/unwind_top_of_stack.rs | 0 .../concurrency/unwind_top_of_stack.stderr | 0 .../dangling_pointers/dangling_pointer_addr_of.rs | 0 .../dangling_pointers/dangling_pointer_addr_of.stderr | 0 .../dangling_pointers/dangling_pointer_deref.rs | 0 .../dangling_pointers/dangling_pointer_deref.stderr | 0 .../dangling_pointers/dangling_zst_deref.rs | 0 .../dangling_pointers/dangling_zst_deref.stderr | 0 .../dangling_pointers/deref-invalid-ptr.rs | 0 .../dangling_pointers/deref-invalid-ptr.stderr | 0 .../dangling_pointers/deref-partially-dangling.rs | 0 .../dangling_pointers/deref-partially-dangling.stderr | 0 tests/{compile-fail => fail}/dangling_pointers/dyn_size.rs | 0 .../dangling_pointers/dyn_size.stderr | 0 .../dangling_pointers/maybe_null_pointer_deref_zst.rs | 0 .../dangling_pointers/maybe_null_pointer_deref_zst.stderr | 0 .../dangling_pointers/maybe_null_pointer_write_zst.rs | 0 .../dangling_pointers/maybe_null_pointer_write_zst.stderr | 0 .../dangling_pointers/null_pointer_deref.rs | 0 .../dangling_pointers/null_pointer_deref.stderr | 0 .../dangling_pointers/null_pointer_deref_zst.rs | 0 .../dangling_pointers/null_pointer_deref_zst.stderr | 0 .../dangling_pointers/null_pointer_write.rs | 0 .../dangling_pointers/null_pointer_write.stderr | 0 .../dangling_pointers/null_pointer_write_zst.rs | 0 .../dangling_pointers/null_pointer_write_zst.stderr | 0 .../dangling_pointers/out_of_bounds_read1.rs | 0 .../dangling_pointers/out_of_bounds_read1.stderr | 0 .../dangling_pointers/out_of_bounds_read2.rs | 0 .../dangling_pointers/out_of_bounds_read2.stderr | 0 .../dangling_pointers/stack_temporary.rs | 0 .../dangling_pointers/stack_temporary.stderr | 0 .../dangling_pointers/storage_dead_dangling.rs | 0 .../dangling_pointers/storage_dead_dangling.stderr | 0 .../dangling_pointers/wild_pointer_deref.rs | 0 .../dangling_pointers/wild_pointer_deref.stderr | 0 tests/{compile-fail => fail}/data_race/alloc_read_race.rs | 0 .../{compile-fail => fail}/data_race/alloc_read_race.stderr | 0 tests/{compile-fail => fail}/data_race/alloc_write_race.rs | 0 .../data_race/alloc_write_race.stderr | 0 .../data_race/atomic_read_na_write_race1.rs | 0 .../data_race/atomic_read_na_write_race1.stderr | 0 .../data_race/atomic_read_na_write_race2.rs | 0 .../data_race/atomic_read_na_write_race2.stderr | 0 .../data_race/atomic_write_na_read_race1.rs | 0 .../data_race/atomic_write_na_read_race1.stderr | 0 .../data_race/atomic_write_na_read_race2.rs | 0 .../data_race/atomic_write_na_read_race2.stderr | 0 .../data_race/atomic_write_na_write_race1.rs | 0 .../data_race/atomic_write_na_write_race1.stderr | 0 .../data_race/atomic_write_na_write_race2.rs | 0 .../data_race/atomic_write_na_write_race2.stderr | 0 .../data_race/dangling_thread_async_race.rs | 0 .../data_race/dangling_thread_async_race.stderr | 0 .../data_race/dangling_thread_race.rs | 0 .../data_race/dangling_thread_race.stderr | 0 .../{compile-fail => fail}/data_race/dealloc_read_race1.rs | 0 .../data_race/dealloc_read_race1.stderr | 0 .../{compile-fail => fail}/data_race/dealloc_read_race2.rs | 0 .../data_race/dealloc_read_race2.stderr | 0 .../data_race/dealloc_read_race_stack.rs | 0 .../data_race/dealloc_read_race_stack.stderr | 0 .../{compile-fail => fail}/data_race/dealloc_write_race1.rs | 0 .../data_race/dealloc_write_race1.stderr | 0 .../{compile-fail => fail}/data_race/dealloc_write_race2.rs | 0 .../data_race/dealloc_write_race2.stderr | 0 .../data_race/dealloc_write_race_stack.rs | 0 .../data_race/dealloc_write_race_stack.stderr | 0 .../data_race/enable_after_join_to_main.rs | 0 .../data_race/enable_after_join_to_main.stderr | 0 tests/{compile-fail => fail}/data_race/read_write_race.rs | 0 .../{compile-fail => fail}/data_race/read_write_race.stderr | 0 .../data_race/read_write_race_stack.rs | 0 .../data_race/read_write_race_stack.stderr | 0 .../{compile-fail => fail}/data_race/relax_acquire_race.rs | 0 .../data_race/relax_acquire_race.stderr | 0 tests/{compile-fail => fail}/data_race/release_seq_race.rs | 0 .../data_race/release_seq_race.stderr | 0 .../data_race/release_seq_race_same_thread.rs | 0 .../data_race/release_seq_race_same_thread.stderr | 0 tests/{compile-fail => fail}/data_race/rmw_race.rs | 0 tests/{compile-fail => fail}/data_race/rmw_race.stderr | 0 tests/{compile-fail => fail}/data_race/write_write_race.rs | 0 .../data_race/write_write_race.stderr | 0 .../data_race/write_write_race_stack.rs | 0 .../data_race/write_write_race_stack.stderr | 0 tests/{compile-fail => fail}/environ-gets-deallocated.rs | 0 .../{compile-fail => fail}/environ-gets-deallocated.stderr | 0 tests/{compile-fail => fail}/erroneous_const.rs | 0 tests/{compile-fail => fail}/erroneous_const.stderr | 0 tests/{compile-fail => fail}/erroneous_const2.rs | 0 tests/{compile-fail => fail}/erroneous_const2.stderr | 0 tests/{compile-fail => fail}/extern_static.rs | 0 tests/{compile-fail => fail}/extern_static.stderr | 0 tests/{compile-fail => fail}/fast_math_both.rs | 0 tests/{compile-fail => fail}/fast_math_both.stderr | 0 tests/{compile-fail => fail}/fast_math_first.rs | 0 tests/{compile-fail => fail}/fast_math_first.stderr | 0 tests/{compile-fail => fail}/fast_math_second.rs | 0 tests/{compile-fail => fail}/fast_math_second.stderr | 0 tests/{compile-fail => fail}/fs/close_stdout.rs | 0 tests/{compile-fail => fail}/fs/close_stdout.stderr | 0 tests/{compile-fail => fail}/fs/isolated_file.rs | 0 tests/{compile-fail => fail}/fs/isolated_file.stderr | 0 tests/{compile-fail => fail}/fs/isolated_stdin.rs | 0 tests/{compile-fail => fail}/fs/isolated_stdin.stderr | 0 tests/{compile-fail => fail}/fs/read_from_stdout.rs | 0 tests/{compile-fail => fail}/fs/read_from_stdout.stderr | 0 .../fs/unix_open_missing_required_mode.rs | 0 .../fs/unix_open_missing_required_mode.stderr | 0 .../fs/unix_open_too_many_args.stderr | 0 tests/{compile-fail => fail}/fs/write_to_stdin.rs | 0 tests/{compile-fail => fail}/fs/write_to_stdin.stderr | 0 .../{compile-fail => fail}/function_calls/check_arg_abi.rs | 0 .../function_calls/check_arg_abi.stderr | 0 .../function_calls/check_arg_count_abort.rs | 0 .../function_calls/check_arg_count_abort.stderr | 0 .../function_calls/check_arg_count_too_few_args.rs | 0 .../function_calls/check_arg_count_too_few_args.stderr | 0 .../function_calls/check_arg_count_too_many_args.rs | 0 .../function_calls/check_arg_count_too_many_args.stderr | 0 .../function_calls/check_callback_abi.rs | 0 .../function_calls/check_callback_abi.stderr | 0 .../exported_symbol_abi_mismatch.cache.stderr | 0 .../exported_symbol_abi_mismatch.fn_ptr.stderr | 0 .../exported_symbol_abi_mismatch.no_cache.stderr | 0 .../function_calls/exported_symbol_abi_mismatch.rs | 0 .../function_calls/exported_symbol_bad_unwind1.rs | 0 .../function_calls/exported_symbol_bad_unwind1.stderr | 0 .../function_calls/exported_symbol_bad_unwind2.both.stderr | 0 .../exported_symbol_bad_unwind2.definition.stderr | 0 .../exported_symbol_bad_unwind2.extern_block.stderr | 0 .../function_calls/exported_symbol_bad_unwind2.rs | 0 .../function_calls/exported_symbol_clashing.rs | 0 .../function_calls/exported_symbol_clashing.stderr | 0 .../function_calls/exported_symbol_shim_clashing.rs | 0 .../function_calls/exported_symbol_shim_clashing.stderr | 0 .../function_calls/exported_symbol_wrong_arguments.rs | 0 .../function_calls/exported_symbol_wrong_arguments.stderr | 0 .../function_calls/exported_symbol_wrong_type.rs | 0 .../function_calls/exported_symbol_wrong_type.stderr | 0 .../function_pointers/cast_box_int_to_fn_ptr.rs | 0 .../function_pointers/cast_box_int_to_fn_ptr.stderr | 0 .../function_pointers/cast_fn_ptr1.rs | 0 .../function_pointers/cast_fn_ptr1.stderr | 0 .../function_pointers/cast_fn_ptr2.rs | 0 .../function_pointers/cast_fn_ptr2.stderr | 0 .../function_pointers/cast_fn_ptr3.rs | 0 .../function_pointers/cast_fn_ptr3.stderr | 0 .../function_pointers/cast_fn_ptr4.rs | 0 .../function_pointers/cast_fn_ptr4.stderr | 0 .../function_pointers/cast_fn_ptr5.rs | 0 .../function_pointers/cast_fn_ptr5.stderr | 0 .../function_pointers/cast_int_to_fn_ptr.rs | 0 .../function_pointers/cast_int_to_fn_ptr.stderr | 0 .../function_pointers/deref_fn_ptr.rs | 0 .../function_pointers/deref_fn_ptr.stderr | 0 .../function_pointers/execute_memory.rs | 0 .../function_pointers/execute_memory.stderr | 0 .../function_pointers/fn_ptr_offset.rs | 0 .../function_pointers/fn_ptr_offset.stderr | 0 tests/{compile-fail => fail}/generator-pinned-moved.rs | 0 tests/{compile-fail => fail}/generator-pinned-moved.stderr | 0 tests/{compile-fail => fail}/intrinsics/assume.rs | 0 tests/{compile-fail => fail}/intrinsics/assume.stderr | 0 tests/{compile-fail => fail}/intrinsics/copy_null.rs | 0 tests/{compile-fail => fail}/intrinsics/copy_null.stderr | 0 tests/{compile-fail => fail}/intrinsics/copy_overflow.rs | 0 .../{compile-fail => fail}/intrinsics/copy_overflow.stderr | 0 tests/{compile-fail => fail}/intrinsics/copy_overlapping.rs | 0 .../intrinsics/copy_overlapping.stderr | 0 tests/{compile-fail => fail}/intrinsics/copy_unaligned.rs | 0 .../{compile-fail => fail}/intrinsics/copy_unaligned.stderr | 0 tests/{compile-fail => fail}/intrinsics/ctlz_nonzero.rs | 0 tests/{compile-fail => fail}/intrinsics/ctlz_nonzero.stderr | 0 tests/{compile-fail => fail}/intrinsics/cttz_nonzero.rs | 0 tests/{compile-fail => fail}/intrinsics/cttz_nonzero.stderr | 0 tests/{compile-fail => fail}/intrinsics/div-by-zero.rs | 0 tests/{compile-fail => fail}/intrinsics/div-by-zero.stderr | 0 tests/{compile-fail => fail}/intrinsics/exact_div1.rs | 0 tests/{compile-fail => fail}/intrinsics/exact_div1.stderr | 0 tests/{compile-fail => fail}/intrinsics/exact_div2.rs | 0 tests/{compile-fail => fail}/intrinsics/exact_div2.stderr | 0 tests/{compile-fail => fail}/intrinsics/exact_div3.rs | 0 tests/{compile-fail => fail}/intrinsics/exact_div3.stderr | 0 tests/{compile-fail => fail}/intrinsics/exact_div4.rs | 0 tests/{compile-fail => fail}/intrinsics/exact_div4.stderr | 0 .../intrinsics/float_to_int_32_inf1.rs | 0 .../intrinsics/float_to_int_32_inf1.stderr | 0 .../intrinsics/float_to_int_32_infneg1.rs | 0 .../intrinsics/float_to_int_32_infneg1.stderr | 0 .../intrinsics/float_to_int_32_nan.rs | 0 .../intrinsics/float_to_int_32_nan.stderr | 0 .../intrinsics/float_to_int_32_nanneg.rs | 0 .../intrinsics/float_to_int_32_nanneg.stderr | 0 .../intrinsics/float_to_int_32_neg.rs | 0 .../intrinsics/float_to_int_32_neg.stderr | 0 .../intrinsics/float_to_int_32_too_big1.rs | 0 .../intrinsics/float_to_int_32_too_big1.stderr | 0 .../intrinsics/float_to_int_32_too_big2.rs | 0 .../intrinsics/float_to_int_32_too_big2.stderr | 0 .../intrinsics/float_to_int_32_too_small1.rs | 0 .../intrinsics/float_to_int_32_too_small1.stderr | 0 .../intrinsics/float_to_int_64_inf1.rs | 0 .../intrinsics/float_to_int_64_inf1.stderr | 0 .../intrinsics/float_to_int_64_infneg1.rs | 0 .../intrinsics/float_to_int_64_infneg1.stderr | 0 .../intrinsics/float_to_int_64_infneg2.rs | 0 .../intrinsics/float_to_int_64_infneg2.stderr | 0 .../intrinsics/float_to_int_64_nan.rs | 0 .../intrinsics/float_to_int_64_nan.stderr | 0 .../intrinsics/float_to_int_64_neg.rs | 0 .../intrinsics/float_to_int_64_neg.stderr | 0 .../intrinsics/float_to_int_64_too_big1.rs | 0 .../intrinsics/float_to_int_64_too_big1.stderr | 0 .../intrinsics/float_to_int_64_too_big2.rs | 0 .../intrinsics/float_to_int_64_too_big2.stderr | 0 .../intrinsics/float_to_int_64_too_big3.rs | 0 .../intrinsics/float_to_int_64_too_big3.stderr | 0 .../intrinsics/float_to_int_64_too_big4.rs | 0 .../intrinsics/float_to_int_64_too_big4.stderr | 0 .../intrinsics/float_to_int_64_too_big5.rs | 0 .../intrinsics/float_to_int_64_too_big5.stderr | 0 .../intrinsics/float_to_int_64_too_big6.rs | 0 .../intrinsics/float_to_int_64_too_big6.stderr | 0 .../intrinsics/float_to_int_64_too_big7.rs | 0 .../intrinsics/float_to_int_64_too_big7.stderr | 0 .../intrinsics/float_to_int_64_too_small1.rs | 0 .../intrinsics/float_to_int_64_too_small1.stderr | 0 .../intrinsics/float_to_int_64_too_small2.rs | 0 .../intrinsics/float_to_int_64_too_small2.stderr | 0 .../intrinsics/float_to_int_64_too_small3.rs | 0 .../intrinsics/float_to_int_64_too_small3.stderr | 0 .../intrinsics/out_of_bounds_ptr_1.rs | 0 .../intrinsics/out_of_bounds_ptr_1.stderr | 0 .../intrinsics/out_of_bounds_ptr_2.rs | 0 .../intrinsics/out_of_bounds_ptr_2.stderr | 0 .../intrinsics/out_of_bounds_ptr_3.rs | 0 .../intrinsics/out_of_bounds_ptr_3.stderr | 0 .../intrinsics/overflowing-unchecked-rsh.rs | 0 .../intrinsics/overflowing-unchecked-rsh.stderr | 0 .../intrinsics/ptr_offset_0_plus_0.rs | 0 .../intrinsics/ptr_offset_0_plus_0.stderr | 0 .../intrinsics/ptr_offset_from_oob.rs | 0 .../intrinsics/ptr_offset_from_oob.stderr | 0 .../intrinsics/ptr_offset_int_plus_int.rs | 0 .../intrinsics/ptr_offset_int_plus_int.stderr | 0 .../intrinsics/ptr_offset_int_plus_ptr.rs | 0 .../intrinsics/ptr_offset_int_plus_ptr.stderr | 0 .../intrinsics/ptr_offset_overflow.rs | 0 .../intrinsics/ptr_offset_overflow.stderr | 0 .../intrinsics/ptr_offset_ptr_plus_0.rs | 0 .../intrinsics/ptr_offset_ptr_plus_0.stderr | 0 tests/{compile-fail => fail}/intrinsics/rem-by-zero.rs | 0 tests/{compile-fail => fail}/intrinsics/rem-by-zero.stderr | 0 tests/{compile-fail => fail}/intrinsics/simd-div-by-zero.rs | 0 .../intrinsics/simd-div-by-zero.stderr | 0 .../{compile-fail => fail}/intrinsics/simd-div-overflow.rs | 0 .../intrinsics/simd-div-overflow.stderr | 0 .../{compile-fail => fail}/intrinsics/simd-float-to-int.rs | 0 .../intrinsics/simd-float-to-int.stderr | 0 tests/{compile-fail => fail}/intrinsics/simd-gather.rs | 0 tests/{compile-fail => fail}/intrinsics/simd-gather.stderr | 0 .../intrinsics/simd-reduce-invalid-bool.rs | 0 .../intrinsics/simd-reduce-invalid-bool.stderr | 0 tests/{compile-fail => fail}/intrinsics/simd-rem-by-zero.rs | 0 .../intrinsics/simd-rem-by-zero.stderr | 0 tests/{compile-fail => fail}/intrinsics/simd-scatter.rs | 0 tests/{compile-fail => fail}/intrinsics/simd-scatter.stderr | 0 .../intrinsics/simd-select-bitmask-invalid.rs | 0 .../intrinsics/simd-select-bitmask-invalid.stderr | 0 .../intrinsics/simd-select-invalid-bool.rs | 0 .../intrinsics/simd-select-invalid-bool.stderr | 0 tests/{compile-fail => fail}/intrinsics/simd-shl-too-far.rs | 0 .../intrinsics/simd-shl-too-far.stderr | 0 tests/{compile-fail => fail}/intrinsics/simd-shr-too-far.rs | 0 .../intrinsics/simd-shr-too-far.stderr | 0 tests/{compile-fail => fail}/intrinsics/unchecked_add1.rs | 0 .../{compile-fail => fail}/intrinsics/unchecked_add1.stderr | 0 tests/{compile-fail => fail}/intrinsics/unchecked_add2.rs | 0 .../{compile-fail => fail}/intrinsics/unchecked_add2.stderr | 0 tests/{compile-fail => fail}/intrinsics/unchecked_div1.rs | 0 .../{compile-fail => fail}/intrinsics/unchecked_div1.stderr | 0 tests/{compile-fail => fail}/intrinsics/unchecked_mul1.rs | 0 .../{compile-fail => fail}/intrinsics/unchecked_mul1.stderr | 0 tests/{compile-fail => fail}/intrinsics/unchecked_mul2.rs | 0 .../{compile-fail => fail}/intrinsics/unchecked_mul2.stderr | 0 tests/{compile-fail => fail}/intrinsics/unchecked_sub1.rs | 0 .../{compile-fail => fail}/intrinsics/unchecked_sub1.stderr | 0 tests/{compile-fail => fail}/intrinsics/unchecked_sub2.rs | 0 .../{compile-fail => fail}/intrinsics/unchecked_sub2.stderr | 0 .../intrinsics/uninit_uninhabited_type.rs | 0 .../intrinsics/uninit_uninhabited_type.stderr | 0 tests/{compile-fail => fail}/intrinsics/write_bytes_null.rs | 0 .../intrinsics/write_bytes_null.stderr | 0 .../intrinsics/write_bytes_overflow.rs | 0 .../intrinsics/write_bytes_overflow.stderr | 0 tests/{compile-fail => fail}/intrinsics/zero_fn_ptr.rs | 0 tests/{compile-fail => fail}/intrinsics/zero_fn_ptr.stderr | 0 tests/{compile-fail => fail}/invalid_bool.rs | 0 tests/{compile-fail => fail}/invalid_bool.stderr | 0 tests/{compile-fail => fail}/invalid_char.rs | 0 tests/{compile-fail => fail}/invalid_char.stderr | 0 tests/{compile-fail => fail}/invalid_enum_tag.rs | 0 tests/{compile-fail => fail}/invalid_enum_tag.stderr | 0 tests/{compile-fail => fail}/invalid_int.rs | 0 tests/{compile-fail => fail}/invalid_int.stderr | 0 tests/{compile-fail => fail}/issue-miri-1112.rs | 0 tests/{compile-fail => fail}/issue-miri-1112.stderr | 0 tests/{compile-fail => fail}/memleak.rs | 0 tests/{compile-fail => fail}/memleak.stderr | 0 tests/{compile-fail => fail}/memleak_rc.32bit.stderr | 0 tests/{compile-fail => fail}/memleak_rc.64bit.stderr | 0 tests/{compile-fail => fail}/memleak_rc.rs | 0 tests/{compile-fail => fail}/modifying_constants.rs | 0 tests/{compile-fail => fail}/modifying_constants.stderr | 0 tests/{compile-fail => fail}/never_say_never.rs | 0 tests/{compile-fail => fail}/never_say_never.stderr | 0 tests/{compile-fail => fail}/never_transmute_humans.rs | 0 tests/{compile-fail => fail}/never_transmute_humans.stderr | 0 tests/{compile-fail => fail}/never_transmute_void.rs | 0 tests/{compile-fail => fail}/never_transmute_void.stderr | 0 tests/{compile-fail => fail}/no_main.rs | 0 tests/{compile-fail => fail}/no_main.stderr | 0 tests/{compile-fail => fail}/null_pointer_deref.stderr | 0 tests/{compile-fail => fail}/null_pointer_deref_zst.stderr | 0 tests/{compile-fail => fail}/null_pointer_write.stderr | 0 tests/{compile-fail => fail}/null_pointer_write_zst.stderr | 0 tests/{compile-fail => fail}/panic/bad_miri_start_panic.rs | 0 .../panic/bad_miri_start_panic.stderr | 0 tests/{compile-fail => fail}/panic/bad_unwind.rs | 0 tests/{compile-fail => fail}/panic/bad_unwind.stderr | 0 tests/{compile-fail => fail}/panic/double_panic.rs | 0 tests/{compile-fail => fail}/panic/double_panic.stderr | 0 tests/{compile-fail => fail}/panic/panic_abort1.rs | 0 tests/{compile-fail => fail}/panic/panic_abort1.stderr | 0 tests/{compile-fail => fail}/panic/panic_abort2.rs | 0 tests/{compile-fail => fail}/panic/panic_abort2.stderr | 0 tests/{compile-fail => fail}/panic/panic_abort3.rs | 0 tests/{compile-fail => fail}/panic/panic_abort3.stderr | 0 tests/{compile-fail => fail}/panic/panic_abort4.rs | 0 tests/{compile-fail => fail}/panic/panic_abort4.stderr | 0 tests/{compile-fail => fail}/panic/unwind_panic_abort.rs | 0 .../{compile-fail => fail}/panic/unwind_panic_abort.stderr | 0 tests/{compile-fail => fail}/pointer_partial_overwrite.rs | 0 .../{compile-fail => fail}/pointer_partial_overwrite.stderr | 0 tests/{compile-fail => fail}/pointer_partial_read.rs | 0 tests/{compile-fail => fail}/pointer_partial_read.stderr | 0 .../{compile-fail => fail}/provenance/ptr_int_unexposed.rs | 0 .../provenance/ptr_int_unexposed.stderr | 0 tests/{compile-fail => fail}/provenance/ptr_invalid.rs | 0 tests/{compile-fail => fail}/provenance/ptr_invalid.stderr | 0 .../provenance/ptr_legacy_provenance.rs | 0 .../provenance/ptr_legacy_provenance.stderr | 0 .../provenance/strict-provenance-offset.rs | 0 .../provenance/strict-provenance-offset.stderr | 0 .../provenance/strict_provenance_transmute.rs | 0 .../provenance/strict_provenance_transmute.stderr | 0 .../ptr_integer_array_transmute.stderr | 0 tests/{compile-fail => fail}/ptr_integer_transmute.stderr | 0 tests/{compile-fail => fail}/rc_as_ptr.rs | 0 tests/{compile-fail => fail}/rc_as_ptr.stderr | 0 tests/{compile-fail => fail}/reading_half_a_pointer.rs | 0 tests/{compile-fail => fail}/reading_half_a_pointer.stderr | 0 tests/{compile-fail => fail}/rustc-error.rs | 0 tests/{compile-fail => fail}/rustc-error.stderr | 0 tests/{compile-fail => fail}/shim_arg_size.32bit.stderr | 0 tests/{compile-fail => fail}/shim_arg_size.64bit.stderr | 0 tests/{compile-fail => fail}/shim_arg_size.rs | 0 tests/{compile-fail => fail}/slice-too-big.stderr | 0 .../stacked_borrows/alias_through_mutation.rs | 0 .../stacked_borrows/alias_through_mutation.stderr | 0 .../{compile-fail => fail}/stacked_borrows/aliasing_mut1.rs | 0 .../stacked_borrows/aliasing_mut1.stderr | 0 .../{compile-fail => fail}/stacked_borrows/aliasing_mut2.rs | 0 .../stacked_borrows/aliasing_mut2.stderr | 0 .../{compile-fail => fail}/stacked_borrows/aliasing_mut3.rs | 0 .../stacked_borrows/aliasing_mut3.stderr | 0 .../{compile-fail => fail}/stacked_borrows/aliasing_mut4.rs | 0 .../stacked_borrows/aliasing_mut4.stderr | 0 .../stacked_borrows/box_exclusive_violation1.rs | 0 .../stacked_borrows/box_exclusive_violation1.stderr | 0 .../stacked_borrows/buggy_as_mut_slice.rs | 0 .../stacked_borrows/buggy_as_mut_slice.stderr | 0 .../stacked_borrows/buggy_split_at_mut.rs | 0 .../stacked_borrows/buggy_split_at_mut.stderr | 0 .../stacked_borrows/deallocate_against_barrier1.rs | 0 .../stacked_borrows/deallocate_against_barrier1.stderr | 0 .../stacked_borrows/deallocate_against_barrier2.rs | 0 .../stacked_borrows/deallocate_against_barrier2.stderr | 0 .../{compile-fail => fail}/stacked_borrows/illegal_read1.rs | 0 .../stacked_borrows/illegal_read1.stderr | 0 .../{compile-fail => fail}/stacked_borrows/illegal_read2.rs | 0 .../stacked_borrows/illegal_read2.stderr | 0 .../{compile-fail => fail}/stacked_borrows/illegal_read3.rs | 0 .../stacked_borrows/illegal_read3.stderr | 0 .../{compile-fail => fail}/stacked_borrows/illegal_read4.rs | 0 .../stacked_borrows/illegal_read4.stderr | 0 .../{compile-fail => fail}/stacked_borrows/illegal_read5.rs | 0 .../stacked_borrows/illegal_read5.stderr | 0 .../{compile-fail => fail}/stacked_borrows/illegal_read6.rs | 0 .../stacked_borrows/illegal_read6.stderr | 0 .../{compile-fail => fail}/stacked_borrows/illegal_read7.rs | 0 .../stacked_borrows/illegal_read7.stderr | 0 .../{compile-fail => fail}/stacked_borrows/illegal_read8.rs | 0 .../stacked_borrows/illegal_read8.stderr | 0 .../stacked_borrows/illegal_write1.rs | 0 .../stacked_borrows/illegal_write1.stderr | 0 .../stacked_borrows/illegal_write2.rs | 0 .../stacked_borrows/illegal_write2.stderr | 0 .../stacked_borrows/illegal_write3.rs | 0 .../stacked_borrows/illegal_write3.stderr | 0 .../stacked_borrows/illegal_write4.rs | 0 .../stacked_borrows/illegal_write4.stderr | 0 .../stacked_borrows/illegal_write5.rs | 0 .../stacked_borrows/illegal_write5.stderr | 0 .../stacked_borrows/illegal_write6.rs | 0 .../stacked_borrows/illegal_write6.stderr | 0 .../{compile-fail => fail}/stacked_borrows/interior_mut1.rs | 0 .../stacked_borrows/interior_mut1.stderr | 0 .../{compile-fail => fail}/stacked_borrows/interior_mut2.rs | 0 .../stacked_borrows/interior_mut2.stderr | 0 .../stacked_borrows/invalidate_against_barrier1.rs | 0 .../stacked_borrows/invalidate_against_barrier1.stderr | 0 .../stacked_borrows/invalidate_against_barrier2.rs | 0 .../stacked_borrows/invalidate_against_barrier2.stderr | 0 .../stacked_borrows/issue-miri-1050-1.rs | 0 .../stacked_borrows/issue-miri-1050-1.stderr | 0 .../stacked_borrows/issue-miri-1050-2.rs | 0 .../stacked_borrows/issue-miri-1050-2.stderr | 0 .../stacked_borrows/load_invalid_mut.rs | 0 .../stacked_borrows/load_invalid_mut.stderr | 0 .../stacked_borrows/load_invalid_shr.rs | 0 .../stacked_borrows/load_invalid_shr.stderr | 0 .../stacked_borrows/mut_exclusive_violation1.rs | 0 .../stacked_borrows/mut_exclusive_violation1.stderr | 0 .../stacked_borrows/mut_exclusive_violation2.rs | 0 .../stacked_borrows/mut_exclusive_violation2.stderr | 0 .../stacked_borrows/outdated_local.rs | 0 .../stacked_borrows/outdated_local.stderr | 0 .../stacked_borrows/pass_invalid_mut.rs | 0 .../stacked_borrows/pass_invalid_mut.stderr | 0 .../stacked_borrows/pass_invalid_shr.rs | 0 .../stacked_borrows/pass_invalid_shr.stderr | 0 .../stacked_borrows/pointer_smuggling.rs | 0 .../stacked_borrows/pointer_smuggling.stderr | 0 .../{compile-fail => fail}/stacked_borrows/raw_tracking.rs | 0 .../stacked_borrows/raw_tracking.stderr | 0 .../stacked_borrows/return_invalid_mut.rs | 0 .../stacked_borrows/return_invalid_mut.stderr | 0 .../stacked_borrows/return_invalid_mut_option.rs | 0 .../stacked_borrows/return_invalid_mut_option.stderr | 0 .../stacked_borrows/return_invalid_mut_tuple.rs | 0 .../stacked_borrows/return_invalid_mut_tuple.stderr | 0 .../stacked_borrows/return_invalid_shr.rs | 0 .../stacked_borrows/return_invalid_shr.stderr | 0 .../stacked_borrows/return_invalid_shr_option.rs | 0 .../stacked_borrows/return_invalid_shr_option.stderr | 0 .../stacked_borrows/return_invalid_shr_tuple.rs | 0 .../stacked_borrows/return_invalid_shr_tuple.stderr | 0 .../stacked_borrows/shared_rw_borrows_are_weak1.rs | 0 .../stacked_borrows/shared_rw_borrows_are_weak1.stderr | 0 .../stacked_borrows/shared_rw_borrows_are_weak2.rs | 0 .../stacked_borrows/shared_rw_borrows_are_weak2.stderr | 0 .../stacked_borrows/shr_frozen_violation1.rs | 0 .../stacked_borrows/shr_frozen_violation1.stderr | 0 .../stacked_borrows/static_memory_modification.rs | 0 .../stacked_borrows/static_memory_modification.stderr | 0 .../stacked_borrows/transmute-is-no-escape.rs | 0 .../stacked_borrows/transmute-is-no-escape.stderr | 0 .../stacked_borrows/unescaped_local.rs | 0 .../stacked_borrows/unescaped_local.stderr | 0 .../stacked_borrows/unescaped_static.rs | 0 .../stacked_borrows/unescaped_static.stderr | 0 tests/{compile-fail => fail}/stacked_borrows/zst_slice.rs | 0 .../{compile-fail => fail}/stacked_borrows/zst_slice.stderr | 0 tests/{compile-fail => fail}/static_memory_modification1.rs | 0 .../static_memory_modification1.stderr | 0 tests/{compile-fail => fail}/static_memory_modification2.rs | 0 .../static_memory_modification2.stderr | 0 tests/{compile-fail => fail}/static_memory_modification3.rs | 0 .../static_memory_modification3.stderr | 0 .../{compile-fail => fail}/strict-provenance-offset.stderr | 0 .../strict_provenance_transmute.stderr | 0 .../sync/libc_pthread_cond_double_destroy.rs | 0 .../sync/libc_pthread_cond_double_destroy.stderr | 0 .../sync/libc_pthread_condattr_double_destroy.rs | 0 .../sync/libc_pthread_condattr_double_destroy.stderr | 0 .../sync/libc_pthread_mutex_NULL_deadlock.rs | 0 .../sync/libc_pthread_mutex_NULL_deadlock.stderr | 0 .../sync/libc_pthread_mutex_deadlock.rs | 0 .../sync/libc_pthread_mutex_deadlock.stderr | 0 .../sync/libc_pthread_mutex_default_deadlock.rs | 0 .../sync/libc_pthread_mutex_default_deadlock.stderr | 0 .../sync/libc_pthread_mutex_destroy_locked.rs | 0 .../sync/libc_pthread_mutex_destroy_locked.stderr | 0 .../sync/libc_pthread_mutex_double_destroy.rs | 0 .../sync/libc_pthread_mutex_double_destroy.stderr | 0 .../sync/libc_pthread_mutex_normal_deadlock.rs | 0 .../sync/libc_pthread_mutex_normal_deadlock.stderr | 0 .../sync/libc_pthread_mutex_normal_unlock_unlocked.rs | 0 .../sync/libc_pthread_mutex_normal_unlock_unlocked.stderr | 0 .../sync/libc_pthread_mutex_wrong_owner.rs | 0 .../sync/libc_pthread_mutex_wrong_owner.stderr | 0 .../sync/libc_pthread_mutexattr_double_destroy.rs | 0 .../sync/libc_pthread_mutexattr_double_destroy.stderr | 0 .../sync/libc_pthread_rwlock_destroy_read_locked.rs | 0 .../sync/libc_pthread_rwlock_destroy_read_locked.stderr | 0 .../sync/libc_pthread_rwlock_destroy_write_locked.rs | 0 .../sync/libc_pthread_rwlock_destroy_write_locked.stderr | 0 .../sync/libc_pthread_rwlock_double_destroy.rs | 0 .../sync/libc_pthread_rwlock_double_destroy.stderr | 0 ...libc_pthread_rwlock_read_write_deadlock_single_thread.rs | 0 ..._pthread_rwlock_read_write_deadlock_single_thread.stderr | 0 .../sync/libc_pthread_rwlock_read_wrong_owner.rs | 0 .../sync/libc_pthread_rwlock_read_wrong_owner.stderr | 0 .../sync/libc_pthread_rwlock_unlock_unlocked.rs | 0 .../sync/libc_pthread_rwlock_unlock_unlocked.stderr | 0 .../sync/libc_pthread_rwlock_write_read_deadlock.rs | 0 .../sync/libc_pthread_rwlock_write_read_deadlock.stderr | 0 ...libc_pthread_rwlock_write_read_deadlock_single_thread.rs | 0 ..._pthread_rwlock_write_read_deadlock_single_thread.stderr | 0 .../sync/libc_pthread_rwlock_write_write_deadlock.rs | 0 .../sync/libc_pthread_rwlock_write_write_deadlock.stderr | 0 ...ibc_pthread_rwlock_write_write_deadlock_single_thread.rs | 0 ...pthread_rwlock_write_write_deadlock_single_thread.stderr | 0 .../sync/libc_pthread_rwlock_write_wrong_owner.rs | 0 .../sync/libc_pthread_rwlock_write_wrong_owner.stderr | 0 tests/{compile-fail => fail}/too-big-slice.stderr | 0 tests/{compile-fail => fail}/too-big-unsized.stderr | 0 tests/{compile-fail => fail}/transmute-pair-uninit.rs | 0 tests/{compile-fail => fail}/transmute-pair-uninit.stderr | 0 tests/{compile-fail => fail}/transmute_fat1.rs | 0 tests/{compile-fail => fail}/transmute_fat1.stderr | 0 tests/{compile-fail => fail}/type-too-large.rs | 0 tests/{compile-fail => fail}/type-too-large.stderr | 0 .../{compile-fail => fail}/unaligned_pointers/alignment.rs | 0 .../unaligned_pointers/alignment.stderr | 0 .../unaligned_pointers/atomic_unaligned.rs | 0 .../unaligned_pointers/atomic_unaligned.stderr | 0 .../unaligned_pointers/dyn_alignment.rs | 0 .../unaligned_pointers/dyn_alignment.stderr | 0 .../unaligned_pointers/intptrcast_alignment_check.rs | 0 .../unaligned_pointers/intptrcast_alignment_check.stderr | 0 .../unaligned_pointers/reference_to_packed.rs | 0 .../unaligned_pointers/reference_to_packed.stderr | 0 .../unaligned_pointers/unaligned_ptr1.rs | 0 .../unaligned_pointers/unaligned_ptr1.stderr | 0 .../unaligned_pointers/unaligned_ptr2.rs | 0 .../unaligned_pointers/unaligned_ptr2.stderr | 0 .../unaligned_pointers/unaligned_ptr3.rs | 0 .../unaligned_pointers/unaligned_ptr3.stderr | 0 .../unaligned_pointers/unaligned_ptr4.rs | 0 .../unaligned_pointers/unaligned_ptr4.stderr | 0 .../unaligned_pointers/unaligned_ptr_addr_of.rs | 0 .../unaligned_pointers/unaligned_ptr_addr_of.stderr | 0 .../unaligned_pointers/unaligned_ptr_zst.rs | 0 .../unaligned_pointers/unaligned_ptr_zst.stderr | 0 tests/{compile-fail => fail}/uninit_buffer.rs | 0 tests/{compile-fail => fail}/uninit_buffer.stderr | 0 tests/{compile-fail => fail}/uninit_byte_read.rs | 0 tests/{compile-fail => fail}/uninit_byte_read.stderr | 0 tests/{compile-fail => fail}/uninit_float.stderr | 0 tests/{compile-fail => fail}/uninit_integer.stderr | 0 tests/{compile-fail => fail}/uninit_integer_signed.stderr | 0 tests/{compile-fail => fail}/uninit_raw_ptr.rs | 0 tests/{compile-fail => fail}/uninit_raw_ptr.stderr | 0 tests/{compile-fail => fail}/unreachable.rs | 0 tests/{compile-fail => fail}/unreachable.stderr | 0 .../{compile-fail => fail}/unsupported_foreign_function.rs | 0 .../unsupported_foreign_function.stderr | 0 tests/{compile-fail => fail}/unsupported_signal.rs | 0 tests/{compile-fail => fail}/unsupported_signal.stderr | 0 tests/{compile-fail => fail}/validity/cast_fn_ptr1.rs | 0 tests/{compile-fail => fail}/validity/cast_fn_ptr1.stderr | 0 tests/{compile-fail => fail}/validity/cast_fn_ptr2.rs | 0 tests/{compile-fail => fail}/validity/cast_fn_ptr2.stderr | 0 tests/{compile-fail => fail}/validity/dangling_ref1.rs | 0 tests/{compile-fail => fail}/validity/dangling_ref1.stderr | 0 tests/{compile-fail => fail}/validity/dangling_ref2.rs | 0 tests/{compile-fail => fail}/validity/dangling_ref2.stderr | 0 tests/{compile-fail => fail}/validity/dangling_ref3.rs | 0 tests/{compile-fail => fail}/validity/dangling_ref3.stderr | 0 tests/{compile-fail => fail}/validity/invalid_bool.rs | 0 tests/{compile-fail => fail}/validity/invalid_bool.stderr | 0 .../{compile-fail => fail}/validity/invalid_bool_uninit.rs | 0 .../validity/invalid_bool_uninit.stderr | 0 tests/{compile-fail => fail}/validity/invalid_char.rs | 0 tests/{compile-fail => fail}/validity/invalid_char.stderr | 0 .../{compile-fail => fail}/validity/invalid_char_uninit.rs | 0 .../validity/invalid_char_uninit.stderr | 0 tests/{compile-fail => fail}/validity/invalid_enum_tag.rs | 0 .../{compile-fail => fail}/validity/invalid_enum_tag.stderr | 0 .../validity/invalid_enum_tag_256variants_uninit.rs | 0 .../validity/invalid_enum_tag_256variants_uninit.stderr | 0 tests/{compile-fail => fail}/validity/invalid_fnptr_null.rs | 0 .../validity/invalid_fnptr_null.stderr | 0 .../{compile-fail => fail}/validity/invalid_fnptr_uninit.rs | 0 .../validity/invalid_fnptr_uninit.stderr | 0 tests/{compile-fail => fail}/validity/invalid_wide_raw.rs | 0 .../{compile-fail => fail}/validity/invalid_wide_raw.stderr | 0 tests/{compile-fail => fail}/validity/nonzero.rs | 0 tests/{compile-fail => fail}/validity/nonzero.stderr | 0 .../validity/ptr_integer_array_transmute.rs | 0 .../validity/ptr_integer_array_transmute.stderr | 0 .../validity/ptr_integer_transmute.rs | 0 .../validity/ptr_integer_transmute.stderr | 0 .../{compile-fail => fail}/validity/ref_to_uninhabited1.rs | 0 .../validity/ref_to_uninhabited1.stderr | 0 .../{compile-fail => fail}/validity/ref_to_uninhabited2.rs | 0 .../validity/ref_to_uninhabited2.stderr | 0 tests/{compile-fail => fail}/validity/too-big-slice.rs | 0 tests/{compile-fail => fail}/validity/too-big-slice.stderr | 0 tests/{compile-fail => fail}/validity/too-big-unsized.rs | 0 .../{compile-fail => fail}/validity/too-big-unsized.stderr | 0 .../validity/transmute_through_ptr.rs | 0 .../validity/transmute_through_ptr.stderr | 0 tests/{compile-fail => fail}/validity/uninit_float.rs | 0 tests/{compile-fail => fail}/validity/uninit_float.stderr | 0 tests/{compile-fail => fail}/validity/uninit_integer.rs | 0 tests/{compile-fail => fail}/validity/uninit_integer.stderr | 0 .../validity/uninit_integer_signed.rs | 0 .../validity/uninit_integer_signed.stderr | 0 tests/{compile-fail => fail}/zst1.rs | 0 tests/{compile-fail => fail}/zst1.stderr | 0 tests/{compile-fail => fail}/zst2.rs | 0 tests/{compile-fail => fail}/zst2.stderr | 0 tests/{compile-fail => fail}/zst3.rs | 0 tests/{compile-fail => fail}/zst3.stderr | 0 .../function_calls/exported_symbol_good_unwind.rs | 0 .../function_calls/exported_symbol_good_unwind.stderr | 0 tests/{run-fail => panic}/panic/div-by-zero-2.rs | 0 tests/{run-fail => panic}/panic/div-by-zero-2.stderr | 0 tests/{run-fail => panic}/panic/overflowing-lsh-neg.rs | 0 tests/{run-fail => panic}/panic/overflowing-lsh-neg.stderr | 0 tests/{run-fail => panic}/panic/overflowing-rsh-1.rs | 0 tests/{run-fail => panic}/panic/overflowing-rsh-1.stderr | 0 tests/{run-fail => panic}/panic/overflowing-rsh-2.rs | 0 tests/{run-fail => panic}/panic/overflowing-rsh-2.stderr | 0 tests/{run-fail => panic}/panic/panic1.rs | 0 tests/{run-fail => panic}/panic/panic1.stderr | 0 tests/{run-fail => panic}/panic/panic2.rs | 0 tests/{run-fail => panic}/panic/panic2.stderr | 0 tests/{run-fail => panic}/panic/panic3.rs | 0 tests/{run-fail => panic}/panic/panic3.stderr | 0 tests/{run-fail => panic}/panic/panic4.rs | 0 tests/{run-fail => panic}/panic/panic4.stderr | 0 .../panic/unsupported_foreign_function.rs | 0 .../panic/unsupported_foreign_function.stderr | 0 tests/{run-fail => panic}/panic/unsupported_syscall.rs | 0 tests/{run-fail => panic}/panic/unsupported_syscall.stderr | 0 tests/{run-fail => panic}/transmute_fat2.rs | 0 tests/{run-fail => panic}/transmute_fat2.stderr | 0 tests/{run-pass => pass}/adjacent-allocs.rs | 0 tests/{run-pass => pass}/align.rs | 0 tests/{run-pass => pass}/align_offset_symbolic.rs | 0 tests/{run-pass => pass}/align_offset_symbolic.stdout | 0 tests/{run-pass => pass}/args.rs | 0 tests/{run-pass => pass}/args.stdout | 0 tests/{run-pass => pass}/arrays.rs | 0 tests/{run-pass => pass}/arrays.stdout | 0 tests/{run-pass => pass}/associated-const.rs | 0 tests/{run-pass => pass}/assume_bug.rs | 0 tests/{run-pass => pass}/async-fn.rs | 0 .../atomic-compare-exchange-weak-never-fail.rs | 0 tests/{run-pass => pass}/atomic.rs | 0 tests/{run-pass => pass}/available-parallelism.rs | 0 tests/{run-pass => pass}/backtrace-api-v0.rs | 0 tests/{run-pass => pass}/backtrace-api-v0.stderr | 0 tests/{run-pass => pass}/backtrace-api-v0.stdout | 0 tests/{run-pass => pass}/backtrace-api-v1.rs | 0 tests/{run-pass => pass}/backtrace-api-v1.stderr | 0 tests/{run-pass => pass}/backtrace-api-v1.stdout | 0 tests/{run-pass => pass}/backtrace-std.rs | 0 tests/{run-pass => pass}/backtrace-std.stderr | 0 tests/{run-pass => pass}/bad_substs.rs | 0 tests/{run-pass => pass}/binary-heap.rs | 0 tests/{run-pass => pass}/binops.rs | 0 tests/{run-pass => pass}/bools.rs | 0 tests/{run-pass => pass}/box.rs | 0 tests/{run-pass => pass}/box.stdout | 0 tests/{run-pass => pass}/btreemap.rs | 0 tests/{run-pass => pass}/c_enums.rs | 0 tests/{run-pass => pass}/calloc.rs | 0 tests/{run-pass => pass}/calls.rs | 0 tests/{run-pass => pass}/cast-rfc0401-vtable-kinds.rs | 0 tests/{run-pass => pass}/cast_fn_ptr.rs | 0 tests/{run-pass => pass}/cast_fn_ptr_unsafe.rs | 0 tests/{run-pass => pass}/catch.rs | 0 tests/{run-pass => pass}/catch.stdout | 0 tests/{run-pass => pass}/cfg_miri.rs | 0 tests/{run-pass => pass}/char.rs | 0 tests/{run-pass => pass}/closure-drop.rs | 0 tests/{run-pass => pass}/closure-field-ty.rs | 0 tests/{run-pass => pass}/closures.rs | 0 .../coerce_non_capture_closure_to_fn_ptr.rs | 0 tests/{run-pass => pass}/coercions.rs | 0 tests/{run-pass => pass}/concurrency/channels.rs | 0 tests/{run-pass => pass}/concurrency/channels.stderr | 0 .../concurrency/concurrent_caller_location.rs | 0 .../concurrency/concurrent_caller_location.stderr | 0 tests/{run-pass => pass}/concurrency/data_race.rs | 0 tests/{run-pass => pass}/concurrency/data_race.stderr | 0 .../concurrency/disable_data_race_detector.rs | 0 .../concurrency/disable_data_race_detector.stderr | 0 tests/{run-pass => pass}/concurrency/issue1643.rs | 0 tests/{run-pass => pass}/concurrency/issue1643.stderr | 0 tests/{run-pass => pass}/concurrency/libc_pthread_cond.rs | 0 tests/{run-pass => pass}/concurrency/linux-futex.rs | 0 tests/{run-pass => pass}/concurrency/linux-futex.stderr | 0 tests/{run-pass => pass}/concurrency/simple.rs | 0 tests/{run-pass => pass}/concurrency/simple.stderr | 0 tests/{run-pass => pass}/concurrency/sync.rs | 0 tests/{run-pass => pass}/concurrency/sync.stderr | 0 tests/{run-pass => pass}/concurrency/sync.stdout | 0 tests/{run-pass => pass}/concurrency/sync_singlethread.rs | 0 tests/{run-pass => pass}/concurrency/thread_locals.rs | 0 tests/{run-pass => pass}/concurrency/thread_locals.stderr | 0 tests/{run-pass => pass}/concurrency/tls_lib_drop.rs | 0 tests/{run-pass => pass}/concurrency/tls_lib_drop.stderr | 0 tests/{run-pass => pass}/concurrency/tls_lib_drop.stdout | 0 .../concurrency/tls_lib_drop_single_thread.rs | 0 .../concurrency/tls_lib_drop_single_thread.stderr | 0 .../concurrency/tls_pthread_drop_order.rs | 0 tests/{run-pass => pass}/const-vec-of-fns.rs | 0 tests/{run-pass => pass}/constants.rs | 0 tests/{run-pass => pass}/current_dir.rs | 0 tests/{run-pass => pass}/current_dir_with_isolation.rs | 0 tests/{run-pass => pass}/current_dir_with_isolation.stderr | 0 tests/{run-pass => pass}/deriving-associated-types.rs | 0 tests/{run-pass => pass}/disable-alignment-check.rs | 0 tests/{run-pass => pass}/drop_empty_slice.rs | 0 tests/{run-pass => pass}/drop_on_array_elements.rs | 0 tests/{run-pass => pass}/drop_on_fat_ptr_array_elements.rs | 0 tests/{run-pass => pass}/drop_on_zst_array_elements.rs | 0 tests/{run-pass => pass}/drop_through_owned_slice.rs | 0 tests/{run-pass => pass}/drop_through_trait_object.rs | 0 tests/{run-pass => pass}/drop_through_trait_object_rc.rs | 0 tests/{run-pass => pass}/dst-field-align.rs | 0 tests/{run-pass => pass}/dst-irrefutable-bind.rs | 0 tests/{run-pass => pass}/dst-raw.rs | 0 tests/{run-pass => pass}/dst-struct-sole.rs | 0 tests/{run-pass => pass}/dst-struct.rs | 0 tests/{run-pass => pass}/dyn-arbitrary-self.rs | 0 tests/{run-pass => pass}/dyn-traits.rs | 0 .../enum-nullable-const-null-with-fields.rs | 0 tests/{run-pass => pass}/enum_discriminant_ptr_value.rs | 0 tests/{run-pass => pass}/enums.rs | 0 tests/{run-pass => pass}/env-exclude.rs | 0 tests/{run-pass => pass}/env-forward.rs | 0 tests/{run-pass => pass}/env-without-isolation.rs | 0 tests/{run-pass => pass}/env.rs | 0 tests/{run-pass => pass}/env.stdout | 0 tests/{run-pass => pass}/exit.rs | 0 tests/{run-pass => pass}/extern_crate_std_in_main.rs | 0 tests/{run-pass => pass}/extern_types.rs | 0 tests/{run-pass => pass}/fat_ptr.rs | 0 tests/{run-pass => pass}/float.rs | 0 tests/{run-pass => pass}/float_fast_math.rs | 0 tests/{run-pass => pass}/foreign-fn-linkname.rs | 0 tests/{run-pass => pass}/format.rs | 0 tests/{run-pass => pass}/format.stdout | 0 tests/{run-pass => pass}/from_utf8.rs | 0 tests/{run-pass => pass}/fs.rs | 0 tests/{run-pass => pass}/fs.stderr | 0 tests/{run-pass => pass}/fs.stdout | 0 tests/{run-pass => pass}/fs_with_isolation.rs | 0 tests/{run-pass => pass}/fs_with_isolation.stderr | 0 .../{run-pass => pass}/function_calls/disable_abi_check.rs | 0 tests/{run-pass => pass}/function_calls/exported_symbol.rs | 0 tests/{run-pass => pass}/function_pointers.rs | 0 tests/{run-pass => pass}/generator.rs | 0 tests/{run-pass => pass}/global_allocator.rs | 0 tests/{run-pass => pass}/global_allocator.stdout | 0 tests/{run-pass => pass}/hashmap.rs | 0 tests/{run-pass => pass}/heap.rs | 0 tests/{run-pass => pass}/heap_allocator.rs | 0 tests/{run-pass => pass}/hello.rs | 0 tests/{run-pass => pass}/hello.stdout | 0 tests/{run-pass => pass}/hide_stdout.rs | 0 tests/{run-pass => pass}/integer-ops.rs | 0 tests/{run-pass => pass}/intptrcast.rs | 0 tests/{run-pass => pass}/intrinsics-integer.rs | 0 tests/{run-pass => pass}/intrinsics-math.rs | 0 tests/{run-pass => pass}/intrinsics-x86.rs | 0 tests/{run-pass => pass}/intrinsics.rs | 0 tests/{run-pass => pass}/ints.rs | 0 tests/{run-pass => pass}/issue-15063.rs | 0 tests/{run-pass => pass}/issue-15080.rs | 0 tests/{run-pass => pass}/issue-15523-big.rs | 0 tests/{run-pass => pass}/issue-17877.rs | 0 tests/{run-pass => pass}/issue-20575.rs | 0 tests/{run-pass => pass}/issue-23261.rs | 0 tests/{run-pass => pass}/issue-26709.rs | 0 tests/{run-pass => pass}/issue-27901.rs | 0 tests/{run-pass => pass}/issue-29746.rs | 0 tests/{run-pass => pass}/issue-30530.rs | 0 tests/{run-pass => pass}/issue-31267-additional.rs | 0 tests/{run-pass => pass}/issue-33387.rs | 0 tests/{run-pass => pass}/issue-34571.rs | 0 tests/{run-pass => pass}/issue-35815.rs | 0 tests/{run-pass => pass}/issue-36278-prefix-nesting.rs | 0 tests/{run-pass => pass}/issue-3794.rs | 0 tests/{run-pass => pass}/issue-3794.stdout | 0 tests/{run-pass => pass}/issue-53728.rs | 0 tests/{run-pass => pass}/issue-5917.rs | 0 tests/{run-pass => pass}/issue-73223.rs | 0 tests/{run-pass => pass}/issue-91636.rs | 0 tests/{run-pass => pass}/issue-94371.rs | 0 tests/{run-pass => pass}/issue-miri-1075.rs | 0 tests/{run-pass => pass}/issue-miri-133.rs | 0 tests/{run-pass => pass}/issue-miri-184.rs | 0 tests/{run-pass => pass}/issue-miri-1925.rs | 0 tests/{run-pass => pass}/issue-miri-2068-2.rs | 0 tests/{run-pass => pass}/issue-miri-2068.rs | 0 tests/{run-pass => pass}/iter.rs | 0 tests/{run-pass => pass}/last-use-in-cap-clause.rs | 0 tests/{run-pass => pass}/leak-in-static.rs | 0 tests/{run-pass => pass}/libc.rs | 0 tests/{run-pass => pass}/libc.stderr | 0 tests/{run-pass => pass}/linked-list.rs | 0 .../{run-pass => pass}/linux-getrandom-without-isolation.rs | 0 tests/{run-pass => pass}/linux-getrandom.rs | 0 tests/{run-pass => pass}/loop-break-value.rs | 0 tests/{run-pass => pass}/loops.rs | 0 tests/{run-pass => pass}/main_fn.rs | 0 tests/{run-pass => pass}/main_result.rs | 0 tests/{run-pass => pass}/malloc.rs | 0 tests/{run-pass => pass}/many_shr_bor.rs | 0 tests/{run-pass => pass}/match_slice.rs | 0 tests/{run-pass => pass}/memchr.rs | 0 tests/{run-pass => pass}/memleak_ignored.rs | 0 tests/{run-pass => pass}/move-arg-2-unique.rs | 0 tests/{run-pass => pass}/move-arg-3-unique.rs | 0 tests/{run-pass => pass}/move-uninit-primval.rs | 0 tests/{run-pass => pass}/mpsc.rs | 0 tests/{run-pass => pass}/multi_arg_closure.rs | 0 tests/{run-pass => pass}/negative_discriminant.rs | 0 tests/{run-pass => pass}/observed_local_mut.rs | 0 tests/{run-pass => pass}/option_box_transmute_ptr.rs | 0 tests/{run-pass => pass}/option_eq.rs | 0 tests/{run-pass => pass}/overflow_checks_off.rs | 0 tests/{run-pass => pass}/overloaded-calls-simple.rs | 0 tests/{run-pass => pass}/packed_struct.rs | 0 tests/{run-pass => pass}/panic/catch_panic.rs | 0 tests/{run-pass => pass}/panic/catch_panic.stderr | 0 tests/{run-pass => pass}/panic/concurrent-panic.rs | 0 tests/{run-pass => pass}/panic/concurrent-panic.stderr | 0 tests/{run-pass => pass}/panic/std-panic-locations.rs | 0 tests/{run-pass => pass}/partially-uninit.rs | 0 tests/{run-pass => pass}/pointers.rs | 0 tests/{run-pass => pass}/portable-simd.rs | 0 tests/{run-pass => pass}/products.rs | 0 tests/{run-pass => pass}/ptr_int_casts.rs | 0 tests/{run-pass => pass}/ptr_int_permissive_provenance.rs | 0 tests/{run-pass => pass}/ptr_offset.rs | 0 tests/{run-pass => pass}/ptr_raw.rs | 0 tests/{run-pass => pass}/rc.rs | 0 tests/{run-pass => pass}/recursive_static.rs | 0 tests/{run-pass => pass}/reentrant-println.rs | 0 tests/{run-pass => pass}/reentrant-println.stdout | 0 .../regions-lifetime-nonfree-late-bound.rs | 0 tests/{run-pass => pass}/regions-mock-trans.rs | 0 tests/{run-pass => pass}/rename_std.rs | 0 tests/{run-pass => pass}/rfc1623.rs | 0 tests/{run-pass => pass}/rust-lang-org.rs | 0 tests/{run-pass => pass}/send-is-not-static-par-for.rs | 0 tests/{run-pass => pass}/sendable-class.rs | 0 tests/{run-pass => pass}/simd-intrinsic-generic-elements.rs | 0 tests/{run-pass => pass}/slices.rs | 0 tests/{run-pass => pass}/small_enum_size_bug.rs | 0 tests/{run-pass => pass}/specialization.rs | 0 tests/{run-pass => pass}/stacked-borrows/2phase.rs | 0 .../stacked-borrows/generators-self-referential.rs | 0 tests/{run-pass => pass}/stacked-borrows/int-to-ptr.rs | 0 .../stacked-borrows/interior_mutability.rs | 0 tests/{run-pass => pass}/stacked-borrows/refcell.rs | 0 tests/{run-pass => pass}/stacked-borrows/stacked-borrows.rs | 0 .../stacked-borrows/stacked-borrows.stderr | 0 tests/{run-pass => pass}/start.rs | 0 tests/{run-pass => pass}/start.stdout | 0 tests/{run-pass => pass}/static_memory_modification.rs | 0 tests/{run-pass => pass}/static_mut.rs | 0 tests/{run-pass => pass}/strings.rs | 0 tests/{run-pass => pass}/subslice_array.rs | 0 tests/{run-pass => pass}/sums.rs | 0 tests/{run-pass => pass}/tag-align-dyn-u64.rs | 0 tests/{run-pass => pass}/threadleak_ignored.rs | 0 tests/{run-pass => pass}/threadleak_ignored.stderr | 0 tests/{run-pass => pass}/time.rs | 0 tests/{run-pass => pass}/too-large-primval-write-problem.rs | 0 tests/{run-pass => pass}/track-alloc-1.rs | 0 tests/{run-pass => pass}/track-alloc-1.stderr | 0 tests/{run-pass => pass}/track-caller-attribute.rs | 0 tests/{run-pass => pass}/transmute_fat.rs | 0 tests/{run-pass => pass}/trivial.rs | 0 tests/{run-pass => pass}/try-operator-custom.rs | 0 .../tuple_like_enum_variant_constructor.rs | 0 .../tuple_like_enum_variant_constructor_pointer_opt.rs | 0 ...uple_like_enum_variant_constructor_struct_pointer_opt.rs | 0 tests/{run-pass => pass}/tuple_like_struct_constructor.rs | 0 tests/{run-pass => pass}/u128.rs | 0 tests/{run-pass => pass}/uninit_number_ignored.rs | 0 tests/{run-pass => pass}/union-overwrite.rs | 0 tests/{run-pass => pass}/union.rs | 0 tests/{run-pass => pass}/unops.rs | 0 tests/{run-pass => pass}/unsized-tuple-impls.rs | 0 tests/{run-pass => pass}/validation_lifetime_resolution.rs | 0 tests/{run-pass => pass}/vec-matching-fold.rs | 0 tests/{run-pass => pass}/vec.rs | 0 tests/{run-pass => pass}/vecdeque.rs | 0 tests/{run-pass => pass}/vecdeque.stdout | 0 tests/{run-pass => pass}/volatile.rs | 0 tests/{run-pass => pass}/without-validation.rs | 0 tests/{run-pass => pass}/write-bytes.rs | 0 tests/{run-pass => pass}/wtf8.rs | 0 tests/{run-pass => pass}/zst.rs | 0 tests/{run-pass => pass}/zst_box.rs | 0 tests/{run-pass => pass}/zst_variant_drop.rs | 0 979 files changed, 4 insertions(+), 4 deletions(-) rename tests/{compile-fail => fail}/abort-terminator.rs (100%) rename tests/{compile-fail => fail}/abort-terminator.stderr (100%) rename tests/{compile-fail => fail}/alloc/deallocate-bad-alignment.rs (100%) rename tests/{compile-fail => fail}/alloc/deallocate-bad-alignment.stderr (100%) rename tests/{compile-fail => fail}/alloc/deallocate-bad-size.rs (100%) rename tests/{compile-fail => fail}/alloc/deallocate-bad-size.stderr (100%) rename tests/{compile-fail => fail}/alloc/deallocate-twice.rs (100%) rename tests/{compile-fail => fail}/alloc/deallocate-twice.stderr (100%) rename tests/{compile-fail => fail}/alloc/global_system_mixup.rs (100%) rename tests/{compile-fail => fail}/alloc/global_system_mixup.stderr (100%) rename tests/{compile-fail => fail}/alloc/no_global_allocator.rs (100%) rename tests/{compile-fail => fail}/alloc/no_global_allocator.stderr (100%) rename tests/{compile-fail => fail}/alloc/reallocate-bad-size.rs (100%) rename tests/{compile-fail => fail}/alloc/reallocate-bad-size.stderr (100%) rename tests/{compile-fail => fail}/alloc/reallocate-change-alloc.rs (100%) rename tests/{compile-fail => fail}/alloc/reallocate-change-alloc.stderr (100%) rename tests/{compile-fail => fail}/alloc/reallocate-dangling.rs (100%) rename tests/{compile-fail => fail}/alloc/reallocate-dangling.stderr (100%) rename tests/{compile-fail => fail}/alloc/stack_free.rs (100%) rename tests/{compile-fail => fail}/alloc/stack_free.stderr (100%) rename tests/{compile-fail => fail}/backtrace/bad-backtrace-decl.rs (100%) rename tests/{compile-fail => fail}/backtrace/bad-backtrace-decl.stderr (100%) rename tests/{compile-fail => fail}/backtrace/bad-backtrace-flags.rs (100%) rename tests/{compile-fail => fail}/backtrace/bad-backtrace-flags.stderr (100%) rename tests/{compile-fail => fail}/backtrace/bad-backtrace-ptr.rs (100%) rename tests/{compile-fail => fail}/backtrace/bad-backtrace-ptr.stderr (100%) rename tests/{compile-fail => fail}/backtrace/bad-backtrace-resolve-flags.rs (100%) rename tests/{compile-fail => fail}/backtrace/bad-backtrace-resolve-flags.stderr (100%) rename tests/{compile-fail => fail}/backtrace/bad-backtrace-resolve-names-flags.rs (100%) rename tests/{compile-fail => fail}/backtrace/bad-backtrace-resolve-names-flags.stderr (100%) rename tests/{compile-fail => fail}/backtrace/bad-backtrace-size-flags.rs (100%) rename tests/{compile-fail => fail}/backtrace/bad-backtrace-size-flags.stderr (100%) rename tests/{compile-fail => fail}/backtrace/bad-backtrace-version.stderr (100%) rename tests/{compile-fail => fail}/box-cell-alias.rs (100%) rename tests/{compile-fail => fail}/box-cell-alias.stderr (100%) rename tests/{compile-fail => fail}/branchless-select-i128-pointer.rs (100%) rename tests/{compile-fail => fail}/branchless-select-i128-pointer.stderr (100%) rename tests/{compile-fail => fail}/breakpoint.rs (100%) rename tests/{compile-fail => fail}/breakpoint.stderr (100%) rename tests/{compile-fail => fail}/concurrency/libc_pthread_create_main_terminate.rs (100%) rename tests/{compile-fail => fail}/concurrency/libc_pthread_create_main_terminate.stderr (100%) rename tests/{compile-fail => fail}/concurrency/libc_pthread_join_detached.rs (100%) rename tests/{compile-fail => fail}/concurrency/libc_pthread_join_detached.stderr (100%) rename tests/{compile-fail => fail}/concurrency/libc_pthread_join_joined.rs (100%) rename tests/{compile-fail => fail}/concurrency/libc_pthread_join_joined.stderr (100%) rename tests/{compile-fail => fail}/concurrency/libc_pthread_join_main.rs (100%) rename tests/{compile-fail => fail}/concurrency/libc_pthread_join_main.stderr (100%) rename tests/{compile-fail => fail}/concurrency/libc_pthread_join_multiple.rs (100%) rename tests/{compile-fail => fail}/concurrency/libc_pthread_join_multiple.stderr (100%) rename tests/{compile-fail => fail}/concurrency/libc_pthread_join_self.rs (100%) rename tests/{compile-fail => fail}/concurrency/libc_pthread_join_self.stderr (100%) rename tests/{compile-fail => fail}/concurrency/thread-spawn.rs (100%) rename tests/{compile-fail => fail}/concurrency/thread_local_static_dealloc.rs (100%) rename tests/{compile-fail => fail}/concurrency/thread_local_static_dealloc.stderr (100%) rename tests/{compile-fail => fail}/concurrency/too_few_args.rs (100%) rename tests/{compile-fail => fail}/concurrency/too_few_args.stderr (100%) rename tests/{compile-fail => fail}/concurrency/too_many_args.rs (100%) rename tests/{compile-fail => fail}/concurrency/too_many_args.stderr (100%) rename tests/{compile-fail => fail}/concurrency/unwind_top_of_stack.rs (100%) rename tests/{compile-fail => fail}/concurrency/unwind_top_of_stack.stderr (100%) rename tests/{compile-fail => fail}/dangling_pointers/dangling_pointer_addr_of.rs (100%) rename tests/{compile-fail => fail}/dangling_pointers/dangling_pointer_addr_of.stderr (100%) rename tests/{compile-fail => fail}/dangling_pointers/dangling_pointer_deref.rs (100%) rename tests/{compile-fail => fail}/dangling_pointers/dangling_pointer_deref.stderr (100%) rename tests/{compile-fail => fail}/dangling_pointers/dangling_zst_deref.rs (100%) rename tests/{compile-fail => fail}/dangling_pointers/dangling_zst_deref.stderr (100%) rename tests/{compile-fail => fail}/dangling_pointers/deref-invalid-ptr.rs (100%) rename tests/{compile-fail => fail}/dangling_pointers/deref-invalid-ptr.stderr (100%) rename tests/{compile-fail => fail}/dangling_pointers/deref-partially-dangling.rs (100%) rename tests/{compile-fail => fail}/dangling_pointers/deref-partially-dangling.stderr (100%) rename tests/{compile-fail => fail}/dangling_pointers/dyn_size.rs (100%) rename tests/{compile-fail => fail}/dangling_pointers/dyn_size.stderr (100%) rename tests/{compile-fail => fail}/dangling_pointers/maybe_null_pointer_deref_zst.rs (100%) rename tests/{compile-fail => fail}/dangling_pointers/maybe_null_pointer_deref_zst.stderr (100%) rename tests/{compile-fail => fail}/dangling_pointers/maybe_null_pointer_write_zst.rs (100%) rename tests/{compile-fail => fail}/dangling_pointers/maybe_null_pointer_write_zst.stderr (100%) rename tests/{compile-fail => fail}/dangling_pointers/null_pointer_deref.rs (100%) rename tests/{compile-fail => fail}/dangling_pointers/null_pointer_deref.stderr (100%) rename tests/{compile-fail => fail}/dangling_pointers/null_pointer_deref_zst.rs (100%) rename tests/{compile-fail => fail}/dangling_pointers/null_pointer_deref_zst.stderr (100%) rename tests/{compile-fail => fail}/dangling_pointers/null_pointer_write.rs (100%) rename tests/{compile-fail => fail}/dangling_pointers/null_pointer_write.stderr (100%) rename tests/{compile-fail => fail}/dangling_pointers/null_pointer_write_zst.rs (100%) rename tests/{compile-fail => fail}/dangling_pointers/null_pointer_write_zst.stderr (100%) rename tests/{compile-fail => fail}/dangling_pointers/out_of_bounds_read1.rs (100%) rename tests/{compile-fail => fail}/dangling_pointers/out_of_bounds_read1.stderr (100%) rename tests/{compile-fail => fail}/dangling_pointers/out_of_bounds_read2.rs (100%) rename tests/{compile-fail => fail}/dangling_pointers/out_of_bounds_read2.stderr (100%) rename tests/{compile-fail => fail}/dangling_pointers/stack_temporary.rs (100%) rename tests/{compile-fail => fail}/dangling_pointers/stack_temporary.stderr (100%) rename tests/{compile-fail => fail}/dangling_pointers/storage_dead_dangling.rs (100%) rename tests/{compile-fail => fail}/dangling_pointers/storage_dead_dangling.stderr (100%) rename tests/{compile-fail => fail}/dangling_pointers/wild_pointer_deref.rs (100%) rename tests/{compile-fail => fail}/dangling_pointers/wild_pointer_deref.stderr (100%) rename tests/{compile-fail => fail}/data_race/alloc_read_race.rs (100%) rename tests/{compile-fail => fail}/data_race/alloc_read_race.stderr (100%) rename tests/{compile-fail => fail}/data_race/alloc_write_race.rs (100%) rename tests/{compile-fail => fail}/data_race/alloc_write_race.stderr (100%) rename tests/{compile-fail => fail}/data_race/atomic_read_na_write_race1.rs (100%) rename tests/{compile-fail => fail}/data_race/atomic_read_na_write_race1.stderr (100%) rename tests/{compile-fail => fail}/data_race/atomic_read_na_write_race2.rs (100%) rename tests/{compile-fail => fail}/data_race/atomic_read_na_write_race2.stderr (100%) rename tests/{compile-fail => fail}/data_race/atomic_write_na_read_race1.rs (100%) rename tests/{compile-fail => fail}/data_race/atomic_write_na_read_race1.stderr (100%) rename tests/{compile-fail => fail}/data_race/atomic_write_na_read_race2.rs (100%) rename tests/{compile-fail => fail}/data_race/atomic_write_na_read_race2.stderr (100%) rename tests/{compile-fail => fail}/data_race/atomic_write_na_write_race1.rs (100%) rename tests/{compile-fail => fail}/data_race/atomic_write_na_write_race1.stderr (100%) rename tests/{compile-fail => fail}/data_race/atomic_write_na_write_race2.rs (100%) rename tests/{compile-fail => fail}/data_race/atomic_write_na_write_race2.stderr (100%) rename tests/{compile-fail => fail}/data_race/dangling_thread_async_race.rs (100%) rename tests/{compile-fail => fail}/data_race/dangling_thread_async_race.stderr (100%) rename tests/{compile-fail => fail}/data_race/dangling_thread_race.rs (100%) rename tests/{compile-fail => fail}/data_race/dangling_thread_race.stderr (100%) rename tests/{compile-fail => fail}/data_race/dealloc_read_race1.rs (100%) rename tests/{compile-fail => fail}/data_race/dealloc_read_race1.stderr (100%) rename tests/{compile-fail => fail}/data_race/dealloc_read_race2.rs (100%) rename tests/{compile-fail => fail}/data_race/dealloc_read_race2.stderr (100%) rename tests/{compile-fail => fail}/data_race/dealloc_read_race_stack.rs (100%) rename tests/{compile-fail => fail}/data_race/dealloc_read_race_stack.stderr (100%) rename tests/{compile-fail => fail}/data_race/dealloc_write_race1.rs (100%) rename tests/{compile-fail => fail}/data_race/dealloc_write_race1.stderr (100%) rename tests/{compile-fail => fail}/data_race/dealloc_write_race2.rs (100%) rename tests/{compile-fail => fail}/data_race/dealloc_write_race2.stderr (100%) rename tests/{compile-fail => fail}/data_race/dealloc_write_race_stack.rs (100%) rename tests/{compile-fail => fail}/data_race/dealloc_write_race_stack.stderr (100%) rename tests/{compile-fail => fail}/data_race/enable_after_join_to_main.rs (100%) rename tests/{compile-fail => fail}/data_race/enable_after_join_to_main.stderr (100%) rename tests/{compile-fail => fail}/data_race/read_write_race.rs (100%) rename tests/{compile-fail => fail}/data_race/read_write_race.stderr (100%) rename tests/{compile-fail => fail}/data_race/read_write_race_stack.rs (100%) rename tests/{compile-fail => fail}/data_race/read_write_race_stack.stderr (100%) rename tests/{compile-fail => fail}/data_race/relax_acquire_race.rs (100%) rename tests/{compile-fail => fail}/data_race/relax_acquire_race.stderr (100%) rename tests/{compile-fail => fail}/data_race/release_seq_race.rs (100%) rename tests/{compile-fail => fail}/data_race/release_seq_race.stderr (100%) rename tests/{compile-fail => fail}/data_race/release_seq_race_same_thread.rs (100%) rename tests/{compile-fail => fail}/data_race/release_seq_race_same_thread.stderr (100%) rename tests/{compile-fail => fail}/data_race/rmw_race.rs (100%) rename tests/{compile-fail => fail}/data_race/rmw_race.stderr (100%) rename tests/{compile-fail => fail}/data_race/write_write_race.rs (100%) rename tests/{compile-fail => fail}/data_race/write_write_race.stderr (100%) rename tests/{compile-fail => fail}/data_race/write_write_race_stack.rs (100%) rename tests/{compile-fail => fail}/data_race/write_write_race_stack.stderr (100%) rename tests/{compile-fail => fail}/environ-gets-deallocated.rs (100%) rename tests/{compile-fail => fail}/environ-gets-deallocated.stderr (100%) rename tests/{compile-fail => fail}/erroneous_const.rs (100%) rename tests/{compile-fail => fail}/erroneous_const.stderr (100%) rename tests/{compile-fail => fail}/erroneous_const2.rs (100%) rename tests/{compile-fail => fail}/erroneous_const2.stderr (100%) rename tests/{compile-fail => fail}/extern_static.rs (100%) rename tests/{compile-fail => fail}/extern_static.stderr (100%) rename tests/{compile-fail => fail}/fast_math_both.rs (100%) rename tests/{compile-fail => fail}/fast_math_both.stderr (100%) rename tests/{compile-fail => fail}/fast_math_first.rs (100%) rename tests/{compile-fail => fail}/fast_math_first.stderr (100%) rename tests/{compile-fail => fail}/fast_math_second.rs (100%) rename tests/{compile-fail => fail}/fast_math_second.stderr (100%) rename tests/{compile-fail => fail}/fs/close_stdout.rs (100%) rename tests/{compile-fail => fail}/fs/close_stdout.stderr (100%) rename tests/{compile-fail => fail}/fs/isolated_file.rs (100%) rename tests/{compile-fail => fail}/fs/isolated_file.stderr (100%) rename tests/{compile-fail => fail}/fs/isolated_stdin.rs (100%) rename tests/{compile-fail => fail}/fs/isolated_stdin.stderr (100%) rename tests/{compile-fail => fail}/fs/read_from_stdout.rs (100%) rename tests/{compile-fail => fail}/fs/read_from_stdout.stderr (100%) rename tests/{compile-fail => fail}/fs/unix_open_missing_required_mode.rs (100%) rename tests/{compile-fail => fail}/fs/unix_open_missing_required_mode.stderr (100%) rename tests/{compile-fail => fail}/fs/unix_open_too_many_args.stderr (100%) rename tests/{compile-fail => fail}/fs/write_to_stdin.rs (100%) rename tests/{compile-fail => fail}/fs/write_to_stdin.stderr (100%) rename tests/{compile-fail => fail}/function_calls/check_arg_abi.rs (100%) rename tests/{compile-fail => fail}/function_calls/check_arg_abi.stderr (100%) rename tests/{compile-fail => fail}/function_calls/check_arg_count_abort.rs (100%) rename tests/{compile-fail => fail}/function_calls/check_arg_count_abort.stderr (100%) rename tests/{compile-fail => fail}/function_calls/check_arg_count_too_few_args.rs (100%) rename tests/{compile-fail => fail}/function_calls/check_arg_count_too_few_args.stderr (100%) rename tests/{compile-fail => fail}/function_calls/check_arg_count_too_many_args.rs (100%) rename tests/{compile-fail => fail}/function_calls/check_arg_count_too_many_args.stderr (100%) rename tests/{compile-fail => fail}/function_calls/check_callback_abi.rs (100%) rename tests/{compile-fail => fail}/function_calls/check_callback_abi.stderr (100%) rename tests/{compile-fail => fail}/function_calls/exported_symbol_abi_mismatch.cache.stderr (100%) rename tests/{compile-fail => fail}/function_calls/exported_symbol_abi_mismatch.fn_ptr.stderr (100%) rename tests/{compile-fail => fail}/function_calls/exported_symbol_abi_mismatch.no_cache.stderr (100%) rename tests/{compile-fail => fail}/function_calls/exported_symbol_abi_mismatch.rs (100%) rename tests/{compile-fail => fail}/function_calls/exported_symbol_bad_unwind1.rs (100%) rename tests/{compile-fail => fail}/function_calls/exported_symbol_bad_unwind1.stderr (100%) rename tests/{compile-fail => fail}/function_calls/exported_symbol_bad_unwind2.both.stderr (100%) rename tests/{compile-fail => fail}/function_calls/exported_symbol_bad_unwind2.definition.stderr (100%) rename tests/{compile-fail => fail}/function_calls/exported_symbol_bad_unwind2.extern_block.stderr (100%) rename tests/{compile-fail => fail}/function_calls/exported_symbol_bad_unwind2.rs (100%) rename tests/{compile-fail => fail}/function_calls/exported_symbol_clashing.rs (100%) rename tests/{compile-fail => fail}/function_calls/exported_symbol_clashing.stderr (100%) rename tests/{compile-fail => fail}/function_calls/exported_symbol_shim_clashing.rs (100%) rename tests/{compile-fail => fail}/function_calls/exported_symbol_shim_clashing.stderr (100%) rename tests/{compile-fail => fail}/function_calls/exported_symbol_wrong_arguments.rs (100%) rename tests/{compile-fail => fail}/function_calls/exported_symbol_wrong_arguments.stderr (100%) rename tests/{compile-fail => fail}/function_calls/exported_symbol_wrong_type.rs (100%) rename tests/{compile-fail => fail}/function_calls/exported_symbol_wrong_type.stderr (100%) rename tests/{compile-fail => fail}/function_pointers/cast_box_int_to_fn_ptr.rs (100%) rename tests/{compile-fail => fail}/function_pointers/cast_box_int_to_fn_ptr.stderr (100%) rename tests/{compile-fail => fail}/function_pointers/cast_fn_ptr1.rs (100%) rename tests/{compile-fail => fail}/function_pointers/cast_fn_ptr1.stderr (100%) rename tests/{compile-fail => fail}/function_pointers/cast_fn_ptr2.rs (100%) rename tests/{compile-fail => fail}/function_pointers/cast_fn_ptr2.stderr (100%) rename tests/{compile-fail => fail}/function_pointers/cast_fn_ptr3.rs (100%) rename tests/{compile-fail => fail}/function_pointers/cast_fn_ptr3.stderr (100%) rename tests/{compile-fail => fail}/function_pointers/cast_fn_ptr4.rs (100%) rename tests/{compile-fail => fail}/function_pointers/cast_fn_ptr4.stderr (100%) rename tests/{compile-fail => fail}/function_pointers/cast_fn_ptr5.rs (100%) rename tests/{compile-fail => fail}/function_pointers/cast_fn_ptr5.stderr (100%) rename tests/{compile-fail => fail}/function_pointers/cast_int_to_fn_ptr.rs (100%) rename tests/{compile-fail => fail}/function_pointers/cast_int_to_fn_ptr.stderr (100%) rename tests/{compile-fail => fail}/function_pointers/deref_fn_ptr.rs (100%) rename tests/{compile-fail => fail}/function_pointers/deref_fn_ptr.stderr (100%) rename tests/{compile-fail => fail}/function_pointers/execute_memory.rs (100%) rename tests/{compile-fail => fail}/function_pointers/execute_memory.stderr (100%) rename tests/{compile-fail => fail}/function_pointers/fn_ptr_offset.rs (100%) rename tests/{compile-fail => fail}/function_pointers/fn_ptr_offset.stderr (100%) rename tests/{compile-fail => fail}/generator-pinned-moved.rs (100%) rename tests/{compile-fail => fail}/generator-pinned-moved.stderr (100%) rename tests/{compile-fail => fail}/intrinsics/assume.rs (100%) rename tests/{compile-fail => fail}/intrinsics/assume.stderr (100%) rename tests/{compile-fail => fail}/intrinsics/copy_null.rs (100%) rename tests/{compile-fail => fail}/intrinsics/copy_null.stderr (100%) rename tests/{compile-fail => fail}/intrinsics/copy_overflow.rs (100%) rename tests/{compile-fail => fail}/intrinsics/copy_overflow.stderr (100%) rename tests/{compile-fail => fail}/intrinsics/copy_overlapping.rs (100%) rename tests/{compile-fail => fail}/intrinsics/copy_overlapping.stderr (100%) rename tests/{compile-fail => fail}/intrinsics/copy_unaligned.rs (100%) rename tests/{compile-fail => fail}/intrinsics/copy_unaligned.stderr (100%) rename tests/{compile-fail => fail}/intrinsics/ctlz_nonzero.rs (100%) rename tests/{compile-fail => fail}/intrinsics/ctlz_nonzero.stderr (100%) rename tests/{compile-fail => fail}/intrinsics/cttz_nonzero.rs (100%) rename tests/{compile-fail => fail}/intrinsics/cttz_nonzero.stderr (100%) rename tests/{compile-fail => fail}/intrinsics/div-by-zero.rs (100%) rename tests/{compile-fail => fail}/intrinsics/div-by-zero.stderr (100%) rename tests/{compile-fail => fail}/intrinsics/exact_div1.rs (100%) rename tests/{compile-fail => fail}/intrinsics/exact_div1.stderr (100%) rename tests/{compile-fail => fail}/intrinsics/exact_div2.rs (100%) rename tests/{compile-fail => fail}/intrinsics/exact_div2.stderr (100%) rename tests/{compile-fail => fail}/intrinsics/exact_div3.rs (100%) rename tests/{compile-fail => fail}/intrinsics/exact_div3.stderr (100%) rename tests/{compile-fail => fail}/intrinsics/exact_div4.rs (100%) rename tests/{compile-fail => fail}/intrinsics/exact_div4.stderr (100%) rename tests/{compile-fail => fail}/intrinsics/float_to_int_32_inf1.rs (100%) rename tests/{compile-fail => fail}/intrinsics/float_to_int_32_inf1.stderr (100%) rename tests/{compile-fail => fail}/intrinsics/float_to_int_32_infneg1.rs (100%) rename tests/{compile-fail => fail}/intrinsics/float_to_int_32_infneg1.stderr (100%) rename tests/{compile-fail => fail}/intrinsics/float_to_int_32_nan.rs (100%) rename tests/{compile-fail => fail}/intrinsics/float_to_int_32_nan.stderr (100%) rename tests/{compile-fail => fail}/intrinsics/float_to_int_32_nanneg.rs (100%) rename tests/{compile-fail => fail}/intrinsics/float_to_int_32_nanneg.stderr (100%) rename tests/{compile-fail => fail}/intrinsics/float_to_int_32_neg.rs (100%) rename tests/{compile-fail => fail}/intrinsics/float_to_int_32_neg.stderr (100%) rename tests/{compile-fail => fail}/intrinsics/float_to_int_32_too_big1.rs (100%) rename tests/{compile-fail => fail}/intrinsics/float_to_int_32_too_big1.stderr (100%) rename tests/{compile-fail => fail}/intrinsics/float_to_int_32_too_big2.rs (100%) rename tests/{compile-fail => fail}/intrinsics/float_to_int_32_too_big2.stderr (100%) rename tests/{compile-fail => fail}/intrinsics/float_to_int_32_too_small1.rs (100%) rename tests/{compile-fail => fail}/intrinsics/float_to_int_32_too_small1.stderr (100%) rename tests/{compile-fail => fail}/intrinsics/float_to_int_64_inf1.rs (100%) rename tests/{compile-fail => fail}/intrinsics/float_to_int_64_inf1.stderr (100%) rename tests/{compile-fail => fail}/intrinsics/float_to_int_64_infneg1.rs (100%) rename tests/{compile-fail => fail}/intrinsics/float_to_int_64_infneg1.stderr (100%) rename tests/{compile-fail => fail}/intrinsics/float_to_int_64_infneg2.rs (100%) rename tests/{compile-fail => fail}/intrinsics/float_to_int_64_infneg2.stderr (100%) rename tests/{compile-fail => fail}/intrinsics/float_to_int_64_nan.rs (100%) rename tests/{compile-fail => fail}/intrinsics/float_to_int_64_nan.stderr (100%) rename tests/{compile-fail => fail}/intrinsics/float_to_int_64_neg.rs (100%) rename tests/{compile-fail => fail}/intrinsics/float_to_int_64_neg.stderr (100%) rename tests/{compile-fail => fail}/intrinsics/float_to_int_64_too_big1.rs (100%) rename tests/{compile-fail => fail}/intrinsics/float_to_int_64_too_big1.stderr (100%) rename tests/{compile-fail => fail}/intrinsics/float_to_int_64_too_big2.rs (100%) rename tests/{compile-fail => fail}/intrinsics/float_to_int_64_too_big2.stderr (100%) rename tests/{compile-fail => fail}/intrinsics/float_to_int_64_too_big3.rs (100%) rename tests/{compile-fail => fail}/intrinsics/float_to_int_64_too_big3.stderr (100%) rename tests/{compile-fail => fail}/intrinsics/float_to_int_64_too_big4.rs (100%) rename tests/{compile-fail => fail}/intrinsics/float_to_int_64_too_big4.stderr (100%) rename tests/{compile-fail => fail}/intrinsics/float_to_int_64_too_big5.rs (100%) rename tests/{compile-fail => fail}/intrinsics/float_to_int_64_too_big5.stderr (100%) rename tests/{compile-fail => fail}/intrinsics/float_to_int_64_too_big6.rs (100%) rename tests/{compile-fail => fail}/intrinsics/float_to_int_64_too_big6.stderr (100%) rename tests/{compile-fail => fail}/intrinsics/float_to_int_64_too_big7.rs (100%) rename tests/{compile-fail => fail}/intrinsics/float_to_int_64_too_big7.stderr (100%) rename tests/{compile-fail => fail}/intrinsics/float_to_int_64_too_small1.rs (100%) rename tests/{compile-fail => fail}/intrinsics/float_to_int_64_too_small1.stderr (100%) rename tests/{compile-fail => fail}/intrinsics/float_to_int_64_too_small2.rs (100%) rename tests/{compile-fail => fail}/intrinsics/float_to_int_64_too_small2.stderr (100%) rename tests/{compile-fail => fail}/intrinsics/float_to_int_64_too_small3.rs (100%) rename tests/{compile-fail => fail}/intrinsics/float_to_int_64_too_small3.stderr (100%) rename tests/{compile-fail => fail}/intrinsics/out_of_bounds_ptr_1.rs (100%) rename tests/{compile-fail => fail}/intrinsics/out_of_bounds_ptr_1.stderr (100%) rename tests/{compile-fail => fail}/intrinsics/out_of_bounds_ptr_2.rs (100%) rename tests/{compile-fail => fail}/intrinsics/out_of_bounds_ptr_2.stderr (100%) rename tests/{compile-fail => fail}/intrinsics/out_of_bounds_ptr_3.rs (100%) rename tests/{compile-fail => fail}/intrinsics/out_of_bounds_ptr_3.stderr (100%) rename tests/{compile-fail => fail}/intrinsics/overflowing-unchecked-rsh.rs (100%) rename tests/{compile-fail => fail}/intrinsics/overflowing-unchecked-rsh.stderr (100%) rename tests/{compile-fail => fail}/intrinsics/ptr_offset_0_plus_0.rs (100%) rename tests/{compile-fail => fail}/intrinsics/ptr_offset_0_plus_0.stderr (100%) rename tests/{compile-fail => fail}/intrinsics/ptr_offset_from_oob.rs (100%) rename tests/{compile-fail => fail}/intrinsics/ptr_offset_from_oob.stderr (100%) rename tests/{compile-fail => fail}/intrinsics/ptr_offset_int_plus_int.rs (100%) rename tests/{compile-fail => fail}/intrinsics/ptr_offset_int_plus_int.stderr (100%) rename tests/{compile-fail => fail}/intrinsics/ptr_offset_int_plus_ptr.rs (100%) rename tests/{compile-fail => fail}/intrinsics/ptr_offset_int_plus_ptr.stderr (100%) rename tests/{compile-fail => fail}/intrinsics/ptr_offset_overflow.rs (100%) rename tests/{compile-fail => fail}/intrinsics/ptr_offset_overflow.stderr (100%) rename tests/{compile-fail => fail}/intrinsics/ptr_offset_ptr_plus_0.rs (100%) rename tests/{compile-fail => fail}/intrinsics/ptr_offset_ptr_plus_0.stderr (100%) rename tests/{compile-fail => fail}/intrinsics/rem-by-zero.rs (100%) rename tests/{compile-fail => fail}/intrinsics/rem-by-zero.stderr (100%) rename tests/{compile-fail => fail}/intrinsics/simd-div-by-zero.rs (100%) rename tests/{compile-fail => fail}/intrinsics/simd-div-by-zero.stderr (100%) rename tests/{compile-fail => fail}/intrinsics/simd-div-overflow.rs (100%) rename tests/{compile-fail => fail}/intrinsics/simd-div-overflow.stderr (100%) rename tests/{compile-fail => fail}/intrinsics/simd-float-to-int.rs (100%) rename tests/{compile-fail => fail}/intrinsics/simd-float-to-int.stderr (100%) rename tests/{compile-fail => fail}/intrinsics/simd-gather.rs (100%) rename tests/{compile-fail => fail}/intrinsics/simd-gather.stderr (100%) rename tests/{compile-fail => fail}/intrinsics/simd-reduce-invalid-bool.rs (100%) rename tests/{compile-fail => fail}/intrinsics/simd-reduce-invalid-bool.stderr (100%) rename tests/{compile-fail => fail}/intrinsics/simd-rem-by-zero.rs (100%) rename tests/{compile-fail => fail}/intrinsics/simd-rem-by-zero.stderr (100%) rename tests/{compile-fail => fail}/intrinsics/simd-scatter.rs (100%) rename tests/{compile-fail => fail}/intrinsics/simd-scatter.stderr (100%) rename tests/{compile-fail => fail}/intrinsics/simd-select-bitmask-invalid.rs (100%) rename tests/{compile-fail => fail}/intrinsics/simd-select-bitmask-invalid.stderr (100%) rename tests/{compile-fail => fail}/intrinsics/simd-select-invalid-bool.rs (100%) rename tests/{compile-fail => fail}/intrinsics/simd-select-invalid-bool.stderr (100%) rename tests/{compile-fail => fail}/intrinsics/simd-shl-too-far.rs (100%) rename tests/{compile-fail => fail}/intrinsics/simd-shl-too-far.stderr (100%) rename tests/{compile-fail => fail}/intrinsics/simd-shr-too-far.rs (100%) rename tests/{compile-fail => fail}/intrinsics/simd-shr-too-far.stderr (100%) rename tests/{compile-fail => fail}/intrinsics/unchecked_add1.rs (100%) rename tests/{compile-fail => fail}/intrinsics/unchecked_add1.stderr (100%) rename tests/{compile-fail => fail}/intrinsics/unchecked_add2.rs (100%) rename tests/{compile-fail => fail}/intrinsics/unchecked_add2.stderr (100%) rename tests/{compile-fail => fail}/intrinsics/unchecked_div1.rs (100%) rename tests/{compile-fail => fail}/intrinsics/unchecked_div1.stderr (100%) rename tests/{compile-fail => fail}/intrinsics/unchecked_mul1.rs (100%) rename tests/{compile-fail => fail}/intrinsics/unchecked_mul1.stderr (100%) rename tests/{compile-fail => fail}/intrinsics/unchecked_mul2.rs (100%) rename tests/{compile-fail => fail}/intrinsics/unchecked_mul2.stderr (100%) rename tests/{compile-fail => fail}/intrinsics/unchecked_sub1.rs (100%) rename tests/{compile-fail => fail}/intrinsics/unchecked_sub1.stderr (100%) rename tests/{compile-fail => fail}/intrinsics/unchecked_sub2.rs (100%) rename tests/{compile-fail => fail}/intrinsics/unchecked_sub2.stderr (100%) rename tests/{compile-fail => fail}/intrinsics/uninit_uninhabited_type.rs (100%) rename tests/{compile-fail => fail}/intrinsics/uninit_uninhabited_type.stderr (100%) rename tests/{compile-fail => fail}/intrinsics/write_bytes_null.rs (100%) rename tests/{compile-fail => fail}/intrinsics/write_bytes_null.stderr (100%) rename tests/{compile-fail => fail}/intrinsics/write_bytes_overflow.rs (100%) rename tests/{compile-fail => fail}/intrinsics/write_bytes_overflow.stderr (100%) rename tests/{compile-fail => fail}/intrinsics/zero_fn_ptr.rs (100%) rename tests/{compile-fail => fail}/intrinsics/zero_fn_ptr.stderr (100%) rename tests/{compile-fail => fail}/invalid_bool.rs (100%) rename tests/{compile-fail => fail}/invalid_bool.stderr (100%) rename tests/{compile-fail => fail}/invalid_char.rs (100%) rename tests/{compile-fail => fail}/invalid_char.stderr (100%) rename tests/{compile-fail => fail}/invalid_enum_tag.rs (100%) rename tests/{compile-fail => fail}/invalid_enum_tag.stderr (100%) rename tests/{compile-fail => fail}/invalid_int.rs (100%) rename tests/{compile-fail => fail}/invalid_int.stderr (100%) rename tests/{compile-fail => fail}/issue-miri-1112.rs (100%) rename tests/{compile-fail => fail}/issue-miri-1112.stderr (100%) rename tests/{compile-fail => fail}/memleak.rs (100%) rename tests/{compile-fail => fail}/memleak.stderr (100%) rename tests/{compile-fail => fail}/memleak_rc.32bit.stderr (100%) rename tests/{compile-fail => fail}/memleak_rc.64bit.stderr (100%) rename tests/{compile-fail => fail}/memleak_rc.rs (100%) rename tests/{compile-fail => fail}/modifying_constants.rs (100%) rename tests/{compile-fail => fail}/modifying_constants.stderr (100%) rename tests/{compile-fail => fail}/never_say_never.rs (100%) rename tests/{compile-fail => fail}/never_say_never.stderr (100%) rename tests/{compile-fail => fail}/never_transmute_humans.rs (100%) rename tests/{compile-fail => fail}/never_transmute_humans.stderr (100%) rename tests/{compile-fail => fail}/never_transmute_void.rs (100%) rename tests/{compile-fail => fail}/never_transmute_void.stderr (100%) rename tests/{compile-fail => fail}/no_main.rs (100%) rename tests/{compile-fail => fail}/no_main.stderr (100%) rename tests/{compile-fail => fail}/null_pointer_deref.stderr (100%) rename tests/{compile-fail => fail}/null_pointer_deref_zst.stderr (100%) rename tests/{compile-fail => fail}/null_pointer_write.stderr (100%) rename tests/{compile-fail => fail}/null_pointer_write_zst.stderr (100%) rename tests/{compile-fail => fail}/panic/bad_miri_start_panic.rs (100%) rename tests/{compile-fail => fail}/panic/bad_miri_start_panic.stderr (100%) rename tests/{compile-fail => fail}/panic/bad_unwind.rs (100%) rename tests/{compile-fail => fail}/panic/bad_unwind.stderr (100%) rename tests/{compile-fail => fail}/panic/double_panic.rs (100%) rename tests/{compile-fail => fail}/panic/double_panic.stderr (100%) rename tests/{compile-fail => fail}/panic/panic_abort1.rs (100%) rename tests/{compile-fail => fail}/panic/panic_abort1.stderr (100%) rename tests/{compile-fail => fail}/panic/panic_abort2.rs (100%) rename tests/{compile-fail => fail}/panic/panic_abort2.stderr (100%) rename tests/{compile-fail => fail}/panic/panic_abort3.rs (100%) rename tests/{compile-fail => fail}/panic/panic_abort3.stderr (100%) rename tests/{compile-fail => fail}/panic/panic_abort4.rs (100%) rename tests/{compile-fail => fail}/panic/panic_abort4.stderr (100%) rename tests/{compile-fail => fail}/panic/unwind_panic_abort.rs (100%) rename tests/{compile-fail => fail}/panic/unwind_panic_abort.stderr (100%) rename tests/{compile-fail => fail}/pointer_partial_overwrite.rs (100%) rename tests/{compile-fail => fail}/pointer_partial_overwrite.stderr (100%) rename tests/{compile-fail => fail}/pointer_partial_read.rs (100%) rename tests/{compile-fail => fail}/pointer_partial_read.stderr (100%) rename tests/{compile-fail => fail}/provenance/ptr_int_unexposed.rs (100%) rename tests/{compile-fail => fail}/provenance/ptr_int_unexposed.stderr (100%) rename tests/{compile-fail => fail}/provenance/ptr_invalid.rs (100%) rename tests/{compile-fail => fail}/provenance/ptr_invalid.stderr (100%) rename tests/{compile-fail => fail}/provenance/ptr_legacy_provenance.rs (100%) rename tests/{compile-fail => fail}/provenance/ptr_legacy_provenance.stderr (100%) rename tests/{compile-fail => fail}/provenance/strict-provenance-offset.rs (100%) rename tests/{compile-fail => fail}/provenance/strict-provenance-offset.stderr (100%) rename tests/{compile-fail => fail}/provenance/strict_provenance_transmute.rs (100%) rename tests/{compile-fail => fail}/provenance/strict_provenance_transmute.stderr (100%) rename tests/{compile-fail => fail}/ptr_integer_array_transmute.stderr (100%) rename tests/{compile-fail => fail}/ptr_integer_transmute.stderr (100%) rename tests/{compile-fail => fail}/rc_as_ptr.rs (100%) rename tests/{compile-fail => fail}/rc_as_ptr.stderr (100%) rename tests/{compile-fail => fail}/reading_half_a_pointer.rs (100%) rename tests/{compile-fail => fail}/reading_half_a_pointer.stderr (100%) rename tests/{compile-fail => fail}/rustc-error.rs (100%) rename tests/{compile-fail => fail}/rustc-error.stderr (100%) rename tests/{compile-fail => fail}/shim_arg_size.32bit.stderr (100%) rename tests/{compile-fail => fail}/shim_arg_size.64bit.stderr (100%) rename tests/{compile-fail => fail}/shim_arg_size.rs (100%) rename tests/{compile-fail => fail}/slice-too-big.stderr (100%) rename tests/{compile-fail => fail}/stacked_borrows/alias_through_mutation.rs (100%) rename tests/{compile-fail => fail}/stacked_borrows/alias_through_mutation.stderr (100%) rename tests/{compile-fail => fail}/stacked_borrows/aliasing_mut1.rs (100%) rename tests/{compile-fail => fail}/stacked_borrows/aliasing_mut1.stderr (100%) rename tests/{compile-fail => fail}/stacked_borrows/aliasing_mut2.rs (100%) rename tests/{compile-fail => fail}/stacked_borrows/aliasing_mut2.stderr (100%) rename tests/{compile-fail => fail}/stacked_borrows/aliasing_mut3.rs (100%) rename tests/{compile-fail => fail}/stacked_borrows/aliasing_mut3.stderr (100%) rename tests/{compile-fail => fail}/stacked_borrows/aliasing_mut4.rs (100%) rename tests/{compile-fail => fail}/stacked_borrows/aliasing_mut4.stderr (100%) rename tests/{compile-fail => fail}/stacked_borrows/box_exclusive_violation1.rs (100%) rename tests/{compile-fail => fail}/stacked_borrows/box_exclusive_violation1.stderr (100%) rename tests/{compile-fail => fail}/stacked_borrows/buggy_as_mut_slice.rs (100%) rename tests/{compile-fail => fail}/stacked_borrows/buggy_as_mut_slice.stderr (100%) rename tests/{compile-fail => fail}/stacked_borrows/buggy_split_at_mut.rs (100%) rename tests/{compile-fail => fail}/stacked_borrows/buggy_split_at_mut.stderr (100%) rename tests/{compile-fail => fail}/stacked_borrows/deallocate_against_barrier1.rs (100%) rename tests/{compile-fail => fail}/stacked_borrows/deallocate_against_barrier1.stderr (100%) rename tests/{compile-fail => fail}/stacked_borrows/deallocate_against_barrier2.rs (100%) rename tests/{compile-fail => fail}/stacked_borrows/deallocate_against_barrier2.stderr (100%) rename tests/{compile-fail => fail}/stacked_borrows/illegal_read1.rs (100%) rename tests/{compile-fail => fail}/stacked_borrows/illegal_read1.stderr (100%) rename tests/{compile-fail => fail}/stacked_borrows/illegal_read2.rs (100%) rename tests/{compile-fail => fail}/stacked_borrows/illegal_read2.stderr (100%) rename tests/{compile-fail => fail}/stacked_borrows/illegal_read3.rs (100%) rename tests/{compile-fail => fail}/stacked_borrows/illegal_read3.stderr (100%) rename tests/{compile-fail => fail}/stacked_borrows/illegal_read4.rs (100%) rename tests/{compile-fail => fail}/stacked_borrows/illegal_read4.stderr (100%) rename tests/{compile-fail => fail}/stacked_borrows/illegal_read5.rs (100%) rename tests/{compile-fail => fail}/stacked_borrows/illegal_read5.stderr (100%) rename tests/{compile-fail => fail}/stacked_borrows/illegal_read6.rs (100%) rename tests/{compile-fail => fail}/stacked_borrows/illegal_read6.stderr (100%) rename tests/{compile-fail => fail}/stacked_borrows/illegal_read7.rs (100%) rename tests/{compile-fail => fail}/stacked_borrows/illegal_read7.stderr (100%) rename tests/{compile-fail => fail}/stacked_borrows/illegal_read8.rs (100%) rename tests/{compile-fail => fail}/stacked_borrows/illegal_read8.stderr (100%) rename tests/{compile-fail => fail}/stacked_borrows/illegal_write1.rs (100%) rename tests/{compile-fail => fail}/stacked_borrows/illegal_write1.stderr (100%) rename tests/{compile-fail => fail}/stacked_borrows/illegal_write2.rs (100%) rename tests/{compile-fail => fail}/stacked_borrows/illegal_write2.stderr (100%) rename tests/{compile-fail => fail}/stacked_borrows/illegal_write3.rs (100%) rename tests/{compile-fail => fail}/stacked_borrows/illegal_write3.stderr (100%) rename tests/{compile-fail => fail}/stacked_borrows/illegal_write4.rs (100%) rename tests/{compile-fail => fail}/stacked_borrows/illegal_write4.stderr (100%) rename tests/{compile-fail => fail}/stacked_borrows/illegal_write5.rs (100%) rename tests/{compile-fail => fail}/stacked_borrows/illegal_write5.stderr (100%) rename tests/{compile-fail => fail}/stacked_borrows/illegal_write6.rs (100%) rename tests/{compile-fail => fail}/stacked_borrows/illegal_write6.stderr (100%) rename tests/{compile-fail => fail}/stacked_borrows/interior_mut1.rs (100%) rename tests/{compile-fail => fail}/stacked_borrows/interior_mut1.stderr (100%) rename tests/{compile-fail => fail}/stacked_borrows/interior_mut2.rs (100%) rename tests/{compile-fail => fail}/stacked_borrows/interior_mut2.stderr (100%) rename tests/{compile-fail => fail}/stacked_borrows/invalidate_against_barrier1.rs (100%) rename tests/{compile-fail => fail}/stacked_borrows/invalidate_against_barrier1.stderr (100%) rename tests/{compile-fail => fail}/stacked_borrows/invalidate_against_barrier2.rs (100%) rename tests/{compile-fail => fail}/stacked_borrows/invalidate_against_barrier2.stderr (100%) rename tests/{compile-fail => fail}/stacked_borrows/issue-miri-1050-1.rs (100%) rename tests/{compile-fail => fail}/stacked_borrows/issue-miri-1050-1.stderr (100%) rename tests/{compile-fail => fail}/stacked_borrows/issue-miri-1050-2.rs (100%) rename tests/{compile-fail => fail}/stacked_borrows/issue-miri-1050-2.stderr (100%) rename tests/{compile-fail => fail}/stacked_borrows/load_invalid_mut.rs (100%) rename tests/{compile-fail => fail}/stacked_borrows/load_invalid_mut.stderr (100%) rename tests/{compile-fail => fail}/stacked_borrows/load_invalid_shr.rs (100%) rename tests/{compile-fail => fail}/stacked_borrows/load_invalid_shr.stderr (100%) rename tests/{compile-fail => fail}/stacked_borrows/mut_exclusive_violation1.rs (100%) rename tests/{compile-fail => fail}/stacked_borrows/mut_exclusive_violation1.stderr (100%) rename tests/{compile-fail => fail}/stacked_borrows/mut_exclusive_violation2.rs (100%) rename tests/{compile-fail => fail}/stacked_borrows/mut_exclusive_violation2.stderr (100%) rename tests/{compile-fail => fail}/stacked_borrows/outdated_local.rs (100%) rename tests/{compile-fail => fail}/stacked_borrows/outdated_local.stderr (100%) rename tests/{compile-fail => fail}/stacked_borrows/pass_invalid_mut.rs (100%) rename tests/{compile-fail => fail}/stacked_borrows/pass_invalid_mut.stderr (100%) rename tests/{compile-fail => fail}/stacked_borrows/pass_invalid_shr.rs (100%) rename tests/{compile-fail => fail}/stacked_borrows/pass_invalid_shr.stderr (100%) rename tests/{compile-fail => fail}/stacked_borrows/pointer_smuggling.rs (100%) rename tests/{compile-fail => fail}/stacked_borrows/pointer_smuggling.stderr (100%) rename tests/{compile-fail => fail}/stacked_borrows/raw_tracking.rs (100%) rename tests/{compile-fail => fail}/stacked_borrows/raw_tracking.stderr (100%) rename tests/{compile-fail => fail}/stacked_borrows/return_invalid_mut.rs (100%) rename tests/{compile-fail => fail}/stacked_borrows/return_invalid_mut.stderr (100%) rename tests/{compile-fail => fail}/stacked_borrows/return_invalid_mut_option.rs (100%) rename tests/{compile-fail => fail}/stacked_borrows/return_invalid_mut_option.stderr (100%) rename tests/{compile-fail => fail}/stacked_borrows/return_invalid_mut_tuple.rs (100%) rename tests/{compile-fail => fail}/stacked_borrows/return_invalid_mut_tuple.stderr (100%) rename tests/{compile-fail => fail}/stacked_borrows/return_invalid_shr.rs (100%) rename tests/{compile-fail => fail}/stacked_borrows/return_invalid_shr.stderr (100%) rename tests/{compile-fail => fail}/stacked_borrows/return_invalid_shr_option.rs (100%) rename tests/{compile-fail => fail}/stacked_borrows/return_invalid_shr_option.stderr (100%) rename tests/{compile-fail => fail}/stacked_borrows/return_invalid_shr_tuple.rs (100%) rename tests/{compile-fail => fail}/stacked_borrows/return_invalid_shr_tuple.stderr (100%) rename tests/{compile-fail => fail}/stacked_borrows/shared_rw_borrows_are_weak1.rs (100%) rename tests/{compile-fail => fail}/stacked_borrows/shared_rw_borrows_are_weak1.stderr (100%) rename tests/{compile-fail => fail}/stacked_borrows/shared_rw_borrows_are_weak2.rs (100%) rename tests/{compile-fail => fail}/stacked_borrows/shared_rw_borrows_are_weak2.stderr (100%) rename tests/{compile-fail => fail}/stacked_borrows/shr_frozen_violation1.rs (100%) rename tests/{compile-fail => fail}/stacked_borrows/shr_frozen_violation1.stderr (100%) rename tests/{compile-fail => fail}/stacked_borrows/static_memory_modification.rs (100%) rename tests/{compile-fail => fail}/stacked_borrows/static_memory_modification.stderr (100%) rename tests/{compile-fail => fail}/stacked_borrows/transmute-is-no-escape.rs (100%) rename tests/{compile-fail => fail}/stacked_borrows/transmute-is-no-escape.stderr (100%) rename tests/{compile-fail => fail}/stacked_borrows/unescaped_local.rs (100%) rename tests/{compile-fail => fail}/stacked_borrows/unescaped_local.stderr (100%) rename tests/{compile-fail => fail}/stacked_borrows/unescaped_static.rs (100%) rename tests/{compile-fail => fail}/stacked_borrows/unescaped_static.stderr (100%) rename tests/{compile-fail => fail}/stacked_borrows/zst_slice.rs (100%) rename tests/{compile-fail => fail}/stacked_borrows/zst_slice.stderr (100%) rename tests/{compile-fail => fail}/static_memory_modification1.rs (100%) rename tests/{compile-fail => fail}/static_memory_modification1.stderr (100%) rename tests/{compile-fail => fail}/static_memory_modification2.rs (100%) rename tests/{compile-fail => fail}/static_memory_modification2.stderr (100%) rename tests/{compile-fail => fail}/static_memory_modification3.rs (100%) rename tests/{compile-fail => fail}/static_memory_modification3.stderr (100%) rename tests/{compile-fail => fail}/strict-provenance-offset.stderr (100%) rename tests/{compile-fail => fail}/strict_provenance_transmute.stderr (100%) rename tests/{compile-fail => fail}/sync/libc_pthread_cond_double_destroy.rs (100%) rename tests/{compile-fail => fail}/sync/libc_pthread_cond_double_destroy.stderr (100%) rename tests/{compile-fail => fail}/sync/libc_pthread_condattr_double_destroy.rs (100%) rename tests/{compile-fail => fail}/sync/libc_pthread_condattr_double_destroy.stderr (100%) rename tests/{compile-fail => fail}/sync/libc_pthread_mutex_NULL_deadlock.rs (100%) rename tests/{compile-fail => fail}/sync/libc_pthread_mutex_NULL_deadlock.stderr (100%) rename tests/{compile-fail => fail}/sync/libc_pthread_mutex_deadlock.rs (100%) rename tests/{compile-fail => fail}/sync/libc_pthread_mutex_deadlock.stderr (100%) rename tests/{compile-fail => fail}/sync/libc_pthread_mutex_default_deadlock.rs (100%) rename tests/{compile-fail => fail}/sync/libc_pthread_mutex_default_deadlock.stderr (100%) rename tests/{compile-fail => fail}/sync/libc_pthread_mutex_destroy_locked.rs (100%) rename tests/{compile-fail => fail}/sync/libc_pthread_mutex_destroy_locked.stderr (100%) rename tests/{compile-fail => fail}/sync/libc_pthread_mutex_double_destroy.rs (100%) rename tests/{compile-fail => fail}/sync/libc_pthread_mutex_double_destroy.stderr (100%) rename tests/{compile-fail => fail}/sync/libc_pthread_mutex_normal_deadlock.rs (100%) rename tests/{compile-fail => fail}/sync/libc_pthread_mutex_normal_deadlock.stderr (100%) rename tests/{compile-fail => fail}/sync/libc_pthread_mutex_normal_unlock_unlocked.rs (100%) rename tests/{compile-fail => fail}/sync/libc_pthread_mutex_normal_unlock_unlocked.stderr (100%) rename tests/{compile-fail => fail}/sync/libc_pthread_mutex_wrong_owner.rs (100%) rename tests/{compile-fail => fail}/sync/libc_pthread_mutex_wrong_owner.stderr (100%) rename tests/{compile-fail => fail}/sync/libc_pthread_mutexattr_double_destroy.rs (100%) rename tests/{compile-fail => fail}/sync/libc_pthread_mutexattr_double_destroy.stderr (100%) rename tests/{compile-fail => fail}/sync/libc_pthread_rwlock_destroy_read_locked.rs (100%) rename tests/{compile-fail => fail}/sync/libc_pthread_rwlock_destroy_read_locked.stderr (100%) rename tests/{compile-fail => fail}/sync/libc_pthread_rwlock_destroy_write_locked.rs (100%) rename tests/{compile-fail => fail}/sync/libc_pthread_rwlock_destroy_write_locked.stderr (100%) rename tests/{compile-fail => fail}/sync/libc_pthread_rwlock_double_destroy.rs (100%) rename tests/{compile-fail => fail}/sync/libc_pthread_rwlock_double_destroy.stderr (100%) rename tests/{compile-fail => fail}/sync/libc_pthread_rwlock_read_write_deadlock_single_thread.rs (100%) rename tests/{compile-fail => fail}/sync/libc_pthread_rwlock_read_write_deadlock_single_thread.stderr (100%) rename tests/{compile-fail => fail}/sync/libc_pthread_rwlock_read_wrong_owner.rs (100%) rename tests/{compile-fail => fail}/sync/libc_pthread_rwlock_read_wrong_owner.stderr (100%) rename tests/{compile-fail => fail}/sync/libc_pthread_rwlock_unlock_unlocked.rs (100%) rename tests/{compile-fail => fail}/sync/libc_pthread_rwlock_unlock_unlocked.stderr (100%) rename tests/{compile-fail => fail}/sync/libc_pthread_rwlock_write_read_deadlock.rs (100%) rename tests/{compile-fail => fail}/sync/libc_pthread_rwlock_write_read_deadlock.stderr (100%) rename tests/{compile-fail => fail}/sync/libc_pthread_rwlock_write_read_deadlock_single_thread.rs (100%) rename tests/{compile-fail => fail}/sync/libc_pthread_rwlock_write_read_deadlock_single_thread.stderr (100%) rename tests/{compile-fail => fail}/sync/libc_pthread_rwlock_write_write_deadlock.rs (100%) rename tests/{compile-fail => fail}/sync/libc_pthread_rwlock_write_write_deadlock.stderr (100%) rename tests/{compile-fail => fail}/sync/libc_pthread_rwlock_write_write_deadlock_single_thread.rs (100%) rename tests/{compile-fail => fail}/sync/libc_pthread_rwlock_write_write_deadlock_single_thread.stderr (100%) rename tests/{compile-fail => fail}/sync/libc_pthread_rwlock_write_wrong_owner.rs (100%) rename tests/{compile-fail => fail}/sync/libc_pthread_rwlock_write_wrong_owner.stderr (100%) rename tests/{compile-fail => fail}/too-big-slice.stderr (100%) rename tests/{compile-fail => fail}/too-big-unsized.stderr (100%) rename tests/{compile-fail => fail}/transmute-pair-uninit.rs (100%) rename tests/{compile-fail => fail}/transmute-pair-uninit.stderr (100%) rename tests/{compile-fail => fail}/transmute_fat1.rs (100%) rename tests/{compile-fail => fail}/transmute_fat1.stderr (100%) rename tests/{compile-fail => fail}/type-too-large.rs (100%) rename tests/{compile-fail => fail}/type-too-large.stderr (100%) rename tests/{compile-fail => fail}/unaligned_pointers/alignment.rs (100%) rename tests/{compile-fail => fail}/unaligned_pointers/alignment.stderr (100%) rename tests/{compile-fail => fail}/unaligned_pointers/atomic_unaligned.rs (100%) rename tests/{compile-fail => fail}/unaligned_pointers/atomic_unaligned.stderr (100%) rename tests/{compile-fail => fail}/unaligned_pointers/dyn_alignment.rs (100%) rename tests/{compile-fail => fail}/unaligned_pointers/dyn_alignment.stderr (100%) rename tests/{compile-fail => fail}/unaligned_pointers/intptrcast_alignment_check.rs (100%) rename tests/{compile-fail => fail}/unaligned_pointers/intptrcast_alignment_check.stderr (100%) rename tests/{compile-fail => fail}/unaligned_pointers/reference_to_packed.rs (100%) rename tests/{compile-fail => fail}/unaligned_pointers/reference_to_packed.stderr (100%) rename tests/{compile-fail => fail}/unaligned_pointers/unaligned_ptr1.rs (100%) rename tests/{compile-fail => fail}/unaligned_pointers/unaligned_ptr1.stderr (100%) rename tests/{compile-fail => fail}/unaligned_pointers/unaligned_ptr2.rs (100%) rename tests/{compile-fail => fail}/unaligned_pointers/unaligned_ptr2.stderr (100%) rename tests/{compile-fail => fail}/unaligned_pointers/unaligned_ptr3.rs (100%) rename tests/{compile-fail => fail}/unaligned_pointers/unaligned_ptr3.stderr (100%) rename tests/{compile-fail => fail}/unaligned_pointers/unaligned_ptr4.rs (100%) rename tests/{compile-fail => fail}/unaligned_pointers/unaligned_ptr4.stderr (100%) rename tests/{compile-fail => fail}/unaligned_pointers/unaligned_ptr_addr_of.rs (100%) rename tests/{compile-fail => fail}/unaligned_pointers/unaligned_ptr_addr_of.stderr (100%) rename tests/{compile-fail => fail}/unaligned_pointers/unaligned_ptr_zst.rs (100%) rename tests/{compile-fail => fail}/unaligned_pointers/unaligned_ptr_zst.stderr (100%) rename tests/{compile-fail => fail}/uninit_buffer.rs (100%) rename tests/{compile-fail => fail}/uninit_buffer.stderr (100%) rename tests/{compile-fail => fail}/uninit_byte_read.rs (100%) rename tests/{compile-fail => fail}/uninit_byte_read.stderr (100%) rename tests/{compile-fail => fail}/uninit_float.stderr (100%) rename tests/{compile-fail => fail}/uninit_integer.stderr (100%) rename tests/{compile-fail => fail}/uninit_integer_signed.stderr (100%) rename tests/{compile-fail => fail}/uninit_raw_ptr.rs (100%) rename tests/{compile-fail => fail}/uninit_raw_ptr.stderr (100%) rename tests/{compile-fail => fail}/unreachable.rs (100%) rename tests/{compile-fail => fail}/unreachable.stderr (100%) rename tests/{compile-fail => fail}/unsupported_foreign_function.rs (100%) rename tests/{compile-fail => fail}/unsupported_foreign_function.stderr (100%) rename tests/{compile-fail => fail}/unsupported_signal.rs (100%) rename tests/{compile-fail => fail}/unsupported_signal.stderr (100%) rename tests/{compile-fail => fail}/validity/cast_fn_ptr1.rs (100%) rename tests/{compile-fail => fail}/validity/cast_fn_ptr1.stderr (100%) rename tests/{compile-fail => fail}/validity/cast_fn_ptr2.rs (100%) rename tests/{compile-fail => fail}/validity/cast_fn_ptr2.stderr (100%) rename tests/{compile-fail => fail}/validity/dangling_ref1.rs (100%) rename tests/{compile-fail => fail}/validity/dangling_ref1.stderr (100%) rename tests/{compile-fail => fail}/validity/dangling_ref2.rs (100%) rename tests/{compile-fail => fail}/validity/dangling_ref2.stderr (100%) rename tests/{compile-fail => fail}/validity/dangling_ref3.rs (100%) rename tests/{compile-fail => fail}/validity/dangling_ref3.stderr (100%) rename tests/{compile-fail => fail}/validity/invalid_bool.rs (100%) rename tests/{compile-fail => fail}/validity/invalid_bool.stderr (100%) rename tests/{compile-fail => fail}/validity/invalid_bool_uninit.rs (100%) rename tests/{compile-fail => fail}/validity/invalid_bool_uninit.stderr (100%) rename tests/{compile-fail => fail}/validity/invalid_char.rs (100%) rename tests/{compile-fail => fail}/validity/invalid_char.stderr (100%) rename tests/{compile-fail => fail}/validity/invalid_char_uninit.rs (100%) rename tests/{compile-fail => fail}/validity/invalid_char_uninit.stderr (100%) rename tests/{compile-fail => fail}/validity/invalid_enum_tag.rs (100%) rename tests/{compile-fail => fail}/validity/invalid_enum_tag.stderr (100%) rename tests/{compile-fail => fail}/validity/invalid_enum_tag_256variants_uninit.rs (100%) rename tests/{compile-fail => fail}/validity/invalid_enum_tag_256variants_uninit.stderr (100%) rename tests/{compile-fail => fail}/validity/invalid_fnptr_null.rs (100%) rename tests/{compile-fail => fail}/validity/invalid_fnptr_null.stderr (100%) rename tests/{compile-fail => fail}/validity/invalid_fnptr_uninit.rs (100%) rename tests/{compile-fail => fail}/validity/invalid_fnptr_uninit.stderr (100%) rename tests/{compile-fail => fail}/validity/invalid_wide_raw.rs (100%) rename tests/{compile-fail => fail}/validity/invalid_wide_raw.stderr (100%) rename tests/{compile-fail => fail}/validity/nonzero.rs (100%) rename tests/{compile-fail => fail}/validity/nonzero.stderr (100%) rename tests/{compile-fail => fail}/validity/ptr_integer_array_transmute.rs (100%) rename tests/{compile-fail => fail}/validity/ptr_integer_array_transmute.stderr (100%) rename tests/{compile-fail => fail}/validity/ptr_integer_transmute.rs (100%) rename tests/{compile-fail => fail}/validity/ptr_integer_transmute.stderr (100%) rename tests/{compile-fail => fail}/validity/ref_to_uninhabited1.rs (100%) rename tests/{compile-fail => fail}/validity/ref_to_uninhabited1.stderr (100%) rename tests/{compile-fail => fail}/validity/ref_to_uninhabited2.rs (100%) rename tests/{compile-fail => fail}/validity/ref_to_uninhabited2.stderr (100%) rename tests/{compile-fail => fail}/validity/too-big-slice.rs (100%) rename tests/{compile-fail => fail}/validity/too-big-slice.stderr (100%) rename tests/{compile-fail => fail}/validity/too-big-unsized.rs (100%) rename tests/{compile-fail => fail}/validity/too-big-unsized.stderr (100%) rename tests/{compile-fail => fail}/validity/transmute_through_ptr.rs (100%) rename tests/{compile-fail => fail}/validity/transmute_through_ptr.stderr (100%) rename tests/{compile-fail => fail}/validity/uninit_float.rs (100%) rename tests/{compile-fail => fail}/validity/uninit_float.stderr (100%) rename tests/{compile-fail => fail}/validity/uninit_integer.rs (100%) rename tests/{compile-fail => fail}/validity/uninit_integer.stderr (100%) rename tests/{compile-fail => fail}/validity/uninit_integer_signed.rs (100%) rename tests/{compile-fail => fail}/validity/uninit_integer_signed.stderr (100%) rename tests/{compile-fail => fail}/zst1.rs (100%) rename tests/{compile-fail => fail}/zst1.stderr (100%) rename tests/{compile-fail => fail}/zst2.rs (100%) rename tests/{compile-fail => fail}/zst2.stderr (100%) rename tests/{compile-fail => fail}/zst3.rs (100%) rename tests/{compile-fail => fail}/zst3.stderr (100%) rename tests/{run-fail => panic}/function_calls/exported_symbol_good_unwind.rs (100%) rename tests/{run-fail => panic}/function_calls/exported_symbol_good_unwind.stderr (100%) rename tests/{run-fail => panic}/panic/div-by-zero-2.rs (100%) rename tests/{run-fail => panic}/panic/div-by-zero-2.stderr (100%) rename tests/{run-fail => panic}/panic/overflowing-lsh-neg.rs (100%) rename tests/{run-fail => panic}/panic/overflowing-lsh-neg.stderr (100%) rename tests/{run-fail => panic}/panic/overflowing-rsh-1.rs (100%) rename tests/{run-fail => panic}/panic/overflowing-rsh-1.stderr (100%) rename tests/{run-fail => panic}/panic/overflowing-rsh-2.rs (100%) rename tests/{run-fail => panic}/panic/overflowing-rsh-2.stderr (100%) rename tests/{run-fail => panic}/panic/panic1.rs (100%) rename tests/{run-fail => panic}/panic/panic1.stderr (100%) rename tests/{run-fail => panic}/panic/panic2.rs (100%) rename tests/{run-fail => panic}/panic/panic2.stderr (100%) rename tests/{run-fail => panic}/panic/panic3.rs (100%) rename tests/{run-fail => panic}/panic/panic3.stderr (100%) rename tests/{run-fail => panic}/panic/panic4.rs (100%) rename tests/{run-fail => panic}/panic/panic4.stderr (100%) rename tests/{run-fail => panic}/panic/unsupported_foreign_function.rs (100%) rename tests/{run-fail => panic}/panic/unsupported_foreign_function.stderr (100%) rename tests/{run-fail => panic}/panic/unsupported_syscall.rs (100%) rename tests/{run-fail => panic}/panic/unsupported_syscall.stderr (100%) rename tests/{run-fail => panic}/transmute_fat2.rs (100%) rename tests/{run-fail => panic}/transmute_fat2.stderr (100%) rename tests/{run-pass => pass}/adjacent-allocs.rs (100%) rename tests/{run-pass => pass}/align.rs (100%) rename tests/{run-pass => pass}/align_offset_symbolic.rs (100%) rename tests/{run-pass => pass}/align_offset_symbolic.stdout (100%) rename tests/{run-pass => pass}/args.rs (100%) rename tests/{run-pass => pass}/args.stdout (100%) rename tests/{run-pass => pass}/arrays.rs (100%) rename tests/{run-pass => pass}/arrays.stdout (100%) rename tests/{run-pass => pass}/associated-const.rs (100%) rename tests/{run-pass => pass}/assume_bug.rs (100%) rename tests/{run-pass => pass}/async-fn.rs (100%) rename tests/{run-pass => pass}/atomic-compare-exchange-weak-never-fail.rs (100%) rename tests/{run-pass => pass}/atomic.rs (100%) rename tests/{run-pass => pass}/available-parallelism.rs (100%) rename tests/{run-pass => pass}/backtrace-api-v0.rs (100%) rename tests/{run-pass => pass}/backtrace-api-v0.stderr (100%) rename tests/{run-pass => pass}/backtrace-api-v0.stdout (100%) rename tests/{run-pass => pass}/backtrace-api-v1.rs (100%) rename tests/{run-pass => pass}/backtrace-api-v1.stderr (100%) rename tests/{run-pass => pass}/backtrace-api-v1.stdout (100%) rename tests/{run-pass => pass}/backtrace-std.rs (100%) rename tests/{run-pass => pass}/backtrace-std.stderr (100%) rename tests/{run-pass => pass}/bad_substs.rs (100%) rename tests/{run-pass => pass}/binary-heap.rs (100%) rename tests/{run-pass => pass}/binops.rs (100%) rename tests/{run-pass => pass}/bools.rs (100%) rename tests/{run-pass => pass}/box.rs (100%) rename tests/{run-pass => pass}/box.stdout (100%) rename tests/{run-pass => pass}/btreemap.rs (100%) rename tests/{run-pass => pass}/c_enums.rs (100%) rename tests/{run-pass => pass}/calloc.rs (100%) rename tests/{run-pass => pass}/calls.rs (100%) rename tests/{run-pass => pass}/cast-rfc0401-vtable-kinds.rs (100%) rename tests/{run-pass => pass}/cast_fn_ptr.rs (100%) rename tests/{run-pass => pass}/cast_fn_ptr_unsafe.rs (100%) rename tests/{run-pass => pass}/catch.rs (100%) rename tests/{run-pass => pass}/catch.stdout (100%) rename tests/{run-pass => pass}/cfg_miri.rs (100%) rename tests/{run-pass => pass}/char.rs (100%) rename tests/{run-pass => pass}/closure-drop.rs (100%) rename tests/{run-pass => pass}/closure-field-ty.rs (100%) rename tests/{run-pass => pass}/closures.rs (100%) rename tests/{run-pass => pass}/coerce_non_capture_closure_to_fn_ptr.rs (100%) rename tests/{run-pass => pass}/coercions.rs (100%) rename tests/{run-pass => pass}/concurrency/channels.rs (100%) rename tests/{run-pass => pass}/concurrency/channels.stderr (100%) rename tests/{run-pass => pass}/concurrency/concurrent_caller_location.rs (100%) rename tests/{run-pass => pass}/concurrency/concurrent_caller_location.stderr (100%) rename tests/{run-pass => pass}/concurrency/data_race.rs (100%) rename tests/{run-pass => pass}/concurrency/data_race.stderr (100%) rename tests/{run-pass => pass}/concurrency/disable_data_race_detector.rs (100%) rename tests/{run-pass => pass}/concurrency/disable_data_race_detector.stderr (100%) rename tests/{run-pass => pass}/concurrency/issue1643.rs (100%) rename tests/{run-pass => pass}/concurrency/issue1643.stderr (100%) rename tests/{run-pass => pass}/concurrency/libc_pthread_cond.rs (100%) rename tests/{run-pass => pass}/concurrency/linux-futex.rs (100%) rename tests/{run-pass => pass}/concurrency/linux-futex.stderr (100%) rename tests/{run-pass => pass}/concurrency/simple.rs (100%) rename tests/{run-pass => pass}/concurrency/simple.stderr (100%) rename tests/{run-pass => pass}/concurrency/sync.rs (100%) rename tests/{run-pass => pass}/concurrency/sync.stderr (100%) rename tests/{run-pass => pass}/concurrency/sync.stdout (100%) rename tests/{run-pass => pass}/concurrency/sync_singlethread.rs (100%) rename tests/{run-pass => pass}/concurrency/thread_locals.rs (100%) rename tests/{run-pass => pass}/concurrency/thread_locals.stderr (100%) rename tests/{run-pass => pass}/concurrency/tls_lib_drop.rs (100%) rename tests/{run-pass => pass}/concurrency/tls_lib_drop.stderr (100%) rename tests/{run-pass => pass}/concurrency/tls_lib_drop.stdout (100%) rename tests/{run-pass => pass}/concurrency/tls_lib_drop_single_thread.rs (100%) rename tests/{run-pass => pass}/concurrency/tls_lib_drop_single_thread.stderr (100%) rename tests/{run-pass => pass}/concurrency/tls_pthread_drop_order.rs (100%) rename tests/{run-pass => pass}/const-vec-of-fns.rs (100%) rename tests/{run-pass => pass}/constants.rs (100%) rename tests/{run-pass => pass}/current_dir.rs (100%) rename tests/{run-pass => pass}/current_dir_with_isolation.rs (100%) rename tests/{run-pass => pass}/current_dir_with_isolation.stderr (100%) rename tests/{run-pass => pass}/deriving-associated-types.rs (100%) rename tests/{run-pass => pass}/disable-alignment-check.rs (100%) rename tests/{run-pass => pass}/drop_empty_slice.rs (100%) rename tests/{run-pass => pass}/drop_on_array_elements.rs (100%) rename tests/{run-pass => pass}/drop_on_fat_ptr_array_elements.rs (100%) rename tests/{run-pass => pass}/drop_on_zst_array_elements.rs (100%) rename tests/{run-pass => pass}/drop_through_owned_slice.rs (100%) rename tests/{run-pass => pass}/drop_through_trait_object.rs (100%) rename tests/{run-pass => pass}/drop_through_trait_object_rc.rs (100%) rename tests/{run-pass => pass}/dst-field-align.rs (100%) rename tests/{run-pass => pass}/dst-irrefutable-bind.rs (100%) rename tests/{run-pass => pass}/dst-raw.rs (100%) rename tests/{run-pass => pass}/dst-struct-sole.rs (100%) rename tests/{run-pass => pass}/dst-struct.rs (100%) rename tests/{run-pass => pass}/dyn-arbitrary-self.rs (100%) rename tests/{run-pass => pass}/dyn-traits.rs (100%) rename tests/{run-pass => pass}/enum-nullable-const-null-with-fields.rs (100%) rename tests/{run-pass => pass}/enum_discriminant_ptr_value.rs (100%) rename tests/{run-pass => pass}/enums.rs (100%) rename tests/{run-pass => pass}/env-exclude.rs (100%) rename tests/{run-pass => pass}/env-forward.rs (100%) rename tests/{run-pass => pass}/env-without-isolation.rs (100%) rename tests/{run-pass => pass}/env.rs (100%) rename tests/{run-pass => pass}/env.stdout (100%) rename tests/{run-pass => pass}/exit.rs (100%) rename tests/{run-pass => pass}/extern_crate_std_in_main.rs (100%) rename tests/{run-pass => pass}/extern_types.rs (100%) rename tests/{run-pass => pass}/fat_ptr.rs (100%) rename tests/{run-pass => pass}/float.rs (100%) rename tests/{run-pass => pass}/float_fast_math.rs (100%) rename tests/{run-pass => pass}/foreign-fn-linkname.rs (100%) rename tests/{run-pass => pass}/format.rs (100%) rename tests/{run-pass => pass}/format.stdout (100%) rename tests/{run-pass => pass}/from_utf8.rs (100%) rename tests/{run-pass => pass}/fs.rs (100%) rename tests/{run-pass => pass}/fs.stderr (100%) rename tests/{run-pass => pass}/fs.stdout (100%) rename tests/{run-pass => pass}/fs_with_isolation.rs (100%) rename tests/{run-pass => pass}/fs_with_isolation.stderr (100%) rename tests/{run-pass => pass}/function_calls/disable_abi_check.rs (100%) rename tests/{run-pass => pass}/function_calls/exported_symbol.rs (100%) rename tests/{run-pass => pass}/function_pointers.rs (100%) rename tests/{run-pass => pass}/generator.rs (100%) rename tests/{run-pass => pass}/global_allocator.rs (100%) rename tests/{run-pass => pass}/global_allocator.stdout (100%) rename tests/{run-pass => pass}/hashmap.rs (100%) rename tests/{run-pass => pass}/heap.rs (100%) rename tests/{run-pass => pass}/heap_allocator.rs (100%) rename tests/{run-pass => pass}/hello.rs (100%) rename tests/{run-pass => pass}/hello.stdout (100%) rename tests/{run-pass => pass}/hide_stdout.rs (100%) rename tests/{run-pass => pass}/integer-ops.rs (100%) rename tests/{run-pass => pass}/intptrcast.rs (100%) rename tests/{run-pass => pass}/intrinsics-integer.rs (100%) rename tests/{run-pass => pass}/intrinsics-math.rs (100%) rename tests/{run-pass => pass}/intrinsics-x86.rs (100%) rename tests/{run-pass => pass}/intrinsics.rs (100%) rename tests/{run-pass => pass}/ints.rs (100%) rename tests/{run-pass => pass}/issue-15063.rs (100%) rename tests/{run-pass => pass}/issue-15080.rs (100%) rename tests/{run-pass => pass}/issue-15523-big.rs (100%) rename tests/{run-pass => pass}/issue-17877.rs (100%) rename tests/{run-pass => pass}/issue-20575.rs (100%) rename tests/{run-pass => pass}/issue-23261.rs (100%) rename tests/{run-pass => pass}/issue-26709.rs (100%) rename tests/{run-pass => pass}/issue-27901.rs (100%) rename tests/{run-pass => pass}/issue-29746.rs (100%) rename tests/{run-pass => pass}/issue-30530.rs (100%) rename tests/{run-pass => pass}/issue-31267-additional.rs (100%) rename tests/{run-pass => pass}/issue-33387.rs (100%) rename tests/{run-pass => pass}/issue-34571.rs (100%) rename tests/{run-pass => pass}/issue-35815.rs (100%) rename tests/{run-pass => pass}/issue-36278-prefix-nesting.rs (100%) rename tests/{run-pass => pass}/issue-3794.rs (100%) rename tests/{run-pass => pass}/issue-3794.stdout (100%) rename tests/{run-pass => pass}/issue-53728.rs (100%) rename tests/{run-pass => pass}/issue-5917.rs (100%) rename tests/{run-pass => pass}/issue-73223.rs (100%) rename tests/{run-pass => pass}/issue-91636.rs (100%) rename tests/{run-pass => pass}/issue-94371.rs (100%) rename tests/{run-pass => pass}/issue-miri-1075.rs (100%) rename tests/{run-pass => pass}/issue-miri-133.rs (100%) rename tests/{run-pass => pass}/issue-miri-184.rs (100%) rename tests/{run-pass => pass}/issue-miri-1925.rs (100%) rename tests/{run-pass => pass}/issue-miri-2068-2.rs (100%) rename tests/{run-pass => pass}/issue-miri-2068.rs (100%) rename tests/{run-pass => pass}/iter.rs (100%) rename tests/{run-pass => pass}/last-use-in-cap-clause.rs (100%) rename tests/{run-pass => pass}/leak-in-static.rs (100%) rename tests/{run-pass => pass}/libc.rs (100%) rename tests/{run-pass => pass}/libc.stderr (100%) rename tests/{run-pass => pass}/linked-list.rs (100%) rename tests/{run-pass => pass}/linux-getrandom-without-isolation.rs (100%) rename tests/{run-pass => pass}/linux-getrandom.rs (100%) rename tests/{run-pass => pass}/loop-break-value.rs (100%) rename tests/{run-pass => pass}/loops.rs (100%) rename tests/{run-pass => pass}/main_fn.rs (100%) rename tests/{run-pass => pass}/main_result.rs (100%) rename tests/{run-pass => pass}/malloc.rs (100%) rename tests/{run-pass => pass}/many_shr_bor.rs (100%) rename tests/{run-pass => pass}/match_slice.rs (100%) rename tests/{run-pass => pass}/memchr.rs (100%) rename tests/{run-pass => pass}/memleak_ignored.rs (100%) rename tests/{run-pass => pass}/move-arg-2-unique.rs (100%) rename tests/{run-pass => pass}/move-arg-3-unique.rs (100%) rename tests/{run-pass => pass}/move-uninit-primval.rs (100%) rename tests/{run-pass => pass}/mpsc.rs (100%) rename tests/{run-pass => pass}/multi_arg_closure.rs (100%) rename tests/{run-pass => pass}/negative_discriminant.rs (100%) rename tests/{run-pass => pass}/observed_local_mut.rs (100%) rename tests/{run-pass => pass}/option_box_transmute_ptr.rs (100%) rename tests/{run-pass => pass}/option_eq.rs (100%) rename tests/{run-pass => pass}/overflow_checks_off.rs (100%) rename tests/{run-pass => pass}/overloaded-calls-simple.rs (100%) rename tests/{run-pass => pass}/packed_struct.rs (100%) rename tests/{run-pass => pass}/panic/catch_panic.rs (100%) rename tests/{run-pass => pass}/panic/catch_panic.stderr (100%) rename tests/{run-pass => pass}/panic/concurrent-panic.rs (100%) rename tests/{run-pass => pass}/panic/concurrent-panic.stderr (100%) rename tests/{run-pass => pass}/panic/std-panic-locations.rs (100%) rename tests/{run-pass => pass}/partially-uninit.rs (100%) rename tests/{run-pass => pass}/pointers.rs (100%) rename tests/{run-pass => pass}/portable-simd.rs (100%) rename tests/{run-pass => pass}/products.rs (100%) rename tests/{run-pass => pass}/ptr_int_casts.rs (100%) rename tests/{run-pass => pass}/ptr_int_permissive_provenance.rs (100%) rename tests/{run-pass => pass}/ptr_offset.rs (100%) rename tests/{run-pass => pass}/ptr_raw.rs (100%) rename tests/{run-pass => pass}/rc.rs (100%) rename tests/{run-pass => pass}/recursive_static.rs (100%) rename tests/{run-pass => pass}/reentrant-println.rs (100%) rename tests/{run-pass => pass}/reentrant-println.stdout (100%) rename tests/{run-pass => pass}/regions-lifetime-nonfree-late-bound.rs (100%) rename tests/{run-pass => pass}/regions-mock-trans.rs (100%) rename tests/{run-pass => pass}/rename_std.rs (100%) rename tests/{run-pass => pass}/rfc1623.rs (100%) rename tests/{run-pass => pass}/rust-lang-org.rs (100%) rename tests/{run-pass => pass}/send-is-not-static-par-for.rs (100%) rename tests/{run-pass => pass}/sendable-class.rs (100%) rename tests/{run-pass => pass}/simd-intrinsic-generic-elements.rs (100%) rename tests/{run-pass => pass}/slices.rs (100%) rename tests/{run-pass => pass}/small_enum_size_bug.rs (100%) rename tests/{run-pass => pass}/specialization.rs (100%) rename tests/{run-pass => pass}/stacked-borrows/2phase.rs (100%) rename tests/{run-pass => pass}/stacked-borrows/generators-self-referential.rs (100%) rename tests/{run-pass => pass}/stacked-borrows/int-to-ptr.rs (100%) rename tests/{run-pass => pass}/stacked-borrows/interior_mutability.rs (100%) rename tests/{run-pass => pass}/stacked-borrows/refcell.rs (100%) rename tests/{run-pass => pass}/stacked-borrows/stacked-borrows.rs (100%) rename tests/{run-pass => pass}/stacked-borrows/stacked-borrows.stderr (100%) rename tests/{run-pass => pass}/start.rs (100%) rename tests/{run-pass => pass}/start.stdout (100%) rename tests/{run-pass => pass}/static_memory_modification.rs (100%) rename tests/{run-pass => pass}/static_mut.rs (100%) rename tests/{run-pass => pass}/strings.rs (100%) rename tests/{run-pass => pass}/subslice_array.rs (100%) rename tests/{run-pass => pass}/sums.rs (100%) rename tests/{run-pass => pass}/tag-align-dyn-u64.rs (100%) rename tests/{run-pass => pass}/threadleak_ignored.rs (100%) rename tests/{run-pass => pass}/threadleak_ignored.stderr (100%) rename tests/{run-pass => pass}/time.rs (100%) rename tests/{run-pass => pass}/too-large-primval-write-problem.rs (100%) rename tests/{run-pass => pass}/track-alloc-1.rs (100%) rename tests/{run-pass => pass}/track-alloc-1.stderr (100%) rename tests/{run-pass => pass}/track-caller-attribute.rs (100%) rename tests/{run-pass => pass}/transmute_fat.rs (100%) rename tests/{run-pass => pass}/trivial.rs (100%) rename tests/{run-pass => pass}/try-operator-custom.rs (100%) rename tests/{run-pass => pass}/tuple_like_enum_variant_constructor.rs (100%) rename tests/{run-pass => pass}/tuple_like_enum_variant_constructor_pointer_opt.rs (100%) rename tests/{run-pass => pass}/tuple_like_enum_variant_constructor_struct_pointer_opt.rs (100%) rename tests/{run-pass => pass}/tuple_like_struct_constructor.rs (100%) rename tests/{run-pass => pass}/u128.rs (100%) rename tests/{run-pass => pass}/uninit_number_ignored.rs (100%) rename tests/{run-pass => pass}/union-overwrite.rs (100%) rename tests/{run-pass => pass}/union.rs (100%) rename tests/{run-pass => pass}/unops.rs (100%) rename tests/{run-pass => pass}/unsized-tuple-impls.rs (100%) rename tests/{run-pass => pass}/validation_lifetime_resolution.rs (100%) rename tests/{run-pass => pass}/vec-matching-fold.rs (100%) rename tests/{run-pass => pass}/vec.rs (100%) rename tests/{run-pass => pass}/vecdeque.rs (100%) rename tests/{run-pass => pass}/vecdeque.stdout (100%) rename tests/{run-pass => pass}/volatile.rs (100%) rename tests/{run-pass => pass}/without-validation.rs (100%) rename tests/{run-pass => pass}/write-bytes.rs (100%) rename tests/{run-pass => pass}/wtf8.rs (100%) rename tests/{run-pass => pass}/zst.rs (100%) rename tests/{run-pass => pass}/zst_box.rs (100%) rename tests/{run-pass => pass}/zst_variant_drop.rs (100%) diff --git a/ci.sh b/ci.sh index 080bd9204db54..01b86ff2f96ba 100755 --- a/ci.sh +++ b/ci.sh @@ -26,7 +26,7 @@ function run_tests { # optimizations up all the way). # Optimizations change diagnostics (mostly backtraces), so we don't check them #FIXME(#2155): we want to only run the pass and panic tests here, not the fail tests. - MIRIFLAGS="-O -Zmir-opt-level=4" MIRI_SKIP_UI_CHECKS=1 ./miri test --locked -- tests/{run-pass,run-fail} + MIRIFLAGS="-O -Zmir-opt-level=4" MIRI_SKIP_UI_CHECKS=1 ./miri test --locked -- tests/{pass,panic} fi # On Windows, there is always "python", not "python3" or "python2". diff --git a/tests/compiletest.rs b/tests/compiletest.rs index 3b6cf6a6d1fda..4481c02d76507 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -132,7 +132,7 @@ fn main() { // Let the tests know where to store temp files (they might run for a different target, which can make this hard to find). env::set_var("MIRI_TEMP", env::temp_dir()); - ui(Mode::Pass, "tests/run-pass"); - ui(Mode::Panic, "tests/run-fail"); - ui(Mode::Fail, "tests/compile-fail"); + ui(Mode::Pass, "tests/pass"); + ui(Mode::Panic, "tests/panic"); + ui(Mode::Fail, "tests/fail"); } diff --git a/tests/compile-fail/abort-terminator.rs b/tests/fail/abort-terminator.rs similarity index 100% rename from tests/compile-fail/abort-terminator.rs rename to tests/fail/abort-terminator.rs diff --git a/tests/compile-fail/abort-terminator.stderr b/tests/fail/abort-terminator.stderr similarity index 100% rename from tests/compile-fail/abort-terminator.stderr rename to tests/fail/abort-terminator.stderr diff --git a/tests/compile-fail/alloc/deallocate-bad-alignment.rs b/tests/fail/alloc/deallocate-bad-alignment.rs similarity index 100% rename from tests/compile-fail/alloc/deallocate-bad-alignment.rs rename to tests/fail/alloc/deallocate-bad-alignment.rs diff --git a/tests/compile-fail/alloc/deallocate-bad-alignment.stderr b/tests/fail/alloc/deallocate-bad-alignment.stderr similarity index 100% rename from tests/compile-fail/alloc/deallocate-bad-alignment.stderr rename to tests/fail/alloc/deallocate-bad-alignment.stderr diff --git a/tests/compile-fail/alloc/deallocate-bad-size.rs b/tests/fail/alloc/deallocate-bad-size.rs similarity index 100% rename from tests/compile-fail/alloc/deallocate-bad-size.rs rename to tests/fail/alloc/deallocate-bad-size.rs diff --git a/tests/compile-fail/alloc/deallocate-bad-size.stderr b/tests/fail/alloc/deallocate-bad-size.stderr similarity index 100% rename from tests/compile-fail/alloc/deallocate-bad-size.stderr rename to tests/fail/alloc/deallocate-bad-size.stderr diff --git a/tests/compile-fail/alloc/deallocate-twice.rs b/tests/fail/alloc/deallocate-twice.rs similarity index 100% rename from tests/compile-fail/alloc/deallocate-twice.rs rename to tests/fail/alloc/deallocate-twice.rs diff --git a/tests/compile-fail/alloc/deallocate-twice.stderr b/tests/fail/alloc/deallocate-twice.stderr similarity index 100% rename from tests/compile-fail/alloc/deallocate-twice.stderr rename to tests/fail/alloc/deallocate-twice.stderr diff --git a/tests/compile-fail/alloc/global_system_mixup.rs b/tests/fail/alloc/global_system_mixup.rs similarity index 100% rename from tests/compile-fail/alloc/global_system_mixup.rs rename to tests/fail/alloc/global_system_mixup.rs diff --git a/tests/compile-fail/alloc/global_system_mixup.stderr b/tests/fail/alloc/global_system_mixup.stderr similarity index 100% rename from tests/compile-fail/alloc/global_system_mixup.stderr rename to tests/fail/alloc/global_system_mixup.stderr diff --git a/tests/compile-fail/alloc/no_global_allocator.rs b/tests/fail/alloc/no_global_allocator.rs similarity index 100% rename from tests/compile-fail/alloc/no_global_allocator.rs rename to tests/fail/alloc/no_global_allocator.rs diff --git a/tests/compile-fail/alloc/no_global_allocator.stderr b/tests/fail/alloc/no_global_allocator.stderr similarity index 100% rename from tests/compile-fail/alloc/no_global_allocator.stderr rename to tests/fail/alloc/no_global_allocator.stderr diff --git a/tests/compile-fail/alloc/reallocate-bad-size.rs b/tests/fail/alloc/reallocate-bad-size.rs similarity index 100% rename from tests/compile-fail/alloc/reallocate-bad-size.rs rename to tests/fail/alloc/reallocate-bad-size.rs diff --git a/tests/compile-fail/alloc/reallocate-bad-size.stderr b/tests/fail/alloc/reallocate-bad-size.stderr similarity index 100% rename from tests/compile-fail/alloc/reallocate-bad-size.stderr rename to tests/fail/alloc/reallocate-bad-size.stderr diff --git a/tests/compile-fail/alloc/reallocate-change-alloc.rs b/tests/fail/alloc/reallocate-change-alloc.rs similarity index 100% rename from tests/compile-fail/alloc/reallocate-change-alloc.rs rename to tests/fail/alloc/reallocate-change-alloc.rs diff --git a/tests/compile-fail/alloc/reallocate-change-alloc.stderr b/tests/fail/alloc/reallocate-change-alloc.stderr similarity index 100% rename from tests/compile-fail/alloc/reallocate-change-alloc.stderr rename to tests/fail/alloc/reallocate-change-alloc.stderr diff --git a/tests/compile-fail/alloc/reallocate-dangling.rs b/tests/fail/alloc/reallocate-dangling.rs similarity index 100% rename from tests/compile-fail/alloc/reallocate-dangling.rs rename to tests/fail/alloc/reallocate-dangling.rs diff --git a/tests/compile-fail/alloc/reallocate-dangling.stderr b/tests/fail/alloc/reallocate-dangling.stderr similarity index 100% rename from tests/compile-fail/alloc/reallocate-dangling.stderr rename to tests/fail/alloc/reallocate-dangling.stderr diff --git a/tests/compile-fail/alloc/stack_free.rs b/tests/fail/alloc/stack_free.rs similarity index 100% rename from tests/compile-fail/alloc/stack_free.rs rename to tests/fail/alloc/stack_free.rs diff --git a/tests/compile-fail/alloc/stack_free.stderr b/tests/fail/alloc/stack_free.stderr similarity index 100% rename from tests/compile-fail/alloc/stack_free.stderr rename to tests/fail/alloc/stack_free.stderr diff --git a/tests/compile-fail/backtrace/bad-backtrace-decl.rs b/tests/fail/backtrace/bad-backtrace-decl.rs similarity index 100% rename from tests/compile-fail/backtrace/bad-backtrace-decl.rs rename to tests/fail/backtrace/bad-backtrace-decl.rs diff --git a/tests/compile-fail/backtrace/bad-backtrace-decl.stderr b/tests/fail/backtrace/bad-backtrace-decl.stderr similarity index 100% rename from tests/compile-fail/backtrace/bad-backtrace-decl.stderr rename to tests/fail/backtrace/bad-backtrace-decl.stderr diff --git a/tests/compile-fail/backtrace/bad-backtrace-flags.rs b/tests/fail/backtrace/bad-backtrace-flags.rs similarity index 100% rename from tests/compile-fail/backtrace/bad-backtrace-flags.rs rename to tests/fail/backtrace/bad-backtrace-flags.rs diff --git a/tests/compile-fail/backtrace/bad-backtrace-flags.stderr b/tests/fail/backtrace/bad-backtrace-flags.stderr similarity index 100% rename from tests/compile-fail/backtrace/bad-backtrace-flags.stderr rename to tests/fail/backtrace/bad-backtrace-flags.stderr diff --git a/tests/compile-fail/backtrace/bad-backtrace-ptr.rs b/tests/fail/backtrace/bad-backtrace-ptr.rs similarity index 100% rename from tests/compile-fail/backtrace/bad-backtrace-ptr.rs rename to tests/fail/backtrace/bad-backtrace-ptr.rs diff --git a/tests/compile-fail/backtrace/bad-backtrace-ptr.stderr b/tests/fail/backtrace/bad-backtrace-ptr.stderr similarity index 100% rename from tests/compile-fail/backtrace/bad-backtrace-ptr.stderr rename to tests/fail/backtrace/bad-backtrace-ptr.stderr diff --git a/tests/compile-fail/backtrace/bad-backtrace-resolve-flags.rs b/tests/fail/backtrace/bad-backtrace-resolve-flags.rs similarity index 100% rename from tests/compile-fail/backtrace/bad-backtrace-resolve-flags.rs rename to tests/fail/backtrace/bad-backtrace-resolve-flags.rs diff --git a/tests/compile-fail/backtrace/bad-backtrace-resolve-flags.stderr b/tests/fail/backtrace/bad-backtrace-resolve-flags.stderr similarity index 100% rename from tests/compile-fail/backtrace/bad-backtrace-resolve-flags.stderr rename to tests/fail/backtrace/bad-backtrace-resolve-flags.stderr diff --git a/tests/compile-fail/backtrace/bad-backtrace-resolve-names-flags.rs b/tests/fail/backtrace/bad-backtrace-resolve-names-flags.rs similarity index 100% rename from tests/compile-fail/backtrace/bad-backtrace-resolve-names-flags.rs rename to tests/fail/backtrace/bad-backtrace-resolve-names-flags.rs diff --git a/tests/compile-fail/backtrace/bad-backtrace-resolve-names-flags.stderr b/tests/fail/backtrace/bad-backtrace-resolve-names-flags.stderr similarity index 100% rename from tests/compile-fail/backtrace/bad-backtrace-resolve-names-flags.stderr rename to tests/fail/backtrace/bad-backtrace-resolve-names-flags.stderr diff --git a/tests/compile-fail/backtrace/bad-backtrace-size-flags.rs b/tests/fail/backtrace/bad-backtrace-size-flags.rs similarity index 100% rename from tests/compile-fail/backtrace/bad-backtrace-size-flags.rs rename to tests/fail/backtrace/bad-backtrace-size-flags.rs diff --git a/tests/compile-fail/backtrace/bad-backtrace-size-flags.stderr b/tests/fail/backtrace/bad-backtrace-size-flags.stderr similarity index 100% rename from tests/compile-fail/backtrace/bad-backtrace-size-flags.stderr rename to tests/fail/backtrace/bad-backtrace-size-flags.stderr diff --git a/tests/compile-fail/backtrace/bad-backtrace-version.stderr b/tests/fail/backtrace/bad-backtrace-version.stderr similarity index 100% rename from tests/compile-fail/backtrace/bad-backtrace-version.stderr rename to tests/fail/backtrace/bad-backtrace-version.stderr diff --git a/tests/compile-fail/box-cell-alias.rs b/tests/fail/box-cell-alias.rs similarity index 100% rename from tests/compile-fail/box-cell-alias.rs rename to tests/fail/box-cell-alias.rs diff --git a/tests/compile-fail/box-cell-alias.stderr b/tests/fail/box-cell-alias.stderr similarity index 100% rename from tests/compile-fail/box-cell-alias.stderr rename to tests/fail/box-cell-alias.stderr diff --git a/tests/compile-fail/branchless-select-i128-pointer.rs b/tests/fail/branchless-select-i128-pointer.rs similarity index 100% rename from tests/compile-fail/branchless-select-i128-pointer.rs rename to tests/fail/branchless-select-i128-pointer.rs diff --git a/tests/compile-fail/branchless-select-i128-pointer.stderr b/tests/fail/branchless-select-i128-pointer.stderr similarity index 100% rename from tests/compile-fail/branchless-select-i128-pointer.stderr rename to tests/fail/branchless-select-i128-pointer.stderr diff --git a/tests/compile-fail/breakpoint.rs b/tests/fail/breakpoint.rs similarity index 100% rename from tests/compile-fail/breakpoint.rs rename to tests/fail/breakpoint.rs diff --git a/tests/compile-fail/breakpoint.stderr b/tests/fail/breakpoint.stderr similarity index 100% rename from tests/compile-fail/breakpoint.stderr rename to tests/fail/breakpoint.stderr diff --git a/tests/compile-fail/concurrency/libc_pthread_create_main_terminate.rs b/tests/fail/concurrency/libc_pthread_create_main_terminate.rs similarity index 100% rename from tests/compile-fail/concurrency/libc_pthread_create_main_terminate.rs rename to tests/fail/concurrency/libc_pthread_create_main_terminate.rs diff --git a/tests/compile-fail/concurrency/libc_pthread_create_main_terminate.stderr b/tests/fail/concurrency/libc_pthread_create_main_terminate.stderr similarity index 100% rename from tests/compile-fail/concurrency/libc_pthread_create_main_terminate.stderr rename to tests/fail/concurrency/libc_pthread_create_main_terminate.stderr diff --git a/tests/compile-fail/concurrency/libc_pthread_join_detached.rs b/tests/fail/concurrency/libc_pthread_join_detached.rs similarity index 100% rename from tests/compile-fail/concurrency/libc_pthread_join_detached.rs rename to tests/fail/concurrency/libc_pthread_join_detached.rs diff --git a/tests/compile-fail/concurrency/libc_pthread_join_detached.stderr b/tests/fail/concurrency/libc_pthread_join_detached.stderr similarity index 100% rename from tests/compile-fail/concurrency/libc_pthread_join_detached.stderr rename to tests/fail/concurrency/libc_pthread_join_detached.stderr diff --git a/tests/compile-fail/concurrency/libc_pthread_join_joined.rs b/tests/fail/concurrency/libc_pthread_join_joined.rs similarity index 100% rename from tests/compile-fail/concurrency/libc_pthread_join_joined.rs rename to tests/fail/concurrency/libc_pthread_join_joined.rs diff --git a/tests/compile-fail/concurrency/libc_pthread_join_joined.stderr b/tests/fail/concurrency/libc_pthread_join_joined.stderr similarity index 100% rename from tests/compile-fail/concurrency/libc_pthread_join_joined.stderr rename to tests/fail/concurrency/libc_pthread_join_joined.stderr diff --git a/tests/compile-fail/concurrency/libc_pthread_join_main.rs b/tests/fail/concurrency/libc_pthread_join_main.rs similarity index 100% rename from tests/compile-fail/concurrency/libc_pthread_join_main.rs rename to tests/fail/concurrency/libc_pthread_join_main.rs diff --git a/tests/compile-fail/concurrency/libc_pthread_join_main.stderr b/tests/fail/concurrency/libc_pthread_join_main.stderr similarity index 100% rename from tests/compile-fail/concurrency/libc_pthread_join_main.stderr rename to tests/fail/concurrency/libc_pthread_join_main.stderr diff --git a/tests/compile-fail/concurrency/libc_pthread_join_multiple.rs b/tests/fail/concurrency/libc_pthread_join_multiple.rs similarity index 100% rename from tests/compile-fail/concurrency/libc_pthread_join_multiple.rs rename to tests/fail/concurrency/libc_pthread_join_multiple.rs diff --git a/tests/compile-fail/concurrency/libc_pthread_join_multiple.stderr b/tests/fail/concurrency/libc_pthread_join_multiple.stderr similarity index 100% rename from tests/compile-fail/concurrency/libc_pthread_join_multiple.stderr rename to tests/fail/concurrency/libc_pthread_join_multiple.stderr diff --git a/tests/compile-fail/concurrency/libc_pthread_join_self.rs b/tests/fail/concurrency/libc_pthread_join_self.rs similarity index 100% rename from tests/compile-fail/concurrency/libc_pthread_join_self.rs rename to tests/fail/concurrency/libc_pthread_join_self.rs diff --git a/tests/compile-fail/concurrency/libc_pthread_join_self.stderr b/tests/fail/concurrency/libc_pthread_join_self.stderr similarity index 100% rename from tests/compile-fail/concurrency/libc_pthread_join_self.stderr rename to tests/fail/concurrency/libc_pthread_join_self.stderr diff --git a/tests/compile-fail/concurrency/thread-spawn.rs b/tests/fail/concurrency/thread-spawn.rs similarity index 100% rename from tests/compile-fail/concurrency/thread-spawn.rs rename to tests/fail/concurrency/thread-spawn.rs diff --git a/tests/compile-fail/concurrency/thread_local_static_dealloc.rs b/tests/fail/concurrency/thread_local_static_dealloc.rs similarity index 100% rename from tests/compile-fail/concurrency/thread_local_static_dealloc.rs rename to tests/fail/concurrency/thread_local_static_dealloc.rs diff --git a/tests/compile-fail/concurrency/thread_local_static_dealloc.stderr b/tests/fail/concurrency/thread_local_static_dealloc.stderr similarity index 100% rename from tests/compile-fail/concurrency/thread_local_static_dealloc.stderr rename to tests/fail/concurrency/thread_local_static_dealloc.stderr diff --git a/tests/compile-fail/concurrency/too_few_args.rs b/tests/fail/concurrency/too_few_args.rs similarity index 100% rename from tests/compile-fail/concurrency/too_few_args.rs rename to tests/fail/concurrency/too_few_args.rs diff --git a/tests/compile-fail/concurrency/too_few_args.stderr b/tests/fail/concurrency/too_few_args.stderr similarity index 100% rename from tests/compile-fail/concurrency/too_few_args.stderr rename to tests/fail/concurrency/too_few_args.stderr diff --git a/tests/compile-fail/concurrency/too_many_args.rs b/tests/fail/concurrency/too_many_args.rs similarity index 100% rename from tests/compile-fail/concurrency/too_many_args.rs rename to tests/fail/concurrency/too_many_args.rs diff --git a/tests/compile-fail/concurrency/too_many_args.stderr b/tests/fail/concurrency/too_many_args.stderr similarity index 100% rename from tests/compile-fail/concurrency/too_many_args.stderr rename to tests/fail/concurrency/too_many_args.stderr diff --git a/tests/compile-fail/concurrency/unwind_top_of_stack.rs b/tests/fail/concurrency/unwind_top_of_stack.rs similarity index 100% rename from tests/compile-fail/concurrency/unwind_top_of_stack.rs rename to tests/fail/concurrency/unwind_top_of_stack.rs diff --git a/tests/compile-fail/concurrency/unwind_top_of_stack.stderr b/tests/fail/concurrency/unwind_top_of_stack.stderr similarity index 100% rename from tests/compile-fail/concurrency/unwind_top_of_stack.stderr rename to tests/fail/concurrency/unwind_top_of_stack.stderr diff --git a/tests/compile-fail/dangling_pointers/dangling_pointer_addr_of.rs b/tests/fail/dangling_pointers/dangling_pointer_addr_of.rs similarity index 100% rename from tests/compile-fail/dangling_pointers/dangling_pointer_addr_of.rs rename to tests/fail/dangling_pointers/dangling_pointer_addr_of.rs diff --git a/tests/compile-fail/dangling_pointers/dangling_pointer_addr_of.stderr b/tests/fail/dangling_pointers/dangling_pointer_addr_of.stderr similarity index 100% rename from tests/compile-fail/dangling_pointers/dangling_pointer_addr_of.stderr rename to tests/fail/dangling_pointers/dangling_pointer_addr_of.stderr diff --git a/tests/compile-fail/dangling_pointers/dangling_pointer_deref.rs b/tests/fail/dangling_pointers/dangling_pointer_deref.rs similarity index 100% rename from tests/compile-fail/dangling_pointers/dangling_pointer_deref.rs rename to tests/fail/dangling_pointers/dangling_pointer_deref.rs diff --git a/tests/compile-fail/dangling_pointers/dangling_pointer_deref.stderr b/tests/fail/dangling_pointers/dangling_pointer_deref.stderr similarity index 100% rename from tests/compile-fail/dangling_pointers/dangling_pointer_deref.stderr rename to tests/fail/dangling_pointers/dangling_pointer_deref.stderr diff --git a/tests/compile-fail/dangling_pointers/dangling_zst_deref.rs b/tests/fail/dangling_pointers/dangling_zst_deref.rs similarity index 100% rename from tests/compile-fail/dangling_pointers/dangling_zst_deref.rs rename to tests/fail/dangling_pointers/dangling_zst_deref.rs diff --git a/tests/compile-fail/dangling_pointers/dangling_zst_deref.stderr b/tests/fail/dangling_pointers/dangling_zst_deref.stderr similarity index 100% rename from tests/compile-fail/dangling_pointers/dangling_zst_deref.stderr rename to tests/fail/dangling_pointers/dangling_zst_deref.stderr diff --git a/tests/compile-fail/dangling_pointers/deref-invalid-ptr.rs b/tests/fail/dangling_pointers/deref-invalid-ptr.rs similarity index 100% rename from tests/compile-fail/dangling_pointers/deref-invalid-ptr.rs rename to tests/fail/dangling_pointers/deref-invalid-ptr.rs diff --git a/tests/compile-fail/dangling_pointers/deref-invalid-ptr.stderr b/tests/fail/dangling_pointers/deref-invalid-ptr.stderr similarity index 100% rename from tests/compile-fail/dangling_pointers/deref-invalid-ptr.stderr rename to tests/fail/dangling_pointers/deref-invalid-ptr.stderr diff --git a/tests/compile-fail/dangling_pointers/deref-partially-dangling.rs b/tests/fail/dangling_pointers/deref-partially-dangling.rs similarity index 100% rename from tests/compile-fail/dangling_pointers/deref-partially-dangling.rs rename to tests/fail/dangling_pointers/deref-partially-dangling.rs diff --git a/tests/compile-fail/dangling_pointers/deref-partially-dangling.stderr b/tests/fail/dangling_pointers/deref-partially-dangling.stderr similarity index 100% rename from tests/compile-fail/dangling_pointers/deref-partially-dangling.stderr rename to tests/fail/dangling_pointers/deref-partially-dangling.stderr diff --git a/tests/compile-fail/dangling_pointers/dyn_size.rs b/tests/fail/dangling_pointers/dyn_size.rs similarity index 100% rename from tests/compile-fail/dangling_pointers/dyn_size.rs rename to tests/fail/dangling_pointers/dyn_size.rs diff --git a/tests/compile-fail/dangling_pointers/dyn_size.stderr b/tests/fail/dangling_pointers/dyn_size.stderr similarity index 100% rename from tests/compile-fail/dangling_pointers/dyn_size.stderr rename to tests/fail/dangling_pointers/dyn_size.stderr diff --git a/tests/compile-fail/dangling_pointers/maybe_null_pointer_deref_zst.rs b/tests/fail/dangling_pointers/maybe_null_pointer_deref_zst.rs similarity index 100% rename from tests/compile-fail/dangling_pointers/maybe_null_pointer_deref_zst.rs rename to tests/fail/dangling_pointers/maybe_null_pointer_deref_zst.rs diff --git a/tests/compile-fail/dangling_pointers/maybe_null_pointer_deref_zst.stderr b/tests/fail/dangling_pointers/maybe_null_pointer_deref_zst.stderr similarity index 100% rename from tests/compile-fail/dangling_pointers/maybe_null_pointer_deref_zst.stderr rename to tests/fail/dangling_pointers/maybe_null_pointer_deref_zst.stderr diff --git a/tests/compile-fail/dangling_pointers/maybe_null_pointer_write_zst.rs b/tests/fail/dangling_pointers/maybe_null_pointer_write_zst.rs similarity index 100% rename from tests/compile-fail/dangling_pointers/maybe_null_pointer_write_zst.rs rename to tests/fail/dangling_pointers/maybe_null_pointer_write_zst.rs diff --git a/tests/compile-fail/dangling_pointers/maybe_null_pointer_write_zst.stderr b/tests/fail/dangling_pointers/maybe_null_pointer_write_zst.stderr similarity index 100% rename from tests/compile-fail/dangling_pointers/maybe_null_pointer_write_zst.stderr rename to tests/fail/dangling_pointers/maybe_null_pointer_write_zst.stderr diff --git a/tests/compile-fail/dangling_pointers/null_pointer_deref.rs b/tests/fail/dangling_pointers/null_pointer_deref.rs similarity index 100% rename from tests/compile-fail/dangling_pointers/null_pointer_deref.rs rename to tests/fail/dangling_pointers/null_pointer_deref.rs diff --git a/tests/compile-fail/dangling_pointers/null_pointer_deref.stderr b/tests/fail/dangling_pointers/null_pointer_deref.stderr similarity index 100% rename from tests/compile-fail/dangling_pointers/null_pointer_deref.stderr rename to tests/fail/dangling_pointers/null_pointer_deref.stderr diff --git a/tests/compile-fail/dangling_pointers/null_pointer_deref_zst.rs b/tests/fail/dangling_pointers/null_pointer_deref_zst.rs similarity index 100% rename from tests/compile-fail/dangling_pointers/null_pointer_deref_zst.rs rename to tests/fail/dangling_pointers/null_pointer_deref_zst.rs diff --git a/tests/compile-fail/dangling_pointers/null_pointer_deref_zst.stderr b/tests/fail/dangling_pointers/null_pointer_deref_zst.stderr similarity index 100% rename from tests/compile-fail/dangling_pointers/null_pointer_deref_zst.stderr rename to tests/fail/dangling_pointers/null_pointer_deref_zst.stderr diff --git a/tests/compile-fail/dangling_pointers/null_pointer_write.rs b/tests/fail/dangling_pointers/null_pointer_write.rs similarity index 100% rename from tests/compile-fail/dangling_pointers/null_pointer_write.rs rename to tests/fail/dangling_pointers/null_pointer_write.rs diff --git a/tests/compile-fail/dangling_pointers/null_pointer_write.stderr b/tests/fail/dangling_pointers/null_pointer_write.stderr similarity index 100% rename from tests/compile-fail/dangling_pointers/null_pointer_write.stderr rename to tests/fail/dangling_pointers/null_pointer_write.stderr diff --git a/tests/compile-fail/dangling_pointers/null_pointer_write_zst.rs b/tests/fail/dangling_pointers/null_pointer_write_zst.rs similarity index 100% rename from tests/compile-fail/dangling_pointers/null_pointer_write_zst.rs rename to tests/fail/dangling_pointers/null_pointer_write_zst.rs diff --git a/tests/compile-fail/dangling_pointers/null_pointer_write_zst.stderr b/tests/fail/dangling_pointers/null_pointer_write_zst.stderr similarity index 100% rename from tests/compile-fail/dangling_pointers/null_pointer_write_zst.stderr rename to tests/fail/dangling_pointers/null_pointer_write_zst.stderr diff --git a/tests/compile-fail/dangling_pointers/out_of_bounds_read1.rs b/tests/fail/dangling_pointers/out_of_bounds_read1.rs similarity index 100% rename from tests/compile-fail/dangling_pointers/out_of_bounds_read1.rs rename to tests/fail/dangling_pointers/out_of_bounds_read1.rs diff --git a/tests/compile-fail/dangling_pointers/out_of_bounds_read1.stderr b/tests/fail/dangling_pointers/out_of_bounds_read1.stderr similarity index 100% rename from tests/compile-fail/dangling_pointers/out_of_bounds_read1.stderr rename to tests/fail/dangling_pointers/out_of_bounds_read1.stderr diff --git a/tests/compile-fail/dangling_pointers/out_of_bounds_read2.rs b/tests/fail/dangling_pointers/out_of_bounds_read2.rs similarity index 100% rename from tests/compile-fail/dangling_pointers/out_of_bounds_read2.rs rename to tests/fail/dangling_pointers/out_of_bounds_read2.rs diff --git a/tests/compile-fail/dangling_pointers/out_of_bounds_read2.stderr b/tests/fail/dangling_pointers/out_of_bounds_read2.stderr similarity index 100% rename from tests/compile-fail/dangling_pointers/out_of_bounds_read2.stderr rename to tests/fail/dangling_pointers/out_of_bounds_read2.stderr diff --git a/tests/compile-fail/dangling_pointers/stack_temporary.rs b/tests/fail/dangling_pointers/stack_temporary.rs similarity index 100% rename from tests/compile-fail/dangling_pointers/stack_temporary.rs rename to tests/fail/dangling_pointers/stack_temporary.rs diff --git a/tests/compile-fail/dangling_pointers/stack_temporary.stderr b/tests/fail/dangling_pointers/stack_temporary.stderr similarity index 100% rename from tests/compile-fail/dangling_pointers/stack_temporary.stderr rename to tests/fail/dangling_pointers/stack_temporary.stderr diff --git a/tests/compile-fail/dangling_pointers/storage_dead_dangling.rs b/tests/fail/dangling_pointers/storage_dead_dangling.rs similarity index 100% rename from tests/compile-fail/dangling_pointers/storage_dead_dangling.rs rename to tests/fail/dangling_pointers/storage_dead_dangling.rs diff --git a/tests/compile-fail/dangling_pointers/storage_dead_dangling.stderr b/tests/fail/dangling_pointers/storage_dead_dangling.stderr similarity index 100% rename from tests/compile-fail/dangling_pointers/storage_dead_dangling.stderr rename to tests/fail/dangling_pointers/storage_dead_dangling.stderr diff --git a/tests/compile-fail/dangling_pointers/wild_pointer_deref.rs b/tests/fail/dangling_pointers/wild_pointer_deref.rs similarity index 100% rename from tests/compile-fail/dangling_pointers/wild_pointer_deref.rs rename to tests/fail/dangling_pointers/wild_pointer_deref.rs diff --git a/tests/compile-fail/dangling_pointers/wild_pointer_deref.stderr b/tests/fail/dangling_pointers/wild_pointer_deref.stderr similarity index 100% rename from tests/compile-fail/dangling_pointers/wild_pointer_deref.stderr rename to tests/fail/dangling_pointers/wild_pointer_deref.stderr diff --git a/tests/compile-fail/data_race/alloc_read_race.rs b/tests/fail/data_race/alloc_read_race.rs similarity index 100% rename from tests/compile-fail/data_race/alloc_read_race.rs rename to tests/fail/data_race/alloc_read_race.rs diff --git a/tests/compile-fail/data_race/alloc_read_race.stderr b/tests/fail/data_race/alloc_read_race.stderr similarity index 100% rename from tests/compile-fail/data_race/alloc_read_race.stderr rename to tests/fail/data_race/alloc_read_race.stderr diff --git a/tests/compile-fail/data_race/alloc_write_race.rs b/tests/fail/data_race/alloc_write_race.rs similarity index 100% rename from tests/compile-fail/data_race/alloc_write_race.rs rename to tests/fail/data_race/alloc_write_race.rs diff --git a/tests/compile-fail/data_race/alloc_write_race.stderr b/tests/fail/data_race/alloc_write_race.stderr similarity index 100% rename from tests/compile-fail/data_race/alloc_write_race.stderr rename to tests/fail/data_race/alloc_write_race.stderr diff --git a/tests/compile-fail/data_race/atomic_read_na_write_race1.rs b/tests/fail/data_race/atomic_read_na_write_race1.rs similarity index 100% rename from tests/compile-fail/data_race/atomic_read_na_write_race1.rs rename to tests/fail/data_race/atomic_read_na_write_race1.rs diff --git a/tests/compile-fail/data_race/atomic_read_na_write_race1.stderr b/tests/fail/data_race/atomic_read_na_write_race1.stderr similarity index 100% rename from tests/compile-fail/data_race/atomic_read_na_write_race1.stderr rename to tests/fail/data_race/atomic_read_na_write_race1.stderr diff --git a/tests/compile-fail/data_race/atomic_read_na_write_race2.rs b/tests/fail/data_race/atomic_read_na_write_race2.rs similarity index 100% rename from tests/compile-fail/data_race/atomic_read_na_write_race2.rs rename to tests/fail/data_race/atomic_read_na_write_race2.rs diff --git a/tests/compile-fail/data_race/atomic_read_na_write_race2.stderr b/tests/fail/data_race/atomic_read_na_write_race2.stderr similarity index 100% rename from tests/compile-fail/data_race/atomic_read_na_write_race2.stderr rename to tests/fail/data_race/atomic_read_na_write_race2.stderr diff --git a/tests/compile-fail/data_race/atomic_write_na_read_race1.rs b/tests/fail/data_race/atomic_write_na_read_race1.rs similarity index 100% rename from tests/compile-fail/data_race/atomic_write_na_read_race1.rs rename to tests/fail/data_race/atomic_write_na_read_race1.rs diff --git a/tests/compile-fail/data_race/atomic_write_na_read_race1.stderr b/tests/fail/data_race/atomic_write_na_read_race1.stderr similarity index 100% rename from tests/compile-fail/data_race/atomic_write_na_read_race1.stderr rename to tests/fail/data_race/atomic_write_na_read_race1.stderr diff --git a/tests/compile-fail/data_race/atomic_write_na_read_race2.rs b/tests/fail/data_race/atomic_write_na_read_race2.rs similarity index 100% rename from tests/compile-fail/data_race/atomic_write_na_read_race2.rs rename to tests/fail/data_race/atomic_write_na_read_race2.rs diff --git a/tests/compile-fail/data_race/atomic_write_na_read_race2.stderr b/tests/fail/data_race/atomic_write_na_read_race2.stderr similarity index 100% rename from tests/compile-fail/data_race/atomic_write_na_read_race2.stderr rename to tests/fail/data_race/atomic_write_na_read_race2.stderr diff --git a/tests/compile-fail/data_race/atomic_write_na_write_race1.rs b/tests/fail/data_race/atomic_write_na_write_race1.rs similarity index 100% rename from tests/compile-fail/data_race/atomic_write_na_write_race1.rs rename to tests/fail/data_race/atomic_write_na_write_race1.rs diff --git a/tests/compile-fail/data_race/atomic_write_na_write_race1.stderr b/tests/fail/data_race/atomic_write_na_write_race1.stderr similarity index 100% rename from tests/compile-fail/data_race/atomic_write_na_write_race1.stderr rename to tests/fail/data_race/atomic_write_na_write_race1.stderr diff --git a/tests/compile-fail/data_race/atomic_write_na_write_race2.rs b/tests/fail/data_race/atomic_write_na_write_race2.rs similarity index 100% rename from tests/compile-fail/data_race/atomic_write_na_write_race2.rs rename to tests/fail/data_race/atomic_write_na_write_race2.rs diff --git a/tests/compile-fail/data_race/atomic_write_na_write_race2.stderr b/tests/fail/data_race/atomic_write_na_write_race2.stderr similarity index 100% rename from tests/compile-fail/data_race/atomic_write_na_write_race2.stderr rename to tests/fail/data_race/atomic_write_na_write_race2.stderr diff --git a/tests/compile-fail/data_race/dangling_thread_async_race.rs b/tests/fail/data_race/dangling_thread_async_race.rs similarity index 100% rename from tests/compile-fail/data_race/dangling_thread_async_race.rs rename to tests/fail/data_race/dangling_thread_async_race.rs diff --git a/tests/compile-fail/data_race/dangling_thread_async_race.stderr b/tests/fail/data_race/dangling_thread_async_race.stderr similarity index 100% rename from tests/compile-fail/data_race/dangling_thread_async_race.stderr rename to tests/fail/data_race/dangling_thread_async_race.stderr diff --git a/tests/compile-fail/data_race/dangling_thread_race.rs b/tests/fail/data_race/dangling_thread_race.rs similarity index 100% rename from tests/compile-fail/data_race/dangling_thread_race.rs rename to tests/fail/data_race/dangling_thread_race.rs diff --git a/tests/compile-fail/data_race/dangling_thread_race.stderr b/tests/fail/data_race/dangling_thread_race.stderr similarity index 100% rename from tests/compile-fail/data_race/dangling_thread_race.stderr rename to tests/fail/data_race/dangling_thread_race.stderr diff --git a/tests/compile-fail/data_race/dealloc_read_race1.rs b/tests/fail/data_race/dealloc_read_race1.rs similarity index 100% rename from tests/compile-fail/data_race/dealloc_read_race1.rs rename to tests/fail/data_race/dealloc_read_race1.rs diff --git a/tests/compile-fail/data_race/dealloc_read_race1.stderr b/tests/fail/data_race/dealloc_read_race1.stderr similarity index 100% rename from tests/compile-fail/data_race/dealloc_read_race1.stderr rename to tests/fail/data_race/dealloc_read_race1.stderr diff --git a/tests/compile-fail/data_race/dealloc_read_race2.rs b/tests/fail/data_race/dealloc_read_race2.rs similarity index 100% rename from tests/compile-fail/data_race/dealloc_read_race2.rs rename to tests/fail/data_race/dealloc_read_race2.rs diff --git a/tests/compile-fail/data_race/dealloc_read_race2.stderr b/tests/fail/data_race/dealloc_read_race2.stderr similarity index 100% rename from tests/compile-fail/data_race/dealloc_read_race2.stderr rename to tests/fail/data_race/dealloc_read_race2.stderr diff --git a/tests/compile-fail/data_race/dealloc_read_race_stack.rs b/tests/fail/data_race/dealloc_read_race_stack.rs similarity index 100% rename from tests/compile-fail/data_race/dealloc_read_race_stack.rs rename to tests/fail/data_race/dealloc_read_race_stack.rs diff --git a/tests/compile-fail/data_race/dealloc_read_race_stack.stderr b/tests/fail/data_race/dealloc_read_race_stack.stderr similarity index 100% rename from tests/compile-fail/data_race/dealloc_read_race_stack.stderr rename to tests/fail/data_race/dealloc_read_race_stack.stderr diff --git a/tests/compile-fail/data_race/dealloc_write_race1.rs b/tests/fail/data_race/dealloc_write_race1.rs similarity index 100% rename from tests/compile-fail/data_race/dealloc_write_race1.rs rename to tests/fail/data_race/dealloc_write_race1.rs diff --git a/tests/compile-fail/data_race/dealloc_write_race1.stderr b/tests/fail/data_race/dealloc_write_race1.stderr similarity index 100% rename from tests/compile-fail/data_race/dealloc_write_race1.stderr rename to tests/fail/data_race/dealloc_write_race1.stderr diff --git a/tests/compile-fail/data_race/dealloc_write_race2.rs b/tests/fail/data_race/dealloc_write_race2.rs similarity index 100% rename from tests/compile-fail/data_race/dealloc_write_race2.rs rename to tests/fail/data_race/dealloc_write_race2.rs diff --git a/tests/compile-fail/data_race/dealloc_write_race2.stderr b/tests/fail/data_race/dealloc_write_race2.stderr similarity index 100% rename from tests/compile-fail/data_race/dealloc_write_race2.stderr rename to tests/fail/data_race/dealloc_write_race2.stderr diff --git a/tests/compile-fail/data_race/dealloc_write_race_stack.rs b/tests/fail/data_race/dealloc_write_race_stack.rs similarity index 100% rename from tests/compile-fail/data_race/dealloc_write_race_stack.rs rename to tests/fail/data_race/dealloc_write_race_stack.rs diff --git a/tests/compile-fail/data_race/dealloc_write_race_stack.stderr b/tests/fail/data_race/dealloc_write_race_stack.stderr similarity index 100% rename from tests/compile-fail/data_race/dealloc_write_race_stack.stderr rename to tests/fail/data_race/dealloc_write_race_stack.stderr diff --git a/tests/compile-fail/data_race/enable_after_join_to_main.rs b/tests/fail/data_race/enable_after_join_to_main.rs similarity index 100% rename from tests/compile-fail/data_race/enable_after_join_to_main.rs rename to tests/fail/data_race/enable_after_join_to_main.rs diff --git a/tests/compile-fail/data_race/enable_after_join_to_main.stderr b/tests/fail/data_race/enable_after_join_to_main.stderr similarity index 100% rename from tests/compile-fail/data_race/enable_after_join_to_main.stderr rename to tests/fail/data_race/enable_after_join_to_main.stderr diff --git a/tests/compile-fail/data_race/read_write_race.rs b/tests/fail/data_race/read_write_race.rs similarity index 100% rename from tests/compile-fail/data_race/read_write_race.rs rename to tests/fail/data_race/read_write_race.rs diff --git a/tests/compile-fail/data_race/read_write_race.stderr b/tests/fail/data_race/read_write_race.stderr similarity index 100% rename from tests/compile-fail/data_race/read_write_race.stderr rename to tests/fail/data_race/read_write_race.stderr diff --git a/tests/compile-fail/data_race/read_write_race_stack.rs b/tests/fail/data_race/read_write_race_stack.rs similarity index 100% rename from tests/compile-fail/data_race/read_write_race_stack.rs rename to tests/fail/data_race/read_write_race_stack.rs diff --git a/tests/compile-fail/data_race/read_write_race_stack.stderr b/tests/fail/data_race/read_write_race_stack.stderr similarity index 100% rename from tests/compile-fail/data_race/read_write_race_stack.stderr rename to tests/fail/data_race/read_write_race_stack.stderr diff --git a/tests/compile-fail/data_race/relax_acquire_race.rs b/tests/fail/data_race/relax_acquire_race.rs similarity index 100% rename from tests/compile-fail/data_race/relax_acquire_race.rs rename to tests/fail/data_race/relax_acquire_race.rs diff --git a/tests/compile-fail/data_race/relax_acquire_race.stderr b/tests/fail/data_race/relax_acquire_race.stderr similarity index 100% rename from tests/compile-fail/data_race/relax_acquire_race.stderr rename to tests/fail/data_race/relax_acquire_race.stderr diff --git a/tests/compile-fail/data_race/release_seq_race.rs b/tests/fail/data_race/release_seq_race.rs similarity index 100% rename from tests/compile-fail/data_race/release_seq_race.rs rename to tests/fail/data_race/release_seq_race.rs diff --git a/tests/compile-fail/data_race/release_seq_race.stderr b/tests/fail/data_race/release_seq_race.stderr similarity index 100% rename from tests/compile-fail/data_race/release_seq_race.stderr rename to tests/fail/data_race/release_seq_race.stderr diff --git a/tests/compile-fail/data_race/release_seq_race_same_thread.rs b/tests/fail/data_race/release_seq_race_same_thread.rs similarity index 100% rename from tests/compile-fail/data_race/release_seq_race_same_thread.rs rename to tests/fail/data_race/release_seq_race_same_thread.rs diff --git a/tests/compile-fail/data_race/release_seq_race_same_thread.stderr b/tests/fail/data_race/release_seq_race_same_thread.stderr similarity index 100% rename from tests/compile-fail/data_race/release_seq_race_same_thread.stderr rename to tests/fail/data_race/release_seq_race_same_thread.stderr diff --git a/tests/compile-fail/data_race/rmw_race.rs b/tests/fail/data_race/rmw_race.rs similarity index 100% rename from tests/compile-fail/data_race/rmw_race.rs rename to tests/fail/data_race/rmw_race.rs diff --git a/tests/compile-fail/data_race/rmw_race.stderr b/tests/fail/data_race/rmw_race.stderr similarity index 100% rename from tests/compile-fail/data_race/rmw_race.stderr rename to tests/fail/data_race/rmw_race.stderr diff --git a/tests/compile-fail/data_race/write_write_race.rs b/tests/fail/data_race/write_write_race.rs similarity index 100% rename from tests/compile-fail/data_race/write_write_race.rs rename to tests/fail/data_race/write_write_race.rs diff --git a/tests/compile-fail/data_race/write_write_race.stderr b/tests/fail/data_race/write_write_race.stderr similarity index 100% rename from tests/compile-fail/data_race/write_write_race.stderr rename to tests/fail/data_race/write_write_race.stderr diff --git a/tests/compile-fail/data_race/write_write_race_stack.rs b/tests/fail/data_race/write_write_race_stack.rs similarity index 100% rename from tests/compile-fail/data_race/write_write_race_stack.rs rename to tests/fail/data_race/write_write_race_stack.rs diff --git a/tests/compile-fail/data_race/write_write_race_stack.stderr b/tests/fail/data_race/write_write_race_stack.stderr similarity index 100% rename from tests/compile-fail/data_race/write_write_race_stack.stderr rename to tests/fail/data_race/write_write_race_stack.stderr diff --git a/tests/compile-fail/environ-gets-deallocated.rs b/tests/fail/environ-gets-deallocated.rs similarity index 100% rename from tests/compile-fail/environ-gets-deallocated.rs rename to tests/fail/environ-gets-deallocated.rs diff --git a/tests/compile-fail/environ-gets-deallocated.stderr b/tests/fail/environ-gets-deallocated.stderr similarity index 100% rename from tests/compile-fail/environ-gets-deallocated.stderr rename to tests/fail/environ-gets-deallocated.stderr diff --git a/tests/compile-fail/erroneous_const.rs b/tests/fail/erroneous_const.rs similarity index 100% rename from tests/compile-fail/erroneous_const.rs rename to tests/fail/erroneous_const.rs diff --git a/tests/compile-fail/erroneous_const.stderr b/tests/fail/erroneous_const.stderr similarity index 100% rename from tests/compile-fail/erroneous_const.stderr rename to tests/fail/erroneous_const.stderr diff --git a/tests/compile-fail/erroneous_const2.rs b/tests/fail/erroneous_const2.rs similarity index 100% rename from tests/compile-fail/erroneous_const2.rs rename to tests/fail/erroneous_const2.rs diff --git a/tests/compile-fail/erroneous_const2.stderr b/tests/fail/erroneous_const2.stderr similarity index 100% rename from tests/compile-fail/erroneous_const2.stderr rename to tests/fail/erroneous_const2.stderr diff --git a/tests/compile-fail/extern_static.rs b/tests/fail/extern_static.rs similarity index 100% rename from tests/compile-fail/extern_static.rs rename to tests/fail/extern_static.rs diff --git a/tests/compile-fail/extern_static.stderr b/tests/fail/extern_static.stderr similarity index 100% rename from tests/compile-fail/extern_static.stderr rename to tests/fail/extern_static.stderr diff --git a/tests/compile-fail/fast_math_both.rs b/tests/fail/fast_math_both.rs similarity index 100% rename from tests/compile-fail/fast_math_both.rs rename to tests/fail/fast_math_both.rs diff --git a/tests/compile-fail/fast_math_both.stderr b/tests/fail/fast_math_both.stderr similarity index 100% rename from tests/compile-fail/fast_math_both.stderr rename to tests/fail/fast_math_both.stderr diff --git a/tests/compile-fail/fast_math_first.rs b/tests/fail/fast_math_first.rs similarity index 100% rename from tests/compile-fail/fast_math_first.rs rename to tests/fail/fast_math_first.rs diff --git a/tests/compile-fail/fast_math_first.stderr b/tests/fail/fast_math_first.stderr similarity index 100% rename from tests/compile-fail/fast_math_first.stderr rename to tests/fail/fast_math_first.stderr diff --git a/tests/compile-fail/fast_math_second.rs b/tests/fail/fast_math_second.rs similarity index 100% rename from tests/compile-fail/fast_math_second.rs rename to tests/fail/fast_math_second.rs diff --git a/tests/compile-fail/fast_math_second.stderr b/tests/fail/fast_math_second.stderr similarity index 100% rename from tests/compile-fail/fast_math_second.stderr rename to tests/fail/fast_math_second.stderr diff --git a/tests/compile-fail/fs/close_stdout.rs b/tests/fail/fs/close_stdout.rs similarity index 100% rename from tests/compile-fail/fs/close_stdout.rs rename to tests/fail/fs/close_stdout.rs diff --git a/tests/compile-fail/fs/close_stdout.stderr b/tests/fail/fs/close_stdout.stderr similarity index 100% rename from tests/compile-fail/fs/close_stdout.stderr rename to tests/fail/fs/close_stdout.stderr diff --git a/tests/compile-fail/fs/isolated_file.rs b/tests/fail/fs/isolated_file.rs similarity index 100% rename from tests/compile-fail/fs/isolated_file.rs rename to tests/fail/fs/isolated_file.rs diff --git a/tests/compile-fail/fs/isolated_file.stderr b/tests/fail/fs/isolated_file.stderr similarity index 100% rename from tests/compile-fail/fs/isolated_file.stderr rename to tests/fail/fs/isolated_file.stderr diff --git a/tests/compile-fail/fs/isolated_stdin.rs b/tests/fail/fs/isolated_stdin.rs similarity index 100% rename from tests/compile-fail/fs/isolated_stdin.rs rename to tests/fail/fs/isolated_stdin.rs diff --git a/tests/compile-fail/fs/isolated_stdin.stderr b/tests/fail/fs/isolated_stdin.stderr similarity index 100% rename from tests/compile-fail/fs/isolated_stdin.stderr rename to tests/fail/fs/isolated_stdin.stderr diff --git a/tests/compile-fail/fs/read_from_stdout.rs b/tests/fail/fs/read_from_stdout.rs similarity index 100% rename from tests/compile-fail/fs/read_from_stdout.rs rename to tests/fail/fs/read_from_stdout.rs diff --git a/tests/compile-fail/fs/read_from_stdout.stderr b/tests/fail/fs/read_from_stdout.stderr similarity index 100% rename from tests/compile-fail/fs/read_from_stdout.stderr rename to tests/fail/fs/read_from_stdout.stderr diff --git a/tests/compile-fail/fs/unix_open_missing_required_mode.rs b/tests/fail/fs/unix_open_missing_required_mode.rs similarity index 100% rename from tests/compile-fail/fs/unix_open_missing_required_mode.rs rename to tests/fail/fs/unix_open_missing_required_mode.rs diff --git a/tests/compile-fail/fs/unix_open_missing_required_mode.stderr b/tests/fail/fs/unix_open_missing_required_mode.stderr similarity index 100% rename from tests/compile-fail/fs/unix_open_missing_required_mode.stderr rename to tests/fail/fs/unix_open_missing_required_mode.stderr diff --git a/tests/compile-fail/fs/unix_open_too_many_args.stderr b/tests/fail/fs/unix_open_too_many_args.stderr similarity index 100% rename from tests/compile-fail/fs/unix_open_too_many_args.stderr rename to tests/fail/fs/unix_open_too_many_args.stderr diff --git a/tests/compile-fail/fs/write_to_stdin.rs b/tests/fail/fs/write_to_stdin.rs similarity index 100% rename from tests/compile-fail/fs/write_to_stdin.rs rename to tests/fail/fs/write_to_stdin.rs diff --git a/tests/compile-fail/fs/write_to_stdin.stderr b/tests/fail/fs/write_to_stdin.stderr similarity index 100% rename from tests/compile-fail/fs/write_to_stdin.stderr rename to tests/fail/fs/write_to_stdin.stderr diff --git a/tests/compile-fail/function_calls/check_arg_abi.rs b/tests/fail/function_calls/check_arg_abi.rs similarity index 100% rename from tests/compile-fail/function_calls/check_arg_abi.rs rename to tests/fail/function_calls/check_arg_abi.rs diff --git a/tests/compile-fail/function_calls/check_arg_abi.stderr b/tests/fail/function_calls/check_arg_abi.stderr similarity index 100% rename from tests/compile-fail/function_calls/check_arg_abi.stderr rename to tests/fail/function_calls/check_arg_abi.stderr diff --git a/tests/compile-fail/function_calls/check_arg_count_abort.rs b/tests/fail/function_calls/check_arg_count_abort.rs similarity index 100% rename from tests/compile-fail/function_calls/check_arg_count_abort.rs rename to tests/fail/function_calls/check_arg_count_abort.rs diff --git a/tests/compile-fail/function_calls/check_arg_count_abort.stderr b/tests/fail/function_calls/check_arg_count_abort.stderr similarity index 100% rename from tests/compile-fail/function_calls/check_arg_count_abort.stderr rename to tests/fail/function_calls/check_arg_count_abort.stderr diff --git a/tests/compile-fail/function_calls/check_arg_count_too_few_args.rs b/tests/fail/function_calls/check_arg_count_too_few_args.rs similarity index 100% rename from tests/compile-fail/function_calls/check_arg_count_too_few_args.rs rename to tests/fail/function_calls/check_arg_count_too_few_args.rs diff --git a/tests/compile-fail/function_calls/check_arg_count_too_few_args.stderr b/tests/fail/function_calls/check_arg_count_too_few_args.stderr similarity index 100% rename from tests/compile-fail/function_calls/check_arg_count_too_few_args.stderr rename to tests/fail/function_calls/check_arg_count_too_few_args.stderr diff --git a/tests/compile-fail/function_calls/check_arg_count_too_many_args.rs b/tests/fail/function_calls/check_arg_count_too_many_args.rs similarity index 100% rename from tests/compile-fail/function_calls/check_arg_count_too_many_args.rs rename to tests/fail/function_calls/check_arg_count_too_many_args.rs diff --git a/tests/compile-fail/function_calls/check_arg_count_too_many_args.stderr b/tests/fail/function_calls/check_arg_count_too_many_args.stderr similarity index 100% rename from tests/compile-fail/function_calls/check_arg_count_too_many_args.stderr rename to tests/fail/function_calls/check_arg_count_too_many_args.stderr diff --git a/tests/compile-fail/function_calls/check_callback_abi.rs b/tests/fail/function_calls/check_callback_abi.rs similarity index 100% rename from tests/compile-fail/function_calls/check_callback_abi.rs rename to tests/fail/function_calls/check_callback_abi.rs diff --git a/tests/compile-fail/function_calls/check_callback_abi.stderr b/tests/fail/function_calls/check_callback_abi.stderr similarity index 100% rename from tests/compile-fail/function_calls/check_callback_abi.stderr rename to tests/fail/function_calls/check_callback_abi.stderr diff --git a/tests/compile-fail/function_calls/exported_symbol_abi_mismatch.cache.stderr b/tests/fail/function_calls/exported_symbol_abi_mismatch.cache.stderr similarity index 100% rename from tests/compile-fail/function_calls/exported_symbol_abi_mismatch.cache.stderr rename to tests/fail/function_calls/exported_symbol_abi_mismatch.cache.stderr diff --git a/tests/compile-fail/function_calls/exported_symbol_abi_mismatch.fn_ptr.stderr b/tests/fail/function_calls/exported_symbol_abi_mismatch.fn_ptr.stderr similarity index 100% rename from tests/compile-fail/function_calls/exported_symbol_abi_mismatch.fn_ptr.stderr rename to tests/fail/function_calls/exported_symbol_abi_mismatch.fn_ptr.stderr diff --git a/tests/compile-fail/function_calls/exported_symbol_abi_mismatch.no_cache.stderr b/tests/fail/function_calls/exported_symbol_abi_mismatch.no_cache.stderr similarity index 100% rename from tests/compile-fail/function_calls/exported_symbol_abi_mismatch.no_cache.stderr rename to tests/fail/function_calls/exported_symbol_abi_mismatch.no_cache.stderr diff --git a/tests/compile-fail/function_calls/exported_symbol_abi_mismatch.rs b/tests/fail/function_calls/exported_symbol_abi_mismatch.rs similarity index 100% rename from tests/compile-fail/function_calls/exported_symbol_abi_mismatch.rs rename to tests/fail/function_calls/exported_symbol_abi_mismatch.rs diff --git a/tests/compile-fail/function_calls/exported_symbol_bad_unwind1.rs b/tests/fail/function_calls/exported_symbol_bad_unwind1.rs similarity index 100% rename from tests/compile-fail/function_calls/exported_symbol_bad_unwind1.rs rename to tests/fail/function_calls/exported_symbol_bad_unwind1.rs diff --git a/tests/compile-fail/function_calls/exported_symbol_bad_unwind1.stderr b/tests/fail/function_calls/exported_symbol_bad_unwind1.stderr similarity index 100% rename from tests/compile-fail/function_calls/exported_symbol_bad_unwind1.stderr rename to tests/fail/function_calls/exported_symbol_bad_unwind1.stderr diff --git a/tests/compile-fail/function_calls/exported_symbol_bad_unwind2.both.stderr b/tests/fail/function_calls/exported_symbol_bad_unwind2.both.stderr similarity index 100% rename from tests/compile-fail/function_calls/exported_symbol_bad_unwind2.both.stderr rename to tests/fail/function_calls/exported_symbol_bad_unwind2.both.stderr diff --git a/tests/compile-fail/function_calls/exported_symbol_bad_unwind2.definition.stderr b/tests/fail/function_calls/exported_symbol_bad_unwind2.definition.stderr similarity index 100% rename from tests/compile-fail/function_calls/exported_symbol_bad_unwind2.definition.stderr rename to tests/fail/function_calls/exported_symbol_bad_unwind2.definition.stderr diff --git a/tests/compile-fail/function_calls/exported_symbol_bad_unwind2.extern_block.stderr b/tests/fail/function_calls/exported_symbol_bad_unwind2.extern_block.stderr similarity index 100% rename from tests/compile-fail/function_calls/exported_symbol_bad_unwind2.extern_block.stderr rename to tests/fail/function_calls/exported_symbol_bad_unwind2.extern_block.stderr diff --git a/tests/compile-fail/function_calls/exported_symbol_bad_unwind2.rs b/tests/fail/function_calls/exported_symbol_bad_unwind2.rs similarity index 100% rename from tests/compile-fail/function_calls/exported_symbol_bad_unwind2.rs rename to tests/fail/function_calls/exported_symbol_bad_unwind2.rs diff --git a/tests/compile-fail/function_calls/exported_symbol_clashing.rs b/tests/fail/function_calls/exported_symbol_clashing.rs similarity index 100% rename from tests/compile-fail/function_calls/exported_symbol_clashing.rs rename to tests/fail/function_calls/exported_symbol_clashing.rs diff --git a/tests/compile-fail/function_calls/exported_symbol_clashing.stderr b/tests/fail/function_calls/exported_symbol_clashing.stderr similarity index 100% rename from tests/compile-fail/function_calls/exported_symbol_clashing.stderr rename to tests/fail/function_calls/exported_symbol_clashing.stderr diff --git a/tests/compile-fail/function_calls/exported_symbol_shim_clashing.rs b/tests/fail/function_calls/exported_symbol_shim_clashing.rs similarity index 100% rename from tests/compile-fail/function_calls/exported_symbol_shim_clashing.rs rename to tests/fail/function_calls/exported_symbol_shim_clashing.rs diff --git a/tests/compile-fail/function_calls/exported_symbol_shim_clashing.stderr b/tests/fail/function_calls/exported_symbol_shim_clashing.stderr similarity index 100% rename from tests/compile-fail/function_calls/exported_symbol_shim_clashing.stderr rename to tests/fail/function_calls/exported_symbol_shim_clashing.stderr diff --git a/tests/compile-fail/function_calls/exported_symbol_wrong_arguments.rs b/tests/fail/function_calls/exported_symbol_wrong_arguments.rs similarity index 100% rename from tests/compile-fail/function_calls/exported_symbol_wrong_arguments.rs rename to tests/fail/function_calls/exported_symbol_wrong_arguments.rs diff --git a/tests/compile-fail/function_calls/exported_symbol_wrong_arguments.stderr b/tests/fail/function_calls/exported_symbol_wrong_arguments.stderr similarity index 100% rename from tests/compile-fail/function_calls/exported_symbol_wrong_arguments.stderr rename to tests/fail/function_calls/exported_symbol_wrong_arguments.stderr diff --git a/tests/compile-fail/function_calls/exported_symbol_wrong_type.rs b/tests/fail/function_calls/exported_symbol_wrong_type.rs similarity index 100% rename from tests/compile-fail/function_calls/exported_symbol_wrong_type.rs rename to tests/fail/function_calls/exported_symbol_wrong_type.rs diff --git a/tests/compile-fail/function_calls/exported_symbol_wrong_type.stderr b/tests/fail/function_calls/exported_symbol_wrong_type.stderr similarity index 100% rename from tests/compile-fail/function_calls/exported_symbol_wrong_type.stderr rename to tests/fail/function_calls/exported_symbol_wrong_type.stderr diff --git a/tests/compile-fail/function_pointers/cast_box_int_to_fn_ptr.rs b/tests/fail/function_pointers/cast_box_int_to_fn_ptr.rs similarity index 100% rename from tests/compile-fail/function_pointers/cast_box_int_to_fn_ptr.rs rename to tests/fail/function_pointers/cast_box_int_to_fn_ptr.rs diff --git a/tests/compile-fail/function_pointers/cast_box_int_to_fn_ptr.stderr b/tests/fail/function_pointers/cast_box_int_to_fn_ptr.stderr similarity index 100% rename from tests/compile-fail/function_pointers/cast_box_int_to_fn_ptr.stderr rename to tests/fail/function_pointers/cast_box_int_to_fn_ptr.stderr diff --git a/tests/compile-fail/function_pointers/cast_fn_ptr1.rs b/tests/fail/function_pointers/cast_fn_ptr1.rs similarity index 100% rename from tests/compile-fail/function_pointers/cast_fn_ptr1.rs rename to tests/fail/function_pointers/cast_fn_ptr1.rs diff --git a/tests/compile-fail/function_pointers/cast_fn_ptr1.stderr b/tests/fail/function_pointers/cast_fn_ptr1.stderr similarity index 100% rename from tests/compile-fail/function_pointers/cast_fn_ptr1.stderr rename to tests/fail/function_pointers/cast_fn_ptr1.stderr diff --git a/tests/compile-fail/function_pointers/cast_fn_ptr2.rs b/tests/fail/function_pointers/cast_fn_ptr2.rs similarity index 100% rename from tests/compile-fail/function_pointers/cast_fn_ptr2.rs rename to tests/fail/function_pointers/cast_fn_ptr2.rs diff --git a/tests/compile-fail/function_pointers/cast_fn_ptr2.stderr b/tests/fail/function_pointers/cast_fn_ptr2.stderr similarity index 100% rename from tests/compile-fail/function_pointers/cast_fn_ptr2.stderr rename to tests/fail/function_pointers/cast_fn_ptr2.stderr diff --git a/tests/compile-fail/function_pointers/cast_fn_ptr3.rs b/tests/fail/function_pointers/cast_fn_ptr3.rs similarity index 100% rename from tests/compile-fail/function_pointers/cast_fn_ptr3.rs rename to tests/fail/function_pointers/cast_fn_ptr3.rs diff --git a/tests/compile-fail/function_pointers/cast_fn_ptr3.stderr b/tests/fail/function_pointers/cast_fn_ptr3.stderr similarity index 100% rename from tests/compile-fail/function_pointers/cast_fn_ptr3.stderr rename to tests/fail/function_pointers/cast_fn_ptr3.stderr diff --git a/tests/compile-fail/function_pointers/cast_fn_ptr4.rs b/tests/fail/function_pointers/cast_fn_ptr4.rs similarity index 100% rename from tests/compile-fail/function_pointers/cast_fn_ptr4.rs rename to tests/fail/function_pointers/cast_fn_ptr4.rs diff --git a/tests/compile-fail/function_pointers/cast_fn_ptr4.stderr b/tests/fail/function_pointers/cast_fn_ptr4.stderr similarity index 100% rename from tests/compile-fail/function_pointers/cast_fn_ptr4.stderr rename to tests/fail/function_pointers/cast_fn_ptr4.stderr diff --git a/tests/compile-fail/function_pointers/cast_fn_ptr5.rs b/tests/fail/function_pointers/cast_fn_ptr5.rs similarity index 100% rename from tests/compile-fail/function_pointers/cast_fn_ptr5.rs rename to tests/fail/function_pointers/cast_fn_ptr5.rs diff --git a/tests/compile-fail/function_pointers/cast_fn_ptr5.stderr b/tests/fail/function_pointers/cast_fn_ptr5.stderr similarity index 100% rename from tests/compile-fail/function_pointers/cast_fn_ptr5.stderr rename to tests/fail/function_pointers/cast_fn_ptr5.stderr diff --git a/tests/compile-fail/function_pointers/cast_int_to_fn_ptr.rs b/tests/fail/function_pointers/cast_int_to_fn_ptr.rs similarity index 100% rename from tests/compile-fail/function_pointers/cast_int_to_fn_ptr.rs rename to tests/fail/function_pointers/cast_int_to_fn_ptr.rs diff --git a/tests/compile-fail/function_pointers/cast_int_to_fn_ptr.stderr b/tests/fail/function_pointers/cast_int_to_fn_ptr.stderr similarity index 100% rename from tests/compile-fail/function_pointers/cast_int_to_fn_ptr.stderr rename to tests/fail/function_pointers/cast_int_to_fn_ptr.stderr diff --git a/tests/compile-fail/function_pointers/deref_fn_ptr.rs b/tests/fail/function_pointers/deref_fn_ptr.rs similarity index 100% rename from tests/compile-fail/function_pointers/deref_fn_ptr.rs rename to tests/fail/function_pointers/deref_fn_ptr.rs diff --git a/tests/compile-fail/function_pointers/deref_fn_ptr.stderr b/tests/fail/function_pointers/deref_fn_ptr.stderr similarity index 100% rename from tests/compile-fail/function_pointers/deref_fn_ptr.stderr rename to tests/fail/function_pointers/deref_fn_ptr.stderr diff --git a/tests/compile-fail/function_pointers/execute_memory.rs b/tests/fail/function_pointers/execute_memory.rs similarity index 100% rename from tests/compile-fail/function_pointers/execute_memory.rs rename to tests/fail/function_pointers/execute_memory.rs diff --git a/tests/compile-fail/function_pointers/execute_memory.stderr b/tests/fail/function_pointers/execute_memory.stderr similarity index 100% rename from tests/compile-fail/function_pointers/execute_memory.stderr rename to tests/fail/function_pointers/execute_memory.stderr diff --git a/tests/compile-fail/function_pointers/fn_ptr_offset.rs b/tests/fail/function_pointers/fn_ptr_offset.rs similarity index 100% rename from tests/compile-fail/function_pointers/fn_ptr_offset.rs rename to tests/fail/function_pointers/fn_ptr_offset.rs diff --git a/tests/compile-fail/function_pointers/fn_ptr_offset.stderr b/tests/fail/function_pointers/fn_ptr_offset.stderr similarity index 100% rename from tests/compile-fail/function_pointers/fn_ptr_offset.stderr rename to tests/fail/function_pointers/fn_ptr_offset.stderr diff --git a/tests/compile-fail/generator-pinned-moved.rs b/tests/fail/generator-pinned-moved.rs similarity index 100% rename from tests/compile-fail/generator-pinned-moved.rs rename to tests/fail/generator-pinned-moved.rs diff --git a/tests/compile-fail/generator-pinned-moved.stderr b/tests/fail/generator-pinned-moved.stderr similarity index 100% rename from tests/compile-fail/generator-pinned-moved.stderr rename to tests/fail/generator-pinned-moved.stderr diff --git a/tests/compile-fail/intrinsics/assume.rs b/tests/fail/intrinsics/assume.rs similarity index 100% rename from tests/compile-fail/intrinsics/assume.rs rename to tests/fail/intrinsics/assume.rs diff --git a/tests/compile-fail/intrinsics/assume.stderr b/tests/fail/intrinsics/assume.stderr similarity index 100% rename from tests/compile-fail/intrinsics/assume.stderr rename to tests/fail/intrinsics/assume.stderr diff --git a/tests/compile-fail/intrinsics/copy_null.rs b/tests/fail/intrinsics/copy_null.rs similarity index 100% rename from tests/compile-fail/intrinsics/copy_null.rs rename to tests/fail/intrinsics/copy_null.rs diff --git a/tests/compile-fail/intrinsics/copy_null.stderr b/tests/fail/intrinsics/copy_null.stderr similarity index 100% rename from tests/compile-fail/intrinsics/copy_null.stderr rename to tests/fail/intrinsics/copy_null.stderr diff --git a/tests/compile-fail/intrinsics/copy_overflow.rs b/tests/fail/intrinsics/copy_overflow.rs similarity index 100% rename from tests/compile-fail/intrinsics/copy_overflow.rs rename to tests/fail/intrinsics/copy_overflow.rs diff --git a/tests/compile-fail/intrinsics/copy_overflow.stderr b/tests/fail/intrinsics/copy_overflow.stderr similarity index 100% rename from tests/compile-fail/intrinsics/copy_overflow.stderr rename to tests/fail/intrinsics/copy_overflow.stderr diff --git a/tests/compile-fail/intrinsics/copy_overlapping.rs b/tests/fail/intrinsics/copy_overlapping.rs similarity index 100% rename from tests/compile-fail/intrinsics/copy_overlapping.rs rename to tests/fail/intrinsics/copy_overlapping.rs diff --git a/tests/compile-fail/intrinsics/copy_overlapping.stderr b/tests/fail/intrinsics/copy_overlapping.stderr similarity index 100% rename from tests/compile-fail/intrinsics/copy_overlapping.stderr rename to tests/fail/intrinsics/copy_overlapping.stderr diff --git a/tests/compile-fail/intrinsics/copy_unaligned.rs b/tests/fail/intrinsics/copy_unaligned.rs similarity index 100% rename from tests/compile-fail/intrinsics/copy_unaligned.rs rename to tests/fail/intrinsics/copy_unaligned.rs diff --git a/tests/compile-fail/intrinsics/copy_unaligned.stderr b/tests/fail/intrinsics/copy_unaligned.stderr similarity index 100% rename from tests/compile-fail/intrinsics/copy_unaligned.stderr rename to tests/fail/intrinsics/copy_unaligned.stderr diff --git a/tests/compile-fail/intrinsics/ctlz_nonzero.rs b/tests/fail/intrinsics/ctlz_nonzero.rs similarity index 100% rename from tests/compile-fail/intrinsics/ctlz_nonzero.rs rename to tests/fail/intrinsics/ctlz_nonzero.rs diff --git a/tests/compile-fail/intrinsics/ctlz_nonzero.stderr b/tests/fail/intrinsics/ctlz_nonzero.stderr similarity index 100% rename from tests/compile-fail/intrinsics/ctlz_nonzero.stderr rename to tests/fail/intrinsics/ctlz_nonzero.stderr diff --git a/tests/compile-fail/intrinsics/cttz_nonzero.rs b/tests/fail/intrinsics/cttz_nonzero.rs similarity index 100% rename from tests/compile-fail/intrinsics/cttz_nonzero.rs rename to tests/fail/intrinsics/cttz_nonzero.rs diff --git a/tests/compile-fail/intrinsics/cttz_nonzero.stderr b/tests/fail/intrinsics/cttz_nonzero.stderr similarity index 100% rename from tests/compile-fail/intrinsics/cttz_nonzero.stderr rename to tests/fail/intrinsics/cttz_nonzero.stderr diff --git a/tests/compile-fail/intrinsics/div-by-zero.rs b/tests/fail/intrinsics/div-by-zero.rs similarity index 100% rename from tests/compile-fail/intrinsics/div-by-zero.rs rename to tests/fail/intrinsics/div-by-zero.rs diff --git a/tests/compile-fail/intrinsics/div-by-zero.stderr b/tests/fail/intrinsics/div-by-zero.stderr similarity index 100% rename from tests/compile-fail/intrinsics/div-by-zero.stderr rename to tests/fail/intrinsics/div-by-zero.stderr diff --git a/tests/compile-fail/intrinsics/exact_div1.rs b/tests/fail/intrinsics/exact_div1.rs similarity index 100% rename from tests/compile-fail/intrinsics/exact_div1.rs rename to tests/fail/intrinsics/exact_div1.rs diff --git a/tests/compile-fail/intrinsics/exact_div1.stderr b/tests/fail/intrinsics/exact_div1.stderr similarity index 100% rename from tests/compile-fail/intrinsics/exact_div1.stderr rename to tests/fail/intrinsics/exact_div1.stderr diff --git a/tests/compile-fail/intrinsics/exact_div2.rs b/tests/fail/intrinsics/exact_div2.rs similarity index 100% rename from tests/compile-fail/intrinsics/exact_div2.rs rename to tests/fail/intrinsics/exact_div2.rs diff --git a/tests/compile-fail/intrinsics/exact_div2.stderr b/tests/fail/intrinsics/exact_div2.stderr similarity index 100% rename from tests/compile-fail/intrinsics/exact_div2.stderr rename to tests/fail/intrinsics/exact_div2.stderr diff --git a/tests/compile-fail/intrinsics/exact_div3.rs b/tests/fail/intrinsics/exact_div3.rs similarity index 100% rename from tests/compile-fail/intrinsics/exact_div3.rs rename to tests/fail/intrinsics/exact_div3.rs diff --git a/tests/compile-fail/intrinsics/exact_div3.stderr b/tests/fail/intrinsics/exact_div3.stderr similarity index 100% rename from tests/compile-fail/intrinsics/exact_div3.stderr rename to tests/fail/intrinsics/exact_div3.stderr diff --git a/tests/compile-fail/intrinsics/exact_div4.rs b/tests/fail/intrinsics/exact_div4.rs similarity index 100% rename from tests/compile-fail/intrinsics/exact_div4.rs rename to tests/fail/intrinsics/exact_div4.rs diff --git a/tests/compile-fail/intrinsics/exact_div4.stderr b/tests/fail/intrinsics/exact_div4.stderr similarity index 100% rename from tests/compile-fail/intrinsics/exact_div4.stderr rename to tests/fail/intrinsics/exact_div4.stderr diff --git a/tests/compile-fail/intrinsics/float_to_int_32_inf1.rs b/tests/fail/intrinsics/float_to_int_32_inf1.rs similarity index 100% rename from tests/compile-fail/intrinsics/float_to_int_32_inf1.rs rename to tests/fail/intrinsics/float_to_int_32_inf1.rs diff --git a/tests/compile-fail/intrinsics/float_to_int_32_inf1.stderr b/tests/fail/intrinsics/float_to_int_32_inf1.stderr similarity index 100% rename from tests/compile-fail/intrinsics/float_to_int_32_inf1.stderr rename to tests/fail/intrinsics/float_to_int_32_inf1.stderr diff --git a/tests/compile-fail/intrinsics/float_to_int_32_infneg1.rs b/tests/fail/intrinsics/float_to_int_32_infneg1.rs similarity index 100% rename from tests/compile-fail/intrinsics/float_to_int_32_infneg1.rs rename to tests/fail/intrinsics/float_to_int_32_infneg1.rs diff --git a/tests/compile-fail/intrinsics/float_to_int_32_infneg1.stderr b/tests/fail/intrinsics/float_to_int_32_infneg1.stderr similarity index 100% rename from tests/compile-fail/intrinsics/float_to_int_32_infneg1.stderr rename to tests/fail/intrinsics/float_to_int_32_infneg1.stderr diff --git a/tests/compile-fail/intrinsics/float_to_int_32_nan.rs b/tests/fail/intrinsics/float_to_int_32_nan.rs similarity index 100% rename from tests/compile-fail/intrinsics/float_to_int_32_nan.rs rename to tests/fail/intrinsics/float_to_int_32_nan.rs diff --git a/tests/compile-fail/intrinsics/float_to_int_32_nan.stderr b/tests/fail/intrinsics/float_to_int_32_nan.stderr similarity index 100% rename from tests/compile-fail/intrinsics/float_to_int_32_nan.stderr rename to tests/fail/intrinsics/float_to_int_32_nan.stderr diff --git a/tests/compile-fail/intrinsics/float_to_int_32_nanneg.rs b/tests/fail/intrinsics/float_to_int_32_nanneg.rs similarity index 100% rename from tests/compile-fail/intrinsics/float_to_int_32_nanneg.rs rename to tests/fail/intrinsics/float_to_int_32_nanneg.rs diff --git a/tests/compile-fail/intrinsics/float_to_int_32_nanneg.stderr b/tests/fail/intrinsics/float_to_int_32_nanneg.stderr similarity index 100% rename from tests/compile-fail/intrinsics/float_to_int_32_nanneg.stderr rename to tests/fail/intrinsics/float_to_int_32_nanneg.stderr diff --git a/tests/compile-fail/intrinsics/float_to_int_32_neg.rs b/tests/fail/intrinsics/float_to_int_32_neg.rs similarity index 100% rename from tests/compile-fail/intrinsics/float_to_int_32_neg.rs rename to tests/fail/intrinsics/float_to_int_32_neg.rs diff --git a/tests/compile-fail/intrinsics/float_to_int_32_neg.stderr b/tests/fail/intrinsics/float_to_int_32_neg.stderr similarity index 100% rename from tests/compile-fail/intrinsics/float_to_int_32_neg.stderr rename to tests/fail/intrinsics/float_to_int_32_neg.stderr diff --git a/tests/compile-fail/intrinsics/float_to_int_32_too_big1.rs b/tests/fail/intrinsics/float_to_int_32_too_big1.rs similarity index 100% rename from tests/compile-fail/intrinsics/float_to_int_32_too_big1.rs rename to tests/fail/intrinsics/float_to_int_32_too_big1.rs diff --git a/tests/compile-fail/intrinsics/float_to_int_32_too_big1.stderr b/tests/fail/intrinsics/float_to_int_32_too_big1.stderr similarity index 100% rename from tests/compile-fail/intrinsics/float_to_int_32_too_big1.stderr rename to tests/fail/intrinsics/float_to_int_32_too_big1.stderr diff --git a/tests/compile-fail/intrinsics/float_to_int_32_too_big2.rs b/tests/fail/intrinsics/float_to_int_32_too_big2.rs similarity index 100% rename from tests/compile-fail/intrinsics/float_to_int_32_too_big2.rs rename to tests/fail/intrinsics/float_to_int_32_too_big2.rs diff --git a/tests/compile-fail/intrinsics/float_to_int_32_too_big2.stderr b/tests/fail/intrinsics/float_to_int_32_too_big2.stderr similarity index 100% rename from tests/compile-fail/intrinsics/float_to_int_32_too_big2.stderr rename to tests/fail/intrinsics/float_to_int_32_too_big2.stderr diff --git a/tests/compile-fail/intrinsics/float_to_int_32_too_small1.rs b/tests/fail/intrinsics/float_to_int_32_too_small1.rs similarity index 100% rename from tests/compile-fail/intrinsics/float_to_int_32_too_small1.rs rename to tests/fail/intrinsics/float_to_int_32_too_small1.rs diff --git a/tests/compile-fail/intrinsics/float_to_int_32_too_small1.stderr b/tests/fail/intrinsics/float_to_int_32_too_small1.stderr similarity index 100% rename from tests/compile-fail/intrinsics/float_to_int_32_too_small1.stderr rename to tests/fail/intrinsics/float_to_int_32_too_small1.stderr diff --git a/tests/compile-fail/intrinsics/float_to_int_64_inf1.rs b/tests/fail/intrinsics/float_to_int_64_inf1.rs similarity index 100% rename from tests/compile-fail/intrinsics/float_to_int_64_inf1.rs rename to tests/fail/intrinsics/float_to_int_64_inf1.rs diff --git a/tests/compile-fail/intrinsics/float_to_int_64_inf1.stderr b/tests/fail/intrinsics/float_to_int_64_inf1.stderr similarity index 100% rename from tests/compile-fail/intrinsics/float_to_int_64_inf1.stderr rename to tests/fail/intrinsics/float_to_int_64_inf1.stderr diff --git a/tests/compile-fail/intrinsics/float_to_int_64_infneg1.rs b/tests/fail/intrinsics/float_to_int_64_infneg1.rs similarity index 100% rename from tests/compile-fail/intrinsics/float_to_int_64_infneg1.rs rename to tests/fail/intrinsics/float_to_int_64_infneg1.rs diff --git a/tests/compile-fail/intrinsics/float_to_int_64_infneg1.stderr b/tests/fail/intrinsics/float_to_int_64_infneg1.stderr similarity index 100% rename from tests/compile-fail/intrinsics/float_to_int_64_infneg1.stderr rename to tests/fail/intrinsics/float_to_int_64_infneg1.stderr diff --git a/tests/compile-fail/intrinsics/float_to_int_64_infneg2.rs b/tests/fail/intrinsics/float_to_int_64_infneg2.rs similarity index 100% rename from tests/compile-fail/intrinsics/float_to_int_64_infneg2.rs rename to tests/fail/intrinsics/float_to_int_64_infneg2.rs diff --git a/tests/compile-fail/intrinsics/float_to_int_64_infneg2.stderr b/tests/fail/intrinsics/float_to_int_64_infneg2.stderr similarity index 100% rename from tests/compile-fail/intrinsics/float_to_int_64_infneg2.stderr rename to tests/fail/intrinsics/float_to_int_64_infneg2.stderr diff --git a/tests/compile-fail/intrinsics/float_to_int_64_nan.rs b/tests/fail/intrinsics/float_to_int_64_nan.rs similarity index 100% rename from tests/compile-fail/intrinsics/float_to_int_64_nan.rs rename to tests/fail/intrinsics/float_to_int_64_nan.rs diff --git a/tests/compile-fail/intrinsics/float_to_int_64_nan.stderr b/tests/fail/intrinsics/float_to_int_64_nan.stderr similarity index 100% rename from tests/compile-fail/intrinsics/float_to_int_64_nan.stderr rename to tests/fail/intrinsics/float_to_int_64_nan.stderr diff --git a/tests/compile-fail/intrinsics/float_to_int_64_neg.rs b/tests/fail/intrinsics/float_to_int_64_neg.rs similarity index 100% rename from tests/compile-fail/intrinsics/float_to_int_64_neg.rs rename to tests/fail/intrinsics/float_to_int_64_neg.rs diff --git a/tests/compile-fail/intrinsics/float_to_int_64_neg.stderr b/tests/fail/intrinsics/float_to_int_64_neg.stderr similarity index 100% rename from tests/compile-fail/intrinsics/float_to_int_64_neg.stderr rename to tests/fail/intrinsics/float_to_int_64_neg.stderr diff --git a/tests/compile-fail/intrinsics/float_to_int_64_too_big1.rs b/tests/fail/intrinsics/float_to_int_64_too_big1.rs similarity index 100% rename from tests/compile-fail/intrinsics/float_to_int_64_too_big1.rs rename to tests/fail/intrinsics/float_to_int_64_too_big1.rs diff --git a/tests/compile-fail/intrinsics/float_to_int_64_too_big1.stderr b/tests/fail/intrinsics/float_to_int_64_too_big1.stderr similarity index 100% rename from tests/compile-fail/intrinsics/float_to_int_64_too_big1.stderr rename to tests/fail/intrinsics/float_to_int_64_too_big1.stderr diff --git a/tests/compile-fail/intrinsics/float_to_int_64_too_big2.rs b/tests/fail/intrinsics/float_to_int_64_too_big2.rs similarity index 100% rename from tests/compile-fail/intrinsics/float_to_int_64_too_big2.rs rename to tests/fail/intrinsics/float_to_int_64_too_big2.rs diff --git a/tests/compile-fail/intrinsics/float_to_int_64_too_big2.stderr b/tests/fail/intrinsics/float_to_int_64_too_big2.stderr similarity index 100% rename from tests/compile-fail/intrinsics/float_to_int_64_too_big2.stderr rename to tests/fail/intrinsics/float_to_int_64_too_big2.stderr diff --git a/tests/compile-fail/intrinsics/float_to_int_64_too_big3.rs b/tests/fail/intrinsics/float_to_int_64_too_big3.rs similarity index 100% rename from tests/compile-fail/intrinsics/float_to_int_64_too_big3.rs rename to tests/fail/intrinsics/float_to_int_64_too_big3.rs diff --git a/tests/compile-fail/intrinsics/float_to_int_64_too_big3.stderr b/tests/fail/intrinsics/float_to_int_64_too_big3.stderr similarity index 100% rename from tests/compile-fail/intrinsics/float_to_int_64_too_big3.stderr rename to tests/fail/intrinsics/float_to_int_64_too_big3.stderr diff --git a/tests/compile-fail/intrinsics/float_to_int_64_too_big4.rs b/tests/fail/intrinsics/float_to_int_64_too_big4.rs similarity index 100% rename from tests/compile-fail/intrinsics/float_to_int_64_too_big4.rs rename to tests/fail/intrinsics/float_to_int_64_too_big4.rs diff --git a/tests/compile-fail/intrinsics/float_to_int_64_too_big4.stderr b/tests/fail/intrinsics/float_to_int_64_too_big4.stderr similarity index 100% rename from tests/compile-fail/intrinsics/float_to_int_64_too_big4.stderr rename to tests/fail/intrinsics/float_to_int_64_too_big4.stderr diff --git a/tests/compile-fail/intrinsics/float_to_int_64_too_big5.rs b/tests/fail/intrinsics/float_to_int_64_too_big5.rs similarity index 100% rename from tests/compile-fail/intrinsics/float_to_int_64_too_big5.rs rename to tests/fail/intrinsics/float_to_int_64_too_big5.rs diff --git a/tests/compile-fail/intrinsics/float_to_int_64_too_big5.stderr b/tests/fail/intrinsics/float_to_int_64_too_big5.stderr similarity index 100% rename from tests/compile-fail/intrinsics/float_to_int_64_too_big5.stderr rename to tests/fail/intrinsics/float_to_int_64_too_big5.stderr diff --git a/tests/compile-fail/intrinsics/float_to_int_64_too_big6.rs b/tests/fail/intrinsics/float_to_int_64_too_big6.rs similarity index 100% rename from tests/compile-fail/intrinsics/float_to_int_64_too_big6.rs rename to tests/fail/intrinsics/float_to_int_64_too_big6.rs diff --git a/tests/compile-fail/intrinsics/float_to_int_64_too_big6.stderr b/tests/fail/intrinsics/float_to_int_64_too_big6.stderr similarity index 100% rename from tests/compile-fail/intrinsics/float_to_int_64_too_big6.stderr rename to tests/fail/intrinsics/float_to_int_64_too_big6.stderr diff --git a/tests/compile-fail/intrinsics/float_to_int_64_too_big7.rs b/tests/fail/intrinsics/float_to_int_64_too_big7.rs similarity index 100% rename from tests/compile-fail/intrinsics/float_to_int_64_too_big7.rs rename to tests/fail/intrinsics/float_to_int_64_too_big7.rs diff --git a/tests/compile-fail/intrinsics/float_to_int_64_too_big7.stderr b/tests/fail/intrinsics/float_to_int_64_too_big7.stderr similarity index 100% rename from tests/compile-fail/intrinsics/float_to_int_64_too_big7.stderr rename to tests/fail/intrinsics/float_to_int_64_too_big7.stderr diff --git a/tests/compile-fail/intrinsics/float_to_int_64_too_small1.rs b/tests/fail/intrinsics/float_to_int_64_too_small1.rs similarity index 100% rename from tests/compile-fail/intrinsics/float_to_int_64_too_small1.rs rename to tests/fail/intrinsics/float_to_int_64_too_small1.rs diff --git a/tests/compile-fail/intrinsics/float_to_int_64_too_small1.stderr b/tests/fail/intrinsics/float_to_int_64_too_small1.stderr similarity index 100% rename from tests/compile-fail/intrinsics/float_to_int_64_too_small1.stderr rename to tests/fail/intrinsics/float_to_int_64_too_small1.stderr diff --git a/tests/compile-fail/intrinsics/float_to_int_64_too_small2.rs b/tests/fail/intrinsics/float_to_int_64_too_small2.rs similarity index 100% rename from tests/compile-fail/intrinsics/float_to_int_64_too_small2.rs rename to tests/fail/intrinsics/float_to_int_64_too_small2.rs diff --git a/tests/compile-fail/intrinsics/float_to_int_64_too_small2.stderr b/tests/fail/intrinsics/float_to_int_64_too_small2.stderr similarity index 100% rename from tests/compile-fail/intrinsics/float_to_int_64_too_small2.stderr rename to tests/fail/intrinsics/float_to_int_64_too_small2.stderr diff --git a/tests/compile-fail/intrinsics/float_to_int_64_too_small3.rs b/tests/fail/intrinsics/float_to_int_64_too_small3.rs similarity index 100% rename from tests/compile-fail/intrinsics/float_to_int_64_too_small3.rs rename to tests/fail/intrinsics/float_to_int_64_too_small3.rs diff --git a/tests/compile-fail/intrinsics/float_to_int_64_too_small3.stderr b/tests/fail/intrinsics/float_to_int_64_too_small3.stderr similarity index 100% rename from tests/compile-fail/intrinsics/float_to_int_64_too_small3.stderr rename to tests/fail/intrinsics/float_to_int_64_too_small3.stderr diff --git a/tests/compile-fail/intrinsics/out_of_bounds_ptr_1.rs b/tests/fail/intrinsics/out_of_bounds_ptr_1.rs similarity index 100% rename from tests/compile-fail/intrinsics/out_of_bounds_ptr_1.rs rename to tests/fail/intrinsics/out_of_bounds_ptr_1.rs diff --git a/tests/compile-fail/intrinsics/out_of_bounds_ptr_1.stderr b/tests/fail/intrinsics/out_of_bounds_ptr_1.stderr similarity index 100% rename from tests/compile-fail/intrinsics/out_of_bounds_ptr_1.stderr rename to tests/fail/intrinsics/out_of_bounds_ptr_1.stderr diff --git a/tests/compile-fail/intrinsics/out_of_bounds_ptr_2.rs b/tests/fail/intrinsics/out_of_bounds_ptr_2.rs similarity index 100% rename from tests/compile-fail/intrinsics/out_of_bounds_ptr_2.rs rename to tests/fail/intrinsics/out_of_bounds_ptr_2.rs diff --git a/tests/compile-fail/intrinsics/out_of_bounds_ptr_2.stderr b/tests/fail/intrinsics/out_of_bounds_ptr_2.stderr similarity index 100% rename from tests/compile-fail/intrinsics/out_of_bounds_ptr_2.stderr rename to tests/fail/intrinsics/out_of_bounds_ptr_2.stderr diff --git a/tests/compile-fail/intrinsics/out_of_bounds_ptr_3.rs b/tests/fail/intrinsics/out_of_bounds_ptr_3.rs similarity index 100% rename from tests/compile-fail/intrinsics/out_of_bounds_ptr_3.rs rename to tests/fail/intrinsics/out_of_bounds_ptr_3.rs diff --git a/tests/compile-fail/intrinsics/out_of_bounds_ptr_3.stderr b/tests/fail/intrinsics/out_of_bounds_ptr_3.stderr similarity index 100% rename from tests/compile-fail/intrinsics/out_of_bounds_ptr_3.stderr rename to tests/fail/intrinsics/out_of_bounds_ptr_3.stderr diff --git a/tests/compile-fail/intrinsics/overflowing-unchecked-rsh.rs b/tests/fail/intrinsics/overflowing-unchecked-rsh.rs similarity index 100% rename from tests/compile-fail/intrinsics/overflowing-unchecked-rsh.rs rename to tests/fail/intrinsics/overflowing-unchecked-rsh.rs diff --git a/tests/compile-fail/intrinsics/overflowing-unchecked-rsh.stderr b/tests/fail/intrinsics/overflowing-unchecked-rsh.stderr similarity index 100% rename from tests/compile-fail/intrinsics/overflowing-unchecked-rsh.stderr rename to tests/fail/intrinsics/overflowing-unchecked-rsh.stderr diff --git a/tests/compile-fail/intrinsics/ptr_offset_0_plus_0.rs b/tests/fail/intrinsics/ptr_offset_0_plus_0.rs similarity index 100% rename from tests/compile-fail/intrinsics/ptr_offset_0_plus_0.rs rename to tests/fail/intrinsics/ptr_offset_0_plus_0.rs diff --git a/tests/compile-fail/intrinsics/ptr_offset_0_plus_0.stderr b/tests/fail/intrinsics/ptr_offset_0_plus_0.stderr similarity index 100% rename from tests/compile-fail/intrinsics/ptr_offset_0_plus_0.stderr rename to tests/fail/intrinsics/ptr_offset_0_plus_0.stderr diff --git a/tests/compile-fail/intrinsics/ptr_offset_from_oob.rs b/tests/fail/intrinsics/ptr_offset_from_oob.rs similarity index 100% rename from tests/compile-fail/intrinsics/ptr_offset_from_oob.rs rename to tests/fail/intrinsics/ptr_offset_from_oob.rs diff --git a/tests/compile-fail/intrinsics/ptr_offset_from_oob.stderr b/tests/fail/intrinsics/ptr_offset_from_oob.stderr similarity index 100% rename from tests/compile-fail/intrinsics/ptr_offset_from_oob.stderr rename to tests/fail/intrinsics/ptr_offset_from_oob.stderr diff --git a/tests/compile-fail/intrinsics/ptr_offset_int_plus_int.rs b/tests/fail/intrinsics/ptr_offset_int_plus_int.rs similarity index 100% rename from tests/compile-fail/intrinsics/ptr_offset_int_plus_int.rs rename to tests/fail/intrinsics/ptr_offset_int_plus_int.rs diff --git a/tests/compile-fail/intrinsics/ptr_offset_int_plus_int.stderr b/tests/fail/intrinsics/ptr_offset_int_plus_int.stderr similarity index 100% rename from tests/compile-fail/intrinsics/ptr_offset_int_plus_int.stderr rename to tests/fail/intrinsics/ptr_offset_int_plus_int.stderr diff --git a/tests/compile-fail/intrinsics/ptr_offset_int_plus_ptr.rs b/tests/fail/intrinsics/ptr_offset_int_plus_ptr.rs similarity index 100% rename from tests/compile-fail/intrinsics/ptr_offset_int_plus_ptr.rs rename to tests/fail/intrinsics/ptr_offset_int_plus_ptr.rs diff --git a/tests/compile-fail/intrinsics/ptr_offset_int_plus_ptr.stderr b/tests/fail/intrinsics/ptr_offset_int_plus_ptr.stderr similarity index 100% rename from tests/compile-fail/intrinsics/ptr_offset_int_plus_ptr.stderr rename to tests/fail/intrinsics/ptr_offset_int_plus_ptr.stderr diff --git a/tests/compile-fail/intrinsics/ptr_offset_overflow.rs b/tests/fail/intrinsics/ptr_offset_overflow.rs similarity index 100% rename from tests/compile-fail/intrinsics/ptr_offset_overflow.rs rename to tests/fail/intrinsics/ptr_offset_overflow.rs diff --git a/tests/compile-fail/intrinsics/ptr_offset_overflow.stderr b/tests/fail/intrinsics/ptr_offset_overflow.stderr similarity index 100% rename from tests/compile-fail/intrinsics/ptr_offset_overflow.stderr rename to tests/fail/intrinsics/ptr_offset_overflow.stderr diff --git a/tests/compile-fail/intrinsics/ptr_offset_ptr_plus_0.rs b/tests/fail/intrinsics/ptr_offset_ptr_plus_0.rs similarity index 100% rename from tests/compile-fail/intrinsics/ptr_offset_ptr_plus_0.rs rename to tests/fail/intrinsics/ptr_offset_ptr_plus_0.rs diff --git a/tests/compile-fail/intrinsics/ptr_offset_ptr_plus_0.stderr b/tests/fail/intrinsics/ptr_offset_ptr_plus_0.stderr similarity index 100% rename from tests/compile-fail/intrinsics/ptr_offset_ptr_plus_0.stderr rename to tests/fail/intrinsics/ptr_offset_ptr_plus_0.stderr diff --git a/tests/compile-fail/intrinsics/rem-by-zero.rs b/tests/fail/intrinsics/rem-by-zero.rs similarity index 100% rename from tests/compile-fail/intrinsics/rem-by-zero.rs rename to tests/fail/intrinsics/rem-by-zero.rs diff --git a/tests/compile-fail/intrinsics/rem-by-zero.stderr b/tests/fail/intrinsics/rem-by-zero.stderr similarity index 100% rename from tests/compile-fail/intrinsics/rem-by-zero.stderr rename to tests/fail/intrinsics/rem-by-zero.stderr diff --git a/tests/compile-fail/intrinsics/simd-div-by-zero.rs b/tests/fail/intrinsics/simd-div-by-zero.rs similarity index 100% rename from tests/compile-fail/intrinsics/simd-div-by-zero.rs rename to tests/fail/intrinsics/simd-div-by-zero.rs diff --git a/tests/compile-fail/intrinsics/simd-div-by-zero.stderr b/tests/fail/intrinsics/simd-div-by-zero.stderr similarity index 100% rename from tests/compile-fail/intrinsics/simd-div-by-zero.stderr rename to tests/fail/intrinsics/simd-div-by-zero.stderr diff --git a/tests/compile-fail/intrinsics/simd-div-overflow.rs b/tests/fail/intrinsics/simd-div-overflow.rs similarity index 100% rename from tests/compile-fail/intrinsics/simd-div-overflow.rs rename to tests/fail/intrinsics/simd-div-overflow.rs diff --git a/tests/compile-fail/intrinsics/simd-div-overflow.stderr b/tests/fail/intrinsics/simd-div-overflow.stderr similarity index 100% rename from tests/compile-fail/intrinsics/simd-div-overflow.stderr rename to tests/fail/intrinsics/simd-div-overflow.stderr diff --git a/tests/compile-fail/intrinsics/simd-float-to-int.rs b/tests/fail/intrinsics/simd-float-to-int.rs similarity index 100% rename from tests/compile-fail/intrinsics/simd-float-to-int.rs rename to tests/fail/intrinsics/simd-float-to-int.rs diff --git a/tests/compile-fail/intrinsics/simd-float-to-int.stderr b/tests/fail/intrinsics/simd-float-to-int.stderr similarity index 100% rename from tests/compile-fail/intrinsics/simd-float-to-int.stderr rename to tests/fail/intrinsics/simd-float-to-int.stderr diff --git a/tests/compile-fail/intrinsics/simd-gather.rs b/tests/fail/intrinsics/simd-gather.rs similarity index 100% rename from tests/compile-fail/intrinsics/simd-gather.rs rename to tests/fail/intrinsics/simd-gather.rs diff --git a/tests/compile-fail/intrinsics/simd-gather.stderr b/tests/fail/intrinsics/simd-gather.stderr similarity index 100% rename from tests/compile-fail/intrinsics/simd-gather.stderr rename to tests/fail/intrinsics/simd-gather.stderr diff --git a/tests/compile-fail/intrinsics/simd-reduce-invalid-bool.rs b/tests/fail/intrinsics/simd-reduce-invalid-bool.rs similarity index 100% rename from tests/compile-fail/intrinsics/simd-reduce-invalid-bool.rs rename to tests/fail/intrinsics/simd-reduce-invalid-bool.rs diff --git a/tests/compile-fail/intrinsics/simd-reduce-invalid-bool.stderr b/tests/fail/intrinsics/simd-reduce-invalid-bool.stderr similarity index 100% rename from tests/compile-fail/intrinsics/simd-reduce-invalid-bool.stderr rename to tests/fail/intrinsics/simd-reduce-invalid-bool.stderr diff --git a/tests/compile-fail/intrinsics/simd-rem-by-zero.rs b/tests/fail/intrinsics/simd-rem-by-zero.rs similarity index 100% rename from tests/compile-fail/intrinsics/simd-rem-by-zero.rs rename to tests/fail/intrinsics/simd-rem-by-zero.rs diff --git a/tests/compile-fail/intrinsics/simd-rem-by-zero.stderr b/tests/fail/intrinsics/simd-rem-by-zero.stderr similarity index 100% rename from tests/compile-fail/intrinsics/simd-rem-by-zero.stderr rename to tests/fail/intrinsics/simd-rem-by-zero.stderr diff --git a/tests/compile-fail/intrinsics/simd-scatter.rs b/tests/fail/intrinsics/simd-scatter.rs similarity index 100% rename from tests/compile-fail/intrinsics/simd-scatter.rs rename to tests/fail/intrinsics/simd-scatter.rs diff --git a/tests/compile-fail/intrinsics/simd-scatter.stderr b/tests/fail/intrinsics/simd-scatter.stderr similarity index 100% rename from tests/compile-fail/intrinsics/simd-scatter.stderr rename to tests/fail/intrinsics/simd-scatter.stderr diff --git a/tests/compile-fail/intrinsics/simd-select-bitmask-invalid.rs b/tests/fail/intrinsics/simd-select-bitmask-invalid.rs similarity index 100% rename from tests/compile-fail/intrinsics/simd-select-bitmask-invalid.rs rename to tests/fail/intrinsics/simd-select-bitmask-invalid.rs diff --git a/tests/compile-fail/intrinsics/simd-select-bitmask-invalid.stderr b/tests/fail/intrinsics/simd-select-bitmask-invalid.stderr similarity index 100% rename from tests/compile-fail/intrinsics/simd-select-bitmask-invalid.stderr rename to tests/fail/intrinsics/simd-select-bitmask-invalid.stderr diff --git a/tests/compile-fail/intrinsics/simd-select-invalid-bool.rs b/tests/fail/intrinsics/simd-select-invalid-bool.rs similarity index 100% rename from tests/compile-fail/intrinsics/simd-select-invalid-bool.rs rename to tests/fail/intrinsics/simd-select-invalid-bool.rs diff --git a/tests/compile-fail/intrinsics/simd-select-invalid-bool.stderr b/tests/fail/intrinsics/simd-select-invalid-bool.stderr similarity index 100% rename from tests/compile-fail/intrinsics/simd-select-invalid-bool.stderr rename to tests/fail/intrinsics/simd-select-invalid-bool.stderr diff --git a/tests/compile-fail/intrinsics/simd-shl-too-far.rs b/tests/fail/intrinsics/simd-shl-too-far.rs similarity index 100% rename from tests/compile-fail/intrinsics/simd-shl-too-far.rs rename to tests/fail/intrinsics/simd-shl-too-far.rs diff --git a/tests/compile-fail/intrinsics/simd-shl-too-far.stderr b/tests/fail/intrinsics/simd-shl-too-far.stderr similarity index 100% rename from tests/compile-fail/intrinsics/simd-shl-too-far.stderr rename to tests/fail/intrinsics/simd-shl-too-far.stderr diff --git a/tests/compile-fail/intrinsics/simd-shr-too-far.rs b/tests/fail/intrinsics/simd-shr-too-far.rs similarity index 100% rename from tests/compile-fail/intrinsics/simd-shr-too-far.rs rename to tests/fail/intrinsics/simd-shr-too-far.rs diff --git a/tests/compile-fail/intrinsics/simd-shr-too-far.stderr b/tests/fail/intrinsics/simd-shr-too-far.stderr similarity index 100% rename from tests/compile-fail/intrinsics/simd-shr-too-far.stderr rename to tests/fail/intrinsics/simd-shr-too-far.stderr diff --git a/tests/compile-fail/intrinsics/unchecked_add1.rs b/tests/fail/intrinsics/unchecked_add1.rs similarity index 100% rename from tests/compile-fail/intrinsics/unchecked_add1.rs rename to tests/fail/intrinsics/unchecked_add1.rs diff --git a/tests/compile-fail/intrinsics/unchecked_add1.stderr b/tests/fail/intrinsics/unchecked_add1.stderr similarity index 100% rename from tests/compile-fail/intrinsics/unchecked_add1.stderr rename to tests/fail/intrinsics/unchecked_add1.stderr diff --git a/tests/compile-fail/intrinsics/unchecked_add2.rs b/tests/fail/intrinsics/unchecked_add2.rs similarity index 100% rename from tests/compile-fail/intrinsics/unchecked_add2.rs rename to tests/fail/intrinsics/unchecked_add2.rs diff --git a/tests/compile-fail/intrinsics/unchecked_add2.stderr b/tests/fail/intrinsics/unchecked_add2.stderr similarity index 100% rename from tests/compile-fail/intrinsics/unchecked_add2.stderr rename to tests/fail/intrinsics/unchecked_add2.stderr diff --git a/tests/compile-fail/intrinsics/unchecked_div1.rs b/tests/fail/intrinsics/unchecked_div1.rs similarity index 100% rename from tests/compile-fail/intrinsics/unchecked_div1.rs rename to tests/fail/intrinsics/unchecked_div1.rs diff --git a/tests/compile-fail/intrinsics/unchecked_div1.stderr b/tests/fail/intrinsics/unchecked_div1.stderr similarity index 100% rename from tests/compile-fail/intrinsics/unchecked_div1.stderr rename to tests/fail/intrinsics/unchecked_div1.stderr diff --git a/tests/compile-fail/intrinsics/unchecked_mul1.rs b/tests/fail/intrinsics/unchecked_mul1.rs similarity index 100% rename from tests/compile-fail/intrinsics/unchecked_mul1.rs rename to tests/fail/intrinsics/unchecked_mul1.rs diff --git a/tests/compile-fail/intrinsics/unchecked_mul1.stderr b/tests/fail/intrinsics/unchecked_mul1.stderr similarity index 100% rename from tests/compile-fail/intrinsics/unchecked_mul1.stderr rename to tests/fail/intrinsics/unchecked_mul1.stderr diff --git a/tests/compile-fail/intrinsics/unchecked_mul2.rs b/tests/fail/intrinsics/unchecked_mul2.rs similarity index 100% rename from tests/compile-fail/intrinsics/unchecked_mul2.rs rename to tests/fail/intrinsics/unchecked_mul2.rs diff --git a/tests/compile-fail/intrinsics/unchecked_mul2.stderr b/tests/fail/intrinsics/unchecked_mul2.stderr similarity index 100% rename from tests/compile-fail/intrinsics/unchecked_mul2.stderr rename to tests/fail/intrinsics/unchecked_mul2.stderr diff --git a/tests/compile-fail/intrinsics/unchecked_sub1.rs b/tests/fail/intrinsics/unchecked_sub1.rs similarity index 100% rename from tests/compile-fail/intrinsics/unchecked_sub1.rs rename to tests/fail/intrinsics/unchecked_sub1.rs diff --git a/tests/compile-fail/intrinsics/unchecked_sub1.stderr b/tests/fail/intrinsics/unchecked_sub1.stderr similarity index 100% rename from tests/compile-fail/intrinsics/unchecked_sub1.stderr rename to tests/fail/intrinsics/unchecked_sub1.stderr diff --git a/tests/compile-fail/intrinsics/unchecked_sub2.rs b/tests/fail/intrinsics/unchecked_sub2.rs similarity index 100% rename from tests/compile-fail/intrinsics/unchecked_sub2.rs rename to tests/fail/intrinsics/unchecked_sub2.rs diff --git a/tests/compile-fail/intrinsics/unchecked_sub2.stderr b/tests/fail/intrinsics/unchecked_sub2.stderr similarity index 100% rename from tests/compile-fail/intrinsics/unchecked_sub2.stderr rename to tests/fail/intrinsics/unchecked_sub2.stderr diff --git a/tests/compile-fail/intrinsics/uninit_uninhabited_type.rs b/tests/fail/intrinsics/uninit_uninhabited_type.rs similarity index 100% rename from tests/compile-fail/intrinsics/uninit_uninhabited_type.rs rename to tests/fail/intrinsics/uninit_uninhabited_type.rs diff --git a/tests/compile-fail/intrinsics/uninit_uninhabited_type.stderr b/tests/fail/intrinsics/uninit_uninhabited_type.stderr similarity index 100% rename from tests/compile-fail/intrinsics/uninit_uninhabited_type.stderr rename to tests/fail/intrinsics/uninit_uninhabited_type.stderr diff --git a/tests/compile-fail/intrinsics/write_bytes_null.rs b/tests/fail/intrinsics/write_bytes_null.rs similarity index 100% rename from tests/compile-fail/intrinsics/write_bytes_null.rs rename to tests/fail/intrinsics/write_bytes_null.rs diff --git a/tests/compile-fail/intrinsics/write_bytes_null.stderr b/tests/fail/intrinsics/write_bytes_null.stderr similarity index 100% rename from tests/compile-fail/intrinsics/write_bytes_null.stderr rename to tests/fail/intrinsics/write_bytes_null.stderr diff --git a/tests/compile-fail/intrinsics/write_bytes_overflow.rs b/tests/fail/intrinsics/write_bytes_overflow.rs similarity index 100% rename from tests/compile-fail/intrinsics/write_bytes_overflow.rs rename to tests/fail/intrinsics/write_bytes_overflow.rs diff --git a/tests/compile-fail/intrinsics/write_bytes_overflow.stderr b/tests/fail/intrinsics/write_bytes_overflow.stderr similarity index 100% rename from tests/compile-fail/intrinsics/write_bytes_overflow.stderr rename to tests/fail/intrinsics/write_bytes_overflow.stderr diff --git a/tests/compile-fail/intrinsics/zero_fn_ptr.rs b/tests/fail/intrinsics/zero_fn_ptr.rs similarity index 100% rename from tests/compile-fail/intrinsics/zero_fn_ptr.rs rename to tests/fail/intrinsics/zero_fn_ptr.rs diff --git a/tests/compile-fail/intrinsics/zero_fn_ptr.stderr b/tests/fail/intrinsics/zero_fn_ptr.stderr similarity index 100% rename from tests/compile-fail/intrinsics/zero_fn_ptr.stderr rename to tests/fail/intrinsics/zero_fn_ptr.stderr diff --git a/tests/compile-fail/invalid_bool.rs b/tests/fail/invalid_bool.rs similarity index 100% rename from tests/compile-fail/invalid_bool.rs rename to tests/fail/invalid_bool.rs diff --git a/tests/compile-fail/invalid_bool.stderr b/tests/fail/invalid_bool.stderr similarity index 100% rename from tests/compile-fail/invalid_bool.stderr rename to tests/fail/invalid_bool.stderr diff --git a/tests/compile-fail/invalid_char.rs b/tests/fail/invalid_char.rs similarity index 100% rename from tests/compile-fail/invalid_char.rs rename to tests/fail/invalid_char.rs diff --git a/tests/compile-fail/invalid_char.stderr b/tests/fail/invalid_char.stderr similarity index 100% rename from tests/compile-fail/invalid_char.stderr rename to tests/fail/invalid_char.stderr diff --git a/tests/compile-fail/invalid_enum_tag.rs b/tests/fail/invalid_enum_tag.rs similarity index 100% rename from tests/compile-fail/invalid_enum_tag.rs rename to tests/fail/invalid_enum_tag.rs diff --git a/tests/compile-fail/invalid_enum_tag.stderr b/tests/fail/invalid_enum_tag.stderr similarity index 100% rename from tests/compile-fail/invalid_enum_tag.stderr rename to tests/fail/invalid_enum_tag.stderr diff --git a/tests/compile-fail/invalid_int.rs b/tests/fail/invalid_int.rs similarity index 100% rename from tests/compile-fail/invalid_int.rs rename to tests/fail/invalid_int.rs diff --git a/tests/compile-fail/invalid_int.stderr b/tests/fail/invalid_int.stderr similarity index 100% rename from tests/compile-fail/invalid_int.stderr rename to tests/fail/invalid_int.stderr diff --git a/tests/compile-fail/issue-miri-1112.rs b/tests/fail/issue-miri-1112.rs similarity index 100% rename from tests/compile-fail/issue-miri-1112.rs rename to tests/fail/issue-miri-1112.rs diff --git a/tests/compile-fail/issue-miri-1112.stderr b/tests/fail/issue-miri-1112.stderr similarity index 100% rename from tests/compile-fail/issue-miri-1112.stderr rename to tests/fail/issue-miri-1112.stderr diff --git a/tests/compile-fail/memleak.rs b/tests/fail/memleak.rs similarity index 100% rename from tests/compile-fail/memleak.rs rename to tests/fail/memleak.rs diff --git a/tests/compile-fail/memleak.stderr b/tests/fail/memleak.stderr similarity index 100% rename from tests/compile-fail/memleak.stderr rename to tests/fail/memleak.stderr diff --git a/tests/compile-fail/memleak_rc.32bit.stderr b/tests/fail/memleak_rc.32bit.stderr similarity index 100% rename from tests/compile-fail/memleak_rc.32bit.stderr rename to tests/fail/memleak_rc.32bit.stderr diff --git a/tests/compile-fail/memleak_rc.64bit.stderr b/tests/fail/memleak_rc.64bit.stderr similarity index 100% rename from tests/compile-fail/memleak_rc.64bit.stderr rename to tests/fail/memleak_rc.64bit.stderr diff --git a/tests/compile-fail/memleak_rc.rs b/tests/fail/memleak_rc.rs similarity index 100% rename from tests/compile-fail/memleak_rc.rs rename to tests/fail/memleak_rc.rs diff --git a/tests/compile-fail/modifying_constants.rs b/tests/fail/modifying_constants.rs similarity index 100% rename from tests/compile-fail/modifying_constants.rs rename to tests/fail/modifying_constants.rs diff --git a/tests/compile-fail/modifying_constants.stderr b/tests/fail/modifying_constants.stderr similarity index 100% rename from tests/compile-fail/modifying_constants.stderr rename to tests/fail/modifying_constants.stderr diff --git a/tests/compile-fail/never_say_never.rs b/tests/fail/never_say_never.rs similarity index 100% rename from tests/compile-fail/never_say_never.rs rename to tests/fail/never_say_never.rs diff --git a/tests/compile-fail/never_say_never.stderr b/tests/fail/never_say_never.stderr similarity index 100% rename from tests/compile-fail/never_say_never.stderr rename to tests/fail/never_say_never.stderr diff --git a/tests/compile-fail/never_transmute_humans.rs b/tests/fail/never_transmute_humans.rs similarity index 100% rename from tests/compile-fail/never_transmute_humans.rs rename to tests/fail/never_transmute_humans.rs diff --git a/tests/compile-fail/never_transmute_humans.stderr b/tests/fail/never_transmute_humans.stderr similarity index 100% rename from tests/compile-fail/never_transmute_humans.stderr rename to tests/fail/never_transmute_humans.stderr diff --git a/tests/compile-fail/never_transmute_void.rs b/tests/fail/never_transmute_void.rs similarity index 100% rename from tests/compile-fail/never_transmute_void.rs rename to tests/fail/never_transmute_void.rs diff --git a/tests/compile-fail/never_transmute_void.stderr b/tests/fail/never_transmute_void.stderr similarity index 100% rename from tests/compile-fail/never_transmute_void.stderr rename to tests/fail/never_transmute_void.stderr diff --git a/tests/compile-fail/no_main.rs b/tests/fail/no_main.rs similarity index 100% rename from tests/compile-fail/no_main.rs rename to tests/fail/no_main.rs diff --git a/tests/compile-fail/no_main.stderr b/tests/fail/no_main.stderr similarity index 100% rename from tests/compile-fail/no_main.stderr rename to tests/fail/no_main.stderr diff --git a/tests/compile-fail/null_pointer_deref.stderr b/tests/fail/null_pointer_deref.stderr similarity index 100% rename from tests/compile-fail/null_pointer_deref.stderr rename to tests/fail/null_pointer_deref.stderr diff --git a/tests/compile-fail/null_pointer_deref_zst.stderr b/tests/fail/null_pointer_deref_zst.stderr similarity index 100% rename from tests/compile-fail/null_pointer_deref_zst.stderr rename to tests/fail/null_pointer_deref_zst.stderr diff --git a/tests/compile-fail/null_pointer_write.stderr b/tests/fail/null_pointer_write.stderr similarity index 100% rename from tests/compile-fail/null_pointer_write.stderr rename to tests/fail/null_pointer_write.stderr diff --git a/tests/compile-fail/null_pointer_write_zst.stderr b/tests/fail/null_pointer_write_zst.stderr similarity index 100% rename from tests/compile-fail/null_pointer_write_zst.stderr rename to tests/fail/null_pointer_write_zst.stderr diff --git a/tests/compile-fail/panic/bad_miri_start_panic.rs b/tests/fail/panic/bad_miri_start_panic.rs similarity index 100% rename from tests/compile-fail/panic/bad_miri_start_panic.rs rename to tests/fail/panic/bad_miri_start_panic.rs diff --git a/tests/compile-fail/panic/bad_miri_start_panic.stderr b/tests/fail/panic/bad_miri_start_panic.stderr similarity index 100% rename from tests/compile-fail/panic/bad_miri_start_panic.stderr rename to tests/fail/panic/bad_miri_start_panic.stderr diff --git a/tests/compile-fail/panic/bad_unwind.rs b/tests/fail/panic/bad_unwind.rs similarity index 100% rename from tests/compile-fail/panic/bad_unwind.rs rename to tests/fail/panic/bad_unwind.rs diff --git a/tests/compile-fail/panic/bad_unwind.stderr b/tests/fail/panic/bad_unwind.stderr similarity index 100% rename from tests/compile-fail/panic/bad_unwind.stderr rename to tests/fail/panic/bad_unwind.stderr diff --git a/tests/compile-fail/panic/double_panic.rs b/tests/fail/panic/double_panic.rs similarity index 100% rename from tests/compile-fail/panic/double_panic.rs rename to tests/fail/panic/double_panic.rs diff --git a/tests/compile-fail/panic/double_panic.stderr b/tests/fail/panic/double_panic.stderr similarity index 100% rename from tests/compile-fail/panic/double_panic.stderr rename to tests/fail/panic/double_panic.stderr diff --git a/tests/compile-fail/panic/panic_abort1.rs b/tests/fail/panic/panic_abort1.rs similarity index 100% rename from tests/compile-fail/panic/panic_abort1.rs rename to tests/fail/panic/panic_abort1.rs diff --git a/tests/compile-fail/panic/panic_abort1.stderr b/tests/fail/panic/panic_abort1.stderr similarity index 100% rename from tests/compile-fail/panic/panic_abort1.stderr rename to tests/fail/panic/panic_abort1.stderr diff --git a/tests/compile-fail/panic/panic_abort2.rs b/tests/fail/panic/panic_abort2.rs similarity index 100% rename from tests/compile-fail/panic/panic_abort2.rs rename to tests/fail/panic/panic_abort2.rs diff --git a/tests/compile-fail/panic/panic_abort2.stderr b/tests/fail/panic/panic_abort2.stderr similarity index 100% rename from tests/compile-fail/panic/panic_abort2.stderr rename to tests/fail/panic/panic_abort2.stderr diff --git a/tests/compile-fail/panic/panic_abort3.rs b/tests/fail/panic/panic_abort3.rs similarity index 100% rename from tests/compile-fail/panic/panic_abort3.rs rename to tests/fail/panic/panic_abort3.rs diff --git a/tests/compile-fail/panic/panic_abort3.stderr b/tests/fail/panic/panic_abort3.stderr similarity index 100% rename from tests/compile-fail/panic/panic_abort3.stderr rename to tests/fail/panic/panic_abort3.stderr diff --git a/tests/compile-fail/panic/panic_abort4.rs b/tests/fail/panic/panic_abort4.rs similarity index 100% rename from tests/compile-fail/panic/panic_abort4.rs rename to tests/fail/panic/panic_abort4.rs diff --git a/tests/compile-fail/panic/panic_abort4.stderr b/tests/fail/panic/panic_abort4.stderr similarity index 100% rename from tests/compile-fail/panic/panic_abort4.stderr rename to tests/fail/panic/panic_abort4.stderr diff --git a/tests/compile-fail/panic/unwind_panic_abort.rs b/tests/fail/panic/unwind_panic_abort.rs similarity index 100% rename from tests/compile-fail/panic/unwind_panic_abort.rs rename to tests/fail/panic/unwind_panic_abort.rs diff --git a/tests/compile-fail/panic/unwind_panic_abort.stderr b/tests/fail/panic/unwind_panic_abort.stderr similarity index 100% rename from tests/compile-fail/panic/unwind_panic_abort.stderr rename to tests/fail/panic/unwind_panic_abort.stderr diff --git a/tests/compile-fail/pointer_partial_overwrite.rs b/tests/fail/pointer_partial_overwrite.rs similarity index 100% rename from tests/compile-fail/pointer_partial_overwrite.rs rename to tests/fail/pointer_partial_overwrite.rs diff --git a/tests/compile-fail/pointer_partial_overwrite.stderr b/tests/fail/pointer_partial_overwrite.stderr similarity index 100% rename from tests/compile-fail/pointer_partial_overwrite.stderr rename to tests/fail/pointer_partial_overwrite.stderr diff --git a/tests/compile-fail/pointer_partial_read.rs b/tests/fail/pointer_partial_read.rs similarity index 100% rename from tests/compile-fail/pointer_partial_read.rs rename to tests/fail/pointer_partial_read.rs diff --git a/tests/compile-fail/pointer_partial_read.stderr b/tests/fail/pointer_partial_read.stderr similarity index 100% rename from tests/compile-fail/pointer_partial_read.stderr rename to tests/fail/pointer_partial_read.stderr diff --git a/tests/compile-fail/provenance/ptr_int_unexposed.rs b/tests/fail/provenance/ptr_int_unexposed.rs similarity index 100% rename from tests/compile-fail/provenance/ptr_int_unexposed.rs rename to tests/fail/provenance/ptr_int_unexposed.rs diff --git a/tests/compile-fail/provenance/ptr_int_unexposed.stderr b/tests/fail/provenance/ptr_int_unexposed.stderr similarity index 100% rename from tests/compile-fail/provenance/ptr_int_unexposed.stderr rename to tests/fail/provenance/ptr_int_unexposed.stderr diff --git a/tests/compile-fail/provenance/ptr_invalid.rs b/tests/fail/provenance/ptr_invalid.rs similarity index 100% rename from tests/compile-fail/provenance/ptr_invalid.rs rename to tests/fail/provenance/ptr_invalid.rs diff --git a/tests/compile-fail/provenance/ptr_invalid.stderr b/tests/fail/provenance/ptr_invalid.stderr similarity index 100% rename from tests/compile-fail/provenance/ptr_invalid.stderr rename to tests/fail/provenance/ptr_invalid.stderr diff --git a/tests/compile-fail/provenance/ptr_legacy_provenance.rs b/tests/fail/provenance/ptr_legacy_provenance.rs similarity index 100% rename from tests/compile-fail/provenance/ptr_legacy_provenance.rs rename to tests/fail/provenance/ptr_legacy_provenance.rs diff --git a/tests/compile-fail/provenance/ptr_legacy_provenance.stderr b/tests/fail/provenance/ptr_legacy_provenance.stderr similarity index 100% rename from tests/compile-fail/provenance/ptr_legacy_provenance.stderr rename to tests/fail/provenance/ptr_legacy_provenance.stderr diff --git a/tests/compile-fail/provenance/strict-provenance-offset.rs b/tests/fail/provenance/strict-provenance-offset.rs similarity index 100% rename from tests/compile-fail/provenance/strict-provenance-offset.rs rename to tests/fail/provenance/strict-provenance-offset.rs diff --git a/tests/compile-fail/provenance/strict-provenance-offset.stderr b/tests/fail/provenance/strict-provenance-offset.stderr similarity index 100% rename from tests/compile-fail/provenance/strict-provenance-offset.stderr rename to tests/fail/provenance/strict-provenance-offset.stderr diff --git a/tests/compile-fail/provenance/strict_provenance_transmute.rs b/tests/fail/provenance/strict_provenance_transmute.rs similarity index 100% rename from tests/compile-fail/provenance/strict_provenance_transmute.rs rename to tests/fail/provenance/strict_provenance_transmute.rs diff --git a/tests/compile-fail/provenance/strict_provenance_transmute.stderr b/tests/fail/provenance/strict_provenance_transmute.stderr similarity index 100% rename from tests/compile-fail/provenance/strict_provenance_transmute.stderr rename to tests/fail/provenance/strict_provenance_transmute.stderr diff --git a/tests/compile-fail/ptr_integer_array_transmute.stderr b/tests/fail/ptr_integer_array_transmute.stderr similarity index 100% rename from tests/compile-fail/ptr_integer_array_transmute.stderr rename to tests/fail/ptr_integer_array_transmute.stderr diff --git a/tests/compile-fail/ptr_integer_transmute.stderr b/tests/fail/ptr_integer_transmute.stderr similarity index 100% rename from tests/compile-fail/ptr_integer_transmute.stderr rename to tests/fail/ptr_integer_transmute.stderr diff --git a/tests/compile-fail/rc_as_ptr.rs b/tests/fail/rc_as_ptr.rs similarity index 100% rename from tests/compile-fail/rc_as_ptr.rs rename to tests/fail/rc_as_ptr.rs diff --git a/tests/compile-fail/rc_as_ptr.stderr b/tests/fail/rc_as_ptr.stderr similarity index 100% rename from tests/compile-fail/rc_as_ptr.stderr rename to tests/fail/rc_as_ptr.stderr diff --git a/tests/compile-fail/reading_half_a_pointer.rs b/tests/fail/reading_half_a_pointer.rs similarity index 100% rename from tests/compile-fail/reading_half_a_pointer.rs rename to tests/fail/reading_half_a_pointer.rs diff --git a/tests/compile-fail/reading_half_a_pointer.stderr b/tests/fail/reading_half_a_pointer.stderr similarity index 100% rename from tests/compile-fail/reading_half_a_pointer.stderr rename to tests/fail/reading_half_a_pointer.stderr diff --git a/tests/compile-fail/rustc-error.rs b/tests/fail/rustc-error.rs similarity index 100% rename from tests/compile-fail/rustc-error.rs rename to tests/fail/rustc-error.rs diff --git a/tests/compile-fail/rustc-error.stderr b/tests/fail/rustc-error.stderr similarity index 100% rename from tests/compile-fail/rustc-error.stderr rename to tests/fail/rustc-error.stderr diff --git a/tests/compile-fail/shim_arg_size.32bit.stderr b/tests/fail/shim_arg_size.32bit.stderr similarity index 100% rename from tests/compile-fail/shim_arg_size.32bit.stderr rename to tests/fail/shim_arg_size.32bit.stderr diff --git a/tests/compile-fail/shim_arg_size.64bit.stderr b/tests/fail/shim_arg_size.64bit.stderr similarity index 100% rename from tests/compile-fail/shim_arg_size.64bit.stderr rename to tests/fail/shim_arg_size.64bit.stderr diff --git a/tests/compile-fail/shim_arg_size.rs b/tests/fail/shim_arg_size.rs similarity index 100% rename from tests/compile-fail/shim_arg_size.rs rename to tests/fail/shim_arg_size.rs diff --git a/tests/compile-fail/slice-too-big.stderr b/tests/fail/slice-too-big.stderr similarity index 100% rename from tests/compile-fail/slice-too-big.stderr rename to tests/fail/slice-too-big.stderr diff --git a/tests/compile-fail/stacked_borrows/alias_through_mutation.rs b/tests/fail/stacked_borrows/alias_through_mutation.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/alias_through_mutation.rs rename to tests/fail/stacked_borrows/alias_through_mutation.rs diff --git a/tests/compile-fail/stacked_borrows/alias_through_mutation.stderr b/tests/fail/stacked_borrows/alias_through_mutation.stderr similarity index 100% rename from tests/compile-fail/stacked_borrows/alias_through_mutation.stderr rename to tests/fail/stacked_borrows/alias_through_mutation.stderr diff --git a/tests/compile-fail/stacked_borrows/aliasing_mut1.rs b/tests/fail/stacked_borrows/aliasing_mut1.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/aliasing_mut1.rs rename to tests/fail/stacked_borrows/aliasing_mut1.rs diff --git a/tests/compile-fail/stacked_borrows/aliasing_mut1.stderr b/tests/fail/stacked_borrows/aliasing_mut1.stderr similarity index 100% rename from tests/compile-fail/stacked_borrows/aliasing_mut1.stderr rename to tests/fail/stacked_borrows/aliasing_mut1.stderr diff --git a/tests/compile-fail/stacked_borrows/aliasing_mut2.rs b/tests/fail/stacked_borrows/aliasing_mut2.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/aliasing_mut2.rs rename to tests/fail/stacked_borrows/aliasing_mut2.rs diff --git a/tests/compile-fail/stacked_borrows/aliasing_mut2.stderr b/tests/fail/stacked_borrows/aliasing_mut2.stderr similarity index 100% rename from tests/compile-fail/stacked_borrows/aliasing_mut2.stderr rename to tests/fail/stacked_borrows/aliasing_mut2.stderr diff --git a/tests/compile-fail/stacked_borrows/aliasing_mut3.rs b/tests/fail/stacked_borrows/aliasing_mut3.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/aliasing_mut3.rs rename to tests/fail/stacked_borrows/aliasing_mut3.rs diff --git a/tests/compile-fail/stacked_borrows/aliasing_mut3.stderr b/tests/fail/stacked_borrows/aliasing_mut3.stderr similarity index 100% rename from tests/compile-fail/stacked_borrows/aliasing_mut3.stderr rename to tests/fail/stacked_borrows/aliasing_mut3.stderr diff --git a/tests/compile-fail/stacked_borrows/aliasing_mut4.rs b/tests/fail/stacked_borrows/aliasing_mut4.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/aliasing_mut4.rs rename to tests/fail/stacked_borrows/aliasing_mut4.rs diff --git a/tests/compile-fail/stacked_borrows/aliasing_mut4.stderr b/tests/fail/stacked_borrows/aliasing_mut4.stderr similarity index 100% rename from tests/compile-fail/stacked_borrows/aliasing_mut4.stderr rename to tests/fail/stacked_borrows/aliasing_mut4.stderr diff --git a/tests/compile-fail/stacked_borrows/box_exclusive_violation1.rs b/tests/fail/stacked_borrows/box_exclusive_violation1.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/box_exclusive_violation1.rs rename to tests/fail/stacked_borrows/box_exclusive_violation1.rs diff --git a/tests/compile-fail/stacked_borrows/box_exclusive_violation1.stderr b/tests/fail/stacked_borrows/box_exclusive_violation1.stderr similarity index 100% rename from tests/compile-fail/stacked_borrows/box_exclusive_violation1.stderr rename to tests/fail/stacked_borrows/box_exclusive_violation1.stderr diff --git a/tests/compile-fail/stacked_borrows/buggy_as_mut_slice.rs b/tests/fail/stacked_borrows/buggy_as_mut_slice.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/buggy_as_mut_slice.rs rename to tests/fail/stacked_borrows/buggy_as_mut_slice.rs diff --git a/tests/compile-fail/stacked_borrows/buggy_as_mut_slice.stderr b/tests/fail/stacked_borrows/buggy_as_mut_slice.stderr similarity index 100% rename from tests/compile-fail/stacked_borrows/buggy_as_mut_slice.stderr rename to tests/fail/stacked_borrows/buggy_as_mut_slice.stderr diff --git a/tests/compile-fail/stacked_borrows/buggy_split_at_mut.rs b/tests/fail/stacked_borrows/buggy_split_at_mut.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/buggy_split_at_mut.rs rename to tests/fail/stacked_borrows/buggy_split_at_mut.rs diff --git a/tests/compile-fail/stacked_borrows/buggy_split_at_mut.stderr b/tests/fail/stacked_borrows/buggy_split_at_mut.stderr similarity index 100% rename from tests/compile-fail/stacked_borrows/buggy_split_at_mut.stderr rename to tests/fail/stacked_borrows/buggy_split_at_mut.stderr diff --git a/tests/compile-fail/stacked_borrows/deallocate_against_barrier1.rs b/tests/fail/stacked_borrows/deallocate_against_barrier1.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/deallocate_against_barrier1.rs rename to tests/fail/stacked_borrows/deallocate_against_barrier1.rs diff --git a/tests/compile-fail/stacked_borrows/deallocate_against_barrier1.stderr b/tests/fail/stacked_borrows/deallocate_against_barrier1.stderr similarity index 100% rename from tests/compile-fail/stacked_borrows/deallocate_against_barrier1.stderr rename to tests/fail/stacked_borrows/deallocate_against_barrier1.stderr diff --git a/tests/compile-fail/stacked_borrows/deallocate_against_barrier2.rs b/tests/fail/stacked_borrows/deallocate_against_barrier2.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/deallocate_against_barrier2.rs rename to tests/fail/stacked_borrows/deallocate_against_barrier2.rs diff --git a/tests/compile-fail/stacked_borrows/deallocate_against_barrier2.stderr b/tests/fail/stacked_borrows/deallocate_against_barrier2.stderr similarity index 100% rename from tests/compile-fail/stacked_borrows/deallocate_against_barrier2.stderr rename to tests/fail/stacked_borrows/deallocate_against_barrier2.stderr diff --git a/tests/compile-fail/stacked_borrows/illegal_read1.rs b/tests/fail/stacked_borrows/illegal_read1.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/illegal_read1.rs rename to tests/fail/stacked_borrows/illegal_read1.rs diff --git a/tests/compile-fail/stacked_borrows/illegal_read1.stderr b/tests/fail/stacked_borrows/illegal_read1.stderr similarity index 100% rename from tests/compile-fail/stacked_borrows/illegal_read1.stderr rename to tests/fail/stacked_borrows/illegal_read1.stderr diff --git a/tests/compile-fail/stacked_borrows/illegal_read2.rs b/tests/fail/stacked_borrows/illegal_read2.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/illegal_read2.rs rename to tests/fail/stacked_borrows/illegal_read2.rs diff --git a/tests/compile-fail/stacked_borrows/illegal_read2.stderr b/tests/fail/stacked_borrows/illegal_read2.stderr similarity index 100% rename from tests/compile-fail/stacked_borrows/illegal_read2.stderr rename to tests/fail/stacked_borrows/illegal_read2.stderr diff --git a/tests/compile-fail/stacked_borrows/illegal_read3.rs b/tests/fail/stacked_borrows/illegal_read3.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/illegal_read3.rs rename to tests/fail/stacked_borrows/illegal_read3.rs diff --git a/tests/compile-fail/stacked_borrows/illegal_read3.stderr b/tests/fail/stacked_borrows/illegal_read3.stderr similarity index 100% rename from tests/compile-fail/stacked_borrows/illegal_read3.stderr rename to tests/fail/stacked_borrows/illegal_read3.stderr diff --git a/tests/compile-fail/stacked_borrows/illegal_read4.rs b/tests/fail/stacked_borrows/illegal_read4.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/illegal_read4.rs rename to tests/fail/stacked_borrows/illegal_read4.rs diff --git a/tests/compile-fail/stacked_borrows/illegal_read4.stderr b/tests/fail/stacked_borrows/illegal_read4.stderr similarity index 100% rename from tests/compile-fail/stacked_borrows/illegal_read4.stderr rename to tests/fail/stacked_borrows/illegal_read4.stderr diff --git a/tests/compile-fail/stacked_borrows/illegal_read5.rs b/tests/fail/stacked_borrows/illegal_read5.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/illegal_read5.rs rename to tests/fail/stacked_borrows/illegal_read5.rs diff --git a/tests/compile-fail/stacked_borrows/illegal_read5.stderr b/tests/fail/stacked_borrows/illegal_read5.stderr similarity index 100% rename from tests/compile-fail/stacked_borrows/illegal_read5.stderr rename to tests/fail/stacked_borrows/illegal_read5.stderr diff --git a/tests/compile-fail/stacked_borrows/illegal_read6.rs b/tests/fail/stacked_borrows/illegal_read6.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/illegal_read6.rs rename to tests/fail/stacked_borrows/illegal_read6.rs diff --git a/tests/compile-fail/stacked_borrows/illegal_read6.stderr b/tests/fail/stacked_borrows/illegal_read6.stderr similarity index 100% rename from tests/compile-fail/stacked_borrows/illegal_read6.stderr rename to tests/fail/stacked_borrows/illegal_read6.stderr diff --git a/tests/compile-fail/stacked_borrows/illegal_read7.rs b/tests/fail/stacked_borrows/illegal_read7.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/illegal_read7.rs rename to tests/fail/stacked_borrows/illegal_read7.rs diff --git a/tests/compile-fail/stacked_borrows/illegal_read7.stderr b/tests/fail/stacked_borrows/illegal_read7.stderr similarity index 100% rename from tests/compile-fail/stacked_borrows/illegal_read7.stderr rename to tests/fail/stacked_borrows/illegal_read7.stderr diff --git a/tests/compile-fail/stacked_borrows/illegal_read8.rs b/tests/fail/stacked_borrows/illegal_read8.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/illegal_read8.rs rename to tests/fail/stacked_borrows/illegal_read8.rs diff --git a/tests/compile-fail/stacked_borrows/illegal_read8.stderr b/tests/fail/stacked_borrows/illegal_read8.stderr similarity index 100% rename from tests/compile-fail/stacked_borrows/illegal_read8.stderr rename to tests/fail/stacked_borrows/illegal_read8.stderr diff --git a/tests/compile-fail/stacked_borrows/illegal_write1.rs b/tests/fail/stacked_borrows/illegal_write1.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/illegal_write1.rs rename to tests/fail/stacked_borrows/illegal_write1.rs diff --git a/tests/compile-fail/stacked_borrows/illegal_write1.stderr b/tests/fail/stacked_borrows/illegal_write1.stderr similarity index 100% rename from tests/compile-fail/stacked_borrows/illegal_write1.stderr rename to tests/fail/stacked_borrows/illegal_write1.stderr diff --git a/tests/compile-fail/stacked_borrows/illegal_write2.rs b/tests/fail/stacked_borrows/illegal_write2.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/illegal_write2.rs rename to tests/fail/stacked_borrows/illegal_write2.rs diff --git a/tests/compile-fail/stacked_borrows/illegal_write2.stderr b/tests/fail/stacked_borrows/illegal_write2.stderr similarity index 100% rename from tests/compile-fail/stacked_borrows/illegal_write2.stderr rename to tests/fail/stacked_borrows/illegal_write2.stderr diff --git a/tests/compile-fail/stacked_borrows/illegal_write3.rs b/tests/fail/stacked_borrows/illegal_write3.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/illegal_write3.rs rename to tests/fail/stacked_borrows/illegal_write3.rs diff --git a/tests/compile-fail/stacked_borrows/illegal_write3.stderr b/tests/fail/stacked_borrows/illegal_write3.stderr similarity index 100% rename from tests/compile-fail/stacked_borrows/illegal_write3.stderr rename to tests/fail/stacked_borrows/illegal_write3.stderr diff --git a/tests/compile-fail/stacked_borrows/illegal_write4.rs b/tests/fail/stacked_borrows/illegal_write4.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/illegal_write4.rs rename to tests/fail/stacked_borrows/illegal_write4.rs diff --git a/tests/compile-fail/stacked_borrows/illegal_write4.stderr b/tests/fail/stacked_borrows/illegal_write4.stderr similarity index 100% rename from tests/compile-fail/stacked_borrows/illegal_write4.stderr rename to tests/fail/stacked_borrows/illegal_write4.stderr diff --git a/tests/compile-fail/stacked_borrows/illegal_write5.rs b/tests/fail/stacked_borrows/illegal_write5.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/illegal_write5.rs rename to tests/fail/stacked_borrows/illegal_write5.rs diff --git a/tests/compile-fail/stacked_borrows/illegal_write5.stderr b/tests/fail/stacked_borrows/illegal_write5.stderr similarity index 100% rename from tests/compile-fail/stacked_borrows/illegal_write5.stderr rename to tests/fail/stacked_borrows/illegal_write5.stderr diff --git a/tests/compile-fail/stacked_borrows/illegal_write6.rs b/tests/fail/stacked_borrows/illegal_write6.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/illegal_write6.rs rename to tests/fail/stacked_borrows/illegal_write6.rs diff --git a/tests/compile-fail/stacked_borrows/illegal_write6.stderr b/tests/fail/stacked_borrows/illegal_write6.stderr similarity index 100% rename from tests/compile-fail/stacked_borrows/illegal_write6.stderr rename to tests/fail/stacked_borrows/illegal_write6.stderr diff --git a/tests/compile-fail/stacked_borrows/interior_mut1.rs b/tests/fail/stacked_borrows/interior_mut1.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/interior_mut1.rs rename to tests/fail/stacked_borrows/interior_mut1.rs diff --git a/tests/compile-fail/stacked_borrows/interior_mut1.stderr b/tests/fail/stacked_borrows/interior_mut1.stderr similarity index 100% rename from tests/compile-fail/stacked_borrows/interior_mut1.stderr rename to tests/fail/stacked_borrows/interior_mut1.stderr diff --git a/tests/compile-fail/stacked_borrows/interior_mut2.rs b/tests/fail/stacked_borrows/interior_mut2.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/interior_mut2.rs rename to tests/fail/stacked_borrows/interior_mut2.rs diff --git a/tests/compile-fail/stacked_borrows/interior_mut2.stderr b/tests/fail/stacked_borrows/interior_mut2.stderr similarity index 100% rename from tests/compile-fail/stacked_borrows/interior_mut2.stderr rename to tests/fail/stacked_borrows/interior_mut2.stderr diff --git a/tests/compile-fail/stacked_borrows/invalidate_against_barrier1.rs b/tests/fail/stacked_borrows/invalidate_against_barrier1.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/invalidate_against_barrier1.rs rename to tests/fail/stacked_borrows/invalidate_against_barrier1.rs diff --git a/tests/compile-fail/stacked_borrows/invalidate_against_barrier1.stderr b/tests/fail/stacked_borrows/invalidate_against_barrier1.stderr similarity index 100% rename from tests/compile-fail/stacked_borrows/invalidate_against_barrier1.stderr rename to tests/fail/stacked_borrows/invalidate_against_barrier1.stderr diff --git a/tests/compile-fail/stacked_borrows/invalidate_against_barrier2.rs b/tests/fail/stacked_borrows/invalidate_against_barrier2.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/invalidate_against_barrier2.rs rename to tests/fail/stacked_borrows/invalidate_against_barrier2.rs diff --git a/tests/compile-fail/stacked_borrows/invalidate_against_barrier2.stderr b/tests/fail/stacked_borrows/invalidate_against_barrier2.stderr similarity index 100% rename from tests/compile-fail/stacked_borrows/invalidate_against_barrier2.stderr rename to tests/fail/stacked_borrows/invalidate_against_barrier2.stderr diff --git a/tests/compile-fail/stacked_borrows/issue-miri-1050-1.rs b/tests/fail/stacked_borrows/issue-miri-1050-1.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/issue-miri-1050-1.rs rename to tests/fail/stacked_borrows/issue-miri-1050-1.rs diff --git a/tests/compile-fail/stacked_borrows/issue-miri-1050-1.stderr b/tests/fail/stacked_borrows/issue-miri-1050-1.stderr similarity index 100% rename from tests/compile-fail/stacked_borrows/issue-miri-1050-1.stderr rename to tests/fail/stacked_borrows/issue-miri-1050-1.stderr diff --git a/tests/compile-fail/stacked_borrows/issue-miri-1050-2.rs b/tests/fail/stacked_borrows/issue-miri-1050-2.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/issue-miri-1050-2.rs rename to tests/fail/stacked_borrows/issue-miri-1050-2.rs diff --git a/tests/compile-fail/stacked_borrows/issue-miri-1050-2.stderr b/tests/fail/stacked_borrows/issue-miri-1050-2.stderr similarity index 100% rename from tests/compile-fail/stacked_borrows/issue-miri-1050-2.stderr rename to tests/fail/stacked_borrows/issue-miri-1050-2.stderr diff --git a/tests/compile-fail/stacked_borrows/load_invalid_mut.rs b/tests/fail/stacked_borrows/load_invalid_mut.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/load_invalid_mut.rs rename to tests/fail/stacked_borrows/load_invalid_mut.rs diff --git a/tests/compile-fail/stacked_borrows/load_invalid_mut.stderr b/tests/fail/stacked_borrows/load_invalid_mut.stderr similarity index 100% rename from tests/compile-fail/stacked_borrows/load_invalid_mut.stderr rename to tests/fail/stacked_borrows/load_invalid_mut.stderr diff --git a/tests/compile-fail/stacked_borrows/load_invalid_shr.rs b/tests/fail/stacked_borrows/load_invalid_shr.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/load_invalid_shr.rs rename to tests/fail/stacked_borrows/load_invalid_shr.rs diff --git a/tests/compile-fail/stacked_borrows/load_invalid_shr.stderr b/tests/fail/stacked_borrows/load_invalid_shr.stderr similarity index 100% rename from tests/compile-fail/stacked_borrows/load_invalid_shr.stderr rename to tests/fail/stacked_borrows/load_invalid_shr.stderr diff --git a/tests/compile-fail/stacked_borrows/mut_exclusive_violation1.rs b/tests/fail/stacked_borrows/mut_exclusive_violation1.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/mut_exclusive_violation1.rs rename to tests/fail/stacked_borrows/mut_exclusive_violation1.rs diff --git a/tests/compile-fail/stacked_borrows/mut_exclusive_violation1.stderr b/tests/fail/stacked_borrows/mut_exclusive_violation1.stderr similarity index 100% rename from tests/compile-fail/stacked_borrows/mut_exclusive_violation1.stderr rename to tests/fail/stacked_borrows/mut_exclusive_violation1.stderr diff --git a/tests/compile-fail/stacked_borrows/mut_exclusive_violation2.rs b/tests/fail/stacked_borrows/mut_exclusive_violation2.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/mut_exclusive_violation2.rs rename to tests/fail/stacked_borrows/mut_exclusive_violation2.rs diff --git a/tests/compile-fail/stacked_borrows/mut_exclusive_violation2.stderr b/tests/fail/stacked_borrows/mut_exclusive_violation2.stderr similarity index 100% rename from tests/compile-fail/stacked_borrows/mut_exclusive_violation2.stderr rename to tests/fail/stacked_borrows/mut_exclusive_violation2.stderr diff --git a/tests/compile-fail/stacked_borrows/outdated_local.rs b/tests/fail/stacked_borrows/outdated_local.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/outdated_local.rs rename to tests/fail/stacked_borrows/outdated_local.rs diff --git a/tests/compile-fail/stacked_borrows/outdated_local.stderr b/tests/fail/stacked_borrows/outdated_local.stderr similarity index 100% rename from tests/compile-fail/stacked_borrows/outdated_local.stderr rename to tests/fail/stacked_borrows/outdated_local.stderr diff --git a/tests/compile-fail/stacked_borrows/pass_invalid_mut.rs b/tests/fail/stacked_borrows/pass_invalid_mut.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/pass_invalid_mut.rs rename to tests/fail/stacked_borrows/pass_invalid_mut.rs diff --git a/tests/compile-fail/stacked_borrows/pass_invalid_mut.stderr b/tests/fail/stacked_borrows/pass_invalid_mut.stderr similarity index 100% rename from tests/compile-fail/stacked_borrows/pass_invalid_mut.stderr rename to tests/fail/stacked_borrows/pass_invalid_mut.stderr diff --git a/tests/compile-fail/stacked_borrows/pass_invalid_shr.rs b/tests/fail/stacked_borrows/pass_invalid_shr.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/pass_invalid_shr.rs rename to tests/fail/stacked_borrows/pass_invalid_shr.rs diff --git a/tests/compile-fail/stacked_borrows/pass_invalid_shr.stderr b/tests/fail/stacked_borrows/pass_invalid_shr.stderr similarity index 100% rename from tests/compile-fail/stacked_borrows/pass_invalid_shr.stderr rename to tests/fail/stacked_borrows/pass_invalid_shr.stderr diff --git a/tests/compile-fail/stacked_borrows/pointer_smuggling.rs b/tests/fail/stacked_borrows/pointer_smuggling.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/pointer_smuggling.rs rename to tests/fail/stacked_borrows/pointer_smuggling.rs diff --git a/tests/compile-fail/stacked_borrows/pointer_smuggling.stderr b/tests/fail/stacked_borrows/pointer_smuggling.stderr similarity index 100% rename from tests/compile-fail/stacked_borrows/pointer_smuggling.stderr rename to tests/fail/stacked_borrows/pointer_smuggling.stderr diff --git a/tests/compile-fail/stacked_borrows/raw_tracking.rs b/tests/fail/stacked_borrows/raw_tracking.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/raw_tracking.rs rename to tests/fail/stacked_borrows/raw_tracking.rs diff --git a/tests/compile-fail/stacked_borrows/raw_tracking.stderr b/tests/fail/stacked_borrows/raw_tracking.stderr similarity index 100% rename from tests/compile-fail/stacked_borrows/raw_tracking.stderr rename to tests/fail/stacked_borrows/raw_tracking.stderr diff --git a/tests/compile-fail/stacked_borrows/return_invalid_mut.rs b/tests/fail/stacked_borrows/return_invalid_mut.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/return_invalid_mut.rs rename to tests/fail/stacked_borrows/return_invalid_mut.rs diff --git a/tests/compile-fail/stacked_borrows/return_invalid_mut.stderr b/tests/fail/stacked_borrows/return_invalid_mut.stderr similarity index 100% rename from tests/compile-fail/stacked_borrows/return_invalid_mut.stderr rename to tests/fail/stacked_borrows/return_invalid_mut.stderr diff --git a/tests/compile-fail/stacked_borrows/return_invalid_mut_option.rs b/tests/fail/stacked_borrows/return_invalid_mut_option.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/return_invalid_mut_option.rs rename to tests/fail/stacked_borrows/return_invalid_mut_option.rs diff --git a/tests/compile-fail/stacked_borrows/return_invalid_mut_option.stderr b/tests/fail/stacked_borrows/return_invalid_mut_option.stderr similarity index 100% rename from tests/compile-fail/stacked_borrows/return_invalid_mut_option.stderr rename to tests/fail/stacked_borrows/return_invalid_mut_option.stderr diff --git a/tests/compile-fail/stacked_borrows/return_invalid_mut_tuple.rs b/tests/fail/stacked_borrows/return_invalid_mut_tuple.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/return_invalid_mut_tuple.rs rename to tests/fail/stacked_borrows/return_invalid_mut_tuple.rs diff --git a/tests/compile-fail/stacked_borrows/return_invalid_mut_tuple.stderr b/tests/fail/stacked_borrows/return_invalid_mut_tuple.stderr similarity index 100% rename from tests/compile-fail/stacked_borrows/return_invalid_mut_tuple.stderr rename to tests/fail/stacked_borrows/return_invalid_mut_tuple.stderr diff --git a/tests/compile-fail/stacked_borrows/return_invalid_shr.rs b/tests/fail/stacked_borrows/return_invalid_shr.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/return_invalid_shr.rs rename to tests/fail/stacked_borrows/return_invalid_shr.rs diff --git a/tests/compile-fail/stacked_borrows/return_invalid_shr.stderr b/tests/fail/stacked_borrows/return_invalid_shr.stderr similarity index 100% rename from tests/compile-fail/stacked_borrows/return_invalid_shr.stderr rename to tests/fail/stacked_borrows/return_invalid_shr.stderr diff --git a/tests/compile-fail/stacked_borrows/return_invalid_shr_option.rs b/tests/fail/stacked_borrows/return_invalid_shr_option.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/return_invalid_shr_option.rs rename to tests/fail/stacked_borrows/return_invalid_shr_option.rs diff --git a/tests/compile-fail/stacked_borrows/return_invalid_shr_option.stderr b/tests/fail/stacked_borrows/return_invalid_shr_option.stderr similarity index 100% rename from tests/compile-fail/stacked_borrows/return_invalid_shr_option.stderr rename to tests/fail/stacked_borrows/return_invalid_shr_option.stderr diff --git a/tests/compile-fail/stacked_borrows/return_invalid_shr_tuple.rs b/tests/fail/stacked_borrows/return_invalid_shr_tuple.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/return_invalid_shr_tuple.rs rename to tests/fail/stacked_borrows/return_invalid_shr_tuple.rs diff --git a/tests/compile-fail/stacked_borrows/return_invalid_shr_tuple.stderr b/tests/fail/stacked_borrows/return_invalid_shr_tuple.stderr similarity index 100% rename from tests/compile-fail/stacked_borrows/return_invalid_shr_tuple.stderr rename to tests/fail/stacked_borrows/return_invalid_shr_tuple.stderr diff --git a/tests/compile-fail/stacked_borrows/shared_rw_borrows_are_weak1.rs b/tests/fail/stacked_borrows/shared_rw_borrows_are_weak1.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/shared_rw_borrows_are_weak1.rs rename to tests/fail/stacked_borrows/shared_rw_borrows_are_weak1.rs diff --git a/tests/compile-fail/stacked_borrows/shared_rw_borrows_are_weak1.stderr b/tests/fail/stacked_borrows/shared_rw_borrows_are_weak1.stderr similarity index 100% rename from tests/compile-fail/stacked_borrows/shared_rw_borrows_are_weak1.stderr rename to tests/fail/stacked_borrows/shared_rw_borrows_are_weak1.stderr diff --git a/tests/compile-fail/stacked_borrows/shared_rw_borrows_are_weak2.rs b/tests/fail/stacked_borrows/shared_rw_borrows_are_weak2.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/shared_rw_borrows_are_weak2.rs rename to tests/fail/stacked_borrows/shared_rw_borrows_are_weak2.rs diff --git a/tests/compile-fail/stacked_borrows/shared_rw_borrows_are_weak2.stderr b/tests/fail/stacked_borrows/shared_rw_borrows_are_weak2.stderr similarity index 100% rename from tests/compile-fail/stacked_borrows/shared_rw_borrows_are_weak2.stderr rename to tests/fail/stacked_borrows/shared_rw_borrows_are_weak2.stderr diff --git a/tests/compile-fail/stacked_borrows/shr_frozen_violation1.rs b/tests/fail/stacked_borrows/shr_frozen_violation1.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/shr_frozen_violation1.rs rename to tests/fail/stacked_borrows/shr_frozen_violation1.rs diff --git a/tests/compile-fail/stacked_borrows/shr_frozen_violation1.stderr b/tests/fail/stacked_borrows/shr_frozen_violation1.stderr similarity index 100% rename from tests/compile-fail/stacked_borrows/shr_frozen_violation1.stderr rename to tests/fail/stacked_borrows/shr_frozen_violation1.stderr diff --git a/tests/compile-fail/stacked_borrows/static_memory_modification.rs b/tests/fail/stacked_borrows/static_memory_modification.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/static_memory_modification.rs rename to tests/fail/stacked_borrows/static_memory_modification.rs diff --git a/tests/compile-fail/stacked_borrows/static_memory_modification.stderr b/tests/fail/stacked_borrows/static_memory_modification.stderr similarity index 100% rename from tests/compile-fail/stacked_borrows/static_memory_modification.stderr rename to tests/fail/stacked_borrows/static_memory_modification.stderr diff --git a/tests/compile-fail/stacked_borrows/transmute-is-no-escape.rs b/tests/fail/stacked_borrows/transmute-is-no-escape.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/transmute-is-no-escape.rs rename to tests/fail/stacked_borrows/transmute-is-no-escape.rs diff --git a/tests/compile-fail/stacked_borrows/transmute-is-no-escape.stderr b/tests/fail/stacked_borrows/transmute-is-no-escape.stderr similarity index 100% rename from tests/compile-fail/stacked_borrows/transmute-is-no-escape.stderr rename to tests/fail/stacked_borrows/transmute-is-no-escape.stderr diff --git a/tests/compile-fail/stacked_borrows/unescaped_local.rs b/tests/fail/stacked_borrows/unescaped_local.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/unescaped_local.rs rename to tests/fail/stacked_borrows/unescaped_local.rs diff --git a/tests/compile-fail/stacked_borrows/unescaped_local.stderr b/tests/fail/stacked_borrows/unescaped_local.stderr similarity index 100% rename from tests/compile-fail/stacked_borrows/unescaped_local.stderr rename to tests/fail/stacked_borrows/unescaped_local.stderr diff --git a/tests/compile-fail/stacked_borrows/unescaped_static.rs b/tests/fail/stacked_borrows/unescaped_static.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/unescaped_static.rs rename to tests/fail/stacked_borrows/unescaped_static.rs diff --git a/tests/compile-fail/stacked_borrows/unescaped_static.stderr b/tests/fail/stacked_borrows/unescaped_static.stderr similarity index 100% rename from tests/compile-fail/stacked_borrows/unescaped_static.stderr rename to tests/fail/stacked_borrows/unescaped_static.stderr diff --git a/tests/compile-fail/stacked_borrows/zst_slice.rs b/tests/fail/stacked_borrows/zst_slice.rs similarity index 100% rename from tests/compile-fail/stacked_borrows/zst_slice.rs rename to tests/fail/stacked_borrows/zst_slice.rs diff --git a/tests/compile-fail/stacked_borrows/zst_slice.stderr b/tests/fail/stacked_borrows/zst_slice.stderr similarity index 100% rename from tests/compile-fail/stacked_borrows/zst_slice.stderr rename to tests/fail/stacked_borrows/zst_slice.stderr diff --git a/tests/compile-fail/static_memory_modification1.rs b/tests/fail/static_memory_modification1.rs similarity index 100% rename from tests/compile-fail/static_memory_modification1.rs rename to tests/fail/static_memory_modification1.rs diff --git a/tests/compile-fail/static_memory_modification1.stderr b/tests/fail/static_memory_modification1.stderr similarity index 100% rename from tests/compile-fail/static_memory_modification1.stderr rename to tests/fail/static_memory_modification1.stderr diff --git a/tests/compile-fail/static_memory_modification2.rs b/tests/fail/static_memory_modification2.rs similarity index 100% rename from tests/compile-fail/static_memory_modification2.rs rename to tests/fail/static_memory_modification2.rs diff --git a/tests/compile-fail/static_memory_modification2.stderr b/tests/fail/static_memory_modification2.stderr similarity index 100% rename from tests/compile-fail/static_memory_modification2.stderr rename to tests/fail/static_memory_modification2.stderr diff --git a/tests/compile-fail/static_memory_modification3.rs b/tests/fail/static_memory_modification3.rs similarity index 100% rename from tests/compile-fail/static_memory_modification3.rs rename to tests/fail/static_memory_modification3.rs diff --git a/tests/compile-fail/static_memory_modification3.stderr b/tests/fail/static_memory_modification3.stderr similarity index 100% rename from tests/compile-fail/static_memory_modification3.stderr rename to tests/fail/static_memory_modification3.stderr diff --git a/tests/compile-fail/strict-provenance-offset.stderr b/tests/fail/strict-provenance-offset.stderr similarity index 100% rename from tests/compile-fail/strict-provenance-offset.stderr rename to tests/fail/strict-provenance-offset.stderr diff --git a/tests/compile-fail/strict_provenance_transmute.stderr b/tests/fail/strict_provenance_transmute.stderr similarity index 100% rename from tests/compile-fail/strict_provenance_transmute.stderr rename to tests/fail/strict_provenance_transmute.stderr diff --git a/tests/compile-fail/sync/libc_pthread_cond_double_destroy.rs b/tests/fail/sync/libc_pthread_cond_double_destroy.rs similarity index 100% rename from tests/compile-fail/sync/libc_pthread_cond_double_destroy.rs rename to tests/fail/sync/libc_pthread_cond_double_destroy.rs diff --git a/tests/compile-fail/sync/libc_pthread_cond_double_destroy.stderr b/tests/fail/sync/libc_pthread_cond_double_destroy.stderr similarity index 100% rename from tests/compile-fail/sync/libc_pthread_cond_double_destroy.stderr rename to tests/fail/sync/libc_pthread_cond_double_destroy.stderr diff --git a/tests/compile-fail/sync/libc_pthread_condattr_double_destroy.rs b/tests/fail/sync/libc_pthread_condattr_double_destroy.rs similarity index 100% rename from tests/compile-fail/sync/libc_pthread_condattr_double_destroy.rs rename to tests/fail/sync/libc_pthread_condattr_double_destroy.rs diff --git a/tests/compile-fail/sync/libc_pthread_condattr_double_destroy.stderr b/tests/fail/sync/libc_pthread_condattr_double_destroy.stderr similarity index 100% rename from tests/compile-fail/sync/libc_pthread_condattr_double_destroy.stderr rename to tests/fail/sync/libc_pthread_condattr_double_destroy.stderr diff --git a/tests/compile-fail/sync/libc_pthread_mutex_NULL_deadlock.rs b/tests/fail/sync/libc_pthread_mutex_NULL_deadlock.rs similarity index 100% rename from tests/compile-fail/sync/libc_pthread_mutex_NULL_deadlock.rs rename to tests/fail/sync/libc_pthread_mutex_NULL_deadlock.rs diff --git a/tests/compile-fail/sync/libc_pthread_mutex_NULL_deadlock.stderr b/tests/fail/sync/libc_pthread_mutex_NULL_deadlock.stderr similarity index 100% rename from tests/compile-fail/sync/libc_pthread_mutex_NULL_deadlock.stderr rename to tests/fail/sync/libc_pthread_mutex_NULL_deadlock.stderr diff --git a/tests/compile-fail/sync/libc_pthread_mutex_deadlock.rs b/tests/fail/sync/libc_pthread_mutex_deadlock.rs similarity index 100% rename from tests/compile-fail/sync/libc_pthread_mutex_deadlock.rs rename to tests/fail/sync/libc_pthread_mutex_deadlock.rs diff --git a/tests/compile-fail/sync/libc_pthread_mutex_deadlock.stderr b/tests/fail/sync/libc_pthread_mutex_deadlock.stderr similarity index 100% rename from tests/compile-fail/sync/libc_pthread_mutex_deadlock.stderr rename to tests/fail/sync/libc_pthread_mutex_deadlock.stderr diff --git a/tests/compile-fail/sync/libc_pthread_mutex_default_deadlock.rs b/tests/fail/sync/libc_pthread_mutex_default_deadlock.rs similarity index 100% rename from tests/compile-fail/sync/libc_pthread_mutex_default_deadlock.rs rename to tests/fail/sync/libc_pthread_mutex_default_deadlock.rs diff --git a/tests/compile-fail/sync/libc_pthread_mutex_default_deadlock.stderr b/tests/fail/sync/libc_pthread_mutex_default_deadlock.stderr similarity index 100% rename from tests/compile-fail/sync/libc_pthread_mutex_default_deadlock.stderr rename to tests/fail/sync/libc_pthread_mutex_default_deadlock.stderr diff --git a/tests/compile-fail/sync/libc_pthread_mutex_destroy_locked.rs b/tests/fail/sync/libc_pthread_mutex_destroy_locked.rs similarity index 100% rename from tests/compile-fail/sync/libc_pthread_mutex_destroy_locked.rs rename to tests/fail/sync/libc_pthread_mutex_destroy_locked.rs diff --git a/tests/compile-fail/sync/libc_pthread_mutex_destroy_locked.stderr b/tests/fail/sync/libc_pthread_mutex_destroy_locked.stderr similarity index 100% rename from tests/compile-fail/sync/libc_pthread_mutex_destroy_locked.stderr rename to tests/fail/sync/libc_pthread_mutex_destroy_locked.stderr diff --git a/tests/compile-fail/sync/libc_pthread_mutex_double_destroy.rs b/tests/fail/sync/libc_pthread_mutex_double_destroy.rs similarity index 100% rename from tests/compile-fail/sync/libc_pthread_mutex_double_destroy.rs rename to tests/fail/sync/libc_pthread_mutex_double_destroy.rs diff --git a/tests/compile-fail/sync/libc_pthread_mutex_double_destroy.stderr b/tests/fail/sync/libc_pthread_mutex_double_destroy.stderr similarity index 100% rename from tests/compile-fail/sync/libc_pthread_mutex_double_destroy.stderr rename to tests/fail/sync/libc_pthread_mutex_double_destroy.stderr diff --git a/tests/compile-fail/sync/libc_pthread_mutex_normal_deadlock.rs b/tests/fail/sync/libc_pthread_mutex_normal_deadlock.rs similarity index 100% rename from tests/compile-fail/sync/libc_pthread_mutex_normal_deadlock.rs rename to tests/fail/sync/libc_pthread_mutex_normal_deadlock.rs diff --git a/tests/compile-fail/sync/libc_pthread_mutex_normal_deadlock.stderr b/tests/fail/sync/libc_pthread_mutex_normal_deadlock.stderr similarity index 100% rename from tests/compile-fail/sync/libc_pthread_mutex_normal_deadlock.stderr rename to tests/fail/sync/libc_pthread_mutex_normal_deadlock.stderr diff --git a/tests/compile-fail/sync/libc_pthread_mutex_normal_unlock_unlocked.rs b/tests/fail/sync/libc_pthread_mutex_normal_unlock_unlocked.rs similarity index 100% rename from tests/compile-fail/sync/libc_pthread_mutex_normal_unlock_unlocked.rs rename to tests/fail/sync/libc_pthread_mutex_normal_unlock_unlocked.rs diff --git a/tests/compile-fail/sync/libc_pthread_mutex_normal_unlock_unlocked.stderr b/tests/fail/sync/libc_pthread_mutex_normal_unlock_unlocked.stderr similarity index 100% rename from tests/compile-fail/sync/libc_pthread_mutex_normal_unlock_unlocked.stderr rename to tests/fail/sync/libc_pthread_mutex_normal_unlock_unlocked.stderr diff --git a/tests/compile-fail/sync/libc_pthread_mutex_wrong_owner.rs b/tests/fail/sync/libc_pthread_mutex_wrong_owner.rs similarity index 100% rename from tests/compile-fail/sync/libc_pthread_mutex_wrong_owner.rs rename to tests/fail/sync/libc_pthread_mutex_wrong_owner.rs diff --git a/tests/compile-fail/sync/libc_pthread_mutex_wrong_owner.stderr b/tests/fail/sync/libc_pthread_mutex_wrong_owner.stderr similarity index 100% rename from tests/compile-fail/sync/libc_pthread_mutex_wrong_owner.stderr rename to tests/fail/sync/libc_pthread_mutex_wrong_owner.stderr diff --git a/tests/compile-fail/sync/libc_pthread_mutexattr_double_destroy.rs b/tests/fail/sync/libc_pthread_mutexattr_double_destroy.rs similarity index 100% rename from tests/compile-fail/sync/libc_pthread_mutexattr_double_destroy.rs rename to tests/fail/sync/libc_pthread_mutexattr_double_destroy.rs diff --git a/tests/compile-fail/sync/libc_pthread_mutexattr_double_destroy.stderr b/tests/fail/sync/libc_pthread_mutexattr_double_destroy.stderr similarity index 100% rename from tests/compile-fail/sync/libc_pthread_mutexattr_double_destroy.stderr rename to tests/fail/sync/libc_pthread_mutexattr_double_destroy.stderr diff --git a/tests/compile-fail/sync/libc_pthread_rwlock_destroy_read_locked.rs b/tests/fail/sync/libc_pthread_rwlock_destroy_read_locked.rs similarity index 100% rename from tests/compile-fail/sync/libc_pthread_rwlock_destroy_read_locked.rs rename to tests/fail/sync/libc_pthread_rwlock_destroy_read_locked.rs diff --git a/tests/compile-fail/sync/libc_pthread_rwlock_destroy_read_locked.stderr b/tests/fail/sync/libc_pthread_rwlock_destroy_read_locked.stderr similarity index 100% rename from tests/compile-fail/sync/libc_pthread_rwlock_destroy_read_locked.stderr rename to tests/fail/sync/libc_pthread_rwlock_destroy_read_locked.stderr diff --git a/tests/compile-fail/sync/libc_pthread_rwlock_destroy_write_locked.rs b/tests/fail/sync/libc_pthread_rwlock_destroy_write_locked.rs similarity index 100% rename from tests/compile-fail/sync/libc_pthread_rwlock_destroy_write_locked.rs rename to tests/fail/sync/libc_pthread_rwlock_destroy_write_locked.rs diff --git a/tests/compile-fail/sync/libc_pthread_rwlock_destroy_write_locked.stderr b/tests/fail/sync/libc_pthread_rwlock_destroy_write_locked.stderr similarity index 100% rename from tests/compile-fail/sync/libc_pthread_rwlock_destroy_write_locked.stderr rename to tests/fail/sync/libc_pthread_rwlock_destroy_write_locked.stderr diff --git a/tests/compile-fail/sync/libc_pthread_rwlock_double_destroy.rs b/tests/fail/sync/libc_pthread_rwlock_double_destroy.rs similarity index 100% rename from tests/compile-fail/sync/libc_pthread_rwlock_double_destroy.rs rename to tests/fail/sync/libc_pthread_rwlock_double_destroy.rs diff --git a/tests/compile-fail/sync/libc_pthread_rwlock_double_destroy.stderr b/tests/fail/sync/libc_pthread_rwlock_double_destroy.stderr similarity index 100% rename from tests/compile-fail/sync/libc_pthread_rwlock_double_destroy.stderr rename to tests/fail/sync/libc_pthread_rwlock_double_destroy.stderr diff --git a/tests/compile-fail/sync/libc_pthread_rwlock_read_write_deadlock_single_thread.rs b/tests/fail/sync/libc_pthread_rwlock_read_write_deadlock_single_thread.rs similarity index 100% rename from tests/compile-fail/sync/libc_pthread_rwlock_read_write_deadlock_single_thread.rs rename to tests/fail/sync/libc_pthread_rwlock_read_write_deadlock_single_thread.rs diff --git a/tests/compile-fail/sync/libc_pthread_rwlock_read_write_deadlock_single_thread.stderr b/tests/fail/sync/libc_pthread_rwlock_read_write_deadlock_single_thread.stderr similarity index 100% rename from tests/compile-fail/sync/libc_pthread_rwlock_read_write_deadlock_single_thread.stderr rename to tests/fail/sync/libc_pthread_rwlock_read_write_deadlock_single_thread.stderr diff --git a/tests/compile-fail/sync/libc_pthread_rwlock_read_wrong_owner.rs b/tests/fail/sync/libc_pthread_rwlock_read_wrong_owner.rs similarity index 100% rename from tests/compile-fail/sync/libc_pthread_rwlock_read_wrong_owner.rs rename to tests/fail/sync/libc_pthread_rwlock_read_wrong_owner.rs diff --git a/tests/compile-fail/sync/libc_pthread_rwlock_read_wrong_owner.stderr b/tests/fail/sync/libc_pthread_rwlock_read_wrong_owner.stderr similarity index 100% rename from tests/compile-fail/sync/libc_pthread_rwlock_read_wrong_owner.stderr rename to tests/fail/sync/libc_pthread_rwlock_read_wrong_owner.stderr diff --git a/tests/compile-fail/sync/libc_pthread_rwlock_unlock_unlocked.rs b/tests/fail/sync/libc_pthread_rwlock_unlock_unlocked.rs similarity index 100% rename from tests/compile-fail/sync/libc_pthread_rwlock_unlock_unlocked.rs rename to tests/fail/sync/libc_pthread_rwlock_unlock_unlocked.rs diff --git a/tests/compile-fail/sync/libc_pthread_rwlock_unlock_unlocked.stderr b/tests/fail/sync/libc_pthread_rwlock_unlock_unlocked.stderr similarity index 100% rename from tests/compile-fail/sync/libc_pthread_rwlock_unlock_unlocked.stderr rename to tests/fail/sync/libc_pthread_rwlock_unlock_unlocked.stderr diff --git a/tests/compile-fail/sync/libc_pthread_rwlock_write_read_deadlock.rs b/tests/fail/sync/libc_pthread_rwlock_write_read_deadlock.rs similarity index 100% rename from tests/compile-fail/sync/libc_pthread_rwlock_write_read_deadlock.rs rename to tests/fail/sync/libc_pthread_rwlock_write_read_deadlock.rs diff --git a/tests/compile-fail/sync/libc_pthread_rwlock_write_read_deadlock.stderr b/tests/fail/sync/libc_pthread_rwlock_write_read_deadlock.stderr similarity index 100% rename from tests/compile-fail/sync/libc_pthread_rwlock_write_read_deadlock.stderr rename to tests/fail/sync/libc_pthread_rwlock_write_read_deadlock.stderr diff --git a/tests/compile-fail/sync/libc_pthread_rwlock_write_read_deadlock_single_thread.rs b/tests/fail/sync/libc_pthread_rwlock_write_read_deadlock_single_thread.rs similarity index 100% rename from tests/compile-fail/sync/libc_pthread_rwlock_write_read_deadlock_single_thread.rs rename to tests/fail/sync/libc_pthread_rwlock_write_read_deadlock_single_thread.rs diff --git a/tests/compile-fail/sync/libc_pthread_rwlock_write_read_deadlock_single_thread.stderr b/tests/fail/sync/libc_pthread_rwlock_write_read_deadlock_single_thread.stderr similarity index 100% rename from tests/compile-fail/sync/libc_pthread_rwlock_write_read_deadlock_single_thread.stderr rename to tests/fail/sync/libc_pthread_rwlock_write_read_deadlock_single_thread.stderr diff --git a/tests/compile-fail/sync/libc_pthread_rwlock_write_write_deadlock.rs b/tests/fail/sync/libc_pthread_rwlock_write_write_deadlock.rs similarity index 100% rename from tests/compile-fail/sync/libc_pthread_rwlock_write_write_deadlock.rs rename to tests/fail/sync/libc_pthread_rwlock_write_write_deadlock.rs diff --git a/tests/compile-fail/sync/libc_pthread_rwlock_write_write_deadlock.stderr b/tests/fail/sync/libc_pthread_rwlock_write_write_deadlock.stderr similarity index 100% rename from tests/compile-fail/sync/libc_pthread_rwlock_write_write_deadlock.stderr rename to tests/fail/sync/libc_pthread_rwlock_write_write_deadlock.stderr diff --git a/tests/compile-fail/sync/libc_pthread_rwlock_write_write_deadlock_single_thread.rs b/tests/fail/sync/libc_pthread_rwlock_write_write_deadlock_single_thread.rs similarity index 100% rename from tests/compile-fail/sync/libc_pthread_rwlock_write_write_deadlock_single_thread.rs rename to tests/fail/sync/libc_pthread_rwlock_write_write_deadlock_single_thread.rs diff --git a/tests/compile-fail/sync/libc_pthread_rwlock_write_write_deadlock_single_thread.stderr b/tests/fail/sync/libc_pthread_rwlock_write_write_deadlock_single_thread.stderr similarity index 100% rename from tests/compile-fail/sync/libc_pthread_rwlock_write_write_deadlock_single_thread.stderr rename to tests/fail/sync/libc_pthread_rwlock_write_write_deadlock_single_thread.stderr diff --git a/tests/compile-fail/sync/libc_pthread_rwlock_write_wrong_owner.rs b/tests/fail/sync/libc_pthread_rwlock_write_wrong_owner.rs similarity index 100% rename from tests/compile-fail/sync/libc_pthread_rwlock_write_wrong_owner.rs rename to tests/fail/sync/libc_pthread_rwlock_write_wrong_owner.rs diff --git a/tests/compile-fail/sync/libc_pthread_rwlock_write_wrong_owner.stderr b/tests/fail/sync/libc_pthread_rwlock_write_wrong_owner.stderr similarity index 100% rename from tests/compile-fail/sync/libc_pthread_rwlock_write_wrong_owner.stderr rename to tests/fail/sync/libc_pthread_rwlock_write_wrong_owner.stderr diff --git a/tests/compile-fail/too-big-slice.stderr b/tests/fail/too-big-slice.stderr similarity index 100% rename from tests/compile-fail/too-big-slice.stderr rename to tests/fail/too-big-slice.stderr diff --git a/tests/compile-fail/too-big-unsized.stderr b/tests/fail/too-big-unsized.stderr similarity index 100% rename from tests/compile-fail/too-big-unsized.stderr rename to tests/fail/too-big-unsized.stderr diff --git a/tests/compile-fail/transmute-pair-uninit.rs b/tests/fail/transmute-pair-uninit.rs similarity index 100% rename from tests/compile-fail/transmute-pair-uninit.rs rename to tests/fail/transmute-pair-uninit.rs diff --git a/tests/compile-fail/transmute-pair-uninit.stderr b/tests/fail/transmute-pair-uninit.stderr similarity index 100% rename from tests/compile-fail/transmute-pair-uninit.stderr rename to tests/fail/transmute-pair-uninit.stderr diff --git a/tests/compile-fail/transmute_fat1.rs b/tests/fail/transmute_fat1.rs similarity index 100% rename from tests/compile-fail/transmute_fat1.rs rename to tests/fail/transmute_fat1.rs diff --git a/tests/compile-fail/transmute_fat1.stderr b/tests/fail/transmute_fat1.stderr similarity index 100% rename from tests/compile-fail/transmute_fat1.stderr rename to tests/fail/transmute_fat1.stderr diff --git a/tests/compile-fail/type-too-large.rs b/tests/fail/type-too-large.rs similarity index 100% rename from tests/compile-fail/type-too-large.rs rename to tests/fail/type-too-large.rs diff --git a/tests/compile-fail/type-too-large.stderr b/tests/fail/type-too-large.stderr similarity index 100% rename from tests/compile-fail/type-too-large.stderr rename to tests/fail/type-too-large.stderr diff --git a/tests/compile-fail/unaligned_pointers/alignment.rs b/tests/fail/unaligned_pointers/alignment.rs similarity index 100% rename from tests/compile-fail/unaligned_pointers/alignment.rs rename to tests/fail/unaligned_pointers/alignment.rs diff --git a/tests/compile-fail/unaligned_pointers/alignment.stderr b/tests/fail/unaligned_pointers/alignment.stderr similarity index 100% rename from tests/compile-fail/unaligned_pointers/alignment.stderr rename to tests/fail/unaligned_pointers/alignment.stderr diff --git a/tests/compile-fail/unaligned_pointers/atomic_unaligned.rs b/tests/fail/unaligned_pointers/atomic_unaligned.rs similarity index 100% rename from tests/compile-fail/unaligned_pointers/atomic_unaligned.rs rename to tests/fail/unaligned_pointers/atomic_unaligned.rs diff --git a/tests/compile-fail/unaligned_pointers/atomic_unaligned.stderr b/tests/fail/unaligned_pointers/atomic_unaligned.stderr similarity index 100% rename from tests/compile-fail/unaligned_pointers/atomic_unaligned.stderr rename to tests/fail/unaligned_pointers/atomic_unaligned.stderr diff --git a/tests/compile-fail/unaligned_pointers/dyn_alignment.rs b/tests/fail/unaligned_pointers/dyn_alignment.rs similarity index 100% rename from tests/compile-fail/unaligned_pointers/dyn_alignment.rs rename to tests/fail/unaligned_pointers/dyn_alignment.rs diff --git a/tests/compile-fail/unaligned_pointers/dyn_alignment.stderr b/tests/fail/unaligned_pointers/dyn_alignment.stderr similarity index 100% rename from tests/compile-fail/unaligned_pointers/dyn_alignment.stderr rename to tests/fail/unaligned_pointers/dyn_alignment.stderr diff --git a/tests/compile-fail/unaligned_pointers/intptrcast_alignment_check.rs b/tests/fail/unaligned_pointers/intptrcast_alignment_check.rs similarity index 100% rename from tests/compile-fail/unaligned_pointers/intptrcast_alignment_check.rs rename to tests/fail/unaligned_pointers/intptrcast_alignment_check.rs diff --git a/tests/compile-fail/unaligned_pointers/intptrcast_alignment_check.stderr b/tests/fail/unaligned_pointers/intptrcast_alignment_check.stderr similarity index 100% rename from tests/compile-fail/unaligned_pointers/intptrcast_alignment_check.stderr rename to tests/fail/unaligned_pointers/intptrcast_alignment_check.stderr diff --git a/tests/compile-fail/unaligned_pointers/reference_to_packed.rs b/tests/fail/unaligned_pointers/reference_to_packed.rs similarity index 100% rename from tests/compile-fail/unaligned_pointers/reference_to_packed.rs rename to tests/fail/unaligned_pointers/reference_to_packed.rs diff --git a/tests/compile-fail/unaligned_pointers/reference_to_packed.stderr b/tests/fail/unaligned_pointers/reference_to_packed.stderr similarity index 100% rename from tests/compile-fail/unaligned_pointers/reference_to_packed.stderr rename to tests/fail/unaligned_pointers/reference_to_packed.stderr diff --git a/tests/compile-fail/unaligned_pointers/unaligned_ptr1.rs b/tests/fail/unaligned_pointers/unaligned_ptr1.rs similarity index 100% rename from tests/compile-fail/unaligned_pointers/unaligned_ptr1.rs rename to tests/fail/unaligned_pointers/unaligned_ptr1.rs diff --git a/tests/compile-fail/unaligned_pointers/unaligned_ptr1.stderr b/tests/fail/unaligned_pointers/unaligned_ptr1.stderr similarity index 100% rename from tests/compile-fail/unaligned_pointers/unaligned_ptr1.stderr rename to tests/fail/unaligned_pointers/unaligned_ptr1.stderr diff --git a/tests/compile-fail/unaligned_pointers/unaligned_ptr2.rs b/tests/fail/unaligned_pointers/unaligned_ptr2.rs similarity index 100% rename from tests/compile-fail/unaligned_pointers/unaligned_ptr2.rs rename to tests/fail/unaligned_pointers/unaligned_ptr2.rs diff --git a/tests/compile-fail/unaligned_pointers/unaligned_ptr2.stderr b/tests/fail/unaligned_pointers/unaligned_ptr2.stderr similarity index 100% rename from tests/compile-fail/unaligned_pointers/unaligned_ptr2.stderr rename to tests/fail/unaligned_pointers/unaligned_ptr2.stderr diff --git a/tests/compile-fail/unaligned_pointers/unaligned_ptr3.rs b/tests/fail/unaligned_pointers/unaligned_ptr3.rs similarity index 100% rename from tests/compile-fail/unaligned_pointers/unaligned_ptr3.rs rename to tests/fail/unaligned_pointers/unaligned_ptr3.rs diff --git a/tests/compile-fail/unaligned_pointers/unaligned_ptr3.stderr b/tests/fail/unaligned_pointers/unaligned_ptr3.stderr similarity index 100% rename from tests/compile-fail/unaligned_pointers/unaligned_ptr3.stderr rename to tests/fail/unaligned_pointers/unaligned_ptr3.stderr diff --git a/tests/compile-fail/unaligned_pointers/unaligned_ptr4.rs b/tests/fail/unaligned_pointers/unaligned_ptr4.rs similarity index 100% rename from tests/compile-fail/unaligned_pointers/unaligned_ptr4.rs rename to tests/fail/unaligned_pointers/unaligned_ptr4.rs diff --git a/tests/compile-fail/unaligned_pointers/unaligned_ptr4.stderr b/tests/fail/unaligned_pointers/unaligned_ptr4.stderr similarity index 100% rename from tests/compile-fail/unaligned_pointers/unaligned_ptr4.stderr rename to tests/fail/unaligned_pointers/unaligned_ptr4.stderr diff --git a/tests/compile-fail/unaligned_pointers/unaligned_ptr_addr_of.rs b/tests/fail/unaligned_pointers/unaligned_ptr_addr_of.rs similarity index 100% rename from tests/compile-fail/unaligned_pointers/unaligned_ptr_addr_of.rs rename to tests/fail/unaligned_pointers/unaligned_ptr_addr_of.rs diff --git a/tests/compile-fail/unaligned_pointers/unaligned_ptr_addr_of.stderr b/tests/fail/unaligned_pointers/unaligned_ptr_addr_of.stderr similarity index 100% rename from tests/compile-fail/unaligned_pointers/unaligned_ptr_addr_of.stderr rename to tests/fail/unaligned_pointers/unaligned_ptr_addr_of.stderr diff --git a/tests/compile-fail/unaligned_pointers/unaligned_ptr_zst.rs b/tests/fail/unaligned_pointers/unaligned_ptr_zst.rs similarity index 100% rename from tests/compile-fail/unaligned_pointers/unaligned_ptr_zst.rs rename to tests/fail/unaligned_pointers/unaligned_ptr_zst.rs diff --git a/tests/compile-fail/unaligned_pointers/unaligned_ptr_zst.stderr b/tests/fail/unaligned_pointers/unaligned_ptr_zst.stderr similarity index 100% rename from tests/compile-fail/unaligned_pointers/unaligned_ptr_zst.stderr rename to tests/fail/unaligned_pointers/unaligned_ptr_zst.stderr diff --git a/tests/compile-fail/uninit_buffer.rs b/tests/fail/uninit_buffer.rs similarity index 100% rename from tests/compile-fail/uninit_buffer.rs rename to tests/fail/uninit_buffer.rs diff --git a/tests/compile-fail/uninit_buffer.stderr b/tests/fail/uninit_buffer.stderr similarity index 100% rename from tests/compile-fail/uninit_buffer.stderr rename to tests/fail/uninit_buffer.stderr diff --git a/tests/compile-fail/uninit_byte_read.rs b/tests/fail/uninit_byte_read.rs similarity index 100% rename from tests/compile-fail/uninit_byte_read.rs rename to tests/fail/uninit_byte_read.rs diff --git a/tests/compile-fail/uninit_byte_read.stderr b/tests/fail/uninit_byte_read.stderr similarity index 100% rename from tests/compile-fail/uninit_byte_read.stderr rename to tests/fail/uninit_byte_read.stderr diff --git a/tests/compile-fail/uninit_float.stderr b/tests/fail/uninit_float.stderr similarity index 100% rename from tests/compile-fail/uninit_float.stderr rename to tests/fail/uninit_float.stderr diff --git a/tests/compile-fail/uninit_integer.stderr b/tests/fail/uninit_integer.stderr similarity index 100% rename from tests/compile-fail/uninit_integer.stderr rename to tests/fail/uninit_integer.stderr diff --git a/tests/compile-fail/uninit_integer_signed.stderr b/tests/fail/uninit_integer_signed.stderr similarity index 100% rename from tests/compile-fail/uninit_integer_signed.stderr rename to tests/fail/uninit_integer_signed.stderr diff --git a/tests/compile-fail/uninit_raw_ptr.rs b/tests/fail/uninit_raw_ptr.rs similarity index 100% rename from tests/compile-fail/uninit_raw_ptr.rs rename to tests/fail/uninit_raw_ptr.rs diff --git a/tests/compile-fail/uninit_raw_ptr.stderr b/tests/fail/uninit_raw_ptr.stderr similarity index 100% rename from tests/compile-fail/uninit_raw_ptr.stderr rename to tests/fail/uninit_raw_ptr.stderr diff --git a/tests/compile-fail/unreachable.rs b/tests/fail/unreachable.rs similarity index 100% rename from tests/compile-fail/unreachable.rs rename to tests/fail/unreachable.rs diff --git a/tests/compile-fail/unreachable.stderr b/tests/fail/unreachable.stderr similarity index 100% rename from tests/compile-fail/unreachable.stderr rename to tests/fail/unreachable.stderr diff --git a/tests/compile-fail/unsupported_foreign_function.rs b/tests/fail/unsupported_foreign_function.rs similarity index 100% rename from tests/compile-fail/unsupported_foreign_function.rs rename to tests/fail/unsupported_foreign_function.rs diff --git a/tests/compile-fail/unsupported_foreign_function.stderr b/tests/fail/unsupported_foreign_function.stderr similarity index 100% rename from tests/compile-fail/unsupported_foreign_function.stderr rename to tests/fail/unsupported_foreign_function.stderr diff --git a/tests/compile-fail/unsupported_signal.rs b/tests/fail/unsupported_signal.rs similarity index 100% rename from tests/compile-fail/unsupported_signal.rs rename to tests/fail/unsupported_signal.rs diff --git a/tests/compile-fail/unsupported_signal.stderr b/tests/fail/unsupported_signal.stderr similarity index 100% rename from tests/compile-fail/unsupported_signal.stderr rename to tests/fail/unsupported_signal.stderr diff --git a/tests/compile-fail/validity/cast_fn_ptr1.rs b/tests/fail/validity/cast_fn_ptr1.rs similarity index 100% rename from tests/compile-fail/validity/cast_fn_ptr1.rs rename to tests/fail/validity/cast_fn_ptr1.rs diff --git a/tests/compile-fail/validity/cast_fn_ptr1.stderr b/tests/fail/validity/cast_fn_ptr1.stderr similarity index 100% rename from tests/compile-fail/validity/cast_fn_ptr1.stderr rename to tests/fail/validity/cast_fn_ptr1.stderr diff --git a/tests/compile-fail/validity/cast_fn_ptr2.rs b/tests/fail/validity/cast_fn_ptr2.rs similarity index 100% rename from tests/compile-fail/validity/cast_fn_ptr2.rs rename to tests/fail/validity/cast_fn_ptr2.rs diff --git a/tests/compile-fail/validity/cast_fn_ptr2.stderr b/tests/fail/validity/cast_fn_ptr2.stderr similarity index 100% rename from tests/compile-fail/validity/cast_fn_ptr2.stderr rename to tests/fail/validity/cast_fn_ptr2.stderr diff --git a/tests/compile-fail/validity/dangling_ref1.rs b/tests/fail/validity/dangling_ref1.rs similarity index 100% rename from tests/compile-fail/validity/dangling_ref1.rs rename to tests/fail/validity/dangling_ref1.rs diff --git a/tests/compile-fail/validity/dangling_ref1.stderr b/tests/fail/validity/dangling_ref1.stderr similarity index 100% rename from tests/compile-fail/validity/dangling_ref1.stderr rename to tests/fail/validity/dangling_ref1.stderr diff --git a/tests/compile-fail/validity/dangling_ref2.rs b/tests/fail/validity/dangling_ref2.rs similarity index 100% rename from tests/compile-fail/validity/dangling_ref2.rs rename to tests/fail/validity/dangling_ref2.rs diff --git a/tests/compile-fail/validity/dangling_ref2.stderr b/tests/fail/validity/dangling_ref2.stderr similarity index 100% rename from tests/compile-fail/validity/dangling_ref2.stderr rename to tests/fail/validity/dangling_ref2.stderr diff --git a/tests/compile-fail/validity/dangling_ref3.rs b/tests/fail/validity/dangling_ref3.rs similarity index 100% rename from tests/compile-fail/validity/dangling_ref3.rs rename to tests/fail/validity/dangling_ref3.rs diff --git a/tests/compile-fail/validity/dangling_ref3.stderr b/tests/fail/validity/dangling_ref3.stderr similarity index 100% rename from tests/compile-fail/validity/dangling_ref3.stderr rename to tests/fail/validity/dangling_ref3.stderr diff --git a/tests/compile-fail/validity/invalid_bool.rs b/tests/fail/validity/invalid_bool.rs similarity index 100% rename from tests/compile-fail/validity/invalid_bool.rs rename to tests/fail/validity/invalid_bool.rs diff --git a/tests/compile-fail/validity/invalid_bool.stderr b/tests/fail/validity/invalid_bool.stderr similarity index 100% rename from tests/compile-fail/validity/invalid_bool.stderr rename to tests/fail/validity/invalid_bool.stderr diff --git a/tests/compile-fail/validity/invalid_bool_uninit.rs b/tests/fail/validity/invalid_bool_uninit.rs similarity index 100% rename from tests/compile-fail/validity/invalid_bool_uninit.rs rename to tests/fail/validity/invalid_bool_uninit.rs diff --git a/tests/compile-fail/validity/invalid_bool_uninit.stderr b/tests/fail/validity/invalid_bool_uninit.stderr similarity index 100% rename from tests/compile-fail/validity/invalid_bool_uninit.stderr rename to tests/fail/validity/invalid_bool_uninit.stderr diff --git a/tests/compile-fail/validity/invalid_char.rs b/tests/fail/validity/invalid_char.rs similarity index 100% rename from tests/compile-fail/validity/invalid_char.rs rename to tests/fail/validity/invalid_char.rs diff --git a/tests/compile-fail/validity/invalid_char.stderr b/tests/fail/validity/invalid_char.stderr similarity index 100% rename from tests/compile-fail/validity/invalid_char.stderr rename to tests/fail/validity/invalid_char.stderr diff --git a/tests/compile-fail/validity/invalid_char_uninit.rs b/tests/fail/validity/invalid_char_uninit.rs similarity index 100% rename from tests/compile-fail/validity/invalid_char_uninit.rs rename to tests/fail/validity/invalid_char_uninit.rs diff --git a/tests/compile-fail/validity/invalid_char_uninit.stderr b/tests/fail/validity/invalid_char_uninit.stderr similarity index 100% rename from tests/compile-fail/validity/invalid_char_uninit.stderr rename to tests/fail/validity/invalid_char_uninit.stderr diff --git a/tests/compile-fail/validity/invalid_enum_tag.rs b/tests/fail/validity/invalid_enum_tag.rs similarity index 100% rename from tests/compile-fail/validity/invalid_enum_tag.rs rename to tests/fail/validity/invalid_enum_tag.rs diff --git a/tests/compile-fail/validity/invalid_enum_tag.stderr b/tests/fail/validity/invalid_enum_tag.stderr similarity index 100% rename from tests/compile-fail/validity/invalid_enum_tag.stderr rename to tests/fail/validity/invalid_enum_tag.stderr diff --git a/tests/compile-fail/validity/invalid_enum_tag_256variants_uninit.rs b/tests/fail/validity/invalid_enum_tag_256variants_uninit.rs similarity index 100% rename from tests/compile-fail/validity/invalid_enum_tag_256variants_uninit.rs rename to tests/fail/validity/invalid_enum_tag_256variants_uninit.rs diff --git a/tests/compile-fail/validity/invalid_enum_tag_256variants_uninit.stderr b/tests/fail/validity/invalid_enum_tag_256variants_uninit.stderr similarity index 100% rename from tests/compile-fail/validity/invalid_enum_tag_256variants_uninit.stderr rename to tests/fail/validity/invalid_enum_tag_256variants_uninit.stderr diff --git a/tests/compile-fail/validity/invalid_fnptr_null.rs b/tests/fail/validity/invalid_fnptr_null.rs similarity index 100% rename from tests/compile-fail/validity/invalid_fnptr_null.rs rename to tests/fail/validity/invalid_fnptr_null.rs diff --git a/tests/compile-fail/validity/invalid_fnptr_null.stderr b/tests/fail/validity/invalid_fnptr_null.stderr similarity index 100% rename from tests/compile-fail/validity/invalid_fnptr_null.stderr rename to tests/fail/validity/invalid_fnptr_null.stderr diff --git a/tests/compile-fail/validity/invalid_fnptr_uninit.rs b/tests/fail/validity/invalid_fnptr_uninit.rs similarity index 100% rename from tests/compile-fail/validity/invalid_fnptr_uninit.rs rename to tests/fail/validity/invalid_fnptr_uninit.rs diff --git a/tests/compile-fail/validity/invalid_fnptr_uninit.stderr b/tests/fail/validity/invalid_fnptr_uninit.stderr similarity index 100% rename from tests/compile-fail/validity/invalid_fnptr_uninit.stderr rename to tests/fail/validity/invalid_fnptr_uninit.stderr diff --git a/tests/compile-fail/validity/invalid_wide_raw.rs b/tests/fail/validity/invalid_wide_raw.rs similarity index 100% rename from tests/compile-fail/validity/invalid_wide_raw.rs rename to tests/fail/validity/invalid_wide_raw.rs diff --git a/tests/compile-fail/validity/invalid_wide_raw.stderr b/tests/fail/validity/invalid_wide_raw.stderr similarity index 100% rename from tests/compile-fail/validity/invalid_wide_raw.stderr rename to tests/fail/validity/invalid_wide_raw.stderr diff --git a/tests/compile-fail/validity/nonzero.rs b/tests/fail/validity/nonzero.rs similarity index 100% rename from tests/compile-fail/validity/nonzero.rs rename to tests/fail/validity/nonzero.rs diff --git a/tests/compile-fail/validity/nonzero.stderr b/tests/fail/validity/nonzero.stderr similarity index 100% rename from tests/compile-fail/validity/nonzero.stderr rename to tests/fail/validity/nonzero.stderr diff --git a/tests/compile-fail/validity/ptr_integer_array_transmute.rs b/tests/fail/validity/ptr_integer_array_transmute.rs similarity index 100% rename from tests/compile-fail/validity/ptr_integer_array_transmute.rs rename to tests/fail/validity/ptr_integer_array_transmute.rs diff --git a/tests/compile-fail/validity/ptr_integer_array_transmute.stderr b/tests/fail/validity/ptr_integer_array_transmute.stderr similarity index 100% rename from tests/compile-fail/validity/ptr_integer_array_transmute.stderr rename to tests/fail/validity/ptr_integer_array_transmute.stderr diff --git a/tests/compile-fail/validity/ptr_integer_transmute.rs b/tests/fail/validity/ptr_integer_transmute.rs similarity index 100% rename from tests/compile-fail/validity/ptr_integer_transmute.rs rename to tests/fail/validity/ptr_integer_transmute.rs diff --git a/tests/compile-fail/validity/ptr_integer_transmute.stderr b/tests/fail/validity/ptr_integer_transmute.stderr similarity index 100% rename from tests/compile-fail/validity/ptr_integer_transmute.stderr rename to tests/fail/validity/ptr_integer_transmute.stderr diff --git a/tests/compile-fail/validity/ref_to_uninhabited1.rs b/tests/fail/validity/ref_to_uninhabited1.rs similarity index 100% rename from tests/compile-fail/validity/ref_to_uninhabited1.rs rename to tests/fail/validity/ref_to_uninhabited1.rs diff --git a/tests/compile-fail/validity/ref_to_uninhabited1.stderr b/tests/fail/validity/ref_to_uninhabited1.stderr similarity index 100% rename from tests/compile-fail/validity/ref_to_uninhabited1.stderr rename to tests/fail/validity/ref_to_uninhabited1.stderr diff --git a/tests/compile-fail/validity/ref_to_uninhabited2.rs b/tests/fail/validity/ref_to_uninhabited2.rs similarity index 100% rename from tests/compile-fail/validity/ref_to_uninhabited2.rs rename to tests/fail/validity/ref_to_uninhabited2.rs diff --git a/tests/compile-fail/validity/ref_to_uninhabited2.stderr b/tests/fail/validity/ref_to_uninhabited2.stderr similarity index 100% rename from tests/compile-fail/validity/ref_to_uninhabited2.stderr rename to tests/fail/validity/ref_to_uninhabited2.stderr diff --git a/tests/compile-fail/validity/too-big-slice.rs b/tests/fail/validity/too-big-slice.rs similarity index 100% rename from tests/compile-fail/validity/too-big-slice.rs rename to tests/fail/validity/too-big-slice.rs diff --git a/tests/compile-fail/validity/too-big-slice.stderr b/tests/fail/validity/too-big-slice.stderr similarity index 100% rename from tests/compile-fail/validity/too-big-slice.stderr rename to tests/fail/validity/too-big-slice.stderr diff --git a/tests/compile-fail/validity/too-big-unsized.rs b/tests/fail/validity/too-big-unsized.rs similarity index 100% rename from tests/compile-fail/validity/too-big-unsized.rs rename to tests/fail/validity/too-big-unsized.rs diff --git a/tests/compile-fail/validity/too-big-unsized.stderr b/tests/fail/validity/too-big-unsized.stderr similarity index 100% rename from tests/compile-fail/validity/too-big-unsized.stderr rename to tests/fail/validity/too-big-unsized.stderr diff --git a/tests/compile-fail/validity/transmute_through_ptr.rs b/tests/fail/validity/transmute_through_ptr.rs similarity index 100% rename from tests/compile-fail/validity/transmute_through_ptr.rs rename to tests/fail/validity/transmute_through_ptr.rs diff --git a/tests/compile-fail/validity/transmute_through_ptr.stderr b/tests/fail/validity/transmute_through_ptr.stderr similarity index 100% rename from tests/compile-fail/validity/transmute_through_ptr.stderr rename to tests/fail/validity/transmute_through_ptr.stderr diff --git a/tests/compile-fail/validity/uninit_float.rs b/tests/fail/validity/uninit_float.rs similarity index 100% rename from tests/compile-fail/validity/uninit_float.rs rename to tests/fail/validity/uninit_float.rs diff --git a/tests/compile-fail/validity/uninit_float.stderr b/tests/fail/validity/uninit_float.stderr similarity index 100% rename from tests/compile-fail/validity/uninit_float.stderr rename to tests/fail/validity/uninit_float.stderr diff --git a/tests/compile-fail/validity/uninit_integer.rs b/tests/fail/validity/uninit_integer.rs similarity index 100% rename from tests/compile-fail/validity/uninit_integer.rs rename to tests/fail/validity/uninit_integer.rs diff --git a/tests/compile-fail/validity/uninit_integer.stderr b/tests/fail/validity/uninit_integer.stderr similarity index 100% rename from tests/compile-fail/validity/uninit_integer.stderr rename to tests/fail/validity/uninit_integer.stderr diff --git a/tests/compile-fail/validity/uninit_integer_signed.rs b/tests/fail/validity/uninit_integer_signed.rs similarity index 100% rename from tests/compile-fail/validity/uninit_integer_signed.rs rename to tests/fail/validity/uninit_integer_signed.rs diff --git a/tests/compile-fail/validity/uninit_integer_signed.stderr b/tests/fail/validity/uninit_integer_signed.stderr similarity index 100% rename from tests/compile-fail/validity/uninit_integer_signed.stderr rename to tests/fail/validity/uninit_integer_signed.stderr diff --git a/tests/compile-fail/zst1.rs b/tests/fail/zst1.rs similarity index 100% rename from tests/compile-fail/zst1.rs rename to tests/fail/zst1.rs diff --git a/tests/compile-fail/zst1.stderr b/tests/fail/zst1.stderr similarity index 100% rename from tests/compile-fail/zst1.stderr rename to tests/fail/zst1.stderr diff --git a/tests/compile-fail/zst2.rs b/tests/fail/zst2.rs similarity index 100% rename from tests/compile-fail/zst2.rs rename to tests/fail/zst2.rs diff --git a/tests/compile-fail/zst2.stderr b/tests/fail/zst2.stderr similarity index 100% rename from tests/compile-fail/zst2.stderr rename to tests/fail/zst2.stderr diff --git a/tests/compile-fail/zst3.rs b/tests/fail/zst3.rs similarity index 100% rename from tests/compile-fail/zst3.rs rename to tests/fail/zst3.rs diff --git a/tests/compile-fail/zst3.stderr b/tests/fail/zst3.stderr similarity index 100% rename from tests/compile-fail/zst3.stderr rename to tests/fail/zst3.stderr diff --git a/tests/run-fail/function_calls/exported_symbol_good_unwind.rs b/tests/panic/function_calls/exported_symbol_good_unwind.rs similarity index 100% rename from tests/run-fail/function_calls/exported_symbol_good_unwind.rs rename to tests/panic/function_calls/exported_symbol_good_unwind.rs diff --git a/tests/run-fail/function_calls/exported_symbol_good_unwind.stderr b/tests/panic/function_calls/exported_symbol_good_unwind.stderr similarity index 100% rename from tests/run-fail/function_calls/exported_symbol_good_unwind.stderr rename to tests/panic/function_calls/exported_symbol_good_unwind.stderr diff --git a/tests/run-fail/panic/div-by-zero-2.rs b/tests/panic/panic/div-by-zero-2.rs similarity index 100% rename from tests/run-fail/panic/div-by-zero-2.rs rename to tests/panic/panic/div-by-zero-2.rs diff --git a/tests/run-fail/panic/div-by-zero-2.stderr b/tests/panic/panic/div-by-zero-2.stderr similarity index 100% rename from tests/run-fail/panic/div-by-zero-2.stderr rename to tests/panic/panic/div-by-zero-2.stderr diff --git a/tests/run-fail/panic/overflowing-lsh-neg.rs b/tests/panic/panic/overflowing-lsh-neg.rs similarity index 100% rename from tests/run-fail/panic/overflowing-lsh-neg.rs rename to tests/panic/panic/overflowing-lsh-neg.rs diff --git a/tests/run-fail/panic/overflowing-lsh-neg.stderr b/tests/panic/panic/overflowing-lsh-neg.stderr similarity index 100% rename from tests/run-fail/panic/overflowing-lsh-neg.stderr rename to tests/panic/panic/overflowing-lsh-neg.stderr diff --git a/tests/run-fail/panic/overflowing-rsh-1.rs b/tests/panic/panic/overflowing-rsh-1.rs similarity index 100% rename from tests/run-fail/panic/overflowing-rsh-1.rs rename to tests/panic/panic/overflowing-rsh-1.rs diff --git a/tests/run-fail/panic/overflowing-rsh-1.stderr b/tests/panic/panic/overflowing-rsh-1.stderr similarity index 100% rename from tests/run-fail/panic/overflowing-rsh-1.stderr rename to tests/panic/panic/overflowing-rsh-1.stderr diff --git a/tests/run-fail/panic/overflowing-rsh-2.rs b/tests/panic/panic/overflowing-rsh-2.rs similarity index 100% rename from tests/run-fail/panic/overflowing-rsh-2.rs rename to tests/panic/panic/overflowing-rsh-2.rs diff --git a/tests/run-fail/panic/overflowing-rsh-2.stderr b/tests/panic/panic/overflowing-rsh-2.stderr similarity index 100% rename from tests/run-fail/panic/overflowing-rsh-2.stderr rename to tests/panic/panic/overflowing-rsh-2.stderr diff --git a/tests/run-fail/panic/panic1.rs b/tests/panic/panic/panic1.rs similarity index 100% rename from tests/run-fail/panic/panic1.rs rename to tests/panic/panic/panic1.rs diff --git a/tests/run-fail/panic/panic1.stderr b/tests/panic/panic/panic1.stderr similarity index 100% rename from tests/run-fail/panic/panic1.stderr rename to tests/panic/panic/panic1.stderr diff --git a/tests/run-fail/panic/panic2.rs b/tests/panic/panic/panic2.rs similarity index 100% rename from tests/run-fail/panic/panic2.rs rename to tests/panic/panic/panic2.rs diff --git a/tests/run-fail/panic/panic2.stderr b/tests/panic/panic/panic2.stderr similarity index 100% rename from tests/run-fail/panic/panic2.stderr rename to tests/panic/panic/panic2.stderr diff --git a/tests/run-fail/panic/panic3.rs b/tests/panic/panic/panic3.rs similarity index 100% rename from tests/run-fail/panic/panic3.rs rename to tests/panic/panic/panic3.rs diff --git a/tests/run-fail/panic/panic3.stderr b/tests/panic/panic/panic3.stderr similarity index 100% rename from tests/run-fail/panic/panic3.stderr rename to tests/panic/panic/panic3.stderr diff --git a/tests/run-fail/panic/panic4.rs b/tests/panic/panic/panic4.rs similarity index 100% rename from tests/run-fail/panic/panic4.rs rename to tests/panic/panic/panic4.rs diff --git a/tests/run-fail/panic/panic4.stderr b/tests/panic/panic/panic4.stderr similarity index 100% rename from tests/run-fail/panic/panic4.stderr rename to tests/panic/panic/panic4.stderr diff --git a/tests/run-fail/panic/unsupported_foreign_function.rs b/tests/panic/panic/unsupported_foreign_function.rs similarity index 100% rename from tests/run-fail/panic/unsupported_foreign_function.rs rename to tests/panic/panic/unsupported_foreign_function.rs diff --git a/tests/run-fail/panic/unsupported_foreign_function.stderr b/tests/panic/panic/unsupported_foreign_function.stderr similarity index 100% rename from tests/run-fail/panic/unsupported_foreign_function.stderr rename to tests/panic/panic/unsupported_foreign_function.stderr diff --git a/tests/run-fail/panic/unsupported_syscall.rs b/tests/panic/panic/unsupported_syscall.rs similarity index 100% rename from tests/run-fail/panic/unsupported_syscall.rs rename to tests/panic/panic/unsupported_syscall.rs diff --git a/tests/run-fail/panic/unsupported_syscall.stderr b/tests/panic/panic/unsupported_syscall.stderr similarity index 100% rename from tests/run-fail/panic/unsupported_syscall.stderr rename to tests/panic/panic/unsupported_syscall.stderr diff --git a/tests/run-fail/transmute_fat2.rs b/tests/panic/transmute_fat2.rs similarity index 100% rename from tests/run-fail/transmute_fat2.rs rename to tests/panic/transmute_fat2.rs diff --git a/tests/run-fail/transmute_fat2.stderr b/tests/panic/transmute_fat2.stderr similarity index 100% rename from tests/run-fail/transmute_fat2.stderr rename to tests/panic/transmute_fat2.stderr diff --git a/tests/run-pass/adjacent-allocs.rs b/tests/pass/adjacent-allocs.rs similarity index 100% rename from tests/run-pass/adjacent-allocs.rs rename to tests/pass/adjacent-allocs.rs diff --git a/tests/run-pass/align.rs b/tests/pass/align.rs similarity index 100% rename from tests/run-pass/align.rs rename to tests/pass/align.rs diff --git a/tests/run-pass/align_offset_symbolic.rs b/tests/pass/align_offset_symbolic.rs similarity index 100% rename from tests/run-pass/align_offset_symbolic.rs rename to tests/pass/align_offset_symbolic.rs diff --git a/tests/run-pass/align_offset_symbolic.stdout b/tests/pass/align_offset_symbolic.stdout similarity index 100% rename from tests/run-pass/align_offset_symbolic.stdout rename to tests/pass/align_offset_symbolic.stdout diff --git a/tests/run-pass/args.rs b/tests/pass/args.rs similarity index 100% rename from tests/run-pass/args.rs rename to tests/pass/args.rs diff --git a/tests/run-pass/args.stdout b/tests/pass/args.stdout similarity index 100% rename from tests/run-pass/args.stdout rename to tests/pass/args.stdout diff --git a/tests/run-pass/arrays.rs b/tests/pass/arrays.rs similarity index 100% rename from tests/run-pass/arrays.rs rename to tests/pass/arrays.rs diff --git a/tests/run-pass/arrays.stdout b/tests/pass/arrays.stdout similarity index 100% rename from tests/run-pass/arrays.stdout rename to tests/pass/arrays.stdout diff --git a/tests/run-pass/associated-const.rs b/tests/pass/associated-const.rs similarity index 100% rename from tests/run-pass/associated-const.rs rename to tests/pass/associated-const.rs diff --git a/tests/run-pass/assume_bug.rs b/tests/pass/assume_bug.rs similarity index 100% rename from tests/run-pass/assume_bug.rs rename to tests/pass/assume_bug.rs diff --git a/tests/run-pass/async-fn.rs b/tests/pass/async-fn.rs similarity index 100% rename from tests/run-pass/async-fn.rs rename to tests/pass/async-fn.rs diff --git a/tests/run-pass/atomic-compare-exchange-weak-never-fail.rs b/tests/pass/atomic-compare-exchange-weak-never-fail.rs similarity index 100% rename from tests/run-pass/atomic-compare-exchange-weak-never-fail.rs rename to tests/pass/atomic-compare-exchange-weak-never-fail.rs diff --git a/tests/run-pass/atomic.rs b/tests/pass/atomic.rs similarity index 100% rename from tests/run-pass/atomic.rs rename to tests/pass/atomic.rs diff --git a/tests/run-pass/available-parallelism.rs b/tests/pass/available-parallelism.rs similarity index 100% rename from tests/run-pass/available-parallelism.rs rename to tests/pass/available-parallelism.rs diff --git a/tests/run-pass/backtrace-api-v0.rs b/tests/pass/backtrace-api-v0.rs similarity index 100% rename from tests/run-pass/backtrace-api-v0.rs rename to tests/pass/backtrace-api-v0.rs diff --git a/tests/run-pass/backtrace-api-v0.stderr b/tests/pass/backtrace-api-v0.stderr similarity index 100% rename from tests/run-pass/backtrace-api-v0.stderr rename to tests/pass/backtrace-api-v0.stderr diff --git a/tests/run-pass/backtrace-api-v0.stdout b/tests/pass/backtrace-api-v0.stdout similarity index 100% rename from tests/run-pass/backtrace-api-v0.stdout rename to tests/pass/backtrace-api-v0.stdout diff --git a/tests/run-pass/backtrace-api-v1.rs b/tests/pass/backtrace-api-v1.rs similarity index 100% rename from tests/run-pass/backtrace-api-v1.rs rename to tests/pass/backtrace-api-v1.rs diff --git a/tests/run-pass/backtrace-api-v1.stderr b/tests/pass/backtrace-api-v1.stderr similarity index 100% rename from tests/run-pass/backtrace-api-v1.stderr rename to tests/pass/backtrace-api-v1.stderr diff --git a/tests/run-pass/backtrace-api-v1.stdout b/tests/pass/backtrace-api-v1.stdout similarity index 100% rename from tests/run-pass/backtrace-api-v1.stdout rename to tests/pass/backtrace-api-v1.stdout diff --git a/tests/run-pass/backtrace-std.rs b/tests/pass/backtrace-std.rs similarity index 100% rename from tests/run-pass/backtrace-std.rs rename to tests/pass/backtrace-std.rs diff --git a/tests/run-pass/backtrace-std.stderr b/tests/pass/backtrace-std.stderr similarity index 100% rename from tests/run-pass/backtrace-std.stderr rename to tests/pass/backtrace-std.stderr diff --git a/tests/run-pass/bad_substs.rs b/tests/pass/bad_substs.rs similarity index 100% rename from tests/run-pass/bad_substs.rs rename to tests/pass/bad_substs.rs diff --git a/tests/run-pass/binary-heap.rs b/tests/pass/binary-heap.rs similarity index 100% rename from tests/run-pass/binary-heap.rs rename to tests/pass/binary-heap.rs diff --git a/tests/run-pass/binops.rs b/tests/pass/binops.rs similarity index 100% rename from tests/run-pass/binops.rs rename to tests/pass/binops.rs diff --git a/tests/run-pass/bools.rs b/tests/pass/bools.rs similarity index 100% rename from tests/run-pass/bools.rs rename to tests/pass/bools.rs diff --git a/tests/run-pass/box.rs b/tests/pass/box.rs similarity index 100% rename from tests/run-pass/box.rs rename to tests/pass/box.rs diff --git a/tests/run-pass/box.stdout b/tests/pass/box.stdout similarity index 100% rename from tests/run-pass/box.stdout rename to tests/pass/box.stdout diff --git a/tests/run-pass/btreemap.rs b/tests/pass/btreemap.rs similarity index 100% rename from tests/run-pass/btreemap.rs rename to tests/pass/btreemap.rs diff --git a/tests/run-pass/c_enums.rs b/tests/pass/c_enums.rs similarity index 100% rename from tests/run-pass/c_enums.rs rename to tests/pass/c_enums.rs diff --git a/tests/run-pass/calloc.rs b/tests/pass/calloc.rs similarity index 100% rename from tests/run-pass/calloc.rs rename to tests/pass/calloc.rs diff --git a/tests/run-pass/calls.rs b/tests/pass/calls.rs similarity index 100% rename from tests/run-pass/calls.rs rename to tests/pass/calls.rs diff --git a/tests/run-pass/cast-rfc0401-vtable-kinds.rs b/tests/pass/cast-rfc0401-vtable-kinds.rs similarity index 100% rename from tests/run-pass/cast-rfc0401-vtable-kinds.rs rename to tests/pass/cast-rfc0401-vtable-kinds.rs diff --git a/tests/run-pass/cast_fn_ptr.rs b/tests/pass/cast_fn_ptr.rs similarity index 100% rename from tests/run-pass/cast_fn_ptr.rs rename to tests/pass/cast_fn_ptr.rs diff --git a/tests/run-pass/cast_fn_ptr_unsafe.rs b/tests/pass/cast_fn_ptr_unsafe.rs similarity index 100% rename from tests/run-pass/cast_fn_ptr_unsafe.rs rename to tests/pass/cast_fn_ptr_unsafe.rs diff --git a/tests/run-pass/catch.rs b/tests/pass/catch.rs similarity index 100% rename from tests/run-pass/catch.rs rename to tests/pass/catch.rs diff --git a/tests/run-pass/catch.stdout b/tests/pass/catch.stdout similarity index 100% rename from tests/run-pass/catch.stdout rename to tests/pass/catch.stdout diff --git a/tests/run-pass/cfg_miri.rs b/tests/pass/cfg_miri.rs similarity index 100% rename from tests/run-pass/cfg_miri.rs rename to tests/pass/cfg_miri.rs diff --git a/tests/run-pass/char.rs b/tests/pass/char.rs similarity index 100% rename from tests/run-pass/char.rs rename to tests/pass/char.rs diff --git a/tests/run-pass/closure-drop.rs b/tests/pass/closure-drop.rs similarity index 100% rename from tests/run-pass/closure-drop.rs rename to tests/pass/closure-drop.rs diff --git a/tests/run-pass/closure-field-ty.rs b/tests/pass/closure-field-ty.rs similarity index 100% rename from tests/run-pass/closure-field-ty.rs rename to tests/pass/closure-field-ty.rs diff --git a/tests/run-pass/closures.rs b/tests/pass/closures.rs similarity index 100% rename from tests/run-pass/closures.rs rename to tests/pass/closures.rs diff --git a/tests/run-pass/coerce_non_capture_closure_to_fn_ptr.rs b/tests/pass/coerce_non_capture_closure_to_fn_ptr.rs similarity index 100% rename from tests/run-pass/coerce_non_capture_closure_to_fn_ptr.rs rename to tests/pass/coerce_non_capture_closure_to_fn_ptr.rs diff --git a/tests/run-pass/coercions.rs b/tests/pass/coercions.rs similarity index 100% rename from tests/run-pass/coercions.rs rename to tests/pass/coercions.rs diff --git a/tests/run-pass/concurrency/channels.rs b/tests/pass/concurrency/channels.rs similarity index 100% rename from tests/run-pass/concurrency/channels.rs rename to tests/pass/concurrency/channels.rs diff --git a/tests/run-pass/concurrency/channels.stderr b/tests/pass/concurrency/channels.stderr similarity index 100% rename from tests/run-pass/concurrency/channels.stderr rename to tests/pass/concurrency/channels.stderr diff --git a/tests/run-pass/concurrency/concurrent_caller_location.rs b/tests/pass/concurrency/concurrent_caller_location.rs similarity index 100% rename from tests/run-pass/concurrency/concurrent_caller_location.rs rename to tests/pass/concurrency/concurrent_caller_location.rs diff --git a/tests/run-pass/concurrency/concurrent_caller_location.stderr b/tests/pass/concurrency/concurrent_caller_location.stderr similarity index 100% rename from tests/run-pass/concurrency/concurrent_caller_location.stderr rename to tests/pass/concurrency/concurrent_caller_location.stderr diff --git a/tests/run-pass/concurrency/data_race.rs b/tests/pass/concurrency/data_race.rs similarity index 100% rename from tests/run-pass/concurrency/data_race.rs rename to tests/pass/concurrency/data_race.rs diff --git a/tests/run-pass/concurrency/data_race.stderr b/tests/pass/concurrency/data_race.stderr similarity index 100% rename from tests/run-pass/concurrency/data_race.stderr rename to tests/pass/concurrency/data_race.stderr diff --git a/tests/run-pass/concurrency/disable_data_race_detector.rs b/tests/pass/concurrency/disable_data_race_detector.rs similarity index 100% rename from tests/run-pass/concurrency/disable_data_race_detector.rs rename to tests/pass/concurrency/disable_data_race_detector.rs diff --git a/tests/run-pass/concurrency/disable_data_race_detector.stderr b/tests/pass/concurrency/disable_data_race_detector.stderr similarity index 100% rename from tests/run-pass/concurrency/disable_data_race_detector.stderr rename to tests/pass/concurrency/disable_data_race_detector.stderr diff --git a/tests/run-pass/concurrency/issue1643.rs b/tests/pass/concurrency/issue1643.rs similarity index 100% rename from tests/run-pass/concurrency/issue1643.rs rename to tests/pass/concurrency/issue1643.rs diff --git a/tests/run-pass/concurrency/issue1643.stderr b/tests/pass/concurrency/issue1643.stderr similarity index 100% rename from tests/run-pass/concurrency/issue1643.stderr rename to tests/pass/concurrency/issue1643.stderr diff --git a/tests/run-pass/concurrency/libc_pthread_cond.rs b/tests/pass/concurrency/libc_pthread_cond.rs similarity index 100% rename from tests/run-pass/concurrency/libc_pthread_cond.rs rename to tests/pass/concurrency/libc_pthread_cond.rs diff --git a/tests/run-pass/concurrency/linux-futex.rs b/tests/pass/concurrency/linux-futex.rs similarity index 100% rename from tests/run-pass/concurrency/linux-futex.rs rename to tests/pass/concurrency/linux-futex.rs diff --git a/tests/run-pass/concurrency/linux-futex.stderr b/tests/pass/concurrency/linux-futex.stderr similarity index 100% rename from tests/run-pass/concurrency/linux-futex.stderr rename to tests/pass/concurrency/linux-futex.stderr diff --git a/tests/run-pass/concurrency/simple.rs b/tests/pass/concurrency/simple.rs similarity index 100% rename from tests/run-pass/concurrency/simple.rs rename to tests/pass/concurrency/simple.rs diff --git a/tests/run-pass/concurrency/simple.stderr b/tests/pass/concurrency/simple.stderr similarity index 100% rename from tests/run-pass/concurrency/simple.stderr rename to tests/pass/concurrency/simple.stderr diff --git a/tests/run-pass/concurrency/sync.rs b/tests/pass/concurrency/sync.rs similarity index 100% rename from tests/run-pass/concurrency/sync.rs rename to tests/pass/concurrency/sync.rs diff --git a/tests/run-pass/concurrency/sync.stderr b/tests/pass/concurrency/sync.stderr similarity index 100% rename from tests/run-pass/concurrency/sync.stderr rename to tests/pass/concurrency/sync.stderr diff --git a/tests/run-pass/concurrency/sync.stdout b/tests/pass/concurrency/sync.stdout similarity index 100% rename from tests/run-pass/concurrency/sync.stdout rename to tests/pass/concurrency/sync.stdout diff --git a/tests/run-pass/concurrency/sync_singlethread.rs b/tests/pass/concurrency/sync_singlethread.rs similarity index 100% rename from tests/run-pass/concurrency/sync_singlethread.rs rename to tests/pass/concurrency/sync_singlethread.rs diff --git a/tests/run-pass/concurrency/thread_locals.rs b/tests/pass/concurrency/thread_locals.rs similarity index 100% rename from tests/run-pass/concurrency/thread_locals.rs rename to tests/pass/concurrency/thread_locals.rs diff --git a/tests/run-pass/concurrency/thread_locals.stderr b/tests/pass/concurrency/thread_locals.stderr similarity index 100% rename from tests/run-pass/concurrency/thread_locals.stderr rename to tests/pass/concurrency/thread_locals.stderr diff --git a/tests/run-pass/concurrency/tls_lib_drop.rs b/tests/pass/concurrency/tls_lib_drop.rs similarity index 100% rename from tests/run-pass/concurrency/tls_lib_drop.rs rename to tests/pass/concurrency/tls_lib_drop.rs diff --git a/tests/run-pass/concurrency/tls_lib_drop.stderr b/tests/pass/concurrency/tls_lib_drop.stderr similarity index 100% rename from tests/run-pass/concurrency/tls_lib_drop.stderr rename to tests/pass/concurrency/tls_lib_drop.stderr diff --git a/tests/run-pass/concurrency/tls_lib_drop.stdout b/tests/pass/concurrency/tls_lib_drop.stdout similarity index 100% rename from tests/run-pass/concurrency/tls_lib_drop.stdout rename to tests/pass/concurrency/tls_lib_drop.stdout diff --git a/tests/run-pass/concurrency/tls_lib_drop_single_thread.rs b/tests/pass/concurrency/tls_lib_drop_single_thread.rs similarity index 100% rename from tests/run-pass/concurrency/tls_lib_drop_single_thread.rs rename to tests/pass/concurrency/tls_lib_drop_single_thread.rs diff --git a/tests/run-pass/concurrency/tls_lib_drop_single_thread.stderr b/tests/pass/concurrency/tls_lib_drop_single_thread.stderr similarity index 100% rename from tests/run-pass/concurrency/tls_lib_drop_single_thread.stderr rename to tests/pass/concurrency/tls_lib_drop_single_thread.stderr diff --git a/tests/run-pass/concurrency/tls_pthread_drop_order.rs b/tests/pass/concurrency/tls_pthread_drop_order.rs similarity index 100% rename from tests/run-pass/concurrency/tls_pthread_drop_order.rs rename to tests/pass/concurrency/tls_pthread_drop_order.rs diff --git a/tests/run-pass/const-vec-of-fns.rs b/tests/pass/const-vec-of-fns.rs similarity index 100% rename from tests/run-pass/const-vec-of-fns.rs rename to tests/pass/const-vec-of-fns.rs diff --git a/tests/run-pass/constants.rs b/tests/pass/constants.rs similarity index 100% rename from tests/run-pass/constants.rs rename to tests/pass/constants.rs diff --git a/tests/run-pass/current_dir.rs b/tests/pass/current_dir.rs similarity index 100% rename from tests/run-pass/current_dir.rs rename to tests/pass/current_dir.rs diff --git a/tests/run-pass/current_dir_with_isolation.rs b/tests/pass/current_dir_with_isolation.rs similarity index 100% rename from tests/run-pass/current_dir_with_isolation.rs rename to tests/pass/current_dir_with_isolation.rs diff --git a/tests/run-pass/current_dir_with_isolation.stderr b/tests/pass/current_dir_with_isolation.stderr similarity index 100% rename from tests/run-pass/current_dir_with_isolation.stderr rename to tests/pass/current_dir_with_isolation.stderr diff --git a/tests/run-pass/deriving-associated-types.rs b/tests/pass/deriving-associated-types.rs similarity index 100% rename from tests/run-pass/deriving-associated-types.rs rename to tests/pass/deriving-associated-types.rs diff --git a/tests/run-pass/disable-alignment-check.rs b/tests/pass/disable-alignment-check.rs similarity index 100% rename from tests/run-pass/disable-alignment-check.rs rename to tests/pass/disable-alignment-check.rs diff --git a/tests/run-pass/drop_empty_slice.rs b/tests/pass/drop_empty_slice.rs similarity index 100% rename from tests/run-pass/drop_empty_slice.rs rename to tests/pass/drop_empty_slice.rs diff --git a/tests/run-pass/drop_on_array_elements.rs b/tests/pass/drop_on_array_elements.rs similarity index 100% rename from tests/run-pass/drop_on_array_elements.rs rename to tests/pass/drop_on_array_elements.rs diff --git a/tests/run-pass/drop_on_fat_ptr_array_elements.rs b/tests/pass/drop_on_fat_ptr_array_elements.rs similarity index 100% rename from tests/run-pass/drop_on_fat_ptr_array_elements.rs rename to tests/pass/drop_on_fat_ptr_array_elements.rs diff --git a/tests/run-pass/drop_on_zst_array_elements.rs b/tests/pass/drop_on_zst_array_elements.rs similarity index 100% rename from tests/run-pass/drop_on_zst_array_elements.rs rename to tests/pass/drop_on_zst_array_elements.rs diff --git a/tests/run-pass/drop_through_owned_slice.rs b/tests/pass/drop_through_owned_slice.rs similarity index 100% rename from tests/run-pass/drop_through_owned_slice.rs rename to tests/pass/drop_through_owned_slice.rs diff --git a/tests/run-pass/drop_through_trait_object.rs b/tests/pass/drop_through_trait_object.rs similarity index 100% rename from tests/run-pass/drop_through_trait_object.rs rename to tests/pass/drop_through_trait_object.rs diff --git a/tests/run-pass/drop_through_trait_object_rc.rs b/tests/pass/drop_through_trait_object_rc.rs similarity index 100% rename from tests/run-pass/drop_through_trait_object_rc.rs rename to tests/pass/drop_through_trait_object_rc.rs diff --git a/tests/run-pass/dst-field-align.rs b/tests/pass/dst-field-align.rs similarity index 100% rename from tests/run-pass/dst-field-align.rs rename to tests/pass/dst-field-align.rs diff --git a/tests/run-pass/dst-irrefutable-bind.rs b/tests/pass/dst-irrefutable-bind.rs similarity index 100% rename from tests/run-pass/dst-irrefutable-bind.rs rename to tests/pass/dst-irrefutable-bind.rs diff --git a/tests/run-pass/dst-raw.rs b/tests/pass/dst-raw.rs similarity index 100% rename from tests/run-pass/dst-raw.rs rename to tests/pass/dst-raw.rs diff --git a/tests/run-pass/dst-struct-sole.rs b/tests/pass/dst-struct-sole.rs similarity index 100% rename from tests/run-pass/dst-struct-sole.rs rename to tests/pass/dst-struct-sole.rs diff --git a/tests/run-pass/dst-struct.rs b/tests/pass/dst-struct.rs similarity index 100% rename from tests/run-pass/dst-struct.rs rename to tests/pass/dst-struct.rs diff --git a/tests/run-pass/dyn-arbitrary-self.rs b/tests/pass/dyn-arbitrary-self.rs similarity index 100% rename from tests/run-pass/dyn-arbitrary-self.rs rename to tests/pass/dyn-arbitrary-self.rs diff --git a/tests/run-pass/dyn-traits.rs b/tests/pass/dyn-traits.rs similarity index 100% rename from tests/run-pass/dyn-traits.rs rename to tests/pass/dyn-traits.rs diff --git a/tests/run-pass/enum-nullable-const-null-with-fields.rs b/tests/pass/enum-nullable-const-null-with-fields.rs similarity index 100% rename from tests/run-pass/enum-nullable-const-null-with-fields.rs rename to tests/pass/enum-nullable-const-null-with-fields.rs diff --git a/tests/run-pass/enum_discriminant_ptr_value.rs b/tests/pass/enum_discriminant_ptr_value.rs similarity index 100% rename from tests/run-pass/enum_discriminant_ptr_value.rs rename to tests/pass/enum_discriminant_ptr_value.rs diff --git a/tests/run-pass/enums.rs b/tests/pass/enums.rs similarity index 100% rename from tests/run-pass/enums.rs rename to tests/pass/enums.rs diff --git a/tests/run-pass/env-exclude.rs b/tests/pass/env-exclude.rs similarity index 100% rename from tests/run-pass/env-exclude.rs rename to tests/pass/env-exclude.rs diff --git a/tests/run-pass/env-forward.rs b/tests/pass/env-forward.rs similarity index 100% rename from tests/run-pass/env-forward.rs rename to tests/pass/env-forward.rs diff --git a/tests/run-pass/env-without-isolation.rs b/tests/pass/env-without-isolation.rs similarity index 100% rename from tests/run-pass/env-without-isolation.rs rename to tests/pass/env-without-isolation.rs diff --git a/tests/run-pass/env.rs b/tests/pass/env.rs similarity index 100% rename from tests/run-pass/env.rs rename to tests/pass/env.rs diff --git a/tests/run-pass/env.stdout b/tests/pass/env.stdout similarity index 100% rename from tests/run-pass/env.stdout rename to tests/pass/env.stdout diff --git a/tests/run-pass/exit.rs b/tests/pass/exit.rs similarity index 100% rename from tests/run-pass/exit.rs rename to tests/pass/exit.rs diff --git a/tests/run-pass/extern_crate_std_in_main.rs b/tests/pass/extern_crate_std_in_main.rs similarity index 100% rename from tests/run-pass/extern_crate_std_in_main.rs rename to tests/pass/extern_crate_std_in_main.rs diff --git a/tests/run-pass/extern_types.rs b/tests/pass/extern_types.rs similarity index 100% rename from tests/run-pass/extern_types.rs rename to tests/pass/extern_types.rs diff --git a/tests/run-pass/fat_ptr.rs b/tests/pass/fat_ptr.rs similarity index 100% rename from tests/run-pass/fat_ptr.rs rename to tests/pass/fat_ptr.rs diff --git a/tests/run-pass/float.rs b/tests/pass/float.rs similarity index 100% rename from tests/run-pass/float.rs rename to tests/pass/float.rs diff --git a/tests/run-pass/float_fast_math.rs b/tests/pass/float_fast_math.rs similarity index 100% rename from tests/run-pass/float_fast_math.rs rename to tests/pass/float_fast_math.rs diff --git a/tests/run-pass/foreign-fn-linkname.rs b/tests/pass/foreign-fn-linkname.rs similarity index 100% rename from tests/run-pass/foreign-fn-linkname.rs rename to tests/pass/foreign-fn-linkname.rs diff --git a/tests/run-pass/format.rs b/tests/pass/format.rs similarity index 100% rename from tests/run-pass/format.rs rename to tests/pass/format.rs diff --git a/tests/run-pass/format.stdout b/tests/pass/format.stdout similarity index 100% rename from tests/run-pass/format.stdout rename to tests/pass/format.stdout diff --git a/tests/run-pass/from_utf8.rs b/tests/pass/from_utf8.rs similarity index 100% rename from tests/run-pass/from_utf8.rs rename to tests/pass/from_utf8.rs diff --git a/tests/run-pass/fs.rs b/tests/pass/fs.rs similarity index 100% rename from tests/run-pass/fs.rs rename to tests/pass/fs.rs diff --git a/tests/run-pass/fs.stderr b/tests/pass/fs.stderr similarity index 100% rename from tests/run-pass/fs.stderr rename to tests/pass/fs.stderr diff --git a/tests/run-pass/fs.stdout b/tests/pass/fs.stdout similarity index 100% rename from tests/run-pass/fs.stdout rename to tests/pass/fs.stdout diff --git a/tests/run-pass/fs_with_isolation.rs b/tests/pass/fs_with_isolation.rs similarity index 100% rename from tests/run-pass/fs_with_isolation.rs rename to tests/pass/fs_with_isolation.rs diff --git a/tests/run-pass/fs_with_isolation.stderr b/tests/pass/fs_with_isolation.stderr similarity index 100% rename from tests/run-pass/fs_with_isolation.stderr rename to tests/pass/fs_with_isolation.stderr diff --git a/tests/run-pass/function_calls/disable_abi_check.rs b/tests/pass/function_calls/disable_abi_check.rs similarity index 100% rename from tests/run-pass/function_calls/disable_abi_check.rs rename to tests/pass/function_calls/disable_abi_check.rs diff --git a/tests/run-pass/function_calls/exported_symbol.rs b/tests/pass/function_calls/exported_symbol.rs similarity index 100% rename from tests/run-pass/function_calls/exported_symbol.rs rename to tests/pass/function_calls/exported_symbol.rs diff --git a/tests/run-pass/function_pointers.rs b/tests/pass/function_pointers.rs similarity index 100% rename from tests/run-pass/function_pointers.rs rename to tests/pass/function_pointers.rs diff --git a/tests/run-pass/generator.rs b/tests/pass/generator.rs similarity index 100% rename from tests/run-pass/generator.rs rename to tests/pass/generator.rs diff --git a/tests/run-pass/global_allocator.rs b/tests/pass/global_allocator.rs similarity index 100% rename from tests/run-pass/global_allocator.rs rename to tests/pass/global_allocator.rs diff --git a/tests/run-pass/global_allocator.stdout b/tests/pass/global_allocator.stdout similarity index 100% rename from tests/run-pass/global_allocator.stdout rename to tests/pass/global_allocator.stdout diff --git a/tests/run-pass/hashmap.rs b/tests/pass/hashmap.rs similarity index 100% rename from tests/run-pass/hashmap.rs rename to tests/pass/hashmap.rs diff --git a/tests/run-pass/heap.rs b/tests/pass/heap.rs similarity index 100% rename from tests/run-pass/heap.rs rename to tests/pass/heap.rs diff --git a/tests/run-pass/heap_allocator.rs b/tests/pass/heap_allocator.rs similarity index 100% rename from tests/run-pass/heap_allocator.rs rename to tests/pass/heap_allocator.rs diff --git a/tests/run-pass/hello.rs b/tests/pass/hello.rs similarity index 100% rename from tests/run-pass/hello.rs rename to tests/pass/hello.rs diff --git a/tests/run-pass/hello.stdout b/tests/pass/hello.stdout similarity index 100% rename from tests/run-pass/hello.stdout rename to tests/pass/hello.stdout diff --git a/tests/run-pass/hide_stdout.rs b/tests/pass/hide_stdout.rs similarity index 100% rename from tests/run-pass/hide_stdout.rs rename to tests/pass/hide_stdout.rs diff --git a/tests/run-pass/integer-ops.rs b/tests/pass/integer-ops.rs similarity index 100% rename from tests/run-pass/integer-ops.rs rename to tests/pass/integer-ops.rs diff --git a/tests/run-pass/intptrcast.rs b/tests/pass/intptrcast.rs similarity index 100% rename from tests/run-pass/intptrcast.rs rename to tests/pass/intptrcast.rs diff --git a/tests/run-pass/intrinsics-integer.rs b/tests/pass/intrinsics-integer.rs similarity index 100% rename from tests/run-pass/intrinsics-integer.rs rename to tests/pass/intrinsics-integer.rs diff --git a/tests/run-pass/intrinsics-math.rs b/tests/pass/intrinsics-math.rs similarity index 100% rename from tests/run-pass/intrinsics-math.rs rename to tests/pass/intrinsics-math.rs diff --git a/tests/run-pass/intrinsics-x86.rs b/tests/pass/intrinsics-x86.rs similarity index 100% rename from tests/run-pass/intrinsics-x86.rs rename to tests/pass/intrinsics-x86.rs diff --git a/tests/run-pass/intrinsics.rs b/tests/pass/intrinsics.rs similarity index 100% rename from tests/run-pass/intrinsics.rs rename to tests/pass/intrinsics.rs diff --git a/tests/run-pass/ints.rs b/tests/pass/ints.rs similarity index 100% rename from tests/run-pass/ints.rs rename to tests/pass/ints.rs diff --git a/tests/run-pass/issue-15063.rs b/tests/pass/issue-15063.rs similarity index 100% rename from tests/run-pass/issue-15063.rs rename to tests/pass/issue-15063.rs diff --git a/tests/run-pass/issue-15080.rs b/tests/pass/issue-15080.rs similarity index 100% rename from tests/run-pass/issue-15080.rs rename to tests/pass/issue-15080.rs diff --git a/tests/run-pass/issue-15523-big.rs b/tests/pass/issue-15523-big.rs similarity index 100% rename from tests/run-pass/issue-15523-big.rs rename to tests/pass/issue-15523-big.rs diff --git a/tests/run-pass/issue-17877.rs b/tests/pass/issue-17877.rs similarity index 100% rename from tests/run-pass/issue-17877.rs rename to tests/pass/issue-17877.rs diff --git a/tests/run-pass/issue-20575.rs b/tests/pass/issue-20575.rs similarity index 100% rename from tests/run-pass/issue-20575.rs rename to tests/pass/issue-20575.rs diff --git a/tests/run-pass/issue-23261.rs b/tests/pass/issue-23261.rs similarity index 100% rename from tests/run-pass/issue-23261.rs rename to tests/pass/issue-23261.rs diff --git a/tests/run-pass/issue-26709.rs b/tests/pass/issue-26709.rs similarity index 100% rename from tests/run-pass/issue-26709.rs rename to tests/pass/issue-26709.rs diff --git a/tests/run-pass/issue-27901.rs b/tests/pass/issue-27901.rs similarity index 100% rename from tests/run-pass/issue-27901.rs rename to tests/pass/issue-27901.rs diff --git a/tests/run-pass/issue-29746.rs b/tests/pass/issue-29746.rs similarity index 100% rename from tests/run-pass/issue-29746.rs rename to tests/pass/issue-29746.rs diff --git a/tests/run-pass/issue-30530.rs b/tests/pass/issue-30530.rs similarity index 100% rename from tests/run-pass/issue-30530.rs rename to tests/pass/issue-30530.rs diff --git a/tests/run-pass/issue-31267-additional.rs b/tests/pass/issue-31267-additional.rs similarity index 100% rename from tests/run-pass/issue-31267-additional.rs rename to tests/pass/issue-31267-additional.rs diff --git a/tests/run-pass/issue-33387.rs b/tests/pass/issue-33387.rs similarity index 100% rename from tests/run-pass/issue-33387.rs rename to tests/pass/issue-33387.rs diff --git a/tests/run-pass/issue-34571.rs b/tests/pass/issue-34571.rs similarity index 100% rename from tests/run-pass/issue-34571.rs rename to tests/pass/issue-34571.rs diff --git a/tests/run-pass/issue-35815.rs b/tests/pass/issue-35815.rs similarity index 100% rename from tests/run-pass/issue-35815.rs rename to tests/pass/issue-35815.rs diff --git a/tests/run-pass/issue-36278-prefix-nesting.rs b/tests/pass/issue-36278-prefix-nesting.rs similarity index 100% rename from tests/run-pass/issue-36278-prefix-nesting.rs rename to tests/pass/issue-36278-prefix-nesting.rs diff --git a/tests/run-pass/issue-3794.rs b/tests/pass/issue-3794.rs similarity index 100% rename from tests/run-pass/issue-3794.rs rename to tests/pass/issue-3794.rs diff --git a/tests/run-pass/issue-3794.stdout b/tests/pass/issue-3794.stdout similarity index 100% rename from tests/run-pass/issue-3794.stdout rename to tests/pass/issue-3794.stdout diff --git a/tests/run-pass/issue-53728.rs b/tests/pass/issue-53728.rs similarity index 100% rename from tests/run-pass/issue-53728.rs rename to tests/pass/issue-53728.rs diff --git a/tests/run-pass/issue-5917.rs b/tests/pass/issue-5917.rs similarity index 100% rename from tests/run-pass/issue-5917.rs rename to tests/pass/issue-5917.rs diff --git a/tests/run-pass/issue-73223.rs b/tests/pass/issue-73223.rs similarity index 100% rename from tests/run-pass/issue-73223.rs rename to tests/pass/issue-73223.rs diff --git a/tests/run-pass/issue-91636.rs b/tests/pass/issue-91636.rs similarity index 100% rename from tests/run-pass/issue-91636.rs rename to tests/pass/issue-91636.rs diff --git a/tests/run-pass/issue-94371.rs b/tests/pass/issue-94371.rs similarity index 100% rename from tests/run-pass/issue-94371.rs rename to tests/pass/issue-94371.rs diff --git a/tests/run-pass/issue-miri-1075.rs b/tests/pass/issue-miri-1075.rs similarity index 100% rename from tests/run-pass/issue-miri-1075.rs rename to tests/pass/issue-miri-1075.rs diff --git a/tests/run-pass/issue-miri-133.rs b/tests/pass/issue-miri-133.rs similarity index 100% rename from tests/run-pass/issue-miri-133.rs rename to tests/pass/issue-miri-133.rs diff --git a/tests/run-pass/issue-miri-184.rs b/tests/pass/issue-miri-184.rs similarity index 100% rename from tests/run-pass/issue-miri-184.rs rename to tests/pass/issue-miri-184.rs diff --git a/tests/run-pass/issue-miri-1925.rs b/tests/pass/issue-miri-1925.rs similarity index 100% rename from tests/run-pass/issue-miri-1925.rs rename to tests/pass/issue-miri-1925.rs diff --git a/tests/run-pass/issue-miri-2068-2.rs b/tests/pass/issue-miri-2068-2.rs similarity index 100% rename from tests/run-pass/issue-miri-2068-2.rs rename to tests/pass/issue-miri-2068-2.rs diff --git a/tests/run-pass/issue-miri-2068.rs b/tests/pass/issue-miri-2068.rs similarity index 100% rename from tests/run-pass/issue-miri-2068.rs rename to tests/pass/issue-miri-2068.rs diff --git a/tests/run-pass/iter.rs b/tests/pass/iter.rs similarity index 100% rename from tests/run-pass/iter.rs rename to tests/pass/iter.rs diff --git a/tests/run-pass/last-use-in-cap-clause.rs b/tests/pass/last-use-in-cap-clause.rs similarity index 100% rename from tests/run-pass/last-use-in-cap-clause.rs rename to tests/pass/last-use-in-cap-clause.rs diff --git a/tests/run-pass/leak-in-static.rs b/tests/pass/leak-in-static.rs similarity index 100% rename from tests/run-pass/leak-in-static.rs rename to tests/pass/leak-in-static.rs diff --git a/tests/run-pass/libc.rs b/tests/pass/libc.rs similarity index 100% rename from tests/run-pass/libc.rs rename to tests/pass/libc.rs diff --git a/tests/run-pass/libc.stderr b/tests/pass/libc.stderr similarity index 100% rename from tests/run-pass/libc.stderr rename to tests/pass/libc.stderr diff --git a/tests/run-pass/linked-list.rs b/tests/pass/linked-list.rs similarity index 100% rename from tests/run-pass/linked-list.rs rename to tests/pass/linked-list.rs diff --git a/tests/run-pass/linux-getrandom-without-isolation.rs b/tests/pass/linux-getrandom-without-isolation.rs similarity index 100% rename from tests/run-pass/linux-getrandom-without-isolation.rs rename to tests/pass/linux-getrandom-without-isolation.rs diff --git a/tests/run-pass/linux-getrandom.rs b/tests/pass/linux-getrandom.rs similarity index 100% rename from tests/run-pass/linux-getrandom.rs rename to tests/pass/linux-getrandom.rs diff --git a/tests/run-pass/loop-break-value.rs b/tests/pass/loop-break-value.rs similarity index 100% rename from tests/run-pass/loop-break-value.rs rename to tests/pass/loop-break-value.rs diff --git a/tests/run-pass/loops.rs b/tests/pass/loops.rs similarity index 100% rename from tests/run-pass/loops.rs rename to tests/pass/loops.rs diff --git a/tests/run-pass/main_fn.rs b/tests/pass/main_fn.rs similarity index 100% rename from tests/run-pass/main_fn.rs rename to tests/pass/main_fn.rs diff --git a/tests/run-pass/main_result.rs b/tests/pass/main_result.rs similarity index 100% rename from tests/run-pass/main_result.rs rename to tests/pass/main_result.rs diff --git a/tests/run-pass/malloc.rs b/tests/pass/malloc.rs similarity index 100% rename from tests/run-pass/malloc.rs rename to tests/pass/malloc.rs diff --git a/tests/run-pass/many_shr_bor.rs b/tests/pass/many_shr_bor.rs similarity index 100% rename from tests/run-pass/many_shr_bor.rs rename to tests/pass/many_shr_bor.rs diff --git a/tests/run-pass/match_slice.rs b/tests/pass/match_slice.rs similarity index 100% rename from tests/run-pass/match_slice.rs rename to tests/pass/match_slice.rs diff --git a/tests/run-pass/memchr.rs b/tests/pass/memchr.rs similarity index 100% rename from tests/run-pass/memchr.rs rename to tests/pass/memchr.rs diff --git a/tests/run-pass/memleak_ignored.rs b/tests/pass/memleak_ignored.rs similarity index 100% rename from tests/run-pass/memleak_ignored.rs rename to tests/pass/memleak_ignored.rs diff --git a/tests/run-pass/move-arg-2-unique.rs b/tests/pass/move-arg-2-unique.rs similarity index 100% rename from tests/run-pass/move-arg-2-unique.rs rename to tests/pass/move-arg-2-unique.rs diff --git a/tests/run-pass/move-arg-3-unique.rs b/tests/pass/move-arg-3-unique.rs similarity index 100% rename from tests/run-pass/move-arg-3-unique.rs rename to tests/pass/move-arg-3-unique.rs diff --git a/tests/run-pass/move-uninit-primval.rs b/tests/pass/move-uninit-primval.rs similarity index 100% rename from tests/run-pass/move-uninit-primval.rs rename to tests/pass/move-uninit-primval.rs diff --git a/tests/run-pass/mpsc.rs b/tests/pass/mpsc.rs similarity index 100% rename from tests/run-pass/mpsc.rs rename to tests/pass/mpsc.rs diff --git a/tests/run-pass/multi_arg_closure.rs b/tests/pass/multi_arg_closure.rs similarity index 100% rename from tests/run-pass/multi_arg_closure.rs rename to tests/pass/multi_arg_closure.rs diff --git a/tests/run-pass/negative_discriminant.rs b/tests/pass/negative_discriminant.rs similarity index 100% rename from tests/run-pass/negative_discriminant.rs rename to tests/pass/negative_discriminant.rs diff --git a/tests/run-pass/observed_local_mut.rs b/tests/pass/observed_local_mut.rs similarity index 100% rename from tests/run-pass/observed_local_mut.rs rename to tests/pass/observed_local_mut.rs diff --git a/tests/run-pass/option_box_transmute_ptr.rs b/tests/pass/option_box_transmute_ptr.rs similarity index 100% rename from tests/run-pass/option_box_transmute_ptr.rs rename to tests/pass/option_box_transmute_ptr.rs diff --git a/tests/run-pass/option_eq.rs b/tests/pass/option_eq.rs similarity index 100% rename from tests/run-pass/option_eq.rs rename to tests/pass/option_eq.rs diff --git a/tests/run-pass/overflow_checks_off.rs b/tests/pass/overflow_checks_off.rs similarity index 100% rename from tests/run-pass/overflow_checks_off.rs rename to tests/pass/overflow_checks_off.rs diff --git a/tests/run-pass/overloaded-calls-simple.rs b/tests/pass/overloaded-calls-simple.rs similarity index 100% rename from tests/run-pass/overloaded-calls-simple.rs rename to tests/pass/overloaded-calls-simple.rs diff --git a/tests/run-pass/packed_struct.rs b/tests/pass/packed_struct.rs similarity index 100% rename from tests/run-pass/packed_struct.rs rename to tests/pass/packed_struct.rs diff --git a/tests/run-pass/panic/catch_panic.rs b/tests/pass/panic/catch_panic.rs similarity index 100% rename from tests/run-pass/panic/catch_panic.rs rename to tests/pass/panic/catch_panic.rs diff --git a/tests/run-pass/panic/catch_panic.stderr b/tests/pass/panic/catch_panic.stderr similarity index 100% rename from tests/run-pass/panic/catch_panic.stderr rename to tests/pass/panic/catch_panic.stderr diff --git a/tests/run-pass/panic/concurrent-panic.rs b/tests/pass/panic/concurrent-panic.rs similarity index 100% rename from tests/run-pass/panic/concurrent-panic.rs rename to tests/pass/panic/concurrent-panic.rs diff --git a/tests/run-pass/panic/concurrent-panic.stderr b/tests/pass/panic/concurrent-panic.stderr similarity index 100% rename from tests/run-pass/panic/concurrent-panic.stderr rename to tests/pass/panic/concurrent-panic.stderr diff --git a/tests/run-pass/panic/std-panic-locations.rs b/tests/pass/panic/std-panic-locations.rs similarity index 100% rename from tests/run-pass/panic/std-panic-locations.rs rename to tests/pass/panic/std-panic-locations.rs diff --git a/tests/run-pass/partially-uninit.rs b/tests/pass/partially-uninit.rs similarity index 100% rename from tests/run-pass/partially-uninit.rs rename to tests/pass/partially-uninit.rs diff --git a/tests/run-pass/pointers.rs b/tests/pass/pointers.rs similarity index 100% rename from tests/run-pass/pointers.rs rename to tests/pass/pointers.rs diff --git a/tests/run-pass/portable-simd.rs b/tests/pass/portable-simd.rs similarity index 100% rename from tests/run-pass/portable-simd.rs rename to tests/pass/portable-simd.rs diff --git a/tests/run-pass/products.rs b/tests/pass/products.rs similarity index 100% rename from tests/run-pass/products.rs rename to tests/pass/products.rs diff --git a/tests/run-pass/ptr_int_casts.rs b/tests/pass/ptr_int_casts.rs similarity index 100% rename from tests/run-pass/ptr_int_casts.rs rename to tests/pass/ptr_int_casts.rs diff --git a/tests/run-pass/ptr_int_permissive_provenance.rs b/tests/pass/ptr_int_permissive_provenance.rs similarity index 100% rename from tests/run-pass/ptr_int_permissive_provenance.rs rename to tests/pass/ptr_int_permissive_provenance.rs diff --git a/tests/run-pass/ptr_offset.rs b/tests/pass/ptr_offset.rs similarity index 100% rename from tests/run-pass/ptr_offset.rs rename to tests/pass/ptr_offset.rs diff --git a/tests/run-pass/ptr_raw.rs b/tests/pass/ptr_raw.rs similarity index 100% rename from tests/run-pass/ptr_raw.rs rename to tests/pass/ptr_raw.rs diff --git a/tests/run-pass/rc.rs b/tests/pass/rc.rs similarity index 100% rename from tests/run-pass/rc.rs rename to tests/pass/rc.rs diff --git a/tests/run-pass/recursive_static.rs b/tests/pass/recursive_static.rs similarity index 100% rename from tests/run-pass/recursive_static.rs rename to tests/pass/recursive_static.rs diff --git a/tests/run-pass/reentrant-println.rs b/tests/pass/reentrant-println.rs similarity index 100% rename from tests/run-pass/reentrant-println.rs rename to tests/pass/reentrant-println.rs diff --git a/tests/run-pass/reentrant-println.stdout b/tests/pass/reentrant-println.stdout similarity index 100% rename from tests/run-pass/reentrant-println.stdout rename to tests/pass/reentrant-println.stdout diff --git a/tests/run-pass/regions-lifetime-nonfree-late-bound.rs b/tests/pass/regions-lifetime-nonfree-late-bound.rs similarity index 100% rename from tests/run-pass/regions-lifetime-nonfree-late-bound.rs rename to tests/pass/regions-lifetime-nonfree-late-bound.rs diff --git a/tests/run-pass/regions-mock-trans.rs b/tests/pass/regions-mock-trans.rs similarity index 100% rename from tests/run-pass/regions-mock-trans.rs rename to tests/pass/regions-mock-trans.rs diff --git a/tests/run-pass/rename_std.rs b/tests/pass/rename_std.rs similarity index 100% rename from tests/run-pass/rename_std.rs rename to tests/pass/rename_std.rs diff --git a/tests/run-pass/rfc1623.rs b/tests/pass/rfc1623.rs similarity index 100% rename from tests/run-pass/rfc1623.rs rename to tests/pass/rfc1623.rs diff --git a/tests/run-pass/rust-lang-org.rs b/tests/pass/rust-lang-org.rs similarity index 100% rename from tests/run-pass/rust-lang-org.rs rename to tests/pass/rust-lang-org.rs diff --git a/tests/run-pass/send-is-not-static-par-for.rs b/tests/pass/send-is-not-static-par-for.rs similarity index 100% rename from tests/run-pass/send-is-not-static-par-for.rs rename to tests/pass/send-is-not-static-par-for.rs diff --git a/tests/run-pass/sendable-class.rs b/tests/pass/sendable-class.rs similarity index 100% rename from tests/run-pass/sendable-class.rs rename to tests/pass/sendable-class.rs diff --git a/tests/run-pass/simd-intrinsic-generic-elements.rs b/tests/pass/simd-intrinsic-generic-elements.rs similarity index 100% rename from tests/run-pass/simd-intrinsic-generic-elements.rs rename to tests/pass/simd-intrinsic-generic-elements.rs diff --git a/tests/run-pass/slices.rs b/tests/pass/slices.rs similarity index 100% rename from tests/run-pass/slices.rs rename to tests/pass/slices.rs diff --git a/tests/run-pass/small_enum_size_bug.rs b/tests/pass/small_enum_size_bug.rs similarity index 100% rename from tests/run-pass/small_enum_size_bug.rs rename to tests/pass/small_enum_size_bug.rs diff --git a/tests/run-pass/specialization.rs b/tests/pass/specialization.rs similarity index 100% rename from tests/run-pass/specialization.rs rename to tests/pass/specialization.rs diff --git a/tests/run-pass/stacked-borrows/2phase.rs b/tests/pass/stacked-borrows/2phase.rs similarity index 100% rename from tests/run-pass/stacked-borrows/2phase.rs rename to tests/pass/stacked-borrows/2phase.rs diff --git a/tests/run-pass/stacked-borrows/generators-self-referential.rs b/tests/pass/stacked-borrows/generators-self-referential.rs similarity index 100% rename from tests/run-pass/stacked-borrows/generators-self-referential.rs rename to tests/pass/stacked-borrows/generators-self-referential.rs diff --git a/tests/run-pass/stacked-borrows/int-to-ptr.rs b/tests/pass/stacked-borrows/int-to-ptr.rs similarity index 100% rename from tests/run-pass/stacked-borrows/int-to-ptr.rs rename to tests/pass/stacked-borrows/int-to-ptr.rs diff --git a/tests/run-pass/stacked-borrows/interior_mutability.rs b/tests/pass/stacked-borrows/interior_mutability.rs similarity index 100% rename from tests/run-pass/stacked-borrows/interior_mutability.rs rename to tests/pass/stacked-borrows/interior_mutability.rs diff --git a/tests/run-pass/stacked-borrows/refcell.rs b/tests/pass/stacked-borrows/refcell.rs similarity index 100% rename from tests/run-pass/stacked-borrows/refcell.rs rename to tests/pass/stacked-borrows/refcell.rs diff --git a/tests/run-pass/stacked-borrows/stacked-borrows.rs b/tests/pass/stacked-borrows/stacked-borrows.rs similarity index 100% rename from tests/run-pass/stacked-borrows/stacked-borrows.rs rename to tests/pass/stacked-borrows/stacked-borrows.rs diff --git a/tests/run-pass/stacked-borrows/stacked-borrows.stderr b/tests/pass/stacked-borrows/stacked-borrows.stderr similarity index 100% rename from tests/run-pass/stacked-borrows/stacked-borrows.stderr rename to tests/pass/stacked-borrows/stacked-borrows.stderr diff --git a/tests/run-pass/start.rs b/tests/pass/start.rs similarity index 100% rename from tests/run-pass/start.rs rename to tests/pass/start.rs diff --git a/tests/run-pass/start.stdout b/tests/pass/start.stdout similarity index 100% rename from tests/run-pass/start.stdout rename to tests/pass/start.stdout diff --git a/tests/run-pass/static_memory_modification.rs b/tests/pass/static_memory_modification.rs similarity index 100% rename from tests/run-pass/static_memory_modification.rs rename to tests/pass/static_memory_modification.rs diff --git a/tests/run-pass/static_mut.rs b/tests/pass/static_mut.rs similarity index 100% rename from tests/run-pass/static_mut.rs rename to tests/pass/static_mut.rs diff --git a/tests/run-pass/strings.rs b/tests/pass/strings.rs similarity index 100% rename from tests/run-pass/strings.rs rename to tests/pass/strings.rs diff --git a/tests/run-pass/subslice_array.rs b/tests/pass/subslice_array.rs similarity index 100% rename from tests/run-pass/subslice_array.rs rename to tests/pass/subslice_array.rs diff --git a/tests/run-pass/sums.rs b/tests/pass/sums.rs similarity index 100% rename from tests/run-pass/sums.rs rename to tests/pass/sums.rs diff --git a/tests/run-pass/tag-align-dyn-u64.rs b/tests/pass/tag-align-dyn-u64.rs similarity index 100% rename from tests/run-pass/tag-align-dyn-u64.rs rename to tests/pass/tag-align-dyn-u64.rs diff --git a/tests/run-pass/threadleak_ignored.rs b/tests/pass/threadleak_ignored.rs similarity index 100% rename from tests/run-pass/threadleak_ignored.rs rename to tests/pass/threadleak_ignored.rs diff --git a/tests/run-pass/threadleak_ignored.stderr b/tests/pass/threadleak_ignored.stderr similarity index 100% rename from tests/run-pass/threadleak_ignored.stderr rename to tests/pass/threadleak_ignored.stderr diff --git a/tests/run-pass/time.rs b/tests/pass/time.rs similarity index 100% rename from tests/run-pass/time.rs rename to tests/pass/time.rs diff --git a/tests/run-pass/too-large-primval-write-problem.rs b/tests/pass/too-large-primval-write-problem.rs similarity index 100% rename from tests/run-pass/too-large-primval-write-problem.rs rename to tests/pass/too-large-primval-write-problem.rs diff --git a/tests/run-pass/track-alloc-1.rs b/tests/pass/track-alloc-1.rs similarity index 100% rename from tests/run-pass/track-alloc-1.rs rename to tests/pass/track-alloc-1.rs diff --git a/tests/run-pass/track-alloc-1.stderr b/tests/pass/track-alloc-1.stderr similarity index 100% rename from tests/run-pass/track-alloc-1.stderr rename to tests/pass/track-alloc-1.stderr diff --git a/tests/run-pass/track-caller-attribute.rs b/tests/pass/track-caller-attribute.rs similarity index 100% rename from tests/run-pass/track-caller-attribute.rs rename to tests/pass/track-caller-attribute.rs diff --git a/tests/run-pass/transmute_fat.rs b/tests/pass/transmute_fat.rs similarity index 100% rename from tests/run-pass/transmute_fat.rs rename to tests/pass/transmute_fat.rs diff --git a/tests/run-pass/trivial.rs b/tests/pass/trivial.rs similarity index 100% rename from tests/run-pass/trivial.rs rename to tests/pass/trivial.rs diff --git a/tests/run-pass/try-operator-custom.rs b/tests/pass/try-operator-custom.rs similarity index 100% rename from tests/run-pass/try-operator-custom.rs rename to tests/pass/try-operator-custom.rs diff --git a/tests/run-pass/tuple_like_enum_variant_constructor.rs b/tests/pass/tuple_like_enum_variant_constructor.rs similarity index 100% rename from tests/run-pass/tuple_like_enum_variant_constructor.rs rename to tests/pass/tuple_like_enum_variant_constructor.rs diff --git a/tests/run-pass/tuple_like_enum_variant_constructor_pointer_opt.rs b/tests/pass/tuple_like_enum_variant_constructor_pointer_opt.rs similarity index 100% rename from tests/run-pass/tuple_like_enum_variant_constructor_pointer_opt.rs rename to tests/pass/tuple_like_enum_variant_constructor_pointer_opt.rs diff --git a/tests/run-pass/tuple_like_enum_variant_constructor_struct_pointer_opt.rs b/tests/pass/tuple_like_enum_variant_constructor_struct_pointer_opt.rs similarity index 100% rename from tests/run-pass/tuple_like_enum_variant_constructor_struct_pointer_opt.rs rename to tests/pass/tuple_like_enum_variant_constructor_struct_pointer_opt.rs diff --git a/tests/run-pass/tuple_like_struct_constructor.rs b/tests/pass/tuple_like_struct_constructor.rs similarity index 100% rename from tests/run-pass/tuple_like_struct_constructor.rs rename to tests/pass/tuple_like_struct_constructor.rs diff --git a/tests/run-pass/u128.rs b/tests/pass/u128.rs similarity index 100% rename from tests/run-pass/u128.rs rename to tests/pass/u128.rs diff --git a/tests/run-pass/uninit_number_ignored.rs b/tests/pass/uninit_number_ignored.rs similarity index 100% rename from tests/run-pass/uninit_number_ignored.rs rename to tests/pass/uninit_number_ignored.rs diff --git a/tests/run-pass/union-overwrite.rs b/tests/pass/union-overwrite.rs similarity index 100% rename from tests/run-pass/union-overwrite.rs rename to tests/pass/union-overwrite.rs diff --git a/tests/run-pass/union.rs b/tests/pass/union.rs similarity index 100% rename from tests/run-pass/union.rs rename to tests/pass/union.rs diff --git a/tests/run-pass/unops.rs b/tests/pass/unops.rs similarity index 100% rename from tests/run-pass/unops.rs rename to tests/pass/unops.rs diff --git a/tests/run-pass/unsized-tuple-impls.rs b/tests/pass/unsized-tuple-impls.rs similarity index 100% rename from tests/run-pass/unsized-tuple-impls.rs rename to tests/pass/unsized-tuple-impls.rs diff --git a/tests/run-pass/validation_lifetime_resolution.rs b/tests/pass/validation_lifetime_resolution.rs similarity index 100% rename from tests/run-pass/validation_lifetime_resolution.rs rename to tests/pass/validation_lifetime_resolution.rs diff --git a/tests/run-pass/vec-matching-fold.rs b/tests/pass/vec-matching-fold.rs similarity index 100% rename from tests/run-pass/vec-matching-fold.rs rename to tests/pass/vec-matching-fold.rs diff --git a/tests/run-pass/vec.rs b/tests/pass/vec.rs similarity index 100% rename from tests/run-pass/vec.rs rename to tests/pass/vec.rs diff --git a/tests/run-pass/vecdeque.rs b/tests/pass/vecdeque.rs similarity index 100% rename from tests/run-pass/vecdeque.rs rename to tests/pass/vecdeque.rs diff --git a/tests/run-pass/vecdeque.stdout b/tests/pass/vecdeque.stdout similarity index 100% rename from tests/run-pass/vecdeque.stdout rename to tests/pass/vecdeque.stdout diff --git a/tests/run-pass/volatile.rs b/tests/pass/volatile.rs similarity index 100% rename from tests/run-pass/volatile.rs rename to tests/pass/volatile.rs diff --git a/tests/run-pass/without-validation.rs b/tests/pass/without-validation.rs similarity index 100% rename from tests/run-pass/without-validation.rs rename to tests/pass/without-validation.rs diff --git a/tests/run-pass/write-bytes.rs b/tests/pass/write-bytes.rs similarity index 100% rename from tests/run-pass/write-bytes.rs rename to tests/pass/write-bytes.rs diff --git a/tests/run-pass/wtf8.rs b/tests/pass/wtf8.rs similarity index 100% rename from tests/run-pass/wtf8.rs rename to tests/pass/wtf8.rs diff --git a/tests/run-pass/zst.rs b/tests/pass/zst.rs similarity index 100% rename from tests/run-pass/zst.rs rename to tests/pass/zst.rs diff --git a/tests/run-pass/zst_box.rs b/tests/pass/zst_box.rs similarity index 100% rename from tests/run-pass/zst_box.rs rename to tests/pass/zst_box.rs diff --git a/tests/run-pass/zst_variant_drop.rs b/tests/pass/zst_variant_drop.rs similarity index 100% rename from tests/run-pass/zst_variant_drop.rs rename to tests/pass/zst_variant_drop.rs From 0b7a148ad9e5b990c9d6278f5010959afdac90ed Mon Sep 17 00:00:00 2001 From: DrMeepster <19316085+DrMeepster@users.noreply.github.com> Date: Wed, 1 Jun 2022 17:32:01 -0700 Subject: [PATCH 3148/3747] add test for backtrace with global allocator --- tests/pass/backtrace-global-alloc.rs | 13 +++++++++++ tests/pass/backtrace-global-alloc.stderr | 28 ++++++++++++++++++++++++ 2 files changed, 41 insertions(+) create mode 100644 tests/pass/backtrace-global-alloc.rs create mode 100644 tests/pass/backtrace-global-alloc.stderr diff --git a/tests/pass/backtrace-global-alloc.rs b/tests/pass/backtrace-global-alloc.rs new file mode 100644 index 0000000000000..8c51bf62706e2 --- /dev/null +++ b/tests/pass/backtrace-global-alloc.rs @@ -0,0 +1,13 @@ +// compile-flags: -Zmiri-disable-isolation + +#![feature(backtrace)] + +use std::alloc::System; +use std::backtrace::Backtrace; + +#[global_allocator] +static GLOBAL_ALLOCATOR: System = System; + +fn main() { + eprint!("{}", Backtrace::capture()); +} diff --git a/tests/pass/backtrace-global-alloc.stderr b/tests/pass/backtrace-global-alloc.stderr new file mode 100644 index 0000000000000..c48061d64d088 --- /dev/null +++ b/tests/pass/backtrace-global-alloc.stderr @@ -0,0 +1,28 @@ + 0: main + at $DIR/backtrace-global-alloc.rs:LL:CC + 1: >::call_once - shim(fn()) + at RUSTLIB/core/src/ops/function.rs:LL:CC + 2: std::sys_common::backtrace::__rust_begin_short_backtrace + at RUSTLIB/std/src/sys_common/backtrace.rs:LL:CC + 3: std::rt::lang_start::{closure#0} + at RUSTLIB/std/src/rt.rs:LL:CC + 4: std::ops::function::impls::call_once + at RUSTLIB/core/src/ops/function.rs:LL:CC + 5: std::panicking::r#try::do_call + at RUSTLIB/std/src/panicking.rs:LL:CC + 6: std::panicking::r#try + at RUSTLIB/std/src/panicking.rs:LL:CC + 7: std::panic::catch_unwind + at RUSTLIB/std/src/panic.rs:LL:CC + 8: std::rt::lang_start_internal::{closure#2} + at RUSTLIB/std/src/rt.rs:LL:CC + 9: std::panicking::r#try::do_call + at RUSTLIB/std/src/panicking.rs:LL:CC + 10: std::panicking::r#try + at RUSTLIB/std/src/panicking.rs:LL:CC + 11: std::panic::catch_unwind + at RUSTLIB/std/src/panic.rs:LL:CC + 12: std::rt::lang_start_internal + at RUSTLIB/std/src/rt.rs:LL:CC + 13: std::rt::lang_start + at RUSTLIB/std/src/rt.rs:LL:CC From e79a331fea9ee9d772de8ffabd7c8aa4cb33dcea Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 2 Jun 2022 15:11:22 -0400 Subject: [PATCH 3149/3747] do not pass TyCtxt by reference --- src/helpers.rs | 2 +- src/machine.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index d9a7edcc11350..8339ecde121e8 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -858,7 +858,7 @@ pub fn isolation_abort_error<'tcx>(name: &str) -> InterpResult<'tcx> { /// Retrieve the list of local crates that should have been passed by cargo-miri in /// MIRI_LOCAL_CRATES and turn them into `CrateNum`s. -pub fn get_local_crates(tcx: &TyCtxt<'_>) -> Vec { +pub fn get_local_crates(tcx: TyCtxt<'_>) -> Vec { // Convert the local crate names from the passed-in config into CrateNums so that they can // be looked up quickly during execution let local_crate_names = std::env::var("MIRI_LOCAL_CRATES") diff --git a/src/machine.rs b/src/machine.rs index 1cb815706195b..9a358bb6d53ae 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -327,7 +327,7 @@ pub struct Evaluator<'mir, 'tcx> { impl<'mir, 'tcx> Evaluator<'mir, 'tcx> { pub(crate) fn new(config: &MiriConfig, layout_cx: LayoutCx<'tcx, TyCtxt<'tcx>>) -> Self { - let local_crates = helpers::get_local_crates(&layout_cx.tcx); + let local_crates = helpers::get_local_crates(layout_cx.tcx); let layouts = PrimitiveLayouts::new(layout_cx).expect("Couldn't get layouts of primitive types"); let profiler = config.measureme_out.as_ref().map(|out| { From bc5da2b5a74e959445f4d12802fac90203c3b924 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 2 Jun 2022 21:09:10 -0400 Subject: [PATCH 3150/3747] test ui output also in rustc test suite --- tests/compiletest.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/compiletest.rs b/tests/compiletest.rs index 3b6cf6a6d1fda..fef2d1f7a588b 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -38,7 +38,7 @@ fn run_tests(mode: Mode, path: &str, target: Option) { flags.push(target.clone()); } - let skip_ui_checks = in_rustc_test_suite || env::var_os("MIRI_SKIP_UI_CHECKS").is_some(); + let skip_ui_checks = env::var_os("MIRI_SKIP_UI_CHECKS").is_some(); let output_conflict_handling = match (env::var_os("MIRI_BLESS").is_some(), skip_ui_checks) { (false, false) => OutputConflictHandling::Error, From 2b9c45f96f57069396e2029583aa762ecca569d4 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 3 Jun 2022 07:36:05 -0400 Subject: [PATCH 3151/3747] delete stale stderr files --- .../backtrace/bad-backtrace-version.stderr | 14 ------------- tests/fail/fs/unix_open_too_many_args.stderr | 20 ------------------- tests/fail/null_pointer_deref.stderr | 15 -------------- tests/fail/null_pointer_deref_zst.stderr | 15 -------------- tests/fail/null_pointer_write.stderr | 15 -------------- tests/fail/null_pointer_write_zst.stderr | 17 ---------------- tests/fail/ptr_integer_array_transmute.stderr | 15 -------------- tests/fail/ptr_integer_transmute.stderr | 15 -------------- tests/fail/slice-too-big.stderr | 15 -------------- tests/fail/strict-provenance-offset.stderr | 16 --------------- tests/fail/strict_provenance_transmute.stderr | 20 ------------------- tests/fail/too-big-slice.stderr | 15 -------------- tests/fail/too-big-unsized.stderr | 15 -------------- tests/fail/uninit_float.stderr | 15 -------------- tests/fail/uninit_integer.stderr | 15 -------------- tests/fail/uninit_integer_signed.stderr | 15 -------------- 16 files changed, 252 deletions(-) delete mode 100644 tests/fail/backtrace/bad-backtrace-version.stderr delete mode 100644 tests/fail/fs/unix_open_too_many_args.stderr delete mode 100644 tests/fail/null_pointer_deref.stderr delete mode 100644 tests/fail/null_pointer_deref_zst.stderr delete mode 100644 tests/fail/null_pointer_write.stderr delete mode 100644 tests/fail/null_pointer_write_zst.stderr delete mode 100644 tests/fail/ptr_integer_array_transmute.stderr delete mode 100644 tests/fail/ptr_integer_transmute.stderr delete mode 100644 tests/fail/slice-too-big.stderr delete mode 100644 tests/fail/strict-provenance-offset.stderr delete mode 100644 tests/fail/strict_provenance_transmute.stderr delete mode 100644 tests/fail/too-big-slice.stderr delete mode 100644 tests/fail/too-big-unsized.stderr delete mode 100644 tests/fail/uninit_float.stderr delete mode 100644 tests/fail/uninit_integer.stderr delete mode 100644 tests/fail/uninit_integer_signed.stderr diff --git a/tests/fail/backtrace/bad-backtrace-version.stderr b/tests/fail/backtrace/bad-backtrace-version.stderr deleted file mode 100644 index 4e7292732754b..0000000000000 --- a/tests/fail/backtrace/bad-backtrace-version.stderr +++ /dev/null @@ -1,14 +0,0 @@ -error: unsupported operation: unknown `miri_resolve_frame` flags 1 - --> $DIR/bad-backtrace-version.rs:7:9 - | -LL | miri_resolve_frame(0 as *mut _, 1); //~ ERROR unsupported operation: unknown `miri_resolve_frame` flags 1 - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unknown `miri_resolve_frame` flags 1 - | - = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support - - = note: inside `main` at $DIR/bad-backtrace-version.rs:7:9 - -note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace - -error: aborting due to previous error - diff --git a/tests/fail/fs/unix_open_too_many_args.stderr b/tests/fail/fs/unix_open_too_many_args.stderr deleted file mode 100644 index f71a44d34daba..0000000000000 --- a/tests/fail/fs/unix_open_too_many_args.stderr +++ /dev/null @@ -1,20 +0,0 @@ -error: Undefined Behavior: incorrect number of arguments for `open`: got 4, expected 2 or 3 - --> $DIR/unix_open_too_many_args.rs:15:24 - | -LL | let _fd = unsafe { libc::open(name_ptr, libc::O_RDONLY, 0, 0) }; //~ ERROR Undefined Behavior: incorrect number of arguments for `ope... - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ incorrect number of arguments for `open`: got 4, expected 2 or 3 - | - = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior - = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - - = note: inside `test_open_too_many_args` at $DIR/unix_open_too_many_args.rs:15:24 -note: inside `main` at $DIR/unix_open_too_many_args.rs:9:5 - --> $DIR/unix_open_too_many_args.rs:9:5 - | -LL | test_open_too_many_args(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^ - -note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace - -error: aborting due to previous error - diff --git a/tests/fail/null_pointer_deref.stderr b/tests/fail/null_pointer_deref.stderr deleted file mode 100644 index 0930160023f1b..0000000000000 --- a/tests/fail/null_pointer_deref.stderr +++ /dev/null @@ -1,15 +0,0 @@ -error: Undefined Behavior: dereferencing pointer failed: null pointer is not a valid pointer - --> $DIR/null_pointer_deref.rs:LL:CC - | -LL | let x: i32 = unsafe { *std::ptr::null() }; - | ^^^^^^^^^^^^^^^^^ dereferencing pointer failed: null pointer is not a valid pointer - | - = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior - = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - - = note: inside `main` at $DIR/null_pointer_deref.rs:LL:CC - -note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace - -error: aborting due to previous error - diff --git a/tests/fail/null_pointer_deref_zst.stderr b/tests/fail/null_pointer_deref_zst.stderr deleted file mode 100644 index 25fea50b15af1..0000000000000 --- a/tests/fail/null_pointer_deref_zst.stderr +++ /dev/null @@ -1,15 +0,0 @@ -error: Undefined Behavior: dereferencing pointer failed: null pointer is not a valid pointer - --> $DIR/null_pointer_deref_zst.rs:LL:CC - | -LL | let x: () = unsafe { *std::ptr::null() }; - | ^^^^^^^^^^^^^^^^^ dereferencing pointer failed: null pointer is not a valid pointer - | - = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior - = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - - = note: inside `main` at $DIR/null_pointer_deref_zst.rs:LL:CC - -note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace - -error: aborting due to previous error - diff --git a/tests/fail/null_pointer_write.stderr b/tests/fail/null_pointer_write.stderr deleted file mode 100644 index 5ac8cc7c20fdf..0000000000000 --- a/tests/fail/null_pointer_write.stderr +++ /dev/null @@ -1,15 +0,0 @@ -error: Undefined Behavior: dereferencing pointer failed: null pointer is not a valid pointer - --> $DIR/null_pointer_write.rs:LL:CC - | -LL | unsafe { *std::ptr::null_mut() = 0i32 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ dereferencing pointer failed: null pointer is not a valid pointer - | - = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior - = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - - = note: inside `main` at $DIR/null_pointer_write.rs:LL:CC - -note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace - -error: aborting due to previous error - diff --git a/tests/fail/null_pointer_write_zst.stderr b/tests/fail/null_pointer_write_zst.stderr deleted file mode 100644 index b40a9154f1826..0000000000000 --- a/tests/fail/null_pointer_write_zst.stderr +++ /dev/null @@ -1,17 +0,0 @@ -error: Undefined Behavior: memory access failed: null pointer is not a valid pointer - | - = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior - = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - - = note: inside `std::ptr::write::<[u8; 0]>` at rustc_src/src/ptr/mod.rs:LL:CC - = note: inside `std::ptr::mut_ptr::::write` at rustc_src/src/ptr/mut_ptr.rs:LL:CC -note: inside `main` at $DIR/null_pointer_write_zst.rs:LL:CC - --> $DIR/null_pointer_write_zst.rs:LL:CC - | -LL | unsafe { std::ptr::null_mut::<[u8; 0]>().write(zst_val) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace - -error: aborting due to previous error - diff --git a/tests/fail/ptr_integer_array_transmute.stderr b/tests/fail/ptr_integer_array_transmute.stderr deleted file mode 100644 index bc2ca54438ff9..0000000000000 --- a/tests/fail/ptr_integer_array_transmute.stderr +++ /dev/null @@ -1,15 +0,0 @@ -error: Undefined Behavior: type validation failed: encountered a pointer, but expected plain (non-pointer) bytes - --> $DIR/ptr_integer_array_transmute.rs:LL:CC - | -LL | let _i: [usize; 1] = unsafe { std::mem::transmute(r) }; - | ^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected plain (non-pointer) bytes - | - = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior - = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - - = note: inside `main` at $DIR/ptr_integer_array_transmute.rs:LL:CC - -note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace - -error: aborting due to previous error - diff --git a/tests/fail/ptr_integer_transmute.stderr b/tests/fail/ptr_integer_transmute.stderr deleted file mode 100644 index de9ebf4eb06b4..0000000000000 --- a/tests/fail/ptr_integer_transmute.stderr +++ /dev/null @@ -1,15 +0,0 @@ -error: Undefined Behavior: type validation failed: encountered pointer to $HEX[ALLOC], but expected initialized plain (non-pointer) bytes - --> $DIR/ptr_integer_transmute.rs:LL:CC - | -LL | let _i: usize = unsafe { std::mem::transmute(r) }; - | ^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to $HEX[ALLOC], but expected initialized plain (non-pointer) bytes - | - = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior - = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - - = note: inside `main` at $DIR/ptr_integer_transmute.rs:LL:CC - -note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace - -error: aborting due to previous error - diff --git a/tests/fail/slice-too-big.stderr b/tests/fail/slice-too-big.stderr deleted file mode 100644 index 13239506c633f..0000000000000 --- a/tests/fail/slice-too-big.stderr +++ /dev/null @@ -1,15 +0,0 @@ -error: Undefined Behavior: type validation failed: encountered invalid reference metadata: slice is bigger than largest supported object - --> $DIR/slice-too-big.rs:5:21 - | -LL | let _x: &[u8] = mem::transmute((ptr, usize::MAX)); //~ ERROR: invalid reference metadata: slice is bigger than largest supported object - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered invalid reference metadata: slice is bigger than largest supported object - | - = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior - = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - - = note: inside `main` at $DIR/slice-too-big.rs:5:21 - -note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace - -error: aborting due to previous error - diff --git a/tests/fail/strict-provenance-offset.stderr b/tests/fail/strict-provenance-offset.stderr deleted file mode 100644 index 482b7a404c513..0000000000000 --- a/tests/fail/strict-provenance-offset.stderr +++ /dev/null @@ -1,16 +0,0 @@ -error: Undefined Behavior: pointer arithmetic failed: $HEX is not a valid pointer - | - = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior - = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - - = note: inside `std::ptr::const_ptr::::offset` at rustc_src/src/ptr/const_ptr.rs:LL:CC -note: inside `main` at $DIR/strict-provenance-offset.rs:LL:CC - --> $DIR/strict-provenance-offset.rs:LL:CC - | -LL | let _ = unsafe { roundtrip.offset(1) }; - | ^^^^^^^^^^^^^^^^^^^ - -note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace - -error: aborting due to previous error - diff --git a/tests/fail/strict_provenance_transmute.stderr b/tests/fail/strict_provenance_transmute.stderr deleted file mode 100644 index c2140b9786ca5..0000000000000 --- a/tests/fail/strict_provenance_transmute.stderr +++ /dev/null @@ -1,20 +0,0 @@ -error: Undefined Behavior: type validation failed: encountered pointer to $HEX[ALLOC], but expected initialized plain (non-pointer) bytes - --> $DIR/strict_provenance_transmute.rs:LL:CC - | -LL | let left_int: usize = mem::transmute(left); - | ^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to $HEX[ALLOC], but expected initialized plain (non-pointer) bytes - | - = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior - = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - - = note: inside `deref` at $DIR/strict_provenance_transmute.rs:LL:CC -note: inside `main` at $DIR/strict_provenance_transmute.rs:LL:CC - --> $DIR/strict_provenance_transmute.rs:LL:CC - | -LL | deref(ptr1, ptr2.with_addr(ptr1.addr())); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace - -error: aborting due to previous error - diff --git a/tests/fail/too-big-slice.stderr b/tests/fail/too-big-slice.stderr deleted file mode 100644 index 11d20d3e623b0..0000000000000 --- a/tests/fail/too-big-slice.stderr +++ /dev/null @@ -1,15 +0,0 @@ -error: Undefined Behavior: type validation failed: encountered invalid reference metadata: slice is bigger than largest supported object - --> $DIR/too-big-slice.rs:LL:CC - | -LL | let _x: &[u8] = mem::transmute((ptr, usize::MAX)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered invalid reference metadata: slice is bigger than largest supported object - | - = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior - = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - - = note: inside `main` at $DIR/too-big-slice.rs:LL:CC - -note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace - -error: aborting due to previous error - diff --git a/tests/fail/too-big-unsized.stderr b/tests/fail/too-big-unsized.stderr deleted file mode 100644 index 0c7b7b23246ef..0000000000000 --- a/tests/fail/too-big-unsized.stderr +++ /dev/null @@ -1,15 +0,0 @@ -error: Undefined Behavior: type validation failed: encountered invalid reference metadata: total size is bigger than largest supported object - --> $DIR/too-big-unsized.rs:LL:CC - | -LL | let _x: &MySlice = mem::transmute((ptr, isize::MAX as usize)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered invalid reference metadata: total size is bigger than largest supported object - | - = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior - = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - - = note: inside `main` at $DIR/too-big-unsized.rs:LL:CC - -note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace - -error: aborting due to previous error - diff --git a/tests/fail/uninit_float.stderr b/tests/fail/uninit_float.stderr deleted file mode 100644 index 90cdc3ba0fae5..0000000000000 --- a/tests/fail/uninit_float.stderr +++ /dev/null @@ -1,15 +0,0 @@ -error: Undefined Behavior: type validation failed at .value: encountered uninitialized bytes, but expected initialized plain (non-pointer) bytes - --> $DIR/uninit_float.rs:LL:CC - | -LL | let _val = unsafe { std::mem::MaybeUninit::::uninit().assume_init() }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .value: encountered uninitialized bytes, but expected initialized plain (non-pointer) bytes - | - = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior - = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - - = note: inside `main` at $DIR/uninit_float.rs:LL:CC - -note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace - -error: aborting due to previous error - diff --git a/tests/fail/uninit_integer.stderr b/tests/fail/uninit_integer.stderr deleted file mode 100644 index 88b57c1d279a0..0000000000000 --- a/tests/fail/uninit_integer.stderr +++ /dev/null @@ -1,15 +0,0 @@ -error: Undefined Behavior: type validation failed at .value: encountered uninitialized bytes, but expected initialized plain (non-pointer) bytes - --> $DIR/uninit_integer.rs:LL:CC - | -LL | let _val = unsafe { std::mem::MaybeUninit::::uninit().assume_init() }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .value: encountered uninitialized bytes, but expected initialized plain (non-pointer) bytes - | - = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior - = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - - = note: inside `main` at $DIR/uninit_integer.rs:LL:CC - -note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace - -error: aborting due to previous error - diff --git a/tests/fail/uninit_integer_signed.stderr b/tests/fail/uninit_integer_signed.stderr deleted file mode 100644 index fc15462280a61..0000000000000 --- a/tests/fail/uninit_integer_signed.stderr +++ /dev/null @@ -1,15 +0,0 @@ -error: Undefined Behavior: type validation failed at .value: encountered uninitialized bytes, but expected initialized plain (non-pointer) bytes - --> $DIR/uninit_integer_signed.rs:LL:CC - | -LL | let _val = unsafe { std::mem::MaybeUninit::::uninit().assume_init() }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .value: encountered uninitialized bytes, but expected initialized plain (non-pointer) bytes - | - = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior - = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - - = note: inside `main` at $DIR/uninit_integer_signed.rs:LL:CC - -note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace - -error: aborting due to previous error - From 625b4ed3412b259c3e2aa0c171b65d745de6af8c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 3 Jun 2022 14:48:45 -0400 Subject: [PATCH 3152/3747] fix dangling reference in the README --- README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/README.md b/README.md index 824a8d3e328a4..a55ebcb125b38 100644 --- a/README.md +++ b/README.md @@ -296,8 +296,7 @@ environment variable. We first document the most relevant and most commonly used * `-Zmiri-strict-provenance` enables [strict provenance](https://github.com/rust-lang/rust/issues/95228) checking in Miri. This means that casting an integer to a pointer yields a result with 'invalid' provenance, i.e., with provenance - that cannot be used for any memory access. Also implies `-Zmiri-tag-raw-pointers` and - `-Zmiri-check-number-validity`. + that cannot be used for any memory access. Also implies `-Zmiri-tag-raw-pointers`. The remaining flags are for advanced use only, and more likely to change or be removed. Some of these are **unsound**, which means they can lead From bcc491a6babbbc8e555980ad157cf8a01777bfde Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matthias=20Kr=C3=BCger?= Date: Sat, 4 Jun 2022 13:40:54 +0200 Subject: [PATCH 3153/3747] clippy fixes clippy::redundant_closure clippy::unnecessary_mut_passed clippy::single_char_pattern clippy::clone_on_copy clippy::into_iter_on_ref clippy::extra_unused_lifetimes --- benches/fibonacci.rs | 4 ++-- benches/smoke.rs | 2 +- src/diagnostics.rs | 18 +++++++++--------- src/eval.rs | 2 +- src/helpers.rs | 4 ++-- src/shims/posix/fs.rs | 2 +- src/stacked_borrows.rs | 4 ++-- 7 files changed, 18 insertions(+), 18 deletions(-) diff --git a/benches/fibonacci.rs b/benches/fibonacci.rs index ebb1b5fd0b185..9a68a69e800f1 100644 --- a/benches/fibonacci.rs +++ b/benches/fibonacci.rs @@ -7,7 +7,7 @@ use crate::helpers::*; #[bench] fn fib(bencher: &mut Bencher) { - bencher.iter(|| fibonacci_helper::main()) + bencher.iter(fibonacci_helper::main) } #[bench] @@ -17,7 +17,7 @@ fn fib_miri(bencher: &mut Bencher) { #[bench] fn fib_iter(bencher: &mut Bencher) { - bencher.iter(|| fibonacci_helper_iterative::main()) + bencher.iter(fibonacci_helper_iterative::main) } #[bench] diff --git a/benches/smoke.rs b/benches/smoke.rs index 9229e972d7f3b..372cd0b22b7ae 100644 --- a/benches/smoke.rs +++ b/benches/smoke.rs @@ -7,7 +7,7 @@ use crate::helpers::*; #[bench] fn noop(bencher: &mut Bencher) { - bencher.iter(|| smoke_helper::main()) + bencher.iter(smoke_helper::main) } /* diff --git a/src/diagnostics.rs b/src/diagnostics.rs index 527ff032d6703..ace521f1bed02 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -166,32 +166,32 @@ pub fn report_error<'tcx, 'mir>( match history { Some(TagHistory::Tagged {tag, created: (created_range, created_span), invalidated, protected }) => { let msg = format!("{:?} was created by a retag at offsets {}", tag, HexRange(*created_range)); - helps.push((Some(created_span.clone()), msg)); + helps.push((Some(*created_span), msg)); if let Some((invalidated_range, invalidated_span)) = invalidated { let msg = format!("{:?} was later invalidated at offsets {}", tag, HexRange(*invalidated_range)); - helps.push((Some(invalidated_span.clone()), msg)); + helps.push((Some(*invalidated_span), msg)); } if let Some((protecting_tag, protecting_tag_span, protection_span)) = protected { - helps.push((Some(protecting_tag_span.clone()), format!("{:?} was protected due to {:?} which was created here", tag, protecting_tag))); - helps.push((Some(protection_span.clone()), "this protector is live for this call".to_string())); + helps.push((Some(*protecting_tag_span), format!("{:?} was protected due to {:?} which was created here", tag, protecting_tag))); + helps.push((Some(*protection_span), "this protector is live for this call".to_string())); } } Some(TagHistory::Untagged{ recently_created, recently_invalidated, matching_created, protected }) => { if let Some((range, span)) = recently_created { let msg = format!("tag was most recently created at offsets {}", HexRange(*range)); - helps.push((Some(span.clone()), msg)); + helps.push((Some(*span), msg)); } if let Some((range, span)) = recently_invalidated { let msg = format!("tag was later invalidated at offsets {}", HexRange(*range)); - helps.push((Some(span.clone()), msg)); + helps.push((Some(*span), msg)); } if let Some((range, span)) = matching_created { let msg = format!("this tag was also created here at offsets {}", HexRange(*range)); - helps.push((Some(span.clone()), msg)); + helps.push((Some(*span), msg)); } if let Some((protecting_tag, protecting_tag_span, protection_span)) = protected { - helps.push((Some(protecting_tag_span.clone()), format!("{:?} was protected due to a tag which was created here", protecting_tag))); - helps.push((Some(protection_span.clone()), "this protector is live for this call".to_string())); + helps.push((Some(*protecting_tag_span), format!("{:?} was protected due to a tag which was created here", protecting_tag))); + helps.push((Some(*protection_span), "this protector is live for this call".to_string())); } } None => {} diff --git a/src/eval.rs b/src/eval.rs index 39fccb0924334..a782dfa3fce17 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -491,6 +491,6 @@ mod tests { let cmd = String::from_utf16_lossy(&args_to_utf16_command_string( [r"C:\Program Files\", "arg1", "arg 2", "arg \" 3"].iter(), )); - assert_eq!(cmd.trim_end_matches("\0"), r#""C:\Program Files\" arg1 "arg 2" "arg \" 3""#); + assert_eq!(cmd.trim_end_matches('\0'), r#""C:\Program Files\" arg1 "arg 2" "arg \" 3""#); } } diff --git a/src/helpers.rs b/src/helpers.rs index 8339ecde121e8..cb4c3c293e939 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -817,7 +817,7 @@ pub struct CurrentSpan<'a, 'mir, 'tcx> { impl<'a, 'mir, 'tcx> CurrentSpan<'a, 'mir, 'tcx> { pub fn get(&mut self) -> Span { - *self.span.get_or_insert_with(|| Self::current_span(&self.machine)) + *self.span.get_or_insert_with(|| Self::current_span(self.machine)) } #[inline(never)] @@ -825,7 +825,7 @@ impl<'a, 'mir, 'tcx> CurrentSpan<'a, 'mir, 'tcx> { machine .threads .active_thread_stack() - .into_iter() + .iter() .rev() .find(|frame| { let def_id = frame.instance.def_id(); diff --git a/src/shims/posix/fs.rs b/src/shims/posix/fs.rs index 79539fd9c49e3..d02410664bd42 100644 --- a/src/shims/posix/fs.rs +++ b/src/shims/posix/fs.rs @@ -304,7 +304,7 @@ pub struct FileHandler { handles: BTreeMap>, } -impl<'tcx> FileHandler { +impl FileHandler { pub(crate) fn new(mute_stdout_stderr: bool) -> FileHandler { let mut handles: BTreeMap<_, Box> = BTreeMap::new(); handles.insert(0i32, Box::new(io::stdin())); diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 6cb71f43118ca..a19e30b113e32 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -684,9 +684,9 @@ impl Stacks { state: &GlobalState, ) -> InterpResult<'tcx> { trace!("deallocation with tag {:?}: {:?}, size {}", tag, alloc_id, range.size.bytes()); - let mut state = state.borrow_mut(); + let state = state.borrow(); self.for_each_mut(range, |offset, stack, history| { - stack.dealloc(tag, (alloc_id, range, offset), &mut state, history) + stack.dealloc(tag, (alloc_id, range, offset), &state, history) })?; Ok(()) } From bd7f83dc3773ee1a0ce6ebb5bf7c3a8cd04bb968 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 4 Jun 2022 11:48:46 -0400 Subject: [PATCH 3154/3747] run clippy on CI --- .github/workflows/ci.yml | 55 ++++++++++++++++++++-------------------- rustup-toolchain | 5 +++- 2 files changed, 31 insertions(+), 29 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f34e92571ff02..41cf159e0c801 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -72,20 +72,10 @@ jobs: shell: bash run: | if [[ ${{ github.event_name }} == 'schedule' ]]; then - RUSTC_HASH=$(git ls-remote https://github.com/rust-lang/rust.git master | awk '{print $1}') + ./rustup-toolchain HEAD --host ${{ matrix.host_target }} else - RUSTC_HASH=$(< rust-version) + ./rustup-toolchain "" --host ${{ matrix.host_target }} fi - # We need a nightly cargo for parts of the cargo miri test suite. - rustup-toolchain-install-master \ - -f \ - -n master "$RUSTC_HASH" \ - -c cargo \ - -c rust-src \ - -c rustc-dev \ - -c llvm-tools \ - --host ${{ matrix.host_target }} - rustup default master - name: Show Rust version run: | @@ -97,26 +87,35 @@ jobs: run: bash ./ci.sh fmt: - name: check formatting (ignored by bors) + name: formatting (ignored by bors) runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - name: Install latest nightly - uses: actions-rs/toolchain@v1 - with: - toolchain: nightly - components: rustfmt - default: true - - name: Check formatting (miri) - uses: actions-rs/cargo@v1 - with: - command: fmt - args: --all -- --check - - name: Check formatting (cargo-miri) - uses: actions-rs/cargo@v1 - with: - command: fmt - args: --manifest-path cargo-miri/Cargo.toml --all -- --check + run: | + rustup toolchain install nightly --component rustfmt + rustup override set nightly + - name: Formatting (miri, ui_test) + run: cargo fmt --all --check + - name: Formatting (cargo-miri) + run: cargo fmt --manifest-path cargo-miri/Cargo.toml --all --check + + clippy: + name: clippy (ignored by bors) + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - name: Install required toolchain + # We need a toolchain that can actually build Miri, just a nightly won't do. + run: | + cargo install rustup-toolchain-install-master # TODO: cache this? + ./rustup-toolchain "" -c clippy + - name: Clippy (miri) + run: cargo clippy --all-targets -- -D warnings + #- name: Clippy (ui_test) + # run: cargo clippy --manifest-path ui_test/Cargo.toml --all-targets -- -D warnings + - name: Clippy (cargo-miri) + run: cargo clippy --manifest-path cargo-miri/Cargo.toml --all-targets -- -D warnings # These jobs doesn't actually test anything, but they're only used to tell # bors the build completed, as there is no practical way to detect when a diff --git a/rustup-toolchain b/rustup-toolchain index 59ce6f85a0856..7e5d57349b9dd 100755 --- a/rustup-toolchain +++ b/rustup-toolchain @@ -12,6 +12,8 @@ set -e # ./rustup-toolchain HEAD: Update "miri" toolchain and `rust-version` file to latest rustc HEAD. # # ./rustup-toolchain $COMMIT: Update "miri" toolchain and `rust-version` file to match that commit. +# +# Any extra parameters are passed to `rustup-toolchain-install-master`. # Make sure rustup-toolchain-install-master is installed. if ! which rustup-toolchain-install-master >/dev/null; then @@ -28,6 +30,7 @@ else NEW_COMMIT="$1" fi echo "$NEW_COMMIT" > rust-version +shift # Check if we already are at that commit. CUR_COMMIT=$(rustc +miri --version -v 2>/dev/null | egrep "^commit-hash: " | cut -d " " -f 2) @@ -39,7 +42,7 @@ fi # Install and setup new toolchain. rustup toolchain uninstall miri -rustup-toolchain-install-master -n miri -c cargo -c rust-src -c rustc-dev -c llvm-tools -- "$NEW_COMMIT" +rustup-toolchain-install-master -n miri -c cargo -c rust-src -c rustc-dev -c llvm-tools "$@" -- "$NEW_COMMIT" rustup override set miri # Cleanup. From 151b6b13e0766c23833038db0a5b99a09562af53 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 4 Jun 2022 11:55:36 -0400 Subject: [PATCH 3155/3747] clippy: main crate --- benches/helpers/fibonacci_helper_iterative.rs | 2 +- src/lib.rs | 7 ++----- src/machine.rs | 6 +++--- src/shims/intrinsics.rs | 2 +- src/shims/posix/sync.rs | 7 ++++--- 5 files changed, 11 insertions(+), 13 deletions(-) diff --git a/benches/helpers/fibonacci_helper_iterative.rs b/benches/helpers/fibonacci_helper_iterative.rs index 59283be4820f7..0c2732828966c 100644 --- a/benches/helpers/fibonacci_helper_iterative.rs +++ b/benches/helpers/fibonacci_helper_iterative.rs @@ -9,7 +9,7 @@ fn fib(n: usize) -> usize { for _ in 0..n { let c = a; a = b; - b = c + b; + b += c; } a } diff --git a/src/lib.rs b/src/lib.rs index e571c8a001029..f7c256656a768 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -7,19 +7,16 @@ #![feature(io_error_more)] #![warn(rust_2018_idioms)] #![allow( - clippy::cast_lossless, clippy::collapsible_else_if, clippy::collapsible_if, clippy::comparison_chain, clippy::enum_variant_names, clippy::field_reassign_with_default, - clippy::from_over_into, - clippy::if_same_then_else, clippy::manual_map, - clippy::needless_lifetimes, clippy::new_without_default, clippy::single_match, - clippy::useless_format + clippy::useless_format, + clippy::derive_partial_eq_without_eq )] extern crate rustc_apfloat; diff --git a/src/machine.rs b/src/machine.rs index 9a358bb6d53ae..6a7cbe58711aa 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -89,10 +89,10 @@ pub enum MiriMemoryKind { Tls, } -impl Into> for MiriMemoryKind { +impl From for MemoryKind { #[inline(always)] - fn into(self) -> MemoryKind { - MemoryKind::Machine(self) + fn from(kind: MiriMemoryKind) -> MemoryKind { + MemoryKind::Machine(kind) } } diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 1f06971a3e70d..8d4da31fd0d77 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -1389,7 +1389,7 @@ fn bool_to_simd_element(b: bool, size: Size) -> Scalar { Scalar::from_int(val, size) } -fn simd_element_to_bool<'tcx>(elem: ImmTy<'tcx, Tag>) -> InterpResult<'tcx, bool> { +fn simd_element_to_bool(elem: ImmTy<'_, Tag>) -> InterpResult<'_, bool> { let val = elem.to_scalar()?.to_int(elem.layout.size)?; Ok(match val { 0 => false, diff --git a/src/shims/posix/sync.rs b/src/shims/posix/sync.rs index f56a309bf0789..373996312eaf6 100644 --- a/src/shims/posix/sync.rs +++ b/src/shims/posix/sync.rs @@ -535,9 +535,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx throw_ub_format!( "unlocked a PTHREAD_MUTEX_NORMAL mutex that was not locked by the current thread" ); - } else if kind == this.eval_libc("PTHREAD_MUTEX_ERRORCHECK")? { - this.eval_libc_i32("EPERM") - } else if kind == this.eval_libc("PTHREAD_MUTEX_RECURSIVE")? { + } else if kind == this.eval_libc("PTHREAD_MUTEX_ERRORCHECK")? + || kind == this.eval_libc("PTHREAD_MUTEX_RECURSIVE")? + { this.eval_libc_i32("EPERM") } else { throw_unsup_format!("called pthread_mutex_unlock on an unsupported type of mutex"); @@ -642,6 +642,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let id = rwlock_get_or_create_id(this, rwlock_op)?; let active_thread = this.get_active_thread(); + #[allow(clippy::if_same_then_else)] if this.rwlock_reader_unlock(id, active_thread) { Ok(0) } else if this.rwlock_writer_unlock(id, active_thread) { From 3d30aece836c5f524b49eb308ee516a09dd9e0a9 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 4 Jun 2022 12:11:23 -0400 Subject: [PATCH 3156/3747] clippy: cargo-miri --- cargo-miri/bin.rs | 49 ++++++++++++++++++++++++----------------------- 1 file changed, 25 insertions(+), 24 deletions(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index 34904279e94f1..ba885d307a85f 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -1,3 +1,5 @@ +#![allow(clippy::useless_format, clippy::derive_partial_eq_without_eq)] + mod version; use std::env; @@ -96,6 +98,9 @@ fn show_version() { // Only use `option_env` on vergen variables to ensure the build succeeds // when vergen failed to find the git info. if let Some(sha) = option_env!("VERGEN_GIT_SHA_SHORT") { + // This `unwrap` can never fail because if VERGEN_GIT_SHA_SHORT exists, then so does + // VERGEN_GIT_COMMIT_DATE. + #[allow(clippy::option_env_unwrap)] write!(&mut version, " ({} {})", sha, option_env!("VERGEN_GIT_COMMIT_DATE").unwrap()) .unwrap(); } @@ -135,16 +140,14 @@ impl> Iterator for ArgSplitFlagValue<'_, I> { fn next(&mut self) -> Option { let arg = self.args.next()?; - if arg.starts_with(self.name) { + if let Some(suffix) = arg.strip_prefix(self.name) { // Strip leading `name`. - let suffix = &arg[self.name.len()..]; if suffix.is_empty() { // This argument is exactly `name`; the next one is the value. return self.args.next().map(Ok); - } else if suffix.starts_with('=') { + } else if let Some(suffix) = suffix.strip_prefix('=') { // This argument is `name=value`; get the value. - // Strip leading `=`. - return Some(Ok(suffix[1..].to_owned())); + return Some(Ok(suffix.to_owned())); } } Some(Err(arg)) @@ -255,7 +258,7 @@ fn xargo_version() -> Option<(u32, u32, u32)> { let line = out .stderr .lines() - .nth(0) + .next() .expect("malformed `xargo --version` output: not at least one line") .expect("malformed `xargo --version` output: error reading first line"); let (name, version) = { @@ -285,7 +288,7 @@ fn xargo_version() -> Option<(u32, u32, u32)> { .expect("malformed `xargo --version` output: not a patch version piece") .parse() .expect("malformed `xargo --version` output: patch version is not an integer"); - if !version_pieces.next().is_none() { + if version_pieces.next().is_some() { panic!("malformed `xargo --version` output: more than three pieces in version"); } Some((major, minor, patch)) @@ -311,7 +314,7 @@ fn ask_to_run(mut cmd: Command, ask: bool, text: &str) { println!("Running `{:?}` to {}.", cmd, text); } - if cmd.status().expect(&format!("failed to execute {:?}", cmd)).success().not() { + if cmd.status().unwrap_or_else(|_| panic!("failed to execute {:?}", cmd)).success().not() { show_error(format!("failed to {}", text)); } } @@ -499,10 +502,11 @@ fn get_cargo_metadata() -> Metadata { for arg in ArgSplitFlagValue::new( env::args().skip(3), // skip the program name, "miri" and "run" / "test" config_flag, - ) { - if let Ok(config) = arg { - cmd.arg(config_flag).arg(config); - } + ) + // Only look at `Ok` + .flatten() + { + cmd.arg(config_flag).arg(arg); } let mut child = cmd .stdin(process::Stdio::null()) @@ -524,11 +528,11 @@ fn get_cargo_metadata() -> Metadata { /// Additionally, somewhere between cargo metadata and TyCtxt, '-' gets replaced with '_' so we /// make that same transformation here. fn local_crates(metadata: &Metadata) -> String { - assert!(metadata.workspace_members.len() > 0); + assert!(!metadata.workspace_members.is_empty()); let mut local_crates = String::new(); for member in &metadata.workspace_members { - let name = member.split(" ").nth(0).unwrap(); - let name = name.replace("-", "_"); + let name = member.split(' ').next().unwrap(); + let name = name.replace('-', "_"); local_crates.push_str(&name); local_crates.push(','); } @@ -708,7 +712,7 @@ fn phase_rustc(mut args: env::Args, phase: RustcPhase) { get_arg_flag_value("--crate-name").unwrap(), // This is technically a `-C` flag but the prefix seems unique enough... // (and cargo passes this before the filename so it should be unique) - get_arg_flag_value("extra-filename").unwrap_or(String::new()), + get_arg_flag_value("extra-filename").unwrap_or_default(), suffix, )); path @@ -808,11 +812,10 @@ fn phase_rustc(mut args: env::Args, phase: RustcPhase) { // Forward arguments, but remove "link" from "--emit" to make this a check-only build. let emit_flag = "--emit"; while let Some(arg) = args.next() { - if arg.starts_with(emit_flag) { + if let Some(val) = arg.strip_prefix(emit_flag) { // Patch this argument. First, extract its value. - let val = &arg[emit_flag.len()..]; - assert!(val.starts_with("="), "`cargo` should pass `--emit=X` as one argument"); - let val = &val[1..]; + let val = + val.strip_prefix('=').expect("`cargo` should pass `--emit=X` as one argument"); let mut val: Vec<_> = val.split(',').collect(); // Now make sure "link" is not in there, but "metadata" is. if let Some(i) = val.iter().position(|&s| s == "link") { @@ -937,12 +940,10 @@ fn phase_runner(binary: &Path, binary_args: env::Args, phase: RunnerPhase) { while let Some(arg) = args.next() { if arg == "--extern" { forward_patched_extern_arg(&mut args, &mut cmd); - } else if arg.starts_with(error_format_flag) { - let suffix = &arg[error_format_flag.len()..]; + } else if let Some(suffix) = arg.strip_prefix(error_format_flag) { assert!(suffix.starts_with('=')); // Drop this argument. - } else if arg.starts_with(json_flag) { - let suffix = &arg[json_flag.len()..]; + } else if let Some(suffix) = arg.strip_prefix(json_flag) { assert!(suffix.starts_with('=')); // Drop this argument. } else { From 32c03080f184704d4ccb19cd359a1d5784d78770 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 4 Jun 2022 19:43:46 -0400 Subject: [PATCH 3157/3747] rustup --- rust-version | 2 +- src/shims/windows/dlsym.rs | 1 + src/shims/windows/foreign_items.rs | 4 ++++ 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 09a847a94fbe6..e7a7ad9dd818c 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -c35035cefc709abddabfb28ecc6a326458d46ce2 +4e725bad73747a4c93a3ac53106e4b4006edc665 diff --git a/src/shims/windows/dlsym.rs b/src/shims/windows/dlsym.rs index fb0c334b3d938..60ef11b796088 100644 --- a/src/shims/windows/dlsym.rs +++ b/src/shims/windows/dlsym.rs @@ -18,6 +18,7 @@ impl Dlsym { pub fn from_str<'tcx>(name: &str) -> InterpResult<'tcx, Option> { Ok(match name { "GetSystemTimePreciseAsFileTime" => None, + "SetThreadDescription" => None, "NtWriteFile" => Some(Dlsym::NtWriteFile), _ => throw_unsup_format!("unsupported Windows dlsym: {}", name), }) diff --git a/src/shims/windows/foreign_items.rs b/src/shims/windows/foreign_items.rs index 1a9b2300f723c..05f9aed174765 100644 --- a/src/shims/windows/foreign_items.rs +++ b/src/shims/windows/foreign_items.rs @@ -415,6 +415,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // There is only one thread, so this always succeeds and returns TRUE. this.write_scalar(Scalar::from_i32(1), dest)?; } + "GetCurrentThread" if this.frame_in_std() => { + let [] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; + this.write_scalar(Scalar::from_machine_isize(1, this), dest)?; + } _ => return Ok(EmulateByNameResult::NotSupported), } From 4a852126b979d6a04f5ce2a0b132dcc88002cea1 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 5 Jun 2022 11:47:39 -0400 Subject: [PATCH 3158/3747] do not use int2ptr casts in strict provenance tests --- ...{strict-provenance-offset.rs => ptr_invalid_offset.rs} | 4 +++- ...provenance-offset.stderr => ptr_invalid_offset.stderr} | 4 ++-- tests/pass/slices.rs | 8 +++++--- 3 files changed, 10 insertions(+), 6 deletions(-) rename tests/fail/provenance/{strict-provenance-offset.rs => ptr_invalid_offset.rs} (59%) rename tests/fail/provenance/{strict-provenance-offset.stderr => ptr_invalid_offset.stderr} (89%) diff --git a/tests/fail/provenance/strict-provenance-offset.rs b/tests/fail/provenance/ptr_invalid_offset.rs similarity index 59% rename from tests/fail/provenance/strict-provenance-offset.rs rename to tests/fail/provenance/ptr_invalid_offset.rs index 6955d0243a9af..4447575405bb6 100644 --- a/tests/fail/provenance/strict-provenance-offset.rs +++ b/tests/fail/provenance/ptr_invalid_offset.rs @@ -1,9 +1,11 @@ // compile-flags: -Zmiri-strict-provenance // error-pattern: not a valid pointer +#![feature(strict_provenance)] fn main() { let x = 22; let ptr = &x as *const _ as *const u8; - let roundtrip = ptr as usize as *const u8; + let roundtrip = std::ptr::invalid::(ptr as usize); + // Not even offsetting this is allowed. let _ = unsafe { roundtrip.offset(1) }; } diff --git a/tests/fail/provenance/strict-provenance-offset.stderr b/tests/fail/provenance/ptr_invalid_offset.stderr similarity index 89% rename from tests/fail/provenance/strict-provenance-offset.stderr rename to tests/fail/provenance/ptr_invalid_offset.stderr index 8e3daca939dba..661fabf29afbf 100644 --- a/tests/fail/provenance/strict-provenance-offset.stderr +++ b/tests/fail/provenance/ptr_invalid_offset.stderr @@ -8,8 +8,8 @@ LL | unsafe { intrinsics::offset(self, count) } = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: inside `std::ptr::const_ptr::::offset` at RUSTLIB/core/src/ptr/const_ptr.rs:LL:CC -note: inside `main` at $DIR/strict-provenance-offset.rs:LL:CC - --> $DIR/strict-provenance-offset.rs:LL:CC +note: inside `main` at $DIR/ptr_invalid_offset.rs:LL:CC + --> $DIR/ptr_invalid_offset.rs:LL:CC | LL | let _ = unsafe { roundtrip.offset(1) }; | ^^^^^^^^^^^^^^^^^^^ diff --git a/tests/pass/slices.rs b/tests/pass/slices.rs index b6537b4f1b4de..6cdfbb7841ae0 100644 --- a/tests/pass/slices.rs +++ b/tests/pass/slices.rs @@ -3,8 +3,10 @@ #![feature(slice_as_chunks)] #![feature(slice_partition_dedup)] #![feature(layout_for_ptr)] +#![feature(strict_provenance)] use std::slice; +use std::ptr; fn slice_of_zst() { fn foo(v: &[T]) -> Option<&[T]> { @@ -25,7 +27,7 @@ fn slice_of_zst() { // In a slice of zero-size elements the pointer is meaningless. // Ensure iteration still works even if the pointer is at the end of the address space. - let slice: &[()] = unsafe { slice::from_raw_parts(-5isize as *const (), 10) }; + let slice: &[()] = unsafe { slice::from_raw_parts(ptr::invalid(-5isize as usize), 10) }; assert_eq!(slice.len(), 10); assert_eq!(slice.iter().count(), 10); @@ -38,7 +40,7 @@ fn slice_of_zst() { assert!(foo(slice).is_some()); // Test mutable iterators as well - let slice: &mut [()] = unsafe { slice::from_raw_parts_mut(-5isize as *mut (), 10) }; + let slice: &mut [()] = unsafe { slice::from_raw_parts_mut(ptr::invalid_mut(-5isize as usize), 10) }; assert_eq!(slice.len(), 10); assert_eq!(slice.iter_mut().count(), 10); @@ -254,7 +256,7 @@ fn test_for_invalidated_pointers() { fn large_raw_slice() { let size = isize::MAX as usize; // Creating a raw slice of size isize::MAX and asking for its size is okay. - let s = std::ptr::slice_from_raw_parts(1usize as *const u8, size); + let s = std::ptr::slice_from_raw_parts(ptr::invalid::(1), size); assert_eq!(size, unsafe { std::mem::size_of_val_raw(s) }); } From b2832008e236d20fdb1ba7d724d389295d1d2493 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 5 Jun 2022 12:14:57 -0400 Subject: [PATCH 3159/3747] add interesting data race test --- tests/fail/data_race/fence_after_load.rs | 24 ++++++++++++++++++++ tests/fail/data_race/fence_after_load.stderr | 17 ++++++++++++++ 2 files changed, 41 insertions(+) create mode 100644 tests/fail/data_race/fence_after_load.rs create mode 100644 tests/fail/data_race/fence_after_load.stderr diff --git a/tests/fail/data_race/fence_after_load.rs b/tests/fail/data_race/fence_after_load.rs new file mode 100644 index 0000000000000..b381715933866 --- /dev/null +++ b/tests/fail/data_race/fence_after_load.rs @@ -0,0 +1,24 @@ +// compile-flags: -Zmiri-disable-isolation +// ignore-windows: Concurrency on Windows is not supported yet. +use std::sync::Arc; +use std::sync::atomic::{AtomicUsize, Ordering, fence}; +use std::time::Duration; +use std::thread; + +fn main() { + static mut V: u32 = 0; + let a = Arc::new(AtomicUsize::default()); + let b = a.clone(); + thread::spawn(move || { + unsafe { V = 1 } + b.store(1, Ordering::SeqCst); + }); + thread::sleep(Duration::from_millis(100)); + fence(Ordering::SeqCst); + // Imagine the other thread's actions happening here. + assert_eq!(a.load(Ordering::Relaxed), 1); + // The fence is useless, since it did not happen-after the `store` in the other thread. + // Hence this is a data race. + // Also see https://github.com/rust-lang/miri/issues/2192. + unsafe { V = 2 } //~ERROR Data race detected +} diff --git a/tests/fail/data_race/fence_after_load.stderr b/tests/fail/data_race/fence_after_load.stderr new file mode 100644 index 0000000000000..14452391327a1 --- /dev/null +++ b/tests/fail/data_race/fence_after_load.stderr @@ -0,0 +1,17 @@ +warning: thread support is experimental and incomplete: weak memory effects are not emulated. + +error: Undefined Behavior: Data race detected between Write on Thread(id = 0, name = "main") and Write on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) + --> $DIR/fence_after_load.rs:LL:CC + | +LL | unsafe { V = 2 } + | ^^^^^ Data race detected between Write on Thread(id = 0, name = "main") and Write on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `main` at $DIR/fence_after_load.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error; 1 warning emitted + From 47745380cd3928779361d34327b622e3813cda93 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 5 Jun 2022 14:20:22 -0400 Subject: [PATCH 3160/3747] make Miri's scheduler proper round-robin --- src/thread.rs | 26 +++++++++++++++------- tests/pass/concurrency/spin_loops.rs | 33 ++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+), 8 deletions(-) create mode 100644 tests/pass/concurrency/spin_loops.rs diff --git a/src/thread.rs b/src/thread.rs index 5673af048fc53..b6fb866f714a4 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -518,16 +518,26 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { return Ok(SchedulingAction::ExecuteTimeoutCallback); } // No callbacks scheduled, pick a regular thread to execute. - // We need to pick a new thread for execution. - for (id, thread) in self.threads.iter_enumerated() { + // The active thread blocked or yielded. So we go search for another enabled thread. + // Curcially, we start searching at the current active thread ID, rather than at 0, since we + // want to avoid always scheduling threads 0 and 1 without ever making progress in thread 2. + // + // `skip(N)` means we start iterating at thread N, so we skip 1 more to start just *after* + // the active thread. Then after that we look at `take(N)`, i.e., the threads *before* the + // active thread. + let threads = self + .threads + .iter_enumerated() + .skip(self.active_thread.index() + 1) + .chain(self.threads.iter_enumerated().take(self.active_thread.index())); + for (id, thread) in threads { + debug_assert_ne!(self.active_thread, id); if thread.state == ThreadState::Enabled { - if !self.yield_active_thread || id != self.active_thread { - self.active_thread = id; - if let Some(data_race) = data_race { - data_race.thread_set_active(self.active_thread); - } - break; + self.active_thread = id; + if let Some(data_race) = data_race { + data_race.thread_set_active(self.active_thread); } + break; } } self.yield_active_thread = false; diff --git a/tests/pass/concurrency/spin_loops.rs b/tests/pass/concurrency/spin_loops.rs new file mode 100644 index 0000000000000..4229e54406815 --- /dev/null +++ b/tests/pass/concurrency/spin_loops.rs @@ -0,0 +1,33 @@ +// ignore-windows: Concurrency on Windows is not supported yet. + +use std::thread; +use std::sync::atomic::{AtomicUsize, Ordering}; + +static FLAG: AtomicUsize = AtomicUsize::new(0); + +// When a thread yields, Miri's scheduler used to pick the thread with the lowest ID +// that can run. IDs are assigned in thread creation order. +// This means we could make 2 threads infinitely ping-pong with each other while +// really there is a 3rd thread that we should schedule to make progress. + +fn main() { + let waiter1 = thread::spawn(|| { + while FLAG.load(Ordering::Acquire) == 0 { + // spin and wait + thread::yield_now(); + } + }); + let waiter2 = thread::spawn(|| { + while FLAG.load(Ordering::Acquire) == 0 { + // spin and wait + thread::yield_now(); + } + }); + let progress = thread::spawn(|| { + FLAG.store(1, Ordering::Release); + }); + // The first `join` blocks the main thread and thus takes it out of the equation. + waiter1.join().unwrap(); + waiter2.join().unwrap(); + progress.join().unwrap(); +} From 34b359be1ec89383baff1dba5f74f5bfe8beedd7 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 5 Jun 2022 14:31:44 -0400 Subject: [PATCH 3161/3747] more spin-loop-tests --- tests/pass/concurrency/spin_loops.rs | 65 +++++++++++++++++++++--- tests/pass/concurrency/spin_loops.stderr | 2 + 2 files changed, 59 insertions(+), 8 deletions(-) create mode 100644 tests/pass/concurrency/spin_loops.stderr diff --git a/tests/pass/concurrency/spin_loops.rs b/tests/pass/concurrency/spin_loops.rs index 4229e54406815..a6fceb03638dd 100644 --- a/tests/pass/concurrency/spin_loops.rs +++ b/tests/pass/concurrency/spin_loops.rs @@ -1,16 +1,17 @@ // ignore-windows: Concurrency on Windows is not supported yet. use std::thread; -use std::sync::atomic::{AtomicUsize, Ordering}; +use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering}; +use std::sync::mpsc; +use std::cell::Cell; -static FLAG: AtomicUsize = AtomicUsize::new(0); +/// When a thread yields, Miri's scheduler used to pick the thread with the lowest ID +/// that can run. IDs are assigned in thread creation order. +/// This means we could make 2 threads infinitely ping-pong with each other while +/// really there is a 3rd thread that we should schedule to make progress. +fn two_player_ping_pong() { + static FLAG: AtomicUsize = AtomicUsize::new(0); -// When a thread yields, Miri's scheduler used to pick the thread with the lowest ID -// that can run. IDs are assigned in thread creation order. -// This means we could make 2 threads infinitely ping-pong with each other while -// really there is a 3rd thread that we should schedule to make progress. - -fn main() { let waiter1 = thread::spawn(|| { while FLAG.load(Ordering::Acquire) == 0 { // spin and wait @@ -31,3 +32,51 @@ fn main() { waiter2.join().unwrap(); progress.join().unwrap(); } + +/// Based on a test by @jethrogb. +fn launcher() { + static THREAD2_LAUNCHED: AtomicBool = AtomicBool::new(false); + + for _ in 0..10 { + let (tx, rx) = mpsc::sync_channel(0); + THREAD2_LAUNCHED.store(false, Ordering::SeqCst); + + let jh = thread::spawn(move || { + struct RecvOnDrop(Cell>>); + + impl Drop for RecvOnDrop { + fn drop(&mut self) { + let rx = self.0.take().unwrap(); + while !THREAD2_LAUNCHED.load(Ordering::SeqCst) { + thread::yield_now(); + } + rx.recv().unwrap(); + } + } + + let tl_rx: RecvOnDrop = RecvOnDrop(Cell::new(None)); + tl_rx.0.set(Some(rx)); + }); + + let tx_clone = tx.clone(); + let jh2 = thread::spawn(move || { + THREAD2_LAUNCHED.store(true, Ordering::SeqCst); + jh.join().unwrap(); + tx_clone.send(()).expect_err( + "Expecting channel to be closed because thread 1 TLS destructors must've run", + ); + }); + + while !THREAD2_LAUNCHED.load(Ordering::SeqCst) { + thread::yield_now(); + } + thread::yield_now(); + tx.send(()).expect("Expecting channel to be live because thread 2 must block on join"); + jh2.join().unwrap(); + } +} + +fn main() { + two_player_ping_pong(); + launcher(); +} diff --git a/tests/pass/concurrency/spin_loops.stderr b/tests/pass/concurrency/spin_loops.stderr new file mode 100644 index 0000000000000..03676519d4f1c --- /dev/null +++ b/tests/pass/concurrency/spin_loops.stderr @@ -0,0 +1,2 @@ +warning: thread support is experimental and incomplete: weak memory effects are not emulated. + From d0a0369a24003da3800957f9bab01f631f76a792 Mon Sep 17 00:00:00 2001 From: infrandomness Date: Sun, 5 Jun 2022 22:29:30 +0200 Subject: [PATCH 3162/3747] Refactor POSIX to UNIX This renames the directory containing posix to unix; where applicable, it also rename functions with the word "posix" to "unix" --- src/machine.rs | 6 +++--- src/shims/dlsym.rs | 8 ++++---- src/shims/foreign_items.rs | 2 +- src/shims/mod.rs | 2 +- src/shims/{posix => unix}/dlsym.rs | 4 ++-- src/shims/{posix => unix}/foreign_items.rs | 10 +++++----- src/shims/{posix => unix}/fs.rs | 0 src/shims/{posix => unix}/linux/dlsym.rs | 0 src/shims/{posix => unix}/linux/foreign_items.rs | 8 ++++---- src/shims/{posix => unix}/linux/mod.rs | 0 src/shims/{posix => unix}/linux/sync.rs | 0 src/shims/{posix => unix}/macos/dlsym.rs | 0 src/shims/{posix => unix}/macos/foreign_items.rs | 4 ++-- src/shims/{posix => unix}/macos/mod.rs | 0 src/shims/{posix => unix}/mod.rs | 0 src/shims/{posix => unix}/sync.rs | 0 src/shims/{posix => unix}/thread.rs | 0 17 files changed, 22 insertions(+), 22 deletions(-) rename src/shims/{posix => unix}/dlsym.rs (94%) rename src/shims/{posix => unix}/foreign_items.rs (98%) rename src/shims/{posix => unix}/fs.rs (100%) rename src/shims/{posix => unix}/linux/dlsym.rs (100%) rename src/shims/{posix => unix}/linux/foreign_items.rs (98%) rename src/shims/{posix => unix}/linux/mod.rs (100%) rename src/shims/{posix => unix}/linux/sync.rs (100%) rename src/shims/{posix => unix}/macos/dlsym.rs (100%) rename src/shims/{posix => unix}/macos/foreign_items.rs (98%) rename src/shims/{posix => unix}/macos/mod.rs (100%) rename src/shims/{posix => unix}/mod.rs (100%) rename src/shims/{posix => unix}/sync.rs (100%) rename src/shims/{posix => unix}/thread.rs (100%) diff --git a/src/machine.rs b/src/machine.rs index 6a7cbe58711aa..369bb92c6f398 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -28,7 +28,7 @@ use rustc_span::Symbol; use rustc_target::abi::Size; use rustc_target::spec::abi::Abi; -use crate::{shims::posix::FileHandler, *}; +use crate::{shims::unix::FileHandler, *}; // Some global facts about the emulated machine. pub const PAGE_SIZE: u64 = 4 * 1024; // FIXME: adjust to target architecture @@ -266,9 +266,9 @@ pub struct Evaluator<'mir, 'tcx> { pub(crate) enforce_abi: bool, /// The table of file descriptors. - pub(crate) file_handler: shims::posix::FileHandler, + pub(crate) file_handler: shims::unix::FileHandler, /// The table of directory descriptors. - pub(crate) dir_handler: shims::posix::DirHandler, + pub(crate) dir_handler: shims::unix::DirHandler, /// The "time anchor" for this machine's monotone clock (for `Instant` simulation). pub(crate) time_anchor: Instant, diff --git a/src/shims/dlsym.rs b/src/shims/dlsym.rs index 05296d3a4eb70..c5081582281bc 100644 --- a/src/shims/dlsym.rs +++ b/src/shims/dlsym.rs @@ -2,13 +2,13 @@ use rustc_middle::mir; use rustc_target::spec::abi::Abi; use crate::*; -use shims::posix::dlsym as posix; +use shims::unix::dlsym as unix; use shims::windows::dlsym as windows; #[derive(Debug, Copy, Clone)] #[allow(non_camel_case_types)] pub enum Dlsym { - Posix(posix::Dlsym), + Posix(unix::Dlsym), Windows(windows::Dlsym), } @@ -18,7 +18,7 @@ impl Dlsym { pub fn from_str<'tcx>(name: &[u8], target_os: &str) -> InterpResult<'tcx, Option> { let name = &*String::from_utf8_lossy(name); Ok(match target_os { - "linux" | "macos" => posix::Dlsym::from_str(name, target_os)?.map(Dlsym::Posix), + "linux" | "macos" => unix::Dlsym::from_str(name, target_os)?.map(Dlsym::Posix), "windows" => windows::Dlsym::from_str(name)?.map(Dlsym::Windows), os => bug!("dlsym not implemented for target_os {}", os), }) @@ -38,7 +38,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); match dlsym { Dlsym::Posix(dlsym) => - posix::EvalContextExt::call_dlsym(this, dlsym, abi, args, dest, ret), + unix::EvalContextExt::call_dlsym(this, dlsym, abi, args, dest, ret), Dlsym::Windows(dlsym) => windows::EvalContextExt::call_dlsym(this, dlsym, abi, args, dest, ret), } diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index e978391801f1e..12b5b40e69e88 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -702,7 +702,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Platform-specific shims _ => match this.tcx.sess.target.os.as_ref() { - "linux" | "macos" => return shims::posix::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, abi, args, dest, ret), + "linux" | "macos" => return shims::unix::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, abi, args, dest, ret), "windows" => return shims::windows::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, abi, args, dest, ret), target => throw_unsup_format!("the target `{}` is not supported", target), } diff --git a/src/shims/mod.rs b/src/shims/mod.rs index 926fcd5d040b8..cdffe2f65b4fc 100644 --- a/src/shims/mod.rs +++ b/src/shims/mod.rs @@ -1,7 +1,7 @@ mod backtrace; pub mod foreign_items; pub mod intrinsics; -pub mod posix; +pub mod unix; pub mod windows; pub mod dlsym; diff --git a/src/shims/posix/dlsym.rs b/src/shims/unix/dlsym.rs similarity index 94% rename from src/shims/posix/dlsym.rs rename to src/shims/unix/dlsym.rs index 339110467c73e..578ae488a98ea 100644 --- a/src/shims/posix/dlsym.rs +++ b/src/shims/unix/dlsym.rs @@ -2,8 +2,8 @@ use rustc_middle::mir; use rustc_target::spec::abi::Abi; use crate::*; -use shims::posix::linux::dlsym as linux; -use shims::posix::macos::dlsym as macos; +use shims::unix::linux::dlsym as linux; +use shims::unix::macos::dlsym as macos; #[derive(Debug, Copy, Clone)] pub enum Dlsym { diff --git a/src/shims/posix/foreign_items.rs b/src/shims/unix/foreign_items.rs similarity index 98% rename from src/shims/posix/foreign_items.rs rename to src/shims/unix/foreign_items.rs index 566befb0efd0a..32cf7e6f891ff 100644 --- a/src/shims/posix/foreign_items.rs +++ b/src/shims/unix/foreign_items.rs @@ -10,9 +10,9 @@ use rustc_target::spec::abi::Abi; use crate::*; use shims::foreign_items::EmulateByNameResult; -use shims::posix::fs::EvalContextExt as _; -use shims::posix::sync::EvalContextExt as _; -use shims::posix::thread::EvalContextExt as _; +use shims::unix::fs::EvalContextExt as _; +use shims::unix::sync::EvalContextExt as _; +use shims::unix::thread::EvalContextExt as _; impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { @@ -477,8 +477,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Platform-specific shims _ => { match this.tcx.sess.target.os.as_ref() { - "linux" => return shims::posix::linux::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, abi, args, dest, ret), - "macos" => return shims::posix::macos::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, abi, args, dest, ret), + "linux" => return shims::unix::linux::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, abi, args, dest, ret), + "macos" => return shims::unix::macos::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, abi, args, dest, ret), _ => unreachable!(), } } diff --git a/src/shims/posix/fs.rs b/src/shims/unix/fs.rs similarity index 100% rename from src/shims/posix/fs.rs rename to src/shims/unix/fs.rs diff --git a/src/shims/posix/linux/dlsym.rs b/src/shims/unix/linux/dlsym.rs similarity index 100% rename from src/shims/posix/linux/dlsym.rs rename to src/shims/unix/linux/dlsym.rs diff --git a/src/shims/posix/linux/foreign_items.rs b/src/shims/unix/linux/foreign_items.rs similarity index 98% rename from src/shims/posix/linux/foreign_items.rs rename to src/shims/unix/linux/foreign_items.rs index f966c63b72399..7a9c687fcd764 100644 --- a/src/shims/posix/linux/foreign_items.rs +++ b/src/shims/unix/linux/foreign_items.rs @@ -4,10 +4,10 @@ use rustc_target::spec::abi::Abi; use crate::*; use shims::foreign_items::EmulateByNameResult; -use shims::posix::fs::EvalContextExt as _; -use shims::posix::linux::sync::futex; -use shims::posix::sync::EvalContextExt as _; -use shims::posix::thread::EvalContextExt as _; +use shims::unix::fs::EvalContextExt as _; +use shims::unix::linux::sync::futex; +use shims::unix::sync::EvalContextExt as _; +use shims::unix::thread::EvalContextExt as _; impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { diff --git a/src/shims/posix/linux/mod.rs b/src/shims/unix/linux/mod.rs similarity index 100% rename from src/shims/posix/linux/mod.rs rename to src/shims/unix/linux/mod.rs diff --git a/src/shims/posix/linux/sync.rs b/src/shims/unix/linux/sync.rs similarity index 100% rename from src/shims/posix/linux/sync.rs rename to src/shims/unix/linux/sync.rs diff --git a/src/shims/posix/macos/dlsym.rs b/src/shims/unix/macos/dlsym.rs similarity index 100% rename from src/shims/posix/macos/dlsym.rs rename to src/shims/unix/macos/dlsym.rs diff --git a/src/shims/posix/macos/foreign_items.rs b/src/shims/unix/macos/foreign_items.rs similarity index 98% rename from src/shims/posix/macos/foreign_items.rs rename to src/shims/unix/macos/foreign_items.rs index 7f6393fd30f10..a1adfa0d2fda5 100644 --- a/src/shims/posix/macos/foreign_items.rs +++ b/src/shims/unix/macos/foreign_items.rs @@ -4,8 +4,8 @@ use rustc_target::spec::abi::Abi; use crate::*; use shims::foreign_items::EmulateByNameResult; -use shims::posix::fs::EvalContextExt as _; -use shims::posix::thread::EvalContextExt as _; +use shims::unix::fs::EvalContextExt as _; +use shims::unix::thread::EvalContextExt as _; impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { diff --git a/src/shims/posix/macos/mod.rs b/src/shims/unix/macos/mod.rs similarity index 100% rename from src/shims/posix/macos/mod.rs rename to src/shims/unix/macos/mod.rs diff --git a/src/shims/posix/mod.rs b/src/shims/unix/mod.rs similarity index 100% rename from src/shims/posix/mod.rs rename to src/shims/unix/mod.rs diff --git a/src/shims/posix/sync.rs b/src/shims/unix/sync.rs similarity index 100% rename from src/shims/posix/sync.rs rename to src/shims/unix/sync.rs diff --git a/src/shims/posix/thread.rs b/src/shims/unix/thread.rs similarity index 100% rename from src/shims/posix/thread.rs rename to src/shims/unix/thread.rs From f31a8e09510380dc3b0f6a36d59b3d4c5b5a3de7 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 6 Jun 2022 11:07:25 -0400 Subject: [PATCH 3163/3747] argument parsing: make better use of strip_prefix --- src/bin/miri.rs | 336 ++++++++++++++++++++---------------------------- 1 file changed, 141 insertions(+), 195 deletions(-) diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 2cf5bc644dbff..e3f38956dae25 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -310,208 +310,154 @@ fn main() { } else if after_dashdash { // Everything that comes after `--` is forwarded to the interpreted crate. miri_config.args.push(arg); - } else { - match arg.as_str() { - "-Zmiri-disable-validation" => { - miri_config.validate = false; - } - "-Zmiri-disable-stacked-borrows" => { - miri_config.stacked_borrows = false; - } - "-Zmiri-disable-data-race-detector" => { - miri_config.data_race_detector = false; - } - "-Zmiri-disable-alignment-check" => { - miri_config.check_alignment = miri::AlignmentCheck::None; - } - "-Zmiri-symbolic-alignment-check" => { - miri_config.check_alignment = miri::AlignmentCheck::Symbolic; - } - "-Zmiri-check-number-validity" => { - eprintln!( - "WARNING: the flag `-Zmiri-check-number-validity` no longer has any effect \ + } else if arg == "--" { + after_dashdash = true; + } else if arg == "-Zmiri-disable-validation" { + miri_config.validate = false; + } else if arg == "-Zmiri-disable-stacked-borrows" { + miri_config.stacked_borrows = false; + } else if arg == "-Zmiri-disable-data-race-detector" { + miri_config.data_race_detector = false; + } else if arg == "-Zmiri-disable-alignment-check" { + miri_config.check_alignment = miri::AlignmentCheck::None; + } else if arg == "-Zmiri-symbolic-alignment-check" { + miri_config.check_alignment = miri::AlignmentCheck::Symbolic; + } else if arg == "-Zmiri-check-number-validity" { + eprintln!( + "WARNING: the flag `-Zmiri-check-number-validity` no longer has any effect \ since it is now enabled by default" - ); - } - "-Zmiri-allow-uninit-numbers" => { - miri_config.allow_uninit_numbers = true; - } - "-Zmiri-allow-ptr-int-transmute" => { - miri_config.allow_ptr_int_transmute = true; - } - "-Zmiri-disable-abi-check" => { - miri_config.check_abi = false; - } - "-Zmiri-disable-isolation" => { - if matches!(isolation_enabled, Some(true)) { - panic!( - "-Zmiri-disable-isolation cannot be used along with -Zmiri-isolation-error" - ); - } else { - isolation_enabled = Some(false); - } - miri_config.isolated_op = miri::IsolatedOp::Allow; - } - arg if arg.starts_with("-Zmiri-isolation-error=") => { - if matches!(isolation_enabled, Some(false)) { - panic!( - "-Zmiri-isolation-error cannot be used along with -Zmiri-disable-isolation" - ); - } else { - isolation_enabled = Some(true); - } - - miri_config.isolated_op = match arg - .strip_prefix("-Zmiri-isolation-error=") - .unwrap() - { - "abort" => miri::IsolatedOp::Reject(miri::RejectOpWith::Abort), - "hide" => miri::IsolatedOp::Reject(miri::RejectOpWith::NoWarning), - "warn" => miri::IsolatedOp::Reject(miri::RejectOpWith::Warning), - "warn-nobacktrace" => - miri::IsolatedOp::Reject(miri::RejectOpWith::WarningWithoutBacktrace), - _ => - panic!( - "-Zmiri-isolation-error must be `abort`, `hide`, `warn`, or `warn-nobacktrace`" - ), - }; - } - "-Zmiri-ignore-leaks" => { - miri_config.ignore_leaks = true; - } - "-Zmiri-panic-on-unsupported" => { - miri_config.panic_on_unsupported = true; - } - "-Zmiri-tag-raw-pointers" => { - miri_config.tag_raw = true; - } - "-Zmiri-strict-provenance" => { - miri_config.provenance_mode = ProvenanceMode::Strict; - miri_config.tag_raw = true; - } - "-Zmiri-permissive-provenance" => { - miri_config.provenance_mode = ProvenanceMode::Permissive; - miri_config.tag_raw = true; - } - "-Zmiri-mute-stdout-stderr" => { - miri_config.mute_stdout_stderr = true; - } - "-Zmiri-track-raw-pointers" => { - eprintln!( - "WARNING: -Zmiri-track-raw-pointers has been renamed to -Zmiri-tag-raw-pointers, the old name is deprecated." - ); - miri_config.tag_raw = true; - } - "--" => { - after_dashdash = true; - } - arg if arg.starts_with("-Zmiri-seed=") => { - if miri_config.seed.is_some() { - panic!("Cannot specify -Zmiri-seed multiple times!"); - } - let seed = u64::from_str_radix(arg.strip_prefix("-Zmiri-seed=").unwrap(), 16) + ); + } else if arg == "-Zmiri-allow-uninit-numbers" { + miri_config.allow_uninit_numbers = true; + } else if arg == "-Zmiri-allow-ptr-int-transmute" { + miri_config.allow_ptr_int_transmute = true; + } else if arg == "-Zmiri-disable-abi-check" { + miri_config.check_abi = false; + } else if arg == "-Zmiri-disable-isolation" { + if matches!(isolation_enabled, Some(true)) { + panic!("-Zmiri-disable-isolation cannot be used along with -Zmiri-isolation-error"); + } else { + isolation_enabled = Some(false); + } + miri_config.isolated_op = miri::IsolatedOp::Allow; + } else if let Some(param) = arg.strip_prefix("-Zmiri-isolation-error=") { + if matches!(isolation_enabled, Some(false)) { + panic!("-Zmiri-isolation-error cannot be used along with -Zmiri-disable-isolation"); + } else { + isolation_enabled = Some(true); + } + + miri_config.isolated_op = match param { + "abort" => miri::IsolatedOp::Reject(miri::RejectOpWith::Abort), + "hide" => miri::IsolatedOp::Reject(miri::RejectOpWith::NoWarning), + "warn" => miri::IsolatedOp::Reject(miri::RejectOpWith::Warning), + "warn-nobacktrace" => + miri::IsolatedOp::Reject(miri::RejectOpWith::WarningWithoutBacktrace), + _ => + panic!( + "-Zmiri-isolation-error must be `abort`, `hide`, `warn`, or `warn-nobacktrace`" + ), + }; + } else if arg == "-Zmiri-ignore-leaks" { + miri_config.ignore_leaks = true; + } else if arg == "-Zmiri-panic-on-unsupported" { + miri_config.panic_on_unsupported = true; + } else if arg == "-Zmiri-tag-raw-pointers" { + miri_config.tag_raw = true; + } else if arg == "-Zmiri-strict-provenance" { + miri_config.provenance_mode = ProvenanceMode::Strict; + miri_config.tag_raw = true; + } else if arg == "-Zmiri-permissive-provenance" { + miri_config.provenance_mode = ProvenanceMode::Permissive; + miri_config.tag_raw = true; + } else if arg == "-Zmiri-mute-stdout-stderr" { + miri_config.mute_stdout_stderr = true; + } else if arg == "-Zmiri-track-raw-pointers" { + eprintln!( + "WARNING: -Zmiri-track-raw-pointers has been renamed to -Zmiri-tag-raw-pointers, the old name is deprecated." + ); + miri_config.tag_raw = true; + } else if let Some(param) = arg.strip_prefix("-Zmiri-seed=") { + if miri_config.seed.is_some() { + panic!("Cannot specify -Zmiri-seed multiple times!"); + } + let seed = u64::from_str_radix(param, 16) .unwrap_or_else(|_| panic!( "-Zmiri-seed should only contain valid hex digits [0-9a-fA-F] and fit into a u64 (max 16 characters)" )); - miri_config.seed = Some(seed); - } - arg if arg.starts_with("-Zmiri-env-exclude=") => { - miri_config - .excluded_env_vars - .push(arg.strip_prefix("-Zmiri-env-exclude=").unwrap().to_owned()); - } - arg if arg.starts_with("-Zmiri-env-forward=") => { - miri_config - .forwarded_env_vars - .push(arg.strip_prefix("-Zmiri-env-forward=").unwrap().to_owned()); - } - arg if arg.starts_with("-Zmiri-track-pointer-tag=") => { - let ids: Vec = match parse_comma_list( - arg.strip_prefix("-Zmiri-track-pointer-tag=").unwrap(), - ) { - Ok(ids) => ids, - Err(err) => - panic!( - "-Zmiri-track-pointer-tag requires a comma separated list of valid `u64` arguments: {}", - err - ), - }; - for id in ids.into_iter().map(miri::PtrId::new) { - if let Some(id) = id { - miri_config.tracked_pointer_tags.insert(id); - } else { - panic!("-Zmiri-track-pointer-tag requires nonzero arguments"); - } - } - } - arg if arg.starts_with("-Zmiri-track-call-id=") => { - let ids: Vec = match parse_comma_list( - arg.strip_prefix("-Zmiri-track-call-id=").unwrap(), - ) { - Ok(ids) => ids, - Err(err) => - panic!( - "-Zmiri-track-call-id requires a comma separated list of valid `u64` arguments: {}", - err - ), - }; - for id in ids.into_iter().map(miri::CallId::new) { - if let Some(id) = id { - miri_config.tracked_call_ids.insert(id); - } else { - panic!("-Zmiri-track-call-id requires a nonzero argument"); - } - } - } - arg if arg.starts_with("-Zmiri-track-alloc-id=") => { - let ids: Vec = match parse_comma_list::( - arg.strip_prefix("-Zmiri-track-alloc-id=").unwrap(), - ) { - Ok(ids) => ids.into_iter().map(miri::AllocId).collect(), - Err(err) => - panic!( - "-Zmiri-track-alloc-id requires a comma separated list of valid non-zero `u64` arguments: {}", - err - ), - }; - miri_config.tracked_alloc_ids.extend(ids); - } - arg if arg.starts_with("-Zmiri-compare-exchange-weak-failure-rate=") => { - let rate = match arg - .strip_prefix("-Zmiri-compare-exchange-weak-failure-rate=") - .unwrap() - .parse::() - { - Ok(rate) if rate >= 0.0 && rate <= 1.0 => rate, - Ok(_) => - panic!( - "-Zmiri-compare-exchange-weak-failure-rate must be between `0.0` and `1.0`" - ), - Err(err) => - panic!( - "-Zmiri-compare-exchange-weak-failure-rate requires a `f64` between `0.0` and `1.0`: {}", - err - ), - }; - miri_config.cmpxchg_weak_failure_rate = rate; - } - arg if arg.starts_with("-Zmiri-measureme=") => { - let measureme_out = arg.strip_prefix("-Zmiri-measureme=").unwrap(); - miri_config.measureme_out = Some(measureme_out.to_string()); - } - arg if arg.starts_with("-Zmiri-backtrace=") => { - miri_config.backtrace_style = match arg.strip_prefix("-Zmiri-backtrace=") { - Some("0") => BacktraceStyle::Off, - Some("1") => BacktraceStyle::Short, - Some("full") => BacktraceStyle::Full, - _ => panic!("-Zmiri-backtrace may only be 0, 1, or full"), - }; + miri_config.seed = Some(seed); + } else if let Some(param) = arg.strip_prefix("-Zmiri-env-exclude=") { + miri_config.excluded_env_vars.push(param.to_owned()); + } else if let Some(param) = arg.strip_prefix("-Zmiri-env-forward=") { + miri_config.forwarded_env_vars.push(param.to_owned()); + } else if let Some(param) = arg.strip_prefix("-Zmiri-track-pointer-tag=") { + let ids: Vec = match parse_comma_list(param) { + Ok(ids) => ids, + Err(err) => + panic!( + "-Zmiri-track-pointer-tag requires a comma separated list of valid `u64` arguments: {}", + err + ), + }; + for id in ids.into_iter().map(miri::PtrId::new) { + if let Some(id) = id { + miri_config.tracked_pointer_tags.insert(id); + } else { + panic!("-Zmiri-track-pointer-tag requires nonzero arguments"); } - _ => { - // Forward to rustc. - rustc_args.push(arg); + } + } else if let Some(param) = arg.strip_prefix("-Zmiri-track-call-id=") { + let ids: Vec = match parse_comma_list(param) { + Ok(ids) => ids, + Err(err) => + panic!( + "-Zmiri-track-call-id requires a comma separated list of valid `u64` arguments: {}", + err + ), + }; + for id in ids.into_iter().map(miri::CallId::new) { + if let Some(id) = id { + miri_config.tracked_call_ids.insert(id); + } else { + panic!("-Zmiri-track-call-id requires a nonzero argument"); } } + } else if let Some(param) = arg.strip_prefix("-Zmiri-track-alloc-id=") { + let ids: Vec = match parse_comma_list::(param) { + Ok(ids) => ids.into_iter().map(miri::AllocId).collect(), + Err(err) => + panic!( + "-Zmiri-track-alloc-id requires a comma separated list of valid non-zero `u64` arguments: {}", + err + ), + }; + miri_config.tracked_alloc_ids.extend(ids); + } else if let Some(param) = arg.strip_prefix("-Zmiri-compare-exchange-weak-failure-rate=") { + let rate = match param.parse::() { + Ok(rate) if rate >= 0.0 && rate <= 1.0 => rate, + Ok(_) => + panic!( + "-Zmiri-compare-exchange-weak-failure-rate must be between `0.0` and `1.0`" + ), + Err(err) => + panic!( + "-Zmiri-compare-exchange-weak-failure-rate requires a `f64` between `0.0` and `1.0`: {}", + err + ), + }; + miri_config.cmpxchg_weak_failure_rate = rate; + } else if let Some(param) = arg.strip_prefix("-Zmiri-measureme=") { + miri_config.measureme_out = Some(param.to_string()); + } else if let Some(param) = arg.strip_prefix("-Zmiri-backtrace=") { + miri_config.backtrace_style = match param { + "0" => BacktraceStyle::Off, + "1" => BacktraceStyle::Short, + "full" => BacktraceStyle::Full, + _ => panic!("-Zmiri-backtrace may only be 0, 1, or full"), + }; + } else { + // Forward to rustc. + rustc_args.push(arg); } } From 63625b03974bdb41f7629045ebfa239328fdcf02 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 3 Jun 2022 08:46:22 -0400 Subject: [PATCH 3164/3747] adjust for better provenance control --- src/diagnostics.rs | 14 +++++++--- src/helpers.rs | 4 +-- tests/fail/branchless-select-i128-pointer.rs | 6 ++--- .../branchless-select-i128-pointer.stderr | 8 +++--- tests/fail/pointer_partial_overwrite.rs | 2 +- tests/fail/pointer_partial_read.rs | 9 ------- tests/fail/pointer_partial_read.stderr | 14 ---------- .../permissive_provenance_transmute.rs | 27 +++++++++++++++++++ .../permissive_provenance_transmute.stderr | 20 ++++++++++++++ .../provenance/strict_provenance_transmute.rs | 4 +-- .../strict_provenance_transmute.stderr | 6 ++--- tests/fail/transmute_fat1.rs | 5 ++-- tests/fail/transmute_fat1.stderr | 9 ++++--- tests/fail/validity/ptr_integer_transmute.rs | 4 --- .../validity/ptr_integer_transmute.stderr | 15 ----------- ..._provenance.rs => ptr_int_from_exposed.rs} | 0 tests/pass/ptr_int_transmute.rs | 22 +++++++++++++++ 17 files changed, 103 insertions(+), 66 deletions(-) delete mode 100644 tests/fail/pointer_partial_read.rs delete mode 100644 tests/fail/pointer_partial_read.stderr create mode 100644 tests/fail/provenance/permissive_provenance_transmute.rs create mode 100644 tests/fail/provenance/permissive_provenance_transmute.stderr delete mode 100644 tests/fail/validity/ptr_integer_transmute.rs delete mode 100644 tests/fail/validity/ptr_integer_transmute.stderr rename tests/pass/{ptr_int_permissive_provenance.rs => ptr_int_from_exposed.rs} (100%) create mode 100644 tests/pass/ptr_int_transmute.rs diff --git a/src/diagnostics.rs b/src/diagnostics.rs index ace521f1bed02..52f93a6cea9d9 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -229,9 +229,16 @@ pub fn report_error<'tcx, 'mir>( }; #[rustfmt::skip] let helps = match e.kind() { - Unsupported(UnsupportedOpInfo::ThreadLocalStatic(_) | UnsupportedOpInfo::ReadExternStatic(_)) => + Unsupported( + UnsupportedOpInfo::ThreadLocalStatic(_) | + UnsupportedOpInfo::ReadExternStatic(_) + ) => panic!("Error should never be raised by Miri: {:?}", e.kind()), - Unsupported(_) => + Unsupported( + UnsupportedOpInfo::Unsupported(_) | + UnsupportedOpInfo::PartialPointerOverwrite(_) | + UnsupportedOpInfo::ReadPointerAsBytes + ) => vec![(None, format!("this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support"))], UndefinedBehavior(UndefinedBehaviorInfo::AlignmentCheckFailed { .. }) if ecx.machine.check_alignment == AlignmentCheck::Symbolic @@ -245,7 +252,8 @@ pub fn report_error<'tcx, 'mir>( (None, format!("this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior")), (None, format!("see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information")), ], - _ => vec![], + InvalidProgram(_) | ResourceExhaustion(_) | MachineStop(_) => + vec![], }; (Some(title), helps) } diff --git a/src/helpers.rs b/src/helpers.rs index cb4c3c293e939..4c79633c72dea 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -681,7 +681,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // FIXME: We are re-getting the allocation each time around the loop. // Would be nice if we could somehow "extend" an existing AllocRange. let alloc = this.get_ptr_alloc(ptr.offset(len, this)?, size1, Align::ONE)?.unwrap(); // not a ZST, so we will get a result - let byte = alloc.read_scalar(alloc_range(Size::ZERO, size1))?.to_u8()?; + let byte = alloc.read_integer(Size::ZERO, size1)?.to_u8()?; if byte == 0 { break; } else { @@ -703,7 +703,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // FIXME: We are re-getting the allocation each time around the loop. // Would be nice if we could somehow "extend" an existing AllocRange. let alloc = this.get_ptr_alloc(ptr, size2, align2)?.unwrap(); // not a ZST, so we will get a result - let wchar = alloc.read_scalar(alloc_range(Size::ZERO, size2))?.to_u16()?; + let wchar = alloc.read_integer(Size::ZERO, size2)?.to_u16()?; if wchar == 0 { break; } else { diff --git a/tests/fail/branchless-select-i128-pointer.rs b/tests/fail/branchless-select-i128-pointer.rs index 61fd57f8f0501..20fbcd1de78a8 100644 --- a/tests/fail/branchless-select-i128-pointer.rs +++ b/tests/fail/branchless-select-i128-pointer.rs @@ -9,10 +9,10 @@ fn main() { for &my_bool in &[true, false] { let mask = -(my_bool as TwoPtrs); // false -> 0, true -> -1 aka !0 // This is branchless code to select one or the other pointer. - // For now, Miri brafs on it, but if this code ever passes we better make sure it behaves correctly. + // However, it drops provenance when transmuting to TwoPtrs, so this is UB. let val = unsafe { - transmute::<_, &str>( - !mask & transmute::<_, TwoPtrs>("false !") | mask & transmute::<_, TwoPtrs>("true !"), //~ERROR encountered (potentially part of) a pointer, but expected plain (non-pointer) bytes + transmute::<_, &str>( //~ERROR type validation failed: encountered a dangling reference + !mask & transmute::<_, TwoPtrs>("false !") | mask & transmute::<_, TwoPtrs>("true !"), ) }; println!("{}", val); diff --git a/tests/fail/branchless-select-i128-pointer.stderr b/tests/fail/branchless-select-i128-pointer.stderr index 2e0f813983031..f37dcf955e331 100644 --- a/tests/fail/branchless-select-i128-pointer.stderr +++ b/tests/fail/branchless-select-i128-pointer.stderr @@ -1,8 +1,10 @@ -error: Undefined Behavior: type validation failed: encountered (potentially part of) a pointer, but expected plain (non-pointer) bytes +error: Undefined Behavior: type validation failed: encountered a dangling reference (address $HEX is unallocated) --> $DIR/branchless-select-i128-pointer.rs:LL:CC | -LL | !mask & transmute::<_, TwoPtrs>("false !") | mask & transmute::<_, TwoPtrs>("true !"), - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered (potentially part of) a pointer, but expected plain (non-pointer) bytes +LL | / transmute::<_, &str>( +LL | | !mask & transmute::<_, TwoPtrs>("false !") | mask & transmute::<_, TwoPtrs>("true !"), +LL | | ) + | |_____________^ type validation failed: encountered a dangling reference (address $HEX is unallocated) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/pointer_partial_overwrite.rs b/tests/fail/pointer_partial_overwrite.rs index 8bee58d20a59b..1bbb33aa2bbd7 100644 --- a/tests/fail/pointer_partial_overwrite.rs +++ b/tests/fail/pointer_partial_overwrite.rs @@ -2,7 +2,7 @@ // compile-flags: -Zmiri-disable-alignment-check -Zmiri-disable-stacked-borrows -Zmiri-disable-validation // Test what happens when we overwrite parts of a pointer. -// Also see . +// Also see . fn main() { let mut p = &42; diff --git a/tests/fail/pointer_partial_read.rs b/tests/fail/pointer_partial_read.rs deleted file mode 100644 index a4a5071f5da09..0000000000000 --- a/tests/fail/pointer_partial_read.rs +++ /dev/null @@ -1,9 +0,0 @@ -// Test what happens when we read parts of a pointer. -// Related to . -fn main() { - let x = 13; - let y = &x; - let z = &y as *const &i32 as *const u8; - // the deref fails, because we are reading only a part of the pointer - let _val = unsafe { *z }; //~ ERROR unable to turn pointer into raw bytes -} diff --git a/tests/fail/pointer_partial_read.stderr b/tests/fail/pointer_partial_read.stderr deleted file mode 100644 index dc35f7e109a54..0000000000000 --- a/tests/fail/pointer_partial_read.stderr +++ /dev/null @@ -1,14 +0,0 @@ -error: unsupported operation: unable to turn pointer into raw bytes - --> $DIR/pointer_partial_read.rs:LL:CC - | -LL | let _val = unsafe { *z }; - | ^^ unable to turn pointer into raw bytes - | - = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support - - = note: inside `main` at $DIR/pointer_partial_read.rs:LL:CC - -note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace - -error: aborting due to previous error - diff --git a/tests/fail/provenance/permissive_provenance_transmute.rs b/tests/fail/provenance/permissive_provenance_transmute.rs new file mode 100644 index 0000000000000..dbfc5732ed3b7 --- /dev/null +++ b/tests/fail/provenance/permissive_provenance_transmute.rs @@ -0,0 +1,27 @@ +// compile-flags: -Zmiri-permissive-provenance -Zmiri-disable-stacked-borrows +#![feature(strict_provenance)] + +use std::mem; + +// This is the example from +// . + +unsafe fn deref(left: *const u8, right: *const u8) { + let left_int: usize = mem::transmute(left); + let right_int: usize = mem::transmute(right); + if left_int == right_int { + // The compiler is allowed to replace `left_int` by `right_int` here... + let left_ptr: *const u8 = mem::transmute(left_int); + // ...which however means here it could be dereferencing the wrong pointer. + let _val = *left_ptr; //~ERROR dereferencing pointer failed + } +} + +fn main() { + let ptr1 = &0u8 as *const u8; + let ptr2 = &1u8 as *const u8; + unsafe { + // Two pointers with the same address but different provenance. + deref(ptr1, ptr2.with_addr(ptr1.addr())); + } +} diff --git a/tests/fail/provenance/permissive_provenance_transmute.stderr b/tests/fail/provenance/permissive_provenance_transmute.stderr new file mode 100644 index 0000000000000..12f3562011a81 --- /dev/null +++ b/tests/fail/provenance/permissive_provenance_transmute.stderr @@ -0,0 +1,20 @@ +error: Undefined Behavior: dereferencing pointer failed: $HEX is not a valid pointer + --> $DIR/permissive_provenance_transmute.rs:LL:CC + | +LL | let _val = *left_ptr; + | ^^^^^^^^^ dereferencing pointer failed: $HEX is not a valid pointer + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `deref` at $DIR/permissive_provenance_transmute.rs:LL:CC +note: inside `main` at $DIR/permissive_provenance_transmute.rs:LL:CC + --> $DIR/permissive_provenance_transmute.rs:LL:CC + | +LL | deref(ptr1, ptr2.with_addr(ptr1.addr())); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/fail/provenance/strict_provenance_transmute.rs b/tests/fail/provenance/strict_provenance_transmute.rs index a684d65b2ce11..12a141e9ddfee 100644 --- a/tests/fail/provenance/strict_provenance_transmute.rs +++ b/tests/fail/provenance/strict_provenance_transmute.rs @@ -7,13 +7,13 @@ use std::mem; // . unsafe fn deref(left: *const u8, right: *const u8) { - let left_int: usize = mem::transmute(left); //~ERROR expected plain (non-pointer) bytes + let left_int: usize = mem::transmute(left); let right_int: usize = mem::transmute(right); if left_int == right_int { // The compiler is allowed to replace `left_int` by `right_int` here... let left_ptr: *const u8 = mem::transmute(left_int); // ...which however means here it could be dereferencing the wrong pointer. - let _val = *left_ptr; + let _val = *left_ptr; //~ERROR dereferencing pointer failed } } diff --git a/tests/fail/provenance/strict_provenance_transmute.stderr b/tests/fail/provenance/strict_provenance_transmute.stderr index 544431815c1bc..8df94d50bbac1 100644 --- a/tests/fail/provenance/strict_provenance_transmute.stderr +++ b/tests/fail/provenance/strict_provenance_transmute.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: type validation failed: encountered pointer to $HEX[ALLOC], but expected plain (non-pointer) bytes +error: Undefined Behavior: dereferencing pointer failed: $HEX is not a valid pointer --> $DIR/strict_provenance_transmute.rs:LL:CC | -LL | let left_int: usize = mem::transmute(left); - | ^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to $HEX[ALLOC], but expected plain (non-pointer) bytes +LL | let _val = *left_ptr; + | ^^^^^^^^^ dereferencing pointer failed: $HEX is not a valid pointer | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/transmute_fat1.rs b/tests/fail/transmute_fat1.rs index da45dad7b7d43..22fb4c6fdcc93 100644 --- a/tests/fail/transmute_fat1.rs +++ b/tests/fail/transmute_fat1.rs @@ -1,5 +1,4 @@ -// This should fail even without validation -// compile-flags: -Zmiri-disable-validation +// error-pattern: type validation failed: encountered a pointer fn main() { #[cfg(target_pointer_width="64")] @@ -10,5 +9,5 @@ fn main() { let bad = unsafe { std::mem::transmute::<&[u8], [u8; 8]>(&[1u8]) }; - let _val = bad[0] + bad[bad.len()-1]; //~ ERROR unable to turn pointer into raw bytes + let _val = bad[0] + bad[bad.len()-1]; } diff --git a/tests/fail/transmute_fat1.stderr b/tests/fail/transmute_fat1.stderr index 2966f042001c3..ea83dd442d2b3 100644 --- a/tests/fail/transmute_fat1.stderr +++ b/tests/fail/transmute_fat1.stderr @@ -1,10 +1,11 @@ -error: unsupported operation: unable to turn pointer into raw bytes +error: Undefined Behavior: type validation failed: encountered a pointer, but expected plain (non-pointer) bytes --> $DIR/transmute_fat1.rs:LL:CC | -LL | let _val = bad[0] + bad[bad.len()-1]; - | ^^^^^^ unable to turn pointer into raw bytes +LL | std::mem::transmute::<&[u8], [u8; 16]>(&[1u8]) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected plain (non-pointer) bytes | - = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: inside `main` at $DIR/transmute_fat1.rs:LL:CC diff --git a/tests/fail/validity/ptr_integer_transmute.rs b/tests/fail/validity/ptr_integer_transmute.rs deleted file mode 100644 index b23ccbbb1b033..0000000000000 --- a/tests/fail/validity/ptr_integer_transmute.rs +++ /dev/null @@ -1,4 +0,0 @@ -fn main() { - let r = &mut 42; - let _i: usize = unsafe { std::mem::transmute(r) }; //~ ERROR expected plain (non-pointer) bytes -} diff --git a/tests/fail/validity/ptr_integer_transmute.stderr b/tests/fail/validity/ptr_integer_transmute.stderr deleted file mode 100644 index cad53d71f4d9d..0000000000000 --- a/tests/fail/validity/ptr_integer_transmute.stderr +++ /dev/null @@ -1,15 +0,0 @@ -error: Undefined Behavior: type validation failed: encountered pointer to $HEX[ALLOC], but expected plain (non-pointer) bytes - --> $DIR/ptr_integer_transmute.rs:LL:CC - | -LL | let _i: usize = unsafe { std::mem::transmute(r) }; - | ^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to $HEX[ALLOC], but expected plain (non-pointer) bytes - | - = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior - = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - - = note: inside `main` at $DIR/ptr_integer_transmute.rs:LL:CC - -note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace - -error: aborting due to previous error - diff --git a/tests/pass/ptr_int_permissive_provenance.rs b/tests/pass/ptr_int_from_exposed.rs similarity index 100% rename from tests/pass/ptr_int_permissive_provenance.rs rename to tests/pass/ptr_int_from_exposed.rs diff --git a/tests/pass/ptr_int_transmute.rs b/tests/pass/ptr_int_transmute.rs new file mode 100644 index 0000000000000..ba50480c5399a --- /dev/null +++ b/tests/pass/ptr_int_transmute.rs @@ -0,0 +1,22 @@ +// Test what happens when we read parts of a pointer. +// Related to . +fn ptr_partial_read() { + let x = 13; + let y = &x; + let z = &y as *const &i32 as *const u8; + + // This just strips provenance, but should work fine otherwise. + let _val = unsafe { *z }; +} + +fn transmute_strip_provenance() { + let r = &mut 42; + let addr = r as *mut _ as usize; + let i: usize = unsafe { std::mem::transmute(r) }; + assert_eq!(i, addr); +} + +fn main() { + ptr_partial_read(); + transmute_strip_provenance(); +} From 34d4928dce663ae9c2292ea84b046419fa995537 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 3 Jun 2022 08:47:00 -0400 Subject: [PATCH 3165/3747] addr no longer exposes :) --- tests/fail/provenance/ptr_int_unexposed.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/fail/provenance/ptr_int_unexposed.rs b/tests/fail/provenance/ptr_int_unexposed.rs index 8a336e43ba18f..310024c1efc70 100644 --- a/tests/fail/provenance/ptr_int_unexposed.rs +++ b/tests/fail/provenance/ptr_int_unexposed.rs @@ -1,12 +1,12 @@ -// compile-flags: -Zmiri-permissive-provenance -Zmiri-disable-stacked-borrows -Zmiri-allow-ptr-int-transmute +// compile-flags: -Zmiri-permissive-provenance -Zmiri-disable-stacked-borrows +#![feature(strict_provenance)] fn main() { let x: i32 = 3; let x_ptr = &x as *const i32; - // TODO: switch this to addr() once we intrinsify it - let x_usize: usize = unsafe { std::mem::transmute(x_ptr) }; - // Cast back a pointer that did *not* get exposed. - let ptr = x_usize as *const i32; + let x_usize: usize = x_ptr.addr(); + // Cast back an address that did *not* get exposed. + let ptr = std::ptr::from_exposed_addr::(x_usize); assert_eq!(unsafe { *ptr }, 3); //~ ERROR Undefined Behavior: dereferencing pointer failed } From b1b38361724489c9227599b6f772b4f6944ce6b6 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 6 Jun 2022 11:44:27 -0400 Subject: [PATCH 3166/3747] fix rustup-toolchain without arguments --- rustup-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rustup-toolchain b/rustup-toolchain index 7e5d57349b9dd..ca5508e225a11 100755 --- a/rustup-toolchain +++ b/rustup-toolchain @@ -30,7 +30,7 @@ else NEW_COMMIT="$1" fi echo "$NEW_COMMIT" > rust-version -shift +shift || true # don't fail if shifting fails # Check if we already are at that commit. CUR_COMMIT=$(rustc +miri --version -v 2>/dev/null | egrep "^commit-hash: " | cut -d " " -f 2) From 7f5cfa54d9816b0b985a737bb2fd3bf48ad98714 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 6 Jun 2022 11:44:36 -0400 Subject: [PATCH 3167/3747] port some tests away from flags we want to remove --- tests/fail/stacked_borrows/illegal_read3.rs | 20 ++++++++----------- .../fail/stacked_borrows/illegal_read3.stderr | 4 ++-- tests/fail/transmute-pair-uninit.rs | 3 +-- tests/fail/transmute-pair-uninit.stderr | 6 +++--- tests/fail/uninit_byte_read.rs | 5 ++--- tests/fail/uninit_byte_read.stderr | 6 +++--- .../invalid_enum_tag_256variants_uninit.rs | 1 + tests/pass/intptrcast.rs | 6 ++---- tests/pass/transmute_fat.rs | 11 ++++------ 9 files changed, 26 insertions(+), 36 deletions(-) diff --git a/tests/fail/stacked_borrows/illegal_read3.rs b/tests/fail/stacked_borrows/illegal_read3.rs index 672c200861c68..3de8f57d6223c 100644 --- a/tests/fail/stacked_borrows/illegal_read3.rs +++ b/tests/fail/stacked_borrows/illegal_read3.rs @@ -1,16 +1,18 @@ -// compile-flags: -Zmiri-allow-ptr-int-transmute // A callee may not read the destination of our `&mut` without us noticing. // Thise code got carefully checked to not introduce any reborrows // that are not explicit in the source. Let's hope the compiler does not break this later! -#![feature(untagged_unions)] - use std::mem; +union HiddenRef { + // We avoid retagging at this type, so shared vs mutable does not matter. + r: &'static i32, +} + fn main() { let mut x: i32 = 15; let xref1 = &mut x; - let xref1_sneaky: usize = unsafe { mem::transmute_copy(&xref1) }; + let xref1_sneaky: HiddenRef = unsafe { mem::transmute_copy(&xref1) }; // Derived from `xref1`, so using raw value is still ok, ... let xref2 = &mut *xref1; callee(xref1_sneaky); @@ -19,14 +21,8 @@ fn main() { //~^ ERROR: borrow stack } -fn callee(xref1: usize) { - // Transmuting through a union to avoid retagging. - union UsizeToRef { - from: usize, - to: &'static mut i32, - } - let xref1 = UsizeToRef { from: xref1 }; +fn callee(xref1: HiddenRef) { // Doing the deref and the transmute (through the union) in the same place expression // should avoid retagging. - let _val = unsafe { *xref1.to }; + let _val = unsafe { *xref1.r }; } diff --git a/tests/fail/stacked_borrows/illegal_read3.stderr b/tests/fail/stacked_borrows/illegal_read3.stderr index ab26696a765c6..75c4305ee81f5 100644 --- a/tests/fail/stacked_borrows/illegal_read3.stderr +++ b/tests/fail/stacked_borrows/illegal_read3.stderr @@ -17,8 +17,8 @@ LL | let xref2 = &mut *xref1; help: was later invalidated at offsets [0x0..0x4] --> $DIR/illegal_read3.rs:LL:CC | -LL | let _val = unsafe { *xref1.to }; - | ^^^^^^^^^ +LL | let _val = unsafe { *xref1.r }; + | ^^^^^^^^ = note: inside `main` at $DIR/illegal_read3.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/transmute-pair-uninit.rs b/tests/fail/transmute-pair-uninit.rs index 18c80ac42ac8e..1bd60f9cff732 100644 --- a/tests/fail/transmute-pair-uninit.rs +++ b/tests/fail/transmute-pair-uninit.rs @@ -1,4 +1,3 @@ -// compile-flags: -Zmiri-allow-uninit-numbers #![feature(core_intrinsics)] use std::mem; @@ -18,6 +17,6 @@ fn main() { assert_eq!(byte, 0); } let v = unsafe { *z.offset(first_undef) }; + //~^ ERROR uninitialized if v == 0 { println!("it is zero"); } - //~^ ERROR this operation requires initialized memory } diff --git a/tests/fail/transmute-pair-uninit.stderr b/tests/fail/transmute-pair-uninit.stderr index f574e97402825..833c3abbb2fb1 100644 --- a/tests/fail/transmute-pair-uninit.stderr +++ b/tests/fail/transmute-pair-uninit.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory +error: Undefined Behavior: type validation failed: encountered uninitialized bytes, but expected initialized bytes --> $DIR/transmute-pair-uninit.rs:LL:CC | -LL | if v == 0 { println!("it is zero"); } - | ^^^^^^ using uninitialized data, but this operation requires initialized memory +LL | let v = unsafe { *z.offset(first_undef) }; + | ^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized bytes, but expected initialized bytes | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/uninit_byte_read.rs b/tests/fail/uninit_byte_read.rs index 9a1f8df94d60f..6868e5895507d 100644 --- a/tests/fail/uninit_byte_read.rs +++ b/tests/fail/uninit_byte_read.rs @@ -1,7 +1,6 @@ -// compile-flags: -Zmiri-allow-uninit-numbers fn main() { let v: Vec = Vec::with_capacity(10); - let undef = unsafe { *v.get_unchecked(5) }; - let x = undef + 1; //~ ERROR this operation requires initialized memory + let undef = unsafe { *v.get_unchecked(5) }; //~ ERROR uninitialized + let x = undef + 1; panic!("this should never print: {}", x); } diff --git a/tests/fail/uninit_byte_read.stderr b/tests/fail/uninit_byte_read.stderr index b07473f95b9e4..d150be3e7e781 100644 --- a/tests/fail/uninit_byte_read.stderr +++ b/tests/fail/uninit_byte_read.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory +error: Undefined Behavior: type validation failed: encountered uninitialized bytes, but expected initialized bytes --> $DIR/uninit_byte_read.rs:LL:CC | -LL | let x = undef + 1; - | ^^^^^^^^^ using uninitialized data, but this operation requires initialized memory +LL | let undef = unsafe { *v.get_unchecked(5) }; + | ^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized bytes, but expected initialized bytes | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/validity/invalid_enum_tag_256variants_uninit.rs b/tests/fail/validity/invalid_enum_tag_256variants_uninit.rs index c36685ab2f467..b6f86698b3fb3 100644 --- a/tests/fail/validity/invalid_enum_tag_256variants_uninit.rs +++ b/tests/fail/validity/invalid_enum_tag_256variants_uninit.rs @@ -1,3 +1,4 @@ +// Even when uninit numbers are allowed, this enum is not. // compile-flags: -Zmiri-allow-uninit-numbers #![allow(unused, deprecated, invalid_value)] diff --git a/tests/pass/intptrcast.rs b/tests/pass/intptrcast.rs index 573bdbae704a4..aafa90204fc2a 100644 --- a/tests/pass/intptrcast.rs +++ b/tests/pass/intptrcast.rs @@ -1,6 +1,4 @@ -// compile-flags: -Zmiri-allow-ptr-int-transmute - -// This returns a miri pointer at type usize, if the argument is a proper pointer +// This strips provenance fn transmute_ptr_to_int(x: *const T) -> usize { unsafe { std::mem::transmute(x) } } @@ -39,7 +37,7 @@ fn transmute() { // transmuting. let a: *const i32 = &42; let b = transmute_ptr_to_int(a) as u8; - let c = a as usize as u8; + let c = a as u8; assert_eq!(b, c); } diff --git a/tests/pass/transmute_fat.rs b/tests/pass/transmute_fat.rs index 8a6e15031cb4d..c62298a9aced2 100644 --- a/tests/pass/transmute_fat.rs +++ b/tests/pass/transmute_fat.rs @@ -1,14 +1,11 @@ // Stacked Borrows disallows this becuase the reference is never cast to a raw pointer. -// compile-flags: -Zmiri-disable-stacked-borrows -Zmiri-allow-ptr-int-transmute +// compile-flags: -Zmiri-disable-stacked-borrows fn main() { // If we are careful, we can exploit data layout... let raw = unsafe { - std::mem::transmute::<&[u8], [usize; 2]>(&[42]) + std::mem::transmute::<&[u8], [*const u8; 2]>(&[42]) }; - let ptr = raw[0] + raw[1]; - // We transmute both ways, to really test allow-ptr-int-transmute. - let ptr: *const u8 = unsafe { std::mem::transmute(ptr) }; - // The pointer is one-past-the end, but we decrement it into bounds before using it - assert_eq!(unsafe { *ptr.offset(-1) }, 42); + let ptr: *const u8 = unsafe { std::mem::transmute_copy(&raw) }; + assert_eq!(unsafe { *ptr }, 42); } From b39e4c729acfb2467fd4aed8cea626de00b73ddf Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 6 Jun 2022 12:10:40 -0400 Subject: [PATCH 3168/3747] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index e7a7ad9dd818c..2898937edfb41 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -4e725bad73747a4c93a3ac53106e4b4006edc665 +9d20fd109809f20c049d6895a5be27a1fbd39daa From 3ba6456181bd2ea335c8e5b91e85b8094e0f8804 Mon Sep 17 00:00:00 2001 From: infrandomness Date: Mon, 6 Jun 2022 18:17:38 +0200 Subject: [PATCH 3169/3747] Fix rustdoc warnings --- src/data_race.rs | 8 ++++---- src/shims/tls.rs | 4 ++-- src/stacked_borrows.rs | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/data_race.rs b/src/data_race.rs index c52b840184661..eb67a487b5a50 100644 --- a/src/data_race.rs +++ b/src/data_race.rs @@ -1,11 +1,11 @@ //! Implementation of a data-race detector using Lamport Timestamps / Vector-clocks //! based on the Dynamic Race Detection for C++: -//! https://www.doc.ic.ac.uk/~afd/homepages/papers/pdfs/2017/POPL.pdf +//! //! which does not report false-positives when fences are used, and gives better //! accuracy in presence of read-modify-write operations. //! //! The implementation contains modifications to correctly model the changes to the memory model in C++20 -//! regarding the weakening of release sequences: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0982r1.html. +//! regarding the weakening of release sequences: . //! Relaxed stores now unconditionally block all currently active release sequences and so per-thread tracking of release //! sequences is not needed. //! @@ -15,7 +15,7 @@ //! This does not explore weak memory orders and so can still miss data-races //! but should not report false-positives //! -//! Data-race definition from(https://en.cppreference.com/w/cpp/language/memory_model#Threads_and_data_races): +//! Data-race definition from(): //! a data race occurs between two memory accesses if they are on different threads, at least one operation //! is non-atomic, at least one operation is a write and neither access happens-before the other. Read the link //! for full definition. @@ -24,7 +24,7 @@ //! because it only re-uses vector indexes once all currently-active (not-terminated) threads have an internal //! vector clock that happens-after the join operation of the candidate thread. Threads that have not been joined //! on are not considered. Since the thread's vector clock will only increase and a data-race implies that -//! there is some index x where clock[x] > thread_clock, when this is true clock[candidate-idx] > thread_clock +//! there is some index x where clock\[x\] > thread_clock, when this is true clock\[candidate-idx\] > thread_clock //! can never hold and hence a data-race can never be reported in that vector index again. //! This means that the thread-index can be safely re-used, starting on the next timestamp for the newly created //! thread. diff --git a/src/shims/tls.rs b/src/shims/tls.rs index 87c8d7eadc3bb..6b4e9d4f75337 100644 --- a/src/shims/tls.rs +++ b/src/shims/tls.rs @@ -135,7 +135,7 @@ impl<'tcx> TlsData<'tcx> { /// [`_tlv_atexit` /// implementation](https://github.com/opensource-apple/dyld/blob/195030646877261f0c8c7ad8b001f52d6a26f514/src/threadLocalVariables.c#L389): /// - /// // NOTE: this does not need locks because it only operates on current thread data + /// NOTE: this does not need locks because it only operates on current thread data pub fn set_macos_thread_dtor( &mut self, thread: ThreadId, @@ -347,7 +347,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// Note: we consistently run TLS destructors for all threads, including the /// main thread. However, it is not clear that we should run the TLS /// destructors for the main thread. See issue: - /// https://github.com/rust-lang/rust/issues/28129. + /// . fn schedule_next_tls_dtor_for_active_thread(&mut self) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let active_thread = this.get_active_thread(); diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index a19e30b113e32..0d671ec653b56 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -945,7 +945,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// it does not alias with anything. /// /// This is a HACK because there is nothing in MIR that would make the retag - /// explicit. Also see https://github.com/rust-lang/rust/issues/71117. + /// explicit. Also see . fn retag_return_place(&mut self) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let return_place = this.frame_mut().return_place; From 84edb76e2698c62d65605d18f1c2294007d3b3aa Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 6 Jun 2022 12:33:48 -0400 Subject: [PATCH 3170/3747] make output bitwidth-independent --- tests/fail/transmute_fat1.rs | 3 ++- tests/fail/transmute_fat1.stderr | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/fail/transmute_fat1.rs b/tests/fail/transmute_fat1.rs index 22fb4c6fdcc93..8b351d3a09e9d 100644 --- a/tests/fail/transmute_fat1.rs +++ b/tests/fail/transmute_fat1.rs @@ -1,4 +1,5 @@ // error-pattern: type validation failed: encountered a pointer +// normalize-stderr-test: "\[u8; (08|16)\]" -> "$$ARRAY" fn main() { #[cfg(target_pointer_width="64")] @@ -7,7 +8,7 @@ fn main() { }; #[cfg(target_pointer_width="32")] let bad = unsafe { - std::mem::transmute::<&[u8], [u8; 8]>(&[1u8]) + std::mem::transmute::<&[u8], [u8; 08]>(&[1u8]) }; let _val = bad[0] + bad[bad.len()-1]; } diff --git a/tests/fail/transmute_fat1.stderr b/tests/fail/transmute_fat1.stderr index ea83dd442d2b3..cbfa8dff2a50c 100644 --- a/tests/fail/transmute_fat1.stderr +++ b/tests/fail/transmute_fat1.stderr @@ -1,7 +1,7 @@ error: Undefined Behavior: type validation failed: encountered a pointer, but expected plain (non-pointer) bytes --> $DIR/transmute_fat1.rs:LL:CC | -LL | std::mem::transmute::<&[u8], [u8; 16]>(&[1u8]) +LL | std::mem::transmute::<&[u8], $ARRAY>(&[1u8]) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected plain (non-pointer) bytes | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior From 8d36e8b32c800e6227ab2ffa7fb64729313e10a1 Mon Sep 17 00:00:00 2001 From: Andy Wang Date: Sat, 25 Dec 2021 23:45:33 +0000 Subject: [PATCH 3171/3747] Add weak memory config option --- src/bin/miri.rs | 3 +++ src/eval.rs | 3 +++ src/machine.rs | 4 ++++ 3 files changed, 10 insertions(+) diff --git a/src/bin/miri.rs b/src/bin/miri.rs index e3f38956dae25..907e620404b9b 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -318,6 +318,7 @@ fn main() { miri_config.stacked_borrows = false; } else if arg == "-Zmiri-disable-data-race-detector" { miri_config.data_race_detector = false; + miri_config.weak_memory_emulation = false; } else if arg == "-Zmiri-disable-alignment-check" { miri_config.check_alignment = miri::AlignmentCheck::None; } else if arg == "-Zmiri-symbolic-alignment-check" { @@ -340,6 +341,8 @@ fn main() { isolation_enabled = Some(false); } miri_config.isolated_op = miri::IsolatedOp::Allow; + } else if arg == "-Zmiri-disable-weak-memory-emulation" { + miri_config.weak_memory_emulation = false; } else if let Some(param) = arg.strip_prefix("-Zmiri-isolation-error=") { if matches!(isolation_enabled, Some(false)) { panic!("-Zmiri-isolation-error cannot be used along with -Zmiri-disable-isolation"); diff --git a/src/eval.rs b/src/eval.rs index a782dfa3fce17..bdf527a0d13e0 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -105,6 +105,8 @@ pub struct MiriConfig { pub tag_raw: bool, /// Determine if data race detection should be enabled pub data_race_detector: bool, + /// Determine if weak memory emulation should be enabled. Requires data race detection to be enabled + pub weak_memory_emulation: bool, /// Rate of spurious failures for compare_exchange_weak atomic operations, /// between 0.0 and 1.0, defaulting to 0.8 (80% chance of failure). pub cmpxchg_weak_failure_rate: f64, @@ -142,6 +144,7 @@ impl Default for MiriConfig { tracked_alloc_ids: HashSet::default(), tag_raw: false, data_race_detector: true, + weak_memory_emulation: true, cmpxchg_weak_failure_rate: 0.8, measureme_out: None, panic_on_unsupported: false, diff --git a/src/machine.rs b/src/machine.rs index 369bb92c6f398..2060bba0b8530 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -323,6 +323,9 @@ pub struct Evaluator<'mir, 'tcx> { /// Corresponds to -Zmiri-mute-stdout-stderr and doesn't write the output but acts as if it succeeded. pub(crate) mute_stdout_stderr: bool, + + /// Whether weak memory emulation is enabled + pub(crate) weak_memory: bool, } impl<'mir, 'tcx> Evaluator<'mir, 'tcx> { @@ -378,6 +381,7 @@ impl<'mir, 'tcx> Evaluator<'mir, 'tcx> { check_alignment: config.check_alignment, cmpxchg_weak_failure_rate: config.cmpxchg_weak_failure_rate, mute_stdout_stderr: config.mute_stdout_stderr, + weak_memory: config.weak_memory_emulation, } } From 16315b1540959e4834ba461471e868868c68c4bc Mon Sep 17 00:00:00 2001 From: Andy Wang Date: Mon, 17 Jan 2022 17:40:17 +0000 Subject: [PATCH 3172/3747] Add test cases --- tests/run-pass/concurrency/weak_memory.rs | 257 ++++++++++++++++++ tests/run-pass/concurrency/weak_memory.stderr | 2 + 2 files changed, 259 insertions(+) create mode 100644 tests/run-pass/concurrency/weak_memory.rs create mode 100644 tests/run-pass/concurrency/weak_memory.stderr diff --git a/tests/run-pass/concurrency/weak_memory.rs b/tests/run-pass/concurrency/weak_memory.rs new file mode 100644 index 0000000000000..bd3d1de7c23e2 --- /dev/null +++ b/tests/run-pass/concurrency/weak_memory.rs @@ -0,0 +1,257 @@ +// ignore-windows: Concurrency on Windows is not supported yet. +// compile-flags: -Zmiri-ignore-leaks -Zmiri-disable-stacked-borrows + +// Weak memory emulation tests. All of the following test if +// our weak memory emulation produces any inconsistent execution outcomes +// +// Due to the random nature of choosing valid stores, it is always +// possible that our tests spuriously succeeds: even though our weak +// memory emulation code has incorrectly identified a store in +// modification order as being valid, it may be never chosen by +// the RNG and never observed in our tests. +// +// To mitigate this, each test is ran enough times such that the chance +// of spurious success is very low. These tests never supriously fail. +// +// Note that we can't effectively test whether our weak memory emulation +// can produce *all* consistent execution outcomes. This may be possible +// if Miri's scheduler is sufficiently random and explores all possible +// interleavings of our small test cases after a reasonable number of runs. +// However, since Miri's scheduler is not even pre-emptive, there will +// always be possible interleavings (and possible execution outcomes), +// that can never be observed regardless of how weak memory emulation is +// implemented. + +// Test cases and their consistent outcomes are from +// http://svr-pes20-cppmem.cl.cam.ac.uk/cppmem/ +// Based on +// M. Batty, S. Owens, S. Sarkar, P. Sewell and T. Weber, +// "Mathematizing C++ concurrency", ACM SIGPLAN Notices, vol. 46, no. 1, pp. 55-66, 2011. +// Available: https://ss265.host.cs.st-andrews.ac.uk/papers/n3132.pdf. + +use std::sync::atomic::Ordering::*; +use std::sync::atomic::{fence, AtomicUsize}; +use std::thread::{spawn, yield_now}; + +#[derive(Copy, Clone)] +struct EvilSend(pub T); + +unsafe impl Send for EvilSend {} +unsafe impl Sync for EvilSend {} + +// We can't create static items because we need to run each test +// multiple tests +fn static_atomic(val: usize) -> &'static AtomicUsize { + let ret = Box::leak(Box::new(AtomicUsize::new(val))); + // A workaround to put the initialisation value in the store buffer + ret.store(val, Relaxed); + ret +} + +// Spins and yields until until acquires a pre-determined value +fn acquires_value(loc: &AtomicUsize, val: usize) -> usize { + while loc.load(Acquire) != val { + yield_now(); + } + val +} + +fn reads_value(loc: &AtomicUsize, val: usize) -> usize { + while loc.load(Relaxed) != val { + yield_now(); + } + val +} + +// https://plv.mpi-sws.org/scfix/paper.pdf +// 2.2 Second Problem: SC Fences are Too Weak +fn test_rwc_syncs() { + /* + int main() { + atomic_int x = 0; + atomic_int y = 0; + + {{{ x.store(1,mo_relaxed); + ||| { r1=x.load(mo_relaxed).readsvalue(1); + fence(mo_seq_cst); + r2=y.load(mo_relaxed); } + ||| { y.store(1,mo_relaxed); + fence(mo_seq_cst); + r3=x.load(mo_relaxed); } + }}} + return 0; + } + */ + let x = static_atomic(0); + let y = static_atomic(0); + + let j1 = spawn(move || { + x.store(1, Relaxed); + }); + + let j2 = spawn(move || { + reads_value(&x, 1); + fence(SeqCst); + y.load(Relaxed) + }); + + let j3 = spawn(move || { + y.store(1, Relaxed); + fence(SeqCst); + x.load(Relaxed) + }); + + j1.join().unwrap(); + let b = j2.join().unwrap(); + let c = j3.join().unwrap(); + + assert_ne!((b, c), (0, 0)); +} + +fn test_corr() { + let x = static_atomic(0); + let y = static_atomic(0); + + let j1 = spawn(move || { + x.store(1, Relaxed); + x.store(2, Relaxed); + }); + + let j2 = spawn(move || { + let r2 = x.load(Relaxed); // -------------------------------------+ + y.store(1, Release); // ---------------------+ | + r2 // | | + }); // | | + // |synchronizes-with |happens-before + let j3 = spawn(move || { // | | + acquires_value(&y, 1); // <------------------+ | + x.load(Relaxed) // <----------------------------------------------+ + // The two reads on x are ordered by hb, so they cannot observe values + // differently from the modification order. If the first read observed + // 2, then the second read must observe 2 as well. + }); + + j1.join().unwrap(); + let r2 = j2.join().unwrap(); + let r3 = j3.join().unwrap(); + if r2 == 2 { + assert_eq!(r3, 2); + } +} + +fn test_wrc() { + let x = static_atomic(0); + let y = static_atomic(0); + + let j1 = spawn(move || { + x.store(1, Release); // ---------------------+---------------------+ + }); // | | + // |synchronizes-with | + let j2 = spawn(move || { // | | + acquires_value(&x, 1); // <------------------+ | + y.store(1, Release); // ---------------------+ |happens-before + }); // | | + // |synchronizes-with | + let j3 = spawn(move || { // | | + acquires_value(&y, 1); // <------------------+ | + x.load(Relaxed) // <-----------------------------------------------+ + }); + + j1.join().unwrap(); + j2.join().unwrap(); + let r3 = j3.join().unwrap(); + + assert_eq!(r3, 1); +} + +fn test_message_passing() { + let mut var = 0u32; + let ptr = &mut var as *mut u32; + let x = EvilSend(ptr); + let y = static_atomic(0); + + let j1 = spawn(move || { + unsafe { *x.0 = 1 }; // -----------------------------------------+ + y.store(1, Release); // ---------------------+ | + }); // | | + // |synchronizes-with | happens-before + let j2 = spawn(move || { // | | + acquires_value(&y, 1); // <------------------+ | + unsafe { *x.0 } // <---------------------------------------------+ + }); + + j1.join().unwrap(); + let r2 = j2.join().unwrap(); + + assert_eq!(r2, 1); +} + +// LB+acq_rel+acq_rel +fn test_load_buffering_acq_rel() { + let x = static_atomic(0); + let y = static_atomic(0); + let j1 = spawn(move || { + let r1 = x.load(Acquire); + y.store(1, Release); + r1 + }); + + let j2 = spawn(move || { + let r2 = y.load(Acquire); + x.store(1, Release); + r2 + }); + + let r1 = j1.join().unwrap(); + let r2 = j2.join().unwrap(); + + // 3 consistent outcomes: (0,0), (0,1), (1,0) + assert_ne!((r1, r2), (1, 1)); +} + +fn test_mixed_access() { + /* + int main() { + atomic_int x = 0; + {{{ + x.store(1, mo_relaxed); + }}} + + x.store(2, mo_relaxed); + + {{{ + r1 = x.load(mo_relaxed); + }}} + + return 0; + } + */ + let x = static_atomic(0); + + spawn(move || { + x.store(1, Relaxed); + }) + .join() + .unwrap(); + + x.store(2, Relaxed); + + let r2 = spawn(move || x.load(Relaxed)).join().unwrap(); + + assert_eq!(r2, 2); +} + +pub fn main() { + // TODO: does this make chances of spurious success + // "sufficiently low"? This also takes a long time to run, + // prehaps each function should be its own test case so they + // can be run in parallel + for _ in 0..500 { + test_mixed_access(); + test_load_buffering_acq_rel(); + test_message_passing(); + test_wrc(); + test_corr(); + test_rwc_syncs(); + } +} diff --git a/tests/run-pass/concurrency/weak_memory.stderr b/tests/run-pass/concurrency/weak_memory.stderr new file mode 100644 index 0000000000000..03676519d4f1c --- /dev/null +++ b/tests/run-pass/concurrency/weak_memory.stderr @@ -0,0 +1,2 @@ +warning: thread support is experimental and incomplete: weak memory effects are not emulated. + From e7698f4f07dcec9cf42b3de133f9ca171d0677f0 Mon Sep 17 00:00:00 2001 From: Andy Wang Date: Mon, 27 Dec 2021 19:07:23 +0000 Subject: [PATCH 3173/3747] Implement weak memory emulation --- src/data_race.rs | 170 +++++++++++-- src/lib.rs | 1 + src/machine.rs | 12 +- src/weak_memory.rs | 297 ++++++++++++++++++++++ tests/run-pass/concurrency/weak_memory.rs | 23 ++ 5 files changed, 476 insertions(+), 27 deletions(-) create mode 100644 src/weak_memory.rs diff --git a/src/data_race.rs b/src/data_race.rs index eb67a487b5a50..82ee32ddee71f 100644 --- a/src/data_race.rs +++ b/src/data_race.rs @@ -12,7 +12,7 @@ //! The implementation also models races with memory allocation and deallocation via treating allocation and //! deallocation as a type of write internally for detecting data-races. //! -//! This does not explore weak memory orders and so can still miss data-races +//! Weak memory orders are explored but not all weak behaviours are exhibited, so it can still miss data-races //! but should not report false-positives //! //! Data-race definition from(): @@ -29,22 +29,6 @@ //! This means that the thread-index can be safely re-used, starting on the next timestamp for the newly created //! thread. //! -//! The sequentially consistent ordering corresponds to the ordering that the threads -//! are currently scheduled, this means that the data-race detector has no additional -//! logic for sequentially consistent accesses at the moment since they are indistinguishable -//! from acquire/release operations. If weak memory orderings are explored then this -//! may need to change or be updated accordingly. -//! -//! Per the C++ spec for the memory model a sequentially consistent operation: -//! "A load operation with this memory order performs an acquire operation, -//! a store performs a release operation, and read-modify-write performs -//! both an acquire operation and a release operation, plus a single total -//! order exists in which all threads observe all modifications in the same -//! order (see Sequentially-consistent ordering below) " -//! So in the absence of weak memory effects a seq-cst load & a seq-cst store is identical -//! to an acquire load and a release store given the global sequentially consistent order -//! of the schedule. -//! //! The timestamps used in the data-race detector assign each sequence of non-atomic operations //! followed by a single atomic or concurrent operation a single timestamp. //! Write, Read, Write, ThreadJoin will be represented by a single timestamp value on a thread. @@ -67,6 +51,7 @@ use std::{ mem, }; +use rustc_const_eval::interpret::alloc_range; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_index::vec::{Idx, IndexVec}; use rustc_middle::{mir, ty::layout::TyAndLayout}; @@ -115,10 +100,10 @@ pub enum AtomicFenceOp { /// of a thread, contains the happens-before clock and /// additional metadata to model atomic fence operations. #[derive(Clone, Default, Debug)] -struct ThreadClockSet { +pub struct ThreadClockSet { /// The increasing clock representing timestamps /// that happen-before this thread. - clock: VClock, + pub clock: VClock, /// The set of timestamps that will happen-before this /// thread once it performs an acquire fence. @@ -127,6 +112,12 @@ struct ThreadClockSet { /// The last timestamp of happens-before relations that /// have been released by this thread by a fence. fence_release: VClock, + + pub fence_seqcst: VClock, + + pub write_seqcst: VClock, + + pub read_seqcst: VClock, } impl ThreadClockSet { @@ -169,7 +160,7 @@ pub struct DataRace; /// common case where no atomic operations /// exists on the memory cell. #[derive(Clone, PartialEq, Eq, Default, Debug)] -struct AtomicMemoryCellClocks { +pub struct AtomicMemoryCellClocks { /// The clock-vector of the timestamp of the last atomic /// read operation performed by each thread. /// This detects potential data-races between atomic read @@ -514,7 +505,32 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { atomic: AtomicReadOp, ) -> InterpResult<'tcx, ScalarMaybeUninit> { let this = self.eval_context_ref(); + // This will read from the last store in the modification order of this location. In case + // weak memory emulation is enabled, this may not be the store we will pick to actually read from and return. + // This is fine with StackedBorrow and race checks because they don't concern metadata on + // the *value* (including the associated provenance if this is an AtomicPtr) at this location. + // Only metadata on the location itself is used. let scalar = this.allow_data_races_ref(move |this| this.read_scalar(&place.into()))?; + + if let Some(global) = &this.machine.data_race { + let (alloc_id, base_offset, ..) = this.ptr_get_alloc_id(place.ptr)?; + if let Some(alloc_buffers) = this.get_alloc_extra(alloc_id)?.weak_memory.as_ref() { + if atomic == AtomicReadOp::SeqCst { + global.sc_read(); + } + let mut rng = this.machine.rng.borrow_mut(); + let loaded = alloc_buffers.buffered_read( + alloc_range(base_offset, place.layout.size), + global, + atomic == AtomicReadOp::SeqCst, + &mut *rng, + || this.validate_atomic_load(place, atomic), + )?; + + return Ok(loaded.unwrap_or(scalar)); + } + } + this.validate_atomic_load(place, atomic)?; Ok(scalar) } @@ -528,7 +544,27 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); this.allow_data_races_mut(move |this| this.write_scalar(val, &(*dest).into()))?; - this.validate_atomic_store(dest, atomic) + + this.validate_atomic_store(dest, atomic)?; + let (alloc_id, base_offset, ..) = this.ptr_get_alloc_id(dest.ptr)?; + if let ( + crate::AllocExtra { weak_memory: Some(alloc_buffers), .. }, + crate::Evaluator { data_race: Some(global), .. }, + ) = this.get_alloc_extra_mut(alloc_id)? + { + if atomic == AtomicWriteOp::SeqCst { + global.sc_write(); + } + let size = dest.layout.size; + alloc_buffers.buffered_write( + val, + alloc_range(base_offset, size), + global, + atomic == AtomicWriteOp::SeqCst, + )?; + } + + Ok(()) } /// Perform an atomic operation on a memory location. @@ -550,6 +586,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { this.allow_data_races_mut(|this| this.write_immediate(*val, &(*place).into()))?; this.validate_atomic_rmw(place, atomic)?; + + this.buffered_atomic_rmw(val.to_scalar_or_uninit(), place, atomic)?; Ok(old) } @@ -565,7 +603,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { let old = this.allow_data_races_mut(|this| this.read_scalar(&place.into()))?; this.allow_data_races_mut(|this| this.write_scalar(new, &(*place).into()))?; + this.validate_atomic_rmw(place, atomic)?; + + this.buffered_atomic_rmw(new, place, atomic)?; Ok(old) } @@ -584,15 +625,25 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { let lt = this.binary_op(mir::BinOp::Lt, &old, &rhs)?.to_scalar()?.to_bool()?; let new_val = if min { - if lt { &old } else { &rhs } + if lt { + &old + } else { + &rhs + } } else { - if lt { &rhs } else { &old } + if lt { + &rhs + } else { + &old + } }; this.allow_data_races_mut(|this| this.write_immediate(**new_val, &(*place).into()))?; this.validate_atomic_rmw(place, atomic)?; + this.buffered_atomic_rmw(new_val.to_scalar_or_uninit(), place, atomic)?; + // Return the old value. Ok(old) } @@ -642,14 +693,56 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { if cmpxchg_success { this.allow_data_races_mut(|this| this.write_scalar(new, &(*place).into()))?; this.validate_atomic_rmw(place, success)?; + this.buffered_atomic_rmw(new, place, success)?; } else { this.validate_atomic_load(place, fail)?; + // A failed compare exchange is equivalent to a load, reading from the latest store + // in the modification order. + // Since `old` is only a value and not the store element, we need to separately + // find it in our store buffer and perform load_impl on it. + if let Some(global) = &this.machine.data_race { + if fail == AtomicReadOp::SeqCst { + global.sc_read(); + } + let size = place.layout.size; + let (alloc_id, base_offset, ..) = this.ptr_get_alloc_id(place.ptr)?; + if let Some(alloc_buffers) = this.get_alloc_extra(alloc_id)?.weak_memory.as_ref() { + if global.multi_threaded.get() { + alloc_buffers.read_from_last_store(alloc_range(base_offset, size), global); + } + } + } } // Return the old value. Ok(res) } + fn buffered_atomic_rmw( + &mut self, + new_val: ScalarMaybeUninit, + place: &MPlaceTy<'tcx, Tag>, + atomic: AtomicRwOp, + ) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + let (alloc_id, base_offset, ..) = this.ptr_get_alloc_id(place.ptr)?; + if let ( + crate::AllocExtra { weak_memory: Some(alloc_buffers), .. }, + crate::Evaluator { data_race: Some(global), .. }, + ) = this.get_alloc_extra_mut(alloc_id)? + { + if atomic == AtomicRwOp::SeqCst { + global.sc_read(); + global.sc_write(); + } + let size = place.layout.size; + let range = alloc_range(base_offset, size); + alloc_buffers.read_from_last_store(range, global); + alloc_buffers.buffered_write(new_val, range, global, atomic == AtomicRwOp::SeqCst)?; + } + Ok(()) + } + /// Update the data-race detector for an atomic read occurring at the /// associated memory-place and on the current thread. fn validate_atomic_load( @@ -723,7 +816,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { fn validate_atomic_fence(&mut self, atomic: AtomicFenceOp) -> InterpResult<'tcx> { let this = self.eval_context_mut(); if let Some(data_race) = &mut this.machine.data_race { - data_race.maybe_perform_sync_operation(move |index, mut clocks| { + data_race.maybe_perform_sync_operation(|index, mut clocks| { log::trace!("Atomic fence on {:?} with ordering {:?}", index, atomic); // Apply data-race detection for the current fences @@ -737,6 +830,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { // Either Release | AcqRel | SeqCst clocks.apply_release_fence(); } + if atomic == AtomicFenceOp::SeqCst { + data_race.last_sc_fence.borrow_mut().set_at_index(&clocks.clock, index); + clocks.fence_seqcst.join(&data_race.last_sc_fence.borrow()); + clocks.write_seqcst.join(&data_race.last_sc_write.borrow()); + } // Increment timestamp in case of release semantics. Ok(atomic != AtomicFenceOp::Acquire) @@ -1116,6 +1214,12 @@ pub struct GlobalState { /// The associated vector index will be moved into re-use candidates /// after the join operation occurs. terminated_threads: RefCell>, + + /// The timestamp of last SC fence performed by each thread + last_sc_fence: RefCell, + + /// The timestamp of last SC write performed by each thread + last_sc_write: RefCell, } impl GlobalState { @@ -1131,6 +1235,8 @@ impl GlobalState { active_thread_count: Cell::new(1), reuse_candidates: RefCell::new(FxHashSet::default()), terminated_threads: RefCell::new(FxHashMap::default()), + last_sc_fence: RefCell::new(VClock::default()), + last_sc_write: RefCell::new(VClock::default()), }; // Setup the main-thread since it is not explicitly created: @@ -1445,7 +1551,7 @@ impl GlobalState { /// Load the current vector clock in use and the current set of thread clocks /// in use for the vector. #[inline] - fn current_thread_state(&self) -> (VectorIdx, Ref<'_, ThreadClockSet>) { + pub fn current_thread_state(&self) -> (VectorIdx, Ref<'_, ThreadClockSet>) { let index = self.current_index(); let ref_vector = self.vector_clocks.borrow(); let clocks = Ref::map(ref_vector, |vec| &vec[index]); @@ -1455,7 +1561,7 @@ impl GlobalState { /// Load the current vector clock in use and the current set of thread clocks /// in use for the vector mutably for modification. #[inline] - fn current_thread_state_mut(&self) -> (VectorIdx, RefMut<'_, ThreadClockSet>) { + pub fn current_thread_state_mut(&self) -> (VectorIdx, RefMut<'_, ThreadClockSet>) { let index = self.current_index(); let ref_vector = self.vector_clocks.borrow_mut(); let clocks = RefMut::map(ref_vector, |vec| &mut vec[index]); @@ -1468,4 +1574,16 @@ impl GlobalState { fn current_index(&self) -> VectorIdx { self.current_index.get() } + + // SC ATOMIC STORE rule in the paper. + fn sc_write(&self) { + let (index, clocks) = self.current_thread_state(); + self.last_sc_write.borrow_mut().set_at_index(&clocks.clock, index); + } + + // SC ATOMIC READ rule in the paper. + fn sc_read(&self) { + let (.., mut clocks) = self.current_thread_state_mut(); + clocks.read_seqcst.join(&self.last_sc_fence.borrow()); + } } diff --git a/src/lib.rs b/src/lib.rs index f7c256656a768..06ab2fabab04f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -45,6 +45,7 @@ mod stacked_borrows; mod sync; mod thread; mod vector_clock; +mod weak_memory; // Establish a "crate-wide prelude": we often import `crate::*`. diff --git a/src/machine.rs b/src/machine.rs index 2060bba0b8530..aa2a930ccd251 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -190,6 +190,9 @@ pub struct AllocExtra { /// Data race detection via the use of a vector-clock, /// this is only added if it is enabled. pub data_race: Option, + /// Weak memory emulation via the use of store buffers, + /// this is only added if it is enabled. + pub weak_memory: Option, } /// Precomputed layouts of primitive types @@ -630,9 +633,16 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { } else { None }; + let buffer_alloc = if ecx.machine.weak_memory { + // FIXME: if this is an atomic obejct, we want to supply its initial value + // while allocating the store buffer here. + Some(weak_memory::AllocExtra::new_allocation(alloc.size())) + } else { + None + }; let alloc: Allocation = alloc.convert_tag_add_extra( &ecx.tcx, - AllocExtra { stacked_borrows: stacks, data_race: race_alloc }, + AllocExtra { stacked_borrows: stacks, data_race: race_alloc, weak_memory: buffer_alloc }, |ptr| Evaluator::tag_alloc_base_pointer(ecx, ptr), ); Cow::Owned(alloc) diff --git a/src/weak_memory.rs b/src/weak_memory.rs new file mode 100644 index 0000000000000..c82a31d0a89c1 --- /dev/null +++ b/src/weak_memory.rs @@ -0,0 +1,297 @@ +//! Implementation of C++11-consistent weak memory emulation using store buffers +//! based on Dynamic Race Detection for C++ ("the paper"): +//! https://www.doc.ic.ac.uk/~afd/homepages/papers/pdfs/2017/POPL.pdf + +// Our and the author's own implementation (tsan11) of the paper have some deviations from the provided operational semantics in §5.3: +// 1. In the operational semantics, store elements keep a copy of the atomic object's vector clock (AtomicCellClocks::sync_vector in miri), +// but this is not used anywhere so it's omitted here. +// +// 2. In the operational semantics, each store element keeps the timestamp of a thread when it loads from the store. +// If the same thread loads from the same store element multiple times, then the timestamps at all loads are saved in a list of load elements. +// This is not necessary as later loads by the same thread will always have greater timetstamp values, so we only need to record the timestamp of the first +// load by each thread. This optimisation is done in tsan11 +// (https://github.com/ChrisLidbury/tsan11/blob/ecbd6b81e9b9454e01cba78eb9d88684168132c7/lib/tsan/rtl/tsan_relaxed.h#L35-L37) +// and here. +// +// 3. §4.5 of the paper wants an SC store to mark all existing stores in the buffer that happens before it +// as SC. This is not done in the operational semantics but implemented correctly in tsan11 +// (https://github.com/ChrisLidbury/tsan11/blob/ecbd6b81e9b9454e01cba78eb9d88684168132c7/lib/tsan/rtl/tsan_relaxed.cc#L160-L167) +// and here. +// +// 4. W_SC ; R_SC case requires the SC load to ignore all but last store maked SC (stores not marked SC are not +// affected). But this rule is applied to all loads in ReadsFromSet from the paper (last two lines of code), not just SC load. +// This is implemented correctly in tsan11 +// (https://github.com/ChrisLidbury/tsan11/blob/ecbd6b81e9b9454e01cba78eb9d88684168132c7/lib/tsan/rtl/tsan_relaxed.cc#L295) +// and here. + +use std::{ + cell::{Ref, RefCell, RefMut}, + collections::VecDeque, +}; + +use rustc_const_eval::interpret::{AllocRange, InterpResult, ScalarMaybeUninit}; +use rustc_data_structures::fx::FxHashMap; +use rustc_target::abi::Size; + +use crate::{ + data_race::{GlobalState, ThreadClockSet}, + RangeMap, Tag, VClock, VTimestamp, VectorIdx, +}; + +pub type AllocExtra = StoreBufferAlloc; +#[derive(Debug, Clone)] +pub struct StoreBufferAlloc { + /// Store buffer of each atomic object in this allocation + // Load may modify a StoreBuffer to record the loading thread's + // timestamp so we need interior mutability here. + store_buffer: RefCell>, +} + +impl StoreBufferAlloc { + pub fn new_allocation(len: Size) -> Self { + Self { store_buffer: RefCell::new(RangeMap::new(len, StoreBuffer::default())) } + } + + /// Gets a store buffer associated with an atomic object in this allocation + fn get_store_buffer(&self, range: AllocRange) -> Ref<'_, StoreBuffer> { + Ref::map(self.store_buffer.borrow(), |range_map| { + let (.., store_buffer) = range_map.iter(range.start, range.size).next().unwrap(); + store_buffer + }) + } + + fn get_store_buffer_mut(&self, range: AllocRange) -> RefMut<'_, StoreBuffer> { + RefMut::map(self.store_buffer.borrow_mut(), |range_map| { + let (.., store_buffer) = range_map.iter_mut(range.start, range.size).next().unwrap(); + store_buffer + }) + } + + /// Reads from the last store in modification order + pub fn read_from_last_store<'tcx>(&self, range: AllocRange, global: &GlobalState) { + let store_buffer = self.get_store_buffer(range); + let store_elem = store_buffer.buffer.back(); + if let Some(store_elem) = store_elem { + let (index, clocks) = global.current_thread_state(); + store_elem.load_impl(index, &clocks); + } + } + + pub fn buffered_read<'tcx>( + &self, + range: AllocRange, + global: &GlobalState, + is_seqcst: bool, + rng: &mut (impl rand::Rng + ?Sized), + validate: impl FnOnce() -> InterpResult<'tcx>, + ) -> InterpResult<'tcx, Option>> { + // Having a live borrow to store_buffer while calling validate_atomic_load is fine + // because the race detector doesn't touch store_buffer + let store_buffer = self.get_store_buffer(range); + + let store_elem = { + // The `clocks` we got here must be dropped before calling validate_atomic_load + // as the race detector will update it + let (.., clocks) = global.current_thread_state(); + // Load from a valid entry in the store buffer + store_buffer.fetch_store(is_seqcst, &clocks, &mut *rng) + }; + + // Unlike in write_scalar_atomic, thread clock updates have to be done + // after we've picked a store element from the store buffer, as presented + // in ATOMIC LOAD rule of the paper. This is because fetch_store + // requires access to ThreadClockSet.clock, which is updated by the race detector + validate()?; + + let loaded = store_elem.map(|store_elem| { + let (index, clocks) = global.current_thread_state(); + store_elem.load_impl(index, &clocks) + }); + Ok(loaded) + } + + pub fn buffered_write<'tcx>( + &mut self, + val: ScalarMaybeUninit, + range: AllocRange, + global: &GlobalState, + is_seqcst: bool, + ) -> InterpResult<'tcx> { + let (index, clocks) = global.current_thread_state(); + + let mut store_buffer = self.get_store_buffer_mut(range); + store_buffer.store_impl(val, index, &clocks.clock, is_seqcst); + Ok(()) + } +} + +const STORE_BUFFER_LIMIT: usize = 128; +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct StoreBuffer { + // Stores to this location in modification order + buffer: VecDeque, +} + +impl Default for StoreBuffer { + fn default() -> Self { + let mut buffer = VecDeque::new(); + buffer.reserve(STORE_BUFFER_LIMIT); + Self { buffer } + } +} + +impl<'mir, 'tcx: 'mir> StoreBuffer { + /// Selects a valid store element in the buffer. + /// The buffer does not contain the value used to initialise the atomic object + /// so a fresh atomic object has an empty store buffer until an explicit store. + fn fetch_store( + &self, + is_seqcst: bool, + clocks: &ThreadClockSet, + rng: &mut R, + ) -> Option<&StoreElement> { + use rand::seq::IteratorRandom; + let mut found_sc = false; + // FIXME: this should be an inclusive take_while (stops after a false predicate, but + // includes the element that gave the false), but such function doesn't yet + // exist in the standard libary https://github.com/rust-lang/rust/issues/62208 + let mut keep_searching = true; + let candidates = self + .buffer + .iter() + .rev() + .take_while(move |&store_elem| { + if !keep_searching { + return false; + } + // CoWR: if a store happens-before the current load, + // then we can't read-from anything earlier in modification order. + if store_elem.timestamp <= clocks.clock[store_elem.store_index] { + log::info!("Stopped due to coherent write-read"); + keep_searching = false; + return true; + } + + // CoRR: if there was a load from this store which happened-before the current load, + // then we cannot read-from anything earlier in modification order. + if store_elem.loads.borrow().iter().any(|(&load_index, &load_timestamp)| { + load_timestamp <= clocks.clock[load_index] + }) { + log::info!("Stopped due to coherent read-read"); + keep_searching = false; + return true; + } + + // The current load, which may be sequenced-after an SC fence, can only read-from + // the last store sequenced-before an SC fence in another thread (or any stores + // later than that SC fence) + if store_elem.timestamp <= clocks.fence_seqcst[store_elem.store_index] { + log::info!("Stopped due to coherent load sequenced after sc fence"); + keep_searching = false; + return true; + } + + // The current non-SC load can only read-from the latest SC store (or any stores later than that + // SC store) + if store_elem.timestamp <= clocks.write_seqcst[store_elem.store_index] + && store_elem.is_seqcst + { + log::info!("Stopped due to needing to load from the last SC store"); + keep_searching = false; + return true; + } + + // The current SC load can only read-from the last store sequenced-before + // the last SC fence (or any stores later than the SC fence) + if is_seqcst && store_elem.timestamp <= clocks.read_seqcst[store_elem.store_index] { + log::info!("Stopped due to sc load needing to load from the last SC store before an SC fence"); + keep_searching = false; + return true; + } + + true + }) + .filter(|&store_elem| { + if is_seqcst { + // An SC load needs to ignore all but last store maked SC (stores not marked SC are not + // affected) + let include = !(store_elem.is_seqcst && found_sc); + found_sc |= store_elem.is_seqcst; + include + } else { + true + } + }); + + candidates.choose(rng) + } + + /// ATOMIC STORE IMPL in the paper (except we don't need the location's vector clock) + fn store_impl( + &mut self, + val: ScalarMaybeUninit, + index: VectorIdx, + thread_clock: &VClock, + is_seqcst: bool, + ) { + let store_elem = StoreElement { + store_index: index, + timestamp: thread_clock[index], + // In the language provided in the paper, an atomic store takes the value from a + // non-atomic memory location. + // But we already have the immediate value here so we don't need to do the memory + // access + val, + is_seqcst, + loads: RefCell::new(FxHashMap::default()), + }; + self.buffer.push_back(store_elem); + if self.buffer.len() > STORE_BUFFER_LIMIT { + self.buffer.pop_front(); + } + if is_seqcst { + // Every store that happens before this needs to be marked as SC + // so that in a later SC load, only the last SC store (i.e. this one) or stores that + // aren't ordered by hb with the last SC is picked. + self.buffer.iter_mut().rev().for_each(|elem| { + if elem.timestamp <= thread_clock[elem.store_index] { + elem.is_seqcst = true; + } + }) + } + } +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct StoreElement { + /// The identifier of the vector index, corresponding to a thread + /// that performed the store. + store_index: VectorIdx, + + /// Whether this store is SC. + is_seqcst: bool, + + /// The timestamp of the storing thread when it performed the store + timestamp: VTimestamp, + /// The value of this store + val: ScalarMaybeUninit, + + /// Timestamp of first loads from this store element by each thread + /// Behind a RefCell to keep load op take &self + loads: RefCell>, +} + +impl StoreElement { + /// ATOMIC LOAD IMPL in the paper + /// Unlike the operational semantics in the paper, we don't need to keep track + /// of the thread timestamp for every single load. Keeping track of the first (smallest) + /// timestamp of each thread that has loaded from a store is sufficient: if the earliest + /// load of another thread happens before the current one, then we must stop searching the store + /// buffer regardless of subsequent loads by the same thread; if the earliest load of another + /// thread doesn't happen before the current one, then no subsequent load by the other thread + /// can happen before the current one. + fn load_impl(&self, index: VectorIdx, clocks: &ThreadClockSet) -> ScalarMaybeUninit { + let _ = self.loads.borrow_mut().try_insert(index, clocks.clock[index]); + self.val + } +} diff --git a/tests/run-pass/concurrency/weak_memory.rs b/tests/run-pass/concurrency/weak_memory.rs index bd3d1de7c23e2..b8e780ade1a03 100644 --- a/tests/run-pass/concurrency/weak_memory.rs +++ b/tests/run-pass/concurrency/weak_memory.rs @@ -63,6 +63,28 @@ fn reads_value(loc: &AtomicUsize, val: usize) -> usize { val } +// https://plv.mpi-sws.org/scfix/paper.pdf +// Test case SB +fn test_sc_store_buffering() { + let x = static_atomic(0); + let y = static_atomic(0); + + let j1 = spawn(move || { + x.store(1, SeqCst); + y.load(SeqCst) + }); + + let j2 = spawn(move || { + y.store(1, SeqCst); + x.load(SeqCst) + }); + + let a = j1.join().unwrap(); + let b = j2.join().unwrap(); + + assert_ne!((a, b), (0, 0)); +} + // https://plv.mpi-sws.org/scfix/paper.pdf // 2.2 Second Problem: SC Fences are Too Weak fn test_rwc_syncs() { @@ -247,6 +269,7 @@ pub fn main() { // prehaps each function should be its own test case so they // can be run in parallel for _ in 0..500 { + test_sc_store_buffering(); test_mixed_access(); test_load_buffering_acq_rel(); test_message_passing(); From aca3b3a645e6d0295e9f1829c37af811a6de5251 Mon Sep 17 00:00:00 2001 From: Andy Wang Date: Fri, 15 Apr 2022 21:44:22 +0100 Subject: [PATCH 3174/3747] set_at_index sets the default value (0) if index doesn't exist in the other vector --- src/vector_clock.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/vector_clock.rs b/src/vector_clock.rs index e13e9c39fc69c..716fdba0f67c2 100644 --- a/src/vector_clock.rs +++ b/src/vector_clock.rs @@ -108,10 +108,8 @@ impl VClock { /// Set the element at the current index of the vector pub fn set_at_index(&mut self, other: &Self, idx: VectorIdx) { - let idx = idx.index(); - let mut_slice = self.get_mut_with_min_len(idx + 1); - let slice = other.as_slice(); - mut_slice[idx] = slice[idx]; + let mut_slice = self.get_mut_with_min_len(idx.index() + 1); + mut_slice[idx.index()] = other[idx]; } /// Set the vector to the all-zero vector From cf266584b7d9e42f6b1ba622b828e7d95c243225 Mon Sep 17 00:00:00 2001 From: Andy Wang Date: Sat, 16 Apr 2022 01:01:49 +0100 Subject: [PATCH 3175/3747] Comment out and provide context to C++20 test --- tests/run-pass/concurrency/weak_memory.rs | 144 +++++++++++----------- 1 file changed, 75 insertions(+), 69 deletions(-) diff --git a/tests/run-pass/concurrency/weak_memory.rs b/tests/run-pass/concurrency/weak_memory.rs index b8e780ade1a03..efbbc45909cfd 100644 --- a/tests/run-pass/concurrency/weak_memory.rs +++ b/tests/run-pass/concurrency/weak_memory.rs @@ -63,73 +63,6 @@ fn reads_value(loc: &AtomicUsize, val: usize) -> usize { val } -// https://plv.mpi-sws.org/scfix/paper.pdf -// Test case SB -fn test_sc_store_buffering() { - let x = static_atomic(0); - let y = static_atomic(0); - - let j1 = spawn(move || { - x.store(1, SeqCst); - y.load(SeqCst) - }); - - let j2 = spawn(move || { - y.store(1, SeqCst); - x.load(SeqCst) - }); - - let a = j1.join().unwrap(); - let b = j2.join().unwrap(); - - assert_ne!((a, b), (0, 0)); -} - -// https://plv.mpi-sws.org/scfix/paper.pdf -// 2.2 Second Problem: SC Fences are Too Weak -fn test_rwc_syncs() { - /* - int main() { - atomic_int x = 0; - atomic_int y = 0; - - {{{ x.store(1,mo_relaxed); - ||| { r1=x.load(mo_relaxed).readsvalue(1); - fence(mo_seq_cst); - r2=y.load(mo_relaxed); } - ||| { y.store(1,mo_relaxed); - fence(mo_seq_cst); - r3=x.load(mo_relaxed); } - }}} - return 0; - } - */ - let x = static_atomic(0); - let y = static_atomic(0); - - let j1 = spawn(move || { - x.store(1, Relaxed); - }); - - let j2 = spawn(move || { - reads_value(&x, 1); - fence(SeqCst); - y.load(Relaxed) - }); - - let j3 = spawn(move || { - y.store(1, Relaxed); - fence(SeqCst); - x.load(Relaxed) - }); - - j1.join().unwrap(); - let b = j2.join().unwrap(); - let c = j3.join().unwrap(); - - assert_ne!((b, c), (0, 0)); -} - fn test_corr() { let x = static_atomic(0); let y = static_atomic(0); @@ -263,18 +196,91 @@ fn test_mixed_access() { assert_eq!(r2, 2); } +// The following two tests are taken from Repairing Sequential Consistency in C/C++11 +// by Lahav et al. +// https://plv.mpi-sws.org/scfix/paper.pdf + +// Test case SB +fn test_sc_store_buffering() { + let x = static_atomic(0); + let y = static_atomic(0); + + let j1 = spawn(move || { + x.store(1, SeqCst); + y.load(SeqCst) + }); + + let j2 = spawn(move || { + y.store(1, SeqCst); + x.load(SeqCst) + }); + + let a = j1.join().unwrap(); + let b = j2.join().unwrap(); + + assert_ne!((a, b), (0, 0)); +} + +// 2.2 Second Problem: SC Fences are Too Weak +// This test should pass under the C++20 model Rust is using. +// Unfortunately, Miri's weak memory emulation only follows C++11 model +// as we don't know how to correctly emulate C++20's revised SC semantics +#[allow(dead_code)] +fn test_cpp20_rwc_syncs() { + /* + int main() { + atomic_int x = 0; + atomic_int y = 0; + + {{{ x.store(1,mo_relaxed); + ||| { r1=x.load(mo_relaxed).readsvalue(1); + fence(mo_seq_cst); + r2=y.load(mo_relaxed); } + ||| { y.store(1,mo_relaxed); + fence(mo_seq_cst); + r3=x.load(mo_relaxed); } + }}} + return 0; + } + */ + let x = static_atomic(0); + let y = static_atomic(0); + + let j1 = spawn(move || { + x.store(1, Relaxed); + }); + + let j2 = spawn(move || { + reads_value(&x, 1); + fence(SeqCst); + y.load(Relaxed) + }); + + let j3 = spawn(move || { + y.store(1, Relaxed); + fence(SeqCst); + x.load(Relaxed) + }); + + j1.join().unwrap(); + let b = j2.join().unwrap(); + let c = j3.join().unwrap(); + + assert_ne!((b, c), (0, 0)); +} + pub fn main() { // TODO: does this make chances of spurious success // "sufficiently low"? This also takes a long time to run, // prehaps each function should be its own test case so they // can be run in parallel for _ in 0..500 { - test_sc_store_buffering(); test_mixed_access(); test_load_buffering_acq_rel(); test_message_passing(); test_wrc(); test_corr(); - test_rwc_syncs(); + test_sc_store_buffering(); + // test_cpp20_rwc_syncs(); } } From ecdab5ff35297e9d70647f076b3aba656c8ad850 Mon Sep 17 00:00:00 2001 From: Andy Wang Date: Sun, 1 May 2022 12:36:00 +0100 Subject: [PATCH 3176/3747] Clearer boundries between alloc metadata with multiple buffers and an individual store buffer --- src/data_race.rs | 20 ++++++++--------- src/weak_memory.rs | 56 +++++++++++++++++++++------------------------- 2 files changed, 36 insertions(+), 40 deletions(-) diff --git a/src/data_race.rs b/src/data_race.rs index 82ee32ddee71f..303cf7007e753 100644 --- a/src/data_race.rs +++ b/src/data_race.rs @@ -519,8 +519,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { global.sc_read(); } let mut rng = this.machine.rng.borrow_mut(); - let loaded = alloc_buffers.buffered_read( - alloc_range(base_offset, place.layout.size), + let buffer = alloc_buffers.get_store_buffer(alloc_range(base_offset, place.layout.size)); + let loaded = buffer.buffered_read( global, atomic == AtomicReadOp::SeqCst, &mut *rng, @@ -555,10 +555,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { if atomic == AtomicWriteOp::SeqCst { global.sc_write(); } - let size = dest.layout.size; - alloc_buffers.buffered_write( + let mut buffer = alloc_buffers.get_store_buffer_mut(alloc_range(base_offset, dest.layout.size)); + buffer.buffered_write( val, - alloc_range(base_offset, size), global, atomic == AtomicWriteOp::SeqCst, )?; @@ -708,7 +707,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { let (alloc_id, base_offset, ..) = this.ptr_get_alloc_id(place.ptr)?; if let Some(alloc_buffers) = this.get_alloc_extra(alloc_id)?.weak_memory.as_ref() { if global.multi_threaded.get() { - alloc_buffers.read_from_last_store(alloc_range(base_offset, size), global); + let buffer = alloc_buffers.get_store_buffer(alloc_range(base_offset, size)); + buffer.read_from_last_store(global); } } } @@ -735,10 +735,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { global.sc_read(); global.sc_write(); } - let size = place.layout.size; - let range = alloc_range(base_offset, size); - alloc_buffers.read_from_last_store(range, global); - alloc_buffers.buffered_write(new_val, range, global, atomic == AtomicRwOp::SeqCst)?; + let range = alloc_range(base_offset, place.layout.size); + let mut buffer = alloc_buffers.get_store_buffer_mut(range); + buffer.read_from_last_store(global); + buffer.buffered_write(new_val, global, atomic == AtomicRwOp::SeqCst)?; } Ok(()) } diff --git a/src/weak_memory.rs b/src/weak_memory.rs index c82a31d0a89c1..2cf9a98b13351 100644 --- a/src/weak_memory.rs +++ b/src/weak_memory.rs @@ -53,33 +53,49 @@ impl StoreBufferAlloc { } /// Gets a store buffer associated with an atomic object in this allocation - fn get_store_buffer(&self, range: AllocRange) -> Ref<'_, StoreBuffer> { + pub fn get_store_buffer(&self, range: AllocRange) -> Ref<'_, StoreBuffer> { Ref::map(self.store_buffer.borrow(), |range_map| { let (.., store_buffer) = range_map.iter(range.start, range.size).next().unwrap(); store_buffer }) } - fn get_store_buffer_mut(&self, range: AllocRange) -> RefMut<'_, StoreBuffer> { + pub fn get_store_buffer_mut(&self, range: AllocRange) -> RefMut<'_, StoreBuffer> { RefMut::map(self.store_buffer.borrow_mut(), |range_map| { let (.., store_buffer) = range_map.iter_mut(range.start, range.size).next().unwrap(); store_buffer }) } +} + +const STORE_BUFFER_LIMIT: usize = 128; +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct StoreBuffer { + // Stores to this location in modification order + buffer: VecDeque, +} + +impl Default for StoreBuffer { + fn default() -> Self { + let mut buffer = VecDeque::new(); + buffer.reserve(STORE_BUFFER_LIMIT); + Self { buffer } + } +} + +impl<'mir, 'tcx: 'mir> StoreBuffer { /// Reads from the last store in modification order - pub fn read_from_last_store<'tcx>(&self, range: AllocRange, global: &GlobalState) { - let store_buffer = self.get_store_buffer(range); - let store_elem = store_buffer.buffer.back(); + pub fn read_from_last_store(&self, global: &GlobalState) { + let store_elem = self.buffer.back(); if let Some(store_elem) = store_elem { let (index, clocks) = global.current_thread_state(); store_elem.load_impl(index, &clocks); } } - pub fn buffered_read<'tcx>( + pub fn buffered_read( &self, - range: AllocRange, global: &GlobalState, is_seqcst: bool, rng: &mut (impl rand::Rng + ?Sized), @@ -87,14 +103,13 @@ impl StoreBufferAlloc { ) -> InterpResult<'tcx, Option>> { // Having a live borrow to store_buffer while calling validate_atomic_load is fine // because the race detector doesn't touch store_buffer - let store_buffer = self.get_store_buffer(range); let store_elem = { // The `clocks` we got here must be dropped before calling validate_atomic_load // as the race detector will update it let (.., clocks) = global.current_thread_state(); // Load from a valid entry in the store buffer - store_buffer.fetch_store(is_seqcst, &clocks, &mut *rng) + self.fetch_store(is_seqcst, &clocks, &mut *rng) }; // Unlike in write_scalar_atomic, thread clock updates have to be done @@ -110,37 +125,18 @@ impl StoreBufferAlloc { Ok(loaded) } - pub fn buffered_write<'tcx>( + pub fn buffered_write( &mut self, val: ScalarMaybeUninit, - range: AllocRange, global: &GlobalState, is_seqcst: bool, ) -> InterpResult<'tcx> { let (index, clocks) = global.current_thread_state(); - let mut store_buffer = self.get_store_buffer_mut(range); - store_buffer.store_impl(val, index, &clocks.clock, is_seqcst); + self.store_impl(val, index, &clocks.clock, is_seqcst); Ok(()) } -} -const STORE_BUFFER_LIMIT: usize = 128; -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct StoreBuffer { - // Stores to this location in modification order - buffer: VecDeque, -} - -impl Default for StoreBuffer { - fn default() -> Self { - let mut buffer = VecDeque::new(); - buffer.reserve(STORE_BUFFER_LIMIT); - Self { buffer } - } -} - -impl<'mir, 'tcx: 'mir> StoreBuffer { /// Selects a valid store element in the buffer. /// The buffer does not contain the value used to initialise the atomic object /// so a fresh atomic object has an empty store buffer until an explicit store. From 53f4887659fd587ca551db664c317fb15998dfd0 Mon Sep 17 00:00:00 2001 From: Andy Wang Date: Fri, 6 May 2022 23:46:29 +0100 Subject: [PATCH 3177/3747] Use a new AllocationMap to store store buffers in the same allocation --- src/allocation_map.rs | 272 ++++++++++++++++++++++++++++++++++++++++++ src/data_race.rs | 26 ++-- src/lib.rs | 1 + src/machine.rs | 8 +- src/weak_memory.rs | 74 +++++++++--- 5 files changed, 342 insertions(+), 39 deletions(-) create mode 100644 src/allocation_map.rs diff --git a/src/allocation_map.rs b/src/allocation_map.rs new file mode 100644 index 0000000000000..6c14ce165407f --- /dev/null +++ b/src/allocation_map.rs @@ -0,0 +1,272 @@ +//! Implements a map from allocation ranges to data. +//! This is somewhat similar to RangeMap, but the ranges +//! and data are discrete and non-splittable. An allocation in the +//! map will always have the same range until explicitly removed + +use rustc_target::abi::Size; +use std::ops::{Index, IndexMut, Range}; + +use rustc_const_eval::interpret::AllocRange; + +#[derive(Clone, Debug)] +struct Elem { + /// The range covered by this element; never empty. + range: AllocRange, + /// The data stored for this element. + data: T, +} + +/// Index of an allocation within the map +type Position = usize; + +#[derive(Clone, Debug)] +pub struct AllocationMap { + v: Vec>, +} + +#[derive(Clone, Debug, PartialEq)] +pub enum AccessType { + /// The access perfectly overlaps (same offset and range) with the exsiting allocation + PerfectlyOverlapping(Position), + /// The access does not touch any exising allocation + Empty(Position), + /// The access overlaps with one or more existing allocations + ImperfectlyOverlapping(Range), +} + +impl AllocationMap { + pub fn new() -> Self { + Self { v: Vec::new() } + } + + /// Finds the position of the allocation containing the given offset. If the offset is not + /// in an existing allocation, then returns Err containing the position + /// where such allocation should be inserted + fn find_offset(&self, offset: Size) -> Result { + // We do a binary search. + let mut left = 0usize; // inclusive + let mut right = self.v.len(); // exclusive + loop { + if left == right { + // No element contains the given offset. But the + // index is where such element should be placed at. + return Err(left); + } + let candidate = left.checked_add(right).unwrap() / 2; + let elem = &self.v[candidate]; + if offset < elem.range.start { + // We are too far right (offset is further left). + debug_assert!(candidate < right); // we are making progress + right = candidate; + } else if offset >= elem.range.end() { + // We are too far left (offset is further right). + debug_assert!(candidate >= left); // we are making progress + left = candidate + 1; + } else { + // This is it! + return Ok(candidate); + } + } + } + + /// Determines whether a given access on `range` overlaps with + /// an existing allocation + pub fn access_type(&self, range: AllocRange) -> AccessType { + match self.find_offset(range.start) { + Ok(index) => { + // Start of the range belongs to an existing object, now let's check the overlapping situation + let elem = &self.v[index]; + // FIXME: derive Eq for AllocRange in rustc + if elem.range.start == range.start && elem.range.size == range.size { + // Happy case: perfectly overlapping access + AccessType::PerfectlyOverlapping(index) + } else { + // FIXME: add a last() method to AllocRange that returns the last inclusive offset (end() is exclusive) + let end_index = match self.find_offset(range.end() - Size::from_bytes(1)) { + // If the end lands in an existing object, add one to get the exclusive index + Ok(inclusive) => inclusive + 1, + Err(exclusive) => exclusive, + }; + + AccessType::ImperfectlyOverlapping(index..end_index) + } + } + Err(index) => { + // Start of the range doesn't belong to an existing object + match self.find_offset(range.end() - Size::from_bytes(1)) { + // Neither does the end + Err(end_index) => + if index == end_index { + // There's nothing between the start and the end, so the range thing is empty + AccessType::Empty(index) + } else { + // Otherwise we have entirely covered an existing object + AccessType::ImperfectlyOverlapping(index..end_index) + }, + // Otherwise at least part of it overlaps with something else + Ok(end_index) => AccessType::ImperfectlyOverlapping(index..end_index + 1), + } + } + } + } + + /// Inserts an object and its occupied range at given position + pub fn insert(&mut self, index: Position, range: AllocRange, data: T) { + self.v.insert(index, Elem { range, data }); + // If we aren't the first element, then our start must be greater than the preivous element's end + if index > 0 { + debug_assert!(self.v[index - 1].range.end() <= range.start); + } + // If we aren't the last element, then our end must be smaller than next element's start + if index < self.v.len() - 1 { + debug_assert!(range.end() <= self.v[index + 1].range.start); + } + } + + /// Removes an object at given position + pub fn remove(&mut self, index: Position) -> T { + self.v.remove(index).data + } +} + +impl Index for AllocationMap { + type Output = T; + + fn index(&self, index: usize) -> &Self::Output { + &self.v[index].data + } +} + +impl IndexMut for AllocationMap { + fn index_mut(&mut self, index: usize) -> &mut Self::Output { + &mut self.v[index].data + } +} + +#[cfg(test)] +mod tests { + use rustc_const_eval::interpret::alloc_range; + + use super::*; + + #[test] + fn empty_map() { + // FIXME: make Size::from_bytes const + let four = Size::from_bytes(4); + let map = AllocationMap::<()>::new(); + + // Correctly tells where we should insert the first element (at index 0) + assert_eq!(map.find_offset(Size::from_bytes(3)), Err(0)); + + // Correctly tells the access type along with the supposed index + assert_eq!(map.access_type(alloc_range(Size::ZERO, four)), AccessType::Empty(0)); + } + + #[test] + #[should_panic] + fn no_overlapping_inserts() { + let four = Size::from_bytes(4); + + let mut map = AllocationMap::<&str>::new(); + + // |_|_|_|_|#|#|#|#|_|_|_|_|... + // 0 1 2 3 4 5 6 7 8 9 a b c d + map.insert(0, alloc_range(four, four), "#"); + // |_|_|_|_|#|#|#|#|_|_|_|_|... + // 0 ^ ^ ^ ^ 5 6 7 8 9 a b c d + map.insert(0, alloc_range(Size::from_bytes(1), four), "@"); + } + + #[test] + fn boundaries() { + let four = Size::from_bytes(4); + + let mut map = AllocationMap::<&str>::new(); + + // |#|#|#|#|_|_|... + // 0 1 2 3 4 5 + map.insert(0, alloc_range(Size::ZERO, four), "#"); + // |#|#|#|#|_|_|... + // 0 1 2 3 ^ 5 + assert_eq!(map.find_offset(four), Err(1)); + // |#|#|#|#|_|_|_|_|_|... + // 0 1 2 3 ^ ^ ^ ^ 8 + assert_eq!(map.access_type(alloc_range(four, four)), AccessType::Empty(1)); + + let eight = Size::from_bytes(8); + // |#|#|#|#|_|_|_|_|@|@|@|@|_|_|... + // 0 1 2 3 4 5 6 7 8 9 a b c d + map.insert(1, alloc_range(eight, four), "@"); + // |#|#|#|#|_|_|_|_|@|@|@|@|_|_|... + // 0 1 2 3 4 5 6 ^ 8 9 a b c d + assert_eq!(map.find_offset(Size::from_bytes(7)), Err(1)); + // |#|#|#|#|_|_|_|_|@|@|@|@|_|_|... + // 0 1 2 3 ^ ^ ^ ^ 8 9 a b c d + assert_eq!(map.access_type(alloc_range(four, four)), AccessType::Empty(1)); + } + + #[test] + fn perfectly_overlapping() { + let four = Size::from_bytes(4); + + let mut map = AllocationMap::<&str>::new(); + + // |#|#|#|#|_|_|... + // 0 1 2 3 4 5 + map.insert(0, alloc_range(Size::ZERO, four), "#"); + // |#|#|#|#|_|_|... + // ^ ^ ^ ^ 4 5 + assert_eq!(map.find_offset(Size::ZERO), Ok(0)); + assert_eq!( + map.access_type(alloc_range(Size::ZERO, four)), + AccessType::PerfectlyOverlapping(0) + ); + + // |#|#|#|#|@|@|@|@|_|... + // 0 1 2 3 4 5 6 7 8 + map.insert(1, alloc_range(four, four), "@"); + // |#|#|#|#|@|@|@|@|_|... + // 0 1 2 3 ^ ^ ^ ^ 8 + assert_eq!(map.find_offset(four), Ok(1)); + assert_eq!(map.access_type(alloc_range(four, four)), AccessType::PerfectlyOverlapping(1)); + } + + #[test] + fn straddling() { + let four = Size::from_bytes(4); + + let mut map = AllocationMap::<&str>::new(); + + // |_|_|_|_|#|#|#|#|_|_|_|_|... + // 0 1 2 3 4 5 6 7 8 9 a b c d + map.insert(0, alloc_range(four, four), "#"); + // |_|_|_|_|#|#|#|#|_|_|_|_|... + // 0 1 ^ ^ ^ ^ 6 7 8 9 a b c d + assert_eq!( + map.access_type(alloc_range(Size::from_bytes(2), four)), + AccessType::ImperfectlyOverlapping(0..1) + ); + // |_|_|_|_|#|#|#|#|_|_|_|_|... + // 0 1 2 3 4 5 ^ ^ ^ ^ a b c d + assert_eq!( + map.access_type(alloc_range(Size::from_bytes(6), four)), + AccessType::ImperfectlyOverlapping(0..1) + ); + // |_|_|_|_|#|#|#|#|_|_|_|_|... + // 0 1 ^ ^ ^ ^ ^ ^ ^ ^ a b c d + assert_eq!( + map.access_type(alloc_range(Size::from_bytes(2), Size::from_bytes(8))), + AccessType::ImperfectlyOverlapping(0..1) + ); + + // |_|_|_|_|#|#|#|#|_|_|@|@|_|_|... + // 0 1 2 3 4 5 6 7 8 9 a b c d + map.insert(1, alloc_range(Size::from_bytes(10), Size::from_bytes(2)), "@"); + // |_|_|_|_|#|#|#|#|_|_|@|@|_|_|... + // 0 1 2 3 4 5 ^ ^ ^ ^ ^ ^ ^ ^ + assert_eq!( + map.access_type(alloc_range(Size::from_bytes(6), Size::from_bytes(8))), + AccessType::ImperfectlyOverlapping(0..2) + ); + } +} diff --git a/src/data_race.rs b/src/data_race.rs index 303cf7007e753..d9bfbc1bdb5a1 100644 --- a/src/data_race.rs +++ b/src/data_race.rs @@ -519,7 +519,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { global.sc_read(); } let mut rng = this.machine.rng.borrow_mut(); - let buffer = alloc_buffers.get_store_buffer(alloc_range(base_offset, place.layout.size)); + let buffer = + alloc_buffers.get_store_buffer(alloc_range(base_offset, place.layout.size)); let loaded = buffer.buffered_read( global, atomic == AtomicReadOp::SeqCst, @@ -555,12 +556,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { if atomic == AtomicWriteOp::SeqCst { global.sc_write(); } - let mut buffer = alloc_buffers.get_store_buffer_mut(alloc_range(base_offset, dest.layout.size)); - buffer.buffered_write( - val, - global, - atomic == AtomicWriteOp::SeqCst, - )?; + let buffer = + alloc_buffers.get_store_buffer_mut(alloc_range(base_offset, dest.layout.size)); + buffer.buffered_write(val, global, atomic == AtomicWriteOp::SeqCst)?; } Ok(()) @@ -624,17 +622,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { let lt = this.binary_op(mir::BinOp::Lt, &old, &rhs)?.to_scalar()?.to_bool()?; let new_val = if min { - if lt { - &old - } else { - &rhs - } + if lt { &old } else { &rhs } } else { - if lt { - &rhs - } else { - &old - } + if lt { &rhs } else { &old } }; this.allow_data_races_mut(|this| this.write_immediate(**new_val, &(*place).into()))?; @@ -736,7 +726,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { global.sc_write(); } let range = alloc_range(base_offset, place.layout.size); - let mut buffer = alloc_buffers.get_store_buffer_mut(range); + let buffer = alloc_buffers.get_store_buffer_mut(range); buffer.read_from_last_store(global); buffer.buffered_write(new_val, global, atomic == AtomicRwOp::SeqCst)?; } diff --git a/src/lib.rs b/src/lib.rs index 06ab2fabab04f..3270a57c4964e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -31,6 +31,7 @@ extern crate rustc_session; extern crate rustc_span; extern crate rustc_target; +mod allocation_map; mod data_race; mod diagnostics; mod eval; diff --git a/src/machine.rs b/src/machine.rs index aa2a930ccd251..ca7fff7b08b9c 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -636,13 +636,17 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { let buffer_alloc = if ecx.machine.weak_memory { // FIXME: if this is an atomic obejct, we want to supply its initial value // while allocating the store buffer here. - Some(weak_memory::AllocExtra::new_allocation(alloc.size())) + Some(weak_memory::AllocExtra::new_allocation()) } else { None }; let alloc: Allocation = alloc.convert_tag_add_extra( &ecx.tcx, - AllocExtra { stacked_borrows: stacks, data_race: race_alloc, weak_memory: buffer_alloc }, + AllocExtra { + stacked_borrows: stacks, + data_race: race_alloc, + weak_memory: buffer_alloc, + }, |ptr| Evaluator::tag_alloc_base_pointer(ecx, ptr), ); Cow::Owned(alloc) diff --git a/src/weak_memory.rs b/src/weak_memory.rs index 2cf9a98b13351..34c669239d5b8 100644 --- a/src/weak_memory.rs +++ b/src/weak_memory.rs @@ -12,7 +12,7 @@ // load by each thread. This optimisation is done in tsan11 // (https://github.com/ChrisLidbury/tsan11/blob/ecbd6b81e9b9454e01cba78eb9d88684168132c7/lib/tsan/rtl/tsan_relaxed.h#L35-L37) // and here. -// +// // 3. §4.5 of the paper wants an SC store to mark all existing stores in the buffer that happens before it // as SC. This is not done in the operational semantics but implemented correctly in tsan11 // (https://github.com/ChrisLidbury/tsan11/blob/ecbd6b81e9b9454e01cba78eb9d88684168132c7/lib/tsan/rtl/tsan_relaxed.cc#L160-L167) @@ -25,48 +25,84 @@ // and here. use std::{ - cell::{Ref, RefCell, RefMut}, + cell::{Ref, RefCell}, collections::VecDeque, }; use rustc_const_eval::interpret::{AllocRange, InterpResult, ScalarMaybeUninit}; use rustc_data_structures::fx::FxHashMap; -use rustc_target::abi::Size; use crate::{ + allocation_map::{AccessType, AllocationMap}, data_race::{GlobalState, ThreadClockSet}, - RangeMap, Tag, VClock, VTimestamp, VectorIdx, + Tag, VClock, VTimestamp, VectorIdx, }; pub type AllocExtra = StoreBufferAlloc; + #[derive(Debug, Clone)] pub struct StoreBufferAlloc { /// Store buffer of each atomic object in this allocation - // Load may modify a StoreBuffer to record the loading thread's - // timestamp so we need interior mutability here. - store_buffer: RefCell>, + // Behind a RefCell because we need to allocate/remove on read access + store_buffer: RefCell>, } impl StoreBufferAlloc { - pub fn new_allocation(len: Size) -> Self { - Self { store_buffer: RefCell::new(RangeMap::new(len, StoreBuffer::default())) } + pub fn new_allocation() -> Self { + Self { store_buffer: RefCell::new(AllocationMap::new()) } } /// Gets a store buffer associated with an atomic object in this allocation pub fn get_store_buffer(&self, range: AllocRange) -> Ref<'_, StoreBuffer> { - Ref::map(self.store_buffer.borrow(), |range_map| { - let (.., store_buffer) = range_map.iter(range.start, range.size).next().unwrap(); - store_buffer - }) + let access_type = self.store_buffer.borrow().access_type(range); + let index = match access_type { + AccessType::PerfectlyOverlapping(index) => index, + AccessType::Empty(index) => { + // First atomic access on this range, allocate a new StoreBuffer + let mut buffer = self.store_buffer.borrow_mut(); + buffer.insert(index, range, StoreBuffer::default()); + index + } + AccessType::ImperfectlyOverlapping(index_range) => { + // Accesses that imperfectly overlaps with existing atomic objects + // do not have well-defined behaviours. But we don't throw a UB here + // because we have (or will) checked that all bytes in the current + // access are non-racy. + // The behaviour here is that we delete all the existing objects this + // access touches, and allocate a new and empty one for the exact range. + // A read on an empty buffer returns None, which means the program will + // observe the latest value in modification order at every byte. + let mut buffer = self.store_buffer.borrow_mut(); + for index in index_range.clone() { + buffer.remove(index); + } + buffer.insert(index_range.start, range, StoreBuffer::default()); + index_range.start + } + }; + Ref::map(self.store_buffer.borrow(), |buffer| &buffer[index]) } - pub fn get_store_buffer_mut(&self, range: AllocRange) -> RefMut<'_, StoreBuffer> { - RefMut::map(self.store_buffer.borrow_mut(), |range_map| { - let (.., store_buffer) = range_map.iter_mut(range.start, range.size).next().unwrap(); - store_buffer - }) + /// Gets a mutable store buffer associated with an atomic object in this allocation + pub fn get_store_buffer_mut(&mut self, range: AllocRange) -> &mut StoreBuffer { + let buffer = self.store_buffer.get_mut(); + let access_type = buffer.access_type(range); + let index = match access_type { + AccessType::PerfectlyOverlapping(index) => index, + AccessType::Empty(index) => { + buffer.insert(index, range, StoreBuffer::default()); + index + } + AccessType::ImperfectlyOverlapping(index_range) => { + for index in index_range.clone() { + buffer.remove(index); + } + buffer.insert(index_range.start, range, StoreBuffer::default()); + index_range.start + } + }; + &mut buffer[index] } - } const STORE_BUFFER_LIMIT: usize = 128; From a71b10381e1e956e87bcd75ffc5ec7273680aba6 Mon Sep 17 00:00:00 2001 From: Andy Wang Date: Sat, 7 May 2022 00:31:17 +0100 Subject: [PATCH 3178/3747] Add imperfectly overlapping test --- tests/run-pass/concurrency/weak_memory.rs | 24 ++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/tests/run-pass/concurrency/weak_memory.rs b/tests/run-pass/concurrency/weak_memory.rs index efbbc45909cfd..90820d4348df5 100644 --- a/tests/run-pass/concurrency/weak_memory.rs +++ b/tests/run-pass/concurrency/weak_memory.rs @@ -28,9 +28,10 @@ // M. Batty, S. Owens, S. Sarkar, P. Sewell and T. Weber, // "Mathematizing C++ concurrency", ACM SIGPLAN Notices, vol. 46, no. 1, pp. 55-66, 2011. // Available: https://ss265.host.cs.st-andrews.ac.uk/papers/n3132.pdf. +#![feature(atomic_from_mut)] use std::sync::atomic::Ordering::*; -use std::sync::atomic::{fence, AtomicUsize}; +use std::sync::atomic::{fence, AtomicU16, AtomicU32, AtomicUsize}; use std::thread::{spawn, yield_now}; #[derive(Copy, Clone)] @@ -196,6 +197,26 @@ fn test_mixed_access() { assert_eq!(r2, 2); } +// Strictly speaking, atomic accesses that imperfectly overlap with existing +// atomic objects are UB. Nonetheless we'd like to provide a sane value when +// the access is not racy. +fn test_imperfectly_overlapping_access() { + let mut qword = AtomicU32::new(42); + assert_eq!(qword.load(Relaxed), 42); + qword.store(u32::to_be(0xabbafafa), Relaxed); + + let qword_mut = qword.get_mut(); + + let dwords_mut = unsafe { std::mem::transmute::<&mut u32, &mut [u16; 2]>(qword_mut) }; + + let (hi_mut, lo_mut) = dwords_mut.split_at_mut(1); + + let (hi, lo) = (AtomicU16::from_mut(&mut hi_mut[0]), AtomicU16::from_mut(&mut lo_mut[0])); + + assert_eq!(u16::from_be(hi.load(Relaxed)), 0xabba); + assert_eq!(u16::from_be(lo.load(Relaxed)), 0xfafa); +} + // The following two tests are taken from Repairing Sequential Consistency in C/C++11 // by Lahav et al. // https://plv.mpi-sws.org/scfix/paper.pdf @@ -270,6 +291,7 @@ fn test_cpp20_rwc_syncs() { } pub fn main() { + test_imperfectly_overlapping_access(); // TODO: does this make chances of spurious success // "sufficiently low"? This also takes a long time to run, // prehaps each function should be its own test case so they From bf7fe68fba3a3bbfaef7fdbace268d0001e038cf Mon Sep 17 00:00:00 2001 From: Andy Wang Date: Sat, 7 May 2022 00:54:54 +0100 Subject: [PATCH 3179/3747] Add -Zmiri-disable-weak-memory-emulation to README --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index a55ebcb125b38..e5c2465944e69 100644 --- a/README.md +++ b/README.md @@ -317,11 +317,13 @@ to Miri failing to detect cases of undefined behavior in a program. can focus on other failures, but it means Miri can miss bugs in your program. Using this flag is **unsound**. * `-Zmiri-disable-data-race-detector` disables checking for data races. Using - this flag is **unsound**. + this flag is **unsound**. This implies `-Zmiri-disable-weak-memory-emulation`. * `-Zmiri-disable-stacked-borrows` disables checking the experimental [Stacked Borrows] aliasing rules. This can make Miri run faster, but it also means no aliasing violations will be detected. Using this flag is **unsound** (but the affected soundness rules are experimental). +* `-Zmiri-disable-weak-memory-emulation` disables the emulation of some C++11 weak + memory effects. * `-Zmiri-disable-validation` disables enforcing validity invariants, which are enforced by default. This is mostly useful to focus on other failures (such as out-of-bounds accesses) first. Setting this flag means Miri can miss bugs From 11ca975cd83351aae3b113ceb754dde4a304a6b5 Mon Sep 17 00:00:00 2001 From: Andy Wang Date: Sat, 7 May 2022 01:07:16 +0100 Subject: [PATCH 3180/3747] Move type definitions together and clarify fetch_store on empty buffer --- src/weak_memory.rs | 59 +++++++++++++++++++++++++--------------------- 1 file changed, 32 insertions(+), 27 deletions(-) diff --git a/src/weak_memory.rs b/src/weak_memory.rs index 34c669239d5b8..0d892a5b38db5 100644 --- a/src/weak_memory.rs +++ b/src/weak_memory.rs @@ -40,6 +40,8 @@ use crate::{ pub type AllocExtra = StoreBufferAlloc; +const STORE_BUFFER_LIMIT: usize = 128; + #[derive(Debug, Clone)] pub struct StoreBufferAlloc { /// Store buffer of each atomic object in this allocation @@ -47,6 +49,31 @@ pub struct StoreBufferAlloc { store_buffer: RefCell>, } +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct StoreBuffer { + // Stores to this location in modification order + buffer: VecDeque, +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct StoreElement { + /// The identifier of the vector index, corresponding to a thread + /// that performed the store. + store_index: VectorIdx, + + /// Whether this store is SC. + is_seqcst: bool, + + /// The timestamp of the storing thread when it performed the store + timestamp: VTimestamp, + /// The value of this store + val: ScalarMaybeUninit, + + /// Timestamp of first loads from this store element by each thread + /// Behind a RefCell to keep load op take &self + loads: RefCell>, +} + impl StoreBufferAlloc { pub fn new_allocation() -> Self { Self { store_buffer: RefCell::new(AllocationMap::new()) } @@ -105,13 +132,6 @@ impl StoreBufferAlloc { } } -const STORE_BUFFER_LIMIT: usize = 128; -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct StoreBuffer { - // Stores to this location in modification order - buffer: VecDeque, -} - impl Default for StoreBuffer { fn default() -> Self { let mut buffer = VecDeque::new(); @@ -175,7 +195,11 @@ impl<'mir, 'tcx: 'mir> StoreBuffer { /// Selects a valid store element in the buffer. /// The buffer does not contain the value used to initialise the atomic object - /// so a fresh atomic object has an empty store buffer until an explicit store. + /// so a fresh atomic object has an empty store buffer and this function + /// will return `None`. In this case, the caller should ensure that the non-buffered + /// value from `MiriEvalContext::read_scalar()` is observed by the program, which is + /// the initial value of the atomic object. `MiriEvalContext::read_scalar()` is always + /// the latest value in modification order so it is always correct to be observed by any thread. fn fetch_store( &self, is_seqcst: bool, @@ -294,25 +318,6 @@ impl<'mir, 'tcx: 'mir> StoreBuffer { } } -#[derive(Debug, Clone, PartialEq, Eq)] -pub struct StoreElement { - /// The identifier of the vector index, corresponding to a thread - /// that performed the store. - store_index: VectorIdx, - - /// Whether this store is SC. - is_seqcst: bool, - - /// The timestamp of the storing thread when it performed the store - timestamp: VTimestamp, - /// The value of this store - val: ScalarMaybeUninit, - - /// Timestamp of first loads from this store element by each thread - /// Behind a RefCell to keep load op take &self - loads: RefCell>, -} - impl StoreElement { /// ATOMIC LOAD IMPL in the paper /// Unlike the operational semantics in the paper, we don't need to keep track From 32627d5abb8791d2de10199964128ea8238d5c2b Mon Sep 17 00:00:00 2001 From: Andy Wang Date: Sat, 7 May 2022 01:46:19 +0100 Subject: [PATCH 3181/3747] Disable weak memory emulation on scheduler-dependent data race tests --- tests/fail/data_race/alloc_read_race.rs | 1 + tests/fail/data_race/alloc_write_race.rs | 1 + tests/fail/data_race/dealloc_read_race_stack.rs | 2 +- tests/fail/data_race/dealloc_write_race_stack.rs | 2 +- tests/fail/data_race/read_write_race_stack.rs | 2 +- tests/fail/data_race/relax_acquire_race.rs | 1 + tests/fail/data_race/release_seq_race.rs | 2 +- tests/fail/data_race/release_seq_race_same_thread.rs | 2 +- tests/fail/data_race/rmw_race.rs | 1 + tests/fail/data_race/write_write_race_stack.rs | 2 +- tests/pass/concurrency/data_race.rs | 1 + 11 files changed, 11 insertions(+), 6 deletions(-) diff --git a/tests/fail/data_race/alloc_read_race.rs b/tests/fail/data_race/alloc_read_race.rs index 093c9024f202d..2ddbb657245a6 100644 --- a/tests/fail/data_race/alloc_read_race.rs +++ b/tests/fail/data_race/alloc_read_race.rs @@ -1,4 +1,5 @@ // ignore-windows: Concurrency on Windows is not supported yet. +// compile-flags: -Zmiri-disable-weak-memory-emulation #![feature(new_uninit)] use std::thread::spawn; diff --git a/tests/fail/data_race/alloc_write_race.rs b/tests/fail/data_race/alloc_write_race.rs index becebe6a122a9..d32eb55676067 100644 --- a/tests/fail/data_race/alloc_write_race.rs +++ b/tests/fail/data_race/alloc_write_race.rs @@ -1,4 +1,5 @@ // ignore-windows: Concurrency on Windows is not supported yet. +// compile-flags: -Zmiri-disable-weak-memory-emulation #![feature(new_uninit)] use std::thread::spawn; diff --git a/tests/fail/data_race/dealloc_read_race_stack.rs b/tests/fail/data_race/dealloc_read_race_stack.rs index 6b573121e5992..b70db5f4ac4b7 100644 --- a/tests/fail/data_race/dealloc_read_race_stack.rs +++ b/tests/fail/data_race/dealloc_read_race_stack.rs @@ -1,5 +1,5 @@ // ignore-windows: Concurrency on Windows is not supported yet. -// compile-flags: -Zmiri-disable-isolation +// compile-flags: -Zmiri-disable-isolation -Zmiri-disable-weak-memory-emulation use std::thread::{spawn, sleep}; use std::ptr::null_mut; diff --git a/tests/fail/data_race/dealloc_write_race_stack.rs b/tests/fail/data_race/dealloc_write_race_stack.rs index 34a16b00b83d3..f2b49fc5f344a 100644 --- a/tests/fail/data_race/dealloc_write_race_stack.rs +++ b/tests/fail/data_race/dealloc_write_race_stack.rs @@ -1,5 +1,5 @@ // ignore-windows: Concurrency on Windows is not supported yet. -// compile-flags: -Zmiri-disable-isolation +// compile-flags: -Zmiri-disable-isolation -Zmiri-disable-weak-memory-emulation use std::thread::{spawn, sleep}; use std::ptr::null_mut; diff --git a/tests/fail/data_race/read_write_race_stack.rs b/tests/fail/data_race/read_write_race_stack.rs index 5a1c0a4b6d6da..9edeed0af6521 100644 --- a/tests/fail/data_race/read_write_race_stack.rs +++ b/tests/fail/data_race/read_write_race_stack.rs @@ -1,5 +1,5 @@ // ignore-windows: Concurrency on Windows is not supported yet. -// compile-flags: -Zmiri-disable-isolation -Zmir-opt-level=0 +// compile-flags: -Zmiri-disable-isolation -Zmir-opt-level=0 -Zmiri-disable-weak-memory-emulation // Note: mir-opt-level set to 0 to prevent the read of stack_var in thread 1 // from being optimized away and preventing the detection of the data-race. diff --git a/tests/fail/data_race/relax_acquire_race.rs b/tests/fail/data_race/relax_acquire_race.rs index 8b8616431f37a..20e63dc4b171a 100644 --- a/tests/fail/data_race/relax_acquire_race.rs +++ b/tests/fail/data_race/relax_acquire_race.rs @@ -1,4 +1,5 @@ // ignore-windows: Concurrency on Windows is not supported yet. +// compile-flags: -Zmiri-disable-weak-memory-emulation use std::thread::spawn; use std::sync::atomic::{AtomicUsize, Ordering}; diff --git a/tests/fail/data_race/release_seq_race.rs b/tests/fail/data_race/release_seq_race.rs index 29c428b388d43..6ff84aa04b263 100644 --- a/tests/fail/data_race/release_seq_race.rs +++ b/tests/fail/data_race/release_seq_race.rs @@ -1,5 +1,5 @@ // ignore-windows: Concurrency on Windows is not supported yet. -// compile-flags: -Zmiri-disable-isolation +// compile-flags: -Zmiri-disable-isolation -Zmiri-disable-weak-memory-emulation use std::thread::{spawn, sleep}; use std::sync::atomic::{AtomicUsize, Ordering}; diff --git a/tests/fail/data_race/release_seq_race_same_thread.rs b/tests/fail/data_race/release_seq_race_same_thread.rs index 54b9f49937c88..1245fb96f497d 100644 --- a/tests/fail/data_race/release_seq_race_same_thread.rs +++ b/tests/fail/data_race/release_seq_race_same_thread.rs @@ -1,5 +1,5 @@ // ignore-windows: Concurrency on Windows is not supported yet. -// compile-flags: -Zmiri-disable-isolation +// compile-flags: -Zmiri-disable-isolation -Zmiri-disable-weak-memory-emulation use std::thread::spawn; use std::sync::atomic::{AtomicUsize, Ordering}; diff --git a/tests/fail/data_race/rmw_race.rs b/tests/fail/data_race/rmw_race.rs index fcf683a65d8ed..c968c83422c06 100644 --- a/tests/fail/data_race/rmw_race.rs +++ b/tests/fail/data_race/rmw_race.rs @@ -1,4 +1,5 @@ // ignore-windows: Concurrency on Windows is not supported yet. +// compile-flags: -Zmiri-disable-weak-memory-emulation use std::thread::spawn; use std::sync::atomic::{AtomicUsize, Ordering}; diff --git a/tests/fail/data_race/write_write_race_stack.rs b/tests/fail/data_race/write_write_race_stack.rs index bfe1464cb5728..daa3e5f5c4789 100644 --- a/tests/fail/data_race/write_write_race_stack.rs +++ b/tests/fail/data_race/write_write_race_stack.rs @@ -1,5 +1,5 @@ // ignore-windows: Concurrency on Windows is not supported yet. -// compile-flags: -Zmiri-disable-isolation +// compile-flags: -Zmiri-disable-isolation -Zmiri-disable-weak-memory-emulation use std::thread::{spawn, sleep}; use std::ptr::null_mut; diff --git a/tests/pass/concurrency/data_race.rs b/tests/pass/concurrency/data_race.rs index 2dc0ee3f8f1ae..c51080f474fb1 100644 --- a/tests/pass/concurrency/data_race.rs +++ b/tests/pass/concurrency/data_race.rs @@ -1,4 +1,5 @@ // ignore-windows: Concurrency on Windows is not supported yet. +// compile-flags: -Zmiri-disable-weak-memory-emulation use std::sync::atomic::{AtomicUsize, fence, Ordering}; From f729f289255bcc8d1bfad614ac74bc51d411826a Mon Sep 17 00:00:00 2001 From: Andy Wang Date: Sat, 7 May 2022 17:34:18 +0100 Subject: [PATCH 3182/3747] Move cpp20_rwc_syncs into compile-fail --- .../weak_memory/cpp20_rwc_syncs.rs | 85 +++++++++++++++++++ tests/run-pass/concurrency/weak_memory.rs | 58 +------------ 2 files changed, 86 insertions(+), 57 deletions(-) create mode 100644 tests/compile-fail/weak_memory/cpp20_rwc_syncs.rs diff --git a/tests/compile-fail/weak_memory/cpp20_rwc_syncs.rs b/tests/compile-fail/weak_memory/cpp20_rwc_syncs.rs new file mode 100644 index 0000000000000..b9e395fd7741f --- /dev/null +++ b/tests/compile-fail/weak_memory/cpp20_rwc_syncs.rs @@ -0,0 +1,85 @@ +// ignore-windows: Concurrency on Windows is not supported yet. +// compile-flags: -Zmiri-ignore-leaks + +// https://plv.mpi-sws.org/scfix/paper.pdf +// 2.2 Second Problem: SC Fences are Too Weak +// This test should pass under the C++20 model Rust is using. +// Unfortunately, Miri's weak memory emulation only follows C++11 model +// as we don't know how to correctly emulate C++20's revised SC semantics, +// so we have to stick to C++11 emulation from exiting research. + +use std::sync::atomic::Ordering::*; +use std::thread::{spawn, yield_now}; +use std::sync::atomic::{fence, AtomicUsize}; + +// Spins and yields until until it reads value +fn reads_value(loc: &AtomicUsize, val: usize) -> usize { + while loc.load(Relaxed) != val { + yield_now(); + } + val +} + +// We can't create static items because we need to run each test +// multiple tests +fn static_atomic(val: usize) -> &'static AtomicUsize { + let ret = Box::leak(Box::new(AtomicUsize::new(val))); + // A workaround to put the initialisation value in the store buffer + ret.store(val, Relaxed); + ret +} + +fn test_cpp20_rwc_syncs() { + /* + int main() { + atomic_int x = 0; + atomic_int y = 0; + + {{{ x.store(1,mo_relaxed); + ||| { r1=x.load(mo_relaxed).readsvalue(1); + fence(mo_seq_cst); + r2=y.load(mo_relaxed); } + ||| { y.store(1,mo_relaxed); + fence(mo_seq_cst); + r3=x.load(mo_relaxed); } + }}} + return 0; + } + */ + let x = static_atomic(0); + let y = static_atomic(0); + + let j1 = spawn(move || { + x.store(1, Relaxed); + }); + + let j2 = spawn(move || { + reads_value(&x, 1); + fence(SeqCst); + y.load(Relaxed) + }); + + let j3 = spawn(move || { + y.store(1, Relaxed); + fence(SeqCst); + x.load(Relaxed) + }); + + j1.join().unwrap(); + let b = j2.join().unwrap(); + let c = j3.join().unwrap(); + + if (b, c) == (0, 0) { + // FIXME: the standalone compiletest-rs needs to support + // failure-status header to allow us to write assert_ne!((b, c), (0, 0)) + // https://rustc-dev-guide.rust-lang.org/tests/headers.html#miscellaneous-headers + // because panic exits with 101 but compile-rs expects 1 + let _ = unsafe { std::mem::MaybeUninit::<*const u32>::uninit().assume_init() }; //~ ERROR uninitialized + } +} + +pub fn main() { + for _ in 0..500 { + test_cpp20_rwc_syncs(); + } +} \ No newline at end of file diff --git a/tests/run-pass/concurrency/weak_memory.rs b/tests/run-pass/concurrency/weak_memory.rs index 90820d4348df5..e85c2d1960c4a 100644 --- a/tests/run-pass/concurrency/weak_memory.rs +++ b/tests/run-pass/concurrency/weak_memory.rs @@ -31,7 +31,7 @@ #![feature(atomic_from_mut)] use std::sync::atomic::Ordering::*; -use std::sync::atomic::{fence, AtomicU16, AtomicU32, AtomicUsize}; +use std::sync::atomic::{AtomicU16, AtomicU32, AtomicUsize}; use std::thread::{spawn, yield_now}; #[derive(Copy, Clone)] @@ -57,13 +57,6 @@ fn acquires_value(loc: &AtomicUsize, val: usize) -> usize { val } -fn reads_value(loc: &AtomicUsize, val: usize) -> usize { - while loc.load(Relaxed) != val { - yield_now(); - } - val -} - fn test_corr() { let x = static_atomic(0); let y = static_atomic(0); @@ -242,54 +235,6 @@ fn test_sc_store_buffering() { assert_ne!((a, b), (0, 0)); } -// 2.2 Second Problem: SC Fences are Too Weak -// This test should pass under the C++20 model Rust is using. -// Unfortunately, Miri's weak memory emulation only follows C++11 model -// as we don't know how to correctly emulate C++20's revised SC semantics -#[allow(dead_code)] -fn test_cpp20_rwc_syncs() { - /* - int main() { - atomic_int x = 0; - atomic_int y = 0; - - {{{ x.store(1,mo_relaxed); - ||| { r1=x.load(mo_relaxed).readsvalue(1); - fence(mo_seq_cst); - r2=y.load(mo_relaxed); } - ||| { y.store(1,mo_relaxed); - fence(mo_seq_cst); - r3=x.load(mo_relaxed); } - }}} - return 0; - } - */ - let x = static_atomic(0); - let y = static_atomic(0); - - let j1 = spawn(move || { - x.store(1, Relaxed); - }); - - let j2 = spawn(move || { - reads_value(&x, 1); - fence(SeqCst); - y.load(Relaxed) - }); - - let j3 = spawn(move || { - y.store(1, Relaxed); - fence(SeqCst); - x.load(Relaxed) - }); - - j1.join().unwrap(); - let b = j2.join().unwrap(); - let c = j3.join().unwrap(); - - assert_ne!((b, c), (0, 0)); -} - pub fn main() { test_imperfectly_overlapping_access(); // TODO: does this make chances of spurious success @@ -303,6 +248,5 @@ pub fn main() { test_wrc(); test_corr(); test_sc_store_buffering(); - // test_cpp20_rwc_syncs(); } } From 89138a67dc2b9f7ac5363bad114984cb35033158 Mon Sep 17 00:00:00 2001 From: Andy Wang Date: Tue, 10 May 2022 23:25:18 +0100 Subject: [PATCH 3183/3747] Add more top-level comments --- src/weak_memory.rs | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/src/weak_memory.rs b/src/weak_memory.rs index 0d892a5b38db5..fc2e220e5e51f 100644 --- a/src/weak_memory.rs +++ b/src/weak_memory.rs @@ -1,6 +1,34 @@ //! Implementation of C++11-consistent weak memory emulation using store buffers //! based on Dynamic Race Detection for C++ ("the paper"): //! https://www.doc.ic.ac.uk/~afd/homepages/papers/pdfs/2017/POPL.pdf +//! +//! This implementation will never generate weak memory behaviours forbidden by the C++11 model, +//! but it is incapable of producing all possible weak behaviours allowed by the model. There are +//! certain weak behaviours observable on real hardware but not while using this. +//! +//! Note that this implementation does not take into account of C++20's memory model revision to SC accesses +//! and fences introduced by P0668 (https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0668r5.html). +//! This implementation is not fully correct under the revised C++20 model and may generate behaviours C++20 +//! disallows. +//! +//! Rust follows the full C++20 memory model (except for the Consume ordering). It is therefore +//! possible for this implementation to generate behaviours never observable when the same program is compiled and +//! run natively. Unfortunately, no literature exists at the time of writing which proposes an implementable and C++20-compatible +//! relaxed memory model that supports all atomic operation existing in Rust. The closest one is +//! A Promising Semantics for Relaxed-Memory Concurrency by Jeehoon Kang et al. (https://www.cs.tau.ac.il/~orilahav/papers/popl17.pdf) +//! However, this model lacks SC accesses and is therefore unusable by Miri (SC accesses are everywhere in library code). +//! +//! If you find anything that proposes a relaxed memory model that is C++20-consistent, supports all orderings Rust's atomic accesses +//! and fences accept, and is implementable (with operational semanitcs), please open a GitHub issue! +//! +//! One characteristic of this implementation, in contrast to some other notable operational models such as ones proposed in +//! Taming Release-Acquire Consistency by Ori Lahav et al. (https://plv.mpi-sws.org/sra/paper.pdf) or Promising Semantics noted above, +//! is that this implementation does not require each thread to hold an isolated view of the entire memory. Here, store buffers are per-location +//! and shared across all threads. This is more memory efficient but does require store elements (representing writes to a location) to record +//! information about reads, whereas in the other two models it is the other way round: reads points to the write it got its value from. +//! Additionally, writes in our implementation do not have globally unique timestamps attached. In the other two models this timestamp is +//! used to make sure a value in a thread's view is not overwritten by a write that occured earlier than the one in the existing view. +//! In our implementation, this is detected using read information attached to store elements, as there is no data strucutre representing reads. // Our and the author's own implementation (tsan11) of the paper have some deviations from the provided operational semantics in §5.3: // 1. In the operational semantics, store elements keep a copy of the atomic object's vector clock (AtomicCellClocks::sync_vector in miri), @@ -40,6 +68,10 @@ use crate::{ pub type AllocExtra = StoreBufferAlloc; +// Each store buffer must be bounded otherwise it will grow indefinitely. +// However, bounding the store buffer means restricting the amount of weak +// behaviours observable. The author picked 128 as a good tradeoff +// so we follow them here. const STORE_BUFFER_LIMIT: usize = 128; #[derive(Debug, Clone)] From 62b514e23571beb0f051b4927e08a31460d324ac Mon Sep 17 00:00:00 2001 From: Andy Wang Date: Tue, 10 May 2022 23:34:38 +0100 Subject: [PATCH 3184/3747] Update README --- README.md | 15 +++++++++------ src/weak_memory.rs | 10 +++++----- 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index e5c2465944e69..ece45fca128cb 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,8 @@ for example: or an invalid enum discriminant) * **Experimental**: Violations of the [Stacked Borrows] rules governing aliasing for reference types -* **Experimental**: Data races (but no weak memory effects) +* **Experimental**: Data races +* **Experimental**: Weak memory emulation On top of that, Miri will also tell you about memory leaks: when there is memory still allocated at the end of the execution, and that memory is not reachable @@ -61,9 +62,11 @@ in your program, and cannot run all programs: not support networking. System API support varies between targets; if you run on Windows it is a good idea to use `--target x86_64-unknown-linux-gnu` to get better support. -* Threading support is not finished yet. E.g., weak memory effects are not - emulated and spin loops (without syscalls) just loop forever. There is no - threading support on Windows. +* Threading support is not finished yet. E.g. spin loops (without syscalls) just + loop forever. There is no threading support on Windows. +* Weak memory emulation may produce weak behaivours unobservable by compiled + programs running on real hardware when `SeqCst` fences are used, and it cannot + produce all behaviors possibly observable on real hardware. [rust]: https://www.rust-lang.org/ [mir]: https://github.com/rust-lang/rfcs/blob/master/text/1211-mir.md @@ -322,13 +325,13 @@ to Miri failing to detect cases of undefined behavior in a program. [Stacked Borrows] aliasing rules. This can make Miri run faster, but it also means no aliasing violations will be detected. Using this flag is **unsound** (but the affected soundness rules are experimental). -* `-Zmiri-disable-weak-memory-emulation` disables the emulation of some C++11 weak - memory effects. * `-Zmiri-disable-validation` disables enforcing validity invariants, which are enforced by default. This is mostly useful to focus on other failures (such as out-of-bounds accesses) first. Setting this flag means Miri can miss bugs in your program. However, this can also help to make Miri run faster. Using this flag is **unsound**. +* `-Zmiri-disable-weak-memory-emulation` disables the emulation of some C++11 weak + memory effects. * `-Zmiri-measureme=` enables `measureme` profiling for the interpreted program. This can be used to find which parts of your program are executing slowly under Miri. The profile is written out to a file with the prefix ``, and can be processed diff --git a/src/weak_memory.rs b/src/weak_memory.rs index fc2e220e5e51f..b9ab129231170 100644 --- a/src/weak_memory.rs +++ b/src/weak_memory.rs @@ -1,26 +1,26 @@ //! Implementation of C++11-consistent weak memory emulation using store buffers //! based on Dynamic Race Detection for C++ ("the paper"): //! https://www.doc.ic.ac.uk/~afd/homepages/papers/pdfs/2017/POPL.pdf -//! +//! //! This implementation will never generate weak memory behaviours forbidden by the C++11 model, //! but it is incapable of producing all possible weak behaviours allowed by the model. There are //! certain weak behaviours observable on real hardware but not while using this. -//! +//! //! Note that this implementation does not take into account of C++20's memory model revision to SC accesses //! and fences introduced by P0668 (https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0668r5.html). //! This implementation is not fully correct under the revised C++20 model and may generate behaviours C++20 //! disallows. -//! +//! //! Rust follows the full C++20 memory model (except for the Consume ordering). It is therefore //! possible for this implementation to generate behaviours never observable when the same program is compiled and //! run natively. Unfortunately, no literature exists at the time of writing which proposes an implementable and C++20-compatible //! relaxed memory model that supports all atomic operation existing in Rust. The closest one is //! A Promising Semantics for Relaxed-Memory Concurrency by Jeehoon Kang et al. (https://www.cs.tau.ac.il/~orilahav/papers/popl17.pdf) //! However, this model lacks SC accesses and is therefore unusable by Miri (SC accesses are everywhere in library code). -//! +//! //! If you find anything that proposes a relaxed memory model that is C++20-consistent, supports all orderings Rust's atomic accesses //! and fences accept, and is implementable (with operational semanitcs), please open a GitHub issue! -//! +//! //! One characteristic of this implementation, in contrast to some other notable operational models such as ones proposed in //! Taming Release-Acquire Consistency by Ori Lahav et al. (https://plv.mpi-sws.org/sra/paper.pdf) or Promising Semantics noted above, //! is that this implementation does not require each thread to hold an isolated view of the entire memory. Here, store buffers are per-location From 773131bb261a2a96426f9024271f5557bbbf5c1a Mon Sep 17 00:00:00 2001 From: Andy Wang Date: Wed, 11 May 2022 23:52:38 +0100 Subject: [PATCH 3185/3747] Improve privacy and comments --- src/data_race.rs | 14 ++++++++++---- src/weak_memory.rs | 2 +- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/src/data_race.rs b/src/data_race.rs index d9bfbc1bdb5a1..78b9b09f16156 100644 --- a/src/data_race.rs +++ b/src/data_race.rs @@ -103,7 +103,7 @@ pub enum AtomicFenceOp { pub struct ThreadClockSet { /// The increasing clock representing timestamps /// that happen-before this thread. - pub clock: VClock, + pub(crate) clock: VClock, /// The set of timestamps that will happen-before this /// thread once it performs an acquire fence. @@ -113,11 +113,17 @@ pub struct ThreadClockSet { /// have been released by this thread by a fence. fence_release: VClock, - pub fence_seqcst: VClock, + /// Timestamps of the last SC fence performed by each + /// thread, updated when this thread performs an SC fence + pub(crate) fence_seqcst: VClock, - pub write_seqcst: VClock, + /// Timestamps of the last SC write performed by each + /// thread, updated when this thread performs an SC fence + pub(crate) write_seqcst: VClock, - pub read_seqcst: VClock, + /// Timestamps of the last SC fence performed by each + /// thread, updated when this thread performs an SC read + pub(crate) read_seqcst: VClock, } impl ThreadClockSet { diff --git a/src/weak_memory.rs b/src/weak_memory.rs index b9ab129231170..46838c5c8a1fa 100644 --- a/src/weak_memory.rs +++ b/src/weak_memory.rs @@ -88,7 +88,7 @@ pub struct StoreBuffer { } #[derive(Debug, Clone, PartialEq, Eq)] -pub struct StoreElement { +struct StoreElement { /// The identifier of the vector index, corresponding to a thread /// that performed the store. store_index: VectorIdx, From 7d874db213cdb17f20c4960e314bcce328d2b61c Mon Sep 17 00:00:00 2001 From: Andy Wang Date: Thu, 12 May 2022 22:04:37 +0100 Subject: [PATCH 3186/3747] Add tests showing weak memory behaviours --- .../consistency.rs} | 39 +--------- .../consistency.stderr} | 0 .../weak_memory/imperfectly_overlapping.rs | 29 +++++++ tests/run-pass/weak_memory/weak.rs | 77 +++++++++++++++++++ tests/run-pass/weak_memory/weak.stderr | 2 + 5 files changed, 112 insertions(+), 35 deletions(-) rename tests/run-pass/{concurrency/weak_memory.rs => weak_memory/consistency.rs} (80%) rename tests/run-pass/{concurrency/weak_memory.stderr => weak_memory/consistency.stderr} (100%) create mode 100644 tests/run-pass/weak_memory/imperfectly_overlapping.rs create mode 100644 tests/run-pass/weak_memory/weak.rs create mode 100644 tests/run-pass/weak_memory/weak.stderr diff --git a/tests/run-pass/concurrency/weak_memory.rs b/tests/run-pass/weak_memory/consistency.rs similarity index 80% rename from tests/run-pass/concurrency/weak_memory.rs rename to tests/run-pass/weak_memory/consistency.rs index e85c2d1960c4a..d7c44f6ac2814 100644 --- a/tests/run-pass/concurrency/weak_memory.rs +++ b/tests/run-pass/weak_memory/consistency.rs @@ -1,8 +1,8 @@ // ignore-windows: Concurrency on Windows is not supported yet. // compile-flags: -Zmiri-ignore-leaks -Zmiri-disable-stacked-borrows -// Weak memory emulation tests. All of the following test if -// our weak memory emulation produces any inconsistent execution outcomes +// The following tests check whether our weak memory emulation produces +// any inconsistent execution outcomes // // Due to the random nature of choosing valid stores, it is always // possible that our tests spuriously succeeds: even though our weak @@ -12,15 +12,6 @@ // // To mitigate this, each test is ran enough times such that the chance // of spurious success is very low. These tests never supriously fail. -// -// Note that we can't effectively test whether our weak memory emulation -// can produce *all* consistent execution outcomes. This may be possible -// if Miri's scheduler is sufficiently random and explores all possible -// interleavings of our small test cases after a reasonable number of runs. -// However, since Miri's scheduler is not even pre-emptive, there will -// always be possible interleavings (and possible execution outcomes), -// that can never be observed regardless of how weak memory emulation is -// implemented. // Test cases and their consistent outcomes are from // http://svr-pes20-cppmem.cl.cam.ac.uk/cppmem/ @@ -28,10 +19,9 @@ // M. Batty, S. Owens, S. Sarkar, P. Sewell and T. Weber, // "Mathematizing C++ concurrency", ACM SIGPLAN Notices, vol. 46, no. 1, pp. 55-66, 2011. // Available: https://ss265.host.cs.st-andrews.ac.uk/papers/n3132.pdf. -#![feature(atomic_from_mut)] +use std::sync::atomic::AtomicUsize; use std::sync::atomic::Ordering::*; -use std::sync::atomic::{AtomicU16, AtomicU32, AtomicUsize}; use std::thread::{spawn, yield_now}; #[derive(Copy, Clone)] @@ -41,7 +31,7 @@ unsafe impl Send for EvilSend {} unsafe impl Sync for EvilSend {} // We can't create static items because we need to run each test -// multiple tests +// multiple times fn static_atomic(val: usize) -> &'static AtomicUsize { let ret = Box::leak(Box::new(AtomicUsize::new(val))); // A workaround to put the initialisation value in the store buffer @@ -190,26 +180,6 @@ fn test_mixed_access() { assert_eq!(r2, 2); } -// Strictly speaking, atomic accesses that imperfectly overlap with existing -// atomic objects are UB. Nonetheless we'd like to provide a sane value when -// the access is not racy. -fn test_imperfectly_overlapping_access() { - let mut qword = AtomicU32::new(42); - assert_eq!(qword.load(Relaxed), 42); - qword.store(u32::to_be(0xabbafafa), Relaxed); - - let qword_mut = qword.get_mut(); - - let dwords_mut = unsafe { std::mem::transmute::<&mut u32, &mut [u16; 2]>(qword_mut) }; - - let (hi_mut, lo_mut) = dwords_mut.split_at_mut(1); - - let (hi, lo) = (AtomicU16::from_mut(&mut hi_mut[0]), AtomicU16::from_mut(&mut lo_mut[0])); - - assert_eq!(u16::from_be(hi.load(Relaxed)), 0xabba); - assert_eq!(u16::from_be(lo.load(Relaxed)), 0xfafa); -} - // The following two tests are taken from Repairing Sequential Consistency in C/C++11 // by Lahav et al. // https://plv.mpi-sws.org/scfix/paper.pdf @@ -236,7 +206,6 @@ fn test_sc_store_buffering() { } pub fn main() { - test_imperfectly_overlapping_access(); // TODO: does this make chances of spurious success // "sufficiently low"? This also takes a long time to run, // prehaps each function should be its own test case so they diff --git a/tests/run-pass/concurrency/weak_memory.stderr b/tests/run-pass/weak_memory/consistency.stderr similarity index 100% rename from tests/run-pass/concurrency/weak_memory.stderr rename to tests/run-pass/weak_memory/consistency.stderr diff --git a/tests/run-pass/weak_memory/imperfectly_overlapping.rs b/tests/run-pass/weak_memory/imperfectly_overlapping.rs new file mode 100644 index 0000000000000..2a8e8e5f323d5 --- /dev/null +++ b/tests/run-pass/weak_memory/imperfectly_overlapping.rs @@ -0,0 +1,29 @@ +// ignore-windows: Concurrency on Windows is not supported yet. +#![feature(atomic_from_mut)] + +use std::sync::atomic::Ordering::*; +use std::sync::atomic::{AtomicU16, AtomicU32}; + +// Strictly speaking, atomic accesses that imperfectly overlap with existing +// atomic objects are UB. Nonetheless we'd like to provide a sane value when +// the access is not racy. +fn test_same_thread() { + let mut qword = AtomicU32::new(42); + assert_eq!(qword.load(Relaxed), 42); + qword.store(u32::to_be(0xabbafafa), Relaxed); + + let qword_mut = qword.get_mut(); + + let dwords_mut = unsafe { std::mem::transmute::<&mut u32, &mut [u16; 2]>(qword_mut) }; + + let (hi_mut, lo_mut) = dwords_mut.split_at_mut(1); + + let (hi, lo) = (AtomicU16::from_mut(&mut hi_mut[0]), AtomicU16::from_mut(&mut lo_mut[0])); + + assert_eq!(u16::from_be(hi.load(Relaxed)), 0xabba); + assert_eq!(u16::from_be(lo.load(Relaxed)), 0xfafa); +} + +pub fn main() { + test_same_thread(); +} diff --git a/tests/run-pass/weak_memory/weak.rs b/tests/run-pass/weak_memory/weak.rs new file mode 100644 index 0000000000000..ab0c20cc97721 --- /dev/null +++ b/tests/run-pass/weak_memory/weak.rs @@ -0,0 +1,77 @@ +// ignore-windows: Concurrency on Windows is not supported yet. +// compile-flags: -Zmiri-ignore-leaks + +// Tests showing weak memory behaviours are exhibited. All tests +// return true when the desired behaviour is seen. +// This is scheduler and pseudo-RNG dependent, so each test is +// run multiple times until one try returns true. +// Spurious failure is possible, if you are really unlucky with +// the RNG. + +use std::sync::atomic::AtomicUsize; +use std::sync::atomic::Ordering::*; +use std::thread::spawn; + +#[derive(Copy, Clone)] +struct EvilSend(pub T); + +unsafe impl Send for EvilSend {} +unsafe impl Sync for EvilSend {} + +// We can't create static items because we need to run each test +// multiple times +fn static_atomic(val: usize) -> &'static AtomicUsize { + let ret = Box::leak(Box::new(AtomicUsize::new(val))); + // A workaround to put the initialisation value in the store buffer + ret.store(val, Relaxed); + ret +} + +fn relaxed() -> bool { + let x = static_atomic(0); + let j1 = spawn(move || { + x.store(1, Relaxed); + x.store(2, Relaxed); + }); + + let j2 = spawn(move || x.load(Relaxed)); + + j1.join().unwrap(); + let r2 = j2.join().unwrap(); + + r2 == 1 +} + +// https://www.doc.ic.ac.uk/~afd/homepages/papers/pdfs/2017/POPL.pdf Figure 8 +fn seq_cst() -> bool { + let x = static_atomic(0); + + let j1 = spawn(move || { + x.store(1, Relaxed); + }); + + let j2 = spawn(move || { + x.store(2, SeqCst); + x.store(3, SeqCst); + }); + + let j3 = spawn(move || x.load(SeqCst)); + + j1.join().unwrap(); + j2.join().unwrap(); + let r3 = j3.join().unwrap(); + + r3 == 1 +} + +// Asserts that the function returns true at least once in 100 runs +macro_rules! assert_once { + ($f:ident) => { + assert!(std::iter::repeat_with(|| $f()).take(100).any(|x| x)); + }; +} + +pub fn main() { + assert_once!(relaxed); + assert_once!(seq_cst); +} diff --git a/tests/run-pass/weak_memory/weak.stderr b/tests/run-pass/weak_memory/weak.stderr new file mode 100644 index 0000000000000..03676519d4f1c --- /dev/null +++ b/tests/run-pass/weak_memory/weak.stderr @@ -0,0 +1,2 @@ +warning: thread support is experimental and incomplete: weak memory effects are not emulated. + From 6040c9f50aa9a66f1cd6d30a92f9483dd51feebe Mon Sep 17 00:00:00 2001 From: Andy Wang Date: Thu, 12 May 2022 18:57:03 +0100 Subject: [PATCH 3187/3747] Refactor store buffer search conditions --- src/weak_memory.rs | 72 +++++++++++++++++++--------------------------- 1 file changed, 30 insertions(+), 42 deletions(-) diff --git a/src/weak_memory.rs b/src/weak_memory.rs index 46838c5c8a1fa..223567d3cae16 100644 --- a/src/weak_memory.rs +++ b/src/weak_memory.rs @@ -252,59 +252,47 @@ impl<'mir, 'tcx: 'mir> StoreBuffer { if !keep_searching { return false; } - // CoWR: if a store happens-before the current load, - // then we can't read-from anything earlier in modification order. - if store_elem.timestamp <= clocks.clock[store_elem.store_index] { - log::info!("Stopped due to coherent write-read"); - keep_searching = false; - return true; - } - // CoRR: if there was a load from this store which happened-before the current load, - // then we cannot read-from anything earlier in modification order. - if store_elem.loads.borrow().iter().any(|(&load_index, &load_timestamp)| { + keep_searching = if store_elem.timestamp <= clocks.clock[store_elem.store_index] { + // CoWR: if a store happens-before the current load, + // then we can't read-from anything earlier in modification order. + log::info!("Stopping due to coherent write-read"); + false + } else if store_elem.loads.borrow().iter().any(|(&load_index, &load_timestamp)| { load_timestamp <= clocks.clock[load_index] }) { - log::info!("Stopped due to coherent read-read"); - keep_searching = false; - return true; - } - - // The current load, which may be sequenced-after an SC fence, can only read-from - // the last store sequenced-before an SC fence in another thread (or any stores - // later than that SC fence) - if store_elem.timestamp <= clocks.fence_seqcst[store_elem.store_index] { - log::info!("Stopped due to coherent load sequenced after sc fence"); - keep_searching = false; - return true; - } - - // The current non-SC load can only read-from the latest SC store (or any stores later than that - // SC store) - if store_elem.timestamp <= clocks.write_seqcst[store_elem.store_index] + // CoRR: if there was a load from this store which happened-before the current load, + // then we cannot read-from anything earlier in modification order. + log::info!("Stopping due to coherent read-read"); + false + } else if store_elem.timestamp <= clocks.fence_seqcst[store_elem.store_index] { + // The current load, which may be sequenced-after an SC fence, can only read-from + // the last store sequenced-before an SC fence in another thread (or any stores + // later than that SC fence) + log::info!("Stopping due to coherent load sequenced after sc fence"); + false + } else if store_elem.timestamp <= clocks.write_seqcst[store_elem.store_index] && store_elem.is_seqcst { - log::info!("Stopped due to needing to load from the last SC store"); - keep_searching = false; - return true; - } - - // The current SC load can only read-from the last store sequenced-before - // the last SC fence (or any stores later than the SC fence) - if is_seqcst && store_elem.timestamp <= clocks.read_seqcst[store_elem.store_index] { - log::info!("Stopped due to sc load needing to load from the last SC store before an SC fence"); - keep_searching = false; - return true; - } + // The current non-SC load can only read-from the latest SC store (or any stores later than that + // SC store) + log::info!("Stopping due to needing to load from the last SC store"); + false + } else if is_seqcst && store_elem.timestamp <= clocks.read_seqcst[store_elem.store_index] { + // The current SC load can only read-from the last store sequenced-before + // the last SC fence (or any stores later than the SC fence) + log::info!("Stopping due to sc load needing to load from the last SC store before an SC fence"); + false + } else {true}; true }) .filter(|&store_elem| { - if is_seqcst { + if is_seqcst && store_elem.is_seqcst { // An SC load needs to ignore all but last store maked SC (stores not marked SC are not // affected) - let include = !(store_elem.is_seqcst && found_sc); - found_sc |= store_elem.is_seqcst; + let include = !found_sc; + found_sc = true; include } else { true From 13e34653461a274c5759f5c33b19285e3daa9df5 Mon Sep 17 00:00:00 2001 From: Andy Wang Date: Fri, 13 May 2022 00:15:57 +0100 Subject: [PATCH 3188/3747] Reduce the number of runs in consistency tests --- tests/run-pass/weak_memory/consistency.rs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/tests/run-pass/weak_memory/consistency.rs b/tests/run-pass/weak_memory/consistency.rs index d7c44f6ac2814..8705d0bc6781a 100644 --- a/tests/run-pass/weak_memory/consistency.rs +++ b/tests/run-pass/weak_memory/consistency.rs @@ -206,11 +206,7 @@ fn test_sc_store_buffering() { } pub fn main() { - // TODO: does this make chances of spurious success - // "sufficiently low"? This also takes a long time to run, - // prehaps each function should be its own test case so they - // can be run in parallel - for _ in 0..500 { + for _ in 0..100 { test_mixed_access(); test_load_buffering_acq_rel(); test_message_passing(); From 8739e45bef31493053816f350a268245b4c0b787 Mon Sep 17 00:00:00 2001 From: Andy Wang Date: Fri, 13 May 2022 23:23:58 +0100 Subject: [PATCH 3189/3747] Move data_race and weak_memory into a submodule --- src/{ => concurrency}/allocation_map.rs | 0 src/{ => concurrency}/data_race.rs | 16 ++++++++-------- src/concurrency/mod.rs | 3 +++ src/{ => concurrency}/weak_memory.rs | 17 +++++++++-------- src/lib.rs | 6 ++---- src/machine.rs | 6 +++++- src/thread.rs | 1 + 7 files changed, 28 insertions(+), 21 deletions(-) rename src/{ => concurrency}/allocation_map.rs (100%) rename src/{ => concurrency}/data_race.rs (99%) create mode 100644 src/concurrency/mod.rs rename src/{ => concurrency}/weak_memory.rs (97%) diff --git a/src/allocation_map.rs b/src/concurrency/allocation_map.rs similarity index 100% rename from src/allocation_map.rs rename to src/concurrency/allocation_map.rs diff --git a/src/data_race.rs b/src/concurrency/data_race.rs similarity index 99% rename from src/data_race.rs rename to src/concurrency/data_race.rs index 78b9b09f16156..c0137bf86d8bf 100644 --- a/src/data_race.rs +++ b/src/concurrency/data_race.rs @@ -100,10 +100,10 @@ pub enum AtomicFenceOp { /// of a thread, contains the happens-before clock and /// additional metadata to model atomic fence operations. #[derive(Clone, Default, Debug)] -pub struct ThreadClockSet { +pub(super) struct ThreadClockSet { /// The increasing clock representing timestamps /// that happen-before this thread. - pub(crate) clock: VClock, + pub(super) clock: VClock, /// The set of timestamps that will happen-before this /// thread once it performs an acquire fence. @@ -115,15 +115,15 @@ pub struct ThreadClockSet { /// Timestamps of the last SC fence performed by each /// thread, updated when this thread performs an SC fence - pub(crate) fence_seqcst: VClock, + pub(super) fence_seqcst: VClock, /// Timestamps of the last SC write performed by each /// thread, updated when this thread performs an SC fence - pub(crate) write_seqcst: VClock, + pub(super) write_seqcst: VClock, /// Timestamps of the last SC fence performed by each /// thread, updated when this thread performs an SC read - pub(crate) read_seqcst: VClock, + pub(super) read_seqcst: VClock, } impl ThreadClockSet { @@ -166,7 +166,7 @@ pub struct DataRace; /// common case where no atomic operations /// exists on the memory cell. #[derive(Clone, PartialEq, Eq, Default, Debug)] -pub struct AtomicMemoryCellClocks { +struct AtomicMemoryCellClocks { /// The clock-vector of the timestamp of the last atomic /// read operation performed by each thread. /// This detects potential data-races between atomic read @@ -1547,7 +1547,7 @@ impl GlobalState { /// Load the current vector clock in use and the current set of thread clocks /// in use for the vector. #[inline] - pub fn current_thread_state(&self) -> (VectorIdx, Ref<'_, ThreadClockSet>) { + pub(super) fn current_thread_state(&self) -> (VectorIdx, Ref<'_, ThreadClockSet>) { let index = self.current_index(); let ref_vector = self.vector_clocks.borrow(); let clocks = Ref::map(ref_vector, |vec| &vec[index]); @@ -1557,7 +1557,7 @@ impl GlobalState { /// Load the current vector clock in use and the current set of thread clocks /// in use for the vector mutably for modification. #[inline] - pub fn current_thread_state_mut(&self) -> (VectorIdx, RefMut<'_, ThreadClockSet>) { + pub(super) fn current_thread_state_mut(&self) -> (VectorIdx, RefMut<'_, ThreadClockSet>) { let index = self.current_index(); let ref_vector = self.vector_clocks.borrow_mut(); let clocks = RefMut::map(ref_vector, |vec| &mut vec[index]); diff --git a/src/concurrency/mod.rs b/src/concurrency/mod.rs new file mode 100644 index 0000000000000..ad1586bbf0f9b --- /dev/null +++ b/src/concurrency/mod.rs @@ -0,0 +1,3 @@ +mod allocation_map; +pub mod data_race; +pub mod weak_memory; diff --git a/src/weak_memory.rs b/src/concurrency/weak_memory.rs similarity index 97% rename from src/weak_memory.rs rename to src/concurrency/weak_memory.rs index 223567d3cae16..5bdadc804f868 100644 --- a/src/weak_memory.rs +++ b/src/concurrency/weak_memory.rs @@ -60,10 +60,11 @@ use std::{ use rustc_const_eval::interpret::{AllocRange, InterpResult, ScalarMaybeUninit}; use rustc_data_structures::fx::FxHashMap; -use crate::{ +use crate::{Tag, VClock, VTimestamp, VectorIdx}; + +use super::{ allocation_map::{AccessType, AllocationMap}, data_race::{GlobalState, ThreadClockSet}, - Tag, VClock, VTimestamp, VectorIdx, }; pub type AllocExtra = StoreBufferAlloc; @@ -82,7 +83,7 @@ pub struct StoreBufferAlloc { } #[derive(Debug, Clone, PartialEq, Eq)] -pub struct StoreBuffer { +pub(super) struct StoreBuffer { // Stores to this location in modification order buffer: VecDeque, } @@ -112,7 +113,7 @@ impl StoreBufferAlloc { } /// Gets a store buffer associated with an atomic object in this allocation - pub fn get_store_buffer(&self, range: AllocRange) -> Ref<'_, StoreBuffer> { + pub(super) fn get_store_buffer(&self, range: AllocRange) -> Ref<'_, StoreBuffer> { let access_type = self.store_buffer.borrow().access_type(range); let index = match access_type { AccessType::PerfectlyOverlapping(index) => index, @@ -143,7 +144,7 @@ impl StoreBufferAlloc { } /// Gets a mutable store buffer associated with an atomic object in this allocation - pub fn get_store_buffer_mut(&mut self, range: AllocRange) -> &mut StoreBuffer { + pub(super) fn get_store_buffer_mut(&mut self, range: AllocRange) -> &mut StoreBuffer { let buffer = self.store_buffer.get_mut(); let access_type = buffer.access_type(range); let index = match access_type { @@ -174,7 +175,7 @@ impl Default for StoreBuffer { impl<'mir, 'tcx: 'mir> StoreBuffer { /// Reads from the last store in modification order - pub fn read_from_last_store(&self, global: &GlobalState) { + pub(super) fn read_from_last_store(&self, global: &GlobalState) { let store_elem = self.buffer.back(); if let Some(store_elem) = store_elem { let (index, clocks) = global.current_thread_state(); @@ -182,7 +183,7 @@ impl<'mir, 'tcx: 'mir> StoreBuffer { } } - pub fn buffered_read( + pub(super) fn buffered_read( &self, global: &GlobalState, is_seqcst: bool, @@ -213,7 +214,7 @@ impl<'mir, 'tcx: 'mir> StoreBuffer { Ok(loaded) } - pub fn buffered_write( + pub(super) fn buffered_write( &mut self, val: ScalarMaybeUninit, global: &GlobalState, diff --git a/src/lib.rs b/src/lib.rs index 3270a57c4964e..982d3873d5730 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -31,8 +31,7 @@ extern crate rustc_session; extern crate rustc_span; extern crate rustc_target; -mod allocation_map; -mod data_race; +mod concurrency; mod diagnostics; mod eval; mod helpers; @@ -46,7 +45,6 @@ mod stacked_borrows; mod sync; mod thread; mod vector_clock; -mod weak_memory; // Establish a "crate-wide prelude": we often import `crate::*`. @@ -65,7 +63,7 @@ pub use crate::shims::time::EvalContextExt as _; pub use crate::shims::tls::{EvalContextExt as _, TlsData}; pub use crate::shims::EvalContextExt as _; -pub use crate::data_race::{ +pub use crate::concurrency::data_race::{ AtomicFenceOp, AtomicReadOp, AtomicRwOp, AtomicWriteOp, EvalContextExt as DataRaceEvalContextExt, }; diff --git a/src/machine.rs b/src/machine.rs index ca7fff7b08b9c..41c852747ad7e 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -28,7 +28,11 @@ use rustc_span::Symbol; use rustc_target::abi::Size; use rustc_target::spec::abi::Abi; -use crate::{shims::unix::FileHandler, *}; +use crate::{ + concurrency::{data_race, weak_memory}, + shims::unix::FileHandler, + *, +}; // Some global facts about the emulated machine. pub const PAGE_SIZE: u64 = 4 * 1024; // FIXME: adjust to target architecture diff --git a/src/thread.rs b/src/thread.rs index b6fb866f714a4..0d702fd9c8e17 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -12,6 +12,7 @@ use rustc_hir::def_id::DefId; use rustc_index::vec::{Idx, IndexVec}; use rustc_middle::mir::Mutability; +use crate::concurrency::data_race; use crate::sync::SynchronizationState; use crate::*; From 335667c7749930f9f30e7045bc29690dd81a85f8 Mon Sep 17 00:00:00 2001 From: Andy Wang Date: Sat, 14 May 2022 01:45:21 +0100 Subject: [PATCH 3190/3747] Move buffered functions into their own ext trait --- src/concurrency/data_race.rs | 89 +++-------------------- src/concurrency/weak_memory.rs | 124 +++++++++++++++++++++++++++++++-- 2 files changed, 128 insertions(+), 85 deletions(-) diff --git a/src/concurrency/data_race.rs b/src/concurrency/data_race.rs index c0137bf86d8bf..22b72dadade74 100644 --- a/src/concurrency/data_race.rs +++ b/src/concurrency/data_race.rs @@ -51,7 +51,6 @@ use std::{ mem, }; -use rustc_const_eval::interpret::alloc_range; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_index::vec::{Idx, IndexVec}; use rustc_middle::{mir, ty::layout::TyAndLayout}; @@ -59,6 +58,8 @@ use rustc_target::abi::Size; use crate::*; +use super::weak_memory::EvalContextExt as _; + pub type AllocExtra = VClockAlloc; /// Valid atomic read-write operations, alias of atomic::Ordering (not non-exhaustive). @@ -517,29 +518,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { // the *value* (including the associated provenance if this is an AtomicPtr) at this location. // Only metadata on the location itself is used. let scalar = this.allow_data_races_ref(move |this| this.read_scalar(&place.into()))?; - - if let Some(global) = &this.machine.data_race { - let (alloc_id, base_offset, ..) = this.ptr_get_alloc_id(place.ptr)?; - if let Some(alloc_buffers) = this.get_alloc_extra(alloc_id)?.weak_memory.as_ref() { - if atomic == AtomicReadOp::SeqCst { - global.sc_read(); - } - let mut rng = this.machine.rng.borrow_mut(); - let buffer = - alloc_buffers.get_store_buffer(alloc_range(base_offset, place.layout.size)); - let loaded = buffer.buffered_read( - global, - atomic == AtomicReadOp::SeqCst, - &mut *rng, - || this.validate_atomic_load(place, atomic), - )?; - - return Ok(loaded.unwrap_or(scalar)); - } - } - - this.validate_atomic_load(place, atomic)?; - Ok(scalar) + this.buffered_atomic_read(place, atomic, scalar, || { + this.validate_atomic_load(place, atomic) + }) } /// Perform an atomic write operation at the memory location. @@ -551,23 +532,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); this.allow_data_races_mut(move |this| this.write_scalar(val, &(*dest).into()))?; - this.validate_atomic_store(dest, atomic)?; - let (alloc_id, base_offset, ..) = this.ptr_get_alloc_id(dest.ptr)?; - if let ( - crate::AllocExtra { weak_memory: Some(alloc_buffers), .. }, - crate::Evaluator { data_race: Some(global), .. }, - ) = this.get_alloc_extra_mut(alloc_id)? - { - if atomic == AtomicWriteOp::SeqCst { - global.sc_write(); - } - let buffer = - alloc_buffers.get_store_buffer_mut(alloc_range(base_offset, dest.layout.size)); - buffer.buffered_write(val, global, atomic == AtomicWriteOp::SeqCst)?; - } - - Ok(()) + this.buffered_atomic_write(val, dest, atomic) } /// Perform an atomic operation on a memory location. @@ -695,50 +661,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { // in the modification order. // Since `old` is only a value and not the store element, we need to separately // find it in our store buffer and perform load_impl on it. - if let Some(global) = &this.machine.data_race { - if fail == AtomicReadOp::SeqCst { - global.sc_read(); - } - let size = place.layout.size; - let (alloc_id, base_offset, ..) = this.ptr_get_alloc_id(place.ptr)?; - if let Some(alloc_buffers) = this.get_alloc_extra(alloc_id)?.weak_memory.as_ref() { - if global.multi_threaded.get() { - let buffer = alloc_buffers.get_store_buffer(alloc_range(base_offset, size)); - buffer.read_from_last_store(global); - } - } - } + this.perform_read_on_buffered_latest(place, fail)?; } // Return the old value. Ok(res) } - fn buffered_atomic_rmw( - &mut self, - new_val: ScalarMaybeUninit, - place: &MPlaceTy<'tcx, Tag>, - atomic: AtomicRwOp, - ) -> InterpResult<'tcx> { - let this = self.eval_context_mut(); - let (alloc_id, base_offset, ..) = this.ptr_get_alloc_id(place.ptr)?; - if let ( - crate::AllocExtra { weak_memory: Some(alloc_buffers), .. }, - crate::Evaluator { data_race: Some(global), .. }, - ) = this.get_alloc_extra_mut(alloc_id)? - { - if atomic == AtomicRwOp::SeqCst { - global.sc_read(); - global.sc_write(); - } - let range = alloc_range(base_offset, place.layout.size); - let buffer = alloc_buffers.get_store_buffer_mut(range); - buffer.read_from_last_store(global); - buffer.buffered_write(new_val, global, atomic == AtomicRwOp::SeqCst)?; - } - Ok(()) - } - /// Update the data-race detector for an atomic read occurring at the /// associated memory-place and on the current thread. fn validate_atomic_load( @@ -1572,13 +1501,13 @@ impl GlobalState { } // SC ATOMIC STORE rule in the paper. - fn sc_write(&self) { + pub(super) fn sc_write(&self) { let (index, clocks) = self.current_thread_state(); self.last_sc_write.borrow_mut().set_at_index(&clocks.clock, index); } // SC ATOMIC READ rule in the paper. - fn sc_read(&self) { + pub(super) fn sc_read(&self) { let (.., mut clocks) = self.current_thread_state_mut(); clocks.read_seqcst.join(&self.last_sc_fence.borrow()); } diff --git a/src/concurrency/weak_memory.rs b/src/concurrency/weak_memory.rs index 5bdadc804f868..fba7d18cdf078 100644 --- a/src/concurrency/weak_memory.rs +++ b/src/concurrency/weak_memory.rs @@ -57,10 +57,12 @@ use std::{ collections::VecDeque, }; -use rustc_const_eval::interpret::{AllocRange, InterpResult, ScalarMaybeUninit}; +use rustc_const_eval::interpret::{ + alloc_range, AllocRange, InterpResult, MPlaceTy, ScalarMaybeUninit, +}; use rustc_data_structures::fx::FxHashMap; -use crate::{Tag, VClock, VTimestamp, VectorIdx}; +use crate::{AtomicReadOp, AtomicRwOp, AtomicWriteOp, Tag, VClock, VTimestamp, VectorIdx}; use super::{ allocation_map::{AccessType, AllocationMap}, @@ -113,7 +115,7 @@ impl StoreBufferAlloc { } /// Gets a store buffer associated with an atomic object in this allocation - pub(super) fn get_store_buffer(&self, range: AllocRange) -> Ref<'_, StoreBuffer> { + fn get_store_buffer(&self, range: AllocRange) -> Ref<'_, StoreBuffer> { let access_type = self.store_buffer.borrow().access_type(range); let index = match access_type { AccessType::PerfectlyOverlapping(index) => index, @@ -144,7 +146,7 @@ impl StoreBufferAlloc { } /// Gets a mutable store buffer associated with an atomic object in this allocation - pub(super) fn get_store_buffer_mut(&mut self, range: AllocRange) -> &mut StoreBuffer { + fn get_store_buffer_mut(&mut self, range: AllocRange) -> &mut StoreBuffer { let buffer = self.store_buffer.get_mut(); let access_type = buffer.access_type(range); let index = match access_type { @@ -201,7 +203,7 @@ impl<'mir, 'tcx: 'mir> StoreBuffer { self.fetch_store(is_seqcst, &clocks, &mut *rng) }; - // Unlike in write_scalar_atomic, thread clock updates have to be done + // Unlike in buffered_atomic_write, thread clock updates have to be done // after we've picked a store element from the store buffer, as presented // in ATOMIC LOAD rule of the paper. This is because fetch_store // requires access to ThreadClockSet.clock, which is updated by the race detector @@ -353,3 +355,115 @@ impl StoreElement { self.val } } + +impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} +pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>: + crate::MiriEvalContextExt<'mir, 'tcx> +{ + fn buffered_atomic_rmw( + &mut self, + new_val: ScalarMaybeUninit, + place: &MPlaceTy<'tcx, Tag>, + atomic: AtomicRwOp, + ) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + let (alloc_id, base_offset, ..) = this.ptr_get_alloc_id(place.ptr)?; + if let ( + crate::AllocExtra { weak_memory: Some(alloc_buffers), .. }, + crate::Evaluator { data_race: Some(global), .. }, + ) = this.get_alloc_extra_mut(alloc_id)? + { + if atomic == AtomicRwOp::SeqCst { + global.sc_read(); + global.sc_write(); + } + let range = alloc_range(base_offset, place.layout.size); + let buffer = alloc_buffers.get_store_buffer_mut(range); + buffer.read_from_last_store(global); + buffer.buffered_write(new_val, global, atomic == AtomicRwOp::SeqCst)?; + } + Ok(()) + } + + fn buffered_atomic_read( + &self, + place: &MPlaceTy<'tcx, Tag>, + atomic: AtomicReadOp, + latest_in_mo: ScalarMaybeUninit, + validate: impl FnOnce() -> InterpResult<'tcx>, + ) -> InterpResult<'tcx, ScalarMaybeUninit> { + let this = self.eval_context_ref(); + if let Some(global) = &this.machine.data_race { + let (alloc_id, base_offset, ..) = this.ptr_get_alloc_id(place.ptr)?; + if let Some(alloc_buffers) = this.get_alloc_extra(alloc_id)?.weak_memory.as_ref() { + if atomic == AtomicReadOp::SeqCst { + global.sc_read(); + } + let mut rng = this.machine.rng.borrow_mut(); + let buffer = + alloc_buffers.get_store_buffer(alloc_range(base_offset, place.layout.size)); + let loaded = buffer.buffered_read( + global, + atomic == AtomicReadOp::SeqCst, + &mut *rng, + validate, + )?; + + return Ok(loaded.unwrap_or(latest_in_mo)); + } + } + + // Race detector or weak memory disabled, simply read the latest value + validate()?; + Ok(latest_in_mo) + } + + fn buffered_atomic_write( + &mut self, + val: ScalarMaybeUninit, + dest: &MPlaceTy<'tcx, Tag>, + atomic: AtomicWriteOp, + ) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + let (alloc_id, base_offset, ..) = this.ptr_get_alloc_id(dest.ptr)?; + if let ( + crate::AllocExtra { weak_memory: Some(alloc_buffers), .. }, + crate::Evaluator { data_race: Some(global), .. }, + ) = this.get_alloc_extra_mut(alloc_id)? + { + if atomic == AtomicWriteOp::SeqCst { + global.sc_write(); + } + let buffer = + alloc_buffers.get_store_buffer_mut(alloc_range(base_offset, dest.layout.size)); + buffer.buffered_write(val, global, atomic == AtomicWriteOp::SeqCst)?; + } + + // Caller should've written to dest with the vanilla scalar write, we do nothing here + Ok(()) + } + + /// Caller should never need to consult the store buffer for the latest value. + /// This function is used exclusively for failed atomic_compare_exchange_scalar + /// to perform load_impl on the latest store element + fn perform_read_on_buffered_latest( + &self, + place: &MPlaceTy<'tcx, Tag>, + atomic: AtomicReadOp, + ) -> InterpResult<'tcx> { + let this = self.eval_context_ref(); + + if let Some(global) = &this.machine.data_race { + if atomic == AtomicReadOp::SeqCst { + global.sc_read(); + } + let size = place.layout.size; + let (alloc_id, base_offset, ..) = this.ptr_get_alloc_id(place.ptr)?; + if let Some(alloc_buffers) = this.get_alloc_extra(alloc_id)?.weak_memory.as_ref() { + let buffer = alloc_buffers.get_store_buffer(alloc_range(base_offset, size)); + buffer.read_from_last_store(global); + } + } + Ok(()) + } +} From 5a4a1bfccc50e0e6c6df98e4b95837de79e01023 Mon Sep 17 00:00:00 2001 From: Andy Wang Date: Sun, 15 May 2022 22:29:40 +0100 Subject: [PATCH 3191/3747] Remove incorrect comment --- src/concurrency/weak_memory.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/concurrency/weak_memory.rs b/src/concurrency/weak_memory.rs index fba7d18cdf078..f6466724b5e97 100644 --- a/src/concurrency/weak_memory.rs +++ b/src/concurrency/weak_memory.rs @@ -127,9 +127,7 @@ impl StoreBufferAlloc { } AccessType::ImperfectlyOverlapping(index_range) => { // Accesses that imperfectly overlaps with existing atomic objects - // do not have well-defined behaviours. But we don't throw a UB here - // because we have (or will) checked that all bytes in the current - // access are non-racy. + // do not have well-defined behaviours. // The behaviour here is that we delete all the existing objects this // access touches, and allocate a new and empty one for the exact range. // A read on an empty buffer returns None, which means the program will From 6b54c9237789c275a82eeb483052b302f490b57c Mon Sep 17 00:00:00 2001 From: Andy Wang Date: Mon, 16 May 2022 20:00:11 +0100 Subject: [PATCH 3192/3747] Throw UB on imperfectly overlapping access --- src/concurrency/allocation_map.rs | 5 -- src/concurrency/weak_memory.rs | 53 ++++++++++--------- .../weak_memory/imperfectly_overlapping.rs | 15 +++--- 3 files changed, 36 insertions(+), 37 deletions(-) rename tests/{run-pass => compile-fail}/weak_memory/imperfectly_overlapping.rs (54%) diff --git a/src/concurrency/allocation_map.rs b/src/concurrency/allocation_map.rs index 6c14ce165407f..5b6c06d59ec27 100644 --- a/src/concurrency/allocation_map.rs +++ b/src/concurrency/allocation_map.rs @@ -122,11 +122,6 @@ impl AllocationMap { debug_assert!(range.end() <= self.v[index + 1].range.start); } } - - /// Removes an object at given position - pub fn remove(&mut self, index: Position) -> T { - self.v.remove(index).data - } } impl Index for AllocationMap { diff --git a/src/concurrency/weak_memory.rs b/src/concurrency/weak_memory.rs index f6466724b5e97..a796b56e2c0a7 100644 --- a/src/concurrency/weak_memory.rs +++ b/src/concurrency/weak_memory.rs @@ -85,7 +85,7 @@ pub struct StoreBufferAlloc { } #[derive(Debug, Clone, PartialEq, Eq)] -pub(super) struct StoreBuffer { +struct StoreBuffer { // Stores to this location in modification order buffer: VecDeque, } @@ -115,7 +115,10 @@ impl StoreBufferAlloc { } /// Gets a store buffer associated with an atomic object in this allocation - fn get_store_buffer(&self, range: AllocRange) -> Ref<'_, StoreBuffer> { + fn get_store_buffer<'tcx>( + &self, + range: AllocRange, + ) -> InterpResult<'tcx, Ref<'_, StoreBuffer>> { let access_type = self.store_buffer.borrow().access_type(range); let index = match access_type { AccessType::PerfectlyOverlapping(index) => index, @@ -128,23 +131,23 @@ impl StoreBufferAlloc { AccessType::ImperfectlyOverlapping(index_range) => { // Accesses that imperfectly overlaps with existing atomic objects // do not have well-defined behaviours. - // The behaviour here is that we delete all the existing objects this - // access touches, and allocate a new and empty one for the exact range. - // A read on an empty buffer returns None, which means the program will - // observe the latest value in modification order at every byte. - let mut buffer = self.store_buffer.borrow_mut(); - for index in index_range.clone() { - buffer.remove(index); + // FIXME: if this access happens before all previous accesses on every object it overlaps + // with, then we would like to tolerate it. However this is not easy to check. + if index_range.start + 1 == index_range.end { + throw_ub_format!("mixed-size access on an existing atomic object"); + } else { + throw_ub_format!("access overlaps with multiple existing atomic objects"); } - buffer.insert(index_range.start, range, StoreBuffer::default()); - index_range.start } }; - Ref::map(self.store_buffer.borrow(), |buffer| &buffer[index]) + Ok(Ref::map(self.store_buffer.borrow(), |buffer| &buffer[index])) } /// Gets a mutable store buffer associated with an atomic object in this allocation - fn get_store_buffer_mut(&mut self, range: AllocRange) -> &mut StoreBuffer { + fn get_store_buffer_mut<'tcx>( + &mut self, + range: AllocRange, + ) -> InterpResult<'tcx, &mut StoreBuffer> { let buffer = self.store_buffer.get_mut(); let access_type = buffer.access_type(range); let index = match access_type { @@ -154,14 +157,14 @@ impl StoreBufferAlloc { index } AccessType::ImperfectlyOverlapping(index_range) => { - for index in index_range.clone() { - buffer.remove(index); + if index_range.start + 1 == index_range.end { + throw_ub_format!("mixed-size access on an existing atomic object"); + } else { + throw_ub_format!("access overlaps with multiple existing atomic objects"); } - buffer.insert(index_range.start, range, StoreBuffer::default()); - index_range.start } }; - &mut buffer[index] + Ok(&mut buffer[index]) } } @@ -175,7 +178,7 @@ impl Default for StoreBuffer { impl<'mir, 'tcx: 'mir> StoreBuffer { /// Reads from the last store in modification order - pub(super) fn read_from_last_store(&self, global: &GlobalState) { + fn read_from_last_store(&self, global: &GlobalState) { let store_elem = self.buffer.back(); if let Some(store_elem) = store_elem { let (index, clocks) = global.current_thread_state(); @@ -183,7 +186,7 @@ impl<'mir, 'tcx: 'mir> StoreBuffer { } } - pub(super) fn buffered_read( + fn buffered_read( &self, global: &GlobalState, is_seqcst: bool, @@ -214,7 +217,7 @@ impl<'mir, 'tcx: 'mir> StoreBuffer { Ok(loaded) } - pub(super) fn buffered_write( + fn buffered_write( &mut self, val: ScalarMaybeUninit, global: &GlobalState, @@ -376,7 +379,7 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>: global.sc_write(); } let range = alloc_range(base_offset, place.layout.size); - let buffer = alloc_buffers.get_store_buffer_mut(range); + let buffer = alloc_buffers.get_store_buffer_mut(range)?; buffer.read_from_last_store(global); buffer.buffered_write(new_val, global, atomic == AtomicRwOp::SeqCst)?; } @@ -399,7 +402,7 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>: } let mut rng = this.machine.rng.borrow_mut(); let buffer = - alloc_buffers.get_store_buffer(alloc_range(base_offset, place.layout.size)); + alloc_buffers.get_store_buffer(alloc_range(base_offset, place.layout.size))?; let loaded = buffer.buffered_read( global, atomic == AtomicReadOp::SeqCst, @@ -433,7 +436,7 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>: global.sc_write(); } let buffer = - alloc_buffers.get_store_buffer_mut(alloc_range(base_offset, dest.layout.size)); + alloc_buffers.get_store_buffer_mut(alloc_range(base_offset, dest.layout.size))?; buffer.buffered_write(val, global, atomic == AtomicWriteOp::SeqCst)?; } @@ -458,7 +461,7 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>: let size = place.layout.size; let (alloc_id, base_offset, ..) = this.ptr_get_alloc_id(place.ptr)?; if let Some(alloc_buffers) = this.get_alloc_extra(alloc_id)?.weak_memory.as_ref() { - let buffer = alloc_buffers.get_store_buffer(alloc_range(base_offset, size)); + let buffer = alloc_buffers.get_store_buffer(alloc_range(base_offset, size))?; buffer.read_from_last_store(global); } } diff --git a/tests/run-pass/weak_memory/imperfectly_overlapping.rs b/tests/compile-fail/weak_memory/imperfectly_overlapping.rs similarity index 54% rename from tests/run-pass/weak_memory/imperfectly_overlapping.rs rename to tests/compile-fail/weak_memory/imperfectly_overlapping.rs index 2a8e8e5f323d5..e3f89b5b684f8 100644 --- a/tests/run-pass/weak_memory/imperfectly_overlapping.rs +++ b/tests/compile-fail/weak_memory/imperfectly_overlapping.rs @@ -1,16 +1,15 @@ // ignore-windows: Concurrency on Windows is not supported yet. #![feature(atomic_from_mut)] +#![feature(core_intrinsics)] +use std::intrinsics::atomic_load; use std::sync::atomic::Ordering::*; use std::sync::atomic::{AtomicU16, AtomicU32}; -// Strictly speaking, atomic accesses that imperfectly overlap with existing -// atomic objects are UB. Nonetheless we'd like to provide a sane value when -// the access is not racy. fn test_same_thread() { let mut qword = AtomicU32::new(42); assert_eq!(qword.load(Relaxed), 42); - qword.store(u32::to_be(0xabbafafa), Relaxed); + qword.store(0xabbafafa, Relaxed); let qword_mut = qword.get_mut(); @@ -18,10 +17,12 @@ fn test_same_thread() { let (hi_mut, lo_mut) = dwords_mut.split_at_mut(1); - let (hi, lo) = (AtomicU16::from_mut(&mut hi_mut[0]), AtomicU16::from_mut(&mut lo_mut[0])); + let (hi, _) = (AtomicU16::from_mut(&mut hi_mut[0]), AtomicU16::from_mut(&mut lo_mut[0])); - assert_eq!(u16::from_be(hi.load(Relaxed)), 0xabba); - assert_eq!(u16::from_be(lo.load(Relaxed)), 0xfafa); + unsafe { + //Equivalent to: hi.load(Ordering::SeqCst) + atomic_load(hi.get_mut() as *mut u16); //~ ERROR: mixed-size access on an existing atomic object + } } pub fn main() { From 577054c6ded13a70ee07d6fc3397518ae1e81710 Mon Sep 17 00:00:00 2001 From: Andy Wang Date: Mon, 16 May 2022 22:26:38 +0100 Subject: [PATCH 3193/3747] Rename variables in AllocationMap --- src/concurrency/allocation_map.rs | 73 ++++++++++++++++--------------- src/concurrency/weak_memory.rs | 32 +++++++------- 2 files changed, 54 insertions(+), 51 deletions(-) diff --git a/src/concurrency/allocation_map.rs b/src/concurrency/allocation_map.rs index 5b6c06d59ec27..2524389c0be83 100644 --- a/src/concurrency/allocation_map.rs +++ b/src/concurrency/allocation_map.rs @@ -49,7 +49,7 @@ impl AllocationMap { loop { if left == right { // No element contains the given offset. But the - // index is where such element should be placed at. + // position is where such element should be placed at. return Err(left); } let candidate = left.checked_add(right).unwrap() / 2; @@ -73,53 +73,56 @@ impl AllocationMap { /// an existing allocation pub fn access_type(&self, range: AllocRange) -> AccessType { match self.find_offset(range.start) { - Ok(index) => { + Ok(pos) => { // Start of the range belongs to an existing object, now let's check the overlapping situation - let elem = &self.v[index]; + let elem = &self.v[pos]; // FIXME: derive Eq for AllocRange in rustc if elem.range.start == range.start && elem.range.size == range.size { // Happy case: perfectly overlapping access - AccessType::PerfectlyOverlapping(index) + AccessType::PerfectlyOverlapping(pos) } else { // FIXME: add a last() method to AllocRange that returns the last inclusive offset (end() is exclusive) - let end_index = match self.find_offset(range.end() - Size::from_bytes(1)) { - // If the end lands in an existing object, add one to get the exclusive index - Ok(inclusive) => inclusive + 1, - Err(exclusive) => exclusive, + let end_pos = match self.find_offset(range.end() - Size::from_bytes(1)) { + // If the end lands in an existing object, add one to get the exclusive position + Ok(inclusive_pos) => inclusive_pos + 1, + Err(exclusive_pos) => exclusive_pos, }; - AccessType::ImperfectlyOverlapping(index..end_index) + AccessType::ImperfectlyOverlapping(pos..end_pos) } } - Err(index) => { + Err(pos) => { // Start of the range doesn't belong to an existing object match self.find_offset(range.end() - Size::from_bytes(1)) { // Neither does the end - Err(end_index) => - if index == end_index { + Err(end_pos) => + if pos == end_pos { // There's nothing between the start and the end, so the range thing is empty - AccessType::Empty(index) + AccessType::Empty(pos) } else { // Otherwise we have entirely covered an existing object - AccessType::ImperfectlyOverlapping(index..end_index) + AccessType::ImperfectlyOverlapping(pos..end_pos) }, // Otherwise at least part of it overlaps with something else - Ok(end_index) => AccessType::ImperfectlyOverlapping(index..end_index + 1), + Ok(end_pos) => AccessType::ImperfectlyOverlapping(pos..end_pos + 1), } } } } /// Inserts an object and its occupied range at given position - pub fn insert(&mut self, index: Position, range: AllocRange, data: T) { - self.v.insert(index, Elem { range, data }); + // The Position can be calculated from AllocRange, but the only user of AllocationMap + // always calls access_type before calling insert/index/index_mut, and we don't + // want to repeat the binary search on each time, so we ask the caller to supply Position + pub fn insert_at_pos(&mut self, pos: Position, range: AllocRange, data: T) { + self.v.insert(pos, Elem { range, data }); // If we aren't the first element, then our start must be greater than the preivous element's end - if index > 0 { - debug_assert!(self.v[index - 1].range.end() <= range.start); + if pos > 0 { + debug_assert!(self.v[pos - 1].range.end() <= range.start); } // If we aren't the last element, then our end must be smaller than next element's start - if index < self.v.len() - 1 { - debug_assert!(range.end() <= self.v[index + 1].range.start); + if pos < self.v.len() - 1 { + debug_assert!(range.end() <= self.v[pos + 1].range.start); } } } @@ -127,14 +130,14 @@ impl AllocationMap { impl Index for AllocationMap { type Output = T; - fn index(&self, index: usize) -> &Self::Output { - &self.v[index].data + fn index(&self, pos: Position) -> &Self::Output { + &self.v[pos].data } } impl IndexMut for AllocationMap { - fn index_mut(&mut self, index: usize) -> &mut Self::Output { - &mut self.v[index].data + fn index_mut(&mut self, pos: Position) -> &mut Self::Output { + &mut self.v[pos].data } } @@ -150,10 +153,10 @@ mod tests { let four = Size::from_bytes(4); let map = AllocationMap::<()>::new(); - // Correctly tells where we should insert the first element (at index 0) + // Correctly tells where we should insert the first element (at position 0) assert_eq!(map.find_offset(Size::from_bytes(3)), Err(0)); - // Correctly tells the access type along with the supposed index + // Correctly tells the access type along with the supposed position assert_eq!(map.access_type(alloc_range(Size::ZERO, four)), AccessType::Empty(0)); } @@ -166,10 +169,10 @@ mod tests { // |_|_|_|_|#|#|#|#|_|_|_|_|... // 0 1 2 3 4 5 6 7 8 9 a b c d - map.insert(0, alloc_range(four, four), "#"); + map.insert_at_pos(0, alloc_range(four, four), "#"); // |_|_|_|_|#|#|#|#|_|_|_|_|... // 0 ^ ^ ^ ^ 5 6 7 8 9 a b c d - map.insert(0, alloc_range(Size::from_bytes(1), four), "@"); + map.insert_at_pos(0, alloc_range(Size::from_bytes(1), four), "@"); } #[test] @@ -180,7 +183,7 @@ mod tests { // |#|#|#|#|_|_|... // 0 1 2 3 4 5 - map.insert(0, alloc_range(Size::ZERO, four), "#"); + map.insert_at_pos(0, alloc_range(Size::ZERO, four), "#"); // |#|#|#|#|_|_|... // 0 1 2 3 ^ 5 assert_eq!(map.find_offset(four), Err(1)); @@ -191,7 +194,7 @@ mod tests { let eight = Size::from_bytes(8); // |#|#|#|#|_|_|_|_|@|@|@|@|_|_|... // 0 1 2 3 4 5 6 7 8 9 a b c d - map.insert(1, alloc_range(eight, four), "@"); + map.insert_at_pos(1, alloc_range(eight, four), "@"); // |#|#|#|#|_|_|_|_|@|@|@|@|_|_|... // 0 1 2 3 4 5 6 ^ 8 9 a b c d assert_eq!(map.find_offset(Size::from_bytes(7)), Err(1)); @@ -208,7 +211,7 @@ mod tests { // |#|#|#|#|_|_|... // 0 1 2 3 4 5 - map.insert(0, alloc_range(Size::ZERO, four), "#"); + map.insert_at_pos(0, alloc_range(Size::ZERO, four), "#"); // |#|#|#|#|_|_|... // ^ ^ ^ ^ 4 5 assert_eq!(map.find_offset(Size::ZERO), Ok(0)); @@ -219,7 +222,7 @@ mod tests { // |#|#|#|#|@|@|@|@|_|... // 0 1 2 3 4 5 6 7 8 - map.insert(1, alloc_range(four, four), "@"); + map.insert_at_pos(1, alloc_range(four, four), "@"); // |#|#|#|#|@|@|@|@|_|... // 0 1 2 3 ^ ^ ^ ^ 8 assert_eq!(map.find_offset(four), Ok(1)); @@ -234,7 +237,7 @@ mod tests { // |_|_|_|_|#|#|#|#|_|_|_|_|... // 0 1 2 3 4 5 6 7 8 9 a b c d - map.insert(0, alloc_range(four, four), "#"); + map.insert_at_pos(0, alloc_range(four, four), "#"); // |_|_|_|_|#|#|#|#|_|_|_|_|... // 0 1 ^ ^ ^ ^ 6 7 8 9 a b c d assert_eq!( @@ -256,7 +259,7 @@ mod tests { // |_|_|_|_|#|#|#|#|_|_|@|@|_|_|... // 0 1 2 3 4 5 6 7 8 9 a b c d - map.insert(1, alloc_range(Size::from_bytes(10), Size::from_bytes(2)), "@"); + map.insert_at_pos(1, alloc_range(Size::from_bytes(10), Size::from_bytes(2)), "@"); // |_|_|_|_|#|#|#|#|_|_|@|@|_|_|... // 0 1 2 3 4 5 ^ ^ ^ ^ ^ ^ ^ ^ assert_eq!( diff --git a/src/concurrency/weak_memory.rs b/src/concurrency/weak_memory.rs index a796b56e2c0a7..bd4ae06892bd0 100644 --- a/src/concurrency/weak_memory.rs +++ b/src/concurrency/weak_memory.rs @@ -120,27 +120,27 @@ impl StoreBufferAlloc { range: AllocRange, ) -> InterpResult<'tcx, Ref<'_, StoreBuffer>> { let access_type = self.store_buffer.borrow().access_type(range); - let index = match access_type { - AccessType::PerfectlyOverlapping(index) => index, - AccessType::Empty(index) => { + let pos = match access_type { + AccessType::PerfectlyOverlapping(pos) => pos, + AccessType::Empty(pos) => { // First atomic access on this range, allocate a new StoreBuffer let mut buffer = self.store_buffer.borrow_mut(); - buffer.insert(index, range, StoreBuffer::default()); - index + buffer.insert_at_pos(pos, range, StoreBuffer::default()); + pos } - AccessType::ImperfectlyOverlapping(index_range) => { + AccessType::ImperfectlyOverlapping(pos_range) => { // Accesses that imperfectly overlaps with existing atomic objects // do not have well-defined behaviours. // FIXME: if this access happens before all previous accesses on every object it overlaps // with, then we would like to tolerate it. However this is not easy to check. - if index_range.start + 1 == index_range.end { + if pos_range.start + 1 == pos_range.end { throw_ub_format!("mixed-size access on an existing atomic object"); } else { throw_ub_format!("access overlaps with multiple existing atomic objects"); } } }; - Ok(Ref::map(self.store_buffer.borrow(), |buffer| &buffer[index])) + Ok(Ref::map(self.store_buffer.borrow(), |buffer| &buffer[pos])) } /// Gets a mutable store buffer associated with an atomic object in this allocation @@ -150,21 +150,21 @@ impl StoreBufferAlloc { ) -> InterpResult<'tcx, &mut StoreBuffer> { let buffer = self.store_buffer.get_mut(); let access_type = buffer.access_type(range); - let index = match access_type { - AccessType::PerfectlyOverlapping(index) => index, - AccessType::Empty(index) => { - buffer.insert(index, range, StoreBuffer::default()); - index + let pos = match access_type { + AccessType::PerfectlyOverlapping(pos) => pos, + AccessType::Empty(pos) => { + buffer.insert_at_pos(pos, range, StoreBuffer::default()); + pos } - AccessType::ImperfectlyOverlapping(index_range) => { - if index_range.start + 1 == index_range.end { + AccessType::ImperfectlyOverlapping(pos_range) => { + if pos_range.start + 1 == pos_range.end { throw_ub_format!("mixed-size access on an existing atomic object"); } else { throw_ub_format!("access overlaps with multiple existing atomic objects"); } } }; - Ok(&mut buffer[index]) + Ok(&mut buffer[pos]) } } From 92145373c350d1e41b852aa0332218f614a85bc3 Mon Sep 17 00:00:00 2001 From: Andy Wang Date: Mon, 16 May 2022 23:05:36 +0100 Subject: [PATCH 3194/3747] Put the initialisation value into the store buffer --- src/concurrency/data_race.rs | 26 ++++-- src/concurrency/weak_memory.rs | 109 ++++++++++++++-------- tests/run-pass/weak_memory/consistency.rs | 13 ++- tests/run-pass/weak_memory/weak.rs | 36 ++++++- 4 files changed, 134 insertions(+), 50 deletions(-) diff --git a/src/concurrency/data_race.rs b/src/concurrency/data_race.rs index 22b72dadade74..2d69d02a100f5 100644 --- a/src/concurrency/data_race.rs +++ b/src/concurrency/data_race.rs @@ -533,7 +533,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { let this = self.eval_context_mut(); this.allow_data_races_mut(move |this| this.write_scalar(val, &(*dest).into()))?; this.validate_atomic_store(dest, atomic)?; - this.buffered_atomic_write(val, dest, atomic) + // FIXME: it's not possible to get the value before write_scalar. A read_scalar will cause + // side effects from a read the program did not perform. So we have to initialise + // the store buffer with the value currently being written + // ONCE this is fixed please remove the hack in buffered_atomic_write() in weak_memory.rs + this.buffered_atomic_write(val, dest, atomic, val) } /// Perform an atomic operation on a memory location. @@ -556,7 +560,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { this.validate_atomic_rmw(place, atomic)?; - this.buffered_atomic_rmw(val.to_scalar_or_uninit(), place, atomic)?; + this.buffered_atomic_rmw( + val.to_scalar_or_uninit(), + place, + atomic, + old.to_scalar_or_uninit(), + )?; Ok(old) } @@ -575,7 +584,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { this.validate_atomic_rmw(place, atomic)?; - this.buffered_atomic_rmw(new, place, atomic)?; + this.buffered_atomic_rmw(new, place, atomic, old)?; Ok(old) } @@ -603,7 +612,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { this.validate_atomic_rmw(place, atomic)?; - this.buffered_atomic_rmw(new_val.to_scalar_or_uninit(), place, atomic)?; + this.buffered_atomic_rmw( + new_val.to_scalar_or_uninit(), + place, + atomic, + old.to_scalar_or_uninit(), + )?; // Return the old value. Ok(old) @@ -654,14 +668,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { if cmpxchg_success { this.allow_data_races_mut(|this| this.write_scalar(new, &(*place).into()))?; this.validate_atomic_rmw(place, success)?; - this.buffered_atomic_rmw(new, place, success)?; + this.buffered_atomic_rmw(new, place, success, old.to_scalar_or_uninit())?; } else { this.validate_atomic_load(place, fail)?; // A failed compare exchange is equivalent to a load, reading from the latest store // in the modification order. // Since `old` is only a value and not the store element, we need to separately // find it in our store buffer and perform load_impl on it. - this.perform_read_on_buffered_latest(place, fail)?; + this.perform_read_on_buffered_latest(place, fail, old.to_scalar_or_uninit())?; } // Return the old value. diff --git a/src/concurrency/weak_memory.rs b/src/concurrency/weak_memory.rs index bd4ae06892bd0..1cb9fba715269 100644 --- a/src/concurrency/weak_memory.rs +++ b/src/concurrency/weak_memory.rs @@ -81,11 +81,11 @@ const STORE_BUFFER_LIMIT: usize = 128; pub struct StoreBufferAlloc { /// Store buffer of each atomic object in this allocation // Behind a RefCell because we need to allocate/remove on read access - store_buffer: RefCell>, + store_buffers: RefCell>, } #[derive(Debug, Clone, PartialEq, Eq)] -struct StoreBuffer { +pub(super) struct StoreBuffer { // Stores to this location in modification order buffer: VecDeque, } @@ -111,21 +111,23 @@ struct StoreElement { impl StoreBufferAlloc { pub fn new_allocation() -> Self { - Self { store_buffer: RefCell::new(AllocationMap::new()) } + Self { store_buffers: RefCell::new(AllocationMap::new()) } } /// Gets a store buffer associated with an atomic object in this allocation - fn get_store_buffer<'tcx>( + /// Or creates one with the specified initial value + fn get_or_create_store_buffer<'tcx>( &self, range: AllocRange, + init: ScalarMaybeUninit, ) -> InterpResult<'tcx, Ref<'_, StoreBuffer>> { - let access_type = self.store_buffer.borrow().access_type(range); + let access_type = self.store_buffers.borrow().access_type(range); let pos = match access_type { AccessType::PerfectlyOverlapping(pos) => pos, AccessType::Empty(pos) => { - // First atomic access on this range, allocate a new StoreBuffer - let mut buffer = self.store_buffer.borrow_mut(); - buffer.insert_at_pos(pos, range, StoreBuffer::default()); + let new_buffer = StoreBuffer::new(init); + let mut buffers = self.store_buffers.borrow_mut(); + buffers.insert_at_pos(pos, range, new_buffer); pos } AccessType::ImperfectlyOverlapping(pos_range) => { @@ -140,20 +142,22 @@ impl StoreBufferAlloc { } } }; - Ok(Ref::map(self.store_buffer.borrow(), |buffer| &buffer[pos])) + Ok(Ref::map(self.store_buffers.borrow(), |buffer| &buffer[pos])) } /// Gets a mutable store buffer associated with an atomic object in this allocation - fn get_store_buffer_mut<'tcx>( + fn get_or_create_store_buffer_mut<'tcx>( &mut self, range: AllocRange, + init: ScalarMaybeUninit, ) -> InterpResult<'tcx, &mut StoreBuffer> { - let buffer = self.store_buffer.get_mut(); - let access_type = buffer.access_type(range); + let buffers = self.store_buffers.get_mut(); + let access_type = buffers.access_type(range); let pos = match access_type { AccessType::PerfectlyOverlapping(pos) => pos, AccessType::Empty(pos) => { - buffer.insert_at_pos(pos, range, StoreBuffer::default()); + let new_buffer = StoreBuffer::new(init); + buffers.insert_at_pos(pos, range, new_buffer); pos } AccessType::ImperfectlyOverlapping(pos_range) => { @@ -164,19 +168,28 @@ impl StoreBufferAlloc { } } }; - Ok(&mut buffer[pos]) + Ok(&mut buffers[pos]) } } -impl Default for StoreBuffer { - fn default() -> Self { +impl<'mir, 'tcx: 'mir> StoreBuffer { + fn new(init: ScalarMaybeUninit) -> Self { let mut buffer = VecDeque::new(); buffer.reserve(STORE_BUFFER_LIMIT); - Self { buffer } + let mut ret = Self { buffer }; + let store_elem = StoreElement { + // The thread index and timestamp of the initialisation write + // are never meaningfully used, so it's fine to leave them as 0 + store_index: VectorIdx::from(0), + timestamp: 0, + val: init, + is_seqcst: false, + loads: RefCell::new(FxHashMap::default()), + }; + ret.buffer.push_back(store_elem); + ret } -} -impl<'mir, 'tcx: 'mir> StoreBuffer { /// Reads from the last store in modification order fn read_from_last_store(&self, global: &GlobalState) { let store_elem = self.buffer.back(); @@ -192,7 +205,7 @@ impl<'mir, 'tcx: 'mir> StoreBuffer { is_seqcst: bool, rng: &mut (impl rand::Rng + ?Sized), validate: impl FnOnce() -> InterpResult<'tcx>, - ) -> InterpResult<'tcx, Option>> { + ) -> InterpResult<'tcx, ScalarMaybeUninit> { // Having a live borrow to store_buffer while calling validate_atomic_load is fine // because the race detector doesn't touch store_buffer @@ -210,10 +223,8 @@ impl<'mir, 'tcx: 'mir> StoreBuffer { // requires access to ThreadClockSet.clock, which is updated by the race detector validate()?; - let loaded = store_elem.map(|store_elem| { - let (index, clocks) = global.current_thread_state(); - store_elem.load_impl(index, &clocks) - }); + let (index, clocks) = global.current_thread_state(); + let loaded = store_elem.load_impl(index, &clocks); Ok(loaded) } @@ -230,23 +241,18 @@ impl<'mir, 'tcx: 'mir> StoreBuffer { } /// Selects a valid store element in the buffer. - /// The buffer does not contain the value used to initialise the atomic object - /// so a fresh atomic object has an empty store buffer and this function - /// will return `None`. In this case, the caller should ensure that the non-buffered - /// value from `MiriEvalContext::read_scalar()` is observed by the program, which is - /// the initial value of the atomic object. `MiriEvalContext::read_scalar()` is always - /// the latest value in modification order so it is always correct to be observed by any thread. fn fetch_store( &self, is_seqcst: bool, clocks: &ThreadClockSet, rng: &mut R, - ) -> Option<&StoreElement> { + ) -> &StoreElement { use rand::seq::IteratorRandom; let mut found_sc = false; - // FIXME: this should be an inclusive take_while (stops after a false predicate, but + // FIXME: we want an inclusive take_while (stops after a false predicate, but // includes the element that gave the false), but such function doesn't yet // exist in the standard libary https://github.com/rust-lang/rust/issues/62208 + // so we have to hack around it with keep_searching let mut keep_searching = true; let candidates = self .buffer @@ -303,7 +309,9 @@ impl<'mir, 'tcx: 'mir> StoreBuffer { } }); - candidates.choose(rng) + candidates + .choose(rng) + .expect("store buffer cannot be empty, an element is populated on construction") } /// ATOMIC STORE IMPL in the paper (except we don't need the location's vector clock) @@ -366,6 +374,7 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>: new_val: ScalarMaybeUninit, place: &MPlaceTy<'tcx, Tag>, atomic: AtomicRwOp, + init: ScalarMaybeUninit, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let (alloc_id, base_offset, ..) = this.ptr_get_alloc_id(place.ptr)?; @@ -379,7 +388,7 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>: global.sc_write(); } let range = alloc_range(base_offset, place.layout.size); - let buffer = alloc_buffers.get_store_buffer_mut(range)?; + let buffer = alloc_buffers.get_or_create_store_buffer_mut(range, init)?; buffer.read_from_last_store(global); buffer.buffered_write(new_val, global, atomic == AtomicRwOp::SeqCst)?; } @@ -401,8 +410,10 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>: global.sc_read(); } let mut rng = this.machine.rng.borrow_mut(); - let buffer = - alloc_buffers.get_store_buffer(alloc_range(base_offset, place.layout.size))?; + let buffer = alloc_buffers.get_or_create_store_buffer( + alloc_range(base_offset, place.layout.size), + latest_in_mo, + )?; let loaded = buffer.buffered_read( global, atomic == AtomicReadOp::SeqCst, @@ -410,7 +421,7 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>: validate, )?; - return Ok(loaded.unwrap_or(latest_in_mo)); + return Ok(loaded); } } @@ -424,6 +435,7 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>: val: ScalarMaybeUninit, dest: &MPlaceTy<'tcx, Tag>, atomic: AtomicWriteOp, + init: ScalarMaybeUninit, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let (alloc_id, base_offset, ..) = this.ptr_get_alloc_id(dest.ptr)?; @@ -435,8 +447,23 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>: if atomic == AtomicWriteOp::SeqCst { global.sc_write(); } - let buffer = - alloc_buffers.get_store_buffer_mut(alloc_range(base_offset, dest.layout.size))?; + + // UGLY HACK: in write_scalar_atomic() we don't know the value before our write, + // so init == val always. If the buffer is fresh then we would've duplicated an entry, + // so we need to remove it. + let was_empty = matches!( + alloc_buffers + .store_buffers + .borrow() + .access_type(alloc_range(base_offset, dest.layout.size)), + AccessType::Empty(_) + ); + let buffer = alloc_buffers + .get_or_create_store_buffer_mut(alloc_range(base_offset, dest.layout.size), init)?; + if was_empty { + buffer.buffer.pop_front(); + } + buffer.buffered_write(val, global, atomic == AtomicWriteOp::SeqCst)?; } @@ -451,6 +478,7 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>: &self, place: &MPlaceTy<'tcx, Tag>, atomic: AtomicReadOp, + init: ScalarMaybeUninit, ) -> InterpResult<'tcx> { let this = self.eval_context_ref(); @@ -461,7 +489,8 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>: let size = place.layout.size; let (alloc_id, base_offset, ..) = this.ptr_get_alloc_id(place.ptr)?; if let Some(alloc_buffers) = this.get_alloc_extra(alloc_id)?.weak_memory.as_ref() { - let buffer = alloc_buffers.get_store_buffer(alloc_range(base_offset, size))?; + let buffer = alloc_buffers + .get_or_create_store_buffer(alloc_range(base_offset, size), init)?; buffer.read_from_last_store(global); } } diff --git a/tests/run-pass/weak_memory/consistency.rs b/tests/run-pass/weak_memory/consistency.rs index 8705d0bc6781a..67f0e8d35dd31 100644 --- a/tests/run-pass/weak_memory/consistency.rs +++ b/tests/run-pass/weak_memory/consistency.rs @@ -34,8 +34,6 @@ unsafe impl Sync for EvilSend {} // multiple times fn static_atomic(val: usize) -> &'static AtomicUsize { let ret = Box::leak(Box::new(AtomicUsize::new(val))); - // A workaround to put the initialisation value in the store buffer - ret.store(val, Relaxed); ret } @@ -205,8 +203,19 @@ fn test_sc_store_buffering() { assert_ne!((a, b), (0, 0)); } +fn test_single_thread() { + let x = AtomicUsize::new(42); + + assert_eq!(x.load(Relaxed), 42); + + x.store(43, Relaxed); + + assert_eq!(x.load(Relaxed), 43); +} + pub fn main() { for _ in 0..100 { + test_single_thread(); test_mixed_access(); test_load_buffering_acq_rel(); test_message_passing(); diff --git a/tests/run-pass/weak_memory/weak.rs b/tests/run-pass/weak_memory/weak.rs index ab0c20cc97721..75380381922d2 100644 --- a/tests/run-pass/weak_memory/weak.rs +++ b/tests/run-pass/weak_memory/weak.rs @@ -22,11 +22,17 @@ unsafe impl Sync for EvilSend {} // multiple times fn static_atomic(val: usize) -> &'static AtomicUsize { let ret = Box::leak(Box::new(AtomicUsize::new(val))); - // A workaround to put the initialisation value in the store buffer - ret.store(val, Relaxed); ret } +// Spins until it reads the given value +fn reads_value(loc: &AtomicUsize, val: usize) -> usize { + while loc.load(Relaxed) != val { + std::hint::spin_loop(); + } + val +} + fn relaxed() -> bool { let x = static_atomic(0); let j1 = spawn(move || { @@ -64,6 +70,31 @@ fn seq_cst() -> bool { r3 == 1 } +fn initialization_write() -> bool { + let x = static_atomic(11); + assert_eq!(x.load(Relaxed), 11); + + let wait = static_atomic(0); + + let j1 = spawn(move || { + x.store(22, Relaxed); + // Relaxed is intentional. We want to test if the thread 2 reads the initialisation write + // after a relaxed write + wait.store(1, Relaxed); + }); + + let j2 = spawn(move || { + reads_value(wait, 1); + x.load(Relaxed) + }); + + j1.join().unwrap(); + let r2 = j2.join().unwrap(); + + r2 == 11 +} + + // Asserts that the function returns true at least once in 100 runs macro_rules! assert_once { ($f:ident) => { @@ -74,4 +105,5 @@ macro_rules! assert_once { pub fn main() { assert_once!(relaxed); assert_once!(seq_cst); + assert_once!(initialization_write); } From e2002b4c657b218d3866342078b5fd0ce3118021 Mon Sep 17 00:00:00 2001 From: Andy Wang Date: Tue, 17 May 2022 00:14:30 +0100 Subject: [PATCH 3195/3747] Amend experimental thread support warnings --- src/shims/unix/thread.rs | 2 +- tests/pass/concurrency/channels.stderr | 2 +- tests/pass/concurrency/concurrent_caller_location.stderr | 2 +- tests/pass/concurrency/data_race.stderr | 2 +- tests/pass/concurrency/disable_data_race_detector.stderr | 2 +- tests/pass/concurrency/issue1643.stderr | 2 +- tests/pass/concurrency/linux-futex.stderr | 2 +- tests/pass/concurrency/simple.stderr | 2 +- tests/pass/concurrency/sync.stderr | 2 +- tests/pass/concurrency/thread_locals.stderr | 2 +- tests/pass/concurrency/tls_lib_drop.stderr | 2 +- tests/pass/libc.stderr | 2 +- tests/pass/panic/concurrent-panic.stderr | 2 +- tests/pass/threadleak_ignored.stderr | 2 +- tests/run-pass/weak_memory/consistency.stderr | 2 +- tests/run-pass/weak_memory/weak.stderr | 2 +- 16 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/shims/unix/thread.rs b/src/shims/unix/thread.rs index 88c3fb0bc8eab..812cb7376b71c 100644 --- a/src/shims/unix/thread.rs +++ b/src/shims/unix/thread.rs @@ -14,7 +14,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); this.tcx.sess.warn( - "thread support is experimental and incomplete: weak memory effects are not emulated.", + "thread support is experimental: weak memory effects are not fully compatible with the Rust atomics memory model.", ); // Create the new thread diff --git a/tests/pass/concurrency/channels.stderr b/tests/pass/concurrency/channels.stderr index 03676519d4f1c..1d0ce4b3853da 100644 --- a/tests/pass/concurrency/channels.stderr +++ b/tests/pass/concurrency/channels.stderr @@ -1,2 +1,2 @@ -warning: thread support is experimental and incomplete: weak memory effects are not emulated. +warning: thread support is experimental: weak memory effects are not fully compatible with the Rust atomics memory model. diff --git a/tests/pass/concurrency/concurrent_caller_location.stderr b/tests/pass/concurrency/concurrent_caller_location.stderr index 03676519d4f1c..1d0ce4b3853da 100644 --- a/tests/pass/concurrency/concurrent_caller_location.stderr +++ b/tests/pass/concurrency/concurrent_caller_location.stderr @@ -1,2 +1,2 @@ -warning: thread support is experimental and incomplete: weak memory effects are not emulated. +warning: thread support is experimental: weak memory effects are not fully compatible with the Rust atomics memory model. diff --git a/tests/pass/concurrency/data_race.stderr b/tests/pass/concurrency/data_race.stderr index 03676519d4f1c..1d0ce4b3853da 100644 --- a/tests/pass/concurrency/data_race.stderr +++ b/tests/pass/concurrency/data_race.stderr @@ -1,2 +1,2 @@ -warning: thread support is experimental and incomplete: weak memory effects are not emulated. +warning: thread support is experimental: weak memory effects are not fully compatible with the Rust atomics memory model. diff --git a/tests/pass/concurrency/disable_data_race_detector.stderr b/tests/pass/concurrency/disable_data_race_detector.stderr index 03676519d4f1c..1d0ce4b3853da 100644 --- a/tests/pass/concurrency/disable_data_race_detector.stderr +++ b/tests/pass/concurrency/disable_data_race_detector.stderr @@ -1,2 +1,2 @@ -warning: thread support is experimental and incomplete: weak memory effects are not emulated. +warning: thread support is experimental: weak memory effects are not fully compatible with the Rust atomics memory model. diff --git a/tests/pass/concurrency/issue1643.stderr b/tests/pass/concurrency/issue1643.stderr index 03676519d4f1c..1d0ce4b3853da 100644 --- a/tests/pass/concurrency/issue1643.stderr +++ b/tests/pass/concurrency/issue1643.stderr @@ -1,2 +1,2 @@ -warning: thread support is experimental and incomplete: weak memory effects are not emulated. +warning: thread support is experimental: weak memory effects are not fully compatible with the Rust atomics memory model. diff --git a/tests/pass/concurrency/linux-futex.stderr b/tests/pass/concurrency/linux-futex.stderr index 03676519d4f1c..1d0ce4b3853da 100644 --- a/tests/pass/concurrency/linux-futex.stderr +++ b/tests/pass/concurrency/linux-futex.stderr @@ -1,2 +1,2 @@ -warning: thread support is experimental and incomplete: weak memory effects are not emulated. +warning: thread support is experimental: weak memory effects are not fully compatible with the Rust atomics memory model. diff --git a/tests/pass/concurrency/simple.stderr b/tests/pass/concurrency/simple.stderr index bb60638bd6834..386dc922691ab 100644 --- a/tests/pass/concurrency/simple.stderr +++ b/tests/pass/concurrency/simple.stderr @@ -1,4 +1,4 @@ -warning: thread support is experimental and incomplete: weak memory effects are not emulated. +warning: thread support is experimental: weak memory effects are not fully compatible with the Rust atomics memory model. thread '' panicked at 'Hello!', $DIR/simple.rs:LL:CC note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace diff --git a/tests/pass/concurrency/sync.stderr b/tests/pass/concurrency/sync.stderr index 03676519d4f1c..1d0ce4b3853da 100644 --- a/tests/pass/concurrency/sync.stderr +++ b/tests/pass/concurrency/sync.stderr @@ -1,2 +1,2 @@ -warning: thread support is experimental and incomplete: weak memory effects are not emulated. +warning: thread support is experimental: weak memory effects are not fully compatible with the Rust atomics memory model. diff --git a/tests/pass/concurrency/thread_locals.stderr b/tests/pass/concurrency/thread_locals.stderr index 03676519d4f1c..1d0ce4b3853da 100644 --- a/tests/pass/concurrency/thread_locals.stderr +++ b/tests/pass/concurrency/thread_locals.stderr @@ -1,2 +1,2 @@ -warning: thread support is experimental and incomplete: weak memory effects are not emulated. +warning: thread support is experimental: weak memory effects are not fully compatible with the Rust atomics memory model. diff --git a/tests/pass/concurrency/tls_lib_drop.stderr b/tests/pass/concurrency/tls_lib_drop.stderr index 03676519d4f1c..1d0ce4b3853da 100644 --- a/tests/pass/concurrency/tls_lib_drop.stderr +++ b/tests/pass/concurrency/tls_lib_drop.stderr @@ -1,2 +1,2 @@ -warning: thread support is experimental and incomplete: weak memory effects are not emulated. +warning: thread support is experimental: weak memory effects are not fully compatible with the Rust atomics memory model. diff --git a/tests/pass/libc.stderr b/tests/pass/libc.stderr index 03676519d4f1c..1d0ce4b3853da 100644 --- a/tests/pass/libc.stderr +++ b/tests/pass/libc.stderr @@ -1,2 +1,2 @@ -warning: thread support is experimental and incomplete: weak memory effects are not emulated. +warning: thread support is experimental: weak memory effects are not fully compatible with the Rust atomics memory model. diff --git a/tests/pass/panic/concurrent-panic.stderr b/tests/pass/panic/concurrent-panic.stderr index ae132c9ee3483..0d4a409dfecf6 100644 --- a/tests/pass/panic/concurrent-panic.stderr +++ b/tests/pass/panic/concurrent-panic.stderr @@ -1,4 +1,4 @@ -warning: thread support is experimental and incomplete: weak memory effects are not emulated. +warning: thread support is experimental: weak memory effects are not fully compatible with the Rust atomics memory model. Thread 1 starting, will block on mutex Thread 1 reported it has started diff --git a/tests/pass/threadleak_ignored.stderr b/tests/pass/threadleak_ignored.stderr index aa037511853b2..9205eb70b2073 100644 --- a/tests/pass/threadleak_ignored.stderr +++ b/tests/pass/threadleak_ignored.stderr @@ -1,3 +1,3 @@ -warning: thread support is experimental and incomplete: weak memory effects are not emulated. +warning: thread support is experimental: weak memory effects are not fully compatible with the Rust atomics memory model. Dropping 0 diff --git a/tests/run-pass/weak_memory/consistency.stderr b/tests/run-pass/weak_memory/consistency.stderr index 03676519d4f1c..1d0ce4b3853da 100644 --- a/tests/run-pass/weak_memory/consistency.stderr +++ b/tests/run-pass/weak_memory/consistency.stderr @@ -1,2 +1,2 @@ -warning: thread support is experimental and incomplete: weak memory effects are not emulated. +warning: thread support is experimental: weak memory effects are not fully compatible with the Rust atomics memory model. diff --git a/tests/run-pass/weak_memory/weak.stderr b/tests/run-pass/weak_memory/weak.stderr index 03676519d4f1c..1d0ce4b3853da 100644 --- a/tests/run-pass/weak_memory/weak.stderr +++ b/tests/run-pass/weak_memory/weak.stderr @@ -1,2 +1,2 @@ -warning: thread support is experimental and incomplete: weak memory effects are not emulated. +warning: thread support is experimental: weak memory effects are not fully compatible with the Rust atomics memory model. From 31c01415cbb1793ae9492f40bbdd917cfe8d1fa5 Mon Sep 17 00:00:00 2001 From: Andy Wang Date: Tue, 17 May 2022 20:04:18 +0100 Subject: [PATCH 3196/3747] Replace yield_now() with spin loop hint --- tests/compile-fail/weak_memory/cpp20_rwc_syncs.rs | 6 +++--- tests/run-pass/weak_memory/consistency.rs | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/compile-fail/weak_memory/cpp20_rwc_syncs.rs b/tests/compile-fail/weak_memory/cpp20_rwc_syncs.rs index b9e395fd7741f..423d0e0e8ffb1 100644 --- a/tests/compile-fail/weak_memory/cpp20_rwc_syncs.rs +++ b/tests/compile-fail/weak_memory/cpp20_rwc_syncs.rs @@ -9,13 +9,13 @@ // so we have to stick to C++11 emulation from exiting research. use std::sync::atomic::Ordering::*; -use std::thread::{spawn, yield_now}; +use std::thread::spawn; use std::sync::atomic::{fence, AtomicUsize}; -// Spins and yields until until it reads value +// Spins until it reads value fn reads_value(loc: &AtomicUsize, val: usize) -> usize { while loc.load(Relaxed) != val { - yield_now(); + std::hint::spin_loop(); } val } diff --git a/tests/run-pass/weak_memory/consistency.rs b/tests/run-pass/weak_memory/consistency.rs index 67f0e8d35dd31..fa13803830f59 100644 --- a/tests/run-pass/weak_memory/consistency.rs +++ b/tests/run-pass/weak_memory/consistency.rs @@ -22,7 +22,7 @@ use std::sync::atomic::AtomicUsize; use std::sync::atomic::Ordering::*; -use std::thread::{spawn, yield_now}; +use std::thread::spawn; #[derive(Copy, Clone)] struct EvilSend(pub T); @@ -37,10 +37,10 @@ fn static_atomic(val: usize) -> &'static AtomicUsize { ret } -// Spins and yields until until acquires a pre-determined value +// Spins until acquires a pre-determined value fn acquires_value(loc: &AtomicUsize, val: usize) -> usize { while loc.load(Acquire) != val { - yield_now(); + std::hint::spin_loop(); } val } From 5ddd4eff0382ba454e8123c663f9e11c14597f79 Mon Sep 17 00:00:00 2001 From: Andy Wang Date: Thu, 19 May 2022 20:14:16 +0100 Subject: [PATCH 3197/3747] Spelling, punctuation and grammar Co-authored-by: Ralf Jung --- README.md | 2 +- tests/compile-fail/weak_memory/cpp20_rwc_syncs.rs | 8 ++++---- tests/run-pass/weak_memory/consistency.rs | 2 +- tests/run-pass/weak_memory/weak.rs | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index ece45fca128cb..938a64cd045b1 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,7 @@ for example: * **Experimental**: Violations of the [Stacked Borrows] rules governing aliasing for reference types * **Experimental**: Data races -* **Experimental**: Weak memory emulation +* **Experimental**: Emulation of weak memory effects (i.e., reads can return outdated values) On top of that, Miri will also tell you about memory leaks: when there is memory still allocated at the end of the execution, and that memory is not reachable diff --git a/tests/compile-fail/weak_memory/cpp20_rwc_syncs.rs b/tests/compile-fail/weak_memory/cpp20_rwc_syncs.rs index 423d0e0e8ffb1..34097f4a89372 100644 --- a/tests/compile-fail/weak_memory/cpp20_rwc_syncs.rs +++ b/tests/compile-fail/weak_memory/cpp20_rwc_syncs.rs @@ -4,15 +4,15 @@ // https://plv.mpi-sws.org/scfix/paper.pdf // 2.2 Second Problem: SC Fences are Too Weak // This test should pass under the C++20 model Rust is using. -// Unfortunately, Miri's weak memory emulation only follows C++11 model +// Unfortunately, Miri's weak memory emulation only follows the C++11 model // as we don't know how to correctly emulate C++20's revised SC semantics, -// so we have to stick to C++11 emulation from exiting research. +// so we have to stick to C++11 emulation from existing research. use std::sync::atomic::Ordering::*; use std::thread::spawn; use std::sync::atomic::{fence, AtomicUsize}; -// Spins until it reads value +// Spins until it reads the given value fn reads_value(loc: &AtomicUsize, val: usize) -> usize { while loc.load(Relaxed) != val { std::hint::spin_loop(); @@ -24,7 +24,7 @@ fn reads_value(loc: &AtomicUsize, val: usize) -> usize { // multiple tests fn static_atomic(val: usize) -> &'static AtomicUsize { let ret = Box::leak(Box::new(AtomicUsize::new(val))); - // A workaround to put the initialisation value in the store buffer + // A workaround to put the initialization value in the store buffer. ret.store(val, Relaxed); ret } diff --git a/tests/run-pass/weak_memory/consistency.rs b/tests/run-pass/weak_memory/consistency.rs index fa13803830f59..8a7c1340cc593 100644 --- a/tests/run-pass/weak_memory/consistency.rs +++ b/tests/run-pass/weak_memory/consistency.rs @@ -37,7 +37,7 @@ fn static_atomic(val: usize) -> &'static AtomicUsize { ret } -// Spins until acquires a pre-determined value +// Spins until it acquires a pre-determined value. fn acquires_value(loc: &AtomicUsize, val: usize) -> usize { while loc.load(Acquire) != val { std::hint::spin_loop(); diff --git a/tests/run-pass/weak_memory/weak.rs b/tests/run-pass/weak_memory/weak.rs index 75380381922d2..70e1bf00f442e 100644 --- a/tests/run-pass/weak_memory/weak.rs +++ b/tests/run-pass/weak_memory/weak.rs @@ -6,7 +6,7 @@ // This is scheduler and pseudo-RNG dependent, so each test is // run multiple times until one try returns true. // Spurious failure is possible, if you are really unlucky with -// the RNG. +// the RNG and always read the latest value from the store buffer. use std::sync::atomic::AtomicUsize; use std::sync::atomic::Ordering::*; From 6d27f188c21f98ff9d8f2f252becb18df27d6c4a Mon Sep 17 00:00:00 2001 From: Andy Wang Date: Sun, 22 May 2022 22:07:50 +0100 Subject: [PATCH 3198/3747] Update src/concurrency/weak_memory.rs Co-authored-by: Ralf Jung --- src/concurrency/weak_memory.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/concurrency/weak_memory.rs b/src/concurrency/weak_memory.rs index 1cb9fba715269..51092478c3fd9 100644 --- a/src/concurrency/weak_memory.rs +++ b/src/concurrency/weak_memory.rs @@ -102,6 +102,9 @@ struct StoreElement { /// The timestamp of the storing thread when it performed the store timestamp: VTimestamp, /// The value of this store + // FIXME: this means the store is either fully initialized or fully uninitialized; + // we will have to change this if we want to support atomics on + // partially initialized data. val: ScalarMaybeUninit, /// Timestamp of first loads from this store element by each thread From dafd813c16231834d3bce7875a8c616d1e49a8c1 Mon Sep 17 00:00:00 2001 From: Andy Wang Date: Sun, 22 May 2022 22:18:22 +0100 Subject: [PATCH 3199/3747] Move transmute into a separate function --- .../weak_memory/imperfectly_overlapping.rs | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/tests/compile-fail/weak_memory/imperfectly_overlapping.rs b/tests/compile-fail/weak_memory/imperfectly_overlapping.rs index e3f89b5b684f8..6f91e147fa834 100644 --- a/tests/compile-fail/weak_memory/imperfectly_overlapping.rs +++ b/tests/compile-fail/weak_memory/imperfectly_overlapping.rs @@ -6,21 +6,26 @@ use std::intrinsics::atomic_load; use std::sync::atomic::Ordering::*; use std::sync::atomic::{AtomicU16, AtomicU32}; +fn split_u32(dword: &mut u32) -> &mut [u16; 2] { + unsafe { std::mem::transmute::<&mut u32, &mut [u16; 2]>(dword) } +} + fn test_same_thread() { - let mut qword = AtomicU32::new(42); - assert_eq!(qword.load(Relaxed), 42); - qword.store(0xabbafafa, Relaxed); + let mut dword = AtomicU32::new(42); + assert_eq!(dword.load(Relaxed), 42); + dword.store(0xabbafafa, Relaxed); - let qword_mut = qword.get_mut(); + let dword_mut = dword.get_mut(); - let dwords_mut = unsafe { std::mem::transmute::<&mut u32, &mut [u16; 2]>(qword_mut) }; + let words_mut = split_u32(dword_mut); - let (hi_mut, lo_mut) = dwords_mut.split_at_mut(1); + let (hi_mut, lo_mut) = words_mut.split_at_mut(1); let (hi, _) = (AtomicU16::from_mut(&mut hi_mut[0]), AtomicU16::from_mut(&mut lo_mut[0])); unsafe { - //Equivalent to: hi.load(Ordering::SeqCst) + // Equivalent to: hi.load(Ordering::SeqCst) + // We need to use intrisics to for precise error location atomic_load(hi.get_mut() as *mut u16); //~ ERROR: mixed-size access on an existing atomic object } } From 7dcb19ead429e526afac7800a0b90f2b39cfa4f1 Mon Sep 17 00:00:00 2001 From: Andy Wang Date: Mon, 23 May 2022 22:05:16 +0100 Subject: [PATCH 3200/3747] Add rust-only operation tests --- .../weak_memory/imperfectly_overlapping.rs | 35 -------- tests/run-pass/weak_memory/extra_cpp.rs | 79 +++++++++++++++++++ tests/run-pass/weak_memory/extra_cpp.stderr | 2 + 3 files changed, 81 insertions(+), 35 deletions(-) delete mode 100644 tests/compile-fail/weak_memory/imperfectly_overlapping.rs create mode 100644 tests/run-pass/weak_memory/extra_cpp.rs create mode 100644 tests/run-pass/weak_memory/extra_cpp.stderr diff --git a/tests/compile-fail/weak_memory/imperfectly_overlapping.rs b/tests/compile-fail/weak_memory/imperfectly_overlapping.rs deleted file mode 100644 index 6f91e147fa834..0000000000000 --- a/tests/compile-fail/weak_memory/imperfectly_overlapping.rs +++ /dev/null @@ -1,35 +0,0 @@ -// ignore-windows: Concurrency on Windows is not supported yet. -#![feature(atomic_from_mut)] -#![feature(core_intrinsics)] - -use std::intrinsics::atomic_load; -use std::sync::atomic::Ordering::*; -use std::sync::atomic::{AtomicU16, AtomicU32}; - -fn split_u32(dword: &mut u32) -> &mut [u16; 2] { - unsafe { std::mem::transmute::<&mut u32, &mut [u16; 2]>(dword) } -} - -fn test_same_thread() { - let mut dword = AtomicU32::new(42); - assert_eq!(dword.load(Relaxed), 42); - dword.store(0xabbafafa, Relaxed); - - let dword_mut = dword.get_mut(); - - let words_mut = split_u32(dword_mut); - - let (hi_mut, lo_mut) = words_mut.split_at_mut(1); - - let (hi, _) = (AtomicU16::from_mut(&mut hi_mut[0]), AtomicU16::from_mut(&mut lo_mut[0])); - - unsafe { - // Equivalent to: hi.load(Ordering::SeqCst) - // We need to use intrisics to for precise error location - atomic_load(hi.get_mut() as *mut u16); //~ ERROR: mixed-size access on an existing atomic object - } -} - -pub fn main() { - test_same_thread(); -} diff --git a/tests/run-pass/weak_memory/extra_cpp.rs b/tests/run-pass/weak_memory/extra_cpp.rs new file mode 100644 index 0000000000000..b20ec58349909 --- /dev/null +++ b/tests/run-pass/weak_memory/extra_cpp.rs @@ -0,0 +1,79 @@ +// compile-flags: -Zmiri-ignore-leaks + +// Tests operations not perfomable through C++'s atomic API +// but doable in safe (at least sound) Rust. + +#![feature(atomic_from_mut)] + +use std::sync::atomic::Ordering::*; +use std::sync::atomic::{AtomicU16, AtomicU32, AtomicUsize}; +use std::thread::spawn; + +fn static_atomic_mut(val: usize) -> &'static mut AtomicUsize { + let ret = Box::leak(Box::new(AtomicUsize::new(val))); + ret +} + +fn split_u32(dword: &mut u32) -> &mut [u16; 2] { + unsafe { std::mem::transmute::<&mut u32, &mut [u16; 2]>(dword) } +} + +fn mem_replace() { + let mut x = AtomicU32::new(0); + + let old_x = std::mem::replace(&mut x, AtomicU32::new(42)); + + assert_eq!(x.load(Relaxed), 42); + assert_eq!(old_x.load(Relaxed), 0); +} + +fn assign_to_mut() { + let x = static_atomic_mut(0); + x.store(1, Relaxed); + + *x = AtomicUsize::new(2); + + assert_eq!(x.load(Relaxed), 2); +} + +fn get_mut_write() { + let x = static_atomic_mut(0); + x.store(1, Relaxed); + { + let x_mut = x.get_mut(); + *x_mut = 2; + } + + let j1 = spawn(move || x.load(Relaxed)); + + let r1 = j1.join().unwrap(); + assert_eq!(r1, 2); +} + +// This is technically doable in C++ with atomic_ref +// but little literature exists atm on its involvement +// in mixed size/atomicity accesses +fn from_mut_split() { + let mut x: u32 = 0; + + { + let x_atomic = AtomicU32::from_mut(&mut x); + x_atomic.store(u32::from_be(0xabbafafa), Relaxed); + } + + let (x_hi, x_lo) = split_u32(&mut x).split_at_mut(1); + + let x_hi_atomic = AtomicU16::from_mut(&mut x_hi[0]); + let x_lo_atomic = AtomicU16::from_mut(&mut x_lo[0]); + + assert_eq!(x_hi_atomic.load(Relaxed), u16::from_be(0xabba)); + assert_eq!(x_lo_atomic.load(Relaxed), u16::from_be(0xfafa)); +} + + +pub fn main() { + get_mut_write(); + from_mut_split(); + assign_to_mut(); + mem_replace(); +} diff --git a/tests/run-pass/weak_memory/extra_cpp.stderr b/tests/run-pass/weak_memory/extra_cpp.stderr new file mode 100644 index 0000000000000..1d0ce4b3853da --- /dev/null +++ b/tests/run-pass/weak_memory/extra_cpp.stderr @@ -0,0 +1,2 @@ +warning: thread support is experimental: weak memory effects are not fully compatible with the Rust atomics memory model. + From 2321b15342b05445ab7d7ac07a28382b454e0206 Mon Sep 17 00:00:00 2001 From: Andy Wang Date: Tue, 24 May 2022 21:07:22 +0100 Subject: [PATCH 3201/3747] Differentiate between not multithreading and temp disabling race detection --- src/concurrency/data_race.rs | 44 +++++++++++++++++++++--------------- 1 file changed, 26 insertions(+), 18 deletions(-) diff --git a/src/concurrency/data_race.rs b/src/concurrency/data_race.rs index 2d69d02a100f5..7ac2ed615a11f 100644 --- a/src/concurrency/data_race.rs +++ b/src/concurrency/data_race.rs @@ -445,14 +445,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { #[inline] fn allow_data_races_ref(&self, op: impl FnOnce(&MiriEvalContext<'mir, 'tcx>) -> R) -> R { let this = self.eval_context_ref(); - let old = if let Some(data_race) = &this.machine.data_race { - data_race.multi_threaded.replace(false) - } else { - false - }; + if let Some(data_race) = &this.machine.data_race { + data_race.ongoing_atomic_access.set(true); + } let result = op(this); if let Some(data_race) = &this.machine.data_race { - data_race.multi_threaded.set(old); + data_race.ongoing_atomic_access.set(false); } result } @@ -466,14 +464,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { op: impl FnOnce(&mut MiriEvalContext<'mir, 'tcx>) -> R, ) -> R { let this = self.eval_context_mut(); - let old = if let Some(data_race) = &this.machine.data_race { - data_race.multi_threaded.replace(false) - } else { - false - }; + if let Some(data_race) = &this.machine.data_race { + data_race.ongoing_atomic_access.set(true); + } let result = op(this); if let Some(data_race) = &this.machine.data_race { - data_race.multi_threaded.set(old); + data_race.ongoing_atomic_access.set(false); } result } @@ -923,7 +919,7 @@ impl VClockAlloc { } /// Detect data-races for an unsynchronized read operation, will not perform - /// data-race detection if `multi-threaded` is false, either due to no threads + /// data-race detection if `race_detecting()` is false, either due to no threads /// being created or if it is temporarily disabled during a racy read or write /// operation for which data-race detection is handled separately, for example /// atomic read operations. @@ -933,7 +929,7 @@ impl VClockAlloc { range: AllocRange, global: &GlobalState, ) -> InterpResult<'tcx> { - if global.multi_threaded.get() { + if global.race_detecting() { let (index, clocks) = global.current_thread_state(); let mut alloc_ranges = self.alloc_ranges.borrow_mut(); for (offset, range) in alloc_ranges.iter_mut(range.start, range.size) { @@ -962,7 +958,7 @@ impl VClockAlloc { write_type: WriteType, global: &mut GlobalState, ) -> InterpResult<'tcx> { - if global.multi_threaded.get() { + if global.race_detecting() { let (index, clocks) = global.current_thread_state(); for (offset, range) in self.alloc_ranges.get_mut().iter_mut(range.start, range.size) { if let Err(DataRace) = range.write_race_detect(&*clocks, index, write_type) { @@ -983,7 +979,7 @@ impl VClockAlloc { } /// Detect data-races for an unsynchronized write operation, will not perform - /// data-race threads if `multi-threaded` is false, either due to no threads + /// data-race threads if `race_detecting()` is false, either due to no threads /// being created or if it is temporarily disabled during a racy read or write /// operation pub fn write<'tcx>( @@ -996,7 +992,7 @@ impl VClockAlloc { } /// Detect data-races for an unsynchronized deallocate operation, will not perform - /// data-race threads if `multi-threaded` is false, either due to no threads + /// data-race threads if `race_detecting()` is false, either due to no threads /// being created or if it is temporarily disabled during a racy read or write /// operation pub fn deallocate<'tcx>( @@ -1026,7 +1022,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { ) -> InterpResult<'tcx> { let this = self.eval_context_ref(); if let Some(data_race) = &this.machine.data_race { - if data_race.multi_threaded.get() { + if data_race.race_detecting() { let size = place.layout.size; let (alloc_id, base_offset, _tag) = this.ptr_get_alloc_id(place.ptr)?; // Load and log the atomic operation. @@ -1116,6 +1112,10 @@ pub struct GlobalState { /// any data-races. multi_threaded: Cell, + /// A flag to mark we are currently performing + /// an atomic access to supress data race detection + ongoing_atomic_access: Cell, + /// Mapping of a vector index to a known set of thread /// clocks, this is not directly mapping from a thread id /// since it may refer to multiple threads. @@ -1167,6 +1167,7 @@ impl GlobalState { pub fn new() -> Self { let mut global_state = GlobalState { multi_threaded: Cell::new(false), + ongoing_atomic_access: Cell::new(false), vector_clocks: RefCell::new(IndexVec::new()), vector_info: RefCell::new(IndexVec::new()), thread_info: RefCell::new(IndexVec::new()), @@ -1192,6 +1193,13 @@ impl GlobalState { global_state } + // We perform data race detection when there are more than 1 active thread + // and we are not currently in the middle of an atomic acces where data race + // is impossible + fn race_detecting(&self) -> bool { + self.multi_threaded.get() && !self.ongoing_atomic_access.get() + } + // Try to find vector index values that can potentially be re-used // by a new thread instead of a new vector index being created. fn find_vector_index_reuse_candidate(&self) -> Option { From 226ed41cca4cf83cd6afc18f0d3ce4ef2cdc8691 Mon Sep 17 00:00:00 2001 From: Andy Wang Date: Tue, 24 May 2022 22:03:04 +0100 Subject: [PATCH 3202/3747] Destroy store buffers on non-racy non-atomic accesses --- src/concurrency/allocation_map.rs | 8 ++++++++ src/concurrency/data_race.rs | 4 ++++ src/concurrency/weak_memory.rs | 28 ++++++++++++++++++++++++---- src/machine.rs | 23 +++++++++++++++++------ 4 files changed, 53 insertions(+), 10 deletions(-) diff --git a/src/concurrency/allocation_map.rs b/src/concurrency/allocation_map.rs index 2524389c0be83..62469dcaf43a8 100644 --- a/src/concurrency/allocation_map.rs +++ b/src/concurrency/allocation_map.rs @@ -125,6 +125,14 @@ impl AllocationMap { debug_assert!(range.end() <= self.v[pos + 1].range.start); } } + + pub fn remove_pos_range(&mut self, pos_range: Range) { + self.v.drain(pos_range); + } + + pub fn remove_from_pos(&mut self, pos: Position) { + self.v.remove(pos); + } } impl Index for AllocationMap { diff --git a/src/concurrency/data_race.rs b/src/concurrency/data_race.rs index 7ac2ed615a11f..2483bcdf49a28 100644 --- a/src/concurrency/data_race.rs +++ b/src/concurrency/data_race.rs @@ -1200,6 +1200,10 @@ impl GlobalState { self.multi_threaded.get() && !self.ongoing_atomic_access.get() } + pub fn ongoing_atomic_access(&self) -> bool { + self.ongoing_atomic_access.get() + } + // Try to find vector index values that can potentially be re-used // by a new thread instead of a new vector index being created. fn find_vector_index_reuse_candidate(&self) -> Option { diff --git a/src/concurrency/weak_memory.rs b/src/concurrency/weak_memory.rs index 51092478c3fd9..7d8d7da6dc4e7 100644 --- a/src/concurrency/weak_memory.rs +++ b/src/concurrency/weak_memory.rs @@ -11,10 +11,10 @@ //! This implementation is not fully correct under the revised C++20 model and may generate behaviours C++20 //! disallows. //! -//! Rust follows the full C++20 memory model (except for the Consume ordering). It is therefore -//! possible for this implementation to generate behaviours never observable when the same program is compiled and -//! run natively. Unfortunately, no literature exists at the time of writing which proposes an implementable and C++20-compatible -//! relaxed memory model that supports all atomic operation existing in Rust. The closest one is +//! Rust follows the C++20 memory model (except for the Consume ordering and some operations not performable through C++'s +//! std::atomic API). It is therefore possible for this implementation to generate behaviours never observable when the +//! same program is compiled and run natively. Unfortunately, no literature exists at the time of writing which proposes +//! an implementable and C++20-compatible relaxed memory model that supports all atomic operation existing in Rust. The closest one is //! A Promising Semantics for Relaxed-Memory Concurrency by Jeehoon Kang et al. (https://www.cs.tau.ac.il/~orilahav/papers/popl17.pdf) //! However, this model lacks SC accesses and is therefore unusable by Miri (SC accesses are everywhere in library code). //! @@ -117,6 +117,26 @@ impl StoreBufferAlloc { Self { store_buffers: RefCell::new(AllocationMap::new()) } } + /// When a non-atomic access happens on a location that has been atomically accessed + /// before without data race, we can determine that the non-atomic access fully happens + /// before all the prior atomic accesses so the location no longer needs to exhibit + /// any weak memory behaviours until further atomic accesses. + pub fn destroy_atomicity<'tcx>(&self, range: AllocRange) { + let mut buffers = self.store_buffers.borrow_mut(); + let access_type = buffers.access_type(range); + match access_type { + AccessType::PerfectlyOverlapping(pos) => { + buffers.remove_from_pos(pos); + } + AccessType::ImperfectlyOverlapping(pos_range) => { + buffers.remove_pos_range(pos_range); + } + AccessType::Empty(_) => { + // Do nothing + } + } + } + /// Gets a store buffer associated with an atomic object in this allocation /// Or creates one with the specified initial value fn get_or_create_store_buffer<'tcx>( diff --git a/src/machine.rs b/src/machine.rs index 41c852747ad7e..6dc2a75b69fd7 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -738,10 +738,17 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { range, machine.stacked_borrows.as_ref().unwrap(), machine.current_span(), - ) - } else { - Ok(()) + )?; } + if let Some(weak_memory) = &alloc_extra.weak_memory { + if !machine.data_race.as_ref().unwrap().ongoing_atomic_access() { + // This is a non-atomic access. And if we are accessing a previously atomically + // accessed location without racing with them, then the location no longer needs + // to exhibit weak-memory behaviours until a fresh atomic access happens + weak_memory.destroy_atomicity(range); + } + } + Ok(()) } #[inline(always)] @@ -762,10 +769,14 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { range, machine.stacked_borrows.as_ref().unwrap(), machine.current_span(), - ) - } else { - Ok(()) + )?; } + if let Some(weak_memory) = &alloc_extra.weak_memory { + if !machine.data_race.as_ref().unwrap().ongoing_atomic_access() { + weak_memory.destroy_atomicity(range); + } + } + Ok(()) } #[inline(always)] From 613d60db0bc0bfac9c3ad57245fc09e08795a550 Mon Sep 17 00:00:00 2001 From: Andy Wang Date: Wed, 25 May 2022 20:46:08 +0100 Subject: [PATCH 3203/3747] Allow non-racy mixed size accesses --- src/concurrency/data_race.rs | 63 ++++++++++++- src/concurrency/weak_memory.rs | 92 +++++++++++++++---- .../weak_memory/cpp20_rwc_syncs.rs | 6 +- .../weak_memory/racing_mixed_size.rs | 38 ++++++++ tests/run-pass/weak_memory/extra_cpp.rs | 89 +++++++++++++++++- 5 files changed, 262 insertions(+), 26 deletions(-) create mode 100644 tests/compile-fail/weak_memory/racing_mixed_size.rs diff --git a/src/concurrency/data_race.rs b/src/concurrency/data_race.rs index 2483bcdf49a28..8b8694ac18352 100644 --- a/src/concurrency/data_race.rs +++ b/src/concurrency/data_race.rs @@ -287,6 +287,20 @@ impl MemoryCellClocks { Ok(()) } + /// Checks if the memory cell write races with any prior atomic read or write + fn write_race_free_with_atomic(&mut self, clocks: &ThreadClockSet) -> bool { + if let Some(atomic) = self.atomic() { + atomic.read_vector <= clocks.clock && atomic.write_vector <= clocks.clock + } else { + true + } + } + + /// Checks if the memory cell read races with any prior atomic write + fn read_race_free_with_atomic(&self, clocks: &ThreadClockSet) -> bool { + if let Some(atomic) = self.atomic() { atomic.write_vector <= clocks.clock } else { true } + } + /// Update memory cell data-race tracking for atomic /// load relaxed semantics, is a no-op if this memory was /// not used previously as atomic memory. @@ -514,6 +528,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { // the *value* (including the associated provenance if this is an AtomicPtr) at this location. // Only metadata on the location itself is used. let scalar = this.allow_data_races_ref(move |this| this.read_scalar(&place.into()))?; + this.validate_overlapping_atomic_read(place)?; this.buffered_atomic_read(place, atomic, scalar, || { this.validate_atomic_load(place, atomic) }) @@ -527,6 +542,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { atomic: AtomicWriteOp, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); + this.validate_overlapping_atomic_write(dest)?; this.allow_data_races_mut(move |this| this.write_scalar(val, &(*dest).into()))?; this.validate_atomic_store(dest, atomic)?; // FIXME: it's not possible to get the value before write_scalar. A read_scalar will cause @@ -547,6 +563,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { ) -> InterpResult<'tcx, ImmTy<'tcx, Tag>> { let this = self.eval_context_mut(); + this.validate_overlapping_atomic_write(place)?; let old = this.allow_data_races_mut(|this| this.read_immediate(&place.into()))?; // Atomics wrap around on overflow. @@ -575,6 +592,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { ) -> InterpResult<'tcx, ScalarMaybeUninit> { let this = self.eval_context_mut(); + this.validate_overlapping_atomic_write(place)?; let old = this.allow_data_races_mut(|this| this.read_scalar(&place.into()))?; this.allow_data_races_mut(|this| this.write_scalar(new, &(*place).into()))?; @@ -595,6 +613,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { ) -> InterpResult<'tcx, ImmTy<'tcx, Tag>> { let this = self.eval_context_mut(); + this.validate_overlapping_atomic_write(place)?; let old = this.allow_data_races_mut(|this| this.read_immediate(&place.into()))?; let lt = this.binary_op(mir::BinOp::Lt, &old, &rhs)?.to_scalar()?.to_bool()?; @@ -637,6 +656,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { use rand::Rng as _; let this = self.eval_context_mut(); + this.validate_overlapping_atomic_write(place)?; // Failure ordering cannot be stronger than success ordering, therefore first attempt // to read with the failure ordering and if successful then try again with the success // read ordering and write in the success case. @@ -686,6 +706,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { atomic: AtomicReadOp, ) -> InterpResult<'tcx> { let this = self.eval_context_ref(); + this.validate_overlapping_atomic_read(place)?; this.validate_atomic_op( place, atomic, @@ -708,6 +729,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { atomic: AtomicWriteOp, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); + this.validate_overlapping_atomic_write(place)?; this.validate_atomic_op( place, atomic, @@ -733,6 +755,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { let acquire = matches!(atomic, Acquire | AcqRel | SeqCst); let release = matches!(atomic, Release | AcqRel | SeqCst); let this = self.eval_context_mut(); + this.validate_overlapping_atomic_write(place)?; this.validate_atomic_op(place, atomic, "Atomic RMW", move |memory, clocks, index, _| { if acquire { memory.load_acquire(clocks, index)?; @@ -918,6 +941,44 @@ impl VClockAlloc { ) } + /// Detect racing atomic writes (not data races) + /// on every byte of the current access range + pub(super) fn read_race_free_with_atomic<'tcx>( + &self, + range: AllocRange, + global: &GlobalState, + ) -> bool { + if global.race_detecting() { + let (_, clocks) = global.current_thread_state(); + let alloc_ranges = self.alloc_ranges.borrow(); + for (_, range) in alloc_ranges.iter(range.start, range.size) { + if !range.read_race_free_with_atomic(&clocks) { + return false; + } + } + } + true + } + + /// Detect racing atomic read and writes (not data races) + /// on every byte of the current access range + pub(super) fn write_race_free_with_atomic<'tcx>( + &mut self, + range: AllocRange, + global: &GlobalState, + ) -> bool { + if global.race_detecting() { + let (_, clocks) = global.current_thread_state(); + let alloc_ranges = self.alloc_ranges.get_mut(); + for (_, range) in alloc_ranges.iter_mut(range.start, range.size) { + if !range.write_race_free_with_atomic(&clocks) { + return false; + } + } + } + true + } + /// Detect data-races for an unsynchronized read operation, will not perform /// data-race detection if `race_detecting()` is false, either due to no threads /// being created or if it is temporarily disabled during a racy read or write @@ -1027,7 +1088,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { let (alloc_id, base_offset, _tag) = this.ptr_get_alloc_id(place.ptr)?; // Load and log the atomic operation. // Note that atomic loads are possible even from read-only allocations, so `get_alloc_extra_mut` is not an option. - let alloc_meta = &this.get_alloc_extra(alloc_id)?.data_race.as_ref().unwrap(); + let alloc_meta = this.get_alloc_extra(alloc_id)?.data_race.as_ref().unwrap(); log::trace!( "Atomic op({}) with ordering {:?} on {:?} (size={})", description, diff --git a/src/concurrency/weak_memory.rs b/src/concurrency/weak_memory.rs index 7d8d7da6dc4e7..a4fbd14f4374e 100644 --- a/src/concurrency/weak_memory.rs +++ b/src/concurrency/weak_memory.rs @@ -29,6 +29,13 @@ //! Additionally, writes in our implementation do not have globally unique timestamps attached. In the other two models this timestamp is //! used to make sure a value in a thread's view is not overwritten by a write that occured earlier than the one in the existing view. //! In our implementation, this is detected using read information attached to store elements, as there is no data strucutre representing reads. +//! +//! Safe/sound Rust allows for more operations on atomic locations than the C++20 atomic API was intended to allow, such as non-atomically accessing +//! a previously atomically accessed location, or accessing previously atomically accessed locations with a differently sized operation +//! (such as accessing the top 16 bits of an AtomicU32). These senarios are generally undiscussed in formalisations of C++ memory model. +//! In Rust, these operations can only be done through a `&mut AtomicFoo` reference or one derived from it, therefore these operations +//! can only happen after all previous accesses on the same locations. This implementation is adapted to allow these operations. +//! A mixed size/atomicity read that races with writes, or a write that races with reads or writes will still cause UBs to be thrown. // Our and the author's own implementation (tsan11) of the paper have some deviations from the provided operational semantics in §5.3: // 1. In the operational semantics, store elements keep a copy of the atomic object's vector clock (AtomicCellClocks::sync_vector in miri), @@ -117,6 +124,14 @@ impl StoreBufferAlloc { Self { store_buffers: RefCell::new(AllocationMap::new()) } } + /// Checks if the range imperfectly overlaps with existing buffers + /// Used to determine if mixed-size atomic accesses + fn is_overlapping(&self, range: AllocRange) -> bool { + let buffers = self.store_buffers.borrow(); + let access_type = buffers.access_type(range); + matches!(access_type, AccessType::ImperfectlyOverlapping(_)) + } + /// When a non-atomic access happens on a location that has been atomically accessed /// before without data race, we can determine that the non-atomic access fully happens /// before all the prior atomic accesses so the location no longer needs to exhibit @@ -148,21 +163,16 @@ impl StoreBufferAlloc { let pos = match access_type { AccessType::PerfectlyOverlapping(pos) => pos, AccessType::Empty(pos) => { - let new_buffer = StoreBuffer::new(init); let mut buffers = self.store_buffers.borrow_mut(); - buffers.insert_at_pos(pos, range, new_buffer); + buffers.insert_at_pos(pos, range, StoreBuffer::new(init)); pos } AccessType::ImperfectlyOverlapping(pos_range) => { - // Accesses that imperfectly overlaps with existing atomic objects - // do not have well-defined behaviours. - // FIXME: if this access happens before all previous accesses on every object it overlaps - // with, then we would like to tolerate it. However this is not easy to check. - if pos_range.start + 1 == pos_range.end { - throw_ub_format!("mixed-size access on an existing atomic object"); - } else { - throw_ub_format!("access overlaps with multiple existing atomic objects"); - } + // Once we reach here we would've already checked that this access is not racy + let mut buffers = self.store_buffers.borrow_mut(); + buffers.remove_pos_range(pos_range.clone()); + buffers.insert_at_pos(pos_range.start, range, StoreBuffer::new(init)); + pos_range.start } }; Ok(Ref::map(self.store_buffers.borrow(), |buffer| &buffer[pos])) @@ -179,16 +189,13 @@ impl StoreBufferAlloc { let pos = match access_type { AccessType::PerfectlyOverlapping(pos) => pos, AccessType::Empty(pos) => { - let new_buffer = StoreBuffer::new(init); - buffers.insert_at_pos(pos, range, new_buffer); + buffers.insert_at_pos(pos, range, StoreBuffer::new(init)); pos } AccessType::ImperfectlyOverlapping(pos_range) => { - if pos_range.start + 1 == pos_range.end { - throw_ub_format!("mixed-size access on an existing atomic object"); - } else { - throw_ub_format!("access overlaps with multiple existing atomic objects"); - } + buffers.remove_pos_range(pos_range.clone()); + buffers.insert_at_pos(pos_range.start, range, StoreBuffer::new(init)); + pos_range.start } }; Ok(&mut buffers[pos]) @@ -392,6 +399,55 @@ impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mi pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { + // If weak memory emulation is enabled, check if this atomic op imperfectly overlaps with a previous + // atomic write. If it does, then we require it to be ordered (non-racy) with all previous atomic + // writes on all the bytes in range + fn validate_overlapping_atomic_read(&self, place: &MPlaceTy<'tcx, Tag>) -> InterpResult<'tcx> { + let this = self.eval_context_ref(); + let (alloc_id, base_offset, ..) = this.ptr_get_alloc_id(place.ptr)?; + if let crate::AllocExtra { + weak_memory: Some(alloc_buffers), + data_race: Some(alloc_clocks), + .. + } = this.get_alloc_extra(alloc_id)? + { + let range = alloc_range(base_offset, place.layout.size); + if alloc_buffers.is_overlapping(range) + && !alloc_clocks + .read_race_free_with_atomic(range, this.machine.data_race.as_ref().unwrap()) + { + throw_ub_format!("racy imperfectly overlapping atomic access"); + } + } + Ok(()) + } + + // Same as above but needs to be ordered with all previous atomic read or writes + fn validate_overlapping_atomic_write( + &mut self, + place: &MPlaceTy<'tcx, Tag>, + ) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + let (alloc_id, base_offset, ..) = this.ptr_get_alloc_id(place.ptr)?; + if let ( + crate::AllocExtra { + weak_memory: Some(alloc_buffers), + data_race: Some(alloc_clocks), + .. + }, + crate::Evaluator { data_race: Some(global), .. }, + ) = this.get_alloc_extra_mut(alloc_id)? + { + let range = alloc_range(base_offset, place.layout.size); + if alloc_buffers.is_overlapping(range) + && !alloc_clocks.write_race_free_with_atomic(range, global) + { + throw_ub_format!("racy imperfectly overlapping atomic access"); + } + } + Ok(()) + } + fn buffered_atomic_rmw( &mut self, new_val: ScalarMaybeUninit, diff --git a/tests/compile-fail/weak_memory/cpp20_rwc_syncs.rs b/tests/compile-fail/weak_memory/cpp20_rwc_syncs.rs index 34097f4a89372..7dad0a12e5ddc 100644 --- a/tests/compile-fail/weak_memory/cpp20_rwc_syncs.rs +++ b/tests/compile-fail/weak_memory/cpp20_rwc_syncs.rs @@ -9,8 +9,8 @@ // so we have to stick to C++11 emulation from existing research. use std::sync::atomic::Ordering::*; -use std::thread::spawn; use std::sync::atomic::{fence, AtomicUsize}; +use std::thread::spawn; // Spins until it reads the given value fn reads_value(loc: &AtomicUsize, val: usize) -> usize { @@ -25,7 +25,7 @@ fn reads_value(loc: &AtomicUsize, val: usize) -> usize { fn static_atomic(val: usize) -> &'static AtomicUsize { let ret = Box::leak(Box::new(AtomicUsize::new(val))); // A workaround to put the initialization value in the store buffer. - ret.store(val, Relaxed); + ret.load(Relaxed); ret } @@ -82,4 +82,4 @@ pub fn main() { for _ in 0..500 { test_cpp20_rwc_syncs(); } -} \ No newline at end of file +} diff --git a/tests/compile-fail/weak_memory/racing_mixed_size.rs b/tests/compile-fail/weak_memory/racing_mixed_size.rs new file mode 100644 index 0000000000000..d4ba48afe39d2 --- /dev/null +++ b/tests/compile-fail/weak_memory/racing_mixed_size.rs @@ -0,0 +1,38 @@ +// compile-flags: -Zmiri-ignore-leaks + +#![feature(core_intrinsics)] + +use std::sync::atomic::AtomicU32; +use std::sync::atomic::Ordering::*; +use std::thread::spawn; + +fn static_atomic_u32(val: u32) -> &'static AtomicU32 { + let ret = Box::leak(Box::new(AtomicU32::new(val))); + ret +} + +fn split_u32_ptr(dword: *const u32) -> *const [u16; 2] { + unsafe { std::mem::transmute::<*const u32, *const [u16; 2]>(dword) } +} + +// Wine's SRWLock implementation does this, which is definitely undefined in C++ memory model +// https://github.com/wine-mirror/wine/blob/303f8042f9db508adaca02ef21f8de4992cb9c03/dlls/ntdll/sync.c#L543-L566 +// Though it probably works just fine on x86 +pub fn main() { + let x = static_atomic_u32(0); + let j1 = spawn(move || { + x.store(1, Relaxed); + }); + + let j2 = spawn(move || { + let x_ptr = x as *const AtomicU32 as *const u32; + let x_split = split_u32_ptr(x_ptr); + unsafe { + let hi = &(*x_split)[0] as *const u16; + std::intrinsics::atomic_load_relaxed(hi); //~ ERROR: imperfectly overlapping + } + }); + + j1.join().unwrap(); + j2.join().unwrap(); +} diff --git a/tests/run-pass/weak_memory/extra_cpp.rs b/tests/run-pass/weak_memory/extra_cpp.rs index b20ec58349909..b1a683798bb32 100644 --- a/tests/run-pass/weak_memory/extra_cpp.rs +++ b/tests/run-pass/weak_memory/extra_cpp.rs @@ -4,13 +4,19 @@ // but doable in safe (at least sound) Rust. #![feature(atomic_from_mut)] +#![feature(core_intrinsics)] use std::sync::atomic::Ordering::*; -use std::sync::atomic::{AtomicU16, AtomicU32, AtomicUsize}; +use std::sync::atomic::{AtomicU16, AtomicU32}; use std::thread::spawn; -fn static_atomic_mut(val: usize) -> &'static mut AtomicUsize { - let ret = Box::leak(Box::new(AtomicUsize::new(val))); +fn static_atomic_mut(val: u32) -> &'static mut AtomicU32 { + let ret = Box::leak(Box::new(AtomicU32::new(val))); + ret +} + +fn static_atomic(val: u32) -> &'static AtomicU32 { + let ret = Box::leak(Box::new(AtomicU32::new(val))); ret } @@ -18,6 +24,10 @@ fn split_u32(dword: &mut u32) -> &mut [u16; 2] { unsafe { std::mem::transmute::<&mut u32, &mut [u16; 2]>(dword) } } +fn split_u32_ptr(dword: *const u32) -> *const [u16; 2] { + unsafe { std::mem::transmute::<*const u32, *const [u16; 2]>(dword) } +} + fn mem_replace() { let mut x = AtomicU32::new(0); @@ -31,7 +41,7 @@ fn assign_to_mut() { let x = static_atomic_mut(0); x.store(1, Relaxed); - *x = AtomicUsize::new(2); + *x = AtomicU32::new(2); assert_eq!(x.load(Relaxed), 2); } @@ -70,10 +80,81 @@ fn from_mut_split() { assert_eq!(x_lo_atomic.load(Relaxed), u16::from_be(0xfafa)); } +// Although not possible to do in safe Rust, +// we allow non-atomic and atomic reads to race +// as this should be sound +fn racing_mixed_atomicity_read() { + let x = static_atomic(0); + x.store(42, Relaxed); + + let j1 = spawn(move || x.load(Relaxed)); + + let j2 = spawn(move || { + let x_ptr = x as *const AtomicU32 as *const u32; + unsafe { std::intrinsics::atomic_load_relaxed(x_ptr) } + }); + + let r1 = j1.join().unwrap(); + let r2 = j2.join().unwrap(); + + assert_eq!(r1, 42); + assert_eq!(r2, 42); +} + +fn racing_mixed_size_read() { + let x = static_atomic(0); + + let j1 = spawn(move || { + x.load(Relaxed); + }); + + let j2 = spawn(move || { + let x_ptr = x as *const AtomicU32 as *const u32; + let x_split = split_u32_ptr(x_ptr); + unsafe { + let hi = &(*x_split)[0] as *const u16; + std::intrinsics::atomic_load_relaxed(hi); //~ ERROR: imperfectly overlapping + } + }); + + j1.join().unwrap(); + j2.join().unwrap(); +} + +fn racing_mixed_atomicity_and_size_read() { + let x = static_atomic(u32::from_be(0xabbafafa)); + + let j1 = spawn(move || { + x.load(Relaxed); + }); + + let j2 = spawn(move || { + let x_ptr = x as *const AtomicU32 as *const u32; + unsafe { *x_ptr }; + }); + + let j3 = spawn(move || { + let x_ptr = x as *const AtomicU32 as *const u32; + let x_split = split_u32_ptr(x_ptr); + unsafe { + let hi = &(*x_split)[0] as *const u16; + std::intrinsics::atomic_load_relaxed(hi) + } + }); + + j1.join().unwrap(); + j2.join().unwrap(); + let r3 = j3.join().unwrap(); + + assert_eq!(r3, u16::from_be(0xabba)); +} pub fn main() { get_mut_write(); from_mut_split(); assign_to_mut(); mem_replace(); + racing_mixed_atomicity_read(); + racing_mixed_size_read(); + racing_mixed_atomicity_and_size_read(); } From bfa56454e9544278be9f5de7abad54bcee9af51c Mon Sep 17 00:00:00 2001 From: Andy Wang Date: Wed, 25 May 2022 21:10:00 +0100 Subject: [PATCH 3204/3747] Split extra_cpp tests into sound and unsafe --- src/concurrency/weak_memory.rs | 1 + tests/run-pass/weak_memory/extra_cpp.rs | 83 +--------------- .../run-pass/weak_memory/extra_cpp_unsafe.rs | 97 +++++++++++++++++++ .../weak_memory/extra_cpp_unsafe.stderr | 2 + 4 files changed, 102 insertions(+), 81 deletions(-) create mode 100644 tests/run-pass/weak_memory/extra_cpp_unsafe.rs create mode 100644 tests/run-pass/weak_memory/extra_cpp_unsafe.stderr diff --git a/src/concurrency/weak_memory.rs b/src/concurrency/weak_memory.rs index a4fbd14f4374e..942d71a52ff28 100644 --- a/src/concurrency/weak_memory.rs +++ b/src/concurrency/weak_memory.rs @@ -36,6 +36,7 @@ //! In Rust, these operations can only be done through a `&mut AtomicFoo` reference or one derived from it, therefore these operations //! can only happen after all previous accesses on the same locations. This implementation is adapted to allow these operations. //! A mixed size/atomicity read that races with writes, or a write that races with reads or writes will still cause UBs to be thrown. +//! You can refer to test cases in weak_memory/extra_cpp.rs and weak_memory/extra_cpp_unsafe.rs for examples of these operations. // Our and the author's own implementation (tsan11) of the paper have some deviations from the provided operational semantics in §5.3: // 1. In the operational semantics, store elements keep a copy of the atomic object's vector clock (AtomicCellClocks::sync_vector in miri), diff --git a/tests/run-pass/weak_memory/extra_cpp.rs b/tests/run-pass/weak_memory/extra_cpp.rs index b1a683798bb32..3edac581c353c 100644 --- a/tests/run-pass/weak_memory/extra_cpp.rs +++ b/tests/run-pass/weak_memory/extra_cpp.rs @@ -15,19 +15,10 @@ fn static_atomic_mut(val: u32) -> &'static mut AtomicU32 { ret } -fn static_atomic(val: u32) -> &'static AtomicU32 { - let ret = Box::leak(Box::new(AtomicU32::new(val))); - ret -} - fn split_u32(dword: &mut u32) -> &mut [u16; 2] { unsafe { std::mem::transmute::<&mut u32, &mut [u16; 2]>(dword) } } -fn split_u32_ptr(dword: *const u32) -> *const [u16; 2] { - unsafe { std::mem::transmute::<*const u32, *const [u16; 2]>(dword) } -} - fn mem_replace() { let mut x = AtomicU32::new(0); @@ -71,6 +62,8 @@ fn from_mut_split() { x_atomic.store(u32::from_be(0xabbafafa), Relaxed); } + // Split the `AtomicU32` into two `AtomicU16`. + // Crucially, there is no non-atomic access to `x`! All accesses are atomic, but of different size. let (x_hi, x_lo) = split_u32(&mut x).split_at_mut(1); let x_hi_atomic = AtomicU16::from_mut(&mut x_hi[0]); @@ -80,81 +73,9 @@ fn from_mut_split() { assert_eq!(x_lo_atomic.load(Relaxed), u16::from_be(0xfafa)); } -// Although not possible to do in safe Rust, -// we allow non-atomic and atomic reads to race -// as this should be sound -fn racing_mixed_atomicity_read() { - let x = static_atomic(0); - x.store(42, Relaxed); - - let j1 = spawn(move || x.load(Relaxed)); - - let j2 = spawn(move || { - let x_ptr = x as *const AtomicU32 as *const u32; - unsafe { std::intrinsics::atomic_load_relaxed(x_ptr) } - }); - - let r1 = j1.join().unwrap(); - let r2 = j2.join().unwrap(); - - assert_eq!(r1, 42); - assert_eq!(r2, 42); -} - -fn racing_mixed_size_read() { - let x = static_atomic(0); - - let j1 = spawn(move || { - x.load(Relaxed); - }); - - let j2 = spawn(move || { - let x_ptr = x as *const AtomicU32 as *const u32; - let x_split = split_u32_ptr(x_ptr); - unsafe { - let hi = &(*x_split)[0] as *const u16; - std::intrinsics::atomic_load_relaxed(hi); //~ ERROR: imperfectly overlapping - } - }); - - j1.join().unwrap(); - j2.join().unwrap(); -} - -fn racing_mixed_atomicity_and_size_read() { - let x = static_atomic(u32::from_be(0xabbafafa)); - - let j1 = spawn(move || { - x.load(Relaxed); - }); - - let j2 = spawn(move || { - let x_ptr = x as *const AtomicU32 as *const u32; - unsafe { *x_ptr }; - }); - - let j3 = spawn(move || { - let x_ptr = x as *const AtomicU32 as *const u32; - let x_split = split_u32_ptr(x_ptr); - unsafe { - let hi = &(*x_split)[0] as *const u16; - std::intrinsics::atomic_load_relaxed(hi) - } - }); - - j1.join().unwrap(); - j2.join().unwrap(); - let r3 = j3.join().unwrap(); - - assert_eq!(r3, u16::from_be(0xabba)); -} - pub fn main() { get_mut_write(); from_mut_split(); assign_to_mut(); mem_replace(); - racing_mixed_atomicity_read(); - racing_mixed_size_read(); - racing_mixed_atomicity_and_size_read(); } diff --git a/tests/run-pass/weak_memory/extra_cpp_unsafe.rs b/tests/run-pass/weak_memory/extra_cpp_unsafe.rs new file mode 100644 index 0000000000000..95cc97d4dbb27 --- /dev/null +++ b/tests/run-pass/weak_memory/extra_cpp_unsafe.rs @@ -0,0 +1,97 @@ +// compile-flags: -Zmiri-ignore-leaks + +// Tests operations not perfomable through C++'s atomic API +// but doable in unsafe Rust which we think *should* be fine. +// Nonetheless they may be determined as inconsistent with the +// memory model in the future. + +#![feature(atomic_from_mut)] +#![feature(core_intrinsics)] + +use std::sync::atomic::AtomicU32; +use std::sync::atomic::Ordering::*; +use std::thread::spawn; + +fn static_atomic(val: u32) -> &'static AtomicU32 { + let ret = Box::leak(Box::new(AtomicU32::new(val))); + ret +} + +fn split_u32_ptr(dword: *const u32) -> *const [u16; 2] { + unsafe { std::mem::transmute::<*const u32, *const [u16; 2]>(dword) } +} + +// We allow non-atomic and atomic reads to race +fn racing_mixed_atomicity_read() { + let x = static_atomic(0); + x.store(42, Relaxed); + + let j1 = spawn(move || x.load(Relaxed)); + + let j2 = spawn(move || { + let x_ptr = x as *const AtomicU32 as *const u32; + unsafe { std::intrinsics::atomic_load_relaxed(x_ptr) } + }); + + let r1 = j1.join().unwrap(); + let r2 = j2.join().unwrap(); + + assert_eq!(r1, 42); + assert_eq!(r2, 42); +} + +// We allow mixed-size atomic reads to race +fn racing_mixed_size_read() { + let x = static_atomic(0); + + let j1 = spawn(move || { + x.load(Relaxed); + }); + + let j2 = spawn(move || { + let x_ptr = x as *const AtomicU32 as *const u32; + let x_split = split_u32_ptr(x_ptr); + unsafe { + let hi = &(*x_split)[0] as *const u16; + std::intrinsics::atomic_load_relaxed(hi); + } + }); + + j1.join().unwrap(); + j2.join().unwrap(); +} + +// And the combination of both of above +fn racing_mixed_atomicity_and_size_read() { + let x = static_atomic(u32::from_be(0xabbafafa)); + + let j1 = spawn(move || { + x.load(Relaxed); + }); + + let j2 = spawn(move || { + let x_ptr = x as *const AtomicU32 as *const u32; + unsafe { *x_ptr }; + }); + + let j3 = spawn(move || { + let x_ptr = x as *const AtomicU32 as *const u32; + let x_split = split_u32_ptr(x_ptr); + unsafe { + let hi = &(*x_split)[0] as *const u16; + std::intrinsics::atomic_load_relaxed(hi) + } + }); + + j1.join().unwrap(); + j2.join().unwrap(); + let r3 = j3.join().unwrap(); + + assert_eq!(r3, u16::from_be(0xabba)); +} + +pub fn main() { + racing_mixed_atomicity_read(); + racing_mixed_size_read(); + racing_mixed_atomicity_and_size_read(); +} diff --git a/tests/run-pass/weak_memory/extra_cpp_unsafe.stderr b/tests/run-pass/weak_memory/extra_cpp_unsafe.stderr new file mode 100644 index 0000000000000..1d0ce4b3853da --- /dev/null +++ b/tests/run-pass/weak_memory/extra_cpp_unsafe.stderr @@ -0,0 +1,2 @@ +warning: thread support is experimental: weak memory effects are not fully compatible with the Rust atomics memory model. + From 6a73dedb36516c89914bbdf7f97c425d8615e1ae Mon Sep 17 00:00:00 2001 From: Andy Wang Date: Wed, 25 May 2022 21:54:30 +0100 Subject: [PATCH 3205/3747] Update experimental threading warning --- src/shims/unix/thread.rs | 2 +- .../weak_memory/cpp20_rwc_syncs.stderr | 23 +++++++++++++++++++ .../weak_memory/racing_mixed_size.rs | 1 + .../weak_memory/racing_mixed_size.stderr | 18 +++++++++++++++ .../libc_pthread_create_main_terminate.stderr | 3 ++- .../libc_pthread_join_detached.stderr | 3 ++- .../libc_pthread_join_joined.stderr | 3 ++- .../concurrency/libc_pthread_join_main.stderr | 3 ++- .../libc_pthread_join_multiple.stderr | 3 ++- .../concurrency/libc_pthread_join_self.stderr | 3 ++- .../thread_local_static_dealloc.stderr | 3 ++- tests/fail/concurrency/too_few_args.stderr | 3 ++- tests/fail/concurrency/too_many_args.stderr | 3 ++- .../concurrency/unwind_top_of_stack.stderr | 3 ++- tests/fail/data_race/alloc_read_race.stderr | 3 ++- tests/fail/data_race/alloc_write_race.stderr | 3 ++- .../atomic_read_na_write_race1.stderr | 3 ++- .../atomic_read_na_write_race2.stderr | 3 ++- .../atomic_write_na_read_race1.stderr | 3 ++- .../atomic_write_na_read_race2.stderr | 3 ++- .../atomic_write_na_write_race1.stderr | 3 ++- .../atomic_write_na_write_race2.stderr | 3 ++- .../dangling_thread_async_race.stderr | 3 ++- .../data_race/dangling_thread_race.stderr | 3 ++- .../fail/data_race/dealloc_read_race1.stderr | 3 ++- .../fail/data_race/dealloc_read_race2.stderr | 3 ++- .../data_race/dealloc_read_race_stack.stderr | 3 ++- .../fail/data_race/dealloc_write_race1.stderr | 3 ++- .../fail/data_race/dealloc_write_race2.stderr | 3 ++- .../data_race/dealloc_write_race_stack.stderr | 3 ++- .../enable_after_join_to_main.stderr | 3 ++- tests/fail/data_race/fence_after_load.stderr | 3 ++- tests/fail/data_race/read_write_race.stderr | 3 ++- .../data_race/read_write_race_stack.stderr | 3 ++- .../fail/data_race/relax_acquire_race.stderr | 3 ++- tests/fail/data_race/release_seq_race.stderr | 3 ++- .../release_seq_race_same_thread.stderr | 3 ++- tests/fail/data_race/rmw_race.stderr | 3 ++- tests/fail/data_race/write_write_race.stderr | 3 ++- .../data_race/write_write_race_stack.stderr | 3 ++- .../sync/libc_pthread_mutex_deadlock.stderr | 3 ++- .../libc_pthread_mutex_wrong_owner.stderr | 3 ++- ...ibc_pthread_rwlock_read_wrong_owner.stderr | 3 ++- ..._pthread_rwlock_write_read_deadlock.stderr | 3 ++- ...pthread_rwlock_write_write_deadlock.stderr | 3 ++- ...bc_pthread_rwlock_write_wrong_owner.stderr | 3 ++- tests/pass/concurrency/channels.stderr | 3 ++- .../concurrent_caller_location.stderr | 3 ++- tests/pass/concurrency/data_race.stderr | 3 ++- .../disable_data_race_detector.stderr | 3 ++- tests/pass/concurrency/issue1643.stderr | 3 ++- tests/pass/concurrency/linux-futex.stderr | 3 ++- tests/pass/concurrency/simple.stderr | 3 ++- tests/pass/concurrency/spin_loops.stderr | 3 ++- tests/pass/concurrency/sync.stderr | 3 ++- tests/pass/concurrency/thread_locals.stderr | 3 ++- tests/pass/concurrency/tls_lib_drop.stderr | 3 ++- tests/pass/libc.stderr | 3 ++- tests/pass/panic/concurrent-panic.stderr | 3 ++- tests/pass/threadleak_ignored.stderr | 3 ++- tests/run-pass/weak_memory/consistency.stderr | 3 ++- tests/run-pass/weak_memory/extra_cpp.rs | 1 + tests/run-pass/weak_memory/extra_cpp.stderr | 3 ++- .../run-pass/weak_memory/extra_cpp_unsafe.rs | 1 + .../weak_memory/extra_cpp_unsafe.stderr | 3 ++- tests/run-pass/weak_memory/weak.stderr | 3 ++- 66 files changed, 165 insertions(+), 61 deletions(-) create mode 100644 tests/compile-fail/weak_memory/cpp20_rwc_syncs.stderr create mode 100644 tests/compile-fail/weak_memory/racing_mixed_size.stderr diff --git a/src/shims/unix/thread.rs b/src/shims/unix/thread.rs index 812cb7376b71c..4dc40cf2fe3dc 100644 --- a/src/shims/unix/thread.rs +++ b/src/shims/unix/thread.rs @@ -14,7 +14,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); this.tcx.sess.warn( - "thread support is experimental: weak memory effects are not fully compatible with the Rust atomics memory model.", + "thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops.\n(see https://github.com/rust-lang/miri/issues/1388)", ); // Create the new thread diff --git a/tests/compile-fail/weak_memory/cpp20_rwc_syncs.stderr b/tests/compile-fail/weak_memory/cpp20_rwc_syncs.stderr new file mode 100644 index 0000000000000..f4f467120e8a4 --- /dev/null +++ b/tests/compile-fail/weak_memory/cpp20_rwc_syncs.stderr @@ -0,0 +1,23 @@ +warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. + (see https://github.com/rust-lang/miri/issues/1388) + +error: Undefined Behavior: type validation failed at .value: encountered uninitialized raw pointer + --> $DIR/cpp20_rwc_syncs.rs:LL:CC + | +LL | let _ = unsafe { std::mem::MaybeUninit::<*const u32>::uninit().assume_init() }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .value: encountered uninitialized raw pointer + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `test_cpp20_rwc_syncs` at $DIR/cpp20_rwc_syncs.rs:LL:CC +note: inside `main` at $DIR/cpp20_rwc_syncs.rs:LL:CC + --> $DIR/cpp20_rwc_syncs.rs:LL:CC + | +LL | test_cpp20_rwc_syncs(); + | ^^^^^^^^^^^^^^^^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error; 1 warning emitted + diff --git a/tests/compile-fail/weak_memory/racing_mixed_size.rs b/tests/compile-fail/weak_memory/racing_mixed_size.rs index d4ba48afe39d2..513d97edb51cf 100644 --- a/tests/compile-fail/weak_memory/racing_mixed_size.rs +++ b/tests/compile-fail/weak_memory/racing_mixed_size.rs @@ -1,3 +1,4 @@ +// ignore-windows: Concurrency on Windows is not supported yet. // compile-flags: -Zmiri-ignore-leaks #![feature(core_intrinsics)] diff --git a/tests/compile-fail/weak_memory/racing_mixed_size.stderr b/tests/compile-fail/weak_memory/racing_mixed_size.stderr new file mode 100644 index 0000000000000..b3074d93c9cb0 --- /dev/null +++ b/tests/compile-fail/weak_memory/racing_mixed_size.stderr @@ -0,0 +1,18 @@ +warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. + (see https://github.com/rust-lang/miri/issues/1388) + +error: Undefined Behavior: racy imperfectly overlapping atomic access + --> $DIR/racing_mixed_size.rs:LL:CC + | +LL | std::intrinsics::atomic_load_relaxed(hi); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ racy imperfectly overlapping atomic access + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside closure at $DIR/racing_mixed_size.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error; 1 warning emitted + diff --git a/tests/fail/concurrency/libc_pthread_create_main_terminate.stderr b/tests/fail/concurrency/libc_pthread_create_main_terminate.stderr index 0f7fbefe0af08..2ce73fdaaec10 100644 --- a/tests/fail/concurrency/libc_pthread_create_main_terminate.stderr +++ b/tests/fail/concurrency/libc_pthread_create_main_terminate.stderr @@ -1,4 +1,5 @@ -warning: thread support is experimental and incomplete: weak memory effects are not emulated. +warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. + (see https://github.com/rust-lang/miri/issues/1388) error: the main thread terminated without waiting for all remaining threads diff --git a/tests/fail/concurrency/libc_pthread_join_detached.stderr b/tests/fail/concurrency/libc_pthread_join_detached.stderr index 688f61a98b904..b106cc4c95418 100644 --- a/tests/fail/concurrency/libc_pthread_join_detached.stderr +++ b/tests/fail/concurrency/libc_pthread_join_detached.stderr @@ -1,4 +1,5 @@ -warning: thread support is experimental and incomplete: weak memory effects are not emulated. +warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. + (see https://github.com/rust-lang/miri/issues/1388) error: Undefined Behavior: trying to join a detached or already joined thread --> $DIR/libc_pthread_join_detached.rs:LL:CC diff --git a/tests/fail/concurrency/libc_pthread_join_joined.stderr b/tests/fail/concurrency/libc_pthread_join_joined.stderr index 518f72de5bef8..438998208d11b 100644 --- a/tests/fail/concurrency/libc_pthread_join_joined.stderr +++ b/tests/fail/concurrency/libc_pthread_join_joined.stderr @@ -1,4 +1,5 @@ -warning: thread support is experimental and incomplete: weak memory effects are not emulated. +warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. + (see https://github.com/rust-lang/miri/issues/1388) error: Undefined Behavior: trying to join a detached or already joined thread --> $DIR/libc_pthread_join_joined.rs:LL:CC diff --git a/tests/fail/concurrency/libc_pthread_join_main.stderr b/tests/fail/concurrency/libc_pthread_join_main.stderr index 5d9ec148e0797..04f2ab07406c0 100644 --- a/tests/fail/concurrency/libc_pthread_join_main.stderr +++ b/tests/fail/concurrency/libc_pthread_join_main.stderr @@ -1,4 +1,5 @@ -warning: thread support is experimental and incomplete: weak memory effects are not emulated. +warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. + (see https://github.com/rust-lang/miri/issues/1388) error: Undefined Behavior: trying to join a detached or already joined thread --> $DIR/libc_pthread_join_main.rs:LL:CC diff --git a/tests/fail/concurrency/libc_pthread_join_multiple.stderr b/tests/fail/concurrency/libc_pthread_join_multiple.stderr index 57126a14ae2ff..daf18c50e034f 100644 --- a/tests/fail/concurrency/libc_pthread_join_multiple.stderr +++ b/tests/fail/concurrency/libc_pthread_join_multiple.stderr @@ -1,4 +1,5 @@ -warning: thread support is experimental and incomplete: weak memory effects are not emulated. +warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. + (see https://github.com/rust-lang/miri/issues/1388) error: Undefined Behavior: trying to join a detached or already joined thread --> $DIR/libc_pthread_join_multiple.rs:LL:CC diff --git a/tests/fail/concurrency/libc_pthread_join_self.stderr b/tests/fail/concurrency/libc_pthread_join_self.stderr index d638d089398ae..b2e0779f5fbbd 100644 --- a/tests/fail/concurrency/libc_pthread_join_self.stderr +++ b/tests/fail/concurrency/libc_pthread_join_self.stderr @@ -1,4 +1,5 @@ -warning: thread support is experimental and incomplete: weak memory effects are not emulated. +warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. + (see https://github.com/rust-lang/miri/issues/1388) error: Undefined Behavior: trying to join itself --> $DIR/libc_pthread_join_self.rs:LL:CC diff --git a/tests/fail/concurrency/thread_local_static_dealloc.stderr b/tests/fail/concurrency/thread_local_static_dealloc.stderr index cdeb22fb31759..ad5528dc555ab 100644 --- a/tests/fail/concurrency/thread_local_static_dealloc.stderr +++ b/tests/fail/concurrency/thread_local_static_dealloc.stderr @@ -1,4 +1,5 @@ -warning: thread support is experimental and incomplete: weak memory effects are not emulated. +warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. + (see https://github.com/rust-lang/miri/issues/1388) error: Undefined Behavior: pointer to ALLOC was dereferenced after this allocation got freed --> $DIR/thread_local_static_dealloc.rs:LL:CC diff --git a/tests/fail/concurrency/too_few_args.stderr b/tests/fail/concurrency/too_few_args.stderr index 7401b2902ead8..1ed8c5a510f4f 100644 --- a/tests/fail/concurrency/too_few_args.stderr +++ b/tests/fail/concurrency/too_few_args.stderr @@ -1,4 +1,5 @@ -warning: thread support is experimental and incomplete: weak memory effects are not emulated. +warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. + (see https://github.com/rust-lang/miri/issues/1388) error: Undefined Behavior: callee has fewer arguments than expected --> $DIR/too_few_args.rs:LL:CC diff --git a/tests/fail/concurrency/too_many_args.stderr b/tests/fail/concurrency/too_many_args.stderr index 951b76317f250..5602dab993b08 100644 --- a/tests/fail/concurrency/too_many_args.stderr +++ b/tests/fail/concurrency/too_many_args.stderr @@ -1,4 +1,5 @@ -warning: thread support is experimental and incomplete: weak memory effects are not emulated. +warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. + (see https://github.com/rust-lang/miri/issues/1388) error: Undefined Behavior: callee has more arguments than expected --> $DIR/too_many_args.rs:LL:CC diff --git a/tests/fail/concurrency/unwind_top_of_stack.stderr b/tests/fail/concurrency/unwind_top_of_stack.stderr index 600b8443d2c79..26a196a5590f1 100644 --- a/tests/fail/concurrency/unwind_top_of_stack.stderr +++ b/tests/fail/concurrency/unwind_top_of_stack.stderr @@ -1,4 +1,5 @@ -warning: thread support is experimental and incomplete: weak memory effects are not emulated. +warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. + (see https://github.com/rust-lang/miri/issues/1388) thread '' panicked at 'explicit panic', $DIR/unwind_top_of_stack.rs:LL:CC note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace diff --git a/tests/fail/data_race/alloc_read_race.stderr b/tests/fail/data_race/alloc_read_race.stderr index 9d9006966b335..0b247fb19bc9c 100644 --- a/tests/fail/data_race/alloc_read_race.stderr +++ b/tests/fail/data_race/alloc_read_race.stderr @@ -1,4 +1,5 @@ -warning: thread support is experimental and incomplete: weak memory effects are not emulated. +warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. + (see https://github.com/rust-lang/miri/issues/1388) error: Undefined Behavior: Data race detected between Read on Thread(id = 2) and Allocate on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) --> $DIR/alloc_read_race.rs:LL:CC diff --git a/tests/fail/data_race/alloc_write_race.stderr b/tests/fail/data_race/alloc_write_race.stderr index 318895cae6b06..3594980ef9b02 100644 --- a/tests/fail/data_race/alloc_write_race.stderr +++ b/tests/fail/data_race/alloc_write_race.stderr @@ -1,4 +1,5 @@ -warning: thread support is experimental and incomplete: weak memory effects are not emulated. +warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. + (see https://github.com/rust-lang/miri/issues/1388) error: Undefined Behavior: Data race detected between Write on Thread(id = 2) and Allocate on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) --> $DIR/alloc_write_race.rs:LL:CC diff --git a/tests/fail/data_race/atomic_read_na_write_race1.stderr b/tests/fail/data_race/atomic_read_na_write_race1.stderr index 09d7accb05431..0c9aaf5a0019a 100644 --- a/tests/fail/data_race/atomic_read_na_write_race1.stderr +++ b/tests/fail/data_race/atomic_read_na_write_race1.stderr @@ -1,4 +1,5 @@ -warning: thread support is experimental and incomplete: weak memory effects are not emulated. +warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. + (see https://github.com/rust-lang/miri/issues/1388) error: Undefined Behavior: Data race detected between Atomic Load on Thread(id = 2) and Write on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) --> $DIR/atomic_read_na_write_race1.rs:LL:CC diff --git a/tests/fail/data_race/atomic_read_na_write_race2.stderr b/tests/fail/data_race/atomic_read_na_write_race2.stderr index 739ce83d0b072..6e3a1330f9dd6 100644 --- a/tests/fail/data_race/atomic_read_na_write_race2.stderr +++ b/tests/fail/data_race/atomic_read_na_write_race2.stderr @@ -1,4 +1,5 @@ -warning: thread support is experimental and incomplete: weak memory effects are not emulated. +warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. + (see https://github.com/rust-lang/miri/issues/1388) error: Undefined Behavior: Data race detected between Write on Thread(id = 2) and Atomic Load on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) --> $DIR/atomic_read_na_write_race2.rs:LL:CC diff --git a/tests/fail/data_race/atomic_write_na_read_race1.stderr b/tests/fail/data_race/atomic_write_na_read_race1.stderr index 6d67f58aaee41..4dc4ac1e6768e 100644 --- a/tests/fail/data_race/atomic_write_na_read_race1.stderr +++ b/tests/fail/data_race/atomic_write_na_read_race1.stderr @@ -1,4 +1,5 @@ -warning: thread support is experimental and incomplete: weak memory effects are not emulated. +warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. + (see https://github.com/rust-lang/miri/issues/1388) error: Undefined Behavior: Data race detected between Read on Thread(id = 2) and Atomic Store on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) --> $DIR/atomic_write_na_read_race1.rs:LL:CC diff --git a/tests/fail/data_race/atomic_write_na_read_race2.stderr b/tests/fail/data_race/atomic_write_na_read_race2.stderr index d9950ebcb75ba..e665073c539e2 100644 --- a/tests/fail/data_race/atomic_write_na_read_race2.stderr +++ b/tests/fail/data_race/atomic_write_na_read_race2.stderr @@ -1,4 +1,5 @@ -warning: thread support is experimental and incomplete: weak memory effects are not emulated. +warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. + (see https://github.com/rust-lang/miri/issues/1388) error: Undefined Behavior: Data race detected between Atomic Store on Thread(id = 2) and Read on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) --> $DIR/atomic_write_na_read_race2.rs:LL:CC diff --git a/tests/fail/data_race/atomic_write_na_write_race1.stderr b/tests/fail/data_race/atomic_write_na_write_race1.stderr index 29ccf7021253e..a70c3b52de503 100644 --- a/tests/fail/data_race/atomic_write_na_write_race1.stderr +++ b/tests/fail/data_race/atomic_write_na_write_race1.stderr @@ -1,4 +1,5 @@ -warning: thread support is experimental and incomplete: weak memory effects are not emulated. +warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. + (see https://github.com/rust-lang/miri/issues/1388) error: Undefined Behavior: Data race detected between Atomic Store on Thread(id = 2) and Write on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) --> $DIR/atomic_write_na_write_race1.rs:LL:CC diff --git a/tests/fail/data_race/atomic_write_na_write_race2.stderr b/tests/fail/data_race/atomic_write_na_write_race2.stderr index 5488f05de031e..79730d507934c 100644 --- a/tests/fail/data_race/atomic_write_na_write_race2.stderr +++ b/tests/fail/data_race/atomic_write_na_write_race2.stderr @@ -1,4 +1,5 @@ -warning: thread support is experimental and incomplete: weak memory effects are not emulated. +warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. + (see https://github.com/rust-lang/miri/issues/1388) error: Undefined Behavior: Data race detected between Write on Thread(id = 2) and Atomic Store on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) --> $DIR/atomic_write_na_write_race2.rs:LL:CC diff --git a/tests/fail/data_race/dangling_thread_async_race.stderr b/tests/fail/data_race/dangling_thread_async_race.stderr index eccc243d696ef..21b3eefc5e418 100644 --- a/tests/fail/data_race/dangling_thread_async_race.stderr +++ b/tests/fail/data_race/dangling_thread_async_race.stderr @@ -1,4 +1,5 @@ -warning: thread support is experimental and incomplete: weak memory effects are not emulated. +warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. + (see https://github.com/rust-lang/miri/issues/1388) error: Undefined Behavior: Data race detected between Write on Thread(id = 3) and Write on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) --> $DIR/dangling_thread_async_race.rs:LL:CC diff --git a/tests/fail/data_race/dangling_thread_race.stderr b/tests/fail/data_race/dangling_thread_race.stderr index 4dffeb14233a1..3ca8862a5819a 100644 --- a/tests/fail/data_race/dangling_thread_race.stderr +++ b/tests/fail/data_race/dangling_thread_race.stderr @@ -1,4 +1,5 @@ -warning: thread support is experimental and incomplete: weak memory effects are not emulated. +warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. + (see https://github.com/rust-lang/miri/issues/1388) error: Undefined Behavior: Data race detected between Write on Thread(id = 0, name = "main") and Write on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) --> $DIR/dangling_thread_race.rs:LL:CC diff --git a/tests/fail/data_race/dealloc_read_race1.stderr b/tests/fail/data_race/dealloc_read_race1.stderr index 37196021ead93..10b32003ff400 100644 --- a/tests/fail/data_race/dealloc_read_race1.stderr +++ b/tests/fail/data_race/dealloc_read_race1.stderr @@ -1,4 +1,5 @@ -warning: thread support is experimental and incomplete: weak memory effects are not emulated. +warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. + (see https://github.com/rust-lang/miri/issues/1388) error: Undefined Behavior: Data race detected between Deallocate on Thread(id = 2) and Read on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) --> $DIR/dealloc_read_race1.rs:LL:CC diff --git a/tests/fail/data_race/dealloc_read_race2.stderr b/tests/fail/data_race/dealloc_read_race2.stderr index 03fb5dbea90d5..a21de1d9f7a9f 100644 --- a/tests/fail/data_race/dealloc_read_race2.stderr +++ b/tests/fail/data_race/dealloc_read_race2.stderr @@ -1,4 +1,5 @@ -warning: thread support is experimental and incomplete: weak memory effects are not emulated. +warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. + (see https://github.com/rust-lang/miri/issues/1388) error: Undefined Behavior: pointer to ALLOC was dereferenced after this allocation got freed --> $DIR/dealloc_read_race2.rs:LL:CC diff --git a/tests/fail/data_race/dealloc_read_race_stack.stderr b/tests/fail/data_race/dealloc_read_race_stack.stderr index 055724fe29794..0f7213eb8d521 100644 --- a/tests/fail/data_race/dealloc_read_race_stack.stderr +++ b/tests/fail/data_race/dealloc_read_race_stack.stderr @@ -1,4 +1,5 @@ -warning: thread support is experimental and incomplete: weak memory effects are not emulated. +warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. + (see https://github.com/rust-lang/miri/issues/1388) error: Undefined Behavior: Data race detected between Deallocate on Thread(id = 1) and Read on Thread(id = 2) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) --> $DIR/dealloc_read_race_stack.rs:LL:CC diff --git a/tests/fail/data_race/dealloc_write_race1.stderr b/tests/fail/data_race/dealloc_write_race1.stderr index 7160f49af697d..76258e9d8fc0b 100644 --- a/tests/fail/data_race/dealloc_write_race1.stderr +++ b/tests/fail/data_race/dealloc_write_race1.stderr @@ -1,4 +1,5 @@ -warning: thread support is experimental and incomplete: weak memory effects are not emulated. +warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. + (see https://github.com/rust-lang/miri/issues/1388) error: Undefined Behavior: Data race detected between Deallocate on Thread(id = 2) and Write on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) --> $DIR/dealloc_write_race1.rs:LL:CC diff --git a/tests/fail/data_race/dealloc_write_race2.stderr b/tests/fail/data_race/dealloc_write_race2.stderr index cb0d0af8672b3..d9aef72118d89 100644 --- a/tests/fail/data_race/dealloc_write_race2.stderr +++ b/tests/fail/data_race/dealloc_write_race2.stderr @@ -1,4 +1,5 @@ -warning: thread support is experimental and incomplete: weak memory effects are not emulated. +warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. + (see https://github.com/rust-lang/miri/issues/1388) error: Undefined Behavior: pointer to ALLOC was dereferenced after this allocation got freed --> $DIR/dealloc_write_race2.rs:LL:CC diff --git a/tests/fail/data_race/dealloc_write_race_stack.stderr b/tests/fail/data_race/dealloc_write_race_stack.stderr index 05a8e1a8b7e21..70533f654b777 100644 --- a/tests/fail/data_race/dealloc_write_race_stack.stderr +++ b/tests/fail/data_race/dealloc_write_race_stack.stderr @@ -1,4 +1,5 @@ -warning: thread support is experimental and incomplete: weak memory effects are not emulated. +warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. + (see https://github.com/rust-lang/miri/issues/1388) error: Undefined Behavior: Data race detected between Deallocate on Thread(id = 1) and Write on Thread(id = 2) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) --> $DIR/dealloc_write_race_stack.rs:LL:CC diff --git a/tests/fail/data_race/enable_after_join_to_main.stderr b/tests/fail/data_race/enable_after_join_to_main.stderr index e612e08ade4ff..58d33ffa8cf3c 100644 --- a/tests/fail/data_race/enable_after_join_to_main.stderr +++ b/tests/fail/data_race/enable_after_join_to_main.stderr @@ -1,4 +1,5 @@ -warning: thread support is experimental and incomplete: weak memory effects are not emulated. +warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. + (see https://github.com/rust-lang/miri/issues/1388) error: Undefined Behavior: Data race detected between Write on Thread(id = 6) and Write on Thread(id = 5) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) --> $DIR/enable_after_join_to_main.rs:LL:CC diff --git a/tests/fail/data_race/fence_after_load.stderr b/tests/fail/data_race/fence_after_load.stderr index 14452391327a1..1e3186b08fa11 100644 --- a/tests/fail/data_race/fence_after_load.stderr +++ b/tests/fail/data_race/fence_after_load.stderr @@ -1,4 +1,5 @@ -warning: thread support is experimental and incomplete: weak memory effects are not emulated. +warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. + (see https://github.com/rust-lang/miri/issues/1388) error: Undefined Behavior: Data race detected between Write on Thread(id = 0, name = "main") and Write on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) --> $DIR/fence_after_load.rs:LL:CC diff --git a/tests/fail/data_race/read_write_race.stderr b/tests/fail/data_race/read_write_race.stderr index fc04141830bff..5078e662546a8 100644 --- a/tests/fail/data_race/read_write_race.stderr +++ b/tests/fail/data_race/read_write_race.stderr @@ -1,4 +1,5 @@ -warning: thread support is experimental and incomplete: weak memory effects are not emulated. +warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. + (see https://github.com/rust-lang/miri/issues/1388) error: Undefined Behavior: Data race detected between Write on Thread(id = 2) and Read on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) --> $DIR/read_write_race.rs:LL:CC diff --git a/tests/fail/data_race/read_write_race_stack.stderr b/tests/fail/data_race/read_write_race_stack.stderr index aad63731ca050..843bea753b651 100644 --- a/tests/fail/data_race/read_write_race_stack.stderr +++ b/tests/fail/data_race/read_write_race_stack.stderr @@ -1,4 +1,5 @@ -warning: thread support is experimental and incomplete: weak memory effects are not emulated. +warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. + (see https://github.com/rust-lang/miri/issues/1388) error: Undefined Behavior: Data race detected between Read on Thread(id = 1) and Write on Thread(id = 2) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) --> $DIR/read_write_race_stack.rs:LL:CC diff --git a/tests/fail/data_race/relax_acquire_race.stderr b/tests/fail/data_race/relax_acquire_race.stderr index a437120c891d7..d2423ff916316 100644 --- a/tests/fail/data_race/relax_acquire_race.stderr +++ b/tests/fail/data_race/relax_acquire_race.stderr @@ -1,4 +1,5 @@ -warning: thread support is experimental and incomplete: weak memory effects are not emulated. +warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. + (see https://github.com/rust-lang/miri/issues/1388) error: Undefined Behavior: Data race detected between Read on Thread(id = 3) and Write on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) --> $DIR/relax_acquire_race.rs:LL:CC diff --git a/tests/fail/data_race/release_seq_race.stderr b/tests/fail/data_race/release_seq_race.stderr index 1a1c7ac64f78e..ffbf50c09172d 100644 --- a/tests/fail/data_race/release_seq_race.stderr +++ b/tests/fail/data_race/release_seq_race.stderr @@ -1,4 +1,5 @@ -warning: thread support is experimental and incomplete: weak memory effects are not emulated. +warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. + (see https://github.com/rust-lang/miri/issues/1388) error: Undefined Behavior: Data race detected between Read on Thread(id = 3) and Write on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) --> $DIR/release_seq_race.rs:LL:CC diff --git a/tests/fail/data_race/release_seq_race_same_thread.stderr b/tests/fail/data_race/release_seq_race_same_thread.stderr index f357c0647d4df..b760215146113 100644 --- a/tests/fail/data_race/release_seq_race_same_thread.stderr +++ b/tests/fail/data_race/release_seq_race_same_thread.stderr @@ -1,4 +1,5 @@ -warning: thread support is experimental and incomplete: weak memory effects are not emulated. +warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. + (see https://github.com/rust-lang/miri/issues/1388) error: Undefined Behavior: Data race detected between Read on Thread(id = 2) and Write on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) --> $DIR/release_seq_race_same_thread.rs:LL:CC diff --git a/tests/fail/data_race/rmw_race.stderr b/tests/fail/data_race/rmw_race.stderr index dd3692c6dcc87..c6b09ba5f00bc 100644 --- a/tests/fail/data_race/rmw_race.stderr +++ b/tests/fail/data_race/rmw_race.stderr @@ -1,4 +1,5 @@ -warning: thread support is experimental and incomplete: weak memory effects are not emulated. +warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. + (see https://github.com/rust-lang/miri/issues/1388) error: Undefined Behavior: Data race detected between Read on Thread(id = 3) and Write on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) --> $DIR/rmw_race.rs:LL:CC diff --git a/tests/fail/data_race/write_write_race.stderr b/tests/fail/data_race/write_write_race.stderr index dafee7dbf8cf4..5acba97486eab 100644 --- a/tests/fail/data_race/write_write_race.stderr +++ b/tests/fail/data_race/write_write_race.stderr @@ -1,4 +1,5 @@ -warning: thread support is experimental and incomplete: weak memory effects are not emulated. +warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. + (see https://github.com/rust-lang/miri/issues/1388) error: Undefined Behavior: Data race detected between Write on Thread(id = 2) and Write on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) --> $DIR/write_write_race.rs:LL:CC diff --git a/tests/fail/data_race/write_write_race_stack.stderr b/tests/fail/data_race/write_write_race_stack.stderr index 8d113673ac156..d052206f4cc72 100644 --- a/tests/fail/data_race/write_write_race_stack.stderr +++ b/tests/fail/data_race/write_write_race_stack.stderr @@ -1,4 +1,5 @@ -warning: thread support is experimental and incomplete: weak memory effects are not emulated. +warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. + (see https://github.com/rust-lang/miri/issues/1388) error: Undefined Behavior: Data race detected between Write on Thread(id = 1) and Write on Thread(id = 2) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) --> $DIR/write_write_race_stack.rs:LL:CC diff --git a/tests/fail/sync/libc_pthread_mutex_deadlock.stderr b/tests/fail/sync/libc_pthread_mutex_deadlock.stderr index ac37096ad80d4..d1f9ee6cdd5f1 100644 --- a/tests/fail/sync/libc_pthread_mutex_deadlock.stderr +++ b/tests/fail/sync/libc_pthread_mutex_deadlock.stderr @@ -1,4 +1,5 @@ -warning: thread support is experimental and incomplete: weak memory effects are not emulated. +warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. + (see https://github.com/rust-lang/miri/issues/1388) error: deadlock: the evaluated program deadlocked --> $DIR/libc_pthread_mutex_deadlock.rs:LL:CC diff --git a/tests/fail/sync/libc_pthread_mutex_wrong_owner.stderr b/tests/fail/sync/libc_pthread_mutex_wrong_owner.stderr index 6603b264d9b48..e9f0e2d4c1573 100644 --- a/tests/fail/sync/libc_pthread_mutex_wrong_owner.stderr +++ b/tests/fail/sync/libc_pthread_mutex_wrong_owner.stderr @@ -1,4 +1,5 @@ -warning: thread support is experimental and incomplete: weak memory effects are not emulated. +warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. + (see https://github.com/rust-lang/miri/issues/1388) error: Undefined Behavior: unlocked a default mutex that was not locked by the current thread --> $DIR/libc_pthread_mutex_wrong_owner.rs:LL:CC diff --git a/tests/fail/sync/libc_pthread_rwlock_read_wrong_owner.stderr b/tests/fail/sync/libc_pthread_rwlock_read_wrong_owner.stderr index d3820f0dcb742..c25ab25a3da5b 100644 --- a/tests/fail/sync/libc_pthread_rwlock_read_wrong_owner.stderr +++ b/tests/fail/sync/libc_pthread_rwlock_read_wrong_owner.stderr @@ -1,4 +1,5 @@ -warning: thread support is experimental and incomplete: weak memory effects are not emulated. +warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. + (see https://github.com/rust-lang/miri/issues/1388) error: Undefined Behavior: unlocked an rwlock that was not locked by the active thread --> $DIR/libc_pthread_rwlock_read_wrong_owner.rs:LL:CC diff --git a/tests/fail/sync/libc_pthread_rwlock_write_read_deadlock.stderr b/tests/fail/sync/libc_pthread_rwlock_write_read_deadlock.stderr index 748a363a27a4d..8fc2ae4c82e56 100644 --- a/tests/fail/sync/libc_pthread_rwlock_write_read_deadlock.stderr +++ b/tests/fail/sync/libc_pthread_rwlock_write_read_deadlock.stderr @@ -1,4 +1,5 @@ -warning: thread support is experimental and incomplete: weak memory effects are not emulated. +warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. + (see https://github.com/rust-lang/miri/issues/1388) error: deadlock: the evaluated program deadlocked --> $DIR/libc_pthread_rwlock_write_read_deadlock.rs:LL:CC diff --git a/tests/fail/sync/libc_pthread_rwlock_write_write_deadlock.stderr b/tests/fail/sync/libc_pthread_rwlock_write_write_deadlock.stderr index c6a03ff9afb82..86c67925fb935 100644 --- a/tests/fail/sync/libc_pthread_rwlock_write_write_deadlock.stderr +++ b/tests/fail/sync/libc_pthread_rwlock_write_write_deadlock.stderr @@ -1,4 +1,5 @@ -warning: thread support is experimental and incomplete: weak memory effects are not emulated. +warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. + (see https://github.com/rust-lang/miri/issues/1388) error: deadlock: the evaluated program deadlocked --> $DIR/libc_pthread_rwlock_write_write_deadlock.rs:LL:CC diff --git a/tests/fail/sync/libc_pthread_rwlock_write_wrong_owner.stderr b/tests/fail/sync/libc_pthread_rwlock_write_wrong_owner.stderr index 02a6cf11c0a20..8965d55a489d1 100644 --- a/tests/fail/sync/libc_pthread_rwlock_write_wrong_owner.stderr +++ b/tests/fail/sync/libc_pthread_rwlock_write_wrong_owner.stderr @@ -1,4 +1,5 @@ -warning: thread support is experimental and incomplete: weak memory effects are not emulated. +warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. + (see https://github.com/rust-lang/miri/issues/1388) error: Undefined Behavior: unlocked an rwlock that was not locked by the active thread --> $DIR/libc_pthread_rwlock_write_wrong_owner.rs:LL:CC diff --git a/tests/pass/concurrency/channels.stderr b/tests/pass/concurrency/channels.stderr index 1d0ce4b3853da..9fe6daa778c1f 100644 --- a/tests/pass/concurrency/channels.stderr +++ b/tests/pass/concurrency/channels.stderr @@ -1,2 +1,3 @@ -warning: thread support is experimental: weak memory effects are not fully compatible with the Rust atomics memory model. +warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. + (see https://github.com/rust-lang/miri/issues/1388) diff --git a/tests/pass/concurrency/concurrent_caller_location.stderr b/tests/pass/concurrency/concurrent_caller_location.stderr index 1d0ce4b3853da..9fe6daa778c1f 100644 --- a/tests/pass/concurrency/concurrent_caller_location.stderr +++ b/tests/pass/concurrency/concurrent_caller_location.stderr @@ -1,2 +1,3 @@ -warning: thread support is experimental: weak memory effects are not fully compatible with the Rust atomics memory model. +warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. + (see https://github.com/rust-lang/miri/issues/1388) diff --git a/tests/pass/concurrency/data_race.stderr b/tests/pass/concurrency/data_race.stderr index 1d0ce4b3853da..9fe6daa778c1f 100644 --- a/tests/pass/concurrency/data_race.stderr +++ b/tests/pass/concurrency/data_race.stderr @@ -1,2 +1,3 @@ -warning: thread support is experimental: weak memory effects are not fully compatible with the Rust atomics memory model. +warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. + (see https://github.com/rust-lang/miri/issues/1388) diff --git a/tests/pass/concurrency/disable_data_race_detector.stderr b/tests/pass/concurrency/disable_data_race_detector.stderr index 1d0ce4b3853da..9fe6daa778c1f 100644 --- a/tests/pass/concurrency/disable_data_race_detector.stderr +++ b/tests/pass/concurrency/disable_data_race_detector.stderr @@ -1,2 +1,3 @@ -warning: thread support is experimental: weak memory effects are not fully compatible with the Rust atomics memory model. +warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. + (see https://github.com/rust-lang/miri/issues/1388) diff --git a/tests/pass/concurrency/issue1643.stderr b/tests/pass/concurrency/issue1643.stderr index 1d0ce4b3853da..9fe6daa778c1f 100644 --- a/tests/pass/concurrency/issue1643.stderr +++ b/tests/pass/concurrency/issue1643.stderr @@ -1,2 +1,3 @@ -warning: thread support is experimental: weak memory effects are not fully compatible with the Rust atomics memory model. +warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. + (see https://github.com/rust-lang/miri/issues/1388) diff --git a/tests/pass/concurrency/linux-futex.stderr b/tests/pass/concurrency/linux-futex.stderr index 1d0ce4b3853da..9fe6daa778c1f 100644 --- a/tests/pass/concurrency/linux-futex.stderr +++ b/tests/pass/concurrency/linux-futex.stderr @@ -1,2 +1,3 @@ -warning: thread support is experimental: weak memory effects are not fully compatible with the Rust atomics memory model. +warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. + (see https://github.com/rust-lang/miri/issues/1388) diff --git a/tests/pass/concurrency/simple.stderr b/tests/pass/concurrency/simple.stderr index 386dc922691ab..0ba9e8645b28a 100644 --- a/tests/pass/concurrency/simple.stderr +++ b/tests/pass/concurrency/simple.stderr @@ -1,4 +1,5 @@ -warning: thread support is experimental: weak memory effects are not fully compatible with the Rust atomics memory model. +warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. + (see https://github.com/rust-lang/miri/issues/1388) thread '' panicked at 'Hello!', $DIR/simple.rs:LL:CC note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace diff --git a/tests/pass/concurrency/spin_loops.stderr b/tests/pass/concurrency/spin_loops.stderr index 03676519d4f1c..9fe6daa778c1f 100644 --- a/tests/pass/concurrency/spin_loops.stderr +++ b/tests/pass/concurrency/spin_loops.stderr @@ -1,2 +1,3 @@ -warning: thread support is experimental and incomplete: weak memory effects are not emulated. +warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. + (see https://github.com/rust-lang/miri/issues/1388) diff --git a/tests/pass/concurrency/sync.stderr b/tests/pass/concurrency/sync.stderr index 1d0ce4b3853da..9fe6daa778c1f 100644 --- a/tests/pass/concurrency/sync.stderr +++ b/tests/pass/concurrency/sync.stderr @@ -1,2 +1,3 @@ -warning: thread support is experimental: weak memory effects are not fully compatible with the Rust atomics memory model. +warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. + (see https://github.com/rust-lang/miri/issues/1388) diff --git a/tests/pass/concurrency/thread_locals.stderr b/tests/pass/concurrency/thread_locals.stderr index 1d0ce4b3853da..9fe6daa778c1f 100644 --- a/tests/pass/concurrency/thread_locals.stderr +++ b/tests/pass/concurrency/thread_locals.stderr @@ -1,2 +1,3 @@ -warning: thread support is experimental: weak memory effects are not fully compatible with the Rust atomics memory model. +warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. + (see https://github.com/rust-lang/miri/issues/1388) diff --git a/tests/pass/concurrency/tls_lib_drop.stderr b/tests/pass/concurrency/tls_lib_drop.stderr index 1d0ce4b3853da..9fe6daa778c1f 100644 --- a/tests/pass/concurrency/tls_lib_drop.stderr +++ b/tests/pass/concurrency/tls_lib_drop.stderr @@ -1,2 +1,3 @@ -warning: thread support is experimental: weak memory effects are not fully compatible with the Rust atomics memory model. +warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. + (see https://github.com/rust-lang/miri/issues/1388) diff --git a/tests/pass/libc.stderr b/tests/pass/libc.stderr index 1d0ce4b3853da..9fe6daa778c1f 100644 --- a/tests/pass/libc.stderr +++ b/tests/pass/libc.stderr @@ -1,2 +1,3 @@ -warning: thread support is experimental: weak memory effects are not fully compatible with the Rust atomics memory model. +warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. + (see https://github.com/rust-lang/miri/issues/1388) diff --git a/tests/pass/panic/concurrent-panic.stderr b/tests/pass/panic/concurrent-panic.stderr index 0d4a409dfecf6..b90cc01bb857e 100644 --- a/tests/pass/panic/concurrent-panic.stderr +++ b/tests/pass/panic/concurrent-panic.stderr @@ -1,4 +1,5 @@ -warning: thread support is experimental: weak memory effects are not fully compatible with the Rust atomics memory model. +warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. + (see https://github.com/rust-lang/miri/issues/1388) Thread 1 starting, will block on mutex Thread 1 reported it has started diff --git a/tests/pass/threadleak_ignored.stderr b/tests/pass/threadleak_ignored.stderr index 9205eb70b2073..af327a3012c37 100644 --- a/tests/pass/threadleak_ignored.stderr +++ b/tests/pass/threadleak_ignored.stderr @@ -1,3 +1,4 @@ -warning: thread support is experimental: weak memory effects are not fully compatible with the Rust atomics memory model. +warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. + (see https://github.com/rust-lang/miri/issues/1388) Dropping 0 diff --git a/tests/run-pass/weak_memory/consistency.stderr b/tests/run-pass/weak_memory/consistency.stderr index 1d0ce4b3853da..9fe6daa778c1f 100644 --- a/tests/run-pass/weak_memory/consistency.stderr +++ b/tests/run-pass/weak_memory/consistency.stderr @@ -1,2 +1,3 @@ -warning: thread support is experimental: weak memory effects are not fully compatible with the Rust atomics memory model. +warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. + (see https://github.com/rust-lang/miri/issues/1388) diff --git a/tests/run-pass/weak_memory/extra_cpp.rs b/tests/run-pass/weak_memory/extra_cpp.rs index 3edac581c353c..750c628458b8a 100644 --- a/tests/run-pass/weak_memory/extra_cpp.rs +++ b/tests/run-pass/weak_memory/extra_cpp.rs @@ -1,3 +1,4 @@ +// ignore-windows: Concurrency on Windows is not supported yet. // compile-flags: -Zmiri-ignore-leaks // Tests operations not perfomable through C++'s atomic API diff --git a/tests/run-pass/weak_memory/extra_cpp.stderr b/tests/run-pass/weak_memory/extra_cpp.stderr index 1d0ce4b3853da..9fe6daa778c1f 100644 --- a/tests/run-pass/weak_memory/extra_cpp.stderr +++ b/tests/run-pass/weak_memory/extra_cpp.stderr @@ -1,2 +1,3 @@ -warning: thread support is experimental: weak memory effects are not fully compatible with the Rust atomics memory model. +warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. + (see https://github.com/rust-lang/miri/issues/1388) diff --git a/tests/run-pass/weak_memory/extra_cpp_unsafe.rs b/tests/run-pass/weak_memory/extra_cpp_unsafe.rs index 95cc97d4dbb27..7c375d7345f3a 100644 --- a/tests/run-pass/weak_memory/extra_cpp_unsafe.rs +++ b/tests/run-pass/weak_memory/extra_cpp_unsafe.rs @@ -1,3 +1,4 @@ +// ignore-windows: Concurrency on Windows is not supported yet. // compile-flags: -Zmiri-ignore-leaks // Tests operations not perfomable through C++'s atomic API diff --git a/tests/run-pass/weak_memory/extra_cpp_unsafe.stderr b/tests/run-pass/weak_memory/extra_cpp_unsafe.stderr index 1d0ce4b3853da..9fe6daa778c1f 100644 --- a/tests/run-pass/weak_memory/extra_cpp_unsafe.stderr +++ b/tests/run-pass/weak_memory/extra_cpp_unsafe.stderr @@ -1,2 +1,3 @@ -warning: thread support is experimental: weak memory effects are not fully compatible with the Rust atomics memory model. +warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. + (see https://github.com/rust-lang/miri/issues/1388) diff --git a/tests/run-pass/weak_memory/weak.stderr b/tests/run-pass/weak_memory/weak.stderr index 1d0ce4b3853da..9fe6daa778c1f 100644 --- a/tests/run-pass/weak_memory/weak.stderr +++ b/tests/run-pass/weak_memory/weak.stderr @@ -1,2 +1,3 @@ -warning: thread support is experimental: weak memory effects are not fully compatible with the Rust atomics memory model. +warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. + (see https://github.com/rust-lang/miri/issues/1388) From a7c832b04a2e11c39c58606182d2666b853c3602 Mon Sep 17 00:00:00 2001 From: Andy Wang Date: Sun, 29 May 2022 09:57:24 +0100 Subject: [PATCH 3206/3747] Wording improvements Co-authored-by: Ralf Jung --- src/concurrency/weak_memory.rs | 4 +++- src/machine.rs | 4 ++-- tests/compile-fail/weak_memory/racing_mixed_size.stderr | 4 ++-- tests/run-pass/weak_memory/extra_cpp_unsafe.rs | 2 +- 4 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/concurrency/weak_memory.rs b/src/concurrency/weak_memory.rs index 942d71a52ff28..888f9edceb329 100644 --- a/src/concurrency/weak_memory.rs +++ b/src/concurrency/weak_memory.rs @@ -417,7 +417,9 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>: && !alloc_clocks .read_race_free_with_atomic(range, this.machine.data_race.as_ref().unwrap()) { - throw_ub_format!("racy imperfectly overlapping atomic access"); + throw_ub_format!( + "racy imperfectly overlapping atomic access is not possible in the C++20 memory model" + ); } } Ok(()) diff --git a/src/machine.rs b/src/machine.rs index 6dc2a75b69fd7..b8cb890870049 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -743,8 +743,8 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { if let Some(weak_memory) = &alloc_extra.weak_memory { if !machine.data_race.as_ref().unwrap().ongoing_atomic_access() { // This is a non-atomic access. And if we are accessing a previously atomically - // accessed location without racing with them, then the location no longer needs - // to exhibit weak-memory behaviours until a fresh atomic access happens + // accessed location without racing with them, then the location no longer + // exhibits weak-memory behaviors until a fresh atomic access happens. weak_memory.destroy_atomicity(range); } } diff --git a/tests/compile-fail/weak_memory/racing_mixed_size.stderr b/tests/compile-fail/weak_memory/racing_mixed_size.stderr index b3074d93c9cb0..b03424a861c9a 100644 --- a/tests/compile-fail/weak_memory/racing_mixed_size.stderr +++ b/tests/compile-fail/weak_memory/racing_mixed_size.stderr @@ -1,11 +1,11 @@ warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. (see https://github.com/rust-lang/miri/issues/1388) -error: Undefined Behavior: racy imperfectly overlapping atomic access +error: Undefined Behavior: racy imperfectly overlapping atomic access is not possible in the C++20 memory model --> $DIR/racing_mixed_size.rs:LL:CC | LL | std::intrinsics::atomic_load_relaxed(hi); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ racy imperfectly overlapping atomic access + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ racy imperfectly overlapping atomic access is not possible in the C++20 memory model | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/run-pass/weak_memory/extra_cpp_unsafe.rs b/tests/run-pass/weak_memory/extra_cpp_unsafe.rs index 7c375d7345f3a..de9a3af3fd3ee 100644 --- a/tests/run-pass/weak_memory/extra_cpp_unsafe.rs +++ b/tests/run-pass/weak_memory/extra_cpp_unsafe.rs @@ -62,7 +62,7 @@ fn racing_mixed_size_read() { j2.join().unwrap(); } -// And the combination of both of above +// And we allow the combination of both of the above. fn racing_mixed_atomicity_and_size_read() { let x = static_atomic(u32::from_be(0xabbafafa)); From ceb173d64773736e0c60ba6104912c725f07c2c9 Mon Sep 17 00:00:00 2001 From: Andy Wang Date: Sun, 29 May 2022 12:03:45 +0100 Subject: [PATCH 3207/3747] Move logic out of machine.rs --- src/concurrency/weak_memory.rs | 28 +++++++++++++++------------- src/machine.rs | 11 ++--------- 2 files changed, 17 insertions(+), 22 deletions(-) diff --git a/src/concurrency/weak_memory.rs b/src/concurrency/weak_memory.rs index 888f9edceb329..3c692783d145b 100644 --- a/src/concurrency/weak_memory.rs +++ b/src/concurrency/weak_memory.rs @@ -135,20 +135,22 @@ impl StoreBufferAlloc { /// When a non-atomic access happens on a location that has been atomically accessed /// before without data race, we can determine that the non-atomic access fully happens - /// before all the prior atomic accesses so the location no longer needs to exhibit + /// after all the prior atomic accesses so the location no longer needs to exhibit /// any weak memory behaviours until further atomic accesses. - pub fn destroy_atomicity<'tcx>(&self, range: AllocRange) { - let mut buffers = self.store_buffers.borrow_mut(); - let access_type = buffers.access_type(range); - match access_type { - AccessType::PerfectlyOverlapping(pos) => { - buffers.remove_from_pos(pos); - } - AccessType::ImperfectlyOverlapping(pos_range) => { - buffers.remove_pos_range(pos_range); - } - AccessType::Empty(_) => { - // Do nothing + pub fn memory_accessed<'tcx>(&self, range: AllocRange, global: &GlobalState) { + if !global.ongoing_atomic_access() { + let mut buffers = self.store_buffers.borrow_mut(); + let access_type = buffers.access_type(range); + match access_type { + AccessType::PerfectlyOverlapping(pos) => { + buffers.remove_from_pos(pos); + } + AccessType::ImperfectlyOverlapping(pos_range) => { + buffers.remove_pos_range(pos_range); + } + AccessType::Empty(_) => { + // The range had no weak behaivours attached, do nothing + } } } } diff --git a/src/machine.rs b/src/machine.rs index b8cb890870049..5ee2d9a9abd41 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -741,12 +741,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { )?; } if let Some(weak_memory) = &alloc_extra.weak_memory { - if !machine.data_race.as_ref().unwrap().ongoing_atomic_access() { - // This is a non-atomic access. And if we are accessing a previously atomically - // accessed location without racing with them, then the location no longer - // exhibits weak-memory behaviors until a fresh atomic access happens. - weak_memory.destroy_atomicity(range); - } + weak_memory.memory_accessed(range, machine.data_race.as_ref().unwrap()); } Ok(()) } @@ -772,9 +767,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { )?; } if let Some(weak_memory) = &alloc_extra.weak_memory { - if !machine.data_race.as_ref().unwrap().ongoing_atomic_access() { - weak_memory.destroy_atomicity(range); - } + weak_memory.memory_accessed(range, machine.data_race.as_ref().unwrap()); } Ok(()) } From 4a07f78dadd3e5608157486b204fd4be2cde15a7 Mon Sep 17 00:00:00 2001 From: Andy Wang Date: Sun, 29 May 2022 15:05:07 +0100 Subject: [PATCH 3208/3747] Forbade all racing mixed size atomic accesses --- src/concurrency/data_race.rs | 52 +++++------------ src/concurrency/weak_memory.rs | 41 +++----------- .../weak_memory/racing_mixed_size.rs | 1 - .../weak_memory/racing_mixed_size_read.rs | 39 +++++++++++++ .../weak_memory/racing_mixed_size_read.stderr | 18 ++++++ .../run-pass/weak_memory/extra_cpp_unsafe.rs | 56 ------------------- 6 files changed, 78 insertions(+), 129 deletions(-) create mode 100644 tests/compile-fail/weak_memory/racing_mixed_size_read.rs create mode 100644 tests/compile-fail/weak_memory/racing_mixed_size_read.stderr diff --git a/src/concurrency/data_race.rs b/src/concurrency/data_race.rs index 8b8694ac18352..61cd6a3c0c0d2 100644 --- a/src/concurrency/data_race.rs +++ b/src/concurrency/data_race.rs @@ -287,8 +287,8 @@ impl MemoryCellClocks { Ok(()) } - /// Checks if the memory cell write races with any prior atomic read or write - fn write_race_free_with_atomic(&mut self, clocks: &ThreadClockSet) -> bool { + /// Checks if the memory cell access is ordered with all prior atomic reads and writes + fn race_free_with_atomic(&self, clocks: &ThreadClockSet) -> bool { if let Some(atomic) = self.atomic() { atomic.read_vector <= clocks.clock && atomic.write_vector <= clocks.clock } else { @@ -296,11 +296,6 @@ impl MemoryCellClocks { } } - /// Checks if the memory cell read races with any prior atomic write - fn read_race_free_with_atomic(&self, clocks: &ThreadClockSet) -> bool { - if let Some(atomic) = self.atomic() { atomic.write_vector <= clocks.clock } else { true } - } - /// Update memory cell data-race tracking for atomic /// load relaxed semantics, is a no-op if this memory was /// not used previously as atomic memory. @@ -528,7 +523,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { // the *value* (including the associated provenance if this is an AtomicPtr) at this location. // Only metadata on the location itself is used. let scalar = this.allow_data_races_ref(move |this| this.read_scalar(&place.into()))?; - this.validate_overlapping_atomic_read(place)?; + this.validate_overlapping_atomic(place)?; this.buffered_atomic_read(place, atomic, scalar, || { this.validate_atomic_load(place, atomic) }) @@ -542,7 +537,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { atomic: AtomicWriteOp, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - this.validate_overlapping_atomic_write(dest)?; + this.validate_overlapping_atomic(dest)?; this.allow_data_races_mut(move |this| this.write_scalar(val, &(*dest).into()))?; this.validate_atomic_store(dest, atomic)?; // FIXME: it's not possible to get the value before write_scalar. A read_scalar will cause @@ -563,7 +558,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { ) -> InterpResult<'tcx, ImmTy<'tcx, Tag>> { let this = self.eval_context_mut(); - this.validate_overlapping_atomic_write(place)?; + this.validate_overlapping_atomic(place)?; let old = this.allow_data_races_mut(|this| this.read_immediate(&place.into()))?; // Atomics wrap around on overflow. @@ -592,7 +587,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { ) -> InterpResult<'tcx, ScalarMaybeUninit> { let this = self.eval_context_mut(); - this.validate_overlapping_atomic_write(place)?; + this.validate_overlapping_atomic(place)?; let old = this.allow_data_races_mut(|this| this.read_scalar(&place.into()))?; this.allow_data_races_mut(|this| this.write_scalar(new, &(*place).into()))?; @@ -613,7 +608,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { ) -> InterpResult<'tcx, ImmTy<'tcx, Tag>> { let this = self.eval_context_mut(); - this.validate_overlapping_atomic_write(place)?; + this.validate_overlapping_atomic(place)?; let old = this.allow_data_races_mut(|this| this.read_immediate(&place.into()))?; let lt = this.binary_op(mir::BinOp::Lt, &old, &rhs)?.to_scalar()?.to_bool()?; @@ -656,7 +651,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { use rand::Rng as _; let this = self.eval_context_mut(); - this.validate_overlapping_atomic_write(place)?; + this.validate_overlapping_atomic(place)?; // Failure ordering cannot be stronger than success ordering, therefore first attempt // to read with the failure ordering and if successful then try again with the success // read ordering and write in the success case. @@ -706,7 +701,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { atomic: AtomicReadOp, ) -> InterpResult<'tcx> { let this = self.eval_context_ref(); - this.validate_overlapping_atomic_read(place)?; + this.validate_overlapping_atomic(place)?; this.validate_atomic_op( place, atomic, @@ -729,7 +724,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { atomic: AtomicWriteOp, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - this.validate_overlapping_atomic_write(place)?; + this.validate_overlapping_atomic(place)?; this.validate_atomic_op( place, atomic, @@ -755,7 +750,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { let acquire = matches!(atomic, Acquire | AcqRel | SeqCst); let release = matches!(atomic, Release | AcqRel | SeqCst); let this = self.eval_context_mut(); - this.validate_overlapping_atomic_write(place)?; + this.validate_overlapping_atomic(place)?; this.validate_atomic_op(place, atomic, "Atomic RMW", move |memory, clocks, index, _| { if acquire { memory.load_acquire(clocks, index)?; @@ -941,9 +936,9 @@ impl VClockAlloc { ) } - /// Detect racing atomic writes (not data races) + /// Detect racing atomic read and writes (not data races) /// on every byte of the current access range - pub(super) fn read_race_free_with_atomic<'tcx>( + pub(super) fn race_free_with_atomic<'tcx>( &self, range: AllocRange, global: &GlobalState, @@ -952,26 +947,7 @@ impl VClockAlloc { let (_, clocks) = global.current_thread_state(); let alloc_ranges = self.alloc_ranges.borrow(); for (_, range) in alloc_ranges.iter(range.start, range.size) { - if !range.read_race_free_with_atomic(&clocks) { - return false; - } - } - } - true - } - - /// Detect racing atomic read and writes (not data races) - /// on every byte of the current access range - pub(super) fn write_race_free_with_atomic<'tcx>( - &mut self, - range: AllocRange, - global: &GlobalState, - ) -> bool { - if global.race_detecting() { - let (_, clocks) = global.current_thread_state(); - let alloc_ranges = self.alloc_ranges.get_mut(); - for (_, range) in alloc_ranges.iter_mut(range.start, range.size) { - if !range.write_race_free_with_atomic(&clocks) { + if !range.race_free_with_atomic(&clocks) { return false; } } diff --git a/src/concurrency/weak_memory.rs b/src/concurrency/weak_memory.rs index 3c692783d145b..9bf46bb23b0bd 100644 --- a/src/concurrency/weak_memory.rs +++ b/src/concurrency/weak_memory.rs @@ -35,7 +35,8 @@ //! (such as accessing the top 16 bits of an AtomicU32). These senarios are generally undiscussed in formalisations of C++ memory model. //! In Rust, these operations can only be done through a `&mut AtomicFoo` reference or one derived from it, therefore these operations //! can only happen after all previous accesses on the same locations. This implementation is adapted to allow these operations. -//! A mixed size/atomicity read that races with writes, or a write that races with reads or writes will still cause UBs to be thrown. +//! A mixed atomicity read that races with writes, or a write that races with reads or writes will still cause UBs to be thrown. +//! Mixed size atomic accesses must not race with any other atomic access, whether read or write, or a UB will be thrown. //! You can refer to test cases in weak_memory/extra_cpp.rs and weak_memory/extra_cpp_unsafe.rs for examples of these operations. // Our and the author's own implementation (tsan11) of the paper have some deviations from the provided operational semantics in §5.3: @@ -403,9 +404,9 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { // If weak memory emulation is enabled, check if this atomic op imperfectly overlaps with a previous - // atomic write. If it does, then we require it to be ordered (non-racy) with all previous atomic - // writes on all the bytes in range - fn validate_overlapping_atomic_read(&self, place: &MPlaceTy<'tcx, Tag>) -> InterpResult<'tcx> { + // atomic read or write. If it does, then we require it to be ordered (non-racy) with all previous atomic + // accesses on all the bytes in range + fn validate_overlapping_atomic(&self, place: &MPlaceTy<'tcx, Tag>) -> InterpResult<'tcx> { let this = self.eval_context_ref(); let (alloc_id, base_offset, ..) = this.ptr_get_alloc_id(place.ptr)?; if let crate::AllocExtra { @@ -417,37 +418,9 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>: let range = alloc_range(base_offset, place.layout.size); if alloc_buffers.is_overlapping(range) && !alloc_clocks - .read_race_free_with_atomic(range, this.machine.data_race.as_ref().unwrap()) + .race_free_with_atomic(range, this.machine.data_race.as_ref().unwrap()) { - throw_ub_format!( - "racy imperfectly overlapping atomic access is not possible in the C++20 memory model" - ); - } - } - Ok(()) - } - - // Same as above but needs to be ordered with all previous atomic read or writes - fn validate_overlapping_atomic_write( - &mut self, - place: &MPlaceTy<'tcx, Tag>, - ) -> InterpResult<'tcx> { - let this = self.eval_context_mut(); - let (alloc_id, base_offset, ..) = this.ptr_get_alloc_id(place.ptr)?; - if let ( - crate::AllocExtra { - weak_memory: Some(alloc_buffers), - data_race: Some(alloc_clocks), - .. - }, - crate::Evaluator { data_race: Some(global), .. }, - ) = this.get_alloc_extra_mut(alloc_id)? - { - let range = alloc_range(base_offset, place.layout.size); - if alloc_buffers.is_overlapping(range) - && !alloc_clocks.write_race_free_with_atomic(range, global) - { - throw_ub_format!("racy imperfectly overlapping atomic access"); + throw_ub_format!("racy imperfectly overlapping atomic access is not possible in the C++20 memory model"); } } Ok(()) diff --git a/tests/compile-fail/weak_memory/racing_mixed_size.rs b/tests/compile-fail/weak_memory/racing_mixed_size.rs index 513d97edb51cf..6d53670a4e92e 100644 --- a/tests/compile-fail/weak_memory/racing_mixed_size.rs +++ b/tests/compile-fail/weak_memory/racing_mixed_size.rs @@ -1,5 +1,4 @@ // ignore-windows: Concurrency on Windows is not supported yet. -// compile-flags: -Zmiri-ignore-leaks #![feature(core_intrinsics)] diff --git a/tests/compile-fail/weak_memory/racing_mixed_size_read.rs b/tests/compile-fail/weak_memory/racing_mixed_size_read.rs new file mode 100644 index 0000000000000..0129b55aff618 --- /dev/null +++ b/tests/compile-fail/weak_memory/racing_mixed_size_read.rs @@ -0,0 +1,39 @@ +// ignore-windows: Concurrency on Windows is not supported yet. + +#![feature(core_intrinsics)] + +use std::sync::atomic::AtomicU32; +use std::sync::atomic::Ordering::*; +use std::thread::spawn; + +fn static_atomic(val: u32) -> &'static AtomicU32 { + let ret = Box::leak(Box::new(AtomicU32::new(val))); + ret +} + +fn split_u32_ptr(dword: *const u32) -> *const [u16; 2] { + unsafe { std::mem::transmute::<*const u32, *const [u16; 2]>(dword) } +} + +// Racing mixed size reads may cause two loads to read-from +// the same store but observe different values, which doesn't make +// sense under the formal model so we forbade this. +pub fn main() { + let x = static_atomic(0); + + let j1 = spawn(move || { + x.load(Relaxed); + }); + + let j2 = spawn(move || { + let x_ptr = x as *const AtomicU32 as *const u32; + let x_split = split_u32_ptr(x_ptr); + unsafe { + let hi = &(*x_split)[0] as *const u16; + std::intrinsics::atomic_load_relaxed(hi); //~ ERROR: imperfectly overlapping + } + }); + + j1.join().unwrap(); + j2.join().unwrap(); +} diff --git a/tests/compile-fail/weak_memory/racing_mixed_size_read.stderr b/tests/compile-fail/weak_memory/racing_mixed_size_read.stderr new file mode 100644 index 0000000000000..80cc2fe756bf2 --- /dev/null +++ b/tests/compile-fail/weak_memory/racing_mixed_size_read.stderr @@ -0,0 +1,18 @@ +warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. + (see https://github.com/rust-lang/miri/issues/1388) + +error: Undefined Behavior: racy imperfectly overlapping atomic access is not possible in the C++20 memory model + --> $DIR/racing_mixed_size_read.rs:LL:CC + | +LL | std::intrinsics::atomic_load_relaxed(hi); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ racy imperfectly overlapping atomic access is not possible in the C++20 memory model + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside closure at $DIR/racing_mixed_size_read.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error; 1 warning emitted + diff --git a/tests/run-pass/weak_memory/extra_cpp_unsafe.rs b/tests/run-pass/weak_memory/extra_cpp_unsafe.rs index de9a3af3fd3ee..478e436e59d1d 100644 --- a/tests/run-pass/weak_memory/extra_cpp_unsafe.rs +++ b/tests/run-pass/weak_memory/extra_cpp_unsafe.rs @@ -18,10 +18,6 @@ fn static_atomic(val: u32) -> &'static AtomicU32 { ret } -fn split_u32_ptr(dword: *const u32) -> *const [u16; 2] { - unsafe { std::mem::transmute::<*const u32, *const [u16; 2]>(dword) } -} - // We allow non-atomic and atomic reads to race fn racing_mixed_atomicity_read() { let x = static_atomic(0); @@ -41,58 +37,6 @@ fn racing_mixed_atomicity_read() { assert_eq!(r2, 42); } -// We allow mixed-size atomic reads to race -fn racing_mixed_size_read() { - let x = static_atomic(0); - - let j1 = spawn(move || { - x.load(Relaxed); - }); - - let j2 = spawn(move || { - let x_ptr = x as *const AtomicU32 as *const u32; - let x_split = split_u32_ptr(x_ptr); - unsafe { - let hi = &(*x_split)[0] as *const u16; - std::intrinsics::atomic_load_relaxed(hi); - } - }); - - j1.join().unwrap(); - j2.join().unwrap(); -} - -// And we allow the combination of both of the above. -fn racing_mixed_atomicity_and_size_read() { - let x = static_atomic(u32::from_be(0xabbafafa)); - - let j1 = spawn(move || { - x.load(Relaxed); - }); - - let j2 = spawn(move || { - let x_ptr = x as *const AtomicU32 as *const u32; - unsafe { *x_ptr }; - }); - - let j3 = spawn(move || { - let x_ptr = x as *const AtomicU32 as *const u32; - let x_split = split_u32_ptr(x_ptr); - unsafe { - let hi = &(*x_split)[0] as *const u16; - std::intrinsics::atomic_load_relaxed(hi) - } - }); - - j1.join().unwrap(); - j2.join().unwrap(); - let r3 = j3.join().unwrap(); - - assert_eq!(r3, u16::from_be(0xabba)); -} - pub fn main() { racing_mixed_atomicity_read(); - racing_mixed_size_read(); - racing_mixed_atomicity_and_size_read(); } From 8215702d5a27c77197cf8d12e03caca6c3884783 Mon Sep 17 00:00:00 2001 From: Andy Wang Date: Sun, 29 May 2022 19:48:36 +0100 Subject: [PATCH 3209/3747] Refer to GitHub issue on overwritten init value --- src/concurrency/data_race.rs | 1 + src/concurrency/weak_memory.rs | 1 + src/machine.rs | 2 -- tests/compile-fail/weak_memory/cpp20_rwc_syncs.rs | 1 + 4 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/concurrency/data_race.rs b/src/concurrency/data_race.rs index 61cd6a3c0c0d2..35baf97b72763 100644 --- a/src/concurrency/data_race.rs +++ b/src/concurrency/data_race.rs @@ -544,6 +544,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { // side effects from a read the program did not perform. So we have to initialise // the store buffer with the value currently being written // ONCE this is fixed please remove the hack in buffered_atomic_write() in weak_memory.rs + // https://github.com/rust-lang/miri/issues/2164 this.buffered_atomic_write(val, dest, atomic, val) } diff --git a/src/concurrency/weak_memory.rs b/src/concurrency/weak_memory.rs index 9bf46bb23b0bd..237a13ea86465 100644 --- a/src/concurrency/weak_memory.rs +++ b/src/concurrency/weak_memory.rs @@ -508,6 +508,7 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>: // UGLY HACK: in write_scalar_atomic() we don't know the value before our write, // so init == val always. If the buffer is fresh then we would've duplicated an entry, // so we need to remove it. + // See https://github.com/rust-lang/miri/issues/2164 let was_empty = matches!( alloc_buffers .store_buffers diff --git a/src/machine.rs b/src/machine.rs index 5ee2d9a9abd41..1ae49edd6001a 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -638,8 +638,6 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { None }; let buffer_alloc = if ecx.machine.weak_memory { - // FIXME: if this is an atomic obejct, we want to supply its initial value - // while allocating the store buffer here. Some(weak_memory::AllocExtra::new_allocation()) } else { None diff --git a/tests/compile-fail/weak_memory/cpp20_rwc_syncs.rs b/tests/compile-fail/weak_memory/cpp20_rwc_syncs.rs index 7dad0a12e5ddc..7fe24d6383462 100644 --- a/tests/compile-fail/weak_memory/cpp20_rwc_syncs.rs +++ b/tests/compile-fail/weak_memory/cpp20_rwc_syncs.rs @@ -25,6 +25,7 @@ fn reads_value(loc: &AtomicUsize, val: usize) -> usize { fn static_atomic(val: usize) -> &'static AtomicUsize { let ret = Box::leak(Box::new(AtomicUsize::new(val))); // A workaround to put the initialization value in the store buffer. + // See https://github.com/rust-lang/miri/issues/2164 ret.load(Relaxed); ret } From c73107164089249477d56fbc580104231459a2a6 Mon Sep 17 00:00:00 2001 From: Andy Wang Date: Sun, 29 May 2022 21:10:36 +0100 Subject: [PATCH 3210/3747] Give flag temp disabling race detector a better name --- src/concurrency/data_race.rs | 25 +++++++++++++------------ src/concurrency/weak_memory.rs | 6 ++++-- 2 files changed, 17 insertions(+), 14 deletions(-) diff --git a/src/concurrency/data_race.rs b/src/concurrency/data_race.rs index 35baf97b72763..f6f0ce528edb3 100644 --- a/src/concurrency/data_race.rs +++ b/src/concurrency/data_race.rs @@ -455,11 +455,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { fn allow_data_races_ref(&self, op: impl FnOnce(&MiriEvalContext<'mir, 'tcx>) -> R) -> R { let this = self.eval_context_ref(); if let Some(data_race) = &this.machine.data_race { - data_race.ongoing_atomic_access.set(true); + data_race.ongoing_action_data_race_free.set(true); } let result = op(this); if let Some(data_race) = &this.machine.data_race { - data_race.ongoing_atomic_access.set(false); + data_race.ongoing_action_data_race_free.set(false); } result } @@ -474,11 +474,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { ) -> R { let this = self.eval_context_mut(); if let Some(data_race) = &this.machine.data_race { - data_race.ongoing_atomic_access.set(true); + data_race.ongoing_action_data_race_free.set(true); } let result = op(this); if let Some(data_race) = &this.machine.data_race { - data_race.ongoing_atomic_access.set(false); + data_race.ongoing_action_data_race_free.set(false); } result } @@ -1151,8 +1151,9 @@ pub struct GlobalState { multi_threaded: Cell, /// A flag to mark we are currently performing - /// an atomic access to supress data race detection - ongoing_atomic_access: Cell, + /// a data race free action (such as atomic access) + /// to supress the race detector + ongoing_action_data_race_free: Cell, /// Mapping of a vector index to a known set of thread /// clocks, this is not directly mapping from a thread id @@ -1205,7 +1206,7 @@ impl GlobalState { pub fn new() -> Self { let mut global_state = GlobalState { multi_threaded: Cell::new(false), - ongoing_atomic_access: Cell::new(false), + ongoing_action_data_race_free: Cell::new(false), vector_clocks: RefCell::new(IndexVec::new()), vector_info: RefCell::new(IndexVec::new()), thread_info: RefCell::new(IndexVec::new()), @@ -1232,14 +1233,14 @@ impl GlobalState { } // We perform data race detection when there are more than 1 active thread - // and we are not currently in the middle of an atomic acces where data race - // is impossible + // and we have not temporarily disabled race detection to perform something + // data race free fn race_detecting(&self) -> bool { - self.multi_threaded.get() && !self.ongoing_atomic_access.get() + self.multi_threaded.get() && !self.ongoing_action_data_race_free.get() } - pub fn ongoing_atomic_access(&self) -> bool { - self.ongoing_atomic_access.get() + pub fn ongoing_action_data_race_free(&self) -> bool { + self.ongoing_action_data_race_free.get() } // Try to find vector index values that can potentially be re-used diff --git a/src/concurrency/weak_memory.rs b/src/concurrency/weak_memory.rs index 237a13ea86465..dc32a3ddca41f 100644 --- a/src/concurrency/weak_memory.rs +++ b/src/concurrency/weak_memory.rs @@ -139,7 +139,7 @@ impl StoreBufferAlloc { /// after all the prior atomic accesses so the location no longer needs to exhibit /// any weak memory behaviours until further atomic accesses. pub fn memory_accessed<'tcx>(&self, range: AllocRange, global: &GlobalState) { - if !global.ongoing_atomic_access() { + if !global.ongoing_action_data_race_free() { let mut buffers = self.store_buffers.borrow_mut(); let access_type = buffers.access_type(range); match access_type { @@ -420,7 +420,9 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>: && !alloc_clocks .race_free_with_atomic(range, this.machine.data_race.as_ref().unwrap()) { - throw_ub_format!("racy imperfectly overlapping atomic access is not possible in the C++20 memory model"); + throw_ub_format!( + "racy imperfectly overlapping atomic access is not possible in the C++20 memory model" + ); } } Ok(()) From 6d0c76ea1b5021ec526421825a4c62b467c5b1e2 Mon Sep 17 00:00:00 2001 From: Andy Wang Date: Sun, 29 May 2022 22:53:57 +0100 Subject: [PATCH 3211/3747] Specify only perfectly overlapping accesses can race --- tests/run-pass/weak_memory/extra_cpp_unsafe.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/run-pass/weak_memory/extra_cpp_unsafe.rs b/tests/run-pass/weak_memory/extra_cpp_unsafe.rs index 478e436e59d1d..d77a090e6e43f 100644 --- a/tests/run-pass/weak_memory/extra_cpp_unsafe.rs +++ b/tests/run-pass/weak_memory/extra_cpp_unsafe.rs @@ -18,7 +18,7 @@ fn static_atomic(val: u32) -> &'static AtomicU32 { ret } -// We allow non-atomic and atomic reads to race +// We allow perfectly overlapping non-atomic and atomic reads to race fn racing_mixed_atomicity_read() { let x = static_atomic(0); x.store(42, Relaxed); From 65f39bd5cf708c5d934ccb6d20efa7b9e54bab2a Mon Sep 17 00:00:00 2001 From: Andy Wang Date: Sat, 4 Jun 2022 18:18:46 +0100 Subject: [PATCH 3212/3747] Move tests to new directories --- tests/{compile-fail => fail}/weak_memory/cpp20_rwc_syncs.rs | 0 tests/{compile-fail => fail}/weak_memory/cpp20_rwc_syncs.stderr | 0 tests/{compile-fail => fail}/weak_memory/racing_mixed_size.rs | 0 tests/{compile-fail => fail}/weak_memory/racing_mixed_size.stderr | 0 .../{compile-fail => fail}/weak_memory/racing_mixed_size_read.rs | 0 .../weak_memory/racing_mixed_size_read.stderr | 0 tests/{run-pass => pass}/weak_memory/consistency.rs | 0 tests/{run-pass => pass}/weak_memory/consistency.stderr | 0 tests/{run-pass => pass}/weak_memory/extra_cpp.rs | 0 tests/{run-pass => pass}/weak_memory/extra_cpp.stderr | 0 tests/{run-pass => pass}/weak_memory/extra_cpp_unsafe.rs | 0 tests/{run-pass => pass}/weak_memory/extra_cpp_unsafe.stderr | 0 tests/{run-pass => pass}/weak_memory/weak.rs | 0 tests/{run-pass => pass}/weak_memory/weak.stderr | 0 14 files changed, 0 insertions(+), 0 deletions(-) rename tests/{compile-fail => fail}/weak_memory/cpp20_rwc_syncs.rs (100%) rename tests/{compile-fail => fail}/weak_memory/cpp20_rwc_syncs.stderr (100%) rename tests/{compile-fail => fail}/weak_memory/racing_mixed_size.rs (100%) rename tests/{compile-fail => fail}/weak_memory/racing_mixed_size.stderr (100%) rename tests/{compile-fail => fail}/weak_memory/racing_mixed_size_read.rs (100%) rename tests/{compile-fail => fail}/weak_memory/racing_mixed_size_read.stderr (100%) rename tests/{run-pass => pass}/weak_memory/consistency.rs (100%) rename tests/{run-pass => pass}/weak_memory/consistency.stderr (100%) rename tests/{run-pass => pass}/weak_memory/extra_cpp.rs (100%) rename tests/{run-pass => pass}/weak_memory/extra_cpp.stderr (100%) rename tests/{run-pass => pass}/weak_memory/extra_cpp_unsafe.rs (100%) rename tests/{run-pass => pass}/weak_memory/extra_cpp_unsafe.stderr (100%) rename tests/{run-pass => pass}/weak_memory/weak.rs (100%) rename tests/{run-pass => pass}/weak_memory/weak.stderr (100%) diff --git a/tests/compile-fail/weak_memory/cpp20_rwc_syncs.rs b/tests/fail/weak_memory/cpp20_rwc_syncs.rs similarity index 100% rename from tests/compile-fail/weak_memory/cpp20_rwc_syncs.rs rename to tests/fail/weak_memory/cpp20_rwc_syncs.rs diff --git a/tests/compile-fail/weak_memory/cpp20_rwc_syncs.stderr b/tests/fail/weak_memory/cpp20_rwc_syncs.stderr similarity index 100% rename from tests/compile-fail/weak_memory/cpp20_rwc_syncs.stderr rename to tests/fail/weak_memory/cpp20_rwc_syncs.stderr diff --git a/tests/compile-fail/weak_memory/racing_mixed_size.rs b/tests/fail/weak_memory/racing_mixed_size.rs similarity index 100% rename from tests/compile-fail/weak_memory/racing_mixed_size.rs rename to tests/fail/weak_memory/racing_mixed_size.rs diff --git a/tests/compile-fail/weak_memory/racing_mixed_size.stderr b/tests/fail/weak_memory/racing_mixed_size.stderr similarity index 100% rename from tests/compile-fail/weak_memory/racing_mixed_size.stderr rename to tests/fail/weak_memory/racing_mixed_size.stderr diff --git a/tests/compile-fail/weak_memory/racing_mixed_size_read.rs b/tests/fail/weak_memory/racing_mixed_size_read.rs similarity index 100% rename from tests/compile-fail/weak_memory/racing_mixed_size_read.rs rename to tests/fail/weak_memory/racing_mixed_size_read.rs diff --git a/tests/compile-fail/weak_memory/racing_mixed_size_read.stderr b/tests/fail/weak_memory/racing_mixed_size_read.stderr similarity index 100% rename from tests/compile-fail/weak_memory/racing_mixed_size_read.stderr rename to tests/fail/weak_memory/racing_mixed_size_read.stderr diff --git a/tests/run-pass/weak_memory/consistency.rs b/tests/pass/weak_memory/consistency.rs similarity index 100% rename from tests/run-pass/weak_memory/consistency.rs rename to tests/pass/weak_memory/consistency.rs diff --git a/tests/run-pass/weak_memory/consistency.stderr b/tests/pass/weak_memory/consistency.stderr similarity index 100% rename from tests/run-pass/weak_memory/consistency.stderr rename to tests/pass/weak_memory/consistency.stderr diff --git a/tests/run-pass/weak_memory/extra_cpp.rs b/tests/pass/weak_memory/extra_cpp.rs similarity index 100% rename from tests/run-pass/weak_memory/extra_cpp.rs rename to tests/pass/weak_memory/extra_cpp.rs diff --git a/tests/run-pass/weak_memory/extra_cpp.stderr b/tests/pass/weak_memory/extra_cpp.stderr similarity index 100% rename from tests/run-pass/weak_memory/extra_cpp.stderr rename to tests/pass/weak_memory/extra_cpp.stderr diff --git a/tests/run-pass/weak_memory/extra_cpp_unsafe.rs b/tests/pass/weak_memory/extra_cpp_unsafe.rs similarity index 100% rename from tests/run-pass/weak_memory/extra_cpp_unsafe.rs rename to tests/pass/weak_memory/extra_cpp_unsafe.rs diff --git a/tests/run-pass/weak_memory/extra_cpp_unsafe.stderr b/tests/pass/weak_memory/extra_cpp_unsafe.stderr similarity index 100% rename from tests/run-pass/weak_memory/extra_cpp_unsafe.stderr rename to tests/pass/weak_memory/extra_cpp_unsafe.stderr diff --git a/tests/run-pass/weak_memory/weak.rs b/tests/pass/weak_memory/weak.rs similarity index 100% rename from tests/run-pass/weak_memory/weak.rs rename to tests/pass/weak_memory/weak.rs diff --git a/tests/run-pass/weak_memory/weak.stderr b/tests/pass/weak_memory/weak.stderr similarity index 100% rename from tests/run-pass/weak_memory/weak.stderr rename to tests/pass/weak_memory/weak.stderr From 137903671305d30ede80586388cd4db535aa92be Mon Sep 17 00:00:00 2001 From: Andy Wang Date: Sun, 5 Jun 2022 10:37:40 +0100 Subject: [PATCH 3213/3747] Simplify known C++20 inconsistency test --- .../cpp20_rwc_syncs.rs | 11 +++++---- tests/fail/should-pass/cpp20_rwc_syncs.stderr | 3 +++ tests/fail/weak_memory/cpp20_rwc_syncs.stderr | 23 ------------------- 3 files changed, 9 insertions(+), 28 deletions(-) rename tests/fail/{weak_memory => should-pass}/cpp20_rwc_syncs.rs (83%) create mode 100644 tests/fail/should-pass/cpp20_rwc_syncs.stderr delete mode 100644 tests/fail/weak_memory/cpp20_rwc_syncs.stderr diff --git a/tests/fail/weak_memory/cpp20_rwc_syncs.rs b/tests/fail/should-pass/cpp20_rwc_syncs.rs similarity index 83% rename from tests/fail/weak_memory/cpp20_rwc_syncs.rs rename to tests/fail/should-pass/cpp20_rwc_syncs.rs index 7fe24d6383462..e5192cd0d6706 100644 --- a/tests/fail/weak_memory/cpp20_rwc_syncs.rs +++ b/tests/fail/should-pass/cpp20_rwc_syncs.rs @@ -1,5 +1,6 @@ // ignore-windows: Concurrency on Windows is not supported yet. // compile-flags: -Zmiri-ignore-leaks +// error-pattern: // https://plv.mpi-sws.org/scfix/paper.pdf // 2.2 Second Problem: SC Fences are Too Weak @@ -70,12 +71,12 @@ fn test_cpp20_rwc_syncs() { let b = j2.join().unwrap(); let c = j3.join().unwrap(); + // We cannot write assert_ne!() since ui_test's fail + // tests expect exit status 1, whereas panics produce 101. + // Our ui_test does not yet support overriding failure status codes. if (b, c) == (0, 0) { - // FIXME: the standalone compiletest-rs needs to support - // failure-status header to allow us to write assert_ne!((b, c), (0, 0)) - // https://rustc-dev-guide.rust-lang.org/tests/headers.html#miscellaneous-headers - // because panic exits with 101 but compile-rs expects 1 - let _ = unsafe { std::mem::MaybeUninit::<*const u32>::uninit().assume_init() }; //~ ERROR uninitialized + // This *should* be unreachable, but Miri will reach it. + std::process::exit(1); } } diff --git a/tests/fail/should-pass/cpp20_rwc_syncs.stderr b/tests/fail/should-pass/cpp20_rwc_syncs.stderr new file mode 100644 index 0000000000000..9fe6daa778c1f --- /dev/null +++ b/tests/fail/should-pass/cpp20_rwc_syncs.stderr @@ -0,0 +1,3 @@ +warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. + (see https://github.com/rust-lang/miri/issues/1388) + diff --git a/tests/fail/weak_memory/cpp20_rwc_syncs.stderr b/tests/fail/weak_memory/cpp20_rwc_syncs.stderr deleted file mode 100644 index f4f467120e8a4..0000000000000 --- a/tests/fail/weak_memory/cpp20_rwc_syncs.stderr +++ /dev/null @@ -1,23 +0,0 @@ -warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. - (see https://github.com/rust-lang/miri/issues/1388) - -error: Undefined Behavior: type validation failed at .value: encountered uninitialized raw pointer - --> $DIR/cpp20_rwc_syncs.rs:LL:CC - | -LL | let _ = unsafe { std::mem::MaybeUninit::<*const u32>::uninit().assume_init() }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .value: encountered uninitialized raw pointer - | - = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior - = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - - = note: inside `test_cpp20_rwc_syncs` at $DIR/cpp20_rwc_syncs.rs:LL:CC -note: inside `main` at $DIR/cpp20_rwc_syncs.rs:LL:CC - --> $DIR/cpp20_rwc_syncs.rs:LL:CC - | -LL | test_cpp20_rwc_syncs(); - | ^^^^^^^^^^^^^^^^^^^^^^ - -note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace - -error: aborting due to previous error; 1 warning emitted - From 6fb7c131ed48d33b8290ce2bf970c37fd9781828 Mon Sep 17 00:00:00 2001 From: Andy Wang Date: Sun, 5 Jun 2022 20:47:01 +0100 Subject: [PATCH 3214/3747] Remove unused lifetimes --- src/concurrency/data_race.rs | 6 +----- src/concurrency/weak_memory.rs | 2 +- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/src/concurrency/data_race.rs b/src/concurrency/data_race.rs index f6f0ce528edb3..28b09d2f909a3 100644 --- a/src/concurrency/data_race.rs +++ b/src/concurrency/data_race.rs @@ -939,11 +939,7 @@ impl VClockAlloc { /// Detect racing atomic read and writes (not data races) /// on every byte of the current access range - pub(super) fn race_free_with_atomic<'tcx>( - &self, - range: AllocRange, - global: &GlobalState, - ) -> bool { + pub(super) fn race_free_with_atomic(&self, range: AllocRange, global: &GlobalState) -> bool { if global.race_detecting() { let (_, clocks) = global.current_thread_state(); let alloc_ranges = self.alloc_ranges.borrow(); diff --git a/src/concurrency/weak_memory.rs b/src/concurrency/weak_memory.rs index dc32a3ddca41f..a771a09ed1ece 100644 --- a/src/concurrency/weak_memory.rs +++ b/src/concurrency/weak_memory.rs @@ -138,7 +138,7 @@ impl StoreBufferAlloc { /// before without data race, we can determine that the non-atomic access fully happens /// after all the prior atomic accesses so the location no longer needs to exhibit /// any weak memory behaviours until further atomic accesses. - pub fn memory_accessed<'tcx>(&self, range: AllocRange, global: &GlobalState) { + pub fn memory_accessed(&self, range: AllocRange, global: &GlobalState) { if !global.ongoing_action_data_race_free() { let mut buffers = self.store_buffers.borrow_mut(); let access_type = buffers.access_type(range); From bf7a5c41540a4005eb0f8d66afda205691fbb14b Mon Sep 17 00:00:00 2001 From: Andy Wang Date: Sun, 5 Jun 2022 21:48:07 +0100 Subject: [PATCH 3215/3747] Add more backgrounds on lazy store buffers Co-authored-by: Ralf Jung --- src/concurrency/weak_memory.rs | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/src/concurrency/weak_memory.rs b/src/concurrency/weak_memory.rs index a771a09ed1ece..02af0efe9fa7f 100644 --- a/src/concurrency/weak_memory.rs +++ b/src/concurrency/weak_memory.rs @@ -30,7 +30,18 @@ //! used to make sure a value in a thread's view is not overwritten by a write that occured earlier than the one in the existing view. //! In our implementation, this is detected using read information attached to store elements, as there is no data strucutre representing reads. //! -//! Safe/sound Rust allows for more operations on atomic locations than the C++20 atomic API was intended to allow, such as non-atomically accessing +//! The C++ memory model is built around the notion of an 'atomic object', so it would be natural +//! to attach store buffers to atomic objects. However, Rust follows LLVM in that it only has +//! 'atomic accesses'. Therefore Miri cannot know when and where atomic 'objects' are being +//! created or destroyed, to manage its store buffers. Instead, we hence lazily create an +//! atomic object on the first atomic access to a given region, and we destroy that object +//! on the next non-atomic or imperfectly overlapping atomic access to that region. +//! These lazy (de)allocations happen in memory_accessed() on non-atomic accesses, and +//! get_or_create_store_buffer() on atomic accesses. This mostly works well, but it does +//! lead to some issues (https://github.com/rust-lang/miri/issues/2164). +//! +//! One consequence of this difference is that safe/sound Rust allows for more operations on atomic locations +//! than the C++20 atomic API was intended to allow, such as non-atomically accessing //! a previously atomically accessed location, or accessing previously atomically accessed locations with a differently sized operation //! (such as accessing the top 16 bits of an AtomicU32). These senarios are generally undiscussed in formalisations of C++ memory model. //! In Rust, these operations can only be done through a `&mut AtomicFoo` reference or one derived from it, therefore these operations @@ -156,8 +167,8 @@ impl StoreBufferAlloc { } } - /// Gets a store buffer associated with an atomic object in this allocation - /// Or creates one with the specified initial value + /// Gets a store buffer associated with an atomic object in this allocation, + /// or creates one with the specified initial value if no atomic object exists yet. fn get_or_create_store_buffer<'tcx>( &self, range: AllocRange, From 1b32d14255aed79e1ff308e8c47b8cb884ed9703 Mon Sep 17 00:00:00 2001 From: Andy Wang Date: Sun, 5 Jun 2022 22:11:55 +0100 Subject: [PATCH 3216/3747] Make racy imperfectly overlapping atomic access unsupported instead of UB Co-authored-by: Ralf Jung --- src/concurrency/weak_memory.rs | 4 ++-- tests/fail/weak_memory/racing_mixed_size.stderr | 7 +++---- tests/fail/weak_memory/racing_mixed_size_read.stderr | 7 +++---- 3 files changed, 8 insertions(+), 10 deletions(-) diff --git a/src/concurrency/weak_memory.rs b/src/concurrency/weak_memory.rs index 02af0efe9fa7f..da36fcd2fb3a8 100644 --- a/src/concurrency/weak_memory.rs +++ b/src/concurrency/weak_memory.rs @@ -431,8 +431,8 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>: && !alloc_clocks .race_free_with_atomic(range, this.machine.data_race.as_ref().unwrap()) { - throw_ub_format!( - "racy imperfectly overlapping atomic access is not possible in the C++20 memory model" + throw_unsup_format!( + "racy imperfectly overlapping atomic access is not possible in the C++20 memory model, and not supported by Miri's weak memory emulation" ); } } diff --git a/tests/fail/weak_memory/racing_mixed_size.stderr b/tests/fail/weak_memory/racing_mixed_size.stderr index b03424a861c9a..fc6be84315d77 100644 --- a/tests/fail/weak_memory/racing_mixed_size.stderr +++ b/tests/fail/weak_memory/racing_mixed_size.stderr @@ -1,14 +1,13 @@ warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. (see https://github.com/rust-lang/miri/issues/1388) -error: Undefined Behavior: racy imperfectly overlapping atomic access is not possible in the C++20 memory model +error: unsupported operation: racy imperfectly overlapping atomic access is not possible in the C++20 memory model, and not supported by Miri's weak memory emulation --> $DIR/racing_mixed_size.rs:LL:CC | LL | std::intrinsics::atomic_load_relaxed(hi); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ racy imperfectly overlapping atomic access is not possible in the C++20 memory model + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ racy imperfectly overlapping atomic access is not possible in the C++20 memory model, and not supported by Miri's weak memory emulation | - = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior - = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support = note: inside closure at $DIR/racing_mixed_size.rs:LL:CC diff --git a/tests/fail/weak_memory/racing_mixed_size_read.stderr b/tests/fail/weak_memory/racing_mixed_size_read.stderr index 80cc2fe756bf2..846d03f5448ff 100644 --- a/tests/fail/weak_memory/racing_mixed_size_read.stderr +++ b/tests/fail/weak_memory/racing_mixed_size_read.stderr @@ -1,14 +1,13 @@ warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. (see https://github.com/rust-lang/miri/issues/1388) -error: Undefined Behavior: racy imperfectly overlapping atomic access is not possible in the C++20 memory model +error: unsupported operation: racy imperfectly overlapping atomic access is not possible in the C++20 memory model, and not supported by Miri's weak memory emulation --> $DIR/racing_mixed_size_read.rs:LL:CC | LL | std::intrinsics::atomic_load_relaxed(hi); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ racy imperfectly overlapping atomic access is not possible in the C++20 memory model + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ racy imperfectly overlapping atomic access is not possible in the C++20 memory model, and not supported by Miri's weak memory emulation | - = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior - = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support = note: inside closure at $DIR/racing_mixed_size_read.rs:LL:CC From 14913e993b9415c3f12159aaa387ed3931a30e73 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 6 Jun 2022 11:45:41 -0400 Subject: [PATCH 3217/3747] deprecate -Zmiri-allow-uninit-numbers and -Zmiri-allow-ptr-int-transmute --- README.md | 6 ++++-- src/bin/miri.rs | 8 ++++++++ .../validity/invalid_enum_tag_256variants_uninit.stderr | 1 + tests/pass/move-uninit-primval.stderr | 1 + tests/pass/uninit_number_ignored.stderr | 1 + 5 files changed, 15 insertions(+), 2 deletions(-) create mode 100644 tests/pass/move-uninit-primval.stderr create mode 100644 tests/pass/uninit_number_ignored.stderr diff --git a/README.md b/README.md index a55ebcb125b38..63990985ba40c 100644 --- a/README.md +++ b/README.md @@ -304,13 +304,15 @@ to Miri failing to detect cases of undefined behavior in a program. * `-Zmiri-allow-uninit-numbers` disables the check to ensure that number types (integer and float types) always hold initialized data. (They must still be initialized when any actual operation, - such as arithmetic, is performed.) Using this flag is **unsound**. This has no effect when + such as arithmetic, is performed.) Using this flag is **unsound** and + [deprecated](https://github.com/rust-lang/miri/issues/2187). This has no effect when `-Zmiri-disable-validation` is present. * `-Zmiri-allow-ptr-int-transmute` makes Miri more accepting of transmutation between pointers and integers via `mem::transmute` or union/pointer type punning. This has two effects: it disables the check against integers storing a pointer (i.e., data with provenance), thus allowing pointer-to-integer transmutation, and it treats integer-to-pointer transmutation as equivalent to - a cast. Using this flag is **unsound**. + a cast. Using this flag is **unsound** and + [deprecated](https://github.com/rust-lang/miri/issues/2188). * `-Zmiri-disable-abi-check` disables checking [function ABI]. Using this flag is **unsound**. * `-Zmiri-disable-alignment-check` disables checking pointer alignment, so you diff --git a/src/bin/miri.rs b/src/bin/miri.rs index e3f38956dae25..efb300a8baf27 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -328,8 +328,16 @@ fn main() { since it is now enabled by default" ); } else if arg == "-Zmiri-allow-uninit-numbers" { + eprintln!( + "WARNING: `-Zmiri-allow-uninit-numbers` is deprecated and planned to be removed. \ + Please let us know at if you rely on this flag." + ); miri_config.allow_uninit_numbers = true; } else if arg == "-Zmiri-allow-ptr-int-transmute" { + eprintln!( + "WARNING: `-Zmiri-allow-ptr-int-transmute` is deprecated and planned to be removed. \ + Please let us know at if you rely on this flag." + ); miri_config.allow_ptr_int_transmute = true; } else if arg == "-Zmiri-disable-abi-check" { miri_config.check_abi = false; diff --git a/tests/fail/validity/invalid_enum_tag_256variants_uninit.stderr b/tests/fail/validity/invalid_enum_tag_256variants_uninit.stderr index 1a6039c477d6e..0e924bb741a9c 100644 --- a/tests/fail/validity/invalid_enum_tag_256variants_uninit.stderr +++ b/tests/fail/validity/invalid_enum_tag_256variants_uninit.stderr @@ -1,3 +1,4 @@ +WARNING: `-Zmiri-allow-uninit-numbers` is deprecated and planned to be removed. Please let us know at if you rely on this flag. error: Undefined Behavior: type validation failed at .: encountered uninitialized bytes, but expected a valid enum tag --> $DIR/invalid_enum_tag_256variants_uninit.rs:LL:CC | diff --git a/tests/pass/move-uninit-primval.stderr b/tests/pass/move-uninit-primval.stderr new file mode 100644 index 0000000000000..d9f2331fe7fa5 --- /dev/null +++ b/tests/pass/move-uninit-primval.stderr @@ -0,0 +1 @@ +WARNING: `-Zmiri-allow-uninit-numbers` is deprecated and planned to be removed. Please let us know at if you rely on this flag. diff --git a/tests/pass/uninit_number_ignored.stderr b/tests/pass/uninit_number_ignored.stderr new file mode 100644 index 0000000000000..d9f2331fe7fa5 --- /dev/null +++ b/tests/pass/uninit_number_ignored.stderr @@ -0,0 +1 @@ +WARNING: `-Zmiri-allow-uninit-numbers` is deprecated and planned to be removed. Please let us know at if you rely on this flag. From 66d3ee157ba5192409753e3f4a488f9ab2063e4a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 6 Jun 2022 19:11:59 -0400 Subject: [PATCH 3218/3747] hotfix for incorrect only- logic --- ui_test/src/lib.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ui_test/src/lib.rs b/ui_test/src/lib.rs index 0b076a5f51ec2..caefee1992ed8 100644 --- a/ui_test/src/lib.rs +++ b/ui_test/src/lib.rs @@ -516,9 +516,10 @@ fn ignore_file(comments: &Comments, target: &str) -> bool { if !target.contains(s) { return true; } + /* FIXME(https://github.com/rust-lang/miri/issues/2206) if get_pointer_width(target) != s { return true; - } + } */ } false } From 89edc355e8229ef8c8083e7974971999386c5ce4 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 6 Jun 2022 19:48:21 -0400 Subject: [PATCH 3219/3747] bless Windows --- tests/fail/concurrency/thread-spawn.stderr | 30 ++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 tests/fail/concurrency/thread-spawn.stderr diff --git a/tests/fail/concurrency/thread-spawn.stderr b/tests/fail/concurrency/thread-spawn.stderr new file mode 100644 index 0000000000000..eb6c6c9b0bb8e --- /dev/null +++ b/tests/fail/concurrency/thread-spawn.stderr @@ -0,0 +1,30 @@ +error: unsupported operation: can't create threads on Windows + --> RUSTLIB/std/src/sys/PLATFORM/thread.rs:LL:CC + | +LL | let ret = c::CreateThread( + | ___________________^ +LL | | ptr::null_mut(), +LL | | stack, +LL | | thread_start, +... | +LL | | ptr::null_mut(), +LL | | ); + | |_________^ can't create threads on Windows + | + = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support + + = note: inside `std::sys::PLATFORM::thread::Thread::new` at RUSTLIB/std/src/sys/PLATFORM/thread.rs:LL:CC + = note: inside `std::thread::Builder::spawn_unchecked_::<[closure@$DIR/thread-spawn.rs:LL:CC], ()>` at RUSTLIB/std/src/thread/mod.rs:LL:CC + = note: inside `std::thread::Builder::spawn_unchecked::<[closure@$DIR/thread-spawn.rs:LL:CC], ()>` at RUSTLIB/std/src/thread/mod.rs:LL:CC + = note: inside `std::thread::Builder::spawn::<[closure@$DIR/thread-spawn.rs:LL:CC], ()>` at RUSTLIB/std/src/thread/mod.rs:LL:CC + = note: inside `std::thread::spawn::<[closure@$DIR/thread-spawn.rs:LL:CC], ()>` at RUSTLIB/std/src/thread/mod.rs:LL:CC +note: inside `main` at $DIR/thread-spawn.rs:LL:CC + --> $DIR/thread-spawn.rs:LL:CC + | +LL | thread::spawn(|| {}); + | ^^^^^^^^^^^^^^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + From dac95a3ad8507fcad5fa64656ededd4cffc5b996 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 6 Jun 2022 17:27:46 -0400 Subject: [PATCH 3220/3747] =?UTF-8?q?rename=20AllocationMap=20=E2=86=92=20?= =?UTF-8?q?RangeObjectMap?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/concurrency/mod.rs | 2 +- ...{allocation_map.rs => range_object_map.rs} | 25 +++++++++---------- src/concurrency/weak_memory.rs | 6 ++--- 3 files changed, 16 insertions(+), 17 deletions(-) rename src/concurrency/{allocation_map.rs => range_object_map.rs} (93%) diff --git a/src/concurrency/mod.rs b/src/concurrency/mod.rs index ad1586bbf0f9b..5f8bba802728c 100644 --- a/src/concurrency/mod.rs +++ b/src/concurrency/mod.rs @@ -1,3 +1,3 @@ -mod allocation_map; pub mod data_race; +mod range_object_map; pub mod weak_memory; diff --git a/src/concurrency/allocation_map.rs b/src/concurrency/range_object_map.rs similarity index 93% rename from src/concurrency/allocation_map.rs rename to src/concurrency/range_object_map.rs index 62469dcaf43a8..2bb3280302392 100644 --- a/src/concurrency/allocation_map.rs +++ b/src/concurrency/range_object_map.rs @@ -1,7 +1,6 @@ -//! Implements a map from allocation ranges to data. -//! This is somewhat similar to RangeMap, but the ranges -//! and data are discrete and non-splittable. An allocation in the -//! map will always have the same range until explicitly removed +//! Implements a map from allocation ranges to data. This is somewhat similar to RangeMap, but the +//! ranges and data are discrete and non-splittable -- they represent distinct "objects". An +//! allocation in the map will always have the same range until explicitly removed use rustc_target::abi::Size; use std::ops::{Index, IndexMut, Range}; @@ -20,7 +19,7 @@ struct Elem { type Position = usize; #[derive(Clone, Debug)] -pub struct AllocationMap { +pub struct RangeObjectMap { v: Vec>, } @@ -34,7 +33,7 @@ pub enum AccessType { ImperfectlyOverlapping(Range), } -impl AllocationMap { +impl RangeObjectMap { pub fn new() -> Self { Self { v: Vec::new() } } @@ -135,7 +134,7 @@ impl AllocationMap { } } -impl Index for AllocationMap { +impl Index for RangeObjectMap { type Output = T; fn index(&self, pos: Position) -> &Self::Output { @@ -143,7 +142,7 @@ impl Index for AllocationMap { } } -impl IndexMut for AllocationMap { +impl IndexMut for RangeObjectMap { fn index_mut(&mut self, pos: Position) -> &mut Self::Output { &mut self.v[pos].data } @@ -159,7 +158,7 @@ mod tests { fn empty_map() { // FIXME: make Size::from_bytes const let four = Size::from_bytes(4); - let map = AllocationMap::<()>::new(); + let map = RangeObjectMap::<()>::new(); // Correctly tells where we should insert the first element (at position 0) assert_eq!(map.find_offset(Size::from_bytes(3)), Err(0)); @@ -173,7 +172,7 @@ mod tests { fn no_overlapping_inserts() { let four = Size::from_bytes(4); - let mut map = AllocationMap::<&str>::new(); + let mut map = RangeObjectMap::<&str>::new(); // |_|_|_|_|#|#|#|#|_|_|_|_|... // 0 1 2 3 4 5 6 7 8 9 a b c d @@ -187,7 +186,7 @@ mod tests { fn boundaries() { let four = Size::from_bytes(4); - let mut map = AllocationMap::<&str>::new(); + let mut map = RangeObjectMap::<&str>::new(); // |#|#|#|#|_|_|... // 0 1 2 3 4 5 @@ -215,7 +214,7 @@ mod tests { fn perfectly_overlapping() { let four = Size::from_bytes(4); - let mut map = AllocationMap::<&str>::new(); + let mut map = RangeObjectMap::<&str>::new(); // |#|#|#|#|_|_|... // 0 1 2 3 4 5 @@ -241,7 +240,7 @@ mod tests { fn straddling() { let four = Size::from_bytes(4); - let mut map = AllocationMap::<&str>::new(); + let mut map = RangeObjectMap::<&str>::new(); // |_|_|_|_|#|#|#|#|_|_|_|_|... // 0 1 2 3 4 5 6 7 8 9 a b c d diff --git a/src/concurrency/weak_memory.rs b/src/concurrency/weak_memory.rs index da36fcd2fb3a8..be3963a93f072 100644 --- a/src/concurrency/weak_memory.rs +++ b/src/concurrency/weak_memory.rs @@ -85,8 +85,8 @@ use rustc_data_structures::fx::FxHashMap; use crate::{AtomicReadOp, AtomicRwOp, AtomicWriteOp, Tag, VClock, VTimestamp, VectorIdx}; use super::{ - allocation_map::{AccessType, AllocationMap}, data_race::{GlobalState, ThreadClockSet}, + range_object_map::{AccessType, RangeObjectMap}, }; pub type AllocExtra = StoreBufferAlloc; @@ -101,7 +101,7 @@ const STORE_BUFFER_LIMIT: usize = 128; pub struct StoreBufferAlloc { /// Store buffer of each atomic object in this allocation // Behind a RefCell because we need to allocate/remove on read access - store_buffers: RefCell>, + store_buffers: RefCell>, } #[derive(Debug, Clone, PartialEq, Eq)] @@ -134,7 +134,7 @@ struct StoreElement { impl StoreBufferAlloc { pub fn new_allocation() -> Self { - Self { store_buffers: RefCell::new(AllocationMap::new()) } + Self { store_buffers: RefCell::new(RangeObjectMap::new()) } } /// Checks if the range imperfectly overlaps with existing buffers From b64c9a0a830c664bf31958a082cf7ad1f0742df9 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 6 Jun 2022 17:44:16 -0400 Subject: [PATCH 3221/3747] make scheduler preemptive, with configurable preemption rate --- README.md | 18 ++++---- src/bin/miri.rs | 11 +++++ src/eval.rs | 5 ++- src/machine.rs | 9 ++++ src/thread.rs | 10 +++++ .../concurrency/libc_pthread_join_self.rs | 2 + tests/fail/data_race/alloc_read_race.rs | 2 +- tests/fail/data_race/alloc_write_race.rs | 2 +- .../fail/data_race/dealloc_read_race_stack.rs | 2 +- .../data_race/dealloc_write_race_stack.rs | 2 +- tests/fail/data_race/read_write_race_stack.rs | 2 +- tests/fail/data_race/relax_acquire_race.rs | 2 +- tests/fail/data_race/release_seq_race.rs | 2 +- .../data_race/release_seq_race_same_thread.rs | 2 +- tests/fail/data_race/rmw_race.rs | 2 +- .../fail/data_race/write_write_race_stack.rs | 2 +- tests/pass/concurrency/spin_loop.rs | 42 +++++++++++++++++++ tests/pass/concurrency/spin_loop.stderr | 3 ++ ...{spin_loops.rs => spin_loops_nopreempt.rs} | 2 + .../concurrency/spin_loops_nopreempt.stderr | 3 ++ tests/pass/concurrency/sync.rs | 3 +- tests/pass/panic/concurrent-panic.rs | 2 + tests/pass/weak_memory/weak.rs | 2 +- 23 files changed, 111 insertions(+), 21 deletions(-) create mode 100644 tests/pass/concurrency/spin_loop.rs create mode 100644 tests/pass/concurrency/spin_loop.stderr rename tests/pass/concurrency/{spin_loops.rs => spin_loops_nopreempt.rs} (96%) create mode 100644 tests/pass/concurrency/spin_loops_nopreempt.stderr diff --git a/README.md b/README.md index 938a64cd045b1..6ccc9e25f6975 100644 --- a/README.md +++ b/README.md @@ -288,14 +288,16 @@ environment variable. We first document the most relevant and most commonly used `-Zmiri-disable-isolation` is set. * `-Zmiri-ignore-leaks` disables the memory leak checker, and also allows some remaining threads to exist when the main thread exits. -* `-Zmiri-seed=` configures the seed of the RNG that Miri uses to resolve - non-determinism. This RNG is used to pick base addresses for allocations. When - isolation is enabled (the default), this is also used to emulate system - entropy. The default seed is 0. You can increase test coverage by running Miri - multiple times with different seeds. - **NOTE**: This entropy is not good enough for cryptographic use! Do not - generate secret keys in Miri or perform other kinds of cryptographic - operations that rely on proper random numbers. +* `-Zmiri-preemption-rate` configures the probability that at the end of a basic block, the active + thread will be preempted. The default is `0.01` (i.e., 1%). Setting this to `0` disables + preemption. +* `-Zmiri-seed=` configures the seed of the RNG that Miri uses to resolve non-determinism. This + RNG is used to pick base addresses for allocations, to determine preemption and failure of + `compare_exchange_weak`, and to control store buffering for weak memory emulation. When isolation + is enabled (the default), this is also used to emulate system entropy. The default seed is 0. You + can increase test coverage by running Miri multiple times with different seeds. **NOTE**: This + entropy is not good enough for cryptographic use! Do not generate secret keys in Miri or perform + other kinds of cryptographic operations that rely on proper random numbers. * `-Zmiri-strict-provenance` enables [strict provenance](https://github.com/rust-lang/rust/issues/95228) checking in Miri. This means that casting an integer to a pointer yields a result with 'invalid' provenance, i.e., with provenance diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 907e620404b9b..64047d146c3b9 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -449,6 +449,17 @@ fn main() { ), }; miri_config.cmpxchg_weak_failure_rate = rate; + } else if let Some(param) = arg.strip_prefix("-Zmiri-preemption-rate=") { + let rate = match param.parse::() { + Ok(rate) if rate >= 0.0 && rate <= 1.0 => rate, + Ok(_) => panic!("-Zmiri-preemption-rate must be between `0.0` and `1.0`"), + Err(err) => + panic!( + "-Zmiri-preemption-rate requires a `f64` between `0.0` and `1.0`: {}", + err + ), + }; + miri_config.preemption_rate = rate; } else if let Some(param) = arg.strip_prefix("-Zmiri-measureme=") { miri_config.measureme_out = Some(param.to_string()); } else if let Some(param) = arg.strip_prefix("-Zmiri-backtrace=") { diff --git a/src/eval.rs b/src/eval.rs index bdf527a0d13e0..7c971d2a1490a 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -122,6 +122,8 @@ pub struct MiriConfig { /// Whether to ignore any output by the program. This is helpful when debugging miri /// as its messages don't get intermingled with the program messages. pub mute_stdout_stderr: bool, + /// The probability of the active thread being preempted at the end of each basic block. + pub preemption_rate: f64, } impl Default for MiriConfig { @@ -145,12 +147,13 @@ impl Default for MiriConfig { tag_raw: false, data_race_detector: true, weak_memory_emulation: true, - cmpxchg_weak_failure_rate: 0.8, + cmpxchg_weak_failure_rate: 0.8, // 80% measureme_out: None, panic_on_unsupported: false, backtrace_style: BacktraceStyle::Short, provenance_mode: ProvenanceMode::Legacy, mute_stdout_stderr: false, + preemption_rate: 0.01, // 1% } } } diff --git a/src/machine.rs b/src/machine.rs index 1ae49edd6001a..5e93045aec1ab 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -333,6 +333,9 @@ pub struct Evaluator<'mir, 'tcx> { /// Whether weak memory emulation is enabled pub(crate) weak_memory: bool, + + /// The probability of the active thread being preempted at the end of each basic block. + pub(crate) preemption_rate: f64, } impl<'mir, 'tcx> Evaluator<'mir, 'tcx> { @@ -389,6 +392,7 @@ impl<'mir, 'tcx> Evaluator<'mir, 'tcx> { cmpxchg_weak_failure_rate: config.cmpxchg_weak_failure_rate, mute_stdout_stderr: config.mute_stdout_stderr, weak_memory: config.weak_memory_emulation, + preemption_rate: config.preemption_rate, } } @@ -846,6 +850,11 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { ecx.active_thread_stack_mut() } + fn before_terminator(ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx> { + ecx.maybe_preempt_active_thread(); + Ok(()) + } + #[inline(always)] fn after_stack_push(ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx> { if ecx.machine.stacked_borrows.is_some() { ecx.retag_return_place() } else { Ok(()) } diff --git a/src/thread.rs b/src/thread.rs index 0d702fd9c8e17..9eabbd77419fb 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -717,6 +717,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.machine.threads.yield_active_thread(); } + #[inline] + fn maybe_preempt_active_thread(&mut self) { + use rand::Rng as _; + + let this = self.eval_context_mut(); + if this.machine.rng.get_mut().gen_bool(this.machine.preemption_rate) { + this.yield_active_thread(); + } + } + #[inline] fn register_timeout_callback( &mut self, diff --git a/tests/fail/concurrency/libc_pthread_join_self.rs b/tests/fail/concurrency/libc_pthread_join_self.rs index 2a8fe12eafd62..db45b33c14684 100644 --- a/tests/fail/concurrency/libc_pthread_join_self.rs +++ b/tests/fail/concurrency/libc_pthread_join_self.rs @@ -1,4 +1,6 @@ // ignore-windows: No libc on Windows +// We are making scheduler assumptions here. +// compile-flags: -Zmiri-preemption-rate=0 // Joining itself is undefined behavior. diff --git a/tests/fail/data_race/alloc_read_race.rs b/tests/fail/data_race/alloc_read_race.rs index 2ddbb657245a6..4adb7071f294b 100644 --- a/tests/fail/data_race/alloc_read_race.rs +++ b/tests/fail/data_race/alloc_read_race.rs @@ -1,5 +1,5 @@ // ignore-windows: Concurrency on Windows is not supported yet. -// compile-flags: -Zmiri-disable-weak-memory-emulation +// compile-flags: -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 #![feature(new_uninit)] use std::thread::spawn; diff --git a/tests/fail/data_race/alloc_write_race.rs b/tests/fail/data_race/alloc_write_race.rs index d32eb55676067..e4a1192f95b39 100644 --- a/tests/fail/data_race/alloc_write_race.rs +++ b/tests/fail/data_race/alloc_write_race.rs @@ -1,5 +1,5 @@ // ignore-windows: Concurrency on Windows is not supported yet. -// compile-flags: -Zmiri-disable-weak-memory-emulation +// compile-flags: -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 #![feature(new_uninit)] use std::thread::spawn; diff --git a/tests/fail/data_race/dealloc_read_race_stack.rs b/tests/fail/data_race/dealloc_read_race_stack.rs index b70db5f4ac4b7..f458d1126efe7 100644 --- a/tests/fail/data_race/dealloc_read_race_stack.rs +++ b/tests/fail/data_race/dealloc_read_race_stack.rs @@ -1,5 +1,5 @@ // ignore-windows: Concurrency on Windows is not supported yet. -// compile-flags: -Zmiri-disable-isolation -Zmiri-disable-weak-memory-emulation +// compile-flags: -Zmiri-disable-isolation -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 use std::thread::{spawn, sleep}; use std::ptr::null_mut; diff --git a/tests/fail/data_race/dealloc_write_race_stack.rs b/tests/fail/data_race/dealloc_write_race_stack.rs index f2b49fc5f344a..d1fe8c3e9a160 100644 --- a/tests/fail/data_race/dealloc_write_race_stack.rs +++ b/tests/fail/data_race/dealloc_write_race_stack.rs @@ -1,5 +1,5 @@ // ignore-windows: Concurrency on Windows is not supported yet. -// compile-flags: -Zmiri-disable-isolation -Zmiri-disable-weak-memory-emulation +// compile-flags: -Zmiri-disable-isolation -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 use std::thread::{spawn, sleep}; use std::ptr::null_mut; diff --git a/tests/fail/data_race/read_write_race_stack.rs b/tests/fail/data_race/read_write_race_stack.rs index 9edeed0af6521..f5c4768296b01 100644 --- a/tests/fail/data_race/read_write_race_stack.rs +++ b/tests/fail/data_race/read_write_race_stack.rs @@ -1,5 +1,5 @@ // ignore-windows: Concurrency on Windows is not supported yet. -// compile-flags: -Zmiri-disable-isolation -Zmir-opt-level=0 -Zmiri-disable-weak-memory-emulation +// compile-flags: -Zmiri-disable-isolation -Zmir-opt-level=0 -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 // Note: mir-opt-level set to 0 to prevent the read of stack_var in thread 1 // from being optimized away and preventing the detection of the data-race. diff --git a/tests/fail/data_race/relax_acquire_race.rs b/tests/fail/data_race/relax_acquire_race.rs index 20e63dc4b171a..64c0f95fa4bae 100644 --- a/tests/fail/data_race/relax_acquire_race.rs +++ b/tests/fail/data_race/relax_acquire_race.rs @@ -1,5 +1,5 @@ // ignore-windows: Concurrency on Windows is not supported yet. -// compile-flags: -Zmiri-disable-weak-memory-emulation +// compile-flags: -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 use std::thread::spawn; use std::sync::atomic::{AtomicUsize, Ordering}; diff --git a/tests/fail/data_race/release_seq_race.rs b/tests/fail/data_race/release_seq_race.rs index 6ff84aa04b263..964d1b4937b89 100644 --- a/tests/fail/data_race/release_seq_race.rs +++ b/tests/fail/data_race/release_seq_race.rs @@ -1,5 +1,5 @@ // ignore-windows: Concurrency on Windows is not supported yet. -// compile-flags: -Zmiri-disable-isolation -Zmiri-disable-weak-memory-emulation +// compile-flags: -Zmiri-disable-isolation -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 use std::thread::{spawn, sleep}; use std::sync::atomic::{AtomicUsize, Ordering}; diff --git a/tests/fail/data_race/release_seq_race_same_thread.rs b/tests/fail/data_race/release_seq_race_same_thread.rs index 1245fb96f497d..01d45a1b7ccf0 100644 --- a/tests/fail/data_race/release_seq_race_same_thread.rs +++ b/tests/fail/data_race/release_seq_race_same_thread.rs @@ -1,5 +1,5 @@ // ignore-windows: Concurrency on Windows is not supported yet. -// compile-flags: -Zmiri-disable-isolation -Zmiri-disable-weak-memory-emulation +// compile-flags: -Zmiri-disable-isolation -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 use std::thread::spawn; use std::sync::atomic::{AtomicUsize, Ordering}; diff --git a/tests/fail/data_race/rmw_race.rs b/tests/fail/data_race/rmw_race.rs index c968c83422c06..fab6fabe5b6fb 100644 --- a/tests/fail/data_race/rmw_race.rs +++ b/tests/fail/data_race/rmw_race.rs @@ -1,5 +1,5 @@ // ignore-windows: Concurrency on Windows is not supported yet. -// compile-flags: -Zmiri-disable-weak-memory-emulation +// compile-flags: -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 use std::thread::spawn; use std::sync::atomic::{AtomicUsize, Ordering}; diff --git a/tests/fail/data_race/write_write_race_stack.rs b/tests/fail/data_race/write_write_race_stack.rs index daa3e5f5c4789..e6ae207d86100 100644 --- a/tests/fail/data_race/write_write_race_stack.rs +++ b/tests/fail/data_race/write_write_race_stack.rs @@ -1,5 +1,5 @@ // ignore-windows: Concurrency on Windows is not supported yet. -// compile-flags: -Zmiri-disable-isolation -Zmiri-disable-weak-memory-emulation +// compile-flags: -Zmiri-disable-isolation -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 use std::thread::{spawn, sleep}; use std::ptr::null_mut; diff --git a/tests/pass/concurrency/spin_loop.rs b/tests/pass/concurrency/spin_loop.rs new file mode 100644 index 0000000000000..7d26077bb49f8 --- /dev/null +++ b/tests/pass/concurrency/spin_loop.rs @@ -0,0 +1,42 @@ +use std::thread; +use std::sync::atomic::{AtomicUsize, Ordering}; + +static FLAG: AtomicUsize = AtomicUsize::new(0); + +fn spin() { + let j = thread::spawn(|| { + while FLAG.load(Ordering::Acquire) == 0 { + // We do *not* yield, and yet this should terminate eventually. + } + }); + thread::yield_now(); // schedule the other thread + FLAG.store(1, Ordering::Release); + j.join().unwrap(); +} + +fn two_player_ping_pong() { + static FLAG: AtomicUsize = AtomicUsize::new(0); + + let waiter1 = thread::spawn(|| { + while FLAG.load(Ordering::Acquire) == 0 { + // We do *not* yield, and yet this should terminate eventually. + } + }); + let waiter2 = thread::spawn(|| { + while FLAG.load(Ordering::Acquire) == 0 { + // We do *not* yield, and yet this should terminate eventually. + } + }); + let progress = thread::spawn(|| { + FLAG.store(1, Ordering::Release); + }); + // The first `join` blocks the main thread and thus takes it out of the equation. + waiter1.join().unwrap(); + waiter2.join().unwrap(); + progress.join().unwrap(); +} + +fn main() { + spin(); + two_player_ping_pong(); +} diff --git a/tests/pass/concurrency/spin_loop.stderr b/tests/pass/concurrency/spin_loop.stderr new file mode 100644 index 0000000000000..9fe6daa778c1f --- /dev/null +++ b/tests/pass/concurrency/spin_loop.stderr @@ -0,0 +1,3 @@ +warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. + (see https://github.com/rust-lang/miri/issues/1388) + diff --git a/tests/pass/concurrency/spin_loops.rs b/tests/pass/concurrency/spin_loops_nopreempt.rs similarity index 96% rename from tests/pass/concurrency/spin_loops.rs rename to tests/pass/concurrency/spin_loops_nopreempt.rs index a6fceb03638dd..d8064f6ed5396 100644 --- a/tests/pass/concurrency/spin_loops.rs +++ b/tests/pass/concurrency/spin_loops_nopreempt.rs @@ -1,4 +1,6 @@ // ignore-windows: Concurrency on Windows is not supported yet. +// This specifically tests behavior *without* preemption. +// compile-flags: -Zmiri-preemption-rate=0 use std::thread; use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering}; diff --git a/tests/pass/concurrency/spin_loops_nopreempt.stderr b/tests/pass/concurrency/spin_loops_nopreempt.stderr new file mode 100644 index 0000000000000..9fe6daa778c1f --- /dev/null +++ b/tests/pass/concurrency/spin_loops_nopreempt.stderr @@ -0,0 +1,3 @@ +warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. + (see https://github.com/rust-lang/miri/issues/1388) + diff --git a/tests/pass/concurrency/sync.rs b/tests/pass/concurrency/sync.rs index 6889aad91cf26..26f44aa437189 100644 --- a/tests/pass/concurrency/sync.rs +++ b/tests/pass/concurrency/sync.rs @@ -1,5 +1,6 @@ // ignore-windows: Concurrency on Windows is not supported yet. -// compile-flags: -Zmiri-disable-isolation -Zmiri-strict-provenance +// We are making scheduler assumptions here. +// compile-flags: -Zmiri-disable-isolation -Zmiri-strict-provenance -Zmiri-preemption-rate=0 use std::sync::{Arc, Barrier, Condvar, Mutex, Once, RwLock}; use std::thread; diff --git a/tests/pass/panic/concurrent-panic.rs b/tests/pass/panic/concurrent-panic.rs index 0ff5788e204d1..7b17ac4fa79c1 100644 --- a/tests/pass/panic/concurrent-panic.rs +++ b/tests/pass/panic/concurrent-panic.rs @@ -1,4 +1,6 @@ // ignore-windows: Concurrency on Windows is not supported yet. +// We are making scheduler assumptions here. +// compile-flags: -Zmiri-preemption-rate=0 //! Cause a panic in one thread while another thread is unwinding. This checks //! that separate threads have their own panicking state. diff --git a/tests/pass/weak_memory/weak.rs b/tests/pass/weak_memory/weak.rs index 70e1bf00f442e..e1e9c41e36f5d 100644 --- a/tests/pass/weak_memory/weak.rs +++ b/tests/pass/weak_memory/weak.rs @@ -1,5 +1,5 @@ // ignore-windows: Concurrency on Windows is not supported yet. -// compile-flags: -Zmiri-ignore-leaks +// compile-flags: -Zmiri-ignore-leaks -Zmiri-preemption-rate=0 // Tests showing weak memory behaviours are exhibited. All tests // return true when the desired behaviour is seen. From bf372a8fbc838e89234adba0339d5f2d1ea5f561 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 6 Jun 2022 18:58:06 -0400 Subject: [PATCH 3222/3747] remove warning about thread support being experimental --- src/shims/unix/thread.rs | 4 ---- tests/pass/concurrency/spin_loop.rs | 1 + 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/src/shims/unix/thread.rs b/src/shims/unix/thread.rs index 4dc40cf2fe3dc..63b9f36d6ffa4 100644 --- a/src/shims/unix/thread.rs +++ b/src/shims/unix/thread.rs @@ -13,10 +13,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - this.tcx.sess.warn( - "thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops.\n(see https://github.com/rust-lang/miri/issues/1388)", - ); - // Create the new thread let new_thread_id = this.create_thread(); diff --git a/tests/pass/concurrency/spin_loop.rs b/tests/pass/concurrency/spin_loop.rs index 7d26077bb49f8..1e81f5dc86dce 100644 --- a/tests/pass/concurrency/spin_loop.rs +++ b/tests/pass/concurrency/spin_loop.rs @@ -1,3 +1,4 @@ +// ignore-windows: Concurrency on Windows is not supported yet. use std::thread; use std::sync::atomic::{AtomicUsize, Ordering}; From 11a8b3a00b72505751743230bf265c9eecfd58db Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 6 Jun 2022 19:00:50 -0400 Subject: [PATCH 3223/3747] bless tests --- .../libc_pthread_create_main_terminate.stderr | 5 +--- .../libc_pthread_join_detached.stderr | 5 +--- .../libc_pthread_join_joined.stderr | 5 +--- .../concurrency/libc_pthread_join_main.stderr | 5 +--- .../libc_pthread_join_multiple.stderr | 5 +--- .../concurrency/libc_pthread_join_self.stderr | 5 +--- .../thread_local_static_dealloc.stderr | 5 +--- tests/fail/concurrency/too_few_args.stderr | 5 +--- tests/fail/concurrency/too_many_args.stderr | 5 +--- .../concurrency/unwind_top_of_stack.stderr | 5 +--- tests/fail/data_race/alloc_read_race.stderr | 5 +--- tests/fail/data_race/alloc_write_race.stderr | 5 +--- .../atomic_read_na_write_race1.stderr | 5 +--- .../atomic_read_na_write_race2.stderr | 5 +--- .../atomic_write_na_read_race1.stderr | 5 +--- .../atomic_write_na_read_race2.stderr | 5 +--- .../atomic_write_na_write_race1.stderr | 5 +--- .../atomic_write_na_write_race2.stderr | 5 +--- .../dangling_thread_async_race.stderr | 5 +--- .../data_race/dangling_thread_race.stderr | 5 +--- .../fail/data_race/dealloc_read_race1.stderr | 5 +--- .../fail/data_race/dealloc_read_race2.stderr | 5 +--- .../data_race/dealloc_read_race_stack.stderr | 5 +--- .../fail/data_race/dealloc_write_race1.stderr | 5 +--- .../fail/data_race/dealloc_write_race2.stderr | 5 +--- .../data_race/dealloc_write_race_stack.stderr | 5 +--- .../enable_after_join_to_main.stderr | 5 +--- tests/fail/data_race/fence_after_load.stderr | 5 +--- tests/fail/data_race/read_write_race.stderr | 5 +--- .../data_race/read_write_race_stack.stderr | 5 +--- .../fail/data_race/relax_acquire_race.stderr | 5 +--- tests/fail/data_race/release_seq_race.stderr | 5 +--- .../release_seq_race_same_thread.stderr | 5 +--- tests/fail/data_race/rmw_race.stderr | 5 +--- tests/fail/data_race/write_write_race.stderr | 5 +--- .../data_race/write_write_race_stack.stderr | 5 +--- tests/fail/should-pass/cpp20_rwc_syncs.rs | 4 +-- tests/fail/should-pass/cpp20_rwc_syncs.stderr | 26 +++++++++++++++++-- .../sync/libc_pthread_mutex_deadlock.stderr | 5 +--- .../libc_pthread_mutex_wrong_owner.stderr | 5 +--- ...ibc_pthread_rwlock_read_wrong_owner.stderr | 5 +--- ..._pthread_rwlock_write_read_deadlock.stderr | 5 +--- ...pthread_rwlock_write_write_deadlock.stderr | 5 +--- ...bc_pthread_rwlock_write_wrong_owner.stderr | 5 +--- .../fail/weak_memory/racing_mixed_size.stderr | 5 +--- .../weak_memory/racing_mixed_size_read.stderr | 5 +--- tests/pass/concurrency/channels.stderr | 3 --- .../concurrent_caller_location.stderr | 3 --- tests/pass/concurrency/data_race.stderr | 3 --- .../disable_data_race_detector.stderr | 3 --- tests/pass/concurrency/issue1643.stderr | 3 --- tests/pass/concurrency/linux-futex.stderr | 3 --- tests/pass/concurrency/simple.stderr | 3 --- tests/pass/concurrency/spin_loop.stderr | 3 --- .../concurrency/spin_loops_nopreempt.stderr | 3 --- tests/pass/concurrency/sync.stderr | 3 --- tests/pass/concurrency/thread_locals.stderr | 3 --- tests/pass/concurrency/tls_lib_drop.stderr | 3 --- tests/pass/libc.stderr | 3 --- tests/pass/panic/concurrent-panic.stderr | 3 --- tests/pass/threadleak_ignored.stderr | 3 --- tests/pass/weak_memory/consistency.stderr | 3 --- tests/pass/weak_memory/extra_cpp.stderr | 3 --- .../pass/weak_memory/extra_cpp_unsafe.stderr | 3 --- tests/pass/weak_memory/weak.stderr | 3 --- 65 files changed, 70 insertions(+), 237 deletions(-) delete mode 100644 tests/pass/concurrency/channels.stderr delete mode 100644 tests/pass/concurrency/concurrent_caller_location.stderr delete mode 100644 tests/pass/concurrency/data_race.stderr delete mode 100644 tests/pass/concurrency/disable_data_race_detector.stderr delete mode 100644 tests/pass/concurrency/issue1643.stderr delete mode 100644 tests/pass/concurrency/linux-futex.stderr delete mode 100644 tests/pass/concurrency/spin_loop.stderr delete mode 100644 tests/pass/concurrency/spin_loops_nopreempt.stderr delete mode 100644 tests/pass/concurrency/sync.stderr delete mode 100644 tests/pass/concurrency/thread_locals.stderr delete mode 100644 tests/pass/concurrency/tls_lib_drop.stderr delete mode 100644 tests/pass/libc.stderr delete mode 100644 tests/pass/weak_memory/consistency.stderr delete mode 100644 tests/pass/weak_memory/extra_cpp.stderr delete mode 100644 tests/pass/weak_memory/extra_cpp_unsafe.stderr delete mode 100644 tests/pass/weak_memory/weak.stderr diff --git a/tests/fail/concurrency/libc_pthread_create_main_terminate.stderr b/tests/fail/concurrency/libc_pthread_create_main_terminate.stderr index 2ce73fdaaec10..c5093c0e60113 100644 --- a/tests/fail/concurrency/libc_pthread_create_main_terminate.stderr +++ b/tests/fail/concurrency/libc_pthread_create_main_terminate.stderr @@ -1,9 +1,6 @@ -warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. - (see https://github.com/rust-lang/miri/issues/1388) - error: the main thread terminated without waiting for all remaining threads note: pass `-Zmiri-ignore-leaks` to disable this check -error: aborting due to previous error; 1 warning emitted +error: aborting due to previous error diff --git a/tests/fail/concurrency/libc_pthread_join_detached.stderr b/tests/fail/concurrency/libc_pthread_join_detached.stderr index b106cc4c95418..44d0f727a395e 100644 --- a/tests/fail/concurrency/libc_pthread_join_detached.stderr +++ b/tests/fail/concurrency/libc_pthread_join_detached.stderr @@ -1,6 +1,3 @@ -warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. - (see https://github.com/rust-lang/miri/issues/1388) - error: Undefined Behavior: trying to join a detached or already joined thread --> $DIR/libc_pthread_join_detached.rs:LL:CC | @@ -14,5 +11,5 @@ LL | ... assert_eq!(libc::pthread_join(native, ptr::null_mut()), 0); note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace -error: aborting due to previous error; 1 warning emitted +error: aborting due to previous error diff --git a/tests/fail/concurrency/libc_pthread_join_joined.stderr b/tests/fail/concurrency/libc_pthread_join_joined.stderr index 438998208d11b..b67974c58eaef 100644 --- a/tests/fail/concurrency/libc_pthread_join_joined.stderr +++ b/tests/fail/concurrency/libc_pthread_join_joined.stderr @@ -1,6 +1,3 @@ -warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. - (see https://github.com/rust-lang/miri/issues/1388) - error: Undefined Behavior: trying to join a detached or already joined thread --> $DIR/libc_pthread_join_joined.rs:LL:CC | @@ -14,5 +11,5 @@ LL | ... assert_eq!(libc::pthread_join(native, ptr::null_mut()), 0); note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace -error: aborting due to previous error; 1 warning emitted +error: aborting due to previous error diff --git a/tests/fail/concurrency/libc_pthread_join_main.stderr b/tests/fail/concurrency/libc_pthread_join_main.stderr index 04f2ab07406c0..3e69df508359a 100644 --- a/tests/fail/concurrency/libc_pthread_join_main.stderr +++ b/tests/fail/concurrency/libc_pthread_join_main.stderr @@ -1,6 +1,3 @@ -warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. - (see https://github.com/rust-lang/miri/issues/1388) - error: Undefined Behavior: trying to join a detached or already joined thread --> $DIR/libc_pthread_join_main.rs:LL:CC | @@ -14,5 +11,5 @@ LL | ... assert_eq!(libc::pthread_join(thread_id, ptr::null_mut()), 0); note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace -error: aborting due to previous error; 1 warning emitted +error: aborting due to previous error diff --git a/tests/fail/concurrency/libc_pthread_join_multiple.stderr b/tests/fail/concurrency/libc_pthread_join_multiple.stderr index daf18c50e034f..997bca9fe4223 100644 --- a/tests/fail/concurrency/libc_pthread_join_multiple.stderr +++ b/tests/fail/concurrency/libc_pthread_join_multiple.stderr @@ -1,6 +1,3 @@ -warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. - (see https://github.com/rust-lang/miri/issues/1388) - error: Undefined Behavior: trying to join a detached or already joined thread --> $DIR/libc_pthread_join_multiple.rs:LL:CC | @@ -14,5 +11,5 @@ LL | ... assert_eq!(libc::pthread_join(native_copy, ptr::null_mut()), 0); note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace -error: aborting due to previous error; 1 warning emitted +error: aborting due to previous error diff --git a/tests/fail/concurrency/libc_pthread_join_self.stderr b/tests/fail/concurrency/libc_pthread_join_self.stderr index b2e0779f5fbbd..8d2acb817f938 100644 --- a/tests/fail/concurrency/libc_pthread_join_self.stderr +++ b/tests/fail/concurrency/libc_pthread_join_self.stderr @@ -1,6 +1,3 @@ -warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. - (see https://github.com/rust-lang/miri/issues/1388) - error: Undefined Behavior: trying to join itself --> $DIR/libc_pthread_join_self.rs:LL:CC | @@ -14,5 +11,5 @@ LL | assert_eq!(libc::pthread_join(native, ptr::null_mut()), 0); note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace -error: aborting due to previous error; 1 warning emitted +error: aborting due to previous error diff --git a/tests/fail/concurrency/thread_local_static_dealloc.stderr b/tests/fail/concurrency/thread_local_static_dealloc.stderr index ad5528dc555ab..a485edc0da93f 100644 --- a/tests/fail/concurrency/thread_local_static_dealloc.stderr +++ b/tests/fail/concurrency/thread_local_static_dealloc.stderr @@ -1,6 +1,3 @@ -warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. - (see https://github.com/rust-lang/miri/issues/1388) - error: Undefined Behavior: pointer to ALLOC was dereferenced after this allocation got freed --> $DIR/thread_local_static_dealloc.rs:LL:CC | @@ -14,5 +11,5 @@ LL | let _val = *(dangling_ptr as *const u8); note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace -error: aborting due to previous error; 1 warning emitted +error: aborting due to previous error diff --git a/tests/fail/concurrency/too_few_args.stderr b/tests/fail/concurrency/too_few_args.stderr index 1ed8c5a510f4f..9d96b718bc305 100644 --- a/tests/fail/concurrency/too_few_args.stderr +++ b/tests/fail/concurrency/too_few_args.stderr @@ -1,6 +1,3 @@ -warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. - (see https://github.com/rust-lang/miri/issues/1388) - error: Undefined Behavior: callee has fewer arguments than expected --> $DIR/too_few_args.rs:LL:CC | @@ -13,5 +10,5 @@ LL | panic!() = note: inside `thread_start` at RUSTLIB/std/src/panic.rs:LL:CC = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) -error: aborting due to previous error; 1 warning emitted +error: aborting due to previous error diff --git a/tests/fail/concurrency/too_many_args.stderr b/tests/fail/concurrency/too_many_args.stderr index 5602dab993b08..7132b8c453afa 100644 --- a/tests/fail/concurrency/too_many_args.stderr +++ b/tests/fail/concurrency/too_many_args.stderr @@ -1,6 +1,3 @@ -warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. - (see https://github.com/rust-lang/miri/issues/1388) - error: Undefined Behavior: callee has more arguments than expected --> $DIR/too_many_args.rs:LL:CC | @@ -13,5 +10,5 @@ LL | panic!() = note: inside `thread_start` at RUSTLIB/std/src/panic.rs:LL:CC = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) -error: aborting due to previous error; 1 warning emitted +error: aborting due to previous error diff --git a/tests/fail/concurrency/unwind_top_of_stack.stderr b/tests/fail/concurrency/unwind_top_of_stack.stderr index 26a196a5590f1..35d6f7c384940 100644 --- a/tests/fail/concurrency/unwind_top_of_stack.stderr +++ b/tests/fail/concurrency/unwind_top_of_stack.stderr @@ -1,6 +1,3 @@ -warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. - (see https://github.com/rust-lang/miri/issues/1388) - thread '' panicked at 'explicit panic', $DIR/unwind_top_of_stack.rs:LL:CC note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace error: Undefined Behavior: unwinding past the topmost frame of the stack @@ -16,5 +13,5 @@ LL | | } = note: inside `thread_start` at $DIR/unwind_top_of_stack.rs:LL:CC -error: aborting due to previous error; 1 warning emitted +error: aborting due to previous error diff --git a/tests/fail/data_race/alloc_read_race.stderr b/tests/fail/data_race/alloc_read_race.stderr index 0b247fb19bc9c..52004f2d2d025 100644 --- a/tests/fail/data_race/alloc_read_race.stderr +++ b/tests/fail/data_race/alloc_read_race.stderr @@ -1,6 +1,3 @@ -warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. - (see https://github.com/rust-lang/miri/issues/1388) - error: Undefined Behavior: Data race detected between Read on Thread(id = 2) and Allocate on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) --> $DIR/alloc_read_race.rs:LL:CC | @@ -14,5 +11,5 @@ LL | *pointer.load(Ordering::Relaxed) note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace -error: aborting due to previous error; 1 warning emitted +error: aborting due to previous error diff --git a/tests/fail/data_race/alloc_write_race.stderr b/tests/fail/data_race/alloc_write_race.stderr index 3594980ef9b02..b6c05b34073c5 100644 --- a/tests/fail/data_race/alloc_write_race.stderr +++ b/tests/fail/data_race/alloc_write_race.stderr @@ -1,6 +1,3 @@ -warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. - (see https://github.com/rust-lang/miri/issues/1388) - error: Undefined Behavior: Data race detected between Write on Thread(id = 2) and Allocate on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) --> $DIR/alloc_write_race.rs:LL:CC | @@ -14,5 +11,5 @@ LL | *pointer.load(Ordering::Relaxed) = 2; note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace -error: aborting due to previous error; 1 warning emitted +error: aborting due to previous error diff --git a/tests/fail/data_race/atomic_read_na_write_race1.stderr b/tests/fail/data_race/atomic_read_na_write_race1.stderr index 0c9aaf5a0019a..80e79eb553ee9 100644 --- a/tests/fail/data_race/atomic_read_na_write_race1.stderr +++ b/tests/fail/data_race/atomic_read_na_write_race1.stderr @@ -1,6 +1,3 @@ -warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. - (see https://github.com/rust-lang/miri/issues/1388) - error: Undefined Behavior: Data race detected between Atomic Load on Thread(id = 2) and Write on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) --> $DIR/atomic_read_na_write_race1.rs:LL:CC | @@ -14,5 +11,5 @@ LL | atomic_load(c.0 as *mut usize) note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace -error: aborting due to previous error; 1 warning emitted +error: aborting due to previous error diff --git a/tests/fail/data_race/atomic_read_na_write_race2.stderr b/tests/fail/data_race/atomic_read_na_write_race2.stderr index 6e3a1330f9dd6..9a432c586afe7 100644 --- a/tests/fail/data_race/atomic_read_na_write_race2.stderr +++ b/tests/fail/data_race/atomic_read_na_write_race2.stderr @@ -1,6 +1,3 @@ -warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. - (see https://github.com/rust-lang/miri/issues/1388) - error: Undefined Behavior: Data race detected between Write on Thread(id = 2) and Atomic Load on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) --> $DIR/atomic_read_na_write_race2.rs:LL:CC | @@ -14,5 +11,5 @@ LL | *atomic_ref.get_mut() = 32; note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace -error: aborting due to previous error; 1 warning emitted +error: aborting due to previous error diff --git a/tests/fail/data_race/atomic_write_na_read_race1.stderr b/tests/fail/data_race/atomic_write_na_read_race1.stderr index 4dc4ac1e6768e..8280f43b518fe 100644 --- a/tests/fail/data_race/atomic_write_na_read_race1.stderr +++ b/tests/fail/data_race/atomic_write_na_read_race1.stderr @@ -1,6 +1,3 @@ -warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. - (see https://github.com/rust-lang/miri/issues/1388) - error: Undefined Behavior: Data race detected between Read on Thread(id = 2) and Atomic Store on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) --> $DIR/atomic_write_na_read_race1.rs:LL:CC | @@ -14,5 +11,5 @@ LL | *atomic_ref.get_mut() note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace -error: aborting due to previous error; 1 warning emitted +error: aborting due to previous error diff --git a/tests/fail/data_race/atomic_write_na_read_race2.stderr b/tests/fail/data_race/atomic_write_na_read_race2.stderr index e665073c539e2..63d0f5814ef4d 100644 --- a/tests/fail/data_race/atomic_write_na_read_race2.stderr +++ b/tests/fail/data_race/atomic_write_na_read_race2.stderr @@ -1,6 +1,3 @@ -warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. - (see https://github.com/rust-lang/miri/issues/1388) - error: Undefined Behavior: Data race detected between Atomic Store on Thread(id = 2) and Read on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) --> $DIR/atomic_write_na_read_race2.rs:LL:CC | @@ -14,5 +11,5 @@ LL | atomic_store(c.0 as *mut usize, 32); note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace -error: aborting due to previous error; 1 warning emitted +error: aborting due to previous error diff --git a/tests/fail/data_race/atomic_write_na_write_race1.stderr b/tests/fail/data_race/atomic_write_na_write_race1.stderr index a70c3b52de503..332be7406c82d 100644 --- a/tests/fail/data_race/atomic_write_na_write_race1.stderr +++ b/tests/fail/data_race/atomic_write_na_write_race1.stderr @@ -1,6 +1,3 @@ -warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. - (see https://github.com/rust-lang/miri/issues/1388) - error: Undefined Behavior: Data race detected between Atomic Store on Thread(id = 2) and Write on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) --> $DIR/atomic_write_na_write_race1.rs:LL:CC | @@ -14,5 +11,5 @@ LL | atomic_store(c.0 as *mut usize, 64); note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace -error: aborting due to previous error; 1 warning emitted +error: aborting due to previous error diff --git a/tests/fail/data_race/atomic_write_na_write_race2.stderr b/tests/fail/data_race/atomic_write_na_write_race2.stderr index 79730d507934c..024f525b12135 100644 --- a/tests/fail/data_race/atomic_write_na_write_race2.stderr +++ b/tests/fail/data_race/atomic_write_na_write_race2.stderr @@ -1,6 +1,3 @@ -warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. - (see https://github.com/rust-lang/miri/issues/1388) - error: Undefined Behavior: Data race detected between Write on Thread(id = 2) and Atomic Store on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) --> $DIR/atomic_write_na_write_race2.rs:LL:CC | @@ -14,5 +11,5 @@ LL | *atomic_ref.get_mut() = 32; note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace -error: aborting due to previous error; 1 warning emitted +error: aborting due to previous error diff --git a/tests/fail/data_race/dangling_thread_async_race.stderr b/tests/fail/data_race/dangling_thread_async_race.stderr index 21b3eefc5e418..6d31e3971e530 100644 --- a/tests/fail/data_race/dangling_thread_async_race.stderr +++ b/tests/fail/data_race/dangling_thread_async_race.stderr @@ -1,6 +1,3 @@ -warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. - (see https://github.com/rust-lang/miri/issues/1388) - error: Undefined Behavior: Data race detected between Write on Thread(id = 3) and Write on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) --> $DIR/dangling_thread_async_race.rs:LL:CC | @@ -14,5 +11,5 @@ LL | *c.0 = 64; note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace -error: aborting due to previous error; 1 warning emitted +error: aborting due to previous error diff --git a/tests/fail/data_race/dangling_thread_race.stderr b/tests/fail/data_race/dangling_thread_race.stderr index 3ca8862a5819a..ba1ef2760f8f6 100644 --- a/tests/fail/data_race/dangling_thread_race.stderr +++ b/tests/fail/data_race/dangling_thread_race.stderr @@ -1,6 +1,3 @@ -warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. - (see https://github.com/rust-lang/miri/issues/1388) - error: Undefined Behavior: Data race detected between Write on Thread(id = 0, name = "main") and Write on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) --> $DIR/dangling_thread_race.rs:LL:CC | @@ -14,5 +11,5 @@ LL | *c.0 = 64; note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace -error: aborting due to previous error; 1 warning emitted +error: aborting due to previous error diff --git a/tests/fail/data_race/dealloc_read_race1.stderr b/tests/fail/data_race/dealloc_read_race1.stderr index 10b32003ff400..6b5cf5fc02f64 100644 --- a/tests/fail/data_race/dealloc_read_race1.stderr +++ b/tests/fail/data_race/dealloc_read_race1.stderr @@ -1,6 +1,3 @@ -warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. - (see https://github.com/rust-lang/miri/issues/1388) - error: Undefined Behavior: Data race detected between Deallocate on Thread(id = 2) and Read on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) --> $DIR/dealloc_read_race1.rs:LL:CC | @@ -14,5 +11,5 @@ LL | __rust_dealloc(ptr.0 as *mut _, std::mem::size_of::(), s note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace -error: aborting due to previous error; 1 warning emitted +error: aborting due to previous error diff --git a/tests/fail/data_race/dealloc_read_race2.stderr b/tests/fail/data_race/dealloc_read_race2.stderr index a21de1d9f7a9f..f703d1896d91f 100644 --- a/tests/fail/data_race/dealloc_read_race2.stderr +++ b/tests/fail/data_race/dealloc_read_race2.stderr @@ -1,6 +1,3 @@ -warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. - (see https://github.com/rust-lang/miri/issues/1388) - error: Undefined Behavior: pointer to ALLOC was dereferenced after this allocation got freed --> $DIR/dealloc_read_race2.rs:LL:CC | @@ -14,5 +11,5 @@ LL | *ptr.0 note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace -error: aborting due to previous error; 1 warning emitted +error: aborting due to previous error diff --git a/tests/fail/data_race/dealloc_read_race_stack.stderr b/tests/fail/data_race/dealloc_read_race_stack.stderr index 0f7213eb8d521..1275d1290b0ac 100644 --- a/tests/fail/data_race/dealloc_read_race_stack.stderr +++ b/tests/fail/data_race/dealloc_read_race_stack.stderr @@ -1,6 +1,3 @@ -warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. - (see https://github.com/rust-lang/miri/issues/1388) - error: Undefined Behavior: Data race detected between Deallocate on Thread(id = 1) and Read on Thread(id = 2) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) --> $DIR/dealloc_read_race_stack.rs:LL:CC | @@ -14,5 +11,5 @@ LL | } note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace -error: aborting due to previous error; 1 warning emitted +error: aborting due to previous error diff --git a/tests/fail/data_race/dealloc_write_race1.stderr b/tests/fail/data_race/dealloc_write_race1.stderr index 76258e9d8fc0b..ac9701d49f5f7 100644 --- a/tests/fail/data_race/dealloc_write_race1.stderr +++ b/tests/fail/data_race/dealloc_write_race1.stderr @@ -1,6 +1,3 @@ -warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. - (see https://github.com/rust-lang/miri/issues/1388) - error: Undefined Behavior: Data race detected between Deallocate on Thread(id = 2) and Write on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) --> $DIR/dealloc_write_race1.rs:LL:CC | @@ -14,5 +11,5 @@ LL | __rust_dealloc(ptr.0 as *mut _, std::mem::size_of::(), s note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace -error: aborting due to previous error; 1 warning emitted +error: aborting due to previous error diff --git a/tests/fail/data_race/dealloc_write_race2.stderr b/tests/fail/data_race/dealloc_write_race2.stderr index d9aef72118d89..37d1c551d4935 100644 --- a/tests/fail/data_race/dealloc_write_race2.stderr +++ b/tests/fail/data_race/dealloc_write_race2.stderr @@ -1,6 +1,3 @@ -warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. - (see https://github.com/rust-lang/miri/issues/1388) - error: Undefined Behavior: pointer to ALLOC was dereferenced after this allocation got freed --> $DIR/dealloc_write_race2.rs:LL:CC | @@ -14,5 +11,5 @@ LL | *ptr.0 = 2; note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace -error: aborting due to previous error; 1 warning emitted +error: aborting due to previous error diff --git a/tests/fail/data_race/dealloc_write_race_stack.stderr b/tests/fail/data_race/dealloc_write_race_stack.stderr index 70533f654b777..28a131aac07b5 100644 --- a/tests/fail/data_race/dealloc_write_race_stack.stderr +++ b/tests/fail/data_race/dealloc_write_race_stack.stderr @@ -1,6 +1,3 @@ -warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. - (see https://github.com/rust-lang/miri/issues/1388) - error: Undefined Behavior: Data race detected between Deallocate on Thread(id = 1) and Write on Thread(id = 2) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) --> $DIR/dealloc_write_race_stack.rs:LL:CC | @@ -14,5 +11,5 @@ LL | } note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace -error: aborting due to previous error; 1 warning emitted +error: aborting due to previous error diff --git a/tests/fail/data_race/enable_after_join_to_main.stderr b/tests/fail/data_race/enable_after_join_to_main.stderr index 58d33ffa8cf3c..db7577b0966e5 100644 --- a/tests/fail/data_race/enable_after_join_to_main.stderr +++ b/tests/fail/data_race/enable_after_join_to_main.stderr @@ -1,6 +1,3 @@ -warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. - (see https://github.com/rust-lang/miri/issues/1388) - error: Undefined Behavior: Data race detected between Write on Thread(id = 6) and Write on Thread(id = 5) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) --> $DIR/enable_after_join_to_main.rs:LL:CC | @@ -14,5 +11,5 @@ LL | *c.0 = 64; note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace -error: aborting due to previous error; 1 warning emitted +error: aborting due to previous error diff --git a/tests/fail/data_race/fence_after_load.stderr b/tests/fail/data_race/fence_after_load.stderr index 1e3186b08fa11..17cc6a82a1c2a 100644 --- a/tests/fail/data_race/fence_after_load.stderr +++ b/tests/fail/data_race/fence_after_load.stderr @@ -1,6 +1,3 @@ -warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. - (see https://github.com/rust-lang/miri/issues/1388) - error: Undefined Behavior: Data race detected between Write on Thread(id = 0, name = "main") and Write on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) --> $DIR/fence_after_load.rs:LL:CC | @@ -14,5 +11,5 @@ LL | unsafe { V = 2 } note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace -error: aborting due to previous error; 1 warning emitted +error: aborting due to previous error diff --git a/tests/fail/data_race/read_write_race.stderr b/tests/fail/data_race/read_write_race.stderr index 5078e662546a8..b775e2b6fdf1f 100644 --- a/tests/fail/data_race/read_write_race.stderr +++ b/tests/fail/data_race/read_write_race.stderr @@ -1,6 +1,3 @@ -warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. - (see https://github.com/rust-lang/miri/issues/1388) - error: Undefined Behavior: Data race detected between Write on Thread(id = 2) and Read on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) --> $DIR/read_write_race.rs:LL:CC | @@ -14,5 +11,5 @@ LL | *c.0 = 64; note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace -error: aborting due to previous error; 1 warning emitted +error: aborting due to previous error diff --git a/tests/fail/data_race/read_write_race_stack.stderr b/tests/fail/data_race/read_write_race_stack.stderr index 843bea753b651..0f5f4956ffdae 100644 --- a/tests/fail/data_race/read_write_race_stack.stderr +++ b/tests/fail/data_race/read_write_race_stack.stderr @@ -1,6 +1,3 @@ -warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. - (see https://github.com/rust-lang/miri/issues/1388) - error: Undefined Behavior: Data race detected between Read on Thread(id = 1) and Write on Thread(id = 2) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) --> $DIR/read_write_race_stack.rs:LL:CC | @@ -14,5 +11,5 @@ LL | stack_var note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace -error: aborting due to previous error; 1 warning emitted +error: aborting due to previous error diff --git a/tests/fail/data_race/relax_acquire_race.stderr b/tests/fail/data_race/relax_acquire_race.stderr index d2423ff916316..fb376b58f2c16 100644 --- a/tests/fail/data_race/relax_acquire_race.stderr +++ b/tests/fail/data_race/relax_acquire_race.stderr @@ -1,6 +1,3 @@ -warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. - (see https://github.com/rust-lang/miri/issues/1388) - error: Undefined Behavior: Data race detected between Read on Thread(id = 3) and Write on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) --> $DIR/relax_acquire_race.rs:LL:CC | @@ -14,5 +11,5 @@ LL | *c.0 note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace -error: aborting due to previous error; 1 warning emitted +error: aborting due to previous error diff --git a/tests/fail/data_race/release_seq_race.stderr b/tests/fail/data_race/release_seq_race.stderr index ffbf50c09172d..1de9c0ac1c7fd 100644 --- a/tests/fail/data_race/release_seq_race.stderr +++ b/tests/fail/data_race/release_seq_race.stderr @@ -1,6 +1,3 @@ -warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. - (see https://github.com/rust-lang/miri/issues/1388) - error: Undefined Behavior: Data race detected between Read on Thread(id = 3) and Write on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) --> $DIR/release_seq_race.rs:LL:CC | @@ -14,5 +11,5 @@ LL | *c.0 note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace -error: aborting due to previous error; 1 warning emitted +error: aborting due to previous error diff --git a/tests/fail/data_race/release_seq_race_same_thread.stderr b/tests/fail/data_race/release_seq_race_same_thread.stderr index b760215146113..9bbdd9a475733 100644 --- a/tests/fail/data_race/release_seq_race_same_thread.stderr +++ b/tests/fail/data_race/release_seq_race_same_thread.stderr @@ -1,6 +1,3 @@ -warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. - (see https://github.com/rust-lang/miri/issues/1388) - error: Undefined Behavior: Data race detected between Read on Thread(id = 2) and Write on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) --> $DIR/release_seq_race_same_thread.rs:LL:CC | @@ -14,5 +11,5 @@ LL | *c.0 note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace -error: aborting due to previous error; 1 warning emitted +error: aborting due to previous error diff --git a/tests/fail/data_race/rmw_race.stderr b/tests/fail/data_race/rmw_race.stderr index c6b09ba5f00bc..10d3291fa733d 100644 --- a/tests/fail/data_race/rmw_race.stderr +++ b/tests/fail/data_race/rmw_race.stderr @@ -1,6 +1,3 @@ -warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. - (see https://github.com/rust-lang/miri/issues/1388) - error: Undefined Behavior: Data race detected between Read on Thread(id = 3) and Write on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) --> $DIR/rmw_race.rs:LL:CC | @@ -14,5 +11,5 @@ LL | *c.0 note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace -error: aborting due to previous error; 1 warning emitted +error: aborting due to previous error diff --git a/tests/fail/data_race/write_write_race.stderr b/tests/fail/data_race/write_write_race.stderr index 5acba97486eab..0054f5bf63a05 100644 --- a/tests/fail/data_race/write_write_race.stderr +++ b/tests/fail/data_race/write_write_race.stderr @@ -1,6 +1,3 @@ -warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. - (see https://github.com/rust-lang/miri/issues/1388) - error: Undefined Behavior: Data race detected between Write on Thread(id = 2) and Write on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) --> $DIR/write_write_race.rs:LL:CC | @@ -14,5 +11,5 @@ LL | *c.0 = 64; note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace -error: aborting due to previous error; 1 warning emitted +error: aborting due to previous error diff --git a/tests/fail/data_race/write_write_race_stack.stderr b/tests/fail/data_race/write_write_race_stack.stderr index d052206f4cc72..2012643431f6e 100644 --- a/tests/fail/data_race/write_write_race_stack.stderr +++ b/tests/fail/data_race/write_write_race_stack.stderr @@ -1,6 +1,3 @@ -warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. - (see https://github.com/rust-lang/miri/issues/1388) - error: Undefined Behavior: Data race detected between Write on Thread(id = 1) and Write on Thread(id = 2) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) --> $DIR/write_write_race_stack.rs:LL:CC | @@ -14,5 +11,5 @@ LL | stack_var = 1usize; note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace -error: aborting due to previous error; 1 warning emitted +error: aborting due to previous error diff --git a/tests/fail/should-pass/cpp20_rwc_syncs.rs b/tests/fail/should-pass/cpp20_rwc_syncs.rs index e5192cd0d6706..00b03bceb65e4 100644 --- a/tests/fail/should-pass/cpp20_rwc_syncs.rs +++ b/tests/fail/should-pass/cpp20_rwc_syncs.rs @@ -1,6 +1,6 @@ // ignore-windows: Concurrency on Windows is not supported yet. // compile-flags: -Zmiri-ignore-leaks -// error-pattern: +// error-pattern: unreachable // https://plv.mpi-sws.org/scfix/paper.pdf // 2.2 Second Problem: SC Fences are Too Weak @@ -76,7 +76,7 @@ fn test_cpp20_rwc_syncs() { // Our ui_test does not yet support overriding failure status codes. if (b, c) == (0, 0) { // This *should* be unreachable, but Miri will reach it. - std::process::exit(1); + unsafe { std::hint::unreachable_unchecked(); } } } diff --git a/tests/fail/should-pass/cpp20_rwc_syncs.stderr b/tests/fail/should-pass/cpp20_rwc_syncs.stderr index 9fe6daa778c1f..9aec82d333654 100644 --- a/tests/fail/should-pass/cpp20_rwc_syncs.stderr +++ b/tests/fail/should-pass/cpp20_rwc_syncs.stderr @@ -1,3 +1,25 @@ -warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. - (see https://github.com/rust-lang/miri/issues/1388) +error: Undefined Behavior: entering unreachable code + --> RUSTLIB/core/src/hint.rs:LL:CC + | +LL | unsafe { intrinsics::unreachable() } + | ^^^^^^^^^^^^^^^^^^^^^^^^^ entering unreachable code + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `std::hint::unreachable_unchecked` at RUSTLIB/core/src/hint.rs:LL:CC +note: inside `test_cpp20_rwc_syncs` at $DIR/cpp20_rwc_syncs.rs:LL:CC + --> $DIR/cpp20_rwc_syncs.rs:LL:CC + | +LL | unsafe { std::hint::unreachable_unchecked(); } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: inside `main` at $DIR/cpp20_rwc_syncs.rs:LL:CC + --> $DIR/cpp20_rwc_syncs.rs:LL:CC + | +LL | test_cpp20_rwc_syncs(); + | ^^^^^^^^^^^^^^^^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error diff --git a/tests/fail/sync/libc_pthread_mutex_deadlock.stderr b/tests/fail/sync/libc_pthread_mutex_deadlock.stderr index d1f9ee6cdd5f1..599655a8692b1 100644 --- a/tests/fail/sync/libc_pthread_mutex_deadlock.stderr +++ b/tests/fail/sync/libc_pthread_mutex_deadlock.stderr @@ -1,6 +1,3 @@ -warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. - (see https://github.com/rust-lang/miri/issues/1388) - error: deadlock: the evaluated program deadlocked --> $DIR/libc_pthread_mutex_deadlock.rs:LL:CC | @@ -11,5 +8,5 @@ LL | assert_eq!(libc::pthread_mutex_lock(lock_copy.0.get() as *mut _ note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace -error: aborting due to previous error; 1 warning emitted +error: aborting due to previous error diff --git a/tests/fail/sync/libc_pthread_mutex_wrong_owner.stderr b/tests/fail/sync/libc_pthread_mutex_wrong_owner.stderr index e9f0e2d4c1573..86d02c22819e8 100644 --- a/tests/fail/sync/libc_pthread_mutex_wrong_owner.stderr +++ b/tests/fail/sync/libc_pthread_mutex_wrong_owner.stderr @@ -1,6 +1,3 @@ -warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. - (see https://github.com/rust-lang/miri/issues/1388) - error: Undefined Behavior: unlocked a default mutex that was not locked by the current thread --> $DIR/libc_pthread_mutex_wrong_owner.rs:LL:CC | @@ -14,5 +11,5 @@ LL | ...t_eq!(libc::pthread_mutex_unlock(lock_copy.0.get() as *mut _), 0); note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace -error: aborting due to previous error; 1 warning emitted +error: aborting due to previous error diff --git a/tests/fail/sync/libc_pthread_rwlock_read_wrong_owner.stderr b/tests/fail/sync/libc_pthread_rwlock_read_wrong_owner.stderr index c25ab25a3da5b..c7c8823eaa371 100644 --- a/tests/fail/sync/libc_pthread_rwlock_read_wrong_owner.stderr +++ b/tests/fail/sync/libc_pthread_rwlock_read_wrong_owner.stderr @@ -1,6 +1,3 @@ -warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. - (see https://github.com/rust-lang/miri/issues/1388) - error: Undefined Behavior: unlocked an rwlock that was not locked by the active thread --> $DIR/libc_pthread_rwlock_read_wrong_owner.rs:LL:CC | @@ -14,5 +11,5 @@ LL | ... assert_eq!(libc::pthread_rwlock_unlock(lock_copy.0.get() as *mut _), note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace -error: aborting due to previous error; 1 warning emitted +error: aborting due to previous error diff --git a/tests/fail/sync/libc_pthread_rwlock_write_read_deadlock.stderr b/tests/fail/sync/libc_pthread_rwlock_write_read_deadlock.stderr index 8fc2ae4c82e56..333fb1afb91b7 100644 --- a/tests/fail/sync/libc_pthread_rwlock_write_read_deadlock.stderr +++ b/tests/fail/sync/libc_pthread_rwlock_write_read_deadlock.stderr @@ -1,6 +1,3 @@ -warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. - (see https://github.com/rust-lang/miri/issues/1388) - error: deadlock: the evaluated program deadlocked --> $DIR/libc_pthread_rwlock_write_read_deadlock.rs:LL:CC | @@ -11,5 +8,5 @@ LL | assert_eq!(libc::pthread_rwlock_wrlock(lock_copy.0.get() as *mu note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace -error: aborting due to previous error; 1 warning emitted +error: aborting due to previous error diff --git a/tests/fail/sync/libc_pthread_rwlock_write_write_deadlock.stderr b/tests/fail/sync/libc_pthread_rwlock_write_write_deadlock.stderr index 86c67925fb935..93bede54fcf18 100644 --- a/tests/fail/sync/libc_pthread_rwlock_write_write_deadlock.stderr +++ b/tests/fail/sync/libc_pthread_rwlock_write_write_deadlock.stderr @@ -1,6 +1,3 @@ -warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. - (see https://github.com/rust-lang/miri/issues/1388) - error: deadlock: the evaluated program deadlocked --> $DIR/libc_pthread_rwlock_write_write_deadlock.rs:LL:CC | @@ -11,5 +8,5 @@ LL | assert_eq!(libc::pthread_rwlock_wrlock(lock_copy.0.get() as *mu note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace -error: aborting due to previous error; 1 warning emitted +error: aborting due to previous error diff --git a/tests/fail/sync/libc_pthread_rwlock_write_wrong_owner.stderr b/tests/fail/sync/libc_pthread_rwlock_write_wrong_owner.stderr index 8965d55a489d1..a7a17ae71b3ad 100644 --- a/tests/fail/sync/libc_pthread_rwlock_write_wrong_owner.stderr +++ b/tests/fail/sync/libc_pthread_rwlock_write_wrong_owner.stderr @@ -1,6 +1,3 @@ -warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. - (see https://github.com/rust-lang/miri/issues/1388) - error: Undefined Behavior: unlocked an rwlock that was not locked by the active thread --> $DIR/libc_pthread_rwlock_write_wrong_owner.rs:LL:CC | @@ -14,5 +11,5 @@ LL | ... assert_eq!(libc::pthread_rwlock_unlock(lock_copy.0.get() as *mut _), note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace -error: aborting due to previous error; 1 warning emitted +error: aborting due to previous error diff --git a/tests/fail/weak_memory/racing_mixed_size.stderr b/tests/fail/weak_memory/racing_mixed_size.stderr index fc6be84315d77..0fb23be06bb78 100644 --- a/tests/fail/weak_memory/racing_mixed_size.stderr +++ b/tests/fail/weak_memory/racing_mixed_size.stderr @@ -1,6 +1,3 @@ -warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. - (see https://github.com/rust-lang/miri/issues/1388) - error: unsupported operation: racy imperfectly overlapping atomic access is not possible in the C++20 memory model, and not supported by Miri's weak memory emulation --> $DIR/racing_mixed_size.rs:LL:CC | @@ -13,5 +10,5 @@ LL | std::intrinsics::atomic_load_relaxed(hi); note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace -error: aborting due to previous error; 1 warning emitted +error: aborting due to previous error diff --git a/tests/fail/weak_memory/racing_mixed_size_read.stderr b/tests/fail/weak_memory/racing_mixed_size_read.stderr index 846d03f5448ff..6de185161084b 100644 --- a/tests/fail/weak_memory/racing_mixed_size_read.stderr +++ b/tests/fail/weak_memory/racing_mixed_size_read.stderr @@ -1,6 +1,3 @@ -warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. - (see https://github.com/rust-lang/miri/issues/1388) - error: unsupported operation: racy imperfectly overlapping atomic access is not possible in the C++20 memory model, and not supported by Miri's weak memory emulation --> $DIR/racing_mixed_size_read.rs:LL:CC | @@ -13,5 +10,5 @@ LL | std::intrinsics::atomic_load_relaxed(hi); note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace -error: aborting due to previous error; 1 warning emitted +error: aborting due to previous error diff --git a/tests/pass/concurrency/channels.stderr b/tests/pass/concurrency/channels.stderr deleted file mode 100644 index 9fe6daa778c1f..0000000000000 --- a/tests/pass/concurrency/channels.stderr +++ /dev/null @@ -1,3 +0,0 @@ -warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. - (see https://github.com/rust-lang/miri/issues/1388) - diff --git a/tests/pass/concurrency/concurrent_caller_location.stderr b/tests/pass/concurrency/concurrent_caller_location.stderr deleted file mode 100644 index 9fe6daa778c1f..0000000000000 --- a/tests/pass/concurrency/concurrent_caller_location.stderr +++ /dev/null @@ -1,3 +0,0 @@ -warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. - (see https://github.com/rust-lang/miri/issues/1388) - diff --git a/tests/pass/concurrency/data_race.stderr b/tests/pass/concurrency/data_race.stderr deleted file mode 100644 index 9fe6daa778c1f..0000000000000 --- a/tests/pass/concurrency/data_race.stderr +++ /dev/null @@ -1,3 +0,0 @@ -warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. - (see https://github.com/rust-lang/miri/issues/1388) - diff --git a/tests/pass/concurrency/disable_data_race_detector.stderr b/tests/pass/concurrency/disable_data_race_detector.stderr deleted file mode 100644 index 9fe6daa778c1f..0000000000000 --- a/tests/pass/concurrency/disable_data_race_detector.stderr +++ /dev/null @@ -1,3 +0,0 @@ -warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. - (see https://github.com/rust-lang/miri/issues/1388) - diff --git a/tests/pass/concurrency/issue1643.stderr b/tests/pass/concurrency/issue1643.stderr deleted file mode 100644 index 9fe6daa778c1f..0000000000000 --- a/tests/pass/concurrency/issue1643.stderr +++ /dev/null @@ -1,3 +0,0 @@ -warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. - (see https://github.com/rust-lang/miri/issues/1388) - diff --git a/tests/pass/concurrency/linux-futex.stderr b/tests/pass/concurrency/linux-futex.stderr deleted file mode 100644 index 9fe6daa778c1f..0000000000000 --- a/tests/pass/concurrency/linux-futex.stderr +++ /dev/null @@ -1,3 +0,0 @@ -warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. - (see https://github.com/rust-lang/miri/issues/1388) - diff --git a/tests/pass/concurrency/simple.stderr b/tests/pass/concurrency/simple.stderr index 0ba9e8645b28a..028cc0fb736ff 100644 --- a/tests/pass/concurrency/simple.stderr +++ b/tests/pass/concurrency/simple.stderr @@ -1,6 +1,3 @@ -warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. - (see https://github.com/rust-lang/miri/issues/1388) - thread '' panicked at 'Hello!', $DIR/simple.rs:LL:CC note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace thread 'childthread' panicked at 'Hello, world!', $DIR/simple.rs:LL:CC diff --git a/tests/pass/concurrency/spin_loop.stderr b/tests/pass/concurrency/spin_loop.stderr deleted file mode 100644 index 9fe6daa778c1f..0000000000000 --- a/tests/pass/concurrency/spin_loop.stderr +++ /dev/null @@ -1,3 +0,0 @@ -warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. - (see https://github.com/rust-lang/miri/issues/1388) - diff --git a/tests/pass/concurrency/spin_loops_nopreempt.stderr b/tests/pass/concurrency/spin_loops_nopreempt.stderr deleted file mode 100644 index 9fe6daa778c1f..0000000000000 --- a/tests/pass/concurrency/spin_loops_nopreempt.stderr +++ /dev/null @@ -1,3 +0,0 @@ -warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. - (see https://github.com/rust-lang/miri/issues/1388) - diff --git a/tests/pass/concurrency/sync.stderr b/tests/pass/concurrency/sync.stderr deleted file mode 100644 index 9fe6daa778c1f..0000000000000 --- a/tests/pass/concurrency/sync.stderr +++ /dev/null @@ -1,3 +0,0 @@ -warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. - (see https://github.com/rust-lang/miri/issues/1388) - diff --git a/tests/pass/concurrency/thread_locals.stderr b/tests/pass/concurrency/thread_locals.stderr deleted file mode 100644 index 9fe6daa778c1f..0000000000000 --- a/tests/pass/concurrency/thread_locals.stderr +++ /dev/null @@ -1,3 +0,0 @@ -warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. - (see https://github.com/rust-lang/miri/issues/1388) - diff --git a/tests/pass/concurrency/tls_lib_drop.stderr b/tests/pass/concurrency/tls_lib_drop.stderr deleted file mode 100644 index 9fe6daa778c1f..0000000000000 --- a/tests/pass/concurrency/tls_lib_drop.stderr +++ /dev/null @@ -1,3 +0,0 @@ -warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. - (see https://github.com/rust-lang/miri/issues/1388) - diff --git a/tests/pass/libc.stderr b/tests/pass/libc.stderr deleted file mode 100644 index 9fe6daa778c1f..0000000000000 --- a/tests/pass/libc.stderr +++ /dev/null @@ -1,3 +0,0 @@ -warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. - (see https://github.com/rust-lang/miri/issues/1388) - diff --git a/tests/pass/panic/concurrent-panic.stderr b/tests/pass/panic/concurrent-panic.stderr index b90cc01bb857e..fd8fabc89cccf 100644 --- a/tests/pass/panic/concurrent-panic.stderr +++ b/tests/pass/panic/concurrent-panic.stderr @@ -1,6 +1,3 @@ -warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. - (see https://github.com/rust-lang/miri/issues/1388) - Thread 1 starting, will block on mutex Thread 1 reported it has started thread '' panicked at 'panic in thread 2', $DIR/concurrent-panic.rs:LL:CC diff --git a/tests/pass/threadleak_ignored.stderr b/tests/pass/threadleak_ignored.stderr index af327a3012c37..7557f49c7584b 100644 --- a/tests/pass/threadleak_ignored.stderr +++ b/tests/pass/threadleak_ignored.stderr @@ -1,4 +1 @@ -warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. - (see https://github.com/rust-lang/miri/issues/1388) - Dropping 0 diff --git a/tests/pass/weak_memory/consistency.stderr b/tests/pass/weak_memory/consistency.stderr deleted file mode 100644 index 9fe6daa778c1f..0000000000000 --- a/tests/pass/weak_memory/consistency.stderr +++ /dev/null @@ -1,3 +0,0 @@ -warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. - (see https://github.com/rust-lang/miri/issues/1388) - diff --git a/tests/pass/weak_memory/extra_cpp.stderr b/tests/pass/weak_memory/extra_cpp.stderr deleted file mode 100644 index 9fe6daa778c1f..0000000000000 --- a/tests/pass/weak_memory/extra_cpp.stderr +++ /dev/null @@ -1,3 +0,0 @@ -warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. - (see https://github.com/rust-lang/miri/issues/1388) - diff --git a/tests/pass/weak_memory/extra_cpp_unsafe.stderr b/tests/pass/weak_memory/extra_cpp_unsafe.stderr deleted file mode 100644 index 9fe6daa778c1f..0000000000000 --- a/tests/pass/weak_memory/extra_cpp_unsafe.stderr +++ /dev/null @@ -1,3 +0,0 @@ -warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. - (see https://github.com/rust-lang/miri/issues/1388) - diff --git a/tests/pass/weak_memory/weak.stderr b/tests/pass/weak_memory/weak.stderr deleted file mode 100644 index 9fe6daa778c1f..0000000000000 --- a/tests/pass/weak_memory/weak.stderr +++ /dev/null @@ -1,3 +0,0 @@ -warning: thread support is experimental: the scheduler is not preemptive, and can get stuck in spin loops. - (see https://github.com/rust-lang/miri/issues/1388) - From 61f5680da02206b4d3c354100f2e8341fde6c2a0 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 7 Jun 2022 07:58:21 -0400 Subject: [PATCH 3224/3747] add stdlib test for TLS dtor order --- tests/pass/concurrency/tls_lib_drop.rs | 109 +++++++++++++++++++++++++ 1 file changed, 109 insertions(+) diff --git a/tests/pass/concurrency/tls_lib_drop.rs b/tests/pass/concurrency/tls_lib_drop.rs index 86f03bac34f61..552b371cc7f12 100644 --- a/tests/pass/concurrency/tls_lib_drop.rs +++ b/tests/pass/concurrency/tls_lib_drop.rs @@ -71,7 +71,116 @@ fn check_blocking() { thread::yield_now(); } +// This test tests that TLS destructors have run before the thread joins. The +// test has no false positives (meaning: if the test fails, there's actually +// an ordering problem). It may have false negatives, where the test passes but +// join is not guaranteed to be after the TLS destructors. However, false +// negatives should be exceedingly rare due to judicious use of +// thread::yield_now and running the test several times. +fn join_orders_after_tls_destructors() { + use std::sync::atomic::{AtomicU8, Ordering}; + + // We emulate a synchronous MPSC rendezvous channel using only atomics and + // thread::yield_now. We can't use std::mpsc as the implementation itself + // may rely on thread locals. + // + // The basic state machine for an SPSC rendezvous channel is: + // FRESH -> THREAD1_WAITING -> MAIN_THREAD_RENDEZVOUS + // where the first transition is done by the “receiving” thread and the 2nd + // transition is done by the “sending” thread. + // + // We add an additional state `THREAD2_LAUNCHED` between `FRESH` and + // `THREAD1_WAITING` to block until all threads are actually running. + // + // A thread that joins on the “receiving” thread completion should never + // observe the channel in the `THREAD1_WAITING` state. If this does occur, + // we switch to the “poison” state `THREAD2_JOINED` and panic all around. + // (This is equivalent to “sending” from an alternate producer thread.) + const FRESH: u8 = 0; + const THREAD2_LAUNCHED: u8 = 1; + const THREAD1_WAITING: u8 = 2; + const MAIN_THREAD_RENDEZVOUS: u8 = 3; + const THREAD2_JOINED: u8 = 4; + static SYNC_STATE: AtomicU8 = AtomicU8::new(FRESH); + + for _ in 0..10 { + SYNC_STATE.store(FRESH, Ordering::SeqCst); + + let jh = thread::Builder::new() + .name("thread1".into()) + .spawn(move || { + struct TlDrop; + + impl Drop for TlDrop { + fn drop(&mut self) { + let mut sync_state = SYNC_STATE.swap(THREAD1_WAITING, Ordering::SeqCst); + loop { + match sync_state { + THREAD2_LAUNCHED | THREAD1_WAITING => thread::yield_now(), + MAIN_THREAD_RENDEZVOUS => break, + THREAD2_JOINED => panic!( + "Thread 1 still running after thread 2 joined on thread 1" + ), + v => unreachable!("sync state: {}", v), + } + sync_state = SYNC_STATE.load(Ordering::SeqCst); + } + } + } + + thread_local! { + static TL_DROP: TlDrop = TlDrop; + } + + TL_DROP.with(|_| {}); + + loop { + match SYNC_STATE.load(Ordering::SeqCst) { + FRESH => thread::yield_now(), + THREAD2_LAUNCHED => break, + v => unreachable!("sync state: {}", v), + } + } + }) + .unwrap(); + + let jh2 = thread::Builder::new() + .name("thread2".into()) + .spawn(move || { + assert_eq!(SYNC_STATE.swap(THREAD2_LAUNCHED, Ordering::SeqCst), FRESH); + jh.join().unwrap(); + match SYNC_STATE.swap(THREAD2_JOINED, Ordering::SeqCst) { + MAIN_THREAD_RENDEZVOUS => return, + THREAD2_LAUNCHED | THREAD1_WAITING => { + panic!("Thread 2 running after thread 1 join before main thread rendezvous") + } + v => unreachable!("sync state: {:?}", v), + } + }) + .unwrap(); + + loop { + match SYNC_STATE.compare_exchange( + THREAD1_WAITING, + MAIN_THREAD_RENDEZVOUS, + Ordering::SeqCst, + Ordering::SeqCst, + ) { + Ok(_) => break, + Err(FRESH) => thread::yield_now(), + Err(THREAD2_LAUNCHED) => thread::yield_now(), + Err(THREAD2_JOINED) => { + panic!("Main thread rendezvous after thread 2 joined thread 1") + } + v => unreachable!("sync state: {:?}", v), + } + } + jh2.join().unwrap(); + } +} + fn main() { check_destructors(); check_blocking(); + join_orders_after_tls_destructors(); } From 4758ce74efebf59f7f31cb564541dfef00483898 Mon Sep 17 00:00:00 2001 From: InfRandomness <43730933+InfRandomness@users.noreply.github.com> Date: Tue, 7 Jun 2022 17:40:14 +0000 Subject: [PATCH 3225/3747] Fix typo --- src/shims/env.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shims/env.rs b/src/shims/env.rs index ae9b8c75145f7..5cffc5c6d1d5b 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -381,7 +381,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let target_os = &this.tcx.sess.target.os; assert!( target_os == "linux" || target_os == "macos", - "`getcwd` is only available for the UNIX target family" + "`chdir` is only available for the UNIX target family" ); let path = this.read_path_from_c_str(this.read_pointer(path_op)?)?; From cca3dea37974a8f624a41c603e0ec5ca6a450299 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 7 Jun 2022 13:59:47 -0400 Subject: [PATCH 3226/3747] update and move cargo-miri operational description --- cargo-miri/bin.rs | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index ba885d307a85f..8b11016ca1be0 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -1063,6 +1063,19 @@ fn main() { // Skip binary name. args.next().unwrap(); + // Dispatch to `cargo-miri` phase. There are four phases: + // - When we are called via `cargo miri`, we run as the frontend and invoke the underlying + // cargo. We set RUSTDOC, RUSTC_WRAPPER and CARGO_TARGET_RUNNER to ourselves. + // - When we are executed due to RUSTDOC, we run rustdoc and set both `--test-builder` and + // `--runtool` to ourselves. + // - When we are executed due to RUSTC_WRAPPER (or as the rustdoc test builder), we build crates + // or store the flags of binary crates for later interpretation. + // - When we are executed due to CARGO_TARGET_RUNNER (or as the rustdoc runtool), we start + // interpretation based on the flags that were stored earlier. + // + // Additionally, we also set ourselves as RUSTC when calling xargo to build the sysroot, which + // has to be treated slightly differently than when we build regular crates. + // Dispatch running as part of sysroot compilation. if env::var_os("MIRI_CALLED_FROM_XARGO").is_some() { phase_rustc(args, RustcPhase::Setup); @@ -1094,14 +1107,6 @@ fn main() { return; } - // Dispatch to `cargo-miri` phase. There are three phases: - // - When we are called via `cargo miri`, we run as the frontend and invoke the underlying - // cargo. We set RUSTC_WRAPPER and CARGO_TARGET_RUNNER to ourselves. - // - When we are executed due to RUSTC_WRAPPER, we build crates or store the flags of - // binary crates for later interpretation. - // - When we are executed due to CARGO_TARGET_RUNNER, we start interpretation based on the - // flags that were stored earlier. - // On top of that, we are also called as RUSTDOC, but that is just a stub currently. match args.next().as_deref() { Some("miri") => phase_cargo_miri(args), Some("rustc") => phase_rustc(args, RustcPhase::Build), From 7a5de0c98afe9497aa74b3bba124e2fda55ce82c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 7 Jun 2022 16:01:44 -0400 Subject: [PATCH 3227/3747] silence another clippy lint --- src/lib.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 982d3873d5730..7d8eb92ac58ed 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -16,7 +16,8 @@ clippy::new_without_default, clippy::single_match, clippy::useless_format, - clippy::derive_partial_eq_without_eq + clippy::derive_partial_eq_without_eq, + clippy::too_many_arguments )] extern crate rustc_apfloat; From aa68111c60d6fe1a58638cf8c407509972627a67 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 7 Jun 2022 16:03:32 -0400 Subject: [PATCH 3228/3747] gate bors on clippy --- .github/workflows/ci.yml | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 41cf159e0c801..2bfc58be28d77 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -86,22 +86,8 @@ jobs: - name: Test run: bash ./ci.sh - fmt: - name: formatting (ignored by bors) - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - name: Install latest nightly - run: | - rustup toolchain install nightly --component rustfmt - rustup override set nightly - - name: Formatting (miri, ui_test) - run: cargo fmt --all --check - - name: Formatting (cargo-miri) - run: cargo fmt --manifest-path cargo-miri/Cargo.toml --all --check - clippy: - name: clippy (ignored by bors) + name: clippy runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 @@ -117,6 +103,20 @@ jobs: - name: Clippy (cargo-miri) run: cargo clippy --manifest-path cargo-miri/Cargo.toml --all-targets -- -D warnings + fmt: + name: formatting (ignored by bors) + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - name: Install latest nightly + run: | + rustup toolchain install nightly --component rustfmt + rustup override set nightly + - name: Formatting (miri, ui_test) + run: cargo fmt --all --check + - name: Formatting (cargo-miri) + run: cargo fmt --manifest-path cargo-miri/Cargo.toml --all --check + # These jobs doesn't actually test anything, but they're only used to tell # bors the build completed, as there is no practical way to detect when a # workflow is successful listening to webhooks only. @@ -126,7 +126,7 @@ jobs: end-success: name: bors build finished runs-on: ubuntu-latest - needs: [build] + needs: [build, clippy] if: github.event.pusher.name == 'bors' && success() steps: - name: mark the job as a success @@ -134,7 +134,7 @@ jobs: end-failure: name: bors build finished runs-on: ubuntu-latest - needs: [build] + needs: [build, clippy] if: github.event.pusher.name == 'bors' && (failure() || cancelled()) steps: - name: mark the job as a failure @@ -144,7 +144,7 @@ jobs: cron-fail-notify: name: cronjob failure notification runs-on: ubuntu-latest - needs: [build] + needs: [build, clippy] if: github.event_name == 'schedule' && (failure() || cancelled()) steps: - name: Install zulip-send From 2b35dd514e249bcd7d570a3443335236b4a5d9b1 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 7 Jun 2022 17:03:11 -0400 Subject: [PATCH 3229/3747] linux-futex test: ensure we join all threads --- tests/pass/concurrency/linux-futex.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tests/pass/concurrency/linux-futex.rs b/tests/pass/concurrency/linux-futex.rs index 8a67e0b525a98..b2791a4285664 100644 --- a/tests/pass/concurrency/linux-futex.rs +++ b/tests/pass/concurrency/linux-futex.rs @@ -132,7 +132,7 @@ fn wait_wake() { static FUTEX: i32 = 0; - thread::spawn(move || { + let t = thread::spawn(move || { thread::sleep(Duration::from_millis(200)); unsafe { assert_eq!(libc::syscall( @@ -155,6 +155,7 @@ fn wait_wake() { } assert!((200..1000).contains(&start.elapsed().as_millis())); + t.join().unwrap(); } fn wait_wake_bitset() { @@ -162,7 +163,7 @@ fn wait_wake_bitset() { static FUTEX: i32 = 0; - thread::spawn(move || { + let t = thread::spawn(move || { thread::sleep(Duration::from_millis(200)); unsafe { assert_eq!(libc::syscall( @@ -202,6 +203,7 @@ fn wait_wake_bitset() { } assert!((400..1000).contains(&start.elapsed().as_millis())); + t.join().unwrap(); } fn main() { From e62e09ac1717191f537bf4d3a52cdfd54413a3e0 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 8 Jun 2022 07:57:43 -0400 Subject: [PATCH 3230/3747] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 2898937edfb41..9a72ffb3225d1 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -9d20fd109809f20c049d6895a5be27a1fbd39daa +e45d9973b2665897a768312e971b82cc62633103 From a310ccc9a4ff515b6fa8914970f14296caf768bc Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 8 Jun 2022 08:06:32 -0400 Subject: [PATCH 3231/3747] some clippy-induced cleanup --- src/concurrency/data_race.rs | 7 ++----- src/helpers.rs | 2 +- src/mono_hash_map.rs | 2 +- src/shims/foreign_items.rs | 14 +++++++------- src/shims/mod.rs | 2 +- src/shims/unix/foreign_items.rs | 2 +- src/shims/unix/fs.rs | 2 +- src/shims/unix/linux/dlsym.rs | 2 +- src/shims/unix/linux/foreign_items.rs | 2 +- src/shims/unix/macos/foreign_items.rs | 2 +- src/shims/windows/foreign_items.rs | 2 +- 11 files changed, 18 insertions(+), 21 deletions(-) diff --git a/src/concurrency/data_race.rs b/src/concurrency/data_race.rs index 28b09d2f909a3..c81eab1ad23e6 100644 --- a/src/concurrency/data_race.rs +++ b/src/concurrency/data_race.rs @@ -259,10 +259,7 @@ impl MemoryCellClocks { /// Load the internal atomic memory cells if they exist. #[inline] fn atomic(&self) -> Option<&AtomicMemoryCellClocks> { - match &self.atomic_ops { - Some(op) => Some(&*op), - None => None, - } + self.atomic_ops.as_deref() } /// Load or create the internal atomic memory metadata @@ -1482,7 +1479,7 @@ impl GlobalState { let thread_name = &self.thread_info.borrow()[thread].thread_name; if let Some(name) = thread_name { let name: &str = name; - format!("Thread(id = {:?}, name = {:?})", thread.to_u32(), &*name) + format!("Thread(id = {:?}, name = {:?})", thread.to_u32(), name) } else { format!("Thread(id = {:?})", thread.to_u32()) } diff --git a/src/helpers.rs b/src/helpers.rs index 4c79633c72dea..c14aca6c781a7 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -255,7 +255,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // Push frame. - let mir = &*this.load_mir(f.def, None)?; + let mir = this.load_mir(f.def, None)?; this.push_stack_frame(f, mir, dest, stack_pop)?; // Initialize arguments. diff --git a/src/mono_hash_map.rs b/src/mono_hash_map.rs index 1ae2083d5661c..45057632df9b5 100644 --- a/src/mono_hash_map.rs +++ b/src/mono_hash_map.rs @@ -61,7 +61,7 @@ impl AllocMap for MonoHashMap { #[inline(always)] fn filter_map_collect(&self, mut f: impl FnMut(&K, &V) -> Option) -> Vec { - self.0.borrow().iter().filter_map(move |(k, v)| f(k, &*v)).collect() + self.0.borrow().iter().filter_map(move |(k, v)| f(k, v)).collect() } /// The most interesting method: Providing a shared reference without diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 12b5b40e69e88..a81dcdc110f1c 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -243,7 +243,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // First: functions that diverge. let ret = match ret { None => - match &*link_name.as_str() { + match link_name.as_str() { "miri_start_panic" => { // `check_shim` happens inside `handle_miri_start_panic`. this.handle_miri_start_panic(abi, link_name, args, unwind)?; @@ -259,7 +259,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let panic_impl_id = tcx.lang_items().panic_impl().unwrap(); let panic_impl_instance = ty::Instance::mono(tcx, panic_impl_id); return Ok(Some(( - &*this.load_mir(panic_impl_instance.def, None)?, + this.load_mir(panic_impl_instance.def, None)?, panic_impl_instance, ))); } @@ -361,7 +361,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Here we dispatch all the shims for foreign functions. If you have a platform specific // shim, add it to the corresponding submodule. - match &*link_name.as_str() { + match link_name.as_str() { // Miri-specific extern functions "miri_static_root" => { let [ptr] = this.check_shim(abi, Abi::Rust, link_name, args)?; @@ -573,7 +573,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let [f] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; // FIXME: Using host floats. let f = f32::from_bits(this.read_scalar(f)?.to_u32()?); - let f = match &*link_name.as_str() { + let f = match link_name.as_str() { "cbrtf" => f.cbrt(), "coshf" => f.cosh(), "sinhf" => f.sinh(), @@ -596,7 +596,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // FIXME: Using host floats. let f1 = f32::from_bits(this.read_scalar(f1)?.to_u32()?); let f2 = f32::from_bits(this.read_scalar(f2)?.to_u32()?); - let n = match &*link_name.as_str() { + let n = match link_name.as_str() { "_hypotf" | "hypotf" => f1.hypot(f2), "atan2f" => f1.atan2(f2), _ => bug!(), @@ -615,7 +615,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let [f] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; // FIXME: Using host floats. let f = f64::from_bits(this.read_scalar(f)?.to_u64()?); - let f = match &*link_name.as_str() { + let f = match link_name.as_str() { "cbrt" => f.cbrt(), "cosh" => f.cosh(), "sinh" => f.sinh(), @@ -636,7 +636,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // FIXME: Using host floats. let f1 = f64::from_bits(this.read_scalar(f1)?.to_u64()?); let f2 = f64::from_bits(this.read_scalar(f2)?.to_u64()?); - let n = match &*link_name.as_str() { + let n = match link_name.as_str() { "_hypot" | "hypot" => f1.hypot(f2), "atan2" => f1.atan2(f2), _ => bug!(), diff --git a/src/shims/mod.rs b/src/shims/mod.rs index cdffe2f65b4fc..f2688bb08caa4 100644 --- a/src/shims/mod.rs +++ b/src/shims/mod.rs @@ -55,7 +55,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // Otherwise, load the MIR. - Ok(Some((&*this.load_mir(instance.def, None)?, instance))) + Ok(Some((this.load_mir(instance.def, None)?, instance))) } /// Returns `true` if the computation was performed, and `false` if we should just evaluate diff --git a/src/shims/unix/foreign_items.rs b/src/shims/unix/foreign_items.rs index 32cf7e6f891ff..5f59426bc5bce 100644 --- a/src/shims/unix/foreign_items.rs +++ b/src/shims/unix/foreign_items.rs @@ -26,7 +26,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, EmulateByNameResult<'mir, 'tcx>> { let this = self.eval_context_mut(); - match &*link_name.as_str() { + match link_name.as_str() { // Environment related shims "getenv" => { let [name] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; diff --git a/src/shims/unix/fs.rs b/src/shims/unix/fs.rs index d02410664bd42..c688455710345 100644 --- a/src/shims/unix/fs.rs +++ b/src/shims/unix/fs.rs @@ -446,7 +446,7 @@ trait EvalContextExtPrivate<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, ' } } Err(e) => - return match e.raw_os_error() { + match e.raw_os_error() { Some(error) => Ok(error), None => throw_unsup_format!( diff --git a/src/shims/unix/linux/dlsym.rs b/src/shims/unix/linux/dlsym.rs index 72e8c7f16f853..01bf17db9f09c 100644 --- a/src/shims/unix/linux/dlsym.rs +++ b/src/shims/unix/linux/dlsym.rs @@ -9,7 +9,7 @@ impl Dlsym { // Returns an error for unsupported symbols, and None if this symbol // should become a NULL pointer (pretend it does not exist). pub fn from_str<'tcx>(name: &str) -> InterpResult<'tcx, Option> { - Ok(match &*name { + Ok(match name { "__pthread_get_minstack" => None, "getrandom" => None, // std falls back to syscall(SYS_getrandom, ...) when this is NULL. "statx" => None, // std falls back to syscall(SYS_statx, ...) when this is NULL. diff --git a/src/shims/unix/linux/foreign_items.rs b/src/shims/unix/linux/foreign_items.rs index 7a9c687fcd764..ab3f39147c60f 100644 --- a/src/shims/unix/linux/foreign_items.rs +++ b/src/shims/unix/linux/foreign_items.rs @@ -21,7 +21,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, EmulateByNameResult<'mir, 'tcx>> { let this = self.eval_context_mut(); - match &*link_name.as_str() { + match link_name.as_str() { // errno "__errno_location" => { let [] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; diff --git a/src/shims/unix/macos/foreign_items.rs b/src/shims/unix/macos/foreign_items.rs index a1adfa0d2fda5..f7dd38f639b0a 100644 --- a/src/shims/unix/macos/foreign_items.rs +++ b/src/shims/unix/macos/foreign_items.rs @@ -19,7 +19,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, EmulateByNameResult<'mir, 'tcx>> { let this = self.eval_context_mut(); - match &*link_name.as_str() { + match link_name.as_str() { // errno "__error" => { let [] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; diff --git a/src/shims/windows/foreign_items.rs b/src/shims/windows/foreign_items.rs index 05f9aed174765..08a319159bc59 100644 --- a/src/shims/windows/foreign_items.rs +++ b/src/shims/windows/foreign_items.rs @@ -28,7 +28,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // DWORD = ULONG = u32 // BOOL = i32 // BOOLEAN = u8 - match &*link_name.as_str() { + match link_name.as_str() { // Environment related shims "GetEnvironmentVariableW" => { let [name, buf, size] = From 295e18df0dd13440f568d691366d55829f36e748 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 8 Jun 2022 08:12:20 -0400 Subject: [PATCH 3232/3747] document how to get a toolchain with clippy --- CONTRIBUTING.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index b74444fbc6e4e..c2290a966b239 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -28,6 +28,11 @@ install that exact version of rustc as a toolchain: This will set up a rustup toolchain called `miri` and set it as an override for the current directory. +If you want to also have `clippy` installed, you need to run this: +``` +./rustup-toolchain "" -c clippy +``` + [`rustup-toolchain-install-master`]: https://github.com/kennytm/rustup-toolchain-install-master ## Building and testing Miri From 657386cc91c7513eaafd327aaf26aa44d6a3da91 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 8 Jun 2022 12:10:54 -0400 Subject: [PATCH 3233/3747] rustup --- rust-version | 2 +- src/machine.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/rust-version b/rust-version index 9a72ffb3225d1..85b2e88ac30cb 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -e45d9973b2665897a768312e971b82cc62633103 +09d52bc5d4260bac8b9a2ea8ac7a07c5c72906f1 diff --git a/src/machine.rs b/src/machine.rs index 5e93045aec1ab..824f0e3fc8748 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -678,8 +678,8 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { fn ptr_from_addr_cast( ecx: &MiriEvalContext<'mir, 'tcx>, addr: u64, - ) -> Pointer> { - intptrcast::GlobalStateInner::ptr_from_addr_cast(ecx, addr) + ) -> InterpResult<'tcx, Pointer>> { + Ok(intptrcast::GlobalStateInner::ptr_from_addr_cast(ecx, addr)) } #[inline(always)] From 956a84bfe0502e126dcdd173fc84eecc10df5ebc Mon Sep 17 00:00:00 2001 From: Nilstrieb <48135649+Nilstrieb@users.noreply.github.com> Date: Wed, 8 Jun 2022 18:22:48 +0200 Subject: [PATCH 3234/3747] Optimize `SbTag::eq` The code before generated really bad code with a branch. This nudges LLVM towards being smarter and simply comparing the integers. --- src/stacked_borrows.rs | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 0d671ec653b56..fd33eea79026c 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -27,12 +27,27 @@ pub type CallId = NonZeroU64; pub type AllocExtra = Stacks; /// Tracking pointer provenance -#[derive(Copy, Clone, Hash, PartialEq, Eq)] +#[derive(Copy, Clone, Hash, Eq)] pub enum SbTag { Tagged(PtrId), Untagged, } +impl SbTag { + fn as_u64(self) -> u64 { + match self { + SbTag::Tagged(id) => id.get(), + SbTag::Untagged => 0, + } + } +} + +impl PartialEq for SbTag { + fn eq(&self, other: &Self) -> bool { + self.as_u64() == other.as_u64() + } +} + impl fmt::Debug for SbTag { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { From c01bf62ee42f7fa28a95449b374812cb47d38a95 Mon Sep 17 00:00:00 2001 From: Nilstrieb <48135649+Nilstrieb@users.noreply.github.com> Date: Wed, 8 Jun 2022 18:43:12 +0200 Subject: [PATCH 3235/3747] Allow `clippy::derive_hash_xor_eq` --- src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/lib.rs b/src/lib.rs index 7d8eb92ac58ed..22869e9b248c0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -17,6 +17,7 @@ clippy::single_match, clippy::useless_format, clippy::derive_partial_eq_without_eq, + clippy::derive_hash_xor_eq, clippy::too_many_arguments )] From 93db9a6d71a7f66df81b5c8adbac7bb71d182bc1 Mon Sep 17 00:00:00 2001 From: Nilstrieb <48135649+Nilstrieb@users.noreply.github.com> Date: Wed, 8 Jun 2022 19:29:54 +0200 Subject: [PATCH 3236/3747] Add comment to explain manual optimization --- src/stacked_borrows.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index fd33eea79026c..88d1b1f10521c 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -44,6 +44,9 @@ impl SbTag { impl PartialEq for SbTag { fn eq(&self, other: &Self) -> bool { + // The codegen for the derived Partialeq is bad here and includes a branch. + // Since this code is extremely hot, this is optimized here. + // https://github.com/rust-lang/rust/issues/49892 self.as_u64() == other.as_u64() } } From 8a40e2e9e3f732f6e720969f6a26b74fcaefc34b Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Wed, 8 Jun 2022 19:32:43 -0400 Subject: [PATCH 3237/3747] Add more bench-cargo-miri programs These example programs are derived from long-running (>15 minutes) tests in the test suites of highly-downloaded crates. They should serve as realistic but also somewhat pathological workloads for the interpreter. The unicode program stresses the code which looks for adjacent and equal stacks to merge them. The backtrace program has an uncommonly large working set of borrow tags per borrow stack. This also updates the .gitignore to ignore files commonly emitted in the course of using these benchmark programs. --- .gitignore | 4 ++ bench-cargo-miri/backtraces/Cargo.lock | 94 +++++++++++++++++++++++++ bench-cargo-miri/backtraces/Cargo.toml | 9 +++ bench-cargo-miri/backtraces/src/main.rs | 29 ++++++++ bench-cargo-miri/mse/Cargo.lock | 7 ++ bench-cargo-miri/serde1/Cargo.lock | 89 +++++++++++++++++++++++ bench-cargo-miri/unicode/Cargo.lock | 16 +++++ bench-cargo-miri/unicode/Cargo.toml | 9 +++ bench-cargo-miri/unicode/src/main.rs | 20 ++++++ 9 files changed, 277 insertions(+) create mode 100644 bench-cargo-miri/backtraces/Cargo.lock create mode 100644 bench-cargo-miri/backtraces/Cargo.toml create mode 100644 bench-cargo-miri/backtraces/src/main.rs create mode 100644 bench-cargo-miri/mse/Cargo.lock create mode 100644 bench-cargo-miri/serde1/Cargo.lock create mode 100644 bench-cargo-miri/unicode/Cargo.lock create mode 100644 bench-cargo-miri/unicode/Cargo.toml create mode 100644 bench-cargo-miri/unicode/src/main.rs diff --git a/.gitignore b/.gitignore index b84a1cfe9f533..dcefbc62c70b3 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,7 @@ tex/*/out *.dot *.rs.bk .vscode +*.mm_profdata +perf.data +perf.data.old +flamegraph.svg diff --git a/bench-cargo-miri/backtraces/Cargo.lock b/bench-cargo-miri/backtraces/Cargo.lock new file mode 100644 index 0000000000000..375b129a7e59b --- /dev/null +++ b/bench-cargo-miri/backtraces/Cargo.lock @@ -0,0 +1,94 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "addr2line" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9ecd88a8c8378ca913a680cd98f0f13ac67383d35993f86c90a70e3f137816b" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + +[[package]] +name = "backtrace" +version = "0.3.65" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11a17d453482a265fd5f8479f2a3f405566e6ca627837aaddb85af8b1ab8ef61" +dependencies = [ + "addr2line", + "cc", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", +] + +[[package]] +name = "backtraces" +version = "0.1.0" +dependencies = [ + "backtrace", +] + +[[package]] +name = "cc" +version = "1.0.73" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "gimli" +version = "0.26.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78cc372d058dcf6d5ecd98510e7fbc9e5aec4d21de70f65fea8fecebcd881bd4" + +[[package]] +name = "libc" +version = "0.2.126" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836" + +[[package]] +name = "memchr" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" + +[[package]] +name = "miniz_oxide" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f5c75688da582b8ffc1f1799e9db273f32133c49e048f614d22ec3256773ccc" +dependencies = [ + "adler", +] + +[[package]] +name = "object" +version = "0.28.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e42c982f2d955fac81dd7e1d0e1426a7d702acd9c98d19ab01083a6a0328c424" +dependencies = [ + "memchr", +] + +[[package]] +name = "rustc-demangle" +version = "0.1.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342" diff --git a/bench-cargo-miri/backtraces/Cargo.toml b/bench-cargo-miri/backtraces/Cargo.toml new file mode 100644 index 0000000000000..1ba96b19395d2 --- /dev/null +++ b/bench-cargo-miri/backtraces/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "backtraces" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +backtrace = "0.3.65" diff --git a/bench-cargo-miri/backtraces/src/main.rs b/bench-cargo-miri/backtraces/src/main.rs new file mode 100644 index 0000000000000..eba51c60dbc5b --- /dev/null +++ b/bench-cargo-miri/backtraces/src/main.rs @@ -0,0 +1,29 @@ +//! Extracted from the backtrace crate's test test_frame_conversion + +use backtrace::{Backtrace, BacktraceFrame}; +use std::fmt::Write; + +fn main() { + let mut frames = vec![]; + backtrace::trace(|frame| { + let converted = BacktraceFrame::from(frame.clone()); + frames.push(converted); + true + }); + + let mut manual = Backtrace::from(frames); + manual.resolve(); + let frames = manual.frames(); + + let mut output = String::new(); + for frame in frames { + // Originally these were println! but we'd prefer our benchmarks to not emit a lot of + // output to stdout/stderr. Unfortunately writeln! to a String is faster, but we still + // manage to exercise interesting code paths in Miri. + writeln!(output, "{:?}", frame.ip()).unwrap(); + writeln!(output, "{:?}", frame.symbol_address()).unwrap(); + writeln!(output, "{:?}", frame.module_base_address()).unwrap(); + writeln!(output, "{:?}", frame.symbols()).unwrap(); + } + drop(output); +} diff --git a/bench-cargo-miri/mse/Cargo.lock b/bench-cargo-miri/mse/Cargo.lock new file mode 100644 index 0000000000000..d2b1aa341bbb6 --- /dev/null +++ b/bench-cargo-miri/mse/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "mse" +version = "0.1.0" diff --git a/bench-cargo-miri/serde1/Cargo.lock b/bench-cargo-miri/serde1/Cargo.lock new file mode 100644 index 0000000000000..4875057613543 --- /dev/null +++ b/bench-cargo-miri/serde1/Cargo.lock @@ -0,0 +1,89 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "cargo-miri-test" +version = "0.1.0" +dependencies = [ + "serde", + "serde_json", +] + +[[package]] +name = "itoa" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "112c678d4050afce233f4f2852bb2eb519230b3cf12f33585275537d7e41578d" + +[[package]] +name = "proc-macro2" +version = "1.0.39" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c54b25569025b7fc9651de43004ae593a75ad88543b17178aa5e1b9c4f15f56f" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1feb54ed693b93a84e14094943b84b7c4eae204c512b7ccb95ab0c66d278ad1" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "ryu" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3f6f92acf49d1b98f7a81226834412ada05458b7364277387724a237f062695" + +[[package]] +name = "serde" +version = "1.0.137" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61ea8d54c77f8315140a05f4c7237403bf38b72704d031543aa1d16abbf517d1" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.137" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f26faba0c3959972377d3b2d306ee9f71faee9714294e41bb777f83f88578be" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.81" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b7ce2b32a1aed03c558dc61a5cd328f15aff2dbc17daad8fb8af04d2100e15c" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "syn" +version = "1.0.96" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0748dd251e24453cb8717f0354206b91557e4ec8703673a4b30208f2abaf1ebf" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "unicode-ident" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d22af068fba1eb5edcb4aea19d382b2a3deb4c8f9d475c589b6ada9e0fd493ee" diff --git a/bench-cargo-miri/unicode/Cargo.lock b/bench-cargo-miri/unicode/Cargo.lock new file mode 100644 index 0000000000000..80d013b7d6d84 --- /dev/null +++ b/bench-cargo-miri/unicode/Cargo.lock @@ -0,0 +1,16 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "unicode" +version = "0.1.0" +dependencies = [ + "unicode-xid", +] + +[[package]] +name = "unicode-xid" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "957e51f3646910546462e67d5f7599b9e4fb8acdd304b087a6494730f9eebf04" diff --git a/bench-cargo-miri/unicode/Cargo.toml b/bench-cargo-miri/unicode/Cargo.toml new file mode 100644 index 0000000000000..7e8708b03f19c --- /dev/null +++ b/bench-cargo-miri/unicode/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "unicode" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +unicode-xid = "0.2.3" diff --git a/bench-cargo-miri/unicode/src/main.rs b/bench-cargo-miri/unicode/src/main.rs new file mode 100644 index 0000000000000..3f0ee5ecf6af6 --- /dev/null +++ b/bench-cargo-miri/unicode/src/main.rs @@ -0,0 +1,20 @@ +//! Extracted from the unicode-xid exhaustive test all_valid_chars_do_not_panic_for_is_xid_continue + +use unicode_xid::UnicodeXID; + +/// A `char` in Rust is a Unicode Scalar Value +/// +/// See: http://www.unicode.org/glossary/#unicode_scalar_value +fn all_valid_chars() -> impl Iterator { + (0u32..=0xD7FF).chain(0xE000u32..=0x10FFFF).map(|u| { + core::convert::TryFrom::try_from(u) + .expect("The selected range should be infallible if the docs match impl") + }) +} + +fn main() { + // Take only the first few chars because we don't want to wait all day + for c in all_valid_chars().take(2_000) { + let _ = UnicodeXID::is_xid_continue(c); + } +} From 4da48e06c7b721075d46b51f686e7e326393ab52 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 10 Jun 2022 20:23:30 -0700 Subject: [PATCH 3238/3747] make frame_in_std check work with inlining --- src/helpers.rs | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index c14aca6c781a7..e353e17c68057 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -729,10 +729,22 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn frame_in_std(&self) -> bool { let this = self.eval_context_ref(); - this.tcx.lang_items().start_fn().map_or(false, |start_fn| { - this.tcx.def_path(this.frame().instance.def_id()).krate - == this.tcx.def_path(start_fn).krate - }) + let Some(start_fn) = this.tcx.lang_items().start_fn() else { + // no_std situations + return false; + }; + let frame = this.frame(); + // Make an attempt to get at the instance of the function this is inlined from. + let instance: Option<_> = try { + let scope = frame.current_source_info()?.scope; + let inlined_parent = frame.body.source_scopes[scope].inlined_parent_scope?; + let source = &frame.body.source_scopes[inlined_parent]; + source.inlined.expect("inlined_parent_scope points to scope without inline info").0 + }; + // Fall back to the instance of the function itself. + let instance = instance.unwrap_or(frame.instance); + // Now check if this is in the same crate as start_fn. + this.tcx.def_path(instance.def_id()).krate == this.tcx.def_path(start_fn).krate } /// Handler that should be called when unsupported functionality is encountered. From eaa1e444eb3efa0bb4e1faf00b0ee2b4e3d8f673 Mon Sep 17 00:00:00 2001 From: infrandomness Date: Thu, 9 Jun 2022 16:20:47 +0200 Subject: [PATCH 3239/3747] Add mandatory cargo_doc Co-authored-by: Joshua Nelson --- .github/workflows/ci.yml | 4 +++- src/concurrency/weak_memory.rs | 10 +++++----- src/eval.rs | 2 +- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2bfc58be28d77..55da948f7b785 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -87,7 +87,7 @@ jobs: run: bash ./ci.sh clippy: - name: clippy + name: clippy + rustdoc runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 @@ -102,6 +102,8 @@ jobs: # run: cargo clippy --manifest-path ui_test/Cargo.toml --all-targets -- -D warnings - name: Clippy (cargo-miri) run: cargo clippy --manifest-path cargo-miri/Cargo.toml --all-targets -- -D warnings + - name: Rustdoc + run: RUSTDOCFLAGS="-Dwarnings" cargo doc --document-private-items fmt: name: formatting (ignored by bors) diff --git a/src/concurrency/weak_memory.rs b/src/concurrency/weak_memory.rs index be3963a93f072..e5f58ee5ddd0b 100644 --- a/src/concurrency/weak_memory.rs +++ b/src/concurrency/weak_memory.rs @@ -1,13 +1,13 @@ //! Implementation of C++11-consistent weak memory emulation using store buffers //! based on Dynamic Race Detection for C++ ("the paper"): -//! https://www.doc.ic.ac.uk/~afd/homepages/papers/pdfs/2017/POPL.pdf +//! //! //! This implementation will never generate weak memory behaviours forbidden by the C++11 model, //! but it is incapable of producing all possible weak behaviours allowed by the model. There are //! certain weak behaviours observable on real hardware but not while using this. //! //! Note that this implementation does not take into account of C++20's memory model revision to SC accesses -//! and fences introduced by P0668 (https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0668r5.html). +//! and fences introduced by P0668 (). //! This implementation is not fully correct under the revised C++20 model and may generate behaviours C++20 //! disallows. //! @@ -15,14 +15,14 @@ //! std::atomic API). It is therefore possible for this implementation to generate behaviours never observable when the //! same program is compiled and run natively. Unfortunately, no literature exists at the time of writing which proposes //! an implementable and C++20-compatible relaxed memory model that supports all atomic operation existing in Rust. The closest one is -//! A Promising Semantics for Relaxed-Memory Concurrency by Jeehoon Kang et al. (https://www.cs.tau.ac.il/~orilahav/papers/popl17.pdf) +//! A Promising Semantics for Relaxed-Memory Concurrency by Jeehoon Kang et al. () //! However, this model lacks SC accesses and is therefore unusable by Miri (SC accesses are everywhere in library code). //! //! If you find anything that proposes a relaxed memory model that is C++20-consistent, supports all orderings Rust's atomic accesses //! and fences accept, and is implementable (with operational semanitcs), please open a GitHub issue! //! //! One characteristic of this implementation, in contrast to some other notable operational models such as ones proposed in -//! Taming Release-Acquire Consistency by Ori Lahav et al. (https://plv.mpi-sws.org/sra/paper.pdf) or Promising Semantics noted above, +//! Taming Release-Acquire Consistency by Ori Lahav et al. () or Promising Semantics noted above, //! is that this implementation does not require each thread to hold an isolated view of the entire memory. Here, store buffers are per-location //! and shared across all threads. This is more memory efficient but does require store elements (representing writes to a location) to record //! information about reads, whereas in the other two models it is the other way round: reads points to the write it got its value from. @@ -38,7 +38,7 @@ //! on the next non-atomic or imperfectly overlapping atomic access to that region. //! These lazy (de)allocations happen in memory_accessed() on non-atomic accesses, and //! get_or_create_store_buffer() on atomic accesses. This mostly works well, but it does -//! lead to some issues (https://github.com/rust-lang/miri/issues/2164). +//! lead to some issues (). //! //! One consequence of this difference is that safe/sound Rust allows for more operations on atomic locations //! than the C++20 atomic API was intended to allow, such as non-atomically accessing diff --git a/src/eval.rs b/src/eval.rs index 7c971d2a1490a..db843b851e58a 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -403,7 +403,7 @@ pub fn eval_entry<'tcx>( /// The string will be UTF-16 encoded and NUL terminated. /// /// Panics if the zeroth argument contains the `"` character because doublequotes -/// in argv[0] cannot be encoded using the standard command line parsing rules. +/// in `argv[0]` cannot be encoded using the standard command line parsing rules. /// /// Further reading: /// * [Parsing C++ command-line arguments](https://docs.microsoft.com/en-us/cpp/cpp/main-function-command-line-args?view=msvc-160#parsing-c-command-line-arguments) From 3e03054ef0056e728a081b03cde8546f91c822aa Mon Sep 17 00:00:00 2001 From: InfRandomness Date: Wed, 8 Jun 2022 10:09:38 +0200 Subject: [PATCH 3240/3747] Add getpid shim --- src/shims/env.rs | 27 +++++++++++++++++++++++++++ src/shims/unix/foreign_items.rs | 6 ++++++ src/shims/windows/foreign_items.rs | 5 +++++ tests/pass/getpid.rs | 9 +++++++++ 4 files changed, 47 insertions(+) create mode 100644 tests/pass/getpid.rs diff --git a/src/shims/env.rs b/src/shims/env.rs index 5cffc5c6d1d5b..a65919286117c 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -465,4 +465,31 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(()) } + + fn getpid(&mut self) -> InterpResult<'tcx, i32> { + let this = self.eval_context_mut(); + let target_os = &this.tcx.sess.target.os; + assert!( + target_os == "linux" || target_os == "macos", + "`getpid` is only available for the UNIX target family" + ); + + this.check_no_isolation("`getpid`")?; + + // The reason we need to do this wacky of a conversion is because + // `libc::getpid` returns an i32, however, `std::process::id()` return an u32. + // So we un-do the conversion that stdlib does and turn it back into an i32. + + Ok(std::process::id() as i32) + } + + #[allow(non_snake_case)] + fn GetCurrentProcessId(&mut self) -> InterpResult<'tcx, u32> { + let this = self.eval_context_mut(); + this.assert_target_os("windows", "GetCurrentProcessId"); + + this.check_no_isolation("`GetCurrentProcessId`")?; + + Ok(std::process::id()) + } } diff --git a/src/shims/unix/foreign_items.rs b/src/shims/unix/foreign_items.rs index 32cf7e6f891ff..2d2a2c0399a8b 100644 --- a/src/shims/unix/foreign_items.rs +++ b/src/shims/unix/foreign_items.rs @@ -474,6 +474,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_null(dest)?; } + "getpid" => { + let [] = this.check_shim(abi, Abi::C { unwind: false}, link_name, args)?; + let result = this.getpid()?; + this.write_scalar(Scalar::from_i32(result), dest)?; + } + // Platform-specific shims _ => { match this.tcx.sess.target.os.as_ref() { diff --git a/src/shims/windows/foreign_items.rs b/src/shims/windows/foreign_items.rs index 05f9aed174765..8b7742e0a4ae3 100644 --- a/src/shims/windows/foreign_items.rs +++ b/src/shims/windows/foreign_items.rs @@ -419,6 +419,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let [] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; this.write_scalar(Scalar::from_machine_isize(1, this), dest)?; } + "GetCurrentProcessId" if this.frame_in_std() => { + let [] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; + let result = this.GetCurrentProcessId()?; + this.write_scalar(Scalar::from_u32(result), dest)?; + } _ => return Ok(EmulateByNameResult::NotSupported), } diff --git a/tests/pass/getpid.rs b/tests/pass/getpid.rs new file mode 100644 index 0000000000000..258fdeaa8497f --- /dev/null +++ b/tests/pass/getpid.rs @@ -0,0 +1,9 @@ +// compile-flags: -Zmiri-disable-isolation + +fn getpid() -> u32 { + std::process::id() +} + +fn main() { + getpid(); +} From 5f1ba4432bf571cbd27f6c808200294d323e2a28 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 11 Jun 2022 08:03:51 -0700 Subject: [PATCH 3241/3747] make some rustdoc comments more readable --- src/concurrency/data_race.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/concurrency/data_race.rs b/src/concurrency/data_race.rs index c81eab1ad23e6..c1bcd2368133b 100644 --- a/src/concurrency/data_race.rs +++ b/src/concurrency/data_race.rs @@ -24,7 +24,7 @@ //! because it only re-uses vector indexes once all currently-active (not-terminated) threads have an internal //! vector clock that happens-after the join operation of the candidate thread. Threads that have not been joined //! on are not considered. Since the thread's vector clock will only increase and a data-race implies that -//! there is some index x where clock\[x\] > thread_clock, when this is true clock\[candidate-idx\] > thread_clock +//! there is some index x where `clock[x] > thread_clock`, when this is true `clock[candidate-idx] > thread_clock` //! can never hold and hence a data-race can never be reported in that vector index again. //! This means that the thread-index can be safely re-used, starting on the next timestamp for the newly created //! thread. From 58d00aa6424f64a72b07afed275a49f76e816016 Mon Sep 17 00:00:00 2001 From: infrandomness Date: Sat, 11 Jun 2022 15:37:49 +0200 Subject: [PATCH 3242/3747] Add target_os_is_unix helper --- src/helpers.rs | 6 ++++++ src/shims/dlsym.rs | 4 +++- src/shims/env.rs | 3 ++- src/shims/foreign_items.rs | 4 ++-- 4 files changed, 13 insertions(+), 4 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index e353e17c68057..b494e85075c41 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -895,3 +895,9 @@ impl std::fmt::Display for HexRange { write!(f, "[{:#x}..{:#x}]", self.0.start.bytes(), self.0.end().bytes()) } } + +/// Helper function used inside the shims of foreign functions to check that +/// `target_os` is a supported UNIX OS. +pub fn target_os_is_unix(target_os: &str) -> bool { + matches!(target_os, "linux" | "macos") +} diff --git a/src/shims/dlsym.rs b/src/shims/dlsym.rs index c5081582281bc..499e9f8a201fd 100644 --- a/src/shims/dlsym.rs +++ b/src/shims/dlsym.rs @@ -1,6 +1,7 @@ use rustc_middle::mir; use rustc_target::spec::abi::Abi; +use crate::helpers::target_os_is_unix; use crate::*; use shims::unix::dlsym as unix; use shims::windows::dlsym as windows; @@ -18,7 +19,8 @@ impl Dlsym { pub fn from_str<'tcx>(name: &[u8], target_os: &str) -> InterpResult<'tcx, Option> { let name = &*String::from_utf8_lossy(name); Ok(match target_os { - "linux" | "macos" => unix::Dlsym::from_str(name, target_os)?.map(Dlsym::Posix), + target if target_os_is_unix(target) => + unix::Dlsym::from_str(name, target)?.map(Dlsym::Posix), "windows" => windows::Dlsym::from_str(name)?.map(Dlsym::Windows), os => bug!("dlsym not implemented for target_os {}", os), }) diff --git a/src/shims/env.rs b/src/shims/env.rs index a65919286117c..91acff40fe165 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -8,6 +8,7 @@ use rustc_data_structures::fx::FxHashMap; use rustc_middle::ty::layout::LayoutOf; use rustc_target::abi::Size; +use crate::helpers::target_os_is_unix; use crate::*; /// Check whether an operation that writes to a target buffer was successful. @@ -55,7 +56,7 @@ impl<'tcx> EnvVars<'tcx> { }; if forward { let var_ptr = match target_os { - "linux" | "macos" => + target if target_os_is_unix(target) => alloc_env_var_as_c_str(name.as_ref(), value.as_ref(), ecx)?, "windows" => alloc_env_var_as_wide_str(name.as_ref(), value.as_ref(), ecx)?, unsupported => diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index a81dcdc110f1c..cd4fedad0fba0 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -22,7 +22,7 @@ use rustc_target::{ }; use super::backtrace::EvalContextExt as _; -use crate::helpers::convert::Truncate; +use crate::helpers::{convert::Truncate, target_os_is_unix}; use crate::*; /// Returned by `emulate_foreign_item_by_name`. @@ -702,7 +702,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Platform-specific shims _ => match this.tcx.sess.target.os.as_ref() { - "linux" | "macos" => return shims::unix::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, abi, args, dest, ret), + target if target_os_is_unix(target) => return shims::unix::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, abi, args, dest, ret), "windows" => return shims::windows::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, abi, args, dest, ret), target => throw_unsup_format!("the target `{}` is not supported", target), } From bc27fbb2f73b6f8d3f629b6954776a6572c2da19 Mon Sep 17 00:00:00 2001 From: infrandomness Date: Sat, 11 Jun 2022 17:54:23 +0200 Subject: [PATCH 3243/3747] Add `assert_target_os_is_unix` function --- src/helpers.rs | 11 +++++++++++ src/shims/env.rs | 36 ++++++------------------------------ 2 files changed, 17 insertions(+), 30 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index b494e85075c41..134f556bf1204 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -493,6 +493,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) } + /// Helper function used inside the shims of foreign functions to assert that the target OS + /// is part of the UNIX family. It panics showing a message with the `name` of the foreign function + /// if this is not the case. + fn assert_target_os_is_unix(&self, name: &str) { + assert!( + target_os_is_unix(self.eval_context_ref().tcx.sess.target.os.as_ref()), + "`{}` is only available for supported UNIX family targets", + name, + ); + } + /// Get last error variable as a place, lazily allocating thread-local storage for it if /// necessary. fn last_error_place(&mut self) -> InterpResult<'tcx, MPlaceTy<'tcx, Tag>> { diff --git a/src/shims/env.rs b/src/shims/env.rs index 91acff40fe165..85ecd2b719f20 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -114,11 +114,7 @@ impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mi pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { fn getenv(&mut self, name_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, Pointer>> { let this = self.eval_context_mut(); - let target_os = &this.tcx.sess.target.os; - assert!( - target_os == "linux" || target_os == "macos", - "`getenv` is only available for the UNIX target family" - ); + this.assert_target_os_is_unix("getenv"); let name_ptr = this.read_pointer(name_op)?; let name = this.read_os_str_from_c_str(name_ptr)?; @@ -212,11 +208,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx value_op: &OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - let target_os = &this.tcx.sess.target.os; - assert!( - target_os == "linux" || target_os == "macos", - "`setenv` is only available for the UNIX target family" - ); + this.assert_target_os_is_unix("setenv"); let name_ptr = this.read_pointer(name_op)?; let value_ptr = this.read_pointer(value_op)?; @@ -286,11 +278,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn unsetenv(&mut self, name_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - let target_os = &this.tcx.sess.target.os; - assert!( - target_os == "linux" || target_os == "macos", - "`unsetenv` is only available for the UNIX target family" - ); + this.assert_target_os_is_unix("unsetenv"); let name_ptr = this.read_pointer(name_op)?; let mut success = None; @@ -320,11 +308,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx size_op: &OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, Pointer>> { let this = self.eval_context_mut(); - let target_os = &this.tcx.sess.target.os; - assert!( - target_os == "linux" || target_os == "macos", - "`getcwd` is only available for the UNIX target family" - ); + this.assert_target_os_is_unix("getcwd"); let buf = this.read_pointer(buf_op)?; let size = this.read_scalar(size_op)?.to_machine_usize(&*this.tcx)?; @@ -379,11 +363,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn chdir(&mut self, path_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - let target_os = &this.tcx.sess.target.os; - assert!( - target_os == "linux" || target_os == "macos", - "`chdir` is only available for the UNIX target family" - ); + this.assert_target_os_is_unix("chdir"); let path = this.read_path_from_c_str(this.read_pointer(path_op)?)?; @@ -469,11 +449,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn getpid(&mut self) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - let target_os = &this.tcx.sess.target.os; - assert!( - target_os == "linux" || target_os == "macos", - "`getpid` is only available for the UNIX target family" - ); + this.assert_target_os_is_unix("getpid"); this.check_no_isolation("`getpid`")?; From b6bcbf76fdd4da771977c1591eaec3faad05a9f3 Mon Sep 17 00:00:00 2001 From: Andy Wang Date: Sat, 11 Jun 2022 20:45:45 +0100 Subject: [PATCH 3244/3747] Prevent futex_wait from reading outdated value --- src/shims/unix/linux/sync.rs | 26 ++++++++++------ tests/pass/concurrency/linux-futex.rs | 44 +++++++++++++++++++++++++++ 2 files changed, 60 insertions(+), 10 deletions(-) diff --git a/src/shims/unix/linux/sync.rs b/src/shims/unix/linux/sync.rs index 72898baa4b0a4..42494da37b799 100644 --- a/src/shims/unix/linux/sync.rs +++ b/src/shims/unix/linux/sync.rs @@ -126,24 +126,26 @@ pub fn futex<'tcx>( Align::from_bytes(4).unwrap(), CheckInAllocMsg::MemoryAccessTest, )?; + // This SeqCst fence is paired with the SeqCst fence in futex_wake. + // Together, they make sure that our read on addr observes the latest + // value in modification order. + // + // If there is another thread which has changed the value of + // addr (to something other than expected) and called futex_wake + // before we get to run, then we must not block our thread + // because there'll be no one to wake us. We must see + // the value changed by the other thread and return without + // actually waiting. + this.atomic_fence(&[], AtomicFenceOp::SeqCst)?; // Read an `i32` through the pointer, regardless of any wrapper types. // It's not uncommon for `addr` to be passed as another type than `*mut i32`, such as `*const AtomicI32`. // FIXME: this fails if `addr` is not a pointer type. - // The atomic ordering for futex(https://man7.org/linux/man-pages/man2/futex.2.html): - // "The load of the value of the futex word is an - // atomic memory access (i.e., using atomic machine instructions - // of the respective architecture). This load, the comparison - // with the expected value, and starting to sleep are performed - // atomically and totally ordered with respect to other futex - // operations on the same futex word." - // SeqCst is total order over all operations. - // FIXME: check if this should be changed when weak memory orders are added. let futex_val = this .read_scalar_at_offset_atomic( &addr.into(), 0, this.machine.layouts.i32, - AtomicReadOp::SeqCst, + AtomicReadOp::Relaxed, )? .to_i32()?; if val == futex_val { @@ -203,6 +205,10 @@ pub fn futex<'tcx>( this.write_scalar(Scalar::from_machine_isize(-1, this), dest)?; return Ok(()); } + // Together with the SeqCst fence in futex_wait, this makes sure that futex_wait + // will see the latest value on addr which could be changed by our caller + // before doing the syscall. + this.atomic_fence(&[], AtomicFenceOp::SeqCst)?; let mut n = 0; for _ in 0..val { if let Some(thread) = this.futex_wake(addr_usize, bitset) { diff --git a/tests/pass/concurrency/linux-futex.rs b/tests/pass/concurrency/linux-futex.rs index b2791a4285664..56aba60d534a6 100644 --- a/tests/pass/concurrency/linux-futex.rs +++ b/tests/pass/concurrency/linux-futex.rs @@ -6,6 +6,8 @@ extern crate libc; use std::mem::MaybeUninit; use std::ptr; +use std::sync::atomic::AtomicI32; +use std::sync::atomic::Ordering; use std::thread; use std::time::{Duration, Instant}; @@ -206,6 +208,47 @@ fn wait_wake_bitset() { t.join().unwrap(); } +const FREE: i32 = 0; +const HELD: i32 = 1; +fn concurrent_wait_wake() { + static FUTEX: AtomicI32 = AtomicI32::new(0); + for _ in 0..100 { + // Suppose the main thread is holding a lock implemented using futex... + FUTEX.store(HELD, Ordering::Relaxed); + + let t = thread::spawn(move || { + // If this syscall runs first, then we'll be woken up by + // the main thread's FUTEX_WAKE, and all is fine. + // + // If this sycall runs after the main thread's store + // and FUTEX_WAKE, the syscall must observe that + // the FUTEX is FREE != HELD and return without waiting + // or we'll deadlock. + unsafe { + libc::syscall( + libc::SYS_futex, + &FUTEX as *const AtomicI32, + libc::FUTEX_WAIT, + HELD, + ptr::null::(), + ); + } + }); + + FUTEX.store(FREE, Ordering::Relaxed); + unsafe { + libc::syscall( + libc::SYS_futex, + &FUTEX as *const AtomicI32, + libc::FUTEX_WAKE, + 1, + ); + } + + t.join().unwrap(); + } +} + fn main() { wake_nobody(); wake_dangling(); @@ -214,4 +257,5 @@ fn main() { wait_absolute_timeout(); wait_wake(); wait_wake_bitset(); + concurrent_wait_wake(); } From 681cb888044601c0c00a02a4302b108758ca7712 Mon Sep 17 00:00:00 2001 From: DrMeepster <19316085+DrMeepster@users.noreply.github.com> Date: Sat, 11 Jun 2022 16:41:32 -0700 Subject: [PATCH 3245/3747] Add cache location on windows to documentation --- CONTRIBUTING.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index c2290a966b239..623480890c925 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -134,7 +134,7 @@ build Miri yourself, the Miri shipped by `rustup` will work. All you have to do is set the `MIRI_LIB_SRC` environment variable to the `library` folder of a `rust-lang/rust` repository checkout. Note that changing files in that directory does not automatically trigger a re-build of the standard library; you have to -clear the Miri build cache manually (on Linux, `rm -rf ~/.cache/miri`). +clear the Miri build cache manually (on Linux, `rm -rf ~/.cache/miri` and on Windows, `rmdir /S "%LOCALAPPDATA%\rust-lang\miri"`). ## Configuring `rust-analyzer` @@ -226,7 +226,7 @@ rustup override set stage2 ``` Important: You need to delete the Miri cache when you change the stdlib; otherwise the -old, chached version will be used. On Linux, the cache is located at `~/.cache/miri`; the exact +old, chached version will be used. On Linux, the cache is located at `~/.cache/miri` and on Windows, the cache is located at `%LOCALAPPDATA%\rust-lang\miri`; the exact location is printed after the library build: "A libstd for Miri is now available in ...". Note: `./x.py --stage 2 compiler/rustc` currently errors with `thread 'main' From 069d8fdb71a9a46a76552e8eea7d427b4d6f08a1 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 5 Jun 2022 12:25:46 -0400 Subject: [PATCH 3246/3747] test for Stacked Borrows error during vtable validation --- tests/fail/stacked_borrows/vtable.rs | 19 ++++++++++++++++++ tests/fail/stacked_borrows/vtable.stderr | 25 ++++++++++++++++++++++++ 2 files changed, 44 insertions(+) create mode 100644 tests/fail/stacked_borrows/vtable.rs create mode 100644 tests/fail/stacked_borrows/vtable.stderr diff --git a/tests/fail/stacked_borrows/vtable.rs b/tests/fail/stacked_borrows/vtable.rs new file mode 100644 index 0000000000000..dd9ba1dfb2bda --- /dev/null +++ b/tests/fail/stacked_borrows/vtable.rs @@ -0,0 +1,19 @@ +// error-pattern: vtable pointer does not have permission +#![feature(ptr_metadata)] + +trait Foo {} + +impl Foo for u32 {} + +fn uwu(thin: *const (), meta: &'static ()) -> *const dyn Foo { + core::ptr::from_raw_parts(thin, unsafe { core::mem::transmute(meta) }) +} + +fn main() { + unsafe { + let orig = 1_u32; + let x = &orig as &dyn Foo; + let (ptr, meta) = (x as *const dyn Foo).to_raw_parts(); + let _ = uwu(ptr, core::mem::transmute(meta)); + } +} diff --git a/tests/fail/stacked_borrows/vtable.stderr b/tests/fail/stacked_borrows/vtable.stderr new file mode 100644 index 0000000000000..ac3d71045f0cc --- /dev/null +++ b/tests/fail/stacked_borrows/vtable.stderr @@ -0,0 +1,25 @@ +error: Undefined Behavior: type validation failed: encountered vtable pointer does not have permission to read drop function pointer + --> RUSTLIB/core/src/ptr/metadata.rs:LL:CC + | +LL | unsafe { PtrRepr { components: PtrComponents { data_address, metadata } }.const_ptr } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered vtable pointer does not have permission to read drop function pointer + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + + = note: inside `std::ptr::from_raw_parts::` at RUSTLIB/core/src/ptr/metadata.rs:LL:CC +note: inside `uwu` at $DIR/vtable.rs:LL:CC + --> $DIR/vtable.rs:LL:CC + | +LL | core::ptr::from_raw_parts(thin, unsafe { core::mem::transmute(meta) }) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: inside `main` at $DIR/vtable.rs:LL:CC + --> $DIR/vtable.rs:LL:CC + | +LL | let _ = uwu(ptr, core::mem::transmute(meta)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + From c3b8509654451e746d6a33d2009c0c68a60c34ad Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 5 Jun 2022 12:26:16 -0400 Subject: [PATCH 3247/3747] =?UTF-8?q?rename=20ExperimentalUb=20=E2=86=92?= =?UTF-8?q?=20StackedBorrowsUb?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/diagnostics.rs | 14 +++++++------- src/stacked_borrows.rs | 9 +-------- 2 files changed, 8 insertions(+), 15 deletions(-) diff --git a/src/diagnostics.rs b/src/diagnostics.rs index 52f93a6cea9d9..0e3e693e33f90 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -16,10 +16,9 @@ pub enum TerminationInfo { Exit(i64), Abort(String), UnsupportedInIsolation(String), - ExperimentalUb { + StackedBorrowsUb { msg: String, help: Option, - url: String, history: Option, }, Deadlock, @@ -43,7 +42,7 @@ impl fmt::Display for TerminationInfo { Exit(code) => write!(f, "the evaluated program completed with exit code {}", code), Abort(msg) => write!(f, "{}", msg), UnsupportedInIsolation(msg) => write!(f, "{}", msg), - ExperimentalUb { msg, .. } => write!(f, "{}", msg), + StackedBorrowsUb { msg, .. } => write!(f, "{}", msg), Deadlock => write!(f, "the evaluated program deadlocked"), MultipleSymbolDefinitions { link_name, .. } => write!(f, "multiple definitions of symbol `{}`", link_name), @@ -146,7 +145,7 @@ pub fn report_error<'tcx, 'mir>( Exit(code) => return Some(*code), Abort(_) => Some("abnormal termination"), UnsupportedInIsolation(_) => Some("unsupported operation"), - ExperimentalUb { .. } => Some("Undefined Behavior"), + StackedBorrowsUb { .. } => Some("Undefined Behavior"), Deadlock => Some("deadlock"), MultipleSymbolDefinitions { .. } | SymbolShimClashing { .. } => None, }; @@ -157,11 +156,12 @@ pub fn report_error<'tcx, 'mir>( (None, format!("pass the flag `-Zmiri-disable-isolation` to disable isolation;")), (None, format!("or pass `-Zmiri-isolation-error=warn` to configure Miri to return an error code from isolated operations (if supported for that operation) and continue with a warning")), ], - ExperimentalUb { url, help, history, .. } => { + StackedBorrowsUb { help, history, .. } => { + let url = "https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md"; msg.extend(help.clone()); let mut helps = vec![ - (None, format!("this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental")), - (None, format!("see {} for further information", url)), + (None, format!("this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental")), + (None, format!("see {url} for further information")), ]; match history { Some(TagHistory::Tagged {tag, created: (created_range, created_span), invalidated, protected }) => { diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 88d1b1f10521c..c78741499c2d4 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -250,14 +250,7 @@ pub fn err_sb_ub<'tcx>( help: Option, history: Option, ) -> InterpError<'tcx> { - err_machine_stop!(TerminationInfo::ExperimentalUb { - msg, - help, - url: format!( - "https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md" - ), - history - }) + err_machine_stop!(TerminationInfo::StackedBorrowsUb { msg, help, history }) } // # Stacked Borrows Core Begin From d9f8312d9ab86828ae7e1890630197d742b7ee3f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 11 Jun 2022 17:42:53 -0700 Subject: [PATCH 3248/3747] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 85b2e88ac30cb..83da802cfcf58 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -09d52bc5d4260bac8b9a2ea8ac7a07c5c72906f1 +99930ac7f8cbb5d9b319b2e2e92794fd6f24f556 From 4ccd3f860a7828c49da9ada9c819cfa0079c32d6 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 11 Jun 2022 17:45:33 -0700 Subject: [PATCH 3249/3747] tweak punctuation --- CONTRIBUTING.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 623480890c925..29a89e4a53659 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -134,7 +134,8 @@ build Miri yourself, the Miri shipped by `rustup` will work. All you have to do is set the `MIRI_LIB_SRC` environment variable to the `library` folder of a `rust-lang/rust` repository checkout. Note that changing files in that directory does not automatically trigger a re-build of the standard library; you have to -clear the Miri build cache manually (on Linux, `rm -rf ~/.cache/miri` and on Windows, `rmdir /S "%LOCALAPPDATA%\rust-lang\miri"`). +clear the Miri build cache manually (on Linux, `rm -rf ~/.cache/miri`; +and on Windows, `rmdir /S "%LOCALAPPDATA%\rust-lang\miri"`). ## Configuring `rust-analyzer` @@ -226,7 +227,8 @@ rustup override set stage2 ``` Important: You need to delete the Miri cache when you change the stdlib; otherwise the -old, chached version will be used. On Linux, the cache is located at `~/.cache/miri` and on Windows, the cache is located at `%LOCALAPPDATA%\rust-lang\miri`; the exact +old, chached version will be used. On Linux, the cache is located at `~/.cache/miri`, +and on Windows, it is located at `%LOCALAPPDATA%\rust-lang\miri`; the exact location is printed after the library build: "A libstd for Miri is now available in ...". Note: `./x.py --stage 2 compiler/rustc` currently errors with `thread 'main' From 6ed05d976efb98ab01aadddcd22c6628cc37bf08 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 11 Jun 2022 22:34:01 -0700 Subject: [PATCH 3250/3747] bless --- tests/fail/box-cell-alias.stderr | 2 +- tests/fail/stacked_borrows/alias_through_mutation.stderr | 2 +- tests/fail/stacked_borrows/aliasing_mut1.stderr | 2 +- tests/fail/stacked_borrows/aliasing_mut2.stderr | 2 +- tests/fail/stacked_borrows/aliasing_mut3.stderr | 2 +- tests/fail/stacked_borrows/aliasing_mut4.stderr | 2 +- tests/fail/stacked_borrows/box_exclusive_violation1.stderr | 2 +- tests/fail/stacked_borrows/buggy_as_mut_slice.stderr | 2 +- tests/fail/stacked_borrows/buggy_split_at_mut.stderr | 2 +- tests/fail/stacked_borrows/deallocate_against_barrier1.stderr | 2 +- tests/fail/stacked_borrows/deallocate_against_barrier2.stderr | 2 +- tests/fail/stacked_borrows/illegal_read1.stderr | 2 +- tests/fail/stacked_borrows/illegal_read2.stderr | 2 +- tests/fail/stacked_borrows/illegal_read3.stderr | 2 +- tests/fail/stacked_borrows/illegal_read4.stderr | 2 +- tests/fail/stacked_borrows/illegal_read5.stderr | 2 +- tests/fail/stacked_borrows/illegal_read6.stderr | 2 +- tests/fail/stacked_borrows/illegal_read7.stderr | 2 +- tests/fail/stacked_borrows/illegal_read8.stderr | 2 +- tests/fail/stacked_borrows/illegal_write1.stderr | 2 +- tests/fail/stacked_borrows/illegal_write2.stderr | 2 +- tests/fail/stacked_borrows/illegal_write3.stderr | 2 +- tests/fail/stacked_borrows/illegal_write4.stderr | 2 +- tests/fail/stacked_borrows/illegal_write5.stderr | 2 +- tests/fail/stacked_borrows/illegal_write6.stderr | 2 +- tests/fail/stacked_borrows/interior_mut1.stderr | 2 +- tests/fail/stacked_borrows/interior_mut2.stderr | 2 +- tests/fail/stacked_borrows/invalidate_against_barrier1.stderr | 2 +- tests/fail/stacked_borrows/invalidate_against_barrier2.stderr | 2 +- tests/fail/stacked_borrows/load_invalid_mut.stderr | 2 +- tests/fail/stacked_borrows/load_invalid_shr.stderr | 2 +- tests/fail/stacked_borrows/mut_exclusive_violation1.stderr | 2 +- tests/fail/stacked_borrows/mut_exclusive_violation2.stderr | 2 +- tests/fail/stacked_borrows/outdated_local.stderr | 2 +- tests/fail/stacked_borrows/pass_invalid_mut.stderr | 2 +- tests/fail/stacked_borrows/pass_invalid_shr.stderr | 2 +- tests/fail/stacked_borrows/pointer_smuggling.stderr | 2 +- tests/fail/stacked_borrows/raw_tracking.stderr | 2 +- tests/fail/stacked_borrows/return_invalid_mut.stderr | 2 +- tests/fail/stacked_borrows/return_invalid_mut_option.stderr | 2 +- tests/fail/stacked_borrows/return_invalid_mut_tuple.stderr | 2 +- tests/fail/stacked_borrows/return_invalid_shr.stderr | 2 +- tests/fail/stacked_borrows/return_invalid_shr_option.stderr | 2 +- tests/fail/stacked_borrows/return_invalid_shr_tuple.stderr | 2 +- tests/fail/stacked_borrows/shared_rw_borrows_are_weak1.stderr | 2 +- tests/fail/stacked_borrows/shared_rw_borrows_are_weak2.stderr | 2 +- tests/fail/stacked_borrows/shr_frozen_violation1.stderr | 2 +- tests/fail/stacked_borrows/transmute-is-no-escape.stderr | 2 +- tests/fail/stacked_borrows/unescaped_local.stderr | 2 +- tests/fail/stacked_borrows/unescaped_static.stderr | 2 +- tests/fail/stacked_borrows/zst_slice.stderr | 2 +- 51 files changed, 51 insertions(+), 51 deletions(-) diff --git a/tests/fail/box-cell-alias.stderr b/tests/fail/box-cell-alias.stderr index a4eaec93a8fb2..44813be9780c0 100644 --- a/tests/fail/box-cell-alias.stderr +++ b/tests/fail/box-cell-alias.stderr @@ -7,7 +7,7 @@ LL | unsafe { (*ptr).set(20); } | trying to reborrow for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location | this error occurs as part of a reborrow at ALLOC[0x0..0x1] | - = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: was created by a retag at offsets [0x0..0x1] --> $DIR/box-cell-alias.rs:LL:CC diff --git a/tests/fail/stacked_borrows/alias_through_mutation.stderr b/tests/fail/stacked_borrows/alias_through_mutation.stderr index 6862a67faec26..610a045efcf24 100644 --- a/tests/fail/stacked_borrows/alias_through_mutation.stderr +++ b/tests/fail/stacked_borrows/alias_through_mutation.stderr @@ -7,7 +7,7 @@ LL | let _val = *target_alias; | attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location | this error occurs as part of an access at ALLOC[0x0..0x4] | - = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: was created by a retag at offsets [0x0..0x4] --> $DIR/alias_through_mutation.rs:LL:CC diff --git a/tests/fail/stacked_borrows/aliasing_mut1.stderr b/tests/fail/stacked_borrows/aliasing_mut1.stderr index 5f2e5cbbad36f..7282612b6fc39 100644 --- a/tests/fail/stacked_borrows/aliasing_mut1.stderr +++ b/tests/fail/stacked_borrows/aliasing_mut1.stderr @@ -4,7 +4,7 @@ error: Undefined Behavior: not granting access to tag because incompatible LL | pub fn safe(_x: &mut i32, _y: &mut i32) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not granting access to tag because incompatible item is protected: [Unique for (call ID)] | - = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: was created by a retag at offsets [0x0..0x4] --> $DIR/aliasing_mut1.rs:LL:CC diff --git a/tests/fail/stacked_borrows/aliasing_mut2.stderr b/tests/fail/stacked_borrows/aliasing_mut2.stderr index bb82252e78d42..d314fff6222e3 100644 --- a/tests/fail/stacked_borrows/aliasing_mut2.stderr +++ b/tests/fail/stacked_borrows/aliasing_mut2.stderr @@ -4,7 +4,7 @@ error: Undefined Behavior: not granting access to tag because incompatible LL | pub fn safe(_x: &i32, _y: &mut i32) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not granting access to tag because incompatible item is protected: [SharedReadOnly for (call ID)] | - = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: was created by a retag at offsets [0x0..0x4] --> $DIR/aliasing_mut2.rs:LL:CC diff --git a/tests/fail/stacked_borrows/aliasing_mut3.stderr b/tests/fail/stacked_borrows/aliasing_mut3.stderr index 0cfddcac84868..a4187be0a25b3 100644 --- a/tests/fail/stacked_borrows/aliasing_mut3.stderr +++ b/tests/fail/stacked_borrows/aliasing_mut3.stderr @@ -7,7 +7,7 @@ LL | pub fn safe(_x: &mut i32, _y: &i32) {} | trying to reborrow for SharedReadOnly permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location | this error occurs as part of a reborrow at ALLOC[0x0..0x4] | - = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: tag was most recently created at offsets [0x0..0x4] --> $DIR/aliasing_mut3.rs:LL:CC diff --git a/tests/fail/stacked_borrows/aliasing_mut4.stderr b/tests/fail/stacked_borrows/aliasing_mut4.stderr index 13b589b94754f..0bf5e863bfa33 100644 --- a/tests/fail/stacked_borrows/aliasing_mut4.stderr +++ b/tests/fail/stacked_borrows/aliasing_mut4.stderr @@ -4,7 +4,7 @@ error: Undefined Behavior: not granting access to tag because incompatible LL | pub fn safe(_x: &i32, _y: &mut Cell) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not granting access to tag because incompatible item is protected: [SharedReadOnly for (call ID)] | - = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: was created by a retag at offsets [0x0..0x4] --> $DIR/aliasing_mut4.rs:LL:CC diff --git a/tests/fail/stacked_borrows/box_exclusive_violation1.stderr b/tests/fail/stacked_borrows/box_exclusive_violation1.stderr index 94d4509553484..90d9451285786 100644 --- a/tests/fail/stacked_borrows/box_exclusive_violation1.stderr +++ b/tests/fail/stacked_borrows/box_exclusive_violation1.stderr @@ -7,7 +7,7 @@ LL | *our | attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location | this error occurs as part of an access at ALLOC[0x0..0x4] | - = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: was created by a retag at offsets [0x0..0x4] --> $DIR/box_exclusive_violation1.rs:LL:CC diff --git a/tests/fail/stacked_borrows/buggy_as_mut_slice.stderr b/tests/fail/stacked_borrows/buggy_as_mut_slice.stderr index 8eed3732a0cb0..b65e49fd4a7d0 100644 --- a/tests/fail/stacked_borrows/buggy_as_mut_slice.stderr +++ b/tests/fail/stacked_borrows/buggy_as_mut_slice.stderr @@ -7,7 +7,7 @@ LL | v1[1] = 5; | attempting a write access using at ALLOC[0x4], but that tag does not exist in the borrow stack for this location | this error occurs as part of an access at ALLOC[0x4..0x8] | - = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: was created by a retag at offsets [0x0..0xc] --> $DIR/buggy_as_mut_slice.rs:LL:CC diff --git a/tests/fail/stacked_borrows/buggy_split_at_mut.stderr b/tests/fail/stacked_borrows/buggy_split_at_mut.stderr index d1d8d1f6aa3c9..1b2536c48e045 100644 --- a/tests/fail/stacked_borrows/buggy_split_at_mut.stderr +++ b/tests/fail/stacked_borrows/buggy_split_at_mut.stderr @@ -7,7 +7,7 @@ LL | let (a, b) = safe::split_at_mut(&mut array, 0); | trying to reborrow for Unique permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location | this error occurs as part of a reborrow at ALLOC[0x0..0x10] | - = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: was created by a retag at offsets [0x0..0x10] --> $DIR/buggy_split_at_mut.rs:LL:CC diff --git a/tests/fail/stacked_borrows/deallocate_against_barrier1.stderr b/tests/fail/stacked_borrows/deallocate_against_barrier1.stderr index 38b84e638be4d..58032fa35a1d5 100644 --- a/tests/fail/stacked_borrows/deallocate_against_barrier1.stderr +++ b/tests/fail/stacked_borrows/deallocate_against_barrier1.stderr @@ -4,7 +4,7 @@ error: Undefined Behavior: deallocating while item is protected: [Unique for (call ID)] | - = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information = note: inside `std::alloc::dealloc` at RUSTLIB/alloc/src/alloc.rs:LL:CC diff --git a/tests/fail/stacked_borrows/deallocate_against_barrier2.stderr b/tests/fail/stacked_borrows/deallocate_against_barrier2.stderr index 72e6814b8e14d..088daec040fec 100644 --- a/tests/fail/stacked_borrows/deallocate_against_barrier2.stderr +++ b/tests/fail/stacked_borrows/deallocate_against_barrier2.stderr @@ -4,7 +4,7 @@ error: Undefined Behavior: deallocating while item is protected: [SharedReadWrit LL | unsafe { __rust_dealloc(ptr, layout.size(), layout.align()) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ deallocating while item is protected: [SharedReadWrite for (call ID)] | - = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information = note: inside `std::alloc::dealloc` at RUSTLIB/alloc/src/alloc.rs:LL:CC diff --git a/tests/fail/stacked_borrows/illegal_read1.stderr b/tests/fail/stacked_borrows/illegal_read1.stderr index ca3147e6221ec..bf78c62a0e799 100644 --- a/tests/fail/stacked_borrows/illegal_read1.stderr +++ b/tests/fail/stacked_borrows/illegal_read1.stderr @@ -7,7 +7,7 @@ LL | let _val = *xref; // ...but any use of raw will invalidate our ref. | attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location | this error occurs as part of an access at ALLOC[0x0..0x4] | - = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: was created by a retag at offsets [0x0..0x4] --> $DIR/illegal_read1.rs:LL:CC diff --git a/tests/fail/stacked_borrows/illegal_read2.stderr b/tests/fail/stacked_borrows/illegal_read2.stderr index b6343ddd30b64..b0bc3f9a7f0d3 100644 --- a/tests/fail/stacked_borrows/illegal_read2.stderr +++ b/tests/fail/stacked_borrows/illegal_read2.stderr @@ -7,7 +7,7 @@ LL | let _val = *xref; // ...but any use of raw will invalidate our ref. | attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location | this error occurs as part of an access at ALLOC[0x0..0x4] | - = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: was created by a retag at offsets [0x0..0x4] --> $DIR/illegal_read2.rs:LL:CC diff --git a/tests/fail/stacked_borrows/illegal_read3.stderr b/tests/fail/stacked_borrows/illegal_read3.stderr index 75c4305ee81f5..34580dec4ee4f 100644 --- a/tests/fail/stacked_borrows/illegal_read3.stderr +++ b/tests/fail/stacked_borrows/illegal_read3.stderr @@ -7,7 +7,7 @@ LL | let _val = *xref2; | attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location | this error occurs as part of an access at ALLOC[0x0..0x4] | - = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: was created by a retag at offsets [0x0..0x4] --> $DIR/illegal_read3.rs:LL:CC diff --git a/tests/fail/stacked_borrows/illegal_read4.stderr b/tests/fail/stacked_borrows/illegal_read4.stderr index 968c31ba23af7..19c361a19542a 100644 --- a/tests/fail/stacked_borrows/illegal_read4.stderr +++ b/tests/fail/stacked_borrows/illegal_read4.stderr @@ -7,7 +7,7 @@ LL | let _illegal = *xref2; | attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location | this error occurs as part of an access at ALLOC[0x0..0x4] | - = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: was created by a retag at offsets [0x0..0x4] --> $DIR/illegal_read4.rs:LL:CC diff --git a/tests/fail/stacked_borrows/illegal_read5.stderr b/tests/fail/stacked_borrows/illegal_read5.stderr index df6f0a1c68862..4af149e3831ed 100644 --- a/tests/fail/stacked_borrows/illegal_read5.stderr +++ b/tests/fail/stacked_borrows/illegal_read5.stderr @@ -7,7 +7,7 @@ LL | let _val = *xref; // the mutable one is dead and gone | attempting a read access using at ALLOC[$HEX], but that tag does not exist in the borrow stack for this location | this error occurs as part of an access at ALLOC[$HEX..$HEX] | - = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: was created by a retag at offsets [$HEX..$HEX] --> $DIR/illegal_read5.rs:LL:CC diff --git a/tests/fail/stacked_borrows/illegal_read6.stderr b/tests/fail/stacked_borrows/illegal_read6.stderr index c2be5bb370c5a..499f060c47c24 100644 --- a/tests/fail/stacked_borrows/illegal_read6.stderr +++ b/tests/fail/stacked_borrows/illegal_read6.stderr @@ -7,7 +7,7 @@ LL | let _val = *raw; | attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location | this error occurs as part of an access at ALLOC[0x0..0x4] | - = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: tag was most recently created at offsets [0x0..0x4] --> $DIR/illegal_read6.rs:LL:CC diff --git a/tests/fail/stacked_borrows/illegal_read7.stderr b/tests/fail/stacked_borrows/illegal_read7.stderr index 921d8872b70b8..e7e1685964bca 100644 --- a/tests/fail/stacked_borrows/illegal_read7.stderr +++ b/tests/fail/stacked_borrows/illegal_read7.stderr @@ -7,7 +7,7 @@ LL | let _val = *x.get_mut(); | trying to reborrow for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location | this error occurs as part of a reborrow at ALLOC[0x0..0x4] | - = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: was created by a retag at offsets [0x0..0x4] --> $DIR/illegal_read7.rs:LL:CC diff --git a/tests/fail/stacked_borrows/illegal_read8.stderr b/tests/fail/stacked_borrows/illegal_read8.stderr index 6c6168032b246..21df77775c8b4 100644 --- a/tests/fail/stacked_borrows/illegal_read8.stderr +++ b/tests/fail/stacked_borrows/illegal_read8.stderr @@ -7,7 +7,7 @@ LL | let _fail = *y1; | attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location | this error occurs as part of an access at ALLOC[0x0..0x4] | - = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: was created by a retag at offsets [0x0..0x4] --> $DIR/illegal_read8.rs:LL:CC diff --git a/tests/fail/stacked_borrows/illegal_write1.stderr b/tests/fail/stacked_borrows/illegal_write1.stderr index 08fa05ff9f1ff..76639960a9232 100644 --- a/tests/fail/stacked_borrows/illegal_write1.stderr +++ b/tests/fail/stacked_borrows/illegal_write1.stderr @@ -7,7 +7,7 @@ LL | let _x = *xref; | attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location | this error occurs as part of an access at ALLOC[0x0..0x4] | - = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: was created by a retag at offsets [0x0..0x4] --> $DIR/illegal_write1.rs:LL:CC diff --git a/tests/fail/stacked_borrows/illegal_write2.stderr b/tests/fail/stacked_borrows/illegal_write2.stderr index 13f41eea91539..3a225123d1f2b 100644 --- a/tests/fail/stacked_borrows/illegal_write2.stderr +++ b/tests/fail/stacked_borrows/illegal_write2.stderr @@ -7,7 +7,7 @@ LL | unsafe { *target2 = 13; } | attempting a write access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location | this error occurs as part of an access at ALLOC[0x0..0x4] | - = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: tag was most recently created at offsets [0x0..0x4] --> $DIR/illegal_write2.rs:LL:CC diff --git a/tests/fail/stacked_borrows/illegal_write3.stderr b/tests/fail/stacked_borrows/illegal_write3.stderr index b37caee5ef203..0dc948b291521 100644 --- a/tests/fail/stacked_borrows/illegal_write3.stderr +++ b/tests/fail/stacked_borrows/illegal_write3.stderr @@ -7,7 +7,7 @@ LL | unsafe { *ptr = 42; } | attempting a write access using at ALLOC[0x0], but that tag only grants SharedReadOnly permission for this location | this error occurs as part of an access at ALLOC[0x0..0x4] | - = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: tag was most recently created at offsets [0x0..0x4] --> $DIR/illegal_write3.rs:LL:CC diff --git a/tests/fail/stacked_borrows/illegal_write4.stderr b/tests/fail/stacked_borrows/illegal_write4.stderr index 5c0b4ec868e2e..404e13d1138a2 100644 --- a/tests/fail/stacked_borrows/illegal_write4.stderr +++ b/tests/fail/stacked_borrows/illegal_write4.stderr @@ -7,7 +7,7 @@ LL | let _val = *reference; | attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location | this error occurs as part of an access at ALLOC[0x0..0x4] | - = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: was created by a retag at offsets [0x0..0x4] --> $DIR/illegal_write4.rs:LL:CC diff --git a/tests/fail/stacked_borrows/illegal_write5.stderr b/tests/fail/stacked_borrows/illegal_write5.stderr index f9a4dcfd8d21d..b119908145654 100644 --- a/tests/fail/stacked_borrows/illegal_write5.stderr +++ b/tests/fail/stacked_borrows/illegal_write5.stderr @@ -7,7 +7,7 @@ LL | let _val = *xref; | attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location | this error occurs as part of an access at ALLOC[0x0..0x4] | - = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: was created by a retag at offsets [0x0..0x4] --> $DIR/illegal_write5.rs:LL:CC diff --git a/tests/fail/stacked_borrows/illegal_write6.stderr b/tests/fail/stacked_borrows/illegal_write6.stderr index 5861aeefaf46c..a58abc8377a00 100644 --- a/tests/fail/stacked_borrows/illegal_write6.stderr +++ b/tests/fail/stacked_borrows/illegal_write6.stderr @@ -4,7 +4,7 @@ error: Undefined Behavior: not granting access to tag because incompa LL | unsafe { *y = 2; } | ^^^^^^ not granting access to tag because incompatible item is protected: [Unique for (call ID)] | - = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: tag was most recently created at offsets [0x0..0x4] --> $DIR/illegal_write6.rs:LL:CC diff --git a/tests/fail/stacked_borrows/interior_mut1.stderr b/tests/fail/stacked_borrows/interior_mut1.stderr index af4163c93605e..82cb6e19133d6 100644 --- a/tests/fail/stacked_borrows/interior_mut1.stderr +++ b/tests/fail/stacked_borrows/interior_mut1.stderr @@ -7,7 +7,7 @@ LL | let _val = *inner_shr.get(); | trying to reborrow for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location | this error occurs as part of a reborrow at ALLOC[0x0..0x4] | - = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: was created by a retag at offsets [0x0..0x4] --> $DIR/interior_mut1.rs:LL:CC diff --git a/tests/fail/stacked_borrows/interior_mut2.stderr b/tests/fail/stacked_borrows/interior_mut2.stderr index 5a4ddf381e715..c8a06e32fda03 100644 --- a/tests/fail/stacked_borrows/interior_mut2.stderr +++ b/tests/fail/stacked_borrows/interior_mut2.stderr @@ -7,7 +7,7 @@ LL | let _val = *inner_shr.get(); | trying to reborrow for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location | this error occurs as part of a reborrow at ALLOC[0x0..0x4] | - = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: was created by a retag at offsets [0x0..0x4] --> $DIR/interior_mut2.rs:LL:CC diff --git a/tests/fail/stacked_borrows/invalidate_against_barrier1.stderr b/tests/fail/stacked_borrows/invalidate_against_barrier1.stderr index 47f7a06a85851..08d597ea1895b 100644 --- a/tests/fail/stacked_borrows/invalidate_against_barrier1.stderr +++ b/tests/fail/stacked_borrows/invalidate_against_barrier1.stderr @@ -4,7 +4,7 @@ error: Undefined Behavior: not granting access to tag because incompa LL | let _val = unsafe { *x }; | ^^ not granting access to tag because incompatible item is protected: [Unique for (call ID)] | - = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: tag was most recently created at offsets [0x0..0x4] --> $DIR/invalidate_against_barrier1.rs:LL:CC diff --git a/tests/fail/stacked_borrows/invalidate_against_barrier2.stderr b/tests/fail/stacked_borrows/invalidate_against_barrier2.stderr index fa2e6aa05a2b8..6aefa216ed56d 100644 --- a/tests/fail/stacked_borrows/invalidate_against_barrier2.stderr +++ b/tests/fail/stacked_borrows/invalidate_against_barrier2.stderr @@ -4,7 +4,7 @@ error: Undefined Behavior: not granting access to tag because incompa LL | unsafe { *x = 0 }; | ^^^^^^ not granting access to tag because incompatible item is protected: [SharedReadOnly for (call ID)] | - = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: tag was most recently created at offsets [0x0..0x4] --> $DIR/invalidate_against_barrier2.rs:LL:CC diff --git a/tests/fail/stacked_borrows/load_invalid_mut.stderr b/tests/fail/stacked_borrows/load_invalid_mut.stderr index 00eda4fe5a316..a15900411ce47 100644 --- a/tests/fail/stacked_borrows/load_invalid_mut.stderr +++ b/tests/fail/stacked_borrows/load_invalid_mut.stderr @@ -7,7 +7,7 @@ LL | let _val = *xref_in_mem; | trying to reborrow for Unique permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location | this error occurs as part of a reborrow at ALLOC[0x0..0x4] | - = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: was created by a retag at offsets [0x0..0x4] --> $DIR/load_invalid_mut.rs:LL:CC diff --git a/tests/fail/stacked_borrows/load_invalid_shr.stderr b/tests/fail/stacked_borrows/load_invalid_shr.stderr index eb61b4762f846..85cb8ef93ebd6 100644 --- a/tests/fail/stacked_borrows/load_invalid_shr.stderr +++ b/tests/fail/stacked_borrows/load_invalid_shr.stderr @@ -7,7 +7,7 @@ LL | let _val = *xref_in_mem; | trying to reborrow for SharedReadOnly permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location | this error occurs as part of a reborrow at ALLOC[0x0..0x4] | - = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: was created by a retag at offsets [0x0..0x4] --> $DIR/load_invalid_shr.rs:LL:CC diff --git a/tests/fail/stacked_borrows/mut_exclusive_violation1.stderr b/tests/fail/stacked_borrows/mut_exclusive_violation1.stderr index 2d8ef7c1a4eb4..4e38bcd2a89ce 100644 --- a/tests/fail/stacked_borrows/mut_exclusive_violation1.stderr +++ b/tests/fail/stacked_borrows/mut_exclusive_violation1.stderr @@ -7,7 +7,7 @@ LL | *LEAK = 7; | attempting a write access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location | this error occurs as part of an access at ALLOC[0x0..0x4] | - = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: tag was most recently created at offsets [0x0..0x4] --> $DIR/mut_exclusive_violation1.rs:LL:CC diff --git a/tests/fail/stacked_borrows/mut_exclusive_violation2.stderr b/tests/fail/stacked_borrows/mut_exclusive_violation2.stderr index ae0eab467bf60..fd52dbe348acc 100644 --- a/tests/fail/stacked_borrows/mut_exclusive_violation2.stderr +++ b/tests/fail/stacked_borrows/mut_exclusive_violation2.stderr @@ -7,7 +7,7 @@ LL | let _val = *raw1; | attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location | this error occurs as part of an access at ALLOC[0x0..0x4] | - = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: was created by a retag at offsets [0x0..0x4] --> $DIR/mut_exclusive_violation2.rs:LL:CC diff --git a/tests/fail/stacked_borrows/outdated_local.stderr b/tests/fail/stacked_borrows/outdated_local.stderr index 1c1deac2317f3..fe3bdd00f462e 100644 --- a/tests/fail/stacked_borrows/outdated_local.stderr +++ b/tests/fail/stacked_borrows/outdated_local.stderr @@ -7,7 +7,7 @@ LL | assert_eq!(unsafe { *y }, 1); | attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location | this error occurs as part of an access at ALLOC[0x0..0x4] | - = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: tag was most recently created at offsets [0x0..0x4] --> $DIR/outdated_local.rs:LL:CC diff --git a/tests/fail/stacked_borrows/pass_invalid_mut.stderr b/tests/fail/stacked_borrows/pass_invalid_mut.stderr index 280e51693a5c0..6af914e55f919 100644 --- a/tests/fail/stacked_borrows/pass_invalid_mut.stderr +++ b/tests/fail/stacked_borrows/pass_invalid_mut.stderr @@ -7,7 +7,7 @@ LL | foo(xref); | trying to reborrow for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location | this error occurs as part of a reborrow at ALLOC[0x0..0x4] | - = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: was created by a retag at offsets [0x0..0x4] --> $DIR/pass_invalid_mut.rs:LL:CC diff --git a/tests/fail/stacked_borrows/pass_invalid_shr.stderr b/tests/fail/stacked_borrows/pass_invalid_shr.stderr index b111832193b9c..d38c582734539 100644 --- a/tests/fail/stacked_borrows/pass_invalid_shr.stderr +++ b/tests/fail/stacked_borrows/pass_invalid_shr.stderr @@ -7,7 +7,7 @@ LL | foo(xref); | trying to reborrow for SharedReadOnly permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location | this error occurs as part of a reborrow at ALLOC[0x0..0x4] | - = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: was created by a retag at offsets [0x0..0x4] --> $DIR/pass_invalid_shr.rs:LL:CC diff --git a/tests/fail/stacked_borrows/pointer_smuggling.stderr b/tests/fail/stacked_borrows/pointer_smuggling.stderr index 097de439f79df..68ac631ec09e5 100644 --- a/tests/fail/stacked_borrows/pointer_smuggling.stderr +++ b/tests/fail/stacked_borrows/pointer_smuggling.stderr @@ -7,7 +7,7 @@ LL | let _x = unsafe { *PTR }; | attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location | this error occurs as part of an access at ALLOC[0x0..0x1] | - = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: tag was most recently created at offsets [0x0..0x1] --> $DIR/pointer_smuggling.rs:LL:CC diff --git a/tests/fail/stacked_borrows/raw_tracking.stderr b/tests/fail/stacked_borrows/raw_tracking.stderr index a03d55a90486a..93ae613c3c6b4 100644 --- a/tests/fail/stacked_borrows/raw_tracking.stderr +++ b/tests/fail/stacked_borrows/raw_tracking.stderr @@ -7,7 +7,7 @@ LL | unsafe { *raw1 = 13; } | attempting a write access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location | this error occurs as part of an access at ALLOC[0x0..0x4] | - = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: was created by a retag at offsets [0x0..0x4] --> $DIR/raw_tracking.rs:LL:CC diff --git a/tests/fail/stacked_borrows/return_invalid_mut.stderr b/tests/fail/stacked_borrows/return_invalid_mut.stderr index 6de657b829808..876850590e51e 100644 --- a/tests/fail/stacked_borrows/return_invalid_mut.stderr +++ b/tests/fail/stacked_borrows/return_invalid_mut.stderr @@ -7,7 +7,7 @@ LL | ret | trying to reborrow for Unique permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location | this error occurs as part of a reborrow at ALLOC[0x4..0x8] | - = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: was created by a retag at offsets [0x4..0x8] --> $DIR/return_invalid_mut.rs:LL:CC diff --git a/tests/fail/stacked_borrows/return_invalid_mut_option.stderr b/tests/fail/stacked_borrows/return_invalid_mut_option.stderr index 8b95765dcc460..98decdc3adc81 100644 --- a/tests/fail/stacked_borrows/return_invalid_mut_option.stderr +++ b/tests/fail/stacked_borrows/return_invalid_mut_option.stderr @@ -7,7 +7,7 @@ LL | Some(_x) => {}, | trying to reborrow for Unique permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location | this error occurs as part of a reborrow at ALLOC[0x4..0x8] | - = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: was created by a retag at offsets [0x4..0x8] --> $DIR/return_invalid_mut_option.rs:LL:CC diff --git a/tests/fail/stacked_borrows/return_invalid_mut_tuple.stderr b/tests/fail/stacked_borrows/return_invalid_mut_tuple.stderr index f9e6d65c78e66..3062d821765a3 100644 --- a/tests/fail/stacked_borrows/return_invalid_mut_tuple.stderr +++ b/tests/fail/stacked_borrows/return_invalid_mut_tuple.stderr @@ -7,7 +7,7 @@ LL | foo(&mut (1, 2)).0; | trying to reborrow for Unique permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location | this error occurs as part of a reborrow at ALLOC[0x4..0x8] | - = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: was created by a retag at offsets [0x4..0x8] --> $DIR/return_invalid_mut_tuple.rs:LL:CC diff --git a/tests/fail/stacked_borrows/return_invalid_shr.stderr b/tests/fail/stacked_borrows/return_invalid_shr.stderr index 20dcb8e93c2cf..aa3f7ddde59e2 100644 --- a/tests/fail/stacked_borrows/return_invalid_shr.stderr +++ b/tests/fail/stacked_borrows/return_invalid_shr.stderr @@ -7,7 +7,7 @@ LL | ret | trying to reborrow for SharedReadOnly permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location | this error occurs as part of a reborrow at ALLOC[0x4..0x8] | - = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: was created by a retag at offsets [0x4..0x8] --> $DIR/return_invalid_shr.rs:LL:CC diff --git a/tests/fail/stacked_borrows/return_invalid_shr_option.stderr b/tests/fail/stacked_borrows/return_invalid_shr_option.stderr index 0c41a10a3f97c..81244a87cb065 100644 --- a/tests/fail/stacked_borrows/return_invalid_shr_option.stderr +++ b/tests/fail/stacked_borrows/return_invalid_shr_option.stderr @@ -7,7 +7,7 @@ LL | Some(_x) => {}, | trying to reborrow for SharedReadOnly permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location | this error occurs as part of a reborrow at ALLOC[0x4..0x8] | - = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: was created by a retag at offsets [0x4..0x8] --> $DIR/return_invalid_shr_option.rs:LL:CC diff --git a/tests/fail/stacked_borrows/return_invalid_shr_tuple.stderr b/tests/fail/stacked_borrows/return_invalid_shr_tuple.stderr index 9e7be7ad01388..9519f2f6f07b7 100644 --- a/tests/fail/stacked_borrows/return_invalid_shr_tuple.stderr +++ b/tests/fail/stacked_borrows/return_invalid_shr_tuple.stderr @@ -7,7 +7,7 @@ LL | foo(&mut (1, 2)).0; | trying to reborrow for SharedReadOnly permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location | this error occurs as part of a reborrow at ALLOC[0x4..0x8] | - = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: was created by a retag at offsets [0x4..0x8] --> $DIR/return_invalid_shr_tuple.rs:LL:CC diff --git a/tests/fail/stacked_borrows/shared_rw_borrows_are_weak1.stderr b/tests/fail/stacked_borrows/shared_rw_borrows_are_weak1.stderr index 576a21bbf6d41..8bb67f62b5318 100644 --- a/tests/fail/stacked_borrows/shared_rw_borrows_are_weak1.stderr +++ b/tests/fail/stacked_borrows/shared_rw_borrows_are_weak1.stderr @@ -7,7 +7,7 @@ LL | y.get_mut(); | trying to reborrow for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location | this error occurs as part of a reborrow at ALLOC[0x0..0x4] | - = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: was created by a retag at offsets [0x0..0x4] --> $DIR/shared_rw_borrows_are_weak1.rs:LL:CC diff --git a/tests/fail/stacked_borrows/shared_rw_borrows_are_weak2.stderr b/tests/fail/stacked_borrows/shared_rw_borrows_are_weak2.stderr index e2159ed5892f8..b339785d64842 100644 --- a/tests/fail/stacked_borrows/shared_rw_borrows_are_weak2.stderr +++ b/tests/fail/stacked_borrows/shared_rw_borrows_are_weak2.stderr @@ -7,7 +7,7 @@ LL | let _val = *y; | attempting a read access using at ALLOC[$HEX], but that tag does not exist in the borrow stack for this location | this error occurs as part of an access at ALLOC[$HEX..$HEX] | - = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: was created by a retag at offsets [$HEX..$HEX] --> $DIR/shared_rw_borrows_are_weak2.rs:LL:CC diff --git a/tests/fail/stacked_borrows/shr_frozen_violation1.stderr b/tests/fail/stacked_borrows/shr_frozen_violation1.stderr index 689ad1c6b6684..a2487cca278cc 100644 --- a/tests/fail/stacked_borrows/shr_frozen_violation1.stderr +++ b/tests/fail/stacked_borrows/shr_frozen_violation1.stderr @@ -7,7 +7,7 @@ LL | unsafe { *(x as *const i32 as *mut i32) = 7; } | attempting a write access using at ALLOC[0x0], but that tag only grants SharedReadOnly permission for this location | this error occurs as part of an access at ALLOC[0x0..0x4] | - = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: tag was most recently created at offsets [0x0..0x4] --> $DIR/shr_frozen_violation1.rs:LL:CC diff --git a/tests/fail/stacked_borrows/transmute-is-no-escape.stderr b/tests/fail/stacked_borrows/transmute-is-no-escape.stderr index f2ea4f919c676..75d74ce393463 100644 --- a/tests/fail/stacked_borrows/transmute-is-no-escape.stderr +++ b/tests/fail/stacked_borrows/transmute-is-no-escape.stderr @@ -7,7 +7,7 @@ LL | unsafe { *raw = 13; } | attempting a write access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location | this error occurs as part of an access at ALLOC[0x0..0x4] | - = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information = note: inside `main` at $DIR/transmute-is-no-escape.rs:LL:CC diff --git a/tests/fail/stacked_borrows/unescaped_local.stderr b/tests/fail/stacked_borrows/unescaped_local.stderr index a8d869549a9a7..42a81245f2a83 100644 --- a/tests/fail/stacked_borrows/unescaped_local.stderr +++ b/tests/fail/stacked_borrows/unescaped_local.stderr @@ -7,7 +7,7 @@ LL | unsafe { *raw = 13; } | attempting a write access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location | this error occurs as part of an access at ALLOC[0x0..0x4] | - = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: tag was most recently created at offsets [0x0..0x4] --> $DIR/unescaped_local.rs:LL:CC diff --git a/tests/fail/stacked_borrows/unescaped_static.stderr b/tests/fail/stacked_borrows/unescaped_static.stderr index b191855644c2e..a0ac19f042934 100644 --- a/tests/fail/stacked_borrows/unescaped_static.stderr +++ b/tests/fail/stacked_borrows/unescaped_static.stderr @@ -7,7 +7,7 @@ LL | let _val = unsafe { *ptr_to_first.add(1) }; | attempting a read access using at ALLOC[0x1], but that tag does not exist in the borrow stack for this location | this error occurs as part of an access at ALLOC[0x1..0x2] | - = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information = note: inside `main` at $DIR/unescaped_static.rs:LL:CC diff --git a/tests/fail/stacked_borrows/zst_slice.stderr b/tests/fail/stacked_borrows/zst_slice.stderr index 6809aa3d25fbd..3474f0c2b4234 100644 --- a/tests/fail/stacked_borrows/zst_slice.stderr +++ b/tests/fail/stacked_borrows/zst_slice.stderr @@ -7,7 +7,7 @@ LL | unsafe { &*index.get_unchecked(self) } | trying to reborrow for SharedReadOnly permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location | this error occurs as part of a reborrow at ALLOC[0x4..0x8] | - = help: this indicates a potential bug in the program: it performed an invalid operation, but the rules it violated are still experimental + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: was created by a retag at offsets [0x0..0x0] --> $DIR/zst_slice.rs:LL:CC From 286a30fb1d512b19ea4e614d378682c066a4c97f Mon Sep 17 00:00:00 2001 From: DrMeepster <19316085+DrMeepster@users.noreply.github.com> Date: Sun, 12 Jun 2022 12:10:13 -0700 Subject: [PATCH 3251/3747] correct the path --- CONTRIBUTING.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 29a89e4a53659..4def6dc1b691e 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -135,7 +135,7 @@ is set the `MIRI_LIB_SRC` environment variable to the `library` folder of a `rust-lang/rust` repository checkout. Note that changing files in that directory does not automatically trigger a re-build of the standard library; you have to clear the Miri build cache manually (on Linux, `rm -rf ~/.cache/miri`; -and on Windows, `rmdir /S "%LOCALAPPDATA%\rust-lang\miri"`). +and on Windows, `rmdir /S "%LOCALAPPDATA%\rust-lang\miri\cache"`). ## Configuring `rust-analyzer` @@ -228,7 +228,7 @@ rustup override set stage2 Important: You need to delete the Miri cache when you change the stdlib; otherwise the old, chached version will be used. On Linux, the cache is located at `~/.cache/miri`, -and on Windows, it is located at `%LOCALAPPDATA%\rust-lang\miri`; the exact +and on Windows, it is located at `%LOCALAPPDATA%\rust-lang\miri\cache`; the exact location is printed after the library build: "A libstd for Miri is now available in ...". Note: `./x.py --stage 2 compiler/rustc` currently errors with `thread 'main' From 238bbd63abc3f6deb1fff6fffd6afc2886f4b7a7 Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Sun, 12 Jun 2022 17:55:41 -0700 Subject: [PATCH 3252/3747] Add `#![feature(yeet_expr)]` --- rust-version | 2 +- src/lib.rs | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 83da802cfcf58..3b3645a97bee1 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -99930ac7f8cbb5d9b319b2e2e92794fd6f24f556 +546c826f0ccaab36e897860205281f490db274e6 diff --git a/src/lib.rs b/src/lib.rs index 22869e9b248c0..dc6c0b8dc603a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -5,6 +5,7 @@ #![feature(try_blocks)] #![feature(let_else)] #![feature(io_error_more)] +#![feature(yeet_expr)] #![warn(rust_2018_idioms)] #![allow( clippy::collapsible_else_if, From 0689f36a5528875d3a0c467a327becbed961e6a6 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Mon, 13 Jun 2022 08:55:34 +0000 Subject: [PATCH 3253/3747] Always show stderr on test failure. --- ui_test/src/lib.rs | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/ui_test/src/lib.rs b/ui_test/src/lib.rs index caefee1992ed8..7f9eb48e05f9e 100644 --- a/ui_test/src/lib.rs +++ b/ui_test/src/lib.rs @@ -147,10 +147,7 @@ pub fn run_tests(config: Config) { eprintln!(); eprintln!("command: {:?}", miri); eprintln!(); - // `None` means never dump, as we already dumped it for an `OutputDiffers` - // `Some(false)` means there's no reason to dump, as all errors are independent of the stderr - // `Some(true)` means that there was a pattern in the .rs file that was not found in the output. - let mut dump_stderr = Some(false); + let mut dump_stderr = true; for error in errors { match error { Error::ExitStatus(mode, exit_status) => eprintln!("{mode:?} got {exit_status}"), @@ -160,7 +157,6 @@ pub fn run_tests(config: Config) { "expected because of pattern here: {}:{definition_line}", path.display().to_string().bold() ); - dump_stderr = dump_stderr.map(|_| true); } Error::NoPatternsFound => { eprintln!("{}", "no error patterns found in failure test".red()); @@ -169,7 +165,7 @@ pub fn run_tests(config: Config) { eprintln!("{}", "error pattern found in success test".red()), Error::OutputDiffers { path, actual, expected } => { if path.extension().unwrap() == "stderr" { - dump_stderr = None; + dump_stderr = false; } eprintln!("actual output differed from expected {}", path.display()); eprintln!("{}", pretty_assertions::StrComparison::new(expected, actual)); @@ -203,7 +199,8 @@ pub fn run_tests(config: Config) { } eprintln!(); } - if let Some(true) = dump_stderr { + // Unless we already dumped the stderr via an OutputDiffers diff, let's dump it here. + if dump_stderr { eprintln!("actual stderr:"); eprintln!("{}", stderr); eprintln!(); From 0648f03133a899269a86cdd204d45582871bbb61 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 6 Jun 2022 18:34:41 -0400 Subject: [PATCH 3254/3747] ensure all worker threads stay around --- ui_test/src/lib.rs | 42 ++++++++++++++++++++++++++---------------- 1 file changed, 26 insertions(+), 16 deletions(-) diff --git a/ui_test/src/lib.rs b/ui_test/src/lib.rs index 7f9eb48e05f9e..8b7b4783fabb2 100644 --- a/ui_test/src/lib.rs +++ b/ui_test/src/lib.rs @@ -1,3 +1,4 @@ +use std::collections::VecDeque; use std::fmt::Write; use std::path::{Path, PathBuf}; use std::process::{Command, ExitStatus}; @@ -6,7 +7,6 @@ use std::sync::Mutex; use colored::*; use comments::ErrorMatch; -use crossbeam::queue::SegQueue; use regex::Regex; use rustc_stderr::{Level, Message}; @@ -55,9 +55,8 @@ pub fn run_tests(config: Config) { // Get the triple with which to run the tests let target = config.target.clone().unwrap_or_else(|| config.get_host()); - // A queue for files or folders to process - let todo = SegQueue::new(); - todo.push(config.root_dir.clone()); + // A channel for files to process + let (submit, receive) = crossbeam::channel::unbounded(); // Some statistics and failure reports. let failures = Mutex::new(vec![]); @@ -66,20 +65,31 @@ pub fn run_tests(config: Config) { let filtered = AtomicUsize::default(); crossbeam::scope(|s| { + // Create a thread that is in charge of walking the directory and submitting jobs. + // It closes the channel when it is done. + s.spawn(|_| { + let mut todo = VecDeque::new(); + todo.push_back(config.root_dir.clone()); + while let Some(path) = todo.pop_front() { + if path.is_dir() { + // Enqueue everything inside this directory. + for entry in std::fs::read_dir(path).unwrap() { + todo.push_back(entry.unwrap().path()); + } + } else if path.extension().map(|ext| ext == "rs").unwrap_or(false) { + // Forward .rs files to the test workers. + submit.send(path).unwrap(); + } + } + // There will be no more jobs. This signals the workers to quit. + // (This also ensures `submit` is moved into this closure.) + drop(submit); + }); + + // Create N worker threads that receive files to test. for _ in 0..std::thread::available_parallelism().unwrap().get() { s.spawn(|_| { - while let Some(path) = todo.pop() { - // Collect everything inside directories - if path.is_dir() { - for entry in std::fs::read_dir(path).unwrap() { - todo.push(entry.unwrap().path()); - } - continue; - } - // Only look at .rs files - if !path.extension().map(|ext| ext == "rs").unwrap_or(false) { - continue; - } + for path in &receive { if !config.path_filter.is_empty() { let path_display = path.display().to_string(); if !config.path_filter.iter().any(|filter| path_display.contains(filter)) { From a2cc014231537d913cc51984a6ec11090d62e787 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 6 Jun 2022 18:53:19 -0400 Subject: [PATCH 3255/3747] test files in a deterministic order --- ui_test/src/lib.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/ui_test/src/lib.rs b/ui_test/src/lib.rs index 8b7b4783fabb2..d6938b19bfe49 100644 --- a/ui_test/src/lib.rs +++ b/ui_test/src/lib.rs @@ -73,8 +73,12 @@ pub fn run_tests(config: Config) { while let Some(path) = todo.pop_front() { if path.is_dir() { // Enqueue everything inside this directory. - for entry in std::fs::read_dir(path).unwrap() { - todo.push_back(entry.unwrap().path()); + // We want it sorted, to have some control over scheduling of slow tests. + let mut entries = + std::fs::read_dir(path).unwrap().collect::, _>>().unwrap(); + entries.sort_by_key(|e| e.file_name()); + for entry in entries { + todo.push_back(entry.path()); } } else if path.extension().map(|ext| ext == "rs").unwrap_or(false) { // Forward .rs files to the test workers. From 8ebdad06158f33accee028c2937f95a8a0fca29a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 6 Jun 2022 18:53:33 -0400 Subject: [PATCH 3256/3747] organize more files into folders, and run the weak-mem consistency test as the very first since it is so slow --- .../{weak_memory/consistency.rs => 0weak_memory_consistency.rs} | 2 +- tests/pass/{ => backtrace}/backtrace-api-v0.rs | 0 tests/pass/{ => backtrace}/backtrace-api-v0.stderr | 0 tests/pass/{ => backtrace}/backtrace-api-v0.stdout | 0 tests/pass/{ => backtrace}/backtrace-api-v1.rs | 0 tests/pass/{ => backtrace}/backtrace-api-v1.stderr | 0 tests/pass/{ => backtrace}/backtrace-api-v1.stdout | 0 tests/pass/{ => backtrace}/backtrace-global-alloc.rs | 0 tests/pass/{ => backtrace}/backtrace-global-alloc.stderr | 0 tests/pass/{ => backtrace}/backtrace-std.rs | 0 tests/pass/{ => backtrace}/backtrace-std.stderr | 0 tests/pass/{ => issues}/issue-15063.rs | 0 tests/pass/{ => issues}/issue-15080.rs | 0 tests/pass/{ => issues}/issue-15523-big.rs | 0 tests/pass/{ => issues}/issue-17877.rs | 0 tests/pass/{ => issues}/issue-20575.rs | 0 tests/pass/{ => issues}/issue-23261.rs | 0 tests/pass/{ => issues}/issue-26709.rs | 0 tests/pass/{ => issues}/issue-27901.rs | 0 tests/pass/{ => issues}/issue-29746.rs | 0 tests/pass/{ => issues}/issue-30530.rs | 0 tests/pass/{ => issues}/issue-31267-additional.rs | 0 tests/pass/{ => issues}/issue-33387.rs | 0 tests/pass/{ => issues}/issue-34571.rs | 0 tests/pass/{ => issues}/issue-35815.rs | 0 tests/pass/{ => issues}/issue-36278-prefix-nesting.rs | 0 tests/pass/{ => issues}/issue-3794.rs | 0 tests/pass/{ => issues}/issue-3794.stdout | 0 tests/pass/{ => issues}/issue-53728.rs | 0 tests/pass/{ => issues}/issue-5917.rs | 0 tests/pass/{ => issues}/issue-73223.rs | 0 tests/pass/{ => issues}/issue-91636.rs | 0 tests/pass/{ => issues}/issue-94371.rs | 0 tests/pass/{ => issues}/issue-miri-1075.rs | 0 tests/pass/{ => issues}/issue-miri-133.rs | 0 tests/pass/{ => issues}/issue-miri-184.rs | 0 tests/pass/{ => issues}/issue-miri-1925.rs | 0 tests/pass/{ => issues}/issue-miri-2068-2.rs | 0 tests/pass/{ => issues}/issue-miri-2068.rs | 0 39 files changed, 1 insertion(+), 1 deletion(-) rename tests/pass/{weak_memory/consistency.rs => 0weak_memory_consistency.rs} (99%) rename tests/pass/{ => backtrace}/backtrace-api-v0.rs (100%) rename tests/pass/{ => backtrace}/backtrace-api-v0.stderr (100%) rename tests/pass/{ => backtrace}/backtrace-api-v0.stdout (100%) rename tests/pass/{ => backtrace}/backtrace-api-v1.rs (100%) rename tests/pass/{ => backtrace}/backtrace-api-v1.stderr (100%) rename tests/pass/{ => backtrace}/backtrace-api-v1.stdout (100%) rename tests/pass/{ => backtrace}/backtrace-global-alloc.rs (100%) rename tests/pass/{ => backtrace}/backtrace-global-alloc.stderr (100%) rename tests/pass/{ => backtrace}/backtrace-std.rs (100%) rename tests/pass/{ => backtrace}/backtrace-std.stderr (100%) rename tests/pass/{ => issues}/issue-15063.rs (100%) rename tests/pass/{ => issues}/issue-15080.rs (100%) rename tests/pass/{ => issues}/issue-15523-big.rs (100%) rename tests/pass/{ => issues}/issue-17877.rs (100%) rename tests/pass/{ => issues}/issue-20575.rs (100%) rename tests/pass/{ => issues}/issue-23261.rs (100%) rename tests/pass/{ => issues}/issue-26709.rs (100%) rename tests/pass/{ => issues}/issue-27901.rs (100%) rename tests/pass/{ => issues}/issue-29746.rs (100%) rename tests/pass/{ => issues}/issue-30530.rs (100%) rename tests/pass/{ => issues}/issue-31267-additional.rs (100%) rename tests/pass/{ => issues}/issue-33387.rs (100%) rename tests/pass/{ => issues}/issue-34571.rs (100%) rename tests/pass/{ => issues}/issue-35815.rs (100%) rename tests/pass/{ => issues}/issue-36278-prefix-nesting.rs (100%) rename tests/pass/{ => issues}/issue-3794.rs (100%) rename tests/pass/{ => issues}/issue-3794.stdout (100%) rename tests/pass/{ => issues}/issue-53728.rs (100%) rename tests/pass/{ => issues}/issue-5917.rs (100%) rename tests/pass/{ => issues}/issue-73223.rs (100%) rename tests/pass/{ => issues}/issue-91636.rs (100%) rename tests/pass/{ => issues}/issue-94371.rs (100%) rename tests/pass/{ => issues}/issue-miri-1075.rs (100%) rename tests/pass/{ => issues}/issue-miri-133.rs (100%) rename tests/pass/{ => issues}/issue-miri-184.rs (100%) rename tests/pass/{ => issues}/issue-miri-1925.rs (100%) rename tests/pass/{ => issues}/issue-miri-2068-2.rs (100%) rename tests/pass/{ => issues}/issue-miri-2068.rs (100%) diff --git a/tests/pass/weak_memory/consistency.rs b/tests/pass/0weak_memory_consistency.rs similarity index 99% rename from tests/pass/weak_memory/consistency.rs rename to tests/pass/0weak_memory_consistency.rs index 8a7c1340cc593..fc9dce0c986ab 100644 --- a/tests/pass/weak_memory/consistency.rs +++ b/tests/pass/0weak_memory_consistency.rs @@ -214,7 +214,7 @@ fn test_single_thread() { } pub fn main() { - for _ in 0..100 { + for _ in 0..50 { test_single_thread(); test_mixed_access(); test_load_buffering_acq_rel(); diff --git a/tests/pass/backtrace-api-v0.rs b/tests/pass/backtrace/backtrace-api-v0.rs similarity index 100% rename from tests/pass/backtrace-api-v0.rs rename to tests/pass/backtrace/backtrace-api-v0.rs diff --git a/tests/pass/backtrace-api-v0.stderr b/tests/pass/backtrace/backtrace-api-v0.stderr similarity index 100% rename from tests/pass/backtrace-api-v0.stderr rename to tests/pass/backtrace/backtrace-api-v0.stderr diff --git a/tests/pass/backtrace-api-v0.stdout b/tests/pass/backtrace/backtrace-api-v0.stdout similarity index 100% rename from tests/pass/backtrace-api-v0.stdout rename to tests/pass/backtrace/backtrace-api-v0.stdout diff --git a/tests/pass/backtrace-api-v1.rs b/tests/pass/backtrace/backtrace-api-v1.rs similarity index 100% rename from tests/pass/backtrace-api-v1.rs rename to tests/pass/backtrace/backtrace-api-v1.rs diff --git a/tests/pass/backtrace-api-v1.stderr b/tests/pass/backtrace/backtrace-api-v1.stderr similarity index 100% rename from tests/pass/backtrace-api-v1.stderr rename to tests/pass/backtrace/backtrace-api-v1.stderr diff --git a/tests/pass/backtrace-api-v1.stdout b/tests/pass/backtrace/backtrace-api-v1.stdout similarity index 100% rename from tests/pass/backtrace-api-v1.stdout rename to tests/pass/backtrace/backtrace-api-v1.stdout diff --git a/tests/pass/backtrace-global-alloc.rs b/tests/pass/backtrace/backtrace-global-alloc.rs similarity index 100% rename from tests/pass/backtrace-global-alloc.rs rename to tests/pass/backtrace/backtrace-global-alloc.rs diff --git a/tests/pass/backtrace-global-alloc.stderr b/tests/pass/backtrace/backtrace-global-alloc.stderr similarity index 100% rename from tests/pass/backtrace-global-alloc.stderr rename to tests/pass/backtrace/backtrace-global-alloc.stderr diff --git a/tests/pass/backtrace-std.rs b/tests/pass/backtrace/backtrace-std.rs similarity index 100% rename from tests/pass/backtrace-std.rs rename to tests/pass/backtrace/backtrace-std.rs diff --git a/tests/pass/backtrace-std.stderr b/tests/pass/backtrace/backtrace-std.stderr similarity index 100% rename from tests/pass/backtrace-std.stderr rename to tests/pass/backtrace/backtrace-std.stderr diff --git a/tests/pass/issue-15063.rs b/tests/pass/issues/issue-15063.rs similarity index 100% rename from tests/pass/issue-15063.rs rename to tests/pass/issues/issue-15063.rs diff --git a/tests/pass/issue-15080.rs b/tests/pass/issues/issue-15080.rs similarity index 100% rename from tests/pass/issue-15080.rs rename to tests/pass/issues/issue-15080.rs diff --git a/tests/pass/issue-15523-big.rs b/tests/pass/issues/issue-15523-big.rs similarity index 100% rename from tests/pass/issue-15523-big.rs rename to tests/pass/issues/issue-15523-big.rs diff --git a/tests/pass/issue-17877.rs b/tests/pass/issues/issue-17877.rs similarity index 100% rename from tests/pass/issue-17877.rs rename to tests/pass/issues/issue-17877.rs diff --git a/tests/pass/issue-20575.rs b/tests/pass/issues/issue-20575.rs similarity index 100% rename from tests/pass/issue-20575.rs rename to tests/pass/issues/issue-20575.rs diff --git a/tests/pass/issue-23261.rs b/tests/pass/issues/issue-23261.rs similarity index 100% rename from tests/pass/issue-23261.rs rename to tests/pass/issues/issue-23261.rs diff --git a/tests/pass/issue-26709.rs b/tests/pass/issues/issue-26709.rs similarity index 100% rename from tests/pass/issue-26709.rs rename to tests/pass/issues/issue-26709.rs diff --git a/tests/pass/issue-27901.rs b/tests/pass/issues/issue-27901.rs similarity index 100% rename from tests/pass/issue-27901.rs rename to tests/pass/issues/issue-27901.rs diff --git a/tests/pass/issue-29746.rs b/tests/pass/issues/issue-29746.rs similarity index 100% rename from tests/pass/issue-29746.rs rename to tests/pass/issues/issue-29746.rs diff --git a/tests/pass/issue-30530.rs b/tests/pass/issues/issue-30530.rs similarity index 100% rename from tests/pass/issue-30530.rs rename to tests/pass/issues/issue-30530.rs diff --git a/tests/pass/issue-31267-additional.rs b/tests/pass/issues/issue-31267-additional.rs similarity index 100% rename from tests/pass/issue-31267-additional.rs rename to tests/pass/issues/issue-31267-additional.rs diff --git a/tests/pass/issue-33387.rs b/tests/pass/issues/issue-33387.rs similarity index 100% rename from tests/pass/issue-33387.rs rename to tests/pass/issues/issue-33387.rs diff --git a/tests/pass/issue-34571.rs b/tests/pass/issues/issue-34571.rs similarity index 100% rename from tests/pass/issue-34571.rs rename to tests/pass/issues/issue-34571.rs diff --git a/tests/pass/issue-35815.rs b/tests/pass/issues/issue-35815.rs similarity index 100% rename from tests/pass/issue-35815.rs rename to tests/pass/issues/issue-35815.rs diff --git a/tests/pass/issue-36278-prefix-nesting.rs b/tests/pass/issues/issue-36278-prefix-nesting.rs similarity index 100% rename from tests/pass/issue-36278-prefix-nesting.rs rename to tests/pass/issues/issue-36278-prefix-nesting.rs diff --git a/tests/pass/issue-3794.rs b/tests/pass/issues/issue-3794.rs similarity index 100% rename from tests/pass/issue-3794.rs rename to tests/pass/issues/issue-3794.rs diff --git a/tests/pass/issue-3794.stdout b/tests/pass/issues/issue-3794.stdout similarity index 100% rename from tests/pass/issue-3794.stdout rename to tests/pass/issues/issue-3794.stdout diff --git a/tests/pass/issue-53728.rs b/tests/pass/issues/issue-53728.rs similarity index 100% rename from tests/pass/issue-53728.rs rename to tests/pass/issues/issue-53728.rs diff --git a/tests/pass/issue-5917.rs b/tests/pass/issues/issue-5917.rs similarity index 100% rename from tests/pass/issue-5917.rs rename to tests/pass/issues/issue-5917.rs diff --git a/tests/pass/issue-73223.rs b/tests/pass/issues/issue-73223.rs similarity index 100% rename from tests/pass/issue-73223.rs rename to tests/pass/issues/issue-73223.rs diff --git a/tests/pass/issue-91636.rs b/tests/pass/issues/issue-91636.rs similarity index 100% rename from tests/pass/issue-91636.rs rename to tests/pass/issues/issue-91636.rs diff --git a/tests/pass/issue-94371.rs b/tests/pass/issues/issue-94371.rs similarity index 100% rename from tests/pass/issue-94371.rs rename to tests/pass/issues/issue-94371.rs diff --git a/tests/pass/issue-miri-1075.rs b/tests/pass/issues/issue-miri-1075.rs similarity index 100% rename from tests/pass/issue-miri-1075.rs rename to tests/pass/issues/issue-miri-1075.rs diff --git a/tests/pass/issue-miri-133.rs b/tests/pass/issues/issue-miri-133.rs similarity index 100% rename from tests/pass/issue-miri-133.rs rename to tests/pass/issues/issue-miri-133.rs diff --git a/tests/pass/issue-miri-184.rs b/tests/pass/issues/issue-miri-184.rs similarity index 100% rename from tests/pass/issue-miri-184.rs rename to tests/pass/issues/issue-miri-184.rs diff --git a/tests/pass/issue-miri-1925.rs b/tests/pass/issues/issue-miri-1925.rs similarity index 100% rename from tests/pass/issue-miri-1925.rs rename to tests/pass/issues/issue-miri-1925.rs diff --git a/tests/pass/issue-miri-2068-2.rs b/tests/pass/issues/issue-miri-2068-2.rs similarity index 100% rename from tests/pass/issue-miri-2068-2.rs rename to tests/pass/issues/issue-miri-2068-2.rs diff --git a/tests/pass/issue-miri-2068.rs b/tests/pass/issues/issue-miri-2068.rs similarity index 100% rename from tests/pass/issue-miri-2068.rs rename to tests/pass/issues/issue-miri-2068.rs From c16c45362ccb854ab9438a5db5ad6152dc7fd519 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Mon, 13 Jun 2022 15:20:01 +0200 Subject: [PATCH 3257/3747] Document file sorting --- ui_test/README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/ui_test/README.md b/ui_test/README.md index b3c9a3378cf30..07a0a67b9143f 100644 --- a/ui_test/README.md +++ b/ui_test/README.md @@ -1,5 +1,10 @@ A smaller version of compiletest-rs +## Magic behavior + +* Tests are run in order of their filenames (files first, then recursing into folders). + So if you have any slow tests, prepend them with a small integral number to make them get run first, taking advantage of parallelism as much as possible (instead of waiting for the slow tests at the end). + ## Supported magic comment annotations Note that the space after `//`, when it is present, is *not* optional -- it must be exactly one. From 56a4c132b6c8661010b5a176d334fd2a0db7cf53 Mon Sep 17 00:00:00 2001 From: Andy Wang Date: Mon, 13 Jun 2022 18:24:19 +0100 Subject: [PATCH 3258/3747] Reduce the number of iterations --- tests/pass/concurrency/linux-futex.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/pass/concurrency/linux-futex.rs b/tests/pass/concurrency/linux-futex.rs index 56aba60d534a6..0d30ddff4809f 100644 --- a/tests/pass/concurrency/linux-futex.rs +++ b/tests/pass/concurrency/linux-futex.rs @@ -212,7 +212,7 @@ const FREE: i32 = 0; const HELD: i32 = 1; fn concurrent_wait_wake() { static FUTEX: AtomicI32 = AtomicI32::new(0); - for _ in 0..100 { + for _ in 0..20 { // Suppose the main thread is holding a lock implemented using futex... FUTEX.store(HELD, Ordering::Relaxed); From 807a19a50a663c75874bb79afeecd4b12de583e2 Mon Sep 17 00:00:00 2001 From: Andy Wang Date: Wed, 15 Jun 2022 01:44:32 +0100 Subject: [PATCH 3259/3747] Elaborate correctness comments --- src/shims/unix/linux/sync.rs | 51 +++++++++++++++++++++++++++++------- 1 file changed, 41 insertions(+), 10 deletions(-) diff --git a/src/shims/unix/linux/sync.rs b/src/shims/unix/linux/sync.rs index 42494da37b799..37d694a32f80e 100644 --- a/src/shims/unix/linux/sync.rs +++ b/src/shims/unix/linux/sync.rs @@ -126,16 +126,47 @@ pub fn futex<'tcx>( Align::from_bytes(4).unwrap(), CheckInAllocMsg::MemoryAccessTest, )?; - // This SeqCst fence is paired with the SeqCst fence in futex_wake. - // Together, they make sure that our read on addr observes the latest - // value in modification order. + // There may be a concurrent thread changing the value of addr + // and then invoking the FUTEX_WAKE syscall. It is critical that the + // effects of this and the other thread are correctly observed, + // otherwise we will deadlock. // - // If there is another thread which has changed the value of - // addr (to something other than expected) and called futex_wake - // before we get to run, then we must not block our thread - // because there'll be no one to wake us. We must see - // the value changed by the other thread and return without - // actually waiting. + // There are two scenarios to consider: + // 1. If we (FUTEX_WAIT) executes first, we'll push ourselves into + // the waiters queue and go to sleep. They (addr write & FUTEX_WAKE) + // will see us in the queue and wake us up. + // 2. If they (addr write & FUTEX_WAKE) executes first, we must observe + // addr's new value. If we see an outdated value that happens to equal + // the expected val, then we'll put ourselves to sleep with no one to wake us + // up, so we end up with a deadlock. This is prevented by having a SeqCst + // fence inside FUTEX_WAKE syscall, and another SeqCst fence + // below, the atomic read on addr after the SeqCst fence is guaranteed + // not to see any value older than the addr write immediately before + // calling FUTEX_WAKE. We'll see futex_val != val and return without + // sleeping. + // + // Note that the fences do not create any happens-before relationship. + // The read sees the write immediately before the fence not because + // one happens after the other, but is instead due to a guarantee unique + // to SeqCst fences that restricts what an atomic read placed AFTER the + // fence can see. The read still has to be atomic, otherwise it's a data + // race. This guarantee cannot be achieved with acquire-release fences + // since they only talk about reads placed BEFORE a fence - and places + // no restrictions on what the read itself can see, only that there is + // a happens-before between the fences IF the read happens to see the + // right value. This is useless to us, since we need the read itself + // to see an up-to-date value. + // + // It is also critical that the fence, the atomic load, and the comparison + // altogether happen atomically. If the other thread's fence in FUTEX_WAKE + // gets interleaved after our fence, then we lose the guarantee on the + // atomic load being up-to-date; if the other thread's write on addr and FUTEX_WAKE + // call are interleaved after the load but before the comparison, then we get a TOCTOU + // race condition, and go to sleep thinking the other thread will wake us up, + // even though they have already finished. + // + // Thankfully, preemptions cannot happen inside a Miri shim, so we do not need to + // do anything special to guarantee fence-load-comparison atomicity. this.atomic_fence(&[], AtomicFenceOp::SeqCst)?; // Read an `i32` through the pointer, regardless of any wrapper types. // It's not uncommon for `addr` to be passed as another type than `*mut i32`, such as `*const AtomicI32`. @@ -149,7 +180,7 @@ pub fn futex<'tcx>( )? .to_i32()?; if val == futex_val { - // The value still matches, so we block the trait make it wait for FUTEX_WAKE. + // The value still matches, so we block the thread make it wait for FUTEX_WAKE. this.block_thread(thread); this.futex_wait(addr_usize, thread, bitset); // Succesfully waking up from FUTEX_WAIT always returns zero. From e70c631a3b15ad5e72c43c09187c6a02e3b92888 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 16 Jun 2022 11:02:54 -0700 Subject: [PATCH 3260/3747] add ICE error level --- ui_test/src/rustc_stderr.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ui_test/src/rustc_stderr.rs b/ui_test/src/rustc_stderr.rs index ac76a78a3cbcb..203014c50d52f 100644 --- a/ui_test/src/rustc_stderr.rs +++ b/ui_test/src/rustc_stderr.rs @@ -16,6 +16,7 @@ struct RustcMessage { #[derive(Copy, Clone, Debug, PartialOrd, Ord, PartialEq, Eq)] pub(crate) enum Level { + Ice = 5, Error = 4, Warn = 3, Help = 2, @@ -52,6 +53,7 @@ impl std::str::FromStr for Level { "HELP" | "help" => Ok(Self::Help), "NOTE" | "note" => Ok(Self::Note), "failure-note" => Ok(Self::FailureNote), + "error: internal compiler error" => Ok(Self::Ice), _ => Err(format!("unknown level `{s}`")), } } From d194e9823c2a51008c2e3b1e2f7b5a6fffead0a1 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 16 Jun 2022 10:03:41 -0700 Subject: [PATCH 3261/3747] rustup --- rust-version | 2 +- tests/fail/data_race/fence_after_load.rs | 3 ++- tests/fail/erroneous_const.stderr | 4 ++-- tests/pass/concurrency/channels.rs | 15 ++++++++++++--- tests/pass/threadleak_ignored.rs | 3 ++- 5 files changed, 19 insertions(+), 8 deletions(-) diff --git a/rust-version b/rust-version index 3b3645a97bee1..792ac12b80440 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -546c826f0ccaab36e897860205281f490db274e6 +1f34da9ec8a85b6f86c5fa1c121ab6f88f2f4966 diff --git a/tests/fail/data_race/fence_after_load.rs b/tests/fail/data_race/fence_after_load.rs index b381715933866..20cc691f88e16 100644 --- a/tests/fail/data_race/fence_after_load.rs +++ b/tests/fail/data_race/fence_after_load.rs @@ -1,4 +1,5 @@ -// compile-flags: -Zmiri-disable-isolation +// We want to control preemption here. +// compile-flags: -Zmiri-disable-isolation -Zmiri-preemption-rate=0 // ignore-windows: Concurrency on Windows is not supported yet. use std::sync::Arc; use std::sync::atomic::{AtomicUsize, Ordering, fence}; diff --git a/tests/fail/erroneous_const.stderr b/tests/fail/erroneous_const.stderr index e1758ad657de7..d4b8f25e03851 100644 --- a/tests/fail/erroneous_const.stderr +++ b/tests/fail/erroneous_const.stderr @@ -6,11 +6,11 @@ LL | const VOID: ! = panic!(); | = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) -error: post-monomorphization error: encountered constants with type errors, stopping evaluation +error: post-monomorphization error: referenced constant has errors --> $DIR/erroneous_const.rs:LL:CC | LL | let _ = PrintName::::VOID; - | ^^^^^^^^^^^^^^^^^^^^ encountered constants with type errors, stopping evaluation + | ^^^^^^^^^^^^^^^^^^^^ referenced constant has errors | = note: inside `no_codegen::` at $DIR/erroneous_const.rs:LL:CC note: inside `main` at $DIR/erroneous_const.rs:LL:CC diff --git a/tests/pass/concurrency/channels.rs b/tests/pass/concurrency/channels.rs index b0c095b2d3598..0d6c1749eb51e 100644 --- a/tests/pass/concurrency/channels.rs +++ b/tests/pass/concurrency/channels.rs @@ -9,20 +9,23 @@ use std::thread; /// The test taken from the Rust documentation. fn simple_send() { let (tx, rx) = channel(); - thread::spawn(move || { + let t = thread::spawn(move || { tx.send(10).unwrap(); }); assert_eq!(rx.recv().unwrap(), 10); + t.join().unwrap(); } /// The test taken from the Rust documentation. fn multiple_send() { let (tx, rx) = channel(); + let mut threads = vec![]; for i in 0..10 { let tx = tx.clone(); - thread::spawn(move || { + let t = thread::spawn(move || { tx.send(i).unwrap(); }); + threads.push(t); } let mut sum = 0; @@ -32,6 +35,10 @@ fn multiple_send() { sum += j; } assert_eq!(sum, 45); + + for t in threads { + t.join().unwrap(); + } } /// The test taken from the Rust documentation. @@ -41,13 +48,15 @@ fn send_on_sync() { // this returns immediately sender.send(1).unwrap(); - thread::spawn(move || { + let t = thread::spawn(move || { // this will block until the previous message has been received sender.send(2).unwrap(); }); assert_eq!(receiver.recv().unwrap(), 1); assert_eq!(receiver.recv().unwrap(), 2); + + t.join().unwrap(); } fn main() { diff --git a/tests/pass/threadleak_ignored.rs b/tests/pass/threadleak_ignored.rs index cbdc7c6e91068..36d39a72b7998 100644 --- a/tests/pass/threadleak_ignored.rs +++ b/tests/pass/threadleak_ignored.rs @@ -1,5 +1,6 @@ // ignore-windows: Concurrency on Windows is not supported yet. -// compile-flags: -Zmiri-ignore-leaks +// FIXME: disallow preemption to work around https://github.com/rust-lang/rust/issues/55005 +// compile-flags: -Zmiri-ignore-leaks -Zmiri-preemption-rate=0 //! Test that leaking threads works, and that their destructors are not executed. From 735e95385317fc658360859cc5381cfd3f4779bf Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 18 Jun 2022 07:49:40 -0700 Subject: [PATCH 3262/3747] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 792ac12b80440..9782fbe6cd456 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -1f34da9ec8a85b6f86c5fa1c121ab6f88f2f4966 +cdcc53b7dc002ea4a7a28105010c5a1126ee31b7 From 737a5b3b9814e919d30f60323a7679697a34b153 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 18 Jun 2022 07:59:46 -0700 Subject: [PATCH 3263/3747] tweak correctness comment --- src/shims/unix/linux/sync.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/shims/unix/linux/sync.rs b/src/shims/unix/linux/sync.rs index 37d694a32f80e..0fdbde8d6775f 100644 --- a/src/shims/unix/linux/sync.rs +++ b/src/shims/unix/linux/sync.rs @@ -132,10 +132,10 @@ pub fn futex<'tcx>( // otherwise we will deadlock. // // There are two scenarios to consider: - // 1. If we (FUTEX_WAIT) executes first, we'll push ourselves into + // 1. If we (FUTEX_WAIT) execute first, we'll push ourselves into // the waiters queue and go to sleep. They (addr write & FUTEX_WAKE) // will see us in the queue and wake us up. - // 2. If they (addr write & FUTEX_WAKE) executes first, we must observe + // 2. If they (addr write & FUTEX_WAKE) execute first, we must observe // addr's new value. If we see an outdated value that happens to equal // the expected val, then we'll put ourselves to sleep with no one to wake us // up, so we end up with a deadlock. This is prevented by having a SeqCst @@ -157,7 +157,9 @@ pub fn futex<'tcx>( // right value. This is useless to us, since we need the read itself // to see an up-to-date value. // - // It is also critical that the fence, the atomic load, and the comparison + // The above case distinction is valid since both FUTEX_WAIT and FUTEX_WAKE + // contain a SeqCst fence, therefore inducting a total order between the operations. + // It is also critical that the fence, the atomic load, and the comparison in FUTEX_WAIT // altogether happen atomically. If the other thread's fence in FUTEX_WAKE // gets interleaved after our fence, then we lose the guarantee on the // atomic load being up-to-date; if the other thread's write on addr and FUTEX_WAKE From 3f9414565d4e0c54edc20123168d70741454913b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 19 Jun 2022 09:18:16 -0700 Subject: [PATCH 3264/3747] readme --- README.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 50a43436dc219..88ac8a1353045 100644 --- a/README.md +++ b/README.md @@ -21,12 +21,15 @@ for example: * **Experimental**: Violations of the [Stacked Borrows] rules governing aliasing for reference types * **Experimental**: Data races -* **Experimental**: Emulation of weak memory effects (i.e., reads can return outdated values) On top of that, Miri will also tell you about memory leaks: when there is memory still allocated at the end of the execution, and that memory is not reachable from a global `static`, Miri will raise an error. +Miri supports almost all Rust language features; in particular, unwinding and +concurrency are properly supported (including some experimental emulation of +weak memory effects, i.e., reads can return outdated values). + You can use Miri to emulate programs on other targets, e.g. to ensure that byte-level data manipulation works correctly both on little-endian and big-endian systems. See @@ -62,8 +65,6 @@ in your program, and cannot run all programs: not support networking. System API support varies between targets; if you run on Windows it is a good idea to use `--target x86_64-unknown-linux-gnu` to get better support. -* Threading support is not finished yet. E.g. spin loops (without syscalls) just - loop forever. There is no threading support on Windows. * Weak memory emulation may produce weak behaivours unobservable by compiled programs running on real hardware when `SeqCst` fences are used, and it cannot produce all behaviors possibly observable on real hardware. From 817adda794b916923534b2733286ee8522430d56 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sat, 30 Apr 2022 11:07:36 -0700 Subject: [PATCH 3265/3747] Add rustfmt::skip to some files Five of the files being skipped here are because rustfmt is buggy (see the error messages below). The others have clearly preferable manual formatting. error[internal]: left behind trailing whitespace --> tests/fail/validity/transmute_through_ptr.rs:18:18:1 | 18 | | ^^^^ | warning: rustfmt has failed to format. See previous 1 errors. error[internal]: left behind trailing whitespace --> tests/fail/stacked_borrows/illegal_read2.rs:10:10:1 | 10 | | ^^^^ | warning: rustfmt has failed to format. See previous 1 errors. error[internal]: left behind trailing whitespace --> tests/fail/stacked_borrows/illegal_read5.rs:15:15:1 | 15 | | ^^^^ | warning: rustfmt has failed to format. See previous 1 errors. error[internal]: left behind trailing whitespace --> tests/fail/stacked_borrows/illegal_read1.rs:10:10:1 | 10 | | ^^^^ | warning: rustfmt has failed to format. See previous 1 errors. error[internal]: left behind trailing whitespace --> tests/fail/erroneous_const2.rs:9:9:1 | 9 | | ^^^^ | warning: rustfmt has failed to format. See previous 1 errors. --- bench-cargo-miri/mse/src/main.rs | 2 ++ tests/fail/erroneous_const2.rs | 1 + tests/fail/stacked_borrows/illegal_read1.rs | 1 + tests/fail/stacked_borrows/illegal_read2.rs | 1 + tests/fail/stacked_borrows/illegal_read5.rs | 1 + tests/fail/validity/transmute_through_ptr.rs | 1 + tests/pass/enums.rs | 1 + 7 files changed, 8 insertions(+) diff --git a/bench-cargo-miri/mse/src/main.rs b/bench-cargo-miri/mse/src/main.rs index b182f6cec65a8..bb5fb80e48c18 100644 --- a/bench-cargo-miri/mse/src/main.rs +++ b/bench-cargo-miri/mse/src/main.rs @@ -1,4 +1,6 @@ +#[rustfmt::skip] // no need to wrap these arrays onto hundreds of lines static EXPECTED: &[u8] = &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 0, 0, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 1, 0, 255, 255, 1, 0, 255, 255, 1, 0, 255, 255, 1, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 255, 255, 0, 0, 254, 255, 0, 0, 254, 255, 0, 0, 254, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 255, 255, 1, 0, 255, 255, 1, 0, 0, 0, 1, 0, 255, 255, 2, 0, 255, 255, 2, 0, 255, 255, 2, 0, 255, 255, 2, 0, 255, 255, 2, 0, 255, 255, 1, 0, 255, 255, 1, 0, 255, 255, 0, 0, 254, 255, 0, 0, 254, 255, 0, 0, 254, 255, 255, 255, 254, 255, 254, 255, 254, 255, 253, 255, 253, 255, 253, 255, 253, 255, 252, 255, 254, 255, 251, 255, 254, 255, 251, 255, 254, 255, 252, 255, 255, 255, 252, 255, 0, 0, 252, 255, 0, 0, 252, 255, 1, 0, 252, 255, 1, 0, 252, 255, 2, 0, 252, 255, 2, 0, 252, 255, 2, 0, 252, 255, 2, 0, 252, 255, 2, 0, 253, 255, 1, 0, 252, 255, 0, 0, 252, 255, 255, 255, 251, 255, 0, 0, 251, 255, 0, 0, 251, 255, 0, 0, 252, 255, 2, 0, 252, 255, 3, 0, 252, 255, 4, 0, 253, 255, 5, 0, 254, 255, 5, 0, 253, 255, 6, 0, 253, 255, 6, 0, 253, 255, 5, 0, 253, 255, 5, 0, 254, 255, 4, 0, 254, 255, 3, 0, 251, 255, 0, 0, 250, 255, 255, 255, 253, 255, 254, 255, 252, 255, 252, 255, 247, 255, 251, 255, 247, 255, 252, 255, 252, 255, 254, 255, 252, 255, 254, 255, 252, 255, 255, 255, 254, 255, 1, 0, 1, 0, 1, 0, 4, 0, 2, 0, 8, 0, 2, 0, 12, 0, 1, 0, 13, 0, 0, 0, 12, 0, 0, 0, 11, 0, 255, 255, 8, 0, 254, 255, 7, 0, 0, 0, 7, 0, 253, 255, 11, 0, 248, 255, 15, 0, 247, 255, 17, 0, 250, 255, 17, 0, 251, 255, 13, 0, 253, 255, 7, 0, 255, 255, 3, 0, 255, 255, 254, 255, 255, 255, 252, 255, 255, 255, 252, 255, 254, 255, 250, 255, 255, 255, 242, 255, 254, 255, 239, 255, 252, 255, 248, 255, 255, 255, 249, 255, 5, 0, 239, 255, 7, 0, 238, 255, 10, 0, 249, 255, 18, 0, 254, 255, 25, 0, 253, 255, 27, 0, 0, 0, 31, 0, 4, 0, 34, 0, 4, 0, 34, 0, 8, 0, 36, 0, 8, 0, 37, 0, 2, 0, 36, 0, 4, 0, 34, 0, 8, 0, 28, 0, 3, 0, 15, 0, 255, 255, 11, 0, 0, 0, 12, 0, 251, 255, 8, 0, 252, 255, 10, 0, 0, 0, 23, 0, 252, 255, 31, 0, 248, 255, 30, 0, 254, 255, 30, 0, 255, 255, 26, 0, 250, 255, 22, 0, 250, 255, 20, 0, 244, 255, 15, 0, 237, 255, 10, 0, 246, 255, 13, 0, 242, 255, 6, 0, 213, 255, 243, 255, 213, 255, 240, 255, 247, 255, 244, 255, 246, 255, 227, 255, 214, 255, 216, 255, 219, 255, 228, 255, 251, 255, 235, 255, 1, 0, 232, 255, 248, 255, 236, 255, 4, 0, 238, 255, 26, 0, 232, 255, 44, 0, 230, 255, 66, 0, 226, 255, 86, 0, 219, 255, 88, 0, 215, 255, 72, 0, 210, 255, 50, 0, 225, 255, 28, 0, 23, 0, 14, 0, 64, 0, 16, 0, 51, 0, 26, 0, 32, 0, 34, 0, 39, 0, 42, 0, 48, 0, 35, 0, 58, 0, 255, 255, 72, 0, 220, 255, 69, 0, 197, 255, 58, 0, 158, 255, 54, 0, 132, 255, 36, 0, 153, 255, 12, 0, 146, 255, 5, 0, 83, 255, 237, 255, 110, 255, 197, 255, 252, 255, 214, 255, 51, 0, 1, 0, 233, 255, 250, 255, 226, 255, 250, 255, 45, 0, 46, 0, 47, 0, 70, 0, 6, 0, 55, 0, 19, 0, 60, 0, 38, 0, 62, 0, 42, 0, 47, 0, 61, 0, 46, 0, 40, 0, 42, 0, 237, 255, 22, 0, 222, 255, 6, 0, 221, 255, 206, 255, 195, 255, 115, 255, 219, 255, 85, 255, 17, 0, 93, 255, 26, 0, 76, 255, 46, 0, 102, 255, 80, 0, 193, 255, 48, 0, 252, 255, 18, 0, 20, 0, 50, 0, 47, 0, 58, 0, 53, 0, 44, 0, 61, 0, 57, 0, 85, 0, 37, 0, 80, 0, 0, 0, 86, 0, 248, 255, 106, 0, 161, 255, 49, 0, 43, 255, 248, 255, 125, 255, 47, 0, 49, 0, 63, 0, 40, 0, 217, 255, 187, 255, 182, 255, 219, 255, 236, 255, 63, 0, 244, 255, 58, 0, 242, 255, 244, 255, 25, 0, 225, 255, 41, 0, 11, 0, 45, 0, 76, 0, 47, 0, 167, 0, 5, 0, 5, 1, 219, 255, 21, 1, 173, 255, 183, 0, 84, 255, 35, 0, 134, 255, 177, 255, 138, 0, 186, 255, 10, 1, 69, 0, 124, 0, 228, 0, 0, 0, 135, 1, 227, 255, 82, 2, 172, 255, 190, 2, 178, 255, 115, 2, 248, 255, 39, 2, 243, 255, 253, 1, 13, 0, 116, 1, 120, 0, 96, 1, 125, 0, 110, 2, 127, 0, 179, 2, 223, 0, 106, 1, 126, 0, 130, 1, 223, 255, 147, 3, 198, 0, 190, 3, 201, 1, 200, 1, 42, 1, 244, 1, 233, 0, 3, 4, 213, 1, 72, 4, 170, 1, 150, 3, 160, 0, 43, 4, 141, 0, 196, 4, 189, 0, 221, 4, 164, 0, 95, 5, 41, 1, 98, 5, 247, 1, 19, 5, 190, 2, 14, 6, 161, 3, 7, 7, 87, 3, 216, 6, 35, 2, 38, 7, 90, 2, 136, 7, 64, 3, 200, 6, 28, 3, 199, 6, 165, 3, 169, 7, 105, 5, 143, 7, 26, 6, 57, 8, 205, 5, 156, 10, 169, 5, 132, 11, 25, 5, 208, 10, 181, 4, 156, 10, 66, 5, 227, 9, 170, 5, 166, 9, 117, 6, 45, 12, 63, 8, 42, 13, 128, 8, 136, 10, 155, 7, 109, 11, 1, 9, 6, 15, 98, 10, 121, 9, 136, 8, 147, 252, 189, 7, 43, 247, 63, 10, 147, 249, 92, 11, 172, 248, 172, 10, 112, 245, 137, 11, 76, 246, 44, 12, 184, 247, 138, 11, 118, 246, 144, 12, 94, 246, 171, 13, 112, 247, 162, 12, 168, 246, 33, 13, 63, 246, 29, 15, 226, 247, 188, 14, 190, 248, 75, 15, 238, 247, 86, 17, 19, 247, 118, 11, 10, 247, 232, 254, 238, 247, 30, 249, 56, 248, 124, 250, 6, 247, 1, 250, 161, 246, 3, 249, 81, 247, 117, 250, 60, 247, 202, 250, 212, 247, 60, 250, 15, 249, 140, 250, 34, 248, 221, 249, 105, 247, 218, 249, 205, 248, 113, 251, 138, 248, 90, 250, 41, 248, 230, 248]; +#[rustfmt::skip] static PCM: &[i16] = &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, -2, 0, -2, 0, -2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 2, 0, 2, 0, 2, 0, 2, 0, 2, 0, 1, 0, 1, 0, 0, -2, 0, -2, 0, -2, 0, -2, -2, -2, -3, -3, -3, -3, -4, -2, -5, -2, -5, -2, -4, 0, -4, 0, -4, 0, -4, 1, -4, 1, -4, 2, -4, 2, -4, 2, -4, 2, -4, 2, -3, 1, -4, 0, -4, 0, -5, 0, -5, 0, -5, 0, -4, 2, -4, 3, -4, 4, -3, 5, -2, 5, -3, 6, -3, 6, -3, 5, -3, 5, -2, 4, -2, 3, -5, 0, -6, 0, -3, -2, -4, -4, -9, -5, -9, -4, -4, -2, -4, -2, -4, 0, -2, 1, 1, 1, 4, 2, 8, 2, 12, 1, 13, 0, 12, 0, 11, 0, 8, -2, 7, 0, 7, -3, 11, -8, 15, -9, 17, -6, 17, -5, 13, -3, 7, 0, 3, 0, -2, 0, -4, 0, -4, -2, -6, 0, -14, -2, -17, -4, -8, 0, -7, 5, -17, 7, -18, 10, -7, 18, -2, 25, -3, 27, 0, 31, 4, 34, 4, 34, 8, 36, 8, 37, 2, 36, 4, 34, 8, 28, 3, 15, 0, 11, 0, 12, -5, 8, -4, 10, 0, 23, -4, 31, -8, 30, -2, 30, 0, 26, -6, 22, -6, 20, -12, 15, -19, 10, -10, 13, -14, 6, -43, -13, -43, -16, -9, -12, -10, -29, -42, -40, -37, -28, -5, -21, 1, -24, -8, -20, 4, -18, 26, -24, 44, -26, 66, -30, 86, -37, 88, -41, 72, -46, 50, -31, 28, 23, 14, 64, 16, 51, 26, 32, 34, 39, 42, 48, 35, 58, 0, 72, -36, 69, -59, 58, -98, 54, -124, 36, -103, 12, -110, 5, -173, -19, -146, -59, -4, -42, 51, 1, -23, -6, -30, -6, 45, 46, 47, 70, 6, 55, 19, 60, 38, 62, 42, 47, 61, 46, 40, 42, -19, 22, -34, 6, -35, -50, -61, -141, -37, -171, 17, -163, 26, -180, 46, -154, 80, -63, 48, -4, 18, 20, 50, 47, 58, 53, 44, 61, 57, 85, 37, 80, 0, 86, -8, 106, -95, 49, -213, -8, -131, 47, 49, 63, 40, -39, -69, -74, -37, -20, 63, -12, 58, -14, -12, 25, -31, 41, 11, 45, 76, 47, 167, 5, 261, -37, 277, -83, 183, -172, 35, -122, -79, 138, -70, 266, 69, 124, 228, 0, 391, -29, 594, -84, 702, -78, 627, -8, 551, -13, 509, 13, 372, 120, 352, 125, 622, 127, 691, 223, 362, 126, 386, -33, 915, 198, 958, 457, 456, 298, 500, 233, 1027, 469, 1096, 426, 918, 160, 1067, 141, 1220, 189, 1245, 164, 1375, 297, 1378, 503, 1299, 702, 1550, 929, 1799, 855, 1752, 547, 1830, 602, 1928, 832, 1736, 796, 1735, 933, 1961, 1385, 1935, 1562, 2105, 1485, 2716, 1449, 2948, 1305, 2768, 1205, 2716, 1346, 2531, 1450, 2470, 1653, 3117, 2111, 3370, 2176, 2696, 1947, 2925, 2305, 3846, 2658, 2425, 2184, -877, 1981, -2261, 2623, -1645, 2908, -1876, 2732, -2704, 2953, -2484, 3116, -2120, 2954, -2442, 3216, -2466, 3499, -2192, 3234, -2392, 3361, -2497, 3869, -2078, 3772, -1858, 3915, -2066, 4438, -2285, 2934, -2294, -280, -2066, -1762, -1992, -1412, -2298, -1535, -2399, -1789, -2223, -1419, -2244, -1334, -2092, -1476, -1777, -1396, -2014, -1571, -2199, -1574, -1843, -1167, -1910, -1446, -2007, -1818]; fn main() { diff --git a/tests/fail/erroneous_const2.rs b/tests/fail/erroneous_const2.rs index cdec2ec4f0953..dc68cd64d738f 100644 --- a/tests/fail/erroneous_const2.rs +++ b/tests/fail/erroneous_const2.rs @@ -4,6 +4,7 @@ const FOO: u32 = [X - Y, Y - X][(X < Y) as usize]; //~^ERROR any use of this value //~|WARN previously accepted +#[rustfmt::skip] // rustfmt bug: https://github.com/rust-lang/rustfmt/issues/5391 fn main() { println!("{}", FOO); //~ERROR post-monomorphization error //~|ERROR evaluation of constant value failed diff --git a/tests/fail/stacked_borrows/illegal_read1.rs b/tests/fail/stacked_borrows/illegal_read1.rs index d942d2b27b999..b5734964060ef 100644 --- a/tests/fail/stacked_borrows/illegal_read1.rs +++ b/tests/fail/stacked_borrows/illegal_read1.rs @@ -1,6 +1,7 @@ // A callee may not read the destination of our `&mut` without // us noticing. +#[rustfmt::skip] // rustfmt bug: https://github.com/rust-lang/rustfmt/issues/5391 fn main() { let mut x = 15; let xraw = &mut x as *mut _; diff --git a/tests/fail/stacked_borrows/illegal_read2.rs b/tests/fail/stacked_borrows/illegal_read2.rs index c50c88d48f8c9..ed6972c1deb93 100644 --- a/tests/fail/stacked_borrows/illegal_read2.rs +++ b/tests/fail/stacked_borrows/illegal_read2.rs @@ -1,6 +1,7 @@ // A callee may not read the destination of our `&mut` without // us noticing. +#[rustfmt::skip] // rustfmt bug: https://github.com/rust-lang/rustfmt/issues/5391 fn main() { let mut x = 15; let xraw = &mut x as *mut _; diff --git a/tests/fail/stacked_borrows/illegal_read5.rs b/tests/fail/stacked_borrows/illegal_read5.rs index 58f506251de2c..71af84e5b5f52 100644 --- a/tests/fail/stacked_borrows/illegal_read5.rs +++ b/tests/fail/stacked_borrows/illegal_read5.rs @@ -5,6 +5,7 @@ use std::cell::RefCell; use std::{mem, ptr}; +#[rustfmt::skip] // rustfmt bug: https://github.com/rust-lang/rustfmt/issues/5391 fn main() { let rc = RefCell::new(0); let mut refmut = rc.borrow_mut(); diff --git a/tests/fail/validity/transmute_through_ptr.rs b/tests/fail/validity/transmute_through_ptr.rs index cd354eac4aef9..b1984429d2de8 100644 --- a/tests/fail/validity/transmute_through_ptr.rs +++ b/tests/fail/validity/transmute_through_ptr.rs @@ -7,6 +7,7 @@ fn evil(x: &mut Bool) { unsafe { *x = 44; } // out-of-bounds enum tag } +#[rustfmt::skip] // rustfmt bug: https://github.com/rust-lang/rustfmt/issues/5391 fn main() { let mut x = Bool::True; evil(&mut x); diff --git a/tests/pass/enums.rs b/tests/pass/enums.rs index 39bf567076c47..d399beb91b2f5 100644 --- a/tests/pass/enums.rs +++ b/tests/pass/enums.rs @@ -64,6 +64,7 @@ fn more_discriminant_overflow() { // from the `bool` field of `V1`), overflowing for variants with large enough // indices (`V3` and `V4`), causing them to be interpreted as other variants. #[allow(dead_code)] + #[rustfmt::skip] // rustfmt prefers every variant on its own line pub enum E2 { V1 { f: bool }, From 66e8751afce516a2ee9fb3324e755f7ad0c42629 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sun, 19 Jun 2022 20:33:59 -0700 Subject: [PATCH 3266/3747] Format tests and benches with rustfmt (1-50 of 300) --- bench-cargo-miri/mse/src/main.rs | 1 - benches/helpers/repeat_manual.rs | 4 +++- test-cargo-miri/cdylib/src/lib.rs | 2 +- test-cargo-miri/issue-1567/src/lib.rs | 2 +- test-cargo-miri/issue-1705/src/lib.rs | 4 ++-- test-cargo-miri/issue-rust-86261/src/lib.rs | 2 +- test-cargo-miri/src/main.rs | 4 ++-- test-cargo-miri/tests/test.rs | 6 +----- tests/fail/abort-terminator.rs | 4 +++- tests/fail/alloc/global_system_mixup.rs | 6 ++++-- tests/fail/concurrency/too_few_args.rs | 3 ++- tests/fail/concurrency/too_many_args.rs | 3 ++- tests/fail/concurrency/unwind_top_of_stack.rs | 6 ++++-- .../fail/dangling_pointers/storage_dead_dangling.rs | 4 +++- tests/fail/data_race/alloc_read_race.rs | 6 +++--- tests/fail/data_race/alloc_write_race.rs | 7 ++++--- tests/fail/data_race/atomic_read_na_write_race1.rs | 4 ++-- tests/fail/data_race/atomic_read_na_write_race2.rs | 2 +- tests/fail/data_race/atomic_write_na_read_race1.rs | 2 +- tests/fail/data_race/atomic_write_na_read_race2.rs | 8 +++----- tests/fail/data_race/atomic_write_na_write_race1.rs | 4 ++-- tests/fail/data_race/atomic_write_na_write_race2.rs | 2 +- tests/fail/data_race/dangling_thread_async_race.rs | 6 ++---- tests/fail/data_race/dangling_thread_race.rs | 7 ++----- tests/fail/data_race/dealloc_read_race2.rs | 6 +++++- tests/fail/data_race/dealloc_read_race_stack.rs | 5 ++--- tests/fail/data_race/dealloc_write_race2.rs | 6 +++++- tests/fail/data_race/dealloc_write_race_stack.rs | 5 ++--- tests/fail/data_race/fence_after_load.rs | 4 ++-- tests/fail/data_race/read_write_race.rs | 4 +--- tests/fail/data_race/read_write_race_stack.rs | 4 ++-- tests/fail/data_race/relax_acquire_race.rs | 2 +- tests/fail/data_race/release_seq_race.rs | 2 +- tests/fail/data_race/release_seq_race_same_thread.rs | 2 +- tests/fail/data_race/rmw_race.rs | 2 +- tests/fail/data_race/write_write_race_stack.rs | 4 ++-- tests/fail/environ-gets-deallocated.rs | 12 ++++++------ .../fail/function_pointers/cast_box_int_to_fn_ptr.rs | 4 +--- tests/fail/function_pointers/cast_fn_ptr1.rs | 4 +--- tests/fail/function_pointers/cast_fn_ptr2.rs | 6 ++---- tests/fail/function_pointers/cast_fn_ptr3.rs | 7 ++----- tests/fail/function_pointers/cast_fn_ptr4.rs | 6 ++---- tests/fail/function_pointers/cast_fn_ptr5.rs | 8 ++++---- tests/fail/function_pointers/cast_int_to_fn_ptr.rs | 4 +--- tests/fail/function_pointers/fn_ptr_offset.rs | 6 +++--- tests/fail/intrinsics/simd-div-by-zero.rs | 12 +++++++----- tests/fail/intrinsics/simd-div-overflow.rs | 12 +++++++----- tests/fail/intrinsics/simd-float-to-int.rs | 8 +++++--- tests/fail/intrinsics/simd-gather.rs | 12 +++++++----- tests/fail/intrinsics/simd-reduce-invalid-bool.rs | 10 ++++++---- 50 files changed, 129 insertions(+), 127 deletions(-) diff --git a/bench-cargo-miri/mse/src/main.rs b/bench-cargo-miri/mse/src/main.rs index bb5fb80e48c18..c09dc2484d380 100644 --- a/bench-cargo-miri/mse/src/main.rs +++ b/bench-cargo-miri/mse/src/main.rs @@ -30,4 +30,3 @@ fn mse(samples: usize, frame_buf: &[i16], buf_ref: &[u8]) -> f64 { } mse / max_samples as f64 } - diff --git a/benches/helpers/repeat_manual.rs b/benches/helpers/repeat_manual.rs index 6ef6f724efcee..bd5d6b1e1264b 100644 --- a/benches/helpers/repeat_manual.rs +++ b/benches/helpers/repeat_manual.rs @@ -1,7 +1,9 @@ fn main() { let mut data: [u8; 1024] = unsafe { std::mem::uninitialized() }; for i in 0..data.len() { - unsafe { std::ptr::write(&mut data[i], 0); } + unsafe { + std::ptr::write(&mut data[i], 0); + } } assert_eq!(data.len(), 1024); } diff --git a/test-cargo-miri/cdylib/src/lib.rs b/test-cargo-miri/cdylib/src/lib.rs index dd89048284dee..e47e588251e4e 100644 --- a/test-cargo-miri/cdylib/src/lib.rs +++ b/test-cargo-miri/cdylib/src/lib.rs @@ -2,5 +2,5 @@ use byteorder::{BigEndian, ByteOrder}; #[no_mangle] extern "C" fn use_the_dependency() { - let _n = ::read_u64(&[1,2,3,4,5,6,7,8]); + let _n = ::read_u64(&[1, 2, 3, 4, 5, 6, 7, 8]); } diff --git a/test-cargo-miri/issue-1567/src/lib.rs b/test-cargo-miri/issue-1567/src/lib.rs index 568617c3ba3ca..5479216832388 100644 --- a/test-cargo-miri/issue-1567/src/lib.rs +++ b/test-cargo-miri/issue-1567/src/lib.rs @@ -1,5 +1,5 @@ use byteorder::{BigEndian, ByteOrder}; pub fn use_the_dependency() { - let _n = ::read_u32(&[1,2,3,4]); + let _n = ::read_u32(&[1, 2, 3, 4]); } diff --git a/test-cargo-miri/issue-1705/src/lib.rs b/test-cargo-miri/issue-1705/src/lib.rs index ef24d3f1a06da..64633490f84b9 100644 --- a/test-cargo-miri/issue-1705/src/lib.rs +++ b/test-cargo-miri/issue-1705/src/lib.rs @@ -1,5 +1,5 @@ -use byteorder::{LittleEndian, ByteOrder}; +use byteorder::{ByteOrder, LittleEndian}; pub fn use_the_dependency() { - let _n = ::read_u32(&[1,2,3,4]); + let _n = ::read_u32(&[1, 2, 3, 4]); } diff --git a/test-cargo-miri/issue-rust-86261/src/lib.rs b/test-cargo-miri/issue-rust-86261/src/lib.rs index db725fdb64ed9..1947c38b77455 100644 --- a/test-cargo-miri/issue-rust-86261/src/lib.rs +++ b/test-cargo-miri/issue-rust-86261/src/lib.rs @@ -3,7 +3,7 @@ // Regression test for https://github.com/rust-lang/rust/issues/86261: // `#[no_mangle]` on a `use` item. #[no_mangle] -use std::{thread,panic, io, boxed, any, string}; +use std::{any, boxed, io, panic, string, thread}; // `#[no_mangle]` on a struct has a similar problem. #[no_mangle] diff --git a/test-cargo-miri/src/main.rs b/test-cargo-miri/src/main.rs index cb1512d050209..5807d0765fb31 100644 --- a/test-cargo-miri/src/main.rs +++ b/test-cargo-miri/src/main.rs @@ -8,7 +8,7 @@ fn main() { assert_eq!(env!("MIRITESTVAR"), "testval"); // Exercise external crate, printing to stdout. - let buf = &[1,2,3,4]; + let buf = &[1, 2, 3, 4]; let n = ::read_u32(buf); assert_eq!(n, 0x01020304); println!("{:#010x}", n); @@ -32,7 +32,7 @@ fn main() { #[cfg(unix)] for line in io::stdin().lock().lines() { let num: i32 = line.unwrap().parse().unwrap(); - println!("{}", 2*num); + println!("{}", 2 * num); } // On non-Unix, reading from stdin is not supported. So we hard-code the right answer. #[cfg(not(unix))] diff --git a/test-cargo-miri/tests/test.rs b/test-cargo-miri/tests/test.rs index 545c79db2760b..8a938ef3c25f6 100644 --- a/test-cargo-miri/tests/test.rs +++ b/test-cargo-miri/tests/test.rs @@ -67,9 +67,5 @@ fn page_size() { let page_size = page_size::get(); // In particular, this checks that it is not 0. - assert!( - page_size.is_power_of_two(), - "page size not a power of two: {}", - page_size - ); + assert!(page_size.is_power_of_two(), "page size not a power of two: {}", page_size); } diff --git a/tests/fail/abort-terminator.rs b/tests/fail/abort-terminator.rs index 8e6e2a766007e..20859047c620e 100644 --- a/tests/fail/abort-terminator.rs +++ b/tests/fail/abort-terminator.rs @@ -1,7 +1,9 @@ // error-pattern: the program aborted #![feature(c_unwind)] -extern "C" fn panic_abort() { panic!() } +extern "C" fn panic_abort() { + panic!() +} fn main() { panic_abort(); diff --git a/tests/fail/alloc/global_system_mixup.rs b/tests/fail/alloc/global_system_mixup.rs index bb87b132f3227..735c52500af67 100644 --- a/tests/fail/alloc/global_system_mixup.rs +++ b/tests/fail/alloc/global_system_mixup.rs @@ -8,10 +8,12 @@ #![feature(allocator_api, slice_ptr_get)] -use std::alloc::{Allocator, Global, System, Layout}; +use std::alloc::{Allocator, Global, Layout, System}; fn main() { let l = Layout::from_size_align(1, 1).unwrap(); let ptr = Global.allocate(l).unwrap().as_non_null_ptr(); - unsafe { System.deallocate(ptr, l); } + unsafe { + System.deallocate(ptr, l); + } } diff --git a/tests/fail/concurrency/too_few_args.rs b/tests/fail/concurrency/too_few_args.rs index e2dfa33af8989..35412353ace4a 100644 --- a/tests/fail/concurrency/too_few_args.rs +++ b/tests/fail/concurrency/too_few_args.rs @@ -19,7 +19,8 @@ fn main() { let attr: libc::pthread_attr_t = mem::zeroed(); // assert_eq!(libc::pthread_attr_init(&mut attr), 0); FIXME: this function is not yet implemented. let thread_start: extern "C" fn() -> *mut libc::c_void = thread_start; - let thread_start: extern "C" fn(*mut libc::c_void) -> *mut libc::c_void = mem::transmute(thread_start); + let thread_start: extern "C" fn(*mut libc::c_void) -> *mut libc::c_void = + mem::transmute(thread_start); assert_eq!(libc::pthread_create(&mut native, &attr, thread_start, ptr::null_mut()), 0); assert_eq!(libc::pthread_join(native, ptr::null_mut()), 0); } diff --git a/tests/fail/concurrency/too_many_args.rs b/tests/fail/concurrency/too_many_args.rs index 0ef12b07073fb..b6156091b0aaf 100644 --- a/tests/fail/concurrency/too_many_args.rs +++ b/tests/fail/concurrency/too_many_args.rs @@ -19,7 +19,8 @@ fn main() { let attr: libc::pthread_attr_t = mem::zeroed(); // assert_eq!(libc::pthread_attr_init(&mut attr), 0); FIXME: this function is not yet implemented. let thread_start: extern "C" fn(*mut libc::c_void, i32) -> *mut libc::c_void = thread_start; - let thread_start: extern "C" fn(*mut libc::c_void) -> *mut libc::c_void = mem::transmute(thread_start); + let thread_start: extern "C" fn(*mut libc::c_void) -> *mut libc::c_void = + mem::transmute(thread_start); assert_eq!(libc::pthread_create(&mut native, &attr, thread_start, ptr::null_mut()), 0); assert_eq!(libc::pthread_join(native, ptr::null_mut()), 0); } diff --git a/tests/fail/concurrency/unwind_top_of_stack.rs b/tests/fail/concurrency/unwind_top_of_stack.rs index 138a43d9d7310..e1c17d07b286a 100644 --- a/tests/fail/concurrency/unwind_top_of_stack.rs +++ b/tests/fail/concurrency/unwind_top_of_stack.rs @@ -20,8 +20,10 @@ fn main() { let attr: libc::pthread_attr_t = mem::zeroed(); // assert_eq!(libc::pthread_attr_init(&mut attr), 0); FIXME: this function is not yet implemented. // Cast to avoid inserting abort-on-unwind. - let thread_start: extern "C-unwind" fn(*mut libc::c_void) -> *mut libc::c_void = thread_start; - let thread_start: extern "C" fn(*mut libc::c_void) -> *mut libc::c_void = mem::transmute(thread_start); + let thread_start: extern "C-unwind" fn(*mut libc::c_void) -> *mut libc::c_void = + thread_start; + let thread_start: extern "C" fn(*mut libc::c_void) -> *mut libc::c_void = + mem::transmute(thread_start); assert_eq!(libc::pthread_create(&mut native, &attr, thread_start, ptr::null_mut()), 0); assert_eq!(libc::pthread_join(native, ptr::null_mut()), 0); } diff --git a/tests/fail/dangling_pointers/storage_dead_dangling.rs b/tests/fail/dangling_pointers/storage_dead_dangling.rs index 4d91498eac168..c87db4b0225a2 100644 --- a/tests/fail/dangling_pointers/storage_dead_dangling.rs +++ b/tests/fail/dangling_pointers/storage_dead_dangling.rs @@ -4,7 +4,9 @@ static mut LEAK: usize = 0; fn fill(v: &mut i32) { - unsafe { LEAK = v as *mut _ as usize; } + unsafe { + LEAK = v as *mut _ as usize; + } } fn evil() { diff --git a/tests/fail/data_race/alloc_read_race.rs b/tests/fail/data_race/alloc_read_race.rs index 4adb7071f294b..12c1b6ec876a1 100644 --- a/tests/fail/data_race/alloc_read_race.rs +++ b/tests/fail/data_race/alloc_read_race.rs @@ -2,10 +2,10 @@ // compile-flags: -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 #![feature(new_uninit)] -use std::thread::spawn; -use std::ptr::null_mut; -use std::sync::atomic::{Ordering, AtomicPtr}; use std::mem::MaybeUninit; +use std::ptr::null_mut; +use std::sync::atomic::{AtomicPtr, Ordering}; +use std::thread::spawn; #[derive(Copy, Clone)] struct EvilSend(pub T); diff --git a/tests/fail/data_race/alloc_write_race.rs b/tests/fail/data_race/alloc_write_race.rs index e4a1192f95b39..c050d24bee10d 100644 --- a/tests/fail/data_race/alloc_write_race.rs +++ b/tests/fail/data_race/alloc_write_race.rs @@ -2,9 +2,9 @@ // compile-flags: -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 #![feature(new_uninit)] -use std::thread::spawn; use std::ptr::null_mut; -use std::sync::atomic::{Ordering, AtomicPtr}; +use std::sync::atomic::{AtomicPtr, Ordering}; +use std::thread::spawn; #[derive(Copy, Clone)] struct EvilSend(pub T); @@ -30,7 +30,8 @@ pub fn main() { // Uses relaxed semantics to not generate // a release sequence. let pointer = &*ptr.0; - pointer.store(Box::into_raw(Box::::new_uninit()) as *mut usize, Ordering::Relaxed); + pointer + .store(Box::into_raw(Box::::new_uninit()) as *mut usize, Ordering::Relaxed); }); let j2 = spawn(move || { diff --git a/tests/fail/data_race/atomic_read_na_write_race1.rs b/tests/fail/data_race/atomic_read_na_write_race1.rs index 44860ee628003..5131e33fef863 100644 --- a/tests/fail/data_race/atomic_read_na_write_race1.rs +++ b/tests/fail/data_race/atomic_read_na_write_race1.rs @@ -1,9 +1,9 @@ // ignore-windows: Concurrency on Windows is not supported yet. #![feature(core_intrinsics)] -use std::thread::spawn; -use std::sync::atomic::AtomicUsize; use std::intrinsics::atomic_load; +use std::sync::atomic::AtomicUsize; +use std::thread::spawn; #[derive(Copy, Clone)] struct EvilSend(pub T); diff --git a/tests/fail/data_race/atomic_read_na_write_race2.rs b/tests/fail/data_race/atomic_read_na_write_race2.rs index 6d28e18886cd8..1c0146367ad55 100644 --- a/tests/fail/data_race/atomic_read_na_write_race2.rs +++ b/tests/fail/data_race/atomic_read_na_write_race2.rs @@ -1,8 +1,8 @@ // ignore-windows: Concurrency on Windows is not supported yet. -use std::thread::spawn; use std::sync::atomic::AtomicUsize; use std::sync::atomic::Ordering; +use std::thread::spawn; #[derive(Copy, Clone)] struct EvilSend(pub T); diff --git a/tests/fail/data_race/atomic_write_na_read_race1.rs b/tests/fail/data_race/atomic_write_na_read_race1.rs index 0b753f6710a5f..a63aafb0453c9 100644 --- a/tests/fail/data_race/atomic_write_na_read_race1.rs +++ b/tests/fail/data_race/atomic_write_na_read_race1.rs @@ -1,8 +1,8 @@ // ignore-windows: Concurrency on Windows is not supported yet. -use std::thread::spawn; use std::sync::atomic::AtomicUsize; use std::sync::atomic::Ordering; +use std::thread::spawn; #[derive(Copy, Clone)] struct EvilSend(pub T); diff --git a/tests/fail/data_race/atomic_write_na_read_race2.rs b/tests/fail/data_race/atomic_write_na_read_race2.rs index a9f5fb2fe5bc5..359970dfff8f3 100644 --- a/tests/fail/data_race/atomic_write_na_read_race2.rs +++ b/tests/fail/data_race/atomic_write_na_read_race2.rs @@ -1,9 +1,9 @@ // ignore-windows: Concurrency on Windows is not supported yet. #![feature(core_intrinsics)] -use std::thread::spawn; -use std::sync::atomic::AtomicUsize; use std::intrinsics::atomic_store; +use std::sync::atomic::AtomicUsize; +use std::thread::spawn; #[derive(Copy, Clone)] struct EvilSend(pub T); @@ -16,9 +16,7 @@ pub fn main() { let b = &mut a as *mut AtomicUsize; let c = EvilSend(b); unsafe { - let j1 = spawn(move || { - *(c.0 as *mut usize) - }); + let j1 = spawn(move || *(c.0 as *mut usize)); let j2 = spawn(move || { //Equivalent to: (&*c.0).store(32, Ordering::SeqCst) diff --git a/tests/fail/data_race/atomic_write_na_write_race1.rs b/tests/fail/data_race/atomic_write_na_write_race1.rs index d5a828fa6e41c..8268924e3c1ac 100644 --- a/tests/fail/data_race/atomic_write_na_write_race1.rs +++ b/tests/fail/data_race/atomic_write_na_write_race1.rs @@ -1,9 +1,9 @@ // ignore-windows: Concurrency on Windows is not supported yet. #![feature(core_intrinsics)] -use std::thread::spawn; -use std::sync::atomic::AtomicUsize; use std::intrinsics::atomic_store; +use std::sync::atomic::AtomicUsize; +use std::thread::spawn; #[derive(Copy, Clone)] struct EvilSend(pub T); diff --git a/tests/fail/data_race/atomic_write_na_write_race2.rs b/tests/fail/data_race/atomic_write_na_write_race2.rs index 9812dcd79920a..440c72a059d8c 100644 --- a/tests/fail/data_race/atomic_write_na_write_race2.rs +++ b/tests/fail/data_race/atomic_write_na_write_race2.rs @@ -1,8 +1,8 @@ // ignore-windows: Concurrency on Windows is not supported yet. -use std::thread::spawn; use std::sync::atomic::AtomicUsize; use std::sync::atomic::Ordering; +use std::thread::spawn; #[derive(Copy, Clone)] struct EvilSend(pub T); diff --git a/tests/fail/data_race/dangling_thread_async_race.rs b/tests/fail/data_race/dangling_thread_async_race.rs index 6aa5a469be3ba..2656f4b7af148 100644 --- a/tests/fail/data_race/dangling_thread_async_race.rs +++ b/tests/fail/data_race/dangling_thread_async_race.rs @@ -1,10 +1,9 @@ // ignore-windows: Concurrency on Windows is not supported yet. // compile-flags: -Zmiri-disable-isolation -use std::thread::{spawn, sleep}; -use std::time::Duration; use std::mem; - +use std::thread::{sleep, spawn}; +use std::time::Duration; #[derive(Copy, Clone)] struct EvilSend(pub T); @@ -12,7 +11,6 @@ struct EvilSend(pub T); unsafe impl Send for EvilSend {} unsafe impl Sync for EvilSend {} - fn main() { let mut a = 0u32; let b = &mut a as *mut u32; diff --git a/tests/fail/data_race/dangling_thread_race.rs b/tests/fail/data_race/dangling_thread_race.rs index 755ba8efdae95..f1174d8ff6ee1 100644 --- a/tests/fail/data_race/dangling_thread_race.rs +++ b/tests/fail/data_race/dangling_thread_race.rs @@ -1,10 +1,9 @@ // ignore-windows: Concurrency on Windows is not supported yet. // compile-flags: -Zmiri-disable-isolation -use std::thread::{spawn, sleep}; -use std::time::Duration; use std::mem; - +use std::thread::{sleep, spawn}; +use std::time::Duration; #[derive(Copy, Clone)] struct EvilSend(pub T); @@ -12,7 +11,6 @@ struct EvilSend(pub T); unsafe impl Send for EvilSend {} unsafe impl Sync for EvilSend {} - fn main() { let mut a = 0u32; let b = &mut a as *mut u32; @@ -34,7 +32,6 @@ fn main() { // remains enabled nevertheless. spawn(|| ()).join().unwrap(); - unsafe { *c.0 = 64; //~ ERROR Data race detected between Write on Thread(id = 0, name = "main") and Write on Thread(id = 1) } diff --git a/tests/fail/data_race/dealloc_read_race2.rs b/tests/fail/data_race/dealloc_read_race2.rs index 9f9dbfc77ed50..984268dca149d 100644 --- a/tests/fail/data_race/dealloc_read_race2.rs +++ b/tests/fail/data_race/dealloc_read_race2.rs @@ -19,7 +19,11 @@ pub fn main() { unsafe { let j1 = spawn(move || { - __rust_dealloc(ptr.0 as *mut _, std::mem::size_of::(), std::mem::align_of::()) + __rust_dealloc( + ptr.0 as *mut _, + std::mem::size_of::(), + std::mem::align_of::(), + ) }); let j2 = spawn(move || { diff --git a/tests/fail/data_race/dealloc_read_race_stack.rs b/tests/fail/data_race/dealloc_read_race_stack.rs index f458d1126efe7..cdb6c182307f8 100644 --- a/tests/fail/data_race/dealloc_read_race_stack.rs +++ b/tests/fail/data_race/dealloc_read_race_stack.rs @@ -1,9 +1,9 @@ // ignore-windows: Concurrency on Windows is not supported yet. // compile-flags: -Zmiri-disable-isolation -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 -use std::thread::{spawn, sleep}; use std::ptr::null_mut; -use std::sync::atomic::{Ordering, AtomicPtr}; +use std::sync::atomic::{AtomicPtr, Ordering}; +use std::thread::{sleep, spawn}; use std::time::Duration; #[derive(Copy, Clone)] @@ -36,7 +36,6 @@ pub fn main() { sleep(Duration::from_millis(200)); // Now `stack_var` gets deallocated. - } //~ ERROR Data race detected between Deallocate on Thread(id = 1) and Read on Thread(id = 2) }); diff --git a/tests/fail/data_race/dealloc_write_race2.rs b/tests/fail/data_race/dealloc_write_race2.rs index 20c05fa8f17bc..2f4b9a194c05e 100644 --- a/tests/fail/data_race/dealloc_write_race2.rs +++ b/tests/fail/data_race/dealloc_write_race2.rs @@ -18,7 +18,11 @@ pub fn main() { unsafe { let j1 = spawn(move || { - __rust_dealloc(ptr.0 as *mut _, std::mem::size_of::(), std::mem::align_of::()); + __rust_dealloc( + ptr.0 as *mut _, + std::mem::size_of::(), + std::mem::align_of::(), + ); }); let j2 = spawn(move || { diff --git a/tests/fail/data_race/dealloc_write_race_stack.rs b/tests/fail/data_race/dealloc_write_race_stack.rs index d1fe8c3e9a160..a209a2cd7dbfb 100644 --- a/tests/fail/data_race/dealloc_write_race_stack.rs +++ b/tests/fail/data_race/dealloc_write_race_stack.rs @@ -1,9 +1,9 @@ // ignore-windows: Concurrency on Windows is not supported yet. // compile-flags: -Zmiri-disable-isolation -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 -use std::thread::{spawn, sleep}; use std::ptr::null_mut; -use std::sync::atomic::{Ordering, AtomicPtr}; +use std::sync::atomic::{AtomicPtr, Ordering}; +use std::thread::{sleep, spawn}; use std::time::Duration; #[derive(Copy, Clone)] @@ -36,7 +36,6 @@ pub fn main() { sleep(Duration::from_millis(200)); // Now `stack_var` gets deallocated. - } //~ ERROR Data race detected between Deallocate on Thread(id = 1) and Write on Thread(id = 2) }); diff --git a/tests/fail/data_race/fence_after_load.rs b/tests/fail/data_race/fence_after_load.rs index 20cc691f88e16..c209ef1812530 100644 --- a/tests/fail/data_race/fence_after_load.rs +++ b/tests/fail/data_race/fence_after_load.rs @@ -1,10 +1,10 @@ // We want to control preemption here. // compile-flags: -Zmiri-disable-isolation -Zmiri-preemption-rate=0 // ignore-windows: Concurrency on Windows is not supported yet. +use std::sync::atomic::{fence, AtomicUsize, Ordering}; use std::sync::Arc; -use std::sync::atomic::{AtomicUsize, Ordering, fence}; -use std::time::Duration; use std::thread; +use std::time::Duration; fn main() { static mut V: u32 = 0; diff --git a/tests/fail/data_race/read_write_race.rs b/tests/fail/data_race/read_write_race.rs index 0df66d66ad077..976ace6e4b6ff 100644 --- a/tests/fail/data_race/read_write_race.rs +++ b/tests/fail/data_race/read_write_race.rs @@ -13,9 +13,7 @@ pub fn main() { let b = &mut a as *mut u32; let c = EvilSend(b); unsafe { - let j1 = spawn(move || { - *c.0 - }); + let j1 = spawn(move || *c.0); let j2 = spawn(move || { *c.0 = 64; //~ ERROR Data race detected between Write on Thread(id = 2) and Read on Thread(id = 1) diff --git a/tests/fail/data_race/read_write_race_stack.rs b/tests/fail/data_race/read_write_race_stack.rs index f5c4768296b01..00c36176a9f1e 100644 --- a/tests/fail/data_race/read_write_race_stack.rs +++ b/tests/fail/data_race/read_write_race_stack.rs @@ -4,9 +4,9 @@ // Note: mir-opt-level set to 0 to prevent the read of stack_var in thread 1 // from being optimized away and preventing the detection of the data-race. -use std::thread::{spawn, sleep}; use std::ptr::null_mut; -use std::sync::atomic::{Ordering, AtomicPtr}; +use std::sync::atomic::{AtomicPtr, Ordering}; +use std::thread::{sleep, spawn}; use std::time::Duration; #[derive(Copy, Clone)] diff --git a/tests/fail/data_race/relax_acquire_race.rs b/tests/fail/data_race/relax_acquire_race.rs index 64c0f95fa4bae..3b350f5c89f2d 100644 --- a/tests/fail/data_race/relax_acquire_race.rs +++ b/tests/fail/data_race/relax_acquire_race.rs @@ -1,8 +1,8 @@ // ignore-windows: Concurrency on Windows is not supported yet. // compile-flags: -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 -use std::thread::spawn; use std::sync::atomic::{AtomicUsize, Ordering}; +use std::thread::spawn; #[derive(Copy, Clone)] struct EvilSend(pub T); diff --git a/tests/fail/data_race/release_seq_race.rs b/tests/fail/data_race/release_seq_race.rs index 964d1b4937b89..ec03888c76b18 100644 --- a/tests/fail/data_race/release_seq_race.rs +++ b/tests/fail/data_race/release_seq_race.rs @@ -1,8 +1,8 @@ // ignore-windows: Concurrency on Windows is not supported yet. // compile-flags: -Zmiri-disable-isolation -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 -use std::thread::{spawn, sleep}; use std::sync::atomic::{AtomicUsize, Ordering}; +use std::thread::{sleep, spawn}; use std::time::Duration; #[derive(Copy, Clone)] diff --git a/tests/fail/data_race/release_seq_race_same_thread.rs b/tests/fail/data_race/release_seq_race_same_thread.rs index 01d45a1b7ccf0..1876238289475 100644 --- a/tests/fail/data_race/release_seq_race_same_thread.rs +++ b/tests/fail/data_race/release_seq_race_same_thread.rs @@ -1,8 +1,8 @@ // ignore-windows: Concurrency on Windows is not supported yet. // compile-flags: -Zmiri-disable-isolation -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 -use std::thread::spawn; use std::sync::atomic::{AtomicUsize, Ordering}; +use std::thread::spawn; #[derive(Copy, Clone)] struct EvilSend(pub T); diff --git a/tests/fail/data_race/rmw_race.rs b/tests/fail/data_race/rmw_race.rs index fab6fabe5b6fb..51577b3b7b191 100644 --- a/tests/fail/data_race/rmw_race.rs +++ b/tests/fail/data_race/rmw_race.rs @@ -1,8 +1,8 @@ // ignore-windows: Concurrency on Windows is not supported yet. // compile-flags: -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 -use std::thread::spawn; use std::sync::atomic::{AtomicUsize, Ordering}; +use std::thread::spawn; #[derive(Copy, Clone)] struct EvilSend(pub T); diff --git a/tests/fail/data_race/write_write_race_stack.rs b/tests/fail/data_race/write_write_race_stack.rs index e6ae207d86100..49de5db43b720 100644 --- a/tests/fail/data_race/write_write_race_stack.rs +++ b/tests/fail/data_race/write_write_race_stack.rs @@ -1,9 +1,9 @@ // ignore-windows: Concurrency on Windows is not supported yet. // compile-flags: -Zmiri-disable-isolation -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 -use std::thread::{spawn, sleep}; use std::ptr::null_mut; -use std::sync::atomic::{Ordering, AtomicPtr}; +use std::sync::atomic::{AtomicPtr, Ordering}; +use std::thread::{sleep, spawn}; use std::time::Duration; #[derive(Copy, Clone)] diff --git a/tests/fail/environ-gets-deallocated.rs b/tests/fail/environ-gets-deallocated.rs index b5a4441d2f9bd..4df9be2bf24de 100644 --- a/tests/fail/environ-gets-deallocated.rs +++ b/tests/fail/environ-gets-deallocated.rs @@ -1,14 +1,14 @@ // ignore-windows: Windows does not have a global environ list that the program can access directly -#[cfg(target_os="linux")] +#[cfg(target_os = "linux")] fn get_environ() -> *const *const u8 { - extern "C" { - static mut environ: *const *const u8; - } - unsafe { environ } + extern "C" { + static mut environ: *const *const u8; + } + unsafe { environ } } -#[cfg(target_os="macos")] +#[cfg(target_os = "macos")] fn get_environ() -> *const *const u8 { extern "C" { fn _NSGetEnviron() -> *mut *const *const u8; diff --git a/tests/fail/function_pointers/cast_box_int_to_fn_ptr.rs b/tests/fail/function_pointers/cast_box_int_to_fn_ptr.rs index 9eea9d92dcd76..f7640cadcbcf1 100644 --- a/tests/fail/function_pointers/cast_box_int_to_fn_ptr.rs +++ b/tests/fail/function_pointers/cast_box_int_to_fn_ptr.rs @@ -3,9 +3,7 @@ fn main() { let b = Box::new(42); - let g = unsafe { - std::mem::transmute::<&Box, &fn(i32)>(&b) - }; + let g = unsafe { std::mem::transmute::<&Box, &fn(i32)>(&b) }; (*g)(42) //~ ERROR it does not point to a function } diff --git a/tests/fail/function_pointers/cast_fn_ptr1.rs b/tests/fail/function_pointers/cast_fn_ptr1.rs index 3702ec8c94c43..e4463210dda9b 100644 --- a/tests/fail/function_pointers/cast_fn_ptr1.rs +++ b/tests/fail/function_pointers/cast_fn_ptr1.rs @@ -1,9 +1,7 @@ fn main() { fn f() {} - let g = unsafe { - std::mem::transmute::(f) - }; + let g = unsafe { std::mem::transmute::(f) }; g(42) //~ ERROR calling a function with more arguments than it expected } diff --git a/tests/fail/function_pointers/cast_fn_ptr2.rs b/tests/fail/function_pointers/cast_fn_ptr2.rs index 39f0867489adc..5d3222548a7d4 100644 --- a/tests/fail/function_pointers/cast_fn_ptr2.rs +++ b/tests/fail/function_pointers/cast_fn_ptr2.rs @@ -1,9 +1,7 @@ fn main() { - fn f(_ : (i32,i32)) {} + fn f(_: (i32, i32)) {} - let g = unsafe { - std::mem::transmute::(f) - }; + let g = unsafe { std::mem::transmute::(f) }; g(42) //~ ERROR calling a function with argument of type (i32, i32) passing data of type i32 } diff --git a/tests/fail/function_pointers/cast_fn_ptr3.rs b/tests/fail/function_pointers/cast_fn_ptr3.rs index 3523db24fa320..943175c347026 100644 --- a/tests/fail/function_pointers/cast_fn_ptr3.rs +++ b/tests/fail/function_pointers/cast_fn_ptr3.rs @@ -1,10 +1,7 @@ fn main() { - fn f(_ : (i32,i32)) {} + fn f(_: (i32, i32)) {} - let g = unsafe { - std::mem::transmute::(f) - }; + let g = unsafe { std::mem::transmute::(f) }; g() //~ ERROR calling a function with fewer arguments than it requires } - diff --git a/tests/fail/function_pointers/cast_fn_ptr4.rs b/tests/fail/function_pointers/cast_fn_ptr4.rs index 22a36a71cef14..238b09b162d2d 100644 --- a/tests/fail/function_pointers/cast_fn_ptr4.rs +++ b/tests/fail/function_pointers/cast_fn_ptr4.rs @@ -1,9 +1,7 @@ fn main() { - fn f(_ : *const [i32]) {} + fn f(_: *const [i32]) {} - let g = unsafe { - std::mem::transmute::(f) - }; + let g = unsafe { std::mem::transmute::(f) }; g(&42 as *const i32) //~ ERROR calling a function with argument of type *const [i32] passing data of type *const i32 } diff --git a/tests/fail/function_pointers/cast_fn_ptr5.rs b/tests/fail/function_pointers/cast_fn_ptr5.rs index fb2b4403363ef..effbd6db18844 100644 --- a/tests/fail/function_pointers/cast_fn_ptr5.rs +++ b/tests/fail/function_pointers/cast_fn_ptr5.rs @@ -1,9 +1,9 @@ fn main() { - fn f() -> u32 { 42 } + fn f() -> u32 { + 42 + } - let g = unsafe { - std::mem::transmute:: u32, fn()>(f) - }; + let g = unsafe { std::mem::transmute:: u32, fn()>(f) }; g() //~ ERROR calling a function with return type u32 passing return place of type () } diff --git a/tests/fail/function_pointers/cast_int_to_fn_ptr.rs b/tests/fail/function_pointers/cast_int_to_fn_ptr.rs index b206cb9ab3601..0adbda50bfe50 100644 --- a/tests/fail/function_pointers/cast_int_to_fn_ptr.rs +++ b/tests/fail/function_pointers/cast_int_to_fn_ptr.rs @@ -2,9 +2,7 @@ // compile-flags: -Zmiri-disable-validation fn main() { - let g = unsafe { - std::mem::transmute::(42) - }; + let g = unsafe { std::mem::transmute::(42) }; g(42) //~ ERROR not a valid pointer } diff --git a/tests/fail/function_pointers/fn_ptr_offset.rs b/tests/fail/function_pointers/fn_ptr_offset.rs index 7e509d53c2614..04c54c015922c 100644 --- a/tests/fail/function_pointers/fn_ptr_offset.rs +++ b/tests/fail/function_pointers/fn_ptr_offset.rs @@ -6,9 +6,9 @@ use std::mem; fn f() {} fn main() { - let x : fn() = f; - let y : *mut u8 = unsafe { mem::transmute(x) }; + let x: fn() = f; + let y: *mut u8 = unsafe { mem::transmute(x) }; let y = y.wrapping_offset(1); - let x : fn() = unsafe { mem::transmute(y) }; + let x: fn() = unsafe { mem::transmute(y) }; x(); //~ ERROR function pointer but it does not point to a function } diff --git a/tests/fail/intrinsics/simd-div-by-zero.rs b/tests/fail/intrinsics/simd-div-by-zero.rs index 4244e63d23e5d..6fdcb875acc13 100644 --- a/tests/fail/intrinsics/simd-div-by-zero.rs +++ b/tests/fail/intrinsics/simd-div-by-zero.rs @@ -8,8 +8,10 @@ extern "platform-intrinsic" { #[allow(non_camel_case_types)] struct i32x2(i32, i32); -fn main() { unsafe { - let x = i32x2(1, 1); - let y = i32x2(1, 0); - simd_div(x, y); //~ERROR Undefined Behavior: dividing by zero -} } +fn main() { + unsafe { + let x = i32x2(1, 1); + let y = i32x2(1, 0); + simd_div(x, y); //~ERROR Undefined Behavior: dividing by zero + } +} diff --git a/tests/fail/intrinsics/simd-div-overflow.rs b/tests/fail/intrinsics/simd-div-overflow.rs index 277b9e807baac..6d52a72e4c6e4 100644 --- a/tests/fail/intrinsics/simd-div-overflow.rs +++ b/tests/fail/intrinsics/simd-div-overflow.rs @@ -8,8 +8,10 @@ extern "platform-intrinsic" { #[allow(non_camel_case_types)] struct i32x2(i32, i32); -fn main() { unsafe { - let x = i32x2(1, i32::MIN); - let y = i32x2(1, -1); - simd_div(x, y); //~ERROR Undefined Behavior: overflow in signed division -} } +fn main() { + unsafe { + let x = i32x2(1, i32::MIN); + let y = i32x2(1, -1); + simd_div(x, y); //~ERROR Undefined Behavior: overflow in signed division + } +} diff --git a/tests/fail/intrinsics/simd-float-to-int.rs b/tests/fail/intrinsics/simd-float-to-int.rs index 88d5a7a466f02..bb9adf07c9e97 100644 --- a/tests/fail/intrinsics/simd-float-to-int.rs +++ b/tests/fail/intrinsics/simd-float-to-int.rs @@ -2,6 +2,8 @@ #![feature(portable_simd)] use std::simd::*; -fn main() { unsafe { - let _x : i32x2 = f32x2::from_array([f32::MAX, f32::MIN]).to_int_unchecked(); -} } +fn main() { + unsafe { + let _x: i32x2 = f32x2::from_array([f32::MAX, f32::MIN]).to_int_unchecked(); + } +} diff --git a/tests/fail/intrinsics/simd-gather.rs b/tests/fail/intrinsics/simd-gather.rs index ae6f048226ddb..ab9cb56ed0bdd 100644 --- a/tests/fail/intrinsics/simd-gather.rs +++ b/tests/fail/intrinsics/simd-gather.rs @@ -2,8 +2,10 @@ #![feature(portable_simd)] use std::simd::*; -fn main() { unsafe { - let vec: &[i8] = &[10, 11, 12, 13, 14, 15, 16, 17, 18]; - let idxs = Simd::from_array([9, 3, 0, 17]); - let _result = Simd::gather_select_unchecked(&vec, Mask::splat(true), idxs, Simd::splat(0)); -} } +fn main() { + unsafe { + let vec: &[i8] = &[10, 11, 12, 13, 14, 15, 16, 17, 18]; + let idxs = Simd::from_array([9, 3, 0, 17]); + let _result = Simd::gather_select_unchecked(&vec, Mask::splat(true), idxs, Simd::splat(0)); + } +} diff --git a/tests/fail/intrinsics/simd-reduce-invalid-bool.rs b/tests/fail/intrinsics/simd-reduce-invalid-bool.rs index 41dd7d74f4ec4..c697fd526f869 100644 --- a/tests/fail/intrinsics/simd-reduce-invalid-bool.rs +++ b/tests/fail/intrinsics/simd-reduce-invalid-bool.rs @@ -8,7 +8,9 @@ extern "platform-intrinsic" { #[allow(non_camel_case_types)] struct i32x2(i32, i32); -fn main() { unsafe { - let x = i32x2(0, 1); - simd_reduce_any(x); //~ERROR must be all-0-bits or all-1-bits -} } +fn main() { + unsafe { + let x = i32x2(0, 1); + simd_reduce_any(x); //~ERROR must be all-0-bits or all-1-bits + } +} From ee132c8d07b2de26e2d078c39980a93045759920 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Sun, 19 Jun 2022 20:43:35 -0700 Subject: [PATCH 3267/3747] Bless stderr files after rustfmt --- tests/fail/abort-terminator.stderr | 6 ++++-- tests/fail/alloc/global_system_mixup.stderr | 2 +- tests/fail/intrinsics/simd-div-by-zero.stderr | 4 ++-- tests/fail/intrinsics/simd-div-overflow.stderr | 4 ++-- tests/fail/intrinsics/simd-float-to-int.stderr | 4 ++-- tests/fail/intrinsics/simd-gather.stderr | 4 ++-- tests/fail/intrinsics/simd-reduce-invalid-bool.stderr | 4 ++-- 7 files changed, 15 insertions(+), 13 deletions(-) diff --git a/tests/fail/abort-terminator.stderr b/tests/fail/abort-terminator.stderr index 76501ca074fdd..b096775e61d31 100644 --- a/tests/fail/abort-terminator.stderr +++ b/tests/fail/abort-terminator.stderr @@ -3,8 +3,10 @@ note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace error: abnormal termination: the program aborted execution --> $DIR/abort-terminator.rs:LL:CC | -LL | extern "C" fn panic_abort() { panic!() } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the program aborted execution +LL | / extern "C" fn panic_abort() { +LL | | panic!() +LL | | } + | |_^ the program aborted execution | = note: inside `panic_abort` at $DIR/abort-terminator.rs:LL:CC note: inside `main` at $DIR/abort-terminator.rs:LL:CC diff --git a/tests/fail/alloc/global_system_mixup.stderr b/tests/fail/alloc/global_system_mixup.stderr index a3b9009e30354..f197bc7917850 100644 --- a/tests/fail/alloc/global_system_mixup.stderr +++ b/tests/fail/alloc/global_system_mixup.stderr @@ -12,7 +12,7 @@ LL | FREE(); note: inside `main` at $DIR/global_system_mixup.rs:LL:CC --> $DIR/global_system_mixup.rs:LL:CC | -LL | unsafe { System.deallocate(ptr, l); } +LL | System.deallocate(ptr, l); | ^ note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/simd-div-by-zero.stderr b/tests/fail/intrinsics/simd-div-by-zero.stderr index 77c12de8d81a0..37e1aafec2c01 100644 --- a/tests/fail/intrinsics/simd-div-by-zero.stderr +++ b/tests/fail/intrinsics/simd-div-by-zero.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: dividing by zero --> $DIR/simd-div-by-zero.rs:LL:CC | -LL | simd_div(x, y); - | ^^^^^^^^^^^^^^ dividing by zero +LL | simd_div(x, y); + | ^^^^^^^^^^^^^^ dividing by zero | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/intrinsics/simd-div-overflow.stderr b/tests/fail/intrinsics/simd-div-overflow.stderr index 53479a738b7b3..b5e8e378a0ab0 100644 --- a/tests/fail/intrinsics/simd-div-overflow.stderr +++ b/tests/fail/intrinsics/simd-div-overflow.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: overflow in signed division (dividing MIN by -1) --> $DIR/simd-div-overflow.rs:LL:CC | -LL | simd_div(x, y); - | ^^^^^^^^^^^^^^ overflow in signed division (dividing MIN by -1) +LL | simd_div(x, y); + | ^^^^^^^^^^^^^^ overflow in signed division (dividing MIN by -1) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/intrinsics/simd-float-to-int.stderr b/tests/fail/intrinsics/simd-float-to-int.stderr index 6e6a136c39af9..cfe272d90a1fc 100644 --- a/tests/fail/intrinsics/simd-float-to-int.stderr +++ b/tests/fail/intrinsics/simd-float-to-int.stderr @@ -11,8 +11,8 @@ LL | implement! { f32 } note: inside `main` at $DIR/simd-float-to-int.rs:LL:CC --> $DIR/simd-float-to-int.rs:LL:CC | -LL | let _x : i32x2 = f32x2::from_array([f32::MAX, f32::MIN]).to_int_unchecked(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | let _x: i32x2 = f32x2::from_array([f32::MAX, f32::MIN]).to_int_unchecked(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: this error originates in the macro `implement` (in Nightly builds, run with -Z macro-backtrace for more info) note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/simd-gather.stderr b/tests/fail/intrinsics/simd-gather.stderr index 8021077a92d37..0464e67f80c65 100644 --- a/tests/fail/intrinsics/simd-gather.stderr +++ b/tests/fail/intrinsics/simd-gather.stderr @@ -11,8 +11,8 @@ LL | unsafe { intrinsics::simd_gather(or, ptrs, enable.to_int()) } note: inside `main` at $DIR/simd-gather.rs:LL:CC --> $DIR/simd-gather.rs:LL:CC | -LL | let _result = Simd::gather_select_unchecked(&vec, Mask::splat(true), idxs, Simd::splat(0)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | let _result = Simd::gather_select_unchecked(&vec, Mask::splat(true), idxs, Simd::splat(0)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/simd-reduce-invalid-bool.stderr b/tests/fail/intrinsics/simd-reduce-invalid-bool.stderr index a2404b174e880..15c39500d4cb0 100644 --- a/tests/fail/intrinsics/simd-reduce-invalid-bool.stderr +++ b/tests/fail/intrinsics/simd-reduce-invalid-bool.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: each element of a SIMD mask must be all-0-bits or all-1-bits --> $DIR/simd-reduce-invalid-bool.rs:LL:CC | -LL | simd_reduce_any(x); - | ^^^^^^^^^^^^^^^^^^ each element of a SIMD mask must be all-0-bits or all-1-bits +LL | simd_reduce_any(x); + | ^^^^^^^^^^^^^^^^^^ each element of a SIMD mask must be all-0-bits or all-1-bits | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information From 6cd74ee9c79f72f2a19cb2a469077fdaf633332d Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Sun, 19 Jun 2022 22:57:10 -0400 Subject: [PATCH 3268/3747] Pass --color=always through cargo-miri --- cargo-miri/bin.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index 8b11016ca1be0..6a5e5dc3913ab 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -945,7 +945,14 @@ fn phase_runner(binary: &Path, binary_args: env::Args, phase: RunnerPhase) { // Drop this argument. } else if let Some(suffix) = arg.strip_prefix(json_flag) { assert!(suffix.starts_with('=')); - // Drop this argument. + // This is how we pass through --color=always. We detect that Cargo is detecting rustc + // to emit the diagnostic structure that Cargo would consume from rustc to emit colored + // diagnostics, and ask rustc to emit them. + // See https://github.com/rust-lang/miri/issues/2037 + if arg.split(',').any(|a| a == "diagnostic-rendered-ansi") { + cmd.arg("--color=always"); + } + // But aside from remembering that colored output was requested, drop this argument. } else { cmd.arg(arg); } From fed5ea8b10c4461ada9b4a121556bb7e0c05a3b2 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Mon, 20 Jun 2022 02:43:06 -0700 Subject: [PATCH 3269/3747] Manual adjustments --- tests/fail/data_race/atomic_write_na_read_race2.rs | 4 +++- tests/fail/data_race/read_write_race.rs | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/tests/fail/data_race/atomic_write_na_read_race2.rs b/tests/fail/data_race/atomic_write_na_read_race2.rs index 359970dfff8f3..0b055c9b96ec0 100644 --- a/tests/fail/data_race/atomic_write_na_read_race2.rs +++ b/tests/fail/data_race/atomic_write_na_read_race2.rs @@ -16,7 +16,9 @@ pub fn main() { let b = &mut a as *mut AtomicUsize; let c = EvilSend(b); unsafe { - let j1 = spawn(move || *(c.0 as *mut usize)); + let j1 = spawn(move || { + let _val = *(c.0 as *mut usize); + }); let j2 = spawn(move || { //Equivalent to: (&*c.0).store(32, Ordering::SeqCst) diff --git a/tests/fail/data_race/read_write_race.rs b/tests/fail/data_race/read_write_race.rs index 976ace6e4b6ff..9197912ef2e9d 100644 --- a/tests/fail/data_race/read_write_race.rs +++ b/tests/fail/data_race/read_write_race.rs @@ -13,7 +13,9 @@ pub fn main() { let b = &mut a as *mut u32; let c = EvilSend(b); unsafe { - let j1 = spawn(move || *c.0); + let j1 = spawn(move || { + let _val = *c.0; + }); let j2 = spawn(move || { *c.0 = 64; //~ ERROR Data race detected between Write on Thread(id = 2) and Read on Thread(id = 1) From 53580c1e18a38ddcc0508df5084c8ce2eeb58c42 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Mon, 20 Jun 2022 02:43:13 -0700 Subject: [PATCH 3270/3747] Add rustfmt CI for currently formatted directories --- .github/workflows/ci.yml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 55da948f7b785..ee65d58dccada 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -116,8 +116,11 @@ jobs: rustup override set nightly - name: Formatting (miri, ui_test) run: cargo fmt --all --check - - name: Formatting (cargo-miri) - run: cargo fmt --manifest-path cargo-miri/Cargo.toml --all --check + - name: Formatting (everything else) + # TODO: Add `tests` (work in progress). + # Maybe change to `find . -name '*.rs'`, superseding the previous step. + run: find bench-cargo-miri benches cargo-miri test-cargo-miri -name '*.rs' + | xargs rustfmt --edition=2021 --config-path ./rustfmt.toml --check # These jobs doesn't actually test anything, but they're only used to tell # bors the build completed, as there is no practical way to detect when a From 619813500bf96f99b9da1603646f6c58b2680deb Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Mon, 20 Jun 2022 15:30:34 -0700 Subject: [PATCH 3271/3747] Format tests with rustfmt (51-100 of 300) --- tests/pass/align.rs | 8 +- tests/pass/align_offset_symbolic.rs | 15 +- tests/pass/backtrace/backtrace-api-v0.rs | 25 ++- tests/pass/backtrace/backtrace-api-v1.rs | 29 ++- tests/pass/backtrace/backtrace-std.rs | 24 ++- tests/pass/binary-heap.rs | 2 +- tests/pass/binops.rs | 19 +- tests/pass/box.rs | 55 +++-- tests/pass/calls.rs | 14 +- tests/pass/cast-rfc0401-vtable-kinds.rs | 36 ++-- tests/pass/cast_fn_ptr.rs | 4 +- tests/pass/catch.rs | 4 +- tests/pass/closure-drop.rs | 5 +- tests/pass/closure-field-ty.rs | 4 +- tests/pass/closures.rs | 24 ++- .../coerce_non_capture_closure_to_fn_ptr.rs | 26 ++- tests/pass/coercions.rs | 59 +++--- .../concurrency/concurrent_caller_location.rs | 2 +- tests/pass/concurrency/data_race.rs | 35 +-- tests/pass/concurrency/simple.rs | 26 +-- tests/pass/concurrency/spin_loop.rs | 2 +- .../pass/concurrency/spin_loops_nopreempt.rs | 4 +- tests/pass/concurrency/sync_singlethread.rs | 4 +- tests/pass/concurrency/tls_lib_drop.rs | 15 +- .../concurrency/tls_pthread_drop_order.rs | 21 +- tests/pass/const-vec-of-fns.rs | 2 +- tests/pass/drop_empty_slice.rs | 2 +- tests/pass/drop_on_array_elements.rs | 6 +- tests/pass/drop_on_fat_ptr_array_elements.rs | 4 +- tests/pass/drop_on_zst_array_elements.rs | 6 +- tests/pass/drop_through_owned_slice.rs | 4 +- tests/pass/drop_through_trait_object.rs | 4 +- tests/pass/drop_through_trait_object_rc.rs | 4 +- tests/pass/dst-field-align.rs | 41 ++-- tests/pass/dst-irrefutable-bind.rs | 8 +- tests/pass/dst-raw.rs | 29 +-- tests/pass/dst-struct-sole.rs | 5 +- tests/pass/dst-struct.rs | 21 +- tests/pass/dyn-arbitrary-self.rs | 10 +- tests/pass/dyn-traits.rs | 17 +- .../enum-nullable-const-null-with-fields.rs | 1 - tests/pass/enums.rs | 18 +- tests/pass/extern_types.rs | 2 +- tests/pass/fat_ptr.rs | 6 +- tests/pass/float.rs | 199 +++++++++++++----- tests/pass/float_fast_math.rs | 2 +- tests/pass/foreign-fn-linkname.rs | 6 +- tests/pass/fs_with_isolation.rs | 7 +- tests/pass/function_calls/exported_symbol.rs | 6 +- tests/pass/function_pointers.rs | 38 +++- 50 files changed, 540 insertions(+), 370 deletions(-) diff --git a/tests/pass/align.rs b/tests/pass/align.rs index 81e7e8c7ccac3..5794b7f542762 100644 --- a/tests/pass/align.rs +++ b/tests/pass/align.rs @@ -2,9 +2,11 @@ fn manual_alignment() { let x = &mut [0u8; 3]; let base_addr = x as *mut _ as usize; - let base_addr_aligned = if base_addr % 2 == 0 { base_addr } else { base_addr+1 }; + let base_addr_aligned = if base_addr % 2 == 0 { base_addr } else { base_addr + 1 }; let u16_ptr = base_addr_aligned as *mut u16; - unsafe { *u16_ptr = 2; } + unsafe { + *u16_ptr = 2; + } } /// Test standard library `align_to`. @@ -12,7 +14,7 @@ fn align_to() { const LEN: usize = 128; let buf = &[0u8; LEN]; let (l, m, r) = unsafe { buf.align_to::() }; - assert!(m.len()*4 >= LEN-4); + assert!(m.len() * 4 >= LEN - 4); assert!(l.len() + r.len() <= 4); } diff --git a/tests/pass/align_offset_symbolic.rs b/tests/pass/align_offset_symbolic.rs index 70b2e00896dc0..ad231bd0d5bb6 100644 --- a/tests/pass/align_offset_symbolic.rs +++ b/tests/pass/align_offset_symbolic.rs @@ -36,31 +36,32 @@ fn test_align_to() { { let (l, m, r) = unsafe { s[1..].align_to::() }; assert_eq!(l.len(), 3); - assert_eq!(m.len(), N-1); + assert_eq!(m.len(), N - 1); assert_eq!(r.len(), 0); assert_eq!(raw.wrapping_offset(4), m.as_ptr() as *const u8); } { - let (l, m, r) = unsafe { s[..4*N - 1].align_to::() }; + let (l, m, r) = unsafe { s[..4 * N - 1].align_to::() }; assert_eq!(l.len(), 0); - assert_eq!(m.len(), N-1); + assert_eq!(m.len(), N - 1); assert_eq!(r.len(), 3); assert_eq!(raw, m.as_ptr() as *const u8); } { - let (l, m, r) = unsafe { s[1..4*N - 1].align_to::() }; + let (l, m, r) = unsafe { s[1..4 * N - 1].align_to::() }; assert_eq!(l.len(), 3); - assert_eq!(m.len(), N-2); + assert_eq!(m.len(), N - 2); assert_eq!(r.len(), 3); assert_eq!(raw.wrapping_offset(4), m.as_ptr() as *const u8); } { - #[repr(align(8))] struct Align8(u64); + #[repr(align(8))] + struct Align8(u64); let (l, m, r) = unsafe { s.align_to::() }; // requested alignment higher than allocation alignment - assert_eq!(l.len(), 4*N); + assert_eq!(l.len(), 4 * N); assert_eq!(r.len(), 0); assert_eq!(m.len(), 0); } diff --git a/tests/pass/backtrace/backtrace-api-v0.rs b/tests/pass/backtrace/backtrace-api-v0.rs index 62702c088dd67..32fd47d8c5813 100644 --- a/tests/pass/backtrace/backtrace-api-v0.rs +++ b/tests/pass/backtrace/backtrace-api-v0.rs @@ -1,14 +1,28 @@ // normalize-stderr-test: "::<.*>" -> "" -#[inline(never)] fn func_a() -> Box<[*mut ()]> { func_b::() } -#[inline(never)] fn func_b() -> Box<[*mut ()]> { func_c() } +#[inline(never)] +fn func_a() -> Box<[*mut ()]> { + func_b::() +} +#[inline(never)] +fn func_b() -> Box<[*mut ()]> { + func_c() +} macro_rules! invoke_func_d { - () => { func_d() } + () => { + func_d() + }; } -#[inline(never)] fn func_c() -> Box<[*mut ()]> { invoke_func_d!() } -#[inline(never)] fn func_d() -> Box<[*mut ()]> { unsafe { miri_get_backtrace(0) } } +#[inline(never)] +fn func_c() -> Box<[*mut ()]> { + invoke_func_d!() +} +#[inline(never)] +fn func_d() -> Box<[*mut ()]> { + unsafe { miri_get_backtrace(0) } +} fn main() { let mut seen_main = false; @@ -51,4 +65,3 @@ struct MiriFrame { colno: u32, fn_ptr: *mut (), } - diff --git a/tests/pass/backtrace/backtrace-api-v1.rs b/tests/pass/backtrace/backtrace-api-v1.rs index 6d4a29c954e9e..c24a5f3e81250 100644 --- a/tests/pass/backtrace/backtrace-api-v1.rs +++ b/tests/pass/backtrace/backtrace-api-v1.rs @@ -1,14 +1,33 @@ // normalize-stderr-test: "::<.*>" -> "" -#[inline(never)] fn func_a() -> Box<[*mut ()]> { func_b::() } -#[inline(never)] fn func_b() -> Box<[*mut ()]> { func_c() } +#[inline(never)] +fn func_a() -> Box<[*mut ()]> { + func_b::() +} +#[inline(never)] +fn func_b() -> Box<[*mut ()]> { + func_c() +} macro_rules! invoke_func_d { - () => { func_d() } + () => { + func_d() + }; } -#[inline(never)] fn func_c() -> Box<[*mut ()]> { invoke_func_d!() } -#[inline(never)] fn func_d() -> Box<[*mut ()]> { unsafe { let count = miri_backtrace_size(0); let mut buf = vec![std::ptr::null_mut(); count]; miri_get_backtrace(1, buf.as_mut_ptr()); buf.into() } } +#[inline(never)] +fn func_c() -> Box<[*mut ()]> { + invoke_func_d!() +} +#[inline(never)] +fn func_d() -> Box<[*mut ()]> { + unsafe { + let count = miri_backtrace_size(0); + let mut buf = vec![std::ptr::null_mut(); count]; + miri_get_backtrace(1, buf.as_mut_ptr()); + buf.into() + } +} fn main() { let mut seen_main = false; diff --git a/tests/pass/backtrace/backtrace-std.rs b/tests/pass/backtrace/backtrace-std.rs index 64b7e7293b194..5de7cdd6a54d0 100644 --- a/tests/pass/backtrace/backtrace-std.rs +++ b/tests/pass/backtrace/backtrace-std.rs @@ -4,15 +4,29 @@ use std::backtrace::Backtrace; -#[inline(never)] fn func_a() -> Backtrace { func_b::() } -#[inline(never)] fn func_b() -> Backtrace { func_c() } +#[inline(never)] +fn func_a() -> Backtrace { + func_b::() +} +#[inline(never)] +fn func_b() -> Backtrace { + func_c() +} macro_rules! invoke_func_d { - () => { func_d() } + () => { + func_d() + }; } -#[inline(never)] fn func_c() -> Backtrace { invoke_func_d!() } -#[inline(never)] fn func_d() -> Backtrace { Backtrace::capture() } +#[inline(never)] +fn func_c() -> Backtrace { + invoke_func_d!() +} +#[inline(never)] +fn func_d() -> Backtrace { + Backtrace::capture() +} fn main() { eprint!("{}", func_a()); diff --git a/tests/pass/binary-heap.rs b/tests/pass/binary-heap.rs index 8b8fa6458e650..278038d8ad321 100644 --- a/tests/pass/binary-heap.rs +++ b/tests/pass/binary-heap.rs @@ -26,7 +26,7 @@ fn drain() { for x in heap.drain() { sum += x; } - assert_eq!(sum, 127*128/2); + assert_eq!(sum, 127 * 128 / 2); assert!(heap.is_empty()); } diff --git a/tests/pass/binops.rs b/tests/pass/binops.rs index 1d03c8b3d0aa5..0988d7ccc4c6e 100644 --- a/tests/pass/binops.rs +++ b/tests/pass/binops.rs @@ -56,21 +56,18 @@ struct P { } fn p(x: isize, y: isize) -> P { - P { - x: x, - y: y - } + P { x: x, y: y } } fn test_class() { - let q = p(1, 2); - let mut r = p(1, 2); + let q = p(1, 2); + let mut r = p(1, 2); - assert_eq!(q, r); - r.y = 17; - assert!((r.y != q.y)); - assert_eq!(r.y, 17); - assert!((q != r)); + assert_eq!(q, r); + r.y = 17; + assert!((r.y != q.y)); + assert_eq!(r.y, 17); + assert!((q != r)); } pub fn main() { diff --git a/tests/pass/box.rs b/tests/pass/box.rs index c29a83507677f..c2ecc3707179f 100644 --- a/tests/pass/box.rs +++ b/tests/pass/box.rs @@ -6,30 +6,34 @@ fn main() { boxed_pair_to_vec(); } -fn into_raw() { unsafe { - let b = Box::new(4i32); - let r = Box::into_raw(b); - - // "lose the tag" - let r2 = ((r as usize)+0) as *mut i32; - *(&mut *r2) = 7; - - // Use original ptr again - *(&mut *r) = 17; - drop(Box::from_raw(r)); -}} +fn into_raw() { + unsafe { + let b = Box::new(4i32); + let r = Box::into_raw(b); + + // "lose the tag" + let r2 = ((r as usize) + 0) as *mut i32; + *(&mut *r2) = 7; + + // Use original ptr again + *(&mut *r) = 17; + drop(Box::from_raw(r)); + } +} -fn into_unique() { unsafe { - let b = Box::new(4i32); - let u = Box::into_unique(b).0; +fn into_unique() { + unsafe { + let b = Box::new(4i32); + let u = Box::into_unique(b).0; - // "lose the tag" - let r = ((u.as_ptr() as usize)+0) as *mut i32; - *(&mut *r) = 7; + // "lose the tag" + let r = ((u.as_ptr() as usize) + 0) as *mut i32; + *(&mut *r) = 7; - // Use original ptr again. - drop(Box::from_raw(u.as_ptr())); -}} + // Use original ptr again. + drop(Box::from_raw(u.as_ptr())); + } +} fn boxed_pair_to_vec() { #[repr(C)] @@ -44,15 +48,10 @@ fn boxed_pair_to_vec() { fn reinterstruct(box_pair: Box) -> Vec { let ref_pair = Box::leak(box_pair) as *mut PairFoo; let ptr_foo = unsafe { &mut (*ref_pair).fst as *mut Foo }; - unsafe { - Vec::from_raw_parts(ptr_foo, 2, 2) - } + unsafe { Vec::from_raw_parts(ptr_foo, 2, 2) } } - let pair_foo = Box::new(PairFoo { - fst: Foo(42), - snd: Foo(1337), - }); + let pair_foo = Box::new(PairFoo { fst: Foo(42), snd: Foo(1337) }); println!("pair_foo = {:?}", pair_foo); for (n, foo) in reinterstruct(pair_foo).into_iter().enumerate() { println!("foo #{} = {:?}", n, foo); diff --git a/tests/pass/calls.rs b/tests/pass/calls.rs index 4cbd7ada69e6f..014d1d3acab7f 100644 --- a/tests/pass/calls.rs +++ b/tests/pass/calls.rs @@ -7,17 +7,15 @@ fn call() -> i32 { fn factorial_recursive() -> i64 { fn fact(n: i64) -> i64 { - if n == 0 { - 1 - } else { - n * fact(n - 1) - } + if n == 0 { 1 } else { n * fact(n - 1) } } fact(10) } fn call_generic() -> (i16, bool) { - fn id(t: T) -> T { t } + fn id(t: T) -> T { + t + } (id(42), id(true)) } @@ -26,7 +24,9 @@ fn cross_crate_fn_call() -> i64 { if 1i32.is_positive() { 1 } else { 0 } } -const fn foo(i: i64) -> i64 { *&i + 1 } +const fn foo(i: i64) -> i64 { + *&i + 1 +} fn const_fn_call() -> i64 { let x = 5 + foo(5); diff --git a/tests/pass/cast-rfc0401-vtable-kinds.rs b/tests/pass/cast-rfc0401-vtable-kinds.rs index 544510be9bb09..d76c23633da1b 100644 --- a/tests/pass/cast-rfc0401-vtable-kinds.rs +++ b/tests/pass/cast-rfc0401-vtable-kinds.rs @@ -2,44 +2,52 @@ // whose vtable have the same kind (both lengths, or both trait pointers). trait Foo { - fn foo(&self, _: T) -> u32 { 42 } + fn foo(&self, _: T) -> u32 { + 42 + } } trait Bar { - fn bar(&self) { println!("Bar!"); } + fn bar(&self) { + println!("Bar!"); + } } impl Foo for () {} -impl Foo for u32 { fn foo(&self, _: u32) -> u32 { self+43 } } +impl Foo for u32 { + fn foo(&self, _: u32) -> u32 { + self + 43 + } +} impl Bar for () {} -unsafe fn round_trip_and_call<'a>(t: *const (dyn Foo+'a)) -> u32 { - let foo_e : *const dyn Foo = t as *const _; +unsafe fn round_trip_and_call<'a>(t: *const (dyn Foo + 'a)) -> u32 { + let foo_e: *const dyn Foo = t as *const _; let r_1 = foo_e as *mut dyn Foo; (&*r_1).foo(0) } #[repr(C)] -struct FooS(T); +struct FooS(T); #[repr(C)] -struct BarS(T); +struct BarS(T); -fn foo_to_bar(u: *const FooS) -> *const BarS { +fn foo_to_bar(u: *const FooS) -> *const BarS { u as *const BarS } fn main() { let x = 4u32; - let y : &dyn Foo = &x; + let y: &dyn Foo = &x; let fl = unsafe { round_trip_and_call(y as *const dyn Foo) }; - assert_eq!(fl, (43+4)); + assert_eq!(fl, (43 + 4)); - let s = FooS([0,1,2]); + let s = FooS([0, 1, 2]); let u: &FooS<[u32]> = &s; let u: *const FooS<[u32]> = u; - let bar_ref : *const BarS<[u32]> = foo_to_bar(u); - let z : &BarS<[u32]> = unsafe{&*bar_ref}; - assert_eq!(&z.0, &[0,1,2]); + let bar_ref: *const BarS<[u32]> = foo_to_bar(u); + let z: &BarS<[u32]> = unsafe { &*bar_ref }; + assert_eq!(&z.0, &[0, 1, 2]); // If validation fails here, that's likely because an immutable suspension is recovered mutably. } diff --git a/tests/pass/cast_fn_ptr.rs b/tests/pass/cast_fn_ptr.rs index 109e8dfc2a02b..8954048f4262c 100644 --- a/tests/pass/cast_fn_ptr.rs +++ b/tests/pass/cast_fn_ptr.rs @@ -1,9 +1,7 @@ fn main() { fn f(_: *const u8) {} - let g = unsafe { - std::mem::transmute::(f) - }; + let g = unsafe { std::mem::transmute::(f) }; g(&42 as *const _); } diff --git a/tests/pass/catch.rs b/tests/pass/catch.rs index 5fd65f138aaf9..745e186a8e17a 100644 --- a/tests/pass/catch.rs +++ b/tests/pass/catch.rs @@ -2,6 +2,8 @@ use std::panic::{catch_unwind, AssertUnwindSafe}; fn main() { let mut i = 3; - let _val = catch_unwind(AssertUnwindSafe(|| {i -= 2;} )); + let _val = catch_unwind(AssertUnwindSafe(|| { + i -= 2; + })); println!("{}", i); } diff --git a/tests/pass/closure-drop.rs b/tests/pass/closure-drop.rs index 374efb6032bf5..9f9454b4c71c5 100644 --- a/tests/pass/closure-drop.rs +++ b/tests/pass/closure-drop.rs @@ -17,9 +17,10 @@ fn main() { // this closure never by val uses its captures // so it's basically a fn(&self) // the shim used to not drop the `x` - let x = move || { let _val = x; }; + let x = move || { + let _val = x; + }; f(x); } assert!(ran_drop); } - diff --git a/tests/pass/closure-field-ty.rs b/tests/pass/closure-field-ty.rs index 0d27728d22322..fdcaf1d517238 100644 --- a/tests/pass/closure-field-ty.rs +++ b/tests/pass/closure-field-ty.rs @@ -3,7 +3,9 @@ fn main() { let mut y = 0; { let mut box_maybe_closure = Box::new(None); - *box_maybe_closure = Some(|| { y += 1; }); + *box_maybe_closure = Some(|| { + y += 1; + }); (box_maybe_closure.unwrap())(); } assert_eq!(y, 1); diff --git a/tests/pass/closures.rs b/tests/pass/closures.rs index 5e2e0f87bdaff..21292765acaa5 100644 --- a/tests/pass/closures.rs +++ b/tests/pass/closures.rs @@ -22,7 +22,9 @@ fn crazy_closure() -> (i32, i32, i32) { } fn closure_arg_adjustment_problem() -> i64 { - fn once(f: F) { f(2); } + fn once(f: F) { + f(2); + } let mut y = 1; { let f = |x| y += x; @@ -32,7 +34,9 @@ fn closure_arg_adjustment_problem() -> i64 { } fn fn_once_closure_with_multiple_args() -> i64 { - fn once i64>(f: F) -> i64 { f(2, 3) } + fn once i64>(f: F) -> i64 { + f(2, 3) + } let y = 1; { let f = |x, z| x + y + z; @@ -50,7 +54,8 @@ fn box_dyn() { let mut i = 5; { let mut x: Box = Box::new(|| i *= 2); - x(); x(); + x(); + x(); } assert_eq!(i, 20); } @@ -88,7 +93,9 @@ fn fn_item_with_multiple_args_as_closure_trait_object() { fn fn_ptr_as_closure_trait_object() { fn foo() {} - fn bar(u: u32) { assert_eq!(u, 42); } + fn bar(u: u32) { + assert_eq!(u, 42); + } fn baa(u: u32, f: f32) { assert_eq!(u, 42); assert_eq!(f, 3.141); @@ -101,13 +108,18 @@ fn fn_ptr_as_closure_trait_object() { f(42, 3.141); } - fn main() { assert_eq!(simple(), 12); assert_eq!(crazy_closure(), (84, 10, 10)); assert_eq!(closure_arg_adjustment_problem(), 3); assert_eq!(fn_once_closure_with_multiple_args(), 6); - assert_eq!(boxed_fn_once(Box::new({let x = 13; move || x})), 13); + assert_eq!( + boxed_fn_once(Box::new({ + let x = 13; + move || x + })), + 13 + ); box_dyn(); fn_item_as_closure_trait_object(); diff --git a/tests/pass/coerce_non_capture_closure_to_fn_ptr.rs b/tests/pass/coerce_non_capture_closure_to_fn_ptr.rs index bd8926aaf1ad5..fde120db027b1 100644 --- a/tests/pass/coerce_non_capture_closure_to_fn_ptr.rs +++ b/tests/pass/coerce_non_capture_closure_to_fn_ptr.rs @@ -1,11 +1,19 @@ -static FOO: fn() = || { assert_ne!(42, 43) }; -static BAR: fn(i32, i32) = |a, b| { assert_ne!(a, b) }; +static FOO: fn() = || assert_ne!(42, 43); +static BAR: fn(i32, i32) = |a, b| assert_ne!(a, b); // use to first make the closure FnOnce() before making it fn() -fn force_once0 R>(f: F) -> F { f } -fn force_once1 R>(f: F) -> F { f } -fn force_mut0 R>(f: F) -> F { f } -fn force_mut1 R>(f: F) -> F { f } +fn force_once0 R>(f: F) -> F { + f +} +fn force_once1 R>(f: F) -> F { + f +} +fn force_mut0 R>(f: F) -> F { + f +} +fn force_mut1 R>(f: F) -> F { + f +} fn main() { FOO(); @@ -15,11 +23,11 @@ fn main() { let boo: &dyn Fn(i32, i32) = &BAR; boo(48, 49); - let f: fn() = ||{}; + let f: fn() = || {}; f(); - let f = force_once0(||{}) as fn(); + let f = force_once0(|| {}) as fn(); f(); - let f = force_mut0(||{}) as fn(); + let f = force_mut0(|| {}) as fn(); f(); let g: fn(i32) = |i| assert_eq!(i, 2); diff --git a/tests/pass/coercions.rs b/tests/pass/coercions.rs index bfc821f799ee4..db0d2ffd44bcf 100644 --- a/tests/pass/coercions.rs +++ b/tests/pass/coercions.rs @@ -1,30 +1,32 @@ #![feature(coerce_unsized, unsize)] -use std::ops::CoerceUnsized; use std::marker::Unsize; +use std::ops::CoerceUnsized; -fn identity_coercion(x: &(dyn Fn(u32)->u32 + Send)) -> &dyn Fn(u32)->u32 { +fn identity_coercion(x: &(dyn Fn(u32) -> u32 + Send)) -> &dyn Fn(u32) -> u32 { x } -fn fn_coercions(f: &fn(u32) -> u32) -> - (unsafe fn(u32) -> u32, - &(dyn Fn(u32) -> u32 + Send)) -{ +fn fn_coercions(f: &fn(u32) -> u32) -> (unsafe fn(u32) -> u32, &(dyn Fn(u32) -> u32 + Send)) { (*f, f) } -fn simple_array_coercion(x: &[u8; 3]) -> &[u8] { x } +fn simple_array_coercion(x: &[u8; 3]) -> &[u8] { + x +} -fn square(a: u32) -> u32 { a * a } +fn square(a: u32) -> u32 { + a * a +} -#[derive(PartialEq,Eq)] -struct PtrWrapper<'a, T: 'a+?Sized>(u32, u32, (), &'a T); -impl<'a, T: ?Sized+Unsize, U: ?Sized> - CoerceUnsized> for PtrWrapper<'a, T> {} +#[derive(PartialEq, Eq)] +struct PtrWrapper<'a, T: 'a + ?Sized>(u32, u32, (), &'a T); +impl<'a, T: ?Sized + Unsize, U: ?Sized> CoerceUnsized> for PtrWrapper<'a, T> {} -struct TrivPtrWrapper<'a, T: 'a+?Sized>(&'a T); -impl<'a, T: ?Sized+Unsize, U: ?Sized> - CoerceUnsized> for TrivPtrWrapper<'a, T> {} +struct TrivPtrWrapper<'a, T: 'a + ?Sized>(&'a T); +impl<'a, T: ?Sized + Unsize, U: ?Sized> CoerceUnsized> + for TrivPtrWrapper<'a, T> +{ +} fn coerce_ptr_wrapper(p: PtrWrapper<[u8; 3]>) -> PtrWrapper<[u8]> { p @@ -34,40 +36,41 @@ fn coerce_triv_ptr_wrapper(p: TrivPtrWrapper<[u8; 3]>) -> TrivPtrWrapper<[u8]> { p } -fn coerce_fat_ptr_wrapper(p: PtrWrapper u32 + Send>) - -> PtrWrapper u32> { +fn coerce_fat_ptr_wrapper( + p: PtrWrapper u32 + Send>, +) -> PtrWrapper u32> { p } -fn coerce_ptr_wrapper_poly<'a, T, Trait: ?Sized>(p: PtrWrapper<'a, T>) - -> PtrWrapper<'a, Trait> - where PtrWrapper<'a, T>: CoerceUnsized> +fn coerce_ptr_wrapper_poly<'a, T, Trait: ?Sized>(p: PtrWrapper<'a, T>) -> PtrWrapper<'a, Trait> +where + PtrWrapper<'a, T>: CoerceUnsized>, { p } fn main() { - let a = [0,1,2]; - let square_local : fn(u32) -> u32 = square; - let (f,g) = fn_coercions(&square_local); + let a = [0, 1, 2]; + let square_local: fn(u32) -> u32 = square; + let (f, g) = fn_coercions(&square_local); // cannot use `square as *const ()` because we can't know whether the compiler duplicates // functions, so two function pointers are only equal if they result from the same function // to function pointer cast - assert_eq!(f as *const (), square_local as *const()); + assert_eq!(f as *const (), square_local as *const ()); assert_eq!(g(4), 16); assert_eq!(identity_coercion(g)(5), 25); assert_eq!(simple_array_coercion(&a), &a); - let w = coerce_ptr_wrapper(PtrWrapper(2,3,(),&a)); - assert!(w == PtrWrapper(2,3,(),&a) as PtrWrapper<[u8]>); + let w = coerce_ptr_wrapper(PtrWrapper(2, 3, (), &a)); + assert!(w == PtrWrapper(2, 3, (), &a) as PtrWrapper<[u8]>); let w = coerce_triv_ptr_wrapper(TrivPtrWrapper(&a)); assert_eq!(&w.0, &a); - let z = coerce_fat_ptr_wrapper(PtrWrapper(2,3,(),&square_local)); + let z = coerce_fat_ptr_wrapper(PtrWrapper(2, 3, (), &square_local)); assert_eq!((z.3)(6), 36); let z: PtrWrapper u32> = - coerce_ptr_wrapper_poly(PtrWrapper(2,3,(),&square_local)); + coerce_ptr_wrapper_poly(PtrWrapper(2, 3, (), &square_local)); assert_eq!((z.3)(6), 36); } diff --git a/tests/pass/concurrency/concurrent_caller_location.rs b/tests/pass/concurrency/concurrent_caller_location.rs index d509d1b3f797d..003b9e9ca9f46 100644 --- a/tests/pass/concurrency/concurrent_caller_location.rs +++ b/tests/pass/concurrency/concurrent_caller_location.rs @@ -1,7 +1,7 @@ // ignore-windows: Concurrency on Windows is not supported yet. -use std::thread::spawn; use std::panic::Location; +use std::thread::spawn; fn initialize() { let _ignore = initialize_inner(); diff --git a/tests/pass/concurrency/data_race.rs b/tests/pass/concurrency/data_race.rs index c51080f474fb1..071f5bbcdf394 100644 --- a/tests/pass/concurrency/data_race.rs +++ b/tests/pass/concurrency/data_race.rs @@ -1,8 +1,7 @@ // ignore-windows: Concurrency on Windows is not supported yet. // compile-flags: -Zmiri-disable-weak-memory-emulation - -use std::sync::atomic::{AtomicUsize, fence, Ordering}; +use std::sync::atomic::{fence, AtomicUsize, Ordering}; use std::thread::spawn; #[derive(Copy, Clone)] @@ -18,9 +17,10 @@ fn test_fence_sync() { let ptr = &mut var as *mut u32; let evil_ptr = EvilSend(ptr); - let j1 = spawn(move || { - unsafe { *evil_ptr.0 = 1; } + unsafe { + *evil_ptr.0 = 1; + } fence(Ordering::Release); SYNC.store(1, Ordering::Relaxed) }); @@ -38,16 +38,15 @@ fn test_fence_sync() { j2.join().unwrap(); } - fn test_multiple_reads() { let mut var = 42u32; let ptr = &mut var as *mut u32; let evil_ptr = EvilSend(ptr); - let j1 = spawn(move || unsafe {*evil_ptr.0}); - let j2 = spawn(move || unsafe {*evil_ptr.0}); - let j3 = spawn(move || unsafe {*evil_ptr.0}); - let j4 = spawn(move || unsafe {*evil_ptr.0}); + let j1 = spawn(move || unsafe { *evil_ptr.0 }); + let j2 = spawn(move || unsafe { *evil_ptr.0 }); + let j3 = spawn(move || unsafe { *evil_ptr.0 }); + let j4 = spawn(move || unsafe { *evil_ptr.0 }); assert_eq!(j1.join().unwrap(), 42); assert_eq!(j2.join().unwrap(), 42); @@ -75,13 +74,7 @@ pub fn test_rmw_no_block() { } }); - let j3 = spawn(move || { - if SYNC.load(Ordering::Acquire) == 2 { - *c.0 - } else { - 0 - } - }); + let j3 = spawn(move || if SYNC.load(Ordering::Acquire) == 2 { *c.0 } else { 0 }); j1.join().unwrap(); j2.join().unwrap(); @@ -101,16 +94,10 @@ pub fn test_simple_release() { SYNC.store(1, Ordering::Release); }); - let j2 = spawn(move || { - if SYNC.load(Ordering::Acquire) == 1 { - *c.0 - } else { - 0 - } - }); + let j2 = spawn(move || if SYNC.load(Ordering::Acquire) == 1 { *c.0 } else { 0 }); j1.join().unwrap(); - assert_eq!(j2.join().unwrap(),1); + assert_eq!(j2.join().unwrap(), 1); } } diff --git a/tests/pass/concurrency/simple.rs b/tests/pass/concurrency/simple.rs index 40d8802472aca..48c1f3d9fb52c 100644 --- a/tests/pass/concurrency/simple.rs +++ b/tests/pass/concurrency/simple.rs @@ -42,31 +42,25 @@ fn create_move_in() { } fn create_move_out() { - let result = thread::spawn(|| { - String::from("Hello!") - }) - .join() - .unwrap(); + let result = thread::spawn(|| String::from("Hello!")).join().unwrap(); assert_eq!(result.len(), 6); } fn panic() { - let result = thread::spawn(|| { - panic!("Hello!") - }) - .join() - .unwrap_err(); + let result = thread::spawn(|| panic!("Hello!")).join().unwrap_err(); let msg = result.downcast_ref::<&'static str>().unwrap(); assert_eq!(*msg, "Hello!"); } fn panic_named() { - thread::Builder::new().name("childthread".to_string()).spawn(move || { - panic!("Hello, world!"); - }) - .unwrap() - .join() - .unwrap_err(); + thread::Builder::new() + .name("childthread".to_string()) + .spawn(move || { + panic!("Hello, world!"); + }) + .unwrap() + .join() + .unwrap_err(); } fn main() { diff --git a/tests/pass/concurrency/spin_loop.rs b/tests/pass/concurrency/spin_loop.rs index 1e81f5dc86dce..e11f0789bb5db 100644 --- a/tests/pass/concurrency/spin_loop.rs +++ b/tests/pass/concurrency/spin_loop.rs @@ -1,6 +1,6 @@ // ignore-windows: Concurrency on Windows is not supported yet. -use std::thread; use std::sync::atomic::{AtomicUsize, Ordering}; +use std::thread; static FLAG: AtomicUsize = AtomicUsize::new(0); diff --git a/tests/pass/concurrency/spin_loops_nopreempt.rs b/tests/pass/concurrency/spin_loops_nopreempt.rs index d8064f6ed5396..99a5410c95dfd 100644 --- a/tests/pass/concurrency/spin_loops_nopreempt.rs +++ b/tests/pass/concurrency/spin_loops_nopreempt.rs @@ -2,10 +2,10 @@ // This specifically tests behavior *without* preemption. // compile-flags: -Zmiri-preemption-rate=0 -use std::thread; +use std::cell::Cell; use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering}; use std::sync::mpsc; -use std::cell::Cell; +use std::thread; /// When a thread yields, Miri's scheduler used to pick the thread with the lowest ID /// that can run. IDs are assigned in thread creation order. diff --git a/tests/pass/concurrency/sync_singlethread.rs b/tests/pass/concurrency/sync_singlethread.rs index 2474fe6633c36..5663e1c1426c9 100644 --- a/tests/pass/concurrency/sync_singlethread.rs +++ b/tests/pass/concurrency/sync_singlethread.rs @@ -1,6 +1,6 @@ -use std::sync::{Mutex, TryLockError}; -use std::sync::atomic; use std::hint; +use std::sync::atomic; +use std::sync::{Mutex, TryLockError}; fn main() { test_mutex_stdlib(); diff --git a/tests/pass/concurrency/tls_lib_drop.rs b/tests/pass/concurrency/tls_lib_drop.rs index 552b371cc7f12..fe46406c283c3 100644 --- a/tests/pass/concurrency/tls_lib_drop.rs +++ b/tests/pass/concurrency/tls_lib_drop.rs @@ -9,7 +9,9 @@ struct TestCell { impl Drop for TestCell { fn drop(&mut self) { - for _ in 0..10 { thread::yield_now(); } + for _ in 0..10 { + thread::yield_now(); + } println!("Dropping: {} (should be before 'Continue main 1').", *self.value.borrow()) } } @@ -43,7 +45,9 @@ struct JoinCell { impl Drop for JoinCell { fn drop(&mut self) { - for _ in 0..10 { thread::yield_now(); } + for _ in 0..10 { + thread::yield_now(); + } let join_handle = self.value.borrow_mut().take().unwrap(); println!("Joining: {} (should be before 'Continue main 2').", join_handle.join().unwrap()); } @@ -118,9 +122,10 @@ fn join_orders_after_tls_destructors() { match sync_state { THREAD2_LAUNCHED | THREAD1_WAITING => thread::yield_now(), MAIN_THREAD_RENDEZVOUS => break, - THREAD2_JOINED => panic!( - "Thread 1 still running after thread 2 joined on thread 1" - ), + THREAD2_JOINED => + panic!( + "Thread 1 still running after thread 2 joined on thread 1" + ), v => unreachable!("sync state: {}", v), } sync_state = SYNC_STATE.load(Ordering::SeqCst); diff --git a/tests/pass/concurrency/tls_pthread_drop_order.rs b/tests/pass/concurrency/tls_pthread_drop_order.rs index 72ab973b0f08f..4d69449821cd2 100644 --- a/tests/pass/concurrency/tls_pthread_drop_order.rs +++ b/tests/pass/concurrency/tls_pthread_drop_order.rs @@ -7,13 +7,13 @@ use std::mem; pub type Key = libc::pthread_key_t; -static mut RECORD : usize = 0; -static mut KEYS : [Key; 2] = [0; 2]; -static mut GLOBALS : [u64; 2] = [1, 0]; +static mut RECORD: usize = 0; +static mut KEYS: [Key; 2] = [0; 2]; +static mut GLOBALS: [u64; 2] = [1, 0]; -static mut CANNARY : *mut u64 = 0 as *mut _; // this serves as a cannary: if TLS dtors are not run properly, this will not get deallocated, making the test fail. +static mut CANNARY: *mut u64 = 0 as *mut _; // this serves as a cannary: if TLS dtors are not run properly, this will not get deallocated, making the test fail. -pub unsafe fn create(dtor: Option) -> Key { +pub unsafe fn create(dtor: Option) -> Key { let mut key = 0; assert_eq!(libc::pthread_key_create(&mut key, mem::transmute(dtor)), 0); key @@ -26,18 +26,19 @@ pub unsafe fn set(key: Key, value: *mut u8) { pub fn record(r: usize) { assert!(r < 10); - unsafe { RECORD = RECORD*10 + r }; + unsafe { RECORD = RECORD * 10 + r }; } -unsafe extern fn dtor(ptr: *mut u64) { +unsafe extern "C" fn dtor(ptr: *mut u64) { assert!(CANNARY != 0 as *mut _); // make sure we do not get run too often let val = *ptr; - let which_key = GLOBALS.iter().position(|global| global as *const _ == ptr).expect("Should find my global"); + let which_key = + GLOBALS.iter().position(|global| global as *const _ == ptr).expect("Should find my global"); record(which_key); if val > 0 { - *ptr = val-1; + *ptr = val - 1; set(KEYS[which_key], ptr as *mut _); } @@ -57,7 +58,7 @@ fn main() { // Initialize the keys we use to check destructor ordering for (key, global) in KEYS.iter_mut().zip(GLOBALS.iter_mut()) { - *key = create(Some(mem::transmute(dtor as unsafe extern fn(*mut u64)))); + *key = create(Some(mem::transmute(dtor as unsafe extern "C" fn(*mut u64)))); set(*key, global as *mut _ as *mut u8); } diff --git a/tests/pass/const-vec-of-fns.rs b/tests/pass/const-vec-of-fns.rs index 9b6c6fcc32efd..7f0782fe32247 100644 --- a/tests/pass/const-vec-of-fns.rs +++ b/tests/pass/const-vec-of-fns.rs @@ -5,7 +5,7 @@ * should be read as a null or otherwise wrong pointer and crash. */ -fn f() { } +fn f() {} static mut CLOSURES: &'static mut [fn()] = &mut [f as fn(), f as fn()]; pub fn main() { diff --git a/tests/pass/drop_empty_slice.rs b/tests/pass/drop_empty_slice.rs index 8b481a0a2dd89..9805ce0ace3f0 100644 --- a/tests/pass/drop_empty_slice.rs +++ b/tests/pass/drop_empty_slice.rs @@ -2,6 +2,6 @@ fn main() { // With the nested Vec, this is calling Offset(Unique::empty(), 0) on drop. - let args : Vec> = Vec::new(); + let args: Vec> = Vec::new(); let _val = box args; } diff --git a/tests/pass/drop_on_array_elements.rs b/tests/pass/drop_on_array_elements.rs index c9b59f635e145..ae1ef036267e2 100644 --- a/tests/pass/drop_on_array_elements.rs +++ b/tests/pass/drop_on_array_elements.rs @@ -5,7 +5,9 @@ static mut DROP_COUNT: usize = 0; impl Drop for Bar { fn drop(&mut self) { assert_eq!(self.0 as usize, unsafe { DROP_COUNT }); // tests whether we are called at a valid address - unsafe { DROP_COUNT += 1; } + unsafe { + DROP_COUNT += 1; + } } } @@ -16,7 +18,7 @@ fn main() { assert_eq!(unsafe { DROP_COUNT }, 4); // check empty case - let b : [Bar; 0] = []; + let b: [Bar; 0] = []; drop(b); assert_eq!(unsafe { DROP_COUNT }, 4); } diff --git a/tests/pass/drop_on_fat_ptr_array_elements.rs b/tests/pass/drop_on_fat_ptr_array_elements.rs index 36162d320212a..40025cd07f7e0 100644 --- a/tests/pass/drop_on_fat_ptr_array_elements.rs +++ b/tests/pass/drop_on_fat_ptr_array_elements.rs @@ -8,7 +8,9 @@ static mut DROP_COUNT: usize = 0; impl Drop for Bar { fn drop(&mut self) { - unsafe { DROP_COUNT += 1; } + unsafe { + DROP_COUNT += 1; + } } } diff --git a/tests/pass/drop_on_zst_array_elements.rs b/tests/pass/drop_on_zst_array_elements.rs index 1887130fdd8a4..babe098e4e6f5 100644 --- a/tests/pass/drop_on_zst_array_elements.rs +++ b/tests/pass/drop_on_zst_array_elements.rs @@ -4,7 +4,9 @@ static mut DROP_COUNT: usize = 0; impl Drop for Bar { fn drop(&mut self) { - unsafe { DROP_COUNT += 1; } + unsafe { + DROP_COUNT += 1; + } } } @@ -15,7 +17,7 @@ fn main() { assert_eq!(unsafe { DROP_COUNT }, 4); // check empty case - let b : [Bar; 0] = []; + let b: [Bar; 0] = []; drop(b); assert_eq!(unsafe { DROP_COUNT }, 4); } diff --git a/tests/pass/drop_through_owned_slice.rs b/tests/pass/drop_through_owned_slice.rs index 3ec6be65ed8b6..8cdeb57d02f79 100644 --- a/tests/pass/drop_through_owned_slice.rs +++ b/tests/pass/drop_through_owned_slice.rs @@ -4,7 +4,9 @@ static mut DROP_COUNT: usize = 0; impl Drop for Bar { fn drop(&mut self) { - unsafe { DROP_COUNT += 1; } + unsafe { + DROP_COUNT += 1; + } } } diff --git a/tests/pass/drop_through_trait_object.rs b/tests/pass/drop_through_trait_object.rs index 97ba69c9fe288..8d22ca9ceb4ab 100644 --- a/tests/pass/drop_through_trait_object.rs +++ b/tests/pass/drop_through_trait_object.rs @@ -6,7 +6,9 @@ static mut DROP_CALLED: bool = false; impl Drop for Bar { fn drop(&mut self) { - unsafe { DROP_CALLED = true; } + unsafe { + DROP_CALLED = true; + } } } diff --git a/tests/pass/drop_through_trait_object_rc.rs b/tests/pass/drop_through_trait_object_rc.rs index 172a4580dc105..7806c0252d270 100644 --- a/tests/pass/drop_through_trait_object_rc.rs +++ b/tests/pass/drop_through_trait_object_rc.rs @@ -6,7 +6,9 @@ static mut DROP_CALLED: bool = false; impl Drop for Bar { fn drop(&mut self) { - unsafe { DROP_CALLED = true; } + unsafe { + DROP_CALLED = true; + } } } diff --git a/tests/pass/dst-field-align.rs b/tests/pass/dst-field-align.rs index 6c827d7b3beae..4d1db03643f79 100644 --- a/tests/pass/dst-field-align.rs +++ b/tests/pass/dst-field-align.rs @@ -1,7 +1,7 @@ #[allow(dead_code)] struct Foo { a: u16, - b: T + b: T, } trait Bar { @@ -9,59 +9,58 @@ trait Bar { } impl Bar for usize { - fn get(&self) -> usize { *self } + fn get(&self) -> usize { + *self + } } struct Baz { - a: T + a: T, } #[allow(dead_code)] struct HasDrop { ptr: Box, - data: T + data: T, } fn main() { // Test that zero-offset works properly - let b : Baz = Baz { a: 7 }; + let b: Baz = Baz { a: 7 }; assert_eq!(b.a.get(), 7); - let b : &Baz = &b; + let b: &Baz = &b; assert_eq!(b.a.get(), 7); // Test that the field is aligned properly - let f : Foo = Foo { a: 0, b: 11 }; + let f: Foo = Foo { a: 0, b: 11 }; assert_eq!(f.b.get(), 11); - let ptr1 : *const u8 = &f.b as *const _ as *const u8; + let ptr1: *const u8 = &f.b as *const _ as *const u8; - let f : &Foo = &f; - let ptr2 : *const u8 = &f.b as *const _ as *const u8; + let f: &Foo = &f; + let ptr2: *const u8 = &f.b as *const _ as *const u8; assert_eq!(f.b.get(), 11); // The pointers should be the same assert_eq!(ptr1, ptr2); // Test that nested DSTs work properly - let f : Foo> = Foo { a: 0, b: Foo { a: 1, b: 17 }}; + let f: Foo> = Foo { a: 0, b: Foo { a: 1, b: 17 } }; assert_eq!(f.b.b.get(), 17); - let f : &Foo> = &f; + let f: &Foo> = &f; assert_eq!(f.b.b.get(), 17); // Test that get the pointer via destructuring works - let f : Foo = Foo { a: 0, b: 11 }; - let f : &Foo = &f; + let f: Foo = Foo { a: 0, b: 11 }; + let f: &Foo = &f; let &Foo { a: _, b: ref bar } = f; assert_eq!(bar.get(), 11); // Make sure that drop flags don't screw things up - let d : HasDrop> = HasDrop { - ptr: Box::new(0), - data: Baz { a: [1,2,3,4] } - }; - assert_eq!([1,2,3,4], d.data.a); + let d: HasDrop> = HasDrop { ptr: Box::new(0), data: Baz { a: [1, 2, 3, 4] } }; + assert_eq!([1, 2, 3, 4], d.data.a); - let d : &HasDrop> = &d; - assert_eq!(&[1,2,3,4], &d.data.a); + let d: &HasDrop> = &d; + assert_eq!(&[1, 2, 3, 4], &d.data.a); } diff --git a/tests/pass/dst-irrefutable-bind.rs b/tests/pass/dst-irrefutable-bind.rs index eeddfce75fd9f..fe7335c0c6564 100644 --- a/tests/pass/dst-irrefutable-bind.rs +++ b/tests/pass/dst-irrefutable-bind.rs @@ -1,14 +1,14 @@ struct Test(T); fn main() { - let x = Test([1,2,3]); - let x : &Test<[i32]> = &x; + let x = Test([1, 2, 3]); + let x: &Test<[i32]> = &x; - let & ref _y = x; + let &ref _y = x; // Make sure binding to a fat pointer behind a reference // still works - let slice = &[1,2,3]; + let slice = &[1, 2, 3]; let x = Test(&slice); let Test(&_slice) = x; } diff --git a/tests/pass/dst-raw.rs b/tests/pass/dst-raw.rs index 0fe2b72b8c6ab..f26191a1d5998 100644 --- a/tests/pass/dst-raw.rs +++ b/tests/pass/dst-raw.rs @@ -1,12 +1,11 @@ // Test DST raw pointers - trait Trait { fn foo(&self) -> isize; } struct A { - f: isize + f: isize, } impl Trait for A { fn foo(&self) -> isize { @@ -15,24 +14,20 @@ impl Trait for A { } struct Foo { - f: T + f: T, } pub fn main() { // raw trait object let x = A { f: 42 }; let z: *const dyn Trait = &x; - let r = unsafe { - (&*z).foo() - }; + let r = unsafe { (&*z).foo() }; assert_eq!(r, 42); // raw DST struct - let p = Foo {f: A { f: 42 }}; + let p = Foo { f: A { f: 42 } }; let o: *const Foo = &p; - let r = unsafe { - (&*o).f.foo() - }; + let r = unsafe { (&*o).f.foo() }; assert_eq!(r, 42); // raw slice @@ -54,7 +49,7 @@ pub fn main() { } // raw DST struct with slice - let c: *const Foo<[_]> = &Foo {f: [1, 2, 3]}; + let c: *const Foo<[_]> = &Foo { f: [1, 2, 3] }; unsafe { let b = (&*c).f[0]; assert_eq!(b, 1); @@ -65,16 +60,12 @@ pub fn main() { // all of the above with *mut let mut x = A { f: 42 }; let z: *mut dyn Trait = &mut x; - let r = unsafe { - (&*z).foo() - }; + let r = unsafe { (&*z).foo() }; assert_eq!(r, 42); - let mut p = Foo {f: A { f: 42 }}; + let mut p = Foo { f: A { f: 42 } }; let o: *mut Foo = &mut p; - let r = unsafe { - (&*o).f.foo() - }; + let r = unsafe { (&*o).f.foo() }; assert_eq!(r, 42); let a: *mut [_] = &mut [1, 2, 3]; @@ -93,7 +84,7 @@ pub fn main() { assert_eq!(len, 3); } - let c: *mut Foo<[_]> = &mut Foo {f: [1, 2, 3]}; + let c: *mut Foo<[_]> = &mut Foo { f: [1, 2, 3] }; unsafe { let b = (&*c).f[0]; assert_eq!(b, 1); diff --git a/tests/pass/dst-struct-sole.rs b/tests/pass/dst-struct-sole.rs index 770af864a44c0..4b25fbb063006 100644 --- a/tests/pass/dst-struct-sole.rs +++ b/tests/pass/dst-struct-sole.rs @@ -1,8 +1,7 @@ // As dst-struct.rs, but the unsized field is the only field in the struct. - struct Fat { - ptr: T + ptr: T, } // x is a fat pointer @@ -13,7 +12,7 @@ fn foo(x: &Fat<[isize]>) { assert_eq!(x.ptr[1], 2); } -fn foo2(x: &Fat<[T]>) { +fn foo2(x: &Fat<[T]>) { let y = &x.ptr; let bar = Bar; assert_eq!(x.ptr.len(), 3); diff --git a/tests/pass/dst-struct.rs b/tests/pass/dst-struct.rs index bd6517bd1fd77..7191068eb2c40 100644 --- a/tests/pass/dst-struct.rs +++ b/tests/pass/dst-struct.rs @@ -3,7 +3,7 @@ struct Fat { f1: isize, f2: &'static str, - ptr: T + ptr: T, } // x is a fat pointer @@ -16,7 +16,7 @@ fn foo(x: &Fat<[isize]>) { assert_eq!(x.f2, "some str"); } -fn foo2(x: &Fat<[T]>) { +fn foo2(x: &Fat<[T]>) { let y = &x.ptr; let bar = Bar; assert_eq!(x.ptr.len(), 3); @@ -37,7 +37,6 @@ fn foo3(x: &Fat>) { assert_eq!(x.ptr.ptr[1], 2); } - #[derive(Copy, Clone, PartialEq, Eq, Debug)] struct Bar; @@ -53,9 +52,9 @@ impl ToBar for Bar { pub fn main() { // With a vec of ints. - let f1 : Fat<[isize; 3]> = Fat { f1: 5, f2: "some str", ptr: [1, 2, 3] }; + let f1: Fat<[isize; 3]> = Fat { f1: 5, f2: "some str", ptr: [1, 2, 3] }; foo(&f1); - let f2 : &Fat<[isize; 3]> = &f1; + let f2: &Fat<[isize; 3]> = &f1; foo(f2); let f3: &Fat<[isize]> = f2; foo(f3); @@ -91,7 +90,7 @@ pub fn main() { assert!(f5.ptr.is_empty()); // Deeply nested. - let f1 = Fat { f1: 5, f2: "some str", ptr: Fat { f1: 8, f2: "deep str", ptr: [1, 2, 3]} }; + let f1 = Fat { f1: 5, f2: "some str", ptr: Fat { f1: 8, f2: "deep str", ptr: [1, 2, 3] } }; foo3(&f1); let f2 = &f1; foo3(f2); @@ -100,7 +99,7 @@ pub fn main() { let f4: &Fat> = &f1; foo3(f4); let f5: &Fat> = - &Fat { f1: 5, f2: "some str", ptr: Fat { f1: 8, f2: "deep str", ptr: [1, 2, 3]} }; + &Fat { f1: 5, f2: "some str", ptr: Fat { f1: 8, f2: "deep str", ptr: [1, 2, 3] } }; foo3(f5); // Box. @@ -110,14 +109,14 @@ pub fn main() { assert_eq!((*f2)[1], 2); // Nested Box. - let f1 : Box> = box Fat { f1: 5, f2: "some str", ptr: [1, 2, 3] }; + let f1: Box> = box Fat { f1: 5, f2: "some str", ptr: [1, 2, 3] }; foo(&*f1); - let f2 : Box> = f1; + let f2: Box> = f1; foo(&*f2); - let f3 : Box> = + let f3: Box> = Box::>::new(Fat { f1: 5, f2: "some str", ptr: [1, 2, 3] }); foo(&*f3); - let f4 : Box> = box Fat { f1: 5, f2: "some str", ptr: [1, 2, 3] }; + let f4: Box> = box Fat { f1: 5, f2: "some str", ptr: [1, 2, 3] }; foo(&*f4); } diff --git a/tests/pass/dyn-arbitrary-self.rs b/tests/pass/dyn-arbitrary-self.rs index 5c19c260dd956..256c72add9220 100644 --- a/tests/pass/dyn-arbitrary-self.rs +++ b/tests/pass/dyn-arbitrary-self.rs @@ -19,11 +19,7 @@ fn pin_box_dyn() { } fn stdlib_pointers() { - use std::{ - rc::Rc, - sync::Arc, - pin::Pin, - }; + use std::{pin::Pin, rc::Rc, sync::Arc}; trait Trait { fn by_rc(self: Rc) -> i64; @@ -63,8 +59,8 @@ fn stdlib_pointers() { fn pointers_and_wrappers() { use std::{ - ops::{Deref, CoerceUnsized, DispatchFromDyn}, marker::Unsize, + ops::{CoerceUnsized, Deref, DispatchFromDyn}, }; struct Ptr(Box); @@ -93,7 +89,6 @@ fn pointers_and_wrappers() { impl, U> CoerceUnsized> for Wrapper {} impl, U> DispatchFromDyn> for Wrapper {} - trait Trait { // This method isn't object-safe yet. Unsized by-value `self` is object-safe (but not callable // without unsized_locals), but wrappers arond `Self` currently are not. @@ -126,7 +121,6 @@ fn pointers_and_wrappers() { assert_eq!(wpw.wrapper_ptr_wrapper(), 7); } - fn main() { pin_box_dyn(); stdlib_pointers(); diff --git a/tests/pass/dyn-traits.rs b/tests/pass/dyn-traits.rs index 51c2130bcd3f3..00667757b0488 100644 --- a/tests/pass/dyn-traits.rs +++ b/tests/pass/dyn-traits.rs @@ -39,7 +39,6 @@ fn ref_box_dyn() { y.box_method(); } - fn box_box_trait() { struct DroppableStruct; @@ -47,17 +46,23 @@ fn box_box_trait() { impl Drop for DroppableStruct { fn drop(&mut self) { - unsafe { DROPPED = true; } + unsafe { + DROPPED = true; + } } } - trait MyTrait { fn dummy(&self) { } } + trait MyTrait { + fn dummy(&self) {} + } impl MyTrait for Box {} - struct Whatever { w: Box } + struct Whatever { + w: Box, + } - impl Whatever { - fn new(w: Box) -> Whatever { + impl Whatever { + fn new(w: Box) -> Whatever { Whatever { w: w } } } diff --git a/tests/pass/enum-nullable-const-null-with-fields.rs b/tests/pass/enum-nullable-const-null-with-fields.rs index 87389c9c3a819..8385cc5d880c6 100644 --- a/tests/pass/enum-nullable-const-null-with-fields.rs +++ b/tests/pass/enum-nullable-const-null-with-fields.rs @@ -1,4 +1,3 @@ - use std::result::Result; use std::result::Result::Ok; diff --git a/tests/pass/enums.rs b/tests/pass/enums.rs index d399beb91b2f5..d2dc06525475e 100644 --- a/tests/pass/enums.rs +++ b/tests/pass/enums.rs @@ -2,24 +2,21 @@ enum MyEnum { MyEmptyVariant, MyNewtypeVariant(i32), MyTupleVariant(i32, i32), - MyStructVariant { - my_first_field: i32, - my_second_field: i32, - } + MyStructVariant { my_first_field: i32, my_second_field: i32 }, } fn test(me: MyEnum) { match me { - MyEnum::MyEmptyVariant => {}, + MyEnum::MyEmptyVariant => {} MyEnum::MyNewtypeVariant(ref val) => assert_eq!(val, &42), MyEnum::MyTupleVariant(ref a, ref b) => { assert_eq!(a, &43); assert_eq!(b, &44); - }, + } MyEnum::MyStructVariant { ref my_first_field, ref my_second_field } => { assert_eq!(my_first_field, &45); assert_eq!(my_second_field, &46); - }, + } } } @@ -41,7 +38,7 @@ fn discriminant_overflow() { let x = Foo::B; match x { - Foo::B => {}, + Foo::B => {} _ => panic!(), } } @@ -126,10 +123,7 @@ fn main() { test(MyEnum::MyEmptyVariant); test(MyEnum::MyNewtypeVariant(42)); test(MyEnum::MyTupleVariant(43, 44)); - test(MyEnum::MyStructVariant{ - my_first_field: 45, - my_second_field: 46, - }); + test(MyEnum::MyStructVariant { my_first_field: 45, my_second_field: 46 }); discriminant_overflow(); more_discriminant_overflow(); diff --git a/tests/pass/extern_types.rs b/tests/pass/extern_types.rs index b37cd8408ba10..aa4c65ea8928a 100644 --- a/tests/pass/extern_types.rs +++ b/tests/pass/extern_types.rs @@ -1,6 +1,6 @@ #![feature(extern_types)] -extern { +extern "C" { type Foo; } diff --git a/tests/pass/fat_ptr.rs b/tests/pass/fat_ptr.rs index 55418c4802a7c..8317156a218dd 100644 --- a/tests/pass/fat_ptr.rs +++ b/tests/pass/fat_ptr.rs @@ -3,7 +3,7 @@ struct Wrapper(u32, T); struct FatPtrContainer<'a> { - ptr: &'a [u8] + ptr: &'a [u8], } fn fat_ptr_project(a: &Wrapper<[u8]>) -> &[u8] { @@ -36,14 +36,14 @@ fn fat_ptr_constant() -> &'static str { } fn main() { - let a = Wrapper(4, [7,6,5]); + let a = Wrapper(4, [7, 6, 5]); let p = fat_ptr_project(&a); let p = fat_ptr_simple(p); let p = fat_ptr_via_local(p); let p = fat_ptr_from_struct(fat_ptr_to_struct(p)); - let mut target : &[u8] = &[42]; + let mut target: &[u8] = &[42]; fat_ptr_store_to(p, &mut target); assert_eq!(target, &a.1); diff --git a/tests/pass/float.rs b/tests/pass/float.rs index e40ea919dca16..48dd99441ebff 100644 --- a/tests/pass/float.rs +++ b/tests/pass/float.rs @@ -26,60 +26,110 @@ trait FloatToInt: Copy { } impl FloatToInt for f32 { - fn cast(self) -> i8 { self as _ } - unsafe fn cast_unchecked(self) -> i8 { self.to_int_unchecked() } + fn cast(self) -> i8 { + self as _ + } + unsafe fn cast_unchecked(self) -> i8 { + self.to_int_unchecked() + } } impl FloatToInt for f32 { - fn cast(self) -> i32 { self as _ } - unsafe fn cast_unchecked(self) -> i32 { self.to_int_unchecked() } + fn cast(self) -> i32 { + self as _ + } + unsafe fn cast_unchecked(self) -> i32 { + self.to_int_unchecked() + } } impl FloatToInt for f32 { - fn cast(self) -> u32 { self as _ } - unsafe fn cast_unchecked(self) -> u32 { self.to_int_unchecked() } + fn cast(self) -> u32 { + self as _ + } + unsafe fn cast_unchecked(self) -> u32 { + self.to_int_unchecked() + } } impl FloatToInt for f32 { - fn cast(self) -> i64 { self as _ } - unsafe fn cast_unchecked(self) -> i64 { self.to_int_unchecked() } + fn cast(self) -> i64 { + self as _ + } + unsafe fn cast_unchecked(self) -> i64 { + self.to_int_unchecked() + } } impl FloatToInt for f32 { - fn cast(self) -> u64 { self as _ } - unsafe fn cast_unchecked(self) -> u64 { self.to_int_unchecked() } + fn cast(self) -> u64 { + self as _ + } + unsafe fn cast_unchecked(self) -> u64 { + self.to_int_unchecked() + } } impl FloatToInt for f64 { - fn cast(self) -> i8 { self as _ } - unsafe fn cast_unchecked(self) -> i8 { self.to_int_unchecked() } + fn cast(self) -> i8 { + self as _ + } + unsafe fn cast_unchecked(self) -> i8 { + self.to_int_unchecked() + } } impl FloatToInt for f64 { - fn cast(self) -> i32 { self as _ } - unsafe fn cast_unchecked(self) -> i32 { self.to_int_unchecked() } + fn cast(self) -> i32 { + self as _ + } + unsafe fn cast_unchecked(self) -> i32 { + self.to_int_unchecked() + } } impl FloatToInt for f64 { - fn cast(self) -> u32 { self as _ } - unsafe fn cast_unchecked(self) -> u32 { self.to_int_unchecked() } + fn cast(self) -> u32 { + self as _ + } + unsafe fn cast_unchecked(self) -> u32 { + self.to_int_unchecked() + } } impl FloatToInt for f64 { - fn cast(self) -> i64 { self as _ } - unsafe fn cast_unchecked(self) -> i64 { self.to_int_unchecked() } + fn cast(self) -> i64 { + self as _ + } + unsafe fn cast_unchecked(self) -> i64 { + self.to_int_unchecked() + } } impl FloatToInt for f64 { - fn cast(self) -> u64 { self as _ } - unsafe fn cast_unchecked(self) -> u64 { self.to_int_unchecked() } + fn cast(self) -> u64 { + self as _ + } + unsafe fn cast_unchecked(self) -> u64 { + self.to_int_unchecked() + } } impl FloatToInt for f64 { - fn cast(self) -> i128 { self as _ } - unsafe fn cast_unchecked(self) -> i128 { self.to_int_unchecked() } + fn cast(self) -> i128 { + self as _ + } + unsafe fn cast_unchecked(self) -> i128 { + self.to_int_unchecked() + } } impl FloatToInt for f64 { - fn cast(self) -> u128 { self as _ } - unsafe fn cast_unchecked(self) -> u128 { self.to_int_unchecked() } + fn cast(self) -> u128 { + self as _ + } + unsafe fn cast_unchecked(self) -> u128 { + self.to_int_unchecked() + } } /// Test this cast both via `as` and via `approx_unchecked` (i.e., it must not saturate). #[track_caller] #[inline(never)] fn test_both_cast(x: F, y: I) - where F: FloatToInt, I: PartialEq + Debug +where + F: FloatToInt, + I: PartialEq + Debug, { assert_eq!(x.cast(), y); assert_eq!(unsafe { x.cast_unchecked() }, y); @@ -87,15 +137,15 @@ fn test_both_cast(x: F, y: I) fn basic() { // basic arithmetic - assert_eq(6.0_f32*6.0_f32, 36.0_f32); - assert_eq(6.0_f64*6.0_f64, 36.0_f64); - assert_eq(-{5.0_f32}, -5.0_f32); - assert_eq(-{5.0_f64}, -5.0_f64); + assert_eq(6.0_f32 * 6.0_f32, 36.0_f32); + assert_eq(6.0_f64 * 6.0_f64, 36.0_f64); + assert_eq(-{ 5.0_f32 }, -5.0_f32); + assert_eq(-{ 5.0_f64 }, -5.0_f64); // infinities, NaN - assert!((5.0_f32/0.0).is_infinite()); - assert_ne!({5.0_f32/0.0}, {-5.0_f32/0.0}); - assert!((5.0_f64/0.0).is_infinite()); - assert_ne!({5.0_f64/0.0}, {5.0_f64/-0.0}); + assert!((5.0_f32 / 0.0).is_infinite()); + assert_ne!({ 5.0_f32 / 0.0 }, { -5.0_f32 / 0.0 }); + assert!((5.0_f64 / 0.0).is_infinite()); + assert_ne!({ 5.0_f64 / 0.0 }, { 5.0_f64 / -0.0 }); assert!((-5.0_f32).sqrt().is_nan()); assert!((-5.0_f64).sqrt().is_nan()); assert_ne!(f32::NAN, f32::NAN); @@ -161,9 +211,9 @@ fn casts() { test_both_cast::(4294967040.0, 0u32.wrapping_sub(256)); test_both_cast::(/*-0x1.ccccccp-1*/ f32::from_bits(0xbf666666), 0); test_both_cast::(/*-0x1.fffffep-1*/ f32::from_bits(0xbf7fffff), 0); - test_both_cast::((u32::MAX-128) as f32, u32::MAX-255); // rounding loss + test_both_cast::((u32::MAX - 128) as f32, u32::MAX - 255); // rounding loss // unrepresentable casts - assert_eq::((u32::MAX-127) as f32 as u32, u32::MAX); // rounds up and then becomes unrepresentable + assert_eq::((u32::MAX - 127) as f32 as u32, u32::MAX); // rounds up and then becomes unrepresentable assert_eq::(4294967296.0f32 as u32, u32::MAX); assert_eq::(-5.0f32 as u32, 0); assert_eq::(f32::MAX as u32, u32::MAX); @@ -187,7 +237,10 @@ fn casts() { test_both_cast::(0.0, 0); test_both_cast::(-0.0, 0); test_both_cast::(/*0x1.199999999999ap+0*/ f64::from_bits(0x3ff199999999999a), 1); - test_both_cast::(/*-0x1.199999999999ap+0*/ f64::from_bits(0xbff199999999999a), -1); + test_both_cast::( + /*-0x1.199999999999ap+0*/ f64::from_bits(0xbff199999999999a), + -1, + ); test_both_cast::(1.9, 1); test_both_cast::(-1.9, -1); test_both_cast::(1e8, 100_000_000); @@ -201,9 +254,15 @@ fn casts() { test_both_cast::(0.0, 0); test_both_cast::(-0.0, 0); test_both_cast::(/*0x0.0000000000001p-1022*/ f64::from_bits(0x1), 0); - test_both_cast::(/*-0x0.0000000000001p-1022*/ f64::from_bits(0x8000000000000001), 0); + test_both_cast::( + /*-0x0.0000000000001p-1022*/ f64::from_bits(0x8000000000000001), + 0, + ); test_both_cast::(/*0x1.199999999999ap+0*/ f64::from_bits(0x3ff199999999999a), 1); - test_both_cast::(/*-0x1.199999999999ap+0*/ f64::from_bits(0xbff199999999999a), -1); + test_both_cast::( + /*-0x1.199999999999ap+0*/ f64::from_bits(0xbff199999999999a), + -1, + ); test_both_cast::(5.0, 5); test_both_cast::(5.9, 5); test_both_cast::(-5.0, -5); @@ -228,11 +287,11 @@ fn casts() { test_both_cast::(-0.99999999999, 0); test_both_cast::(5.0, 5); test_both_cast::(1e16, 10000000000000000); - test_both_cast::((u64::MAX-1024) as f64, u64::MAX-2047); // rounding loss + test_both_cast::((u64::MAX - 1024) as f64, u64::MAX - 2047); // rounding loss test_both_cast::(9223372036854775808.0, 9223372036854775808); // unrepresentable casts assert_eq::(-5.0f64 as u64, 0); - assert_eq::((u64::MAX-1023) as f64 as u64, u64::MAX); // rounds up and then becomes unrepresentable + assert_eq::((u64::MAX - 1023) as f64 as u64, u64::MAX); // rounds up and then becomes unrepresentable assert_eq::(18446744073709551616.0f64 as u64, u64::MAX); assert_eq::(f64::MAX as u64, u64::MAX); assert_eq::(f64::MIN as u64, 0); @@ -258,10 +317,22 @@ fn casts() { assert_eq::((-16777217i32) as f32, -16777216.0); assert_eq::(16777219i32 as f32, 16777220.0); assert_eq::((-16777219i32) as f32, -16777220.0); - assert_eq::(0x7fffff4000000001i64 as f32, /*0x1.fffffep+62*/ f32::from_bits(0x5effffff)); - assert_eq::(0x8000004000000001u64 as i64 as f32, /*-0x1.fffffep+62*/ f32::from_bits(0xdeffffff)); - assert_eq::(0x0020000020000001i64 as f32, /*0x1.000002p+53*/ f32::from_bits(0x5a000001)); - assert_eq::(0xffdfffffdfffffffu64 as i64 as f32, /*-0x1.000002p+53*/ f32::from_bits(0xda000001)); + assert_eq::( + 0x7fffff4000000001i64 as f32, + /*0x1.fffffep+62*/ f32::from_bits(0x5effffff), + ); + assert_eq::( + 0x8000004000000001u64 as i64 as f32, + /*-0x1.fffffep+62*/ f32::from_bits(0xdeffffff), + ); + assert_eq::( + 0x0020000020000001i64 as f32, + /*0x1.000002p+53*/ f32::from_bits(0x5a000001), + ); + assert_eq::( + 0xffdfffffdfffffffu64 as i64 as f32, + /*-0x1.000002p+53*/ f32::from_bits(0xda000001), + ); assert_eq::(i128::MIN as f32, -170141183460469231731687303715884105728.0f32); assert_eq::(u128::MAX as f32, f32::INFINITY); // saturation @@ -284,12 +355,30 @@ fn casts() { assert_eq::((0.0f32 as f64).to_bits(), 0.0f64.to_bits()); assert_eq::(((-0.0f32) as f64).to_bits(), (-0.0f64).to_bits()); assert_eq::(5.0f32 as f64, 5.0f64); - assert_eq::(/*0x1p-149*/ f32::from_bits(0x1) as f64, /*0x1p-149*/ f64::from_bits(0x36a0000000000000)); - assert_eq::(/*-0x1p-149*/ f32::from_bits(0x80000001) as f64, /*-0x1p-149*/ f64::from_bits(0xb6a0000000000000)); - assert_eq::(/*0x1.fffffep+127*/ f32::from_bits(0x7f7fffff) as f64, /*0x1.fffffep+127*/ f64::from_bits(0x47efffffe0000000)); - assert_eq::(/*-0x1.fffffep+127*/ (-f32::from_bits(0x7f7fffff)) as f64, /*-0x1.fffffep+127*/ -f64::from_bits(0x47efffffe0000000)); - assert_eq::(/*0x1p-119*/ f32::from_bits(0x4000000) as f64, /*0x1p-119*/ f64::from_bits(0x3880000000000000)); - assert_eq::(/*0x1.8f867ep+125*/ f32::from_bits(0x7e47c33f) as f64, 6.6382536710104395e+37); + assert_eq::( + /*0x1p-149*/ f32::from_bits(0x1) as f64, + /*0x1p-149*/ f64::from_bits(0x36a0000000000000), + ); + assert_eq::( + /*-0x1p-149*/ f32::from_bits(0x80000001) as f64, + /*-0x1p-149*/ f64::from_bits(0xb6a0000000000000), + ); + assert_eq::( + /*0x1.fffffep+127*/ f32::from_bits(0x7f7fffff) as f64, + /*0x1.fffffep+127*/ f64::from_bits(0x47efffffe0000000), + ); + assert_eq::( + /*-0x1.fffffep+127*/ (-f32::from_bits(0x7f7fffff)) as f64, + /*-0x1.fffffep+127*/ -f64::from_bits(0x47efffffe0000000), + ); + assert_eq::( + /*0x1p-119*/ f32::from_bits(0x4000000) as f64, + /*0x1p-119*/ f64::from_bits(0x3880000000000000), + ); + assert_eq::( + /*0x1.8f867ep+125*/ f32::from_bits(0x7e47c33f) as f64, + 6.6382536710104395e+37, + ); assert_eq::(f32::INFINITY as f64, f64::INFINITY); assert_eq::(f32::NEG_INFINITY as f64, f64::NEG_INFINITY); @@ -299,8 +388,14 @@ fn casts() { assert_eq::(5.0f64 as f32, 5.0f32); assert_eq::(/*0x0.0000000000001p-1022*/ f64::from_bits(0x1) as f32, 0.0); assert_eq::(/*-0x0.0000000000001p-1022*/ (-f64::from_bits(0x1)) as f32, -0.0); - assert_eq::(/*0x1.fffffe0000000p-127*/ f64::from_bits(0x380fffffe0000000) as f32, /*0x1p-149*/ f32::from_bits(0x800000)); - assert_eq::(/*0x1.4eae4f7024c7p+108*/ f64::from_bits(0x46b4eae4f7024c70) as f32, /*0x1.4eae5p+108*/ f32::from_bits(0x75a75728)); + assert_eq::( + /*0x1.fffffe0000000p-127*/ f64::from_bits(0x380fffffe0000000) as f32, + /*0x1p-149*/ f32::from_bits(0x800000), + ); + assert_eq::( + /*0x1.4eae4f7024c7p+108*/ f64::from_bits(0x46b4eae4f7024c70) as f32, + /*0x1.4eae5p+108*/ f32::from_bits(0x75a75728), + ); assert_eq::(f64::MAX as f32, f32::INFINITY); assert_eq::(f64::MIN as f32, f32::NEG_INFINITY); assert_eq::(f64::INFINITY as f32, f32::INFINITY); diff --git a/tests/pass/float_fast_math.rs b/tests/pass/float_fast_math.rs index 8e5a88ff336a2..52d985667df2d 100644 --- a/tests/pass/float_fast_math.rs +++ b/tests/pass/float_fast_math.rs @@ -1,6 +1,6 @@ #![feature(core_intrinsics)] -use std::intrinsics::{fadd_fast, fsub_fast, fmul_fast, fdiv_fast, frem_fast}; +use std::intrinsics::{fadd_fast, fdiv_fast, fmul_fast, frem_fast, fsub_fast}; #[inline(never)] pub fn test_operations_f64(a: f64, b: f64) { diff --git a/tests/pass/foreign-fn-linkname.rs b/tests/pass/foreign-fn-linkname.rs index 60303c7d7c7c7..391b182fda03c 100644 --- a/tests/pass/foreign-fn-linkname.rs +++ b/tests/pass/foreign-fn-linkname.rs @@ -7,7 +7,7 @@ use std::ffi::CString; mod mlibc { use libc::{c_char, size_t}; - extern { + extern "C" { #[link_name = "strlen"] pub fn my_strlen(str: *const c_char) -> size_t; } @@ -16,9 +16,7 @@ mod mlibc { fn strlen(str: String) -> usize { // C string is terminated with a zero let s = CString::new(str).unwrap(); - unsafe { - mlibc::my_strlen(s.as_ptr()) as usize - } + unsafe { mlibc::my_strlen(s.as_ptr()) as usize } } pub fn main() { diff --git a/tests/pass/fs_with_isolation.rs b/tests/pass/fs_with_isolation.rs index cd91cd9be30e7..6753145e92b29 100644 --- a/tests/pass/fs_with_isolation.rs +++ b/tests/pass/fs_with_isolation.rs @@ -7,9 +7,9 @@ extern crate libc; use std::ffi::CString; -use std::os::unix; use std::fs::{self, File}; use std::io::{Error, ErrorKind}; +use std::os::unix; fn main() { // test `open` @@ -25,7 +25,10 @@ fn main() { assert_eq!(fs::remove_file("foo.txt").unwrap_err().kind(), ErrorKind::PermissionDenied); // test `symlink` - assert_eq!(unix::fs::symlink("foo.txt", "foo_link.txt").unwrap_err().kind(), ErrorKind::PermissionDenied); + assert_eq!( + unix::fs::symlink("foo.txt", "foo_link.txt").unwrap_err().kind(), + ErrorKind::PermissionDenied + ); // test `readlink` let symlink_c_str = CString::new("foo.txt").unwrap(); diff --git a/tests/pass/function_calls/exported_symbol.rs b/tests/pass/function_calls/exported_symbol.rs index ff56bb78a2187..27aee9c883588 100644 --- a/tests/pass/function_calls/exported_symbol.rs +++ b/tests/pass/function_calls/exported_symbol.rs @@ -24,7 +24,6 @@ impl AssocFn { } } - fn main() { // Repeat calls to make sure the `Instance` cache is not broken. for _ in 0..3 { @@ -69,9 +68,8 @@ fn main() { } unsafe { - let transmute = |f| { - std::mem::transmute:: i32, unsafe fn() -> i32>(f) - }; + let transmute = + |f| std::mem::transmute:: i32, unsafe fn() -> i32>(f); assert_eq!(transmute(bar)(), -2); assert_eq!(transmute(baz)(), -3); assert_eq!(transmute(qux)(), -4); diff --git a/tests/pass/function_pointers.rs b/tests/pass/function_pointers.rs index e7d9b2ddd98ca..b66826e3fcdfb 100644 --- a/tests/pass/function_pointers.rs +++ b/tests/pass/function_pointers.rs @@ -16,7 +16,7 @@ fn f() -> T { } fn g(i: i32) -> i32 { - i*42 + i * 42 } fn h(i: i32, j: i32) -> i32 { @@ -31,17 +31,35 @@ fn call_fn_ptr() -> i32 { return_fn_ptr(f)() } -fn indirect i32>(f: F) -> i32 { f() } -fn indirect_mut i32>(mut f: F) -> i32 { f() } -fn indirect_once i32>(f: F) -> i32 { f() } +fn indirect i32>(f: F) -> i32 { + f() +} +fn indirect_mut i32>(mut f: F) -> i32 { + f() +} +fn indirect_once i32>(f: F) -> i32 { + f() +} -fn indirect2 i32>(f: F) -> i32 { f(10) } -fn indirect_mut2 i32>(mut f: F) -> i32 { f(10) } -fn indirect_once2 i32>(f: F) -> i32 { f(10) } +fn indirect2 i32>(f: F) -> i32 { + f(10) +} +fn indirect_mut2 i32>(mut f: F) -> i32 { + f(10) +} +fn indirect_once2 i32>(f: F) -> i32 { + f(10) +} -fn indirect3 i32>(f: F) -> i32 { f(10, 3) } -fn indirect_mut3 i32>(mut f: F) -> i32 { f(10, 3) } -fn indirect_once3 i32>(f: F) -> i32 { f(10, 3) } +fn indirect3 i32>(f: F) -> i32 { + f(10, 3) +} +fn indirect_mut3 i32>(mut f: F) -> i32 { + f(10, 3) +} +fn indirect_once3 i32>(f: F) -> i32 { + f(10, 3) +} fn main() { assert_eq!(call_fn_ptr(), 42); From fafeccaef73bfd1fe9e1f9ab49f0dc050d6fd54c Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Mon, 20 Jun 2022 15:39:27 -0700 Subject: [PATCH 3272/3747] Bless stdout files after rustfmt --- tests/pass/backtrace/backtrace-api-v0.stdout | 10 +++++----- tests/pass/backtrace/backtrace-api-v1.stdout | 10 +++++----- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/tests/pass/backtrace/backtrace-api-v0.stdout b/tests/pass/backtrace/backtrace-api-v0.stdout index 9de1d034bb73b..2fe31dd0e6bae 100644 --- a/tests/pass/backtrace/backtrace-api-v0.stdout +++ b/tests/pass/backtrace/backtrace-api-v0.stdout @@ -1,5 +1,5 @@ -$DIR/backtrace-api-v0.rs:11:59 (func_d) -$DIR/backtrace-api-v0.rs:10:50 (func_c) -$DIR/backtrace-api-v0.rs:4:53 (func_b) -$DIR/backtrace-api-v0.rs:3:50 (func_a) -$DIR/backtrace-api-v0.rs:15:18 (main) +$DIR/backtrace-api-v0.rs:24:14 (func_d) +$DIR/backtrace-api-v0.rs:20:5 (func_c) +$DIR/backtrace-api-v0.rs:9:5 (func_b) +$DIR/backtrace-api-v0.rs:5:5 (func_a) +$DIR/backtrace-api-v0.rs:29:18 (main) diff --git a/tests/pass/backtrace/backtrace-api-v1.stdout b/tests/pass/backtrace/backtrace-api-v1.stdout index b820a1be0a199..0d2ae3b516a87 100644 --- a/tests/pass/backtrace/backtrace-api-v1.stdout +++ b/tests/pass/backtrace/backtrace-api-v1.stdout @@ -1,5 +1,5 @@ -$DIR/backtrace-api-v1.rs:11:144 (func_d) -$DIR/backtrace-api-v1.rs:10:50 (func_c) -$DIR/backtrace-api-v1.rs:4:53 (func_b) -$DIR/backtrace-api-v1.rs:3:50 (func_a) -$DIR/backtrace-api-v1.rs:15:18 (main) +$DIR/backtrace-api-v1.rs:27:9 (func_d) +$DIR/backtrace-api-v1.rs:20:5 (func_c) +$DIR/backtrace-api-v1.rs:9:5 (func_b) +$DIR/backtrace-api-v1.rs:5:5 (func_a) +$DIR/backtrace-api-v1.rs:34:18 (main) From df8d8b655b9ff5c1a941697119cc7fac41e77321 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Mon, 20 Jun 2022 16:00:37 -0700 Subject: [PATCH 3273/3747] Format tests with rustfmt (101-150 of 300) --- tests/pass/generator.rs | 30 +++++-- tests/pass/hashmap.rs | 8 +- tests/pass/integer-ops.rs | 10 +-- tests/pass/intrinsics-math.rs | 9 +- tests/pass/intrinsics.rs | 10 ++- tests/pass/ints.rs | 4 +- tests/pass/issues/issue-15063.rs | 8 +- tests/pass/issues/issue-15080.rs | 5 +- tests/pass/issues/issue-15523-big.rs | 1 - tests/pass/issues/issue-17877.rs | 22 +++-- tests/pass/issues/issue-23261.rs | 2 +- tests/pass/issues/issue-27901.rs | 8 +- tests/pass/issues/issue-29746.rs | 10 +-- tests/pass/issues/issue-30530.rs | 3 +- tests/pass/issues/issue-34571.rs | 2 +- .../pass/issues/issue-36278-prefix-nesting.rs | 5 +- tests/pass/issues/issue-5917.rs | 7 +- tests/pass/issues/issue-miri-133.rs | 9 +- tests/pass/issues/issue-miri-2068-2.rs | 22 ++--- tests/pass/last-use-in-cap-clause.rs | 8 +- tests/pass/leak-in-static.rs | 5 +- tests/pass/libc.rs | 86 +++++++++++++------ tests/pass/linked-list.rs | 3 +- .../pass/linux-getrandom-without-isolation.rs | 34 +++++++- tests/pass/linux-getrandom.rs | 34 +++++++- tests/pass/loop-break-value.rs | 20 ++--- tests/pass/malloc.rs | 2 +- tests/pass/many_shr_bor.rs | 2 +- tests/pass/match_slice.rs | 6 +- tests/pass/move-arg-2-unique.rs | 4 +- tests/pass/move-uninit-primval.rs | 4 +- tests/pass/negative_discriminant.rs | 5 +- tests/pass/overflow_checks_off.rs | 2 +- tests/pass/overloaded-calls-simple.rs | 10 +-- tests/pass/packed_struct.rs | 34 ++++---- tests/pass/partially-uninit.rs | 16 ++-- tests/pass/pointers.rs | 7 +- tests/pass/portable-simd.rs | 16 ++-- tests/pass/products.rs | 7 +- tests/pass/ptr_offset.rs | 30 ++++--- tests/pass/ptr_raw.rs | 8 +- tests/pass/rc.rs | 10 +-- tests/pass/regions-mock-trans.rs | 19 ++-- tests/pass/send-is-not-static-par-for.rs | 15 ++-- tests/pass/sendable-class.rs | 7 +- tests/pass/simd-intrinsic-generic-elements.rs | 4 +- tests/pass/slices.rs | 35 ++++---- tests/pass/specialization.rs | 8 +- tests/pass/stacked-borrows/2phase.rs | 34 ++++---- .../stacked-borrows/interior_mutability.rs | 18 ++-- 50 files changed, 395 insertions(+), 273 deletions(-) diff --git a/tests/pass/generator.rs b/tests/pass/generator.rs index 9d786edc5ae2c..06f48666c557f 100644 --- a/tests/pass/generator.rs +++ b/tests/pass/generator.rs @@ -1,15 +1,19 @@ #![feature(generators, generator_trait, never_type)] -use std::ops::{GeneratorState::{self, *}, Generator}; -use std::pin::Pin; -use std::sync::atomic::{AtomicUsize, Ordering}; use std::fmt::Debug; use std::mem::ManuallyDrop; +use std::ops::{ + Generator, + GeneratorState::{self, *}, +}; +use std::pin::Pin; use std::ptr; +use std::sync::atomic::{AtomicUsize, Ordering}; fn basic() { fn finish(mut amt: usize, mut t: T) -> T::Return - where T: Generator + where + T: Generator, { // We are not moving the `t` around until it gets dropped, so this is okay. let mut t = unsafe { Pin::new_unchecked(&mut t) }; @@ -23,7 +27,7 @@ fn basic() { } GeneratorState::Complete(ret) => { assert_eq!(amt, 0); - return ret + return ret; } } } @@ -46,7 +50,7 @@ fn basic() { assert_eq!(x, 2); }); - finish(7*8/2, || { + finish(7 * 8 / 2, || { for i in 0..8 { yield i; } @@ -67,7 +71,10 @@ fn basic() { }); finish(2, || { - if { yield 1; false } { + if { + yield 1; + false + } { yield 1; panic!() } @@ -90,7 +97,9 @@ fn basic() { let b = true; finish(1, || { yield 1; - if b { return; } + if b { + return; + } #[allow(unused)] let x = never(); #[allow(unreachable_code)] @@ -101,7 +110,10 @@ fn basic() { finish(3, || { yield 1; #[allow(unreachable_code)] - let _x: (String, !) = (String::new(), { yield 2; return }); + let _x: (String, !) = (String::new(), { + yield 2; + return; + }); }); } diff --git a/tests/pass/hashmap.rs b/tests/pass/hashmap.rs index 215f762efcc98..29ddd6c59a1a6 100644 --- a/tests/pass/hashmap.rs +++ b/tests/pass/hashmap.rs @@ -17,19 +17,19 @@ fn test_all_refs<'a, T: 'a>(dummy: &mut T, iter: impl Iterator fn smoketest_map(mut map: HashMap) { map.insert(0, 0); - assert_eq!(map.values().fold(0, |x, y| x+y), 0); + assert_eq!(map.values().fold(0, |x, y| x + y), 0); let num = 25; for i in 1..num { map.insert(i, i); } - assert_eq!(map.values().fold(0, |x, y| x+y), num*(num-1)/2); // check the right things are in the table now + assert_eq!(map.values().fold(0, |x, y| x + y), num * (num - 1) / 2); // check the right things are in the table now // Inserting again replaces the existing entries for i in 0..num { - map.insert(i, num-1-i); + map.insert(i, num - 1 - i); } - assert_eq!(map.values().fold(0, |x, y| x+y), num*(num-1)/2); + assert_eq!(map.values().fold(0, |x, y| x + y), num * (num - 1) / 2); test_all_refs(&mut 13, map.values_mut()); } diff --git a/tests/pass/integer-ops.rs b/tests/pass/integer-ops.rs index 764b2dca82caa..8e2799d689056 100644 --- a/tests/pass/integer-ops.rs +++ b/tests/pass/integer-ops.rs @@ -42,7 +42,7 @@ pub fn main() { let m = -0xFEDCBA987654322i64; assert_eq!(n.rotate_right(4), m); - let n = 0x0123456789ABCDEFi64; + let n = 0x0123456789ABCDEFi64; let m = -0x1032547698BADCFFi64; assert_eq!(n.swap_bytes(), m); @@ -169,9 +169,9 @@ pub fn main() { assert_eq!(0x10i32.overflowing_shr(4), (0x1, false)); assert_eq!(0x10i32.overflowing_shr(36), (0x1, true)); - assert_eq!(10i8.overflowing_abs(), (10,false)); - assert_eq!((-10i8).overflowing_abs(), (10,false)); - assert_eq!((-128i8).overflowing_abs(), (-128,true)); + assert_eq!(10i8.overflowing_abs(), (10, false)); + assert_eq!((-10i8).overflowing_abs(), (10, false)); + assert_eq!((-128i8).overflowing_abs(), (-128, true)); // Logarithms macro_rules! test_log { @@ -180,7 +180,7 @@ pub fn main() { assert_eq!($type::MIN.checked_log10(), None); assert_eq!($type::MAX.checked_log2(), Some($max_log2)); assert_eq!($type::MAX.checked_log10(), Some($max_log10)); - } + }; } test_log!(i8, 6, 2); diff --git a/tests/pass/intrinsics-math.rs b/tests/pass/intrinsics-math.rs index 98cb87ee93422..0cb42580fcb2c 100644 --- a/tests/pass/intrinsics-math.rs +++ b/tests/pass/intrinsics-math.rs @@ -9,15 +9,14 @@ // except according to those terms. macro_rules! assert_approx_eq { - ($a:expr, $b:expr) => ({ + ($a:expr, $b:expr) => {{ let (a, b) = (&$a, &$b); - assert!((*a - *b).abs() < 1.0e-6, - "{} is not approximately equal to {}", *a, *b); - }) + assert!((*a - *b).abs() < 1.0e-6, "{} is not approximately equal to {}", *a, *b); + }}; } fn ldexp(a: f64, b: i32) -> f64 { - extern { + extern "C" { fn ldexp(x: f64, n: i32) -> f64; } unsafe { ldexp(a, b) } diff --git a/tests/pass/intrinsics.rs b/tests/pass/intrinsics.rs index 6885641c02ea0..9e310082f3590 100644 --- a/tests/pass/intrinsics.rs +++ b/tests/pass/intrinsics.rs @@ -20,8 +20,12 @@ fn main() { assert_eq!(size_of_val(&[1, 2, 3] as &[i32]), 12); assert_eq!(size_of_val("foobar"), 6); - unsafe { assert_eq!(size_of_val_raw(&[1] as &[i32] as *const [i32]), 4); } - unsafe { assert_eq!(size_of_val_raw(0x100 as *const i32), 4); } + unsafe { + assert_eq!(size_of_val_raw(&[1] as &[i32] as *const [i32]), 4); + } + unsafe { + assert_eq!(size_of_val_raw(0x100 as *const i32), 4); + } assert_eq!(intrinsics::type_name::>(), "core::option::Option"); @@ -33,7 +37,7 @@ fn main() { let _v = intrinsics::discriminant_value(&Some(())); let _v = intrinsics::discriminant_value(&0); let _v = intrinsics::discriminant_value(&true); - let _v = intrinsics::discriminant_value(&vec![1,2,3]); + let _v = intrinsics::discriminant_value(&vec![1, 2, 3]); let addr = &13 as *const i32; let addr2 = (addr as usize).wrapping_add(usize::MAX).wrapping_add(1); diff --git a/tests/pass/ints.rs b/tests/pass/ints.rs index 5d7c383088dee..c04c6921f3c42 100644 --- a/tests/pass/ints.rs +++ b/tests/pass/ints.rs @@ -17,7 +17,7 @@ fn indirect_add() -> i64 { } fn arith() -> i32 { - 3*3 + 4*4 + 3 * 3 + 4 * 4 } fn match_int() -> i16 { @@ -48,7 +48,7 @@ fn main() { assert_eq!(neg(), -1); assert_eq!(add(), 3); assert_eq!(indirect_add(), 3); - assert_eq!(arith(), 5*5); + assert_eq!(arith(), 5 * 5); assert_eq!(match_int(), 20); assert_eq!(match_int_range(), 4); assert_eq!(i64::MIN.overflowing_mul(-1), (i64::MIN, true)); diff --git a/tests/pass/issues/issue-15063.rs b/tests/pass/issues/issue-15063.rs index c85590bb8b4bd..cbb1b90f68629 100644 --- a/tests/pass/issues/issue-15063.rs +++ b/tests/pass/issues/issue-15063.rs @@ -1,8 +1,10 @@ #[allow(dead_code)] -enum Two { A, B } +enum Two { + A, + B, +} impl Drop for Two { - fn drop(&mut self) { - } + fn drop(&mut self) {} } fn main() { let _k = Two::A; diff --git a/tests/pass/issues/issue-15080.rs b/tests/pass/issues/issue-15080.rs index 2008e6e157db8..4a360993116c3 100644 --- a/tests/pass/issues/issue-15080.rs +++ b/tests/pass/issues/issue-15080.rs @@ -1,7 +1,7 @@ fn main() { let mut x: &[_] = &[1, 2, 3, 4]; - let mut result = vec!(); + let mut result = vec![]; loop { x = match *x { [1, n, 3, ref rest @ ..] => { @@ -12,8 +12,7 @@ fn main() { result.push(n); rest } - [] => - break + [] => break, } } assert_eq!(result, [2, 4]); diff --git a/tests/pass/issues/issue-15523-big.rs b/tests/pass/issues/issue-15523-big.rs index 75fd8d8dfce8f..7c9fec3ab04b0 100644 --- a/tests/pass/issues/issue-15523-big.rs +++ b/tests/pass/issues/issue-15523-big.rs @@ -27,7 +27,6 @@ fn main() { assert!(Eu64::Pos2 < Eu64::PosMax); assert!(Eu64::Pos1 < Eu64::PosMax); - assert!(Ei64::Pos2 > Ei64::Pos1); assert!(Ei64::Pos2 > Ei64::Neg1); assert!(Ei64::Pos1 > Ei64::Neg1); diff --git a/tests/pass/issues/issue-17877.rs b/tests/pass/issues/issue-17877.rs index fa24ab9f4aae8..a65c5513de004 100644 --- a/tests/pass/issues/issue-17877.rs +++ b/tests/pass/issues/issue-17877.rs @@ -1,11 +1,17 @@ fn main() { - assert_eq!(match [0u8; 16*1024] { - _ => 42_usize, - }, 42_usize); + assert_eq!( + match [0u8; 16 * 1024] { + _ => 42_usize, + }, + 42_usize + ); - assert_eq!(match [0u8; 16*1024] { - [1, ..] => 0_usize, - [0, ..] => 1_usize, - _ => 2_usize - }, 1_usize); + assert_eq!( + match [0u8; 16 * 1024] { + [1, ..] => 0_usize, + [0, ..] => 1_usize, + _ => 2_usize, + }, + 1_usize + ); } diff --git a/tests/pass/issues/issue-23261.rs b/tests/pass/issues/issue-23261.rs index f3c2f58ddbca1..f98252c18bf5c 100644 --- a/tests/pass/issues/issue-23261.rs +++ b/tests/pass/issues/issue-23261.rs @@ -2,7 +2,7 @@ struct Foo { a: i32, - inner: T + inner: T, } trait Get { diff --git a/tests/pass/issues/issue-27901.rs b/tests/pass/issues/issue-27901.rs index b0822accb6b6b..a9f5dc98720fc 100644 --- a/tests/pass/issues/issue-27901.rs +++ b/tests/pass/issues/issue-27901.rs @@ -1,5 +1,9 @@ -trait Stream { type Item; } -impl<'a> Stream for &'a str { type Item = u8; } +trait Stream { + type Item; +} +impl<'a> Stream for &'a str { + type Item = u8; +} fn f<'s>(s: &'s str) -> (&'s str, <&'s str as Stream>::Item) { (s, 42) } diff --git a/tests/pass/issues/issue-29746.rs b/tests/pass/issues/issue-29746.rs index d04703d6877c8..43bed4464b9c8 100644 --- a/tests/pass/issues/issue-29746.rs +++ b/tests/pass/issues/issue-29746.rs @@ -25,11 +25,11 @@ macro_rules! zip { } fn main() { - let p1 = vec![1i32, 2].into_iter(); - let p2 = vec!["10", "20"].into_iter(); - let p3 = vec![100u16, 200].into_iter(); + let p1 = vec![1i32, 2].into_iter(); + let p2 = vec!["10", "20"].into_iter(); + let p3 = vec![100u16, 200].into_iter(); let p4 = vec![1000i64, 2000].into_iter(); - let e = zip!([p1,p2,p3,p4]).collect::>(); - assert_eq!(e[0], (1i32,"10",100u16,1000i64)); + let e = zip!([p1, p2, p3, p4]).collect::>(); + assert_eq!(e[0], (1i32, "10", 100u16, 1000i64)); } diff --git a/tests/pass/issues/issue-30530.rs b/tests/pass/issues/issue-30530.rs index 86c2d9184e016..472b42adaac85 100644 --- a/tests/pass/issues/issue-30530.rs +++ b/tests/pass/issues/issue-30530.rs @@ -21,7 +21,8 @@ pub enum Handler { } fn main() { - #[allow(unused_must_use)] { + #[allow(unused_must_use)] + { take(Handler::Default, Box::new(main)); } } diff --git a/tests/pass/issues/issue-34571.rs b/tests/pass/issues/issue-34571.rs index 28fe076b644d4..e1ed8d19e4ea6 100644 --- a/tests/pass/issues/issue-34571.rs +++ b/tests/pass/issues/issue-34571.rs @@ -5,6 +5,6 @@ enum Foo { fn main() { match Foo::Foo(1) { - _ => () + _ => (), } } diff --git a/tests/pass/issues/issue-36278-prefix-nesting.rs b/tests/pass/issues/issue-36278-prefix-nesting.rs index cbffbbc0e0f86..6bc8f02c3bafb 100644 --- a/tests/pass/issues/issue-36278-prefix-nesting.rs +++ b/tests/pass/issues/issue-36278-prefix-nesting.rs @@ -9,11 +9,12 @@ struct P([u8; SZ], T); type Ack = P>; fn main() { - let size_of_sized; let size_of_unsized; + let size_of_sized; + let size_of_unsized; let x: Box> = Box::new(P([0; SZ], P([0; SZ], [0; 0]))); size_of_sized = mem::size_of_val::>(&x); let align_of_sized = mem::align_of_val::>(&x); - let y: Box> = x; + let y: Box> = x; size_of_unsized = mem::size_of_val::>(&y); assert_eq!(size_of_sized, size_of_unsized); assert_eq!(align_of_sized, 1); diff --git a/tests/pass/issues/issue-5917.rs b/tests/pass/issues/issue-5917.rs index eb506dd3a17eb..f7bbb4350e2be 100644 --- a/tests/pass/issues/issue-5917.rs +++ b/tests/pass/issues/issue-5917.rs @@ -1,7 +1,6 @@ - -struct T (&'static [isize]); -static STATIC : T = T (&[5, 4, 3]); -pub fn main () { +struct T(&'static [isize]); +static STATIC: T = T(&[5, 4, 3]); +pub fn main() { let T(ref v) = STATIC; assert_eq!(v[0], 5); } diff --git a/tests/pass/issues/issue-miri-133.rs b/tests/pass/issues/issue-miri-133.rs index 406b5e102c8b4..02c9732571330 100644 --- a/tests/pass/issues/issue-miri-133.rs +++ b/tests/pass/issues/issue-miri-133.rs @@ -4,17 +4,12 @@ struct S { _u: U, size_of_u: usize, _v: V, - size_of_v: usize + size_of_v: usize, } impl S { fn new(u: U, v: V) -> Self { - S { - _u: u, - size_of_u: size_of::(), - _v: v, - size_of_v: size_of::() - } + S { _u: u, size_of_u: size_of::(), _v: v, size_of_v: size_of::() } } } diff --git a/tests/pass/issues/issue-miri-2068-2.rs b/tests/pass/issues/issue-miri-2068-2.rs index 45b2004e33538..204a4dd05642d 100644 --- a/tests/pass/issues/issue-miri-2068-2.rs +++ b/tests/pass/issues/issue-miri-2068-2.rs @@ -2,13 +2,15 @@ use std::mem::MaybeUninit; -fn main() { unsafe { - let mut x = MaybeUninit::::uninit(); - // Put in a ptr. - x.as_mut_ptr().cast::<&i32>().write_unaligned(&0); - // Overwrite parts of that pointer with 'uninit' through a Scalar. - let ptr = x.as_mut_ptr().cast::(); - *ptr = MaybeUninit::uninit().assume_init(); - // Reading this back should hence work fine. - let _c = *ptr; -} } +fn main() { + unsafe { + let mut x = MaybeUninit::::uninit(); + // Put in a ptr. + x.as_mut_ptr().cast::<&i32>().write_unaligned(&0); + // Overwrite parts of that pointer with 'uninit' through a Scalar. + let ptr = x.as_mut_ptr().cast::(); + *ptr = MaybeUninit::uninit().assume_init(); + // Reading this back should hence work fine. + let _c = *ptr; + } +} diff --git a/tests/pass/last-use-in-cap-clause.rs b/tests/pass/last-use-in-cap-clause.rs index 9d137f706bd33..2160aea16346f 100644 --- a/tests/pass/last-use-in-cap-clause.rs +++ b/tests/pass/last-use-in-cap-clause.rs @@ -1,12 +1,14 @@ // Make sure #1399 stays fixed #[allow(dead_code)] -struct A { a: Box } +struct A { + a: Box, +} fn foo() -> Box isize + 'static> { let k: Box<_> = Box::new(22); - let _u = A {a: k.clone()}; - let result = || 22; + let _u = A { a: k.clone() }; + let result = || 22; Box::new(result) } diff --git a/tests/pass/leak-in-static.rs b/tests/pass/leak-in-static.rs index a20577125e73f..9523394408806 100644 --- a/tests/pass/leak-in-static.rs +++ b/tests/pass/leak-in-static.rs @@ -1,4 +1,7 @@ -use std::{ptr, sync::atomic::{AtomicPtr, Ordering}}; +use std::{ + ptr, + sync::atomic::{AtomicPtr, Ordering}, +}; static mut LEAKER: Option>> = None; diff --git a/tests/pass/libc.rs b/tests/pass/libc.rs index bf5ae98290118..5991fae5bb1e6 100644 --- a/tests/pass/libc.rs +++ b/tests/pass/libc.rs @@ -7,7 +7,9 @@ extern crate libc; #[cfg(target_os = "linux")] fn tmp() -> std::path::PathBuf { - std::env::var("MIRI_TEMP").map(std::path::PathBuf::from).unwrap_or_else(|_| std::env::temp_dir()) + std::env::var("MIRI_TEMP") + .map(std::path::PathBuf::from) + .unwrap_or_else(|_| std::env::temp_dir()) } #[cfg(target_os = "linux")] @@ -91,7 +93,10 @@ fn test_mutex_libc_init_recursive() { unsafe { let mut attr: libc::pthread_mutexattr_t = std::mem::zeroed(); assert_eq!(libc::pthread_mutexattr_init(&mut attr as *mut _), 0); - assert_eq!(libc::pthread_mutexattr_settype(&mut attr as *mut _, libc::PTHREAD_MUTEX_RECURSIVE), 0); + assert_eq!( + libc::pthread_mutexattr_settype(&mut attr as *mut _, libc::PTHREAD_MUTEX_RECURSIVE), + 0 + ); let mut mutex: libc::pthread_mutex_t = std::mem::zeroed(); assert_eq!(libc::pthread_mutex_init(&mut mutex as *mut _, &mut attr as *mut _), 0); assert_eq!(libc::pthread_mutex_lock(&mut mutex as *mut _), 0); @@ -111,8 +116,14 @@ fn test_mutex_libc_init_recursive() { fn test_mutex_libc_init_normal() { unsafe { let mut mutexattr: libc::pthread_mutexattr_t = std::mem::zeroed(); - assert_eq!(libc::pthread_mutexattr_settype(&mut mutexattr as *mut _, 0x12345678), libc::EINVAL); - assert_eq!(libc::pthread_mutexattr_settype(&mut mutexattr as *mut _, libc::PTHREAD_MUTEX_NORMAL), 0); + assert_eq!( + libc::pthread_mutexattr_settype(&mut mutexattr as *mut _, 0x12345678), + libc::EINVAL + ); + assert_eq!( + libc::pthread_mutexattr_settype(&mut mutexattr as *mut _, libc::PTHREAD_MUTEX_NORMAL), + 0 + ); let mut mutex: libc::pthread_mutex_t = std::mem::zeroed(); assert_eq!(libc::pthread_mutex_init(&mut mutex as *mut _, &mutexattr as *const _), 0); assert_eq!(libc::pthread_mutex_lock(&mut mutex as *mut _), 0); @@ -127,7 +138,13 @@ fn test_mutex_libc_init_normal() { fn test_mutex_libc_init_errorcheck() { unsafe { let mut mutexattr: libc::pthread_mutexattr_t = std::mem::zeroed(); - assert_eq!(libc::pthread_mutexattr_settype(&mut mutexattr as *mut _, libc::PTHREAD_MUTEX_ERRORCHECK), 0); + assert_eq!( + libc::pthread_mutexattr_settype( + &mut mutexattr as *mut _, + libc::PTHREAD_MUTEX_ERRORCHECK + ), + 0 + ); let mut mutex: libc::pthread_mutex_t = std::mem::zeroed(); assert_eq!(libc::pthread_mutex_init(&mut mutex as *mut _, &mutexattr as *const _), 0); assert_eq!(libc::pthread_mutex_lock(&mut mutex as *mut _), 0); @@ -193,21 +210,48 @@ fn test_rwlock_libc_static_initializer() { /// Note: `prctl` exists only on Linux. #[cfg(target_os = "linux")] fn test_prctl_thread_name() { - use std::ffi::CString; use libc::c_long; + use std::ffi::CString; unsafe { let mut buf = [255; 10]; - assert_eq!(libc::prctl(libc::PR_GET_NAME, buf.as_mut_ptr(), 0 as c_long, 0 as c_long, 0 as c_long), 0); + assert_eq!( + libc::prctl(libc::PR_GET_NAME, buf.as_mut_ptr(), 0 as c_long, 0 as c_long, 0 as c_long), + 0 + ); assert_eq!(b"\0", &buf); let thread_name = CString::new("hello").expect("CString::new failed"); - assert_eq!(libc::prctl(libc::PR_SET_NAME, thread_name.as_ptr(), 0 as c_long, 0 as c_long, 0 as c_long), 0); + assert_eq!( + libc::prctl( + libc::PR_SET_NAME, + thread_name.as_ptr(), + 0 as c_long, + 0 as c_long, + 0 as c_long + ), + 0 + ); let mut buf = [255; 6]; - assert_eq!(libc::prctl(libc::PR_GET_NAME, buf.as_mut_ptr(), 0 as c_long, 0 as c_long, 0 as c_long), 0); + assert_eq!( + libc::prctl(libc::PR_GET_NAME, buf.as_mut_ptr(), 0 as c_long, 0 as c_long, 0 as c_long), + 0 + ); assert_eq!(b"hello\0", &buf); let long_thread_name = CString::new("01234567890123456789").expect("CString::new failed"); - assert_eq!(libc::prctl(libc::PR_SET_NAME, long_thread_name.as_ptr(), 0 as c_long, 0 as c_long, 0 as c_long), 0); + assert_eq!( + libc::prctl( + libc::PR_SET_NAME, + long_thread_name.as_ptr(), + 0 as c_long, + 0 as c_long, + 0 as c_long + ), + 0 + ); let mut buf = [255; 16]; - assert_eq!(libc::prctl(libc::PR_GET_NAME, buf.as_mut_ptr(), 0 as c_long, 0 as c_long, 0 as c_long), 0); + assert_eq!( + libc::prctl(libc::PR_GET_NAME, buf.as_mut_ptr(), 0 as c_long, 0 as c_long, 0 as c_long), + 0 + ); assert_eq!(b"012345678901234\0", &buf); } } @@ -225,7 +269,9 @@ fn test_thread_local_errno() { assert_eq!(*__errno_location(), 0); *__errno_location() = 0xBAD1DEA; assert_eq!(*__errno_location(), 0xBAD1DEA); - }).join().unwrap(); + }) + .join() + .unwrap(); assert_eq!(*__errno_location(), 0xBEEF); } } @@ -234,21 +280,13 @@ fn test_thread_local_errno() { #[cfg(target_os = "linux")] fn test_clocks() { let mut tp = std::mem::MaybeUninit::::uninit(); - let is_error = unsafe { - libc::clock_gettime(libc::CLOCK_REALTIME, tp.as_mut_ptr()) - }; + let is_error = unsafe { libc::clock_gettime(libc::CLOCK_REALTIME, tp.as_mut_ptr()) }; assert_eq!(is_error, 0); - let is_error = unsafe { - libc::clock_gettime(libc::CLOCK_REALTIME_COARSE, tp.as_mut_ptr()) - }; + let is_error = unsafe { libc::clock_gettime(libc::CLOCK_REALTIME_COARSE, tp.as_mut_ptr()) }; assert_eq!(is_error, 0); - let is_error = unsafe { - libc::clock_gettime(libc::CLOCK_MONOTONIC, tp.as_mut_ptr()) - }; + let is_error = unsafe { libc::clock_gettime(libc::CLOCK_MONOTONIC, tp.as_mut_ptr()) }; assert_eq!(is_error, 0); - let is_error = unsafe { - libc::clock_gettime(libc::CLOCK_MONOTONIC_COARSE, tp.as_mut_ptr()) - }; + let is_error = unsafe { libc::clock_gettime(libc::CLOCK_MONOTONIC_COARSE, tp.as_mut_ptr()) }; assert_eq!(is_error, 0); } diff --git a/tests/pass/linked-list.rs b/tests/pass/linked-list.rs index 0ed9d6032d0e5..7377f9f60b01e 100644 --- a/tests/pass/linked-list.rs +++ b/tests/pass/linked-list.rs @@ -45,8 +45,7 @@ fn main() { assert_eq!(m.len(), 3 + len * 2); let mut m2 = m.clone(); - assert_eq!(m.into_iter().collect::>(), - [-10, -2, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 99]); + assert_eq!(m.into_iter().collect::>(), [-10, -2, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 99]); test_all_refs(&mut 13, m2.iter_mut()); } diff --git a/tests/pass/linux-getrandom-without-isolation.rs b/tests/pass/linux-getrandom-without-isolation.rs index e08d4466a7bf7..a88db57cc09d5 100644 --- a/tests/pass/linux-getrandom-without-isolation.rs +++ b/tests/pass/linux-getrandom-without-isolation.rs @@ -6,10 +6,36 @@ extern crate libc; fn main() { let mut buf = [0u8; 5]; unsafe { - assert_eq!(libc::syscall(libc::SYS_getrandom, 0 as *mut libc::c_void, 0 as libc::size_t, 0 as libc::c_uint), 0); - assert_eq!(libc::syscall(libc::SYS_getrandom, buf.as_mut_ptr() as *mut libc::c_void, 5 as libc::size_t, 0 as libc::c_uint), 5); + assert_eq!( + libc::syscall( + libc::SYS_getrandom, + 0 as *mut libc::c_void, + 0 as libc::size_t, + 0 as libc::c_uint + ), + 0 + ); + assert_eq!( + libc::syscall( + libc::SYS_getrandom, + buf.as_mut_ptr() as *mut libc::c_void, + 5 as libc::size_t, + 0 as libc::c_uint + ), + 5 + ); - assert_eq!(libc::getrandom(0 as *mut libc::c_void, 0 as libc::size_t, 0 as libc::c_uint), 0); - assert_eq!(libc::getrandom(buf.as_mut_ptr() as *mut libc::c_void, 5 as libc::size_t, 0 as libc::c_uint), 5); + assert_eq!( + libc::getrandom(0 as *mut libc::c_void, 0 as libc::size_t, 0 as libc::c_uint), + 0 + ); + assert_eq!( + libc::getrandom( + buf.as_mut_ptr() as *mut libc::c_void, + 5 as libc::size_t, + 0 as libc::c_uint + ), + 5 + ); } } diff --git a/tests/pass/linux-getrandom.rs b/tests/pass/linux-getrandom.rs index 762e754f8127d..6911176995354 100644 --- a/tests/pass/linux-getrandom.rs +++ b/tests/pass/linux-getrandom.rs @@ -5,10 +5,36 @@ extern crate libc; fn main() { let mut buf = [0u8; 5]; unsafe { - assert_eq!(libc::syscall(libc::SYS_getrandom, 0 as *mut libc::c_void, 0 as libc::size_t, 0 as libc::c_uint), 0); - assert_eq!(libc::syscall(libc::SYS_getrandom, buf.as_mut_ptr() as *mut libc::c_void, 5 as libc::size_t, 0 as libc::c_uint), 5); + assert_eq!( + libc::syscall( + libc::SYS_getrandom, + 0 as *mut libc::c_void, + 0 as libc::size_t, + 0 as libc::c_uint + ), + 0 + ); + assert_eq!( + libc::syscall( + libc::SYS_getrandom, + buf.as_mut_ptr() as *mut libc::c_void, + 5 as libc::size_t, + 0 as libc::c_uint + ), + 5 + ); - assert_eq!(libc::getrandom(0 as *mut libc::c_void, 0 as libc::size_t, 0 as libc::c_uint), 0); - assert_eq!(libc::getrandom(buf.as_mut_ptr() as *mut libc::c_void, 5 as libc::size_t, 0 as libc::c_uint), 5); + assert_eq!( + libc::getrandom(0 as *mut libc::c_void, 0 as libc::size_t, 0 as libc::c_uint), + 0 + ); + assert_eq!( + libc::getrandom( + buf.as_mut_ptr() as *mut libc::c_void, + 5 as libc::size_t, + 0 as libc::c_uint + ), + 5 + ); } } diff --git a/tests/pass/loop-break-value.rs b/tests/pass/loop-break-value.rs index bd7afa7ec1a80..bc4c967d26a5b 100644 --- a/tests/pass/loop-break-value.rs +++ b/tests/pass/loop-break-value.rs @@ -16,7 +16,7 @@ pub fn main() { let _never: ! = loop { break loop { break 'outer panic!(); - } + }; }; } }; @@ -36,19 +36,15 @@ pub fn main() { assert_eq!(coerced, &[17u32]); let trait_unified = loop { - break if true { - break Default::default() - } else { - break [13, 14] - }; + break if true { break Default::default() } else { break [13, 14] }; }; assert_eq!(trait_unified, [0, 0]); let trait_unified_2 = loop { if false { - break [String::from("Hello")] + break [String::from("Hello")]; } else { - break Default::default() + break Default::default(); }; }; // compare lengths; ptr comparison is not deterministic @@ -56,11 +52,7 @@ pub fn main() { assert_eq!(trait_unified_2[0].len(), 0); let trait_unified_3 = loop { - break if false { - break [String::from("Hello")] - } else { - ["Yes".into()] - }; + break if false { break [String::from("Hello")] } else { ["Yes".into()] }; }; assert_eq!(trait_unified_3, ["Yes"]); @@ -87,7 +79,7 @@ pub fn main() { Default::default() } else { break; - } + }; }; assert_eq!(regular_break_3, ()); diff --git a/tests/pass/malloc.rs b/tests/pass/malloc.rs index b8eb7b50d3403..72abc68bb96b1 100644 --- a/tests/pass/malloc.rs +++ b/tests/pass/malloc.rs @@ -4,7 +4,7 @@ extern crate libc; -use core::{slice, ptr}; +use core::{ptr, slice}; fn main() { // Test that small allocations sometimes *are* not very aligned. diff --git a/tests/pass/many_shr_bor.rs b/tests/pass/many_shr_bor.rs index ba2f9b61b1f30..376b41dd6e209 100644 --- a/tests/pass/many_shr_bor.rs +++ b/tests/pass/many_shr_bor.rs @@ -24,7 +24,7 @@ fn test1() { fn test2(r: &mut RefCell) { let x = &*r; // releasing write lock, first suspension recorded let mut x_ref = x.borrow_mut(); - let x_inner : &mut i32 = &mut *x_ref; // new inner write lock, with same lifetime as outer lock + let x_inner: &mut i32 = &mut *x_ref; // new inner write lock, with same lifetime as outer lock let _x_inner_shr = &*x_inner; // releasing inner write lock, recording suspension let _y = &*r; // second suspension for the outer write lock let _x_inner_shr2 = &*x_inner; // 2nd suspension for inner write lock diff --git a/tests/pass/match_slice.rs b/tests/pass/match_slice.rs index 568a1a1c88182..e40a63ef2003b 100644 --- a/tests/pass/match_slice.rs +++ b/tests/pass/match_slice.rs @@ -1,8 +1,8 @@ fn main() { let x = "hello"; match x { - "foo" => {}, - "bar" => {}, - _ => {}, + "foo" => {} + "bar" => {} + _ => {} } } diff --git a/tests/pass/move-arg-2-unique.rs b/tests/pass/move-arg-2-unique.rs index b31b868bb96d5..669602ac70436 100644 --- a/tests/pass/move-arg-2-unique.rs +++ b/tests/pass/move-arg-2-unique.rs @@ -1,6 +1,8 @@ #![feature(box_syntax)] -fn test(foo: Box> ) { assert_eq!((*foo)[0], 10); } +fn test(foo: Box>) { + assert_eq!((*foo)[0], 10); +} pub fn main() { let x = box vec![10]; diff --git a/tests/pass/move-uninit-primval.rs b/tests/pass/move-uninit-primval.rs index 0edc3c9e6cd84..1ca3873d1d368 100644 --- a/tests/pass/move-uninit-primval.rs +++ b/tests/pass/move-uninit-primval.rs @@ -7,9 +7,7 @@ struct Foo { fn main() { unsafe { - let foo = Foo { - _inner: std::mem::uninitialized(), - }; + let foo = Foo { _inner: std::mem::uninitialized() }; let _bar = foo; } } diff --git a/tests/pass/negative_discriminant.rs b/tests/pass/negative_discriminant.rs index 16f175e7dfc80..5a58deeac0f31 100644 --- a/tests/pass/negative_discriminant.rs +++ b/tests/pass/negative_discriminant.rs @@ -1,4 +1,7 @@ -enum AB { A = -1, B = 1 } +enum AB { + A = -1, + B = 1, +} fn main() { match AB::A { diff --git a/tests/pass/overflow_checks_off.rs b/tests/pass/overflow_checks_off.rs index d6c6971e49521..2896d3161f763 100644 --- a/tests/pass/overflow_checks_off.rs +++ b/tests/pass/overflow_checks_off.rs @@ -8,7 +8,7 @@ // use std::ops::*; fn main() { - assert_eq!(-{-0x80i8}, -0x80); + assert_eq!(-{ -0x80i8 }, -0x80); assert_eq!(0xffu8 + 1, 0_u8); assert_eq!(0u8 - 1, 0xff_u8); diff --git a/tests/pass/overloaded-calls-simple.rs b/tests/pass/overloaded-calls-simple.rs index 12e632c251b42..9fcf7d4a819a5 100644 --- a/tests/pass/overloaded-calls-simple.rs +++ b/tests/pass/overloaded-calls-simple.rs @@ -1,4 +1,3 @@ - #![feature(lang_items, unboxed_closures, fn_traits)] struct S3 { @@ -6,18 +5,15 @@ struct S3 { y: i32, } -impl FnOnce<(i32,i32)> for S3 { +impl FnOnce<(i32, i32)> for S3 { type Output = i32; - extern "rust-call" fn call_once(self, (z,zz): (i32,i32)) -> i32 { + extern "rust-call" fn call_once(self, (z, zz): (i32, i32)) -> i32 { self.x * self.y * z * zz } } fn main() { - let s = S3 { - x: 3, - y: 3, - }; + let s = S3 { x: 3, y: 3 }; let ans = s(3, 1); assert_eq!(ans, 27); } diff --git a/tests/pass/packed_struct.rs b/tests/pass/packed_struct.rs index dd95d660d75ec..85acab858aab9 100644 --- a/tests/pass/packed_struct.rs +++ b/tests/pass/packed_struct.rs @@ -31,34 +31,31 @@ fn test_basic() { assert_eq!(x, 42); } - let mut x = S { - fill: 0, - a: 42, - b: 99, - }; + let mut x = S { fill: 0, a: 42, b: 99 }; let a = x.a; let b = x.b; assert_eq!(a, 42); assert_eq!(b, 99); assert_eq!(&x.fill, &0); // `fill` just requirs 1-byte-align, so this is fine // can't do `assert_eq!(x.a, 42)`, because `assert_eq!` takes a reference - assert_eq!({x.a}, 42); - assert_eq!({x.b}, 99); + assert_eq!({ x.a }, 42); + assert_eq!({ x.b }, 99); // but we *can* take a raw pointer! assert_eq!(unsafe { ptr::addr_of!(x.a).read_unaligned() }, 42); assert_eq!(unsafe { ptr::addr_of!(x.b).read_unaligned() }, 99); x.b = 77; - assert_eq!({x.b}, 77); + assert_eq!({ x.b }, 77); - test(Test2 { x: 0, other: &Test1 { x: 0, other: &42 }}); + test(Test2 { x: 0, other: &Test1 { x: 0, other: &42 } }); } fn test_unsizing() { #[repr(packed)] #[allow(dead_code)] struct UnalignedPtr<'a, T: ?Sized> - where T: 'a, + where + T: 'a, { data: &'a T, } @@ -67,7 +64,8 @@ fn test_unsizing() { where T: std::marker::Unsize + ?Sized, U: ?Sized, - { } + { + } let arr = [1, 2, 3]; let arr_unaligned: UnalignedPtr<[i32; 3]> = UnalignedPtr { data: &arr }; @@ -86,7 +84,7 @@ fn test_drop() { } } - #[repr(packed,C)] + #[repr(packed, C)] struct Packed { f1: u8, // this should move the second field to something not very aligned f2: T, @@ -100,10 +98,10 @@ fn test_inner_packed() { // Even if just the inner struct is packed, accesses to the outer field can get unaligned. // Make sure that works. #[repr(packed)] - #[derive(Clone,Copy)] + #[derive(Clone, Copy)] struct Inner(u32); - #[derive(Clone,Copy)] + #[derive(Clone, Copy)] struct Outer(u8, Inner); let o = Outer(0, Inner(42)); @@ -115,12 +113,12 @@ fn test_inner_packed() { fn test_static() { #[repr(packed)] struct Foo { - i: i32 + i: i32, } static FOO: Foo = Foo { i: 42 }; - assert_eq!({FOO.i}, 42); + assert_eq!({ FOO.i }, 42); } fn test_derive() { @@ -132,8 +130,8 @@ fn test_derive() { c: usize, } - let x = P {a: 1usize, b: 2u8, c: 3usize}; - let y = P {a: 1usize, b: 2u8, c: 4usize}; + let x = P { a: 1usize, b: 2u8, c: 3usize }; + let y = P { a: 1usize, b: 2u8, c: 4usize }; let _clone = x.clone(); assert!(x != y); diff --git a/tests/pass/partially-uninit.rs b/tests/pass/partially-uninit.rs index 5ee9abbcb95bb..db26a2084b1c0 100644 --- a/tests/pass/partially-uninit.rs +++ b/tests/pass/partially-uninit.rs @@ -4,10 +4,12 @@ use std::mem::{self, MaybeUninit}; #[derive(Copy, Clone, Debug, PartialEq)] struct Demo(bool, u16); -fn main() { unsafe { - // Transmute-round-trip through a type with Scalar layout is lossless. - // This is tricky because that 'scalar' is *partially* uninitialized. - let x = Demo(true, 3); - let y: MaybeUninit = mem::transmute(x); - assert_eq!(x, mem::transmute(y)); -} } +fn main() { + unsafe { + // Transmute-round-trip through a type with Scalar layout is lossless. + // This is tricky because that 'scalar' is *partially* uninitialized. + let x = Demo(true, 3); + let y: MaybeUninit = mem::transmute(x); + assert_eq!(x, mem::transmute(y)); + } +} diff --git a/tests/pass/pointers.rs b/tests/pass/pointers.rs index 5bf60c32541db..898ecc0faf755 100644 --- a/tests/pass/pointers.rs +++ b/tests/pass/pointers.rs @@ -37,7 +37,7 @@ fn match_ref_mut() -> i8 { let opt = Some(&mut t); match opt { Some(&mut (ref mut x, ref mut y)) => *x += *y, - None => {}, + None => {} } } t.0 @@ -59,7 +59,10 @@ fn main() { // Compare even dangling pointers with NULL, and with others in the same allocation, including // out-of-bounds. assert!(dangling_pointer() != std::ptr::null()); - assert!(match dangling_pointer() as usize { 0 => false, _ => true }); + assert!(match dangling_pointer() as usize { + 0 => false, + _ => true, + }); let dangling = dangling_pointer(); assert!(dangling == dangling); assert!(dangling.wrapping_add(1) != dangling); diff --git a/tests/pass/portable-simd.rs b/tests/pass/portable-simd.rs index 3e43595c94aee..ffbaa1832ecba 100644 --- a/tests/pass/portable-simd.rs +++ b/tests/pass/portable-simd.rs @@ -16,10 +16,10 @@ fn simd_ops_f32() { assert_eq!(a.max(b * f32x4::splat(4.0)), f32x4::from_array([10.0, 10.0, 12.0, 10.0])); assert_eq!(a.min(b * f32x4::splat(4.0)), f32x4::from_array([4.0, 8.0, 10.0, -16.0])); - assert_eq!(a.mul_add(b, a), (a*b)+a); - assert_eq!(b.mul_add(b, a), (b*b)+a); - assert_eq!((a*a).sqrt(), a); - assert_eq!((b*b).sqrt(), b.abs()); + assert_eq!(a.mul_add(b, a), (a * b) + a); + assert_eq!(b.mul_add(b, a), (b * b) + a); + assert_eq!((a * a).sqrt(), a); + assert_eq!((b * b).sqrt(), b.abs()); assert_eq!(a.lanes_eq(f32x4::splat(5.0) * b), Mask::from_array([false, true, false, false])); assert_eq!(a.lanes_ne(f32x4::splat(5.0) * b), Mask::from_array([true, false, true, true])); @@ -65,10 +65,10 @@ fn simd_ops_f64() { assert_eq!(a.max(b * f64x4::splat(4.0)), f64x4::from_array([10.0, 10.0, 12.0, 10.0])); assert_eq!(a.min(b * f64x4::splat(4.0)), f64x4::from_array([4.0, 8.0, 10.0, -16.0])); - assert_eq!(a.mul_add(b, a), (a*b)+a); - assert_eq!(b.mul_add(b, a), (b*b)+a); - assert_eq!((a*a).sqrt(), a); - assert_eq!((b*b).sqrt(), b.abs()); + assert_eq!(a.mul_add(b, a), (a * b) + a); + assert_eq!(b.mul_add(b, a), (b * b) + a); + assert_eq!((a * a).sqrt(), a); + assert_eq!((b * b).sqrt(), b.abs()); assert_eq!(a.lanes_eq(f64x4::splat(5.0) * b), Mask::from_array([false, true, false, false])); assert_eq!(a.lanes_ne(f64x4::splat(5.0) * b), Mask::from_array([true, false, true, true])); diff --git a/tests/pass/products.rs b/tests/pass/products.rs index 86bb71a0be560..767d756e5ae18 100644 --- a/tests/pass/products.rs +++ b/tests/pass/products.rs @@ -11,7 +11,10 @@ fn tuple_5() -> (i16, i16, i16, i16, i16) { } #[derive(Debug, PartialEq)] -struct Pair { x: i8, y: i8 } +struct Pair { + x: i8, + y: i8, +} fn pair() -> Pair { Pair { x: 10, y: 20 } @@ -27,6 +30,6 @@ fn main() { assert_eq!(tuple(), (1,)); assert_eq!(tuple_2(), (1, 2)); assert_eq!(tuple_5(), (1, 2, 3, 4, 5)); - assert_eq!(pair(), Pair { x: 10, y: 20} ); + assert_eq!(pair(), Pair { x: 10, y: 20 }); assert_eq!(field_access(), (15, 20)); } diff --git a/tests/pass/ptr_offset.rs b/tests/pass/ptr_offset.rs index 4c6341813f5b7..1b25df721452f 100644 --- a/tests/pass/ptr_offset.rs +++ b/tests/pass/ptr_offset.rs @@ -8,21 +8,23 @@ fn main() { ptr_offset(); } -fn test_offset_from() { unsafe { - let buf = [0u32; 4]; +fn test_offset_from() { + unsafe { + let buf = [0u32; 4]; - let x = buf.as_ptr() as *const u8; - let y = x.offset(12); + let x = buf.as_ptr() as *const u8; + let y = x.offset(12); - assert_eq!(y.offset_from(x), 12); - assert_eq!(x.offset_from(y), -12); - assert_eq!((y as *const u32).offset_from(x as *const u32), 12/4); - assert_eq!((x as *const u32).offset_from(y as *const u32), -12/4); + assert_eq!(y.offset_from(x), 12); + assert_eq!(x.offset_from(y), -12); + assert_eq!((y as *const u32).offset_from(x as *const u32), 12 / 4); + assert_eq!((x as *const u32).offset_from(y as *const u32), -12 / 4); - let x = (((x as usize) * 2) / 2) as *const u8; - assert_eq!(y.offset_from(x), 12); - assert_eq!(x.offset_from(y), -12); -} } + let x = (((x as usize) * 2) / 2) as *const u8; + assert_eq!(y.offset_from(x), 12); + assert_eq!(x.offset_from(y), -12); + } +} // This also internally uses offset_from. fn test_vec_into_iter() { @@ -50,7 +52,9 @@ fn ptr_arith_offset_overflow() { } fn ptr_offset() { - fn f() -> i32 { 42 } + fn f() -> i32 { + 42 + } let v = [1i16, 2]; let x = &v as *const [i16; 2] as *const i16; diff --git a/tests/pass/ptr_raw.rs b/tests/pass/ptr_raw.rs index 4fbbb270957b3..3ba0fba9a9412 100644 --- a/tests/pass/ptr_raw.rs +++ b/tests/pass/ptr_raw.rs @@ -5,12 +5,16 @@ fn basic_raw() { assert_eq!(*x, 12); let raw = x as *mut i32; - unsafe { *raw = 42; } + unsafe { + *raw = 42; + } assert_eq!(*x, 42); let raw = x as *mut i32; - unsafe { *raw = 12; } + unsafe { + *raw = 12; + } *x = 23; assert_eq!(*x, 23); diff --git a/tests/pass/rc.rs b/tests/pass/rc.rs index 6d51825fc0df2..260e350f27ac2 100644 --- a/tests/pass/rc.rs +++ b/tests/pass/rc.rs @@ -3,9 +3,9 @@ #![feature(get_mut_unchecked)] use std::cell::{Cell, RefCell}; +use std::fmt::Debug; use std::rc::{Rc, Weak}; use std::sync::{Arc, Weak as ArcWeak}; -use std::fmt::Debug; fn rc_refcell() { let r = Rc::new(RefCell::new(42)); @@ -30,7 +30,7 @@ fn rc_refcell2() { let x = r2.borrow(); let r3 = r.clone(); let y = r3.borrow(); - assert_eq!((*x + *y)/2, 52); + assert_eq!((*x + *y) / 2, 52); } fn rc_raw() { @@ -62,9 +62,9 @@ fn check_unique_rc(mut r: Rc) { } fn rc_from() { - check_unique_rc::<[_]>(Rc::from(&[1,2,3] as &[_])); - check_unique_rc::<[_]>(Rc::from(vec![1,2,3])); - check_unique_rc::<[_]>(Rc::from(Box::new([1,2,3]) as Box<[_]>)); + check_unique_rc::<[_]>(Rc::from(&[1, 2, 3] as &[_])); + check_unique_rc::<[_]>(Rc::from(vec![1, 2, 3])); + check_unique_rc::<[_]>(Rc::from(Box::new([1, 2, 3]) as Box<[_]>)); check_unique_rc::(Rc::from("Hello, World!")); } diff --git a/tests/pass/regions-mock-trans.rs b/tests/pass/regions-mock-trans.rs index 23ec91461db5f..5dafc88756f11 100644 --- a/tests/pass/regions-mock-trans.rs +++ b/tests/pass/regions-mock-trans.rs @@ -9,32 +9,29 @@ use std::mem; struct Arena(()); struct Bcx<'a> { - fcx: &'a Fcx<'a> + fcx: &'a Fcx<'a>, } #[allow(dead_code)] struct Fcx<'a> { arena: &'a Arena, - ccx: &'a Ccx + ccx: &'a Ccx, } #[allow(dead_code)] struct Ccx { - x: isize + x: isize, } -fn alloc<'a>(_bcx : &'a Arena) -> &'a mut Bcx<'a> { - unsafe { - mem::transmute(libc::malloc(mem::size_of::>() - as libc::size_t)) - } +fn alloc<'a>(_bcx: &'a Arena) -> &'a mut Bcx<'a> { + unsafe { mem::transmute(libc::malloc(mem::size_of::>() as libc::size_t)) } } -fn h<'a>(bcx : &'a Bcx<'a>) -> &'a mut Bcx<'a> { +fn h<'a>(bcx: &'a Bcx<'a>) -> &'a mut Bcx<'a> { return alloc(bcx.fcx.arena); } -fn g(fcx : &Fcx) { +fn g(fcx: &Fcx) { let bcx = Bcx { fcx: fcx }; let bcx2 = h(&bcx); unsafe { @@ -42,7 +39,7 @@ fn g(fcx : &Fcx) { } } -fn f(ccx : &Ccx) { +fn f(ccx: &Ccx) { let a = Arena(()); let fcx = Fcx { arena: &a, ccx: ccx }; return g(&fcx); diff --git a/tests/pass/send-is-not-static-par-for.rs b/tests/pass/send-is-not-static-par-for.rs index 396a87fca060d..642f75ecc09bf 100644 --- a/tests/pass/send-is-not-static-par-for.rs +++ b/tests/pass/send-is-not-static-par-for.rs @@ -1,9 +1,10 @@ use std::sync::Mutex; fn par_for(iter: I, f: F) - where I: Iterator, - I::Item: Send, - F: Fn(I::Item) + Sync +where + I: Iterator, + I::Item: Send, + F: Fn(I::Item) + Sync, { for item in iter { f(item) @@ -12,9 +13,7 @@ fn par_for(iter: I, f: F) fn sum(x: &[i32]) { let sum_lengths = Mutex::new(0); - par_for(x.windows(4), |x| { - *sum_lengths.lock().unwrap() += x.len() - }); + par_for(x.windows(4), |x| *sum_lengths.lock().unwrap() += x.len()); assert_eq!(*sum_lengths.lock().unwrap(), (x.len() - 3) * 4); } @@ -23,9 +22,7 @@ fn main() { let mut elements = [0; 20]; // iterators over references into this stack frame - par_for(elements.iter_mut().enumerate(), |(i, x)| { - *x = i as i32 - }); + par_for(elements.iter_mut().enumerate(), |(i, x)| *x = i as i32); sum(&elements) } diff --git a/tests/pass/sendable-class.rs b/tests/pass/sendable-class.rs index b2feb5316f873..a05278f1855a2 100644 --- a/tests/pass/sendable-class.rs +++ b/tests/pass/sendable-class.rs @@ -8,11 +8,8 @@ struct Foo { j: char, } -fn foo(i:isize, j: char) -> Foo { - Foo { - i: i, - j: j - } +fn foo(i: isize, j: char) -> Foo { + Foo { i: i, j: j } } pub fn main() { diff --git a/tests/pass/simd-intrinsic-generic-elements.rs b/tests/pass/simd-intrinsic-generic-elements.rs index 32de27a96233a..5958357c8b7b1 100644 --- a/tests/pass/simd-intrinsic-generic-elements.rs +++ b/tests/pass/simd-intrinsic-generic-elements.rs @@ -11,8 +11,7 @@ struct i32x4(i32, i32, i32, i32); #[repr(simd)] #[derive(Copy, Clone, Debug, PartialEq)] #[allow(non_camel_case_types)] -struct i32x8(i32, i32, i32, i32, - i32, i32, i32, i32); +struct i32x8(i32, i32, i32, i32, i32, i32, i32, i32); fn main() { let _x2 = i32x2(20, 21); @@ -22,5 +21,4 @@ fn main() { let _y2 = i32x2(120, 121); let _y4 = i32x4(140, 141, 142, 143); let _y8 = i32x8(180, 181, 182, 183, 184, 185, 186, 187); - } diff --git a/tests/pass/slices.rs b/tests/pass/slices.rs index 6cdfbb7841ae0..3a13ec59a02ea 100644 --- a/tests/pass/slices.rs +++ b/tests/pass/slices.rs @@ -5,8 +5,8 @@ #![feature(layout_for_ptr)] #![feature(strict_provenance)] -use std::slice; use std::ptr; +use std::slice; fn slice_of_zst() { fn foo(v: &[T]) -> Option<&[T]> { @@ -40,7 +40,8 @@ fn slice_of_zst() { assert!(foo(slice).is_some()); // Test mutable iterators as well - let slice: &mut [()] = unsafe { slice::from_raw_parts_mut(ptr::invalid_mut(-5isize as usize), 10) }; + let slice: &mut [()] = + unsafe { slice::from_raw_parts_mut(ptr::invalid_mut(-5isize as usize), 10) }; assert_eq!(slice.len(), 10); assert_eq!(slice.iter_mut().count(), 10); @@ -56,11 +57,11 @@ fn slice_of_zst() { fn test_iter_ref_consistency() { use std::fmt::Debug; - fn test(x : T) { - let v : &[T] = &[x, x, x]; - let v_ptrs : [*const T; 3] = match v { + fn test(x: T) { + let v: &[T] = &[x, x, x]; + let v_ptrs: [*const T; 3] = match v { [ref v1, ref v2, ref v3] => [v1 as *const _, v2 as *const _, v3 as *const _], - _ => unreachable!() + _ => unreachable!(), }; let len = v.len(); @@ -104,19 +105,19 @@ fn test_iter_ref_consistency() { assert_eq!(it.size_hint(), (remaining, Some(remaining))); let prev = it.next_back().unwrap(); - assert_eq!(prev as *const _, v_ptrs[remaining-1]); + assert_eq!(prev as *const _, v_ptrs[remaining - 1]); } assert_eq!(it.size_hint(), (0, Some(0))); assert_eq!(it.next_back(), None, "The final call to next_back() should return None"); } } - fn test_mut(x : T) { - let v : &mut [T] = &mut [x, x, x]; - let v_ptrs : [*mut T; 3] = match v { + fn test_mut(x: T) { + let v: &mut [T] = &mut [x, x, x]; + let v_ptrs: [*mut T; 3] = match v { [ref v1, ref v2, ref v3] => - [v1 as *const _ as *mut _, v2 as *const _ as *mut _, v3 as *const _ as *mut _], - _ => unreachable!() + [v1 as *const _ as *mut _, v2 as *const _ as *mut _, v3 as *const _ as *mut _], + _ => unreachable!(), }; let len = v.len(); @@ -160,7 +161,7 @@ fn test_iter_ref_consistency() { assert_eq!(it.size_hint(), (remaining, Some(remaining))); let prev = it.next_back().unwrap(); - assert_eq!(prev as *mut _, v_ptrs[remaining-1]); + assert_eq!(prev as *mut _, v_ptrs[remaining - 1]); } assert_eq!(it.size_hint(), (0, Some(0))); assert_eq!(it.next_back(), None, "The final call to next_back() should return None"); @@ -215,10 +216,14 @@ fn test_for_invalidated_pointers() { // The invalidated `*const` pointer (the first argument to `core::ptr::copy`) is then used // after the fact when `core::ptr::copy` is called, which triggers undefined behavior. - unsafe { assert_eq!(0, *buffer.as_mut_ptr_range().start ); } + unsafe { + assert_eq!(0, *buffer.as_mut_ptr_range().start); + } // Check that the pointer range is in-bounds, while we're at it let range = buffer.as_mut_ptr_range(); - unsafe { assert_eq!(*range.start, *range.end.sub(len)); } + unsafe { + assert_eq!(*range.start, *range.end.sub(len)); + } buffer.reverse(); diff --git a/tests/pass/specialization.rs b/tests/pass/specialization.rs index 44cef00a22c36..428dea073eb53 100644 --- a/tests/pass/specialization.rs +++ b/tests/pass/specialization.rs @@ -6,11 +6,15 @@ trait IsUnit { } impl IsUnit for T { - default fn is_unit() -> bool { false } + default fn is_unit() -> bool { + false + } } impl IsUnit for () { - fn is_unit() -> bool { true } + fn is_unit() -> bool { + true + } } fn specialization() -> (bool, bool) { diff --git a/tests/pass/stacked-borrows/2phase.rs b/tests/pass/stacked-borrows/2phase.rs index 065c76913a71e..2a7588377feb4 100644 --- a/tests/pass/stacked-borrows/2phase.rs +++ b/tests/pass/stacked-borrows/2phase.rs @@ -21,7 +21,9 @@ fn two_phase3(b: bool) { let mut y = vec![]; x.push(( { - if b { x = &mut y }; + if b { + x = &mut y + }; 22 }, x.len(), @@ -31,16 +33,16 @@ fn two_phase3(b: bool) { #[allow(unreachable_code)] fn two_phase_raw() { let x: &mut Vec = &mut vec![]; - x.push( - { - // Unfortunately this does not trigger the problem of creating a - // raw ponter from a pointer that had a two-phase borrow derived from - // it because of the implicit &mut reborrow. - let raw = x as *mut _; - unsafe { *raw = vec![1]; } - return + x.push({ + // Unfortunately this does not trigger the problem of creating a + // raw ponter from a pointer that had a two-phase borrow derived from + // it because of the implicit &mut reborrow. + let raw = x as *mut _; + unsafe { + *raw = vec![1]; } - ); + return; + }); } fn two_phase_overlapping1() { @@ -68,13 +70,11 @@ fn with_interior_mutability() { let mut x = Cell::new(1); let l = &x; - x - .do_the_thing({ - x.set(3); - l.set(4); - x.get() + l.get() - }) - ; + x.do_the_thing({ + x.set(3); + l.set(4); + x.get() + l.get() + }); } fn main() { diff --git a/tests/pass/stacked-borrows/interior_mutability.rs b/tests/pass/stacked-borrows/interior_mutability.rs index 23d82b8e435b8..1ac9706b525f1 100644 --- a/tests/pass/stacked-borrows/interior_mutability.rs +++ b/tests/pass/stacked-borrows/interior_mutability.rs @@ -1,5 +1,5 @@ -use std::mem::MaybeUninit; use std::cell::{Cell, RefCell, UnsafeCell}; +use std::mem::MaybeUninit; fn main() { aliasing_mut_and_shr(); @@ -28,7 +28,7 @@ fn aliasing_mut_and_shr() { let mut bmut = rc.borrow_mut(); inner(&rc, &mut *bmut); drop(bmut); - assert_eq!(*rc.borrow(), 23+12); + assert_eq!(*rc.borrow(), 23 + 12); } fn aliasing_frz_and_shr() { @@ -59,9 +59,11 @@ fn into_interior_mutability() { // Two-phase borrows of the pointer returned by UnsafeCell::get() should not // invalidate aliases. -fn unsafe_cell_2phase() { unsafe { - let x = &UnsafeCell::new(vec![]); - let x2 = &*x; - (*x.get()).push(0); - let _val = (*x2.get()).get(0); -} } +fn unsafe_cell_2phase() { + unsafe { + let x = &UnsafeCell::new(vec![]); + let x2 = &*x; + (*x.get()).push(0); + let _val = (*x2.get()).get(0); + } +} From 6b8c371f068ef83fbb11c0829c5c21965eef4aa2 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Mon, 20 Jun 2022 16:08:00 -0700 Subject: [PATCH 3274/3747] Manual adjustments --- tests/pass/issues/issue-17877.rs | 4 ++-- tests/pass/libc.rs | 24 +++++++++---------- .../pass/linux-getrandom-without-isolation.rs | 14 +++++------ tests/pass/linux-getrandom.rs | 14 +++++------ tests/pass/stacked-borrows/2phase.rs | 4 ++-- 5 files changed, 30 insertions(+), 30 deletions(-) diff --git a/tests/pass/issues/issue-17877.rs b/tests/pass/issues/issue-17877.rs index a65c5513de004..64d397f91aeec 100644 --- a/tests/pass/issues/issue-17877.rs +++ b/tests/pass/issues/issue-17877.rs @@ -3,7 +3,7 @@ fn main() { match [0u8; 16 * 1024] { _ => 42_usize, }, - 42_usize + 42_usize, ); assert_eq!( @@ -12,6 +12,6 @@ fn main() { [0, ..] => 1_usize, _ => 2_usize, }, - 1_usize + 1_usize, ); } diff --git a/tests/pass/libc.rs b/tests/pass/libc.rs index 5991fae5bb1e6..f97b9dd2b9eaa 100644 --- a/tests/pass/libc.rs +++ b/tests/pass/libc.rs @@ -95,7 +95,7 @@ fn test_mutex_libc_init_recursive() { assert_eq!(libc::pthread_mutexattr_init(&mut attr as *mut _), 0); assert_eq!( libc::pthread_mutexattr_settype(&mut attr as *mut _, libc::PTHREAD_MUTEX_RECURSIVE), - 0 + 0, ); let mut mutex: libc::pthread_mutex_t = std::mem::zeroed(); assert_eq!(libc::pthread_mutex_init(&mut mutex as *mut _, &mut attr as *mut _), 0); @@ -118,11 +118,11 @@ fn test_mutex_libc_init_normal() { let mut mutexattr: libc::pthread_mutexattr_t = std::mem::zeroed(); assert_eq!( libc::pthread_mutexattr_settype(&mut mutexattr as *mut _, 0x12345678), - libc::EINVAL + libc::EINVAL, ); assert_eq!( libc::pthread_mutexattr_settype(&mut mutexattr as *mut _, libc::PTHREAD_MUTEX_NORMAL), - 0 + 0, ); let mut mutex: libc::pthread_mutex_t = std::mem::zeroed(); assert_eq!(libc::pthread_mutex_init(&mut mutex as *mut _, &mutexattr as *const _), 0); @@ -141,9 +141,9 @@ fn test_mutex_libc_init_errorcheck() { assert_eq!( libc::pthread_mutexattr_settype( &mut mutexattr as *mut _, - libc::PTHREAD_MUTEX_ERRORCHECK + libc::PTHREAD_MUTEX_ERRORCHECK, ), - 0 + 0, ); let mut mutex: libc::pthread_mutex_t = std::mem::zeroed(); assert_eq!(libc::pthread_mutex_init(&mut mutex as *mut _, &mutexattr as *const _), 0); @@ -216,7 +216,7 @@ fn test_prctl_thread_name() { let mut buf = [255; 10]; assert_eq!( libc::prctl(libc::PR_GET_NAME, buf.as_mut_ptr(), 0 as c_long, 0 as c_long, 0 as c_long), - 0 + 0, ); assert_eq!(b"\0", &buf); let thread_name = CString::new("hello").expect("CString::new failed"); @@ -226,14 +226,14 @@ fn test_prctl_thread_name() { thread_name.as_ptr(), 0 as c_long, 0 as c_long, - 0 as c_long + 0 as c_long, ), - 0 + 0, ); let mut buf = [255; 6]; assert_eq!( libc::prctl(libc::PR_GET_NAME, buf.as_mut_ptr(), 0 as c_long, 0 as c_long, 0 as c_long), - 0 + 0, ); assert_eq!(b"hello\0", &buf); let long_thread_name = CString::new("01234567890123456789").expect("CString::new failed"); @@ -243,14 +243,14 @@ fn test_prctl_thread_name() { long_thread_name.as_ptr(), 0 as c_long, 0 as c_long, - 0 as c_long + 0 as c_long, ), - 0 + 0, ); let mut buf = [255; 16]; assert_eq!( libc::prctl(libc::PR_GET_NAME, buf.as_mut_ptr(), 0 as c_long, 0 as c_long, 0 as c_long), - 0 + 0, ); assert_eq!(b"012345678901234\0", &buf); } diff --git a/tests/pass/linux-getrandom-without-isolation.rs b/tests/pass/linux-getrandom-without-isolation.rs index a88db57cc09d5..ad1a1f27c7713 100644 --- a/tests/pass/linux-getrandom-without-isolation.rs +++ b/tests/pass/linux-getrandom-without-isolation.rs @@ -11,31 +11,31 @@ fn main() { libc::SYS_getrandom, 0 as *mut libc::c_void, 0 as libc::size_t, - 0 as libc::c_uint + 0 as libc::c_uint, ), - 0 + 0, ); assert_eq!( libc::syscall( libc::SYS_getrandom, buf.as_mut_ptr() as *mut libc::c_void, 5 as libc::size_t, - 0 as libc::c_uint + 0 as libc::c_uint, ), - 5 + 5, ); assert_eq!( libc::getrandom(0 as *mut libc::c_void, 0 as libc::size_t, 0 as libc::c_uint), - 0 + 0, ); assert_eq!( libc::getrandom( buf.as_mut_ptr() as *mut libc::c_void, 5 as libc::size_t, - 0 as libc::c_uint + 0 as libc::c_uint, ), - 5 + 5, ); } } diff --git a/tests/pass/linux-getrandom.rs b/tests/pass/linux-getrandom.rs index 6911176995354..7d3f899f4408a 100644 --- a/tests/pass/linux-getrandom.rs +++ b/tests/pass/linux-getrandom.rs @@ -10,31 +10,31 @@ fn main() { libc::SYS_getrandom, 0 as *mut libc::c_void, 0 as libc::size_t, - 0 as libc::c_uint + 0 as libc::c_uint, ), - 0 + 0, ); assert_eq!( libc::syscall( libc::SYS_getrandom, buf.as_mut_ptr() as *mut libc::c_void, 5 as libc::size_t, - 0 as libc::c_uint + 0 as libc::c_uint, ), - 5 + 5, ); assert_eq!( libc::getrandom(0 as *mut libc::c_void, 0 as libc::size_t, 0 as libc::c_uint), - 0 + 0, ); assert_eq!( libc::getrandom( buf.as_mut_ptr() as *mut libc::c_void, 5 as libc::size_t, - 0 as libc::c_uint + 0 as libc::c_uint, ), - 5 + 5, ); } } diff --git a/tests/pass/stacked-borrows/2phase.rs b/tests/pass/stacked-borrows/2phase.rs index 2a7588377feb4..345cb64ccf713 100644 --- a/tests/pass/stacked-borrows/2phase.rs +++ b/tests/pass/stacked-borrows/2phase.rs @@ -22,8 +22,8 @@ fn two_phase3(b: bool) { x.push(( { if b { - x = &mut y - }; + x = &mut y; + } 22 }, x.len(), From 8efc049a9f0ad4b0bd95fa479ef6ec4b8d440b4b Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Mon, 20 Jun 2022 15:43:42 -0700 Subject: [PATCH 3275/3747] Manual adjustments --- tests/pass/align_offset_symbolic.rs | 1 + tests/pass/catch.rs | 4 +--- tests/pass/closure-field-ty.rs | 4 +--- tests/pass/closures.rs | 2 +- 4 files changed, 4 insertions(+), 7 deletions(-) diff --git a/tests/pass/align_offset_symbolic.rs b/tests/pass/align_offset_symbolic.rs index ad231bd0d5bb6..b57a23ab83682 100644 --- a/tests/pass/align_offset_symbolic.rs +++ b/tests/pass/align_offset_symbolic.rs @@ -60,6 +60,7 @@ fn test_align_to() { { #[repr(align(8))] struct Align8(u64); + let (l, m, r) = unsafe { s.align_to::() }; // requested alignment higher than allocation alignment assert_eq!(l.len(), 4 * N); assert_eq!(r.len(), 0); diff --git a/tests/pass/catch.rs b/tests/pass/catch.rs index 745e186a8e17a..4ede23e68ce25 100644 --- a/tests/pass/catch.rs +++ b/tests/pass/catch.rs @@ -2,8 +2,6 @@ use std::panic::{catch_unwind, AssertUnwindSafe}; fn main() { let mut i = 3; - let _val = catch_unwind(AssertUnwindSafe(|| { - i -= 2; - })); + let _val = catch_unwind(AssertUnwindSafe(|| i -= 2)); println!("{}", i); } diff --git a/tests/pass/closure-field-ty.rs b/tests/pass/closure-field-ty.rs index fdcaf1d517238..1c90a15f8c5ca 100644 --- a/tests/pass/closure-field-ty.rs +++ b/tests/pass/closure-field-ty.rs @@ -3,9 +3,7 @@ fn main() { let mut y = 0; { let mut box_maybe_closure = Box::new(None); - *box_maybe_closure = Some(|| { - y += 1; - }); + *box_maybe_closure = Some(|| y += 1); (box_maybe_closure.unwrap())(); } assert_eq!(y, 1); diff --git a/tests/pass/closures.rs b/tests/pass/closures.rs index 21292765acaa5..40aedbcaf4545 100644 --- a/tests/pass/closures.rs +++ b/tests/pass/closures.rs @@ -118,7 +118,7 @@ fn main() { let x = 13; move || x })), - 13 + 13, ); box_dyn(); From 069f5b6615a42dc8be1133277650c466f6cb8dc5 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Mon, 20 Jun 2022 23:40:39 -0700 Subject: [PATCH 3276/3747] Format tests with rustfmt (151-200 of 300) --- tests/fail/intrinsics/simd-rem-by-zero.rs | 12 ++-- tests/fail/intrinsics/simd-scatter.rs | 16 +++-- .../intrinsics/simd-select-bitmask-invalid.rs | 10 +-- .../intrinsics/simd-select-invalid-bool.rs | 10 +-- tests/fail/intrinsics/simd-shl-too-far.rs | 12 ++-- tests/fail/intrinsics/simd-shr-too-far.rs | 12 ++-- tests/fail/invalid_enum_tag.rs | 5 +- tests/fail/issue-miri-1112.rs | 6 +- tests/fail/memleak_rc.rs | 2 +- tests/fail/modifying_constants.rs | 2 +- tests/fail/never_say_never.rs | 6 +- tests/fail/never_transmute_void.rs | 4 +- tests/fail/rc_as_ptr.rs | 2 +- tests/fail/reading_half_a_pointer.rs | 2 +- tests/fail/shim_arg_size.rs | 4 +- tests/fail/should-pass/cpp20_rwc_syncs.rs | 4 +- .../stacked_borrows/alias_through_mutation.rs | 4 +- tests/fail/stacked_borrows/aliasing_mut1.rs | 5 +- tests/fail/stacked_borrows/aliasing_mut2.rs | 5 +- tests/fail/stacked_borrows/aliasing_mut3.rs | 5 +- tests/fail/stacked_borrows/aliasing_mut4.rs | 7 +- .../box_exclusive_violation1.rs | 30 +++++---- .../stacked_borrows/buggy_as_mut_slice.rs | 6 +- .../stacked_borrows/buggy_split_at_mut.rs | 8 ++- tests/fail/stacked_borrows/illegal_read6.rs | 16 +++-- tests/fail/stacked_borrows/illegal_read7.rs | 30 +++++---- tests/fail/stacked_borrows/illegal_read8.rs | 22 ++++--- tests/fail/stacked_borrows/interior_mut1.rs | 22 ++++--- tests/panic/panic/panic1.rs | 1 - tests/panic/transmute_fat2.rs | 18 ++--- tests/pass/stacked-borrows/refcell.rs | 8 +-- tests/pass/stacked-borrows/stacked-borrows.rs | 65 +++++++++++-------- tests/pass/static_memory_modification.rs | 2 +- tests/pass/static_mut.rs | 2 +- tests/pass/strings.rs | 2 +- tests/pass/tag-align-dyn-u64.rs | 6 +- tests/pass/time.rs | 10 ++- tests/pass/track-caller-attribute.rs | 5 +- tests/pass/transmute_fat.rs | 4 +- tests/pass/u128.rs | 24 ++++--- tests/pass/union.rs | 19 ++++-- tests/pass/unops.rs | 2 +- tests/pass/unsized-tuple-impls.rs | 4 +- tests/pass/validation_lifetime_resolution.rs | 12 +++- tests/pass/vec-matching-fold.rs | 30 ++++----- tests/pass/vec.rs | 30 +++------ tests/pass/vecdeque.rs | 2 +- tests/pass/weak_memory/weak.rs | 1 - tests/pass/wtf8.rs | 2 +- tests/pass/zst.rs | 8 ++- 50 files changed, 280 insertions(+), 246 deletions(-) diff --git a/tests/fail/intrinsics/simd-rem-by-zero.rs b/tests/fail/intrinsics/simd-rem-by-zero.rs index bc3128b5fb5f1..82cbaed462c69 100644 --- a/tests/fail/intrinsics/simd-rem-by-zero.rs +++ b/tests/fail/intrinsics/simd-rem-by-zero.rs @@ -8,8 +8,10 @@ extern "platform-intrinsic" { #[allow(non_camel_case_types)] struct i32x2(i32, i32); -fn main() { unsafe { - let x = i32x2(1, 1); - let y = i32x2(1, 0); - simd_rem(x, y); //~ERROR Undefined Behavior: calculating the remainder with a divisor of zero -} } +fn main() { + unsafe { + let x = i32x2(1, 1); + let y = i32x2(1, 0); + simd_rem(x, y); //~ERROR Undefined Behavior: calculating the remainder with a divisor of zero + } +} diff --git a/tests/fail/intrinsics/simd-scatter.rs b/tests/fail/intrinsics/simd-scatter.rs index f46e4f0d4f6a8..d7a7e344aa30c 100644 --- a/tests/fail/intrinsics/simd-scatter.rs +++ b/tests/fail/intrinsics/simd-scatter.rs @@ -2,8 +2,14 @@ #![feature(portable_simd)] use std::simd::*; -fn main() { unsafe { - let mut vec: Vec = vec![10, 11, 12, 13, 14, 15, 16, 17, 18]; - let idxs = Simd::from_array([9, 3, 0, 17]); - Simd::from_array([-27, 82, -41, 124]).scatter_select_unchecked(&mut vec, Mask::splat(true), idxs); -} } +fn main() { + unsafe { + let mut vec: Vec = vec![10, 11, 12, 13, 14, 15, 16, 17, 18]; + let idxs = Simd::from_array([9, 3, 0, 17]); + Simd::from_array([-27, 82, -41, 124]).scatter_select_unchecked( + &mut vec, + Mask::splat(true), + idxs, + ); + } +} diff --git a/tests/fail/intrinsics/simd-select-bitmask-invalid.rs b/tests/fail/intrinsics/simd-select-bitmask-invalid.rs index ab69072c30976..cc9170c646462 100644 --- a/tests/fail/intrinsics/simd-select-bitmask-invalid.rs +++ b/tests/fail/intrinsics/simd-select-bitmask-invalid.rs @@ -9,7 +9,9 @@ extern "platform-intrinsic" { #[derive(Copy, Clone)] struct i32x2(i32, i32); -fn main() { unsafe { - let x = i32x2(0, 1); - simd_select_bitmask(0b11111111u8, x, x); //~ERROR bitmask less than 8 bits long must be filled with 0s for the remaining bits -} } +fn main() { + unsafe { + let x = i32x2(0, 1); + simd_select_bitmask(0b11111111u8, x, x); //~ERROR bitmask less than 8 bits long must be filled with 0s for the remaining bits + } +} diff --git a/tests/fail/intrinsics/simd-select-invalid-bool.rs b/tests/fail/intrinsics/simd-select-invalid-bool.rs index 98f67cfcd7e13..8ccf4c362c90b 100644 --- a/tests/fail/intrinsics/simd-select-invalid-bool.rs +++ b/tests/fail/intrinsics/simd-select-invalid-bool.rs @@ -9,7 +9,9 @@ extern "platform-intrinsic" { #[derive(Copy, Clone)] struct i32x2(i32, i32); -fn main() { unsafe { - let x = i32x2(0, 1); - simd_select(x, x, x); //~ERROR must be all-0-bits or all-1-bits -} } +fn main() { + unsafe { + let x = i32x2(0, 1); + simd_select(x, x, x); //~ERROR must be all-0-bits or all-1-bits + } +} diff --git a/tests/fail/intrinsics/simd-shl-too-far.rs b/tests/fail/intrinsics/simd-shl-too-far.rs index b973386f1b5c8..e971b042066cb 100644 --- a/tests/fail/intrinsics/simd-shl-too-far.rs +++ b/tests/fail/intrinsics/simd-shl-too-far.rs @@ -8,8 +8,10 @@ extern "platform-intrinsic" { #[allow(non_camel_case_types)] struct i32x2(i32, i32); -fn main() { unsafe { - let x = i32x2(1, 1); - let y = i32x2(100, 0); - simd_shl(x, y); //~ERROR overflowing shift by 100 in `simd_shl` in SIMD lane 0 -} } +fn main() { + unsafe { + let x = i32x2(1, 1); + let y = i32x2(100, 0); + simd_shl(x, y); //~ERROR overflowing shift by 100 in `simd_shl` in SIMD lane 0 + } +} diff --git a/tests/fail/intrinsics/simd-shr-too-far.rs b/tests/fail/intrinsics/simd-shr-too-far.rs index 0b4eb8c116797..ae071f0b7ea13 100644 --- a/tests/fail/intrinsics/simd-shr-too-far.rs +++ b/tests/fail/intrinsics/simd-shr-too-far.rs @@ -8,8 +8,10 @@ extern "platform-intrinsic" { #[allow(non_camel_case_types)] struct i32x2(i32, i32); -fn main() { unsafe { - let x = i32x2(1, 1); - let y = i32x2(20, 40); - simd_shr(x, y); //~ERROR overflowing shift by 40 in `simd_shr` in SIMD lane 1 -} } +fn main() { + unsafe { + let x = i32x2(1, 1); + let y = i32x2(20, 40); + simd_shr(x, y); //~ERROR overflowing shift by 40 in `simd_shr` in SIMD lane 1 + } +} diff --git a/tests/fail/invalid_enum_tag.rs b/tests/fail/invalid_enum_tag.rs index 63b6003f3d89e..7ba4da9018a71 100644 --- a/tests/fail/invalid_enum_tag.rs +++ b/tests/fail/invalid_enum_tag.rs @@ -8,7 +8,10 @@ use std::mem; #[repr(C)] pub enum Foo { - A, B, C, D + A, + B, + C, + D, } fn main() { diff --git a/tests/fail/issue-miri-1112.rs b/tests/fail/issue-miri-1112.rs index a00bed190e605..caf2b28c5a86e 100644 --- a/tests/fail/issue-miri-1112.rs +++ b/tests/fail/issue-miri-1112.rs @@ -12,11 +12,7 @@ pub struct Meta { impl Meta { pub fn new() -> Self { - Meta { - drop_fn: |_| {}, - size: 0, - align: 1, - } + Meta { drop_fn: |_| {}, size: 0, align: 1 } } } diff --git a/tests/fail/memleak_rc.rs b/tests/fail/memleak_rc.rs index 17bcb36f36106..9ea809f76299b 100644 --- a/tests/fail/memleak_rc.rs +++ b/tests/fail/memleak_rc.rs @@ -2,8 +2,8 @@ // stderr-per-bitwidth // normalize-stderr-test: ".*│.*" -> "$$stripped$$" -use std::rc::Rc; use std::cell::RefCell; +use std::rc::Rc; struct Dummy(Rc>>); diff --git a/tests/fail/modifying_constants.rs b/tests/fail/modifying_constants.rs index 2d18dccd319c3..0c884142bf1d7 100644 --- a/tests/fail/modifying_constants.rs +++ b/tests/fail/modifying_constants.rs @@ -4,6 +4,6 @@ fn main() { let x = &1; // the `&1` is promoted to a constant, but it used to be that only the pointer is marked static, not the pointee let y = unsafe { &mut *(x as *const i32 as *mut i32) }; - *y = 42; //~ ERROR read-only + *y = 42; //~ ERROR read-only assert_eq!(*x, 42); } diff --git a/tests/fail/never_say_never.rs b/tests/fail/never_say_never.rs index 37dfe827d997b..7aae8a29211ed 100644 --- a/tests/fail/never_say_never.rs +++ b/tests/fail/never_say_never.rs @@ -7,9 +7,11 @@ fn main() { let y = &5; let x: ! = unsafe { - *(y as *const _ as *const !) //~ ERROR entering unreachable code + *(y as *const _ as *const !) //~ ERROR entering unreachable code }; f(x) } -fn f(x: !) -> ! { x } +fn f(x: !) -> ! { + x +} diff --git a/tests/fail/never_transmute_void.rs b/tests/fail/never_transmute_void.rs index e5aa04dfec1af..f5d0f914dac7b 100644 --- a/tests/fail/never_transmute_void.rs +++ b/tests/fail/never_transmute_void.rs @@ -14,8 +14,6 @@ mod m { } fn main() { - let v = unsafe { - std::mem::transmute::<(), m::Void>(()) - }; + let v = unsafe { std::mem::transmute::<(), m::Void>(()) }; m::f(v); //~ inside `main` } diff --git a/tests/fail/rc_as_ptr.rs b/tests/fail/rc_as_ptr.rs index dc4e099982f80..049330ef363c6 100644 --- a/tests/fail/rc_as_ptr.rs +++ b/tests/fail/rc_as_ptr.rs @@ -1,8 +1,8 @@ // This should fail even without validation // compile-flags: -Zmiri-disable-validation -use std::rc::{Rc, Weak}; use std::ptr; +use std::rc::{Rc, Weak}; /// Taken from the `Weak::as_ptr` doctest. fn main() { diff --git a/tests/fail/reading_half_a_pointer.rs b/tests/fail/reading_half_a_pointer.rs index 6e765a1b0ba14..2a3b096b2f5a1 100644 --- a/tests/fail/reading_half_a_pointer.rs +++ b/tests/fail/reading_half_a_pointer.rs @@ -13,7 +13,7 @@ struct Wrapper { data: Data, } -static G : i32 = 0; +static G: i32 = 0; fn main() { let mut w = Wrapper { align: 0, data: Data { pad: 0, ptr: &G } }; diff --git a/tests/fail/shim_arg_size.rs b/tests/fail/shim_arg_size.rs index 1297e5ed070f6..37557de0a5e4b 100644 --- a/tests/fail/shim_arg_size.rs +++ b/tests/fail/shim_arg_size.rs @@ -4,10 +4,10 @@ fn main() { extern "C" { // Use the wrong type(ie. not the pointer width) for the `size` // argument. - #[cfg(target_pointer_width="64")] + #[cfg(target_pointer_width = "64")] fn malloc(size: u32) -> *mut std::ffi::c_void; - #[cfg(target_pointer_width="32")] + #[cfg(target_pointer_width = "32")] fn malloc(size: u16) -> *mut std::ffi::c_void; } diff --git a/tests/fail/should-pass/cpp20_rwc_syncs.rs b/tests/fail/should-pass/cpp20_rwc_syncs.rs index 00b03bceb65e4..85c24246dbeb5 100644 --- a/tests/fail/should-pass/cpp20_rwc_syncs.rs +++ b/tests/fail/should-pass/cpp20_rwc_syncs.rs @@ -76,7 +76,9 @@ fn test_cpp20_rwc_syncs() { // Our ui_test does not yet support overriding failure status codes. if (b, c) == (0, 0) { // This *should* be unreachable, but Miri will reach it. - unsafe { std::hint::unreachable_unchecked(); } + unsafe { + std::hint::unreachable_unchecked(); + } } } diff --git a/tests/fail/stacked_borrows/alias_through_mutation.rs b/tests/fail/stacked_borrows/alias_through_mutation.rs index 4a153d74ffb0b..15d8e45f8b8b0 100644 --- a/tests/fail/stacked_borrows/alias_through_mutation.rs +++ b/tests/fail/stacked_borrows/alias_through_mutation.rs @@ -1,6 +1,8 @@ // This makes a ref that was passed to us via &mut alias with things it should not alias with fn retarget(x: &mut &u32, target: &mut u32) { - unsafe { *x = &mut *(target as *mut _); } + unsafe { + *x = &mut *(target as *mut _); + } } fn main() { diff --git a/tests/fail/stacked_borrows/aliasing_mut1.rs b/tests/fail/stacked_borrows/aliasing_mut1.rs index d047925163bd6..ebee134a8acba 100644 --- a/tests/fail/stacked_borrows/aliasing_mut1.rs +++ b/tests/fail/stacked_borrows/aliasing_mut1.rs @@ -8,8 +8,7 @@ fn main() { // We need to apply some tricky to be able to call `safe` with two mutable references // with the same tag: We transmute both the fn ptr (to take raw ptrs) and the argument // (to be raw, but still have the unique tag). - let safe_raw: fn(x: *mut i32, y: *mut i32) = unsafe { - mem::transmute::(safe) - }; + let safe_raw: fn(x: *mut i32, y: *mut i32) = + unsafe { mem::transmute::(safe) }; safe_raw(xraw, xraw); } diff --git a/tests/fail/stacked_borrows/aliasing_mut2.rs b/tests/fail/stacked_borrows/aliasing_mut2.rs index c679e01677eb5..971dbb63a9d66 100644 --- a/tests/fail/stacked_borrows/aliasing_mut2.rs +++ b/tests/fail/stacked_borrows/aliasing_mut2.rs @@ -8,8 +8,7 @@ fn main() { let xraw: *mut i32 = unsafe { mem::transmute_copy(&xref) }; let xshr = &*xref; // transmute fn ptr around so that we can avoid retagging - let safe_raw: fn(x: *const i32, y: *mut i32) = unsafe { - mem::transmute::(safe) - }; + let safe_raw: fn(x: *const i32, y: *mut i32) = + unsafe { mem::transmute::(safe) }; safe_raw(xshr, xraw); } diff --git a/tests/fail/stacked_borrows/aliasing_mut3.rs b/tests/fail/stacked_borrows/aliasing_mut3.rs index 3943e9576158c..91904b0b1d14b 100644 --- a/tests/fail/stacked_borrows/aliasing_mut3.rs +++ b/tests/fail/stacked_borrows/aliasing_mut3.rs @@ -8,8 +8,7 @@ fn main() { let xraw: *mut i32 = unsafe { mem::transmute_copy(&xref) }; let xshr = &*xref; // transmute fn ptr around so that we can avoid retagging - let safe_raw: fn(x: *mut i32, y: *const i32) = unsafe { - mem::transmute::(safe) - }; + let safe_raw: fn(x: *mut i32, y: *const i32) = + unsafe { mem::transmute::(safe) }; safe_raw(xraw, xshr); } diff --git a/tests/fail/stacked_borrows/aliasing_mut4.rs b/tests/fail/stacked_borrows/aliasing_mut4.rs index 778935a6d0b0d..79caed5dd6b4d 100644 --- a/tests/fail/stacked_borrows/aliasing_mut4.rs +++ b/tests/fail/stacked_borrows/aliasing_mut4.rs @@ -1,5 +1,5 @@ -use std::mem; use std::cell::Cell; +use std::mem; // Make sure &mut UnsafeCell also is exclusive pub fn safe(_x: &i32, _y: &mut Cell) {} //~ ERROR protect @@ -10,8 +10,7 @@ fn main() { let xraw: *mut i32 = unsafe { mem::transmute_copy(&xref) }; let xshr = &*xref; // transmute fn ptr around so that we can avoid retagging - let safe_raw: fn(x: *const i32, y: *mut Cell) = unsafe { - mem::transmute::), _>(safe) - }; + let safe_raw: fn(x: *const i32, y: *mut Cell) = + unsafe { mem::transmute::), _>(safe) }; safe_raw(xshr, xraw as *mut _); } diff --git a/tests/fail/stacked_borrows/box_exclusive_violation1.rs b/tests/fail/stacked_borrows/box_exclusive_violation1.rs index 7d7f5e24e2b0b..3ca480ae7ab83 100644 --- a/tests/fail/stacked_borrows/box_exclusive_violation1.rs +++ b/tests/fail/stacked_borrows/box_exclusive_violation1.rs @@ -1,14 +1,14 @@ fn demo_mut_advanced_unique(mut our: Box) -> i32 { - unknown_code_1(&*our); + unknown_code_1(&*our); - // This "re-asserts" uniqueness of the reference: After writing, we know - // our tag is at the top of the stack. - *our = 5; + // This "re-asserts" uniqueness of the reference: After writing, we know + // our tag is at the top of the stack. + *our = 5; - unknown_code_2(); + unknown_code_2(); - // We know this will return 5 - *our //~ ERROR borrow stack + // We know this will return 5 + *our //~ ERROR borrow stack } // Now comes the evil context @@ -16,13 +16,17 @@ use std::ptr; static mut LEAK: *mut i32 = ptr::null_mut(); -fn unknown_code_1(x: &i32) { unsafe { - LEAK = x as *const _ as *mut _; -} } +fn unknown_code_1(x: &i32) { + unsafe { + LEAK = x as *const _ as *mut _; + } +} -fn unknown_code_2() { unsafe { - *LEAK = 7; -} } +fn unknown_code_2() { + unsafe { + *LEAK = 7; + } +} fn main() { demo_mut_advanced_unique(Box::new(0)); diff --git a/tests/fail/stacked_borrows/buggy_as_mut_slice.rs b/tests/fail/stacked_borrows/buggy_as_mut_slice.rs index 9ff67ae354220..6744e4ef44814 100644 --- a/tests/fail/stacked_borrows/buggy_as_mut_slice.rs +++ b/tests/fail/stacked_borrows/buggy_as_mut_slice.rs @@ -2,14 +2,12 @@ mod safe { use std::slice::from_raw_parts_mut; pub fn as_mut_slice(self_: &Vec) -> &mut [T] { - unsafe { - from_raw_parts_mut(self_.as_ptr() as *mut T, self_.len()) - } + unsafe { from_raw_parts_mut(self_.as_ptr() as *mut T, self_.len()) } } } fn main() { - let v = vec![0,1,2]; + let v = vec![0, 1, 2]; let v1 = safe::as_mut_slice(&v); let _v2 = safe::as_mut_slice(&v); v1[1] = 5; diff --git a/tests/fail/stacked_borrows/buggy_split_at_mut.rs b/tests/fail/stacked_borrows/buggy_split_at_mut.rs index 798f68fa13cc9..a2ef0fcf178db 100644 --- a/tests/fail/stacked_borrows/buggy_split_at_mut.rs +++ b/tests/fail/stacked_borrows/buggy_split_at_mut.rs @@ -8,14 +8,16 @@ mod safe { unsafe { assert!(mid <= len); - (from_raw_parts_mut(ptr, len - mid), // BUG: should be "mid" instead of "len - mid" - from_raw_parts_mut(ptr.offset(mid as isize), len - mid)) + ( + from_raw_parts_mut(ptr, len - mid), // BUG: should be "mid" instead of "len - mid" + from_raw_parts_mut(ptr.offset(mid as isize), len - mid), + ) } } } fn main() { - let mut array = [1,2,3,4]; + let mut array = [1, 2, 3, 4]; let (a, b) = safe::split_at_mut(&mut array, 0); //~^ ERROR borrow stack a[1] = 5; diff --git a/tests/fail/stacked_borrows/illegal_read6.rs b/tests/fail/stacked_borrows/illegal_read6.rs index dc37814729000..af89566f65074 100644 --- a/tests/fail/stacked_borrows/illegal_read6.rs +++ b/tests/fail/stacked_borrows/illegal_read6.rs @@ -1,8 +1,10 @@ // Creating a shared reference does not leak the data to raw pointers. -fn main() { unsafe { - let x = &mut 0; - let raw = x as *mut _; - let x = &mut *x; // kill `raw` - let _y = &*x; // this should not activate `raw` again - let _val = *raw; //~ ERROR borrow stack -} } +fn main() { + unsafe { + let x = &mut 0; + let raw = x as *mut _; + let x = &mut *x; // kill `raw` + let _y = &*x; // this should not activate `raw` again + let _val = *raw; //~ ERROR borrow stack + } +} diff --git a/tests/fail/stacked_borrows/illegal_read7.rs b/tests/fail/stacked_borrows/illegal_read7.rs index 25d0878c04553..e960bd5388c03 100644 --- a/tests/fail/stacked_borrows/illegal_read7.rs +++ b/tests/fail/stacked_borrows/illegal_read7.rs @@ -4,17 +4,19 @@ use std::cell::Cell; use std::ptr; -fn main() { unsafe { - let x = &mut Cell::new(0); - let raw = x as *mut Cell; - let x = &mut *raw; - let _shr = &*x; - // The state here is interesting because the top of the stack is [Unique, SharedReadWrite], - // just like if we had done `x as *mut _`. - // If we said that reading from a lower item is fine if the top item is `SharedReadWrite` - // (one way to maybe preserve a stack discipline), then we could now read from `raw` - // without invalidating `x`. That would be bad! It would mean that creating `shr` - // leaked `x` to `raw`. - let _val = ptr::read(raw); - let _val = *x.get_mut(); //~ ERROR borrow stack -} } +fn main() { + unsafe { + let x = &mut Cell::new(0); + let raw = x as *mut Cell; + let x = &mut *raw; + let _shr = &*x; + // The state here is interesting because the top of the stack is [Unique, SharedReadWrite], + // just like if we had done `x as *mut _`. + // If we said that reading from a lower item is fine if the top item is `SharedReadWrite` + // (one way to maybe preserve a stack discipline), then we could now read from `raw` + // without invalidating `x`. That would be bad! It would mean that creating `shr` + // leaked `x` to `raw`. + let _val = ptr::read(raw); + let _val = *x.get_mut(); //~ ERROR borrow stack + } +} diff --git a/tests/fail/stacked_borrows/illegal_read8.rs b/tests/fail/stacked_borrows/illegal_read8.rs index 72fca84ba19ba..9fef673fe6c13 100644 --- a/tests/fail/stacked_borrows/illegal_read8.rs +++ b/tests/fail/stacked_borrows/illegal_read8.rs @@ -1,13 +1,15 @@ // Make sure that creating a raw ptr next to a shared ref works // but the shared ref still gets invalidated when the raw ptr is used for writing. -fn main() { unsafe { - use std::mem; - let x = &mut 0; - let y1: &i32 = mem::transmute(&*x); // launder lifetimes - let y2 = x as *mut _; - let _val = *y2; - let _val = *y1; - *y2 += 1; - let _fail = *y1; //~ ERROR borrow stack -} } +fn main() { + unsafe { + use std::mem; + let x = &mut 0; + let y1: &i32 = mem::transmute(&*x); // launder lifetimes + let y2 = x as *mut _; + let _val = *y2; + let _val = *y1; + *y2 += 1; + let _fail = *y1; //~ ERROR borrow stack + } +} diff --git a/tests/fail/stacked_borrows/interior_mut1.rs b/tests/fail/stacked_borrows/interior_mut1.rs index e2f8233bd86b2..1ef78edbb7ce2 100644 --- a/tests/fail/stacked_borrows/interior_mut1.rs +++ b/tests/fail/stacked_borrows/interior_mut1.rs @@ -1,15 +1,17 @@ use std::cell::UnsafeCell; -fn main() { unsafe { - let c = &UnsafeCell::new(UnsafeCell::new(0)); - let inner_uniq = &mut *c.get(); - // stack: [c: SharedReadWrite, inner_uniq: Unique] +fn main() { + unsafe { + let c = &UnsafeCell::new(UnsafeCell::new(0)); + let inner_uniq = &mut *c.get(); + // stack: [c: SharedReadWrite, inner_uniq: Unique] - let inner_shr = &*inner_uniq; // adds a SharedReadWrite - // stack: [c: SharedReadWrite, inner_uniq: Unique, inner_shr: SharedReadWrite] + let inner_shr = &*inner_uniq; // adds a SharedReadWrite + // stack: [c: SharedReadWrite, inner_uniq: Unique, inner_shr: SharedReadWrite] - *c.get() = UnsafeCell::new(1); // invalidates inner_shr - // stack: [c: SharedReadWrite] + *c.get() = UnsafeCell::new(1); // invalidates inner_shr + // stack: [c: SharedReadWrite] - let _val = *inner_shr.get(); //~ ERROR borrow stack -} } + let _val = *inner_shr.get(); //~ ERROR borrow stack + } +} diff --git a/tests/panic/panic/panic1.rs b/tests/panic/panic/panic1.rs index cfaa642beb8e2..e15d7656de834 100644 --- a/tests/panic/panic/panic1.rs +++ b/tests/panic/panic/panic1.rs @@ -1,7 +1,6 @@ // rustc-env: RUST_BACKTRACE=1 // compile-flags: -Zmiri-disable-isolation - fn main() { std::panic!("panicking from libstd"); } diff --git a/tests/panic/transmute_fat2.rs b/tests/panic/transmute_fat2.rs index 2f0271d5813f5..0205433ad9fb9 100644 --- a/tests/panic/transmute_fat2.rs +++ b/tests/panic/transmute_fat2.rs @@ -1,16 +1,10 @@ fn main() { - #[cfg(all(target_endian="little", target_pointer_width="64"))] - let bad = unsafe { - std::mem::transmute::(42) - }; - #[cfg(all(target_endian="big", target_pointer_width="64"))] - let bad = unsafe { - std::mem::transmute::(42 << 64) - }; - #[cfg(all(target_endian="little", target_pointer_width="32"))] - let bad = unsafe { - std::mem::transmute::(42) - }; + #[cfg(all(target_endian = "little", target_pointer_width = "64"))] + let bad = unsafe { std::mem::transmute::(42) }; + #[cfg(all(target_endian = "big", target_pointer_width = "64"))] + let bad = unsafe { std::mem::transmute::(42 << 64) }; + #[cfg(all(target_endian = "little", target_pointer_width = "32"))] + let bad = unsafe { std::mem::transmute::(42) }; // This created a slice with length 0, so the following will fail the bounds check. bad[0]; } diff --git a/tests/pass/stacked-borrows/refcell.rs b/tests/pass/stacked-borrows/refcell.rs index 83db10577cebf..ecb6f48d30b07 100644 --- a/tests/pass/stacked-borrows/refcell.rs +++ b/tests/pass/stacked-borrows/refcell.rs @@ -1,4 +1,4 @@ -use std::cell::{RefCell, Ref, RefMut}; +use std::cell::{Ref, RefCell, RefMut}; fn main() { basic(); @@ -70,8 +70,8 @@ fn ref_mut_protector() { /// Make sure we do not have bad enum layout optimizations. fn rust_issue_68303() { - let optional=Some(RefCell::new(false)); - let mut handle=optional.as_ref().unwrap().borrow_mut(); + let optional = Some(RefCell::new(false)); + let mut handle = optional.as_ref().unwrap().borrow_mut(); assert!(optional.is_some()); - *handle=true; + *handle = true; } diff --git a/tests/pass/stacked-borrows/stacked-borrows.rs b/tests/pass/stacked-borrows/stacked-borrows.rs index 80bab726a8f15..131783ef4fb58 100644 --- a/tests/pass/stacked-borrows/stacked-borrows.rs +++ b/tests/pass/stacked-borrows/stacked-borrows.rs @@ -50,7 +50,9 @@ fn mut_raw_then_mut_shr() { let xraw = &mut *xref as *mut _; let xshr = &*xref; assert_eq!(*xshr, 2); - unsafe { *xraw = 4; } + unsafe { + *xraw = 4; + } assert_eq!(x, 4); } @@ -60,7 +62,9 @@ fn mut_shr_then_mut_raw() { let xref = &mut 2; let _xshr = &*xref; let xraw = xref as *mut _; - unsafe { *xraw = 3; } + unsafe { + *xraw = 3; + } assert_eq!(*xref, 3); } @@ -75,7 +79,9 @@ fn mut_raw_mut() { let xraw = xref1 as *mut _; let _xref2 = unsafe { &mut *xraw }; let _val = *xref1; - unsafe { *xraw = 4; } + unsafe { + *xraw = 4; + } // we can now use both xraw and xref1, for reading assert_eq!(*xref1, 4); assert_eq!(unsafe { *xraw }, 4); @@ -112,23 +118,27 @@ fn direct_mut_to_const_raw() { } // Make sure that we can create two raw pointers from a mutable reference and use them both. -fn two_raw() { unsafe { - let x = &mut 0; - let y1 = x as *mut _; - let y2 = x as *mut _; - *y1 += 2; - *y2 += 1; -} } +fn two_raw() { + unsafe { + let x = &mut 0; + let y1 = x as *mut _; + let y2 = x as *mut _; + *y1 += 2; + *y2 += 1; + } +} // Make sure that creating a *mut does not invalidate existing shared references. -fn shr_and_raw() { unsafe { - use std::mem; - let x = &mut 0; - let y1: &i32 = mem::transmute(&*x); // launder lifetimes - let y2 = x as *mut _; - let _val = *y1; - *y2 += 1; -} } +fn shr_and_raw() { + unsafe { + use std::mem; + let x = &mut 0; + let y1: &i32 = mem::transmute(&*x); // launder lifetimes + let y2 = x as *mut _; + let _val = *y1; + *y2 += 1; + } +} fn disjoint_mutable_subborrows() { struct Foo { @@ -136,23 +146,20 @@ fn disjoint_mutable_subborrows() { b: Vec, } - unsafe fn borrow_field_a<'a>(this:*mut Foo) -> &'a mut String { + unsafe fn borrow_field_a<'a>(this: *mut Foo) -> &'a mut String { &mut (*this).a } - unsafe fn borrow_field_b<'a>(this:*mut Foo) -> &'a mut Vec { + unsafe fn borrow_field_b<'a>(this: *mut Foo) -> &'a mut Vec { &mut (*this).b } - let mut foo = Foo { - a: "hello".into(), - b: vec![0,1,2], - }; + let mut foo = Foo { a: "hello".into(), b: vec![0, 1, 2] }; let ptr = &mut foo as *mut Foo; - let a = unsafe{ borrow_field_a(ptr) }; - let b = unsafe{ borrow_field_b(ptr) }; + let a = unsafe { borrow_field_a(ptr) }; + let b = unsafe { borrow_field_b(ptr) }; b.push(4); a.push_str(" world"); eprintln!("{:?} {:?}", a, b); @@ -181,7 +188,9 @@ fn raw_ref_to_part() { fn array_casts() { let mut x: [usize; 2] = [0, 0]; let p = &mut x as *mut usize; - unsafe { *p.add(1) = 1; } + unsafe { + *p.add(1) = 1; + } let x: [usize; 2] = [0, 1]; let p = &x as *const usize; @@ -192,7 +201,7 @@ fn array_casts() { fn mut_below_shr() { let x = 0; let y = &x; - let p = unsafe { core::mem::transmute::<&&i32,&&mut i32>(&y) }; + let p = unsafe { core::mem::transmute::<&&i32, &&mut i32>(&y) }; let r = &**p; let _val = *r; } diff --git a/tests/pass/static_memory_modification.rs b/tests/pass/static_memory_modification.rs index 6a41078177983..84a524b1ed163 100644 --- a/tests/pass/static_memory_modification.rs +++ b/tests/pass/static_memory_modification.rs @@ -1,4 +1,4 @@ -use std::sync::atomic::{Ordering, AtomicUsize}; +use std::sync::atomic::{AtomicUsize, Ordering}; static mut X: usize = 5; static Y: AtomicUsize = AtomicUsize::new(5); diff --git a/tests/pass/static_mut.rs b/tests/pass/static_mut.rs index 0aa6a2e92b624..218b02525bd55 100644 --- a/tests/pass/static_mut.rs +++ b/tests/pass/static_mut.rs @@ -1,5 +1,5 @@ static mut FOO: i32 = 42; -static BAR: Foo = Foo(unsafe { &FOO as *const _} ); +static BAR: Foo = Foo(unsafe { &FOO as *const _ }); #[allow(dead_code)] struct Foo(*const i32); diff --git a/tests/pass/strings.rs b/tests/pass/strings.rs index 77ecaed4fe9b8..ccefc69bd180e 100644 --- a/tests/pass/strings.rs +++ b/tests/pass/strings.rs @@ -22,7 +22,7 @@ fn fat_pointer_on_32_bit() { fn str_indexing() { let mut x = "Hello".to_string(); - let _v = &mut x[..3]; // Test IndexMut on String. + let _v = &mut x[..3]; // Test IndexMut on String. } fn unique_aliasing() { diff --git a/tests/pass/tag-align-dyn-u64.rs b/tests/pass/tag-align-dyn-u64.rs index 460c2b25594af..72211a8d3f3af 100644 --- a/tests/pass/tag-align-dyn-u64.rs +++ b/tests/pass/tag-align-dyn-u64.rs @@ -11,17 +11,17 @@ use std::mem; enum Tag { - Tag2(A) + Tag2(A), } #[allow(dead_code)] struct Rec { c8: u8, - t: Tag + t: Tag, } fn mk_rec() -> Rec { - return Rec { c8:0, t:Tag::Tag2(0) }; + return Rec { c8: 0, t: Tag::Tag2(0) }; } fn is_u64_aligned(u: &Tag) -> bool { diff --git a/tests/pass/time.rs b/tests/pass/time.rs index cce29003e5676..38e846309d728 100644 --- a/tests/pass/time.rs +++ b/tests/pass/time.rs @@ -1,6 +1,6 @@ // compile-flags: -Zmiri-disable-isolation -use std::time::{SystemTime, Instant, Duration}; +use std::time::{Duration, Instant, SystemTime}; fn duration_sanity(diff: Duration) { // On my laptop, I observed times around 15-40ms. Add 10x lee-way both ways. @@ -25,7 +25,9 @@ fn main() { let year = 1970 + years_since_epoch; assert!(2020 <= year && year < 2100); // Do some work to make time pass. - for _ in 0..10 { drop(vec![42]); } + for _ in 0..10 { + drop(vec![42]); + } let now2 = SystemTime::now(); assert!(now2 > now1); // Sanity-check the difference we got. @@ -37,7 +39,9 @@ fn main() { // Check `Instant`. let now1 = Instant::now(); // Do some work to make time pass. - for _ in 0..10 { drop(vec![42]); } + for _ in 0..10 { + drop(vec![42]); + } let now2 = Instant::now(); assert!(now2 > now1); // Sanity-check the difference we got. diff --git a/tests/pass/track-caller-attribute.rs b/tests/pass/track-caller-attribute.rs index d1115faa8f756..dd1e2f809adfe 100644 --- a/tests/pass/track-caller-attribute.rs +++ b/tests/pass/track-caller-attribute.rs @@ -16,7 +16,9 @@ fn nested_tracked() -> &'static Location<'static> { } macro_rules! caller_location_from_macro { - () => (core::panic::Location::caller()); + () => { + core::panic::Location::caller() + }; } fn test_fn_ptr() { @@ -62,7 +64,6 @@ fn test_trait_obj() { assert_eq!(location.file(), file!()); assert_eq!(location.line(), expected_line); assert_eq!(location.column(), 28); - } fn main() { diff --git a/tests/pass/transmute_fat.rs b/tests/pass/transmute_fat.rs index c62298a9aced2..1d2ec92a80389 100644 --- a/tests/pass/transmute_fat.rs +++ b/tests/pass/transmute_fat.rs @@ -3,9 +3,7 @@ fn main() { // If we are careful, we can exploit data layout... - let raw = unsafe { - std::mem::transmute::<&[u8], [*const u8; 2]>(&[42]) - }; + let raw = unsafe { std::mem::transmute::<&[u8], [*const u8; 2]>(&[42]) }; let ptr: *const u8 = unsafe { std::mem::transmute_copy(&raw) }; assert_eq!(unsafe { *ptr }, 42); } diff --git a/tests/pass/u128.rs b/tests/pass/u128.rs index fae73476275b3..c327b5cab3d86 100644 --- a/tests/pass/u128.rs +++ b/tests/pass/u128.rs @@ -8,9 +8,10 @@ fn main() { let y: u128 = 0xFFFF_FFFF_FFFF_FFFF__FFFF_FFFF_FFFF_FFFE; assert_eq!(!1, y); assert_eq!(x, y | 1); - assert_eq!(0xFAFF_0000_FF8F_0000__FFFF_0000_FFFF_FFFE, - y & - 0xFAFF_0000_FF8F_0000__FFFF_0000_FFFF_FFFF); + assert_eq!( + 0xFAFF_0000_FF8F_0000__FFFF_0000_FFFF_FFFE, + y & 0xFAFF_0000_FF8F_0000__FFFF_0000_FFFF_FFFF + ); let z: u128 = 0xABCD_EF; assert_eq!(z * z, 0x734C_C2F2_A521); assert_eq!(z * z * z * z, 0x33EE_0E2A_54E2_59DA_A0E7_8E41); @@ -19,8 +20,10 @@ fn main() { assert_eq!(k + k, 0x2468_ACF1_3579_BDFF_DB97_530E_CA86_420); assert_eq!(0, k - k); assert_eq!(0x1234_5678_9ABC_DEFF_EDCB_A987_5A86_421, k - z); - assert_eq!(0x1000_0000_0000_0000_0000_0000_0000_000, - k - 0x234_5678_9ABC_DEFF_EDCB_A987_6543_210); + assert_eq!( + 0x1000_0000_0000_0000_0000_0000_0000_000, + k - 0x234_5678_9ABC_DEFF_EDCB_A987_6543_210 + ); assert_eq!(0x6EF5_DE4C_D3BC_2AAA_3BB4_CC5D_D6EE_8, k / 42); assert_eq!(0, k % 42); assert_eq!(15, z % 42); @@ -38,7 +41,7 @@ fn main() { assert_eq!((z as f32) as u128, z); assert_eq!((z as f64 * 16.0) as u128, z * 16); assert_eq!((z as f32 * 16.0) as u128, z * 16); - let l :u128 = 432 << 100; + let l: u128 = 432 << 100; assert_eq!((l as f32) as u128, l); assert_eq!((l as f64) as u128, l); // formatting @@ -46,10 +49,11 @@ fn main() { assert_eq!("147573952589676412928", format!("{}", j)); assert_eq!("80000000000000000", format!("{:x}", j)); assert_eq!("20000000000000000000000", format!("{:o}", j)); - assert_eq!("10000000000000000000000000000000000000000000000000000000000000000000", - format!("{:b}", j)); - assert_eq!("340282366920938463463374607431768211455", - format!("{}", u128::MAX)); + assert_eq!( + "10000000000000000000000000000000000000000000000000000000000000000000", + format!("{:b}", j) + ); + assert_eq!("340282366920938463463374607431768211455", format!("{}", u128::MAX)); assert_eq!("147573952589676412928", format!("{:?}", j)); // common traits assert_eq!(x, b(x.clone())); diff --git a/tests/pass/union.rs b/tests/pass/union.rs index c80918ee527c2..bf7a7b828175d 100644 --- a/tests/pass/union.rs +++ b/tests/pass/union.rs @@ -45,7 +45,10 @@ fn b() { fn c() { #[repr(u32)] - enum Tag { I, F } + enum Tag { + I, + F, + } #[repr(C)] union U { @@ -68,10 +71,10 @@ fn c() { } } } - assert!(is_zero(Value { tag: Tag::I, u: U { i: 0 }})); - assert!(is_zero(Value { tag: Tag::F, u: U { f: 0.0 }})); - assert!(!is_zero(Value { tag: Tag::I, u: U { i: 1 }})); - assert!(!is_zero(Value { tag: Tag::F, u: U { f: 42.0 }})); + assert!(is_zero(Value { tag: Tag::I, u: U { i: 0 } })); + assert!(is_zero(Value { tag: Tag::F, u: U { f: 0.0 } })); + assert!(!is_zero(Value { tag: Tag::I, u: U { i: 1 } })); + assert!(!is_zero(Value { tag: Tag::F, u: U { f: 42.0 } })); } fn d() { @@ -82,8 +85,10 @@ fn d() { let u = MyUnion { f1: 10 }; unsafe { match u { - MyUnion { f1: 10 } => { } - MyUnion { f2: _f2 } => { panic!("foo"); } + MyUnion { f1: 10 } => {} + MyUnion { f2: _f2 } => { + panic!("foo"); + } } } } diff --git a/tests/pass/unops.rs b/tests/pass/unops.rs index 650c51ba5d997..f23f68ccbad00 100644 --- a/tests/pass/unops.rs +++ b/tests/pass/unops.rs @@ -1,5 +1,5 @@ fn main() { assert_eq!(!true, false); assert_eq!(!0xFFu16, 0xFF00); - assert_eq!(-{1i16}, -1i16); + assert_eq!(-{ 1i16 }, -1i16); } diff --git a/tests/pass/unsized-tuple-impls.rs b/tests/pass/unsized-tuple-impls.rs index 54bd6f5c34f83..bbab1125a0afd 100644 --- a/tests/pass/unsized-tuple-impls.rs +++ b/tests/pass/unsized-tuple-impls.rs @@ -2,8 +2,8 @@ use std::mem; fn main() { - let x : &(i32, i32, [i32]) = &(0, 1, [2, 3]); - let y : &(i32, i32, [i32]) = &(0, 1, [2, 3, 4]); + let x: &(i32, i32, [i32]) = &(0, 1, [2, 3]); + let y: &(i32, i32, [i32]) = &(0, 1, [2, 3, 4]); let mut a = [y, x]; a.sort(); assert_eq!(a, [x, y]); diff --git a/tests/pass/validation_lifetime_resolution.rs b/tests/pass/validation_lifetime_resolution.rs index a0eea517095bf..f5eef2ad6e753 100644 --- a/tests/pass/validation_lifetime_resolution.rs +++ b/tests/pass/validation_lifetime_resolution.rs @@ -7,16 +7,22 @@ trait Id { impl<'a> Id for &'a mut i32 { type Out = &'a mut i32; - fn id(self) -> Self { self } + fn id(self) -> Self { + self + } } impl<'a> Id for &'a mut u32 { type Out = &'a mut u32; - fn id(self) -> Self { self } + fn id(self) -> Self { + self + } } -fn foo(mut x: T) where for<'a> &'a mut T: Id +fn foo(mut x: T) +where + for<'a> &'a mut T: Id, { let x = &mut x; let _y = x.id(); diff --git a/tests/pass/vec-matching-fold.rs b/tests/pass/vec-matching-fold.rs index 749f93fc0fd2c..3a869703bf96a 100644 --- a/tests/pass/vec-matching-fold.rs +++ b/tests/pass/vec-matching-fold.rs @@ -1,32 +1,30 @@ use std::fmt::Debug; -fn foldl(values: &[T], - initial: U, - mut function: F) - -> U where - U: Clone+Debug, T:Debug, +fn foldl(values: &[T], initial: U, mut function: F) -> U +where + U: Clone + Debug, + T: Debug, F: FnMut(U, &T) -> U, -{ match values { - [head, tail @ ..] => - foldl(tail, function(initial, head), function), +{ + match values { + [head, tail @ ..] => foldl(tail, function(initial, head), function), [] => { - let res = initial.clone(); res + let res = initial.clone(); + res } } } -fn foldr(values: &[T], - initial: U, - mut function: F) - -> U where +fn foldr(values: &[T], initial: U, mut function: F) -> U +where U: Clone, F: FnMut(&T, U) -> U, { match values { - [head @ .., tail] => - foldr(head, function(tail, initial), function), + [head @ .., tail] => foldr(head, function(tail, initial), function), [] => { - let res = initial.clone(); res + let res = initial.clone(); + res } } } diff --git a/tests/pass/vec.rs b/tests/pass/vec.rs index 788f05ce97741..89c2561acd970 100644 --- a/tests/pass/vec.rs +++ b/tests/pass/vec.rs @@ -33,51 +33,37 @@ fn make_vec_macro_repeat_zeroed() -> Vec { } fn vec_into_iter() -> u8 { - vec![1, 2, 3, 4] - .into_iter() - .map(|x| x * x) - .fold(0, |x, y| x + y) + vec![1, 2, 3, 4].into_iter().map(|x| x * x).fold(0, |x, y| x + y) } fn vec_into_iter_rev() -> u8 { - vec![1, 2, 3, 4] - .into_iter() - .map(|x| x * x) - .fold(0, |x, y| x + y) + vec![1, 2, 3, 4].into_iter().map(|x| x * x).fold(0, |x, y| x + y) } fn vec_into_iter_zst() -> usize { - vec![[0u64; 0], [0u64; 0]] - .into_iter() - .rev() - .map(|x| x.len()) - .sum() + vec![[0u64; 0], [0u64; 0]].into_iter().rev().map(|x| x.len()).sum() } fn vec_into_iter_rev_zst() -> usize { - vec![[0u64; 0], [0u64; 0]] - .into_iter() - .rev() - .map(|x| x.len()) - .sum() + vec![[0u64; 0], [0u64; 0]].into_iter().rev().map(|x| x.len()).sum() } fn vec_iter_and_mut() { - let mut v = vec![1,2,3,4]; + let mut v = vec![1, 2, 3, 4]; for i in v.iter_mut() { *i += 1; } - assert_eq!(v.iter().sum::(), 2+3+4+5); + assert_eq!(v.iter().sum::(), 2 + 3 + 4 + 5); test_all_refs(&mut 13, v.iter_mut()); } fn vec_iter_and_mut_rev() { - let mut v = vec![1,2,3,4]; + let mut v = vec![1, 2, 3, 4]; for i in v.iter_mut().rev() { *i += 1; } - assert_eq!(v.iter().sum::(), 2+3+4+5); + assert_eq!(v.iter().sum::(), 2 + 3 + 4 + 5); } fn vec_reallocate() -> Vec { diff --git a/tests/pass/vecdeque.rs b/tests/pass/vecdeque.rs index fa6707632dc76..d2295a7afb599 100644 --- a/tests/pass/vecdeque.rs +++ b/tests/pass/vecdeque.rs @@ -23,7 +23,7 @@ fn main() { src.push_front(Box::new(2)); dst.append(&mut src); for a in dst.iter() { - assert_eq!(**a, 2); + assert_eq!(**a, 2); } // Regression test for Debug impl's diff --git a/tests/pass/weak_memory/weak.rs b/tests/pass/weak_memory/weak.rs index e1e9c41e36f5d..b9ceb61f0c9fc 100644 --- a/tests/pass/weak_memory/weak.rs +++ b/tests/pass/weak_memory/weak.rs @@ -94,7 +94,6 @@ fn initialization_write() -> bool { r2 == 11 } - // Asserts that the function returns true at least once in 100 runs macro_rules! assert_once { ($f:ident) => { diff --git a/tests/pass/wtf8.rs b/tests/pass/wtf8.rs index 5a58150680817..e31b00e95244e 100644 --- a/tests/pass/wtf8.rs +++ b/tests/pass/wtf8.rs @@ -1,7 +1,7 @@ // only-windows -use std::os::windows::ffi::{OsStrExt, OsStringExt}; use std::ffi::{OsStr, OsString}; +use std::os::windows::ffi::{OsStrExt, OsStringExt}; fn test1() { let base = "a\té \u{7f}💩\r"; diff --git a/tests/pass/zst.rs b/tests/pass/zst.rs index 9884735709139..3a853e7d8a68f 100644 --- a/tests/pass/zst.rs +++ b/tests/pass/zst.rs @@ -19,6 +19,10 @@ fn main() { assert_eq!(use_zst(), A); let x = 42 as *mut [u8; 0]; // Reading and writing is ok. - unsafe { *x = zst_val; } - unsafe { let _y = *x; } + unsafe { + *x = zst_val; + } + unsafe { + let _y = *x; + } } From 30376ba709ef627d09a0ff365cd76ec58f329880 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Mon, 20 Jun 2022 23:45:49 -0700 Subject: [PATCH 3277/3747] Manual adjustments --- tests/pass/u128.rs | 6 +++--- tests/pass/union.rs | 4 +--- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/tests/pass/u128.rs b/tests/pass/u128.rs index c327b5cab3d86..0ef7a514cb653 100644 --- a/tests/pass/u128.rs +++ b/tests/pass/u128.rs @@ -10,7 +10,7 @@ fn main() { assert_eq!(x, y | 1); assert_eq!( 0xFAFF_0000_FF8F_0000__FFFF_0000_FFFF_FFFE, - y & 0xFAFF_0000_FF8F_0000__FFFF_0000_FFFF_FFFF + y & 0xFAFF_0000_FF8F_0000__FFFF_0000_FFFF_FFFF, ); let z: u128 = 0xABCD_EF; assert_eq!(z * z, 0x734C_C2F2_A521); @@ -22,7 +22,7 @@ fn main() { assert_eq!(0x1234_5678_9ABC_DEFF_EDCB_A987_5A86_421, k - z); assert_eq!( 0x1000_0000_0000_0000_0000_0000_0000_000, - k - 0x234_5678_9ABC_DEFF_EDCB_A987_6543_210 + k - 0x234_5678_9ABC_DEFF_EDCB_A987_6543_210, ); assert_eq!(0x6EF5_DE4C_D3BC_2AAA_3BB4_CC5D_D6EE_8, k / 42); assert_eq!(0, k % 42); @@ -51,7 +51,7 @@ fn main() { assert_eq!("20000000000000000000000", format!("{:o}", j)); assert_eq!( "10000000000000000000000000000000000000000000000000000000000000000000", - format!("{:b}", j) + format!("{:b}", j), ); assert_eq!("340282366920938463463374607431768211455", format!("{}", u128::MAX)); assert_eq!("147573952589676412928", format!("{:?}", j)); diff --git a/tests/pass/union.rs b/tests/pass/union.rs index bf7a7b828175d..f98a213102851 100644 --- a/tests/pass/union.rs +++ b/tests/pass/union.rs @@ -86,9 +86,7 @@ fn d() { unsafe { match u { MyUnion { f1: 10 } => {} - MyUnion { f2: _f2 } => { - panic!("foo"); - } + MyUnion { f2: _f2 } => panic!("foo"), } } } From 1c66163871fc0c88bdfa435b8c5d6aedf2a3d4c7 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Mon, 20 Jun 2022 23:49:55 -0700 Subject: [PATCH 3278/3747] Bless stderr files after rustfmt --- tests/fail/intrinsics/simd-rem-by-zero.stderr | 4 ++-- tests/fail/intrinsics/simd-scatter.stderr | 8 ++++++-- .../simd-select-bitmask-invalid.stderr | 4 ++-- .../simd-select-invalid-bool.stderr | 4 ++-- tests/fail/intrinsics/simd-shl-too-far.stderr | 4 ++-- tests/fail/intrinsics/simd-shr-too-far.stderr | 4 ++-- tests/fail/should-pass/cpp20_rwc_syncs.stderr | 4 ++-- .../alias_through_mutation.stderr | 4 ++-- .../box_exclusive_violation1.stderr | 20 +++++++++---------- .../stacked_borrows/buggy_as_mut_slice.stderr | 4 ++-- .../stacked_borrows/buggy_split_at_mut.stderr | 8 ++++---- .../fail/stacked_borrows/illegal_read6.stderr | 18 ++++++++--------- .../fail/stacked_borrows/illegal_read7.stderr | 18 ++++++++--------- .../fail/stacked_borrows/illegal_read8.stderr | 18 ++++++++--------- .../fail/stacked_borrows/interior_mut1.stderr | 18 ++++++++--------- 15 files changed, 72 insertions(+), 68 deletions(-) diff --git a/tests/fail/intrinsics/simd-rem-by-zero.stderr b/tests/fail/intrinsics/simd-rem-by-zero.stderr index 98e5ca2079721..1adc9f8235eef 100644 --- a/tests/fail/intrinsics/simd-rem-by-zero.stderr +++ b/tests/fail/intrinsics/simd-rem-by-zero.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: calculating the remainder with a divisor of zero --> $DIR/simd-rem-by-zero.rs:LL:CC | -LL | simd_rem(x, y); - | ^^^^^^^^^^^^^^ calculating the remainder with a divisor of zero +LL | simd_rem(x, y); + | ^^^^^^^^^^^^^^ calculating the remainder with a divisor of zero | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/intrinsics/simd-scatter.stderr b/tests/fail/intrinsics/simd-scatter.stderr index 08536c6112555..bc6a06fc88e52 100644 --- a/tests/fail/intrinsics/simd-scatter.stderr +++ b/tests/fail/intrinsics/simd-scatter.stderr @@ -11,8 +11,12 @@ LL | intrinsics::simd_scatter(self, ptrs, enable.to_int()) note: inside `main` at $DIR/simd-scatter.rs:LL:CC --> $DIR/simd-scatter.rs:LL:CC | -LL | Simd::from_array([-27, 82, -41, 124]).scatter_select_unchecked(&mut vec, Mask::splat(true), idxs); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | / Simd::from_array([-27, 82, -41, 124]).scatter_select_unchecked( +LL | | &mut vec, +LL | | Mask::splat(true), +LL | | idxs, +LL | | ); + | |_________^ note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/simd-select-bitmask-invalid.stderr b/tests/fail/intrinsics/simd-select-bitmask-invalid.stderr index e5fe3c886cb84..0a72ed39827b2 100644 --- a/tests/fail/intrinsics/simd-select-bitmask-invalid.stderr +++ b/tests/fail/intrinsics/simd-select-bitmask-invalid.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: a SIMD bitmask less than 8 bits long must be filled with 0s for the remaining bits --> $DIR/simd-select-bitmask-invalid.rs:LL:CC | -LL | simd_select_bitmask(0b11111111u8, x, x); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ a SIMD bitmask less than 8 bits long must be filled with 0s for the remaining bits +LL | simd_select_bitmask(0b11111111u8, x, x); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ a SIMD bitmask less than 8 bits long must be filled with 0s for the remaining bits | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/intrinsics/simd-select-invalid-bool.stderr b/tests/fail/intrinsics/simd-select-invalid-bool.stderr index f0a1282edac46..c0ceaac06cddf 100644 --- a/tests/fail/intrinsics/simd-select-invalid-bool.stderr +++ b/tests/fail/intrinsics/simd-select-invalid-bool.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: each element of a SIMD mask must be all-0-bits or all-1-bits --> $DIR/simd-select-invalid-bool.rs:LL:CC | -LL | simd_select(x, x, x); - | ^^^^^^^^^^^^^^^^^^^^ each element of a SIMD mask must be all-0-bits or all-1-bits +LL | simd_select(x, x, x); + | ^^^^^^^^^^^^^^^^^^^^ each element of a SIMD mask must be all-0-bits or all-1-bits | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/intrinsics/simd-shl-too-far.stderr b/tests/fail/intrinsics/simd-shl-too-far.stderr index dcd38d6f01140..1d990e341e68d 100644 --- a/tests/fail/intrinsics/simd-shl-too-far.stderr +++ b/tests/fail/intrinsics/simd-shl-too-far.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: overflowing shift by 100 in `simd_shl` in SIMD lane 0 --> $DIR/simd-shl-too-far.rs:LL:CC | -LL | simd_shl(x, y); - | ^^^^^^^^^^^^^^ overflowing shift by 100 in `simd_shl` in SIMD lane 0 +LL | simd_shl(x, y); + | ^^^^^^^^^^^^^^ overflowing shift by 100 in `simd_shl` in SIMD lane 0 | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/intrinsics/simd-shr-too-far.stderr b/tests/fail/intrinsics/simd-shr-too-far.stderr index c2c2850522f5a..58ef3737545aa 100644 --- a/tests/fail/intrinsics/simd-shr-too-far.stderr +++ b/tests/fail/intrinsics/simd-shr-too-far.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: overflowing shift by 40 in `simd_shr` in SIMD lane 1 --> $DIR/simd-shr-too-far.rs:LL:CC | -LL | simd_shr(x, y); - | ^^^^^^^^^^^^^^ overflowing shift by 40 in `simd_shr` in SIMD lane 1 +LL | simd_shr(x, y); + | ^^^^^^^^^^^^^^ overflowing shift by 40 in `simd_shr` in SIMD lane 1 | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/should-pass/cpp20_rwc_syncs.stderr b/tests/fail/should-pass/cpp20_rwc_syncs.stderr index 9aec82d333654..5f0e86dc653ec 100644 --- a/tests/fail/should-pass/cpp20_rwc_syncs.stderr +++ b/tests/fail/should-pass/cpp20_rwc_syncs.stderr @@ -11,8 +11,8 @@ LL | unsafe { intrinsics::unreachable() } note: inside `test_cpp20_rwc_syncs` at $DIR/cpp20_rwc_syncs.rs:LL:CC --> $DIR/cpp20_rwc_syncs.rs:LL:CC | -LL | unsafe { std::hint::unreachable_unchecked(); } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | std::hint::unreachable_unchecked(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ note: inside `main` at $DIR/cpp20_rwc_syncs.rs:LL:CC --> $DIR/cpp20_rwc_syncs.rs:LL:CC | diff --git a/tests/fail/stacked_borrows/alias_through_mutation.stderr b/tests/fail/stacked_borrows/alias_through_mutation.stderr index 610a045efcf24..eb02136478f2b 100644 --- a/tests/fail/stacked_borrows/alias_through_mutation.stderr +++ b/tests/fail/stacked_borrows/alias_through_mutation.stderr @@ -12,8 +12,8 @@ LL | let _val = *target_alias; help: was created by a retag at offsets [0x0..0x4] --> $DIR/alias_through_mutation.rs:LL:CC | -LL | unsafe { *x = &mut *(target as *mut _); } - | ^^^^^^^^^^^^^^^^^^^^^^^^ +LL | *x = &mut *(target as *mut _); + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: was later invalidated at offsets [0x0..0x4] --> $DIR/alias_through_mutation.rs:LL:CC | diff --git a/tests/fail/stacked_borrows/box_exclusive_violation1.stderr b/tests/fail/stacked_borrows/box_exclusive_violation1.stderr index 90d9451285786..3c3e6bbf1bc72 100644 --- a/tests/fail/stacked_borrows/box_exclusive_violation1.stderr +++ b/tests/fail/stacked_borrows/box_exclusive_violation1.stderr @@ -1,11 +1,11 @@ error: Undefined Behavior: attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location --> $DIR/box_exclusive_violation1.rs:LL:CC | -LL | *our - | ^^^^ - | | - | attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location - | this error occurs as part of an access at ALLOC[0x0..0x4] +LL | *our + | ^^^^ + | | + | attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | this error occurs as part of an access at ALLOC[0x0..0x4] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information @@ -13,18 +13,18 @@ help: was created by a retag at offsets [0x0..0x4] --> $DIR/box_exclusive_violation1.rs:LL:CC | LL | / fn demo_mut_advanced_unique(mut our: Box) -> i32 { -LL | | unknown_code_1(&*our); +LL | | unknown_code_1(&*our); LL | | -LL | | // This "re-asserts" uniqueness of the reference: After writing, we know +LL | | // This "re-asserts" uniqueness of the reference: After writing, we know ... | -LL | | *our +LL | | *our LL | | } | |_^ help: was later invalidated at offsets [0x0..0x4] --> $DIR/box_exclusive_violation1.rs:LL:CC | -LL | *LEAK = 7; - | ^^^^^^^^^ +LL | *LEAK = 7; + | ^^^^^^^^^ = note: inside `demo_mut_advanced_unique` at $DIR/box_exclusive_violation1.rs:LL:CC note: inside `main` at $DIR/box_exclusive_violation1.rs:LL:CC --> $DIR/box_exclusive_violation1.rs:LL:CC diff --git a/tests/fail/stacked_borrows/buggy_as_mut_slice.stderr b/tests/fail/stacked_borrows/buggy_as_mut_slice.stderr index b65e49fd4a7d0..14cede13b7a18 100644 --- a/tests/fail/stacked_borrows/buggy_as_mut_slice.stderr +++ b/tests/fail/stacked_borrows/buggy_as_mut_slice.stderr @@ -17,8 +17,8 @@ LL | let v1 = safe::as_mut_slice(&v); help: was later invalidated at offsets [0x0..0xc] --> $DIR/buggy_as_mut_slice.rs:LL:CC | -LL | from_raw_parts_mut(self_.as_ptr() as *mut T, self_.len()) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | unsafe { from_raw_parts_mut(self_.as_ptr() as *mut T, self_.len()) } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: inside `main` at $DIR/buggy_as_mut_slice.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/buggy_split_at_mut.stderr b/tests/fail/stacked_borrows/buggy_split_at_mut.stderr index 1b2536c48e045..47ab7d6a062a7 100644 --- a/tests/fail/stacked_borrows/buggy_split_at_mut.stderr +++ b/tests/fail/stacked_borrows/buggy_split_at_mut.stderr @@ -12,13 +12,13 @@ LL | let (a, b) = safe::split_at_mut(&mut array, 0); help: was created by a retag at offsets [0x0..0x10] --> $DIR/buggy_split_at_mut.rs:LL:CC | -LL | (from_raw_parts_mut(ptr, len - mid), // BUG: should be "mid" instead of "len - mid" - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | from_raw_parts_mut(ptr, len - mid), // BUG: should be "mid" instead of "len - mid" + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: was later invalidated at offsets [0x0..0x10] --> $DIR/buggy_split_at_mut.rs:LL:CC | -LL | from_raw_parts_mut(ptr.offset(mid as isize), len - mid)) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | from_raw_parts_mut(ptr.offset(mid as isize), len - mid), + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: inside `main` at $DIR/buggy_split_at_mut.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/illegal_read6.stderr b/tests/fail/stacked_borrows/illegal_read6.stderr index 499f060c47c24..9782f1aa3a58d 100644 --- a/tests/fail/stacked_borrows/illegal_read6.stderr +++ b/tests/fail/stacked_borrows/illegal_read6.stderr @@ -1,24 +1,24 @@ error: Undefined Behavior: attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location --> $DIR/illegal_read6.rs:LL:CC | -LL | let _val = *raw; - | ^^^^ - | | - | attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location - | this error occurs as part of an access at ALLOC[0x0..0x4] +LL | let _val = *raw; + | ^^^^ + | | + | attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | this error occurs as part of an access at ALLOC[0x0..0x4] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: tag was most recently created at offsets [0x0..0x4] --> $DIR/illegal_read6.rs:LL:CC | -LL | let raw = x as *mut _; - | ^ +LL | let raw = x as *mut _; + | ^ help: tag was later invalidated at offsets [0x0..0x4] --> $DIR/illegal_read6.rs:LL:CC | -LL | let x = &mut *x; // kill `raw` - | ^^^^^^^ +LL | let x = &mut *x; // kill `raw` + | ^^^^^^^ = note: inside `main` at $DIR/illegal_read6.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/illegal_read7.stderr b/tests/fail/stacked_borrows/illegal_read7.stderr index e7e1685964bca..3d70945fa6c63 100644 --- a/tests/fail/stacked_borrows/illegal_read7.stderr +++ b/tests/fail/stacked_borrows/illegal_read7.stderr @@ -1,24 +1,24 @@ error: Undefined Behavior: trying to reborrow for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location --> $DIR/illegal_read7.rs:LL:CC | -LL | let _val = *x.get_mut(); - | ^^^^^^^^^^^ - | | - | trying to reborrow for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location - | this error occurs as part of a reborrow at ALLOC[0x0..0x4] +LL | let _val = *x.get_mut(); + | ^^^^^^^^^^^ + | | + | trying to reborrow for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | this error occurs as part of a reborrow at ALLOC[0x0..0x4] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: was created by a retag at offsets [0x0..0x4] --> $DIR/illegal_read7.rs:LL:CC | -LL | let x = &mut *raw; - | ^^^^^^^^^ +LL | let x = &mut *raw; + | ^^^^^^^^^ help: was later invalidated at offsets [0x0..0x4] --> $DIR/illegal_read7.rs:LL:CC | -LL | let _val = ptr::read(raw); - | ^^^^^^^^^^^^^^ +LL | let _val = ptr::read(raw); + | ^^^^^^^^^^^^^^ = note: inside `main` at $DIR/illegal_read7.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/illegal_read8.stderr b/tests/fail/stacked_borrows/illegal_read8.stderr index 21df77775c8b4..7c0cb0066b270 100644 --- a/tests/fail/stacked_borrows/illegal_read8.stderr +++ b/tests/fail/stacked_borrows/illegal_read8.stderr @@ -1,24 +1,24 @@ error: Undefined Behavior: attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location --> $DIR/illegal_read8.rs:LL:CC | -LL | let _fail = *y1; - | ^^^ - | | - | attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location - | this error occurs as part of an access at ALLOC[0x0..0x4] +LL | let _fail = *y1; + | ^^^ + | | + | attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | this error occurs as part of an access at ALLOC[0x0..0x4] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: was created by a retag at offsets [0x0..0x4] --> $DIR/illegal_read8.rs:LL:CC | -LL | let y1: &i32 = mem::transmute(&*x); // launder lifetimes - | ^^^^^^^^^^^^^^^^^^^ +LL | let y1: &i32 = mem::transmute(&*x); // launder lifetimes + | ^^^^^^^^^^^^^^^^^^^ help: was later invalidated at offsets [0x0..0x4] --> $DIR/illegal_read8.rs:LL:CC | -LL | *y2 += 1; - | ^^^^^^^^ +LL | *y2 += 1; + | ^^^^^^^^ = note: inside `main` at $DIR/illegal_read8.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/interior_mut1.stderr b/tests/fail/stacked_borrows/interior_mut1.stderr index 82cb6e19133d6..2490fd3e1e9aa 100644 --- a/tests/fail/stacked_borrows/interior_mut1.stderr +++ b/tests/fail/stacked_borrows/interior_mut1.stderr @@ -1,24 +1,24 @@ error: Undefined Behavior: trying to reborrow for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location --> $DIR/interior_mut1.rs:LL:CC | -LL | let _val = *inner_shr.get(); - | ^^^^^^^^^^^^^^^ - | | - | trying to reborrow for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location - | this error occurs as part of a reborrow at ALLOC[0x0..0x4] +LL | let _val = *inner_shr.get(); + | ^^^^^^^^^^^^^^^ + | | + | trying to reborrow for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | this error occurs as part of a reborrow at ALLOC[0x0..0x4] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: was created by a retag at offsets [0x0..0x4] --> $DIR/interior_mut1.rs:LL:CC | -LL | let inner_shr = &*inner_uniq; // adds a SharedReadWrite - | ^^^^^^^^^^^^ +LL | let inner_shr = &*inner_uniq; // adds a SharedReadWrite + | ^^^^^^^^^^^^ help: was later invalidated at offsets [0x0..0x4] --> $DIR/interior_mut1.rs:LL:CC | -LL | *c.get() = UnsafeCell::new(1); // invalidates inner_shr - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | *c.get() = UnsafeCell::new(1); // invalidates inner_shr + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: inside `main` at $DIR/interior_mut1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace From 3348869f42020680bd588132ae77272e810bd770 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 20 Jun 2022 21:24:06 -0700 Subject: [PATCH 3279/3747] move nopreempt sync tests to their own file --- tests/pass/concurrency/sync.rs | 33 +------------------ tests/pass/concurrency/sync_nopreempt.rs | 40 ++++++++++++++++++++++++ 2 files changed, 41 insertions(+), 32 deletions(-) create mode 100644 tests/pass/concurrency/sync_nopreempt.rs diff --git a/tests/pass/concurrency/sync.rs b/tests/pass/concurrency/sync.rs index 26f44aa437189..5b7805ba22651 100644 --- a/tests/pass/concurrency/sync.rs +++ b/tests/pass/concurrency/sync.rs @@ -1,6 +1,5 @@ // ignore-windows: Concurrency on Windows is not supported yet. -// We are making scheduler assumptions here. -// compile-flags: -Zmiri-disable-isolation -Zmiri-strict-provenance -Zmiri-preemption-rate=0 +// compile-flags: -Zmiri-disable-isolation -Zmiri-strict-provenance use std::sync::{Arc, Barrier, Condvar, Mutex, Once, RwLock}; use std::thread; @@ -53,35 +52,6 @@ fn check_conditional_variables_notify_one() { } } -fn check_conditional_variables_notify_all() { - let pair = Arc::new(((Mutex::new(())), Condvar::new())); - - // Spawn threads and block them on the conditional variable. - let handles: Vec<_> = (0..5) - .map(|_| { - let pair2 = pair.clone(); - thread::spawn(move || { - let (lock, cvar) = &*pair2; - let guard = lock.lock().unwrap(); - // Block waiting on the conditional variable. - let _ = cvar.wait(guard).unwrap(); - }) - }) - .inspect(|_| { - thread::yield_now(); - thread::yield_now(); - }) - .collect(); - - let (_, cvar) = &*pair; - // Unblock all threads. - cvar.notify_all(); - - for handle in handles { - handle.join().unwrap(); - } -} - /// Test that waiting on a conditional variable with a timeout does not /// deadlock. fn check_conditional_variables_timed_wait_timeout() { @@ -301,7 +271,6 @@ fn check_condvar() { fn main() { check_barriers(); check_conditional_variables_notify_one(); - check_conditional_variables_notify_all(); check_conditional_variables_timed_wait_timeout(); check_conditional_variables_timed_wait_notimeout(); check_mutex(); diff --git a/tests/pass/concurrency/sync_nopreempt.rs b/tests/pass/concurrency/sync_nopreempt.rs new file mode 100644 index 0000000000000..38dbeb575d641 --- /dev/null +++ b/tests/pass/concurrency/sync_nopreempt.rs @@ -0,0 +1,40 @@ +// ignore-windows: Concurrency on Windows is not supported yet. +// We are making scheduler assumptions here. +// compile-flags: -Zmiri-strict-provenance -Zmiri-preemption-rate=0 + +use std::sync::{Condvar, Mutex, Arc}; +use std::thread; + +fn check_conditional_variables_notify_all() { + let pair = Arc::new(((Mutex::new(())), Condvar::new())); + + // Spawn threads and block them on the conditional variable. + let handles: Vec<_> = (0..5) + .map(|_| { + let pair2 = pair.clone(); + thread::spawn(move || { + let (lock, cvar) = &*pair2; + let guard = lock.lock().unwrap(); + // Block waiting on the conditional variable. + let _ = cvar.wait(guard).unwrap(); + }) + }) + .inspect(|_| { + // Ensure the other threads all run and block on the `wait`. + thread::yield_now(); + thread::yield_now(); + }) + .collect(); + + let (_, cvar) = &*pair; + // Unblock all threads. + cvar.notify_all(); + + for handle in handles { + handle.join().unwrap(); + } +} + +fn main() { + check_conditional_variables_notify_all(); +} From b5bc4e1b0c2e96d91e57b450051f29ab454a1c5b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 20 Jun 2022 22:02:02 -0700 Subject: [PATCH 3280/3747] add tests that fail due to SRW protectors also do more iterations of weak mem consistency, since now that is no longer the slowest test ;) --- tests/pass/0concurrency_arc_drop.rs | 19 ++++++++++ tests/pass/0weak_memory_consistency.rs | 2 +- .../stacked-borrows/interior_mutability.rs | 35 ++++++++++++++++++- 3 files changed, 54 insertions(+), 2 deletions(-) create mode 100644 tests/pass/0concurrency_arc_drop.rs diff --git a/tests/pass/0concurrency_arc_drop.rs b/tests/pass/0concurrency_arc_drop.rs new file mode 100644 index 0000000000000..b5192cd421409 --- /dev/null +++ b/tests/pass/0concurrency_arc_drop.rs @@ -0,0 +1,19 @@ +// ignore-windows: Concurrency on Windows is not supported yet. +use std::sync::Arc; +use std::thread; + +/// Test for Arc::drop bug (https://github.com/rust-lang/rust/issues/55005) +fn main() { + // The bug seems to take up to 700 iterations to reproduce with most seeds (tested 0-9). + for _ in 0..700 { + let arc_1 = Arc::new(()); + let arc_2 = arc_1.clone(); + let thread = thread::spawn(|| drop(arc_2)); + let mut i = 0; + while i < 256 { + i += 1; + } + drop(arc_1); + thread.join().unwrap(); + } +} diff --git a/tests/pass/0weak_memory_consistency.rs b/tests/pass/0weak_memory_consistency.rs index fc9dce0c986ab..601d8547f8c06 100644 --- a/tests/pass/0weak_memory_consistency.rs +++ b/tests/pass/0weak_memory_consistency.rs @@ -214,7 +214,7 @@ fn test_single_thread() { } pub fn main() { - for _ in 0..50 { + for _ in 0..75 { test_single_thread(); test_mixed_access(); test_load_buffering_acq_rel(); diff --git a/tests/pass/stacked-borrows/interior_mutability.rs b/tests/pass/stacked-borrows/interior_mutability.rs index 1ac9706b525f1..9ee8af45aefe9 100644 --- a/tests/pass/stacked-borrows/interior_mutability.rs +++ b/tests/pass/stacked-borrows/interior_mutability.rs @@ -1,11 +1,14 @@ +// compile-flags: -Zmiri-tag-raw-pointers use std::cell::{Cell, RefCell, UnsafeCell}; -use std::mem::MaybeUninit; +use std::mem::{self, MaybeUninit}; fn main() { aliasing_mut_and_shr(); aliasing_frz_and_shr(); into_interior_mutability(); unsafe_cell_2phase(); + unsafe_cell_deallocate(); + unsafe_cell_invalidate(); } fn aliasing_mut_and_shr() { @@ -67,3 +70,33 @@ fn unsafe_cell_2phase() { let _val = (*x2.get()).get(0); } } + +/// Make sure we can deallocate an UnsafeCell that was passed to an active fn call. +/// (This is the fix for https://github.com/rust-lang/rust/issues/55005.) +fn unsafe_cell_deallocate() { + fn f(x: &UnsafeCell) { + let b: Box = unsafe { Box::from_raw(x as *const _ as *mut i32) }; + drop(b) + } + + let b = Box::new(0i32); + f(unsafe { mem::transmute(Box::into_raw(b)) }); +} + +/// As a side-effect of the above, we also allow this -- at least for now. +fn unsafe_cell_invalidate() { + fn f(_x: &UnsafeCell, y: *mut i32) { + // Writing to y invalidates x, but that is okay. + unsafe { + *y += 1; + } + } + + let mut x = 0i32; + let raw1 = &mut x as *mut _; + let ref1 = unsafe { &mut *raw1 }; + let raw2 = ref1 as *mut _; + // Now the borrow stack is: raw1, ref2, raw2. + // So using raw1 invalidates raw2. + f(unsafe { mem::transmute(raw2) }, raw1); +} From 1b214a0d128779a03accff4e9426edb7c570082c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 20 Jun 2022 22:12:05 -0700 Subject: [PATCH 3281/3747] do not protect SRW items --- src/stacked_borrows.rs | 7 ++++ .../deallocate_against_barrier2.rs | 17 --------- .../deallocate_against_barrier2.stderr | 38 ------------------- 3 files changed, 7 insertions(+), 55 deletions(-) delete mode 100644 tests/fail/stacked_borrows/deallocate_against_barrier2.rs delete mode 100644 tests/fail/stacked_borrows/deallocate_against_barrier2.stderr diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index c78741499c2d4..0c537e0d7a5c6 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -821,6 +821,13 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } else { Permission::SharedReadWrite }; + let protector = if frozen { + protector + } else { + // We do not protect inside UnsafeCell. + // This fixes https://github.com/rust-lang/rust/issues/55005. + None + }; let item = Item { perm, tag: new_tag, protector }; let mut global = this.machine.stacked_borrows.as_ref().unwrap().borrow_mut(); stacked_borrows.for_each(range, |offset, stack, history| { diff --git a/tests/fail/stacked_borrows/deallocate_against_barrier2.rs b/tests/fail/stacked_borrows/deallocate_against_barrier2.rs deleted file mode 100644 index 9c0c59d364f28..0000000000000 --- a/tests/fail/stacked_borrows/deallocate_against_barrier2.rs +++ /dev/null @@ -1,17 +0,0 @@ -// error-pattern: deallocating while item is protected - -use std::cell::Cell; - -// Check that even `&Cell` are dereferenceable. -// Also see . -fn inner(x: &Cell, f: fn(&Cell)) { - // `f` may mutate, but it may not deallocate! - f(x) -} - -fn main() { - inner(Box::leak(Box::new(Cell::new(0))), |x| { - let raw = x as *const _ as *mut Cell; - drop(unsafe { Box::from_raw(raw) }); - }); -} diff --git a/tests/fail/stacked_borrows/deallocate_against_barrier2.stderr b/tests/fail/stacked_borrows/deallocate_against_barrier2.stderr deleted file mode 100644 index 088daec040fec..0000000000000 --- a/tests/fail/stacked_borrows/deallocate_against_barrier2.stderr +++ /dev/null @@ -1,38 +0,0 @@ -error: Undefined Behavior: deallocating while item is protected: [SharedReadWrite for (call ID)] - --> RUSTLIB/alloc/src/alloc.rs:LL:CC - | -LL | unsafe { __rust_dealloc(ptr, layout.size(), layout.align()) } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ deallocating while item is protected: [SharedReadWrite for (call ID)] - | - = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental - = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information - - = note: inside `std::alloc::dealloc` at RUSTLIB/alloc/src/alloc.rs:LL:CC - = note: inside `::deallocate` at RUSTLIB/alloc/src/alloc.rs:LL:CC - = note: inside `alloc::alloc::box_free::, std::alloc::Global>` at RUSTLIB/alloc/src/alloc.rs:LL:CC - = note: inside `std::ptr::drop_in_place::>> - shim(Some(std::boxed::Box>))` at RUSTLIB/core/src/ptr/mod.rs:LL:CC - = note: inside `std::mem::drop::>>` at RUSTLIB/core/src/mem/mod.rs:LL:CC -note: inside closure at $DIR/deallocate_against_barrier2.rs:LL:CC - --> $DIR/deallocate_against_barrier2.rs:LL:CC - | -LL | drop(unsafe { Box::from_raw(raw) }); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: inside `<[closure@$DIR/deallocate_against_barrier2.rs:LL:CC] as std::ops::FnOnce<(&std::cell::Cell,)>>::call_once - shim` at RUSTLIB/core/src/ops/function.rs:LL:CC -note: inside `inner` at $DIR/deallocate_against_barrier2.rs:LL:CC - --> $DIR/deallocate_against_barrier2.rs:LL:CC - | -LL | f(x) - | ^^^^ -note: inside `main` at $DIR/deallocate_against_barrier2.rs:LL:CC - --> $DIR/deallocate_against_barrier2.rs:LL:CC - | -LL | / inner(Box::leak(Box::new(Cell::new(0))), |x| { -LL | | let raw = x as *const _ as *mut Cell; -LL | | drop(unsafe { Box::from_raw(raw) }); -LL | | }); - | |______^ - -note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace - -error: aborting due to previous error - From 5490e775df81e08ff605d8cba7b12624245259b4 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Tue, 21 Jun 2022 11:27:44 -0700 Subject: [PATCH 3282/3747] Format tests with rustfmt (201-224 of 300) --- .../thread_local_static_dealloc.rs | 10 +++--- tests/fail/stacked_borrows/interior_mut2.rs | 32 ++++++++++--------- .../fail/stacked_borrows/issue-miri-1050-1.rs | 10 +++--- .../fail/stacked_borrows/issue-miri-1050-2.rs | 10 +++--- .../mut_exclusive_violation1.rs | 30 +++++++++-------- .../mut_exclusive_violation2.rs | 18 ++++++----- .../return_invalid_mut_option.rs | 4 +-- .../return_invalid_shr_option.rs | 4 +-- .../shared_rw_borrows_are_weak1.rs | 18 ++++++----- .../shared_rw_borrows_are_weak2.rs | 18 ++++++----- .../sync/libc_pthread_mutex_destroy_locked.rs | 5 ++- .../libc_pthread_mutex_normal_deadlock.rs | 5 ++- ...bc_pthread_mutex_normal_unlock_unlocked.rs | 5 ++- tests/fail/transmute-pair-uninit.rs | 6 ++-- tests/fail/transmute_fat1.rs | 14 +++----- tests/fail/unaligned_pointers/alignment.rs | 2 +- tests/fail/validity/cast_fn_ptr1.rs | 2 +- tests/fail/validity/cast_fn_ptr2.rs | 4 ++- tests/fail/validity/invalid_enum_tag.rs | 5 ++- tests/fail/validity/invalid_wide_raw.rs | 4 +-- tests/fail/validity/ref_to_uninhabited1.rs | 12 ++++--- tests/fail/validity/ref_to_uninhabited2.rs | 8 +++-- tests/fail/validity/too-big-slice.rs | 10 +++--- tests/fail/validity/too-big-unsized.rs | 12 ++++--- 24 files changed, 143 insertions(+), 105 deletions(-) diff --git a/tests/fail/concurrency/thread_local_static_dealloc.rs b/tests/fail/concurrency/thread_local_static_dealloc.rs index 73e4ab596585d..d5a4bf27f8973 100644 --- a/tests/fail/concurrency/thread_local_static_dealloc.rs +++ b/tests/fail/concurrency/thread_local_static_dealloc.rs @@ -7,7 +7,9 @@ #[thread_local] static mut TLS: u8 = 0; -fn main() { unsafe { - let dangling_ptr = std::thread::spawn(|| &TLS as *const u8 as usize).join().unwrap(); - let _val = *(dangling_ptr as *const u8); //~ ERROR dereferenced after this allocation got freed -} } +fn main() { + unsafe { + let dangling_ptr = std::thread::spawn(|| &TLS as *const u8 as usize).join().unwrap(); + let _val = *(dangling_ptr as *const u8); //~ ERROR dereferenced after this allocation got freed + } +} diff --git a/tests/fail/stacked_borrows/interior_mut2.rs b/tests/fail/stacked_borrows/interior_mut2.rs index 45770020d33d7..4433f28e3459a 100644 --- a/tests/fail/stacked_borrows/interior_mut2.rs +++ b/tests/fail/stacked_borrows/interior_mut2.rs @@ -7,22 +7,24 @@ unsafe fn unsafe_cell_get(x: &UnsafeCell) -> &'static mut T { mem::transmute(x) } -fn main() { unsafe { - let c = &UnsafeCell::new(UnsafeCell::new(0)); - let inner_uniq = &mut *c.get(); - let inner_shr = &*inner_uniq; - // stack: [c: SharedReadWrite, inner_uniq: Unique, inner_shr: SharedReadWrite] +fn main() { + unsafe { + let c = &UnsafeCell::new(UnsafeCell::new(0)); + let inner_uniq = &mut *c.get(); + let inner_shr = &*inner_uniq; + // stack: [c: SharedReadWrite, inner_uniq: Unique, inner_shr: SharedReadWrite] - let _val = c.get().read(); // invalidates inner_uniq - // stack: [c: SharedReadWrite, inner_uniq: Disabled, inner_shr: SharedReadWrite] + let _val = c.get().read(); // invalidates inner_uniq + // stack: [c: SharedReadWrite, inner_uniq: Disabled, inner_shr: SharedReadWrite] - // We have to be careful not to add any raw pointers above inner_uniq in - // the stack, hence the use of unsafe_cell_get. - let _val = *unsafe_cell_get(inner_shr); // this still works + // We have to be careful not to add any raw pointers above inner_uniq in + // the stack, hence the use of unsafe_cell_get. + let _val = *unsafe_cell_get(inner_shr); // this still works - *c.get() = UnsafeCell::new(0); // now inner_shr gets invalidated - // stack: [c: SharedReadWrite] + *c.get() = UnsafeCell::new(0); // now inner_shr gets invalidated + // stack: [c: SharedReadWrite] - // now this does not work any more - let _val = *inner_shr.get(); //~ ERROR borrow stack -} } + // now this does not work any more + let _val = *inner_shr.get(); //~ ERROR borrow stack + } +} diff --git a/tests/fail/stacked_borrows/issue-miri-1050-1.rs b/tests/fail/stacked_borrows/issue-miri-1050-1.rs index 852eb69968ed7..c1fc695e0d651 100644 --- a/tests/fail/stacked_borrows/issue-miri-1050-1.rs +++ b/tests/fail/stacked_borrows/issue-miri-1050-1.rs @@ -1,6 +1,8 @@ // error-pattern: pointer to 4 bytes starting at offset 0 is out-of-bounds -fn main() { unsafe { - let ptr = Box::into_raw(Box::new(0u16)); - Box::from_raw(ptr as *mut u32); -} } +fn main() { + unsafe { + let ptr = Box::into_raw(Box::new(0u16)); + Box::from_raw(ptr as *mut u32); + } +} diff --git a/tests/fail/stacked_borrows/issue-miri-1050-2.rs b/tests/fail/stacked_borrows/issue-miri-1050-2.rs index 8f0b475016046..7d8809cedcd79 100644 --- a/tests/fail/stacked_borrows/issue-miri-1050-2.rs +++ b/tests/fail/stacked_borrows/issue-miri-1050-2.rs @@ -1,7 +1,9 @@ // error-pattern: is not a valid pointer use std::ptr::NonNull; -fn main() { unsafe { - let ptr = NonNull::::dangling(); - Box::from_raw(ptr.as_ptr()); -} } +fn main() { + unsafe { + let ptr = NonNull::::dangling(); + Box::from_raw(ptr.as_ptr()); + } +} diff --git a/tests/fail/stacked_borrows/mut_exclusive_violation1.rs b/tests/fail/stacked_borrows/mut_exclusive_violation1.rs index 03343b985a021..a1cb7107eee0d 100644 --- a/tests/fail/stacked_borrows/mut_exclusive_violation1.rs +++ b/tests/fail/stacked_borrows/mut_exclusive_violation1.rs @@ -1,14 +1,14 @@ fn demo_mut_advanced_unique(our: &mut i32) -> i32 { - unknown_code_1(&*our); + unknown_code_1(&*our); - // This "re-asserts" uniqueness of the reference: After writing, we know - // our tag is at the top of the stack. - *our = 5; + // This "re-asserts" uniqueness of the reference: After writing, we know + // our tag is at the top of the stack. + *our = 5; - unknown_code_2(); + unknown_code_2(); - // We know this will return 5 - *our + // We know this will return 5 + *our } // Now comes the evil context @@ -16,13 +16,17 @@ use std::ptr; static mut LEAK: *mut i32 = ptr::null_mut(); -fn unknown_code_1(x: &i32) { unsafe { - LEAK = x as *const _ as *mut _; -} } +fn unknown_code_1(x: &i32) { + unsafe { + LEAK = x as *const _ as *mut _; + } +} -fn unknown_code_2() { unsafe { - *LEAK = 7; //~ ERROR borrow stack -} } +fn unknown_code_2() { + unsafe { + *LEAK = 7; //~ ERROR borrow stack + } +} fn main() { demo_mut_advanced_unique(&mut 0); diff --git a/tests/fail/stacked_borrows/mut_exclusive_violation2.rs b/tests/fail/stacked_borrows/mut_exclusive_violation2.rs index c6802c5ec94ee..a5bf8353bae8c 100644 --- a/tests/fail/stacked_borrows/mut_exclusive_violation2.rs +++ b/tests/fail/stacked_borrows/mut_exclusive_violation2.rs @@ -1,10 +1,12 @@ use std::ptr::NonNull; -fn main() { unsafe { - let x = &mut 0; - let mut ptr1 = NonNull::from(x); - let mut ptr2 = ptr1.clone(); - let raw1 = ptr1.as_mut(); - let _raw2 = ptr2.as_mut(); - let _val = *raw1; //~ ERROR borrow stack -} } +fn main() { + unsafe { + let x = &mut 0; + let mut ptr1 = NonNull::from(x); + let mut ptr2 = ptr1.clone(); + let raw1 = ptr1.as_mut(); + let _raw2 = ptr2.as_mut(); + let _val = *raw1; //~ ERROR borrow stack + } +} diff --git a/tests/fail/stacked_borrows/return_invalid_mut_option.rs b/tests/fail/stacked_borrows/return_invalid_mut_option.rs index 1cb3f3f920267..ccdb3dc505790 100644 --- a/tests/fail/stacked_borrows/return_invalid_mut_option.rs +++ b/tests/fail/stacked_borrows/return_invalid_mut_option.rs @@ -10,7 +10,7 @@ fn foo(x: &mut (i32, i32)) -> Option<&mut i32> { fn main() { match foo(&mut (1, 2)) { - Some(_x) => {}, //~ ERROR borrow stack - None => {}, + Some(_x) => {} //~ ERROR borrow stack + None => {} } } diff --git a/tests/fail/stacked_borrows/return_invalid_shr_option.rs b/tests/fail/stacked_borrows/return_invalid_shr_option.rs index 2d8527fa3fb4f..42b4871c46747 100644 --- a/tests/fail/stacked_borrows/return_invalid_shr_option.rs +++ b/tests/fail/stacked_borrows/return_invalid_shr_option.rs @@ -9,7 +9,7 @@ fn foo(x: &mut (i32, i32)) -> Option<&i32> { fn main() { match foo(&mut (1, 2)) { - Some(_x) => {}, //~ ERROR borrow stack - None => {}, + Some(_x) => {} //~ ERROR borrow stack + None => {} } } diff --git a/tests/fail/stacked_borrows/shared_rw_borrows_are_weak1.rs b/tests/fail/stacked_borrows/shared_rw_borrows_are_weak1.rs index d734caf1d97ae..a08d2b716ee73 100644 --- a/tests/fail/stacked_borrows/shared_rw_borrows_are_weak1.rs +++ b/tests/fail/stacked_borrows/shared_rw_borrows_are_weak1.rs @@ -2,13 +2,15 @@ // *below* an already granted Unique -- so writing to // the SharedReadWrite will invalidate the Unique. -use std::mem; use std::cell::Cell; +use std::mem; -fn main() { unsafe { - let x = &mut Cell::new(0); - let y: &mut Cell = mem::transmute(&mut *x); // launder lifetime - let shr_rw = &*x; // thanks to interior mutability this will be a SharedReadWrite - shr_rw.set(1); - y.get_mut(); //~ ERROR borrow stack -} } +fn main() { + unsafe { + let x = &mut Cell::new(0); + let y: &mut Cell = mem::transmute(&mut *x); // launder lifetime + let shr_rw = &*x; // thanks to interior mutability this will be a SharedReadWrite + shr_rw.set(1); + y.get_mut(); //~ ERROR borrow stack + } +} diff --git a/tests/fail/stacked_borrows/shared_rw_borrows_are_weak2.rs b/tests/fail/stacked_borrows/shared_rw_borrows_are_weak2.rs index d4aef74dff6ba..07163456cebe7 100644 --- a/tests/fail/stacked_borrows/shared_rw_borrows_are_weak2.rs +++ b/tests/fail/stacked_borrows/shared_rw_borrows_are_weak2.rs @@ -3,13 +3,15 @@ // the SharedReadWrite will invalidate the SharedReadWrite. // normalize-stderr-test: "0x[0-9a-fA-F]+" -> "$$HEX" -use std::mem; use std::cell::RefCell; +use std::mem; -fn main() { unsafe { - let x = &mut RefCell::new(0); - let y: &i32 = mem::transmute(&*x.borrow()); // launder lifetime - let shr_rw = &*x; // thanks to interior mutability this will be a SharedReadWrite - shr_rw.replace(1); - let _val = *y; //~ ERROR borrow stack -} } +fn main() { + unsafe { + let x = &mut RefCell::new(0); + let y: &i32 = mem::transmute(&*x.borrow()); // launder lifetime + let shr_rw = &*x; // thanks to interior mutability this will be a SharedReadWrite + shr_rw.replace(1); + let _val = *y; //~ ERROR borrow stack + } +} diff --git a/tests/fail/sync/libc_pthread_mutex_destroy_locked.rs b/tests/fail/sync/libc_pthread_mutex_destroy_locked.rs index e7ed8ad296211..461a81b8fbac7 100644 --- a/tests/fail/sync/libc_pthread_mutex_destroy_locked.rs +++ b/tests/fail/sync/libc_pthread_mutex_destroy_locked.rs @@ -7,7 +7,10 @@ extern crate libc; fn main() { unsafe { let mut mutexattr: libc::pthread_mutexattr_t = std::mem::zeroed(); - assert_eq!(libc::pthread_mutexattr_settype(&mut mutexattr as *mut _, libc::PTHREAD_MUTEX_NORMAL), 0); + assert_eq!( + libc::pthread_mutexattr_settype(&mut mutexattr as *mut _, libc::PTHREAD_MUTEX_NORMAL), + 0 + ); let mut mutex: libc::pthread_mutex_t = std::mem::zeroed(); assert_eq!(libc::pthread_mutex_init(&mut mutex as *mut _, &mutexattr as *const _), 0); assert_eq!(libc::pthread_mutex_lock(&mut mutex as *mut _), 0); diff --git a/tests/fail/sync/libc_pthread_mutex_normal_deadlock.rs b/tests/fail/sync/libc_pthread_mutex_normal_deadlock.rs index 96e0ff3bfff72..7e7af617d5d9c 100644 --- a/tests/fail/sync/libc_pthread_mutex_normal_deadlock.rs +++ b/tests/fail/sync/libc_pthread_mutex_normal_deadlock.rs @@ -7,7 +7,10 @@ extern crate libc; fn main() { unsafe { let mut mutexattr: libc::pthread_mutexattr_t = std::mem::zeroed(); - assert_eq!(libc::pthread_mutexattr_settype(&mut mutexattr as *mut _, libc::PTHREAD_MUTEX_NORMAL), 0); + assert_eq!( + libc::pthread_mutexattr_settype(&mut mutexattr as *mut _, libc::PTHREAD_MUTEX_NORMAL), + 0 + ); let mut mutex: libc::pthread_mutex_t = std::mem::zeroed(); assert_eq!(libc::pthread_mutex_init(&mut mutex as *mut _, &mutexattr as *const _), 0); assert_eq!(libc::pthread_mutex_lock(&mut mutex as *mut _), 0); diff --git a/tests/fail/sync/libc_pthread_mutex_normal_unlock_unlocked.rs b/tests/fail/sync/libc_pthread_mutex_normal_unlock_unlocked.rs index 65de62484d5ed..c8dd84b838a2d 100644 --- a/tests/fail/sync/libc_pthread_mutex_normal_unlock_unlocked.rs +++ b/tests/fail/sync/libc_pthread_mutex_normal_unlock_unlocked.rs @@ -7,7 +7,10 @@ extern crate libc; fn main() { unsafe { let mut mutexattr: libc::pthread_mutexattr_t = std::mem::zeroed(); - assert_eq!(libc::pthread_mutexattr_settype(&mut mutexattr as *mut _, libc::PTHREAD_MUTEX_NORMAL), 0); + assert_eq!( + libc::pthread_mutexattr_settype(&mut mutexattr as *mut _, libc::PTHREAD_MUTEX_NORMAL), + 0 + ); let mut mutex: libc::pthread_mutex_t = std::mem::zeroed(); assert_eq!(libc::pthread_mutex_init(&mut mutex as *mut _, &mutexattr as *const _), 0); assert_eq!(libc::pthread_mutex_lock(&mut mutex as *mut _), 0); diff --git a/tests/fail/transmute-pair-uninit.rs b/tests/fail/transmute-pair-uninit.rs index 1bd60f9cff732..0835287b9e4ff 100644 --- a/tests/fail/transmute-pair-uninit.rs +++ b/tests/fail/transmute-pair-uninit.rs @@ -10,7 +10,7 @@ fn main() { let y = &x; // Now read this bytewise. There should be (`ptr_size + 1`) def bytes followed by // (`ptr_size - 1`) undef bytes (the padding after the bool) in there. - let z : *const u8 = y as *const _ as *const _; + let z: *const u8 = y as *const _ as *const _; let first_undef = mem::size_of::() as isize + 1; for i in 0..first_undef { let byte = unsafe { *z.offset(i) }; @@ -18,5 +18,7 @@ fn main() { } let v = unsafe { *z.offset(first_undef) }; //~^ ERROR uninitialized - if v == 0 { println!("it is zero"); } + if v == 0 { + println!("it is zero"); + } } diff --git a/tests/fail/transmute_fat1.rs b/tests/fail/transmute_fat1.rs index 8b351d3a09e9d..f9fa2ace75700 100644 --- a/tests/fail/transmute_fat1.rs +++ b/tests/fail/transmute_fat1.rs @@ -2,13 +2,9 @@ // normalize-stderr-test: "\[u8; (08|16)\]" -> "$$ARRAY" fn main() { - #[cfg(target_pointer_width="64")] - let bad = unsafe { - std::mem::transmute::<&[u8], [u8; 16]>(&[1u8]) - }; - #[cfg(target_pointer_width="32")] - let bad = unsafe { - std::mem::transmute::<&[u8], [u8; 08]>(&[1u8]) - }; - let _val = bad[0] + bad[bad.len()-1]; + #[cfg(target_pointer_width = "64")] + let bad = unsafe { std::mem::transmute::<&[u8], [u8; 16]>(&[1u8]) }; + #[cfg(target_pointer_width = "32")] + let bad = unsafe { std::mem::transmute::<&[u8], [u8; 08]>(&[1u8]) }; + let _val = bad[0] + bad[bad.len() - 1]; } diff --git a/tests/fail/unaligned_pointers/alignment.rs b/tests/fail/unaligned_pointers/alignment.rs index b77f0eef82dd1..e99d8c967cddd 100644 --- a/tests/fail/unaligned_pointers/alignment.rs +++ b/tests/fail/unaligned_pointers/alignment.rs @@ -8,7 +8,7 @@ fn main() { let x_ptr: *mut u8 = x.as_mut_ptr(); // At least one of these is definitely unaligned. unsafe { - *(x_ptr as *mut u32) = 42; + *(x_ptr as *mut u32) = 42; *(x_ptr.add(1) as *mut u32) = 42; } } diff --git a/tests/fail/validity/cast_fn_ptr1.rs b/tests/fail/validity/cast_fn_ptr1.rs index d755c163bba0e..020e7be34f706 100644 --- a/tests/fail/validity/cast_fn_ptr1.rs +++ b/tests/fail/validity/cast_fn_ptr1.rs @@ -2,7 +2,7 @@ fn main() { // Cast a function pointer such that on a call, the argument gets transmuted // from raw ptr to reference. This is ABI-compatible, so it's not the call that // should fail, but validation should. - fn f(_x: &i32) { } + fn f(_x: &i32) {} let g: fn(*const i32) = unsafe { std::mem::transmute(f as fn(&i32)) }; diff --git a/tests/fail/validity/cast_fn_ptr2.rs b/tests/fail/validity/cast_fn_ptr2.rs index d78d56b5b6d6a..10fc39f56fae3 100644 --- a/tests/fail/validity/cast_fn_ptr2.rs +++ b/tests/fail/validity/cast_fn_ptr2.rs @@ -2,7 +2,9 @@ fn main() { // Cast a function pointer such that when returning, the return value gets transmuted // from raw ptr to reference. This is ABI-compatible, so it's not the call that // should fail, but validation should. - fn f() -> *const i32 { 0usize as *const i32 } + fn f() -> *const i32 { + 0usize as *const i32 + } let g: fn() -> &'static i32 = unsafe { std::mem::transmute(f as fn() -> *const i32) }; diff --git a/tests/fail/validity/invalid_enum_tag.rs b/tests/fail/validity/invalid_enum_tag.rs index d4ee3cc8a34a8..9722e6492c829 100644 --- a/tests/fail/validity/invalid_enum_tag.rs +++ b/tests/fail/validity/invalid_enum_tag.rs @@ -1,6 +1,9 @@ #[repr(C)] pub enum Foo { - A, B, C, D + A, + B, + C, + D, } fn main() { diff --git a/tests/fail/validity/invalid_wide_raw.rs b/tests/fail/validity/invalid_wide_raw.rs index ac2d79b5a92ad..0a2f6f5b152c5 100644 --- a/tests/fail/validity/invalid_wide_raw.rs +++ b/tests/fail/validity/invalid_wide_raw.rs @@ -1,11 +1,11 @@ #![allow(invalid_value)] fn main() { - trait T { } + trait T {} #[derive(Debug)] struct S { #[allow(dead_code)] - x: * mut dyn T + x: *mut dyn T, } dbg!(S { x: unsafe { std::mem::transmute((0usize, 0usize)) } }); //~ ERROR: encountered dangling vtable pointer in wide pointer } diff --git a/tests/fail/validity/ref_to_uninhabited1.rs b/tests/fail/validity/ref_to_uninhabited1.rs index 51a3279ffae97..a46ce017c5a0f 100644 --- a/tests/fail/validity/ref_to_uninhabited1.rs +++ b/tests/fail/validity/ref_to_uninhabited1.rs @@ -1,7 +1,9 @@ #![feature(never_type)] -use std::mem::{transmute, forget}; +use std::mem::{forget, transmute}; -fn main() { unsafe { - let x: Box = transmute(&mut 42); //~ERROR encountered a box pointing to uninhabited type ! - forget(x); -} } +fn main() { + unsafe { + let x: Box = transmute(&mut 42); //~ERROR encountered a box pointing to uninhabited type ! + forget(x); + } +} diff --git a/tests/fail/validity/ref_to_uninhabited2.rs b/tests/fail/validity/ref_to_uninhabited2.rs index 3778719dc58ce..0a791d1e7fee8 100644 --- a/tests/fail/validity/ref_to_uninhabited2.rs +++ b/tests/fail/validity/ref_to_uninhabited2.rs @@ -2,6 +2,8 @@ use std::mem::transmute; enum Void {} -fn main() { unsafe { - let _x: &(i32, Void) = transmute(&42); //~ERROR encountered a reference pointing to uninhabited type (i32, Void) -} } +fn main() { + unsafe { + let _x: &(i32, Void) = transmute(&42); //~ERROR encountered a reference pointing to uninhabited type (i32, Void) + } +} diff --git a/tests/fail/validity/too-big-slice.rs b/tests/fail/validity/too-big-slice.rs index 6a4c18249ee7d..61d9032207585 100644 --- a/tests/fail/validity/too-big-slice.rs +++ b/tests/fail/validity/too-big-slice.rs @@ -1,6 +1,8 @@ use std::mem; -fn main() { unsafe { - let ptr = Box::into_raw(Box::new(0u8)); - let _x: &[u8] = mem::transmute((ptr, usize::MAX)); //~ ERROR: invalid reference metadata: slice is bigger than largest supported object -} } +fn main() { + unsafe { + let ptr = Box::into_raw(Box::new(0u8)); + let _x: &[u8] = mem::transmute((ptr, usize::MAX)); //~ ERROR: invalid reference metadata: slice is bigger than largest supported object + } +} diff --git a/tests/fail/validity/too-big-unsized.rs b/tests/fail/validity/too-big-unsized.rs index 824190a66eebf..280205dccbf23 100644 --- a/tests/fail/validity/too-big-unsized.rs +++ b/tests/fail/validity/too-big-unsized.rs @@ -6,8 +6,10 @@ struct MySlice { tail: [u8], } -fn main() { unsafe { - let ptr = Box::into_raw(Box::new(0u8)); - // The slice part is actually not "too big", but together with the `prefix` field it is. - let _x: &MySlice = mem::transmute((ptr, isize::MAX as usize)); //~ ERROR: invalid reference metadata: total size is bigger than largest supported object -} } +fn main() { + unsafe { + let ptr = Box::into_raw(Box::new(0u8)); + // The slice part is actually not "too big", but together with the `prefix` field it is. + let _x: &MySlice = mem::transmute((ptr, isize::MAX as usize)); //~ ERROR: invalid reference metadata: total size is bigger than largest supported object + } +} From b3a689e0089a1e41d11f6d4fa83ace7505bbb164 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Tue, 21 Jun 2022 11:28:00 -0700 Subject: [PATCH 3283/3747] Manual adjustments --- tests/fail/sync/libc_pthread_mutex_destroy_locked.rs | 2 +- tests/fail/sync/libc_pthread_mutex_normal_deadlock.rs | 2 +- tests/fail/sync/libc_pthread_mutex_normal_unlock_unlocked.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/fail/sync/libc_pthread_mutex_destroy_locked.rs b/tests/fail/sync/libc_pthread_mutex_destroy_locked.rs index 461a81b8fbac7..85a37db341fab 100644 --- a/tests/fail/sync/libc_pthread_mutex_destroy_locked.rs +++ b/tests/fail/sync/libc_pthread_mutex_destroy_locked.rs @@ -9,7 +9,7 @@ fn main() { let mut mutexattr: libc::pthread_mutexattr_t = std::mem::zeroed(); assert_eq!( libc::pthread_mutexattr_settype(&mut mutexattr as *mut _, libc::PTHREAD_MUTEX_NORMAL), - 0 + 0, ); let mut mutex: libc::pthread_mutex_t = std::mem::zeroed(); assert_eq!(libc::pthread_mutex_init(&mut mutex as *mut _, &mutexattr as *const _), 0); diff --git a/tests/fail/sync/libc_pthread_mutex_normal_deadlock.rs b/tests/fail/sync/libc_pthread_mutex_normal_deadlock.rs index 7e7af617d5d9c..7e29a41920ea6 100644 --- a/tests/fail/sync/libc_pthread_mutex_normal_deadlock.rs +++ b/tests/fail/sync/libc_pthread_mutex_normal_deadlock.rs @@ -9,7 +9,7 @@ fn main() { let mut mutexattr: libc::pthread_mutexattr_t = std::mem::zeroed(); assert_eq!( libc::pthread_mutexattr_settype(&mut mutexattr as *mut _, libc::PTHREAD_MUTEX_NORMAL), - 0 + 0, ); let mut mutex: libc::pthread_mutex_t = std::mem::zeroed(); assert_eq!(libc::pthread_mutex_init(&mut mutex as *mut _, &mutexattr as *const _), 0); diff --git a/tests/fail/sync/libc_pthread_mutex_normal_unlock_unlocked.rs b/tests/fail/sync/libc_pthread_mutex_normal_unlock_unlocked.rs index c8dd84b838a2d..1f1a2ef34b72e 100644 --- a/tests/fail/sync/libc_pthread_mutex_normal_unlock_unlocked.rs +++ b/tests/fail/sync/libc_pthread_mutex_normal_unlock_unlocked.rs @@ -9,7 +9,7 @@ fn main() { let mut mutexattr: libc::pthread_mutexattr_t = std::mem::zeroed(); assert_eq!( libc::pthread_mutexattr_settype(&mut mutexattr as *mut _, libc::PTHREAD_MUTEX_NORMAL), - 0 + 0, ); let mut mutex: libc::pthread_mutex_t = std::mem::zeroed(); assert_eq!(libc::pthread_mutex_init(&mut mutex as *mut _, &mutexattr as *const _), 0); From 7d40530c523bc5c39a0ceb264bada529f4fcb086 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Tue, 21 Jun 2022 11:28:24 -0700 Subject: [PATCH 3284/3747] Bless stderr files after rustfmt --- .../thread_local_static_dealloc.stderr | 4 ++-- .../fail/stacked_borrows/interior_mut2.stderr | 18 +++++++-------- .../stacked_borrows/issue-miri-1050-1.stderr | 4 ++-- .../stacked_borrows/issue-miri-1050-2.stderr | 4 ++-- .../mut_exclusive_violation1.stderr | 22 +++++++++---------- .../mut_exclusive_violation2.stderr | 18 +++++++-------- .../return_invalid_mut_option.stderr | 2 +- .../return_invalid_shr_option.stderr | 2 +- .../shared_rw_borrows_are_weak1.stderr | 18 +++++++-------- .../shared_rw_borrows_are_weak2.stderr | 18 +++++++-------- tests/fail/transmute_fat1.stderr | 4 ++-- .../fail/unaligned_pointers/alignment.stderr | 4 ++-- .../fail/validity/ref_to_uninhabited1.stderr | 4 ++-- .../fail/validity/ref_to_uninhabited2.stderr | 4 ++-- tests/fail/validity/too-big-slice.stderr | 4 ++-- tests/fail/validity/too-big-unsized.stderr | 4 ++-- 16 files changed, 67 insertions(+), 67 deletions(-) diff --git a/tests/fail/concurrency/thread_local_static_dealloc.stderr b/tests/fail/concurrency/thread_local_static_dealloc.stderr index a485edc0da93f..2a3a8f0f55c3b 100644 --- a/tests/fail/concurrency/thread_local_static_dealloc.stderr +++ b/tests/fail/concurrency/thread_local_static_dealloc.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: pointer to ALLOC was dereferenced after this allocation got freed --> $DIR/thread_local_static_dealloc.rs:LL:CC | -LL | let _val = *(dangling_ptr as *const u8); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pointer to ALLOC was dereferenced after this allocation got freed +LL | let _val = *(dangling_ptr as *const u8); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pointer to ALLOC was dereferenced after this allocation got freed | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/stacked_borrows/interior_mut2.stderr b/tests/fail/stacked_borrows/interior_mut2.stderr index c8a06e32fda03..33060a7818ff0 100644 --- a/tests/fail/stacked_borrows/interior_mut2.stderr +++ b/tests/fail/stacked_borrows/interior_mut2.stderr @@ -1,24 +1,24 @@ error: Undefined Behavior: trying to reborrow for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location --> $DIR/interior_mut2.rs:LL:CC | -LL | let _val = *inner_shr.get(); - | ^^^^^^^^^^^^^^^ - | | - | trying to reborrow for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location - | this error occurs as part of a reborrow at ALLOC[0x0..0x4] +LL | let _val = *inner_shr.get(); + | ^^^^^^^^^^^^^^^ + | | + | trying to reborrow for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | this error occurs as part of a reborrow at ALLOC[0x0..0x4] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: was created by a retag at offsets [0x0..0x4] --> $DIR/interior_mut2.rs:LL:CC | -LL | let inner_shr = &*inner_uniq; - | ^^^^^^^^^^^^ +LL | let inner_shr = &*inner_uniq; + | ^^^^^^^^^^^^ help: was later invalidated at offsets [0x0..0x4] --> $DIR/interior_mut2.rs:LL:CC | -LL | *c.get() = UnsafeCell::new(0); // now inner_shr gets invalidated - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | *c.get() = UnsafeCell::new(0); // now inner_shr gets invalidated + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: inside `main` at $DIR/interior_mut2.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/issue-miri-1050-1.stderr b/tests/fail/stacked_borrows/issue-miri-1050-1.stderr index b4953f95181a4..c2c471fba8810 100644 --- a/tests/fail/stacked_borrows/issue-miri-1050-1.stderr +++ b/tests/fail/stacked_borrows/issue-miri-1050-1.stderr @@ -12,8 +12,8 @@ LL | Box(unsafe { Unique::new_unchecked(raw) }, alloc) note: inside `main` at $DIR/issue-miri-1050-1.rs:LL:CC --> $DIR/issue-miri-1050-1.rs:LL:CC | -LL | Box::from_raw(ptr as *mut u32); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | Box::from_raw(ptr as *mut u32); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/issue-miri-1050-2.stderr b/tests/fail/stacked_borrows/issue-miri-1050-2.stderr index cd6cfc0ecc3ae..c49852cb7f4f8 100644 --- a/tests/fail/stacked_borrows/issue-miri-1050-2.stderr +++ b/tests/fail/stacked_borrows/issue-miri-1050-2.stderr @@ -12,8 +12,8 @@ LL | Box(unsafe { Unique::new_unchecked(raw) }, alloc) note: inside `main` at $DIR/issue-miri-1050-2.rs:LL:CC --> $DIR/issue-miri-1050-2.rs:LL:CC | -LL | Box::from_raw(ptr.as_ptr()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | Box::from_raw(ptr.as_ptr()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/mut_exclusive_violation1.stderr b/tests/fail/stacked_borrows/mut_exclusive_violation1.stderr index 4e38bcd2a89ce..ea14536a39905 100644 --- a/tests/fail/stacked_borrows/mut_exclusive_violation1.stderr +++ b/tests/fail/stacked_borrows/mut_exclusive_violation1.stderr @@ -1,30 +1,30 @@ error: Undefined Behavior: attempting a write access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location --> $DIR/mut_exclusive_violation1.rs:LL:CC | -LL | *LEAK = 7; - | ^^^^^^^^^ - | | - | attempting a write access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location - | this error occurs as part of an access at ALLOC[0x0..0x4] +LL | *LEAK = 7; + | ^^^^^^^^^ + | | + | attempting a write access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | this error occurs as part of an access at ALLOC[0x0..0x4] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: tag was most recently created at offsets [0x0..0x4] --> $DIR/mut_exclusive_violation1.rs:LL:CC | -LL | LEAK = x as *const _ as *mut _; - | ^ +LL | LEAK = x as *const _ as *mut _; + | ^ help: tag was later invalidated at offsets [0x0..0x4] --> $DIR/mut_exclusive_violation1.rs:LL:CC | -LL | *our = 5; - | ^^^^^^^^ +LL | *our = 5; + | ^^^^^^^^ = note: inside `unknown_code_2` at $DIR/mut_exclusive_violation1.rs:LL:CC note: inside `demo_mut_advanced_unique` at $DIR/mut_exclusive_violation1.rs:LL:CC --> $DIR/mut_exclusive_violation1.rs:LL:CC | -LL | unknown_code_2(); - | ^^^^^^^^^^^^^^^^ +LL | unknown_code_2(); + | ^^^^^^^^^^^^^^^^ note: inside `main` at $DIR/mut_exclusive_violation1.rs:LL:CC --> $DIR/mut_exclusive_violation1.rs:LL:CC | diff --git a/tests/fail/stacked_borrows/mut_exclusive_violation2.stderr b/tests/fail/stacked_borrows/mut_exclusive_violation2.stderr index fd52dbe348acc..85baf93613a20 100644 --- a/tests/fail/stacked_borrows/mut_exclusive_violation2.stderr +++ b/tests/fail/stacked_borrows/mut_exclusive_violation2.stderr @@ -1,24 +1,24 @@ error: Undefined Behavior: attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location --> $DIR/mut_exclusive_violation2.rs:LL:CC | -LL | let _val = *raw1; - | ^^^^^ - | | - | attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location - | this error occurs as part of an access at ALLOC[0x0..0x4] +LL | let _val = *raw1; + | ^^^^^ + | | + | attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | this error occurs as part of an access at ALLOC[0x0..0x4] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: was created by a retag at offsets [0x0..0x4] --> $DIR/mut_exclusive_violation2.rs:LL:CC | -LL | let raw1 = ptr1.as_mut(); - | ^^^^^^^^^^^^^ +LL | let raw1 = ptr1.as_mut(); + | ^^^^^^^^^^^^^ help: was later invalidated at offsets [0x0..0x4] --> $DIR/mut_exclusive_violation2.rs:LL:CC | -LL | let _raw2 = ptr2.as_mut(); - | ^^^^^^^^^^^^^ +LL | let _raw2 = ptr2.as_mut(); + | ^^^^^^^^^^^^^ = note: inside `main` at $DIR/mut_exclusive_violation2.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/return_invalid_mut_option.stderr b/tests/fail/stacked_borrows/return_invalid_mut_option.stderr index 98decdc3adc81..4bee128d68a40 100644 --- a/tests/fail/stacked_borrows/return_invalid_mut_option.stderr +++ b/tests/fail/stacked_borrows/return_invalid_mut_option.stderr @@ -1,7 +1,7 @@ error: Undefined Behavior: trying to reborrow for Unique permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location --> $DIR/return_invalid_mut_option.rs:LL:CC | -LL | Some(_x) => {}, +LL | Some(_x) => {} | ^^ | | | trying to reborrow for Unique permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location diff --git a/tests/fail/stacked_borrows/return_invalid_shr_option.stderr b/tests/fail/stacked_borrows/return_invalid_shr_option.stderr index 81244a87cb065..a23c69d12db16 100644 --- a/tests/fail/stacked_borrows/return_invalid_shr_option.stderr +++ b/tests/fail/stacked_borrows/return_invalid_shr_option.stderr @@ -1,7 +1,7 @@ error: Undefined Behavior: trying to reborrow for SharedReadOnly permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location --> $DIR/return_invalid_shr_option.rs:LL:CC | -LL | Some(_x) => {}, +LL | Some(_x) => {} | ^^ | | | trying to reborrow for SharedReadOnly permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location diff --git a/tests/fail/stacked_borrows/shared_rw_borrows_are_weak1.stderr b/tests/fail/stacked_borrows/shared_rw_borrows_are_weak1.stderr index 8bb67f62b5318..151654bad5cfe 100644 --- a/tests/fail/stacked_borrows/shared_rw_borrows_are_weak1.stderr +++ b/tests/fail/stacked_borrows/shared_rw_borrows_are_weak1.stderr @@ -1,24 +1,24 @@ error: Undefined Behavior: trying to reborrow for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location --> $DIR/shared_rw_borrows_are_weak1.rs:LL:CC | -LL | y.get_mut(); - | ^^^^^^^^^^^ - | | - | trying to reborrow for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location - | this error occurs as part of a reborrow at ALLOC[0x0..0x4] +LL | y.get_mut(); + | ^^^^^^^^^^^ + | | + | trying to reborrow for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | this error occurs as part of a reborrow at ALLOC[0x0..0x4] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: was created by a retag at offsets [0x0..0x4] --> $DIR/shared_rw_borrows_are_weak1.rs:LL:CC | -LL | let y: &mut Cell = mem::transmute(&mut *x); // launder lifetime - | ^^^^^^^^^^^^^^^^^^^^^^^ +LL | let y: &mut Cell = mem::transmute(&mut *x); // launder lifetime + | ^^^^^^^^^^^^^^^^^^^^^^^ help: was later invalidated at offsets [0x0..0x4] --> $DIR/shared_rw_borrows_are_weak1.rs:LL:CC | -LL | shr_rw.set(1); - | ^^^^^^^^^^^^^ +LL | shr_rw.set(1); + | ^^^^^^^^^^^^^ = note: inside `main` at $DIR/shared_rw_borrows_are_weak1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/shared_rw_borrows_are_weak2.stderr b/tests/fail/stacked_borrows/shared_rw_borrows_are_weak2.stderr index b339785d64842..c0bf809356bd6 100644 --- a/tests/fail/stacked_borrows/shared_rw_borrows_are_weak2.stderr +++ b/tests/fail/stacked_borrows/shared_rw_borrows_are_weak2.stderr @@ -1,24 +1,24 @@ error: Undefined Behavior: attempting a read access using at ALLOC[$HEX], but that tag does not exist in the borrow stack for this location --> $DIR/shared_rw_borrows_are_weak2.rs:LL:CC | -LL | let _val = *y; - | ^^ - | | - | attempting a read access using at ALLOC[$HEX], but that tag does not exist in the borrow stack for this location - | this error occurs as part of an access at ALLOC[$HEX..$HEX] +LL | let _val = *y; + | ^^ + | | + | attempting a read access using at ALLOC[$HEX], but that tag does not exist in the borrow stack for this location + | this error occurs as part of an access at ALLOC[$HEX..$HEX] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: was created by a retag at offsets [$HEX..$HEX] --> $DIR/shared_rw_borrows_are_weak2.rs:LL:CC | -LL | let y: &i32 = mem::transmute(&*x.borrow()); // launder lifetime - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | let y: &i32 = mem::transmute(&*x.borrow()); // launder lifetime + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: was later invalidated at offsets [$HEX..$HEX] --> $DIR/shared_rw_borrows_are_weak2.rs:LL:CC | -LL | shr_rw.replace(1); - | ^^^^^^^^^^^^^^^^^ +LL | shr_rw.replace(1); + | ^^^^^^^^^^^^^^^^^ = note: inside `main` at $DIR/shared_rw_borrows_are_weak2.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/transmute_fat1.stderr b/tests/fail/transmute_fat1.stderr index cbfa8dff2a50c..2b095dc3c1c02 100644 --- a/tests/fail/transmute_fat1.stderr +++ b/tests/fail/transmute_fat1.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: type validation failed: encountered a pointer, but expected plain (non-pointer) bytes --> $DIR/transmute_fat1.rs:LL:CC | -LL | std::mem::transmute::<&[u8], $ARRAY>(&[1u8]) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected plain (non-pointer) bytes +LL | let bad = unsafe { std::mem::transmute::<&[u8], $ARRAY>(&[1u8]) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected plain (non-pointer) bytes | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/unaligned_pointers/alignment.stderr b/tests/fail/unaligned_pointers/alignment.stderr index c21e2ed2ec674..0e6ca83366ad2 100644 --- a/tests/fail/unaligned_pointers/alignment.stderr +++ b/tests/fail/unaligned_pointers/alignment.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: accessing memory with alignment ALIGN, but alignment ALIGN is required --> $DIR/alignment.rs:LL:CC | -LL | *(x_ptr as *mut u32) = 42; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ accessing memory with alignment ALIGN, but alignment ALIGN is required +LL | *(x_ptr as *mut u32) = 42; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ accessing memory with alignment ALIGN, but alignment ALIGN is required | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/validity/ref_to_uninhabited1.stderr b/tests/fail/validity/ref_to_uninhabited1.stderr index de41944944e3a..dbaee46a93b8f 100644 --- a/tests/fail/validity/ref_to_uninhabited1.stderr +++ b/tests/fail/validity/ref_to_uninhabited1.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: type validation failed: encountered a box pointing to uninhabited type ! --> $DIR/ref_to_uninhabited1.rs:LL:CC | -LL | let x: Box = transmute(&mut 42); - | ^^^^^^^^^^^^^^^^^^ type validation failed: encountered a box pointing to uninhabited type ! +LL | let x: Box = transmute(&mut 42); + | ^^^^^^^^^^^^^^^^^^ type validation failed: encountered a box pointing to uninhabited type ! | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/validity/ref_to_uninhabited2.stderr b/tests/fail/validity/ref_to_uninhabited2.stderr index 754c39e78901c..115cdfedf7775 100644 --- a/tests/fail/validity/ref_to_uninhabited2.stderr +++ b/tests/fail/validity/ref_to_uninhabited2.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: type validation failed: encountered a reference pointing to uninhabited type (i32, Void) --> $DIR/ref_to_uninhabited2.rs:LL:CC | -LL | let _x: &(i32, Void) = transmute(&42); - | ^^^^^^^^^^^^^^ type validation failed: encountered a reference pointing to uninhabited type (i32, Void) +LL | let _x: &(i32, Void) = transmute(&42); + | ^^^^^^^^^^^^^^ type validation failed: encountered a reference pointing to uninhabited type (i32, Void) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/validity/too-big-slice.stderr b/tests/fail/validity/too-big-slice.stderr index 11d20d3e623b0..9c8d2929bda00 100644 --- a/tests/fail/validity/too-big-slice.stderr +++ b/tests/fail/validity/too-big-slice.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: type validation failed: encountered invalid reference metadata: slice is bigger than largest supported object --> $DIR/too-big-slice.rs:LL:CC | -LL | let _x: &[u8] = mem::transmute((ptr, usize::MAX)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered invalid reference metadata: slice is bigger than largest supported object +LL | let _x: &[u8] = mem::transmute((ptr, usize::MAX)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered invalid reference metadata: slice is bigger than largest supported object | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/validity/too-big-unsized.stderr b/tests/fail/validity/too-big-unsized.stderr index 0c7b7b23246ef..18dc5d8b9c18e 100644 --- a/tests/fail/validity/too-big-unsized.stderr +++ b/tests/fail/validity/too-big-unsized.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: type validation failed: encountered invalid reference metadata: total size is bigger than largest supported object --> $DIR/too-big-unsized.rs:LL:CC | -LL | let _x: &MySlice = mem::transmute((ptr, isize::MAX as usize)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered invalid reference metadata: total size is bigger than largest supported object +LL | let _x: &MySlice = mem::transmute((ptr, isize::MAX as usize)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered invalid reference metadata: total size is bigger than largest supported object | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information From 6827ac2f37908f328305bae91d2e5387975da64e Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Tue, 21 Jun 2022 11:38:02 -0700 Subject: [PATCH 3285/3747] Format tests with rustfmt (225-275 of 300) --- tests/fail/box-cell-alias.rs | 4 +++- .../dangling_pointers/maybe_null_pointer_write_zst.rs | 4 +++- tests/fail/intrinsics/copy_null.rs | 4 +++- tests/fail/intrinsics/copy_unaligned.rs | 4 +++- tests/fail/intrinsics/exact_div1.rs | 4 +++- tests/fail/intrinsics/exact_div2.rs | 4 +++- tests/fail/intrinsics/exact_div3.rs | 4 +++- tests/fail/intrinsics/exact_div4.rs | 4 +++- tests/fail/intrinsics/float_to_int_32_inf1.rs | 4 +++- tests/fail/intrinsics/float_to_int_32_infneg1.rs | 4 +++- tests/fail/intrinsics/float_to_int_32_nan.rs | 4 +++- tests/fail/intrinsics/float_to_int_32_nanneg.rs | 4 +++- tests/fail/intrinsics/float_to_int_32_neg.rs | 4 +++- tests/fail/intrinsics/float_to_int_32_too_big1.rs | 4 +++- tests/fail/intrinsics/float_to_int_32_too_big2.rs | 4 +++- tests/fail/intrinsics/float_to_int_32_too_small1.rs | 4 +++- tests/fail/intrinsics/float_to_int_64_inf1.rs | 4 +++- tests/fail/intrinsics/float_to_int_64_infneg1.rs | 4 +++- tests/fail/intrinsics/float_to_int_64_infneg2.rs | 4 +++- tests/fail/intrinsics/float_to_int_64_nan.rs | 4 +++- tests/fail/intrinsics/float_to_int_64_neg.rs | 4 +++- tests/fail/intrinsics/float_to_int_64_too_big1.rs | 4 +++- tests/fail/intrinsics/float_to_int_64_too_big2.rs | 4 +++- tests/fail/intrinsics/float_to_int_64_too_big3.rs | 4 +++- tests/fail/intrinsics/float_to_int_64_too_big4.rs | 4 +++- tests/fail/intrinsics/float_to_int_64_too_big5.rs | 4 +++- tests/fail/intrinsics/float_to_int_64_too_big6.rs | 4 +++- tests/fail/intrinsics/float_to_int_64_too_big7.rs | 4 +++- tests/fail/intrinsics/float_to_int_64_too_small1.rs | 4 +++- tests/fail/intrinsics/float_to_int_64_too_small2.rs | 4 +++- tests/fail/intrinsics/float_to_int_64_too_small3.rs | 4 +++- tests/fail/intrinsics/unchecked_add1.rs | 4 +++- tests/fail/intrinsics/unchecked_add2.rs | 4 +++- tests/fail/intrinsics/unchecked_div1.rs | 4 +++- tests/fail/intrinsics/unchecked_mul1.rs | 4 +++- tests/fail/intrinsics/unchecked_mul2.rs | 4 +++- tests/fail/intrinsics/unchecked_sub1.rs | 4 +++- tests/fail/intrinsics/unchecked_sub2.rs | 4 +++- tests/fail/panic/unwind_panic_abort.rs | 4 +++- tests/fail/stacked_borrows/illegal_write1.rs | 6 ++++-- tests/fail/stacked_borrows/illegal_write2.rs | 4 +++- tests/fail/stacked_borrows/illegal_write3.rs | 4 +++- tests/fail/stacked_borrows/illegal_write6.rs | 4 +++- tests/fail/stacked_borrows/raw_tracking.rs | 8 ++++++-- tests/fail/stacked_borrows/shr_frozen_violation1.rs | 10 ++++++---- tests/fail/stacked_borrows/transmute-is-no-escape.rs | 4 +++- tests/fail/stacked_borrows/unescaped_local.rs | 4 +++- .../unaligned_pointers/intptrcast_alignment_check.rs | 6 ++++-- tests/fail/validity/transmute_through_ptr.rs | 8 ++++++-- tests/fail/zst2.rs | 4 +++- tests/fail/zst3.rs | 8 ++++++-- 51 files changed, 167 insertions(+), 59 deletions(-) diff --git a/tests/fail/box-cell-alias.rs b/tests/fail/box-cell-alias.rs index 49cce2750784a..ffda1033d44bf 100644 --- a/tests/fail/box-cell-alias.rs +++ b/tests/fail/box-cell-alias.rs @@ -6,7 +6,9 @@ use std::cell::Cell; fn helper(val: Box>, ptr: *const Cell) -> u8 { val.set(10); - unsafe { (*ptr).set(20); } //~ ERROR does not exist in the borrow stack + unsafe { + (*ptr).set(20); + } //~ ERROR does not exist in the borrow stack val.get() } diff --git a/tests/fail/dangling_pointers/maybe_null_pointer_write_zst.rs b/tests/fail/dangling_pointers/maybe_null_pointer_write_zst.rs index 7f50b9827d94b..78384502337c7 100644 --- a/tests/fail/dangling_pointers/maybe_null_pointer_write_zst.rs +++ b/tests/fail/dangling_pointers/maybe_null_pointer_write_zst.rs @@ -7,5 +7,7 @@ fn main() { // Also not assigning directly as that's array initialization, not assignment. let zst_val = [1u8; 0]; let ptr = (&0u8 as *const u8).wrapping_sub(0x800) as *mut [u8; 0]; - unsafe { *ptr = zst_val; } //~ ERROR out-of-bounds + unsafe { + *ptr = zst_val; + } //~ ERROR out-of-bounds } diff --git a/tests/fail/intrinsics/copy_null.rs b/tests/fail/intrinsics/copy_null.rs index 8f32ad1a760ff..1e572fe4a8559 100644 --- a/tests/fail/intrinsics/copy_null.rs +++ b/tests/fail/intrinsics/copy_null.rs @@ -9,5 +9,7 @@ fn main() { let mut data = [0u16; 4]; let ptr = &mut data[0] as *mut u16; // Even copying 0 elements from NULL should error. - unsafe { copy_nonoverlapping(std::ptr::null(), ptr, 0); } //~ ERROR: memory access failed: null pointer is not a valid pointer + unsafe { + copy_nonoverlapping(std::ptr::null(), ptr, 0); + } //~ ERROR: memory access failed: null pointer is not a valid pointer } diff --git a/tests/fail/intrinsics/copy_unaligned.rs b/tests/fail/intrinsics/copy_unaligned.rs index 84f4de93461e7..d7097bb91d3a6 100644 --- a/tests/fail/intrinsics/copy_unaligned.rs +++ b/tests/fail/intrinsics/copy_unaligned.rs @@ -9,5 +9,7 @@ fn main() { let mut data = [0u16; 8]; let ptr = (&mut data[0] as *mut u16 as *mut u8).wrapping_add(1) as *mut u16; // Even copying 0 elements to something unaligned should error - unsafe { copy_nonoverlapping(&data[5], ptr, 0); } //~ ERROR accessing memory with alignment 1, but alignment 2 is required + unsafe { + copy_nonoverlapping(&data[5], ptr, 0); + } //~ ERROR accessing memory with alignment 1, but alignment 2 is required } diff --git a/tests/fail/intrinsics/exact_div1.rs b/tests/fail/intrinsics/exact_div1.rs index 171bedeadc672..5d2185f1ee1b5 100644 --- a/tests/fail/intrinsics/exact_div1.rs +++ b/tests/fail/intrinsics/exact_div1.rs @@ -1,5 +1,7 @@ #![feature(core_intrinsics)] fn main() { // divison by 0 - unsafe { std::intrinsics::exact_div(2, 0); } //~ ERROR divisor of zero + unsafe { + std::intrinsics::exact_div(2, 0); + } //~ ERROR divisor of zero } diff --git a/tests/fail/intrinsics/exact_div2.rs b/tests/fail/intrinsics/exact_div2.rs index 1327046920d26..e0301fbd73e23 100644 --- a/tests/fail/intrinsics/exact_div2.rs +++ b/tests/fail/intrinsics/exact_div2.rs @@ -1,5 +1,7 @@ #![feature(core_intrinsics)] fn main() { // divison with a remainder - unsafe { std::intrinsics::exact_div(2u16, 3); } //~ ERROR 2_u16 cannot be divided by 3_u16 without remainder + unsafe { + std::intrinsics::exact_div(2u16, 3); + } //~ ERROR 2_u16 cannot be divided by 3_u16 without remainder } diff --git a/tests/fail/intrinsics/exact_div3.rs b/tests/fail/intrinsics/exact_div3.rs index 6a309442749b1..5f74b2dfa818b 100644 --- a/tests/fail/intrinsics/exact_div3.rs +++ b/tests/fail/intrinsics/exact_div3.rs @@ -1,5 +1,7 @@ #![feature(core_intrinsics)] fn main() { // signed divison with a remainder - unsafe { std::intrinsics::exact_div(-19i8, 2); } //~ ERROR -19_i8 cannot be divided by 2_i8 without remainder + unsafe { + std::intrinsics::exact_div(-19i8, 2); + } //~ ERROR -19_i8 cannot be divided by 2_i8 without remainder } diff --git a/tests/fail/intrinsics/exact_div4.rs b/tests/fail/intrinsics/exact_div4.rs index 2831795de82ea..f70746d2a1164 100644 --- a/tests/fail/intrinsics/exact_div4.rs +++ b/tests/fail/intrinsics/exact_div4.rs @@ -1,5 +1,7 @@ #![feature(core_intrinsics)] fn main() { // divison of MIN by -1 - unsafe { std::intrinsics::exact_div(i64::MIN, -1); } //~ ERROR overflow in signed remainder (dividing MIN by -1) + unsafe { + std::intrinsics::exact_div(i64::MIN, -1); + } //~ ERROR overflow in signed remainder (dividing MIN by -1) } diff --git a/tests/fail/intrinsics/float_to_int_32_inf1.rs b/tests/fail/intrinsics/float_to_int_32_inf1.rs index a56f4aefad3a7..32c2e09b53a3e 100644 --- a/tests/fail/intrinsics/float_to_int_32_inf1.rs +++ b/tests/fail/intrinsics/float_to_int_32_inf1.rs @@ -6,5 +6,7 @@ extern "rust-intrinsic" { } fn main() { - unsafe { float_to_int_unchecked::(f32::INFINITY); } //~ ERROR: cannot be represented in target type `i32` + unsafe { + float_to_int_unchecked::(f32::INFINITY); + } //~ ERROR: cannot be represented in target type `i32` } diff --git a/tests/fail/intrinsics/float_to_int_32_infneg1.rs b/tests/fail/intrinsics/float_to_int_32_infneg1.rs index d18f75fcca8ab..e1ba2224a088c 100644 --- a/tests/fail/intrinsics/float_to_int_32_infneg1.rs +++ b/tests/fail/intrinsics/float_to_int_32_infneg1.rs @@ -6,5 +6,7 @@ extern "rust-intrinsic" { } fn main() { - unsafe { float_to_int_unchecked::(f32::NEG_INFINITY); } //~ ERROR: cannot be represented in target type `i32` + unsafe { + float_to_int_unchecked::(f32::NEG_INFINITY); + } //~ ERROR: cannot be represented in target type `i32` } diff --git a/tests/fail/intrinsics/float_to_int_32_nan.rs b/tests/fail/intrinsics/float_to_int_32_nan.rs index e1fe8c7cf2f74..6c128d94a87f8 100644 --- a/tests/fail/intrinsics/float_to_int_32_nan.rs +++ b/tests/fail/intrinsics/float_to_int_32_nan.rs @@ -6,5 +6,7 @@ extern "rust-intrinsic" { } fn main() { - unsafe { float_to_int_unchecked::(f32::NAN); } //~ ERROR: cannot be represented in target type `u32` + unsafe { + float_to_int_unchecked::(f32::NAN); + } //~ ERROR: cannot be represented in target type `u32` } diff --git a/tests/fail/intrinsics/float_to_int_32_nanneg.rs b/tests/fail/intrinsics/float_to_int_32_nanneg.rs index 38899045c92c0..9bc628e9db924 100644 --- a/tests/fail/intrinsics/float_to_int_32_nanneg.rs +++ b/tests/fail/intrinsics/float_to_int_32_nanneg.rs @@ -6,5 +6,7 @@ extern "rust-intrinsic" { } fn main() { - unsafe { float_to_int_unchecked::(-f32::NAN); } //~ ERROR: cannot be represented in target type `u32` + unsafe { + float_to_int_unchecked::(-f32::NAN); + } //~ ERROR: cannot be represented in target type `u32` } diff --git a/tests/fail/intrinsics/float_to_int_32_neg.rs b/tests/fail/intrinsics/float_to_int_32_neg.rs index f15cf9a9cd643..188a9256db7ed 100644 --- a/tests/fail/intrinsics/float_to_int_32_neg.rs +++ b/tests/fail/intrinsics/float_to_int_32_neg.rs @@ -6,5 +6,7 @@ extern "rust-intrinsic" { } fn main() { - unsafe { float_to_int_unchecked::(-1.000000001f32); } //~ ERROR: cannot be represented in target type `u32` + unsafe { + float_to_int_unchecked::(-1.000000001f32); + } //~ ERROR: cannot be represented in target type `u32` } diff --git a/tests/fail/intrinsics/float_to_int_32_too_big1.rs b/tests/fail/intrinsics/float_to_int_32_too_big1.rs index ccbf917c8e89f..787941e63e2ba 100644 --- a/tests/fail/intrinsics/float_to_int_32_too_big1.rs +++ b/tests/fail/intrinsics/float_to_int_32_too_big1.rs @@ -6,5 +6,7 @@ extern "rust-intrinsic" { } fn main() { - unsafe { float_to_int_unchecked::(2147483648.0f32); } //~ ERROR: cannot be represented in target type `i32` + unsafe { + float_to_int_unchecked::(2147483648.0f32); + } //~ ERROR: cannot be represented in target type `i32` } diff --git a/tests/fail/intrinsics/float_to_int_32_too_big2.rs b/tests/fail/intrinsics/float_to_int_32_too_big2.rs index 6598fd36e038a..39b74cb048691 100644 --- a/tests/fail/intrinsics/float_to_int_32_too_big2.rs +++ b/tests/fail/intrinsics/float_to_int_32_too_big2.rs @@ -6,5 +6,7 @@ extern "rust-intrinsic" { } fn main() { - unsafe { float_to_int_unchecked::((u32::MAX-127) as f32); } //~ ERROR: cannot be represented in target type `u32` + unsafe { + float_to_int_unchecked::((u32::MAX - 127) as f32); + } //~ ERROR: cannot be represented in target type `u32` } diff --git a/tests/fail/intrinsics/float_to_int_32_too_small1.rs b/tests/fail/intrinsics/float_to_int_32_too_small1.rs index 89f09e1e3f18a..a96738214bd01 100644 --- a/tests/fail/intrinsics/float_to_int_32_too_small1.rs +++ b/tests/fail/intrinsics/float_to_int_32_too_small1.rs @@ -6,5 +6,7 @@ extern "rust-intrinsic" { } fn main() { - unsafe { float_to_int_unchecked::(-2147483904.0f32); } //~ ERROR: cannot be represented in target type `i32` + unsafe { + float_to_int_unchecked::(-2147483904.0f32); + } //~ ERROR: cannot be represented in target type `i32` } diff --git a/tests/fail/intrinsics/float_to_int_64_inf1.rs b/tests/fail/intrinsics/float_to_int_64_inf1.rs index e1a7b818d8539..259ec883f6caa 100644 --- a/tests/fail/intrinsics/float_to_int_64_inf1.rs +++ b/tests/fail/intrinsics/float_to_int_64_inf1.rs @@ -6,5 +6,7 @@ extern "rust-intrinsic" { } fn main() { - unsafe { float_to_int_unchecked::(f64::INFINITY); } //~ ERROR: cannot be represented in target type `u128` + unsafe { + float_to_int_unchecked::(f64::INFINITY); + } //~ ERROR: cannot be represented in target type `u128` } diff --git a/tests/fail/intrinsics/float_to_int_64_infneg1.rs b/tests/fail/intrinsics/float_to_int_64_infneg1.rs index a1d757b1511e6..3bc5ac710e974 100644 --- a/tests/fail/intrinsics/float_to_int_64_infneg1.rs +++ b/tests/fail/intrinsics/float_to_int_64_infneg1.rs @@ -6,5 +6,7 @@ extern "rust-intrinsic" { } fn main() { - unsafe { float_to_int_unchecked::(f64::NEG_INFINITY); } //~ ERROR: cannot be represented in target type `u128` + unsafe { + float_to_int_unchecked::(f64::NEG_INFINITY); + } //~ ERROR: cannot be represented in target type `u128` } diff --git a/tests/fail/intrinsics/float_to_int_64_infneg2.rs b/tests/fail/intrinsics/float_to_int_64_infneg2.rs index e48d19f1a6a86..81a79c4d2116a 100644 --- a/tests/fail/intrinsics/float_to_int_64_infneg2.rs +++ b/tests/fail/intrinsics/float_to_int_64_infneg2.rs @@ -6,5 +6,7 @@ extern "rust-intrinsic" { } fn main() { - unsafe { float_to_int_unchecked::(f64::NEG_INFINITY); } //~ ERROR: cannot be represented in target type `i128` + unsafe { + float_to_int_unchecked::(f64::NEG_INFINITY); + } //~ ERROR: cannot be represented in target type `i128` } diff --git a/tests/fail/intrinsics/float_to_int_64_nan.rs b/tests/fail/intrinsics/float_to_int_64_nan.rs index 03f378f5bcb72..47580ad5b2a00 100644 --- a/tests/fail/intrinsics/float_to_int_64_nan.rs +++ b/tests/fail/intrinsics/float_to_int_64_nan.rs @@ -6,5 +6,7 @@ extern "rust-intrinsic" { } fn main() { - unsafe { float_to_int_unchecked::(f64::NAN); } //~ ERROR: cannot be represented in target type `u32` + unsafe { + float_to_int_unchecked::(f64::NAN); + } //~ ERROR: cannot be represented in target type `u32` } diff --git a/tests/fail/intrinsics/float_to_int_64_neg.rs b/tests/fail/intrinsics/float_to_int_64_neg.rs index d0b5a3e21cf9e..0e97c2f26bb3a 100644 --- a/tests/fail/intrinsics/float_to_int_64_neg.rs +++ b/tests/fail/intrinsics/float_to_int_64_neg.rs @@ -6,5 +6,7 @@ extern "rust-intrinsic" { } fn main() { - unsafe { float_to_int_unchecked::(-1.0000000000001f64); } //~ ERROR: cannot be represented in target type `u128` + unsafe { + float_to_int_unchecked::(-1.0000000000001f64); + } //~ ERROR: cannot be represented in target type `u128` } diff --git a/tests/fail/intrinsics/float_to_int_64_too_big1.rs b/tests/fail/intrinsics/float_to_int_64_too_big1.rs index f928f161872e2..fb75a793ded42 100644 --- a/tests/fail/intrinsics/float_to_int_64_too_big1.rs +++ b/tests/fail/intrinsics/float_to_int_64_too_big1.rs @@ -6,5 +6,7 @@ extern "rust-intrinsic" { } fn main() { - unsafe { float_to_int_unchecked::(2147483648.0f64); } //~ ERROR: cannot be represented in target type `i32` + unsafe { + float_to_int_unchecked::(2147483648.0f64); + } //~ ERROR: cannot be represented in target type `i32` } diff --git a/tests/fail/intrinsics/float_to_int_64_too_big2.rs b/tests/fail/intrinsics/float_to_int_64_too_big2.rs index feb24c362dda7..0c039ff8493e0 100644 --- a/tests/fail/intrinsics/float_to_int_64_too_big2.rs +++ b/tests/fail/intrinsics/float_to_int_64_too_big2.rs @@ -6,5 +6,7 @@ extern "rust-intrinsic" { } fn main() { - unsafe { float_to_int_unchecked::(9223372036854775808.0f64); } //~ ERROR: cannot be represented in target type `i64` + unsafe { + float_to_int_unchecked::(9223372036854775808.0f64); + } //~ ERROR: cannot be represented in target type `i64` } diff --git a/tests/fail/intrinsics/float_to_int_64_too_big3.rs b/tests/fail/intrinsics/float_to_int_64_too_big3.rs index cd491bfed7eb9..b9d2775f0325d 100644 --- a/tests/fail/intrinsics/float_to_int_64_too_big3.rs +++ b/tests/fail/intrinsics/float_to_int_64_too_big3.rs @@ -6,5 +6,7 @@ extern "rust-intrinsic" { } fn main() { - unsafe { float_to_int_unchecked::(18446744073709551616.0f64); } //~ ERROR: cannot be represented in target type `u64` + unsafe { + float_to_int_unchecked::(18446744073709551616.0f64); + } //~ ERROR: cannot be represented in target type `u64` } diff --git a/tests/fail/intrinsics/float_to_int_64_too_big4.rs b/tests/fail/intrinsics/float_to_int_64_too_big4.rs index e9623dba947f3..4a2dc7822f78c 100644 --- a/tests/fail/intrinsics/float_to_int_64_too_big4.rs +++ b/tests/fail/intrinsics/float_to_int_64_too_big4.rs @@ -6,5 +6,7 @@ extern "rust-intrinsic" { } fn main() { - unsafe { float_to_int_unchecked::(u128::MAX as f64); } //~ ERROR: cannot be represented in target type `u128` + unsafe { + float_to_int_unchecked::(u128::MAX as f64); + } //~ ERROR: cannot be represented in target type `u128` } diff --git a/tests/fail/intrinsics/float_to_int_64_too_big5.rs b/tests/fail/intrinsics/float_to_int_64_too_big5.rs index 9c31c690b4e8a..bf1f797a0003e 100644 --- a/tests/fail/intrinsics/float_to_int_64_too_big5.rs +++ b/tests/fail/intrinsics/float_to_int_64_too_big5.rs @@ -6,5 +6,7 @@ extern "rust-intrinsic" { } fn main() { - unsafe { float_to_int_unchecked::(240282366920938463463374607431768211455.0f64); } //~ ERROR: cannot be represented in target type `i128` + unsafe { + float_to_int_unchecked::(240282366920938463463374607431768211455.0f64); + } //~ ERROR: cannot be represented in target type `i128` } diff --git a/tests/fail/intrinsics/float_to_int_64_too_big6.rs b/tests/fail/intrinsics/float_to_int_64_too_big6.rs index f008131a6e529..2b6d6359c9a81 100644 --- a/tests/fail/intrinsics/float_to_int_64_too_big6.rs +++ b/tests/fail/intrinsics/float_to_int_64_too_big6.rs @@ -6,5 +6,7 @@ extern "rust-intrinsic" { } fn main() { - unsafe { float_to_int_unchecked::(f64::MAX); } //~ ERROR: cannot be represented in target type `u128` + unsafe { + float_to_int_unchecked::(f64::MAX); + } //~ ERROR: cannot be represented in target type `u128` } diff --git a/tests/fail/intrinsics/float_to_int_64_too_big7.rs b/tests/fail/intrinsics/float_to_int_64_too_big7.rs index 69922e60a6bc2..e9b1333232c0a 100644 --- a/tests/fail/intrinsics/float_to_int_64_too_big7.rs +++ b/tests/fail/intrinsics/float_to_int_64_too_big7.rs @@ -6,5 +6,7 @@ extern "rust-intrinsic" { } fn main() { - unsafe { float_to_int_unchecked::(f64::MIN); } //~ ERROR: cannot be represented in target type `i128` + unsafe { + float_to_int_unchecked::(f64::MIN); + } //~ ERROR: cannot be represented in target type `i128` } diff --git a/tests/fail/intrinsics/float_to_int_64_too_small1.rs b/tests/fail/intrinsics/float_to_int_64_too_small1.rs index 08f2f9e3fd26c..652edf1931b3e 100644 --- a/tests/fail/intrinsics/float_to_int_64_too_small1.rs +++ b/tests/fail/intrinsics/float_to_int_64_too_small1.rs @@ -6,5 +6,7 @@ extern "rust-intrinsic" { } fn main() { - unsafe { float_to_int_unchecked::(-2147483649.0f64); } //~ ERROR: cannot be represented in target type `i32` + unsafe { + float_to_int_unchecked::(-2147483649.0f64); + } //~ ERROR: cannot be represented in target type `i32` } diff --git a/tests/fail/intrinsics/float_to_int_64_too_small2.rs b/tests/fail/intrinsics/float_to_int_64_too_small2.rs index f7b205de5346c..d3d5559291b3a 100644 --- a/tests/fail/intrinsics/float_to_int_64_too_small2.rs +++ b/tests/fail/intrinsics/float_to_int_64_too_small2.rs @@ -6,5 +6,7 @@ extern "rust-intrinsic" { } fn main() { - unsafe { float_to_int_unchecked::(-9223372036854777856.0f64); } //~ ERROR: cannot be represented in target type `i64` + unsafe { + float_to_int_unchecked::(-9223372036854777856.0f64); + } //~ ERROR: cannot be represented in target type `i64` } diff --git a/tests/fail/intrinsics/float_to_int_64_too_small3.rs b/tests/fail/intrinsics/float_to_int_64_too_small3.rs index 779441f7448c8..0e22951a45cdb 100644 --- a/tests/fail/intrinsics/float_to_int_64_too_small3.rs +++ b/tests/fail/intrinsics/float_to_int_64_too_small3.rs @@ -6,5 +6,7 @@ extern "rust-intrinsic" { } fn main() { - unsafe { float_to_int_unchecked::(-240282366920938463463374607431768211455.0f64); } //~ ERROR: cannot be represented in target type `i128` + unsafe { + float_to_int_unchecked::(-240282366920938463463374607431768211455.0f64); + } //~ ERROR: cannot be represented in target type `i128` } diff --git a/tests/fail/intrinsics/unchecked_add1.rs b/tests/fail/intrinsics/unchecked_add1.rs index f48b91422c6e7..90d0a3d01236f 100644 --- a/tests/fail/intrinsics/unchecked_add1.rs +++ b/tests/fail/intrinsics/unchecked_add1.rs @@ -1,5 +1,7 @@ #![feature(core_intrinsics)] fn main() { // MAX overflow - unsafe { std::intrinsics::unchecked_add(40000u16, 30000); } //~ ERROR overflow executing `unchecked_add` + unsafe { + std::intrinsics::unchecked_add(40000u16, 30000); + } //~ ERROR overflow executing `unchecked_add` } diff --git a/tests/fail/intrinsics/unchecked_add2.rs b/tests/fail/intrinsics/unchecked_add2.rs index 150986541c3d9..68e9fb4563e7e 100644 --- a/tests/fail/intrinsics/unchecked_add2.rs +++ b/tests/fail/intrinsics/unchecked_add2.rs @@ -1,5 +1,7 @@ #![feature(core_intrinsics)] fn main() { // MIN overflow - unsafe { std::intrinsics::unchecked_add(-30000i16, -8000); } //~ ERROR overflow executing `unchecked_add` + unsafe { + std::intrinsics::unchecked_add(-30000i16, -8000); + } //~ ERROR overflow executing `unchecked_add` } diff --git a/tests/fail/intrinsics/unchecked_div1.rs b/tests/fail/intrinsics/unchecked_div1.rs index 08b654da3ed75..23fc1514f1a18 100644 --- a/tests/fail/intrinsics/unchecked_div1.rs +++ b/tests/fail/intrinsics/unchecked_div1.rs @@ -1,5 +1,7 @@ #![feature(core_intrinsics)] fn main() { // MIN/-1 cannot be represented - unsafe { std::intrinsics::unchecked_div(i16::MIN, -1); } //~ ERROR overflow in signed division (dividing MIN by -1) + unsafe { + std::intrinsics::unchecked_div(i16::MIN, -1); + } //~ ERROR overflow in signed division (dividing MIN by -1) } diff --git a/tests/fail/intrinsics/unchecked_mul1.rs b/tests/fail/intrinsics/unchecked_mul1.rs index 050e3ff243770..f26d4d3d213f8 100644 --- a/tests/fail/intrinsics/unchecked_mul1.rs +++ b/tests/fail/intrinsics/unchecked_mul1.rs @@ -1,5 +1,7 @@ #![feature(core_intrinsics)] fn main() { // MAX overflow - unsafe { std::intrinsics::unchecked_mul(300u16, 250u16); } //~ ERROR overflow executing `unchecked_mul` + unsafe { + std::intrinsics::unchecked_mul(300u16, 250u16); + } //~ ERROR overflow executing `unchecked_mul` } diff --git a/tests/fail/intrinsics/unchecked_mul2.rs b/tests/fail/intrinsics/unchecked_mul2.rs index 4fb77783b4ce7..f3e20e8c295d9 100644 --- a/tests/fail/intrinsics/unchecked_mul2.rs +++ b/tests/fail/intrinsics/unchecked_mul2.rs @@ -1,5 +1,7 @@ #![feature(core_intrinsics)] fn main() { // MIN overflow - unsafe { std::intrinsics::unchecked_mul(1_000_000_000i32, -4); } //~ ERROR overflow executing `unchecked_mul` + unsafe { + std::intrinsics::unchecked_mul(1_000_000_000i32, -4); + } //~ ERROR overflow executing `unchecked_mul` } diff --git a/tests/fail/intrinsics/unchecked_sub1.rs b/tests/fail/intrinsics/unchecked_sub1.rs index 69b32dd319b6f..3ea5e618074cc 100644 --- a/tests/fail/intrinsics/unchecked_sub1.rs +++ b/tests/fail/intrinsics/unchecked_sub1.rs @@ -1,5 +1,7 @@ #![feature(core_intrinsics)] fn main() { // MIN overflow - unsafe { std::intrinsics::unchecked_sub(14u32, 22); } //~ ERROR overflow executing `unchecked_sub` + unsafe { + std::intrinsics::unchecked_sub(14u32, 22); + } //~ ERROR overflow executing `unchecked_sub` } diff --git a/tests/fail/intrinsics/unchecked_sub2.rs b/tests/fail/intrinsics/unchecked_sub2.rs index 5609ea7a3eddc..0e9892e58a52d 100644 --- a/tests/fail/intrinsics/unchecked_sub2.rs +++ b/tests/fail/intrinsics/unchecked_sub2.rs @@ -1,5 +1,7 @@ #![feature(core_intrinsics)] fn main() { // MAX overflow - unsafe { std::intrinsics::unchecked_sub(30000i16, -7000); } //~ ERROR overflow executing `unchecked_sub` + unsafe { + std::intrinsics::unchecked_sub(30000i16, -7000); + } //~ ERROR overflow executing `unchecked_sub` } diff --git a/tests/fail/panic/unwind_panic_abort.rs b/tests/fail/panic/unwind_panic_abort.rs index a333a4b0ded8f..7cb0c7b027991 100644 --- a/tests/fail/panic/unwind_panic_abort.rs +++ b/tests/fail/panic/unwind_panic_abort.rs @@ -7,5 +7,7 @@ extern "Rust" { } fn main() { - unsafe { miri_start_panic(&mut 0); } //~ ERROR unwinding past a stack frame that does not allow unwinding + unsafe { + miri_start_panic(&mut 0); + } //~ ERROR unwinding past a stack frame that does not allow unwinding } diff --git a/tests/fail/stacked_borrows/illegal_write1.rs b/tests/fail/stacked_borrows/illegal_write1.rs index dd262a341ed2d..5bdd4ef1f052a 100644 --- a/tests/fail/stacked_borrows/illegal_write1.rs +++ b/tests/fail/stacked_borrows/illegal_write1.rs @@ -2,8 +2,10 @@ fn main() { let target = Box::new(42); // has an implicit raw let xref = &*target; { - let x : *mut u32 = xref as *const _ as *mut _; - unsafe { *x = 42; } // invalidates shared ref, activates raw + let x: *mut u32 = xref as *const _ as *mut _; + unsafe { + *x = 42; + } // invalidates shared ref, activates raw } let _x = *xref; //~ ERROR borrow stack } diff --git a/tests/fail/stacked_borrows/illegal_write2.rs b/tests/fail/stacked_borrows/illegal_write2.rs index 62ea05e1811e7..25a9cc4012ba3 100644 --- a/tests/fail/stacked_borrows/illegal_write2.rs +++ b/tests/fail/stacked_borrows/illegal_write2.rs @@ -3,6 +3,8 @@ fn main() { let target2 = target as *mut _; drop(&mut *target); // reborrow // Now make sure our ref is still the only one. - unsafe { *target2 = 13; } //~ ERROR borrow stack + unsafe { + *target2 = 13; + } //~ ERROR borrow stack let _val = *target; } diff --git a/tests/fail/stacked_borrows/illegal_write3.rs b/tests/fail/stacked_borrows/illegal_write3.rs index 7851eeb02690a..4bbd1e56a747d 100644 --- a/tests/fail/stacked_borrows/illegal_write3.rs +++ b/tests/fail/stacked_borrows/illegal_write3.rs @@ -3,6 +3,8 @@ fn main() { // Make sure raw ptr with raw tag cannot mutate frozen location without breaking the shared ref. let r#ref = ⌖ // freeze let ptr = r#ref as *const _ as *mut _; // raw ptr, with raw tag - unsafe { *ptr = 42; } //~ ERROR only grants SharedReadOnly permission + unsafe { + *ptr = 42; + } //~ ERROR only grants SharedReadOnly permission let _val = *r#ref; } diff --git a/tests/fail/stacked_borrows/illegal_write6.rs b/tests/fail/stacked_borrows/illegal_write6.rs index 6985e7f0ead3b..49ffb9a8604ba 100644 --- a/tests/fail/stacked_borrows/illegal_write6.rs +++ b/tests/fail/stacked_borrows/illegal_write6.rs @@ -7,6 +7,8 @@ fn main() { fn foo(a: &mut u32, y: *mut u32) -> u32 { *a = 1; let _b = &*a; - unsafe { *y = 2; } //~ ERROR: not granting access to tag + unsafe { + *y = 2; + } //~ ERROR: not granting access to tag return *a; } diff --git a/tests/fail/stacked_borrows/raw_tracking.rs b/tests/fail/stacked_borrows/raw_tracking.rs index a8e1d806cbbb2..22898483bf196 100644 --- a/tests/fail/stacked_borrows/raw_tracking.rs +++ b/tests/fail/stacked_borrows/raw_tracking.rs @@ -7,6 +7,10 @@ fn main() { let raw2 = &mut l as *mut _; // invalidates raw1 // Without raw pointer tracking, Stacked Borrows cannot distinguish raw1 and raw2, and thus // fails to realize that raw1 should not be used any more. - unsafe { *raw1 = 13; } //~ ERROR does not exist in the borrow stack - unsafe { *raw2 = 13; } + unsafe { + *raw1 = 13; + } //~ ERROR does not exist in the borrow stack + unsafe { + *raw2 = 13; + } } diff --git a/tests/fail/stacked_borrows/shr_frozen_violation1.rs b/tests/fail/stacked_borrows/shr_frozen_violation1.rs index 1ea96086d3e46..803e8c6eb1013 100644 --- a/tests/fail/stacked_borrows/shr_frozen_violation1.rs +++ b/tests/fail/stacked_borrows/shr_frozen_violation1.rs @@ -1,7 +1,7 @@ fn foo(x: &mut i32) -> i32 { - *x = 5; - unknown_code(&*x); - *x // must return 5 + *x = 5; + unknown_code(&*x); + *x // must return 5 } fn main() { @@ -9,5 +9,7 @@ fn main() { } fn unknown_code(x: &i32) { - unsafe { *(x as *const i32 as *mut i32) = 7; } //~ ERROR only grants SharedReadOnly permission + unsafe { + *(x as *const i32 as *mut i32) = 7; + } //~ ERROR only grants SharedReadOnly permission } diff --git a/tests/fail/stacked_borrows/transmute-is-no-escape.rs b/tests/fail/stacked_borrows/transmute-is-no-escape.rs index e9282c5ba8f27..2a766d2c1b7ca 100644 --- a/tests/fail/stacked_borrows/transmute-is-no-escape.rs +++ b/tests/fail/stacked_borrows/transmute-is-no-escape.rs @@ -10,5 +10,7 @@ fn main() { let _raw: *mut i32 = unsafe { mem::transmute(&mut x[0]) }; // `raw` still carries a tag, so we get another pointer to the same location that does not carry a tag let raw = (&mut x[1] as *mut i32).wrapping_offset(-1); - unsafe { *raw = 13; } //~ ERROR borrow stack + unsafe { + *raw = 13; + } //~ ERROR borrow stack } diff --git a/tests/fail/stacked_borrows/unescaped_local.rs b/tests/fail/stacked_borrows/unescaped_local.rs index b49e6cce63bc3..c807f936d121f 100644 --- a/tests/fail/stacked_borrows/unescaped_local.rs +++ b/tests/fail/stacked_borrows/unescaped_local.rs @@ -4,5 +4,7 @@ fn main() { let mut x = 42; let raw = &mut x as *mut i32 as usize as *mut i32; let _ptr = &mut x; - unsafe { *raw = 13; } //~ ERROR borrow stack + unsafe { + *raw = 13; + } //~ ERROR borrow stack } diff --git a/tests/fail/unaligned_pointers/intptrcast_alignment_check.rs b/tests/fail/unaligned_pointers/intptrcast_alignment_check.rs index 9872a493c02a9..ca892f8320920 100644 --- a/tests/fail/unaligned_pointers/intptrcast_alignment_check.rs +++ b/tests/fail/unaligned_pointers/intptrcast_alignment_check.rs @@ -10,8 +10,10 @@ fn main() { let x = &mut [0u8; 3]; let base_addr = x as *mut _ as usize; // Manually make sure the pointer is properly aligned. - let base_addr_aligned = if base_addr % 2 == 0 { base_addr } else { base_addr+1 }; + let base_addr_aligned = if base_addr % 2 == 0 { base_addr } else { base_addr + 1 }; let u16_ptr = base_addr_aligned as *mut u16; - unsafe { *u16_ptr = 2; } //~ERROR memory with alignment 1, but alignment 2 is required + unsafe { + *u16_ptr = 2; + } //~ERROR memory with alignment 1, but alignment 2 is required println!("{:?}", x); } diff --git a/tests/fail/validity/transmute_through_ptr.rs b/tests/fail/validity/transmute_through_ptr.rs index b1984429d2de8..23da1ba12572a 100644 --- a/tests/fail/validity/transmute_through_ptr.rs +++ b/tests/fail/validity/transmute_through_ptr.rs @@ -1,10 +1,14 @@ #[repr(u32)] #[derive(Debug)] -enum Bool { True } +enum Bool { + True, +} fn evil(x: &mut Bool) { let x = x as *mut _ as *mut u32; - unsafe { *x = 44; } // out-of-bounds enum tag + unsafe { + *x = 44; + } // out-of-bounds enum tag } #[rustfmt::skip] // rustfmt bug: https://github.com/rust-lang/rustfmt/issues/5391 diff --git a/tests/fail/zst2.rs b/tests/fail/zst2.rs index a602cb731e402..cd9cf3618d254 100644 --- a/tests/fail/zst2.rs +++ b/tests/fail/zst2.rs @@ -11,5 +11,7 @@ fn main() { let mut x_box = Box::new(1u8); let x = &mut *x_box as *mut _ as *mut [u8; 0]; drop(x_box); - unsafe { *x = zst_val; } //~ ERROR dereferenced after this allocation got freed + unsafe { + *x = zst_val; + } //~ ERROR dereferenced after this allocation got freed } diff --git a/tests/fail/zst3.rs b/tests/fail/zst3.rs index 7ecb8c7dca9d5..defb5a626ba55 100644 --- a/tests/fail/zst3.rs +++ b/tests/fail/zst3.rs @@ -11,8 +11,12 @@ fn main() { let mut x_box = Box::new(1u8); let x = (&mut *x_box as *mut u8).wrapping_offset(1); // This one is just "at the edge", but still okay - unsafe { *(x as *mut [u8; 0]) = zst_val; } + unsafe { + *(x as *mut [u8; 0]) = zst_val; + } // One byte further is OOB. let x = x.wrapping_offset(1); - unsafe { *(x as *mut [u8; 0]) = zst_val; } //~ ERROR out-of-bounds + unsafe { + *(x as *mut [u8; 0]) = zst_val; + } //~ ERROR out-of-bounds } From 7326da7ce3750087fe13effd595c73caf92f5cdf Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Tue, 21 Jun 2022 11:40:02 -0700 Subject: [PATCH 3286/3747] Manual adjustments --- tests/fail/box-cell-alias.rs | 4 ++-- tests/fail/dangling_pointers/maybe_null_pointer_write_zst.rs | 4 ++-- tests/fail/intrinsics/copy_null.rs | 4 ++-- tests/fail/intrinsics/copy_unaligned.rs | 4 ++-- tests/fail/intrinsics/exact_div1.rs | 4 ++-- tests/fail/intrinsics/exact_div2.rs | 4 ++-- tests/fail/intrinsics/exact_div3.rs | 4 ++-- tests/fail/intrinsics/exact_div4.rs | 4 ++-- tests/fail/intrinsics/float_to_int_32_inf1.rs | 4 ++-- tests/fail/intrinsics/float_to_int_32_infneg1.rs | 4 ++-- tests/fail/intrinsics/float_to_int_32_nan.rs | 4 ++-- tests/fail/intrinsics/float_to_int_32_nanneg.rs | 4 ++-- tests/fail/intrinsics/float_to_int_32_neg.rs | 4 ++-- tests/fail/intrinsics/float_to_int_32_too_big1.rs | 4 ++-- tests/fail/intrinsics/float_to_int_32_too_big2.rs | 4 ++-- tests/fail/intrinsics/float_to_int_32_too_small1.rs | 4 ++-- tests/fail/intrinsics/float_to_int_64_inf1.rs | 4 ++-- tests/fail/intrinsics/float_to_int_64_infneg1.rs | 4 ++-- tests/fail/intrinsics/float_to_int_64_infneg2.rs | 4 ++-- tests/fail/intrinsics/float_to_int_64_nan.rs | 4 ++-- tests/fail/intrinsics/float_to_int_64_neg.rs | 4 ++-- tests/fail/intrinsics/float_to_int_64_too_big1.rs | 4 ++-- tests/fail/intrinsics/float_to_int_64_too_big2.rs | 4 ++-- tests/fail/intrinsics/float_to_int_64_too_big3.rs | 4 ++-- tests/fail/intrinsics/float_to_int_64_too_big4.rs | 4 ++-- tests/fail/intrinsics/float_to_int_64_too_big5.rs | 4 ++-- tests/fail/intrinsics/float_to_int_64_too_big6.rs | 4 ++-- tests/fail/intrinsics/float_to_int_64_too_big7.rs | 4 ++-- tests/fail/intrinsics/float_to_int_64_too_small1.rs | 4 ++-- tests/fail/intrinsics/float_to_int_64_too_small2.rs | 4 ++-- tests/fail/intrinsics/float_to_int_64_too_small3.rs | 4 ++-- tests/fail/intrinsics/unchecked_add1.rs | 4 ++-- tests/fail/intrinsics/unchecked_add2.rs | 4 ++-- tests/fail/intrinsics/unchecked_div1.rs | 4 ++-- tests/fail/intrinsics/unchecked_mul1.rs | 4 ++-- tests/fail/intrinsics/unchecked_mul2.rs | 4 ++-- tests/fail/intrinsics/unchecked_sub1.rs | 4 ++-- tests/fail/intrinsics/unchecked_sub2.rs | 4 ++-- tests/fail/panic/unwind_panic_abort.rs | 4 ++-- tests/fail/stacked_borrows/illegal_write1.rs | 4 ++-- tests/fail/stacked_borrows/illegal_write2.rs | 4 ++-- tests/fail/stacked_borrows/illegal_write3.rs | 4 ++-- tests/fail/stacked_borrows/illegal_write6.rs | 4 ++-- tests/fail/stacked_borrows/raw_tracking.rs | 4 ++-- tests/fail/stacked_borrows/shr_frozen_violation1.rs | 4 ++-- tests/fail/stacked_borrows/transmute-is-no-escape.rs | 4 ++-- tests/fail/stacked_borrows/unescaped_local.rs | 4 ++-- tests/fail/unaligned_pointers/intptrcast_alignment_check.rs | 4 ++-- tests/fail/validity/transmute_through_ptr.rs | 4 ++-- tests/fail/zst2.rs | 4 ++-- tests/fail/zst3.rs | 4 ++-- 51 files changed, 102 insertions(+), 102 deletions(-) diff --git a/tests/fail/box-cell-alias.rs b/tests/fail/box-cell-alias.rs index ffda1033d44bf..c1fec28ae3b7b 100644 --- a/tests/fail/box-cell-alias.rs +++ b/tests/fail/box-cell-alias.rs @@ -7,8 +7,8 @@ use std::cell::Cell; fn helper(val: Box>, ptr: *const Cell) -> u8 { val.set(10); unsafe { - (*ptr).set(20); - } //~ ERROR does not exist in the borrow stack + (*ptr).set(20); //~ ERROR does not exist in the borrow stack + } val.get() } diff --git a/tests/fail/dangling_pointers/maybe_null_pointer_write_zst.rs b/tests/fail/dangling_pointers/maybe_null_pointer_write_zst.rs index 78384502337c7..3115da436be84 100644 --- a/tests/fail/dangling_pointers/maybe_null_pointer_write_zst.rs +++ b/tests/fail/dangling_pointers/maybe_null_pointer_write_zst.rs @@ -8,6 +8,6 @@ fn main() { let zst_val = [1u8; 0]; let ptr = (&0u8 as *const u8).wrapping_sub(0x800) as *mut [u8; 0]; unsafe { - *ptr = zst_val; - } //~ ERROR out-of-bounds + *ptr = zst_val; //~ ERROR out-of-bounds + } } diff --git a/tests/fail/intrinsics/copy_null.rs b/tests/fail/intrinsics/copy_null.rs index 1e572fe4a8559..7ab41232498ea 100644 --- a/tests/fail/intrinsics/copy_null.rs +++ b/tests/fail/intrinsics/copy_null.rs @@ -10,6 +10,6 @@ fn main() { let ptr = &mut data[0] as *mut u16; // Even copying 0 elements from NULL should error. unsafe { - copy_nonoverlapping(std::ptr::null(), ptr, 0); - } //~ ERROR: memory access failed: null pointer is not a valid pointer + copy_nonoverlapping(std::ptr::null(), ptr, 0); //~ ERROR: memory access failed: null pointer is not a valid pointer + } } diff --git a/tests/fail/intrinsics/copy_unaligned.rs b/tests/fail/intrinsics/copy_unaligned.rs index d7097bb91d3a6..162f06bfacd9b 100644 --- a/tests/fail/intrinsics/copy_unaligned.rs +++ b/tests/fail/intrinsics/copy_unaligned.rs @@ -10,6 +10,6 @@ fn main() { let ptr = (&mut data[0] as *mut u16 as *mut u8).wrapping_add(1) as *mut u16; // Even copying 0 elements to something unaligned should error unsafe { - copy_nonoverlapping(&data[5], ptr, 0); - } //~ ERROR accessing memory with alignment 1, but alignment 2 is required + copy_nonoverlapping(&data[5], ptr, 0); //~ ERROR accessing memory with alignment 1, but alignment 2 is required + } } diff --git a/tests/fail/intrinsics/exact_div1.rs b/tests/fail/intrinsics/exact_div1.rs index 5d2185f1ee1b5..d8af789e99a20 100644 --- a/tests/fail/intrinsics/exact_div1.rs +++ b/tests/fail/intrinsics/exact_div1.rs @@ -2,6 +2,6 @@ fn main() { // divison by 0 unsafe { - std::intrinsics::exact_div(2, 0); - } //~ ERROR divisor of zero + std::intrinsics::exact_div(2, 0); //~ ERROR divisor of zero + } } diff --git a/tests/fail/intrinsics/exact_div2.rs b/tests/fail/intrinsics/exact_div2.rs index e0301fbd73e23..80f9131bab799 100644 --- a/tests/fail/intrinsics/exact_div2.rs +++ b/tests/fail/intrinsics/exact_div2.rs @@ -2,6 +2,6 @@ fn main() { // divison with a remainder unsafe { - std::intrinsics::exact_div(2u16, 3); - } //~ ERROR 2_u16 cannot be divided by 3_u16 without remainder + std::intrinsics::exact_div(2u16, 3); //~ ERROR 2_u16 cannot be divided by 3_u16 without remainder + } } diff --git a/tests/fail/intrinsics/exact_div3.rs b/tests/fail/intrinsics/exact_div3.rs index 5f74b2dfa818b..976fca29f9bac 100644 --- a/tests/fail/intrinsics/exact_div3.rs +++ b/tests/fail/intrinsics/exact_div3.rs @@ -2,6 +2,6 @@ fn main() { // signed divison with a remainder unsafe { - std::intrinsics::exact_div(-19i8, 2); - } //~ ERROR -19_i8 cannot be divided by 2_i8 without remainder + std::intrinsics::exact_div(-19i8, 2); //~ ERROR -19_i8 cannot be divided by 2_i8 without remainder + } } diff --git a/tests/fail/intrinsics/exact_div4.rs b/tests/fail/intrinsics/exact_div4.rs index f70746d2a1164..5f4ca587e6d77 100644 --- a/tests/fail/intrinsics/exact_div4.rs +++ b/tests/fail/intrinsics/exact_div4.rs @@ -2,6 +2,6 @@ fn main() { // divison of MIN by -1 unsafe { - std::intrinsics::exact_div(i64::MIN, -1); - } //~ ERROR overflow in signed remainder (dividing MIN by -1) + std::intrinsics::exact_div(i64::MIN, -1); //~ ERROR overflow in signed remainder (dividing MIN by -1) + } } diff --git a/tests/fail/intrinsics/float_to_int_32_inf1.rs b/tests/fail/intrinsics/float_to_int_32_inf1.rs index 32c2e09b53a3e..a57845426d582 100644 --- a/tests/fail/intrinsics/float_to_int_32_inf1.rs +++ b/tests/fail/intrinsics/float_to_int_32_inf1.rs @@ -7,6 +7,6 @@ extern "rust-intrinsic" { fn main() { unsafe { - float_to_int_unchecked::(f32::INFINITY); - } //~ ERROR: cannot be represented in target type `i32` + float_to_int_unchecked::(f32::INFINITY); //~ ERROR: cannot be represented in target type `i32` + } } diff --git a/tests/fail/intrinsics/float_to_int_32_infneg1.rs b/tests/fail/intrinsics/float_to_int_32_infneg1.rs index e1ba2224a088c..d383fc5b50ac1 100644 --- a/tests/fail/intrinsics/float_to_int_32_infneg1.rs +++ b/tests/fail/intrinsics/float_to_int_32_infneg1.rs @@ -7,6 +7,6 @@ extern "rust-intrinsic" { fn main() { unsafe { - float_to_int_unchecked::(f32::NEG_INFINITY); - } //~ ERROR: cannot be represented in target type `i32` + float_to_int_unchecked::(f32::NEG_INFINITY); //~ ERROR: cannot be represented in target type `i32` + } } diff --git a/tests/fail/intrinsics/float_to_int_32_nan.rs b/tests/fail/intrinsics/float_to_int_32_nan.rs index 6c128d94a87f8..a39a5066b6f8b 100644 --- a/tests/fail/intrinsics/float_to_int_32_nan.rs +++ b/tests/fail/intrinsics/float_to_int_32_nan.rs @@ -7,6 +7,6 @@ extern "rust-intrinsic" { fn main() { unsafe { - float_to_int_unchecked::(f32::NAN); - } //~ ERROR: cannot be represented in target type `u32` + float_to_int_unchecked::(f32::NAN); //~ ERROR: cannot be represented in target type `u32` + } } diff --git a/tests/fail/intrinsics/float_to_int_32_nanneg.rs b/tests/fail/intrinsics/float_to_int_32_nanneg.rs index 9bc628e9db924..71436eb3ba846 100644 --- a/tests/fail/intrinsics/float_to_int_32_nanneg.rs +++ b/tests/fail/intrinsics/float_to_int_32_nanneg.rs @@ -7,6 +7,6 @@ extern "rust-intrinsic" { fn main() { unsafe { - float_to_int_unchecked::(-f32::NAN); - } //~ ERROR: cannot be represented in target type `u32` + float_to_int_unchecked::(-f32::NAN); //~ ERROR: cannot be represented in target type `u32` + } } diff --git a/tests/fail/intrinsics/float_to_int_32_neg.rs b/tests/fail/intrinsics/float_to_int_32_neg.rs index 188a9256db7ed..98ba964e47c2a 100644 --- a/tests/fail/intrinsics/float_to_int_32_neg.rs +++ b/tests/fail/intrinsics/float_to_int_32_neg.rs @@ -7,6 +7,6 @@ extern "rust-intrinsic" { fn main() { unsafe { - float_to_int_unchecked::(-1.000000001f32); - } //~ ERROR: cannot be represented in target type `u32` + float_to_int_unchecked::(-1.000000001f32); //~ ERROR: cannot be represented in target type `u32` + } } diff --git a/tests/fail/intrinsics/float_to_int_32_too_big1.rs b/tests/fail/intrinsics/float_to_int_32_too_big1.rs index 787941e63e2ba..424b8fd965e9c 100644 --- a/tests/fail/intrinsics/float_to_int_32_too_big1.rs +++ b/tests/fail/intrinsics/float_to_int_32_too_big1.rs @@ -7,6 +7,6 @@ extern "rust-intrinsic" { fn main() { unsafe { - float_to_int_unchecked::(2147483648.0f32); - } //~ ERROR: cannot be represented in target type `i32` + float_to_int_unchecked::(2147483648.0f32); //~ ERROR: cannot be represented in target type `i32` + } } diff --git a/tests/fail/intrinsics/float_to_int_32_too_big2.rs b/tests/fail/intrinsics/float_to_int_32_too_big2.rs index 39b74cb048691..5c50926c4df3e 100644 --- a/tests/fail/intrinsics/float_to_int_32_too_big2.rs +++ b/tests/fail/intrinsics/float_to_int_32_too_big2.rs @@ -7,6 +7,6 @@ extern "rust-intrinsic" { fn main() { unsafe { - float_to_int_unchecked::((u32::MAX - 127) as f32); - } //~ ERROR: cannot be represented in target type `u32` + float_to_int_unchecked::((u32::MAX - 127) as f32); //~ ERROR: cannot be represented in target type `u32` + } } diff --git a/tests/fail/intrinsics/float_to_int_32_too_small1.rs b/tests/fail/intrinsics/float_to_int_32_too_small1.rs index a96738214bd01..e0abd19d03fc9 100644 --- a/tests/fail/intrinsics/float_to_int_32_too_small1.rs +++ b/tests/fail/intrinsics/float_to_int_32_too_small1.rs @@ -7,6 +7,6 @@ extern "rust-intrinsic" { fn main() { unsafe { - float_to_int_unchecked::(-2147483904.0f32); - } //~ ERROR: cannot be represented in target type `i32` + float_to_int_unchecked::(-2147483904.0f32); //~ ERROR: cannot be represented in target type `i32` + } } diff --git a/tests/fail/intrinsics/float_to_int_64_inf1.rs b/tests/fail/intrinsics/float_to_int_64_inf1.rs index 259ec883f6caa..f5f842e58ece4 100644 --- a/tests/fail/intrinsics/float_to_int_64_inf1.rs +++ b/tests/fail/intrinsics/float_to_int_64_inf1.rs @@ -7,6 +7,6 @@ extern "rust-intrinsic" { fn main() { unsafe { - float_to_int_unchecked::(f64::INFINITY); - } //~ ERROR: cannot be represented in target type `u128` + float_to_int_unchecked::(f64::INFINITY); //~ ERROR: cannot be represented in target type `u128` + } } diff --git a/tests/fail/intrinsics/float_to_int_64_infneg1.rs b/tests/fail/intrinsics/float_to_int_64_infneg1.rs index 3bc5ac710e974..244c25b31cbfc 100644 --- a/tests/fail/intrinsics/float_to_int_64_infneg1.rs +++ b/tests/fail/intrinsics/float_to_int_64_infneg1.rs @@ -7,6 +7,6 @@ extern "rust-intrinsic" { fn main() { unsafe { - float_to_int_unchecked::(f64::NEG_INFINITY); - } //~ ERROR: cannot be represented in target type `u128` + float_to_int_unchecked::(f64::NEG_INFINITY); //~ ERROR: cannot be represented in target type `u128` + } } diff --git a/tests/fail/intrinsics/float_to_int_64_infneg2.rs b/tests/fail/intrinsics/float_to_int_64_infneg2.rs index 81a79c4d2116a..f7a663d12a56c 100644 --- a/tests/fail/intrinsics/float_to_int_64_infneg2.rs +++ b/tests/fail/intrinsics/float_to_int_64_infneg2.rs @@ -7,6 +7,6 @@ extern "rust-intrinsic" { fn main() { unsafe { - float_to_int_unchecked::(f64::NEG_INFINITY); - } //~ ERROR: cannot be represented in target type `i128` + float_to_int_unchecked::(f64::NEG_INFINITY); //~ ERROR: cannot be represented in target type `i128` + } } diff --git a/tests/fail/intrinsics/float_to_int_64_nan.rs b/tests/fail/intrinsics/float_to_int_64_nan.rs index 47580ad5b2a00..171cbcc59344f 100644 --- a/tests/fail/intrinsics/float_to_int_64_nan.rs +++ b/tests/fail/intrinsics/float_to_int_64_nan.rs @@ -7,6 +7,6 @@ extern "rust-intrinsic" { fn main() { unsafe { - float_to_int_unchecked::(f64::NAN); - } //~ ERROR: cannot be represented in target type `u32` + float_to_int_unchecked::(f64::NAN); //~ ERROR: cannot be represented in target type `u32` + } } diff --git a/tests/fail/intrinsics/float_to_int_64_neg.rs b/tests/fail/intrinsics/float_to_int_64_neg.rs index 0e97c2f26bb3a..40b67e173b97a 100644 --- a/tests/fail/intrinsics/float_to_int_64_neg.rs +++ b/tests/fail/intrinsics/float_to_int_64_neg.rs @@ -7,6 +7,6 @@ extern "rust-intrinsic" { fn main() { unsafe { - float_to_int_unchecked::(-1.0000000000001f64); - } //~ ERROR: cannot be represented in target type `u128` + float_to_int_unchecked::(-1.0000000000001f64); //~ ERROR: cannot be represented in target type `u128` + } } diff --git a/tests/fail/intrinsics/float_to_int_64_too_big1.rs b/tests/fail/intrinsics/float_to_int_64_too_big1.rs index fb75a793ded42..e785123c4ca91 100644 --- a/tests/fail/intrinsics/float_to_int_64_too_big1.rs +++ b/tests/fail/intrinsics/float_to_int_64_too_big1.rs @@ -7,6 +7,6 @@ extern "rust-intrinsic" { fn main() { unsafe { - float_to_int_unchecked::(2147483648.0f64); - } //~ ERROR: cannot be represented in target type `i32` + float_to_int_unchecked::(2147483648.0f64); //~ ERROR: cannot be represented in target type `i32` + } } diff --git a/tests/fail/intrinsics/float_to_int_64_too_big2.rs b/tests/fail/intrinsics/float_to_int_64_too_big2.rs index 0c039ff8493e0..4bf31d8ac0271 100644 --- a/tests/fail/intrinsics/float_to_int_64_too_big2.rs +++ b/tests/fail/intrinsics/float_to_int_64_too_big2.rs @@ -7,6 +7,6 @@ extern "rust-intrinsic" { fn main() { unsafe { - float_to_int_unchecked::(9223372036854775808.0f64); - } //~ ERROR: cannot be represented in target type `i64` + float_to_int_unchecked::(9223372036854775808.0f64); //~ ERROR: cannot be represented in target type `i64` + } } diff --git a/tests/fail/intrinsics/float_to_int_64_too_big3.rs b/tests/fail/intrinsics/float_to_int_64_too_big3.rs index b9d2775f0325d..9775a56724bc2 100644 --- a/tests/fail/intrinsics/float_to_int_64_too_big3.rs +++ b/tests/fail/intrinsics/float_to_int_64_too_big3.rs @@ -7,6 +7,6 @@ extern "rust-intrinsic" { fn main() { unsafe { - float_to_int_unchecked::(18446744073709551616.0f64); - } //~ ERROR: cannot be represented in target type `u64` + float_to_int_unchecked::(18446744073709551616.0f64); //~ ERROR: cannot be represented in target type `u64` + } } diff --git a/tests/fail/intrinsics/float_to_int_64_too_big4.rs b/tests/fail/intrinsics/float_to_int_64_too_big4.rs index 4a2dc7822f78c..53ff06e1e4678 100644 --- a/tests/fail/intrinsics/float_to_int_64_too_big4.rs +++ b/tests/fail/intrinsics/float_to_int_64_too_big4.rs @@ -7,6 +7,6 @@ extern "rust-intrinsic" { fn main() { unsafe { - float_to_int_unchecked::(u128::MAX as f64); - } //~ ERROR: cannot be represented in target type `u128` + float_to_int_unchecked::(u128::MAX as f64); //~ ERROR: cannot be represented in target type `u128` + } } diff --git a/tests/fail/intrinsics/float_to_int_64_too_big5.rs b/tests/fail/intrinsics/float_to_int_64_too_big5.rs index bf1f797a0003e..44356ff1771b1 100644 --- a/tests/fail/intrinsics/float_to_int_64_too_big5.rs +++ b/tests/fail/intrinsics/float_to_int_64_too_big5.rs @@ -7,6 +7,6 @@ extern "rust-intrinsic" { fn main() { unsafe { - float_to_int_unchecked::(240282366920938463463374607431768211455.0f64); - } //~ ERROR: cannot be represented in target type `i128` + float_to_int_unchecked::(240282366920938463463374607431768211455.0f64); //~ ERROR: cannot be represented in target type `i128` + } } diff --git a/tests/fail/intrinsics/float_to_int_64_too_big6.rs b/tests/fail/intrinsics/float_to_int_64_too_big6.rs index 2b6d6359c9a81..66f5be96bfd0e 100644 --- a/tests/fail/intrinsics/float_to_int_64_too_big6.rs +++ b/tests/fail/intrinsics/float_to_int_64_too_big6.rs @@ -7,6 +7,6 @@ extern "rust-intrinsic" { fn main() { unsafe { - float_to_int_unchecked::(f64::MAX); - } //~ ERROR: cannot be represented in target type `u128` + float_to_int_unchecked::(f64::MAX); //~ ERROR: cannot be represented in target type `u128` + } } diff --git a/tests/fail/intrinsics/float_to_int_64_too_big7.rs b/tests/fail/intrinsics/float_to_int_64_too_big7.rs index e9b1333232c0a..18b380e8575ee 100644 --- a/tests/fail/intrinsics/float_to_int_64_too_big7.rs +++ b/tests/fail/intrinsics/float_to_int_64_too_big7.rs @@ -7,6 +7,6 @@ extern "rust-intrinsic" { fn main() { unsafe { - float_to_int_unchecked::(f64::MIN); - } //~ ERROR: cannot be represented in target type `i128` + float_to_int_unchecked::(f64::MIN); //~ ERROR: cannot be represented in target type `i128` + } } diff --git a/tests/fail/intrinsics/float_to_int_64_too_small1.rs b/tests/fail/intrinsics/float_to_int_64_too_small1.rs index 652edf1931b3e..2a23b1dc8a4b8 100644 --- a/tests/fail/intrinsics/float_to_int_64_too_small1.rs +++ b/tests/fail/intrinsics/float_to_int_64_too_small1.rs @@ -7,6 +7,6 @@ extern "rust-intrinsic" { fn main() { unsafe { - float_to_int_unchecked::(-2147483649.0f64); - } //~ ERROR: cannot be represented in target type `i32` + float_to_int_unchecked::(-2147483649.0f64); //~ ERROR: cannot be represented in target type `i32` + } } diff --git a/tests/fail/intrinsics/float_to_int_64_too_small2.rs b/tests/fail/intrinsics/float_to_int_64_too_small2.rs index d3d5559291b3a..7fc3effda5dff 100644 --- a/tests/fail/intrinsics/float_to_int_64_too_small2.rs +++ b/tests/fail/intrinsics/float_to_int_64_too_small2.rs @@ -7,6 +7,6 @@ extern "rust-intrinsic" { fn main() { unsafe { - float_to_int_unchecked::(-9223372036854777856.0f64); - } //~ ERROR: cannot be represented in target type `i64` + float_to_int_unchecked::(-9223372036854777856.0f64); //~ ERROR: cannot be represented in target type `i64` + } } diff --git a/tests/fail/intrinsics/float_to_int_64_too_small3.rs b/tests/fail/intrinsics/float_to_int_64_too_small3.rs index 0e22951a45cdb..2a8f9c366425d 100644 --- a/tests/fail/intrinsics/float_to_int_64_too_small3.rs +++ b/tests/fail/intrinsics/float_to_int_64_too_small3.rs @@ -7,6 +7,6 @@ extern "rust-intrinsic" { fn main() { unsafe { - float_to_int_unchecked::(-240282366920938463463374607431768211455.0f64); - } //~ ERROR: cannot be represented in target type `i128` + float_to_int_unchecked::(-240282366920938463463374607431768211455.0f64); //~ ERROR: cannot be represented in target type `i128` + } } diff --git a/tests/fail/intrinsics/unchecked_add1.rs b/tests/fail/intrinsics/unchecked_add1.rs index 90d0a3d01236f..5409f66e805ea 100644 --- a/tests/fail/intrinsics/unchecked_add1.rs +++ b/tests/fail/intrinsics/unchecked_add1.rs @@ -2,6 +2,6 @@ fn main() { // MAX overflow unsafe { - std::intrinsics::unchecked_add(40000u16, 30000); - } //~ ERROR overflow executing `unchecked_add` + std::intrinsics::unchecked_add(40000u16, 30000); //~ ERROR overflow executing `unchecked_add` + } } diff --git a/tests/fail/intrinsics/unchecked_add2.rs b/tests/fail/intrinsics/unchecked_add2.rs index 68e9fb4563e7e..5deef7ee5ccd3 100644 --- a/tests/fail/intrinsics/unchecked_add2.rs +++ b/tests/fail/intrinsics/unchecked_add2.rs @@ -2,6 +2,6 @@ fn main() { // MIN overflow unsafe { - std::intrinsics::unchecked_add(-30000i16, -8000); - } //~ ERROR overflow executing `unchecked_add` + std::intrinsics::unchecked_add(-30000i16, -8000); //~ ERROR overflow executing `unchecked_add` + } } diff --git a/tests/fail/intrinsics/unchecked_div1.rs b/tests/fail/intrinsics/unchecked_div1.rs index 23fc1514f1a18..c06a5bdce93e6 100644 --- a/tests/fail/intrinsics/unchecked_div1.rs +++ b/tests/fail/intrinsics/unchecked_div1.rs @@ -2,6 +2,6 @@ fn main() { // MIN/-1 cannot be represented unsafe { - std::intrinsics::unchecked_div(i16::MIN, -1); - } //~ ERROR overflow in signed division (dividing MIN by -1) + std::intrinsics::unchecked_div(i16::MIN, -1); //~ ERROR overflow in signed division (dividing MIN by -1) + } } diff --git a/tests/fail/intrinsics/unchecked_mul1.rs b/tests/fail/intrinsics/unchecked_mul1.rs index f26d4d3d213f8..140bc9e6c75b2 100644 --- a/tests/fail/intrinsics/unchecked_mul1.rs +++ b/tests/fail/intrinsics/unchecked_mul1.rs @@ -2,6 +2,6 @@ fn main() { // MAX overflow unsafe { - std::intrinsics::unchecked_mul(300u16, 250u16); - } //~ ERROR overflow executing `unchecked_mul` + std::intrinsics::unchecked_mul(300u16, 250u16); //~ ERROR overflow executing `unchecked_mul` + } } diff --git a/tests/fail/intrinsics/unchecked_mul2.rs b/tests/fail/intrinsics/unchecked_mul2.rs index f3e20e8c295d9..c4d16084b3f03 100644 --- a/tests/fail/intrinsics/unchecked_mul2.rs +++ b/tests/fail/intrinsics/unchecked_mul2.rs @@ -2,6 +2,6 @@ fn main() { // MIN overflow unsafe { - std::intrinsics::unchecked_mul(1_000_000_000i32, -4); - } //~ ERROR overflow executing `unchecked_mul` + std::intrinsics::unchecked_mul(1_000_000_000i32, -4); //~ ERROR overflow executing `unchecked_mul` + } } diff --git a/tests/fail/intrinsics/unchecked_sub1.rs b/tests/fail/intrinsics/unchecked_sub1.rs index 3ea5e618074cc..cff79f9135f1f 100644 --- a/tests/fail/intrinsics/unchecked_sub1.rs +++ b/tests/fail/intrinsics/unchecked_sub1.rs @@ -2,6 +2,6 @@ fn main() { // MIN overflow unsafe { - std::intrinsics::unchecked_sub(14u32, 22); - } //~ ERROR overflow executing `unchecked_sub` + std::intrinsics::unchecked_sub(14u32, 22); //~ ERROR overflow executing `unchecked_sub` + } } diff --git a/tests/fail/intrinsics/unchecked_sub2.rs b/tests/fail/intrinsics/unchecked_sub2.rs index 0e9892e58a52d..9b741c2663d89 100644 --- a/tests/fail/intrinsics/unchecked_sub2.rs +++ b/tests/fail/intrinsics/unchecked_sub2.rs @@ -2,6 +2,6 @@ fn main() { // MAX overflow unsafe { - std::intrinsics::unchecked_sub(30000i16, -7000); - } //~ ERROR overflow executing `unchecked_sub` + std::intrinsics::unchecked_sub(30000i16, -7000); //~ ERROR overflow executing `unchecked_sub` + } } diff --git a/tests/fail/panic/unwind_panic_abort.rs b/tests/fail/panic/unwind_panic_abort.rs index 7cb0c7b027991..6afcd7ae7ff1f 100644 --- a/tests/fail/panic/unwind_panic_abort.rs +++ b/tests/fail/panic/unwind_panic_abort.rs @@ -8,6 +8,6 @@ extern "Rust" { fn main() { unsafe { - miri_start_panic(&mut 0); - } //~ ERROR unwinding past a stack frame that does not allow unwinding + miri_start_panic(&mut 0); //~ ERROR unwinding past a stack frame that does not allow unwinding + } } diff --git a/tests/fail/stacked_borrows/illegal_write1.rs b/tests/fail/stacked_borrows/illegal_write1.rs index 5bdd4ef1f052a..3b67accbbd2eb 100644 --- a/tests/fail/stacked_borrows/illegal_write1.rs +++ b/tests/fail/stacked_borrows/illegal_write1.rs @@ -4,8 +4,8 @@ fn main() { { let x: *mut u32 = xref as *const _ as *mut _; unsafe { - *x = 42; - } // invalidates shared ref, activates raw + *x = 42; // invalidates shared ref, activates raw + } } let _x = *xref; //~ ERROR borrow stack } diff --git a/tests/fail/stacked_borrows/illegal_write2.rs b/tests/fail/stacked_borrows/illegal_write2.rs index 25a9cc4012ba3..a106b4240c3c0 100644 --- a/tests/fail/stacked_borrows/illegal_write2.rs +++ b/tests/fail/stacked_borrows/illegal_write2.rs @@ -4,7 +4,7 @@ fn main() { drop(&mut *target); // reborrow // Now make sure our ref is still the only one. unsafe { - *target2 = 13; - } //~ ERROR borrow stack + *target2 = 13; //~ ERROR borrow stack + } let _val = *target; } diff --git a/tests/fail/stacked_borrows/illegal_write3.rs b/tests/fail/stacked_borrows/illegal_write3.rs index 4bbd1e56a747d..5bf651b33aa08 100644 --- a/tests/fail/stacked_borrows/illegal_write3.rs +++ b/tests/fail/stacked_borrows/illegal_write3.rs @@ -4,7 +4,7 @@ fn main() { let r#ref = ⌖ // freeze let ptr = r#ref as *const _ as *mut _; // raw ptr, with raw tag unsafe { - *ptr = 42; - } //~ ERROR only grants SharedReadOnly permission + *ptr = 42; //~ ERROR only grants SharedReadOnly permission + } let _val = *r#ref; } diff --git a/tests/fail/stacked_borrows/illegal_write6.rs b/tests/fail/stacked_borrows/illegal_write6.rs index 49ffb9a8604ba..07d57241205f3 100644 --- a/tests/fail/stacked_borrows/illegal_write6.rs +++ b/tests/fail/stacked_borrows/illegal_write6.rs @@ -8,7 +8,7 @@ fn foo(a: &mut u32, y: *mut u32) -> u32 { *a = 1; let _b = &*a; unsafe { - *y = 2; - } //~ ERROR: not granting access to tag + *y = 2; //~ ERROR: not granting access to tag + } return *a; } diff --git a/tests/fail/stacked_borrows/raw_tracking.rs b/tests/fail/stacked_borrows/raw_tracking.rs index 22898483bf196..0a99e4ce47e7f 100644 --- a/tests/fail/stacked_borrows/raw_tracking.rs +++ b/tests/fail/stacked_borrows/raw_tracking.rs @@ -8,8 +8,8 @@ fn main() { // Without raw pointer tracking, Stacked Borrows cannot distinguish raw1 and raw2, and thus // fails to realize that raw1 should not be used any more. unsafe { - *raw1 = 13; - } //~ ERROR does not exist in the borrow stack + *raw1 = 13; //~ ERROR does not exist in the borrow stack + } unsafe { *raw2 = 13; } diff --git a/tests/fail/stacked_borrows/shr_frozen_violation1.rs b/tests/fail/stacked_borrows/shr_frozen_violation1.rs index 803e8c6eb1013..a6dd9ef4c2eef 100644 --- a/tests/fail/stacked_borrows/shr_frozen_violation1.rs +++ b/tests/fail/stacked_borrows/shr_frozen_violation1.rs @@ -10,6 +10,6 @@ fn main() { fn unknown_code(x: &i32) { unsafe { - *(x as *const i32 as *mut i32) = 7; - } //~ ERROR only grants SharedReadOnly permission + *(x as *const i32 as *mut i32) = 7; //~ ERROR only grants SharedReadOnly permission + } } diff --git a/tests/fail/stacked_borrows/transmute-is-no-escape.rs b/tests/fail/stacked_borrows/transmute-is-no-escape.rs index 2a766d2c1b7ca..e23c893d6aaa3 100644 --- a/tests/fail/stacked_borrows/transmute-is-no-escape.rs +++ b/tests/fail/stacked_borrows/transmute-is-no-escape.rs @@ -11,6 +11,6 @@ fn main() { // `raw` still carries a tag, so we get another pointer to the same location that does not carry a tag let raw = (&mut x[1] as *mut i32).wrapping_offset(-1); unsafe { - *raw = 13; - } //~ ERROR borrow stack + *raw = 13; //~ ERROR borrow stack + } } diff --git a/tests/fail/stacked_borrows/unescaped_local.rs b/tests/fail/stacked_borrows/unescaped_local.rs index c807f936d121f..bfc937bb12b7f 100644 --- a/tests/fail/stacked_borrows/unescaped_local.rs +++ b/tests/fail/stacked_borrows/unescaped_local.rs @@ -5,6 +5,6 @@ fn main() { let raw = &mut x as *mut i32 as usize as *mut i32; let _ptr = &mut x; unsafe { - *raw = 13; - } //~ ERROR borrow stack + *raw = 13; //~ ERROR borrow stack + } } diff --git a/tests/fail/unaligned_pointers/intptrcast_alignment_check.rs b/tests/fail/unaligned_pointers/intptrcast_alignment_check.rs index ca892f8320920..e96f08fc9a7a9 100644 --- a/tests/fail/unaligned_pointers/intptrcast_alignment_check.rs +++ b/tests/fail/unaligned_pointers/intptrcast_alignment_check.rs @@ -13,7 +13,7 @@ fn main() { let base_addr_aligned = if base_addr % 2 == 0 { base_addr } else { base_addr + 1 }; let u16_ptr = base_addr_aligned as *mut u16; unsafe { - *u16_ptr = 2; - } //~ERROR memory with alignment 1, but alignment 2 is required + *u16_ptr = 2; //~ERROR memory with alignment 1, but alignment 2 is required + } println!("{:?}", x); } diff --git a/tests/fail/validity/transmute_through_ptr.rs b/tests/fail/validity/transmute_through_ptr.rs index 23da1ba12572a..4af3b8aef6aaa 100644 --- a/tests/fail/validity/transmute_through_ptr.rs +++ b/tests/fail/validity/transmute_through_ptr.rs @@ -7,8 +7,8 @@ enum Bool { fn evil(x: &mut Bool) { let x = x as *mut _ as *mut u32; unsafe { - *x = 44; - } // out-of-bounds enum tag + *x = 44; // out-of-bounds enum tag + } } #[rustfmt::skip] // rustfmt bug: https://github.com/rust-lang/rustfmt/issues/5391 diff --git a/tests/fail/zst2.rs b/tests/fail/zst2.rs index cd9cf3618d254..2499f79142dbe 100644 --- a/tests/fail/zst2.rs +++ b/tests/fail/zst2.rs @@ -12,6 +12,6 @@ fn main() { let x = &mut *x_box as *mut _ as *mut [u8; 0]; drop(x_box); unsafe { - *x = zst_val; - } //~ ERROR dereferenced after this allocation got freed + *x = zst_val; //~ ERROR dereferenced after this allocation got freed + } } diff --git a/tests/fail/zst3.rs b/tests/fail/zst3.rs index defb5a626ba55..741374c7ad988 100644 --- a/tests/fail/zst3.rs +++ b/tests/fail/zst3.rs @@ -17,6 +17,6 @@ fn main() { // One byte further is OOB. let x = x.wrapping_offset(1); unsafe { - *(x as *mut [u8; 0]) = zst_val; - } //~ ERROR out-of-bounds + *(x as *mut [u8; 0]) = zst_val; //~ ERROR out-of-bounds + } } From f1044d2f774b3525ab28372ccd2be30911f2eb29 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Tue, 21 Jun 2022 11:42:19 -0700 Subject: [PATCH 3287/3747] Bless stderr files after rustfmt --- tests/fail/box-cell-alias.stderr | 10 +++++----- .../maybe_null_pointer_write_zst.stderr | 4 ++-- tests/fail/intrinsics/copy_null.stderr | 4 ++-- tests/fail/intrinsics/copy_unaligned.stderr | 4 ++-- tests/fail/intrinsics/exact_div1.stderr | 4 ++-- tests/fail/intrinsics/exact_div2.stderr | 4 ++-- tests/fail/intrinsics/exact_div3.stderr | 4 ++-- tests/fail/intrinsics/exact_div4.stderr | 4 ++-- .../intrinsics/float_to_int_32_inf1.stderr | 4 ++-- .../intrinsics/float_to_int_32_infneg1.stderr | 4 ++-- .../fail/intrinsics/float_to_int_32_nan.stderr | 4 ++-- .../intrinsics/float_to_int_32_nanneg.stderr | 4 ++-- .../fail/intrinsics/float_to_int_32_neg.stderr | 4 ++-- .../intrinsics/float_to_int_32_too_big1.stderr | 4 ++-- .../intrinsics/float_to_int_32_too_big2.stderr | 4 ++-- .../float_to_int_32_too_small1.stderr | 4 ++-- .../intrinsics/float_to_int_64_inf1.stderr | 4 ++-- .../intrinsics/float_to_int_64_infneg1.stderr | 4 ++-- .../intrinsics/float_to_int_64_infneg2.stderr | 4 ++-- .../fail/intrinsics/float_to_int_64_nan.stderr | 4 ++-- .../fail/intrinsics/float_to_int_64_neg.stderr | 4 ++-- .../intrinsics/float_to_int_64_too_big1.stderr | 4 ++-- .../intrinsics/float_to_int_64_too_big2.stderr | 4 ++-- .../intrinsics/float_to_int_64_too_big3.stderr | 4 ++-- .../intrinsics/float_to_int_64_too_big4.stderr | 4 ++-- .../intrinsics/float_to_int_64_too_big5.stderr | 4 ++-- .../intrinsics/float_to_int_64_too_big6.stderr | 4 ++-- .../intrinsics/float_to_int_64_too_big7.stderr | 4 ++-- .../float_to_int_64_too_small1.stderr | 4 ++-- .../float_to_int_64_too_small2.stderr | 4 ++-- .../float_to_int_64_too_small3.stderr | 4 ++-- tests/fail/intrinsics/unchecked_add1.stderr | 4 ++-- tests/fail/intrinsics/unchecked_add2.stderr | 4 ++-- tests/fail/intrinsics/unchecked_div1.stderr | 4 ++-- tests/fail/intrinsics/unchecked_mul1.stderr | 4 ++-- tests/fail/intrinsics/unchecked_mul2.stderr | 4 ++-- tests/fail/intrinsics/unchecked_sub1.stderr | 4 ++-- tests/fail/intrinsics/unchecked_sub2.stderr | 4 ++-- tests/fail/panic/unwind_panic_abort.stderr | 4 ++-- .../fail/stacked_borrows/illegal_write1.stderr | 4 ++-- .../fail/stacked_borrows/illegal_write2.stderr | 10 +++++----- .../fail/stacked_borrows/illegal_write3.stderr | 10 +++++----- .../fail/stacked_borrows/illegal_write6.stderr | 7 ++++--- tests/fail/stacked_borrows/raw_tracking.stderr | 10 +++++----- .../shr_frozen_violation1.stderr | 18 +++++++++--------- .../transmute-is-no-escape.stderr | 10 +++++----- .../stacked_borrows/unescaped_local.stderr | 10 +++++----- .../intptrcast_alignment_check.stderr | 4 ++-- tests/fail/zst2.stderr | 4 ++-- tests/fail/zst3.stderr | 4 ++-- 50 files changed, 127 insertions(+), 126 deletions(-) diff --git a/tests/fail/box-cell-alias.stderr b/tests/fail/box-cell-alias.stderr index 44813be9780c0..e5a3ad3d33af0 100644 --- a/tests/fail/box-cell-alias.stderr +++ b/tests/fail/box-cell-alias.stderr @@ -1,11 +1,11 @@ error: Undefined Behavior: trying to reborrow for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location --> $DIR/box-cell-alias.rs:LL:CC | -LL | unsafe { (*ptr).set(20); } - | ^^^^^^^^^^^^^^ - | | - | trying to reborrow for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location - | this error occurs as part of a reborrow at ALLOC[0x0..0x1] +LL | (*ptr).set(20); + | ^^^^^^^^^^^^^^ + | | + | trying to reborrow for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | this error occurs as part of a reborrow at ALLOC[0x0..0x1] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information diff --git a/tests/fail/dangling_pointers/maybe_null_pointer_write_zst.stderr b/tests/fail/dangling_pointers/maybe_null_pointer_write_zst.stderr index dc810424abc6c..79fd2ba086853 100644 --- a/tests/fail/dangling_pointers/maybe_null_pointer_write_zst.stderr +++ b/tests/fail/dangling_pointers/maybe_null_pointer_write_zst.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: dereferencing pointer failed: ALLOC has size 1, so pointer at offset -2048 is out-of-bounds --> $DIR/maybe_null_pointer_write_zst.rs:LL:CC | -LL | unsafe { *ptr = zst_val; } - | ^^^^^^^^^^^^^^ dereferencing pointer failed: ALLOC has size 1, so pointer at offset -2048 is out-of-bounds +LL | *ptr = zst_val; + | ^^^^^^^^^^^^^^ dereferencing pointer failed: ALLOC has size 1, so pointer at offset -2048 is out-of-bounds | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/intrinsics/copy_null.stderr b/tests/fail/intrinsics/copy_null.stderr index 461f529fa85d5..bb5a8742e9091 100644 --- a/tests/fail/intrinsics/copy_null.stderr +++ b/tests/fail/intrinsics/copy_null.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: memory access failed: null pointer is not a valid pointer --> $DIR/copy_null.rs:LL:CC | -LL | unsafe { copy_nonoverlapping(std::ptr::null(), ptr, 0); } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: null pointer is not a valid pointer +LL | copy_nonoverlapping(std::ptr::null(), ptr, 0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: null pointer is not a valid pointer | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/intrinsics/copy_unaligned.stderr b/tests/fail/intrinsics/copy_unaligned.stderr index b99588698d22d..b244eaeb41916 100644 --- a/tests/fail/intrinsics/copy_unaligned.stderr +++ b/tests/fail/intrinsics/copy_unaligned.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: accessing memory with alignment ALIGN, but alignment ALIGN is required --> $DIR/copy_unaligned.rs:LL:CC | -LL | unsafe { copy_nonoverlapping(&data[5], ptr, 0); } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ accessing memory with alignment ALIGN, but alignment ALIGN is required +LL | copy_nonoverlapping(&data[5], ptr, 0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ accessing memory with alignment ALIGN, but alignment ALIGN is required | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/intrinsics/exact_div1.stderr b/tests/fail/intrinsics/exact_div1.stderr index a0f03b201a8de..66f8168fade72 100644 --- a/tests/fail/intrinsics/exact_div1.stderr +++ b/tests/fail/intrinsics/exact_div1.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: calculating the remainder with a divisor of zero --> $DIR/exact_div1.rs:LL:CC | -LL | unsafe { std::intrinsics::exact_div(2, 0); } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ calculating the remainder with a divisor of zero +LL | std::intrinsics::exact_div(2, 0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ calculating the remainder with a divisor of zero | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/intrinsics/exact_div2.stderr b/tests/fail/intrinsics/exact_div2.stderr index 78a85c9caac6b..2c102dd0b55cd 100644 --- a/tests/fail/intrinsics/exact_div2.stderr +++ b/tests/fail/intrinsics/exact_div2.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: exact_div: 2_u16 cannot be divided by 3_u16 without remainder --> $DIR/exact_div2.rs:LL:CC | -LL | unsafe { std::intrinsics::exact_div(2u16, 3); } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ exact_div: 2_u16 cannot be divided by 3_u16 without remainder +LL | std::intrinsics::exact_div(2u16, 3); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ exact_div: 2_u16 cannot be divided by 3_u16 without remainder | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/intrinsics/exact_div3.stderr b/tests/fail/intrinsics/exact_div3.stderr index 3062b60d468e9..61eacdc65ff3e 100644 --- a/tests/fail/intrinsics/exact_div3.stderr +++ b/tests/fail/intrinsics/exact_div3.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: exact_div: -19_i8 cannot be divided by 2_i8 without remainder --> $DIR/exact_div3.rs:LL:CC | -LL | unsafe { std::intrinsics::exact_div(-19i8, 2); } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ exact_div: -19_i8 cannot be divided by 2_i8 without remainder +LL | std::intrinsics::exact_div(-19i8, 2); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ exact_div: -19_i8 cannot be divided by 2_i8 without remainder | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/intrinsics/exact_div4.stderr b/tests/fail/intrinsics/exact_div4.stderr index 1ae67ad87a5da..a3f5aafbe2d6b 100644 --- a/tests/fail/intrinsics/exact_div4.stderr +++ b/tests/fail/intrinsics/exact_div4.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: overflow in signed remainder (dividing MIN by -1) --> $DIR/exact_div4.rs:LL:CC | -LL | unsafe { std::intrinsics::exact_div(i64::MIN, -1); } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflow in signed remainder (dividing MIN by -1) +LL | std::intrinsics::exact_div(i64::MIN, -1); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflow in signed remainder (dividing MIN by -1) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/intrinsics/float_to_int_32_inf1.stderr b/tests/fail/intrinsics/float_to_int_32_inf1.stderr index cdf232d93eb21..b12fd13b5f4da 100644 --- a/tests/fail/intrinsics/float_to_int_32_inf1.stderr +++ b/tests/fail/intrinsics/float_to_int_32_inf1.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on +Inf which cannot be represented in target type `i32` --> $DIR/float_to_int_32_inf1.rs:LL:CC | -LL | unsafe { float_to_int_unchecked::(f32::INFINITY); } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on +Inf which cannot be represented in target type `i32` +LL | float_to_int_unchecked::(f32::INFINITY); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on +Inf which cannot be represented in target type `i32` | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/intrinsics/float_to_int_32_infneg1.stderr b/tests/fail/intrinsics/float_to_int_32_infneg1.stderr index ae7301193682b..d9223462bfa59 100644 --- a/tests/fail/intrinsics/float_to_int_32_infneg1.stderr +++ b/tests/fail/intrinsics/float_to_int_32_infneg1.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on -Inf which cannot be represented in target type `i32` --> $DIR/float_to_int_32_infneg1.rs:LL:CC | -LL | unsafe { float_to_int_unchecked::(f32::NEG_INFINITY); } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on -Inf which cannot be represented in target type `i32` +LL | float_to_int_unchecked::(f32::NEG_INFINITY); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on -Inf which cannot be represented in target type `i32` | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/intrinsics/float_to_int_32_nan.stderr b/tests/fail/intrinsics/float_to_int_32_nan.stderr index 9c20abef78df9..cb8764174abdc 100644 --- a/tests/fail/intrinsics/float_to_int_32_nan.stderr +++ b/tests/fail/intrinsics/float_to_int_32_nan.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on NaN which cannot be represented in target type `u32` --> $DIR/float_to_int_32_nan.rs:LL:CC | -LL | unsafe { float_to_int_unchecked::(f32::NAN); } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on NaN which cannot be represented in target type `u32` +LL | float_to_int_unchecked::(f32::NAN); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on NaN which cannot be represented in target type `u32` | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/intrinsics/float_to_int_32_nanneg.stderr b/tests/fail/intrinsics/float_to_int_32_nanneg.stderr index f5675fd654dda..49e19bf963565 100644 --- a/tests/fail/intrinsics/float_to_int_32_nanneg.stderr +++ b/tests/fail/intrinsics/float_to_int_32_nanneg.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on NaN which cannot be represented in target type `u32` --> $DIR/float_to_int_32_nanneg.rs:LL:CC | -LL | unsafe { float_to_int_unchecked::(-f32::NAN); } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on NaN which cannot be represented in target type `u32` +LL | float_to_int_unchecked::(-f32::NAN); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on NaN which cannot be represented in target type `u32` | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/intrinsics/float_to_int_32_neg.stderr b/tests/fail/intrinsics/float_to_int_32_neg.stderr index 3b7c755af6544..5d847166a0718 100644 --- a/tests/fail/intrinsics/float_to_int_32_neg.stderr +++ b/tests/fail/intrinsics/float_to_int_32_neg.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on -1 which cannot be represented in target type `u32` --> $DIR/float_to_int_32_neg.rs:LL:CC | -LL | unsafe { float_to_int_unchecked::(-1.000000001f32); } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on -1 which cannot be represented in target type `u32` +LL | float_to_int_unchecked::(-1.000000001f32); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on -1 which cannot be represented in target type `u32` | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/intrinsics/float_to_int_32_too_big1.stderr b/tests/fail/intrinsics/float_to_int_32_too_big1.stderr index abfda9eef0af4..be6ad1f381d4d 100644 --- a/tests/fail/intrinsics/float_to_int_32_too_big1.stderr +++ b/tests/fail/intrinsics/float_to_int_32_too_big1.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on 2.14748365E+9 which cannot be represented in target type `i32` --> $DIR/float_to_int_32_too_big1.rs:LL:CC | -LL | unsafe { float_to_int_unchecked::(2147483648.0f32); } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on 2.14748365E+9 which cannot be represented in target type `i32` +LL | float_to_int_unchecked::(2147483648.0f32); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on 2.14748365E+9 which cannot be represented in target type `i32` | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/intrinsics/float_to_int_32_too_big2.stderr b/tests/fail/intrinsics/float_to_int_32_too_big2.stderr index 2680d0c9908c9..d7fbe5a34b52b 100644 --- a/tests/fail/intrinsics/float_to_int_32_too_big2.stderr +++ b/tests/fail/intrinsics/float_to_int_32_too_big2.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on 4.2949673E+9 which cannot be represented in target type `u32` --> $DIR/float_to_int_32_too_big2.rs:LL:CC | -LL | unsafe { float_to_int_unchecked::((u32::MAX-127) as f32); } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on 4.2949673E+9 which cannot be represented in target type `u32` +LL | float_to_int_unchecked::((u32::MAX - 127) as f32); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on 4.2949673E+9 which cannot be represented in target type `u32` | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/intrinsics/float_to_int_32_too_small1.stderr b/tests/fail/intrinsics/float_to_int_32_too_small1.stderr index b03bd380df47c..2c225b85ec90c 100644 --- a/tests/fail/intrinsics/float_to_int_32_too_small1.stderr +++ b/tests/fail/intrinsics/float_to_int_32_too_small1.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on -2.1474839E+9 which cannot be represented in target type `i32` --> $DIR/float_to_int_32_too_small1.rs:LL:CC | -LL | unsafe { float_to_int_unchecked::(-2147483904.0f32); } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on -2.1474839E+9 which cannot be represented in target type `i32` +LL | float_to_int_unchecked::(-2147483904.0f32); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on -2.1474839E+9 which cannot be represented in target type `i32` | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/intrinsics/float_to_int_64_inf1.stderr b/tests/fail/intrinsics/float_to_int_64_inf1.stderr index 7509844cfd41b..7bb1f08afa874 100644 --- a/tests/fail/intrinsics/float_to_int_64_inf1.stderr +++ b/tests/fail/intrinsics/float_to_int_64_inf1.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on +Inf which cannot be represented in target type `u128` --> $DIR/float_to_int_64_inf1.rs:LL:CC | -LL | unsafe { float_to_int_unchecked::(f64::INFINITY); } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on +Inf which cannot be represented in target type `u128` +LL | float_to_int_unchecked::(f64::INFINITY); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on +Inf which cannot be represented in target type `u128` | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/intrinsics/float_to_int_64_infneg1.stderr b/tests/fail/intrinsics/float_to_int_64_infneg1.stderr index 539cd52d83d0e..eb96f6869a143 100644 --- a/tests/fail/intrinsics/float_to_int_64_infneg1.stderr +++ b/tests/fail/intrinsics/float_to_int_64_infneg1.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on -Inf which cannot be represented in target type `u128` --> $DIR/float_to_int_64_infneg1.rs:LL:CC | -LL | unsafe { float_to_int_unchecked::(f64::NEG_INFINITY); } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on -Inf which cannot be represented in target type `u128` +LL | float_to_int_unchecked::(f64::NEG_INFINITY); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on -Inf which cannot be represented in target type `u128` | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/intrinsics/float_to_int_64_infneg2.stderr b/tests/fail/intrinsics/float_to_int_64_infneg2.stderr index ceb18c3f4121c..a2f847be9071b 100644 --- a/tests/fail/intrinsics/float_to_int_64_infneg2.stderr +++ b/tests/fail/intrinsics/float_to_int_64_infneg2.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on -Inf which cannot be represented in target type `i128` --> $DIR/float_to_int_64_infneg2.rs:LL:CC | -LL | unsafe { float_to_int_unchecked::(f64::NEG_INFINITY); } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on -Inf which cannot be represented in target type `i128` +LL | float_to_int_unchecked::(f64::NEG_INFINITY); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on -Inf which cannot be represented in target type `i128` | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/intrinsics/float_to_int_64_nan.stderr b/tests/fail/intrinsics/float_to_int_64_nan.stderr index eee8d2fac0b31..8da8549758208 100644 --- a/tests/fail/intrinsics/float_to_int_64_nan.stderr +++ b/tests/fail/intrinsics/float_to_int_64_nan.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on NaN which cannot be represented in target type `u32` --> $DIR/float_to_int_64_nan.rs:LL:CC | -LL | unsafe { float_to_int_unchecked::(f64::NAN); } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on NaN which cannot be represented in target type `u32` +LL | float_to_int_unchecked::(f64::NAN); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on NaN which cannot be represented in target type `u32` | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/intrinsics/float_to_int_64_neg.stderr b/tests/fail/intrinsics/float_to_int_64_neg.stderr index 384c0232465a8..35bb0aaa22cb3 100644 --- a/tests/fail/intrinsics/float_to_int_64_neg.stderr +++ b/tests/fail/intrinsics/float_to_int_64_neg.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on -1 which cannot be represented in target type `u128` --> $DIR/float_to_int_64_neg.rs:LL:CC | -LL | unsafe { float_to_int_unchecked::(-1.0000000000001f64); } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on -1 which cannot be represented in target type `u128` +LL | float_to_int_unchecked::(-1.0000000000001f64); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on -1 which cannot be represented in target type `u128` | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/intrinsics/float_to_int_64_too_big1.stderr b/tests/fail/intrinsics/float_to_int_64_too_big1.stderr index bb5b10a2710f8..e031e00709e03 100644 --- a/tests/fail/intrinsics/float_to_int_64_too_big1.stderr +++ b/tests/fail/intrinsics/float_to_int_64_too_big1.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on 2147483648 which cannot be represented in target type `i32` --> $DIR/float_to_int_64_too_big1.rs:LL:CC | -LL | unsafe { float_to_int_unchecked::(2147483648.0f64); } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on 2147483648 which cannot be represented in target type `i32` +LL | float_to_int_unchecked::(2147483648.0f64); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on 2147483648 which cannot be represented in target type `i32` | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/intrinsics/float_to_int_64_too_big2.stderr b/tests/fail/intrinsics/float_to_int_64_too_big2.stderr index a4d57c2f5ceeb..8c4478603fbd5 100644 --- a/tests/fail/intrinsics/float_to_int_64_too_big2.stderr +++ b/tests/fail/intrinsics/float_to_int_64_too_big2.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on 9.2233720368547758E+18 which cannot be represented in target type `i64` --> $DIR/float_to_int_64_too_big2.rs:LL:CC | -LL | unsafe { float_to_int_unchecked::(9223372036854775808.0f64); } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on 9.2233720368547758E+18 which cannot be represented in target type `i64` +LL | float_to_int_unchecked::(9223372036854775808.0f64); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on 9.2233720368547758E+18 which cannot be represented in target type `i64` | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/intrinsics/float_to_int_64_too_big3.stderr b/tests/fail/intrinsics/float_to_int_64_too_big3.stderr index 2b7379fcbd387..d7f97f37de593 100644 --- a/tests/fail/intrinsics/float_to_int_64_too_big3.stderr +++ b/tests/fail/intrinsics/float_to_int_64_too_big3.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on 1.8446744073709552E+19 which cannot be represented in target type `u64` --> $DIR/float_to_int_64_too_big3.rs:LL:CC | -LL | unsafe { float_to_int_unchecked::(18446744073709551616.0f64); } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on 1.8446744073709552E+19 which cannot be represented in target type `u64` +LL | float_to_int_unchecked::(18446744073709551616.0f64); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on 1.8446744073709552E+19 which cannot be represented in target type `u64` | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/intrinsics/float_to_int_64_too_big4.stderr b/tests/fail/intrinsics/float_to_int_64_too_big4.stderr index d30817607b9f0..cfac443f4c9ed 100644 --- a/tests/fail/intrinsics/float_to_int_64_too_big4.stderr +++ b/tests/fail/intrinsics/float_to_int_64_too_big4.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on 3.4028236692093846E+38 which cannot be represented in target type `u128` --> $DIR/float_to_int_64_too_big4.rs:LL:CC | -LL | unsafe { float_to_int_unchecked::(u128::MAX as f64); } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on 3.4028236692093846E+38 which cannot be represented in target type `u128` +LL | float_to_int_unchecked::(u128::MAX as f64); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on 3.4028236692093846E+38 which cannot be represented in target type `u128` | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/intrinsics/float_to_int_64_too_big5.stderr b/tests/fail/intrinsics/float_to_int_64_too_big5.stderr index f6b0c0a3527f5..a0d501dad303f 100644 --- a/tests/fail/intrinsics/float_to_int_64_too_big5.stderr +++ b/tests/fail/intrinsics/float_to_int_64_too_big5.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on 2.4028236692093845E+38 which cannot be represented in target type `i128` --> $DIR/float_to_int_64_too_big5.rs:LL:CC | -LL | unsafe { float_to_int_unchecked::(240282366920938463463374607431768211455.0f64); } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on 2.4028236692093845E+38 which cannot be represented in target type `i128` +LL | float_to_int_unchecked::(240282366920938463463374607431768211455.0f64); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on 2.4028236692093845E+38 which cannot be represented in target type `i128` | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/intrinsics/float_to_int_64_too_big6.stderr b/tests/fail/intrinsics/float_to_int_64_too_big6.stderr index e0eab8148b07c..afb5d4ffe7228 100644 --- a/tests/fail/intrinsics/float_to_int_64_too_big6.stderr +++ b/tests/fail/intrinsics/float_to_int_64_too_big6.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on 1.7976931348623157E+308 which cannot be represented in target type `u128` --> $DIR/float_to_int_64_too_big6.rs:LL:CC | -LL | unsafe { float_to_int_unchecked::(f64::MAX); } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on 1.7976931348623157E+308 which cannot be represented in target type `u128` +LL | float_to_int_unchecked::(f64::MAX); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on 1.7976931348623157E+308 which cannot be represented in target type `u128` | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/intrinsics/float_to_int_64_too_big7.stderr b/tests/fail/intrinsics/float_to_int_64_too_big7.stderr index a291b21c7aad5..291acf529b4fc 100644 --- a/tests/fail/intrinsics/float_to_int_64_too_big7.stderr +++ b/tests/fail/intrinsics/float_to_int_64_too_big7.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on -1.7976931348623157E+308 which cannot be represented in target type `i128` --> $DIR/float_to_int_64_too_big7.rs:LL:CC | -LL | unsafe { float_to_int_unchecked::(f64::MIN); } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on -1.7976931348623157E+308 which cannot be represented in target type `i128` +LL | float_to_int_unchecked::(f64::MIN); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on -1.7976931348623157E+308 which cannot be represented in target type `i128` | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/intrinsics/float_to_int_64_too_small1.stderr b/tests/fail/intrinsics/float_to_int_64_too_small1.stderr index 81ca218505dd4..ceb625972690f 100644 --- a/tests/fail/intrinsics/float_to_int_64_too_small1.stderr +++ b/tests/fail/intrinsics/float_to_int_64_too_small1.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on -2147483649 which cannot be represented in target type `i32` --> $DIR/float_to_int_64_too_small1.rs:LL:CC | -LL | unsafe { float_to_int_unchecked::(-2147483649.0f64); } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on -2147483649 which cannot be represented in target type `i32` +LL | float_to_int_unchecked::(-2147483649.0f64); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on -2147483649 which cannot be represented in target type `i32` | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/intrinsics/float_to_int_64_too_small2.stderr b/tests/fail/intrinsics/float_to_int_64_too_small2.stderr index 245f5cf0238cb..f8255c2daca09 100644 --- a/tests/fail/intrinsics/float_to_int_64_too_small2.stderr +++ b/tests/fail/intrinsics/float_to_int_64_too_small2.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on -9.2233720368547778E+18 which cannot be represented in target type `i64` --> $DIR/float_to_int_64_too_small2.rs:LL:CC | -LL | unsafe { float_to_int_unchecked::(-9223372036854777856.0f64); } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on -9.2233720368547778E+18 which cannot be represented in target type `i64` +LL | float_to_int_unchecked::(-9223372036854777856.0f64); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on -9.2233720368547778E+18 which cannot be represented in target type `i64` | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/intrinsics/float_to_int_64_too_small3.stderr b/tests/fail/intrinsics/float_to_int_64_too_small3.stderr index f684ed2cde987..6bfb6f1f18d8a 100644 --- a/tests/fail/intrinsics/float_to_int_64_too_small3.stderr +++ b/tests/fail/intrinsics/float_to_int_64_too_small3.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on -2.4028236692093845E+38 which cannot be represented in target type `i128` --> $DIR/float_to_int_64_too_small3.rs:LL:CC | -LL | unsafe { float_to_int_unchecked::(-240282366920938463463374607431768211455.0f64); } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on -2.4028236692093845E+38 which cannot be represented in target type `i128` +LL | float_to_int_unchecked::(-240282366920938463463374607431768211455.0f64); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on -2.4028236692093845E+38 which cannot be represented in target type `i128` | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/intrinsics/unchecked_add1.stderr b/tests/fail/intrinsics/unchecked_add1.stderr index b967b46ac9bac..403bbbac5149f 100644 --- a/tests/fail/intrinsics/unchecked_add1.stderr +++ b/tests/fail/intrinsics/unchecked_add1.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: overflow executing `unchecked_add` --> $DIR/unchecked_add1.rs:LL:CC | -LL | unsafe { std::intrinsics::unchecked_add(40000u16, 30000); } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflow executing `unchecked_add` +LL | std::intrinsics::unchecked_add(40000u16, 30000); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflow executing `unchecked_add` | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/intrinsics/unchecked_add2.stderr b/tests/fail/intrinsics/unchecked_add2.stderr index 18a116b7da96b..4881fce719e7e 100644 --- a/tests/fail/intrinsics/unchecked_add2.stderr +++ b/tests/fail/intrinsics/unchecked_add2.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: overflow executing `unchecked_add` --> $DIR/unchecked_add2.rs:LL:CC | -LL | unsafe { std::intrinsics::unchecked_add(-30000i16, -8000); } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflow executing `unchecked_add` +LL | std::intrinsics::unchecked_add(-30000i16, -8000); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflow executing `unchecked_add` | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/intrinsics/unchecked_div1.stderr b/tests/fail/intrinsics/unchecked_div1.stderr index f153e4efd984b..4792608961d3d 100644 --- a/tests/fail/intrinsics/unchecked_div1.stderr +++ b/tests/fail/intrinsics/unchecked_div1.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: overflow in signed division (dividing MIN by -1) --> $DIR/unchecked_div1.rs:LL:CC | -LL | unsafe { std::intrinsics::unchecked_div(i16::MIN, -1); } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflow in signed division (dividing MIN by -1) +LL | std::intrinsics::unchecked_div(i16::MIN, -1); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflow in signed division (dividing MIN by -1) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/intrinsics/unchecked_mul1.stderr b/tests/fail/intrinsics/unchecked_mul1.stderr index 5372ba9933a25..e94676fdfed79 100644 --- a/tests/fail/intrinsics/unchecked_mul1.stderr +++ b/tests/fail/intrinsics/unchecked_mul1.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: overflow executing `unchecked_mul` --> $DIR/unchecked_mul1.rs:LL:CC | -LL | unsafe { std::intrinsics::unchecked_mul(300u16, 250u16); } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflow executing `unchecked_mul` +LL | std::intrinsics::unchecked_mul(300u16, 250u16); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflow executing `unchecked_mul` | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/intrinsics/unchecked_mul2.stderr b/tests/fail/intrinsics/unchecked_mul2.stderr index 20a44d2422ae9..493e04e46634d 100644 --- a/tests/fail/intrinsics/unchecked_mul2.stderr +++ b/tests/fail/intrinsics/unchecked_mul2.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: overflow executing `unchecked_mul` --> $DIR/unchecked_mul2.rs:LL:CC | -LL | unsafe { std::intrinsics::unchecked_mul(1_000_000_000i32, -4); } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflow executing `unchecked_mul` +LL | std::intrinsics::unchecked_mul(1_000_000_000i32, -4); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflow executing `unchecked_mul` | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/intrinsics/unchecked_sub1.stderr b/tests/fail/intrinsics/unchecked_sub1.stderr index 12abfed8ff73a..838005dc1e31d 100644 --- a/tests/fail/intrinsics/unchecked_sub1.stderr +++ b/tests/fail/intrinsics/unchecked_sub1.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: overflow executing `unchecked_sub` --> $DIR/unchecked_sub1.rs:LL:CC | -LL | unsafe { std::intrinsics::unchecked_sub(14u32, 22); } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflow executing `unchecked_sub` +LL | std::intrinsics::unchecked_sub(14u32, 22); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflow executing `unchecked_sub` | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/intrinsics/unchecked_sub2.stderr b/tests/fail/intrinsics/unchecked_sub2.stderr index d62d2de2f930d..dc4b170198797 100644 --- a/tests/fail/intrinsics/unchecked_sub2.stderr +++ b/tests/fail/intrinsics/unchecked_sub2.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: overflow executing `unchecked_sub` --> $DIR/unchecked_sub2.rs:LL:CC | -LL | unsafe { std::intrinsics::unchecked_sub(30000i16, -7000); } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflow executing `unchecked_sub` +LL | std::intrinsics::unchecked_sub(30000i16, -7000); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflow executing `unchecked_sub` | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/panic/unwind_panic_abort.stderr b/tests/fail/panic/unwind_panic_abort.stderr index 7ae965156f007..7094aebd6131c 100644 --- a/tests/fail/panic/unwind_panic_abort.stderr +++ b/tests/fail/panic/unwind_panic_abort.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: unwinding past a stack frame that does not allow unwinding --> $DIR/unwind_panic_abort.rs:LL:CC | -LL | unsafe { miri_start_panic(&mut 0); } - | ^^^^^^^^^^^^^^^^^^^^^^^^ unwinding past a stack frame that does not allow unwinding +LL | miri_start_panic(&mut 0); + | ^^^^^^^^^^^^^^^^^^^^^^^^ unwinding past a stack frame that does not allow unwinding | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/stacked_borrows/illegal_write1.stderr b/tests/fail/stacked_borrows/illegal_write1.stderr index 76639960a9232..a70a45f2235af 100644 --- a/tests/fail/stacked_borrows/illegal_write1.stderr +++ b/tests/fail/stacked_borrows/illegal_write1.stderr @@ -17,8 +17,8 @@ LL | let xref = &*target; help: was later invalidated at offsets [0x0..0x4] --> $DIR/illegal_write1.rs:LL:CC | -LL | unsafe { *x = 42; } // invalidates shared ref, activates raw - | ^^^^^^^ +LL | *x = 42; // invalidates shared ref, activates raw + | ^^^^^^^ = note: inside `main` at $DIR/illegal_write1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/illegal_write2.stderr b/tests/fail/stacked_borrows/illegal_write2.stderr index 3a225123d1f2b..d2a06cc386a14 100644 --- a/tests/fail/stacked_borrows/illegal_write2.stderr +++ b/tests/fail/stacked_borrows/illegal_write2.stderr @@ -1,11 +1,11 @@ error: Undefined Behavior: attempting a write access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location --> $DIR/illegal_write2.rs:LL:CC | -LL | unsafe { *target2 = 13; } - | ^^^^^^^^^^^^^ - | | - | attempting a write access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location - | this error occurs as part of an access at ALLOC[0x0..0x4] +LL | *target2 = 13; + | ^^^^^^^^^^^^^ + | | + | attempting a write access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | this error occurs as part of an access at ALLOC[0x0..0x4] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information diff --git a/tests/fail/stacked_borrows/illegal_write3.stderr b/tests/fail/stacked_borrows/illegal_write3.stderr index 0dc948b291521..fc87557ea9b46 100644 --- a/tests/fail/stacked_borrows/illegal_write3.stderr +++ b/tests/fail/stacked_borrows/illegal_write3.stderr @@ -1,11 +1,11 @@ error: Undefined Behavior: attempting a write access using at ALLOC[0x0], but that tag only grants SharedReadOnly permission for this location --> $DIR/illegal_write3.rs:LL:CC | -LL | unsafe { *ptr = 42; } - | ^^^^^^^^^ - | | - | attempting a write access using at ALLOC[0x0], but that tag only grants SharedReadOnly permission for this location - | this error occurs as part of an access at ALLOC[0x0..0x4] +LL | *ptr = 42; + | ^^^^^^^^^ + | | + | attempting a write access using at ALLOC[0x0], but that tag only grants SharedReadOnly permission for this location + | this error occurs as part of an access at ALLOC[0x0..0x4] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information diff --git a/tests/fail/stacked_borrows/illegal_write6.stderr b/tests/fail/stacked_borrows/illegal_write6.stderr index a58abc8377a00..3a7fc0ef8116b 100644 --- a/tests/fail/stacked_borrows/illegal_write6.stderr +++ b/tests/fail/stacked_borrows/illegal_write6.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: not granting access to tag because incompatible item is protected: [Unique for (call ID)] --> $DIR/illegal_write6.rs:LL:CC | -LL | unsafe { *y = 2; } - | ^^^^^^ not granting access to tag because incompatible item is protected: [Unique for (call ID)] +LL | *y = 2; + | ^^^^^^ not granting access to tag because incompatible item is protected: [Unique for (call ID)] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information @@ -22,7 +22,8 @@ help: this protector is live for this call LL | / fn foo(a: &mut u32, y: *mut u32) -> u32 { LL | | *a = 1; LL | | let _b = &*a; -LL | | unsafe { *y = 2; } +LL | | unsafe { +... | LL | | return *a; LL | | } | |_^ diff --git a/tests/fail/stacked_borrows/raw_tracking.stderr b/tests/fail/stacked_borrows/raw_tracking.stderr index 93ae613c3c6b4..60a277ee057ec 100644 --- a/tests/fail/stacked_borrows/raw_tracking.stderr +++ b/tests/fail/stacked_borrows/raw_tracking.stderr @@ -1,11 +1,11 @@ error: Undefined Behavior: attempting a write access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location --> $DIR/raw_tracking.rs:LL:CC | -LL | unsafe { *raw1 = 13; } - | ^^^^^^^^^^ - | | - | attempting a write access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location - | this error occurs as part of an access at ALLOC[0x0..0x4] +LL | *raw1 = 13; + | ^^^^^^^^^^ + | | + | attempting a write access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | this error occurs as part of an access at ALLOC[0x0..0x4] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information diff --git a/tests/fail/stacked_borrows/shr_frozen_violation1.stderr b/tests/fail/stacked_borrows/shr_frozen_violation1.stderr index a2487cca278cc..0808d8471b452 100644 --- a/tests/fail/stacked_borrows/shr_frozen_violation1.stderr +++ b/tests/fail/stacked_borrows/shr_frozen_violation1.stderr @@ -1,25 +1,25 @@ error: Undefined Behavior: attempting a write access using at ALLOC[0x0], but that tag only grants SharedReadOnly permission for this location --> $DIR/shr_frozen_violation1.rs:LL:CC | -LL | unsafe { *(x as *const i32 as *mut i32) = 7; } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | | - | attempting a write access using at ALLOC[0x0], but that tag only grants SharedReadOnly permission for this location - | this error occurs as part of an access at ALLOC[0x0..0x4] +LL | *(x as *const i32 as *mut i32) = 7; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | attempting a write access using at ALLOC[0x0], but that tag only grants SharedReadOnly permission for this location + | this error occurs as part of an access at ALLOC[0x0..0x4] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: tag was most recently created at offsets [0x0..0x4] --> $DIR/shr_frozen_violation1.rs:LL:CC | -LL | unsafe { *(x as *const i32 as *mut i32) = 7; } - | ^ +LL | *(x as *const i32 as *mut i32) = 7; + | ^ = note: inside `unknown_code` at $DIR/shr_frozen_violation1.rs:LL:CC note: inside `foo` at $DIR/shr_frozen_violation1.rs:LL:CC --> $DIR/shr_frozen_violation1.rs:LL:CC | -LL | unknown_code(&*x); - | ^^^^^^^^^^^^^^^^^ +LL | unknown_code(&*x); + | ^^^^^^^^^^^^^^^^^ note: inside `main` at $DIR/shr_frozen_violation1.rs:LL:CC --> $DIR/shr_frozen_violation1.rs:LL:CC | diff --git a/tests/fail/stacked_borrows/transmute-is-no-escape.stderr b/tests/fail/stacked_borrows/transmute-is-no-escape.stderr index 75d74ce393463..c077e37844d15 100644 --- a/tests/fail/stacked_borrows/transmute-is-no-escape.stderr +++ b/tests/fail/stacked_borrows/transmute-is-no-escape.stderr @@ -1,11 +1,11 @@ error: Undefined Behavior: attempting a write access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location --> $DIR/transmute-is-no-escape.rs:LL:CC | -LL | unsafe { *raw = 13; } - | ^^^^^^^^^ - | | - | attempting a write access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location - | this error occurs as part of an access at ALLOC[0x0..0x4] +LL | *raw = 13; + | ^^^^^^^^^ + | | + | attempting a write access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | this error occurs as part of an access at ALLOC[0x0..0x4] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information diff --git a/tests/fail/stacked_borrows/unescaped_local.stderr b/tests/fail/stacked_borrows/unescaped_local.stderr index 42a81245f2a83..616c60b8aa1b8 100644 --- a/tests/fail/stacked_borrows/unescaped_local.stderr +++ b/tests/fail/stacked_borrows/unescaped_local.stderr @@ -1,11 +1,11 @@ error: Undefined Behavior: attempting a write access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location --> $DIR/unescaped_local.rs:LL:CC | -LL | unsafe { *raw = 13; } - | ^^^^^^^^^ - | | - | attempting a write access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location - | this error occurs as part of an access at ALLOC[0x0..0x4] +LL | *raw = 13; + | ^^^^^^^^^ + | | + | attempting a write access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | this error occurs as part of an access at ALLOC[0x0..0x4] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information diff --git a/tests/fail/unaligned_pointers/intptrcast_alignment_check.stderr b/tests/fail/unaligned_pointers/intptrcast_alignment_check.stderr index 8e0986c453356..fe63b05a55014 100644 --- a/tests/fail/unaligned_pointers/intptrcast_alignment_check.stderr +++ b/tests/fail/unaligned_pointers/intptrcast_alignment_check.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: accessing memory with alignment ALIGN, but alignment ALIGN is required --> $DIR/intptrcast_alignment_check.rs:LL:CC | -LL | unsafe { *u16_ptr = 2; } - | ^^^^^^^^^^^^ accessing memory with alignment ALIGN, but alignment ALIGN is required +LL | *u16_ptr = 2; + | ^^^^^^^^^^^^ accessing memory with alignment ALIGN, but alignment ALIGN is required | = help: this usually indicates that your program performed an invalid operation and caused Undefined Behavior = help: but due to `-Zmiri-symbolic-alignment-check`, alignment errors can also be false positives diff --git a/tests/fail/zst2.stderr b/tests/fail/zst2.stderr index 088bb2a1ccf0c..0df2098d2e19a 100644 --- a/tests/fail/zst2.stderr +++ b/tests/fail/zst2.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: pointer to ALLOC was dereferenced after this allocation got freed --> $DIR/zst2.rs:LL:CC | -LL | unsafe { *x = zst_val; } - | ^^^^^^^^^^^^ pointer to ALLOC was dereferenced after this allocation got freed +LL | *x = zst_val; + | ^^^^^^^^^^^^ pointer to ALLOC was dereferenced after this allocation got freed | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/zst3.stderr b/tests/fail/zst3.stderr index a7d84dcaad590..dce0d7b3891ca 100644 --- a/tests/fail/zst3.stderr +++ b/tests/fail/zst3.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: dereferencing pointer failed: ALLOC has size 1, so pointer at offset 2 is out-of-bounds --> $DIR/zst3.rs:LL:CC | -LL | unsafe { *(x as *mut [u8; 0]) = zst_val; } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ dereferencing pointer failed: ALLOC has size 1, so pointer at offset 2 is out-of-bounds +LL | *(x as *mut [u8; 0]) = zst_val; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ dereferencing pointer failed: ALLOC has size 1, so pointer at offset 2 is out-of-bounds | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information From 8d1b2ca3ec998fc8bdbfe03f5c8faf7cc138a9ed Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 14 Jun 2022 09:45:02 -0700 Subject: [PATCH 3288/3747] check that tag_alloc_base_pointer is not called on the wrong things --- src/machine.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/machine.rs b/src/machine.rs index 824f0e3fc8748..955677df6f079 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -662,6 +662,19 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { ecx: &MiriEvalContext<'mir, 'tcx>, ptr: Pointer, ) -> Pointer { + if cfg!(debug_assertions) { + // The machine promises to never call us on thread-local or extern statics. + let alloc_id = ptr.provenance; + match ecx.tcx.get_global_alloc(alloc_id) { + Some(GlobalAlloc::Static(def_id)) if ecx.tcx.is_thread_local_static(def_id) => { + panic!("tag_alloc_base_pointer called on thread-local static") + } + Some(GlobalAlloc::Static(def_id)) if ecx.tcx.is_foreign_item(def_id) => { + panic!("tag_alloc_base_pointer called on extern static") + } + _ => {} + } + } let absolute_addr = intptrcast::GlobalStateInner::rel_ptr_to_addr(ecx, ptr); let sb_tag = if let Some(stacked_borrows) = &ecx.machine.stacked_borrows { stacked_borrows.borrow_mut().base_tag(ptr.provenance) From f992099820993005ec9ac9ddf6d6646b85c55311 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 19 Jun 2022 09:45:05 -0700 Subject: [PATCH 3289/3747] fix ICE when const refers to extern static --- src/machine.rs | 8 ++++---- src/thread.rs | 2 +- tests/fail/extern_static_in_const.rs | 11 +++++++++++ tests/fail/extern_static_in_const.stderr | 14 ++++++++++++++ 4 files changed, 30 insertions(+), 5 deletions(-) create mode 100644 tests/fail/extern_static_in_const.rs create mode 100644 tests/fail/extern_static_in_const.stderr diff --git a/src/machine.rs b/src/machine.rs index 955677df6f079..d14ddaa1a6bbf 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -618,7 +618,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { id: AllocId, alloc: Cow<'b, Allocation>, kind: Option>, - ) -> Cow<'b, Allocation> { + ) -> InterpResult<'tcx, Cow<'b, Allocation>> { if ecx.machine.tracked_alloc_ids.contains(&id) { register_diagnostic(NonHaltingDiagnostic::CreatedAlloc(id)); } @@ -653,9 +653,9 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { data_race: race_alloc, weak_memory: buffer_alloc, }, - |ptr| Evaluator::tag_alloc_base_pointer(ecx, ptr), - ); - Cow::Owned(alloc) + |ptr| ecx.global_base_pointer(ptr), + )?; + Ok(Cow::Owned(alloc)) } fn tag_alloc_base_pointer( diff --git a/src/thread.rs b/src/thread.rs index 9eabbd77419fb..2135806de3ed5 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -587,7 +587,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // This allocation will be deallocated when the thread dies, so it is not in read-only memory. allocation.mutability = Mutability::Mut; // Create a fresh allocation with this content. - let new_alloc = this.allocate_raw_ptr(allocation, MiriMemoryKind::Tls.into()); + let new_alloc = this.allocate_raw_ptr(allocation, MiriMemoryKind::Tls.into())?; this.machine.threads.set_thread_local_alloc(def_id, new_alloc); Ok(new_alloc) } diff --git a/tests/fail/extern_static_in_const.rs b/tests/fail/extern_static_in_const.rs new file mode 100644 index 0000000000000..4c1de6ace51d3 --- /dev/null +++ b/tests/fail/extern_static_in_const.rs @@ -0,0 +1,11 @@ +//! Even referencing an unknown `extern static` already triggers an error. + +extern "C" { + static E: [u8; 0]; +} + +static X: &'static [u8; 0] = unsafe { &E }; + +fn main() { + let _val = X; //~ ERROR is not supported by Miri +} diff --git a/tests/fail/extern_static_in_const.stderr b/tests/fail/extern_static_in_const.stderr new file mode 100644 index 0000000000000..8524bb02c054f --- /dev/null +++ b/tests/fail/extern_static_in_const.stderr @@ -0,0 +1,14 @@ +error: unsupported operation: `extern` static `E` from crate `extern_static_in_const` is not supported by Miri + --> $DIR/extern_static_in_const.rs:LL:CC + | +LL | let _val = X; + | ^ `extern` static `E` from crate `extern_static_in_const` is not supported by Miri + | + = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support + + = note: inside `main` at $DIR/extern_static_in_const.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + From b29a706edd5e9b7d9f8bf0ba1beb2374326f8acf Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 21 Jun 2022 21:03:52 -0700 Subject: [PATCH 3290/3747] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 9782fbe6cd456..45773390616b9 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -cdcc53b7dc002ea4a7a28105010c5a1126ee31b7 +a09c668c965f735f4cd59e7158662b9daa0b71ba From 7308f8f3cfbdaf13613278140d256e85ecc1c84c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 21 Jun 2022 22:24:18 -0700 Subject: [PATCH 3291/3747] ui_test: fix behavior of only-Nbits comments --- ui_test/src/comments.rs | 29 ++++++++++++++++++++++++---- ui_test/src/lib.rs | 42 ++++++++++++++++++----------------------- 2 files changed, 43 insertions(+), 28 deletions(-) diff --git a/ui_test/src/comments.rs b/ui_test/src/comments.rs index cc9870a63be4b..d50d6a5345739 100644 --- a/ui_test/src/comments.rs +++ b/ui_test/src/comments.rs @@ -15,9 +15,9 @@ pub(crate) struct Comments { /// List of revision names to execute. Can only be speicified once pub revisions: Option>, /// Don't run this test if any of these filters apply - pub ignore: Vec, + pub ignore: Vec, /// Only run this test if all of these filters apply - pub only: Vec, + pub only: Vec, /// Generate one .stderr file per bit width, by prepending with `.64bit` and similar pub stderr_per_bitwidth: bool, /// Additional flags to pass to the executable @@ -31,6 +31,16 @@ pub(crate) struct Comments { pub error_matches: Vec, } + +/// The conditions used for "ignore" and "only" filters. +#[derive(Debug)] +pub(crate) enum Condition { + /// The given string must appear in the target. + Target(String), + /// Tests that the bitwidth is the given one. + Bitwidth(u8), +} + #[derive(Debug)] pub(crate) struct ErrorMatch { pub matched: String, @@ -42,6 +52,17 @@ pub(crate) struct ErrorMatch { pub line: usize, } +impl Condition { + fn parse(c: &str) -> Self { + if let Some(bits) = c.strip_suffix("bit") { + let bits: u8 = bits.parse().expect("ignore/only filter ending in 'bit' must be of the form 'Nbit' for some integer N"); + Condition::Bitwidth(bits) + } else { + Condition::Target(c.to_owned()) + } + } +} + impl Comments { pub(crate) fn parse_file(path: &Path) -> Self { let content = std::fs::read_to_string(path).unwrap(); @@ -75,14 +96,14 @@ impl Comments { .split_once(|c: char| c == ':' || c.is_whitespace()) .map(|(s, _)| s) .unwrap_or(s); - this.ignore.push(s.to_owned()); + this.ignore.push(Condition::parse(s)); } if let Some(s) = line.strip_prefix("// only-") { let s = s .split_once(|c: char| c == ':' || c.is_whitespace()) .map(|(s, _)| s) .unwrap_or(s); - this.only.push(s.to_owned()); + this.only.push(Condition::parse(s)); } if line.starts_with("// stderr-per-bitwidth") { assert!( diff --git a/ui_test/src/lib.rs b/ui_test/src/lib.rs index d6938b19bfe49..9706221446806 100644 --- a/ui_test/src/lib.rs +++ b/ui_test/src/lib.rs @@ -10,7 +10,7 @@ use comments::ErrorMatch; use regex::Regex; use rustc_stderr::{Level, Message}; -use crate::comments::Comments; +use crate::comments::{Comments, Condition}; mod comments; mod rustc_stderr; @@ -103,7 +103,7 @@ pub fn run_tests(config: Config) { } let comments = Comments::parse_file(&path); // Ignore file if only/ignore rules do (not) apply - if ignore_file(&comments, &target) { + if !test_file_conditions(&comments, &target) { ignored.fetch_add(1, Ordering::Relaxed); eprintln!( "{} ... {}", @@ -509,42 +509,36 @@ fn check_output( fn output_path(path: &Path, comments: &Comments, kind: String, target: &str) -> PathBuf { if comments.stderr_per_bitwidth { - return path.with_extension(format!("{}.{kind}", get_pointer_width(target))); + return path.with_extension(format!("{}bit.{kind}", get_pointer_width(target))); } path.with_extension(kind) } -fn ignore_file(comments: &Comments, target: &str) -> bool { - for s in &comments.ignore { - if target.contains(s) { - return true; - } - if get_pointer_width(target) == s { - return true; - } +fn test_condition(condition: &Condition, target: &str) -> bool { + match condition { + Condition::Bitwidth(bits) => get_pointer_width(target) == *bits, + Condition::Target(t) => target.contains(t), } - for s in &comments.only { - if !target.contains(s) { - return true; - } - /* FIXME(https://github.com/rust-lang/miri/issues/2206) - if get_pointer_width(target) != s { - return true; - } */ +} + +/// Returns whether according to the in-file conditions, this file should be run. +fn test_file_conditions(comments: &Comments, target: &str) -> bool { + if comments.ignore.iter().any(|c| test_condition(c, target)) { + return false; } - false + comments.only.iter().all(|c| test_condition(c, target)) } // Taken 1:1 from compiletest-rs -fn get_pointer_width(triple: &str) -> &'static str { +fn get_pointer_width(triple: &str) -> u8 { if (triple.contains("64") && !triple.ends_with("gnux32") && !triple.ends_with("gnu_ilp32")) || triple.starts_with("s390x") { - "64bit" + 64 } else if triple.starts_with("avr") { - "16bit" + 16 } else { - "32bit" + 32 } } From 7d09004aee288b3debfcfa734c77a4805ad76822 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Tue, 21 Jun 2022 22:56:50 -0700 Subject: [PATCH 3292/3747] Format tests with rustfmt (276-287 of 299) --- tests/fail/branchless-select-i128-pointer.rs | 6 +- tests/fail/data_race/dealloc_read_race1.rs | 10 +- tests/fail/data_race/dealloc_write_race1.rs | 6 +- .../fail/function_calls/check_callback_abi.rs | 3 +- .../exported_symbol_abi_mismatch.rs | 8 +- tests/fail/type-too-large.rs | 3 +- tests/fail/validity/invalid_char.rs | 9 +- tests/pass/0weak_memory_consistency.rs | 12 +- tests/pass/concurrency/linux-futex.rs | 195 +++++++++--------- tests/pass/deriving-associated-types.rs | 113 ++++------ tests/pass/heap_allocator.rs | 108 ++++++---- tests/pass/iter.rs | 9 +- 12 files changed, 251 insertions(+), 231 deletions(-) diff --git a/tests/fail/branchless-select-i128-pointer.rs b/tests/fail/branchless-select-i128-pointer.rs index 20fbcd1de78a8..b0c9c0fd72821 100644 --- a/tests/fail/branchless-select-i128-pointer.rs +++ b/tests/fail/branchless-select-i128-pointer.rs @@ -11,8 +11,10 @@ fn main() { // This is branchless code to select one or the other pointer. // However, it drops provenance when transmuting to TwoPtrs, so this is UB. let val = unsafe { - transmute::<_, &str>( //~ERROR type validation failed: encountered a dangling reference - !mask & transmute::<_, TwoPtrs>("false !") | mask & transmute::<_, TwoPtrs>("true !"), + transmute::<_, &str>( + //~ERROR type validation failed: encountered a dangling reference + !mask & transmute::<_, TwoPtrs>("false !") + | mask & transmute::<_, TwoPtrs>("true !"), ) }; println!("{}", val); diff --git a/tests/fail/data_race/dealloc_read_race1.rs b/tests/fail/data_race/dealloc_read_race1.rs index 14b02e95cc233..38bbd81f1e2fb 100644 --- a/tests/fail/data_race/dealloc_read_race1.rs +++ b/tests/fail/data_race/dealloc_read_race1.rs @@ -18,12 +18,14 @@ pub fn main() { let ptr = EvilSend(pointer); unsafe { - let j1 = spawn(move || { - *ptr.0 - }); + let j1 = spawn(move || *ptr.0); let j2 = spawn(move || { - __rust_dealloc(ptr.0 as *mut _, std::mem::size_of::(), std::mem::align_of::()); //~ ERROR Data race detected between Deallocate on Thread(id = 2) and Read on Thread(id = 1) + __rust_dealloc( + ptr.0 as *mut _, + std::mem::size_of::(), + std::mem::align_of::(), + ); //~ ERROR Data race detected between Deallocate on Thread(id = 2) and Read on Thread(id = 1) }); j1.join().unwrap(); diff --git a/tests/fail/data_race/dealloc_write_race1.rs b/tests/fail/data_race/dealloc_write_race1.rs index edcdfffdb5f53..1cfaeb2cb25a6 100644 --- a/tests/fail/data_race/dealloc_write_race1.rs +++ b/tests/fail/data_race/dealloc_write_race1.rs @@ -22,7 +22,11 @@ pub fn main() { }); let j2 = spawn(move || { - __rust_dealloc(ptr.0 as *mut _, std::mem::size_of::(), std::mem::align_of::()); //~ ERROR Data race detected between Deallocate on Thread(id = 2) and Write on Thread(id = 1) + __rust_dealloc( + ptr.0 as *mut _, + std::mem::size_of::(), + std::mem::align_of::(), + ); //~ ERROR Data race detected between Deallocate on Thread(id = 2) and Write on Thread(id = 1) }); j1.join().unwrap(); diff --git a/tests/fail/function_calls/check_callback_abi.rs b/tests/fail/function_calls/check_callback_abi.rs index e36bfe1c5783e..f76839c34f208 100644 --- a/tests/fail/function_calls/check_callback_abi.rs +++ b/tests/fail/function_calls/check_callback_abi.rs @@ -8,7 +8,8 @@ fn main() { unsafe { // Make sure we check the ABI when Miri itself invokes a function // as part of a shim implementation. - std::intrinsics::r#try( //~ ERROR calling a function with ABI C using caller ABI Rust + std::intrinsics::r#try( + //~ ERROR calling a function with ABI C using caller ABI Rust std::mem::transmute::(try_fn), std::ptr::null_mut(), |_, _| unreachable!(), diff --git a/tests/fail/function_calls/exported_symbol_abi_mismatch.rs b/tests/fail/function_calls/exported_symbol_abi_mismatch.rs index 7dbda584e8d4c..7e8fb2cffecbb 100644 --- a/tests/fail/function_calls/exported_symbol_abi_mismatch.rs +++ b/tests/fail/function_calls/exported_symbol_abi_mismatch.rs @@ -10,12 +10,16 @@ fn main() { } #[cfg(fn_ptr)] - unsafe { std::mem::transmute::(foo)() } + unsafe { + std::mem::transmute::(foo)() + } //[fn_ptr]~^ ERROR calling a function with calling convention Rust using calling convention C // `Instance` caching should not suppress ABI check. #[cfg(cache)] - unsafe { foo() } + unsafe { + foo() + } { #[cfg_attr(any(cache, fn_ptr), allow(clashing_extern_declarations))] diff --git a/tests/fail/type-too-large.rs b/tests/fail/type-too-large.rs index 2c4ff7013a460..d9e19ed818763 100644 --- a/tests/fail/type-too-large.rs +++ b/tests/fail/type-too-large.rs @@ -1,6 +1,5 @@ // ignore-32bit fn main() { - let _fat: [u8; (1<<61)+(1<<31)] = - [0; (1u64<<61) as usize +(1u64<<31) as usize]; //~ ERROR post-monomorphization error + let _fat: [u8; (1 << 61) + (1 << 31)] = [0; (1u64 << 61) as usize + (1u64 << 31) as usize]; //~ ERROR post-monomorphization error } diff --git a/tests/fail/validity/invalid_char.rs b/tests/fail/validity/invalid_char.rs index 079823f894a86..a868dac8875df 100644 --- a/tests/fail/validity/invalid_char.rs +++ b/tests/fail/validity/invalid_char.rs @@ -1,8 +1,9 @@ fn main() { assert!(std::char::from_u32(-1_i32 as u32).is_none()); - let _val = match unsafe { std::mem::transmute::(-1) } { //~ ERROR encountered 0xffffffff, but expected a valid unicode scalar value - 'a' => {true}, - 'b' => {false}, - _ => {true}, + let _val = match unsafe { std::mem::transmute::(-1) } { + //~ ERROR encountered 0xffffffff, but expected a valid unicode scalar value + 'a' => true, + 'b' => false, + _ => true, }; } diff --git a/tests/pass/0weak_memory_consistency.rs b/tests/pass/0weak_memory_consistency.rs index fc9dce0c986ab..ae8d281858c23 100644 --- a/tests/pass/0weak_memory_consistency.rs +++ b/tests/pass/0weak_memory_consistency.rs @@ -60,7 +60,8 @@ fn test_corr() { r2 // | | }); // | | // |synchronizes-with |happens-before - let j3 = spawn(move || { // | | + let j3 = spawn(move || { + // | | acquires_value(&y, 1); // <------------------+ | x.load(Relaxed) // <----------------------------------------------+ // The two reads on x are ordered by hb, so they cannot observe values @@ -84,12 +85,14 @@ fn test_wrc() { x.store(1, Release); // ---------------------+---------------------+ }); // | | // |synchronizes-with | - let j2 = spawn(move || { // | | + let j2 = spawn(move || { + // | | acquires_value(&x, 1); // <------------------+ | y.store(1, Release); // ---------------------+ |happens-before }); // | | // |synchronizes-with | - let j3 = spawn(move || { // | | + let j3 = spawn(move || { + // | | acquires_value(&y, 1); // <------------------+ | x.load(Relaxed) // <-----------------------------------------------+ }); @@ -112,7 +115,8 @@ fn test_message_passing() { y.store(1, Release); // ---------------------+ | }); // | | // |synchronizes-with | happens-before - let j2 = spawn(move || { // | | + let j2 = spawn(move || { + // | | acquires_value(&y, 1); // <------------------+ | unsafe { *x.0 } // <---------------------------------------------+ }); diff --git a/tests/pass/concurrency/linux-futex.rs b/tests/pass/concurrency/linux-futex.rs index 0d30ddff4809f..74fec411b4c99 100644 --- a/tests/pass/concurrency/linux-futex.rs +++ b/tests/pass/concurrency/linux-futex.rs @@ -16,25 +16,23 @@ fn wake_nobody() { // Wake 1 waiter. Expect zero waiters woken up, as nobody is waiting. unsafe { - assert_eq!(libc::syscall( - libc::SYS_futex, - &futex as *const i32, - libc::FUTEX_WAKE, - 1, - ), 0); + assert_eq!(libc::syscall(libc::SYS_futex, &futex as *const i32, libc::FUTEX_WAKE, 1,), 0); } // Same, but without omitting the unused arguments. unsafe { - assert_eq!(libc::syscall( - libc::SYS_futex, - &futex as *const i32, - libc::FUTEX_WAKE, - 1, - ptr::null::(), - 0usize, - 0, - ), 0); + assert_eq!( + libc::syscall( + libc::SYS_futex, + &futex as *const i32, + libc::FUTEX_WAKE, + 1, + ptr::null::(), + 0usize, + 0, + ), + 0 + ); } } @@ -45,12 +43,7 @@ fn wake_dangling() { // Wake 1 waiter. Expect zero waiters woken up, as nobody is waiting. unsafe { - assert_eq!(libc::syscall( - libc::SYS_futex, - ptr, - libc::FUTEX_WAKE, - 1, - ), 0); + assert_eq!(libc::syscall(libc::SYS_futex, ptr, libc::FUTEX_WAKE, 1,), 0); } } @@ -59,13 +52,16 @@ fn wait_wrong_val() { // Only wait if the futex value is 456. unsafe { - assert_eq!(libc::syscall( - libc::SYS_futex, - &futex as *const i32, - libc::FUTEX_WAIT, - 456, - ptr::null::(), - ), -1); + assert_eq!( + libc::syscall( + libc::SYS_futex, + &futex as *const i32, + libc::FUTEX_WAIT, + 456, + ptr::null::(), + ), + -1 + ); assert_eq!(*libc::__errno_location(), libc::EAGAIN); } } @@ -77,16 +73,16 @@ fn wait_timeout() { // Wait for 200ms, with nobody waking us up early. unsafe { - assert_eq!(libc::syscall( - libc::SYS_futex, - &futex as *const i32, - libc::FUTEX_WAIT, - 123, - &libc::timespec { - tv_sec: 0, - tv_nsec: 200_000_000, - }, - ), -1); + assert_eq!( + libc::syscall( + libc::SYS_futex, + &futex as *const i32, + libc::FUTEX_WAIT, + 123, + &libc::timespec { tv_sec: 0, tv_nsec: 200_000_000 }, + ), + -1 + ); assert_eq!(*libc::__errno_location(), libc::ETIMEDOUT); } @@ -114,15 +110,18 @@ fn wait_absolute_timeout() { // Wait for 200ms from now, with nobody waking us up early. unsafe { - assert_eq!(libc::syscall( - libc::SYS_futex, - &futex as *const i32, - libc::FUTEX_WAIT_BITSET, - 123, - &timeout, - 0usize, - u32::MAX, - ), -1); + assert_eq!( + libc::syscall( + libc::SYS_futex, + &futex as *const i32, + libc::FUTEX_WAIT_BITSET, + 123, + &timeout, + 0usize, + u32::MAX, + ), + -1 + ); assert_eq!(*libc::__errno_location(), libc::ETIMEDOUT); } @@ -137,23 +136,29 @@ fn wait_wake() { let t = thread::spawn(move || { thread::sleep(Duration::from_millis(200)); unsafe { - assert_eq!(libc::syscall( - libc::SYS_futex, - &FUTEX as *const i32, - libc::FUTEX_WAKE, - 10, // Wake up at most 10 threads. - ), 1); // Woken up one thread. + assert_eq!( + libc::syscall( + libc::SYS_futex, + &FUTEX as *const i32, + libc::FUTEX_WAKE, + 10, // Wake up at most 10 threads. + ), + 1 + ); // Woken up one thread. } }); unsafe { - assert_eq!(libc::syscall( - libc::SYS_futex, - &FUTEX as *const i32, - libc::FUTEX_WAIT, - 0, - ptr::null::(), - ), 0); + assert_eq!( + libc::syscall( + libc::SYS_futex, + &FUTEX as *const i32, + libc::FUTEX_WAIT, + 0, + ptr::null::(), + ), + 0 + ); } assert!((200..1000).contains(&start.elapsed().as_millis())); @@ -168,40 +173,49 @@ fn wait_wake_bitset() { let t = thread::spawn(move || { thread::sleep(Duration::from_millis(200)); unsafe { - assert_eq!(libc::syscall( - libc::SYS_futex, - &FUTEX as *const i32, - libc::FUTEX_WAKE_BITSET, - 10, // Wake up at most 10 threads. - ptr::null::(), - 0usize, - 0b1001, // bitset - ), 0); // Didn't match any thread. + assert_eq!( + libc::syscall( + libc::SYS_futex, + &FUTEX as *const i32, + libc::FUTEX_WAKE_BITSET, + 10, // Wake up at most 10 threads. + ptr::null::(), + 0usize, + 0b1001, // bitset + ), + 0 + ); // Didn't match any thread. } thread::sleep(Duration::from_millis(200)); unsafe { - assert_eq!(libc::syscall( - libc::SYS_futex, - &FUTEX as *const i32, - libc::FUTEX_WAKE_BITSET, - 10, // Wake up at most 10 threads. - ptr::null::(), - 0usize, - 0b0110, // bitset - ), 1); // Woken up one thread. + assert_eq!( + libc::syscall( + libc::SYS_futex, + &FUTEX as *const i32, + libc::FUTEX_WAKE_BITSET, + 10, // Wake up at most 10 threads. + ptr::null::(), + 0usize, + 0b0110, // bitset + ), + 1 + ); // Woken up one thread. } }); unsafe { - assert_eq!(libc::syscall( - libc::SYS_futex, - &FUTEX as *const i32, - libc::FUTEX_WAIT_BITSET, - 0, - ptr::null::(), - 0usize, - 0b0100, // bitset - ), 0); + assert_eq!( + libc::syscall( + libc::SYS_futex, + &FUTEX as *const i32, + libc::FUTEX_WAIT_BITSET, + 0, + ptr::null::(), + 0usize, + 0b0100, // bitset + ), + 0 + ); } assert!((400..1000).contains(&start.elapsed().as_millis())); @@ -237,12 +251,7 @@ fn concurrent_wait_wake() { FUTEX.store(FREE, Ordering::Relaxed); unsafe { - libc::syscall( - libc::SYS_futex, - &FUTEX as *const AtomicI32, - libc::FUTEX_WAKE, - 1, - ); + libc::syscall(libc::SYS_futex, &FUTEX as *const AtomicI32, libc::FUTEX_WAKE, 1); } t.join().unwrap(); diff --git a/tests/pass/deriving-associated-types.rs b/tests/pass/deriving-associated-types.rs index 52104d8486b05..4803792a97cee 100644 --- a/tests/pass/deriving-associated-types.rs +++ b/tests/pass/deriving-associated-types.rs @@ -40,10 +40,15 @@ struct TupleStruct( ::Type, Option<::Type>, ::Type, -) where C: WhereTrait; +) +where + C: WhereTrait; #[derive(PartialEq, Debug)] -pub struct Struct where C: WhereTrait { +pub struct Struct +where + C: WhereTrait, +{ m1: module::Type, m2: Option, a1: A, @@ -62,7 +67,10 @@ pub struct Struct where C: WhereTrait { } #[derive(PartialEq, Debug)] -enum Enum where C: WhereTrait { +enum Enum +where + C: WhereTrait, +{ Unit, Seq( module::Type, @@ -101,35 +109,11 @@ enum Enum where C: WhereTrait { } fn main() { - - let e: Enum< - i32, - i32, - i32, - > = Enum::Seq( - 0, - None, - 0, - PrivateStruct(0), - 0, - 0, - None, - 0, - None, - 0, - 0, - None, - 0, - None, - 0, - ); + let e: Enum = + Enum::Seq(0, None, 0, PrivateStruct(0), 0, 0, None, 0, None, 0, 0, None, 0, None, 0); assert_eq!(e, e); - let e: Enum< - i32, - i32, - i32, - > = Enum::Map { + let e: Enum = Enum::Map { m1: 0, m2: None, a1: 0, @@ -147,52 +131,29 @@ fn main() { d: 0, }; assert_eq!(e, e); - let e: TupleStruct< - i32, - i32, - i32, - > = TupleStruct( - 0, - None, - 0, - PrivateStruct(0), - 0, - 0, - None, - 0, - None, - 0, - 0, - None, - 0, - None, - 0, - ); - assert_eq!(e, e); + let e: TupleStruct = + TupleStruct(0, None, 0, PrivateStruct(0), 0, 0, None, 0, None, 0, 0, None, 0, None, 0); + assert_eq!(e, e); - let e: Struct< - i32, - i32, - i32, - > = Struct { - m1: 0, - m2: None, - a1: 0, - a2: PrivateStruct(0), - b: 0, - b1: 0, - b2: None, - b3: 0, - b4: None, - c: 0, - c1: 0, - c2: None, - c3: 0, - c4: None, - d: 0, - }; - assert_eq!(e, e); + let e: Struct = Struct { + m1: 0, + m2: None, + a1: 0, + a2: PrivateStruct(0), + b: 0, + b1: 0, + b2: None, + b3: 0, + b4: None, + c: 0, + c1: 0, + c2: None, + c3: 0, + c4: None, + d: 0, + }; + assert_eq!(e, e); - let e = Enum::Unit::; - assert_eq!(e, e); + let e = Enum::Unit::; + assert_eq!(e, e); } diff --git a/tests/pass/heap_allocator.rs b/tests/pass/heap_allocator.rs index e428868af78bf..a3ab5b21f0b3e 100644 --- a/tests/pass/heap_allocator.rs +++ b/tests/pass/heap_allocator.rs @@ -1,58 +1,90 @@ #![feature(allocator_api, slice_ptr_get)] +use std::alloc::{Allocator, Global, Layout, System}; use std::ptr::NonNull; -use std::alloc::{Global, Allocator, Layout, System}; use std::slice; -fn check_alloc(allocator: T) { unsafe { - for &align in &[4, 8, 16, 32] { - let layout_20 = Layout::from_size_align(20, align).unwrap(); - let layout_40 = Layout::from_size_align(40, 4*align).unwrap(); - let layout_10 = Layout::from_size_align(10, align/2).unwrap(); +fn check_alloc(allocator: T) { + unsafe { + for &align in &[4, 8, 16, 32] { + let layout_20 = Layout::from_size_align(20, align).unwrap(); + let layout_40 = Layout::from_size_align(40, 4 * align).unwrap(); + let layout_10 = Layout::from_size_align(10, align / 2).unwrap(); - for _ in 0..32 { - let a = allocator.allocate(layout_20).unwrap().as_non_null_ptr(); - assert_eq!(a.as_ptr() as usize % layout_20.align(), 0, "pointer is incorrectly aligned"); - allocator.deallocate(a, layout_20); - } + for _ in 0..32 { + let a = allocator.allocate(layout_20).unwrap().as_non_null_ptr(); + assert_eq!( + a.as_ptr() as usize % layout_20.align(), + 0, + "pointer is incorrectly aligned" + ); + allocator.deallocate(a, layout_20); + } - let p1 = allocator.allocate_zeroed(layout_20).unwrap().as_non_null_ptr(); - assert_eq!(p1.as_ptr() as usize % layout_20.align(), 0, "pointer is incorrectly aligned"); - assert_eq!(*p1.as_ptr(), 0); + let p1 = allocator.allocate_zeroed(layout_20).unwrap().as_non_null_ptr(); + assert_eq!( + p1.as_ptr() as usize % layout_20.align(), + 0, + "pointer is incorrectly aligned" + ); + assert_eq!(*p1.as_ptr(), 0); - // old size < new size - let p2 = allocator.grow(p1, layout_20, layout_40).unwrap().as_non_null_ptr(); - assert_eq!(p2.as_ptr() as usize % layout_40.align(), 0, "pointer is incorrectly aligned"); - let slice = slice::from_raw_parts(p2.as_ptr(), 20); - assert_eq!(&slice, &[0_u8; 20]); + // old size < new size + let p2 = allocator.grow(p1, layout_20, layout_40).unwrap().as_non_null_ptr(); + assert_eq!( + p2.as_ptr() as usize % layout_40.align(), + 0, + "pointer is incorrectly aligned" + ); + let slice = slice::from_raw_parts(p2.as_ptr(), 20); + assert_eq!(&slice, &[0_u8; 20]); - // old size == new size - let p3 = allocator.grow(p2, layout_40, layout_40).unwrap().as_non_null_ptr(); - assert_eq!(p3.as_ptr() as usize % layout_40.align(), 0, "pointer is incorrectly aligned"); - let slice = slice::from_raw_parts(p3.as_ptr(), 20); - assert_eq!(&slice, &[0_u8; 20]); + // old size == new size + let p3 = allocator.grow(p2, layout_40, layout_40).unwrap().as_non_null_ptr(); + assert_eq!( + p3.as_ptr() as usize % layout_40.align(), + 0, + "pointer is incorrectly aligned" + ); + let slice = slice::from_raw_parts(p3.as_ptr(), 20); + assert_eq!(&slice, &[0_u8; 20]); - // old size > new size - let p4 = allocator.shrink(p3, layout_40, layout_10).unwrap().as_non_null_ptr(); - assert_eq!(p4.as_ptr() as usize % layout_10.align(), 0, "pointer is incorrectly aligned"); - let slice = slice::from_raw_parts(p4.as_ptr(), 10); - assert_eq!(&slice, &[0_u8; 10]); + // old size > new size + let p4 = allocator.shrink(p3, layout_40, layout_10).unwrap().as_non_null_ptr(); + assert_eq!( + p4.as_ptr() as usize % layout_10.align(), + 0, + "pointer is incorrectly aligned" + ); + let slice = slice::from_raw_parts(p4.as_ptr(), 10); + assert_eq!(&slice, &[0_u8; 10]); - allocator.deallocate(p4, layout_10); + allocator.deallocate(p4, layout_10); + } } -} } +} fn check_align_requests(allocator: T) { - for &size in &[2, 8, 64] { // size less than and bigger than alignment - for &align in &[4, 8, 16, 32] { // Be sure to cover less than and bigger than `MIN_ALIGN` for all architectures + for &size in &[2, 8, 64] { + // size less than and bigger than alignment + for &align in &[4, 8, 16, 32] { + // Be sure to cover less than and bigger than `MIN_ALIGN` for all architectures let iterations = 32; unsafe { - let pointers: Vec<_> = (0..iterations).map(|_| { - allocator.allocate(Layout::from_size_align(size, align).unwrap()).unwrap().as_non_null_ptr() - }).collect(); + let pointers: Vec<_> = (0..iterations) + .map(|_| { + allocator + .allocate(Layout::from_size_align(size, align).unwrap()) + .unwrap() + .as_non_null_ptr() + }) + .collect(); for &ptr in &pointers { - assert_eq!((ptr.as_ptr() as usize) % align, 0, - "Got a pointer less aligned than requested") + assert_eq!( + (ptr.as_ptr() as usize) % align, + 0, + "Got a pointer less aligned than requested" + ) } // Clean up. diff --git a/tests/pass/iter.rs b/tests/pass/iter.rs index 6192dd0d37e89..8ee03d1126413 100644 --- a/tests/pass/iter.rs +++ b/tests/pass/iter.rs @@ -1,5 +1,6 @@ fn iter_empty_and_zst() { - for _ in Vec::::new().iter() { // this iterates over a Unique::empty() + for _ in Vec::::new().iter() { + // this iterates over a Unique::empty() panic!("We should never be here."); } @@ -21,13 +22,13 @@ fn test_iterator_step_by_nth() { } fn iter_any() { - let f = |x: &u8| { 10u8 == *x }; + let f = |x: &u8| 10u8 == *x; f(&1u8); - let g = |(), x: &u8| { 10u8 == *x }; + let g = |(), x: &u8| 10u8 == *x; g((), &1u8); - let h = |(), (), x: &u8| { 10u8 == *x }; + let h = |(), (), x: &u8| 10u8 == *x; h((), (), &1u8); [1, 2, 3u8].iter().any(|elt| 10 == *elt); From ba23d37b70253be905349aaeb0781eb6eba05333 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Tue, 21 Jun 2022 22:57:06 -0700 Subject: [PATCH 3293/3747] Format tests with rustfmt (288-299 of 299) --- .../fail/unaligned_pointers/dyn_alignment.rs | 7 +- .../unaligned_pointers/reference_to_packed.rs | 8 +- .../fail/unaligned_pointers/unaligned_ptr1.rs | 3 +- .../fail/unaligned_pointers/unaligned_ptr3.rs | 3 +- .../fail/unaligned_pointers/unaligned_ptr4.rs | 3 +- .../unaligned_ptr_addr_of.rs | 3 +- .../unaligned_pointers/unaligned_ptr_zst.rs | 3 +- tests/pass/intrinsics-integer.rs | 316 +++++++++++------- tests/pass/panic/catch_panic.rs | 41 ++- tests/pass/ptr_int_casts.rs | 22 +- .../regions-lifetime-nonfree-late-bound.rs | 14 +- tests/pass/sums.rs | 9 +- 12 files changed, 273 insertions(+), 159 deletions(-) diff --git a/tests/fail/unaligned_pointers/dyn_alignment.rs b/tests/fail/unaligned_pointers/dyn_alignment.rs index 91d9ec475b1fe..39dd6f9e4c079 100644 --- a/tests/fail/unaligned_pointers/dyn_alignment.rs +++ b/tests/fail/unaligned_pointers/dyn_alignment.rs @@ -6,7 +6,8 @@ struct MuchAlign; fn main() { - for _ in 0..10 { // Try many times as this might work by chance. + for _ in 0..10 { + // Try many times as this might work by chance. let buf = [0u32; 256]; // `buf` is sufficiently aligned for `layout.align` on a `dyn Debug`, but not // for the actual alignment required by `MuchAlign`. @@ -14,7 +15,9 @@ fn main() { // as the reference is not aligned to its dynamic alignment requirements. let mut ptr = &MuchAlign as &dyn std::fmt::Debug; // Overwrite the data part of `ptr` so it points to `buf`. - unsafe { (&mut ptr as *mut _ as *mut *const u8).write(&buf as *const _ as *const u8); } + unsafe { + (&mut ptr as *mut _ as *mut *const u8).write(&buf as *const _ as *const u8); + } // Re-borrow that. This should be UB. let _ptr = &*ptr; //~ERROR alignment 256 is required } diff --git a/tests/fail/unaligned_pointers/reference_to_packed.rs b/tests/fail/unaligned_pointers/reference_to_packed.rs index b376859d22c11..74b2f308e2301 100644 --- a/tests/fail/unaligned_pointers/reference_to_packed.rs +++ b/tests/fail/unaligned_pointers/reference_to_packed.rs @@ -10,11 +10,9 @@ struct Foo { } fn main() { - for _ in 0..10 { // Try many times as this might work by chance. - let foo = Foo { - x: 42, - y: 99, - }; + for _ in 0..10 { + // Try many times as this might work by chance. + let foo = Foo { x: 42, y: 99 }; let p = &foo.x; let i = *p; //~ERROR alignment 4 is required } diff --git a/tests/fail/unaligned_pointers/unaligned_ptr1.rs b/tests/fail/unaligned_pointers/unaligned_ptr1.rs index 1d72e5170b7c2..445eb051ae2d1 100644 --- a/tests/fail/unaligned_pointers/unaligned_ptr1.rs +++ b/tests/fail/unaligned_pointers/unaligned_ptr1.rs @@ -2,7 +2,8 @@ // compile-flags: -Zmiri-disable-validation -Zmiri-disable-stacked-borrows fn main() { - for _ in 0..10 { // Try many times as this might work by chance. + for _ in 0..10 { + // Try many times as this might work by chance. let x = [2u16, 3, 4]; // Make it big enough so we don't get an out-of-bounds error. let x = &x[0] as *const _ as *const u32; // This must fail because alignment is violated: the allocation's base is not sufficiently aligned. diff --git a/tests/fail/unaligned_pointers/unaligned_ptr3.rs b/tests/fail/unaligned_pointers/unaligned_ptr3.rs index ecab83b05a09f..f13ae48886753 100644 --- a/tests/fail/unaligned_pointers/unaligned_ptr3.rs +++ b/tests/fail/unaligned_pointers/unaligned_ptr3.rs @@ -2,7 +2,8 @@ // compile-flags: -Zmiri-disable-validation -Zmiri-disable-stacked-borrows fn main() { - for _ in 0..10 { // Try many times as this might work by chance. + for _ in 0..10 { + // Try many times as this might work by chance. let x = [2u16, 3, 4, 5]; // Make it big enough so we don't get an out-of-bounds error. let x = &x[0] as *const _ as *const *const u8; // cast to ptr-to-ptr, so that we load a ptr // This must fail because alignment is violated. Test specifically for loading pointers, diff --git a/tests/fail/unaligned_pointers/unaligned_ptr4.rs b/tests/fail/unaligned_pointers/unaligned_ptr4.rs index 10766746bd42d..18ae48b0a1e50 100644 --- a/tests/fail/unaligned_pointers/unaligned_ptr4.rs +++ b/tests/fail/unaligned_pointers/unaligned_ptr4.rs @@ -4,7 +4,8 @@ fn main() { // Make sure we notice when a u16 is loaded at offset 1 into a u8 allocation. // (This would be missed if u8 allocations are *always* at odd addresses.) - for _ in 0..10 { // Try many times as this might work by chance. + for _ in 0..10 { + // Try many times as this might work by chance. let x = [0u8; 4]; let ptr = x.as_ptr().wrapping_offset(1).cast::(); let _val = unsafe { *ptr }; //~ERROR but alignment diff --git a/tests/fail/unaligned_pointers/unaligned_ptr_addr_of.rs b/tests/fail/unaligned_pointers/unaligned_ptr_addr_of.rs index e33f3c8598f33..0604a7eb2d2b1 100644 --- a/tests/fail/unaligned_pointers/unaligned_ptr_addr_of.rs +++ b/tests/fail/unaligned_pointers/unaligned_ptr_addr_of.rs @@ -3,7 +3,8 @@ use std::ptr; fn main() { - for _ in 0..10 { // Try many times as this might work by chance. + for _ in 0..10 { + // Try many times as this might work by chance. let x = [2u16, 3, 4]; // Make it big enough so we don't get an out-of-bounds error. let x = &x[0] as *const _ as *const u32; // This must fail because alignment is violated: the allocation's base is not sufficiently aligned. diff --git a/tests/fail/unaligned_pointers/unaligned_ptr_zst.rs b/tests/fail/unaligned_pointers/unaligned_ptr_zst.rs index 27403c11abc74..983939688f1ba 100644 --- a/tests/fail/unaligned_pointers/unaligned_ptr_zst.rs +++ b/tests/fail/unaligned_pointers/unaligned_ptr_zst.rs @@ -3,7 +3,8 @@ // compile-flags: -Zmir-opt-level=0 -Zmiri-disable-validation fn main() { - for i in 0..10 { // Try many times as this might work by chance. + for i in 0..10 { + // Try many times as this might work by chance. let x = i as u8; let x = &x as *const _ as *const [u32; 0]; // This must fail because alignment is violated. Test specifically for loading ZST. diff --git a/tests/pass/intrinsics-integer.rs b/tests/pass/intrinsics-integer.rs index af3517af6f7a0..e8a3056f2c342 100644 --- a/tests/pass/intrinsics-integer.rs +++ b/tests/pass/intrinsics-integer.rs @@ -13,110 +13,194 @@ use std::intrinsics::*; pub fn main() { unsafe { - assert_eq!(ctpop(0u8), 0); assert_eq!(ctpop(0i8), 0); - assert_eq!(ctpop(0u16), 0); assert_eq!(ctpop(0i16), 0); - assert_eq!(ctpop(0u32), 0); assert_eq!(ctpop(0i32), 0); - assert_eq!(ctpop(0u64), 0); assert_eq!(ctpop(0i64), 0); - - assert_eq!(ctpop(1u8), 1); assert_eq!(ctpop(1i8), 1); - assert_eq!(ctpop(1u16), 1); assert_eq!(ctpop(1i16), 1); - assert_eq!(ctpop(1u32), 1); assert_eq!(ctpop(1i32), 1); - assert_eq!(ctpop(1u64), 1); assert_eq!(ctpop(1i64), 1); - - assert_eq!(ctpop(10u8), 2); assert_eq!(ctpop(10i8), 2); - assert_eq!(ctpop(10u16), 2); assert_eq!(ctpop(10i16), 2); - assert_eq!(ctpop(10u32), 2); assert_eq!(ctpop(10i32), 2); - assert_eq!(ctpop(10u64), 2); assert_eq!(ctpop(10i64), 2); - - assert_eq!(ctpop(100u8), 3); assert_eq!(ctpop(100i8), 3); - assert_eq!(ctpop(100u16), 3); assert_eq!(ctpop(100i16), 3); - assert_eq!(ctpop(100u32), 3); assert_eq!(ctpop(100i32), 3); - assert_eq!(ctpop(100u64), 3); assert_eq!(ctpop(100i64), 3); - - assert_eq!(ctpop(-1i8 as u8), 8); assert_eq!(ctpop(-1i8), 8); - assert_eq!(ctpop(-1i16 as u16), 16); assert_eq!(ctpop(-1i16), 16); - assert_eq!(ctpop(-1i32 as u32), 32); assert_eq!(ctpop(-1i32), 32); - assert_eq!(ctpop(-1i64 as u64), 64); assert_eq!(ctpop(-1i64), 64); - - assert_eq!(ctlz(0u8), 8); assert_eq!(ctlz(0i8), 8); - assert_eq!(ctlz(0u16), 16); assert_eq!(ctlz(0i16), 16); - assert_eq!(ctlz(0u32), 32); assert_eq!(ctlz(0i32), 32); - assert_eq!(ctlz(0u64), 64); assert_eq!(ctlz(0i64), 64); - - assert_eq!(ctlz(1u8), 7); assert_eq!(ctlz(1i8), 7); - assert_eq!(ctlz(1u16), 15); assert_eq!(ctlz(1i16), 15); - assert_eq!(ctlz(1u32), 31); assert_eq!(ctlz(1i32), 31); - assert_eq!(ctlz(1u64), 63); assert_eq!(ctlz(1i64), 63); - - assert_eq!(ctlz(10u8), 4); assert_eq!(ctlz(10i8), 4); - assert_eq!(ctlz(10u16), 12); assert_eq!(ctlz(10i16), 12); - assert_eq!(ctlz(10u32), 28); assert_eq!(ctlz(10i32), 28); - assert_eq!(ctlz(10u64), 60); assert_eq!(ctlz(10i64), 60); - - assert_eq!(ctlz(100u8), 1); assert_eq!(ctlz(100i8), 1); - assert_eq!(ctlz(100u16), 9); assert_eq!(ctlz(100i16), 9); - assert_eq!(ctlz(100u32), 25); assert_eq!(ctlz(100i32), 25); - assert_eq!(ctlz(100u64), 57); assert_eq!(ctlz(100i64), 57); - - assert_eq!(ctlz_nonzero(1u8), 7); assert_eq!(ctlz_nonzero(1i8), 7); - assert_eq!(ctlz_nonzero(1u16), 15); assert_eq!(ctlz_nonzero(1i16), 15); - assert_eq!(ctlz_nonzero(1u32), 31); assert_eq!(ctlz_nonzero(1i32), 31); - assert_eq!(ctlz_nonzero(1u64), 63); assert_eq!(ctlz_nonzero(1i64), 63); - - assert_eq!(ctlz_nonzero(10u8), 4); assert_eq!(ctlz_nonzero(10i8), 4); - assert_eq!(ctlz_nonzero(10u16), 12); assert_eq!(ctlz_nonzero(10i16), 12); - assert_eq!(ctlz_nonzero(10u32), 28); assert_eq!(ctlz_nonzero(10i32), 28); - assert_eq!(ctlz_nonzero(10u64), 60); assert_eq!(ctlz_nonzero(10i64), 60); - - assert_eq!(ctlz_nonzero(100u8), 1); assert_eq!(ctlz_nonzero(100i8), 1); - assert_eq!(ctlz_nonzero(100u16), 9); assert_eq!(ctlz_nonzero(100i16), 9); - assert_eq!(ctlz_nonzero(100u32), 25); assert_eq!(ctlz_nonzero(100i32), 25); - assert_eq!(ctlz_nonzero(100u64), 57); assert_eq!(ctlz_nonzero(100i64), 57); - - assert_eq!(cttz(-1i8 as u8), 0); assert_eq!(cttz(-1i8), 0); - assert_eq!(cttz(-1i16 as u16), 0); assert_eq!(cttz(-1i16), 0); - assert_eq!(cttz(-1i32 as u32), 0); assert_eq!(cttz(-1i32), 0); - assert_eq!(cttz(-1i64 as u64), 0); assert_eq!(cttz(-1i64), 0); - - assert_eq!(cttz(0u8), 8); assert_eq!(cttz(0i8), 8); - assert_eq!(cttz(0u16), 16); assert_eq!(cttz(0i16), 16); - assert_eq!(cttz(0u32), 32); assert_eq!(cttz(0i32), 32); - assert_eq!(cttz(0u64), 64); assert_eq!(cttz(0i64), 64); - - assert_eq!(cttz(1u8), 0); assert_eq!(cttz(1i8), 0); - assert_eq!(cttz(1u16), 0); assert_eq!(cttz(1i16), 0); - assert_eq!(cttz(1u32), 0); assert_eq!(cttz(1i32), 0); - assert_eq!(cttz(1u64), 0); assert_eq!(cttz(1i64), 0); - - assert_eq!(cttz(10u8), 1); assert_eq!(cttz(10i8), 1); - assert_eq!(cttz(10u16), 1); assert_eq!(cttz(10i16), 1); - assert_eq!(cttz(10u32), 1); assert_eq!(cttz(10i32), 1); - assert_eq!(cttz(10u64), 1); assert_eq!(cttz(10i64), 1); - - assert_eq!(cttz(100u8), 2); assert_eq!(cttz(100i8), 2); - assert_eq!(cttz(100u16), 2); assert_eq!(cttz(100i16), 2); - assert_eq!(cttz(100u32), 2); assert_eq!(cttz(100i32), 2); - assert_eq!(cttz(100u64), 2); assert_eq!(cttz(100i64), 2); - - assert_eq!(cttz_nonzero(-1i8 as u8), 0); assert_eq!(cttz_nonzero(-1i8), 0); - assert_eq!(cttz_nonzero(-1i16 as u16), 0); assert_eq!(cttz_nonzero(-1i16), 0); - assert_eq!(cttz_nonzero(-1i32 as u32), 0); assert_eq!(cttz_nonzero(-1i32), 0); - assert_eq!(cttz_nonzero(-1i64 as u64), 0); assert_eq!(cttz_nonzero(-1i64), 0); - - assert_eq!(cttz_nonzero(1u8), 0); assert_eq!(cttz_nonzero(1i8), 0); - assert_eq!(cttz_nonzero(1u16), 0); assert_eq!(cttz_nonzero(1i16), 0); - assert_eq!(cttz_nonzero(1u32), 0); assert_eq!(cttz_nonzero(1i32), 0); - assert_eq!(cttz_nonzero(1u64), 0); assert_eq!(cttz_nonzero(1i64), 0); - - assert_eq!(cttz_nonzero(10u8), 1); assert_eq!(cttz_nonzero(10i8), 1); - assert_eq!(cttz_nonzero(10u16), 1); assert_eq!(cttz_nonzero(10i16), 1); - assert_eq!(cttz_nonzero(10u32), 1); assert_eq!(cttz_nonzero(10i32), 1); - assert_eq!(cttz_nonzero(10u64), 1); assert_eq!(cttz_nonzero(10i64), 1); - - assert_eq!(cttz_nonzero(100u8), 2); assert_eq!(cttz_nonzero(100i8), 2); - assert_eq!(cttz_nonzero(100u16), 2); assert_eq!(cttz_nonzero(100i16), 2); - assert_eq!(cttz_nonzero(100u32), 2); assert_eq!(cttz_nonzero(100i32), 2); - assert_eq!(cttz_nonzero(100u64), 2); assert_eq!(cttz_nonzero(100i64), 2); + assert_eq!(ctpop(0u8), 0); + assert_eq!(ctpop(0i8), 0); + assert_eq!(ctpop(0u16), 0); + assert_eq!(ctpop(0i16), 0); + assert_eq!(ctpop(0u32), 0); + assert_eq!(ctpop(0i32), 0); + assert_eq!(ctpop(0u64), 0); + assert_eq!(ctpop(0i64), 0); + + assert_eq!(ctpop(1u8), 1); + assert_eq!(ctpop(1i8), 1); + assert_eq!(ctpop(1u16), 1); + assert_eq!(ctpop(1i16), 1); + assert_eq!(ctpop(1u32), 1); + assert_eq!(ctpop(1i32), 1); + assert_eq!(ctpop(1u64), 1); + assert_eq!(ctpop(1i64), 1); + + assert_eq!(ctpop(10u8), 2); + assert_eq!(ctpop(10i8), 2); + assert_eq!(ctpop(10u16), 2); + assert_eq!(ctpop(10i16), 2); + assert_eq!(ctpop(10u32), 2); + assert_eq!(ctpop(10i32), 2); + assert_eq!(ctpop(10u64), 2); + assert_eq!(ctpop(10i64), 2); + + assert_eq!(ctpop(100u8), 3); + assert_eq!(ctpop(100i8), 3); + assert_eq!(ctpop(100u16), 3); + assert_eq!(ctpop(100i16), 3); + assert_eq!(ctpop(100u32), 3); + assert_eq!(ctpop(100i32), 3); + assert_eq!(ctpop(100u64), 3); + assert_eq!(ctpop(100i64), 3); + + assert_eq!(ctpop(-1i8 as u8), 8); + assert_eq!(ctpop(-1i8), 8); + assert_eq!(ctpop(-1i16 as u16), 16); + assert_eq!(ctpop(-1i16), 16); + assert_eq!(ctpop(-1i32 as u32), 32); + assert_eq!(ctpop(-1i32), 32); + assert_eq!(ctpop(-1i64 as u64), 64); + assert_eq!(ctpop(-1i64), 64); + + assert_eq!(ctlz(0u8), 8); + assert_eq!(ctlz(0i8), 8); + assert_eq!(ctlz(0u16), 16); + assert_eq!(ctlz(0i16), 16); + assert_eq!(ctlz(0u32), 32); + assert_eq!(ctlz(0i32), 32); + assert_eq!(ctlz(0u64), 64); + assert_eq!(ctlz(0i64), 64); + + assert_eq!(ctlz(1u8), 7); + assert_eq!(ctlz(1i8), 7); + assert_eq!(ctlz(1u16), 15); + assert_eq!(ctlz(1i16), 15); + assert_eq!(ctlz(1u32), 31); + assert_eq!(ctlz(1i32), 31); + assert_eq!(ctlz(1u64), 63); + assert_eq!(ctlz(1i64), 63); + + assert_eq!(ctlz(10u8), 4); + assert_eq!(ctlz(10i8), 4); + assert_eq!(ctlz(10u16), 12); + assert_eq!(ctlz(10i16), 12); + assert_eq!(ctlz(10u32), 28); + assert_eq!(ctlz(10i32), 28); + assert_eq!(ctlz(10u64), 60); + assert_eq!(ctlz(10i64), 60); + + assert_eq!(ctlz(100u8), 1); + assert_eq!(ctlz(100i8), 1); + assert_eq!(ctlz(100u16), 9); + assert_eq!(ctlz(100i16), 9); + assert_eq!(ctlz(100u32), 25); + assert_eq!(ctlz(100i32), 25); + assert_eq!(ctlz(100u64), 57); + assert_eq!(ctlz(100i64), 57); + + assert_eq!(ctlz_nonzero(1u8), 7); + assert_eq!(ctlz_nonzero(1i8), 7); + assert_eq!(ctlz_nonzero(1u16), 15); + assert_eq!(ctlz_nonzero(1i16), 15); + assert_eq!(ctlz_nonzero(1u32), 31); + assert_eq!(ctlz_nonzero(1i32), 31); + assert_eq!(ctlz_nonzero(1u64), 63); + assert_eq!(ctlz_nonzero(1i64), 63); + + assert_eq!(ctlz_nonzero(10u8), 4); + assert_eq!(ctlz_nonzero(10i8), 4); + assert_eq!(ctlz_nonzero(10u16), 12); + assert_eq!(ctlz_nonzero(10i16), 12); + assert_eq!(ctlz_nonzero(10u32), 28); + assert_eq!(ctlz_nonzero(10i32), 28); + assert_eq!(ctlz_nonzero(10u64), 60); + assert_eq!(ctlz_nonzero(10i64), 60); + + assert_eq!(ctlz_nonzero(100u8), 1); + assert_eq!(ctlz_nonzero(100i8), 1); + assert_eq!(ctlz_nonzero(100u16), 9); + assert_eq!(ctlz_nonzero(100i16), 9); + assert_eq!(ctlz_nonzero(100u32), 25); + assert_eq!(ctlz_nonzero(100i32), 25); + assert_eq!(ctlz_nonzero(100u64), 57); + assert_eq!(ctlz_nonzero(100i64), 57); + + assert_eq!(cttz(-1i8 as u8), 0); + assert_eq!(cttz(-1i8), 0); + assert_eq!(cttz(-1i16 as u16), 0); + assert_eq!(cttz(-1i16), 0); + assert_eq!(cttz(-1i32 as u32), 0); + assert_eq!(cttz(-1i32), 0); + assert_eq!(cttz(-1i64 as u64), 0); + assert_eq!(cttz(-1i64), 0); + + assert_eq!(cttz(0u8), 8); + assert_eq!(cttz(0i8), 8); + assert_eq!(cttz(0u16), 16); + assert_eq!(cttz(0i16), 16); + assert_eq!(cttz(0u32), 32); + assert_eq!(cttz(0i32), 32); + assert_eq!(cttz(0u64), 64); + assert_eq!(cttz(0i64), 64); + + assert_eq!(cttz(1u8), 0); + assert_eq!(cttz(1i8), 0); + assert_eq!(cttz(1u16), 0); + assert_eq!(cttz(1i16), 0); + assert_eq!(cttz(1u32), 0); + assert_eq!(cttz(1i32), 0); + assert_eq!(cttz(1u64), 0); + assert_eq!(cttz(1i64), 0); + + assert_eq!(cttz(10u8), 1); + assert_eq!(cttz(10i8), 1); + assert_eq!(cttz(10u16), 1); + assert_eq!(cttz(10i16), 1); + assert_eq!(cttz(10u32), 1); + assert_eq!(cttz(10i32), 1); + assert_eq!(cttz(10u64), 1); + assert_eq!(cttz(10i64), 1); + + assert_eq!(cttz(100u8), 2); + assert_eq!(cttz(100i8), 2); + assert_eq!(cttz(100u16), 2); + assert_eq!(cttz(100i16), 2); + assert_eq!(cttz(100u32), 2); + assert_eq!(cttz(100i32), 2); + assert_eq!(cttz(100u64), 2); + assert_eq!(cttz(100i64), 2); + + assert_eq!(cttz_nonzero(-1i8 as u8), 0); + assert_eq!(cttz_nonzero(-1i8), 0); + assert_eq!(cttz_nonzero(-1i16 as u16), 0); + assert_eq!(cttz_nonzero(-1i16), 0); + assert_eq!(cttz_nonzero(-1i32 as u32), 0); + assert_eq!(cttz_nonzero(-1i32), 0); + assert_eq!(cttz_nonzero(-1i64 as u64), 0); + assert_eq!(cttz_nonzero(-1i64), 0); + + assert_eq!(cttz_nonzero(1u8), 0); + assert_eq!(cttz_nonzero(1i8), 0); + assert_eq!(cttz_nonzero(1u16), 0); + assert_eq!(cttz_nonzero(1i16), 0); + assert_eq!(cttz_nonzero(1u32), 0); + assert_eq!(cttz_nonzero(1i32), 0); + assert_eq!(cttz_nonzero(1u64), 0); + assert_eq!(cttz_nonzero(1i64), 0); + + assert_eq!(cttz_nonzero(10u8), 1); + assert_eq!(cttz_nonzero(10i8), 1); + assert_eq!(cttz_nonzero(10u16), 1); + assert_eq!(cttz_nonzero(10i16), 1); + assert_eq!(cttz_nonzero(10u32), 1); + assert_eq!(cttz_nonzero(10i32), 1); + assert_eq!(cttz_nonzero(10u64), 1); + assert_eq!(cttz_nonzero(10i64), 1); + + assert_eq!(cttz_nonzero(100u8), 2); + assert_eq!(cttz_nonzero(100i8), 2); + assert_eq!(cttz_nonzero(100u16), 2); + assert_eq!(cttz_nonzero(100i16), 2); + assert_eq!(cttz_nonzero(100u32), 2); + assert_eq!(cttz_nonzero(100i32), 2); + assert_eq!(cttz_nonzero(100u64), 2); + assert_eq!(cttz_nonzero(100i64), 2); assert_eq!(bswap(0x0Au8), 0x0A); // no-op assert_eq!(bswap(0x0Ai8), 0x0A); // no-op @@ -127,20 +211,20 @@ pub fn main() { assert_eq!(bswap(0x0122334455667708u64), 0x0877665544332201); assert_eq!(bswap(0x0122334455667708i64), 0x0877665544332201); - assert_eq!(exact_div(9*9u32, 3), 27); - assert_eq!(exact_div(-9*9i32, 3), -27); - assert_eq!(exact_div(9*9i8, -3), -27); - assert_eq!(exact_div(-9*9i64, -3), 27); + assert_eq!(exact_div(9 * 9u32, 3), 27); + assert_eq!(exact_div(-9 * 9i32, 3), -27); + assert_eq!(exact_div(9 * 9i8, -3), -27); + assert_eq!(exact_div(-9 * 9i64, -3), 27); - assert_eq!(unchecked_div(9*9u32, 2), 40); - assert_eq!(unchecked_div(-9*9i32, 2), -40); - assert_eq!(unchecked_div(9*9i8, -2), -40); - assert_eq!(unchecked_div(-9*9i64, -2), 40); + assert_eq!(unchecked_div(9 * 9u32, 2), 40); + assert_eq!(unchecked_div(-9 * 9i32, 2), -40); + assert_eq!(unchecked_div(9 * 9i8, -2), -40); + assert_eq!(unchecked_div(-9 * 9i64, -2), 40); - assert_eq!(unchecked_rem(9*9u32, 2), 1); - assert_eq!(unchecked_rem(-9*9i32, 2), -1); - assert_eq!(unchecked_rem(9*9i8, -2), 1); - assert_eq!(unchecked_rem(-9*9i64, -2), -1); + assert_eq!(unchecked_rem(9 * 9u32, 2), 1); + assert_eq!(unchecked_rem(-9 * 9i32, 2), -1); + assert_eq!(unchecked_rem(9 * 9i8, -2), 1); + assert_eq!(unchecked_rem(-9 * 9i64, -2), -1); assert_eq!(unchecked_add(23u8, 19), 42); assert_eq!(unchecked_add(5, -10), -5); diff --git a/tests/pass/panic/catch_panic.rs b/tests/pass/panic/catch_panic.rs index 80881948c03c8..2fb00391cd795 100644 --- a/tests/pass/panic/catch_panic.rs +++ b/tests/pass/panic/catch_panic.rs @@ -3,8 +3,8 @@ #![feature(never_type)] #![allow(unconditional_panic, non_fmt_panics)] -use std::panic::{catch_unwind, AssertUnwindSafe}; use std::cell::Cell; +use std::panic::{catch_unwind, AssertUnwindSafe}; thread_local! { static MY_COUNTER: Cell = Cell::new(0); @@ -59,23 +59,29 @@ fn main() { test(None, |old_val| core::panic!("Hello from panic: {:?}", old_val)); // Built-in panics; also make sure the message is right. - test( - Some("index out of bounds: the len is 3 but the index is 4"), - |_old_val| { let _val = [0, 1, 2][4]; loop {} }, - ); - test( - Some("attempt to divide by zero"), - |_old_val| { let _val = 1/0; loop {} }, - ); - - test( - Some("align_offset: align is not a power-of-two"), - |_old_val| { (0usize as *const u8).align_offset(3); loop {} }, - ); + test(Some("index out of bounds: the len is 3 but the index is 4"), |_old_val| { + let _val = [0, 1, 2][4]; + loop {} + }); + test(Some("attempt to divide by zero"), |_old_val| { + let _val = 1 / 0; + loop {} + }); + + test(Some("align_offset: align is not a power-of-two"), |_old_val| { + (0usize as *const u8).align_offset(3); + loop {} + }); // Assertion and debug assertion - test(None, |_old_val| { assert!(false); loop {} }); - test(None, |_old_val| { debug_assert!(false); loop {} }); + test(None, |_old_val| { + assert!(false); + loop {} + }); + test(None, |_old_val| { + debug_assert!(false); + loop {} + }); eprintln!("Success!"); // Make sure we get this in stderr } @@ -89,7 +95,8 @@ fn test(expect_msg: Option<&str>, do_panic: impl FnOnce(usize) -> !) { let res = catch_unwind(AssertUnwindSafe(|| { let _string = "LEAKED FROM CLOSURE".to_string(); do_panic_counter(do_panic) - })).expect_err("do_panic() did not panic!"); + })) + .expect_err("do_panic() did not panic!"); // See if we can extract the panic message. let msg = if let Some(s) = res.downcast_ref::() { diff --git a/tests/pass/ptr_int_casts.rs b/tests/pass/ptr_int_casts.rs index b9815126a8c79..aa60fd0c81efd 100644 --- a/tests/pass/ptr_int_casts.rs +++ b/tests/pass/ptr_int_casts.rs @@ -5,12 +5,14 @@ fn eq_ref(x: &T, y: &T) -> bool { x as *const _ == y as *const _ } -fn f() -> i32 { 42 } +fn f() -> i32 { + 42 +} fn ptr_int_casts() { // int-ptr-int assert_eq!(1 as *const i32 as usize, 1); - assert_eq!((1 as *const i32).wrapping_offset(4) as usize, 1 + 4*4); + assert_eq!((1 as *const i32).wrapping_offset(4) as usize, 1 + 4 * 4); // negative overflowing wrapping_offset (going through memory because // this used to trigger an ICE on 32bit) @@ -18,7 +20,8 @@ fn ptr_int_casts() { *val = (1 as *const u8).wrapping_offset(-4); assert_eq!(*val as usize, usize::MAX - 2); - { // ptr-int-ptr + { + // ptr-int-ptr let x = 13; let mut y = &x as &_ as *const _ as usize; y += 13; @@ -27,13 +30,14 @@ fn ptr_int_casts() { assert!(eq_ref(&x, unsafe { &*y })); } - { // fnptr-int-fnptr - let x : fn() -> i32 = f; - let y : *mut u8 = unsafe { mem::transmute(x as fn() -> i32) }; + { + // fnptr-int-fnptr + let x: fn() -> i32 = f; + let y: *mut u8 = unsafe { mem::transmute(x as fn() -> i32) }; let mut y = y as usize; y += 13; y -= 13; - let x : fn() -> i32 = unsafe { mem::transmute(y as *mut u8) }; + let x: fn() -> i32 = unsafe { mem::transmute(y as *mut u8) }; assert_eq!(x(), 42); } @@ -51,13 +55,13 @@ fn ptr_int_ops() { // bit-operations, covered by alignment assert_eq!(x & 1, 0); assert_eq!(x & 0, 0); - assert_eq!(1 & (x+1), 1); + assert_eq!(1 & (x + 1), 1); let _y = !1 & x; let _y = !0 & x; let _y = x & !1; // remainder, covered by alignment assert_eq!(x % 2, 0); - assert_eq!((x+1) % 2, 1); + assert_eq!((x + 1) % 2, 1); // remainder with 1 is always 0 assert_eq!(x % 1, 0); } diff --git a/tests/pass/regions-lifetime-nonfree-late-bound.rs b/tests/pass/regions-lifetime-nonfree-late-bound.rs index 78aeea64814a7..c91ac36ed6b41 100644 --- a/tests/pass/regions-lifetime-nonfree-late-bound.rs +++ b/tests/pass/regions-lifetime-nonfree-late-bound.rs @@ -16,15 +16,23 @@ pub fn main() { fn explicit() { - fn test(_x: Option>) where F: FnMut(Box FnMut(&'a isize)>) {} + fn test(_x: Option>) + where + F: FnMut(Box FnMut(&'a isize)>), + { + } test(Some(box |_f: Box FnMut(&'a isize)>| {})); } // The code below is shorthand for the code above (and more likely // to represent what one encounters in practice). fn implicit() { - fn test(_x: Option>) where F: FnMut(Box) {} - test(Some(box |_f: Box| {})); + fn test(_x: Option>) + where + F: FnMut(Box), + { + } + test(Some(box |_f: Box| {})); } explicit(); diff --git a/tests/pass/sums.rs b/tests/pass/sums.rs index daeba060a78bf..84ff96942002b 100644 --- a/tests/pass/sums.rs +++ b/tests/pass/sums.rs @@ -1,12 +1,17 @@ #[derive(Debug, PartialEq)] -enum Unit { Unit(()) } // Force non-C-enum representation. +enum Unit { + Unit(()), +} // Force non-C-enum representation. fn return_unit() -> Unit { Unit::Unit(()) } #[derive(Debug, PartialEq)] -enum MyBool { False(()), True(()) } // Force non-C-enum representation. +enum MyBool { + False(()), + True(()), +} // Force non-C-enum representation. fn return_true() -> MyBool { MyBool::True(()) From 639f660dde9936368714a10a80a325a78a1b3a99 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Tue, 21 Jun 2022 23:03:34 -0700 Subject: [PATCH 3294/3747] Manual adjustments --- tests/fail/branchless-select-i128-pointer.rs | 2 +- tests/fail/data_race/dealloc_read_race1.rs | 7 +++-- tests/fail/data_race/dealloc_write_race1.rs | 3 +- .../fail/function_calls/check_callback_abi.rs | 2 +- .../exported_symbol_abi_mismatch.rs | 14 ++++++---- tests/fail/type-too-large.rs | 3 +- tests/fail/validity/invalid_char.rs | 2 +- tests/pass/0weak_memory_consistency.rs | 23 ++++++++------- tests/pass/concurrency/linux-futex.rs | 28 +++++++++---------- tests/pass/heap_allocator.rs | 21 +++++++------- tests/pass/iter.rs | 2 +- 11 files changed, 56 insertions(+), 51 deletions(-) diff --git a/tests/fail/branchless-select-i128-pointer.rs b/tests/fail/branchless-select-i128-pointer.rs index b0c9c0fd72821..7e1b969e02cf6 100644 --- a/tests/fail/branchless-select-i128-pointer.rs +++ b/tests/fail/branchless-select-i128-pointer.rs @@ -12,7 +12,7 @@ fn main() { // However, it drops provenance when transmuting to TwoPtrs, so this is UB. let val = unsafe { transmute::<_, &str>( - //~ERROR type validation failed: encountered a dangling reference + //~^ ERROR type validation failed: encountered a dangling reference !mask & transmute::<_, TwoPtrs>("false !") | mask & transmute::<_, TwoPtrs>("true !"), ) diff --git a/tests/fail/data_race/dealloc_read_race1.rs b/tests/fail/data_race/dealloc_read_race1.rs index 38bbd81f1e2fb..555700a75d3ae 100644 --- a/tests/fail/data_race/dealloc_read_race1.rs +++ b/tests/fail/data_race/dealloc_read_race1.rs @@ -18,14 +18,17 @@ pub fn main() { let ptr = EvilSend(pointer); unsafe { - let j1 = spawn(move || *ptr.0); + let j1 = spawn(move || { + let _val = *ptr.0; + }); let j2 = spawn(move || { __rust_dealloc( + //~^ ERROR Data race detected between Deallocate on Thread(id = 2) and Read on Thread(id = 1) ptr.0 as *mut _, std::mem::size_of::(), std::mem::align_of::(), - ); //~ ERROR Data race detected between Deallocate on Thread(id = 2) and Read on Thread(id = 1) + ); }); j1.join().unwrap(); diff --git a/tests/fail/data_race/dealloc_write_race1.rs b/tests/fail/data_race/dealloc_write_race1.rs index 1cfaeb2cb25a6..44078a044a7f8 100644 --- a/tests/fail/data_race/dealloc_write_race1.rs +++ b/tests/fail/data_race/dealloc_write_race1.rs @@ -23,10 +23,11 @@ pub fn main() { let j2 = spawn(move || { __rust_dealloc( + //~^ ERROR Data race detected between Deallocate on Thread(id = 2) and Write on Thread(id = 1) ptr.0 as *mut _, std::mem::size_of::(), std::mem::align_of::(), - ); //~ ERROR Data race detected between Deallocate on Thread(id = 2) and Write on Thread(id = 1) + ); }); j1.join().unwrap(); diff --git a/tests/fail/function_calls/check_callback_abi.rs b/tests/fail/function_calls/check_callback_abi.rs index f76839c34f208..0a5a2d48d2743 100644 --- a/tests/fail/function_calls/check_callback_abi.rs +++ b/tests/fail/function_calls/check_callback_abi.rs @@ -9,7 +9,7 @@ fn main() { // Make sure we check the ABI when Miri itself invokes a function // as part of a shim implementation. std::intrinsics::r#try( - //~ ERROR calling a function with ABI C using caller ABI Rust + //~^ ERROR calling a function with ABI C using caller ABI Rust std::mem::transmute::(try_fn), std::ptr::null_mut(), |_, _| unreachable!(), diff --git a/tests/fail/function_calls/exported_symbol_abi_mismatch.rs b/tests/fail/function_calls/exported_symbol_abi_mismatch.rs index 7e8fb2cffecbb..c337e1f29f16f 100644 --- a/tests/fail/function_calls/exported_symbol_abi_mismatch.rs +++ b/tests/fail/function_calls/exported_symbol_abi_mismatch.rs @@ -11,14 +11,14 @@ fn main() { #[cfg(fn_ptr)] unsafe { - std::mem::transmute::(foo)() + std::mem::transmute::(foo)(); + //[fn_ptr]~^ ERROR calling a function with calling convention Rust using calling convention C } - //[fn_ptr]~^ ERROR calling a function with calling convention Rust using calling convention C // `Instance` caching should not suppress ABI check. #[cfg(cache)] unsafe { - foo() + foo(); } { @@ -26,8 +26,10 @@ fn main() { extern "C" { fn foo(); } - unsafe { foo() } - //[no_cache]~^ ERROR calling a function with calling convention Rust using calling convention C - //[cache]~^^ ERROR calling a function with calling convention Rust using calling convention C + unsafe { + foo(); + //[no_cache]~^ ERROR calling a function with calling convention Rust using calling convention C + //[cache]~| ERROR calling a function with calling convention Rust using calling convention C + } } } diff --git a/tests/fail/type-too-large.rs b/tests/fail/type-too-large.rs index d9e19ed818763..08f7a49b0255c 100644 --- a/tests/fail/type-too-large.rs +++ b/tests/fail/type-too-large.rs @@ -1,5 +1,6 @@ // ignore-32bit fn main() { - let _fat: [u8; (1 << 61) + (1 << 31)] = [0; (1u64 << 61) as usize + (1u64 << 31) as usize]; //~ ERROR post-monomorphization error + let _fat: [u8; (1 << 61) + (1 << 31)]; + _fat = [0; (1u64 << 61) as usize + (1u64 << 31) as usize]; //~ ERROR post-monomorphization error } diff --git a/tests/fail/validity/invalid_char.rs b/tests/fail/validity/invalid_char.rs index a868dac8875df..80749fd7c7916 100644 --- a/tests/fail/validity/invalid_char.rs +++ b/tests/fail/validity/invalid_char.rs @@ -1,7 +1,7 @@ fn main() { assert!(std::char::from_u32(-1_i32 as u32).is_none()); let _val = match unsafe { std::mem::transmute::(-1) } { - //~ ERROR encountered 0xffffffff, but expected a valid unicode scalar value + //~^ ERROR encountered 0xffffffff, but expected a valid unicode scalar value 'a' => true, 'b' => false, _ => true, diff --git a/tests/pass/0weak_memory_consistency.rs b/tests/pass/0weak_memory_consistency.rs index ae8d281858c23..0f798d2b575e0 100644 --- a/tests/pass/0weak_memory_consistency.rs +++ b/tests/pass/0weak_memory_consistency.rs @@ -54,14 +54,14 @@ fn test_corr() { x.store(2, Relaxed); }); + #[rustfmt::skip] let j2 = spawn(move || { let r2 = x.load(Relaxed); // -------------------------------------+ y.store(1, Release); // ---------------------+ | r2 // | | }); // | | - // |synchronizes-with |happens-before - let j3 = spawn(move || { - // | | + #[rustfmt::skip] // |synchronizes-with |happens-before + let j3 = spawn(move || { // | | acquires_value(&y, 1); // <------------------+ | x.load(Relaxed) // <----------------------------------------------+ // The two reads on x are ordered by hb, so they cannot observe values @@ -81,18 +81,17 @@ fn test_wrc() { let x = static_atomic(0); let y = static_atomic(0); + #[rustfmt::skip] let j1 = spawn(move || { x.store(1, Release); // ---------------------+---------------------+ }); // | | - // |synchronizes-with | - let j2 = spawn(move || { - // | | + #[rustfmt::skip] // |synchronizes-with | + let j2 = spawn(move || { // | | acquires_value(&x, 1); // <------------------+ | y.store(1, Release); // ---------------------+ |happens-before }); // | | - // |synchronizes-with | - let j3 = spawn(move || { - // | | + #[rustfmt::skip] // |synchronizes-with | + let j3 = spawn(move || { // | | acquires_value(&y, 1); // <------------------+ | x.load(Relaxed) // <-----------------------------------------------+ }); @@ -110,13 +109,13 @@ fn test_message_passing() { let x = EvilSend(ptr); let y = static_atomic(0); + #[rustfmt::skip] let j1 = spawn(move || { unsafe { *x.0 = 1 }; // -----------------------------------------+ y.store(1, Release); // ---------------------+ | }); // | | - // |synchronizes-with | happens-before - let j2 = spawn(move || { - // | | + #[rustfmt::skip] // |synchronizes-with | happens-before + let j2 = spawn(move || { // | | acquires_value(&y, 1); // <------------------+ | unsafe { *x.0 } // <---------------------------------------------+ }); diff --git a/tests/pass/concurrency/linux-futex.rs b/tests/pass/concurrency/linux-futex.rs index 74fec411b4c99..2c60df1ee138a 100644 --- a/tests/pass/concurrency/linux-futex.rs +++ b/tests/pass/concurrency/linux-futex.rs @@ -16,7 +16,7 @@ fn wake_nobody() { // Wake 1 waiter. Expect zero waiters woken up, as nobody is waiting. unsafe { - assert_eq!(libc::syscall(libc::SYS_futex, &futex as *const i32, libc::FUTEX_WAKE, 1,), 0); + assert_eq!(libc::syscall(libc::SYS_futex, &futex as *const i32, libc::FUTEX_WAKE, 1), 0); } // Same, but without omitting the unused arguments. @@ -31,7 +31,7 @@ fn wake_nobody() { 0usize, 0, ), - 0 + 0, ); } } @@ -43,7 +43,7 @@ fn wake_dangling() { // Wake 1 waiter. Expect zero waiters woken up, as nobody is waiting. unsafe { - assert_eq!(libc::syscall(libc::SYS_futex, ptr, libc::FUTEX_WAKE, 1,), 0); + assert_eq!(libc::syscall(libc::SYS_futex, ptr, libc::FUTEX_WAKE, 1), 0); } } @@ -60,7 +60,7 @@ fn wait_wrong_val() { 456, ptr::null::(), ), - -1 + -1, ); assert_eq!(*libc::__errno_location(), libc::EAGAIN); } @@ -81,7 +81,7 @@ fn wait_timeout() { 123, &libc::timespec { tv_sec: 0, tv_nsec: 200_000_000 }, ), - -1 + -1, ); assert_eq!(*libc::__errno_location(), libc::ETIMEDOUT); } @@ -120,7 +120,7 @@ fn wait_absolute_timeout() { 0usize, u32::MAX, ), - -1 + -1, ); assert_eq!(*libc::__errno_location(), libc::ETIMEDOUT); } @@ -143,8 +143,8 @@ fn wait_wake() { libc::FUTEX_WAKE, 10, // Wake up at most 10 threads. ), - 1 - ); // Woken up one thread. + 1, // Woken up one thread. + ); } }); @@ -157,7 +157,7 @@ fn wait_wake() { 0, ptr::null::(), ), - 0 + 0, ); } @@ -183,8 +183,8 @@ fn wait_wake_bitset() { 0usize, 0b1001, // bitset ), - 0 - ); // Didn't match any thread. + 0, // Didn't match any thread. + ); } thread::sleep(Duration::from_millis(200)); unsafe { @@ -198,8 +198,8 @@ fn wait_wake_bitset() { 0usize, 0b0110, // bitset ), - 1 - ); // Woken up one thread. + 1, // Woken up one thread. + ); } }); @@ -214,7 +214,7 @@ fn wait_wake_bitset() { 0usize, 0b0100, // bitset ), - 0 + 0, ); } diff --git a/tests/pass/heap_allocator.rs b/tests/pass/heap_allocator.rs index a3ab5b21f0b3e..2c38dcb49f1ce 100644 --- a/tests/pass/heap_allocator.rs +++ b/tests/pass/heap_allocator.rs @@ -16,7 +16,7 @@ fn check_alloc(allocator: T) { assert_eq!( a.as_ptr() as usize % layout_20.align(), 0, - "pointer is incorrectly aligned" + "pointer is incorrectly aligned", ); allocator.deallocate(a, layout_20); } @@ -25,7 +25,7 @@ fn check_alloc(allocator: T) { assert_eq!( p1.as_ptr() as usize % layout_20.align(), 0, - "pointer is incorrectly aligned" + "pointer is incorrectly aligned", ); assert_eq!(*p1.as_ptr(), 0); @@ -34,7 +34,7 @@ fn check_alloc(allocator: T) { assert_eq!( p2.as_ptr() as usize % layout_40.align(), 0, - "pointer is incorrectly aligned" + "pointer is incorrectly aligned", ); let slice = slice::from_raw_parts(p2.as_ptr(), 20); assert_eq!(&slice, &[0_u8; 20]); @@ -44,7 +44,7 @@ fn check_alloc(allocator: T) { assert_eq!( p3.as_ptr() as usize % layout_40.align(), 0, - "pointer is incorrectly aligned" + "pointer is incorrectly aligned", ); let slice = slice::from_raw_parts(p3.as_ptr(), 20); assert_eq!(&slice, &[0_u8; 20]); @@ -54,7 +54,7 @@ fn check_alloc(allocator: T) { assert_eq!( p4.as_ptr() as usize % layout_10.align(), 0, - "pointer is incorrectly aligned" + "pointer is incorrectly aligned", ); let slice = slice::from_raw_parts(p4.as_ptr(), 10); assert_eq!(&slice, &[0_u8; 10]); @@ -65,10 +65,9 @@ fn check_alloc(allocator: T) { } fn check_align_requests(allocator: T) { - for &size in &[2, 8, 64] { - // size less than and bigger than alignment - for &align in &[4, 8, 16, 32] { - // Be sure to cover less than and bigger than `MIN_ALIGN` for all architectures + #[rustfmt::skip] // https://github.com/rust-lang/rustfmt/issues/3255 + for &size in &[2, 8, 64] { // size less than and bigger than alignment + for &align in &[4, 8, 16, 32] { // Be sure to cover less than and bigger than `MIN_ALIGN` for all architectures let iterations = 32; unsafe { let pointers: Vec<_> = (0..iterations) @@ -83,7 +82,7 @@ fn check_align_requests(allocator: T) { assert_eq!( (ptr.as_ptr() as usize) % align, 0, - "Got a pointer less aligned than requested" + "Got a pointer less aligned than requested", ) } @@ -93,7 +92,7 @@ fn check_align_requests(allocator: T) { } } } - } + }; } fn global_to_box() { diff --git a/tests/pass/iter.rs b/tests/pass/iter.rs index 8ee03d1126413..31d0d7442d9d2 100644 --- a/tests/pass/iter.rs +++ b/tests/pass/iter.rs @@ -1,6 +1,6 @@ fn iter_empty_and_zst() { + // Iterate over a Unique::empty() for _ in Vec::::new().iter() { - // this iterates over a Unique::empty() panic!("We should never be here."); } From 05893d90269c6cbea4428b570bcfd09c1cb7c063 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Tue, 21 Jun 2022 23:21:37 -0700 Subject: [PATCH 3295/3747] Bless stderr files after rustfmt --- tests/fail/branchless-select-i128-pointer.stderr | 4 +++- tests/fail/data_race/dealloc_read_race1.stderr | 9 +++++++-- tests/fail/data_race/dealloc_write_race1.stderr | 9 +++++++-- tests/fail/function_calls/check_callback_abi.stderr | 1 + .../exported_symbol_abi_mismatch.cache.stderr | 4 ++-- .../exported_symbol_abi_mismatch.fn_ptr.stderr | 4 ++-- .../exported_symbol_abi_mismatch.no_cache.stderr | 4 ++-- tests/fail/type-too-large.stderr | 4 ++-- 8 files changed, 26 insertions(+), 13 deletions(-) diff --git a/tests/fail/branchless-select-i128-pointer.stderr b/tests/fail/branchless-select-i128-pointer.stderr index f37dcf955e331..374d6ab068091 100644 --- a/tests/fail/branchless-select-i128-pointer.stderr +++ b/tests/fail/branchless-select-i128-pointer.stderr @@ -2,7 +2,9 @@ error: Undefined Behavior: type validation failed: encountered a dangling refere --> $DIR/branchless-select-i128-pointer.rs:LL:CC | LL | / transmute::<_, &str>( -LL | | !mask & transmute::<_, TwoPtrs>("false !") | mask & transmute::<_, TwoPtrs>("true !"), +LL | | +LL | | !mask & transmute::<_, TwoPtrs>("false !") +LL | | | mask & transmute::<_, TwoPtrs>("true !"), LL | | ) | |_____________^ type validation failed: encountered a dangling reference (address $HEX is unallocated) | diff --git a/tests/fail/data_race/dealloc_read_race1.stderr b/tests/fail/data_race/dealloc_read_race1.stderr index 6b5cf5fc02f64..91a681e744505 100644 --- a/tests/fail/data_race/dealloc_read_race1.stderr +++ b/tests/fail/data_race/dealloc_read_race1.stderr @@ -1,8 +1,13 @@ error: Undefined Behavior: Data race detected between Deallocate on Thread(id = 2) and Read on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) --> $DIR/dealloc_read_race1.rs:LL:CC | -LL | __rust_dealloc(ptr.0 as *mut _, std::mem::size_of::(), std::mem::align_of::()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Data race detected between Deallocate on Thread(id = 2) and Read on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) +LL | / __rust_dealloc( +LL | | +LL | | ptr.0 as *mut _, +LL | | std::mem::size_of::(), +LL | | std::mem::align_of::(), +LL | | ); + | |_____________^ Data race detected between Deallocate on Thread(id = 2) and Read on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/data_race/dealloc_write_race1.stderr b/tests/fail/data_race/dealloc_write_race1.stderr index ac9701d49f5f7..dc1a6ed267c6b 100644 --- a/tests/fail/data_race/dealloc_write_race1.stderr +++ b/tests/fail/data_race/dealloc_write_race1.stderr @@ -1,8 +1,13 @@ error: Undefined Behavior: Data race detected between Deallocate on Thread(id = 2) and Write on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) --> $DIR/dealloc_write_race1.rs:LL:CC | -LL | __rust_dealloc(ptr.0 as *mut _, std::mem::size_of::(), std::mem::align_of::()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Data race detected between Deallocate on Thread(id = 2) and Write on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) +LL | / __rust_dealloc( +LL | | +LL | | ptr.0 as *mut _, +LL | | std::mem::size_of::(), +LL | | std::mem::align_of::(), +LL | | ); + | |_____________^ Data race detected between Deallocate on Thread(id = 2) and Write on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/function_calls/check_callback_abi.stderr b/tests/fail/function_calls/check_callback_abi.stderr index ea7c2bb6b4ae4..56314e6d28593 100644 --- a/tests/fail/function_calls/check_callback_abi.stderr +++ b/tests/fail/function_calls/check_callback_abi.stderr @@ -2,6 +2,7 @@ error: Undefined Behavior: calling a function with ABI C using caller ABI Rust --> $DIR/check_callback_abi.rs:LL:CC | LL | / std::intrinsics::r#try( +LL | | LL | | std::mem::transmute::(try_fn), LL | | std::ptr::null_mut(), LL | | |_, _| unreachable!(), diff --git a/tests/fail/function_calls/exported_symbol_abi_mismatch.cache.stderr b/tests/fail/function_calls/exported_symbol_abi_mismatch.cache.stderr index bf0d27d91576a..dee7f66e0ad9c 100644 --- a/tests/fail/function_calls/exported_symbol_abi_mismatch.cache.stderr +++ b/tests/fail/function_calls/exported_symbol_abi_mismatch.cache.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: calling a function with calling convention Rust using calling convention C --> $DIR/exported_symbol_abi_mismatch.rs:LL:CC | -LL | unsafe { foo() } - | ^^^^^ calling a function with calling convention Rust using calling convention C +LL | foo(); + | ^^^^^ calling a function with calling convention Rust using calling convention C | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/function_calls/exported_symbol_abi_mismatch.fn_ptr.stderr b/tests/fail/function_calls/exported_symbol_abi_mismatch.fn_ptr.stderr index ee810af315fc0..ebe19796609cf 100644 --- a/tests/fail/function_calls/exported_symbol_abi_mismatch.fn_ptr.stderr +++ b/tests/fail/function_calls/exported_symbol_abi_mismatch.fn_ptr.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: calling a function with calling convention Rust using calling convention C --> $DIR/exported_symbol_abi_mismatch.rs:LL:CC | -LL | unsafe { std::mem::transmute::(foo)() } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ calling a function with calling convention Rust using calling convention C +LL | std::mem::transmute::(foo)(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ calling a function with calling convention Rust using calling convention C | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/function_calls/exported_symbol_abi_mismatch.no_cache.stderr b/tests/fail/function_calls/exported_symbol_abi_mismatch.no_cache.stderr index bf0d27d91576a..dee7f66e0ad9c 100644 --- a/tests/fail/function_calls/exported_symbol_abi_mismatch.no_cache.stderr +++ b/tests/fail/function_calls/exported_symbol_abi_mismatch.no_cache.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: calling a function with calling convention Rust using calling convention C --> $DIR/exported_symbol_abi_mismatch.rs:LL:CC | -LL | unsafe { foo() } - | ^^^^^ calling a function with calling convention Rust using calling convention C +LL | foo(); + | ^^^^^ calling a function with calling convention Rust using calling convention C | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/type-too-large.stderr b/tests/fail/type-too-large.stderr index 3d555da40cc3e..cb1d725ec878c 100644 --- a/tests/fail/type-too-large.stderr +++ b/tests/fail/type-too-large.stderr @@ -1,8 +1,8 @@ error: post-monomorphization error: values of the type `[u8; 2305843011361177600]` are too big for the current architecture --> $DIR/type-too-large.rs:LL:CC | -LL | [0; (1u64<<61) as usize +(1u64<<31) as usize]; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ values of the type `[u8; 2305843011361177600]` are too big for the current architecture +LL | _fat = [0; (1u64 << 61) as usize + (1u64 << 31) as usize]; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ values of the type `[u8; 2305843011361177600]` are too big for the current architecture | = note: inside `main` at $DIR/type-too-large.rs:LL:CC From 274085cebdbbe01522818c0b1e5f1f00af97ed9d Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Tue, 21 Jun 2022 23:48:09 -0700 Subject: [PATCH 3296/3747] Manual adjustments --- .../fail/unaligned_pointers/dyn_alignment.rs | 2 +- .../unaligned_pointers/reference_to_packed.rs | 2 +- .../fail/unaligned_pointers/unaligned_ptr1.rs | 2 +- .../fail/unaligned_pointers/unaligned_ptr3.rs | 2 +- .../fail/unaligned_pointers/unaligned_ptr4.rs | 3 +- .../unaligned_ptr_addr_of.rs | 2 +- .../unaligned_pointers/unaligned_ptr_zst.rs | 2 +- tests/pass/intrinsics-integer.rs | 292 +++++++----------- tests/pass/ptr_int_casts.rs | 4 +- tests/pass/sums.rs | 8 +- 10 files changed, 118 insertions(+), 201 deletions(-) diff --git a/tests/fail/unaligned_pointers/dyn_alignment.rs b/tests/fail/unaligned_pointers/dyn_alignment.rs index 39dd6f9e4c079..730dd87cbb10f 100644 --- a/tests/fail/unaligned_pointers/dyn_alignment.rs +++ b/tests/fail/unaligned_pointers/dyn_alignment.rs @@ -6,8 +6,8 @@ struct MuchAlign; fn main() { + // Try many times as this might work by chance. for _ in 0..10 { - // Try many times as this might work by chance. let buf = [0u32; 256]; // `buf` is sufficiently aligned for `layout.align` on a `dyn Debug`, but not // for the actual alignment required by `MuchAlign`. diff --git a/tests/fail/unaligned_pointers/reference_to_packed.rs b/tests/fail/unaligned_pointers/reference_to_packed.rs index 74b2f308e2301..c42f0e27aeada 100644 --- a/tests/fail/unaligned_pointers/reference_to_packed.rs +++ b/tests/fail/unaligned_pointers/reference_to_packed.rs @@ -10,8 +10,8 @@ struct Foo { } fn main() { + // Try many times as this might work by chance. for _ in 0..10 { - // Try many times as this might work by chance. let foo = Foo { x: 42, y: 99 }; let p = &foo.x; let i = *p; //~ERROR alignment 4 is required diff --git a/tests/fail/unaligned_pointers/unaligned_ptr1.rs b/tests/fail/unaligned_pointers/unaligned_ptr1.rs index 445eb051ae2d1..7d192e5d3928b 100644 --- a/tests/fail/unaligned_pointers/unaligned_ptr1.rs +++ b/tests/fail/unaligned_pointers/unaligned_ptr1.rs @@ -2,8 +2,8 @@ // compile-flags: -Zmiri-disable-validation -Zmiri-disable-stacked-borrows fn main() { + // Try many times as this might work by chance. for _ in 0..10 { - // Try many times as this might work by chance. let x = [2u16, 3, 4]; // Make it big enough so we don't get an out-of-bounds error. let x = &x[0] as *const _ as *const u32; // This must fail because alignment is violated: the allocation's base is not sufficiently aligned. diff --git a/tests/fail/unaligned_pointers/unaligned_ptr3.rs b/tests/fail/unaligned_pointers/unaligned_ptr3.rs index f13ae48886753..748a31681a780 100644 --- a/tests/fail/unaligned_pointers/unaligned_ptr3.rs +++ b/tests/fail/unaligned_pointers/unaligned_ptr3.rs @@ -2,8 +2,8 @@ // compile-flags: -Zmiri-disable-validation -Zmiri-disable-stacked-borrows fn main() { + // Try many times as this might work by chance. for _ in 0..10 { - // Try many times as this might work by chance. let x = [2u16, 3, 4, 5]; // Make it big enough so we don't get an out-of-bounds error. let x = &x[0] as *const _ as *const *const u8; // cast to ptr-to-ptr, so that we load a ptr // This must fail because alignment is violated. Test specifically for loading pointers, diff --git a/tests/fail/unaligned_pointers/unaligned_ptr4.rs b/tests/fail/unaligned_pointers/unaligned_ptr4.rs index 18ae48b0a1e50..d01cabfa31cc8 100644 --- a/tests/fail/unaligned_pointers/unaligned_ptr4.rs +++ b/tests/fail/unaligned_pointers/unaligned_ptr4.rs @@ -4,8 +4,9 @@ fn main() { // Make sure we notice when a u16 is loaded at offset 1 into a u8 allocation. // (This would be missed if u8 allocations are *always* at odd addresses.) + // + // Try many times as this might work by chance. for _ in 0..10 { - // Try many times as this might work by chance. let x = [0u8; 4]; let ptr = x.as_ptr().wrapping_offset(1).cast::(); let _val = unsafe { *ptr }; //~ERROR but alignment diff --git a/tests/fail/unaligned_pointers/unaligned_ptr_addr_of.rs b/tests/fail/unaligned_pointers/unaligned_ptr_addr_of.rs index 0604a7eb2d2b1..dff92d56d70e8 100644 --- a/tests/fail/unaligned_pointers/unaligned_ptr_addr_of.rs +++ b/tests/fail/unaligned_pointers/unaligned_ptr_addr_of.rs @@ -3,8 +3,8 @@ use std::ptr; fn main() { + // Try many times as this might work by chance. for _ in 0..10 { - // Try many times as this might work by chance. let x = [2u16, 3, 4]; // Make it big enough so we don't get an out-of-bounds error. let x = &x[0] as *const _ as *const u32; // This must fail because alignment is violated: the allocation's base is not sufficiently aligned. diff --git a/tests/fail/unaligned_pointers/unaligned_ptr_zst.rs b/tests/fail/unaligned_pointers/unaligned_ptr_zst.rs index 983939688f1ba..8252ea83c870c 100644 --- a/tests/fail/unaligned_pointers/unaligned_ptr_zst.rs +++ b/tests/fail/unaligned_pointers/unaligned_ptr_zst.rs @@ -3,8 +3,8 @@ // compile-flags: -Zmir-opt-level=0 -Zmiri-disable-validation fn main() { + // Try many times as this might work by chance. for i in 0..10 { - // Try many times as this might work by chance. let x = i as u8; let x = &x as *const _ as *const [u32; 0]; // This must fail because alignment is violated. Test specifically for loading ZST. diff --git a/tests/pass/intrinsics-integer.rs b/tests/pass/intrinsics-integer.rs index e8a3056f2c342..546931f6ff875 100644 --- a/tests/pass/intrinsics-integer.rs +++ b/tests/pass/intrinsics-integer.rs @@ -13,194 +13,110 @@ use std::intrinsics::*; pub fn main() { unsafe { - assert_eq!(ctpop(0u8), 0); - assert_eq!(ctpop(0i8), 0); - assert_eq!(ctpop(0u16), 0); - assert_eq!(ctpop(0i16), 0); - assert_eq!(ctpop(0u32), 0); - assert_eq!(ctpop(0i32), 0); - assert_eq!(ctpop(0u64), 0); - assert_eq!(ctpop(0i64), 0); - - assert_eq!(ctpop(1u8), 1); - assert_eq!(ctpop(1i8), 1); - assert_eq!(ctpop(1u16), 1); - assert_eq!(ctpop(1i16), 1); - assert_eq!(ctpop(1u32), 1); - assert_eq!(ctpop(1i32), 1); - assert_eq!(ctpop(1u64), 1); - assert_eq!(ctpop(1i64), 1); - - assert_eq!(ctpop(10u8), 2); - assert_eq!(ctpop(10i8), 2); - assert_eq!(ctpop(10u16), 2); - assert_eq!(ctpop(10i16), 2); - assert_eq!(ctpop(10u32), 2); - assert_eq!(ctpop(10i32), 2); - assert_eq!(ctpop(10u64), 2); - assert_eq!(ctpop(10i64), 2); - - assert_eq!(ctpop(100u8), 3); - assert_eq!(ctpop(100i8), 3); - assert_eq!(ctpop(100u16), 3); - assert_eq!(ctpop(100i16), 3); - assert_eq!(ctpop(100u32), 3); - assert_eq!(ctpop(100i32), 3); - assert_eq!(ctpop(100u64), 3); - assert_eq!(ctpop(100i64), 3); - - assert_eq!(ctpop(-1i8 as u8), 8); - assert_eq!(ctpop(-1i8), 8); - assert_eq!(ctpop(-1i16 as u16), 16); - assert_eq!(ctpop(-1i16), 16); - assert_eq!(ctpop(-1i32 as u32), 32); - assert_eq!(ctpop(-1i32), 32); - assert_eq!(ctpop(-1i64 as u64), 64); - assert_eq!(ctpop(-1i64), 64); - - assert_eq!(ctlz(0u8), 8); - assert_eq!(ctlz(0i8), 8); - assert_eq!(ctlz(0u16), 16); - assert_eq!(ctlz(0i16), 16); - assert_eq!(ctlz(0u32), 32); - assert_eq!(ctlz(0i32), 32); - assert_eq!(ctlz(0u64), 64); - assert_eq!(ctlz(0i64), 64); - - assert_eq!(ctlz(1u8), 7); - assert_eq!(ctlz(1i8), 7); - assert_eq!(ctlz(1u16), 15); - assert_eq!(ctlz(1i16), 15); - assert_eq!(ctlz(1u32), 31); - assert_eq!(ctlz(1i32), 31); - assert_eq!(ctlz(1u64), 63); - assert_eq!(ctlz(1i64), 63); - - assert_eq!(ctlz(10u8), 4); - assert_eq!(ctlz(10i8), 4); - assert_eq!(ctlz(10u16), 12); - assert_eq!(ctlz(10i16), 12); - assert_eq!(ctlz(10u32), 28); - assert_eq!(ctlz(10i32), 28); - assert_eq!(ctlz(10u64), 60); - assert_eq!(ctlz(10i64), 60); - - assert_eq!(ctlz(100u8), 1); - assert_eq!(ctlz(100i8), 1); - assert_eq!(ctlz(100u16), 9); - assert_eq!(ctlz(100i16), 9); - assert_eq!(ctlz(100u32), 25); - assert_eq!(ctlz(100i32), 25); - assert_eq!(ctlz(100u64), 57); - assert_eq!(ctlz(100i64), 57); - - assert_eq!(ctlz_nonzero(1u8), 7); - assert_eq!(ctlz_nonzero(1i8), 7); - assert_eq!(ctlz_nonzero(1u16), 15); - assert_eq!(ctlz_nonzero(1i16), 15); - assert_eq!(ctlz_nonzero(1u32), 31); - assert_eq!(ctlz_nonzero(1i32), 31); - assert_eq!(ctlz_nonzero(1u64), 63); - assert_eq!(ctlz_nonzero(1i64), 63); - - assert_eq!(ctlz_nonzero(10u8), 4); - assert_eq!(ctlz_nonzero(10i8), 4); - assert_eq!(ctlz_nonzero(10u16), 12); - assert_eq!(ctlz_nonzero(10i16), 12); - assert_eq!(ctlz_nonzero(10u32), 28); - assert_eq!(ctlz_nonzero(10i32), 28); - assert_eq!(ctlz_nonzero(10u64), 60); - assert_eq!(ctlz_nonzero(10i64), 60); - - assert_eq!(ctlz_nonzero(100u8), 1); - assert_eq!(ctlz_nonzero(100i8), 1); - assert_eq!(ctlz_nonzero(100u16), 9); - assert_eq!(ctlz_nonzero(100i16), 9); - assert_eq!(ctlz_nonzero(100u32), 25); - assert_eq!(ctlz_nonzero(100i32), 25); - assert_eq!(ctlz_nonzero(100u64), 57); - assert_eq!(ctlz_nonzero(100i64), 57); - - assert_eq!(cttz(-1i8 as u8), 0); - assert_eq!(cttz(-1i8), 0); - assert_eq!(cttz(-1i16 as u16), 0); - assert_eq!(cttz(-1i16), 0); - assert_eq!(cttz(-1i32 as u32), 0); - assert_eq!(cttz(-1i32), 0); - assert_eq!(cttz(-1i64 as u64), 0); - assert_eq!(cttz(-1i64), 0); - - assert_eq!(cttz(0u8), 8); - assert_eq!(cttz(0i8), 8); - assert_eq!(cttz(0u16), 16); - assert_eq!(cttz(0i16), 16); - assert_eq!(cttz(0u32), 32); - assert_eq!(cttz(0i32), 32); - assert_eq!(cttz(0u64), 64); - assert_eq!(cttz(0i64), 64); - - assert_eq!(cttz(1u8), 0); - assert_eq!(cttz(1i8), 0); - assert_eq!(cttz(1u16), 0); - assert_eq!(cttz(1i16), 0); - assert_eq!(cttz(1u32), 0); - assert_eq!(cttz(1i32), 0); - assert_eq!(cttz(1u64), 0); - assert_eq!(cttz(1i64), 0); - - assert_eq!(cttz(10u8), 1); - assert_eq!(cttz(10i8), 1); - assert_eq!(cttz(10u16), 1); - assert_eq!(cttz(10i16), 1); - assert_eq!(cttz(10u32), 1); - assert_eq!(cttz(10i32), 1); - assert_eq!(cttz(10u64), 1); - assert_eq!(cttz(10i64), 1); - - assert_eq!(cttz(100u8), 2); - assert_eq!(cttz(100i8), 2); - assert_eq!(cttz(100u16), 2); - assert_eq!(cttz(100i16), 2); - assert_eq!(cttz(100u32), 2); - assert_eq!(cttz(100i32), 2); - assert_eq!(cttz(100u64), 2); - assert_eq!(cttz(100i64), 2); - - assert_eq!(cttz_nonzero(-1i8 as u8), 0); - assert_eq!(cttz_nonzero(-1i8), 0); - assert_eq!(cttz_nonzero(-1i16 as u16), 0); - assert_eq!(cttz_nonzero(-1i16), 0); - assert_eq!(cttz_nonzero(-1i32 as u32), 0); - assert_eq!(cttz_nonzero(-1i32), 0); - assert_eq!(cttz_nonzero(-1i64 as u64), 0); - assert_eq!(cttz_nonzero(-1i64), 0); - - assert_eq!(cttz_nonzero(1u8), 0); - assert_eq!(cttz_nonzero(1i8), 0); - assert_eq!(cttz_nonzero(1u16), 0); - assert_eq!(cttz_nonzero(1i16), 0); - assert_eq!(cttz_nonzero(1u32), 0); - assert_eq!(cttz_nonzero(1i32), 0); - assert_eq!(cttz_nonzero(1u64), 0); - assert_eq!(cttz_nonzero(1i64), 0); - - assert_eq!(cttz_nonzero(10u8), 1); - assert_eq!(cttz_nonzero(10i8), 1); - assert_eq!(cttz_nonzero(10u16), 1); - assert_eq!(cttz_nonzero(10i16), 1); - assert_eq!(cttz_nonzero(10u32), 1); - assert_eq!(cttz_nonzero(10i32), 1); - assert_eq!(cttz_nonzero(10u64), 1); - assert_eq!(cttz_nonzero(10i64), 1); - - assert_eq!(cttz_nonzero(100u8), 2); - assert_eq!(cttz_nonzero(100i8), 2); - assert_eq!(cttz_nonzero(100u16), 2); - assert_eq!(cttz_nonzero(100i16), 2); - assert_eq!(cttz_nonzero(100u32), 2); - assert_eq!(cttz_nonzero(100i32), 2); - assert_eq!(cttz_nonzero(100u64), 2); - assert_eq!(cttz_nonzero(100i64), 2); + [assert_eq!(ctpop(0u8), 0), assert_eq!(ctpop(0i8), 0)]; + [assert_eq!(ctpop(0u16), 0), assert_eq!(ctpop(0i16), 0)]; + [assert_eq!(ctpop(0u32), 0), assert_eq!(ctpop(0i32), 0)]; + [assert_eq!(ctpop(0u64), 0), assert_eq!(ctpop(0i64), 0)]; + + [assert_eq!(ctpop(1u8), 1), assert_eq!(ctpop(1i8), 1)]; + [assert_eq!(ctpop(1u16), 1), assert_eq!(ctpop(1i16), 1)]; + [assert_eq!(ctpop(1u32), 1), assert_eq!(ctpop(1i32), 1)]; + [assert_eq!(ctpop(1u64), 1), assert_eq!(ctpop(1i64), 1)]; + + [assert_eq!(ctpop(10u8), 2), assert_eq!(ctpop(10i8), 2)]; + [assert_eq!(ctpop(10u16), 2), assert_eq!(ctpop(10i16), 2)]; + [assert_eq!(ctpop(10u32), 2), assert_eq!(ctpop(10i32), 2)]; + [assert_eq!(ctpop(10u64), 2), assert_eq!(ctpop(10i64), 2)]; + + [assert_eq!(ctpop(100u8), 3), assert_eq!(ctpop(100i8), 3)]; + [assert_eq!(ctpop(100u16), 3), assert_eq!(ctpop(100i16), 3)]; + [assert_eq!(ctpop(100u32), 3), assert_eq!(ctpop(100i32), 3)]; + [assert_eq!(ctpop(100u64), 3), assert_eq!(ctpop(100i64), 3)]; + + [assert_eq!(ctpop(-1i8 as u8), 8), assert_eq!(ctpop(-1i8), 8)]; + [assert_eq!(ctpop(-1i16 as u16), 16), assert_eq!(ctpop(-1i16), 16)]; + [assert_eq!(ctpop(-1i32 as u32), 32), assert_eq!(ctpop(-1i32), 32)]; + [assert_eq!(ctpop(-1i64 as u64), 64), assert_eq!(ctpop(-1i64), 64)]; + + [assert_eq!(ctlz(0u8), 8), assert_eq!(ctlz(0i8), 8)]; + [assert_eq!(ctlz(0u16), 16), assert_eq!(ctlz(0i16), 16)]; + [assert_eq!(ctlz(0u32), 32), assert_eq!(ctlz(0i32), 32)]; + [assert_eq!(ctlz(0u64), 64), assert_eq!(ctlz(0i64), 64)]; + + [assert_eq!(ctlz(1u8), 7), assert_eq!(ctlz(1i8), 7)]; + [assert_eq!(ctlz(1u16), 15), assert_eq!(ctlz(1i16), 15)]; + [assert_eq!(ctlz(1u32), 31), assert_eq!(ctlz(1i32), 31)]; + [assert_eq!(ctlz(1u64), 63), assert_eq!(ctlz(1i64), 63)]; + + [assert_eq!(ctlz(10u8), 4), assert_eq!(ctlz(10i8), 4)]; + [assert_eq!(ctlz(10u16), 12), assert_eq!(ctlz(10i16), 12)]; + [assert_eq!(ctlz(10u32), 28), assert_eq!(ctlz(10i32), 28)]; + [assert_eq!(ctlz(10u64), 60), assert_eq!(ctlz(10i64), 60)]; + + [assert_eq!(ctlz(100u8), 1), assert_eq!(ctlz(100i8), 1)]; + [assert_eq!(ctlz(100u16), 9), assert_eq!(ctlz(100i16), 9)]; + [assert_eq!(ctlz(100u32), 25), assert_eq!(ctlz(100i32), 25)]; + [assert_eq!(ctlz(100u64), 57), assert_eq!(ctlz(100i64), 57)]; + + [assert_eq!(ctlz_nonzero(1u8), 7), assert_eq!(ctlz_nonzero(1i8), 7)]; + [assert_eq!(ctlz_nonzero(1u16), 15), assert_eq!(ctlz_nonzero(1i16), 15)]; + [assert_eq!(ctlz_nonzero(1u32), 31), assert_eq!(ctlz_nonzero(1i32), 31)]; + [assert_eq!(ctlz_nonzero(1u64), 63), assert_eq!(ctlz_nonzero(1i64), 63)]; + + [assert_eq!(ctlz_nonzero(10u8), 4), assert_eq!(ctlz_nonzero(10i8), 4)]; + [assert_eq!(ctlz_nonzero(10u16), 12), assert_eq!(ctlz_nonzero(10i16), 12)]; + [assert_eq!(ctlz_nonzero(10u32), 28), assert_eq!(ctlz_nonzero(10i32), 28)]; + [assert_eq!(ctlz_nonzero(10u64), 60), assert_eq!(ctlz_nonzero(10i64), 60)]; + + [assert_eq!(ctlz_nonzero(100u8), 1), assert_eq!(ctlz_nonzero(100i8), 1)]; + [assert_eq!(ctlz_nonzero(100u16), 9), assert_eq!(ctlz_nonzero(100i16), 9)]; + [assert_eq!(ctlz_nonzero(100u32), 25), assert_eq!(ctlz_nonzero(100i32), 25)]; + [assert_eq!(ctlz_nonzero(100u64), 57), assert_eq!(ctlz_nonzero(100i64), 57)]; + + [assert_eq!(cttz(-1i8 as u8), 0), assert_eq!(cttz(-1i8), 0)]; + [assert_eq!(cttz(-1i16 as u16), 0), assert_eq!(cttz(-1i16), 0)]; + [assert_eq!(cttz(-1i32 as u32), 0), assert_eq!(cttz(-1i32), 0)]; + [assert_eq!(cttz(-1i64 as u64), 0), assert_eq!(cttz(-1i64), 0)]; + + [assert_eq!(cttz(0u8), 8), assert_eq!(cttz(0i8), 8)]; + [assert_eq!(cttz(0u16), 16), assert_eq!(cttz(0i16), 16)]; + [assert_eq!(cttz(0u32), 32), assert_eq!(cttz(0i32), 32)]; + [assert_eq!(cttz(0u64), 64), assert_eq!(cttz(0i64), 64)]; + + [assert_eq!(cttz(1u8), 0), assert_eq!(cttz(1i8), 0)]; + [assert_eq!(cttz(1u16), 0), assert_eq!(cttz(1i16), 0)]; + [assert_eq!(cttz(1u32), 0), assert_eq!(cttz(1i32), 0)]; + [assert_eq!(cttz(1u64), 0), assert_eq!(cttz(1i64), 0)]; + + [assert_eq!(cttz(10u8), 1), assert_eq!(cttz(10i8), 1)]; + [assert_eq!(cttz(10u16), 1), assert_eq!(cttz(10i16), 1)]; + [assert_eq!(cttz(10u32), 1), assert_eq!(cttz(10i32), 1)]; + [assert_eq!(cttz(10u64), 1), assert_eq!(cttz(10i64), 1)]; + + [assert_eq!(cttz(100u8), 2), assert_eq!(cttz(100i8), 2)]; + [assert_eq!(cttz(100u16), 2), assert_eq!(cttz(100i16), 2)]; + [assert_eq!(cttz(100u32), 2), assert_eq!(cttz(100i32), 2)]; + [assert_eq!(cttz(100u64), 2), assert_eq!(cttz(100i64), 2)]; + + [assert_eq!(cttz_nonzero(-1i8 as u8), 0), assert_eq!(cttz_nonzero(-1i8), 0)]; + [assert_eq!(cttz_nonzero(-1i16 as u16), 0), assert_eq!(cttz_nonzero(-1i16), 0)]; + [assert_eq!(cttz_nonzero(-1i32 as u32), 0), assert_eq!(cttz_nonzero(-1i32), 0)]; + [assert_eq!(cttz_nonzero(-1i64 as u64), 0), assert_eq!(cttz_nonzero(-1i64), 0)]; + + [assert_eq!(cttz_nonzero(1u8), 0), assert_eq!(cttz_nonzero(1i8), 0)]; + [assert_eq!(cttz_nonzero(1u16), 0), assert_eq!(cttz_nonzero(1i16), 0)]; + [assert_eq!(cttz_nonzero(1u32), 0), assert_eq!(cttz_nonzero(1i32), 0)]; + [assert_eq!(cttz_nonzero(1u64), 0), assert_eq!(cttz_nonzero(1i64), 0)]; + + [assert_eq!(cttz_nonzero(10u8), 1), assert_eq!(cttz_nonzero(10i8), 1)]; + [assert_eq!(cttz_nonzero(10u16), 1), assert_eq!(cttz_nonzero(10i16), 1)]; + [assert_eq!(cttz_nonzero(10u32), 1), assert_eq!(cttz_nonzero(10i32), 1)]; + [assert_eq!(cttz_nonzero(10u64), 1), assert_eq!(cttz_nonzero(10i64), 1)]; + + [assert_eq!(cttz_nonzero(100u8), 2), assert_eq!(cttz_nonzero(100i8), 2)]; + [assert_eq!(cttz_nonzero(100u16), 2), assert_eq!(cttz_nonzero(100i16), 2)]; + [assert_eq!(cttz_nonzero(100u32), 2), assert_eq!(cttz_nonzero(100i32), 2)]; + [assert_eq!(cttz_nonzero(100u64), 2), assert_eq!(cttz_nonzero(100i64), 2)]; assert_eq!(bswap(0x0Au8), 0x0A); // no-op assert_eq!(bswap(0x0Ai8), 0x0A); // no-op diff --git a/tests/pass/ptr_int_casts.rs b/tests/pass/ptr_int_casts.rs index aa60fd0c81efd..889b6bd04f9d5 100644 --- a/tests/pass/ptr_int_casts.rs +++ b/tests/pass/ptr_int_casts.rs @@ -20,8 +20,8 @@ fn ptr_int_casts() { *val = (1 as *const u8).wrapping_offset(-4); assert_eq!(*val as usize, usize::MAX - 2); + // ptr-int-ptr { - // ptr-int-ptr let x = 13; let mut y = &x as &_ as *const _ as usize; y += 13; @@ -30,8 +30,8 @@ fn ptr_int_casts() { assert!(eq_ref(&x, unsafe { &*y })); } + // fnptr-int-fnptr { - // fnptr-int-fnptr let x: fn() -> i32 = f; let y: *mut u8 = unsafe { mem::transmute(x as fn() -> i32) }; let mut y = y as usize; diff --git a/tests/pass/sums.rs b/tests/pass/sums.rs index 84ff96942002b..3256d4c65116a 100644 --- a/tests/pass/sums.rs +++ b/tests/pass/sums.rs @@ -1,7 +1,7 @@ #[derive(Debug, PartialEq)] enum Unit { - Unit(()), -} // Force non-C-enum representation. + Unit(()), // Force non-C-enum representation. +} fn return_unit() -> Unit { Unit::Unit(()) @@ -9,9 +9,9 @@ fn return_unit() -> Unit { #[derive(Debug, PartialEq)] enum MyBool { - False(()), + False(()), // Force non-C-enum representation. True(()), -} // Force non-C-enum representation. +} fn return_true() -> MyBool { MyBool::True(()) From 599a0cf4fc0440ec391b6d1fc736bb68dd28028b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 22 Jun 2022 08:52:48 -0700 Subject: [PATCH 3297/3747] fmt --- ui_test/src/comments.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/ui_test/src/comments.rs b/ui_test/src/comments.rs index d50d6a5345739..43c687e9c9a50 100644 --- a/ui_test/src/comments.rs +++ b/ui_test/src/comments.rs @@ -31,7 +31,6 @@ pub(crate) struct Comments { pub error_matches: Vec, } - /// The conditions used for "ignore" and "only" filters. #[derive(Debug)] pub(crate) enum Condition { @@ -55,7 +54,9 @@ pub(crate) struct ErrorMatch { impl Condition { fn parse(c: &str) -> Self { if let Some(bits) = c.strip_suffix("bit") { - let bits: u8 = bits.parse().expect("ignore/only filter ending in 'bit' must be of the form 'Nbit' for some integer N"); + let bits: u8 = bits.parse().expect( + "ignore/only filter ending in 'bit' must be of the form 'Nbit' for some integer N", + ); Condition::Bitwidth(bits) } else { Condition::Target(c.to_owned()) From 0eb8e60ed0f4a83f955a0a2433aafd7b1b07b54c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 22 Jun 2022 10:02:33 -0700 Subject: [PATCH 3298/3747] avoid setting both RUSTC and RUSTC_WRAPPER --- cargo-miri/bin.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index 6a5e5dc3913ab..a7be5843d4e6a 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -638,6 +638,14 @@ fn phase_cargo_miri(mut args: env::Args) { ); } cmd.env("RUSTC_WRAPPER", &cargo_miri_path); + // Having both `RUSTC_WRAPPER` and `RUSTC` set does some odd things, so let's avoid that. + // See . + if env::var_os("RUSTC").is_some() && env::var_os("MIRI").is_none() { + println!( + "WARNING: Ignoring `RUSTC` environment variable; set `MIRI` if you want to control the binary used as the driver." + ); + } + cmd.env_remove("RUSTC"); let runner_env_name = |triple: &str| format!("CARGO_TARGET_{}_RUNNER", triple.to_uppercase().replace('-', "_")); From c4ffe680e3fdb2240d810a311327d1268681af1d Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Tue, 21 Jun 2022 16:30:45 +0000 Subject: [PATCH 3299/3747] Require local annotations for local diagnostics --- tests/fail/abort-terminator.rs | 3 +-- tests/fail/concurrency/too_few_args.rs | 3 +-- tests/fail/concurrency/too_many_args.rs | 3 +-- tests/fail/concurrency/unwind_top_of_stack.rs | 2 +- .../concurrency/unwind_top_of_stack.stderr | 1 + .../intrinsics/overflowing-unchecked-rsh.rs | 3 +-- .../intrinsics/uninit_uninhabited_type.rs | 2 +- tests/fail/intrinsics/zero_fn_ptr.rs | 3 +-- tests/fail/panic/bad_unwind.rs | 2 +- ...wlock_read_write_deadlock_single_thread.rs | 3 +-- ...wlock_write_read_deadlock_single_thread.rs | 3 +-- ...lock_write_write_deadlock_single_thread.rs | 3 +-- tests/fail/transmute_fat1.rs | 15 +++++++++------ tests/fail/transmute_fat1.stderr | 4 ++-- tests/fail/unaligned_pointers/alignment.rs | 12 ++++++------ .../fail/unaligned_pointers/alignment.stderr | 4 ++-- ui_test/src/lib.rs | 19 +------------------ ui_test/src/rustc_stderr.rs | 2 +- 18 files changed, 33 insertions(+), 54 deletions(-) diff --git a/tests/fail/abort-terminator.rs b/tests/fail/abort-terminator.rs index 20859047c620e..fcdeaa0ffea28 100644 --- a/tests/fail/abort-terminator.rs +++ b/tests/fail/abort-terminator.rs @@ -1,7 +1,6 @@ -// error-pattern: the program aborted #![feature(c_unwind)] -extern "C" fn panic_abort() { +extern "C" fn panic_abort() { //~ ERROR: the program aborted panic!() } diff --git a/tests/fail/concurrency/too_few_args.rs b/tests/fail/concurrency/too_few_args.rs index 35412353ace4a..23fa38d881288 100644 --- a/tests/fail/concurrency/too_few_args.rs +++ b/tests/fail/concurrency/too_few_args.rs @@ -1,5 +1,4 @@ // ignore-windows: Concurrency on Windows is not supported yet. -// error-pattern: callee has fewer arguments than expected //! The thread function must have exactly one argument. @@ -10,7 +9,7 @@ extern crate libc; use std::{mem, ptr}; extern "C" fn thread_start() -> *mut libc::c_void { - panic!() + panic!() //~ ERROR: callee has fewer arguments than expected } fn main() { diff --git a/tests/fail/concurrency/too_many_args.rs b/tests/fail/concurrency/too_many_args.rs index b6156091b0aaf..af5a377a04e4b 100644 --- a/tests/fail/concurrency/too_many_args.rs +++ b/tests/fail/concurrency/too_many_args.rs @@ -1,5 +1,4 @@ // ignore-windows: Concurrency on Windows is not supported yet. -// error-pattern: callee has more arguments than expected //! The thread function must have exactly one argument. @@ -10,7 +9,7 @@ extern crate libc; use std::{mem, ptr}; extern "C" fn thread_start(_null: *mut libc::c_void, _x: i32) -> *mut libc::c_void { - panic!() + panic!() //~ ERROR: callee has more arguments than expected } fn main() { diff --git a/tests/fail/concurrency/unwind_top_of_stack.rs b/tests/fail/concurrency/unwind_top_of_stack.rs index e1c17d07b286a..9e6088be7a7ee 100644 --- a/tests/fail/concurrency/unwind_top_of_stack.rs +++ b/tests/fail/concurrency/unwind_top_of_stack.rs @@ -1,6 +1,5 @@ // ignore-windows: Concurrency on Windows is not supported yet. // compile-flags: -Zmiri-disable-abi-check -// error-pattern: unwinding past the topmost frame of the stack //! Unwinding past the top frame of a stack is Undefined Behavior. @@ -11,6 +10,7 @@ extern crate libc; use std::{mem, ptr}; extern "C-unwind" fn thread_start(_null: *mut libc::c_void) -> *mut libc::c_void { +//~^ ERROR unwinding past the topmost frame of the stack panic!() } diff --git a/tests/fail/concurrency/unwind_top_of_stack.stderr b/tests/fail/concurrency/unwind_top_of_stack.stderr index 35d6f7c384940..f72f01a9d6e97 100644 --- a/tests/fail/concurrency/unwind_top_of_stack.stderr +++ b/tests/fail/concurrency/unwind_top_of_stack.stderr @@ -4,6 +4,7 @@ error: Undefined Behavior: unwinding past the topmost frame of the stack --> $DIR/unwind_top_of_stack.rs:LL:CC | LL | / extern "C-unwind" fn thread_start(_null: *mut libc::c_void) -> *mut libc::c_void { +LL | | LL | | panic!() LL | | } | |_^ unwinding past the topmost frame of the stack diff --git a/tests/fail/intrinsics/overflowing-unchecked-rsh.rs b/tests/fail/intrinsics/overflowing-unchecked-rsh.rs index 6402f4bb74c6a..958a9f90ed983 100644 --- a/tests/fail/intrinsics/overflowing-unchecked-rsh.rs +++ b/tests/fail/intrinsics/overflowing-unchecked-rsh.rs @@ -2,10 +2,9 @@ use std::intrinsics::*; -// error-pattern: overflowing shift by 64 in `unchecked_shr` - fn main() { unsafe { let _n = unchecked_shr(1i64, 64); + //~^ ERROR: overflowing shift by 64 in `unchecked_shr` } } diff --git a/tests/fail/intrinsics/uninit_uninhabited_type.rs b/tests/fail/intrinsics/uninit_uninhabited_type.rs index 2337ff0f6c26c..e606d8b283c8a 100644 --- a/tests/fail/intrinsics/uninit_uninhabited_type.rs +++ b/tests/fail/intrinsics/uninit_uninhabited_type.rs @@ -1,7 +1,7 @@ -// error-pattern: attempted to instantiate uninhabited type `!` #![feature(never_type)] #[allow(deprecated, invalid_value)] fn main() { unsafe { std::mem::uninitialized::() }; + //~^ ERROR: attempted to instantiate uninhabited type `!` } diff --git a/tests/fail/intrinsics/zero_fn_ptr.rs b/tests/fail/intrinsics/zero_fn_ptr.rs index 098a8e01347f3..6d9ae14c5c479 100644 --- a/tests/fail/intrinsics/zero_fn_ptr.rs +++ b/tests/fail/intrinsics/zero_fn_ptr.rs @@ -1,6 +1,5 @@ -// error-pattern: attempted to zero-initialize type `fn()`, which is invalid - #[allow(deprecated, invalid_value)] fn main() { unsafe { std::mem::zeroed::() }; + //~^ ERROR: attempted to zero-initialize type `fn()`, which is invalid } diff --git a/tests/fail/panic/bad_unwind.rs b/tests/fail/panic/bad_unwind.rs index 1feee9a12ae04..370b372a7d373 100644 --- a/tests/fail/panic/bad_unwind.rs +++ b/tests/fail/panic/bad_unwind.rs @@ -1,4 +1,3 @@ -// error-pattern: unwinding past a stack frame that does not allow unwinding #![feature(c_unwind)] //! Unwinding when the caller ABI is "C" (without "-unwind") is UB. @@ -11,4 +10,5 @@ fn main() { let unwind: extern "C-unwind" fn() = unwind; let unwind: extern "C" fn() = unsafe { std::mem::transmute(unwind) }; std::panic::catch_unwind(|| unwind()).unwrap_err(); + //~^ ERROR: unwinding past a stack frame that does not allow unwinding } diff --git a/tests/fail/sync/libc_pthread_rwlock_read_write_deadlock_single_thread.rs b/tests/fail/sync/libc_pthread_rwlock_read_write_deadlock_single_thread.rs index da45d062d03b8..dd4707d60e4ca 100644 --- a/tests/fail/sync/libc_pthread_rwlock_read_write_deadlock_single_thread.rs +++ b/tests/fail/sync/libc_pthread_rwlock_read_write_deadlock_single_thread.rs @@ -1,5 +1,4 @@ // ignore-windows: No libc on Windows -// error-pattern: deadlock #![feature(rustc_private)] @@ -9,6 +8,6 @@ fn main() { let rw = std::cell::UnsafeCell::new(libc::PTHREAD_RWLOCK_INITIALIZER); unsafe { assert_eq!(libc::pthread_rwlock_rdlock(rw.get()), 0); - libc::pthread_rwlock_wrlock(rw.get()); + libc::pthread_rwlock_wrlock(rw.get()); //~ ERROR: deadlock } } diff --git a/tests/fail/sync/libc_pthread_rwlock_write_read_deadlock_single_thread.rs b/tests/fail/sync/libc_pthread_rwlock_write_read_deadlock_single_thread.rs index ee2e57a9ab375..1b460e7174d28 100644 --- a/tests/fail/sync/libc_pthread_rwlock_write_read_deadlock_single_thread.rs +++ b/tests/fail/sync/libc_pthread_rwlock_write_read_deadlock_single_thread.rs @@ -1,5 +1,4 @@ // ignore-windows: No libc on Windows -// error-pattern: deadlock #![feature(rustc_private)] @@ -9,6 +8,6 @@ fn main() { let rw = std::cell::UnsafeCell::new(libc::PTHREAD_RWLOCK_INITIALIZER); unsafe { assert_eq!(libc::pthread_rwlock_wrlock(rw.get()), 0); - libc::pthread_rwlock_rdlock(rw.get()); + libc::pthread_rwlock_rdlock(rw.get()); //~ ERROR: deadlock } } diff --git a/tests/fail/sync/libc_pthread_rwlock_write_write_deadlock_single_thread.rs b/tests/fail/sync/libc_pthread_rwlock_write_write_deadlock_single_thread.rs index f0404f202e561..cc327ec46bc29 100644 --- a/tests/fail/sync/libc_pthread_rwlock_write_write_deadlock_single_thread.rs +++ b/tests/fail/sync/libc_pthread_rwlock_write_write_deadlock_single_thread.rs @@ -1,5 +1,4 @@ // ignore-windows: No libc on Windows -// error-pattern: deadlock #![feature(rustc_private)] @@ -9,6 +8,6 @@ fn main() { let rw = std::cell::UnsafeCell::new(libc::PTHREAD_RWLOCK_INITIALIZER); unsafe { assert_eq!(libc::pthread_rwlock_wrlock(rw.get()), 0); - libc::pthread_rwlock_wrlock(rw.get()); + libc::pthread_rwlock_wrlock(rw.get()); //~ ERROR: deadlock } } diff --git a/tests/fail/transmute_fat1.rs b/tests/fail/transmute_fat1.rs index f9fa2ace75700..79286f3e27dd8 100644 --- a/tests/fail/transmute_fat1.rs +++ b/tests/fail/transmute_fat1.rs @@ -1,10 +1,13 @@ -// error-pattern: type validation failed: encountered a pointer -// normalize-stderr-test: "\[u8; (08|16)\]" -> "$$ARRAY" +#[cfg(target_pointer_width = "64")] +const N: usize = 16; + +#[cfg(target_pointer_width = "32")] +const N: usize = 8; fn main() { - #[cfg(target_pointer_width = "64")] - let bad = unsafe { std::mem::transmute::<&[u8], [u8; 16]>(&[1u8]) }; - #[cfg(target_pointer_width = "32")] - let bad = unsafe { std::mem::transmute::<&[u8], [u8; 08]>(&[1u8]) }; + let bad = unsafe { + std::mem::transmute::<&[u8], [u8; N]>(&[1u8]) + //~^ ERROR: type validation failed: encountered a pointer + }; let _val = bad[0] + bad[bad.len() - 1]; } diff --git a/tests/fail/transmute_fat1.stderr b/tests/fail/transmute_fat1.stderr index 2b095dc3c1c02..baf6195f92ad9 100644 --- a/tests/fail/transmute_fat1.stderr +++ b/tests/fail/transmute_fat1.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: type validation failed: encountered a pointer, but expected plain (non-pointer) bytes --> $DIR/transmute_fat1.rs:LL:CC | -LL | let bad = unsafe { std::mem::transmute::<&[u8], $ARRAY>(&[1u8]) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected plain (non-pointer) bytes +LL | std::mem::transmute::<&[u8], [u8; N]>(&[1u8]) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected plain (non-pointer) bytes | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/unaligned_pointers/alignment.rs b/tests/fail/unaligned_pointers/alignment.rs index e99d8c967cddd..abee75ec71b17 100644 --- a/tests/fail/unaligned_pointers/alignment.rs +++ b/tests/fail/unaligned_pointers/alignment.rs @@ -1,14 +1,14 @@ -// error-pattern: but alignment 4 is required -// normalize-stderr-test: "\.add\(1\)" -> " " +// normalize-stderr-test: "\| +\^+" -> "| ^" fn main() { // No retry needed, this fails reliably. let mut x = [0u8; 20]; let x_ptr: *mut u8 = x.as_mut_ptr(); - // At least one of these is definitely unaligned. + #[rustfmt::skip] unsafe { - *(x_ptr as *mut u32) = 42; - *(x_ptr.add(1) as *mut u32) = 42; - } + // At least one of these is definitely unaligned. + *(x_ptr as *mut u32) = 42; *(x_ptr.add(1) as *mut u32) = 42; + //~^ ERROR: but alignment 4 is required + }; } diff --git a/tests/fail/unaligned_pointers/alignment.stderr b/tests/fail/unaligned_pointers/alignment.stderr index 0e6ca83366ad2..5f691d0490954 100644 --- a/tests/fail/unaligned_pointers/alignment.stderr +++ b/tests/fail/unaligned_pointers/alignment.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: accessing memory with alignment ALIGN, but alignment ALIGN is required --> $DIR/alignment.rs:LL:CC | -LL | *(x_ptr as *mut u32) = 42; - | ^^^^^^^^^^^^^^^^^^^^^^^^^ accessing memory with alignment ALIGN, but alignment ALIGN is required +LL | *(x_ptr as *mut u32) = 42; *(x_ptr.add(1) as *mut u32) = 42; + | ^ accessing memory with alignment ALIGN, but alignment ALIGN is required | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/ui_test/src/lib.rs b/ui_test/src/lib.rs index 9706221446806..30e1296f7b396 100644 --- a/ui_test/src/lib.rs +++ b/ui_test/src/lib.rs @@ -374,8 +374,6 @@ fn check_annotations( comments: &Comments, ) { if let Some((ref error_pattern, definition_line)) = comments.error_pattern { - let mut found = false; - // first check the diagnostics messages outside of our file. We check this first, so that // you can mix in-file annotations with // error-pattern annotations, even if there is overlap // in the messages. @@ -384,22 +382,7 @@ fn check_annotations( .position(|msg| msg.message.contains(error_pattern)) { messages_from_unknown_file_or_line.remove(i); - found = true; - } - - // if nothing was found, check the ones inside our file. We permit this because some tests may have - // flaky line numbers for their messages. - if !found { - for line in &mut messages { - if let Some(i) = line.iter().position(|msg| msg.message.contains(error_pattern)) { - line.remove(i); - found = true; - break; - } - } - } - - if !found { + } else { errors.push(Error::PatternNotFound { pattern: error_pattern.to_string(), definition_line, diff --git a/ui_test/src/rustc_stderr.rs b/ui_test/src/rustc_stderr.rs index 203014c50d52f..2d3845752e9a5 100644 --- a/ui_test/src/rustc_stderr.rs +++ b/ui_test/src/rustc_stderr.rs @@ -116,7 +116,7 @@ impl Span { } pub(crate) fn filter_annotations_from_rendered(rendered: &str) -> std::borrow::Cow<'_, str> { - let annotations = Regex::new(r"\s*//~.*").unwrap(); + let annotations = Regex::new(r"\s*//(\[[^\]]\])?~.*").unwrap(); annotations.replace_all(&rendered, "") } From e286090d7a66f0213aafdc90d5fbd856dd5c05b5 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 23 Jun 2022 13:57:27 -0400 Subject: [PATCH 3300/3747] make rustfmt mandatory and used pinned toolchain --- .github/workflows/ci.yml | 43 ++++++++++++++++------------------------ 1 file changed, 17 insertions(+), 26 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ee65d58dccada..85937a8e44458 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -86,8 +86,8 @@ jobs: - name: Test run: bash ./ci.sh - clippy: - name: clippy + rustdoc + style: + name: style checks runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 @@ -95,33 +95,24 @@ jobs: # We need a toolchain that can actually build Miri, just a nightly won't do. run: | cargo install rustup-toolchain-install-master # TODO: cache this? - ./rustup-toolchain "" -c clippy - - name: Clippy (miri) + ./rustup-toolchain "" -c clippy -c rustfmt + - name: rustfmt (miri, ui_test) + run: cargo fmt --all --check + - name: rustfmt (everything else) + # TODO: Add `tests` (work in progress). + # Maybe change to `find . -name '*.rs'`, superseding the previous step. + run: | + find bench-cargo-miri benches cargo-miri test-cargo-miri -name '*.rs' \ + | xargs rustfmt --edition=2021 --config-path ./rustfmt.toml --check + - name: clippy (miri) run: cargo clippy --all-targets -- -D warnings #- name: Clippy (ui_test) # run: cargo clippy --manifest-path ui_test/Cargo.toml --all-targets -- -D warnings - - name: Clippy (cargo-miri) + - name: clippy (cargo-miri) run: cargo clippy --manifest-path cargo-miri/Cargo.toml --all-targets -- -D warnings - - name: Rustdoc + - name: rustdoc run: RUSTDOCFLAGS="-Dwarnings" cargo doc --document-private-items - fmt: - name: formatting (ignored by bors) - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v3 - - name: Install latest nightly - run: | - rustup toolchain install nightly --component rustfmt - rustup override set nightly - - name: Formatting (miri, ui_test) - run: cargo fmt --all --check - - name: Formatting (everything else) - # TODO: Add `tests` (work in progress). - # Maybe change to `find . -name '*.rs'`, superseding the previous step. - run: find bench-cargo-miri benches cargo-miri test-cargo-miri -name '*.rs' - | xargs rustfmt --edition=2021 --config-path ./rustfmt.toml --check - # These jobs doesn't actually test anything, but they're only used to tell # bors the build completed, as there is no practical way to detect when a # workflow is successful listening to webhooks only. @@ -131,7 +122,7 @@ jobs: end-success: name: bors build finished runs-on: ubuntu-latest - needs: [build, clippy] + needs: [build, style] if: github.event.pusher.name == 'bors' && success() steps: - name: mark the job as a success @@ -139,7 +130,7 @@ jobs: end-failure: name: bors build finished runs-on: ubuntu-latest - needs: [build, clippy] + needs: [build, style] if: github.event.pusher.name == 'bors' && (failure() || cancelled()) steps: - name: mark the job as a failure @@ -149,7 +140,7 @@ jobs: cron-fail-notify: name: cronjob failure notification runs-on: ubuntu-latest - needs: [build, clippy] + needs: [build, style] if: github.event_name == 'schedule' && (failure() || cancelled()) steps: - name: Install zulip-send From 2cbc461389b27fdc50c06a4e551bdc5ee07c7076 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Wed, 22 Jun 2022 05:00:07 -0700 Subject: [PATCH 3301/3747] Add './miri fmt' and use it in CI --- .github/workflows/ci.yml | 12 +++--------- miri | 9 ++++++++- rustup-toolchain | 2 +- 3 files changed, 12 insertions(+), 11 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 85937a8e44458..45c0bea370ac4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -95,15 +95,9 @@ jobs: # We need a toolchain that can actually build Miri, just a nightly won't do. run: | cargo install rustup-toolchain-install-master # TODO: cache this? - ./rustup-toolchain "" -c clippy -c rustfmt - - name: rustfmt (miri, ui_test) - run: cargo fmt --all --check - - name: rustfmt (everything else) - # TODO: Add `tests` (work in progress). - # Maybe change to `find . -name '*.rs'`, superseding the previous step. - run: | - find bench-cargo-miri benches cargo-miri test-cargo-miri -name '*.rs' \ - | xargs rustfmt --edition=2021 --config-path ./rustfmt.toml --check + ./rustup-toolchain "" -c clippy + - name: rustfmt + run: ./miri fmt --check - name: clippy (miri) run: cargo clippy --all-targets -- -D warnings #- name: Clippy (ui_test) diff --git a/miri b/miri index 5c9cb81885c92..e89a9e380fff6 100755 --- a/miri +++ b/miri @@ -21,10 +21,13 @@ to the final `cargo test` invocation. ./miri run : Build miri, set up a sysroot and then run the driver with the given . -All commands also exist in a "-debug" variant (e.g. "./miri run-debug +The commands above also exist in a "-debug" variant (e.g. "./miri run-debug ") which uses debug builds instead of release builds, for faster build times and slower execution times. +./miri fmt : +Format all sources and tests. are passed to `rustfmt`. + ENVIRONMENT VARIABLES MIRI_SYSROOT: @@ -156,6 +159,10 @@ run|run-debug) # Then run the actual command. exec cargo run $CARGO_BUILD_FLAGS -- --sysroot "$MIRI_SYSROOT" "$@" ;; +fmt) + find "$MIRIDIR" -not \( -name target -prune \) -name '*.rs' \ + | xargs rustfmt --edition=2021 --config-path "$MIRIDIR/rustfmt.toml" "$@" + ;; *) if [ -n "$COMMAND" ]; then echo "Unknown command: $COMMAND" diff --git a/rustup-toolchain b/rustup-toolchain index ca5508e225a11..34472c727f62f 100755 --- a/rustup-toolchain +++ b/rustup-toolchain @@ -42,7 +42,7 @@ fi # Install and setup new toolchain. rustup toolchain uninstall miri -rustup-toolchain-install-master -n miri -c cargo -c rust-src -c rustc-dev -c llvm-tools "$@" -- "$NEW_COMMIT" +rustup-toolchain-install-master -n miri -c cargo -c rust-src -c rustc-dev -c llvm-tools -c rustfmt "$@" -- "$NEW_COMMIT" rustup override set miri # Cleanup. From a23eb46b5b5f104a3ffe66ae717d6c2563918a95 Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Thu, 23 Jun 2022 12:50:44 -0700 Subject: [PATCH 3302/3747] Format late arrivals with rustfmt --- tests/fail/abort-terminator.rs | 3 ++- tests/fail/concurrency/unwind_top_of_stack.rs | 2 +- tests/pass/concurrency/sync_nopreempt.rs | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/tests/fail/abort-terminator.rs b/tests/fail/abort-terminator.rs index fcdeaa0ffea28..195be4ca41f86 100644 --- a/tests/fail/abort-terminator.rs +++ b/tests/fail/abort-terminator.rs @@ -1,6 +1,7 @@ #![feature(c_unwind)] -extern "C" fn panic_abort() { //~ ERROR: the program aborted +extern "C" fn panic_abort() { + //~ ERROR: the program aborted panic!() } diff --git a/tests/fail/concurrency/unwind_top_of_stack.rs b/tests/fail/concurrency/unwind_top_of_stack.rs index 9e6088be7a7ee..39f7ae8bafb99 100644 --- a/tests/fail/concurrency/unwind_top_of_stack.rs +++ b/tests/fail/concurrency/unwind_top_of_stack.rs @@ -10,7 +10,7 @@ extern crate libc; use std::{mem, ptr}; extern "C-unwind" fn thread_start(_null: *mut libc::c_void) -> *mut libc::c_void { -//~^ ERROR unwinding past the topmost frame of the stack + //~^ ERROR unwinding past the topmost frame of the stack panic!() } diff --git a/tests/pass/concurrency/sync_nopreempt.rs b/tests/pass/concurrency/sync_nopreempt.rs index 38dbeb575d641..8895d62df95fe 100644 --- a/tests/pass/concurrency/sync_nopreempt.rs +++ b/tests/pass/concurrency/sync_nopreempt.rs @@ -2,7 +2,7 @@ // We are making scheduler assumptions here. // compile-flags: -Zmiri-strict-provenance -Zmiri-preemption-rate=0 -use std::sync::{Condvar, Mutex, Arc}; +use std::sync::{Arc, Condvar, Mutex}; use std::thread; fn check_conditional_variables_notify_all() { From 8833197a62522cb01f73d0a1074e9a0cfa6ac5da Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Thu, 23 Jun 2022 12:51:40 -0700 Subject: [PATCH 3303/3747] Manual adjustments --- tests/fail/abort-terminator.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/fail/abort-terminator.rs b/tests/fail/abort-terminator.rs index 195be4ca41f86..c954443a27629 100644 --- a/tests/fail/abort-terminator.rs +++ b/tests/fail/abort-terminator.rs @@ -1,7 +1,7 @@ #![feature(c_unwind)] extern "C" fn panic_abort() { - //~ ERROR: the program aborted + //~^ ERROR: the program aborted panic!() } From e5f40ca9cb8ed9412543df307ba5d20fedb51c8f Mon Sep 17 00:00:00 2001 From: David Tolnay Date: Thu, 23 Jun 2022 13:08:12 -0700 Subject: [PATCH 3304/3747] Bless stderr files after rustfmt --- tests/fail/abort-terminator.stderr | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/fail/abort-terminator.stderr b/tests/fail/abort-terminator.stderr index b096775e61d31..ec9ce76685b55 100644 --- a/tests/fail/abort-terminator.stderr +++ b/tests/fail/abort-terminator.stderr @@ -4,6 +4,7 @@ error: abnormal termination: the program aborted execution --> $DIR/abort-terminator.rs:LL:CC | LL | / extern "C" fn panic_abort() { +LL | | LL | | panic!() LL | | } | |_^ the program aborted execution From bb6fcb71c07a21d6655295de4ff0a130596d47f0 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 24 Jun 2022 09:13:36 -0400 Subject: [PATCH 3305/3747] only one Zulip cron job topic per month --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 45c0bea370ac4..c603d1f5d2549 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -145,7 +145,7 @@ jobs: ZULIP_BOT_EMAIL: ${{ secrets.ZULIP_BOT_EMAIL }} ZULIP_API_TOKEN: ${{ secrets.ZULIP_API_TOKEN }} run: | - ~/.local/bin/zulip-send --stream miri --subject "Cron Job Failure $(date -uI)" \ + ~/.local/bin/zulip-send --stream miri --subject "Cron Job Failure (miri, $(date -u +%Y-%m))" \ --message 'Dear @**RalfJ** and @**oli** It would appear that the Miri cron job build failed. Would you mind investigating this issue? From 57ce47b72814f8147d2cddb87628b17aa1084e74 Mon Sep 17 00:00:00 2001 From: carbotaniuman <41451839+carbotaniuman@users.noreply.github.com> Date: Wed, 15 Jun 2022 14:55:21 -0500 Subject: [PATCH 3306/3747] Handle wildcard pointers in SB --- src/machine.rs | 26 +- src/stacked_borrows.rs | 244 +++++++++++++----- src/stacked_borrows/diagnostics.rs | 22 +- .../permissive_provenance_transmute.rs | 2 +- tests/fail/provenance/ptr_int_unexposed.rs | 2 +- tests/pass/ptr_int_from_exposed.rs | 2 +- tests/pass/stacked-borrows/int-to-ptr.rs | 72 +++++- 7 files changed, 282 insertions(+), 88 deletions(-) diff --git a/src/machine.rs b/src/machine.rs index d14ddaa1a6bbf..c2a7a34a9cc08 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -489,7 +489,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { type AllocExtra = AllocExtra; type PointerTag = Tag; - type TagExtra = SbTag; + type TagExtra = Option; type MemoryMap = MonoHashMap, Allocation)>; @@ -708,8 +708,24 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { ptr: Pointer, ) -> InterpResult<'tcx> { match ptr.provenance { - Tag::Concrete(concrete) => - intptrcast::GlobalStateInner::expose_addr(ecx, concrete.alloc_id), + Tag::Concrete(ConcreteTag { alloc_id, sb }) => { + intptrcast::GlobalStateInner::expose_addr(ecx, alloc_id); + + let (size, _) = + ecx.get_alloc_size_and_align(alloc_id, AllocCheck::MaybeDead).unwrap(); + + // Function pointers and dead objects don't have an alloc_extra so we ignore them. + if let Ok(alloc_extra) = ecx.get_alloc_extra(alloc_id) { + if let Some(stacked_borrows) = &alloc_extra.stacked_borrows { + stacked_borrows.ptr_exposed( + alloc_id, + sb, + alloc_range(Size::from_bytes(0), size), + ecx.machine.stacked_borrows.as_ref().unwrap(), + )?; + } + } + } Tag::Wildcard => { // No need to do anything for wildcard pointers as // their provenances have already been previously exposed. @@ -728,8 +744,8 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { rel.map(|(alloc_id, size)| { let sb = match ptr.provenance { - Tag::Concrete(ConcreteTag { sb, .. }) => sb, - Tag::Wildcard => SbTag::Untagged, + Tag::Concrete(ConcreteTag { sb, .. }) => Some(sb), + Tag::Wildcard => None, }; (alloc_id, size, sb) }) diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 0c537e0d7a5c6..ad7569008e20c 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -104,6 +104,10 @@ pub struct Stack { /// * Above a `SharedReadOnly` there can only be more `SharedReadOnly`. /// * Except for `Untagged`, no tag occurs in the stack more than once. borrows: Vec, + /// If this is `Some(id)`, then the actual current stack is unknown. What we do know + /// is that `borrows` are at the top of the stack, and below it are arbitrarily many items + /// whose `tag` is either `Untagged` or strictly less than `id`. + unknown_bottom: Option, } /// Extra per-allocation state. @@ -113,6 +117,8 @@ pub struct Stacks { stacks: RefCell>, /// Stores past operations on this allocation history: RefCell, + /// The set of tags that have been exposed + exposed_tags: RefCell>, } /// Extra global state, available to the memory access hooks. @@ -283,32 +289,72 @@ impl Permission { impl<'tcx> Stack { /// Find the item granting the given kind of access to the given tag, and return where /// it is on the stack. - fn find_granting(&self, access: AccessKind, tag: SbTag) -> Option { - self.borrows + // TODO: Doc ok with Some(index) or None if unknown_bottom used + // Err if does not match + fn find_granting( + &self, + access: AccessKind, + tag: Option, + exposed_tags: &FxHashSet, + ) -> Result, ()> { + let res = self + .borrows .iter() .enumerate() // we also need to know *where* in the stack .rev() // search top-to-bottom // Return permission of first item that grants access. // We require a permission with the right tag, ensuring U3 and F3. - .find_map( - |(idx, item)| { - if tag == item.tag && item.perm.grants(access) { Some(idx) } else { None } + .find_map(|(idx, item)| { + match tag { + Some(tag) if tag == item.tag && item.perm.grants(access) => Some(idx), + None if exposed_tags.contains(&item.tag) => Some(idx), + _ => None, + } + }); + + if res.is_some() { + return Ok(res); + } + + match self.unknown_bottom { + Some(id) => + match tag { + Some(tag) => + match tag { + SbTag::Tagged(tag_id) if tag_id < id => Ok(None), + SbTag::Untagged => Ok(None), + _ => Err(()), + }, + None => Ok(None), }, - ) + None => Err(()), + } } /// Find the first write-incompatible item above the given one -- /// i.e, find the height to which the stack will be truncated when writing to `granting`. - fn find_first_write_incompatible(&self, granting: usize) -> usize { - let perm = self.borrows[granting].perm; + fn find_first_write_incompatible(&self, granting: Option) -> usize { + let perm = if let Some(idx) = granting { + self.borrows[idx].perm + } else { + // I assume this has to be it? + Permission::SharedReadWrite + }; + match perm { Permission::SharedReadOnly => bug!("Cannot use SharedReadOnly for writing"), Permission::Disabled => bug!("Cannot use Disabled for anything"), // On a write, everything above us is incompatible. - Permission::Unique => granting + 1, + Permission::Unique => + if let Some(idx) = granting { + idx + 1 + } else { + 0 + }, Permission::SharedReadWrite => { // The SharedReadWrite *just* above us are compatible, to skip those. - let mut idx = granting + 1; + let mut idx = if let Some(idx) = granting { idx + 1 } else { 0 }; + while let Some(item) = self.borrows.get(idx) { if item.perm == Permission::SharedReadWrite { // Go on. @@ -380,58 +426,67 @@ impl<'tcx> Stack { fn access( &mut self, access: AccessKind, - tag: SbTag, + tag: Option, (alloc_id, alloc_range, offset): (AllocId, AllocRange, Size), // just for debug printing and error messages global: &mut GlobalStateInner, current_span: &mut CurrentSpan<'_, '_, 'tcx>, alloc_history: &mut AllocHistory, + exposed_tags: &FxHashSet, ) -> InterpResult<'tcx> { // Two main steps: Find granting item, remove incompatible items above. // Step 1: Find granting item. - let granting_idx = self.find_granting(access, tag).ok_or_else(|| { + let granting_idx = self.find_granting(access, tag, exposed_tags).map_err(|_| { alloc_history.access_error(access, tag, alloc_id, alloc_range, offset, self) })?; // Step 2: Remove incompatible items above them. Make sure we do not remove protected // items. Behavior differs for reads and writes. - if access == AccessKind::Write { - // Remove everything above the write-compatible items, like a proper stack. This makes sure read-only and unique - // pointers become invalid on write accesses (ensures F2a, and ensures U2 for write accesses). - let first_incompatible_idx = self.find_first_write_incompatible(granting_idx); - for item in self.borrows.drain(first_incompatible_idx..).rev() { - trace!("access: popping item {:?}", item); - Stack::check_protector( - &item, - Some((tag, alloc_range, offset, access)), - global, - alloc_history, - )?; - alloc_history.log_invalidation(item.tag, alloc_range, current_span); - } - } else { - // On a read, *disable* all `Unique` above the granting item. This ensures U2 for read accesses. - // The reason this is not following the stack discipline (by removing the first Unique and - // everything on top of it) is that in `let raw = &mut *x as *mut _; let _val = *x;`, the second statement - // would pop the `Unique` from the reborrow of the first statement, and subsequently also pop the - // `SharedReadWrite` for `raw`. - // This pattern occurs a lot in the standard library: create a raw pointer, then also create a shared - // reference and use that. - // We *disable* instead of removing `Unique` to avoid "connecting" two neighbouring blocks of SRWs. - for idx in ((granting_idx + 1)..self.borrows.len()).rev() { - let item = &mut self.borrows[idx]; - if item.perm == Permission::Unique { - trace!("access: disabling item {:?}", item); + if let Some(tag) = tag { + if access == AccessKind::Write { + // Remove everything above the write-compatible items, like a proper stack. This makes sure read-only and unique + // pointers become invalid on write accesses (ensures F2a, and ensures U2 for write accesses). + let first_incompatible_idx = self.find_first_write_incompatible(granting_idx); + for item in self.borrows.drain(first_incompatible_idx..).rev() { + trace!("access: popping item {:?}", item); Stack::check_protector( - item, + &item, Some((tag, alloc_range, offset, access)), global, alloc_history, )?; - item.perm = Permission::Disabled; alloc_history.log_invalidation(item.tag, alloc_range, current_span); } + } else { + let start_idx = if let Some(idx) = granting_idx { idx + 1 } else { 0 }; + // On a read, *disable* all `Unique` above the granting item. This ensures U2 for read accesses. + // The reason this is not following the stack discipline (by removing the first Unique and + // everything on top of it) is that in `let raw = &mut *x as *mut _; let _val = *x;`, the second statement + // would pop the `Unique` from the reborrow of the first statement, and subsequently also pop the + // `SharedReadWrite` for `raw`. + // This pattern occurs a lot in the standard library: create a raw pointer, then also create a shared + // reference and use that. + // We *disable* instead of removing `Unique` to avoid "connecting" two neighbouring blocks of SRWs. + for idx in (start_idx..self.borrows.len()).rev() { + let item = &mut self.borrows[idx]; + + if item.perm == Permission::Unique { + trace!("access: disabling item {:?}", item); + Stack::check_protector( + item, + Some((tag, alloc_range, offset, access)), + global, + alloc_history, + )?; + item.perm = Permission::Disabled; + alloc_history.log_invalidation(item.tag, alloc_range, current_span); + } + } } + } else { + self.borrows.clear(); + // TODO + // self.borrows.push(ItemOrUnknown::Unknown(global.next_ptr_id)); } // Done. @@ -442,19 +497,20 @@ impl<'tcx> Stack { /// active protectors at all because we will remove all items. fn dealloc( &mut self, - tag: SbTag, + tag: Option, (alloc_id, alloc_range, offset): (AllocId, AllocRange, Size), // just for debug printing and error messages global: &GlobalStateInner, alloc_history: &mut AllocHistory, + exposed_tags: &FxHashSet, ) -> InterpResult<'tcx> { // Step 1: Find granting item. - self.find_granting(AccessKind::Write, tag).ok_or_else(|| { + self.find_granting(AccessKind::Write, tag, exposed_tags).map_err(|_| { err_sb_ub(format!( "no item granting write access for deallocation to tag {:?} at {:?} found in borrow stack", tag, alloc_id, ), None, - alloc_history.get_logs_relevant_to(tag, alloc_range, offset, None), + tag.and_then(|tag| alloc_history.get_logs_relevant_to(tag, alloc_range, offset, None)), ) })?; @@ -462,7 +518,6 @@ impl<'tcx> Stack { for item in self.borrows.drain(..).rev() { Stack::check_protector(&item, None, global, alloc_history)?; } - Ok(()) } @@ -474,21 +529,17 @@ impl<'tcx> Stack { /// `range` that we are currently checking. fn grant( &mut self, - derived_from: SbTag, + derived_from: Option, new: Item, (alloc_id, alloc_range, offset): (AllocId, AllocRange, Size), // just for debug printing and error messages global: &mut GlobalStateInner, current_span: &mut CurrentSpan<'_, '_, 'tcx>, alloc_history: &mut AllocHistory, + exposed_tags: &FxHashSet, ) -> InterpResult<'tcx> { // Figure out which access `perm` corresponds to. let access = if new.perm.grants(AccessKind::Write) { AccessKind::Write } else { AccessKind::Read }; - // Now we figure out which item grants our parent (`derived_from`) this kind of access. - // We use that to determine where to put the new item. - let granting_idx = self.find_granting(access, derived_from).ok_or_else(|| { - alloc_history.grant_error(derived_from, new, alloc_id, alloc_range, offset, self) - })?; // Compute where to put the new item. // Either way, we ensure that we insert the new item in a way such that between @@ -498,6 +549,21 @@ impl<'tcx> Stack { access == AccessKind::Write, "this case only makes sense for stack-like accesses" ); + + // Now we figure out which item grants our parent (`derived_from`) this kind of access. + // We use that to determine where to put the new item. + let granting_idx = + self.find_granting(access, derived_from, exposed_tags).map_err(|_| { + alloc_history.grant_error( + derived_from, + new, + alloc_id, + alloc_range, + offset, + self, + ) + })?; + // SharedReadWrite can coexist with "existing loans", meaning they don't act like a write // access. Instead of popping the stack, we insert the item at the place the stack would // be popped to (i.e., we insert it above all the write-compatible items). @@ -514,6 +580,7 @@ impl<'tcx> Stack { global, current_span, alloc_history, + exposed_tags, )?; // We insert "as far up as possible": We know only compatible items are remaining @@ -522,7 +589,6 @@ impl<'tcx> Stack { // This ensures U1 and F1. self.borrows.len() }; - // Put the new item there. As an optimization, deduplicate if it is equal to one of its new neighbors. if self.borrows[new_idx - 1] == new || self.borrows.get(new_idx) == Some(&new) { // Optimization applies, done. @@ -531,7 +597,6 @@ impl<'tcx> Stack { trace!("reborrow: adding item {:?}", new); self.borrows.insert(new_idx, new); } - Ok(()) } } @@ -542,11 +607,12 @@ impl<'tcx> Stacks { /// Creates new stack with initial tag. fn new(size: Size, perm: Permission, tag: SbTag) -> Self { let item = Item { perm, tag, protector: None }; - let stack = Stack { borrows: vec![item] }; + let stack = Stack { borrows: vec![item], unknown_bottom: None }; Stacks { stacks: RefCell::new(RangeMap::new(size, stack)), history: RefCell::new(AllocHistory::new()), + exposed_tags: RefCell::new(FxHashSet::default()), } } @@ -554,12 +620,18 @@ impl<'tcx> Stacks { fn for_each( &self, range: AllocRange, - mut f: impl FnMut(Size, &mut Stack, &mut AllocHistory) -> InterpResult<'tcx>, + mut f: impl FnMut( + Size, + &mut Stack, + &mut AllocHistory, + &mut FxHashSet, + ) -> InterpResult<'tcx>, ) -> InterpResult<'tcx> { let mut stacks = self.stacks.borrow_mut(); let history = &mut *self.history.borrow_mut(); + let exposed_tags = &mut *self.exposed_tags.borrow_mut(); for (offset, stack) in stacks.iter_mut(range.start, range.size) { - f(offset, stack, history)?; + f(offset, stack, history, exposed_tags)?; } Ok(()) } @@ -568,12 +640,18 @@ impl<'tcx> Stacks { fn for_each_mut( &mut self, range: AllocRange, - mut f: impl FnMut(Size, &mut Stack, &mut AllocHistory) -> InterpResult<'tcx>, + mut f: impl FnMut( + Size, + &mut Stack, + &mut AllocHistory, + &mut FxHashSet, + ) -> InterpResult<'tcx>, ) -> InterpResult<'tcx> { let stacks = self.stacks.get_mut(); let history = &mut *self.history.borrow_mut(); + let exposed_tags = self.exposed_tags.get_mut(); for (offset, stack) in stacks.iter_mut(range.start, range.size) { - f(offset, stack, history)?; + f(offset, stack, history, exposed_tags)?; } Ok(()) } @@ -631,11 +709,31 @@ impl Stacks { } #[inline(always)] - pub fn memory_read<'tcx>( + pub fn ptr_exposed<'tcx>( &self, alloc_id: AllocId, tag: SbTag, range: AllocRange, + _state: &GlobalState, + ) -> InterpResult<'tcx> { + trace!( + "allocation exposed with tag {:?}: {:?}, size {}", + tag, + Pointer::new(alloc_id, range.start), + range.size.bytes() + ); + + self.exposed_tags.borrow_mut().insert(tag); + + Ok(()) + } + + #[inline(always)] + pub fn memory_read<'tcx>( + &self, + alloc_id: AllocId, + tag: Option, + range: AllocRange, state: &GlobalState, mut current_span: CurrentSpan<'_, '_, 'tcx>, ) -> InterpResult<'tcx> { @@ -646,7 +744,7 @@ impl Stacks { range.size.bytes() ); let mut state = state.borrow_mut(); - self.for_each(range, |offset, stack, history| { + self.for_each(range, |offset, stack, history, exposed_tags| { stack.access( AccessKind::Read, tag, @@ -654,6 +752,7 @@ impl Stacks { &mut state, &mut current_span, history, + exposed_tags, ) }) } @@ -662,7 +761,7 @@ impl Stacks { pub fn memory_written<'tcx>( &mut self, alloc_id: AllocId, - tag: SbTag, + tag: Option, range: AllocRange, state: &GlobalState, mut current_span: CurrentSpan<'_, '_, 'tcx>, @@ -674,7 +773,7 @@ impl Stacks { range.size.bytes() ); let mut state = state.borrow_mut(); - self.for_each_mut(range, |offset, stack, history| { + self.for_each_mut(range, |offset, stack, history, exposed_tags| { stack.access( AccessKind::Write, tag, @@ -682,6 +781,7 @@ impl Stacks { &mut state, &mut current_span, history, + exposed_tags, ) }) } @@ -690,14 +790,14 @@ impl Stacks { pub fn memory_deallocated<'tcx>( &mut self, alloc_id: AllocId, - tag: SbTag, + tag: Option, range: AllocRange, state: &GlobalState, ) -> InterpResult<'tcx> { trace!("deallocation with tag {:?}: {:?}, size {}", tag, alloc_id, range.size.bytes()); let state = state.borrow(); - self.for_each_mut(range, |offset, stack, history| { - stack.dealloc(tag, (alloc_id, range, offset), &state, history) + self.for_each_mut(range, |offset, stack, history, exposed_tags| { + stack.dealloc(tag, (alloc_id, range, offset), &state, history, exposed_tags) })?; Ok(()) } @@ -749,7 +849,9 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Dangling slices are a common case here; it's valid to get their length but with raw // pointer tagging for example all calls to get_unchecked on them are invalid. if let Ok((alloc_id, base_offset, orig_tag)) = this.ptr_try_get_alloc_id(place.ptr) { - log_creation(this, current_span, alloc_id, base_offset, orig_tag)?; + if let Some(orig_tag) = orig_tag { + log_creation(this, current_span, alloc_id, base_offset, orig_tag)?; + } } trace!( @@ -762,7 +864,9 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx return Ok(()); } let (alloc_id, base_offset, orig_tag) = this.ptr_get_alloc_id(place.ptr)?; - log_creation(this, current_span, alloc_id, base_offset, orig_tag)?; + if let Some(orig_tag) = orig_tag { + log_creation(this, current_span, alloc_id, base_offset, orig_tag)?; + } // Ensure we bail out if the pointer goes out-of-bounds (see miri#1050). let (alloc_size, _) = @@ -830,7 +934,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx }; let item = Item { perm, tag: new_tag, protector }; let mut global = this.machine.stacked_borrows.as_ref().unwrap().borrow_mut(); - stacked_borrows.for_each(range, |offset, stack, history| { + stacked_borrows.for_each(range, |offset, stack, history, exposed_tags| { stack.grant( orig_tag, item, @@ -838,6 +942,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx &mut *global, current_span, history, + exposed_tags, ) }) })?; @@ -854,7 +959,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let range = alloc_range(base_offset, size); let mut global = machine.stacked_borrows.as_ref().unwrap().borrow_mut(); let current_span = &mut machine.current_span(); // `get_alloc_extra_mut` invalidated our old `current_span` - stacked_borrows.for_each_mut(range, |offset, stack, history| { + stacked_borrows.for_each_mut(range, |offset, stack, history, exposed_tags| { stack.grant( orig_tag, item, @@ -862,6 +967,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx &mut global, current_span, history, + exposed_tags, ) })?; diff --git a/src/stacked_borrows/diagnostics.rs b/src/stacked_borrows/diagnostics.rs index 5400e9abe5038..224954c761591 100644 --- a/src/stacked_borrows/diagnostics.rs +++ b/src/stacked_borrows/diagnostics.rs @@ -197,7 +197,7 @@ impl AllocHistory { /// Report a descriptive error when `new` could not be granted from `derived_from`. pub fn grant_error<'tcx>( &self, - derived_from: SbTag, + derived_from: Option, new: Item, alloc_id: AllocId, alloc_range: AllocRange, @@ -214,7 +214,9 @@ impl AllocHistory { err_sb_ub( format!("{}{}", action, error_cause(stack, derived_from)), Some(operation_summary("a reborrow", alloc_id, alloc_range)), - self.get_logs_relevant_to(derived_from, alloc_range, error_offset, None), + derived_from.and_then(|derived_from| { + self.get_logs_relevant_to(derived_from, alloc_range, error_offset, None) + }), ) } @@ -222,7 +224,7 @@ impl AllocHistory { pub fn access_error<'tcx>( &self, access: AccessKind, - tag: SbTag, + tag: Option, alloc_id: AllocId, alloc_range: AllocRange, error_offset: Size, @@ -238,7 +240,7 @@ impl AllocHistory { err_sb_ub( format!("{}{}", action, error_cause(stack, tag)), Some(operation_summary("an access", alloc_id, alloc_range)), - self.get_logs_relevant_to(tag, alloc_range, error_offset, None), + tag.and_then(|tag| self.get_logs_relevant_to(tag, alloc_range, error_offset, None)), ) } } @@ -251,10 +253,14 @@ fn operation_summary( format!("this error occurs as part of {} at {:?}{}", operation, alloc_id, HexRange(alloc_range)) } -fn error_cause(stack: &Stack, tag: SbTag) -> &'static str { - if stack.borrows.iter().any(|item| item.tag == tag && item.perm != Permission::Disabled) { - ", but that tag only grants SharedReadOnly permission for this location" +fn error_cause(stack: &Stack, tag: Option) -> &'static str { + if let Some(tag) = tag { + if stack.borrows.iter().any(|item| item.tag == tag && item.perm != Permission::Disabled) { + ", but that tag only grants SharedReadOnly permission for this location" + } else { + ", but that tag does not exist in the borrow stack for this location" + } } else { - ", but that tag does not exist in the borrow stack for this location" + ", but no exposed tags are valid in the borrow stack for this location" } } diff --git a/tests/fail/provenance/permissive_provenance_transmute.rs b/tests/fail/provenance/permissive_provenance_transmute.rs index dbfc5732ed3b7..28e6ba6230803 100644 --- a/tests/fail/provenance/permissive_provenance_transmute.rs +++ b/tests/fail/provenance/permissive_provenance_transmute.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-permissive-provenance -Zmiri-disable-stacked-borrows +// compile-flags: -Zmiri-permissive-provenance #![feature(strict_provenance)] use std::mem; diff --git a/tests/fail/provenance/ptr_int_unexposed.rs b/tests/fail/provenance/ptr_int_unexposed.rs index 310024c1efc70..ad29d38dc3f7a 100644 --- a/tests/fail/provenance/ptr_int_unexposed.rs +++ b/tests/fail/provenance/ptr_int_unexposed.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-permissive-provenance -Zmiri-disable-stacked-borrows +// compile-flags: -Zmiri-permissive-provenance #![feature(strict_provenance)] fn main() { diff --git a/tests/pass/ptr_int_from_exposed.rs b/tests/pass/ptr_int_from_exposed.rs index e025cf921313a..dc9cb393b7815 100644 --- a/tests/pass/ptr_int_from_exposed.rs +++ b/tests/pass/ptr_int_from_exposed.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-permissive-provenance -Zmiri-disable-stacked-borrows +// compile-flags: -Zmiri-permissive-provenance #![feature(strict_provenance)] use std::ptr; diff --git a/tests/pass/stacked-borrows/int-to-ptr.rs b/tests/pass/stacked-borrows/int-to-ptr.rs index efba0da1b9358..dc581d8af618f 100644 --- a/tests/pass/stacked-borrows/int-to-ptr.rs +++ b/tests/pass/stacked-borrows/int-to-ptr.rs @@ -1,6 +1,6 @@ -fn main() { - ref_raw_int_raw(); -} +// compile-flags: -Zmiri-permissive-provenance +#![feature(strict_provenance)] +use std::ptr; // Just to make sure that casting a ref to raw, to int and back to raw // and only then using it works. This rules out ideas like "do escape-to-raw lazily"; @@ -11,3 +11,69 @@ fn ref_raw_int_raw() { let xraw = xref as *mut i32 as usize as *mut i32; assert_eq!(unsafe { *xraw }, 3); } + +/// Ensure that we do not just pick the topmost possible item on int2ptr casts. +fn example(variant: bool) { unsafe { + fn not_so_innocent(x: &mut u32) -> usize { + let x_raw4 = x as *mut u32; + x_raw4.expose_addr() + } + + let mut c = 42u32; + + let x_unique1 = &mut c; + // [..., Unique(1)] + + let x_raw2 = x_unique1 as *mut u32; + let x_raw2_addr = x_raw2.expose_addr(); + // [..., Unique(1), SharedRW(2)] + + let x_unique3 = &mut *x_raw2; + // [.., Unique(1), SharedRW(2), Unique(3)] + + assert_eq!(not_so_innocent(x_unique3), x_raw2_addr); + // [.., Unique(1), SharedRW(2), Unique(3), ..., SharedRW(4)] + + // Do an int2ptr cast. This can pick tag 2 or 4 (the two previously exposed tags). + // 4 is the "obvious" choice (topmost tag, what we used to do with untagged pointers). + // And indeed if `variant == true` it is the only possible choice. + // But if `variant == false` then 2 is the only possible choice! + let x_wildcard = ptr::from_exposed_addr_mut::(x_raw2_addr); + + if variant { + // If we picked 2, this will invalidate 3. + *x_wildcard = 10; + // Now we use 3. Only possible if above we picked 4. + *x_unique3 = 12; + } else { + // This invalidates tag 4. + *x_unique3 = 10; + // Now try to write with the "guessed" tag; it must be 2. + *x_wildcard = 12; + } +} } + +fn test() { unsafe { + let root = &mut 42; + let root_raw = root as *mut i32; + let addr1 = root_raw as usize; + let child = &mut *root_raw; + let child_raw = child as *mut i32; + let addr2 = child_raw as usize; + assert_eq!(addr1, addr2); + // First use child. + *(addr2 as *mut i32) -= 2; // picks child_raw + *child -= 2; + // Then use root. + *(addr1 as *mut i32) += 2; // picks root_raw + *root += 2; + // Value should be unchanged. + assert_eq!(*root, 42); +} } + +fn main() { + ref_raw_int_raw(); + example(false); + example(true); + test(); +} From c7feb014b0b73d2e06ccfd3b754171d3fec7eeda Mon Sep 17 00:00:00 2001 From: carbotaniuman <41451839+carbotaniuman@users.noreply.github.com> Date: Wed, 15 Jun 2022 20:53:44 -0500 Subject: [PATCH 3307/3747] Maybe this wil work --- src/stacked_borrows.rs | 49 ++++++++++++++++-------------- src/stacked_borrows/diagnostics.rs | 19 ++++++++++-- 2 files changed, 44 insertions(+), 24 deletions(-) diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index ad7569008e20c..d28c6425cd42c 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -485,8 +485,7 @@ impl<'tcx> Stack { } } else { self.borrows.clear(); - // TODO - // self.borrows.push(ItemOrUnknown::Unknown(global.next_ptr_id)); + self.unknown_bottom = Some(global.next_ptr_id); } // Done. @@ -541,6 +540,20 @@ impl<'tcx> Stack { let access = if new.perm.grants(AccessKind::Write) { AccessKind::Write } else { AccessKind::Read }; + // Now we figure out which item grants our parent (`derived_from`) this kind of access. + // We use that to determine where to put the new item. + let granting_idx = + self.find_granting(access, derived_from, exposed_tags).map_err(|_| { + alloc_history.grant_error( + derived_from, + new, + alloc_id, + alloc_range, + offset, + self, + ) + })?; + // Compute where to put the new item. // Either way, we ensure that we insert the new item in a way such that between // `derived_from` and the new one, there are only items *compatible with* `derived_from`. @@ -550,25 +563,17 @@ impl<'tcx> Stack { "this case only makes sense for stack-like accesses" ); - // Now we figure out which item grants our parent (`derived_from`) this kind of access. - // We use that to determine where to put the new item. - let granting_idx = - self.find_granting(access, derived_from, exposed_tags).map_err(|_| { - alloc_history.grant_error( - derived_from, - new, - alloc_id, - alloc_range, - offset, - self, - ) - })?; - - // SharedReadWrite can coexist with "existing loans", meaning they don't act like a write - // access. Instead of popping the stack, we insert the item at the place the stack would - // be popped to (i.e., we insert it above all the write-compatible items). - // This ensures F2b by adding the new item below any potentially existing `SharedReadOnly`. - self.find_first_write_incompatible(granting_idx) + if derived_from.is_some() { + // SharedReadWrite can coexist with "existing loans", meaning they don't act like a write + // access. Instead of popping the stack, we insert the item at the place the stack would + // be popped to (i.e., we insert it above all the write-compatible items). + // This ensures F2b by adding the new item below any potentially existing `SharedReadOnly`. + self.find_first_write_incompatible(granting_idx) + } else { + // TODO: is this correct + self.borrows.clear(); + 0 + } } else { // A "safe" reborrow for a pointer that actually expects some aliasing guarantees. // Here, creating a reference actually counts as an access. @@ -590,7 +595,7 @@ impl<'tcx> Stack { self.borrows.len() }; // Put the new item there. As an optimization, deduplicate if it is equal to one of its new neighbors. - if self.borrows[new_idx - 1] == new || self.borrows.get(new_idx) == Some(&new) { + if self.borrows.get(new_idx) == Some(&new) || new_idx > 0 && self.borrows.get(new_idx - 1) == Some(&new) { // Optimization applies, done. trace!("reborrow: avoiding adding redundant item {:?}", new); } else { diff --git a/src/stacked_borrows/diagnostics.rs b/src/stacked_borrows/diagnostics.rs index 224954c761591..6a22d9a74392f 100644 --- a/src/stacked_borrows/diagnostics.rs +++ b/src/stacked_borrows/diagnostics.rs @@ -4,6 +4,8 @@ use rustc_middle::mir::interpret::{AllocId, AllocRange}; use rustc_span::{Span, SpanData}; use rustc_target::abi::Size; +use core::fmt::Debug; + use crate::helpers::{CurrentSpan, HexRange}; use crate::stacked_borrows::{err_sb_ub, AccessKind, Permission}; use crate::Item; @@ -204,9 +206,16 @@ impl AllocHistory { error_offset: Size, stack: &Stack, ) -> InterpError<'tcx> { + // TODO: Fix this properly + let z = &derived_from; + let f = if let Some(ref t) = z { + t as &dyn Debug + } else { + &"" as &dyn Debug + }; let action = format!( "trying to reborrow {:?} for {:?} permission at {}[{:#x}]", - derived_from, + f, new.perm, alloc_id, error_offset.bytes(), @@ -230,10 +239,16 @@ impl AllocHistory { error_offset: Size, stack: &Stack, ) -> InterpError<'tcx> { + let z = &tag; + let f = if let Some(ref t) = z { + t as &dyn Debug + } else { + &"" as &dyn Debug + }; let action = format!( "attempting a {} using {:?} at {}[{:#x}]", access, - tag, + f, alloc_id, error_offset.bytes(), ); From d1e7de117c84ccfe611a14791dbb53c5e1520b50 Mon Sep 17 00:00:00 2001 From: carbotaniuman <41451839+carbotaniuman@users.noreply.github.com> Date: Wed, 15 Jun 2022 20:55:54 -0500 Subject: [PATCH 3308/3747] Try fix stuff --- src/stacked_borrows.rs | 17 ++++++----------- src/stacked_borrows/diagnostics.rs | 12 ++---------- 2 files changed, 8 insertions(+), 21 deletions(-) diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index d28c6425cd42c..75c2ff265879a 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -543,16 +543,9 @@ impl<'tcx> Stack { // Now we figure out which item grants our parent (`derived_from`) this kind of access. // We use that to determine where to put the new item. let granting_idx = - self.find_granting(access, derived_from, exposed_tags).map_err(|_| { - alloc_history.grant_error( - derived_from, - new, - alloc_id, - alloc_range, - offset, - self, - ) - })?; + self.find_granting(access, derived_from, exposed_tags).map_err(|_| { + alloc_history.grant_error(derived_from, new, alloc_id, alloc_range, offset, self) + })?; // Compute where to put the new item. // Either way, we ensure that we insert the new item in a way such that between @@ -595,7 +588,9 @@ impl<'tcx> Stack { self.borrows.len() }; // Put the new item there. As an optimization, deduplicate if it is equal to one of its new neighbors. - if self.borrows.get(new_idx) == Some(&new) || new_idx > 0 && self.borrows.get(new_idx - 1) == Some(&new) { + if self.borrows.get(new_idx) == Some(&new) + || new_idx > 0 && self.borrows.get(new_idx - 1) == Some(&new) + { // Optimization applies, done. trace!("reborrow: avoiding adding redundant item {:?}", new); } else { diff --git a/src/stacked_borrows/diagnostics.rs b/src/stacked_borrows/diagnostics.rs index 6a22d9a74392f..91dfe22c19649 100644 --- a/src/stacked_borrows/diagnostics.rs +++ b/src/stacked_borrows/diagnostics.rs @@ -208,11 +208,7 @@ impl AllocHistory { ) -> InterpError<'tcx> { // TODO: Fix this properly let z = &derived_from; - let f = if let Some(ref t) = z { - t as &dyn Debug - } else { - &"" as &dyn Debug - }; + let f = if let Some(ref t) = z { t as &dyn Debug } else { &"" as &dyn Debug }; let action = format!( "trying to reborrow {:?} for {:?} permission at {}[{:#x}]", f, @@ -240,11 +236,7 @@ impl AllocHistory { stack: &Stack, ) -> InterpError<'tcx> { let z = &tag; - let f = if let Some(ref t) = z { - t as &dyn Debug - } else { - &"" as &dyn Debug - }; + let f = if let Some(ref t) = z { t as &dyn Debug } else { &"" as &dyn Debug }; let action = format!( "attempting a {} using {:?} at {}[{:#x}]", access, From 2deb9e5dae5b6d6b66105fda92e2d30e48a0cfab Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 24 Jun 2022 16:21:47 -0400 Subject: [PATCH 3309/3747] add exposed_only_ro test --- tests/fail/stacked_borrows/exposed_only_ro.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 tests/fail/stacked_borrows/exposed_only_ro.rs diff --git a/tests/fail/stacked_borrows/exposed_only_ro.rs b/tests/fail/stacked_borrows/exposed_only_ro.rs new file mode 100644 index 0000000000000..b3adb0b855f63 --- /dev/null +++ b/tests/fail/stacked_borrows/exposed_only_ro.rs @@ -0,0 +1,12 @@ +// compile-flags: -Zmiri-permissive-provenance +#![feature(strict_provenance)] + +// If we have only exposed read-only pointers, doing a write through a wildcard ptr should fail. + +fn main() { + let mut x = 0; + let _fool = &mut x as *mut i32; // this would have fooled the old untagged pointer logic + let addr = (&x as *const i32).expose_addr(); + let ptr = std::ptr::from_exposed_addr_mut::(addr); + unsafe { ptr.write(0) }; //~ ERROR: borrow stack +} From c0f7118342ccf77330c92d50222f90856730254b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 24 Jun 2022 16:45:22 -0400 Subject: [PATCH 3310/3747] reorganize exposure code a bit --- src/intptrcast.rs | 7 +++++-- src/machine.rs | 18 ++---------------- src/stacked_borrows.rs | 35 ++++++++++++++--------------------- 3 files changed, 21 insertions(+), 39 deletions(-) diff --git a/src/intptrcast.rs b/src/intptrcast.rs index 4a86490ed09a9..279bf3d01d2e8 100644 --- a/src/intptrcast.rs +++ b/src/intptrcast.rs @@ -101,14 +101,17 @@ impl<'mir, 'tcx> GlobalStateInner { } } - pub fn expose_addr(ecx: &MiriEvalContext<'mir, 'tcx>, alloc_id: AllocId) { + pub fn expose_ptr(ecx: &mut MiriEvalContext<'mir, 'tcx>, alloc_id: AllocId, sb: SbTag) { trace!("Exposing allocation id {:?}", alloc_id); - let mut global_state = ecx.machine.intptrcast.borrow_mut(); + let global_state = ecx.machine.intptrcast.get_mut(); // In legacy and strict mode, we don't need this, so we can save some cycles // by not tracking it. if global_state.provenance_mode == ProvenanceMode::Permissive { global_state.exposed.insert(alloc_id); + if ecx.machine.stacked_borrows.is_some() { + ecx.expose_tag(alloc_id, sb); + } } } diff --git a/src/machine.rs b/src/machine.rs index c2a7a34a9cc08..3704a53851418 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -489,6 +489,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { type AllocExtra = AllocExtra; type PointerTag = Tag; + // `None` represents a wildcard pointer. type TagExtra = Option; type MemoryMap = @@ -709,22 +710,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { ) -> InterpResult<'tcx> { match ptr.provenance { Tag::Concrete(ConcreteTag { alloc_id, sb }) => { - intptrcast::GlobalStateInner::expose_addr(ecx, alloc_id); - - let (size, _) = - ecx.get_alloc_size_and_align(alloc_id, AllocCheck::MaybeDead).unwrap(); - - // Function pointers and dead objects don't have an alloc_extra so we ignore them. - if let Ok(alloc_extra) = ecx.get_alloc_extra(alloc_id) { - if let Some(stacked_borrows) = &alloc_extra.stacked_borrows { - stacked_borrows.ptr_exposed( - alloc_id, - sb, - alloc_range(Size::from_bytes(0), size), - ecx.machine.stacked_borrows.as_ref().unwrap(), - )?; - } - } + intptrcast::GlobalStateInner::expose_ptr(ecx, alloc_id, sb); } Tag::Wildcard => { // No need to do anything for wildcard pointers as diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 75c2ff265879a..b66864b8302a8 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -117,7 +117,7 @@ pub struct Stacks { stacks: RefCell>, /// Stores past operations on this allocation history: RefCell, - /// The set of tags that have been exposed + /// The set of tags that have been exposed inside this allocation. exposed_tags: RefCell>, } @@ -708,26 +708,6 @@ impl Stacks { stacks } - #[inline(always)] - pub fn ptr_exposed<'tcx>( - &self, - alloc_id: AllocId, - tag: SbTag, - range: AllocRange, - _state: &GlobalState, - ) -> InterpResult<'tcx> { - trace!( - "allocation exposed with tag {:?}: {:?}, size {}", - tag, - Pointer::new(alloc_id, range.start), - range.size.bytes() - ); - - self.exposed_tags.borrow_mut().insert(tag); - - Ok(()) - } - #[inline(always)] pub fn memory_read<'tcx>( &self, @@ -1096,4 +1076,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(()) } + + /// Mark the given tag as exposed. It was found on a pointer with the given AllocId. + fn expose_tag(&mut self, alloc_id: AllocId, tag: SbTag) { + let this = self.eval_context_mut(); + + // Function pointers and dead objects don't have an alloc_extra so we ignore them. + // This is okay because accessing them is UB anyway, no need for any Stacked Borrows checks. + // FIXME: this catches `InterpError`, which we should not usually do. + // We might need a proper fallible API from `memory.rs` to avoid this though. + if let Ok((alloc_extra, _)) = this.get_alloc_extra_mut(alloc_id) { + alloc_extra.stacked_borrows.as_mut().unwrap().exposed_tags.get_mut().insert(tag); + } + } } From 8d6fdaa024138de464a74ebd5307c706c68a3eef Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 24 Jun 2022 18:02:25 -0400 Subject: [PATCH 3311/3747] make the tests pass (and some formatting) --- README.md | 4 +- src/intptrcast.rs | 3 +- src/lib.rs | 1 + src/stacked_borrows.rs | 223 ++++++++++-------- tests/fail/stacked_borrows/exposed_only_ro.rs | 2 +- .../stacked_borrows/exposed_only_ro.stderr | 18 ++ tests/pass/stacked-borrows/int-to-ptr.rs | 110 ++++----- 7 files changed, 201 insertions(+), 160 deletions(-) create mode 100644 tests/fail/stacked_borrows/exposed_only_ro.stderr diff --git a/README.md b/README.md index 88ac8a1353045..f6b2413c65f59 100644 --- a/README.md +++ b/README.md @@ -358,9 +358,7 @@ to Miri failing to detect cases of undefined behavior in a program. for pointer-to-int and int-to-pointer casts, respectively. This will necessarily miss some bugs as those semantics are not efficiently implementable in a sanitizer, but it will only miss bugs that concerns - memory/pointers which is subject to these operations. Also note that this flag - is currently incompatible with Stacked Borrows, so you will have to also pass - `-Zmiri-disable-stacked-borrows` to use this. + memory/pointers which is subject to these operations. * `-Zmiri-symbolic-alignment-check` makes the alignment check more strict. By default, alignment is checked by casting the pointer to an integer, and making sure that is a multiple of the alignment. This can lead to cases where a diff --git a/src/intptrcast.rs b/src/intptrcast.rs index 279bf3d01d2e8..9ec96b8f491e2 100644 --- a/src/intptrcast.rs +++ b/src/intptrcast.rs @@ -102,12 +102,11 @@ impl<'mir, 'tcx> GlobalStateInner { } pub fn expose_ptr(ecx: &mut MiriEvalContext<'mir, 'tcx>, alloc_id: AllocId, sb: SbTag) { - trace!("Exposing allocation id {:?}", alloc_id); - let global_state = ecx.machine.intptrcast.get_mut(); // In legacy and strict mode, we don't need this, so we can save some cycles // by not tracking it. if global_state.provenance_mode == ProvenanceMode::Permissive { + trace!("Exposing allocation id {alloc_id:?}"); global_state.exposed.insert(alloc_id); if ecx.machine.stacked_borrows.is_some() { ecx.expose_tag(alloc_id, sb); diff --git a/src/lib.rs b/src/lib.rs index dc6c0b8dc603a..432f469733cbe 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -6,6 +6,7 @@ #![feature(let_else)] #![feature(io_error_more)] #![feature(yeet_expr)] +#![feature(is_some_with)] #![warn(rust_2018_idioms)] #![allow( clippy::collapsible_else_if, diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index b66864b8302a8..8411d85f0e019 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -104,9 +104,10 @@ pub struct Stack { /// * Above a `SharedReadOnly` there can only be more `SharedReadOnly`. /// * Except for `Untagged`, no tag occurs in the stack more than once. borrows: Vec, - /// If this is `Some(id)`, then the actual current stack is unknown. What we do know - /// is that `borrows` are at the top of the stack, and below it are arbitrarily many items - /// whose `tag` is either `Untagged` or strictly less than `id`. + /// If this is `Some(id)`, then the actual current stack is unknown. THis can happen when + /// wildcard pointers are used to access this location. What we do know is that `borrows` are at + /// the top of the stack, and below it are arbitrarily many items whose `tag` is either + /// `Untagged` or strictly less than `id`. unknown_bottom: Option, } @@ -289,72 +290,72 @@ impl Permission { impl<'tcx> Stack { /// Find the item granting the given kind of access to the given tag, and return where /// it is on the stack. - // TODO: Doc ok with Some(index) or None if unknown_bottom used - // Err if does not match + /// `Ok(None)` indicates it matched the "unknown" part of the stack, or it was a wildcard tag + /// and we have no clue what exactly it matched (but it could have matched something) + /// `Err` indicates it was not found. fn find_granting( &self, access: AccessKind, tag: Option, exposed_tags: &FxHashSet, ) -> Result, ()> { - let res = self - .borrows - .iter() - .enumerate() // we also need to know *where* in the stack - .rev() // search top-to-bottom - // Return permission of first item that grants access. - // We require a permission with the right tag, ensuring U3 and F3. - .find_map(|(idx, item)| { - match tag { - Some(tag) if tag == item.tag && item.perm.grants(access) => Some(idx), - None if exposed_tags.contains(&item.tag) => Some(idx), - _ => None, - } - }); + let Some(tag) = tag else { + // Handle the wildcard case. + // Go search the stack for an exposed tag. + let maybe_in_stack = self + .borrows + .iter() + .rev() // search top-to-bottom + .find_map(|item| { + // If the item fits and *might* be this wildcard, use it. + if item.perm.grants(access) && exposed_tags.contains(&item.tag) { + Some(()) + } else { + None + } + }) + .is_some(); + // If we couldn't find it in the stack, check the unknown bottom. + let found = maybe_in_stack || self.unknown_bottom.is_some(); + return if found { Ok(None) } else { Err(()) }; + }; - if res.is_some() { - return Ok(res); + if let Some(idx) = + self.borrows + .iter() + .enumerate() // we also need to know *where* in the stack + .rev() // search top-to-bottom + // Return permission of first item that grants access. + // We require a permission with the right tag, ensuring U3 and F3. + .find_map(|(idx, item)| { + if tag == item.tag && item.perm.grants(access) { Some(idx) } else { None } + }) + { + return Ok(Some(idx)); } - match self.unknown_bottom { - Some(id) => - match tag { - Some(tag) => - match tag { - SbTag::Tagged(tag_id) if tag_id < id => Ok(None), - SbTag::Untagged => Ok(None), - _ => Err(()), - }, - None => Ok(None), - }, - None => Err(()), - } + // Couldn't find it in the stack; but if there is an unknown bottom it might be there. + let found = self.unknown_bottom.is_some_and(|&unknown_limit| { + match tag { + SbTag::Tagged(tag_id) => tag_id < unknown_limit, // unknown_limit is an upper bound for what can be in the unknown bottom. + SbTag::Untagged => true, // yeah whatever + } + }); + if found { Ok(None) } else { Err(()) } } /// Find the first write-incompatible item above the given one -- /// i.e, find the height to which the stack will be truncated when writing to `granting`. - fn find_first_write_incompatible(&self, granting: Option) -> usize { - let perm = if let Some(idx) = granting { - self.borrows[idx].perm - } else { - // I assume this has to be it? - Permission::SharedReadWrite - }; - + fn find_first_write_incompatible(&self, granting: usize) -> usize { + let perm = self.borrows[granting].perm; match perm { Permission::SharedReadOnly => bug!("Cannot use SharedReadOnly for writing"), Permission::Disabled => bug!("Cannot use Disabled for anything"), // On a write, everything above us is incompatible. - Permission::Unique => - if let Some(idx) = granting { - idx + 1 - } else { - 0 - }, + Permission::Unique => granting + 1, Permission::SharedReadWrite => { // The SharedReadWrite *just* above us are compatible, to skip those. - let mut idx = if let Some(idx) = granting { idx + 1 } else { 0 }; - + let mut idx = granting + 1; while let Some(item) = self.borrows.get(idx) { if item.perm == Permission::SharedReadWrite { // Go on. @@ -440,52 +441,57 @@ impl<'tcx> Stack { alloc_history.access_error(access, tag, alloc_id, alloc_range, offset, self) })?; + let Some(granting_idx) = granting_idx else { + // The access used a wildcard pointer or matched the unknown bottom. + // Nobody knows what happened, so forget everything. + trace!("access: clearing stack due to wildcard"); + self.borrows.clear(); + self.unknown_bottom = Some(global.next_ptr_id); + return Ok(()); + }; + let tag = tag.unwrap(); // only precise tags have precise locations + // Step 2: Remove incompatible items above them. Make sure we do not remove protected // items. Behavior differs for reads and writes. - if let Some(tag) = tag { - if access == AccessKind::Write { - // Remove everything above the write-compatible items, like a proper stack. This makes sure read-only and unique - // pointers become invalid on write accesses (ensures F2a, and ensures U2 for write accesses). - let first_incompatible_idx = self.find_first_write_incompatible(granting_idx); - for item in self.borrows.drain(first_incompatible_idx..).rev() { - trace!("access: popping item {:?}", item); + if access == AccessKind::Write { + // Remove everything above the write-compatible items, like a proper stack. This makes sure read-only and unique + // pointers become invalid on write accesses (ensures F2a, and ensures U2 for write accesses). + let first_incompatible_idx = self.find_first_write_incompatible(granting_idx); + for item in self.borrows.drain(first_incompatible_idx..).rev() { + trace!("access: popping item {:?}", item); + Stack::check_protector( + &item, + Some((tag, alloc_range, offset, access)), + global, + alloc_history, + )?; + alloc_history.log_invalidation(item.tag, alloc_range, current_span); + } + } else { + // On a read, *disable* all `Unique` above the granting item. This ensures U2 for read accesses. + // The reason this is not following the stack discipline (by removing the first Unique and + // everything on top of it) is that in `let raw = &mut *x as *mut _; let _val = *x;`, the second statement + // would pop the `Unique` from the reborrow of the first statement, and subsequently also pop the + // `SharedReadWrite` for `raw`. + // This pattern occurs a lot in the standard library: create a raw pointer, then also create a shared + // reference and use that. + // We *disable* instead of removing `Unique` to avoid "connecting" two neighbouring blocks of SRWs. + let first_incompatible_idx = granting_idx + 1; + for idx in (first_incompatible_idx..self.borrows.len()).rev() { + let item = &mut self.borrows[idx]; + + if item.perm == Permission::Unique { + trace!("access: disabling item {:?}", item); Stack::check_protector( - &item, + item, Some((tag, alloc_range, offset, access)), global, alloc_history, )?; + item.perm = Permission::Disabled; alloc_history.log_invalidation(item.tag, alloc_range, current_span); } - } else { - let start_idx = if let Some(idx) = granting_idx { idx + 1 } else { 0 }; - // On a read, *disable* all `Unique` above the granting item. This ensures U2 for read accesses. - // The reason this is not following the stack discipline (by removing the first Unique and - // everything on top of it) is that in `let raw = &mut *x as *mut _; let _val = *x;`, the second statement - // would pop the `Unique` from the reborrow of the first statement, and subsequently also pop the - // `SharedReadWrite` for `raw`. - // This pattern occurs a lot in the standard library: create a raw pointer, then also create a shared - // reference and use that. - // We *disable* instead of removing `Unique` to avoid "connecting" two neighbouring blocks of SRWs. - for idx in (start_idx..self.borrows.len()).rev() { - let item = &mut self.borrows[idx]; - - if item.perm == Permission::Unique { - trace!("access: disabling item {:?}", item); - Stack::check_protector( - item, - Some((tag, alloc_range, offset, access)), - global, - alloc_history, - )?; - item.perm = Permission::Disabled; - alloc_history.log_invalidation(item.tag, alloc_range, current_span); - } - } } - } else { - self.borrows.clear(); - self.unknown_bottom = Some(global.next_ptr_id); } // Done. @@ -502,7 +508,7 @@ impl<'tcx> Stack { alloc_history: &mut AllocHistory, exposed_tags: &FxHashSet, ) -> InterpResult<'tcx> { - // Step 1: Find granting item. + // Step 1: Make sure there is a granting item. self.find_granting(AccessKind::Write, tag, exposed_tags).map_err(|_| { err_sb_ub(format!( "no item granting write access for deallocation to tag {:?} at {:?} found in borrow stack", @@ -556,17 +562,20 @@ impl<'tcx> Stack { "this case only makes sense for stack-like accesses" ); - if derived_from.is_some() { - // SharedReadWrite can coexist with "existing loans", meaning they don't act like a write - // access. Instead of popping the stack, we insert the item at the place the stack would - // be popped to (i.e., we insert it above all the write-compatible items). - // This ensures F2b by adding the new item below any potentially existing `SharedReadOnly`. - self.find_first_write_incompatible(granting_idx) - } else { - // TODO: is this correct + let Some(granting_idx) = granting_idx else { + // The parent is a wildcard pointer or matched the unknown bottom. + // Nobody knows what happened, so forget everything. + trace!("reborrow: clearing stack due to wildcard"); self.borrows.clear(); - 0 - } + self.unknown_bottom = Some(global.next_ptr_id); + return Ok(()); + }; + + // SharedReadWrite can coexist with "existing loans", meaning they don't act like a write + // access. Instead of popping the stack, we insert the item at the place the stack would + // be popped to (i.e., we insert it above all the write-compatible items). + // This ensures F2b by adding the new item below any potentially existing `SharedReadOnly`. + self.find_first_write_incompatible(granting_idx) } else { // A "safe" reborrow for a pointer that actually expects some aliasing guarantees. // Here, creating a reference actually counts as an access. @@ -587,9 +596,11 @@ impl<'tcx> Stack { // This ensures U1 and F1. self.borrows.len() }; + // Put the new item there. As an optimization, deduplicate if it is equal to one of its new neighbors. + // `new_idx` might be 0 if we just cleared the entire stack. if self.borrows.get(new_idx) == Some(&new) - || new_idx > 0 && self.borrows.get(new_idx - 1) == Some(&new) + || (new_idx > 0 && self.borrows[new_idx - 1] == new) { // Optimization applies, done. trace!("reborrow: avoiding adding redundant item {:?}", new); @@ -648,7 +659,7 @@ impl<'tcx> Stacks { ) -> InterpResult<'tcx>, ) -> InterpResult<'tcx> { let stacks = self.stacks.get_mut(); - let history = &mut *self.history.borrow_mut(); + let history = &mut *self.history.get_mut(); let exposed_tags = self.exposed_tags.get_mut(); for (offset, stack) in stacks.iter_mut(range.start, range.size) { f(offset, stack, history, exposed_tags)?; @@ -1083,10 +1094,20 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Function pointers and dead objects don't have an alloc_extra so we ignore them. // This is okay because accessing them is UB anyway, no need for any Stacked Borrows checks. + // NOT using `get_alloc_extra_mut` since this might be a read-only allocation! // FIXME: this catches `InterpError`, which we should not usually do. // We might need a proper fallible API from `memory.rs` to avoid this though. - if let Ok((alloc_extra, _)) = this.get_alloc_extra_mut(alloc_id) { - alloc_extra.stacked_borrows.as_mut().unwrap().exposed_tags.get_mut().insert(tag); + match this.get_alloc_extra(alloc_id) { + Ok(alloc_extra) => { + trace!("Stacked Borrows tag {tag:?} exposed in {alloc_id}"); + alloc_extra.stacked_borrows.as_ref().unwrap().exposed_tags.borrow_mut().insert(tag); + } + Err(err) => { + trace!( + "Not exposing Stacked Borrows tag {tag:?} due to error \ + when accessing {alloc_id}: {err}" + ); + } } } } diff --git a/tests/fail/stacked_borrows/exposed_only_ro.rs b/tests/fail/stacked_borrows/exposed_only_ro.rs index b3adb0b855f63..9b4234499df04 100644 --- a/tests/fail/stacked_borrows/exposed_only_ro.rs +++ b/tests/fail/stacked_borrows/exposed_only_ro.rs @@ -8,5 +8,5 @@ fn main() { let _fool = &mut x as *mut i32; // this would have fooled the old untagged pointer logic let addr = (&x as *const i32).expose_addr(); let ptr = std::ptr::from_exposed_addr_mut::(addr); - unsafe { ptr.write(0) }; //~ ERROR: borrow stack + unsafe { *ptr = 0 }; //~ ERROR: borrow stack } diff --git a/tests/fail/stacked_borrows/exposed_only_ro.stderr b/tests/fail/stacked_borrows/exposed_only_ro.stderr new file mode 100644 index 0000000000000..9748fe78c7184 --- /dev/null +++ b/tests/fail/stacked_borrows/exposed_only_ro.stderr @@ -0,0 +1,18 @@ +error: Undefined Behavior: attempting a write access using "" at ALLOC[0x0], but no exposed tags are valid in the borrow stack for this location + --> $DIR/exposed_only_ro.rs:LL:CC + | +LL | unsafe { *ptr = 0 }; + | ^^^^^^^^ + | | + | attempting a write access using "" at ALLOC[0x0], but no exposed tags are valid in the borrow stack for this location + | this error occurs as part of an access at ALLOC[0x0..0x4] + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information + + = note: inside `main` at $DIR/exposed_only_ro.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/pass/stacked-borrows/int-to-ptr.rs b/tests/pass/stacked-borrows/int-to-ptr.rs index dc581d8af618f..dc3675406276f 100644 --- a/tests/pass/stacked-borrows/int-to-ptr.rs +++ b/tests/pass/stacked-borrows/int-to-ptr.rs @@ -13,63 +13,67 @@ fn ref_raw_int_raw() { } /// Ensure that we do not just pick the topmost possible item on int2ptr casts. -fn example(variant: bool) { unsafe { - fn not_so_innocent(x: &mut u32) -> usize { - let x_raw4 = x as *mut u32; - x_raw4.expose_addr() - } +fn example(variant: bool) { + unsafe { + fn not_so_innocent(x: &mut u32) -> usize { + let x_raw4 = x as *mut u32; + x_raw4.expose_addr() + } + + let mut c = 42u32; + + let x_unique1 = &mut c; + // [..., Unique(1)] + + let x_raw2 = x_unique1 as *mut u32; + let x_raw2_addr = x_raw2.expose_addr(); + // [..., Unique(1), SharedRW(2)] + + let x_unique3 = &mut *x_raw2; + // [.., Unique(1), SharedRW(2), Unique(3)] - let mut c = 42u32; + assert_eq!(not_so_innocent(x_unique3), x_raw2_addr); + // [.., Unique(1), SharedRW(2), Unique(3), ..., SharedRW(4)] - let x_unique1 = &mut c; - // [..., Unique(1)] - - let x_raw2 = x_unique1 as *mut u32; - let x_raw2_addr = x_raw2.expose_addr(); - // [..., Unique(1), SharedRW(2)] - - let x_unique3 = &mut *x_raw2; - // [.., Unique(1), SharedRW(2), Unique(3)] - - assert_eq!(not_so_innocent(x_unique3), x_raw2_addr); - // [.., Unique(1), SharedRW(2), Unique(3), ..., SharedRW(4)] - - // Do an int2ptr cast. This can pick tag 2 or 4 (the two previously exposed tags). - // 4 is the "obvious" choice (topmost tag, what we used to do with untagged pointers). - // And indeed if `variant == true` it is the only possible choice. - // But if `variant == false` then 2 is the only possible choice! - let x_wildcard = ptr::from_exposed_addr_mut::(x_raw2_addr); - - if variant { - // If we picked 2, this will invalidate 3. - *x_wildcard = 10; - // Now we use 3. Only possible if above we picked 4. - *x_unique3 = 12; - } else { - // This invalidates tag 4. - *x_unique3 = 10; - // Now try to write with the "guessed" tag; it must be 2. - *x_wildcard = 12; + // Do an int2ptr cast. This can pick tag 2 or 4 (the two previously exposed tags). + // 4 is the "obvious" choice (topmost tag, what we used to do with untagged pointers). + // And indeed if `variant == true` it is the only possible choice. + // But if `variant == false` then 2 is the only possible choice! + let x_wildcard = ptr::from_exposed_addr_mut::(x_raw2_addr); + + if variant { + // If we picked 2, this will invalidate 3. + *x_wildcard = 10; + // Now we use 3. Only possible if above we picked 4. + *x_unique3 = 12; + } else { + // This invalidates tag 4. + *x_unique3 = 10; + // Now try to write with the "guessed" tag; it must be 2. + *x_wildcard = 12; + } } -} } +} -fn test() { unsafe { - let root = &mut 42; - let root_raw = root as *mut i32; - let addr1 = root_raw as usize; - let child = &mut *root_raw; - let child_raw = child as *mut i32; - let addr2 = child_raw as usize; - assert_eq!(addr1, addr2); - // First use child. - *(addr2 as *mut i32) -= 2; // picks child_raw - *child -= 2; - // Then use root. - *(addr1 as *mut i32) += 2; // picks root_raw - *root += 2; - // Value should be unchanged. - assert_eq!(*root, 42); -} } +fn test() { + unsafe { + let root = &mut 42; + let root_raw = root as *mut i32; + let addr1 = root_raw as usize; + let child = &mut *root_raw; + let child_raw = child as *mut i32; + let addr2 = child_raw as usize; + assert_eq!(addr1, addr2); + // First use child. + *(addr2 as *mut i32) -= 2; // picks child_raw + *child -= 2; + // Then use root. + *(addr1 as *mut i32) += 2; // picks root_raw + *root += 2; + // Value should be unchanged. + assert_eq!(*root, 42); + } +} fn main() { ref_raw_int_raw(); From 2f9750783ced5099b90086af4a23f5af000a9f28 Mon Sep 17 00:00:00 2001 From: Wesley Wiser Date: Fri, 24 Jun 2022 19:04:50 -0400 Subject: [PATCH 3312/3747] Update measureme to the latest version --- Cargo.lock | 4 ++-- Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 29b7e0bec26ad..880fa271d97db 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -231,9 +231,9 @@ dependencies = [ [[package]] name = "measureme" -version = "9.1.2" +version = "10.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78f7a41bc6f856a2cf0e95094ad5121f82500e2d9a0f3c0171d98f6566d8117d" +checksum = "cbdc226fa10994e8f66a4d2f6f000148bc563a1c671b6dcd2135737018033d8a" dependencies = [ "log", "memmap2", diff --git a/Cargo.toml b/Cargo.toml index cf6f4c8b2ee96..6b7f369ae5a98 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -29,7 +29,7 @@ smallvec = "1.7" # See the `src/tools/rustc-workspace-hack/README.md` file in `rust-lang/rust` # for more information. rustc-workspace-hack = "1.0.0" -measureme = "9.1.2" +measureme = "10.0.0" # Enable some feature flags that dev-dependencies need but dependencies # do not. This makes `./miri install` after `./miri build` faster. From 4fbb284a99d0eceeefcf7f7fdb5c6c545ea68ae2 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 24 Jun 2022 19:45:35 -0400 Subject: [PATCH 3313/3747] implement 'delimited' expose tracking so we still detect some UB --- src/diagnostics.rs | 8 +- src/intptrcast.rs | 8 +- src/lib.rs | 9 +- src/machine.rs | 34 ++- src/stacked_borrows.rs | 227 ++++++++++++------ src/stacked_borrows/diagnostics.rs | 23 +- .../stacked_borrows/exposed_only_ro.stderr | 4 +- .../illegal_read_despite_exposed1.rs | 17 ++ .../illegal_read_despite_exposed1.stderr | 18 ++ .../illegal_read_despite_exposed2.rs | 18 ++ .../illegal_read_despite_exposed2.stderr | 18 ++ .../illegal_write_despite_exposed1.rs | 16 ++ .../illegal_write_despite_exposed1.stderr | 18 ++ 13 files changed, 293 insertions(+), 125 deletions(-) create mode 100644 tests/fail/stacked_borrows/illegal_read_despite_exposed1.rs create mode 100644 tests/fail/stacked_borrows/illegal_read_despite_exposed1.stderr create mode 100644 tests/fail/stacked_borrows/illegal_read_despite_exposed2.rs create mode 100644 tests/fail/stacked_borrows/illegal_read_despite_exposed2.stderr create mode 100644 tests/fail/stacked_borrows/illegal_write_despite_exposed1.rs create mode 100644 tests/fail/stacked_borrows/illegal_write_despite_exposed1.stderr diff --git a/src/diagnostics.rs b/src/diagnostics.rs index 0e3e693e33f90..230f46c569dbf 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -8,7 +8,7 @@ use rustc_middle::ty; use rustc_span::{source_map::DUMMY_SP, Span, SpanData, Symbol}; use crate::helpers::HexRange; -use crate::stacked_borrows::{diagnostics::TagHistory, AccessKind, SbTag}; +use crate::stacked_borrows::{diagnostics::TagHistory, AccessKind}; use crate::*; /// Details of premature program termination. @@ -61,9 +61,9 @@ impl MachineStopType for TerminationInfo {} /// Miri specific diagnostics pub enum NonHaltingDiagnostic { CreatedPointerTag(NonZeroU64), - /// This `Item` was popped from the borrow stack, either due to a grant of - /// `AccessKind` to `SbTag` or a deallocation when the second argument is `None`. - PoppedPointerTag(Item, Option<(SbTag, AccessKind)>), + /// This `Item` was popped from the borrow stack, either due to an access with the given tag or + /// a deallocation when the second argument is `None`. + PoppedPointerTag(Item, Option<(SbTagExtra, AccessKind)>), CreatedCallId(CallId), CreatedAlloc(AllocId), FreedAlloc(AllocId), diff --git a/src/intptrcast.rs b/src/intptrcast.rs index 9ec96b8f491e2..cfaf61f9d5c88 100644 --- a/src/intptrcast.rs +++ b/src/intptrcast.rs @@ -142,9 +142,7 @@ impl<'mir, 'tcx> GlobalStateInner { // Determine the allocation this points to at cast time. let alloc_id = Self::alloc_id_from_addr(ecx, addr); Pointer::new( - alloc_id.map(|alloc_id| { - Tag::Concrete(ConcreteTag { alloc_id, sb: SbTag::Untagged }) - }), + alloc_id.map(|alloc_id| Tag::Concrete { alloc_id, sb: SbTag::Untagged }), Size::from_bytes(addr), ) } @@ -222,8 +220,8 @@ impl<'mir, 'tcx> GlobalStateInner { ) -> Option<(AllocId, Size)> { let (tag, addr) = ptr.into_parts(); // addr is absolute (Tag provenance) - let alloc_id = if let Tag::Concrete(concrete) = tag { - concrete.alloc_id + let alloc_id = if let Tag::Concrete { alloc_id, .. } = tag { + alloc_id } else { // A wildcard pointer. assert_eq!(ecx.machine.intptrcast.borrow().provenance_mode, ProvenanceMode::Permissive); diff --git a/src/lib.rs b/src/lib.rs index 432f469733cbe..68489c9b47b96 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -7,6 +7,7 @@ #![feature(io_error_more)] #![feature(yeet_expr)] #![feature(is_some_with)] +#![feature(nonzero_ops)] #![warn(rust_2018_idioms)] #![allow( clippy::collapsible_else_if, @@ -81,15 +82,15 @@ pub use crate::eval::{ pub use crate::helpers::{CurrentSpan, EvalContextExt as HelpersEvalContextExt}; pub use crate::intptrcast::ProvenanceMode; pub use crate::machine::{ - AllocExtra, ConcreteTag, Evaluator, FrameData, MiriEvalContext, MiriEvalContextExt, - MiriMemoryKind, Tag, NUM_CPUS, PAGE_SIZE, STACK_ADDR, STACK_SIZE, + AllocExtra, Evaluator, FrameData, MiriEvalContext, MiriEvalContextExt, MiriMemoryKind, Tag, + NUM_CPUS, PAGE_SIZE, STACK_ADDR, STACK_SIZE, }; pub use crate::mono_hash_map::MonoHashMap; pub use crate::operator::EvalContextExt as OperatorEvalContextExt; pub use crate::range_map::RangeMap; pub use crate::stacked_borrows::{ - CallId, EvalContextExt as StackedBorEvalContextExt, Item, Permission, PtrId, SbTag, Stack, - Stacks, + CallId, EvalContextExt as StackedBorEvalContextExt, Item, Permission, PtrId, SbTag, SbTagExtra, + Stack, Stacks, }; pub use crate::sync::{CondvarId, EvalContextExt as SyncEvalContextExt, MutexId, RwLockId}; pub use crate::thread::{ diff --git a/src/machine.rs b/src/machine.rs index 3704a53851418..5810ac6d7ecac 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -130,17 +130,14 @@ impl fmt::Display for MiriMemoryKind { /// Pointer provenance (tag). #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub enum Tag { - Concrete(ConcreteTag), + Concrete { + alloc_id: AllocId, + /// Stacked Borrows tag. + sb: SbTag, + }, Wildcard, } -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub struct ConcreteTag { - pub alloc_id: AllocId, - /// Stacked Borrows tag. - pub sb: SbTag, -} - #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] static_assert_size!(Pointer, 24); // #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] @@ -160,15 +157,15 @@ impl Provenance for Tag { write!(f, "0x{:x}", addr.bytes())?; match tag { - Tag::Concrete(tag) => { + Tag::Concrete { alloc_id, sb } => { // Forward `alternate` flag to `alloc_id` printing. if f.alternate() { - write!(f, "[{:#?}]", tag.alloc_id)?; + write!(f, "[{:#?}]", alloc_id)?; } else { - write!(f, "[{:?}]", tag.alloc_id)?; + write!(f, "[{:?}]", alloc_id)?; } // Print Stacked Borrows tag. - write!(f, "{:?}", tag.sb)?; + write!(f, "{:?}", sb)?; } Tag::Wildcard => { write!(f, "[Wildcard]")?; @@ -180,7 +177,7 @@ impl Provenance for Tag { fn get_alloc_id(self) -> Option { match self { - Tag::Concrete(concrete) => Some(concrete.alloc_id), + Tag::Concrete { alloc_id, .. } => Some(alloc_id), Tag::Wildcard => None, } } @@ -489,8 +486,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { type AllocExtra = AllocExtra; type PointerTag = Tag; - // `None` represents a wildcard pointer. - type TagExtra = Option; + type TagExtra = SbTagExtra; type MemoryMap = MonoHashMap, Allocation)>; @@ -683,7 +679,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { SbTag::Untagged }; Pointer::new( - Tag::Concrete(ConcreteTag { alloc_id: ptr.provenance, sb: sb_tag }), + Tag::Concrete { alloc_id: ptr.provenance, sb: sb_tag }, Size::from_bytes(absolute_addr), ) } @@ -709,7 +705,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { ptr: Pointer, ) -> InterpResult<'tcx> { match ptr.provenance { - Tag::Concrete(ConcreteTag { alloc_id, sb }) => { + Tag::Concrete { alloc_id, sb } => { intptrcast::GlobalStateInner::expose_ptr(ecx, alloc_id, sb); } Tag::Wildcard => { @@ -730,8 +726,8 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { rel.map(|(alloc_id, size)| { let sb = match ptr.provenance { - Tag::Concrete(ConcreteTag { sb, .. }) => Some(sb), - Tag::Wildcard => None, + Tag::Concrete { sb, .. } => SbTagExtra::Concrete(sb), + Tag::Wildcard => SbTagExtra::Wildcard, }; (alloc_id, size, sb) }) diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 8411d85f0e019..b7b339ce77bf0 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -3,6 +3,7 @@ use log::trace; use std::cell::RefCell; +use std::cmp; use std::fmt; use std::num::NonZeroU64; @@ -60,6 +61,32 @@ impl fmt::Debug for SbTag { } } +/// The "extra" information an SB pointer has over a regular AllocId. +/// Newtype for `Option`. +#[derive(Copy, Clone)] +pub enum SbTagExtra { + Concrete(SbTag), + Wildcard, +} + +impl fmt::Debug for SbTagExtra { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + SbTagExtra::Concrete(tag) => write!(f, "{tag:?}"), + SbTagExtra::Wildcard => write!(f, ""), + } + } +} + +impl SbTagExtra { + fn and_then(self, f: impl FnOnce(SbTag) -> Option) -> Option { + match self { + SbTagExtra::Concrete(tag) => f(tag), + SbTagExtra::Wildcard => None, + } + } +} + /// Indicates which permission is granted (by this item to some pointers) #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] pub enum Permission { @@ -108,6 +135,8 @@ pub struct Stack { /// wildcard pointers are used to access this location. What we do know is that `borrows` are at /// the top of the stack, and below it are arbitrarily many items whose `tag` is either /// `Untagged` or strictly less than `id`. + /// When the bottom is unknown, `borrows` always has a `SharedReadOnly` or `Unique` at the bottom; + /// we never have the unknown-to-known boundary in an SRW group. unknown_bottom: Option, } @@ -289,35 +318,37 @@ impl Permission { /// Core per-location operations: access, dealloc, reborrow. impl<'tcx> Stack { /// Find the item granting the given kind of access to the given tag, and return where - /// it is on the stack. - /// `Ok(None)` indicates it matched the "unknown" part of the stack, or it was a wildcard tag - /// and we have no clue what exactly it matched (but it could have matched something) + /// it is on the stack. For wildcard tags, the given index is approximate, but if *no* + /// index is given it means the match was *not* in the known part of the stack. + /// `Ok(None)` indicates it matched the "unknown" part of the stack. /// `Err` indicates it was not found. fn find_granting( &self, access: AccessKind, - tag: Option, + tag: SbTagExtra, exposed_tags: &FxHashSet, ) -> Result, ()> { - let Some(tag) = tag else { + let SbTagExtra::Concrete(tag) = tag else { // Handle the wildcard case. // Go search the stack for an exposed tag. - let maybe_in_stack = self - .borrows - .iter() - .rev() // search top-to-bottom - .find_map(|item| { - // If the item fits and *might* be this wildcard, use it. - if item.perm.grants(access) && exposed_tags.contains(&item.tag) { - Some(()) - } else { - None - } - }) - .is_some(); + if let Some(idx) = + self.borrows + .iter() + .enumerate() // we also need to know *where* in the stack + .rev() // search top-to-bottom + .find_map(|(idx, item)| { + // If the item fits and *might* be this wildcard, use it. + if item.perm.grants(access) && exposed_tags.contains(&item.tag) { + Some(idx) + } else { + None + } + }) + { + return Ok(Some(idx)); + } // If we couldn't find it in the stack, check the unknown bottom. - let found = maybe_in_stack || self.unknown_bottom.is_some(); - return if found { Ok(None) } else { Err(()) }; + return if self.unknown_bottom.is_some() { Ok(None) } else { Err(()) }; }; if let Some(idx) = @@ -351,8 +382,10 @@ impl<'tcx> Stack { match perm { Permission::SharedReadOnly => bug!("Cannot use SharedReadOnly for writing"), Permission::Disabled => bug!("Cannot use Disabled for anything"), - // On a write, everything above us is incompatible. - Permission::Unique => granting + 1, + Permission::Unique => { + // On a write, everything above us is incompatible. + granting + 1 + } Permission::SharedReadWrite => { // The SharedReadWrite *just* above us are compatible, to skip those. let mut idx = granting + 1; @@ -380,7 +413,7 @@ impl<'tcx> Stack { /// currently checking. fn check_protector( item: &Item, - provoking_access: Option<(SbTag, AllocRange, Size, AccessKind)>, // just for debug printing and error messages + provoking_access: Option<(SbTagExtra, AllocRange, Size, AccessKind)>, // just for debug printing and error messages global: &GlobalStateInner, alloc_history: &mut AllocHistory, ) -> InterpResult<'tcx> { @@ -401,12 +434,14 @@ impl<'tcx> Stack { tag, item ), None, - alloc_history.get_logs_relevant_to( - tag, - alloc_range, - offset, - Some(item.tag), - ), + tag.and_then(|tag| { + alloc_history.get_logs_relevant_to( + tag, + alloc_range, + offset, + Some(item.tag), + ) + }), ))? } else { Err(err_sb_ub( @@ -427,7 +462,7 @@ impl<'tcx> Stack { fn access( &mut self, access: AccessKind, - tag: Option, + tag: SbTagExtra, (alloc_id, alloc_range, offset): (AllocId, AllocRange, Size), // just for debug printing and error messages global: &mut GlobalStateInner, current_span: &mut CurrentSpan<'_, '_, 'tcx>, @@ -441,22 +476,22 @@ impl<'tcx> Stack { alloc_history.access_error(access, tag, alloc_id, alloc_range, offset, self) })?; - let Some(granting_idx) = granting_idx else { - // The access used a wildcard pointer or matched the unknown bottom. - // Nobody knows what happened, so forget everything. - trace!("access: clearing stack due to wildcard"); - self.borrows.clear(); - self.unknown_bottom = Some(global.next_ptr_id); - return Ok(()); - }; - let tag = tag.unwrap(); // only precise tags have precise locations - // Step 2: Remove incompatible items above them. Make sure we do not remove protected // items. Behavior differs for reads and writes. + // In case of wildcards/unknown matches, we remove everything that is *definitely* gone. if access == AccessKind::Write { // Remove everything above the write-compatible items, like a proper stack. This makes sure read-only and unique // pointers become invalid on write accesses (ensures F2a, and ensures U2 for write accesses). - let first_incompatible_idx = self.find_first_write_incompatible(granting_idx); + let first_incompatible_idx = if let Some(granting_idx) = granting_idx { + // The granting_idx *might* be approximate, but any lower idx would remove more + // things. Even if this is a Unique and the lower idx is an SRW (which removes + // less), there is an SRW group boundary here so strictly more would get removed. + self.find_first_write_incompatible(granting_idx) + } else { + // We are writing to something in the unknown part. + // There is a SRW group boundary between the unknown and the known, so everything is incompatible. + 0 + }; for item in self.borrows.drain(first_incompatible_idx..).rev() { trace!("access: popping item {:?}", item); Stack::check_protector( @@ -476,7 +511,13 @@ impl<'tcx> Stack { // This pattern occurs a lot in the standard library: create a raw pointer, then also create a shared // reference and use that. // We *disable* instead of removing `Unique` to avoid "connecting" two neighbouring blocks of SRWs. - let first_incompatible_idx = granting_idx + 1; + let first_incompatible_idx = if let Some(granting_idx) = granting_idx { + // The granting_idx *might* be approximate, but any lower idx would disable more things. + granting_idx + 1 + } else { + // We are reading from something in the unknown part. That means *all* `Unique` we know about are dead now. + 0 + }; for idx in (first_incompatible_idx..self.borrows.len()).rev() { let item = &mut self.borrows[idx]; @@ -494,6 +535,31 @@ impl<'tcx> Stack { } } + // If this was an approximate action, we now collapse everything into an unknown. + if granting_idx.is_none() || matches!(tag, SbTagExtra::Wildcard) { + // Compute the upper bound of the items that remain. + // (This is why we did all the work above: to reduce the items we have to consider here.) + let mut max = NonZeroU64::new(1).unwrap(); + for item in &self.borrows { + // Skip disabled items, they cannot be matched anyway. + if !matches!(item.perm, Permission::Disabled) { + if let SbTag::Tagged(tag) = item.tag { + // We are looking for a strict upper bound, so add 1 to this tag. + max = cmp::max(tag.checked_add(1).unwrap(), max); + } + } + } + if let Some(unk) = self.unknown_bottom { + max = cmp::max(unk, max); + } + // Use `max` as new strict upper bound for everything. + trace!( + "access: forgetting stack to upper bound {max} due to wildcard or unknown access" + ); + self.borrows.clear(); + self.unknown_bottom = Some(max); + } + // Done. Ok(()) } @@ -502,7 +568,7 @@ impl<'tcx> Stack { /// active protectors at all because we will remove all items. fn dealloc( &mut self, - tag: Option, + tag: SbTagExtra, (alloc_id, alloc_range, offset): (AllocId, AllocRange, Size), // just for debug printing and error messages global: &GlobalStateInner, alloc_history: &mut AllocHistory, @@ -534,7 +600,7 @@ impl<'tcx> Stack { /// `range` that we are currently checking. fn grant( &mut self, - derived_from: Option, + derived_from: SbTagExtra, new: Item, (alloc_id, alloc_range, offset): (AllocId, AllocRange, Size), // just for debug printing and error messages global: &mut GlobalStateInner, @@ -562,10 +628,12 @@ impl<'tcx> Stack { "this case only makes sense for stack-like accesses" ); - let Some(granting_idx) = granting_idx else { + let (Some(granting_idx), SbTagExtra::Concrete(_)) = (granting_idx, derived_from) else { // The parent is a wildcard pointer or matched the unknown bottom. - // Nobody knows what happened, so forget everything. - trace!("reborrow: clearing stack due to wildcard"); + // This is approximate. Nobody knows what happened, so forget everything. + // The new thing is SRW anyway, so we cannot push it "on top of the unkown part" + // (for all we know, it might join an SRW group inside the unknown). + trace!("reborrow: forgetting stack entirely due to SharedReadWrite reborrow from wildcard or unknown"); self.borrows.clear(); self.unknown_bottom = Some(global.next_ptr_id); return Ok(()); @@ -723,7 +791,7 @@ impl Stacks { pub fn memory_read<'tcx>( &self, alloc_id: AllocId, - tag: Option, + tag: SbTagExtra, range: AllocRange, state: &GlobalState, mut current_span: CurrentSpan<'_, '_, 'tcx>, @@ -752,7 +820,7 @@ impl Stacks { pub fn memory_written<'tcx>( &mut self, alloc_id: AllocId, - tag: Option, + tag: SbTagExtra, range: AllocRange, state: &GlobalState, mut current_span: CurrentSpan<'_, '_, 'tcx>, @@ -781,7 +849,7 @@ impl Stacks { pub fn memory_deallocated<'tcx>( &mut self, alloc_id: AllocId, - tag: Option, + tag: SbTagExtra, range: AllocRange, state: &GlobalState, ) -> InterpResult<'tcx> { @@ -798,6 +866,8 @@ impl Stacks { /// to grant for which references, and when to add protectors. impl<'mir, 'tcx: 'mir> EvalContextPrivExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { + /// Returns the `AllocId` the reborrow was done in, if some actual borrow stack manipulation + /// happened. fn reborrow( &mut self, place: &MPlaceTy<'tcx, Tag>, @@ -805,7 +875,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx kind: RefKind, new_tag: SbTag, protect: bool, - ) -> InterpResult<'tcx> { + ) -> InterpResult<'tcx, Option> { let this = self.eval_context_mut(); let current_span = &mut this.machine.current_span(); @@ -815,6 +885,10 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx base_offset, orig_tag| -> InterpResult<'tcx> { + let SbTagExtra::Concrete(orig_tag) = orig_tag else { + // FIXME: should we log this? + return Ok(()) + }; let extra = this.get_alloc_extra(alloc_id)?; let stacked_borrows = extra.stacked_borrows.as_ref().expect("we should have Stacked Borrows data"); @@ -832,6 +906,13 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx }; if size == Size::ZERO { + trace!( + "reborrow of size 0: {} reference {:?} derived from {:?} (pointee {})", + kind, + new_tag, + place.ptr, + place.layout.ty, + ); // Don't update any stacks for a zero-sized access; borrow stacks are per-byte and this // touches no bytes so there is no stack to put this tag in. // However, if the pointer for this operation points at a real allocation we still @@ -840,24 +921,14 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Dangling slices are a common case here; it's valid to get their length but with raw // pointer tagging for example all calls to get_unchecked on them are invalid. if let Ok((alloc_id, base_offset, orig_tag)) = this.ptr_try_get_alloc_id(place.ptr) { - if let Some(orig_tag) = orig_tag { - log_creation(this, current_span, alloc_id, base_offset, orig_tag)?; - } + log_creation(this, current_span, alloc_id, base_offset, orig_tag)?; + return Ok(Some(alloc_id)); } - - trace!( - "reborrow of size 0: {} reference {:?} derived from {:?} (pointee {})", - kind, - new_tag, - place.ptr, - place.layout.ty, - ); - return Ok(()); + // This pointer doesn't come with an AllocId. :shrug: + return Ok(None); } let (alloc_id, base_offset, orig_tag) = this.ptr_get_alloc_id(place.ptr)?; - if let Some(orig_tag) = orig_tag { - log_creation(this, current_span, alloc_id, base_offset, orig_tag)?; - } + log_creation(this, current_span, alloc_id, base_offset, orig_tag)?; // Ensure we bail out if the pointer goes out-of-bounds (see miri#1050). let (alloc_size, _) = @@ -937,7 +1008,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) }) })?; - return Ok(()); + return Ok(Some(alloc_id)); } }; // Here we can avoid `borrow()` calls because we have mutable references. @@ -962,7 +1033,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) })?; - Ok(()) + Ok(Some(alloc_id)) } /// Retags an indidual pointer, returning the retagged version. @@ -997,16 +1068,22 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx }; // Reborrow. - this.reborrow(&place, size, kind, new_tag, protect)?; + let alloc_id = this.reborrow(&place, size, kind, new_tag, protect)?; // Adjust pointer. let new_place = place.map_provenance(|p| { - p.map(|t| { - // TODO: Fix this eventually - if let Tag::Concrete(t) = t { - Tag::Concrete(ConcreteTag { sb: new_tag, ..t }) - } else { - t + p.map(|prov| { + match alloc_id { + Some(alloc_id) => { + // If `reborrow` could figure out the AllocId of this ptr, hard-code it into the new one. + // Even if we started out with a wildcard, this newly retagged pointer is tied to that allocation. + Tag::Concrete { alloc_id, sb: new_tag } + } + None => { + // Looks like this has to stay a wildcard pointer. + assert!(matches!(prov, Tag::Wildcard)); + Tag::Wildcard + } } }) }); diff --git a/src/stacked_borrows/diagnostics.rs b/src/stacked_borrows/diagnostics.rs index 91dfe22c19649..d3c706c1404ab 100644 --- a/src/stacked_borrows/diagnostics.rs +++ b/src/stacked_borrows/diagnostics.rs @@ -4,12 +4,11 @@ use rustc_middle::mir::interpret::{AllocId, AllocRange}; use rustc_span::{Span, SpanData}; use rustc_target::abi::Size; -use core::fmt::Debug; - use crate::helpers::{CurrentSpan, HexRange}; use crate::stacked_borrows::{err_sb_ub, AccessKind, Permission}; use crate::Item; use crate::SbTag; +use crate::SbTagExtra; use crate::Stack; use rustc_middle::mir::interpret::InterpError; @@ -199,19 +198,15 @@ impl AllocHistory { /// Report a descriptive error when `new` could not be granted from `derived_from`. pub fn grant_error<'tcx>( &self, - derived_from: Option, + derived_from: SbTagExtra, new: Item, alloc_id: AllocId, alloc_range: AllocRange, error_offset: Size, stack: &Stack, ) -> InterpError<'tcx> { - // TODO: Fix this properly - let z = &derived_from; - let f = if let Some(ref t) = z { t as &dyn Debug } else { &"" as &dyn Debug }; let action = format!( - "trying to reborrow {:?} for {:?} permission at {}[{:#x}]", - f, + "trying to reborrow {derived_from:?} for {:?} permission at {}[{:#x}]", new.perm, alloc_id, error_offset.bytes(), @@ -229,18 +224,14 @@ impl AllocHistory { pub fn access_error<'tcx>( &self, access: AccessKind, - tag: Option, + tag: SbTagExtra, alloc_id: AllocId, alloc_range: AllocRange, error_offset: Size, stack: &Stack, ) -> InterpError<'tcx> { - let z = &tag; - let f = if let Some(ref t) = z { t as &dyn Debug } else { &"" as &dyn Debug }; let action = format!( - "attempting a {} using {:?} at {}[{:#x}]", - access, - f, + "attempting a {access} using {tag:?} at {}[{:#x}]", alloc_id, error_offset.bytes(), ); @@ -260,8 +251,8 @@ fn operation_summary( format!("this error occurs as part of {} at {:?}{}", operation, alloc_id, HexRange(alloc_range)) } -fn error_cause(stack: &Stack, tag: Option) -> &'static str { - if let Some(tag) = tag { +fn error_cause(stack: &Stack, tag: SbTagExtra) -> &'static str { + if let SbTagExtra::Concrete(tag) = tag { if stack.borrows.iter().any(|item| item.tag == tag && item.perm != Permission::Disabled) { ", but that tag only grants SharedReadOnly permission for this location" } else { diff --git a/tests/fail/stacked_borrows/exposed_only_ro.stderr b/tests/fail/stacked_borrows/exposed_only_ro.stderr index 9748fe78c7184..ceeca61e5587a 100644 --- a/tests/fail/stacked_borrows/exposed_only_ro.stderr +++ b/tests/fail/stacked_borrows/exposed_only_ro.stderr @@ -1,10 +1,10 @@ -error: Undefined Behavior: attempting a write access using "" at ALLOC[0x0], but no exposed tags are valid in the borrow stack for this location +error: Undefined Behavior: attempting a write access using at ALLOC[0x0], but no exposed tags are valid in the borrow stack for this location --> $DIR/exposed_only_ro.rs:LL:CC | LL | unsafe { *ptr = 0 }; | ^^^^^^^^ | | - | attempting a write access using "" at ALLOC[0x0], but no exposed tags are valid in the borrow stack for this location + | attempting a write access using at ALLOC[0x0], but no exposed tags are valid in the borrow stack for this location | this error occurs as part of an access at ALLOC[0x0..0x4] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental diff --git a/tests/fail/stacked_borrows/illegal_read_despite_exposed1.rs b/tests/fail/stacked_borrows/illegal_read_despite_exposed1.rs new file mode 100644 index 0000000000000..61a5e05d34cd3 --- /dev/null +++ b/tests/fail/stacked_borrows/illegal_read_despite_exposed1.rs @@ -0,0 +1,17 @@ +// compile-flags: -Zmiri-permissive-provenance + +fn main() { + unsafe { + let root = &mut 42; + let addr = root as *mut i32 as usize; + let exposed_ptr = addr as *mut i32; + // From the exposed ptr, we get a new unique ptr. + let root2 = &mut *exposed_ptr; + let _fool = root2 as *mut _; // this would have fooled the old untagged pointer logic + // Stack: Unknown( at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + --> $DIR/illegal_read_despite_exposed1.rs:LL:CC + | +LL | let _val = *root2; + | ^^^^^^ + | | + | attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | this error occurs as part of an access at ALLOC[0x0..0x4] + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information + + = note: inside `main` at $DIR/illegal_read_despite_exposed1.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/fail/stacked_borrows/illegal_read_despite_exposed2.rs b/tests/fail/stacked_borrows/illegal_read_despite_exposed2.rs new file mode 100644 index 0000000000000..b45b7b5d285c2 --- /dev/null +++ b/tests/fail/stacked_borrows/illegal_read_despite_exposed2.rs @@ -0,0 +1,18 @@ +// compile-flags: -Zmiri-permissive-provenance + +fn main() { + unsafe { + let root = &mut 42; + let addr = root as *mut i32 as usize; + let exposed_ptr = addr as *mut i32; + // From the exposed ptr, we get a new unique ptr. + let root2 = &mut *exposed_ptr; + // let _fool = root2 as *mut _; // this would [fool] us, since SRW(N+1) remains on the stack + // Stack: Unknown( at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + --> $DIR/illegal_read_despite_exposed2.rs:LL:CC + | +LL | let _val = *root2; + | ^^^^^^ + | | + | attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | this error occurs as part of an access at ALLOC[0x0..0x4] + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information + + = note: inside `main` at $DIR/illegal_read_despite_exposed2.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/fail/stacked_borrows/illegal_write_despite_exposed1.rs b/tests/fail/stacked_borrows/illegal_write_despite_exposed1.rs new file mode 100644 index 0000000000000..b50399b9df521 --- /dev/null +++ b/tests/fail/stacked_borrows/illegal_write_despite_exposed1.rs @@ -0,0 +1,16 @@ +// compile-flags: -Zmiri-permissive-provenance + +fn main() { + unsafe { + let root = &mut 42; + let addr = root as *mut i32 as usize; + let exposed_ptr = addr as *mut i32; + // From the exposed ptr, we get a new SRO ptr. + let root2 = &*exposed_ptr; + // Stack: Unknown( at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + --> $DIR/illegal_write_despite_exposed1.rs:LL:CC + | +LL | let _val = *root2; + | ^^^^^^ + | | + | attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | this error occurs as part of an access at ALLOC[0x0..0x4] + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information + + = note: inside `main` at $DIR/illegal_write_despite_exposed1.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + From 58c79c5b6f2717241ec14aa61442b98ca8b66d00 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 24 Jun 2022 22:02:17 -0400 Subject: [PATCH 3314/3747] tweaks and feedback --- src/machine.rs | 8 +- src/stacked_borrows.rs | 84 ++++++++----------- src/stacked_borrows/diagnostics.rs | 2 +- .../stacked_borrows/exposed_only_ro.stderr | 4 +- .../illegal_read_despite_exposed2.rs | 10 ++- 5 files changed, 48 insertions(+), 60 deletions(-) diff --git a/src/machine.rs b/src/machine.rs index 5810ac6d7ecac..79414ada5eac9 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -646,7 +646,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { let alloc: Allocation = alloc.convert_tag_add_extra( &ecx.tcx, AllocExtra { - stacked_borrows: stacks, + stacked_borrows: stacks.map(RefCell::new), data_race: race_alloc, weak_memory: buffer_alloc, }, @@ -745,7 +745,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { data_race.read(alloc_id, range, machine.data_race.as_ref().unwrap())?; } if let Some(stacked_borrows) = &alloc_extra.stacked_borrows { - stacked_borrows.memory_read( + stacked_borrows.borrow_mut().memory_read( alloc_id, tag, range, @@ -771,7 +771,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { data_race.write(alloc_id, range, machine.data_race.as_mut().unwrap())?; } if let Some(stacked_borrows) = &mut alloc_extra.stacked_borrows { - stacked_borrows.memory_written( + stacked_borrows.get_mut().memory_written( alloc_id, tag, range, @@ -800,7 +800,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { data_race.deallocate(alloc_id, range, machine.data_race.as_mut().unwrap())?; } if let Some(stacked_borrows) = &mut alloc_extra.stacked_borrows { - stacked_borrows.memory_deallocated( + stacked_borrows.get_mut().memory_deallocated( alloc_id, tag, range, diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index b7b339ce77bf0..6fa70ddfc5d4e 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -25,7 +25,8 @@ use diagnostics::{AllocHistory, TagHistory}; pub type PtrId = NonZeroU64; pub type CallId = NonZeroU64; -pub type AllocExtra = Stacks; +// Even reading memory can have effects on the stack, so we need a `RefCell` here. +pub type AllocExtra = RefCell; /// Tracking pointer provenance #[derive(Copy, Clone, Hash, Eq)] @@ -131,7 +132,7 @@ pub struct Stack { /// * Above a `SharedReadOnly` there can only be more `SharedReadOnly`. /// * Except for `Untagged`, no tag occurs in the stack more than once. borrows: Vec, - /// If this is `Some(id)`, then the actual current stack is unknown. THis can happen when + /// If this is `Some(id)`, then the actual current stack is unknown. This can happen when /// wildcard pointers are used to access this location. What we do know is that `borrows` are at /// the top of the stack, and below it are arbitrarily many items whose `tag` is either /// `Untagged` or strictly less than `id`. @@ -144,11 +145,11 @@ pub struct Stack { #[derive(Clone, Debug)] pub struct Stacks { // Even reading memory can have effects on the stack, so we need a `RefCell` here. - stacks: RefCell>, + stacks: RangeMap, /// Stores past operations on this allocation - history: RefCell, + history: AllocHistory, /// The set of tags that have been exposed inside this allocation. - exposed_tags: RefCell>, + exposed_tags: FxHashSet, } /// Extra global state, available to the memory access hooks. @@ -689,34 +690,14 @@ impl<'tcx> Stacks { let stack = Stack { borrows: vec![item], unknown_bottom: None }; Stacks { - stacks: RefCell::new(RangeMap::new(size, stack)), - history: RefCell::new(AllocHistory::new()), - exposed_tags: RefCell::new(FxHashSet::default()), + stacks: RangeMap::new(size, stack), + history: AllocHistory::new(), + exposed_tags: FxHashSet::default(), } } /// Call `f` on every stack in the range. fn for_each( - &self, - range: AllocRange, - mut f: impl FnMut( - Size, - &mut Stack, - &mut AllocHistory, - &mut FxHashSet, - ) -> InterpResult<'tcx>, - ) -> InterpResult<'tcx> { - let mut stacks = self.stacks.borrow_mut(); - let history = &mut *self.history.borrow_mut(); - let exposed_tags = &mut *self.exposed_tags.borrow_mut(); - for (offset, stack) in stacks.iter_mut(range.start, range.size) { - f(offset, stack, history, exposed_tags)?; - } - Ok(()) - } - - /// Call `f` on every stack in the range. - fn for_each_mut( &mut self, range: AllocRange, mut f: impl FnMut( @@ -726,11 +707,8 @@ impl<'tcx> Stacks { &mut FxHashSet, ) -> InterpResult<'tcx>, ) -> InterpResult<'tcx> { - let stacks = self.stacks.get_mut(); - let history = &mut *self.history.get_mut(); - let exposed_tags = self.exposed_tags.get_mut(); - for (offset, stack) in stacks.iter_mut(range.start, range.size) { - f(offset, stack, history, exposed_tags)?; + for (offset, stack) in self.stacks.iter_mut(range.start, range.size) { + f(offset, stack, &mut self.history, &mut self.exposed_tags)?; } Ok(()) } @@ -777,8 +755,8 @@ impl Stacks { (tag, Permission::SharedReadWrite) } }; - let stacks = Stacks::new(size, perm, base_tag); - stacks.history.borrow_mut().log_creation( + let mut stacks = Stacks::new(size, perm, base_tag); + stacks.history.log_creation( None, base_tag, alloc_range(Size::ZERO, size), @@ -789,7 +767,7 @@ impl Stacks { #[inline(always)] pub fn memory_read<'tcx>( - &self, + &mut self, alloc_id: AllocId, tag: SbTagExtra, range: AllocRange, @@ -832,7 +810,7 @@ impl Stacks { range.size.bytes() ); let mut state = state.borrow_mut(); - self.for_each_mut(range, |offset, stack, history, exposed_tags| { + self.for_each(range, |offset, stack, history, exposed_tags| { stack.access( AccessKind::Write, tag, @@ -855,7 +833,7 @@ impl Stacks { ) -> InterpResult<'tcx> { trace!("deallocation with tag {:?}: {:?}, size {}", tag, alloc_id, range.size.bytes()); let state = state.borrow(); - self.for_each_mut(range, |offset, stack, history, exposed_tags| { + self.for_each(range, |offset, stack, history, exposed_tags| { stack.dealloc(tag, (alloc_id, range, offset), &state, history, exposed_tags) })?; Ok(()) @@ -890,17 +868,19 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx return Ok(()) }; let extra = this.get_alloc_extra(alloc_id)?; - let stacked_borrows = - extra.stacked_borrows.as_ref().expect("we should have Stacked Borrows data"); - let mut alloc_history = stacked_borrows.history.borrow_mut(); - alloc_history.log_creation( + let mut stacked_borrows = extra + .stacked_borrows + .as_ref() + .expect("we should have Stacked Borrows data") + .borrow_mut(); + stacked_borrows.history.log_creation( Some(orig_tag), new_tag, alloc_range(base_offset, size), current_span, ); if protect { - alloc_history.log_protector(orig_tag, new_tag, current_span); + stacked_borrows.history.log_protector(orig_tag, new_tag, current_span); } Ok(()) }; @@ -976,8 +956,11 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // We have to use shared references to alloc/memory_extra here since // `visit_freeze_sensitive` needs to access the global state. let extra = this.get_alloc_extra(alloc_id)?; - let stacked_borrows = - extra.stacked_borrows.as_ref().expect("we should have Stacked Borrows data"); + let mut stacked_borrows = extra + .stacked_borrows + .as_ref() + .expect("we should have Stacked Borrows data") + .borrow_mut(); this.visit_freeze_sensitive(place, size, |mut range, frozen| { // Adjust range. range.start += base_offset; @@ -1015,13 +998,16 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Note that this asserts that the allocation is mutable -- but since we are creating a // mutable pointer, that seems reasonable. let (alloc_extra, machine) = this.get_alloc_extra_mut(alloc_id)?; - let stacked_borrows = - alloc_extra.stacked_borrows.as_mut().expect("we should have Stacked Borrows data"); + let mut stacked_borrows = alloc_extra + .stacked_borrows + .as_mut() + .expect("we should have Stacked Borrows data") + .borrow_mut(); let item = Item { perm, tag: new_tag, protector }; let range = alloc_range(base_offset, size); let mut global = machine.stacked_borrows.as_ref().unwrap().borrow_mut(); let current_span = &mut machine.current_span(); // `get_alloc_extra_mut` invalidated our old `current_span` - stacked_borrows.for_each_mut(range, |offset, stack, history, exposed_tags| { + stacked_borrows.for_each(range, |offset, stack, history, exposed_tags| { stack.grant( orig_tag, item, @@ -1177,7 +1163,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx match this.get_alloc_extra(alloc_id) { Ok(alloc_extra) => { trace!("Stacked Borrows tag {tag:?} exposed in {alloc_id}"); - alloc_extra.stacked_borrows.as_ref().unwrap().exposed_tags.borrow_mut().insert(tag); + alloc_extra.stacked_borrows.as_ref().unwrap().borrow_mut().exposed_tags.insert(tag); } Err(err) => { trace!( diff --git a/src/stacked_borrows/diagnostics.rs b/src/stacked_borrows/diagnostics.rs index d3c706c1404ab..a4a7f5e7a1e35 100644 --- a/src/stacked_borrows/diagnostics.rs +++ b/src/stacked_borrows/diagnostics.rs @@ -259,6 +259,6 @@ fn error_cause(stack: &Stack, tag: SbTagExtra) -> &'static str { ", but that tag does not exist in the borrow stack for this location" } } else { - ", but no exposed tags are valid in the borrow stack for this location" + ", but no exposed tags have suitable permission in the borrow stack for this location" } } diff --git a/tests/fail/stacked_borrows/exposed_only_ro.stderr b/tests/fail/stacked_borrows/exposed_only_ro.stderr index ceeca61e5587a..28fa98b6020c0 100644 --- a/tests/fail/stacked_borrows/exposed_only_ro.stderr +++ b/tests/fail/stacked_borrows/exposed_only_ro.stderr @@ -1,10 +1,10 @@ -error: Undefined Behavior: attempting a write access using at ALLOC[0x0], but no exposed tags are valid in the borrow stack for this location +error: Undefined Behavior: attempting a write access using at ALLOC[0x0], but no exposed tags have suitable permission in the borrow stack for this location --> $DIR/exposed_only_ro.rs:LL:CC | LL | unsafe { *ptr = 0 }; | ^^^^^^^^ | | - | attempting a write access using at ALLOC[0x0], but no exposed tags are valid in the borrow stack for this location + | attempting a write access using at ALLOC[0x0], but no exposed tags have suitable permission in the borrow stack for this location | this error occurs as part of an access at ALLOC[0x0..0x4] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental diff --git a/tests/fail/stacked_borrows/illegal_read_despite_exposed2.rs b/tests/fail/stacked_borrows/illegal_read_despite_exposed2.rs index b45b7b5d285c2..19d0784591e49 100644 --- a/tests/fail/stacked_borrows/illegal_read_despite_exposed2.rs +++ b/tests/fail/stacked_borrows/illegal_read_despite_exposed2.rs @@ -7,12 +7,14 @@ fn main() { let exposed_ptr = addr as *mut i32; // From the exposed ptr, we get a new unique ptr. let root2 = &mut *exposed_ptr; - // let _fool = root2 as *mut _; // this would [fool] us, since SRW(N+1) remains on the stack - // Stack: Unknown( Date: Mon, 20 Jun 2022 15:16:32 -0400 Subject: [PATCH 3315/3747] Actually pass through the request for --color=always --- cargo-miri/bin.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index a7be5843d4e6a..6caa96a4f6f66 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -957,7 +957,10 @@ fn phase_runner(binary: &Path, binary_args: env::Args, phase: RunnerPhase) { // to emit the diagnostic structure that Cargo would consume from rustc to emit colored // diagnostics, and ask rustc to emit them. // See https://github.com/rust-lang/miri/issues/2037 - if arg.split(',').any(|a| a == "diagnostic-rendered-ansi") { + // First skip over the leading `=`, then check for diagnostic-rendered-ansi in the + // comma-separated list + if suffix.strip_prefix('=').unwrap().split(',').any(|a| a == "diagnostic-rendered-ansi") + { cmd.arg("--color=always"); } // But aside from remembering that colored output was requested, drop this argument. From f66c64bed25448af4b732b86255bd0c624dd4bac Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 25 Jun 2022 11:52:29 -0400 Subject: [PATCH 3316/3747] remove a FIXME that is not actually a bug --- src/shims/unix/linux/sync.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/shims/unix/linux/sync.rs b/src/shims/unix/linux/sync.rs index 0fdbde8d6775f..6be1e672f85f0 100644 --- a/src/shims/unix/linux/sync.rs +++ b/src/shims/unix/linux/sync.rs @@ -172,7 +172,6 @@ pub fn futex<'tcx>( this.atomic_fence(&[], AtomicFenceOp::SeqCst)?; // Read an `i32` through the pointer, regardless of any wrapper types. // It's not uncommon for `addr` to be passed as another type than `*mut i32`, such as `*const AtomicI32`. - // FIXME: this fails if `addr` is not a pointer type. let futex_val = this .read_scalar_at_offset_atomic( &addr.into(), From 54fbd313a6f08681a02d51fdafa321cb6a14d87e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 25 Jun 2022 12:27:50 -0400 Subject: [PATCH 3317/3747] README: multi-seed loop: also test the 0 seed --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f6b2413c65f59..7f373f078a097 100644 --- a/README.md +++ b/README.md @@ -192,7 +192,7 @@ randomness that is used to determine allocation base addresses. The following snippet calls Miri in a loop with different values for the seed: ``` -for seed in $({ echo obase=16; seq 255; } | bc); do +for seed in $({ echo obase=16; seq 0 255; } | bc); do MIRIFLAGS=-Zmiri-seed=$seed cargo miri test || { echo "Last seed: $seed"; break; }; done ``` From 9124420b2fd64ded303d5e8d8ad41df813d83985 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 25 Jun 2022 15:06:53 -0400 Subject: [PATCH 3318/3747] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 45773390616b9..dafb049cc5a85 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -a09c668c965f735f4cd59e7158662b9daa0b71ba +8aab472d52ba7314dc193c73abcd384e2586123c From e5022bf48ab9e2fff34754d018bba61e6dd2feb5 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 25 Jun 2022 15:17:37 -0400 Subject: [PATCH 3319/3747] join all the threads --- tests/pass/concurrency/sync.rs | 51 ++---------------------- tests/pass/concurrency/sync_nopreempt.rs | 49 ++++++++++++++++++++++- 2 files changed, 51 insertions(+), 49 deletions(-) diff --git a/tests/pass/concurrency/sync.rs b/tests/pass/concurrency/sync.rs index 5b7805ba22651..396c1a97e07e8 100644 --- a/tests/pass/concurrency/sync.rs +++ b/tests/pass/concurrency/sync.rs @@ -35,7 +35,7 @@ fn check_conditional_variables_notify_one() { let pair2 = pair.clone(); // Spawn a new thread. - thread::spawn(move || { + let t = thread::spawn(move || { thread::yield_now(); let (lock, cvar) = &*pair2; let mut started = lock.lock().unwrap(); @@ -50,6 +50,8 @@ fn check_conditional_variables_notify_one() { while !*started { started = cvar.wait(started).unwrap(); } + + t.join().unwrap(); } /// Test that waiting on a conditional variable with a timeout does not @@ -191,51 +193,6 @@ fn check_once() { } } -fn check_rwlock_unlock_bug1() { - // There was a bug where when un-read-locking an rwlock that still has other - // readers waiting, we'd accidentally also let a writer in. - // That caused an ICE. - let l = Arc::new(RwLock::new(0)); - - let r1 = l.read().unwrap(); - let r2 = l.read().unwrap(); - - // Make a waiting writer. - let l2 = l.clone(); - thread::spawn(move || { - let mut w = l2.write().unwrap(); - *w += 1; - }); - thread::yield_now(); - - drop(r1); - assert_eq!(*r2, 0); - thread::yield_now(); - thread::yield_now(); - thread::yield_now(); - assert_eq!(*r2, 0); - drop(r2); -} - -fn check_rwlock_unlock_bug2() { - // There was a bug where when un-read-locking an rwlock by letting the last reader leaver, - // we'd forget to wake up a writer. - // That meant the writer thread could never run again. - let l = Arc::new(RwLock::new(0)); - - let r = l.read().unwrap(); - - // Make a waiting writer. - let l2 = l.clone(); - let h = thread::spawn(move || { - let _w = l2.write().unwrap(); - }); - thread::yield_now(); - - drop(r); - h.join().unwrap(); -} - fn park_timeout() { let start = Instant::now(); @@ -277,8 +234,6 @@ fn main() { check_rwlock_write(); check_rwlock_read_no_deadlock(); check_once(); - check_rwlock_unlock_bug1(); - check_rwlock_unlock_bug2(); park_timeout(); park_unpark(); check_condvar(); diff --git a/tests/pass/concurrency/sync_nopreempt.rs b/tests/pass/concurrency/sync_nopreempt.rs index 8895d62df95fe..391f65ae5a9cb 100644 --- a/tests/pass/concurrency/sync_nopreempt.rs +++ b/tests/pass/concurrency/sync_nopreempt.rs @@ -2,7 +2,7 @@ // We are making scheduler assumptions here. // compile-flags: -Zmiri-strict-provenance -Zmiri-preemption-rate=0 -use std::sync::{Arc, Condvar, Mutex}; +use std::sync::{Arc, Condvar, Mutex, RwLock}; use std::thread; fn check_conditional_variables_notify_all() { @@ -35,6 +35,53 @@ fn check_conditional_variables_notify_all() { } } +fn check_rwlock_unlock_bug1() { + // There was a bug where when un-read-locking an rwlock that still has other + // readers waiting, we'd accidentally also let a writer in. + // That caused an ICE. + let l = Arc::new(RwLock::new(0)); + + let r1 = l.read().unwrap(); + let r2 = l.read().unwrap(); + + // Make a waiting writer. + let l2 = l.clone(); + thread::spawn(move || { + let mut w = l2.write().unwrap(); + *w += 1; + }); + thread::yield_now(); + + drop(r1); + assert_eq!(*r2, 0); + thread::yield_now(); + thread::yield_now(); + thread::yield_now(); + assert_eq!(*r2, 0); + drop(r2); +} + +fn check_rwlock_unlock_bug2() { + // There was a bug where when un-read-locking an rwlock by letting the last reader leaver, + // we'd forget to wake up a writer. + // That meant the writer thread could never run again. + let l = Arc::new(RwLock::new(0)); + + let r = l.read().unwrap(); + + // Make a waiting writer. + let l2 = l.clone(); + let h = thread::spawn(move || { + let _w = l2.write().unwrap(); + }); + thread::yield_now(); + + drop(r); + h.join().unwrap(); +} + fn main() { check_conditional_variables_notify_all(); + check_rwlock_unlock_bug1(); + check_rwlock_unlock_bug2(); } From 7c025a8f0eac5297c1d8cc3daf31dc27cad0694d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 25 Jun 2022 15:45:45 -0400 Subject: [PATCH 3320/3747] test for forgetting locked mutex --- tests/pass/concurrency/mutex_leak.rs | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 tests/pass/concurrency/mutex_leak.rs diff --git a/tests/pass/concurrency/mutex_leak.rs b/tests/pass/concurrency/mutex_leak.rs new file mode 100644 index 0000000000000..7fbc6dd30166b --- /dev/null +++ b/tests/pass/concurrency/mutex_leak.rs @@ -0,0 +1,9 @@ +// compile-flags: -Zmiri-ignore-leaks +use std::mem; +use std::sync::Mutex; + +fn main() { + // Test for https://github.com/rust-lang/rust/issues/85434 + let m = Mutex::new(5i32); + mem::forget(m.lock()); +} From d3ca71ba3765a4b12143c963d4db8712ca969a1e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 25 Jun 2022 19:15:11 -0400 Subject: [PATCH 3321/3747] test that &mut !Unpin references are protected --- .../deallocate_against_barrier2.rs | 16 ++++++++ .../deallocate_against_barrier2.stderr | 38 +++++++++++++++++++ 2 files changed, 54 insertions(+) create mode 100644 tests/fail/stacked_borrows/deallocate_against_barrier2.rs create mode 100644 tests/fail/stacked_borrows/deallocate_against_barrier2.stderr diff --git a/tests/fail/stacked_borrows/deallocate_against_barrier2.rs b/tests/fail/stacked_borrows/deallocate_against_barrier2.rs new file mode 100644 index 0000000000000..4680f6769a1c2 --- /dev/null +++ b/tests/fail/stacked_borrows/deallocate_against_barrier2.rs @@ -0,0 +1,16 @@ +// error-pattern: deallocating while item is protected +use std::marker::PhantomPinned; + +pub struct NotUnpin(i32, PhantomPinned); + +fn inner(x: &mut NotUnpin, f: fn(&mut NotUnpin)) { + // `f` may mutate, but it may not deallocate! + f(x) +} + +fn main() { + inner(Box::leak(Box::new(NotUnpin(0, PhantomPinned))), |x| { + let raw = x as *mut _; + drop(unsafe { Box::from_raw(raw) }); + }); +} diff --git a/tests/fail/stacked_borrows/deallocate_against_barrier2.stderr b/tests/fail/stacked_borrows/deallocate_against_barrier2.stderr new file mode 100644 index 0000000000000..22776656e0199 --- /dev/null +++ b/tests/fail/stacked_borrows/deallocate_against_barrier2.stderr @@ -0,0 +1,38 @@ +error: Undefined Behavior: deallocating while item is protected: [SharedReadWrite for (call ID)] + --> RUSTLIB/alloc/src/alloc.rs:LL:CC + | +LL | unsafe { __rust_dealloc(ptr, layout.size(), layout.align()) } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ deallocating while item is protected: [SharedReadWrite for (call ID)] + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information + + = note: inside `std::alloc::dealloc` at RUSTLIB/alloc/src/alloc.rs:LL:CC + = note: inside `::deallocate` at RUSTLIB/alloc/src/alloc.rs:LL:CC + = note: inside `alloc::alloc::box_free::` at RUSTLIB/alloc/src/alloc.rs:LL:CC + = note: inside `std::ptr::drop_in_place::> - shim(Some(std::boxed::Box))` at RUSTLIB/core/src/ptr/mod.rs:LL:CC + = note: inside `std::mem::drop::>` at RUSTLIB/core/src/mem/mod.rs:LL:CC +note: inside closure at $DIR/deallocate_against_barrier2.rs:LL:CC + --> $DIR/deallocate_against_barrier2.rs:LL:CC + | +LL | drop(unsafe { Box::from_raw(raw) }); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: inside `<[closure@$DIR/deallocate_against_barrier2.rs:LL:CC] as std::ops::FnOnce<(&mut NotUnpin,)>>::call_once - shim` at RUSTLIB/core/src/ops/function.rs:LL:CC +note: inside `inner` at $DIR/deallocate_against_barrier2.rs:LL:CC + --> $DIR/deallocate_against_barrier2.rs:LL:CC + | +LL | f(x) + | ^^^^ +note: inside `main` at $DIR/deallocate_against_barrier2.rs:LL:CC + --> $DIR/deallocate_against_barrier2.rs:LL:CC + | +LL | / inner(Box::leak(Box::new(NotUnpin(0, PhantomPinned))), |x| { +LL | | let raw = x as *mut _; +LL | | drop(unsafe { Box::from_raw(raw) }); +LL | | }); + | |______^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + From fed0e1639777cf33caf381ac3bc588ad082398eb Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 25 Jun 2022 20:01:36 -0400 Subject: [PATCH 3322/3747] don't assert the same thing twice --- cargo-miri/bin.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index 6caa96a4f6f66..4d7b7da6634ce 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -952,15 +952,14 @@ fn phase_runner(binary: &Path, binary_args: env::Args, phase: RunnerPhase) { assert!(suffix.starts_with('=')); // Drop this argument. } else if let Some(suffix) = arg.strip_prefix(json_flag) { - assert!(suffix.starts_with('=')); + let suffix = suffix.strip_prefix('=').unwrap(); // This is how we pass through --color=always. We detect that Cargo is detecting rustc // to emit the diagnostic structure that Cargo would consume from rustc to emit colored // diagnostics, and ask rustc to emit them. // See https://github.com/rust-lang/miri/issues/2037 // First skip over the leading `=`, then check for diagnostic-rendered-ansi in the // comma-separated list - if suffix.strip_prefix('=').unwrap().split(',').any(|a| a == "diagnostic-rendered-ansi") - { + if suffix.split(',').any(|a| a == "diagnostic-rendered-ansi") { cmd.arg("--color=always"); } // But aside from remembering that colored output was requested, drop this argument. From 5aeba7f86bb099c079c079e5381a3d976e6f5fdc Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 25 Jun 2022 23:30:29 -0400 Subject: [PATCH 3323/3747] make a bunch of tests look more like how they did before rustfmt --- tests/fail/box-cell-alias.rs | 4 +--- tests/fail/box-cell-alias.stderr | 10 +++++----- .../dangling_pointers/maybe_null_pointer_write_zst.rs | 4 +--- .../maybe_null_pointer_write_zst.stderr | 4 ++-- tests/fail/intrinsics/exact_div1.rs | 4 +--- tests/fail/intrinsics/exact_div1.stderr | 4 ++-- tests/fail/intrinsics/exact_div2.rs | 4 +--- tests/fail/intrinsics/exact_div2.stderr | 4 ++-- tests/fail/intrinsics/exact_div3.rs | 4 +--- tests/fail/intrinsics/exact_div3.stderr | 4 ++-- tests/fail/intrinsics/exact_div4.rs | 4 +--- tests/fail/intrinsics/exact_div4.stderr | 4 ++-- tests/fail/stacked_borrows/illegal_write1.rs | 4 +--- tests/fail/stacked_borrows/illegal_write1.stderr | 4 ++-- tests/fail/stacked_borrows/illegal_write2.rs | 4 +--- tests/fail/stacked_borrows/illegal_write2.stderr | 10 +++++----- tests/fail/stacked_borrows/illegal_write3.rs | 4 +--- tests/fail/stacked_borrows/illegal_write3.stderr | 10 +++++----- tests/fail/stacked_borrows/illegal_write6.rs | 4 +--- tests/fail/stacked_borrows/illegal_write6.stderr | 7 +++---- tests/fail/stacked_borrows/raw_tracking.rs | 8 ++------ tests/fail/stacked_borrows/raw_tracking.stderr | 10 +++++----- tests/fail/stacked_borrows/transmute-is-no-escape.rs | 4 +--- .../fail/stacked_borrows/transmute-is-no-escape.stderr | 10 +++++----- .../unaligned_pointers/intptrcast_alignment_check.rs | 4 +--- .../intptrcast_alignment_check.stderr | 4 ++-- tests/fail/validity/transmute_through_ptr.rs | 4 +--- tests/fail/zst2.rs | 4 +--- tests/fail/zst2.stderr | 4 ++-- tests/fail/zst3.rs | 8 ++------ tests/fail/zst3.stderr | 4 ++-- tests/pass/concurrency/data_race.rs | 4 +--- 32 files changed, 65 insertions(+), 104 deletions(-) diff --git a/tests/fail/box-cell-alias.rs b/tests/fail/box-cell-alias.rs index c1fec28ae3b7b..d3f505d2da5cc 100644 --- a/tests/fail/box-cell-alias.rs +++ b/tests/fail/box-cell-alias.rs @@ -6,9 +6,7 @@ use std::cell::Cell; fn helper(val: Box>, ptr: *const Cell) -> u8 { val.set(10); - unsafe { - (*ptr).set(20); //~ ERROR does not exist in the borrow stack - } + unsafe { (*ptr).set(20) }; //~ ERROR does not exist in the borrow stack val.get() } diff --git a/tests/fail/box-cell-alias.stderr b/tests/fail/box-cell-alias.stderr index e5a3ad3d33af0..446aafe640128 100644 --- a/tests/fail/box-cell-alias.stderr +++ b/tests/fail/box-cell-alias.stderr @@ -1,11 +1,11 @@ error: Undefined Behavior: trying to reborrow for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location --> $DIR/box-cell-alias.rs:LL:CC | -LL | (*ptr).set(20); - | ^^^^^^^^^^^^^^ - | | - | trying to reborrow for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location - | this error occurs as part of a reborrow at ALLOC[0x0..0x1] +LL | unsafe { (*ptr).set(20) }; + | ^^^^^^^^^^^^^^ + | | + | trying to reborrow for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | this error occurs as part of a reborrow at ALLOC[0x0..0x1] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information diff --git a/tests/fail/dangling_pointers/maybe_null_pointer_write_zst.rs b/tests/fail/dangling_pointers/maybe_null_pointer_write_zst.rs index 3115da436be84..4a8d498aa1f52 100644 --- a/tests/fail/dangling_pointers/maybe_null_pointer_write_zst.rs +++ b/tests/fail/dangling_pointers/maybe_null_pointer_write_zst.rs @@ -7,7 +7,5 @@ fn main() { // Also not assigning directly as that's array initialization, not assignment. let zst_val = [1u8; 0]; let ptr = (&0u8 as *const u8).wrapping_sub(0x800) as *mut [u8; 0]; - unsafe { - *ptr = zst_val; //~ ERROR out-of-bounds - } + unsafe { *ptr = zst_val }; //~ ERROR out-of-bounds } diff --git a/tests/fail/dangling_pointers/maybe_null_pointer_write_zst.stderr b/tests/fail/dangling_pointers/maybe_null_pointer_write_zst.stderr index 79fd2ba086853..41e54735ca925 100644 --- a/tests/fail/dangling_pointers/maybe_null_pointer_write_zst.stderr +++ b/tests/fail/dangling_pointers/maybe_null_pointer_write_zst.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: dereferencing pointer failed: ALLOC has size 1, so pointer at offset -2048 is out-of-bounds --> $DIR/maybe_null_pointer_write_zst.rs:LL:CC | -LL | *ptr = zst_val; - | ^^^^^^^^^^^^^^ dereferencing pointer failed: ALLOC has size 1, so pointer at offset -2048 is out-of-bounds +LL | unsafe { *ptr = zst_val }; + | ^^^^^^^^^^^^^^ dereferencing pointer failed: ALLOC has size 1, so pointer at offset -2048 is out-of-bounds | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/intrinsics/exact_div1.rs b/tests/fail/intrinsics/exact_div1.rs index d8af789e99a20..f926424a4b67a 100644 --- a/tests/fail/intrinsics/exact_div1.rs +++ b/tests/fail/intrinsics/exact_div1.rs @@ -1,7 +1,5 @@ #![feature(core_intrinsics)] fn main() { // divison by 0 - unsafe { - std::intrinsics::exact_div(2, 0); //~ ERROR divisor of zero - } + unsafe { std::intrinsics::exact_div(2, 0) }; //~ ERROR divisor of zero } diff --git a/tests/fail/intrinsics/exact_div1.stderr b/tests/fail/intrinsics/exact_div1.stderr index 66f8168fade72..59e853d0ececf 100644 --- a/tests/fail/intrinsics/exact_div1.stderr +++ b/tests/fail/intrinsics/exact_div1.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: calculating the remainder with a divisor of zero --> $DIR/exact_div1.rs:LL:CC | -LL | std::intrinsics::exact_div(2, 0); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ calculating the remainder with a divisor of zero +LL | unsafe { std::intrinsics::exact_div(2, 0) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ calculating the remainder with a divisor of zero | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/intrinsics/exact_div2.rs b/tests/fail/intrinsics/exact_div2.rs index 80f9131bab799..fc252aa798578 100644 --- a/tests/fail/intrinsics/exact_div2.rs +++ b/tests/fail/intrinsics/exact_div2.rs @@ -1,7 +1,5 @@ #![feature(core_intrinsics)] fn main() { // divison with a remainder - unsafe { - std::intrinsics::exact_div(2u16, 3); //~ ERROR 2_u16 cannot be divided by 3_u16 without remainder - } + unsafe { std::intrinsics::exact_div(2u16, 3) }; //~ ERROR 2_u16 cannot be divided by 3_u16 without remainder } diff --git a/tests/fail/intrinsics/exact_div2.stderr b/tests/fail/intrinsics/exact_div2.stderr index 2c102dd0b55cd..dfbcdd1f34f1e 100644 --- a/tests/fail/intrinsics/exact_div2.stderr +++ b/tests/fail/intrinsics/exact_div2.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: exact_div: 2_u16 cannot be divided by 3_u16 without remainder --> $DIR/exact_div2.rs:LL:CC | -LL | std::intrinsics::exact_div(2u16, 3); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ exact_div: 2_u16 cannot be divided by 3_u16 without remainder +LL | unsafe { std::intrinsics::exact_div(2u16, 3) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ exact_div: 2_u16 cannot be divided by 3_u16 without remainder | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/intrinsics/exact_div3.rs b/tests/fail/intrinsics/exact_div3.rs index 976fca29f9bac..4d2511adc1f58 100644 --- a/tests/fail/intrinsics/exact_div3.rs +++ b/tests/fail/intrinsics/exact_div3.rs @@ -1,7 +1,5 @@ #![feature(core_intrinsics)] fn main() { // signed divison with a remainder - unsafe { - std::intrinsics::exact_div(-19i8, 2); //~ ERROR -19_i8 cannot be divided by 2_i8 without remainder - } + unsafe { std::intrinsics::exact_div(-19i8, 2) }; //~ ERROR -19_i8 cannot be divided by 2_i8 without remainder } diff --git a/tests/fail/intrinsics/exact_div3.stderr b/tests/fail/intrinsics/exact_div3.stderr index 61eacdc65ff3e..c3b908ce0ad55 100644 --- a/tests/fail/intrinsics/exact_div3.stderr +++ b/tests/fail/intrinsics/exact_div3.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: exact_div: -19_i8 cannot be divided by 2_i8 without remainder --> $DIR/exact_div3.rs:LL:CC | -LL | std::intrinsics::exact_div(-19i8, 2); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ exact_div: -19_i8 cannot be divided by 2_i8 without remainder +LL | unsafe { std::intrinsics::exact_div(-19i8, 2) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ exact_div: -19_i8 cannot be divided by 2_i8 without remainder | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/intrinsics/exact_div4.rs b/tests/fail/intrinsics/exact_div4.rs index 5f4ca587e6d77..df6433d1cb22b 100644 --- a/tests/fail/intrinsics/exact_div4.rs +++ b/tests/fail/intrinsics/exact_div4.rs @@ -1,7 +1,5 @@ #![feature(core_intrinsics)] fn main() { // divison of MIN by -1 - unsafe { - std::intrinsics::exact_div(i64::MIN, -1); //~ ERROR overflow in signed remainder (dividing MIN by -1) - } + unsafe { std::intrinsics::exact_div(i64::MIN, -1) }; //~ ERROR overflow in signed remainder (dividing MIN by -1) } diff --git a/tests/fail/intrinsics/exact_div4.stderr b/tests/fail/intrinsics/exact_div4.stderr index a3f5aafbe2d6b..b82950674fbcc 100644 --- a/tests/fail/intrinsics/exact_div4.stderr +++ b/tests/fail/intrinsics/exact_div4.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: overflow in signed remainder (dividing MIN by -1) --> $DIR/exact_div4.rs:LL:CC | -LL | std::intrinsics::exact_div(i64::MIN, -1); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflow in signed remainder (dividing MIN by -1) +LL | unsafe { std::intrinsics::exact_div(i64::MIN, -1) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflow in signed remainder (dividing MIN by -1) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/stacked_borrows/illegal_write1.rs b/tests/fail/stacked_borrows/illegal_write1.rs index 3b67accbbd2eb..1f566f18c1f8e 100644 --- a/tests/fail/stacked_borrows/illegal_write1.rs +++ b/tests/fail/stacked_borrows/illegal_write1.rs @@ -3,9 +3,7 @@ fn main() { let xref = &*target; { let x: *mut u32 = xref as *const _ as *mut _; - unsafe { - *x = 42; // invalidates shared ref, activates raw - } + unsafe { *x = 42 }; // invalidates shared ref, activates raw } let _x = *xref; //~ ERROR borrow stack } diff --git a/tests/fail/stacked_borrows/illegal_write1.stderr b/tests/fail/stacked_borrows/illegal_write1.stderr index a70a45f2235af..1731e3c1de13d 100644 --- a/tests/fail/stacked_borrows/illegal_write1.stderr +++ b/tests/fail/stacked_borrows/illegal_write1.stderr @@ -17,8 +17,8 @@ LL | let xref = &*target; help: was later invalidated at offsets [0x0..0x4] --> $DIR/illegal_write1.rs:LL:CC | -LL | *x = 42; // invalidates shared ref, activates raw - | ^^^^^^^ +LL | unsafe { *x = 42 }; // invalidates shared ref, activates raw + | ^^^^^^^ = note: inside `main` at $DIR/illegal_write1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/illegal_write2.rs b/tests/fail/stacked_borrows/illegal_write2.rs index a106b4240c3c0..32dc474385d6c 100644 --- a/tests/fail/stacked_borrows/illegal_write2.rs +++ b/tests/fail/stacked_borrows/illegal_write2.rs @@ -3,8 +3,6 @@ fn main() { let target2 = target as *mut _; drop(&mut *target); // reborrow // Now make sure our ref is still the only one. - unsafe { - *target2 = 13; //~ ERROR borrow stack - } + unsafe { *target2 = 13 }; //~ ERROR borrow stack let _val = *target; } diff --git a/tests/fail/stacked_borrows/illegal_write2.stderr b/tests/fail/stacked_borrows/illegal_write2.stderr index d2a06cc386a14..7e896c530ac73 100644 --- a/tests/fail/stacked_borrows/illegal_write2.stderr +++ b/tests/fail/stacked_borrows/illegal_write2.stderr @@ -1,11 +1,11 @@ error: Undefined Behavior: attempting a write access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location --> $DIR/illegal_write2.rs:LL:CC | -LL | *target2 = 13; - | ^^^^^^^^^^^^^ - | | - | attempting a write access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location - | this error occurs as part of an access at ALLOC[0x0..0x4] +LL | unsafe { *target2 = 13 }; + | ^^^^^^^^^^^^^ + | | + | attempting a write access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | this error occurs as part of an access at ALLOC[0x0..0x4] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information diff --git a/tests/fail/stacked_borrows/illegal_write3.rs b/tests/fail/stacked_borrows/illegal_write3.rs index 5bf651b33aa08..87fdbae701926 100644 --- a/tests/fail/stacked_borrows/illegal_write3.rs +++ b/tests/fail/stacked_borrows/illegal_write3.rs @@ -3,8 +3,6 @@ fn main() { // Make sure raw ptr with raw tag cannot mutate frozen location without breaking the shared ref. let r#ref = ⌖ // freeze let ptr = r#ref as *const _ as *mut _; // raw ptr, with raw tag - unsafe { - *ptr = 42; //~ ERROR only grants SharedReadOnly permission - } + unsafe { *ptr = 42 }; //~ ERROR only grants SharedReadOnly permission let _val = *r#ref; } diff --git a/tests/fail/stacked_borrows/illegal_write3.stderr b/tests/fail/stacked_borrows/illegal_write3.stderr index fc87557ea9b46..7e9c82769d6ad 100644 --- a/tests/fail/stacked_borrows/illegal_write3.stderr +++ b/tests/fail/stacked_borrows/illegal_write3.stderr @@ -1,11 +1,11 @@ error: Undefined Behavior: attempting a write access using at ALLOC[0x0], but that tag only grants SharedReadOnly permission for this location --> $DIR/illegal_write3.rs:LL:CC | -LL | *ptr = 42; - | ^^^^^^^^^ - | | - | attempting a write access using at ALLOC[0x0], but that tag only grants SharedReadOnly permission for this location - | this error occurs as part of an access at ALLOC[0x0..0x4] +LL | unsafe { *ptr = 42 }; + | ^^^^^^^^^ + | | + | attempting a write access using at ALLOC[0x0], but that tag only grants SharedReadOnly permission for this location + | this error occurs as part of an access at ALLOC[0x0..0x4] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information diff --git a/tests/fail/stacked_borrows/illegal_write6.rs b/tests/fail/stacked_borrows/illegal_write6.rs index 07d57241205f3..c50b7c5816f63 100644 --- a/tests/fail/stacked_borrows/illegal_write6.rs +++ b/tests/fail/stacked_borrows/illegal_write6.rs @@ -7,8 +7,6 @@ fn main() { fn foo(a: &mut u32, y: *mut u32) -> u32 { *a = 1; let _b = &*a; - unsafe { - *y = 2; //~ ERROR: not granting access to tag - } + unsafe { *y = 2 }; //~ ERROR: not granting access to tag return *a; } diff --git a/tests/fail/stacked_borrows/illegal_write6.stderr b/tests/fail/stacked_borrows/illegal_write6.stderr index 3a7fc0ef8116b..11757cca9b657 100644 --- a/tests/fail/stacked_borrows/illegal_write6.stderr +++ b/tests/fail/stacked_borrows/illegal_write6.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: not granting access to tag because incompatible item is protected: [Unique for (call ID)] --> $DIR/illegal_write6.rs:LL:CC | -LL | *y = 2; - | ^^^^^^ not granting access to tag because incompatible item is protected: [Unique for (call ID)] +LL | unsafe { *y = 2 }; + | ^^^^^^ not granting access to tag because incompatible item is protected: [Unique for (call ID)] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information @@ -22,8 +22,7 @@ help: this protector is live for this call LL | / fn foo(a: &mut u32, y: *mut u32) -> u32 { LL | | *a = 1; LL | | let _b = &*a; -LL | | unsafe { -... | +LL | | unsafe { *y = 2 }; LL | | return *a; LL | | } | |_^ diff --git a/tests/fail/stacked_borrows/raw_tracking.rs b/tests/fail/stacked_borrows/raw_tracking.rs index 0a99e4ce47e7f..0b9c058f06ef1 100644 --- a/tests/fail/stacked_borrows/raw_tracking.rs +++ b/tests/fail/stacked_borrows/raw_tracking.rs @@ -7,10 +7,6 @@ fn main() { let raw2 = &mut l as *mut _; // invalidates raw1 // Without raw pointer tracking, Stacked Borrows cannot distinguish raw1 and raw2, and thus // fails to realize that raw1 should not be used any more. - unsafe { - *raw1 = 13; //~ ERROR does not exist in the borrow stack - } - unsafe { - *raw2 = 13; - } + unsafe { *raw1 = 13 }; //~ ERROR does not exist in the borrow stack + unsafe { *raw2 = 13 }; } diff --git a/tests/fail/stacked_borrows/raw_tracking.stderr b/tests/fail/stacked_borrows/raw_tracking.stderr index 60a277ee057ec..d3674893fab8e 100644 --- a/tests/fail/stacked_borrows/raw_tracking.stderr +++ b/tests/fail/stacked_borrows/raw_tracking.stderr @@ -1,11 +1,11 @@ error: Undefined Behavior: attempting a write access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location --> $DIR/raw_tracking.rs:LL:CC | -LL | *raw1 = 13; - | ^^^^^^^^^^ - | | - | attempting a write access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location - | this error occurs as part of an access at ALLOC[0x0..0x4] +LL | unsafe { *raw1 = 13 }; + | ^^^^^^^^^^ + | | + | attempting a write access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | this error occurs as part of an access at ALLOC[0x0..0x4] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information diff --git a/tests/fail/stacked_borrows/transmute-is-no-escape.rs b/tests/fail/stacked_borrows/transmute-is-no-escape.rs index e23c893d6aaa3..45035683d5c00 100644 --- a/tests/fail/stacked_borrows/transmute-is-no-escape.rs +++ b/tests/fail/stacked_borrows/transmute-is-no-escape.rs @@ -10,7 +10,5 @@ fn main() { let _raw: *mut i32 = unsafe { mem::transmute(&mut x[0]) }; // `raw` still carries a tag, so we get another pointer to the same location that does not carry a tag let raw = (&mut x[1] as *mut i32).wrapping_offset(-1); - unsafe { - *raw = 13; //~ ERROR borrow stack - } + unsafe { *raw = 13 }; //~ ERROR borrow stack } diff --git a/tests/fail/stacked_borrows/transmute-is-no-escape.stderr b/tests/fail/stacked_borrows/transmute-is-no-escape.stderr index c077e37844d15..a9682f806ba2b 100644 --- a/tests/fail/stacked_borrows/transmute-is-no-escape.stderr +++ b/tests/fail/stacked_borrows/transmute-is-no-escape.stderr @@ -1,11 +1,11 @@ error: Undefined Behavior: attempting a write access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location --> $DIR/transmute-is-no-escape.rs:LL:CC | -LL | *raw = 13; - | ^^^^^^^^^ - | | - | attempting a write access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location - | this error occurs as part of an access at ALLOC[0x0..0x4] +LL | unsafe { *raw = 13 }; + | ^^^^^^^^^ + | | + | attempting a write access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | this error occurs as part of an access at ALLOC[0x0..0x4] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information diff --git a/tests/fail/unaligned_pointers/intptrcast_alignment_check.rs b/tests/fail/unaligned_pointers/intptrcast_alignment_check.rs index e96f08fc9a7a9..0a326a453e9a4 100644 --- a/tests/fail/unaligned_pointers/intptrcast_alignment_check.rs +++ b/tests/fail/unaligned_pointers/intptrcast_alignment_check.rs @@ -12,8 +12,6 @@ fn main() { // Manually make sure the pointer is properly aligned. let base_addr_aligned = if base_addr % 2 == 0 { base_addr } else { base_addr + 1 }; let u16_ptr = base_addr_aligned as *mut u16; - unsafe { - *u16_ptr = 2; //~ERROR memory with alignment 1, but alignment 2 is required - } + unsafe { *u16_ptr = 2 }; //~ERROR memory with alignment 1, but alignment 2 is required println!("{:?}", x); } diff --git a/tests/fail/unaligned_pointers/intptrcast_alignment_check.stderr b/tests/fail/unaligned_pointers/intptrcast_alignment_check.stderr index fe63b05a55014..347486187e1b9 100644 --- a/tests/fail/unaligned_pointers/intptrcast_alignment_check.stderr +++ b/tests/fail/unaligned_pointers/intptrcast_alignment_check.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: accessing memory with alignment ALIGN, but alignment ALIGN is required --> $DIR/intptrcast_alignment_check.rs:LL:CC | -LL | *u16_ptr = 2; - | ^^^^^^^^^^^^ accessing memory with alignment ALIGN, but alignment ALIGN is required +LL | unsafe { *u16_ptr = 2 }; + | ^^^^^^^^^^^^ accessing memory with alignment ALIGN, but alignment ALIGN is required | = help: this usually indicates that your program performed an invalid operation and caused Undefined Behavior = help: but due to `-Zmiri-symbolic-alignment-check`, alignment errors can also be false positives diff --git a/tests/fail/validity/transmute_through_ptr.rs b/tests/fail/validity/transmute_through_ptr.rs index 4af3b8aef6aaa..049c57e61939a 100644 --- a/tests/fail/validity/transmute_through_ptr.rs +++ b/tests/fail/validity/transmute_through_ptr.rs @@ -6,9 +6,7 @@ enum Bool { fn evil(x: &mut Bool) { let x = x as *mut _ as *mut u32; - unsafe { - *x = 44; // out-of-bounds enum tag - } + unsafe { *x = 44 }; // out-of-bounds enum tag } #[rustfmt::skip] // rustfmt bug: https://github.com/rust-lang/rustfmt/issues/5391 diff --git a/tests/fail/zst2.rs b/tests/fail/zst2.rs index 2499f79142dbe..9f92e8994d266 100644 --- a/tests/fail/zst2.rs +++ b/tests/fail/zst2.rs @@ -11,7 +11,5 @@ fn main() { let mut x_box = Box::new(1u8); let x = &mut *x_box as *mut _ as *mut [u8; 0]; drop(x_box); - unsafe { - *x = zst_val; //~ ERROR dereferenced after this allocation got freed - } + unsafe { *x = zst_val }; //~ ERROR dereferenced after this allocation got freed } diff --git a/tests/fail/zst2.stderr b/tests/fail/zst2.stderr index 0df2098d2e19a..3112a87489a92 100644 --- a/tests/fail/zst2.stderr +++ b/tests/fail/zst2.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: pointer to ALLOC was dereferenced after this allocation got freed --> $DIR/zst2.rs:LL:CC | -LL | *x = zst_val; - | ^^^^^^^^^^^^ pointer to ALLOC was dereferenced after this allocation got freed +LL | unsafe { *x = zst_val }; + | ^^^^^^^^^^^^ pointer to ALLOC was dereferenced after this allocation got freed | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/zst3.rs b/tests/fail/zst3.rs index 741374c7ad988..3f3b0af14dbea 100644 --- a/tests/fail/zst3.rs +++ b/tests/fail/zst3.rs @@ -11,12 +11,8 @@ fn main() { let mut x_box = Box::new(1u8); let x = (&mut *x_box as *mut u8).wrapping_offset(1); // This one is just "at the edge", but still okay - unsafe { - *(x as *mut [u8; 0]) = zst_val; - } + unsafe { *(x as *mut [u8; 0]) = zst_val }; // One byte further is OOB. let x = x.wrapping_offset(1); - unsafe { - *(x as *mut [u8; 0]) = zst_val; //~ ERROR out-of-bounds - } + unsafe { *(x as *mut [u8; 0]) = zst_val }; //~ ERROR out-of-bounds } diff --git a/tests/fail/zst3.stderr b/tests/fail/zst3.stderr index dce0d7b3891ca..bc3436b14ac00 100644 --- a/tests/fail/zst3.stderr +++ b/tests/fail/zst3.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: dereferencing pointer failed: ALLOC has size 1, so pointer at offset 2 is out-of-bounds --> $DIR/zst3.rs:LL:CC | -LL | *(x as *mut [u8; 0]) = zst_val; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ dereferencing pointer failed: ALLOC has size 1, so pointer at offset 2 is out-of-bounds +LL | unsafe { *(x as *mut [u8; 0]) = zst_val }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ dereferencing pointer failed: ALLOC has size 1, so pointer at offset 2 is out-of-bounds | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/pass/concurrency/data_race.rs b/tests/pass/concurrency/data_race.rs index 071f5bbcdf394..812003ef4d97d 100644 --- a/tests/pass/concurrency/data_race.rs +++ b/tests/pass/concurrency/data_race.rs @@ -18,9 +18,7 @@ fn test_fence_sync() { let evil_ptr = EvilSend(ptr); let j1 = spawn(move || { - unsafe { - *evil_ptr.0 = 1; - } + unsafe { *evil_ptr.0 = 1 }; fence(Ordering::Release); SYNC.store(1, Ordering::Relaxed) }); From e667ccb4594b5415626f18dbe34c1713b59e3941 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 25 Jun 2022 23:22:42 -0400 Subject: [PATCH 3324/3747] test that futexes induce appropriate synchronization --- tests/pass/concurrency/linux-futex.rs | 32 +++++++++++++++++++++++---- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/tests/pass/concurrency/linux-futex.rs b/tests/pass/concurrency/linux-futex.rs index 2c60df1ee138a..b65dd46d5974c 100644 --- a/tests/pass/concurrency/linux-futex.rs +++ b/tests/pass/concurrency/linux-futex.rs @@ -222,11 +222,17 @@ fn wait_wake_bitset() { t.join().unwrap(); } -const FREE: i32 = 0; -const HELD: i32 = 1; fn concurrent_wait_wake() { + const FREE: i32 = 0; + const HELD: i32 = 1; + static FUTEX: AtomicI32 = AtomicI32::new(0); - for _ in 0..20 { + static mut DATA: i32 = 0; + static WOKEN: AtomicI32 = AtomicI32::new(0); + + let rounds = 50; + for _ in 0..rounds { + unsafe { DATA = 0 }; // Reset // Suppose the main thread is holding a lock implemented using futex... FUTEX.store(HELD, Ordering::Relaxed); @@ -239,23 +245,41 @@ fn concurrent_wait_wake() { // the FUTEX is FREE != HELD and return without waiting // or we'll deadlock. unsafe { - libc::syscall( + let ret = libc::syscall( libc::SYS_futex, &FUTEX as *const AtomicI32, libc::FUTEX_WAIT, HELD, ptr::null::(), ); + if ret == 0 { + // We actually slept. And then woke up again. So we should be ordered-after + // what happened-before the FUTEX_WAKE. So this is not a race. + assert_eq!(DATA, 1); + // Also remember that this happened at least once. + WOKEN.fetch_add(1, Ordering::Relaxed); + } } }); + // Increase the chance that the other thread actually goes to sleep. + // (5 yields in a loop seem to make that happen around 40% of the time.) + for _ in 0..5 { + thread::yield_now(); + } FUTEX.store(FREE, Ordering::Relaxed); unsafe { + DATA = 1; libc::syscall(libc::SYS_futex, &FUTEX as *const AtomicI32, libc::FUTEX_WAKE, 1); } t.join().unwrap(); } + + // Make sure we got the interesting case (of having woken a thread) at least once, but not *each* time. + let woken = WOKEN.load(Ordering::Relaxed); + assert!(woken > 0 && woken < rounds); + //eprintln!("waking happened {woken} times"); } fn main() { From 34be937d5f67d789969b1b731967fa26cc490a9c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 26 Jun 2022 12:31:53 -0400 Subject: [PATCH 3325/3747] add -Zmiri-report-progress to regularly print a stacktrace of what we are executing --- README.md | 4 ++++ src/bin/miri.rs | 9 +++++++++ src/diagnostics.rs | 3 +++ src/eval.rs | 3 +++ src/machine.rs | 17 +++++++++++++++++ test-cargo-miri/build.rs | 2 +- 6 files changed, 37 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 7f373f078a097..117794b77ee61 100644 --- a/README.md +++ b/README.md @@ -292,6 +292,10 @@ environment variable. We first document the most relevant and most commonly used * `-Zmiri-preemption-rate` configures the probability that at the end of a basic block, the active thread will be preempted. The default is `0.01` (i.e., 1%). Setting this to `0` disables preemption. +* `-Zmiri-report-progress` makes Miri print the current stacktrace every now and then, so you can + tell what it is doing when a program just keeps running. You can customize how frequently the + report is printed via `-Zmiri-report-progress=`, which prints the report every N basic + blocks. * `-Zmiri-seed=` configures the seed of the RNG that Miri uses to resolve non-determinism. This RNG is used to pick base addresses for allocations, to determine preemption and failure of `compare_exchange_weak`, and to control store buffering for weak memory emulation. When isolation diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 7dc642365c509..91148400c99b2 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -468,6 +468,15 @@ fn main() { ), }; miri_config.preemption_rate = rate; + } else if arg == "-Zmiri-report-progress" { + // This makes it take a few seconds between progress reports on my laptop. + miri_config.report_progress = Some(1_000_000); + } else if let Some(param) = arg.strip_prefix("-Zmiri-report-progress=") { + let interval = match param.parse::() { + Ok(i) => i, + Err(err) => panic!("-Zmiri-report-progress requires a `u32`: {}", err), + }; + miri_config.report_progress = Some(interval); } else if let Some(param) = arg.strip_prefix("-Zmiri-measureme=") { miri_config.measureme_out = Some(param.to_string()); } else if let Some(param) = arg.strip_prefix("-Zmiri-backtrace=") { diff --git a/src/diagnostics.rs b/src/diagnostics.rs index 230f46c569dbf..6986d9c57271f 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -68,6 +68,7 @@ pub enum NonHaltingDiagnostic { CreatedAlloc(AllocId), FreedAlloc(AllocId), RejectedIsolatedOp(String), + ProgressReport, } /// Level of Miri specific diagnostics @@ -465,6 +466,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx FreedAlloc(AllocId(id)) => format!("freed allocation with id {id}"), RejectedIsolatedOp(ref op) => format!("{op} was made to return an error due to isolation"), + ProgressReport => + format!("progress report: current operation being executed is here"), }; let (title, diag_level) = match e { diff --git a/src/eval.rs b/src/eval.rs index db843b851e58a..7beb2ec9c4ad5 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -124,6 +124,8 @@ pub struct MiriConfig { pub mute_stdout_stderr: bool, /// The probability of the active thread being preempted at the end of each basic block. pub preemption_rate: f64, + /// Report the current instruction being executed every N basic blocks. + pub report_progress: Option, } impl Default for MiriConfig { @@ -154,6 +156,7 @@ impl Default for MiriConfig { provenance_mode: ProvenanceMode::Legacy, mute_stdout_stderr: false, preemption_rate: 0.01, // 1% + report_progress: None, } } } diff --git a/src/machine.rs b/src/machine.rs index 79414ada5eac9..3621744e8025c 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -333,6 +333,11 @@ pub struct Evaluator<'mir, 'tcx> { /// The probability of the active thread being preempted at the end of each basic block. pub(crate) preemption_rate: f64, + + /// If `Some`, we will report the current stack every N basic blocks. + pub(crate) report_progress: Option, + /// The number of blocks that passed since the last progress report. + pub(crate) since_progress_report: u32, } impl<'mir, 'tcx> Evaluator<'mir, 'tcx> { @@ -390,6 +395,8 @@ impl<'mir, 'tcx> Evaluator<'mir, 'tcx> { mute_stdout_stderr: config.mute_stdout_stderr, weak_memory: config.weak_memory_emulation, preemption_rate: config.preemption_rate, + report_progress: config.report_progress, + since_progress_report: 0, } } @@ -862,6 +869,16 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { } fn before_terminator(ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx> { + // Possibly report our progress. + if let Some(report_progress) = ecx.machine.report_progress { + if ecx.machine.since_progress_report >= report_progress { + register_diagnostic(NonHaltingDiagnostic::ProgressReport); + ecx.machine.since_progress_report = 0; + } + // Cannot overflow, since it is strictly less than `report_progress`. + ecx.machine.since_progress_report += 1; + } + // These are our preemption points. ecx.maybe_preempt_active_thread(); Ok(()) } diff --git a/test-cargo-miri/build.rs b/test-cargo-miri/build.rs index 72a4ee0de30ba..8b1e3af6231a0 100644 --- a/test-cargo-miri/build.rs +++ b/test-cargo-miri/build.rs @@ -16,7 +16,7 @@ fn main() { not_in_miri(); // Cargo calls `miri --print=cfg` to populate the `CARGO_CFG_*` env vars. // Make sure that the "miri" flag is set. - assert!(env::var_os("CARGO_CFG_MIRI").is_some()); + assert!(env::var_os("CARGO_CFG_MIRI").is_some(), "cargo failed to tell us about `--cfg miri`"); println!("cargo:rerun-if-changed=build.rs"); println!("cargo:rerun-if-env-changed=MIRITESTVAR"); println!("cargo:rustc-env=MIRITESTVAR=testval"); From 60570a39c7b0e3a8ed55e934eb7a18792f436bbe Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 26 Jun 2022 18:59:48 -0400 Subject: [PATCH 3326/3747] trophy case: add the data race in thread::scope --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 117794b77ee61..50586c9eceaf8 100644 --- a/README.md +++ b/README.md @@ -586,6 +586,7 @@ Definite bugs found: * [`crossbeam-epoch` calling `assume_init` on a partly-initialized `MaybeUninit`](https://github.com/crossbeam-rs/crossbeam/pull/779) * [`integer-encoding` dereferencing a misaligned pointer](https://github.com/dermesser/integer-encoding-rs/pull/23) * [`rkyv` constructing a `Box<[u8]>` from an overaligned allocation](https://github.com/rkyv/rkyv/commit/a9417193a34757e12e24263178be8b2eebb72456) +* [Data race in `thread::scope`](https://github.com/rust-lang/rust/issues/98498) Violations of [Stacked Borrows] found that are likely bugs (but Stacked Borrows is currently just an experiment): From 9130034337b30e975beb2c265e309187c574561e Mon Sep 17 00:00:00 2001 From: infrandomness Date: Thu, 9 Jun 2022 16:06:07 +0200 Subject: [PATCH 3327/3747] Initial freebsd work --- ci.sh | 1 + src/helpers.rs | 2 +- src/shims/unix/dlsym.rs | 4 +++ src/shims/unix/foreign_items.rs | 1 + src/shims/unix/freebsd/dlsym.rs | 35 +++++++++++++++++++++++++ src/shims/unix/freebsd/foreign_items.rs | 23 ++++++++++++++++ src/shims/unix/freebsd/mod.rs | 2 ++ src/shims/unix/macos/dlsym.rs | 7 ++--- src/shims/unix/mod.rs | 1 + tests/pass/libc.rs | 20 +++++++------- 10 files changed, 80 insertions(+), 16 deletions(-) create mode 100644 src/shims/unix/freebsd/dlsym.rs create mode 100644 src/shims/unix/freebsd/foreign_items.rs create mode 100644 src/shims/unix/freebsd/mod.rs diff --git a/ci.sh b/ci.sh index 01b86ff2f96ba..f436e0179ab63 100755 --- a/ci.sh +++ b/ci.sh @@ -50,6 +50,7 @@ case $HOST_TARGET in MIRI_TEST_TARGET=i686-unknown-linux-gnu run_tests MIRI_TEST_TARGET=aarch64-apple-darwin run_tests MIRI_TEST_TARGET=i686-pc-windows-msvc run_tests + MIRI_TEST_TARGET=x86_64-unknown-freebsd run_tests ;; x86_64-apple-darwin) MIRI_TEST_TARGET=mips64-unknown-linux-gnuabi64 run_tests # big-endian architecture diff --git a/src/helpers.rs b/src/helpers.rs index 134f556bf1204..86823f2817887 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -910,5 +910,5 @@ impl std::fmt::Display for HexRange { /// Helper function used inside the shims of foreign functions to check that /// `target_os` is a supported UNIX OS. pub fn target_os_is_unix(target_os: &str) -> bool { - matches!(target_os, "linux" | "macos") + matches!(target_os, "linux" | "macos" | "freebsd") } diff --git a/src/shims/unix/dlsym.rs b/src/shims/unix/dlsym.rs index 578ae488a98ea..f183971b59aa1 100644 --- a/src/shims/unix/dlsym.rs +++ b/src/shims/unix/dlsym.rs @@ -4,11 +4,13 @@ use rustc_target::spec::abi::Abi; use crate::*; use shims::unix::linux::dlsym as linux; use shims::unix::macos::dlsym as macos; +use shims::unix::freebsd::dlsym as freebsd; #[derive(Debug, Copy, Clone)] pub enum Dlsym { Linux(linux::Dlsym), MacOs(macos::Dlsym), + FreeBSD(freebsd::Dlsym) } impl Dlsym { @@ -18,6 +20,7 @@ impl Dlsym { Ok(match target_os { "linux" => linux::Dlsym::from_str(name)?.map(Dlsym::Linux), "macos" => macos::Dlsym::from_str(name)?.map(Dlsym::MacOs), + "freebsd" => freebsd::Dlsym::from_str(name)?.map(Dlsym::FreeBSD), _ => unreachable!(), }) } @@ -40,6 +43,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx match dlsym { Dlsym::Linux(dlsym) => linux::EvalContextExt::call_dlsym(this, dlsym, args, dest, ret), Dlsym::MacOs(dlsym) => macos::EvalContextExt::call_dlsym(this, dlsym, args, dest, ret), + Dlsym::FreeBSD(dlsym) => freebsd::EvalContextExt::call_dlsym(this, dlsym, args, dest, ret) } } } diff --git a/src/shims/unix/foreign_items.rs b/src/shims/unix/foreign_items.rs index d002ab75b9bed..d789b0c640475 100644 --- a/src/shims/unix/foreign_items.rs +++ b/src/shims/unix/foreign_items.rs @@ -485,6 +485,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx match this.tcx.sess.target.os.as_ref() { "linux" => return shims::unix::linux::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, abi, args, dest, ret), "macos" => return shims::unix::macos::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, abi, args, dest, ret), + "freebsd" => return shims::unix::freebsd::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, abi, args, dest, ret), _ => unreachable!(), } } diff --git a/src/shims/unix/freebsd/dlsym.rs b/src/shims/unix/freebsd/dlsym.rs new file mode 100644 index 0000000000000..57125c14fa0cd --- /dev/null +++ b/src/shims/unix/freebsd/dlsym.rs @@ -0,0 +1,35 @@ +use rustc_middle::mir; + +use crate::*; +use helpers::check_arg_count; + +#[derive(Debug, Copy, Clone)] +#[allow(non_camel_case_types)] +pub enum Dlsym { + getentropy, +} + +impl Dlsym { + // Returns an error for unsupported symbols, and None if this symbol + // should become a NULL pointer (pretend it does not exist). + pub fn from_str<'tcx>(name: &str) -> InterpResult<'tcx, Option> { + throw_unsup_format!("unsupported FreeBSD dlsym: {}", name) + } +} + +impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} +pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { + fn call_dlsym( + &mut self, + dlsym: Dlsym, + _args: &[OpTy<'tcx, Tag>], + _dest: &PlaceTy<'tcx, Tag>, + ret: Option, + ) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + let _ret = ret.expect("we don't support any diverging dlsym"); + assert!(this.tcx.sess.target.os == "freebsd"); + + match dlsym {} + } +} diff --git a/src/shims/unix/freebsd/foreign_items.rs b/src/shims/unix/freebsd/foreign_items.rs new file mode 100644 index 0000000000000..ac261cecc2e0a --- /dev/null +++ b/src/shims/unix/freebsd/foreign_items.rs @@ -0,0 +1,23 @@ +use rustc_middle::mir; +use rustc_span::Symbol; +use rustc_target::spec::abi::Abi; + +use crate::*; +use shims::foreign_items::EmulateByNameResult; + +impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} + +pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { + fn emulate_foreign_item_by_name( + &mut self, + link_name: Symbol, + abi: Abi, + args: &[OpTy<'tcx, Tag>], + dest: &PlaceTy<'tcx, Tag>, + _ret: mir::BasicBlock, + ) -> InterpResult<'tcx, EmulateByNameResult<'mir, 'tcx>> { + let this = self.eval_context_mut(); + // match + Ok(EmulateByNameResult::NeedsJumping) + } +} \ No newline at end of file diff --git a/src/shims/unix/freebsd/mod.rs b/src/shims/unix/freebsd/mod.rs new file mode 100644 index 0000000000000..428d997d787c8 --- /dev/null +++ b/src/shims/unix/freebsd/mod.rs @@ -0,0 +1,2 @@ +pub mod foreign_items; +pub mod dlsym; \ No newline at end of file diff --git a/src/shims/unix/macos/dlsym.rs b/src/shims/unix/macos/dlsym.rs index 2e97b7918e96b..ee0ff01c05ed1 100644 --- a/src/shims/unix/macos/dlsym.rs +++ b/src/shims/unix/macos/dlsym.rs @@ -3,12 +3,10 @@ use rustc_middle::mir; use log::trace; use crate::*; -use helpers::check_arg_count; #[derive(Debug, Copy, Clone)] #[allow(non_camel_case_types)] pub enum Dlsym { - getentropy, } impl Dlsym { @@ -16,8 +14,7 @@ impl Dlsym { // should become a NULL pointer (pretend it does not exist). pub fn from_str<'tcx>(name: &str) -> InterpResult<'tcx, Option> { Ok(match name { - "getentropy" => Some(Dlsym::getentropy), - _ => throw_unsup_format!("unsupported macOS dlsym: {}", name), + _ => throw_unsup_format!("unsupported freebsd dlsym: {}", name), }) } } @@ -33,7 +30,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let ret = ret.expect("we don't support any diverging dlsym"); - assert!(this.tcx.sess.target.os == "macos"); + assert!(this.tcx.sess.target.os == "freebsd"); match dlsym { Dlsym::getentropy => { diff --git a/src/shims/unix/mod.rs b/src/shims/unix/mod.rs index f40dfaefb92ac..4002b056b4b21 100644 --- a/src/shims/unix/mod.rs +++ b/src/shims/unix/mod.rs @@ -7,5 +7,6 @@ mod thread; mod linux; mod macos; +mod freebsd; pub use fs::{DirHandler, FileHandler}; diff --git a/tests/pass/libc.rs b/tests/pass/libc.rs index f97b9dd2b9eaa..0b6bc64395344 100644 --- a/tests/pass/libc.rs +++ b/tests/pass/libc.rs @@ -5,14 +5,14 @@ extern crate libc; -#[cfg(target_os = "linux")] +#[cfg(target_os = "linux, freebsd")] fn tmp() -> std::path::PathBuf { std::env::var("MIRI_TEMP") .map(std::path::PathBuf::from) .unwrap_or_else(|_| std::env::temp_dir()) } -#[cfg(target_os = "linux")] +#[cfg(target_os = "linux, freebsd")] fn test_posix_fadvise() { use std::convert::TryInto; use std::fs::{remove_file, File}; @@ -42,7 +42,7 @@ fn test_posix_fadvise() { assert_eq!(result, 0); } -#[cfg(target_os = "linux")] +#[cfg(target_os = "linux, freebsd")] fn test_sync_file_range() { use std::fs::{remove_file, File}; use std::io::Write; @@ -208,7 +208,7 @@ fn test_rwlock_libc_static_initializer() { /// Test whether the `prctl` shim correctly sets the thread name. /// /// Note: `prctl` exists only on Linux. -#[cfg(target_os = "linux")] +#[cfg(target_os = "linux,freebsd")] fn test_prctl_thread_name() { use libc::c_long; use std::ffi::CString; @@ -277,7 +277,7 @@ fn test_thread_local_errno() { } /// Tests whether clock support exists at all -#[cfg(target_os = "linux")] +#[cfg(target_os = "linux,freebsd")] fn test_clocks() { let mut tp = std::mem::MaybeUninit::::uninit(); let is_error = unsafe { libc::clock_gettime(libc::CLOCK_REALTIME, tp.as_mut_ptr()) }; @@ -291,10 +291,10 @@ fn test_clocks() { } fn main() { - #[cfg(target_os = "linux")] + #[cfg(target_os = "linux,freebsd")] test_posix_fadvise(); - #[cfg(target_os = "linux")] + #[cfg(target_os = "linux,freebsd")] test_sync_file_range(); test_mutex_libc_init_recursive(); @@ -302,14 +302,14 @@ fn main() { test_mutex_libc_init_errorcheck(); test_rwlock_libc_static_initializer(); - #[cfg(target_os = "linux")] + #[cfg(target_os = "linux,freebsd")] test_mutex_libc_static_initializer_recursive(); - #[cfg(target_os = "linux")] + #[cfg(target_os = "linux,freebsd")] test_prctl_thread_name(); test_thread_local_errno(); - #[cfg(target_os = "linux")] + #[cfg(target_os = "linux,freebsd")] test_clocks(); } From 97a512070aa6d648ddde025a7cc9784fad7624f9 Mon Sep 17 00:00:00 2001 From: infrandomness Date: Thu, 9 Jun 2022 16:50:34 +0200 Subject: [PATCH 3328/3747] Fix pending reviews --- src/shims/unix/dlsym.rs | 7 ++++--- src/shims/unix/freebsd/dlsym.rs | 5 +---- src/shims/unix/freebsd/foreign_items.rs | 2 +- src/shims/unix/freebsd/mod.rs | 2 +- src/shims/unix/macos/dlsym.rs | 7 +++++-- src/shims/unix/mod.rs | 2 +- tests/pass/libc.rs | 20 ++++++++++---------- 7 files changed, 23 insertions(+), 22 deletions(-) diff --git a/src/shims/unix/dlsym.rs b/src/shims/unix/dlsym.rs index f183971b59aa1..e1f819fb85671 100644 --- a/src/shims/unix/dlsym.rs +++ b/src/shims/unix/dlsym.rs @@ -2,15 +2,15 @@ use rustc_middle::mir; use rustc_target::spec::abi::Abi; use crate::*; +use shims::unix::freebsd::dlsym as freebsd; use shims::unix::linux::dlsym as linux; use shims::unix::macos::dlsym as macos; -use shims::unix::freebsd::dlsym as freebsd; #[derive(Debug, Copy, Clone)] pub enum Dlsym { Linux(linux::Dlsym), MacOs(macos::Dlsym), - FreeBSD(freebsd::Dlsym) + FreeBSD(freebsd::Dlsym), } impl Dlsym { @@ -43,7 +43,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx match dlsym { Dlsym::Linux(dlsym) => linux::EvalContextExt::call_dlsym(this, dlsym, args, dest, ret), Dlsym::MacOs(dlsym) => macos::EvalContextExt::call_dlsym(this, dlsym, args, dest, ret), - Dlsym::FreeBSD(dlsym) => freebsd::EvalContextExt::call_dlsym(this, dlsym, args, dest, ret) + Dlsym::FreeBSD(dlsym) => + freebsd::EvalContextExt::call_dlsym(this, dlsym, args, dest, ret), } } } diff --git a/src/shims/unix/freebsd/dlsym.rs b/src/shims/unix/freebsd/dlsym.rs index 57125c14fa0cd..18347d274e93c 100644 --- a/src/shims/unix/freebsd/dlsym.rs +++ b/src/shims/unix/freebsd/dlsym.rs @@ -1,13 +1,10 @@ use rustc_middle::mir; use crate::*; -use helpers::check_arg_count; #[derive(Debug, Copy, Clone)] #[allow(non_camel_case_types)] -pub enum Dlsym { - getentropy, -} +pub enum Dlsym {} impl Dlsym { // Returns an error for unsupported symbols, and None if this symbol diff --git a/src/shims/unix/freebsd/foreign_items.rs b/src/shims/unix/freebsd/foreign_items.rs index ac261cecc2e0a..7127252388677 100644 --- a/src/shims/unix/freebsd/foreign_items.rs +++ b/src/shims/unix/freebsd/foreign_items.rs @@ -20,4 +20,4 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // match Ok(EmulateByNameResult::NeedsJumping) } -} \ No newline at end of file +} diff --git a/src/shims/unix/freebsd/mod.rs b/src/shims/unix/freebsd/mod.rs index 428d997d787c8..434f5f30b5a56 100644 --- a/src/shims/unix/freebsd/mod.rs +++ b/src/shims/unix/freebsd/mod.rs @@ -1,2 +1,2 @@ +pub mod dlsym; pub mod foreign_items; -pub mod dlsym; \ No newline at end of file diff --git a/src/shims/unix/macos/dlsym.rs b/src/shims/unix/macos/dlsym.rs index ee0ff01c05ed1..2e97b7918e96b 100644 --- a/src/shims/unix/macos/dlsym.rs +++ b/src/shims/unix/macos/dlsym.rs @@ -3,10 +3,12 @@ use rustc_middle::mir; use log::trace; use crate::*; +use helpers::check_arg_count; #[derive(Debug, Copy, Clone)] #[allow(non_camel_case_types)] pub enum Dlsym { + getentropy, } impl Dlsym { @@ -14,7 +16,8 @@ impl Dlsym { // should become a NULL pointer (pretend it does not exist). pub fn from_str<'tcx>(name: &str) -> InterpResult<'tcx, Option> { Ok(match name { - _ => throw_unsup_format!("unsupported freebsd dlsym: {}", name), + "getentropy" => Some(Dlsym::getentropy), + _ => throw_unsup_format!("unsupported macOS dlsym: {}", name), }) } } @@ -30,7 +33,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let ret = ret.expect("we don't support any diverging dlsym"); - assert!(this.tcx.sess.target.os == "freebsd"); + assert!(this.tcx.sess.target.os == "macos"); match dlsym { Dlsym::getentropy => { diff --git a/src/shims/unix/mod.rs b/src/shims/unix/mod.rs index 4002b056b4b21..8e8c70bbd0faf 100644 --- a/src/shims/unix/mod.rs +++ b/src/shims/unix/mod.rs @@ -5,8 +5,8 @@ mod fs; mod sync; mod thread; +mod freebsd; mod linux; mod macos; -mod freebsd; pub use fs::{DirHandler, FileHandler}; diff --git a/tests/pass/libc.rs b/tests/pass/libc.rs index 0b6bc64395344..e73e796449cc5 100644 --- a/tests/pass/libc.rs +++ b/tests/pass/libc.rs @@ -5,14 +5,14 @@ extern crate libc; -#[cfg(target_os = "linux, freebsd")] +#[cfg(any(target_os = "linux", target_os = "freebsd"))] fn tmp() -> std::path::PathBuf { std::env::var("MIRI_TEMP") .map(std::path::PathBuf::from) .unwrap_or_else(|_| std::env::temp_dir()) } -#[cfg(target_os = "linux, freebsd")] +#[cfg(any(target_os = "linux", target_os = "freebsd"))] fn test_posix_fadvise() { use std::convert::TryInto; use std::fs::{remove_file, File}; @@ -42,7 +42,7 @@ fn test_posix_fadvise() { assert_eq!(result, 0); } -#[cfg(target_os = "linux, freebsd")] +#[cfg(any(target_os = "linux", target_os = "freebsd"))] fn test_sync_file_range() { use std::fs::{remove_file, File}; use std::io::Write; @@ -208,7 +208,7 @@ fn test_rwlock_libc_static_initializer() { /// Test whether the `prctl` shim correctly sets the thread name. /// /// Note: `prctl` exists only on Linux. -#[cfg(target_os = "linux,freebsd")] +#[cfg(any(target_os = "linux", target_os = "freebsd"))] fn test_prctl_thread_name() { use libc::c_long; use std::ffi::CString; @@ -277,7 +277,7 @@ fn test_thread_local_errno() { } /// Tests whether clock support exists at all -#[cfg(target_os = "linux,freebsd")] +#[cfg(any(target_os = "linux", target_os = "freebsd"))] fn test_clocks() { let mut tp = std::mem::MaybeUninit::::uninit(); let is_error = unsafe { libc::clock_gettime(libc::CLOCK_REALTIME, tp.as_mut_ptr()) }; @@ -291,10 +291,10 @@ fn test_clocks() { } fn main() { - #[cfg(target_os = "linux,freebsd")] + #[cfg(any(target_os = "linux", target_os = "freebsd"))] test_posix_fadvise(); - #[cfg(target_os = "linux,freebsd")] + #[cfg(any(target_os = "linux", target_os = "freebsd"))] test_sync_file_range(); test_mutex_libc_init_recursive(); @@ -302,14 +302,14 @@ fn main() { test_mutex_libc_init_errorcheck(); test_rwlock_libc_static_initializer(); - #[cfg(target_os = "linux,freebsd")] + #[cfg(any(target_os = "linux", target_os = "freebsd"))] test_mutex_libc_static_initializer_recursive(); - #[cfg(target_os = "linux,freebsd")] + #[cfg(any(target_os = "linux", target_os = "freebsd"))] test_prctl_thread_name(); test_thread_local_errno(); - #[cfg(target_os = "linux,freebsd")] + #[cfg(any(target_os = "linux", target_os = "freebsd"))] test_clocks(); } From e89b4d6df22e2056f2651d685f67d666908d079a Mon Sep 17 00:00:00 2001 From: infrandomness Date: Fri, 10 Jun 2022 12:12:20 +0200 Subject: [PATCH 3329/3747] Fix panicking ui_tests framework --- src/shims/unix/freebsd/foreign_items.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/shims/unix/freebsd/foreign_items.rs b/src/shims/unix/freebsd/foreign_items.rs index 7127252388677..0efc44af82bab 100644 --- a/src/shims/unix/freebsd/foreign_items.rs +++ b/src/shims/unix/freebsd/foreign_items.rs @@ -17,7 +17,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx _ret: mir::BasicBlock, ) -> InterpResult<'tcx, EmulateByNameResult<'mir, 'tcx>> { let this = self.eval_context_mut(); - // match + match link_name.as_str() { + _ => return Ok(EmulateByNameResult::NotSupported), + } Ok(EmulateByNameResult::NeedsJumping) } } From f2cbd3e2bc732186d8aafea9f930fcc3b0c34ce0 Mon Sep 17 00:00:00 2001 From: infrandomness Date: Sun, 12 Jun 2022 11:47:43 +0200 Subject: [PATCH 3330/3747] Add `pthread_attr_getstack` shim --- src/shims/unix/freebsd/foreign_items.rs | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/shims/unix/freebsd/foreign_items.rs b/src/shims/unix/freebsd/foreign_items.rs index 0efc44af82bab..4ff588e51a45d 100644 --- a/src/shims/unix/freebsd/foreign_items.rs +++ b/src/shims/unix/freebsd/foreign_items.rs @@ -18,6 +18,27 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, EmulateByNameResult<'mir, 'tcx>> { let this = self.eval_context_mut(); match link_name.as_str() { + // Querying system information + "pthread_attr_getstack" => { + // We don't support "pthread_attr_setstack", so we just pretend all stacks have the same values here. + let [attr_place, addr_place, size_place] = + this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + this.deref_operand(attr_place)?; + let addr_place = this.deref_operand(addr_place)?; + let size_place = this.deref_operand(size_place)?; + + this.write_scalar( + Scalar::from_uint(STACK_ADDR, this.pointer_size()), + &addr_place.into(), + )?; + this.write_scalar( + Scalar::from_uint(STACK_SIZE, this.pointer_size()), + &size_place.into(), + )?; + + // Return success (`0`). + this.write_null(dest)?; + } _ => return Ok(EmulateByNameResult::NotSupported), } Ok(EmulateByNameResult::NeedsJumping) From 93c61f3905d9ee123dd3ff2e07a48ed428a52e72 Mon Sep 17 00:00:00 2001 From: infrandomness Date: Sun, 12 Jun 2022 11:47:59 +0200 Subject: [PATCH 3331/3747] Add `pthread_attr_get_np` shim --- src/shims/unix/freebsd/foreign_items.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/shims/unix/freebsd/foreign_items.rs b/src/shims/unix/freebsd/foreign_items.rs index 4ff588e51a45d..b1d0eed2c0ed1 100644 --- a/src/shims/unix/freebsd/foreign_items.rs +++ b/src/shims/unix/freebsd/foreign_items.rs @@ -39,6 +39,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Return success (`0`). this.write_null(dest)?; } + + // Linux's `pthread_getattr_np` equivalent + "pthread_attr_get_np" if this.frame_in_std() => { + let [_thread, _attr] = + this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + this.write_null(dest)?; + } _ => return Ok(EmulateByNameResult::NotSupported), } Ok(EmulateByNameResult::NeedsJumping) From aaa8ebb5765146665cb5b8fdc88d12c9b67d0ca5 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 26 Jun 2022 16:20:37 -0400 Subject: [PATCH 3332/3747] only test a few tests on FreeBSD --- ci.sh | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/ci.sh b/ci.sh index f436e0179ab63..1fa67f52139ed 100755 --- a/ci.sh +++ b/ci.sh @@ -42,6 +42,16 @@ function run_tests { echo } +function run_tests_minimal { + if [ -n "${MIRI_TEST_TARGET+exists}" ]; then + echo "Testing MINIMAL foreign architecture $MIRI_TEST_TARGET: only testing $@" + else + echo "Testing MINIMAL host architecture: only testing $@" + fi + + ./miri test --locked -- "$@" +} + # host run_tests @@ -50,7 +60,7 @@ case $HOST_TARGET in MIRI_TEST_TARGET=i686-unknown-linux-gnu run_tests MIRI_TEST_TARGET=aarch64-apple-darwin run_tests MIRI_TEST_TARGET=i686-pc-windows-msvc run_tests - MIRI_TEST_TARGET=x86_64-unknown-freebsd run_tests + MIRI_TEST_TARGET=x86_64-unknown-freebsd run_tests_minimal hello integer vec ;; x86_64-apple-darwin) MIRI_TEST_TARGET=mips64-unknown-linux-gnuabi64 run_tests # big-endian architecture From 84a02787d8cc81f10bc9119dec5239c687915210 Mon Sep 17 00:00:00 2001 From: infrandomness Date: Mon, 27 Jun 2022 01:13:13 +0200 Subject: [PATCH 3333/3747] Address code review - Merge pthread_attr_getstack shim to unix/foreign_items.rs --- src/shims/unix/foreign_items.rs | 22 ++++++++++++++++++++++ src/shims/unix/freebsd/foreign_items.rs | 22 ---------------------- src/shims/unix/linux/foreign_items.rs | 22 +--------------------- 3 files changed, 23 insertions(+), 43 deletions(-) diff --git a/src/shims/unix/foreign_items.rs b/src/shims/unix/foreign_items.rs index d789b0c640475..4993690767c14 100644 --- a/src/shims/unix/foreign_items.rs +++ b/src/shims/unix/foreign_items.rs @@ -461,6 +461,28 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_null(dest)?; } + // Querying system information + "pthread_attr_getstack" => { + // We don't support "pthread_attr_setstack", so we just pretend all stacks have the same values here. + let [attr_place, addr_place, size_place] = + this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + this.deref_operand(attr_place)?; + let addr_place = this.deref_operand(addr_place)?; + let size_place = this.deref_operand(size_place)?; + + this.write_scalar( + Scalar::from_uint(STACK_ADDR, this.pointer_size()), + &addr_place.into(), + )?; + this.write_scalar( + Scalar::from_uint(STACK_SIZE, this.pointer_size()), + &size_place.into(), + )?; + + // Return success (`0`). + this.write_null(dest)?; + } + | "signal" | "sigaltstack" if this.frame_in_std() => { diff --git a/src/shims/unix/freebsd/foreign_items.rs b/src/shims/unix/freebsd/foreign_items.rs index b1d0eed2c0ed1..cad1192337404 100644 --- a/src/shims/unix/freebsd/foreign_items.rs +++ b/src/shims/unix/freebsd/foreign_items.rs @@ -18,28 +18,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, EmulateByNameResult<'mir, 'tcx>> { let this = self.eval_context_mut(); match link_name.as_str() { - // Querying system information - "pthread_attr_getstack" => { - // We don't support "pthread_attr_setstack", so we just pretend all stacks have the same values here. - let [attr_place, addr_place, size_place] = - this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; - this.deref_operand(attr_place)?; - let addr_place = this.deref_operand(addr_place)?; - let size_place = this.deref_operand(size_place)?; - - this.write_scalar( - Scalar::from_uint(STACK_ADDR, this.pointer_size()), - &addr_place.into(), - )?; - this.write_scalar( - Scalar::from_uint(STACK_SIZE, this.pointer_size()), - &size_place.into(), - )?; - - // Return success (`0`). - this.write_null(dest)?; - } - // Linux's `pthread_getattr_np` equivalent "pthread_attr_get_np" if this.frame_in_std() => { let [_thread, _attr] = diff --git a/src/shims/unix/linux/foreign_items.rs b/src/shims/unix/linux/foreign_items.rs index ab3f39147c60f..500250745c8b7 100644 --- a/src/shims/unix/linux/foreign_items.rs +++ b/src/shims/unix/linux/foreign_items.rs @@ -80,27 +80,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_i32(result), dest)?; } - // Querying system information - "pthread_attr_getstack" => { - // We don't support "pthread_attr_setstack", so we just pretend all stacks have the same values here. - let [attr_place, addr_place, size_place] = - this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; - this.deref_operand(attr_place)?; - let addr_place = this.deref_operand(addr_place)?; - let size_place = this.deref_operand(size_place)?; - - this.write_scalar( - Scalar::from_uint(STACK_ADDR, this.pointer_size()), - &addr_place.into(), - )?; - this.write_scalar( - Scalar::from_uint(STACK_SIZE, this.pointer_size()), - &size_place.into(), - )?; - - // Return success (`0`). - this.write_null(dest)?; - } + // Threading "prctl" => { From aa072d72ccf79e313ef28b73a8bced367d9a4a6f Mon Sep 17 00:00:00 2001 From: infrandomness Date: Mon, 27 Jun 2022 01:22:13 +0200 Subject: [PATCH 3334/3747] Cargo fmt --- src/shims/unix/linux/foreign_items.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/shims/unix/linux/foreign_items.rs b/src/shims/unix/linux/foreign_items.rs index 500250745c8b7..48abe9bf08c33 100644 --- a/src/shims/unix/linux/foreign_items.rs +++ b/src/shims/unix/linux/foreign_items.rs @@ -80,8 +80,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_i32(result), dest)?; } - - // Threading "prctl" => { // prctl is variadic. (It is not documented like that in the manpage, but defined like that in the libc crate.) From 13d425daebe539b1a48731faecf1d1ba5287aa72 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 26 Jun 2022 21:14:18 -0400 Subject: [PATCH 3335/3747] make permissive provenance and raw-ptr tagging the default --- README.md | 25 ++---- src/bin/miri.rs | 7 +- src/diagnostics.rs | 25 +++++- src/eval.rs | 5 +- src/intptrcast.rs | 76 +++++++++---------- src/machine.rs | 3 +- src/stacked_borrows.rs | 8 +- test-cargo-miri/run-test.py | 5 -- .../fail/backtrace/bad-backtrace-flags.stderr | 17 ++++- tests/fail/backtrace/bad-backtrace-ptr.stderr | 17 ++++- .../bad-backtrace-resolve-flags.stderr | 17 ++++- .../bad-backtrace-resolve-names-flags.stderr | 17 ++++- .../thread_local_static_dealloc.stderr | 17 ++++- .../deref-invalid-ptr.stderr | 17 ++++- .../storage_dead_dangling.stderr | 22 +++++- .../wild_pointer_deref.stderr | 17 ++++- .../intrinsics/ptr_offset_0_plus_0.stderr | 17 ++++- .../intrinsics/ptr_offset_int_plus_int.stderr | 17 ++++- .../intrinsics/ptr_offset_int_plus_ptr.stderr | 17 ++++- .../fail/provenance/ptr_legacy_provenance.rs | 22 ------ .../provenance/ptr_legacy_provenance.stderr | 15 ---- .../fail/stacked_borrows/aliasing_mut3.stderr | 8 +- .../box_exclusive_violation1.rs | 4 +- .../box_exclusive_violation1.stderr | 33 ++++---- tests/fail/stacked_borrows/illegal_read3.rs | 2 +- .../fail/stacked_borrows/illegal_read6.stderr | 8 +- tests/fail/stacked_borrows/illegal_write1.rs | 4 +- .../stacked_borrows/illegal_write1.stderr | 21 ++--- .../stacked_borrows/illegal_write2.stderr | 8 +- .../stacked_borrows/illegal_write3.stderr | 6 +- tests/fail/stacked_borrows/illegal_write4.rs | 4 +- .../stacked_borrows/illegal_write4.stderr | 2 +- .../stacked_borrows/illegal_write6.stderr | 8 +- .../invalidate_against_barrier1.stderr | 8 +- .../invalidate_against_barrier2.stderr | 8 +- .../mut_exclusive_violation1.stderr | 8 +- .../stacked_borrows/outdated_local.stderr | 8 +- .../stacked_borrows/pointer_smuggling.stderr | 8 +- tests/fail/stacked_borrows/raw_tracking.rs | 1 - .../shr_frozen_violation1.stderr | 6 +- .../transmute-is-no-escape.stderr | 10 ++- .../stacked_borrows/unescaped_local.stderr | 32 ++++---- .../stacked_borrows/unescaped_static.stderr | 10 ++- .../intptrcast_alignment_check.stderr | 17 ++++- tests/fail/uninit_byte_read.rs | 1 + tests/fail/validity/cast_fn_ptr1.stderr | 17 ++++- tests/fail/validity/cast_fn_ptr2.stderr | 22 +++++- tests/pass/adjacent-allocs.rs | 2 + tests/pass/align.stderr | 20 +++++ tests/pass/box.rs | 2 +- tests/pass/box.stderr | 20 +++++ .../concurrency/tls_pthread_drop_order.rs | 7 +- tests/pass/extern_types.stderr | 15 ++++ tests/pass/intptrcast.rs | 2 + tests/pass/intrinsics.rs | 1 + .../pass/linux-getrandom-without-isolation.rs | 6 +- tests/pass/linux-getrandom.rs | 6 +- tests/pass/panic/catch_panic.rs | 2 +- tests/pass/ptr_int_casts.rs | 1 + tests/pass/ptr_offset.rs | 1 + tests/pass/stacked-borrows/2phase.rs | 2 - .../stacked-borrows/interior_mutability.rs | 1 - tests/pass/stacked-borrows/stacked-borrows.rs | 1 - tests/pass/zst.rs | 1 + 64 files changed, 491 insertions(+), 246 deletions(-) delete mode 100644 tests/fail/provenance/ptr_legacy_provenance.rs delete mode 100644 tests/fail/provenance/ptr_legacy_provenance.stderr create mode 100644 tests/pass/align.stderr create mode 100644 tests/pass/box.stderr create mode 100644 tests/pass/extern_types.stderr diff --git a/README.md b/README.md index 50586c9eceaf8..efdbf5143d9f7 100644 --- a/README.md +++ b/README.md @@ -306,7 +306,7 @@ environment variable. We first document the most relevant and most commonly used * `-Zmiri-strict-provenance` enables [strict provenance](https://github.com/rust-lang/rust/issues/95228) checking in Miri. This means that casting an integer to a pointer yields a result with 'invalid' provenance, i.e., with provenance - that cannot be used for any memory access. Also implies `-Zmiri-tag-raw-pointers`. + that cannot be used for any memory access. The remaining flags are for advanced use only, and more likely to change or be removed. Some of these are **unsound**, which means they can lead @@ -321,7 +321,7 @@ to Miri failing to detect cases of undefined behavior in a program. integers via `mem::transmute` or union/pointer type punning. This has two effects: it disables the check against integers storing a pointer (i.e., data with provenance), thus allowing pointer-to-integer transmutation, and it treats integer-to-pointer transmutation as equivalent to - a cast. Using this flag is **unsound** and + a cast. Implies `-Zmiri-permissive-provenance`. Using this flag is **unsound** and [deprecated](https://github.com/rust-lang/miri/issues/2188). * `-Zmiri-disable-abi-check` disables checking [function ABI]. Using this flag is **unsound**. @@ -354,15 +354,11 @@ to Miri failing to detect cases of undefined behavior in a program. application instead of raising an error within the context of Miri (and halting execution). Note that code might not expect these operations to ever panic, so this flag can lead to strange (mis)behavior. -* `-Zmiri-permissive-provenance` is **experimental**. This will make Miri do a - best-effort attempt to implement the semantics of - [`expose_addr`](https://doc.rust-lang.org/nightly/std/primitive.pointer.html#method.expose_addr) - and - [`ptr::from_exposed_addr`](https://doc.rust-lang.org/nightly/std/ptr/fn.from_exposed_addr.html) - for pointer-to-int and int-to-pointer casts, respectively. This will - necessarily miss some bugs as those semantics are not efficiently - implementable in a sanitizer, but it will only miss bugs that concerns - memory/pointers which is subject to these operations. +* `-Zmiri-permissive-provenance` disables the warning for integer-to-pointer casts and + [`ptr::from_exposed_addr`](https://doc.rust-lang.org/nightly/std/ptr/fn.from_exposed_addr.html). + This will necessarily miss some bugs as those operations are not efficiently and accurately + implementable in a sanitizer, but it will only miss bugs that concern memory/pointers which is + subject to these operations. * `-Zmiri-symbolic-alignment-check` makes the alignment check more strict. By default, alignment is checked by casting the pointer to an integer, and making sure that is a multiple of the alignment. This can lead to cases where a @@ -389,13 +385,6 @@ to Miri failing to detect cases of undefined behavior in a program. happening and where in your code would be a good place to look for it. Specifying this argument multiple times does not overwrite the previous values, instead it appends its values to the list. Listing a tag multiple times has no effect. -* `-Zmiri-tag-raw-pointers` makes Stacked Borrows assign proper tags even for raw pointers. This can - make valid code using int-to-ptr casts fail to pass the checks, but also can help identify latent - aliasing issues in code that Miri accepts by default. You can recognize false positives by - `` occurring in the message -- this indicates a pointer that was cast from an integer, - so Miri was unable to track this pointer. Note that it is not currently guaranteed that code that - works with `-Zmiri-tag-raw-pointers` also works without `-Zmiri-tag-raw-pointers`, but for the - vast majority of code, this will be the case. [function ABI]: https://doc.rust-lang.org/reference/items/functions.html#extern-function-qualifier diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 91148400c99b2..7bced912645db 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -340,6 +340,7 @@ fn main() { Please let us know at if you rely on this flag." ); miri_config.allow_ptr_int_transmute = true; + miri_config.provenance_mode = ProvenanceMode::Permissive; } else if arg == "-Zmiri-disable-abi-check" { miri_config.check_abi = false; } else if arg == "-Zmiri-disable-isolation" { @@ -374,20 +375,18 @@ fn main() { } else if arg == "-Zmiri-panic-on-unsupported" { miri_config.panic_on_unsupported = true; } else if arg == "-Zmiri-tag-raw-pointers" { - miri_config.tag_raw = true; + eprintln!("WARNING: `-Zmiri-tag-raw-pointers` has no effect; it is enabled by default"); } else if arg == "-Zmiri-strict-provenance" { miri_config.provenance_mode = ProvenanceMode::Strict; - miri_config.tag_raw = true; + miri_config.allow_ptr_int_transmute = false; } else if arg == "-Zmiri-permissive-provenance" { miri_config.provenance_mode = ProvenanceMode::Permissive; - miri_config.tag_raw = true; } else if arg == "-Zmiri-mute-stdout-stderr" { miri_config.mute_stdout_stderr = true; } else if arg == "-Zmiri-track-raw-pointers" { eprintln!( "WARNING: -Zmiri-track-raw-pointers has been renamed to -Zmiri-tag-raw-pointers, the old name is deprecated." ); - miri_config.tag_raw = true; } else if let Some(param) = arg.strip_prefix("-Zmiri-seed=") { if miri_config.seed.is_some() { panic!("Cannot specify -Zmiri-seed multiple times!"); diff --git a/src/diagnostics.rs b/src/diagnostics.rs index 6986d9c57271f..d17d1e6ed4c87 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -69,6 +69,7 @@ pub enum NonHaltingDiagnostic { FreedAlloc(AllocId), RejectedIsolatedOp(String), ProgressReport, + Int2Ptr, } /// Level of Miri specific diagnostics @@ -468,15 +469,35 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx format!("{op} was made to return an error due to isolation"), ProgressReport => format!("progress report: current operation being executed is here"), + Int2Ptr => format!("pointer-to-integer cast"), }; let (title, diag_level) = match e { RejectedIsolatedOp(_) => ("operation rejected by isolation", DiagLevel::Warning), - _ => ("tracking was triggered", DiagLevel::Note), + Int2Ptr => ("pointer-to-integer cast", DiagLevel::Warning), + CreatedPointerTag(..) + | PoppedPointerTag(..) + | CreatedCallId(..) + | CreatedAlloc(..) + | FreedAlloc(..) + | ProgressReport => ("tracking was triggered", DiagLevel::Note), }; - report_msg(this, diag_level, title, vec![msg], vec![], &stacktrace); + let helps = match e { + Int2Ptr => + vec![ + (None, format!("this program is using integer-to-pointer casts or (equivalently) `from_exposed_addr`,")), + (None, format!("which means that Miri might miss pointer bugs in this program")), + (None, format!("see https://doc.rust-lang.org/nightly/std/ptr/fn.from_exposed_addr.html for more details on that operation")), + (None, format!("to ensure that Miri does not miss bugs in your program, use `with_addr` (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance) instead")), + (None, format!("you can then pass the `-Zmiri-strict-provenance` flag to Miri, to ensure you are not relying on `from_exposed_addr` semantics")), + (None, format!("alternatively, the `-Zmiri-permissive-provenance` flag disables this warning")), + ], + _ => vec![], + }; + + report_msg(this, diag_level, title, vec![msg], helps, &stacktrace); } }); } diff --git a/src/eval.rs b/src/eval.rs index 7beb2ec9c4ad5..fa252953fe6e4 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -101,8 +101,6 @@ pub struct MiriConfig { pub tracked_call_ids: HashSet, /// The allocation ids to report about. pub tracked_alloc_ids: HashSet, - /// Whether to track raw pointers in stacked borrows. - pub tag_raw: bool, /// Determine if data race detection should be enabled pub data_race_detector: bool, /// Determine if weak memory emulation should be enabled. Requires data race detection to be enabled @@ -146,14 +144,13 @@ impl Default for MiriConfig { tracked_pointer_tags: HashSet::default(), tracked_call_ids: HashSet::default(), tracked_alloc_ids: HashSet::default(), - tag_raw: false, data_race_detector: true, weak_memory_emulation: true, cmpxchg_weak_failure_rate: 0.8, // 80% measureme_out: None, panic_on_unsupported: false, backtrace_style: BacktraceStyle::Short, - provenance_mode: ProvenanceMode::Legacy, + provenance_mode: ProvenanceMode::Default, mute_stdout_stderr: false, preemption_rate: 0.01, // 1% report_progress: None, diff --git a/src/intptrcast.rs b/src/intptrcast.rs index cfaf61f9d5c88..c92954a218ca2 100644 --- a/src/intptrcast.rs +++ b/src/intptrcast.rs @@ -11,16 +11,13 @@ use crate::*; #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub enum ProvenanceMode { - /// Int2ptr casts return pointers with "wildcard" provenance - /// that basically matches that of all exposed pointers - /// (and SB tags, if enabled). + /// We support `expose_addr`/`from_exposed_addr` via "wildcard" provenance. + /// However, we want on `from_exposed_addr` to alert the user of the precision loss. + Default, + /// Like `Default`, but without the warning. Permissive, - /// Int2ptr casts return pointers with an invalid provenance, - /// i.e., not valid for any memory access. + /// We error on `from_exposed_addr`, ensuring no precision loss. Strict, - /// Int2ptr casts determine the allocation they point to at cast time. - /// All allocations are considered exposed. - Legacy, } pub type GlobalState = RefCell; @@ -66,6 +63,8 @@ impl<'mir, 'tcx> GlobalStateInner { let pos = global_state.int_to_ptr_map.binary_search_by_key(&addr, |(addr, _)| *addr); + // Determine the in-bounds provenance for this pointer. + // (This is only called on an actual access, so in-bounds is the only possible kind of provenance.) let alloc_id = match pos { Ok(pos) => Some(global_state.int_to_ptr_map[pos].1), Err(0) => None, @@ -91,21 +90,14 @@ impl<'mir, 'tcx> GlobalStateInner { } }?; - // In legacy mode, we consider all allocations exposed. - if global_state.provenance_mode == ProvenanceMode::Legacy - || global_state.exposed.contains(&alloc_id) - { - Some(alloc_id) - } else { - None - } + // We only use this provenance if it has been exposed. + if global_state.exposed.contains(&alloc_id) { Some(alloc_id) } else { None } } pub fn expose_ptr(ecx: &mut MiriEvalContext<'mir, 'tcx>, alloc_id: AllocId, sb: SbTag) { let global_state = ecx.machine.intptrcast.get_mut(); - // In legacy and strict mode, we don't need this, so we can save some cycles - // by not tracking it. - if global_state.provenance_mode == ProvenanceMode::Permissive { + // In strict mode, we don't need this, so we can save some cycles by not tracking it. + if global_state.provenance_mode != ProvenanceMode::Strict { trace!("Exposing allocation id {alloc_id:?}"); global_state.exposed.insert(alloc_id); if ecx.machine.stacked_borrows.is_some() { @@ -120,42 +112,43 @@ impl<'mir, 'tcx> GlobalStateInner { ) -> Pointer> { trace!("Transmuting 0x{:x} to a pointer", addr); - if ecx.machine.allow_ptr_int_transmute { - // When we allow transmutes, treat them like casts. - Self::ptr_from_addr_cast(ecx, addr) + let provenance = if ecx.machine.allow_ptr_int_transmute { + // When we allow transmutes, treat them like casts: generating a wildcard pointer. + Some(Tag::Wildcard) } else { - // We consider transmuted pointers to be "invalid" (`None` provenance). - Pointer::new(None, Size::from_bytes(addr)) - } + // Usually, we consider transmuted pointers to be "invalid" (`None` provenance). + None + }; + Pointer::new(provenance, Size::from_bytes(addr)) } pub fn ptr_from_addr_cast( ecx: &MiriEvalContext<'mir, 'tcx>, addr: u64, - ) -> Pointer> { + ) -> InterpResult<'tcx, Pointer>> { trace!("Casting 0x{:x} to a pointer", addr); let global_state = ecx.machine.intptrcast.borrow(); match global_state.provenance_mode { - ProvenanceMode::Legacy => { - // Determine the allocation this points to at cast time. - let alloc_id = Self::alloc_id_from_addr(ecx, addr); - Pointer::new( - alloc_id.map(|alloc_id| Tag::Concrete { alloc_id, sb: SbTag::Untagged }), - Size::from_bytes(addr), - ) + ProvenanceMode::Default => { + // The first time this happens, print a warning. + use std::sync::atomic::{AtomicBool, Ordering}; + static FIRST_WARNING: AtomicBool = AtomicBool::new(true); + if FIRST_WARNING.swap(false, Ordering::Relaxed) { + register_diagnostic(NonHaltingDiagnostic::Int2Ptr); + } } ProvenanceMode::Strict => { - // We don't support int2ptr casts in this mode (i.e., we treat them like - // transmutes). - Pointer::new(None, Size::from_bytes(addr)) - } - ProvenanceMode::Permissive => { - // This is how wildcard pointers are born. - Pointer::new(Some(Tag::Wildcard), Size::from_bytes(addr)) + throw_unsup_format!( + "integer-to-pointer casts and `from_exposed_addr` are not supported with `-Zmiri-strict-provenance`; use `with_addr` instead" + ) } + ProvenanceMode::Permissive => {} } + + // This is how wildcard pointers are born. + Ok(Pointer::new(Some(Tag::Wildcard), Size::from_bytes(addr))) } fn alloc_base_addr(ecx: &MiriEvalContext<'mir, 'tcx>, alloc_id: AllocId) -> u64 { @@ -214,6 +207,8 @@ impl<'mir, 'tcx> GlobalStateInner { dl.overflowing_offset(base_addr, offset.bytes()).0 } + /// Whena pointer is used for a memory access, this computes where in which allocation the + /// access is going. pub fn abs_ptr_to_rel( ecx: &MiriEvalContext<'mir, 'tcx>, ptr: Pointer, @@ -224,7 +219,6 @@ impl<'mir, 'tcx> GlobalStateInner { alloc_id } else { // A wildcard pointer. - assert_eq!(ecx.machine.intptrcast.borrow().provenance_mode, ProvenanceMode::Permissive); GlobalStateInner::alloc_id_from_addr(ecx, addr.bytes())? }; diff --git a/src/machine.rs b/src/machine.rs index 3621744e8025c..d6a65a2a44c8c 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -353,7 +353,6 @@ impl<'mir, 'tcx> Evaluator<'mir, 'tcx> { Some(RefCell::new(stacked_borrows::GlobalStateInner::new( config.tracked_pointer_tags.clone(), config.tracked_call_ids.clone(), - config.tag_raw, ))) } else { None @@ -696,7 +695,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { ecx: &MiriEvalContext<'mir, 'tcx>, addr: u64, ) -> InterpResult<'tcx, Pointer>> { - Ok(intptrcast::GlobalStateInner::ptr_from_addr_cast(ecx, addr)) + intptrcast::GlobalStateInner::ptr_from_addr_cast(ecx, addr) } #[inline(always)] diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 6fa70ddfc5d4e..23408027626c6 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -219,11 +219,7 @@ impl fmt::Display for RefKind { /// Utilities for initialization and ID generation impl GlobalStateInner { - pub fn new( - tracked_pointer_tags: HashSet, - tracked_call_ids: HashSet, - tag_raw: bool, - ) -> Self { + pub fn new(tracked_pointer_tags: HashSet, tracked_call_ids: HashSet) -> Self { GlobalStateInner { next_ptr_id: NonZeroU64::new(1).unwrap(), base_ptr_ids: FxHashMap::default(), @@ -231,7 +227,7 @@ impl GlobalStateInner { active_calls: FxHashSet::default(), tracked_pointer_tags, tracked_call_ids, - tag_raw, + tag_raw: true, } } diff --git a/test-cargo-miri/run-test.py b/test-cargo-miri/run-test.py index 19965639489bf..42978c481bff9 100755 --- a/test-cargo-miri/run-test.py +++ b/test-cargo-miri/run-test.py @@ -124,11 +124,6 @@ def test_cargo_miri_test(): "test.cross-target.stdout.ref", "test.stderr-empty.ref", env={'MIRIFLAGS': "-Zmiri-disable-isolation"}, ) - test("`cargo miri test` (raw-ptr tracking)", - cargo_miri("test"), - default_ref, "test.stderr-empty.ref", - env={'MIRIFLAGS': "-Zmiri-tag-raw-pointers"}, - ) test("`cargo miri test` (with filter)", cargo_miri("test") + ["--", "--format=pretty", "le1"], filter_ref, "test.stderr-empty.ref", diff --git a/tests/fail/backtrace/bad-backtrace-flags.stderr b/tests/fail/backtrace/bad-backtrace-flags.stderr index f6ffe3c93c891..ba16335fce3a7 100644 --- a/tests/fail/backtrace/bad-backtrace-flags.stderr +++ b/tests/fail/backtrace/bad-backtrace-flags.stderr @@ -1,3 +1,18 @@ +warning: pointer-to-integer cast + --> $DIR/bad-backtrace-flags.rs:LL:CC + | +LL | miri_get_backtrace(2, 0 as *mut _); + | ^^^^^^^^^^^ pointer-to-integer cast + | + = help: this program is using integer-to-pointer casts or (equivalently) `from_exposed_addr`, + = help: which means that Miri might miss pointer bugs in this program + = help: see https://doc.rust-lang.org/nightly/std/ptr/fn.from_exposed_addr.html for more details on that operation + = help: to ensure that Miri does not miss bugs in your program, use `with_addr` (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance) instead + = help: you can then pass the `-Zmiri-strict-provenance` flag to Miri, to ensure you are not relying on `from_exposed_addr` semantics + = help: alternatively, the `-Zmiri-permissive-provenance` flag disables this warning + + = note: inside `main` at $DIR/bad-backtrace-flags.rs:LL:CC + error: unsupported operation: unknown `miri_get_backtrace` flags 2 --> $DIR/bad-backtrace-flags.rs:LL:CC | @@ -10,5 +25,5 @@ LL | miri_get_backtrace(2, 0 as *mut _); note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace -error: aborting due to previous error +error: aborting due to previous error; 1 warning emitted diff --git a/tests/fail/backtrace/bad-backtrace-ptr.stderr b/tests/fail/backtrace/bad-backtrace-ptr.stderr index ed726a5dcdc22..75268b6671421 100644 --- a/tests/fail/backtrace/bad-backtrace-ptr.stderr +++ b/tests/fail/backtrace/bad-backtrace-ptr.stderr @@ -1,3 +1,18 @@ +warning: pointer-to-integer cast + --> $DIR/bad-backtrace-ptr.rs:LL:CC + | +LL | miri_resolve_frame(0 as *mut _, 0); + | ^^^^^^^^^^^ pointer-to-integer cast + | + = help: this program is using integer-to-pointer casts or (equivalently) `from_exposed_addr`, + = help: which means that Miri might miss pointer bugs in this program + = help: see https://doc.rust-lang.org/nightly/std/ptr/fn.from_exposed_addr.html for more details on that operation + = help: to ensure that Miri does not miss bugs in your program, use `with_addr` (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance) instead + = help: you can then pass the `-Zmiri-strict-provenance` flag to Miri, to ensure you are not relying on `from_exposed_addr` semantics + = help: alternatively, the `-Zmiri-permissive-provenance` flag disables this warning + + = note: inside `main` at $DIR/bad-backtrace-ptr.rs:LL:CC + error: Undefined Behavior: null pointer is not a valid pointer for this operation --> $DIR/bad-backtrace-ptr.rs:LL:CC | @@ -11,5 +26,5 @@ LL | miri_resolve_frame(0 as *mut _, 0); note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace -error: aborting due to previous error +error: aborting due to previous error; 1 warning emitted diff --git a/tests/fail/backtrace/bad-backtrace-resolve-flags.stderr b/tests/fail/backtrace/bad-backtrace-resolve-flags.stderr index 49495651dfec4..fad9ffe119209 100644 --- a/tests/fail/backtrace/bad-backtrace-resolve-flags.stderr +++ b/tests/fail/backtrace/bad-backtrace-resolve-flags.stderr @@ -1,3 +1,18 @@ +warning: pointer-to-integer cast + --> $DIR/bad-backtrace-resolve-flags.rs:LL:CC + | +LL | let mut buf = vec![0 as *mut _; miri_backtrace_size(0)]; + | ^^^^^^^^^^^ pointer-to-integer cast + | + = help: this program is using integer-to-pointer casts or (equivalently) `from_exposed_addr`, + = help: which means that Miri might miss pointer bugs in this program + = help: see https://doc.rust-lang.org/nightly/std/ptr/fn.from_exposed_addr.html for more details on that operation + = help: to ensure that Miri does not miss bugs in your program, use `with_addr` (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance) instead + = help: you can then pass the `-Zmiri-strict-provenance` flag to Miri, to ensure you are not relying on `from_exposed_addr` semantics + = help: alternatively, the `-Zmiri-permissive-provenance` flag disables this warning + + = note: inside `main` at $DIR/bad-backtrace-resolve-flags.rs:LL:CC + error: unsupported operation: unknown `miri_resolve_frame` flags 2 --> $DIR/bad-backtrace-resolve-flags.rs:LL:CC | @@ -10,5 +25,5 @@ LL | miri_resolve_frame(buf[0], 2); note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace -error: aborting due to previous error +error: aborting due to previous error; 1 warning emitted diff --git a/tests/fail/backtrace/bad-backtrace-resolve-names-flags.stderr b/tests/fail/backtrace/bad-backtrace-resolve-names-flags.stderr index d575caa4ff4ed..18b03df21c6f6 100644 --- a/tests/fail/backtrace/bad-backtrace-resolve-names-flags.stderr +++ b/tests/fail/backtrace/bad-backtrace-resolve-names-flags.stderr @@ -1,3 +1,18 @@ +warning: pointer-to-integer cast + --> $DIR/bad-backtrace-resolve-names-flags.rs:LL:CC + | +LL | let mut buf = vec![0 as *mut _; miri_backtrace_size(0)]; + | ^^^^^^^^^^^ pointer-to-integer cast + | + = help: this program is using integer-to-pointer casts or (equivalently) `from_exposed_addr`, + = help: which means that Miri might miss pointer bugs in this program + = help: see https://doc.rust-lang.org/nightly/std/ptr/fn.from_exposed_addr.html for more details on that operation + = help: to ensure that Miri does not miss bugs in your program, use `with_addr` (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance) instead + = help: you can then pass the `-Zmiri-strict-provenance` flag to Miri, to ensure you are not relying on `from_exposed_addr` semantics + = help: alternatively, the `-Zmiri-permissive-provenance` flag disables this warning + + = note: inside `main` at $DIR/bad-backtrace-resolve-names-flags.rs:LL:CC + error: unsupported operation: unknown `miri_resolve_frame_names` flags 2 --> $DIR/bad-backtrace-resolve-names-flags.rs:LL:CC | @@ -10,5 +25,5 @@ LL | ... miri_resolve_frame_names(buf[0], 2, 0 as *mut _, 0 as *mut _); note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace -error: aborting due to previous error +error: aborting due to previous error; 1 warning emitted diff --git a/tests/fail/concurrency/thread_local_static_dealloc.stderr b/tests/fail/concurrency/thread_local_static_dealloc.stderr index 2a3a8f0f55c3b..31a64eec36858 100644 --- a/tests/fail/concurrency/thread_local_static_dealloc.stderr +++ b/tests/fail/concurrency/thread_local_static_dealloc.stderr @@ -1,3 +1,18 @@ +warning: pointer-to-integer cast + --> $DIR/thread_local_static_dealloc.rs:LL:CC + | +LL | let _val = *(dangling_ptr as *const u8); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ pointer-to-integer cast + | + = help: this program is using integer-to-pointer casts or (equivalently) `from_exposed_addr`, + = help: which means that Miri might miss pointer bugs in this program + = help: see https://doc.rust-lang.org/nightly/std/ptr/fn.from_exposed_addr.html for more details on that operation + = help: to ensure that Miri does not miss bugs in your program, use `with_addr` (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance) instead + = help: you can then pass the `-Zmiri-strict-provenance` flag to Miri, to ensure you are not relying on `from_exposed_addr` semantics + = help: alternatively, the `-Zmiri-permissive-provenance` flag disables this warning + + = note: inside `main` at $DIR/thread_local_static_dealloc.rs:LL:CC + error: Undefined Behavior: pointer to ALLOC was dereferenced after this allocation got freed --> $DIR/thread_local_static_dealloc.rs:LL:CC | @@ -11,5 +26,5 @@ LL | let _val = *(dangling_ptr as *const u8); note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace -error: aborting due to previous error +error: aborting due to previous error; 1 warning emitted diff --git a/tests/fail/dangling_pointers/deref-invalid-ptr.stderr b/tests/fail/dangling_pointers/deref-invalid-ptr.stderr index f4361d9fefa95..ffd7fb1980dc4 100644 --- a/tests/fail/dangling_pointers/deref-invalid-ptr.stderr +++ b/tests/fail/dangling_pointers/deref-invalid-ptr.stderr @@ -1,3 +1,18 @@ +warning: pointer-to-integer cast + --> $DIR/deref-invalid-ptr.rs:LL:CC + | +LL | let x = 16usize as *const u32; + | ^^^^^^^^^^^^^^^^^^^^^ pointer-to-integer cast + | + = help: this program is using integer-to-pointer casts or (equivalently) `from_exposed_addr`, + = help: which means that Miri might miss pointer bugs in this program + = help: see https://doc.rust-lang.org/nightly/std/ptr/fn.from_exposed_addr.html for more details on that operation + = help: to ensure that Miri does not miss bugs in your program, use `with_addr` (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance) instead + = help: you can then pass the `-Zmiri-strict-provenance` flag to Miri, to ensure you are not relying on `from_exposed_addr` semantics + = help: alternatively, the `-Zmiri-permissive-provenance` flag disables this warning + + = note: inside `main` at $DIR/deref-invalid-ptr.rs:LL:CC + error: Undefined Behavior: dereferencing pointer failed: 0x10 is not a valid pointer --> $DIR/deref-invalid-ptr.rs:LL:CC | @@ -11,5 +26,5 @@ LL | let _y = unsafe { &*x as *const u32 }; note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace -error: aborting due to previous error +error: aborting due to previous error; 1 warning emitted diff --git a/tests/fail/dangling_pointers/storage_dead_dangling.stderr b/tests/fail/dangling_pointers/storage_dead_dangling.stderr index aed14105ad077..3a94a7fa58ee9 100644 --- a/tests/fail/dangling_pointers/storage_dead_dangling.stderr +++ b/tests/fail/dangling_pointers/storage_dead_dangling.stderr @@ -1,3 +1,23 @@ +warning: pointer-to-integer cast + --> $DIR/storage_dead_dangling.rs:LL:CC + | +LL | unsafe { &mut *(LEAK as *mut i32) }; + | ^^^^^^^^^^^^^^^^^^ pointer-to-integer cast + | + = help: this program is using integer-to-pointer casts or (equivalently) `from_exposed_addr`, + = help: which means that Miri might miss pointer bugs in this program + = help: see https://doc.rust-lang.org/nightly/std/ptr/fn.from_exposed_addr.html for more details on that operation + = help: to ensure that Miri does not miss bugs in your program, use `with_addr` (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance) instead + = help: you can then pass the `-Zmiri-strict-provenance` flag to Miri, to ensure you are not relying on `from_exposed_addr` semantics + = help: alternatively, the `-Zmiri-permissive-provenance` flag disables this warning + + = note: inside `evil` at $DIR/storage_dead_dangling.rs:LL:CC +note: inside `main` at $DIR/storage_dead_dangling.rs:LL:CC + --> $DIR/storage_dead_dangling.rs:LL:CC + | +LL | evil(); + | ^^^^^^ + error: Undefined Behavior: pointer to ALLOC was dereferenced after this allocation got freed --> $DIR/storage_dead_dangling.rs:LL:CC | @@ -16,5 +36,5 @@ LL | evil(); note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace -error: aborting due to previous error +error: aborting due to previous error; 1 warning emitted diff --git a/tests/fail/dangling_pointers/wild_pointer_deref.stderr b/tests/fail/dangling_pointers/wild_pointer_deref.stderr index b20f310da083b..960f9c9ce3e9c 100644 --- a/tests/fail/dangling_pointers/wild_pointer_deref.stderr +++ b/tests/fail/dangling_pointers/wild_pointer_deref.stderr @@ -1,3 +1,18 @@ +warning: pointer-to-integer cast + --> $DIR/wild_pointer_deref.rs:LL:CC + | +LL | let p = 44 as *const i32; + | ^^^^^^^^^^^^^^^^ pointer-to-integer cast + | + = help: this program is using integer-to-pointer casts or (equivalently) `from_exposed_addr`, + = help: which means that Miri might miss pointer bugs in this program + = help: see https://doc.rust-lang.org/nightly/std/ptr/fn.from_exposed_addr.html for more details on that operation + = help: to ensure that Miri does not miss bugs in your program, use `with_addr` (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance) instead + = help: you can then pass the `-Zmiri-strict-provenance` flag to Miri, to ensure you are not relying on `from_exposed_addr` semantics + = help: alternatively, the `-Zmiri-permissive-provenance` flag disables this warning + + = note: inside `main` at $DIR/wild_pointer_deref.rs:LL:CC + error: Undefined Behavior: dereferencing pointer failed: 0x2c is not a valid pointer --> $DIR/wild_pointer_deref.rs:LL:CC | @@ -11,5 +26,5 @@ LL | let x = unsafe { *p }; note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace -error: aborting due to previous error +error: aborting due to previous error; 1 warning emitted diff --git a/tests/fail/intrinsics/ptr_offset_0_plus_0.stderr b/tests/fail/intrinsics/ptr_offset_0_plus_0.stderr index 741314ea8a680..2474820545d24 100644 --- a/tests/fail/intrinsics/ptr_offset_0_plus_0.stderr +++ b/tests/fail/intrinsics/ptr_offset_0_plus_0.stderr @@ -1,3 +1,18 @@ +warning: pointer-to-integer cast + --> $DIR/ptr_offset_0_plus_0.rs:LL:CC + | +LL | let x = 0 as *mut i32; + | ^^^^^^^^^^^^^ pointer-to-integer cast + | + = help: this program is using integer-to-pointer casts or (equivalently) `from_exposed_addr`, + = help: which means that Miri might miss pointer bugs in this program + = help: see https://doc.rust-lang.org/nightly/std/ptr/fn.from_exposed_addr.html for more details on that operation + = help: to ensure that Miri does not miss bugs in your program, use `with_addr` (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance) instead + = help: you can then pass the `-Zmiri-strict-provenance` flag to Miri, to ensure you are not relying on `from_exposed_addr` semantics + = help: alternatively, the `-Zmiri-permissive-provenance` flag disables this warning + + = note: inside `main` at $DIR/ptr_offset_0_plus_0.rs:LL:CC + error: Undefined Behavior: pointer arithmetic failed: null pointer is not a valid pointer --> RUSTLIB/core/src/ptr/mut_ptr.rs:LL:CC | @@ -16,5 +31,5 @@ LL | let _x = unsafe { x.offset(0) }; // UB despite offset 0, NULL is never note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace -error: aborting due to previous error +error: aborting due to previous error; 1 warning emitted diff --git a/tests/fail/intrinsics/ptr_offset_int_plus_int.stderr b/tests/fail/intrinsics/ptr_offset_int_plus_int.stderr index e6b8f102f3946..f5cbd4bbbf731 100644 --- a/tests/fail/intrinsics/ptr_offset_int_plus_int.stderr +++ b/tests/fail/intrinsics/ptr_offset_int_plus_int.stderr @@ -1,3 +1,18 @@ +warning: pointer-to-integer cast + --> $DIR/ptr_offset_int_plus_int.rs:LL:CC + | +LL | let _val = (1 as *mut u8).offset(1); + | ^^^^^^^^^^^^^^ pointer-to-integer cast + | + = help: this program is using integer-to-pointer casts or (equivalently) `from_exposed_addr`, + = help: which means that Miri might miss pointer bugs in this program + = help: see https://doc.rust-lang.org/nightly/std/ptr/fn.from_exposed_addr.html for more details on that operation + = help: to ensure that Miri does not miss bugs in your program, use `with_addr` (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance) instead + = help: you can then pass the `-Zmiri-strict-provenance` flag to Miri, to ensure you are not relying on `from_exposed_addr` semantics + = help: alternatively, the `-Zmiri-permissive-provenance` flag disables this warning + + = note: inside `main` at $DIR/ptr_offset_int_plus_int.rs:LL:CC + error: Undefined Behavior: pointer arithmetic failed: 0x1 is not a valid pointer --> RUSTLIB/core/src/ptr/mut_ptr.rs:LL:CC | @@ -16,5 +31,5 @@ LL | let _val = (1 as *mut u8).offset(1); note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace -error: aborting due to previous error +error: aborting due to previous error; 1 warning emitted diff --git a/tests/fail/intrinsics/ptr_offset_int_plus_ptr.stderr b/tests/fail/intrinsics/ptr_offset_int_plus_ptr.stderr index f88ad758d438d..577a377f076e7 100644 --- a/tests/fail/intrinsics/ptr_offset_int_plus_ptr.stderr +++ b/tests/fail/intrinsics/ptr_offset_int_plus_ptr.stderr @@ -1,3 +1,18 @@ +warning: pointer-to-integer cast + --> $DIR/ptr_offset_int_plus_ptr.rs:LL:CC + | +LL | let _val = (1 as *mut u8).offset(ptr as isize); + | ^^^^^^^^^^^^^^ pointer-to-integer cast + | + = help: this program is using integer-to-pointer casts or (equivalently) `from_exposed_addr`, + = help: which means that Miri might miss pointer bugs in this program + = help: see https://doc.rust-lang.org/nightly/std/ptr/fn.from_exposed_addr.html for more details on that operation + = help: to ensure that Miri does not miss bugs in your program, use `with_addr` (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance) instead + = help: you can then pass the `-Zmiri-strict-provenance` flag to Miri, to ensure you are not relying on `from_exposed_addr` semantics + = help: alternatively, the `-Zmiri-permissive-provenance` flag disables this warning + + = note: inside `main` at $DIR/ptr_offset_int_plus_ptr.rs:LL:CC + error: Undefined Behavior: pointer arithmetic failed: 0x1 is not a valid pointer --> RUSTLIB/core/src/ptr/mut_ptr.rs:LL:CC | @@ -16,5 +31,5 @@ LL | let _val = (1 as *mut u8).offset(ptr as isize); note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace -error: aborting due to previous error +error: aborting due to previous error; 1 warning emitted diff --git a/tests/fail/provenance/ptr_legacy_provenance.rs b/tests/fail/provenance/ptr_legacy_provenance.rs deleted file mode 100644 index 538ec4484edb9..0000000000000 --- a/tests/fail/provenance/ptr_legacy_provenance.rs +++ /dev/null @@ -1,22 +0,0 @@ -// compile-flags: -Zmiri-disable-stacked-borrows -// normalize-stderr-test: "offset -[0-9]+" -> "offset -XX" -#![feature(strict_provenance)] - -use std::ptr; - -// Make sure that with legacy provenance, the allocation id of -// a casted pointer is determined at cast-time -fn main() { - let x: i32 = 0; - let y: i32 = 1; - - let x_ptr = &x as *const i32; - let y_ptr = &y as *const i32; - - let x_usize = x_ptr.expose_addr(); - let y_usize = y_ptr.expose_addr(); - - let ptr = ptr::from_exposed_addr::(y_usize); - let ptr = ptr.with_addr(x_usize); - assert_eq!(unsafe { *ptr }, 0); //~ ERROR is out-of-bounds -} diff --git a/tests/fail/provenance/ptr_legacy_provenance.stderr b/tests/fail/provenance/ptr_legacy_provenance.stderr deleted file mode 100644 index 4552be08145d4..0000000000000 --- a/tests/fail/provenance/ptr_legacy_provenance.stderr +++ /dev/null @@ -1,15 +0,0 @@ -error: Undefined Behavior: dereferencing pointer failed: ALLOC has size 4, so pointer to 4 bytes starting at offset -XX is out-of-bounds - --> $DIR/ptr_legacy_provenance.rs:LL:CC - | -LL | assert_eq!(unsafe { *ptr }, 0); - | ^^^^ dereferencing pointer failed: ALLOC has size 4, so pointer to 4 bytes starting at offset -XX is out-of-bounds - | - = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior - = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - - = note: inside `main` at $DIR/ptr_legacy_provenance.rs:LL:CC - -note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace - -error: aborting due to previous error - diff --git a/tests/fail/stacked_borrows/aliasing_mut3.stderr b/tests/fail/stacked_borrows/aliasing_mut3.stderr index a4187be0a25b3..66220cfbfc4d3 100644 --- a/tests/fail/stacked_borrows/aliasing_mut3.stderr +++ b/tests/fail/stacked_borrows/aliasing_mut3.stderr @@ -1,20 +1,20 @@ -error: Undefined Behavior: trying to reborrow for SharedReadOnly permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location +error: Undefined Behavior: trying to reborrow for SharedReadOnly permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location --> $DIR/aliasing_mut3.rs:LL:CC | LL | pub fn safe(_x: &mut i32, _y: &i32) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | - | trying to reborrow for SharedReadOnly permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | trying to reborrow for SharedReadOnly permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location | this error occurs as part of a reborrow at ALLOC[0x0..0x4] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information -help: tag was most recently created at offsets [0x0..0x4] +help: was created by a retag at offsets [0x0..0x4] --> $DIR/aliasing_mut3.rs:LL:CC | LL | safe_raw(xraw, xshr); | ^^^^ -help: tag was later invalidated at offsets [0x0..0x4] +help: was later invalidated at offsets [0x0..0x4] --> $DIR/aliasing_mut3.rs:LL:CC | LL | pub fn safe(_x: &mut i32, _y: &i32) {} diff --git a/tests/fail/stacked_borrows/box_exclusive_violation1.rs b/tests/fail/stacked_borrows/box_exclusive_violation1.rs index 3ca480ae7ab83..66d092d6277c8 100644 --- a/tests/fail/stacked_borrows/box_exclusive_violation1.rs +++ b/tests/fail/stacked_borrows/box_exclusive_violation1.rs @@ -8,7 +8,7 @@ fn demo_mut_advanced_unique(mut our: Box) -> i32 { unknown_code_2(); // We know this will return 5 - *our //~ ERROR borrow stack + *our } // Now comes the evil context @@ -24,7 +24,7 @@ fn unknown_code_1(x: &i32) { fn unknown_code_2() { unsafe { - *LEAK = 7; + *LEAK = 7; //~ ERROR borrow stack } } diff --git a/tests/fail/stacked_borrows/box_exclusive_violation1.stderr b/tests/fail/stacked_borrows/box_exclusive_violation1.stderr index 3c3e6bbf1bc72..06c2dc340b7ba 100644 --- a/tests/fail/stacked_borrows/box_exclusive_violation1.stderr +++ b/tests/fail/stacked_borrows/box_exclusive_violation1.stderr @@ -1,31 +1,30 @@ -error: Undefined Behavior: attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location +error: Undefined Behavior: attempting a write access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location --> $DIR/box_exclusive_violation1.rs:LL:CC | -LL | *our - | ^^^^ - | | - | attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location - | this error occurs as part of an access at ALLOC[0x0..0x4] +LL | *LEAK = 7; + | ^^^^^^^^^ + | | + | attempting a write access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | this error occurs as part of an access at ALLOC[0x0..0x4] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: was created by a retag at offsets [0x0..0x4] --> $DIR/box_exclusive_violation1.rs:LL:CC | -LL | / fn demo_mut_advanced_unique(mut our: Box) -> i32 { -LL | | unknown_code_1(&*our); -LL | | -LL | | // This "re-asserts" uniqueness of the reference: After writing, we know -... | -LL | | *our -LL | | } - | |_^ +LL | LEAK = x as *const _ as *mut _; + | ^ help: was later invalidated at offsets [0x0..0x4] --> $DIR/box_exclusive_violation1.rs:LL:CC | -LL | *LEAK = 7; - | ^^^^^^^^^ - = note: inside `demo_mut_advanced_unique` at $DIR/box_exclusive_violation1.rs:LL:CC +LL | *our = 5; + | ^^^^^^^^ + = note: inside `unknown_code_2` at $DIR/box_exclusive_violation1.rs:LL:CC +note: inside `demo_mut_advanced_unique` at $DIR/box_exclusive_violation1.rs:LL:CC + --> $DIR/box_exclusive_violation1.rs:LL:CC + | +LL | unknown_code_2(); + | ^^^^^^^^^^^^^^^^ note: inside `main` at $DIR/box_exclusive_violation1.rs:LL:CC --> $DIR/box_exclusive_violation1.rs:LL:CC | diff --git a/tests/fail/stacked_borrows/illegal_read3.rs b/tests/fail/stacked_borrows/illegal_read3.rs index 3de8f57d6223c..0173ca14b22da 100644 --- a/tests/fail/stacked_borrows/illegal_read3.rs +++ b/tests/fail/stacked_borrows/illegal_read3.rs @@ -5,7 +5,7 @@ use std::mem; union HiddenRef { - // We avoid retagging at this type, so shared vs mutable does not matter. + // We avoid retagging at this type, and we only read, so shared vs mutable does not matter. r: &'static i32, } diff --git a/tests/fail/stacked_borrows/illegal_read6.stderr b/tests/fail/stacked_borrows/illegal_read6.stderr index 9782f1aa3a58d..2098dbdc6a492 100644 --- a/tests/fail/stacked_borrows/illegal_read6.stderr +++ b/tests/fail/stacked_borrows/illegal_read6.stderr @@ -1,20 +1,20 @@ -error: Undefined Behavior: attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location +error: Undefined Behavior: attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location --> $DIR/illegal_read6.rs:LL:CC | LL | let _val = *raw; | ^^^^ | | - | attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location | this error occurs as part of an access at ALLOC[0x0..0x4] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information -help: tag was most recently created at offsets [0x0..0x4] +help: was created by a retag at offsets [0x0..0x4] --> $DIR/illegal_read6.rs:LL:CC | LL | let raw = x as *mut _; | ^ -help: tag was later invalidated at offsets [0x0..0x4] +help: was later invalidated at offsets [0x0..0x4] --> $DIR/illegal_read6.rs:LL:CC | LL | let x = &mut *x; // kill `raw` diff --git a/tests/fail/stacked_borrows/illegal_write1.rs b/tests/fail/stacked_borrows/illegal_write1.rs index 1f566f18c1f8e..58600402e4edd 100644 --- a/tests/fail/stacked_borrows/illegal_write1.rs +++ b/tests/fail/stacked_borrows/illegal_write1.rs @@ -3,7 +3,7 @@ fn main() { let xref = &*target; { let x: *mut u32 = xref as *const _ as *mut _; - unsafe { *x = 42 }; // invalidates shared ref, activates raw + unsafe { *x = 42 }; //~ ERROR only grants SharedReadOnly permission } - let _x = *xref; //~ ERROR borrow stack + let _x = *xref; } diff --git a/tests/fail/stacked_borrows/illegal_write1.stderr b/tests/fail/stacked_borrows/illegal_write1.stderr index 1731e3c1de13d..b2084da862fe0 100644 --- a/tests/fail/stacked_borrows/illegal_write1.stderr +++ b/tests/fail/stacked_borrows/illegal_write1.stderr @@ -1,24 +1,19 @@ -error: Undefined Behavior: attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location +error: Undefined Behavior: attempting a write access using at ALLOC[0x0], but that tag only grants SharedReadOnly permission for this location --> $DIR/illegal_write1.rs:LL:CC | -LL | let _x = *xref; - | ^^^^^ - | | - | attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location - | this error occurs as part of an access at ALLOC[0x0..0x4] +LL | unsafe { *x = 42 }; + | ^^^^^^^ + | | + | attempting a write access using at ALLOC[0x0], but that tag only grants SharedReadOnly permission for this location + | this error occurs as part of an access at ALLOC[0x0..0x4] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: was created by a retag at offsets [0x0..0x4] --> $DIR/illegal_write1.rs:LL:CC | -LL | let xref = &*target; - | ^^^^^^^^ -help: was later invalidated at offsets [0x0..0x4] - --> $DIR/illegal_write1.rs:LL:CC - | -LL | unsafe { *x = 42 }; // invalidates shared ref, activates raw - | ^^^^^^^ +LL | let x: *mut u32 = xref as *const _ as *mut _; + | ^^^^ = note: inside `main` at $DIR/illegal_write1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/illegal_write2.stderr b/tests/fail/stacked_borrows/illegal_write2.stderr index 7e896c530ac73..09784bd79a188 100644 --- a/tests/fail/stacked_borrows/illegal_write2.stderr +++ b/tests/fail/stacked_borrows/illegal_write2.stderr @@ -1,20 +1,20 @@ -error: Undefined Behavior: attempting a write access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location +error: Undefined Behavior: attempting a write access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location --> $DIR/illegal_write2.rs:LL:CC | LL | unsafe { *target2 = 13 }; | ^^^^^^^^^^^^^ | | - | attempting a write access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | attempting a write access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location | this error occurs as part of an access at ALLOC[0x0..0x4] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information -help: tag was most recently created at offsets [0x0..0x4] +help: was created by a retag at offsets [0x0..0x4] --> $DIR/illegal_write2.rs:LL:CC | LL | let target2 = target as *mut _; | ^^^^^^ -help: tag was later invalidated at offsets [0x0..0x4] +help: was later invalidated at offsets [0x0..0x4] --> $DIR/illegal_write2.rs:LL:CC | LL | drop(&mut *target); // reborrow diff --git a/tests/fail/stacked_borrows/illegal_write3.stderr b/tests/fail/stacked_borrows/illegal_write3.stderr index 7e9c82769d6ad..983894dad065c 100644 --- a/tests/fail/stacked_borrows/illegal_write3.stderr +++ b/tests/fail/stacked_borrows/illegal_write3.stderr @@ -1,15 +1,15 @@ -error: Undefined Behavior: attempting a write access using at ALLOC[0x0], but that tag only grants SharedReadOnly permission for this location +error: Undefined Behavior: attempting a write access using at ALLOC[0x0], but that tag only grants SharedReadOnly permission for this location --> $DIR/illegal_write3.rs:LL:CC | LL | unsafe { *ptr = 42 }; | ^^^^^^^^^ | | - | attempting a write access using at ALLOC[0x0], but that tag only grants SharedReadOnly permission for this location + | attempting a write access using at ALLOC[0x0], but that tag only grants SharedReadOnly permission for this location | this error occurs as part of an access at ALLOC[0x0..0x4] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information -help: tag was most recently created at offsets [0x0..0x4] +help: was created by a retag at offsets [0x0..0x4] --> $DIR/illegal_write3.rs:LL:CC | LL | let ptr = r#ref as *const _ as *mut _; // raw ptr, with raw tag diff --git a/tests/fail/stacked_borrows/illegal_write4.rs b/tests/fail/stacked_borrows/illegal_write4.rs index be4f89ba289a1..654a23d382b8d 100644 --- a/tests/fail/stacked_borrows/illegal_write4.rs +++ b/tests/fail/stacked_borrows/illegal_write4.rs @@ -6,8 +6,8 @@ fn main() { // Even just creating it unfreezes. let raw = &mut target as *mut _; // let this leak to raw let reference = unsafe { &*raw }; // freeze - let ptr = reference as *const _ as *mut i32; // raw ptr, with raw tag - let _mut_ref: &mut i32 = unsafe { mem::transmute(ptr) }; // &mut, with raw tag + let _ptr = reference as *const _ as *mut i32; // raw ptr, with raw tag + let _mut_ref: &mut i32 = unsafe { mem::transmute(raw) }; // &mut, with raw tag // Now we retag, making our ref top-of-stack -- and, in particular, unfreezing. let _val = *reference; //~ ERROR borrow stack } diff --git a/tests/fail/stacked_borrows/illegal_write4.stderr b/tests/fail/stacked_borrows/illegal_write4.stderr index 404e13d1138a2..ac4dd68bbc7e4 100644 --- a/tests/fail/stacked_borrows/illegal_write4.stderr +++ b/tests/fail/stacked_borrows/illegal_write4.stderr @@ -17,7 +17,7 @@ LL | let reference = unsafe { &*raw }; // freeze help: was later invalidated at offsets [0x0..0x4] --> $DIR/illegal_write4.rs:LL:CC | -LL | let _mut_ref: &mut i32 = unsafe { mem::transmute(ptr) }; // &mut, with raw tag +LL | let _mut_ref: &mut i32 = unsafe { mem::transmute(raw) }; // &mut, with raw tag | ^^^^^^^^^^^^^^^^^^^ = note: inside `main` at $DIR/illegal_write4.rs:LL:CC diff --git a/tests/fail/stacked_borrows/illegal_write6.stderr b/tests/fail/stacked_borrows/illegal_write6.stderr index 11757cca9b657..563397e062d59 100644 --- a/tests/fail/stacked_borrows/illegal_write6.stderr +++ b/tests/fail/stacked_borrows/illegal_write6.stderr @@ -1,17 +1,17 @@ -error: Undefined Behavior: not granting access to tag because incompatible item is protected: [Unique for (call ID)] +error: Undefined Behavior: not granting access to tag because incompatible item is protected: [Unique for (call ID)] --> $DIR/illegal_write6.rs:LL:CC | LL | unsafe { *y = 2 }; - | ^^^^^^ not granting access to tag because incompatible item is protected: [Unique for (call ID)] + | ^^^^^^ not granting access to tag because incompatible item is protected: [Unique for (call ID)] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information -help: tag was most recently created at offsets [0x0..0x4] +help: was created by a retag at offsets [0x0..0x4] --> $DIR/illegal_write6.rs:LL:CC | LL | let p = x as *mut u32; | ^ -help: was protected due to a tag which was created here +help: was protected due to which was created here --> $DIR/illegal_write6.rs:LL:CC | LL | foo(x, p); diff --git a/tests/fail/stacked_borrows/invalidate_against_barrier1.stderr b/tests/fail/stacked_borrows/invalidate_against_barrier1.stderr index 08d597ea1895b..826cdc9b5f8e6 100644 --- a/tests/fail/stacked_borrows/invalidate_against_barrier1.stderr +++ b/tests/fail/stacked_borrows/invalidate_against_barrier1.stderr @@ -1,17 +1,17 @@ -error: Undefined Behavior: not granting access to tag because incompatible item is protected: [Unique for (call ID)] +error: Undefined Behavior: not granting access to tag because incompatible item is protected: [Unique for (call ID)] --> $DIR/invalidate_against_barrier1.rs:LL:CC | LL | let _val = unsafe { *x }; - | ^^ not granting access to tag because incompatible item is protected: [Unique for (call ID)] + | ^^ not granting access to tag because incompatible item is protected: [Unique for (call ID)] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information -help: tag was most recently created at offsets [0x0..0x4] +help: was created by a retag at offsets [0x0..0x4] --> $DIR/invalidate_against_barrier1.rs:LL:CC | LL | let xraw = &mut x as *mut _; | ^^^^^^ -help: was protected due to a tag which was created here +help: was protected due to which was created here --> $DIR/invalidate_against_barrier1.rs:LL:CC | LL | inner(xraw, xref); diff --git a/tests/fail/stacked_borrows/invalidate_against_barrier2.stderr b/tests/fail/stacked_borrows/invalidate_against_barrier2.stderr index 6aefa216ed56d..1cf90f91db02b 100644 --- a/tests/fail/stacked_borrows/invalidate_against_barrier2.stderr +++ b/tests/fail/stacked_borrows/invalidate_against_barrier2.stderr @@ -1,17 +1,17 @@ -error: Undefined Behavior: not granting access to tag because incompatible item is protected: [SharedReadOnly for (call ID)] +error: Undefined Behavior: not granting access to tag because incompatible item is protected: [SharedReadOnly for (call ID)] --> $DIR/invalidate_against_barrier2.rs:LL:CC | LL | unsafe { *x = 0 }; - | ^^^^^^ not granting access to tag because incompatible item is protected: [SharedReadOnly for (call ID)] + | ^^^^^^ not granting access to tag because incompatible item is protected: [SharedReadOnly for (call ID)] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information -help: tag was most recently created at offsets [0x0..0x4] +help: was created by a retag at offsets [0x0..0x4] --> $DIR/invalidate_against_barrier2.rs:LL:CC | LL | let xraw = &mut x as *mut _; | ^^^^^^ -help: was protected due to a tag which was created here +help: was protected due to which was created here --> $DIR/invalidate_against_barrier2.rs:LL:CC | LL | inner(xraw, xref); diff --git a/tests/fail/stacked_borrows/mut_exclusive_violation1.stderr b/tests/fail/stacked_borrows/mut_exclusive_violation1.stderr index ea14536a39905..8afb4fee18b51 100644 --- a/tests/fail/stacked_borrows/mut_exclusive_violation1.stderr +++ b/tests/fail/stacked_borrows/mut_exclusive_violation1.stderr @@ -1,20 +1,20 @@ -error: Undefined Behavior: attempting a write access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location +error: Undefined Behavior: attempting a write access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location --> $DIR/mut_exclusive_violation1.rs:LL:CC | LL | *LEAK = 7; | ^^^^^^^^^ | | - | attempting a write access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | attempting a write access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location | this error occurs as part of an access at ALLOC[0x0..0x4] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information -help: tag was most recently created at offsets [0x0..0x4] +help: was created by a retag at offsets [0x0..0x4] --> $DIR/mut_exclusive_violation1.rs:LL:CC | LL | LEAK = x as *const _ as *mut _; | ^ -help: tag was later invalidated at offsets [0x0..0x4] +help: was later invalidated at offsets [0x0..0x4] --> $DIR/mut_exclusive_violation1.rs:LL:CC | LL | *our = 5; diff --git a/tests/fail/stacked_borrows/outdated_local.stderr b/tests/fail/stacked_borrows/outdated_local.stderr index fe3bdd00f462e..c218d500cf8b8 100644 --- a/tests/fail/stacked_borrows/outdated_local.stderr +++ b/tests/fail/stacked_borrows/outdated_local.stderr @@ -1,20 +1,20 @@ -error: Undefined Behavior: attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location +error: Undefined Behavior: attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location --> $DIR/outdated_local.rs:LL:CC | LL | assert_eq!(unsafe { *y }, 1); | ^^ | | - | attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location | this error occurs as part of an access at ALLOC[0x0..0x4] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information -help: tag was most recently created at offsets [0x0..0x4] +help: was created by a retag at offsets [0x0..0x4] --> $DIR/outdated_local.rs:LL:CC | LL | let y: *const i32 = &x; | ^^ -help: tag was later invalidated at offsets [0x0..0x4] +help: was later invalidated at offsets [0x0..0x4] --> $DIR/outdated_local.rs:LL:CC | LL | x = 1; // this invalidates y by reactivating the lowermost uniq borrow for this local diff --git a/tests/fail/stacked_borrows/pointer_smuggling.stderr b/tests/fail/stacked_borrows/pointer_smuggling.stderr index 68ac631ec09e5..a3ab1b9fc5e5c 100644 --- a/tests/fail/stacked_borrows/pointer_smuggling.stderr +++ b/tests/fail/stacked_borrows/pointer_smuggling.stderr @@ -1,20 +1,20 @@ -error: Undefined Behavior: attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location +error: Undefined Behavior: attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location --> $DIR/pointer_smuggling.rs:LL:CC | LL | let _x = unsafe { *PTR }; | ^^^^ | | - | attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location | this error occurs as part of an access at ALLOC[0x0..0x1] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information -help: tag was most recently created at offsets [0x0..0x1] +help: was created by a retag at offsets [0x0..0x1] --> $DIR/pointer_smuggling.rs:LL:CC | LL | PTR = x; | ^ -help: tag was later invalidated at offsets [0x0..0x1] +help: was later invalidated at offsets [0x0..0x1] --> $DIR/pointer_smuggling.rs:LL:CC | LL | *val = 2; // this invalidates any raw ptrs `fun1` might have created. diff --git a/tests/fail/stacked_borrows/raw_tracking.rs b/tests/fail/stacked_borrows/raw_tracking.rs index 0b9c058f06ef1..49fe983125500 100644 --- a/tests/fail/stacked_borrows/raw_tracking.rs +++ b/tests/fail/stacked_borrows/raw_tracking.rs @@ -1,4 +1,3 @@ -// compile-flags: -Zmiri-tag-raw-pointers //! This demonstrates a provenance problem that requires tracking of raw pointers to be detected. fn main() { diff --git a/tests/fail/stacked_borrows/shr_frozen_violation1.stderr b/tests/fail/stacked_borrows/shr_frozen_violation1.stderr index 0808d8471b452..55872300713a2 100644 --- a/tests/fail/stacked_borrows/shr_frozen_violation1.stderr +++ b/tests/fail/stacked_borrows/shr_frozen_violation1.stderr @@ -1,15 +1,15 @@ -error: Undefined Behavior: attempting a write access using at ALLOC[0x0], but that tag only grants SharedReadOnly permission for this location +error: Undefined Behavior: attempting a write access using at ALLOC[0x0], but that tag only grants SharedReadOnly permission for this location --> $DIR/shr_frozen_violation1.rs:LL:CC | LL | *(x as *const i32 as *mut i32) = 7; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | - | attempting a write access using at ALLOC[0x0], but that tag only grants SharedReadOnly permission for this location + | attempting a write access using at ALLOC[0x0], but that tag only grants SharedReadOnly permission for this location | this error occurs as part of an access at ALLOC[0x0..0x4] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information -help: tag was most recently created at offsets [0x0..0x4] +help: was created by a retag at offsets [0x0..0x4] --> $DIR/shr_frozen_violation1.rs:LL:CC | LL | *(x as *const i32 as *mut i32) = 7; diff --git a/tests/fail/stacked_borrows/transmute-is-no-escape.stderr b/tests/fail/stacked_borrows/transmute-is-no-escape.stderr index a9682f806ba2b..91c3ff9f8634a 100644 --- a/tests/fail/stacked_borrows/transmute-is-no-escape.stderr +++ b/tests/fail/stacked_borrows/transmute-is-no-escape.stderr @@ -1,15 +1,19 @@ -error: Undefined Behavior: attempting a write access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location +error: Undefined Behavior: attempting a write access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location --> $DIR/transmute-is-no-escape.rs:LL:CC | LL | unsafe { *raw = 13 }; | ^^^^^^^^^ | | - | attempting a write access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | attempting a write access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location | this error occurs as part of an access at ALLOC[0x0..0x4] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information - +help: was created by a retag at offsets [0x4..0x8] + --> $DIR/transmute-is-no-escape.rs:LL:CC + | +LL | let raw = (&mut x[1] as *mut i32).wrapping_offset(-1); + | ^^^^^^^^^ = note: inside `main` at $DIR/transmute-is-no-escape.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/unescaped_local.stderr b/tests/fail/stacked_borrows/unescaped_local.stderr index 616c60b8aa1b8..2f6605c058b2d 100644 --- a/tests/fail/stacked_borrows/unescaped_local.stderr +++ b/tests/fail/stacked_borrows/unescaped_local.stderr @@ -1,27 +1,33 @@ -error: Undefined Behavior: attempting a write access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location +warning: pointer-to-integer cast + --> $DIR/unescaped_local.rs:LL:CC + | +LL | let raw = &mut x as *mut i32 as usize as *mut i32; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pointer-to-integer cast + | + = help: this program is using integer-to-pointer casts or (equivalently) `from_exposed_addr`, + = help: which means that Miri might miss pointer bugs in this program + = help: see https://doc.rust-lang.org/nightly/std/ptr/fn.from_exposed_addr.html for more details on that operation + = help: to ensure that Miri does not miss bugs in your program, use `with_addr` (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance) instead + = help: you can then pass the `-Zmiri-strict-provenance` flag to Miri, to ensure you are not relying on `from_exposed_addr` semantics + = help: alternatively, the `-Zmiri-permissive-provenance` flag disables this warning + + = note: inside `main` at $DIR/unescaped_local.rs:LL:CC + +error: Undefined Behavior: attempting a write access using at ALLOC[0x0], but no exposed tags have suitable permission in the borrow stack for this location --> $DIR/unescaped_local.rs:LL:CC | LL | *raw = 13; | ^^^^^^^^^ | | - | attempting a write access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | attempting a write access using at ALLOC[0x0], but no exposed tags have suitable permission in the borrow stack for this location | this error occurs as part of an access at ALLOC[0x0..0x4] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information -help: tag was most recently created at offsets [0x0..0x4] - --> $DIR/unescaped_local.rs:LL:CC - | -LL | let raw = &mut x as *mut i32 as usize as *mut i32; - | ^^^^^^ -help: tag was later invalidated at offsets [0x0..0x4] - --> $DIR/unescaped_local.rs:LL:CC - | -LL | let _ptr = &mut x; - | ^^^^^^ + = note: inside `main` at $DIR/unescaped_local.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace -error: aborting due to previous error +error: aborting due to previous error; 1 warning emitted diff --git a/tests/fail/stacked_borrows/unescaped_static.stderr b/tests/fail/stacked_borrows/unescaped_static.stderr index a0ac19f042934..621e9617fdfcc 100644 --- a/tests/fail/stacked_borrows/unescaped_static.stderr +++ b/tests/fail/stacked_borrows/unescaped_static.stderr @@ -1,15 +1,19 @@ -error: Undefined Behavior: attempting a read access using at ALLOC[0x1], but that tag does not exist in the borrow stack for this location +error: Undefined Behavior: attempting a read access using at ALLOC[0x1], but that tag does not exist in the borrow stack for this location --> $DIR/unescaped_static.rs:LL:CC | LL | let _val = unsafe { *ptr_to_first.add(1) }; | ^^^^^^^^^^^^^^^^^^^^ | | - | attempting a read access using at ALLOC[0x1], but that tag does not exist in the borrow stack for this location + | attempting a read access using at ALLOC[0x1], but that tag does not exist in the borrow stack for this location | this error occurs as part of an access at ALLOC[0x1..0x2] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information - +help: was created by a retag at offsets [0x0..0x1] + --> $DIR/unescaped_static.rs:LL:CC + | +LL | let ptr_to_first = &ARRAY[0] as *const u8; + | ^^^^^^^^^ = note: inside `main` at $DIR/unescaped_static.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/unaligned_pointers/intptrcast_alignment_check.stderr b/tests/fail/unaligned_pointers/intptrcast_alignment_check.stderr index 347486187e1b9..bd8d161de8327 100644 --- a/tests/fail/unaligned_pointers/intptrcast_alignment_check.stderr +++ b/tests/fail/unaligned_pointers/intptrcast_alignment_check.stderr @@ -1,3 +1,18 @@ +warning: pointer-to-integer cast + --> $DIR/intptrcast_alignment_check.rs:LL:CC + | +LL | let u16_ptr = base_addr_aligned as *mut u16; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pointer-to-integer cast + | + = help: this program is using integer-to-pointer casts or (equivalently) `from_exposed_addr`, + = help: which means that Miri might miss pointer bugs in this program + = help: see https://doc.rust-lang.org/nightly/std/ptr/fn.from_exposed_addr.html for more details on that operation + = help: to ensure that Miri does not miss bugs in your program, use `with_addr` (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance) instead + = help: you can then pass the `-Zmiri-strict-provenance` flag to Miri, to ensure you are not relying on `from_exposed_addr` semantics + = help: alternatively, the `-Zmiri-permissive-provenance` flag disables this warning + + = note: inside `main` at $DIR/intptrcast_alignment_check.rs:LL:CC + error: Undefined Behavior: accessing memory with alignment ALIGN, but alignment ALIGN is required --> $DIR/intptrcast_alignment_check.rs:LL:CC | @@ -11,5 +26,5 @@ LL | unsafe { *u16_ptr = 2 }; note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace -error: aborting due to previous error +error: aborting due to previous error; 1 warning emitted diff --git a/tests/fail/uninit_byte_read.rs b/tests/fail/uninit_byte_read.rs index 6868e5895507d..683088e78bffb 100644 --- a/tests/fail/uninit_byte_read.rs +++ b/tests/fail/uninit_byte_read.rs @@ -1,3 +1,4 @@ +// compile-flags: -Zmiri-disable-stacked-borrows fn main() { let v: Vec = Vec::with_capacity(10); let undef = unsafe { *v.get_unchecked(5) }; //~ ERROR uninitialized diff --git a/tests/fail/validity/cast_fn_ptr1.stderr b/tests/fail/validity/cast_fn_ptr1.stderr index d048377a7793d..d75857900052e 100644 --- a/tests/fail/validity/cast_fn_ptr1.stderr +++ b/tests/fail/validity/cast_fn_ptr1.stderr @@ -1,3 +1,18 @@ +warning: pointer-to-integer cast + --> $DIR/cast_fn_ptr1.rs:LL:CC + | +LL | g(0usize as *const i32) + | ^^^^^^^^^^^^^^^^^^^^ pointer-to-integer cast + | + = help: this program is using integer-to-pointer casts or (equivalently) `from_exposed_addr`, + = help: which means that Miri might miss pointer bugs in this program + = help: see https://doc.rust-lang.org/nightly/std/ptr/fn.from_exposed_addr.html for more details on that operation + = help: to ensure that Miri does not miss bugs in your program, use `with_addr` (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance) instead + = help: you can then pass the `-Zmiri-strict-provenance` flag to Miri, to ensure you are not relying on `from_exposed_addr` semantics + = help: alternatively, the `-Zmiri-permissive-provenance` flag disables this warning + + = note: inside `main` at $DIR/cast_fn_ptr1.rs:LL:CC + error: Undefined Behavior: type validation failed: encountered a null reference --> $DIR/cast_fn_ptr1.rs:LL:CC | @@ -11,5 +26,5 @@ LL | g(0usize as *const i32) note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace -error: aborting due to previous error +error: aborting due to previous error; 1 warning emitted diff --git a/tests/fail/validity/cast_fn_ptr2.stderr b/tests/fail/validity/cast_fn_ptr2.stderr index 10b9b9b8602b6..d47b39356ffcd 100644 --- a/tests/fail/validity/cast_fn_ptr2.stderr +++ b/tests/fail/validity/cast_fn_ptr2.stderr @@ -1,3 +1,23 @@ +warning: pointer-to-integer cast + --> $DIR/cast_fn_ptr2.rs:LL:CC + | +LL | 0usize as *const i32 + | ^^^^^^^^^^^^^^^^^^^^ pointer-to-integer cast + | + = help: this program is using integer-to-pointer casts or (equivalently) `from_exposed_addr`, + = help: which means that Miri might miss pointer bugs in this program + = help: see https://doc.rust-lang.org/nightly/std/ptr/fn.from_exposed_addr.html for more details on that operation + = help: to ensure that Miri does not miss bugs in your program, use `with_addr` (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance) instead + = help: you can then pass the `-Zmiri-strict-provenance` flag to Miri, to ensure you are not relying on `from_exposed_addr` semantics + = help: alternatively, the `-Zmiri-permissive-provenance` flag disables this warning + + = note: inside `main::f` at $DIR/cast_fn_ptr2.rs:LL:CC +note: inside `main` at $DIR/cast_fn_ptr2.rs:LL:CC + --> $DIR/cast_fn_ptr2.rs:LL:CC + | +LL | let _x = g(); + | ^^^ + error: Undefined Behavior: type validation failed: encountered a null reference --> $DIR/cast_fn_ptr2.rs:LL:CC | @@ -11,5 +31,5 @@ LL | let _x = g(); note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace -error: aborting due to previous error +error: aborting due to previous error; 1 warning emitted diff --git a/tests/pass/adjacent-allocs.rs b/tests/pass/adjacent-allocs.rs index 509965fe4fa97..925430ae20309 100644 --- a/tests/pass/adjacent-allocs.rs +++ b/tests/pass/adjacent-allocs.rs @@ -1,3 +1,5 @@ +// compile-flags: -Zmiri-permissive-provenance + fn main() { // The slack between allocations is random. // Loop a few times to hit the zero-slack case. diff --git a/tests/pass/align.stderr b/tests/pass/align.stderr new file mode 100644 index 0000000000000..9a15ec2cda6cd --- /dev/null +++ b/tests/pass/align.stderr @@ -0,0 +1,20 @@ +warning: pointer-to-integer cast + --> $DIR/align.rs:LL:CC + | +LL | let u16_ptr = base_addr_aligned as *mut u16; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pointer-to-integer cast + | + = help: this program is using integer-to-pointer casts or (equivalently) `from_exposed_addr`, + = help: which means that Miri might miss pointer bugs in this program + = help: see https://doc.rust-lang.org/nightly/std/ptr/fn.from_exposed_addr.html for more details on that operation + = help: to ensure that Miri does not miss bugs in your program, use `with_addr` (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance) instead + = help: you can then pass the `-Zmiri-strict-provenance` flag to Miri, to ensure you are not relying on `from_exposed_addr` semantics + = help: alternatively, the `-Zmiri-permissive-provenance` flag disables this warning + + = note: inside `manual_alignment` at $DIR/align.rs:LL:CC +note: inside `main` at $DIR/align.rs:LL:CC + --> $DIR/align.rs:LL:CC + | +LL | manual_alignment(); + | ^^^^^^^^^^^^^^^^^^ + diff --git a/tests/pass/box.rs b/tests/pass/box.rs index c2ecc3707179f..7bbe7be516b9a 100644 --- a/tests/pass/box.rs +++ b/tests/pass/box.rs @@ -47,7 +47,7 @@ fn boxed_pair_to_vec() { struct Foo(u64); fn reinterstruct(box_pair: Box) -> Vec { let ref_pair = Box::leak(box_pair) as *mut PairFoo; - let ptr_foo = unsafe { &mut (*ref_pair).fst as *mut Foo }; + let ptr_foo = unsafe { std::ptr::addr_of_mut!((*ref_pair).fst) }; unsafe { Vec::from_raw_parts(ptr_foo, 2, 2) } } diff --git a/tests/pass/box.stderr b/tests/pass/box.stderr new file mode 100644 index 0000000000000..eac98bf2d124f --- /dev/null +++ b/tests/pass/box.stderr @@ -0,0 +1,20 @@ +warning: pointer-to-integer cast + --> $DIR/box.rs:LL:CC + | +LL | let r2 = ((r as usize) + 0) as *mut i32; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pointer-to-integer cast + | + = help: this program is using integer-to-pointer casts or (equivalently) `from_exposed_addr`, + = help: which means that Miri might miss pointer bugs in this program + = help: see https://doc.rust-lang.org/nightly/std/ptr/fn.from_exposed_addr.html for more details on that operation + = help: to ensure that Miri does not miss bugs in your program, use `with_addr` (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance) instead + = help: you can then pass the `-Zmiri-strict-provenance` flag to Miri, to ensure you are not relying on `from_exposed_addr` semantics + = help: alternatively, the `-Zmiri-permissive-provenance` flag disables this warning + + = note: inside `into_raw` at $DIR/box.rs:LL:CC +note: inside `main` at $DIR/box.rs:LL:CC + --> $DIR/box.rs:LL:CC + | +LL | into_raw(); + | ^^^^^^^^^^ + diff --git a/tests/pass/concurrency/tls_pthread_drop_order.rs b/tests/pass/concurrency/tls_pthread_drop_order.rs index 4d69449821cd2..29c57bf49a338 100644 --- a/tests/pass/concurrency/tls_pthread_drop_order.rs +++ b/tests/pass/concurrency/tls_pthread_drop_order.rs @@ -4,6 +4,7 @@ extern crate libc; use std::mem; +use std::ptr; pub type Key = libc::pthread_key_t; @@ -11,7 +12,7 @@ static mut RECORD: usize = 0; static mut KEYS: [Key; 2] = [0; 2]; static mut GLOBALS: [u64; 2] = [1, 0]; -static mut CANNARY: *mut u64 = 0 as *mut _; // this serves as a cannary: if TLS dtors are not run properly, this will not get deallocated, making the test fail. +static mut CANNARY: *mut u64 = ptr::null_mut(); // this serves as a cannary: if TLS dtors are not run properly, this will not get deallocated, making the test fail. pub unsafe fn create(dtor: Option) -> Key { let mut key = 0; @@ -30,7 +31,7 @@ pub fn record(r: usize) { } unsafe extern "C" fn dtor(ptr: *mut u64) { - assert!(CANNARY != 0 as *mut _); // make sure we do not get run too often + assert!(CANNARY != ptr::null_mut()); // make sure we do not get run too often let val = *ptr; let which_key = @@ -48,7 +49,7 @@ unsafe extern "C" fn dtor(ptr: *mut u64) { // The correct sequence is: First key 0, then key 1, then key 0. if RECORD == 0_1_0 { drop(Box::from_raw(CANNARY)); - CANNARY = 0 as *mut _; + CANNARY = ptr::null_mut(); } } diff --git a/tests/pass/extern_types.stderr b/tests/pass/extern_types.stderr new file mode 100644 index 0000000000000..730a430425356 --- /dev/null +++ b/tests/pass/extern_types.stderr @@ -0,0 +1,15 @@ +warning: pointer-to-integer cast + --> $DIR/extern_types.rs:LL:CC + | +LL | let x: &Foo = unsafe { &*(16 as *const Foo) }; + | ^^^^^^^^^^^^^^^^^^ pointer-to-integer cast + | + = help: this program is using integer-to-pointer casts or (equivalently) `from_exposed_addr`, + = help: which means that Miri might miss pointer bugs in this program + = help: see https://doc.rust-lang.org/nightly/std/ptr/fn.from_exposed_addr.html for more details on that operation + = help: to ensure that Miri does not miss bugs in your program, use `with_addr` (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance) instead + = help: you can then pass the `-Zmiri-strict-provenance` flag to Miri, to ensure you are not relying on `from_exposed_addr` semantics + = help: alternatively, the `-Zmiri-permissive-provenance` flag disables this warning + + = note: inside `main` at $DIR/extern_types.rs:LL:CC + diff --git a/tests/pass/intptrcast.rs b/tests/pass/intptrcast.rs index aafa90204fc2a..a5e1d196529ef 100644 --- a/tests/pass/intptrcast.rs +++ b/tests/pass/intptrcast.rs @@ -1,3 +1,5 @@ +// compile-flags: -Zmiri-permissive-provenance + // This strips provenance fn transmute_ptr_to_int(x: *const T) -> usize { unsafe { std::mem::transmute(x) } diff --git a/tests/pass/intrinsics.rs b/tests/pass/intrinsics.rs index 9e310082f3590..0042872a3b45b 100644 --- a/tests/pass/intrinsics.rs +++ b/tests/pass/intrinsics.rs @@ -1,3 +1,4 @@ +// compile-flags: -Zmiri-permissive-provenance #![feature(core_intrinsics, const_raw_ptr_comparison)] #![feature(layout_for_ptr)] diff --git a/tests/pass/linux-getrandom-without-isolation.rs b/tests/pass/linux-getrandom-without-isolation.rs index ad1a1f27c7713..56a53699477e8 100644 --- a/tests/pass/linux-getrandom-without-isolation.rs +++ b/tests/pass/linux-getrandom-without-isolation.rs @@ -3,13 +3,15 @@ #![feature(rustc_private)] extern crate libc; +use std::ptr; + fn main() { let mut buf = [0u8; 5]; unsafe { assert_eq!( libc::syscall( libc::SYS_getrandom, - 0 as *mut libc::c_void, + ptr::null_mut::(), 0 as libc::size_t, 0 as libc::c_uint, ), @@ -26,7 +28,7 @@ fn main() { ); assert_eq!( - libc::getrandom(0 as *mut libc::c_void, 0 as libc::size_t, 0 as libc::c_uint), + libc::getrandom(ptr::null_mut::(), 0 as libc::size_t, 0 as libc::c_uint), 0, ); assert_eq!( diff --git a/tests/pass/linux-getrandom.rs b/tests/pass/linux-getrandom.rs index 7d3f899f4408a..a3596e4c7a9c0 100644 --- a/tests/pass/linux-getrandom.rs +++ b/tests/pass/linux-getrandom.rs @@ -2,13 +2,15 @@ #![feature(rustc_private)] extern crate libc; +use std::ptr; + fn main() { let mut buf = [0u8; 5]; unsafe { assert_eq!( libc::syscall( libc::SYS_getrandom, - 0 as *mut libc::c_void, + ptr::null_mut::(), 0 as libc::size_t, 0 as libc::c_uint, ), @@ -25,7 +27,7 @@ fn main() { ); assert_eq!( - libc::getrandom(0 as *mut libc::c_void, 0 as libc::size_t, 0 as libc::c_uint), + libc::getrandom(ptr::null_mut::(), 0 as libc::size_t, 0 as libc::c_uint), 0, ); assert_eq!( diff --git a/tests/pass/panic/catch_panic.rs b/tests/pass/panic/catch_panic.rs index 2fb00391cd795..3979fb3b07146 100644 --- a/tests/pass/panic/catch_panic.rs +++ b/tests/pass/panic/catch_panic.rs @@ -1,5 +1,5 @@ // We test the `align_offset` panic below, make sure we test the interpreter impl and not the "real" one. -// compile-flags: -Zmiri-symbolic-alignment-check +// compile-flags: -Zmiri-symbolic-alignment-check -Zmiri-permissive-provenance #![feature(never_type)] #![allow(unconditional_panic, non_fmt_panics)] diff --git a/tests/pass/ptr_int_casts.rs b/tests/pass/ptr_int_casts.rs index 889b6bd04f9d5..ffe6a114c66b3 100644 --- a/tests/pass/ptr_int_casts.rs +++ b/tests/pass/ptr_int_casts.rs @@ -1,3 +1,4 @@ +// compile-flags: -Zmiri-permissive-provenance use std::mem; use std::ptr; diff --git a/tests/pass/ptr_offset.rs b/tests/pass/ptr_offset.rs index 1b25df721452f..b16a06a7260b3 100644 --- a/tests/pass/ptr_offset.rs +++ b/tests/pass/ptr_offset.rs @@ -1,3 +1,4 @@ +// compile-flags: -Zmiri-permissive-provenance use std::{mem, ptr}; fn main() { diff --git a/tests/pass/stacked-borrows/2phase.rs b/tests/pass/stacked-borrows/2phase.rs index 345cb64ccf713..eb543d691e10b 100644 --- a/tests/pass/stacked-borrows/2phase.rs +++ b/tests/pass/stacked-borrows/2phase.rs @@ -1,5 +1,3 @@ -// compile-flags: -Zmiri-tag-raw-pointers - trait S: Sized { fn tpb(&mut self, _s: Self) {} } diff --git a/tests/pass/stacked-borrows/interior_mutability.rs b/tests/pass/stacked-borrows/interior_mutability.rs index 9ee8af45aefe9..79958ab5539d4 100644 --- a/tests/pass/stacked-borrows/interior_mutability.rs +++ b/tests/pass/stacked-borrows/interior_mutability.rs @@ -1,4 +1,3 @@ -// compile-flags: -Zmiri-tag-raw-pointers use std::cell::{Cell, RefCell, UnsafeCell}; use std::mem::{self, MaybeUninit}; diff --git a/tests/pass/stacked-borrows/stacked-borrows.rs b/tests/pass/stacked-borrows/stacked-borrows.rs index 131783ef4fb58..eb0ff167eb123 100644 --- a/tests/pass/stacked-borrows/stacked-borrows.rs +++ b/tests/pass/stacked-borrows/stacked-borrows.rs @@ -1,4 +1,3 @@ -// compile-flags: -Zmiri-tag-raw-pointers use std::ptr; // Test various stacked-borrows-related things. diff --git a/tests/pass/zst.rs b/tests/pass/zst.rs index 3a853e7d8a68f..fade1e0dad88f 100644 --- a/tests/pass/zst.rs +++ b/tests/pass/zst.rs @@ -1,3 +1,4 @@ +// compile-flags: -Zmiri-permissive-provenance #[derive(PartialEq, Debug)] struct A; From 294ef15adbf6b4778a8eb638b31a48744914ec0a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 26 Jun 2022 21:26:14 -0400 Subject: [PATCH 3336/3747] more int2ptr cast tests, and fix casting of addresses inside dead allocations --- src/intptrcast.rs | 12 +++++++-- tests/fail/backtrace/bad-backtrace-flags.rs | 2 +- .../fail/backtrace/bad-backtrace-flags.stderr | 21 +++------------ tests/fail/backtrace/bad-backtrace-ptr.rs | 2 +- tests/fail/backtrace/bad-backtrace-ptr.stderr | 21 +++------------ .../backtrace/bad-backtrace-resolve-flags.rs | 2 +- .../bad-backtrace-resolve-flags.stderr | 17 +----------- .../bad-backtrace-resolve-names-flags.rs | 4 +-- .../bad-backtrace-resolve-names-flags.stderr | 21 +++------------ .../thread_local_static_dealloc.rs | 7 +++-- .../thread_local_static_dealloc.stderr | 21 +++------------ .../dangling_pointers/deref-invalid-ptr.rs | 2 +- .../deref-invalid-ptr.stderr | 17 +----------- .../storage_dead_dangling.rs | 6 ++--- .../storage_dead_dangling.stderr | 26 +++--------------- .../dangling_pointers/wild_pointer_deref.rs | 2 ++ .../wild_pointer_deref.stderr | 17 +----------- tests/fail/intrinsics/ptr_offset_0_plus_0.rs | 1 + .../intrinsics/ptr_offset_0_plus_0.stderr | 17 +----------- .../intrinsics/ptr_offset_int_plus_int.rs | 1 + .../intrinsics/ptr_offset_int_plus_int.stderr | 17 +----------- .../intrinsics/ptr_offset_int_plus_ptr.rs | 1 + .../intrinsics/ptr_offset_int_plus_ptr.stderr | 17 +----------- .../permissive_provenance_transmute.stderr | 20 -------------- ...e_transmute.rs => provenance_transmute.rs} | 0 ...ute.stderr => provenance_transmute.stderr} | 8 +++--- .../fail/provenance/strict_provenance_cast.rs | 6 +++++ .../provenance/strict_provenance_cast.stderr | 14 ++++++++++ .../provenance/strict_provenance_transmute.rs | 27 ------------------- tests/fail/stacked_borrows/unescaped_local.rs | 2 ++ .../stacked_borrows/unescaped_local.stderr | 17 +----------- .../intptrcast_alignment_check.rs | 2 +- .../intptrcast_alignment_check.stderr | 17 +----------- tests/fail/validity/cast_fn_ptr1.rs | 2 ++ tests/fail/validity/cast_fn_ptr1.stderr | 17 +----------- tests/fail/validity/cast_fn_ptr2.rs | 2 ++ tests/fail/validity/cast_fn_ptr2.stderr | 22 +-------------- tests/pass/adjacent-allocs.rs | 27 +++++++++++++++++-- tests/pass/align.rs | 2 ++ tests/pass/align.stderr | 20 -------------- tests/pass/intptrcast.rs | 11 ++++++++ 41 files changed, 123 insertions(+), 347 deletions(-) delete mode 100644 tests/fail/provenance/permissive_provenance_transmute.stderr rename tests/fail/provenance/{permissive_provenance_transmute.rs => provenance_transmute.rs} (100%) rename tests/fail/provenance/{strict_provenance_transmute.stderr => provenance_transmute.stderr} (75%) create mode 100644 tests/fail/provenance/strict_provenance_cast.rs create mode 100644 tests/fail/provenance/strict_provenance_cast.stderr delete mode 100644 tests/fail/provenance/strict_provenance_transmute.rs delete mode 100644 tests/pass/align.stderr diff --git a/src/intptrcast.rs b/src/intptrcast.rs index c92954a218ca2..cb0d6517b9426 100644 --- a/src/intptrcast.rs +++ b/src/intptrcast.rs @@ -90,8 +90,16 @@ impl<'mir, 'tcx> GlobalStateInner { } }?; - // We only use this provenance if it has been exposed. - if global_state.exposed.contains(&alloc_id) { Some(alloc_id) } else { None } + // We only use this provenance if it has been exposed, *and* is still live. + if global_state.exposed.contains(&alloc_id) { + // FIXME: this catches `InterpError`, which we should not usually do. + // We might need a proper fallible API from `memory.rs` to avoid this though. + if let Ok(_) = ecx.get_alloc_size_and_align(alloc_id, AllocCheck::Live) { + return Some(alloc_id); + } + } + + None } pub fn expose_ptr(ecx: &mut MiriEvalContext<'mir, 'tcx>, alloc_id: AllocId, sb: SbTag) { diff --git a/tests/fail/backtrace/bad-backtrace-flags.rs b/tests/fail/backtrace/bad-backtrace-flags.rs index 5f30513e931ef..9e24d32a33310 100644 --- a/tests/fail/backtrace/bad-backtrace-flags.rs +++ b/tests/fail/backtrace/bad-backtrace-flags.rs @@ -4,6 +4,6 @@ extern "Rust" { fn main() { unsafe { - miri_get_backtrace(2, 0 as *mut _); //~ ERROR unsupported operation: unknown `miri_get_backtrace` flags 2 + miri_get_backtrace(2, std::ptr::null_mut()); //~ ERROR unsupported operation: unknown `miri_get_backtrace` flags 2 } } diff --git a/tests/fail/backtrace/bad-backtrace-flags.stderr b/tests/fail/backtrace/bad-backtrace-flags.stderr index ba16335fce3a7..6d62ffc00e51c 100644 --- a/tests/fail/backtrace/bad-backtrace-flags.stderr +++ b/tests/fail/backtrace/bad-backtrace-flags.stderr @@ -1,23 +1,8 @@ -warning: pointer-to-integer cast - --> $DIR/bad-backtrace-flags.rs:LL:CC - | -LL | miri_get_backtrace(2, 0 as *mut _); - | ^^^^^^^^^^^ pointer-to-integer cast - | - = help: this program is using integer-to-pointer casts or (equivalently) `from_exposed_addr`, - = help: which means that Miri might miss pointer bugs in this program - = help: see https://doc.rust-lang.org/nightly/std/ptr/fn.from_exposed_addr.html for more details on that operation - = help: to ensure that Miri does not miss bugs in your program, use `with_addr` (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance) instead - = help: you can then pass the `-Zmiri-strict-provenance` flag to Miri, to ensure you are not relying on `from_exposed_addr` semantics - = help: alternatively, the `-Zmiri-permissive-provenance` flag disables this warning - - = note: inside `main` at $DIR/bad-backtrace-flags.rs:LL:CC - error: unsupported operation: unknown `miri_get_backtrace` flags 2 --> $DIR/bad-backtrace-flags.rs:LL:CC | -LL | miri_get_backtrace(2, 0 as *mut _); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unknown `miri_get_backtrace` flags 2 +LL | miri_get_backtrace(2, std::ptr::null_mut()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unknown `miri_get_backtrace` flags 2 | = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support @@ -25,5 +10,5 @@ LL | miri_get_backtrace(2, 0 as *mut _); note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace -error: aborting due to previous error; 1 warning emitted +error: aborting due to previous error diff --git a/tests/fail/backtrace/bad-backtrace-ptr.rs b/tests/fail/backtrace/bad-backtrace-ptr.rs index c83bf1eb382e8..73d3561445d57 100644 --- a/tests/fail/backtrace/bad-backtrace-ptr.rs +++ b/tests/fail/backtrace/bad-backtrace-ptr.rs @@ -4,6 +4,6 @@ extern "Rust" { fn main() { unsafe { - miri_resolve_frame(0 as *mut _, 0); //~ ERROR null pointer is not a valid pointer for this operation + miri_resolve_frame(std::ptr::null_mut(), 0); //~ ERROR null pointer is not a valid pointer for this operation } } diff --git a/tests/fail/backtrace/bad-backtrace-ptr.stderr b/tests/fail/backtrace/bad-backtrace-ptr.stderr index 75268b6671421..6911db9de02fd 100644 --- a/tests/fail/backtrace/bad-backtrace-ptr.stderr +++ b/tests/fail/backtrace/bad-backtrace-ptr.stderr @@ -1,23 +1,8 @@ -warning: pointer-to-integer cast - --> $DIR/bad-backtrace-ptr.rs:LL:CC - | -LL | miri_resolve_frame(0 as *mut _, 0); - | ^^^^^^^^^^^ pointer-to-integer cast - | - = help: this program is using integer-to-pointer casts or (equivalently) `from_exposed_addr`, - = help: which means that Miri might miss pointer bugs in this program - = help: see https://doc.rust-lang.org/nightly/std/ptr/fn.from_exposed_addr.html for more details on that operation - = help: to ensure that Miri does not miss bugs in your program, use `with_addr` (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance) instead - = help: you can then pass the `-Zmiri-strict-provenance` flag to Miri, to ensure you are not relying on `from_exposed_addr` semantics - = help: alternatively, the `-Zmiri-permissive-provenance` flag disables this warning - - = note: inside `main` at $DIR/bad-backtrace-ptr.rs:LL:CC - error: Undefined Behavior: null pointer is not a valid pointer for this operation --> $DIR/bad-backtrace-ptr.rs:LL:CC | -LL | miri_resolve_frame(0 as *mut _, 0); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ null pointer is not a valid pointer for this operation +LL | miri_resolve_frame(std::ptr::null_mut(), 0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ null pointer is not a valid pointer for this operation | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information @@ -26,5 +11,5 @@ LL | miri_resolve_frame(0 as *mut _, 0); note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace -error: aborting due to previous error; 1 warning emitted +error: aborting due to previous error diff --git a/tests/fail/backtrace/bad-backtrace-resolve-flags.rs b/tests/fail/backtrace/bad-backtrace-resolve-flags.rs index 5a30253a893b8..2d4d6195029d1 100644 --- a/tests/fail/backtrace/bad-backtrace-resolve-flags.rs +++ b/tests/fail/backtrace/bad-backtrace-resolve-flags.rs @@ -15,7 +15,7 @@ extern "Rust" { fn main() { unsafe { - let mut buf = vec![0 as *mut _; miri_backtrace_size(0)]; + let mut buf = vec![std::ptr::null_mut(); miri_backtrace_size(0)]; miri_get_backtrace(1, buf.as_mut_ptr()); diff --git a/tests/fail/backtrace/bad-backtrace-resolve-flags.stderr b/tests/fail/backtrace/bad-backtrace-resolve-flags.stderr index fad9ffe119209..49495651dfec4 100644 --- a/tests/fail/backtrace/bad-backtrace-resolve-flags.stderr +++ b/tests/fail/backtrace/bad-backtrace-resolve-flags.stderr @@ -1,18 +1,3 @@ -warning: pointer-to-integer cast - --> $DIR/bad-backtrace-resolve-flags.rs:LL:CC - | -LL | let mut buf = vec![0 as *mut _; miri_backtrace_size(0)]; - | ^^^^^^^^^^^ pointer-to-integer cast - | - = help: this program is using integer-to-pointer casts or (equivalently) `from_exposed_addr`, - = help: which means that Miri might miss pointer bugs in this program - = help: see https://doc.rust-lang.org/nightly/std/ptr/fn.from_exposed_addr.html for more details on that operation - = help: to ensure that Miri does not miss bugs in your program, use `with_addr` (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance) instead - = help: you can then pass the `-Zmiri-strict-provenance` flag to Miri, to ensure you are not relying on `from_exposed_addr` semantics - = help: alternatively, the `-Zmiri-permissive-provenance` flag disables this warning - - = note: inside `main` at $DIR/bad-backtrace-resolve-flags.rs:LL:CC - error: unsupported operation: unknown `miri_resolve_frame` flags 2 --> $DIR/bad-backtrace-resolve-flags.rs:LL:CC | @@ -25,5 +10,5 @@ LL | miri_resolve_frame(buf[0], 2); note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace -error: aborting due to previous error; 1 warning emitted +error: aborting due to previous error diff --git a/tests/fail/backtrace/bad-backtrace-resolve-names-flags.rs b/tests/fail/backtrace/bad-backtrace-resolve-names-flags.rs index 8e69a275753f1..6cea1fec1b241 100644 --- a/tests/fail/backtrace/bad-backtrace-resolve-names-flags.rs +++ b/tests/fail/backtrace/bad-backtrace-resolve-names-flags.rs @@ -6,11 +6,11 @@ extern "Rust" { fn main() { unsafe { - let mut buf = vec![0 as *mut _; miri_backtrace_size(0)]; + let mut buf = vec![std::ptr::null_mut(); miri_backtrace_size(0)]; miri_get_backtrace(1, buf.as_mut_ptr()); // miri_resolve_frame_names will error from an invalid backtrace before it will from invalid flags - miri_resolve_frame_names(buf[0], 2, 0 as *mut _, 0 as *mut _); //~ ERROR unsupported operation: unknown `miri_resolve_frame_names` flags 2 + miri_resolve_frame_names(buf[0], 2, std::ptr::null_mut(), std::ptr::null_mut()); //~ ERROR unsupported operation: unknown `miri_resolve_frame_names` flags 2 } } diff --git a/tests/fail/backtrace/bad-backtrace-resolve-names-flags.stderr b/tests/fail/backtrace/bad-backtrace-resolve-names-flags.stderr index 18b03df21c6f6..aa470cb9de054 100644 --- a/tests/fail/backtrace/bad-backtrace-resolve-names-flags.stderr +++ b/tests/fail/backtrace/bad-backtrace-resolve-names-flags.stderr @@ -1,23 +1,8 @@ -warning: pointer-to-integer cast - --> $DIR/bad-backtrace-resolve-names-flags.rs:LL:CC - | -LL | let mut buf = vec![0 as *mut _; miri_backtrace_size(0)]; - | ^^^^^^^^^^^ pointer-to-integer cast - | - = help: this program is using integer-to-pointer casts or (equivalently) `from_exposed_addr`, - = help: which means that Miri might miss pointer bugs in this program - = help: see https://doc.rust-lang.org/nightly/std/ptr/fn.from_exposed_addr.html for more details on that operation - = help: to ensure that Miri does not miss bugs in your program, use `with_addr` (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance) instead - = help: you can then pass the `-Zmiri-strict-provenance` flag to Miri, to ensure you are not relying on `from_exposed_addr` semantics - = help: alternatively, the `-Zmiri-permissive-provenance` flag disables this warning - - = note: inside `main` at $DIR/bad-backtrace-resolve-names-flags.rs:LL:CC - error: unsupported operation: unknown `miri_resolve_frame_names` flags 2 --> $DIR/bad-backtrace-resolve-names-flags.rs:LL:CC | -LL | ... miri_resolve_frame_names(buf[0], 2, 0 as *mut _, 0 as *mut _); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unknown `miri_resolve_frame_names` flags 2 +LL | ... miri_resolve_frame_names(buf[0], 2, std::ptr::null_mut(), std::ptr::null_mut()); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unknown `miri_resolve_frame_names` flags 2 | = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support @@ -25,5 +10,5 @@ LL | ... miri_resolve_frame_names(buf[0], 2, 0 as *mut _, 0 as *mut _); note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace -error: aborting due to previous error; 1 warning emitted +error: aborting due to previous error diff --git a/tests/fail/concurrency/thread_local_static_dealloc.rs b/tests/fail/concurrency/thread_local_static_dealloc.rs index d5a4bf27f8973..e6031b5e4c0c5 100644 --- a/tests/fail/concurrency/thread_local_static_dealloc.rs +++ b/tests/fail/concurrency/thread_local_static_dealloc.rs @@ -7,9 +7,12 @@ #[thread_local] static mut TLS: u8 = 0; +struct SendRaw(*const u8); +unsafe impl Send for SendRaw {} + fn main() { unsafe { - let dangling_ptr = std::thread::spawn(|| &TLS as *const u8 as usize).join().unwrap(); - let _val = *(dangling_ptr as *const u8); //~ ERROR dereferenced after this allocation got freed + let dangling_ptr = std::thread::spawn(|| SendRaw(&TLS as *const u8)).join().unwrap(); + let _val = *dangling_ptr.0; //~ ERROR dereferenced after this allocation got freed } } diff --git a/tests/fail/concurrency/thread_local_static_dealloc.stderr b/tests/fail/concurrency/thread_local_static_dealloc.stderr index 31a64eec36858..d54c569de36e6 100644 --- a/tests/fail/concurrency/thread_local_static_dealloc.stderr +++ b/tests/fail/concurrency/thread_local_static_dealloc.stderr @@ -1,23 +1,8 @@ -warning: pointer-to-integer cast - --> $DIR/thread_local_static_dealloc.rs:LL:CC - | -LL | let _val = *(dangling_ptr as *const u8); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ pointer-to-integer cast - | - = help: this program is using integer-to-pointer casts or (equivalently) `from_exposed_addr`, - = help: which means that Miri might miss pointer bugs in this program - = help: see https://doc.rust-lang.org/nightly/std/ptr/fn.from_exposed_addr.html for more details on that operation - = help: to ensure that Miri does not miss bugs in your program, use `with_addr` (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance) instead - = help: you can then pass the `-Zmiri-strict-provenance` flag to Miri, to ensure you are not relying on `from_exposed_addr` semantics - = help: alternatively, the `-Zmiri-permissive-provenance` flag disables this warning - - = note: inside `main` at $DIR/thread_local_static_dealloc.rs:LL:CC - error: Undefined Behavior: pointer to ALLOC was dereferenced after this allocation got freed --> $DIR/thread_local_static_dealloc.rs:LL:CC | -LL | let _val = *(dangling_ptr as *const u8); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pointer to ALLOC was dereferenced after this allocation got freed +LL | let _val = *dangling_ptr.0; + | ^^^^^^^^^^^^^^^ pointer to ALLOC was dereferenced after this allocation got freed | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information @@ -26,5 +11,5 @@ LL | let _val = *(dangling_ptr as *const u8); note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace -error: aborting due to previous error; 1 warning emitted +error: aborting due to previous error diff --git a/tests/fail/dangling_pointers/deref-invalid-ptr.rs b/tests/fail/dangling_pointers/deref-invalid-ptr.rs index 56830e97caa37..cb2bbec8bcf01 100644 --- a/tests/fail/dangling_pointers/deref-invalid-ptr.rs +++ b/tests/fail/dangling_pointers/deref-invalid-ptr.rs @@ -1,5 +1,5 @@ // This should fail even without validation. -// compile-flags: -Zmiri-disable-validation +// compile-flags: -Zmiri-disable-validation -Zmiri-permissive-provenance fn main() { let x = 16usize as *const u32; diff --git a/tests/fail/dangling_pointers/deref-invalid-ptr.stderr b/tests/fail/dangling_pointers/deref-invalid-ptr.stderr index ffd7fb1980dc4..f4361d9fefa95 100644 --- a/tests/fail/dangling_pointers/deref-invalid-ptr.stderr +++ b/tests/fail/dangling_pointers/deref-invalid-ptr.stderr @@ -1,18 +1,3 @@ -warning: pointer-to-integer cast - --> $DIR/deref-invalid-ptr.rs:LL:CC - | -LL | let x = 16usize as *const u32; - | ^^^^^^^^^^^^^^^^^^^^^ pointer-to-integer cast - | - = help: this program is using integer-to-pointer casts or (equivalently) `from_exposed_addr`, - = help: which means that Miri might miss pointer bugs in this program - = help: see https://doc.rust-lang.org/nightly/std/ptr/fn.from_exposed_addr.html for more details on that operation - = help: to ensure that Miri does not miss bugs in your program, use `with_addr` (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance) instead - = help: you can then pass the `-Zmiri-strict-provenance` flag to Miri, to ensure you are not relying on `from_exposed_addr` semantics - = help: alternatively, the `-Zmiri-permissive-provenance` flag disables this warning - - = note: inside `main` at $DIR/deref-invalid-ptr.rs:LL:CC - error: Undefined Behavior: dereferencing pointer failed: 0x10 is not a valid pointer --> $DIR/deref-invalid-ptr.rs:LL:CC | @@ -26,5 +11,5 @@ LL | let _y = unsafe { &*x as *const u32 }; note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace -error: aborting due to previous error; 1 warning emitted +error: aborting due to previous error diff --git a/tests/fail/dangling_pointers/storage_dead_dangling.rs b/tests/fail/dangling_pointers/storage_dead_dangling.rs index c87db4b0225a2..370162142de97 100644 --- a/tests/fail/dangling_pointers/storage_dead_dangling.rs +++ b/tests/fail/dangling_pointers/storage_dead_dangling.rs @@ -1,5 +1,5 @@ // This should fail even without validation, but some MIR opts mask the error -// compile-flags: -Zmiri-disable-validation -Zmir-opt-level=0 +// compile-flags: -Zmiri-disable-validation -Zmir-opt-level=0 -Zmiri-permissive-provenance static mut LEAK: usize = 0; @@ -10,7 +10,7 @@ fn fill(v: &mut i32) { } fn evil() { - unsafe { &mut *(LEAK as *mut i32) }; //~ ERROR dereferenced after this allocation got freed + unsafe { &mut *(LEAK as *mut i32) }; //~ ERROR is not a valid pointer } fn main() { @@ -21,6 +21,6 @@ fn main() { _y = x; } // Now we use a pointer to `x` which is no longer in scope, and thus dead (even though the - // `main` stack frame still exists). + // `main` stack frame still exists). We even try going through a `usize` for extra sneakiness! evil(); } diff --git a/tests/fail/dangling_pointers/storage_dead_dangling.stderr b/tests/fail/dangling_pointers/storage_dead_dangling.stderr index 3a94a7fa58ee9..d6030643bfaa1 100644 --- a/tests/fail/dangling_pointers/storage_dead_dangling.stderr +++ b/tests/fail/dangling_pointers/storage_dead_dangling.stderr @@ -1,28 +1,8 @@ -warning: pointer-to-integer cast +error: Undefined Behavior: dereferencing pointer failed: $HEX is not a valid pointer --> $DIR/storage_dead_dangling.rs:LL:CC | LL | unsafe { &mut *(LEAK as *mut i32) }; - | ^^^^^^^^^^^^^^^^^^ pointer-to-integer cast - | - = help: this program is using integer-to-pointer casts or (equivalently) `from_exposed_addr`, - = help: which means that Miri might miss pointer bugs in this program - = help: see https://doc.rust-lang.org/nightly/std/ptr/fn.from_exposed_addr.html for more details on that operation - = help: to ensure that Miri does not miss bugs in your program, use `with_addr` (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance) instead - = help: you can then pass the `-Zmiri-strict-provenance` flag to Miri, to ensure you are not relying on `from_exposed_addr` semantics - = help: alternatively, the `-Zmiri-permissive-provenance` flag disables this warning - - = note: inside `evil` at $DIR/storage_dead_dangling.rs:LL:CC -note: inside `main` at $DIR/storage_dead_dangling.rs:LL:CC - --> $DIR/storage_dead_dangling.rs:LL:CC - | -LL | evil(); - | ^^^^^^ - -error: Undefined Behavior: pointer to ALLOC was dereferenced after this allocation got freed - --> $DIR/storage_dead_dangling.rs:LL:CC - | -LL | unsafe { &mut *(LEAK as *mut i32) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^ pointer to ALLOC was dereferenced after this allocation got freed + | ^^^^^^^^^^^^^^^^^^^^^^^^ dereferencing pointer failed: $HEX is not a valid pointer | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information @@ -36,5 +16,5 @@ LL | evil(); note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace -error: aborting due to previous error; 1 warning emitted +error: aborting due to previous error diff --git a/tests/fail/dangling_pointers/wild_pointer_deref.rs b/tests/fail/dangling_pointers/wild_pointer_deref.rs index eebaea48ba67d..7c9f5281fbbbe 100644 --- a/tests/fail/dangling_pointers/wild_pointer_deref.rs +++ b/tests/fail/dangling_pointers/wild_pointer_deref.rs @@ -1,3 +1,5 @@ +// compile-flags: -Zmiri-permissive-provenance + fn main() { let p = 44 as *const i32; let x = unsafe { *p }; //~ ERROR is not a valid pointer diff --git a/tests/fail/dangling_pointers/wild_pointer_deref.stderr b/tests/fail/dangling_pointers/wild_pointer_deref.stderr index 960f9c9ce3e9c..b20f310da083b 100644 --- a/tests/fail/dangling_pointers/wild_pointer_deref.stderr +++ b/tests/fail/dangling_pointers/wild_pointer_deref.stderr @@ -1,18 +1,3 @@ -warning: pointer-to-integer cast - --> $DIR/wild_pointer_deref.rs:LL:CC - | -LL | let p = 44 as *const i32; - | ^^^^^^^^^^^^^^^^ pointer-to-integer cast - | - = help: this program is using integer-to-pointer casts or (equivalently) `from_exposed_addr`, - = help: which means that Miri might miss pointer bugs in this program - = help: see https://doc.rust-lang.org/nightly/std/ptr/fn.from_exposed_addr.html for more details on that operation - = help: to ensure that Miri does not miss bugs in your program, use `with_addr` (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance) instead - = help: you can then pass the `-Zmiri-strict-provenance` flag to Miri, to ensure you are not relying on `from_exposed_addr` semantics - = help: alternatively, the `-Zmiri-permissive-provenance` flag disables this warning - - = note: inside `main` at $DIR/wild_pointer_deref.rs:LL:CC - error: Undefined Behavior: dereferencing pointer failed: 0x2c is not a valid pointer --> $DIR/wild_pointer_deref.rs:LL:CC | @@ -26,5 +11,5 @@ LL | let x = unsafe { *p }; note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace -error: aborting due to previous error; 1 warning emitted +error: aborting due to previous error diff --git a/tests/fail/intrinsics/ptr_offset_0_plus_0.rs b/tests/fail/intrinsics/ptr_offset_0_plus_0.rs index 248d85d65e24b..ca38f39d25157 100644 --- a/tests/fail/intrinsics/ptr_offset_0_plus_0.rs +++ b/tests/fail/intrinsics/ptr_offset_0_plus_0.rs @@ -1,4 +1,5 @@ // error-pattern: pointer arithmetic failed: null pointer is not a valid pointer +// compile-flags: -Zmiri-permissive-provenance fn main() { let x = 0 as *mut i32; diff --git a/tests/fail/intrinsics/ptr_offset_0_plus_0.stderr b/tests/fail/intrinsics/ptr_offset_0_plus_0.stderr index 2474820545d24..741314ea8a680 100644 --- a/tests/fail/intrinsics/ptr_offset_0_plus_0.stderr +++ b/tests/fail/intrinsics/ptr_offset_0_plus_0.stderr @@ -1,18 +1,3 @@ -warning: pointer-to-integer cast - --> $DIR/ptr_offset_0_plus_0.rs:LL:CC - | -LL | let x = 0 as *mut i32; - | ^^^^^^^^^^^^^ pointer-to-integer cast - | - = help: this program is using integer-to-pointer casts or (equivalently) `from_exposed_addr`, - = help: which means that Miri might miss pointer bugs in this program - = help: see https://doc.rust-lang.org/nightly/std/ptr/fn.from_exposed_addr.html for more details on that operation - = help: to ensure that Miri does not miss bugs in your program, use `with_addr` (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance) instead - = help: you can then pass the `-Zmiri-strict-provenance` flag to Miri, to ensure you are not relying on `from_exposed_addr` semantics - = help: alternatively, the `-Zmiri-permissive-provenance` flag disables this warning - - = note: inside `main` at $DIR/ptr_offset_0_plus_0.rs:LL:CC - error: Undefined Behavior: pointer arithmetic failed: null pointer is not a valid pointer --> RUSTLIB/core/src/ptr/mut_ptr.rs:LL:CC | @@ -31,5 +16,5 @@ LL | let _x = unsafe { x.offset(0) }; // UB despite offset 0, NULL is never note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace -error: aborting due to previous error; 1 warning emitted +error: aborting due to previous error diff --git a/tests/fail/intrinsics/ptr_offset_int_plus_int.rs b/tests/fail/intrinsics/ptr_offset_int_plus_int.rs index e332a9dc624a0..809938d999731 100644 --- a/tests/fail/intrinsics/ptr_offset_int_plus_int.rs +++ b/tests/fail/intrinsics/ptr_offset_int_plus_int.rs @@ -1,4 +1,5 @@ // error-pattern: is not a valid pointer +// compile-flags: -Zmiri-permissive-provenance fn main() { // Can't offset an integer pointer by non-zero offset. diff --git a/tests/fail/intrinsics/ptr_offset_int_plus_int.stderr b/tests/fail/intrinsics/ptr_offset_int_plus_int.stderr index f5cbd4bbbf731..e6b8f102f3946 100644 --- a/tests/fail/intrinsics/ptr_offset_int_plus_int.stderr +++ b/tests/fail/intrinsics/ptr_offset_int_plus_int.stderr @@ -1,18 +1,3 @@ -warning: pointer-to-integer cast - --> $DIR/ptr_offset_int_plus_int.rs:LL:CC - | -LL | let _val = (1 as *mut u8).offset(1); - | ^^^^^^^^^^^^^^ pointer-to-integer cast - | - = help: this program is using integer-to-pointer casts or (equivalently) `from_exposed_addr`, - = help: which means that Miri might miss pointer bugs in this program - = help: see https://doc.rust-lang.org/nightly/std/ptr/fn.from_exposed_addr.html for more details on that operation - = help: to ensure that Miri does not miss bugs in your program, use `with_addr` (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance) instead - = help: you can then pass the `-Zmiri-strict-provenance` flag to Miri, to ensure you are not relying on `from_exposed_addr` semantics - = help: alternatively, the `-Zmiri-permissive-provenance` flag disables this warning - - = note: inside `main` at $DIR/ptr_offset_int_plus_int.rs:LL:CC - error: Undefined Behavior: pointer arithmetic failed: 0x1 is not a valid pointer --> RUSTLIB/core/src/ptr/mut_ptr.rs:LL:CC | @@ -31,5 +16,5 @@ LL | let _val = (1 as *mut u8).offset(1); note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace -error: aborting due to previous error; 1 warning emitted +error: aborting due to previous error diff --git a/tests/fail/intrinsics/ptr_offset_int_plus_ptr.rs b/tests/fail/intrinsics/ptr_offset_int_plus_ptr.rs index 2d27e25a7af1f..903f89ff70ec4 100644 --- a/tests/fail/intrinsics/ptr_offset_int_plus_ptr.rs +++ b/tests/fail/intrinsics/ptr_offset_int_plus_ptr.rs @@ -1,4 +1,5 @@ // error-pattern: is not a valid pointer +// compile-flags: -Zmiri-permissive-provenance fn main() { let ptr = Box::into_raw(Box::new(0u32)); diff --git a/tests/fail/intrinsics/ptr_offset_int_plus_ptr.stderr b/tests/fail/intrinsics/ptr_offset_int_plus_ptr.stderr index 577a377f076e7..f88ad758d438d 100644 --- a/tests/fail/intrinsics/ptr_offset_int_plus_ptr.stderr +++ b/tests/fail/intrinsics/ptr_offset_int_plus_ptr.stderr @@ -1,18 +1,3 @@ -warning: pointer-to-integer cast - --> $DIR/ptr_offset_int_plus_ptr.rs:LL:CC - | -LL | let _val = (1 as *mut u8).offset(ptr as isize); - | ^^^^^^^^^^^^^^ pointer-to-integer cast - | - = help: this program is using integer-to-pointer casts or (equivalently) `from_exposed_addr`, - = help: which means that Miri might miss pointer bugs in this program - = help: see https://doc.rust-lang.org/nightly/std/ptr/fn.from_exposed_addr.html for more details on that operation - = help: to ensure that Miri does not miss bugs in your program, use `with_addr` (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance) instead - = help: you can then pass the `-Zmiri-strict-provenance` flag to Miri, to ensure you are not relying on `from_exposed_addr` semantics - = help: alternatively, the `-Zmiri-permissive-provenance` flag disables this warning - - = note: inside `main` at $DIR/ptr_offset_int_plus_ptr.rs:LL:CC - error: Undefined Behavior: pointer arithmetic failed: 0x1 is not a valid pointer --> RUSTLIB/core/src/ptr/mut_ptr.rs:LL:CC | @@ -31,5 +16,5 @@ LL | let _val = (1 as *mut u8).offset(ptr as isize); note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace -error: aborting due to previous error; 1 warning emitted +error: aborting due to previous error diff --git a/tests/fail/provenance/permissive_provenance_transmute.stderr b/tests/fail/provenance/permissive_provenance_transmute.stderr deleted file mode 100644 index 12f3562011a81..0000000000000 --- a/tests/fail/provenance/permissive_provenance_transmute.stderr +++ /dev/null @@ -1,20 +0,0 @@ -error: Undefined Behavior: dereferencing pointer failed: $HEX is not a valid pointer - --> $DIR/permissive_provenance_transmute.rs:LL:CC - | -LL | let _val = *left_ptr; - | ^^^^^^^^^ dereferencing pointer failed: $HEX is not a valid pointer - | - = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior - = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - - = note: inside `deref` at $DIR/permissive_provenance_transmute.rs:LL:CC -note: inside `main` at $DIR/permissive_provenance_transmute.rs:LL:CC - --> $DIR/permissive_provenance_transmute.rs:LL:CC - | -LL | deref(ptr1, ptr2.with_addr(ptr1.addr())); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace - -error: aborting due to previous error - diff --git a/tests/fail/provenance/permissive_provenance_transmute.rs b/tests/fail/provenance/provenance_transmute.rs similarity index 100% rename from tests/fail/provenance/permissive_provenance_transmute.rs rename to tests/fail/provenance/provenance_transmute.rs diff --git a/tests/fail/provenance/strict_provenance_transmute.stderr b/tests/fail/provenance/provenance_transmute.stderr similarity index 75% rename from tests/fail/provenance/strict_provenance_transmute.stderr rename to tests/fail/provenance/provenance_transmute.stderr index 8df94d50bbac1..9cbec077e42c0 100644 --- a/tests/fail/provenance/strict_provenance_transmute.stderr +++ b/tests/fail/provenance/provenance_transmute.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: dereferencing pointer failed: $HEX is not a valid pointer - --> $DIR/strict_provenance_transmute.rs:LL:CC + --> $DIR/provenance_transmute.rs:LL:CC | LL | let _val = *left_ptr; | ^^^^^^^^^ dereferencing pointer failed: $HEX is not a valid pointer @@ -7,9 +7,9 @@ LL | let _val = *left_ptr; = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: inside `deref` at $DIR/strict_provenance_transmute.rs:LL:CC -note: inside `main` at $DIR/strict_provenance_transmute.rs:LL:CC - --> $DIR/strict_provenance_transmute.rs:LL:CC + = note: inside `deref` at $DIR/provenance_transmute.rs:LL:CC +note: inside `main` at $DIR/provenance_transmute.rs:LL:CC + --> $DIR/provenance_transmute.rs:LL:CC | LL | deref(ptr1, ptr2.with_addr(ptr1.addr())); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/tests/fail/provenance/strict_provenance_cast.rs b/tests/fail/provenance/strict_provenance_cast.rs new file mode 100644 index 0000000000000..8b2b053bdb591 --- /dev/null +++ b/tests/fail/provenance/strict_provenance_cast.rs @@ -0,0 +1,6 @@ +// compile-flags: -Zmiri-strict-provenance + +fn main() { + let addr = &0 as *const i32 as usize; + let _ptr = addr as *const i32; //~ ERROR integer-to-pointer casts and `from_exposed_addr` are not supported +} diff --git a/tests/fail/provenance/strict_provenance_cast.stderr b/tests/fail/provenance/strict_provenance_cast.stderr new file mode 100644 index 0000000000000..32a39b81d9d7f --- /dev/null +++ b/tests/fail/provenance/strict_provenance_cast.stderr @@ -0,0 +1,14 @@ +error: unsupported operation: integer-to-pointer casts and `from_exposed_addr` are not supported with `-Zmiri-strict-provenance`; use `with_addr` instead + --> $DIR/strict_provenance_cast.rs:LL:CC + | +LL | let _ptr = addr as *const i32; + | ^^^^^^^^^^^^^^^^^^ integer-to-pointer casts and `from_exposed_addr` are not supported with `-Zmiri-strict-provenance`; use `with_addr` instead + | + = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support + + = note: inside `main` at $DIR/strict_provenance_cast.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/fail/provenance/strict_provenance_transmute.rs b/tests/fail/provenance/strict_provenance_transmute.rs deleted file mode 100644 index 12a141e9ddfee..0000000000000 --- a/tests/fail/provenance/strict_provenance_transmute.rs +++ /dev/null @@ -1,27 +0,0 @@ -// compile-flags: -Zmiri-strict-provenance -#![feature(strict_provenance)] - -use std::mem; - -// This is the example from -// . - -unsafe fn deref(left: *const u8, right: *const u8) { - let left_int: usize = mem::transmute(left); - let right_int: usize = mem::transmute(right); - if left_int == right_int { - // The compiler is allowed to replace `left_int` by `right_int` here... - let left_ptr: *const u8 = mem::transmute(left_int); - // ...which however means here it could be dereferencing the wrong pointer. - let _val = *left_ptr; //~ERROR dereferencing pointer failed - } -} - -fn main() { - let ptr1 = &0u8 as *const u8; - let ptr2 = &1u8 as *const u8; - unsafe { - // Two pointers with the same address but different provenance. - deref(ptr1, ptr2.with_addr(ptr1.addr())); - } -} diff --git a/tests/fail/stacked_borrows/unescaped_local.rs b/tests/fail/stacked_borrows/unescaped_local.rs index bfc937bb12b7f..c994f6c3818a9 100644 --- a/tests/fail/stacked_borrows/unescaped_local.rs +++ b/tests/fail/stacked_borrows/unescaped_local.rs @@ -1,3 +1,5 @@ +// compile-flags: -Zmiri-permissive-provenance + // Make sure we cannot use raw ptrs to access a local that // we took the direct address of. fn main() { diff --git a/tests/fail/stacked_borrows/unescaped_local.stderr b/tests/fail/stacked_borrows/unescaped_local.stderr index 2f6605c058b2d..464296651c5e6 100644 --- a/tests/fail/stacked_borrows/unescaped_local.stderr +++ b/tests/fail/stacked_borrows/unescaped_local.stderr @@ -1,18 +1,3 @@ -warning: pointer-to-integer cast - --> $DIR/unescaped_local.rs:LL:CC - | -LL | let raw = &mut x as *mut i32 as usize as *mut i32; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pointer-to-integer cast - | - = help: this program is using integer-to-pointer casts or (equivalently) `from_exposed_addr`, - = help: which means that Miri might miss pointer bugs in this program - = help: see https://doc.rust-lang.org/nightly/std/ptr/fn.from_exposed_addr.html for more details on that operation - = help: to ensure that Miri does not miss bugs in your program, use `with_addr` (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance) instead - = help: you can then pass the `-Zmiri-strict-provenance` flag to Miri, to ensure you are not relying on `from_exposed_addr` semantics - = help: alternatively, the `-Zmiri-permissive-provenance` flag disables this warning - - = note: inside `main` at $DIR/unescaped_local.rs:LL:CC - error: Undefined Behavior: attempting a write access using at ALLOC[0x0], but no exposed tags have suitable permission in the borrow stack for this location --> $DIR/unescaped_local.rs:LL:CC | @@ -29,5 +14,5 @@ LL | *raw = 13; note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace -error: aborting due to previous error; 1 warning emitted +error: aborting due to previous error diff --git a/tests/fail/unaligned_pointers/intptrcast_alignment_check.rs b/tests/fail/unaligned_pointers/intptrcast_alignment_check.rs index 0a326a453e9a4..dea9335ab751a 100644 --- a/tests/fail/unaligned_pointers/intptrcast_alignment_check.rs +++ b/tests/fail/unaligned_pointers/intptrcast_alignment_check.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-symbolic-alignment-check +// compile-flags: -Zmiri-symbolic-alignment-check -Zmiri-permissive-provenance // With the symbolic alignment check, even with intptrcast and without // validation, we want to be *sure* to catch bugs that arise from pointers being // insufficiently aligned. The only way to achieve that is not not let programs diff --git a/tests/fail/unaligned_pointers/intptrcast_alignment_check.stderr b/tests/fail/unaligned_pointers/intptrcast_alignment_check.stderr index bd8d161de8327..347486187e1b9 100644 --- a/tests/fail/unaligned_pointers/intptrcast_alignment_check.stderr +++ b/tests/fail/unaligned_pointers/intptrcast_alignment_check.stderr @@ -1,18 +1,3 @@ -warning: pointer-to-integer cast - --> $DIR/intptrcast_alignment_check.rs:LL:CC - | -LL | let u16_ptr = base_addr_aligned as *mut u16; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pointer-to-integer cast - | - = help: this program is using integer-to-pointer casts or (equivalently) `from_exposed_addr`, - = help: which means that Miri might miss pointer bugs in this program - = help: see https://doc.rust-lang.org/nightly/std/ptr/fn.from_exposed_addr.html for more details on that operation - = help: to ensure that Miri does not miss bugs in your program, use `with_addr` (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance) instead - = help: you can then pass the `-Zmiri-strict-provenance` flag to Miri, to ensure you are not relying on `from_exposed_addr` semantics - = help: alternatively, the `-Zmiri-permissive-provenance` flag disables this warning - - = note: inside `main` at $DIR/intptrcast_alignment_check.rs:LL:CC - error: Undefined Behavior: accessing memory with alignment ALIGN, but alignment ALIGN is required --> $DIR/intptrcast_alignment_check.rs:LL:CC | @@ -26,5 +11,5 @@ LL | unsafe { *u16_ptr = 2 }; note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace -error: aborting due to previous error; 1 warning emitted +error: aborting due to previous error diff --git a/tests/fail/validity/cast_fn_ptr1.rs b/tests/fail/validity/cast_fn_ptr1.rs index 020e7be34f706..eb5774fe79956 100644 --- a/tests/fail/validity/cast_fn_ptr1.rs +++ b/tests/fail/validity/cast_fn_ptr1.rs @@ -1,3 +1,5 @@ +// compile-flags: -Zmiri-permissive-provenance + fn main() { // Cast a function pointer such that on a call, the argument gets transmuted // from raw ptr to reference. This is ABI-compatible, so it's not the call that diff --git a/tests/fail/validity/cast_fn_ptr1.stderr b/tests/fail/validity/cast_fn_ptr1.stderr index d75857900052e..d048377a7793d 100644 --- a/tests/fail/validity/cast_fn_ptr1.stderr +++ b/tests/fail/validity/cast_fn_ptr1.stderr @@ -1,18 +1,3 @@ -warning: pointer-to-integer cast - --> $DIR/cast_fn_ptr1.rs:LL:CC - | -LL | g(0usize as *const i32) - | ^^^^^^^^^^^^^^^^^^^^ pointer-to-integer cast - | - = help: this program is using integer-to-pointer casts or (equivalently) `from_exposed_addr`, - = help: which means that Miri might miss pointer bugs in this program - = help: see https://doc.rust-lang.org/nightly/std/ptr/fn.from_exposed_addr.html for more details on that operation - = help: to ensure that Miri does not miss bugs in your program, use `with_addr` (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance) instead - = help: you can then pass the `-Zmiri-strict-provenance` flag to Miri, to ensure you are not relying on `from_exposed_addr` semantics - = help: alternatively, the `-Zmiri-permissive-provenance` flag disables this warning - - = note: inside `main` at $DIR/cast_fn_ptr1.rs:LL:CC - error: Undefined Behavior: type validation failed: encountered a null reference --> $DIR/cast_fn_ptr1.rs:LL:CC | @@ -26,5 +11,5 @@ LL | g(0usize as *const i32) note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace -error: aborting due to previous error; 1 warning emitted +error: aborting due to previous error diff --git a/tests/fail/validity/cast_fn_ptr2.rs b/tests/fail/validity/cast_fn_ptr2.rs index 10fc39f56fae3..1cf4ca7d19d8e 100644 --- a/tests/fail/validity/cast_fn_ptr2.rs +++ b/tests/fail/validity/cast_fn_ptr2.rs @@ -1,3 +1,5 @@ +// compile-flags: -Zmiri-permissive-provenance + fn main() { // Cast a function pointer such that when returning, the return value gets transmuted // from raw ptr to reference. This is ABI-compatible, so it's not the call that diff --git a/tests/fail/validity/cast_fn_ptr2.stderr b/tests/fail/validity/cast_fn_ptr2.stderr index d47b39356ffcd..10b9b9b8602b6 100644 --- a/tests/fail/validity/cast_fn_ptr2.stderr +++ b/tests/fail/validity/cast_fn_ptr2.stderr @@ -1,23 +1,3 @@ -warning: pointer-to-integer cast - --> $DIR/cast_fn_ptr2.rs:LL:CC - | -LL | 0usize as *const i32 - | ^^^^^^^^^^^^^^^^^^^^ pointer-to-integer cast - | - = help: this program is using integer-to-pointer casts or (equivalently) `from_exposed_addr`, - = help: which means that Miri might miss pointer bugs in this program - = help: see https://doc.rust-lang.org/nightly/std/ptr/fn.from_exposed_addr.html for more details on that operation - = help: to ensure that Miri does not miss bugs in your program, use `with_addr` (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance) instead - = help: you can then pass the `-Zmiri-strict-provenance` flag to Miri, to ensure you are not relying on `from_exposed_addr` semantics - = help: alternatively, the `-Zmiri-permissive-provenance` flag disables this warning - - = note: inside `main::f` at $DIR/cast_fn_ptr2.rs:LL:CC -note: inside `main` at $DIR/cast_fn_ptr2.rs:LL:CC - --> $DIR/cast_fn_ptr2.rs:LL:CC - | -LL | let _x = g(); - | ^^^ - error: Undefined Behavior: type validation failed: encountered a null reference --> $DIR/cast_fn_ptr2.rs:LL:CC | @@ -31,5 +11,5 @@ LL | let _x = g(); note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace -error: aborting due to previous error; 1 warning emitted +error: aborting due to previous error diff --git a/tests/pass/adjacent-allocs.rs b/tests/pass/adjacent-allocs.rs index 925430ae20309..b3483a5b43800 100644 --- a/tests/pass/adjacent-allocs.rs +++ b/tests/pass/adjacent-allocs.rs @@ -1,9 +1,9 @@ // compile-flags: -Zmiri-permissive-provenance -fn main() { +fn test1() { // The slack between allocations is random. // Loop a few times to hit the zero-slack case. - for _ in 0..1024 { + for _ in 0..512 { let n = 0u64; let ptr: *const u64 = &n; @@ -22,3 +22,26 @@ fn main() { unsafe { *zst } } } + +fn test2() { + fn foo() -> u64 { + 0 + } + + for _ in 0..512 { + let n = 0u64; + let ptr: *const u64 = &n; + foo(); + let iptr = ptr as usize; + unsafe { + let start = &*std::ptr::slice_from_raw_parts(iptr as *const (), 1); + let end = &*std::ptr::slice_from_raw_parts((iptr + 8) as *const (), 1); + assert_eq!(start.len(), end.len()); + } + } +} + +fn main() { + test1(); + test2(); +} diff --git a/tests/pass/align.rs b/tests/pass/align.rs index 5794b7f542762..f412541bde17a 100644 --- a/tests/pass/align.rs +++ b/tests/pass/align.rs @@ -1,3 +1,5 @@ +// compile-flags: -Zmiri-permissive-provenance + /// This manually makes sure that we have a pointer with the proper alignment. fn manual_alignment() { let x = &mut [0u8; 3]; diff --git a/tests/pass/align.stderr b/tests/pass/align.stderr deleted file mode 100644 index 9a15ec2cda6cd..0000000000000 --- a/tests/pass/align.stderr +++ /dev/null @@ -1,20 +0,0 @@ -warning: pointer-to-integer cast - --> $DIR/align.rs:LL:CC - | -LL | let u16_ptr = base_addr_aligned as *mut u16; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pointer-to-integer cast - | - = help: this program is using integer-to-pointer casts or (equivalently) `from_exposed_addr`, - = help: which means that Miri might miss pointer bugs in this program - = help: see https://doc.rust-lang.org/nightly/std/ptr/fn.from_exposed_addr.html for more details on that operation - = help: to ensure that Miri does not miss bugs in your program, use `with_addr` (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance) instead - = help: you can then pass the `-Zmiri-strict-provenance` flag to Miri, to ensure you are not relying on `from_exposed_addr` semantics - = help: alternatively, the `-Zmiri-permissive-provenance` flag disables this warning - - = note: inside `manual_alignment` at $DIR/align.rs:LL:CC -note: inside `main` at $DIR/align.rs:LL:CC - --> $DIR/align.rs:LL:CC - | -LL | manual_alignment(); - | ^^^^^^^^^^^^^^^^^^ - diff --git a/tests/pass/intptrcast.rs b/tests/pass/intptrcast.rs index a5e1d196529ef..2417a83493bef 100644 --- a/tests/pass/intptrcast.rs +++ b/tests/pass/intptrcast.rs @@ -90,6 +90,16 @@ fn ptr_eq_integer() { assert!(x != 64 as *const i32); } +fn zst_deref_of_dangling() { + let b = Box::new(0); + let addr = &*b as *const _ as usize; + drop(b); + // Now if we cast `addr` to a ptr it might pick up the dangling provenance. + // But if we only do a ZST deref there is no UB here! + let zst = addr as *const (); + let _val = unsafe { *zst }; +} + fn main() { cast(); cast_dangling(); @@ -101,4 +111,5 @@ fn main() { ptr_eq_out_of_bounds(); ptr_eq_out_of_bounds_null(); ptr_eq_integer(); + zst_deref_of_dangling(); } From 5c16713056ceb866c89bb94c344285dee87d9d0d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 26 Jun 2022 22:01:03 -0400 Subject: [PATCH 3337/3747] remove support for untagged pointers good riddance! --- src/bin/miri.rs | 2 +- src/diagnostics.rs | 18 ---- src/eval.rs | 2 +- src/lib.rs | 2 +- src/machine.rs | 8 +- src/stacked_borrows.rs | 165 +++++++++-------------------- src/stacked_borrows/diagnostics.rs | 94 +++------------- 7 files changed, 74 insertions(+), 217 deletions(-) diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 7bced912645db..a56b4bc6d1b4e 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -409,7 +409,7 @@ fn main() { err ), }; - for id in ids.into_iter().map(miri::PtrId::new) { + for id in ids.into_iter().map(miri::SbTag::new) { if let Some(id) = id { miri_config.tracked_pointer_tags.insert(id); } else { diff --git a/src/diagnostics.rs b/src/diagnostics.rs index d17d1e6ed4c87..8176e51338a5a 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -178,24 +178,6 @@ pub fn report_error<'tcx, 'mir>( helps.push((Some(*protection_span), "this protector is live for this call".to_string())); } } - Some(TagHistory::Untagged{ recently_created, recently_invalidated, matching_created, protected }) => { - if let Some((range, span)) = recently_created { - let msg = format!("tag was most recently created at offsets {}", HexRange(*range)); - helps.push((Some(*span), msg)); - } - if let Some((range, span)) = recently_invalidated { - let msg = format!("tag was later invalidated at offsets {}", HexRange(*range)); - helps.push((Some(*span), msg)); - } - if let Some((range, span)) = matching_created { - let msg = format!("this tag was also created here at offsets {}", HexRange(*range)); - helps.push((Some(*span), msg)); - } - if let Some((protecting_tag, protecting_tag_span, protection_span)) = protected { - helps.push((Some(*protecting_tag_span), format!("{:?} was protected due to a tag which was created here", protecting_tag))); - helps.push((Some(*protection_span), "this protector is live for this call".to_string())); - } - } None => {} } helps diff --git a/src/eval.rs b/src/eval.rs index fa252953fe6e4..12f1f52c78a33 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -96,7 +96,7 @@ pub struct MiriConfig { /// The seed to use when non-determinism or randomness are required (e.g. ptr-to-int cast, `getrandom()`). pub seed: Option, /// The stacked borrows pointer ids to report about - pub tracked_pointer_tags: HashSet, + pub tracked_pointer_tags: HashSet, /// The stacked borrows call IDs to report about pub tracked_call_ids: HashSet, /// The allocation ids to report about. diff --git a/src/lib.rs b/src/lib.rs index 68489c9b47b96..1633667fcad89 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -89,7 +89,7 @@ pub use crate::mono_hash_map::MonoHashMap; pub use crate::operator::EvalContextExt as OperatorEvalContextExt; pub use crate::range_map::RangeMap; pub use crate::stacked_borrows::{ - CallId, EvalContextExt as StackedBorEvalContextExt, Item, Permission, PtrId, SbTag, SbTagExtra, + CallId, EvalContextExt as StackedBorEvalContextExt, Item, Permission, SbTag, SbTagExtra, Stack, Stacks, }; pub use crate::sync::{CondvarId, EvalContextExt as SyncEvalContextExt, MutexId, RwLockId}; diff --git a/src/machine.rs b/src/machine.rs index d6a65a2a44c8c..5b18475458975 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -140,8 +140,9 @@ pub enum Tag { #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] static_assert_size!(Pointer, 24); +// FIXME: this would with in 24bytes but layout optimizations are not smart enough // #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] -// static_assert_size!(Pointer>, 24); +//static_assert_size!(Pointer>, 24); #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] static_assert_size!(ScalarMaybeUninit, 32); @@ -680,9 +681,10 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { } let absolute_addr = intptrcast::GlobalStateInner::rel_ptr_to_addr(ecx, ptr); let sb_tag = if let Some(stacked_borrows) = &ecx.machine.stacked_borrows { - stacked_borrows.borrow_mut().base_tag(ptr.provenance) + stacked_borrows.borrow_mut().base_ptr_tag(ptr.provenance) } else { - SbTag::Untagged + // Value does not matter, SB is disabled + SbTag::default() }; Pointer::new( Tag::Concrete { alloc_id: ptr.provenance, sb: sb_tag }, diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 23408027626c6..e79116a28ecfe 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -23,42 +23,29 @@ use crate::*; pub mod diagnostics; use diagnostics::{AllocHistory, TagHistory}; -pub type PtrId = NonZeroU64; pub type CallId = NonZeroU64; + // Even reading memory can have effects on the stack, so we need a `RefCell` here. pub type AllocExtra = RefCell; /// Tracking pointer provenance -#[derive(Copy, Clone, Hash, Eq)] -pub enum SbTag { - Tagged(PtrId), - Untagged, -} +#[derive(Copy, Clone, Hash, PartialEq, Eq)] +pub struct SbTag(NonZeroU64); impl SbTag { - fn as_u64(self) -> u64 { - match self { - SbTag::Tagged(id) => id.get(), - SbTag::Untagged => 0, - } + pub fn new(i: u64) -> Option { + NonZeroU64::new(i).map(SbTag) } -} -impl PartialEq for SbTag { - fn eq(&self, other: &Self) -> bool { - // The codegen for the derived Partialeq is bad here and includes a branch. - // Since this code is extremely hot, this is optimized here. - // https://github.com/rust-lang/rust/issues/49892 - self.as_u64() == other.as_u64() + // The default to be used when SB is disabled + pub fn default() -> Self { + Self::new(1).unwrap() } } impl fmt::Debug for SbTag { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - SbTag::Tagged(id) => write!(f, "<{}>", id), - SbTag::Untagged => write!(f, ""), - } + write!(f, "<{}>", self.0) } } @@ -73,7 +60,7 @@ pub enum SbTagExtra { impl fmt::Debug for SbTagExtra { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { - SbTagExtra::Concrete(tag) => write!(f, "{tag:?}"), + SbTagExtra::Concrete(pid) => write!(f, "{pid:?}"), SbTagExtra::Wildcard => write!(f, ""), } } @@ -82,7 +69,7 @@ impl fmt::Debug for SbTagExtra { impl SbTagExtra { fn and_then(self, f: impl FnOnce(SbTag) -> Option) -> Option { match self { - SbTagExtra::Concrete(tag) => f(tag), + SbTagExtra::Concrete(pid) => f(pid), SbTagExtra::Wildcard => None, } } @@ -130,15 +117,15 @@ pub struct Stack { /// Used *mostly* as a stack; never empty. /// Invariants: /// * Above a `SharedReadOnly` there can only be more `SharedReadOnly`. - /// * Except for `Untagged`, no tag occurs in the stack more than once. + /// * No tag occurs in the stack more than once. borrows: Vec, /// If this is `Some(id)`, then the actual current stack is unknown. This can happen when /// wildcard pointers are used to access this location. What we do know is that `borrows` are at - /// the top of the stack, and below it are arbitrarily many items whose `tag` is either - /// `Untagged` or strictly less than `id`. + /// the top of the stack, and below it are arbitrarily many items whose `tag` is strictly less + /// than `id`. /// When the bottom is unknown, `borrows` always has a `SharedReadOnly` or `Unique` at the bottom; /// we never have the unknown-to-known boundary in an SRW group. - unknown_bottom: Option, + unknown_bottom: Option, } /// Extra per-allocation state. @@ -156,21 +143,19 @@ pub struct Stacks { #[derive(Debug)] pub struct GlobalStateInner { /// Next unused pointer ID (tag). - next_ptr_id: PtrId, + next_ptr_tag: SbTag, /// Table storing the "base" tag for each allocation. /// The base tag is the one used for the initial pointer. /// We need this in a separate table to handle cyclic statics. - base_ptr_ids: FxHashMap, + base_ptr_tags: FxHashMap, /// Next unused call ID (for protectors). next_call_id: CallId, /// Those call IDs corresponding to functions that are still running. active_calls: FxHashSet, /// The pointer ids to trace - tracked_pointer_tags: HashSet, + tracked_pointer_tags: HashSet, /// The call ids to trace tracked_call_ids: HashSet, - /// Whether to track raw pointers. - tag_raw: bool, } /// We need interior mutable access to the global state. @@ -219,24 +204,23 @@ impl fmt::Display for RefKind { /// Utilities for initialization and ID generation impl GlobalStateInner { - pub fn new(tracked_pointer_tags: HashSet, tracked_call_ids: HashSet) -> Self { + pub fn new(tracked_pointer_tags: HashSet, tracked_call_ids: HashSet) -> Self { GlobalStateInner { - next_ptr_id: NonZeroU64::new(1).unwrap(), - base_ptr_ids: FxHashMap::default(), + next_ptr_tag: SbTag(NonZeroU64::new(1).unwrap()), + base_ptr_tags: FxHashMap::default(), next_call_id: NonZeroU64::new(1).unwrap(), active_calls: FxHashSet::default(), tracked_pointer_tags, tracked_call_ids, - tag_raw: true, } } - fn new_ptr(&mut self) -> PtrId { - let id = self.next_ptr_id; + fn new_ptr(&mut self) -> SbTag { + let id = self.next_ptr_tag; if self.tracked_pointer_tags.contains(&id) { - register_diagnostic(NonHaltingDiagnostic::CreatedPointerTag(id)); + register_diagnostic(NonHaltingDiagnostic::CreatedPointerTag(id.0)); } - self.next_ptr_id = NonZeroU64::new(id.get() + 1).unwrap(); + self.next_ptr_tag = SbTag(NonZeroU64::new(id.0.get() + 1).unwrap()); id } @@ -259,22 +243,14 @@ impl GlobalStateInner { self.active_calls.contains(&id) } - pub fn base_tag(&mut self, id: AllocId) -> SbTag { - self.base_ptr_ids.get(&id).copied().unwrap_or_else(|| { - let tag = SbTag::Tagged(self.new_ptr()); + pub fn base_ptr_tag(&mut self, id: AllocId) -> SbTag { + self.base_ptr_tags.get(&id).copied().unwrap_or_else(|| { + let tag = self.new_ptr(); trace!("New allocation {:?} has base tag {:?}", id, tag); - self.base_ptr_ids.try_insert(id, tag).unwrap(); + self.base_ptr_tags.try_insert(id, tag).unwrap(); tag }) } - - pub fn base_tag_untagged(&mut self, id: AllocId) -> SbTag { - trace!("New allocation {:?} has no base tag (untagged)", id); - let tag = SbTag::Untagged; - // This must only be done on new allocations. - self.base_ptr_ids.try_insert(id, tag).unwrap(); - tag - } } /// Error reporting @@ -364,10 +340,7 @@ impl<'tcx> Stack { // Couldn't find it in the stack; but if there is an unknown bottom it might be there. let found = self.unknown_bottom.is_some_and(|&unknown_limit| { - match tag { - SbTag::Tagged(tag_id) => tag_id < unknown_limit, // unknown_limit is an upper bound for what can be in the unknown bottom. - SbTag::Untagged => true, // yeah whatever - } + tag.0 < unknown_limit.0 // unknown_limit is an upper bound for what can be in the unknown bottom. }); if found { Ok(None) } else { Err(()) } } @@ -408,23 +381,22 @@ impl<'tcx> Stack { /// Within `provoking_access, the `AllocRange` refers the entire operation, and /// the `Size` refers to the specific location in the `AllocRange` that we are /// currently checking. - fn check_protector( + fn item_popped( item: &Item, provoking_access: Option<(SbTagExtra, AllocRange, Size, AccessKind)>, // just for debug printing and error messages global: &GlobalStateInner, alloc_history: &mut AllocHistory, ) -> InterpResult<'tcx> { - if let SbTag::Tagged(id) = item.tag { - if global.tracked_pointer_tags.contains(&id) { - register_diagnostic(NonHaltingDiagnostic::PoppedPointerTag( - *item, - provoking_access.map(|(tag, _alloc_range, _size, access)| (tag, access)), - )); - } + if global.tracked_pointer_tags.contains(&item.tag) { + register_diagnostic(NonHaltingDiagnostic::PoppedPointerTag( + *item, + provoking_access.map(|(tag, _alloc_range, _size, access)| (tag, access)), + )); } + if let Some(call) = item.protector { if global.is_active(call) { - if let Some((tag, alloc_range, offset, _access)) = provoking_access { + if let Some((tag, _alloc_range, _offset, _access)) = provoking_access { Err(err_sb_ub( format!( "not granting access to tag {:?} because incompatible item is protected: {:?}", @@ -434,8 +406,6 @@ impl<'tcx> Stack { tag.and_then(|tag| { alloc_history.get_logs_relevant_to( tag, - alloc_range, - offset, Some(item.tag), ) }), @@ -491,7 +461,7 @@ impl<'tcx> Stack { }; for item in self.borrows.drain(first_incompatible_idx..).rev() { trace!("access: popping item {:?}", item); - Stack::check_protector( + Stack::item_popped( &item, Some((tag, alloc_range, offset, access)), global, @@ -520,7 +490,7 @@ impl<'tcx> Stack { if item.perm == Permission::Unique { trace!("access: disabling item {:?}", item); - Stack::check_protector( + Stack::item_popped( item, Some((tag, alloc_range, offset, access)), global, @@ -540,21 +510,19 @@ impl<'tcx> Stack { for item in &self.borrows { // Skip disabled items, they cannot be matched anyway. if !matches!(item.perm, Permission::Disabled) { - if let SbTag::Tagged(tag) = item.tag { - // We are looking for a strict upper bound, so add 1 to this tag. - max = cmp::max(tag.checked_add(1).unwrap(), max); - } + // We are looking for a strict upper bound, so add 1 to this tag. + max = cmp::max(item.tag.0.checked_add(1).unwrap(), max); } } if let Some(unk) = self.unknown_bottom { - max = cmp::max(unk, max); + max = cmp::max(unk.0, max); } // Use `max` as new strict upper bound for everything. trace!( "access: forgetting stack to upper bound {max} due to wildcard or unknown access" ); self.borrows.clear(); - self.unknown_bottom = Some(max); + self.unknown_bottom = Some(SbTag(max)); } // Done. @@ -566,7 +534,7 @@ impl<'tcx> Stack { fn dealloc( &mut self, tag: SbTagExtra, - (alloc_id, alloc_range, offset): (AllocId, AllocRange, Size), // just for debug printing and error messages + (alloc_id, _alloc_range, _offset): (AllocId, AllocRange, Size), // just for debug printing and error messages global: &GlobalStateInner, alloc_history: &mut AllocHistory, exposed_tags: &FxHashSet, @@ -578,13 +546,13 @@ impl<'tcx> Stack { tag, alloc_id, ), None, - tag.and_then(|tag| alloc_history.get_logs_relevant_to(tag, alloc_range, offset, None)), + tag.and_then(|tag| alloc_history.get_logs_relevant_to(tag, None)), ) })?; // Step 2: Remove all items. Also checks for protectors. for item in self.borrows.drain(..).rev() { - Stack::check_protector(&item, None, global, alloc_history)?; + Stack::item_popped(&item, None, global, alloc_history)?; } Ok(()) } @@ -632,7 +600,7 @@ impl<'tcx> Stack { // (for all we know, it might join an SRW group inside the unknown). trace!("reborrow: forgetting stack entirely due to SharedReadWrite reborrow from wildcard or unknown"); self.borrows.clear(); - self.unknown_bottom = Some(global.next_ptr_id); + self.unknown_bottom = Some(global.next_ptr_tag); return Ok(()); }; @@ -726,30 +694,9 @@ impl Stacks { // not through a pointer). That is, whenever we directly write to a local, this will pop // everything else off the stack, invalidating all previous pointers, // and in particular, *all* raw pointers. - MemoryKind::Stack => (extra.base_tag(id), Permission::Unique), - // `Global` memory can be referenced by global pointers from `tcx`. - // Thus we call `global_base_ptr` such that the global pointers get the same tag - // as what we use here. - // `ExternStatic` is used for extern statics, so the same reasoning applies. - // The others are various forms of machine-managed special global memory, and we can get - // away with precise tracking there. - // The base pointer is not unique, so the base permission is `SharedReadWrite`. - MemoryKind::CallerLocation - | MemoryKind::Machine( - MiriMemoryKind::Global - | MiriMemoryKind::ExternStatic - | MiriMemoryKind::Tls - | MiriMemoryKind::Runtime - | MiriMemoryKind::Machine, - ) => (extra.base_tag(id), Permission::SharedReadWrite), - // Heap allocations we only track precisely when raw pointers are tagged, for now. - MemoryKind::Machine( - MiriMemoryKind::Rust | MiriMemoryKind::C | MiriMemoryKind::WinHeap, - ) => { - let tag = - if extra.tag_raw { extra.base_tag(id) } else { extra.base_tag_untagged(id) }; - (tag, Permission::SharedReadWrite) - } + MemoryKind::Stack => (extra.base_ptr_tag(id), Permission::Unique), + // Everything else is shared by default. + _ => (extra.base_ptr_tag(id), Permission::SharedReadWrite), }; let mut stacks = Stacks::new(size, perm, base_tag); stacks.history.log_creation( @@ -1039,15 +986,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx }; // Compute new borrow. - let new_tag = { - let mem_extra = this.machine.stacked_borrows.as_mut().unwrap().get_mut(); - match kind { - // Give up tracking for raw pointers. - RefKind::Raw { .. } if !mem_extra.tag_raw => SbTag::Untagged, - // All other pointers are properly tracked. - _ => SbTag::Tagged(mem_extra.new_ptr()), - } - }; + let new_tag = this.machine.stacked_borrows.as_mut().unwrap().get_mut().new_ptr(); // Reborrow. let alloc_id = this.reborrow(&place, size, kind, new_tag, protect)?; diff --git a/src/stacked_borrows/diagnostics.rs b/src/stacked_borrows/diagnostics.rs index a4a7f5e7a1e35..0a7edcdc89c12 100644 --- a/src/stacked_borrows/diagnostics.rs +++ b/src/stacked_borrows/diagnostics.rs @@ -32,7 +32,6 @@ struct Protection { #[derive(Clone, Debug)] struct Event { - time: usize, parent: Option, tag: SbTag, range: AllocRange, @@ -46,12 +45,6 @@ pub enum TagHistory { invalidated: Option<(AllocRange, SpanData)>, protected: Option<(SbTag, SpanData, SpanData)>, }, - Untagged { - recently_created: Option<(AllocRange, SpanData)>, - recently_invalidated: Option<(AllocRange, SpanData)>, - matching_created: Option<(AllocRange, SpanData)>, - protected: Option<(SbTag, SpanData, SpanData)>, - }, } impl AllocHistory { @@ -72,7 +65,7 @@ impl AllocHistory { current_span: &mut CurrentSpan<'_, '_, '_>, ) { let span = current_span.get(); - self.creations.push(Event { parent, tag, range, span, time: self.current_time }); + self.creations.push(Event { parent, tag, range, span }); self.current_time += 1; } @@ -83,7 +76,7 @@ impl AllocHistory { current_span: &mut CurrentSpan<'_, '_, '_>, ) { let span = current_span.get(); - self.invalidations.push(Event { parent: None, tag, range, span, time: self.current_time }); + self.invalidations.push(Event { parent: None, tag, range, span }); self.current_time += 1; } @@ -101,8 +94,6 @@ impl AllocHistory { pub fn get_logs_relevant_to( &self, tag: SbTag, - alloc_range: AllocRange, - offset: Size, protector_tag: Option, ) -> Option { let protected = protector_tag @@ -125,74 +116,17 @@ impl AllocHistory { }) }); - if let SbTag::Tagged(_) = tag { - let get_matching = |events: &[Event]| { - events.iter().rev().find_map(|event| { - if event.tag == tag { Some((event.range, event.span.data())) } else { None } - }) - }; - Some(TagHistory::Tagged { - tag, - created: get_matching(&self.creations)?, - invalidated: get_matching(&self.invalidations), - protected, - }) - } else { - let mut created_time = 0; - // Find the most recently created tag that satsfies this offset - let recently_created = self.creations.iter().rev().find_map(|event| { - if event.tag == tag && offset >= event.range.start && offset < event.range.end() { - created_time = event.time; - Some((event.range, event.span.data())) - } else { - None - } - }); - - // Find a different recently created tag that satisfies this whole operation, predates - // the recently created tag, and has a different span. - // We're trying to make a guess at which span the user wanted to provide the tag that - // they're using. - let matching_created = recently_created.and_then(|(_created_range, created_span)| { - self.creations.iter().rev().find_map(|event| { - if event.tag == tag - && alloc_range.start >= event.range.start - && alloc_range.end() <= event.range.end() - && event.span.data() != created_span - && event.time != created_time - { - Some((event.range, event.span.data())) - } else { - None - } - }) - }); - - // Find the most recent invalidation of this tag which post-dates the creation - let recently_invalidated = recently_created.and_then(|_| { - self.invalidations - .iter() - .rev() - .take_while(|event| event.time > created_time) - .find_map(|event| { - if event.tag == tag - && offset >= event.range.start - && offset < event.range.end() - { - Some((event.range, event.span.data())) - } else { - None - } - }) - }); - - Some(TagHistory::Untagged { - recently_created, - matching_created, - recently_invalidated, - protected, + let get_matching = |events: &[Event]| { + events.iter().rev().find_map(|event| { + if event.tag == tag { Some((event.range, event.span.data())) } else { None } }) - } + }; + Some(TagHistory::Tagged { + tag, + created: get_matching(&self.creations)?, + invalidated: get_matching(&self.invalidations), + protected, + }) } /// Report a descriptive error when `new` could not be granted from `derived_from`. @@ -215,7 +149,7 @@ impl AllocHistory { format!("{}{}", action, error_cause(stack, derived_from)), Some(operation_summary("a reborrow", alloc_id, alloc_range)), derived_from.and_then(|derived_from| { - self.get_logs_relevant_to(derived_from, alloc_range, error_offset, None) + self.get_logs_relevant_to(derived_from, None) }), ) } @@ -238,7 +172,7 @@ impl AllocHistory { err_sb_ub( format!("{}{}", action, error_cause(stack, tag)), Some(operation_summary("an access", alloc_id, alloc_range)), - tag.and_then(|tag| self.get_logs_relevant_to(tag, alloc_range, error_offset, None)), + tag.and_then(|tag| self.get_logs_relevant_to(tag, None)), ) } } From 4120425108855824356019cc3e7f6c2bfff157c1 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 26 Jun 2022 22:07:02 -0400 Subject: [PATCH 3338/3747] readme: move some things around --- README.md | 32 +++++++++++++++----------------- 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index efdbf5143d9f7..d7c50e9613fd0 100644 --- a/README.md +++ b/README.md @@ -289,6 +289,11 @@ environment variable. We first document the most relevant and most commonly used `-Zmiri-disable-isolation` is set. * `-Zmiri-ignore-leaks` disables the memory leak checker, and also allows some remaining threads to exist when the main thread exits. +* `-Zmiri-permissive-provenance` disables the warning for integer-to-pointer casts and + [`ptr::from_exposed_addr`](https://doc.rust-lang.org/nightly/std/ptr/fn.from_exposed_addr.html). + This will necessarily miss some bugs as those operations are not efficiently and accurately + implementable in a sanitizer, but it will only miss bugs that concern memory/pointers which is + subject to these operations. * `-Zmiri-preemption-rate` configures the probability that at the end of a basic block, the active thread will be preempted. The default is `0.01` (i.e., 1%). Setting this to `0` disables preemption. @@ -307,6 +312,16 @@ environment variable. We first document the most relevant and most commonly used provenance](https://github.com/rust-lang/rust/issues/95228) checking in Miri. This means that casting an integer to a pointer yields a result with 'invalid' provenance, i.e., with provenance that cannot be used for any memory access. +* `-Zmiri-symbolic-alignment-check` makes the alignment check more strict. By default, alignment is + checked by casting the pointer to an integer, and making sure that is a multiple of the alignment. + This can lead to cases where a program passes the alignment check by pure chance, because things + "happened to be" sufficiently aligned -- there is no UB in this execution but there would be UB in + others. To avoid such cases, the symbolic alignment check only takes into account the requested + alignment of the relevant allocation, and the offset into that allocation. This avoids missing + such bugs, but it also incurs some false positives when the code does manual integer arithmetic to + ensure alignment. (The standard library `align_to` method works fine in both modes; under + symbolic alignment it only fills the middle slice when the allocation guarantees sufficient + alignment.) The remaining flags are for advanced use only, and more likely to change or be removed. Some of these are **unsound**, which means they can lead @@ -354,23 +369,6 @@ to Miri failing to detect cases of undefined behavior in a program. application instead of raising an error within the context of Miri (and halting execution). Note that code might not expect these operations to ever panic, so this flag can lead to strange (mis)behavior. -* `-Zmiri-permissive-provenance` disables the warning for integer-to-pointer casts and - [`ptr::from_exposed_addr`](https://doc.rust-lang.org/nightly/std/ptr/fn.from_exposed_addr.html). - This will necessarily miss some bugs as those operations are not efficiently and accurately - implementable in a sanitizer, but it will only miss bugs that concern memory/pointers which is - subject to these operations. -* `-Zmiri-symbolic-alignment-check` makes the alignment check more strict. By - default, alignment is checked by casting the pointer to an integer, and making - sure that is a multiple of the alignment. This can lead to cases where a - program passes the alignment check by pure chance, because things "happened to - be" sufficiently aligned -- there is no UB in this execution but there would - be UB in others. To avoid such cases, the symbolic alignment check only takes - into account the requested alignment of the relevant allocation, and the - offset into that allocation. This avoids missing such bugs, but it also - incurs some false positives when the code does manual integer arithmetic to - ensure alignment. (The standard library `align_to` method works fine in both - modes; under symbolic alignment it only fills the middle slice when the - allocation guarantees sufficient alignment.) * `-Zmiri-track-alloc-id=,,...` shows a backtrace when the given allocations are being allocated or freed. This helps in debugging memory leaks and use after free bugs. Specifying this argument multiple times does not overwrite the previous From 1a5dfbeb7a9c4289bb1e8903a8768603e673f128 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 26 Jun 2022 22:27:38 -0400 Subject: [PATCH 3339/3747] fmt --- src/intptrcast.rs | 2 +- src/lib.rs | 4 ++-- src/stacked_borrows.rs | 7 +------ src/stacked_borrows/diagnostics.rs | 4 +--- 4 files changed, 5 insertions(+), 12 deletions(-) diff --git a/src/intptrcast.rs b/src/intptrcast.rs index cb0d6517b9426..83739c48efc58 100644 --- a/src/intptrcast.rs +++ b/src/intptrcast.rs @@ -94,7 +94,7 @@ impl<'mir, 'tcx> GlobalStateInner { if global_state.exposed.contains(&alloc_id) { // FIXME: this catches `InterpError`, which we should not usually do. // We might need a proper fallible API from `memory.rs` to avoid this though. - if let Ok(_) = ecx.get_alloc_size_and_align(alloc_id, AllocCheck::Live) { + if ecx.get_alloc_size_and_align(alloc_id, AllocCheck::Live).is_ok() { return Some(alloc_id); } } diff --git a/src/lib.rs b/src/lib.rs index 1633667fcad89..621af171f4a8e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -89,8 +89,8 @@ pub use crate::mono_hash_map::MonoHashMap; pub use crate::operator::EvalContextExt as OperatorEvalContextExt; pub use crate::range_map::RangeMap; pub use crate::stacked_borrows::{ - CallId, EvalContextExt as StackedBorEvalContextExt, Item, Permission, SbTag, SbTagExtra, - Stack, Stacks, + CallId, EvalContextExt as StackedBorEvalContextExt, Item, Permission, SbTag, SbTagExtra, Stack, + Stacks, }; pub use crate::sync::{CondvarId, EvalContextExt as SyncEvalContextExt, MutexId, RwLockId}; pub use crate::thread::{ diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index e79116a28ecfe..ea1132d3e12a4 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -403,12 +403,7 @@ impl<'tcx> Stack { tag, item ), None, - tag.and_then(|tag| { - alloc_history.get_logs_relevant_to( - tag, - Some(item.tag), - ) - }), + tag.and_then(|tag| alloc_history.get_logs_relevant_to(tag, Some(item.tag))), ))? } else { Err(err_sb_ub( diff --git a/src/stacked_borrows/diagnostics.rs b/src/stacked_borrows/diagnostics.rs index 0a7edcdc89c12..b1ff864bcd5e1 100644 --- a/src/stacked_borrows/diagnostics.rs +++ b/src/stacked_borrows/diagnostics.rs @@ -148,9 +148,7 @@ impl AllocHistory { err_sb_ub( format!("{}{}", action, error_cause(stack, derived_from)), Some(operation_summary("a reborrow", alloc_id, alloc_range)), - derived_from.and_then(|derived_from| { - self.get_logs_relevant_to(derived_from, None) - }), + derived_from.and_then(|derived_from| self.get_logs_relevant_to(derived_from, None)), ) } From 3abec0e2afdc635b1e2f4cfaf971a7fcd9a9e332 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 26 Jun 2022 23:00:54 -0400 Subject: [PATCH 3340/3747] make macOS happy --- test-cargo-miri/run-test.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/test-cargo-miri/run-test.py b/test-cargo-miri/run-test.py index 42978c481bff9..a16019a05e69f 100755 --- a/test-cargo-miri/run-test.py +++ b/test-cargo-miri/run-test.py @@ -114,15 +114,16 @@ def test_cargo_miri_test(): default_ref = "test.cross-target.stdout.ref" if is_foreign else "test.default.stdout.ref" filter_ref = "test.filter.cross-target.stdout.ref" if is_foreign else "test.filter.stdout.ref" + # macOS needs permissive provenance inside getrandom. test("`cargo miri test`", cargo_miri("test"), default_ref, "test.stderr-empty.ref", - env={'MIRIFLAGS': "-Zmiri-seed=feed"}, + env={'MIRIFLAGS': "-Zmiri-permissive-provenance -Zmiri-seed=feed"}, ) test("`cargo miri test` (no isolation, no doctests)", cargo_miri("test") + ["--bins", "--tests"], # no `--lib`, we disabled that in `Cargo.toml` "test.cross-target.stdout.ref", "test.stderr-empty.ref", - env={'MIRIFLAGS': "-Zmiri-disable-isolation"}, + env={'MIRIFLAGS': "-Zmiri-permissive-provenance -Zmiri-disable-isolation"}, ) test("`cargo miri test` (with filter)", cargo_miri("test") + ["--", "--format=pretty", "le1"], @@ -131,6 +132,7 @@ def test_cargo_miri_test(): test("`cargo miri test` (test target)", cargo_miri("test") + ["--test", "test", "--", "--format=pretty"], "test.test-target.stdout.ref", "test.stderr-empty.ref", + env={'MIRIFLAGS': "-Zmiri-permissive-provenance"}, ) test("`cargo miri test` (bin target)", cargo_miri("test") + ["--bin", "cargo-miri-test", "--", "--format=pretty"], @@ -148,11 +150,13 @@ def test_cargo_miri_test(): test("`cargo miri test` (custom target dir)", cargo_miri("test") + ["--target-dir=custom-test"], default_ref, "test.stderr-empty.ref", + env={'MIRIFLAGS': "-Zmiri-permissive-provenance"}, ) del os.environ["CARGO_TARGET_DIR"] # this overrides `build.target-dir` passed by `--config`, so unset it test("`cargo miri test` (config-cli)", cargo_miri("test") + ["--config=build.target-dir=\"config-cli\"", "-Zunstable-options"], default_ref, "test.stderr-empty.ref", + env={'MIRIFLAGS': "-Zmiri-permissive-provenance"}, ) os.chdir(os.path.dirname(os.path.realpath(__file__))) From b479f092a86c5524c76088346ac53cd4d0f86e0a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 26 Jun 2022 23:14:16 -0400 Subject: [PATCH 3341/3747] avoid unnecessary indirection in miri-track-raw-pointers warning --- src/bin/miri.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/bin/miri.rs b/src/bin/miri.rs index a56b4bc6d1b4e..1ccc54d6be196 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -385,7 +385,7 @@ fn main() { miri_config.mute_stdout_stderr = true; } else if arg == "-Zmiri-track-raw-pointers" { eprintln!( - "WARNING: -Zmiri-track-raw-pointers has been renamed to -Zmiri-tag-raw-pointers, the old name is deprecated." + "WARNING: `-Zmiri-track-raw-pointers` has no effect; it is enabled by default" ); } else if let Some(param) = arg.strip_prefix("-Zmiri-seed=") { if miri_config.seed.is_some() { From d9e7a3ae820b23d54ee9d1145e0295d1486601d6 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 27 Jun 2022 08:35:25 -0400 Subject: [PATCH 3342/3747] typo Co-authored-by: Oli Scherer --- src/intptrcast.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/intptrcast.rs b/src/intptrcast.rs index 83739c48efc58..5e6088303f819 100644 --- a/src/intptrcast.rs +++ b/src/intptrcast.rs @@ -215,7 +215,7 @@ impl<'mir, 'tcx> GlobalStateInner { dl.overflowing_offset(base_addr, offset.bytes()).0 } - /// Whena pointer is used for a memory access, this computes where in which allocation the + /// When a pointer is used for a memory access, this computes where in which allocation the /// access is going. pub fn abs_ptr_to_rel( ecx: &MiriEvalContext<'mir, 'tcx>, From fb186a2f2d6ea3851f7e41f7e66a81a0a4f9146f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 27 Jun 2022 11:44:45 -0400 Subject: [PATCH 3343/3747] make sure a thread is joined --- tests/pass/concurrency/sync_nopreempt.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/pass/concurrency/sync_nopreempt.rs b/tests/pass/concurrency/sync_nopreempt.rs index 391f65ae5a9cb..b5e726dac7b68 100644 --- a/tests/pass/concurrency/sync_nopreempt.rs +++ b/tests/pass/concurrency/sync_nopreempt.rs @@ -46,7 +46,7 @@ fn check_rwlock_unlock_bug1() { // Make a waiting writer. let l2 = l.clone(); - thread::spawn(move || { + let t = thread::spawn(move || { let mut w = l2.write().unwrap(); *w += 1; }); @@ -59,6 +59,7 @@ fn check_rwlock_unlock_bug1() { thread::yield_now(); assert_eq!(*r2, 0); drop(r2); + t.join().unwrap(); } fn check_rwlock_unlock_bug2() { From 5719897fb0ba0a91fd1b094019c5caf7f58e6e9f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 27 Jun 2022 13:38:32 -0400 Subject: [PATCH 3344/3747] improve old comment --- src/shims/unix/foreign_items.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/shims/unix/foreign_items.rs b/src/shims/unix/foreign_items.rs index 4993690767c14..d0c93ef4cdaf3 100644 --- a/src/shims/unix/foreign_items.rs +++ b/src/shims/unix/foreign_items.rs @@ -463,10 +463,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Querying system information "pthread_attr_getstack" => { - // We don't support "pthread_attr_setstack", so we just pretend all stacks have the same values here. + // We don't support "pthread_attr_setstack", so we just pretend all stacks have the same values here. Hence we can mostly ignore the input `attr_place`. let [attr_place, addr_place, size_place] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; - this.deref_operand(attr_place)?; + let _attr_place = this.deref_operand(attr_place)?; let addr_place = this.deref_operand(addr_place)?; let size_place = this.deref_operand(size_place)?; From 67e89b53e24d6bdf56d5c063f2c8997ab7d2381f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 27 Jun 2022 20:04:46 -0400 Subject: [PATCH 3345/3747] fix warning text --- src/diagnostics.rs | 4 ++-- tests/pass/box.stderr | 4 ++-- tests/pass/extern_types.stderr | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/diagnostics.rs b/src/diagnostics.rs index 8176e51338a5a..1a030bedd928c 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -451,13 +451,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx format!("{op} was made to return an error due to isolation"), ProgressReport => format!("progress report: current operation being executed is here"), - Int2Ptr => format!("pointer-to-integer cast"), + Int2Ptr => format!("integer-to-pointer cast"), }; let (title, diag_level) = match e { RejectedIsolatedOp(_) => ("operation rejected by isolation", DiagLevel::Warning), - Int2Ptr => ("pointer-to-integer cast", DiagLevel::Warning), + Int2Ptr => ("integer-to-pointer cast", DiagLevel::Warning), CreatedPointerTag(..) | PoppedPointerTag(..) | CreatedCallId(..) diff --git a/tests/pass/box.stderr b/tests/pass/box.stderr index eac98bf2d124f..eeb49eec5c052 100644 --- a/tests/pass/box.stderr +++ b/tests/pass/box.stderr @@ -1,8 +1,8 @@ -warning: pointer-to-integer cast +warning: integer-to-pointer cast --> $DIR/box.rs:LL:CC | LL | let r2 = ((r as usize) + 0) as *mut i32; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pointer-to-integer cast + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ integer-to-pointer cast | = help: this program is using integer-to-pointer casts or (equivalently) `from_exposed_addr`, = help: which means that Miri might miss pointer bugs in this program diff --git a/tests/pass/extern_types.stderr b/tests/pass/extern_types.stderr index 730a430425356..f23526b52b4e7 100644 --- a/tests/pass/extern_types.stderr +++ b/tests/pass/extern_types.stderr @@ -1,8 +1,8 @@ -warning: pointer-to-integer cast +warning: integer-to-pointer cast --> $DIR/extern_types.rs:LL:CC | LL | let x: &Foo = unsafe { &*(16 as *const Foo) }; - | ^^^^^^^^^^^^^^^^^^ pointer-to-integer cast + | ^^^^^^^^^^^^^^^^^^ integer-to-pointer cast | = help: this program is using integer-to-pointer casts or (equivalently) `from_exposed_addr`, = help: which means that Miri might miss pointer bugs in this program From c1eddbc7fefe34bb0213261cb4aa18f4bc11b1c5 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 27 Jun 2022 20:22:50 -0400 Subject: [PATCH 3346/3747] show int2ptr warning once for each span (but don't duplicate the long help) --- src/diagnostics.rs | 10 ++++++---- src/intptrcast.rs | 17 ++++++++++++----- src/lib.rs | 1 + tests/pass/box.stderr | 13 +++++++++++++ 4 files changed, 32 insertions(+), 9 deletions(-) diff --git a/src/diagnostics.rs b/src/diagnostics.rs index 1a030bedd928c..83949a75dee05 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -69,7 +69,9 @@ pub enum NonHaltingDiagnostic { FreedAlloc(AllocId), RejectedIsolatedOp(String), ProgressReport, - Int2Ptr, + Int2Ptr { + details: bool, + }, } /// Level of Miri specific diagnostics @@ -451,13 +453,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx format!("{op} was made to return an error due to isolation"), ProgressReport => format!("progress report: current operation being executed is here"), - Int2Ptr => format!("integer-to-pointer cast"), + Int2Ptr { .. } => format!("integer-to-pointer cast"), }; let (title, diag_level) = match e { RejectedIsolatedOp(_) => ("operation rejected by isolation", DiagLevel::Warning), - Int2Ptr => ("integer-to-pointer cast", DiagLevel::Warning), + Int2Ptr { .. } => ("integer-to-pointer cast", DiagLevel::Warning), CreatedPointerTag(..) | PoppedPointerTag(..) | CreatedCallId(..) @@ -467,7 +469,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx }; let helps = match e { - Int2Ptr => + Int2Ptr { details: true } => vec![ (None, format!("this program is using integer-to-pointer casts or (equivalently) `from_exposed_addr`,")), (None, format!("which means that Miri might miss pointer bugs in this program")), diff --git a/src/intptrcast.rs b/src/intptrcast.rs index 5e6088303f819..a95b20868d212 100644 --- a/src/intptrcast.rs +++ b/src/intptrcast.rs @@ -5,6 +5,7 @@ use log::trace; use rand::Rng; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_span::Span; use rustc_target::abi::{HasDataLayout, Size}; use crate::*; @@ -140,12 +141,18 @@ impl<'mir, 'tcx> GlobalStateInner { match global_state.provenance_mode { ProvenanceMode::Default => { - // The first time this happens, print a warning. - use std::sync::atomic::{AtomicBool, Ordering}; - static FIRST_WARNING: AtomicBool = AtomicBool::new(true); - if FIRST_WARNING.swap(false, Ordering::Relaxed) { - register_diagnostic(NonHaltingDiagnostic::Int2Ptr); + // The first time this happens at a particular location, print a warning. + thread_local! { + // `Span` is non-`Send`, so we use a thread-local instead. + static PAST_WARNINGS: RefCell> = RefCell::default(); } + PAST_WARNINGS.with_borrow_mut(|past_warnings| { + let first = past_warnings.is_empty(); + if past_warnings.insert(ecx.cur_span()) { + // Newly inserted, so first time we see this span. + register_diagnostic(NonHaltingDiagnostic::Int2Ptr { details: first }); + } + }); } ProvenanceMode::Strict => { throw_unsup_format!( diff --git a/src/lib.rs b/src/lib.rs index 621af171f4a8e..e199fae31ee82 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -8,6 +8,7 @@ #![feature(yeet_expr)] #![feature(is_some_with)] #![feature(nonzero_ops)] +#![feature(local_key_cell_methods)] #![warn(rust_2018_idioms)] #![allow( clippy::collapsible_else_if, diff --git a/tests/pass/box.stderr b/tests/pass/box.stderr index eeb49eec5c052..d821fcd9d1513 100644 --- a/tests/pass/box.stderr +++ b/tests/pass/box.stderr @@ -18,3 +18,16 @@ note: inside `main` at $DIR/box.rs:LL:CC LL | into_raw(); | ^^^^^^^^^^ +warning: integer-to-pointer cast + --> $DIR/box.rs:LL:CC + | +LL | let r = ((u.as_ptr() as usize) + 0) as *mut i32; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ integer-to-pointer cast + | + = note: inside `into_unique` at $DIR/box.rs:LL:CC +note: inside `main` at $DIR/box.rs:LL:CC + --> $DIR/box.rs:LL:CC + | +LL | into_unique(); + | ^^^^^^^^^^^^^ + From 098704e10fda8da532022fc9ef91e6a9173fd203 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 27 Jun 2022 11:09:28 -0400 Subject: [PATCH 3347/3747] make use of get_alloc_info --- src/intptrcast.rs | 27 ++++++------------- src/shims/mod.rs | 2 +- src/stacked_borrows.rs | 19 ++++++------- tests/fail/function_pointers/deref_fn_ptr.rs | 2 +- .../function_pointers/deref_fn_ptr.stderr | 4 +-- 5 files changed, 20 insertions(+), 34 deletions(-) diff --git a/src/intptrcast.rs b/src/intptrcast.rs index a95b20868d212..0ef5b08f9e40f 100644 --- a/src/intptrcast.rs +++ b/src/intptrcast.rs @@ -76,27 +76,17 @@ impl<'mir, 'tcx> GlobalStateInner { // This never overflows because `addr >= glb` let offset = addr - glb; // If the offset exceeds the size of the allocation, don't use this `alloc_id`. - - if offset - <= ecx - .get_alloc_size_and_align(alloc_id, AllocCheck::MaybeDead) - .unwrap() - .0 - .bytes() - { - Some(alloc_id) - } else { - None - } + let size = ecx.get_alloc_info(alloc_id).0; + if offset <= size.bytes() { Some(alloc_id) } else { None } } }?; // We only use this provenance if it has been exposed, *and* is still live. if global_state.exposed.contains(&alloc_id) { - // FIXME: this catches `InterpError`, which we should not usually do. - // We might need a proper fallible API from `memory.rs` to avoid this though. - if ecx.get_alloc_size_and_align(alloc_id, AllocCheck::Live).is_ok() { - return Some(alloc_id); + let (_size, _align, kind) = ecx.get_alloc_info(alloc_id); + match kind { + AllocKind::LiveData | AllocKind::Function => return Some(alloc_id), + AllocKind::Dead => {} } } @@ -174,9 +164,8 @@ impl<'mir, 'tcx> GlobalStateInner { Entry::Occupied(entry) => *entry.get(), Entry::Vacant(entry) => { // There is nothing wrong with a raw pointer being cast to an integer only after - // it became dangling. Hence `MaybeDead`. - let (size, align) = - ecx.get_alloc_size_and_align(alloc_id, AllocCheck::MaybeDead).unwrap(); + // it became dangling. Hence we allow dead allocations. + let (size, align, _kind) = ecx.get_alloc_info(alloc_id); // This allocation does not have a base address yet, pick one. // Leave some space to the previous allocation, to give it some chance to be less aligned. diff --git a/src/shims/mod.rs b/src/shims/mod.rs index f2688bb08caa4..2423ffaf5fe01 100644 --- a/src/shims/mod.rs +++ b/src/shims/mod.rs @@ -87,7 +87,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let ptr = this.read_pointer(ptr_op)?; if let Ok((alloc_id, _offset, _)) = this.ptr_try_get_alloc_id(ptr) { // Only do anything if we can identify the allocation this goes to. - let (_, cur_align) = this.get_alloc_size_and_align(alloc_id, AllocCheck::MaybeDead)?; + let (_size, cur_align, _kind) = this.get_alloc_info(alloc_id); if cur_align.bytes() >= req_align { // If the allocation alignment is at least the required alignment we use the // real implementation. diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index ea1132d3e12a4..66f756d7b08d4 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -849,8 +849,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx log_creation(this, current_span, alloc_id, base_offset, orig_tag)?; // Ensure we bail out if the pointer goes out-of-bounds (see miri#1050). - let (alloc_size, _) = - this.get_alloc_size_and_align(alloc_id, AllocCheck::Dereferenceable)?; + let (alloc_size, _) = this.get_live_alloc_size_and_align(alloc_id)?; if base_offset + size > alloc_size { throw_ub!(PointerOutOfBounds { alloc_id, @@ -1088,18 +1087,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Function pointers and dead objects don't have an alloc_extra so we ignore them. // This is okay because accessing them is UB anyway, no need for any Stacked Borrows checks. // NOT using `get_alloc_extra_mut` since this might be a read-only allocation! - // FIXME: this catches `InterpError`, which we should not usually do. - // We might need a proper fallible API from `memory.rs` to avoid this though. - match this.get_alloc_extra(alloc_id) { - Ok(alloc_extra) => { + let (_size, _align, kind) = this.get_alloc_info(alloc_id); + match kind { + AllocKind::LiveData => { + // This should have alloc_extra data. + let alloc_extra = this.get_alloc_extra(alloc_id).unwrap(); trace!("Stacked Borrows tag {tag:?} exposed in {alloc_id}"); alloc_extra.stacked_borrows.as_ref().unwrap().borrow_mut().exposed_tags.insert(tag); } - Err(err) => { - trace!( - "Not exposing Stacked Borrows tag {tag:?} due to error \ - when accessing {alloc_id}: {err}" - ); + AllocKind::Function | AllocKind::Dead => { + // No stacked borrows on these allocations. } } } diff --git a/tests/fail/function_pointers/deref_fn_ptr.rs b/tests/fail/function_pointers/deref_fn_ptr.rs index e604f96ea16f1..f22f73487b48c 100644 --- a/tests/fail/function_pointers/deref_fn_ptr.rs +++ b/tests/fail/function_pointers/deref_fn_ptr.rs @@ -2,7 +2,7 @@ fn f() {} fn main() { let x: u8 = unsafe { - *std::mem::transmute::(f) //~ ERROR contains a function + *std::mem::transmute::(f) //~ ERROR out-of-bounds }; panic!("this should never print: {}", x); } diff --git a/tests/fail/function_pointers/deref_fn_ptr.stderr b/tests/fail/function_pointers/deref_fn_ptr.stderr index 1e3da2726d4b8..619b58f699a32 100644 --- a/tests/fail/function_pointers/deref_fn_ptr.stderr +++ b/tests/fail/function_pointers/deref_fn_ptr.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: accessing ALLOC which contains a function +error: Undefined Behavior: dereferencing pointer failed: ALLOC has size 0, so pointer to 1 byte starting at offset 0 is out-of-bounds --> $DIR/deref_fn_ptr.rs:LL:CC | LL | *std::mem::transmute::(f) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ accessing ALLOC which contains a function + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ dereferencing pointer failed: ALLOC has size 0, so pointer to 1 byte starting at offset 0 is out-of-bounds | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information From ea30b6baddcdba49fdd47fa21d609011e32b6929 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 27 Jun 2022 21:29:40 -0400 Subject: [PATCH 3348/3747] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index dafb049cc5a85..5bda09cfdb2b0 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -8aab472d52ba7314dc193c73abcd384e2586123c +7f08d04d60d03e1a52dae61ce6aa50996898702b From c16b380d6bf3a72a8fcaa2b6ae469f0fa49f9ad5 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 27 Jun 2022 08:13:55 -0400 Subject: [PATCH 3349/3747] finally we can actually have adjacent allocations :) --- src/intptrcast.rs | 11 ++++---- tests/pass/adjacent-allocs.rs | 16 ++++++++++++ tests/pass/intptrcast.rs | 48 +++++++++++++++++++++++++++++++++++ 3 files changed, 70 insertions(+), 5 deletions(-) diff --git a/src/intptrcast.rs b/src/intptrcast.rs index a95b20868d212..1a630259cf6af 100644 --- a/src/intptrcast.rs +++ b/src/intptrcast.rs @@ -1,4 +1,5 @@ use std::cell::RefCell; +use std::cmp::max; use std::collections::hash_map::Entry; use log::trace; @@ -198,11 +199,11 @@ impl<'mir, 'tcx> GlobalStateInner { slack, ); - // Remember next base address. Leave a gap of at least 1 to avoid two zero-sized allocations - // having the same base address, and to avoid ambiguous provenance for the address between two - // allocations (also see https://github.com/rust-lang/unsafe-code-guidelines/issues/313). - let size_plus_1 = size.bytes().checked_add(1).unwrap(); - global_state.next_base_addr = base_addr.checked_add(size_plus_1).unwrap(); + // Remember next base address. If this allocation is zero-sized, leave a gap + // of at least 1 to avoid two allocations having the same base address. + // (The logic in `alloc_id_from_addr` assumes unique addresses, and function + // pointers to different functions need to be distinguishable!) + global_state.next_base_addr = base_addr.checked_add(max(size.bytes(), 1)).unwrap(); // Given that `next_base_addr` increases in each allocation, pushing the // corresponding tuple keeps `int_to_ptr_map` sorted global_state.int_to_ptr_map.push((base_addr, alloc_id)); diff --git a/tests/pass/adjacent-allocs.rs b/tests/pass/adjacent-allocs.rs index b3483a5b43800..d0dc8b5d87622 100644 --- a/tests/pass/adjacent-allocs.rs +++ b/tests/pass/adjacent-allocs.rs @@ -1,5 +1,20 @@ // compile-flags: -Zmiri-permissive-provenance +fn ensure_allocs_can_be_adjacent() { + for _ in 0..512 { + let n = 0u64; + let ptr: *const u64 = &n; + let ptr2 = { + let m = 0u64; + &m as *const u64 + }; + if ptr.wrapping_add(1) == ptr2 { + return; + } + } + panic!("never saw adjacent stack variables?"); +} + fn test1() { // The slack between allocations is random. // Loop a few times to hit the zero-slack case. @@ -42,6 +57,7 @@ fn test2() { } fn main() { + ensure_allocs_can_be_adjacent(); test1(); test2(); } diff --git a/tests/pass/intptrcast.rs b/tests/pass/intptrcast.rs index 2417a83493bef..aebf5b2223895 100644 --- a/tests/pass/intptrcast.rs +++ b/tests/pass/intptrcast.rs @@ -1,5 +1,7 @@ // compile-flags: -Zmiri-permissive-provenance +use std::mem; + // This strips provenance fn transmute_ptr_to_int(x: *const T) -> usize { unsafe { std::mem::transmute(x) } @@ -100,6 +102,51 @@ fn zst_deref_of_dangling() { let _val = unsafe { *zst }; } +fn functions() { + // Roundtrip a few functions through integers. Do this multiple times to make sure this does not + // work by chance. If we did not give unique addresses to ZST allocations -- which fn + // allocations are -- then we might be unable to cast back, or we might call the wrong function! + // Every function gets at most one address so doing a loop would not help... + fn fn0() -> i32 { + 0 + } + fn fn1() -> i32 { + 1 + } + fn fn2() -> i32 { + 2 + } + fn fn3() -> i32 { + 3 + } + fn fn4() -> i32 { + 4 + } + fn fn5() -> i32 { + 5 + } + fn fn6() -> i32 { + 6 + } + fn fn7() -> i32 { + 7 + } + let fns = [ + fn0 as fn() -> i32 as *const () as usize, + fn1 as fn() -> i32 as *const () as usize, + fn2 as fn() -> i32 as *const () as usize, + fn3 as fn() -> i32 as *const () as usize, + fn4 as fn() -> i32 as *const () as usize, + fn5 as fn() -> i32 as *const () as usize, + fn6 as fn() -> i32 as *const () as usize, + fn7 as fn() -> i32 as *const () as usize, + ]; + for (idx, &addr) in fns.iter().enumerate() { + let fun: fn() -> i32 = unsafe { mem::transmute(addr as *const ()) }; + assert_eq!(fun(), idx as i32); + } +} + fn main() { cast(); cast_dangling(); @@ -112,4 +159,5 @@ fn main() { ptr_eq_out_of_bounds_null(); ptr_eq_integer(); zst_deref_of_dangling(); + functions(); } From 108fe3473c59984027d6e5caeab1b11caf2531a7 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 27 Jun 2022 11:16:27 -0400 Subject: [PATCH 3350/3747] update getrandom --- test-cargo-miri/Cargo.lock | 78 ++++++++++++++++--------------------- test-cargo-miri/run-test.py | 2 +- 2 files changed, 35 insertions(+), 45 deletions(-) diff --git a/test-cargo-miri/Cargo.lock b/test-cargo-miri/Cargo.lock index 4bece389dc87f..d34db9f14dfcf 100644 --- a/test-cargo-miri/Cargo.lock +++ b/test-cargo-miri/Cargo.lock @@ -16,7 +16,7 @@ dependencies = [ "cdylib", "exported_symbol", "getrandom 0.1.16", - "getrandom 0.2.2", + "getrandom 0.2.7", "issue_1567", "issue_1691", "issue_1705", @@ -64,20 +64,20 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.2" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9495705279e7140bf035dde1f6e750c162df8b625267cd52cc44e0b156732c8" +checksum = "4eb1a864a501629691edf6c15a593b7a51eebaa1e8468e9ddc623de7c9b58ec6" dependencies = [ "cfg-if", "libc", - "wasi 0.10.2+wasi-snapshot-preview1", + "wasi 0.11.0+wasi-snapshot-preview1", ] [[package]] name = "hermit-abi" -version = "0.1.18" +version = "0.1.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "322f4de77956e22ed0e5032c359a0f1273f1f7f0d79bfa3b8ffbc730d7fbcc5c" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" dependencies = [ "libc", ] @@ -110,15 +110,15 @@ version = "0.1.0" [[package]] name = "libc" -version = "0.2.92" +version = "0.2.126" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56d855069fafbb9b344c0f962150cd2c1187975cb1c22c1522c240d8c4986714" +checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836" [[package]] name = "num_cpus" -version = "1.13.0" +version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3" +checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1" dependencies = [ "hermit-abi", "libc", @@ -136,45 +136,44 @@ dependencies = [ [[package]] name = "ppv-lite86" -version = "0.2.10" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857" +checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872" [[package]] name = "proc-macro2" -version = "1.0.26" +version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a152013215dca273577e18d2bf00fa862b89b24169fb78c4c95aeb07992c9cec" +checksum = "dd96a1e8ed2596c337f8eae5f24924ec83f5ad5ab21ea8e455d3566c69fbcaf7" dependencies = [ - "unicode-xid", + "unicode-ident", ] [[package]] name = "quote" -version = "1.0.9" +version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7" +checksum = "3bcdf212e9776fbcb2d23ab029360416bb1706b1aea2d1a5ba002727cbcab804" dependencies = [ "proc-macro2", ] [[package]] name = "rand" -version = "0.8.3" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ef9e7e66b4468674bfcb0c81af8b7fa0bb154fa9f28eb840da5c447baeb8d7e" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ "libc", "rand_chacha", "rand_core", - "rand_hc", ] [[package]] name = "rand_chacha" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e12735cf05c9e10bf21534da50a147b924d555dc7a547c42e6bb2d5b6017ae0d" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" dependencies = [ "ppv-lite86", "rand_core", @@ -182,27 +181,18 @@ dependencies = [ [[package]] name = "rand_core" -version = "0.6.2" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34cf66eb183df1c5876e2dcf6b13d57340741e8dc255b48e40a26de954d06ae7" +checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7" dependencies = [ - "getrandom 0.2.2", -] - -[[package]] -name = "rand_hc" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3190ef7066a446f2e7f42e239d161e905420ccab01eb967c9eb27d21b2322a73" -dependencies = [ - "rand_core", + "getrandom 0.2.7", ] [[package]] name = "serde_derive" -version = "1.0.125" +version = "1.0.137" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b093b7a2bb58203b5da3056c05b4ec1fed827dcfdb37347a8841695263b3d06d" +checksum = "1f26faba0c3959972377d3b2d306ee9f71faee9714294e41bb777f83f88578be" dependencies = [ "proc-macro2", "quote", @@ -218,20 +208,20 @@ dependencies = [ [[package]] name = "syn" -version = "1.0.68" +version = "1.0.98" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ce15dd3ed8aa2f8eeac4716d6ef5ab58b6b9256db41d7e1a0224c2788e8fd87" +checksum = "c50aef8a904de4c23c788f104b7dddc7d6f79c647c7c8ce4cc8f73eb0ca773dd" dependencies = [ "proc-macro2", "quote", - "unicode-xid", + "unicode-ident", ] [[package]] -name = "unicode-xid" -version = "0.2.1" +name = "unicode-ident" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" +checksum = "5bd2fe26506023ed7b5e1e315add59d6f584c621d037f9368fea9cfb988f368c" [[package]] name = "wasi" @@ -241,9 +231,9 @@ checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" [[package]] name = "wasi" -version = "0.10.2+wasi-snapshot-preview1" +version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "winapi" diff --git a/test-cargo-miri/run-test.py b/test-cargo-miri/run-test.py index a16019a05e69f..09e7df39b1c07 100755 --- a/test-cargo-miri/run-test.py +++ b/test-cargo-miri/run-test.py @@ -114,7 +114,7 @@ def test_cargo_miri_test(): default_ref = "test.cross-target.stdout.ref" if is_foreign else "test.default.stdout.ref" filter_ref = "test.filter.cross-target.stdout.ref" if is_foreign else "test.filter.stdout.ref" - # macOS needs permissive provenance inside getrandom. + # macOS needs permissive provenance inside getrandom_1. test("`cargo miri test`", cargo_miri("test"), default_ref, "test.stderr-empty.ref", From 65497649602ca5b56bed9418eda7d2e2be72487d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 27 Jun 2022 22:11:09 -0400 Subject: [PATCH 3351/3747] typo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d7c50e9613fd0..a7ee11e82e0f0 100644 --- a/README.md +++ b/README.md @@ -277,7 +277,7 @@ environment variable. We first document the most relevant and most commonly used and `warn-nobacktrace` are the supported actions. The default is to `abort`, which halts the machine. Some (but not all) operations also support continuing execution with a "permission denied" error being returned to the program. - `warn` prints a full backtrace when that happen; `warn-nobacktrace` is less + `warn` prints a full backtrace when that happens; `warn-nobacktrace` is less verbose. `hide` hides the warning entirely. * `-Zmiri-env-exclude=` keeps the `var` environment variable isolated from the host so that it cannot be accessed by the program. Can be used multiple times to exclude several variables. The From 8bd4bbe3e4b4630cb96f238618d1bb7b3aea5502 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 28 Jun 2022 08:52:22 -0400 Subject: [PATCH 3352/3747] tweak int2ptr diagnostics --- src/diagnostics.rs | 25 +++++++++++++------ src/intptrcast.rs | 4 +-- .../fail/provenance/strict_provenance_cast.rs | 2 +- .../provenance/strict_provenance_cast.stderr | 6 ++--- tests/pass/box.stderr | 12 ++++----- tests/pass/extern_types.stderr | 12 ++++----- 6 files changed, 34 insertions(+), 27 deletions(-) diff --git a/src/diagnostics.rs b/src/diagnostics.rs index 83949a75dee05..c762b3d8106de 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -21,6 +21,7 @@ pub enum TerminationInfo { help: Option, history: Option, }, + Int2PtrWithStrictProvenance, Deadlock, MultipleSymbolDefinitions { link_name: Symbol, @@ -42,6 +43,11 @@ impl fmt::Display for TerminationInfo { Exit(code) => write!(f, "the evaluated program completed with exit code {}", code), Abort(msg) => write!(f, "{}", msg), UnsupportedInIsolation(msg) => write!(f, "{}", msg), + Int2PtrWithStrictProvenance => + write!( + f, + "integer-to-pointer casts and `ptr::from_exposed_addr` are not supported with `-Zmiri-strict-provenance`" + ), StackedBorrowsUb { msg, .. } => write!(f, "{}", msg), Deadlock => write!(f, "the evaluated program deadlocked"), MultipleSymbolDefinitions { link_name, .. } => @@ -148,7 +154,8 @@ pub fn report_error<'tcx, 'mir>( let title = match info { Exit(code) => return Some(*code), Abort(_) => Some("abnormal termination"), - UnsupportedInIsolation(_) => Some("unsupported operation"), + UnsupportedInIsolation(_) | Int2PtrWithStrictProvenance => + Some("unsupported operation"), StackedBorrowsUb { .. } => Some("Undefined Behavior"), Deadlock => Some("deadlock"), MultipleSymbolDefinitions { .. } | SymbolShimClashing { .. } => None, @@ -177,7 +184,7 @@ pub fn report_error<'tcx, 'mir>( } if let Some((protecting_tag, protecting_tag_span, protection_span)) = protected { helps.push((Some(*protecting_tag_span), format!("{:?} was protected due to {:?} which was created here", tag, protecting_tag))); - helps.push((Some(*protection_span), "this protector is live for this call".to_string())); + helps.push((Some(*protection_span), format!("this protector is live for this call"))); } } None => {} @@ -191,6 +198,8 @@ pub fn report_error<'tcx, 'mir>( ], SymbolShimClashing { link_name, span } => vec![(Some(*span), format!("the `{}` symbol is defined here", link_name))], + Int2PtrWithStrictProvenance => + vec![(None, format!("use Strict Provenance APIs (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance, https://crates.io/crates/sptr) instead"))], _ => vec![], }; (title, helps) @@ -471,12 +480,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let helps = match e { Int2Ptr { details: true } => vec![ - (None, format!("this program is using integer-to-pointer casts or (equivalently) `from_exposed_addr`,")), - (None, format!("which means that Miri might miss pointer bugs in this program")), - (None, format!("see https://doc.rust-lang.org/nightly/std/ptr/fn.from_exposed_addr.html for more details on that operation")), - (None, format!("to ensure that Miri does not miss bugs in your program, use `with_addr` (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance) instead")), - (None, format!("you can then pass the `-Zmiri-strict-provenance` flag to Miri, to ensure you are not relying on `from_exposed_addr` semantics")), - (None, format!("alternatively, the `-Zmiri-permissive-provenance` flag disables this warning")), + (None, format!("This program is using integer-to-pointer casts or (equivalently) `ptr::from_exposed_addr`,")), + (None, format!("which means that Miri might miss pointer bugs in this program.")), + (None, format!("See https://doc.rust-lang.org/nightly/std/ptr/fn.from_exposed_addr.html for more details on that operation.")), + (None, format!("To ensure that Miri does not miss bugs in your program, use Strict Provenance APIs (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance, https://crates.io/crates/sptr) instead.")), + (None, format!("You can then pass the `-Zmiri-strict-provenance` flag to Miri, to ensure you are not relying on `from_exposed_addr` semantics.")), + (None, format!("Alternatively, the `-Zmiri-permissive-provenance` flag disables this warning.")), ], _ => vec![], }; diff --git a/src/intptrcast.rs b/src/intptrcast.rs index 0ebc62ebbfb19..5a33ada450443 100644 --- a/src/intptrcast.rs +++ b/src/intptrcast.rs @@ -146,9 +146,7 @@ impl<'mir, 'tcx> GlobalStateInner { }); } ProvenanceMode::Strict => { - throw_unsup_format!( - "integer-to-pointer casts and `from_exposed_addr` are not supported with `-Zmiri-strict-provenance`; use `with_addr` instead" - ) + throw_machine_stop!(TerminationInfo::Int2PtrWithStrictProvenance); } ProvenanceMode::Permissive => {} } diff --git a/tests/fail/provenance/strict_provenance_cast.rs b/tests/fail/provenance/strict_provenance_cast.rs index 8b2b053bdb591..968c4dfded37a 100644 --- a/tests/fail/provenance/strict_provenance_cast.rs +++ b/tests/fail/provenance/strict_provenance_cast.rs @@ -2,5 +2,5 @@ fn main() { let addr = &0 as *const i32 as usize; - let _ptr = addr as *const i32; //~ ERROR integer-to-pointer casts and `from_exposed_addr` are not supported + let _ptr = addr as *const i32; //~ ERROR integer-to-pointer casts and `ptr::from_exposed_addr` are not supported } diff --git a/tests/fail/provenance/strict_provenance_cast.stderr b/tests/fail/provenance/strict_provenance_cast.stderr index 32a39b81d9d7f..ab64f2bb288ea 100644 --- a/tests/fail/provenance/strict_provenance_cast.stderr +++ b/tests/fail/provenance/strict_provenance_cast.stderr @@ -1,10 +1,10 @@ -error: unsupported operation: integer-to-pointer casts and `from_exposed_addr` are not supported with `-Zmiri-strict-provenance`; use `with_addr` instead +error: unsupported operation: integer-to-pointer casts and `ptr::from_exposed_addr` are not supported with `-Zmiri-strict-provenance` --> $DIR/strict_provenance_cast.rs:LL:CC | LL | let _ptr = addr as *const i32; - | ^^^^^^^^^^^^^^^^^^ integer-to-pointer casts and `from_exposed_addr` are not supported with `-Zmiri-strict-provenance`; use `with_addr` instead + | ^^^^^^^^^^^^^^^^^^ integer-to-pointer casts and `ptr::from_exposed_addr` are not supported with `-Zmiri-strict-provenance` | - = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support + = help: use Strict Provenance APIs (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance, https://crates.io/crates/sptr) instead = note: inside `main` at $DIR/strict_provenance_cast.rs:LL:CC diff --git a/tests/pass/box.stderr b/tests/pass/box.stderr index d821fcd9d1513..41c752d5d0fc7 100644 --- a/tests/pass/box.stderr +++ b/tests/pass/box.stderr @@ -4,12 +4,12 @@ warning: integer-to-pointer cast LL | let r2 = ((r as usize) + 0) as *mut i32; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ integer-to-pointer cast | - = help: this program is using integer-to-pointer casts or (equivalently) `from_exposed_addr`, - = help: which means that Miri might miss pointer bugs in this program - = help: see https://doc.rust-lang.org/nightly/std/ptr/fn.from_exposed_addr.html for more details on that operation - = help: to ensure that Miri does not miss bugs in your program, use `with_addr` (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance) instead - = help: you can then pass the `-Zmiri-strict-provenance` flag to Miri, to ensure you are not relying on `from_exposed_addr` semantics - = help: alternatively, the `-Zmiri-permissive-provenance` flag disables this warning + = help: This program is using integer-to-pointer casts or (equivalently) `ptr::from_exposed_addr`, + = help: which means that Miri might miss pointer bugs in this program. + = help: See https://doc.rust-lang.org/nightly/std/ptr/fn.from_exposed_addr.html for more details on that operation. + = help: To ensure that Miri does not miss bugs in your program, use Strict Provenance APIs (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance, https://crates.io/crates/sptr) instead. + = help: You can then pass the `-Zmiri-strict-provenance` flag to Miri, to ensure you are not relying on `from_exposed_addr` semantics. + = help: Alternatively, the `-Zmiri-permissive-provenance` flag disables this warning. = note: inside `into_raw` at $DIR/box.rs:LL:CC note: inside `main` at $DIR/box.rs:LL:CC diff --git a/tests/pass/extern_types.stderr b/tests/pass/extern_types.stderr index f23526b52b4e7..3a4acec5ddb9e 100644 --- a/tests/pass/extern_types.stderr +++ b/tests/pass/extern_types.stderr @@ -4,12 +4,12 @@ warning: integer-to-pointer cast LL | let x: &Foo = unsafe { &*(16 as *const Foo) }; | ^^^^^^^^^^^^^^^^^^ integer-to-pointer cast | - = help: this program is using integer-to-pointer casts or (equivalently) `from_exposed_addr`, - = help: which means that Miri might miss pointer bugs in this program - = help: see https://doc.rust-lang.org/nightly/std/ptr/fn.from_exposed_addr.html for more details on that operation - = help: to ensure that Miri does not miss bugs in your program, use `with_addr` (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance) instead - = help: you can then pass the `-Zmiri-strict-provenance` flag to Miri, to ensure you are not relying on `from_exposed_addr` semantics - = help: alternatively, the `-Zmiri-permissive-provenance` flag disables this warning + = help: This program is using integer-to-pointer casts or (equivalently) `ptr::from_exposed_addr`, + = help: which means that Miri might miss pointer bugs in this program. + = help: See https://doc.rust-lang.org/nightly/std/ptr/fn.from_exposed_addr.html for more details on that operation. + = help: To ensure that Miri does not miss bugs in your program, use Strict Provenance APIs (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance, https://crates.io/crates/sptr) instead. + = help: You can then pass the `-Zmiri-strict-provenance` flag to Miri, to ensure you are not relying on `from_exposed_addr` semantics. + = help: Alternatively, the `-Zmiri-permissive-provenance` flag disables this warning. = note: inside `main` at $DIR/extern_types.rs:LL:CC From 28dea673bec32b5d59545912f53ad22b8944f3a4 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 29 Jun 2022 08:33:06 -0400 Subject: [PATCH 3353/3747] rustup --- rust-version | 2 +- src/diagnostics.rs | 4 + src/shims/intrinsics.rs | 122 +++++++++--------- .../data_race/atomic_read_na_write_race1.rs | 4 +- .../atomic_read_na_write_race1.stderr | 4 +- tests/fail/panic/double_panic.stderr | 1 - tests/fail/panic/panic_abort1.stderr | 1 - tests/fail/panic/panic_abort2.stderr | 1 - tests/fail/panic/panic_abort3.stderr | 2 - tests/fail/panic/panic_abort4.stderr | 1 - .../unaligned_pointers/atomic_unaligned.rs | 2 +- .../atomic_unaligned.stderr | 4 +- 12 files changed, 73 insertions(+), 75 deletions(-) diff --git a/rust-version b/rust-version index 5bda09cfdb2b0..4f24d29e34b48 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -7f08d04d60d03e1a52dae61ce6aa50996898702b +493c960a3e6cdd2e2fbe8b6ea130fadea05f1ab0 diff --git a/src/diagnostics.rs b/src/diagnostics.rs index c762b3d8106de..95252a1134294 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -107,6 +107,10 @@ fn prune_stacktrace<'mir, 'tcx>( // bug in the Rust runtime, we don't prune away every frame. let has_local_frame = stacktrace.iter().any(|frame| ecx.machine.is_local(frame)); if has_local_frame { + // Remove all frames marked with `caller_location` -- that attribute indicates we + // usually want to point at the caller, not them. + stacktrace.retain(|frame| !frame.instance.def.requires_caller_location(*ecx.tcx)); + // This is part of the logic that `std` uses to select the relevant part of a // backtrace. But here, we only look for __rust_begin_short_backtrace, not // __rust_end_short_backtrace because the end symbol comes from a call to the default diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 8d4da31fd0d77..fa5a6e9c273e5 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -864,95 +864,95 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // Atomic operations - "atomic_load" => this.atomic_load(args, dest, AtomicReadOp::SeqCst)?, + "atomic_load_seqcst" => this.atomic_load(args, dest, AtomicReadOp::SeqCst)?, "atomic_load_relaxed" => this.atomic_load(args, dest, AtomicReadOp::Relaxed)?, - "atomic_load_acq" => this.atomic_load(args, dest, AtomicReadOp::Acquire)?, + "atomic_load_acquire" => this.atomic_load(args, dest, AtomicReadOp::Acquire)?, - "atomic_store" => this.atomic_store(args, AtomicWriteOp::SeqCst)?, + "atomic_store_seqcst" => this.atomic_store(args, AtomicWriteOp::SeqCst)?, "atomic_store_relaxed" => this.atomic_store(args, AtomicWriteOp::Relaxed)?, - "atomic_store_rel" => this.atomic_store(args, AtomicWriteOp::Release)?, + "atomic_store_release" => this.atomic_store(args, AtomicWriteOp::Release)?, - "atomic_fence_acq" => this.atomic_fence(args, AtomicFenceOp::Acquire)?, - "atomic_fence_rel" => this.atomic_fence(args, AtomicFenceOp::Release)?, + "atomic_fence_acquire" => this.atomic_fence(args, AtomicFenceOp::Acquire)?, + "atomic_fence_release" => this.atomic_fence(args, AtomicFenceOp::Release)?, "atomic_fence_acqrel" => this.atomic_fence(args, AtomicFenceOp::AcqRel)?, - "atomic_fence" => this.atomic_fence(args, AtomicFenceOp::SeqCst)?, + "atomic_fence_seqcst" => this.atomic_fence(args, AtomicFenceOp::SeqCst)?, - "atomic_singlethreadfence_acq" => this.compiler_fence(args, AtomicFenceOp::Acquire)?, - "atomic_singlethreadfence_rel" => this.compiler_fence(args, AtomicFenceOp::Release)?, + "atomic_singlethreadfence_acquire" => this.compiler_fence(args, AtomicFenceOp::Acquire)?, + "atomic_singlethreadfence_release" => this.compiler_fence(args, AtomicFenceOp::Release)?, "atomic_singlethreadfence_acqrel" => this.compiler_fence(args, AtomicFenceOp::AcqRel)?, - "atomic_singlethreadfence" => this.compiler_fence(args, AtomicFenceOp::SeqCst)?, + "atomic_singlethreadfence_seqcst" => this.compiler_fence(args, AtomicFenceOp::SeqCst)?, - "atomic_xchg" => this.atomic_exchange(args, dest, AtomicRwOp::SeqCst)?, - "atomic_xchg_acq" => this.atomic_exchange(args, dest, AtomicRwOp::Acquire)?, - "atomic_xchg_rel" => this.atomic_exchange(args, dest, AtomicRwOp::Release)?, + "atomic_xchg_seqcst" => this.atomic_exchange(args, dest, AtomicRwOp::SeqCst)?, + "atomic_xchg_acquire" => this.atomic_exchange(args, dest, AtomicRwOp::Acquire)?, + "atomic_xchg_release" => this.atomic_exchange(args, dest, AtomicRwOp::Release)?, "atomic_xchg_acqrel" => this.atomic_exchange(args, dest, AtomicRwOp::AcqRel)?, "atomic_xchg_relaxed" => this.atomic_exchange(args, dest, AtomicRwOp::Relaxed)?, #[rustfmt::skip] - "atomic_cxchg" => + "atomic_cxchg_seqcst_seqcst" => this.atomic_compare_exchange(args, dest, AtomicRwOp::SeqCst, AtomicReadOp::SeqCst)?, #[rustfmt::skip] - "atomic_cxchg_acq" => + "atomic_cxchg_acquire_acquire" => this.atomic_compare_exchange(args, dest, AtomicRwOp::Acquire, AtomicReadOp::Acquire)?, #[rustfmt::skip] - "atomic_cxchg_rel" => + "atomic_cxchg_release_relaxed" => this.atomic_compare_exchange(args, dest, AtomicRwOp::Release, AtomicReadOp::Relaxed)?, #[rustfmt::skip] - "atomic_cxchg_acqrel" => + "atomic_cxchg_acqrel_acquire" => this.atomic_compare_exchange(args, dest, AtomicRwOp::AcqRel, AtomicReadOp::Acquire)?, #[rustfmt::skip] - "atomic_cxchg_relaxed" => + "atomic_cxchg_relaxed_relaxed" => this.atomic_compare_exchange(args, dest, AtomicRwOp::Relaxed, AtomicReadOp::Relaxed)?, #[rustfmt::skip] - "atomic_cxchg_acq_failrelaxed" => + "atomic_cxchg_acquire_relaxed" => this.atomic_compare_exchange(args, dest, AtomicRwOp::Acquire, AtomicReadOp::Relaxed)?, #[rustfmt::skip] - "atomic_cxchg_acqrel_failrelaxed" => + "atomic_cxchg_acqrel_relaxed" => this.atomic_compare_exchange(args, dest, AtomicRwOp::AcqRel, AtomicReadOp::Relaxed)?, #[rustfmt::skip] - "atomic_cxchg_failrelaxed" => + "atomic_cxchg_seqcst_relaxed" => this.atomic_compare_exchange(args, dest, AtomicRwOp::SeqCst, AtomicReadOp::Relaxed)?, #[rustfmt::skip] - "atomic_cxchg_failacq" => + "atomic_cxchg_seqcst_acquire" => this.atomic_compare_exchange(args, dest, AtomicRwOp::SeqCst, AtomicReadOp::Acquire)?, #[rustfmt::skip] - "atomic_cxchgweak" => + "atomic_cxchgweak_seqcst_seqcst" => this.atomic_compare_exchange_weak(args, dest, AtomicRwOp::SeqCst, AtomicReadOp::SeqCst)?, #[rustfmt::skip] - "atomic_cxchgweak_acq" => + "atomic_cxchgweak_acquire_acquire" => this.atomic_compare_exchange_weak(args, dest, AtomicRwOp::Acquire, AtomicReadOp::Acquire)?, #[rustfmt::skip] - "atomic_cxchgweak_rel" => + "atomic_cxchgweak_release_relaxed" => this.atomic_compare_exchange_weak(args, dest, AtomicRwOp::Release, AtomicReadOp::Relaxed)?, #[rustfmt::skip] - "atomic_cxchgweak_acqrel" => + "atomic_cxchgweak_acqrel_acquire" => this.atomic_compare_exchange_weak(args, dest, AtomicRwOp::AcqRel, AtomicReadOp::Acquire)?, #[rustfmt::skip] - "atomic_cxchgweak_relaxed" => + "atomic_cxchgweak_relaxed_relaxed" => this.atomic_compare_exchange_weak(args, dest, AtomicRwOp::Relaxed, AtomicReadOp::Relaxed)?, #[rustfmt::skip] - "atomic_cxchgweak_acq_failrelaxed" => + "atomic_cxchgweak_acquire_relaxed" => this.atomic_compare_exchange_weak(args, dest, AtomicRwOp::Acquire, AtomicReadOp::Relaxed)?, #[rustfmt::skip] - "atomic_cxchgweak_acqrel_failrelaxed" => + "atomic_cxchgweak_acqrel_relaxed" => this.atomic_compare_exchange_weak(args, dest, AtomicRwOp::AcqRel, AtomicReadOp::Relaxed)?, #[rustfmt::skip] - "atomic_cxchgweak_failrelaxed" => + "atomic_cxchgweak_seqcst_relaxed" => this.atomic_compare_exchange_weak(args, dest, AtomicRwOp::SeqCst, AtomicReadOp::Relaxed)?, #[rustfmt::skip] - "atomic_cxchgweak_failacq" => + "atomic_cxchgweak_seqcst_acquire" => this.atomic_compare_exchange_weak(args, dest, AtomicRwOp::SeqCst, AtomicReadOp::Acquire)?, #[rustfmt::skip] - "atomic_or" => + "atomic_or_seqcst" => this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitOr, false), AtomicRwOp::SeqCst)?, #[rustfmt::skip] - "atomic_or_acq" => + "atomic_or_acquire" => this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitOr, false), AtomicRwOp::Acquire)?, #[rustfmt::skip] - "atomic_or_rel" => + "atomic_or_release" => this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitOr, false), AtomicRwOp::Release)?, #[rustfmt::skip] "atomic_or_acqrel" => @@ -961,13 +961,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "atomic_or_relaxed" => this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitOr, false), AtomicRwOp::Relaxed)?, #[rustfmt::skip] - "atomic_xor" => + "atomic_xor_seqcst" => this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitXor, false), AtomicRwOp::SeqCst)?, #[rustfmt::skip] - "atomic_xor_acq" => + "atomic_xor_acquire" => this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitXor, false), AtomicRwOp::Acquire)?, #[rustfmt::skip] - "atomic_xor_rel" => + "atomic_xor_release" => this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitXor, false), AtomicRwOp::Release)?, #[rustfmt::skip] "atomic_xor_acqrel" => @@ -976,13 +976,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "atomic_xor_relaxed" => this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitXor, false), AtomicRwOp::Relaxed)?, #[rustfmt::skip] - "atomic_and" => + "atomic_and_seqcst" => this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitAnd, false), AtomicRwOp::SeqCst)?, #[rustfmt::skip] - "atomic_and_acq" => + "atomic_and_acquire" => this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitAnd, false), AtomicRwOp::Acquire)?, #[rustfmt::skip] - "atomic_and_rel" => + "atomic_and_release" => this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitAnd, false), AtomicRwOp::Release)?, #[rustfmt::skip] "atomic_and_acqrel" => @@ -991,13 +991,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "atomic_and_relaxed" => this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitAnd, false), AtomicRwOp::Relaxed)?, #[rustfmt::skip] - "atomic_nand" => + "atomic_nand_seqcst" => this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitAnd, true), AtomicRwOp::SeqCst)?, #[rustfmt::skip] - "atomic_nand_acq" => + "atomic_nand_acquire" => this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitAnd, true), AtomicRwOp::Acquire)?, #[rustfmt::skip] - "atomic_nand_rel" => + "atomic_nand_release" => this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitAnd, true), AtomicRwOp::Release)?, #[rustfmt::skip] "atomic_nand_acqrel" => @@ -1006,13 +1006,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "atomic_nand_relaxed" => this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitAnd, true), AtomicRwOp::Relaxed)?, #[rustfmt::skip] - "atomic_xadd" => + "atomic_xadd_seqcst" => this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::Add, false), AtomicRwOp::SeqCst)?, #[rustfmt::skip] - "atomic_xadd_acq" => + "atomic_xadd_acquire" => this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::Add, false), AtomicRwOp::Acquire)?, #[rustfmt::skip] - "atomic_xadd_rel" => + "atomic_xadd_release" => this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::Add, false), AtomicRwOp::Release)?, #[rustfmt::skip] "atomic_xadd_acqrel" => @@ -1021,13 +1021,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "atomic_xadd_relaxed" => this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::Add, false), AtomicRwOp::Relaxed)?, #[rustfmt::skip] - "atomic_xsub" => + "atomic_xsub_seqcst" => this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::Sub, false), AtomicRwOp::SeqCst)?, #[rustfmt::skip] - "atomic_xsub_acq" => + "atomic_xsub_acquire" => this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::Sub, false), AtomicRwOp::Acquire)?, #[rustfmt::skip] - "atomic_xsub_rel" => + "atomic_xsub_release" => this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::Sub, false), AtomicRwOp::Release)?, #[rustfmt::skip] "atomic_xsub_acqrel" => @@ -1035,28 +1035,28 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx #[rustfmt::skip] "atomic_xsub_relaxed" => this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::Sub, false), AtomicRwOp::Relaxed)?, - "atomic_min" => this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOp::SeqCst)?, - "atomic_min_acq" => this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOp::Acquire)?, - "atomic_min_rel" => this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOp::Release)?, + "atomic_min_seqcst" => this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOp::SeqCst)?, + "atomic_min_acquire" => this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOp::Acquire)?, + "atomic_min_release" => this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOp::Release)?, "atomic_min_acqrel" => this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOp::AcqRel)?, "atomic_min_relaxed" => this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOp::Relaxed)?, - "atomic_max" => this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOp::SeqCst)?, - "atomic_max_acq" => this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOp::Acquire)?, - "atomic_max_rel" => this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOp::Release)?, + "atomic_max_seqcst" => this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOp::SeqCst)?, + "atomic_max_acquire" => this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOp::Acquire)?, + "atomic_max_release" => this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOp::Release)?, "atomic_max_acqrel" => this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOp::AcqRel)?, "atomic_max_relaxed" => this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOp::Relaxed)?, - "atomic_umin" => this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOp::SeqCst)?, - "atomic_umin_acq" => this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOp::Acquire)?, - "atomic_umin_rel" => this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOp::Release)?, + "atomic_umin_seqcst" => this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOp::SeqCst)?, + "atomic_umin_acquire" => this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOp::Acquire)?, + "atomic_umin_release" => this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOp::Release)?, "atomic_umin_acqrel" => this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOp::AcqRel)?, "atomic_umin_relaxed" => this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOp::Relaxed)?, - "atomic_umax" => this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOp::SeqCst)?, - "atomic_umax_acq" => this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOp::Acquire)?, - "atomic_umax_rel" => this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOp::Release)?, + "atomic_umax_seqcst" => this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOp::SeqCst)?, + "atomic_umax_acquire" => this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOp::Acquire)?, + "atomic_umax_release" => this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOp::Release)?, "atomic_umax_acqrel" => this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOp::AcqRel)?, "atomic_umax_relaxed" => diff --git a/tests/fail/data_race/atomic_read_na_write_race1.rs b/tests/fail/data_race/atomic_read_na_write_race1.rs index 5131e33fef863..5cf2f26bf1f03 100644 --- a/tests/fail/data_race/atomic_read_na_write_race1.rs +++ b/tests/fail/data_race/atomic_read_na_write_race1.rs @@ -1,7 +1,7 @@ // ignore-windows: Concurrency on Windows is not supported yet. #![feature(core_intrinsics)] -use std::intrinsics::atomic_load; +use std::intrinsics; use std::sync::atomic::AtomicUsize; use std::thread::spawn; @@ -22,7 +22,7 @@ pub fn main() { let j2 = spawn(move || { //Equivalent to: (&*c.0).load(Ordering::SeqCst) - atomic_load(c.0 as *mut usize) //~ ERROR Data race detected between Atomic Load on Thread(id = 2) and Write on Thread(id = 1) + intrinsics::atomic_load_seqcst(c.0 as *mut usize) //~ ERROR Data race detected between Atomic Load on Thread(id = 2) and Write on Thread(id = 1) }); j1.join().unwrap(); diff --git a/tests/fail/data_race/atomic_read_na_write_race1.stderr b/tests/fail/data_race/atomic_read_na_write_race1.stderr index 80e79eb553ee9..51cdb239507a5 100644 --- a/tests/fail/data_race/atomic_read_na_write_race1.stderr +++ b/tests/fail/data_race/atomic_read_na_write_race1.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: Data race detected between Atomic Load on Thread(id = 2) and Write on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) --> $DIR/atomic_read_na_write_race1.rs:LL:CC | -LL | atomic_load(c.0 as *mut usize) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Data race detected between Atomic Load on Thread(id = 2) and Write on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) +LL | intrinsics::atomic_load_seqcst(c.0 as *mut usize) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Data race detected between Atomic Load on Thread(id = 2) and Write on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/panic/double_panic.stderr b/tests/fail/panic/double_panic.stderr index 0dbd68c0984f9..c88dfd39e1072 100644 --- a/tests/fail/panic/double_panic.stderr +++ b/tests/fail/panic/double_panic.stderr @@ -75,7 +75,6 @@ LL | ABORT(); = note: inside `std::panicking::rust_panic_with_hook` at RUSTLIB/std/src/panicking.rs:LL:CC = note: inside closure at RUSTLIB/std/src/panicking.rs:LL:CC = note: inside `std::sys_common::backtrace::__rust_end_short_backtrace::<[closure@std::rt::begin_panic<&str>::{closure#0}], !>` at RUSTLIB/std/src/sys_common/backtrace.rs:LL:CC - = note: inside `std::rt::begin_panic::<&str>` at RUSTLIB/std/src/panicking.rs:LL:CC note: inside `::drop` at RUSTLIB/std/src/panic.rs:LL:CC --> $DIR/double_panic.rs:LL:CC | diff --git a/tests/fail/panic/panic_abort1.stderr b/tests/fail/panic/panic_abort1.stderr index 9610a161280a0..808fccaaeca88 100644 --- a/tests/fail/panic/panic_abort1.stderr +++ b/tests/fail/panic/panic_abort1.stderr @@ -12,7 +12,6 @@ LL | ABORT(); = note: inside `std::panicking::rust_panic_with_hook` at RUSTLIB/std/src/panicking.rs:LL:CC = note: inside closure at RUSTLIB/std/src/panicking.rs:LL:CC = note: inside `std::sys_common::backtrace::__rust_end_short_backtrace::<[closure@std::rt::begin_panic<&str>::{closure#0}], !>` at RUSTLIB/std/src/sys_common/backtrace.rs:LL:CC - = note: inside `std::rt::begin_panic::<&str>` at RUSTLIB/std/src/panicking.rs:LL:CC note: inside `main` at RUSTLIB/std/src/panic.rs:LL:CC --> $DIR/panic_abort1.rs:LL:CC | diff --git a/tests/fail/panic/panic_abort2.stderr b/tests/fail/panic/panic_abort2.stderr index 0c446323a7791..9b86dc92f7178 100644 --- a/tests/fail/panic/panic_abort2.stderr +++ b/tests/fail/panic/panic_abort2.stderr @@ -13,7 +13,6 @@ LL | ABORT(); = note: inside closure at RUSTLIB/std/src/panicking.rs:LL:CC = note: inside `std::sys_common::backtrace::__rust_end_short_backtrace::<[closure@std::panicking::begin_panic_handler::{closure#0}], !>` at RUSTLIB/std/src/sys_common/backtrace.rs:LL:CC = note: inside `std::panicking::begin_panic_handler` at RUSTLIB/std/src/panicking.rs:LL:CC - = note: inside `std::rt::panic_fmt` at RUSTLIB/core/src/panicking.rs:LL:CC note: inside `main` at RUSTLIB/std/src/panic.rs:LL:CC --> $DIR/panic_abort2.rs:LL:CC | diff --git a/tests/fail/panic/panic_abort3.stderr b/tests/fail/panic/panic_abort3.stderr index 2d7b576372e08..2bb50d55bfe42 100644 --- a/tests/fail/panic/panic_abort3.stderr +++ b/tests/fail/panic/panic_abort3.stderr @@ -13,8 +13,6 @@ LL | ABORT(); = note: inside closure at RUSTLIB/std/src/panicking.rs:LL:CC = note: inside `std::sys_common::backtrace::__rust_end_short_backtrace::<[closure@std::panicking::begin_panic_handler::{closure#0}], !>` at RUSTLIB/std/src/sys_common/backtrace.rs:LL:CC = note: inside `std::panicking::begin_panic_handler` at RUSTLIB/std/src/panicking.rs:LL:CC - = note: inside `std::rt::panic_fmt` at RUSTLIB/core/src/panicking.rs:LL:CC - = note: inside `core::panicking::panic` at RUSTLIB/core/src/panicking.rs:LL:CC note: inside `main` at RUSTLIB/core/src/panic.rs:LL:CC --> $DIR/panic_abort3.rs:LL:CC | diff --git a/tests/fail/panic/panic_abort4.stderr b/tests/fail/panic/panic_abort4.stderr index b0b11248104d9..8ab5793016120 100644 --- a/tests/fail/panic/panic_abort4.stderr +++ b/tests/fail/panic/panic_abort4.stderr @@ -13,7 +13,6 @@ LL | ABORT(); = note: inside closure at RUSTLIB/std/src/panicking.rs:LL:CC = note: inside `std::sys_common::backtrace::__rust_end_short_backtrace::<[closure@std::panicking::begin_panic_handler::{closure#0}], !>` at RUSTLIB/std/src/sys_common/backtrace.rs:LL:CC = note: inside `std::panicking::begin_panic_handler` at RUSTLIB/std/src/panicking.rs:LL:CC - = note: inside `std::rt::panic_fmt` at RUSTLIB/core/src/panicking.rs:LL:CC note: inside `main` at RUSTLIB/core/src/panic.rs:LL:CC --> $DIR/panic_abort4.rs:LL:CC | diff --git a/tests/fail/unaligned_pointers/atomic_unaligned.rs b/tests/fail/unaligned_pointers/atomic_unaligned.rs index 7e0704ac6fc06..74dd0b415c930 100644 --- a/tests/fail/unaligned_pointers/atomic_unaligned.rs +++ b/tests/fail/unaligned_pointers/atomic_unaligned.rs @@ -7,7 +7,7 @@ fn main() { let z = [0u32; 2]; let zptr = &z as *const _ as *const u64; unsafe { - ::std::intrinsics::atomic_load(zptr); + ::std::intrinsics::atomic_load_seqcst(zptr); //~^ERROR accessing memory with alignment 4, but alignment 8 is required } } diff --git a/tests/fail/unaligned_pointers/atomic_unaligned.stderr b/tests/fail/unaligned_pointers/atomic_unaligned.stderr index f56e6612fb32f..e3b7f4cdbc9a7 100644 --- a/tests/fail/unaligned_pointers/atomic_unaligned.stderr +++ b/tests/fail/unaligned_pointers/atomic_unaligned.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: accessing memory with alignment ALIGN, but alignment ALIGN is required --> $DIR/atomic_unaligned.rs:LL:CC | -LL | ::std::intrinsics::atomic_load(zptr); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ accessing memory with alignment ALIGN, but alignment ALIGN is required +LL | ::std::intrinsics::atomic_load_seqcst(zptr); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ accessing memory with alignment ALIGN, but alignment ALIGN is required | = help: this usually indicates that your program performed an invalid operation and caused Undefined Behavior = help: but due to `-Zmiri-symbolic-alignment-check`, alignment errors can also be false positives From ea8dba411bdfc9d1ea38a2c9b89e91250137ad29 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 29 Jun 2022 09:31:11 -0400 Subject: [PATCH 3354/3747] improve atomics test coverage --- tests/pass/atomic.rs | 38 ++++++++++++++++++++++++++++++++++---- 1 file changed, 34 insertions(+), 4 deletions(-) diff --git a/tests/pass/atomic.rs b/tests/pass/atomic.rs index 9a9e852ecf50f..07b5d5f3d236f 100644 --- a/tests/pass/atomic.rs +++ b/tests/pass/atomic.rs @@ -2,7 +2,7 @@ use std::sync::atomic::{compiler_fence, fence, AtomicBool, AtomicIsize, AtomicU6 fn main() { atomic_bool(); - atomic_isize(); + atomic_all_ops(); atomic_u64(); atomic_fences(); weak_sometimes_fails(); @@ -25,6 +25,7 @@ fn atomic_bool() { assert_eq!(*ATOMIC.get_mut(), false); } } + // There isn't a trait to use to make this generic, so just use a macro macro_rules! compare_exchange_weak_loop { ($atom:expr, $from:expr, $to:expr, $succ_order:expr, $fail_order:expr) => { @@ -39,10 +40,40 @@ macro_rules! compare_exchange_weak_loop { } }; } -fn atomic_isize() { + +/// Make sure we can handle all the intrinsics +fn atomic_all_ops() { static ATOMIC: AtomicIsize = AtomicIsize::new(0); + static ATOMIC_UNSIGNED: AtomicU64 = AtomicU64::new(0); + + + // loads + for o in [Relaxed, Acquire, SeqCst] { + ATOMIC.load(o); + } - // Make sure trans can emit all the intrinsics correctly + // stores + for o in [Relaxed, Release, SeqCst] { + ATOMIC.store(1, o); + } + + // most RMWs + for o in [Relaxed, Release, Acquire, AcqRel, SeqCst] { + ATOMIC.swap(0, o); + ATOMIC.fetch_or(0, o); + ATOMIC.fetch_xor(0, o); + ATOMIC.fetch_and(0, o); + ATOMIC.fetch_nand(0, o); + ATOMIC.fetch_add(0, o); + ATOMIC.fetch_sub(0, o); + ATOMIC.fetch_min(0, o); + ATOMIC.fetch_max(0, o); + ATOMIC_UNSIGNED.fetch_min(0, o); + ATOMIC_UNSIGNED.fetch_max(0, o); + } + + // RMWs with deparate failure ordering + ATOMIC.store(0, SeqCst); assert_eq!(ATOMIC.compare_exchange(0, 1, Relaxed, Relaxed), Ok(0)); assert_eq!(ATOMIC.compare_exchange(0, 2, Acquire, Relaxed), Err(1)); assert_eq!(ATOMIC.compare_exchange(0, 1, Release, Relaxed), Err(1)); @@ -59,7 +90,6 @@ fn atomic_isize() { assert_eq!(ATOMIC.compare_exchange_weak(0, 1, Release, Relaxed), Err(1)); compare_exchange_weak_loop!(ATOMIC, 1, 0, AcqRel, Relaxed); assert_eq!(ATOMIC.load(Relaxed), 0); - ATOMIC.compare_exchange_weak(0, 1, AcqRel, Relaxed).ok(); ATOMIC.compare_exchange_weak(0, 1, SeqCst, Relaxed).ok(); ATOMIC.compare_exchange_weak(0, 1, Acquire, Acquire).ok(); ATOMIC.compare_exchange_weak(0, 1, AcqRel, Acquire).ok(); From f389d46b04c42c3f85ceeb182eabeac94a392b7b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 29 Jun 2022 09:33:12 -0400 Subject: [PATCH 3355/3747] also prune caller_location frames when backtrace=off --- src/diagnostics.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/diagnostics.rs b/src/diagnostics.rs index 95252a1134294..55598c19ef6b7 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -96,6 +96,9 @@ fn prune_stacktrace<'mir, 'tcx>( ) -> (Vec>, bool) { match ecx.machine.backtrace_style { BacktraceStyle::Off => { + // Remove all frames marked with `caller_location` -- that attribute indicates we + // usually want to point at the caller, not them. + stacktrace.retain(|frame| !frame.instance.def.requires_caller_location(*ecx.tcx)); // Retain one frame so that we can print a span for the error itself stacktrace.truncate(1); (stacktrace, false) From 839c120b40bf14cf4dd51b03b0af3ce7eaf0502d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 29 Jun 2022 10:09:18 -0400 Subject: [PATCH 3356/3747] fmt --- src/shims/intrinsics.rs | 39 ++++++++++++++++++++++++++------------- tests/pass/atomic.rs | 1 - 2 files changed, 26 insertions(+), 14 deletions(-) diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index fa5a6e9c273e5..5926832011583 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -877,11 +877,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "atomic_fence_acqrel" => this.atomic_fence(args, AtomicFenceOp::AcqRel)?, "atomic_fence_seqcst" => this.atomic_fence(args, AtomicFenceOp::SeqCst)?, - "atomic_singlethreadfence_acquire" => this.compiler_fence(args, AtomicFenceOp::Acquire)?, - "atomic_singlethreadfence_release" => this.compiler_fence(args, AtomicFenceOp::Release)?, + "atomic_singlethreadfence_acquire" => + this.compiler_fence(args, AtomicFenceOp::Acquire)?, + "atomic_singlethreadfence_release" => + this.compiler_fence(args, AtomicFenceOp::Release)?, "atomic_singlethreadfence_acqrel" => this.compiler_fence(args, AtomicFenceOp::AcqRel)?, - "atomic_singlethreadfence_seqcst" => this.compiler_fence(args, AtomicFenceOp::SeqCst)?, + "atomic_singlethreadfence_seqcst" => + this.compiler_fence(args, AtomicFenceOp::SeqCst)?, "atomic_xchg_seqcst" => this.atomic_exchange(args, dest, AtomicRwOp::SeqCst)?, "atomic_xchg_acquire" => this.atomic_exchange(args, dest, AtomicRwOp::Acquire)?, @@ -1036,27 +1039,37 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "atomic_xsub_relaxed" => this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::Sub, false), AtomicRwOp::Relaxed)?, "atomic_min_seqcst" => this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOp::SeqCst)?, - "atomic_min_acquire" => this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOp::Acquire)?, - "atomic_min_release" => this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOp::Release)?, + "atomic_min_acquire" => + this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOp::Acquire)?, + "atomic_min_release" => + this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOp::Release)?, "atomic_min_acqrel" => this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOp::AcqRel)?, "atomic_min_relaxed" => this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOp::Relaxed)?, "atomic_max_seqcst" => this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOp::SeqCst)?, - "atomic_max_acquire" => this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOp::Acquire)?, - "atomic_max_release" => this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOp::Release)?, + "atomic_max_acquire" => + this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOp::Acquire)?, + "atomic_max_release" => + this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOp::Release)?, "atomic_max_acqrel" => this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOp::AcqRel)?, "atomic_max_relaxed" => this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOp::Relaxed)?, - "atomic_umin_seqcst" => this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOp::SeqCst)?, - "atomic_umin_acquire" => this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOp::Acquire)?, - "atomic_umin_release" => this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOp::Release)?, + "atomic_umin_seqcst" => + this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOp::SeqCst)?, + "atomic_umin_acquire" => + this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOp::Acquire)?, + "atomic_umin_release" => + this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOp::Release)?, "atomic_umin_acqrel" => this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOp::AcqRel)?, "atomic_umin_relaxed" => this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOp::Relaxed)?, - "atomic_umax_seqcst" => this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOp::SeqCst)?, - "atomic_umax_acquire" => this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOp::Acquire)?, - "atomic_umax_release" => this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOp::Release)?, + "atomic_umax_seqcst" => + this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOp::SeqCst)?, + "atomic_umax_acquire" => + this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOp::Acquire)?, + "atomic_umax_release" => + this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOp::Release)?, "atomic_umax_acqrel" => this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOp::AcqRel)?, "atomic_umax_relaxed" => diff --git a/tests/pass/atomic.rs b/tests/pass/atomic.rs index 07b5d5f3d236f..b0c3cc889d556 100644 --- a/tests/pass/atomic.rs +++ b/tests/pass/atomic.rs @@ -46,7 +46,6 @@ fn atomic_all_ops() { static ATOMIC: AtomicIsize = AtomicIsize::new(0); static ATOMIC_UNSIGNED: AtomicU64 = AtomicU64::new(0); - // loads for o in [Relaxed, Acquire, SeqCst] { ATOMIC.load(o); From 6f7c0c0a2ab186a2393acbeac4107390d98e2d82 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 29 Jun 2022 10:14:26 -0400 Subject: [PATCH 3357/3747] revert --color=always changes --- cargo-miri/bin.rs | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index 4d7b7da6634ce..9627adeb2e792 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -952,17 +952,8 @@ fn phase_runner(binary: &Path, binary_args: env::Args, phase: RunnerPhase) { assert!(suffix.starts_with('=')); // Drop this argument. } else if let Some(suffix) = arg.strip_prefix(json_flag) { - let suffix = suffix.strip_prefix('=').unwrap(); - // This is how we pass through --color=always. We detect that Cargo is detecting rustc - // to emit the diagnostic structure that Cargo would consume from rustc to emit colored - // diagnostics, and ask rustc to emit them. - // See https://github.com/rust-lang/miri/issues/2037 - // First skip over the leading `=`, then check for diagnostic-rendered-ansi in the - // comma-separated list - if suffix.split(',').any(|a| a == "diagnostic-rendered-ansi") { - cmd.arg("--color=always"); - } - // But aside from remembering that colored output was requested, drop this argument. + assert!(suffix.starts_with('=')); + // Drop this argument. } else { cmd.arg(arg); } From ad549194f9cb66a884e5a374e1bc491dcdd7f21c Mon Sep 17 00:00:00 2001 From: Christian Legnitto Date: Wed, 29 Jun 2022 13:14:30 -0400 Subject: [PATCH 3358/3747] Update path to passing tests in CONTRIBUTING.md examples This appears to be renamed from `tests/run-pass` to `tests/pass`. --- CONTRIBUTING.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 4def6dc1b691e..ad8bd2a17a6c7 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -60,8 +60,8 @@ generation and linking obviously will have no effect) [and more][miri-flags]. For example, you can (cross-)run the driver on a particular file by doing ```sh -./miri run tests/run-pass/format.rs -./miri run tests/run-pass/hello.rs --target i686-unknown-linux-gnu +./miri run tests/pass/format.rs +./miri run tests/pass/hello.rs --target i686-unknown-linux-gnu ``` and you can (cross-)run the entire test suite using: @@ -79,7 +79,7 @@ You can get a trace of which MIR statements are being executed by setting the `MIRI_LOG` environment variable. For example: ```sh -MIRI_LOG=info ./miri run tests/run-pass/vec.rs +MIRI_LOG=info ./miri run tests/pass/vec.rs ``` Setting `MIRI_LOG` like this will configure logging for Miri itself as well as @@ -88,7 +88,7 @@ can also do more targeted configuration, e.g. the following helps debug the stacked borrows implementation: ```sh -MIRI_LOG=rustc_mir::interpret=info,miri::stacked_borrows ./miri run tests/run-pass/vec.rs +MIRI_LOG=rustc_mir::interpret=info,miri::stacked_borrows ./miri run tests/pass/vec.rs ``` In addition, you can set `MIRI_BACKTRACE=1` to get a backtrace of where an From 73a1a27a450c0a7c0bfcab258230bb3165d9c05c Mon Sep 17 00:00:00 2001 From: Christian Legnitto Date: Wed, 29 Jun 2022 13:30:30 -0400 Subject: [PATCH 3359/3747] Support `gettimeofday` on more than macos This appears to be in linux and in openbsd as well: * https://github.com/torvalds/linux/blob/master/lib/vdso/gettimeofday.c * https://github.com/openbsd/src/blob/master/sys/sys/time.h#L439 Co-authored-by: Ralf Jung --- src/shims/time.rs | 2 +- src/shims/unix/foreign_items.rs | 7 +++++++ src/shims/unix/macos/foreign_items.rs | 5 ----- tests/pass/libc.rs | 22 ++++++++++++++++++++++ 4 files changed, 30 insertions(+), 6 deletions(-) diff --git a/src/shims/time.rs b/src/shims/time.rs index be453a429ec51..0fd5cebd23451 100644 --- a/src/shims/time.rs +++ b/src/shims/time.rs @@ -64,7 +64,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - this.assert_target_os("macos", "gettimeofday"); + this.assert_target_os_is_unix("gettimeofday"); this.check_no_isolation("`gettimeofday`")?; // Using tz is obsolete and should always be null diff --git a/src/shims/unix/foreign_items.rs b/src/shims/unix/foreign_items.rs index d0c93ef4cdaf3..4a452800044ff 100644 --- a/src/shims/unix/foreign_items.rs +++ b/src/shims/unix/foreign_items.rs @@ -139,6 +139,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_machine_isize(result, this), dest)?; } + // Time related shims + "gettimeofday" => { + let [tv, tz] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let result = this.gettimeofday(tv, tz)?; + this.write_scalar(Scalar::from_i32(result), dest)?; + } + // Allocation "posix_memalign" => { let [ret, align, size] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; diff --git a/src/shims/unix/macos/foreign_items.rs b/src/shims/unix/macos/foreign_items.rs index f7dd38f639b0a..e545a4691bf04 100644 --- a/src/shims/unix/macos/foreign_items.rs +++ b/src/shims/unix/macos/foreign_items.rs @@ -78,11 +78,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // Time related shims - "gettimeofday" => { - let [tv, tz] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; - let result = this.gettimeofday(tv, tz)?; - this.write_scalar(Scalar::from_i32(result), dest)?; - } "mach_absolute_time" => { let [] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.mach_absolute_time()?; diff --git a/tests/pass/libc.rs b/tests/pass/libc.rs index e73e796449cc5..b108a01dae37e 100644 --- a/tests/pass/libc.rs +++ b/tests/pass/libc.rs @@ -290,10 +290,32 @@ fn test_clocks() { assert_eq!(is_error, 0); } +fn test_posix_gettimeofday() { + let mut tp = std::mem::MaybeUninit::::uninit(); + let tz = std::ptr::null_mut::(); + #[cfg(target_os = "macos")] // `tz` has a different type on macOS + let tz = tz as *mut libc::c_void; + let is_error = unsafe { libc::gettimeofday(tp.as_mut_ptr(), tz) }; + assert_eq!(is_error, 0); + let tv = unsafe { tp.assume_init() }; + assert!(tv.tv_sec > 0); + assert!(tv.tv_usec >= 0); // Theoretically this could be 0. + + // Test that non-null tz returns an error. + let mut tz = std::mem::MaybeUninit::::uninit(); + let tz_ptr = tz.as_mut_ptr(); + #[cfg(target_os = "macos")] // `tz` has a different type on macOS + let tz_ptr = tz_ptr as *mut libc::c_void; + let is_error = unsafe { libc::gettimeofday(tp.as_mut_ptr(), tz_ptr) }; + assert_eq!(is_error, -1); +} + fn main() { #[cfg(any(target_os = "linux", target_os = "freebsd"))] test_posix_fadvise(); + test_posix_gettimeofday(); + #[cfg(any(target_os = "linux", target_os = "freebsd"))] test_sync_file_range(); From 02f8cb2d551d06e24b4072c6caf1bf0e129f2eba Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 29 Jun 2022 18:14:41 -0400 Subject: [PATCH 3360/3747] add ./miri clippy --- .github/workflows/ci.yml | 8 ++------ miri | 8 ++++++++ rustup-toolchain | 2 +- 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c603d1f5d2549..7d6e39dc31b26 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -98,12 +98,8 @@ jobs: ./rustup-toolchain "" -c clippy - name: rustfmt run: ./miri fmt --check - - name: clippy (miri) - run: cargo clippy --all-targets -- -D warnings - #- name: Clippy (ui_test) - # run: cargo clippy --manifest-path ui_test/Cargo.toml --all-targets -- -D warnings - - name: clippy (cargo-miri) - run: cargo clippy --manifest-path cargo-miri/Cargo.toml --all-targets -- -D warnings + - name: clippy + run: ./miri clippy -- -D warnings - name: rustdoc run: RUSTDOCFLAGS="-Dwarnings" cargo doc --document-private-items diff --git a/miri b/miri index e89a9e380fff6..4dd34e0ef6c5b 100755 --- a/miri +++ b/miri @@ -28,6 +28,9 @@ times and slower execution times. ./miri fmt : Format all sources and tests. are passed to `rustfmt`. +./miri clippy : +Format all sources and tests. are passed to `cargo clippy`. + ENVIRONMENT VARIABLES MIRI_SYSROOT: @@ -163,6 +166,11 @@ fmt) find "$MIRIDIR" -not \( -name target -prune \) -name '*.rs' \ | xargs rustfmt --edition=2021 --config-path "$MIRIDIR/rustfmt.toml" "$@" ;; +clippy) + cargo clippy $CARGO_BUILD_FLAGS --manifest-path "$MIRIDIR"/Cargo.toml --all-targets "$@" + #cargo clippy $CARGO_BUILD_FLAGS --manifest-path "$MIRIDIR"/ui_test/Cargo.toml --all-targets "$@" + cargo clippy $CARGO_BUILD_FLAGS --manifest-path "$MIRIDIR"/cargo-miri/Cargo.toml "$@" + ;; *) if [ -n "$COMMAND" ]; then echo "Unknown command: $COMMAND" diff --git a/rustup-toolchain b/rustup-toolchain index 34472c727f62f..7b9a17145d055 100755 --- a/rustup-toolchain +++ b/rustup-toolchain @@ -42,7 +42,7 @@ fi # Install and setup new toolchain. rustup toolchain uninstall miri -rustup-toolchain-install-master -n miri -c cargo -c rust-src -c rustc-dev -c llvm-tools -c rustfmt "$@" -- "$NEW_COMMIT" +rustup-toolchain-install-master -n miri -c cargo -c rust-src -c rustc-dev -c llvm-tools -c rustfmt -c clippy "$@" -- "$NEW_COMMIT" rustup override set miri # Cleanup. From e33efc75171ca48dfcd30984dfc356cdbfc5c1e4 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 29 Jun 2022 18:17:28 -0400 Subject: [PATCH 3361/3747] make ui_test pass clippy --- miri | 2 +- ui_test/src/comments.rs | 2 +- ui_test/src/lib.rs | 8 +++++--- ui_test/src/rustc_stderr.rs | 6 +++--- ui_test/src/tests.rs | 2 +- 5 files changed, 11 insertions(+), 9 deletions(-) diff --git a/miri b/miri index 4dd34e0ef6c5b..6b7e9dbf03f89 100755 --- a/miri +++ b/miri @@ -168,7 +168,7 @@ fmt) ;; clippy) cargo clippy $CARGO_BUILD_FLAGS --manifest-path "$MIRIDIR"/Cargo.toml --all-targets "$@" - #cargo clippy $CARGO_BUILD_FLAGS --manifest-path "$MIRIDIR"/ui_test/Cargo.toml --all-targets "$@" + cargo clippy $CARGO_BUILD_FLAGS --manifest-path "$MIRIDIR"/ui_test/Cargo.toml --all-targets "$@" cargo clippy $CARGO_BUILD_FLAGS --manifest-path "$MIRIDIR"/cargo-miri/Cargo.toml "$@" ;; *) diff --git a/ui_test/src/comments.rs b/ui_test/src/comments.rs index 43c687e9c9a50..e7b4968a9ca62 100644 --- a/ui_test/src/comments.rs +++ b/ui_test/src/comments.rs @@ -90,7 +90,7 @@ impl Comments { path.display() ); this.revisions = - Some(revisions.trim().split_whitespace().map(|s| s.to_string()).collect()); + Some(revisions.split_whitespace().map(|s| s.to_string()).collect()); } if let Some(s) = line.strip_prefix("// ignore-") { let s = s diff --git a/ui_test/src/lib.rs b/ui_test/src/lib.rs index 30e1296f7b396..ff0c4e1c8996b 100644 --- a/ui_test/src/lib.rs +++ b/ui_test/src/lib.rs @@ -1,3 +1,5 @@ +#![allow(clippy::enum_variant_names, clippy::useless_format, clippy::too_many_arguments)] + use std::collections::VecDeque; use std::fmt::Write; use std::path::{Path, PathBuf}; @@ -338,17 +340,17 @@ fn check_test_result( revised("stderr"), target, &config.stderr_filters, - &config, + config, comments, ); check_output( - &stdout, + stdout, path, errors, revised("stdout"), target, &config.stdout_filters, - &config, + config, comments, ); // Check error annotations in the source against output diff --git a/ui_test/src/rustc_stderr.rs b/ui_test/src/rustc_stderr.rs index 2d3845752e9a5..ea32ce4bd2934 100644 --- a/ui_test/src/rustc_stderr.rs +++ b/ui_test/src/rustc_stderr.rs @@ -117,16 +117,16 @@ impl Span { pub(crate) fn filter_annotations_from_rendered(rendered: &str) -> std::borrow::Cow<'_, str> { let annotations = Regex::new(r"\s*//(\[[^\]]\])?~.*").unwrap(); - annotations.replace_all(&rendered, "") + annotations.replace_all(rendered, "") } pub(crate) fn process(file: &Path, stderr: &[u8]) -> Diagnostics { - let stderr = std::str::from_utf8(&stderr).unwrap(); + let stderr = std::str::from_utf8(stderr).unwrap(); let mut rendered = String::new(); let mut messages = vec![]; let mut messages_from_unknown_file_or_line = vec![]; for line in stderr.lines() { - if line.starts_with("{") { + if line.starts_with('{') { match serde_json::from_str::(line) { Ok(msg) => { write!( diff --git a/ui_test/src/tests.rs b/ui_test/src/tests.rs index 7e08a68be7b9a..a45f8f8933c90 100644 --- a/ui_test/src/tests.rs +++ b/ui_test/src/tests.rs @@ -29,7 +29,7 @@ fn main() { } "; let path = Path::new("$DIR/"); - let comments = Comments::parse(&path, s); + let comments = Comments::parse(path, s); let mut errors = vec![]; let config = config(); let messages = vec![ From c4e86e103ec7e7c70376d178369eff084db8d237 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 29 Jun 2022 17:53:09 -0400 Subject: [PATCH 3362/3747] add option for recursive field retagging --- README.md | 3 + rust-version | 2 +- src/bin/miri.rs | 2 + src/eval.rs | 3 + src/machine.rs | 1 + src/stacked_borrows.rs | 69 +++++++++++++++++-- .../fail/stacked_borrows/newtype_retagging.rs | 19 +++++ .../stacked_borrows/newtype_retagging.stderr | 50 ++++++++++++++ .../stacked-borrows/interior_mutability.rs | 1 + tests/pass/stacked-borrows/refcell.rs | 1 + tests/pass/stacked-borrows/stacked-borrows.rs | 1 + 11 files changed, 146 insertions(+), 6 deletions(-) create mode 100644 tests/fail/stacked_borrows/newtype_retagging.rs create mode 100644 tests/fail/stacked_borrows/newtype_retagging.stderr diff --git a/README.md b/README.md index a7ee11e82e0f0..bfc32d04a9d14 100644 --- a/README.md +++ b/README.md @@ -369,6 +369,9 @@ to Miri failing to detect cases of undefined behavior in a program. application instead of raising an error within the context of Miri (and halting execution). Note that code might not expect these operations to ever panic, so this flag can lead to strange (mis)behavior. +* `-Zmiri-retag-fields` changes Stacked Borrows retagging to recurse into fields. + This means that references in fields of structs/enums/tuples/arrays/... are retagged, + and in particular, they are protected when passed as function arguments. * `-Zmiri-track-alloc-id=,,...` shows a backtrace when the given allocations are being allocated or freed. This helps in debugging memory leaks and use after free bugs. Specifying this argument multiple times does not overwrite the previous diff --git a/rust-version b/rust-version index 4f24d29e34b48..323af716826d9 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -493c960a3e6cdd2e2fbe8b6ea130fadea05f1ab0 +ddcbba036aee08f0709f98a92a342a278eae5c05 diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 1ccc54d6be196..4f00e4be18ab4 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -383,6 +383,8 @@ fn main() { miri_config.provenance_mode = ProvenanceMode::Permissive; } else if arg == "-Zmiri-mute-stdout-stderr" { miri_config.mute_stdout_stderr = true; + } else if arg == "-Zmiri-retag-fields" { + miri_config.retag_fields = true; } else if arg == "-Zmiri-track-raw-pointers" { eprintln!( "WARNING: `-Zmiri-track-raw-pointers` has no effect; it is enabled by default" diff --git a/src/eval.rs b/src/eval.rs index 12f1f52c78a33..c9fc05500a3c6 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -124,6 +124,8 @@ pub struct MiriConfig { pub preemption_rate: f64, /// Report the current instruction being executed every N basic blocks. pub report_progress: Option, + /// Whether Stacked Borrows retagging should recurse into fields of datatypes. + pub retag_fields: bool, } impl Default for MiriConfig { @@ -154,6 +156,7 @@ impl Default for MiriConfig { mute_stdout_stderr: false, preemption_rate: 0.01, // 1% report_progress: None, + retag_fields: false, } } } diff --git a/src/machine.rs b/src/machine.rs index 5b18475458975..4aeb42d3d0fe3 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -354,6 +354,7 @@ impl<'mir, 'tcx> Evaluator<'mir, 'tcx> { Some(RefCell::new(stacked_borrows::GlobalStateInner::new( config.tracked_pointer_tags.clone(), config.tracked_call_ids.clone(), + config.retag_fields, ))) } else { None diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 66f756d7b08d4..3fc0eaf10c094 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -156,6 +156,8 @@ pub struct GlobalStateInner { tracked_pointer_tags: HashSet, /// The call ids to trace tracked_call_ids: HashSet, + /// Whether to recurse into datatypes when searching for pointers to retag. + retag_fields: bool, } /// We need interior mutable access to the global state. @@ -204,7 +206,11 @@ impl fmt::Display for RefKind { /// Utilities for initialization and ID generation impl GlobalStateInner { - pub fn new(tracked_pointer_tags: HashSet, tracked_call_ids: HashSet) -> Self { + pub fn new( + tracked_pointer_tags: HashSet, + tracked_call_ids: HashSet, + retag_fields: bool, + ) -> Self { GlobalStateInner { next_ptr_tag: SbTag(NonZeroU64::new(1).unwrap()), base_ptr_tags: FxHashMap::default(), @@ -212,6 +218,7 @@ impl GlobalStateInner { active_calls: FxHashSet::default(), tracked_pointer_tags, tracked_call_ids, + retag_fields, } } @@ -1035,17 +1042,69 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } - // We only reborrow "bare" references/boxes. - // Not traversing into fields helps with , - // but might also cost us optimization and analyses. We will have to experiment more with this. + // We need a visitor to visit all references. However, that requires + // a `MPlaceTy` (or `OpTy), so we have a fast path for reference types that + // avoids allocating. + if let Some((mutbl, protector)) = qualify(place.layout.ty, kind) { // Fast path. let val = this.read_immediate(&this.place_to_op(place)?)?; let val = this.retag_reference(&val, mutbl, protector)?; this.write_immediate(*val, place)?; + return Ok(()); } - Ok(()) + // If we don't want to recurse, we are already done. + if !this.machine.stacked_borrows.as_mut().unwrap().get_mut().retag_fields { + return Ok(()); + } + + // Skip some types that have no further structure we might care about. + if matches!( + place.layout.ty.kind(), + ty::RawPtr(..) + | ty::Ref(..) + | ty::Int(..) + | ty::Uint(..) + | ty::Float(..) + | ty::Bool + | ty::Char + ) { + return Ok(()); + } + // Now go visit this thing. + let place = this.force_allocation(place)?; + + let mut visitor = RetagVisitor { ecx: this, kind }; + return visitor.visit_value(&place); + + // The actual visitor. + struct RetagVisitor<'ecx, 'mir, 'tcx> { + ecx: &'ecx mut MiriEvalContext<'mir, 'tcx>, + kind: RetagKind, + } + impl<'ecx, 'mir, 'tcx> MutValueVisitor<'mir, 'tcx, Evaluator<'mir, 'tcx>> + for RetagVisitor<'ecx, 'mir, 'tcx> + { + type V = MPlaceTy<'tcx, Tag>; + + #[inline(always)] + fn ecx(&mut self) -> &mut MiriEvalContext<'mir, 'tcx> { + &mut self.ecx + } + + fn visit_value(&mut self, place: &MPlaceTy<'tcx, Tag>) -> InterpResult<'tcx> { + if let Some((mutbl, protector)) = qualify(place.layout.ty, self.kind) { + let val = self.ecx.read_immediate(&place.into())?; + let val = self.ecx.retag_reference(&val, mutbl, protector)?; + self.ecx.write_immediate(*val, &(*place).into())?; + } else { + // Maybe we need to go deeper. + self.walk_value(place)?; + } + Ok(()) + } + } } /// After a stack frame got pushed, retag the return place so that we are sure diff --git a/tests/fail/stacked_borrows/newtype_retagging.rs b/tests/fail/stacked_borrows/newtype_retagging.rs new file mode 100644 index 0000000000000..8f932f08086ac --- /dev/null +++ b/tests/fail/stacked_borrows/newtype_retagging.rs @@ -0,0 +1,19 @@ +// compile-flags: -Zmiri-retag-fields +// error-pattern: incompatible item is protected +struct Newtype<'a>(&'a mut i32); + +fn dealloc_while_running(_n: Newtype<'_>, dealloc: impl FnOnce()) { + dealloc(); +} + +// Make sure that we protect references inside structs. +fn main() { + let ptr = Box::into_raw(Box::new(0i32)); + #[rustfmt::skip] // I like my newlines + unsafe { + dealloc_while_running( + Newtype(&mut *ptr), + || drop(Box::from_raw(ptr)), + ) + }; +} diff --git a/tests/fail/stacked_borrows/newtype_retagging.stderr b/tests/fail/stacked_borrows/newtype_retagging.stderr new file mode 100644 index 0000000000000..f65231b661f97 --- /dev/null +++ b/tests/fail/stacked_borrows/newtype_retagging.stderr @@ -0,0 +1,50 @@ +error: Undefined Behavior: not granting access to tag because incompatible item is protected: [Unique for (call ID)] + --> RUSTLIB/alloc/src/boxed.rs:LL:CC + | +LL | Box(unsafe { Unique::new_unchecked(raw) }, alloc) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not granting access to tag because incompatible item is protected: [Unique for (call ID)] + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information +help: was created by a retag at offsets [0x0..0x4] + --> $DIR/newtype_retagging.rs:LL:CC + | +LL | let ptr = Box::into_raw(Box::new(0i32)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: was protected due to which was created here + --> $DIR/newtype_retagging.rs:LL:CC + | +LL | Newtype(&mut *ptr), + | ^^^^^^^^^^^^^^^^^^ +help: this protector is live for this call + --> $DIR/newtype_retagging.rs:LL:CC + | +LL | / fn dealloc_while_running(_n: Newtype<'_>, dealloc: impl FnOnce()) { +LL | | dealloc(); +LL | | } + | |_^ + = note: inside `std::boxed::Box::::from_raw_in` at RUSTLIB/alloc/src/boxed.rs:LL:CC + = note: inside `std::boxed::Box::::from_raw` at RUSTLIB/alloc/src/boxed.rs:LL:CC +note: inside closure at $DIR/newtype_retagging.rs:LL:CC + --> $DIR/newtype_retagging.rs:LL:CC + | +LL | || drop(Box::from_raw(ptr)), + | ^^^^^^^^^^^^^^^^^^ +note: inside `dealloc_while_running::<[closure@$DIR/newtype_retagging.rs:LL:CC]>` at $DIR/newtype_retagging.rs:LL:CC + --> $DIR/newtype_retagging.rs:LL:CC + | +LL | dealloc(); + | ^^^^^^^^^ +note: inside `main` at $DIR/newtype_retagging.rs:LL:CC + --> $DIR/newtype_retagging.rs:LL:CC + | +LL | / dealloc_while_running( +LL | | Newtype(&mut *ptr), +LL | | || drop(Box::from_raw(ptr)), +LL | | ) + | |_________^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/pass/stacked-borrows/interior_mutability.rs b/tests/pass/stacked-borrows/interior_mutability.rs index 79958ab5539d4..6ac364b716c55 100644 --- a/tests/pass/stacked-borrows/interior_mutability.rs +++ b/tests/pass/stacked-borrows/interior_mutability.rs @@ -1,3 +1,4 @@ +// compile-flags: -Zmiri-retag-fields use std::cell::{Cell, RefCell, UnsafeCell}; use std::mem::{self, MaybeUninit}; diff --git a/tests/pass/stacked-borrows/refcell.rs b/tests/pass/stacked-borrows/refcell.rs index ecb6f48d30b07..e9d7f67152880 100644 --- a/tests/pass/stacked-borrows/refcell.rs +++ b/tests/pass/stacked-borrows/refcell.rs @@ -1,3 +1,4 @@ +// compile-flags: -Zmiri-retag-fields use std::cell::{Ref, RefCell, RefMut}; fn main() { diff --git a/tests/pass/stacked-borrows/stacked-borrows.rs b/tests/pass/stacked-borrows/stacked-borrows.rs index eb0ff167eb123..3669a08a1bc4b 100644 --- a/tests/pass/stacked-borrows/stacked-borrows.rs +++ b/tests/pass/stacked-borrows/stacked-borrows.rs @@ -1,3 +1,4 @@ +// compile-flags: -Zmiri-retag-fields use std::ptr; // Test various stacked-borrows-related things. From 955f961f8327926477ea906a7f4140d5b9dbfa45 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 29 Jun 2022 17:56:47 -0400 Subject: [PATCH 3363/3747] merge two SB test files --- .../stacked-borrows/interior_mutability.rs | 75 +++++++++++++++++- tests/pass/stacked-borrows/refcell.rs | 78 ------------------- 2 files changed, 74 insertions(+), 79 deletions(-) delete mode 100644 tests/pass/stacked-borrows/refcell.rs diff --git a/tests/pass/stacked-borrows/interior_mutability.rs b/tests/pass/stacked-borrows/interior_mutability.rs index 6ac364b716c55..96ad67505a73e 100644 --- a/tests/pass/stacked-borrows/interior_mutability.rs +++ b/tests/pass/stacked-borrows/interior_mutability.rs @@ -1,5 +1,5 @@ // compile-flags: -Zmiri-retag-fields -use std::cell::{Cell, RefCell, UnsafeCell}; +use std::cell::{Cell, Ref, RefCell, RefMut, UnsafeCell}; use std::mem::{self, MaybeUninit}; fn main() { @@ -9,6 +9,10 @@ fn main() { unsafe_cell_2phase(); unsafe_cell_deallocate(); unsafe_cell_invalidate(); + refcell_basic(); + ref_protector(); + ref_mut_protector(); + rust_issue_68303(); } fn aliasing_mut_and_shr() { @@ -100,3 +104,72 @@ fn unsafe_cell_invalidate() { // So using raw1 invalidates raw2. f(unsafe { mem::transmute(raw2) }, raw1); } + +fn refcell_basic() { + let c = RefCell::new(42); + { + let s1 = c.borrow(); + let _x: i32 = *s1; + let s2 = c.borrow(); + let _x: i32 = *s1; + let _y: i32 = *s2; + let _x: i32 = *s1; + let _y: i32 = *s2; + } + { + let mut m = c.borrow_mut(); + let _z: i32 = *m; + { + let s: &i32 = &*m; + let _x = *s; + } + *m = 23; + let _z: i32 = *m; + } + { + let s1 = c.borrow(); + let _x: i32 = *s1; + let s2 = c.borrow(); + let _x: i32 = *s1; + let _y: i32 = *s2; + let _x: i32 = *s1; + let _y: i32 = *s2; + } +} + +// Adding a Stacked Borrows protector for `Ref` would break this +fn ref_protector() { + fn break_it(rc: &RefCell, r: Ref<'_, i32>) { + // `r` has a shared reference, it is passed in as argument and hence + // a protector is added that marks this memory as read-only for the entire + // duration of this function. + drop(r); + // *oops* here we can mutate that memory. + *rc.borrow_mut() = 2; + } + + let rc = RefCell::new(0); + break_it(&rc, rc.borrow()) +} + +fn ref_mut_protector() { + fn break_it(rc: &RefCell, r: RefMut<'_, i32>) { + // `r` has a shared reference, it is passed in as argument and hence + // a protector is added that marks this memory as inaccessible for the entire + // duration of this function + drop(r); + // *oops* here we can mutate that memory. + *rc.borrow_mut() = 2; + } + + let rc = RefCell::new(0); + break_it(&rc, rc.borrow_mut()) +} + +/// Make sure we do not have bad enum layout optimizations. +fn rust_issue_68303() { + let optional = Some(RefCell::new(false)); + let mut handle = optional.as_ref().unwrap().borrow_mut(); + assert!(optional.is_some()); + *handle = true; +} diff --git a/tests/pass/stacked-borrows/refcell.rs b/tests/pass/stacked-borrows/refcell.rs deleted file mode 100644 index e9d7f67152880..0000000000000 --- a/tests/pass/stacked-borrows/refcell.rs +++ /dev/null @@ -1,78 +0,0 @@ -// compile-flags: -Zmiri-retag-fields -use std::cell::{Ref, RefCell, RefMut}; - -fn main() { - basic(); - ref_protector(); - ref_mut_protector(); - rust_issue_68303(); -} - -fn basic() { - let c = RefCell::new(42); - { - let s1 = c.borrow(); - let _x: i32 = *s1; - let s2 = c.borrow(); - let _x: i32 = *s1; - let _y: i32 = *s2; - let _x: i32 = *s1; - let _y: i32 = *s2; - } - { - let mut m = c.borrow_mut(); - let _z: i32 = *m; - { - let s: &i32 = &*m; - let _x = *s; - } - *m = 23; - let _z: i32 = *m; - } - { - let s1 = c.borrow(); - let _x: i32 = *s1; - let s2 = c.borrow(); - let _x: i32 = *s1; - let _y: i32 = *s2; - let _x: i32 = *s1; - let _y: i32 = *s2; - } -} - -// Adding a Stacked Borrows protector for `Ref` would break this -fn ref_protector() { - fn break_it(rc: &RefCell, r: Ref<'_, i32>) { - // `r` has a shared reference, it is passed in as argument and hence - // a protector is added that marks this memory as read-only for the entire - // duration of this function. - drop(r); - // *oops* here we can mutate that memory. - *rc.borrow_mut() = 2; - } - - let rc = RefCell::new(0); - break_it(&rc, rc.borrow()) -} - -fn ref_mut_protector() { - fn break_it(rc: &RefCell, r: RefMut<'_, i32>) { - // `r` has a shared reference, it is passed in as argument and hence - // a protector is added that marks this memory as inaccessible for the entire - // duration of this function - drop(r); - // *oops* here we can mutate that memory. - *rc.borrow_mut() = 2; - } - - let rc = RefCell::new(0); - break_it(&rc, rc.borrow_mut()) -} - -/// Make sure we do not have bad enum layout optimizations. -fn rust_issue_68303() { - let optional = Some(RefCell::new(false)); - let mut handle = optional.as_ref().unwrap().borrow_mut(); - assert!(optional.is_some()); - *handle = true; -} From a2e61aeeff0b5522eb8929a60326d0191f168f39 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 29 Jun 2022 21:31:27 -0400 Subject: [PATCH 3364/3747] rustup --- rust-version | 2 +- tests/fail/branchless-select-i128-pointer.rs | 2 +- tests/fail/branchless-select-i128-pointer.stderr | 4 ++-- tests/fail/issue-miri-1112.stderr | 4 ++-- tests/fail/stacked_borrows/vtable.stderr | 4 ++-- tests/fail/transmute-pair-uninit.stderr | 4 ++-- tests/fail/transmute_fat1.rs | 2 +- tests/fail/transmute_fat1.stderr | 4 ++-- tests/fail/uninit_byte_read.stderr | 4 ++-- tests/fail/uninit_raw_ptr.rs | 2 +- tests/fail/uninit_raw_ptr.stderr | 4 ++-- tests/fail/validity/cast_fn_ptr1.stderr | 4 ++-- tests/fail/validity/cast_fn_ptr2.stderr | 4 ++-- tests/fail/validity/dangling_ref1.stderr | 4 ++-- tests/fail/validity/dangling_ref2.stderr | 4 ++-- tests/fail/validity/dangling_ref3.stderr | 4 ++-- tests/fail/validity/invalid_bool.stderr | 4 ++-- tests/fail/validity/invalid_bool_uninit.stderr | 4 ++-- tests/fail/validity/invalid_char.stderr | 4 ++-- tests/fail/validity/invalid_char_uninit.stderr | 4 ++-- tests/fail/validity/invalid_enum_tag.rs | 2 +- tests/fail/validity/invalid_enum_tag.stderr | 6 +++--- tests/fail/validity/invalid_enum_tag_256variants_uninit.rs | 2 +- .../validity/invalid_enum_tag_256variants_uninit.stderr | 4 ++-- tests/fail/validity/invalid_fnptr_null.stderr | 4 ++-- tests/fail/validity/invalid_fnptr_uninit.stderr | 4 ++-- tests/fail/validity/invalid_wide_raw.stderr | 4 ++-- tests/fail/validity/nonzero.stderr | 4 ++-- tests/fail/validity/ptr_integer_array_transmute.stderr | 4 ++-- tests/fail/validity/ref_to_uninhabited1.stderr | 4 ++-- tests/fail/validity/ref_to_uninhabited2.stderr | 4 ++-- tests/fail/validity/too-big-slice.stderr | 4 ++-- tests/fail/validity/too-big-unsized.stderr | 4 ++-- tests/fail/validity/transmute_through_ptr.rs | 2 +- tests/fail/validity/transmute_through_ptr.stderr | 4 ++-- tests/fail/validity/uninit_float.rs | 2 +- tests/fail/validity/uninit_float.stderr | 4 ++-- tests/fail/validity/uninit_integer.rs | 2 +- tests/fail/validity/uninit_integer.stderr | 4 ++-- tests/fail/validity/uninit_integer_signed.rs | 2 +- tests/fail/validity/uninit_integer_signed.stderr | 4 ++-- 41 files changed, 73 insertions(+), 73 deletions(-) diff --git a/rust-version b/rust-version index 323af716826d9..1ab8e6b5a8cea 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -ddcbba036aee08f0709f98a92a342a278eae5c05 +bf45371f262e184b4a77adea88c8ac01ac79759b diff --git a/tests/fail/branchless-select-i128-pointer.rs b/tests/fail/branchless-select-i128-pointer.rs index 7e1b969e02cf6..a3b4021ba0c2a 100644 --- a/tests/fail/branchless-select-i128-pointer.rs +++ b/tests/fail/branchless-select-i128-pointer.rs @@ -12,7 +12,7 @@ fn main() { // However, it drops provenance when transmuting to TwoPtrs, so this is UB. let val = unsafe { transmute::<_, &str>( - //~^ ERROR type validation failed: encountered a dangling reference + //~^ ERROR constructing invalid value: encountered a dangling reference !mask & transmute::<_, TwoPtrs>("false !") | mask & transmute::<_, TwoPtrs>("true !"), ) diff --git a/tests/fail/branchless-select-i128-pointer.stderr b/tests/fail/branchless-select-i128-pointer.stderr index 374d6ab068091..5cb05f33ddea3 100644 --- a/tests/fail/branchless-select-i128-pointer.stderr +++ b/tests/fail/branchless-select-i128-pointer.stderr @@ -1,4 +1,4 @@ -error: Undefined Behavior: type validation failed: encountered a dangling reference (address $HEX is unallocated) +error: Undefined Behavior: constructing invalid value: encountered a dangling reference (address $HEX is unallocated) --> $DIR/branchless-select-i128-pointer.rs:LL:CC | LL | / transmute::<_, &str>( @@ -6,7 +6,7 @@ LL | | LL | | !mask & transmute::<_, TwoPtrs>("false !") LL | | | mask & transmute::<_, TwoPtrs>("true !"), LL | | ) - | |_____________^ type validation failed: encountered a dangling reference (address $HEX is unallocated) + | |_____________^ constructing invalid value: encountered a dangling reference (address $HEX is unallocated) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/issue-miri-1112.stderr b/tests/fail/issue-miri-1112.stderr index 1dfcad0c147b4..cf692bddaf44d 100644 --- a/tests/fail/issue-miri-1112.stderr +++ b/tests/fail/issue-miri-1112.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: type validation failed: encountered invalid drop function pointer in vtable (function has incompatible signature) +error: Undefined Behavior: constructing invalid value: encountered invalid drop function pointer in vtable (function has incompatible signature) --> $DIR/issue-miri-1112.rs:LL:CC | LL | let obj = std::mem::transmute::(obj); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered invalid drop function pointer in vtable (function has incompatible signature) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered invalid drop function pointer in vtable (function has incompatible signature) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/stacked_borrows/vtable.stderr b/tests/fail/stacked_borrows/vtable.stderr index ac3d71045f0cc..31c3d5982e5ea 100644 --- a/tests/fail/stacked_borrows/vtable.stderr +++ b/tests/fail/stacked_borrows/vtable.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: type validation failed: encountered vtable pointer does not have permission to read drop function pointer +error: Undefined Behavior: constructing invalid value: encountered vtable pointer does not have permission to read drop function pointer --> RUSTLIB/core/src/ptr/metadata.rs:LL:CC | LL | unsafe { PtrRepr { components: PtrComponents { data_address, metadata } }.const_ptr } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered vtable pointer does not have permission to read drop function pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered vtable pointer does not have permission to read drop function pointer | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/transmute-pair-uninit.stderr b/tests/fail/transmute-pair-uninit.stderr index 833c3abbb2fb1..c1f90c3efb6eb 100644 --- a/tests/fail/transmute-pair-uninit.stderr +++ b/tests/fail/transmute-pair-uninit.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: type validation failed: encountered uninitialized bytes, but expected initialized bytes +error: Undefined Behavior: constructing invalid value: encountered uninitialized bytes, but expected initialized bytes --> $DIR/transmute-pair-uninit.rs:LL:CC | LL | let v = unsafe { *z.offset(first_undef) }; - | ^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized bytes, but expected initialized bytes + | ^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered uninitialized bytes, but expected initialized bytes | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/transmute_fat1.rs b/tests/fail/transmute_fat1.rs index 79286f3e27dd8..a60efb98f9d87 100644 --- a/tests/fail/transmute_fat1.rs +++ b/tests/fail/transmute_fat1.rs @@ -7,7 +7,7 @@ const N: usize = 8; fn main() { let bad = unsafe { std::mem::transmute::<&[u8], [u8; N]>(&[1u8]) - //~^ ERROR: type validation failed: encountered a pointer + //~^ ERROR: constructing invalid value: encountered a pointer }; let _val = bad[0] + bad[bad.len() - 1]; } diff --git a/tests/fail/transmute_fat1.stderr b/tests/fail/transmute_fat1.stderr index baf6195f92ad9..6263427bac5ba 100644 --- a/tests/fail/transmute_fat1.stderr +++ b/tests/fail/transmute_fat1.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: type validation failed: encountered a pointer, but expected plain (non-pointer) bytes +error: Undefined Behavior: constructing invalid value: encountered a pointer, but expected plain (non-pointer) bytes --> $DIR/transmute_fat1.rs:LL:CC | LL | std::mem::transmute::<&[u8], [u8; N]>(&[1u8]) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected plain (non-pointer) bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a pointer, but expected plain (non-pointer) bytes | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/uninit_byte_read.stderr b/tests/fail/uninit_byte_read.stderr index d150be3e7e781..d15b10dc6ed09 100644 --- a/tests/fail/uninit_byte_read.stderr +++ b/tests/fail/uninit_byte_read.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: type validation failed: encountered uninitialized bytes, but expected initialized bytes +error: Undefined Behavior: constructing invalid value: encountered uninitialized bytes, but expected initialized bytes --> $DIR/uninit_byte_read.rs:LL:CC | LL | let undef = unsafe { *v.get_unchecked(5) }; - | ^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized bytes, but expected initialized bytes + | ^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered uninitialized bytes, but expected initialized bytes | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/uninit_raw_ptr.rs b/tests/fail/uninit_raw_ptr.rs index beb9ad1270941..c2ede1bb146ad 100644 --- a/tests/fail/uninit_raw_ptr.rs +++ b/tests/fail/uninit_raw_ptr.rs @@ -1,4 +1,4 @@ fn main() { let _val = unsafe { std::mem::MaybeUninit::<*const u8>::uninit().assume_init() }; - //~^ ERROR type validation failed at .value: encountered uninitialized raw pointer + //~^ ERROR constructing invalid value at .value: encountered uninitialized raw pointer } diff --git a/tests/fail/uninit_raw_ptr.stderr b/tests/fail/uninit_raw_ptr.stderr index 96074fc1e7890..c76f59e13e7f5 100644 --- a/tests/fail/uninit_raw_ptr.stderr +++ b/tests/fail/uninit_raw_ptr.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: type validation failed at .value: encountered uninitialized raw pointer +error: Undefined Behavior: constructing invalid value at .value: encountered uninitialized raw pointer --> $DIR/uninit_raw_ptr.rs:LL:CC | LL | let _val = unsafe { std::mem::MaybeUninit::<*const u8>::uninit().assume_init() }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .value: encountered uninitialized raw pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .value: encountered uninitialized raw pointer | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/validity/cast_fn_ptr1.stderr b/tests/fail/validity/cast_fn_ptr1.stderr index d048377a7793d..05c75ac133861 100644 --- a/tests/fail/validity/cast_fn_ptr1.stderr +++ b/tests/fail/validity/cast_fn_ptr1.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: type validation failed: encountered a null reference +error: Undefined Behavior: constructing invalid value: encountered a null reference --> $DIR/cast_fn_ptr1.rs:LL:CC | LL | g(0usize as *const i32) - | ^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a null reference + | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a null reference | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/validity/cast_fn_ptr2.stderr b/tests/fail/validity/cast_fn_ptr2.stderr index 10b9b9b8602b6..8bee099caf3bf 100644 --- a/tests/fail/validity/cast_fn_ptr2.stderr +++ b/tests/fail/validity/cast_fn_ptr2.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: type validation failed: encountered a null reference +error: Undefined Behavior: constructing invalid value: encountered a null reference --> $DIR/cast_fn_ptr2.rs:LL:CC | LL | let _x = g(); - | ^^^ type validation failed: encountered a null reference + | ^^^ constructing invalid value: encountered a null reference | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/validity/dangling_ref1.stderr b/tests/fail/validity/dangling_ref1.stderr index 0d358fd7f7f96..290963c6d4ee6 100644 --- a/tests/fail/validity/dangling_ref1.stderr +++ b/tests/fail/validity/dangling_ref1.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: type validation failed: encountered a dangling reference (address 0x10 is unallocated) +error: Undefined Behavior: constructing invalid value: encountered a dangling reference (address 0x10 is unallocated) --> $DIR/dangling_ref1.rs:LL:CC | LL | let _x: &i32 = unsafe { mem::transmute(16usize) }; - | ^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a dangling reference (address 0x10 is unallocated) + | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling reference (address 0x10 is unallocated) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/validity/dangling_ref2.stderr b/tests/fail/validity/dangling_ref2.stderr index e3bbb72fdcf1e..ce60f973ffe88 100644 --- a/tests/fail/validity/dangling_ref2.stderr +++ b/tests/fail/validity/dangling_ref2.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: type validation failed: encountered a dangling reference (going beyond the bounds of its allocation) +error: Undefined Behavior: constructing invalid value: encountered a dangling reference (going beyond the bounds of its allocation) --> $DIR/dangling_ref2.rs:LL:CC | LL | let _x: &i32 = unsafe { mem::transmute(ptr) }; - | ^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a dangling reference (going beyond the bounds of its allocation) + | ^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling reference (going beyond the bounds of its allocation) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/validity/dangling_ref3.stderr b/tests/fail/validity/dangling_ref3.stderr index 5842eca9fc8ea..aa25f16560863 100644 --- a/tests/fail/validity/dangling_ref3.stderr +++ b/tests/fail/validity/dangling_ref3.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: type validation failed: encountered a dangling reference (use-after-free) +error: Undefined Behavior: constructing invalid value: encountered a dangling reference (use-after-free) --> $DIR/dangling_ref3.rs:LL:CC | LL | let _x: &i32 = unsafe { mem::transmute(dangling()) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a dangling reference (use-after-free) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling reference (use-after-free) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/validity/invalid_bool.stderr b/tests/fail/validity/invalid_bool.stderr index d17319d2dce8c..756c094d6e866 100644 --- a/tests/fail/validity/invalid_bool.stderr +++ b/tests/fail/validity/invalid_bool.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: type validation failed: encountered 0x02, but expected a boolean +error: Undefined Behavior: constructing invalid value: encountered 0x02, but expected a boolean --> $DIR/invalid_bool.rs:LL:CC | LL | let _b = unsafe { std::mem::transmute::(2) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0x02, but expected a boolean + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0x02, but expected a boolean | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/validity/invalid_bool_uninit.stderr b/tests/fail/validity/invalid_bool_uninit.stderr index e262e69dc6968..5236cab450b68 100644 --- a/tests/fail/validity/invalid_bool_uninit.stderr +++ b/tests/fail/validity/invalid_bool_uninit.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: type validation failed: encountered uninitialized bytes, but expected a boolean +error: Undefined Behavior: constructing invalid value: encountered uninitialized bytes, but expected a boolean --> $DIR/invalid_bool_uninit.rs:LL:CC | LL | let _b = unsafe { MyUninit { init: () }.uninit }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized bytes, but expected a boolean + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered uninitialized bytes, but expected a boolean | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/validity/invalid_char.stderr b/tests/fail/validity/invalid_char.stderr index 99f5ce0bb2118..538af4aefcab9 100644 --- a/tests/fail/validity/invalid_char.stderr +++ b/tests/fail/validity/invalid_char.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: type validation failed: encountered $HEX, but expected a valid unicode scalar value (in `0..=$HEX` but not in `$HEX..=$HEX`) +error: Undefined Behavior: constructing invalid value: encountered $HEX, but expected a valid unicode scalar value (in `0..=$HEX` but not in `$HEX..=$HEX`) --> $DIR/invalid_char.rs:LL:CC | LL | let _val = match unsafe { std::mem::transmute::(-1) } { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered $HEX, but expected a valid unicode scalar value (in `0..=$HEX` but not in `$HEX..=$HEX`) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered $HEX, but expected a valid unicode scalar value (in `0..=$HEX` but not in `$HEX..=$HEX`) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/validity/invalid_char_uninit.stderr b/tests/fail/validity/invalid_char_uninit.stderr index b27c9b2bb69ca..12bc0faa5135b 100644 --- a/tests/fail/validity/invalid_char_uninit.stderr +++ b/tests/fail/validity/invalid_char_uninit.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: type validation failed: encountered uninitialized bytes, but expected a valid unicode scalar value (in `0..=$HEX` but not in `$HEX..=$HEX`) +error: Undefined Behavior: constructing invalid value: encountered uninitialized bytes, but expected a valid unicode scalar value (in `0..=$HEX` but not in `$HEX..=$HEX`) --> $DIR/invalid_char_uninit.rs:LL:CC | LL | let _b = unsafe { MyUninit { init: () }.uninit }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized bytes, but expected a valid unicode scalar value (in `0..=$HEX` but not in `$HEX..=$HEX`) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered uninitialized bytes, but expected a valid unicode scalar value (in `0..=$HEX` but not in `$HEX..=$HEX`) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/validity/invalid_enum_tag.rs b/tests/fail/validity/invalid_enum_tag.rs index 9722e6492c829..4bc60ba51e70c 100644 --- a/tests/fail/validity/invalid_enum_tag.rs +++ b/tests/fail/validity/invalid_enum_tag.rs @@ -7,5 +7,5 @@ pub enum Foo { } fn main() { - let _f = unsafe { std::mem::transmute::(42) }; //~ ERROR type validation failed at .: encountered 0x0000002a, but expected a valid enum tag + let _f = unsafe { std::mem::transmute::(42) }; //~ ERROR constructing invalid value at .: encountered 0x0000002a, but expected a valid enum tag } diff --git a/tests/fail/validity/invalid_enum_tag.stderr b/tests/fail/validity/invalid_enum_tag.stderr index c6d862ae1b026..c7014ae71ac22 100644 --- a/tests/fail/validity/invalid_enum_tag.stderr +++ b/tests/fail/validity/invalid_enum_tag.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: type validation failed at .: encountered $HEX, but expected a valid enum tag +error: Undefined Behavior: constructing invalid value at .: encountered $HEX, but expected a valid enum tag --> $DIR/invalid_enum_tag.rs:LL:CC | -LL | ... { std::mem::transmute::(42) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .: encountered $HEX, but expected a valid enum tag +LL | let _f = unsafe { std::mem::transmute::(42) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .: encountered $HEX, but expected a valid enum tag | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/validity/invalid_enum_tag_256variants_uninit.rs b/tests/fail/validity/invalid_enum_tag_256variants_uninit.rs index b6f86698b3fb3..7573a64d0eba8 100644 --- a/tests/fail/validity/invalid_enum_tag_256variants_uninit.rs +++ b/tests/fail/validity/invalid_enum_tag_256variants_uninit.rs @@ -268,5 +268,5 @@ union MyUninit { } fn main() { - let _a = unsafe { MyUninit { init: () }.uninit }; //~ ERROR type validation failed at .: encountered uninitialized bytes, but expected a valid enum tag + let _a = unsafe { MyUninit { init: () }.uninit }; //~ ERROR constructing invalid value at .: encountered uninitialized bytes, but expected a valid enum tag } diff --git a/tests/fail/validity/invalid_enum_tag_256variants_uninit.stderr b/tests/fail/validity/invalid_enum_tag_256variants_uninit.stderr index 0e924bb741a9c..c9fd312a96ce5 100644 --- a/tests/fail/validity/invalid_enum_tag_256variants_uninit.stderr +++ b/tests/fail/validity/invalid_enum_tag_256variants_uninit.stderr @@ -1,9 +1,9 @@ WARNING: `-Zmiri-allow-uninit-numbers` is deprecated and planned to be removed. Please let us know at if you rely on this flag. -error: Undefined Behavior: type validation failed at .: encountered uninitialized bytes, but expected a valid enum tag +error: Undefined Behavior: constructing invalid value at .: encountered uninitialized bytes, but expected a valid enum tag --> $DIR/invalid_enum_tag_256variants_uninit.rs:LL:CC | LL | let _a = unsafe { MyUninit { init: () }.uninit }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .: encountered uninitialized bytes, but expected a valid enum tag + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .: encountered uninitialized bytes, but expected a valid enum tag | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/validity/invalid_fnptr_null.stderr b/tests/fail/validity/invalid_fnptr_null.stderr index e3cea40e0c338..13e8957e615ff 100644 --- a/tests/fail/validity/invalid_fnptr_null.stderr +++ b/tests/fail/validity/invalid_fnptr_null.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: type validation failed: encountered a null function pointer +error: Undefined Behavior: constructing invalid value: encountered a null function pointer --> $DIR/invalid_fnptr_null.rs:LL:CC | LL | let _b: fn() = unsafe { std::mem::transmute(0usize) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a null function pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a null function pointer | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/validity/invalid_fnptr_uninit.stderr b/tests/fail/validity/invalid_fnptr_uninit.stderr index 84a5657e78709..b64655fa81897 100644 --- a/tests/fail/validity/invalid_fnptr_uninit.stderr +++ b/tests/fail/validity/invalid_fnptr_uninit.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: type validation failed: encountered uninitialized bytes, but expected a proper pointer or integer value +error: Undefined Behavior: constructing invalid value: encountered uninitialized bytes, but expected a proper pointer or integer value --> $DIR/invalid_fnptr_uninit.rs:LL:CC | LL | let _b = unsafe { MyUninit { init: () }.uninit }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered uninitialized bytes, but expected a proper pointer or integer value + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered uninitialized bytes, but expected a proper pointer or integer value | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/validity/invalid_wide_raw.stderr b/tests/fail/validity/invalid_wide_raw.stderr index f64b824d6ba6e..633f8f8adbc23 100644 --- a/tests/fail/validity/invalid_wide_raw.stderr +++ b/tests/fail/validity/invalid_wide_raw.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: type validation failed: encountered dangling vtable pointer in wide pointer +error: Undefined Behavior: constructing invalid value: encountered dangling vtable pointer in wide pointer --> $DIR/invalid_wide_raw.rs:LL:CC | LL | dbg!(S { x: unsafe { std::mem::transmute((0usize, 0usize)) } }); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered dangling vtable pointer in wide pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered dangling vtable pointer in wide pointer | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/validity/nonzero.stderr b/tests/fail/validity/nonzero.stderr index ba01acb6a1694..0c6a241723071 100644 --- a/tests/fail/validity/nonzero.stderr +++ b/tests/fail/validity/nonzero.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: type validation failed: encountered 0, but expected something greater or equal to 1 +error: Undefined Behavior: constructing invalid value: encountered 0, but expected something greater or equal to 1 --> $DIR/nonzero.rs:LL:CC | LL | let _x = Some(unsafe { NonZero(0) }); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0, but expected something greater or equal to 1 + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0, but expected something greater or equal to 1 | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/validity/ptr_integer_array_transmute.stderr b/tests/fail/validity/ptr_integer_array_transmute.stderr index bc2ca54438ff9..39b4ebfc8f132 100644 --- a/tests/fail/validity/ptr_integer_array_transmute.stderr +++ b/tests/fail/validity/ptr_integer_array_transmute.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: type validation failed: encountered a pointer, but expected plain (non-pointer) bytes +error: Undefined Behavior: constructing invalid value: encountered a pointer, but expected plain (non-pointer) bytes --> $DIR/ptr_integer_array_transmute.rs:LL:CC | LL | let _i: [usize; 1] = unsafe { std::mem::transmute(r) }; - | ^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered a pointer, but expected plain (non-pointer) bytes + | ^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a pointer, but expected plain (non-pointer) bytes | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/validity/ref_to_uninhabited1.stderr b/tests/fail/validity/ref_to_uninhabited1.stderr index dbaee46a93b8f..526b6a4dc2515 100644 --- a/tests/fail/validity/ref_to_uninhabited1.stderr +++ b/tests/fail/validity/ref_to_uninhabited1.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: type validation failed: encountered a box pointing to uninhabited type ! +error: Undefined Behavior: constructing invalid value: encountered a box pointing to uninhabited type ! --> $DIR/ref_to_uninhabited1.rs:LL:CC | LL | let x: Box = transmute(&mut 42); - | ^^^^^^^^^^^^^^^^^^ type validation failed: encountered a box pointing to uninhabited type ! + | ^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a box pointing to uninhabited type ! | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/validity/ref_to_uninhabited2.stderr b/tests/fail/validity/ref_to_uninhabited2.stderr index 115cdfedf7775..297b0540ab014 100644 --- a/tests/fail/validity/ref_to_uninhabited2.stderr +++ b/tests/fail/validity/ref_to_uninhabited2.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: type validation failed: encountered a reference pointing to uninhabited type (i32, Void) +error: Undefined Behavior: constructing invalid value: encountered a reference pointing to uninhabited type (i32, Void) --> $DIR/ref_to_uninhabited2.rs:LL:CC | LL | let _x: &(i32, Void) = transmute(&42); - | ^^^^^^^^^^^^^^ type validation failed: encountered a reference pointing to uninhabited type (i32, Void) + | ^^^^^^^^^^^^^^ constructing invalid value: encountered a reference pointing to uninhabited type (i32, Void) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/validity/too-big-slice.stderr b/tests/fail/validity/too-big-slice.stderr index 9c8d2929bda00..52077f16a1c8c 100644 --- a/tests/fail/validity/too-big-slice.stderr +++ b/tests/fail/validity/too-big-slice.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: type validation failed: encountered invalid reference metadata: slice is bigger than largest supported object +error: Undefined Behavior: constructing invalid value: encountered invalid reference metadata: slice is bigger than largest supported object --> $DIR/too-big-slice.rs:LL:CC | LL | let _x: &[u8] = mem::transmute((ptr, usize::MAX)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered invalid reference metadata: slice is bigger than largest supported object + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered invalid reference metadata: slice is bigger than largest supported object | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/validity/too-big-unsized.stderr b/tests/fail/validity/too-big-unsized.stderr index 18dc5d8b9c18e..a20f1de6d57dc 100644 --- a/tests/fail/validity/too-big-unsized.stderr +++ b/tests/fail/validity/too-big-unsized.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: type validation failed: encountered invalid reference metadata: total size is bigger than largest supported object +error: Undefined Behavior: constructing invalid value: encountered invalid reference metadata: total size is bigger than largest supported object --> $DIR/too-big-unsized.rs:LL:CC | LL | let _x: &MySlice = mem::transmute((ptr, isize::MAX as usize)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered invalid reference metadata: total size is bigger than largest supported object + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered invalid reference metadata: total size is bigger than largest supported object | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/validity/transmute_through_ptr.rs b/tests/fail/validity/transmute_through_ptr.rs index 049c57e61939a..9db2ba9953044 100644 --- a/tests/fail/validity/transmute_through_ptr.rs +++ b/tests/fail/validity/transmute_through_ptr.rs @@ -14,6 +14,6 @@ fn main() { let mut x = Bool::True; evil(&mut x); let y = x; // reading this ought to be enough to trigger validation - //~^ ERROR type validation failed at .: encountered 0x0000002c, but expected a valid enum tag + //~^ ERROR constructing invalid value at .: encountered 0x0000002c, but expected a valid enum tag println!("{:?}", y); // make sure it is used (and not optimized away) } diff --git a/tests/fail/validity/transmute_through_ptr.stderr b/tests/fail/validity/transmute_through_ptr.stderr index d06dbe3194f5f..50f699d7f9b52 100644 --- a/tests/fail/validity/transmute_through_ptr.stderr +++ b/tests/fail/validity/transmute_through_ptr.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: type validation failed at .: encountered $HEX, but expected a valid enum tag +error: Undefined Behavior: constructing invalid value at .: encountered $HEX, but expected a valid enum tag --> $DIR/transmute_through_ptr.rs:LL:CC | LL | let y = x; // reading this ought to be enough to trigger validation - | ^ type validation failed at .: encountered $HEX, but expected a valid enum tag + | ^ constructing invalid value at .: encountered $HEX, but expected a valid enum tag | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/validity/uninit_float.rs b/tests/fail/validity/uninit_float.rs index e79cbb45f9848..43748570d9a49 100644 --- a/tests/fail/validity/uninit_float.rs +++ b/tests/fail/validity/uninit_float.rs @@ -2,5 +2,5 @@ fn main() { let _val = unsafe { std::mem::MaybeUninit::::uninit().assume_init() }; - //~^ ERROR type validation failed at .value: encountered uninitialized bytes, but expected initialized bytes + //~^ ERROR constructing invalid value at .value: encountered uninitialized bytes, but expected initialized bytes } diff --git a/tests/fail/validity/uninit_float.stderr b/tests/fail/validity/uninit_float.stderr index 3f244adbabed0..946897bd4ea6f 100644 --- a/tests/fail/validity/uninit_float.stderr +++ b/tests/fail/validity/uninit_float.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: type validation failed at .value: encountered uninitialized bytes, but expected initialized bytes +error: Undefined Behavior: constructing invalid value at .value: encountered uninitialized bytes, but expected initialized bytes --> $DIR/uninit_float.rs:LL:CC | LL | let _val = unsafe { std::mem::MaybeUninit::::uninit().assume_init() }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .value: encountered uninitialized bytes, but expected initialized bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .value: encountered uninitialized bytes, but expected initialized bytes | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/validity/uninit_integer.rs b/tests/fail/validity/uninit_integer.rs index bfa25d6ef356d..b5a367ba8cb70 100644 --- a/tests/fail/validity/uninit_integer.rs +++ b/tests/fail/validity/uninit_integer.rs @@ -2,5 +2,5 @@ fn main() { let _val = unsafe { std::mem::MaybeUninit::::uninit().assume_init() }; - //~^ ERROR type validation failed at .value: encountered uninitialized bytes, but expected initialized bytes + //~^ ERROR constructing invalid value at .value: encountered uninitialized bytes, but expected initialized bytes } diff --git a/tests/fail/validity/uninit_integer.stderr b/tests/fail/validity/uninit_integer.stderr index e3e2f0a178526..7e9d38a4b7bb9 100644 --- a/tests/fail/validity/uninit_integer.stderr +++ b/tests/fail/validity/uninit_integer.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: type validation failed at .value: encountered uninitialized bytes, but expected initialized bytes +error: Undefined Behavior: constructing invalid value at .value: encountered uninitialized bytes, but expected initialized bytes --> $DIR/uninit_integer.rs:LL:CC | LL | let _val = unsafe { std::mem::MaybeUninit::::uninit().assume_init() }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .value: encountered uninitialized bytes, but expected initialized bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .value: encountered uninitialized bytes, but expected initialized bytes | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/validity/uninit_integer_signed.rs b/tests/fail/validity/uninit_integer_signed.rs index 1764120805c42..609bad7e4fb68 100644 --- a/tests/fail/validity/uninit_integer_signed.rs +++ b/tests/fail/validity/uninit_integer_signed.rs @@ -2,5 +2,5 @@ fn main() { let _val = unsafe { std::mem::MaybeUninit::::uninit().assume_init() }; - //~^ ERROR type validation failed at .value: encountered uninitialized bytes, but expected initialized bytes + //~^ ERROR constructing invalid value at .value: encountered uninitialized bytes, but expected initialized bytes } diff --git a/tests/fail/validity/uninit_integer_signed.stderr b/tests/fail/validity/uninit_integer_signed.stderr index e6d9b51e40e40..bd8ea42c3a435 100644 --- a/tests/fail/validity/uninit_integer_signed.stderr +++ b/tests/fail/validity/uninit_integer_signed.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: type validation failed at .value: encountered uninitialized bytes, but expected initialized bytes +error: Undefined Behavior: constructing invalid value at .value: encountered uninitialized bytes, but expected initialized bytes --> $DIR/uninit_integer_signed.rs:LL:CC | LL | let _val = unsafe { std::mem::MaybeUninit::::uninit().assume_init() }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed at .value: encountered uninitialized bytes, but expected initialized bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .value: encountered uninitialized bytes, but expected initialized bytes | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information From 6a204e2dec621d0cec4b9290733feee67d49b8c8 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 29 Jun 2022 22:17:46 -0400 Subject: [PATCH 3365/3747] use Rust SnakeCase --- src/shims/unix/dlsym.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/shims/unix/dlsym.rs b/src/shims/unix/dlsym.rs index e1f819fb85671..2c563a9551f24 100644 --- a/src/shims/unix/dlsym.rs +++ b/src/shims/unix/dlsym.rs @@ -10,7 +10,7 @@ use shims::unix::macos::dlsym as macos; pub enum Dlsym { Linux(linux::Dlsym), MacOs(macos::Dlsym), - FreeBSD(freebsd::Dlsym), + FreeBsd(freebsd::Dlsym), } impl Dlsym { @@ -20,7 +20,7 @@ impl Dlsym { Ok(match target_os { "linux" => linux::Dlsym::from_str(name)?.map(Dlsym::Linux), "macos" => macos::Dlsym::from_str(name)?.map(Dlsym::MacOs), - "freebsd" => freebsd::Dlsym::from_str(name)?.map(Dlsym::FreeBSD), + "freebsd" => freebsd::Dlsym::from_str(name)?.map(Dlsym::FreeBsd), _ => unreachable!(), }) } @@ -43,7 +43,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx match dlsym { Dlsym::Linux(dlsym) => linux::EvalContextExt::call_dlsym(this, dlsym, args, dest, ret), Dlsym::MacOs(dlsym) => macos::EvalContextExt::call_dlsym(this, dlsym, args, dest, ret), - Dlsym::FreeBSD(dlsym) => + Dlsym::FreeBsd(dlsym) => freebsd::EvalContextExt::call_dlsym(this, dlsym, args, dest, ret), } } From a9f9d48b1a071dd067bdd17bd83d0a06ad2ab923 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 29 Jun 2022 13:29:35 +0000 Subject: [PATCH 3366/3747] Support no-std targets and test it in CI --- CONTRIBUTING.md | 10 ++++++++++ README.md | 2 ++ cargo-miri/bin.rs | 18 ++++++++++-------- ci.sh | 1 + tests/pass/no_std.rs | 21 +++++++++++++++++++++ 5 files changed, 44 insertions(+), 8 deletions(-) create mode 100644 tests/pass/no_std.rs diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index ad8bd2a17a6c7..7dfa9d73120f5 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -71,6 +71,16 @@ and you can (cross-)run the entire test suite using: MIRI_TEST_TARGET=i686-unknown-linux-gnu ./miri test ``` +If your target doesn't support libstd, you can run miri with + +``` +MIRI_NO_STD=1 MIRI_TEST_TARGET=thumbv7em-none-eabihf ./miri test tests/fail/alloc/no_global_allocator.rs +MIRI_NO_STD=1 ./miri run tests/pass/no_std.rs --target thumbv7em-none-eabihf +``` + +to avoid attempting (and failing) to build libstd. Note that almost no tests will pass +this way, but you can run individual tests. + `./miri test FILTER` only runs those tests that contain `FILTER` in their filename (including the base directory, e.g. `./miri test fail` will run all compile-fail tests). diff --git a/README.md b/README.md index bfc32d04a9d14..2d9609fb0b706 100644 --- a/README.md +++ b/README.md @@ -419,6 +419,8 @@ Moreover, Miri recognizes some environment variables: * `MIRI_TEST_TARGET` (recognized by the test suite) indicates which target architecture to test against. `miri` and `cargo miri` accept the `--target` flag for the same purpose. +* `MIRI_NO_STD` (recognized by `cargo miri` and the test suite) makes sure that the target's + sysroot is built without libstd. This allows testing and running no_std programs. * `MIRI_BLESS` (recognized by the test suite) overwrite all `stderr` and `stdout` files instead of checking whether the output matches. * `MIRI_SKIP_UI_CHECKS` (recognized by the test suite) don't check whether the diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index 9627adeb2e792..4c9f3aabaab49 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -398,11 +398,12 @@ fn setup(subcommand: MiriCommand) { if !dir.exists() { fs::create_dir_all(&dir).unwrap(); } - // The interesting bit: Xargo.toml - File::create(dir.join("Xargo.toml")) - .unwrap() - .write_all( - br#" + let mut xargo_toml = File::create(dir.join("Xargo.toml")).unwrap(); + if std::env::var_os("MIRI_NO_STD").is_none() { + // The interesting bit: Xargo.toml (only needs content if we actually need std) + xargo_toml + .write_all( + br#" [dependencies.std] default_features = false # We support unwinding, so enable that panic runtime. @@ -410,8 +411,9 @@ features = ["panic_unwind", "backtrace"] [dependencies.test] "#, - ) - .unwrap(); + ) + .unwrap(); + } // The boring bits: a dummy project for xargo. // FIXME: With xargo-check, can we avoid doing this? File::create(dir.join("Cargo.toml")) @@ -428,7 +430,7 @@ path = "lib.rs" "#, ) .unwrap(); - File::create(dir.join("lib.rs")).unwrap(); + File::create(dir.join("lib.rs")).unwrap().write_all(b"#![no_std]").unwrap(); // Determine architectures. // We always need to set a target so rustc bootstrap can tell apart host from target crates. diff --git a/ci.sh b/ci.sh index 1fa67f52139ed..e3a106308592c 100755 --- a/ci.sh +++ b/ci.sh @@ -61,6 +61,7 @@ case $HOST_TARGET in MIRI_TEST_TARGET=aarch64-apple-darwin run_tests MIRI_TEST_TARGET=i686-pc-windows-msvc run_tests MIRI_TEST_TARGET=x86_64-unknown-freebsd run_tests_minimal hello integer vec + MIRI_NO_STD=1 ./miri run tests/pass/no_std.rs --target thumbv7em-none-eabihf # no_std embedded architecture minimal test ;; x86_64-apple-darwin) MIRI_TEST_TARGET=mips64-unknown-linux-gnuabi64 run_tests # big-endian architecture diff --git a/tests/pass/no_std.rs b/tests/pass/no_std.rs new file mode 100644 index 0000000000000..6808dab8143f4 --- /dev/null +++ b/tests/pass/no_std.rs @@ -0,0 +1,21 @@ +#![feature(lang_items, start)] +#![no_std] +// windows tls dtors go through libstd right now, thus this test +// cannot pass. When windows tls dtors go through the special magic +// windows linker section, we can run this test on windows again. +// ignore-windows + +#[start] +fn start(_: isize, _: *const *const u8) -> isize { + for _ in 0..10 {} + + 0 +} + +#[panic_handler] +fn panic_handler(_: &core::panic::PanicInfo) -> ! { + loop {} +} + +#[lang = "eh_personality"] +fn eh_personality() {} From c1d10cdbe0df35840e418fee170adf7aa5cc108c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 30 Jun 2022 10:04:23 -0400 Subject: [PATCH 3367/3747] use run_tests_minimal for the new no-std test --- ci.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci.sh b/ci.sh index e3a106308592c..e9ebb6f136f4f 100755 --- a/ci.sh +++ b/ci.sh @@ -61,7 +61,7 @@ case $HOST_TARGET in MIRI_TEST_TARGET=aarch64-apple-darwin run_tests MIRI_TEST_TARGET=i686-pc-windows-msvc run_tests MIRI_TEST_TARGET=x86_64-unknown-freebsd run_tests_minimal hello integer vec - MIRI_NO_STD=1 ./miri run tests/pass/no_std.rs --target thumbv7em-none-eabihf # no_std embedded architecture minimal test + MIRI_TEST_TARGET=thumbv7em-none-eabihf MIRI_NO_STD=1 run_tests_minimal no_std # no_std embedded architecture ;; x86_64-apple-darwin) MIRI_TEST_TARGET=mips64-unknown-linux-gnuabi64 run_tests # big-endian architecture From aef78d3a9f2e71d4e7cbd635ea7eb4baa9918e46 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 30 Jun 2022 11:13:26 -0400 Subject: [PATCH 3368/3747] make -Zmiri-env-forward take precedence over -Zmiri-env-exclude --- README.md | 5 +++-- src/shims/env.rs | 8 ++++---- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 2d9609fb0b706..32cbc4f1e458a 100644 --- a/README.md +++ b/README.md @@ -285,8 +285,9 @@ environment variable. We first document the most relevant and most commonly used harness](https://github.com/rust-lang/miri/issues/1702). This has no effect unless `-Zmiri-disable-isolation` is also set. * `-Zmiri-env-forward=` forwards the `var` environment variable to the interpreted program. Can - be used multiple times to forward several variables. This has no effect if - `-Zmiri-disable-isolation` is set. + be used multiple times to forward several variables. This takes precedence over + `-Zmiri-env-exclude`: if a variable is both forwarded and exluced, it *will* get forwarded. This + means in particular `-Zmiri-env-forward=TERM` overwrites the default exclusion of `TERM`. * `-Zmiri-ignore-leaks` disables the memory leak checker, and also allows some remaining threads to exist when the main thread exits. * `-Zmiri-permissive-provenance` disables the warning for integer-to-pointer casts and diff --git a/src/shims/env.rs b/src/shims/env.rs index 85ecd2b719f20..f4aaeea2c122e 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -50,10 +50,10 @@ impl<'tcx> EnvVars<'tcx> { // Skip the loop entirely if we don't want to forward anything. if ecx.machine.communicate() || !config.forwarded_env_vars.is_empty() { for (name, value) in env::vars_os() { - let forward = match ecx.machine.communicate() { - true => !excluded_env_vars.iter().any(|v| **v == name), - false => config.forwarded_env_vars.iter().any(|v| **v == name), - }; + // Always forward what is in `forwarded_env_vars`; that list can take precedence over excluded_env_vars. + let forward = config.forwarded_env_vars.iter().any(|v| **v == name) + || (ecx.machine.communicate() + && !excluded_env_vars.iter().any(|v| **v == name)); if forward { let var_ptr = match target_os { target if target_os_is_unix(target) => From 7f3fbbdee7cea0b165bd3620d971b78ca35362e7 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 30 Jun 2022 18:41:32 -0400 Subject: [PATCH 3369/3747] allocation tracking: also print size, alignment, kind of the allocation --- src/diagnostics.rs | 6 ++++-- src/machine.rs | 9 +++++++-- tests/pass/track-alloc-1.rs | 1 + tests/pass/track-alloc-1.stderr | 2 +- 4 files changed, 13 insertions(+), 5 deletions(-) diff --git a/src/diagnostics.rs b/src/diagnostics.rs index 55598c19ef6b7..1ffcdc799edf0 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -6,6 +6,7 @@ use log::trace; use rustc_middle::ty; use rustc_span::{source_map::DUMMY_SP, Span, SpanData, Symbol}; +use rustc_target::abi::{Align, Size}; use crate::helpers::HexRange; use crate::stacked_borrows::{diagnostics::TagHistory, AccessKind}; @@ -71,7 +72,7 @@ pub enum NonHaltingDiagnostic { /// a deallocation when the second argument is `None`. PoppedPointerTag(Item, Option<(SbTagExtra, AccessKind)>), CreatedCallId(CallId), - CreatedAlloc(AllocId), + CreatedAlloc(AllocId, Size, Align, MemoryKind), FreedAlloc(AllocId), RejectedIsolatedOp(String), ProgressReport, @@ -463,7 +464,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } }, CreatedCallId(id) => format!("function call with id {id}"), - CreatedAlloc(AllocId(id)) => format!("created allocation with id {id}"), + CreatedAlloc(AllocId(id), size, align, kind) => + format!("created {kind} allocation of {} bytes (alignment {} bytes) with id {id}", size.bytes(), align.bytes()), FreedAlloc(AllocId(id)) => format!("freed allocation with id {id}"), RejectedIsolatedOp(ref op) => format!("{op} was made to return an error due to isolation"), diff --git a/src/machine.rs b/src/machine.rs index 4aeb42d3d0fe3..abc55cde737ec 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -624,11 +624,16 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { alloc: Cow<'b, Allocation>, kind: Option>, ) -> InterpResult<'tcx, Cow<'b, Allocation>> { + let kind = kind.expect("we set our STATIC_KIND so this cannot be None"); if ecx.machine.tracked_alloc_ids.contains(&id) { - register_diagnostic(NonHaltingDiagnostic::CreatedAlloc(id)); + register_diagnostic(NonHaltingDiagnostic::CreatedAlloc( + id, + alloc.size(), + alloc.align, + kind, + )); } - let kind = kind.expect("we set our STATIC_KIND so this cannot be None"); let alloc = alloc.into_owned(); let stacks = if let Some(stacked_borrows) = &ecx.machine.stacked_borrows { Some(Stacks::new_allocation( diff --git a/tests/pass/track-alloc-1.rs b/tests/pass/track-alloc-1.rs index 7bb217309f944..bbd88ed5d53e0 100644 --- a/tests/pass/track-alloc-1.rs +++ b/tests/pass/track-alloc-1.rs @@ -2,4 +2,5 @@ // Early allocations are probably part of the runtime and therefore uninteresting, but they // shouldn't cause a crash. // compile-flags: -Zmiri-track-alloc-id=1 +// normalize-stderr-test: "[48] bytes" -> "SIZE bytes" fn main() {} diff --git a/tests/pass/track-alloc-1.stderr b/tests/pass/track-alloc-1.stderr index be96b729838d6..7206edbb7010b 100644 --- a/tests/pass/track-alloc-1.stderr +++ b/tests/pass/track-alloc-1.stderr @@ -1,5 +1,5 @@ note: tracking was triggered | - = note: created allocation with id 1 + = note: created extern static allocation of SIZE bytes (alignment ALIGN bytes) with id 1 = note: (no span available) From a1fabb94786b0c551a11849383d3a9241254a807 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 1 Jul 2022 07:53:17 -0400 Subject: [PATCH 3370/3747] make miri script work from other working directories --- miri | 60 +++++++++++++++++++++++++++++++++--------------------------- 1 file changed, 33 insertions(+), 27 deletions(-) diff --git a/miri b/miri index 6b7e9dbf03f89..b84213f93809c 100755 --- a/miri +++ b/miri @@ -5,14 +5,14 @@ USAGE=$(cat <<"EOF" ./miri install : Installs the miri driver and cargo-miri. are passed to `cargo -install`. Sets up the rpath such that the installed binary should work in any +install`. Sets up the rpath such that the installed binary should work in any working directory. ./miri build : -Just build miri. are passed to `cargo build`. +Just build miri. are passed to `cargo build`. ./miri check : -Just check miri. are passed to `cargo check`. +Just check miri. are passed to `cargo check`. ./miri test : Build miri, set up a sysroot and then run the test suite. are passed @@ -26,10 +26,10 @@ The commands above also exist in a "-debug" variant (e.g. "./miri run-debug times and slower execution times. ./miri fmt : -Format all sources and tests. are passed to `rustfmt`. +Format all sources and tests. are passed to `rustfmt`. ./miri clippy : -Format all sources and tests. are passed to `cargo clippy`. +Format all sources and tests. are passed to `cargo clippy`. ENVIRONMENT VARIABLES @@ -42,17 +42,23 @@ EOF ) ## Preparation -TARGET=$(rustc --version --verbose | grep "^host:" | cut -d ' ' -f 2) -SYSROOT=$(rustc --print sysroot) -LIBDIR=$SYSROOT/lib/rustlib/$TARGET/lib # macOS does not have a useful readlink/realpath so we have to use Python instead... MIRIDIR=$(dirname "$(python3 -c 'import os, sys; print(os.path.realpath(sys.argv[1]))' "$0")") +# Determine toolchain *in the Miri dir* and use that. +TOOLCHAIN=$(cd "$MIRIDIR"; rustup show active-toolchain | head -n 1 | cut -d ' ' -f 1) +# Determine some toolchain properties +TARGET=$(rustc +$TOOLCHAIN --version --verbose | grep "^host:" | cut -d ' ' -f 2) +SYSROOT=$(rustc +$TOOLCHAIN --print sysroot) +LIBDIR=$SYSROOT/lib/rustlib/$TARGET/lib + if ! test -d "$LIBDIR"; then echo "Something went wrong determining the library dir." echo "I got $LIBDIR but that does not exist." echo "Please report a bug at https://github.com/rust-lang/miri/issues." exit 2 fi + +CARGO="cargo +$TOOLCHAIN" if [ -z "$CARGO_INCREMENTAL" ]; then # Default CARGO_INCREMENTAL to 1. export CARGO_INCREMENTAL=1 @@ -68,15 +74,15 @@ export RUSTFLAGS="-C link-args=-Wl,-rpath,$LIBDIR -C debug-assertions -C debugin ## Helper functions -# Build a sysroot and set MIRI_SYSROOT to use it. Arguments are passed to `cargo miri setup`. +# Build a sysroot and set MIRI_SYSROOT to use it. Arguments are passed to `cargo miri setup`. build_sysroot() { # Build once, for the user to see. - cargo run $CARGO_BUILD_FLAGS --manifest-path "$MIRIDIR"/cargo-miri/Cargo.toml -- miri setup "$@" + $CARGO run $CARGO_BUILD_FLAGS --manifest-path "$MIRIDIR"/cargo-miri/Cargo.toml -- miri setup "$@" # Call again, to just set env var. - export MIRI_SYSROOT="$(cargo run $CARGO_BUILD_FLAGS --manifest-path "$MIRIDIR"/cargo-miri/Cargo.toml -q -- miri setup --print-sysroot "$@")" + export MIRI_SYSROOT="$($CARGO run $CARGO_BUILD_FLAGS --manifest-path "$MIRIDIR"/cargo-miri/Cargo.toml -q -- miri setup --print-sysroot "$@")" } -# Prepare and set MIRI_SYSROOT. Respects `MIRI_TEST_TARGET` and takes into account +# Prepare and set MIRI_SYSROOT. Respects `MIRI_TEST_TARGET` and takes into account # locally built vs. distributed rustc. find_sysroot() { if [ -n "$MIRI_SYSROOT" ]; then @@ -116,22 +122,22 @@ case "$COMMAND" in install|install-debug) # "--locked" to respect the Cargo.lock file if it exists, # "--offline" to avoid querying the registry (for yanked packages). - cargo install $CARGO_INSTALL_FLAGS --path "$MIRIDIR" --force --locked --offline "$@" - cargo install $CARGO_INSTALL_FLAGS --path "$MIRIDIR"/cargo-miri --force --locked --offline "$@" + $CARGO install $CARGO_INSTALL_FLAGS --path "$MIRIDIR" --force --locked --offline "$@" + $CARGO install $CARGO_INSTALL_FLAGS --path "$MIRIDIR"/cargo-miri --force --locked --offline "$@" ;; check|check-debug) # Check, and let caller control flags. - cargo check $CARGO_BUILD_FLAGS --manifest-path "$MIRIDIR"/Cargo.toml --all-targets "$@" - cargo check $CARGO_BUILD_FLAGS --manifest-path "$MIRIDIR"/cargo-miri/Cargo.toml "$@" + $CARGO check $CARGO_BUILD_FLAGS --manifest-path "$MIRIDIR"/Cargo.toml --all-targets "$@" + $CARGO check $CARGO_BUILD_FLAGS --manifest-path "$MIRIDIR"/cargo-miri/Cargo.toml "$@" ;; build|build-debug) # Build, and let caller control flags. - cargo build $CARGO_BUILD_FLAGS --manifest-path "$MIRIDIR"/Cargo.toml "$@" - cargo build $CARGO_BUILD_FLAGS --manifest-path "$MIRIDIR"/cargo-miri/Cargo.toml "$@" + $CARGO build $CARGO_BUILD_FLAGS --manifest-path "$MIRIDIR"/Cargo.toml "$@" + $CARGO build $CARGO_BUILD_FLAGS --manifest-path "$MIRIDIR"/cargo-miri/Cargo.toml "$@" ;; test|test-debug|bless|bless-debug) # First build and get a sysroot. - cargo build $CARGO_BUILD_FLAGS + $CARGO build $CARGO_BUILD_FLAGS --manifest-path "$MIRIDIR"/Cargo.toml find_sysroot case "$COMMAND" in bless|bless-debug) @@ -140,8 +146,8 @@ test|test-debug|bless|bless-debug) esac # Then test, and let caller control flags. # Only in root project and ui_test as `cargo-miri` has no tests. - cargo test $CARGO_BUILD_FLAGS "$@" - cargo test $CARGO_BUILD_FLAGS --manifest-path ui_test/Cargo.toml "$@" + $CARGO test $CARGO_BUILD_FLAGS --manifest-path "$MIRIDIR"/Cargo.toml "$@" + $CARGO test $CARGO_BUILD_FLAGS --manifest-path "$MIRIDIR"/ui_test/Cargo.toml "$@" ;; run|run-debug) # Scan for "--target" to set the "MIRI_TEST_TARGET" env var so @@ -157,19 +163,19 @@ run|run-debug) done fi # First build and get a sysroot. - cargo build $CARGO_BUILD_FLAGS + $CARGO build $CARGO_BUILD_FLAGS --manifest-path "$MIRIDIR"/Cargo.toml find_sysroot # Then run the actual command. - exec cargo run $CARGO_BUILD_FLAGS -- --sysroot "$MIRI_SYSROOT" "$@" + exec $CARGO run $CARGO_BUILD_FLAGS --manifest-path "$MIRIDIR"/Cargo.toml -- --sysroot "$MIRI_SYSROOT" "$@" ;; fmt) find "$MIRIDIR" -not \( -name target -prune \) -name '*.rs' \ - | xargs rustfmt --edition=2021 --config-path "$MIRIDIR/rustfmt.toml" "$@" + | xargs rustfmt +$TOOLCHAIN --edition=2021 --config-path "$MIRIDIR/rustfmt.toml" "$@" ;; clippy) - cargo clippy $CARGO_BUILD_FLAGS --manifest-path "$MIRIDIR"/Cargo.toml --all-targets "$@" - cargo clippy $CARGO_BUILD_FLAGS --manifest-path "$MIRIDIR"/ui_test/Cargo.toml --all-targets "$@" - cargo clippy $CARGO_BUILD_FLAGS --manifest-path "$MIRIDIR"/cargo-miri/Cargo.toml "$@" + $CARGO clippy $CARGO_BUILD_FLAGS --manifest-path "$MIRIDIR"/Cargo.toml --all-targets "$@" + $CARGO clippy $CARGO_BUILD_FLAGS --manifest-path "$MIRIDIR"/ui_test/Cargo.toml --all-targets "$@" + $CARGO clippy $CARGO_BUILD_FLAGS --manifest-path "$MIRIDIR"/cargo-miri/Cargo.toml "$@" ;; *) if [ -n "$COMMAND" ]; then From 7d09313727d37841e89713bd4d6f86cd7aa4fda1 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 1 Jul 2022 09:55:02 -0400 Subject: [PATCH 3371/3747] add './miri many-seeds', and respect MIRIFLAGS in './miri run' --- miri | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/miri b/miri index b84213f93809c..0d3d361af2fac 100755 --- a/miri +++ b/miri @@ -20,6 +20,7 @@ to the final `cargo test` invocation. ./miri run : Build miri, set up a sysroot and then run the driver with the given . +(Also respects MIRIFLAGS environment variable.) The commands above also exist in a "-debug" variant (e.g. "./miri run-debug ") which uses debug builds instead of release builds, for faster build @@ -31,6 +32,11 @@ Format all sources and tests. are passed to `rustfmt`. ./miri clippy : Format all sources and tests. are passed to `cargo clippy`. +./miri many-seeds : +Runs over and over again with different seeds for Miri. The MIRIFLAGS +variable is set to its original value appended with ` -Zmiri-seed=$SEED` for +many different seeds. + ENVIRONMENT VARIABLES MIRI_SYSROOT: @@ -41,6 +47,20 @@ Pass extra flags to all cargo invocations. EOF ) +# Determine command. +COMMAND="$1" +[ $# -gt 0 ] && shift + +## Handle some commands early, since they should *not* alter the environment. +case "$COMMAND" in +many-seeds) + for SEED in $({ echo obase=16; seq 0 255; } | bc); do + MIRIFLAGS="$MIRIFLAGS -Zmiri-seed=$SEED" $@ || { echo "Failing seed: $SEED"; break; } + done + exit 0 + ;; +esac + ## Preparation # macOS does not have a useful readlink/realpath so we have to use Python instead... MIRIDIR=$(dirname "$(python3 -c 'import os, sys; print(os.path.realpath(sys.argv[1]))' "$0")") @@ -99,10 +119,6 @@ find_sysroot() { ## Main -# Determine command. -COMMAND="$1" -[ $# -gt 0 ] && shift - # Determine flags passed to all cargo invocations. # This is a bit more annoying that one would hope due to # . @@ -166,7 +182,7 @@ run|run-debug) $CARGO build $CARGO_BUILD_FLAGS --manifest-path "$MIRIDIR"/Cargo.toml find_sysroot # Then run the actual command. - exec $CARGO run $CARGO_BUILD_FLAGS --manifest-path "$MIRIDIR"/Cargo.toml -- --sysroot "$MIRI_SYSROOT" "$@" + exec $CARGO run $CARGO_BUILD_FLAGS --manifest-path "$MIRIDIR"/Cargo.toml -- --sysroot "$MIRI_SYSROOT" $MIRIFLAGS "$@" ;; fmt) find "$MIRIDIR" -not \( -name target -prune \) -name '*.rs' \ From 9bc7938bc27d3757278c55839c1865ee74c50baa Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 1 Jul 2022 10:01:00 -0400 Subject: [PATCH 3372/3747] more tweaks --- miri | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/miri b/miri index 0d3d361af2fac..349cf818fb2a2 100755 --- a/miri +++ b/miri @@ -63,14 +63,14 @@ esac ## Preparation # macOS does not have a useful readlink/realpath so we have to use Python instead... -MIRIDIR=$(dirname "$(python3 -c 'import os, sys; print(os.path.realpath(sys.argv[1]))' "$0")") +MIRIDIR=$(python3 -c 'import os, sys; print(os.path.dirname(os.path.realpath(sys.argv[1])))' "$0") # Determine toolchain *in the Miri dir* and use that. TOOLCHAIN=$(cd "$MIRIDIR"; rustup show active-toolchain | head -n 1 | cut -d ' ' -f 1) + # Determine some toolchain properties TARGET=$(rustc +$TOOLCHAIN --version --verbose | grep "^host:" | cut -d ' ' -f 2) SYSROOT=$(rustc +$TOOLCHAIN --print sysroot) LIBDIR=$SYSROOT/lib/rustlib/$TARGET/lib - if ! test -d "$LIBDIR"; then echo "Something went wrong determining the library dir." echo "I got $LIBDIR but that does not exist." @@ -78,6 +78,7 @@ if ! test -d "$LIBDIR"; then exit 2 fi +# Prepare flags for cargo and rustc. CARGO="cargo +$TOOLCHAIN" if [ -z "$CARGO_INCREMENTAL" ]; then # Default CARGO_INCREMENTAL to 1. @@ -91,6 +92,19 @@ fi # We enable debug-assertions to get tracing. # We enable line-only debuginfo for backtraces. export RUSTFLAGS="-C link-args=-Wl,-rpath,$LIBDIR -C debug-assertions -C debuginfo=1 $RUSTFLAGS" +# Determine flags passed to all cargo invocations. +# This is a bit more annoying that one would hope due to +# . +case "$COMMAND" in +*-debug) + CARGO_INSTALL_FLAGS="--target $TARGET --debug $CARGO_EXTRA_FLAGS" + CARGO_BUILD_FLAGS="--target $TARGET $CARGO_EXTRA_FLAGS" + ;; +*) + CARGO_INSTALL_FLAGS="--target $TARGET $CARGO_EXTRA_FLAGS" + CARGO_BUILD_FLAGS="--target $TARGET --release $CARGO_EXTRA_FLAGS" + ;; +esac ## Helper functions @@ -119,20 +133,6 @@ find_sysroot() { ## Main -# Determine flags passed to all cargo invocations. -# This is a bit more annoying that one would hope due to -# . -case "$COMMAND" in -*-debug) - CARGO_INSTALL_FLAGS="--target $TARGET --debug $CARGO_EXTRA_FLAGS" - CARGO_BUILD_FLAGS="--target $TARGET $CARGO_EXTRA_FLAGS" - ;; -*) - CARGO_INSTALL_FLAGS="--target $TARGET $CARGO_EXTRA_FLAGS" - CARGO_BUILD_FLAGS="--target $TARGET --release $CARGO_EXTRA_FLAGS" - ;; -esac - # Run command. case "$COMMAND" in install|install-debug) From af39709a9c4aa053e31c09a5fbb488ed06cf55b0 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 1 Jul 2022 10:14:31 -0400 Subject: [PATCH 3373/3747] rustup --- rust-version | 2 +- src/concurrency/data_race.rs | 10 +++++----- src/stacked_borrows.rs | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/rust-version b/rust-version index 1ab8e6b5a8cea..4198e8cf3c086 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -bf45371f262e184b4a77adea88c8ac01ac79759b +ca1e68b3229e710c3948a361ee770d846a88e6da diff --git a/src/concurrency/data_race.rs b/src/concurrency/data_race.rs index c1bcd2368133b..7f6304c3815f1 100644 --- a/src/concurrency/data_race.rs +++ b/src/concurrency/data_race.rs @@ -535,7 +535,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); this.validate_overlapping_atomic(dest)?; - this.allow_data_races_mut(move |this| this.write_scalar(val, &(*dest).into()))?; + this.allow_data_races_mut(move |this| this.write_scalar(val, &dest.into()))?; this.validate_atomic_store(dest, atomic)?; // FIXME: it's not possible to get the value before write_scalar. A read_scalar will cause // side effects from a read the program did not perform. So we have to initialise @@ -562,7 +562,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { // Atomics wrap around on overflow. let val = this.binary_op(op, &old, rhs)?; let val = if neg { this.unary_op(mir::UnOp::Not, &val)? } else { val }; - this.allow_data_races_mut(|this| this.write_immediate(*val, &(*place).into()))?; + this.allow_data_races_mut(|this| this.write_immediate(*val, &place.into()))?; this.validate_atomic_rmw(place, atomic)?; @@ -587,7 +587,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { this.validate_overlapping_atomic(place)?; let old = this.allow_data_races_mut(|this| this.read_scalar(&place.into()))?; - this.allow_data_races_mut(|this| this.write_scalar(new, &(*place).into()))?; + this.allow_data_races_mut(|this| this.write_scalar(new, &place.into()))?; this.validate_atomic_rmw(place, atomic)?; @@ -616,7 +616,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { if lt { &rhs } else { &old } }; - this.allow_data_races_mut(|this| this.write_immediate(**new_val, &(*place).into()))?; + this.allow_data_races_mut(|this| this.write_immediate(**new_val, &place.into()))?; this.validate_atomic_rmw(place, atomic)?; @@ -675,7 +675,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { // if successful, perform a full rw-atomic validation // otherwise treat this as an atomic load with the fail ordering. if cmpxchg_success { - this.allow_data_races_mut(|this| this.write_scalar(new, &(*place).into()))?; + this.allow_data_races_mut(|this| this.write_scalar(new, &place.into()))?; this.validate_atomic_rmw(place, success)?; this.buffered_atomic_rmw(new, place, success, old.to_scalar_or_uninit())?; } else { diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 3fc0eaf10c094..5ca58d90e07d9 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -1097,7 +1097,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if let Some((mutbl, protector)) = qualify(place.layout.ty, self.kind) { let val = self.ecx.read_immediate(&place.into())?; let val = self.ecx.retag_reference(&val, mutbl, protector)?; - self.ecx.write_immediate(*val, &(*place).into())?; + self.ecx.write_immediate(*val, &place.into())?; } else { // Maybe we need to go deeper. self.walk_value(place)?; From 12d04ac4c4291c031b7d1cd63707a6cd59c895a8 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 1 Jul 2022 12:25:35 -0400 Subject: [PATCH 3374/3747] make clippy happy --- src/concurrency/data_race.rs | 6 +++--- src/eval.rs | 10 +++++----- src/stacked_borrows.rs | 4 ++-- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/concurrency/data_race.rs b/src/concurrency/data_race.rs index 7f6304c3815f1..36178269e025e 100644 --- a/src/concurrency/data_race.rs +++ b/src/concurrency/data_race.rs @@ -964,7 +964,7 @@ impl VClockAlloc { let (index, clocks) = global.current_thread_state(); let mut alloc_ranges = self.alloc_ranges.borrow_mut(); for (offset, range) in alloc_ranges.iter_mut(range.start, range.size) { - if let Err(DataRace) = range.read_race_detect(&*clocks, index) { + if let Err(DataRace) = range.read_race_detect(&clocks, index) { // Report data-race. return Self::report_data_race( global, @@ -992,7 +992,7 @@ impl VClockAlloc { if global.race_detecting() { let (index, clocks) = global.current_thread_state(); for (offset, range) in self.alloc_ranges.get_mut().iter_mut(range.start, range.size) { - if let Err(DataRace) = range.write_race_detect(&*clocks, index, write_type) { + if let Err(DataRace) = range.write_race_detect(&clocks, index, write_type) { // Report data-race return Self::report_data_race( global, @@ -1072,7 +1072,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { for (offset, range) in alloc_meta.alloc_ranges.borrow_mut().iter_mut(base_offset, size) { - if let Err(DataRace) = op(range, &mut *clocks, index, atomic) { + if let Err(DataRace) = op(range, &mut clocks, index, atomic) { mem::drop(clocks); return VClockAlloc::report_data_race( data_race, diff --git a/src/eval.rs b/src/eval.rs index c9fc05500a3c6..1536b826ac466 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -215,7 +215,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( let arg_place = ecx.allocate(ecx.layout_of(arg_type)?, MiriMemoryKind::Machine.into())?; ecx.write_os_str_to_c_str(OsStr::new(arg), arg_place.ptr, size)?; - ecx.mark_immutable(&*arg_place); + ecx.mark_immutable(&arg_place); argvs.push(arg_place.to_ref(&ecx)); } // Make an array with all these pointers, in the Miri memory. @@ -227,7 +227,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( let place = ecx.mplace_field(&argvs_place, idx)?; ecx.write_immediate(arg, &place.into())?; } - ecx.mark_immutable(&*argvs_place); + ecx.mark_immutable(&argvs_place); // A pointer to that place is the 3rd argument for main. let argv = argvs_place.to_ref(&ecx); // Store `argc` and `argv` for macOS `_NSGetArg{c,v}`. @@ -235,7 +235,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( let argc_place = ecx.allocate(ecx.machine.layouts.isize, MiriMemoryKind::Machine.into())?; ecx.write_scalar(argc, &argc_place.into())?; - ecx.mark_immutable(&*argc_place); + ecx.mark_immutable(&argc_place); ecx.machine.argc = Some(*argc_place); let argv_place = ecx.allocate( @@ -243,7 +243,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( MiriMemoryKind::Machine.into(), )?; ecx.write_immediate(argv, &argv_place.into())?; - ecx.mark_immutable(&*argv_place); + ecx.mark_immutable(&argv_place); ecx.machine.argv = Some(*argv_place); } // Store command line as UTF-16 for Windows `GetCommandLineW`. @@ -260,7 +260,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( let place = ecx.mplace_field(&cmd_place, idx)?; ecx.write_scalar(Scalar::from_u16(c), &place.into())?; } - ecx.mark_immutable(&*cmd_place); + ecx.mark_immutable(&cmd_place); } argv }; diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 5ca58d90e07d9..2cf5eb70c171f 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -928,7 +928,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx orig_tag, item, (alloc_id, range, offset), - &mut *global, + &mut global, current_span, history, exposed_tags, @@ -1090,7 +1090,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx #[inline(always)] fn ecx(&mut self) -> &mut MiriEvalContext<'mir, 'tcx> { - &mut self.ecx + self.ecx } fn visit_value(&mut self, place: &MPlaceTy<'tcx, Tag>) -> InterpResult<'tcx> { From dca2bb68b3010a7cd47ae1e79674dcc7812828ce Mon Sep 17 00:00:00 2001 From: InfRandomness Date: Fri, 1 Jul 2022 18:36:14 +0200 Subject: [PATCH 3375/3747] Add `__error` to freebsd shims Signed-off-by: InfRandomness --- src/shims/unix/freebsd/foreign_items.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/shims/unix/freebsd/foreign_items.rs b/src/shims/unix/freebsd/foreign_items.rs index cad1192337404..66e339cc4a820 100644 --- a/src/shims/unix/freebsd/foreign_items.rs +++ b/src/shims/unix/freebsd/foreign_items.rs @@ -24,6 +24,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; this.write_null(dest)?; } + + // errno + "__error" => { + let [] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let errno_place = this.last_error_place()?; + this.write_scalar(errno_place.to_ref(this).to_scalar()?, dest)?; + } + _ => return Ok(EmulateByNameResult::NotSupported), } Ok(EmulateByNameResult::NeedsJumping) From dc47649d215fea0c850b0c69c204f85c6cbdb77e Mon Sep 17 00:00:00 2001 From: InfRandomness Date: Fri, 1 Jul 2022 18:52:32 +0200 Subject: [PATCH 3376/3747] Add `current_dir_with_isolation` to freebsd tests list Signed-off-by: InfRandomness --- ci.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci.sh b/ci.sh index e9ebb6f136f4f..816fbb3101ca8 100755 --- a/ci.sh +++ b/ci.sh @@ -60,7 +60,7 @@ case $HOST_TARGET in MIRI_TEST_TARGET=i686-unknown-linux-gnu run_tests MIRI_TEST_TARGET=aarch64-apple-darwin run_tests MIRI_TEST_TARGET=i686-pc-windows-msvc run_tests - MIRI_TEST_TARGET=x86_64-unknown-freebsd run_tests_minimal hello integer vec + MIRI_TEST_TARGET=x86_64-unknown-freebsd run_tests_minimal hello integer vec current_dir_with_isolation MIRI_TEST_TARGET=thumbv7em-none-eabihf MIRI_NO_STD=1 run_tests_minimal no_std # no_std embedded architecture ;; x86_64-apple-darwin) From 734e8903f2b1a3165bda29318d5ab492186473e5 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 1 Jul 2022 14:12:25 -0400 Subject: [PATCH 3377/3747] more current_dir tests for freebsd --- ci.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci.sh b/ci.sh index 816fbb3101ca8..3d6bd817ff17a 100755 --- a/ci.sh +++ b/ci.sh @@ -60,7 +60,7 @@ case $HOST_TARGET in MIRI_TEST_TARGET=i686-unknown-linux-gnu run_tests MIRI_TEST_TARGET=aarch64-apple-darwin run_tests MIRI_TEST_TARGET=i686-pc-windows-msvc run_tests - MIRI_TEST_TARGET=x86_64-unknown-freebsd run_tests_minimal hello integer vec current_dir_with_isolation + MIRI_TEST_TARGET=x86_64-unknown-freebsd run_tests_minimal hello integer vec current_dir MIRI_TEST_TARGET=thumbv7em-none-eabihf MIRI_NO_STD=1 run_tests_minimal no_std # no_std embedded architecture ;; x86_64-apple-darwin) From ab0005bc38fcb6d57d3077adcc5f58c3853fe292 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 1 Jul 2022 14:13:36 -0400 Subject: [PATCH 3378/3747] run data_race tests on bsd --- ci.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci.sh b/ci.sh index 3d6bd817ff17a..5c7ab545f9581 100755 --- a/ci.sh +++ b/ci.sh @@ -60,7 +60,7 @@ case $HOST_TARGET in MIRI_TEST_TARGET=i686-unknown-linux-gnu run_tests MIRI_TEST_TARGET=aarch64-apple-darwin run_tests MIRI_TEST_TARGET=i686-pc-windows-msvc run_tests - MIRI_TEST_TARGET=x86_64-unknown-freebsd run_tests_minimal hello integer vec current_dir + MIRI_TEST_TARGET=x86_64-unknown-freebsd run_tests_minimal hello integer vec current_dir data_race MIRI_TEST_TARGET=thumbv7em-none-eabihf MIRI_NO_STD=1 run_tests_minimal no_std # no_std embedded architecture ;; x86_64-apple-darwin) From f238513efac3193ed7d05222d03b8052690de0a3 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 1 Jul 2022 16:21:46 -0400 Subject: [PATCH 3379/3747] rename some data_race types for more clarity --- src/concurrency/data_race.rs | 56 +++++----- src/concurrency/weak_memory.rs | 24 ++-- src/lib.rs | 2 +- src/shims/intrinsics.rs | 198 ++++++++++++++++----------------- src/shims/unix/linux/sync.rs | 6 +- src/shims/unix/sync.rs | 28 ++--- src/shims/windows/sync.rs | 4 +- 7 files changed, 159 insertions(+), 159 deletions(-) diff --git a/src/concurrency/data_race.rs b/src/concurrency/data_race.rs index 36178269e025e..ef0920d9698df 100644 --- a/src/concurrency/data_race.rs +++ b/src/concurrency/data_race.rs @@ -62,9 +62,9 @@ use super::weak_memory::EvalContextExt as _; pub type AllocExtra = VClockAlloc; -/// Valid atomic read-write operations, alias of atomic::Ordering (not non-exhaustive). +/// Valid atomic read-write orderings, alias of atomic::Ordering (not non-exhaustive). #[derive(Copy, Clone, PartialEq, Eq, Debug)] -pub enum AtomicRwOp { +pub enum AtomicRwOrd { Relaxed, Acquire, Release, @@ -72,25 +72,25 @@ pub enum AtomicRwOp { SeqCst, } -/// Valid atomic read operations, subset of atomic::Ordering. +/// Valid atomic read orderings, subset of atomic::Ordering. #[derive(Copy, Clone, PartialEq, Eq, Debug)] -pub enum AtomicReadOp { +pub enum AtomicReadOrd { Relaxed, Acquire, SeqCst, } -/// Valid atomic write operations, subset of atomic::Ordering. +/// Valid atomic write orderings, subset of atomic::Ordering. #[derive(Copy, Clone, PartialEq, Eq, Debug)] -pub enum AtomicWriteOp { +pub enum AtomicWriteOrd { Relaxed, Release, SeqCst, } -/// Valid atomic fence operations, subset of atomic::Ordering. +/// Valid atomic fence orderings, subset of atomic::Ordering. #[derive(Copy, Clone, PartialEq, Eq, Debug)] -pub enum AtomicFenceOp { +pub enum AtomicFenceOrd { Acquire, Release, AcqRel, @@ -486,7 +486,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { op: &OpTy<'tcx, Tag>, offset: u64, layout: TyAndLayout<'tcx>, - atomic: AtomicReadOp, + atomic: AtomicReadOrd, ) -> InterpResult<'tcx, ScalarMaybeUninit> { let this = self.eval_context_ref(); let value_place = this.deref_operand_and_offset(op, offset, layout)?; @@ -500,7 +500,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { offset: u64, value: impl Into>, layout: TyAndLayout<'tcx>, - atomic: AtomicWriteOp, + atomic: AtomicWriteOrd, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let value_place = this.deref_operand_and_offset(op, offset, layout)?; @@ -511,7 +511,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { fn read_scalar_atomic( &self, place: &MPlaceTy<'tcx, Tag>, - atomic: AtomicReadOp, + atomic: AtomicReadOrd, ) -> InterpResult<'tcx, ScalarMaybeUninit> { let this = self.eval_context_ref(); // This will read from the last store in the modification order of this location. In case @@ -531,7 +531,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { &mut self, val: ScalarMaybeUninit, dest: &MPlaceTy<'tcx, Tag>, - atomic: AtomicWriteOp, + atomic: AtomicWriteOrd, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); this.validate_overlapping_atomic(dest)?; @@ -552,7 +552,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { rhs: &ImmTy<'tcx, Tag>, op: mir::BinOp, neg: bool, - atomic: AtomicRwOp, + atomic: AtomicRwOrd, ) -> InterpResult<'tcx, ImmTy<'tcx, Tag>> { let this = self.eval_context_mut(); @@ -581,7 +581,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { &mut self, place: &MPlaceTy<'tcx, Tag>, new: ScalarMaybeUninit, - atomic: AtomicRwOp, + atomic: AtomicRwOrd, ) -> InterpResult<'tcx, ScalarMaybeUninit> { let this = self.eval_context_mut(); @@ -602,7 +602,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { place: &MPlaceTy<'tcx, Tag>, rhs: ImmTy<'tcx, Tag>, min: bool, - atomic: AtomicRwOp, + atomic: AtomicRwOrd, ) -> InterpResult<'tcx, ImmTy<'tcx, Tag>> { let this = self.eval_context_mut(); @@ -642,8 +642,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { place: &MPlaceTy<'tcx, Tag>, expect_old: &ImmTy<'tcx, Tag>, new: ScalarMaybeUninit, - success: AtomicRwOp, - fail: AtomicReadOp, + success: AtomicRwOrd, + fail: AtomicReadOrd, can_fail_spuriously: bool, ) -> InterpResult<'tcx, Immediate> { use rand::Rng as _; @@ -696,7 +696,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { fn validate_atomic_load( &self, place: &MPlaceTy<'tcx, Tag>, - atomic: AtomicReadOp, + atomic: AtomicReadOrd, ) -> InterpResult<'tcx> { let this = self.eval_context_ref(); this.validate_overlapping_atomic(place)?; @@ -705,7 +705,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { atomic, "Atomic Load", move |memory, clocks, index, atomic| { - if atomic == AtomicReadOp::Relaxed { + if atomic == AtomicReadOrd::Relaxed { memory.load_relaxed(&mut *clocks, index) } else { memory.load_acquire(&mut *clocks, index) @@ -719,7 +719,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { fn validate_atomic_store( &mut self, place: &MPlaceTy<'tcx, Tag>, - atomic: AtomicWriteOp, + atomic: AtomicWriteOrd, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); this.validate_overlapping_atomic(place)?; @@ -728,7 +728,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { atomic, "Atomic Store", move |memory, clocks, index, atomic| { - if atomic == AtomicWriteOp::Relaxed { + if atomic == AtomicWriteOrd::Relaxed { memory.store_relaxed(clocks, index) } else { memory.store_release(clocks, index) @@ -742,9 +742,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { fn validate_atomic_rmw( &mut self, place: &MPlaceTy<'tcx, Tag>, - atomic: AtomicRwOp, + atomic: AtomicRwOrd, ) -> InterpResult<'tcx> { - use AtomicRwOp::*; + use AtomicRwOrd::*; let acquire = matches!(atomic, Acquire | AcqRel | SeqCst); let release = matches!(atomic, Release | AcqRel | SeqCst); let this = self.eval_context_mut(); @@ -764,7 +764,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { } /// Update the data-race detector for an atomic fence on the current thread. - fn validate_atomic_fence(&mut self, atomic: AtomicFenceOp) -> InterpResult<'tcx> { + fn validate_atomic_fence(&mut self, atomic: AtomicFenceOrd) -> InterpResult<'tcx> { let this = self.eval_context_mut(); if let Some(data_race) = &mut this.machine.data_race { data_race.maybe_perform_sync_operation(|index, mut clocks| { @@ -773,22 +773,22 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { // Apply data-race detection for the current fences // this treats AcqRel and SeqCst as the same as an acquire // and release fence applied in the same timestamp. - if atomic != AtomicFenceOp::Release { + if atomic != AtomicFenceOrd::Release { // Either Acquire | AcqRel | SeqCst clocks.apply_acquire_fence(); } - if atomic != AtomicFenceOp::Acquire { + if atomic != AtomicFenceOrd::Acquire { // Either Release | AcqRel | SeqCst clocks.apply_release_fence(); } - if atomic == AtomicFenceOp::SeqCst { + if atomic == AtomicFenceOrd::SeqCst { data_race.last_sc_fence.borrow_mut().set_at_index(&clocks.clock, index); clocks.fence_seqcst.join(&data_race.last_sc_fence.borrow()); clocks.write_seqcst.join(&data_race.last_sc_write.borrow()); } // Increment timestamp in case of release semantics. - Ok(atomic != AtomicFenceOp::Acquire) + Ok(atomic != AtomicFenceOrd::Acquire) }) } else { Ok(()) diff --git a/src/concurrency/weak_memory.rs b/src/concurrency/weak_memory.rs index e5f58ee5ddd0b..28a54c2e3b6c1 100644 --- a/src/concurrency/weak_memory.rs +++ b/src/concurrency/weak_memory.rs @@ -82,7 +82,7 @@ use rustc_const_eval::interpret::{ }; use rustc_data_structures::fx::FxHashMap; -use crate::{AtomicReadOp, AtomicRwOp, AtomicWriteOp, Tag, VClock, VTimestamp, VectorIdx}; +use crate::{AtomicReadOrd, AtomicRwOrd, AtomicWriteOrd, Tag, VClock, VTimestamp, VectorIdx}; use super::{ data_race::{GlobalState, ThreadClockSet}, @@ -443,7 +443,7 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>: &mut self, new_val: ScalarMaybeUninit, place: &MPlaceTy<'tcx, Tag>, - atomic: AtomicRwOp, + atomic: AtomicRwOrd, init: ScalarMaybeUninit, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); @@ -453,14 +453,14 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>: crate::Evaluator { data_race: Some(global), .. }, ) = this.get_alloc_extra_mut(alloc_id)? { - if atomic == AtomicRwOp::SeqCst { + if atomic == AtomicRwOrd::SeqCst { global.sc_read(); global.sc_write(); } let range = alloc_range(base_offset, place.layout.size); let buffer = alloc_buffers.get_or_create_store_buffer_mut(range, init)?; buffer.read_from_last_store(global); - buffer.buffered_write(new_val, global, atomic == AtomicRwOp::SeqCst)?; + buffer.buffered_write(new_val, global, atomic == AtomicRwOrd::SeqCst)?; } Ok(()) } @@ -468,7 +468,7 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>: fn buffered_atomic_read( &self, place: &MPlaceTy<'tcx, Tag>, - atomic: AtomicReadOp, + atomic: AtomicReadOrd, latest_in_mo: ScalarMaybeUninit, validate: impl FnOnce() -> InterpResult<'tcx>, ) -> InterpResult<'tcx, ScalarMaybeUninit> { @@ -476,7 +476,7 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>: if let Some(global) = &this.machine.data_race { let (alloc_id, base_offset, ..) = this.ptr_get_alloc_id(place.ptr)?; if let Some(alloc_buffers) = this.get_alloc_extra(alloc_id)?.weak_memory.as_ref() { - if atomic == AtomicReadOp::SeqCst { + if atomic == AtomicReadOrd::SeqCst { global.sc_read(); } let mut rng = this.machine.rng.borrow_mut(); @@ -486,7 +486,7 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>: )?; let loaded = buffer.buffered_read( global, - atomic == AtomicReadOp::SeqCst, + atomic == AtomicReadOrd::SeqCst, &mut *rng, validate, )?; @@ -504,7 +504,7 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>: &mut self, val: ScalarMaybeUninit, dest: &MPlaceTy<'tcx, Tag>, - atomic: AtomicWriteOp, + atomic: AtomicWriteOrd, init: ScalarMaybeUninit, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); @@ -514,7 +514,7 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>: crate::Evaluator { data_race: Some(global), .. }, ) = this.get_alloc_extra_mut(alloc_id)? { - if atomic == AtomicWriteOp::SeqCst { + if atomic == AtomicWriteOrd::SeqCst { global.sc_write(); } @@ -535,7 +535,7 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>: buffer.buffer.pop_front(); } - buffer.buffered_write(val, global, atomic == AtomicWriteOp::SeqCst)?; + buffer.buffered_write(val, global, atomic == AtomicWriteOrd::SeqCst)?; } // Caller should've written to dest with the vanilla scalar write, we do nothing here @@ -548,13 +548,13 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>: fn perform_read_on_buffered_latest( &self, place: &MPlaceTy<'tcx, Tag>, - atomic: AtomicReadOp, + atomic: AtomicReadOrd, init: ScalarMaybeUninit, ) -> InterpResult<'tcx> { let this = self.eval_context_ref(); if let Some(global) = &this.machine.data_race { - if atomic == AtomicReadOp::SeqCst { + if atomic == AtomicReadOrd::SeqCst { global.sc_read(); } let size = place.layout.size; diff --git a/src/lib.rs b/src/lib.rs index e199fae31ee82..b3d408a6dc072 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -70,7 +70,7 @@ pub use crate::shims::tls::{EvalContextExt as _, TlsData}; pub use crate::shims::EvalContextExt as _; pub use crate::concurrency::data_race::{ - AtomicFenceOp, AtomicReadOp, AtomicRwOp, AtomicWriteOp, + AtomicFenceOrd, AtomicReadOrd, AtomicRwOrd, AtomicWriteOrd, EvalContextExt as DataRaceEvalContextExt, }; pub use crate::diagnostics::{ diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 5926832011583..9705f56cd1077 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -864,216 +864,216 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // Atomic operations - "atomic_load_seqcst" => this.atomic_load(args, dest, AtomicReadOp::SeqCst)?, - "atomic_load_relaxed" => this.atomic_load(args, dest, AtomicReadOp::Relaxed)?, - "atomic_load_acquire" => this.atomic_load(args, dest, AtomicReadOp::Acquire)?, + "atomic_load_seqcst" => this.atomic_load(args, dest, AtomicReadOrd::SeqCst)?, + "atomic_load_relaxed" => this.atomic_load(args, dest, AtomicReadOrd::Relaxed)?, + "atomic_load_acquire" => this.atomic_load(args, dest, AtomicReadOrd::Acquire)?, - "atomic_store_seqcst" => this.atomic_store(args, AtomicWriteOp::SeqCst)?, - "atomic_store_relaxed" => this.atomic_store(args, AtomicWriteOp::Relaxed)?, - "atomic_store_release" => this.atomic_store(args, AtomicWriteOp::Release)?, + "atomic_store_seqcst" => this.atomic_store(args, AtomicWriteOrd::SeqCst)?, + "atomic_store_relaxed" => this.atomic_store(args, AtomicWriteOrd::Relaxed)?, + "atomic_store_release" => this.atomic_store(args, AtomicWriteOrd::Release)?, - "atomic_fence_acquire" => this.atomic_fence(args, AtomicFenceOp::Acquire)?, - "atomic_fence_release" => this.atomic_fence(args, AtomicFenceOp::Release)?, - "atomic_fence_acqrel" => this.atomic_fence(args, AtomicFenceOp::AcqRel)?, - "atomic_fence_seqcst" => this.atomic_fence(args, AtomicFenceOp::SeqCst)?, + "atomic_fence_acquire" => this.atomic_fence(args, AtomicFenceOrd::Acquire)?, + "atomic_fence_release" => this.atomic_fence(args, AtomicFenceOrd::Release)?, + "atomic_fence_acqrel" => this.atomic_fence(args, AtomicFenceOrd::AcqRel)?, + "atomic_fence_seqcst" => this.atomic_fence(args, AtomicFenceOrd::SeqCst)?, "atomic_singlethreadfence_acquire" => - this.compiler_fence(args, AtomicFenceOp::Acquire)?, + this.compiler_fence(args, AtomicFenceOrd::Acquire)?, "atomic_singlethreadfence_release" => - this.compiler_fence(args, AtomicFenceOp::Release)?, + this.compiler_fence(args, AtomicFenceOrd::Release)?, "atomic_singlethreadfence_acqrel" => - this.compiler_fence(args, AtomicFenceOp::AcqRel)?, + this.compiler_fence(args, AtomicFenceOrd::AcqRel)?, "atomic_singlethreadfence_seqcst" => - this.compiler_fence(args, AtomicFenceOp::SeqCst)?, + this.compiler_fence(args, AtomicFenceOrd::SeqCst)?, - "atomic_xchg_seqcst" => this.atomic_exchange(args, dest, AtomicRwOp::SeqCst)?, - "atomic_xchg_acquire" => this.atomic_exchange(args, dest, AtomicRwOp::Acquire)?, - "atomic_xchg_release" => this.atomic_exchange(args, dest, AtomicRwOp::Release)?, - "atomic_xchg_acqrel" => this.atomic_exchange(args, dest, AtomicRwOp::AcqRel)?, - "atomic_xchg_relaxed" => this.atomic_exchange(args, dest, AtomicRwOp::Relaxed)?, + "atomic_xchg_seqcst" => this.atomic_exchange(args, dest, AtomicRwOrd::SeqCst)?, + "atomic_xchg_acquire" => this.atomic_exchange(args, dest, AtomicRwOrd::Acquire)?, + "atomic_xchg_release" => this.atomic_exchange(args, dest, AtomicRwOrd::Release)?, + "atomic_xchg_acqrel" => this.atomic_exchange(args, dest, AtomicRwOrd::AcqRel)?, + "atomic_xchg_relaxed" => this.atomic_exchange(args, dest, AtomicRwOrd::Relaxed)?, #[rustfmt::skip] "atomic_cxchg_seqcst_seqcst" => - this.atomic_compare_exchange(args, dest, AtomicRwOp::SeqCst, AtomicReadOp::SeqCst)?, + this.atomic_compare_exchange(args, dest, AtomicRwOrd::SeqCst, AtomicReadOrd::SeqCst)?, #[rustfmt::skip] "atomic_cxchg_acquire_acquire" => - this.atomic_compare_exchange(args, dest, AtomicRwOp::Acquire, AtomicReadOp::Acquire)?, + this.atomic_compare_exchange(args, dest, AtomicRwOrd::Acquire, AtomicReadOrd::Acquire)?, #[rustfmt::skip] "atomic_cxchg_release_relaxed" => - this.atomic_compare_exchange(args, dest, AtomicRwOp::Release, AtomicReadOp::Relaxed)?, + this.atomic_compare_exchange(args, dest, AtomicRwOrd::Release, AtomicReadOrd::Relaxed)?, #[rustfmt::skip] "atomic_cxchg_acqrel_acquire" => - this.atomic_compare_exchange(args, dest, AtomicRwOp::AcqRel, AtomicReadOp::Acquire)?, + this.atomic_compare_exchange(args, dest, AtomicRwOrd::AcqRel, AtomicReadOrd::Acquire)?, #[rustfmt::skip] "atomic_cxchg_relaxed_relaxed" => - this.atomic_compare_exchange(args, dest, AtomicRwOp::Relaxed, AtomicReadOp::Relaxed)?, + this.atomic_compare_exchange(args, dest, AtomicRwOrd::Relaxed, AtomicReadOrd::Relaxed)?, #[rustfmt::skip] "atomic_cxchg_acquire_relaxed" => - this.atomic_compare_exchange(args, dest, AtomicRwOp::Acquire, AtomicReadOp::Relaxed)?, + this.atomic_compare_exchange(args, dest, AtomicRwOrd::Acquire, AtomicReadOrd::Relaxed)?, #[rustfmt::skip] "atomic_cxchg_acqrel_relaxed" => - this.atomic_compare_exchange(args, dest, AtomicRwOp::AcqRel, AtomicReadOp::Relaxed)?, + this.atomic_compare_exchange(args, dest, AtomicRwOrd::AcqRel, AtomicReadOrd::Relaxed)?, #[rustfmt::skip] "atomic_cxchg_seqcst_relaxed" => - this.atomic_compare_exchange(args, dest, AtomicRwOp::SeqCst, AtomicReadOp::Relaxed)?, + this.atomic_compare_exchange(args, dest, AtomicRwOrd::SeqCst, AtomicReadOrd::Relaxed)?, #[rustfmt::skip] "atomic_cxchg_seqcst_acquire" => - this.atomic_compare_exchange(args, dest, AtomicRwOp::SeqCst, AtomicReadOp::Acquire)?, + this.atomic_compare_exchange(args, dest, AtomicRwOrd::SeqCst, AtomicReadOrd::Acquire)?, #[rustfmt::skip] "atomic_cxchgweak_seqcst_seqcst" => - this.atomic_compare_exchange_weak(args, dest, AtomicRwOp::SeqCst, AtomicReadOp::SeqCst)?, + this.atomic_compare_exchange_weak(args, dest, AtomicRwOrd::SeqCst, AtomicReadOrd::SeqCst)?, #[rustfmt::skip] "atomic_cxchgweak_acquire_acquire" => - this.atomic_compare_exchange_weak(args, dest, AtomicRwOp::Acquire, AtomicReadOp::Acquire)?, + this.atomic_compare_exchange_weak(args, dest, AtomicRwOrd::Acquire, AtomicReadOrd::Acquire)?, #[rustfmt::skip] "atomic_cxchgweak_release_relaxed" => - this.atomic_compare_exchange_weak(args, dest, AtomicRwOp::Release, AtomicReadOp::Relaxed)?, + this.atomic_compare_exchange_weak(args, dest, AtomicRwOrd::Release, AtomicReadOrd::Relaxed)?, #[rustfmt::skip] "atomic_cxchgweak_acqrel_acquire" => - this.atomic_compare_exchange_weak(args, dest, AtomicRwOp::AcqRel, AtomicReadOp::Acquire)?, + this.atomic_compare_exchange_weak(args, dest, AtomicRwOrd::AcqRel, AtomicReadOrd::Acquire)?, #[rustfmt::skip] "atomic_cxchgweak_relaxed_relaxed" => - this.atomic_compare_exchange_weak(args, dest, AtomicRwOp::Relaxed, AtomicReadOp::Relaxed)?, + this.atomic_compare_exchange_weak(args, dest, AtomicRwOrd::Relaxed, AtomicReadOrd::Relaxed)?, #[rustfmt::skip] "atomic_cxchgweak_acquire_relaxed" => - this.atomic_compare_exchange_weak(args, dest, AtomicRwOp::Acquire, AtomicReadOp::Relaxed)?, + this.atomic_compare_exchange_weak(args, dest, AtomicRwOrd::Acquire, AtomicReadOrd::Relaxed)?, #[rustfmt::skip] "atomic_cxchgweak_acqrel_relaxed" => - this.atomic_compare_exchange_weak(args, dest, AtomicRwOp::AcqRel, AtomicReadOp::Relaxed)?, + this.atomic_compare_exchange_weak(args, dest, AtomicRwOrd::AcqRel, AtomicReadOrd::Relaxed)?, #[rustfmt::skip] "atomic_cxchgweak_seqcst_relaxed" => - this.atomic_compare_exchange_weak(args, dest, AtomicRwOp::SeqCst, AtomicReadOp::Relaxed)?, + this.atomic_compare_exchange_weak(args, dest, AtomicRwOrd::SeqCst, AtomicReadOrd::Relaxed)?, #[rustfmt::skip] "atomic_cxchgweak_seqcst_acquire" => - this.atomic_compare_exchange_weak(args, dest, AtomicRwOp::SeqCst, AtomicReadOp::Acquire)?, + this.atomic_compare_exchange_weak(args, dest, AtomicRwOrd::SeqCst, AtomicReadOrd::Acquire)?, #[rustfmt::skip] "atomic_or_seqcst" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitOr, false), AtomicRwOp::SeqCst)?, + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitOr, false), AtomicRwOrd::SeqCst)?, #[rustfmt::skip] "atomic_or_acquire" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitOr, false), AtomicRwOp::Acquire)?, + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitOr, false), AtomicRwOrd::Acquire)?, #[rustfmt::skip] "atomic_or_release" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitOr, false), AtomicRwOp::Release)?, + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitOr, false), AtomicRwOrd::Release)?, #[rustfmt::skip] "atomic_or_acqrel" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitOr, false), AtomicRwOp::AcqRel)?, + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitOr, false), AtomicRwOrd::AcqRel)?, #[rustfmt::skip] "atomic_or_relaxed" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitOr, false), AtomicRwOp::Relaxed)?, + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitOr, false), AtomicRwOrd::Relaxed)?, #[rustfmt::skip] "atomic_xor_seqcst" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitXor, false), AtomicRwOp::SeqCst)?, + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitXor, false), AtomicRwOrd::SeqCst)?, #[rustfmt::skip] "atomic_xor_acquire" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitXor, false), AtomicRwOp::Acquire)?, + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitXor, false), AtomicRwOrd::Acquire)?, #[rustfmt::skip] "atomic_xor_release" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitXor, false), AtomicRwOp::Release)?, + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitXor, false), AtomicRwOrd::Release)?, #[rustfmt::skip] "atomic_xor_acqrel" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitXor, false), AtomicRwOp::AcqRel)?, + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitXor, false), AtomicRwOrd::AcqRel)?, #[rustfmt::skip] "atomic_xor_relaxed" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitXor, false), AtomicRwOp::Relaxed)?, + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitXor, false), AtomicRwOrd::Relaxed)?, #[rustfmt::skip] "atomic_and_seqcst" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitAnd, false), AtomicRwOp::SeqCst)?, + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitAnd, false), AtomicRwOrd::SeqCst)?, #[rustfmt::skip] "atomic_and_acquire" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitAnd, false), AtomicRwOp::Acquire)?, + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitAnd, false), AtomicRwOrd::Acquire)?, #[rustfmt::skip] "atomic_and_release" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitAnd, false), AtomicRwOp::Release)?, + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitAnd, false), AtomicRwOrd::Release)?, #[rustfmt::skip] "atomic_and_acqrel" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitAnd, false), AtomicRwOp::AcqRel)?, + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitAnd, false), AtomicRwOrd::AcqRel)?, #[rustfmt::skip] "atomic_and_relaxed" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitAnd, false), AtomicRwOp::Relaxed)?, + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitAnd, false), AtomicRwOrd::Relaxed)?, #[rustfmt::skip] "atomic_nand_seqcst" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitAnd, true), AtomicRwOp::SeqCst)?, + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitAnd, true), AtomicRwOrd::SeqCst)?, #[rustfmt::skip] "atomic_nand_acquire" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitAnd, true), AtomicRwOp::Acquire)?, + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitAnd, true), AtomicRwOrd::Acquire)?, #[rustfmt::skip] "atomic_nand_release" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitAnd, true), AtomicRwOp::Release)?, + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitAnd, true), AtomicRwOrd::Release)?, #[rustfmt::skip] "atomic_nand_acqrel" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitAnd, true), AtomicRwOp::AcqRel)?, + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitAnd, true), AtomicRwOrd::AcqRel)?, #[rustfmt::skip] "atomic_nand_relaxed" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitAnd, true), AtomicRwOp::Relaxed)?, + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitAnd, true), AtomicRwOrd::Relaxed)?, #[rustfmt::skip] "atomic_xadd_seqcst" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::Add, false), AtomicRwOp::SeqCst)?, + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::Add, false), AtomicRwOrd::SeqCst)?, #[rustfmt::skip] "atomic_xadd_acquire" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::Add, false), AtomicRwOp::Acquire)?, + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::Add, false), AtomicRwOrd::Acquire)?, #[rustfmt::skip] "atomic_xadd_release" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::Add, false), AtomicRwOp::Release)?, + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::Add, false), AtomicRwOrd::Release)?, #[rustfmt::skip] "atomic_xadd_acqrel" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::Add, false), AtomicRwOp::AcqRel)?, + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::Add, false), AtomicRwOrd::AcqRel)?, #[rustfmt::skip] "atomic_xadd_relaxed" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::Add, false), AtomicRwOp::Relaxed)?, + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::Add, false), AtomicRwOrd::Relaxed)?, #[rustfmt::skip] "atomic_xsub_seqcst" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::Sub, false), AtomicRwOp::SeqCst)?, + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::Sub, false), AtomicRwOrd::SeqCst)?, #[rustfmt::skip] "atomic_xsub_acquire" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::Sub, false), AtomicRwOp::Acquire)?, + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::Sub, false), AtomicRwOrd::Acquire)?, #[rustfmt::skip] "atomic_xsub_release" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::Sub, false), AtomicRwOp::Release)?, + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::Sub, false), AtomicRwOrd::Release)?, #[rustfmt::skip] "atomic_xsub_acqrel" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::Sub, false), AtomicRwOp::AcqRel)?, + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::Sub, false), AtomicRwOrd::AcqRel)?, #[rustfmt::skip] "atomic_xsub_relaxed" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::Sub, false), AtomicRwOp::Relaxed)?, - "atomic_min_seqcst" => this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOp::SeqCst)?, + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::Sub, false), AtomicRwOrd::Relaxed)?, + "atomic_min_seqcst" => this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOrd::SeqCst)?, "atomic_min_acquire" => - this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOp::Acquire)?, + this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOrd::Acquire)?, "atomic_min_release" => - this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOp::Release)?, - "atomic_min_acqrel" => this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOp::AcqRel)?, + this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOrd::Release)?, + "atomic_min_acqrel" => this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOrd::AcqRel)?, "atomic_min_relaxed" => - this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOp::Relaxed)?, - "atomic_max_seqcst" => this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOp::SeqCst)?, + this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOrd::Relaxed)?, + "atomic_max_seqcst" => this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOrd::SeqCst)?, "atomic_max_acquire" => - this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOp::Acquire)?, + this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOrd::Acquire)?, "atomic_max_release" => - this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOp::Release)?, - "atomic_max_acqrel" => this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOp::AcqRel)?, + this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOrd::Release)?, + "atomic_max_acqrel" => this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOrd::AcqRel)?, "atomic_max_relaxed" => - this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOp::Relaxed)?, + this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOrd::Relaxed)?, "atomic_umin_seqcst" => - this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOp::SeqCst)?, + this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOrd::SeqCst)?, "atomic_umin_acquire" => - this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOp::Acquire)?, + this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOrd::Acquire)?, "atomic_umin_release" => - this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOp::Release)?, + this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOrd::Release)?, "atomic_umin_acqrel" => - this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOp::AcqRel)?, + this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOrd::AcqRel)?, "atomic_umin_relaxed" => - this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOp::Relaxed)?, + this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOrd::Relaxed)?, "atomic_umax_seqcst" => - this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOp::SeqCst)?, + this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOrd::SeqCst)?, "atomic_umax_acquire" => - this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOp::Acquire)?, + this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOrd::Acquire)?, "atomic_umax_release" => - this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOp::Release)?, + this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOrd::Release)?, "atomic_umax_acqrel" => - this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOp::AcqRel)?, + this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOrd::AcqRel)?, "atomic_umax_relaxed" => - this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOp::Relaxed)?, + this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOrd::Relaxed)?, // Other "exact_div" => { @@ -1101,7 +1101,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx &mut self, args: &[OpTy<'tcx, Tag>], dest: &PlaceTy<'tcx, Tag>, - atomic: AtomicReadOp, + atomic: AtomicReadOrd, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); @@ -1129,7 +1129,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn atomic_store( &mut self, args: &[OpTy<'tcx, Tag>], - atomic: AtomicWriteOp, + atomic: AtomicWriteOrd, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); @@ -1156,7 +1156,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn compiler_fence( &mut self, args: &[OpTy<'tcx, Tag>], - atomic: AtomicFenceOp, + atomic: AtomicFenceOrd, ) -> InterpResult<'tcx> { let [] = check_arg_count(args)?; let _ = atomic; @@ -1167,7 +1167,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn atomic_fence( &mut self, args: &[OpTy<'tcx, Tag>], - atomic: AtomicFenceOp, + atomic: AtomicFenceOrd, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let [] = check_arg_count(args)?; @@ -1180,7 +1180,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx args: &[OpTy<'tcx, Tag>], dest: &PlaceTy<'tcx, Tag>, atomic_op: AtomicOp, - atomic: AtomicRwOp, + atomic: AtomicRwOrd, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); @@ -1226,7 +1226,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx &mut self, args: &[OpTy<'tcx, Tag>], dest: &PlaceTy<'tcx, Tag>, - atomic: AtomicRwOp, + atomic: AtomicRwOrd, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); @@ -1254,8 +1254,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx &mut self, args: &[OpTy<'tcx, Tag>], dest: &PlaceTy<'tcx, Tag>, - success: AtomicRwOp, - fail: AtomicReadOp, + success: AtomicRwOrd, + fail: AtomicReadOrd, can_fail_spuriously: bool, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); @@ -1294,8 +1294,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx &mut self, args: &[OpTy<'tcx, Tag>], dest: &PlaceTy<'tcx, Tag>, - success: AtomicRwOp, - fail: AtomicReadOp, + success: AtomicRwOrd, + fail: AtomicReadOrd, ) -> InterpResult<'tcx> { self.atomic_compare_exchange_impl(args, dest, success, fail, false) } @@ -1304,8 +1304,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx &mut self, args: &[OpTy<'tcx, Tag>], dest: &PlaceTy<'tcx, Tag>, - success: AtomicRwOp, - fail: AtomicReadOp, + success: AtomicRwOrd, + fail: AtomicReadOrd, ) -> InterpResult<'tcx> { self.atomic_compare_exchange_impl(args, dest, success, fail, true) } diff --git a/src/shims/unix/linux/sync.rs b/src/shims/unix/linux/sync.rs index 6be1e672f85f0..a0e35c730c3d6 100644 --- a/src/shims/unix/linux/sync.rs +++ b/src/shims/unix/linux/sync.rs @@ -169,7 +169,7 @@ pub fn futex<'tcx>( // // Thankfully, preemptions cannot happen inside a Miri shim, so we do not need to // do anything special to guarantee fence-load-comparison atomicity. - this.atomic_fence(&[], AtomicFenceOp::SeqCst)?; + this.atomic_fence(&[], AtomicFenceOrd::SeqCst)?; // Read an `i32` through the pointer, regardless of any wrapper types. // It's not uncommon for `addr` to be passed as another type than `*mut i32`, such as `*const AtomicI32`. let futex_val = this @@ -177,7 +177,7 @@ pub fn futex<'tcx>( &addr.into(), 0, this.machine.layouts.i32, - AtomicReadOp::Relaxed, + AtomicReadOrd::Relaxed, )? .to_i32()?; if val == futex_val { @@ -240,7 +240,7 @@ pub fn futex<'tcx>( // Together with the SeqCst fence in futex_wait, this makes sure that futex_wait // will see the latest value on addr which could be changed by our caller // before doing the syscall. - this.atomic_fence(&[], AtomicFenceOp::SeqCst)?; + this.atomic_fence(&[], AtomicFenceOrd::SeqCst)?; let mut n = 0; for _ in 0..val { if let Some(thread) = this.futex_wake(addr_usize, bitset) { diff --git a/src/shims/unix/sync.rs b/src/shims/unix/sync.rs index 373996312eaf6..ae63907c2c865 100644 --- a/src/shims/unix/sync.rs +++ b/src/shims/unix/sync.rs @@ -68,7 +68,7 @@ fn mutex_get_kind<'mir, 'tcx: 'mir>( mutex_op, offset, ecx.machine.layouts.i32, - AtomicReadOp::Relaxed, + AtomicReadOrd::Relaxed, ) } @@ -83,7 +83,7 @@ fn mutex_set_kind<'mir, 'tcx: 'mir>( offset, kind, layout_of_maybe_uninit(ecx.tcx, ecx.tcx.types.i32), - AtomicWriteOp::Relaxed, + AtomicWriteOrd::Relaxed, ) } @@ -91,7 +91,7 @@ fn mutex_get_id<'mir, 'tcx: 'mir>( ecx: &MiriEvalContext<'mir, 'tcx>, mutex_op: &OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, ScalarMaybeUninit> { - ecx.read_scalar_at_offset_atomic(mutex_op, 4, ecx.machine.layouts.u32, AtomicReadOp::Relaxed) + ecx.read_scalar_at_offset_atomic(mutex_op, 4, ecx.machine.layouts.u32, AtomicReadOrd::Relaxed) } fn mutex_set_id<'mir, 'tcx: 'mir>( @@ -104,7 +104,7 @@ fn mutex_set_id<'mir, 'tcx: 'mir>( 4, id, layout_of_maybe_uninit(ecx.tcx, ecx.tcx.types.u32), - AtomicWriteOp::Relaxed, + AtomicWriteOrd::Relaxed, ) } @@ -120,8 +120,8 @@ fn mutex_get_or_create_id<'mir, 'tcx: 'mir>( &value_place, &ImmTy::from_uint(0u32, ecx.machine.layouts.u32), next_id.to_u32_scalar().into(), - AtomicRwOp::Relaxed, - AtomicReadOp::Relaxed, + AtomicRwOrd::Relaxed, + AtomicReadOrd::Relaxed, false, )? .to_scalar_pair() @@ -147,7 +147,7 @@ fn rwlock_get_id<'mir, 'tcx: 'mir>( ecx: &MiriEvalContext<'mir, 'tcx>, rwlock_op: &OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, ScalarMaybeUninit> { - ecx.read_scalar_at_offset_atomic(rwlock_op, 4, ecx.machine.layouts.u32, AtomicReadOp::Relaxed) + ecx.read_scalar_at_offset_atomic(rwlock_op, 4, ecx.machine.layouts.u32, AtomicReadOrd::Relaxed) } fn rwlock_set_id<'mir, 'tcx: 'mir>( @@ -160,7 +160,7 @@ fn rwlock_set_id<'mir, 'tcx: 'mir>( 4, id, layout_of_maybe_uninit(ecx.tcx, ecx.tcx.types.u32), - AtomicWriteOp::Relaxed, + AtomicWriteOrd::Relaxed, ) } @@ -176,8 +176,8 @@ fn rwlock_get_or_create_id<'mir, 'tcx: 'mir>( &value_place, &ImmTy::from_uint(0u32, ecx.machine.layouts.u32), next_id.to_u32_scalar().into(), - AtomicRwOp::Relaxed, - AtomicReadOp::Relaxed, + AtomicRwOrd::Relaxed, + AtomicReadOrd::Relaxed, false, )? .to_scalar_pair() @@ -231,7 +231,7 @@ fn cond_get_id<'mir, 'tcx: 'mir>( ecx: &MiriEvalContext<'mir, 'tcx>, cond_op: &OpTy<'tcx, Tag>, ) -> InterpResult<'tcx, ScalarMaybeUninit> { - ecx.read_scalar_at_offset_atomic(cond_op, 4, ecx.machine.layouts.u32, AtomicReadOp::Relaxed) + ecx.read_scalar_at_offset_atomic(cond_op, 4, ecx.machine.layouts.u32, AtomicReadOrd::Relaxed) } fn cond_set_id<'mir, 'tcx: 'mir>( @@ -244,7 +244,7 @@ fn cond_set_id<'mir, 'tcx: 'mir>( 4, id, layout_of_maybe_uninit(ecx.tcx, ecx.tcx.types.u32), - AtomicWriteOp::Relaxed, + AtomicWriteOrd::Relaxed, ) } @@ -260,8 +260,8 @@ fn cond_get_or_create_id<'mir, 'tcx: 'mir>( &value_place, &ImmTy::from_uint(0u32, ecx.machine.layouts.u32), next_id.to_u32_scalar().into(), - AtomicRwOp::Relaxed, - AtomicReadOp::Relaxed, + AtomicRwOrd::Relaxed, + AtomicReadOrd::Relaxed, false, )? .to_scalar_pair() diff --git a/src/shims/windows/sync.rs b/src/shims/windows/sync.rs index 6a6b2269e62a0..35603f7f38632 100644 --- a/src/shims/windows/sync.rs +++ b/src/shims/windows/sync.rs @@ -15,8 +15,8 @@ fn srwlock_get_or_create_id<'mir, 'tcx: 'mir>( &value_place, &ImmTy::from_uint(0u32, ecx.machine.layouts.u32), next_id.to_u32_scalar().into(), - AtomicRwOp::Relaxed, - AtomicReadOp::Relaxed, + AtomicRwOrd::Relaxed, + AtomicReadOrd::Relaxed, false, )? .to_scalar_pair() From dfdedae840a3703fc8fe4e7c958645f416087625 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 1 Jul 2022 17:07:29 -0400 Subject: [PATCH 3380/3747] avoid copying thread manager state in data race detector --- src/concurrency/data_race.rs | 224 +++++++++++++++------------------ src/concurrency/weak_memory.rs | 54 ++++---- src/machine.rs | 28 ++++- src/shims/intrinsics.rs | 12 +- src/thread.rs | 47 ++++--- 5 files changed, 186 insertions(+), 179 deletions(-) diff --git a/src/concurrency/data_race.rs b/src/concurrency/data_race.rs index ef0920d9698df..205b56ca4c071 100644 --- a/src/concurrency/data_race.rs +++ b/src/concurrency/data_race.rs @@ -39,11 +39,6 @@ //! so some atomic operations that only perform acquires do not increment the timestamp. Due to shared //! code some atomic operations may increment the timestamp when not necessary but this has no effect //! on the data-race detection code. -//! -//! FIXME: -//! currently we have our own local copy of the currently active thread index and names, this is due -//! in part to the inability to access the current location of threads.active_thread inside the AllocExtra -//! read, write and deallocate functions and should be cleaned up in the future. use std::{ cell::{Cell, Ref, RefCell, RefMut}, @@ -767,7 +762,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { fn validate_atomic_fence(&mut self, atomic: AtomicFenceOrd) -> InterpResult<'tcx> { let this = self.eval_context_mut(); if let Some(data_race) = &mut this.machine.data_race { - data_race.maybe_perform_sync_operation(|index, mut clocks| { + data_race.maybe_perform_sync_operation(&this.machine.threads, |index, mut clocks| { log::trace!("Atomic fence on {:?} with ordering {:?}", index, atomic); // Apply data-race detection for the current fences @@ -807,6 +802,7 @@ impl VClockAlloc { /// Create a new data-race detector for newly allocated memory. pub fn new_allocation( global: &GlobalState, + thread_mgr: &ThreadManager<'_, '_>, len: Size, kind: MemoryKind, ) -> VClockAlloc { @@ -816,7 +812,7 @@ impl VClockAlloc { MiriMemoryKind::Rust | MiriMemoryKind::C | MiriMemoryKind::WinHeap, ) | MemoryKind::Stack => { - let (alloc_index, clocks) = global.current_thread_state(); + let (alloc_index, clocks) = global.current_thread_state(thread_mgr); let alloc_timestamp = clocks.clock[alloc_index]; (alloc_timestamp, alloc_index) } @@ -878,12 +874,13 @@ impl VClockAlloc { #[inline(never)] fn report_data_race<'tcx>( global: &GlobalState, + thread_mgr: &ThreadManager<'_, '_>, range: &MemoryCellClocks, action: &str, is_atomic: bool, ptr_dbg: Pointer, ) -> InterpResult<'tcx> { - let (current_index, current_clocks) = global.current_thread_state(); + let (current_index, current_clocks) = global.current_thread_state(thread_mgr); let write_clock; let (other_action, other_thread, other_clock) = if range.write > current_clocks.clock[range.write_index] @@ -918,8 +915,8 @@ impl VClockAlloc { }; // Load elaborated thread information about the racing thread actions. - let current_thread_info = global.print_thread_metadata(current_index); - let other_thread_info = global.print_thread_metadata(other_thread); + let current_thread_info = global.print_thread_metadata(thread_mgr, current_index); + let other_thread_info = global.print_thread_metadata(thread_mgr, other_thread); // Throw the data-race detection. throw_ub_format!( @@ -936,9 +933,14 @@ impl VClockAlloc { /// Detect racing atomic read and writes (not data races) /// on every byte of the current access range - pub(super) fn race_free_with_atomic(&self, range: AllocRange, global: &GlobalState) -> bool { + pub(super) fn race_free_with_atomic( + &self, + range: AllocRange, + global: &GlobalState, + thread_mgr: &ThreadManager<'_, '_>, + ) -> bool { if global.race_detecting() { - let (_, clocks) = global.current_thread_state(); + let (_, clocks) = global.current_thread_state(thread_mgr); let alloc_ranges = self.alloc_ranges.borrow(); for (_, range) in alloc_ranges.iter(range.start, range.size) { if !range.race_free_with_atomic(&clocks) { @@ -959,15 +961,17 @@ impl VClockAlloc { alloc_id: AllocId, range: AllocRange, global: &GlobalState, + thread_mgr: &ThreadManager<'_, '_>, ) -> InterpResult<'tcx> { if global.race_detecting() { - let (index, clocks) = global.current_thread_state(); + let (index, clocks) = global.current_thread_state(thread_mgr); let mut alloc_ranges = self.alloc_ranges.borrow_mut(); for (offset, range) in alloc_ranges.iter_mut(range.start, range.size) { if let Err(DataRace) = range.read_race_detect(&clocks, index) { // Report data-race. return Self::report_data_race( global, + thread_mgr, range, "Read", false, @@ -988,14 +992,16 @@ impl VClockAlloc { range: AllocRange, write_type: WriteType, global: &mut GlobalState, + thread_mgr: &ThreadManager<'_, '_>, ) -> InterpResult<'tcx> { if global.race_detecting() { - let (index, clocks) = global.current_thread_state(); + let (index, clocks) = global.current_thread_state(thread_mgr); for (offset, range) in self.alloc_ranges.get_mut().iter_mut(range.start, range.size) { if let Err(DataRace) = range.write_race_detect(&clocks, index, write_type) { // Report data-race return Self::report_data_race( global, + thread_mgr, range, write_type.get_descriptor(), false, @@ -1018,8 +1024,9 @@ impl VClockAlloc { alloc_id: AllocId, range: AllocRange, global: &mut GlobalState, + thread_mgr: &ThreadManager<'_, '_>, ) -> InterpResult<'tcx> { - self.unique_access(alloc_id, range, WriteType::Write, global) + self.unique_access(alloc_id, range, WriteType::Write, global, thread_mgr) } /// Detect data-races for an unsynchronized deallocate operation, will not perform @@ -1031,8 +1038,9 @@ impl VClockAlloc { alloc_id: AllocId, range: AllocRange, global: &mut GlobalState, + thread_mgr: &ThreadManager<'_, '_>, ) -> InterpResult<'tcx> { - self.unique_access(alloc_id, range, WriteType::Deallocate, global) + self.unique_access(alloc_id, range, WriteType::Deallocate, global, thread_mgr) } } @@ -1068,26 +1076,30 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { ); // Perform the atomic operation. - data_race.maybe_perform_sync_operation(|index, mut clocks| { - for (offset, range) in - alloc_meta.alloc_ranges.borrow_mut().iter_mut(base_offset, size) - { - if let Err(DataRace) = op(range, &mut clocks, index, atomic) { - mem::drop(clocks); - return VClockAlloc::report_data_race( - data_race, - range, - description, - true, - Pointer::new(alloc_id, offset), - ) - .map(|_| true); + data_race.maybe_perform_sync_operation( + &this.machine.threads, + |index, mut clocks| { + for (offset, range) in + alloc_meta.alloc_ranges.borrow_mut().iter_mut(base_offset, size) + { + if let Err(DataRace) = op(range, &mut clocks, index, atomic) { + mem::drop(clocks); + return VClockAlloc::report_data_race( + data_race, + &this.machine.threads, + range, + description, + true, + Pointer::new(alloc_id, offset), + ) + .map(|_| true); + } } - } - // This conservatively assumes all operations have release semantics - Ok(true) - })?; + // This conservatively assumes all operations have release semantics + Ok(true) + }, + )?; // Log changes to atomic memory. if log::log_enabled!(log::Level::Trace) { @@ -1117,11 +1129,6 @@ struct ThreadExtraState { /// read during data-race reporting. vector_index: Option, - /// The name of the thread, updated for better - /// diagnostics when reporting detected data - /// races. - thread_name: Option>, - /// Thread termination vector clock, this /// is set on thread termination and is used /// for joining on threads since the vector_index @@ -1161,9 +1168,6 @@ pub struct GlobalState { /// The mapping of a given thread to associated thread metadata. thread_info: RefCell>, - /// The current vector index being executed. - current_index: Cell, - /// Potential vector indices that could be re-used on thread creation /// values are inserted here on after the thread has terminated and /// been joined with, and hence may potentially become free @@ -1173,12 +1177,6 @@ pub struct GlobalState { /// active vector-clocks catch up with the threads timestamp. reuse_candidates: RefCell>, - /// Counts the number of threads that are currently active - /// if the number of active threads reduces to 1 and then - /// a join operation occurs with the remaining main thread - /// then multi-threaded execution may be disabled. - active_thread_count: Cell, - /// This contains threads that have terminated, but not yet joined /// and so cannot become re-use candidates until a join operation /// occurs. @@ -1203,8 +1201,6 @@ impl GlobalState { vector_clocks: RefCell::new(IndexVec::new()), vector_info: RefCell::new(IndexVec::new()), thread_info: RefCell::new(IndexVec::new()), - current_index: Cell::new(VectorIdx::new(0)), - active_thread_count: Cell::new(1), reuse_candidates: RefCell::new(FxHashSet::default()), terminated_threads: RefCell::new(FxHashMap::default()), last_sc_fence: RefCell::new(VClock::default()), @@ -1216,11 +1212,10 @@ impl GlobalState { // the main-thread a name of "main". let index = global_state.vector_clocks.get_mut().push(ThreadClockSet::default()); global_state.vector_info.get_mut().push(ThreadId::new(0)); - global_state.thread_info.get_mut().push(ThreadExtraState { - vector_index: Some(index), - thread_name: Some("main".to_string().into_boxed_str()), - termination_vector_clock: None, - }); + global_state + .thread_info + .get_mut() + .push(ThreadExtraState { vector_index: Some(index), termination_vector_clock: None }); global_state } @@ -1274,14 +1269,10 @@ impl GlobalState { // Hook for thread creation, enabled multi-threaded execution and marks // the current thread timestamp as happening-before the current thread. #[inline] - pub fn thread_created(&mut self, thread: ThreadId) { - let current_index = self.current_index(); - - // Increment the number of active threads. - let active_threads = self.active_thread_count.get(); - self.active_thread_count.set(active_threads + 1); + pub fn thread_created(&mut self, thread_mgr: &ThreadManager<'_, '_>, thread: ThreadId) { + let current_index = self.current_index(thread_mgr); - // Enable multi-threaded execution, there are now two threads + // Enable multi-threaded execution, there are now at least two threads // so data-races are now possible. self.multi_threaded.set(true); @@ -1339,21 +1330,27 @@ impl GlobalState { created.increment_clock(created_index); } - /// Hook on a thread join to update the implicit happens-before relation - /// between the joined thread and the current thread. + /// Hook on a thread join to update the implicit happens-before relation between the joined + /// thread (the joinee, the thread that someone waited on) and the current thread (the joiner, + /// the thread who was waiting). #[inline] - pub fn thread_joined(&mut self, current_thread: ThreadId, join_thread: ThreadId) { + pub fn thread_joined( + &mut self, + thread_mgr: &ThreadManager<'_, '_>, + joiner: ThreadId, + joinee: ThreadId, + ) { let clocks_vec = self.vector_clocks.get_mut(); let thread_info = self.thread_info.get_mut(); // Load the vector clock of the current thread. - let current_index = thread_info[current_thread] + let current_index = thread_info[joiner] .vector_index .expect("Performed thread join on thread with no assigned vector"); let current = &mut clocks_vec[current_index]; // Load the associated vector clock for the terminated thread. - let join_clock = thread_info[join_thread] + let join_clock = thread_info[joinee] .termination_vector_clock .as_ref() .expect("Joined with thread but thread has not terminated"); @@ -1363,10 +1360,9 @@ impl GlobalState { // Is not a release operation so the clock is not incremented. current.clock.join(join_clock); - // Check the number of active threads, if the value is 1 + // Check the number of live threads, if the value is 1 // then test for potentially disabling multi-threaded execution. - let active_threads = self.active_thread_count.get(); - if active_threads == 1 { + if thread_mgr.get_live_thread_count() == 1 { // May potentially be able to disable multi-threaded execution. let current_clock = &clocks_vec[current_index]; if clocks_vec @@ -1383,7 +1379,7 @@ impl GlobalState { // If the thread is marked as terminated but not joined // then move the thread to the re-use set. let termination = self.terminated_threads.get_mut(); - if let Some(index) = termination.remove(&join_thread) { + if let Some(index) = termination.remove(&joinee) { let reuse = self.reuse_candidates.get_mut(); reuse.insert(index); } @@ -1397,8 +1393,8 @@ impl GlobalState { /// This should be called strictly before any calls to /// `thread_joined`. #[inline] - pub fn thread_terminated(&mut self) { - let current_index = self.current_index(); + pub fn thread_terminated(&mut self, thread_mgr: &ThreadManager<'_, '_>) { + let current_index = self.current_index(thread_mgr); // Increment the clock to a unique termination timestamp. let vector_clocks = self.vector_clocks.get_mut(); @@ -1420,35 +1416,6 @@ impl GlobalState { // occurs. let termination = self.terminated_threads.get_mut(); termination.insert(current_thread, current_index); - - // Reduce the number of active threads, now that a thread has - // terminated. - let mut active_threads = self.active_thread_count.get(); - active_threads -= 1; - self.active_thread_count.set(active_threads); - } - - /// Hook for updating the local tracker of the currently - /// enabled thread, should always be updated whenever - /// `active_thread` in thread.rs is updated. - #[inline] - pub fn thread_set_active(&self, thread: ThreadId) { - let thread_info = self.thread_info.borrow(); - let vector_idx = thread_info[thread] - .vector_index - .expect("Setting thread active with no assigned vector"); - self.current_index.set(vector_idx); - } - - /// Hook for updating the local tracker of the threads name - /// this should always mirror the local value in thread.rs - /// the thread name is used for improved diagnostics - /// during a data-race. - #[inline] - pub fn thread_set_name(&mut self, thread: ThreadId, name: String) { - let name = name.into_boxed_str(); - let thread_info = self.thread_info.get_mut(); - thread_info[thread].thread_name = Some(name); } /// Attempt to perform a synchronized operation, this @@ -1460,12 +1427,13 @@ impl GlobalState { /// operation may create. fn maybe_perform_sync_operation<'tcx>( &self, + thread_mgr: &ThreadManager<'_, '_>, op: impl FnOnce(VectorIdx, RefMut<'_, ThreadClockSet>) -> InterpResult<'tcx, bool>, ) -> InterpResult<'tcx> { if self.multi_threaded.get() { - let (index, clocks) = self.current_thread_state_mut(); + let (index, clocks) = self.current_thread_state_mut(thread_mgr); if op(index, clocks)? { - let (_, mut clocks) = self.current_thread_state_mut(); + let (_, mut clocks) = self.current_thread_state_mut(thread_mgr); clocks.increment_clock(index); } } @@ -1474,15 +1442,18 @@ impl GlobalState { /// Internal utility to identify a thread stored internally /// returns the id and the name for better diagnostics. - fn print_thread_metadata(&self, vector: VectorIdx) -> String { + fn print_thread_metadata( + &self, + thread_mgr: &ThreadManager<'_, '_>, + vector: VectorIdx, + ) -> String { let thread = self.vector_info.borrow()[vector]; - let thread_name = &self.thread_info.borrow()[thread].thread_name; - if let Some(name) = thread_name { - let name: &str = name; - format!("Thread(id = {:?}, name = {:?})", thread.to_u32(), name) - } else { - format!("Thread(id = {:?})", thread.to_u32()) - } + let thread_name = thread_mgr.get_thread_name(); + format!( + "Thread(id = {:?}, name = {:?})", + thread.to_u32(), + String::from_utf8_lossy(thread_name) + ) } /// Acquire a lock, express that the previous call of @@ -1534,8 +1505,11 @@ impl GlobalState { /// Load the current vector clock in use and the current set of thread clocks /// in use for the vector. #[inline] - pub(super) fn current_thread_state(&self) -> (VectorIdx, Ref<'_, ThreadClockSet>) { - let index = self.current_index(); + pub(super) fn current_thread_state( + &self, + thread_mgr: &ThreadManager<'_, '_>, + ) -> (VectorIdx, Ref<'_, ThreadClockSet>) { + let index = self.current_index(thread_mgr); let ref_vector = self.vector_clocks.borrow(); let clocks = Ref::map(ref_vector, |vec| &vec[index]); (index, clocks) @@ -1544,8 +1518,11 @@ impl GlobalState { /// Load the current vector clock in use and the current set of thread clocks /// in use for the vector mutably for modification. #[inline] - pub(super) fn current_thread_state_mut(&self) -> (VectorIdx, RefMut<'_, ThreadClockSet>) { - let index = self.current_index(); + pub(super) fn current_thread_state_mut( + &self, + thread_mgr: &ThreadManager<'_, '_>, + ) -> (VectorIdx, RefMut<'_, ThreadClockSet>) { + let index = self.current_index(thread_mgr); let ref_vector = self.vector_clocks.borrow_mut(); let clocks = RefMut::map(ref_vector, |vec| &mut vec[index]); (index, clocks) @@ -1554,19 +1531,22 @@ impl GlobalState { /// Return the current thread, should be the same /// as the data-race active thread. #[inline] - fn current_index(&self) -> VectorIdx { - self.current_index.get() + fn current_index(&self, thread_mgr: &ThreadManager<'_, '_>) -> VectorIdx { + let active_thread_id = thread_mgr.get_active_thread_id(); + self.thread_info.borrow()[active_thread_id] + .vector_index + .expect("active thread has no assigned vector") } // SC ATOMIC STORE rule in the paper. - pub(super) fn sc_write(&self) { - let (index, clocks) = self.current_thread_state(); + pub(super) fn sc_write(&self, thread_mgr: &ThreadManager<'_, '_>) { + let (index, clocks) = self.current_thread_state(thread_mgr); self.last_sc_write.borrow_mut().set_at_index(&clocks.clock, index); } // SC ATOMIC READ rule in the paper. - pub(super) fn sc_read(&self) { - let (.., mut clocks) = self.current_thread_state_mut(); + pub(super) fn sc_read(&self, thread_mgr: &ThreadManager<'_, '_>) { + let (.., mut clocks) = self.current_thread_state_mut(thread_mgr); clocks.read_seqcst.join(&self.last_sc_fence.borrow()); } } diff --git a/src/concurrency/weak_memory.rs b/src/concurrency/weak_memory.rs index 28a54c2e3b6c1..e7ed9ea09a82a 100644 --- a/src/concurrency/weak_memory.rs +++ b/src/concurrency/weak_memory.rs @@ -82,10 +82,12 @@ use rustc_const_eval::interpret::{ }; use rustc_data_structures::fx::FxHashMap; -use crate::{AtomicReadOrd, AtomicRwOrd, AtomicWriteOrd, Tag, VClock, VTimestamp, VectorIdx}; +use crate::{ + AtomicReadOrd, AtomicRwOrd, AtomicWriteOrd, Tag, ThreadManager, VClock, VTimestamp, VectorIdx, +}; use super::{ - data_race::{GlobalState, ThreadClockSet}, + data_race::{GlobalState as DataRaceState, ThreadClockSet}, range_object_map::{AccessType, RangeObjectMap}, }; @@ -149,7 +151,7 @@ impl StoreBufferAlloc { /// before without data race, we can determine that the non-atomic access fully happens /// after all the prior atomic accesses so the location no longer needs to exhibit /// any weak memory behaviours until further atomic accesses. - pub fn memory_accessed(&self, range: AllocRange, global: &GlobalState) { + pub fn memory_accessed(&self, range: AllocRange, global: &DataRaceState) { if !global.ongoing_action_data_race_free() { let mut buffers = self.store_buffers.borrow_mut(); let access_type = buffers.access_type(range); @@ -236,17 +238,18 @@ impl<'mir, 'tcx: 'mir> StoreBuffer { } /// Reads from the last store in modification order - fn read_from_last_store(&self, global: &GlobalState) { + fn read_from_last_store(&self, global: &DataRaceState, thread_mgr: &ThreadManager<'_, '_>) { let store_elem = self.buffer.back(); if let Some(store_elem) = store_elem { - let (index, clocks) = global.current_thread_state(); + let (index, clocks) = global.current_thread_state(thread_mgr); store_elem.load_impl(index, &clocks); } } fn buffered_read( &self, - global: &GlobalState, + global: &DataRaceState, + thread_mgr: &ThreadManager<'_, '_>, is_seqcst: bool, rng: &mut (impl rand::Rng + ?Sized), validate: impl FnOnce() -> InterpResult<'tcx>, @@ -257,7 +260,7 @@ impl<'mir, 'tcx: 'mir> StoreBuffer { let store_elem = { // The `clocks` we got here must be dropped before calling validate_atomic_load // as the race detector will update it - let (.., clocks) = global.current_thread_state(); + let (.., clocks) = global.current_thread_state(thread_mgr); // Load from a valid entry in the store buffer self.fetch_store(is_seqcst, &clocks, &mut *rng) }; @@ -268,7 +271,7 @@ impl<'mir, 'tcx: 'mir> StoreBuffer { // requires access to ThreadClockSet.clock, which is updated by the race detector validate()?; - let (index, clocks) = global.current_thread_state(); + let (index, clocks) = global.current_thread_state(thread_mgr); let loaded = store_elem.load_impl(index, &clocks); Ok(loaded) } @@ -276,10 +279,11 @@ impl<'mir, 'tcx: 'mir> StoreBuffer { fn buffered_write( &mut self, val: ScalarMaybeUninit, - global: &GlobalState, + global: &DataRaceState, + thread_mgr: &ThreadManager<'_, '_>, is_seqcst: bool, ) -> InterpResult<'tcx> { - let (index, clocks) = global.current_thread_state(); + let (index, clocks) = global.current_thread_state(thread_mgr); self.store_impl(val, index, &clocks.clock, is_seqcst); Ok(()) @@ -428,8 +432,11 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>: { let range = alloc_range(base_offset, place.layout.size); if alloc_buffers.is_overlapping(range) - && !alloc_clocks - .race_free_with_atomic(range, this.machine.data_race.as_ref().unwrap()) + && !alloc_clocks.race_free_with_atomic( + range, + this.machine.data_race.as_ref().unwrap(), + &this.machine.threads, + ) { throw_unsup_format!( "racy imperfectly overlapping atomic access is not possible in the C++20 memory model, and not supported by Miri's weak memory emulation" @@ -450,17 +457,17 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>: let (alloc_id, base_offset, ..) = this.ptr_get_alloc_id(place.ptr)?; if let ( crate::AllocExtra { weak_memory: Some(alloc_buffers), .. }, - crate::Evaluator { data_race: Some(global), .. }, + crate::Evaluator { data_race: Some(global), threads, .. }, ) = this.get_alloc_extra_mut(alloc_id)? { if atomic == AtomicRwOrd::SeqCst { - global.sc_read(); - global.sc_write(); + global.sc_read(threads); + global.sc_write(threads); } let range = alloc_range(base_offset, place.layout.size); let buffer = alloc_buffers.get_or_create_store_buffer_mut(range, init)?; - buffer.read_from_last_store(global); - buffer.buffered_write(new_val, global, atomic == AtomicRwOrd::SeqCst)?; + buffer.read_from_last_store(global, threads); + buffer.buffered_write(new_val, global, threads, atomic == AtomicRwOrd::SeqCst)?; } Ok(()) } @@ -477,7 +484,7 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>: let (alloc_id, base_offset, ..) = this.ptr_get_alloc_id(place.ptr)?; if let Some(alloc_buffers) = this.get_alloc_extra(alloc_id)?.weak_memory.as_ref() { if atomic == AtomicReadOrd::SeqCst { - global.sc_read(); + global.sc_read(&this.machine.threads); } let mut rng = this.machine.rng.borrow_mut(); let buffer = alloc_buffers.get_or_create_store_buffer( @@ -486,6 +493,7 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>: )?; let loaded = buffer.buffered_read( global, + &this.machine.threads, atomic == AtomicReadOrd::SeqCst, &mut *rng, validate, @@ -511,11 +519,11 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>: let (alloc_id, base_offset, ..) = this.ptr_get_alloc_id(dest.ptr)?; if let ( crate::AllocExtra { weak_memory: Some(alloc_buffers), .. }, - crate::Evaluator { data_race: Some(global), .. }, + crate::Evaluator { data_race: Some(global), threads, .. }, ) = this.get_alloc_extra_mut(alloc_id)? { if atomic == AtomicWriteOrd::SeqCst { - global.sc_write(); + global.sc_write(threads); } // UGLY HACK: in write_scalar_atomic() we don't know the value before our write, @@ -535,7 +543,7 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>: buffer.buffer.pop_front(); } - buffer.buffered_write(val, global, atomic == AtomicWriteOrd::SeqCst)?; + buffer.buffered_write(val, global, threads, atomic == AtomicWriteOrd::SeqCst)?; } // Caller should've written to dest with the vanilla scalar write, we do nothing here @@ -555,14 +563,14 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>: if let Some(global) = &this.machine.data_race { if atomic == AtomicReadOrd::SeqCst { - global.sc_read(); + global.sc_read(&this.machine.threads); } let size = place.layout.size; let (alloc_id, base_offset, ..) = this.ptr_get_alloc_id(place.ptr)?; if let Some(alloc_buffers) = this.get_alloc_extra(alloc_id)?.weak_memory.as_ref() { let buffer = alloc_buffers .get_or_create_store_buffer(alloc_range(base_offset, size), init)?; - buffer.read_from_last_store(global); + buffer.read_from_last_store(global, &this.machine.threads); } } Ok(()) diff --git a/src/machine.rs b/src/machine.rs index abc55cde737ec..86b174182c1f1 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -647,7 +647,12 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { None }; let race_alloc = if let Some(data_race) = &ecx.machine.data_race { - Some(data_race::AllocExtra::new_allocation(data_race, alloc.size(), kind)) + Some(data_race::AllocExtra::new_allocation( + data_race, + &ecx.machine.threads, + alloc.size(), + kind, + )) } else { None }; @@ -756,7 +761,12 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { range: AllocRange, ) -> InterpResult<'tcx> { if let Some(data_race) = &alloc_extra.data_race { - data_race.read(alloc_id, range, machine.data_race.as_ref().unwrap())?; + data_race.read( + alloc_id, + range, + machine.data_race.as_ref().unwrap(), + &machine.threads, + )?; } if let Some(stacked_borrows) = &alloc_extra.stacked_borrows { stacked_borrows.borrow_mut().memory_read( @@ -782,7 +792,12 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { range: AllocRange, ) -> InterpResult<'tcx> { if let Some(data_race) = &mut alloc_extra.data_race { - data_race.write(alloc_id, range, machine.data_race.as_mut().unwrap())?; + data_race.write( + alloc_id, + range, + machine.data_race.as_mut().unwrap(), + &machine.threads, + )?; } if let Some(stacked_borrows) = &mut alloc_extra.stacked_borrows { stacked_borrows.get_mut().memory_written( @@ -811,7 +826,12 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { register_diagnostic(NonHaltingDiagnostic::FreedAlloc(alloc_id)); } if let Some(data_race) = &mut alloc_extra.data_race { - data_race.deallocate(alloc_id, range, machine.data_race.as_mut().unwrap())?; + data_race.deallocate( + alloc_id, + range, + machine.data_race.as_mut().unwrap(), + &machine.threads, + )?; } if let Some(stacked_borrows) = &mut alloc_extra.stacked_borrows { stacked_borrows.get_mut().memory_deallocated( diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 9705f56cd1077..d8f6292e9df39 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -1038,20 +1038,24 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx #[rustfmt::skip] "atomic_xsub_relaxed" => this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::Sub, false), AtomicRwOrd::Relaxed)?, - "atomic_min_seqcst" => this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOrd::SeqCst)?, + "atomic_min_seqcst" => + this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOrd::SeqCst)?, "atomic_min_acquire" => this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOrd::Acquire)?, "atomic_min_release" => this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOrd::Release)?, - "atomic_min_acqrel" => this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOrd::AcqRel)?, + "atomic_min_acqrel" => + this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOrd::AcqRel)?, "atomic_min_relaxed" => this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOrd::Relaxed)?, - "atomic_max_seqcst" => this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOrd::SeqCst)?, + "atomic_max_seqcst" => + this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOrd::SeqCst)?, "atomic_max_acquire" => this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOrd::Acquire)?, "atomic_max_release" => this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOrd::Release)?, - "atomic_max_acqrel" => this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOrd::AcqRel)?, + "atomic_max_acqrel" => + this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOrd::AcqRel)?, "atomic_max_relaxed" => this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOrd::Relaxed)?, "atomic_umin_seqcst" => diff --git a/src/thread.rs b/src/thread.rs index 2135806de3ed5..7327f2b8114f6 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -289,15 +289,21 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { } /// Get the id of the currently active thread. - fn get_active_thread_id(&self) -> ThreadId { + pub fn get_active_thread_id(&self) -> ThreadId { self.active_thread } /// Get the total number of threads that were ever spawn by this program. - fn get_total_thread_count(&self) -> usize { + pub fn get_total_thread_count(&self) -> usize { self.threads.len() } + /// Get the total of threads that are currently live, i.e., not yet terminated. + /// (They might be blocked.) + pub fn get_live_thread_count(&self) -> usize { + self.threads.iter().filter(|t| !matches!(t.state, ThreadState::Terminated)).count() + } + /// Has the given thread terminated? fn has_terminated(&self, thread_id: ThreadId) -> bool { self.threads[thread_id].state == ThreadState::Terminated @@ -366,7 +372,7 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { } else { // The thread has already terminated - mark join happens-before if let Some(data_race) = data_race { - data_race.thread_joined(self.active_thread, joined_thread_id); + data_race.thread_joined(self, self.active_thread, joined_thread_id); } } Ok(()) @@ -378,7 +384,7 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { } /// Get the name of the active thread. - fn get_thread_name(&self) -> &[u8] { + pub fn get_thread_name(&self) -> &[u8] { self.active_thread_ref().thread_name() } @@ -460,21 +466,25 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { false }); } - // Set the thread into a terminated state in the data-race detector + // Set the thread into a terminated state in the data-race detector. if let Some(ref mut data_race) = data_race { - data_race.thread_terminated(); + data_race.thread_terminated(self); } // Check if we need to unblock any threads. + let mut joined_threads = vec![]; // store which threads joined, we'll need it for (i, thread) in self.threads.iter_enumerated_mut() { if thread.state == ThreadState::BlockedOnJoin(self.active_thread) { // The thread has terminated, mark happens-before edge to joining thread - if let Some(ref mut data_race) = data_race { - data_race.thread_joined(i, self.active_thread); + if let Some(_) = data_race { + joined_threads.push(i); } trace!("unblocking {:?} because {:?} terminated", i, self.active_thread); thread.state = ThreadState::Enabled; } } + for &i in &joined_threads { + data_race.as_mut().unwrap().thread_joined(self, i, self.active_thread); + } free_tls_statics } @@ -484,10 +494,7 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { /// used in stateless model checkers such as Loom: run the active thread as /// long as we can and switch only when we have to (the active thread was /// blocked, terminated, or has explicitly asked to be preempted). - fn schedule( - &mut self, - data_race: &Option, - ) -> InterpResult<'tcx, SchedulingAction> { + fn schedule(&mut self) -> InterpResult<'tcx, SchedulingAction> { // Check whether the thread has **just** terminated (`check_terminated` // checks whether the thread has popped all its stack and if yes, sets // the thread state to terminated). @@ -535,9 +542,6 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { debug_assert_ne!(self.active_thread, id); if thread.state == ThreadState::Enabled { self.active_thread = id; - if let Some(data_race) = data_race { - data_race.thread_set_active(self.active_thread); - } break; } } @@ -598,7 +602,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); let id = this.machine.threads.create_thread(); if let Some(data_race) = &mut this.machine.data_race { - data_race.thread_created(id); + data_race.thread_created(&this.machine.threads, id); } id } @@ -619,9 +623,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx #[inline] fn set_active_thread(&mut self, thread_id: ThreadId) -> ThreadId { let this = self.eval_context_mut(); - if let Some(data_race) = &this.machine.data_race { - data_race.thread_set_active(thread_id); - } this.machine.threads.set_active_thread_id(thread_id) } @@ -682,11 +683,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx #[inline] fn set_active_thread_name(&mut self, new_thread_name: Vec) { let this = self.eval_context_mut(); - if let Some(data_race) = &mut this.machine.data_race { - if let Ok(string) = String::from_utf8(new_thread_name.clone()) { - data_race.thread_set_name(this.machine.threads.active_thread, string); - } - } this.machine.threads.set_thread_name(new_thread_name); } @@ -776,8 +772,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx #[inline] fn schedule(&mut self) -> InterpResult<'tcx, SchedulingAction> { let this = self.eval_context_mut(); - let data_race = &this.machine.data_race; - this.machine.threads.schedule(data_race) + this.machine.threads.schedule() } /// Handles thread termination of the active thread: wakes up threads joining on this one, From 3bbcafe3b59ee5c4537f65e820835c526531fe59 Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Tue, 7 Dec 2021 22:05:13 -0500 Subject: [PATCH 3381/3747] Cache lookups into the borrow stack This adds a very simple LRU-like cache which stores the locations of often-used tags. While the implementation is very simple, the cache hit rate is incredible at ~99.9% on most programs, and often the element at position 0 in the cache has a hit rate of 90%. So the sub-optimality of this cache basicaly vanishes into the noise in a profile. Additionally, we keep a range which denotes where there might be an item granting Unique permission in the stack, so that when we invalidate Uniques we do not need to scan much of the stack, and often scan nothing at all. --- Cargo.toml | 5 + src/lib.rs | 4 +- src/stacked_borrows.rs | 139 +++--------- src/stacked_borrows/diagnostics.rs | 5 +- src/stacked_borrows/stack.rs | 349 +++++++++++++++++++++++++++++ ui_test/Cargo.toml | 4 + 6 files changed, 398 insertions(+), 108 deletions(-) create mode 100644 src/stacked_borrows/stack.rs diff --git a/Cargo.toml b/Cargo.toml index 6b7f369ae5a98..0dead9fa28f70 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -50,3 +50,8 @@ rustc_private = true [[test]] name = "compiletest" harness = false + +[features] +default = ["stack-cache"] +expensive-debug-assertions = [] +stack-cache = [] diff --git a/src/lib.rs b/src/lib.rs index e199fae31ee82..a98239711ef42 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -90,8 +90,8 @@ pub use crate::mono_hash_map::MonoHashMap; pub use crate::operator::EvalContextExt as OperatorEvalContextExt; pub use crate::range_map::RangeMap; pub use crate::stacked_borrows::{ - CallId, EvalContextExt as StackedBorEvalContextExt, Item, Permission, SbTag, SbTagExtra, Stack, - Stacks, + stack::Stack, CallId, EvalContextExt as StackedBorEvalContextExt, Item, Permission, PtrId, + SbTag, SbTagExtra, Stacks, }; pub use crate::sync::{CondvarId, EvalContextExt as SyncEvalContextExt, MutexId, RwLockId}; pub use crate::thread::{ diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 2cf5eb70c171f..3a4b4ad65fa1a 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -23,6 +23,10 @@ use crate::*; pub mod diagnostics; use diagnostics::{AllocHistory, TagHistory}; +pub mod stack; +use stack::Stack; + +pub type PtrId = NonZeroU64; pub type CallId = NonZeroU64; // Even reading memory can have effects on the stack, so we need a `RefCell` here. @@ -111,23 +115,6 @@ impl fmt::Debug for Item { } } -/// Extra per-location state. -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct Stack { - /// Used *mostly* as a stack; never empty. - /// Invariants: - /// * Above a `SharedReadOnly` there can only be more `SharedReadOnly`. - /// * No tag occurs in the stack more than once. - borrows: Vec, - /// If this is `Some(id)`, then the actual current stack is unknown. This can happen when - /// wildcard pointers are used to access this location. What we do know is that `borrows` are at - /// the top of the stack, and below it are arbitrarily many items whose `tag` is strictly less - /// than `id`. - /// When the bottom is unknown, `borrows` always has a `SharedReadOnly` or `Unique` at the bottom; - /// we never have the unknown-to-known boundary in an SRW group. - unknown_bottom: Option, -} - /// Extra per-allocation state. #[derive(Clone, Debug)] pub struct Stacks { @@ -297,65 +284,10 @@ impl Permission { /// Core per-location operations: access, dealloc, reborrow. impl<'tcx> Stack { - /// Find the item granting the given kind of access to the given tag, and return where - /// it is on the stack. For wildcard tags, the given index is approximate, but if *no* - /// index is given it means the match was *not* in the known part of the stack. - /// `Ok(None)` indicates it matched the "unknown" part of the stack. - /// `Err` indicates it was not found. - fn find_granting( - &self, - access: AccessKind, - tag: SbTagExtra, - exposed_tags: &FxHashSet, - ) -> Result, ()> { - let SbTagExtra::Concrete(tag) = tag else { - // Handle the wildcard case. - // Go search the stack for an exposed tag. - if let Some(idx) = - self.borrows - .iter() - .enumerate() // we also need to know *where* in the stack - .rev() // search top-to-bottom - .find_map(|(idx, item)| { - // If the item fits and *might* be this wildcard, use it. - if item.perm.grants(access) && exposed_tags.contains(&item.tag) { - Some(idx) - } else { - None - } - }) - { - return Ok(Some(idx)); - } - // If we couldn't find it in the stack, check the unknown bottom. - return if self.unknown_bottom.is_some() { Ok(None) } else { Err(()) }; - }; - - if let Some(idx) = - self.borrows - .iter() - .enumerate() // we also need to know *where* in the stack - .rev() // search top-to-bottom - // Return permission of first item that grants access. - // We require a permission with the right tag, ensuring U3 and F3. - .find_map(|(idx, item)| { - if tag == item.tag && item.perm.grants(access) { Some(idx) } else { None } - }) - { - return Ok(Some(idx)); - } - - // Couldn't find it in the stack; but if there is an unknown bottom it might be there. - let found = self.unknown_bottom.is_some_and(|&unknown_limit| { - tag.0 < unknown_limit.0 // unknown_limit is an upper bound for what can be in the unknown bottom. - }); - if found { Ok(None) } else { Err(()) } - } - /// Find the first write-incompatible item above the given one -- /// i.e, find the height to which the stack will be truncated when writing to `granting`. fn find_first_write_incompatible(&self, granting: usize) -> usize { - let perm = self.borrows[granting].perm; + let perm = self.get(granting).unwrap().perm; match perm { Permission::SharedReadOnly => bug!("Cannot use SharedReadOnly for writing"), Permission::Disabled => bug!("Cannot use Disabled for anything"), @@ -366,7 +298,7 @@ impl<'tcx> Stack { Permission::SharedReadWrite => { // The SharedReadWrite *just* above us are compatible, to skip those. let mut idx = granting + 1; - while let Some(item) = self.borrows.get(idx) { + while let Some(item) = self.get(idx) { if item.perm == Permission::SharedReadWrite { // Go on. idx += 1; @@ -461,8 +393,7 @@ impl<'tcx> Stack { // There is a SRW group boundary between the unknown and the known, so everything is incompatible. 0 }; - for item in self.borrows.drain(first_incompatible_idx..).rev() { - trace!("access: popping item {:?}", item); + self.pop_items_after(first_incompatible_idx, |item| { Stack::item_popped( &item, Some((tag, alloc_range, offset, access)), @@ -470,7 +401,8 @@ impl<'tcx> Stack { alloc_history, )?; alloc_history.log_invalidation(item.tag, alloc_range, current_span); - } + Ok(()) + })?; } else { // On a read, *disable* all `Unique` above the granting item. This ensures U2 for read accesses. // The reason this is not following the stack discipline (by removing the first Unique and @@ -487,21 +419,16 @@ impl<'tcx> Stack { // We are reading from something in the unknown part. That means *all* `Unique` we know about are dead now. 0 }; - for idx in (first_incompatible_idx..self.borrows.len()).rev() { - let item = &mut self.borrows[idx]; - - if item.perm == Permission::Unique { - trace!("access: disabling item {:?}", item); - Stack::item_popped( - item, - Some((tag, alloc_range, offset, access)), - global, - alloc_history, - )?; - item.perm = Permission::Disabled; - alloc_history.log_invalidation(item.tag, alloc_range, current_span); - } - } + self.disable_uniques_starting_at(first_incompatible_idx, |item| { + Stack::item_popped( + &item, + Some((tag, alloc_range, offset, access)), + global, + alloc_history, + )?; + alloc_history.log_invalidation(item.tag, alloc_range, current_span); + Ok(()) + })?; } // If this was an approximate action, we now collapse everything into an unknown. @@ -509,22 +436,22 @@ impl<'tcx> Stack { // Compute the upper bound of the items that remain. // (This is why we did all the work above: to reduce the items we have to consider here.) let mut max = NonZeroU64::new(1).unwrap(); - for item in &self.borrows { + for i in 0..self.len() { + let item = self.get(i).unwrap(); // Skip disabled items, they cannot be matched anyway. if !matches!(item.perm, Permission::Disabled) { // We are looking for a strict upper bound, so add 1 to this tag. max = cmp::max(item.tag.0.checked_add(1).unwrap(), max); } } - if let Some(unk) = self.unknown_bottom { + if let Some(unk) = self.unknown_bottom() { max = cmp::max(unk.0, max); } // Use `max` as new strict upper bound for everything. trace!( "access: forgetting stack to upper bound {max} due to wildcard or unknown access" ); - self.borrows.clear(); - self.unknown_bottom = Some(SbTag(max)); + self.set_unknown_bottom(SbTag(max)); } // Done. @@ -553,7 +480,8 @@ impl<'tcx> Stack { })?; // Step 2: Remove all items. Also checks for protectors. - for item in self.borrows.drain(..).rev() { + for idx in (0..self.len()).rev() { + let item = self.get(idx).unwrap(); Stack::item_popped(&item, None, global, alloc_history)?; } Ok(()) @@ -601,8 +529,7 @@ impl<'tcx> Stack { // The new thing is SRW anyway, so we cannot push it "on top of the unkown part" // (for all we know, it might join an SRW group inside the unknown). trace!("reborrow: forgetting stack entirely due to SharedReadWrite reborrow from wildcard or unknown"); - self.borrows.clear(); - self.unknown_bottom = Some(global.next_ptr_tag); + self.set_unknown_bottom(global.next_ptr_tag); return Ok(()); }; @@ -629,19 +556,18 @@ impl<'tcx> Stack { // on top of `derived_from`, and we want the new item at the top so that we // get the strongest possible guarantees. // This ensures U1 and F1. - self.borrows.len() + self.len() }; // Put the new item there. As an optimization, deduplicate if it is equal to one of its new neighbors. // `new_idx` might be 0 if we just cleared the entire stack. - if self.borrows.get(new_idx) == Some(&new) - || (new_idx > 0 && self.borrows[new_idx - 1] == new) + if self.get(new_idx) == Some(new) || (new_idx > 0 && self.get(new_idx - 1).unwrap() == new) { // Optimization applies, done. trace!("reborrow: avoiding adding redundant item {:?}", new); } else { trace!("reborrow: adding item {:?}", new); - self.borrows.insert(new_idx, new); + self.insert(new_idx, new); } Ok(()) } @@ -653,8 +579,8 @@ impl<'tcx> Stacks { /// Creates new stack with initial tag. fn new(size: Size, perm: Permission, tag: SbTag) -> Self { let item = Item { perm, tag, protector: None }; - let stack = Stack { borrows: vec![item], unknown_bottom: None }; + let stack = Stack::new(item); Stacks { stacks: RangeMap::new(size, stack), history: AllocHistory::new(), @@ -900,11 +826,14 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // We have to use shared references to alloc/memory_extra here since // `visit_freeze_sensitive` needs to access the global state. let extra = this.get_alloc_extra(alloc_id)?; + let mut stacked_borrows = extra .stacked_borrows .as_ref() .expect("we should have Stacked Borrows data") .borrow_mut(); + let mut current_span = this.machine.current_span(); + this.visit_freeze_sensitive(place, size, |mut range, frozen| { // Adjust range. range.start += base_offset; @@ -929,7 +858,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx item, (alloc_id, range, offset), &mut global, - current_span, + &mut current_span, history, exposed_tags, ) diff --git a/src/stacked_borrows/diagnostics.rs b/src/stacked_borrows/diagnostics.rs index b1ff864bcd5e1..a7b8e5f13cea4 100644 --- a/src/stacked_borrows/diagnostics.rs +++ b/src/stacked_borrows/diagnostics.rs @@ -185,7 +185,10 @@ fn operation_summary( fn error_cause(stack: &Stack, tag: SbTagExtra) -> &'static str { if let SbTagExtra::Concrete(tag) = tag { - if stack.borrows.iter().any(|item| item.tag == tag && item.perm != Permission::Disabled) { + if (0..stack.len()) + .map(|i| stack.get(i).unwrap()) + .any(|item| item.tag == tag && item.perm != Permission::Disabled) + { ", but that tag only grants SharedReadOnly permission for this location" } else { ", but that tag does not exist in the borrow stack for this location" diff --git a/src/stacked_borrows/stack.rs b/src/stacked_borrows/stack.rs new file mode 100644 index 0000000000000..e6dc507802fd0 --- /dev/null +++ b/src/stacked_borrows/stack.rs @@ -0,0 +1,349 @@ +use crate::stacked_borrows::{AccessKind, Item, Permission, SbTag, SbTagExtra}; +use rustc_data_structures::fx::FxHashSet; +#[cfg(feature = "stack-cache")] +use std::ops::Range; + +/// Exactly what cache size we should use is a difficult tradeoff. There will always be some +/// workload which has a `SbTag` working set which exceeds the size of the cache, and ends up +/// falling back to linear searches of the borrow stack very often. +/// The cost of making this value too large is that the loop in `Stack::insert` which ensures the +/// entries in the cache stay correct after an insert becomes expensive. +#[cfg(feature = "stack-cache")] +const CACHE_LEN: usize = 32; + +/// Extra per-location state. +#[derive(Clone, Debug)] +pub struct Stack { + /// Used *mostly* as a stack; never empty. + /// Invariants: + /// * Above a `SharedReadOnly` there can only be more `SharedReadOnly`. + /// * Except for `Untagged`, no tag occurs in the stack more than once. + borrows: Vec, + /// If this is `Some(id)`, then the actual current stack is unknown. This can happen when + /// wildcard pointers are used to access this location. What we do know is that `borrows` are at + /// the top of the stack, and below it are arbitrarily many items whose `tag` is strictly less + /// than `id`. + /// When the bottom is unknown, `borrows` always has a `SharedReadOnly` or `Unique` at the bottom; + /// we never have the unknown-to-known boundary in an SRW group. + unknown_bottom: Option, + + /// A small LRU cache of searches of the borrow stack. This only caches accesses of `Tagged`, + /// because those are unique in the stack. + #[cfg(feature = "stack-cache")] + cache: StackCache, + /// On a read, we need to disable all `Unique` above the granting item. We can avoid most of + /// this scan by keeping track of the region of the borrow stack that may contain `Unique`s. + #[cfg(feature = "stack-cache")] + unique_range: Range, +} + +/// A very small cache of searches of the borrow stack +/// This maps tags to locations in the borrow stack. Any use of this still needs to do a +/// probably-cold random access into the borrow stack to figure out what `Permission` an +/// `SbTag` grants. We could avoid this by also storing the `Permission` in the cache, but +/// most lookups into the cache are immediately followed by access of the full borrow stack anyway. +#[cfg(feature = "stack-cache")] +#[derive(Clone, Debug)] +struct StackCache { + tags: [SbTag; CACHE_LEN], // Hot in find_granting + idx: [usize; CACHE_LEN], // Hot in grant +} + +#[cfg(feature = "stack-cache")] +impl StackCache { + fn add(&mut self, idx: usize, tag: SbTag) { + self.tags.copy_within(0..CACHE_LEN - 1, 1); + self.tags[0] = tag; + self.idx.copy_within(0..CACHE_LEN - 1, 1); + self.idx[0] = idx; + } +} + +impl PartialEq for Stack { + fn eq(&self, other: &Self) -> bool { + // All the semantics of Stack are in self.borrows, everything else is caching + self.borrows == other.borrows + } +} + +impl Eq for Stack {} + +impl<'tcx> Stack { + /// Panics if any of the caching mechanisms have broken, + /// - The StackCache indices don't refer to the parallel tags, + /// - There are no Unique tags outside of first_unique..last_unique + #[cfg(feature = "expensive-debug-assertions")] + fn verify_cache_consistency(&self) { + if self.borrows.len() > CACHE_LEN { + for (tag, stack_idx) in self.cache.tags.iter().zip(self.cache.idx.iter()) { + assert_eq!(self.borrows[*stack_idx].tag, *tag); + } + } + + for (idx, item) in self.borrows.iter().enumerate() { + if item.perm == Permission::Unique { + assert!( + self.unique_range.contains(&idx), + "{:?} {:?}", + self.unique_range, + self.borrows + ); + } + } + } + + /// Find the item granting the given kind of access to the given tag, and return where + /// it is on the stack. For wildcard tags, the given index is approximate, but if *no* + /// index is given it means the match was *not* in the known part of the stack. + /// `Ok(None)` indicates it matched the "unknown" part of the stack. + /// `Err` indicates it was not found. + pub fn find_granting( + &mut self, + access: AccessKind, + tag: SbTagExtra, + exposed_tags: &FxHashSet, + ) -> Result, ()> { + #[cfg(feature = "expensive-debug-assertions")] + self.verify_cache_consistency(); + + let SbTagExtra::Concrete(tag) = tag else { + // Handle the wildcard case. + // Go search the stack for an exposed tag. + if let Some(idx) = + self.borrows + .iter() + .enumerate() // we also need to know *where* in the stack + .rev() // search top-to-bottom + .find_map(|(idx, item)| { + // If the item fits and *might* be this wildcard, use it. + if item.perm.grants(access) && exposed_tags.contains(&item.tag) { + Some(idx) + } else { + None + } + }) + { + return Ok(Some(idx)); + } + // If we couldn't find it in the stack, check the unknown bottom. + return if self.unknown_bottom.is_some() { Ok(None) } else { Err(()) }; + }; + + if let Some(idx) = self.find_granting_tagged(access, tag) { + return Ok(Some(idx)); + } + + // Couldn't find it in the stack; but if there is an unknown bottom it might be there. + let found = self.unknown_bottom.is_some_and(|&unknown_limit| { + tag.0 < unknown_limit.0 // unknown_limit is an upper bound for what can be in the unknown bottom. + }); + if found { Ok(None) } else { Err(()) } + } + + fn find_granting_tagged(&mut self, access: AccessKind, tag: SbTag) -> Option { + #[cfg(feature = "stack-cache")] + if let Some(idx) = self.find_granting_cache(access, tag) { + return Some(idx); + } + + // If we didn't find the tag in the cache, fall back to a linear search of the + // whole stack, and add the tag to the stack. + for (stack_idx, item) in self.borrows.iter().enumerate().rev() { + if tag == item.tag && item.perm.grants(access) { + #[cfg(feature = "stack-cache")] + self.cache.add(stack_idx, tag); + return Some(stack_idx); + } + } + None + } + + #[cfg(feature = "stack-cache")] + fn find_granting_cache(&mut self, access: AccessKind, tag: SbTag) -> Option { + // When the borrow stack is empty, there are no tags we could put into the cache that would + // be valid. Additionally, since lookups into the cache are a linear search it doesn't make + // sense to use the cache when it is no smaller than a search of the borrow stack itself. + if self.borrows.len() <= CACHE_LEN { + return None; + } + // Search the cache for the tag we're looking up + let cache_idx = self.cache.tags.iter().position(|t| *t == tag)?; + let stack_idx = self.cache.idx[cache_idx]; + // If we found the tag, look up its position in the stack to see if it grants + // the required permission + if self.borrows[stack_idx].perm.grants(access) { + // If it does, and it's already in the most-recently-used position, move it + // there. + if cache_idx != 0 { + self.cache.add(stack_idx, tag); + } + Some(stack_idx) + } else { + // Tag is in the cache, but it doesn't grant the required permission + None + } + } + + pub fn insert(&mut self, new_idx: usize, new: Item) { + self.borrows.insert(new_idx, new); + + #[cfg(feature = "stack-cache")] + self.insert_cache(new_idx, new); + } + + #[cfg(feature = "stack-cache")] + fn insert_cache(&mut self, new_idx: usize, new: Item) { + // Adjust the possibly-unique range if an insert occurs before or within it + if self.unique_range.start >= new_idx { + self.unique_range.start += 1; + } + if self.unique_range.end >= new_idx { + self.unique_range.end += 1; + } + if new.perm == Permission::Unique { + // Make sure the possibly-unique range contains the new borrow + self.unique_range.start = self.unique_range.start.min(new_idx); + self.unique_range.end = self.unique_range.end.max(new_idx + 1); + } + + // The above insert changes the meaning of every index in the cache >= new_idx, so now + // we need to find every one of those indexes and increment it. + for idx in &mut self.cache.idx { + if *idx >= new_idx { + *idx += 1; + } + } + + // This primes the cache for the next access, which is almost always the just-added tag. + self.cache.add(new_idx, new.tag); + + #[cfg(feature = "expensive-debug-assertions")] + self.verify_cache_consistency(); + } + + /// Construct a new `Stack` using the passed `Item` as the base tag. + pub fn new(item: Item) -> Self { + Stack { + borrows: vec![item], + unknown_bottom: None, + #[cfg(feature = "stack-cache")] + cache: StackCache { idx: [0; CACHE_LEN], tags: [item.tag; CACHE_LEN] }, + #[cfg(feature = "stack-cache")] + unique_range: if item.perm == Permission::Unique { 0..1 } else { 0..0 }, + } + } + + pub fn get(&self, idx: usize) -> Option { + self.borrows.get(idx).cloned() + } + + #[allow(clippy::len_without_is_empty)] // Stacks are never empty + pub fn len(&self) -> usize { + self.borrows.len() + } + + pub fn unknown_bottom(&self) -> Option { + self.unknown_bottom + } + + pub fn set_unknown_bottom(&mut self, tag: SbTag) { + self.borrows.clear(); + self.unknown_bottom = Some(tag); + } + + /// Find all `Unique` elements in this borrow stack above `granting_idx`, pass a copy of them + /// to the `visitor`, then set their `Permission` to `Disabled`. + pub fn disable_uniques_starting_at crate::InterpResult<'tcx>>( + &mut self, + disable_start: usize, + mut visitor: V, + ) -> crate::InterpResult<'tcx> { + #[cfg(feature = "stack-cache")] + let unique_range = self.unique_range.clone(); + #[cfg(not(feature = "stack-cache"))] + let unique_range = 0..self.len(); + + if disable_start <= unique_range.end { + // add 1 so we don't disable the granting item + let lower = unique_range.start.max(disable_start); + let upper = (unique_range.end + 1).min(self.borrows.len()); + for item in &mut self.borrows[lower..upper] { + if item.perm == Permission::Unique { + log::trace!("access: disabling item {:?}", item); + visitor(*item)?; + item.perm = Permission::Disabled; + } + } + } + + #[cfg(feature = "stack-cache")] + if disable_start < self.unique_range.start { + // We disabled all Unique items + self.unique_range.start = 0; + self.unique_range.end = 0; + } else { + // Truncate the range to disable_start. This is + 2 because we are only removing + // elements after disable_start, and this range does not include the end. + self.unique_range.end = self.unique_range.end.min(disable_start + 1); + } + + #[cfg(feature = "expensive-debug-assertions")] + self.verify_cache_consistency(); + + Ok(()) + } + + /// Produces an iterator which iterates over `range` in reverse, and when dropped removes that + /// range of `Item`s from this `Stack`. + pub fn pop_items_after crate::InterpResult<'tcx>>( + &mut self, + start: usize, + mut visitor: V, + ) -> crate::InterpResult<'tcx> { + while self.borrows.len() > start { + let item = self.borrows.pop().unwrap(); + visitor(item)?; + } + + #[cfg(feature = "stack-cache")] + if !self.borrows.is_empty() { + // After we remove from the borrow stack, every aspect of our caching may be invalid, but it is + // also possible that the whole cache is still valid. So we call this method to repair what + // aspects of the cache are now invalid, instead of resetting the whole thing to a trivially + // valid default state. + let base_tag = self.borrows[0].tag; + let mut removed = 0; + let mut cursor = 0; + // Remove invalid entries from the cache by rotating them to the end of the cache, then + // keep track of how many invalid elements there are and overwrite them with the base tag. + // The base tag here serves as a harmless default value. + for _ in 0..CACHE_LEN - 1 { + if self.cache.idx[cursor] >= start { + self.cache.idx[cursor..CACHE_LEN - removed].rotate_left(1); + self.cache.tags[cursor..CACHE_LEN - removed].rotate_left(1); + removed += 1; + } else { + cursor += 1; + } + } + for i in CACHE_LEN - removed - 1..CACHE_LEN { + self.cache.idx[i] = 0; + self.cache.tags[i] = base_tag; + } + + if start < self.unique_range.start.saturating_sub(1) { + // We removed all the Unique items + self.unique_range = 0..0; + } else { + // Ensure the range doesn't extend past the new top of the stack + self.unique_range.end = self.unique_range.end.min(start + 1); + } + } else { + self.unique_range = 0..0; + } + + #[cfg(feature = "expensive-debug-assertions")] + self.verify_cache_consistency(); + Ok(()) + } +} diff --git a/ui_test/Cargo.toml b/ui_test/Cargo.toml index 92c00915cbfeb..0838733db2de3 100644 --- a/ui_test/Cargo.toml +++ b/ui_test/Cargo.toml @@ -14,3 +14,7 @@ crossbeam = "0.8.1" lazy_static = "1.4.0" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" + +[features] +# Doesn't do anything, but the miri script wants to pass the same flags to ui_test and miri itself +expensive-debug-assertions = [] From d09db1660b0c7baca06029369bc48b8d9c604f0a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 1 Jul 2022 17:33:17 -0400 Subject: [PATCH 3382/3747] fix and slightly improve data race reports --- src/concurrency/data_race.rs | 17 ++++--------- src/concurrency/weak_memory.rs | 2 +- src/thread.rs | 25 ++++++++++++++----- tests/compiletest.rs | 2 -- tests/fail/data_race/alloc_read_race.rs | 2 +- tests/fail/data_race/alloc_read_race.stderr | 4 +-- tests/fail/data_race/alloc_write_race.rs | 2 +- tests/fail/data_race/alloc_write_race.stderr | 4 +-- .../data_race/atomic_read_na_write_race1.rs | 2 +- .../atomic_read_na_write_race1.stderr | 4 +-- .../data_race/atomic_read_na_write_race2.rs | 2 +- .../atomic_read_na_write_race2.stderr | 4 +-- .../data_race/atomic_write_na_read_race1.rs | 2 +- .../atomic_write_na_read_race1.stderr | 4 +-- .../data_race/atomic_write_na_read_race2.rs | 2 +- .../atomic_write_na_read_race2.stderr | 4 +-- .../data_race/atomic_write_na_write_race1.rs | 2 +- .../atomic_write_na_write_race1.stderr | 4 +-- .../data_race/atomic_write_na_write_race2.rs | 2 +- .../atomic_write_na_write_race2.stderr | 4 +-- .../data_race/dangling_thread_async_race.rs | 2 +- .../dangling_thread_async_race.stderr | 4 +-- tests/fail/data_race/dangling_thread_race.rs | 2 +- .../data_race/dangling_thread_race.stderr | 4 +-- tests/fail/data_race/dealloc_read_race1.rs | 2 +- .../fail/data_race/dealloc_read_race1.stderr | 4 +-- tests/fail/data_race/dealloc_read_race2.rs | 2 +- .../fail/data_race/dealloc_read_race_stack.rs | 2 +- .../data_race/dealloc_read_race_stack.stderr | 4 +-- tests/fail/data_race/dealloc_write_race1.rs | 2 +- .../fail/data_race/dealloc_write_race1.stderr | 4 +-- tests/fail/data_race/dealloc_write_race2.rs | 2 +- .../data_race/dealloc_write_race_stack.rs | 2 +- .../data_race/dealloc_write_race_stack.stderr | 4 +-- .../data_race/enable_after_join_to_main.rs | 2 +- .../enable_after_join_to_main.stderr | 4 +-- tests/fail/data_race/fence_after_load.rs | 2 +- tests/fail/data_race/fence_after_load.stderr | 4 +-- tests/fail/data_race/read_write_race.rs | 2 +- tests/fail/data_race/read_write_race.stderr | 4 +-- tests/fail/data_race/read_write_race_stack.rs | 2 +- .../data_race/read_write_race_stack.stderr | 4 +-- tests/fail/data_race/relax_acquire_race.rs | 2 +- .../fail/data_race/relax_acquire_race.stderr | 4 +-- tests/fail/data_race/release_seq_race.rs | 2 +- tests/fail/data_race/release_seq_race.stderr | 4 +-- .../data_race/release_seq_race_same_thread.rs | 2 +- .../release_seq_race_same_thread.stderr | 4 +-- tests/fail/data_race/rmw_race.rs | 2 +- tests/fail/data_race/rmw_race.stderr | 4 +-- tests/fail/data_race/write_write_race.rs | 2 +- tests/fail/data_race/write_write_race.stderr | 4 +-- .../fail/data_race/write_write_race_stack.rs | 2 +- .../data_race/write_write_race_stack.stderr | 4 +-- tests/pass/libc.rs | 3 ++- 55 files changed, 101 insertions(+), 96 deletions(-) diff --git a/src/concurrency/data_race.rs b/src/concurrency/data_race.rs index 205b56ca4c071..4b402b51fc59d 100644 --- a/src/concurrency/data_race.rs +++ b/src/concurrency/data_race.rs @@ -882,7 +882,7 @@ impl VClockAlloc { ) -> InterpResult<'tcx> { let (current_index, current_clocks) = global.current_thread_state(thread_mgr); let write_clock; - let (other_action, other_thread, other_clock) = if range.write + let (other_action, other_thread, _other_clock) = if range.write > current_clocks.clock[range.write_index] { // Convert the write action into the vector clock it @@ -920,14 +920,12 @@ impl VClockAlloc { // Throw the data-race detection. throw_ub_format!( - "Data race detected between {} on {} and {} on {} at {:?} (current vector clock = {:?}, conflicting timestamp = {:?})", + "Data race detected between {} on {} and {} on {} at {:?}", action, current_thread_info, other_action, other_thread_info, ptr_dbg, - current_clocks.clock, - other_clock ) } @@ -1208,8 +1206,7 @@ impl GlobalState { }; // Setup the main-thread since it is not explicitly created: - // uses vector index and thread-id 0, also the rust runtime gives - // the main-thread a name of "main". + // uses vector index and thread-id 0. let index = global_state.vector_clocks.get_mut().push(ThreadClockSet::default()); global_state.vector_info.get_mut().push(ThreadId::new(0)); global_state @@ -1448,12 +1445,8 @@ impl GlobalState { vector: VectorIdx, ) -> String { let thread = self.vector_info.borrow()[vector]; - let thread_name = thread_mgr.get_thread_name(); - format!( - "Thread(id = {:?}, name = {:?})", - thread.to_u32(), - String::from_utf8_lossy(thread_name) - ) + let thread_name = thread_mgr.get_thread_name(thread); + format!("thread `{}`", String::from_utf8_lossy(thread_name)) } /// Acquire a lock, express that the previous call of diff --git a/src/concurrency/weak_memory.rs b/src/concurrency/weak_memory.rs index e7ed9ea09a82a..f7cc9c4732ace 100644 --- a/src/concurrency/weak_memory.rs +++ b/src/concurrency/weak_memory.rs @@ -9,7 +9,7 @@ //! Note that this implementation does not take into account of C++20's memory model revision to SC accesses //! and fences introduced by P0668 (). //! This implementation is not fully correct under the revised C++20 model and may generate behaviours C++20 -//! disallows. +//! disallows (). //! //! Rust follows the C++20 memory model (except for the Consume ordering and some operations not performable through C++'s //! std::atomic API). It is therefore possible for this implementation to generate behaviours never observable when the diff --git a/src/thread.rs b/src/thread.rs index 7327f2b8114f6..420eeb810fd87 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -170,6 +170,14 @@ impl<'mir, 'tcx> Default for Thread<'mir, 'tcx> { } } +impl<'mir, 'tcx> Thread<'mir, 'tcx> { + fn new(name: &str) -> Self { + let mut thread = Thread::default(); + thread.thread_name = Some(Vec::from(name.as_bytes())); + thread + } +} + /// A specific moment in time. #[derive(Debug)] pub enum Time { @@ -230,7 +238,7 @@ impl<'mir, 'tcx> Default for ThreadManager<'mir, 'tcx> { fn default() -> Self { let mut threads = IndexVec::new(); // Create the main thread and add it to the list of threads. - let mut main_thread = Thread::default(); + let mut main_thread = Thread::new("main"); // The main thread can *not* be joined on. main_thread.join_status = ThreadJoinStatus::Detached; threads.push(main_thread); @@ -379,15 +387,20 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { } /// Set the name of the active thread. - fn set_thread_name(&mut self, new_thread_name: Vec) { + fn set_active_thread_name(&mut self, new_thread_name: Vec) { self.active_thread_mut().thread_name = Some(new_thread_name); } /// Get the name of the active thread. - pub fn get_thread_name(&self) -> &[u8] { + pub fn get_active_thread_name(&self) -> &[u8] { self.active_thread_ref().thread_name() } + /// Get the name of the given thread. + pub fn get_thread_name(&self, thread: ThreadId) -> &[u8] { + self.threads[thread].thread_name() + } + /// Put the thread into the blocked state. fn block_thread(&mut self, thread: ThreadId) { let state = &mut self.threads[thread].state; @@ -475,7 +488,7 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { for (i, thread) in self.threads.iter_enumerated_mut() { if thread.state == ThreadState::BlockedOnJoin(self.active_thread) { // The thread has terminated, mark happens-before edge to joining thread - if let Some(_) = data_race { + if data_race.is_some() { joined_threads.push(i); } trace!("unblocking {:?} because {:?} terminated", i, self.active_thread); @@ -683,7 +696,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx #[inline] fn set_active_thread_name(&mut self, new_thread_name: Vec) { let this = self.eval_context_mut(); - this.machine.threads.set_thread_name(new_thread_name); + this.machine.threads.set_active_thread_name(new_thread_name); } #[inline] @@ -692,7 +705,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx 'mir: 'c, { let this = self.eval_context_ref(); - this.machine.threads.get_thread_name() + this.machine.threads.get_active_thread_name() } #[inline] diff --git a/tests/compiletest.rs b/tests/compiletest.rs index e4d8511b51df5..754fccd63b13d 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -94,8 +94,6 @@ regexes! { "([0-9]+: ) +0x[0-9a-f]+ - (.*)" => "$1$2", // erase long hexadecimals r"0x[0-9a-fA-F]+[0-9a-fA-F]{2,2}" => "$$HEX", - // erase clocks - r"VClock\(\[[^\]]+\]\)" => "VClock", // erase specific alignments "alignment [0-9]+" => "alignment ALIGN", // erase thread caller ids diff --git a/tests/fail/data_race/alloc_read_race.rs b/tests/fail/data_race/alloc_read_race.rs index 12c1b6ec876a1..1eac8ce0f26c6 100644 --- a/tests/fail/data_race/alloc_read_race.rs +++ b/tests/fail/data_race/alloc_read_race.rs @@ -38,7 +38,7 @@ pub fn main() { let pointer = &*ptr.0; // Note: could also error due to reading uninitialized memory, but the data-race detector triggers first. - *pointer.load(Ordering::Relaxed) //~ ERROR Data race detected between Read on Thread(id = 2) and Allocate on Thread(id = 1) + *pointer.load(Ordering::Relaxed) //~ ERROR Data race detected between Read on thread `` and Allocate on thread `` }); j1.join().unwrap(); diff --git a/tests/fail/data_race/alloc_read_race.stderr b/tests/fail/data_race/alloc_read_race.stderr index 52004f2d2d025..2049e4f4a193a 100644 --- a/tests/fail/data_race/alloc_read_race.stderr +++ b/tests/fail/data_race/alloc_read_race.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: Data race detected between Read on Thread(id = 2) and Allocate on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) +error: Undefined Behavior: Data race detected between Read on thread `` and Allocate on thread `` at ALLOC --> $DIR/alloc_read_race.rs:LL:CC | LL | *pointer.load(Ordering::Relaxed) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Data race detected between Read on Thread(id = 2) and Allocate on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Data race detected between Read on thread `` and Allocate on thread `` at ALLOC | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/data_race/alloc_write_race.rs b/tests/fail/data_race/alloc_write_race.rs index c050d24bee10d..e618b72a82270 100644 --- a/tests/fail/data_race/alloc_write_race.rs +++ b/tests/fail/data_race/alloc_write_race.rs @@ -36,7 +36,7 @@ pub fn main() { let j2 = spawn(move || { let pointer = &*ptr.0; - *pointer.load(Ordering::Relaxed) = 2; //~ ERROR Data race detected between Write on Thread(id = 2) and Allocate on Thread(id = 1) + *pointer.load(Ordering::Relaxed) = 2; //~ ERROR Data race detected between Write on thread `` and Allocate on thread `` }); j1.join().unwrap(); diff --git a/tests/fail/data_race/alloc_write_race.stderr b/tests/fail/data_race/alloc_write_race.stderr index b6c05b34073c5..82e3d92479d94 100644 --- a/tests/fail/data_race/alloc_write_race.stderr +++ b/tests/fail/data_race/alloc_write_race.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: Data race detected between Write on Thread(id = 2) and Allocate on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) +error: Undefined Behavior: Data race detected between Write on thread `` and Allocate on thread `` at ALLOC --> $DIR/alloc_write_race.rs:LL:CC | LL | *pointer.load(Ordering::Relaxed) = 2; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Data race detected between Write on Thread(id = 2) and Allocate on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Data race detected between Write on thread `` and Allocate on thread `` at ALLOC | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/data_race/atomic_read_na_write_race1.rs b/tests/fail/data_race/atomic_read_na_write_race1.rs index 5cf2f26bf1f03..3b948eea98051 100644 --- a/tests/fail/data_race/atomic_read_na_write_race1.rs +++ b/tests/fail/data_race/atomic_read_na_write_race1.rs @@ -22,7 +22,7 @@ pub fn main() { let j2 = spawn(move || { //Equivalent to: (&*c.0).load(Ordering::SeqCst) - intrinsics::atomic_load_seqcst(c.0 as *mut usize) //~ ERROR Data race detected between Atomic Load on Thread(id = 2) and Write on Thread(id = 1) + intrinsics::atomic_load_seqcst(c.0 as *mut usize) //~ ERROR Data race detected between Atomic Load on thread `` and Write on thread `` }); j1.join().unwrap(); diff --git a/tests/fail/data_race/atomic_read_na_write_race1.stderr b/tests/fail/data_race/atomic_read_na_write_race1.stderr index 51cdb239507a5..4b5355e866e25 100644 --- a/tests/fail/data_race/atomic_read_na_write_race1.stderr +++ b/tests/fail/data_race/atomic_read_na_write_race1.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: Data race detected between Atomic Load on Thread(id = 2) and Write on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) +error: Undefined Behavior: Data race detected between Atomic Load on thread `` and Write on thread `` at ALLOC --> $DIR/atomic_read_na_write_race1.rs:LL:CC | LL | intrinsics::atomic_load_seqcst(c.0 as *mut usize) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Data race detected between Atomic Load on Thread(id = 2) and Write on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Data race detected between Atomic Load on thread `` and Write on thread `` at ALLOC | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/data_race/atomic_read_na_write_race2.rs b/tests/fail/data_race/atomic_read_na_write_race2.rs index 1c0146367ad55..44b4eebee8051 100644 --- a/tests/fail/data_race/atomic_read_na_write_race2.rs +++ b/tests/fail/data_race/atomic_read_na_write_race2.rs @@ -22,7 +22,7 @@ pub fn main() { let j2 = spawn(move || { let atomic_ref = &mut *c.0; - *atomic_ref.get_mut() = 32; //~ ERROR Data race detected between Write on Thread(id = 2) and Atomic Load on Thread(id = 1) + *atomic_ref.get_mut() = 32; //~ ERROR Data race detected between Write on thread `` and Atomic Load on thread `` }); j1.join().unwrap(); diff --git a/tests/fail/data_race/atomic_read_na_write_race2.stderr b/tests/fail/data_race/atomic_read_na_write_race2.stderr index 9a432c586afe7..3eb9f17bae760 100644 --- a/tests/fail/data_race/atomic_read_na_write_race2.stderr +++ b/tests/fail/data_race/atomic_read_na_write_race2.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: Data race detected between Write on Thread(id = 2) and Atomic Load on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) +error: Undefined Behavior: Data race detected between Write on thread `` and Atomic Load on thread `` at ALLOC --> $DIR/atomic_read_na_write_race2.rs:LL:CC | LL | *atomic_ref.get_mut() = 32; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ Data race detected between Write on Thread(id = 2) and Atomic Load on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ Data race detected between Write on thread `` and Atomic Load on thread `` at ALLOC | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/data_race/atomic_write_na_read_race1.rs b/tests/fail/data_race/atomic_write_na_read_race1.rs index a63aafb0453c9..44dc1a9084168 100644 --- a/tests/fail/data_race/atomic_write_na_read_race1.rs +++ b/tests/fail/data_race/atomic_write_na_read_race1.rs @@ -22,7 +22,7 @@ pub fn main() { let j2 = spawn(move || { let atomic_ref = &mut *c.0; - *atomic_ref.get_mut() //~ ERROR Data race detected between Read on Thread(id = 2) and Atomic Store on Thread(id = 1) + *atomic_ref.get_mut() //~ ERROR Data race detected between Read on thread `` and Atomic Store on thread `` }); j1.join().unwrap(); diff --git a/tests/fail/data_race/atomic_write_na_read_race1.stderr b/tests/fail/data_race/atomic_write_na_read_race1.stderr index 8280f43b518fe..810fa54d41cee 100644 --- a/tests/fail/data_race/atomic_write_na_read_race1.stderr +++ b/tests/fail/data_race/atomic_write_na_read_race1.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: Data race detected between Read on Thread(id = 2) and Atomic Store on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) +error: Undefined Behavior: Data race detected between Read on thread `` and Atomic Store on thread `` at ALLOC --> $DIR/atomic_write_na_read_race1.rs:LL:CC | LL | *atomic_ref.get_mut() - | ^^^^^^^^^^^^^^^^^^^^^ Data race detected between Read on Thread(id = 2) and Atomic Store on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) + | ^^^^^^^^^^^^^^^^^^^^^ Data race detected between Read on thread `` and Atomic Store on thread `` at ALLOC | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/data_race/atomic_write_na_read_race2.rs b/tests/fail/data_race/atomic_write_na_read_race2.rs index 0b055c9b96ec0..b4b21b64fc1fb 100644 --- a/tests/fail/data_race/atomic_write_na_read_race2.rs +++ b/tests/fail/data_race/atomic_write_na_read_race2.rs @@ -22,7 +22,7 @@ pub fn main() { let j2 = spawn(move || { //Equivalent to: (&*c.0).store(32, Ordering::SeqCst) - atomic_store(c.0 as *mut usize, 32); //~ ERROR Data race detected between Atomic Store on Thread(id = 2) and Read on Thread(id = 1) + atomic_store(c.0 as *mut usize, 32); //~ ERROR Data race detected between Atomic Store on thread `` and Read on thread `` }); j1.join().unwrap(); diff --git a/tests/fail/data_race/atomic_write_na_read_race2.stderr b/tests/fail/data_race/atomic_write_na_read_race2.stderr index 63d0f5814ef4d..77f69e2bc3400 100644 --- a/tests/fail/data_race/atomic_write_na_read_race2.stderr +++ b/tests/fail/data_race/atomic_write_na_read_race2.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: Data race detected between Atomic Store on Thread(id = 2) and Read on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) +error: Undefined Behavior: Data race detected between Atomic Store on thread `` and Read on thread `` at ALLOC --> $DIR/atomic_write_na_read_race2.rs:LL:CC | LL | atomic_store(c.0 as *mut usize, 32); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Data race detected between Atomic Store on Thread(id = 2) and Read on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Data race detected between Atomic Store on thread `` and Read on thread `` at ALLOC | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/data_race/atomic_write_na_write_race1.rs b/tests/fail/data_race/atomic_write_na_write_race1.rs index 8268924e3c1ac..b1a4cfb98bd13 100644 --- a/tests/fail/data_race/atomic_write_na_write_race1.rs +++ b/tests/fail/data_race/atomic_write_na_write_race1.rs @@ -22,7 +22,7 @@ pub fn main() { let j2 = spawn(move || { //Equivalent to: (&*c.0).store(64, Ordering::SeqCst) - atomic_store(c.0 as *mut usize, 64); //~ ERROR Data race detected between Atomic Store on Thread(id = 2) and Write on Thread(id = 1) + atomic_store(c.0 as *mut usize, 64); //~ ERROR Data race detected between Atomic Store on thread `` and Write on thread `` }); j1.join().unwrap(); diff --git a/tests/fail/data_race/atomic_write_na_write_race1.stderr b/tests/fail/data_race/atomic_write_na_write_race1.stderr index 332be7406c82d..8e70de5e4aff6 100644 --- a/tests/fail/data_race/atomic_write_na_write_race1.stderr +++ b/tests/fail/data_race/atomic_write_na_write_race1.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: Data race detected between Atomic Store on Thread(id = 2) and Write on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) +error: Undefined Behavior: Data race detected between Atomic Store on thread `` and Write on thread `` at ALLOC --> $DIR/atomic_write_na_write_race1.rs:LL:CC | LL | atomic_store(c.0 as *mut usize, 64); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Data race detected between Atomic Store on Thread(id = 2) and Write on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Data race detected between Atomic Store on thread `` and Write on thread `` at ALLOC | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/data_race/atomic_write_na_write_race2.rs b/tests/fail/data_race/atomic_write_na_write_race2.rs index 440c72a059d8c..dbdce8f6237ce 100644 --- a/tests/fail/data_race/atomic_write_na_write_race2.rs +++ b/tests/fail/data_race/atomic_write_na_write_race2.rs @@ -22,7 +22,7 @@ pub fn main() { let j2 = spawn(move || { let atomic_ref = &mut *c.0; - *atomic_ref.get_mut() = 32; //~ ERROR Data race detected between Write on Thread(id = 2) and Atomic Store on Thread(id = 1) + *atomic_ref.get_mut() = 32; //~ ERROR Data race detected between Write on thread `` and Atomic Store on thread `` }); j1.join().unwrap(); diff --git a/tests/fail/data_race/atomic_write_na_write_race2.stderr b/tests/fail/data_race/atomic_write_na_write_race2.stderr index 024f525b12135..310c2ed7df8a1 100644 --- a/tests/fail/data_race/atomic_write_na_write_race2.stderr +++ b/tests/fail/data_race/atomic_write_na_write_race2.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: Data race detected between Write on Thread(id = 2) and Atomic Store on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) +error: Undefined Behavior: Data race detected between Write on thread `` and Atomic Store on thread `` at ALLOC --> $DIR/atomic_write_na_write_race2.rs:LL:CC | LL | *atomic_ref.get_mut() = 32; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ Data race detected between Write on Thread(id = 2) and Atomic Store on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ Data race detected between Write on thread `` and Atomic Store on thread `` at ALLOC | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/data_race/dangling_thread_async_race.rs b/tests/fail/data_race/dangling_thread_async_race.rs index 2656f4b7af148..65325b60f2f39 100644 --- a/tests/fail/data_race/dangling_thread_async_race.rs +++ b/tests/fail/data_race/dangling_thread_async_race.rs @@ -34,7 +34,7 @@ fn main() { let join2 = unsafe { spawn(move || { - *c.0 = 64; //~ ERROR Data race detected between Write on Thread(id = 3) and Write on Thread(id = 1) + *c.0 = 64; //~ ERROR Data race detected between Write on thread `` and Write on thread `` }) }; diff --git a/tests/fail/data_race/dangling_thread_async_race.stderr b/tests/fail/data_race/dangling_thread_async_race.stderr index 6d31e3971e530..efdc913ce27a9 100644 --- a/tests/fail/data_race/dangling_thread_async_race.stderr +++ b/tests/fail/data_race/dangling_thread_async_race.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: Data race detected between Write on Thread(id = 3) and Write on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) +error: Undefined Behavior: Data race detected between Write on thread `` and Write on thread `` at ALLOC --> $DIR/dangling_thread_async_race.rs:LL:CC | LL | *c.0 = 64; - | ^^^^^^^^^ Data race detected between Write on Thread(id = 3) and Write on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) + | ^^^^^^^^^ Data race detected between Write on thread `` and Write on thread `` at ALLOC | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/data_race/dangling_thread_race.rs b/tests/fail/data_race/dangling_thread_race.rs index f1174d8ff6ee1..09e7032c93308 100644 --- a/tests/fail/data_race/dangling_thread_race.rs +++ b/tests/fail/data_race/dangling_thread_race.rs @@ -33,6 +33,6 @@ fn main() { spawn(|| ()).join().unwrap(); unsafe { - *c.0 = 64; //~ ERROR Data race detected between Write on Thread(id = 0, name = "main") and Write on Thread(id = 1) + *c.0 = 64; //~ ERROR Data race detected between Write on thread `main` and Write on thread `` } } diff --git a/tests/fail/data_race/dangling_thread_race.stderr b/tests/fail/data_race/dangling_thread_race.stderr index ba1ef2760f8f6..899cfdd095e38 100644 --- a/tests/fail/data_race/dangling_thread_race.stderr +++ b/tests/fail/data_race/dangling_thread_race.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: Data race detected between Write on Thread(id = 0, name = "main") and Write on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) +error: Undefined Behavior: Data race detected between Write on thread `main` and Write on thread `` at ALLOC --> $DIR/dangling_thread_race.rs:LL:CC | LL | *c.0 = 64; - | ^^^^^^^^^ Data race detected between Write on Thread(id = 0, name = "main") and Write on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) + | ^^^^^^^^^ Data race detected between Write on thread `main` and Write on thread `` at ALLOC | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/data_race/dealloc_read_race1.rs b/tests/fail/data_race/dealloc_read_race1.rs index 555700a75d3ae..ff2ac8ca522a5 100644 --- a/tests/fail/data_race/dealloc_read_race1.rs +++ b/tests/fail/data_race/dealloc_read_race1.rs @@ -24,7 +24,7 @@ pub fn main() { let j2 = spawn(move || { __rust_dealloc( - //~^ ERROR Data race detected between Deallocate on Thread(id = 2) and Read on Thread(id = 1) + //~^ ERROR Data race detected between Deallocate on thread `` and Read on thread `` ptr.0 as *mut _, std::mem::size_of::(), std::mem::align_of::(), diff --git a/tests/fail/data_race/dealloc_read_race1.stderr b/tests/fail/data_race/dealloc_read_race1.stderr index 91a681e744505..9e35fb7b6bd82 100644 --- a/tests/fail/data_race/dealloc_read_race1.stderr +++ b/tests/fail/data_race/dealloc_read_race1.stderr @@ -1,4 +1,4 @@ -error: Undefined Behavior: Data race detected between Deallocate on Thread(id = 2) and Read on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) +error: Undefined Behavior: Data race detected between Deallocate on thread `` and Read on thread `` at ALLOC --> $DIR/dealloc_read_race1.rs:LL:CC | LL | / __rust_dealloc( @@ -7,7 +7,7 @@ LL | | ptr.0 as *mut _, LL | | std::mem::size_of::(), LL | | std::mem::align_of::(), LL | | ); - | |_____________^ Data race detected between Deallocate on Thread(id = 2) and Read on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) + | |_____________^ Data race detected between Deallocate on thread `` and Read on thread `` at ALLOC | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/data_race/dealloc_read_race2.rs b/tests/fail/data_race/dealloc_read_race2.rs index 984268dca149d..4bb6444f6a626 100644 --- a/tests/fail/data_race/dealloc_read_race2.rs +++ b/tests/fail/data_race/dealloc_read_race2.rs @@ -27,7 +27,7 @@ pub fn main() { }); let j2 = spawn(move || { - // Also an error of the form: Data race detected between Read on Thread(id = 2) and Deallocate on Thread(id = 1) + // Also an error of the form: Data race detected between Read on thread `` and Deallocate on thread `` // but the invalid allocation is detected first. *ptr.0 //~ ERROR dereferenced after this allocation got freed }); diff --git a/tests/fail/data_race/dealloc_read_race_stack.rs b/tests/fail/data_race/dealloc_read_race_stack.rs index cdb6c182307f8..e079581a0d89b 100644 --- a/tests/fail/data_race/dealloc_read_race_stack.rs +++ b/tests/fail/data_race/dealloc_read_race_stack.rs @@ -36,7 +36,7 @@ pub fn main() { sleep(Duration::from_millis(200)); // Now `stack_var` gets deallocated. - } //~ ERROR Data race detected between Deallocate on Thread(id = 1) and Read on Thread(id = 2) + } //~ ERROR Data race detected between Deallocate on thread `` and Read on thread `` }); let j2 = spawn(move || { diff --git a/tests/fail/data_race/dealloc_read_race_stack.stderr b/tests/fail/data_race/dealloc_read_race_stack.stderr index 1275d1290b0ac..b1e7d3649ecb3 100644 --- a/tests/fail/data_race/dealloc_read_race_stack.stderr +++ b/tests/fail/data_race/dealloc_read_race_stack.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: Data race detected between Deallocate on Thread(id = 1) and Read on Thread(id = 2) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) +error: Undefined Behavior: Data race detected between Deallocate on thread `` and Read on thread `` at ALLOC --> $DIR/dealloc_read_race_stack.rs:LL:CC | LL | } - | ^ Data race detected between Deallocate on Thread(id = 1) and Read on Thread(id = 2) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) + | ^ Data race detected between Deallocate on thread `` and Read on thread `` at ALLOC | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/data_race/dealloc_write_race1.rs b/tests/fail/data_race/dealloc_write_race1.rs index 44078a044a7f8..9cd0ebc642521 100644 --- a/tests/fail/data_race/dealloc_write_race1.rs +++ b/tests/fail/data_race/dealloc_write_race1.rs @@ -23,7 +23,7 @@ pub fn main() { let j2 = spawn(move || { __rust_dealloc( - //~^ ERROR Data race detected between Deallocate on Thread(id = 2) and Write on Thread(id = 1) + //~^ ERROR Data race detected between Deallocate on thread `` and Write on thread `` ptr.0 as *mut _, std::mem::size_of::(), std::mem::align_of::(), diff --git a/tests/fail/data_race/dealloc_write_race1.stderr b/tests/fail/data_race/dealloc_write_race1.stderr index dc1a6ed267c6b..a9ac03eb31db9 100644 --- a/tests/fail/data_race/dealloc_write_race1.stderr +++ b/tests/fail/data_race/dealloc_write_race1.stderr @@ -1,4 +1,4 @@ -error: Undefined Behavior: Data race detected between Deallocate on Thread(id = 2) and Write on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) +error: Undefined Behavior: Data race detected between Deallocate on thread `` and Write on thread `` at ALLOC --> $DIR/dealloc_write_race1.rs:LL:CC | LL | / __rust_dealloc( @@ -7,7 +7,7 @@ LL | | ptr.0 as *mut _, LL | | std::mem::size_of::(), LL | | std::mem::align_of::(), LL | | ); - | |_____________^ Data race detected between Deallocate on Thread(id = 2) and Write on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) + | |_____________^ Data race detected between Deallocate on thread `` and Write on thread `` at ALLOC | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/data_race/dealloc_write_race2.rs b/tests/fail/data_race/dealloc_write_race2.rs index 2f4b9a194c05e..9b1b8f0614754 100644 --- a/tests/fail/data_race/dealloc_write_race2.rs +++ b/tests/fail/data_race/dealloc_write_race2.rs @@ -26,7 +26,7 @@ pub fn main() { }); let j2 = spawn(move || { - // Also an error of the form: Data race detected between Write on Thread(id = 2) and Deallocate on Thread(id = 1) + // Also an error of the form: Data race detected between Write on thread `` and Deallocate on thread `` // but the invalid allocation is detected first. *ptr.0 = 2; //~ ERROR dereferenced after this allocation got freed }); diff --git a/tests/fail/data_race/dealloc_write_race_stack.rs b/tests/fail/data_race/dealloc_write_race_stack.rs index a209a2cd7dbfb..2f12570892732 100644 --- a/tests/fail/data_race/dealloc_write_race_stack.rs +++ b/tests/fail/data_race/dealloc_write_race_stack.rs @@ -36,7 +36,7 @@ pub fn main() { sleep(Duration::from_millis(200)); // Now `stack_var` gets deallocated. - } //~ ERROR Data race detected between Deallocate on Thread(id = 1) and Write on Thread(id = 2) + } //~ ERROR Data race detected between Deallocate on thread `` and Write on thread `` }); let j2 = spawn(move || { diff --git a/tests/fail/data_race/dealloc_write_race_stack.stderr b/tests/fail/data_race/dealloc_write_race_stack.stderr index 28a131aac07b5..622ac25189be5 100644 --- a/tests/fail/data_race/dealloc_write_race_stack.stderr +++ b/tests/fail/data_race/dealloc_write_race_stack.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: Data race detected between Deallocate on Thread(id = 1) and Write on Thread(id = 2) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) +error: Undefined Behavior: Data race detected between Deallocate on thread `` and Write on thread `` at ALLOC --> $DIR/dealloc_write_race_stack.rs:LL:CC | LL | } - | ^ Data race detected between Deallocate on Thread(id = 1) and Write on Thread(id = 2) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) + | ^ Data race detected between Deallocate on thread `` and Write on thread `` at ALLOC | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/data_race/enable_after_join_to_main.rs b/tests/fail/data_race/enable_after_join_to_main.rs index 832158a34a6a6..6f0735fac897c 100644 --- a/tests/fail/data_race/enable_after_join_to_main.rs +++ b/tests/fail/data_race/enable_after_join_to_main.rs @@ -29,7 +29,7 @@ pub fn main() { }); let j2 = spawn(move || { - *c.0 = 64; //~ ERROR Data race detected between Write on Thread(id = 6) and Write on Thread(id = 5) + *c.0 = 64; //~ ERROR Data race detected between Write on thread `` and Write on thread `` }); j1.join().unwrap(); diff --git a/tests/fail/data_race/enable_after_join_to_main.stderr b/tests/fail/data_race/enable_after_join_to_main.stderr index db7577b0966e5..4426952e44b55 100644 --- a/tests/fail/data_race/enable_after_join_to_main.stderr +++ b/tests/fail/data_race/enable_after_join_to_main.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: Data race detected between Write on Thread(id = 6) and Write on Thread(id = 5) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) +error: Undefined Behavior: Data race detected between Write on thread `` and Write on thread `` at ALLOC --> $DIR/enable_after_join_to_main.rs:LL:CC | LL | *c.0 = 64; - | ^^^^^^^^^ Data race detected between Write on Thread(id = 6) and Write on Thread(id = 5) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) + | ^^^^^^^^^ Data race detected between Write on thread `` and Write on thread `` at ALLOC | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/data_race/fence_after_load.rs b/tests/fail/data_race/fence_after_load.rs index c209ef1812530..5a8c2e585f49a 100644 --- a/tests/fail/data_race/fence_after_load.rs +++ b/tests/fail/data_race/fence_after_load.rs @@ -21,5 +21,5 @@ fn main() { // The fence is useless, since it did not happen-after the `store` in the other thread. // Hence this is a data race. // Also see https://github.com/rust-lang/miri/issues/2192. - unsafe { V = 2 } //~ERROR Data race detected + unsafe { V = 2 } //~ERROR Data race detected between Write on thread `main` and Write on thread `` } diff --git a/tests/fail/data_race/fence_after_load.stderr b/tests/fail/data_race/fence_after_load.stderr index 17cc6a82a1c2a..b9cffeda27bef 100644 --- a/tests/fail/data_race/fence_after_load.stderr +++ b/tests/fail/data_race/fence_after_load.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: Data race detected between Write on Thread(id = 0, name = "main") and Write on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) +error: Undefined Behavior: Data race detected between Write on thread `main` and Write on thread `` at ALLOC --> $DIR/fence_after_load.rs:LL:CC | LL | unsafe { V = 2 } - | ^^^^^ Data race detected between Write on Thread(id = 0, name = "main") and Write on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) + | ^^^^^ Data race detected between Write on thread `main` and Write on thread `` at ALLOC | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/data_race/read_write_race.rs b/tests/fail/data_race/read_write_race.rs index 9197912ef2e9d..eeb49bb42ab7c 100644 --- a/tests/fail/data_race/read_write_race.rs +++ b/tests/fail/data_race/read_write_race.rs @@ -18,7 +18,7 @@ pub fn main() { }); let j2 = spawn(move || { - *c.0 = 64; //~ ERROR Data race detected between Write on Thread(id = 2) and Read on Thread(id = 1) + *c.0 = 64; //~ ERROR Data race detected between Write on thread `` and Read on thread `` }); j1.join().unwrap(); diff --git a/tests/fail/data_race/read_write_race.stderr b/tests/fail/data_race/read_write_race.stderr index b775e2b6fdf1f..a65e7006cf0a8 100644 --- a/tests/fail/data_race/read_write_race.stderr +++ b/tests/fail/data_race/read_write_race.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: Data race detected between Write on Thread(id = 2) and Read on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) +error: Undefined Behavior: Data race detected between Write on thread `` and Read on thread `` at ALLOC --> $DIR/read_write_race.rs:LL:CC | LL | *c.0 = 64; - | ^^^^^^^^^ Data race detected between Write on Thread(id = 2) and Read on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) + | ^^^^^^^^^ Data race detected between Write on thread `` and Read on thread `` at ALLOC | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/data_race/read_write_race_stack.rs b/tests/fail/data_race/read_write_race_stack.rs index 00c36176a9f1e..124f12d1ecd28 100644 --- a/tests/fail/data_race/read_write_race_stack.rs +++ b/tests/fail/data_race/read_write_race_stack.rs @@ -43,7 +43,7 @@ pub fn main() { sleep(Duration::from_millis(200)); - stack_var //~ ERROR Data race detected between Read on Thread(id = 1) and Write on Thread(id = 2) + stack_var //~ ERROR Data race detected between Read on thread `` and Write on thread `` }); let j2 = spawn(move || { diff --git a/tests/fail/data_race/read_write_race_stack.stderr b/tests/fail/data_race/read_write_race_stack.stderr index 0f5f4956ffdae..390b3ab38ede0 100644 --- a/tests/fail/data_race/read_write_race_stack.stderr +++ b/tests/fail/data_race/read_write_race_stack.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: Data race detected between Read on Thread(id = 1) and Write on Thread(id = 2) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) +error: Undefined Behavior: Data race detected between Read on thread `` and Write on thread `` at ALLOC --> $DIR/read_write_race_stack.rs:LL:CC | LL | stack_var - | ^^^^^^^^^ Data race detected between Read on Thread(id = 1) and Write on Thread(id = 2) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) + | ^^^^^^^^^ Data race detected between Read on thread `` and Write on thread `` at ALLOC | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/data_race/relax_acquire_race.rs b/tests/fail/data_race/relax_acquire_race.rs index 3b350f5c89f2d..faa23a150e3fa 100644 --- a/tests/fail/data_race/relax_acquire_race.rs +++ b/tests/fail/data_race/relax_acquire_race.rs @@ -38,7 +38,7 @@ pub fn main() { let j3 = spawn(move || { if SYNC.load(Ordering::Acquire) == 2 { - *c.0 //~ ERROR Data race detected between Read on Thread(id = 3) and Write on Thread(id = 1) + *c.0 //~ ERROR Data race detected between Read on thread `` and Write on thread `` } else { 0 } diff --git a/tests/fail/data_race/relax_acquire_race.stderr b/tests/fail/data_race/relax_acquire_race.stderr index fb376b58f2c16..85de60c026550 100644 --- a/tests/fail/data_race/relax_acquire_race.stderr +++ b/tests/fail/data_race/relax_acquire_race.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: Data race detected between Read on Thread(id = 3) and Write on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) +error: Undefined Behavior: Data race detected between Read on thread `` and Write on thread `` at ALLOC --> $DIR/relax_acquire_race.rs:LL:CC | LL | *c.0 - | ^^^^ Data race detected between Read on Thread(id = 3) and Write on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) + | ^^^^ Data race detected between Read on thread `` and Write on thread `` at ALLOC | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/data_race/release_seq_race.rs b/tests/fail/data_race/release_seq_race.rs index ec03888c76b18..ab6926102a2a1 100644 --- a/tests/fail/data_race/release_seq_race.rs +++ b/tests/fail/data_race/release_seq_race.rs @@ -42,7 +42,7 @@ pub fn main() { let j3 = spawn(move || { sleep(Duration::from_millis(500)); if SYNC.load(Ordering::Acquire) == 3 { - *c.0 //~ ERROR Data race detected between Read on Thread(id = 3) and Write on Thread(id = 1) + *c.0 //~ ERROR Data race detected between Read on thread `` and Write on thread `` } else { 0 } diff --git a/tests/fail/data_race/release_seq_race.stderr b/tests/fail/data_race/release_seq_race.stderr index 1de9c0ac1c7fd..db333d756f855 100644 --- a/tests/fail/data_race/release_seq_race.stderr +++ b/tests/fail/data_race/release_seq_race.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: Data race detected between Read on Thread(id = 3) and Write on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) +error: Undefined Behavior: Data race detected between Read on thread `` and Write on thread `` at ALLOC --> $DIR/release_seq_race.rs:LL:CC | LL | *c.0 - | ^^^^ Data race detected between Read on Thread(id = 3) and Write on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) + | ^^^^ Data race detected between Read on thread `` and Write on thread `` at ALLOC | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/data_race/release_seq_race_same_thread.rs b/tests/fail/data_race/release_seq_race_same_thread.rs index 1876238289475..d3d18f0e2540d 100644 --- a/tests/fail/data_race/release_seq_race_same_thread.rs +++ b/tests/fail/data_race/release_seq_race_same_thread.rs @@ -38,7 +38,7 @@ pub fn main() { let j2 = spawn(move || { if SYNC.load(Ordering::Acquire) == 2 { - *c.0 //~ ERROR Data race detected between Read on Thread(id = 2) and Write on Thread(id = 1) + *c.0 //~ ERROR Data race detected between Read on thread `` and Write on thread `` } else { 0 } diff --git a/tests/fail/data_race/release_seq_race_same_thread.stderr b/tests/fail/data_race/release_seq_race_same_thread.stderr index 9bbdd9a475733..f4c38d5315006 100644 --- a/tests/fail/data_race/release_seq_race_same_thread.stderr +++ b/tests/fail/data_race/release_seq_race_same_thread.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: Data race detected between Read on Thread(id = 2) and Write on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) +error: Undefined Behavior: Data race detected between Read on thread `` and Write on thread `` at ALLOC --> $DIR/release_seq_race_same_thread.rs:LL:CC | LL | *c.0 - | ^^^^ Data race detected between Read on Thread(id = 2) and Write on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) + | ^^^^ Data race detected between Read on thread `` and Write on thread `` at ALLOC | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/data_race/rmw_race.rs b/tests/fail/data_race/rmw_race.rs index 51577b3b7b191..800b1043c00b5 100644 --- a/tests/fail/data_race/rmw_race.rs +++ b/tests/fail/data_race/rmw_race.rs @@ -39,7 +39,7 @@ pub fn main() { let j3 = spawn(move || { if SYNC.load(Ordering::Acquire) == 3 { - *c.0 //~ ERROR Data race detected between Read on Thread(id = 3) and Write on Thread(id = 1) + *c.0 //~ ERROR Data race detected between Read on thread `` and Write on thread `` } else { 0 } diff --git a/tests/fail/data_race/rmw_race.stderr b/tests/fail/data_race/rmw_race.stderr index 10d3291fa733d..346fcc31b9c06 100644 --- a/tests/fail/data_race/rmw_race.stderr +++ b/tests/fail/data_race/rmw_race.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: Data race detected between Read on Thread(id = 3) and Write on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) +error: Undefined Behavior: Data race detected between Read on thread `` and Write on thread `` at ALLOC --> $DIR/rmw_race.rs:LL:CC | LL | *c.0 - | ^^^^ Data race detected between Read on Thread(id = 3) and Write on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) + | ^^^^ Data race detected between Read on thread `` and Write on thread `` at ALLOC | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/data_race/write_write_race.rs b/tests/fail/data_race/write_write_race.rs index 61909eda86337..989ae31a6d281 100644 --- a/tests/fail/data_race/write_write_race.rs +++ b/tests/fail/data_race/write_write_race.rs @@ -18,7 +18,7 @@ pub fn main() { }); let j2 = spawn(move || { - *c.0 = 64; //~ ERROR Data race detected between Write on Thread(id = 2) and Write on Thread(id = 1) + *c.0 = 64; //~ ERROR Data race detected between Write on thread `` and Write on thread `` }); j1.join().unwrap(); diff --git a/tests/fail/data_race/write_write_race.stderr b/tests/fail/data_race/write_write_race.stderr index 0054f5bf63a05..e6254281aef36 100644 --- a/tests/fail/data_race/write_write_race.stderr +++ b/tests/fail/data_race/write_write_race.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: Data race detected between Write on Thread(id = 2) and Write on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) +error: Undefined Behavior: Data race detected between Write on thread `` and Write on thread `` at ALLOC --> $DIR/write_write_race.rs:LL:CC | LL | *c.0 = 64; - | ^^^^^^^^^ Data race detected between Write on Thread(id = 2) and Write on Thread(id = 1) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) + | ^^^^^^^^^ Data race detected between Write on thread `` and Write on thread `` at ALLOC | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/data_race/write_write_race_stack.rs b/tests/fail/data_race/write_write_race_stack.rs index 49de5db43b720..3c1eabbf251b2 100644 --- a/tests/fail/data_race/write_write_race_stack.rs +++ b/tests/fail/data_race/write_write_race_stack.rs @@ -40,7 +40,7 @@ pub fn main() { sleep(Duration::from_millis(200)); - stack_var = 1usize; //~ ERROR Data race detected between Write on Thread(id = 1) and Write on Thread(id = 2) + stack_var = 1usize; //~ ERROR Data race detected between Write on thread `` and Write on thread `` // read to silence errors stack_var diff --git a/tests/fail/data_race/write_write_race_stack.stderr b/tests/fail/data_race/write_write_race_stack.stderr index 2012643431f6e..1f7318e6f9515 100644 --- a/tests/fail/data_race/write_write_race_stack.stderr +++ b/tests/fail/data_race/write_write_race_stack.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: Data race detected between Write on Thread(id = 1) and Write on Thread(id = 2) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) +error: Undefined Behavior: Data race detected between Write on thread `` and Write on thread `` at ALLOC --> $DIR/write_write_race_stack.rs:LL:CC | LL | stack_var = 1usize; - | ^^^^^^^^^^^^^^^^^^ Data race detected between Write on Thread(id = 1) and Write on Thread(id = 2) at ALLOC (current vector clock = VClock, conflicting timestamp = VClock) + | ^^^^^^^^^^^^^^^^^^ Data race detected between Write on thread `` and Write on thread `` at ALLOC | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/pass/libc.rs b/tests/pass/libc.rs index b108a01dae37e..bf7a59da973cd 100644 --- a/tests/pass/libc.rs +++ b/tests/pass/libc.rs @@ -218,7 +218,8 @@ fn test_prctl_thread_name() { libc::prctl(libc::PR_GET_NAME, buf.as_mut_ptr(), 0 as c_long, 0 as c_long, 0 as c_long), 0, ); - assert_eq!(b"\0", &buf); + // Rust runtime might set thread name, so we allow two options here. + assert!(&buf[..10] == b"\0" || &buf[..5] == b"main\0"); let thread_name = CString::new("hello").expect("CString::new failed"); assert_eq!( libc::prctl( From 17acc3f71cf8a8e4f2b3c82d453982dd08e13d07 Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Fri, 1 Jul 2022 20:15:34 -0400 Subject: [PATCH 3383/3747] Document implementation a bit, add some fast paths --- src/stacked_borrows/stack.rs | 26 ++++++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/src/stacked_borrows/stack.rs b/src/stacked_borrows/stack.rs index e6dc507802fd0..6e0d166086fc7 100644 --- a/src/stacked_borrows/stack.rs +++ b/src/stacked_borrows/stack.rs @@ -51,6 +51,13 @@ struct StackCache { #[cfg(feature = "stack-cache")] impl StackCache { + /// When a tag is used, we call this function to add or refresh it in the cache. + /// + /// We use position in the cache to represent how recently a tag was used; the first position + /// is the most recently used tag. So an add shifts every element towards the end, and inserts + /// the new element at the start. We lose the last element. + /// This strategy is effective at keeping the most-accessed tags in the cache, but it costs a + /// linear shift across the entire cache when we add a new tag. fn add(&mut self, idx: usize, tag: SbTag) { self.tags.copy_within(0..CACHE_LEN - 1, 1); self.tags[0] = tag; @@ -172,9 +179,12 @@ impl<'tcx> Stack { // If we found the tag, look up its position in the stack to see if it grants // the required permission if self.borrows[stack_idx].perm.grants(access) { - // If it does, and it's already in the most-recently-used position, move it - // there. - if cache_idx != 0 { + // If it does, and it's not already in the most-recently-used position, move it there. + // Except if the tag is in position 1, this is equivalent to just a swap, so do that. + if cache_idx == 1 { + self.cache.tags.swap(0, 1); + self.cache.idx.swap(0, 1); + } else if cache_idx > 1 { self.cache.add(stack_idx, tag); } Some(stack_idx) @@ -208,9 +218,13 @@ impl<'tcx> Stack { // The above insert changes the meaning of every index in the cache >= new_idx, so now // we need to find every one of those indexes and increment it. - for idx in &mut self.cache.idx { - if *idx >= new_idx { - *idx += 1; + // But if the insert is at the end (equivalent to a push), we can skip this step because + // it didn't change the position of any other tags. + if new_idx != self.borrows.len() - 1 { + for idx in &mut self.cache.idx { + if *idx >= new_idx { + *idx += 1; + } } } From a1473ea8f5b065a81c046d53e465d1d0b9e01fad Mon Sep 17 00:00:00 2001 From: Christian Legnitto Date: Fri, 1 Jul 2022 20:05:15 -0600 Subject: [PATCH 3384/3747] Support (stat/fstat/lstat)64 on macos "In order to accommodate advanced capabilities of newer file systems, the struct stat, struct statfs, and struct dirent data structures were updated in Mac OSX 10.5." "TRANSITIONAL DESCRIPTION (NOW DEPRECATED) The fstat64, lstat64 and stat64 routines are equivalent to their corresponding non-64-suffixed routine, when 64-bit inodes are in effect. They were added before there was support for the symbol variants, and so are now deprecated. Instead of using these, set the _DARWIN_USE_64_BIT_INODE macro before including header files to force 64-bit inode support. The stat64 structure used by these deprecated routines is the same as the stat structure when 64-bit inodes are in effect (see above)." "HISTORY An lstat() function call appeared in 4.2BSD. The stat64(), fstat64(), and lstat64() system calls first appeared in Mac OS X 10.5 (Leopard) and are now deprecated in favor of the corresponding symbol variants. The fstatat() system call appeared in OS X 10.10" --- src/shims/unix/macos/foreign_items.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/shims/unix/macos/foreign_items.rs b/src/shims/unix/macos/foreign_items.rs index e545a4691bf04..5cd885db7099b 100644 --- a/src/shims/unix/macos/foreign_items.rs +++ b/src/shims/unix/macos/foreign_items.rs @@ -33,19 +33,19 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let result = this.close(result)?; this.write_scalar(Scalar::from_i32(result), dest)?; } - "stat" | "stat$INODE64" => { + "stat" | "stat64" | "stat$INODE64" => { let [path, buf] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.macos_stat(path, buf)?; this.write_scalar(Scalar::from_i32(result), dest)?; } - "lstat" | "lstat$INODE64" => { + "lstat" | "lstat64" | "lstat$INODE64" => { let [path, buf] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.macos_lstat(path, buf)?; this.write_scalar(Scalar::from_i32(result), dest)?; } - "fstat" | "fstat$INODE64" => { + "fstat" | "fstat64" | "fstat$INODE64" => { let [fd, buf] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.macos_fstat(fd, buf)?; this.write_scalar(Scalar::from_i32(result), dest)?; From 5ec25359ff620c6f7371c55b4fa778c9127f9be8 Mon Sep 17 00:00:00 2001 From: InfRandomness Date: Fri, 1 Jul 2022 21:24:24 +0200 Subject: [PATCH 3385/3747] Add `environ` extern implementation to freebsd Signed-off-by: InfRandomness --- src/machine.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/machine.rs b/src/machine.rs index 86b174182c1f1..1b7fc4ffb9637 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -442,6 +442,14 @@ impl<'mir, 'tcx> Evaluator<'mir, 'tcx> { Self::add_extern_static(this, name, place.ptr); } } + "freebsd" => { + // "environ" + Self::add_extern_static( + this, + "environ", + this.machine.env_vars.environ.unwrap().ptr, + ); + } "windows" => { // "_tls_used" // This is some obscure hack that is part of the Windows TLS story. It's a `u8`. From a26be7ea5f353a3db9bc7684029b57f8e2c41259 Mon Sep 17 00:00:00 2001 From: InfRandomness Date: Fri, 1 Jul 2022 21:28:45 +0200 Subject: [PATCH 3386/3747] Enable env test on freebsd Signed-off-by: InfRandomness --- ci.sh | 2 +- tests/fail/environ-gets-deallocated.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ci.sh b/ci.sh index 5c7ab545f9581..b914477d44a81 100755 --- a/ci.sh +++ b/ci.sh @@ -60,7 +60,7 @@ case $HOST_TARGET in MIRI_TEST_TARGET=i686-unknown-linux-gnu run_tests MIRI_TEST_TARGET=aarch64-apple-darwin run_tests MIRI_TEST_TARGET=i686-pc-windows-msvc run_tests - MIRI_TEST_TARGET=x86_64-unknown-freebsd run_tests_minimal hello integer vec current_dir data_race + MIRI_TEST_TARGET=x86_64-unknown-freebsd run_tests_minimal hello integer vec current_dir data_race env MIRI_TEST_TARGET=thumbv7em-none-eabihf MIRI_NO_STD=1 run_tests_minimal no_std # no_std embedded architecture ;; x86_64-apple-darwin) diff --git a/tests/fail/environ-gets-deallocated.rs b/tests/fail/environ-gets-deallocated.rs index 4df9be2bf24de..f50a66e2c766e 100644 --- a/tests/fail/environ-gets-deallocated.rs +++ b/tests/fail/environ-gets-deallocated.rs @@ -1,6 +1,6 @@ // ignore-windows: Windows does not have a global environ list that the program can access directly -#[cfg(target_os = "linux")] +#[cfg(any(target_os = "linux", target_os = "freebsd"))] fn get_environ() -> *const *const u8 { extern "C" { static mut environ: *const *const u8; From c0cbb662d2103149b7ce3f8ff3e75fc4933e9f3d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 2 Jul 2022 08:38:07 -0400 Subject: [PATCH 3387/3747] rustup --- rust-version | 2 +- tests/fail/erroneous_const2.stderr | 4 +--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/rust-version b/rust-version index 4198e8cf3c086..682914e88290b 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -ca1e68b3229e710c3948a361ee770d846a88e6da +46b8c23f3eb5e4d0e0aa27eb3f20d5b8fc3ed51f diff --git a/tests/fail/erroneous_const2.stderr b/tests/fail/erroneous_const2.stderr index d5c89a8e82bf3..75e3d9bcd2114 100644 --- a/tests/fail/erroneous_const2.stderr +++ b/tests/fail/erroneous_const2.stderr @@ -2,9 +2,7 @@ error: any use of this value will cause an error --> $DIR/erroneous_const2.rs:LL:CC | LL | const FOO: u32 = [X - Y, Y - X][(X < Y) as usize]; - | ------------------^^^^^--------------------------- - | | - | attempt to compute `5_u32 - 6_u32`, which would overflow + | -------------- ^^^^^ attempt to compute `5_u32 - 6_u32`, which would overflow | = note: `#[deny(const_err)]` on by default = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! From 98d20490f4dd104f684f52e33adbdbedc92ab720 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 2 Jul 2022 08:58:04 -0400 Subject: [PATCH 3388/3747] move some POSIX file shims from linux to unix module --- src/shims/unix/foreign_items.rs | 19 +++++++++++++++++-- src/shims/unix/linux/foreign_items.rs | 18 ------------------ src/shims/unix/macos/foreign_items.rs | 12 ++++++++++-- 3 files changed, 27 insertions(+), 22 deletions(-) diff --git a/src/shims/unix/foreign_items.rs b/src/shims/unix/foreign_items.rs index 4a452800044ff..43b0f7df7f01f 100644 --- a/src/shims/unix/foreign_items.rs +++ b/src/shims/unix/foreign_items.rs @@ -62,6 +62,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let result = this.open(args)?; this.write_scalar(Scalar::from_i32(result), dest)?; } + "close" => { + let [fd] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let result = this.close(fd)?; + this.write_scalar(Scalar::from_i32(result), dest)?; + } "fcntl" => { // `fcntl` is variadic. The argument count is checked based on the first argument // in `this.fcntl()`, so we do not use `check_shim` here. @@ -112,17 +117,27 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let result = this.rmdir(path)?; this.write_scalar(Scalar::from_i32(result), dest)?; } + "opendir" => { + let [name] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let result = this.opendir(name)?; + this.write_scalar(result, dest)?; + } "closedir" => { let [dirp] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.closedir(dirp)?; this.write_scalar(Scalar::from_i32(result), dest)?; } - "lseek" | "lseek64" => { + "lseek64" => { let [fd, offset, whence] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.lseek64(fd, offset, whence)?; - // "lseek" is only used on macOS which is 64bit-only, so `i64` always works. this.write_scalar(Scalar::from_i64(result), dest)?; } + "ftruncate64" => { + let [fd, length] = + this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let result = this.ftruncate64(fd, length)?; + this.write_scalar(Scalar::from_i32(result), dest)?; + } "fsync" => { let [fd] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.fsync(fd)?; diff --git a/src/shims/unix/linux/foreign_items.rs b/src/shims/unix/linux/foreign_items.rs index 48abe9bf08c33..d89a2c78f4b19 100644 --- a/src/shims/unix/linux/foreign_items.rs +++ b/src/shims/unix/linux/foreign_items.rs @@ -30,29 +30,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // File related shims (but also see "syscall" below for statx) - // These symbols have different names on Linux and macOS, which is the only reason they are not - // in the `posix` module. - "close" => { - let [fd] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; - let result = this.close(fd)?; - this.write_scalar(Scalar::from_i32(result), dest)?; - } - "opendir" => { - let [name] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; - let result = this.opendir(name)?; - this.write_scalar(result, dest)?; - } "readdir64" => { let [dirp] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.linux_readdir64(dirp)?; this.write_scalar(result, dest)?; } - "ftruncate64" => { - let [fd, length] = - this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; - let result = this.ftruncate64(fd, length)?; - this.write_scalar(Scalar::from_i32(result), dest)?; - } // Linux-only "posix_fadvise" => { let [fd, offset, len, advice] = diff --git a/src/shims/unix/macos/foreign_items.rs b/src/shims/unix/macos/foreign_items.rs index 5cd885db7099b..089a082fa3699 100644 --- a/src/shims/unix/macos/foreign_items.rs +++ b/src/shims/unix/macos/foreign_items.rs @@ -28,7 +28,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // File related shims - "close" | "close$NOCANCEL" => { + "close$NOCANCEL" => { let [result] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.close(result)?; this.write_scalar(Scalar::from_i32(result), dest)?; @@ -50,7 +50,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let result = this.macos_fstat(fd, buf)?; this.write_scalar(Scalar::from_i32(result), dest)?; } - "opendir" | "opendir$INODE64" => { + "opendir$INODE64" => { let [name] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.opendir(name)?; this.write_scalar(result, dest)?; @@ -61,9 +61,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let result = this.macos_readdir_r(dirp, entry, result)?; this.write_scalar(Scalar::from_i32(result), dest)?; } + "lseek" => { + let [fd, offset, whence] = + this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + // macOS is 64bit-only, so this is lseek64 + let result = this.lseek64(fd, offset, whence)?; + this.write_scalar(Scalar::from_i64(result), dest)?; + } "ftruncate" => { let [fd, length] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + // macOS is 64bit-only, so this is ftruncate64 let result = this.ftruncate64(fd, length)?; this.write_scalar(Scalar::from_i32(result), dest)?; } From ae51998191313b7191831e831d93a6d3fe0e4238 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 2 Jul 2022 09:06:17 -0400 Subject: [PATCH 3389/3747] male libc.rs at least build on FreeBSD --- tests/pass/libc.rs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/tests/pass/libc.rs b/tests/pass/libc.rs index bf7a59da973cd..d08430a43260a 100644 --- a/tests/pass/libc.rs +++ b/tests/pass/libc.rs @@ -42,7 +42,7 @@ fn test_posix_fadvise() { assert_eq!(result, 0); } -#[cfg(any(target_os = "linux", target_os = "freebsd"))] +#[cfg(any(target_os = "linux"))] fn test_sync_file_range() { use std::fs::{remove_file, File}; use std::io::Write; @@ -208,7 +208,7 @@ fn test_rwlock_libc_static_initializer() { /// Test whether the `prctl` shim correctly sets the thread name. /// /// Note: `prctl` exists only on Linux. -#[cfg(any(target_os = "linux", target_os = "freebsd"))] +#[cfg(any(target_os = "linux"))] fn test_prctl_thread_name() { use libc::c_long; use std::ffi::CString; @@ -259,9 +259,9 @@ fn test_prctl_thread_name() { /// Tests whether each thread has its own `__errno_location`. fn test_thread_local_errno() { - #[cfg(not(target_os = "macos"))] + #[cfg(target_os = "linux")] use libc::__errno_location; - #[cfg(target_os = "macos")] + #[cfg(any(target_os = "macos", target_os = "freebsd"))] use libc::__error as __errno_location; unsafe { @@ -278,7 +278,7 @@ fn test_thread_local_errno() { } /// Tests whether clock support exists at all -#[cfg(any(target_os = "linux", target_os = "freebsd"))] +#[cfg(any(target_os = "linux"))] fn test_clocks() { let mut tp = std::mem::MaybeUninit::::uninit(); let is_error = unsafe { libc::clock_gettime(libc::CLOCK_REALTIME, tp.as_mut_ptr()) }; @@ -317,7 +317,7 @@ fn main() { test_posix_gettimeofday(); - #[cfg(any(target_os = "linux", target_os = "freebsd"))] + #[cfg(any(target_os = "linux"))] test_sync_file_range(); test_mutex_libc_init_recursive(); @@ -325,14 +325,14 @@ fn main() { test_mutex_libc_init_errorcheck(); test_rwlock_libc_static_initializer(); - #[cfg(any(target_os = "linux", target_os = "freebsd"))] + #[cfg(any(target_os = "linux"))] test_mutex_libc_static_initializer_recursive(); - #[cfg(any(target_os = "linux", target_os = "freebsd"))] + #[cfg(any(target_os = "linux"))] test_prctl_thread_name(); test_thread_local_errno(); - #[cfg(any(target_os = "linux", target_os = "freebsd"))] + #[cfg(any(target_os = "linux"))] test_clocks(); } From 5ba2c1e6be8d79837fb439bafe74b9a20500cf22 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 2 Jul 2022 09:06:35 -0400 Subject: [PATCH 3390/3747] posix_fadvise is not Linux-specific --- src/shims/unix/foreign_items.rs | 10 ++++++++++ src/shims/unix/linux/foreign_items.rs | 10 ---------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/shims/unix/foreign_items.rs b/src/shims/unix/foreign_items.rs index 43b0f7df7f01f..44147433c037e 100644 --- a/src/shims/unix/foreign_items.rs +++ b/src/shims/unix/foreign_items.rs @@ -153,6 +153,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let result = this.readlink(pathname, buf, bufsize)?; this.write_scalar(Scalar::from_machine_isize(result, this), dest)?; } + "posix_fadvise" => { + let [fd, offset, len, advice] = + this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + this.read_scalar(fd)?.to_i32()?; + this.read_scalar(offset)?.to_machine_isize(this)?; + this.read_scalar(len)?.to_machine_isize(this)?; + this.read_scalar(advice)?.to_i32()?; + // fadvise is only informational, we can ignore it. + this.write_null(dest)?; + } // Time related shims "gettimeofday" => { diff --git a/src/shims/unix/linux/foreign_items.rs b/src/shims/unix/linux/foreign_items.rs index d89a2c78f4b19..bbdb1b8a31c45 100644 --- a/src/shims/unix/linux/foreign_items.rs +++ b/src/shims/unix/linux/foreign_items.rs @@ -36,16 +36,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(result, dest)?; } // Linux-only - "posix_fadvise" => { - let [fd, offset, len, advice] = - this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; - this.read_scalar(fd)?.to_i32()?; - this.read_scalar(offset)?.to_machine_isize(this)?; - this.read_scalar(len)?.to_machine_isize(this)?; - this.read_scalar(advice)?.to_i32()?; - // fadvise is only informational, we can ignore it. - this.write_null(dest)?; - } "sync_file_range" => { let [fd, offset, nbytes, flags] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; From 98254f67af20a67747835f03c314be9c9a42d769 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 2 Jul 2022 10:11:39 -0400 Subject: [PATCH 3391/3747] pointer tag tracking: on creation, log the offsets it is created for --- src/diagnostics.rs | 12 ++++--- src/stacked_borrows.rs | 32 ++++++++++++++----- .../alloc/deallocate-bad-alignment.stderr | 2 +- tests/fail/alloc/deallocate-bad-size.stderr | 2 +- tests/fail/alloc/deallocate-twice.stderr | 2 +- tests/fail/alloc/global_system_mixup.stderr | 2 +- tests/fail/alloc/no_global_allocator.stderr | 2 +- tests/fail/alloc/reallocate-bad-size.stderr | 2 +- .../fail/alloc/reallocate-change-alloc.stderr | 2 +- tests/fail/alloc/reallocate-dangling.stderr | 2 +- tests/fail/alloc/stack_free.stderr | 2 +- .../fail/backtrace/bad-backtrace-decl.stderr | 2 +- .../fail/backtrace/bad-backtrace-flags.stderr | 2 +- tests/fail/backtrace/bad-backtrace-ptr.stderr | 2 +- .../bad-backtrace-resolve-flags.stderr | 2 +- .../bad-backtrace-resolve-names-flags.stderr | 2 +- .../backtrace/bad-backtrace-size-flags.stderr | 2 +- tests/fail/box-cell-alias.stderr | 1 + .../branchless-select-i128-pointer.stderr | 2 +- .../libc_pthread_join_detached.stderr | 2 +- .../libc_pthread_join_joined.stderr | 2 +- .../concurrency/libc_pthread_join_main.stderr | 2 +- .../libc_pthread_join_multiple.stderr | 2 +- .../concurrency/libc_pthread_join_self.stderr | 2 +- tests/fail/concurrency/thread-spawn.stderr | 2 +- .../thread_local_static_dealloc.stderr | 2 +- tests/fail/concurrency/too_few_args.stderr | 2 +- tests/fail/concurrency/too_many_args.stderr | 2 +- .../concurrency/unwind_top_of_stack.stderr | 2 +- .../dangling_pointer_addr_of.stderr | 2 +- .../dangling_pointer_deref.stderr | 2 +- .../dangling_zst_deref.stderr | 2 +- .../deref-invalid-ptr.stderr | 2 +- .../deref-partially-dangling.stderr | 2 +- tests/fail/dangling_pointers/dyn_size.stderr | 2 +- .../maybe_null_pointer_deref_zst.stderr | 2 +- .../maybe_null_pointer_write_zst.stderr | 2 +- .../null_pointer_deref.stderr | 2 +- .../null_pointer_deref_zst.stderr | 2 +- .../null_pointer_write.stderr | 2 +- .../null_pointer_write_zst.stderr | 2 +- .../out_of_bounds_read1.stderr | 2 +- .../out_of_bounds_read2.stderr | 2 +- .../dangling_pointers/stack_temporary.stderr | 2 +- .../storage_dead_dangling.stderr | 2 +- .../wild_pointer_deref.stderr | 2 +- tests/fail/data_race/alloc_read_race.stderr | 2 +- tests/fail/data_race/alloc_write_race.stderr | 2 +- .../atomic_read_na_write_race1.stderr | 2 +- .../atomic_read_na_write_race2.stderr | 2 +- .../atomic_write_na_read_race1.stderr | 2 +- .../atomic_write_na_read_race2.stderr | 2 +- .../atomic_write_na_write_race1.stderr | 2 +- .../atomic_write_na_write_race2.stderr | 2 +- .../dangling_thread_async_race.stderr | 2 +- .../data_race/dangling_thread_race.stderr | 2 +- .../fail/data_race/dealloc_read_race1.stderr | 2 +- .../fail/data_race/dealloc_read_race2.stderr | 2 +- .../data_race/dealloc_read_race_stack.stderr | 2 +- .../fail/data_race/dealloc_write_race1.stderr | 2 +- .../fail/data_race/dealloc_write_race2.stderr | 2 +- .../data_race/dealloc_write_race_stack.stderr | 2 +- .../enable_after_join_to_main.stderr | 2 +- tests/fail/data_race/fence_after_load.stderr | 2 +- tests/fail/data_race/read_write_race.stderr | 2 +- .../data_race/read_write_race_stack.stderr | 2 +- .../fail/data_race/relax_acquire_race.stderr | 2 +- tests/fail/data_race/release_seq_race.stderr | 2 +- .../release_seq_race_same_thread.stderr | 2 +- tests/fail/data_race/rmw_race.stderr | 2 +- tests/fail/data_race/write_write_race.stderr | 2 +- .../data_race/write_write_race_stack.stderr | 2 +- tests/fail/environ-gets-deallocated.stderr | 2 +- tests/fail/extern_static.stderr | 2 +- tests/fail/extern_static_in_const.stderr | 2 +- tests/fail/fast_math_both.stderr | 2 +- tests/fail/fast_math_first.stderr | 2 +- tests/fail/fast_math_second.stderr | 2 +- tests/fail/fs/close_stdout.stderr | 2 +- tests/fail/fs/isolated_file.stderr | 2 +- tests/fail/fs/isolated_stdin.stderr | 2 +- tests/fail/fs/read_from_stdout.stderr | 2 +- .../fs/unix_open_missing_required_mode.stderr | 2 +- tests/fail/fs/write_to_stdin.stderr | 2 +- .../fail/function_calls/check_arg_abi.stderr | 2 +- .../check_arg_count_abort.stderr | 2 +- .../check_arg_count_too_few_args.stderr | 2 +- .../check_arg_count_too_many_args.stderr | 2 +- .../function_calls/check_callback_abi.stderr | 2 +- .../exported_symbol_abi_mismatch.cache.stderr | 2 +- ...exported_symbol_abi_mismatch.fn_ptr.stderr | 2 +- ...ported_symbol_abi_mismatch.no_cache.stderr | 2 +- .../exported_symbol_bad_unwind1.stderr | 2 +- ...ted_symbol_bad_unwind2.extern_block.stderr | 2 +- .../exported_symbol_clashing.stderr | 1 + .../exported_symbol_shim_clashing.stderr | 1 + .../exported_symbol_wrong_arguments.stderr | 2 +- .../exported_symbol_wrong_type.stderr | 2 +- .../cast_box_int_to_fn_ptr.stderr | 2 +- .../function_pointers/cast_fn_ptr1.stderr | 2 +- .../function_pointers/cast_fn_ptr2.stderr | 2 +- .../function_pointers/cast_fn_ptr3.stderr | 2 +- .../function_pointers/cast_fn_ptr4.stderr | 2 +- .../function_pointers/cast_fn_ptr5.stderr | 2 +- .../cast_int_to_fn_ptr.stderr | 2 +- .../function_pointers/deref_fn_ptr.stderr | 2 +- .../function_pointers/execute_memory.stderr | 2 +- .../function_pointers/fn_ptr_offset.stderr | 2 +- tests/fail/generator-pinned-moved.stderr | 2 +- tests/fail/intrinsics/assume.stderr | 2 +- tests/fail/intrinsics/copy_null.stderr | 2 +- tests/fail/intrinsics/copy_overflow.stderr | 2 +- tests/fail/intrinsics/copy_overlapping.stderr | 2 +- tests/fail/intrinsics/copy_unaligned.stderr | 2 +- tests/fail/intrinsics/ctlz_nonzero.stderr | 2 +- tests/fail/intrinsics/cttz_nonzero.stderr | 2 +- tests/fail/intrinsics/div-by-zero.stderr | 2 +- tests/fail/intrinsics/exact_div1.stderr | 2 +- tests/fail/intrinsics/exact_div2.stderr | 2 +- tests/fail/intrinsics/exact_div3.stderr | 2 +- tests/fail/intrinsics/exact_div4.stderr | 2 +- .../intrinsics/float_to_int_32_inf1.stderr | 2 +- .../intrinsics/float_to_int_32_infneg1.stderr | 2 +- .../intrinsics/float_to_int_32_nan.stderr | 2 +- .../intrinsics/float_to_int_32_nanneg.stderr | 2 +- .../intrinsics/float_to_int_32_neg.stderr | 2 +- .../float_to_int_32_too_big1.stderr | 2 +- .../float_to_int_32_too_big2.stderr | 2 +- .../float_to_int_32_too_small1.stderr | 2 +- .../intrinsics/float_to_int_64_inf1.stderr | 2 +- .../intrinsics/float_to_int_64_infneg1.stderr | 2 +- .../intrinsics/float_to_int_64_infneg2.stderr | 2 +- .../intrinsics/float_to_int_64_nan.stderr | 2 +- .../intrinsics/float_to_int_64_neg.stderr | 2 +- .../float_to_int_64_too_big1.stderr | 2 +- .../float_to_int_64_too_big2.stderr | 2 +- .../float_to_int_64_too_big3.stderr | 2 +- .../float_to_int_64_too_big4.stderr | 2 +- .../float_to_int_64_too_big5.stderr | 2 +- .../float_to_int_64_too_big6.stderr | 2 +- .../float_to_int_64_too_big7.stderr | 2 +- .../float_to_int_64_too_small1.stderr | 2 +- .../float_to_int_64_too_small2.stderr | 2 +- .../float_to_int_64_too_small3.stderr | 2 +- .../intrinsics/out_of_bounds_ptr_1.stderr | 2 +- .../intrinsics/out_of_bounds_ptr_2.stderr | 2 +- .../intrinsics/out_of_bounds_ptr_3.stderr | 2 +- .../overflowing-unchecked-rsh.stderr | 2 +- .../intrinsics/ptr_offset_0_plus_0.stderr | 2 +- .../intrinsics/ptr_offset_from_oob.stderr | 2 +- .../intrinsics/ptr_offset_int_plus_int.stderr | 2 +- .../intrinsics/ptr_offset_int_plus_ptr.stderr | 2 +- .../intrinsics/ptr_offset_overflow.stderr | 2 +- .../intrinsics/ptr_offset_ptr_plus_0.stderr | 2 +- tests/fail/intrinsics/rem-by-zero.stderr | 2 +- tests/fail/intrinsics/simd-div-by-zero.stderr | 2 +- .../fail/intrinsics/simd-div-overflow.stderr | 2 +- .../fail/intrinsics/simd-float-to-int.stderr | 2 +- tests/fail/intrinsics/simd-gather.stderr | 2 +- .../simd-reduce-invalid-bool.stderr | 2 +- tests/fail/intrinsics/simd-rem-by-zero.stderr | 2 +- tests/fail/intrinsics/simd-scatter.stderr | 2 +- .../simd-select-bitmask-invalid.stderr | 2 +- .../simd-select-invalid-bool.stderr | 2 +- tests/fail/intrinsics/simd-shl-too-far.stderr | 2 +- tests/fail/intrinsics/simd-shr-too-far.stderr | 2 +- tests/fail/intrinsics/unchecked_add1.stderr | 2 +- tests/fail/intrinsics/unchecked_add2.stderr | 2 +- tests/fail/intrinsics/unchecked_div1.stderr | 2 +- tests/fail/intrinsics/unchecked_mul1.stderr | 2 +- tests/fail/intrinsics/unchecked_mul2.stderr | 2 +- tests/fail/intrinsics/unchecked_sub1.stderr | 2 +- tests/fail/intrinsics/unchecked_sub2.stderr | 2 +- tests/fail/intrinsics/write_bytes_null.stderr | 2 +- .../intrinsics/write_bytes_overflow.stderr | 2 +- tests/fail/invalid_bool.stderr | 2 +- tests/fail/invalid_char.stderr | 2 +- tests/fail/invalid_enum_tag.stderr | 2 +- tests/fail/invalid_int.stderr | 2 +- tests/fail/issue-miri-1112.stderr | 2 +- tests/fail/modifying_constants.stderr | 2 +- tests/fail/never_say_never.stderr | 2 +- tests/fail/never_transmute_humans.stderr | 2 +- tests/fail/never_transmute_void.stderr | 2 +- tests/fail/panic/bad_miri_start_panic.stderr | 2 +- tests/fail/panic/bad_unwind.stderr | 2 +- tests/fail/panic/unwind_panic_abort.stderr | 2 +- tests/fail/pointer_partial_overwrite.stderr | 2 +- .../provenance/provenance_transmute.stderr | 2 +- .../fail/provenance/ptr_int_unexposed.stderr | 2 +- tests/fail/provenance/ptr_invalid.stderr | 2 +- .../fail/provenance/ptr_invalid_offset.stderr | 2 +- .../provenance/strict_provenance_cast.stderr | 2 +- tests/fail/rc_as_ptr.stderr | 2 +- tests/fail/reading_half_a_pointer.stderr | 2 +- tests/fail/shim_arg_size.32bit.stderr | 2 +- tests/fail/shim_arg_size.64bit.stderr | 2 +- tests/fail/should-pass/cpp20_rwc_syncs.stderr | 2 +- .../alias_through_mutation.stderr | 1 + .../fail/stacked_borrows/aliasing_mut1.stderr | 1 + .../fail/stacked_borrows/aliasing_mut2.stderr | 1 + .../fail/stacked_borrows/aliasing_mut3.stderr | 1 + .../fail/stacked_borrows/aliasing_mut4.stderr | 1 + .../box_exclusive_violation1.stderr | 1 + .../stacked_borrows/buggy_as_mut_slice.stderr | 1 + .../stacked_borrows/buggy_split_at_mut.stderr | 1 + .../deallocate_against_barrier1.stderr | 2 +- .../deallocate_against_barrier2.stderr | 2 +- .../stacked_borrows/exposed_only_ro.stderr | 2 +- .../fail/stacked_borrows/illegal_read1.stderr | 1 + .../fail/stacked_borrows/illegal_read2.stderr | 1 + .../fail/stacked_borrows/illegal_read3.stderr | 1 + .../fail/stacked_borrows/illegal_read4.stderr | 1 + .../fail/stacked_borrows/illegal_read5.stderr | 1 + .../fail/stacked_borrows/illegal_read6.stderr | 1 + .../fail/stacked_borrows/illegal_read7.stderr | 1 + .../fail/stacked_borrows/illegal_read8.stderr | 1 + .../illegal_read_despite_exposed1.stderr | 2 +- .../illegal_read_despite_exposed2.stderr | 2 +- .../stacked_borrows/illegal_write1.stderr | 1 + .../stacked_borrows/illegal_write2.stderr | 1 + .../stacked_borrows/illegal_write3.stderr | 1 + .../stacked_borrows/illegal_write4.stderr | 1 + .../stacked_borrows/illegal_write5.stderr | 1 + .../stacked_borrows/illegal_write6.stderr | 1 + .../illegal_write_despite_exposed1.stderr | 2 +- .../fail/stacked_borrows/interior_mut1.stderr | 1 + .../fail/stacked_borrows/interior_mut2.stderr | 1 + .../invalidate_against_barrier1.stderr | 1 + .../invalidate_against_barrier2.stderr | 1 + .../stacked_borrows/issue-miri-1050-1.stderr | 2 +- .../stacked_borrows/issue-miri-1050-2.stderr | 2 +- .../stacked_borrows/load_invalid_mut.stderr | 1 + .../stacked_borrows/load_invalid_shr.stderr | 1 + .../mut_exclusive_violation1.stderr | 1 + .../mut_exclusive_violation2.stderr | 1 + .../stacked_borrows/newtype_retagging.stderr | 1 + .../stacked_borrows/outdated_local.stderr | 1 + .../stacked_borrows/pass_invalid_mut.stderr | 1 + .../stacked_borrows/pass_invalid_shr.stderr | 1 + .../stacked_borrows/pointer_smuggling.stderr | 1 + .../fail/stacked_borrows/raw_tracking.stderr | 1 + .../stacked_borrows/return_invalid_mut.stderr | 1 + .../return_invalid_mut_option.stderr | 1 + .../return_invalid_mut_tuple.stderr | 1 + .../stacked_borrows/return_invalid_shr.stderr | 1 + .../return_invalid_shr_option.stderr | 1 + .../return_invalid_shr_tuple.stderr | 1 + .../shared_rw_borrows_are_weak1.stderr | 1 + .../shared_rw_borrows_are_weak2.stderr | 1 + .../shr_frozen_violation1.stderr | 1 + .../static_memory_modification.stderr | 2 +- .../transmute-is-no-escape.stderr | 1 + .../stacked_borrows/unescaped_local.stderr | 2 +- .../stacked_borrows/unescaped_static.stderr | 1 + tests/fail/stacked_borrows/vtable.stderr | 2 +- tests/fail/stacked_borrows/zst_slice.stderr | 1 + tests/fail/static_memory_modification1.stderr | 2 +- tests/fail/static_memory_modification2.stderr | 2 +- tests/fail/static_memory_modification3.stderr | 2 +- .../libc_pthread_cond_double_destroy.stderr | 2 +- ...ibc_pthread_condattr_double_destroy.stderr | 2 +- .../libc_pthread_mutex_NULL_deadlock.stderr | 2 +- ...libc_pthread_mutex_default_deadlock.stderr | 2 +- .../libc_pthread_mutex_destroy_locked.stderr | 2 +- .../libc_pthread_mutex_double_destroy.stderr | 2 +- ...thread_mutex_normal_unlock_unlocked.stderr | 2 +- .../libc_pthread_mutex_wrong_owner.stderr | 2 +- ...bc_pthread_mutexattr_double_destroy.stderr | 2 +- ..._pthread_rwlock_destroy_read_locked.stderr | 2 +- ...pthread_rwlock_destroy_write_locked.stderr | 2 +- .../libc_pthread_rwlock_double_destroy.stderr | 2 +- ...ibc_pthread_rwlock_read_wrong_owner.stderr | 2 +- ...libc_pthread_rwlock_unlock_unlocked.stderr | 2 +- ...bc_pthread_rwlock_write_wrong_owner.stderr | 2 +- tests/fail/transmute-pair-uninit.stderr | 2 +- tests/fail/transmute_fat1.stderr | 2 +- .../fail/unaligned_pointers/alignment.stderr | 2 +- .../atomic_unaligned.stderr | 2 +- .../unaligned_pointers/dyn_alignment.stderr | 2 +- .../intptrcast_alignment_check.stderr | 2 +- .../reference_to_packed.stderr | 2 +- .../unaligned_pointers/unaligned_ptr1.stderr | 2 +- .../unaligned_pointers/unaligned_ptr2.stderr | 2 +- .../unaligned_pointers/unaligned_ptr3.stderr | 2 +- .../unaligned_pointers/unaligned_ptr4.stderr | 2 +- .../unaligned_ptr_addr_of.stderr | 2 +- .../unaligned_ptr_zst.stderr | 2 +- tests/fail/uninit_buffer.stderr | 2 +- tests/fail/uninit_byte_read.stderr | 2 +- tests/fail/uninit_raw_ptr.stderr | 2 +- tests/fail/unreachable.stderr | 2 +- .../fail/unsupported_foreign_function.stderr | 2 +- tests/fail/unsupported_signal.stderr | 2 +- tests/fail/validity/cast_fn_ptr1.stderr | 2 +- tests/fail/validity/cast_fn_ptr2.stderr | 2 +- tests/fail/validity/dangling_ref1.stderr | 2 +- tests/fail/validity/dangling_ref2.stderr | 2 +- tests/fail/validity/dangling_ref3.stderr | 2 +- tests/fail/validity/invalid_bool.stderr | 2 +- .../fail/validity/invalid_bool_uninit.stderr | 2 +- tests/fail/validity/invalid_char.stderr | 2 +- .../fail/validity/invalid_char_uninit.stderr | 2 +- tests/fail/validity/invalid_enum_tag.stderr | 2 +- ...invalid_enum_tag_256variants_uninit.stderr | 2 +- tests/fail/validity/invalid_fnptr_null.stderr | 2 +- .../fail/validity/invalid_fnptr_uninit.stderr | 2 +- tests/fail/validity/invalid_wide_raw.stderr | 2 +- tests/fail/validity/nonzero.stderr | 2 +- .../ptr_integer_array_transmute.stderr | 2 +- .../fail/validity/ref_to_uninhabited1.stderr | 2 +- .../fail/validity/ref_to_uninhabited2.stderr | 2 +- tests/fail/validity/too-big-slice.stderr | 2 +- tests/fail/validity/too-big-unsized.stderr | 2 +- .../validity/transmute_through_ptr.stderr | 2 +- tests/fail/validity/uninit_float.stderr | 2 +- tests/fail/validity/uninit_integer.stderr | 2 +- .../validity/uninit_integer_signed.stderr | 2 +- .../fail/weak_memory/racing_mixed_size.stderr | 2 +- .../weak_memory/racing_mixed_size_read.stderr | 2 +- tests/fail/zst1.stderr | 2 +- tests/fail/zst2.stderr | 2 +- tests/fail/zst3.stderr | 2 +- tests/pass/box.stderr | 2 +- tests/pass/extern_types.stderr | 2 +- 325 files changed, 354 insertions(+), 285 deletions(-) diff --git a/src/diagnostics.rs b/src/diagnostics.rs index 1ffcdc799edf0..28d4733718ef9 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -67,7 +67,7 @@ impl MachineStopType for TerminationInfo {} /// Miri specific diagnostics pub enum NonHaltingDiagnostic { - CreatedPointerTag(NonZeroU64), + CreatedPointerTag(NonZeroU64, Option<(AllocId, AllocRange)>), /// This `Item` was popped from the borrow stack, either due to an access with the given tag or /// a deallocation when the second argument is `None`. PoppedPointerTag(Item, Option<(SbTagExtra, AccessKind)>), @@ -318,7 +318,7 @@ fn report_msg<'mir, 'tcx>( diag_level: DiagLevel, title: &str, span_msg: Vec, - mut helps: Vec<(Option, String)>, + helps: Vec<(Option, String)>, stacktrace: &[FrameInfo<'tcx>], ) { let span = stacktrace.first().map_or(DUMMY_SP, |fi| fi.span); @@ -344,8 +344,6 @@ fn report_msg<'mir, 'tcx>( // Show help messages. if !helps.is_empty() { - // Add visual separator before backtrace. - helps.last_mut().unwrap().1.push('\n'); for (span_data, help) in helps { if let Some(span_data) = span_data { err.span_help(span_data.span(), &help); @@ -353,6 +351,8 @@ fn report_msg<'mir, 'tcx>( err.help(&help); } } + // Add visual separator before backtrace. + err.note("backtrace:"); } // Add backtrace for (idx, frame_info) in stacktrace.iter().enumerate() { @@ -448,7 +448,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx for e in diagnostics.drain(..) { use NonHaltingDiagnostic::*; let msg = match e { - CreatedPointerTag(tag) => format!("created tag {:?}", tag), + CreatedPointerTag(tag, None) => format!("created tag {tag:?}"), + CreatedPointerTag(tag, Some((alloc_id, range))) => + format!("created tag {tag:?} at {alloc_id}{}", HexRange(range)), PoppedPointerTag(item, tag) => match tag { None => diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 2cf5eb70c171f..cc3d099e1c1c1 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -222,11 +222,9 @@ impl GlobalStateInner { } } + /// Generates a new pointer tag. Remember to also check track_pointer_tags and log its creation! fn new_ptr(&mut self) -> SbTag { let id = self.next_ptr_tag; - if self.tracked_pointer_tags.contains(&id) { - register_diagnostic(NonHaltingDiagnostic::CreatedPointerTag(id.0)); - } self.next_ptr_tag = SbTag(NonZeroU64::new(id.0.get() + 1).unwrap()); id } @@ -253,6 +251,9 @@ impl GlobalStateInner { pub fn base_ptr_tag(&mut self, id: AllocId) -> SbTag { self.base_ptr_tags.get(&id).copied().unwrap_or_else(|| { let tag = self.new_ptr(); + if self.tracked_pointer_tags.contains(&tag) { + register_diagnostic(NonHaltingDiagnostic::CreatedPointerTag(tag.0, None)); + } trace!("New allocation {:?} has base tag {:?}", id, tag); self.base_ptr_tags.try_insert(id, tag).unwrap(); tag @@ -802,16 +803,30 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); let current_span = &mut this.machine.current_span(); + // It is crucial that this gets called on all code paths, to ensure we track tag creation. let log_creation = |this: &MiriEvalContext<'mir, 'tcx>, current_span: &mut CurrentSpan<'_, 'mir, 'tcx>, - alloc_id, - base_offset, - orig_tag| + loc: Option<(AllocId, Size, SbTagExtra)>| // alloc_id, base_offset, orig_tag -> InterpResult<'tcx> { + let global = this.machine.stacked_borrows.as_ref().unwrap().borrow(); + if global.tracked_pointer_tags.contains(&new_tag) { + register_diagnostic(NonHaltingDiagnostic::CreatedPointerTag( + new_tag.0, + loc.map(|(alloc_id, base_offset, _)| (alloc_id, alloc_range(base_offset, size))), + )); + } + drop(global); // don't hold that reference any longer than we have to + + let Some((alloc_id, base_offset, orig_tag)) = loc else { + return Ok(()) + }; + + // The SB history tracking needs a parent tag, so skip if we come from a wildcard. let SbTagExtra::Concrete(orig_tag) = orig_tag else { // FIXME: should we log this? return Ok(()) }; + let extra = this.get_alloc_extra(alloc_id)?; let mut stacked_borrows = extra .stacked_borrows @@ -846,14 +861,15 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Dangling slices are a common case here; it's valid to get their length but with raw // pointer tagging for example all calls to get_unchecked on them are invalid. if let Ok((alloc_id, base_offset, orig_tag)) = this.ptr_try_get_alloc_id(place.ptr) { - log_creation(this, current_span, alloc_id, base_offset, orig_tag)?; + log_creation(this, current_span, Some((alloc_id, base_offset, orig_tag)))?; return Ok(Some(alloc_id)); } // This pointer doesn't come with an AllocId. :shrug: + log_creation(this, current_span, None)?; return Ok(None); } let (alloc_id, base_offset, orig_tag) = this.ptr_get_alloc_id(place.ptr)?; - log_creation(this, current_span, alloc_id, base_offset, orig_tag)?; + log_creation(this, current_span, Some((alloc_id, base_offset, orig_tag)))?; // Ensure we bail out if the pointer goes out-of-bounds (see miri#1050). let (alloc_size, _) = this.get_live_alloc_size_and_align(alloc_id)?; diff --git a/tests/fail/alloc/deallocate-bad-alignment.stderr b/tests/fail/alloc/deallocate-bad-alignment.stderr index 52c0310cabaa8..e46533ad70d3e 100644 --- a/tests/fail/alloc/deallocate-bad-alignment.stderr +++ b/tests/fail/alloc/deallocate-bad-alignment.stderr @@ -6,7 +6,7 @@ LL | unsafe { __rust_dealloc(ptr, layout.size(), layout.align()) } | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `std::alloc::dealloc` at RUSTLIB/alloc/src/alloc.rs:LL:CC note: inside `main` at $DIR/deallocate-bad-alignment.rs:LL:CC --> $DIR/deallocate-bad-alignment.rs:LL:CC diff --git a/tests/fail/alloc/deallocate-bad-size.stderr b/tests/fail/alloc/deallocate-bad-size.stderr index fe0a5130eb544..d3ca2a4544bf1 100644 --- a/tests/fail/alloc/deallocate-bad-size.stderr +++ b/tests/fail/alloc/deallocate-bad-size.stderr @@ -6,7 +6,7 @@ LL | unsafe { __rust_dealloc(ptr, layout.size(), layout.align()) } | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `std::alloc::dealloc` at RUSTLIB/alloc/src/alloc.rs:LL:CC note: inside `main` at $DIR/deallocate-bad-size.rs:LL:CC --> $DIR/deallocate-bad-size.rs:LL:CC diff --git a/tests/fail/alloc/deallocate-twice.stderr b/tests/fail/alloc/deallocate-twice.stderr index cca20be6e661a..1fadb277a0e40 100644 --- a/tests/fail/alloc/deallocate-twice.stderr +++ b/tests/fail/alloc/deallocate-twice.stderr @@ -6,7 +6,7 @@ LL | unsafe { __rust_dealloc(ptr, layout.size(), layout.align()) } | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `std::alloc::dealloc` at RUSTLIB/alloc/src/alloc.rs:LL:CC note: inside `main` at $DIR/deallocate-twice.rs:LL:CC --> $DIR/deallocate-twice.rs:LL:CC diff --git a/tests/fail/alloc/global_system_mixup.stderr b/tests/fail/alloc/global_system_mixup.stderr index f197bc7917850..60b91155f5e53 100644 --- a/tests/fail/alloc/global_system_mixup.stderr +++ b/tests/fail/alloc/global_system_mixup.stderr @@ -6,7 +6,7 @@ LL | FREE(); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `std::sys::PLATFORM::alloc::::dealloc` at RUSTLIB/std/src/sys/PLATFORM/alloc.rs:LL:CC = note: inside `::deallocate` at RUSTLIB/std/src/alloc.rs:LL:CC note: inside `main` at $DIR/global_system_mixup.rs:LL:CC diff --git a/tests/fail/alloc/no_global_allocator.stderr b/tests/fail/alloc/no_global_allocator.stderr index 2a9840ee83c4c..5c11df9539c1c 100644 --- a/tests/fail/alloc/no_global_allocator.stderr +++ b/tests/fail/alloc/no_global_allocator.stderr @@ -5,7 +5,7 @@ LL | __rust_alloc(1, 1); | ^^^^^^^^^^^^^^^^^^ can't call foreign function: __rust_alloc | = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support - + = note: backtrace: = note: inside `start` at $DIR/no_global_allocator.rs:LL:CC error: aborting due to previous error diff --git a/tests/fail/alloc/reallocate-bad-size.stderr b/tests/fail/alloc/reallocate-bad-size.stderr index 04dce05e78f54..abe47e29ed324 100644 --- a/tests/fail/alloc/reallocate-bad-size.stderr +++ b/tests/fail/alloc/reallocate-bad-size.stderr @@ -6,7 +6,7 @@ LL | unsafe { __rust_realloc(ptr, layout.size(), layout.align(), new_size) } | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `std::alloc::realloc` at RUSTLIB/alloc/src/alloc.rs:LL:CC note: inside `main` at $DIR/reallocate-bad-size.rs:LL:CC --> $DIR/reallocate-bad-size.rs:LL:CC diff --git a/tests/fail/alloc/reallocate-change-alloc.stderr b/tests/fail/alloc/reallocate-change-alloc.stderr index d400931379b06..c22e44b754c9a 100644 --- a/tests/fail/alloc/reallocate-change-alloc.stderr +++ b/tests/fail/alloc/reallocate-change-alloc.stderr @@ -6,7 +6,7 @@ LL | let _z = *x; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/reallocate-change-alloc.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/alloc/reallocate-dangling.stderr b/tests/fail/alloc/reallocate-dangling.stderr index 84e7b934202ae..5eeaab8700c8d 100644 --- a/tests/fail/alloc/reallocate-dangling.stderr +++ b/tests/fail/alloc/reallocate-dangling.stderr @@ -6,7 +6,7 @@ LL | unsafe { __rust_realloc(ptr, layout.size(), layout.align(), new_size) } | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `std::alloc::realloc` at RUSTLIB/alloc/src/alloc.rs:LL:CC note: inside `main` at $DIR/reallocate-dangling.rs:LL:CC --> $DIR/reallocate-dangling.rs:LL:CC diff --git a/tests/fail/alloc/stack_free.stderr b/tests/fail/alloc/stack_free.stderr index 073510a6080da..6ce522df58d6e 100644 --- a/tests/fail/alloc/stack_free.stderr +++ b/tests/fail/alloc/stack_free.stderr @@ -6,7 +6,7 @@ LL | unsafe { __rust_dealloc(ptr, layout.size(), layout.align()) } | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `std::alloc::dealloc` at RUSTLIB/alloc/src/alloc.rs:LL:CC = note: inside `::deallocate` at RUSTLIB/alloc/src/alloc.rs:LL:CC = note: inside `alloc::alloc::box_free::` at RUSTLIB/alloc/src/alloc.rs:LL:CC diff --git a/tests/fail/backtrace/bad-backtrace-decl.stderr b/tests/fail/backtrace/bad-backtrace-decl.stderr index 007ef96f72a95..3cb4a8e8a4589 100644 --- a/tests/fail/backtrace/bad-backtrace-decl.stderr +++ b/tests/fail/backtrace/bad-backtrace-decl.stderr @@ -6,7 +6,7 @@ LL | ... miri_resolve_frame(*frame, 0); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/bad-backtrace-decl.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/backtrace/bad-backtrace-flags.stderr b/tests/fail/backtrace/bad-backtrace-flags.stderr index 6d62ffc00e51c..f186fb1e57179 100644 --- a/tests/fail/backtrace/bad-backtrace-flags.stderr +++ b/tests/fail/backtrace/bad-backtrace-flags.stderr @@ -5,7 +5,7 @@ LL | miri_get_backtrace(2, std::ptr::null_mut()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unknown `miri_get_backtrace` flags 2 | = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support - + = note: backtrace: = note: inside `main` at $DIR/bad-backtrace-flags.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/backtrace/bad-backtrace-ptr.stderr b/tests/fail/backtrace/bad-backtrace-ptr.stderr index 6911db9de02fd..969523d8b3fec 100644 --- a/tests/fail/backtrace/bad-backtrace-ptr.stderr +++ b/tests/fail/backtrace/bad-backtrace-ptr.stderr @@ -6,7 +6,7 @@ LL | miri_resolve_frame(std::ptr::null_mut(), 0); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/bad-backtrace-ptr.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/backtrace/bad-backtrace-resolve-flags.stderr b/tests/fail/backtrace/bad-backtrace-resolve-flags.stderr index 49495651dfec4..cf80488de22dd 100644 --- a/tests/fail/backtrace/bad-backtrace-resolve-flags.stderr +++ b/tests/fail/backtrace/bad-backtrace-resolve-flags.stderr @@ -5,7 +5,7 @@ LL | miri_resolve_frame(buf[0], 2); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unknown `miri_resolve_frame` flags 2 | = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support - + = note: backtrace: = note: inside `main` at $DIR/bad-backtrace-resolve-flags.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/backtrace/bad-backtrace-resolve-names-flags.stderr b/tests/fail/backtrace/bad-backtrace-resolve-names-flags.stderr index aa470cb9de054..c7e0d41009ad0 100644 --- a/tests/fail/backtrace/bad-backtrace-resolve-names-flags.stderr +++ b/tests/fail/backtrace/bad-backtrace-resolve-names-flags.stderr @@ -5,7 +5,7 @@ LL | ... miri_resolve_frame_names(buf[0], 2, std::ptr::null_mut(), std::ptr::n | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unknown `miri_resolve_frame_names` flags 2 | = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support - + = note: backtrace: = note: inside `main` at $DIR/bad-backtrace-resolve-names-flags.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/backtrace/bad-backtrace-size-flags.stderr b/tests/fail/backtrace/bad-backtrace-size-flags.stderr index 09f22b74b9c34..0cfe5d7173ce1 100644 --- a/tests/fail/backtrace/bad-backtrace-size-flags.stderr +++ b/tests/fail/backtrace/bad-backtrace-size-flags.stderr @@ -5,7 +5,7 @@ LL | miri_backtrace_size(2); | ^^^^^^^^^^^^^^^^^^^^^^ unknown `miri_backtrace_size` flags 2 | = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support - + = note: backtrace: = note: inside `main` at $DIR/bad-backtrace-size-flags.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/box-cell-alias.stderr b/tests/fail/box-cell-alias.stderr index 446aafe640128..c7fd1c6415e03 100644 --- a/tests/fail/box-cell-alias.stderr +++ b/tests/fail/box-cell-alias.stderr @@ -19,6 +19,7 @@ help: was later invalidated at offsets [0x0..0x1] | LL | let res = helper(val, ptr); | ^^^ + = note: backtrace: = note: inside `helper` at $DIR/box-cell-alias.rs:LL:CC note: inside `main` at $DIR/box-cell-alias.rs:LL:CC --> $DIR/box-cell-alias.rs:LL:CC diff --git a/tests/fail/branchless-select-i128-pointer.stderr b/tests/fail/branchless-select-i128-pointer.stderr index 5cb05f33ddea3..15befcd126553 100644 --- a/tests/fail/branchless-select-i128-pointer.stderr +++ b/tests/fail/branchless-select-i128-pointer.stderr @@ -10,7 +10,7 @@ LL | | ) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/branchless-select-i128-pointer.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/concurrency/libc_pthread_join_detached.stderr b/tests/fail/concurrency/libc_pthread_join_detached.stderr index 44d0f727a395e..be9781ff46ea1 100644 --- a/tests/fail/concurrency/libc_pthread_join_detached.stderr +++ b/tests/fail/concurrency/libc_pthread_join_detached.stderr @@ -6,7 +6,7 @@ LL | ... assert_eq!(libc::pthread_join(native, ptr::null_mut()), 0); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/libc_pthread_join_detached.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/concurrency/libc_pthread_join_joined.stderr b/tests/fail/concurrency/libc_pthread_join_joined.stderr index b67974c58eaef..5ac35ffe512e3 100644 --- a/tests/fail/concurrency/libc_pthread_join_joined.stderr +++ b/tests/fail/concurrency/libc_pthread_join_joined.stderr @@ -6,7 +6,7 @@ LL | ... assert_eq!(libc::pthread_join(native, ptr::null_mut()), 0); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/libc_pthread_join_joined.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/concurrency/libc_pthread_join_main.stderr b/tests/fail/concurrency/libc_pthread_join_main.stderr index 3e69df508359a..fe136549ce511 100644 --- a/tests/fail/concurrency/libc_pthread_join_main.stderr +++ b/tests/fail/concurrency/libc_pthread_join_main.stderr @@ -6,7 +6,7 @@ LL | ... assert_eq!(libc::pthread_join(thread_id, ptr::null_mut()), 0); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside closure at $DIR/libc_pthread_join_main.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/concurrency/libc_pthread_join_multiple.stderr b/tests/fail/concurrency/libc_pthread_join_multiple.stderr index 997bca9fe4223..9b91e5a3d0ed1 100644 --- a/tests/fail/concurrency/libc_pthread_join_multiple.stderr +++ b/tests/fail/concurrency/libc_pthread_join_multiple.stderr @@ -6,7 +6,7 @@ LL | ... assert_eq!(libc::pthread_join(native_copy, ptr::null_mut()), 0); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside closure at $DIR/libc_pthread_join_multiple.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/concurrency/libc_pthread_join_self.stderr b/tests/fail/concurrency/libc_pthread_join_self.stderr index 8d2acb817f938..38e758e46c125 100644 --- a/tests/fail/concurrency/libc_pthread_join_self.stderr +++ b/tests/fail/concurrency/libc_pthread_join_self.stderr @@ -6,7 +6,7 @@ LL | assert_eq!(libc::pthread_join(native, ptr::null_mut()), 0); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside closure at $DIR/libc_pthread_join_self.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/concurrency/thread-spawn.stderr b/tests/fail/concurrency/thread-spawn.stderr index eb6c6c9b0bb8e..2e4b3a045e691 100644 --- a/tests/fail/concurrency/thread-spawn.stderr +++ b/tests/fail/concurrency/thread-spawn.stderr @@ -12,7 +12,7 @@ LL | | ); | |_________^ can't create threads on Windows | = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support - + = note: backtrace: = note: inside `std::sys::PLATFORM::thread::Thread::new` at RUSTLIB/std/src/sys/PLATFORM/thread.rs:LL:CC = note: inside `std::thread::Builder::spawn_unchecked_::<[closure@$DIR/thread-spawn.rs:LL:CC], ()>` at RUSTLIB/std/src/thread/mod.rs:LL:CC = note: inside `std::thread::Builder::spawn_unchecked::<[closure@$DIR/thread-spawn.rs:LL:CC], ()>` at RUSTLIB/std/src/thread/mod.rs:LL:CC diff --git a/tests/fail/concurrency/thread_local_static_dealloc.stderr b/tests/fail/concurrency/thread_local_static_dealloc.stderr index d54c569de36e6..58e7cf07348f7 100644 --- a/tests/fail/concurrency/thread_local_static_dealloc.stderr +++ b/tests/fail/concurrency/thread_local_static_dealloc.stderr @@ -6,7 +6,7 @@ LL | let _val = *dangling_ptr.0; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/thread_local_static_dealloc.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/concurrency/too_few_args.stderr b/tests/fail/concurrency/too_few_args.stderr index 9d96b718bc305..093a307685019 100644 --- a/tests/fail/concurrency/too_few_args.stderr +++ b/tests/fail/concurrency/too_few_args.stderr @@ -6,7 +6,7 @@ LL | panic!() | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `thread_start` at RUSTLIB/std/src/panic.rs:LL:CC = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/fail/concurrency/too_many_args.stderr b/tests/fail/concurrency/too_many_args.stderr index 7132b8c453afa..87e22ec1dcf65 100644 --- a/tests/fail/concurrency/too_many_args.stderr +++ b/tests/fail/concurrency/too_many_args.stderr @@ -6,7 +6,7 @@ LL | panic!() | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `thread_start` at RUSTLIB/std/src/panic.rs:LL:CC = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/fail/concurrency/unwind_top_of_stack.stderr b/tests/fail/concurrency/unwind_top_of_stack.stderr index f72f01a9d6e97..efd19ef4c51ad 100644 --- a/tests/fail/concurrency/unwind_top_of_stack.stderr +++ b/tests/fail/concurrency/unwind_top_of_stack.stderr @@ -11,7 +11,7 @@ LL | | } | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `thread_start` at $DIR/unwind_top_of_stack.rs:LL:CC error: aborting due to previous error diff --git a/tests/fail/dangling_pointers/dangling_pointer_addr_of.stderr b/tests/fail/dangling_pointers/dangling_pointer_addr_of.stderr index 1e793f549acd3..a6a2ca1507b50 100644 --- a/tests/fail/dangling_pointers/dangling_pointer_addr_of.stderr +++ b/tests/fail/dangling_pointers/dangling_pointer_addr_of.stderr @@ -6,7 +6,7 @@ LL | let x = unsafe { ptr::addr_of!(*p) }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at RUSTLIB/core/src/ptr/mod.rs:LL:CC = note: this error originates in the macro `ptr::addr_of` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/fail/dangling_pointers/dangling_pointer_deref.stderr b/tests/fail/dangling_pointers/dangling_pointer_deref.stderr index 69e7af74857a2..cca3d0278aec3 100644 --- a/tests/fail/dangling_pointers/dangling_pointer_deref.stderr +++ b/tests/fail/dangling_pointers/dangling_pointer_deref.stderr @@ -6,7 +6,7 @@ LL | let x = unsafe { *p }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/dangling_pointer_deref.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/dangling_pointers/dangling_zst_deref.stderr b/tests/fail/dangling_pointers/dangling_zst_deref.stderr index 658635433c7a8..66626a925cc68 100644 --- a/tests/fail/dangling_pointers/dangling_zst_deref.stderr +++ b/tests/fail/dangling_pointers/dangling_zst_deref.stderr @@ -6,7 +6,7 @@ LL | let _x = unsafe { *p }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/dangling_zst_deref.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/dangling_pointers/deref-invalid-ptr.stderr b/tests/fail/dangling_pointers/deref-invalid-ptr.stderr index f4361d9fefa95..0dc73a6e3b133 100644 --- a/tests/fail/dangling_pointers/deref-invalid-ptr.stderr +++ b/tests/fail/dangling_pointers/deref-invalid-ptr.stderr @@ -6,7 +6,7 @@ LL | let _y = unsafe { &*x as *const u32 }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/deref-invalid-ptr.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/dangling_pointers/deref-partially-dangling.stderr b/tests/fail/dangling_pointers/deref-partially-dangling.stderr index dc51eae71a3a3..e37b6885922bd 100644 --- a/tests/fail/dangling_pointers/deref-partially-dangling.stderr +++ b/tests/fail/dangling_pointers/deref-partially-dangling.stderr @@ -6,7 +6,7 @@ LL | let val = unsafe { (*xptr).1 }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/deref-partially-dangling.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/dangling_pointers/dyn_size.stderr b/tests/fail/dangling_pointers/dyn_size.stderr index 6048a3b4434d6..0abcee595e159 100644 --- a/tests/fail/dangling_pointers/dyn_size.stderr +++ b/tests/fail/dangling_pointers/dyn_size.stderr @@ -6,7 +6,7 @@ LL | let _ptr = unsafe { &*ptr }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/dyn_size.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/dangling_pointers/maybe_null_pointer_deref_zst.stderr b/tests/fail/dangling_pointers/maybe_null_pointer_deref_zst.stderr index b4da315a55427..222f2a6281962 100644 --- a/tests/fail/dangling_pointers/maybe_null_pointer_deref_zst.stderr +++ b/tests/fail/dangling_pointers/maybe_null_pointer_deref_zst.stderr @@ -6,7 +6,7 @@ LL | let _x: () = unsafe { *ptr }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/maybe_null_pointer_deref_zst.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/dangling_pointers/maybe_null_pointer_write_zst.stderr b/tests/fail/dangling_pointers/maybe_null_pointer_write_zst.stderr index 41e54735ca925..12228bc1d7177 100644 --- a/tests/fail/dangling_pointers/maybe_null_pointer_write_zst.stderr +++ b/tests/fail/dangling_pointers/maybe_null_pointer_write_zst.stderr @@ -6,7 +6,7 @@ LL | unsafe { *ptr = zst_val }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/maybe_null_pointer_write_zst.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/dangling_pointers/null_pointer_deref.stderr b/tests/fail/dangling_pointers/null_pointer_deref.stderr index 0930160023f1b..10f4c0f384167 100644 --- a/tests/fail/dangling_pointers/null_pointer_deref.stderr +++ b/tests/fail/dangling_pointers/null_pointer_deref.stderr @@ -6,7 +6,7 @@ LL | let x: i32 = unsafe { *std::ptr::null() }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/null_pointer_deref.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/dangling_pointers/null_pointer_deref_zst.stderr b/tests/fail/dangling_pointers/null_pointer_deref_zst.stderr index 25fea50b15af1..600b9b4254955 100644 --- a/tests/fail/dangling_pointers/null_pointer_deref_zst.stderr +++ b/tests/fail/dangling_pointers/null_pointer_deref_zst.stderr @@ -6,7 +6,7 @@ LL | let x: () = unsafe { *std::ptr::null() }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/null_pointer_deref_zst.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/dangling_pointers/null_pointer_write.stderr b/tests/fail/dangling_pointers/null_pointer_write.stderr index 5ac8cc7c20fdf..803191a7fcfb4 100644 --- a/tests/fail/dangling_pointers/null_pointer_write.stderr +++ b/tests/fail/dangling_pointers/null_pointer_write.stderr @@ -6,7 +6,7 @@ LL | unsafe { *std::ptr::null_mut() = 0i32 }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/null_pointer_write.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/dangling_pointers/null_pointer_write_zst.stderr b/tests/fail/dangling_pointers/null_pointer_write_zst.stderr index ee8afcfb7d904..2b4d26f8edaf8 100644 --- a/tests/fail/dangling_pointers/null_pointer_write_zst.stderr +++ b/tests/fail/dangling_pointers/null_pointer_write_zst.stderr @@ -6,7 +6,7 @@ LL | copy_nonoverlapping(&src as *const T, dst, 1); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `std::ptr::write::<[u8; 0]>` at RUSTLIB/core/src/ptr/mod.rs:LL:CC = note: inside `std::ptr::mut_ptr::::write` at RUSTLIB/core/src/ptr/mut_ptr.rs:LL:CC note: inside `main` at $DIR/null_pointer_write_zst.rs:LL:CC diff --git a/tests/fail/dangling_pointers/out_of_bounds_read1.stderr b/tests/fail/dangling_pointers/out_of_bounds_read1.stderr index 1982b07066b1c..2abc7a457b9a8 100644 --- a/tests/fail/dangling_pointers/out_of_bounds_read1.stderr +++ b/tests/fail/dangling_pointers/out_of_bounds_read1.stderr @@ -6,7 +6,7 @@ LL | let x = unsafe { *v.as_ptr().wrapping_offset(5) }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/out_of_bounds_read1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/dangling_pointers/out_of_bounds_read2.stderr b/tests/fail/dangling_pointers/out_of_bounds_read2.stderr index b70ce44c48a08..e0735dd1f926a 100644 --- a/tests/fail/dangling_pointers/out_of_bounds_read2.stderr +++ b/tests/fail/dangling_pointers/out_of_bounds_read2.stderr @@ -6,7 +6,7 @@ LL | let x = unsafe { *v.as_ptr().wrapping_offset(5) }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/out_of_bounds_read2.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/dangling_pointers/stack_temporary.stderr b/tests/fail/dangling_pointers/stack_temporary.stderr index f4f84765be54b..dd24e6dd675cf 100644 --- a/tests/fail/dangling_pointers/stack_temporary.stderr +++ b/tests/fail/dangling_pointers/stack_temporary.stderr @@ -6,7 +6,7 @@ LL | let val = *x; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/stack_temporary.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/dangling_pointers/storage_dead_dangling.stderr b/tests/fail/dangling_pointers/storage_dead_dangling.stderr index d6030643bfaa1..23b66325571f7 100644 --- a/tests/fail/dangling_pointers/storage_dead_dangling.stderr +++ b/tests/fail/dangling_pointers/storage_dead_dangling.stderr @@ -6,7 +6,7 @@ LL | unsafe { &mut *(LEAK as *mut i32) }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `evil` at $DIR/storage_dead_dangling.rs:LL:CC note: inside `main` at $DIR/storage_dead_dangling.rs:LL:CC --> $DIR/storage_dead_dangling.rs:LL:CC diff --git a/tests/fail/dangling_pointers/wild_pointer_deref.stderr b/tests/fail/dangling_pointers/wild_pointer_deref.stderr index b20f310da083b..67b28e25e1dde 100644 --- a/tests/fail/dangling_pointers/wild_pointer_deref.stderr +++ b/tests/fail/dangling_pointers/wild_pointer_deref.stderr @@ -6,7 +6,7 @@ LL | let x = unsafe { *p }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/wild_pointer_deref.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/data_race/alloc_read_race.stderr b/tests/fail/data_race/alloc_read_race.stderr index 2049e4f4a193a..b180c30bdf342 100644 --- a/tests/fail/data_race/alloc_read_race.stderr +++ b/tests/fail/data_race/alloc_read_race.stderr @@ -6,7 +6,7 @@ LL | *pointer.load(Ordering::Relaxed) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside closure at $DIR/alloc_read_race.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/data_race/alloc_write_race.stderr b/tests/fail/data_race/alloc_write_race.stderr index 82e3d92479d94..bae65b6262f4a 100644 --- a/tests/fail/data_race/alloc_write_race.stderr +++ b/tests/fail/data_race/alloc_write_race.stderr @@ -6,7 +6,7 @@ LL | *pointer.load(Ordering::Relaxed) = 2; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside closure at $DIR/alloc_write_race.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/data_race/atomic_read_na_write_race1.stderr b/tests/fail/data_race/atomic_read_na_write_race1.stderr index 4b5355e866e25..2a0ca9260782c 100644 --- a/tests/fail/data_race/atomic_read_na_write_race1.stderr +++ b/tests/fail/data_race/atomic_read_na_write_race1.stderr @@ -6,7 +6,7 @@ LL | intrinsics::atomic_load_seqcst(c.0 as *mut usize) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside closure at $DIR/atomic_read_na_write_race1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/data_race/atomic_read_na_write_race2.stderr b/tests/fail/data_race/atomic_read_na_write_race2.stderr index 3eb9f17bae760..48a9c85469080 100644 --- a/tests/fail/data_race/atomic_read_na_write_race2.stderr +++ b/tests/fail/data_race/atomic_read_na_write_race2.stderr @@ -6,7 +6,7 @@ LL | *atomic_ref.get_mut() = 32; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside closure at $DIR/atomic_read_na_write_race2.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/data_race/atomic_write_na_read_race1.stderr b/tests/fail/data_race/atomic_write_na_read_race1.stderr index 810fa54d41cee..b3e12168255a7 100644 --- a/tests/fail/data_race/atomic_write_na_read_race1.stderr +++ b/tests/fail/data_race/atomic_write_na_read_race1.stderr @@ -6,7 +6,7 @@ LL | *atomic_ref.get_mut() | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside closure at $DIR/atomic_write_na_read_race1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/data_race/atomic_write_na_read_race2.stderr b/tests/fail/data_race/atomic_write_na_read_race2.stderr index 77f69e2bc3400..69bf6c5f37425 100644 --- a/tests/fail/data_race/atomic_write_na_read_race2.stderr +++ b/tests/fail/data_race/atomic_write_na_read_race2.stderr @@ -6,7 +6,7 @@ LL | atomic_store(c.0 as *mut usize, 32); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside closure at $DIR/atomic_write_na_read_race2.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/data_race/atomic_write_na_write_race1.stderr b/tests/fail/data_race/atomic_write_na_write_race1.stderr index 8e70de5e4aff6..6abcf4fe3d12b 100644 --- a/tests/fail/data_race/atomic_write_na_write_race1.stderr +++ b/tests/fail/data_race/atomic_write_na_write_race1.stderr @@ -6,7 +6,7 @@ LL | atomic_store(c.0 as *mut usize, 64); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside closure at $DIR/atomic_write_na_write_race1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/data_race/atomic_write_na_write_race2.stderr b/tests/fail/data_race/atomic_write_na_write_race2.stderr index 310c2ed7df8a1..2de1c68588880 100644 --- a/tests/fail/data_race/atomic_write_na_write_race2.stderr +++ b/tests/fail/data_race/atomic_write_na_write_race2.stderr @@ -6,7 +6,7 @@ LL | *atomic_ref.get_mut() = 32; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside closure at $DIR/atomic_write_na_write_race2.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/data_race/dangling_thread_async_race.stderr b/tests/fail/data_race/dangling_thread_async_race.stderr index efdc913ce27a9..66bb8b0be4048 100644 --- a/tests/fail/data_race/dangling_thread_async_race.stderr +++ b/tests/fail/data_race/dangling_thread_async_race.stderr @@ -6,7 +6,7 @@ LL | *c.0 = 64; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside closure at $DIR/dangling_thread_async_race.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/data_race/dangling_thread_race.stderr b/tests/fail/data_race/dangling_thread_race.stderr index 899cfdd095e38..1fd9afe176331 100644 --- a/tests/fail/data_race/dangling_thread_race.stderr +++ b/tests/fail/data_race/dangling_thread_race.stderr @@ -6,7 +6,7 @@ LL | *c.0 = 64; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/dangling_thread_race.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/data_race/dealloc_read_race1.stderr b/tests/fail/data_race/dealloc_read_race1.stderr index 9e35fb7b6bd82..eec74e8b542a0 100644 --- a/tests/fail/data_race/dealloc_read_race1.stderr +++ b/tests/fail/data_race/dealloc_read_race1.stderr @@ -11,7 +11,7 @@ LL | | ); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside closure at $DIR/dealloc_read_race1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/data_race/dealloc_read_race2.stderr b/tests/fail/data_race/dealloc_read_race2.stderr index f703d1896d91f..41a1224101fc5 100644 --- a/tests/fail/data_race/dealloc_read_race2.stderr +++ b/tests/fail/data_race/dealloc_read_race2.stderr @@ -6,7 +6,7 @@ LL | *ptr.0 | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside closure at $DIR/dealloc_read_race2.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/data_race/dealloc_read_race_stack.stderr b/tests/fail/data_race/dealloc_read_race_stack.stderr index b1e7d3649ecb3..3c125e03a680c 100644 --- a/tests/fail/data_race/dealloc_read_race_stack.stderr +++ b/tests/fail/data_race/dealloc_read_race_stack.stderr @@ -6,7 +6,7 @@ LL | } | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside closure at $DIR/dealloc_read_race_stack.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/data_race/dealloc_write_race1.stderr b/tests/fail/data_race/dealloc_write_race1.stderr index a9ac03eb31db9..f16c0040bb8a4 100644 --- a/tests/fail/data_race/dealloc_write_race1.stderr +++ b/tests/fail/data_race/dealloc_write_race1.stderr @@ -11,7 +11,7 @@ LL | | ); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside closure at $DIR/dealloc_write_race1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/data_race/dealloc_write_race2.stderr b/tests/fail/data_race/dealloc_write_race2.stderr index 37d1c551d4935..6f2e829b42971 100644 --- a/tests/fail/data_race/dealloc_write_race2.stderr +++ b/tests/fail/data_race/dealloc_write_race2.stderr @@ -6,7 +6,7 @@ LL | *ptr.0 = 2; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside closure at $DIR/dealloc_write_race2.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/data_race/dealloc_write_race_stack.stderr b/tests/fail/data_race/dealloc_write_race_stack.stderr index 622ac25189be5..ed069bb6fcd61 100644 --- a/tests/fail/data_race/dealloc_write_race_stack.stderr +++ b/tests/fail/data_race/dealloc_write_race_stack.stderr @@ -6,7 +6,7 @@ LL | } | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside closure at $DIR/dealloc_write_race_stack.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/data_race/enable_after_join_to_main.stderr b/tests/fail/data_race/enable_after_join_to_main.stderr index 4426952e44b55..cd707bdcfa9c5 100644 --- a/tests/fail/data_race/enable_after_join_to_main.stderr +++ b/tests/fail/data_race/enable_after_join_to_main.stderr @@ -6,7 +6,7 @@ LL | *c.0 = 64; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside closure at $DIR/enable_after_join_to_main.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/data_race/fence_after_load.stderr b/tests/fail/data_race/fence_after_load.stderr index b9cffeda27bef..878342c1bd9ff 100644 --- a/tests/fail/data_race/fence_after_load.stderr +++ b/tests/fail/data_race/fence_after_load.stderr @@ -6,7 +6,7 @@ LL | unsafe { V = 2 } | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/fence_after_load.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/data_race/read_write_race.stderr b/tests/fail/data_race/read_write_race.stderr index a65e7006cf0a8..b87a7a10974e8 100644 --- a/tests/fail/data_race/read_write_race.stderr +++ b/tests/fail/data_race/read_write_race.stderr @@ -6,7 +6,7 @@ LL | *c.0 = 64; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside closure at $DIR/read_write_race.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/data_race/read_write_race_stack.stderr b/tests/fail/data_race/read_write_race_stack.stderr index 390b3ab38ede0..29739d5083c4c 100644 --- a/tests/fail/data_race/read_write_race_stack.stderr +++ b/tests/fail/data_race/read_write_race_stack.stderr @@ -6,7 +6,7 @@ LL | stack_var | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside closure at $DIR/read_write_race_stack.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/data_race/relax_acquire_race.stderr b/tests/fail/data_race/relax_acquire_race.stderr index 85de60c026550..21f9e6f960352 100644 --- a/tests/fail/data_race/relax_acquire_race.stderr +++ b/tests/fail/data_race/relax_acquire_race.stderr @@ -6,7 +6,7 @@ LL | *c.0 | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside closure at $DIR/relax_acquire_race.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/data_race/release_seq_race.stderr b/tests/fail/data_race/release_seq_race.stderr index db333d756f855..a7bca03547e50 100644 --- a/tests/fail/data_race/release_seq_race.stderr +++ b/tests/fail/data_race/release_seq_race.stderr @@ -6,7 +6,7 @@ LL | *c.0 | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside closure at $DIR/release_seq_race.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/data_race/release_seq_race_same_thread.stderr b/tests/fail/data_race/release_seq_race_same_thread.stderr index f4c38d5315006..515ce17e16cd0 100644 --- a/tests/fail/data_race/release_seq_race_same_thread.stderr +++ b/tests/fail/data_race/release_seq_race_same_thread.stderr @@ -6,7 +6,7 @@ LL | *c.0 | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside closure at $DIR/release_seq_race_same_thread.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/data_race/rmw_race.stderr b/tests/fail/data_race/rmw_race.stderr index 346fcc31b9c06..905592fc22247 100644 --- a/tests/fail/data_race/rmw_race.stderr +++ b/tests/fail/data_race/rmw_race.stderr @@ -6,7 +6,7 @@ LL | *c.0 | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside closure at $DIR/rmw_race.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/data_race/write_write_race.stderr b/tests/fail/data_race/write_write_race.stderr index e6254281aef36..afb9f4c1edb79 100644 --- a/tests/fail/data_race/write_write_race.stderr +++ b/tests/fail/data_race/write_write_race.stderr @@ -6,7 +6,7 @@ LL | *c.0 = 64; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside closure at $DIR/write_write_race.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/data_race/write_write_race_stack.stderr b/tests/fail/data_race/write_write_race_stack.stderr index 1f7318e6f9515..97977bc297c16 100644 --- a/tests/fail/data_race/write_write_race_stack.stderr +++ b/tests/fail/data_race/write_write_race_stack.stderr @@ -6,7 +6,7 @@ LL | stack_var = 1usize; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside closure at $DIR/write_write_race_stack.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/environ-gets-deallocated.stderr b/tests/fail/environ-gets-deallocated.stderr index 640d953a811d2..bb6525fa80614 100644 --- a/tests/fail/environ-gets-deallocated.stderr +++ b/tests/fail/environ-gets-deallocated.stderr @@ -6,7 +6,7 @@ LL | let _y = unsafe { *pointer }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/environ-gets-deallocated.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/extern_static.stderr b/tests/fail/extern_static.stderr index e673d074bc84c..0adb996decdbd 100644 --- a/tests/fail/extern_static.stderr +++ b/tests/fail/extern_static.stderr @@ -5,7 +5,7 @@ LL | let _val = unsafe { std::ptr::addr_of!(FOO) }; | ^^^ `extern` static `FOO` from crate `extern_static` is not supported by Miri | = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support - + = note: backtrace: = note: inside `main` at $DIR/extern_static.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/extern_static_in_const.stderr b/tests/fail/extern_static_in_const.stderr index 8524bb02c054f..ebd5dd7fee157 100644 --- a/tests/fail/extern_static_in_const.stderr +++ b/tests/fail/extern_static_in_const.stderr @@ -5,7 +5,7 @@ LL | let _val = X; | ^ `extern` static `E` from crate `extern_static_in_const` is not supported by Miri | = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support - + = note: backtrace: = note: inside `main` at $DIR/extern_static_in_const.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/fast_math_both.stderr b/tests/fail/fast_math_both.stderr index 542044df4d9cb..902c9a1f8bb53 100644 --- a/tests/fail/fast_math_both.stderr +++ b/tests/fail/fast_math_both.stderr @@ -6,7 +6,7 @@ LL | ...: f32 = core::intrinsics::fsub_fast(f32::NAN, f32::NAN); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/fast_math_both.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/fast_math_first.stderr b/tests/fail/fast_math_first.stderr index 74ba08dc87878..986b487991f99 100644 --- a/tests/fail/fast_math_first.stderr +++ b/tests/fail/fast_math_first.stderr @@ -6,7 +6,7 @@ LL | ... let _x: f32 = core::intrinsics::frem_fast(f32::NAN, 3.2); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/fast_math_first.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/fast_math_second.stderr b/tests/fail/fast_math_second.stderr index cbb059a07f682..c5abb17f8fac9 100644 --- a/tests/fail/fast_math_second.stderr +++ b/tests/fail/fast_math_second.stderr @@ -6,7 +6,7 @@ LL | ...f32 = core::intrinsics::fmul_fast(3.4f32, f32::INFINITY); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/fast_math_second.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/fs/close_stdout.stderr b/tests/fail/fs/close_stdout.stderr index 79fa0458b4bd5..08f744a5c4588 100644 --- a/tests/fail/fs/close_stdout.stderr +++ b/tests/fail/fs/close_stdout.stderr @@ -5,7 +5,7 @@ LL | libc::close(1); | ^^^^^^^^^^^^^^ stdout cannot be closed | = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support - + = note: backtrace: = note: inside `main` at $DIR/close_stdout.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/fs/isolated_file.stderr b/tests/fail/fs/isolated_file.stderr index d06698c940dd6..e75d7b7c3d93b 100644 --- a/tests/fail/fs/isolated_file.stderr +++ b/tests/fail/fs/isolated_file.stderr @@ -6,7 +6,7 @@ LL | let fd = cvt_r(|| unsafe { open64(path.as_ptr(), flags, opts.mode a | = help: pass the flag `-Zmiri-disable-isolation` to disable isolation; = help: or pass `-Zmiri-isolation-error=warn` to configure Miri to return an error code from isolated operations (if supported for that operation) and continue with a warning - + = note: backtrace: = note: inside closure at RUSTLIB/std/src/sys/PLATFORM/fs.rs:LL:CC = note: inside `std::sys::PLATFORM::cvt_r::` at RUSTLIB/std/src/sys/PLATFORM/mod.rs:LL:CC = note: inside `std::sys::PLATFORM::fs::File::open_c` at RUSTLIB/std/src/sys/PLATFORM/fs.rs:LL:CC diff --git a/tests/fail/fs/isolated_stdin.stderr b/tests/fail/fs/isolated_stdin.stderr index 4fbd11e7cd9b1..fe9700f07b396 100644 --- a/tests/fail/fs/isolated_stdin.stderr +++ b/tests/fail/fs/isolated_stdin.stderr @@ -6,7 +6,7 @@ LL | libc::read(0, bytes.as_mut_ptr() as *mut libc::c_void, 512); | = help: pass the flag `-Zmiri-disable-isolation` to disable isolation; = help: or pass `-Zmiri-isolation-error=warn` to configure Miri to return an error code from isolated operations (if supported for that operation) and continue with a warning - + = note: backtrace: = note: inside `main` at $DIR/isolated_stdin.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/fs/read_from_stdout.stderr b/tests/fail/fs/read_from_stdout.stderr index 45573c471e2ad..5c16999cbf79a 100644 --- a/tests/fail/fs/read_from_stdout.stderr +++ b/tests/fail/fs/read_from_stdout.stderr @@ -5,7 +5,7 @@ LL | libc::read(1, bytes.as_mut_ptr() as *mut libc::c_void, 512); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot read from stdout | = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support - + = note: backtrace: = note: inside `main` at $DIR/read_from_stdout.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/fs/unix_open_missing_required_mode.stderr b/tests/fail/fs/unix_open_missing_required_mode.stderr index 7003234331242..a7297efaff960 100644 --- a/tests/fail/fs/unix_open_missing_required_mode.stderr +++ b/tests/fail/fs/unix_open_missing_required_mode.stderr @@ -6,7 +6,7 @@ LL | ...safe { libc::open(name_ptr, libc::O_CREAT) }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `test_file_open_missing_needed_mode` at $DIR/unix_open_missing_required_mode.rs:LL:CC note: inside `main` at $DIR/unix_open_missing_required_mode.rs:LL:CC --> $DIR/unix_open_missing_required_mode.rs:LL:CC diff --git a/tests/fail/fs/write_to_stdin.stderr b/tests/fail/fs/write_to_stdin.stderr index 1cbc3eef66ae9..518d36b5551bf 100644 --- a/tests/fail/fs/write_to_stdin.stderr +++ b/tests/fail/fs/write_to_stdin.stderr @@ -5,7 +5,7 @@ LL | libc::write(0, bytes.as_ptr() as *const libc::c_void, 5); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot write to stdin | = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support - + = note: backtrace: = note: inside `main` at $DIR/write_to_stdin.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/function_calls/check_arg_abi.stderr b/tests/fail/function_calls/check_arg_abi.stderr index 9ee7d301b19ff..952acde9ea537 100644 --- a/tests/fail/function_calls/check_arg_abi.stderr +++ b/tests/fail/function_calls/check_arg_abi.stderr @@ -6,7 +6,7 @@ LL | let _ = malloc(0); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/check_arg_abi.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/function_calls/check_arg_count_abort.stderr b/tests/fail/function_calls/check_arg_count_abort.stderr index c7682578f99b8..bf24c5c917942 100644 --- a/tests/fail/function_calls/check_arg_count_abort.stderr +++ b/tests/fail/function_calls/check_arg_count_abort.stderr @@ -6,7 +6,7 @@ LL | abort(1); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/check_arg_count_abort.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/function_calls/check_arg_count_too_few_args.stderr b/tests/fail/function_calls/check_arg_count_too_few_args.stderr index b7d6bbfd5719b..ac0ec606dac8b 100644 --- a/tests/fail/function_calls/check_arg_count_too_few_args.stderr +++ b/tests/fail/function_calls/check_arg_count_too_few_args.stderr @@ -6,7 +6,7 @@ LL | let _ = malloc(); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/check_arg_count_too_few_args.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/function_calls/check_arg_count_too_many_args.stderr b/tests/fail/function_calls/check_arg_count_too_many_args.stderr index 33cc5750b890e..b465b02b6e42e 100644 --- a/tests/fail/function_calls/check_arg_count_too_many_args.stderr +++ b/tests/fail/function_calls/check_arg_count_too_many_args.stderr @@ -6,7 +6,7 @@ LL | let _ = malloc(1, 2); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/check_arg_count_too_many_args.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/function_calls/check_callback_abi.stderr b/tests/fail/function_calls/check_callback_abi.stderr index 56314e6d28593..5d5c30a203ac2 100644 --- a/tests/fail/function_calls/check_callback_abi.stderr +++ b/tests/fail/function_calls/check_callback_abi.stderr @@ -11,7 +11,7 @@ LL | | ); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/check_callback_abi.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/function_calls/exported_symbol_abi_mismatch.cache.stderr b/tests/fail/function_calls/exported_symbol_abi_mismatch.cache.stderr index dee7f66e0ad9c..ba2b4de889b7e 100644 --- a/tests/fail/function_calls/exported_symbol_abi_mismatch.cache.stderr +++ b/tests/fail/function_calls/exported_symbol_abi_mismatch.cache.stderr @@ -6,7 +6,7 @@ LL | foo(); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/exported_symbol_abi_mismatch.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/function_calls/exported_symbol_abi_mismatch.fn_ptr.stderr b/tests/fail/function_calls/exported_symbol_abi_mismatch.fn_ptr.stderr index ebe19796609cf..358f86c0403b5 100644 --- a/tests/fail/function_calls/exported_symbol_abi_mismatch.fn_ptr.stderr +++ b/tests/fail/function_calls/exported_symbol_abi_mismatch.fn_ptr.stderr @@ -6,7 +6,7 @@ LL | std::mem::transmute::(foo)(); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/exported_symbol_abi_mismatch.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/function_calls/exported_symbol_abi_mismatch.no_cache.stderr b/tests/fail/function_calls/exported_symbol_abi_mismatch.no_cache.stderr index dee7f66e0ad9c..ba2b4de889b7e 100644 --- a/tests/fail/function_calls/exported_symbol_abi_mismatch.no_cache.stderr +++ b/tests/fail/function_calls/exported_symbol_abi_mismatch.no_cache.stderr @@ -6,7 +6,7 @@ LL | foo(); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/exported_symbol_abi_mismatch.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/function_calls/exported_symbol_bad_unwind1.stderr b/tests/fail/function_calls/exported_symbol_bad_unwind1.stderr index 8cd74f1fd86df..0b943432c2076 100644 --- a/tests/fail/function_calls/exported_symbol_bad_unwind1.stderr +++ b/tests/fail/function_calls/exported_symbol_bad_unwind1.stderr @@ -8,7 +8,7 @@ LL | unsafe { unwind() } | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/exported_symbol_bad_unwind1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/function_calls/exported_symbol_bad_unwind2.extern_block.stderr b/tests/fail/function_calls/exported_symbol_bad_unwind2.extern_block.stderr index fac42bf66ae4b..f974eb87037a4 100644 --- a/tests/fail/function_calls/exported_symbol_bad_unwind2.extern_block.stderr +++ b/tests/fail/function_calls/exported_symbol_bad_unwind2.extern_block.stderr @@ -8,7 +8,7 @@ LL | unsafe { nounwind() } | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/exported_symbol_bad_unwind2.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/function_calls/exported_symbol_clashing.stderr b/tests/fail/function_calls/exported_symbol_clashing.stderr index 1ddd882c4cb3b..998b7c415930e 100644 --- a/tests/fail/function_calls/exported_symbol_clashing.stderr +++ b/tests/fail/function_calls/exported_symbol_clashing.stderr @@ -14,6 +14,7 @@ help: then it's defined here again, in crate `exported_symbol_clashing` | LL | fn bar() {} | ^^^^^^^^ + = note: backtrace: = note: inside `main` at $DIR/exported_symbol_clashing.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/function_calls/exported_symbol_shim_clashing.stderr b/tests/fail/function_calls/exported_symbol_shim_clashing.stderr index fa25b4e3f3472..69b99b3747336 100644 --- a/tests/fail/function_calls/exported_symbol_shim_clashing.stderr +++ b/tests/fail/function_calls/exported_symbol_shim_clashing.stderr @@ -12,6 +12,7 @@ LL | | LL | | unreachable!() LL | | } | |_^ + = note: backtrace: = note: inside `main` at $DIR/exported_symbol_shim_clashing.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/function_calls/exported_symbol_wrong_arguments.stderr b/tests/fail/function_calls/exported_symbol_wrong_arguments.stderr index fe5498c85d7fb..2e80e833710e7 100644 --- a/tests/fail/function_calls/exported_symbol_wrong_arguments.stderr +++ b/tests/fail/function_calls/exported_symbol_wrong_arguments.stderr @@ -6,7 +6,7 @@ LL | unsafe { foo(1) } | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/exported_symbol_wrong_arguments.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/function_calls/exported_symbol_wrong_type.stderr b/tests/fail/function_calls/exported_symbol_wrong_type.stderr index f402704908712..900e23d1212ec 100644 --- a/tests/fail/function_calls/exported_symbol_wrong_type.stderr +++ b/tests/fail/function_calls/exported_symbol_wrong_type.stderr @@ -6,7 +6,7 @@ LL | unsafe { FOO() } | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/exported_symbol_wrong_type.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/function_pointers/cast_box_int_to_fn_ptr.stderr b/tests/fail/function_pointers/cast_box_int_to_fn_ptr.stderr index 13f8ef3782439..436cced9f02e5 100644 --- a/tests/fail/function_pointers/cast_box_int_to_fn_ptr.stderr +++ b/tests/fail/function_pointers/cast_box_int_to_fn_ptr.stderr @@ -6,7 +6,7 @@ LL | (*g)(42) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/cast_box_int_to_fn_ptr.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/function_pointers/cast_fn_ptr1.stderr b/tests/fail/function_pointers/cast_fn_ptr1.stderr index 765dbb6578ab1..972fd9afc8ea7 100644 --- a/tests/fail/function_pointers/cast_fn_ptr1.stderr +++ b/tests/fail/function_pointers/cast_fn_ptr1.stderr @@ -6,7 +6,7 @@ LL | g(42) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/cast_fn_ptr1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/function_pointers/cast_fn_ptr2.stderr b/tests/fail/function_pointers/cast_fn_ptr2.stderr index 123d0e1b0bb6e..638c4ca6781ed 100644 --- a/tests/fail/function_pointers/cast_fn_ptr2.stderr +++ b/tests/fail/function_pointers/cast_fn_ptr2.stderr @@ -6,7 +6,7 @@ LL | g(42) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/cast_fn_ptr2.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/function_pointers/cast_fn_ptr3.stderr b/tests/fail/function_pointers/cast_fn_ptr3.stderr index 51f6ca0713d72..e21d1c6b6f733 100644 --- a/tests/fail/function_pointers/cast_fn_ptr3.stderr +++ b/tests/fail/function_pointers/cast_fn_ptr3.stderr @@ -6,7 +6,7 @@ LL | g() | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/cast_fn_ptr3.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/function_pointers/cast_fn_ptr4.stderr b/tests/fail/function_pointers/cast_fn_ptr4.stderr index 515f00ec3929f..b1acafcebe7e1 100644 --- a/tests/fail/function_pointers/cast_fn_ptr4.stderr +++ b/tests/fail/function_pointers/cast_fn_ptr4.stderr @@ -6,7 +6,7 @@ LL | g(&42 as *const i32) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/cast_fn_ptr4.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/function_pointers/cast_fn_ptr5.stderr b/tests/fail/function_pointers/cast_fn_ptr5.stderr index 2978866c92905..c4915f905bf3e 100644 --- a/tests/fail/function_pointers/cast_fn_ptr5.stderr +++ b/tests/fail/function_pointers/cast_fn_ptr5.stderr @@ -6,7 +6,7 @@ LL | g() | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/cast_fn_ptr5.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/function_pointers/cast_int_to_fn_ptr.stderr b/tests/fail/function_pointers/cast_int_to_fn_ptr.stderr index 25501e74913d4..3a80120a9b926 100644 --- a/tests/fail/function_pointers/cast_int_to_fn_ptr.stderr +++ b/tests/fail/function_pointers/cast_int_to_fn_ptr.stderr @@ -6,7 +6,7 @@ LL | g(42) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/cast_int_to_fn_ptr.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/function_pointers/deref_fn_ptr.stderr b/tests/fail/function_pointers/deref_fn_ptr.stderr index 619b58f699a32..ecd001964a1bc 100644 --- a/tests/fail/function_pointers/deref_fn_ptr.stderr +++ b/tests/fail/function_pointers/deref_fn_ptr.stderr @@ -6,7 +6,7 @@ LL | *std::mem::transmute::(f) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/deref_fn_ptr.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/function_pointers/execute_memory.stderr b/tests/fail/function_pointers/execute_memory.stderr index daa6277b85e41..b6438934b2b34 100644 --- a/tests/fail/function_pointers/execute_memory.stderr +++ b/tests/fail/function_pointers/execute_memory.stderr @@ -6,7 +6,7 @@ LL | f() | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/execute_memory.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/function_pointers/fn_ptr_offset.stderr b/tests/fail/function_pointers/fn_ptr_offset.stderr index 0f3baab1b512a..b5164d02ace1b 100644 --- a/tests/fail/function_pointers/fn_ptr_offset.stderr +++ b/tests/fail/function_pointers/fn_ptr_offset.stderr @@ -6,7 +6,7 @@ LL | x(); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/fn_ptr_offset.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/generator-pinned-moved.stderr b/tests/fail/generator-pinned-moved.stderr index 0ccf3091cde73..f1fb366d0652e 100644 --- a/tests/fail/generator-pinned-moved.stderr +++ b/tests/fail/generator-pinned-moved.stderr @@ -6,7 +6,7 @@ LL | *num += 1; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside closure at $DIR/generator-pinned-moved.rs:LL:CC note: inside ` as std::iter::Iterator>::next` at $DIR/generator-pinned-moved.rs:LL:CC --> $DIR/generator-pinned-moved.rs:LL:CC diff --git a/tests/fail/intrinsics/assume.stderr b/tests/fail/intrinsics/assume.stderr index e5059a699b103..1664e7ad743f4 100644 --- a/tests/fail/intrinsics/assume.stderr +++ b/tests/fail/intrinsics/assume.stderr @@ -6,7 +6,7 @@ LL | std::intrinsics::assume(x > 42); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/assume.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/copy_null.stderr b/tests/fail/intrinsics/copy_null.stderr index bb5a8742e9091..110408227e181 100644 --- a/tests/fail/intrinsics/copy_null.stderr +++ b/tests/fail/intrinsics/copy_null.stderr @@ -6,7 +6,7 @@ LL | copy_nonoverlapping(std::ptr::null(), ptr, 0); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/copy_null.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/copy_overflow.stderr b/tests/fail/intrinsics/copy_overflow.stderr index 897ea5ffec5e2..76917ae7ea157 100644 --- a/tests/fail/intrinsics/copy_overflow.stderr +++ b/tests/fail/intrinsics/copy_overflow.stderr @@ -6,7 +6,7 @@ LL | copy(src, dst, count) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `std::intrinsics::copy::` at RUSTLIB/core/src/intrinsics.rs:LL:CC = note: inside `std::ptr::mut_ptr::::copy_from` at RUSTLIB/core/src/ptr/mut_ptr.rs:LL:CC note: inside `main` at $DIR/copy_overflow.rs:LL:CC diff --git a/tests/fail/intrinsics/copy_overlapping.stderr b/tests/fail/intrinsics/copy_overlapping.stderr index cba08d9b5c823..9298a87712bbc 100644 --- a/tests/fail/intrinsics/copy_overlapping.stderr +++ b/tests/fail/intrinsics/copy_overlapping.stderr @@ -6,7 +6,7 @@ LL | copy_nonoverlapping(a, b, 2); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/copy_overlapping.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/copy_unaligned.stderr b/tests/fail/intrinsics/copy_unaligned.stderr index b244eaeb41916..890c7b12e03d7 100644 --- a/tests/fail/intrinsics/copy_unaligned.stderr +++ b/tests/fail/intrinsics/copy_unaligned.stderr @@ -6,7 +6,7 @@ LL | copy_nonoverlapping(&data[5], ptr, 0); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/copy_unaligned.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/ctlz_nonzero.stderr b/tests/fail/intrinsics/ctlz_nonzero.stderr index 0c895cf138e95..7d4d3dd8e1b86 100644 --- a/tests/fail/intrinsics/ctlz_nonzero.stderr +++ b/tests/fail/intrinsics/ctlz_nonzero.stderr @@ -6,7 +6,7 @@ LL | ctlz_nonzero(0u8); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/ctlz_nonzero.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/cttz_nonzero.stderr b/tests/fail/intrinsics/cttz_nonzero.stderr index 5257668d53e9d..284bfc1c4c994 100644 --- a/tests/fail/intrinsics/cttz_nonzero.stderr +++ b/tests/fail/intrinsics/cttz_nonzero.stderr @@ -6,7 +6,7 @@ LL | cttz_nonzero(0u8); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/cttz_nonzero.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/div-by-zero.stderr b/tests/fail/intrinsics/div-by-zero.stderr index 388f4aef7fa96..061123ddc1dec 100644 --- a/tests/fail/intrinsics/div-by-zero.stderr +++ b/tests/fail/intrinsics/div-by-zero.stderr @@ -6,7 +6,7 @@ LL | let _n = unchecked_div(1i64, 0); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/div-by-zero.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/exact_div1.stderr b/tests/fail/intrinsics/exact_div1.stderr index 59e853d0ececf..6564fad475def 100644 --- a/tests/fail/intrinsics/exact_div1.stderr +++ b/tests/fail/intrinsics/exact_div1.stderr @@ -6,7 +6,7 @@ LL | unsafe { std::intrinsics::exact_div(2, 0) }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/exact_div1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/exact_div2.stderr b/tests/fail/intrinsics/exact_div2.stderr index dfbcdd1f34f1e..7e8e2ee18121b 100644 --- a/tests/fail/intrinsics/exact_div2.stderr +++ b/tests/fail/intrinsics/exact_div2.stderr @@ -6,7 +6,7 @@ LL | unsafe { std::intrinsics::exact_div(2u16, 3) }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/exact_div2.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/exact_div3.stderr b/tests/fail/intrinsics/exact_div3.stderr index c3b908ce0ad55..8b1f15794b7cd 100644 --- a/tests/fail/intrinsics/exact_div3.stderr +++ b/tests/fail/intrinsics/exact_div3.stderr @@ -6,7 +6,7 @@ LL | unsafe { std::intrinsics::exact_div(-19i8, 2) }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/exact_div3.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/exact_div4.stderr b/tests/fail/intrinsics/exact_div4.stderr index b82950674fbcc..4da670bc846cf 100644 --- a/tests/fail/intrinsics/exact_div4.stderr +++ b/tests/fail/intrinsics/exact_div4.stderr @@ -6,7 +6,7 @@ LL | unsafe { std::intrinsics::exact_div(i64::MIN, -1) }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/exact_div4.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/float_to_int_32_inf1.stderr b/tests/fail/intrinsics/float_to_int_32_inf1.stderr index b12fd13b5f4da..88cd4a7c184b4 100644 --- a/tests/fail/intrinsics/float_to_int_32_inf1.stderr +++ b/tests/fail/intrinsics/float_to_int_32_inf1.stderr @@ -6,7 +6,7 @@ LL | float_to_int_unchecked::(f32::INFINITY); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/float_to_int_32_inf1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/float_to_int_32_infneg1.stderr b/tests/fail/intrinsics/float_to_int_32_infneg1.stderr index d9223462bfa59..a833001840481 100644 --- a/tests/fail/intrinsics/float_to_int_32_infneg1.stderr +++ b/tests/fail/intrinsics/float_to_int_32_infneg1.stderr @@ -6,7 +6,7 @@ LL | float_to_int_unchecked::(f32::NEG_INFINITY); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/float_to_int_32_infneg1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/float_to_int_32_nan.stderr b/tests/fail/intrinsics/float_to_int_32_nan.stderr index cb8764174abdc..9bf312a9ccbd8 100644 --- a/tests/fail/intrinsics/float_to_int_32_nan.stderr +++ b/tests/fail/intrinsics/float_to_int_32_nan.stderr @@ -6,7 +6,7 @@ LL | float_to_int_unchecked::(f32::NAN); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/float_to_int_32_nan.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/float_to_int_32_nanneg.stderr b/tests/fail/intrinsics/float_to_int_32_nanneg.stderr index 49e19bf963565..be105ccdaa711 100644 --- a/tests/fail/intrinsics/float_to_int_32_nanneg.stderr +++ b/tests/fail/intrinsics/float_to_int_32_nanneg.stderr @@ -6,7 +6,7 @@ LL | float_to_int_unchecked::(-f32::NAN); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/float_to_int_32_nanneg.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/float_to_int_32_neg.stderr b/tests/fail/intrinsics/float_to_int_32_neg.stderr index 5d847166a0718..6f926d442bb4e 100644 --- a/tests/fail/intrinsics/float_to_int_32_neg.stderr +++ b/tests/fail/intrinsics/float_to_int_32_neg.stderr @@ -6,7 +6,7 @@ LL | float_to_int_unchecked::(-1.000000001f32); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/float_to_int_32_neg.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/float_to_int_32_too_big1.stderr b/tests/fail/intrinsics/float_to_int_32_too_big1.stderr index be6ad1f381d4d..880eb6f48a9b3 100644 --- a/tests/fail/intrinsics/float_to_int_32_too_big1.stderr +++ b/tests/fail/intrinsics/float_to_int_32_too_big1.stderr @@ -6,7 +6,7 @@ LL | float_to_int_unchecked::(2147483648.0f32); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/float_to_int_32_too_big1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/float_to_int_32_too_big2.stderr b/tests/fail/intrinsics/float_to_int_32_too_big2.stderr index d7fbe5a34b52b..9ee3e2feed2f9 100644 --- a/tests/fail/intrinsics/float_to_int_32_too_big2.stderr +++ b/tests/fail/intrinsics/float_to_int_32_too_big2.stderr @@ -6,7 +6,7 @@ LL | float_to_int_unchecked::((u32::MAX - 127) as f32); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/float_to_int_32_too_big2.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/float_to_int_32_too_small1.stderr b/tests/fail/intrinsics/float_to_int_32_too_small1.stderr index 2c225b85ec90c..0f23fc05fd723 100644 --- a/tests/fail/intrinsics/float_to_int_32_too_small1.stderr +++ b/tests/fail/intrinsics/float_to_int_32_too_small1.stderr @@ -6,7 +6,7 @@ LL | float_to_int_unchecked::(-2147483904.0f32); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/float_to_int_32_too_small1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/float_to_int_64_inf1.stderr b/tests/fail/intrinsics/float_to_int_64_inf1.stderr index 7bb1f08afa874..eb493f141cbdd 100644 --- a/tests/fail/intrinsics/float_to_int_64_inf1.stderr +++ b/tests/fail/intrinsics/float_to_int_64_inf1.stderr @@ -6,7 +6,7 @@ LL | float_to_int_unchecked::(f64::INFINITY); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/float_to_int_64_inf1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/float_to_int_64_infneg1.stderr b/tests/fail/intrinsics/float_to_int_64_infneg1.stderr index eb96f6869a143..5e499e2712020 100644 --- a/tests/fail/intrinsics/float_to_int_64_infneg1.stderr +++ b/tests/fail/intrinsics/float_to_int_64_infneg1.stderr @@ -6,7 +6,7 @@ LL | float_to_int_unchecked::(f64::NEG_INFINITY); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/float_to_int_64_infneg1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/float_to_int_64_infneg2.stderr b/tests/fail/intrinsics/float_to_int_64_infneg2.stderr index a2f847be9071b..da22fa481727f 100644 --- a/tests/fail/intrinsics/float_to_int_64_infneg2.stderr +++ b/tests/fail/intrinsics/float_to_int_64_infneg2.stderr @@ -6,7 +6,7 @@ LL | float_to_int_unchecked::(f64::NEG_INFINITY); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/float_to_int_64_infneg2.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/float_to_int_64_nan.stderr b/tests/fail/intrinsics/float_to_int_64_nan.stderr index 8da8549758208..eff110ad724c4 100644 --- a/tests/fail/intrinsics/float_to_int_64_nan.stderr +++ b/tests/fail/intrinsics/float_to_int_64_nan.stderr @@ -6,7 +6,7 @@ LL | float_to_int_unchecked::(f64::NAN); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/float_to_int_64_nan.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/float_to_int_64_neg.stderr b/tests/fail/intrinsics/float_to_int_64_neg.stderr index 35bb0aaa22cb3..8d8851a9d7bf2 100644 --- a/tests/fail/intrinsics/float_to_int_64_neg.stderr +++ b/tests/fail/intrinsics/float_to_int_64_neg.stderr @@ -6,7 +6,7 @@ LL | float_to_int_unchecked::(-1.0000000000001f64); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/float_to_int_64_neg.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/float_to_int_64_too_big1.stderr b/tests/fail/intrinsics/float_to_int_64_too_big1.stderr index e031e00709e03..53c999ccba92f 100644 --- a/tests/fail/intrinsics/float_to_int_64_too_big1.stderr +++ b/tests/fail/intrinsics/float_to_int_64_too_big1.stderr @@ -6,7 +6,7 @@ LL | float_to_int_unchecked::(2147483648.0f64); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/float_to_int_64_too_big1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/float_to_int_64_too_big2.stderr b/tests/fail/intrinsics/float_to_int_64_too_big2.stderr index 8c4478603fbd5..4f5927eed59a2 100644 --- a/tests/fail/intrinsics/float_to_int_64_too_big2.stderr +++ b/tests/fail/intrinsics/float_to_int_64_too_big2.stderr @@ -6,7 +6,7 @@ LL | float_to_int_unchecked::(9223372036854775808.0f64); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/float_to_int_64_too_big2.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/float_to_int_64_too_big3.stderr b/tests/fail/intrinsics/float_to_int_64_too_big3.stderr index d7f97f37de593..d439b8695efb6 100644 --- a/tests/fail/intrinsics/float_to_int_64_too_big3.stderr +++ b/tests/fail/intrinsics/float_to_int_64_too_big3.stderr @@ -6,7 +6,7 @@ LL | float_to_int_unchecked::(18446744073709551616.0f64); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/float_to_int_64_too_big3.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/float_to_int_64_too_big4.stderr b/tests/fail/intrinsics/float_to_int_64_too_big4.stderr index cfac443f4c9ed..56677cd315544 100644 --- a/tests/fail/intrinsics/float_to_int_64_too_big4.stderr +++ b/tests/fail/intrinsics/float_to_int_64_too_big4.stderr @@ -6,7 +6,7 @@ LL | float_to_int_unchecked::(u128::MAX as f64); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/float_to_int_64_too_big4.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/float_to_int_64_too_big5.stderr b/tests/fail/intrinsics/float_to_int_64_too_big5.stderr index a0d501dad303f..ab5b2c954aecc 100644 --- a/tests/fail/intrinsics/float_to_int_64_too_big5.stderr +++ b/tests/fail/intrinsics/float_to_int_64_too_big5.stderr @@ -6,7 +6,7 @@ LL | float_to_int_unchecked::(2402823669209384634633746074317 | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/float_to_int_64_too_big5.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/float_to_int_64_too_big6.stderr b/tests/fail/intrinsics/float_to_int_64_too_big6.stderr index afb5d4ffe7228..e64ab2262715c 100644 --- a/tests/fail/intrinsics/float_to_int_64_too_big6.stderr +++ b/tests/fail/intrinsics/float_to_int_64_too_big6.stderr @@ -6,7 +6,7 @@ LL | float_to_int_unchecked::(f64::MAX); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/float_to_int_64_too_big6.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/float_to_int_64_too_big7.stderr b/tests/fail/intrinsics/float_to_int_64_too_big7.stderr index 291acf529b4fc..e9809e3ba5899 100644 --- a/tests/fail/intrinsics/float_to_int_64_too_big7.stderr +++ b/tests/fail/intrinsics/float_to_int_64_too_big7.stderr @@ -6,7 +6,7 @@ LL | float_to_int_unchecked::(f64::MIN); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/float_to_int_64_too_big7.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/float_to_int_64_too_small1.stderr b/tests/fail/intrinsics/float_to_int_64_too_small1.stderr index ceb625972690f..714205ca1bebd 100644 --- a/tests/fail/intrinsics/float_to_int_64_too_small1.stderr +++ b/tests/fail/intrinsics/float_to_int_64_too_small1.stderr @@ -6,7 +6,7 @@ LL | float_to_int_unchecked::(-2147483649.0f64); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/float_to_int_64_too_small1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/float_to_int_64_too_small2.stderr b/tests/fail/intrinsics/float_to_int_64_too_small2.stderr index f8255c2daca09..b2302bf905ac6 100644 --- a/tests/fail/intrinsics/float_to_int_64_too_small2.stderr +++ b/tests/fail/intrinsics/float_to_int_64_too_small2.stderr @@ -6,7 +6,7 @@ LL | float_to_int_unchecked::(-9223372036854777856.0f64); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/float_to_int_64_too_small2.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/float_to_int_64_too_small3.stderr b/tests/fail/intrinsics/float_to_int_64_too_small3.stderr index 6bfb6f1f18d8a..bcff0fb630423 100644 --- a/tests/fail/intrinsics/float_to_int_64_too_small3.stderr +++ b/tests/fail/intrinsics/float_to_int_64_too_small3.stderr @@ -6,7 +6,7 @@ LL | float_to_int_unchecked::(-240282366920938463463374607431 | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/float_to_int_64_too_small3.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/out_of_bounds_ptr_1.stderr b/tests/fail/intrinsics/out_of_bounds_ptr_1.stderr index 8a7da324ef897..2c4d6bbc50cf8 100644 --- a/tests/fail/intrinsics/out_of_bounds_ptr_1.stderr +++ b/tests/fail/intrinsics/out_of_bounds_ptr_1.stderr @@ -6,7 +6,7 @@ LL | unsafe { intrinsics::offset(self, count) } | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `std::ptr::const_ptr::::offset` at RUSTLIB/core/src/ptr/const_ptr.rs:LL:CC note: inside `main` at $DIR/out_of_bounds_ptr_1.rs:LL:CC --> $DIR/out_of_bounds_ptr_1.rs:LL:CC diff --git a/tests/fail/intrinsics/out_of_bounds_ptr_2.stderr b/tests/fail/intrinsics/out_of_bounds_ptr_2.stderr index 78a17a2ab7b5a..70ce2dc02a821 100644 --- a/tests/fail/intrinsics/out_of_bounds_ptr_2.stderr +++ b/tests/fail/intrinsics/out_of_bounds_ptr_2.stderr @@ -6,7 +6,7 @@ LL | unsafe { intrinsics::offset(self, count) } | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `std::ptr::const_ptr::::offset` at RUSTLIB/core/src/ptr/const_ptr.rs:LL:CC note: inside `main` at $DIR/out_of_bounds_ptr_2.rs:LL:CC --> $DIR/out_of_bounds_ptr_2.rs:LL:CC diff --git a/tests/fail/intrinsics/out_of_bounds_ptr_3.stderr b/tests/fail/intrinsics/out_of_bounds_ptr_3.stderr index 9866529eeeb55..075f40b54a2c7 100644 --- a/tests/fail/intrinsics/out_of_bounds_ptr_3.stderr +++ b/tests/fail/intrinsics/out_of_bounds_ptr_3.stderr @@ -6,7 +6,7 @@ LL | unsafe { intrinsics::offset(self, count) } | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `std::ptr::const_ptr::::offset` at RUSTLIB/core/src/ptr/const_ptr.rs:LL:CC note: inside `main` at $DIR/out_of_bounds_ptr_3.rs:LL:CC --> $DIR/out_of_bounds_ptr_3.rs:LL:CC diff --git a/tests/fail/intrinsics/overflowing-unchecked-rsh.stderr b/tests/fail/intrinsics/overflowing-unchecked-rsh.stderr index 0d22b166b2678..705ae01188b8c 100644 --- a/tests/fail/intrinsics/overflowing-unchecked-rsh.stderr +++ b/tests/fail/intrinsics/overflowing-unchecked-rsh.stderr @@ -6,7 +6,7 @@ LL | let _n = unchecked_shr(1i64, 64); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/overflowing-unchecked-rsh.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/ptr_offset_0_plus_0.stderr b/tests/fail/intrinsics/ptr_offset_0_plus_0.stderr index 741314ea8a680..ae9dd15b13304 100644 --- a/tests/fail/intrinsics/ptr_offset_0_plus_0.stderr +++ b/tests/fail/intrinsics/ptr_offset_0_plus_0.stderr @@ -6,7 +6,7 @@ LL | unsafe { intrinsics::offset(self, count) as *mut T } | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `std::ptr::mut_ptr::::offset` at RUSTLIB/core/src/ptr/mut_ptr.rs:LL:CC note: inside `main` at $DIR/ptr_offset_0_plus_0.rs:LL:CC --> $DIR/ptr_offset_0_plus_0.rs:LL:CC diff --git a/tests/fail/intrinsics/ptr_offset_from_oob.stderr b/tests/fail/intrinsics/ptr_offset_from_oob.stderr index 0e723a5ee3951..699ca1a87ae87 100644 --- a/tests/fail/intrinsics/ptr_offset_from_oob.stderr +++ b/tests/fail/intrinsics/ptr_offset_from_oob.stderr @@ -6,7 +6,7 @@ LL | unsafe { ptr_offset_from(end_ptr, end_ptr) }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/ptr_offset_from_oob.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/ptr_offset_int_plus_int.stderr b/tests/fail/intrinsics/ptr_offset_int_plus_int.stderr index e6b8f102f3946..49e02651e9636 100644 --- a/tests/fail/intrinsics/ptr_offset_int_plus_int.stderr +++ b/tests/fail/intrinsics/ptr_offset_int_plus_int.stderr @@ -6,7 +6,7 @@ LL | unsafe { intrinsics::offset(self, count) as *mut T } | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `std::ptr::mut_ptr::::offset` at RUSTLIB/core/src/ptr/mut_ptr.rs:LL:CC note: inside `main` at $DIR/ptr_offset_int_plus_int.rs:LL:CC --> $DIR/ptr_offset_int_plus_int.rs:LL:CC diff --git a/tests/fail/intrinsics/ptr_offset_int_plus_ptr.stderr b/tests/fail/intrinsics/ptr_offset_int_plus_ptr.stderr index f88ad758d438d..fa7a107ab5340 100644 --- a/tests/fail/intrinsics/ptr_offset_int_plus_ptr.stderr +++ b/tests/fail/intrinsics/ptr_offset_int_plus_ptr.stderr @@ -6,7 +6,7 @@ LL | unsafe { intrinsics::offset(self, count) as *mut T } | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `std::ptr::mut_ptr::::offset` at RUSTLIB/core/src/ptr/mut_ptr.rs:LL:CC note: inside `main` at $DIR/ptr_offset_int_plus_ptr.rs:LL:CC --> $DIR/ptr_offset_int_plus_ptr.rs:LL:CC diff --git a/tests/fail/intrinsics/ptr_offset_overflow.stderr b/tests/fail/intrinsics/ptr_offset_overflow.stderr index a144141c3c381..d8596acc33b0c 100644 --- a/tests/fail/intrinsics/ptr_offset_overflow.stderr +++ b/tests/fail/intrinsics/ptr_offset_overflow.stderr @@ -6,7 +6,7 @@ LL | unsafe { intrinsics::offset(self, count) } | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `std::ptr::const_ptr::::offset` at RUSTLIB/core/src/ptr/const_ptr.rs:LL:CC note: inside `main` at $DIR/ptr_offset_overflow.rs:LL:CC --> $DIR/ptr_offset_overflow.rs:LL:CC diff --git a/tests/fail/intrinsics/ptr_offset_ptr_plus_0.stderr b/tests/fail/intrinsics/ptr_offset_ptr_plus_0.stderr index 15e21ee676f7c..c9b7f88385d90 100644 --- a/tests/fail/intrinsics/ptr_offset_ptr_plus_0.stderr +++ b/tests/fail/intrinsics/ptr_offset_ptr_plus_0.stderr @@ -6,7 +6,7 @@ LL | unsafe { intrinsics::offset(self, count) as *mut T } | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `std::ptr::mut_ptr::::offset` at RUSTLIB/core/src/ptr/mut_ptr.rs:LL:CC note: inside `main` at $DIR/ptr_offset_ptr_plus_0.rs:LL:CC --> $DIR/ptr_offset_ptr_plus_0.rs:LL:CC diff --git a/tests/fail/intrinsics/rem-by-zero.stderr b/tests/fail/intrinsics/rem-by-zero.stderr index 7501aca7b247f..1da33d8eaf59c 100644 --- a/tests/fail/intrinsics/rem-by-zero.stderr +++ b/tests/fail/intrinsics/rem-by-zero.stderr @@ -6,7 +6,7 @@ LL | let _n = unchecked_rem(3u32, 0); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/rem-by-zero.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/simd-div-by-zero.stderr b/tests/fail/intrinsics/simd-div-by-zero.stderr index 37e1aafec2c01..552749c48ea7d 100644 --- a/tests/fail/intrinsics/simd-div-by-zero.stderr +++ b/tests/fail/intrinsics/simd-div-by-zero.stderr @@ -6,7 +6,7 @@ LL | simd_div(x, y); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/simd-div-by-zero.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/simd-div-overflow.stderr b/tests/fail/intrinsics/simd-div-overflow.stderr index b5e8e378a0ab0..98a3c15162708 100644 --- a/tests/fail/intrinsics/simd-div-overflow.stderr +++ b/tests/fail/intrinsics/simd-div-overflow.stderr @@ -6,7 +6,7 @@ LL | simd_div(x, y); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/simd-div-overflow.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/simd-float-to-int.stderr b/tests/fail/intrinsics/simd-float-to-int.stderr index cfe272d90a1fc..233074105b2b9 100644 --- a/tests/fail/intrinsics/simd-float-to-int.stderr +++ b/tests/fail/intrinsics/simd-float-to-int.stderr @@ -6,7 +6,7 @@ LL | implement! { f32 } | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `core::core_simd::round::>::to_int_unchecked::` at RUSTLIB/core/src/../../portable-simd/crates/core_simd/src/round.rs:LL:CC note: inside `main` at $DIR/simd-float-to-int.rs:LL:CC --> $DIR/simd-float-to-int.rs:LL:CC diff --git a/tests/fail/intrinsics/simd-gather.stderr b/tests/fail/intrinsics/simd-gather.stderr index 0464e67f80c65..6b935bc6e2549 100644 --- a/tests/fail/intrinsics/simd-gather.stderr +++ b/tests/fail/intrinsics/simd-gather.stderr @@ -6,7 +6,7 @@ LL | unsafe { intrinsics::simd_gather(or, ptrs, enable.to_int()) } | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `std::simd::Simd::::gather_select_unchecked` at RUSTLIB/core/src/../../portable-simd/crates/core_simd/src/vector.rs:LL:CC note: inside `main` at $DIR/simd-gather.rs:LL:CC --> $DIR/simd-gather.rs:LL:CC diff --git a/tests/fail/intrinsics/simd-reduce-invalid-bool.stderr b/tests/fail/intrinsics/simd-reduce-invalid-bool.stderr index 15c39500d4cb0..5a44861feee1c 100644 --- a/tests/fail/intrinsics/simd-reduce-invalid-bool.stderr +++ b/tests/fail/intrinsics/simd-reduce-invalid-bool.stderr @@ -6,7 +6,7 @@ LL | simd_reduce_any(x); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/simd-reduce-invalid-bool.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/simd-rem-by-zero.stderr b/tests/fail/intrinsics/simd-rem-by-zero.stderr index 1adc9f8235eef..dd68d3aa18406 100644 --- a/tests/fail/intrinsics/simd-rem-by-zero.stderr +++ b/tests/fail/intrinsics/simd-rem-by-zero.stderr @@ -6,7 +6,7 @@ LL | simd_rem(x, y); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/simd-rem-by-zero.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/simd-scatter.stderr b/tests/fail/intrinsics/simd-scatter.stderr index bc6a06fc88e52..24fc6782f1493 100644 --- a/tests/fail/intrinsics/simd-scatter.stderr +++ b/tests/fail/intrinsics/simd-scatter.stderr @@ -6,7 +6,7 @@ LL | intrinsics::simd_scatter(self, ptrs, enable.to_int()) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `std::simd::Simd::::scatter_select_unchecked` at RUSTLIB/core/src/../../portable-simd/crates/core_simd/src/vector.rs:LL:CC note: inside `main` at $DIR/simd-scatter.rs:LL:CC --> $DIR/simd-scatter.rs:LL:CC diff --git a/tests/fail/intrinsics/simd-select-bitmask-invalid.stderr b/tests/fail/intrinsics/simd-select-bitmask-invalid.stderr index 0a72ed39827b2..7b3b3292ef78a 100644 --- a/tests/fail/intrinsics/simd-select-bitmask-invalid.stderr +++ b/tests/fail/intrinsics/simd-select-bitmask-invalid.stderr @@ -6,7 +6,7 @@ LL | simd_select_bitmask(0b11111111u8, x, x); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/simd-select-bitmask-invalid.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/simd-select-invalid-bool.stderr b/tests/fail/intrinsics/simd-select-invalid-bool.stderr index c0ceaac06cddf..ad5a89310681f 100644 --- a/tests/fail/intrinsics/simd-select-invalid-bool.stderr +++ b/tests/fail/intrinsics/simd-select-invalid-bool.stderr @@ -6,7 +6,7 @@ LL | simd_select(x, x, x); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/simd-select-invalid-bool.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/simd-shl-too-far.stderr b/tests/fail/intrinsics/simd-shl-too-far.stderr index 1d990e341e68d..cea99f681932f 100644 --- a/tests/fail/intrinsics/simd-shl-too-far.stderr +++ b/tests/fail/intrinsics/simd-shl-too-far.stderr @@ -6,7 +6,7 @@ LL | simd_shl(x, y); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/simd-shl-too-far.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/simd-shr-too-far.stderr b/tests/fail/intrinsics/simd-shr-too-far.stderr index 58ef3737545aa..df3288a805c8e 100644 --- a/tests/fail/intrinsics/simd-shr-too-far.stderr +++ b/tests/fail/intrinsics/simd-shr-too-far.stderr @@ -6,7 +6,7 @@ LL | simd_shr(x, y); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/simd-shr-too-far.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/unchecked_add1.stderr b/tests/fail/intrinsics/unchecked_add1.stderr index 403bbbac5149f..9d48590593f52 100644 --- a/tests/fail/intrinsics/unchecked_add1.stderr +++ b/tests/fail/intrinsics/unchecked_add1.stderr @@ -6,7 +6,7 @@ LL | std::intrinsics::unchecked_add(40000u16, 30000); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/unchecked_add1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/unchecked_add2.stderr b/tests/fail/intrinsics/unchecked_add2.stderr index 4881fce719e7e..64691932e7120 100644 --- a/tests/fail/intrinsics/unchecked_add2.stderr +++ b/tests/fail/intrinsics/unchecked_add2.stderr @@ -6,7 +6,7 @@ LL | std::intrinsics::unchecked_add(-30000i16, -8000); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/unchecked_add2.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/unchecked_div1.stderr b/tests/fail/intrinsics/unchecked_div1.stderr index 4792608961d3d..867c8e0a9d398 100644 --- a/tests/fail/intrinsics/unchecked_div1.stderr +++ b/tests/fail/intrinsics/unchecked_div1.stderr @@ -6,7 +6,7 @@ LL | std::intrinsics::unchecked_div(i16::MIN, -1); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/unchecked_div1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/unchecked_mul1.stderr b/tests/fail/intrinsics/unchecked_mul1.stderr index e94676fdfed79..4d3a45d415757 100644 --- a/tests/fail/intrinsics/unchecked_mul1.stderr +++ b/tests/fail/intrinsics/unchecked_mul1.stderr @@ -6,7 +6,7 @@ LL | std::intrinsics::unchecked_mul(300u16, 250u16); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/unchecked_mul1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/unchecked_mul2.stderr b/tests/fail/intrinsics/unchecked_mul2.stderr index 493e04e46634d..b64ef116be45d 100644 --- a/tests/fail/intrinsics/unchecked_mul2.stderr +++ b/tests/fail/intrinsics/unchecked_mul2.stderr @@ -6,7 +6,7 @@ LL | std::intrinsics::unchecked_mul(1_000_000_000i32, -4); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/unchecked_mul2.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/unchecked_sub1.stderr b/tests/fail/intrinsics/unchecked_sub1.stderr index 838005dc1e31d..8454382777a02 100644 --- a/tests/fail/intrinsics/unchecked_sub1.stderr +++ b/tests/fail/intrinsics/unchecked_sub1.stderr @@ -6,7 +6,7 @@ LL | std::intrinsics::unchecked_sub(14u32, 22); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/unchecked_sub1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/unchecked_sub2.stderr b/tests/fail/intrinsics/unchecked_sub2.stderr index dc4b170198797..2e6fc2e0b64f5 100644 --- a/tests/fail/intrinsics/unchecked_sub2.stderr +++ b/tests/fail/intrinsics/unchecked_sub2.stderr @@ -6,7 +6,7 @@ LL | std::intrinsics::unchecked_sub(30000i16, -7000); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/unchecked_sub2.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/write_bytes_null.stderr b/tests/fail/intrinsics/write_bytes_null.stderr index 77f675e8fb629..8e8156531b16a 100644 --- a/tests/fail/intrinsics/write_bytes_null.stderr +++ b/tests/fail/intrinsics/write_bytes_null.stderr @@ -6,7 +6,7 @@ LL | unsafe { write_bytes::(std::ptr::null_mut(), 0, 0) }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/write_bytes_null.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/write_bytes_overflow.stderr b/tests/fail/intrinsics/write_bytes_overflow.stderr index 0d5259dce2f4c..1e5381279529f 100644 --- a/tests/fail/intrinsics/write_bytes_overflow.stderr +++ b/tests/fail/intrinsics/write_bytes_overflow.stderr @@ -6,7 +6,7 @@ LL | write_bytes(dst, val, count) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `std::intrinsics::write_bytes::` at RUSTLIB/core/src/intrinsics.rs:LL:CC = note: inside `std::ptr::mut_ptr::::write_bytes` at RUSTLIB/core/src/ptr/mut_ptr.rs:LL:CC note: inside `main` at $DIR/write_bytes_overflow.rs:LL:CC diff --git a/tests/fail/invalid_bool.stderr b/tests/fail/invalid_bool.stderr index 23c5365618b8d..26cd41bdca3aa 100644 --- a/tests/fail/invalid_bool.stderr +++ b/tests/fail/invalid_bool.stderr @@ -6,7 +6,7 @@ LL | let _x = b == std::hint::black_box(true); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/invalid_bool.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/invalid_char.stderr b/tests/fail/invalid_char.stderr index 69f3ef1f4a6da..d605ae44750b7 100644 --- a/tests/fail/invalid_char.stderr +++ b/tests/fail/invalid_char.stderr @@ -6,7 +6,7 @@ LL | let _x = c == 'x'; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/invalid_char.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/invalid_enum_tag.stderr b/tests/fail/invalid_enum_tag.stderr index b5e93d320a861..2f5a4541129c9 100644 --- a/tests/fail/invalid_enum_tag.stderr +++ b/tests/fail/invalid_enum_tag.stderr @@ -6,7 +6,7 @@ LL | Discriminant(intrinsics::discriminant_value(v)) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `std::mem::discriminant::` at RUSTLIB/core/src/mem/mod.rs:LL:CC note: inside `main` at $DIR/invalid_enum_tag.rs:LL:CC --> $DIR/invalid_enum_tag.rs:LL:CC diff --git a/tests/fail/invalid_int.stderr b/tests/fail/invalid_int.stderr index cd7919444f0a9..85aa3fb5a08bc 100644 --- a/tests/fail/invalid_int.stderr +++ b/tests/fail/invalid_int.stderr @@ -6,7 +6,7 @@ LL | let _x = i + 0; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/invalid_int.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/issue-miri-1112.stderr b/tests/fail/issue-miri-1112.stderr index cf692bddaf44d..89dc8dc327f82 100644 --- a/tests/fail/issue-miri-1112.stderr +++ b/tests/fail/issue-miri-1112.stderr @@ -6,7 +6,7 @@ LL | let obj = std::mem::transmute::(obj) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `FunnyPointer::from_data_ptr` at $DIR/issue-miri-1112.rs:LL:CC note: inside `main` at $DIR/issue-miri-1112.rs:LL:CC --> $DIR/issue-miri-1112.rs:LL:CC diff --git a/tests/fail/modifying_constants.stderr b/tests/fail/modifying_constants.stderr index 995011482323d..853e3a9015e7b 100644 --- a/tests/fail/modifying_constants.stderr +++ b/tests/fail/modifying_constants.stderr @@ -6,7 +6,7 @@ LL | *y = 42; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/modifying_constants.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/never_say_never.stderr b/tests/fail/never_say_never.stderr index 22ad10f131035..4072a0376f5c7 100644 --- a/tests/fail/never_say_never.stderr +++ b/tests/fail/never_say_never.stderr @@ -6,7 +6,7 @@ LL | *(y as *const _ as *const !) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/never_say_never.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/never_transmute_humans.stderr b/tests/fail/never_transmute_humans.stderr index 6d8fa37e98ef9..2a8ee0a3e9bd1 100644 --- a/tests/fail/never_transmute_humans.stderr +++ b/tests/fail/never_transmute_humans.stderr @@ -6,7 +6,7 @@ LL | std::mem::transmute::(Human) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/never_transmute_humans.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/never_transmute_void.stderr b/tests/fail/never_transmute_void.stderr index 8d8a4d0e832f9..31614ef3edf88 100644 --- a/tests/fail/never_transmute_void.stderr +++ b/tests/fail/never_transmute_void.stderr @@ -6,7 +6,7 @@ LL | match v.0 {} | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `m::f` at $DIR/never_transmute_void.rs:LL:CC note: inside `main` at $DIR/never_transmute_void.rs:LL:CC --> $DIR/never_transmute_void.rs:LL:CC diff --git a/tests/fail/panic/bad_miri_start_panic.stderr b/tests/fail/panic/bad_miri_start_panic.stderr index dca5d39b7665e..a664590e36ae1 100644 --- a/tests/fail/panic/bad_miri_start_panic.stderr +++ b/tests/fail/panic/bad_miri_start_panic.stderr @@ -6,7 +6,7 @@ LL | unsafe { miri_start_panic(&mut 0) } | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/bad_miri_start_panic.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/panic/bad_unwind.stderr b/tests/fail/panic/bad_unwind.stderr index 745cef8be702c..be8a3668ac522 100644 --- a/tests/fail/panic/bad_unwind.stderr +++ b/tests/fail/panic/bad_unwind.stderr @@ -8,7 +8,7 @@ LL | std::panic::catch_unwind(|| unwind()).unwrap_err(); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside closure at $DIR/bad_unwind.rs:LL:CC = note: inside `std::panicking::r#try::do_call::<[closure@$DIR/bad_unwind.rs:LL:CC], ()>` at RUSTLIB/std/src/panicking.rs:LL:CC = note: inside `std::panicking::r#try::<(), [closure@$DIR/bad_unwind.rs:LL:CC]>` at RUSTLIB/std/src/panicking.rs:LL:CC diff --git a/tests/fail/panic/unwind_panic_abort.stderr b/tests/fail/panic/unwind_panic_abort.stderr index 7094aebd6131c..df4b9522f4671 100644 --- a/tests/fail/panic/unwind_panic_abort.stderr +++ b/tests/fail/panic/unwind_panic_abort.stderr @@ -6,7 +6,7 @@ LL | miri_start_panic(&mut 0); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/unwind_panic_abort.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/pointer_partial_overwrite.stderr b/tests/fail/pointer_partial_overwrite.stderr index 6779df99c3fbf..cd3c4ddd6ca43 100644 --- a/tests/fail/pointer_partial_overwrite.stderr +++ b/tests/fail/pointer_partial_overwrite.stderr @@ -6,7 +6,7 @@ LL | let x = *p; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/pointer_partial_overwrite.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/provenance/provenance_transmute.stderr b/tests/fail/provenance/provenance_transmute.stderr index 9cbec077e42c0..ddbf64f383806 100644 --- a/tests/fail/provenance/provenance_transmute.stderr +++ b/tests/fail/provenance/provenance_transmute.stderr @@ -6,7 +6,7 @@ LL | let _val = *left_ptr; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `deref` at $DIR/provenance_transmute.rs:LL:CC note: inside `main` at $DIR/provenance_transmute.rs:LL:CC --> $DIR/provenance_transmute.rs:LL:CC diff --git a/tests/fail/provenance/ptr_int_unexposed.stderr b/tests/fail/provenance/ptr_int_unexposed.stderr index cdd25d0e638ef..f0c47e54859ee 100644 --- a/tests/fail/provenance/ptr_int_unexposed.stderr +++ b/tests/fail/provenance/ptr_int_unexposed.stderr @@ -6,7 +6,7 @@ LL | assert_eq!(unsafe { *ptr }, 3); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/ptr_int_unexposed.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/provenance/ptr_invalid.stderr b/tests/fail/provenance/ptr_invalid.stderr index 76a40765eb2ff..0d6c0f92d93bb 100644 --- a/tests/fail/provenance/ptr_invalid.stderr +++ b/tests/fail/provenance/ptr_invalid.stderr @@ -6,7 +6,7 @@ LL | let _val = unsafe { *xptr_invalid }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/ptr_invalid.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/provenance/ptr_invalid_offset.stderr b/tests/fail/provenance/ptr_invalid_offset.stderr index 661fabf29afbf..8f19d4ec93580 100644 --- a/tests/fail/provenance/ptr_invalid_offset.stderr +++ b/tests/fail/provenance/ptr_invalid_offset.stderr @@ -6,7 +6,7 @@ LL | unsafe { intrinsics::offset(self, count) } | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `std::ptr::const_ptr::::offset` at RUSTLIB/core/src/ptr/const_ptr.rs:LL:CC note: inside `main` at $DIR/ptr_invalid_offset.rs:LL:CC --> $DIR/ptr_invalid_offset.rs:LL:CC diff --git a/tests/fail/provenance/strict_provenance_cast.stderr b/tests/fail/provenance/strict_provenance_cast.stderr index ab64f2bb288ea..ff6ab1c9e95bf 100644 --- a/tests/fail/provenance/strict_provenance_cast.stderr +++ b/tests/fail/provenance/strict_provenance_cast.stderr @@ -5,7 +5,7 @@ LL | let _ptr = addr as *const i32; | ^^^^^^^^^^^^^^^^^^ integer-to-pointer casts and `ptr::from_exposed_addr` are not supported with `-Zmiri-strict-provenance` | = help: use Strict Provenance APIs (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance, https://crates.io/crates/sptr) instead - + = note: backtrace: = note: inside `main` at $DIR/strict_provenance_cast.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/rc_as_ptr.stderr b/tests/fail/rc_as_ptr.stderr index d4864da04e41f..f2dd245be3458 100644 --- a/tests/fail/rc_as_ptr.stderr +++ b/tests/fail/rc_as_ptr.stderr @@ -6,7 +6,7 @@ LL | assert_eq!(42, **unsafe { &*Weak::as_ptr(&weak) }); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at RUSTLIB/core/src/macros/mod.rs:LL:CC = note: this error originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/fail/reading_half_a_pointer.stderr b/tests/fail/reading_half_a_pointer.stderr index 505c8deafb6d5..d6690f0c7a012 100644 --- a/tests/fail/reading_half_a_pointer.stderr +++ b/tests/fail/reading_half_a_pointer.stderr @@ -5,7 +5,7 @@ LL | let _x = *d_alias; | ^^^^^^^^ unable to turn pointer into raw bytes | = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support - + = note: backtrace: = note: inside `main` at $DIR/reading_half_a_pointer.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/shim_arg_size.32bit.stderr b/tests/fail/shim_arg_size.32bit.stderr index 3b54a5b512481..84b09acbac3dc 100644 --- a/tests/fail/shim_arg_size.32bit.stderr +++ b/tests/fail/shim_arg_size.32bit.stderr @@ -6,7 +6,7 @@ LL | let _p1 = malloc(42); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/shim_arg_size.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/shim_arg_size.64bit.stderr b/tests/fail/shim_arg_size.64bit.stderr index 5e33604c121d6..98ed99d6d729e 100644 --- a/tests/fail/shim_arg_size.64bit.stderr +++ b/tests/fail/shim_arg_size.64bit.stderr @@ -6,7 +6,7 @@ LL | let _p1 = malloc(42); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/shim_arg_size.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/should-pass/cpp20_rwc_syncs.stderr b/tests/fail/should-pass/cpp20_rwc_syncs.stderr index 5f0e86dc653ec..0ab02687e2aef 100644 --- a/tests/fail/should-pass/cpp20_rwc_syncs.stderr +++ b/tests/fail/should-pass/cpp20_rwc_syncs.stderr @@ -6,7 +6,7 @@ LL | unsafe { intrinsics::unreachable() } | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `std::hint::unreachable_unchecked` at RUSTLIB/core/src/hint.rs:LL:CC note: inside `test_cpp20_rwc_syncs` at $DIR/cpp20_rwc_syncs.rs:LL:CC --> $DIR/cpp20_rwc_syncs.rs:LL:CC diff --git a/tests/fail/stacked_borrows/alias_through_mutation.stderr b/tests/fail/stacked_borrows/alias_through_mutation.stderr index eb02136478f2b..ec985cb26a996 100644 --- a/tests/fail/stacked_borrows/alias_through_mutation.stderr +++ b/tests/fail/stacked_borrows/alias_through_mutation.stderr @@ -19,6 +19,7 @@ help: was later invalidated at offsets [0x0..0x4] | LL | *target = 13; | ^^^^^^^^^^^^ + = note: backtrace: = note: inside `main` at $DIR/alias_through_mutation.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/aliasing_mut1.stderr b/tests/fail/stacked_borrows/aliasing_mut1.stderr index 7282612b6fc39..34a53aa8f307a 100644 --- a/tests/fail/stacked_borrows/aliasing_mut1.stderr +++ b/tests/fail/stacked_borrows/aliasing_mut1.stderr @@ -21,6 +21,7 @@ help: this protector is live for this call | LL | pub fn safe(_x: &mut i32, _y: &mut i32) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: backtrace: = note: inside `safe` at $DIR/aliasing_mut1.rs:LL:CC note: inside `main` at $DIR/aliasing_mut1.rs:LL:CC --> $DIR/aliasing_mut1.rs:LL:CC diff --git a/tests/fail/stacked_borrows/aliasing_mut2.stderr b/tests/fail/stacked_borrows/aliasing_mut2.stderr index d314fff6222e3..7830648ee8f3c 100644 --- a/tests/fail/stacked_borrows/aliasing_mut2.stderr +++ b/tests/fail/stacked_borrows/aliasing_mut2.stderr @@ -21,6 +21,7 @@ help: this protector is live for this call | LL | pub fn safe(_x: &i32, _y: &mut i32) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: backtrace: = note: inside `safe` at $DIR/aliasing_mut2.rs:LL:CC note: inside `main` at $DIR/aliasing_mut2.rs:LL:CC --> $DIR/aliasing_mut2.rs:LL:CC diff --git a/tests/fail/stacked_borrows/aliasing_mut3.stderr b/tests/fail/stacked_borrows/aliasing_mut3.stderr index 66220cfbfc4d3..8e489b738657a 100644 --- a/tests/fail/stacked_borrows/aliasing_mut3.stderr +++ b/tests/fail/stacked_borrows/aliasing_mut3.stderr @@ -19,6 +19,7 @@ help: was later invalidated at offsets [0x0..0x4] | LL | pub fn safe(_x: &mut i32, _y: &i32) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: backtrace: = note: inside `safe` at $DIR/aliasing_mut3.rs:LL:CC note: inside `main` at $DIR/aliasing_mut3.rs:LL:CC --> $DIR/aliasing_mut3.rs:LL:CC diff --git a/tests/fail/stacked_borrows/aliasing_mut4.stderr b/tests/fail/stacked_borrows/aliasing_mut4.stderr index 0bf5e863bfa33..f62ce1e519649 100644 --- a/tests/fail/stacked_borrows/aliasing_mut4.stderr +++ b/tests/fail/stacked_borrows/aliasing_mut4.stderr @@ -21,6 +21,7 @@ help: this protector is live for this call | LL | pub fn safe(_x: &i32, _y: &mut Cell) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: backtrace: = note: inside `safe` at $DIR/aliasing_mut4.rs:LL:CC note: inside `main` at $DIR/aliasing_mut4.rs:LL:CC --> $DIR/aliasing_mut4.rs:LL:CC diff --git a/tests/fail/stacked_borrows/box_exclusive_violation1.stderr b/tests/fail/stacked_borrows/box_exclusive_violation1.stderr index 06c2dc340b7ba..88ecca87962d5 100644 --- a/tests/fail/stacked_borrows/box_exclusive_violation1.stderr +++ b/tests/fail/stacked_borrows/box_exclusive_violation1.stderr @@ -19,6 +19,7 @@ help: was later invalidated at offsets [0x0..0x4] | LL | *our = 5; | ^^^^^^^^ + = note: backtrace: = note: inside `unknown_code_2` at $DIR/box_exclusive_violation1.rs:LL:CC note: inside `demo_mut_advanced_unique` at $DIR/box_exclusive_violation1.rs:LL:CC --> $DIR/box_exclusive_violation1.rs:LL:CC diff --git a/tests/fail/stacked_borrows/buggy_as_mut_slice.stderr b/tests/fail/stacked_borrows/buggy_as_mut_slice.stderr index 14cede13b7a18..6e78ed6c72983 100644 --- a/tests/fail/stacked_borrows/buggy_as_mut_slice.stderr +++ b/tests/fail/stacked_borrows/buggy_as_mut_slice.stderr @@ -19,6 +19,7 @@ help: was later invalidated at offsets [0x0..0xc] | LL | unsafe { from_raw_parts_mut(self_.as_ptr() as *mut T, self_.len()) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: backtrace: = note: inside `main` at $DIR/buggy_as_mut_slice.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/buggy_split_at_mut.stderr b/tests/fail/stacked_borrows/buggy_split_at_mut.stderr index 47ab7d6a062a7..6e6dc38aaf061 100644 --- a/tests/fail/stacked_borrows/buggy_split_at_mut.stderr +++ b/tests/fail/stacked_borrows/buggy_split_at_mut.stderr @@ -19,6 +19,7 @@ help: was later invalidated at offsets [0x0..0x10] | LL | from_raw_parts_mut(ptr.offset(mid as isize), len - mid), | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: backtrace: = note: inside `main` at $DIR/buggy_split_at_mut.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/deallocate_against_barrier1.stderr b/tests/fail/stacked_borrows/deallocate_against_barrier1.stderr index 58032fa35a1d5..c3ea7a437cdb1 100644 --- a/tests/fail/stacked_borrows/deallocate_against_barrier1.stderr +++ b/tests/fail/stacked_borrows/deallocate_against_barrier1.stderr @@ -6,7 +6,7 @@ LL | unsafe { __rust_dealloc(ptr, layout.size(), layout.align()) } | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information - + = note: backtrace: = note: inside `std::alloc::dealloc` at RUSTLIB/alloc/src/alloc.rs:LL:CC = note: inside `::deallocate` at RUSTLIB/alloc/src/alloc.rs:LL:CC = note: inside `alloc::alloc::box_free::` at RUSTLIB/alloc/src/alloc.rs:LL:CC diff --git a/tests/fail/stacked_borrows/deallocate_against_barrier2.stderr b/tests/fail/stacked_borrows/deallocate_against_barrier2.stderr index 22776656e0199..d6c31e0649ec3 100644 --- a/tests/fail/stacked_borrows/deallocate_against_barrier2.stderr +++ b/tests/fail/stacked_borrows/deallocate_against_barrier2.stderr @@ -6,7 +6,7 @@ LL | unsafe { __rust_dealloc(ptr, layout.size(), layout.align()) } | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information - + = note: backtrace: = note: inside `std::alloc::dealloc` at RUSTLIB/alloc/src/alloc.rs:LL:CC = note: inside `::deallocate` at RUSTLIB/alloc/src/alloc.rs:LL:CC = note: inside `alloc::alloc::box_free::` at RUSTLIB/alloc/src/alloc.rs:LL:CC diff --git a/tests/fail/stacked_borrows/exposed_only_ro.stderr b/tests/fail/stacked_borrows/exposed_only_ro.stderr index 28fa98b6020c0..af76183fb25da 100644 --- a/tests/fail/stacked_borrows/exposed_only_ro.stderr +++ b/tests/fail/stacked_borrows/exposed_only_ro.stderr @@ -9,7 +9,7 @@ LL | unsafe { *ptr = 0 }; | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information - + = note: backtrace: = note: inside `main` at $DIR/exposed_only_ro.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/illegal_read1.stderr b/tests/fail/stacked_borrows/illegal_read1.stderr index bf78c62a0e799..3f4ade9a712f0 100644 --- a/tests/fail/stacked_borrows/illegal_read1.stderr +++ b/tests/fail/stacked_borrows/illegal_read1.stderr @@ -19,6 +19,7 @@ help: was later invalidated at offsets [0x0..0x4] | LL | let _val = unsafe { *xraw }; | ^^^^^ + = note: backtrace: = note: inside `main` at $DIR/illegal_read1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/illegal_read2.stderr b/tests/fail/stacked_borrows/illegal_read2.stderr index b0bc3f9a7f0d3..cb0ac56027828 100644 --- a/tests/fail/stacked_borrows/illegal_read2.stderr +++ b/tests/fail/stacked_borrows/illegal_read2.stderr @@ -19,6 +19,7 @@ help: was later invalidated at offsets [0x0..0x4] | LL | let shr = unsafe { &*xraw }; | ^^^^^^ + = note: backtrace: = note: inside `main` at $DIR/illegal_read2.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/illegal_read3.stderr b/tests/fail/stacked_borrows/illegal_read3.stderr index 34580dec4ee4f..bdeca5f7ec86e 100644 --- a/tests/fail/stacked_borrows/illegal_read3.stderr +++ b/tests/fail/stacked_borrows/illegal_read3.stderr @@ -19,6 +19,7 @@ help: was later invalidated at offsets [0x0..0x4] | LL | let _val = unsafe { *xref1.r }; | ^^^^^^^^ + = note: backtrace: = note: inside `main` at $DIR/illegal_read3.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/illegal_read4.stderr b/tests/fail/stacked_borrows/illegal_read4.stderr index 19c361a19542a..59c2088c0c85d 100644 --- a/tests/fail/stacked_borrows/illegal_read4.stderr +++ b/tests/fail/stacked_borrows/illegal_read4.stderr @@ -19,6 +19,7 @@ help: was later invalidated at offsets [0x0..0x4] | LL | let _val = unsafe { *xraw }; // use the raw again, this invalidates xref2 *even* with the special read except for uniq refs | ^^^^^ + = note: backtrace: = note: inside `main` at $DIR/illegal_read4.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/illegal_read5.stderr b/tests/fail/stacked_borrows/illegal_read5.stderr index 4af149e3831ed..d1506f1996847 100644 --- a/tests/fail/stacked_borrows/illegal_read5.stderr +++ b/tests/fail/stacked_borrows/illegal_read5.stderr @@ -19,6 +19,7 @@ help: was later invalidated at offsets [$HEX..$HEX] | LL | mem::forget(unsafe { ptr::read(xshr) }); // but after reading through the shared ref | ^^^^^^^^^^^^^^^ + = note: backtrace: = note: inside `main` at $DIR/illegal_read5.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/illegal_read6.stderr b/tests/fail/stacked_borrows/illegal_read6.stderr index 2098dbdc6a492..5abea6f611a40 100644 --- a/tests/fail/stacked_borrows/illegal_read6.stderr +++ b/tests/fail/stacked_borrows/illegal_read6.stderr @@ -19,6 +19,7 @@ help: was later invalidated at offsets [0x0..0x4] | LL | let x = &mut *x; // kill `raw` | ^^^^^^^ + = note: backtrace: = note: inside `main` at $DIR/illegal_read6.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/illegal_read7.stderr b/tests/fail/stacked_borrows/illegal_read7.stderr index 3d70945fa6c63..56ebd93918bf3 100644 --- a/tests/fail/stacked_borrows/illegal_read7.stderr +++ b/tests/fail/stacked_borrows/illegal_read7.stderr @@ -19,6 +19,7 @@ help: was later invalidated at offsets [0x0..0x4] | LL | let _val = ptr::read(raw); | ^^^^^^^^^^^^^^ + = note: backtrace: = note: inside `main` at $DIR/illegal_read7.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/illegal_read8.stderr b/tests/fail/stacked_borrows/illegal_read8.stderr index 7c0cb0066b270..ef150e84f274e 100644 --- a/tests/fail/stacked_borrows/illegal_read8.stderr +++ b/tests/fail/stacked_borrows/illegal_read8.stderr @@ -19,6 +19,7 @@ help: was later invalidated at offsets [0x0..0x4] | LL | *y2 += 1; | ^^^^^^^^ + = note: backtrace: = note: inside `main` at $DIR/illegal_read8.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/illegal_read_despite_exposed1.stderr b/tests/fail/stacked_borrows/illegal_read_despite_exposed1.stderr index fde135f752f78..7c77c62575d70 100644 --- a/tests/fail/stacked_borrows/illegal_read_despite_exposed1.stderr +++ b/tests/fail/stacked_borrows/illegal_read_despite_exposed1.stderr @@ -9,7 +9,7 @@ LL | let _val = *root2; | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information - + = note: backtrace: = note: inside `main` at $DIR/illegal_read_despite_exposed1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/illegal_read_despite_exposed2.stderr b/tests/fail/stacked_borrows/illegal_read_despite_exposed2.stderr index 947d9fd70a0d2..4fbbd4c6bedeb 100644 --- a/tests/fail/stacked_borrows/illegal_read_despite_exposed2.stderr +++ b/tests/fail/stacked_borrows/illegal_read_despite_exposed2.stderr @@ -9,7 +9,7 @@ LL | let _val = *root2; | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information - + = note: backtrace: = note: inside `main` at $DIR/illegal_read_despite_exposed2.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/illegal_write1.stderr b/tests/fail/stacked_borrows/illegal_write1.stderr index b2084da862fe0..f939720516922 100644 --- a/tests/fail/stacked_borrows/illegal_write1.stderr +++ b/tests/fail/stacked_borrows/illegal_write1.stderr @@ -14,6 +14,7 @@ help: was created by a retag at offsets [0x0..0x4] | LL | let x: *mut u32 = xref as *const _ as *mut _; | ^^^^ + = note: backtrace: = note: inside `main` at $DIR/illegal_write1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/illegal_write2.stderr b/tests/fail/stacked_borrows/illegal_write2.stderr index 09784bd79a188..92dacf214f8c2 100644 --- a/tests/fail/stacked_borrows/illegal_write2.stderr +++ b/tests/fail/stacked_borrows/illegal_write2.stderr @@ -19,6 +19,7 @@ help: was later invalidated at offsets [0x0..0x4] | LL | drop(&mut *target); // reborrow | ^^^^^^^^^^^^ + = note: backtrace: = note: inside `main` at $DIR/illegal_write2.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/illegal_write3.stderr b/tests/fail/stacked_borrows/illegal_write3.stderr index 983894dad065c..bb6d189f85205 100644 --- a/tests/fail/stacked_borrows/illegal_write3.stderr +++ b/tests/fail/stacked_borrows/illegal_write3.stderr @@ -14,6 +14,7 @@ help: was created by a retag at offsets [0x0..0x4] | LL | let ptr = r#ref as *const _ as *mut _; // raw ptr, with raw tag | ^^^^^ + = note: backtrace: = note: inside `main` at $DIR/illegal_write3.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/illegal_write4.stderr b/tests/fail/stacked_borrows/illegal_write4.stderr index ac4dd68bbc7e4..97301d64deb3f 100644 --- a/tests/fail/stacked_borrows/illegal_write4.stderr +++ b/tests/fail/stacked_borrows/illegal_write4.stderr @@ -19,6 +19,7 @@ help: was later invalidated at offsets [0x0..0x4] | LL | let _mut_ref: &mut i32 = unsafe { mem::transmute(raw) }; // &mut, with raw tag | ^^^^^^^^^^^^^^^^^^^ + = note: backtrace: = note: inside `main` at $DIR/illegal_write4.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/illegal_write5.stderr b/tests/fail/stacked_borrows/illegal_write5.stderr index b119908145654..9cb32d7bdfd1c 100644 --- a/tests/fail/stacked_borrows/illegal_write5.stderr +++ b/tests/fail/stacked_borrows/illegal_write5.stderr @@ -19,6 +19,7 @@ help: was later invalidated at offsets [0x0..0x4] | LL | unsafe { *xraw = 15 }; | ^^^^^^^^^^ + = note: backtrace: = note: inside `main` at $DIR/illegal_write5.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/illegal_write6.stderr b/tests/fail/stacked_borrows/illegal_write6.stderr index 563397e062d59..cbf4a22f23f27 100644 --- a/tests/fail/stacked_borrows/illegal_write6.stderr +++ b/tests/fail/stacked_borrows/illegal_write6.stderr @@ -26,6 +26,7 @@ LL | | unsafe { *y = 2 }; LL | | return *a; LL | | } | |_^ + = note: backtrace: = note: inside `foo` at $DIR/illegal_write6.rs:LL:CC note: inside `main` at $DIR/illegal_write6.rs:LL:CC --> $DIR/illegal_write6.rs:LL:CC diff --git a/tests/fail/stacked_borrows/illegal_write_despite_exposed1.stderr b/tests/fail/stacked_borrows/illegal_write_despite_exposed1.stderr index ac96c9dac8d84..0f5834077b3d8 100644 --- a/tests/fail/stacked_borrows/illegal_write_despite_exposed1.stderr +++ b/tests/fail/stacked_borrows/illegal_write_despite_exposed1.stderr @@ -9,7 +9,7 @@ LL | let _val = *root2; | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information - + = note: backtrace: = note: inside `main` at $DIR/illegal_write_despite_exposed1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/interior_mut1.stderr b/tests/fail/stacked_borrows/interior_mut1.stderr index 2490fd3e1e9aa..73be074ce91a7 100644 --- a/tests/fail/stacked_borrows/interior_mut1.stderr +++ b/tests/fail/stacked_borrows/interior_mut1.stderr @@ -19,6 +19,7 @@ help: was later invalidated at offsets [0x0..0x4] | LL | *c.get() = UnsafeCell::new(1); // invalidates inner_shr | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: backtrace: = note: inside `main` at $DIR/interior_mut1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/interior_mut2.stderr b/tests/fail/stacked_borrows/interior_mut2.stderr index 33060a7818ff0..74e91d49c418d 100644 --- a/tests/fail/stacked_borrows/interior_mut2.stderr +++ b/tests/fail/stacked_borrows/interior_mut2.stderr @@ -19,6 +19,7 @@ help: was later invalidated at offsets [0x0..0x4] | LL | *c.get() = UnsafeCell::new(0); // now inner_shr gets invalidated | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: backtrace: = note: inside `main` at $DIR/interior_mut2.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/invalidate_against_barrier1.stderr b/tests/fail/stacked_borrows/invalidate_against_barrier1.stderr index 826cdc9b5f8e6..5f54134a24315 100644 --- a/tests/fail/stacked_borrows/invalidate_against_barrier1.stderr +++ b/tests/fail/stacked_borrows/invalidate_against_barrier1.stderr @@ -26,6 +26,7 @@ LL | | // unique for the duration of this call. LL | | let _val = unsafe { *x }; LL | | } | |_^ + = note: backtrace: = note: inside `inner` at $DIR/invalidate_against_barrier1.rs:LL:CC note: inside `main` at $DIR/invalidate_against_barrier1.rs:LL:CC --> $DIR/invalidate_against_barrier1.rs:LL:CC diff --git a/tests/fail/stacked_borrows/invalidate_against_barrier2.stderr b/tests/fail/stacked_borrows/invalidate_against_barrier2.stderr index 1cf90f91db02b..15bc91e869f9d 100644 --- a/tests/fail/stacked_borrows/invalidate_against_barrier2.stderr +++ b/tests/fail/stacked_borrows/invalidate_against_barrier2.stderr @@ -26,6 +26,7 @@ LL | | // immutable for the duration of this call. LL | | unsafe { *x = 0 }; LL | | } | |_^ + = note: backtrace: = note: inside `inner` at $DIR/invalidate_against_barrier2.rs:LL:CC note: inside `main` at $DIR/invalidate_against_barrier2.rs:LL:CC --> $DIR/invalidate_against_barrier2.rs:LL:CC diff --git a/tests/fail/stacked_borrows/issue-miri-1050-1.stderr b/tests/fail/stacked_borrows/issue-miri-1050-1.stderr index c2c471fba8810..8180a60a837af 100644 --- a/tests/fail/stacked_borrows/issue-miri-1050-1.stderr +++ b/tests/fail/stacked_borrows/issue-miri-1050-1.stderr @@ -6,7 +6,7 @@ LL | Box(unsafe { Unique::new_unchecked(raw) }, alloc) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `std::boxed::Box::::from_raw_in` at RUSTLIB/alloc/src/boxed.rs:LL:CC = note: inside `std::boxed::Box::::from_raw` at RUSTLIB/alloc/src/boxed.rs:LL:CC note: inside `main` at $DIR/issue-miri-1050-1.rs:LL:CC diff --git a/tests/fail/stacked_borrows/issue-miri-1050-2.stderr b/tests/fail/stacked_borrows/issue-miri-1050-2.stderr index c49852cb7f4f8..61ce006dc82b9 100644 --- a/tests/fail/stacked_borrows/issue-miri-1050-2.stderr +++ b/tests/fail/stacked_borrows/issue-miri-1050-2.stderr @@ -6,7 +6,7 @@ LL | Box(unsafe { Unique::new_unchecked(raw) }, alloc) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `std::boxed::Box::::from_raw_in` at RUSTLIB/alloc/src/boxed.rs:LL:CC = note: inside `std::boxed::Box::::from_raw` at RUSTLIB/alloc/src/boxed.rs:LL:CC note: inside `main` at $DIR/issue-miri-1050-2.rs:LL:CC diff --git a/tests/fail/stacked_borrows/load_invalid_mut.stderr b/tests/fail/stacked_borrows/load_invalid_mut.stderr index a15900411ce47..293d85cc9f457 100644 --- a/tests/fail/stacked_borrows/load_invalid_mut.stderr +++ b/tests/fail/stacked_borrows/load_invalid_mut.stderr @@ -19,6 +19,7 @@ help: was later invalidated at offsets [0x0..0x4] | LL | let _val = unsafe { *xraw }; // invalidate xref | ^^^^^ + = note: backtrace: = note: inside `main` at $DIR/load_invalid_mut.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/load_invalid_shr.stderr b/tests/fail/stacked_borrows/load_invalid_shr.stderr index 85cb8ef93ebd6..5749daa51fd9f 100644 --- a/tests/fail/stacked_borrows/load_invalid_shr.stderr +++ b/tests/fail/stacked_borrows/load_invalid_shr.stderr @@ -19,6 +19,7 @@ help: was later invalidated at offsets [0x0..0x4] | LL | unsafe { *xraw = 42 }; // unfreeze | ^^^^^^^^^^ + = note: backtrace: = note: inside `main` at $DIR/load_invalid_shr.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/mut_exclusive_violation1.stderr b/tests/fail/stacked_borrows/mut_exclusive_violation1.stderr index 8afb4fee18b51..acc904794fb53 100644 --- a/tests/fail/stacked_borrows/mut_exclusive_violation1.stderr +++ b/tests/fail/stacked_borrows/mut_exclusive_violation1.stderr @@ -19,6 +19,7 @@ help: was later invalidated at offsets [0x0..0x4] | LL | *our = 5; | ^^^^^^^^ + = note: backtrace: = note: inside `unknown_code_2` at $DIR/mut_exclusive_violation1.rs:LL:CC note: inside `demo_mut_advanced_unique` at $DIR/mut_exclusive_violation1.rs:LL:CC --> $DIR/mut_exclusive_violation1.rs:LL:CC diff --git a/tests/fail/stacked_borrows/mut_exclusive_violation2.stderr b/tests/fail/stacked_borrows/mut_exclusive_violation2.stderr index 85baf93613a20..5bbf9bc518472 100644 --- a/tests/fail/stacked_borrows/mut_exclusive_violation2.stderr +++ b/tests/fail/stacked_borrows/mut_exclusive_violation2.stderr @@ -19,6 +19,7 @@ help: was later invalidated at offsets [0x0..0x4] | LL | let _raw2 = ptr2.as_mut(); | ^^^^^^^^^^^^^ + = note: backtrace: = note: inside `main` at $DIR/mut_exclusive_violation2.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/newtype_retagging.stderr b/tests/fail/stacked_borrows/newtype_retagging.stderr index f65231b661f97..860a628492c78 100644 --- a/tests/fail/stacked_borrows/newtype_retagging.stderr +++ b/tests/fail/stacked_borrows/newtype_retagging.stderr @@ -23,6 +23,7 @@ LL | / fn dealloc_while_running(_n: Newtype<'_>, dealloc: impl FnOnce()) { LL | | dealloc(); LL | | } | |_^ + = note: backtrace: = note: inside `std::boxed::Box::::from_raw_in` at RUSTLIB/alloc/src/boxed.rs:LL:CC = note: inside `std::boxed::Box::::from_raw` at RUSTLIB/alloc/src/boxed.rs:LL:CC note: inside closure at $DIR/newtype_retagging.rs:LL:CC diff --git a/tests/fail/stacked_borrows/outdated_local.stderr b/tests/fail/stacked_borrows/outdated_local.stderr index c218d500cf8b8..d2ada64586312 100644 --- a/tests/fail/stacked_borrows/outdated_local.stderr +++ b/tests/fail/stacked_borrows/outdated_local.stderr @@ -19,6 +19,7 @@ help: was later invalidated at offsets [0x0..0x4] | LL | x = 1; // this invalidates y by reactivating the lowermost uniq borrow for this local | ^^^^^ + = note: backtrace: = note: inside `main` at $DIR/outdated_local.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/pass_invalid_mut.stderr b/tests/fail/stacked_borrows/pass_invalid_mut.stderr index 6af914e55f919..933ef1ad5970a 100644 --- a/tests/fail/stacked_borrows/pass_invalid_mut.stderr +++ b/tests/fail/stacked_borrows/pass_invalid_mut.stderr @@ -19,6 +19,7 @@ help: was later invalidated at offsets [0x0..0x4] | LL | let _val = unsafe { *xraw }; // invalidate xref | ^^^^^ + = note: backtrace: = note: inside `main` at $DIR/pass_invalid_mut.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/pass_invalid_shr.stderr b/tests/fail/stacked_borrows/pass_invalid_shr.stderr index d38c582734539..02cf62f033261 100644 --- a/tests/fail/stacked_borrows/pass_invalid_shr.stderr +++ b/tests/fail/stacked_borrows/pass_invalid_shr.stderr @@ -19,6 +19,7 @@ help: was later invalidated at offsets [0x0..0x4] | LL | unsafe { *xraw = 42 }; // unfreeze | ^^^^^^^^^^ + = note: backtrace: = note: inside `main` at $DIR/pass_invalid_shr.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/pointer_smuggling.stderr b/tests/fail/stacked_borrows/pointer_smuggling.stderr index a3ab1b9fc5e5c..66427bdf64d69 100644 --- a/tests/fail/stacked_borrows/pointer_smuggling.stderr +++ b/tests/fail/stacked_borrows/pointer_smuggling.stderr @@ -19,6 +19,7 @@ help: was later invalidated at offsets [0x0..0x1] | LL | *val = 2; // this invalidates any raw ptrs `fun1` might have created. | ^^^^^^^^ + = note: backtrace: = note: inside `fun2` at $DIR/pointer_smuggling.rs:LL:CC note: inside `main` at $DIR/pointer_smuggling.rs:LL:CC --> $DIR/pointer_smuggling.rs:LL:CC diff --git a/tests/fail/stacked_borrows/raw_tracking.stderr b/tests/fail/stacked_borrows/raw_tracking.stderr index d3674893fab8e..2028a91142727 100644 --- a/tests/fail/stacked_borrows/raw_tracking.stderr +++ b/tests/fail/stacked_borrows/raw_tracking.stderr @@ -19,6 +19,7 @@ help: was later invalidated at offsets [0x0..0x4] | LL | let raw2 = &mut l as *mut _; // invalidates raw1 | ^^^^^^ + = note: backtrace: = note: inside `main` at $DIR/raw_tracking.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/return_invalid_mut.stderr b/tests/fail/stacked_borrows/return_invalid_mut.stderr index 876850590e51e..230c3e82ff231 100644 --- a/tests/fail/stacked_borrows/return_invalid_mut.stderr +++ b/tests/fail/stacked_borrows/return_invalid_mut.stderr @@ -19,6 +19,7 @@ help: was later invalidated at offsets [0x0..0x8] | LL | let _val = unsafe { *xraw }; // invalidate xref | ^^^^^ + = note: backtrace: = note: inside `foo` at $DIR/return_invalid_mut.rs:LL:CC note: inside `main` at $DIR/return_invalid_mut.rs:LL:CC --> $DIR/return_invalid_mut.rs:LL:CC diff --git a/tests/fail/stacked_borrows/return_invalid_mut_option.stderr b/tests/fail/stacked_borrows/return_invalid_mut_option.stderr index 4bee128d68a40..f278113e42577 100644 --- a/tests/fail/stacked_borrows/return_invalid_mut_option.stderr +++ b/tests/fail/stacked_borrows/return_invalid_mut_option.stderr @@ -19,6 +19,7 @@ help: was later invalidated at offsets [0x0..0x8] | LL | let _val = unsafe { *xraw }; // invalidate xref | ^^^^^ + = note: backtrace: = note: inside `main` at $DIR/return_invalid_mut_option.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/return_invalid_mut_tuple.stderr b/tests/fail/stacked_borrows/return_invalid_mut_tuple.stderr index 3062d821765a3..9465fd072ea93 100644 --- a/tests/fail/stacked_borrows/return_invalid_mut_tuple.stderr +++ b/tests/fail/stacked_borrows/return_invalid_mut_tuple.stderr @@ -19,6 +19,7 @@ help: was later invalidated at offsets [0x0..0x8] | LL | let _val = unsafe { *xraw }; // invalidate xref | ^^^^^ + = note: backtrace: = note: inside `main` at $DIR/return_invalid_mut_tuple.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/return_invalid_shr.stderr b/tests/fail/stacked_borrows/return_invalid_shr.stderr index aa3f7ddde59e2..75ea8bb89ec0f 100644 --- a/tests/fail/stacked_borrows/return_invalid_shr.stderr +++ b/tests/fail/stacked_borrows/return_invalid_shr.stderr @@ -19,6 +19,7 @@ help: was later invalidated at offsets [0x0..0x8] | LL | unsafe { *xraw = (42, 23) }; // unfreeze | ^^^^^^^^^^^^^^^^ + = note: backtrace: = note: inside `foo` at $DIR/return_invalid_shr.rs:LL:CC note: inside `main` at $DIR/return_invalid_shr.rs:LL:CC --> $DIR/return_invalid_shr.rs:LL:CC diff --git a/tests/fail/stacked_borrows/return_invalid_shr_option.stderr b/tests/fail/stacked_borrows/return_invalid_shr_option.stderr index a23c69d12db16..27656b46ccfcb 100644 --- a/tests/fail/stacked_borrows/return_invalid_shr_option.stderr +++ b/tests/fail/stacked_borrows/return_invalid_shr_option.stderr @@ -19,6 +19,7 @@ help: was later invalidated at offsets [0x0..0x8] | LL | unsafe { *xraw = (42, 23) }; // unfreeze | ^^^^^^^^^^^^^^^^ + = note: backtrace: = note: inside `main` at $DIR/return_invalid_shr_option.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/return_invalid_shr_tuple.stderr b/tests/fail/stacked_borrows/return_invalid_shr_tuple.stderr index 9519f2f6f07b7..9fdc878086514 100644 --- a/tests/fail/stacked_borrows/return_invalid_shr_tuple.stderr +++ b/tests/fail/stacked_borrows/return_invalid_shr_tuple.stderr @@ -19,6 +19,7 @@ help: was later invalidated at offsets [0x0..0x8] | LL | unsafe { *xraw = (42, 23) }; // unfreeze | ^^^^^^^^^^^^^^^^ + = note: backtrace: = note: inside `main` at $DIR/return_invalid_shr_tuple.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/shared_rw_borrows_are_weak1.stderr b/tests/fail/stacked_borrows/shared_rw_borrows_are_weak1.stderr index 151654bad5cfe..9909778ab28ed 100644 --- a/tests/fail/stacked_borrows/shared_rw_borrows_are_weak1.stderr +++ b/tests/fail/stacked_borrows/shared_rw_borrows_are_weak1.stderr @@ -19,6 +19,7 @@ help: was later invalidated at offsets [0x0..0x4] | LL | shr_rw.set(1); | ^^^^^^^^^^^^^ + = note: backtrace: = note: inside `main` at $DIR/shared_rw_borrows_are_weak1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/shared_rw_borrows_are_weak2.stderr b/tests/fail/stacked_borrows/shared_rw_borrows_are_weak2.stderr index c0bf809356bd6..2c0117577f2e5 100644 --- a/tests/fail/stacked_borrows/shared_rw_borrows_are_weak2.stderr +++ b/tests/fail/stacked_borrows/shared_rw_borrows_are_weak2.stderr @@ -19,6 +19,7 @@ help: was later invalidated at offsets [$HEX..$HEX] | LL | shr_rw.replace(1); | ^^^^^^^^^^^^^^^^^ + = note: backtrace: = note: inside `main` at $DIR/shared_rw_borrows_are_weak2.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/shr_frozen_violation1.stderr b/tests/fail/stacked_borrows/shr_frozen_violation1.stderr index 55872300713a2..47799b18e1f9d 100644 --- a/tests/fail/stacked_borrows/shr_frozen_violation1.stderr +++ b/tests/fail/stacked_borrows/shr_frozen_violation1.stderr @@ -14,6 +14,7 @@ help: was created by a retag at offsets [0x0..0x4] | LL | *(x as *const i32 as *mut i32) = 7; | ^ + = note: backtrace: = note: inside `unknown_code` at $DIR/shr_frozen_violation1.rs:LL:CC note: inside `foo` at $DIR/shr_frozen_violation1.rs:LL:CC --> $DIR/shr_frozen_violation1.rs:LL:CC diff --git a/tests/fail/stacked_borrows/static_memory_modification.stderr b/tests/fail/stacked_borrows/static_memory_modification.stderr index 091eb29f64d7a..c8a0dc8dca2d8 100644 --- a/tests/fail/stacked_borrows/static_memory_modification.stderr +++ b/tests/fail/stacked_borrows/static_memory_modification.stderr @@ -6,7 +6,7 @@ LL | std::mem::transmute::<&usize, &mut usize>(&X) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/static_memory_modification.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/transmute-is-no-escape.stderr b/tests/fail/stacked_borrows/transmute-is-no-escape.stderr index 91c3ff9f8634a..b48abb3df7098 100644 --- a/tests/fail/stacked_borrows/transmute-is-no-escape.stderr +++ b/tests/fail/stacked_borrows/transmute-is-no-escape.stderr @@ -14,6 +14,7 @@ help: was created by a retag at offsets [0x4..0x8] | LL | let raw = (&mut x[1] as *mut i32).wrapping_offset(-1); | ^^^^^^^^^ + = note: backtrace: = note: inside `main` at $DIR/transmute-is-no-escape.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/unescaped_local.stderr b/tests/fail/stacked_borrows/unescaped_local.stderr index 464296651c5e6..6302ccde98373 100644 --- a/tests/fail/stacked_borrows/unescaped_local.stderr +++ b/tests/fail/stacked_borrows/unescaped_local.stderr @@ -9,7 +9,7 @@ LL | *raw = 13; | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information - + = note: backtrace: = note: inside `main` at $DIR/unescaped_local.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/unescaped_static.stderr b/tests/fail/stacked_borrows/unescaped_static.stderr index 621e9617fdfcc..018ff77b2e939 100644 --- a/tests/fail/stacked_borrows/unescaped_static.stderr +++ b/tests/fail/stacked_borrows/unescaped_static.stderr @@ -14,6 +14,7 @@ help: was created by a retag at offsets [0x0..0x1] | LL | let ptr_to_first = &ARRAY[0] as *const u8; | ^^^^^^^^^ + = note: backtrace: = note: inside `main` at $DIR/unescaped_static.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/vtable.stderr b/tests/fail/stacked_borrows/vtable.stderr index 31c3d5982e5ea..534f811e48abe 100644 --- a/tests/fail/stacked_borrows/vtable.stderr +++ b/tests/fail/stacked_borrows/vtable.stderr @@ -6,7 +6,7 @@ LL | unsafe { PtrRepr { components: PtrComponents { data_address, metadata } | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `std::ptr::from_raw_parts::` at RUSTLIB/core/src/ptr/metadata.rs:LL:CC note: inside `uwu` at $DIR/vtable.rs:LL:CC --> $DIR/vtable.rs:LL:CC diff --git a/tests/fail/stacked_borrows/zst_slice.stderr b/tests/fail/stacked_borrows/zst_slice.stderr index 3474f0c2b4234..2878f4c069af7 100644 --- a/tests/fail/stacked_borrows/zst_slice.stderr +++ b/tests/fail/stacked_borrows/zst_slice.stderr @@ -14,6 +14,7 @@ help: was created by a retag at offsets [0x0..0x0] | LL | assert_eq!(*s.get_unchecked(1), 2); | ^^^^^^^^^^^^^^^^^^ + = note: backtrace: = note: inside `core::slice::::get_unchecked::` at RUSTLIB/core/src/slice/mod.rs:LL:CC note: inside `main` at $DIR/zst_slice.rs:LL:CC --> $DIR/zst_slice.rs:LL:CC diff --git a/tests/fail/static_memory_modification1.stderr b/tests/fail/static_memory_modification1.stderr index a37a79fa56f90..47590afc1d1a7 100644 --- a/tests/fail/static_memory_modification1.stderr +++ b/tests/fail/static_memory_modification1.stderr @@ -6,7 +6,7 @@ LL | *std::mem::transmute::<&usize, &mut usize>(&X) = 6; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/static_memory_modification1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/static_memory_modification2.stderr b/tests/fail/static_memory_modification2.stderr index d38f3f6342c34..c8fce81ede550 100644 --- a/tests/fail/static_memory_modification2.stderr +++ b/tests/fail/static_memory_modification2.stderr @@ -6,7 +6,7 @@ LL | transmute::<&[u8], &mut [u8]>(s.as_bytes())[4] = 42; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/static_memory_modification2.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/static_memory_modification3.stderr b/tests/fail/static_memory_modification3.stderr index 96e3877c54fba..16b06bb3f7968 100644 --- a/tests/fail/static_memory_modification3.stderr +++ b/tests/fail/static_memory_modification3.stderr @@ -6,7 +6,7 @@ LL | transmute::<&[u8], &mut [u8]>(bs)[4] = 42; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/static_memory_modification3.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/sync/libc_pthread_cond_double_destroy.stderr b/tests/fail/sync/libc_pthread_cond_double_destroy.stderr index 362952678139a..0e1c776f59658 100644 --- a/tests/fail/sync/libc_pthread_cond_double_destroy.stderr +++ b/tests/fail/sync/libc_pthread_cond_double_destroy.stderr @@ -6,7 +6,7 @@ LL | libc::pthread_cond_destroy(cond.as_mut_ptr()); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/libc_pthread_cond_double_destroy.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/sync/libc_pthread_condattr_double_destroy.stderr b/tests/fail/sync/libc_pthread_condattr_double_destroy.stderr index 14439445e727d..dee50249b6b63 100644 --- a/tests/fail/sync/libc_pthread_condattr_double_destroy.stderr +++ b/tests/fail/sync/libc_pthread_condattr_double_destroy.stderr @@ -6,7 +6,7 @@ LL | libc::pthread_condattr_destroy(attr.as_mut_ptr()); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/libc_pthread_condattr_double_destroy.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/sync/libc_pthread_mutex_NULL_deadlock.stderr b/tests/fail/sync/libc_pthread_mutex_NULL_deadlock.stderr index d42174b9fb743..1b40f39d04bc2 100644 --- a/tests/fail/sync/libc_pthread_mutex_NULL_deadlock.stderr +++ b/tests/fail/sync/libc_pthread_mutex_NULL_deadlock.stderr @@ -6,7 +6,7 @@ LL | libc::pthread_mutex_lock(&mut mutex as *mut _); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/libc_pthread_mutex_NULL_deadlock.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/sync/libc_pthread_mutex_default_deadlock.stderr b/tests/fail/sync/libc_pthread_mutex_default_deadlock.stderr index cb5daef68cbeb..7606472beb979 100644 --- a/tests/fail/sync/libc_pthread_mutex_default_deadlock.stderr +++ b/tests/fail/sync/libc_pthread_mutex_default_deadlock.stderr @@ -6,7 +6,7 @@ LL | libc::pthread_mutex_lock(&mut mutex as *mut _); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/libc_pthread_mutex_default_deadlock.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/sync/libc_pthread_mutex_destroy_locked.stderr b/tests/fail/sync/libc_pthread_mutex_destroy_locked.stderr index 96a3c645ab630..40a7b3de09d58 100644 --- a/tests/fail/sync/libc_pthread_mutex_destroy_locked.stderr +++ b/tests/fail/sync/libc_pthread_mutex_destroy_locked.stderr @@ -6,7 +6,7 @@ LL | libc::pthread_mutex_destroy(&mut mutex as *mut _); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/libc_pthread_mutex_destroy_locked.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/sync/libc_pthread_mutex_double_destroy.stderr b/tests/fail/sync/libc_pthread_mutex_double_destroy.stderr index 9df2dd32b8041..274d4496266b0 100644 --- a/tests/fail/sync/libc_pthread_mutex_double_destroy.stderr +++ b/tests/fail/sync/libc_pthread_mutex_double_destroy.stderr @@ -6,7 +6,7 @@ LL | libc::pthread_mutex_destroy(mutex.as_mut_ptr()); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/libc_pthread_mutex_double_destroy.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/sync/libc_pthread_mutex_normal_unlock_unlocked.stderr b/tests/fail/sync/libc_pthread_mutex_normal_unlock_unlocked.stderr index b0858374cd9fb..daa9a7c514483 100644 --- a/tests/fail/sync/libc_pthread_mutex_normal_unlock_unlocked.stderr +++ b/tests/fail/sync/libc_pthread_mutex_normal_unlock_unlocked.stderr @@ -6,7 +6,7 @@ LL | libc::pthread_mutex_unlock(&mut mutex as *mut _); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/libc_pthread_mutex_normal_unlock_unlocked.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/sync/libc_pthread_mutex_wrong_owner.stderr b/tests/fail/sync/libc_pthread_mutex_wrong_owner.stderr index 86d02c22819e8..83c22b2673d62 100644 --- a/tests/fail/sync/libc_pthread_mutex_wrong_owner.stderr +++ b/tests/fail/sync/libc_pthread_mutex_wrong_owner.stderr @@ -6,7 +6,7 @@ LL | ...t_eq!(libc::pthread_mutex_unlock(lock_copy.0.get() as *mut _), 0); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside closure at $DIR/libc_pthread_mutex_wrong_owner.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/sync/libc_pthread_mutexattr_double_destroy.stderr b/tests/fail/sync/libc_pthread_mutexattr_double_destroy.stderr index 21adfa61d115d..44a201fe05836 100644 --- a/tests/fail/sync/libc_pthread_mutexattr_double_destroy.stderr +++ b/tests/fail/sync/libc_pthread_mutexattr_double_destroy.stderr @@ -6,7 +6,7 @@ LL | libc::pthread_mutexattr_destroy(attr.as_mut_ptr()); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/libc_pthread_mutexattr_double_destroy.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/sync/libc_pthread_rwlock_destroy_read_locked.stderr b/tests/fail/sync/libc_pthread_rwlock_destroy_read_locked.stderr index 80a88a773e5ca..43f8b2dcca6f9 100644 --- a/tests/fail/sync/libc_pthread_rwlock_destroy_read_locked.stderr +++ b/tests/fail/sync/libc_pthread_rwlock_destroy_read_locked.stderr @@ -6,7 +6,7 @@ LL | libc::pthread_rwlock_destroy(rw.get()); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/libc_pthread_rwlock_destroy_read_locked.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/sync/libc_pthread_rwlock_destroy_write_locked.stderr b/tests/fail/sync/libc_pthread_rwlock_destroy_write_locked.stderr index 0fd49a63306c2..cbaa2b3fcce9f 100644 --- a/tests/fail/sync/libc_pthread_rwlock_destroy_write_locked.stderr +++ b/tests/fail/sync/libc_pthread_rwlock_destroy_write_locked.stderr @@ -6,7 +6,7 @@ LL | libc::pthread_rwlock_destroy(rw.get()); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/libc_pthread_rwlock_destroy_write_locked.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/sync/libc_pthread_rwlock_double_destroy.stderr b/tests/fail/sync/libc_pthread_rwlock_double_destroy.stderr index d60afc67c85b5..159e1b9881a90 100644 --- a/tests/fail/sync/libc_pthread_rwlock_double_destroy.stderr +++ b/tests/fail/sync/libc_pthread_rwlock_double_destroy.stderr @@ -6,7 +6,7 @@ LL | libc::pthread_rwlock_destroy(&mut lock); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/libc_pthread_rwlock_double_destroy.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/sync/libc_pthread_rwlock_read_wrong_owner.stderr b/tests/fail/sync/libc_pthread_rwlock_read_wrong_owner.stderr index c7c8823eaa371..0921f3d4b506c 100644 --- a/tests/fail/sync/libc_pthread_rwlock_read_wrong_owner.stderr +++ b/tests/fail/sync/libc_pthread_rwlock_read_wrong_owner.stderr @@ -6,7 +6,7 @@ LL | ... assert_eq!(libc::pthread_rwlock_unlock(lock_copy.0.get() as *mut _), | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside closure at $DIR/libc_pthread_rwlock_read_wrong_owner.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/sync/libc_pthread_rwlock_unlock_unlocked.stderr b/tests/fail/sync/libc_pthread_rwlock_unlock_unlocked.stderr index f8454d05587fc..67bfde22edcfe 100644 --- a/tests/fail/sync/libc_pthread_rwlock_unlock_unlocked.stderr +++ b/tests/fail/sync/libc_pthread_rwlock_unlock_unlocked.stderr @@ -6,7 +6,7 @@ LL | libc::pthread_rwlock_unlock(rw.get()); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/libc_pthread_rwlock_unlock_unlocked.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/sync/libc_pthread_rwlock_write_wrong_owner.stderr b/tests/fail/sync/libc_pthread_rwlock_write_wrong_owner.stderr index a7a17ae71b3ad..d066cb687a1a7 100644 --- a/tests/fail/sync/libc_pthread_rwlock_write_wrong_owner.stderr +++ b/tests/fail/sync/libc_pthread_rwlock_write_wrong_owner.stderr @@ -6,7 +6,7 @@ LL | ... assert_eq!(libc::pthread_rwlock_unlock(lock_copy.0.get() as *mut _), | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside closure at $DIR/libc_pthread_rwlock_write_wrong_owner.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/transmute-pair-uninit.stderr b/tests/fail/transmute-pair-uninit.stderr index c1f90c3efb6eb..ac6bf8243eee3 100644 --- a/tests/fail/transmute-pair-uninit.stderr +++ b/tests/fail/transmute-pair-uninit.stderr @@ -6,7 +6,7 @@ LL | let v = unsafe { *z.offset(first_undef) }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/transmute-pair-uninit.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/transmute_fat1.stderr b/tests/fail/transmute_fat1.stderr index 6263427bac5ba..a2dcffb255fe4 100644 --- a/tests/fail/transmute_fat1.stderr +++ b/tests/fail/transmute_fat1.stderr @@ -6,7 +6,7 @@ LL | std::mem::transmute::<&[u8], [u8; N]>(&[1u8]) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/transmute_fat1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/unaligned_pointers/alignment.stderr b/tests/fail/unaligned_pointers/alignment.stderr index 5f691d0490954..f3bd7ca27571d 100644 --- a/tests/fail/unaligned_pointers/alignment.stderr +++ b/tests/fail/unaligned_pointers/alignment.stderr @@ -6,7 +6,7 @@ LL | *(x_ptr as *mut u32) = 42; *(x_ptr.add(1) as *mut u32) = 42; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/alignment.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/unaligned_pointers/atomic_unaligned.stderr b/tests/fail/unaligned_pointers/atomic_unaligned.stderr index e3b7f4cdbc9a7..bde4ff615c295 100644 --- a/tests/fail/unaligned_pointers/atomic_unaligned.stderr +++ b/tests/fail/unaligned_pointers/atomic_unaligned.stderr @@ -6,7 +6,7 @@ LL | ::std::intrinsics::atomic_load_seqcst(zptr); | = help: this usually indicates that your program performed an invalid operation and caused Undefined Behavior = help: but due to `-Zmiri-symbolic-alignment-check`, alignment errors can also be false positives - + = note: backtrace: = note: inside `main` at $DIR/atomic_unaligned.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/unaligned_pointers/dyn_alignment.stderr b/tests/fail/unaligned_pointers/dyn_alignment.stderr index 6c64f0e365e7c..930ec994d002d 100644 --- a/tests/fail/unaligned_pointers/dyn_alignment.stderr +++ b/tests/fail/unaligned_pointers/dyn_alignment.stderr @@ -6,7 +6,7 @@ LL | let _ptr = &*ptr; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/dyn_alignment.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/unaligned_pointers/intptrcast_alignment_check.stderr b/tests/fail/unaligned_pointers/intptrcast_alignment_check.stderr index 347486187e1b9..963fa81b655c8 100644 --- a/tests/fail/unaligned_pointers/intptrcast_alignment_check.stderr +++ b/tests/fail/unaligned_pointers/intptrcast_alignment_check.stderr @@ -6,7 +6,7 @@ LL | unsafe { *u16_ptr = 2 }; | = help: this usually indicates that your program performed an invalid operation and caused Undefined Behavior = help: but due to `-Zmiri-symbolic-alignment-check`, alignment errors can also be false positives - + = note: backtrace: = note: inside `main` at $DIR/intptrcast_alignment_check.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/unaligned_pointers/reference_to_packed.stderr b/tests/fail/unaligned_pointers/reference_to_packed.stderr index 3dbc47f71d7b4..ce667c1e8dece 100644 --- a/tests/fail/unaligned_pointers/reference_to_packed.stderr +++ b/tests/fail/unaligned_pointers/reference_to_packed.stderr @@ -6,7 +6,7 @@ LL | let i = *p; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/reference_to_packed.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/unaligned_pointers/unaligned_ptr1.stderr b/tests/fail/unaligned_pointers/unaligned_ptr1.stderr index afc458e9ccb12..c557ebb11f679 100644 --- a/tests/fail/unaligned_pointers/unaligned_ptr1.stderr +++ b/tests/fail/unaligned_pointers/unaligned_ptr1.stderr @@ -6,7 +6,7 @@ LL | let _x = unsafe { *x }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/unaligned_ptr1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/unaligned_pointers/unaligned_ptr2.stderr b/tests/fail/unaligned_pointers/unaligned_ptr2.stderr index ac1ef5c381211..5bff916213178 100644 --- a/tests/fail/unaligned_pointers/unaligned_ptr2.stderr +++ b/tests/fail/unaligned_pointers/unaligned_ptr2.stderr @@ -6,7 +6,7 @@ LL | let _x = unsafe { *x }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/unaligned_ptr2.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/unaligned_pointers/unaligned_ptr3.stderr b/tests/fail/unaligned_pointers/unaligned_ptr3.stderr index 7075bb4c7b4b5..f887f38bec53e 100644 --- a/tests/fail/unaligned_pointers/unaligned_ptr3.stderr +++ b/tests/fail/unaligned_pointers/unaligned_ptr3.stderr @@ -6,7 +6,7 @@ LL | let _x = unsafe { *x }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/unaligned_ptr3.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/unaligned_pointers/unaligned_ptr4.stderr b/tests/fail/unaligned_pointers/unaligned_ptr4.stderr index e72f28682fd7d..f2fe961eb6a13 100644 --- a/tests/fail/unaligned_pointers/unaligned_ptr4.stderr +++ b/tests/fail/unaligned_pointers/unaligned_ptr4.stderr @@ -6,7 +6,7 @@ LL | let _val = unsafe { *ptr }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/unaligned_ptr4.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/unaligned_pointers/unaligned_ptr_addr_of.stderr b/tests/fail/unaligned_pointers/unaligned_ptr_addr_of.stderr index 31f9163b3cf05..157eb68b50d8d 100644 --- a/tests/fail/unaligned_pointers/unaligned_ptr_addr_of.stderr +++ b/tests/fail/unaligned_pointers/unaligned_ptr_addr_of.stderr @@ -6,7 +6,7 @@ LL | let _x = unsafe { ptr::addr_of!(*x) }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at RUSTLIB/core/src/ptr/mod.rs:LL:CC = note: this error originates in the macro `ptr::addr_of` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/fail/unaligned_pointers/unaligned_ptr_zst.stderr b/tests/fail/unaligned_pointers/unaligned_ptr_zst.stderr index 7ee9a949cc717..da53e922b7a94 100644 --- a/tests/fail/unaligned_pointers/unaligned_ptr_zst.stderr +++ b/tests/fail/unaligned_pointers/unaligned_ptr_zst.stderr @@ -6,7 +6,7 @@ LL | let _x = unsafe { *x }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/unaligned_ptr_zst.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/uninit_buffer.stderr b/tests/fail/uninit_buffer.stderr index 02e4bcb90be63..e684ca8f07714 100644 --- a/tests/fail/uninit_buffer.stderr +++ b/tests/fail/uninit_buffer.stderr @@ -6,7 +6,7 @@ LL | let mut order = unsafe { memcmp(left.as_ptr(), right.as_ptr(), len) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `::compare` at RUSTLIB/core/src/slice/cmp.rs:LL:CC = note: inside `core::slice::cmp::::cmp` at RUSTLIB/core/src/slice/cmp.rs:LL:CC note: inside `main` at $DIR/uninit_buffer.rs:LL:CC diff --git a/tests/fail/uninit_byte_read.stderr b/tests/fail/uninit_byte_read.stderr index d15b10dc6ed09..174d0d2416e3d 100644 --- a/tests/fail/uninit_byte_read.stderr +++ b/tests/fail/uninit_byte_read.stderr @@ -6,7 +6,7 @@ LL | let undef = unsafe { *v.get_unchecked(5) }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/uninit_byte_read.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/uninit_raw_ptr.stderr b/tests/fail/uninit_raw_ptr.stderr index c76f59e13e7f5..7241cf04ae4a1 100644 --- a/tests/fail/uninit_raw_ptr.stderr +++ b/tests/fail/uninit_raw_ptr.stderr @@ -6,7 +6,7 @@ LL | let _val = unsafe { std::mem::MaybeUninit::<*const u8>::uninit().assume | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/uninit_raw_ptr.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/unreachable.stderr b/tests/fail/unreachable.stderr index 1cad7dd901b74..e9eb3649dea4a 100644 --- a/tests/fail/unreachable.stderr +++ b/tests/fail/unreachable.stderr @@ -6,7 +6,7 @@ LL | unsafe { intrinsics::unreachable() } | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `std::hint::unreachable_unchecked` at RUSTLIB/core/src/hint.rs:LL:CC note: inside `main` at $DIR/unreachable.rs:LL:CC --> $DIR/unreachable.rs:LL:CC diff --git a/tests/fail/unsupported_foreign_function.stderr b/tests/fail/unsupported_foreign_function.stderr index b8b1925d2cccf..3298f57dd51e7 100644 --- a/tests/fail/unsupported_foreign_function.stderr +++ b/tests/fail/unsupported_foreign_function.stderr @@ -5,7 +5,7 @@ LL | foo(); | ^^^^^ can't call foreign function: foo | = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support - + = note: backtrace: = note: inside `main` at $DIR/unsupported_foreign_function.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/unsupported_signal.stderr b/tests/fail/unsupported_signal.stderr index 8fcbc7fb47395..622b1876e0f86 100644 --- a/tests/fail/unsupported_signal.stderr +++ b/tests/fail/unsupported_signal.stderr @@ -5,7 +5,7 @@ LL | libc::signal(libc::SIGPIPE, libc::SIG_IGN); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't call foreign function: signal | = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support - + = note: backtrace: = note: inside `main` at $DIR/unsupported_signal.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/validity/cast_fn_ptr1.stderr b/tests/fail/validity/cast_fn_ptr1.stderr index 05c75ac133861..6ac10b10a0035 100644 --- a/tests/fail/validity/cast_fn_ptr1.stderr +++ b/tests/fail/validity/cast_fn_ptr1.stderr @@ -6,7 +6,7 @@ LL | g(0usize as *const i32) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/cast_fn_ptr1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/validity/cast_fn_ptr2.stderr b/tests/fail/validity/cast_fn_ptr2.stderr index 8bee099caf3bf..cd73237c867fe 100644 --- a/tests/fail/validity/cast_fn_ptr2.stderr +++ b/tests/fail/validity/cast_fn_ptr2.stderr @@ -6,7 +6,7 @@ LL | let _x = g(); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/cast_fn_ptr2.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/validity/dangling_ref1.stderr b/tests/fail/validity/dangling_ref1.stderr index 290963c6d4ee6..52e1ae2acb851 100644 --- a/tests/fail/validity/dangling_ref1.stderr +++ b/tests/fail/validity/dangling_ref1.stderr @@ -6,7 +6,7 @@ LL | let _x: &i32 = unsafe { mem::transmute(16usize) }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/dangling_ref1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/validity/dangling_ref2.stderr b/tests/fail/validity/dangling_ref2.stderr index ce60f973ffe88..f9d0ad5515c82 100644 --- a/tests/fail/validity/dangling_ref2.stderr +++ b/tests/fail/validity/dangling_ref2.stderr @@ -6,7 +6,7 @@ LL | let _x: &i32 = unsafe { mem::transmute(ptr) }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/dangling_ref2.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/validity/dangling_ref3.stderr b/tests/fail/validity/dangling_ref3.stderr index aa25f16560863..37b8d6bce6e84 100644 --- a/tests/fail/validity/dangling_ref3.stderr +++ b/tests/fail/validity/dangling_ref3.stderr @@ -6,7 +6,7 @@ LL | let _x: &i32 = unsafe { mem::transmute(dangling()) }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/dangling_ref3.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/validity/invalid_bool.stderr b/tests/fail/validity/invalid_bool.stderr index 756c094d6e866..31575a439b5bb 100644 --- a/tests/fail/validity/invalid_bool.stderr +++ b/tests/fail/validity/invalid_bool.stderr @@ -6,7 +6,7 @@ LL | let _b = unsafe { std::mem::transmute::(2) }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/invalid_bool.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/validity/invalid_bool_uninit.stderr b/tests/fail/validity/invalid_bool_uninit.stderr index 5236cab450b68..a4f2d844fd265 100644 --- a/tests/fail/validity/invalid_bool_uninit.stderr +++ b/tests/fail/validity/invalid_bool_uninit.stderr @@ -6,7 +6,7 @@ LL | let _b = unsafe { MyUninit { init: () }.uninit }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/invalid_bool_uninit.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/validity/invalid_char.stderr b/tests/fail/validity/invalid_char.stderr index 538af4aefcab9..a64452041f6f4 100644 --- a/tests/fail/validity/invalid_char.stderr +++ b/tests/fail/validity/invalid_char.stderr @@ -6,7 +6,7 @@ LL | let _val = match unsafe { std::mem::transmute::(-1) } { | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/invalid_char.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/validity/invalid_char_uninit.stderr b/tests/fail/validity/invalid_char_uninit.stderr index 12bc0faa5135b..10dff84238680 100644 --- a/tests/fail/validity/invalid_char_uninit.stderr +++ b/tests/fail/validity/invalid_char_uninit.stderr @@ -6,7 +6,7 @@ LL | let _b = unsafe { MyUninit { init: () }.uninit }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/invalid_char_uninit.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/validity/invalid_enum_tag.stderr b/tests/fail/validity/invalid_enum_tag.stderr index c7014ae71ac22..e6a484d7bde3d 100644 --- a/tests/fail/validity/invalid_enum_tag.stderr +++ b/tests/fail/validity/invalid_enum_tag.stderr @@ -6,7 +6,7 @@ LL | let _f = unsafe { std::mem::transmute::(42) }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/invalid_enum_tag.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/validity/invalid_enum_tag_256variants_uninit.stderr b/tests/fail/validity/invalid_enum_tag_256variants_uninit.stderr index c9fd312a96ce5..c3ebf462b6d75 100644 --- a/tests/fail/validity/invalid_enum_tag_256variants_uninit.stderr +++ b/tests/fail/validity/invalid_enum_tag_256variants_uninit.stderr @@ -7,7 +7,7 @@ LL | let _a = unsafe { MyUninit { init: () }.uninit }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/invalid_enum_tag_256variants_uninit.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/validity/invalid_fnptr_null.stderr b/tests/fail/validity/invalid_fnptr_null.stderr index 13e8957e615ff..6c744f204445f 100644 --- a/tests/fail/validity/invalid_fnptr_null.stderr +++ b/tests/fail/validity/invalid_fnptr_null.stderr @@ -6,7 +6,7 @@ LL | let _b: fn() = unsafe { std::mem::transmute(0usize) }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/invalid_fnptr_null.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/validity/invalid_fnptr_uninit.stderr b/tests/fail/validity/invalid_fnptr_uninit.stderr index b64655fa81897..55307f6b98d11 100644 --- a/tests/fail/validity/invalid_fnptr_uninit.stderr +++ b/tests/fail/validity/invalid_fnptr_uninit.stderr @@ -6,7 +6,7 @@ LL | let _b = unsafe { MyUninit { init: () }.uninit }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/invalid_fnptr_uninit.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/validity/invalid_wide_raw.stderr b/tests/fail/validity/invalid_wide_raw.stderr index 633f8f8adbc23..624b9764c9e14 100644 --- a/tests/fail/validity/invalid_wide_raw.stderr +++ b/tests/fail/validity/invalid_wide_raw.stderr @@ -6,7 +6,7 @@ LL | dbg!(S { x: unsafe { std::mem::transmute((0usize, 0usize)) } }); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/invalid_wide_raw.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/validity/nonzero.stderr b/tests/fail/validity/nonzero.stderr index 0c6a241723071..05b08d99d36d9 100644 --- a/tests/fail/validity/nonzero.stderr +++ b/tests/fail/validity/nonzero.stderr @@ -6,7 +6,7 @@ LL | let _x = Some(unsafe { NonZero(0) }); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/nonzero.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/validity/ptr_integer_array_transmute.stderr b/tests/fail/validity/ptr_integer_array_transmute.stderr index 39b4ebfc8f132..43eedb70fe654 100644 --- a/tests/fail/validity/ptr_integer_array_transmute.stderr +++ b/tests/fail/validity/ptr_integer_array_transmute.stderr @@ -6,7 +6,7 @@ LL | let _i: [usize; 1] = unsafe { std::mem::transmute(r) }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/ptr_integer_array_transmute.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/validity/ref_to_uninhabited1.stderr b/tests/fail/validity/ref_to_uninhabited1.stderr index 526b6a4dc2515..ae606d0a80132 100644 --- a/tests/fail/validity/ref_to_uninhabited1.stderr +++ b/tests/fail/validity/ref_to_uninhabited1.stderr @@ -6,7 +6,7 @@ LL | let x: Box = transmute(&mut 42); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/ref_to_uninhabited1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/validity/ref_to_uninhabited2.stderr b/tests/fail/validity/ref_to_uninhabited2.stderr index 297b0540ab014..3db040eeda10a 100644 --- a/tests/fail/validity/ref_to_uninhabited2.stderr +++ b/tests/fail/validity/ref_to_uninhabited2.stderr @@ -6,7 +6,7 @@ LL | let _x: &(i32, Void) = transmute(&42); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/ref_to_uninhabited2.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/validity/too-big-slice.stderr b/tests/fail/validity/too-big-slice.stderr index 52077f16a1c8c..591dc6d7b5c27 100644 --- a/tests/fail/validity/too-big-slice.stderr +++ b/tests/fail/validity/too-big-slice.stderr @@ -6,7 +6,7 @@ LL | let _x: &[u8] = mem::transmute((ptr, usize::MAX)); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/too-big-slice.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/validity/too-big-unsized.stderr b/tests/fail/validity/too-big-unsized.stderr index a20f1de6d57dc..3b8b9f50cf87e 100644 --- a/tests/fail/validity/too-big-unsized.stderr +++ b/tests/fail/validity/too-big-unsized.stderr @@ -6,7 +6,7 @@ LL | let _x: &MySlice = mem::transmute((ptr, isize::MAX as usize)); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/too-big-unsized.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/validity/transmute_through_ptr.stderr b/tests/fail/validity/transmute_through_ptr.stderr index 50f699d7f9b52..bf79e8649d01a 100644 --- a/tests/fail/validity/transmute_through_ptr.stderr +++ b/tests/fail/validity/transmute_through_ptr.stderr @@ -6,7 +6,7 @@ LL | let y = x; // reading this ought to be enough to trigger validation | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/transmute_through_ptr.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/validity/uninit_float.stderr b/tests/fail/validity/uninit_float.stderr index 946897bd4ea6f..2fe27c904329d 100644 --- a/tests/fail/validity/uninit_float.stderr +++ b/tests/fail/validity/uninit_float.stderr @@ -6,7 +6,7 @@ LL | let _val = unsafe { std::mem::MaybeUninit::::uninit().assume_init( | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/uninit_float.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/validity/uninit_integer.stderr b/tests/fail/validity/uninit_integer.stderr index 7e9d38a4b7bb9..c461fc5afaa31 100644 --- a/tests/fail/validity/uninit_integer.stderr +++ b/tests/fail/validity/uninit_integer.stderr @@ -6,7 +6,7 @@ LL | let _val = unsafe { std::mem::MaybeUninit::::uninit().assume_ini | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/uninit_integer.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/validity/uninit_integer_signed.stderr b/tests/fail/validity/uninit_integer_signed.stderr index bd8ea42c3a435..c53c96c596e4a 100644 --- a/tests/fail/validity/uninit_integer_signed.stderr +++ b/tests/fail/validity/uninit_integer_signed.stderr @@ -6,7 +6,7 @@ LL | let _val = unsafe { std::mem::MaybeUninit::::uninit().assume_init( | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/uninit_integer_signed.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/weak_memory/racing_mixed_size.stderr b/tests/fail/weak_memory/racing_mixed_size.stderr index 0fb23be06bb78..4c53828a6ce69 100644 --- a/tests/fail/weak_memory/racing_mixed_size.stderr +++ b/tests/fail/weak_memory/racing_mixed_size.stderr @@ -5,7 +5,7 @@ LL | std::intrinsics::atomic_load_relaxed(hi); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ racy imperfectly overlapping atomic access is not possible in the C++20 memory model, and not supported by Miri's weak memory emulation | = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support - + = note: backtrace: = note: inside closure at $DIR/racing_mixed_size.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/weak_memory/racing_mixed_size_read.stderr b/tests/fail/weak_memory/racing_mixed_size_read.stderr index 6de185161084b..9988f4a86d426 100644 --- a/tests/fail/weak_memory/racing_mixed_size_read.stderr +++ b/tests/fail/weak_memory/racing_mixed_size_read.stderr @@ -5,7 +5,7 @@ LL | std::intrinsics::atomic_load_relaxed(hi); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ racy imperfectly overlapping atomic access is not possible in the C++20 memory model, and not supported by Miri's weak memory emulation | = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support - + = note: backtrace: = note: inside closure at $DIR/racing_mixed_size_read.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/zst1.stderr b/tests/fail/zst1.stderr index ba13c9d7e52af..eeb2429d4c6fc 100644 --- a/tests/fail/zst1.stderr +++ b/tests/fail/zst1.stderr @@ -6,7 +6,7 @@ LL | let _val = unsafe { *x }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/zst1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/zst2.stderr b/tests/fail/zst2.stderr index 3112a87489a92..8687e8636bfe8 100644 --- a/tests/fail/zst2.stderr +++ b/tests/fail/zst2.stderr @@ -6,7 +6,7 @@ LL | unsafe { *x = zst_val }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/zst2.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/zst3.stderr b/tests/fail/zst3.stderr index bc3436b14ac00..43233d4d2afd3 100644 --- a/tests/fail/zst3.stderr +++ b/tests/fail/zst3.stderr @@ -6,7 +6,7 @@ LL | unsafe { *(x as *mut [u8; 0]) = zst_val }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - + = note: backtrace: = note: inside `main` at $DIR/zst3.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/pass/box.stderr b/tests/pass/box.stderr index 41c752d5d0fc7..2c2534fa2b05a 100644 --- a/tests/pass/box.stderr +++ b/tests/pass/box.stderr @@ -10,7 +10,7 @@ LL | let r2 = ((r as usize) + 0) as *mut i32; = help: To ensure that Miri does not miss bugs in your program, use Strict Provenance APIs (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance, https://crates.io/crates/sptr) instead. = help: You can then pass the `-Zmiri-strict-provenance` flag to Miri, to ensure you are not relying on `from_exposed_addr` semantics. = help: Alternatively, the `-Zmiri-permissive-provenance` flag disables this warning. - + = note: backtrace: = note: inside `into_raw` at $DIR/box.rs:LL:CC note: inside `main` at $DIR/box.rs:LL:CC --> $DIR/box.rs:LL:CC diff --git a/tests/pass/extern_types.stderr b/tests/pass/extern_types.stderr index 3a4acec5ddb9e..fcb04d951d16a 100644 --- a/tests/pass/extern_types.stderr +++ b/tests/pass/extern_types.stderr @@ -10,6 +10,6 @@ LL | let x: &Foo = unsafe { &*(16 as *const Foo) }; = help: To ensure that Miri does not miss bugs in your program, use Strict Provenance APIs (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance, https://crates.io/crates/sptr) instead. = help: You can then pass the `-Zmiri-strict-provenance` flag to Miri, to ensure you are not relying on `from_exposed_addr` semantics. = help: Alternatively, the `-Zmiri-permissive-provenance` flag disables this warning. - + = note: backtrace: = note: inside `main` at $DIR/extern_types.rs:LL:CC From 7cdbf98f57ed767342f8f9d192f21cfd75ef2a75 Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Sat, 2 Jul 2022 13:22:22 -0400 Subject: [PATCH 3392/3747] Explain the behavior of the cache upon clear --- src/stacked_borrows/stack.rs | 19 ++++++++++++++----- ui_test/Cargo.toml | 4 ---- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/src/stacked_borrows/stack.rs b/src/stacked_borrows/stack.rs index 6e0d166086fc7..5ad9b5dc5353a 100644 --- a/src/stacked_borrows/stack.rs +++ b/src/stacked_borrows/stack.rs @@ -53,7 +53,7 @@ struct StackCache { impl StackCache { /// When a tag is used, we call this function to add or refresh it in the cache. /// - /// We use position in the cache to represent how recently a tag was used; the first position + /// We use the position in the cache to represent how recently a tag was used; the first position /// is the most recently used tag. So an add shifts every element towards the end, and inserts /// the new element at the start. We lose the last element. /// This strategy is effective at keeping the most-accessed tags in the cache, but it costs a @@ -104,7 +104,7 @@ impl<'tcx> Stack { /// index is given it means the match was *not* in the known part of the stack. /// `Ok(None)` indicates it matched the "unknown" part of the stack. /// `Err` indicates it was not found. - pub fn find_granting( + pub(super) fn find_granting( &mut self, access: AccessKind, tag: SbTagExtra, @@ -167,9 +167,15 @@ impl<'tcx> Stack { #[cfg(feature = "stack-cache")] fn find_granting_cache(&mut self, access: AccessKind, tag: SbTag) -> Option { - // When the borrow stack is empty, there are no tags we could put into the cache that would - // be valid. Additionally, since lookups into the cache are a linear search it doesn't make - // sense to use the cache when it is no smaller than a search of the borrow stack itself. + // This looks like a common-sense optimization; we're going to do a linear search of the + // cache or the borrow stack to scan the shorter of the two. This optimization is miniscule + // and this check actually ensures we do not access an invalid cache. + // When a stack is created and when tags are removed from the top of the borrow stack, we + // need some valid value to populate the cache. In both cases, we try to use the bottom + // item. But when the stack is cleared in `set_unknown_bottom` there is nothing we could + // place in the cache that is correct. But due to the way we populate the cache in + // `StackCache::add`, we know that when the borrow stack has grown larger than the cache, + // every slot in the cache is valid. if self.borrows.len() <= CACHE_LEN { return None; } @@ -261,6 +267,9 @@ impl<'tcx> Stack { } pub fn set_unknown_bottom(&mut self, tag: SbTag) { + // We clear the borrow stack but the lookup cache doesn't support clearing per se. Instead, + // there is a check explained in `find_granting_cache` which protects against accessing the + // cache when it has been cleared and not yet refilled. self.borrows.clear(); self.unknown_bottom = Some(tag); } diff --git a/ui_test/Cargo.toml b/ui_test/Cargo.toml index 0838733db2de3..92c00915cbfeb 100644 --- a/ui_test/Cargo.toml +++ b/ui_test/Cargo.toml @@ -14,7 +14,3 @@ crossbeam = "0.8.1" lazy_static = "1.4.0" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" - -[features] -# Doesn't do anything, but the miri script wants to pass the same flags to ui_test and miri itself -expensive-debug-assertions = [] From b4520e459159781966d678cc0f65c8d295f523e4 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 2 Jul 2022 12:26:00 -0400 Subject: [PATCH 3393/3747] test fs::read_link surface function --- tests/pass/fs.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/tests/pass/fs.rs b/tests/pass/fs.rs index bc78cb560f00a..e106ca5d02bb8 100644 --- a/tests/pass/fs.rs +++ b/tests/pass/fs.rs @@ -8,7 +8,8 @@ extern crate libc; use std::ffi::CString; use std::fs::{ - create_dir, read_dir, remove_dir, remove_dir_all, remove_file, rename, File, OpenOptions, + create_dir, read_dir, read_link, remove_dir, remove_dir_all, remove_file, rename, File, + OpenOptions, }; use std::io::{Error, ErrorKind, Read, Result, Seek, SeekFrom, Write}; use std::path::{Path, PathBuf}; @@ -317,10 +318,12 @@ fn test_symlink() { assert_eq!(Error::last_os_error().kind(), ErrorKind::NotFound); } - // Test that metadata of a symbolic link is correct. + // Test that metadata of a symbolic link (i.e., the file it points to) is correct. check_metadata(bytes, &symlink_path).unwrap(); // Test that the metadata of a symbolic link is correct when not following it. assert!(symlink_path.symlink_metadata().unwrap().file_type().is_symlink()); + // Check that we can follow the link. + assert_eq!(read_link(&symlink_path).unwrap(), path); // Removing symbolic link should succeed. remove_file(&symlink_path).unwrap(); From 733b141789743f71a7fb1dc8f448a94f771d0849 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 2 Jul 2022 16:06:23 -0400 Subject: [PATCH 3394/3747] ./miri many-seeds: also print the seed before we try it --- miri | 1 + 1 file changed, 1 insertion(+) diff --git a/miri b/miri index 349cf818fb2a2..56e3f30348192 100755 --- a/miri +++ b/miri @@ -55,6 +55,7 @@ COMMAND="$1" case "$COMMAND" in many-seeds) for SEED in $({ echo obase=16; seq 0 255; } | bc); do + echo "Trying seed: $SEED" MIRIFLAGS="$MIRIFLAGS -Zmiri-seed=$SEED" $@ || { echo "Failing seed: $SEED"; break; } done exit 0 From d9c441c5abfbe9052a2d682c1ae644513a68b767 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 2 Jul 2022 18:33:03 -0400 Subject: [PATCH 3395/3747] put call to stacked borrows end_call in a more sensible place --- src/machine.rs | 5 ++++- src/shims/panic.rs | 8 ++------ 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/machine.rs b/src/machine.rs index 1b7fc4ffb9637..716d4bd5b90c3 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -930,7 +930,10 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { unwinding: bool, ) -> InterpResult<'tcx, StackPopJump> { let timing = frame.extra.timing.take(); - let res = ecx.handle_stack_pop(frame.extra, unwinding); + if let Some(stacked_borrows) = &ecx.machine.stacked_borrows { + stacked_borrows.borrow_mut().end_call(frame.extra.call_id); + } + let res = ecx.handle_stack_pop_unwind(frame.extra, unwinding); if let Some(profiler) = ecx.machine.profiler.as_ref() { profiler.finish_recording_interval_event(timing.unwrap()); } diff --git a/src/shims/panic.rs b/src/shims/panic.rs index ed6e72591dd00..2ef0a741d52fb 100644 --- a/src/shims/panic.rs +++ b/src/shims/panic.rs @@ -115,17 +115,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(()) } - fn handle_stack_pop( + fn handle_stack_pop_unwind( &mut self, mut extra: FrameData<'tcx>, unwinding: bool, ) -> InterpResult<'tcx, StackPopJump> { let this = self.eval_context_mut(); - - trace!("handle_stack_pop(extra = {:?}, unwinding = {})", extra, unwinding); - if let Some(stacked_borrows) = &this.machine.stacked_borrows { - stacked_borrows.borrow_mut().end_call(extra.call_id); - } + trace!("handle_stack_pop_unwind(extra = {:?}, unwinding = {})", extra, unwinding); // We only care about `catch_panic` if we're unwinding - if we're doing a normal // return, then we don't need to do anything special. From dcdf4fb6f62245200031fa8f84c19e188e8363df Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 2 Jul 2022 18:36:34 -0400 Subject: [PATCH 3396/3747] readme tweaks --- README.md | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 32cbc4f1e458a..4681a3d382146 100644 --- a/README.md +++ b/README.md @@ -65,9 +65,9 @@ in your program, and cannot run all programs: not support networking. System API support varies between targets; if you run on Windows it is a good idea to use `--target x86_64-unknown-linux-gnu` to get better support. -* Weak memory emulation may produce weak behaivours unobservable by compiled - programs running on real hardware when `SeqCst` fences are used, and it cannot - produce all behaviors possibly observable on real hardware. +* Weak memory emulation may [produce weak behaivours](https://github.com/rust-lang/miri/issues/2301) + unobservable by compiled programs running on real hardware when `SeqCst` fences are used, and it + cannot produce all behaviors possibly observable on real hardware. [rust]: https://www.rust-lang.org/ [mir]: https://github.com/rust-lang/rfcs/blob/master/text/1211-mir.md @@ -192,8 +192,9 @@ randomness that is used to determine allocation base addresses. The following snippet calls Miri in a loop with different values for the seed: ``` -for seed in $({ echo obase=16; seq 0 255; } | bc); do - MIRIFLAGS=-Zmiri-seed=$seed cargo miri test || { echo "Last seed: $seed"; break; }; +for SEED in $({ echo obase=16; seq 0 255; } | bc); do + echo "Trying seed: $SEED" + MIRIFLAGS=-Zmiri-seed=$SEED cargo miri test || { echo "Failing seed: $SEED"; break; }; done ``` From f3b479d5569fa013020db1d940aeb38dadc9060b Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Sat, 2 Jul 2022 19:44:55 -0400 Subject: [PATCH 3397/3747] Explain cache behavior a bit better, clean up diff --- Cargo.toml | 1 + src/lib.rs | 4 ++-- src/stacked_borrows.rs | 10 +++------- src/stacked_borrows/stack.rs | 22 +++++++++++++++------- 4 files changed, 21 insertions(+), 16 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 0dead9fa28f70..f612e7a3e9e50 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -53,5 +53,6 @@ harness = false [features] default = ["stack-cache"] +# Will be enabled on CI via `--all-features`. expensive-debug-assertions = [] stack-cache = [] diff --git a/src/lib.rs b/src/lib.rs index a98239711ef42..269980ede3796 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -90,8 +90,8 @@ pub use crate::mono_hash_map::MonoHashMap; pub use crate::operator::EvalContextExt as OperatorEvalContextExt; pub use crate::range_map::RangeMap; pub use crate::stacked_borrows::{ - stack::Stack, CallId, EvalContextExt as StackedBorEvalContextExt, Item, Permission, PtrId, - SbTag, SbTagExtra, Stacks, + stack::Stack, CallId, EvalContextExt as StackedBorEvalContextExt, Item, Permission, SbTag, + SbTagExtra, Stacks, }; pub use crate::sync::{CondvarId, EvalContextExt as SyncEvalContextExt, MutexId, RwLockId}; pub use crate::thread::{ diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 3a4b4ad65fa1a..01d67fcf59e0b 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -26,7 +26,6 @@ use diagnostics::{AllocHistory, TagHistory}; pub mod stack; use stack::Stack; -pub type PtrId = NonZeroU64; pub type CallId = NonZeroU64; // Even reading memory can have effects on the stack, so we need a `RefCell` here. @@ -479,7 +478,7 @@ impl<'tcx> Stack { ) })?; - // Step 2: Remove all items. Also checks for protectors. + // Step 2: Consider all items removed. This checks for protectors. for idx in (0..self.len()).rev() { let item = self.get(idx).unwrap(); Stack::item_popped(&item, None, global, alloc_history)?; @@ -579,8 +578,8 @@ impl<'tcx> Stacks { /// Creates new stack with initial tag. fn new(size: Size, perm: Permission, tag: SbTag) -> Self { let item = Item { perm, tag, protector: None }; - let stack = Stack::new(item); + Stacks { stacks: RangeMap::new(size, stack), history: AllocHistory::new(), @@ -826,14 +825,11 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // We have to use shared references to alloc/memory_extra here since // `visit_freeze_sensitive` needs to access the global state. let extra = this.get_alloc_extra(alloc_id)?; - let mut stacked_borrows = extra .stacked_borrows .as_ref() .expect("we should have Stacked Borrows data") .borrow_mut(); - let mut current_span = this.machine.current_span(); - this.visit_freeze_sensitive(place, size, |mut range, frozen| { // Adjust range. range.start += base_offset; @@ -858,7 +854,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx item, (alloc_id, range, offset), &mut global, - &mut current_span, + current_span, history, exposed_tags, ) diff --git a/src/stacked_borrows/stack.rs b/src/stacked_borrows/stack.rs index 5ad9b5dc5353a..1c3ee0fd573aa 100644 --- a/src/stacked_borrows/stack.rs +++ b/src/stacked_borrows/stack.rs @@ -27,8 +27,7 @@ pub struct Stack { /// we never have the unknown-to-known boundary in an SRW group. unknown_bottom: Option, - /// A small LRU cache of searches of the borrow stack. This only caches accesses of `Tagged`, - /// because those are unique in the stack. + /// A small LRU cache of searches of the borrow stack. #[cfg(feature = "stack-cache")] cache: StackCache, /// On a read, we need to disable all `Unique` above the granting item. We can avoid most of @@ -42,6 +41,11 @@ pub struct Stack { /// probably-cold random access into the borrow stack to figure out what `Permission` an /// `SbTag` grants. We could avoid this by also storing the `Permission` in the cache, but /// most lookups into the cache are immediately followed by access of the full borrow stack anyway. +/// +/// It may seem like maintaining this cache is a waste for small stacks, but +/// (a) iterating over small fixed-size arrays is super fast, and (b) empirically this helps *a lot*, +/// probably because runtime is dominated by large stacks. +/// arrays is super fast #[cfg(feature = "stack-cache")] #[derive(Clone, Debug)] struct StackCache { @@ -81,7 +85,9 @@ impl<'tcx> Stack { /// - There are no Unique tags outside of first_unique..last_unique #[cfg(feature = "expensive-debug-assertions")] fn verify_cache_consistency(&self) { - if self.borrows.len() > CACHE_LEN { + // Only a full cache needs to be valid. Also see the comments in find_granting_cache + // and set_unknown_bottom. + if self.borrows.len() >= CACHE_LEN { for (tag, stack_idx) in self.cache.tags.iter().zip(self.cache.idx.iter()) { assert_eq!(self.borrows[*stack_idx].tag, *tag); } @@ -154,7 +160,7 @@ impl<'tcx> Stack { } // If we didn't find the tag in the cache, fall back to a linear search of the - // whole stack, and add the tag to the stack. + // whole stack, and add the tag to the cache. for (stack_idx, item) in self.borrows.iter().enumerate().rev() { if tag == item.tag && item.perm.grants(access) { #[cfg(feature = "stack-cache")] @@ -185,8 +191,11 @@ impl<'tcx> Stack { // If we found the tag, look up its position in the stack to see if it grants // the required permission if self.borrows[stack_idx].perm.grants(access) { - // If it does, and it's not already in the most-recently-used position, move it there. - // Except if the tag is in position 1, this is equivalent to just a swap, so do that. + // If it does, and it's not already in the most-recently-used position, re-insert it at + // the most-recently-used position. This technically reduces the efficiency of the + // cache by duplicating elements, but current benchmarks do not seem to benefit from + // avoiding this duplication. + // But if the tag is in position 1, avoiding the duplicating add is trivial. if cache_idx == 1 { self.cache.tags.swap(0, 1); self.cache.idx.swap(0, 1); @@ -287,7 +296,6 @@ impl<'tcx> Stack { let unique_range = 0..self.len(); if disable_start <= unique_range.end { - // add 1 so we don't disable the granting item let lower = unique_range.start.max(disable_start); let upper = (unique_range.end + 1).min(self.borrows.len()); for item in &mut self.borrows[lower..upper] { From b004a03bdb6affd7b07322114967bd1693208a69 Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Sat, 2 Jul 2022 20:45:27 -0400 Subject: [PATCH 3398/3747] Typo --- src/stacked_borrows/stack.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/stacked_borrows/stack.rs b/src/stacked_borrows/stack.rs index 1c3ee0fd573aa..ccdd85eafd8eb 100644 --- a/src/stacked_borrows/stack.rs +++ b/src/stacked_borrows/stack.rs @@ -45,7 +45,6 @@ pub struct Stack { /// It may seem like maintaining this cache is a waste for small stacks, but /// (a) iterating over small fixed-size arrays is super fast, and (b) empirically this helps *a lot*, /// probably because runtime is dominated by large stacks. -/// arrays is super fast #[cfg(feature = "stack-cache")] #[derive(Clone, Debug)] struct StackCache { From 672d721544f4793a20f8c9565bb0808e9991694d Mon Sep 17 00:00:00 2001 From: DQ Date: Sun, 3 Jul 2022 11:32:36 +0200 Subject: [PATCH 3399/3747] Clarify `-Zmiri-track-pointer-tag` to explicitly say it also tracks tag creation --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 4681a3d382146..dc297115fa1b6 100644 --- a/README.md +++ b/README.md @@ -383,8 +383,8 @@ to Miri failing to detect cases of undefined behavior in a program. Borrows "protectors". Specifying this argument multiple times does not overwrite the previous values, instead it appends its values to the list. Listing an id multiple times has no effect. * `-Zmiri-track-pointer-tag=,,...` shows a backtrace when a given pointer tag - is popped from a borrow stack (which is where the tag becomes invalid and any - future use of it will error). This helps you in finding out why UB is + is created or when it is popped from a borrow stack (which is where the tag becomes invalid + and any future use of it will error). This helps you in finding out why UB is happening and where in your code would be a good place to look for it. Specifying this argument multiple times does not overwrite the previous values, instead it appends its values to the list. Listing a tag multiple times has no effect. From 5f7bc9739b312391d808e2406422a49027f8d68d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 3 Jul 2022 08:13:58 -0400 Subject: [PATCH 3400/3747] move arc_drop test to miri-test-libstd and make weak memory consistency test a bit faster again --- tests/pass/0concurrency_arc_drop.rs | 19 ------------------- tests/pass/0weak_memory_consistency.rs | 2 +- 2 files changed, 1 insertion(+), 20 deletions(-) delete mode 100644 tests/pass/0concurrency_arc_drop.rs diff --git a/tests/pass/0concurrency_arc_drop.rs b/tests/pass/0concurrency_arc_drop.rs deleted file mode 100644 index b5192cd421409..0000000000000 --- a/tests/pass/0concurrency_arc_drop.rs +++ /dev/null @@ -1,19 +0,0 @@ -// ignore-windows: Concurrency on Windows is not supported yet. -use std::sync::Arc; -use std::thread; - -/// Test for Arc::drop bug (https://github.com/rust-lang/rust/issues/55005) -fn main() { - // The bug seems to take up to 700 iterations to reproduce with most seeds (tested 0-9). - for _ in 0..700 { - let arc_1 = Arc::new(()); - let arc_2 = arc_1.clone(); - let thread = thread::spawn(|| drop(arc_2)); - let mut i = 0; - while i < 256 { - i += 1; - } - drop(arc_1); - thread.join().unwrap(); - } -} diff --git a/tests/pass/0weak_memory_consistency.rs b/tests/pass/0weak_memory_consistency.rs index d4680130e7fb8..0f798d2b575e0 100644 --- a/tests/pass/0weak_memory_consistency.rs +++ b/tests/pass/0weak_memory_consistency.rs @@ -217,7 +217,7 @@ fn test_single_thread() { } pub fn main() { - for _ in 0..75 { + for _ in 0..50 { test_single_thread(); test_mixed_access(); test_load_buffering_acq_rel(); From c6f44c1639e6c7ce5f84213649967d8542b51b3b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 3 Jul 2022 08:18:03 -0400 Subject: [PATCH 3401/3747] another one for the trophy case --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 4681a3d382146..48bba65286098 100644 --- a/README.md +++ b/README.md @@ -581,6 +581,7 @@ Definite bugs found: * [`integer-encoding` dereferencing a misaligned pointer](https://github.com/dermesser/integer-encoding-rs/pull/23) * [`rkyv` constructing a `Box<[u8]>` from an overaligned allocation](https://github.com/rkyv/rkyv/commit/a9417193a34757e12e24263178be8b2eebb72456) * [Data race in `thread::scope`](https://github.com/rust-lang/rust/issues/98498) +* [`regex` incorrectly handling unaligned `Vec` buffers](https://www.reddit.com/r/rust/comments/vq3mmu/comment/ienc7t0?context=3) Violations of [Stacked Borrows] found that are likely bugs (but Stacked Borrows is currently just an experiment): From e71f8b06304b639133b119829d4cb20b99536d89 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 3 Jul 2022 08:35:44 -0400 Subject: [PATCH 3402/3747] fix ./miri run with MIRI_TEST_TARGET --- README.md | 6 +++--- miri | 24 ++++++++++++++---------- 2 files changed, 17 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 48bba65286098..d831b4979b256 100644 --- a/README.md +++ b/README.md @@ -418,9 +418,9 @@ Moreover, Miri recognizes some environment variables: sysroot to use. Only set this if you do not want to use the automatically created sysroot. (The `miri` driver sysroot is controlled via the `--sysroot` flag instead.) -* `MIRI_TEST_TARGET` (recognized by the test suite) indicates which target - architecture to test against. `miri` and `cargo miri` accept the `--target` - flag for the same purpose. +* `MIRI_TEST_TARGET` (recognized by the test suite and the `./miri` script) indicates which target + architecture to test against. `miri` and `cargo miri` accept the `--target` flag for the same + purpose. * `MIRI_NO_STD` (recognized by `cargo miri` and the test suite) makes sure that the target's sysroot is built without libstd. This allows testing and running no_std programs. * `MIRI_BLESS` (recognized by the test suite) overwrite all `stderr` and `stdout` files diff --git a/miri b/miri index 56e3f30348192..da5634d6a95c1 100755 --- a/miri +++ b/miri @@ -167,17 +167,21 @@ test|test-debug|bless|bless-debug) $CARGO test $CARGO_BUILD_FLAGS --manifest-path "$MIRIDIR"/ui_test/Cargo.toml "$@" ;; run|run-debug) - # Scan for "--target" to set the "MIRI_TEST_TARGET" env var so + # Scan for "--target" to overwrite the "MIRI_TEST_TARGET" env var so # that we set the MIRI_SYSROOT up the right way. - if [ -z "$MIRI_TEST_TARGET" ]; then - for ARG in "$@"; do - if [ "$LAST_ARG" = "--target" ]; then - # Found it! - export MIRI_TEST_TARGET="$ARG" - break - fi - LAST_ARG="$ARG" - done + FOUND_TARGET_OPT=0 + for ARG in "$@"; do + if [ "$LAST_ARG" = "--target" ]; then + # Found it! + export MIRI_TEST_TARGET="$ARG" + FOUND_TARGET_OPT=1 + break + fi + LAST_ARG="$ARG" + done + if [ "$FOUND_TARGET_OPT" = "0" ] && [ -n "$MIRI_TEST_TARGET" ]; then + # Make sure Miri actually uses this target. + MIRIFLAGS="$MIRIFLAGS --target $MIRI_TEST_TARGET" fi # First build and get a sysroot. $CARGO build $CARGO_BUILD_FLAGS --manifest-path "$MIRIDIR"/Cargo.toml From 1b9e19a39b8f884e4a85011d25641e8bc3480288 Mon Sep 17 00:00:00 2001 From: DQ Date: Sun, 3 Jul 2022 15:47:39 +0200 Subject: [PATCH 3403/3747] clarify that a (tracked) tag may never be popped Co-authored-by: Ralf Jung --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index dc297115fa1b6..787952b9d746d 100644 --- a/README.md +++ b/README.md @@ -383,7 +383,7 @@ to Miri failing to detect cases of undefined behavior in a program. Borrows "protectors". Specifying this argument multiple times does not overwrite the previous values, instead it appends its values to the list. Listing an id multiple times has no effect. * `-Zmiri-track-pointer-tag=,,...` shows a backtrace when a given pointer tag - is created or when it is popped from a borrow stack (which is where the tag becomes invalid + is created and when (if ever) it is popped from a borrow stack (which is where the tag becomes invalid and any future use of it will error). This helps you in finding out why UB is happening and where in your code would be a good place to look for it. Specifying this argument multiple times does not overwrite the previous From 2fc92788181011a1995f055a3fac3296b3028574 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 3 Jul 2022 10:45:39 -0400 Subject: [PATCH 3404/3747] no doctests in ui_test --- ui_test/Cargo.toml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ui_test/Cargo.toml b/ui_test/Cargo.toml index 92c00915cbfeb..f221cc93fa716 100644 --- a/ui_test/Cargo.toml +++ b/ui_test/Cargo.toml @@ -3,7 +3,9 @@ name = "ui_test" version = "0.1.0" edition = "2021" -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html +[lib] +test = true # we have unit tests +doctest = false # but no doc tests [dependencies] rustc_version = "0.4" From a4e7e1e6b59e006d5b5599e2d6a181a77bf8ee04 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 3 Jul 2022 11:54:47 -0400 Subject: [PATCH 3405/3747] fix retagging of vtable ptrs --- src/stacked_borrows.rs | 5 +++++ tests/pass/stacked-borrows/stacked-borrows.rs | 14 ++++++++++++++ 2 files changed, 19 insertions(+) diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 3fa001eabfd27..cc2ea0b76d87c 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -1039,6 +1039,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let val = self.ecx.read_immediate(&place.into())?; let val = self.ecx.retag_reference(&val, mutbl, protector)?; self.ecx.write_immediate(*val, &place.into())?; + } else if matches!(place.layout.ty.kind(), ty::RawPtr(..)) { + // Wide raw pointers *do* have fields and their types are strange. + // vtables have a type like `&[*const (); 3]` or so! + // Do *not* recurse into them. + // (No need to worry about wide references or boxes, those always "qualify".) } else { // Maybe we need to go deeper. self.walk_value(place)?; diff --git a/tests/pass/stacked-borrows/stacked-borrows.rs b/tests/pass/stacked-borrows/stacked-borrows.rs index 3669a08a1bc4b..b915a2ddf8f67 100644 --- a/tests/pass/stacked-borrows/stacked-borrows.rs +++ b/tests/pass/stacked-borrows/stacked-borrows.rs @@ -1,4 +1,5 @@ // compile-flags: -Zmiri-retag-fields +#![feature(allocator_api)] use std::ptr; // Test various stacked-borrows-related things. @@ -17,6 +18,7 @@ fn main() { raw_ref_to_part(); array_casts(); mut_below_shr(); + wide_raw_ptr_in_tuple(); } // Make sure that reading from an `&mut` does, like reborrowing to `&`, @@ -205,3 +207,15 @@ fn mut_below_shr() { let r = &**p; let _val = *r; } + +fn wide_raw_ptr_in_tuple() { + let mut x: Box = Box::new("ouch"); + let r = &mut *x as *mut dyn std::any::Any; + // This triggers the visitor-based recursive retagging. It is *not* supposed to retag raw + // pointers, but then the visitor might recurse into the "fields" of a wide raw pointer and + // finds a reference (to a vtable) there that it wants to retag... and that would be Wrong. + let pair = (r, &0); + let r = unsafe { &mut *pair.0 }; + // Make sure the fn ptr part of the vtable is still fine. + r.type_id(); +} From 248a10eaf5cc6df2491a6e708524a41503674ffb Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 3 Jul 2022 12:28:57 -0400 Subject: [PATCH 3406/3747] reduce regex features to reduce rebuilds --- Cargo.toml | 3 ++- ui_test/Cargo.toml | 3 ++- ui_test/src/comments.rs | 2 +- ui_test/src/rustc_stderr.rs | 2 +- 4 files changed, 6 insertions(+), 4 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index f612e7a3e9e50..af73a7af31c71 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -39,7 +39,8 @@ libc = "0.2" [dev-dependencies] colored = "2" ui_test = { path = "ui_test" } -regex = "1.5.5" +# Features chosen to match those required by env_logger, to avoid rebuilds +regex = { version = "1.5.5", default-features = false, features = ["perf", "std"] } lazy_static = "1.4.0" [package.metadata.rust-analyzer] diff --git a/ui_test/Cargo.toml b/ui_test/Cargo.toml index 92c00915cbfeb..dab46c5253c7b 100644 --- a/ui_test/Cargo.toml +++ b/ui_test/Cargo.toml @@ -8,7 +8,8 @@ edition = "2021" [dependencies] rustc_version = "0.4" colored = "2" -regex = "1.5.5" +# Features chosen to match those required by env_logger, to avoid rebuilds +regex = { version = "1.5.5", default-features = false, features = ["perf", "std"] } pretty_assertions = "1.2.1" crossbeam = "0.8.1" lazy_static = "1.4.0" diff --git a/ui_test/src/comments.rs b/ui_test/src/comments.rs index e7b4968a9ca62..3fd65d643a1cf 100644 --- a/ui_test/src/comments.rs +++ b/ui_test/src/comments.rs @@ -75,7 +75,7 @@ impl Comments { pub(crate) fn parse(path: &Path, content: &str) -> Self { let mut this = Self::default(); let error_pattern_regex = - Regex::new(r"//(\[(?P[^\]]+)\])?~(?P\||[\^]+)?\s*(?PERROR|HELP|WARN|NOTE)?:?(?P.*)") + Regex::new(r"//(\[(?P[^\]]+)\])?~(?P\||[\^]+)? *(?PERROR|HELP|WARN|NOTE)?:?(?P.*)") .unwrap(); // The line that a `|` will refer to diff --git a/ui_test/src/rustc_stderr.rs b/ui_test/src/rustc_stderr.rs index ea32ce4bd2934..fc772c84040bf 100644 --- a/ui_test/src/rustc_stderr.rs +++ b/ui_test/src/rustc_stderr.rs @@ -116,7 +116,7 @@ impl Span { } pub(crate) fn filter_annotations_from_rendered(rendered: &str) -> std::borrow::Cow<'_, str> { - let annotations = Regex::new(r"\s*//(\[[^\]]\])?~.*").unwrap(); + let annotations = Regex::new(r" *//(\[[^\]]\])?~.*").unwrap(); annotations.replace_all(rendered, "") } From 0ce1e14c8956a86e2099cf6d1a9b4e2135f52a6f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 4 Jul 2022 12:51:20 -0400 Subject: [PATCH 3407/3747] update vscode settings --- CONTRIBUTING.md | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 7dfa9d73120f5..a3bad3d154075 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -154,19 +154,24 @@ to `.vscode/settings.json` in your local Miri clone: ```json { + "rust-analyzer.rustc.source": "discover", + "rust-analyzer.linkedProjects": [ + "./Cargo.toml", + "./cargo-miri/Cargo.toml" + ], "rust-analyzer.checkOnSave.overrideCommand": [ "./miri", "check", "--message-format=json" ], + "rust-analyzer.buildScripts.overrideCommand": [ + "./miri", + "check", + "--message-format=json", + ], "rust-analyzer.rustfmt.extraArgs": [ "+nightly" ], - "rust-analyzer.rustcSource": "discover", - "rust-analyzer.linkedProjects": [ - "./Cargo.toml", - "./cargo-miri/Cargo.toml" - ] } ``` From 22aa7f98c5cfb28aee0205f56ee1a6ee781ab2ba Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 4 Jul 2022 13:46:11 -0400 Subject: [PATCH 3408/3747] call_function: make the unit-return-type case more convenient --- src/eval.rs | 4 ++-- src/helpers.rs | 11 +++++++++-- src/shims/panic.rs | 10 ++++------ src/shims/tls.rs | 9 +++------ src/shims/unix/thread.rs | 2 +- 5 files changed, 19 insertions(+), 17 deletions(-) diff --git a/src/eval.rs b/src/eval.rs index 1536b826ac466..d75b4f5fa6d2a 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -289,7 +289,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( start_instance, Abi::Rust, &[Scalar::from_pointer(main_ptr, &ecx).into(), argc.into(), argv], - &ret_place.into(), + Some(&ret_place.into()), StackPopCleanup::Root { cleanup: true }, )?; } @@ -298,7 +298,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( entry_instance, Abi::Rust, &[argc.into(), argv], - &ret_place.into(), + Some(&ret_place.into()), StackPopCleanup::Root { cleanup: true }, )?; } diff --git a/src/helpers.rs b/src/helpers.rs index 86823f2817887..c051d44fa2561 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -235,12 +235,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// Call a function: Push the stack frame and pass the arguments. /// For now, arguments must be scalars (so that the caller does not have to know the layout). + /// + /// If you do not provie a return place, a dangling zero-sized place will be created + /// for your convenience. fn call_function( &mut self, f: ty::Instance<'tcx>, caller_abi: Abi, args: &[Immediate], - dest: &PlaceTy<'tcx, Tag>, + dest: Option<&PlaceTy<'tcx, Tag>>, stack_pop: StackPopCleanup, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); @@ -256,7 +259,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Push frame. let mir = this.load_mir(f.def, None)?; - this.push_stack_frame(f, mir, dest, stack_pop)?; + let dest = match dest { + Some(dest) => *dest, + None => MPlaceTy::dangling(this.layout_of(mir.return_ty())?).into(), + }; + this.push_stack_frame(f, mir, &dest, stack_pop)?; // Initialize arguments. let mut callee_args = this.frame().body.args_iter(); diff --git a/src/shims/panic.rs b/src/shims/panic.rs index 2ef0a741d52fb..c356dd86676da 100644 --- a/src/shims/panic.rs +++ b/src/shims/panic.rs @@ -91,12 +91,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Now we make a function call, and pass `data` as first and only argument. let f_instance = this.get_ptr_fn(try_fn)?.as_instance()?; trace!("try_fn: {:?}", f_instance); - let ret_place = MPlaceTy::dangling(this.machine.layouts.unit).into(); this.call_function( f_instance, Abi::Rust, &[data.into()], - &ret_place, + None, // Directly return to caller. StackPopCleanup::Goto { ret: Some(ret), unwind: StackPopUnwind::Skip }, )?; @@ -144,12 +143,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let f_instance = this.get_ptr_fn(this.scalar_to_ptr(catch_unwind.catch_fn)?)?.as_instance()?; trace!("catch_fn: {:?}", f_instance); - let ret_place = MPlaceTy::dangling(this.machine.layouts.unit).into(); this.call_function( f_instance, Abi::Rust, &[catch_unwind.data.into(), payload.into()], - &ret_place, + None, // Directly return to caller of `try`. StackPopCleanup::Goto { ret: Some(catch_unwind.ret), unwind: StackPopUnwind::Skip }, )?; @@ -175,7 +173,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx panic, Abi::Rust, &[msg.to_ref(this)], - &MPlaceTy::dangling(this.machine.layouts.unit).into(), + None, StackPopCleanup::Goto { ret: None, unwind }, ) } @@ -204,7 +202,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx panic_bounds_check, Abi::Rust, &[index.into(), len.into()], - &MPlaceTy::dangling(this.machine.layouts.unit).into(), + None, StackPopCleanup::Goto { ret: None, unwind: match unwind { diff --git a/src/shims/tls.rs b/src/shims/tls.rs index 6b4e9d4f75337..5a72c872b04d0 100644 --- a/src/shims/tls.rs +++ b/src/shims/tls.rs @@ -253,12 +253,11 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // The signature of this function is `unsafe extern "system" fn(h: c::LPVOID, dwReason: c::DWORD, pv: c::LPVOID)`. let reason = this.eval_path_scalar(&["std", "sys", "windows", "c", "DLL_THREAD_DETACH"])?; - let ret_place = MPlaceTy::dangling(this.machine.layouts.unit).into(); this.call_function( thread_callback, Abi::System { unwind: false }, &[Scalar::null_ptr(this).into(), reason.into(), Scalar::null_ptr(this).into()], - &ret_place, + None, StackPopCleanup::Root { cleanup: true }, )?; @@ -276,12 +275,11 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if let Some((instance, data)) = this.machine.tls.macos_thread_dtors.remove(&thread_id) { trace!("Running macos dtor {:?} on {:?} at {:?}", instance, data, thread_id); - let ret_place = MPlaceTy::dangling(this.machine.layouts.unit).into(); this.call_function( instance, Abi::C { unwind: false }, &[data.into()], - &ret_place, + None, StackPopCleanup::Root { cleanup: true }, )?; @@ -319,12 +317,11 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "data can't be NULL when dtor is called!" ); - let ret_place = MPlaceTy::dangling(this.machine.layouts.unit).into(); this.call_function( instance, Abi::C { unwind: false }, &[ptr.into()], - &ret_place, + None, StackPopCleanup::Root { cleanup: true }, )?; diff --git a/src/shims/unix/thread.rs b/src/shims/unix/thread.rs index 63b9f36d6ffa4..8dc5f81354a32 100644 --- a/src/shims/unix/thread.rs +++ b/src/shims/unix/thread.rs @@ -47,7 +47,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx instance, Abi::C { unwind: false }, &[*func_arg], - &ret_place.into(), + Some(&ret_place.into()), StackPopCleanup::Root { cleanup: true }, )?; From 25cbfcc5be6245ffce5fb39474f777b4885e5f61 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 4 Jul 2022 15:11:14 -0400 Subject: [PATCH 3409/3747] delete ancient benchmarks --- benches/fibonacci.rs | 26 -------- benches/helpers/fibonacci_helper.rs | 8 --- benches/helpers/fibonacci_helper_iterative.rs | 15 ----- benches/helpers/miri_helper.rs | 59 ------------------- benches/helpers/mod.rs | 7 --- benches/helpers/repeat.rs | 4 -- benches/helpers/repeat_manual.rs | 9 --- benches/helpers/smoke_helper.rs | 2 - benches/repeat.rs | 16 ----- benches/smoke.rs | 35 ----------- 10 files changed, 181 deletions(-) delete mode 100644 benches/fibonacci.rs delete mode 100644 benches/helpers/fibonacci_helper.rs delete mode 100644 benches/helpers/fibonacci_helper_iterative.rs delete mode 100644 benches/helpers/miri_helper.rs delete mode 100644 benches/helpers/mod.rs delete mode 100644 benches/helpers/repeat.rs delete mode 100644 benches/helpers/repeat_manual.rs delete mode 100644 benches/helpers/smoke_helper.rs delete mode 100644 benches/repeat.rs delete mode 100644 benches/smoke.rs diff --git a/benches/fibonacci.rs b/benches/fibonacci.rs deleted file mode 100644 index 9a68a69e800f1..0000000000000 --- a/benches/fibonacci.rs +++ /dev/null @@ -1,26 +0,0 @@ -#![feature(test, rustc_private)] - -extern crate test; -use crate::test::Bencher; -mod helpers; -use crate::helpers::*; - -#[bench] -fn fib(bencher: &mut Bencher) { - bencher.iter(fibonacci_helper::main) -} - -#[bench] -fn fib_miri(bencher: &mut Bencher) { - miri_helper::run("fibonacci_helper", bencher); -} - -#[bench] -fn fib_iter(bencher: &mut Bencher) { - bencher.iter(fibonacci_helper_iterative::main) -} - -#[bench] -fn fib_iter_miri(bencher: &mut Bencher) { - miri_helper::run("fibonacci_helper_iterative", bencher); -} diff --git a/benches/helpers/fibonacci_helper.rs b/benches/helpers/fibonacci_helper.rs deleted file mode 100644 index 586f1ce7da4d4..0000000000000 --- a/benches/helpers/fibonacci_helper.rs +++ /dev/null @@ -1,8 +0,0 @@ -#[inline(never)] -pub fn main() { - assert_eq!(fib(10), 55); -} - -fn fib(n: usize) -> usize { - if n <= 2 { 1 } else { fib(n - 1) + fib(n - 2) } -} diff --git a/benches/helpers/fibonacci_helper_iterative.rs b/benches/helpers/fibonacci_helper_iterative.rs deleted file mode 100644 index 0c2732828966c..0000000000000 --- a/benches/helpers/fibonacci_helper_iterative.rs +++ /dev/null @@ -1,15 +0,0 @@ -#[inline(never)] -pub fn main() { - assert_eq!(fib(10), 55); -} - -fn fib(n: usize) -> usize { - let mut a = 0; - let mut b = 1; - for _ in 0..n { - let c = a; - a = b; - b += c; - } - a -} diff --git a/benches/helpers/miri_helper.rs b/benches/helpers/miri_helper.rs deleted file mode 100644 index be542c2bc0a6a..0000000000000 --- a/benches/helpers/miri_helper.rs +++ /dev/null @@ -1,59 +0,0 @@ -extern crate rustc_driver; -extern crate rustc_hir; -extern crate rustc_interface; - -use rustc_driver::Compilation; -use rustc_interface::{interface, Queries}; - -use crate::test::Bencher; - -struct MiriCompilerCalls<'a> { - bencher: &'a mut Bencher, -} - -impl rustc_driver::Callbacks for MiriCompilerCalls<'_> { - fn after_analysis<'tcx>( - &mut self, - compiler: &interface::Compiler, - queries: &'tcx Queries<'tcx>, - ) -> Compilation { - compiler.session().abort_if_errors(); - - queries.global_ctxt().unwrap().peek_mut().enter(|tcx| { - let (entry_def_id, entry_type) = - tcx.entry_fn(()).expect("no main or start function found"); - - self.bencher.iter(|| { - let config = miri::MiriConfig::default(); - miri::eval_entry(tcx, entry_def_id, entry_type, config); - }); - }); - - compiler.session().abort_if_errors(); - - Compilation::Stop - } -} - -fn find_sysroot() -> String { - // Taken from https://github.com/Manishearth/rust-clippy/pull/911. - let home = option_env!("RUSTUP_HOME").or(option_env!("MULTIRUST_HOME")); - let toolchain = option_env!("RUSTUP_TOOLCHAIN").or(option_env!("MULTIRUST_TOOLCHAIN")); - match (home, toolchain) { - (Some(home), Some(toolchain)) => format!("{}/toolchains/{}", home, toolchain), - _ => - option_env!("RUST_SYSROOT") - .expect("need to specify RUST_SYSROOT env var or use rustup or multirust") - .to_owned(), - } -} - -pub fn run(filename: &str, bencher: &mut Bencher) { - let args = &[ - "miri".to_string(), - format!("benches/helpers/{}.rs", filename), - "--sysroot".to_string(), - find_sysroot(), - ]; - rustc_driver::RunCompiler::new(args, &mut MiriCompilerCalls { bencher }).run().unwrap() -} diff --git a/benches/helpers/mod.rs b/benches/helpers/mod.rs deleted file mode 100644 index 27504a2cc034d..0000000000000 --- a/benches/helpers/mod.rs +++ /dev/null @@ -1,7 +0,0 @@ -// This module gets included in multiple crates, and they each only use part of it. -#![allow(dead_code)] - -pub mod fibonacci_helper; -pub mod fibonacci_helper_iterative; -pub mod miri_helper; -pub mod smoke_helper; diff --git a/benches/helpers/repeat.rs b/benches/helpers/repeat.rs deleted file mode 100644 index 0e8c5980b82bd..0000000000000 --- a/benches/helpers/repeat.rs +++ /dev/null @@ -1,4 +0,0 @@ -fn main() { - let data: [u8; 1024] = [42; 1024]; - assert_eq!(data.len(), 1024); -} diff --git a/benches/helpers/repeat_manual.rs b/benches/helpers/repeat_manual.rs deleted file mode 100644 index bd5d6b1e1264b..0000000000000 --- a/benches/helpers/repeat_manual.rs +++ /dev/null @@ -1,9 +0,0 @@ -fn main() { - let mut data: [u8; 1024] = unsafe { std::mem::uninitialized() }; - for i in 0..data.len() { - unsafe { - std::ptr::write(&mut data[i], 0); - } - } - assert_eq!(data.len(), 1024); -} diff --git a/benches/helpers/smoke_helper.rs b/benches/helpers/smoke_helper.rs deleted file mode 100644 index e81db817aeace..0000000000000 --- a/benches/helpers/smoke_helper.rs +++ /dev/null @@ -1,2 +0,0 @@ -#[inline(never)] -pub fn main() {} diff --git a/benches/repeat.rs b/benches/repeat.rs deleted file mode 100644 index 0369b1f74cf59..0000000000000 --- a/benches/repeat.rs +++ /dev/null @@ -1,16 +0,0 @@ -#![feature(test, rustc_private)] - -extern crate test; -use crate::test::Bencher; -mod helpers; -use crate::helpers::*; - -#[bench] -fn repeat(bencher: &mut Bencher) { - miri_helper::run("repeat", bencher); -} - -#[bench] -fn repeat_manual(bencher: &mut Bencher) { - miri_helper::run("repeat_manual", bencher); -} diff --git a/benches/smoke.rs b/benches/smoke.rs deleted file mode 100644 index 372cd0b22b7ae..0000000000000 --- a/benches/smoke.rs +++ /dev/null @@ -1,35 +0,0 @@ -#![feature(test, rustc_private)] - -extern crate test; -use crate::test::Bencher; -mod helpers; -use crate::helpers::*; - -#[bench] -fn noop(bencher: &mut Bencher) { - bencher.iter(smoke_helper::main) -} - -/* -// really slow -#[bench] -fn noop_miri_full(bencher: &mut Bencher) { - let path = std::env::var("RUST_SYSROOT").expect("env variable `RUST_SYSROOT` not set"); - bencher.iter(|| { - let mut process = std::process::Command::new("target/release/miri"); - process.arg("benches/smoke_helper.rs") - .arg("--sysroot").arg(&path); - let output = process.output().unwrap(); - if !output.status.success() { - println!("{}", String::from_utf8(output.stdout).unwrap()); - println!("{}", String::from_utf8(output.stderr).unwrap()); - panic!("failed to run miri"); - } - }) -} -*/ - -#[bench] -fn noop_miri_interpreter(bencher: &mut Bencher) { - miri_helper::run("smoke_helper", bencher); -} From 04a0135af772f8ce34a5473dcc7a350c1a80d598 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 4 Jul 2022 15:12:40 -0400 Subject: [PATCH 3410/3747] make unicode benchmark not take 20s --- bench-cargo-miri/unicode/src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bench-cargo-miri/unicode/src/main.rs b/bench-cargo-miri/unicode/src/main.rs index 3f0ee5ecf6af6..3cf25ba9cf6c2 100644 --- a/bench-cargo-miri/unicode/src/main.rs +++ b/bench-cargo-miri/unicode/src/main.rs @@ -14,7 +14,7 @@ fn all_valid_chars() -> impl Iterator { fn main() { // Take only the first few chars because we don't want to wait all day - for c in all_valid_chars().take(2_000) { + for c in all_valid_chars().take(1_500) { let _ = UnicodeXID::is_xid_continue(c); } } From d7a9989f52a392425359b81ca094c6e1986d1533 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 4 Jul 2022 15:15:23 -0400 Subject: [PATCH 3411/3747] add command to run our benchmarks --- CONTRIBUTING.md | 6 ++++++ miri | 30 ++++++++++++++++++++++++------ 2 files changed, 30 insertions(+), 6 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index a3bad3d154075..bde1921eb8ce4 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -147,6 +147,12 @@ does not automatically trigger a re-build of the standard library; you have to clear the Miri build cache manually (on Linux, `rm -rf ~/.cache/miri`; and on Windows, `rmdir /S "%LOCALAPPDATA%\rust-lang\miri\cache"`). +### Benchmarking + +Miri comes with a few benchmarks; you can run `./miri bench` to run them with the locally built +Miri. Note: this will run `./miri install` as a side-effect. Also requires `hyperfine` to be +installed (`cargo install hyperfine`). + ## Configuring `rust-analyzer` To configure `rust-analyzer` and VS Code for working on Miri, save the following diff --git a/miri b/miri index da5634d6a95c1..2debf70c16644 100755 --- a/miri +++ b/miri @@ -37,6 +37,10 @@ Runs over and over again with different seeds for Miri. The MIRIFLAGS variable is set to its original value appended with ` -Zmiri-seed=$SEED` for many different seeds. +./miri bench : +Runs the benchmarks from bench-cargo-miri in hyperfine. hyperfine needs to be installed. + can explicitly list the benchmarks to run; by default, all of them are run. + ENVIRONMENT VARIABLES MIRI_SYSROOT: @@ -47,6 +51,11 @@ Pass extra flags to all cargo invocations. EOF ) +## Preparation +# macOS does not have a useful readlink/realpath so we have to use Python instead... +MIRIDIR=$(python3 -c 'import os, sys; print(os.path.dirname(os.path.realpath(sys.argv[1])))' "$0") +TOOLCHAIN=$(cd "$MIRIDIR"; rustup show active-toolchain | head -n 1 | cut -d ' ' -f 1) + # Determine command. COMMAND="$1" [ $# -gt 0 ] && shift @@ -60,14 +69,23 @@ many-seeds) done exit 0 ;; +bench) + # Make sure we have an up-to-date Miri installed + "$0" install + # Run the requested benchmarks + if [ -z "$@" ]; then + BENCHES=( $(ls "$MIRIDIR/bench-cargo-miri" ) ) + else + BENCHES=("$@") + fi + for BENCH in "${BENCHES[@]}"; do + hyperfine -w 1 -m 5 --shell=none "cargo +$TOOLCHAIN miri run --manifest-path bench-cargo-miri/$BENCH/Cargo.toml" + done + exit 0 + ;; esac -## Preparation -# macOS does not have a useful readlink/realpath so we have to use Python instead... -MIRIDIR=$(python3 -c 'import os, sys; print(os.path.dirname(os.path.realpath(sys.argv[1])))' "$0") -# Determine toolchain *in the Miri dir* and use that. -TOOLCHAIN=$(cd "$MIRIDIR"; rustup show active-toolchain | head -n 1 | cut -d ' ' -f 1) - +## Prepare the environment # Determine some toolchain properties TARGET=$(rustc +$TOOLCHAIN --version --verbose | grep "^host:" | cut -d ' ' -f 2) SYSROOT=$(rustc +$TOOLCHAIN --print sysroot) From 97dd53d5effb08d61bd737557cce8ce0e3a8567f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 4 Jul 2022 15:26:02 -0400 Subject: [PATCH 3412/3747] remove ancient tex files --- tex/final-presentation/latexmkrc | 12 - tex/final-presentation/rust-logo-512x512.png | Bin 96029 -> 0 bytes tex/final-presentation/slides.tex | 444 ------------- tex/report/latexmkrc | 12 - tex/report/miri-report.tex | 663 ------------------- 5 files changed, 1131 deletions(-) delete mode 100644 tex/final-presentation/latexmkrc delete mode 100644 tex/final-presentation/rust-logo-512x512.png delete mode 100644 tex/final-presentation/slides.tex delete mode 100644 tex/report/latexmkrc delete mode 100644 tex/report/miri-report.tex diff --git a/tex/final-presentation/latexmkrc b/tex/final-presentation/latexmkrc deleted file mode 100644 index 23aa1a481b3eb..0000000000000 --- a/tex/final-presentation/latexmkrc +++ /dev/null @@ -1,12 +0,0 @@ -# vim: ft=perl - -$pdf_mode = 1; -$pdflatex = 'lualatex --shell-escape %O %S'; -$out_dir = 'out'; - -# This improves latexmk's detection of source files and generated files. -$recorder = 1; - -# Ignore always-regenerated *.pyg files from the minted package when considering -# whether to run pdflatex again. -$hash_calc_ignore_pattern{'pyg'} = '.*'; diff --git a/tex/final-presentation/rust-logo-512x512.png b/tex/final-presentation/rust-logo-512x512.png deleted file mode 100644 index 38484c670e01f3f355672d6c95f79f035a963a44..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 96029 zcmZs?XIxX!(mkAn0HKGD)X+hYqBLm<9YFy_rFRq*6cD77gr)(MA}AM|8MW7b3UBkIWu$C%&awg?>GxHBPM!YdH?{xbi-Kx4gdhUxCH?q zG#8h{;6LX8VBqo%eVx0(Q=2X0_w6QYsYA6R<<&ATM?>BqoV}wf9YjpP)ALz<-8Cgy zRM%-;Diocg{Yx*NHg6gvgS8_I2m_M40l6z%ZZEzxyn83|2KtA;?1%;e1brSQtcng$ z&V<+{Ze}RBw8zl>|K9M&oCXqtS)plCDk#?fJ+X*jN4c?7P%F^ZMnWvy$tM4MK_@VN z2P-)1D~yyh<_8Zr_5bgUYJk0!qYgg&Ij=Q62%y$_OB{4yb?txOJ61j$KZ5MTbC{7C z*sT8@r1JRbuY8CfmB#gzy`qY<$a$#AyK#`UYr@ofR$Hiq9DxZ*Zs7`0W+UUZ0rJ+ut!y zB{DRk+Ws5JP04-k8V`*HOT(>-@i--lm?VN~J3VN>(@pyPU_4(#(WYe^G+#Ld!2{2m zmx8usVz5mQk4jPumO%fDR2J(x3*T_QrM5}VOSh|D+)WXp*r#24LWex;Dd$1ygB!lm zew*Qg`I*A%glm1o=NXQG{~2t9UQT$fkyU!g)0AbnY5^L8bBlt`dG|#?tuv)8$d*xD z>l{Lo@|G9oym0U{l)f345;M$3Jc-zj4!M}flPU8oJoa3N)>WbMhpPaV; z#m^ErRNgz2b0+yB0gyNCZ;~feE+l;(ytJx<({_aSY3l&OTdlkH)=aKE)e!OBf)E0V zK14Lm2X(zHc{xctv$FJ;H-xX1>{=5X)+RJigl-sxo=%O|A8?B0PMGjvu)*=wP=X{L|4DSs9YAG&BVDS0RiAwBjQ^*Dy~Cfku?4w~YJ!>X~z3tO!c? z%QaO#9y~f1Yra0sw7bwiOeA9?TuU-D^Y zg0lB46ZdX|Kl1qN_#pn<68RUQS<6n^*YKn6ytjeaMiRxuVV+den0?|a2od@w@IdGr zLwK{_&3UURHrk^*{9>Fm8~@&W|2K<&a{~BoR7bRO&npmK>?6`vlcYa+L}dQwTKp}vbSae=>|}hUWJ@ibCN$i;rAd>fJdC7q8tzvsNI3uU z0hifdqX7tGI9b?wD>dg(R=t};ekumF=$>Dkr_qUvu5Wkl(M-MdADHPkf}AB^Y?hBz z>{vbU7f}A`LXT$G>Rn||X(_Elfo&oHk0SK9h)dVyX>GQJLS-7hnBCX7dRU4<*T|U* z;UMMD1JWz+VE}xgL~m+qt&IoeFt+=)Z zl8^m{oP216c0~;hZ4}k7jt|d-CT%0dsqy3-|T+TrCj4?)PRdMj){~&z_ zy-DDhL|M6`8f*i8kT-Dcl|j`KDH>D9n*X+5}AO9}5$ ziSLc!lEgOxXup_z>#g02ztyc$W>!^i<)Fbv(so}4o1DK?GoBp869Run^iP;%YzuWg z3!?5ZDGadcY@Aw?jw+m3)CDI-x0m<>kJrOF%ITzRN*xL-!R;S7X!w1Z=B$6|WJ@q6 z8oT)Z*#!RwRB=(FQyVV{h+00}*G`u8W{OwR_$spLE@??d{V!G|TC$1~9yvc=6{^(P z_IvyXxvaDSs}pFhe548^s}}TMkBM-UfK@+lFS+(sqqq1P7f|No8z%G>(^BIhf~fr6Lrdq2^hfRIQx?(`Wc?G5q871y3VW*&YfRVJ^xjoUUx8k`t^maFOYc?_S6?`Wv`CjcGRTc z=OZtF0jB5AHSj0S1b%8v>uEJ_g2v9sW>`5aT~Df#EwWwT?i!g3i5Z|GaY!!O>i zy#oYbT5l^w59WZ63a)@0Yu|#eU#~N${JaoiC2qHQ{H)pYWJ230I0Z1M_ka#wE}So+ zp}Af5;8uNe%t1v!ch9?DQ+scQ^me^KALI4ns7zr}F22H-8Drcm7+fr>B{hJET_CSf zfQlrtQq=Vup74BW1YEK{EWYWhE(g_{6{A}OZ>l>Jpxf+%; zobF$R8a4I(GkF`1qOL-HnclR0*ZNxyc5Ood8f+`#Tv`3h4*Fa=Y}j@YCw$CbCm(RX zDpn2ynAy2L`!&ByAOUvlaoT7=(k|PJBv6lp%naI@s<_7J_jYjI4h{ZB^$o{>0r9zZ zM#3*M&%^-1ksLH3cskg%@OL6A18@J+4`|g_-LE@KHrnj?Uame=N)Q?tcLPuQU@dDx z9m~1hu`h0>^^%prfCopHGo8MKh9nK%_d$ic0BmHhuQ3xG1}C1_gn9iKOL+H3_Bk{l z#@N;c2*w&Om*t;9?Qqi`3-l`Z+duFH)2CZ>3PP7xPI7(ZO@pzqV|R{_earDZHI-8O z(Hu~5elZK7jX&T6)+-(Jcp;xTG{6< z@q6^gjG`MX zqIO0v%Gra!om%GL*#Kj}&cR^p?sZaNoH4sL-m&fBUPxjEy1tyjzLmBjda#RxonI+8 zn(7w-eM(DUWRpy(NH>6iLFbiiyX3;qzXzfe6Liq`l@Wd#N+yY~Hwz z-mELtMiLY@uu#o5i;cT^O|Zy0w_MG0kuwjNYSkjU&HDWpS0K+BR)Hc1SH7?|llGd| zR(_8E?8+>+LoO}_%kbW}Lq3$xL@wezzSX>n#$;15<4O&7p$u09H~bH^XCJ0uLEAnN z5$h8}P?9-|}DVXjH7 z)+K}^6Q+FDmO<_kWVrgy;D-nC-Obus)spQf;9~GM?{N1S&64pvcCGRb)u!>uqHn+A z7~M;Z9bL4kWmQN6j>?>-#7?8VcO8PjW^DX4$9=TN)#?>7dElMIPY#es8#FelhchLw z$K;4~eap)dh;by$RXUX;$Gq*XQzpUFZf|_q>Gr6j)AhJ%=>1}J?q4|KSh$9IUKzNe zY{()ERvUY?so<|z@#z1#0CO!NMNdfg2icNM0K3;V|BkiDhcD&K)EX81G3Ys{9WKg! z`%ljL46YxDGJZAOwvI|vCyTruVJ%E`9Nf%yH$U>$${aV=ZohGVV%NQ{r*c?lf^>>hEFceuOi}wwEbfUG3g8baJty1e|(PdrB1s3fm zh*TPGPh!Oj9mWc4MPD%i#fm5Y&o$=}|t19Var3Yv7I_K-HVqi~m z90RX(Our6Og8ZI8UDkZ+r?gu?cD9bs>f3=>)rg+~nlWyQ?A&{?ZL)px{``)y4$r6a z(_!@iW7ujjBdF6pUG(GH0V9?R3|{7@QnqJoHoHty=rLa}PBZZKKNO7iHo!Y!k}@$2 zw{0RYT_SUbV3-B+4s4t{qfhV-_ot6NM{=wis}mE$r@r-^%m=-D+PeM?4r_B}kCbxS>^9I(m zT9UfWnVTujnVb5pp9{%h2@+!y%bfTs2$YxZoUO`jn@WSc$$NS!E>hf-@ve=lbC)!Y z-1RO%4DQGcN_DiU6@%uW(($kPZ(U&r+~fwJ9N%(bXR0Z&X8lcaK^r5DvvVeu5iFBr zzVK3GrzcbSe>KXf_l)Y+V@(1rI?S7f8T7FNK8B93hou?tkMMT2T2Bl9U03~-YX-aq zGk@zhxInPE)Bws=$h#6Dc+4-v&ZV)u<-TMJU0}at{vyJ!5}cBcV)AkA)CVq5Q?dZ0 zZzHe`_l&5CjJ%!M`|pXZr&^NJd#AdsV!O5(CcqhSh`2wKYyqsS>h|Y;K3wqPSa@BA z`aHsIHA;e}9;U{}36^4q==dhiLc53U}n&QlM+I6Z2evk`pW~D~ZvPLv8T$c4^z}`Zq zN=k;J>>;1hH6WgDu-BJOG->x_2Hu1XflFGy*f&#uU2-n2iDGYh&es4vJR*icZoaX= zEs0hpa|mlJ#zhCjv=J|Bb0 z{itvQ{F81-vYYL%=cgm&%ZbaU{OxE3ylnMzku7E{fR3SR+ph0)C2Ky{zaiU%YMHsP z=N-=)Lkwe#&hKmhl-|IX3E5i}Nj+zj_m!!!b5VpklgDBk5Q7${38nkMqvpd+Rpo)Z z`5&FUI1e_4@6#zGAM9bV@ej4#2|mK0xxz;6%?Q6|Ik1SDVIdr)nsPO9l6@y3HE zpUahZ4ERp^uH4CFx!37_7j`a^$8rkXoVXgU{q=qye(Hyyje1Hg!$J>~5#w81l%^+n zBK_#+!Het9n3M`%y;u1w%`gW#5+4!-+7dR*fD3M6A%OFM8E%!#OQ2`Gq-xI0&iQVAdbngm)!}# zjS2gbZ{=GP{~zdtZW2iznruX$gQ$!;8p!J52MK^mE+pyXyK0O?}n^;szP)>oN9heFA!S72$rquTb z0rKopiU{4jssBSo=gYaiC&)%YOuXUATvl0Hr%>4jcFgQoLeZLKx_b6wBUq-bQ^|(s zoaM%Y6(u`-@oZhX-8*d|tiPS7UguWte)hrEwa2B*6<2SS{YY$Fbn6wkRCVuVy1)Vb zwbL1pez*Ut)iSiEcKhE`c9dj0<)gmt>EKaE)^|Eei!5e_iPE;LpGGX1#P02(;tmB) zRa;qfph!*rL7p8sp=b-84nA;ug8%c)5c!z)HC~n3drZ&DP1xfM+JgD(oHe`1AU10D zy{sr-4!SPHOLUq2Jd}#HB?#RK*txXZbp4`=kNyV?k&u#)=C;I*iqo}K`{y`j8{++1 z^UwHi*=dqV^$uy->wU+Lo-zsVyH>(>1U|zzRHA4X0~2Sv27X#{m3-*&?9bNj{`Y> zl@p9jJ22hOdSe$uqpJjN{hXpr`!E__9XBtm@}lP^&r>-!D$l8PNYko5XQ(r+5>eI z-WKy%{6b5B+2SH&uaUL?=XYz;kw1C<{JlwpV{VHsEp}_deyV9l_gvoo;lcIE=$Su{ zXG5mK%spkQA>L+XU!E&%Ne}dG!nfb>YEL^peQ;t~_0dQDlKVS&v}_R2-CUn?F4Eof zZLEJl?Sn%J<1DAIv3BGD{`L+PYmmmz{dAkpq;FNA>~C_59;9wFSX#}5%$2LU0HfVz+vI z;9(zv7bkGx>m4Xn=zC`!OeCh^*+pG*#nZ}?1^bSzZkIb!7nKDh z=mox8y%}UPUf@9BT03xiwp2PjTD$%8$5G>bEo{Rdl@F@ZcewP@GTfshmBS` zJ>o0K{KQ(vm2{9@i~*6iYB-*$hwwFXaBL4Zb6J zRfxJPD zSkS{>`KMLwIZN}uq*s~Rb`xdmfa-QU0qK=Fs!Z7aps~Gd1HTUV$+>yM@_HD@XMFWd z3^kM@Bnji-HI4E2)#N%1Iky#=wRvU+W7I|;vMC0{8r{w2(tbYgzk$_bZO#4J79|0a6ruQ*~ojaXs#&DIeT908jVK`sc z^l&oH*qEL1iMGlgi5OjYOglTYg$)uU4DG#iDhbB<$T7ET&3FKuG^l%==_cVvOk!-* zCeVR5u+>77-FnMN_>DE#WttiN$Ps}d107vOfUp9Cu=6+m3-Z{jwtTFm9#xk+hcD@g zoFczlUqqSNZ5&Rub}WvY4==rMRVn60 zkk_Mc<#x((sD}mS@l-59x4sT>s7WgVf6ocT(Z708EbFK6E3T5Qy}jS?bAkdoSC1LD zBq7ac7FsW}Yv(526w%!I;w6-&1Io3`QJRN^eS{$;U?P`aW zg>rZmVMRyc&m{SHzp`GLpqhblLby%yAm^5xOd1@@$5(Ri+!8!G0~VJrdAzPmz9(b_xFRm)Y_0E&siFlg($FDZQGk57oh^Y4S768l-*gO*URv3pS#6tY5zte@_EIObSLS_~^`BneEMok%y)4#O8;`@;_moBXN< zb&k_UOQtmH)*i9D@I6=+AG4uK>$2+^`Kq%&EVtjeoO4y(VXp4oG$bl#)mOOJ!TEy( z*j~XPdGe?bWFO6{s}TpnLaEDiIW(UZBlKLae}Jx0T!ZN9VK~ym&w9Ip%jNU3+!lHZ zcdc;3cQ=zl?xJq;F22+Ej>37gIWYFpMf;Y*&;ZQx`B6jQmhs+sO@4~1>Uz-Jthe(H zVaT@#jN4)#5T*&dm}-4dc5y|eV%5@&oDVk2&a)oyR-A>YEm%JJ@c1m?^HYD>H6!AWYJ+{=wuI8@Tos9GG0@jL#E<}Z zNx(dqn;I!iA7hDdA9RRPi<;jqx+(_~k=kf(FwxCZr147UgVC%{h;Ko{{3Cdk1>5o+%9g5t_%LQG$#uKYl$CE1SRM+1_L9aKX&B%36 zARlDD(Xq#h14JIN!3ksIxYilAmj~g^NOwZVXk+VIMY&XF62p6>{sThu_16zi;vmYu ztuj*IHx%wzS!*2MqeaaaXxanxZ=g&BqVy8NcNIquiXwNWV*&X10{MxvAo<2K4bAZG zoU5UI+nlRzBE$uW?A@)&h_qey>67C7LYBFMY(I>i9MyL=QV{{?k$DUvxQCj$Im@53 zuAil1GVZ)b#zUVXp7TSh1ccwbeP1gF5maS(InM$Cc?h*FJ%rp;qHArn&$VU@7!x}^ zJMKw&!!wi}S>brqmzxSPCJA&ryic9}>z+@mX3`t(PPrIBG}PGyQkn{_2MX`X&_yoU zL+aIl|4Km@X>b#;`Pq!vb7irBDpcEEqkYb)Z0Y4ebHm;0YNR66M#CwaQy6`d@-k;D zAwQshv(sn6;#G~j#TqQad=p7ZT%`+k-y5+f+XXD6x(v4ak3x^Rk><8v2q-jBl?PdD7Q1(-sk+t^yYJ+3k@Oji*CWQh)J5ic$gRfcFkA5y@3TvV*i zl7iAb<$F!36n(Xb{alkpP3YNgw@Q9NoAZxlNVno#v^mWA9DNQMvJYl41Ki?EhODO6 zM^9r4)8z#dL}}I=czAXS&2$*WxM;rV!gO{3bdlZ;LOI!cCs(qLe6IZd5u=5?S#wtr z0(@r=QK|^4v$#4OgQJZU^dD7r`J~Vb&qzBIUp1Z^RHfcSeaBD~KHwius>^}AdfzzZ zmj5H1IR&LZXuVeb%+bwpNl3}g&nVz1gLzadqLSv1*%HCQwai1819Ohnz zPdoe^`*pWczGZQUPo4M=ze3uCTX{{WV)&-i)n4roDn44v{<$vKc$nKKi~6K&+mW=@ zon(GGDMnZuh|{(;O%i#tMqzTY0~38Yfsf>7-VdOO`L23Ua=jRlt|39V(sy_ITt`Cf zW9X!HQ~C*1Gm;9ieL?Fqn^P3-DON;HuM8tHa-hE4G}|Q5w-%~Ps&f|$K}yqqH*z7pg-{*eG1()5-^$^ExgobG-7TjFqqKJI~45wUAXlBYwc#uc5V z(Cz*Z*RqJ`80Mc=GQV@zOBb)5yN*7kA|xhE&=^y&73ZqXJ0p%nmw@>mTY`AuU(159 z_r3ca+n;m8s_>j`JyZ{NY}O{aPu8lB?)2uP9j@#oTB~7I1Pa|=N(LoV;GfZY-c1UH zyqGHbIMkEVE|5n@b(wR$SPst z;~WbHpdwkvxPL3!1cGC--n@OGUWLJr^L6KW=_1|ULGuiC)Bu_P`n=lpBk9mQi$>X$ zjhc?l{=bip&s;eP0c}0ndBE-2*ma&oCj*sTdZuUk#1fYTVi}2;fye7xIyvz!Dp@rOH_PPMGhFVllnPUFPE1=$)fFot;fHl|JE^`tAcg|6t9#!y6R3vfq zt+-gx>*iU}0jD~xMPqPZ3Zd4Py66*HB_5!2yS@tq-JO?u8j>w^pEBMLJU(M%#pbe8 z!rZ%dLN8Bd3YLqJAJ@|FJAF(&`*qi3QQnUYj-TkMJF3}DBtHo_I01g+{@TE04z;03 z?5q|%)b6WTi%_BrPfORZz8*g|-5TOL++{++WXeQ*uFLLBfWRl>^zW-F9;g2o%}wS zXT*3yjwalmQ8UFAolf^XClZ+kd<%_+}38lH2M^X+YTg`O?GxA@E4t8`T+7O+n2 z!adZVzP0mkXJokXJ293@4uJ2JjLYR3((E84C~4rOF}chP=fR3Nm2X0|DcW?A_mq^F zbky{(AeHuA?0vwm!}qpG-t0&+M*GH#%#m(c=yqdj_>twwpB}dbdk^vtfylcG|8zU~ z8+qp0so!o2hSC&9TF?PQbB(8-yqO>U5~>pP&(}~FMsKB9p;b%=RHKSmWu1sm_59c*z0EeyWSx5djy+LJ>Ce;`+F&eIS|iQZgFTu>V2fHUfmkP#7?jRGtktp?hO2 zizuT`6ip|p@m1OLFz2J_O`V)Yv|xy_xzT$=qWHH?%FT^`xufQb3BqJO<_nb*p7i8t z?&GtxF9Z2NpURe3S7Q3E@0H^|5aa)8Wgp(Fg(nd7dybL+uANf__`ddDW}j>|Jddj) za?rs?H?@1jge*nV!5If5OS{+N(OUt=A)2PWZ#{WTjk|AqI7400Rg{;vI5$}iX)WUB z$NVCVppd8EaOx&BtZB5}7J@vL56;)so}-!RFMny<=s|)^ga5F-4U@feH$M??Hn)Il6H1R4?Vbv zmEDc*gh{Ova86D0AZ{L+Y!6Hl2OIO;44_uq!$t!v^7e6y4WizlzZX76naeUR#sfFJ zV~aUdSVC=P_5lr`?9e2%6Fu-R!Hvm1*vwWXNQB~z zq5WWOY&dYf)d6#SEGT9*&)NWz?6(#QqBc>Z*=w+pVp-KiSHx&X>g&Q%q>N?3pNw0h zCjK&l>>i=@(Exd-tYQ9(CF+%xdZ+>j7Zaz8Ng7Y$ib$I!HO^wkHrQ?87^j_0C*3l< z8PPE(#Ikx;(`nSM{UbXThMF2-c~g+mI(D_B+vmz!r7^bCkXXIHYE!%=|K0O5UWA!0 z^rc`7%At-OZbMN@qCnist4KWsCKJg6#|7S8l&96iO*Z6X_gv;-$(pLLeObU5%NxK@ zTMxG-%)_A51R`aH4y8tV9ZvL74Gs#;zJ(ee9 z&e0xjvYE7{u}kv+4yAH^d(u%tX*VSF6fQF2g}ZT zsBxfFitPun5B|!+L!8gShgBD=0sm+5y<5op+4zq8jRx722UgU)#N?x(dxlBNPh{S9 zqI&yI=~g$njm8?Gl+q_&xgy9Xek?oxxN9QR4`1@0XLXuu(d;z!O?Hp+zCKN=2wGJV z>>4+Sqd*N$P0pUAe$QsXCt;kj-{!Q|yFJ+)iF0~LxCIJW6l8VzJmRH%$hs!~xRc_O zCQUY#+;u2^)9K{KN^!VBBo(*HKS2UtpB`lV-O1Utlq4|Tcx291wL4G`t2}YldA?a9 zu1At$v5-dhV#{ySMLtu>q!m_p^A*Yy#0vUVg)3cUfqW>r&?eMu<^Qt^QRXyBx}Tkk zX&7bKBd%LJ@~&mptP_5{!p}{be>Nwao^@-lU!__2`FI%%y}Y!HP2AHpAX2nes1$O7 z8{e@1$1Ik@$|SSdk#z$7nHcHt!{MF&?P~o)YH~k7YMBdO)4Otgoe)F) zXF4}lW@y>SD?k{8sM04Ecfdv3ZeYJCi7#?5J3Y1QGU3LA%-zJyMUCA#R^N1?td}i^ zopJ7=^le-hIn>XRNYS$?o$!g}N({=D6+U=;O_DVG@T`axxj&%2!SuLtf)6-!8?l^A zwUEs8(K!fA#Rhr>MXK( z`G3XDBFblvA?~O}e)($dO4-X`8ngTGI)ctN>z|R3Y^SkPQ9m!@Wozj-J( z-}zk<SRf2aL~MseMN8ChVo3oxzP`_kE13hGKJ5Uo;DV00DmW;f!%>s05d2hICk;|(4h zpNzqszjgE8zR85zekDfGVxy0|{F4hG$#_D@8H~PA{cJGGt?W~7 zrNy9<1DW4-iT}P#I`#ciUL03F>FQvZIH9b^u~AUTXIMiz1S>`K&pEBjNh%4>9@7M< zR1oD(TuwT)9Ne$gIbBPR_;3+!zsQ~bYQTh)J22UQIGM>0THue$P-O@mmbH%D(@Cna zNj|5YvoG@yf&sLRg?B+DAba-cjal?*6wH}&_VKb6>wEyXI|d-7^1pI~AZK#zsZPhC zzKwRMp3?2p0_!dS3$9vd0KhWgOp682aYDaNCs0a@l%acVTM;fNl;|T>j_SSCsMAN% z(8zL@L}7CH8?qy`m0_~LeE)Xmo8R{Ze_(q>elf?jNbDwx)jeOnEw*XM-^F2z|Bia|OJt#p^SAm7 zHe`W5RptJ!PH8S{E06Iw*C$s0{8HOO;##Wr2?2;oupMJd6P$UtLwkPT9R--?!k(NP7@j$=J=+wb3@%{dX-39Ews(geq9s zUzByJ`U$(;{?ee-$JiB%; zHgmW^fV|vdtiJ3pzY1hcWD;Y1Wm{td{c26bXD`MHy# zh(FfLzY7d!%I&eg$8PUep|VS=FqDWOamg?dGHnHcc4%I8uV47~O2H%0x}@>5_BpZ` zDGEji#w_n&rvc6J4+uA`FogJV1d1}+=ctN-Jl{i~aE4>zBJo2)2$6Y}J}S#u<;~d| z!^D$uzR8XLBVw(Ck7}A68Vv<4-C@l5&-9C$qk4;z@6T*GCbtwRf*hW7;+5Pmze&8j zK^bHJc}j_zHJ2o??%`?o;5yl;&E=0gO{f4dQcK#XW~G@Aa@%82^bX3*({6Dop-5DZ)pyeZM@Ip>RfqZY!XI)hZW?; zd@b-z@lsjL3o8jKLrDpKER2vieeZ&~Hl#HM+iGWCUlWbey}Y z1T1=}+z5nk!x_?@-i)}1L{ng9EeY4!qI zd*9Go-jU*)f{wK|lX?fre0M;YlVcK$_;u)Gm-6)8ggQGxhWit3}j zyWwP1=EO?DhDmRfJ16mevY{Z7$4-8)=7~`3*-+cYa85h8K|B6VOzsZ~lNi)jW$Zz8 zxLD#9<}v-%eec=>qb%s(90Q~AE#${RWsR5}*bsYFGtcgDS6rC^fI z7Rq$BpKd@$Ky|#ae2Brx8ks-*6TN#T4M4v@w$BU9%i*NM>YVk(*f|7#vEjpO?iH`P zbUDF?^77+~7yu0`&JkaTcO)DIyOaLyiFD{n9Ak({Ps6eIP2C4uXVuz&P^Qb=7MHw~ zH~ZfLF3v*4N7T=I?EE53WIFErTYn$l`z$DA_d&X3iMhQsX~X@5T`^&n_*R-79?1;3 zBS6+CqCRfJ;~L2=`F|FY-jkQ$m3|YXR6h&_mW;gGp3Xh{RQQ@d`0fCIuDAi`RN0uA2Az zAC2rsRdlWrgtY>Bq?Wl;lmL&)_@I$|6qjmTAg_S`yOq0hOu}Rx?+oM?xgL0wOzN5g zwhfrVkge}p>H)02MTuARz@?5_ee>Xo8YjM57zp&@_08q!ef%ksq_6}+EKZjj!NBVi z<0Z}d2FdWMwV;*e%_rvKc3M_H--u@e0ov^_S;w`3RoUWwW+ftY(`EyN^<^+x-9jWWJ!cU zbh!{F)<&UwJq^fF1^?G=u(8E^;d{Cke93L_HZnZY-My$T{z^7W#a{+x z@3Y@7wIJ1tJdzOx)sDYncNR%n7K%9%5~pn3hU}L=6w)E@q#R*4IG3@=uTd?VW!>zJ z@mB(^(8OUEq00{rGV*gbcB>kWuhtIPR<%srsj3_bFQnKUd_>T9I)S}c1;}E6Q=%NJ z!q%=if~X{3fn4Ju#9Ue|&k!aDen}kMp!gA?O;noN_u8w;YtBWmP+sY@OIYj6%auBD z=x}$!dzIZU8GmJd@6hhw_Yq@F7Hs&VMu+4!PU_8l_@b=f(iHi9TqLg=uQHTMnGcsp z*r~FMv`DpbNsfojKLx--sV>_H%>dYdO3D=h3p`=|w=n1-Vw;Iecd$!T6P&$H!~7RD@?oJOsd~7Uo}T(-FL~Nz%j`WqFCuOYgey z@{(@k#W=Hc?lti(yR#%2Bu472J_(VGNIwsBdLyg7(MeW<_sX0#Q6rH;yB%i}Zz!+# zR|MTnp^Ptz-To6UF`7b_i;+V6H6@6|lwPtv<0hcii~R$b3W2wtsEe#@d*X*lPQN7; zQ==^|4p#r9i--f5Lb6zOFQCNMmnts|y8p{c4-Bq{SYw~@V2uRyf2O#0m`Usl1HPA1 zD#TF5Csqfc@Dz%j0r}#n$ys^8TR#KBtDK32XDUgrP;&Zi{+!_fa=-6?Wyb~vCuMBp ze%;J88}{1sjye>ze8Q=5H;J1I^?l5I*{tV;9*Dk!PGH!jPg>Y$0Q9I%c$#i;&TL~} z8e)5x;FT#7>$@i=O?Ym%jcH>%@UoVB>gfUEeERpCd`3bKV9>T&Z{M7Oiu!GK3N*#l z`PwL6*bXE-{t0&rV&Q{Jy$^4qrJcW@?@J|^Z#A#X3w{f+ZoQi{ehU}Dt@GH`SsTsb@kuaN4@;VYep_SKJ{08b7F3XC!cy8yv~ z8ESH~F0eJe?2SQeX>KoydKt^O=;SGH@KqjzdItuuqWXpXLY=ComV6}1lRS$_wq*B{ z9{9T6U+nmQAUSY+lGECiY zLWFw<0jg5BJl?GJOsC6p?{6l&5KcBm2}4P#1C{0LRi_SNGbZ3LVa6&sdfj@VIKUds z%-NTy+2yBzx8TQH;*oQrMNgz}>M&kxW>8Xua)R9I6JIr@fj@;Ae1@)a=prxx4<~>! z?fvR>PiFf_h;@s#8yFoo(|vKQ$sqTsa#fNl-$aj0jmkbsZyELVjVd8U*C7fJe2Hrr z3*JWo_fgD?s4-nNF<8>}YcXNUqx5^N?c3$P;*`Rpq#iUk+u&&=)&g#)OQLKKy9RPE zQ&!!j`QYNMbs~Xv=h|;!5?=tmqR3EG@t0=kjocsJD5pgF3l@TiK|23{bALmGw!@k} z!M643xPhaaH!_8oq8!J@t-B3yZkVWXD`P;`ya?Km)<~VIs9e@ej0OfUG={_|2}AEB zBJM)!8-R^a3<5l0%8Da^eigR@o>3_X`yx;J%Wq~F^X@1H?sF|kZWQL0=hOYYVo17M zji=u%GO*rY@F3b(YU{O74D8Z~+*4Z3ljakoH^fZSMO*SnVk!RVN%{{%cmY6aMZ}pV zrg`kIQMc32IEuN{!>ZFb;!el@4yCKZuxL2RgsxsbMbl}Gub|aD;l=98^|;(rcVfAXP<#2u#)h(Yph^*t!cf76JV$44L{zlP8Zz zr28c1d<@L!jc9H`db^R1w%O#*w!(lMmp?wNFhvC+ z8pY_{0_QXHN1eI!XLdE=Fx{8iuvAI?<({m1J58ckt49S9JKt3qseWlebY~yl`GXSq zohbP|8(3?LwHM>?Itn}e+IDk;&{VupfP5xccg8a1|4SN_!y(7)&h-K>W85w=xr0sr z1QXCvfF`~JOA#nk;y^ZF-G!V*eq|Po(gl|~JXsbhX#A+KproUA8En|T?&$)DI}AyH z_;qp8pohcU3X-#Ek2~Nz{tCB?PUh&k)t90zLK#h{@kCUnQu+l`&JLLGPj0H3zlXON z^iaI(-=tE+dQnj-Ctuvp!n~I$rC;veWKG85+yU9YR9O}!lX-$8r^)M_o!H1aFCNv; z>hKi!^RuMvPq_&@rpn~x@%6)Tqf@Erq?$9WXFX^h#n06MPg_{3H@yFIdEhQB%l?5J zCuqv;P~dP}8`n3|=zcVDTA<1xVK-!w#%>iKiDP8%zg4E)LfWDnPPKYd6-Cs$F z_-+V)aAfXvji|qC`Q&Y)UUUr4e2w}#ZC)aZE_C?chM?u87?geHqPf3=jMyGY2~V*|!(?|bdg#GrSBH}(r&z0Yud@Mueo@&M@((y0c_Ip1O?epgQZI$V|KKcbtN&GQ6~)-A z!GP?ec&((DVy>C9m-mt#{`!_W(%GPdm7Sch58cix}h^}8;A`R6>ZbMATG%VW7Cz;Y8S z4GiHUMLLTsJwWN?DZ$wHdFa&!iEaymHA!+cp~+kG29N-(3m$$ncy8{){9qe|8GzT* zS`?tYG{s+}>k`iyvU*E4?;%?;!0Gp85}(u>_PV6ULh-tKM+}pEx}2m0Wv!_EBFA*V z<22HTdyv8eDdqW`gFVxDy+G=}#76RoUn;rHSZy^Ap7=V{RCR{HY3Rw`U|=1N*FxTM ze%?_3+MM+2Cnp&9R`d#<_+AA64uXkoCuqjz{|Pg*=SpEK+;+2Q+bSFNH=g9iI{%dd7N&PZmp= z!2XQ#HT+q1u^r4kWqJ?HCoqH8y54qTgDwqyZ>m?_J&cHTNBZws)AE%^Bfq8_>D^c1 zd4dWBFx??#ITvD3bd%XH2}JIbsJyDIBM0SywTeH)v_P(69u(>h_Nn11AIlrmyQe9s#Kj}s8{r6_t#Bbunab^y4?tZ5EM5a`n5T)jst{B+#I9F&#>MMGd zH~92QTVY$3YHOi8U@*p)#f5!+G)DnNC`Ru9(`b|d|RNTan5&wM`w?q}1!+S)T?Wrvyb$4d2l z=b6K3FiJK7xFwa?>2c(JN@w$%hcbHG)`Ec;G!a#J8E%XPGPoiw1AqjgOP{oLHA3@n zsr*AeZ#$H=3L$}b=>if}obB@@!9>86!;@i$H&aa(T&D07IC%Uif8TEVkq6=gcFdB3 zZb3#}BGco}nX1Ql?7DdYoVOX#UWq&qXS7~=dr=olIDm? z+TQ@-)geX9s6swgye6kqYDVDg4Q_J+M+S%y(|pV#6E_O76rI z^PcL$`b#;i+I%aW*|%5l&e{s^4s13>T@{o0H-$a8Z?!Y(wzzhb{ua$EihIs2uy`fe z=tri}gbGtT7_zsdY&G=RjHbb(Y_dX|#mGfebgVtFic%O$RTc&Nq=?r#o+}A#cZ;i8Pq|X?#$-2rK)^9y(%+f&pDqT^BQE?OilHp{6 z;KL)Wq^GR3zYbGyS}QE|g1N6?{oC!$)D@6cT~k^C_I}Bp#7*!-=2_9>?pSnq94b*D z-aDf2bg+G@Iu7TI?6bx=b}k>@sYF%!B@okPt5DYe!lUyzxrpd@0qLLZlagQ}goe5V z_pQa;W!WS%6E<41ZNKT^>vhA(z*QC+QFJum@a&=bV*k?>oR2Ky#NloTWDtJ-$gHIdQBP_o_!E^}$S_K)&K zu}|(ES(_7X6ax+NP||Uzb6+e7UJp@28S3cQo8LKH44LUYUYAR_2|c$_ox#uAUE+35 zevN;a6Eay5cK55p)Bdy~x9`)Wj4u%vfQP>45IfKvdD!aE6n11RGcbiTxTQD2JC|yZ zIifwFq|JXQZT|#S-!3xjAX2yibL0L; z)8{xv@cez5Uz2SuLR1@BT5VYP$bpc&xXc#ips}*lD;nMwq9omQ=(9q@=Y}hlzP3uhxji6j% zDW9C`6ly&qxM+)>RT#4f$E5i(JkKBFxEg7Dy;I&YRW=_@wlQot|M8vpf?89;y`Kjo zbuV3k(fmc#kn=Ji-R}~Rw@q6dVE8o1Z=sT*tt{wPHB=Ao)#|&(Oo)f_Y!Jd` z4;sn3o_?I?EjlCf`ejNpmnmMN;F1!8X=6$0Rq_$d!y$q@${Q@q8qZZ%1W4Zr+B+`u z^e^+w47T^{&VhQ8ycNL^uy<^rdOT)Qzi*L~I$+W!zC4cX=;UcBxKm)u6tmc{i(Y&O zp5h~(Dq^%KMkW+;rHRg|`)3tXV-t$`qpUS0jjy^1=BXnd?{j>TE56!btbS75g2+sY zGu!p+3n;WXrn%LVxzp`Wmf?7p6!*1KRa!lU*>+c%Qzr8&fkqh)M@2r1K6|>|ElWR#s%7{3$D~r}5}_^E=NlcggZ}qMaortzLJN~aB#We5Es#pLxF_60I_@-EfCwrYci92UPHnCGL2M=3!*16^(SoZlL-s+QH6#&fKJ zyMN9|cE@`>f)X1Y=$AAgG37Nim*9|%ICLJUof2&SD3J9!V_v^J7 zbDb2=0^$YrS{~ysA-*!jKm6nN)>bG?=in!#T5yY72y*D2wR#RWG>eWpXe)nUhTdV{ zL`7LNVs%>_+I4X}N78miL`EqyBTU(i$i&8g|2=oh9+|5YcqBhLbw^#SGM=c<8R1mN z6OYCdRc;JJR`tphyLGC;Deb5#2$&*IDzVLmxd_j9mH2>%z%O~c1zX_yzsJn?X6(o$ zCYG{=jauqD7*>%5J^slKEm*%=`9%vud(%#CKF8*STv>i0cjkI zqMP3k%zI3jI%fV5#ld_%JPZ*Z6$oO8h-q@b4x z;#xiWSXTBKx7NsmtGY6V68j;x$<=gfW$Ul5Mhp1=9VU4Wcy^mV&3yNpMHGFcUk^xDmMs_v~dS|${ zRfAu9J1FDIaY4F!r^>kO_t}B+KXZJVcb;-fb#XkS?89P$#@EJfU$Y6U%2#^hAN)H1 zvI%>!wxLJ`1P-mvJ@j}C5tDgMa+oW*w193ic6b2ZZ>y#byHzcU$Ie~*aPp=H{4s&# z>2JV6QIE*wY5_x$=&(ws(I#Rws&HIk%pe}%^mr9oA9KbKW1E{|{-3M$>rjDG2)F0@ zxKy6@=r^4b-yfxsyv|%Uc9)P{DV!(G7AKwzK5O~5>b*j5!FvT=AH<_?a+8MQay04< z4fZY8>U04IjA+RB+gd&*5f=2bWq?B{eXlFw|D`(TV93)?nfvk=EnT?Xjx7Ceny>L| z89b1gdxDINbwfl;sO)wkJ`X}!Z*I#BI>^hD_M41edb!k z*V!szgh=A_MWOwex69Qlk%r^ImPJO>2r@iz4heg z!(VQ{6QV7ySs)O=emA^~%FGwBd^bRWXof6(uG{awrSb8viQdSg(Y@vWJ`-B;t2@rD zpFSKE2C`=dn6Vd3E^eKF4BKYn;CyW)A?$z~^5vZ;}4n_=uchvet~>kV_hzbpt#5rM`n>?n5Sbh34czmWNw${I@Js^Q-?I4uB z@UqJ;yguboFX?t-2%!VtMZ`lNhhJ{CD8g;ZMRP8wHIbck zZFZo-s4AUR=V)`+u2ZTToS7U<(7swbU&p@k5%D&1oNsMH|$9*gLyd` z)19C%ZS8!tY-Z(Ohv#({XL!d)gctuS`JuXyYR){IbglTHn6mIo)R2t^a!rfV!d3Q8 z_>eEFadI5<+dX*%ad`BND+V<0%;1P`ED86O5kEo$0FQ`|IlwLN3?MKOczCmm!uRZ- zLhb_#;!SW1$5`13Etj){!0oqq*KH`}EqMk9-`7V0$;`VA9zh2x*adF?)qXT>wo;Ff z*bx9d6(LWc=;ohCo2hPg;s5^VDExv2*Hnz}|An(g<09I;ZaC>Wg zv$k);YCmzBe`J1CLliH6`Q-(U>rqW5)>IY<27>YL(AH-K7cZhzF{^Rzdrltn#7sun za?*-v&d}D1wF6*rpU}rwdJjQYK7$VsmThQJLNs5nporUkb4SL%B?ReQs+(;1@Sv5k zU^QHwl*qjL7ry;@ZpG5)=nCBfxuf-&f5hVvp7#-60AQBShr8seB^uhqH@%OT56v zi#Np6!7P-cwGyI`L485jL%vb)j28e7?IA>aYNViY`KCBK65Msx zG6zpzKnk9~5CW|J)d3fft4kkWoDDY)%-RJF!{7S&X%@BGMXgT&JQQ;UUrCYplL;ye$HEXnDFGh8OH}CEK(ANOJncBkHZNj5nLap12etyaSg1IkS5Z@edOyHD8vjzXDD%`c-K*W5A zTwuMLPVD0*CW#TKncKnyl;dgrc@5sfZvTka*EN2>;Xq_gHT(-6X?Smz88f^yAT!e> zeVCliESQR?YU@Orv0pDcAPBC^a$BTh1b%U{U@iH_9Pv^lwr2;QzqI7Bu;w;^j|i91 zgQ*Tr$_o0vI5>-bSWDLZ-D1S(#j!8##CE39C3doxA~{lOI*B14Pvqnc)jOE9eTULK z+tAkqEWDwX9&u}g=MMiacq|L(wjc`GxC0fUpdF7YhJYaG@uu*!e>hFFLwww(}c zmH;#U`vy3h=iZ4V4vFO^0j|PBhq`i1g!@=Yne~@@vBPY4Aa?X#a1&JS0QHuy(BRO9eAM#w_Yb796If7%v6{j)IoWvD$N6~8jin;r4 zm!kaOM~;^6YX!S-;EDSk%s0b$KH{qZ{!d`(w};h0`e_u}Mtwr1hadw;On3GDxQYia ziYTnXT**)jIli3hxYM%*>{~lsQ70G%IPdF4<=C4$efRUS_1so9(_xZ z=kYe5u@Lu=*b_t{mgr7|USmBs=lLS4^dBjI~unLX~y;lrok5Jl)U5Y^zb^oExVzxLFAS-2A9bcw2`NX%zl5y>&pIl zkocK76Vt(*izS<;!2vCi)9TPSyC)OwkYP4cr(^ej_17hZY6YD6p|k{asDdR$F&;QC zYSF^m`z6&DME(}>ydY(S(8mz!2^rix*%Nw#%A&yQ1A&fDFTS&JOe9`j*Eo>-Y+-Gy z^B8b4u5jdH-){f7>HKZ{`7!OiiQa7Uy*o*}k@+8b0xW{*4!+48%Jj;44QIAjUogU-p8nCb0(ZI zUxMzPo0b&Z58gIQ!qxgnV3~a@WlRRqsrLo#rM&p}ZF0ERnf5^>F^e`c87^PMaIsmS zN?l)`e8D!=w-ve@u0VLWYv(7;<%?XsQ$b3HXI}2r5B$;41~1dhf9*=`fzPQ0agc9Y z-35mj`sBo+{sCEQhN^>0<>313`B4@(sVw8!n&sP+Nx5Yit|}AmKSKElfug?Kwdp5f zQ#m-B@q@pfA*lhpLr>xX76Glj=f#OJz21V0M)P+vek~ksKSp#1s(4Q0DYf4CYL4S; z7{a+k)+a#Ip!7>pOQ6t)U2TdW2Y=d&ug!@GioCZ za6$8!=Ww=ee-7OSFg87|4{Dpb6_;BQMJy~gD*v7L0llGw%;_|5HmF!f~HG`chKm!d| z{t?8xHK3v?htQy^taRAt2;k7Y7$PtQi44Gw-IIRXy$|rCn}H9Muycyx-St#%yvayC;*{}yJVby zn(@bi)HD{=*t!13KxS#buAVzkeBns*al1hFjSYa_5%X2VUPs9KN(wb2px4?tmAv-|u z#2PjYLDYe7-o3q|ds0GmjnrQZ7hGZS-rvL{L!yc!@6{(?`PP8Py25ohHtX0f@3U2S z$VxShJlt${P-N`OuguR>WpkG?vun6lz*q#rPmP$$ibm0UGLiq*c zxlK5*Q`l4a*p?HK8N;c73Xhjy*tl-3L#kmQPaYusmSMd{dNRNv{Z)Nt2hi^0pJ}3= zHho;r_r_ zo>;f0EePL!&i{;WM^_ZQokCOw287-$J77v}rtrD_3@g1gY-z35%AmLe|N9GPIraD^ z{{sBhovyo@WK|sdN9U`9 z`uEn^3j{|LbkvAFG+-^%FQ z;M|Il0#!i#f%Xw?6GW(;1UPb|q{-h9abxfa?}z@HLxH)j8q2TV5sjYl;b<=5|RebB3HQy*Ux${twai^?QDh0GDxf9$@d)I4Vx#%+`JpEb#PaH4GPnz z+&ICp(Mk~2-#FoVyQ9kzm>O84x>Z9|3}k8p;V}`dxJ-n66Fe#09YU}m;CimrvJ z1fXQUl4`x?F~3@#ii1T0f%wG(4EW7>TF#DEMZiWn0+;y|GA(0=qapiw25-)WP#ae8 zX4)83a~J&s5!$(_686E{4P~5$Aedz!bN)LToZi@U+4p4wi&%uY+9SV*e9o#ux0lo5O z-F>(2^PIk|G@^z6WncksV|X-g5a2o~aJ&i|;uI?6Q*K4c5+q9J?gOU~#`gtQ88^of z55L|UcI!tEU1;xuZYBa1k;J%T08%JSjtG1YXgUn)|EEbv7Y9N~)}&U_s-r%KXafCU z$Gu=M=St%d{u}Mz{*tK)WWbu5R*T^gK2=)s7pRd-B3`fPeEv-o(Z?HzKhs`f<&eeF ziLo*td#4jD&`DI{uxWFjgndl;aM9%Z-}8gh_&8Lk29o#*76Ep)3vc2LqzI2-ryBhI zX1pak=ovhd3~k1RPGYaZ_7g6-8IQhwWePMeJ5-eo<~Ms->%(%7>*T{?#M#?M(Bfor zbZ7*R*oSU=4iq(xGUnqhPG|0(;;#(h80n3g+l+PYyjk4*lCE)U`JCWz^%9t?LwWPo zwigHmkd&`Zz&RiAa6(0_Sq=I3h0ZoOxu3qR8#Z+A2T#n_BK5BG;eAS%UYPb@>~z?x zA=nOK#h{O6EMv~|!(%R>q9csLQU-mM9tC#YM>`sU9G=z9y$EU!zJ5SU&P(z3v0Pc9 zlV1gWyPtrZZ6Dk3FyupVfONVd8l*E+ZcKEfZ7-;0== z^_=I%X}po|R@e>IBn0K>XlN%B85ztZRR%VgvzBBhRnMh#Q};D(rGL(kW24he-$qIP z%JpU?x&Au0CKdk}&-)GWi*IPq6?)pdqqCoVOeMmc&T~`}=@u$86o<%_9{QI4x{~?< zox9*l{w=8Lg535>q57eW74(s6813QZBz1&u38mNj5D%Slm}|K@1-^_!F{Lx!L^PD` zIHDGJT(Gh49u9=HSzgzU8)BKk9Ber2%=lb$RpM#}EL4)h(j`m-vo;7Ps8 z;#*?N{@)7^Pp^|Nk!HSB?x1$m|1^~VSw9CaY2F7^BJ7aH`KfNBr@f%yc8?p$3ShUIv*j-}TZ4%e7ou2N*jksz zfQMrvsl^{&Ik`(-36jNOx+_F1DQ`y>bViO5vBFAWr9A(|c!Xu#i5M_Ird-lkeQ_J~ zHgr_WUHE1W822GLJTZ+w*Ve9cWp8JPKWee7t81~ls3>?#qSx-_*cqq)M9|Ou)|k=) zJ71O0|Jbu{+sHnSc{ss5+&3HBAKA>wNb$XM_#y#d?EX_09+*o9azEiYztyZCVs7j! z>(wY?ByZW(or0H}D;Hjnaq)PMynt2~#S_cw+TD5%l-h!vIO1$g(U!3|{kCNH%VRzF z5-drrq8V|3p#pNI+SeZnbeCXivr&~If3B}R=74&g_YTwm|ebqVnc&+!iE`J*6u0-2Pv#y zx*aSW_uldX)rLcP6Z{WBv}c5c)TPv}e7M?GZ^{YILtEQZPYPKDXI28Xl$D^rplWL| z{z5fO6obtaBg~h1Ps=VEV7f_*Uuxat1Ia>9p`gWA_?Wd)++Kki^%lfj#6N^Z{aJl* zwedO4h(p7MxoqgMacf?cATtOJESk#kn#dXEr|F9cBilpdc-jrH-0g!{-gX8F*&aio zI!PDjywf_f>+75a6# zmz$}+QzhEJmS==1jw8O#OuS*(wnumydSs1InKNY4zX- zZmGP?HU7lOro}_7VI{WgZzki#hR`W^DfWA$7?}O8WB7j}VWEZE@*ES9%un2DaJY<4 z*p;!;?O|0U1*QGR_QkfGCej*s2*ywVtLH>bfH3stUOH*I^%V z=$c($!!DG=u@~4`KOqN-99&@qIV(vDomR10T4IU><9a(w0Plf$)_*NTM$)eBjhRBmUNsk<%z^Fi;8! zxp*_wCZ#GY?-R}(9$QBP+ww>`YcSUW*i>>P)uVSY^zXN3&0_%1hJCT~osWJ}zKbH> zyQGMJaQ`@R?=DR{?CwBU8cX*IEI5qMUMchpx?rl0ksQXWKxy=}MpQq;Y-6KkZ#NRy z3m1zqo6iJ!T-)D5kX@77PvqAGoU3L(lYb8_;)T|*fqisR)e+EeN9^TidXO#qxev>= zj3JOi-_C9dK=q@dl~9X{7_`lt>Jq0eW?Z)}%bP3;UFNA0Uq?+SztQ5Z!tFPUmsOACJDZSIFH;!80%2u~zr@9+WH&bgW2O zB-Pe9wqM-f8Cvf({o1{Bb-jS)|8bJPz^ZzZS|PIxD%s) z?v|gMp-MFdps1d3VswO_Lj2%bu&vwCkORm*z4p7^BK`1619xsMFvU|i8GTTSa!8VH zF|f086v=^~S6%Ia41_8p6$3U3!1%C$uLH-w7B3C#59C{foQH4w`JVJC-5;eCnB?|w z4*A;3`WP|$R>p^{a=)+F4wfwAr+u*;$ND8F&8QP&qRlDshmKFTo_YJ^u};3YXqT8s z@}~<|-F9j*G|NVR0vFNASX-*+J>cWWO$X4cw41YgUvEYr;IFr}5W{!|BU^r}!X;)= z1R#=)MLyy20%a5Fz*U$WO^0>xl)8@1a?(tw%-ESTT&69d+=ME&gT)-F3|c=&%2V9{ z9YsjlY`Pqv$-cLRxBjF{Q#sEJ(rzk;PSCV`HpEOKy#@lb*wWSoLhZZhoo%};9PQB~HE~8e?nh0T`Rf5`uT#{cTcFD;AcCz>1i=5TAv~`M-k1MFe0P@L~00a>ROePSUZJY4)3N_F(X8hq3nhGG`s)XYm;3`9J< zp8Jv&Lx+;LOG`eHhDy+(X){5OUAU$yNrHbjAr~!%z#yEUGZCkP>*1&(DCC07I8JdZ zR0ePMz;XGOTTt;;c&j~PP2zRV>Ig{K|AxeHg{}3=F;BA2Tw!2Um4WGQ1!Sdl?MPD(uD)~iY@d2&um&glTI$L*NJYyO!tQ(mB-|4o9QJ0edLgv34fB}KBQT(Hk=X31G zJbrEPEb-JuZUU;i76^xc6p13B)JcBo2JxXb-*VAg!h1C$K+GvbPa89~UK<|4`Vl>=J0$}2xP#KW1x zrgqG$TV(EGm=ZC*rZ&48ciA6yWb}$2&iSj(%Ch>OE(^ zZcc`t?KtK3APTz-87(n*ycu>{lRP_!qp1Mau`=h^wiOn(^H)PG$YM)ET!RNEc>~W2 z6^kMH%PL9`oQTW&tVW2(0q=peX!VQYhZ(??vC8o}arQalQb(-N67eCAAnS+Z_lpQ3 zmk@C89U@Qx1n|ekfn&e=sH7JZuN99oVFP#Twt#+Ac0XjsJWITZk^R=ue3$$0!;0A{P^f)xFu@ZA;o zOb+AD2dapP$|CIzWh9XtfAVs7?_;R<2W#K>iiJwnJ`9PAa&~yIMh1s_d0}`*zUoiW z)hz_DdbBG5xvECN|4Sy$m_H~o`+0@Om?8u@g1Iz8E4yOSoF6Ip{5(P#Ad=#gSB1j7-%P4Z6U@H{N?#&Q_-3o!wz9&eU9e9FnS6VnZFW9>)1BES% zR@0`>);WeMw=EPTea{c9*nFeT2~;-4k`~&GAW$iwK?#FH@MsY( z5`g8p0|aiu8BhWL=Yc^hTk#nSKKi{08Bv14z-m1(eQGy66$ z+YjV=ib70!fC2+1qvJ$Y%K8(q!`~xD8L+1g-2Zo_g`cp0JX0!e8O-$ zLpMU4CJ_TVlkbV{BNnQynQ}0|A`;&nB4FC0%5cE}48{XBiZoRK_a1;l4ONQ(W1WfF z)P2a-t7d&Xs!m|8B|&$!cIY_Kj{@!y3Y%M~l%181^#CZ_*c-hv@zAMGcH3qufZJt@ zm)BmN#>&E&OU#&CLRE_SbjZK|KDoSjl>VBadU=ei)Dft#r=vi{n)ujBX$y{H8=jkr-vg{fWwt& z11De~4ng;XPb6H@%Kp?C4U`(~ym`tZ_2Jn4&sg0{4pHsUnATA-k&!J%_UW~fia#r- zN#yh;1FNY8Nf%PAOIn}+o1J9JMGV^1Tjoa{S>^RT3+x%VCSAQX@KLU_$`OKM3AQ6WF$`&|_xR{i`{ykx=^QMkCdtAQ` z1a3nwz6HIx3VX7h!eEl;GVC<<(R7O!VGj@mBA%>~jc3A&ufTUfpos3pWb~pFV8~b? zonFw)7HPMaDTlgp*l)`qo)e}QpE6}0ZC3x8S-HX(6^MABSmojQs_8q$;4C2PkT=3D zS#sCKj50l(@mxkN3P?P9^4Br{^-EZ{XlIJn7(V?hF@4W98XkR_e6Ze67Z)iqe?r+? z9DY+6c_S2C)ZnYup&ZH$;Baum^~jh-{N{<8K~MIZe0=CeTv_-5wuu76>eSM!BTkLj ztB zLL{Capp@Z3N(Ybt*)PCBQC(R8(1cf4Lxj?K$=le}7$vs!&~{4`-YShnO8i2;kq8|f z&zvA(ydOU-ku= z@!Ve!_k6Pmi4aCj@EL1zg5=f8zDaYKY=S80VEfZu4|51;$iChZ{S{a0pu7rJ9q_!tWz98qG2HPOVJa^89w$6BnmpRsilP8rKQH|o+UWkb zR^5NEsk}e_+yPqEhGERZ;4416v)+`Ibx;VU-5e%eZcy>N7e#kuX`Q`yO^gnx~{J=B3hXXZam$e@XYu<12_ zJ^ki&$oNL^s+rV_e? zxN>Q)=UwJU9)L6xrvVb0Q_czi5f>{ZB-MI(Z()i2;3u{WKwSRHLv(m#bb+(tQkBj9 ziKCwrB+9P=IAo5Q3?UKU{G9VC<8N|}aR4uCCM;6~Wc#vZ#HR6wcH<BJ?IQHK= z z620~i^HrAe^1HqD0mN=q+^RHBy$}yEXz(Ju84YB>TuK9BPf9n_G3Y@AXHgwrWT8)3 zQCuwuSUYTgqMp_DlmJS3e}Br9&ie+lPNR;jsFK%sCg2O2Z29lpJ(&v;{fi#_wZBCP zr|=RG;TEa6|LCLH-v2*!%hT9zV0|M2RvL>ox0bPPhYrptUd^2>gxL5|4d z%?h5NVj>4Esn@;-#C8{)KfD*@P3DO$@}Zn1h#_2s~1hVc-R*JK5!H5S$FG1 z2w7l=+{UL6FHUDA(LqFkWMjFn+{DKRfMOk@W*{)DVxG&x35;v;A5-RKz+8bw*fx=@ zvGRU|W!l;$0USyGfgxPP(AgR%CsMOv=l|A8H`qo_kwP1Lj_5F6C2+|D>Y_KYSbdN2 z&irVEsCn|ioxw+&71gVQio2VrI;mqTwP=UFJ&`fU6=Lq_JTV5UmJ&h|C!V^zrK-t$ z8kj0IlHv}7(@pC#q-^>f@%58PQ)sAbKsgKr+)A602RyH6bP#Wgp5q3d2@WN4$`~&J zzzW<>Mx&Qi>zZU9vhNEdP=uat2q@FERGaax5=TyPiis=ES}^n=6$5-#+3bYWIBObI zSdrq9ia@0b``1Q@YQ+h8z4P(pnd5k@H)~%{h#EavbSFVF`FK=Rw&Pf_p`+K;v9}yS z#Rv9iCo<|UJr@LoEmr*qz{99ZOJ2LiIu!kau;Gy&(omQ-7YEUOF-a{*z%#3=S35?t z_Pw^|NZuzEWr2wy9v;9NDFMuC1wX0l7@1q-=-%v}2I#Z*S>B{z?Zfl9yahLI_-VXhZ03vDz};2hr}Jma6Emw3`XfIFK@yeuX5Ic_@QAA}@QU;gc_OU2H8jS^UC&dA#YUh%TfqMAP{(V zPH$k=k8)At3Lk*tJ-m+O7ude(zh+V*tO(Yxs$Ki4&>dhbfuD zW4CwN!kk!~INr{-0|Kvr02X_H2qN#vUnB#2;G$bwE>*BYlW9~rKj5jz&O}qq=t*b{ zn#ql#hmIM=@AO~#k`D!W?vNkT2j|ze?+#Eg5kApW|5qLXuU7Hml`i`VL1dy_5|o!U zc%gwn*w{(NX??gmXFkN^iqdtjdcz^Cq0 zTYfm)Z<#~e>@SfVm8k1HYr7o(QsfhSH^RY)S+4Jw!*U6OcU3(tX=I)r2eUIu2I$Qj z@d}N0{S&G1ti=lXMH$;!lI>?f9?&2^y6llU^il6cV}q+H>gh^+0gKXy3lFDB!}B-C5%E(z$Cj{G~$Pl&ffXaE$v1m%Pge@XH`qj;CId z7;ZnQDLv0<;i(G|uYFKae$L}i!AYd7>lOHy2Ay3K1Gvx&n<1Ppohu(i7y|v zd&Eiy)2LjP^Qw1~1IB6`dTczi7x7w+%o8;py6}Jhpl2*Ci;YF91{>RY!t(&z1^suE zT@f=BC;w4B5q~;Qmqvcjm1LB0d09^6eaTT&=qq>XbTPHvpDNR{ZNKPdJ|x4-KN=lX z-5+)D62%-i5;A$G$XHji2ore%jqdtOK3}~10hj^ti>|u8*`>)jGZ|NHLpP>2Z5XeKyEyIH1^tYp;JPYWn$1n z6P38|4Gj543EVM$|JGfZ@<^lcZO4rOoaP6Gv--+KDVzMCob{D!6WzFYM+s43{ZZ#V zDes%`N4#ez76vl%EmxUyzY|0**wQLuiRZd+83K`VBZ&2}HI``+qE(+j+fl_bVjjbi zKUwB^gwc~y_0Px3&ZzXN>;*eb0j4ae+HKYA8g8+qIm|+am<`^nza~%@AP@%IEzs=r1dR0s3F9pq`BO>goODmbRk2W7l2 zInE3GXdoab%4oQ;t9sw>W>Acz0|gP7%qIN5U)P3uUmlH*FlbB$f!uKN^&^sJ_8N)s zdhX4QdkdPH?EUo?{HixTC{Hm~KxIs4|5UH5S|oFl?D_VMgZJQq%llWcUGZ#i36gMA!RHbky&Bj2v<}o^#3@z@_4A; z?|<%{#n{Kbg^@%hltPIasZ=T|NhKqx6rqg@GnecX?OHxesq~?;CHkahh$xD7vdo~O zY-1nH^1I*P>*Y0ndGXx2&-0vf-pe@*-cg%yGI4VpQjQ4TC465pBe!a5MQmTMax2|o z^1uV`o;OPCKSOSXrUhp+Va^BQl}2WC;X`yFwSKhr*gtj{p)2VIUT-d#ED^KkUqk-g zBYU_K$S#^}C2=$f{11KlPh5CVhVS^E8QZ?@$e_uBW!>chdk|h0=Izyz9{FeX2jK+) zc2quQtc7m(td*vnGjb$u~hDG4UQq10JsGTYVNR-iE0dG6J=y<-w_k2@DIeggmfQufu{ zvxe}{2>tI`?-0{V5s_jE2T_;JHu(B@!NYgoe6IN&lx4H}Sa3!0;f zHTxQR@LGhK({3B0+Wz?mf?EN25{R*j9EW4kxVj5j@o124l~zt@{xANw_xJK@a@ zFGU2C^6ZYgd<1kl0Ud2PvAt1us^G%!>R7fv?@g)tu?^xEkH0B@7ybzC>nBAjIv}8h zhNJ!y`!JyCsH%aOd?$lC`iVPEY~Bo_va9acfM+&GPPcx3wao@Un*K zm(`~ev3aK!sIMA*OHF2B2M(U2BJaDHMJvRnZs>tYHhLM-01iJy=gi2z#}>8PRsR0a z&|xUtKg~SzZEx4NSI4`pH^*g_;kE7g^_eeY?RY;<8qaFg$aIpGDAUg{qB^@>-lpL? z@#vz(py!67quu*|)jcs8owc&OJNAB0gdH`}p=s@KXW*S>%;d?UImu!Z;Hf3cMxv9o zephQw2m08G{%M^fsjBz)&e8S95sV_jF8q`CYV$N-1%wYhH1JD%Dz{>=Dm$3|vL_ z4~?!uR)6PiIcUeQ014I8fOcAu{Pm{d;6Bc`e9VAN7oP2p``&rJ<9+Nx6HZrCK%XRM zc-^_H2!ni-G;qkhC$d!$Cs0^+8zFo&C~GN8oPE?{HrN2E+QR^9f3I5E1*cy>)hSMmH z#OI0*34*!RB0im|R5}dMGRr(S%GPG^j)VKdl>1DMY z=z5 z?MuV)(pzt3O$hyb`>(CzBbL^{laG#8qCdd(J=kjpV5|zF&fb=Xr3xTciIH&$5KW-^ zsI|$C+eokLBv#$l)%X%`98Ef{BHEOW9DIm2i|AfdY5kL^y68~af0bllPfh=$z_o8> z-H=S~7yh-R#K_hws6^PbVml{Q9P`l7 zI@XQnC!}T(y}wV~&ABLYjYjWCD0eePkP?}yP^t+63c#$`t=WEs_I>s;R~mTkVf-1% zowg3sX5Xe}4H8C-@7AY{a5wA995E(+f4*)w-6iK=1uPi5MSyNbhDILuvpZ`+A#hB^ z->Qd&L0j-0cn%9NgK+%|v?_vyP@9}jjy<7MLqAZwx5$XvcSIQ|MVptXh*ajIEH%Ks zVn>6_n@?;)AU)>e82!!EL4c2LBYC{F$F_|>Mi|6-9WjfHTCe1IAsK99^$=}aymqXA> zYJ~#f)UBMZCS;F3r@NqF~@DtP0&S_hoP0ThIOZXl;V0sI9blqWrnv_WA2pOkb8lm#tc(g)URbo)@>f0AdJrPiyk7 zOC}v^qy{xIZno++napWi7I{a;_6g7(&;b8NY16@(e@Wpj@kb>!H6xr7CUR>sZE?a zks>=?)A~MkYaK0fQXtA8Kt)lc^g01UCZ#NEgtzZ_X3Ux8@140R$47MTpm2eFFhD#y z5PM#YiufBZgcS(EIGWc8)Wwg{pDtk;JuWe*)!*0+!W`?kx7<~K57eHqkkD0% znAyaZ>u$*8SUb3m@y)3R(=#e+Rf*1y=VT)Q)#AwcHO$cQ*8@2}kawNz6*BgmUugCc zgr_zkldBg`(eKJUW@UN9nTW8S2sg5(X;j|Y1>kE(g(nlA*qp$GpV`N+eYzto2$h6# z35=IGC!{9D4>tk!<$-`auL2=YfJ=;x=OjOTuio6sCvzta$o=HlH)i{bo2ON-_7Hs_E7taO(r8sG8VVH8uOe`Z2LIkKmrn4v^+B*f9j){+OTajL=Mpg9JCC-VT3Z) z5MXLg8<##Lk@ij-d2gC53X`uFBj~Gnvt^_7H;1TEhoud8v%33lBvgdNo98d z`zyZwQkv_-z4qtw!?eZN@d4}oouh92wnK_gF(n(ePLd}E$>@zT$8UI;@oAV!K>X zqB8)dY(tt0n#YWRGW!g}o*qP%n&tOB$Bi#1!;CNS32DxB7E80oJpQYhOVsfMn^d~g zAyDk#a{b(tXoWta27y|<7&!eUYPxL>K%k5WBYt?U;0+uMs6D_S)AdrqQ*earbJ&m3 z@8-aHD$cm`Ugr7&nUWQHj7r(h0%w^yYbTo!+I~F2>orQD>&u?pdmiR-N_MM;9T`#N zJu+no6}Kk75B)9NEDF|+F?+BQ1Xi#nAHmi^+#W_VLwEgiIrtWwxHm{qaHPvhwU&M7 zQ)xl_!jnYgs4?#(JxX~UZ|X89&Dz{&WRP$z$KYEHUkN#`*K8Ejg?OP}BXsqzn9~cM zA<|-(^e;hS&Yh%Z$TPTdkueN{ri`=J4lrI+nBuokhR-2a00(I#QFiX8Xpsv0b)T_R z^sPUpZx+M8d>w~^+hu#5agrnJE8 z-Au#t*@mmL5^Hf{(kVIcC1FWtD8DUl668W5_Jr<3eWLFI#p@_zf+hg;NhJop_DaWk ze(D`m1mW#(4-ljA(nvg!Z5T0{Jh0^5E34X;x79JbDS;%!hvcB%fL*A4#&u2m$Z!YD zQbv1oCsyfPK+=ceW9EQB;w;$kFI#sH$a0a%U&pAxDV#Tp$D4y((-ob02%|+E!slX# zWHFOKdnaSAkr`*e;tW~JZ<*?YS}A*Q!jU&H-c%*4&-!WbmTD`v=TdvUDnx7gdF}liu$unkg5IFPi5I} zA7K3PW*|_ExKrvaSU`mI%70NBK5q4pYM^W{GbbUG6{G$Wk1%1oq%ztCiKc%9J%@6s zwa^j-+l&^p*!^P5L#?^V59yT0=?pSYb4bSK)hU|6!*1(b8VD?YFgJ(~_!@uNr&M!{ z-a1zJw4+G{ZYyw;3l0*n(nm5odG7nyK5YL;;N35;ole?2l*)DV7id$xlnG@!NdN7{ z2d$Mx5q>dv8}?w?dK9F?YSrg$cmcVX(mXAo$wBg0IRr50XNt0yO#a%|ux5p36}cO` z!Ex)5&>8_vu@4rFL~*W9^omra7i5UOim>rdMDN>Ee%AKKB_zAqq+#M zt@lIHv|w6~;yBbJi;tDV7~@Uh@|ixwlXGii79Sd9atpyfn6ZWEb5Isj$+vbLpQJaA z<4ExG)ry!fN*e*Yp|NRM913R?A>4DaJUzzgiOC0((bFGxzA?&}TSFS33~Suw{6w_e zK)PPE-z9h21HtrbWCz=7UG={LMlY5ANZ|fm%Ko>n;3EQ&HS_^5v4Nue5aROK#^1-; z%ZT`22MK$7qG0*!&N9-v9n`)Ep^|GZ|4i#6mbW2c*&DlS!aq^G>j@Xwr|zkm#6}?P z`wdD>Ll&>B_d}pQfx)M3`AuF9yjeJ0t5IY=jQY#?m6{fI90CMYS3P>ao^xCW>g3dj zI1#b@rvsG|qt+m{m>Cr{?Lui#%5HDX$^72|I6K)yx?w!~_Mzk~0xhNVB?!Edkr+Mf zS~72O->fOzJB(2IhBQR5Mos1_I$g*bDNk45msE0oq4dou?z(dBlDP2`c$al{`rTXX z@+}B&!?&DCi~g|NLXWR=#rTmg9#=i~%MMRN$nO)8wtU9NL9R}_nZKW{FP-9bK)o`t zf?JZszPF$>OggZo=~9vL6aBrOgH9sVB?Sb)mc#;iMn_ zqN;-$dh!D~w|lthBDtXK&o@N>#2LJt0_%P7fgVhz3ec2W+H!=i;F#8BEQHIg66;-!6a@)5@U9=v_hOjaviTPWO_ z5}gY%wX5&ktV{*X-%0j(>0Nym_#kTybZmv~e^0p6W~3AYIcwbqq-E8H$F9ygx! z_xk;5@DlgdF0MgOw2>k=Iw%r2Z_3M;r?B^%RBfgSspM^b62q$gM~dAK<`9=X)EE5x z621fc+tq!@C=Z{VdKrSJqFV9LL}*qZ!ZI{ezlNRsPUaY3z?nm8Om(=#+|Hv})BFoJ zB`@Ti+0J}4-OBhI@?bdenG8=GUsd`^>#lMMWT;>FwRY7UI4*Q*nag_#D{3Y9ooNp& zIS|=qsg4kZZ)!3u31nWh*E1zi;i-_DWA=xJleRQSh1Z`e2E4LPH@J$>IKZf=6xIE; zn#HI1`~sd~ZqD~#(l?6S4dbljC+6yeATjtFd00RIpsfDgisf;JrA) zSV3ud^LCNrh|YY5Ikm`C8$G&d;^S)0dpQXaxUbGowj=v}#fK8FOz;Tz_p|5!kI#?N z!V}G|b{*^8_0rb>_D>P&ZnzK4c>vZ^ITny>DIy^0JeUtN94_Bc5x}U8&tQrLA5`j{C8XqeN+EoW#8??~Ty*BZ?J#^&%3iZ&c#< z5^+N4(`SEl&WqQ$;Oe6lW}UVqLKqacQF{Lc%q%uxuq5jd?9zS4Itz!XuZp@rizZXU z^?yAPhs<3+b$;x`zE|26fuD_yTN^eKXkMTazcurX+@ZB!VIf-QZ+Qj6i81UDWWb}N z%QoYqpX+j@t7?n5e67P$@jjA&Xw5~@iAc5&{wn2uU+fxw(dHyO4uUOj`7e&M%VJpO z)y%v;JnZIG4;$$|B`WhLOeEX7y zFfyD%1>trK$V?cfXZJ>37&(z%-J>@7-M;53F=$L`coTRVFxOho)A|3*4Bn^Da~$Do z$N9Y-%#g5&*h_VL?$zfR*2irgiSOt1rgjalqp)3*{ZNK&4Zq+x`&Q-Viy8>ChsdYLEcH&NW&sPX*5~&yYmWcQEZi55ph3O zp)Pt|Am@cR?8+)3Voz5o1QHO@v2`CLb($Kq`S%_!D2}~S$ZXGi8EI^OZl^wASvfUw z4~KIu-p6MW&#MW9X#)A_UPL6(1T+anot=yiu$eal*ikDQJL5!LgV~FN78;<3!wQx~ zdhl#>S5UjPHcgfBZ!Ukec!vf@|E4iEB`MHkTTbLveh@tdj`R|HP=!rblwGpz8V0OP z;2K8X9bd6fE2cd6hG(;vZbf3>kx9ON<(BQg7NW0W!InBNu>pl0=p%rIFB(1*27dXd zI*BlKODJM3*4mPll;GA?5}dODoWb6cqC2^`p^;XCCE(TZDlN8 zb1-8U_s&9Ce6HFzxllb(896YwVw-+yE)dTd+lDR?vBGc z{IJCjjY3un4*Q={hbg4*H+??|=y^nq%7ABXSU}=8p7NS|_a7S9a2FY?`rdiC{~*5o z8l~@NWu<>n+CcCAMF@_clwTewEFAi{ghs@!rsT9_lVOh0PZeYw=3G%@r|->6W5w^` zpMBI+*=6lJyfx>9_4}9$i{M1=^`SIw5}WUW(tE!8S;d@e&lu)Oj|^k=G&{lDQgSb7dmo1ye_Y zy~Mk2jnqk5#aksYIHnO;?9mV?QSp^bD00j1@-2$lpAUYdSUfCWDWDQxmB$$+cOYw% z`_JYhJ32IYy*SIQj#7wg>_T6voUU(ep*>Mf9PWtUfZ5x~V^;weT-0pFE)`(KHs|Gr zs^ayGM&IWCX<8WYlT;DAkrABAMTmD}dXs|2H3B^Dv(0AdDHD22W!sN>Fsz@dCbkTx z&4EcCF7GW`Qo9oxZlM-Z2j|o9l^mabyqo)2L9*##_ci*TA-8~14fgK8+dFn}AB;~K zmVqV+OMVXHv#0$p@Qtg76Z#_KI~{F;{7&(H^IOj>IN{Y=Ngsi+0w_i8ch6iKjZkDZH)(^0$&<6!>RQ&oK$ z;U)GQJ4#DxVhBz{V`mIFTEO9i1z?=8MwPLgymWLfM90|WBfJZjCJJKh(UP|=>ayHz z#yI%#UA25r83Zr%V00_1%Gx70Zk??$%1e3jx94~p$HldU@-nNVPxmd4nVxI5Oq)WYvg8_exe z==t@1&ao*5_Pf#3Skl}D*$0Fy#WhiiH5IFf#J3ur0jTCq?fa`sXG!(7Z!Xu-qG}7By3g39v5*KEtR@>;<~)`wT5+R?2cVrLRaL{ z58oe#@E3m^POfANc$;bAKq%iRejI~pe4p?li1a$C2c(CI$YVpBZQJApG`#(DVnZjD zm$N7V&*7c|c69?wgJWaA9)!Q9E4pqAFZkM8c89AhY|h*?v~}*rQt9>C@?Bzg8ZTgh zr}tqJ$6nCZgR7mxnyR%;u{SyHdyw4G`M|ZS7``b|)zy~ZGsrPhL*2Hw7lWx1uL5aD z7Q%ap-}Ae;dt#)2H%cZbT<%)Ffy?>j3&ipy9E?(?wC^6VPKcEk%5U=hh9ZA-7sCG?4mFvjF-s?5|;~!O1xX-3! z>a4=`1+te9!Lv|g@7N!*b2|?aD4ynv+nQ*=JvdVTI+H`sB$ZqsckWV~7 z-}B2l&<1yxVpNVdp=c8`^aO2EY%hrFdl?VQCO>|V(e^~?23niX2xi?{^Ki@R^n2HQ zYRHWTit`}w4hd_(CIey%B4!=e0`3pMx;@l>-H6&!!_8Lyq$enRi##Jjk%}|ss*5x( z1fIFl*|L1zMF8>2;es#L($QoOd1#FP&=vI}tbw0KgfMsM#39Mh)O3f2^k6D0N-?HK zz}rg;A0PfXdek75J40@|8j1%X`>QmXp`jNIFX(9Rg5G?tr3V6{j0%nLl=CU#nbXVv zGPnLbwtKmM{A1UzUA1fIds5?9Kqaew(q9vAqwk3`1|xw*ghGC4_7VNmZMwRyq0-^ zchIkxzt|rWuxR*WJDk0m47pA zi4X0G&2xgvZG!gfr37}8utTvrrUSjTx(&{^?%u#tvDd<2Q?O{0RUe(uiLhxXpM1;0 z0ikq5Tvf(hMTn*@CcxY=ercA3zqN+>=E924Ir0nTu#*sUovTBYxR=*(aW&Fd2`g-7 z_Pn~}Ldz^c$u|L6#nJpze^%M(L7%^UO=PkGrSG%qF2G4>$YJb$irCncMwYB>3D@?q zB+SfAnmGDpeX64zyM!~QZVI+2)R1|T)3eSSReqcFePXh#Y7|Bg{prhFsh;6Cm4bj{ zg)9YZ!ED_nS@vcwyFnXHem4GZ=J14dV|;fiQ^6+osRk^|=QG2;vD@PLidDmuv$h|K2Zjhf;n~&TR z-EyO-1|UZ~(gxYG;m)Ic1iFo!vlW>Kd&z$m3RnS|Due?FE`@YZ`-(MVy3Y8Ye-x3q4s@l~B!&xlJjl9)N~7kD{g)!q3{N^^my-b|P@x6RE$2F!n5%^DwME z?7_)zIlGZ!|62%VFOiOR^B+CpdsOr1e8gP{Ogocyj9|>eQ-ccA)+YqU5xi=4ozy^W zUz-iWshFZ8N?(-Xs_XO4lTip+Lv9(>l!HpGv0r=BSGVZ~Em@ZwNs16YQ3}e?BhpeA zw`tcmCB1MFTPtRE72JqK>}!8|5eLB!{ugQ;_lhSeesKB9nUR} zW2QB8Lq>uQ)^e)(gOSO2@oE6cxbmPTv5H{h7jc4Ch8{d!zz9`dmPjHBq8f+xDP>0B zW%r{^6KWtB<#>eUE>lQueRW@y)^cG)vNWnVR-NLIKFRFe^PWcOX2w^1tYIQpB?@i< z!AutfOE-h~mRnKmfJHsWmBSDJVTai@syYc)y4`G03O7xn%qS)re?KdJyU!48YOL62 zx-xD-*#a!U5yfmvb7rmBvICN@itLxIEL$RfaaGKc;iEXW)J{f!4eM-_7AIWT6eXHN zfc5gQzSeDd7az;`>b&YE;i$F3%6PbK!%>X&Br)JLvLAD_**rPcut5d7gEDv2lU!PL zhhED2lo5O`WXSvd6nARZo4a0&UK&m6_84Mq7T3Pzr*C*#Y#6@ub77Us2QNJV*fg@V zp-AB}M5%RvMWK9m?|M%QQQNz_#_Fsy+S_WhFM1cXml$_QtjlF(CQxA_{k2g#6exK- zU)-7YN~3tHplBA+)CZzY;mTcX0{G(skatoFcy{L*pq?a~S=8>>W}ER}hOUfDim&wl z%wrndj{8=H_wxH6{uyT;%iR1~eXcJ#&>VLr<-hsN({ufGb6B6(ltC-;S0`H3&km^? z%*^73jNUWLrp;W$2o&+HYv~4Mb^`}CJz<|X%tU#Ik7M9}bQ=Q6ag)KW{}L&Gu?wbFoA!xDs1`1FyfpFBGLYTYd1wWX#_~Z zCWwJE)cd$6jOM3@hTj*SowNVSPOUZmJCL<3Lq-5e6-B_()eHm3hZmk^7C4X!l(wg* z*M}IyFSILDY3Atm{C8@ew;X}!J2-uRarkYe2LPcJqJF?0a5YRmCD}oEkiNwB9GWU) z-XUcsEUdbtMs9QyJ6%zpOyd}$eOebJKs zPGPzAy-bMP$Y_2$6N4hfYV%F}4c`eV$R{0tc_iQj$B-C4Ql5l;8E|@ra=)jgI8SCT zgdQ)X#Y5$KyIRp+i+dNeKd2mjoH}lK2cS&`rcE zgRyh%Uk=H^T^T#zCV1K-cSY{tqaF#9?}M?;T)WjSTc($^4QBV*&J(eog>hZN+Mf_*u7ZAa0)Pd7_dFQmT^Uhq+AXh%)rT!Olrj=0K(fA%@S0Wh zznL&@6)hG%*vEdD_tyXWhNV97{`k=*LU_Binty^rWzr{c@!aNRV|0T+Iodmsb3rQG zi;re)1;OxX`S52scsL$F;paPGxJ=Bce+kVyTa)NE;+F?@V0=n=mgF@P6<4|a=v|BN zkCh{lFZjdPM6)iU4sFRbO|e^P+1fP3MNij(-TE)OZ2aigyQdcHLGdS2j*XyVT10gg zq-uuhq#t9)dXv_N;~5si9fw_PugJKSXX;gYhg%O$-@*sjZby#$4=aFljaAyW>*H0-44WX ztSA2P{Ug{+3WUcSoHR-Kkg@=wvMI~Hsa6c{oE2HLNcLHsK4zywbTvw*ACzq*(K4u* z9zB&i_csZFx{V|T%2N~9wWY{5c%eKS5(+~I4=>5wG4BSfPi#GOUijpX z%r6MGQKkTznm{|3L)|-9S7e;I9VJ~B^0 zmE%m7+%q754L-NzcBxX|3nW|)YV4w4IYoM;vfEHRr{!g=e+T`8`kzsh+zGd>0k4CzE4lObBLhHB4V2nxUsam5apSO zS#F*r3xGMdYMA=esU@FvZpoglrBWJ&%CU|PH!tdjIzsq-so(hQty>fJ?jnQvGm9;R zo00f8Jl={mbvgn=@YT;@s?c!HtBP^YPq?7^g8@&JIyEn91GX3*L1nf8glTw}gjF-d zbsHm)khD*)UTL4sd`3NzcW&eaN{Vq6Ac3NXIk<{C^Vbd_LUQwtC)yOz^x+@`Fc%UQ z^N<3xq7gtCE~#7;zaT>{G2x04G<;;3d`YOm|I5$XfIB5XW35t@?WI88MyDvb0QIj8G?KQavlYv114CBY^#YB zPX=vJjI||eA=S0!ko=`pQ1d%uXy^gn%AsR1B40*J5PtDBg+C=nem_os=!PXUo-w`eg6e zt0Lp9d_o_|AzM-75$D*5Po*{ODPwszMQT%y{r4%ZvTqB+fPj5XdoYldLnvh~mPmge z!a+gy_7c2Ou_r6EC&UIPe{i8)=X-|$N1gcSPL=`qdyb)0A~uUh>ck*K_y^?S<$xaW zdK2U)2WyE9&j0uu*jCnYw;nd3MypQ9?kJqUA-U)yw`p}oE4@#P?AN^3p&3l(ns7W$ zBQraI7ar;?8MVX}e*XHfsss-a4?Y@2s27vL^2Kmd;&Y)nE?(gAQW?p1(>H7*ZJ}}p z2#Rit+}vaF*j?*KPGuWaB1vH8_;i6VTf6P3A7VpbEbeCh)7tdn5mzgot9F;K7Ljp> zXQ*58hk?yPQ2+rBn7|xKFnQ$rb<*3?>W5ks^j3fZl*5yz&h5BZW_J9@P07rWRIT45 zKm0Rqi7jb72R*9bgpA{U8ya^x&Os7-Z)1M#P@Q`mlZlf~{WV zk79m%#rtP28oA?oPTa$->e~~H;9RRHjQZzaBNQ8728=I$VpYov!~>khLV3E_J}0%4 zu1}0qcO{SHalMi|?EHxLP>kKkdcSz;yQw%kaMrMj``9L&@G%yycU~jG7Zf?pWV|im z=&^QXJ{wE%#@ko`)dm1RtIFX^Gxh{+6`g_>n=<67H*CQzU$lebB-+rfpzHfRa?q(C z^T=gu85Nd6I)xNmq~rDKI}tv3{9vCkvWk=AX~P#O{hDkLXs%jV=6q?zm86<%E8~fN z#W>H(k>FHwfrB$oD&H+*QXMm=dyMdX@T*4V<7ITb+B|&jS&3%%iAN6pg|(JaA~Y*7 zdUBS*vo=kPh?B#zz2|E9?;r7x;;!_&vUc+>cUm8VaT)RddwkcKYdZ*tcSD>oIJk7b zzxtfKggOrFh`2OAt;vvCDIN=(4W$RqnQlnE2HBN$w9EgA zoGXt+VWyL(2>2H<52BwEpbN1OEaxV_loK#g>4ELuiqRM1eKd3hQx+f`#vLh_7vsxU zoBbp!F4;k458n=-HKhdIpc~37q|U-O;H1mS%wXAWaex2R_sbLIPlV-(yt=(gGD2LM zO>->Zb!O^U6nTnwYQU5qQo=`cwxdgOt!Zo5xu`%PzJGC%0FHFXA-Bwq#v+4WG2av* z5DUf0IjX-LJYR^=Lge7LA@mU}TFwCN^BdfwU^9E*?)@Z81*g(0{{+w!@GuLbut^c9 zMz9DRQYV7l$}tb z0#xZFjkg>glF<2A%BoziOk5T*omMp}7DD=cLt85O$feN@70Oc?h zOXM9@+ha$~yfE6feD=W^*`q8a2P%DCENi8(wCmnpJ$N|8R|}LW;zk%M#=mm@DrA3XTV8j5cvz zWz%lrX1RHIH-alTwz!#%bCYs;Ke|WomFkz&9>w2m2TI$NA3!i1U5?d8I?+a=QvXMWq4};H@-#J zFy)mjma~Bt-g$BCFJHJ~ha%Ck?mgIS*omu4LrlO4q4w*;cne@E$YB%d&kdzQLgv4! zyW#I#j#4e&i1qGTSjUsxbAm6G@}93^qBR@YHwRx7qnHK}c1e>Q>~_K?;O&9=BYBHr z_gU;uR*vnivnj2U$7D4N;FmTp8!*$?@?ESSQyzJVo4dKL59n4ihqs4Z|1cYz%kEa7 z6~fbxx|};<->4&D(Qo;W-^Z}tP2O58YPzXej!@>rG4f6Sd?hf-s7067fX!;&!Yk69 zIN6J1OzQYxLOj=O7}*Hak_p24$3NokE&E4TZA@yS45#^Q#+dv-W4D#z9;m<`a?g%0 z`1V=3o4t>W^|T_cBph2kZQ{9C^%25IpIR(h%5gdBBs7{_s_DQ`I* zlqB1gw$3z`*OSkvQ}r|jpVbWY*A(PGk%0*=I8p&E8pOxE2e|wUcd99DTBL)H=u#Cb zzx{V%%T0T0o=~}5Y0y3@S zpkysLBSP}eHU-GnlttoZ;?fcvt>F*f9nKcbUqzwE{ZIW*CR#a`_!)pM4QgaDzGNNN z&FIuUBw%=vAd2F1&KuVN^U_BACcOyQ2KDg4kRl)B%6<80%Vx6wvy96SJ(8hb_hJ1OL%Jbb`{wt`Ars$b2O7 zWz%qpFv@I3sy_Am-0CzQqc^?CbcEgfGVoZ=8gJwzV0fW-I*bIR8X*S`ZaR#6EsNq{ z8NrGGmbejai(HEvZnx?STTrDcf6N*)B!JM3C$xO4EQCB%NntMD>Z`}%iq(-Vr)YHYJl(sU^{VXkr^b@bx$c#*^=9U z#mr1QtW)E3NdNd$I72e|2L&Ej8<cWt#i^eJg%#!CE1K9ST7hQ7=kkC)v{p^k#fMKQI97_p~dIn1wRPzVDAP@(5FokvC(I2%-{MoTC*Gayb0P>kiEv&^7WBFX$LMiH zwYn2 zEe^=4NJ}2L1uRZz>rTx%Inon%j+v8Ag*mPn1Vmuyg+mRf{q&vZ9{TbhS5-J^d@{T; ze_vrOfs=hGeoAMM0v~GlZ`0X5jV$H&GfrA8>$UWcDJ$>rCP1q7=E^mVb_w&BIeb^xCDB#7q-UeDAydE_`!S9v$BtyL2Po5CNh__Pu@&tty@c z$gKz#T&x_@n*!e|3yv)P4}e5!mngTqkp> z3*$$%W`&tODPWtU{ku;#sjuuEPhU)%EdRi_Pd;OxEW2+xoNLb@VUM1p{`)B6(ZDPT z2?QFzYuF0dh$BD@8TVZ#Yy@8D8+O|lBb#zU#G{@EF=r3?AQevCVcGp*2cL7b*2oUu zikJCw9!&D47bBRv)KW-BJI@tapA&I)iisdJ%13^ZsMI2Lm#*Ie_!%If+_I#y(Hm%;F30`Hb7^j9a@~JVN?i3d2{cc<%a%S&9Dyyxemj zQ?x&a6r?ys7JR{BucsHIo*jXpYohXv-FAZ0mk9G!uK$+;j zt|@^}LEPnsNIqLOdF}umsioUjo98kT)w0Kj7CrnQ0>Zk))?4*9QL9vbJ88h9TUK)U zJK%&PLr>9i^;2n0onJsvfsL*3AMeR+e{lRX%L$^hRI4lmPLs1~`zB{Pb6Q>$<5P{! z868=0yLp<)B87W6NT=|aWQbSDZka#jVngy_?;r|N4cW{_>1K7j*-Q7>rDVs{LkCQ^ zo>=wR`IW2hYTrnV^U+2?A&!|GNpSVae0{HzYuie5EU3yrvZpPVq@eI{YBLCN8M-P}MkhjL(n1Cq1U~;yLL5BCf2Jlm`Z*A`XoWlk+A6|> zWV~LnyaAlAHT23^TlQ_8HCE$D1fwb>0&H`hG8}Ju(DGwIcTZYIngppdED9YZFcbyoLKrL+yrlr4TQ}2zGLIq91t^uV zR}XCIIM4tf_c_uXXvRIC$$u2w*byNt-=V#o3yf=V=7^iZ?KNZXoE4ArLJM9F($fEp z2-aApO5Vs2i0u$;JH_Yb4ZNgI!Z!4b9Z|WYr#tw%&^q8MhloC?SLL91K5XhG@1w@T z2fqNzm{)Z+WQ{Hnmk4Nr=V`kQ5N<<%cb#m{WtBwCHoJhjWE zv3>o($st|?VI&dzV{`-=FoiXu<99Sx!aOIUM5|D`1H}eafC|gDiJ9dUqU%eh%6@fe zcNtWiL09)iv^(oQlp`w1CPPCFz#$g9-;zZ!C0c$M>D5l1jS`Ja36~$1nlfx$cqL1X z>U*+PkgZOQmk|f$qH9^SW6XaN_yiE(x(0;TTCIujUJiXYN>+)EiNLSyp2=W+J*bK1=-jb=&A7ohQ!gExHbgEEgDJ$CfPd7c^g{OW+ z_hwSaX+(+6Myr1LVx8!|wB!$y! zszL{vR*UVgN)X4Rl}hX7unVH^nG?7~mV(wEbitTBPApy#y#wKYo1&Uk(9YU7xP})O zx#L6W^#c|x+0`xYb5o-YE#6D5Tg%Y+shC+D5QhT^eRzLJ58=O9r0V~Xbmf6e|NsB> ze(x}I%`Id@xvwa6usNc1ARQ{PQc)DDPbtUV=ui}WR8-2+K~#FsDWVe{wkRpe z<{X>7f3Lp3zy0IA*Y$ipo{!@hj9D4_eIUC5hg!3ehl}ZVJXunN9#Ebo-hu!dxlagWjBAj_sj5S<3nVXzxCf4!(8=!k(@4vPRz7 zxwuut)Z(g73yC*mM5OI#>Jb+IDX;4CdIfB^F?M8{A=^pG2CTl6uD%mPhKCTF&scXuxK$^SOY6(LzxWJ-~SGnh6BT_4L~tyxJF27gVXB`j(}gql$5thzF{`-<9n zAT0T9q#W=JPhM%AB7Km37jA>+#mO{?oyN){^8oe%VLot??aD}MP(Nm?MCqz*k-O|X z(RFKF61Mp_N>gyww~$vfo#a_RV-6lT?5_Z8Ito+VqT6wbB{ZgZZ<-BCj$?DGWgeK| ztZ{6nkId>fg%!m3Lx?w@K-rsxZs%pg8&PZlQFNa_T(J$yAxfmHPjux}xKCGPG30tt zg*&(&m;>QfCaohBWM?S^HTN3vE2_1zBFssg-GgH76%TO5qqr`>vixC1Tsw>Ra!oHI zU?at$@xp&fTu+dsmI?OG^|3-&H?9EgIv51HkvClqbvf#&$z1?WA4Swy!h|T4HS|Un zUHnlKY)q=z;qfb&F-iXH#Nt;{Hfeb$pnpcyJ)#vDjAazsX7nZ7WOs z1MB(C$9C;T?(Bw6e{46hY1(~Ln`2~8OqGPb`s5|ke7ZK-jP4U%Qo z1#y*C0Bh*`8L(#qrl)(u)Z>6TzuHcZP^wl&0zz#qX^Ktl6R_eVdqK%s}1 zHaFxr?~0yX7%82U0UzsRbv$>KF23pD_}jlWD<5d0I(LdlVU9$RxDq#evI!Q15h-4j zW$y1*V!IhM_GUg?+4~1C{>*uOf;NRE_SZiaHWN$$Z`-g*3V5wPvF#LrFTWmlkP5Ps z9B;2uxpQd~Qu@F!-HU%o9lf`AE|IknPo(=vXWbo&fz$zlHaJ*5M{VPjy3BAslAIQd zd~LSk|5{r{2AloNh977{W2Sfwz2tT(7Tc`~0_yq%5IO1oDZu{a9DBY5e(wp)I>wk= z!R|1mmER@XJa7iC7`8B8r_l`R>vEw%B4xfl;Wxta1lTjf0!n;t`Eg*)gz~J18cp4! zw~bM(FCu7&2-q>npHXo9fERklxVXTDF)>(*9rWCiFtcG z%eK?&k3&T;sSsZSpr;c!xYP3y)X^w$9{D*X#1V^A6&-XQ*Z)@g(Wn6;)x?J^2O+QA z2@LFA0^*^78cDe@g7Bl^XUTkN1H`fV9T9#d3K2}XkR2ew)kgXkvmY=0zreY$N# zZ755kuDUDFi+_c zJz8#ivYI?9+_Eb4FCkFpDrDSh9`--p zMR%o2;`3}_Ro4{AS9pIKULsz%vXnUUzv^xPv+tog%;YDhu|?qXUh$;GU=dAiNENIl zV{0FR4nvkmjpBNT?7fKs?zOff<}{JB`#MPT6@R*TPVhCjAVkX>d5_8#IA~Z*CwkD< zsd#gZ15$xN%XR5sYHr*PhpUvU1-Hs<+g4Y0W>2+esdOY^sc^h>-2(+Xf6st;U-km` zd-=-FS5@{}QlQ(y=3f5njZpym zOof3fr;$u;%+nE4j~6#crEc3ap!4I3Mx$d#=-aZ;O_X^UN=wqoxyS4MqqKkG9kJvI6s*=Dyk zSU3-ZurAX#4Lhn1T7A>XO<1(-wdTY>_m@VR+pJXcA~9N2uR_C>CF~Pf=1WQJye6dz zylgfN`czmb02o6TmAY9K-FGs;^|JC8uE-P!Q|O7DB~ENLFt1*XQIvSK0$?GD7zEm8 zxVd$YCrv-)J$`x6BYw z-4MX5zm|x%HqwMfwE1d88~Lh74O>8bTUh;_a&YI;PoQ<+y&6_nR;GN_`M0v(%@L?3 z@AASRHo46n+*1k7RIZ57M4XvM+nZzP70+H;d^)BG4ljydT4Pkb^Aa@}aScW|{8N9u z>n&}^GEx>%j><^LVHyX37MWKo0Aj|;BksGEt)xnEoo0mX4*`kUq>`oqXp}j?5D9>8 zJ;9f2UrrcJSUn+1##u&*zl5}pG~YHdWY}dfgknI zgI`03VmUpL3PrMLc}nNus)>(f`Y5CCL@QljaErhatyqUS2o8rT@Ko#yps#kKcsw}6Nj z0f62zIQa(yM~CAcXn~PSVt>W6Gf?z>8E_@h=|K2ABpa{~_o{xH3n8*F1wb)0*IG;# z?H`@PZ)(l{pjv(v-bBcoYNI?I;w&KippOVPp)6lnsTK~8y#m&0=t&hBG=Ye5iaNva?~P5ZCLwHLK?d2LA?NTrrSeEd9%LRrd%xl zO<~+4`2el~LIu%F({g_k!23LT{_sTEf4_$b;q zM(<*ke+d-;Dg9moT&>c5o_?zaSR4`S_h2Cn^wiq`p1XI}z;}NanKG-Ppak_4W~~I+ zP2BY6WERuzbPD~4*Cqpi2yOL{s#^(Nfj6?25FvbBhwQe-5>TIj);*g6j2mO`J;!3H zbJ9CjDS+L&_@zpYT7w|%e;ba#pIi^HX*Ty7Blc@JsBY*y@Q@}tqIz|yQ_fA`Q1l2j z328C@)O`Nwg&ZW_A$>K)e~k_GEn~JuAw5V{xh-vwEVGUB zMz0GgieU69yl|fNbzX^SZDkwweyb>*#+T#cNuIt`#>`h2K+ zdp2N5WeCFW>66Y?NV{PD0P#CS$o#2GIIoi8NCVC};nB>6t*XY|(2eNh#XW$S|LVjm z1mr>L3uiN+LCgL5`jJ=3w2N~0%)zfzHkAY%-)QN*g#lrM!K7fGnh$^3Z8f$4g+U*} zfVG6!C)_Q=1$2`Bwq1{@k+JfZLt#Ghg9OZfT7K6OYBh=#(f&N6-+*v6jeoPffw^s5 zzl?+yPpWOrQ_kz_=U17u(zvJaLW(vTxq`iK(?*>e_mp)YYjZD1bTnf7o2NpD_|2o5 ze?MkV182)cT8A%T_~dJr6A)Q}M@WE7ZJF#umq#kSJ+1oVxCZ*l=-5a^z$s>m1%={z z4~0}xHdH=R0U_FcUc*H1R>+YecuMxmNAe92|9_FqrrfW! z=VrFk)6<-DGX^lpSrQ)dITQ?}bKH9Ejk^B&69T)_G~xV@3dG%#$$^Z<9ZI84TjN&= zy6QfZo&b${>8Wa?c%>D07IJM37vbk8yT`xQ(m(@bx^dd&l{U+cVRIi(H>bIuIfIE~ z(pACN1VwPWAuoAB$34iVd1QAq%o8YJTX(o%7)I3PB=X38skbG118>vG;J^}SNA>B7 zO2X*pDT(X5@vngcWCnJ{gxD$`;mrnybNvv8nh6~B9JZW@R|&Wa@-kE3P$VyN%I~Uo zr~=j2oh*yN@EFdDJXwI`dnH$kXs2eCGh=G=`SWU!9{PCCbQH9T1*|V z`WbWSanmeU=sst5IobfFc!Au7ZWK!7-oMAgd*{Lb49);n+#_5n}XU)Mn^|* zkSFn3035N)voG5>LW-4-l{z*i8B~vV-sF|yRQS2z@^5Q7Crxf}i1#Bc`52m!O176wlL`LIy4H65KvB{@1^sN^o zZbqbi|0&cC(gqudqXyvlT&2|Q*6ejD*s4{sg@*cdeWY{|+`)Zet|vc5glGvn8``invI-LS52cGcSxskbzdWNP zR$%MB5cq)Dmt&nxu-L;s0`AMrAkv*Se-^Y87*WxXQyLy7UV%!h^Ch5cPZO#F=>#5H z$&IeX0$O<_fkNS0!ekXJIn_lJwWO}y8g&0q>xM0@9fnb%Eb;)LT~8UXd_@=^qjR~`qn25c_k^90?OfA&_5kEP*n8wrJ8>}%7P%%4HN`MftHO!M2n4DbDX6Y zUC?{0d)_C4??4y;`14kpL|gar!Y$$Py~m=6DMd!nN=G|)PRe+#gQ+{lvH1x|Y?3H5c~P)Rh{c$G^3dy&&(Od>Ff!6z-FESvBbb@i?5n)k*)1Nbeo0Y;g7;^(d{JO?O^>u|KJuzQgubd~5hh-yZ7dzO1!_K2!SO2z~}|66ZFSa=w8#Op;mQrJs{hTE=vc>h$iX)rYy>+D?! zPi5!bPc#v^a=gTttrG+IH-cmyiXiels5Q;j%1DW|$7-lxMw%;%YCCKA%Toc%Z}Wrf?h!k_$Gdn_zG1;NGzEwv^57H6vghmQA(PS5@{uTo0|(Lx zVD)V7AX8;y?YfBqpV!T{SeKQD(mJsJ8cVAeqd5X@I236 z1;DSfRM3SB%tq<$a&_RiJkuc_efG!T9k0&lbQBORqm$MmkoJMSrnq{aNZIEYJ1;wr z5>N^>sAr;~YqKoeu|;n65d_OQLC4hC1uHRGRM+H&cESqK1>*eMQYC$4R=!s39697T zrK@a2`6VjA<}$)IdTt?Kfr9*We6fKz?0~q%zchn);+eh4VUl`9M)TFC5VzOwOdYd? zJS4SysRD7y32?b1Ea-dLt|MwlzcYVu`%&J8tNy=&xwFuorhh;@ELJp78ffk287hQi zW|kKPdD$p}Sdp?WSlT7e*#!}`E!vopw3-ZFE~nIzxT_R0JAS-8U>y7JG``Ev$G7Y1 z9e5`86npmF_&8zX0($L0O)~vK=jGd3S^m#Al&A-MBC&hOks?G{zZv;)f7aMND9|x4;P9CYQUsYP1I?b7#A-#rAx*GyJpr7OWW+j2 zt2FSr&AnlpC&HoxJX863dT$SP`4`Vagx6oZ!GM(lIN$5cXE~K3<6itb5ww7|WDu>= zg|gN#8AtnBgEOG-vvTA-jdT=;bFA0id2Sa$8$sN>tlj?<$pcWUZD~%)nna0b z-k!lU5F*dcIAB$T;(}{iMuTnvB2o5f|BR#1dJI`v><*;P*kN=2g)T~U%0*_nyN_Rk z*@Z1Fgn%6rFcYg7oZE>{&W^x`2V3Mb>!*j)Ii?MQe^Oq$)KFu$s1fJuQ1^x{;9Amz z)5%!+X*&CvgTBOPv)Yoq8%e_7n4&8B0M%2*X!h4@aa@PRLixKBR}x@?v&6{z^J8iN z6%Y|uZEQ2Rt?#gsg#qk4=iP{Xo%DEdq~iH6L;3cb<~row6<+Ii170&5UEU)Jkb~KUBP#w#D6s=);=soxlI0_ zP;f=*>MUrrzEop>J!N3efpfM?^tS$2!B{cZ+(UNV=7}g^GtJw$UQhzB?QBe$ZbclJ zl^ukQS_ zJQvLehBKcotGuo>vR31(&zhR<&TaM@8n*ZC8U~29kl-*(;D&9Mj{p7yj%YJ1rtxWt z@B(e-obk$w%g=Tig2`xZF{`;PG(S@H$?92FIx~xsxO?Y$Ic}xj^VfJHX&V zrQ;)QtP^NEG4zQ)&+zkW=hD8OeOGWI+?WY(fcVc7YA~@YOf&w(QLpX0-<38e(RkA z?L#wizMhHl>%R=~mi`nNHg`BmJ`F;<1!yn0O9}#Hga-ySTEMRqj2R`j+rB0*%c#L0 zw8(>?80#7URQHFf{Q2q9g4dEN)#1*6HC5W>mp4vNmJEl@EDt->AmDA}6%`JfgY@~Z zeN98~6xMwPcULkno*3CKin75=HPLu`V9Z_}qI~20({M7SW0Jt0!i^GUV)NYe)jV+~ zOf0Eb$Ps7&(LP~qur@tzf@dlLSuhmO1W{al4k`~0*tcx*Cc&oEUFuD{qXhhL|Cb~Y{9gAw)jw( zq?Gn-+x-IbHWW;572*-YZI62W{{8365u#h_-VdA3TPmj79Z4N9pfDnr`gcrHc33@m z(P~w)yX;|mS6}9J-;VD!?@R|qLVl^o6OEp>$MpYkN_>^)r2i4rWNjr-jJ?e~WCa&z zcJ4J6+8GO-bIIaC{Vy8D&E!=S3zvH;w~~2+Er>GlqWZkc`dZ&x490L@L%_Y7yuZI} z6G9u=@pwnMMOrNqRie#akIW~wSc0F5+?)TLP!aPyLr@SZznQBBgmW8kjdhrHl^VO_ zJ=xV_ey_#kEo&gr_VGpm6~$nBYH$RrUUWzqwb4yy#9r1Abu9?@Y>cn8A`~LC6Yy z@a_N>svf-_`Buq2`U`JfCM#2WVOnr7!}OWKRzlf zff64!v>$?(WPbNR*wUo2#c`^1zBDuQt#fJ0t})TO{garEY!3-+J}!xQv-#ZiU*9c! z6i!_7!RLeMe&4<4XY2)5Qh(;M3EUwG57oqra>fN~#*QGseVhtD+bS>7qI`BE9za3W zG3@d*a!H4Ht&HjK#-VPXnIjurI!oyRrKK1ZMKUfDYPNI))7~XUvGb(3=Dcp){Ob=n z-cYOopB>2&L}>4T@M~?ehpF6VeNCjmC8GlRTsDSXeVHQZR4>@_7QASU&7|@VH{Dm_ zu8IWl8{%#IpW(*q=c&f0$MFyS>gRn}jD#-y&ans4CijbmlFb)$Zvp+A_z}xzog{^m zOag1(#~l-RY&hr8mT4ZZ9JXIaVWh(NcF0_w=9zY_YVS!>`fnmrJe(m78puoF1= zyWt_NQ%*lV3jdu?TC;+$23lsA3X>etAN*oqW`&o`p7ubo95UDZ`D-$)z(bITaA|d$ zZ0FiRD=T~?|Nl1`8n?ra=(vH%8w5bkcZH3dpomT9j}@tePZ1w=o_CYI3r;~PocSB*`y=*tU_6`DvVXe z!iLvkulo)mz#FDIQPBX!y!Na`-#KpD!qC}w8en+u7#?*!Eq~_if_mK&oL4wOxKq5; zW5w=G{3@QlF!p=}x7foBCz^Gx4{nfE0N z3MGP^@+}k3qMipq<_D4zdKB{&6Nu};zLRDk){|$X56TA!U~~ZA&{v6b0#?P5gprQg zv3o@6_Qa0Q%mjogZl~eXVMFuG6f4W1;avNH4SdB_irJTWB#_@93hiKLD?qwtH*7Jh z0FAGV~CPEWmFLuP_t7noxKmey@LJE1h6U{xAfpkoFWy+G>8Yj zP=!5sUS1miRq1AQM}sI>|Lm^g*uT(}N#1FT^;-eJR{qY(#82RP|j-X`@hMVHH&!HhH%RZ@`6eUGdmj|vBV?0L5C7Ubk_r9Fx#er z!onJBbvWr$hOJ35{q?)g$$!Qv&;~}8!cRA{j=hHe<23Gc-79}a^RIKjSvOzN>CJ?s z60o3j=u4)C&NTCI9XR0**k=fD{DhFBG z4m6S#fu%06L4i(yykMnrx(OsYC$7!+kon(o8o3H&pB`9seIj@0Dj46pTX^V`YD;a& zmUtg@1_+nnO$g?eE)RM88#AIf{FyC$|6D6_uAz=+FD2$sU|e#@yCH}OSJ4b`yEz|`*rs0mc$LCFwqcxoXP(q$Qr-!xjs60Iow@^? zt{z-;-6~scbU<(fn;O0yfoBCy^P=7sXyZi+z`u>smGK_?#NvOO?ZvxSNSs>T` zjLDxnONSqi39OTFsRlk0q=knPu&j1PuvZmrpN)Pb041I(3RIBCDy&%HG0ZbH?0IcH zcJMriSnAM_bm1j#d=8gh8DUO=+A5N>2iQV9rveA+$@@X|m?lSKh>)qcWZr@n5w0!mC;_HiqEWYMTc?8{9 zimz|vH4{s60e8X>5zZ??vXqdjNkXgV&fbWvC+_-#Vd_kD@oqI|L5vUT- zyH%&OgZOR_#%Vv3j(Zq-j0p;<0lo%o&QQX8$N29W_#|z5)C|P`MzOR+<}GwOq!$hn z$g{;U0DPI4pV;go|Kcp=T)K(>Fq6C4_~q7(9l?fwyzu0|O~s^|tQ;F=n}1H;J3T^{sK0u9mBRm^ZvyJ5LV;OmHq| z)EpwTsCz^ap{m?{a5gCN=`LUk8J#~I(NMj0;0sw&XEjU?UTPq89iPp)qV&)2;ftDU zRpQ%p(Zj}=8CtB(Wx_eV%Zwl1{Z$oV7cZA>cw8+Wo>z$%g-loV;zL0AcE194Ifb9Z zVpS9wGh*j=5P%A0*%OtNV$}{G{=&zG#U#)%z({(vc99*m!uTrH_3-At;HNxa6F~`; z{fN-BW-&Lrx@mJ1d59&mZ(WQ?LV?CM3Z4?E;yM8nW9`rPKS2(5kX^@zKu0R)XngMZ zD)ed|5ZGX43K)wJ}$4pC$RU@c%BLGmTr zwCfu^ZW*O=!xCah^IgzOcd?-Hi0Qb|z2Hbe35be&fV`r+TK=q=c%oZ3^tvKov6 z!u2fY{!p5?ndh{jx5{vCq47K;15EN`;VS0fH2f$8uh7i{vBFs;=(;$1rtdwVCrutN=uHT#MP<>dt6{AoL0J16}DNxSb* z-b_}~{%(A~I&N;p%B`E2#)f}>gq!XtmLMkZy9L`R-ZjvhC4Xjco(BPq|G`;kyYuBp zC@9hhFwDtCzsAkNC`+8r>u((u>^A-b`1|VP0z1|?f1D$Gxw_gH?bcgnKzKR!_$qZ{ zV+pi#SWNGm=Omi1-GrRSAPii zIV;iZ!7!Ay5(TS}a~j)@73SBz9}sM5oe{u-_S_2Gd644>L{pmy*bg{E0yQA>+<=_9f7+R^h9OW(O&Hp$FJ!!3GNNlEj|l;>FYczgIm%Sjh|v}f z+!~HX@?NCl13x7A&QphF6)$3Z^@x9-$nd+{apzI^P;uq9C~J}-D$hZ(-cvjNK5#|o zIrZ2JeiArg}L>_1xXQgmyndSn!z2HS_SEjq@5} z7DIk=mWODI$33!~v-5c4EI&M>7`-!Bp3zAhwBnyFqQ({~rxg8aKch@>c#8d@auL#N(8}K{|E}GuVLaG!$1d za}+47*5*5)M~pFN!mF?QXG*~RV-JdV_|B8kn}#@R4Yv*rN5=U@uexy=Fj|!Odk}ri zZ!1zwLgX$*$OZ8cRk5!0yJ$i0_bO|7W6Fx7A`~>vGFoh__UITE#9Q|?{pC*&F(hE% zTV}ICu=iZH`FntAKBNq+9iOn*0*21(kRA~c8%?e+aN9)edV_Du;U*Pcuc{2u} zqisOo1>wG$u^&G#$a#w5;T@2Qf0w|oLXic!K*9nm6aLKg*y#MHO}`J*KtE5CI}Wm( zk@YeFI4(>xvw6~jES1q!9P|Bi!B)Lu1VGBpHj+do#e?bSR&JxXk`!95!n zpC6}7rom^x3T#*L3yhgJ?b|B|K_a)~rNy+wjBfn-Ec}jy=>;eo!N3+ubr67hue*@O zF{HtHu57WH@aGCRevZQF1WF=(pqj5Zv*gpWz3KCmrVj4qRPo*Pg=SfxW8QeVoU3ds+T`?z_y?0zq9 zh(MKukt%xR8r9)#A(a&l^G&%3?SQ>!qo z@B(#lKW}^_GJHAh#gtO9yNz)F0?L6kB!)Qbgk;pVGQDn}Ch-Ow%P!+g{xq4n;%Yyp zq=5RVP&$l&3iwQQ_(;40!1yHRvK|{qT(-@dF4(5JlW&`cOgdFkxw^<~$+?;FaH$cc z!=sZJMTykF55jZ}mV~%BLjHtjfE!s$huhxZF6Qz&RiFz`uRHO96VcCBxkDqA1{V-k}`Op z(osyT9Ty`Vk60*nv)3X*K1Z$(E|r3>)(sgk9VCk7xxTtkb@D zVg5|n`F~-hx#FDoaxU@q-ITQ?p*t^2m*vGb*(vX~*qe^8zg;71?`;PTCaQj>?T6Nh zmR8_{2^9Q^C-ed?Krq62Y&3+fP=mLNDilGe8Wv{FPt3e0cWeDGD#^Y?J#NZ*uDm9j z_C(@T^7q<2b(WQq z{k<(8QAH{&{`C#WqAlvmPdi`hfEV3O=byIp7wx-VnEsks0t{FG2$ogNoBr{54rLb8 zmip#v40$aLo5wnGH?%bK)R#(|so@JZB~my;M6kiMH=@za+A^<&2d3)Z*#o3^b_R!; z#$Vc>5O?;1ST*kI-aY7&ppEj|YQ+3ecdV(ffPfJ__ywbi4-lUQK}n?wD;e99N&J%l zgh%@pD9v2dNUTyX_g~sqaV45(02a|8-gSpI@8b}@d)MQeiLh&n*h`9?4}@39KqFxfaZVaH>+5jKq1g}w zJFE!kCC_`qUMQ6#nhX!V&&c9?=zNAy#U5X{Aw1>Bs@`EWs6FZOwq_Cd`hfi~V~D5j zKz`E}7@P0@Z9otn0pDF)&}GFBI*v&li9G;x3{D;c@L634^wsiTy@b0T!U=oV7`Clz zF!I5d$$ngEWj-&ASx>yAL%2rra3NJrW$jfa65olZIar1G`4DJMj;mGy%KHs39A~;K ziE#&aQE#)j0}8PL7O)PRqzynriU@!Ok{FbL-V#AQP|yHfyCT0p;fCZ&^^J|VPC4Toh;5Z@n#-j9DcFKh}S+(|n6WTZs=I)+q zi3P?za4%Q1pGPl5cR7Ej5B`E z{W5k20Cs9)saBv?zw7=;CtShL(hc3bR4i@Cx~Ksk zm0&?6ZW8!o#lLLl0}$<+WSDhN00)1T2#2_)a_c>fJOsS7SYT^FD?ge=FO>G)4f4R!Qw>Ux)1k zl2-s6(iVmcley#k{z`h5rRaeo(2vXKJcq=bP~~^_rC?qOTDxx@GO>BP{GJu?g~UT* zv>vU)UD}*;Dv%X>-6=P=G(tx6p+&p#tc!!uBeNPN)3pyLB5Z=qxi9@(BoU zb$~Yes7lJqwWM@N+%mjr1(Nosn`zrG{G4>&H?&J;KR*t`=6!w^V z5U8DTUqW2sqs`Vo?)I3D9Ym|cVlE-<55cpRM65@Y0e6V!)6Gc?_+~Ow7`n;{a$JGV zSK*;1c`AdIwE8-U;l$AdkCere3K*2N>UZPm2H=IE{}UC_%WqtkHf#PvB>QX?j0T{w zf{^Xxu@Kd7Bv@A?zU~0p!I}1QjFZK;(em<~INID~&S+SeFJM)ipFMO(=Km6NAV;2J zHm-61pbkDC9Bcny7rF>^t>=&4Ls#b1WbKrVJF~`q?ed`cTApax=i1MFtkt4`?v#`W z0?nlbH-?xR8tZD^OvJv?t1}mztfK?T6a2a=u_G!TioPb4UQmKZF5tecBe)ZS-F{m3 z_x&sd@5l^OM(^ySH5J+cwxra!EXQPL{QLK0a9=-mn*>pPCn>0ZGkHaI$-!S6Cq@Sw z7+!#sfSBMXt@x86B!)dOke%|vuzD6nbU{A(4)&s64VJxmO@#AZWu9GWU+}FPZ~+2J z&~t0D_R8;f^GF!1q3wUK<&WM$WBZ}-q|X1cG+1`|uPo$bQXv9%dogU49Pi`N)%3!G zonof<1dnxDKJbz4Kf$DblTD_8>3CC@&qS~&^**ldE6che$;cVe6et29X;_Dy?6<;< z6yL2#dDY7Og2VmeG-$sRhuXcjGsDNQ{RFg_D)LWfHZGP)oxb8kitPOsQe+8u0B_|P zC(|?U`sPf$R3$!u&l`cSk%(lR(dAaPa-5}Apd*cz{U{Z0WpLMEB6Ape#9~#>1$pnm z1W~kudEG{SZ-}E+xHx<}K1Ys#j^)}|PgvXA54_?o8~>J0&>mAo*NdoZJMzE1_EK4jCgLahemePY$H?t{2Y?1{>TfO7T?=DhEoP2G`Y@%KVQT32_eo5t{c$n9cHnH6m#)}g@3m_th7C_I-7x$ zRcOd}j>f()82dB-c?^qndj0eo2?n0vx91AmFM7aW}n^Vd!_4pl{x|VTmt-@nK1eHg@zkRdXZryZX33z7P`=MHRXWuVJ{Qh{|G=pSI$M_WzU9UAAQy$CmQKjxm9a^dxf}-(rfn1O9RTc8Fl^ znTSES&BnqU?U^5eB=#tsz;dis3GlvE;P1MD6!cS|guc`0fH8}lS1oc&=O#;O*5XM* zz=JewsTytB4;Uu?XhECY76ely>lwl`fSVtKVwV)a&XMUC z!gvBI*~Z8+2U(o~a{I;;pSwA>?Y;i1DnHIj_E+7otr z`?bbS&~<7e_fM1^BDfl1&hD@)8QZjaP*B(FUs1G@BOSmYZ*qhHoTT(ARLq&m{c$Au z5~U7+caUTrNRmJ=jSo=HsYnYTVetj$$c>6JwAo>>rfFtm-wHu;GJh8-|6Z#K zx_fBItLDaSBPtAGLdAt6(EGD?qul+8^!ri|1&9$VBi6?yE+#__o5%7EDXapH;(dHf z?=*PPgLhqdj2B#=f|sfe_{ic%NJkSt!a4$7eO`1aEi=rEKmRu&wh8QCV#zgTe=r{q z|6IB9oW^sLj1heOg1#5>B!ru`3;SoTd=cybViA_9bTSi9@<@aprT|%pw9hBk_ebN^w?Eq_A6)&wh2HQ9{;Lq07XCsk(p51!rkCy29t820xr76Jb(o~;v_6@~u)DpPo z_L*2ndA4AzWUBoX9OQjc9e~p%ffcJc0qH;);t0Sh<6WTd89_y%09KpJEN)!_Tyk6i zYog%v>GWM|H79gSwsGpM)|V{p(SW&q19u%2?6!v+0X^jA7`a*IfpZ?Ffh*K)z_rL5+A%>vhTSYPI=-at~Gp$?v(ff60+Q-%r{ z>>YQ)qQ5KL9hJOksP2mTlly&% zzF4U0Hw9!rZKg(6{6Z!Up4Z6WBHS~FIR|IF23#r$oiw?9dRDp;U>#vD7CkGGxEZE% zD1mAGFcUy7=9t6=e~EHd{`M28v2+1E%KCrTb((qYZ40}QiNc#;0O@#$_bX@ ztX%nj5|@;#%=2>H?10&=8ydcbEWdLus8&CZ!L~E#AhZ5qyASRneaqRPG}VyX7&5f) ziPqg1t!KMRTk6)#YpI7L!eyrJQNVSqdz4ec5E>5S?(Ph`|CAgE<`KWn7bEC}HA&kR zzZHBVbuBRFx66u35a}vFQ&sMqV47Zdx9=pWU5i!r|2M7hApty2DXpX}(->jNSyo=k?9Pr;2%Sy@c2kJifE|Xu(C0K(J6_IwJZ}2saqju`h zpla5=j6pMYd$}!Vg<++J4p}I_xl6GgA{N? z)^06#)B;Psj^Mw2@ju)C2>u?;ODy5d1(cp7Yhh>!_|68g3>E?GQJvGtJ3F)C-#3!U zNAs;z8FH-^@tju<_~GY7>{v)E71un5J-&m^CqSHVKbV`PEcB|KmaLnPj8G%Jy+iHx{oY>-_= z)QNXw`4h6mG5c(6MqVS;_z6R?;OZ-vy^7HUK*R0VFE4=aagE8fqD%;LpExIu*wOF* z6mW_1Nz08SNw}F+e<4TPshAj@S+B8pS0;I9YJ=c27`TU49|FsshW(@h5z(dyj&PlN zHJ%MOCZPIenG~sK} z5Qh-X(FZLG4nH1SxjvmFLR0$a3A_Q}-a8h0!c_i^#G1m3EoS59=helBAgU4WZue@1 z@jOkreT9Z}^}BW2+y$UI?N4gxM7R9M>6?(;mA3*)qsnL>w(QPwn;2_I5pf>x(&k=w z27c0L;+&^NDwxBcRUTvitTgcGW!`O;XV1LdY%3?Cf1*+YZ7m4;FE-|?2YB$!r8!AP zG|_t^oJ;D1f!<@+O-_%ioGiH2*SpWzN`Bgp?_7x=PQ@A~w=JIeSVZm62dytTvdzGw zmmatGf}=IKI)X7f=q82FvwHw`Y(PnBJbrj2LVEpm9YH2DB|qSWf|8U zuFaV}$qB#AJvq`>og12VY{@)71p|A|*7VvI}wCq!XNR!$8{n~Wku4O|%-knaKW%{n3 zvq_xbX#j`FG|pP`EMO5iNPmd-Jfl@F*om^jhhmyd<-U~1iZ7x-;>+GLJ78s&WRL&U z02V_z?~D?L4l9c}Db3wzLxSkelMNQ$tMM*;-4-@I&(^ zicUikCYHFE5t$CFAhmO z?rtVKw^DAr=0E&q{Q&KmzXN~ZFrXKc^cbROf8$)ED)Rr}MF-JxL`Bb#ndlW0SXe{?-Y*?#86B7;_p0DOl4EratPfmvmYAki4G#Xs~e&@lGvLkxb>pa602@s%x^*9!YXsux6rG?Y^|7o$UZ>#!$K zDj+M`D(`!QC~@9tkKTN+a5AQ#`0sx5O6Sb1K8UV8bw&~-NPe+-dU6-C(h+RG1U+R{ z<+~S|{2xhY8VKe0zVY+S!q~^YGZM;PDwSo%lJ-!RLXD`j2`PlkgNP_fq9l_N6-mjG zWu_u3g(PGdi70!v!OT4W^Zotbc;OAt%z5r}&V60i=l)k>bKTDAPfi`f?-6+8SONP2 z>)#MXkYIlb?JDkvK08eo8_Swi-o)D(TMO9fFua-?*wQc>i4|@KT>l+qxMSWVFV%}i zWz)kJ8Z(?;gjT2}m;%*sg3mRgWr@`%hVi&#A6!Y5)M=CDJAyN!AZ=v$)PFM0J|*OC z%#@@40>jAsFJP~$6rA`?P5ep?$CC2k{gtktf42yIiL^cweV&@c?-mT^bVko$vP;-N z#oCpUKaq_TDQH?aKy(@?eusxVV+$im09L3q92bMl0PA=+ARcWYL>S}Z*hb&6C;zCg za4`@w;D`6_70iy8G~A0IGcpAqJ9=T$v8z@QH&RAD^2;A#%X4`?Uyc)3*2%qK==1%2 z-sRp^mXA2sZc@hx)*n7itX>0JhS`4WE$+QE`ksH5!ZSI*lZT%6hRlVnW22(z2A~f* z=V+>Y5LIs$L0y`XX6S`^iWW-v{kLO}S7FIR_c=MQ+p z1=CZ)Wz>8K@87<0Ie%LP^opeA93Yz3vkXYg9Y7h6AhNd~HtK4xNK3f#xl5#kN|%nv zT+A7^K+XsQOD#%A0sV*Hn|%oSwM9=RLb4PV^}vrE*!(7P;C{7PBJ8rvR%15TJRm}7 zO4X4VdD)E}>LU@)HgY9SiOKNi#!@GjI75$GslFIB07-uJS%3%VJSJP>L3$2r=mcyl z^~^?r1HU!T+q&W9fD#}3f>1tKgFE5{zs+(@Z;^dVOzmH<3i;izX_>Ce~U3l+4!NM!W zk8YXc5?X%~921JIgV`MkCJACkgiOZGI`0ifS%yk(Y=uSV&xQ=b?!6f7i9R7^y29qc zjaveWZqkWYV&0`X!08V|hV1m^q5Wo!pI@=>U+;F>EV8V#7ZO-caH+~Iz9jKNocCUs zSc4fQ`o7WmuI`yGjIBcfw=r^(RT4|`5Wjm8u!F4Yx-k;r8cFEpGTj~LrHWDh^+0Dl zujHn@!DH)qRHqd8_fIV#kv5f#ttD(|#>(+1gn;Tjju2(TZ=pEspS2Q!)=yt?^6!lt z6Z7iD$uuGoaqsa6{aoNEg}v-KIQCkot>r{-p5p{ehl?`O zeDZGinA|GDStgD#0DP|X>HNo{fw<@e9D93-GqO=%;${EjQ*|ILii<=*5L&$8XQUs+ z$dYG$^YIZXLhrPS2HMdY<+BQe&aFkBk02;>jG@6=7rd(I6#{ZQBC5>1PgZBTl?yI9 zc=b;FrDyC@a*e)`=O1w|iA#TS>Q+Gb(MiR*^(Un+cxv0%Mk#g>++PXP7Qw@1>S#BX z->}-_3iT*G)+x+3Qt}HtdpmC^6nTfo`^x;7jUGwRg5n> zbsRt60g|bWE4rx^x1mL}69?8&m|B8veYb3VS_C-mF35r4>X&B#vtsTV`e)jf!owGB#~+UNWB~PCdny3WEy<{TiLmlS>92$JC?CsiV zFA>8?{;mu^RsxSFMR?XEUl%ylhxM(TTiyhN zlwuJ02XEIK$?Q|nTd&qKcFD=S^AXR(bZ!p9l9x#qYxjY?omvOBSMK;aw*H|9S%7&O zNBgF$Qxnpc$HHRB!)nEK$^+|WRC2BQ0UPO?I4oe~6wkG1EM0Pu_jWoudQ~5M=B9DY zK#LK>RQ}$`4$vR-6eMWs4!VG7w#VPAv-ti~>RNl`0E8!bglv3{d;ZOVS3@>+KLY^W z@3D^?aqdMm+3D$^^_S$~(F8~Gaxv-WRSg30u=Y_5>YQ-_{imc77#&5il)yh_qE2y% z#aaRf<`~`Rx2ivAP*V~I`;JByosGtf(*-*p99Cc~y;OHyqUSUT_ehQi!?l8#-{c01 zF-PW+RnzX$7f$5-u{vwKmXmKn;pxK9CN&DiT-WlZ6=>(B$#}HuSM$0BL1>sIc_{K- z&(@r(;y%5f9b_7gx;+ZrxQG;lw=};k{sq$G{2RoT0uiUA8w`l0dt^#uK+J zXLzYjOVD>{Q&W1pQDn~t0?iXN)<5KGf6_BSh0p^g|Mk|@6R}=AZEhY=ptyKXLlIN7 z+PlPR8&QH1`fnBlPIv}bpdo;;1Z2FHa+udyN)CdS1$x%Um)w0#iu>**MXQi$8GOT` z+_2B;(b&mt#z#NJ)vxtgqZr-a5a|h$xE9@g|EQO7=wAD=TPr%M@}6I`3Ll%X``r#n zQ!QZX3w-0Ms4Y+l!=5RENQ!quG#cL@uoI8F``ZVYzSHH0Kt#AY_}jdjXEBes z-0YIl5x9~23klz4k)aiS+~`A~eZeGmGAB`dDza9A@egFab&R1ltGZ~Dm!wNFRQGoA z$oj=HFvietpsAd(9uFRdaUhv2y_n$-t zm%GFp0dp6ly0_VjpA|GI-~`2e5!m@WCFvWAZ&z~avbsR}^3l#xnnnpcq-<-@Zy^-j z-h{>gb5QtBIM5U9XX>5YatsT$8N!5d=!eUA;2H8VKLhEXDHj1pGrDtfjR=7{6zwPS zmC{aU#Ae3`%rVUw!ORC_jr0X=x3zWy9bFH(rdcvo`%WCns7*e7QC6f~_t3tM^Mel? zPfdp+v}Xt|>u+<}bg0`d;Is@z=FY#e)ZYMbs(BR!89s&r2|%KE`|*8`VZZPuoD`{q zq<^sa2}L=|e_XxQy2x?ERDDqT-*5?X#=jbQRNGgPCJR!ZYBHK11G0F_AV`kw=H8Lh zgi*cx7}S3rA1O>_pGp>)|G)=Apk<3qFOJ3(W~zdb3XJm-c$)`xwS5AC{LeUAJrs2j ze~9Y$K>mjIMd*PF!~-N}e>Bf8`JSryQK6RX$Qn)%jEM^ggm3K{>Wa8?`4CxwFOnd<8I z8KJnA5sh)s0yEv6--MV!Ec|-pdD&Gq=v)2;(*|E9IB8R_u6lqpWD-t$5cxf}m*%(L-`cgfwe8G={bryEyYJ~eON zAKmP@FZPdAS}cxCft@WgN`Dg(fg98!a$K6cTS%?7o(8vkwVME0H92{|iE)YfCt5wh zB7-=JR&6jn_Vt5k|8F8~twMFm z&+Qhf)x;^7zb53EOid9!PxM`!cMLj_!=Im}!1Ts<;Iw)%iKU23=40jv(C0fcC#mU5 zWSs;?jp^Il)I`iAZEwrt)2zex>M8!J5R{*T|8s$;Q%+vY`7VvS0>>r zW>|Agp^heY7E z`*n=sbpxjfJ+@=5zqm8_^@4K$x@!%c<;4n^6K~_10U8YF+OT)crtjZ5w}}kLn}eir zH|YKWR?(ljyr)?vcxDcFv_NhG4&yRD6A>;AYGLbk>Vx3v;GoG7*CS!oj@P(DgA)w> z=}>Xx$z<^@{*eb-B^x)aii)1XY}Q;htd{Y6LpQ_wu!N{=6)$WM>HJP+uaIi}B2{&X z?uWgwCI9N!*)htT3BNrg%2sJ&c<@47X3UX(rp$FwBUFu@gV+lGASLc{!SAbI@ zGoON^0rK8V1ZS5k_SVBOFtN@}n10-EAxo=x#JXHOWBVA21_LfOmHJ{Ok%~IryyLUZSAcz zem88$)@PHGVECY{6Kq_8pDZ4F=acQl4_qjAci`7+PAkX)iD|$8y24xQw4gW8sUhw$#m|&PPkKkHF(ba)cwCDGf=ZRqESKKv((q{_h_Y(V~;C7V9mw29kxsJ;B z`p7e!ZJb}^LpR-k1^{xhVG<;GuS=x<<{S7rADT^bDBLqt-{o}+0S*=k7do>SwMXe& zq!@5&Vacr&7;Ml(P%pu$S--edb}{s+1WgZQCS4p)+s%1$C8hlHS9t6BItL}fE@;8} zmDuRF>^a3A?&!Ln!TOTyz3xbYR{vHBA^S+PITq>B}K!c1S7d^x%2C^o)?g<2y{#-#-G zFHFPq3WPe_>_FgRA)s9rL1t^agxJfjOX^Yt)CDgSrbmN`E~lkt-TJW2x-X^=U(ekc zr7PwW@yu}k_YQK`s*JhNnxl-5aF^R3*I4{`JKT^wrrzbq1}M9T^oIaTd=?u0>a1-c zWrj0*OOVc;{PPvQ&V(13h!BJWcutXq%e$uhTyTU}IO|=1+|WyCD2fKhqc*}gC9va| z0W=DT@De>prNtpQwcrY*KeZhDPzAU$TAAR(x@|$El7(2*w@q%N@-Y({@%ODCBNRLK z0KBt2XpFZO3QC8eLfRL}5C=f2{$ zEk6xwLI4|B)ux{c0~=f;m_{J=aH`#z<+R%jSeLWMa&};{&Ou&R4{5qmsAVGS7s=?Y zV`^wDWDb2Xc=tloG>g3aYrC^JOL}NqPNuTDjM!~cJ2tGvj9m-3Kvm|pbf~I~%YYwy zz|9%=eR(`$?gKpwJVLv_gG>W01f(1Xx`W|a2=xEeh+Fj7t<;iUtJTa}-fJb8-cx%y z1Qz8B$FNT)drb14@wRX@S>0b&qMTLCO0Cp7&5Mk`3u)Z80XSvz%2ki+Nc8)EWt7<$ z%^WgA{pl)xF^%WGGiYMG&G$Sm-Zs;0`PByS+*woxD`5P|@$ou_kr_dj%CEXGZ95vN z2p!E)r?ON3;mHK1jFa-98@p;ub=vp=%!2;j__94 zJ$$&}u_#RzH{4!Pk@?|DFd;pIgwt=ehH2+xr2S6hmK{7k47Y-ogvvsTQB zsYT+Nt{11m<#0_CIFBhRlCjX+9Rqi@Xb37A4}4dk$FRp3V`V)i`apx8`iHUUV_Yqb zC#|J^bqAoJH1=K6#=+Y#(N*%+M;XVk-1HuHm2af1B_uc4isDvC5)4CD39@l8K-;U5 z>G)caF4u@;ogxCd^!;u@B{10UrMow7|&TCcNiU1Y_Kkgr!|^i1(?ox-9P98ZczZC^Ta<3>C-x z##%>NF;k2KM!H_eH0Dvn91j_J=8bI>28*cv|Lx$CoX}UE1rFU zL(|m?g7n8}P$RtZ(^>@a)rQaA0~H_7XLlyv7$*xMAQ8)+FH^!z5I_a*_|Aa&S*Y&! z1yxedZRK=)Iujxr_!|yrNUemENzmxHL*ocL2f|y+?_!~KRC(85Q69X8O}n7(&UAfq zT&M8Z5SQcdy=F>yT7Hrm2 z<<+O@mqH)^+1w9@(_BtktWX6Hx%6NBjQIn{n;)pB{z*z7YwTDb<@4GGJ;P5M;K11> z%MYyOZP*ZkcuvK4ZK91cAh^ileV)bcKn*BMJE>%1_MAgStqcPqfWf2GCvN&|+cJ)TsAX6tP$-O)-(WFXl`KTDE z2u#K7`oD5Bd$JEE9_(AdOcE}RNJ1gt8mDt6b3pTN+&zXc$M3c4B+Cdm5ospEwl1+R zpcQ!J6`Md_HI&Bn^EvySQBTHPoA~B*(QgSS>TLIXSqxZL2d8sK&%?O07xYT(54ptA z1gkcD+Af5enGljClaww03|o~WeM(@~$UPxlP24DQz3%7MYY9cX=bcaMwsBWKla^ZX zgv@g^p4J-q&oa1qo{|XNjf|j!1b)Ve%U%HR~>>7+& zJtFN`Ol~aLLM=TX@X4Lm3!Fab?B}|>U<{+-QZT0U+^Xh$NN_A>qU;LCOQji2MV7cH3 zoIW<@(MHBi1{4FR)VcwdyV7;Q^ube}+xeQLcYeCeV+c)W971=LJbmgQ0iNGRtx`ll zc@5+a#zwJ*2K2J)g*WkZ#E)F0F{gv{09zhUbJ%2|@6LNWYi{m*WSYt@#H89p`UcHY z40CRz#r;#NvwC}qQ7-Y5{`rGx2KLP#a`#VT~T{N1CM_!8J&fvf~ zvs=deNjxD$+8Rvtn|s*sPF)l3KL%)rhtG~f_1BS_{tqHrE59Z6Z^9zqN%hCXo@={? zx&f!WF>03F(5|oUyz-Mo=VtS|90V;}mVXdwRV;-1U;OF#T>^}Tw+DoD_Oboo|H9U@ zS}MOE38KJrIRJi(ddHw?8_1>{A}IXH=@y`j#lz`m{;2nK zenGb%(<%i3*kPJg;+PY79~FVI?-iF<)~OT?e@@xRD0^JTP;ZakO~bj1oaGIdE%`YH+>L$P(((RZ4x&L6hrtv8 zOnrsPfyvfgt=)I<2$4o>$0JaHf6qD%38+iqQScKKXd}Rmme;9-7z$6yhq~jvAe~&O zba)NuFEa<$S5O-^i|dAXD1*ZS-!$g*ekM1i9$(K;xTgbQw~y?jtPJ#Skbv6`6eMr6 zNC)yR>dXz%dZ*`_?=@J#Aeh)|-LJ0@Q|j>^q(vO;^atpR{G%&gQ7?(o_BA(59#hB1maI{pjM=c^d38cK*$=N|6NXYxV9xChXW_ zv6Uo(w7lFi=B*;HcH$??QmnkvU0JOPDY}Wj*k7H#%hdxgAFm zoy_zOR)wNa;=CmV^n8%`&#S-k@5%SnK#|l#DlUziArlD8RKN<0x$q8uoBwx@ytjR! zZ~{D$^slLs?1A6c*4wovUh~k;8dP@zuU0|v2EGP%aGKYkG>>@&>a`e@jNI96N*a8a`zvPiWDlW%_TpB3rU<0nhR`4y$ z2WZrPEgBgG%t}=evyz3x+-r$P6R>mK^suZj?G5j3eay^I`ict}%FzHa7lnZ+#Xo@> z7ZsW0iP%XkeHt{x{gW5$%_^ZOg3jxd2n`u9@mGkwgim4=bpK;9l6U-9x*oiPtGYc# z1{1O4?Hk+au|AHIIaxfKN6iGxPU!3=-Zx*yp0R)RJz*c)bf~;}TZG1tn%~k_2@q%p z{Cj_WjxZ%?w0Oe&wh*0s1V?L91l68c!PP0d3w1qE^9@cFL6^=Pt$MfZyI1-Sy&Y1*m@YczTX%Ts<3=SwMKA$d}0`i zL3c3GAjVG^>;xp(hdYO6<6aE6!gZuo?TW_spzH9PrH=+c^50dFXMe}h#wNv`j~_L0 z0>({_&PNClc&gJDG;fJqsw64%T8+Za$5Fz#4X$Is;?ojwYr7YOk(2oT8F*?4RVF7= zZv*}@L3fexnLgqF6(FrT>bI4G&1ZxVsrhPk6UApdI1Xb0H+Zq0N>w>J-K_i882fXsU$J3gaGAY{3g$Te$AGQsS*0SsjUN4$!U{(*%cYd39Tckt5!bn2|ji=j%7_%RZz=hlhLHKTdky6foKmmn!_kWu zY2LM&2uR)zD5;GfYXq!sD&)X~d78W{z#(_YotI3!oAF4*COmBBxA@MkFE?0I;x zQKk0;#=g!zL*{X`yw6eqc|I?-fS2vG_klhLZ3D1;O|QxWMKQ-c^B(E!2=lLjX|~e2`@#Y+>BU zhtGUQ^0?9OBdXr&F}qpfl7MMN1J6mc&VKq6n|Zv`7*l2H{w*@=bADZMlJfMK%^%37 zHnO;BYiD7ov{Sr2BM|t+N?HhT)j7VFX2b5Nibqf8f$5B3>=E+(=V^m1P6D%bxiu?)@J9UwSJYZ?_OTYmBU+kRByuz zs>SkOe^OU`7j<4}vK}8d-?8wc-jU(Jd@g>U{xbsUk;NH=_3%{AYaq!gw;4?a0=fSl zxHI_H_;NB?m!LMJ^*2w5u<;Rl0~wBre$8`a?aJyxB+vfKaz)E8D0!cKckNApa7ohq z+dVqQ#=qANWaQx*9L1FHkuz}w!@9nN&o?gt5s9_GiigGbQLK(B5jzl^gHHeVakPCe zj~E`4qwB0u_;!EY0Y*JQSkkn~1{H$-7Al_ECZtpjkE|0AaS#AjI(M}0;B~7KC*^Qw zRtQ|8du(sPv^iZxoxHC#Y7G%oD5YGXrgJf;oi9vJP3KEnPjIpTI82{8&1qK+xy%{ggdIZEhl}{b_Bbg$!6d@rS7%tl8hh=#wD+RhE zL%}x&JwRh`rg-aFQSQHiYvGsw%k}8Tm>2-w zOkLf1nvAU*I4RVg^uebL0dhk=W`KK;@NH=W&Amm(;ECh%SL>bQmG7EZUzV{NTTKGN zMk6}JI(qND4RgJsK8rs%yw3bHm*@e1J)5`Gg@^Aq)D?2tJ|_EeI+c5Lt+7DlC#D`0 zEvntylV6|nB23|oK9-SpysbOk_FH<_sbOkjc_E+__)m~3uLuTI77<>3X1f9^Au@}JEDVn;FLs8yNgiZOox`&{Z?}&k*8aZir-|}$Ev-S zc&@!WLXCi*r2WP2sLEqv_rMixCCPkm@xuD0x)n{)2LEk{lmOk8tsG~gXsccoQ;N6x zO;-Hcp3Sbrvv%$YVv&con(X0vyt?W$C{|qTzjyR*w%fpTHutuk@-J7VZmILM%3O=@vw9@y@N7+pm3m;rmm0Mq`k?}`p z-x0w~m_+W=hR1`fR5dbVYZ(K6I>G~mDj6N~n+G(H{-nFb7$cNFB+F%-OJdFw#PbP} zhGTg#TaP(nInawp2#24}%6hseqe(|#vDSFp?EAgT2>N#$|De{&FP=2C5GQV44JwgJ zd05o>5OleYF!pcc(62QyF%A)w!rx0r#}u}zP5T8iV`5}8@sDv+lgc8<@Da&NiGFGn z)1>e0e@Z_jU+X~l;OU&ciSQq|bFgAr7b0ke$n@~A5JruROe`ptUvZ*(cd_5)lYdK^ z6HXnlNl4nh%Y5TNvCj>+#BhYt@<$T@c};JUaq*$Y(?;DI&+}z}7He5sSn=JI`RWMT zQ_orXW#wQ->6_xKBP^F8!PBx&7n4&?WMDpSqSG=v1aRt+^LEK3+vG!<@ta0F1{iBJ ze(4Wg5mgA$>D*hIW+;IE3Z%p@g|=zp$oy=;Gj1k0x<%_tvAQ8oU*$Hnj@7eL;8QO1 zs+%@`Av1W5vf!MvhTP;oevCfiCrOyaMaMms7V!vB_B3n&5xBhnp3KjexJ3v$3_&@$foKH?OO#psme$CJ8g!%6?JI= zp58UI0qWZ<;)hpNS=vsip2YQXOskf#oE4`8T?v^V>LEwb4JjZxIkf>BV+;g)C#`>z zeVYE#6^V%a$TQLUl96D*iMnXs6=?ycE*uhqJh#lt@42-U>#qx&ZaeZl4~_-5KYq$l z#=B71p_gbQ99y1W%cRKz4*lAL-5amVF}~#O=l+qr;VaWOMv6#R0ynvz^l9Q|*!CmX z8}Qs?2V|OeKoig1Aoj*bh>rs_FRsP>8Pkdp>6z=1?itfz{yFa7+|4Wc6yay{MV&N~ zK}I*mOliK*a*Fd185@H$Kmx^>5`;{^wgxwcLO+%`6nteh{T4n*4g}JIpcVR2L* zME|Q(3P`voQ^dln^GW_RAie(c=-)CnyrdXoZAZW|o@9EYaQNJ|`}7A9#9bs)nzxps zzYus$^;*E%S9#C8=GZQzA-(>-ZLZN7^UD0)VvK{YuBd27L^W%(^l2@@Me=}9D)9pW zViiBWbo^PXspk|Fd{z7Fq-d0|`C4wThN?_(BKeT)l9P^jqS@>+!~Fm@xeC*4895YU zFLZTsXeH_NiobG=ov)?>4P5rHug-DUC7!sjg+{Znp;@ooBZjB^J{)xEg~jKg zeLAQDLH&d#TCy54D7}FbxgU?)DFm7nZ&cH(M1YgDX&guVpQxJaTS(h)o=Gru$zL7t$FS+?Cj(dUlw`|LlznW!3{FLP)!MS>3sWLaNH2r$B zoF}}JhTp9_^for)BvaL9@>o7=0p=&4agOy5G$iEQo1_y-Jmd{_Sq96|lbs^Osox*2 zpI!)H; zBh_*6nDt1y#Sm+=Mk~*%un2o+L$#`92r7Jr{-5IMnr<1<#yQ7R(T@kFW_ICmUvyU} zO`u0)}jHP&GMy;%MsFB`uFQE+ZPAO-_8EnUGqm!4{DNk!pQ|nG8Dn#{8nt$RO=)>y8denfq zh5xabbAbHN}(8Pd3)j5BD%Oel%)p!3Q;y-b`ZB# z$UM(*KV~V4$0=kPi@Y`Qv;Nxn@6{R;gKYlnrX>|`<3GQq!`(z9)N#CD=c-#}Q0KrC zyUGZ<06+6!oeo-Tw{p+zi`E1BbCb$swqiskh1O-eXNdrBZ;O^!1wglDPp3o6aMJ@7 z+S`Emc<_3A;h%Zd4%lHg8txl=p7$pk zpRgZ=%xi!7DaP$RE;7c{fs^aWq^6Zi^}0-N1MOn@?SlLhM zetlph@kZ>^qbKB4mbbErg3W)ycH|LzM@gOtgpqo4#-D}s>OQ|0-KWUEgDW3pM@8yU zMiv$}-<~sH8k=Ykd!zh%k>4^?^+%;|{+ht;E%o;9D;I9^+@1dA#E&RmpKE?F=qPqE zDrO41!j+ieTcF(VFLd6CV{|e8i`SLSa*VpIb$+D_&$jowKh^=|P&f|P`T3Hk_tWBc z#|~a-&21{2D!n(6DwCDwk$Z-LAFEuL`Q-CY%!VzD#~H^^m}{FJ(PB{TSNfe^ies5L z2|#hTE(dGz9ZC(0;?N@W@be_{R)Cv!h5d(Lcbe;aK&rbxuFm)<=VSlYB=p);z#XIL znGXd8I_(ACg^q=XcX*ra9w)38RH^Ol4=wGF@X^z&XS_Qu<y|(-_q8NVV2<$9;r7O`J+#dM$jiy{8F1J}xg9Db6-Hlun+!F6|VuhioceUqC^< zW%uE`PX?u~9veMblP`kv+~jLZyC|7~gKhNTZ!xBb_ic$70ibnU36VhLH?7zfdavs3 zB(ZXNeNoXsl8n}{ zLH_LA6@mG(^J9i&`&*rx-{I17)Ed>yFJzocHD5gO6O-0q+z}iw6OZ~`$ZFz21JT2n zT@1OfF@xOkV2$*~jN@Y8$ePm@Sh_wT>)d$p-{s&*j<%rh9`!bVUbkm}v2N%HY-SGX zEq5Poj?L!W+M5G#XGrL#sf$;WqYsft57g0uRlo@$al@U|7D;rN4fYK`*jR7ufuL|p zO8fAs;HfqLLzq2|eOfdiZGfzqriVU7f(}S9>up>l_RrAJiJ?uPUkP{g^o-G=HN(Lj zXRn5hp1?y2&u?4G>-{8?J84D9PTAGooa!y!;ld=6v433u9y8t-A}f7$vs@@EYk4#I z-?f(*`n7f^H}+mc5kPDA(6YQ0SlCYGSDkvR{g%bfC27{p1sLc|mk-5oB?d4JW9({m z&y4ee5|0O9R>{M+4-?a1T{jo9!W0wMUBYChk9zJFJDu+PCZ3wXZAjUo4#ahKc)$gL{kG+n*Q81`;y5ItT_sySu z?G7-eHWL4)dcb&`&AYYvHNIa) z9Ng@^nRK<51z}3h2=9ldR%!Xsq7LkvzYniiN0}0FWjk6nR~4@gTN;?1uKF<6&9@Br z+A$f@no{20?>q6}fZ!H{Cbi5-L>ZKR(q!crSoSH(=#Vf%-#uH?O{4V21diL4%sI!` z4ohVou=gmF9J^953PszQ(IhQ_Rsu%6gqaO^h+z{Io;<1D(_6)4-(qv8L%s?2bj=(m zJK+hD{0q`~>*LXicyu(h?RqnciqY6LelcXhPAceJ{|MYw$L{T5U&G-cZ~QR%8+2wN zzY2tI0$f^wkl`btu)Q=l{E;opi7>oFMR|ksjS|~{KYI}EnGP7Y4ETvmc@peR9;%31 zW&qb#Gk+r3^Zk69)%b#}il}kBQ832^+sikHBQA3zN+utLLfyJr`++(_d-LIK)}@}} zoXO#_;m?s5+;yAB^<8Ty-s3L34?ABb7UtYq8aYHwq$)3#wodAuzb2BiOYoG#Dv4HTeOustgn>%nPg(S9?-)gR3-sgr$OLN3WxJqHe(F;z^JC;i9;?;Bm@WJdqk2s|vF z#4r&wjvRU zdfVDAY5fq3v^(@T)y;X|@{Gxam-l#mwSC)lIs7B>So3#-kB4Z-7pkY8jm??$T@Nfb zO%=L5$E(rbB%*ADeJM!Zwbzg`nzM&JxHW?JxPu;O!CO6=Klk%yeR0I4+C%Jfl2P>4 zJes%ND?%A0;4tS{^YR@qKr05UZ-eLc$^xcrsZ5w%*6i_`fT&CLQ7LY++9APO31<_^ zh3?E?=YCP#@xL9iPlBT}UJ|sX`zp_`l(BVp#XJ>PJbaV)pw^1vPg$2Q1goB+P=UTv zT;{0heF_{B)5pl~y0==Uh6u`|Y3hNU%1xgKG44rK9z6bAeWzuw6$}ZsUA=a9{^6Tnr+-AcenXSjy*|D^c z^bL{n;H@56vwY=LiWU4b^j&Zc@}iCVnD?Mxm5jS@xZRjUXY;&;4cYq&OHzfijI^Uv zNI|sY#c#aLtUg~DgDWP(6t8vxISLk%zO5e*ZT{8Y_ELP^Yh|_<3XNhdQB|t ze%hMXS-1Xtu-}R+h}pU>;B`$&TAYcx{ASjgH7i=6y7X?=RyPw=bqB+D1? zf0O#Dd3h?ME$I4Ahr0de_77?a0uJ+*436KXG9(4!=hJb>9ta9A*-}{jL?$@x_9x7)oHRP$E z*Ht5mZJF}%{j!9c()*@F44FpHca@9(y+V6-L72Vnpv*Tduq}-a9dZlAK~ELLv-WuC zX8rG1_xH_ls+tRH(xhKAPuiMe>P2U24311nf*(eZxUkWN-Qts7JmaN5WD(W(>KQJ1 z^N?WeM}Ayufl|`dgx1E?0$t&}4*}Lj*50Klb(nZC|689~@3Lyt#f#cW0eZai!b&%I z-+5~PTWnTDAT0v)e{+jE#9;Ws=%mQtkx6<(84jrTon+toGV-D2@{YGehqH~UQ)UM> zMadgC{J_bV5>HMEw-`qcmA0xl0ZIojcSHzwv?rBB<|n=i?#e+N`t$XfO5zts!`DV} z!WYLIaOk6YGxJsBSu47=2&KKj&GOO4fSHwE-J6NWNA0osZTZZnRQ|m7$SA>0&LxMM zMy_|+_3+nW1;M#pdzyKd^m{JH6>@_fuk33+S{JhVhvn=1+=(^(l0*~Aa&d$i!$@#* zvC7)76NkcBzY3t#;e-K2Tg&@RyJ%oD7Vu_{^?3qAs;OW=^BjU+dtGAS{TT&UdZ#ai zu~LUmU!tHsZXD5e`-sTX{-E)f; z)_|?e$a}ak^GkxJ;@N@W#Wj5!=c7tieV@kJnthNhAbq<@?f3VHVM8*5ECNzRM;1q4 zFn;V)RtmmK2oVEclEU(H`}{8~mMln~`!`wsdUIDm>4Z>v^0gPfEK!s*wA-dVea}bC zyt1=la@bx&<_mA9byCdx9~OLd5U9#4XwKRDmU>-9I={{L-|Iu|qr+zz&f_B{r9$ZL zoK_a3BEM5!oVmhypICaa{Z+%gdk8w!Q672zxe!n$AWv^g3js-gp(8*kWNG>7H>&-H zH!)w1)!c`!pm*egIu`kt_$B=0KF|JAm0$Y6Prq^Rm*E*7Wtt7y^nP+oFo;e(x69>a z5D_=A0~8~_&qkq|G-bXTWtC!b9If*A29S~6u=$io>1rgD01Q`M_##0kH}P1 z(U~Wzy|_yYZ&jB9zCWrxgRrIEdKd+q9C98hBeqP;1o)_kpAJoa{6x0a*t;yIVaLeK zuokZi;zt~8bK^^DWoH*Lv>&sp4|uhb-uIwGroMLW;CKfW zJ*@5;dmefaVoO&36OIh?v|ms8M4Qr1jyWQ3=+O6kD@9RLVaUZknif-Re3Z1W+e*c;buHzlEAL%|@pN+EB$BWkbsF!B3hqpj$S3TB`4A|x7mT|{# zYF~Sq!&}dK*URv@b-QXISA+VKE@28b;~XC_7PpOxf;nvG*}E0@rmtY+I3j?RG(9*~ zBoR;I)k;Uyl3NOJryq}ouim%+Q3OkRypFNk6_ou^SaXC_Dzv|$?4!au@v%3WQ@$|q zLtDm2xjMW#fYS8WCImgQA>y1-S`UIK_bvmTkL~T3VL}!;wFg9A%eHxm1*0UcP|;$NANn;UNWonGb-;K_bJ9Jj*_nAy(Eg?E@U@xS z=@KE_3>&FA4H#iBn3wQ{VWP_!ZH*$r*#yL{II{}-`IkM+N) zHJYiTOERrzbfeMg?@Z5KQ7mILtyE8=)Sq3iw}UJYA|+SQn0Lm7AoLz}_L(FBk5`C? z3-aTRxCM;6{lN7exnI7TE(|F^PcHUre~red26<&hXc<=2hiQffL{+&~>3$1JKUTQd zyq^53TiJVJK7Tl^nN_5R+qJRPO0YJZx46<_X)4lWi*Vhp6)X3QEZ}1thXhhnt*P7` zm&fvo^UzX6q+R^-NNe7IdHG~fK(MNJh4k&ibCp4rE4Llvd;I@$c60?--VHEK4V4Hu zeFW|y*YHT}wbf2p{IZ|;0`~#6?zrcjkBGKmo+b_45~G|kj_U86Nkn1K`v(K>lB=^% zM?7o#i9_t&qS+g1-Yc|im_HNZ&Tl+ct5*?>kJS$vG_~!>G9&w$goD!Clnx0=F)-iR2B}Gj33h-j{RF&Lfnk--8Cz7Cuzw_- zE4=ls&eY~#<{i9ePg6#9SN7Krl8T~>x^Cc+?qGS8)% ze=Z&B_yLSDk`-(_J;EDNbd9b2RWys`!d1^b)s|KzQL!Kx#&JVeb}qu=itt4H+x~~- zc5c9AJb(lY_LL>v0_~^BG2^J;Lk9YD?U=pGZw2a+;UoM-+~c0~^u7?@{zC2hvD7ye ziJyU>4VG$CEiWJxVmxu0seVsH=s6fvrL;x@QU*BuBk&n+3dMg}{U}AV{k=CtwSD1G zUBP&X#bkGLikTW}<-Ag`Qu)HA?u*OapSKr*Pu>d1n?hG+wK)LqnQ^sFUmicN??bo6 zd1`m1B&x^Do_;t06*;R#jx)ce2NgVft$)|}4aY+sPyWHOK3?)q#ro$Pc9#aRbu9cb zR?K->sxZE*qi_zvj5_CHd%;K%;kh)t{l=zM6!&&a<4>bEk$se~Qv%m@6g5nSvP_}X zHpO<)!WIW`QT{e>JLGZ`jsrWjvuowX$Uf@9&vB{CfGH{oH3vmm9?oJG3UHKYhmV^H z;$P8lM!CrcJM{1z~>#JoXVW6+bz_$nZiCvV!6+C&tSnOpNUiI6TyP?FS zQIz4SFEX=KhdFw+EJny%3ugvbbJq#0i@vo*>8s!VzO;Qj;V<6o14#hN{ys$d?_GY(EIKtyK@$}I&>?<3Hzsmcs;RB3TF0L?^A zPp`OJ1~gj?OkTd>2P-hsnuv=edOkCB#>Z6vzqRU*ld)lwh>4n7Pwx4m)x+~Wc4{M# zT9b+JAkps?%gTLSajYDHMi?M96RrP!)L*PfGcu%Bioexz90K85a%83B6)i2TCuyVg zt$1JHDUfw=iW*jSV|2mQad$T)cUP;XV76lOe;bt>sTpD)c8Vmf_Ai*5_WNHh@d=RJNiNaN_fjA2}jHt2QyR#(uNNoCJ+D?YpI5)qQ4f0B6TR? zNjM?rmHr>e@I8bFN0#HtVueCs3u60|4K z!SDiaFeGxq{jV#2vJ`0wH{b{BYFOUSxZbudgF?-eY~&75<>si__EN0$Esw+PD^mGR zLUxPQh?9rs@AzP17e}aq%T5{P?7xWV2tG#YPfj*G>3c@p8cpU;>At+JO1=7%_r&R& zUq&rO;K<9FdNxI-UJM59AnGkFM-8yQ&js)MdeTx3NeF4WGwFxXXrbk`Fylg!zV&?| zcyBOt$D*)&^<7bd?2~+q1^s}2e-aZ&31vnnS0;ep0bDTo0LaGQ$)*>jERI#xF1*rE zU&~mL(Tk+y7y;#?ovk_U5wLzs$r6h`^RwtRG{lb(*)KB7`}Meh>c_{64!J1p9y(C` zG12^1)YbsP+#KFUn4uu-(BC6I1d>}MjOk~P`mk&Tc+}RjEe7gwtIrF+?39;QY~VH7 z%BiPR9H?8mEljWZX!tMYk*=d3uo#BYi`4zH@p~jBId9eTZ|23FjnypbAge^ol2EA1NrWr-juX0EodIYB7>cvz53 z_};j}kcv^5%9_Q~MC$9LX(kc?!G_w}-SG5z`=04!JS4c2P6Mn7P=5o!?YIh4a>S_y z1?$4wfT0{4c9wCXU8RX?-)gk<7n;$|2npV}VHaT9eZ z{t546gtyEDU(=JcrkO%93S;wPRWT27VF`Zis(0^(gwrOTacm_+a5F>F6oYcTqWFq=ut#)+G&KIckoh3oBPcz|m z6?FQ^N@>c7cDURe%X|b(IXbl9$ z{TH-b&h~9m!xK6H>5rJ6_(e}9&Xq3@Xtyuk2RE=~s;~Xt1BD)aI`Fc416U9=&SwqA zONRJBqMoCtQF=+{SFt_PrAhDome~{FQikj~f5GaOczF};o6HlS9#YP|hrg&K2sGqv zp-t1%!=*cOrbrgAz2~CfKFcVCD{uH4lFNJ=LaFe91fas`holZ|E)&BmN@~o*6sjPy z#FAC|?8WA88F!GKnd17#I{>vIh-L3{(Rp1R-{D)uOvixz!gezMkI=F|*It?RkI}jd zE%yEX>Eq66Nc*hL+sbC6`?tGhNBSp6UI{Pqv`#)Zm+L6&Q%jo^jbBfn1{GkS{Fkr! zLWy%P=jsT~z+gbZWxEL$3kB@nJws0Y!j~hhy!mu0%Pfv9Nsyt`Mp*^S(r9#92M5i3w;*i&gzxQZ}^nwK5lJ(${SkM z9C2SS%j(dF3<>a*b4aku`ex)1DBBXip;tilBBpID*``WFnl(Cdr~0Hi05+(2A^ti6 zJFkXDgn+-||DA!EYnj)@QgMGs79JYnp$oP);aYnuMO0M}aK^Li;c$(`q1xCn1?+Jl{kZB4&7eXfl%%?59*;+ zGK~p{H3GoVTQ7%CCQwa&jcrnKe((e8r|FXm#?OjX5v}<7$Y%k$c{wkwLK1*g+wVjr zjkDF^H{S?FLmvZ%zMYKVl~!f|BSy1-kcR@p3EIwgwxmi{&>b~W>t~d57Bh75N1ZLn ziM_Sj^W^NgjSm>UO3nJPcq|=iY6SLykY1K}5yOM4HCCw8(np90gPR~*mA7n>p<}2y zJ{_szCgob1p4a4yL$PTk?-aH!6fciRGWa?24OV8W$0Q0(w>d z{(2mc6yEs1LGN1myv|k0CVkST5_MQApN7p3COd^SL_f850`@pO0Ef#Dm8%>f1`wUj zf}j;|M1TARety~$%VHxgzyjPtfCStL9A>W-Fx^L7#jBJ|Z~;zOxg2i9P-OiPw7h^F zDJot-cnLn-R%XYtB1!}NMRi3$Eb062=p8R|O?V=mp*yqOz?QG0EPY7TcBKg)hp7c+ z0hotC=rO6twLX5Og_7#d*8^CIn_pCM=BB%waeF1o&8hB@^N8a;dDu%uKVuWGjwmJb zBCK2{v|^26Hi+I`{8wrnQuYWclCliosSmJPT^N)7`ayhcN%k;;Dzvh)Xj~-mQK+s+ zZ*P&6v0$X%$@BrwuJ@dJKMX#eS-dnlP@((#{lzcAmDXFqCZk>S+C*Vx;fl7T9{6bl z`hLsZD&Dmb=S@L|$U-991En!jn3vBU|0!auWLtu)$fOD;%4zqRpXQ`2Ke+3j_{uEQ zBk3Q|L4u9AOQv47h=K!jnS<|)r|i|=KPX-P(_*_{5fXJ4ctECl6$>AOa-w^;#amRcd zoah6Mw&-}>+(8O1xuZl70xmH!6(W2i_n!lM?ccG5z-|7*8&CScfznwS> z8b(Ug#utWBLDhg0Q_Q!A`!}kEtnWi>qWfXbD7%+<)zzrAeD|~q*f)!4#AP#(WMApG zHPOekodbj0in|K-fsDz7(JIz)Nh-M^CtDK2<tM z4RDG_AWrpBM~@2XY!NA~sY)*yScD?!hpiLA;ZWDq5BNLoWyPE~&3A!9z@c8DhI&?a zB?(3!GQ@C!o)`~7n_ac}lV+dvZyrCHHtTsB@TxGv4S0-Ne0WFj)ki!274#Q^i+g+@ zX{V-&10A$E|N4hyLf*Gt_~h%tD*8Gr7QXYw_qh^cYt@t<%IQ)(jOGK_;FE?@1Dv*-*5IW9aoD(Y7nRX7sCX`mHb&grPi{L3A^y3OW+Ms%^gqGC+6A*SI|I*5ZE3PkmGZJ3R0I|JV z|GQ#opT4Qiv+hhtXBNbfX}kh_B3643Y$>c?{MK2JYifr7`1m&`?&MMoW{uWMM-sxFW;%e;g zKJC|PLbQ!$=qpQX4hP09|E7CH%~9^ev_Rz%Izco|MTea~k}LAWOGOy7y08ec_r>+F z*WC&gpSl$Ws#X5rt1aM|-bI{XWn9(_sJ?bLmJy7I>&Xj64u&WdVir(DU?mNnm!ssz zNjQ~~$stFZ;7|PD_Vv&9B|k3oMgsLdO#S?3Y0e0?&&nRThB_&F8q`waSwr!h{&Jb- z{37`0%^kG4R$?L59Hu!x}nOE5T(f?!aa5SNBUPkg!*2 z?IE!D`={COdV`Cv+ARuis;%3uj1a-N=s-9dpUI4F$XI5LU;%yv1x|OLDyN4SHDgRj zDM2r_&EbYOWd44a<`sOn4O}AzGrZSynzpHoEB${&q5CdkCHi2@Nl$?Ks&GaBLa2H8 zvJLqc_dC23(o*4ow2>C|!BaxMfMt|KZSQD5 z!Ql(1JwqbC|);Vs$qIn6m^F# zF1q4&$ej#=sAo zBeEw3%$#=`0^D!!n>-5U$EJLkl1;ETe?fR{v_7+{-G;pxrAvTWQ)3HxB7w+mw9osZ zbzza16C**AfH%7;e+Dpf<|P!AX&74+-X_dh6K)UDOagw8F8&OtxK#V6c~#}rCGetZ zq-L`5emFZB%j0Rn=j283wqoY*vD5$H}-&33CX zVevyIz+-buic1MGStK!&jdABY(#@9v52jCL$98PTjh_a{olg(rPJsm!naR~V zmLjB-i7KgLrzPrTy&|X_|Hg_F!Cowf*}1CD5JIu5!7F3wv&x^=0?i>ar=lmn8BN-A z@=kwnV4HTn8Np=_v6I<6i~gwLh*dAMiT=!CzFF@+>xK!t=ivzO&D z8cMj59#y-m=hM>XpPiQ#zEX@^oz1*v`fH~A=IX>|63NPBM$3b(9OG#WV0K8j3QVJ{ zeMxpyf{EzzlVC`OJxCc&qHi?Q`JuxJrNJW#p&|*wpDzFs`mwsJfBScql-f8jZXQs+Eq3e1QKfr-YO7om>Z?rP@nCNb1+qEwIwemkDs8V{jD5-!s zoh}Pn|1)1vLQ{pMiG3lpH58(F73@s(CGk30pij_VWK)w7aZ%6tJ2}_ZxOeU+(4JFP zDZNv>?@b!7;6@Pb4V(P7a`g+Qr{8^r2Gp_wCs0g4b&v*X`ZmE9u}AhzKiaD%tO zoV1NsTacB1XdUFM0!*15v%#S5s-`yegQnYb|5a%BU9LO*v&9(%0^eo($;7Q07GZ8o z#X9Sv+)ryS&p`U)ITR2WE8&3E^B+jGAF+RmC)l#?e(|Z?g5YF{LQa2*Fcg8V@d5`g!C)t%%=b zG;A79>e4X~qVjWN-~ETW`t1HsBQ@z;x_Y56%c8y=-9*pEuaZOgx{Nsru!Rq&kxe+D z`@<6z1j}1uO@EKm9&NRk)(*}mTKJ-Mp1KY)c0H+Y`28PU7#@( zcC^J62aFh>Q+VVdENR5S!d=lB-|bAM(hcx4g!V3$EFb-R+LQm0CnaSz%PWGB73fbAmBZf>q2_p~D$b+w{h};U6$_)xmFnrfLGxmEuHn*DnMkL?eMd zy%yvIF((4YpFu!l6D|%tNPr-VCGgw*o*cG6=HG_ggRm$WN-=e0A@1C!d!^u8$M za->#(W4OoR(eV88=cI$1w)vGssNx0fu39m5v#@y*qqqi?luE*+yv-(G$R+zom+CA)1L;D%H3o>$@ zI5Y+@AZ09pbEt>TB&A)e)Oaa>peK~T$0#-SSe;K^RD@zt$N1nstHbbMkJ6@=10vwA z23&%{C8J^aG?PHos`MIiK8ty8#c%5trg0nrDd^HVMMRxP3{L88bHVP7NT2)5Jp#OM zZ2MfdKaGjX7A!XFkoq_2p@rJY>s9(b)b#~7KR>F;9{2uR)~vQLruP+QfO!azauU?< zetqWeF4}BWBf61rPwAWG{VLf}3$p+G?9)co{y?9R3P>K)$h}(y zFJE+CM1THn8a`F-g#@EMA-Jo4uq9W1k6V>yWj3U&<(S(V9t~0;nIM8B7zT}5oSwW~ z5Z>ROpz=ECJ*c5vJr3LBxJ}}?ZaMcU{Qj8h-`BHYM zaBR3~(x2e@-cN+oe$OItT2wLCgE*72RK%4WI0xiCevt71^?4b%QmHg20`tD}4yp}C z6wfl{@u~}d{ry7Yb*6q)ofVnAyJu=7;moD_P za)9eC`?zp_oW}-RqzjYES*Qb5!3E#>B(cMvUU7qPEv=h}`Dw<|52p!M5RT@JYlFII zS`D7RN~;y zhjb@h=~im!Q%M|x2UD8s;FeRBtMGBfNDw2jJMCddt@45GiOnf(Os~TOrVbmUa{I4? z14&J-$3#Fy;o4^;Kwg3rAvI1YNn8PAZEVjgo2eUE^>IKP<0yw}0mb z&BMIusiJ;-d+GSVj6cAGUe&j@H0L3w_r7#<*w^guE}-J)zw1N+uIL&{z=5RUwg!F= z6dNlFPsVb|C2I%af|r`_bU;yIYK>G`%C1MZ+!{0F5aRw8U;B0rv>38-Kd{V|+ul&g zCMnTlqwD$1U1}d9LgOa*j@$j7*wvd}ToQ!VZjKts8%GIJlXP&# zFWmjy<0~Kx&0MDe;&SF3e1#?C(Vdrk6nm~@&Gm0ZA&cbCGF60;9%6Wo`mkACi2CgU{`&ZY4_grc&i|dXW^WzW*1-j}2Mu_jp8QMJ za&f~gtUBnREK$r}6o+(WeR-oZ7aof;&FRpZa%k~I*>e~C2a?5okSOkMT#x#*`)5fu zi}>bc7`m1p6fJ2((>jIztGUR8v_p~lXbiz>GU%H2if8Td+@_bJr1#B?MpDQ@v7X}} zSDV7|T)w6KV$c*}Bqm5Cwirj-?%k!U3m_%$mj!NxI)`x;DSZ$(Q>cA>_3>`?QkoQr z{abLDK84!5mZ)me!Nzi-%<{Pm_0I5+Ejn1U^e&sh+i)e_^uN{kF}=ZN!R?*lA%-3g z-IjM;9_vW1Ipb56eD2wGdbVchW?JrxP<$7o=)e^K0k&{JGE!|pu5UAMX8Y-Bs2W8c zj-9s9U&=ui%WrMRLN#VzEv&S7F#-o|)Ajiy&stMn!bzO~p3#V=Z>Is?O0$kdJ)b?k zr7(?|KHXW}Y66`avA-x>8H$Xk+Rrg_d-Ga)pxWW@c8>ofWadn zh(b_UZa#>9jIQ;^0Kt7gWXr9(t6Qpn2}P;&Gi%!oau6JiH~Oz{6LC!mD&Bx7QmZSn z5NxuuCy0)lQW{*A7^9r`zShvDVQGdi@$$Ru^xMv%SWCBF?VA_ZmcHhyW^`yoMAEta zMDDZx>QP?eL%@INNWo5Czl^%YG0MfcZ`z?C#SuNyV9O{t!vt@%nmLC60aAqnTzR;U z=~bLKpwh+Hgd0J?WgitNlLgXTl`3pE8)XHM z5^S8T`*RmzW`>edxJ>W zUq^cGUZ13QW**0wbRW%;4#EC@mU!iiK-~#OYTO77cpKhkob#R_2IQT81l>m-*j+}~ z(BMAF1gT%mqby6(M+Z7WHQ1SRwBZtfMuG%iaSnma-f4)U+H0zNh~*nt5A4cx9;Ser z>%k>#r;i^v-OEBeH^4xNG%@KP$jXu89-(i=LgBZrqE#||d z_4KF8RdpTionLsc%$l2L>ZX?+0iEM%vWh-Ow+YI|L5V{>6EC%u*v+kRB%kn?G3VWa zQ%2;R5&ny)^sb$0Y>ygw`qAl=XdJrhp(nqDV;2RJ#9u<9%uT|h8Lk*O3Bq|nZ9ZO= zkvF@LO_gcpDHqq4Fjg&S$};ONFG;>-tCLR+Th3-n87ZTfbONyZhZ^)kr``5|) zi2H3I2l~iSV+HwCQ$<7})E=y*O(Gq}kxIK7dAX11&J%>6dxw{I6X>y#Ik?f06cYxBk(h&MG(q)SiPtS%WnEv>y-)=b8&s?cVn?U zSf=-Hk$Ikq2Cr=yw_+Qh#(xahiP97ULWiJFeWkyuy;RC;omV%AbO{XPz=-taYUxtX@wtf2~U)KR@Eg2R%;&PSw`813MqX3aqH)hL?2W4rG5+A z|BNC`k`o`WGHmdgPV)N4_vo|-poRo8Z|~zEu4wg}yWHkY=>#1@@>k+R-o

WQOwr zeybucG!3XCdRd1EJn0|b#2%%0pu#pI`20&SEYG-n2`JB(o%EJ?*x4Z;PhCr2iT*x$ zx4-sn!tk!z{!W4L1eJKc8d_d-mX6WZxG?n0C4H^0jNCZCN zYE?@tzEwPA&R?2#aTsZ+B9?FdO^4sM{fFFYYp>9-RUpMr4-6iNB2R;PBBuo*3ZgG2 zGhrN0%^A4K^#too4U<9{KSe^jN%PTjX_qJ&;f!kg8oNr@Nt>|T5S4ik6<;gXmb}tW zp?(>5;GY!SHv;u7+xuY~K_}*@P3*gA=>!--IZUe@%lYUA>EW#vu4MIXO&Ao@du2aL z5Uy>rcNMh*J1~#*5It{vO{a0Nr##7R9aFky$%q)~%V#=yqwJFxo{$`xavJsBLC2P` z#n51+fYAIQr% z3+l{p@FY8wl21JT8Al#>!>8Nlw zNKC$`qOy+;+$>O=IOs%@(vd($P57!xKjsSIM9`}s{pt{E;4x4y%tW(u&lRUSxuDoI zv)-jg3Dr6^(NszPXM6vWQss(v6gOQY*F~9s&D)-tic34NtrnWmY=H}W#IFZGCyEJ1 zDIfCdG_JCy-(#260ZS1dy5s_$*TRHofqSNTemfFbh+%#*32-?Rf21)#Lmig#K9*m9i(#UlPOV{meOsHNpsIO z;%L7s=IX_9@RDYFIM3u96-OBRB*}FA(FIbY|3vr$Zf(Xu4ZQnvzh)~u=-l7?W7^&F zh1pY@&-_ZrlO&KRDH>TEwu++V|NBAh8z)=BN3+mhj7s5OEZBnDZ&xiSGK$oeVj*^! z9eFz!69vG9uk&E?AX?LV-Ma-!?bNT$C;txva{4WTuJpt+A0a*@EHO}{Gp zD|>R^g(s#xtkUZVTfY)J65j7PcyhMC=wD$%>AQNF&X6D^&+ zyXc&YshEH5Db$@YJJJhB)ox)CcO4yN+pa2u{uhim-}{DzA7-^fPIM1N1QJuflrn7z zX+`mplK1riHqS>;?HgdFx2+~ygsjX8d%ZdeeSz&xC<`nr$F0|zW=&$GgwT^IM|3&e`@VyTUD!j1+6VE?fAJIS-p*Y-{P*s{-&FUk`rZHDNe|E#4vdAo&fgN# zQqy6uiST?E=|Pq4dhY&3_j$*+8=CN&7ytRT^9`IN z2jY_uU0t)h=Ut=19jLrfG3L!qPqAJ{xBx>@-ogLH_{Oa*s^DTHiAX)Zwa^5>)#V@_ z7svbct`KRz=MF3?U)eL#51+TIkNA6WB^0&n;W8Bj8{2qJru==^RrMg6WfitH7uoW0 zM4Cc3Mqo546W=Q@awoMjMXc!NKRfqA04uR=rvi^?Y_$Jt6~RUkd45_qg>C`iMy}D! ze|I>by%PcVCQs1e|NW6*`vCdqk@2eFM*M1X9A{Tt#7PG-O=wJUi`2wD|KBbD|4Z^} aJeJ~~sNZ&L7?B?U_tVuf)cmUM5dD7*zoIh$ diff --git a/tex/final-presentation/slides.tex b/tex/final-presentation/slides.tex deleted file mode 100644 index c5e1f51ba19c6..0000000000000 --- a/tex/final-presentation/slides.tex +++ /dev/null @@ -1,444 +0,0 @@ -\documentclass{beamer} -\usecolortheme{beaver} -\beamertemplatenavigationsymbolsempty - -% Fonts -\usepackage{fontspec} -\setmainfont{Source Serif Pro}[Ligatures=TeX] -\setsansfont{Source Sans Pro}[Ligatures=TeX] -\setmonofont{Source Code Pro}[ - BoldFont={* Medium}, - BoldItalicFont={* Medium Italic}, -] - -\usepackage[outputdir=out]{minted} -\usepackage{tikz} -\usetikzlibrary{positioning, fit} - -\tikzset{ - invisible/.style={opacity=0,text opacity=0}, - highlight/.style={color=red}, - intro/.code args={<#1>}{% - \only<#1>{\pgfkeysalso{highlight}} - \alt<#1->{}{\pgfkeysalso{invisible}} - }, -} - -\title{Miri} -\subtitle{An interpreter for Rust's mid-level intermediate representation} -\author{ - Scott Olson - \texorpdfstring{\\ \scriptsize{Supervisor: Christopher Dutchyn}}{} -} -\institute{ - CMPT 400 \\ - University of Saskatchewan -} -\date{} -\titlegraphic{ - \includegraphics[width=64px,height=64px]{rust-logo-512x512.png} \\ - \scriptsize{\url{https://www.rust-lang.org}} -} - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% Intro slides -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -\begin{document} - -\maketitle - -\begin{frame}[fragile] - \frametitle{What is Rust? \small{[review]}} - - According to the website\dots - - \begin{quote} - \textbf{Rust} is a systems programming language that runs blazingly fast, - prevents nearly all segfaults, and guarantees thread safety. - \end{quote} - - It's a new programming language from Mozilla, and it looks like this: - - \begin{minted}[ - autogobble, - fontsize=\footnotesize, - mathescape, - xleftmargin=.3in, - ]{rust} - fn factorial(n: u64) -> u64 { - (1..n).fold(1, |a, b| a * b) - } - - fn main() { - for x in 1..6 { - println!("{}", factorial(x)); - } - // $\Rightarrow$ 1 - // $\Rightarrow$ 1 - // $\Rightarrow$ 2 - // $\Rightarrow$ 6 - // $\Rightarrow$ 24 - } - \end{minted} -\end{frame} - -\begin{frame} - \frametitle{How does Rust compile code? \onslide<-6>{\small{[review]}}} - - \begin{center} - \begin{tikzpicture}[x=4cm, y=3.5cm, auto, rounded corners] - \tikzstyle{basic-stage}=[rectangle, draw, thick, align=center] - \tikzstyle{stage}=[basic-stage, font=\tiny] - \tikzstyle{pass}=[thick, -stealth] - \tikzstyle{pass-label}=[font=\footnotesize] - - \node[basic-stage] (src) at (0,0) {Source\\Code}; - \node[basic-stage] (mach) at (2,-1) {Machine\\Code}; - - \draw<1>[pass, out=0, in=180] - (src.east) to node[font=\Huge] {?} (mach.west); - - \node[stage, intro=<2>] (ast) at (1,0) - {\normalsize{AST} \\ Abstract Syntax Tree}; - \draw[pass, intro=<2>] - (src) -- node[pass-label] {Parse} (ast); - - \node[stage, intro=<3>] (hir) at (2,0) - {\normalsize{HIR} \\ High-level Intermediate\\Representation}; - \draw[pass, intro=<3>] - (ast) -- node[pass-label] {Simplify} (hir); - - \node[stage, intro=<4>] (mir) at (0,-1) - {\normalsize{MIR} \\ Mid-level Intermediate\\Representation}; - \path (hir.south) -- coordinate (middle) (mir.north); - \draw[pass, intro=<4>] - (hir.south) |- (middle) -| (mir.north); - \node[pass-label, above, intro=<4>] at (middle) {Lower}; - - \node[stage, intro=<5>] (llvm) at (1,-1) - {\normalsize{LLVM IR} \\ Low-level Intermediate\\Representation}; - \draw[pass, intro=<5>] - (mir) -- node[pass-label] {Translate} (llvm); - - \draw<6->[pass, intro=<6>] - (llvm) -- node[pass-label] {Magic} (mach); - - \node[stage, intro=<7>] (exec) at (1,-1.75) - {\normalsize{Execution}}; - \draw[pass, intro=<7>] - (mach) -- node[pass-label] {CPU} (exec); - - \draw[pass, intro=<8>] - (mir) -- node[pass-label] {Miri} (exec); - \end{tikzpicture} - \end{center} -\end{frame} - -\begin{frame} - \frametitle{Why build Miri?} - \begin{itemize} - \item For fun and learning. - - \item I originally planned to use it for testing the compiler and execution - of unsafe code, but shifted my goals along the way. \pause - - \item Now it serves as an experimental implementation of the upcoming - compile-time function evaluation feature in Rust. \pause - - \begin{itemize} - \item Similar to C++14's \mintinline{cpp}{constexpr} feature. - - \item You can do complicated calculations at compile time and compile - their \emph{results} into the executable. \pause - - \item For example, you can compute a ``perfect hash function'' for a - statically-known map at compile-time and have guaranteed no-collision - lookup at runtime. \pause - - \item Miri actually supports far more of Rust than C++14's - \mintinline{cpp}{constexpr} does of C++ --- even heap allocation and - unsafe code. - \end{itemize} - \end{itemize} -\end{frame} - -\begin{frame} - \frametitle{How was it built?} - - At first I wrote a naive version with a number of downsides: - - \begin{itemize} - \item represented values in a traditional dynamic language format, where - every value was the same size. - - \item didn't work well for aggregates (structs, enums, arrays, etc.). - - \item made unsafe programming tricks that make assumptions about low-level - value layout essentially impossible. - \end{itemize} -\end{frame} - -\begin{frame} - \frametitle{How was it built?} - \begin{itemize} - \item Later, a Rust compiler team member proposed a ``Rust abstract - machine'' with specialized value layout which solved my previous problems. - \pause - - \item His proposal was intended for a compile-time function evaluator in the - Rust compiler, so I effectively implemented an experimental version of - that. \pause - - \item After this point, making Miri work well was primarily a software - engineering problem. - \end{itemize} -\end{frame} - -\begin{frame} - \frametitle{Data layout} - \begin{itemize} - \item Memory in Miri is literally a HashMap from ``allocation IDs'' to - ``abstract allocations''. - - \item Allocations are represented by: \pause - \begin{enumerate} - \item An array of \textbf{raw bytes} with a size based on the type of - the value \pause - \item A set of \textbf{relocations} --- pointers into other abstract - allocations \pause - \item A mask determining which bytes are \textbf{undefined} - \end{enumerate} - \end{itemize} -\end{frame} - -\begin{frame}[fragile] - \frametitle{\texttt{square} example} - \begin{center} - \begin{minted}[autogobble,fontsize=\scriptsize]{rust} - // Rust - fn square(n: u64) -> u64 { - n * n - } - - // Generated MIR - fn square(arg0: u64) -> u64 { - let var0: u64; // n // On function entry, Miri creates - // virtual allocations for all the - // arguments, variables, and - // temporaries. - - bb0: { - var0 = arg0; // Copy the argument into `n`. - return = Mul(var0, var0); // Multiply `n` with itself. - goto -> bb1; // Jump to basic block `bb1`. - } - - bb1: { - return; // Return from the current fn. - } - } - \end{minted} - \end{center} -\end{frame} - -\begin{frame}[fragile] - \frametitle{\texttt{sum} example} - \begin{center} - \begin{minted}[autogobble,fontsize=\tiny]{rust} - // Rust - fn sum() -> u64 { - let mut sum = 0; let mut i = 0; - while i < 10 { sum += i; i += 1; } - sum - } - - // Generated MIR - fn sum() -> u64 { - let mut var0: u64; // sum - let mut var1: u64; // i - let mut tmp0: bool; - - bb0: { - // sum = 0; i = 0; - var0 = const 0u64; var1 = const 0u64; goto -> bb1; - } - bb1: { - // if i < 10 { goto bb2; } else { goto bb3; } - tmp0 = Lt(var1, const 10u64); - if(tmp0) -> [true: bb2, false: bb3]; - } - bb2: { - var0 = Add(var0, var1); // sum = sum + i; - var1 = Add(var1, const 1u64); // i = i + 1; - goto -> bb1; - } - bb3: { - return = var0; goto -> bb4; - } - bb4: { return; } - } - \end{minted} - \end{center} -\end{frame} - -\begin{frame}[fragile] - \frametitle{Heap allocations!} - \begin{minted}[autogobble,fontsize=\scriptsize]{rust} - fn make_vec() -> Vec { - // Empty array with space for 4 bytes - allocated on the heap! - let mut vec = Vec::with_capacity(4); - // Initialize the first two slots. - vec.push(1); - vec.push(2); - vec - } - - // For reference: - // struct Vec { capacity: usize, data: *mut T, length: usize } - - // Resulting allocations (on 32-bit little-endian architectures): - // Region A: - // 04 00 00 00 00 00 00 00 02 00 00 00 - // └───(B)───┘ - // - // Region B: - // 01 02 __ __ (underscores denote undefined bytes) - \end{minted} - - \footnotesize{Evaluating the above involves a number of compiler built-ins, - ``unsafe'' code blocks, and more inside the standard library, - but Miri handles it all.} -\end{frame} - -\begin{frame}[fragile] - \frametitle{Unsafe code!} - \begin{minted}[autogobble,fontsize=\scriptsize]{rust} - fn out_of_bounds() -> u8 { - let mut vec = vec![1, 2] - unsafe { *vec.get_unchecked(5) } - } - - // test.rs:3: error: pointer offset outside bounds of allocation - // test.rs:3: unsafe { *vec.get_unchecked(5) } - // ^~~~~~~~~~~~~~~~~~~~~ - - fn undefined_bytes() -> u8 { - let mut vec = Vec::with_capacity(10); - unsafe { *vec.get_unchecked(5) } - } - - // test.rs:3: error: attempted to read undefined bytes - // test.rs:3: unsafe { *vec.get_unchecked(5) } - // ^~~~~~~~~~~~~~~~~~~~~ - \end{minted} -\end{frame} - -\begin{frame} - \frametitle{What can't Miri do?} - \begin{itemize} - \item Miri can't do all the stuff I didn't implement yet. :) - \begin{itemize} - \item non-trivial casts - \item function pointers - \item calling destructors and freeing memory - \item taking target architecture endianess and alignment information - into account when computing data layout - \item handling all constants properly (but, well, Miri might be - replacing the old constants system) - \end{itemize} - \pause - - \item Miri can't do foreign function calls (e.g. calling functions defined - in C or C++), but there is a reasonable way it could be done with libffi. - \begin{itemize} - \item On the other hand, for constant evaluation in the compiler, you - want the evaluator to be deterministic and safe, so FFI calls might be - banned anyway. - \end{itemize} - \pause - - \item Without quite some effort, Miri will probably never handle inline - assembly... - \end{itemize} -\end{frame} - -\begin{frame} - \begin{center} - \LARGE{Questions?} - \end{center} -\end{frame} - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -% Extra slides -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -\begin{frame}[fragile] - \frametitle{\texttt{varN} vs. \texttt{argN}} - \begin{center} - \begin{minted}[autogobble,fontsize=\scriptsize]{rust} - // Rust - type Pair = (u64, u64); - fn swap((a, b): Pair) -> Pair { - (b, a) - } - - // Generated MIR - fn swap(arg0: (u64, u64)) -> (u64, u64) { - let var0: u64; // a - let var1: u64; // b - - bb0: { - var0 = arg0.0; // get the 1st part of the pair - var1 = arg0.1; // get the 2nd part of the pair - return = (var1, var0); // build a new pair in the result - goto -> bb1; - } - - bb1: { - return; - } - } - \end{minted} - \end{center} -\end{frame} - -\begin{frame}[fragile] - \frametitle{\texttt{factorial} example} - \begin{center} - \begin{minted}[autogobble,fontsize=\tiny]{rust} - // Rust - fn factorial(n: u64) -> u64 { - (1..n).fold(1, |a, b| a * b) - } - - // Generated MIR - fn factorial(arg0: u64) -> u64 { - let var0: u64; // n - let mut tmp0: Range; // Miri calculates sizes for generics like Range. - let mut tmp1: [closure]; - - bb0: { - var0 = arg0; - - // tmp0 = 1..n - tmp0 = Range { start: const 1u64, end: var0 }; - - // tmp1 = |a, b| a * b - tmp1 = [closure]; - - // This loads the MIR for the `fold` fn from the standard library. - // In general, MIR for any function from any library can be loaded. - // return tmp0.fold(1, tmp1) - return = Range::fold(tmp0, const 1u64, tmp1) -> bb1; - } - - bb1: { - return; - } - } - \end{minted} - \end{center} -\end{frame} - -\end{document} diff --git a/tex/report/latexmkrc b/tex/report/latexmkrc deleted file mode 100644 index 23aa1a481b3eb..0000000000000 --- a/tex/report/latexmkrc +++ /dev/null @@ -1,12 +0,0 @@ -# vim: ft=perl - -$pdf_mode = 1; -$pdflatex = 'lualatex --shell-escape %O %S'; -$out_dir = 'out'; - -# This improves latexmk's detection of source files and generated files. -$recorder = 1; - -# Ignore always-regenerated *.pyg files from the minted package when considering -# whether to run pdflatex again. -$hash_calc_ignore_pattern{'pyg'} = '.*'; diff --git a/tex/report/miri-report.tex b/tex/report/miri-report.tex deleted file mode 100644 index 27a063de0272a..0000000000000 --- a/tex/report/miri-report.tex +++ /dev/null @@ -1,663 +0,0 @@ -% vim: tw=100 - -\documentclass[twocolumn]{article} -\usepackage{blindtext} -\usepackage[hypcap]{caption} -\usepackage{fontspec} -\usepackage[colorlinks, urlcolor={blue!80!black}]{hyperref} -\usepackage[outputdir=out]{minted} -\usepackage{relsize} -\usepackage{xcolor} - -\setmonofont{Source Code Pro}[ - BoldFont={* Medium}, - BoldItalicFont={* Medium Italic}, - Scale=MatchLowercase, -] - -\newcommand{\rust}[1]{\mintinline{rust}{#1}} - -\begin{document} - -\title{Miri: \\ \smaller{An interpreter for Rust's mid-level intermediate representation}} -\author{Scott Olson\footnote{\href{mailto:scott@solson.me}{scott@solson.me}} \\ - \smaller{Supervised by Christopher Dutchyn}} -\date{April 12th, 2016} -\maketitle - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -\section{Abstract} - -The increasing need for safe low-level code in contexts like operating systems and browsers is -driving the development of Rust\footnote{\url{https://www.rust-lang.org}}, a programming language -promising high performance without the risk of memory unsafety. To make programming more convenient, -it's often desirable to be able to generate code or perform some computation at compile-time. The -former is mostly covered by Rust's existing macro feature or build-time code generation, but the -latter is currently restricted to a limited form of constant evaluation capable of little beyond -simple math. - -The architecture of the compiler at the time the existing constant evaluator was built limited its -potential for future extension. However, a new intermediate representation was recently -added\footnote{\href{https://github.com/rust-lang/rfcs/blob/master/text/1211-mir.md}{Rust RFC \#1211: Mid-level IR (MIR)}} -to the Rust compiler between the abstract syntax tree and the back-end LLVM IR, called mid-level -intermediate representation, or MIR for short. This report will demonstrate that writing an -interpreter for MIR is a surprisingly effective approach for supporting a large proportion of Rust's -features in compile-time execution. - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -\section{Background} - -The Rust compiler generates an instance of \rust{Mir} for each function [\autoref{fig:mir}]. Each -\rust{Mir} structure represents a control-flow graph for a given function, and contains a list of -``basic blocks'' which in turn contain a list of statements followed by a single terminator. Each -statement is of the form \rust{place = rvalue}. An \rust{Place} is used for referencing variables -and calculating addresses such as when dereferencing pointers, accessing fields, or indexing arrays. -An \rust{Rvalue} represents the core set of operations possible in MIR, including reading a value -from an place, performing math operations, creating new pointers, structures, and arrays, and so -on. Finally, a terminator decides where control will flow next, optionally based on the value of a -boolean or integer. - -\begin{figure}[ht] - \begin{minted}[autogobble]{rust} - struct Mir { - basic_blocks: Vec, - // ... - } - - struct BasicBlockData { - statements: Vec, - terminator: Terminator, - // ... - } - - struct Statement { - place: Place, - rvalue: Rvalue - } - - enum Terminator { - Goto { target: BasicBlock }, - If { - cond: Operand, - targets: [BasicBlock; 2] - }, - // ... - } - \end{minted} - \caption{MIR (simplified)} - \label{fig:mir} -\end{figure} - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -\section{First implementation} - -\subsection{Basic operation} - -To investigate the possibility of executing Rust at compile-time I wrote an interpreter for MIR -called Miri\footnote{\url{https://github.com/solson/miri}}. The structure of the interpreter closely -mirrors the structure of MIR itself. It starts executing a function by iterating the statement list -in the starting basic block, translating the place into a pointer and using the rvalue to decide -what to write into that pointer. Evaluating the rvalue may involve reads (such as for the two sides -of a binary operation) or construction of new values. When the terminator is reached, it is used to -decide which basic block to jump to next. Finally, Miri repeats this entire process, reading -statements from the new block. - -\subsection{Function calls} - -To handle function call terminators\footnote{Calls occur only as terminators, never as rvalues.}, -Miri is required to store some information in a virtual call stack so that it may pick up where it -left off when the callee returns. Each stack frame stores a reference to the \rust{Mir} for the -function being executed, its local variables, its return value location\footnote{Return value -pointers are passed in by callers.}, and the basic block where execution should resume. When Miri -encounters a \rust{Return} terminator in the MIR, it pops one frame off the stack and resumes the -previous function. Miri's execution ends when the function it was initially invoked with returns, -leaving the call stack empty. - -It should be noted that Miri does not itself recurse when a function is called; it merely pushes a -virtual stack frame and jumps to the top of the interpreter loop. Consequently, Miri can interpret -deeply recursive programs without overflowing its native call stack. This approach would allow Miri -to set a virtual stack depth limit and report an error when a program exceeds it. - -\subsection{Flaws} - -This version of Miri supported quite a bit of the Rust language, including booleans, integers, -if-conditions, while-loops, structures, enums, arrays, tuples, pointers, and function calls, -requiring approximately 400 lines of Rust code. However, it had a particularly naive value -representation with a number of downsides. It resembled the data layout of a dynamic language like -Ruby or Python, where every value has the same size\footnote{An \rust{enum} is a discriminated union -with a tag and space to fit the largest variant, regardless of which variant it contains.} in the -interpreter: - -\begin{minted}[autogobble]{rust} - enum Value { - Uninitialized, - Bool(bool), - Int(i64), - Pointer(Pointer), // index into stack - Aggregate { - variant: usize, - data: Pointer, - }, - } -\end{minted} - -This representation did not work well for aggregate types\footnote{That is, structures, enums, -arrays, tuples, and closures.} and required strange hacks to support them. Their contained values -were allocated elsewhere on the stack and pointed to by the aggregate value, which made it more -complicated to implement copying aggregate values from place to place. - -Moreover, while the aggregate issues could be worked around, this value representation made common -unsafe programming tricks (which make assumptions about the low-level value layout) fundamentally -impossible. - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -\section{Current implementation} - -Roughly halfway through my time working on Miri, Eduard -Burtescu\footnote{\href{https://github.com/eddyb}{eddyb on GitHub}} from the Rust compiler -team\footnote{\url{https://www.rust-lang.org/team.html\#Compiler}} made a post on Rust's internal -forums about a ``Rust Abstract Machine'' -specification\footnote{\href{https://internals.rust-lang.org/t/mir-constant-evaluation/3143/31}{Burtescu's -reply on ``MIR constant evaluation''}} which could be used to implement more powerful compile-time -function execution, similar to what is supported by C++14's \mintinline{cpp}{constexpr} feature. -After clarifying some of the details of the data layout with Burtescu via IRC, I started -implementing it in Miri. - -\subsection{Raw value representation} - -The main difference in the new value representation was to represent values by ``abstract -allocations'' containing arrays of raw bytes with different sizes depending on their types. This -mimics how Rust values are represented when compiled for physical machines. In addition to the raw -bytes, allocations carry information about pointers and undefined bytes. - -\begin{minted}[autogobble]{rust} - struct Memory { - map: HashMap, - next_id: AllocId, - } - - struct Allocation { - bytes: Vec, - relocations: BTreeMap, - undef_mask: UndefMask, - } -\end{minted} - -\subsubsection{Relocations} - -The abstract machine represents pointers through ``relocations'', which are analogous to relocations -in linkers\footnote{\href{https://en.wikipedia.org/wiki/Relocation_(computing)}{Relocation -(computing) - Wikipedia}}. Instead of storing a global memory address in the raw byte representation -like on a physical machine, we store an offset from the start of the target allocation and add an -entry to the relocation table which maps the index of the offset bytes to the target allocation. - -In \autoref{fig:reloc}, the relocation stored at offset 0 in \rust{y} points to offset 2 in \rust{x} -(the 2nd 16-bit integer). Thus, the relocation table for \rust{y} is \texttt{\{0 => -x\}}, meaning the next $N$ bytes after offset 0 denote an offset into allocation \rust{x} where $N$ -is the size of a pointer (4 in this example). The example shows this as a labelled line beneath the -offset bytes. - -In effect, the abstract machine represents pointers as \rust{(allocation_id, offset)} pairs. This -makes it easy to detect when pointer accesses go out of bounds. - -\begin{figure}[hb] - \begin{minted}[autogobble]{rust} - let x: [i16; 3] = [0xAABB, 0xCCDD, 0xEEFF]; - let y = &x[1]; - // x: BB AA DD CC FF EE (6 bytes) - // y: 02 00 00 00 (4 bytes) - // └───(x)───┘ - \end{minted} - \caption{Example relocation on 32-bit little-endian} - \label{fig:reloc} -\end{figure} - -\subsubsection{Undefined byte mask} - -The final piece of an abstract allocation is the undefined byte mask. Logically, we store a boolean -for the definedness of every byte in the allocation, but there are multiple ways to make the storage -more compact. I tried two implementations: one based on the endpoints of alternating ranges of -defined and undefined bytes and the other based on a bitmask. The former is more compact but I found -it surprisingly difficult to update cleanly. I currently use the much simpler bitmask system. - -See \autoref{fig:undef} for an example of an undefined byte in a value, represented by underscores. -Note that there is a value for the second byte in the byte array, but it doesn't matter what it is. -The bitmask would be $10_2$, i.e.\ \rust{[true, false]}. - -\begin{figure}[hb] - \begin{minted}[autogobble]{rust} - let x: [u8; 2] = unsafe { - [1, std::mem::uninitialized()] - }; - // x: 01 __ (2 bytes) - \end{minted} - \caption{Example undefined byte} - \label{fig:undef} -\end{figure} - -\subsection{Computing data layout} - -Currently, the Rust compiler's data layouts for types are hidden from Miri, so it does its own data -layout computation which will not always match what the compiler does, since Miri doesn't take -target type alignments into account. In the future, the Rust compiler may be modified so that Miri -can use the exact same data layout. - -Miri's data layout calculation is a relatively simple transformation from Rust types to a structure -with constant size values for primitives and sets of fields with offsets for aggregate types. These -layouts are cached for performance. - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -\section{Deterministic execution} -\label{sec:deterministic} - -In order to be effective as a compile-time evaluator, Miri must have \emph{deterministic execution}, -as explained by Burtescu in the ``Rust Abstract Machine'' post. That is, given a function and -arguments to that function, Miri should always produce identical results. This is important for -coherence in the type checker when constant evaluations are involved in types, such as for sizes of -array types: - -\begin{minted}[autogobble,mathescape]{rust} - const fn get_size() -> usize { /* $\ldots$ */ } - let array: [i32; get_size()]; -\end{minted} - -Since Miri allows execution of unsafe code\footnote{In fact, the distinction between safe and unsafe -doesn't exist at the MIR level.}, it is specifically designed to remain safe while interpreting -potentially unsafe code. When Miri encounters an unrecoverable error, it reports it via the Rust -compiler's usual error reporting mechanism, pointing to the part of the original code where the -error occurred. Below is an example from Miri's -repository.\footnote{\href{https://github.com/solson/miri/blob/master/test/errors.rs}{miri/test/errors.rs}} - -\begin{minted}[autogobble]{rust} - let b = Box::new(42); - let p: *const i32 = &*b; - drop(b); - unsafe { *p } - // ~~ error: dangling pointer - // was dereferenced -\end{minted} -\label{dangling-pointer} - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -\section{Language support} - -In its current state, Miri supports a large proportion of the Rust language, detailed below. The -major exception is a lack of support for FFI\footnote{Foreign Function Interface, e.g.\ calling -functions defined in Assembly, C, or C++.}, which eliminates possibilities like reading and writing -files, user input, graphics, and more. However, for compile-time evaluation in Rust, this limitation -is desired. - -\subsection{Primitives} - -Miri supports booleans, integers of various sizes and signed-ness (i.e.\ \rust{i8}, \rust{i16}, -\rust{i32}, \rust{i64}, \rust{isize}, \rust{u8}, \rust{u16}, \rust{u32}, \rust{u64}, \rust{usize}), -and unary and binary operations over these types. The \rust{isize} and \rust{usize} types will be -sized according to the target machine's pointer size just like in compiled Rust. The \rust{char} and -float types (\rust{f32}, \rust{f64}) are not supported yet, but there are no known barriers to doing -so. - -When examining a boolean in an \rust{if} condition, Miri will report an error if its byte -representation is not precisely 0 or 1, since having any other value for a boolean is undefined -behaviour in Rust. The \rust{char} type will have similar restrictions once it is implemented. - -\subsection{Pointers} - -Both references and raw pointers are supported, with essentially no difference between them in Miri. -It is also possible to do pointer comparisons and math. However, a few operations are considered -errors and a few require special support. - -Firstly, pointers into the same allocations may be compared for ordering, but pointers into -different allocations are considered unordered and Miri will complain if you attempt this. The -reasoning is that different allocations may have different orderings in the global address space at -runtime, making this non-deterministic. However, pointers into different allocations \emph{may} be -compared for direct equality (they are always unequal). - -Secondly, pointers represented using relocations may be compared against pointers casted from -integers (e.g.\ \rust{0 as *const i32}) for things like null pointer checks. To handle these cases, -Miri has a concept of ``integer pointers'' which are always unequal to abstract pointers. Integer -pointers can be compared and operated upon freely. However, note that it is impossible to go from an -integer pointer to an abstract pointer backed by a relocation. It is not valid to dereference an -integer pointer. - -\subsubsection{Slice pointers} - -Rust supports pointers to ``dynamically-sized types'' such as \rust{[T]} and \rust{str} which -represent arrays of indeterminate size. Pointers to such types contain an address \emph{and} the -length of the referenced array. Miri supports these fully. - -\subsubsection{Trait objects} - -Rust also supports pointers to ``trait objects'' which represent some type that implements a trait, -with the specific type unknown at compile-time. These are implemented using virtual dispatch with a -vtable, similar to virtual methods in C++. Miri does not currently support these at all. - -\subsection{Aggregates} - -Aggregates include types declared with \rust{struct} or \rust{enum} as well as tuples, arrays, and -closures. Miri supports all common usage of all of these types. The main missing piece is to handle -\texttt{\#[repr(..)]} annotations which adjust the layout of a \rust{struct} or \rust{enum}. - -\subsection{Place projections} - -This category includes field accesses, dereferencing, accessing data in an \rust{enum} variant, and -indexing arrays. Miri supports all of these, including nested projections such as -\rust{*foo.bar[2]}. - -\subsection{Control flow} - -All of Rust's standard control flow features, including \rust{loop}, \rust{while}, \rust{for}, -\rust{if}, \rust{if let}, \rust{while let}, \rust{match}, \rust{break}, \rust{continue}, and -\rust{return} are supported. In fact, supporting these was quite easy since the Rust compiler -reduces them all down to a small set of control-flow graph primitives in MIR. - -\subsection{Function calls} - -As previously described, Miri supports arbitrary function calls without growing the native stack -(only its virtual call stack). It is somewhat limited by the fact that cross-crate\footnote{A crate -is a single Rust library (or executable).} calls only work for functions whose MIR is stored in -crate metadata. This is currently true for \rust{const}, generic, and inline functions. -A branch of the compiler could be made that stores MIR for all functions. This would be a non-issue -for a compile-time evaluator based on Miri, since it would only call \rust{const fn}s. - -\subsubsection{Method calls} - -Miri supports trait method calls, including invoking all the compiler-internal lookup needed to find -the correct implementation of the method. - -\subsubsection{Closures} - -Calls to closures are also supported with the exception of one edge case\footnote{Calling a closure -that takes a reference to its captures via a closure interface that passes the captures by value is -not yet supported.}. The value part of a closure that holds the captured variables is handled as an -aggregate and the function call part is mostly the same as a trait method call, but with the added -complication that closures use a separate calling convention within the compiler. - -\subsubsection{Function pointers} - -Function pointers are not currently supported by Miri, but there is a relatively simple way they -could be encoded using a relocation with a special reserved allocation identifier. The offset of the -relocation would determine which function it points to in a special array of functions in the -interpreter. - -\subsubsection{Intrinsics} - -To support unsafe code, and in particular to support Rust's standard library, it became clear that -Miri would have to support calls to compiler -intrinsics\footnote{\url{https://doc.rust-lang.org/stable/std/intrinsics/index.html}}. Intrinsics -are function calls which cause the Rust compiler to produce special-purpose code instead of a -regular function call. Miri simply recognizes intrinsic calls by their unique -ABI\footnote{Application Binary Interface, which defines calling conventions. Includes ``C'', -``Rust'', and ``rust-intrinsic''.} and name and runs special-purpose code to handle them. - -An example of an important intrinsic is \rust{size_of} which will cause Miri to write the size of -the type in question to the return value location. The Rust standard library uses intrinsics heavily -to implement various data structures, so this was a major step toward supporting them. Intrinsics -have been implemented on a case-by-case basis as tests which required them were written, and not all -intrinsics are supported yet. - -\subsubsection{Generic function calls} - -Miri needs special support for generic function calls since Rust is a \emph{monomorphizing} -compiler, meaning it generates a special version of each function for each distinct set of type -parameters it gets called with. Since functions in MIR are still polymorphic, Miri has to do the -same thing and substitute function type parameters into all types it encounters to get fully -concrete, monomorphized types. For example, in\ldots - -\begin{minted}[autogobble]{rust} - fn some(t: T) -> Option { Some(t) } -\end{minted} - -\ldots{}Miri needs to know the size of \rust{T} to copy the right amount of bytes from the argument -to the return value. If we call \rust{some(10i32)} Miri will execute \rust{some} knowing that -\rust{T = i32} and generate a representation for \rust{Option}. - -Miri currently does this monomorphization lazily on-demand unlike the Rust back-end which does it -all ahead of time. - -\subsection{Heap allocations} - -The next piece of the puzzle for supporting interesting programs (and the standard library) was heap -allocations. There are two main interfaces for heap allocation in Rust: the built-in \rust{Box} -rvalue in MIR and a set of C ABI foreign functions including \rust{__rust_allocate}, -\rust{__rust_reallocate}, and \rust{__rust_deallocate}. These correspond approximately to -\mintinline{c}{malloc}, \mintinline{c}{realloc}, and \mintinline{c}{free} in C. - -The \rust{Box} rvalue allocates enough space for a single value of a given type. This was easy to -support in Miri. It simply creates a new abstract allocation in the same manner as for -stack-allocated values, since there's no major difference between them in Miri. - -The allocator functions, which are used to implement things like Rust's standard \rust{Vec} type, -were a bit trickier. Rust declares them as \rust{extern "C" fn} so that different allocator -libraries can be linked in at the user's option. Since Miri doesn't actually support FFI and wants -full control of allocations for safety, it ``cheats'' and recognizes these allocator functions in -essentially the same way it recognizes compiler intrinsics. Then, a call to \rust{__rust_allocate} -simply creates another abstract allocation with the requested size and \rust{__rust_reallocate} -grows one. - -In the future, Miri should also track which allocations came from \rust{__rust_allocate} so it can -reject reallocate or deallocate calls on stack allocations. - -\subsection{Destructors} - -When a value which ``owns'' some resource (like a heap allocation or file handle) goes out of scope, -Rust inserts \emph{drop glue} that calls the user-defined destructor for the type if it has one, and -then drops all of the subfields. Destructors for types like \rust{Box} and \rust{Vec} -deallocate heap memory. - -Miri doesn't yet support calling user-defined destructors, but it has most of the machinery in place -to do so already. There \emph{is} support for dropping \rust{Box} types, including deallocating -their associated allocations. This is enough to properly execute the dangling pointer example in -\autoref{sec:deterministic}. - -\subsection{Constants} - -Only basic integer, boolean, string, and byte-string literals are currently supported. Evaluating -more complicated constant expressions in their current form would be a somewhat pointless exercise -for Miri. Instead, we should lower constant expressions to MIR so Miri can run them directly, which -is precisely what would need be done to use Miri as the compiler's constant evaluator. - -\subsection{Static variables} - -Miri doesn't currently support statics, but they would need support similar to constants. Also note -that while it would be invalid to write to static (i.e.\ global) variables in Miri executions, it -would probably be fine to allow reads. - -\subsection{Standard library} - -Throughout the implementation of the above features, I often followed this process: - -\begin{enumerate} - \item Try using a feature from the standard library. - \item See where Miri runs into stuff it can't handle. - \item Fix the problem. - \item Go to 1. -\end{enumerate} - -At present, Miri supports a number of major non-trivial features from the standard library along -with tons of minor features. Smart pointer types such as \rust{Box}, \rust{Rc}\footnote{Reference -counted shared pointer} and \rust{Arc}\footnote{Atomically reference-counted thread-safe shared -pointer} all seem to work. I've also tested using the shared smart pointer types with \rust{Cell} -and \rust{RefCell}\footnote{\href{https://doc.rust-lang.org/stable/std/cell/index.html}{Rust -documentation for cell types}} for internal mutability, and that works as well, although -\rust{RefCell} can't ever be borrowed twice until I implement destructor calls, since a destructor -is what releases the borrow. - -But the standard library collection I spent the most time on was \rust{Vec}, the standard -dynamically-growable array type, similar to C++'s \texttt{std::vector} or Java's -\texttt{java.util.ArrayList}. In Rust, \rust{Vec} is an extremely pervasive collection, so -supporting it is a big win for supporting a larger swath of Rust programs in Miri. - -See \autoref{fig:vec} for an example (working in Miri today) of initializing a \rust{Vec} with a -small amount of space on the heap and then pushing enough elements to force it to reallocate its -data array. This involves cross-crate generic function calls, unsafe code using raw pointers, heap -allocation, handling of uninitialized memory, compiler intrinsics, and more. - -\begin{figure}[t] - \begin{minted}[autogobble]{rust} - struct Vec { - data: *mut T, // 4 byte pointer - capacity: usize, // 4 byte integer - length: usize, // 4 byte integer - } - - let mut v: Vec = - Vec::with_capacity(2); - // v: 00 00 00 00 02 00 00 00 00 00 00 00 - // └─(data)──┘ - // data: __ __ - - v.push(1); - // v: 00 00 00 00 02 00 00 00 01 00 00 00 - // └─(data)──┘ - // data: 01 __ - - v.push(2); - // v: 00 00 00 00 02 00 00 00 02 00 00 00 - // └─(data)──┘ - // data: 01 02 - - v.push(3); - // v: 00 00 00 00 04 00 00 00 03 00 00 00 - // └─(data)──┘ - // data: 01 02 03 __ - \end{minted} - \caption{\rust{Vec} example on 32-bit little-endian} - \label{fig:vec} -\end{figure} - -Miri supports unsafe operations on \rust{Vec} like \rust{v.set_len(10)} or -\rust{v.get_unchecked(2)}, provided that such calls do no invoke undefined behaviour. If a call -\emph{does} invoke undefined behaviour, Miri will abort with an appropriate error message (see -\autoref{fig:vec-error}). - -\begin{figure}[t] - \begin{minted}[autogobble]{rust} - fn out_of_bounds() -> u8 { - let v = vec![1, 2]; - let p = unsafe { v.get_unchecked(5) }; - *p + 10 - // ~~ error: pointer offset outside - // bounds of allocation - } - - fn undefined_bytes() -> u8 { - let v = Vec::::with_capacity(10); - let p = unsafe { v.get_unchecked(5) }; - *p + 10 - // ~~~~~~~ error: attempted to read - // undefined bytes - } - \end{minted} - \caption{\rust{Vec} examples with undefined behaviour} - \label{fig:vec-error} -\end{figure} - -\newpage - -Here is one final code sample Miri can execute that demonstrates many features at once, including -vectors, heap allocation, iterators, closures, raw pointers, and math: - -\begin{minted}[autogobble]{rust} - let x: u8 = vec![1, 2, 3, 4] - .into_iter() - .map(|x| x * x) - .fold(0, |x, y| x + y); - // x: 1e (that is, the hex value - // 0x1e = 30 = 1 + 4 + 9 + 16) -\end{minted} - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -\section{Future directions} - -\subsection{Finishing the implementation} - -There are a number of pressing items on my to-do list for Miri, including: - -\begin{itemize} - \item A much more comprehensive and automated test suite. - \item User-defined destructor calls. - \item Non-trivial casts between primitive types like integers and pointers. - \item Handling statics and global memory. - \item Reporting errors for all undefined behaviour.\footnote{\href{https://doc.rust-lang.org/reference.html\#behavior-considered-undefined}{The Rust reference on what is considered undefined behaviour}} - \item Function pointers. - \item Accounting for target machine primitive type alignment and endianness. - \item Optimizations (undefined byte masks, tail-calls). - \item Benchmarking Miri vs. unoptimized Rust. - \item Various \texttt{TODO}s and \texttt{FIXME}s left in the code. - \item Integrating into the compiler proper. -\end{itemize} - -\subsection{Future projects} - -Other possible Miri-related projects include: - -\begin{itemize} - \item A read-eval-print-loop (REPL) for Rust, which may be easier to implement on top of Miri than - the usual LLVM back-end. - \item A graphical or text-mode debugger that steps through MIR execution one statement at a time, - for figuring out why some compile-time execution is raising an error or simply learning how Rust - works at a low level. - \item A less restricted version of Miri that is able to run foreign functions from C/C++ and - generally has full access to the operating system. Such an interpreter could be used to more - quickly prototype changes to the Rust language that would otherwise require changes to the LLVM - back-end. - \item Unit-testing the compiler by comparing the results of Miri's execution against the results - of LLVM-compiled machine code's execution. This would help to guarantee that compile-time - execution works the same as runtime execution. - \item Some kind of Miri-based symbolic evaluator that examines multiple possible code paths at - once to determine if undefined behaviour could be observed on any of them. -\end{itemize} - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -\section{Final thoughts} - -Writing an interpreter which models values of varying sizes, stack and heap allocation, unsafe -memory operations, and more requires some unconventional techniques compared to conventional -interpreters targeting dynamically-typed languages. However, aside from the somewhat complicated -abstract memory model, making Miri work was primarily a software engineering problem, and not a -particularly tricky one. This is a testament to MIR's suitability as an intermediate representation -for Rust---removing enough unnecessary abstraction to keep it simple. For example, Miri doesn't even -need to know that there are different kinds of loops, or how to match patterns in a \rust{match} -expression. - -Another advantage to targeting MIR is that any new features at the syntax-level or type-level -generally require little to no change in Miri. For example, when the new ``question mark'' syntax -for error handling\footnote{ - \href{https://github.com/rust-lang/rfcs/blob/master/text/0243-trait-based-exception-handling.md} - {Question mark syntax RFC}} -was added to rustc, Miri required no change to support it. -When specialization\footnote{ - \href{https://github.com/rust-lang/rfcs/blob/master/text/1210-impl-specialization.md} - {Specialization RFC}} -was added, Miri supported it with just minor changes to trait method lookup. - -Of course, Miri also has limitations. The inability to execute FFI and inline assembly reduces the -amount of Rust programs Miri could ever execute. The good news is that in the constant evaluator, -FFI can be stubbed out in cases where it makes sense, like I did with \rust{__rust_allocate}. For a -version of Miri not intended for constant evaluation, it may be possible to use libffi to call C -functions from the interpreter. - -In conclusion, Miri is a surprisingly effective project, and a lot of fun to implement. Due to MIR's -tendency to collapse multiple source-level features into one, I often ended up supporting features I -hadn't explicitly intended to. I am excited to work with the compiler team going forward to try to -make Miri useful for constant evaluation in Rust. - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -\section{Thanks} - -A big thanks goes to Eduard Burtescu for writing the abstract machine specification and answering my -incessant questions on IRC, to Niko Matsakis for coming up with the idea for Miri and supporting my -desire to work with the Rust compiler, and to my research supervisor Christopher Dutchyn. Thanks -also to everyone else on the compiler team and on Mozilla IRC who helped me figure stuff out. -Finally, thanks to Daniel Keep and everyone else who helped fix my numerous writing mistakes. - -\end{document} From 722c229c425bdfa249242581f82818c846cd1c5b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 4 Jul 2022 15:58:55 -0400 Subject: [PATCH 3413/3747] add a simple benchmark with concurrency --- bench-cargo-miri/serde2/Cargo.lock | 89 +++++++++++++++++++++++++++++ bench-cargo-miri/serde2/Cargo.toml | 9 +++ bench-cargo-miri/serde2/src/main.rs | 18 ++++++ 3 files changed, 116 insertions(+) create mode 100644 bench-cargo-miri/serde2/Cargo.lock create mode 100644 bench-cargo-miri/serde2/Cargo.toml create mode 100644 bench-cargo-miri/serde2/src/main.rs diff --git a/bench-cargo-miri/serde2/Cargo.lock b/bench-cargo-miri/serde2/Cargo.lock new file mode 100644 index 0000000000000..4875057613543 --- /dev/null +++ b/bench-cargo-miri/serde2/Cargo.lock @@ -0,0 +1,89 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "cargo-miri-test" +version = "0.1.0" +dependencies = [ + "serde", + "serde_json", +] + +[[package]] +name = "itoa" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "112c678d4050afce233f4f2852bb2eb519230b3cf12f33585275537d7e41578d" + +[[package]] +name = "proc-macro2" +version = "1.0.39" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c54b25569025b7fc9651de43004ae593a75ad88543b17178aa5e1b9c4f15f56f" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1feb54ed693b93a84e14094943b84b7c4eae204c512b7ccb95ab0c66d278ad1" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "ryu" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3f6f92acf49d1b98f7a81226834412ada05458b7364277387724a237f062695" + +[[package]] +name = "serde" +version = "1.0.137" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61ea8d54c77f8315140a05f4c7237403bf38b72704d031543aa1d16abbf517d1" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.137" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f26faba0c3959972377d3b2d306ee9f71faee9714294e41bb777f83f88578be" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.81" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b7ce2b32a1aed03c558dc61a5cd328f15aff2dbc17daad8fb8af04d2100e15c" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "syn" +version = "1.0.96" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0748dd251e24453cb8717f0354206b91557e4ec8703673a4b30208f2abaf1ebf" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "unicode-ident" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d22af068fba1eb5edcb4aea19d382b2a3deb4c8f9d475c589b6ada9e0fd493ee" diff --git a/bench-cargo-miri/serde2/Cargo.toml b/bench-cargo-miri/serde2/Cargo.toml new file mode 100644 index 0000000000000..29f0abff5d73d --- /dev/null +++ b/bench-cargo-miri/serde2/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "cargo-miri-test" +version = "0.1.0" +authors = ["Oliver Schneider "] +edition = "2018" + +[dependencies] +serde = { version = "*", features = ["derive"] } +serde_json = "*" diff --git a/bench-cargo-miri/serde2/src/main.rs b/bench-cargo-miri/serde2/src/main.rs new file mode 100644 index 0000000000000..c81b32c13fefb --- /dev/null +++ b/bench-cargo-miri/serde2/src/main.rs @@ -0,0 +1,18 @@ +// Like serde1, but in two threads concurrently. And we don't print. +static JSON: &str = r#"{"buffer":[-29,-42,-40,-37,-28,-5,-21,1,-24,-8,-20,4,-18,26,-24,44,-26,66,-30,86,-37,88,-41,72,-46,50,-31,28,23,14,64,16,51,26,32,34,39,42,48,35,58,0,72,-36,69,-59,58,-98,54,-124,36,-103,12,-110,5,-173,-19,-146,-59,-4,-42,51,1,-23,-6,-30,-6,45,46,47,70,6,55,19,60,38,62,42,47,61,46,40,42,-19,22,-34,6,-35,-50,-61,-141,-37,-171,17,-163,26,-180,46,-154,80,-63,48,-4,18,20,50,47,58,53,44,61,57,85,37,80,0,86,-8,106,-95,49,-213,-8,-131,47,49,63,40,-39,-69,-74,-37,-20,63,-12,58,-14,-12,25,-31,41,11,45,76,47,167,5,261,-37,277,-83,183,-172,35,-122,-79,138,-70,266,69,124,228,0,391,-29,594,-84,702,-78,627,-8,551,-13,509,13,372,120,352,125,622,127,691,223,362,126,386,-33,915,198,958,457,456,298,500,233,1027,469,1096,426,918,160,1067,141,1220,189,1245,164,1375,297,1378,503,1299,702,1550,929,1799,855,1752,547,1830,602,1928,832,1736,796,1735,933,1961,1385,1935,1562,2105,1485,2716,1449,2948,1305,2768,1205,2716,1346,2531,1450,2470,1653,3117,2111,3370,2176,2696,1947,2925,2305,3846,2658,2425,2184,-877,1981,-2261,2623,-1645,2908,-1876,2732,-2704,2953,-2484,3116,-2120,2954,-2442,3216,-2466,3499,-2192,3234,-2392,3361,-2497,3869,-2078,3772,-1858,3915,-2066,4438,-2285,2934,-2294,-280,-2066,-1762,-1992,-1412,-2298,-1535,-2399,-1789,-2223,-1419,-2244,-1334,-2092,-1476,-1777,-1396,-2014,-1571,-2199,-1574,-1843,-1167,-1910,-1446,-2007,-1818,-1506,-1331,-2526,-2048,-5535,-4573,-7148,-5828,-6422,-5327,-5840,-5488,-5992,-6144,-6014,-6164,-6109,-6234,-6271,-6388,-6288,-6156,-6517,-6249,-6794,-6602,-6822,-6418,-6788,-6245,-6490,-6560,-6394,-6794,-7920,-6937,-10397,-7140,-11428,-6972,-11019,-6610,-11141,-6665,-11913,-7046,-11979,-7235,-11599,-7015,-11854,-6912,-12161,-7441,-12136,-7761,-12861,-7292,-13390,-7254,-12345,-7809,-12490,-7463,-13983,-6969,-10489,-8465,-2382,-11054,1272,-12247,-270,-12060,-323,-12113,502,-12486,-697,-12251,-1086,-12141,-181,-13116,-670,-13509,-1173,-12592,-443,-12811,-449,-13698,-934,-12850,-747,-13083,-873,-15036,-1161,-11478,-1047,-2669,-1407,1006,-1658,-1146,-1195,-1297,-1421,-73,-1946,-977,-1590,-1499,-1577,-1010,-1862,-1256,-1389,-962,-1692,-509,-2613,-1317,-2087,-1359,-1997,-1034,-2891,-2024,-119,-84,5651,5723,8074,8306,7156,6870,6985,7106,7312,8403,7114,8096,7173,7848,7082,7827,6761,7189,6985,7368,7076,7835,6992,7297,7453,7260,7016,7755,6025,7429,8533,7352,14150,7628,17142,7077,16399,6947,15939,7475,16564,7069,16463,6882,16400,7602,17031,7233,16543,6517,15395,7018,15985,7104,16689,6869,15655,7622,16155,7198,17884,6022,14056,8856,5665,14484,1815,16782,3034,15786,3107,15664,2312,16517,2965,16443,3036,16120,2287,16584,2479,16720,2693,16073,2535,16159,2958,16609,3067,16086,2716,16579,3035,17752,3092,13704,2499,5265,2620,1452,2808,3024,2444,3275,2839,2267,3340,2857,2968,3232,3066,2867,3152,3072,2248,2961,2413,2807,3238,3237,2368,2699,2262,2392,3537,3339,827,823,-5020,-5359,-7095,-7857,-5973,-6274,-6208,-6279,-6934,-7181,-6893,-6647,-7146,-6687,-7026,-7328,-6451,-6924,-6763,-6535,-7109,-6639,-6926,-6559,-7188,-6799,-6727,-6955,-5786,-6554,-8543,-6796,-14465,-7190,-17356,-6641,-16372,-6529,-15941,-6898,-16526,-6434,-16219,-6520,-16222,-7449,-17077,-7097,-16665,-6476,-15675,-7026,-16498,-6848,-17147,-6271,-15894,-7069,-16266,-7032,-17817,-5991,-13796,-8594,-5421,-14349,-1649,-17288,-2847,-16525,-2974,-15945,-2324,-16482,-3022,-16593,-3097,-16451,-2420,-16780,-2649,-16641,-2836,-15900,-2660,-16214,-3050,-16827,-3111,-15993,-2741,-16151,-2994,-17537,-2933,-13812,-2314,-5216,-2475,-1125,-2648,-2801,-2290,-3285,-2796,-2243,-3415,-2642,-3109,-3000,-3271,-2839,-3408,-3161,-2497,-2876,-2603,-2570,-3351,-3173,-2416,-2832,-2235,-2408,-3405,-3186,-613,-768,5271,5201,7376,7644,6241,6176,6366,6275,6964,7124,6831,6508,6998,6566,6836,7230,6277,6777,6589,6376,6934,6536,6819,6494,7160,6749,6736,6900,5822,6476,8593,6747,14520,7204,17448,6637,16490,6483,16033,6906,16600,6511,16304,6568,16279,7438,17079,7072,16624,6463,15577,7028,16343,6877,16990,6331,15760,7121,16140,7023,17719,5944,13748,8575,5401,14336,1645,17210,2880,16419,3036,15896,2382,16483,3074,16584,3143,16425,2443,16782,2650,16695,2825,15978,2632,16272,3015,16880,3084,16096,2709,16289,2965,17641,2932,13887,2323,5330,2474,1286,2656,2954,2309,3410,2803,2373,3414,2795,3106,3151,3263,2952,3403,3241,2483,2969,2568,2681,3316,3245,2383,2837,2199,2390,3396,3165,641,706,-5230,-5323,-7307,-7790,-6136,-6317,-6268,-6419,-6884,-7278,-6766,-6666,-6976,-6731,-6853,-7406,-6308,-6958,-6636,-6553,-6978,-6703,-6829,-6647,-7156,-6883,-6737,-7017,-5814,-6581,-8575,-6833,-14490,-7270,-17411,-6699,-16466,-6539,-16016,-6931,-16571,-6504,-16257,-6551,-16202,-7408,-16983,-7021,-16545,-6410,-15512,-6976,-16305,-6803,-17017,-6243,-15820,-7037,-16197,-6923,-17802,-5820,-13840,-8455,-5475,-14227,-1724,-17099,-2923,-16314,-3008,-15801,-2362,-16392,-3088,-16506,-3163,-16356,-2503,-16700,-2717,-16605,-2855,-15904,-2710,-16226,-3108,-16870,-3089,-16101,-2747,-16257,-3087,-17584,-2975,-13868,-2324,-5343,-2548,-1275,-2673,-2917,-2213,-3363,-2694,-2311,-3251,-2744,-2867,-3129,-3034,-2939,-3190,-3234,-2346,-2964,-2639,-2658,-3558,-3241,-2670,-2892,-2453,-2437,-3564,-3175,-771,-779,5105,5171,7308,7655,6265,6204,6397,6288,7024,7172,6903,6586,7002,6627,6777,7308,6190,6889,6537,6465,7011,6613,6985,6631,7393,6934,7073,7072,6112,6615,8751,6859,14672,7282,17448,6652,16146,6448,15565,6899,16151,6547,15860,6591,16048,7446,17065,7064,16661,6368,15774,6857,16524,6677,16825,6071,15577,6900,16119,7040,17490,6118,13495,8696,5432,14446,1678,17366,3036,16488,3624,15834,3012,16382,3575,16465,3685,16301,2815,16708,2982,16679,3356,15952,2934,16049,3290,16352,3964,15605,3612,16222,3647,17764,4272,13865,3977,5384,3592,1580,3794,3243,3627,3670,3622,2758,4007,3130,3835,3294,3964,3065,4468,3408,3933,3234,3789,3118,4634,3643,4211,3174,4155,3176,5512,4400,2792,1730,-3702,-4499,-5940,-6691,-4265,-5094,-4381,-5215,-4918,-5746,-4217,-4871,-4402,-4981,-4479,-5525,-3732,-4968,-4118,-4924,-4300,-5349,-3422,-5021,-3876,-4886,-4087,-4860,-2790,-4254,-5025,-4196,-10898,-4415,-13419,-4007,-12198,-4121,-11995,-4413,-12471,-3808,-11937,-3920,-11792,-4583,-12284,-3776,-12085,-3107,-11421,-3583,-11226,-3081,-11157,-2768,-10580,-3914,-10424,-3197,-11040,-1715,-9822,-5144,-6189,-11154,-4236,-13029,-5134,-11598,-5507,-10949,-4921,-11142,-4999,-11180,-4883,-11184,-4366,-11090,-4548,-10887,-4818,-10708,-4866,-10534,-5253,-10272,-5179,-9894,-4633,-10029,-4773,-10382,-4977,-8674,-4668,-5292,-4651,-3928,-4629,-4465,-4312,-3994,-4459,-3528,-4570,-4400,-4272,-4601,-4482,-4035,-4627,-4334,-4080,-4498,-4045,-3835,-4204,-3526,-3695,-3646,-4045,-4101,-4856,-4628,-3338,-3235,-673,-508,28,147,-453,-639,11,0,8,-2,7,0,7,-3,11,-8,15,-9,17,-6,17,-5,13,-3,7,0,3,0,-2,0,-4,0,-4,-2,-6,0,-14,-2,-17,-4,-8,0,-7,5,-17,7,-18,10,-7,18,-2,25,-3,27,0,31,4,34,4,34,8,36,8,37,2,36,4,34,8,28,3,15,0,11,0,12,-5,8,-4,10,0,23,-4,31,-8,30,-2,30,0,26,-6,22,-6,20,-12,15,-19,10,-10,13,-14,6,-43,-13,-43,-16,-9,-12,-10,-29,-42,-40,-37,-28,-5,-21,1,-24,-8,-20,4,-18,26,-24,44,-26,66,-30,86,-37,88,-41,72,-46,50,-31,28,23,14,64,16,51,26,32,34,39,42,48,35,58,0,72,-36,69,-59,58,-98,54,-124,36,-103,12,-110,5,-173,-19,-146,-59,-4,-42,51,1,-23,-6,-30,-6,45,46,47,70,6,55,19,60,38,62,42,47,61,46,40,42,-19,22,-34,6,-35,-50,-61,-141,-37,-171,17,-163,26,-180,46,-154,80,-63,48,-4,18,20,50,47,58,53,44,61,57,85,37,80,0,86,-8,106,-95,49,-213,-8,-131,47,49,63,40,-39,-69,-74,-37,-20,63,-12,58,-14,-12,25,-31,41,11,45,76,47,167,5,261,-37,277,-83,183,-172,35,-122,-79,138,-70,266,69,124,228,0,391,-29,594,-84,702,-78,627,-8,551,-13,509,13,372,120,352,125,622,127,691,223,362,126,386,-33,915,198,958,457,456,298,500,233,1027,469,1096,426,918,160,1067,141,1220,189,1245,164,1375,297,1378,503,1299,702,1550,929,1799,855,1752,547,1830,602,1928,832,1736,796,1735,933,1961,1385,1935,1562,2105,1485,2716,1449,2948,1305,2768,1205,2716,1346,2531,1450,2470,1653,3117,2111,3370,2176,2696,1947,2925,2305,3846,2658,2425,2184,-877,1981,-2261,2623,-1645,2908,-1876,2732,-2704,2953,-2484,3116,-2120,2954,-2442,3216,-2466,3499,-2192,3234,-2392,3361,-2497,3869,-2078,3772,-1858,3915,-2066,4438,-2285,2934,-2294,-280,-2066,-1762,-1992,-1412,-2298,-1535,-2399,-1789,-2223,-1419,-2244,-1334,-2092,-1476,-1777,-1396,-2014,-1571,-2199,-1574,-1843,-1167,-1910,-1446,-2007,-1818,-1506,-1331,-2526,-2048,-5535,-4573,-7148,-5828,-6422,-5327,-5840,-5488,-5992,-6144,-6014,-6164,-6109,-6234,-6271,-6388,-6288,-6156,-6517,-6249,-6794,-6602,-6822,-6418,-6788,-6245,-6490,-6560,-6394,-6794,-7920,-6937,-10397,-7140,-11428,-6972,-11019,-6610,-11141,-6665,-11913,-7046,-11979,-7235,-11599,-7015,-11854,-6912,-12161,-7441,-12136,-7761,-12861,-7292,-13390,-7254,-12345,-7809,-12490,-7463,-13983,-6969,-10489,-8465,-2382,-11054,1272,-12247,-270,-12060,-323,-12113,502,-12486,-697,-12251,-1086,-12141,-181,-13116,-670,-13509,-1173,-12592,-443,-12811,-449,-13698,-934,-12850,-747,-13083,-873,-15036,-1161,-11478,-1047,-2669,-1407,1006,-1658,-1146,-1195,-1297,-1421,-73,-1946,-977,-1590,-1499,-1577,-1010,-1862,-1256,-1389,-962,-1692,-509,-2613,-1317,-2087,-1359,-1997,-1034,-2891,-2024,-119,-84,5651,5723,8074,8306,7156,6870,6985,7106,7312,8403,7114,8096,7173,7848,7082,7827,6761,7189,6985,7368]}"#; + +use serde::Deserialize; +use std::thread; + +#[derive(Deserialize)] +struct DeriveStruct { + buffer: Vec, +} + +fn main() { + let t = thread::spawn(|| { + let _info: DeriveStruct = serde_json::from_str(JSON).unwrap(); + }); + let _info: DeriveStruct = serde_json::from_str(JSON).unwrap(); + t.join().unwrap(); +} From 58b6e592a218f28383b40beb7d78b750173ab67d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 4 Jul 2022 16:10:32 -0400 Subject: [PATCH 3414/3747] trophy case++ --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 00d64d8cc7041..52934a6cd4bc0 100644 --- a/README.md +++ b/README.md @@ -582,6 +582,7 @@ Definite bugs found: * [`rkyv` constructing a `Box<[u8]>` from an overaligned allocation](https://github.com/rkyv/rkyv/commit/a9417193a34757e12e24263178be8b2eebb72456) * [Data race in `thread::scope`](https://github.com/rust-lang/rust/issues/98498) * [`regex` incorrectly handling unaligned `Vec` buffers](https://www.reddit.com/r/rust/comments/vq3mmu/comment/ienc7t0?context=3) +* [Incorrect use of `compare_exchange_weak` in `once_cell`](https://github.com/matklad/once_cell/issues/186) Violations of [Stacked Borrows] found that are likely bugs (but Stacked Borrows is currently just an experiment): From 6ec8909fdb76574f0d236a6b4d783d7bbc5fa4b2 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 4 Jul 2022 19:26:43 -0400 Subject: [PATCH 3415/3747] less silly Cargo.toml --- bench-cargo-miri/serde1/Cargo.toml | 4 ++-- bench-cargo-miri/serde2/Cargo.toml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/bench-cargo-miri/serde1/Cargo.toml b/bench-cargo-miri/serde1/Cargo.toml index 29f0abff5d73d..7cb863a7abf33 100644 --- a/bench-cargo-miri/serde1/Cargo.toml +++ b/bench-cargo-miri/serde1/Cargo.toml @@ -5,5 +5,5 @@ authors = ["Oliver Schneider "] edition = "2018" [dependencies] -serde = { version = "*", features = ["derive"] } -serde_json = "*" +serde = { version = "1.0", features = ["derive"] } +serde_json = "1.0" diff --git a/bench-cargo-miri/serde2/Cargo.toml b/bench-cargo-miri/serde2/Cargo.toml index 29f0abff5d73d..7cb863a7abf33 100644 --- a/bench-cargo-miri/serde2/Cargo.toml +++ b/bench-cargo-miri/serde2/Cargo.toml @@ -5,5 +5,5 @@ authors = ["Oliver Schneider "] edition = "2018" [dependencies] -serde = { version = "*", features = ["derive"] } -serde_json = "*" +serde = { version = "1.0", features = ["derive"] } +serde_json = "1.0" From b2e64653ebdc7c314fb28a6ef8c944a40888ba00 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 4 Jul 2022 19:40:44 -0400 Subject: [PATCH 3416/3747] ensure that benchmarks can actually run --- ci.sh | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/ci.sh b/ci.sh index b914477d44a81..7bdbffd09eee9 100755 --- a/ci.sh +++ b/ci.sh @@ -40,6 +40,13 @@ function run_tests { # any interactive questions. ${PYTHON} test-cargo-miri/run-test.py echo + + # Ensure that our benchmarks all work, on the host at least. + if [ -z "${MIRI_TEST_TARGET+exists}" ]; then + for BENCH in $(ls "bench-cargo-miri"); do + cargo miri run --manifest-path bench-cargo-miri/$BENCH/Cargo.toml + done + fi } function run_tests_minimal { From 6083963b4b67279f5f4c2464f944f8e672be409d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 4 Jul 2022 20:05:22 -0400 Subject: [PATCH 3417/3747] do not enable expensive-debug-assertions in installed Miri in CI --- ci.sh | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/ci.sh b/ci.sh index 7bdbffd09eee9..e7c6ed833c60c 100755 --- a/ci.sh +++ b/ci.sh @@ -1,15 +1,16 @@ #!/bin/bash set -euo pipefail +set -x # Determine configuration export RUSTFLAGS="-D warnings" export CARGO_INCREMENTAL=0 -export CARGO_EXTRA_FLAGS="--all-features" +export CARGO_EXTRA_FLAGS="--all-features" # in particular, expensive-debug-assertions # Prepare echo "Build and install miri" -./miri build --all-targets --locked -./miri install # implicitly locked +CARGO_EXTRA_FLAGS="" ./miri install # implicitly locked -- and the *installed* Miri does *not* get the expensive-debug-assertions feature +./miri build --all-targets --locked # the build that all the `./miri test` below will use echo # Test From afb937ab25e17adc5f2b76fcdf64d8804bdd65b9 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Tue, 5 Jul 2022 10:17:43 +0000 Subject: [PATCH 3418/3747] Bump rust version --- rust-version | 2 +- src/diagnostics.rs | 2 +- src/helpers.rs | 4 ++-- src/stacked_borrows.rs | 2 +- src/stacked_borrows/diagnostics.rs | 6 ++---- 5 files changed, 7 insertions(+), 9 deletions(-) diff --git a/rust-version b/rust-version index 682914e88290b..b726558b7662f 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -46b8c23f3eb5e4d0e0aa27eb3f20d5b8fc3ed51f +4045ce641a9eede71cc12031a2cd71692b273890 diff --git a/src/diagnostics.rs b/src/diagnostics.rs index 28d4733718ef9..a942390e549f5 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -450,7 +450,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let msg = match e { CreatedPointerTag(tag, None) => format!("created tag {tag:?}"), CreatedPointerTag(tag, Some((alloc_id, range))) => - format!("created tag {tag:?} at {alloc_id}{}", HexRange(range)), + format!("created tag {tag:?} at {alloc_id:?}{}", HexRange(range)), PoppedPointerTag(item, tag) => match tag { None => diff --git a/src/helpers.rs b/src/helpers.rs index c051d44fa2561..7e702e065619d 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -699,7 +699,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // FIXME: We are re-getting the allocation each time around the loop. // Would be nice if we could somehow "extend" an existing AllocRange. let alloc = this.get_ptr_alloc(ptr.offset(len, this)?, size1, Align::ONE)?.unwrap(); // not a ZST, so we will get a result - let byte = alloc.read_integer(Size::ZERO, size1)?.to_u8()?; + let byte = alloc.read_integer(alloc_range(Size::ZERO, size1))?.to_u8()?; if byte == 0 { break; } else { @@ -721,7 +721,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // FIXME: We are re-getting the allocation each time around the loop. // Would be nice if we could somehow "extend" an existing AllocRange. let alloc = this.get_ptr_alloc(ptr, size2, align2)?.unwrap(); // not a ZST, so we will get a result - let wchar = alloc.read_integer(Size::ZERO, size2)?.to_u16()?; + let wchar = alloc.read_integer(alloc_range(Size::ZERO, size2))?.to_u16()?; if wchar == 0 { break; } else { diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index cc2ea0b76d87c..efc38fdae3f25 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -1097,7 +1097,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx AllocKind::LiveData => { // This should have alloc_extra data. let alloc_extra = this.get_alloc_extra(alloc_id).unwrap(); - trace!("Stacked Borrows tag {tag:?} exposed in {alloc_id}"); + trace!("Stacked Borrows tag {tag:?} exposed in {alloc_id:?}"); alloc_extra.stacked_borrows.as_ref().unwrap().borrow_mut().exposed_tags.insert(tag); } AllocKind::Function | AllocKind::Dead => { diff --git a/src/stacked_borrows/diagnostics.rs b/src/stacked_borrows/diagnostics.rs index a7b8e5f13cea4..fe3716a911162 100644 --- a/src/stacked_borrows/diagnostics.rs +++ b/src/stacked_borrows/diagnostics.rs @@ -140,9 +140,8 @@ impl AllocHistory { stack: &Stack, ) -> InterpError<'tcx> { let action = format!( - "trying to reborrow {derived_from:?} for {:?} permission at {}[{:#x}]", + "trying to reborrow {derived_from:?} for {:?} permission at {alloc_id:?}[{:#x}]", new.perm, - alloc_id, error_offset.bytes(), ); err_sb_ub( @@ -163,8 +162,7 @@ impl AllocHistory { stack: &Stack, ) -> InterpError<'tcx> { let action = format!( - "attempting a {access} using {tag:?} at {}[{:#x}]", - alloc_id, + "attempting a {access} using {tag:?} at {alloc_id:?}[{:#x}]", error_offset.bytes(), ); err_sb_ub( From a07398d44139fe675bbf3560462151a6524d8065 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 5 Jul 2022 07:38:42 -0400 Subject: [PATCH 3419/3747] we don't need HexRange any more --- src/diagnostics.rs | 33 +++++++++++++++++------------- src/helpers.rs | 9 -------- src/stacked_borrows/diagnostics.rs | 4 ++-- 3 files changed, 21 insertions(+), 25 deletions(-) diff --git a/src/diagnostics.rs b/src/diagnostics.rs index a942390e549f5..11b5a21b2af89 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -8,7 +8,6 @@ use rustc_middle::ty; use rustc_span::{source_map::DUMMY_SP, Span, SpanData, Symbol}; use rustc_target::abi::{Align, Size}; -use crate::helpers::HexRange; use crate::stacked_borrows::{diagnostics::TagHistory, AccessKind}; use crate::*; @@ -184,14 +183,14 @@ pub fn report_error<'tcx, 'mir>( ]; match history { Some(TagHistory::Tagged {tag, created: (created_range, created_span), invalidated, protected }) => { - let msg = format!("{:?} was created by a retag at offsets {}", tag, HexRange(*created_range)); + let msg = format!("{tag:?} was created by a retag at offsets {created_range:?}"); helps.push((Some(*created_span), msg)); if let Some((invalidated_range, invalidated_span)) = invalidated { - let msg = format!("{:?} was later invalidated at offsets {}", tag, HexRange(*invalidated_range)); + let msg = format!("{tag:?} was later invalidated at offsets {invalidated_range:?}"); helps.push((Some(*invalidated_span), msg)); } if let Some((protecting_tag, protecting_tag_span, protection_span)) = protected { - helps.push((Some(*protecting_tag_span), format!("{:?} was protected due to {:?} which was created here", tag, protecting_tag))); + helps.push((Some(*protecting_tag_span), format!("{tag:?} was protected due to {protecting_tag:?} which was created here"))); helps.push((Some(*protection_span), format!("this protector is live for this call"))); } } @@ -448,32 +447,38 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx for e in diagnostics.drain(..) { use NonHaltingDiagnostic::*; let msg = match e { - CreatedPointerTag(tag, None) => format!("created tag {tag:?}"), + CreatedPointerTag(tag, None) => + format!("created tag {tag:?}"), CreatedPointerTag(tag, Some((alloc_id, range))) => - format!("created tag {tag:?} at {alloc_id:?}{}", HexRange(range)), + format!("created tag {tag:?} at {alloc_id:?}{range:?}"), PoppedPointerTag(item, tag) => match tag { None => format!( - "popped tracked tag for item {:?} due to deallocation", - item + "popped tracked tag for item {item:?} due to deallocation", ), Some((tag, access)) => { format!( - "popped tracked tag for item {:?} due to {:?} access for {:?}", - item, access, tag + "popped tracked tag for item {item:?} due to {access:?} access for {tag:?}", ) } }, - CreatedCallId(id) => format!("function call with id {id}"), + CreatedCallId(id) => + format!("function call with id {id}"), CreatedAlloc(AllocId(id), size, align, kind) => - format!("created {kind} allocation of {} bytes (alignment {} bytes) with id {id}", size.bytes(), align.bytes()), - FreedAlloc(AllocId(id)) => format!("freed allocation with id {id}"), + format!( + "created {kind} allocation of {size} bytes (alignment {align} bytes) with id {id}", + size = size.bytes(), + align = align.bytes(), + ), + FreedAlloc(AllocId(id)) => + format!("freed allocation with id {id}"), RejectedIsolatedOp(ref op) => format!("{op} was made to return an error due to isolation"), ProgressReport => format!("progress report: current operation being executed is here"), - Int2Ptr { .. } => format!("integer-to-pointer cast"), + Int2Ptr { .. } => + format!("integer-to-pointer cast"), }; let (title, diag_level) = match e { diff --git a/src/helpers.rs b/src/helpers.rs index 7e702e065619d..4b2604afa2c15 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -905,15 +905,6 @@ pub fn get_local_crates(tcx: TyCtxt<'_>) -> Vec { local_crates } -/// Formats an AllocRange like [0x1..0x3], for use in diagnostics. -pub struct HexRange(pub AllocRange); - -impl std::fmt::Display for HexRange { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "[{:#x}..{:#x}]", self.0.start.bytes(), self.0.end().bytes()) - } -} - /// Helper function used inside the shims of foreign functions to check that /// `target_os` is a supported UNIX OS. pub fn target_os_is_unix(target_os: &str) -> bool { diff --git a/src/stacked_borrows/diagnostics.rs b/src/stacked_borrows/diagnostics.rs index fe3716a911162..cee643fdf8212 100644 --- a/src/stacked_borrows/diagnostics.rs +++ b/src/stacked_borrows/diagnostics.rs @@ -4,7 +4,7 @@ use rustc_middle::mir::interpret::{AllocId, AllocRange}; use rustc_span::{Span, SpanData}; use rustc_target::abi::Size; -use crate::helpers::{CurrentSpan, HexRange}; +use crate::helpers::CurrentSpan; use crate::stacked_borrows::{err_sb_ub, AccessKind, Permission}; use crate::Item; use crate::SbTag; @@ -178,7 +178,7 @@ fn operation_summary( alloc_id: AllocId, alloc_range: AllocRange, ) -> String { - format!("this error occurs as part of {} at {:?}{}", operation, alloc_id, HexRange(alloc_range)) + format!("this error occurs as part of {operation} at {alloc_id:?}{alloc_range:?}") } fn error_cause(stack: &Stack, tag: SbTagExtra) -> &'static str { From 2931e0fd63541d6e39ffa9ec75ffc9b614b73a16 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 3 Jul 2022 23:18:27 -0400 Subject: [PATCH 3420/3747] handle Box with allocators --- src/stacked_borrows.rs | 32 +++++++++---- tests/pass/box-custom-alloc.rs | 87 ++++++++++++++++++++++++++++++++++ 2 files changed, 110 insertions(+), 9 deletions(-) create mode 100644 tests/pass/box-custom-alloc.rs diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index efc38fdae3f25..9969fbdbcd343 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -976,27 +976,30 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Raw pointers need to be enabled. ty::RawPtr(tym) if kind == RetagKind::Raw => Some((RefKind::Raw { mutable: tym.mutbl == Mutability::Mut }, false)), - // Boxes do not get a protector: protectors reflect that references outlive the call - // they were passed in to; that's just not the case for boxes. - ty::Adt(..) if ty.is_box() => Some((RefKind::Unique { two_phase: false }, false)), + // Boxes are handled separately due to that allocator situation. _ => None, } } // We need a visitor to visit all references. However, that requires - // a `MPlaceTy` (or `OpTy), so we have a fast path for reference types that + // a `MPlaceTy` (or `OpTy`), so we have a fast path for reference types that // avoids allocating. - if let Some((mutbl, protector)) = qualify(place.layout.ty, kind) { + if let Some((ref_kind, protector)) = qualify(place.layout.ty, kind) { // Fast path. let val = this.read_immediate(&this.place_to_op(place)?)?; - let val = this.retag_reference(&val, mutbl, protector)?; + let val = this.retag_reference(&val, ref_kind, protector)?; this.write_immediate(*val, place)?; return Ok(()); } // If we don't want to recurse, we are already done. - if !this.machine.stacked_borrows.as_mut().unwrap().get_mut().retag_fields { + // EXCEPT if this is a `Box`, then we have to recurse because allocators. + // (Yes this means we technically also recursively retag the allocator itself even if field + // retagging is not enabled. *shrug*) + if !this.machine.stacked_borrows.as_mut().unwrap().get_mut().retag_fields + && !place.layout.ty.ty_adt_def().is_some_and(|adt| adt.is_box()) + { return Ok(()); } @@ -1034,10 +1037,21 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx self.ecx } + fn visit_box(&mut self, place: &MPlaceTy<'tcx, Tag>) -> InterpResult<'tcx> { + // Boxes do not get a protector: protectors reflect that references outlive the call + // they were passed in to; that's just not the case for boxes. + let (ref_kind, protector) = (RefKind::Unique { two_phase: false }, false); + + let val = self.ecx.read_immediate(&place.into())?; + let val = self.ecx.retag_reference(&val, ref_kind, protector)?; + self.ecx.write_immediate(*val, &place.into())?; + Ok(()) + } + fn visit_value(&mut self, place: &MPlaceTy<'tcx, Tag>) -> InterpResult<'tcx> { - if let Some((mutbl, protector)) = qualify(place.layout.ty, self.kind) { + if let Some((ref_kind, protector)) = qualify(place.layout.ty, self.kind) { let val = self.ecx.read_immediate(&place.into())?; - let val = self.ecx.retag_reference(&val, mutbl, protector)?; + let val = self.ecx.retag_reference(&val, ref_kind, protector)?; self.ecx.write_immediate(*val, &place.into())?; } else if matches!(place.layout.ty.kind(), ty::RawPtr(..)) { // Wide raw pointers *do* have fields and their types are strange. diff --git a/tests/pass/box-custom-alloc.rs b/tests/pass/box-custom-alloc.rs new file mode 100644 index 0000000000000..ef432a86d460a --- /dev/null +++ b/tests/pass/box-custom-alloc.rs @@ -0,0 +1,87 @@ +#![allow(incomplete_features)] // for trait upcasting +#![feature(allocator_api, trait_upcasting)] + +use std::alloc::Layout; +use std::alloc::{AllocError, Allocator}; +use std::cell::Cell; +use std::mem::MaybeUninit; +use std::ptr::{self, NonNull}; + +struct OnceAlloc<'a> { + space: Cell<&'a mut [MaybeUninit]>, +} + +unsafe impl<'shared, 'a: 'shared> Allocator for &'shared OnceAlloc<'a> { + fn allocate(&self, layout: Layout) -> Result, AllocError> { + let space = self.space.replace(&mut []); + + let (ptr, len) = (space.as_mut_ptr(), space.len()); + + if ptr.align_offset(layout.align()) != 0 || len < layout.size() { + return Err(AllocError); + } + + let slice_ptr = ptr::slice_from_raw_parts_mut(ptr as *mut u8, len); + unsafe { Ok(NonNull::new_unchecked(slice_ptr)) } + } + + unsafe fn deallocate(&self, _ptr: NonNull, _layout: Layout) {} +} + +trait MyTrait { + fn hello(&self) -> u8; +} + +impl MyTrait for [u8; 1] { + fn hello(&self) -> u8 { + self[0] + } +} + +trait TheTrait: MyTrait {} + +impl TheTrait for [u8; 1] {} + +/// `Box` is a `ScalarPair` where the 2nd component is the allocator. +fn test1() { + let mut space = vec![MaybeUninit::new(0); 1]; + let once_alloc = OnceAlloc { space: Cell::new(&mut space[..]) }; + + let boxed = Box::new_in([42u8; 1], &once_alloc); + let _val = *boxed; + let with_dyn: Box = boxed; + assert_eq!(42, with_dyn.hello()); + let with_dyn: Box = with_dyn; // upcast + assert_eq!(42, with_dyn.hello()); +} + +// Make the allocator itself so big that the Box is not even a ScalarPair any more. +struct OnceAllocRef<'s, 'a>(&'s OnceAlloc<'a>, u64); + +unsafe impl<'shared, 'a: 'shared> Allocator for OnceAllocRef<'shared, 'a> { + fn allocate(&self, layout: Layout) -> Result, AllocError> { + self.0.allocate(layout) + } + + unsafe fn deallocate(&self, ptr: NonNull, layout: Layout) { + self.0.deallocate(ptr, layout) + } +} + +/// `Box` is an `Aggregate`. +fn test2() { + let mut space = vec![MaybeUninit::new(0); 1]; + let once_alloc = OnceAlloc { space: Cell::new(&mut space[..]) }; + + let boxed = Box::new_in([42u8; 1], OnceAllocRef(&once_alloc, 0)); + let _val = *boxed; + let with_dyn: Box = boxed; + assert_eq!(42, with_dyn.hello()); + let with_dyn: Box = with_dyn; // upcast + assert_eq!(42, with_dyn.hello()); +} + +fn main() { + test1(); + test2(); +} From f3f4bafa1bc670a0b1f6b182407a5b5ddabd5008 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 5 Jul 2022 18:16:20 -0400 Subject: [PATCH 3421/3747] rustup --- rust-version | 2 +- src/machine.rs | 5 +++++ tests/fail/backtrace/bad-backtrace-ptr.rs | 2 +- tests/fail/backtrace/bad-backtrace-ptr.stderr | 4 ++-- tests/fail/dangling_pointers/deref-invalid-ptr.rs | 2 +- tests/fail/dangling_pointers/deref-invalid-ptr.stderr | 4 ++-- tests/fail/dangling_pointers/null_pointer_deref.rs | 2 +- tests/fail/dangling_pointers/null_pointer_deref.stderr | 4 ++-- tests/fail/dangling_pointers/null_pointer_deref_zst.rs | 2 +- tests/fail/dangling_pointers/null_pointer_deref_zst.stderr | 4 ++-- tests/fail/dangling_pointers/null_pointer_write.rs | 2 +- tests/fail/dangling_pointers/null_pointer_write.stderr | 4 ++-- tests/fail/dangling_pointers/null_pointer_write_zst.rs | 2 +- tests/fail/dangling_pointers/null_pointer_write_zst.stderr | 4 ++-- tests/fail/dangling_pointers/storage_dead_dangling.rs | 2 +- tests/fail/dangling_pointers/storage_dead_dangling.stderr | 4 ++-- tests/fail/dangling_pointers/wild_pointer_deref.rs | 2 +- tests/fail/dangling_pointers/wild_pointer_deref.stderr | 4 ++-- tests/fail/function_pointers/cast_int_to_fn_ptr.rs | 2 +- tests/fail/function_pointers/cast_int_to_fn_ptr.stderr | 4 ++-- tests/fail/intrinsics/copy_null.rs | 2 +- tests/fail/intrinsics/copy_null.stderr | 4 ++-- tests/fail/intrinsics/out_of_bounds_ptr_1.stderr | 4 ++-- tests/fail/intrinsics/out_of_bounds_ptr_3.stderr | 4 ++-- tests/fail/intrinsics/ptr_offset_0_plus_0.rs | 2 +- tests/fail/intrinsics/ptr_offset_0_plus_0.stderr | 4 ++-- tests/fail/intrinsics/ptr_offset_int_plus_int.rs | 2 +- tests/fail/intrinsics/ptr_offset_int_plus_int.stderr | 4 ++-- tests/fail/intrinsics/ptr_offset_int_plus_ptr.rs | 2 +- tests/fail/intrinsics/ptr_offset_int_plus_ptr.stderr | 4 ++-- tests/fail/intrinsics/ptr_offset_ptr_plus_0.stderr | 4 ++-- tests/fail/intrinsics/write_bytes_null.rs | 2 +- tests/fail/intrinsics/write_bytes_null.stderr | 4 ++-- tests/fail/provenance/provenance_transmute.stderr | 4 ++-- tests/fail/provenance/ptr_int_unexposed.stderr | 4 ++-- tests/fail/provenance/ptr_invalid.rs | 2 +- tests/fail/provenance/ptr_invalid.stderr | 4 ++-- tests/fail/provenance/ptr_invalid_offset.rs | 2 +- tests/fail/provenance/ptr_invalid_offset.stderr | 4 ++-- tests/fail/stacked_borrows/issue-miri-1050-1.stderr | 4 ++-- tests/fail/stacked_borrows/issue-miri-1050-2.rs | 2 +- tests/fail/stacked_borrows/issue-miri-1050-2.stderr | 4 ++-- 42 files changed, 69 insertions(+), 64 deletions(-) diff --git a/rust-version b/rust-version index b726558b7662f..bc4489ab57ca4 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -4045ce641a9eede71cc12031a2cd71692b273890 +41ad4d9b2dbb895666337d162eda52619a6056db diff --git a/src/machine.rs b/src/machine.rs index 716d4bd5b90c3..18b9a074c7c3b 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -541,6 +541,11 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { ecx.machine.enforce_abi } + #[inline(always)] + fn check_binop_checks_overflow(ecx: &MiriEvalContext<'mir, 'tcx>) -> bool { + ecx.tcx.sess.overflow_checks() + } + #[inline(always)] fn find_mir_or_eval_fn( ecx: &mut MiriEvalContext<'mir, 'tcx>, diff --git a/tests/fail/backtrace/bad-backtrace-ptr.rs b/tests/fail/backtrace/bad-backtrace-ptr.rs index 73d3561445d57..a435b0a69578c 100644 --- a/tests/fail/backtrace/bad-backtrace-ptr.rs +++ b/tests/fail/backtrace/bad-backtrace-ptr.rs @@ -4,6 +4,6 @@ extern "Rust" { fn main() { unsafe { - miri_resolve_frame(std::ptr::null_mut(), 0); //~ ERROR null pointer is not a valid pointer for this operation + miri_resolve_frame(std::ptr::null_mut(), 0); //~ ERROR null pointer is a dangling pointer } } diff --git a/tests/fail/backtrace/bad-backtrace-ptr.stderr b/tests/fail/backtrace/bad-backtrace-ptr.stderr index 969523d8b3fec..72755afb34a7c 100644 --- a/tests/fail/backtrace/bad-backtrace-ptr.stderr +++ b/tests/fail/backtrace/bad-backtrace-ptr.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: null pointer is not a valid pointer for this operation +error: Undefined Behavior: out-of-bounds pointer use: null pointer is a dangling pointer (it has no provenance) --> $DIR/bad-backtrace-ptr.rs:LL:CC | LL | miri_resolve_frame(std::ptr::null_mut(), 0); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ null pointer is not a valid pointer for this operation + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer use: null pointer is a dangling pointer (it has no provenance) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/dangling_pointers/deref-invalid-ptr.rs b/tests/fail/dangling_pointers/deref-invalid-ptr.rs index cb2bbec8bcf01..31b52da774b0c 100644 --- a/tests/fail/dangling_pointers/deref-invalid-ptr.rs +++ b/tests/fail/dangling_pointers/deref-invalid-ptr.rs @@ -3,5 +3,5 @@ fn main() { let x = 16usize as *const u32; - let _y = unsafe { &*x as *const u32 }; //~ ERROR is not a valid pointer + let _y = unsafe { &*x as *const u32 }; //~ ERROR is a dangling pointer } diff --git a/tests/fail/dangling_pointers/deref-invalid-ptr.stderr b/tests/fail/dangling_pointers/deref-invalid-ptr.stderr index 0dc73a6e3b133..68003284994eb 100644 --- a/tests/fail/dangling_pointers/deref-invalid-ptr.stderr +++ b/tests/fail/dangling_pointers/deref-invalid-ptr.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: dereferencing pointer failed: 0x10 is not a valid pointer +error: Undefined Behavior: dereferencing pointer failed: 0x10[noalloc] is a dangling pointer (it has no provenance) --> $DIR/deref-invalid-ptr.rs:LL:CC | LL | let _y = unsafe { &*x as *const u32 }; - | ^^^ dereferencing pointer failed: 0x10 is not a valid pointer + | ^^^ dereferencing pointer failed: 0x10[noalloc] is a dangling pointer (it has no provenance) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/dangling_pointers/null_pointer_deref.rs b/tests/fail/dangling_pointers/null_pointer_deref.rs index 92c45b183c0c7..dad6de85e002d 100644 --- a/tests/fail/dangling_pointers/null_pointer_deref.rs +++ b/tests/fail/dangling_pointers/null_pointer_deref.rs @@ -1,5 +1,5 @@ #[allow(deref_nullptr)] fn main() { - let x: i32 = unsafe { *std::ptr::null() }; //~ ERROR null pointer is not a valid pointer + let x: i32 = unsafe { *std::ptr::null() }; //~ ERROR null pointer is a dangling pointer panic!("this should never print: {}", x); } diff --git a/tests/fail/dangling_pointers/null_pointer_deref.stderr b/tests/fail/dangling_pointers/null_pointer_deref.stderr index 10f4c0f384167..fbb922c4c113c 100644 --- a/tests/fail/dangling_pointers/null_pointer_deref.stderr +++ b/tests/fail/dangling_pointers/null_pointer_deref.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: dereferencing pointer failed: null pointer is not a valid pointer +error: Undefined Behavior: dereferencing pointer failed: null pointer is a dangling pointer (it has no provenance) --> $DIR/null_pointer_deref.rs:LL:CC | LL | let x: i32 = unsafe { *std::ptr::null() }; - | ^^^^^^^^^^^^^^^^^ dereferencing pointer failed: null pointer is not a valid pointer + | ^^^^^^^^^^^^^^^^^ dereferencing pointer failed: null pointer is a dangling pointer (it has no provenance) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/dangling_pointers/null_pointer_deref_zst.rs b/tests/fail/dangling_pointers/null_pointer_deref_zst.rs index f3830c078e5e7..21b0ce37d8dff 100644 --- a/tests/fail/dangling_pointers/null_pointer_deref_zst.rs +++ b/tests/fail/dangling_pointers/null_pointer_deref_zst.rs @@ -3,6 +3,6 @@ #[allow(deref_nullptr)] fn main() { - let x: () = unsafe { *std::ptr::null() }; //~ ERROR dereferencing pointer failed: null pointer is not a valid pointer + let x: () = unsafe { *std::ptr::null() }; //~ ERROR dereferencing pointer failed: null pointer is a dangling pointer panic!("this should never print: {:?}", x); } diff --git a/tests/fail/dangling_pointers/null_pointer_deref_zst.stderr b/tests/fail/dangling_pointers/null_pointer_deref_zst.stderr index 600b9b4254955..40b8d0899b13c 100644 --- a/tests/fail/dangling_pointers/null_pointer_deref_zst.stderr +++ b/tests/fail/dangling_pointers/null_pointer_deref_zst.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: dereferencing pointer failed: null pointer is not a valid pointer +error: Undefined Behavior: dereferencing pointer failed: null pointer is a dangling pointer (it has no provenance) --> $DIR/null_pointer_deref_zst.rs:LL:CC | LL | let x: () = unsafe { *std::ptr::null() }; - | ^^^^^^^^^^^^^^^^^ dereferencing pointer failed: null pointer is not a valid pointer + | ^^^^^^^^^^^^^^^^^ dereferencing pointer failed: null pointer is a dangling pointer (it has no provenance) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/dangling_pointers/null_pointer_write.rs b/tests/fail/dangling_pointers/null_pointer_write.rs index f8dca6882c2d5..c7255baf6642d 100644 --- a/tests/fail/dangling_pointers/null_pointer_write.rs +++ b/tests/fail/dangling_pointers/null_pointer_write.rs @@ -1,4 +1,4 @@ #[allow(deref_nullptr)] fn main() { - unsafe { *std::ptr::null_mut() = 0i32 }; //~ ERROR null pointer is not a valid pointer + unsafe { *std::ptr::null_mut() = 0i32 }; //~ ERROR null pointer is a dangling pointer } diff --git a/tests/fail/dangling_pointers/null_pointer_write.stderr b/tests/fail/dangling_pointers/null_pointer_write.stderr index 803191a7fcfb4..a5bf59e26d25b 100644 --- a/tests/fail/dangling_pointers/null_pointer_write.stderr +++ b/tests/fail/dangling_pointers/null_pointer_write.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: dereferencing pointer failed: null pointer is not a valid pointer +error: Undefined Behavior: dereferencing pointer failed: null pointer is a dangling pointer (it has no provenance) --> $DIR/null_pointer_write.rs:LL:CC | LL | unsafe { *std::ptr::null_mut() = 0i32 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ dereferencing pointer failed: null pointer is not a valid pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ dereferencing pointer failed: null pointer is a dangling pointer (it has no provenance) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/dangling_pointers/null_pointer_write_zst.rs b/tests/fail/dangling_pointers/null_pointer_write_zst.rs index 63474d9651756..60e2d7c663e07 100644 --- a/tests/fail/dangling_pointers/null_pointer_write_zst.rs +++ b/tests/fail/dangling_pointers/null_pointer_write_zst.rs @@ -1,6 +1,6 @@ // Some optimizations remove ZST accesses, thus masking this UB. // compile-flags: -Zmir-opt-level=0 -// error-pattern: memory access failed: null pointer is not a valid pointer +// error-pattern: memory access failed: null pointer is a dangling pointer #[allow(deref_nullptr)] fn main() { diff --git a/tests/fail/dangling_pointers/null_pointer_write_zst.stderr b/tests/fail/dangling_pointers/null_pointer_write_zst.stderr index 2b4d26f8edaf8..0535aaa3e2d16 100644 --- a/tests/fail/dangling_pointers/null_pointer_write_zst.stderr +++ b/tests/fail/dangling_pointers/null_pointer_write_zst.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: memory access failed: null pointer is not a valid pointer +error: Undefined Behavior: memory access failed: null pointer is a dangling pointer (it has no provenance) --> RUSTLIB/core/src/ptr/mod.rs:LL:CC | LL | copy_nonoverlapping(&src as *const T, dst, 1); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: null pointer is not a valid pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: null pointer is a dangling pointer (it has no provenance) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/dangling_pointers/storage_dead_dangling.rs b/tests/fail/dangling_pointers/storage_dead_dangling.rs index 370162142de97..64ed37d151134 100644 --- a/tests/fail/dangling_pointers/storage_dead_dangling.rs +++ b/tests/fail/dangling_pointers/storage_dead_dangling.rs @@ -10,7 +10,7 @@ fn fill(v: &mut i32) { } fn evil() { - unsafe { &mut *(LEAK as *mut i32) }; //~ ERROR is not a valid pointer + unsafe { &mut *(LEAK as *mut i32) }; //~ ERROR is a dangling pointer } fn main() { diff --git a/tests/fail/dangling_pointers/storage_dead_dangling.stderr b/tests/fail/dangling_pointers/storage_dead_dangling.stderr index 23b66325571f7..25c12feaa82d1 100644 --- a/tests/fail/dangling_pointers/storage_dead_dangling.stderr +++ b/tests/fail/dangling_pointers/storage_dead_dangling.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: dereferencing pointer failed: $HEX is not a valid pointer +error: Undefined Behavior: dereferencing pointer failed: $HEX[noalloc] is a dangling pointer (it has no provenance) --> $DIR/storage_dead_dangling.rs:LL:CC | LL | unsafe { &mut *(LEAK as *mut i32) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^ dereferencing pointer failed: $HEX is not a valid pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^ dereferencing pointer failed: $HEX[noalloc] is a dangling pointer (it has no provenance) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/dangling_pointers/wild_pointer_deref.rs b/tests/fail/dangling_pointers/wild_pointer_deref.rs index 7c9f5281fbbbe..9f6b370c050f4 100644 --- a/tests/fail/dangling_pointers/wild_pointer_deref.rs +++ b/tests/fail/dangling_pointers/wild_pointer_deref.rs @@ -2,6 +2,6 @@ fn main() { let p = 44 as *const i32; - let x = unsafe { *p }; //~ ERROR is not a valid pointer + let x = unsafe { *p }; //~ ERROR is a dangling pointer panic!("this should never print: {}", x); } diff --git a/tests/fail/dangling_pointers/wild_pointer_deref.stderr b/tests/fail/dangling_pointers/wild_pointer_deref.stderr index 67b28e25e1dde..571bbcef6595c 100644 --- a/tests/fail/dangling_pointers/wild_pointer_deref.stderr +++ b/tests/fail/dangling_pointers/wild_pointer_deref.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: dereferencing pointer failed: 0x2c is not a valid pointer +error: Undefined Behavior: dereferencing pointer failed: 0x2c[noalloc] is a dangling pointer (it has no provenance) --> $DIR/wild_pointer_deref.rs:LL:CC | LL | let x = unsafe { *p }; - | ^^ dereferencing pointer failed: 0x2c is not a valid pointer + | ^^ dereferencing pointer failed: 0x2c[noalloc] is a dangling pointer (it has no provenance) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/function_pointers/cast_int_to_fn_ptr.rs b/tests/fail/function_pointers/cast_int_to_fn_ptr.rs index 0adbda50bfe50..e287533ffc742 100644 --- a/tests/fail/function_pointers/cast_int_to_fn_ptr.rs +++ b/tests/fail/function_pointers/cast_int_to_fn_ptr.rs @@ -4,5 +4,5 @@ fn main() { let g = unsafe { std::mem::transmute::(42) }; - g(42) //~ ERROR not a valid pointer + g(42) //~ ERROR is a dangling pointer } diff --git a/tests/fail/function_pointers/cast_int_to_fn_ptr.stderr b/tests/fail/function_pointers/cast_int_to_fn_ptr.stderr index 3a80120a9b926..3d4acbe6f09ae 100644 --- a/tests/fail/function_pointers/cast_int_to_fn_ptr.stderr +++ b/tests/fail/function_pointers/cast_int_to_fn_ptr.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: 0x2a is not a valid pointer +error: Undefined Behavior: out-of-bounds pointer use: 0x2a[noalloc] is a dangling pointer (it has no provenance) --> $DIR/cast_int_to_fn_ptr.rs:LL:CC | LL | g(42) - | ^^^^^ 0x2a is not a valid pointer + | ^^^^^ out-of-bounds pointer use: 0x2a[noalloc] is a dangling pointer (it has no provenance) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/intrinsics/copy_null.rs b/tests/fail/intrinsics/copy_null.rs index 7ab41232498ea..237e517f2875a 100644 --- a/tests/fail/intrinsics/copy_null.rs +++ b/tests/fail/intrinsics/copy_null.rs @@ -10,6 +10,6 @@ fn main() { let ptr = &mut data[0] as *mut u16; // Even copying 0 elements from NULL should error. unsafe { - copy_nonoverlapping(std::ptr::null(), ptr, 0); //~ ERROR: memory access failed: null pointer is not a valid pointer + copy_nonoverlapping(std::ptr::null(), ptr, 0); //~ ERROR: memory access failed: null pointer is a dangling pointer } } diff --git a/tests/fail/intrinsics/copy_null.stderr b/tests/fail/intrinsics/copy_null.stderr index 110408227e181..d7725064832e4 100644 --- a/tests/fail/intrinsics/copy_null.stderr +++ b/tests/fail/intrinsics/copy_null.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: memory access failed: null pointer is not a valid pointer +error: Undefined Behavior: memory access failed: null pointer is a dangling pointer (it has no provenance) --> $DIR/copy_null.rs:LL:CC | LL | copy_nonoverlapping(std::ptr::null(), ptr, 0); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: null pointer is not a valid pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: null pointer is a dangling pointer (it has no provenance) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/intrinsics/out_of_bounds_ptr_1.stderr b/tests/fail/intrinsics/out_of_bounds_ptr_1.stderr index 2c4d6bbc50cf8..789e9d1f6cbed 100644 --- a/tests/fail/intrinsics/out_of_bounds_ptr_1.stderr +++ b/tests/fail/intrinsics/out_of_bounds_ptr_1.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: pointer arithmetic failed: ALLOC has size 4, so pointer to 5 bytes starting at offset 0 is out-of-bounds +error: Undefined Behavior: out-of-bounds pointer arithmetic: ALLOC has size 4, so pointer to 5 bytes starting at offset 0 is out-of-bounds --> RUSTLIB/core/src/ptr/const_ptr.rs:LL:CC | LL | unsafe { intrinsics::offset(self, count) } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pointer arithmetic failed: ALLOC has size 4, so pointer to 5 bytes starting at offset 0 is out-of-bounds + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer arithmetic: ALLOC has size 4, so pointer to 5 bytes starting at offset 0 is out-of-bounds | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/intrinsics/out_of_bounds_ptr_3.stderr b/tests/fail/intrinsics/out_of_bounds_ptr_3.stderr index 075f40b54a2c7..973bf043e155c 100644 --- a/tests/fail/intrinsics/out_of_bounds_ptr_3.stderr +++ b/tests/fail/intrinsics/out_of_bounds_ptr_3.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: pointer arithmetic failed: ALLOC has size 4, so pointer to 1 byte starting at offset -1 is out-of-bounds +error: Undefined Behavior: out-of-bounds pointer arithmetic: ALLOC has size 4, so pointer to 1 byte starting at offset -1 is out-of-bounds --> RUSTLIB/core/src/ptr/const_ptr.rs:LL:CC | LL | unsafe { intrinsics::offset(self, count) } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pointer arithmetic failed: ALLOC has size 4, so pointer to 1 byte starting at offset -1 is out-of-bounds + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer arithmetic: ALLOC has size 4, so pointer to 1 byte starting at offset -1 is out-of-bounds | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/intrinsics/ptr_offset_0_plus_0.rs b/tests/fail/intrinsics/ptr_offset_0_plus_0.rs index ca38f39d25157..4098d6b0ced2d 100644 --- a/tests/fail/intrinsics/ptr_offset_0_plus_0.rs +++ b/tests/fail/intrinsics/ptr_offset_0_plus_0.rs @@ -1,4 +1,4 @@ -// error-pattern: pointer arithmetic failed: null pointer is not a valid pointer +// error-pattern: null pointer is a dangling pointer // compile-flags: -Zmiri-permissive-provenance fn main() { diff --git a/tests/fail/intrinsics/ptr_offset_0_plus_0.stderr b/tests/fail/intrinsics/ptr_offset_0_plus_0.stderr index ae9dd15b13304..cb9b02c840519 100644 --- a/tests/fail/intrinsics/ptr_offset_0_plus_0.stderr +++ b/tests/fail/intrinsics/ptr_offset_0_plus_0.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: pointer arithmetic failed: null pointer is not a valid pointer +error: Undefined Behavior: out-of-bounds pointer arithmetic: null pointer is a dangling pointer (it has no provenance) --> RUSTLIB/core/src/ptr/mut_ptr.rs:LL:CC | LL | unsafe { intrinsics::offset(self, count) as *mut T } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pointer arithmetic failed: null pointer is not a valid pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer arithmetic: null pointer is a dangling pointer (it has no provenance) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/intrinsics/ptr_offset_int_plus_int.rs b/tests/fail/intrinsics/ptr_offset_int_plus_int.rs index 809938d999731..817a8b9801b78 100644 --- a/tests/fail/intrinsics/ptr_offset_int_plus_int.rs +++ b/tests/fail/intrinsics/ptr_offset_int_plus_int.rs @@ -1,4 +1,4 @@ -// error-pattern: is not a valid pointer +// error-pattern: is a dangling pointer // compile-flags: -Zmiri-permissive-provenance fn main() { diff --git a/tests/fail/intrinsics/ptr_offset_int_plus_int.stderr b/tests/fail/intrinsics/ptr_offset_int_plus_int.stderr index 49e02651e9636..e92b0a3216652 100644 --- a/tests/fail/intrinsics/ptr_offset_int_plus_int.stderr +++ b/tests/fail/intrinsics/ptr_offset_int_plus_int.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: pointer arithmetic failed: 0x1 is not a valid pointer +error: Undefined Behavior: out-of-bounds pointer arithmetic: 0x1[noalloc] is a dangling pointer (it has no provenance) --> RUSTLIB/core/src/ptr/mut_ptr.rs:LL:CC | LL | unsafe { intrinsics::offset(self, count) as *mut T } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pointer arithmetic failed: 0x1 is not a valid pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer arithmetic: 0x1[noalloc] is a dangling pointer (it has no provenance) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/intrinsics/ptr_offset_int_plus_ptr.rs b/tests/fail/intrinsics/ptr_offset_int_plus_ptr.rs index 903f89ff70ec4..ed6370bf7f178 100644 --- a/tests/fail/intrinsics/ptr_offset_int_plus_ptr.rs +++ b/tests/fail/intrinsics/ptr_offset_int_plus_ptr.rs @@ -1,4 +1,4 @@ -// error-pattern: is not a valid pointer +// error-pattern: is a dangling pointer // compile-flags: -Zmiri-permissive-provenance fn main() { diff --git a/tests/fail/intrinsics/ptr_offset_int_plus_ptr.stderr b/tests/fail/intrinsics/ptr_offset_int_plus_ptr.stderr index fa7a107ab5340..47eac678e2efc 100644 --- a/tests/fail/intrinsics/ptr_offset_int_plus_ptr.stderr +++ b/tests/fail/intrinsics/ptr_offset_int_plus_ptr.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: pointer arithmetic failed: 0x1 is not a valid pointer +error: Undefined Behavior: out-of-bounds pointer arithmetic: 0x1[noalloc] is a dangling pointer (it has no provenance) --> RUSTLIB/core/src/ptr/mut_ptr.rs:LL:CC | LL | unsafe { intrinsics::offset(self, count) as *mut T } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pointer arithmetic failed: 0x1 is not a valid pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer arithmetic: 0x1[noalloc] is a dangling pointer (it has no provenance) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/intrinsics/ptr_offset_ptr_plus_0.stderr b/tests/fail/intrinsics/ptr_offset_ptr_plus_0.stderr index c9b7f88385d90..767ed2fc3c45e 100644 --- a/tests/fail/intrinsics/ptr_offset_ptr_plus_0.stderr +++ b/tests/fail/intrinsics/ptr_offset_ptr_plus_0.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: pointer arithmetic failed: ALLOC has size 4, so pointer at offset 32 is out-of-bounds +error: Undefined Behavior: out-of-bounds pointer arithmetic: ALLOC has size 4, so pointer at offset 32 is out-of-bounds --> RUSTLIB/core/src/ptr/mut_ptr.rs:LL:CC | LL | unsafe { intrinsics::offset(self, count) as *mut T } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pointer arithmetic failed: ALLOC has size 4, so pointer at offset 32 is out-of-bounds + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer arithmetic: ALLOC has size 4, so pointer at offset 32 is out-of-bounds | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/intrinsics/write_bytes_null.rs b/tests/fail/intrinsics/write_bytes_null.rs index 60966f0a94c0d..81b155da44c33 100644 --- a/tests/fail/intrinsics/write_bytes_null.rs +++ b/tests/fail/intrinsics/write_bytes_null.rs @@ -6,5 +6,5 @@ extern "rust-intrinsic" { } fn main() { - unsafe { write_bytes::(std::ptr::null_mut(), 0, 0) }; //~ ERROR memory access failed: null pointer is not a valid pointer + unsafe { write_bytes::(std::ptr::null_mut(), 0, 0) }; //~ ERROR memory access failed: null pointer is a dangling pointer } diff --git a/tests/fail/intrinsics/write_bytes_null.stderr b/tests/fail/intrinsics/write_bytes_null.stderr index 8e8156531b16a..8fd866aa8b325 100644 --- a/tests/fail/intrinsics/write_bytes_null.stderr +++ b/tests/fail/intrinsics/write_bytes_null.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: memory access failed: null pointer is not a valid pointer +error: Undefined Behavior: memory access failed: null pointer is a dangling pointer (it has no provenance) --> $DIR/write_bytes_null.rs:LL:CC | LL | unsafe { write_bytes::(std::ptr::null_mut(), 0, 0) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: null pointer is not a valid pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: null pointer is a dangling pointer (it has no provenance) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/provenance/provenance_transmute.stderr b/tests/fail/provenance/provenance_transmute.stderr index ddbf64f383806..5b7e9442d7c07 100644 --- a/tests/fail/provenance/provenance_transmute.stderr +++ b/tests/fail/provenance/provenance_transmute.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: dereferencing pointer failed: $HEX is not a valid pointer +error: Undefined Behavior: dereferencing pointer failed: $HEX[noalloc] is a dangling pointer (it has no provenance) --> $DIR/provenance_transmute.rs:LL:CC | LL | let _val = *left_ptr; - | ^^^^^^^^^ dereferencing pointer failed: $HEX is not a valid pointer + | ^^^^^^^^^ dereferencing pointer failed: $HEX[noalloc] is a dangling pointer (it has no provenance) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/provenance/ptr_int_unexposed.stderr b/tests/fail/provenance/ptr_int_unexposed.stderr index f0c47e54859ee..f5ea7718c78ae 100644 --- a/tests/fail/provenance/ptr_int_unexposed.stderr +++ b/tests/fail/provenance/ptr_int_unexposed.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: dereferencing pointer failed: $HEX is not a valid pointer +error: Undefined Behavior: dereferencing pointer failed: $HEX[noalloc] is a dangling pointer (it has no provenance) --> $DIR/ptr_int_unexposed.rs:LL:CC | LL | assert_eq!(unsafe { *ptr }, 3); - | ^^^^ dereferencing pointer failed: $HEX is not a valid pointer + | ^^^^ dereferencing pointer failed: $HEX[noalloc] is a dangling pointer (it has no provenance) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/provenance/ptr_invalid.rs b/tests/fail/provenance/ptr_invalid.rs index f4f3ed5afa5c4..be5666b2efadd 100644 --- a/tests/fail/provenance/ptr_invalid.rs +++ b/tests/fail/provenance/ptr_invalid.rs @@ -5,5 +5,5 @@ fn main() { let x = 42; let xptr = &x as *const i32; let xptr_invalid = std::ptr::invalid::(xptr.expose_addr()); - let _val = unsafe { *xptr_invalid }; //~ ERROR is not a valid pointer + let _val = unsafe { *xptr_invalid }; //~ ERROR is a dangling pointer } diff --git a/tests/fail/provenance/ptr_invalid.stderr b/tests/fail/provenance/ptr_invalid.stderr index 0d6c0f92d93bb..02bfef3ae73f2 100644 --- a/tests/fail/provenance/ptr_invalid.stderr +++ b/tests/fail/provenance/ptr_invalid.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: dereferencing pointer failed: $HEX is not a valid pointer +error: Undefined Behavior: dereferencing pointer failed: $HEX[noalloc] is a dangling pointer (it has no provenance) --> $DIR/ptr_invalid.rs:LL:CC | LL | let _val = unsafe { *xptr_invalid }; - | ^^^^^^^^^^^^^ dereferencing pointer failed: $HEX is not a valid pointer + | ^^^^^^^^^^^^^ dereferencing pointer failed: $HEX[noalloc] is a dangling pointer (it has no provenance) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/provenance/ptr_invalid_offset.rs b/tests/fail/provenance/ptr_invalid_offset.rs index 4447575405bb6..08fb57a6569ce 100644 --- a/tests/fail/provenance/ptr_invalid_offset.rs +++ b/tests/fail/provenance/ptr_invalid_offset.rs @@ -1,5 +1,5 @@ // compile-flags: -Zmiri-strict-provenance -// error-pattern: not a valid pointer +// error-pattern: is a dangling pointer #![feature(strict_provenance)] fn main() { diff --git a/tests/fail/provenance/ptr_invalid_offset.stderr b/tests/fail/provenance/ptr_invalid_offset.stderr index 8f19d4ec93580..df73689deae8d 100644 --- a/tests/fail/provenance/ptr_invalid_offset.stderr +++ b/tests/fail/provenance/ptr_invalid_offset.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: pointer arithmetic failed: $HEX is not a valid pointer +error: Undefined Behavior: out-of-bounds pointer arithmetic: $HEX[noalloc] is a dangling pointer (it has no provenance) --> RUSTLIB/core/src/ptr/const_ptr.rs:LL:CC | LL | unsafe { intrinsics::offset(self, count) } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ pointer arithmetic failed: $HEX is not a valid pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer arithmetic: $HEX[noalloc] is a dangling pointer (it has no provenance) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/stacked_borrows/issue-miri-1050-1.stderr b/tests/fail/stacked_borrows/issue-miri-1050-1.stderr index 8180a60a837af..946e3e8e66640 100644 --- a/tests/fail/stacked_borrows/issue-miri-1050-1.stderr +++ b/tests/fail/stacked_borrows/issue-miri-1050-1.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: ALLOC has size 2, so pointer to 4 bytes starting at offset 0 is out-of-bounds +error: Undefined Behavior: out-of-bounds pointer use: ALLOC has size 2, so pointer to 4 bytes starting at offset 0 is out-of-bounds --> RUSTLIB/alloc/src/boxed.rs:LL:CC | LL | Box(unsafe { Unique::new_unchecked(raw) }, alloc) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ALLOC has size 2, so pointer to 4 bytes starting at offset 0 is out-of-bounds + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer use: ALLOC has size 2, so pointer to 4 bytes starting at offset 0 is out-of-bounds | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/stacked_borrows/issue-miri-1050-2.rs b/tests/fail/stacked_borrows/issue-miri-1050-2.rs index 7d8809cedcd79..2a969686d4da9 100644 --- a/tests/fail/stacked_borrows/issue-miri-1050-2.rs +++ b/tests/fail/stacked_borrows/issue-miri-1050-2.rs @@ -1,4 +1,4 @@ -// error-pattern: is not a valid pointer +// error-pattern: is a dangling pointer use std::ptr::NonNull; fn main() { diff --git a/tests/fail/stacked_borrows/issue-miri-1050-2.stderr b/tests/fail/stacked_borrows/issue-miri-1050-2.stderr index 61ce006dc82b9..33ac311766775 100644 --- a/tests/fail/stacked_borrows/issue-miri-1050-2.stderr +++ b/tests/fail/stacked_borrows/issue-miri-1050-2.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: 0x4 is not a valid pointer +error: Undefined Behavior: out-of-bounds pointer use: 0x4[noalloc] is a dangling pointer (it has no provenance) --> RUSTLIB/alloc/src/boxed.rs:LL:CC | LL | Box(unsafe { Unique::new_unchecked(raw) }, alloc) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 0x4 is not a valid pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer use: 0x4[noalloc] is a dangling pointer (it has no provenance) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information From 6c8ad4abc9e794b412dfe17edf186b28fe2a3e1a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 5 Jul 2022 21:11:48 -0400 Subject: [PATCH 3422/3747] fix comparing wide raw pointers --- src/operator.rs | 16 +++++++++++++--- tests/pass/pointers.rs | 25 +++++++++++++++++++++++++ 2 files changed, 38 insertions(+), 3 deletions(-) diff --git a/src/operator.rs b/src/operator.rs index 61c72270e9f7e..33c97e7d31098 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -44,9 +44,19 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { } Lt | Le | Gt | Ge => { - // Just compare the integers. - let left = left.to_scalar()?.to_bits(left.layout.size)?; - let right = right.to_scalar()?.to_bits(right.layout.size)?; + let size = self.pointer_size(); + // Just compare the bits. ScalarPairs are compared lexicographically. + // We thus always compare pairs and simply fill scalars up with 0. + let left = match **left { + Immediate::Scalar(l) => (l.check_init()?.to_bits(size)?, 0), + Immediate::ScalarPair(l1, l2) => + (l1.check_init()?.to_bits(size)?, l2.check_init()?.to_bits(size)?), + }; + let right = match **right { + Immediate::Scalar(r) => (r.check_init()?.to_bits(size)?, 0), + Immediate::ScalarPair(r1, r2) => + (r1.check_init()?.to_bits(size)?, r2.check_init()?.to_bits(size)?), + }; let res = match bin_op { Lt => left < right, Le => left <= right, diff --git a/tests/pass/pointers.rs b/tests/pass/pointers.rs index 898ecc0faf755..a0c20af426973 100644 --- a/tests/pass/pointers.rs +++ b/tests/pass/pointers.rs @@ -1,3 +1,5 @@ +use std::mem::transmute; + fn one_line_ref() -> i16 { *&1 } @@ -48,6 +50,27 @@ fn dangling_pointer() -> *const i32 { &b.0 as *const i32 } +fn wide_ptr_ops() { + let a: *const dyn Send = &1 as &dyn Send; + let b: *const dyn Send = &1 as &dyn Send; + let _val = a == b; + let _val = a != b; + let _val = a < b; + let _val = a <= b; + let _val = a > b; + let _val = a >= b; + + let a: *const [u8] = unsafe { transmute((1usize, 1usize)) }; + let b: *const [u8] = unsafe { transmute((1usize, 2usize)) }; + // confirmed with rustc. + assert!(!(a == b)); + assert!(a != b); + assert!(a <= b); + assert!(a < b); + assert!(!(a >= b)); + assert!(!(a > b)); +} + fn main() { assert_eq!(one_line_ref(), 1); assert_eq!(basic_ref(), 1); @@ -91,4 +114,6 @@ fn main() { assert!(dangling > 2); assert!(dangling > 3); assert!(dangling >= 4); + + wide_ptr_ops(); } From de2915bba709c96c902d7666d5173b8196349e81 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 5 Jul 2022 22:29:38 -0400 Subject: [PATCH 3423/3747] rustup --- rust-version | 2 +- tests/pass/enums.rs | 13 +++++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/rust-version b/rust-version index bc4489ab57ca4..123c4a5b5b56a 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -41ad4d9b2dbb895666337d162eda52619a6056db +f342bea9d19f14616c6559312552e6d0ee529cfd diff --git a/tests/pass/enums.rs b/tests/pass/enums.rs index d2dc06525475e..ac7aafc1bb2e3 100644 --- a/tests/pass/enums.rs +++ b/tests/pass/enums.rs @@ -119,6 +119,18 @@ fn more_discriminant_overflow() { } } +fn overaligned_casts() { + #[allow(dead_code)] + #[repr(align(8))] + enum Aligned { + Zero = 0, + One = 1, + } + + let aligned = Aligned::Zero; + assert_eq!(aligned as u8, 0); +} + fn main() { test(MyEnum::MyEmptyVariant); test(MyEnum::MyNewtypeVariant(42)); @@ -127,4 +139,5 @@ fn main() { discriminant_overflow(); more_discriminant_overflow(); + overaligned_casts(); } From 907a003f14cb34e8b429f23bfb86a4a33634ea68 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 6 Jul 2022 09:47:48 -0400 Subject: [PATCH 3424/3747] tweak format strings --- src/diagnostics.rs | 31 ++++++++++-------------- src/intptrcast.rs | 4 ++-- src/machine.rs | 2 +- src/shims/intrinsics.rs | 38 ++++++++++++------------------ src/stacked_borrows/diagnostics.rs | 10 ++++---- tests/fail/uninit_buffer.stderr | 2 +- 6 files changed, 37 insertions(+), 50 deletions(-) diff --git a/src/diagnostics.rs b/src/diagnostics.rs index 11b5a21b2af89..289c46a5d2ef8 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -40,24 +40,20 @@ impl fmt::Display for TerminationInfo { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { use TerminationInfo::*; match self { - Exit(code) => write!(f, "the evaluated program completed with exit code {}", code), - Abort(msg) => write!(f, "{}", msg), - UnsupportedInIsolation(msg) => write!(f, "{}", msg), + Exit(code) => write!(f, "the evaluated program completed with exit code {code}"), + Abort(msg) => write!(f, "{msg}"), + UnsupportedInIsolation(msg) => write!(f, "{msg}"), Int2PtrWithStrictProvenance => write!( f, "integer-to-pointer casts and `ptr::from_exposed_addr` are not supported with `-Zmiri-strict-provenance`" ), - StackedBorrowsUb { msg, .. } => write!(f, "{}", msg), + StackedBorrowsUb { msg, .. } => write!(f, "{msg}"), Deadlock => write!(f, "the evaluated program deadlocked"), MultipleSymbolDefinitions { link_name, .. } => - write!(f, "multiple definitions of symbol `{}`", link_name), + write!(f, "multiple definitions of symbol `{link_name}`"), SymbolShimClashing { link_name, .. } => - write!( - f, - "found `{}` symbol definition that clashes with a built-in shim", - link_name - ), + write!(f, "found `{link_name}` symbol definition that clashes with a built-in shim",), } } } @@ -200,11 +196,11 @@ pub fn report_error<'tcx, 'mir>( } MultipleSymbolDefinitions { first, first_crate, second, second_crate, .. } => vec![ - (Some(*first), format!("it's first defined here, in crate `{}`", first_crate)), - (Some(*second), format!("then it's defined here again, in crate `{}`", second_crate)), + (Some(*first), format!("it's first defined here, in crate `{first_crate}`")), + (Some(*second), format!("then it's defined here again, in crate `{second_crate}`")), ], SymbolShimClashing { link_name, span } => - vec![(Some(*span), format!("the `{}` symbol is defined here", link_name))], + vec![(Some(*span), format!("the `{link_name}` symbol is defined here"))], Int2PtrWithStrictProvenance => vec![(None, format!("use Strict Provenance APIs (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance, https://crates.io/crates/sptr) instead"))], _ => vec![], @@ -227,7 +223,7 @@ pub fn report_error<'tcx, 'mir>( ) => "post-monomorphization error", kind => - bug!("This error should be impossible in Miri: {:?}", kind), + bug!("This error should be impossible in Miri: {kind:?}"), }; #[rustfmt::skip] let helps = match e.kind() { @@ -235,7 +231,7 @@ pub fn report_error<'tcx, 'mir>( UnsupportedOpInfo::ThreadLocalStatic(_) | UnsupportedOpInfo::ReadExternStatic(_) ) => - panic!("Error should never be raised by Miri: {:?}", e.kind()), + panic!("Error should never be raised by Miri: {kind:?}", kind = e.kind()), Unsupported( UnsupportedOpInfo::Unsupported(_) | UnsupportedOpInfo::PartialPointerOverwrite(_) | @@ -295,9 +291,8 @@ pub fn report_error<'tcx, 'mir>( match e.kind() { UndefinedBehavior(UndefinedBehaviorInfo::InvalidUninitBytes(Some((alloc_id, access)))) => { eprintln!( - "Uninitialized read occurred at offsets 0x{:x}..0x{:x} into this allocation:", - access.uninit_offset.bytes(), - access.uninit_offset.bytes() + access.uninit_size.bytes(), + "Uninitialized read occurred at {alloc_id:?}{range:?}, in this allocation:", + range = alloc_range(access.uninit_offset, access.uninit_size), ); eprintln!("{:?}", ecx.dump_alloc(*alloc_id)); } diff --git a/src/intptrcast.rs b/src/intptrcast.rs index 5a33ada450443..e569960f68fba 100644 --- a/src/intptrcast.rs +++ b/src/intptrcast.rs @@ -110,7 +110,7 @@ impl<'mir, 'tcx> GlobalStateInner { ecx: &MiriEvalContext<'mir, 'tcx>, addr: u64, ) -> Pointer> { - trace!("Transmuting 0x{:x} to a pointer", addr); + trace!("Transmuting {:#x} to a pointer", addr); let provenance = if ecx.machine.allow_ptr_int_transmute { // When we allow transmutes, treat them like casts: generating a wildcard pointer. @@ -126,7 +126,7 @@ impl<'mir, 'tcx> GlobalStateInner { ecx: &MiriEvalContext<'mir, 'tcx>, addr: u64, ) -> InterpResult<'tcx, Pointer>> { - trace!("Casting 0x{:x} to a pointer", addr); + trace!("Casting {:#x} to a pointer", addr); let global_state = ecx.machine.intptrcast.borrow(); diff --git a/src/machine.rs b/src/machine.rs index 18b9a074c7c3b..029c32cad9173 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -155,7 +155,7 @@ impl Provenance for Tag { fn fmt(ptr: &Pointer, f: &mut fmt::Formatter<'_>) -> fmt::Result { let (tag, addr) = ptr.into_parts(); // address is absolute - write!(f, "0x{:x}", addr.bytes())?; + write!(f, "{:#x}", addr.bytes())?; match tag { Tag::Concrete { alloc_id, sb } => { diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index d8f6292e9df39..652f5c94cb372 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -36,7 +36,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let intrinsic_name = this.tcx.item_name(instance.def_id()); let intrinsic_name = intrinsic_name.as_str(); let ret = match ret { - None => throw_unsup_format!("unimplemented (diverging) intrinsic: {}", intrinsic_name), + None => throw_unsup_format!("unimplemented (diverging) intrinsic: `{intrinsic_name}`"), Some(p) => p, }; @@ -86,7 +86,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // `checked_mul` enforces a too small bound (the correct one would probably be machine_isize_max), // but no actual allocation can be big enough for the difference to be noticeable. let byte_count = ty_layout.size.checked_mul(count, this).ok_or_else(|| { - err_ub_format!("overflow computing total size of `{}`", intrinsic_name) + err_ub_format!("overflow computing total size of `{intrinsic_name}`") })?; this.write_bytes_ptr( ptr, @@ -200,24 +200,20 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ty::Float(FloatTy::F32) => x.to_scalar()?.to_f32()?.is_finite(), ty::Float(FloatTy::F64) => x.to_scalar()?.to_f64()?.is_finite(), _ => bug!( - "`{}` called with non-float input type {:?}", - intrinsic_name, - x.layout.ty + "`{intrinsic_name}` called with non-float input type {ty:?}", + ty = x.layout.ty, ), }) }; match (float_finite(a)?, float_finite(b)?) { (false, false) => throw_ub_format!( - "`{}` intrinsic called with non-finite value as both parameters", - intrinsic_name, + "`{intrinsic_name}` intrinsic called with non-finite value as both parameters", ), (false, _) => throw_ub_format!( - "`{}` intrinsic called with non-finite value as first parameter", - intrinsic_name, + "`{intrinsic_name}` intrinsic called with non-finite value as first parameter", ), (_, false) => throw_ub_format!( - "`{}` intrinsic called with non-finite value as second parameter", - intrinsic_name, + "`{intrinsic_name}` intrinsic called with non-finite value as second parameter", ), _ => {} } @@ -494,7 +490,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // See . if overflowed { let r_val = right.to_scalar()?.to_bits(right.layout.size)?; - throw_ub_format!("overflowing shift by {} in `{}` in SIMD lane {}", r_val, intrinsic_name, i); + throw_ub_format!("overflowing shift by {r_val} in `{intrinsic_name}` in SIMD lane {i}"); } } if matches!(mir_op, BinOp::Eq | BinOp::Ne | BinOp::Lt | BinOp::Le | BinOp::Gt | BinOp::Ge) { @@ -751,9 +747,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.float_to_int_unchecked(op.to_scalar()?.to_f64()?, dest.layout.ty)?.into(), _ => throw_unsup_format!( - "Unsupported SIMD cast from element type {} to {}", - op.layout.ty, - dest.layout.ty + "Unsupported SIMD cast from element type {from_ty} to {to_ty}", + from_ty = op.layout.ty, + to_ty = dest.layout.ty, ), }; this.write_immediate(val, &dest.into())?; @@ -1093,7 +1089,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx throw_machine_stop!(TerminationInfo::Abort("Trace/breakpoint trap".to_string())) } - name => throw_unsup_format!("unimplemented intrinsic: {}", name), + name => throw_unsup_format!("unimplemented intrinsic: `{name}`"), } trace!("{:?}", this.dump_place(**dest)); @@ -1340,9 +1336,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } else { // `f` was not representable in this integer type. throw_ub_format!( - "`float_to_int_unchecked` intrinsic called on {} which cannot be represented in target type `{:?}`", - f, - dest_ty, + "`float_to_int_unchecked` intrinsic called on {f} which cannot be represented in target type `{dest_ty:?}`", ); } } @@ -1356,14 +1350,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } else { // `f` was not representable in this integer type. throw_ub_format!( - "`float_to_int_unchecked` intrinsic called on {} which cannot be represented in target type `{:?}`", - f, - dest_ty, + "`float_to_int_unchecked` intrinsic called on {f} which cannot be represented in target type `{dest_ty:?}`", ); } } // Nothing else - _ => bug!("`float_to_int_unchecked` called with non-int output type {:?}", dest_ty), + _ => bug!("`float_to_int_unchecked` called with non-int output type {dest_ty:?}"), }) } } diff --git a/src/stacked_borrows/diagnostics.rs b/src/stacked_borrows/diagnostics.rs index cee643fdf8212..d787865c4e2d2 100644 --- a/src/stacked_borrows/diagnostics.rs +++ b/src/stacked_borrows/diagnostics.rs @@ -140,9 +140,9 @@ impl AllocHistory { stack: &Stack, ) -> InterpError<'tcx> { let action = format!( - "trying to reborrow {derived_from:?} for {:?} permission at {alloc_id:?}[{:#x}]", - new.perm, - error_offset.bytes(), + "trying to reborrow {derived_from:?} for {new_perm:?} permission at {alloc_id:?}[{offset:#x}]", + new_perm = new.perm, + offset = error_offset.bytes(), ); err_sb_ub( format!("{}{}", action, error_cause(stack, derived_from)), @@ -162,8 +162,8 @@ impl AllocHistory { stack: &Stack, ) -> InterpError<'tcx> { let action = format!( - "attempting a {access} using {tag:?} at {alloc_id:?}[{:#x}]", - error_offset.bytes(), + "attempting a {access} using {tag:?} at {alloc_id:?}[{offset:#x}]", + offset = error_offset.bytes(), ); err_sb_ub( format!("{}{}", action, error_cause(stack, tag)), diff --git a/tests/fail/uninit_buffer.stderr b/tests/fail/uninit_buffer.stderr index e684ca8f07714..e8faf8dd8b971 100644 --- a/tests/fail/uninit_buffer.stderr +++ b/tests/fail/uninit_buffer.stderr @@ -17,7 +17,7 @@ LL | drop(slice1.cmp(slice2)); note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace -Uninitialized read occurred at offsets 0x4..0x10 into this allocation: +Uninitialized read occurred at ALLOC[0x4..0x10], in this allocation: ALLOC (Rust heap, size: 32, align: 8) { 0x00 │ 41 42 43 44 __ __ __ __ __ __ __ __ __ __ __ __ │ ABCD░░░░░░░░░░░░ 0x10 │ 00 __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ │ .░░░░░░░░░░░░░░░ From 501a6b4687a73068ff86c01a37d009c6ea2743dc Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 6 Jul 2022 14:06:15 -0400 Subject: [PATCH 3425/3747] rustup --- rust-version | 2 +- src/machine.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/rust-version b/rust-version index 123c4a5b5b56a..da7e1a1ae7d29 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -f342bea9d19f14616c6559312552e6d0ee529cfd +049308cf8b48e9d67e54d6d0b01c10c79d1efc3a diff --git a/src/machine.rs b/src/machine.rs index 029c32cad9173..a2d9e9ced1a14 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -542,7 +542,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { } #[inline(always)] - fn check_binop_checks_overflow(ecx: &MiriEvalContext<'mir, 'tcx>) -> bool { + fn checked_binop_checks_overflow(ecx: &MiriEvalContext<'mir, 'tcx>) -> bool { ecx.tcx.sess.overflow_checks() } From d5f1c263806880280a3e4d9b01170791d360c618 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 6 Jul 2022 21:28:47 -0400 Subject: [PATCH 3426/3747] rustup; ptr atomics --- rust-version | 2 +- src/helpers.rs | 4 +-- src/operator.rs | 66 ++++++++++++++++++++--------------------- src/shims/intrinsics.rs | 31 +++++++++++-------- tests/pass/atomic.rs | 55 +++++++++++++++++++++++++++++++++- 5 files changed, 107 insertions(+), 51 deletions(-) diff --git a/rust-version b/rust-version index da7e1a1ae7d29..8f3b1d39fd049 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -049308cf8b48e9d67e54d6d0b01c10c79d1efc3a +7665c3543079ebc3710b676d0fd6951bedfd4b29 diff --git a/src/helpers.rs b/src/helpers.rs index 4b2604afa2c15..29bf92af3faf2 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -195,9 +195,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// Test if this pointer equals 0. fn ptr_is_null(&self, ptr: Pointer>) -> InterpResult<'tcx, bool> { - let this = self.eval_context_ref(); - let null = Scalar::null_ptr(this); - this.ptr_eq(Scalar::from_maybe_pointer(ptr, this), null) + Ok(ptr.addr().bytes() == 0) } /// Get the `Place` for a local diff --git a/src/operator.rs b/src/operator.rs index 33c97e7d31098..e7a43ac955200 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -1,6 +1,7 @@ use log::trace; use rustc_middle::{mir, ty::Ty}; +use rustc_target::abi::Size; use crate::*; @@ -11,8 +12,6 @@ pub trait EvalContextExt<'tcx> { left: &ImmTy<'tcx, Tag>, right: &ImmTy<'tcx, Tag>, ) -> InterpResult<'tcx, (Scalar, bool, Ty<'tcx>)>; - - fn ptr_eq(&self, left: Scalar, right: Scalar) -> InterpResult<'tcx, bool>; } impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { @@ -27,23 +26,8 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { trace!("ptr_op: {:?} {:?} {:?}", *left, bin_op, *right); Ok(match bin_op { - Eq | Ne => { - // This supports fat pointers. - #[rustfmt::skip] - let eq = match (**left, **right) { - (Immediate::Scalar(left), Immediate::Scalar(right)) => { - self.ptr_eq(left.check_init()?, right.check_init()?)? - } - (Immediate::ScalarPair(left1, left2), Immediate::ScalarPair(right1, right2)) => { - self.ptr_eq(left1.check_init()?, right1.check_init()?)? - && self.ptr_eq(left2.check_init()?, right2.check_init()?)? - } - _ => bug!("Type system should not allow comparing Scalar with ScalarPair"), - }; - (Scalar::from_bool(if bin_op == Eq { eq } else { !eq }), false, self.tcx.types.bool) - } - - Lt | Le | Gt | Ge => { + Eq | Ne | Lt | Le | Gt | Ge => { + assert_eq!(left.layout.abi, right.layout.abi); // types an differ, e.g. fn ptrs with different `for` let size = self.pointer_size(); // Just compare the bits. ScalarPairs are compared lexicographically. // We thus always compare pairs and simply fill scalars up with 0. @@ -58,35 +42,49 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { (r1.check_init()?.to_bits(size)?, r2.check_init()?.to_bits(size)?), }; let res = match bin_op { + Eq => left == right, + Ne => left != right, Lt => left < right, Le => left <= right, Gt => left > right, Ge => left >= right, - _ => bug!("We already established it has to be one of these operators."), + _ => bug!(), }; (Scalar::from_bool(res), false, self.tcx.types.bool) } Offset => { + assert!(left.layout.ty.is_unsafe_ptr()); + let ptr = self.scalar_to_ptr(left.to_scalar()?)?; + let offset = right.to_scalar()?.to_machine_isize(self)?; + let pointee_ty = left.layout.ty.builtin_deref(true).expect("Offset called on non-ptr type").ty; - let ptr = self.ptr_offset_inbounds( - self.scalar_to_ptr(left.to_scalar()?)?, - pointee_ty, - right.to_scalar()?.to_machine_isize(self)?, - )?; + let ptr = self.ptr_offset_inbounds(ptr, pointee_ty, offset)?; (Scalar::from_maybe_pointer(ptr, self), false, left.layout.ty) } - _ => bug!("Invalid operator on pointers: {:?}", bin_op), - }) - } + // Some more operations are possible with atomics. + // The return value always has the provenance of the *left* operand. + Add | Sub | BitOr | BitAnd | BitXor => { + assert!(left.layout.ty.is_unsafe_ptr()); + assert!(right.layout.ty.is_unsafe_ptr()); + let ptr = self.scalar_to_ptr(left.to_scalar()?)?; + // We do the actual operation with usize-typed scalars. + let left = ImmTy::from_uint(ptr.addr().bytes(), self.machine.layouts.usize); + let right = ImmTy::from_uint( + right.to_scalar()?.to_machine_usize(self)?, + self.machine.layouts.usize, + ); + let (result, overflowing, _ty) = + self.overflowing_binary_op(bin_op, &left, &right)?; + // Construct a new pointer with the provenance of `ptr` (the LHS). + let result_ptr = + Pointer::new(ptr.provenance, Size::from_bytes(result.to_machine_usize(self)?)); + (Scalar::from_maybe_pointer(result_ptr, self), overflowing, left.layout.ty) + } - fn ptr_eq(&self, left: Scalar, right: Scalar) -> InterpResult<'tcx, bool> { - let size = self.pointer_size(); - // Just compare the integers. - let left = left.to_bits(size)?; - let right = right.to_bits(size)?; - Ok(left == right) + _ => span_bug!(self.cur_span(), "Invalid operator on pointers: {:?}", bin_op), + }) } } diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 652f5c94cb372..9cf9461715f1a 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -314,7 +314,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ty::Float(FloatTy::F64) => this.float_to_int_unchecked(val.to_scalar()?.to_f64()?, dest.layout.ty)?, _ => - bug!( + span_bug!( + this.cur_span(), "`float_to_int_unchecked` called with non-float input type {:?}", val.layout.ty ), @@ -371,7 +372,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Op::Abs => { // Works for f32 and f64. let ty::Float(float_ty) = op.layout.ty.kind() else { - bug!("{} operand is not a float", intrinsic_name) + span_bug!(this.cur_span(), "{} operand is not a float", intrinsic_name) }; let op = op.to_scalar()?; match float_ty { @@ -381,7 +382,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } Op::HostOp(host_op) => { let ty::Float(float_ty) = op.layout.ty.kind() else { - bug!("{} operand is not a float", intrinsic_name) + span_bug!(this.cur_span(), "{} operand is not a float", intrinsic_name) }; // FIXME using host floats match float_ty { @@ -546,7 +547,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Works for f32 and f64. let ty::Float(float_ty) = dest.layout.ty.kind() else { - bug!("{} operand is not a float", intrinsic_name) + span_bug!(this.cur_span(), "{} operand is not a float", intrinsic_name) }; let val = match float_ty { FloatTy::F32 => @@ -763,7 +764,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // `index` is an array, not a SIMD type let ty::Array(_, index_len) = index.layout.ty.kind() else { - bug!("simd_shuffle index argument has non-array type {}", index.layout.ty) + span_bug!(this.cur_span(), "simd_shuffle index argument has non-array type {}", index.layout.ty) }; let index_len = index_len.eval_usize(*this.tcx, this.param_env()); @@ -785,10 +786,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx &this.mplace_index(&right, src_index - left_len)?.into(), )? } else { - bug!( - "simd_shuffle index {} is out of bounds for 2 vectors of size {}", - src_index, - left_len + span_bug!( + this.cur_span(), + "simd_shuffle index {src_index} is out of bounds for 2 vectors of size {left_len}", ); }; this.write_immediate(*val, &dest.into())?; @@ -1187,8 +1187,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let [place, rhs] = check_arg_count(args)?; let place = this.deref_operand(place)?; - if !place.layout.ty.is_integral() { - bug!("Atomic arithmetic operations only work on integer types"); + if !place.layout.ty.is_integral() && !place.layout.ty.is_unsafe_ptr() { + span_bug!( + this.cur_span(), + "atomic arithmetic operations only work on integer and raw pointer types", + ); } let rhs = this.read_immediate(rhs)?; @@ -1355,7 +1358,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } // Nothing else - _ => bug!("`float_to_int_unchecked` called with non-int output type {dest_ty:?}"), + _ => + span_bug!( + this.cur_span(), + "`float_to_int_unchecked` called with non-int output type {dest_ty:?}" + ), }) } } diff --git a/tests/pass/atomic.rs b/tests/pass/atomic.rs index b0c3cc889d556..75e9cbdf13262 100644 --- a/tests/pass/atomic.rs +++ b/tests/pass/atomic.rs @@ -1,10 +1,15 @@ -use std::sync::atomic::{compiler_fence, fence, AtomicBool, AtomicIsize, AtomicU64, Ordering::*}; +// compile-flags: -Zmiri-strict-provenance +#![feature(strict_provenance, strict_provenance_atomic_ptr)] +use std::sync::atomic::{ + compiler_fence, fence, AtomicBool, AtomicIsize, AtomicPtr, AtomicU64, Ordering::*, +}; fn main() { atomic_bool(); atomic_all_ops(); atomic_u64(); atomic_fences(); + atomic_ptr(); weak_sometimes_fails(); } @@ -130,6 +135,54 @@ fn atomic_fences() { compiler_fence(AcqRel); } +fn atomic_ptr() { + use std::ptr; + let array: Vec = (0..100).into_iter().collect(); // a target to point to, to test provenance things + let x = array.as_ptr() as *mut i32; + + let ptr = AtomicPtr::::new(ptr::null_mut()); + assert!(ptr.load(Relaxed).addr() == 0); + ptr.store(ptr::invalid_mut(13), SeqCst); + assert!(ptr.swap(x, Relaxed).addr() == 13); + unsafe { assert!(*ptr.load(Acquire) == 0) }; + + // comparison ignores provenance + assert_eq!( + ptr.compare_exchange( + (&mut 0 as *mut i32).with_addr(x.addr()), + ptr::invalid_mut(0), + SeqCst, + SeqCst + ) + .unwrap() + .addr(), + x.addr(), + ); + assert_eq!( + ptr.compare_exchange( + (&mut 0 as *mut i32).with_addr(x.addr()), + ptr::invalid_mut(0), + SeqCst, + SeqCst + ) + .unwrap_err() + .addr(), + 0, + ); + ptr.store(x, Relaxed); + + assert_eq!(ptr.fetch_ptr_add(13, AcqRel).addr(), x.addr()); + unsafe { assert_eq!(*ptr.load(SeqCst), 13) }; // points to index 13 now + assert_eq!(ptr.fetch_ptr_sub(4, AcqRel).addr(), x.addr() + 13 * 4); + unsafe { assert_eq!(*ptr.load(SeqCst), 9) }; + assert_eq!(ptr.fetch_or(3, AcqRel).addr(), x.addr() + 9 * 4); // ptr is 4-aligned, so set the last 2 bits + assert_eq!(ptr.fetch_and(!3, AcqRel).addr(), (x.addr() + 9 * 4) | 3); // and unset them again + unsafe { assert_eq!(*ptr.load(SeqCst), 9) }; + assert_eq!(ptr.fetch_xor(0xdeadbeef, AcqRel).addr(), x.addr() + 9 * 4); + assert_eq!(ptr.fetch_xor(0xdeadbeef, AcqRel).addr(), (x.addr() + 9 * 4) ^ 0xdeadbeef); + unsafe { assert_eq!(*ptr.load(SeqCst), 9) }; // after XORing twice with the same thing, we get our ptr back +} + fn weak_sometimes_fails() { let atomic = AtomicBool::new(false); let tries = 100; From e5df0cc770893d3139f7b5610e09eebe5df79ae1 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 2 Jul 2022 20:10:44 -0400 Subject: [PATCH 3427/3747] adjust tests for removal of unsized_locals --- tests/fail/unsized-local.rs | 23 ++++++++++++++++++++ tests/fail/unsized-local.stderr | 14 ++++++++++++ tests/pass/dyn-traits.rs | 12 ++++------- tests/pass/unsized-tuple-impls.rs | 13 ----------- tests/pass/unsized.rs | 36 +++++++++++++++++++++++++++++++ 5 files changed, 77 insertions(+), 21 deletions(-) create mode 100644 tests/fail/unsized-local.rs create mode 100644 tests/fail/unsized-local.stderr delete mode 100644 tests/pass/unsized-tuple-impls.rs create mode 100644 tests/pass/unsized.rs diff --git a/tests/fail/unsized-local.rs b/tests/fail/unsized-local.rs new file mode 100644 index 0000000000000..8dd07c585c627 --- /dev/null +++ b/tests/fail/unsized-local.rs @@ -0,0 +1,23 @@ +#![feature(unsized_locals)] +#![allow(incomplete_features)] + +fn main() { + pub trait Foo { + fn foo(self) -> String; + } + + struct A; + + impl Foo for A { + fn foo(self) -> String { + format!("hello") + } + } + + let x = *(Box::new(A) as Box); //~ERROR unsized locals are not supported + assert_eq!(x.foo(), format!("hello")); + + // I'm not sure whether we want this to work + let x = Box::new(A) as Box; + assert_eq!(x.foo(), format!("hello")); +} diff --git a/tests/fail/unsized-local.stderr b/tests/fail/unsized-local.stderr new file mode 100644 index 0000000000000..8277bc4546cb1 --- /dev/null +++ b/tests/fail/unsized-local.stderr @@ -0,0 +1,14 @@ +error: unsupported operation: unsized locals are not supported + --> $DIR/unsized-local.rs:LL:CC + | +LL | let x = *(Box::new(A) as Box); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unsized locals are not supported + | + = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support + = note: backtrace: + = note: inside `main` at $DIR/unsized-local.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/pass/dyn-traits.rs b/tests/pass/dyn-traits.rs index 00667757b0488..908d521a0d816 100644 --- a/tests/pass/dyn-traits.rs +++ b/tests/pass/dyn-traits.rs @@ -1,6 +1,3 @@ -#![feature(unsized_locals, unsized_fn_params)] -#![allow(incomplete_features)] - fn ref_box_dyn() { struct Struct(i32); @@ -75,6 +72,9 @@ fn box_box_trait() { assert!(unsafe { DROPPED }); } +// Disabled for now: unsized locals are not supported, +// their current MIR encoding is just not great. +/* fn unsized_dyn() { pub trait Foo { fn foo(self) -> String; @@ -95,7 +95,6 @@ fn unsized_dyn() { let x = Box::new(A) as Box; assert_eq!(x.foo(), format!("hello")); } - fn unsized_dyn_autoderef() { pub trait Foo { fn foo(self) -> String; @@ -140,12 +139,9 @@ fn unsized_dyn_autoderef() { let x = Box::new(|| "hello".to_owned()) as Box String>; assert_eq!(&x.foo() as &str, "hello"); } +*/ fn main() { ref_box_dyn(); box_box_trait(); - - // "exotic" receivers - unsized_dyn(); - unsized_dyn_autoderef(); } diff --git a/tests/pass/unsized-tuple-impls.rs b/tests/pass/unsized-tuple-impls.rs deleted file mode 100644 index bbab1125a0afd..0000000000000 --- a/tests/pass/unsized-tuple-impls.rs +++ /dev/null @@ -1,13 +0,0 @@ -#![feature(unsized_tuple_coercion)] -use std::mem; - -fn main() { - let x: &(i32, i32, [i32]) = &(0, 1, [2, 3]); - let y: &(i32, i32, [i32]) = &(0, 1, [2, 3, 4]); - let mut a = [y, x]; - a.sort(); - assert_eq!(a, [x, y]); - - assert_eq!(&format!("{:?}", a), "[(0, 1, [2, 3]), (0, 1, [2, 3, 4])]"); - assert_eq!(mem::size_of_val(x), 16); -} diff --git a/tests/pass/unsized.rs b/tests/pass/unsized.rs new file mode 100644 index 0000000000000..c7e0c7925753f --- /dev/null +++ b/tests/pass/unsized.rs @@ -0,0 +1,36 @@ +#![feature(unsized_tuple_coercion)] +#![feature(unsized_fn_params)] + +use std::mem; + +fn unsized_tuple() { + let x: &(i32, i32, [i32]) = &(0, 1, [2, 3]); + let y: &(i32, i32, [i32]) = &(0, 1, [2, 3, 4]); + let mut a = [y, x]; + a.sort(); + assert_eq!(a, [x, y]); + + assert_eq!(&format!("{:?}", a), "[(0, 1, [2, 3]), (0, 1, [2, 3, 4])]"); + assert_eq!(mem::size_of_val(x), 16); +} + +fn unsized_params() { + pub fn f0(_f: dyn FnOnce()) {} + pub fn f1(_s: str) {} + pub fn f2(_x: i32, _y: [i32]) {} + pub fn f3(_p: dyn Send) {} + + let c: Box = Box::new(|| {}); + f0(*c); + let foo = "foo".to_string().into_boxed_str(); + f1(*foo); + let sl: Box::<[i32]> = [0, 1, 2].to_vec().into_boxed_slice(); + f2(5, *sl); + let p: Box = Box::new((1, 2)); + f3(*p); +} + +fn main() { + unsized_tuple(); + unsized_params(); +} From e9176c747e626383e37832514130d078b611f995 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 2 Jul 2022 20:28:39 -0400 Subject: [PATCH 3428/3747] test for better error location on stack pop --- tests/fail/data_race/stack_pop_race.rs | 22 ++++++++++++++++++++++ tests/fail/data_race/stack_pop_race.stderr | 20 ++++++++++++++++++++ 2 files changed, 42 insertions(+) create mode 100644 tests/fail/data_race/stack_pop_race.rs create mode 100644 tests/fail/data_race/stack_pop_race.stderr diff --git a/tests/fail/data_race/stack_pop_race.rs b/tests/fail/data_race/stack_pop_race.rs new file mode 100644 index 0000000000000..fa81306b78cae --- /dev/null +++ b/tests/fail/data_race/stack_pop_race.rs @@ -0,0 +1,22 @@ +// compile-flags: -Zmiri-preemption-rate=0 +use std::thread; + +#[derive(Copy, Clone)] +struct MakeSend(*const i32); +unsafe impl Send for MakeSend {} + +fn main() { race(0); } + +// Using an argument for the ptr to point to, since those do not get StorageDead. +fn race(local: i32) { + let ptr = MakeSend(&local as *const i32); + thread::spawn(move || { + let ptr = ptr; + let _val = unsafe { *ptr.0 }; + }); + // Make the other thread go first so that it does not UAF. + thread::yield_now(); + // Deallocating the local (when `main` returns) + // races with the read in the other thread. + // Make sure the error points at this function's end, not just the call site. +} //~ERROR Data race detected between Deallocate on thread `main` and Read on thread `` diff --git a/tests/fail/data_race/stack_pop_race.stderr b/tests/fail/data_race/stack_pop_race.stderr new file mode 100644 index 0000000000000..e7e2ba7e8bd9c --- /dev/null +++ b/tests/fail/data_race/stack_pop_race.stderr @@ -0,0 +1,20 @@ +error: Undefined Behavior: Data race detected between Deallocate on thread `main` and Read on thread `` at ALLOC + --> $DIR/stack_pop_race.rs:LL:CC + | +LL | } + | ^ Data race detected between Deallocate on thread `main` and Read on thread `` at ALLOC + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: backtrace: + = note: inside `race` at $DIR/stack_pop_race.rs:LL:CC +note: inside `main` at $DIR/stack_pop_race.rs:LL:CC + --> $DIR/stack_pop_race.rs:LL:CC + | +LL | fn main() { race(0); } + | ^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + From 5fed3ebc26ae0a9b17c0099fa71df636644f7312 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 2 Jul 2022 21:17:35 -0400 Subject: [PATCH 3429/3747] adjust code for copy_op changes --- src/machine.rs | 2 +- src/shims/intrinsics.rs | 4 ++-- tests/pass/transmute_fat.rs | 1 + 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/machine.rs b/src/machine.rs index a2d9e9ced1a14..12df9e271fb96 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -169,7 +169,7 @@ impl Provenance for Tag { write!(f, "{:?}", sb)?; } Tag::Wildcard => { - write!(f, "[Wildcard]")?; + write!(f, "[wildcard]")?; } } diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 9cf9461715f1a..ab79438c734de 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -68,12 +68,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "volatile_load" => { let [place] = check_arg_count(args)?; let place = this.deref_operand(place)?; - this.copy_op(&place.into(), dest)?; + this.copy_op(&place.into(), dest, /*allow_transmute*/ false)?; } "volatile_store" => { let [place, dest] = check_arg_count(args)?; let place = this.deref_operand(place)?; - this.copy_op(dest, &place.into())?; + this.copy_op(dest, &place.into(), /*allow_transmute*/ false)?; } "write_bytes" | "volatile_set_memory" => { diff --git a/tests/pass/transmute_fat.rs b/tests/pass/transmute_fat.rs index 1d2ec92a80389..b752e5504d4c9 100644 --- a/tests/pass/transmute_fat.rs +++ b/tests/pass/transmute_fat.rs @@ -3,6 +3,7 @@ fn main() { // If we are careful, we can exploit data layout... + // This is a tricky case since we are transmuting a ScalarPair type to a non-ScalarPair type. let raw = unsafe { std::mem::transmute::<&[u8], [*const u8; 2]>(&[42]) }; let ptr: *const u8 = unsafe { std::mem::transmute_copy(&raw) }; assert_eq!(unsafe { *ptr }, 42); From b6602f5d11fb9da3de05eefc856d7ec102c23139 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 6 Jul 2022 21:45:47 -0400 Subject: [PATCH 3430/3747] rustup --- rust-version | 2 +- src/operator.rs | 2 ++ tests/fail/data_race/stack_pop_race.rs | 5 ++++- tests/fail/data_race/stack_pop_race.stderr | 4 ++-- tests/pass/unsized.rs | 2 +- 5 files changed, 10 insertions(+), 5 deletions(-) diff --git a/rust-version b/rust-version index 8f3b1d39fd049..37d1eb0fbdeca 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -7665c3543079ebc3710b676d0fd6951bedfd4b29 +8824d131619e58a38bde8bcf56401629b91a204a diff --git a/src/operator.rs b/src/operator.rs index e7a43ac955200..2c77830a6d145 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -35,11 +35,13 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { Immediate::Scalar(l) => (l.check_init()?.to_bits(size)?, 0), Immediate::ScalarPair(l1, l2) => (l1.check_init()?.to_bits(size)?, l2.check_init()?.to_bits(size)?), + Immediate::Uninit => throw_ub!(InvalidUninitBytes(None)), }; let right = match **right { Immediate::Scalar(r) => (r.check_init()?.to_bits(size)?, 0), Immediate::ScalarPair(r1, r2) => (r1.check_init()?.to_bits(size)?, r2.check_init()?.to_bits(size)?), + Immediate::Uninit => throw_ub!(InvalidUninitBytes(None)), }; let res = match bin_op { Eq => left == right, diff --git a/tests/fail/data_race/stack_pop_race.rs b/tests/fail/data_race/stack_pop_race.rs index fa81306b78cae..bae8856001428 100644 --- a/tests/fail/data_race/stack_pop_race.rs +++ b/tests/fail/data_race/stack_pop_race.rs @@ -1,3 +1,4 @@ +// ignore-windows: Concurrency on Windows is not supported yet. // compile-flags: -Zmiri-preemption-rate=0 use std::thread; @@ -5,7 +6,9 @@ use std::thread; struct MakeSend(*const i32); unsafe impl Send for MakeSend {} -fn main() { race(0); } +fn main() { + race(0); +} // Using an argument for the ptr to point to, since those do not get StorageDead. fn race(local: i32) { diff --git a/tests/fail/data_race/stack_pop_race.stderr b/tests/fail/data_race/stack_pop_race.stderr index e7e2ba7e8bd9c..ba830753f6eea 100644 --- a/tests/fail/data_race/stack_pop_race.stderr +++ b/tests/fail/data_race/stack_pop_race.stderr @@ -11,8 +11,8 @@ LL | } note: inside `main` at $DIR/stack_pop_race.rs:LL:CC --> $DIR/stack_pop_race.rs:LL:CC | -LL | fn main() { race(0); } - | ^^^^^^^ +LL | race(0); + | ^^^^^^^ note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/pass/unsized.rs b/tests/pass/unsized.rs index c7e0c7925753f..d9beac4327d7f 100644 --- a/tests/pass/unsized.rs +++ b/tests/pass/unsized.rs @@ -24,7 +24,7 @@ fn unsized_params() { f0(*c); let foo = "foo".to_string().into_boxed_str(); f1(*foo); - let sl: Box::<[i32]> = [0, 1, 2].to_vec().into_boxed_slice(); + let sl: Box<[i32]> = [0, 1, 2].to_vec().into_boxed_slice(); f2(5, *sl); let p: Box = Box::new((1, 2)); f3(*p); From 6b3986f44d2e7fa388e80bb03abd6d26b1e573a4 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 7 Jul 2022 07:42:31 -0400 Subject: [PATCH 3431/3747] remove a dead optimization --- src/stacked_borrows.rs | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 9969fbdbcd343..4e83c2c8aa967 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -559,16 +559,9 @@ impl<'tcx> Stack { self.len() }; - // Put the new item there. As an optimization, deduplicate if it is equal to one of its new neighbors. - // `new_idx` might be 0 if we just cleared the entire stack. - if self.get(new_idx) == Some(new) || (new_idx > 0 && self.get(new_idx - 1).unwrap() == new) - { - // Optimization applies, done. - trace!("reborrow: avoiding adding redundant item {:?}", new); - } else { - trace!("reborrow: adding item {:?}", new); - self.insert(new_idx, new); - } + // Put the new item there. + trace!("reborrow: adding item {:?}", new); + self.insert(new_idx, new); Ok(()) } } From 52abae6826277f350723823968ce468d061c3a1d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 7 Jul 2022 08:20:24 -0400 Subject: [PATCH 3432/3747] fix comment in ./miri --- miri | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/miri b/miri index 2debf70c16644..f0d92b6a2b539 100755 --- a/miri +++ b/miri @@ -30,7 +30,7 @@ times and slower execution times. Format all sources and tests. are passed to `rustfmt`. ./miri clippy : -Format all sources and tests. are passed to `cargo clippy`. +Runs clippy on all sources. are passed to `cargo clippy`. ./miri many-seeds : Runs over and over again with different seeds for Miri. The MIRIFLAGS From 23d1f1a5a3cccd4a0867833b4f0dc6e3ad5ad532 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 7 Jul 2022 20:12:30 -0400 Subject: [PATCH 3433/3747] rustup --- rust-version | 2 +- src/diagnostics.rs | 4 ++-- tests/fail/uninit_buffer.rs | 2 +- tests/fail/uninit_buffer.stderr | 6 +++--- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/rust-version b/rust-version index 37d1eb0fbdeca..53e7908f42c84 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -8824d131619e58a38bde8bcf56401629b91a204a +1517f5de01c445b5124b30f02257b02b4c5ef3b2 diff --git a/src/diagnostics.rs b/src/diagnostics.rs index 289c46a5d2ef8..4dfa7bd07cbec 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -291,8 +291,8 @@ pub fn report_error<'tcx, 'mir>( match e.kind() { UndefinedBehavior(UndefinedBehaviorInfo::InvalidUninitBytes(Some((alloc_id, access)))) => { eprintln!( - "Uninitialized read occurred at {alloc_id:?}{range:?}, in this allocation:", - range = alloc_range(access.uninit_offset, access.uninit_size), + "Uninitialized memory occurred at {alloc_id:?}{range:?}, in this allocation:", + range = access.uninit, ); eprintln!("{:?}", ecx.dump_alloc(*alloc_id)); } diff --git a/tests/fail/uninit_buffer.rs b/tests/fail/uninit_buffer.rs index 351181016e4bf..c8ebd835d36a4 100644 --- a/tests/fail/uninit_buffer.rs +++ b/tests/fail/uninit_buffer.rs @@ -1,4 +1,4 @@ -// error-pattern: 12 bytes are uninitialized +// error-pattern: memory is uninitialized at [0x4..0x10] use std::alloc::{alloc, dealloc, Layout}; use std::slice::from_raw_parts; diff --git a/tests/fail/uninit_buffer.stderr b/tests/fail/uninit_buffer.stderr index e8faf8dd8b971..879c827eb8840 100644 --- a/tests/fail/uninit_buffer.stderr +++ b/tests/fail/uninit_buffer.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: reading 16 bytes of memory starting at ALLOC, but 12 bytes are uninitialized starting at ALLOC+0x4, and this operation requires initialized memory +error: Undefined Behavior: reading memory at ALLOC[0x0..0x10], but memory is uninitialized at [0x4..0x10], and this operation requires initialized memory --> RUSTLIB/core/src/slice/cmp.rs:LL:CC | LL | let mut order = unsafe { memcmp(left.as_ptr(), right.as_ptr(), len) as isize }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ reading 16 bytes of memory starting at ALLOC, but 12 bytes are uninitialized starting at ALLOC+0x4, and this operation requires initialized memory + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ reading memory at ALLOC[0x0..0x10], but memory is uninitialized at [0x4..0x10], and this operation requires initialized memory | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information @@ -17,7 +17,7 @@ LL | drop(slice1.cmp(slice2)); note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace -Uninitialized read occurred at ALLOC[0x4..0x10], in this allocation: +Uninitialized memory occurred at ALLOC[0x4..0x10], in this allocation: ALLOC (Rust heap, size: 32, align: 8) { 0x00 │ 41 42 43 44 __ __ __ __ __ __ __ __ __ __ __ __ │ ABCD░░░░░░░░░░░░ 0x10 │ 00 __ __ __ __ __ __ __ __ __ __ __ __ __ __ __ │ .░░░░░░░░░░░░░░░ From 4bd4838c15f75c693840d33b9c48ad7d6a310791 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Tue, 5 Jul 2022 09:08:00 +0000 Subject: [PATCH 3434/3747] Implement strict comment parsing for ui tests --- miri | 2 +- ui_test/src/comments.rs | 240 +++++++++++++++++++++++++++++----- ui_test/src/comments/tests.rs | 25 ++++ 3 files changed, 235 insertions(+), 32 deletions(-) diff --git a/miri b/miri index f0d92b6a2b539..be51535d59bf3 100755 --- a/miri +++ b/miri @@ -181,8 +181,8 @@ test|test-debug|bless|bless-debug) esac # Then test, and let caller control flags. # Only in root project and ui_test as `cargo-miri` has no tests. - $CARGO test $CARGO_BUILD_FLAGS --manifest-path "$MIRIDIR"/Cargo.toml "$@" $CARGO test $CARGO_BUILD_FLAGS --manifest-path "$MIRIDIR"/ui_test/Cargo.toml "$@" + $CARGO test $CARGO_BUILD_FLAGS --manifest-path "$MIRIDIR"/Cargo.toml "$@" ;; run|run-debug) # Scan for "--target" to overwrite the "MIRI_TEST_TARGET" env var so diff --git a/ui_test/src/comments.rs b/ui_test/src/comments.rs index 3fd65d643a1cf..d4ee3efd1404f 100644 --- a/ui_test/src/comments.rs +++ b/ui_test/src/comments.rs @@ -64,6 +64,43 @@ impl Condition { } } +macro_rules! checked { + ($path:expr, $l:expr) => { + let path = $path; + let l = $l; + #[allow(unused_macros)] + macro_rules! exit { + ($fmt:expr $$(,$args:expr)*) => {{ + eprint!("{}:{l}: ", path.display()); + eprintln!($fmt, $$($args,)*); + #[cfg(not(test))] + std::process::exit(1); + #[cfg(test)] + panic!(); + }}; + } + #[allow(unused_macros)] + macro_rules! check { + ($cond:expr, $fmt:expr $$(,$args:expr)*) => {{ + if !$cond { + exit!($fmt $$(,$args)*); + } + }}; + } + #[allow(unused_macros)] + macro_rules! unwrap { + ($cond:expr, $fmt:expr $$(,$args:expr)*) => {{ + match $cond { + Some(val) => val, + None => { + exit!($fmt $$(,$args)*); + } + } + }}; + } + }; +} + impl Comments { pub(crate) fn parse_file(path: &Path) -> Self { let content = std::fs::read_to_string(path).unwrap(); @@ -72,14 +109,45 @@ impl Comments { /// Parse comments in `content`. /// `path` is only used to emit diagnostics if parsing fails. - pub(crate) fn parse(path: &Path, content: &str) -> Self { + /// + /// This function will only parse `//@` and `//~` style comments + /// and ignore all others + fn parse_checked(path: &Path, content: &str) -> Self { let mut this = Self::default(); - let error_pattern_regex = - Regex::new(r"//(\[(?P[^\]]+)\])?~(?P\||[\^]+)? *(?PERROR|HELP|WARN|NOTE)?:?(?P.*)") - .unwrap(); // The line that a `|` will refer to let mut fallthrough_to = None; + for (l, line) in content.lines().enumerate() { + let l = l + 1; // enumerate starts at 0, but line numbers start at 1 + if let Some((_, command)) = line.split_once("//@") { + let command = command.trim(); + if let Some((command, args)) = command.split_once(':') { + this.parse_command_with_args(command, args, path, l); + } else if let Some((command, _comments)) = command.split_once(' ') { + this.parse_command(command, path, l) + } else { + this.parse_command(command, path, l) + } + } else if let Some((_, pattern)) = line.split_once("//~") { + this.parse_pattern(pattern, &mut fallthrough_to, path, l) + } else if let Some((_, pattern)) = line.split_once("//[") { + this.parse_revisioned_pattern(pattern, &mut fallthrough_to, path, l) + } else { + fallthrough_to = None; + } + } + this + } + + /// Parse comments in `content`. + /// `path` is only used to emit diagnostics if parsing fails. + pub(crate) fn parse(path: &Path, content: &str) -> Self { + let mut this = Self::parse_checked(path, content); + if content.contains("//@") { + // Migration mode: if new syntax is used, ignore all old syntax + return this; + } + for (l, line) in content.lines().enumerate() { let l = l + 1; // enumerate starts at 0, but line numbers start at 1 if let Some(revisions) = line.strip_prefix("// revisions:") { @@ -140,36 +208,146 @@ impl Comments { ); this.error_pattern = Some((s.trim().to_string(), l)); } - if let Some(captures) = error_pattern_regex.captures(line) { - // FIXME: check that the error happens on the marked line - let matched = captures["text"].trim().to_string(); + } + this + } - let revision = captures.name("revision").map(|rev| rev.as_str().to_string()); + fn parse_command_with_args(&mut self, command: &str, args: &str, path: &Path, l: usize) { + checked!(path, l); + match command { + "revisions" => { + check!(self.revisions.is_none(), "cannot specifiy revisions twice"); + self.revisions = Some(args.split_whitespace().map(|s| s.to_string()).collect()); + } + "compile-flags" => { + self.compile_flags.extend(args.split_whitespace().map(|s| s.to_string())); + } + "rustc-env" => + for env in args.split_whitespace() { + let (k, v) = unwrap!( + env.split_once('='), + "environment variables must be key/value pairs separated by a `=`" + ); + self.env_vars.push((k.to_string(), v.to_string())); + }, + "normalize-stderr-test" => { + let (from, to) = + unwrap!(args.split_once("->"), "normalize-stderr-test needs a `->`"); + let from = from.trim().trim_matches('"'); + let to = to.trim().trim_matches('"'); + let from = unwrap!(Regex::new(from).ok(), "invalid regex"); + self.normalize_stderr.push((from, to.to_string())); + } + "error-pattern" => { + check!( + self.error_pattern.is_none(), + "cannot specifiy error_pattern twice, previous: {:?}", + self.error_pattern + ); + self.error_pattern = Some((args.trim().to_string(), l)); + } + _ => exit!("unknown command {command} with args {args}"), + } + } - let level = captures.name("level").map(|rev| rev.as_str().parse().unwrap()); + fn parse_command(&mut self, command: &str, path: &Path, l: usize) { + checked!(path, l); - let match_line = match captures.name("offset").map(|rev| rev.as_str()) { - Some("|") => fallthrough_to.expect("`//~|` pattern without preceding line"), - Some(pat) => { - debug_assert!(pat.chars().all(|c| c == '^')); - l - pat.len() - } - None => l, - }; - - fallthrough_to = Some(match_line); - - this.error_matches.push(ErrorMatch { - matched, - revision, - level, - definition_line: l, - line: match_line, - }); - } else { - fallthrough_to = None; - } + if let Some(s) = command.strip_prefix("ignore-") { + self.ignore.push(Condition::parse(s)); + return; } - this + + if let Some(s) = command.strip_prefix("only-") { + self.only.push(Condition::parse(s)); + return; + } + + if command.starts_with("stderr-per-bitwidth") { + check!(!self.stderr_per_bitwidth, "cannot specifiy stderr-per-bitwidth twice"); + self.stderr_per_bitwidth = true; + return; + } + + exit!("unknown command {command}"); + } + + fn parse_pattern( + &mut self, + pattern: &str, + fallthrough_to: &mut Option, + path: &Path, + l: usize, + ) { + self.parse_pattern_inner(pattern, fallthrough_to, None, path, l) + } + + fn parse_revisioned_pattern( + &mut self, + pattern: &str, + fallthrough_to: &mut Option, + path: &Path, + l: usize, + ) { + checked!(path, l); + let (revision, pattern) = + unwrap!(pattern.split_once(']'), "`//[` without corresponding `]`"); + if pattern.starts_with('~') { + self.parse_pattern_inner( + &pattern[1..], + fallthrough_to, + Some(revision.to_owned()), + path, + l, + ) + } else { + exit!("revisioned pattern must have `~` following the `]`"); + } + } + + // parse something like (?P\||[\^]+)? *(?PERROR|HELP|WARN|NOTE)?:?(?P.*) + fn parse_pattern_inner( + &mut self, + pattern: &str, + fallthrough_to: &mut Option, + revision: Option, + path: &Path, + l: usize, + ) { + checked!(path, l); + // FIXME: check that the error happens on the marked line + + let (match_line, pattern) = match unwrap!(pattern.chars().next(), "no pattern specified") { + '|' => + (*unwrap!(fallthrough_to, "`//~|` pattern without preceding line"), &pattern[1..]), + '^' => { + let offset = pattern.chars().take_while(|&c| c == '^').count(); + (l - offset, &pattern[offset..]) + } + _ => (l, pattern), + }; + + let (level, pattern) = match pattern.trim_start().split_once(|c| matches!(c, ':' | ' ')) { + None => (None, pattern), + Some((level, pattern_without_level)) => + match level.parse().ok() { + Some(level) => (Some(level), pattern_without_level), + None => (None, pattern), + }, + }; + + let matched = pattern.trim().to_string(); + + check!(!matched.is_empty(), "no pattern specified"); + + *fallthrough_to = Some(match_line); + + self.error_matches.push(ErrorMatch { + matched, + revision, + level, + definition_line: l, + line: match_line, + }); } } diff --git a/ui_test/src/comments/tests.rs b/ui_test/src/comments/tests.rs index ef9662241424a..dc69a5d4d600c 100644 --- a/ui_test/src/comments/tests.rs +++ b/ui_test/src/comments/tests.rs @@ -20,3 +20,28 @@ fn main() { "encountered a dangling reference (address $HEX is unallocated)" ); } + +#[test] +fn parse_slash_slash_at() { + let s = r" +//@ error-pattern: foomp +use std::mem; + + "; + let comments = Comments::parse(Path::new(""), s); + println!("parsed comments: {:#?}", comments); + assert_eq!(comments.error_pattern, Some(("foomp".to_string(), 2))); +} + +#[test] +#[should_panic] +fn parse_slash_slash_at_fail() { + let s = r" +//@ error-pattern foomp +use std::mem; + + "; + let comments = Comments::parse(Path::new(""), s); + println!("parsed comments: {:#?}", comments); + assert_eq!(comments.error_pattern, Some(("foomp".to_string(), 2))); +} From 389915e09b2c5759865e829050cf0574d2cbe587 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Tue, 5 Jul 2022 09:15:22 +0000 Subject: [PATCH 3435/3747] Replace all //error-pattern comments with strict syntax and fix other comments in the same files --- tests/fail/alloc/deallocate-bad-alignment.rs | 2 +- tests/fail/alloc/deallocate-bad-size.rs | 2 +- tests/fail/alloc/deallocate-twice.rs | 2 +- tests/fail/alloc/global_system_mixup.rs | 8 ++++---- tests/fail/alloc/reallocate-bad-size.rs | 2 +- tests/fail/alloc/reallocate-dangling.rs | 2 +- tests/fail/alloc/stack_free.rs | 4 ++-- .../libc_pthread_create_main_terminate.rs | 4 ++-- tests/fail/concurrency/thread-spawn.rs | 4 ++-- .../dangling_pointers/null_pointer_write_zst.rs | 4 ++-- tests/fail/fs/isolated_file.rs | 4 ++-- tests/fail/intrinsics/copy_overflow.rs | 2 +- tests/fail/intrinsics/out_of_bounds_ptr_1.rs | 2 +- tests/fail/intrinsics/out_of_bounds_ptr_2.rs | 2 +- tests/fail/intrinsics/out_of_bounds_ptr_3.rs | 2 +- tests/fail/intrinsics/ptr_offset_0_plus_0.rs | 4 ++-- tests/fail/intrinsics/ptr_offset_int_plus_int.rs | 4 ++-- tests/fail/intrinsics/ptr_offset_int_plus_ptr.rs | 4 ++-- tests/fail/intrinsics/ptr_offset_overflow.rs | 2 +- tests/fail/intrinsics/ptr_offset_ptr_plus_0.rs | 2 +- tests/fail/intrinsics/simd-float-to-int.rs | 2 +- tests/fail/intrinsics/simd-gather.rs | 2 +- tests/fail/intrinsics/simd-scatter.rs | 2 +- tests/fail/intrinsics/write_bytes_overflow.rs | 2 +- tests/fail/invalid_enum_tag.rs | 4 ++-- tests/fail/memleak.rs | 4 ++-- tests/fail/memleak_rc.rs | 6 +++--- tests/fail/memleak_rc.stderr | 11 +++++++++++ tests/fail/no_main.rs | 2 +- tests/fail/panic/double_panic.rs | 6 +++--- tests/fail/panic/panic_abort1.rs | 8 ++++---- tests/fail/panic/panic_abort2.rs | 8 ++++---- tests/fail/panic/panic_abort3.rs | 8 ++++---- tests/fail/panic/panic_abort4.rs | 8 ++++---- tests/fail/provenance/ptr_invalid_offset.rs | 4 ++-- tests/fail/should-pass/cpp20_rwc_syncs.rs | 6 +++--- .../stacked_borrows/deallocate_against_barrier1.rs | 2 +- .../stacked_borrows/deallocate_against_barrier2.rs | 2 +- tests/fail/stacked_borrows/issue-miri-1050-1.rs | 2 +- tests/fail/stacked_borrows/issue-miri-1050-2.rs | 2 +- tests/fail/stacked_borrows/newtype_retagging.rs | 4 ++-- tests/fail/stacked_borrows/vtable.rs | 2 +- tests/fail/stacked_borrows/zst_slice.rs | 2 +- tests/fail/uninit_buffer.rs | 2 +- tests/fail/unreachable.rs | 2 +- ui_test/README.md | 4 +--- ui_test/src/comments.rs | 13 ++++--------- ui_test/src/lib.rs | 2 +- 48 files changed, 94 insertions(+), 90 deletions(-) create mode 100644 tests/fail/memleak_rc.stderr diff --git a/tests/fail/alloc/deallocate-bad-alignment.rs b/tests/fail/alloc/deallocate-bad-alignment.rs index 852a0660217ee..a07d8254ad3d5 100644 --- a/tests/fail/alloc/deallocate-bad-alignment.rs +++ b/tests/fail/alloc/deallocate-bad-alignment.rs @@ -1,6 +1,6 @@ use std::alloc::{alloc, dealloc, Layout}; -// error-pattern: has size 1 and alignment 1, but gave size 1 and alignment 2 +//@error-pattern: has size 1 and alignment 1, but gave size 1 and alignment 2 fn main() { unsafe { diff --git a/tests/fail/alloc/deallocate-bad-size.rs b/tests/fail/alloc/deallocate-bad-size.rs index 167cc015c2da9..47aaef1935e90 100644 --- a/tests/fail/alloc/deallocate-bad-size.rs +++ b/tests/fail/alloc/deallocate-bad-size.rs @@ -1,6 +1,6 @@ use std::alloc::{alloc, dealloc, Layout}; -// error-pattern: has size 1 and alignment 1, but gave size 2 and alignment 1 +//@error-pattern: has size 1 and alignment 1, but gave size 2 and alignment 1 fn main() { unsafe { diff --git a/tests/fail/alloc/deallocate-twice.rs b/tests/fail/alloc/deallocate-twice.rs index 67312b0d96dda..1eb9bbf91ca5c 100644 --- a/tests/fail/alloc/deallocate-twice.rs +++ b/tests/fail/alloc/deallocate-twice.rs @@ -1,6 +1,6 @@ use std::alloc::{alloc, dealloc, Layout}; -// error-pattern: dereferenced after this allocation got freed +//@error-pattern: dereferenced after this allocation got freed fn main() { unsafe { diff --git a/tests/fail/alloc/global_system_mixup.rs b/tests/fail/alloc/global_system_mixup.rs index 735c52500af67..01db2f1a225df 100644 --- a/tests/fail/alloc/global_system_mixup.rs +++ b/tests/fail/alloc/global_system_mixup.rs @@ -1,10 +1,10 @@ // Make sure we detect when the `Global` and `System` allocators are mixed // (even when the default `Global` uses `System`). -// error-pattern: which is Rust heap memory, using +//@error-pattern: which is Rust heap memory, using -// normalize-stderr-test: "using [A-Za-z]+ heap deallocation operation" -> "using PLATFORM heap deallocation operation" -// normalize-stderr-test: "\| +\^+" -> "| ^" -// normalize-stderr-test: "libc::free\([^()]*\)|unsafe \{ HeapFree\([^()]*\) \};" -> "FREE();" +//@normalize-stderr-test: "using [A-Za-z]+ heap deallocation operation" -> "using PLATFORM heap deallocation operation" +//@normalize-stderr-test: "\| +\^+" -> "| ^" +//@normalize-stderr-test: "libc::free\([^()]*\)|unsafe \{ HeapFree\([^()]*\) \};" -> "FREE();" #![feature(allocator_api, slice_ptr_get)] diff --git a/tests/fail/alloc/reallocate-bad-size.rs b/tests/fail/alloc/reallocate-bad-size.rs index d6a27c930a28b..145c3393d677a 100644 --- a/tests/fail/alloc/reallocate-bad-size.rs +++ b/tests/fail/alloc/reallocate-bad-size.rs @@ -1,6 +1,6 @@ use std::alloc::{alloc, realloc, Layout}; -// error-pattern: has size 1 and alignment 1, but gave size 2 and alignment 1 +//@error-pattern: has size 1 and alignment 1, but gave size 2 and alignment 1 fn main() { unsafe { diff --git a/tests/fail/alloc/reallocate-dangling.rs b/tests/fail/alloc/reallocate-dangling.rs index 62eb7582a2f70..34f1658344a5e 100644 --- a/tests/fail/alloc/reallocate-dangling.rs +++ b/tests/fail/alloc/reallocate-dangling.rs @@ -1,6 +1,6 @@ use std::alloc::{alloc, dealloc, realloc, Layout}; -// error-pattern: dereferenced after this allocation got freed +//@error-pattern: dereferenced after this allocation got freed fn main() { unsafe { diff --git a/tests/fail/alloc/stack_free.rs b/tests/fail/alloc/stack_free.rs index d854fa993a79f..a97431bc2f05e 100644 --- a/tests/fail/alloc/stack_free.rs +++ b/tests/fail/alloc/stack_free.rs @@ -1,7 +1,7 @@ // Validation/SB changes why we fail -// compile-flags: -Zmiri-disable-validation -Zmiri-disable-stacked-borrows +//@compile-flags: -Zmiri-disable-validation -Zmiri-disable-stacked-borrows -// error-pattern: which is stack variable memory, using Rust heap deallocation operation +//@error-pattern: which is stack variable memory, using Rust heap deallocation operation fn main() { let x = 42; diff --git a/tests/fail/concurrency/libc_pthread_create_main_terminate.rs b/tests/fail/concurrency/libc_pthread_create_main_terminate.rs index 9b576bbb0868d..ab80cdd205bca 100644 --- a/tests/fail/concurrency/libc_pthread_create_main_terminate.rs +++ b/tests/fail/concurrency/libc_pthread_create_main_terminate.rs @@ -1,5 +1,5 @@ -// ignore-windows: No libc on Windows -// error-pattern: the main thread terminated without waiting for all remaining threads +//@ignore-windows: No libc on Windows +//@error-pattern: the main thread terminated without waiting for all remaining threads // Check that we terminate the program when the main thread terminates. diff --git a/tests/fail/concurrency/thread-spawn.rs b/tests/fail/concurrency/thread-spawn.rs index 948ce946d8948..650a42b43b5d3 100644 --- a/tests/fail/concurrency/thread-spawn.rs +++ b/tests/fail/concurrency/thread-spawn.rs @@ -1,8 +1,8 @@ -// only-windows: Only Windows is not supported. +//@only-windows: Only Windows is not supported. use std::thread; -// error-pattern: can't create threads on Windows +//@error-pattern: can't create threads on Windows fn main() { thread::spawn(|| {}); diff --git a/tests/fail/dangling_pointers/null_pointer_write_zst.rs b/tests/fail/dangling_pointers/null_pointer_write_zst.rs index 60e2d7c663e07..7181a5979b442 100644 --- a/tests/fail/dangling_pointers/null_pointer_write_zst.rs +++ b/tests/fail/dangling_pointers/null_pointer_write_zst.rs @@ -1,6 +1,6 @@ // Some optimizations remove ZST accesses, thus masking this UB. -// compile-flags: -Zmir-opt-level=0 -// error-pattern: memory access failed: null pointer is a dangling pointer +//@compile-flags: -Zmir-opt-level=0 +//@error-pattern: memory access failed: null pointer is a dangling pointer #[allow(deref_nullptr)] fn main() { diff --git a/tests/fail/fs/isolated_file.rs b/tests/fail/fs/isolated_file.rs index 5b7270f18931c..00bb492147a8c 100644 --- a/tests/fail/fs/isolated_file.rs +++ b/tests/fail/fs/isolated_file.rs @@ -1,5 +1,5 @@ -// ignore-windows: File handling is not implemented yet -// error-pattern: `open` not available when isolation is enabled +//@ignore-windows: File handling is not implemented yet +//@error-pattern: `open` not available when isolation is enabled fn main() { let _file = std::fs::File::open("file.txt").unwrap(); diff --git a/tests/fail/intrinsics/copy_overflow.rs b/tests/fail/intrinsics/copy_overflow.rs index b09aedcf7470e..c4ce192c449c3 100644 --- a/tests/fail/intrinsics/copy_overflow.rs +++ b/tests/fail/intrinsics/copy_overflow.rs @@ -1,4 +1,4 @@ -// error-pattern: overflow computing total size +//@error-pattern: overflow computing total size use std::mem; fn main() { diff --git a/tests/fail/intrinsics/out_of_bounds_ptr_1.rs b/tests/fail/intrinsics/out_of_bounds_ptr_1.rs index d200b3eb0297f..0109bff696888 100644 --- a/tests/fail/intrinsics/out_of_bounds_ptr_1.rs +++ b/tests/fail/intrinsics/out_of_bounds_ptr_1.rs @@ -1,4 +1,4 @@ -// error-pattern: pointer to 5 bytes starting at offset 0 is out-of-bounds +//@error-pattern: pointer to 5 bytes starting at offset 0 is out-of-bounds fn main() { let v = [0i8; 4]; let x = &v as *const i8; diff --git a/tests/fail/intrinsics/out_of_bounds_ptr_2.rs b/tests/fail/intrinsics/out_of_bounds_ptr_2.rs index 52b385b8e3b48..74d391dc21208 100644 --- a/tests/fail/intrinsics/out_of_bounds_ptr_2.rs +++ b/tests/fail/intrinsics/out_of_bounds_ptr_2.rs @@ -1,4 +1,4 @@ -// error-pattern: overflowing in-bounds pointer arithmetic +//@error-pattern: overflowing in-bounds pointer arithmetic fn main() { let v = [0i8; 4]; let x = &v as *const i8; diff --git a/tests/fail/intrinsics/out_of_bounds_ptr_3.rs b/tests/fail/intrinsics/out_of_bounds_ptr_3.rs index cd0861efe5d95..b54cf3dd25c03 100644 --- a/tests/fail/intrinsics/out_of_bounds_ptr_3.rs +++ b/tests/fail/intrinsics/out_of_bounds_ptr_3.rs @@ -1,4 +1,4 @@ -// error-pattern: pointer to 1 byte starting at offset -1 is out-of-bounds +//@error-pattern: pointer to 1 byte starting at offset -1 is out-of-bounds fn main() { let v = [0i8; 4]; let x = &v as *const i8; diff --git a/tests/fail/intrinsics/ptr_offset_0_plus_0.rs b/tests/fail/intrinsics/ptr_offset_0_plus_0.rs index 4098d6b0ced2d..32974a825a54c 100644 --- a/tests/fail/intrinsics/ptr_offset_0_plus_0.rs +++ b/tests/fail/intrinsics/ptr_offset_0_plus_0.rs @@ -1,5 +1,5 @@ -// error-pattern: null pointer is a dangling pointer -// compile-flags: -Zmiri-permissive-provenance +//@error-pattern: null pointer is a dangling pointer +//@compile-flags: -Zmiri-permissive-provenance fn main() { let x = 0 as *mut i32; diff --git a/tests/fail/intrinsics/ptr_offset_int_plus_int.rs b/tests/fail/intrinsics/ptr_offset_int_plus_int.rs index 817a8b9801b78..f51e00746e2fd 100644 --- a/tests/fail/intrinsics/ptr_offset_int_plus_int.rs +++ b/tests/fail/intrinsics/ptr_offset_int_plus_int.rs @@ -1,5 +1,5 @@ -// error-pattern: is a dangling pointer -// compile-flags: -Zmiri-permissive-provenance +//@error-pattern: is a dangling pointer +//@compile-flags: -Zmiri-permissive-provenance fn main() { // Can't offset an integer pointer by non-zero offset. diff --git a/tests/fail/intrinsics/ptr_offset_int_plus_ptr.rs b/tests/fail/intrinsics/ptr_offset_int_plus_ptr.rs index ed6370bf7f178..8fc4d7fe7350b 100644 --- a/tests/fail/intrinsics/ptr_offset_int_plus_ptr.rs +++ b/tests/fail/intrinsics/ptr_offset_int_plus_ptr.rs @@ -1,5 +1,5 @@ -// error-pattern: is a dangling pointer -// compile-flags: -Zmiri-permissive-provenance +//@error-pattern: is a dangling pointer +//@compile-flags: -Zmiri-permissive-provenance fn main() { let ptr = Box::into_raw(Box::new(0u32)); diff --git a/tests/fail/intrinsics/ptr_offset_overflow.rs b/tests/fail/intrinsics/ptr_offset_overflow.rs index 734547b6013b0..829cf90c855d7 100644 --- a/tests/fail/intrinsics/ptr_offset_overflow.rs +++ b/tests/fail/intrinsics/ptr_offset_overflow.rs @@ -1,4 +1,4 @@ -// error-pattern: overflowing in-bounds pointer arithmetic +//@error-pattern: overflowing in-bounds pointer arithmetic fn main() { let v = [1i8, 2]; let x = &v[1] as *const i8; diff --git a/tests/fail/intrinsics/ptr_offset_ptr_plus_0.rs b/tests/fail/intrinsics/ptr_offset_ptr_plus_0.rs index 8760345409c8e..f8ee7d0b5092a 100644 --- a/tests/fail/intrinsics/ptr_offset_ptr_plus_0.rs +++ b/tests/fail/intrinsics/ptr_offset_ptr_plus_0.rs @@ -1,4 +1,4 @@ -// error-pattern: pointer at offset 32 is out-of-bounds +//@error-pattern: pointer at offset 32 is out-of-bounds fn main() { let x = Box::into_raw(Box::new(0u32)); diff --git a/tests/fail/intrinsics/simd-float-to-int.rs b/tests/fail/intrinsics/simd-float-to-int.rs index bb9adf07c9e97..a5bae36d92a46 100644 --- a/tests/fail/intrinsics/simd-float-to-int.rs +++ b/tests/fail/intrinsics/simd-float-to-int.rs @@ -1,4 +1,4 @@ -// error-pattern: cannot be represented in target type `i32` +//@error-pattern: cannot be represented in target type `i32` #![feature(portable_simd)] use std::simd::*; diff --git a/tests/fail/intrinsics/simd-gather.rs b/tests/fail/intrinsics/simd-gather.rs index ab9cb56ed0bdd..e394cce9a4fe3 100644 --- a/tests/fail/intrinsics/simd-gather.rs +++ b/tests/fail/intrinsics/simd-gather.rs @@ -1,4 +1,4 @@ -// error-pattern: pointer to 1 byte starting at offset 9 is out-of-bounds +//@error-pattern: pointer to 1 byte starting at offset 9 is out-of-bounds #![feature(portable_simd)] use std::simd::*; diff --git a/tests/fail/intrinsics/simd-scatter.rs b/tests/fail/intrinsics/simd-scatter.rs index d7a7e344aa30c..d2bc73399548b 100644 --- a/tests/fail/intrinsics/simd-scatter.rs +++ b/tests/fail/intrinsics/simd-scatter.rs @@ -1,4 +1,4 @@ -// error-pattern: pointer to 1 byte starting at offset 9 is out-of-bounds +//@error-pattern: pointer to 1 byte starting at offset 9 is out-of-bounds #![feature(portable_simd)] use std::simd::*; diff --git a/tests/fail/intrinsics/write_bytes_overflow.rs b/tests/fail/intrinsics/write_bytes_overflow.rs index a6bf2acb16f30..5c49dc00165c9 100644 --- a/tests/fail/intrinsics/write_bytes_overflow.rs +++ b/tests/fail/intrinsics/write_bytes_overflow.rs @@ -1,4 +1,4 @@ -// error-pattern: overflow computing total size of `write_bytes` +//@error-pattern: overflow computing total size of `write_bytes` use std::mem; fn main() { diff --git a/tests/fail/invalid_enum_tag.rs b/tests/fail/invalid_enum_tag.rs index 7ba4da9018a71..92cc1d1d34e48 100644 --- a/tests/fail/invalid_enum_tag.rs +++ b/tests/fail/invalid_enum_tag.rs @@ -1,8 +1,8 @@ // Validation makes this fail in the wrong place // Make sure we find these even with many checks disabled. -// compile-flags: -Zmiri-disable-alignment-check -Zmiri-disable-stacked-borrows -Zmiri-disable-validation +//@compile-flags: -Zmiri-disable-alignment-check -Zmiri-disable-stacked-borrows -Zmiri-disable-validation -// error-pattern: enum value has invalid tag +//@error-pattern: enum value has invalid tag use std::mem; diff --git a/tests/fail/memleak.rs b/tests/fail/memleak.rs index 7dee9ddf1c988..d384caf81a57e 100644 --- a/tests/fail/memleak.rs +++ b/tests/fail/memleak.rs @@ -1,5 +1,5 @@ -// error-pattern: the evaluated program leaked memory -// normalize-stderr-test: ".*│.*" -> "$$stripped$$" +//@error-pattern: the evaluated program leaked memory +//@normalize-stderr-test: ".*│.*" -> "$$stripped$$" fn main() { std::mem::forget(Box::new(42)); diff --git a/tests/fail/memleak_rc.rs b/tests/fail/memleak_rc.rs index 9ea809f76299b..76ecd71b011aa 100644 --- a/tests/fail/memleak_rc.rs +++ b/tests/fail/memleak_rc.rs @@ -1,6 +1,6 @@ -// error-pattern: the evaluated program leaked memory -// stderr-per-bitwidth -// normalize-stderr-test: ".*│.*" -> "$$stripped$$" +//@error-pattern: the evaluated program leaked memory +//@stderr-per-bitwidth +//@normalize-stderr-test: ".*│.*" -> "$$stripped$$" use std::cell::RefCell; use std::rc::Rc; diff --git a/tests/fail/memleak_rc.stderr b/tests/fail/memleak_rc.stderr new file mode 100644 index 0000000000000..290de49c82c0b --- /dev/null +++ b/tests/fail/memleak_rc.stderr @@ -0,0 +1,11 @@ +The following memory was leaked: ALLOC (Rust heap, size: 32, align: 8) { + 0x00 │ 01 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 │ ................ + 0x10 │ 00 00 00 00 00 00 00 00 ╾$HEX[a1765]─╼ │ ........╾──────╼ +} + +error: the evaluated program leaked memory + +note: pass `-Zmiri-ignore-leaks` to disable this check + +error: aborting due to previous error + diff --git a/tests/fail/no_main.rs b/tests/fail/no_main.rs index a9e8e816828c0..e28205040871a 100644 --- a/tests/fail/no_main.rs +++ b/tests/fail/no_main.rs @@ -1,2 +1,2 @@ -// error-pattern: miri can only run programs that have a main function +//@error-pattern: miri can only run programs that have a main function #![no_main] diff --git a/tests/fail/panic/double_panic.rs b/tests/fail/panic/double_panic.rs index f3af66a79abc4..8919d51bb2f74 100644 --- a/tests/fail/panic/double_panic.rs +++ b/tests/fail/panic/double_panic.rs @@ -1,6 +1,6 @@ -// error-pattern: the program aborted -// normalize-stderr-test: "\| +\^+" -> "| ^" -// normalize-stderr-test: "unsafe \{ libc::abort\(\) \}|crate::intrinsics::abort\(\);" -> "ABORT();" +//@error-pattern: the program aborted +//@normalize-stderr-test: "\| +\^+" -> "| ^" +//@normalize-stderr-test: "unsafe \{ libc::abort\(\) \}|crate::intrinsics::abort\(\);" -> "ABORT();" struct Foo; impl Drop for Foo { diff --git a/tests/fail/panic/panic_abort1.rs b/tests/fail/panic/panic_abort1.rs index 9c094c659837a..00a01ce6e8137 100644 --- a/tests/fail/panic/panic_abort1.rs +++ b/tests/fail/panic/panic_abort1.rs @@ -1,7 +1,7 @@ -// error-pattern: the program aborted execution -// normalize-stderr-test: "\| +\^+" -> "| ^" -// normalize-stderr-test: "libc::abort\(\);|core::intrinsics::abort\(\);" -> "ABORT();" -// compile-flags: -C panic=abort +//@error-pattern: the program aborted execution +//@normalize-stderr-test: "\| +\^+" -> "| ^" +//@normalize-stderr-test: "libc::abort\(\);|core::intrinsics::abort\(\);" -> "ABORT();" +//@compile-flags: -C panic=abort fn main() { std::panic!("panicking from libstd"); diff --git a/tests/fail/panic/panic_abort2.rs b/tests/fail/panic/panic_abort2.rs index 7eb9a3c24aa24..dee0de96703a1 100644 --- a/tests/fail/panic/panic_abort2.rs +++ b/tests/fail/panic/panic_abort2.rs @@ -1,7 +1,7 @@ -// error-pattern: the program aborted execution -// normalize-stderr-test: "\| +\^+" -> "| ^" -// normalize-stderr-test: "libc::abort\(\);|core::intrinsics::abort\(\);" -> "ABORT();" -// compile-flags: -C panic=abort +//@error-pattern: the program aborted execution +//@normalize-stderr-test: "\| +\^+" -> "| ^" +//@normalize-stderr-test: "libc::abort\(\);|core::intrinsics::abort\(\);" -> "ABORT();" +//@compile-flags: -C panic=abort fn main() { std::panic!("{}-panicking from libstd", 42); diff --git a/tests/fail/panic/panic_abort3.rs b/tests/fail/panic/panic_abort3.rs index 1940b48bad78d..a448aab3ea458 100644 --- a/tests/fail/panic/panic_abort3.rs +++ b/tests/fail/panic/panic_abort3.rs @@ -1,7 +1,7 @@ -// error-pattern: the program aborted execution -// normalize-stderr-test: "\| +\^+" -> "| ^" -// normalize-stderr-test: "libc::abort\(\);|core::intrinsics::abort\(\);" -> "ABORT();" -// compile-flags: -C panic=abort +//@error-pattern: the program aborted execution +//@normalize-stderr-test: "\| +\^+" -> "| ^" +//@normalize-stderr-test: "libc::abort\(\);|core::intrinsics::abort\(\);" -> "ABORT();" +//@compile-flags: -C panic=abort fn main() { core::panic!("panicking from libcore"); diff --git a/tests/fail/panic/panic_abort4.rs b/tests/fail/panic/panic_abort4.rs index e5190ea0765d1..4995dad9d71ab 100644 --- a/tests/fail/panic/panic_abort4.rs +++ b/tests/fail/panic/panic_abort4.rs @@ -1,7 +1,7 @@ -// error-pattern: the program aborted execution -// normalize-stderr-test: "\| +\^+" -> "| ^" -// normalize-stderr-test: "libc::abort\(\);|core::intrinsics::abort\(\);" -> "ABORT();" -// compile-flags: -C panic=abort +//@error-pattern: the program aborted execution +//@normalize-stderr-test: "\| +\^+" -> "| ^" +//@normalize-stderr-test: "libc::abort\(\);|core::intrinsics::abort\(\);" -> "ABORT();" +//@compile-flags: -C panic=abort fn main() { core::panic!("{}-panicking from libcore", 42); diff --git a/tests/fail/provenance/ptr_invalid_offset.rs b/tests/fail/provenance/ptr_invalid_offset.rs index 08fb57a6569ce..a3510d8e89290 100644 --- a/tests/fail/provenance/ptr_invalid_offset.rs +++ b/tests/fail/provenance/ptr_invalid_offset.rs @@ -1,5 +1,5 @@ -// compile-flags: -Zmiri-strict-provenance -// error-pattern: is a dangling pointer +//@compile-flags: -Zmiri-strict-provenance +//@error-pattern: is a dangling pointer #![feature(strict_provenance)] fn main() { diff --git a/tests/fail/should-pass/cpp20_rwc_syncs.rs b/tests/fail/should-pass/cpp20_rwc_syncs.rs index 85c24246dbeb5..6478f446accc4 100644 --- a/tests/fail/should-pass/cpp20_rwc_syncs.rs +++ b/tests/fail/should-pass/cpp20_rwc_syncs.rs @@ -1,6 +1,6 @@ -// ignore-windows: Concurrency on Windows is not supported yet. -// compile-flags: -Zmiri-ignore-leaks -// error-pattern: unreachable +//@ignore-windows: Concurrency on Windows is not supported yet. +//@compile-flags: -Zmiri-ignore-leaks +//@error-pattern: unreachable // https://plv.mpi-sws.org/scfix/paper.pdf // 2.2 Second Problem: SC Fences are Too Weak diff --git a/tests/fail/stacked_borrows/deallocate_against_barrier1.rs b/tests/fail/stacked_borrows/deallocate_against_barrier1.rs index bf18c9a058cf9..0798f863ce110 100644 --- a/tests/fail/stacked_borrows/deallocate_against_barrier1.rs +++ b/tests/fail/stacked_borrows/deallocate_against_barrier1.rs @@ -1,4 +1,4 @@ -// error-pattern: deallocating while item is protected +//@error-pattern: deallocating while item is protected fn inner(x: &mut i32, f: fn(&mut i32)) { // `f` may mutate, but it may not deallocate! diff --git a/tests/fail/stacked_borrows/deallocate_against_barrier2.rs b/tests/fail/stacked_borrows/deallocate_against_barrier2.rs index 4680f6769a1c2..23c54c8d89883 100644 --- a/tests/fail/stacked_borrows/deallocate_against_barrier2.rs +++ b/tests/fail/stacked_borrows/deallocate_against_barrier2.rs @@ -1,4 +1,4 @@ -// error-pattern: deallocating while item is protected +//@error-pattern: deallocating while item is protected use std::marker::PhantomPinned; pub struct NotUnpin(i32, PhantomPinned); diff --git a/tests/fail/stacked_borrows/issue-miri-1050-1.rs b/tests/fail/stacked_borrows/issue-miri-1050-1.rs index c1fc695e0d651..6e14b9af146c6 100644 --- a/tests/fail/stacked_borrows/issue-miri-1050-1.rs +++ b/tests/fail/stacked_borrows/issue-miri-1050-1.rs @@ -1,4 +1,4 @@ -// error-pattern: pointer to 4 bytes starting at offset 0 is out-of-bounds +//@error-pattern: pointer to 4 bytes starting at offset 0 is out-of-bounds fn main() { unsafe { diff --git a/tests/fail/stacked_borrows/issue-miri-1050-2.rs b/tests/fail/stacked_borrows/issue-miri-1050-2.rs index 2a969686d4da9..571cb6213fec2 100644 --- a/tests/fail/stacked_borrows/issue-miri-1050-2.rs +++ b/tests/fail/stacked_borrows/issue-miri-1050-2.rs @@ -1,4 +1,4 @@ -// error-pattern: is a dangling pointer +//@error-pattern: is a dangling pointer use std::ptr::NonNull; fn main() { diff --git a/tests/fail/stacked_borrows/newtype_retagging.rs b/tests/fail/stacked_borrows/newtype_retagging.rs index 8f932f08086ac..4786cd02d954f 100644 --- a/tests/fail/stacked_borrows/newtype_retagging.rs +++ b/tests/fail/stacked_borrows/newtype_retagging.rs @@ -1,5 +1,5 @@ -// compile-flags: -Zmiri-retag-fields -// error-pattern: incompatible item is protected +//@compile-flags: -Zmiri-retag-fields +//@error-pattern: incompatible item is protected struct Newtype<'a>(&'a mut i32); fn dealloc_while_running(_n: Newtype<'_>, dealloc: impl FnOnce()) { diff --git a/tests/fail/stacked_borrows/vtable.rs b/tests/fail/stacked_borrows/vtable.rs index dd9ba1dfb2bda..27e035c404bab 100644 --- a/tests/fail/stacked_borrows/vtable.rs +++ b/tests/fail/stacked_borrows/vtable.rs @@ -1,4 +1,4 @@ -// error-pattern: vtable pointer does not have permission +//@error-pattern: vtable pointer does not have permission #![feature(ptr_metadata)] trait Foo {} diff --git a/tests/fail/stacked_borrows/zst_slice.rs b/tests/fail/stacked_borrows/zst_slice.rs index d45b3dcac087b..336b1041df091 100644 --- a/tests/fail/stacked_borrows/zst_slice.rs +++ b/tests/fail/stacked_borrows/zst_slice.rs @@ -1,5 +1,5 @@ // compile-flags: -Zmiri-strict-provenance -// error-pattern: does not exist in the borrow stack +//@error-pattern: does not exist in the borrow stack fn main() { unsafe { diff --git a/tests/fail/uninit_buffer.rs b/tests/fail/uninit_buffer.rs index c8ebd835d36a4..d21371225e571 100644 --- a/tests/fail/uninit_buffer.rs +++ b/tests/fail/uninit_buffer.rs @@ -1,4 +1,4 @@ -// error-pattern: memory is uninitialized at [0x4..0x10] +//@error-pattern: memory is uninitialized at [0x4..0x10] use std::alloc::{alloc, dealloc, Layout}; use std::slice::from_raw_parts; diff --git a/tests/fail/unreachable.rs b/tests/fail/unreachable.rs index 245ef29cad353..ef2bb42c65cc6 100644 --- a/tests/fail/unreachable.rs +++ b/tests/fail/unreachable.rs @@ -1,4 +1,4 @@ -// error-pattern: entering unreachable code +//@error-pattern: entering unreachable code fn main() { unsafe { std::hint::unreachable_unchecked() } } diff --git a/ui_test/README.md b/ui_test/README.md index 07a0a67b9143f..f7852c82e44b5 100644 --- a/ui_test/README.md +++ b/ui_test/README.md @@ -7,14 +7,12 @@ A smaller version of compiletest-rs ## Supported magic comment annotations -Note that the space after `//`, when it is present, is *not* optional -- it must be exactly one. - * `// ignore-XXX` avoids running the test on targets whose triple contains `XXX` * `XXX` can also be one of `64bit`, `32bit` or `16bit` * `// only-XXX` avoids running the test on targets whose triple **does not** contain `XXX` * `XXX` can also be one of `64bit`, `32bit` or `16bit` * `// stderr-per-bitwidth` produces one stderr file per bitwidth, as they may differ significantly sometimes -* `// error-pattern: XXX` make sure the stderr output contains `XXX` +* `//@error-pattern: XXX` make sure the stderr output contains `XXX` * `//~ ERROR: XXX` make sure the stderr output contains `XXX` for an error in the line where this comment is written * Also supports `HELP`, `WARN` or `NOTE` for different kind of message * if one of those levels is specified explicitly, *all* diagnostics of this level or higher need an annotation. If you want to avoid this, just leave out the all caps level note entirely. diff --git a/ui_test/src/comments.rs b/ui_test/src/comments.rs index d4ee3efd1404f..569dad5a25702 100644 --- a/ui_test/src/comments.rs +++ b/ui_test/src/comments.rs @@ -246,7 +246,8 @@ impl Comments { ); self.error_pattern = Some((args.trim().to_string(), l)); } - _ => exit!("unknown command {command} with args {args}"), + // Maybe the user just left a comment explaining a command without arguments + _ => self.parse_command(command, path, l), } } @@ -292,14 +293,8 @@ impl Comments { checked!(path, l); let (revision, pattern) = unwrap!(pattern.split_once(']'), "`//[` without corresponding `]`"); - if pattern.starts_with('~') { - self.parse_pattern_inner( - &pattern[1..], - fallthrough_to, - Some(revision.to_owned()), - path, - l, - ) + if let Some(pattern) = pattern.strip_prefix('~') { + self.parse_pattern_inner(pattern, fallthrough_to, Some(revision.to_owned()), path, l) } else { exit!("revisioned pattern must have `~` following the `]`"); } diff --git a/ui_test/src/lib.rs b/ui_test/src/lib.rs index ff0c4e1c8996b..21b8c54ff20fd 100644 --- a/ui_test/src/lib.rs +++ b/ui_test/src/lib.rs @@ -377,7 +377,7 @@ fn check_annotations( ) { if let Some((ref error_pattern, definition_line)) = comments.error_pattern { // first check the diagnostics messages outside of our file. We check this first, so that - // you can mix in-file annotations with // error-pattern annotations, even if there is overlap + // you can mix in-file annotations with //@error-pattern annotations, even if there is overlap // in the messages. if let Some(i) = messages_from_unknown_file_or_line .iter() From b3e64c252a3834ba880daf478dd0630bb61365d3 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 6 Jul 2022 08:42:32 +0000 Subject: [PATCH 3436/3747] Revert testing ui_test before ui tests --- miri | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/miri b/miri index be51535d59bf3..f0d92b6a2b539 100755 --- a/miri +++ b/miri @@ -181,8 +181,8 @@ test|test-debug|bless|bless-debug) esac # Then test, and let caller control flags. # Only in root project and ui_test as `cargo-miri` has no tests. - $CARGO test $CARGO_BUILD_FLAGS --manifest-path "$MIRIDIR"/ui_test/Cargo.toml "$@" $CARGO test $CARGO_BUILD_FLAGS --manifest-path "$MIRIDIR"/Cargo.toml "$@" + $CARGO test $CARGO_BUILD_FLAGS --manifest-path "$MIRIDIR"/ui_test/Cargo.toml "$@" ;; run|run-debug) # Scan for "--target" to overwrite the "MIRI_TEST_TARGET" env var so From 570032b0dd8042243721b78f50d186577a52a3a9 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 6 Jul 2022 09:09:53 +0000 Subject: [PATCH 3437/3747] Introduce a proper error handling framework --- Cargo.lock | 194 ++++++++++++++++++++++++++++++++++ tests/compiletest.rs | 20 ++-- ui_test/Cargo.lock | 194 ++++++++++++++++++++++++++++++++++ ui_test/Cargo.toml | 2 + ui_test/src/comments.rs | 18 ++-- ui_test/src/comments/tests.rs | 28 +++-- ui_test/src/lib.rs | 10 +- ui_test/src/tests.rs | 55 ++++++---- 8 files changed, 471 insertions(+), 50 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 880fa271d97db..cc707c630e54e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,21 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "addr2line" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9ecd88a8c8378ca913a680cd98f0f13ac67383d35993f86c90a70e3f137816b" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + [[package]] name = "aho-corasick" version = "0.7.18" @@ -37,18 +52,66 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +[[package]] +name = "backtrace" +version = "0.3.65" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11a17d453482a265fd5f8479f2a3f405566e6ca627837aaddb85af8b1ab8ef61" +dependencies = [ + "addr2line", + "cc", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", +] + [[package]] name = "bitflags" version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +[[package]] +name = "cc" +version = "1.0.73" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11" + [[package]] name = "cfg-if" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "color-eyre" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ebf286c900a6d5867aeff75cfee3192857bb7f24b547d4f0df2ed6baa812c90" +dependencies = [ + "backtrace", + "color-spantrace", + "eyre", + "indenter", + "once_cell", + "owo-colors", + "tracing-error", +] + +[[package]] +name = "color-spantrace" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ba75b3d9449ecdccb27ecbc479fdc0b87fa2dd43d2f8298f9bf0e59aacc8dce" +dependencies = [ + "once_cell", + "owo-colors", + "tracing-core", + "tracing-error", +] + [[package]] name = "colored" version = "2.0.0" @@ -158,6 +221,16 @@ dependencies = [ "termcolor", ] +[[package]] +name = "eyre" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c2b6b5a29c02cdc822728b7d7b8ae1bab3e3b05d44522770ddd49722eeac7eb" +dependencies = [ + "indenter", + "once_cell", +] + [[package]] name = "getrandom" version = "0.2.3" @@ -169,6 +242,12 @@ dependencies = [ "wasi", ] +[[package]] +name = "gimli" +version = "0.26.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78cc372d058dcf6d5ecd98510e7fbc9e5aec4d21de70f65fea8fecebcd881bd4" + [[package]] name = "hermit-abi" version = "0.1.19" @@ -184,6 +263,12 @@ version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" +[[package]] +name = "indenter" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683" + [[package]] name = "instant" version = "0.1.12" @@ -267,6 +352,15 @@ dependencies = [ "autocfg", ] +[[package]] +name = "miniz_oxide" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f5c75688da582b8ffc1f1799e9db273f32133c49e048f614d22ec3256773ccc" +dependencies = [ + "adler", +] + [[package]] name = "miri" version = "0.1.0" @@ -286,6 +380,21 @@ dependencies = [ "ui_test", ] +[[package]] +name = "object" +version = "0.28.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e42c982f2d955fac81dd7e1d0e1426a7d702acd9c98d19ab01083a6a0328c424" +dependencies = [ + "memchr", +] + +[[package]] +name = "once_cell" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18a6dbe30758c9f83eb00cbea4ac95966305f5a7772f3f42ebfc7fc7eddbd8e1" + [[package]] name = "output_vt100" version = "0.1.3" @@ -295,6 +404,12 @@ dependencies = [ "winapi", ] +[[package]] +name = "owo-colors" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "decf7381921fea4dcb2549c5667eda59b3ec297ab7e2b5fc33eac69d2e7da87b" + [[package]] name = "parking_lot" version = "0.11.2" @@ -329,6 +444,12 @@ dependencies = [ "libc", ] +[[package]] +name = "pin-project-lite" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" + [[package]] name = "ppv-lite86" version = "0.2.15" @@ -431,6 +552,12 @@ version = "0.6.25" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" +[[package]] +name = "rustc-demangle" +version = "0.1.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342" + [[package]] name = "rustc-hash" version = "1.1.0" @@ -501,6 +628,15 @@ dependencies = [ "serde", ] +[[package]] +name = "sharded-slab" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "900fba806f70c630b0a382d0d825e17a0f19fcd059a2ade1ff237bcddf446b31" +dependencies = [ + "lazy_static", +] + [[package]] name = "shell-escape" version = "0.1.5" @@ -533,10 +669,62 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "thread_local" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5516c27b78311c50bf42c071425c560ac799b11c30b31f87e3081965fe5e0180" +dependencies = [ + "once_cell", +] + +[[package]] +name = "tracing" +version = "0.1.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a400e31aa60b9d44a52a8ee0343b5b18566b03a8321e0d321f695cf56e940160" +dependencies = [ + "cfg-if", + "pin-project-lite", + "tracing-core", +] + +[[package]] +name = "tracing-core" +version = "0.1.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b7358be39f2f274f322d2aaed611acc57f382e8eb1e5b48cb9ae30933495ce7" +dependencies = [ + "once_cell", + "valuable", +] + +[[package]] +name = "tracing-error" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d686ec1c0f384b1277f097b2f279a2ecc11afe8c133c1aabf036a27cb4cd206e" +dependencies = [ + "tracing", + "tracing-subscriber", +] + +[[package]] +name = "tracing-subscriber" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a713421342a5a666b7577783721d3117f1b69a393df803ee17bb73b1e122a59" +dependencies = [ + "sharded-slab", + "thread_local", + "tracing-core", +] + [[package]] name = "ui_test" version = "0.1.0" dependencies = [ + "color-eyre", "colored", "crossbeam", "lazy_static", @@ -553,6 +741,12 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d22af068fba1eb5edcb4aea19d382b2a3deb4c8f9d475c589b6ada9e0fd493ee" +[[package]] +name = "valuable" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" + [[package]] name = "wasi" version = "0.10.2+wasi-snapshot-preview1" diff --git a/tests/compiletest.rs b/tests/compiletest.rs index 754fccd63b13d..9537fb993c47f 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -2,13 +2,13 @@ use colored::*; use regex::Regex; use std::env; use std::path::PathBuf; -use ui_test::{Config, Mode, OutputConflictHandling}; +use ui_test::{Config, Mode, OutputConflictHandling, color_eyre::Result}; fn miri_path() -> PathBuf { PathBuf::from(option_env!("MIRI").unwrap_or(env!("CARGO_BIN_EXE_miri"))) } -fn run_tests(mode: Mode, path: &str, target: Option) { +fn run_tests(mode: Mode, path: &str, target: Option) -> Result<()> { let in_rustc_test_suite = option_env!("RUSTC_STAGE").is_some(); // Add some flags we always want. @@ -108,7 +108,7 @@ regexes! { "sys/[a-z]+/" => "sys/PLATFORM/", } -fn ui(mode: Mode, path: &str) { +fn ui(mode: Mode, path: &str) -> Result<()> { let target = get_target(); let msg = format!( @@ -117,20 +117,24 @@ fn ui(mode: Mode, path: &str) { ); eprintln!("{}", msg.green().bold()); - run_tests(mode, path, target); + run_tests(mode, path, target) } fn get_target() -> Option { env::var("MIRI_TEST_TARGET").ok() } -fn main() { +fn main() -> Result<()> { + ui_test::color_eyre::install()?; + // Add a test env var to do environment communication tests. env::set_var("MIRI_ENV_VAR_TEST", "0"); // Let the tests know where to store temp files (they might run for a different target, which can make this hard to find). env::set_var("MIRI_TEMP", env::temp_dir()); - ui(Mode::Pass, "tests/pass"); - ui(Mode::Panic, "tests/panic"); - ui(Mode::Fail, "tests/fail"); + ui(Mode::Pass, "tests/pass")?; + ui(Mode::Panic, "tests/panic")?; + ui(Mode::Fail, "tests/fail")?; + + Ok(()) } diff --git a/ui_test/Cargo.lock b/ui_test/Cargo.lock index 5a4cdb892713e..2065cc34bef85 100644 --- a/ui_test/Cargo.lock +++ b/ui_test/Cargo.lock @@ -2,6 +2,21 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "addr2line" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9ecd88a8c8378ca913a680cd98f0f13ac67383d35993f86c90a70e3f137816b" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + [[package]] name = "aho-corasick" version = "0.7.18" @@ -37,12 +52,60 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +[[package]] +name = "backtrace" +version = "0.3.65" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11a17d453482a265fd5f8479f2a3f405566e6ca627837aaddb85af8b1ab8ef61" +dependencies = [ + "addr2line", + "cc", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", +] + +[[package]] +name = "cc" +version = "1.0.73" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11" + [[package]] name = "cfg-if" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "color-eyre" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ebf286c900a6d5867aeff75cfee3192857bb7f24b547d4f0df2ed6baa812c90" +dependencies = [ + "backtrace", + "color-spantrace", + "eyre", + "indenter", + "once_cell", + "owo-colors", + "tracing-error", +] + +[[package]] +name = "color-spantrace" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ba75b3d9449ecdccb27ecbc479fdc0b87fa2dd43d2f8298f9bf0e59aacc8dce" +dependencies = [ + "once_cell", + "owo-colors", + "tracing-core", + "tracing-error", +] + [[package]] name = "colored" version = "2.0.0" @@ -139,6 +202,22 @@ version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0e25ea47919b1560c4e3b7fe0aaab9becf5b84a10325ddf7db0f0ba5e1026499" +[[package]] +name = "eyre" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c2b6b5a29c02cdc822728b7d7b8ae1bab3e3b05d44522770ddd49722eeac7eb" +dependencies = [ + "indenter", + "once_cell", +] + +[[package]] +name = "gimli" +version = "0.26.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78cc372d058dcf6d5ecd98510e7fbc9e5aec4d21de70f65fea8fecebcd881bd4" + [[package]] name = "hermit-abi" version = "0.1.19" @@ -148,6 +227,12 @@ dependencies = [ "libc", ] +[[package]] +name = "indenter" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683" + [[package]] name = "itoa" version = "1.0.2" @@ -181,6 +266,30 @@ dependencies = [ "autocfg", ] +[[package]] +name = "miniz_oxide" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f5c75688da582b8ffc1f1799e9db273f32133c49e048f614d22ec3256773ccc" +dependencies = [ + "adler", +] + +[[package]] +name = "object" +version = "0.28.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e42c982f2d955fac81dd7e1d0e1426a7d702acd9c98d19ab01083a6a0328c424" +dependencies = [ + "memchr", +] + +[[package]] +name = "once_cell" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18a6dbe30758c9f83eb00cbea4ac95966305f5a7772f3f42ebfc7fc7eddbd8e1" + [[package]] name = "output_vt100" version = "0.1.3" @@ -190,6 +299,18 @@ dependencies = [ "winapi", ] +[[package]] +name = "owo-colors" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "decf7381921fea4dcb2549c5667eda59b3ec297ab7e2b5fc33eac69d2e7da87b" + +[[package]] +name = "pin-project-lite" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" + [[package]] name = "pretty_assertions" version = "1.2.1" @@ -237,6 +358,12 @@ version = "0.6.26" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49b3de9ec5dc0a3417da371aab17d729997c15010e7fd24ff707773a33bddb64" +[[package]] +name = "rustc-demangle" +version = "0.1.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342" + [[package]] name = "rustc_version" version = "0.4.0" @@ -295,6 +422,15 @@ dependencies = [ "serde", ] +[[package]] +name = "sharded-slab" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "900fba806f70c630b0a382d0d825e17a0f19fcd059a2ade1ff237bcddf446b31" +dependencies = [ + "lazy_static", +] + [[package]] name = "syn" version = "1.0.95" @@ -306,10 +442,62 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "thread_local" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5516c27b78311c50bf42c071425c560ac799b11c30b31f87e3081965fe5e0180" +dependencies = [ + "once_cell", +] + +[[package]] +name = "tracing" +version = "0.1.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a400e31aa60b9d44a52a8ee0343b5b18566b03a8321e0d321f695cf56e940160" +dependencies = [ + "cfg-if", + "pin-project-lite", + "tracing-core", +] + +[[package]] +name = "tracing-core" +version = "0.1.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b7358be39f2f274f322d2aaed611acc57f382e8eb1e5b48cb9ae30933495ce7" +dependencies = [ + "once_cell", + "valuable", +] + +[[package]] +name = "tracing-error" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d686ec1c0f384b1277f097b2f279a2ecc11afe8c133c1aabf036a27cb4cd206e" +dependencies = [ + "tracing", + "tracing-subscriber", +] + +[[package]] +name = "tracing-subscriber" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a713421342a5a666b7577783721d3117f1b69a393df803ee17bb73b1e122a59" +dependencies = [ + "sharded-slab", + "thread_local", + "tracing-core", +] + [[package]] name = "ui_test" version = "0.1.0" dependencies = [ + "color-eyre", "colored", "crossbeam", "lazy_static", @@ -326,6 +514,12 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d22af068fba1eb5edcb4aea19d382b2a3deb4c8f9d475c589b6ada9e0fd493ee" +[[package]] +name = "valuable" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" + [[package]] name = "winapi" version = "0.3.9" diff --git a/ui_test/Cargo.toml b/ui_test/Cargo.toml index 1d480b6938140..94c5acb6b70b6 100644 --- a/ui_test/Cargo.toml +++ b/ui_test/Cargo.toml @@ -17,3 +17,5 @@ crossbeam = "0.8.1" lazy_static = "1.4.0" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" +color-eyre = "0.6.1" + diff --git a/ui_test/src/comments.rs b/ui_test/src/comments.rs index 569dad5a25702..fcbcae33f2d7c 100644 --- a/ui_test/src/comments.rs +++ b/ui_test/src/comments.rs @@ -4,6 +4,8 @@ use regex::Regex; use crate::rustc_stderr::Level; +use color_eyre::eyre::Result; + #[cfg(test)] mod tests; @@ -102,8 +104,8 @@ macro_rules! checked { } impl Comments { - pub(crate) fn parse_file(path: &Path) -> Self { - let content = std::fs::read_to_string(path).unwrap(); + pub(crate) fn parse_file(path: &Path) -> Result { + let content = std::fs::read_to_string(path)?; Self::parse(path, &content) } @@ -112,7 +114,7 @@ impl Comments { /// /// This function will only parse `//@` and `//~` style comments /// and ignore all others - fn parse_checked(path: &Path, content: &str) -> Self { + fn parse_checked(path: &Path, content: &str) -> Result { let mut this = Self::default(); // The line that a `|` will refer to @@ -136,16 +138,16 @@ impl Comments { fallthrough_to = None; } } - this + Ok(this) } /// Parse comments in `content`. /// `path` is only used to emit diagnostics if parsing fails. - pub(crate) fn parse(path: &Path, content: &str) -> Self { - let mut this = Self::parse_checked(path, content); + pub(crate) fn parse(path: &Path, content: &str) -> Result { + let mut this = Self::parse_checked(path, content)?; if content.contains("//@") { // Migration mode: if new syntax is used, ignore all old syntax - return this; + return Ok(this); } for (l, line) in content.lines().enumerate() { @@ -209,7 +211,7 @@ impl Comments { this.error_pattern = Some((s.trim().to_string(), l)); } } - this + Ok(this) } fn parse_command_with_args(&mut self, command: &str, args: &str, path: &Path, l: usize) { diff --git a/ui_test/src/comments/tests.rs b/ui_test/src/comments/tests.rs index dc69a5d4d600c..0573ee8ba706c 100644 --- a/ui_test/src/comments/tests.rs +++ b/ui_test/src/comments/tests.rs @@ -1,9 +1,13 @@ -use std::path::Path; +use std::{path::Path, panic::catch_unwind}; use super::Comments; +use color_eyre::eyre::{Result, bail}; +use crate::tests::init; + #[test] -fn parse_simple_comment() { +fn parse_simple_comment() -> Result<()> { + init(); let s = r" use std::mem; @@ -11,7 +15,7 @@ fn main() { let _x: &i32 = unsafe { mem::transmute(16usize) }; //~ ERROR encountered a dangling reference (address $HEX is unallocated) } "; - let comments = Comments::parse(Path::new(""), s); + let comments = Comments::parse(Path::new(""), s)?; println!("parsed comments: {:#?}", comments); assert_eq!(comments.error_matches[0].definition_line, 5); assert_eq!(comments.error_matches[0].revision, None); @@ -19,29 +23,33 @@ fn main() { comments.error_matches[0].matched, "encountered a dangling reference (address $HEX is unallocated)" ); + Ok(()) } #[test] -fn parse_slash_slash_at() { +fn parse_slash_slash_at() -> Result<()> { + init(); let s = r" //@ error-pattern: foomp use std::mem; "; - let comments = Comments::parse(Path::new(""), s); + let comments = Comments::parse(Path::new(""), s)?; println!("parsed comments: {:#?}", comments); assert_eq!(comments.error_pattern, Some(("foomp".to_string(), 2))); + Ok(()) } #[test] -#[should_panic] -fn parse_slash_slash_at_fail() { +fn parse_slash_slash_at_fail() -> Result<()> { + init(); let s = r" //@ error-pattern foomp use std::mem; "; - let comments = Comments::parse(Path::new(""), s); - println!("parsed comments: {:#?}", comments); - assert_eq!(comments.error_pattern, Some(("foomp".to_string(), 2))); + match catch_unwind(|| Comments::parse(Path::new(""), s)) { + Ok(_) => bail!("expected parsing to panic"), + Err(_) => Ok(()), + } } diff --git a/ui_test/src/lib.rs b/ui_test/src/lib.rs index 21b8c54ff20fd..90e7669f62aa3 100644 --- a/ui_test/src/lib.rs +++ b/ui_test/src/lib.rs @@ -11,6 +11,8 @@ use colored::*; use comments::ErrorMatch; use regex::Regex; use rustc_stderr::{Level, Message}; +use color_eyre::eyre::Result; +pub use color_eyre; use crate::comments::{Comments, Condition}; @@ -51,7 +53,7 @@ pub enum OutputConflictHandling { pub type Filter = Vec<(Regex, &'static str)>; -pub fn run_tests(config: Config) { +pub fn run_tests(config: Config) -> Result<()> { eprintln!(" Compiler flags: {:?}", config.args); // Get the triple with which to run the tests @@ -94,7 +96,7 @@ pub fn run_tests(config: Config) { // Create N worker threads that receive files to test. for _ in 0..std::thread::available_parallelism().unwrap().get() { - s.spawn(|_| { + s.spawn(|_| -> Result<()> { for path in &receive { if !config.path_filter.is_empty() { let path_display = path.display().to_string(); @@ -103,7 +105,7 @@ pub fn run_tests(config: Config) { continue; } } - let comments = Comments::parse_file(&path); + let comments = Comments::parse_file(&path)?; // Ignore file if only/ignore rules do (not) apply if !test_file_conditions(&comments, &target) { ignored.fetch_add(1, Ordering::Relaxed); @@ -142,6 +144,7 @@ pub fn run_tests(config: Config) { } } } + Ok(()) }); } }) @@ -246,6 +249,7 @@ pub fn run_tests(config: Config) { filtered.to_string().yellow(), ); eprintln!(); + Ok(()) } #[derive(Debug)] diff --git a/ui_test/src/tests.rs b/ui_test/src/tests.rs index a45f8f8933c90..13a242f8d8a73 100644 --- a/ui_test/src/tests.rs +++ b/ui_test/src/tests.rs @@ -20,7 +20,8 @@ fn config() -> Config { } #[test] -fn issue_2156() { +fn issue_2156() -> Result<()> { + init(); let s = r" use std::mem; @@ -29,7 +30,7 @@ fn main() { } "; let path = Path::new("$DIR/"); - let comments = Comments::parse(path, s); + let comments = Comments::parse(path, s)?; let mut errors = vec![]; let config = config(); let messages = vec![ @@ -46,13 +47,14 @@ fn main() { [ Error::PatternNotFound { definition_line: 5, .. }, Error::ErrorsWithoutPattern { path: Some((_, 5)), .. }, - ] => {} + ] => Ok(()), _ => panic!("{:#?}", errors), } } #[test] -fn find_pattern() { +fn find_pattern() -> Result<()> { + init(); let s = r" use std::mem; @@ -60,7 +62,7 @@ fn main() { let _x: &i32 = unsafe { mem::transmute(16usize) }; //~ ERROR encountered a dangling reference (address 0x10 is unallocated) } "; - let comments = Comments::parse(Path::new(""), s); + let comments = Comments::parse(Path::new(""), s)?; let config = config(); { let messages = vec![vec![], vec![], vec![], vec![], vec![], vec![ @@ -137,14 +139,15 @@ fn main() { ); match &errors[..] { // Note no `ErrorsWithoutPattern`, because there are no `//~NOTE` in the test file, so we ignore them - [Error::PatternNotFound { definition_line: 5, .. }] => {} + [Error::PatternNotFound { definition_line: 5, .. }] => Ok(()), _ => panic!("not the expected error: {:#?}", errors), } } } #[test] -fn duplicate_pattern() { +fn duplicate_pattern() -> Result<()> { + init(); let s = r" use std::mem; @@ -153,7 +156,7 @@ fn main() { //~^ ERROR encountered a dangling reference (address 0x10 is unallocated) } "; - let comments = Comments::parse(Path::new(""), s); + let comments = Comments::parse(Path::new(""), s)?; let config = config(); let messages = vec![ vec![], vec![], vec![], vec![], vec![], @@ -167,13 +170,14 @@ fn main() { let mut errors = vec![]; check_annotations(messages, vec![], Path::new("moobar"), &mut errors, &config, "", &comments); match &errors[..] { - [Error::PatternNotFound { definition_line: 6, .. }] => {} + [Error::PatternNotFound { definition_line: 6, .. }] => Ok(()), _ => panic!("{:#?}", errors), } } #[test] -fn missing_pattern() { +fn missing_pattern() -> Result<()> { + init(); let s = r" use std::mem; @@ -181,7 +185,7 @@ fn main() { let _x: &i32 = unsafe { mem::transmute(16usize) }; //~ ERROR encountered a dangling reference (address 0x10 is unallocated) } "; - let comments = Comments::parse(Path::new(""), s); + let comments = Comments::parse(Path::new(""), s)?; let config = config(); let messages = vec![ vec![], vec![], vec![], vec![], vec![], @@ -199,13 +203,14 @@ fn main() { let mut errors = vec![]; check_annotations(messages, vec![], Path::new("moobar"), &mut errors, &config, "", &comments); match &errors[..] { - [Error::ErrorsWithoutPattern { path: Some((_, 5)), .. }] => {} + [Error::ErrorsWithoutPattern { path: Some((_, 5)), .. }] => Ok(()), _ => panic!("{:#?}", errors), } } #[test] -fn missing_warn_pattern() { +fn missing_warn_pattern() -> Result<()> { + init(); let s = r" use std::mem; @@ -214,7 +219,7 @@ fn main() { //~^ WARN cake } "; - let comments = Comments::parse(Path::new(""), s); + let comments = Comments::parse(Path::new(""), s)?; let config = config(); let messages= vec![ vec![], @@ -242,7 +247,7 @@ fn main() { match &errors[..] { [Error::ErrorsWithoutPattern { path: Some((_, 5)), msgs, .. }] => match &msgs[..] { - [Message { message, level: Level::Warn }] if message == "kaboom" => {} + [Message { message, level: Level::Warn }] if message == "kaboom" => Ok(()), _ => panic!("{:#?}", msgs), }, _ => panic!("{:#?}", errors), @@ -250,7 +255,8 @@ fn main() { } #[test] -fn missing_implicit_warn_pattern() { +fn missing_implicit_warn_pattern() -> Result<()> { + init(); let s = r" use std::mem; @@ -259,7 +265,7 @@ fn main() { //~^ cake } "; - let comments = Comments::parse(Path::new(""), s); + let comments = Comments::parse(Path::new(""), s)?; let config = config(); let messages = vec![ vec![], @@ -285,13 +291,14 @@ fn main() { let mut errors = vec![]; check_annotations(messages, vec![], Path::new("moobar"), &mut errors, &config, "", &comments); match &errors[..] { - [] => {} + [] => Ok(()), _ => panic!("{:#?}", errors), } } #[test] -fn implicit_err_pattern() { +fn implicit_err_pattern() -> Result<()> { + init(); let s = r" use std::mem; @@ -299,7 +306,7 @@ fn main() { let _x: &i32 = unsafe { mem::transmute(16usize) }; //~ encountered a dangling reference (address 0x10 is unallocated) } "; - let comments = Comments::parse(Path::new(""), s); + let comments = Comments::parse(Path::new(""), s)?; let config = config(); let messages = vec![ vec![], @@ -317,7 +324,13 @@ fn main() { let mut errors = vec![]; check_annotations(messages, vec![], Path::new("moobar"), &mut errors, &config, "", &comments); match &errors[..] { - [Error::ErrorPatternWithoutErrorAnnotation(_, 5)] => {} + [Error::ErrorPatternWithoutErrorAnnotation(_, 5)] => Ok(()), _ => panic!("{:#?}", errors), } } + +static INIT: std::sync::Once = std::sync::Once::new(); + +pub fn init() { + INIT.call_once(|| color_eyre::install().unwrap()); +} From 54b6b034104ce81a8d02800b9fc7d5181389b4df Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 6 Jul 2022 09:44:03 +0000 Subject: [PATCH 3438/3747] Actually use eyre and get rid of the ad-hoc macros emulating error handling --- tests/compiletest.rs | 2 +- ui_test/src/comments.rs | 166 +++++++++++++++------------------- ui_test/src/comments/tests.rs | 8 +- ui_test/src/lib.rs | 18 ++-- 4 files changed, 88 insertions(+), 106 deletions(-) diff --git a/tests/compiletest.rs b/tests/compiletest.rs index 9537fb993c47f..008fc7806457f 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -2,7 +2,7 @@ use colored::*; use regex::Regex; use std::env; use std::path::PathBuf; -use ui_test::{Config, Mode, OutputConflictHandling, color_eyre::Result}; +use ui_test::{color_eyre::Result, Config, Mode, OutputConflictHandling}; fn miri_path() -> PathBuf { PathBuf::from(option_env!("MIRI").unwrap_or(env!("CARGO_BIN_EXE_miri"))) diff --git a/ui_test/src/comments.rs b/ui_test/src/comments.rs index fcbcae33f2d7c..481565cfea0a6 100644 --- a/ui_test/src/comments.rs +++ b/ui_test/src/comments.rs @@ -4,7 +4,7 @@ use regex::Regex; use crate::rustc_stderr::Level; -use color_eyre::eyre::Result; +use color_eyre::eyre::{bail, ensure, eyre, Result}; #[cfg(test)] mod tests; @@ -66,43 +66,6 @@ impl Condition { } } -macro_rules! checked { - ($path:expr, $l:expr) => { - let path = $path; - let l = $l; - #[allow(unused_macros)] - macro_rules! exit { - ($fmt:expr $$(,$args:expr)*) => {{ - eprint!("{}:{l}: ", path.display()); - eprintln!($fmt, $$($args,)*); - #[cfg(not(test))] - std::process::exit(1); - #[cfg(test)] - panic!(); - }}; - } - #[allow(unused_macros)] - macro_rules! check { - ($cond:expr, $fmt:expr $$(,$args:expr)*) => {{ - if !$cond { - exit!($fmt $$(,$args)*); - } - }}; - } - #[allow(unused_macros)] - macro_rules! unwrap { - ($cond:expr, $fmt:expr $$(,$args:expr)*) => {{ - match $cond { - Some(val) => val, - None => { - exit!($fmt $$(,$args)*); - } - } - }}; - } - }; -} - impl Comments { pub(crate) fn parse_file(path: &Path) -> Result { let content = std::fs::read_to_string(path)?; @@ -121,24 +84,36 @@ impl Comments { let mut fallthrough_to = None; for (l, line) in content.lines().enumerate() { let l = l + 1; // enumerate starts at 0, but line numbers start at 1 - if let Some((_, command)) = line.split_once("//@") { - let command = command.trim(); - if let Some((command, args)) = command.split_once(':') { - this.parse_command_with_args(command, args, path, l); - } else if let Some((command, _comments)) = command.split_once(' ') { - this.parse_command(command, path, l) - } else { - this.parse_command(command, path, l) - } - } else if let Some((_, pattern)) = line.split_once("//~") { - this.parse_pattern(pattern, &mut fallthrough_to, path, l) - } else if let Some((_, pattern)) = line.split_once("//[") { - this.parse_revisioned_pattern(pattern, &mut fallthrough_to, path, l) + this.parse_checked_line(l, &mut fallthrough_to, line).map_err(|err| { + err.wrap_err(format!("{}:{l}: failed to parse annotation", path.display())) + })?; + } + Ok(this) + } + + fn parse_checked_line( + &mut self, + l: usize, + fallthrough_to: &mut Option, + line: &str, + ) -> Result<()> { + if let Some((_, command)) = line.split_once("//@") { + let command = command.trim(); + if let Some((command, args)) = command.split_once(':') { + self.parse_command_with_args(command, args, l) + } else if let Some((command, _comments)) = command.split_once(' ') { + self.parse_command(command) } else { - fallthrough_to = None; + self.parse_command(command) } + } else if let Some((_, pattern)) = line.split_once("//~") { + self.parse_pattern(pattern, fallthrough_to, l) + } else if let Some((_, pattern)) = line.split_once("//[") { + self.parse_revisioned_pattern(pattern, fallthrough_to, l) + } else { + *fallthrough_to = None; + Ok(()) } - Ok(this) } /// Parse comments in `content`. @@ -214,11 +189,10 @@ impl Comments { Ok(this) } - fn parse_command_with_args(&mut self, command: &str, args: &str, path: &Path, l: usize) { - checked!(path, l); + fn parse_command_with_args(&mut self, command: &str, args: &str, l: usize) -> Result<()> { match command { "revisions" => { - check!(self.revisions.is_none(), "cannot specifiy revisions twice"); + ensure!(self.revisions.is_none(), "cannot specifiy revisions twice"); self.revisions = Some(args.split_whitespace().map(|s| s.to_string()).collect()); } "compile-flags" => { @@ -226,22 +200,22 @@ impl Comments { } "rustc-env" => for env in args.split_whitespace() { - let (k, v) = unwrap!( - env.split_once('='), - "environment variables must be key/value pairs separated by a `=`" - ); + let (k, v) = env.split_once('=').ok_or_else(|| { + eyre!("environment variables must be key/value pairs separated by a `=`") + })?; self.env_vars.push((k.to_string(), v.to_string())); }, "normalize-stderr-test" => { - let (from, to) = - unwrap!(args.split_once("->"), "normalize-stderr-test needs a `->`"); + let (from, to) = args + .split_once("->") + .ok_or_else(|| eyre!("normalize-stderr-test needs a `->`"))?; let from = from.trim().trim_matches('"'); let to = to.trim().trim_matches('"'); - let from = unwrap!(Regex::new(from).ok(), "invalid regex"); + let from = Regex::new(from).ok().ok_or_else(|| eyre!("invalid regex"))?; self.normalize_stderr.push((from, to.to_string())); } "error-pattern" => { - check!( + ensure!( self.error_pattern.is_none(), "cannot specifiy error_pattern twice, previous: {:?}", self.error_pattern @@ -249,56 +223,52 @@ impl Comments { self.error_pattern = Some((args.trim().to_string(), l)); } // Maybe the user just left a comment explaining a command without arguments - _ => self.parse_command(command, path, l), + _ => self.parse_command(command)?, } + Ok(()) } - fn parse_command(&mut self, command: &str, path: &Path, l: usize) { - checked!(path, l); - + fn parse_command(&mut self, command: &str) -> Result<()> { if let Some(s) = command.strip_prefix("ignore-") { self.ignore.push(Condition::parse(s)); - return; + return Ok(()); } if let Some(s) = command.strip_prefix("only-") { self.only.push(Condition::parse(s)); - return; + return Ok(()); } if command.starts_with("stderr-per-bitwidth") { - check!(!self.stderr_per_bitwidth, "cannot specifiy stderr-per-bitwidth twice"); + ensure!(!self.stderr_per_bitwidth, "cannot specifiy stderr-per-bitwidth twice"); self.stderr_per_bitwidth = true; - return; + return Ok(()); } - exit!("unknown command {command}"); + bail!("unknown command {command}"); } fn parse_pattern( &mut self, pattern: &str, fallthrough_to: &mut Option, - path: &Path, l: usize, - ) { - self.parse_pattern_inner(pattern, fallthrough_to, None, path, l) + ) -> Result<()> { + self.parse_pattern_inner(pattern, fallthrough_to, None, l) } fn parse_revisioned_pattern( &mut self, pattern: &str, fallthrough_to: &mut Option, - path: &Path, l: usize, - ) { - checked!(path, l); + ) -> Result<()> { let (revision, pattern) = - unwrap!(pattern.split_once(']'), "`//[` without corresponding `]`"); + pattern.split_once(']').ok_or_else(|| eyre!("`//[` without corresponding `]`"))?; if let Some(pattern) = pattern.strip_prefix('~') { - self.parse_pattern_inner(pattern, fallthrough_to, Some(revision.to_owned()), path, l) + self.parse_pattern_inner(pattern, fallthrough_to, Some(revision.to_owned()), l) } else { - exit!("revisioned pattern must have `~` following the `]`"); + bail!("revisioned pattern must have `~` following the `]`"); } } @@ -308,21 +278,25 @@ impl Comments { pattern: &str, fallthrough_to: &mut Option, revision: Option, - path: &Path, l: usize, - ) { - checked!(path, l); + ) -> Result<()> { // FIXME: check that the error happens on the marked line - let (match_line, pattern) = match unwrap!(pattern.chars().next(), "no pattern specified") { - '|' => - (*unwrap!(fallthrough_to, "`//~|` pattern without preceding line"), &pattern[1..]), - '^' => { - let offset = pattern.chars().take_while(|&c| c == '^').count(); - (l - offset, &pattern[offset..]) - } - _ => (l, pattern), - }; + let (match_line, pattern) = + match pattern.chars().next().ok_or_else(|| eyre!("no pattern specified"))? { + '|' => + ( + *fallthrough_to + .as_mut() + .ok_or_else(|| eyre!("`//~|` pattern without preceding line"))?, + &pattern[1..], + ), + '^' => { + let offset = pattern.chars().take_while(|&c| c == '^').count(); + (l - offset, &pattern[offset..]) + } + _ => (l, pattern), + }; let (level, pattern) = match pattern.trim_start().split_once(|c| matches!(c, ':' | ' ')) { None => (None, pattern), @@ -335,7 +309,7 @@ impl Comments { let matched = pattern.trim().to_string(); - check!(!matched.is_empty(), "no pattern specified"); + ensure!(!matched.is_empty(), "no pattern specified"); *fallthrough_to = Some(match_line); @@ -346,5 +320,7 @@ impl Comments { definition_line: l, line: match_line, }); + + Ok(()) } } diff --git a/ui_test/src/comments/tests.rs b/ui_test/src/comments/tests.rs index 0573ee8ba706c..cdd81aa990538 100644 --- a/ui_test/src/comments/tests.rs +++ b/ui_test/src/comments/tests.rs @@ -1,9 +1,9 @@ -use std::{path::Path, panic::catch_unwind}; +use std::path::Path; use super::Comments; -use color_eyre::eyre::{Result, bail}; use crate::tests::init; +use color_eyre::eyre::{bail, Result}; #[test] fn parse_simple_comment() -> Result<()> { @@ -48,8 +48,8 @@ fn parse_slash_slash_at_fail() -> Result<()> { use std::mem; "; - match catch_unwind(|| Comments::parse(Path::new(""), s)) { - Ok(_) => bail!("expected parsing to panic"), + match Comments::parse(Path::new(""), s) { + Ok(_) => bail!("expected parsing to fail"), Err(_) => Ok(()), } } diff --git a/ui_test/src/lib.rs b/ui_test/src/lib.rs index 90e7669f62aa3..da562fcac7d29 100644 --- a/ui_test/src/lib.rs +++ b/ui_test/src/lib.rs @@ -7,12 +7,12 @@ use std::process::{Command, ExitStatus}; use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::Mutex; +pub use color_eyre; +use color_eyre::eyre::Result; use colored::*; use comments::ErrorMatch; use regex::Regex; use rustc_stderr::{Level, Message}; -use color_eyre::eyre::Result; -pub use color_eyre; use crate::comments::{Comments, Condition}; @@ -68,7 +68,7 @@ pub fn run_tests(config: Config) -> Result<()> { let ignored = AtomicUsize::default(); let filtered = AtomicUsize::default(); - crossbeam::scope(|s| { + crossbeam::scope(|s| -> Result<()> { // Create a thread that is in charge of walking the directory and submitting jobs. // It closes the channel when it is done. s.spawn(|_| { @@ -94,9 +94,11 @@ pub fn run_tests(config: Config) -> Result<()> { drop(submit); }); + let mut threads = vec![]; + // Create N worker threads that receive files to test. for _ in 0..std::thread::available_parallelism().unwrap().get() { - s.spawn(|_| -> Result<()> { + threads.push(s.spawn(|_| -> Result<()> { for path in &receive { if !config.path_filter.is_empty() { let path_display = path.display().to_string(); @@ -145,10 +147,14 @@ pub fn run_tests(config: Config) -> Result<()> { } } Ok(()) - }); + })); + } + for thread in threads { + thread.join().unwrap()?; } + Ok(()) }) - .unwrap(); + .unwrap()?; // Print all errors in a single thread to show reliable output let failures = failures.into_inner().unwrap(); From 63916d6f0429718112661e47fac37b2fcfea338e Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 6 Jul 2022 09:53:52 +0000 Subject: [PATCH 3439/3747] Document all the things --- ui_test/README.md | 38 +++++++++++++++++++++++++------------- ui_test/src/comments.rs | 2 +- 2 files changed, 26 insertions(+), 14 deletions(-) diff --git a/ui_test/README.md b/ui_test/README.md index f7852c82e44b5..fef2c6d44ba6a 100644 --- a/ui_test/README.md +++ b/ui_test/README.md @@ -7,25 +7,37 @@ A smaller version of compiletest-rs ## Supported magic comment annotations -* `// ignore-XXX` avoids running the test on targets whose triple contains `XXX` +If your test tests for failure, you need to add a `//~` annotation where the error is happening +to make sure that the test will always keep failing with a specific message at the annotated line. + +`//~ ERROR: XXX` make sure the stderr output contains `XXX` for an error in the line where this comment is written + +* Also supports `HELP`, `WARN` or `NOTE` for different kind of message + * if one of those levels is specified explicitly, *all* diagnostics of this level or higher need an annotation. If you want to avoid this, just leave out the all caps level note entirely. +* If the all caps note is left out, a message of any level is matched. Leaving it out is not allowed for `ERROR` levels. +* This checks the output *before* normalization, so you can check things that get normalized away, but need to + be careful not to accidentally have a pattern that differs between platforms. + +In order to change how a single test is tested, you can add various `//@` comments to the test. +Any other comments will be ignored, and all `//@` comments must be formatted precisely as +their command specifies, or the test will fail without even being run. + +* `//@ignore-XXX` avoids running the test on targets whose triple contains `XXX` * `XXX` can also be one of `64bit`, `32bit` or `16bit` -* `// only-XXX` avoids running the test on targets whose triple **does not** contain `XXX` +* `//@only-XXX` avoids running the test on targets whose triple **does not** contain `XXX` * `XXX` can also be one of `64bit`, `32bit` or `16bit` -* `// stderr-per-bitwidth` produces one stderr file per bitwidth, as they may differ significantly sometimes +* `//@stderr-per-bitwidth` produces one stderr file per bitwidth, as they may differ significantly sometimes * `//@error-pattern: XXX` make sure the stderr output contains `XXX` -* `//~ ERROR: XXX` make sure the stderr output contains `XXX` for an error in the line where this comment is written - * Also supports `HELP`, `WARN` or `NOTE` for different kind of message - * if one of those levels is specified explicitly, *all* diagnostics of this level or higher need an annotation. If you want to avoid this, just leave out the all caps level note entirely. - * If the all caps note is left out, a message of any level is matched. Leaving it out is not allowed for `ERROR` levels. - * This checks the output *before* normalization, so you can check things that get normalized away, but need to - be careful not to accidentally have a pattern that differs between platforms. -* `// revisions: XXX YYY` runs the test once for each space separated name in the list +* `//@revisions: XXX YYY` runs the test once for each space separated name in the list * emits one stderr file per revision * `//~` comments can be restricted to specific revisions by adding the revision name before the `~` in square brackets: `//[XXX]~` -* `// compile-flags: XXX` appends `XXX` to the command line arguments passed to the rustc driver -* `// rustc-env: XXX=YYY` sets the env var `XXX` to `YYY` for the rustc driver execution. +* `//@compile-flags: XXX` appends `XXX` to the command line arguments passed to the rustc driver + * you can specify this multiple times, and all the flags will accumulate +* `//@rustc-env: XXX=YYY` sets the env var `XXX` to `YYY` for the rustc driver execution. * for Miri these env vars are used during compilation via rustc and during the emulation of the program -* `// normalize-stderr-test: "REGEX" -> "REPLACEMENT"` replaces all matches of `REGEX` in the stderr with `REPLACEMENT`. The replacement may specify `$1` and similar backreferences to paste captures. + * you can specify this multiple times, accumulating all the env vars +* `//@normalize-stderr-test: "REGEX" -> "REPLACEMENT"` replaces all matches of `REGEX` in the stderr with `REPLACEMENT`. The replacement may specify `$1` and similar backreferences to paste captures. + * you can specify multiple such commands, there is no need to create a single regex that handles multiple replacements that you want to perform. ## Significant differences to compiletest-rs diff --git a/ui_test/src/comments.rs b/ui_test/src/comments.rs index 481565cfea0a6..dd6ca9581ab2d 100644 --- a/ui_test/src/comments.rs +++ b/ui_test/src/comments.rs @@ -75,7 +75,7 @@ impl Comments { /// Parse comments in `content`. /// `path` is only used to emit diagnostics if parsing fails. /// - /// This function will only parse `//@` and `//~` style comments + /// This function will only parse `//@` and `//~` style comments (and the `//[xxx]~` variant) /// and ignore all others fn parse_checked(path: &Path, content: &str) -> Result { let mut this = Self::default(); From f15a56d9bcc9712bca842f182e160df1942aea98 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 6 Jul 2022 10:17:21 +0000 Subject: [PATCH 3440/3747] Implement a proper command parser... ... that grabs things from the front instead of splitting at spaces and colons and hoping for the best --- ui_test/src/comments.rs | 63 ++++++++++++++++++----------------- ui_test/src/comments/tests.rs | 2 +- 2 files changed, 34 insertions(+), 31 deletions(-) diff --git a/ui_test/src/comments.rs b/ui_test/src/comments.rs index dd6ca9581ab2d..fa46b54970009 100644 --- a/ui_test/src/comments.rs +++ b/ui_test/src/comments.rs @@ -98,14 +98,7 @@ impl Comments { line: &str, ) -> Result<()> { if let Some((_, command)) = line.split_once("//@") { - let command = command.trim(); - if let Some((command, args)) = command.split_once(':') { - self.parse_command_with_args(command, args, l) - } else if let Some((command, _comments)) = command.split_once(' ') { - self.parse_command(command) - } else { - self.parse_command(command) - } + self.parse_command(command.trim(), l) } else if let Some((_, pattern)) = line.split_once("//~") { self.parse_pattern(pattern, fallthrough_to, l) } else if let Some((_, pattern)) = line.split_once("//[") { @@ -189,7 +182,22 @@ impl Comments { Ok(this) } - fn parse_command_with_args(&mut self, command: &str, args: &str, l: usize) -> Result<()> { + fn parse_command(&mut self, command: &str, l: usize) -> Result<()> { + // Commands are letters or dashes, grab everything until the first character that is neither of those. + let (command, args) = match command.chars().position(|c: char| !c.is_alphabetic() && c != '-') { + None => (command, ""), + Some(i) => { + let (command, args) = command.split_at(i); + let mut args = args.chars(); + let next = args.next().expect("the `position` above guarantees that there is at least one char"); + let args = match next { + ':' | ' ' => args.as_str(), + _ => bail!("expected space or `:`, got `{next}`"), + }; + (command, args) + } + }; + match command { "revisions" => { ensure!(self.revisions.is_none(), "cannot specifiy revisions twice"); @@ -222,30 +230,25 @@ impl Comments { ); self.error_pattern = Some((args.trim().to_string(), l)); } - // Maybe the user just left a comment explaining a command without arguments - _ => self.parse_command(command)?, - } - Ok(()) - } - - fn parse_command(&mut self, command: &str) -> Result<()> { - if let Some(s) = command.strip_prefix("ignore-") { - self.ignore.push(Condition::parse(s)); - return Ok(()); - } - - if let Some(s) = command.strip_prefix("only-") { - self.only.push(Condition::parse(s)); - return Ok(()); - } + "stderr-per-bitwidth" => { + ensure!(!self.stderr_per_bitwidth, "cannot specifiy stderr-per-bitwidth twice"); + self.stderr_per_bitwidth = true; + } + command => { + if let Some(s) = command.strip_prefix("ignore-") { + self.ignore.push(Condition::parse(s)); + return Ok(()); + } - if command.starts_with("stderr-per-bitwidth") { - ensure!(!self.stderr_per_bitwidth, "cannot specifiy stderr-per-bitwidth twice"); - self.stderr_per_bitwidth = true; - return Ok(()); + if let Some(s) = command.strip_prefix("only-") { + self.only.push(Condition::parse(s)); + return Ok(()); + } + bail!("unknown command {command}"); + } } - bail!("unknown command {command}"); + Ok(()) } fn parse_pattern( diff --git a/ui_test/src/comments/tests.rs b/ui_test/src/comments/tests.rs index cdd81aa990538..15a0aae247b1d 100644 --- a/ui_test/src/comments/tests.rs +++ b/ui_test/src/comments/tests.rs @@ -44,7 +44,7 @@ use std::mem; fn parse_slash_slash_at_fail() -> Result<()> { init(); let s = r" -//@ error-pattern foomp +//@ error-patttern foomp use std::mem; "; From eab02b69e51165274af4b1e1df9625df5347a6a5 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 6 Jul 2022 10:38:14 +0000 Subject: [PATCH 3441/3747] rustfmt --- ui_test/src/comments.rs | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/ui_test/src/comments.rs b/ui_test/src/comments.rs index fa46b54970009..727e6a2aa237d 100644 --- a/ui_test/src/comments.rs +++ b/ui_test/src/comments.rs @@ -184,19 +184,22 @@ impl Comments { fn parse_command(&mut self, command: &str, l: usize) -> Result<()> { // Commands are letters or dashes, grab everything until the first character that is neither of those. - let (command, args) = match command.chars().position(|c: char| !c.is_alphabetic() && c != '-') { - None => (command, ""), - Some(i) => { - let (command, args) = command.split_at(i); - let mut args = args.chars(); - let next = args.next().expect("the `position` above guarantees that there is at least one char"); - let args = match next { - ':' | ' ' => args.as_str(), - _ => bail!("expected space or `:`, got `{next}`"), - }; - (command, args) - } - }; + let (command, args) = + match command.chars().position(|c: char| !c.is_alphabetic() && c != '-') { + None => (command, ""), + Some(i) => { + let (command, args) = command.split_at(i); + let mut args = args.chars(); + let next = args + .next() + .expect("the `position` above guarantees that there is at least one char"); + let args = match next { + ':' | ' ' => args.as_str(), + _ => bail!("expected space or `:`, got `{next}`"), + }; + (command, args) + } + }; match command { "revisions" => { From cc35d809c1d7585e03044524d9b2838200880791 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Thu, 7 Jul 2022 08:07:50 +0000 Subject: [PATCH 3442/3747] Remove an outdated comment --- ui_test/src/comments.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/ui_test/src/comments.rs b/ui_test/src/comments.rs index 727e6a2aa237d..0727c182a304f 100644 --- a/ui_test/src/comments.rs +++ b/ui_test/src/comments.rs @@ -286,8 +286,6 @@ impl Comments { revision: Option, l: usize, ) -> Result<()> { - // FIXME: check that the error happens on the marked line - let (match_line, pattern) = match pattern.chars().next().ok_or_else(|| eyre!("no pattern specified"))? { '|' => From a1e0d0df79d58aba78d2aabe783647e5cd80ba81 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Thu, 7 Jul 2022 08:13:24 +0000 Subject: [PATCH 3443/3747] Add some comments --- ui_test/src/comments.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ui_test/src/comments.rs b/ui_test/src/comments.rs index 0727c182a304f..905ce96c50aaa 100644 --- a/ui_test/src/comments.rs +++ b/ui_test/src/comments.rs @@ -80,8 +80,7 @@ impl Comments { fn parse_checked(path: &Path, content: &str) -> Result { let mut this = Self::default(); - // The line that a `|` will refer to - let mut fallthrough_to = None; + let mut fallthrough_to = None; // The line that a `|` will refer to. for (l, line) in content.lines().enumerate() { let l = l + 1; // enumerate starts at 0, but line numbers start at 1 this.parse_checked_line(l, &mut fallthrough_to, line).map_err(|err| { @@ -190,6 +189,7 @@ impl Comments { Some(i) => { let (command, args) = command.split_at(i); let mut args = args.chars(); + // Commands are separated from their arguments by ':' or ' ' let next = args .next() .expect("the `position` above guarantees that there is at least one char"); From bc07c19961b889fbecbfea9f7bca43b6174cffdb Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Thu, 7 Jul 2022 08:15:21 +0000 Subject: [PATCH 3444/3747] Explain `tests::init` function --- ui_test/src/tests.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ui_test/src/tests.rs b/ui_test/src/tests.rs index 13a242f8d8a73..11a3d6aca2784 100644 --- a/ui_test/src/tests.rs +++ b/ui_test/src/tests.rs @@ -329,8 +329,8 @@ fn main() { } } -static INIT: std::sync::Once = std::sync::Once::new(); - +/// Call this from every test to initialize eyre only once across all tests. pub fn init() { + static INIT: std::sync::Once = std::sync::Once::new(); INIT.call_once(|| color_eyre::install().unwrap()); } From 9b71180e52bda136230b8185823728a7497556bb Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Thu, 7 Jul 2022 08:55:24 +0000 Subject: [PATCH 3445/3747] Create a proper normalization regex parser --- ui_test/src/comments.rs | 39 ++++++++++++++++++++++++++++++++------- 1 file changed, 32 insertions(+), 7 deletions(-) diff --git a/ui_test/src/comments.rs b/ui_test/src/comments.rs index 905ce96c50aaa..63a14ce13b56d 100644 --- a/ui_test/src/comments.rs +++ b/ui_test/src/comments.rs @@ -197,7 +197,7 @@ impl Comments { ':' | ' ' => args.as_str(), _ => bail!("expected space or `:`, got `{next}`"), }; - (command, args) + (command, args.trim()) } }; @@ -217,12 +217,37 @@ impl Comments { self.env_vars.push((k.to_string(), v.to_string())); }, "normalize-stderr-test" => { - let (from, to) = args - .split_once("->") - .ok_or_else(|| eyre!("normalize-stderr-test needs a `->`"))?; - let from = from.trim().trim_matches('"'); - let to = to.trim().trim_matches('"'); - let from = Regex::new(from).ok().ok_or_else(|| eyre!("invalid regex"))?; + fn parse_str(s: &str) -> Result<(&str, &str)> { + let mut chars = s.char_indices(); + match chars.next().ok_or_else(|| eyre!("missing arguments"))?.1 { + '"' => { + let s = chars.as_str(); + let mut escaped = false; + for (i, c) in chars { + if escaped { + escaped = false; + } else if c == '"' { + return Ok((&s[..(i - 1)], s[i..].trim_start())) + } else { + escaped = c == '\\'; + } + } + bail!("no closing quotes found for {s}") + } + c => bail!("expected '\"', got {c}"), + } + } + + let (from, rest) = parse_str(args)?; + + let to = rest.strip_prefix("->").ok_or_else(|| { + eyre!("normalize-stderr-test needs a pattern and replacement separated by `->`") + })?.trim_start(); + let (to, rest) = parse_str(to)?; + + ensure!(rest.is_empty(), "trailing text after pattern replacement: {rest}"); + + let from = Regex::new(from)?; self.normalize_stderr.push((from, to.to_string())); } "error-pattern" => { From af798232eb9ab5f7c8c8c5760d2c96d4612e0d7c Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Thu, 7 Jul 2022 09:20:48 +0000 Subject: [PATCH 3446/3747] Rustfmt --- ui_test/src/comments.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui_test/src/comments.rs b/ui_test/src/comments.rs index 63a14ce13b56d..6f2d8aa086d94 100644 --- a/ui_test/src/comments.rs +++ b/ui_test/src/comments.rs @@ -227,7 +227,7 @@ impl Comments { if escaped { escaped = false; } else if c == '"' { - return Ok((&s[..(i - 1)], s[i..].trim_start())) + return Ok((&s[..(i - 1)], s[i..].trim_start())); } else { escaped = c == '\\'; } From 334aa3d7f84f66bd96a94dda499d5300f3333b15 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Fri, 8 Jul 2022 15:14:25 +0000 Subject: [PATCH 3447/3747] Add FIXME --- ui_test/src/comments.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/ui_test/src/comments.rs b/ui_test/src/comments.rs index 6f2d8aa086d94..080a887d9e740 100644 --- a/ui_test/src/comments.rs +++ b/ui_test/src/comments.rs @@ -193,6 +193,7 @@ impl Comments { let next = args .next() .expect("the `position` above guarantees that there is at least one char"); + // FIXME: this replicates the existing flexibility in our syntax. Consider requiring the colon. let args = match next { ':' | ' ' => args.as_str(), _ => bail!("expected space or `:`, got `{next}`"), From 1597cec887c0716fd0fa4e537d786b8a8d62829d Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Fri, 8 Jul 2022 15:16:16 +0000 Subject: [PATCH 3448/3747] Documentation --- ui_test/src/comments.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ui_test/src/comments.rs b/ui_test/src/comments.rs index 080a887d9e740..2b6108f255f8e 100644 --- a/ui_test/src/comments.rs +++ b/ui_test/src/comments.rs @@ -218,6 +218,9 @@ impl Comments { self.env_vars.push((k.to_string(), v.to_string())); }, "normalize-stderr-test" => { + /// Parses a string literal. `s` has to start with `"`; everything until the next `"` is + /// returned in the first component. `\` can be used to escape arbitrary character. + /// Second return component is the rest of the string with leading whitespace removed. fn parse_str(s: &str) -> Result<(&str, &str)> { let mut chars = s.char_indices(); match chars.next().ok_or_else(|| eyre!("missing arguments"))?.1 { @@ -226,6 +229,7 @@ impl Comments { let mut escaped = false; for (i, c) in chars { if escaped { + // Accept any character as literal after a `\`. escaped = false; } else if c == '"' { return Ok((&s[..(i - 1)], s[i..].trim_start())); From e4f7c6845ce09da759bad521d4dd23cf70632874 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Fri, 8 Jul 2022 15:20:28 +0000 Subject: [PATCH 3449/3747] Hide regular backtrace information from user-facing errors --- ui_test/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui_test/Cargo.toml b/ui_test/Cargo.toml index 94c5acb6b70b6..cdc5e5db472c1 100644 --- a/ui_test/Cargo.toml +++ b/ui_test/Cargo.toml @@ -17,5 +17,5 @@ crossbeam = "0.8.1" lazy_static = "1.4.0" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" -color-eyre = "0.6.1" +color-eyre = { version = "0.6.1", default-features = false, features = ["capture-spantrace"] } From 6e106617f10b2431aeb0fdb84d50cbdcb0d4dad8 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Fri, 8 Jul 2022 16:08:32 +0000 Subject: [PATCH 3450/3747] Port all tests --- tests/fail/box-cell-alias.rs | 2 +- .../concurrency/libc_pthread_join_detached.rs | 2 +- .../concurrency/libc_pthread_join_joined.rs | 2 +- .../concurrency/libc_pthread_join_main.rs | 2 +- .../concurrency/libc_pthread_join_multiple.rs | 2 +- .../concurrency/libc_pthread_join_self.rs | 4 +- .../thread_local_static_dealloc.rs | 2 +- tests/fail/concurrency/too_few_args.rs | 2 +- tests/fail/concurrency/too_many_args.rs | 2 +- tests/fail/concurrency/unwind_top_of_stack.rs | 4 +- .../dangling_pointer_addr_of.rs | 2 +- .../dangling_pointer_deref.rs | 2 +- .../dangling_pointers/dangling_zst_deref.rs | 2 +- .../dangling_pointers/deref-invalid-ptr.rs | 2 +- tests/fail/dangling_pointers/dyn_size.rs | 2 +- .../maybe_null_pointer_deref_zst.rs | 2 +- .../maybe_null_pointer_write_zst.rs | 2 +- .../null_pointer_deref_zst.rs | 2 +- .../fail/dangling_pointers/stack_temporary.rs | 2 +- .../storage_dead_dangling.rs | 2 +- .../dangling_pointers/wild_pointer_deref.rs | 2 +- tests/fail/data_race/alloc_read_race.rs | 4 +- tests/fail/data_race/alloc_write_race.rs | 4 +- .../data_race/atomic_read_na_write_race1.rs | 2 +- .../data_race/atomic_read_na_write_race2.rs | 2 +- .../data_race/atomic_write_na_read_race1.rs | 2 +- .../data_race/atomic_write_na_read_race2.rs | 2 +- .../data_race/atomic_write_na_write_race1.rs | 2 +- .../data_race/atomic_write_na_write_race2.rs | 2 +- .../data_race/dangling_thread_async_race.rs | 4 +- tests/fail/data_race/dangling_thread_race.rs | 4 +- tests/fail/data_race/dealloc_read_race1.rs | 2 +- tests/fail/data_race/dealloc_read_race2.rs | 2 +- .../fail/data_race/dealloc_read_race_stack.rs | 4 +- tests/fail/data_race/dealloc_write_race1.rs | 2 +- tests/fail/data_race/dealloc_write_race2.rs | 2 +- .../data_race/dealloc_write_race_stack.rs | 4 +- .../data_race/enable_after_join_to_main.rs | 2 +- tests/fail/data_race/fence_after_load.rs | 4 +- tests/fail/data_race/read_write_race.rs | 2 +- tests/fail/data_race/read_write_race_stack.rs | 4 +- tests/fail/data_race/relax_acquire_race.rs | 4 +- tests/fail/data_race/release_seq_race.rs | 4 +- .../data_race/release_seq_race_same_thread.rs | 4 +- tests/fail/data_race/rmw_race.rs | 4 +- tests/fail/data_race/stack_pop_race.rs | 4 +- tests/fail/data_race/write_write_race.rs | 2 +- .../fail/data_race/write_write_race_stack.rs | 4 +- tests/fail/environ-gets-deallocated.rs | 2 +- tests/fail/erroneous_const.rs | 2 +- tests/fail/fs/close_stdout.rs | 4 +- tests/fail/fs/isolated_stdin.rs | 2 +- tests/fail/fs/read_from_stdout.rs | 4 +- .../fs/unix_open_missing_required_mode.rs | 4 +- tests/fail/fs/write_to_stdin.rs | 2 +- .../exported_symbol_abi_mismatch.rs | 2 +- .../exported_symbol_bad_unwind1.rs | 2 +- .../exported_symbol_bad_unwind2.rs | 2 +- .../cast_box_int_to_fn_ptr.rs | 2 +- .../function_pointers/cast_int_to_fn_ptr.rs | 2 +- .../fail/function_pointers/execute_memory.rs | 2 +- tests/fail/function_pointers/fn_ptr_offset.rs | 2 +- tests/fail/generator-pinned-moved.rs | 2 +- tests/fail/invalid_bool.rs | 2 +- tests/fail/invalid_char.rs | 2 +- tests/fail/invalid_int.rs | 2 +- tests/fail/modifying_constants.rs | 2 +- tests/fail/never_say_never.rs | 2 +- tests/fail/never_transmute_humans.rs | 2 +- tests/fail/never_transmute_void.rs | 2 +- tests/fail/panic/bad_miri_start_panic.rs | 2 +- tests/fail/panic/unwind_panic_abort.rs | 2 +- tests/fail/pointer_partial_overwrite.rs | 2 +- tests/fail/provenance/provenance_transmute.rs | 2 +- tests/fail/provenance/ptr_int_unexposed.rs | 2 +- .../fail/provenance/strict_provenance_cast.rs | 2 +- tests/fail/rc_as_ptr.rs | 2 +- tests/fail/shim_arg_size.rs | 2 +- tests/fail/stacked_borrows/exposed_only_ro.rs | 2 +- tests/fail/stacked_borrows/illegal_read5.rs | 2 +- .../illegal_read_despite_exposed1.rs | 2 +- .../illegal_read_despite_exposed2.rs | 2 +- .../illegal_write_despite_exposed1.rs | 2 +- .../fail/stacked_borrows/load_invalid_mut.rs | 2 +- .../fail/stacked_borrows/load_invalid_shr.rs | 2 +- .../shared_rw_borrows_are_weak2.rs | 2 +- tests/fail/stacked_borrows/unescaped_local.rs | 2 +- tests/fail/stacked_borrows/zst_slice.rs | 2 +- tests/fail/static_memory_modification1.rs | 2 +- tests/fail/static_memory_modification2.rs | 2 +- tests/fail/static_memory_modification3.rs | 2 +- .../sync/libc_pthread_cond_double_destroy.rs | 2 +- .../libc_pthread_condattr_double_destroy.rs | 2 +- .../sync/libc_pthread_mutex_NULL_deadlock.rs | 2 +- .../fail/sync/libc_pthread_mutex_deadlock.rs | 2 +- .../libc_pthread_mutex_default_deadlock.rs | 2 +- .../sync/libc_pthread_mutex_destroy_locked.rs | 2 +- .../sync/libc_pthread_mutex_double_destroy.rs | 2 +- .../libc_pthread_mutex_normal_deadlock.rs | 2 +- ...bc_pthread_mutex_normal_unlock_unlocked.rs | 2 +- .../sync/libc_pthread_mutex_wrong_owner.rs | 2 +- .../libc_pthread_mutexattr_double_destroy.rs | 2 +- ...libc_pthread_rwlock_destroy_read_locked.rs | 2 +- ...ibc_pthread_rwlock_destroy_write_locked.rs | 2 +- .../libc_pthread_rwlock_double_destroy.rs | 2 +- ...wlock_read_write_deadlock_single_thread.rs | 2 +- .../libc_pthread_rwlock_read_wrong_owner.rs | 2 +- .../libc_pthread_rwlock_unlock_unlocked.rs | 2 +- ...libc_pthread_rwlock_write_read_deadlock.rs | 2 +- ...wlock_write_read_deadlock_single_thread.rs | 2 +- ...ibc_pthread_rwlock_write_write_deadlock.rs | 2 +- ...lock_write_write_deadlock_single_thread.rs | 2 +- .../libc_pthread_rwlock_write_wrong_owner.rs | 2 +- tests/fail/type-too-large.rs | 2 +- tests/fail/unaligned_pointers/alignment.rs | 2 +- .../unaligned_pointers/atomic_unaligned.rs | 2 +- .../fail/unaligned_pointers/dyn_alignment.rs | 2 +- .../intptrcast_alignment_check.rs | 2 +- .../unaligned_pointers/reference_to_packed.rs | 2 +- .../fail/unaligned_pointers/unaligned_ptr1.rs | 2 +- .../fail/unaligned_pointers/unaligned_ptr2.rs | 2 +- .../fail/unaligned_pointers/unaligned_ptr3.rs | 2 +- .../fail/unaligned_pointers/unaligned_ptr4.rs | 2 +- .../unaligned_ptr_addr_of.rs | 2 +- .../unaligned_pointers/unaligned_ptr_zst.rs | 2 +- tests/fail/uninit_byte_read.rs | 2 +- tests/fail/unsupported_signal.rs | 2 +- tests/fail/validity/cast_fn_ptr1.rs | 2 +- tests/fail/validity/cast_fn_ptr2.rs | 2 +- tests/fail/validity/dangling_ref1.rs | 2 +- tests/fail/validity/dangling_ref2.rs | 2 +- tests/fail/validity/dangling_ref3.rs | 2 +- .../invalid_enum_tag_256variants_uninit.rs | 2 +- tests/fail/validity/nonzero.rs | 2 +- tests/fail/weak_memory/racing_mixed_size.rs | 2 +- .../weak_memory/racing_mixed_size_read.rs | 2 +- tests/fail/zst2.rs | 2 +- tests/fail/zst3.rs | 2 +- tests/panic/panic/panic1.rs | 4 +- .../panic/unsupported_foreign_function.rs | 2 +- tests/panic/panic/unsupported_syscall.rs | 6 +- tests/pass/0weak_memory_consistency.rs | 4 +- tests/pass/adjacent-allocs.rs | 2 +- tests/pass/align.rs | 2 +- tests/pass/align_offset_symbolic.rs | 2 +- ...atomic-compare-exchange-weak-never-fail.rs | 2 +- tests/pass/atomic.rs | 2 +- tests/pass/backtrace/backtrace-api-v0.rs | 2 +- tests/pass/backtrace/backtrace-api-v1.rs | 2 +- .../pass/backtrace/backtrace-global-alloc.rs | 2 +- tests/pass/backtrace/backtrace-std.rs | 2 +- tests/pass/btreemap.rs | 2 +- tests/pass/calloc.rs | 2 +- tests/pass/concurrency/channels.rs | 4 +- .../concurrency/concurrent_caller_location.rs | 2 +- tests/pass/concurrency/data_race.rs | 4 +- .../concurrency/disable_data_race_detector.rs | 4 +- tests/pass/concurrency/issue1643.rs | 2 +- tests/pass/concurrency/libc_pthread_cond.rs | 6 +- tests/pass/concurrency/linux-futex.rs | 4 +- tests/pass/concurrency/mutex_leak.rs | 2 +- tests/pass/concurrency/simple.rs | 4 +- tests/pass/concurrency/spin_loop.rs | 2 +- .../pass/concurrency/spin_loops_nopreempt.rs | 4 +- tests/pass/concurrency/sync.rs | 4 +- tests/pass/concurrency/sync_nopreempt.rs | 4 +- tests/pass/concurrency/thread_locals.rs | 4 +- tests/pass/concurrency/tls_lib_drop.rs | 2 +- .../concurrency/tls_pthread_drop_order.rs | 2 +- tests/pass/current_dir.rs | 2 +- tests/pass/current_dir_with_isolation.rs | 6 +- tests/pass/disable-alignment-check.rs | 2 +- tests/pass/enum_discriminant_ptr_value.rs | 2 +- tests/pass/env-exclude.rs | 2 +- tests/pass/env-forward.rs | 2 +- tests/pass/env-without-isolation.rs | 2 +- tests/pass/fs.rs | 4 +- tests/pass/fs_with_isolation.rs | 6 +- .../pass/function_calls/disable_abi_check.rs | 2 +- tests/pass/getpid.rs | 2 +- tests/pass/hide_stdout.rs | 2 +- tests/pass/integer-ops.rs | 2 +- tests/pass/intptrcast.rs | 2 +- tests/pass/intrinsics.rs | 2 +- tests/pass/issues/issue-miri-1925.rs | 2 +- tests/pass/issues/issue-miri-2068-2.rs | 2 +- tests/pass/libc.rs | 4 +- .../pass/linux-getrandom-without-isolation.rs | 4 +- tests/pass/linux-getrandom.rs | 2 +- tests/pass/malloc.rs | 2 +- tests/pass/memleak_ignored.rs | 2 +- tests/pass/move-uninit-primval.rs | 2 +- tests/pass/no_std.rs | 2 +- tests/pass/observed_local_mut.rs | 2 +- tests/pass/overflow_checks_off.rs | 2 +- tests/pass/panic/catch_panic.rs | 2 +- tests/pass/panic/concurrent-panic.rs | 4 +- tests/pass/portable-simd.rs | 2 +- tests/pass/ptr_int_casts.rs | 2 +- tests/pass/ptr_int_from_exposed.rs | 2 +- tests/pass/ptr_offset.rs | 2 +- tests/pass/rc.rs | 2 +- tests/pass/slices.rs | 2 +- tests/pass/stacked-borrows/int-to-ptr.rs | 2 +- .../stacked-borrows/interior_mutability.rs | 2 +- tests/pass/stacked-borrows/stacked-borrows.rs | 2 +- tests/pass/strings.rs | 2 +- tests/pass/threadleak_ignored.rs | 4 +- tests/pass/time.rs | 2 +- tests/pass/track-alloc-1.rs | 4 +- tests/pass/transmute_fat.rs | 2 +- tests/pass/uninit_number_ignored.rs | 2 +- tests/pass/vec.rs | 2 +- tests/pass/vecdeque.rs | 2 +- tests/pass/weak_memory/extra_cpp.rs | 4 +- tests/pass/weak_memory/extra_cpp_unsafe.rs | 4 +- tests/pass/weak_memory/weak.rs | 4 +- tests/pass/without-validation.rs | 2 +- tests/pass/wtf8.rs | 2 +- tests/pass/zst.rs | 2 +- ui_test/src/comments.rs | 80 +------------------ 221 files changed, 269 insertions(+), 345 deletions(-) diff --git a/tests/fail/box-cell-alias.rs b/tests/fail/box-cell-alias.rs index d3f505d2da5cc..319845d86a63b 100644 --- a/tests/fail/box-cell-alias.rs +++ b/tests/fail/box-cell-alias.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-strict-provenance +//@compile-flags: -Zmiri-strict-provenance // Taken from . diff --git a/tests/fail/concurrency/libc_pthread_join_detached.rs b/tests/fail/concurrency/libc_pthread_join_detached.rs index dcd06596de130..1ec1d630ecb90 100644 --- a/tests/fail/concurrency/libc_pthread_join_detached.rs +++ b/tests/fail/concurrency/libc_pthread_join_detached.rs @@ -1,4 +1,4 @@ -// ignore-windows: No libc on Windows +//@ignore-windows: No libc on Windows // Joining a detached thread is undefined behavior. diff --git a/tests/fail/concurrency/libc_pthread_join_joined.rs b/tests/fail/concurrency/libc_pthread_join_joined.rs index 26f33f1f5f949..b067556e51b07 100644 --- a/tests/fail/concurrency/libc_pthread_join_joined.rs +++ b/tests/fail/concurrency/libc_pthread_join_joined.rs @@ -1,4 +1,4 @@ -// ignore-windows: No libc on Windows +//@ignore-windows: No libc on Windows // Joining an already joined thread is undefined behavior. diff --git a/tests/fail/concurrency/libc_pthread_join_main.rs b/tests/fail/concurrency/libc_pthread_join_main.rs index 15e43776ab828..ebfe8c865e3dc 100644 --- a/tests/fail/concurrency/libc_pthread_join_main.rs +++ b/tests/fail/concurrency/libc_pthread_join_main.rs @@ -1,4 +1,4 @@ -// ignore-windows: No libc on Windows +//@ignore-windows: No libc on Windows // Joining the main thread is undefined behavior. diff --git a/tests/fail/concurrency/libc_pthread_join_multiple.rs b/tests/fail/concurrency/libc_pthread_join_multiple.rs index d86233a67643b..39cd9ff77976f 100644 --- a/tests/fail/concurrency/libc_pthread_join_multiple.rs +++ b/tests/fail/concurrency/libc_pthread_join_multiple.rs @@ -1,4 +1,4 @@ -// ignore-windows: No libc on Windows +//@ignore-windows: No libc on Windows // Joining the same thread from multiple threads is undefined behavior. diff --git a/tests/fail/concurrency/libc_pthread_join_self.rs b/tests/fail/concurrency/libc_pthread_join_self.rs index db45b33c14684..7b91560ab6b19 100644 --- a/tests/fail/concurrency/libc_pthread_join_self.rs +++ b/tests/fail/concurrency/libc_pthread_join_self.rs @@ -1,6 +1,6 @@ -// ignore-windows: No libc on Windows +//@ignore-windows: No libc on Windows // We are making scheduler assumptions here. -// compile-flags: -Zmiri-preemption-rate=0 +//@compile-flags: -Zmiri-preemption-rate=0 // Joining itself is undefined behavior. diff --git a/tests/fail/concurrency/thread_local_static_dealloc.rs b/tests/fail/concurrency/thread_local_static_dealloc.rs index e6031b5e4c0c5..8cca1eba2d86c 100644 --- a/tests/fail/concurrency/thread_local_static_dealloc.rs +++ b/tests/fail/concurrency/thread_local_static_dealloc.rs @@ -1,4 +1,4 @@ -// ignore-windows: Concurrency on Windows is not supported yet. +//@ignore-windows: Concurrency on Windows is not supported yet. //! Ensure that thread-local statics get deallocated when the thread dies. diff --git a/tests/fail/concurrency/too_few_args.rs b/tests/fail/concurrency/too_few_args.rs index 23fa38d881288..5d173b3848073 100644 --- a/tests/fail/concurrency/too_few_args.rs +++ b/tests/fail/concurrency/too_few_args.rs @@ -1,4 +1,4 @@ -// ignore-windows: Concurrency on Windows is not supported yet. +//@ignore-windows: Concurrency on Windows is not supported yet. //! The thread function must have exactly one argument. diff --git a/tests/fail/concurrency/too_many_args.rs b/tests/fail/concurrency/too_many_args.rs index af5a377a04e4b..8305765a37a35 100644 --- a/tests/fail/concurrency/too_many_args.rs +++ b/tests/fail/concurrency/too_many_args.rs @@ -1,4 +1,4 @@ -// ignore-windows: Concurrency on Windows is not supported yet. +//@ignore-windows: Concurrency on Windows is not supported yet. //! The thread function must have exactly one argument. diff --git a/tests/fail/concurrency/unwind_top_of_stack.rs b/tests/fail/concurrency/unwind_top_of_stack.rs index 39f7ae8bafb99..d5dfcd0871d81 100644 --- a/tests/fail/concurrency/unwind_top_of_stack.rs +++ b/tests/fail/concurrency/unwind_top_of_stack.rs @@ -1,5 +1,5 @@ -// ignore-windows: Concurrency on Windows is not supported yet. -// compile-flags: -Zmiri-disable-abi-check +//@ignore-windows: Concurrency on Windows is not supported yet. +//@compile-flags: -Zmiri-disable-abi-check //! Unwinding past the top frame of a stack is Undefined Behavior. diff --git a/tests/fail/dangling_pointers/dangling_pointer_addr_of.rs b/tests/fail/dangling_pointers/dangling_pointer_addr_of.rs index 5de4138711716..a38a44c18f47f 100644 --- a/tests/fail/dangling_pointers/dangling_pointer_addr_of.rs +++ b/tests/fail/dangling_pointers/dangling_pointer_addr_of.rs @@ -1,5 +1,5 @@ // Make sure we find these even with many checks disabled. -// compile-flags: -Zmiri-disable-alignment-check -Zmiri-disable-stacked-borrows -Zmiri-disable-validation +//@compile-flags: -Zmiri-disable-alignment-check -Zmiri-disable-stacked-borrows -Zmiri-disable-validation use std::ptr; fn main() { diff --git a/tests/fail/dangling_pointers/dangling_pointer_deref.rs b/tests/fail/dangling_pointers/dangling_pointer_deref.rs index e088a5532581f..55b5205a8b301 100644 --- a/tests/fail/dangling_pointers/dangling_pointer_deref.rs +++ b/tests/fail/dangling_pointers/dangling_pointer_deref.rs @@ -1,5 +1,5 @@ // Make sure we find these even with many checks disabled. -// compile-flags: -Zmiri-disable-alignment-check -Zmiri-disable-stacked-borrows -Zmiri-disable-validation +//@compile-flags: -Zmiri-disable-alignment-check -Zmiri-disable-stacked-borrows -Zmiri-disable-validation fn main() { let p = { diff --git a/tests/fail/dangling_pointers/dangling_zst_deref.rs b/tests/fail/dangling_pointers/dangling_zst_deref.rs index 01e864213df79..2a09dc4b0e891 100644 --- a/tests/fail/dangling_pointers/dangling_zst_deref.rs +++ b/tests/fail/dangling_pointers/dangling_zst_deref.rs @@ -1,6 +1,6 @@ // Make sure we find these even with many checks disabled. // Some optimizations remove ZST accesses, thus masking this UB. -// compile-flags: -Zmir-opt-level=0 -Zmiri-disable-alignment-check -Zmiri-disable-stacked-borrows -Zmiri-disable-validation +//@compile-flags: -Zmir-opt-level=0 -Zmiri-disable-alignment-check -Zmiri-disable-stacked-borrows -Zmiri-disable-validation fn main() { let p = { diff --git a/tests/fail/dangling_pointers/deref-invalid-ptr.rs b/tests/fail/dangling_pointers/deref-invalid-ptr.rs index 31b52da774b0c..924021e8cb93a 100644 --- a/tests/fail/dangling_pointers/deref-invalid-ptr.rs +++ b/tests/fail/dangling_pointers/deref-invalid-ptr.rs @@ -1,5 +1,5 @@ // This should fail even without validation. -// compile-flags: -Zmiri-disable-validation -Zmiri-permissive-provenance +//@compile-flags: -Zmiri-disable-validation -Zmiri-permissive-provenance fn main() { let x = 16usize as *const u32; diff --git a/tests/fail/dangling_pointers/dyn_size.rs b/tests/fail/dangling_pointers/dyn_size.rs index 56de3970f1bb2..adb7febe5074e 100644 --- a/tests/fail/dangling_pointers/dyn_size.rs +++ b/tests/fail/dangling_pointers/dyn_size.rs @@ -1,5 +1,5 @@ // should find the bug even without these, but gets masked by optimizations -// compile-flags: -Zmiri-disable-validation -Zmiri-disable-stacked-borrows -Zmir-opt-level=0 +//@compile-flags: -Zmiri-disable-validation -Zmiri-disable-stacked-borrows -Zmir-opt-level=0 struct SliceWithHead(u8, [u8]); diff --git a/tests/fail/dangling_pointers/maybe_null_pointer_deref_zst.rs b/tests/fail/dangling_pointers/maybe_null_pointer_deref_zst.rs index 357eadf91c7f0..37fb91e28f298 100644 --- a/tests/fail/dangling_pointers/maybe_null_pointer_deref_zst.rs +++ b/tests/fail/dangling_pointers/maybe_null_pointer_deref_zst.rs @@ -1,5 +1,5 @@ // Some optimizations remove ZST accesses, thus masking this UB. -// compile-flags: -Zmir-opt-level=0 +//@compile-flags: -Zmir-opt-level=0 fn main() { // This pointer *could* be NULL so we cannot load from it, not even at ZST diff --git a/tests/fail/dangling_pointers/maybe_null_pointer_write_zst.rs b/tests/fail/dangling_pointers/maybe_null_pointer_write_zst.rs index 4a8d498aa1f52..de8034bbbac3c 100644 --- a/tests/fail/dangling_pointers/maybe_null_pointer_write_zst.rs +++ b/tests/fail/dangling_pointers/maybe_null_pointer_write_zst.rs @@ -1,5 +1,5 @@ // Some optimizations remove ZST accesses, thus masking this UB. -// compile-flags: -Zmir-opt-level=0 +//@compile-flags: -Zmir-opt-level=0 fn main() { // This pointer *could* be NULL so we cannot load from it, not even at ZST. diff --git a/tests/fail/dangling_pointers/null_pointer_deref_zst.rs b/tests/fail/dangling_pointers/null_pointer_deref_zst.rs index 21b0ce37d8dff..1f73983a81619 100644 --- a/tests/fail/dangling_pointers/null_pointer_deref_zst.rs +++ b/tests/fail/dangling_pointers/null_pointer_deref_zst.rs @@ -1,5 +1,5 @@ // Some optimizations remove ZST accesses, thus masking this UB. -// compile-flags: -Zmir-opt-level=0 +//@compile-flags: -Zmir-opt-level=0 #[allow(deref_nullptr)] fn main() { diff --git a/tests/fail/dangling_pointers/stack_temporary.rs b/tests/fail/dangling_pointers/stack_temporary.rs index cbd788bbf414e..dc446ca4b3c81 100644 --- a/tests/fail/dangling_pointers/stack_temporary.rs +++ b/tests/fail/dangling_pointers/stack_temporary.rs @@ -1,5 +1,5 @@ // This should fail even without validation, but some MIR opts mask the error -// compile-flags: -Zmiri-disable-validation -Zmir-opt-level=0 +//@compile-flags: -Zmiri-disable-validation -Zmir-opt-level=0 unsafe fn make_ref<'a>(x: *mut i32) -> &'a mut i32 { &mut *x diff --git a/tests/fail/dangling_pointers/storage_dead_dangling.rs b/tests/fail/dangling_pointers/storage_dead_dangling.rs index 64ed37d151134..10c6e7f97d2ee 100644 --- a/tests/fail/dangling_pointers/storage_dead_dangling.rs +++ b/tests/fail/dangling_pointers/storage_dead_dangling.rs @@ -1,5 +1,5 @@ // This should fail even without validation, but some MIR opts mask the error -// compile-flags: -Zmiri-disable-validation -Zmir-opt-level=0 -Zmiri-permissive-provenance +//@compile-flags: -Zmiri-disable-validation -Zmir-opt-level=0 -Zmiri-permissive-provenance static mut LEAK: usize = 0; diff --git a/tests/fail/dangling_pointers/wild_pointer_deref.rs b/tests/fail/dangling_pointers/wild_pointer_deref.rs index 9f6b370c050f4..15d71a6bcccd2 100644 --- a/tests/fail/dangling_pointers/wild_pointer_deref.rs +++ b/tests/fail/dangling_pointers/wild_pointer_deref.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-permissive-provenance +//@compile-flags: -Zmiri-permissive-provenance fn main() { let p = 44 as *const i32; diff --git a/tests/fail/data_race/alloc_read_race.rs b/tests/fail/data_race/alloc_read_race.rs index 1eac8ce0f26c6..e3c003a343a04 100644 --- a/tests/fail/data_race/alloc_read_race.rs +++ b/tests/fail/data_race/alloc_read_race.rs @@ -1,5 +1,5 @@ -// ignore-windows: Concurrency on Windows is not supported yet. -// compile-flags: -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 +//@ignore-windows: Concurrency on Windows is not supported yet. +//@compile-flags: -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 #![feature(new_uninit)] use std::mem::MaybeUninit; diff --git a/tests/fail/data_race/alloc_write_race.rs b/tests/fail/data_race/alloc_write_race.rs index e618b72a82270..4ad03ee87dda3 100644 --- a/tests/fail/data_race/alloc_write_race.rs +++ b/tests/fail/data_race/alloc_write_race.rs @@ -1,5 +1,5 @@ -// ignore-windows: Concurrency on Windows is not supported yet. -// compile-flags: -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 +//@ignore-windows: Concurrency on Windows is not supported yet. +//@compile-flags: -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 #![feature(new_uninit)] use std::ptr::null_mut; diff --git a/tests/fail/data_race/atomic_read_na_write_race1.rs b/tests/fail/data_race/atomic_read_na_write_race1.rs index 3b948eea98051..71d7a66597d18 100644 --- a/tests/fail/data_race/atomic_read_na_write_race1.rs +++ b/tests/fail/data_race/atomic_read_na_write_race1.rs @@ -1,4 +1,4 @@ -// ignore-windows: Concurrency on Windows is not supported yet. +//@ignore-windows: Concurrency on Windows is not supported yet. #![feature(core_intrinsics)] use std::intrinsics; diff --git a/tests/fail/data_race/atomic_read_na_write_race2.rs b/tests/fail/data_race/atomic_read_na_write_race2.rs index 44b4eebee8051..a490f47da7c31 100644 --- a/tests/fail/data_race/atomic_read_na_write_race2.rs +++ b/tests/fail/data_race/atomic_read_na_write_race2.rs @@ -1,4 +1,4 @@ -// ignore-windows: Concurrency on Windows is not supported yet. +//@ignore-windows: Concurrency on Windows is not supported yet. use std::sync::atomic::AtomicUsize; use std::sync::atomic::Ordering; diff --git a/tests/fail/data_race/atomic_write_na_read_race1.rs b/tests/fail/data_race/atomic_write_na_read_race1.rs index 44dc1a9084168..40066d91b1ff2 100644 --- a/tests/fail/data_race/atomic_write_na_read_race1.rs +++ b/tests/fail/data_race/atomic_write_na_read_race1.rs @@ -1,4 +1,4 @@ -// ignore-windows: Concurrency on Windows is not supported yet. +//@ignore-windows: Concurrency on Windows is not supported yet. use std::sync::atomic::AtomicUsize; use std::sync::atomic::Ordering; diff --git a/tests/fail/data_race/atomic_write_na_read_race2.rs b/tests/fail/data_race/atomic_write_na_read_race2.rs index b4b21b64fc1fb..0bfadcba3ed34 100644 --- a/tests/fail/data_race/atomic_write_na_read_race2.rs +++ b/tests/fail/data_race/atomic_write_na_read_race2.rs @@ -1,4 +1,4 @@ -// ignore-windows: Concurrency on Windows is not supported yet. +//@ignore-windows: Concurrency on Windows is not supported yet. #![feature(core_intrinsics)] use std::intrinsics::atomic_store; diff --git a/tests/fail/data_race/atomic_write_na_write_race1.rs b/tests/fail/data_race/atomic_write_na_write_race1.rs index b1a4cfb98bd13..258f5dd142efe 100644 --- a/tests/fail/data_race/atomic_write_na_write_race1.rs +++ b/tests/fail/data_race/atomic_write_na_write_race1.rs @@ -1,4 +1,4 @@ -// ignore-windows: Concurrency on Windows is not supported yet. +//@ignore-windows: Concurrency on Windows is not supported yet. #![feature(core_intrinsics)] use std::intrinsics::atomic_store; diff --git a/tests/fail/data_race/atomic_write_na_write_race2.rs b/tests/fail/data_race/atomic_write_na_write_race2.rs index dbdce8f6237ce..51068262d5889 100644 --- a/tests/fail/data_race/atomic_write_na_write_race2.rs +++ b/tests/fail/data_race/atomic_write_na_write_race2.rs @@ -1,4 +1,4 @@ -// ignore-windows: Concurrency on Windows is not supported yet. +//@ignore-windows: Concurrency on Windows is not supported yet. use std::sync::atomic::AtomicUsize; use std::sync::atomic::Ordering; diff --git a/tests/fail/data_race/dangling_thread_async_race.rs b/tests/fail/data_race/dangling_thread_async_race.rs index 65325b60f2f39..7bb20adfcd5fc 100644 --- a/tests/fail/data_race/dangling_thread_async_race.rs +++ b/tests/fail/data_race/dangling_thread_async_race.rs @@ -1,5 +1,5 @@ -// ignore-windows: Concurrency on Windows is not supported yet. -// compile-flags: -Zmiri-disable-isolation +//@ignore-windows: Concurrency on Windows is not supported yet. +//@compile-flags: -Zmiri-disable-isolation use std::mem; use std::thread::{sleep, spawn}; diff --git a/tests/fail/data_race/dangling_thread_race.rs b/tests/fail/data_race/dangling_thread_race.rs index 09e7032c93308..7e198eef6e94e 100644 --- a/tests/fail/data_race/dangling_thread_race.rs +++ b/tests/fail/data_race/dangling_thread_race.rs @@ -1,5 +1,5 @@ -// ignore-windows: Concurrency on Windows is not supported yet. -// compile-flags: -Zmiri-disable-isolation +//@ignore-windows: Concurrency on Windows is not supported yet. +//@compile-flags: -Zmiri-disable-isolation use std::mem; use std::thread::{sleep, spawn}; diff --git a/tests/fail/data_race/dealloc_read_race1.rs b/tests/fail/data_race/dealloc_read_race1.rs index ff2ac8ca522a5..634904cbfdce5 100644 --- a/tests/fail/data_race/dealloc_read_race1.rs +++ b/tests/fail/data_race/dealloc_read_race1.rs @@ -1,4 +1,4 @@ -// ignore-windows: Concurrency on Windows is not supported yet. +//@ignore-windows: Concurrency on Windows is not supported yet. use std::thread::spawn; diff --git a/tests/fail/data_race/dealloc_read_race2.rs b/tests/fail/data_race/dealloc_read_race2.rs index 4bb6444f6a626..91ec3c2bd8724 100644 --- a/tests/fail/data_race/dealloc_read_race2.rs +++ b/tests/fail/data_race/dealloc_read_race2.rs @@ -1,4 +1,4 @@ -// ignore-windows: Concurrency on Windows is not supported yet. +//@ignore-windows: Concurrency on Windows is not supported yet. use std::thread::spawn; diff --git a/tests/fail/data_race/dealloc_read_race_stack.rs b/tests/fail/data_race/dealloc_read_race_stack.rs index e079581a0d89b..a43c96a6701e6 100644 --- a/tests/fail/data_race/dealloc_read_race_stack.rs +++ b/tests/fail/data_race/dealloc_read_race_stack.rs @@ -1,5 +1,5 @@ -// ignore-windows: Concurrency on Windows is not supported yet. -// compile-flags: -Zmiri-disable-isolation -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 +//@ignore-windows: Concurrency on Windows is not supported yet. +//@compile-flags: -Zmiri-disable-isolation -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 use std::ptr::null_mut; use std::sync::atomic::{AtomicPtr, Ordering}; diff --git a/tests/fail/data_race/dealloc_write_race1.rs b/tests/fail/data_race/dealloc_write_race1.rs index 9cd0ebc642521..f95a9be172749 100644 --- a/tests/fail/data_race/dealloc_write_race1.rs +++ b/tests/fail/data_race/dealloc_write_race1.rs @@ -1,4 +1,4 @@ -// ignore-windows: Concurrency on Windows is not supported yet. +//@ignore-windows: Concurrency on Windows is not supported yet. use std::thread::spawn; diff --git a/tests/fail/data_race/dealloc_write_race2.rs b/tests/fail/data_race/dealloc_write_race2.rs index 9b1b8f0614754..922738354fb07 100644 --- a/tests/fail/data_race/dealloc_write_race2.rs +++ b/tests/fail/data_race/dealloc_write_race2.rs @@ -1,4 +1,4 @@ -// ignore-windows: Concurrency on Windows is not supported yet. +//@ignore-windows: Concurrency on Windows is not supported yet. use std::thread::spawn; diff --git a/tests/fail/data_race/dealloc_write_race_stack.rs b/tests/fail/data_race/dealloc_write_race_stack.rs index 2f12570892732..6b87cbe61cad5 100644 --- a/tests/fail/data_race/dealloc_write_race_stack.rs +++ b/tests/fail/data_race/dealloc_write_race_stack.rs @@ -1,5 +1,5 @@ -// ignore-windows: Concurrency on Windows is not supported yet. -// compile-flags: -Zmiri-disable-isolation -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 +//@ignore-windows: Concurrency on Windows is not supported yet. +//@compile-flags: -Zmiri-disable-isolation -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 use std::ptr::null_mut; use std::sync::atomic::{AtomicPtr, Ordering}; diff --git a/tests/fail/data_race/enable_after_join_to_main.rs b/tests/fail/data_race/enable_after_join_to_main.rs index 6f0735fac897c..757a41adc9328 100644 --- a/tests/fail/data_race/enable_after_join_to_main.rs +++ b/tests/fail/data_race/enable_after_join_to_main.rs @@ -1,4 +1,4 @@ -// ignore-windows: Concurrency on Windows is not supported yet. +//@ignore-windows: Concurrency on Windows is not supported yet. use std::thread::spawn; diff --git a/tests/fail/data_race/fence_after_load.rs b/tests/fail/data_race/fence_after_load.rs index 5a8c2e585f49a..7a8d66bf8f29f 100644 --- a/tests/fail/data_race/fence_after_load.rs +++ b/tests/fail/data_race/fence_after_load.rs @@ -1,6 +1,6 @@ // We want to control preemption here. -// compile-flags: -Zmiri-disable-isolation -Zmiri-preemption-rate=0 -// ignore-windows: Concurrency on Windows is not supported yet. +//@compile-flags: -Zmiri-disable-isolation -Zmiri-preemption-rate=0 +//@ignore-windows: Concurrency on Windows is not supported yet. use std::sync::atomic::{fence, AtomicUsize, Ordering}; use std::sync::Arc; use std::thread; diff --git a/tests/fail/data_race/read_write_race.rs b/tests/fail/data_race/read_write_race.rs index eeb49bb42ab7c..cffbba1a70f33 100644 --- a/tests/fail/data_race/read_write_race.rs +++ b/tests/fail/data_race/read_write_race.rs @@ -1,4 +1,4 @@ -// ignore-windows: Concurrency on Windows is not supported yet. +//@ignore-windows: Concurrency on Windows is not supported yet. use std::thread::spawn; diff --git a/tests/fail/data_race/read_write_race_stack.rs b/tests/fail/data_race/read_write_race_stack.rs index 124f12d1ecd28..3999c57bcf424 100644 --- a/tests/fail/data_race/read_write_race_stack.rs +++ b/tests/fail/data_race/read_write_race_stack.rs @@ -1,5 +1,5 @@ -// ignore-windows: Concurrency on Windows is not supported yet. -// compile-flags: -Zmiri-disable-isolation -Zmir-opt-level=0 -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 +//@ignore-windows: Concurrency on Windows is not supported yet. +//@compile-flags: -Zmiri-disable-isolation -Zmir-opt-level=0 -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 // Note: mir-opt-level set to 0 to prevent the read of stack_var in thread 1 // from being optimized away and preventing the detection of the data-race. diff --git a/tests/fail/data_race/relax_acquire_race.rs b/tests/fail/data_race/relax_acquire_race.rs index faa23a150e3fa..3038efe99efa0 100644 --- a/tests/fail/data_race/relax_acquire_race.rs +++ b/tests/fail/data_race/relax_acquire_race.rs @@ -1,5 +1,5 @@ -// ignore-windows: Concurrency on Windows is not supported yet. -// compile-flags: -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 +//@ignore-windows: Concurrency on Windows is not supported yet. +//@compile-flags: -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 use std::sync::atomic::{AtomicUsize, Ordering}; use std::thread::spawn; diff --git a/tests/fail/data_race/release_seq_race.rs b/tests/fail/data_race/release_seq_race.rs index ab6926102a2a1..ca227bf5ad29d 100644 --- a/tests/fail/data_race/release_seq_race.rs +++ b/tests/fail/data_race/release_seq_race.rs @@ -1,5 +1,5 @@ -// ignore-windows: Concurrency on Windows is not supported yet. -// compile-flags: -Zmiri-disable-isolation -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 +//@ignore-windows: Concurrency on Windows is not supported yet. +//@compile-flags: -Zmiri-disable-isolation -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 use std::sync::atomic::{AtomicUsize, Ordering}; use std::thread::{sleep, spawn}; diff --git a/tests/fail/data_race/release_seq_race_same_thread.rs b/tests/fail/data_race/release_seq_race_same_thread.rs index d3d18f0e2540d..c9b0cd7773ef7 100644 --- a/tests/fail/data_race/release_seq_race_same_thread.rs +++ b/tests/fail/data_race/release_seq_race_same_thread.rs @@ -1,5 +1,5 @@ -// ignore-windows: Concurrency on Windows is not supported yet. -// compile-flags: -Zmiri-disable-isolation -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 +//@ignore-windows: Concurrency on Windows is not supported yet. +//@compile-flags: -Zmiri-disable-isolation -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 use std::sync::atomic::{AtomicUsize, Ordering}; use std::thread::spawn; diff --git a/tests/fail/data_race/rmw_race.rs b/tests/fail/data_race/rmw_race.rs index 800b1043c00b5..ca8123177ab33 100644 --- a/tests/fail/data_race/rmw_race.rs +++ b/tests/fail/data_race/rmw_race.rs @@ -1,5 +1,5 @@ -// ignore-windows: Concurrency on Windows is not supported yet. -// compile-flags: -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 +//@ignore-windows: Concurrency on Windows is not supported yet. +//@compile-flags: -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 use std::sync::atomic::{AtomicUsize, Ordering}; use std::thread::spawn; diff --git a/tests/fail/data_race/stack_pop_race.rs b/tests/fail/data_race/stack_pop_race.rs index bae8856001428..a31c434604bb7 100644 --- a/tests/fail/data_race/stack_pop_race.rs +++ b/tests/fail/data_race/stack_pop_race.rs @@ -1,5 +1,5 @@ -// ignore-windows: Concurrency on Windows is not supported yet. -// compile-flags: -Zmiri-preemption-rate=0 +//@ignore-windows: Concurrency on Windows is not supported yet. +//@compile-flags: -Zmiri-preemption-rate=0 use std::thread; #[derive(Copy, Clone)] diff --git a/tests/fail/data_race/write_write_race.rs b/tests/fail/data_race/write_write_race.rs index 989ae31a6d281..ddd710bce08dc 100644 --- a/tests/fail/data_race/write_write_race.rs +++ b/tests/fail/data_race/write_write_race.rs @@ -1,4 +1,4 @@ -// ignore-windows: Concurrency on Windows is not supported yet. +//@ignore-windows: Concurrency on Windows is not supported yet. use std::thread::spawn; diff --git a/tests/fail/data_race/write_write_race_stack.rs b/tests/fail/data_race/write_write_race_stack.rs index 3c1eabbf251b2..96b40affaed01 100644 --- a/tests/fail/data_race/write_write_race_stack.rs +++ b/tests/fail/data_race/write_write_race_stack.rs @@ -1,5 +1,5 @@ -// ignore-windows: Concurrency on Windows is not supported yet. -// compile-flags: -Zmiri-disable-isolation -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 +//@ignore-windows: Concurrency on Windows is not supported yet. +//@compile-flags: -Zmiri-disable-isolation -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 use std::ptr::null_mut; use std::sync::atomic::{AtomicPtr, Ordering}; diff --git a/tests/fail/environ-gets-deallocated.rs b/tests/fail/environ-gets-deallocated.rs index f50a66e2c766e..34941b9449234 100644 --- a/tests/fail/environ-gets-deallocated.rs +++ b/tests/fail/environ-gets-deallocated.rs @@ -1,4 +1,4 @@ -// ignore-windows: Windows does not have a global environ list that the program can access directly +//@ignore-windows: Windows does not have a global environ list that the program can access directly #[cfg(any(target_os = "linux", target_os = "freebsd"))] fn get_environ() -> *const *const u8 { diff --git a/tests/fail/erroneous_const.rs b/tests/fail/erroneous_const.rs index 8975694f51cc3..ce1392d102b7a 100644 --- a/tests/fail/erroneous_const.rs +++ b/tests/fail/erroneous_const.rs @@ -1,7 +1,7 @@ //! Make sure we detect erroneous constants post-monomorphization even when they are unused. //! (https://github.com/rust-lang/miri/issues/1382) // Inlining changes the error location -// compile-flags: -Zmir-opt-level=0 +//@compile-flags: -Zmir-opt-level=0 #![feature(never_type)] #![warn(warnings, const_err)] diff --git a/tests/fail/fs/close_stdout.rs b/tests/fail/fs/close_stdout.rs index 4f10d5e0c990d..2737011128779 100644 --- a/tests/fail/fs/close_stdout.rs +++ b/tests/fail/fs/close_stdout.rs @@ -1,5 +1,5 @@ -// ignore-windows: No libc on Windows -// compile-flags: -Zmiri-disable-isolation +//@ignore-windows: No libc on Windows +//@compile-flags: -Zmiri-disable-isolation // FIXME: standard handles cannot be closed (https://github.com/rust-lang/rust/issues/40032) diff --git a/tests/fail/fs/isolated_stdin.rs b/tests/fail/fs/isolated_stdin.rs index 4098a104761ee..b41534c5c3a87 100644 --- a/tests/fail/fs/isolated_stdin.rs +++ b/tests/fail/fs/isolated_stdin.rs @@ -1,4 +1,4 @@ -// ignore-windows: No libc on Windows +//@ignore-windows: No libc on Windows #![feature(rustc_private)] diff --git a/tests/fail/fs/read_from_stdout.rs b/tests/fail/fs/read_from_stdout.rs index 17f1735f6aded..4862bf0a162c0 100644 --- a/tests/fail/fs/read_from_stdout.rs +++ b/tests/fail/fs/read_from_stdout.rs @@ -1,5 +1,5 @@ -// compile-flags: -Zmiri-disable-isolation -// ignore-windows: No libc on Windows +//@compile-flags: -Zmiri-disable-isolation +//@ignore-windows: No libc on Windows #![feature(rustc_private)] diff --git a/tests/fail/fs/unix_open_missing_required_mode.rs b/tests/fail/fs/unix_open_missing_required_mode.rs index bd2ae6094be18..e714d26e7835c 100644 --- a/tests/fail/fs/unix_open_missing_required_mode.rs +++ b/tests/fail/fs/unix_open_missing_required_mode.rs @@ -1,5 +1,5 @@ -// ignore-windows: No libc on Windows -// compile-flags: -Zmiri-disable-isolation +//@ignore-windows: No libc on Windows +//@compile-flags: -Zmiri-disable-isolation #![feature(rustc_private)] diff --git a/tests/fail/fs/write_to_stdin.rs b/tests/fail/fs/write_to_stdin.rs index c2754636c860c..9d55a60b64b80 100644 --- a/tests/fail/fs/write_to_stdin.rs +++ b/tests/fail/fs/write_to_stdin.rs @@ -1,4 +1,4 @@ -// ignore-windows: No libc on Windows +//@ignore-windows: No libc on Windows #![feature(rustc_private)] diff --git a/tests/fail/function_calls/exported_symbol_abi_mismatch.rs b/tests/fail/function_calls/exported_symbol_abi_mismatch.rs index c337e1f29f16f..e7372d5ec50a2 100644 --- a/tests/fail/function_calls/exported_symbol_abi_mismatch.rs +++ b/tests/fail/function_calls/exported_symbol_abi_mismatch.rs @@ -1,4 +1,4 @@ -// revisions: no_cache cache fn_ptr +//@revisions: no_cache cache fn_ptr #[no_mangle] fn foo() {} diff --git a/tests/fail/function_calls/exported_symbol_bad_unwind1.rs b/tests/fail/function_calls/exported_symbol_bad_unwind1.rs index 91b0e8fc03f22..0a5636138d80f 100644 --- a/tests/fail/function_calls/exported_symbol_bad_unwind1.rs +++ b/tests/fail/function_calls/exported_symbol_bad_unwind1.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-disable-abi-check +//@compile-flags: -Zmiri-disable-abi-check #![feature(c_unwind)] #[no_mangle] diff --git a/tests/fail/function_calls/exported_symbol_bad_unwind2.rs b/tests/fail/function_calls/exported_symbol_bad_unwind2.rs index e80a79d1028dd..861789f862e6e 100644 --- a/tests/fail/function_calls/exported_symbol_bad_unwind2.rs +++ b/tests/fail/function_calls/exported_symbol_bad_unwind2.rs @@ -1,4 +1,4 @@ -// revisions: extern_block definition both +//@revisions: extern_block definition both #![feature(rustc_attrs, c_unwind)] #[cfg_attr(any(definition, both), rustc_allocator_nounwind)] diff --git a/tests/fail/function_pointers/cast_box_int_to_fn_ptr.rs b/tests/fail/function_pointers/cast_box_int_to_fn_ptr.rs index f7640cadcbcf1..6edf88a543de9 100644 --- a/tests/fail/function_pointers/cast_box_int_to_fn_ptr.rs +++ b/tests/fail/function_pointers/cast_box_int_to_fn_ptr.rs @@ -1,5 +1,5 @@ // Validation makes this fail in the wrong place -// compile-flags: -Zmiri-disable-validation +//@compile-flags: -Zmiri-disable-validation fn main() { let b = Box::new(42); diff --git a/tests/fail/function_pointers/cast_int_to_fn_ptr.rs b/tests/fail/function_pointers/cast_int_to_fn_ptr.rs index e287533ffc742..272376307d7c1 100644 --- a/tests/fail/function_pointers/cast_int_to_fn_ptr.rs +++ b/tests/fail/function_pointers/cast_int_to_fn_ptr.rs @@ -1,5 +1,5 @@ // Validation makes this fail in the wrong place -// compile-flags: -Zmiri-disable-validation +//@compile-flags: -Zmiri-disable-validation fn main() { let g = unsafe { std::mem::transmute::(42) }; diff --git a/tests/fail/function_pointers/execute_memory.rs b/tests/fail/function_pointers/execute_memory.rs index 2e6b58a753cd9..0ca29a3594e52 100644 --- a/tests/fail/function_pointers/execute_memory.rs +++ b/tests/fail/function_pointers/execute_memory.rs @@ -1,5 +1,5 @@ // Validation makes this fail in the wrong place -// compile-flags: -Zmiri-disable-validation +//@compile-flags: -Zmiri-disable-validation #![feature(box_syntax)] diff --git a/tests/fail/function_pointers/fn_ptr_offset.rs b/tests/fail/function_pointers/fn_ptr_offset.rs index 04c54c015922c..5f269760f1100 100644 --- a/tests/fail/function_pointers/fn_ptr_offset.rs +++ b/tests/fail/function_pointers/fn_ptr_offset.rs @@ -1,5 +1,5 @@ // Validation makes this fail in the wrong place -// compile-flags: -Zmiri-disable-validation +//@compile-flags: -Zmiri-disable-validation use std::mem; diff --git a/tests/fail/generator-pinned-moved.rs b/tests/fail/generator-pinned-moved.rs index 8c8e828470043..915dcdea82e49 100644 --- a/tests/fail/generator-pinned-moved.rs +++ b/tests/fail/generator-pinned-moved.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-disable-validation +//@compile-flags: -Zmiri-disable-validation #![feature(generators, generator_trait)] use std::{ diff --git a/tests/fail/invalid_bool.rs b/tests/fail/invalid_bool.rs index c0c982b8ca21d..b2052d982ed80 100644 --- a/tests/fail/invalid_bool.rs +++ b/tests/fail/invalid_bool.rs @@ -1,6 +1,6 @@ // Validation makes this fail in the wrong place // Make sure we find these even with many checks disabled. -// compile-flags: -Zmiri-disable-alignment-check -Zmiri-disable-stacked-borrows -Zmiri-disable-validation +//@compile-flags: -Zmiri-disable-alignment-check -Zmiri-disable-stacked-borrows -Zmiri-disable-validation #![feature(bench_black_box)] fn main() { diff --git a/tests/fail/invalid_char.rs b/tests/fail/invalid_char.rs index 9d485b73f2469..8d814fd92e0c6 100644 --- a/tests/fail/invalid_char.rs +++ b/tests/fail/invalid_char.rs @@ -1,6 +1,6 @@ // Validation makes this fail in the wrong place // Make sure we find these even with many checks disabled. -// compile-flags: -Zmiri-disable-alignment-check -Zmiri-disable-stacked-borrows -Zmiri-disable-validation +//@compile-flags: -Zmiri-disable-alignment-check -Zmiri-disable-stacked-borrows -Zmiri-disable-validation fn main() { let c = 0xFFFFFFu32; diff --git a/tests/fail/invalid_int.rs b/tests/fail/invalid_int.rs index 26a85802079b0..6914c66faec38 100644 --- a/tests/fail/invalid_int.rs +++ b/tests/fail/invalid_int.rs @@ -1,6 +1,6 @@ // Validation makes this fail in the wrong place // Make sure we find these even with many checks disabled. -// compile-flags: -Zmiri-disable-alignment-check -Zmiri-disable-stacked-borrows -Zmiri-disable-validation +//@compile-flags: -Zmiri-disable-alignment-check -Zmiri-disable-stacked-borrows -Zmiri-disable-validation fn main() { let i = unsafe { std::mem::MaybeUninit::::uninit().assume_init() }; diff --git a/tests/fail/modifying_constants.rs b/tests/fail/modifying_constants.rs index 0c884142bf1d7..3c47661a4b2d4 100644 --- a/tests/fail/modifying_constants.rs +++ b/tests/fail/modifying_constants.rs @@ -1,5 +1,5 @@ // This should fail even without validation/SB -// compile-flags: -Zmiri-disable-validation -Zmiri-disable-stacked-borrows +//@compile-flags: -Zmiri-disable-validation -Zmiri-disable-stacked-borrows fn main() { let x = &1; // the `&1` is promoted to a constant, but it used to be that only the pointer is marked static, not the pointee diff --git a/tests/fail/never_say_never.rs b/tests/fail/never_say_never.rs index 7aae8a29211ed..6beaada56e9a4 100644 --- a/tests/fail/never_say_never.rs +++ b/tests/fail/never_say_never.rs @@ -1,5 +1,5 @@ // This should fail even without validation -// compile-flags: -Zmiri-disable-validation +//@compile-flags: -Zmiri-disable-validation #![feature(never_type)] #![allow(unreachable_code)] diff --git a/tests/fail/never_transmute_humans.rs b/tests/fail/never_transmute_humans.rs index 8a7d7bfcc682a..010c9d4146d81 100644 --- a/tests/fail/never_transmute_humans.rs +++ b/tests/fail/never_transmute_humans.rs @@ -1,5 +1,5 @@ // This should fail even without validation -// compile-flags: -Zmiri-disable-validation +//@compile-flags: -Zmiri-disable-validation #![feature(never_type)] diff --git a/tests/fail/never_transmute_void.rs b/tests/fail/never_transmute_void.rs index f5d0f914dac7b..d9c34aa7a5ca0 100644 --- a/tests/fail/never_transmute_void.rs +++ b/tests/fail/never_transmute_void.rs @@ -1,5 +1,5 @@ // This should fail even without validation -// compile-flags: -Zmiri-disable-validation +//@compile-flags: -Zmiri-disable-validation #![feature(never_type)] #![allow(unused, invalid_value)] diff --git a/tests/fail/panic/bad_miri_start_panic.rs b/tests/fail/panic/bad_miri_start_panic.rs index 089cd86f1b8f8..9beeccd1d2204 100644 --- a/tests/fail/panic/bad_miri_start_panic.rs +++ b/tests/fail/panic/bad_miri_start_panic.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-disable-abi-check +//@compile-flags: -Zmiri-disable-abi-check // This feature is required to trigger the error using the "C" ABI. #![feature(c_unwind)] diff --git a/tests/fail/panic/unwind_panic_abort.rs b/tests/fail/panic/unwind_panic_abort.rs index 6afcd7ae7ff1f..40dcf1bc2a3a1 100644 --- a/tests/fail/panic/unwind_panic_abort.rs +++ b/tests/fail/panic/unwind_panic_abort.rs @@ -1,4 +1,4 @@ -// compile-flags: -Cpanic=abort +//@compile-flags: -Cpanic=abort //! Unwinding despite `-C panic=abort` is an error. diff --git a/tests/fail/pointer_partial_overwrite.rs b/tests/fail/pointer_partial_overwrite.rs index 1bbb33aa2bbd7..95af3569f35b3 100644 --- a/tests/fail/pointer_partial_overwrite.rs +++ b/tests/fail/pointer_partial_overwrite.rs @@ -1,5 +1,5 @@ // Make sure we find these even with many checks disabled. -// compile-flags: -Zmiri-disable-alignment-check -Zmiri-disable-stacked-borrows -Zmiri-disable-validation +//@compile-flags: -Zmiri-disable-alignment-check -Zmiri-disable-stacked-borrows -Zmiri-disable-validation // Test what happens when we overwrite parts of a pointer. // Also see . diff --git a/tests/fail/provenance/provenance_transmute.rs b/tests/fail/provenance/provenance_transmute.rs index 28e6ba6230803..90208c88d6946 100644 --- a/tests/fail/provenance/provenance_transmute.rs +++ b/tests/fail/provenance/provenance_transmute.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-permissive-provenance +//@compile-flags: -Zmiri-permissive-provenance #![feature(strict_provenance)] use std::mem; diff --git a/tests/fail/provenance/ptr_int_unexposed.rs b/tests/fail/provenance/ptr_int_unexposed.rs index ad29d38dc3f7a..5522aa33c7410 100644 --- a/tests/fail/provenance/ptr_int_unexposed.rs +++ b/tests/fail/provenance/ptr_int_unexposed.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-permissive-provenance +//@compile-flags: -Zmiri-permissive-provenance #![feature(strict_provenance)] fn main() { diff --git a/tests/fail/provenance/strict_provenance_cast.rs b/tests/fail/provenance/strict_provenance_cast.rs index 968c4dfded37a..bca7ea90a31d0 100644 --- a/tests/fail/provenance/strict_provenance_cast.rs +++ b/tests/fail/provenance/strict_provenance_cast.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-strict-provenance +//@compile-flags: -Zmiri-strict-provenance fn main() { let addr = &0 as *const i32 as usize; diff --git a/tests/fail/rc_as_ptr.rs b/tests/fail/rc_as_ptr.rs index 049330ef363c6..9aafa2628425a 100644 --- a/tests/fail/rc_as_ptr.rs +++ b/tests/fail/rc_as_ptr.rs @@ -1,5 +1,5 @@ // This should fail even without validation -// compile-flags: -Zmiri-disable-validation +//@compile-flags: -Zmiri-disable-validation use std::ptr; use std::rc::{Rc, Weak}; diff --git a/tests/fail/shim_arg_size.rs b/tests/fail/shim_arg_size.rs index 37557de0a5e4b..d1ffdf8cddb42 100644 --- a/tests/fail/shim_arg_size.rs +++ b/tests/fail/shim_arg_size.rs @@ -1,4 +1,4 @@ -// stderr-per-bitwidth +//@stderr-per-bitwidth fn main() { extern "C" { diff --git a/tests/fail/stacked_borrows/exposed_only_ro.rs b/tests/fail/stacked_borrows/exposed_only_ro.rs index 9b4234499df04..f2fdc213b1430 100644 --- a/tests/fail/stacked_borrows/exposed_only_ro.rs +++ b/tests/fail/stacked_borrows/exposed_only_ro.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-permissive-provenance +//@compile-flags: -Zmiri-permissive-provenance #![feature(strict_provenance)] // If we have only exposed read-only pointers, doing a write through a wildcard ptr should fail. diff --git a/tests/fail/stacked_borrows/illegal_read5.rs b/tests/fail/stacked_borrows/illegal_read5.rs index 71af84e5b5f52..8f86a4f0a6b58 100644 --- a/tests/fail/stacked_borrows/illegal_read5.rs +++ b/tests/fail/stacked_borrows/illegal_read5.rs @@ -1,6 +1,6 @@ // We *can* have aliasing &RefCell and &mut T, but we cannot read through the former. // Else we couldn't optimize based on the assumption that `xref` below is truly unique. -// normalize-stderr-test: "0x[0-9a-fA-F]+" -> "$$HEX" +//@normalize-stderr-test: "0x[0-9a-fA-F]+" -> "$$HEX" use std::cell::RefCell; use std::{mem, ptr}; diff --git a/tests/fail/stacked_borrows/illegal_read_despite_exposed1.rs b/tests/fail/stacked_borrows/illegal_read_despite_exposed1.rs index 61a5e05d34cd3..d779d4e446571 100644 --- a/tests/fail/stacked_borrows/illegal_read_despite_exposed1.rs +++ b/tests/fail/stacked_borrows/illegal_read_despite_exposed1.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-permissive-provenance +//@compile-flags: -Zmiri-permissive-provenance fn main() { unsafe { diff --git a/tests/fail/stacked_borrows/illegal_read_despite_exposed2.rs b/tests/fail/stacked_borrows/illegal_read_despite_exposed2.rs index 19d0784591e49..20b44e9e027b4 100644 --- a/tests/fail/stacked_borrows/illegal_read_despite_exposed2.rs +++ b/tests/fail/stacked_borrows/illegal_read_despite_exposed2.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-permissive-provenance +//@compile-flags: -Zmiri-permissive-provenance fn main() { unsafe { diff --git a/tests/fail/stacked_borrows/illegal_write_despite_exposed1.rs b/tests/fail/stacked_borrows/illegal_write_despite_exposed1.rs index b50399b9df521..f14fcb14793ce 100644 --- a/tests/fail/stacked_borrows/illegal_write_despite_exposed1.rs +++ b/tests/fail/stacked_borrows/illegal_write_despite_exposed1.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-permissive-provenance +//@compile-flags: -Zmiri-permissive-provenance fn main() { unsafe { diff --git a/tests/fail/stacked_borrows/load_invalid_mut.rs b/tests/fail/stacked_borrows/load_invalid_mut.rs index c2c4ce6726dfb..f0ae77f861012 100644 --- a/tests/fail/stacked_borrows/load_invalid_mut.rs +++ b/tests/fail/stacked_borrows/load_invalid_mut.rs @@ -1,5 +1,5 @@ // Make sure we catch this even without validation -// compile-flags: -Zmiri-disable-validation +//@compile-flags: -Zmiri-disable-validation // Make sure that we cannot load from memory a `&mut` that got already invalidated. fn main() { diff --git a/tests/fail/stacked_borrows/load_invalid_shr.rs b/tests/fail/stacked_borrows/load_invalid_shr.rs index 7d681f649a107..36ffef656e7f3 100644 --- a/tests/fail/stacked_borrows/load_invalid_shr.rs +++ b/tests/fail/stacked_borrows/load_invalid_shr.rs @@ -1,5 +1,5 @@ // Make sure we catch this even without validation -// compile-flags: -Zmiri-disable-validation +//@compile-flags: -Zmiri-disable-validation // Make sure that we cannot load from memory a `&` that got already invalidated. fn main() { diff --git a/tests/fail/stacked_borrows/shared_rw_borrows_are_weak2.rs b/tests/fail/stacked_borrows/shared_rw_borrows_are_weak2.rs index 07163456cebe7..2fc05c2bf4cc7 100644 --- a/tests/fail/stacked_borrows/shared_rw_borrows_are_weak2.rs +++ b/tests/fail/stacked_borrows/shared_rw_borrows_are_weak2.rs @@ -1,7 +1,7 @@ // We want to test that granting a SharedReadWrite will be added // *below* an already granted SharedReadWrite -- so writing to // the SharedReadWrite will invalidate the SharedReadWrite. -// normalize-stderr-test: "0x[0-9a-fA-F]+" -> "$$HEX" +//@normalize-stderr-test: "0x[0-9a-fA-F]+" -> "$$HEX" use std::cell::RefCell; use std::mem; diff --git a/tests/fail/stacked_borrows/unescaped_local.rs b/tests/fail/stacked_borrows/unescaped_local.rs index c994f6c3818a9..e6cd8f09b1ad9 100644 --- a/tests/fail/stacked_borrows/unescaped_local.rs +++ b/tests/fail/stacked_borrows/unescaped_local.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-permissive-provenance +//@compile-flags: -Zmiri-permissive-provenance // Make sure we cannot use raw ptrs to access a local that // we took the direct address of. diff --git a/tests/fail/stacked_borrows/zst_slice.rs b/tests/fail/stacked_borrows/zst_slice.rs index 336b1041df091..3e27f514bc888 100644 --- a/tests/fail/stacked_borrows/zst_slice.rs +++ b/tests/fail/stacked_borrows/zst_slice.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-strict-provenance +//@compile-flags: -Zmiri-strict-provenance //@error-pattern: does not exist in the borrow stack fn main() { diff --git a/tests/fail/static_memory_modification1.rs b/tests/fail/static_memory_modification1.rs index 6284fec1601ad..38e8af4c4f1a5 100644 --- a/tests/fail/static_memory_modification1.rs +++ b/tests/fail/static_memory_modification1.rs @@ -1,5 +1,5 @@ // Stacked Borrows detects that we are casting & to &mut and so it changes why we fail -// compile-flags: -Zmiri-disable-stacked-borrows +//@compile-flags: -Zmiri-disable-stacked-borrows static X: usize = 5; diff --git a/tests/fail/static_memory_modification2.rs b/tests/fail/static_memory_modification2.rs index 558070d8a7917..2e9d123c6d394 100644 --- a/tests/fail/static_memory_modification2.rs +++ b/tests/fail/static_memory_modification2.rs @@ -1,5 +1,5 @@ // Stacked Borrows detects that we are casting & to &mut and so it changes why we fail -// compile-flags: -Zmiri-disable-stacked-borrows +//@compile-flags: -Zmiri-disable-stacked-borrows use std::mem::transmute; diff --git a/tests/fail/static_memory_modification3.rs b/tests/fail/static_memory_modification3.rs index 93df1c5945344..34ccd13c429d8 100644 --- a/tests/fail/static_memory_modification3.rs +++ b/tests/fail/static_memory_modification3.rs @@ -1,5 +1,5 @@ // Stacked Borrows detects that we are casting & to &mut and so it changes why we fail -// compile-flags: -Zmiri-disable-stacked-borrows +//@compile-flags: -Zmiri-disable-stacked-borrows use std::mem::transmute; diff --git a/tests/fail/sync/libc_pthread_cond_double_destroy.rs b/tests/fail/sync/libc_pthread_cond_double_destroy.rs index 18be75b308cf0..d358b3d4f631f 100644 --- a/tests/fail/sync/libc_pthread_cond_double_destroy.rs +++ b/tests/fail/sync/libc_pthread_cond_double_destroy.rs @@ -1,4 +1,4 @@ -// ignore-windows: No libc on Windows +//@ignore-windows: No libc on Windows #![feature(rustc_private)] /// Test that destroying a pthread_cond twice fails, even without a check for number validity diff --git a/tests/fail/sync/libc_pthread_condattr_double_destroy.rs b/tests/fail/sync/libc_pthread_condattr_double_destroy.rs index 1543a5841ad28..bf6b038a212f1 100644 --- a/tests/fail/sync/libc_pthread_condattr_double_destroy.rs +++ b/tests/fail/sync/libc_pthread_condattr_double_destroy.rs @@ -1,4 +1,4 @@ -// ignore-windows: No libc on Windows +//@ignore-windows: No libc on Windows #![feature(rustc_private)] /// Test that destroying a pthread_condattr twice fails, even without a check for number validity diff --git a/tests/fail/sync/libc_pthread_mutex_NULL_deadlock.rs b/tests/fail/sync/libc_pthread_mutex_NULL_deadlock.rs index 3a737b2e3e155..22dd656023b73 100644 --- a/tests/fail/sync/libc_pthread_mutex_NULL_deadlock.rs +++ b/tests/fail/sync/libc_pthread_mutex_NULL_deadlock.rs @@ -1,4 +1,4 @@ -// ignore-windows: No libc on Windows +//@ignore-windows: No libc on Windows // // Check that if we pass NULL attribute, then we get the default mutex type. diff --git a/tests/fail/sync/libc_pthread_mutex_deadlock.rs b/tests/fail/sync/libc_pthread_mutex_deadlock.rs index 5d04635a36c88..597d7721b12d2 100644 --- a/tests/fail/sync/libc_pthread_mutex_deadlock.rs +++ b/tests/fail/sync/libc_pthread_mutex_deadlock.rs @@ -1,4 +1,4 @@ -// ignore-windows: No libc on Windows +//@ignore-windows: No libc on Windows #![feature(rustc_private)] diff --git a/tests/fail/sync/libc_pthread_mutex_default_deadlock.rs b/tests/fail/sync/libc_pthread_mutex_default_deadlock.rs index 0f6f570d70b02..e34dfe5e367e1 100644 --- a/tests/fail/sync/libc_pthread_mutex_default_deadlock.rs +++ b/tests/fail/sync/libc_pthread_mutex_default_deadlock.rs @@ -1,4 +1,4 @@ -// ignore-windows: No libc on Windows +//@ignore-windows: No libc on Windows // // Check that if we do not set the mutex type, it is the default. diff --git a/tests/fail/sync/libc_pthread_mutex_destroy_locked.rs b/tests/fail/sync/libc_pthread_mutex_destroy_locked.rs index 85a37db341fab..ada3d311134d3 100644 --- a/tests/fail/sync/libc_pthread_mutex_destroy_locked.rs +++ b/tests/fail/sync/libc_pthread_mutex_destroy_locked.rs @@ -1,4 +1,4 @@ -// ignore-windows: No libc on Windows +//@ignore-windows: No libc on Windows #![feature(rustc_private)] diff --git a/tests/fail/sync/libc_pthread_mutex_double_destroy.rs b/tests/fail/sync/libc_pthread_mutex_double_destroy.rs index 3710810cd2c33..4cf006437b391 100644 --- a/tests/fail/sync/libc_pthread_mutex_double_destroy.rs +++ b/tests/fail/sync/libc_pthread_mutex_double_destroy.rs @@ -1,4 +1,4 @@ -// ignore-windows: No libc on Windows +//@ignore-windows: No libc on Windows #![feature(rustc_private)] /// Test that destroying a pthread_mutex twice fails, even without a check for number validity diff --git a/tests/fail/sync/libc_pthread_mutex_normal_deadlock.rs b/tests/fail/sync/libc_pthread_mutex_normal_deadlock.rs index 7e29a41920ea6..8ecad494cfee6 100644 --- a/tests/fail/sync/libc_pthread_mutex_normal_deadlock.rs +++ b/tests/fail/sync/libc_pthread_mutex_normal_deadlock.rs @@ -1,4 +1,4 @@ -// ignore-windows: No libc on Windows +//@ignore-windows: No libc on Windows #![feature(rustc_private)] diff --git a/tests/fail/sync/libc_pthread_mutex_normal_unlock_unlocked.rs b/tests/fail/sync/libc_pthread_mutex_normal_unlock_unlocked.rs index 1f1a2ef34b72e..0109907a11862 100644 --- a/tests/fail/sync/libc_pthread_mutex_normal_unlock_unlocked.rs +++ b/tests/fail/sync/libc_pthread_mutex_normal_unlock_unlocked.rs @@ -1,4 +1,4 @@ -// ignore-windows: No libc on Windows +//@ignore-windows: No libc on Windows #![feature(rustc_private)] diff --git a/tests/fail/sync/libc_pthread_mutex_wrong_owner.rs b/tests/fail/sync/libc_pthread_mutex_wrong_owner.rs index d69929d4ed465..d91245104b0e1 100644 --- a/tests/fail/sync/libc_pthread_mutex_wrong_owner.rs +++ b/tests/fail/sync/libc_pthread_mutex_wrong_owner.rs @@ -1,4 +1,4 @@ -// ignore-windows: No libc on Windows +//@ignore-windows: No libc on Windows #![feature(rustc_private)] diff --git a/tests/fail/sync/libc_pthread_mutexattr_double_destroy.rs b/tests/fail/sync/libc_pthread_mutexattr_double_destroy.rs index c232780ee2ea3..ffa786b65893f 100644 --- a/tests/fail/sync/libc_pthread_mutexattr_double_destroy.rs +++ b/tests/fail/sync/libc_pthread_mutexattr_double_destroy.rs @@ -1,4 +1,4 @@ -// ignore-windows: No libc on Windows +//@ignore-windows: No libc on Windows #![feature(rustc_private)] /// Test that destroying a pthread_mutexattr twice fails, even without a check for number validity diff --git a/tests/fail/sync/libc_pthread_rwlock_destroy_read_locked.rs b/tests/fail/sync/libc_pthread_rwlock_destroy_read_locked.rs index 8750a7388fca2..6a9f548d1a301 100644 --- a/tests/fail/sync/libc_pthread_rwlock_destroy_read_locked.rs +++ b/tests/fail/sync/libc_pthread_rwlock_destroy_read_locked.rs @@ -1,4 +1,4 @@ -// ignore-windows: No libc on Windows +//@ignore-windows: No libc on Windows #![feature(rustc_private)] diff --git a/tests/fail/sync/libc_pthread_rwlock_destroy_write_locked.rs b/tests/fail/sync/libc_pthread_rwlock_destroy_write_locked.rs index aecccfa503103..5f5f16d2cf0ee 100644 --- a/tests/fail/sync/libc_pthread_rwlock_destroy_write_locked.rs +++ b/tests/fail/sync/libc_pthread_rwlock_destroy_write_locked.rs @@ -1,4 +1,4 @@ -// ignore-windows: No libc on Windows +//@ignore-windows: No libc on Windows #![feature(rustc_private)] diff --git a/tests/fail/sync/libc_pthread_rwlock_double_destroy.rs b/tests/fail/sync/libc_pthread_rwlock_double_destroy.rs index 055bb1af489f4..1ba89fb22cf39 100644 --- a/tests/fail/sync/libc_pthread_rwlock_double_destroy.rs +++ b/tests/fail/sync/libc_pthread_rwlock_double_destroy.rs @@ -1,4 +1,4 @@ -// ignore-windows: No libc on Windows +//@ignore-windows: No libc on Windows #![feature(rustc_private)] /// Test that destroying a pthread_rwlock twice fails, even without a check for number validity diff --git a/tests/fail/sync/libc_pthread_rwlock_read_write_deadlock_single_thread.rs b/tests/fail/sync/libc_pthread_rwlock_read_write_deadlock_single_thread.rs index dd4707d60e4ca..9c8d22310cab9 100644 --- a/tests/fail/sync/libc_pthread_rwlock_read_write_deadlock_single_thread.rs +++ b/tests/fail/sync/libc_pthread_rwlock_read_write_deadlock_single_thread.rs @@ -1,4 +1,4 @@ -// ignore-windows: No libc on Windows +//@ignore-windows: No libc on Windows #![feature(rustc_private)] diff --git a/tests/fail/sync/libc_pthread_rwlock_read_wrong_owner.rs b/tests/fail/sync/libc_pthread_rwlock_read_wrong_owner.rs index a73a8496a3296..361cc7cdd850d 100644 --- a/tests/fail/sync/libc_pthread_rwlock_read_wrong_owner.rs +++ b/tests/fail/sync/libc_pthread_rwlock_read_wrong_owner.rs @@ -1,4 +1,4 @@ -// ignore-windows: No libc on Windows +//@ignore-windows: No libc on Windows #![feature(rustc_private)] diff --git a/tests/fail/sync/libc_pthread_rwlock_unlock_unlocked.rs b/tests/fail/sync/libc_pthread_rwlock_unlock_unlocked.rs index 8b3de53828df6..7918a9665a033 100644 --- a/tests/fail/sync/libc_pthread_rwlock_unlock_unlocked.rs +++ b/tests/fail/sync/libc_pthread_rwlock_unlock_unlocked.rs @@ -1,4 +1,4 @@ -// ignore-windows: No libc on Windows +//@ignore-windows: No libc on Windows #![feature(rustc_private)] diff --git a/tests/fail/sync/libc_pthread_rwlock_write_read_deadlock.rs b/tests/fail/sync/libc_pthread_rwlock_write_read_deadlock.rs index 19dce431c8b1c..3158b944a7f77 100644 --- a/tests/fail/sync/libc_pthread_rwlock_write_read_deadlock.rs +++ b/tests/fail/sync/libc_pthread_rwlock_write_read_deadlock.rs @@ -1,4 +1,4 @@ -// ignore-windows: No libc on Windows +//@ignore-windows: No libc on Windows #![feature(rustc_private)] diff --git a/tests/fail/sync/libc_pthread_rwlock_write_read_deadlock_single_thread.rs b/tests/fail/sync/libc_pthread_rwlock_write_read_deadlock_single_thread.rs index 1b460e7174d28..c6b468eb89b11 100644 --- a/tests/fail/sync/libc_pthread_rwlock_write_read_deadlock_single_thread.rs +++ b/tests/fail/sync/libc_pthread_rwlock_write_read_deadlock_single_thread.rs @@ -1,4 +1,4 @@ -// ignore-windows: No libc on Windows +//@ignore-windows: No libc on Windows #![feature(rustc_private)] diff --git a/tests/fail/sync/libc_pthread_rwlock_write_write_deadlock.rs b/tests/fail/sync/libc_pthread_rwlock_write_write_deadlock.rs index 098c1c2fe26cc..91adaf85499fa 100644 --- a/tests/fail/sync/libc_pthread_rwlock_write_write_deadlock.rs +++ b/tests/fail/sync/libc_pthread_rwlock_write_write_deadlock.rs @@ -1,4 +1,4 @@ -// ignore-windows: No libc on Windows +//@ignore-windows: No libc on Windows #![feature(rustc_private)] diff --git a/tests/fail/sync/libc_pthread_rwlock_write_write_deadlock_single_thread.rs b/tests/fail/sync/libc_pthread_rwlock_write_write_deadlock_single_thread.rs index cc327ec46bc29..13a7ceefc7bbe 100644 --- a/tests/fail/sync/libc_pthread_rwlock_write_write_deadlock_single_thread.rs +++ b/tests/fail/sync/libc_pthread_rwlock_write_write_deadlock_single_thread.rs @@ -1,4 +1,4 @@ -// ignore-windows: No libc on Windows +//@ignore-windows: No libc on Windows #![feature(rustc_private)] diff --git a/tests/fail/sync/libc_pthread_rwlock_write_wrong_owner.rs b/tests/fail/sync/libc_pthread_rwlock_write_wrong_owner.rs index 663dedb6f6fca..a205bbcb6b55b 100644 --- a/tests/fail/sync/libc_pthread_rwlock_write_wrong_owner.rs +++ b/tests/fail/sync/libc_pthread_rwlock_write_wrong_owner.rs @@ -1,4 +1,4 @@ -// ignore-windows: No libc on Windows +//@ignore-windows: No libc on Windows #![feature(rustc_private)] diff --git a/tests/fail/type-too-large.rs b/tests/fail/type-too-large.rs index 08f7a49b0255c..932964ebdd7b9 100644 --- a/tests/fail/type-too-large.rs +++ b/tests/fail/type-too-large.rs @@ -1,4 +1,4 @@ -// ignore-32bit +//@ignore-32bit fn main() { let _fat: [u8; (1 << 61) + (1 << 31)]; diff --git a/tests/fail/unaligned_pointers/alignment.rs b/tests/fail/unaligned_pointers/alignment.rs index abee75ec71b17..438e74e5b8d52 100644 --- a/tests/fail/unaligned_pointers/alignment.rs +++ b/tests/fail/unaligned_pointers/alignment.rs @@ -1,4 +1,4 @@ -// normalize-stderr-test: "\| +\^+" -> "| ^" +//@normalize-stderr-test: "\| +\^+" -> "| ^" fn main() { // No retry needed, this fails reliably. diff --git a/tests/fail/unaligned_pointers/atomic_unaligned.rs b/tests/fail/unaligned_pointers/atomic_unaligned.rs index 74dd0b415c930..68b0efdbfeb44 100644 --- a/tests/fail/unaligned_pointers/atomic_unaligned.rs +++ b/tests/fail/unaligned_pointers/atomic_unaligned.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-symbolic-alignment-check +//@compile-flags: -Zmiri-symbolic-alignment-check #![feature(core_intrinsics)] fn main() { diff --git a/tests/fail/unaligned_pointers/dyn_alignment.rs b/tests/fail/unaligned_pointers/dyn_alignment.rs index 730dd87cbb10f..fe9c395230290 100644 --- a/tests/fail/unaligned_pointers/dyn_alignment.rs +++ b/tests/fail/unaligned_pointers/dyn_alignment.rs @@ -1,5 +1,5 @@ // should find the bug even without validation and stacked borrows, but gets masked by optimizations -// compile-flags: -Zmiri-disable-validation -Zmiri-disable-stacked-borrows -Zmir-opt-level=0 +//@compile-flags: -Zmiri-disable-validation -Zmiri-disable-stacked-borrows -Zmir-opt-level=0 #[repr(align(256))] #[derive(Debug)] diff --git a/tests/fail/unaligned_pointers/intptrcast_alignment_check.rs b/tests/fail/unaligned_pointers/intptrcast_alignment_check.rs index dea9335ab751a..172461424ec04 100644 --- a/tests/fail/unaligned_pointers/intptrcast_alignment_check.rs +++ b/tests/fail/unaligned_pointers/intptrcast_alignment_check.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-symbolic-alignment-check -Zmiri-permissive-provenance +//@compile-flags: -Zmiri-symbolic-alignment-check -Zmiri-permissive-provenance // With the symbolic alignment check, even with intptrcast and without // validation, we want to be *sure* to catch bugs that arise from pointers being // insufficiently aligned. The only way to achieve that is not not let programs diff --git a/tests/fail/unaligned_pointers/reference_to_packed.rs b/tests/fail/unaligned_pointers/reference_to_packed.rs index c42f0e27aeada..b4659805745aa 100644 --- a/tests/fail/unaligned_pointers/reference_to_packed.rs +++ b/tests/fail/unaligned_pointers/reference_to_packed.rs @@ -1,5 +1,5 @@ // This should fail even without validation/SB -// compile-flags: -Zmiri-disable-validation -Zmiri-disable-stacked-borrows +//@compile-flags: -Zmiri-disable-validation -Zmiri-disable-stacked-borrows #![allow(dead_code, unused_variables, unaligned_references)] diff --git a/tests/fail/unaligned_pointers/unaligned_ptr1.rs b/tests/fail/unaligned_pointers/unaligned_ptr1.rs index 7d192e5d3928b..a3b483281139d 100644 --- a/tests/fail/unaligned_pointers/unaligned_ptr1.rs +++ b/tests/fail/unaligned_pointers/unaligned_ptr1.rs @@ -1,5 +1,5 @@ // This should fail even without validation or Stacked Borrows. -// compile-flags: -Zmiri-disable-validation -Zmiri-disable-stacked-borrows +//@compile-flags: -Zmiri-disable-validation -Zmiri-disable-stacked-borrows fn main() { // Try many times as this might work by chance. diff --git a/tests/fail/unaligned_pointers/unaligned_ptr2.rs b/tests/fail/unaligned_pointers/unaligned_ptr2.rs index 49612e2b8a096..88fcd30278d72 100644 --- a/tests/fail/unaligned_pointers/unaligned_ptr2.rs +++ b/tests/fail/unaligned_pointers/unaligned_ptr2.rs @@ -1,5 +1,5 @@ // This should fail even without validation or Stacked Borrows. -// compile-flags: -Zmiri-disable-validation -Zmiri-disable-stacked-borrows +//@compile-flags: -Zmiri-disable-validation -Zmiri-disable-stacked-borrows fn main() { // No retry needed, this fails reliably. diff --git a/tests/fail/unaligned_pointers/unaligned_ptr3.rs b/tests/fail/unaligned_pointers/unaligned_ptr3.rs index 748a31681a780..3a4b1497ae6bb 100644 --- a/tests/fail/unaligned_pointers/unaligned_ptr3.rs +++ b/tests/fail/unaligned_pointers/unaligned_ptr3.rs @@ -1,5 +1,5 @@ // This should fail even without validation or Stacked Borrows. -// compile-flags: -Zmiri-disable-validation -Zmiri-disable-stacked-borrows +//@compile-flags: -Zmiri-disable-validation -Zmiri-disable-stacked-borrows fn main() { // Try many times as this might work by chance. diff --git a/tests/fail/unaligned_pointers/unaligned_ptr4.rs b/tests/fail/unaligned_pointers/unaligned_ptr4.rs index d01cabfa31cc8..659fbf1470ce1 100644 --- a/tests/fail/unaligned_pointers/unaligned_ptr4.rs +++ b/tests/fail/unaligned_pointers/unaligned_ptr4.rs @@ -1,5 +1,5 @@ // This should fail even without validation or Stacked Borrows. -// compile-flags: -Zmiri-disable-validation -Zmiri-disable-stacked-borrows +//@compile-flags: -Zmiri-disable-validation -Zmiri-disable-stacked-borrows fn main() { // Make sure we notice when a u16 is loaded at offset 1 into a u8 allocation. diff --git a/tests/fail/unaligned_pointers/unaligned_ptr_addr_of.rs b/tests/fail/unaligned_pointers/unaligned_ptr_addr_of.rs index dff92d56d70e8..28a58556eb395 100644 --- a/tests/fail/unaligned_pointers/unaligned_ptr_addr_of.rs +++ b/tests/fail/unaligned_pointers/unaligned_ptr_addr_of.rs @@ -1,5 +1,5 @@ // This should fail even without validation or Stacked Borrows. -// compile-flags: -Zmiri-disable-validation -Zmiri-disable-stacked-borrows +//@compile-flags: -Zmiri-disable-validation -Zmiri-disable-stacked-borrows use std::ptr; fn main() { diff --git a/tests/fail/unaligned_pointers/unaligned_ptr_zst.rs b/tests/fail/unaligned_pointers/unaligned_ptr_zst.rs index 8252ea83c870c..26c315d34bf50 100644 --- a/tests/fail/unaligned_pointers/unaligned_ptr_zst.rs +++ b/tests/fail/unaligned_pointers/unaligned_ptr_zst.rs @@ -1,6 +1,6 @@ // This should fail even without validation // Some optimizations remove ZST accesses, thus masking this UB. -// compile-flags: -Zmir-opt-level=0 -Zmiri-disable-validation +//@compile-flags: -Zmir-opt-level=0 -Zmiri-disable-validation fn main() { // Try many times as this might work by chance. diff --git a/tests/fail/uninit_byte_read.rs b/tests/fail/uninit_byte_read.rs index 683088e78bffb..e08d34d138561 100644 --- a/tests/fail/uninit_byte_read.rs +++ b/tests/fail/uninit_byte_read.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-disable-stacked-borrows +//@compile-flags: -Zmiri-disable-stacked-borrows fn main() { let v: Vec = Vec::with_capacity(10); let undef = unsafe { *v.get_unchecked(5) }; //~ ERROR uninitialized diff --git a/tests/fail/unsupported_signal.rs b/tests/fail/unsupported_signal.rs index 3e76d1c3f3847..9cdf3cfdc664f 100644 --- a/tests/fail/unsupported_signal.rs +++ b/tests/fail/unsupported_signal.rs @@ -1,6 +1,6 @@ //! `signal()` is special on Linux and macOS that it's only supported within libstd. //! The implementation is not complete enough to permit user code to call it. -// ignore-windows: No libc on Windows +//@ignore-windows: No libc on Windows #![feature(rustc_private)] extern crate libc; diff --git a/tests/fail/validity/cast_fn_ptr1.rs b/tests/fail/validity/cast_fn_ptr1.rs index eb5774fe79956..1bd889e899941 100644 --- a/tests/fail/validity/cast_fn_ptr1.rs +++ b/tests/fail/validity/cast_fn_ptr1.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-permissive-provenance +//@compile-flags: -Zmiri-permissive-provenance fn main() { // Cast a function pointer such that on a call, the argument gets transmuted diff --git a/tests/fail/validity/cast_fn_ptr2.rs b/tests/fail/validity/cast_fn_ptr2.rs index 1cf4ca7d19d8e..7e7ad4710f5c3 100644 --- a/tests/fail/validity/cast_fn_ptr2.rs +++ b/tests/fail/validity/cast_fn_ptr2.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-permissive-provenance +//@compile-flags: -Zmiri-permissive-provenance fn main() { // Cast a function pointer such that when returning, the return value gets transmuted diff --git a/tests/fail/validity/dangling_ref1.rs b/tests/fail/validity/dangling_ref1.rs index 78425cde4a8aa..cc94cc6ca0edb 100644 --- a/tests/fail/validity/dangling_ref1.rs +++ b/tests/fail/validity/dangling_ref1.rs @@ -1,5 +1,5 @@ // Make sure we catch this even without Stacked Borrows -// compile-flags: -Zmiri-disable-stacked-borrows +//@compile-flags: -Zmiri-disable-stacked-borrows use std::mem; fn main() { diff --git a/tests/fail/validity/dangling_ref2.rs b/tests/fail/validity/dangling_ref2.rs index 7aff1a49785cc..eba026fdda86a 100644 --- a/tests/fail/validity/dangling_ref2.rs +++ b/tests/fail/validity/dangling_ref2.rs @@ -1,5 +1,5 @@ // Make sure we catch this even without Stacked Borrows -// compile-flags: -Zmiri-disable-stacked-borrows +//@compile-flags: -Zmiri-disable-stacked-borrows use std::mem; fn main() { diff --git a/tests/fail/validity/dangling_ref3.rs b/tests/fail/validity/dangling_ref3.rs index 495a266a85dc6..8decc845ecb45 100644 --- a/tests/fail/validity/dangling_ref3.rs +++ b/tests/fail/validity/dangling_ref3.rs @@ -1,5 +1,5 @@ // Make sure we catch this even without Stacked Borrows -// compile-flags: -Zmiri-disable-stacked-borrows +//@compile-flags: -Zmiri-disable-stacked-borrows use std::mem; fn dangling() -> *const u8 { diff --git a/tests/fail/validity/invalid_enum_tag_256variants_uninit.rs b/tests/fail/validity/invalid_enum_tag_256variants_uninit.rs index 7573a64d0eba8..10e30cf85fe62 100644 --- a/tests/fail/validity/invalid_enum_tag_256variants_uninit.rs +++ b/tests/fail/validity/invalid_enum_tag_256variants_uninit.rs @@ -1,5 +1,5 @@ // Even when uninit numbers are allowed, this enum is not. -// compile-flags: -Zmiri-allow-uninit-numbers +//@compile-flags: -Zmiri-allow-uninit-numbers #![allow(unused, deprecated, invalid_value)] #[derive(Copy, Clone)] diff --git a/tests/fail/validity/nonzero.rs b/tests/fail/validity/nonzero.rs index 8ff19a2b43865..6344bb61ae25e 100644 --- a/tests/fail/validity/nonzero.rs +++ b/tests/fail/validity/nonzero.rs @@ -1,5 +1,5 @@ // gets masked by optimizations -// compile-flags: -Zmir-opt-level=0 +//@compile-flags: -Zmir-opt-level=0 #![feature(rustc_attrs)] #![allow(unused_attributes)] diff --git a/tests/fail/weak_memory/racing_mixed_size.rs b/tests/fail/weak_memory/racing_mixed_size.rs index 6d53670a4e92e..3608377e9199e 100644 --- a/tests/fail/weak_memory/racing_mixed_size.rs +++ b/tests/fail/weak_memory/racing_mixed_size.rs @@ -1,4 +1,4 @@ -// ignore-windows: Concurrency on Windows is not supported yet. +//@ignore-windows: Concurrency on Windows is not supported yet. #![feature(core_intrinsics)] diff --git a/tests/fail/weak_memory/racing_mixed_size_read.rs b/tests/fail/weak_memory/racing_mixed_size_read.rs index 0129b55aff618..e87b6d6fd01f5 100644 --- a/tests/fail/weak_memory/racing_mixed_size_read.rs +++ b/tests/fail/weak_memory/racing_mixed_size_read.rs @@ -1,4 +1,4 @@ -// ignore-windows: Concurrency on Windows is not supported yet. +//@ignore-windows: Concurrency on Windows is not supported yet. #![feature(core_intrinsics)] diff --git a/tests/fail/zst2.rs b/tests/fail/zst2.rs index 9f92e8994d266..55c78fe8f944e 100644 --- a/tests/fail/zst2.rs +++ b/tests/fail/zst2.rs @@ -1,5 +1,5 @@ // Some optimizations remove ZST accesses, thus masking this UB. -// compile-flags: -Zmir-opt-level=0 +//@compile-flags: -Zmir-opt-level=0 fn main() { // Not using the () type here, as writes of that type do not even have MIR generated. diff --git a/tests/fail/zst3.rs b/tests/fail/zst3.rs index 3f3b0af14dbea..47a7c0d3c2a4b 100644 --- a/tests/fail/zst3.rs +++ b/tests/fail/zst3.rs @@ -1,5 +1,5 @@ // Some optimizations remove ZST accesses, thus masking this UB. -// compile-flags: -Zmir-opt-level=0 +//@compile-flags: -Zmir-opt-level=0 fn main() { // Not using the () type here, as writes of that type do not even have MIR generated. diff --git a/tests/panic/panic/panic1.rs b/tests/panic/panic/panic1.rs index e15d7656de834..dbddf41fdbf71 100644 --- a/tests/panic/panic/panic1.rs +++ b/tests/panic/panic/panic1.rs @@ -1,5 +1,5 @@ -// rustc-env: RUST_BACKTRACE=1 -// compile-flags: -Zmiri-disable-isolation +//@rustc-env: RUST_BACKTRACE=1 +//@compile-flags: -Zmiri-disable-isolation fn main() { std::panic!("panicking from libstd"); diff --git a/tests/panic/panic/unsupported_foreign_function.rs b/tests/panic/panic/unsupported_foreign_function.rs index bc3d02c5f2795..a78646528fb12 100644 --- a/tests/panic/panic/unsupported_foreign_function.rs +++ b/tests/panic/panic/unsupported_foreign_function.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-panic-on-unsupported +//@compile-flags: -Zmiri-panic-on-unsupported fn main() { extern "Rust" { diff --git a/tests/panic/panic/unsupported_syscall.rs b/tests/panic/panic/unsupported_syscall.rs index 2e62a5d8ae8d2..3338c46c04efc 100644 --- a/tests/panic/panic/unsupported_syscall.rs +++ b/tests/panic/panic/unsupported_syscall.rs @@ -1,6 +1,6 @@ -// ignore-windows: No libc on Windows -// ignore-apple: `syscall` is not supported on macOS -// compile-flags: -Zmiri-panic-on-unsupported +//@ignore-windows: No libc on Windows +//@ignore-apple: `syscall` is not supported on macOS +//@compile-flags: -Zmiri-panic-on-unsupported #![feature(rustc_private)] extern crate libc; diff --git a/tests/pass/0weak_memory_consistency.rs b/tests/pass/0weak_memory_consistency.rs index 0f798d2b575e0..19e19b47cfed3 100644 --- a/tests/pass/0weak_memory_consistency.rs +++ b/tests/pass/0weak_memory_consistency.rs @@ -1,5 +1,5 @@ -// ignore-windows: Concurrency on Windows is not supported yet. -// compile-flags: -Zmiri-ignore-leaks -Zmiri-disable-stacked-borrows +//@ignore-windows: Concurrency on Windows is not supported yet. +//@compile-flags: -Zmiri-ignore-leaks -Zmiri-disable-stacked-borrows // The following tests check whether our weak memory emulation produces // any inconsistent execution outcomes diff --git a/tests/pass/adjacent-allocs.rs b/tests/pass/adjacent-allocs.rs index d0dc8b5d87622..0051c62121cd5 100644 --- a/tests/pass/adjacent-allocs.rs +++ b/tests/pass/adjacent-allocs.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-permissive-provenance +//@compile-flags: -Zmiri-permissive-provenance fn ensure_allocs_can_be_adjacent() { for _ in 0..512 { diff --git a/tests/pass/align.rs b/tests/pass/align.rs index f412541bde17a..997abd7339226 100644 --- a/tests/pass/align.rs +++ b/tests/pass/align.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-permissive-provenance +//@compile-flags: -Zmiri-permissive-provenance /// This manually makes sure that we have a pointer with the proper alignment. fn manual_alignment() { diff --git a/tests/pass/align_offset_symbolic.rs b/tests/pass/align_offset_symbolic.rs index b57a23ab83682..b3e5733836390 100644 --- a/tests/pass/align_offset_symbolic.rs +++ b/tests/pass/align_offset_symbolic.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-symbolic-alignment-check +//@compile-flags: -Zmiri-symbolic-alignment-check fn test_align_offset() { let d = Box::new([0u32; 4]); diff --git a/tests/pass/atomic-compare-exchange-weak-never-fail.rs b/tests/pass/atomic-compare-exchange-weak-never-fail.rs index 2c2d4e61d9f5e..8d3d71869f42e 100644 --- a/tests/pass/atomic-compare-exchange-weak-never-fail.rs +++ b/tests/pass/atomic-compare-exchange-weak-never-fail.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-compare-exchange-weak-failure-rate=0.0 +//@compile-flags: -Zmiri-compare-exchange-weak-failure-rate=0.0 use std::sync::atomic::{AtomicBool, Ordering::*}; // Ensure that compare_exchange_weak never fails. diff --git a/tests/pass/atomic.rs b/tests/pass/atomic.rs index 75e9cbdf13262..9b82e006fa162 100644 --- a/tests/pass/atomic.rs +++ b/tests/pass/atomic.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-strict-provenance +//@compile-flags: -Zmiri-strict-provenance #![feature(strict_provenance, strict_provenance_atomic_ptr)] use std::sync::atomic::{ compiler_fence, fence, AtomicBool, AtomicIsize, AtomicPtr, AtomicU64, Ordering::*, diff --git a/tests/pass/backtrace/backtrace-api-v0.rs b/tests/pass/backtrace/backtrace-api-v0.rs index 32fd47d8c5813..5cd12959ca40e 100644 --- a/tests/pass/backtrace/backtrace-api-v0.rs +++ b/tests/pass/backtrace/backtrace-api-v0.rs @@ -1,4 +1,4 @@ -// normalize-stderr-test: "::<.*>" -> "" +//@normalize-stderr-test: "::<.*>" -> "" #[inline(never)] fn func_a() -> Box<[*mut ()]> { diff --git a/tests/pass/backtrace/backtrace-api-v1.rs b/tests/pass/backtrace/backtrace-api-v1.rs index c24a5f3e81250..1e35574b39b6c 100644 --- a/tests/pass/backtrace/backtrace-api-v1.rs +++ b/tests/pass/backtrace/backtrace-api-v1.rs @@ -1,4 +1,4 @@ -// normalize-stderr-test: "::<.*>" -> "" +//@normalize-stderr-test: "::<.*>" -> "" #[inline(never)] fn func_a() -> Box<[*mut ()]> { diff --git a/tests/pass/backtrace/backtrace-global-alloc.rs b/tests/pass/backtrace/backtrace-global-alloc.rs index 8c51bf62706e2..45d6535bc139a 100644 --- a/tests/pass/backtrace/backtrace-global-alloc.rs +++ b/tests/pass/backtrace/backtrace-global-alloc.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-disable-isolation +//@compile-flags: -Zmiri-disable-isolation #![feature(backtrace)] diff --git a/tests/pass/backtrace/backtrace-std.rs b/tests/pass/backtrace/backtrace-std.rs index 5de7cdd6a54d0..488b87ede8fc9 100644 --- a/tests/pass/backtrace/backtrace-std.rs +++ b/tests/pass/backtrace/backtrace-std.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-disable-isolation +//@compile-flags: -Zmiri-disable-isolation #![feature(backtrace)] diff --git a/tests/pass/btreemap.rs b/tests/pass/btreemap.rs index 413d7ef53d1cd..040c648d4747b 100644 --- a/tests/pass/btreemap.rs +++ b/tests/pass/btreemap.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-strict-provenance +//@compile-flags: -Zmiri-strict-provenance #![feature(btree_drain_filter)] use std::collections::{BTreeMap, BTreeSet}; use std::mem; diff --git a/tests/pass/calloc.rs b/tests/pass/calloc.rs index 9f614ce971ba9..a75bb0606118a 100644 --- a/tests/pass/calloc.rs +++ b/tests/pass/calloc.rs @@ -1,4 +1,4 @@ -// ignore-windows: No libc on Windows +//@ignore-windows: No libc on Windows #![feature(rustc_private)] diff --git a/tests/pass/concurrency/channels.rs b/tests/pass/concurrency/channels.rs index 0d6c1749eb51e..e94c69b286d60 100644 --- a/tests/pass/concurrency/channels.rs +++ b/tests/pass/concurrency/channels.rs @@ -1,5 +1,5 @@ -// ignore-windows: Concurrency on Windows is not supported yet. -// compile-flags: -Zmiri-strict-provenance +//@ignore-windows: Concurrency on Windows is not supported yet. +//@compile-flags: -Zmiri-strict-provenance use std::sync::mpsc::{channel, sync_channel}; use std::thread; diff --git a/tests/pass/concurrency/concurrent_caller_location.rs b/tests/pass/concurrency/concurrent_caller_location.rs index 003b9e9ca9f46..6bd601abd56e9 100644 --- a/tests/pass/concurrency/concurrent_caller_location.rs +++ b/tests/pass/concurrency/concurrent_caller_location.rs @@ -1,4 +1,4 @@ -// ignore-windows: Concurrency on Windows is not supported yet. +//@ignore-windows: Concurrency on Windows is not supported yet. use std::panic::Location; use std::thread::spawn; diff --git a/tests/pass/concurrency/data_race.rs b/tests/pass/concurrency/data_race.rs index 812003ef4d97d..69b6c53a2b792 100644 --- a/tests/pass/concurrency/data_race.rs +++ b/tests/pass/concurrency/data_race.rs @@ -1,5 +1,5 @@ -// ignore-windows: Concurrency on Windows is not supported yet. -// compile-flags: -Zmiri-disable-weak-memory-emulation +//@ignore-windows: Concurrency on Windows is not supported yet. +//@compile-flags: -Zmiri-disable-weak-memory-emulation use std::sync::atomic::{fence, AtomicUsize, Ordering}; use std::thread::spawn; diff --git a/tests/pass/concurrency/disable_data_race_detector.rs b/tests/pass/concurrency/disable_data_race_detector.rs index 14e2d5651de0e..a3c1e4621a3ac 100644 --- a/tests/pass/concurrency/disable_data_race_detector.rs +++ b/tests/pass/concurrency/disable_data_race_detector.rs @@ -1,5 +1,5 @@ -// ignore-windows: Concurrency on Windows is not supported yet. -// compile-flags: -Zmiri-disable-data-race-detector +//@ignore-windows: Concurrency on Windows is not supported yet. +//@compile-flags: -Zmiri-disable-data-race-detector use std::thread::spawn; diff --git a/tests/pass/concurrency/issue1643.rs b/tests/pass/concurrency/issue1643.rs index 1238a1bd6f5e1..cfe9cf4cc2f78 100644 --- a/tests/pass/concurrency/issue1643.rs +++ b/tests/pass/concurrency/issue1643.rs @@ -1,4 +1,4 @@ -// ignore-windows: Concurrency on Windows is not supported yet. +//@ignore-windows: Concurrency on Windows is not supported yet. use std::thread::spawn; diff --git a/tests/pass/concurrency/libc_pthread_cond.rs b/tests/pass/concurrency/libc_pthread_cond.rs index 1f6f46cbeb517..8d245e2f8ddd8 100644 --- a/tests/pass/concurrency/libc_pthread_cond.rs +++ b/tests/pass/concurrency/libc_pthread_cond.rs @@ -1,6 +1,6 @@ -// ignore-windows: No libc on Windows -// ignore-apple: pthread_condattr_setclock is not supported on MacOS. -// compile-flags: -Zmiri-disable-isolation +//@ignore-windows: No libc on Windows +//@ignore-apple: pthread_condattr_setclock is not supported on MacOS. +//@compile-flags: -Zmiri-disable-isolation #![feature(rustc_private)] diff --git a/tests/pass/concurrency/linux-futex.rs b/tests/pass/concurrency/linux-futex.rs index b65dd46d5974c..1ec0ec599f7b0 100644 --- a/tests/pass/concurrency/linux-futex.rs +++ b/tests/pass/concurrency/linux-futex.rs @@ -1,5 +1,5 @@ -// only-linux -// compile-flags: -Zmiri-disable-isolation +//@only-linux +//@compile-flags: -Zmiri-disable-isolation #![feature(rustc_private)] extern crate libc; diff --git a/tests/pass/concurrency/mutex_leak.rs b/tests/pass/concurrency/mutex_leak.rs index 7fbc6dd30166b..3ac0c9336b7b1 100644 --- a/tests/pass/concurrency/mutex_leak.rs +++ b/tests/pass/concurrency/mutex_leak.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-ignore-leaks +//@compile-flags: -Zmiri-ignore-leaks use std::mem; use std::sync::Mutex; diff --git a/tests/pass/concurrency/simple.rs b/tests/pass/concurrency/simple.rs index 48c1f3d9fb52c..ac268dab5e94b 100644 --- a/tests/pass/concurrency/simple.rs +++ b/tests/pass/concurrency/simple.rs @@ -1,5 +1,5 @@ -// ignore-windows: Concurrency on Windows is not supported yet. -// compile-flags: -Zmiri-strict-provenance +//@ignore-windows: Concurrency on Windows is not supported yet. +//@compile-flags: -Zmiri-strict-provenance use std::thread; diff --git a/tests/pass/concurrency/spin_loop.rs b/tests/pass/concurrency/spin_loop.rs index e11f0789bb5db..e1c472589904d 100644 --- a/tests/pass/concurrency/spin_loop.rs +++ b/tests/pass/concurrency/spin_loop.rs @@ -1,4 +1,4 @@ -// ignore-windows: Concurrency on Windows is not supported yet. +//@ignore-windows: Concurrency on Windows is not supported yet. use std::sync::atomic::{AtomicUsize, Ordering}; use std::thread; diff --git a/tests/pass/concurrency/spin_loops_nopreempt.rs b/tests/pass/concurrency/spin_loops_nopreempt.rs index 99a5410c95dfd..823d2ec76540c 100644 --- a/tests/pass/concurrency/spin_loops_nopreempt.rs +++ b/tests/pass/concurrency/spin_loops_nopreempt.rs @@ -1,6 +1,6 @@ -// ignore-windows: Concurrency on Windows is not supported yet. +//@ignore-windows: Concurrency on Windows is not supported yet. // This specifically tests behavior *without* preemption. -// compile-flags: -Zmiri-preemption-rate=0 +//@compile-flags: -Zmiri-preemption-rate=0 use std::cell::Cell; use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering}; diff --git a/tests/pass/concurrency/sync.rs b/tests/pass/concurrency/sync.rs index 396c1a97e07e8..b7e6f229faae2 100644 --- a/tests/pass/concurrency/sync.rs +++ b/tests/pass/concurrency/sync.rs @@ -1,5 +1,5 @@ -// ignore-windows: Concurrency on Windows is not supported yet. -// compile-flags: -Zmiri-disable-isolation -Zmiri-strict-provenance +//@ignore-windows: Concurrency on Windows is not supported yet. +//@compile-flags: -Zmiri-disable-isolation -Zmiri-strict-provenance use std::sync::{Arc, Barrier, Condvar, Mutex, Once, RwLock}; use std::thread; diff --git a/tests/pass/concurrency/sync_nopreempt.rs b/tests/pass/concurrency/sync_nopreempt.rs index b5e726dac7b68..e6ee4fe594f10 100644 --- a/tests/pass/concurrency/sync_nopreempt.rs +++ b/tests/pass/concurrency/sync_nopreempt.rs @@ -1,6 +1,6 @@ -// ignore-windows: Concurrency on Windows is not supported yet. +//@ignore-windows: Concurrency on Windows is not supported yet. // We are making scheduler assumptions here. -// compile-flags: -Zmiri-strict-provenance -Zmiri-preemption-rate=0 +//@compile-flags: -Zmiri-strict-provenance -Zmiri-preemption-rate=0 use std::sync::{Arc, Condvar, Mutex, RwLock}; use std::thread; diff --git a/tests/pass/concurrency/thread_locals.rs b/tests/pass/concurrency/thread_locals.rs index 5b11539f7f119..82ce61d958d89 100644 --- a/tests/pass/concurrency/thread_locals.rs +++ b/tests/pass/concurrency/thread_locals.rs @@ -1,5 +1,5 @@ -// ignore-windows: Concurrency on Windows is not supported yet. -// compile-flags: -Zmiri-strict-provenance +//@ignore-windows: Concurrency on Windows is not supported yet. +//@compile-flags: -Zmiri-strict-provenance //! The main purpose of this test is to check that if we take a pointer to //! thread's `t1` thread-local `A` and send it to another thread `t2`, diff --git a/tests/pass/concurrency/tls_lib_drop.rs b/tests/pass/concurrency/tls_lib_drop.rs index fe46406c283c3..74ba8ee762071 100644 --- a/tests/pass/concurrency/tls_lib_drop.rs +++ b/tests/pass/concurrency/tls_lib_drop.rs @@ -1,4 +1,4 @@ -// ignore-windows: Concurrency on Windows is not supported yet. +//@ignore-windows: Concurrency on Windows is not supported yet. use std::cell::RefCell; use std::thread; diff --git a/tests/pass/concurrency/tls_pthread_drop_order.rs b/tests/pass/concurrency/tls_pthread_drop_order.rs index 29c57bf49a338..b265e7da0b259 100644 --- a/tests/pass/concurrency/tls_pthread_drop_order.rs +++ b/tests/pass/concurrency/tls_pthread_drop_order.rs @@ -1,4 +1,4 @@ -// ignore-windows: No libc on Windows +//@ignore-windows: No libc on Windows #![feature(rustc_private)] extern crate libc; diff --git a/tests/pass/current_dir.rs b/tests/pass/current_dir.rs index a88f820951ca4..069b462ab371a 100644 --- a/tests/pass/current_dir.rs +++ b/tests/pass/current_dir.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-disable-isolation +//@compile-flags: -Zmiri-disable-isolation use std::env; use std::io::ErrorKind; diff --git a/tests/pass/current_dir_with_isolation.rs b/tests/pass/current_dir_with_isolation.rs index 98c44d57b65ad..9dbcfeae2d644 100644 --- a/tests/pass/current_dir_with_isolation.rs +++ b/tests/pass/current_dir_with_isolation.rs @@ -1,6 +1,6 @@ -// compile-flags: -Zmiri-isolation-error=warn-nobacktrace -// normalize-stderr-test: "(getcwd|GetCurrentDirectoryW)" -> "$$GETCWD" -// normalize-stderr-test: "(chdir|SetCurrentDirectoryW)" -> "$$SETCWD" +//@compile-flags: -Zmiri-isolation-error=warn-nobacktrace +//@normalize-stderr-test: "(getcwd|GetCurrentDirectoryW)" -> "$$GETCWD" +//@normalize-stderr-test: "(chdir|SetCurrentDirectoryW)" -> "$$SETCWD" use std::env; use std::io::ErrorKind; diff --git a/tests/pass/disable-alignment-check.rs b/tests/pass/disable-alignment-check.rs index 2fb0dd8369df7..366aff4a9f8ec 100644 --- a/tests/pass/disable-alignment-check.rs +++ b/tests/pass/disable-alignment-check.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-disable-alignment-check +//@compile-flags: -Zmiri-disable-alignment-check fn main() { let mut x = [0u8; 20]; diff --git a/tests/pass/enum_discriminant_ptr_value.rs b/tests/pass/enum_discriminant_ptr_value.rs index 618d503cd5f21..4a3820777cff7 100644 --- a/tests/pass/enum_discriminant_ptr_value.rs +++ b/tests/pass/enum_discriminant_ptr_value.rs @@ -1,6 +1,6 @@ // A niche-optimized enum where the discriminant is a pointer value -- relies on ptr-to-int casts in // the niche handling code. -// compile-flags: -Zmiri-disable-stacked-borrows -Zmiri-disable-validation +//@compile-flags: -Zmiri-disable-stacked-borrows -Zmiri-disable-validation fn main() { let x = 42; diff --git a/tests/pass/env-exclude.rs b/tests/pass/env-exclude.rs index 1e251084f0227..14ad827463a4e 100644 --- a/tests/pass/env-exclude.rs +++ b/tests/pass/env-exclude.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-disable-isolation -Zmiri-env-exclude=MIRI_ENV_VAR_TEST +//@compile-flags: -Zmiri-disable-isolation -Zmiri-env-exclude=MIRI_ENV_VAR_TEST fn main() { assert!(std::env::var("MIRI_ENV_VAR_TEST").is_err()); diff --git a/tests/pass/env-forward.rs b/tests/pass/env-forward.rs index 8eebc45f55a71..da7730b00f089 100644 --- a/tests/pass/env-forward.rs +++ b/tests/pass/env-forward.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-env-forward=MIRI_ENV_VAR_TEST +//@compile-flags: -Zmiri-env-forward=MIRI_ENV_VAR_TEST fn main() { assert_eq!(std::env::var("MIRI_ENV_VAR_TEST"), Ok("0".to_owned())); diff --git a/tests/pass/env-without-isolation.rs b/tests/pass/env-without-isolation.rs index 638476209888a..3d7461eecfe88 100644 --- a/tests/pass/env-without-isolation.rs +++ b/tests/pass/env-without-isolation.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-disable-isolation +//@compile-flags: -Zmiri-disable-isolation fn main() { assert_eq!(std::env::var("MIRI_ENV_VAR_TEST"), Ok("0".to_owned())); diff --git a/tests/pass/fs.rs b/tests/pass/fs.rs index e106ca5d02bb8..ced7831568e7b 100644 --- a/tests/pass/fs.rs +++ b/tests/pass/fs.rs @@ -1,5 +1,5 @@ -// ignore-windows: File handling is not implemented yet -// compile-flags: -Zmiri-disable-isolation +//@ignore-windows: File handling is not implemented yet +//@compile-flags: -Zmiri-disable-isolation #![feature(rustc_private)] #![feature(io_error_more)] diff --git a/tests/pass/fs_with_isolation.rs b/tests/pass/fs_with_isolation.rs index 6753145e92b29..719882702cdd2 100644 --- a/tests/pass/fs_with_isolation.rs +++ b/tests/pass/fs_with_isolation.rs @@ -1,6 +1,6 @@ -// ignore-windows: File handling is not implemented yet -// compile-flags: -Zmiri-isolation-error=warn-nobacktrace -// normalize-stderr-test: "(stat(x)?)" -> "$$STAT" +//@ignore-windows: File handling is not implemented yet +//@compile-flags: -Zmiri-isolation-error=warn-nobacktrace +//@normalize-stderr-test: "(stat(x)?)" -> "$$STAT" #![feature(rustc_private)] diff --git a/tests/pass/function_calls/disable_abi_check.rs b/tests/pass/function_calls/disable_abi_check.rs index 1f8554741376b..e6251b5355886 100644 --- a/tests/pass/function_calls/disable_abi_check.rs +++ b/tests/pass/function_calls/disable_abi_check.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-disable-abi-check +//@compile-flags: -Zmiri-disable-abi-check #![feature(core_intrinsics)] fn main() { diff --git a/tests/pass/getpid.rs b/tests/pass/getpid.rs index 258fdeaa8497f..733545462ebc0 100644 --- a/tests/pass/getpid.rs +++ b/tests/pass/getpid.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-disable-isolation +//@compile-flags: -Zmiri-disable-isolation fn getpid() -> u32 { std::process::id() diff --git a/tests/pass/hide_stdout.rs b/tests/pass/hide_stdout.rs index 3ee68d01f43d3..cfd05a8396cb5 100644 --- a/tests/pass/hide_stdout.rs +++ b/tests/pass/hide_stdout.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-mute-stdout-stderr +//@compile-flags: -Zmiri-mute-stdout-stderr fn main() { println!("print to stdout"); diff --git a/tests/pass/integer-ops.rs b/tests/pass/integer-ops.rs index 8e2799d689056..8608d12d4d872 100644 --- a/tests/pass/integer-ops.rs +++ b/tests/pass/integer-ops.rs @@ -1,4 +1,4 @@ -// compile-flags: -Coverflow-checks=off +//@compile-flags: -Coverflow-checks=off #![feature(int_log)] #![allow(arithmetic_overflow)] diff --git a/tests/pass/intptrcast.rs b/tests/pass/intptrcast.rs index aebf5b2223895..e7ff90cb6bf09 100644 --- a/tests/pass/intptrcast.rs +++ b/tests/pass/intptrcast.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-permissive-provenance +//@compile-flags: -Zmiri-permissive-provenance use std::mem; diff --git a/tests/pass/intrinsics.rs b/tests/pass/intrinsics.rs index 0042872a3b45b..756744badaf9c 100644 --- a/tests/pass/intrinsics.rs +++ b/tests/pass/intrinsics.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-permissive-provenance +//@compile-flags: -Zmiri-permissive-provenance #![feature(core_intrinsics, const_raw_ptr_comparison)] #![feature(layout_for_ptr)] diff --git a/tests/pass/issues/issue-miri-1925.rs b/tests/pass/issues/issue-miri-1925.rs index 262889f56eaee..8655681349194 100644 --- a/tests/pass/issues/issue-miri-1925.rs +++ b/tests/pass/issues/issue-miri-1925.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-symbolic-alignment-check +//@compile-flags: -Zmiri-symbolic-alignment-check use std::mem::size_of; diff --git a/tests/pass/issues/issue-miri-2068-2.rs b/tests/pass/issues/issue-miri-2068-2.rs index 204a4dd05642d..f33806e8b4433 100644 --- a/tests/pass/issues/issue-miri-2068-2.rs +++ b/tests/pass/issues/issue-miri-2068-2.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-disable-validation +//@compile-flags: -Zmiri-disable-validation use std::mem::MaybeUninit; diff --git a/tests/pass/libc.rs b/tests/pass/libc.rs index d08430a43260a..53c85d2b07d1a 100644 --- a/tests/pass/libc.rs +++ b/tests/pass/libc.rs @@ -1,5 +1,5 @@ -// ignore-windows: No libc on Windows -// compile-flags: -Zmiri-disable-isolation +//@ignore-windows: No libc on Windows +//@compile-flags: -Zmiri-disable-isolation #![feature(rustc_private)] diff --git a/tests/pass/linux-getrandom-without-isolation.rs b/tests/pass/linux-getrandom-without-isolation.rs index 56a53699477e8..90e054533c14d 100644 --- a/tests/pass/linux-getrandom-without-isolation.rs +++ b/tests/pass/linux-getrandom-without-isolation.rs @@ -1,5 +1,5 @@ -// only-linux -// compile-flags: -Zmiri-disable-isolation +//@only-linux +//@compile-flags: -Zmiri-disable-isolation #![feature(rustc_private)] extern crate libc; diff --git a/tests/pass/linux-getrandom.rs b/tests/pass/linux-getrandom.rs index a3596e4c7a9c0..70c106f6460aa 100644 --- a/tests/pass/linux-getrandom.rs +++ b/tests/pass/linux-getrandom.rs @@ -1,4 +1,4 @@ -// only-linux +//@only-linux #![feature(rustc_private)] extern crate libc; diff --git a/tests/pass/malloc.rs b/tests/pass/malloc.rs index 72abc68bb96b1..c0a6a89fbed0c 100644 --- a/tests/pass/malloc.rs +++ b/tests/pass/malloc.rs @@ -1,4 +1,4 @@ -// ignore-windows: No libc on Windows +//@ignore-windows: No libc on Windows #![feature(rustc_private)] diff --git a/tests/pass/memleak_ignored.rs b/tests/pass/memleak_ignored.rs index fddf14121ef35..60e06094e1771 100644 --- a/tests/pass/memleak_ignored.rs +++ b/tests/pass/memleak_ignored.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-ignore-leaks +//@compile-flags: -Zmiri-ignore-leaks fn main() { std::mem::forget(Box::new(42)); diff --git a/tests/pass/move-uninit-primval.rs b/tests/pass/move-uninit-primval.rs index 1ca3873d1d368..220470b637fcb 100644 --- a/tests/pass/move-uninit-primval.rs +++ b/tests/pass/move-uninit-primval.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-allow-uninit-numbers +//@compile-flags: -Zmiri-allow-uninit-numbers #![allow(deprecated)] struct Foo { diff --git a/tests/pass/no_std.rs b/tests/pass/no_std.rs index 6808dab8143f4..d8a462daf5a94 100644 --- a/tests/pass/no_std.rs +++ b/tests/pass/no_std.rs @@ -3,7 +3,7 @@ // windows tls dtors go through libstd right now, thus this test // cannot pass. When windows tls dtors go through the special magic // windows linker section, we can run this test on windows again. -// ignore-windows +//@ignore-windows #[start] fn start(_: isize, _: *const *const u8) -> isize { diff --git a/tests/pass/observed_local_mut.rs b/tests/pass/observed_local_mut.rs index 888b6f85e3fd5..ca0f569860b82 100644 --- a/tests/pass/observed_local_mut.rs +++ b/tests/pass/observed_local_mut.rs @@ -1,5 +1,5 @@ // Stacked Borrows catches this (correctly) as UB. -// compile-flags: -Zmiri-disable-stacked-borrows +//@compile-flags: -Zmiri-disable-stacked-borrows // This test is intended to guard against the problem described in commit // 39bb1254d1eaf74f45a4e741097e33fc942168d5. diff --git a/tests/pass/overflow_checks_off.rs b/tests/pass/overflow_checks_off.rs index 2896d3161f763..79aa510ef97fe 100644 --- a/tests/pass/overflow_checks_off.rs +++ b/tests/pass/overflow_checks_off.rs @@ -1,4 +1,4 @@ -// compile-flags: -C overflow-checks=off +//@compile-flags: -C overflow-checks=off // Check that we correctly implement the intended behavior of these operators // when they are not being overflow-checked. diff --git a/tests/pass/panic/catch_panic.rs b/tests/pass/panic/catch_panic.rs index 3979fb3b07146..308904406538c 100644 --- a/tests/pass/panic/catch_panic.rs +++ b/tests/pass/panic/catch_panic.rs @@ -1,5 +1,5 @@ // We test the `align_offset` panic below, make sure we test the interpreter impl and not the "real" one. -// compile-flags: -Zmiri-symbolic-alignment-check -Zmiri-permissive-provenance +//@compile-flags: -Zmiri-symbolic-alignment-check -Zmiri-permissive-provenance #![feature(never_type)] #![allow(unconditional_panic, non_fmt_panics)] diff --git a/tests/pass/panic/concurrent-panic.rs b/tests/pass/panic/concurrent-panic.rs index 7b17ac4fa79c1..1231760865fb0 100644 --- a/tests/pass/panic/concurrent-panic.rs +++ b/tests/pass/panic/concurrent-panic.rs @@ -1,6 +1,6 @@ -// ignore-windows: Concurrency on Windows is not supported yet. +//@ignore-windows: Concurrency on Windows is not supported yet. // We are making scheduler assumptions here. -// compile-flags: -Zmiri-preemption-rate=0 +//@compile-flags: -Zmiri-preemption-rate=0 //! Cause a panic in one thread while another thread is unwinding. This checks //! that separate threads have their own panicking state. diff --git a/tests/pass/portable-simd.rs b/tests/pass/portable-simd.rs index ffbaa1832ecba..0dfe617bd8dc9 100644 --- a/tests/pass/portable-simd.rs +++ b/tests/pass/portable-simd.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-strict-provenance +//@compile-flags: -Zmiri-strict-provenance #![feature(portable_simd, platform_intrinsics)] use std::simd::*; diff --git a/tests/pass/ptr_int_casts.rs b/tests/pass/ptr_int_casts.rs index ffe6a114c66b3..3044ac092b7d4 100644 --- a/tests/pass/ptr_int_casts.rs +++ b/tests/pass/ptr_int_casts.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-permissive-provenance +//@compile-flags: -Zmiri-permissive-provenance use std::mem; use std::ptr; diff --git a/tests/pass/ptr_int_from_exposed.rs b/tests/pass/ptr_int_from_exposed.rs index dc9cb393b7815..ef7ff34d26b23 100644 --- a/tests/pass/ptr_int_from_exposed.rs +++ b/tests/pass/ptr_int_from_exposed.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-permissive-provenance +//@compile-flags: -Zmiri-permissive-provenance #![feature(strict_provenance)] use std::ptr; diff --git a/tests/pass/ptr_offset.rs b/tests/pass/ptr_offset.rs index b16a06a7260b3..5270e8663b2d7 100644 --- a/tests/pass/ptr_offset.rs +++ b/tests/pass/ptr_offset.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-permissive-provenance +//@compile-flags: -Zmiri-permissive-provenance use std::{mem, ptr}; fn main() { diff --git a/tests/pass/rc.rs b/tests/pass/rc.rs index 260e350f27ac2..569dbc459a5b5 100644 --- a/tests/pass/rc.rs +++ b/tests/pass/rc.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-strict-provenance +//@compile-flags: -Zmiri-strict-provenance #![feature(new_uninit)] #![feature(get_mut_unchecked)] diff --git a/tests/pass/slices.rs b/tests/pass/slices.rs index 3a13ec59a02ea..a56b97a5088fa 100644 --- a/tests/pass/slices.rs +++ b/tests/pass/slices.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-strict-provenance +//@compile-flags: -Zmiri-strict-provenance #![feature(new_uninit)] #![feature(slice_as_chunks)] #![feature(slice_partition_dedup)] diff --git a/tests/pass/stacked-borrows/int-to-ptr.rs b/tests/pass/stacked-borrows/int-to-ptr.rs index dc3675406276f..c3e30627a7ce3 100644 --- a/tests/pass/stacked-borrows/int-to-ptr.rs +++ b/tests/pass/stacked-borrows/int-to-ptr.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-permissive-provenance +//@compile-flags: -Zmiri-permissive-provenance #![feature(strict_provenance)] use std::ptr; diff --git a/tests/pass/stacked-borrows/interior_mutability.rs b/tests/pass/stacked-borrows/interior_mutability.rs index 96ad67505a73e..c6373a7eaf135 100644 --- a/tests/pass/stacked-borrows/interior_mutability.rs +++ b/tests/pass/stacked-borrows/interior_mutability.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-retag-fields +//@compile-flags: -Zmiri-retag-fields use std::cell::{Cell, Ref, RefCell, RefMut, UnsafeCell}; use std::mem::{self, MaybeUninit}; diff --git a/tests/pass/stacked-borrows/stacked-borrows.rs b/tests/pass/stacked-borrows/stacked-borrows.rs index b915a2ddf8f67..ef6eb346c17b1 100644 --- a/tests/pass/stacked-borrows/stacked-borrows.rs +++ b/tests/pass/stacked-borrows/stacked-borrows.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-retag-fields +//@compile-flags: -Zmiri-retag-fields #![feature(allocator_api)] use std::ptr; diff --git a/tests/pass/strings.rs b/tests/pass/strings.rs index ccefc69bd180e..5e2d2e9b5b5c1 100644 --- a/tests/pass/strings.rs +++ b/tests/pass/strings.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-strict-provenance +//@compile-flags: -Zmiri-strict-provenance fn empty() -> &'static str { "" diff --git a/tests/pass/threadleak_ignored.rs b/tests/pass/threadleak_ignored.rs index 36d39a72b7998..2ba0b453ff394 100644 --- a/tests/pass/threadleak_ignored.rs +++ b/tests/pass/threadleak_ignored.rs @@ -1,6 +1,6 @@ -// ignore-windows: Concurrency on Windows is not supported yet. +//@ignore-windows: Concurrency on Windows is not supported yet. // FIXME: disallow preemption to work around https://github.com/rust-lang/rust/issues/55005 -// compile-flags: -Zmiri-ignore-leaks -Zmiri-preemption-rate=0 +//@compile-flags: -Zmiri-ignore-leaks -Zmiri-preemption-rate=0 //! Test that leaking threads works, and that their destructors are not executed. diff --git a/tests/pass/time.rs b/tests/pass/time.rs index 38e846309d728..e1094006fb1fa 100644 --- a/tests/pass/time.rs +++ b/tests/pass/time.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-disable-isolation +//@compile-flags: -Zmiri-disable-isolation use std::time::{Duration, Instant, SystemTime}; diff --git a/tests/pass/track-alloc-1.rs b/tests/pass/track-alloc-1.rs index bbd88ed5d53e0..427c800dc51d2 100644 --- a/tests/pass/track-alloc-1.rs +++ b/tests/pass/track-alloc-1.rs @@ -1,6 +1,6 @@ // Ensure that tracking early allocations doesn't ICE Miri. // Early allocations are probably part of the runtime and therefore uninteresting, but they // shouldn't cause a crash. -// compile-flags: -Zmiri-track-alloc-id=1 -// normalize-stderr-test: "[48] bytes" -> "SIZE bytes" +//@compile-flags: -Zmiri-track-alloc-id=1 +//@normalize-stderr-test: "[48] bytes" -> "SIZE bytes" fn main() {} diff --git a/tests/pass/transmute_fat.rs b/tests/pass/transmute_fat.rs index b752e5504d4c9..dfd78ace520c5 100644 --- a/tests/pass/transmute_fat.rs +++ b/tests/pass/transmute_fat.rs @@ -1,5 +1,5 @@ // Stacked Borrows disallows this becuase the reference is never cast to a raw pointer. -// compile-flags: -Zmiri-disable-stacked-borrows +//@compile-flags: -Zmiri-disable-stacked-borrows fn main() { // If we are careful, we can exploit data layout... diff --git a/tests/pass/uninit_number_ignored.rs b/tests/pass/uninit_number_ignored.rs index 13aac61ba84cc..44f6fa2679853 100644 --- a/tests/pass/uninit_number_ignored.rs +++ b/tests/pass/uninit_number_ignored.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-allow-uninit-numbers +//@compile-flags: -Zmiri-allow-uninit-numbers // This test is adapted from https://github.com/rust-lang/miri/issues/1340#issue-600900312. fn main() { diff --git a/tests/pass/vec.rs b/tests/pass/vec.rs index 89c2561acd970..26732cec5eb9a 100644 --- a/tests/pass/vec.rs +++ b/tests/pass/vec.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-strict-provenance +//@compile-flags: -Zmiri-strict-provenance // Gather all references from a mutable iterator and make sure Miri notices if // using them is dangerous. fn test_all_refs<'a, T: 'a>(dummy: &mut T, iter: impl Iterator) { diff --git a/tests/pass/vecdeque.rs b/tests/pass/vecdeque.rs index d2295a7afb599..6f56f9d103e9d 100644 --- a/tests/pass/vecdeque.rs +++ b/tests/pass/vecdeque.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-strict-provenance +//@compile-flags: -Zmiri-strict-provenance use std::collections::VecDeque; fn test_all_refs<'a, T: 'a>(dummy: &mut T, iter: impl Iterator) { diff --git a/tests/pass/weak_memory/extra_cpp.rs b/tests/pass/weak_memory/extra_cpp.rs index 750c628458b8a..61ba1ab922489 100644 --- a/tests/pass/weak_memory/extra_cpp.rs +++ b/tests/pass/weak_memory/extra_cpp.rs @@ -1,5 +1,5 @@ -// ignore-windows: Concurrency on Windows is not supported yet. -// compile-flags: -Zmiri-ignore-leaks +//@ignore-windows: Concurrency on Windows is not supported yet. +//@compile-flags: -Zmiri-ignore-leaks // Tests operations not perfomable through C++'s atomic API // but doable in safe (at least sound) Rust. diff --git a/tests/pass/weak_memory/extra_cpp_unsafe.rs b/tests/pass/weak_memory/extra_cpp_unsafe.rs index d77a090e6e43f..0aff70ab7b786 100644 --- a/tests/pass/weak_memory/extra_cpp_unsafe.rs +++ b/tests/pass/weak_memory/extra_cpp_unsafe.rs @@ -1,5 +1,5 @@ -// ignore-windows: Concurrency on Windows is not supported yet. -// compile-flags: -Zmiri-ignore-leaks +//@ignore-windows: Concurrency on Windows is not supported yet. +//@compile-flags: -Zmiri-ignore-leaks // Tests operations not perfomable through C++'s atomic API // but doable in unsafe Rust which we think *should* be fine. diff --git a/tests/pass/weak_memory/weak.rs b/tests/pass/weak_memory/weak.rs index b9ceb61f0c9fc..1d82b85844f41 100644 --- a/tests/pass/weak_memory/weak.rs +++ b/tests/pass/weak_memory/weak.rs @@ -1,5 +1,5 @@ -// ignore-windows: Concurrency on Windows is not supported yet. -// compile-flags: -Zmiri-ignore-leaks -Zmiri-preemption-rate=0 +//@ignore-windows: Concurrency on Windows is not supported yet. +//@compile-flags: -Zmiri-ignore-leaks -Zmiri-preemption-rate=0 // Tests showing weak memory behaviours are exhibited. All tests // return true when the desired behaviour is seen. diff --git a/tests/pass/without-validation.rs b/tests/pass/without-validation.rs index 8cff3a5c4b2e8..934c44a7deb4d 100644 --- a/tests/pass/without-validation.rs +++ b/tests/pass/without-validation.rs @@ -1,5 +1,5 @@ // When we notice something breaks only without validation, we add a test here. -// compile-flags: -Zmiri-disable-validation +//@compile-flags: -Zmiri-disable-validation use std::cell::*; fn refcell_unsize() { diff --git a/tests/pass/wtf8.rs b/tests/pass/wtf8.rs index e31b00e95244e..bf23f65c7f0c7 100644 --- a/tests/pass/wtf8.rs +++ b/tests/pass/wtf8.rs @@ -1,4 +1,4 @@ -// only-windows +//@only-windows use std::ffi::{OsStr, OsString}; use std::os::windows::ffi::{OsStrExt, OsStringExt}; diff --git a/tests/pass/zst.rs b/tests/pass/zst.rs index fade1e0dad88f..a56386a691f8d 100644 --- a/tests/pass/zst.rs +++ b/tests/pass/zst.rs @@ -1,4 +1,4 @@ -// compile-flags: -Zmiri-permissive-provenance +//@compile-flags: -Zmiri-permissive-provenance #[derive(PartialEq, Debug)] struct A; diff --git a/ui_test/src/comments.rs b/ui_test/src/comments.rs index 2b6108f255f8e..4046a9fc0ddf7 100644 --- a/ui_test/src/comments.rs +++ b/ui_test/src/comments.rs @@ -74,10 +74,7 @@ impl Comments { /// Parse comments in `content`. /// `path` is only used to emit diagnostics if parsing fails. - /// - /// This function will only parse `//@` and `//~` style comments (and the `//[xxx]~` variant) - /// and ignore all others - fn parse_checked(path: &Path, content: &str) -> Result { + pub(crate) fn parse(path: &Path, content: &str) -> Result { let mut this = Self::default(); let mut fallthrough_to = None; // The line that a `|` will refer to. @@ -108,83 +105,10 @@ impl Comments { } } - /// Parse comments in `content`. - /// `path` is only used to emit diagnostics if parsing fails. - pub(crate) fn parse(path: &Path, content: &str) -> Result { - let mut this = Self::parse_checked(path, content)?; - if content.contains("//@") { - // Migration mode: if new syntax is used, ignore all old syntax - return Ok(this); - } - - for (l, line) in content.lines().enumerate() { - let l = l + 1; // enumerate starts at 0, but line numbers start at 1 - if let Some(revisions) = line.strip_prefix("// revisions:") { - assert_eq!( - this.revisions, - None, - "{}:{l}, cannot specifiy revisions twice", - path.display() - ); - this.revisions = - Some(revisions.split_whitespace().map(|s| s.to_string()).collect()); - } - if let Some(s) = line.strip_prefix("// ignore-") { - let s = s - .split_once(|c: char| c == ':' || c.is_whitespace()) - .map(|(s, _)| s) - .unwrap_or(s); - this.ignore.push(Condition::parse(s)); - } - if let Some(s) = line.strip_prefix("// only-") { - let s = s - .split_once(|c: char| c == ':' || c.is_whitespace()) - .map(|(s, _)| s) - .unwrap_or(s); - this.only.push(Condition::parse(s)); - } - if line.starts_with("// stderr-per-bitwidth") { - assert!( - !this.stderr_per_bitwidth, - "{}:{l}, cannot specifiy stderr-per-bitwidth twice", - path.display() - ); - this.stderr_per_bitwidth = true; - } - if let Some(s) = line.strip_prefix("// compile-flags:") { - this.compile_flags.extend(s.split_whitespace().map(|s| s.to_string())); - } - if let Some(s) = line.strip_prefix("// rustc-env:") { - for env in s.split_whitespace() { - if let Some((k, v)) = env.split_once('=') { - this.env_vars.push((k.to_string(), v.to_string())); - } - } - } - if let Some(s) = line.strip_prefix("// normalize-stderr-test:") { - let (from, to) = s.split_once("->").expect("normalize-stderr-test needs a `->`"); - let from = from.trim().trim_matches('"'); - let to = to.trim().trim_matches('"'); - let from = Regex::new(from).unwrap(); - this.normalize_stderr.push((from, to.to_string())); - } - if let Some(s) = line.strip_prefix("// error-pattern:") { - assert_eq!( - this.error_pattern, - None, - "{}:{l}, cannot specifiy error_pattern twice", - path.display() - ); - this.error_pattern = Some((s.trim().to_string(), l)); - } - } - Ok(this) - } - fn parse_command(&mut self, command: &str, l: usize) -> Result<()> { // Commands are letters or dashes, grab everything until the first character that is neither of those. let (command, args) = - match command.chars().position(|c: char| !c.is_alphabetic() && c != '-') { + match command.chars().position(|c: char| !c.is_alphanumeric() && c != '-') { None => (command, ""), Some(i) => { let (command, args) = command.split_at(i); From fdffaf740bf15dbcedd630b0ac6bd81293202bc8 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 8 Jul 2022 17:17:44 -0400 Subject: [PATCH 3451/3747] ui_test: require colon after command --- ui_test/src/comments.rs | 11 +++++------ ui_test/src/comments/tests.rs | 14 ++++++++++++++ 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/ui_test/src/comments.rs b/ui_test/src/comments.rs index 4046a9fc0ddf7..12f0864d9ab8d 100644 --- a/ui_test/src/comments.rs +++ b/ui_test/src/comments.rs @@ -117,12 +117,8 @@ impl Comments { let next = args .next() .expect("the `position` above guarantees that there is at least one char"); - // FIXME: this replicates the existing flexibility in our syntax. Consider requiring the colon. - let args = match next { - ':' | ' ' => args.as_str(), - _ => bail!("expected space or `:`, got `{next}`"), - }; - (command, args.trim()) + ensure!(next == ':', "test command must be followed by : (or end the line)"); + (command, args.as_str().trim()) } }; @@ -188,16 +184,19 @@ impl Comments { self.error_pattern = Some((args.trim().to_string(), l)); } "stderr-per-bitwidth" => { + // args are ignored (can be sue as comment) ensure!(!self.stderr_per_bitwidth, "cannot specifiy stderr-per-bitwidth twice"); self.stderr_per_bitwidth = true; } command => { if let Some(s) = command.strip_prefix("ignore-") { + // args are ignored (can be sue as comment) self.ignore.push(Condition::parse(s)); return Ok(()); } if let Some(s) = command.strip_prefix("only-") { + // args are ignored (can be sue as comment) self.only.push(Condition::parse(s)); return Ok(()); } diff --git a/ui_test/src/comments/tests.rs b/ui_test/src/comments/tests.rs index 15a0aae247b1d..096cc8eab9657 100644 --- a/ui_test/src/comments/tests.rs +++ b/ui_test/src/comments/tests.rs @@ -53,3 +53,17 @@ use std::mem; Err(_) => Ok(()), } } + +#[test] +fn missing_colon_fail() -> Result<()> { + init(); + let s = r" +//@stderr-per-bitwidth hello +use std::mem; + + "; + match Comments::parse(Path::new(""), s) { + Ok(_) => bail!("expected parsing to fail"), + Err(_) => Ok(()), + } +} From d260dffa19515495a6b7dcd21770826f57179bb1 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 8 Jul 2022 17:18:17 -0400 Subject: [PATCH 3452/3747] =?UTF-8?q?rename=20ui=5Ftest::comments=20?= =?UTF-8?q?=E2=86=92=20parser?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ui_test/src/lib.rs | 6 +++--- ui_test/src/{comments.rs => parser.rs} | 0 ui_test/src/{comments => parser}/tests.rs | 0 3 files changed, 3 insertions(+), 3 deletions(-) rename ui_test/src/{comments.rs => parser.rs} (100%) rename ui_test/src/{comments => parser}/tests.rs (100%) diff --git a/ui_test/src/lib.rs b/ui_test/src/lib.rs index da562fcac7d29..bebda768babee 100644 --- a/ui_test/src/lib.rs +++ b/ui_test/src/lib.rs @@ -10,13 +10,13 @@ use std::sync::Mutex; pub use color_eyre; use color_eyre::eyre::Result; use colored::*; -use comments::ErrorMatch; +use parser::ErrorMatch; use regex::Regex; use rustc_stderr::{Level, Message}; -use crate::comments::{Comments, Condition}; +use crate::parser::{Comments, Condition}; -mod comments; +mod parser; mod rustc_stderr; #[cfg(test)] mod tests; diff --git a/ui_test/src/comments.rs b/ui_test/src/parser.rs similarity index 100% rename from ui_test/src/comments.rs rename to ui_test/src/parser.rs diff --git a/ui_test/src/comments/tests.rs b/ui_test/src/parser/tests.rs similarity index 100% rename from ui_test/src/comments/tests.rs rename to ui_test/src/parser/tests.rs From 2850db9f6b2172e11b5e7d9b4b685fd288797886 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 9 Jul 2022 07:51:06 -0400 Subject: [PATCH 3453/3747] typo Co-authored-by: Oli Scherer --- ui_test/src/parser.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui_test/src/parser.rs b/ui_test/src/parser.rs index 12f0864d9ab8d..72ccc0136201c 100644 --- a/ui_test/src/parser.rs +++ b/ui_test/src/parser.rs @@ -184,7 +184,7 @@ impl Comments { self.error_pattern = Some((args.trim().to_string(), l)); } "stderr-per-bitwidth" => { - // args are ignored (can be sue as comment) + // args are ignored (can be used as comment) ensure!(!self.stderr_per_bitwidth, "cannot specifiy stderr-per-bitwidth twice"); self.stderr_per_bitwidth = true; } From c9b207eba63b814cf39652fc9573318a7efc938b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 9 Jul 2022 12:49:37 -0400 Subject: [PATCH 3454/3747] extend a comment in readlink --- src/shims/unix/fs.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/shims/unix/fs.rs b/src/shims/unix/fs.rs index c688455710345..c7d7789f03ab7 100644 --- a/src/shims/unix/fs.rs +++ b/src/shims/unix/fs.rs @@ -1639,6 +1639,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let result = std::fs::read_link(pathname); match result { Ok(resolved) => { + // 'readlink' truncates the resolved path if the provided buffer is not large + // enough, and does *not* add a null terminator. That means we cannot use the usual + // `write_path_to_c_str` and have to re-implement parts of it ourselves. let resolved = this.convert_path_separator( Cow::Borrowed(resolved.as_ref()), crate::shims::os_str::PathConversion::HostToTarget, @@ -1648,8 +1651,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if path_bytes.len() > bufsize { path_bytes = &path_bytes[..bufsize] } - // 'readlink' truncates the resolved path if - // the provided buffer is not large enough. this.write_bytes_ptr(buf, path_bytes.iter().copied())?; Ok(path_bytes.len().try_into().unwrap()) } From bf5af84640f5494e6e915c00adadf83ce1d62637 Mon Sep 17 00:00:00 2001 From: TechiePi <48295028+Techie-Pi@users.noreply.github.com> Date: Sun, 10 Jul 2022 23:41:35 +0200 Subject: [PATCH 3455/3747] Fix README typo "behaivours" -> "behaviours". Just something I noticed while reading --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 52934a6cd4bc0..7679537e7f88b 100644 --- a/README.md +++ b/README.md @@ -65,7 +65,7 @@ in your program, and cannot run all programs: not support networking. System API support varies between targets; if you run on Windows it is a good idea to use `--target x86_64-unknown-linux-gnu` to get better support. -* Weak memory emulation may [produce weak behaivours](https://github.com/rust-lang/miri/issues/2301) +* Weak memory emulation may [produce weak behaviours](https://github.com/rust-lang/miri/issues/2301) unobservable by compiled programs running on real hardware when `SeqCst` fences are used, and it cannot produce all behaviors possibly observable on real hardware. From 45abee46be9223dd4bbe895f836093c04ead1e89 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 10 Jul 2022 20:15:35 -0400 Subject: [PATCH 3456/3747] make a test deterministic --- rust-version | 2 +- tests/fail/data_race/enable_after_join_to_main.rs | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 53e7908f42c84..2a26cb608235a 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -1517f5de01c445b5124b30f02257b02b4c5ef3b2 +c396bb3b8a16b1f2762b7c6078dc3e023f6a2493 diff --git a/tests/fail/data_race/enable_after_join_to_main.rs b/tests/fail/data_race/enable_after_join_to_main.rs index 757a41adc9328..290589690a389 100644 --- a/tests/fail/data_race/enable_after_join_to_main.rs +++ b/tests/fail/data_race/enable_after_join_to_main.rs @@ -1,3 +1,5 @@ +// We want to control preemption here. +//@compile-flags: -Zmiri-preemption-rate=0 //@ignore-windows: Concurrency on Windows is not supported yet. use std::thread::spawn; From 444ba75ac5fb0754b306b56b2fc2427d008f6b06 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 10 Jul 2022 20:19:41 -0400 Subject: [PATCH 3457/3747] make more tests deterministic --- tests/fail/data_race/atomic_read_na_write_race1.rs | 2 ++ tests/fail/data_race/atomic_read_na_write_race2.rs | 2 ++ tests/fail/data_race/atomic_write_na_read_race1.rs | 2 ++ tests/fail/data_race/atomic_write_na_read_race2.rs | 2 ++ tests/fail/data_race/atomic_write_na_write_race1.rs | 2 ++ tests/fail/data_race/atomic_write_na_write_race2.rs | 2 ++ tests/fail/data_race/dangling_thread_async_race.rs | 3 ++- tests/fail/data_race/dangling_thread_race.rs | 3 ++- tests/fail/data_race/dealloc_read_race1.rs | 2 ++ tests/fail/data_race/dealloc_read_race2.rs | 2 ++ tests/fail/data_race/dealloc_write_race1.rs | 2 ++ tests/fail/data_race/dealloc_write_race2.rs | 2 ++ tests/fail/data_race/read_write_race.rs | 2 ++ tests/fail/data_race/write_write_race.rs | 2 ++ tests/fail/weak_memory/racing_mixed_size.rs | 2 ++ tests/fail/weak_memory/racing_mixed_size_read.rs | 2 ++ 16 files changed, 32 insertions(+), 2 deletions(-) diff --git a/tests/fail/data_race/atomic_read_na_write_race1.rs b/tests/fail/data_race/atomic_read_na_write_race1.rs index 71d7a66597d18..ada25173f255f 100644 --- a/tests/fail/data_race/atomic_read_na_write_race1.rs +++ b/tests/fail/data_race/atomic_read_na_write_race1.rs @@ -1,3 +1,5 @@ +// We want to control preemption here. +//@compile-flags: -Zmiri-preemption-rate=0 //@ignore-windows: Concurrency on Windows is not supported yet. #![feature(core_intrinsics)] diff --git a/tests/fail/data_race/atomic_read_na_write_race2.rs b/tests/fail/data_race/atomic_read_na_write_race2.rs index a490f47da7c31..b355e4816dde1 100644 --- a/tests/fail/data_race/atomic_read_na_write_race2.rs +++ b/tests/fail/data_race/atomic_read_na_write_race2.rs @@ -1,3 +1,5 @@ +// We want to control preemption here. +//@compile-flags: -Zmiri-preemption-rate=0 //@ignore-windows: Concurrency on Windows is not supported yet. use std::sync::atomic::AtomicUsize; diff --git a/tests/fail/data_race/atomic_write_na_read_race1.rs b/tests/fail/data_race/atomic_write_na_read_race1.rs index 40066d91b1ff2..53305c68cb766 100644 --- a/tests/fail/data_race/atomic_write_na_read_race1.rs +++ b/tests/fail/data_race/atomic_write_na_read_race1.rs @@ -1,3 +1,5 @@ +// We want to control preemption here. +//@compile-flags: -Zmiri-preemption-rate=0 //@ignore-windows: Concurrency on Windows is not supported yet. use std::sync::atomic::AtomicUsize; diff --git a/tests/fail/data_race/atomic_write_na_read_race2.rs b/tests/fail/data_race/atomic_write_na_read_race2.rs index 0bfadcba3ed34..21b0abbcaba97 100644 --- a/tests/fail/data_race/atomic_write_na_read_race2.rs +++ b/tests/fail/data_race/atomic_write_na_read_race2.rs @@ -1,3 +1,5 @@ +// We want to control preemption here. +//@compile-flags: -Zmiri-preemption-rate=0 //@ignore-windows: Concurrency on Windows is not supported yet. #![feature(core_intrinsics)] diff --git a/tests/fail/data_race/atomic_write_na_write_race1.rs b/tests/fail/data_race/atomic_write_na_write_race1.rs index 258f5dd142efe..a8ac18f32136c 100644 --- a/tests/fail/data_race/atomic_write_na_write_race1.rs +++ b/tests/fail/data_race/atomic_write_na_write_race1.rs @@ -1,3 +1,5 @@ +// We want to control preemption here. +//@compile-flags: -Zmiri-preemption-rate=0 //@ignore-windows: Concurrency on Windows is not supported yet. #![feature(core_intrinsics)] diff --git a/tests/fail/data_race/atomic_write_na_write_race2.rs b/tests/fail/data_race/atomic_write_na_write_race2.rs index 51068262d5889..e3b3e226d8c73 100644 --- a/tests/fail/data_race/atomic_write_na_write_race2.rs +++ b/tests/fail/data_race/atomic_write_na_write_race2.rs @@ -1,3 +1,5 @@ +// We want to control preemption here. +//@compile-flags: -Zmiri-preemption-rate=0 //@ignore-windows: Concurrency on Windows is not supported yet. use std::sync::atomic::AtomicUsize; diff --git a/tests/fail/data_race/dangling_thread_async_race.rs b/tests/fail/data_race/dangling_thread_async_race.rs index 7bb20adfcd5fc..be06740201d2a 100644 --- a/tests/fail/data_race/dangling_thread_async_race.rs +++ b/tests/fail/data_race/dangling_thread_async_race.rs @@ -1,5 +1,6 @@ +// We want to control preemption here. +//@compile-flags: -Zmiri-disable-isolation -Zmiri-preemption-rate=0 //@ignore-windows: Concurrency on Windows is not supported yet. -//@compile-flags: -Zmiri-disable-isolation use std::mem; use std::thread::{sleep, spawn}; diff --git a/tests/fail/data_race/dangling_thread_race.rs b/tests/fail/data_race/dangling_thread_race.rs index 7e198eef6e94e..90957e4026e3e 100644 --- a/tests/fail/data_race/dangling_thread_race.rs +++ b/tests/fail/data_race/dangling_thread_race.rs @@ -1,5 +1,6 @@ +// We want to control preemption here. +//@compile-flags: -Zmiri-disable-isolation -Zmiri-preemption-rate=0 //@ignore-windows: Concurrency on Windows is not supported yet. -//@compile-flags: -Zmiri-disable-isolation use std::mem; use std::thread::{sleep, spawn}; diff --git a/tests/fail/data_race/dealloc_read_race1.rs b/tests/fail/data_race/dealloc_read_race1.rs index 634904cbfdce5..b37f4fda2bd4b 100644 --- a/tests/fail/data_race/dealloc_read_race1.rs +++ b/tests/fail/data_race/dealloc_read_race1.rs @@ -1,3 +1,5 @@ +// We want to control preemption here. +//@compile-flags: -Zmiri-preemption-rate=0 //@ignore-windows: Concurrency on Windows is not supported yet. use std::thread::spawn; diff --git a/tests/fail/data_race/dealloc_read_race2.rs b/tests/fail/data_race/dealloc_read_race2.rs index 91ec3c2bd8724..280b86924be81 100644 --- a/tests/fail/data_race/dealloc_read_race2.rs +++ b/tests/fail/data_race/dealloc_read_race2.rs @@ -1,3 +1,5 @@ +// We want to control preemption here. +//@compile-flags: -Zmiri-preemption-rate=0 //@ignore-windows: Concurrency on Windows is not supported yet. use std::thread::spawn; diff --git a/tests/fail/data_race/dealloc_write_race1.rs b/tests/fail/data_race/dealloc_write_race1.rs index f95a9be172749..17fb444f9c63d 100644 --- a/tests/fail/data_race/dealloc_write_race1.rs +++ b/tests/fail/data_race/dealloc_write_race1.rs @@ -1,3 +1,5 @@ +// We want to control preemption here. +//@compile-flags: -Zmiri-preemption-rate=0 //@ignore-windows: Concurrency on Windows is not supported yet. use std::thread::spawn; diff --git a/tests/fail/data_race/dealloc_write_race2.rs b/tests/fail/data_race/dealloc_write_race2.rs index 922738354fb07..6afb1182a029a 100644 --- a/tests/fail/data_race/dealloc_write_race2.rs +++ b/tests/fail/data_race/dealloc_write_race2.rs @@ -1,3 +1,5 @@ +// We want to control preemption here. +//@compile-flags: -Zmiri-preemption-rate=0 //@ignore-windows: Concurrency on Windows is not supported yet. use std::thread::spawn; diff --git a/tests/fail/data_race/read_write_race.rs b/tests/fail/data_race/read_write_race.rs index cffbba1a70f33..4c1d87746d726 100644 --- a/tests/fail/data_race/read_write_race.rs +++ b/tests/fail/data_race/read_write_race.rs @@ -1,3 +1,5 @@ +// We want to control preemption here. +//@compile-flags: -Zmiri-preemption-rate=0 //@ignore-windows: Concurrency on Windows is not supported yet. use std::thread::spawn; diff --git a/tests/fail/data_race/write_write_race.rs b/tests/fail/data_race/write_write_race.rs index ddd710bce08dc..de4d4d70c5006 100644 --- a/tests/fail/data_race/write_write_race.rs +++ b/tests/fail/data_race/write_write_race.rs @@ -1,3 +1,5 @@ +// We want to control preemption here. +//@compile-flags: -Zmiri-preemption-rate=0 //@ignore-windows: Concurrency on Windows is not supported yet. use std::thread::spawn; diff --git a/tests/fail/weak_memory/racing_mixed_size.rs b/tests/fail/weak_memory/racing_mixed_size.rs index 3608377e9199e..d697e5f8fbeae 100644 --- a/tests/fail/weak_memory/racing_mixed_size.rs +++ b/tests/fail/weak_memory/racing_mixed_size.rs @@ -1,3 +1,5 @@ +// We want to control preemption here. +//@compile-flags: -Zmiri-preemption-rate=0 //@ignore-windows: Concurrency on Windows is not supported yet. #![feature(core_intrinsics)] diff --git a/tests/fail/weak_memory/racing_mixed_size_read.rs b/tests/fail/weak_memory/racing_mixed_size_read.rs index e87b6d6fd01f5..0eacaeeaa9ee8 100644 --- a/tests/fail/weak_memory/racing_mixed_size_read.rs +++ b/tests/fail/weak_memory/racing_mixed_size_read.rs @@ -1,3 +1,5 @@ +// We want to control preemption here. +//@compile-flags: -Zmiri-preemption-rate=0 //@ignore-windows: Concurrency on Windows is not supported yet. #![feature(core_intrinsics)] From f3496cbe4bf917032220b14a4bc4a89b406a5a85 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Mon, 11 Jul 2022 11:44:55 +0000 Subject: [PATCH 3458/3747] require level and colon in `//~` style comments --- tests/fail/alloc/reallocate-change-alloc.rs | 2 +- tests/fail/backtrace/bad-backtrace-decl.rs | 2 +- tests/fail/backtrace/bad-backtrace-flags.rs | 2 +- tests/fail/backtrace/bad-backtrace-ptr.rs | 2 +- .../backtrace/bad-backtrace-resolve-flags.rs | 2 +- .../bad-backtrace-resolve-names-flags.rs | 2 +- .../backtrace/bad-backtrace-size-flags.rs | 2 +- tests/fail/box-cell-alias.rs | 2 +- tests/fail/branchless-select-i128-pointer.rs | 2 +- tests/fail/breakpoint.rs | 2 +- .../thread_local_static_dealloc.rs | 2 +- tests/fail/concurrency/unwind_top_of_stack.rs | 2 +- .../dangling_pointer_addr_of.rs | 2 +- .../dangling_pointer_deref.rs | 2 +- .../dangling_pointers/dangling_zst_deref.rs | 2 +- .../dangling_pointers/deref-invalid-ptr.rs | 2 +- .../deref-partially-dangling.rs | 2 +- tests/fail/dangling_pointers/dyn_size.rs | 2 +- .../maybe_null_pointer_deref_zst.rs | 2 +- .../maybe_null_pointer_write_zst.rs | 2 +- .../dangling_pointers/null_pointer_deref.rs | 2 +- .../null_pointer_deref_zst.rs | 2 +- .../dangling_pointers/null_pointer_write.rs | 2 +- .../dangling_pointers/out_of_bounds_read1.rs | 2 +- .../dangling_pointers/out_of_bounds_read2.rs | 2 +- .../fail/dangling_pointers/stack_temporary.rs | 2 +- .../storage_dead_dangling.rs | 2 +- .../dangling_pointers/wild_pointer_deref.rs | 2 +- tests/fail/data_race/alloc_read_race.rs | 2 +- tests/fail/data_race/alloc_write_race.rs | 2 +- .../data_race/atomic_read_na_write_race1.rs | 2 +- .../data_race/atomic_read_na_write_race2.rs | 2 +- .../data_race/atomic_write_na_read_race1.rs | 2 +- .../data_race/atomic_write_na_read_race2.rs | 2 +- .../data_race/atomic_write_na_write_race1.rs | 2 +- .../data_race/atomic_write_na_write_race2.rs | 2 +- .../data_race/dangling_thread_async_race.rs | 2 +- tests/fail/data_race/dangling_thread_race.rs | 2 +- tests/fail/data_race/dealloc_read_race1.rs | 2 +- tests/fail/data_race/dealloc_read_race2.rs | 2 +- .../fail/data_race/dealloc_read_race_stack.rs | 2 +- tests/fail/data_race/dealloc_write_race1.rs | 2 +- tests/fail/data_race/dealloc_write_race2.rs | 2 +- .../data_race/dealloc_write_race_stack.rs | 2 +- .../data_race/enable_after_join_to_main.rs | 2 +- tests/fail/data_race/fence_after_load.rs | 2 +- tests/fail/data_race/read_write_race.rs | 2 +- tests/fail/data_race/read_write_race_stack.rs | 2 +- tests/fail/data_race/relax_acquire_race.rs | 2 +- tests/fail/data_race/release_seq_race.rs | 2 +- .../data_race/release_seq_race_same_thread.rs | 2 +- tests/fail/data_race/rmw_race.rs | 2 +- tests/fail/data_race/stack_pop_race.rs | 2 +- tests/fail/data_race/write_write_race.rs | 2 +- .../fail/data_race/write_write_race_stack.rs | 2 +- tests/fail/environ-gets-deallocated.rs | 2 +- tests/fail/erroneous_const.rs | 4 +- tests/fail/erroneous_const2.rs | 12 +-- tests/fail/extern_static.rs | 2 +- tests/fail/extern_static_in_const.rs | 2 +- tests/fail/fast_math_both.rs | 2 +- tests/fail/fast_math_first.rs | 2 +- tests/fail/fast_math_second.rs | 2 +- tests/fail/fs/close_stdout.rs | 2 +- tests/fail/fs/isolated_stdin.rs | 2 +- tests/fail/fs/read_from_stdout.rs | 2 +- .../fs/unix_open_missing_required_mode.rs | 2 +- tests/fail/fs/write_to_stdin.rs | 2 +- tests/fail/function_calls/check_arg_abi.rs | 2 +- .../function_calls/check_arg_count_abort.rs | 2 +- .../check_arg_count_too_few_args.rs | 2 +- .../check_arg_count_too_many_args.rs | 2 +- .../fail/function_calls/check_callback_abi.rs | 2 +- .../exported_symbol_abi_mismatch.rs | 6 +- .../exported_symbol_bad_unwind1.rs | 2 +- .../exported_symbol_bad_unwind2.both.stderr | 4 +- ...orted_symbol_bad_unwind2.definition.stderr | 4 +- .../exported_symbol_bad_unwind2.rs | 6 +- .../exported_symbol_clashing.rs | 6 +- .../exported_symbol_shim_clashing.rs | 4 +- .../exported_symbol_wrong_arguments.rs | 2 +- .../exported_symbol_wrong_type.rs | 2 +- .../cast_box_int_to_fn_ptr.rs | 2 +- tests/fail/function_pointers/cast_fn_ptr1.rs | 2 +- tests/fail/function_pointers/cast_fn_ptr2.rs | 2 +- tests/fail/function_pointers/cast_fn_ptr3.rs | 2 +- tests/fail/function_pointers/cast_fn_ptr4.rs | 2 +- tests/fail/function_pointers/cast_fn_ptr5.rs | 2 +- .../function_pointers/cast_int_to_fn_ptr.rs | 2 +- tests/fail/function_pointers/deref_fn_ptr.rs | 2 +- .../fail/function_pointers/execute_memory.rs | 2 +- tests/fail/function_pointers/fn_ptr_offset.rs | 2 +- tests/fail/generator-pinned-moved.rs | 2 +- tests/fail/intrinsics/assume.rs | 2 +- tests/fail/intrinsics/copy_overlapping.rs | 2 +- tests/fail/intrinsics/copy_unaligned.rs | 2 +- tests/fail/intrinsics/ctlz_nonzero.rs | 2 +- tests/fail/intrinsics/cttz_nonzero.rs | 2 +- tests/fail/intrinsics/div-by-zero.rs | 2 +- tests/fail/intrinsics/exact_div1.rs | 2 +- tests/fail/intrinsics/exact_div2.rs | 2 +- tests/fail/intrinsics/exact_div3.rs | 2 +- tests/fail/intrinsics/exact_div4.rs | 2 +- tests/fail/intrinsics/ptr_offset_from_oob.rs | 2 +- tests/fail/intrinsics/rem-by-zero.rs | 2 +- tests/fail/intrinsics/simd-div-by-zero.rs | 2 +- tests/fail/intrinsics/simd-div-overflow.rs | 2 +- .../intrinsics/simd-reduce-invalid-bool.rs | 2 +- tests/fail/intrinsics/simd-rem-by-zero.rs | 2 +- .../intrinsics/simd-select-bitmask-invalid.rs | 2 +- .../intrinsics/simd-select-invalid-bool.rs | 2 +- tests/fail/intrinsics/simd-shl-too-far.rs | 2 +- tests/fail/intrinsics/simd-shr-too-far.rs | 2 +- tests/fail/intrinsics/unchecked_add1.rs | 2 +- tests/fail/intrinsics/unchecked_add2.rs | 2 +- tests/fail/intrinsics/unchecked_div1.rs | 2 +- tests/fail/intrinsics/unchecked_mul1.rs | 2 +- tests/fail/intrinsics/unchecked_mul2.rs | 2 +- tests/fail/intrinsics/unchecked_sub1.rs | 2 +- tests/fail/intrinsics/unchecked_sub2.rs | 2 +- tests/fail/intrinsics/write_bytes_null.rs | 2 +- tests/fail/invalid_bool.rs | 2 +- tests/fail/invalid_char.rs | 2 +- tests/fail/invalid_int.rs | 2 +- tests/fail/issue-miri-1112.rs | 2 +- tests/fail/modifying_constants.rs | 2 +- tests/fail/never_say_never.rs | 2 +- tests/fail/never_transmute_humans.rs | 2 +- tests/fail/never_transmute_void.rs | 5 +- tests/fail/panic/bad_miri_start_panic.rs | 2 +- tests/fail/panic/unwind_panic_abort.rs | 2 +- tests/fail/pointer_partial_overwrite.rs | 2 +- tests/fail/provenance/provenance_transmute.rs | 2 +- tests/fail/provenance/ptr_int_unexposed.rs | 2 +- tests/fail/provenance/ptr_invalid.rs | 2 +- .../fail/provenance/strict_provenance_cast.rs | 2 +- tests/fail/rc_as_ptr.rs | 2 +- tests/fail/reading_half_a_pointer.rs | 2 +- tests/fail/rustc-error.rs | 2 +- tests/fail/shim_arg_size.rs | 2 +- .../stacked_borrows/alias_through_mutation.rs | 2 +- tests/fail/stacked_borrows/aliasing_mut1.rs | 2 +- tests/fail/stacked_borrows/aliasing_mut2.rs | 2 +- tests/fail/stacked_borrows/aliasing_mut3.rs | 2 +- tests/fail/stacked_borrows/aliasing_mut4.rs | 2 +- .../box_exclusive_violation1.rs | 2 +- .../stacked_borrows/buggy_as_mut_slice.rs | 2 +- .../stacked_borrows/buggy_split_at_mut.rs | 2 +- tests/fail/stacked_borrows/illegal_read4.rs | 2 +- tests/fail/stacked_borrows/illegal_read5.rs | 2 +- tests/fail/stacked_borrows/illegal_read6.rs | 2 +- tests/fail/stacked_borrows/illegal_read7.rs | 2 +- tests/fail/stacked_borrows/illegal_read8.rs | 2 +- tests/fail/stacked_borrows/illegal_write1.rs | 2 +- tests/fail/stacked_borrows/illegal_write2.rs | 2 +- tests/fail/stacked_borrows/illegal_write3.rs | 2 +- tests/fail/stacked_borrows/illegal_write4.rs | 2 +- tests/fail/stacked_borrows/interior_mut1.rs | 2 +- tests/fail/stacked_borrows/interior_mut2.rs | 2 +- .../invalidate_against_barrier1.rs | 2 +- .../invalidate_against_barrier2.rs | 2 +- .../fail/stacked_borrows/load_invalid_mut.rs | 2 +- .../fail/stacked_borrows/load_invalid_shr.rs | 2 +- .../mut_exclusive_violation1.rs | 2 +- .../mut_exclusive_violation2.rs | 2 +- tests/fail/stacked_borrows/outdated_local.rs | 2 +- .../fail/stacked_borrows/pass_invalid_mut.rs | 2 +- .../fail/stacked_borrows/pass_invalid_shr.rs | 2 +- .../fail/stacked_borrows/pointer_smuggling.rs | 2 +- tests/fail/stacked_borrows/raw_tracking.rs | 2 +- .../stacked_borrows/return_invalid_mut.rs | 2 +- .../return_invalid_mut_option.rs | 2 +- .../stacked_borrows/return_invalid_shr.rs | 2 +- .../return_invalid_shr_option.rs | 2 +- .../return_invalid_shr_tuple.rs | 2 +- .../shared_rw_borrows_are_weak1.rs | 2 +- .../shared_rw_borrows_are_weak2.rs | 2 +- .../stacked_borrows/shr_frozen_violation1.rs | 2 +- .../static_memory_modification.rs | 2 +- .../stacked_borrows/transmute-is-no-escape.rs | 2 +- tests/fail/stacked_borrows/unescaped_local.rs | 2 +- .../fail/stacked_borrows/unescaped_static.rs | 2 +- tests/fail/static_memory_modification1.rs | 2 +- tests/fail/static_memory_modification2.rs | 2 +- tests/fail/static_memory_modification3.rs | 2 +- .../sync/libc_pthread_cond_double_destroy.rs | 2 +- .../libc_pthread_condattr_double_destroy.rs | 2 +- .../sync/libc_pthread_mutex_NULL_deadlock.rs | 2 +- .../libc_pthread_mutex_default_deadlock.rs | 2 +- .../sync/libc_pthread_mutex_destroy_locked.rs | 2 +- .../sync/libc_pthread_mutex_double_destroy.rs | 2 +- .../libc_pthread_mutex_normal_deadlock.rs | 2 +- ...bc_pthread_mutex_normal_unlock_unlocked.rs | 2 +- .../libc_pthread_mutexattr_double_destroy.rs | 2 +- ...libc_pthread_rwlock_destroy_read_locked.rs | 2 +- ...ibc_pthread_rwlock_destroy_write_locked.rs | 2 +- .../libc_pthread_rwlock_double_destroy.rs | 2 +- .../libc_pthread_rwlock_unlock_unlocked.rs | 2 +- tests/fail/transmute-pair-uninit.rs | 2 +- tests/fail/type-too-large.rs | 2 +- .../unaligned_pointers/atomic_unaligned.rs | 2 +- .../fail/unaligned_pointers/dyn_alignment.rs | 2 +- .../intptrcast_alignment_check.rs | 2 +- .../unaligned_pointers/reference_to_packed.rs | 2 +- .../fail/unaligned_pointers/unaligned_ptr1.rs | 2 +- .../fail/unaligned_pointers/unaligned_ptr2.rs | 2 +- .../fail/unaligned_pointers/unaligned_ptr3.rs | 2 +- .../fail/unaligned_pointers/unaligned_ptr4.rs | 2 +- .../unaligned_ptr_addr_of.rs | 2 +- .../unaligned_pointers/unaligned_ptr_zst.rs | 2 +- tests/fail/uninit_byte_read.rs | 2 +- tests/fail/uninit_raw_ptr.rs | 2 +- tests/fail/unsized-local.rs | 2 +- tests/fail/unsupported_foreign_function.rs | 2 +- tests/fail/unsupported_signal.rs | 2 +- tests/fail/validity/cast_fn_ptr1.rs | 2 +- tests/fail/validity/cast_fn_ptr2.rs | 2 +- tests/fail/validity/dangling_ref1.rs | 2 +- tests/fail/validity/dangling_ref2.rs | 2 +- tests/fail/validity/dangling_ref3.rs | 2 +- tests/fail/validity/invalid_bool.rs | 2 +- tests/fail/validity/invalid_bool_uninit.rs | 2 +- tests/fail/validity/invalid_char.rs | 2 +- tests/fail/validity/invalid_char_uninit.rs | 2 +- tests/fail/validity/invalid_enum_tag.rs | 2 +- .../invalid_enum_tag_256variants_uninit.rs | 2 +- tests/fail/validity/invalid_fnptr_null.rs | 2 +- tests/fail/validity/invalid_fnptr_uninit.rs | 2 +- tests/fail/validity/nonzero.rs | 2 +- .../validity/ptr_integer_array_transmute.rs | 2 +- tests/fail/validity/ref_to_uninhabited1.rs | 2 +- tests/fail/validity/ref_to_uninhabited2.rs | 2 +- tests/fail/validity/transmute_through_ptr.rs | 2 +- tests/fail/validity/uninit_float.rs | 2 +- tests/fail/validity/uninit_integer.rs | 2 +- tests/fail/validity/uninit_integer_signed.rs | 2 +- tests/fail/zst1.rs | 2 +- tests/fail/zst2.rs | 2 +- tests/fail/zst3.rs | 2 +- ui_test/src/lib.rs | 40 +++---- ui_test/src/parser.rs | 31 ++++-- ui_test/src/parser/tests.rs | 46 ++++---- ui_test/src/rustc_stderr.rs | 5 +- ui_test/src/tests.rs | 101 +++++------------- 244 files changed, 348 insertions(+), 386 deletions(-) diff --git a/tests/fail/alloc/reallocate-change-alloc.rs b/tests/fail/alloc/reallocate-change-alloc.rs index 14d05e7457512..3ad56da2c2fff 100644 --- a/tests/fail/alloc/reallocate-change-alloc.rs +++ b/tests/fail/alloc/reallocate-change-alloc.rs @@ -4,6 +4,6 @@ fn main() { unsafe { let x = alloc(Layout::from_size_align_unchecked(1, 1)); let _y = realloc(x, Layout::from_size_align_unchecked(1, 1), 1); - let _z = *x; //~ ERROR dereferenced after this allocation got freed + let _z = *x; //~ ERROR: dereferenced after this allocation got freed } } diff --git a/tests/fail/backtrace/bad-backtrace-decl.rs b/tests/fail/backtrace/bad-backtrace-decl.rs index 23379992d5ecb..97a70103e6461 100644 --- a/tests/fail/backtrace/bad-backtrace-decl.rs +++ b/tests/fail/backtrace/bad-backtrace-decl.rs @@ -7,7 +7,7 @@ fn main() { let frames = unsafe { miri_get_backtrace(0) }; for frame in frames.into_iter() { unsafe { - miri_resolve_frame(*frame, 0); //~ ERROR Undefined Behavior: bad declaration of miri_resolve_frame - should return a struct with 5 fields + miri_resolve_frame(*frame, 0); //~ ERROR: Undefined Behavior: bad declaration of miri_resolve_frame - should return a struct with 5 fields } } } diff --git a/tests/fail/backtrace/bad-backtrace-flags.rs b/tests/fail/backtrace/bad-backtrace-flags.rs index 9e24d32a33310..a4e186eaa98a4 100644 --- a/tests/fail/backtrace/bad-backtrace-flags.rs +++ b/tests/fail/backtrace/bad-backtrace-flags.rs @@ -4,6 +4,6 @@ extern "Rust" { fn main() { unsafe { - miri_get_backtrace(2, std::ptr::null_mut()); //~ ERROR unsupported operation: unknown `miri_get_backtrace` flags 2 + miri_get_backtrace(2, std::ptr::null_mut()); //~ ERROR: unsupported operation: unknown `miri_get_backtrace` flags 2 } } diff --git a/tests/fail/backtrace/bad-backtrace-ptr.rs b/tests/fail/backtrace/bad-backtrace-ptr.rs index a435b0a69578c..843d0d11873d2 100644 --- a/tests/fail/backtrace/bad-backtrace-ptr.rs +++ b/tests/fail/backtrace/bad-backtrace-ptr.rs @@ -4,6 +4,6 @@ extern "Rust" { fn main() { unsafe { - miri_resolve_frame(std::ptr::null_mut(), 0); //~ ERROR null pointer is a dangling pointer + miri_resolve_frame(std::ptr::null_mut(), 0); //~ ERROR: null pointer is a dangling pointer } } diff --git a/tests/fail/backtrace/bad-backtrace-resolve-flags.rs b/tests/fail/backtrace/bad-backtrace-resolve-flags.rs index 2d4d6195029d1..31e3915f3d64f 100644 --- a/tests/fail/backtrace/bad-backtrace-resolve-flags.rs +++ b/tests/fail/backtrace/bad-backtrace-resolve-flags.rs @@ -20,6 +20,6 @@ fn main() { miri_get_backtrace(1, buf.as_mut_ptr()); // miri_resolve_frame will error from an invalid backtrace before it will from invalid flags - miri_resolve_frame(buf[0], 2); //~ ERROR unsupported operation: unknown `miri_resolve_frame` flags 2 + miri_resolve_frame(buf[0], 2); //~ ERROR: unsupported operation: unknown `miri_resolve_frame` flags 2 } } diff --git a/tests/fail/backtrace/bad-backtrace-resolve-names-flags.rs b/tests/fail/backtrace/bad-backtrace-resolve-names-flags.rs index 6cea1fec1b241..44c3c025043b6 100644 --- a/tests/fail/backtrace/bad-backtrace-resolve-names-flags.rs +++ b/tests/fail/backtrace/bad-backtrace-resolve-names-flags.rs @@ -11,6 +11,6 @@ fn main() { miri_get_backtrace(1, buf.as_mut_ptr()); // miri_resolve_frame_names will error from an invalid backtrace before it will from invalid flags - miri_resolve_frame_names(buf[0], 2, std::ptr::null_mut(), std::ptr::null_mut()); //~ ERROR unsupported operation: unknown `miri_resolve_frame_names` flags 2 + miri_resolve_frame_names(buf[0], 2, std::ptr::null_mut(), std::ptr::null_mut()); //~ ERROR: unsupported operation: unknown `miri_resolve_frame_names` flags 2 } } diff --git a/tests/fail/backtrace/bad-backtrace-size-flags.rs b/tests/fail/backtrace/bad-backtrace-size-flags.rs index 25eded9e48df7..bba74c71a5e8f 100644 --- a/tests/fail/backtrace/bad-backtrace-size-flags.rs +++ b/tests/fail/backtrace/bad-backtrace-size-flags.rs @@ -4,6 +4,6 @@ extern "Rust" { fn main() { unsafe { - miri_backtrace_size(2); //~ ERROR unsupported operation: unknown `miri_backtrace_size` flags 2 + miri_backtrace_size(2); //~ ERROR: unsupported operation: unknown `miri_backtrace_size` flags 2 } } diff --git a/tests/fail/box-cell-alias.rs b/tests/fail/box-cell-alias.rs index 319845d86a63b..1a4a3b97ea3ff 100644 --- a/tests/fail/box-cell-alias.rs +++ b/tests/fail/box-cell-alias.rs @@ -6,7 +6,7 @@ use std::cell::Cell; fn helper(val: Box>, ptr: *const Cell) -> u8 { val.set(10); - unsafe { (*ptr).set(20) }; //~ ERROR does not exist in the borrow stack + unsafe { (*ptr).set(20) }; //~ ERROR: does not exist in the borrow stack val.get() } diff --git a/tests/fail/branchless-select-i128-pointer.rs b/tests/fail/branchless-select-i128-pointer.rs index a3b4021ba0c2a..2b861e5447b03 100644 --- a/tests/fail/branchless-select-i128-pointer.rs +++ b/tests/fail/branchless-select-i128-pointer.rs @@ -12,7 +12,7 @@ fn main() { // However, it drops provenance when transmuting to TwoPtrs, so this is UB. let val = unsafe { transmute::<_, &str>( - //~^ ERROR constructing invalid value: encountered a dangling reference + //~^ ERROR: constructing invalid value: encountered a dangling reference !mask & transmute::<_, TwoPtrs>("false !") | mask & transmute::<_, TwoPtrs>("true !"), ) diff --git a/tests/fail/breakpoint.rs b/tests/fail/breakpoint.rs index d0a0239eb933b..fb1d4d958ee6b 100644 --- a/tests/fail/breakpoint.rs +++ b/tests/fail/breakpoint.rs @@ -2,6 +2,6 @@ fn main() { unsafe { - core::intrinsics::breakpoint() //~ ERROR Trace/breakpoint trap + core::intrinsics::breakpoint() //~ ERROR: Trace/breakpoint trap }; } diff --git a/tests/fail/concurrency/thread_local_static_dealloc.rs b/tests/fail/concurrency/thread_local_static_dealloc.rs index 8cca1eba2d86c..f638e21901dd7 100644 --- a/tests/fail/concurrency/thread_local_static_dealloc.rs +++ b/tests/fail/concurrency/thread_local_static_dealloc.rs @@ -13,6 +13,6 @@ unsafe impl Send for SendRaw {} fn main() { unsafe { let dangling_ptr = std::thread::spawn(|| SendRaw(&TLS as *const u8)).join().unwrap(); - let _val = *dangling_ptr.0; //~ ERROR dereferenced after this allocation got freed + let _val = *dangling_ptr.0; //~ ERROR: dereferenced after this allocation got freed } } diff --git a/tests/fail/concurrency/unwind_top_of_stack.rs b/tests/fail/concurrency/unwind_top_of_stack.rs index d5dfcd0871d81..3bd9284c7c8a2 100644 --- a/tests/fail/concurrency/unwind_top_of_stack.rs +++ b/tests/fail/concurrency/unwind_top_of_stack.rs @@ -10,7 +10,7 @@ extern crate libc; use std::{mem, ptr}; extern "C-unwind" fn thread_start(_null: *mut libc::c_void) -> *mut libc::c_void { - //~^ ERROR unwinding past the topmost frame of the stack + //~^ ERROR: unwinding past the topmost frame of the stack panic!() } diff --git a/tests/fail/dangling_pointers/dangling_pointer_addr_of.rs b/tests/fail/dangling_pointers/dangling_pointer_addr_of.rs index a38a44c18f47f..4249c1cbf0177 100644 --- a/tests/fail/dangling_pointers/dangling_pointer_addr_of.rs +++ b/tests/fail/dangling_pointers/dangling_pointer_addr_of.rs @@ -7,6 +7,6 @@ fn main() { let b = Box::new(42); &*b as *const i32 }; - let x = unsafe { ptr::addr_of!(*p) }; //~ ERROR dereferenced after this allocation got freed + let x = unsafe { ptr::addr_of!(*p) }; //~ ERROR: dereferenced after this allocation got freed panic!("this should never print: {:?}", x); } diff --git a/tests/fail/dangling_pointers/dangling_pointer_deref.rs b/tests/fail/dangling_pointers/dangling_pointer_deref.rs index 55b5205a8b301..ad2a599b60b48 100644 --- a/tests/fail/dangling_pointers/dangling_pointer_deref.rs +++ b/tests/fail/dangling_pointers/dangling_pointer_deref.rs @@ -6,6 +6,6 @@ fn main() { let b = Box::new(42); &*b as *const i32 }; - let x = unsafe { *p }; //~ ERROR dereferenced after this allocation got freed + let x = unsafe { *p }; //~ ERROR: dereferenced after this allocation got freed panic!("this should never print: {}", x); } diff --git a/tests/fail/dangling_pointers/dangling_zst_deref.rs b/tests/fail/dangling_pointers/dangling_zst_deref.rs index 2a09dc4b0e891..534d7d5f42f32 100644 --- a/tests/fail/dangling_pointers/dangling_zst_deref.rs +++ b/tests/fail/dangling_pointers/dangling_zst_deref.rs @@ -7,5 +7,5 @@ fn main() { let b = Box::new(42); &*b as *const i32 as *const () }; - let _x = unsafe { *p }; //~ ERROR dereferenced after this allocation got freed + let _x = unsafe { *p }; //~ ERROR: dereferenced after this allocation got freed } diff --git a/tests/fail/dangling_pointers/deref-invalid-ptr.rs b/tests/fail/dangling_pointers/deref-invalid-ptr.rs index 924021e8cb93a..57e95ef19dc99 100644 --- a/tests/fail/dangling_pointers/deref-invalid-ptr.rs +++ b/tests/fail/dangling_pointers/deref-invalid-ptr.rs @@ -3,5 +3,5 @@ fn main() { let x = 16usize as *const u32; - let _y = unsafe { &*x as *const u32 }; //~ ERROR is a dangling pointer + let _y = unsafe { &*x as *const u32 }; //~ ERROR: is a dangling pointer } diff --git a/tests/fail/dangling_pointers/deref-partially-dangling.rs b/tests/fail/dangling_pointers/deref-partially-dangling.rs index b7fcf4559e0ad..27040c26dc212 100644 --- a/tests/fail/dangling_pointers/deref-partially-dangling.rs +++ b/tests/fail/dangling_pointers/deref-partially-dangling.rs @@ -3,6 +3,6 @@ fn main() { let x = (1, 13); let xptr = &x as *const _ as *const (i32, i32, i32); - let val = unsafe { (*xptr).1 }; //~ ERROR pointer to 12 bytes starting at offset 0 is out-of-bounds + let val = unsafe { (*xptr).1 }; //~ ERROR: pointer to 12 bytes starting at offset 0 is out-of-bounds assert_eq!(val, 13); } diff --git a/tests/fail/dangling_pointers/dyn_size.rs b/tests/fail/dangling_pointers/dyn_size.rs index adb7febe5074e..54f353ebebeb1 100644 --- a/tests/fail/dangling_pointers/dyn_size.rs +++ b/tests/fail/dangling_pointers/dyn_size.rs @@ -9,5 +9,5 @@ fn main() { // That should be UB, as the reference is not fully dereferencable. let ptr: *const SliceWithHead = unsafe { std::mem::transmute((&buf, 4usize)) }; // Re-borrow that. This should be UB. - let _ptr = unsafe { &*ptr }; //~ ERROR pointer to 5 bytes starting at offset 0 is out-of-bounds + let _ptr = unsafe { &*ptr }; //~ ERROR: pointer to 5 bytes starting at offset 0 is out-of-bounds } diff --git a/tests/fail/dangling_pointers/maybe_null_pointer_deref_zst.rs b/tests/fail/dangling_pointers/maybe_null_pointer_deref_zst.rs index 37fb91e28f298..a48a3189db2e3 100644 --- a/tests/fail/dangling_pointers/maybe_null_pointer_deref_zst.rs +++ b/tests/fail/dangling_pointers/maybe_null_pointer_deref_zst.rs @@ -4,5 +4,5 @@ fn main() { // This pointer *could* be NULL so we cannot load from it, not even at ZST let ptr = (&0u8 as *const u8).wrapping_sub(0x800) as *const (); - let _x: () = unsafe { *ptr }; //~ ERROR out-of-bounds + let _x: () = unsafe { *ptr }; //~ ERROR: out-of-bounds } diff --git a/tests/fail/dangling_pointers/maybe_null_pointer_write_zst.rs b/tests/fail/dangling_pointers/maybe_null_pointer_write_zst.rs index de8034bbbac3c..449c65d218a02 100644 --- a/tests/fail/dangling_pointers/maybe_null_pointer_write_zst.rs +++ b/tests/fail/dangling_pointers/maybe_null_pointer_write_zst.rs @@ -7,5 +7,5 @@ fn main() { // Also not assigning directly as that's array initialization, not assignment. let zst_val = [1u8; 0]; let ptr = (&0u8 as *const u8).wrapping_sub(0x800) as *mut [u8; 0]; - unsafe { *ptr = zst_val }; //~ ERROR out-of-bounds + unsafe { *ptr = zst_val }; //~ ERROR: out-of-bounds } diff --git a/tests/fail/dangling_pointers/null_pointer_deref.rs b/tests/fail/dangling_pointers/null_pointer_deref.rs index dad6de85e002d..a0773c63cf6bf 100644 --- a/tests/fail/dangling_pointers/null_pointer_deref.rs +++ b/tests/fail/dangling_pointers/null_pointer_deref.rs @@ -1,5 +1,5 @@ #[allow(deref_nullptr)] fn main() { - let x: i32 = unsafe { *std::ptr::null() }; //~ ERROR null pointer is a dangling pointer + let x: i32 = unsafe { *std::ptr::null() }; //~ ERROR: null pointer is a dangling pointer panic!("this should never print: {}", x); } diff --git a/tests/fail/dangling_pointers/null_pointer_deref_zst.rs b/tests/fail/dangling_pointers/null_pointer_deref_zst.rs index 1f73983a81619..d6a607c61cbeb 100644 --- a/tests/fail/dangling_pointers/null_pointer_deref_zst.rs +++ b/tests/fail/dangling_pointers/null_pointer_deref_zst.rs @@ -3,6 +3,6 @@ #[allow(deref_nullptr)] fn main() { - let x: () = unsafe { *std::ptr::null() }; //~ ERROR dereferencing pointer failed: null pointer is a dangling pointer + let x: () = unsafe { *std::ptr::null() }; //~ ERROR: dereferencing pointer failed: null pointer is a dangling pointer panic!("this should never print: {:?}", x); } diff --git a/tests/fail/dangling_pointers/null_pointer_write.rs b/tests/fail/dangling_pointers/null_pointer_write.rs index c7255baf6642d..954596f57542e 100644 --- a/tests/fail/dangling_pointers/null_pointer_write.rs +++ b/tests/fail/dangling_pointers/null_pointer_write.rs @@ -1,4 +1,4 @@ #[allow(deref_nullptr)] fn main() { - unsafe { *std::ptr::null_mut() = 0i32 }; //~ ERROR null pointer is a dangling pointer + unsafe { *std::ptr::null_mut() = 0i32 }; //~ ERROR: null pointer is a dangling pointer } diff --git a/tests/fail/dangling_pointers/out_of_bounds_read1.rs b/tests/fail/dangling_pointers/out_of_bounds_read1.rs index ef5cdeec99677..58a64eecace8c 100644 --- a/tests/fail/dangling_pointers/out_of_bounds_read1.rs +++ b/tests/fail/dangling_pointers/out_of_bounds_read1.rs @@ -1,5 +1,5 @@ fn main() { let v: Vec = vec![1, 2]; - let x = unsafe { *v.as_ptr().wrapping_offset(5) }; //~ ERROR out-of-bounds + let x = unsafe { *v.as_ptr().wrapping_offset(5) }; //~ ERROR: out-of-bounds panic!("this should never print: {}", x); } diff --git a/tests/fail/dangling_pointers/out_of_bounds_read2.rs b/tests/fail/dangling_pointers/out_of_bounds_read2.rs index ef5cdeec99677..58a64eecace8c 100644 --- a/tests/fail/dangling_pointers/out_of_bounds_read2.rs +++ b/tests/fail/dangling_pointers/out_of_bounds_read2.rs @@ -1,5 +1,5 @@ fn main() { let v: Vec = vec![1, 2]; - let x = unsafe { *v.as_ptr().wrapping_offset(5) }; //~ ERROR out-of-bounds + let x = unsafe { *v.as_ptr().wrapping_offset(5) }; //~ ERROR: out-of-bounds panic!("this should never print: {}", x); } diff --git a/tests/fail/dangling_pointers/stack_temporary.rs b/tests/fail/dangling_pointers/stack_temporary.rs index dc446ca4b3c81..1373773f68d59 100644 --- a/tests/fail/dangling_pointers/stack_temporary.rs +++ b/tests/fail/dangling_pointers/stack_temporary.rs @@ -8,7 +8,7 @@ unsafe fn make_ref<'a>(x: *mut i32) -> &'a mut i32 { fn main() { unsafe { let x = make_ref(&mut 0); // The temporary storing "0" is deallocated at the ";"! - let val = *x; //~ ERROR dereferenced after this allocation got freed + let val = *x; //~ ERROR: dereferenced after this allocation got freed println!("{}", val); } } diff --git a/tests/fail/dangling_pointers/storage_dead_dangling.rs b/tests/fail/dangling_pointers/storage_dead_dangling.rs index 10c6e7f97d2ee..03113585d1464 100644 --- a/tests/fail/dangling_pointers/storage_dead_dangling.rs +++ b/tests/fail/dangling_pointers/storage_dead_dangling.rs @@ -10,7 +10,7 @@ fn fill(v: &mut i32) { } fn evil() { - unsafe { &mut *(LEAK as *mut i32) }; //~ ERROR is a dangling pointer + unsafe { &mut *(LEAK as *mut i32) }; //~ ERROR: is a dangling pointer } fn main() { diff --git a/tests/fail/dangling_pointers/wild_pointer_deref.rs b/tests/fail/dangling_pointers/wild_pointer_deref.rs index 15d71a6bcccd2..9ffc681465504 100644 --- a/tests/fail/dangling_pointers/wild_pointer_deref.rs +++ b/tests/fail/dangling_pointers/wild_pointer_deref.rs @@ -2,6 +2,6 @@ fn main() { let p = 44 as *const i32; - let x = unsafe { *p }; //~ ERROR is a dangling pointer + let x = unsafe { *p }; //~ ERROR: is a dangling pointer panic!("this should never print: {}", x); } diff --git a/tests/fail/data_race/alloc_read_race.rs b/tests/fail/data_race/alloc_read_race.rs index e3c003a343a04..bdd38ea056933 100644 --- a/tests/fail/data_race/alloc_read_race.rs +++ b/tests/fail/data_race/alloc_read_race.rs @@ -38,7 +38,7 @@ pub fn main() { let pointer = &*ptr.0; // Note: could also error due to reading uninitialized memory, but the data-race detector triggers first. - *pointer.load(Ordering::Relaxed) //~ ERROR Data race detected between Read on thread `` and Allocate on thread `` + *pointer.load(Ordering::Relaxed) //~ ERROR: Data race detected between Read on thread `` and Allocate on thread `` }); j1.join().unwrap(); diff --git a/tests/fail/data_race/alloc_write_race.rs b/tests/fail/data_race/alloc_write_race.rs index 4ad03ee87dda3..1322f727e6f01 100644 --- a/tests/fail/data_race/alloc_write_race.rs +++ b/tests/fail/data_race/alloc_write_race.rs @@ -36,7 +36,7 @@ pub fn main() { let j2 = spawn(move || { let pointer = &*ptr.0; - *pointer.load(Ordering::Relaxed) = 2; //~ ERROR Data race detected between Write on thread `` and Allocate on thread `` + *pointer.load(Ordering::Relaxed) = 2; //~ ERROR: Data race detected between Write on thread `` and Allocate on thread `` }); j1.join().unwrap(); diff --git a/tests/fail/data_race/atomic_read_na_write_race1.rs b/tests/fail/data_race/atomic_read_na_write_race1.rs index ada25173f255f..3cdb9d4a6543e 100644 --- a/tests/fail/data_race/atomic_read_na_write_race1.rs +++ b/tests/fail/data_race/atomic_read_na_write_race1.rs @@ -24,7 +24,7 @@ pub fn main() { let j2 = spawn(move || { //Equivalent to: (&*c.0).load(Ordering::SeqCst) - intrinsics::atomic_load_seqcst(c.0 as *mut usize) //~ ERROR Data race detected between Atomic Load on thread `` and Write on thread `` + intrinsics::atomic_load_seqcst(c.0 as *mut usize) //~ ERROR: Data race detected between Atomic Load on thread `` and Write on thread `` }); j1.join().unwrap(); diff --git a/tests/fail/data_race/atomic_read_na_write_race2.rs b/tests/fail/data_race/atomic_read_na_write_race2.rs index b355e4816dde1..79f9cceb5c9c6 100644 --- a/tests/fail/data_race/atomic_read_na_write_race2.rs +++ b/tests/fail/data_race/atomic_read_na_write_race2.rs @@ -24,7 +24,7 @@ pub fn main() { let j2 = spawn(move || { let atomic_ref = &mut *c.0; - *atomic_ref.get_mut() = 32; //~ ERROR Data race detected between Write on thread `` and Atomic Load on thread `` + *atomic_ref.get_mut() = 32; //~ ERROR: Data race detected between Write on thread `` and Atomic Load on thread `` }); j1.join().unwrap(); diff --git a/tests/fail/data_race/atomic_write_na_read_race1.rs b/tests/fail/data_race/atomic_write_na_read_race1.rs index 53305c68cb766..6e9f37a9c43bd 100644 --- a/tests/fail/data_race/atomic_write_na_read_race1.rs +++ b/tests/fail/data_race/atomic_write_na_read_race1.rs @@ -24,7 +24,7 @@ pub fn main() { let j2 = spawn(move || { let atomic_ref = &mut *c.0; - *atomic_ref.get_mut() //~ ERROR Data race detected between Read on thread `` and Atomic Store on thread `` + *atomic_ref.get_mut() //~ ERROR: Data race detected between Read on thread `` and Atomic Store on thread `` }); j1.join().unwrap(); diff --git a/tests/fail/data_race/atomic_write_na_read_race2.rs b/tests/fail/data_race/atomic_write_na_read_race2.rs index 21b0abbcaba97..4ab5abd5a3ee2 100644 --- a/tests/fail/data_race/atomic_write_na_read_race2.rs +++ b/tests/fail/data_race/atomic_write_na_read_race2.rs @@ -24,7 +24,7 @@ pub fn main() { let j2 = spawn(move || { //Equivalent to: (&*c.0).store(32, Ordering::SeqCst) - atomic_store(c.0 as *mut usize, 32); //~ ERROR Data race detected between Atomic Store on thread `` and Read on thread `` + atomic_store(c.0 as *mut usize, 32); //~ ERROR: Data race detected between Atomic Store on thread `` and Read on thread `` }); j1.join().unwrap(); diff --git a/tests/fail/data_race/atomic_write_na_write_race1.rs b/tests/fail/data_race/atomic_write_na_write_race1.rs index a8ac18f32136c..4c4ec0865cc90 100644 --- a/tests/fail/data_race/atomic_write_na_write_race1.rs +++ b/tests/fail/data_race/atomic_write_na_write_race1.rs @@ -24,7 +24,7 @@ pub fn main() { let j2 = spawn(move || { //Equivalent to: (&*c.0).store(64, Ordering::SeqCst) - atomic_store(c.0 as *mut usize, 64); //~ ERROR Data race detected between Atomic Store on thread `` and Write on thread `` + atomic_store(c.0 as *mut usize, 64); //~ ERROR: Data race detected between Atomic Store on thread `` and Write on thread `` }); j1.join().unwrap(); diff --git a/tests/fail/data_race/atomic_write_na_write_race2.rs b/tests/fail/data_race/atomic_write_na_write_race2.rs index e3b3e226d8c73..715c2d44b2607 100644 --- a/tests/fail/data_race/atomic_write_na_write_race2.rs +++ b/tests/fail/data_race/atomic_write_na_write_race2.rs @@ -24,7 +24,7 @@ pub fn main() { let j2 = spawn(move || { let atomic_ref = &mut *c.0; - *atomic_ref.get_mut() = 32; //~ ERROR Data race detected between Write on thread `` and Atomic Store on thread `` + *atomic_ref.get_mut() = 32; //~ ERROR: Data race detected between Write on thread `` and Atomic Store on thread `` }); j1.join().unwrap(); diff --git a/tests/fail/data_race/dangling_thread_async_race.rs b/tests/fail/data_race/dangling_thread_async_race.rs index be06740201d2a..732e89c89907c 100644 --- a/tests/fail/data_race/dangling_thread_async_race.rs +++ b/tests/fail/data_race/dangling_thread_async_race.rs @@ -35,7 +35,7 @@ fn main() { let join2 = unsafe { spawn(move || { - *c.0 = 64; //~ ERROR Data race detected between Write on thread `` and Write on thread `` + *c.0 = 64; //~ ERROR: Data race detected between Write on thread `` and Write on thread `` }) }; diff --git a/tests/fail/data_race/dangling_thread_race.rs b/tests/fail/data_race/dangling_thread_race.rs index 90957e4026e3e..170fa8b774401 100644 --- a/tests/fail/data_race/dangling_thread_race.rs +++ b/tests/fail/data_race/dangling_thread_race.rs @@ -34,6 +34,6 @@ fn main() { spawn(|| ()).join().unwrap(); unsafe { - *c.0 = 64; //~ ERROR Data race detected between Write on thread `main` and Write on thread `` + *c.0 = 64; //~ ERROR: Data race detected between Write on thread `main` and Write on thread `` } } diff --git a/tests/fail/data_race/dealloc_read_race1.rs b/tests/fail/data_race/dealloc_read_race1.rs index b37f4fda2bd4b..80a0fe2111ec6 100644 --- a/tests/fail/data_race/dealloc_read_race1.rs +++ b/tests/fail/data_race/dealloc_read_race1.rs @@ -26,7 +26,7 @@ pub fn main() { let j2 = spawn(move || { __rust_dealloc( - //~^ ERROR Data race detected between Deallocate on thread `` and Read on thread `` + //~^ ERROR: Data race detected between Deallocate on thread `` and Read on thread `` ptr.0 as *mut _, std::mem::size_of::(), std::mem::align_of::(), diff --git a/tests/fail/data_race/dealloc_read_race2.rs b/tests/fail/data_race/dealloc_read_race2.rs index 280b86924be81..898588a1a0e88 100644 --- a/tests/fail/data_race/dealloc_read_race2.rs +++ b/tests/fail/data_race/dealloc_read_race2.rs @@ -31,7 +31,7 @@ pub fn main() { let j2 = spawn(move || { // Also an error of the form: Data race detected between Read on thread `` and Deallocate on thread `` // but the invalid allocation is detected first. - *ptr.0 //~ ERROR dereferenced after this allocation got freed + *ptr.0 //~ ERROR: dereferenced after this allocation got freed }); j1.join().unwrap(); diff --git a/tests/fail/data_race/dealloc_read_race_stack.rs b/tests/fail/data_race/dealloc_read_race_stack.rs index a43c96a6701e6..475379a02ecfe 100644 --- a/tests/fail/data_race/dealloc_read_race_stack.rs +++ b/tests/fail/data_race/dealloc_read_race_stack.rs @@ -36,7 +36,7 @@ pub fn main() { sleep(Duration::from_millis(200)); // Now `stack_var` gets deallocated. - } //~ ERROR Data race detected between Deallocate on thread `` and Read on thread `` + } //~ ERROR: Data race detected between Deallocate on thread `` and Read on thread `` }); let j2 = spawn(move || { diff --git a/tests/fail/data_race/dealloc_write_race1.rs b/tests/fail/data_race/dealloc_write_race1.rs index 17fb444f9c63d..711b7ba9d4eb7 100644 --- a/tests/fail/data_race/dealloc_write_race1.rs +++ b/tests/fail/data_race/dealloc_write_race1.rs @@ -25,7 +25,7 @@ pub fn main() { let j2 = spawn(move || { __rust_dealloc( - //~^ ERROR Data race detected between Deallocate on thread `` and Write on thread `` + //~^ ERROR: Data race detected between Deallocate on thread `` and Write on thread `` ptr.0 as *mut _, std::mem::size_of::(), std::mem::align_of::(), diff --git a/tests/fail/data_race/dealloc_write_race2.rs b/tests/fail/data_race/dealloc_write_race2.rs index 6afb1182a029a..e7b7d558ed9df 100644 --- a/tests/fail/data_race/dealloc_write_race2.rs +++ b/tests/fail/data_race/dealloc_write_race2.rs @@ -30,7 +30,7 @@ pub fn main() { let j2 = spawn(move || { // Also an error of the form: Data race detected between Write on thread `` and Deallocate on thread `` // but the invalid allocation is detected first. - *ptr.0 = 2; //~ ERROR dereferenced after this allocation got freed + *ptr.0 = 2; //~ ERROR: dereferenced after this allocation got freed }); j1.join().unwrap(); diff --git a/tests/fail/data_race/dealloc_write_race_stack.rs b/tests/fail/data_race/dealloc_write_race_stack.rs index 6b87cbe61cad5..7f6beb7f32d83 100644 --- a/tests/fail/data_race/dealloc_write_race_stack.rs +++ b/tests/fail/data_race/dealloc_write_race_stack.rs @@ -36,7 +36,7 @@ pub fn main() { sleep(Duration::from_millis(200)); // Now `stack_var` gets deallocated. - } //~ ERROR Data race detected between Deallocate on thread `` and Write on thread `` + } //~ ERROR: Data race detected between Deallocate on thread `` and Write on thread `` }); let j2 = spawn(move || { diff --git a/tests/fail/data_race/enable_after_join_to_main.rs b/tests/fail/data_race/enable_after_join_to_main.rs index 290589690a389..2e9fce198d1d4 100644 --- a/tests/fail/data_race/enable_after_join_to_main.rs +++ b/tests/fail/data_race/enable_after_join_to_main.rs @@ -31,7 +31,7 @@ pub fn main() { }); let j2 = spawn(move || { - *c.0 = 64; //~ ERROR Data race detected between Write on thread `` and Write on thread `` + *c.0 = 64; //~ ERROR: Data race detected between Write on thread `` and Write on thread `` }); j1.join().unwrap(); diff --git a/tests/fail/data_race/fence_after_load.rs b/tests/fail/data_race/fence_after_load.rs index 7a8d66bf8f29f..f41c7a25523e8 100644 --- a/tests/fail/data_race/fence_after_load.rs +++ b/tests/fail/data_race/fence_after_load.rs @@ -21,5 +21,5 @@ fn main() { // The fence is useless, since it did not happen-after the `store` in the other thread. // Hence this is a data race. // Also see https://github.com/rust-lang/miri/issues/2192. - unsafe { V = 2 } //~ERROR Data race detected between Write on thread `main` and Write on thread `` + unsafe { V = 2 } //~ERROR: Data race detected between Write on thread `main` and Write on thread `` } diff --git a/tests/fail/data_race/read_write_race.rs b/tests/fail/data_race/read_write_race.rs index 4c1d87746d726..e1134669f7821 100644 --- a/tests/fail/data_race/read_write_race.rs +++ b/tests/fail/data_race/read_write_race.rs @@ -20,7 +20,7 @@ pub fn main() { }); let j2 = spawn(move || { - *c.0 = 64; //~ ERROR Data race detected between Write on thread `` and Read on thread `` + *c.0 = 64; //~ ERROR: Data race detected between Write on thread `` and Read on thread `` }); j1.join().unwrap(); diff --git a/tests/fail/data_race/read_write_race_stack.rs b/tests/fail/data_race/read_write_race_stack.rs index 3999c57bcf424..802e90d222af0 100644 --- a/tests/fail/data_race/read_write_race_stack.rs +++ b/tests/fail/data_race/read_write_race_stack.rs @@ -43,7 +43,7 @@ pub fn main() { sleep(Duration::from_millis(200)); - stack_var //~ ERROR Data race detected between Read on thread `` and Write on thread `` + stack_var //~ ERROR: Data race detected between Read on thread `` and Write on thread `` }); let j2 = spawn(move || { diff --git a/tests/fail/data_race/relax_acquire_race.rs b/tests/fail/data_race/relax_acquire_race.rs index 3038efe99efa0..4238372f21fad 100644 --- a/tests/fail/data_race/relax_acquire_race.rs +++ b/tests/fail/data_race/relax_acquire_race.rs @@ -38,7 +38,7 @@ pub fn main() { let j3 = spawn(move || { if SYNC.load(Ordering::Acquire) == 2 { - *c.0 //~ ERROR Data race detected between Read on thread `` and Write on thread `` + *c.0 //~ ERROR: Data race detected between Read on thread `` and Write on thread `` } else { 0 } diff --git a/tests/fail/data_race/release_seq_race.rs b/tests/fail/data_race/release_seq_race.rs index ca227bf5ad29d..cd11aac95955f 100644 --- a/tests/fail/data_race/release_seq_race.rs +++ b/tests/fail/data_race/release_seq_race.rs @@ -42,7 +42,7 @@ pub fn main() { let j3 = spawn(move || { sleep(Duration::from_millis(500)); if SYNC.load(Ordering::Acquire) == 3 { - *c.0 //~ ERROR Data race detected between Read on thread `` and Write on thread `` + *c.0 //~ ERROR: Data race detected between Read on thread `` and Write on thread `` } else { 0 } diff --git a/tests/fail/data_race/release_seq_race_same_thread.rs b/tests/fail/data_race/release_seq_race_same_thread.rs index c9b0cd7773ef7..854ea09f11ebb 100644 --- a/tests/fail/data_race/release_seq_race_same_thread.rs +++ b/tests/fail/data_race/release_seq_race_same_thread.rs @@ -38,7 +38,7 @@ pub fn main() { let j2 = spawn(move || { if SYNC.load(Ordering::Acquire) == 2 { - *c.0 //~ ERROR Data race detected between Read on thread `` and Write on thread `` + *c.0 //~ ERROR: Data race detected between Read on thread `` and Write on thread `` } else { 0 } diff --git a/tests/fail/data_race/rmw_race.rs b/tests/fail/data_race/rmw_race.rs index ca8123177ab33..2f7f8986a49e1 100644 --- a/tests/fail/data_race/rmw_race.rs +++ b/tests/fail/data_race/rmw_race.rs @@ -39,7 +39,7 @@ pub fn main() { let j3 = spawn(move || { if SYNC.load(Ordering::Acquire) == 3 { - *c.0 //~ ERROR Data race detected between Read on thread `` and Write on thread `` + *c.0 //~ ERROR: Data race detected between Read on thread `` and Write on thread `` } else { 0 } diff --git a/tests/fail/data_race/stack_pop_race.rs b/tests/fail/data_race/stack_pop_race.rs index a31c434604bb7..444c28d50aaf5 100644 --- a/tests/fail/data_race/stack_pop_race.rs +++ b/tests/fail/data_race/stack_pop_race.rs @@ -22,4 +22,4 @@ fn race(local: i32) { // Deallocating the local (when `main` returns) // races with the read in the other thread. // Make sure the error points at this function's end, not just the call site. -} //~ERROR Data race detected between Deallocate on thread `main` and Read on thread `` +} //~ERROR: Data race detected between Deallocate on thread `main` and Read on thread `` diff --git a/tests/fail/data_race/write_write_race.rs b/tests/fail/data_race/write_write_race.rs index de4d4d70c5006..fae4582e7e470 100644 --- a/tests/fail/data_race/write_write_race.rs +++ b/tests/fail/data_race/write_write_race.rs @@ -20,7 +20,7 @@ pub fn main() { }); let j2 = spawn(move || { - *c.0 = 64; //~ ERROR Data race detected between Write on thread `` and Write on thread `` + *c.0 = 64; //~ ERROR: Data race detected between Write on thread `` and Write on thread `` }); j1.join().unwrap(); diff --git a/tests/fail/data_race/write_write_race_stack.rs b/tests/fail/data_race/write_write_race_stack.rs index 96b40affaed01..4b83413b39224 100644 --- a/tests/fail/data_race/write_write_race_stack.rs +++ b/tests/fail/data_race/write_write_race_stack.rs @@ -40,7 +40,7 @@ pub fn main() { sleep(Duration::from_millis(200)); - stack_var = 1usize; //~ ERROR Data race detected between Write on thread `` and Write on thread `` + stack_var = 1usize; //~ ERROR: Data race detected between Write on thread `` and Write on thread `` // read to silence errors stack_var diff --git a/tests/fail/environ-gets-deallocated.rs b/tests/fail/environ-gets-deallocated.rs index 34941b9449234..39629610c6320 100644 --- a/tests/fail/environ-gets-deallocated.rs +++ b/tests/fail/environ-gets-deallocated.rs @@ -20,5 +20,5 @@ fn main() { let pointer = get_environ(); let _x = unsafe { *pointer }; std::env::set_var("FOO", "BAR"); - let _y = unsafe { *pointer }; //~ ERROR dereferenced after this allocation got freed + let _y = unsafe { *pointer }; //~ ERROR: dereferenced after this allocation got freed } diff --git a/tests/fail/erroneous_const.rs b/tests/fail/erroneous_const.rs index ce1392d102b7a..c35a905035932 100644 --- a/tests/fail/erroneous_const.rs +++ b/tests/fail/erroneous_const.rs @@ -7,12 +7,12 @@ struct PrintName(T); impl PrintName { - const VOID: ! = panic!(); //~ERROR evaluation of `PrintName::::VOID` failed + const VOID: ! = panic!(); //~ERROR: evaluation of `PrintName::::VOID` failed } fn no_codegen() { if false { - let _ = PrintName::::VOID; //~ERROR post-monomorphization error + let _ = PrintName::::VOID; //~ERROR: post-monomorphization error } } fn main() { diff --git a/tests/fail/erroneous_const2.rs b/tests/fail/erroneous_const2.rs index dc68cd64d738f..6628166cfacdf 100644 --- a/tests/fail/erroneous_const2.rs +++ b/tests/fail/erroneous_const2.rs @@ -1,13 +1,13 @@ const X: u32 = 5; const Y: u32 = 6; const FOO: u32 = [X - Y, Y - X][(X < Y) as usize]; -//~^ERROR any use of this value -//~|WARN previously accepted +//~^ERROR: any use of this value +//~|WARN: previously accepted #[rustfmt::skip] // rustfmt bug: https://github.com/rust-lang/rustfmt/issues/5391 fn main() { - println!("{}", FOO); //~ERROR post-monomorphization error - //~|ERROR evaluation of constant value failed - //~|ERROR erroneous constant used - //~|WARN previously accepted + println!("{}", FOO); //~ERROR: post-monomorphization error + //~|ERROR: evaluation of constant value failed + //~|ERROR: erroneous constant used + //~|WARN: previously accepted } diff --git a/tests/fail/extern_static.rs b/tests/fail/extern_static.rs index f3466d5e7180c..f8805db8d1439 100644 --- a/tests/fail/extern_static.rs +++ b/tests/fail/extern_static.rs @@ -5,5 +5,5 @@ extern "C" { } fn main() { - let _val = unsafe { std::ptr::addr_of!(FOO) }; //~ ERROR is not supported by Miri + let _val = unsafe { std::ptr::addr_of!(FOO) }; //~ ERROR: is not supported by Miri } diff --git a/tests/fail/extern_static_in_const.rs b/tests/fail/extern_static_in_const.rs index 4c1de6ace51d3..31c192bf44bea 100644 --- a/tests/fail/extern_static_in_const.rs +++ b/tests/fail/extern_static_in_const.rs @@ -7,5 +7,5 @@ extern "C" { static X: &'static [u8; 0] = unsafe { &E }; fn main() { - let _val = X; //~ ERROR is not supported by Miri + let _val = X; //~ ERROR: is not supported by Miri } diff --git a/tests/fail/fast_math_both.rs b/tests/fail/fast_math_both.rs index 844e4e95211f9..dd2787bf40f40 100644 --- a/tests/fail/fast_math_both.rs +++ b/tests/fail/fast_math_both.rs @@ -2,6 +2,6 @@ fn main() { unsafe { - let _x: f32 = core::intrinsics::fsub_fast(f32::NAN, f32::NAN); //~ ERROR `fsub_fast` intrinsic called with non-finite value as both parameters + let _x: f32 = core::intrinsics::fsub_fast(f32::NAN, f32::NAN); //~ ERROR: `fsub_fast` intrinsic called with non-finite value as both parameters } } diff --git a/tests/fail/fast_math_first.rs b/tests/fail/fast_math_first.rs index 470ebe620050f..e495498ab2869 100644 --- a/tests/fail/fast_math_first.rs +++ b/tests/fail/fast_math_first.rs @@ -2,6 +2,6 @@ fn main() { unsafe { - let _x: f32 = core::intrinsics::frem_fast(f32::NAN, 3.2); //~ ERROR `frem_fast` intrinsic called with non-finite value as first parameter + let _x: f32 = core::intrinsics::frem_fast(f32::NAN, 3.2); //~ ERROR: `frem_fast` intrinsic called with non-finite value as first parameter } } diff --git a/tests/fail/fast_math_second.rs b/tests/fail/fast_math_second.rs index e8d70a4a79e7a..408c461077fc5 100644 --- a/tests/fail/fast_math_second.rs +++ b/tests/fail/fast_math_second.rs @@ -2,6 +2,6 @@ fn main() { unsafe { - let _x: f32 = core::intrinsics::fmul_fast(3.4f32, f32::INFINITY); //~ ERROR `fmul_fast` intrinsic called with non-finite value as second parameter + let _x: f32 = core::intrinsics::fmul_fast(3.4f32, f32::INFINITY); //~ ERROR: `fmul_fast` intrinsic called with non-finite value as second parameter } } diff --git a/tests/fail/fs/close_stdout.rs b/tests/fail/fs/close_stdout.rs index 2737011128779..3271722de0f9e 100644 --- a/tests/fail/fs/close_stdout.rs +++ b/tests/fail/fs/close_stdout.rs @@ -9,6 +9,6 @@ extern crate libc; fn main() { unsafe { - libc::close(1); //~ ERROR stdout cannot be closed + libc::close(1); //~ ERROR: stdout cannot be closed } } diff --git a/tests/fail/fs/isolated_stdin.rs b/tests/fail/fs/isolated_stdin.rs index b41534c5c3a87..27c66c58eb2f8 100644 --- a/tests/fail/fs/isolated_stdin.rs +++ b/tests/fail/fs/isolated_stdin.rs @@ -7,7 +7,7 @@ extern crate libc; fn main() -> std::io::Result<()> { let mut bytes = [0u8; 512]; unsafe { - libc::read(0, bytes.as_mut_ptr() as *mut libc::c_void, 512); //~ ERROR `read` from stdin not available when isolation is enabled + libc::read(0, bytes.as_mut_ptr() as *mut libc::c_void, 512); //~ ERROR: `read` from stdin not available when isolation is enabled } Ok(()) } diff --git a/tests/fail/fs/read_from_stdout.rs b/tests/fail/fs/read_from_stdout.rs index 4862bf0a162c0..d78bc9f34d7d3 100644 --- a/tests/fail/fs/read_from_stdout.rs +++ b/tests/fail/fs/read_from_stdout.rs @@ -8,7 +8,7 @@ extern crate libc; fn main() -> std::io::Result<()> { let mut bytes = [0u8; 512]; unsafe { - libc::read(1, bytes.as_mut_ptr() as *mut libc::c_void, 512); //~ ERROR cannot read from stdout + libc::read(1, bytes.as_mut_ptr() as *mut libc::c_void, 512); //~ ERROR: cannot read from stdout } Ok(()) } diff --git a/tests/fail/fs/unix_open_missing_required_mode.rs b/tests/fail/fs/unix_open_missing_required_mode.rs index e714d26e7835c..03993db81f576 100644 --- a/tests/fail/fs/unix_open_missing_required_mode.rs +++ b/tests/fail/fs/unix_open_missing_required_mode.rs @@ -12,5 +12,5 @@ fn main() { fn test_file_open_missing_needed_mode() { let name = b"missing_arg.txt\0"; let name_ptr = name.as_ptr().cast::(); - let _fd = unsafe { libc::open(name_ptr, libc::O_CREAT) }; //~ ERROR Undefined Behavior: incorrect number of arguments for `open` with `O_CREAT`: got 2, expected at least 3 + let _fd = unsafe { libc::open(name_ptr, libc::O_CREAT) }; //~ ERROR: Undefined Behavior: incorrect number of arguments for `open` with `O_CREAT`: got 2, expected at least 3 } diff --git a/tests/fail/fs/write_to_stdin.rs b/tests/fail/fs/write_to_stdin.rs index 9d55a60b64b80..78ea0f4a18bd5 100644 --- a/tests/fail/fs/write_to_stdin.rs +++ b/tests/fail/fs/write_to_stdin.rs @@ -7,7 +7,7 @@ extern crate libc; fn main() -> std::io::Result<()> { let bytes = b"hello"; unsafe { - libc::write(0, bytes.as_ptr() as *const libc::c_void, 5); //~ ERROR cannot write to stdin + libc::write(0, bytes.as_ptr() as *const libc::c_void, 5); //~ ERROR: cannot write to stdin } Ok(()) } diff --git a/tests/fail/function_calls/check_arg_abi.rs b/tests/fail/function_calls/check_arg_abi.rs index 5656c7a0e4cb6..ffa0443ce507a 100644 --- a/tests/fail/function_calls/check_arg_abi.rs +++ b/tests/fail/function_calls/check_arg_abi.rs @@ -4,6 +4,6 @@ fn main() { } unsafe { - let _ = malloc(0); //~ ERROR calling a function with ABI C using caller ABI Rust + let _ = malloc(0); //~ ERROR: calling a function with ABI C using caller ABI Rust }; } diff --git a/tests/fail/function_calls/check_arg_count_abort.rs b/tests/fail/function_calls/check_arg_count_abort.rs index 85e1b9deeb36f..967a78bf83187 100644 --- a/tests/fail/function_calls/check_arg_count_abort.rs +++ b/tests/fail/function_calls/check_arg_count_abort.rs @@ -5,6 +5,6 @@ fn main() { unsafe { abort(1); - //~^ ERROR Undefined Behavior: incorrect number of arguments: got 1, expected 0 + //~^ ERROR: Undefined Behavior: incorrect number of arguments: got 1, expected 0 } } diff --git a/tests/fail/function_calls/check_arg_count_too_few_args.rs b/tests/fail/function_calls/check_arg_count_too_few_args.rs index e1cea99eb90b2..223c95ffca46b 100644 --- a/tests/fail/function_calls/check_arg_count_too_few_args.rs +++ b/tests/fail/function_calls/check_arg_count_too_few_args.rs @@ -4,6 +4,6 @@ fn main() { } unsafe { - let _ = malloc(); //~ ERROR Undefined Behavior: incorrect number of arguments: got 0, expected 1 + let _ = malloc(); //~ ERROR: Undefined Behavior: incorrect number of arguments: got 0, expected 1 }; } diff --git a/tests/fail/function_calls/check_arg_count_too_many_args.rs b/tests/fail/function_calls/check_arg_count_too_many_args.rs index c4028b940ff03..7ee9c40bf7a4b 100644 --- a/tests/fail/function_calls/check_arg_count_too_many_args.rs +++ b/tests/fail/function_calls/check_arg_count_too_many_args.rs @@ -4,6 +4,6 @@ fn main() { } unsafe { - let _ = malloc(1, 2); //~ ERROR Undefined Behavior: incorrect number of arguments: got 2, expected 1 + let _ = malloc(1, 2); //~ ERROR: Undefined Behavior: incorrect number of arguments: got 2, expected 1 }; } diff --git a/tests/fail/function_calls/check_callback_abi.rs b/tests/fail/function_calls/check_callback_abi.rs index 0a5a2d48d2743..883d5ae8096bd 100644 --- a/tests/fail/function_calls/check_callback_abi.rs +++ b/tests/fail/function_calls/check_callback_abi.rs @@ -9,7 +9,7 @@ fn main() { // Make sure we check the ABI when Miri itself invokes a function // as part of a shim implementation. std::intrinsics::r#try( - //~^ ERROR calling a function with ABI C using caller ABI Rust + //~^ ERROR: calling a function with ABI C using caller ABI Rust std::mem::transmute::(try_fn), std::ptr::null_mut(), |_, _| unreachable!(), diff --git a/tests/fail/function_calls/exported_symbol_abi_mismatch.rs b/tests/fail/function_calls/exported_symbol_abi_mismatch.rs index e7372d5ec50a2..dbf72b5b61ad9 100644 --- a/tests/fail/function_calls/exported_symbol_abi_mismatch.rs +++ b/tests/fail/function_calls/exported_symbol_abi_mismatch.rs @@ -12,7 +12,7 @@ fn main() { #[cfg(fn_ptr)] unsafe { std::mem::transmute::(foo)(); - //[fn_ptr]~^ ERROR calling a function with calling convention Rust using calling convention C + //[fn_ptr]~^ ERROR: calling a function with calling convention Rust using calling convention C } // `Instance` caching should not suppress ABI check. @@ -28,8 +28,8 @@ fn main() { } unsafe { foo(); - //[no_cache]~^ ERROR calling a function with calling convention Rust using calling convention C - //[cache]~| ERROR calling a function with calling convention Rust using calling convention C + //[no_cache]~^ ERROR: calling a function with calling convention Rust using calling convention C + //[cache]~| ERROR: calling a function with calling convention Rust using calling convention C } } } diff --git a/tests/fail/function_calls/exported_symbol_bad_unwind1.rs b/tests/fail/function_calls/exported_symbol_bad_unwind1.rs index 0a5636138d80f..5f4df7c6a1ef3 100644 --- a/tests/fail/function_calls/exported_symbol_bad_unwind1.rs +++ b/tests/fail/function_calls/exported_symbol_bad_unwind1.rs @@ -11,5 +11,5 @@ fn main() { fn unwind(); } unsafe { unwind() } - //~^ ERROR unwinding past a stack frame that does not allow unwinding + //~^ ERROR: unwinding past a stack frame that does not allow unwinding } diff --git a/tests/fail/function_calls/exported_symbol_bad_unwind2.both.stderr b/tests/fail/function_calls/exported_symbol_bad_unwind2.both.stderr index 48df075ba622b..74f1d2b113100 100644 --- a/tests/fail/function_calls/exported_symbol_bad_unwind2.both.stderr +++ b/tests/fail/function_calls/exported_symbol_bad_unwind2.both.stderr @@ -4,8 +4,8 @@ error: abnormal termination: the program aborted execution --> $DIR/exported_symbol_bad_unwind2.rs:LL:CC | LL | / extern "C-unwind" fn nounwind() { -LL | | //[definition]~^ ERROR abnormal termination: the program aborted execution -LL | | //[both]~^^ ERROR abnormal termination: the program aborted execution +LL | | //[definition]~^ ERROR: abnormal termination: the program aborted execution +LL | | //[both]~^^ ERROR: abnormal termination: the program aborted execution LL | | panic!(); LL | | } | |_^ the program aborted execution diff --git a/tests/fail/function_calls/exported_symbol_bad_unwind2.definition.stderr b/tests/fail/function_calls/exported_symbol_bad_unwind2.definition.stderr index 48df075ba622b..74f1d2b113100 100644 --- a/tests/fail/function_calls/exported_symbol_bad_unwind2.definition.stderr +++ b/tests/fail/function_calls/exported_symbol_bad_unwind2.definition.stderr @@ -4,8 +4,8 @@ error: abnormal termination: the program aborted execution --> $DIR/exported_symbol_bad_unwind2.rs:LL:CC | LL | / extern "C-unwind" fn nounwind() { -LL | | //[definition]~^ ERROR abnormal termination: the program aborted execution -LL | | //[both]~^^ ERROR abnormal termination: the program aborted execution +LL | | //[definition]~^ ERROR: abnormal termination: the program aborted execution +LL | | //[both]~^^ ERROR: abnormal termination: the program aborted execution LL | | panic!(); LL | | } | |_^ the program aborted execution diff --git a/tests/fail/function_calls/exported_symbol_bad_unwind2.rs b/tests/fail/function_calls/exported_symbol_bad_unwind2.rs index 861789f862e6e..d9aacdb8aea4e 100644 --- a/tests/fail/function_calls/exported_symbol_bad_unwind2.rs +++ b/tests/fail/function_calls/exported_symbol_bad_unwind2.rs @@ -4,8 +4,8 @@ #[cfg_attr(any(definition, both), rustc_allocator_nounwind)] #[no_mangle] extern "C-unwind" fn nounwind() { - //[definition]~^ ERROR abnormal termination: the program aborted execution - //[both]~^^ ERROR abnormal termination: the program aborted execution + //[definition]~^ ERROR: abnormal termination: the program aborted execution + //[both]~^^ ERROR: abnormal termination: the program aborted execution panic!(); } @@ -15,5 +15,5 @@ fn main() { fn nounwind(); } unsafe { nounwind() } - //[extern_block]~^ ERROR unwinding past a stack frame that does not allow unwinding + //[extern_block]~^ ERROR: unwinding past a stack frame that does not allow unwinding } diff --git a/tests/fail/function_calls/exported_symbol_clashing.rs b/tests/fail/function_calls/exported_symbol_clashing.rs index 0e64778d8909f..45ad412e7a55e 100644 --- a/tests/fail/function_calls/exported_symbol_clashing.rs +++ b/tests/fail/function_calls/exported_symbol_clashing.rs @@ -1,15 +1,15 @@ #[no_mangle] fn foo() {} -//~^ HELP it's first defined here, in crate `exported_symbol_clashing` +//~^ HELP: it's first defined here, in crate `exported_symbol_clashing` #[export_name = "foo"] fn bar() {} -//~^ HELP then it's defined here again, in crate `exported_symbol_clashing` +//~^ HELP: then it's defined here again, in crate `exported_symbol_clashing` fn main() { extern "Rust" { fn foo(); } unsafe { foo() } - //~^ ERROR multiple definitions of symbol `foo` + //~^ ERROR: multiple definitions of symbol `foo` } diff --git a/tests/fail/function_calls/exported_symbol_shim_clashing.rs b/tests/fail/function_calls/exported_symbol_shim_clashing.rs index c46d57cee0dde..dffae7adbb972 100644 --- a/tests/fail/function_calls/exported_symbol_shim_clashing.rs +++ b/tests/fail/function_calls/exported_symbol_shim_clashing.rs @@ -1,6 +1,6 @@ #[no_mangle] extern "C" fn malloc(_: usize) -> *mut std::ffi::c_void { - //~^ HELP the `malloc` symbol is defined here + //~^ HELP: the `malloc` symbol is defined here unreachable!() } @@ -10,6 +10,6 @@ fn main() { } unsafe { malloc(0); - //~^ ERROR found `malloc` symbol definition that clashes with a built-in shim + //~^ ERROR: found `malloc` symbol definition that clashes with a built-in shim } } diff --git a/tests/fail/function_calls/exported_symbol_wrong_arguments.rs b/tests/fail/function_calls/exported_symbol_wrong_arguments.rs index 8fb364bb9bd10..a108944c5e434 100644 --- a/tests/fail/function_calls/exported_symbol_wrong_arguments.rs +++ b/tests/fail/function_calls/exported_symbol_wrong_arguments.rs @@ -5,5 +5,5 @@ fn main() { extern "Rust" { fn foo(_: i32); } - unsafe { foo(1) } //~ ERROR calling a function with more arguments than it expected + unsafe { foo(1) } //~ ERROR: calling a function with more arguments than it expected } diff --git a/tests/fail/function_calls/exported_symbol_wrong_type.rs b/tests/fail/function_calls/exported_symbol_wrong_type.rs index 3ffd506c94bb5..e273e354334f8 100644 --- a/tests/fail/function_calls/exported_symbol_wrong_type.rs +++ b/tests/fail/function_calls/exported_symbol_wrong_type.rs @@ -5,5 +5,5 @@ fn main() { extern "C" { fn FOO(); } - unsafe { FOO() } //~ ERROR attempt to call an exported symbol that is not defined as a function + unsafe { FOO() } //~ ERROR: attempt to call an exported symbol that is not defined as a function } diff --git a/tests/fail/function_pointers/cast_box_int_to_fn_ptr.rs b/tests/fail/function_pointers/cast_box_int_to_fn_ptr.rs index 6edf88a543de9..9815569b607f2 100644 --- a/tests/fail/function_pointers/cast_box_int_to_fn_ptr.rs +++ b/tests/fail/function_pointers/cast_box_int_to_fn_ptr.rs @@ -5,5 +5,5 @@ fn main() { let b = Box::new(42); let g = unsafe { std::mem::transmute::<&Box, &fn(i32)>(&b) }; - (*g)(42) //~ ERROR it does not point to a function + (*g)(42) //~ ERROR: it does not point to a function } diff --git a/tests/fail/function_pointers/cast_fn_ptr1.rs b/tests/fail/function_pointers/cast_fn_ptr1.rs index e4463210dda9b..c0e96a43cc522 100644 --- a/tests/fail/function_pointers/cast_fn_ptr1.rs +++ b/tests/fail/function_pointers/cast_fn_ptr1.rs @@ -3,5 +3,5 @@ fn main() { let g = unsafe { std::mem::transmute::(f) }; - g(42) //~ ERROR calling a function with more arguments than it expected + g(42) //~ ERROR: calling a function with more arguments than it expected } diff --git a/tests/fail/function_pointers/cast_fn_ptr2.rs b/tests/fail/function_pointers/cast_fn_ptr2.rs index 5d3222548a7d4..20384f0965b82 100644 --- a/tests/fail/function_pointers/cast_fn_ptr2.rs +++ b/tests/fail/function_pointers/cast_fn_ptr2.rs @@ -3,5 +3,5 @@ fn main() { let g = unsafe { std::mem::transmute::(f) }; - g(42) //~ ERROR calling a function with argument of type (i32, i32) passing data of type i32 + g(42) //~ ERROR: calling a function with argument of type (i32, i32) passing data of type i32 } diff --git a/tests/fail/function_pointers/cast_fn_ptr3.rs b/tests/fail/function_pointers/cast_fn_ptr3.rs index 943175c347026..920fb51abb644 100644 --- a/tests/fail/function_pointers/cast_fn_ptr3.rs +++ b/tests/fail/function_pointers/cast_fn_ptr3.rs @@ -3,5 +3,5 @@ fn main() { let g = unsafe { std::mem::transmute::(f) }; - g() //~ ERROR calling a function with fewer arguments than it requires + g() //~ ERROR: calling a function with fewer arguments than it requires } diff --git a/tests/fail/function_pointers/cast_fn_ptr4.rs b/tests/fail/function_pointers/cast_fn_ptr4.rs index 238b09b162d2d..f0ea5ccfe0f5a 100644 --- a/tests/fail/function_pointers/cast_fn_ptr4.rs +++ b/tests/fail/function_pointers/cast_fn_ptr4.rs @@ -3,5 +3,5 @@ fn main() { let g = unsafe { std::mem::transmute::(f) }; - g(&42 as *const i32) //~ ERROR calling a function with argument of type *const [i32] passing data of type *const i32 + g(&42 as *const i32) //~ ERROR: calling a function with argument of type *const [i32] passing data of type *const i32 } diff --git a/tests/fail/function_pointers/cast_fn_ptr5.rs b/tests/fail/function_pointers/cast_fn_ptr5.rs index effbd6db18844..0fdab49b94b6f 100644 --- a/tests/fail/function_pointers/cast_fn_ptr5.rs +++ b/tests/fail/function_pointers/cast_fn_ptr5.rs @@ -5,5 +5,5 @@ fn main() { let g = unsafe { std::mem::transmute:: u32, fn()>(f) }; - g() //~ ERROR calling a function with return type u32 passing return place of type () + g() //~ ERROR: calling a function with return type u32 passing return place of type () } diff --git a/tests/fail/function_pointers/cast_int_to_fn_ptr.rs b/tests/fail/function_pointers/cast_int_to_fn_ptr.rs index 272376307d7c1..dbf8a560fb7af 100644 --- a/tests/fail/function_pointers/cast_int_to_fn_ptr.rs +++ b/tests/fail/function_pointers/cast_int_to_fn_ptr.rs @@ -4,5 +4,5 @@ fn main() { let g = unsafe { std::mem::transmute::(42) }; - g(42) //~ ERROR is a dangling pointer + g(42) //~ ERROR: is a dangling pointer } diff --git a/tests/fail/function_pointers/deref_fn_ptr.rs b/tests/fail/function_pointers/deref_fn_ptr.rs index f22f73487b48c..f071b63902fee 100644 --- a/tests/fail/function_pointers/deref_fn_ptr.rs +++ b/tests/fail/function_pointers/deref_fn_ptr.rs @@ -2,7 +2,7 @@ fn f() {} fn main() { let x: u8 = unsafe { - *std::mem::transmute::(f) //~ ERROR out-of-bounds + *std::mem::transmute::(f) //~ ERROR: out-of-bounds }; panic!("this should never print: {}", x); } diff --git a/tests/fail/function_pointers/execute_memory.rs b/tests/fail/function_pointers/execute_memory.rs index 0ca29a3594e52..967933e769b8c 100644 --- a/tests/fail/function_pointers/execute_memory.rs +++ b/tests/fail/function_pointers/execute_memory.rs @@ -7,6 +7,6 @@ fn main() { let x = box 42; unsafe { let f = std::mem::transmute::, fn()>(x); - f() //~ ERROR function pointer but it does not point to a function + f() //~ ERROR: function pointer but it does not point to a function } } diff --git a/tests/fail/function_pointers/fn_ptr_offset.rs b/tests/fail/function_pointers/fn_ptr_offset.rs index 5f269760f1100..eba0953ac863f 100644 --- a/tests/fail/function_pointers/fn_ptr_offset.rs +++ b/tests/fail/function_pointers/fn_ptr_offset.rs @@ -10,5 +10,5 @@ fn main() { let y: *mut u8 = unsafe { mem::transmute(x) }; let y = y.wrapping_offset(1); let x: fn() = unsafe { mem::transmute(y) }; - x(); //~ ERROR function pointer but it does not point to a function + x(); //~ ERROR: function pointer but it does not point to a function } diff --git a/tests/fail/generator-pinned-moved.rs b/tests/fail/generator-pinned-moved.rs index 915dcdea82e49..240ae18cc45a6 100644 --- a/tests/fail/generator-pinned-moved.rs +++ b/tests/fail/generator-pinned-moved.rs @@ -12,7 +12,7 @@ fn firstn() -> impl Generator { let num = &mut num; yield *num; - *num += 1; //~ ERROR dereferenced after this allocation got freed + *num += 1; //~ ERROR: dereferenced after this allocation got freed } } diff --git a/tests/fail/intrinsics/assume.rs b/tests/fail/intrinsics/assume.rs index ad193d8499181..be06d0a7a554d 100644 --- a/tests/fail/intrinsics/assume.rs +++ b/tests/fail/intrinsics/assume.rs @@ -5,6 +5,6 @@ fn main() { unsafe { std::intrinsics::assume(x < 10); std::intrinsics::assume(x > 1); - std::intrinsics::assume(x > 42); //~ ERROR `assume` intrinsic called with `false` + std::intrinsics::assume(x > 42); //~ ERROR: `assume` intrinsic called with `false` } } diff --git a/tests/fail/intrinsics/copy_overlapping.rs b/tests/fail/intrinsics/copy_overlapping.rs index 8d3c68139317e..3df881bd43ca4 100644 --- a/tests/fail/intrinsics/copy_overlapping.rs +++ b/tests/fail/intrinsics/copy_overlapping.rs @@ -10,6 +10,6 @@ fn main() { unsafe { let a = data.as_mut_ptr(); let b = a.wrapping_offset(1) as *mut _; - copy_nonoverlapping(a, b, 2); //~ ERROR copy_nonoverlapping called on overlapping ranges + copy_nonoverlapping(a, b, 2); //~ ERROR: copy_nonoverlapping called on overlapping ranges } } diff --git a/tests/fail/intrinsics/copy_unaligned.rs b/tests/fail/intrinsics/copy_unaligned.rs index 162f06bfacd9b..281217f06f516 100644 --- a/tests/fail/intrinsics/copy_unaligned.rs +++ b/tests/fail/intrinsics/copy_unaligned.rs @@ -10,6 +10,6 @@ fn main() { let ptr = (&mut data[0] as *mut u16 as *mut u8).wrapping_add(1) as *mut u16; // Even copying 0 elements to something unaligned should error unsafe { - copy_nonoverlapping(&data[5], ptr, 0); //~ ERROR accessing memory with alignment 1, but alignment 2 is required + copy_nonoverlapping(&data[5], ptr, 0); //~ ERROR: accessing memory with alignment 1, but alignment 2 is required } } diff --git a/tests/fail/intrinsics/ctlz_nonzero.rs b/tests/fail/intrinsics/ctlz_nonzero.rs index e82ed89da18a7..c26cd4cadb539 100644 --- a/tests/fail/intrinsics/ctlz_nonzero.rs +++ b/tests/fail/intrinsics/ctlz_nonzero.rs @@ -10,6 +10,6 @@ pub fn main() { unsafe { use crate::rusti::*; - ctlz_nonzero(0u8); //~ ERROR `ctlz_nonzero` called on 0 + ctlz_nonzero(0u8); //~ ERROR: `ctlz_nonzero` called on 0 } } diff --git a/tests/fail/intrinsics/cttz_nonzero.rs b/tests/fail/intrinsics/cttz_nonzero.rs index 205b552081148..25a0501fdd80e 100644 --- a/tests/fail/intrinsics/cttz_nonzero.rs +++ b/tests/fail/intrinsics/cttz_nonzero.rs @@ -10,6 +10,6 @@ pub fn main() { unsafe { use crate::rusti::*; - cttz_nonzero(0u8); //~ ERROR `cttz_nonzero` called on 0 + cttz_nonzero(0u8); //~ ERROR: `cttz_nonzero` called on 0 } } diff --git a/tests/fail/intrinsics/div-by-zero.rs b/tests/fail/intrinsics/div-by-zero.rs index d67d06dc1e674..78c05c543a8f0 100644 --- a/tests/fail/intrinsics/div-by-zero.rs +++ b/tests/fail/intrinsics/div-by-zero.rs @@ -4,6 +4,6 @@ use std::intrinsics::*; fn main() { unsafe { - let _n = unchecked_div(1i64, 0); //~ERROR dividing by zero + let _n = unchecked_div(1i64, 0); //~ERROR: dividing by zero } } diff --git a/tests/fail/intrinsics/exact_div1.rs b/tests/fail/intrinsics/exact_div1.rs index f926424a4b67a..3dda9d1090de7 100644 --- a/tests/fail/intrinsics/exact_div1.rs +++ b/tests/fail/intrinsics/exact_div1.rs @@ -1,5 +1,5 @@ #![feature(core_intrinsics)] fn main() { // divison by 0 - unsafe { std::intrinsics::exact_div(2, 0) }; //~ ERROR divisor of zero + unsafe { std::intrinsics::exact_div(2, 0) }; //~ ERROR: divisor of zero } diff --git a/tests/fail/intrinsics/exact_div2.rs b/tests/fail/intrinsics/exact_div2.rs index fc252aa798578..00064fa0b9c11 100644 --- a/tests/fail/intrinsics/exact_div2.rs +++ b/tests/fail/intrinsics/exact_div2.rs @@ -1,5 +1,5 @@ #![feature(core_intrinsics)] fn main() { // divison with a remainder - unsafe { std::intrinsics::exact_div(2u16, 3) }; //~ ERROR 2_u16 cannot be divided by 3_u16 without remainder + unsafe { std::intrinsics::exact_div(2u16, 3) }; //~ ERROR: 2_u16 cannot be divided by 3_u16 without remainder } diff --git a/tests/fail/intrinsics/exact_div3.rs b/tests/fail/intrinsics/exact_div3.rs index 4d2511adc1f58..a61abcd137e17 100644 --- a/tests/fail/intrinsics/exact_div3.rs +++ b/tests/fail/intrinsics/exact_div3.rs @@ -1,5 +1,5 @@ #![feature(core_intrinsics)] fn main() { // signed divison with a remainder - unsafe { std::intrinsics::exact_div(-19i8, 2) }; //~ ERROR -19_i8 cannot be divided by 2_i8 without remainder + unsafe { std::intrinsics::exact_div(-19i8, 2) }; //~ ERROR: -19_i8 cannot be divided by 2_i8 without remainder } diff --git a/tests/fail/intrinsics/exact_div4.rs b/tests/fail/intrinsics/exact_div4.rs index df6433d1cb22b..b5b60190b4ece 100644 --- a/tests/fail/intrinsics/exact_div4.rs +++ b/tests/fail/intrinsics/exact_div4.rs @@ -1,5 +1,5 @@ #![feature(core_intrinsics)] fn main() { // divison of MIN by -1 - unsafe { std::intrinsics::exact_div(i64::MIN, -1) }; //~ ERROR overflow in signed remainder (dividing MIN by -1) + unsafe { std::intrinsics::exact_div(i64::MIN, -1) }; //~ ERROR: overflow in signed remainder (dividing MIN by -1) } diff --git a/tests/fail/intrinsics/ptr_offset_from_oob.rs b/tests/fail/intrinsics/ptr_offset_from_oob.rs index ef1ca1e2729d6..1fd5100a97b9f 100644 --- a/tests/fail/intrinsics/ptr_offset_from_oob.rs +++ b/tests/fail/intrinsics/ptr_offset_from_oob.rs @@ -7,5 +7,5 @@ fn main() { let length = 10; let end_ptr = start_ptr.wrapping_add(length); // Even if the offset is 0, a dangling OOB pointer is not allowed. - unsafe { ptr_offset_from(end_ptr, end_ptr) }; //~ERROR pointer at offset 10 is out-of-bounds + unsafe { ptr_offset_from(end_ptr, end_ptr) }; //~ERROR: pointer at offset 10 is out-of-bounds } diff --git a/tests/fail/intrinsics/rem-by-zero.rs b/tests/fail/intrinsics/rem-by-zero.rs index e904049e3b466..ac80852e8dcfc 100644 --- a/tests/fail/intrinsics/rem-by-zero.rs +++ b/tests/fail/intrinsics/rem-by-zero.rs @@ -4,6 +4,6 @@ use std::intrinsics::*; fn main() { unsafe { - let _n = unchecked_rem(3u32, 0); //~ ERROR calculating the remainder with a divisor of zero + let _n = unchecked_rem(3u32, 0); //~ ERROR: calculating the remainder with a divisor of zero } } diff --git a/tests/fail/intrinsics/simd-div-by-zero.rs b/tests/fail/intrinsics/simd-div-by-zero.rs index 6fdcb875acc13..5fa6f69d00593 100644 --- a/tests/fail/intrinsics/simd-div-by-zero.rs +++ b/tests/fail/intrinsics/simd-div-by-zero.rs @@ -12,6 +12,6 @@ fn main() { unsafe { let x = i32x2(1, 1); let y = i32x2(1, 0); - simd_div(x, y); //~ERROR Undefined Behavior: dividing by zero + simd_div(x, y); //~ERROR: Undefined Behavior: dividing by zero } } diff --git a/tests/fail/intrinsics/simd-div-overflow.rs b/tests/fail/intrinsics/simd-div-overflow.rs index 6d52a72e4c6e4..57712b1b836b5 100644 --- a/tests/fail/intrinsics/simd-div-overflow.rs +++ b/tests/fail/intrinsics/simd-div-overflow.rs @@ -12,6 +12,6 @@ fn main() { unsafe { let x = i32x2(1, i32::MIN); let y = i32x2(1, -1); - simd_div(x, y); //~ERROR Undefined Behavior: overflow in signed division + simd_div(x, y); //~ERROR: Undefined Behavior: overflow in signed division } } diff --git a/tests/fail/intrinsics/simd-reduce-invalid-bool.rs b/tests/fail/intrinsics/simd-reduce-invalid-bool.rs index c697fd526f869..354f8213120a2 100644 --- a/tests/fail/intrinsics/simd-reduce-invalid-bool.rs +++ b/tests/fail/intrinsics/simd-reduce-invalid-bool.rs @@ -11,6 +11,6 @@ struct i32x2(i32, i32); fn main() { unsafe { let x = i32x2(0, 1); - simd_reduce_any(x); //~ERROR must be all-0-bits or all-1-bits + simd_reduce_any(x); //~ERROR: must be all-0-bits or all-1-bits } } diff --git a/tests/fail/intrinsics/simd-rem-by-zero.rs b/tests/fail/intrinsics/simd-rem-by-zero.rs index 82cbaed462c69..625889bb67b57 100644 --- a/tests/fail/intrinsics/simd-rem-by-zero.rs +++ b/tests/fail/intrinsics/simd-rem-by-zero.rs @@ -12,6 +12,6 @@ fn main() { unsafe { let x = i32x2(1, 1); let y = i32x2(1, 0); - simd_rem(x, y); //~ERROR Undefined Behavior: calculating the remainder with a divisor of zero + simd_rem(x, y); //~ERROR: Undefined Behavior: calculating the remainder with a divisor of zero } } diff --git a/tests/fail/intrinsics/simd-select-bitmask-invalid.rs b/tests/fail/intrinsics/simd-select-bitmask-invalid.rs index cc9170c646462..8a3895ac14cf8 100644 --- a/tests/fail/intrinsics/simd-select-bitmask-invalid.rs +++ b/tests/fail/intrinsics/simd-select-bitmask-invalid.rs @@ -12,6 +12,6 @@ struct i32x2(i32, i32); fn main() { unsafe { let x = i32x2(0, 1); - simd_select_bitmask(0b11111111u8, x, x); //~ERROR bitmask less than 8 bits long must be filled with 0s for the remaining bits + simd_select_bitmask(0b11111111u8, x, x); //~ERROR: bitmask less than 8 bits long must be filled with 0s for the remaining bits } } diff --git a/tests/fail/intrinsics/simd-select-invalid-bool.rs b/tests/fail/intrinsics/simd-select-invalid-bool.rs index 8ccf4c362c90b..7f7ee3af49516 100644 --- a/tests/fail/intrinsics/simd-select-invalid-bool.rs +++ b/tests/fail/intrinsics/simd-select-invalid-bool.rs @@ -12,6 +12,6 @@ struct i32x2(i32, i32); fn main() { unsafe { let x = i32x2(0, 1); - simd_select(x, x, x); //~ERROR must be all-0-bits or all-1-bits + simd_select(x, x, x); //~ERROR: must be all-0-bits or all-1-bits } } diff --git a/tests/fail/intrinsics/simd-shl-too-far.rs b/tests/fail/intrinsics/simd-shl-too-far.rs index e971b042066cb..5c517c17b3a4b 100644 --- a/tests/fail/intrinsics/simd-shl-too-far.rs +++ b/tests/fail/intrinsics/simd-shl-too-far.rs @@ -12,6 +12,6 @@ fn main() { unsafe { let x = i32x2(1, 1); let y = i32x2(100, 0); - simd_shl(x, y); //~ERROR overflowing shift by 100 in `simd_shl` in SIMD lane 0 + simd_shl(x, y); //~ERROR: overflowing shift by 100 in `simd_shl` in SIMD lane 0 } } diff --git a/tests/fail/intrinsics/simd-shr-too-far.rs b/tests/fail/intrinsics/simd-shr-too-far.rs index ae071f0b7ea13..5f1475a677813 100644 --- a/tests/fail/intrinsics/simd-shr-too-far.rs +++ b/tests/fail/intrinsics/simd-shr-too-far.rs @@ -12,6 +12,6 @@ fn main() { unsafe { let x = i32x2(1, 1); let y = i32x2(20, 40); - simd_shr(x, y); //~ERROR overflowing shift by 40 in `simd_shr` in SIMD lane 1 + simd_shr(x, y); //~ERROR: overflowing shift by 40 in `simd_shr` in SIMD lane 1 } } diff --git a/tests/fail/intrinsics/unchecked_add1.rs b/tests/fail/intrinsics/unchecked_add1.rs index 5409f66e805ea..25dbb817fae0d 100644 --- a/tests/fail/intrinsics/unchecked_add1.rs +++ b/tests/fail/intrinsics/unchecked_add1.rs @@ -2,6 +2,6 @@ fn main() { // MAX overflow unsafe { - std::intrinsics::unchecked_add(40000u16, 30000); //~ ERROR overflow executing `unchecked_add` + std::intrinsics::unchecked_add(40000u16, 30000); //~ ERROR: overflow executing `unchecked_add` } } diff --git a/tests/fail/intrinsics/unchecked_add2.rs b/tests/fail/intrinsics/unchecked_add2.rs index 5deef7ee5ccd3..a454f6478059f 100644 --- a/tests/fail/intrinsics/unchecked_add2.rs +++ b/tests/fail/intrinsics/unchecked_add2.rs @@ -2,6 +2,6 @@ fn main() { // MIN overflow unsafe { - std::intrinsics::unchecked_add(-30000i16, -8000); //~ ERROR overflow executing `unchecked_add` + std::intrinsics::unchecked_add(-30000i16, -8000); //~ ERROR: overflow executing `unchecked_add` } } diff --git a/tests/fail/intrinsics/unchecked_div1.rs b/tests/fail/intrinsics/unchecked_div1.rs index c06a5bdce93e6..6706cee30ef54 100644 --- a/tests/fail/intrinsics/unchecked_div1.rs +++ b/tests/fail/intrinsics/unchecked_div1.rs @@ -2,6 +2,6 @@ fn main() { // MIN/-1 cannot be represented unsafe { - std::intrinsics::unchecked_div(i16::MIN, -1); //~ ERROR overflow in signed division (dividing MIN by -1) + std::intrinsics::unchecked_div(i16::MIN, -1); //~ ERROR: overflow in signed division (dividing MIN by -1) } } diff --git a/tests/fail/intrinsics/unchecked_mul1.rs b/tests/fail/intrinsics/unchecked_mul1.rs index 140bc9e6c75b2..514eb60602da3 100644 --- a/tests/fail/intrinsics/unchecked_mul1.rs +++ b/tests/fail/intrinsics/unchecked_mul1.rs @@ -2,6 +2,6 @@ fn main() { // MAX overflow unsafe { - std::intrinsics::unchecked_mul(300u16, 250u16); //~ ERROR overflow executing `unchecked_mul` + std::intrinsics::unchecked_mul(300u16, 250u16); //~ ERROR: overflow executing `unchecked_mul` } } diff --git a/tests/fail/intrinsics/unchecked_mul2.rs b/tests/fail/intrinsics/unchecked_mul2.rs index c4d16084b3f03..e103c1e7ad179 100644 --- a/tests/fail/intrinsics/unchecked_mul2.rs +++ b/tests/fail/intrinsics/unchecked_mul2.rs @@ -2,6 +2,6 @@ fn main() { // MIN overflow unsafe { - std::intrinsics::unchecked_mul(1_000_000_000i32, -4); //~ ERROR overflow executing `unchecked_mul` + std::intrinsics::unchecked_mul(1_000_000_000i32, -4); //~ ERROR: overflow executing `unchecked_mul` } } diff --git a/tests/fail/intrinsics/unchecked_sub1.rs b/tests/fail/intrinsics/unchecked_sub1.rs index cff79f9135f1f..e99f88edc8635 100644 --- a/tests/fail/intrinsics/unchecked_sub1.rs +++ b/tests/fail/intrinsics/unchecked_sub1.rs @@ -2,6 +2,6 @@ fn main() { // MIN overflow unsafe { - std::intrinsics::unchecked_sub(14u32, 22); //~ ERROR overflow executing `unchecked_sub` + std::intrinsics::unchecked_sub(14u32, 22); //~ ERROR: overflow executing `unchecked_sub` } } diff --git a/tests/fail/intrinsics/unchecked_sub2.rs b/tests/fail/intrinsics/unchecked_sub2.rs index 9b741c2663d89..f83f6843c9ecd 100644 --- a/tests/fail/intrinsics/unchecked_sub2.rs +++ b/tests/fail/intrinsics/unchecked_sub2.rs @@ -2,6 +2,6 @@ fn main() { // MAX overflow unsafe { - std::intrinsics::unchecked_sub(30000i16, -7000); //~ ERROR overflow executing `unchecked_sub` + std::intrinsics::unchecked_sub(30000i16, -7000); //~ ERROR: overflow executing `unchecked_sub` } } diff --git a/tests/fail/intrinsics/write_bytes_null.rs b/tests/fail/intrinsics/write_bytes_null.rs index 81b155da44c33..2f46c820fb73b 100644 --- a/tests/fail/intrinsics/write_bytes_null.rs +++ b/tests/fail/intrinsics/write_bytes_null.rs @@ -6,5 +6,5 @@ extern "rust-intrinsic" { } fn main() { - unsafe { write_bytes::(std::ptr::null_mut(), 0, 0) }; //~ ERROR memory access failed: null pointer is a dangling pointer + unsafe { write_bytes::(std::ptr::null_mut(), 0, 0) }; //~ ERROR: memory access failed: null pointer is a dangling pointer } diff --git a/tests/fail/invalid_bool.rs b/tests/fail/invalid_bool.rs index b2052d982ed80..525f8831c1c00 100644 --- a/tests/fail/invalid_bool.rs +++ b/tests/fail/invalid_bool.rs @@ -5,5 +5,5 @@ fn main() { let b = unsafe { std::mem::transmute::(2) }; - let _x = b == std::hint::black_box(true); //~ ERROR interpreting an invalid 8-bit value as a bool + let _x = b == std::hint::black_box(true); //~ ERROR: interpreting an invalid 8-bit value as a bool } diff --git a/tests/fail/invalid_char.rs b/tests/fail/invalid_char.rs index 8d814fd92e0c6..699248229445f 100644 --- a/tests/fail/invalid_char.rs +++ b/tests/fail/invalid_char.rs @@ -6,5 +6,5 @@ fn main() { let c = 0xFFFFFFu32; assert!(std::char::from_u32(c).is_none()); let c = unsafe { std::mem::transmute::(c) }; - let _x = c == 'x'; //~ ERROR interpreting an invalid 32-bit value as a char + let _x = c == 'x'; //~ ERROR: interpreting an invalid 32-bit value as a char } diff --git a/tests/fail/invalid_int.rs b/tests/fail/invalid_int.rs index 6914c66faec38..4f76f8b6d9488 100644 --- a/tests/fail/invalid_int.rs +++ b/tests/fail/invalid_int.rs @@ -4,5 +4,5 @@ fn main() { let i = unsafe { std::mem::MaybeUninit::::uninit().assume_init() }; - let _x = i + 0; //~ ERROR this operation requires initialized memory + let _x = i + 0; //~ ERROR: this operation requires initialized memory } diff --git a/tests/fail/issue-miri-1112.rs b/tests/fail/issue-miri-1112.rs index caf2b28c5a86e..abf627bb2a767 100644 --- a/tests/fail/issue-miri-1112.rs +++ b/tests/fail/issue-miri-1112.rs @@ -28,7 +28,7 @@ impl FunnyPointer { data: data as *const _ as *const (), vtable: ptr as *const _ as *const (), }; - let obj = std::mem::transmute::(obj); //~ ERROR invalid drop function pointer in vtable + let obj = std::mem::transmute::(obj); //~ ERROR: invalid drop function pointer in vtable &*obj } } diff --git a/tests/fail/modifying_constants.rs b/tests/fail/modifying_constants.rs index 3c47661a4b2d4..2783ebd155ff5 100644 --- a/tests/fail/modifying_constants.rs +++ b/tests/fail/modifying_constants.rs @@ -4,6 +4,6 @@ fn main() { let x = &1; // the `&1` is promoted to a constant, but it used to be that only the pointer is marked static, not the pointee let y = unsafe { &mut *(x as *const i32 as *mut i32) }; - *y = 42; //~ ERROR read-only + *y = 42; //~ ERROR: read-only assert_eq!(*x, 42); } diff --git a/tests/fail/never_say_never.rs b/tests/fail/never_say_never.rs index 6beaada56e9a4..f6d3dc790bf00 100644 --- a/tests/fail/never_say_never.rs +++ b/tests/fail/never_say_never.rs @@ -7,7 +7,7 @@ fn main() { let y = &5; let x: ! = unsafe { - *(y as *const _ as *const !) //~ ERROR entering unreachable code + *(y as *const _ as *const !) //~ ERROR: entering unreachable code }; f(x) } diff --git a/tests/fail/never_transmute_humans.rs b/tests/fail/never_transmute_humans.rs index 010c9d4146d81..de723433dc283 100644 --- a/tests/fail/never_transmute_humans.rs +++ b/tests/fail/never_transmute_humans.rs @@ -7,6 +7,6 @@ struct Human; fn main() { let _x: ! = unsafe { - std::mem::transmute::(Human) //~ ERROR transmuting to uninhabited + std::mem::transmute::(Human) //~ ERROR: transmuting to uninhabited }; } diff --git a/tests/fail/never_transmute_void.rs b/tests/fail/never_transmute_void.rs index d9c34aa7a5ca0..19473e9ac2141 100644 --- a/tests/fail/never_transmute_void.rs +++ b/tests/fail/never_transmute_void.rs @@ -1,5 +1,6 @@ // This should fail even without validation //@compile-flags: -Zmiri-disable-validation +//@require-annotations-for-level: ERROR #![feature(never_type)] #![allow(unused, invalid_value)] @@ -9,11 +10,11 @@ mod m { pub struct Void(VoidI); pub fn f(v: Void) -> ! { - match v.0 {} //~ ERROR entering unreachable code + match v.0 {} //~ ERROR: entering unreachable code } } fn main() { let v = unsafe { std::mem::transmute::<(), m::Void>(()) }; - m::f(v); //~ inside `main` + m::f(v); //~ NOTE: inside `main` } diff --git a/tests/fail/panic/bad_miri_start_panic.rs b/tests/fail/panic/bad_miri_start_panic.rs index 9beeccd1d2204..4b0ae60b10101 100644 --- a/tests/fail/panic/bad_miri_start_panic.rs +++ b/tests/fail/panic/bad_miri_start_panic.rs @@ -8,5 +8,5 @@ extern "C" { fn main() { unsafe { miri_start_panic(&mut 0) } - //~^ ERROR unwinding past a stack frame that does not allow unwinding + //~^ ERROR: unwinding past a stack frame that does not allow unwinding } diff --git a/tests/fail/panic/unwind_panic_abort.rs b/tests/fail/panic/unwind_panic_abort.rs index 40dcf1bc2a3a1..c21fa85a90439 100644 --- a/tests/fail/panic/unwind_panic_abort.rs +++ b/tests/fail/panic/unwind_panic_abort.rs @@ -8,6 +8,6 @@ extern "Rust" { fn main() { unsafe { - miri_start_panic(&mut 0); //~ ERROR unwinding past a stack frame that does not allow unwinding + miri_start_panic(&mut 0); //~ ERROR: unwinding past a stack frame that does not allow unwinding } } diff --git a/tests/fail/pointer_partial_overwrite.rs b/tests/fail/pointer_partial_overwrite.rs index 95af3569f35b3..63f0649b8ed3e 100644 --- a/tests/fail/pointer_partial_overwrite.rs +++ b/tests/fail/pointer_partial_overwrite.rs @@ -12,6 +12,6 @@ fn main() { // "attempted to interpret some raw bytes as a pointer address" instead of // "attempted to read undefined bytes" } - let x = *p; //~ ERROR this operation requires initialized memory + let x = *p; //~ ERROR: this operation requires initialized memory panic!("this should never print: {}", x); } diff --git a/tests/fail/provenance/provenance_transmute.rs b/tests/fail/provenance/provenance_transmute.rs index 90208c88d6946..abcfc060e52bc 100644 --- a/tests/fail/provenance/provenance_transmute.rs +++ b/tests/fail/provenance/provenance_transmute.rs @@ -13,7 +13,7 @@ unsafe fn deref(left: *const u8, right: *const u8) { // The compiler is allowed to replace `left_int` by `right_int` here... let left_ptr: *const u8 = mem::transmute(left_int); // ...which however means here it could be dereferencing the wrong pointer. - let _val = *left_ptr; //~ERROR dereferencing pointer failed + let _val = *left_ptr; //~ERROR: dereferencing pointer failed } } diff --git a/tests/fail/provenance/ptr_int_unexposed.rs b/tests/fail/provenance/ptr_int_unexposed.rs index 5522aa33c7410..dd8d52b2d2e24 100644 --- a/tests/fail/provenance/ptr_int_unexposed.rs +++ b/tests/fail/provenance/ptr_int_unexposed.rs @@ -8,5 +8,5 @@ fn main() { let x_usize: usize = x_ptr.addr(); // Cast back an address that did *not* get exposed. let ptr = std::ptr::from_exposed_addr::(x_usize); - assert_eq!(unsafe { *ptr }, 3); //~ ERROR Undefined Behavior: dereferencing pointer failed + assert_eq!(unsafe { *ptr }, 3); //~ ERROR: Undefined Behavior: dereferencing pointer failed } diff --git a/tests/fail/provenance/ptr_invalid.rs b/tests/fail/provenance/ptr_invalid.rs index be5666b2efadd..d7d32d83e0771 100644 --- a/tests/fail/provenance/ptr_invalid.rs +++ b/tests/fail/provenance/ptr_invalid.rs @@ -5,5 +5,5 @@ fn main() { let x = 42; let xptr = &x as *const i32; let xptr_invalid = std::ptr::invalid::(xptr.expose_addr()); - let _val = unsafe { *xptr_invalid }; //~ ERROR is a dangling pointer + let _val = unsafe { *xptr_invalid }; //~ ERROR: is a dangling pointer } diff --git a/tests/fail/provenance/strict_provenance_cast.rs b/tests/fail/provenance/strict_provenance_cast.rs index bca7ea90a31d0..0016e78792540 100644 --- a/tests/fail/provenance/strict_provenance_cast.rs +++ b/tests/fail/provenance/strict_provenance_cast.rs @@ -2,5 +2,5 @@ fn main() { let addr = &0 as *const i32 as usize; - let _ptr = addr as *const i32; //~ ERROR integer-to-pointer casts and `ptr::from_exposed_addr` are not supported + let _ptr = addr as *const i32; //~ ERROR: integer-to-pointer casts and `ptr::from_exposed_addr` are not supported } diff --git a/tests/fail/rc_as_ptr.rs b/tests/fail/rc_as_ptr.rs index 9aafa2628425a..6aea1870748cc 100644 --- a/tests/fail/rc_as_ptr.rs +++ b/tests/fail/rc_as_ptr.rs @@ -16,5 +16,5 @@ fn main() { drop(strong); // But not any more. We can do Weak::as_raw(&weak), but accessing the pointer would lead to // undefined behaviour. - assert_eq!(42, **unsafe { &*Weak::as_ptr(&weak) }); //~ ERROR dereferenced after this allocation got freed + assert_eq!(42, **unsafe { &*Weak::as_ptr(&weak) }); //~ ERROR: dereferenced after this allocation got freed } diff --git a/tests/fail/reading_half_a_pointer.rs b/tests/fail/reading_half_a_pointer.rs index 2a3b096b2f5a1..a8cdb11f40baf 100644 --- a/tests/fail/reading_half_a_pointer.rs +++ b/tests/fail/reading_half_a_pointer.rs @@ -24,6 +24,6 @@ fn main() { // starts 1 byte to the right, so using it would actually be wrong! let d_alias = &mut w.data as *mut _ as *mut *const u8; unsafe { - let _x = *d_alias; //~ ERROR unable to turn pointer into raw bytes + let _x = *d_alias; //~ ERROR: unable to turn pointer into raw bytes } } diff --git a/tests/fail/rustc-error.rs b/tests/fail/rustc-error.rs index 3579a143f53b7..7fc73bf365d5e 100644 --- a/tests/fail/rustc-error.rs +++ b/tests/fail/rustc-error.rs @@ -1,4 +1,4 @@ // Make sure we exit with non-0 status code when the program fails to build. fn main() { - println("Hello, world!"); //~ ERROR expected function, found macro + println("Hello, world!"); //~ ERROR: expected function, found macro } diff --git a/tests/fail/shim_arg_size.rs b/tests/fail/shim_arg_size.rs index d1ffdf8cddb42..383df286d4c85 100644 --- a/tests/fail/shim_arg_size.rs +++ b/tests/fail/shim_arg_size.rs @@ -12,6 +12,6 @@ fn main() { } unsafe { - let _p1 = malloc(42); //~ ERROR Undefined Behavior: scalar size mismatch + let _p1 = malloc(42); //~ ERROR: Undefined Behavior: scalar size mismatch }; } diff --git a/tests/fail/stacked_borrows/alias_through_mutation.rs b/tests/fail/stacked_borrows/alias_through_mutation.rs index 15d8e45f8b8b0..dfadeec6c9e91 100644 --- a/tests/fail/stacked_borrows/alias_through_mutation.rs +++ b/tests/fail/stacked_borrows/alias_through_mutation.rs @@ -11,5 +11,5 @@ fn main() { retarget(&mut target_alias, target); // now `target_alias` points to the same thing as `target` *target = 13; - let _val = *target_alias; //~ ERROR borrow stack + let _val = *target_alias; //~ ERROR: borrow stack } diff --git a/tests/fail/stacked_borrows/aliasing_mut1.rs b/tests/fail/stacked_borrows/aliasing_mut1.rs index ebee134a8acba..14a27d8e9dd65 100644 --- a/tests/fail/stacked_borrows/aliasing_mut1.rs +++ b/tests/fail/stacked_borrows/aliasing_mut1.rs @@ -1,6 +1,6 @@ use std::mem; -pub fn safe(_x: &mut i32, _y: &mut i32) {} //~ ERROR protect +pub fn safe(_x: &mut i32, _y: &mut i32) {} //~ ERROR: protect fn main() { let mut x = 0; diff --git a/tests/fail/stacked_borrows/aliasing_mut2.rs b/tests/fail/stacked_borrows/aliasing_mut2.rs index 971dbb63a9d66..84d901f83bbcc 100644 --- a/tests/fail/stacked_borrows/aliasing_mut2.rs +++ b/tests/fail/stacked_borrows/aliasing_mut2.rs @@ -1,6 +1,6 @@ use std::mem; -pub fn safe(_x: &i32, _y: &mut i32) {} //~ ERROR protect +pub fn safe(_x: &i32, _y: &mut i32) {} //~ ERROR: protect fn main() { let mut x = 0; diff --git a/tests/fail/stacked_borrows/aliasing_mut3.rs b/tests/fail/stacked_borrows/aliasing_mut3.rs index 91904b0b1d14b..f1ba06b6e4f7a 100644 --- a/tests/fail/stacked_borrows/aliasing_mut3.rs +++ b/tests/fail/stacked_borrows/aliasing_mut3.rs @@ -1,6 +1,6 @@ use std::mem; -pub fn safe(_x: &mut i32, _y: &i32) {} //~ ERROR borrow stack +pub fn safe(_x: &mut i32, _y: &i32) {} //~ ERROR: borrow stack fn main() { let mut x = 0; diff --git a/tests/fail/stacked_borrows/aliasing_mut4.rs b/tests/fail/stacked_borrows/aliasing_mut4.rs index 79caed5dd6b4d..52081b56223da 100644 --- a/tests/fail/stacked_borrows/aliasing_mut4.rs +++ b/tests/fail/stacked_borrows/aliasing_mut4.rs @@ -2,7 +2,7 @@ use std::cell::Cell; use std::mem; // Make sure &mut UnsafeCell also is exclusive -pub fn safe(_x: &i32, _y: &mut Cell) {} //~ ERROR protect +pub fn safe(_x: &i32, _y: &mut Cell) {} //~ ERROR: protect fn main() { let mut x = 0; diff --git a/tests/fail/stacked_borrows/box_exclusive_violation1.rs b/tests/fail/stacked_borrows/box_exclusive_violation1.rs index 66d092d6277c8..ce7ff8f9e2aad 100644 --- a/tests/fail/stacked_borrows/box_exclusive_violation1.rs +++ b/tests/fail/stacked_borrows/box_exclusive_violation1.rs @@ -24,7 +24,7 @@ fn unknown_code_1(x: &i32) { fn unknown_code_2() { unsafe { - *LEAK = 7; //~ ERROR borrow stack + *LEAK = 7; //~ ERROR: borrow stack } } diff --git a/tests/fail/stacked_borrows/buggy_as_mut_slice.rs b/tests/fail/stacked_borrows/buggy_as_mut_slice.rs index 6744e4ef44814..5eeec933c7c86 100644 --- a/tests/fail/stacked_borrows/buggy_as_mut_slice.rs +++ b/tests/fail/stacked_borrows/buggy_as_mut_slice.rs @@ -11,5 +11,5 @@ fn main() { let v1 = safe::as_mut_slice(&v); let _v2 = safe::as_mut_slice(&v); v1[1] = 5; - //~^ ERROR borrow stack + //~^ ERROR: borrow stack } diff --git a/tests/fail/stacked_borrows/buggy_split_at_mut.rs b/tests/fail/stacked_borrows/buggy_split_at_mut.rs index a2ef0fcf178db..92380a4bf4967 100644 --- a/tests/fail/stacked_borrows/buggy_split_at_mut.rs +++ b/tests/fail/stacked_borrows/buggy_split_at_mut.rs @@ -19,7 +19,7 @@ mod safe { fn main() { let mut array = [1, 2, 3, 4]; let (a, b) = safe::split_at_mut(&mut array, 0); - //~^ ERROR borrow stack + //~^ ERROR: borrow stack a[1] = 5; b[1] = 6; } diff --git a/tests/fail/stacked_borrows/illegal_read4.rs b/tests/fail/stacked_borrows/illegal_read4.rs index d7e281e3ffe5c..2d4e395a42703 100644 --- a/tests/fail/stacked_borrows/illegal_read4.rs +++ b/tests/fail/stacked_borrows/illegal_read4.rs @@ -5,5 +5,5 @@ fn main() { let xraw = xref1 as *mut _; let xref2 = unsafe { &mut *xraw }; let _val = unsafe { *xraw }; // use the raw again, this invalidates xref2 *even* with the special read except for uniq refs - let _illegal = *xref2; //~ ERROR borrow stack + let _illegal = *xref2; //~ ERROR: borrow stack } diff --git a/tests/fail/stacked_borrows/illegal_read5.rs b/tests/fail/stacked_borrows/illegal_read5.rs index 8f86a4f0a6b58..49556e618d27b 100644 --- a/tests/fail/stacked_borrows/illegal_read5.rs +++ b/tests/fail/stacked_borrows/illegal_read5.rs @@ -14,5 +14,5 @@ fn main() { let _val = *xref; // we can even still use our mutable reference mem::forget(unsafe { ptr::read(xshr) }); // but after reading through the shared ref let _val = *xref; // the mutable one is dead and gone - //~^ ERROR borrow stack + //~^ ERROR: borrow stack } diff --git a/tests/fail/stacked_borrows/illegal_read6.rs b/tests/fail/stacked_borrows/illegal_read6.rs index af89566f65074..943a61af4f6ef 100644 --- a/tests/fail/stacked_borrows/illegal_read6.rs +++ b/tests/fail/stacked_borrows/illegal_read6.rs @@ -5,6 +5,6 @@ fn main() { let raw = x as *mut _; let x = &mut *x; // kill `raw` let _y = &*x; // this should not activate `raw` again - let _val = *raw; //~ ERROR borrow stack + let _val = *raw; //~ ERROR: borrow stack } } diff --git a/tests/fail/stacked_borrows/illegal_read7.rs b/tests/fail/stacked_borrows/illegal_read7.rs index e960bd5388c03..e263e8b70a91d 100644 --- a/tests/fail/stacked_borrows/illegal_read7.rs +++ b/tests/fail/stacked_borrows/illegal_read7.rs @@ -17,6 +17,6 @@ fn main() { // without invalidating `x`. That would be bad! It would mean that creating `shr` // leaked `x` to `raw`. let _val = ptr::read(raw); - let _val = *x.get_mut(); //~ ERROR borrow stack + let _val = *x.get_mut(); //~ ERROR: borrow stack } } diff --git a/tests/fail/stacked_borrows/illegal_read8.rs b/tests/fail/stacked_borrows/illegal_read8.rs index 9fef673fe6c13..13c12cc75d77b 100644 --- a/tests/fail/stacked_borrows/illegal_read8.rs +++ b/tests/fail/stacked_borrows/illegal_read8.rs @@ -10,6 +10,6 @@ fn main() { let _val = *y2; let _val = *y1; *y2 += 1; - let _fail = *y1; //~ ERROR borrow stack + let _fail = *y1; //~ ERROR: borrow stack } } diff --git a/tests/fail/stacked_borrows/illegal_write1.rs b/tests/fail/stacked_borrows/illegal_write1.rs index 58600402e4edd..7abf2f5a9b8fc 100644 --- a/tests/fail/stacked_borrows/illegal_write1.rs +++ b/tests/fail/stacked_borrows/illegal_write1.rs @@ -3,7 +3,7 @@ fn main() { let xref = &*target; { let x: *mut u32 = xref as *const _ as *mut _; - unsafe { *x = 42 }; //~ ERROR only grants SharedReadOnly permission + unsafe { *x = 42 }; //~ ERROR: only grants SharedReadOnly permission } let _x = *xref; } diff --git a/tests/fail/stacked_borrows/illegal_write2.rs b/tests/fail/stacked_borrows/illegal_write2.rs index 32dc474385d6c..62074bcdbdc14 100644 --- a/tests/fail/stacked_borrows/illegal_write2.rs +++ b/tests/fail/stacked_borrows/illegal_write2.rs @@ -3,6 +3,6 @@ fn main() { let target2 = target as *mut _; drop(&mut *target); // reborrow // Now make sure our ref is still the only one. - unsafe { *target2 = 13 }; //~ ERROR borrow stack + unsafe { *target2 = 13 }; //~ ERROR: borrow stack let _val = *target; } diff --git a/tests/fail/stacked_borrows/illegal_write3.rs b/tests/fail/stacked_borrows/illegal_write3.rs index 87fdbae701926..cb143340dedb8 100644 --- a/tests/fail/stacked_borrows/illegal_write3.rs +++ b/tests/fail/stacked_borrows/illegal_write3.rs @@ -3,6 +3,6 @@ fn main() { // Make sure raw ptr with raw tag cannot mutate frozen location without breaking the shared ref. let r#ref = ⌖ // freeze let ptr = r#ref as *const _ as *mut _; // raw ptr, with raw tag - unsafe { *ptr = 42 }; //~ ERROR only grants SharedReadOnly permission + unsafe { *ptr = 42 }; //~ ERROR: only grants SharedReadOnly permission let _val = *r#ref; } diff --git a/tests/fail/stacked_borrows/illegal_write4.rs b/tests/fail/stacked_borrows/illegal_write4.rs index 654a23d382b8d..082eebcba1ba9 100644 --- a/tests/fail/stacked_borrows/illegal_write4.rs +++ b/tests/fail/stacked_borrows/illegal_write4.rs @@ -9,5 +9,5 @@ fn main() { let _ptr = reference as *const _ as *mut i32; // raw ptr, with raw tag let _mut_ref: &mut i32 = unsafe { mem::transmute(raw) }; // &mut, with raw tag // Now we retag, making our ref top-of-stack -- and, in particular, unfreezing. - let _val = *reference; //~ ERROR borrow stack + let _val = *reference; //~ ERROR: borrow stack } diff --git a/tests/fail/stacked_borrows/interior_mut1.rs b/tests/fail/stacked_borrows/interior_mut1.rs index 1ef78edbb7ce2..a27295fbf2cc0 100644 --- a/tests/fail/stacked_borrows/interior_mut1.rs +++ b/tests/fail/stacked_borrows/interior_mut1.rs @@ -12,6 +12,6 @@ fn main() { *c.get() = UnsafeCell::new(1); // invalidates inner_shr // stack: [c: SharedReadWrite] - let _val = *inner_shr.get(); //~ ERROR borrow stack + let _val = *inner_shr.get(); //~ ERROR: borrow stack } } diff --git a/tests/fail/stacked_borrows/interior_mut2.rs b/tests/fail/stacked_borrows/interior_mut2.rs index 4433f28e3459a..ba5eb63084e05 100644 --- a/tests/fail/stacked_borrows/interior_mut2.rs +++ b/tests/fail/stacked_borrows/interior_mut2.rs @@ -25,6 +25,6 @@ fn main() { // stack: [c: SharedReadWrite] // now this does not work any more - let _val = *inner_shr.get(); //~ ERROR borrow stack + let _val = *inner_shr.get(); //~ ERROR: borrow stack } } diff --git a/tests/fail/stacked_borrows/invalidate_against_barrier1.rs b/tests/fail/stacked_borrows/invalidate_against_barrier1.rs index 3a214a75b5059..d0f43510c28ff 100644 --- a/tests/fail/stacked_borrows/invalidate_against_barrier1.rs +++ b/tests/fail/stacked_borrows/invalidate_against_barrier1.rs @@ -2,7 +2,7 @@ fn inner(x: *mut i32, _y: &mut i32) { // If `x` and `y` alias, retagging is fine with this... but we really // shouldn't be allowed to use `x` at all because `y` was assumed to be // unique for the duration of this call. - let _val = unsafe { *x }; //~ ERROR protect + let _val = unsafe { *x }; //~ ERROR: protect } fn main() { diff --git a/tests/fail/stacked_borrows/invalidate_against_barrier2.rs b/tests/fail/stacked_borrows/invalidate_against_barrier2.rs index 86e4a84287ec1..f4e767302fd00 100644 --- a/tests/fail/stacked_borrows/invalidate_against_barrier2.rs +++ b/tests/fail/stacked_borrows/invalidate_against_barrier2.rs @@ -2,7 +2,7 @@ fn inner(x: *mut i32, _y: &i32) { // If `x` and `y` alias, retagging is fine with this... but we really // shouldn't be allowed to write to `x` at all because `y` was assumed to be // immutable for the duration of this call. - unsafe { *x = 0 }; //~ ERROR protect + unsafe { *x = 0 }; //~ ERROR: protect } fn main() { diff --git a/tests/fail/stacked_borrows/load_invalid_mut.rs b/tests/fail/stacked_borrows/load_invalid_mut.rs index f0ae77f861012..ec69b08a1f8a5 100644 --- a/tests/fail/stacked_borrows/load_invalid_mut.rs +++ b/tests/fail/stacked_borrows/load_invalid_mut.rs @@ -8,5 +8,5 @@ fn main() { let xref = unsafe { &mut *xraw }; let xref_in_mem = Box::new(xref); let _val = unsafe { *xraw }; // invalidate xref - let _val = *xref_in_mem; //~ ERROR borrow stack + let _val = *xref_in_mem; //~ ERROR: borrow stack } diff --git a/tests/fail/stacked_borrows/load_invalid_shr.rs b/tests/fail/stacked_borrows/load_invalid_shr.rs index 36ffef656e7f3..6de857acffaa2 100644 --- a/tests/fail/stacked_borrows/load_invalid_shr.rs +++ b/tests/fail/stacked_borrows/load_invalid_shr.rs @@ -8,5 +8,5 @@ fn main() { let xref = unsafe { &*xraw }; let xref_in_mem = Box::new(xref); unsafe { *xraw = 42 }; // unfreeze - let _val = *xref_in_mem; //~ ERROR borrow stack + let _val = *xref_in_mem; //~ ERROR: borrow stack } diff --git a/tests/fail/stacked_borrows/mut_exclusive_violation1.rs b/tests/fail/stacked_borrows/mut_exclusive_violation1.rs index a1cb7107eee0d..c2c13855fcb5c 100644 --- a/tests/fail/stacked_borrows/mut_exclusive_violation1.rs +++ b/tests/fail/stacked_borrows/mut_exclusive_violation1.rs @@ -24,7 +24,7 @@ fn unknown_code_1(x: &i32) { fn unknown_code_2() { unsafe { - *LEAK = 7; //~ ERROR borrow stack + *LEAK = 7; //~ ERROR: borrow stack } } diff --git a/tests/fail/stacked_borrows/mut_exclusive_violation2.rs b/tests/fail/stacked_borrows/mut_exclusive_violation2.rs index a5bf8353bae8c..980ffad3c160c 100644 --- a/tests/fail/stacked_borrows/mut_exclusive_violation2.rs +++ b/tests/fail/stacked_borrows/mut_exclusive_violation2.rs @@ -7,6 +7,6 @@ fn main() { let mut ptr2 = ptr1.clone(); let raw1 = ptr1.as_mut(); let _raw2 = ptr2.as_mut(); - let _val = *raw1; //~ ERROR borrow stack + let _val = *raw1; //~ ERROR: borrow stack } } diff --git a/tests/fail/stacked_borrows/outdated_local.rs b/tests/fail/stacked_borrows/outdated_local.rs index 4cb655366ef1f..1d4007cf0c435 100644 --- a/tests/fail/stacked_borrows/outdated_local.rs +++ b/tests/fail/stacked_borrows/outdated_local.rs @@ -3,7 +3,7 @@ fn main() { let y: *const i32 = &x; x = 1; // this invalidates y by reactivating the lowermost uniq borrow for this local - assert_eq!(unsafe { *y }, 1); //~ ERROR borrow stack + assert_eq!(unsafe { *y }, 1); //~ ERROR: borrow stack assert_eq!(x, 1); } diff --git a/tests/fail/stacked_borrows/pass_invalid_mut.rs b/tests/fail/stacked_borrows/pass_invalid_mut.rs index d8a53b7a96309..b2e5b8495073a 100644 --- a/tests/fail/stacked_borrows/pass_invalid_mut.rs +++ b/tests/fail/stacked_borrows/pass_invalid_mut.rs @@ -6,5 +6,5 @@ fn main() { let xraw = x as *mut _; let xref = unsafe { &mut *xraw }; let _val = unsafe { *xraw }; // invalidate xref - foo(xref); //~ ERROR borrow stack + foo(xref); //~ ERROR: borrow stack } diff --git a/tests/fail/stacked_borrows/pass_invalid_shr.rs b/tests/fail/stacked_borrows/pass_invalid_shr.rs index 091604a283b9c..539ebb430a3ed 100644 --- a/tests/fail/stacked_borrows/pass_invalid_shr.rs +++ b/tests/fail/stacked_borrows/pass_invalid_shr.rs @@ -6,5 +6,5 @@ fn main() { let xraw = x as *mut _; let xref = unsafe { &*xraw }; unsafe { *xraw = 42 }; // unfreeze - foo(xref); //~ ERROR borrow stack + foo(xref); //~ ERROR: borrow stack } diff --git a/tests/fail/stacked_borrows/pointer_smuggling.rs b/tests/fail/stacked_borrows/pointer_smuggling.rs index f724cdd2a7694..839e8b5abdeef 100644 --- a/tests/fail/stacked_borrows/pointer_smuggling.rs +++ b/tests/fail/stacked_borrows/pointer_smuggling.rs @@ -8,7 +8,7 @@ fn fun1(x: &mut u8) { fn fun2() { // Now we use a pointer we are not allowed to use - let _x = unsafe { *PTR }; //~ ERROR borrow stack + let _x = unsafe { *PTR }; //~ ERROR: borrow stack } fn main() { diff --git a/tests/fail/stacked_borrows/raw_tracking.rs b/tests/fail/stacked_borrows/raw_tracking.rs index 49fe983125500..5950e910b8a65 100644 --- a/tests/fail/stacked_borrows/raw_tracking.rs +++ b/tests/fail/stacked_borrows/raw_tracking.rs @@ -6,6 +6,6 @@ fn main() { let raw2 = &mut l as *mut _; // invalidates raw1 // Without raw pointer tracking, Stacked Borrows cannot distinguish raw1 and raw2, and thus // fails to realize that raw1 should not be used any more. - unsafe { *raw1 = 13 }; //~ ERROR does not exist in the borrow stack + unsafe { *raw1 = 13 }; //~ ERROR: does not exist in the borrow stack unsafe { *raw2 = 13 }; } diff --git a/tests/fail/stacked_borrows/return_invalid_mut.rs b/tests/fail/stacked_borrows/return_invalid_mut.rs index 54004ec438823..acdc7a4ace697 100644 --- a/tests/fail/stacked_borrows/return_invalid_mut.rs +++ b/tests/fail/stacked_borrows/return_invalid_mut.rs @@ -3,7 +3,7 @@ fn foo(x: &mut (i32, i32)) -> &mut i32 { let xraw = x as *mut (i32, i32); let ret = unsafe { &mut (*xraw).1 }; let _val = unsafe { *xraw }; // invalidate xref - ret //~ ERROR borrow stack + ret //~ ERROR: borrow stack } fn main() { diff --git a/tests/fail/stacked_borrows/return_invalid_mut_option.rs b/tests/fail/stacked_borrows/return_invalid_mut_option.rs index ccdb3dc505790..931b420166e7d 100644 --- a/tests/fail/stacked_borrows/return_invalid_mut_option.rs +++ b/tests/fail/stacked_borrows/return_invalid_mut_option.rs @@ -10,7 +10,7 @@ fn foo(x: &mut (i32, i32)) -> Option<&mut i32> { fn main() { match foo(&mut (1, 2)) { - Some(_x) => {} //~ ERROR borrow stack + Some(_x) => {} //~ ERROR: borrow stack None => {} } } diff --git a/tests/fail/stacked_borrows/return_invalid_shr.rs b/tests/fail/stacked_borrows/return_invalid_shr.rs index eab026f9a47c6..a595b91c834c8 100644 --- a/tests/fail/stacked_borrows/return_invalid_shr.rs +++ b/tests/fail/stacked_borrows/return_invalid_shr.rs @@ -3,7 +3,7 @@ fn foo(x: &mut (i32, i32)) -> &i32 { let xraw = x as *mut (i32, i32); let ret = unsafe { &(*xraw).1 }; unsafe { *xraw = (42, 23) }; // unfreeze - ret //~ ERROR borrow stack + ret //~ ERROR: borrow stack } fn main() { diff --git a/tests/fail/stacked_borrows/return_invalid_shr_option.rs b/tests/fail/stacked_borrows/return_invalid_shr_option.rs index 42b4871c46747..56af567f6e8f5 100644 --- a/tests/fail/stacked_borrows/return_invalid_shr_option.rs +++ b/tests/fail/stacked_borrows/return_invalid_shr_option.rs @@ -9,7 +9,7 @@ fn foo(x: &mut (i32, i32)) -> Option<&i32> { fn main() { match foo(&mut (1, 2)) { - Some(_x) => {} //~ ERROR borrow stack + Some(_x) => {} //~ ERROR: borrow stack None => {} } } diff --git a/tests/fail/stacked_borrows/return_invalid_shr_tuple.rs b/tests/fail/stacked_borrows/return_invalid_shr_tuple.rs index d7494d6ee653b..38f01d7cc20b3 100644 --- a/tests/fail/stacked_borrows/return_invalid_shr_tuple.rs +++ b/tests/fail/stacked_borrows/return_invalid_shr_tuple.rs @@ -8,5 +8,5 @@ fn foo(x: &mut (i32, i32)) -> (&i32,) { } fn main() { - foo(&mut (1, 2)).0; //~ ERROR borrow stack + foo(&mut (1, 2)).0; //~ ERROR: borrow stack } diff --git a/tests/fail/stacked_borrows/shared_rw_borrows_are_weak1.rs b/tests/fail/stacked_borrows/shared_rw_borrows_are_weak1.rs index a08d2b716ee73..91994d286b95c 100644 --- a/tests/fail/stacked_borrows/shared_rw_borrows_are_weak1.rs +++ b/tests/fail/stacked_borrows/shared_rw_borrows_are_weak1.rs @@ -11,6 +11,6 @@ fn main() { let y: &mut Cell = mem::transmute(&mut *x); // launder lifetime let shr_rw = &*x; // thanks to interior mutability this will be a SharedReadWrite shr_rw.set(1); - y.get_mut(); //~ ERROR borrow stack + y.get_mut(); //~ ERROR: borrow stack } } diff --git a/tests/fail/stacked_borrows/shared_rw_borrows_are_weak2.rs b/tests/fail/stacked_borrows/shared_rw_borrows_are_weak2.rs index 2fc05c2bf4cc7..ee44ebbb07185 100644 --- a/tests/fail/stacked_borrows/shared_rw_borrows_are_weak2.rs +++ b/tests/fail/stacked_borrows/shared_rw_borrows_are_weak2.rs @@ -12,6 +12,6 @@ fn main() { let y: &i32 = mem::transmute(&*x.borrow()); // launder lifetime let shr_rw = &*x; // thanks to interior mutability this will be a SharedReadWrite shr_rw.replace(1); - let _val = *y; //~ ERROR borrow stack + let _val = *y; //~ ERROR: borrow stack } } diff --git a/tests/fail/stacked_borrows/shr_frozen_violation1.rs b/tests/fail/stacked_borrows/shr_frozen_violation1.rs index a6dd9ef4c2eef..11082da6ea3ab 100644 --- a/tests/fail/stacked_borrows/shr_frozen_violation1.rs +++ b/tests/fail/stacked_borrows/shr_frozen_violation1.rs @@ -10,6 +10,6 @@ fn main() { fn unknown_code(x: &i32) { unsafe { - *(x as *const i32 as *mut i32) = 7; //~ ERROR only grants SharedReadOnly permission + *(x as *const i32 as *mut i32) = 7; //~ ERROR: only grants SharedReadOnly permission } } diff --git a/tests/fail/stacked_borrows/static_memory_modification.rs b/tests/fail/stacked_borrows/static_memory_modification.rs index 417a03bb0335b..84d7878b264e5 100644 --- a/tests/fail/stacked_borrows/static_memory_modification.rs +++ b/tests/fail/stacked_borrows/static_memory_modification.rs @@ -3,6 +3,6 @@ static X: usize = 5; #[allow(mutable_transmutes)] fn main() { let _x = unsafe { - std::mem::transmute::<&usize, &mut usize>(&X) //~ ERROR writing to alloc1 which is read-only + std::mem::transmute::<&usize, &mut usize>(&X) //~ ERROR: writing to alloc1 which is read-only }; } diff --git a/tests/fail/stacked_borrows/transmute-is-no-escape.rs b/tests/fail/stacked_borrows/transmute-is-no-escape.rs index 45035683d5c00..c7d6090232016 100644 --- a/tests/fail/stacked_borrows/transmute-is-no-escape.rs +++ b/tests/fail/stacked_borrows/transmute-is-no-escape.rs @@ -10,5 +10,5 @@ fn main() { let _raw: *mut i32 = unsafe { mem::transmute(&mut x[0]) }; // `raw` still carries a tag, so we get another pointer to the same location that does not carry a tag let raw = (&mut x[1] as *mut i32).wrapping_offset(-1); - unsafe { *raw = 13 }; //~ ERROR borrow stack + unsafe { *raw = 13 }; //~ ERROR: borrow stack } diff --git a/tests/fail/stacked_borrows/unescaped_local.rs b/tests/fail/stacked_borrows/unescaped_local.rs index e6cd8f09b1ad9..5b808472b4e63 100644 --- a/tests/fail/stacked_borrows/unescaped_local.rs +++ b/tests/fail/stacked_borrows/unescaped_local.rs @@ -7,6 +7,6 @@ fn main() { let raw = &mut x as *mut i32 as usize as *mut i32; let _ptr = &mut x; unsafe { - *raw = 13; //~ ERROR borrow stack + *raw = 13; //~ ERROR: borrow stack } } diff --git a/tests/fail/stacked_borrows/unescaped_static.rs b/tests/fail/stacked_borrows/unescaped_static.rs index 0f0467fc5cb99..66641d648d86f 100644 --- a/tests/fail/stacked_borrows/unescaped_static.rs +++ b/tests/fail/stacked_borrows/unescaped_static.rs @@ -3,5 +3,5 @@ static ARRAY: [u8; 2] = [0, 1]; fn main() { let ptr_to_first = &ARRAY[0] as *const u8; // Illegally use this to access the 2nd element. - let _val = unsafe { *ptr_to_first.add(1) }; //~ ERROR borrow stack + let _val = unsafe { *ptr_to_first.add(1) }; //~ ERROR: borrow stack } diff --git a/tests/fail/static_memory_modification1.rs b/tests/fail/static_memory_modification1.rs index 38e8af4c4f1a5..66794e7535a45 100644 --- a/tests/fail/static_memory_modification1.rs +++ b/tests/fail/static_memory_modification1.rs @@ -6,7 +6,7 @@ static X: usize = 5; #[allow(mutable_transmutes)] fn main() { unsafe { - *std::mem::transmute::<&usize, &mut usize>(&X) = 6; //~ ERROR read-only + *std::mem::transmute::<&usize, &mut usize>(&X) = 6; //~ ERROR: read-only assert_eq!(X, 6); } } diff --git a/tests/fail/static_memory_modification2.rs b/tests/fail/static_memory_modification2.rs index 2e9d123c6d394..d8ae3a57c51e3 100644 --- a/tests/fail/static_memory_modification2.rs +++ b/tests/fail/static_memory_modification2.rs @@ -7,6 +7,6 @@ use std::mem::transmute; fn main() { unsafe { let s = "this is a test"; - transmute::<&[u8], &mut [u8]>(s.as_bytes())[4] = 42; //~ ERROR read-only + transmute::<&[u8], &mut [u8]>(s.as_bytes())[4] = 42; //~ ERROR: read-only } } diff --git a/tests/fail/static_memory_modification3.rs b/tests/fail/static_memory_modification3.rs index 34ccd13c429d8..b8e2c6470ff20 100644 --- a/tests/fail/static_memory_modification3.rs +++ b/tests/fail/static_memory_modification3.rs @@ -7,6 +7,6 @@ use std::mem::transmute; fn main() { unsafe { let bs = b"this is a test"; - transmute::<&[u8], &mut [u8]>(bs)[4] = 42; //~ ERROR read-only + transmute::<&[u8], &mut [u8]>(bs)[4] = 42; //~ ERROR: read-only } } diff --git a/tests/fail/sync/libc_pthread_cond_double_destroy.rs b/tests/fail/sync/libc_pthread_cond_double_destroy.rs index d358b3d4f631f..77235d485cde7 100644 --- a/tests/fail/sync/libc_pthread_cond_double_destroy.rs +++ b/tests/fail/sync/libc_pthread_cond_double_destroy.rs @@ -17,6 +17,6 @@ fn main() { libc::pthread_cond_destroy(cond.as_mut_ptr()); libc::pthread_cond_destroy(cond.as_mut_ptr()); - //~^ ERROR Undefined Behavior: using uninitialized data, but this operation requires initialized memory + //~^ ERROR: Undefined Behavior: using uninitialized data, but this operation requires initialized memory } } diff --git a/tests/fail/sync/libc_pthread_condattr_double_destroy.rs b/tests/fail/sync/libc_pthread_condattr_double_destroy.rs index bf6b038a212f1..3b4522fb046c7 100644 --- a/tests/fail/sync/libc_pthread_condattr_double_destroy.rs +++ b/tests/fail/sync/libc_pthread_condattr_double_destroy.rs @@ -14,6 +14,6 @@ fn main() { libc::pthread_condattr_destroy(attr.as_mut_ptr()); libc::pthread_condattr_destroy(attr.as_mut_ptr()); - //~^ ERROR Undefined Behavior: using uninitialized data, but this operation requires initialized memory + //~^ ERROR: Undefined Behavior: using uninitialized data, but this operation requires initialized memory } } diff --git a/tests/fail/sync/libc_pthread_mutex_NULL_deadlock.rs b/tests/fail/sync/libc_pthread_mutex_NULL_deadlock.rs index 22dd656023b73..ade9903b9dd50 100644 --- a/tests/fail/sync/libc_pthread_mutex_NULL_deadlock.rs +++ b/tests/fail/sync/libc_pthread_mutex_NULL_deadlock.rs @@ -11,6 +11,6 @@ fn main() { let mut mutex: libc::pthread_mutex_t = std::mem::zeroed(); assert_eq!(libc::pthread_mutex_init(&mut mutex as *mut _, std::ptr::null() as *const _), 0); assert_eq!(libc::pthread_mutex_lock(&mut mutex as *mut _), 0); - libc::pthread_mutex_lock(&mut mutex as *mut _); //~ ERROR Undefined Behavior: trying to acquire already locked default mutex + libc::pthread_mutex_lock(&mut mutex as *mut _); //~ ERROR: Undefined Behavior: trying to acquire already locked default mutex } } diff --git a/tests/fail/sync/libc_pthread_mutex_default_deadlock.rs b/tests/fail/sync/libc_pthread_mutex_default_deadlock.rs index e34dfe5e367e1..dee5c80e9c405 100644 --- a/tests/fail/sync/libc_pthread_mutex_default_deadlock.rs +++ b/tests/fail/sync/libc_pthread_mutex_default_deadlock.rs @@ -12,6 +12,6 @@ fn main() { let mut mutex: libc::pthread_mutex_t = std::mem::zeroed(); assert_eq!(libc::pthread_mutex_init(&mut mutex as *mut _, &mutexattr as *const _), 0); assert_eq!(libc::pthread_mutex_lock(&mut mutex as *mut _), 0); - libc::pthread_mutex_lock(&mut mutex as *mut _); //~ ERROR Undefined Behavior: trying to acquire already locked default mutex + libc::pthread_mutex_lock(&mut mutex as *mut _); //~ ERROR: Undefined Behavior: trying to acquire already locked default mutex } } diff --git a/tests/fail/sync/libc_pthread_mutex_destroy_locked.rs b/tests/fail/sync/libc_pthread_mutex_destroy_locked.rs index ada3d311134d3..a7ef5e44c9da1 100644 --- a/tests/fail/sync/libc_pthread_mutex_destroy_locked.rs +++ b/tests/fail/sync/libc_pthread_mutex_destroy_locked.rs @@ -14,6 +14,6 @@ fn main() { let mut mutex: libc::pthread_mutex_t = std::mem::zeroed(); assert_eq!(libc::pthread_mutex_init(&mut mutex as *mut _, &mutexattr as *const _), 0); assert_eq!(libc::pthread_mutex_lock(&mut mutex as *mut _), 0); - libc::pthread_mutex_destroy(&mut mutex as *mut _); //~ ERROR destroyed a locked mutex + libc::pthread_mutex_destroy(&mut mutex as *mut _); //~ ERROR: destroyed a locked mutex } } diff --git a/tests/fail/sync/libc_pthread_mutex_double_destroy.rs b/tests/fail/sync/libc_pthread_mutex_double_destroy.rs index 4cf006437b391..8f60409b0052b 100644 --- a/tests/fail/sync/libc_pthread_mutex_double_destroy.rs +++ b/tests/fail/sync/libc_pthread_mutex_double_destroy.rs @@ -18,6 +18,6 @@ fn main() { libc::pthread_mutex_destroy(mutex.as_mut_ptr()); libc::pthread_mutex_destroy(mutex.as_mut_ptr()); - //~^ ERROR Undefined Behavior: using uninitialized data, but this operation requires initialized memory + //~^ ERROR: Undefined Behavior: using uninitialized data, but this operation requires initialized memory } } diff --git a/tests/fail/sync/libc_pthread_mutex_normal_deadlock.rs b/tests/fail/sync/libc_pthread_mutex_normal_deadlock.rs index 8ecad494cfee6..45475249befcd 100644 --- a/tests/fail/sync/libc_pthread_mutex_normal_deadlock.rs +++ b/tests/fail/sync/libc_pthread_mutex_normal_deadlock.rs @@ -14,6 +14,6 @@ fn main() { let mut mutex: libc::pthread_mutex_t = std::mem::zeroed(); assert_eq!(libc::pthread_mutex_init(&mut mutex as *mut _, &mutexattr as *const _), 0); assert_eq!(libc::pthread_mutex_lock(&mut mutex as *mut _), 0); - libc::pthread_mutex_lock(&mut mutex as *mut _); //~ ERROR deadlock: the evaluated program deadlocked + libc::pthread_mutex_lock(&mut mutex as *mut _); //~ ERROR: deadlock: the evaluated program deadlocked } } diff --git a/tests/fail/sync/libc_pthread_mutex_normal_unlock_unlocked.rs b/tests/fail/sync/libc_pthread_mutex_normal_unlock_unlocked.rs index 0109907a11862..da23819ebc314 100644 --- a/tests/fail/sync/libc_pthread_mutex_normal_unlock_unlocked.rs +++ b/tests/fail/sync/libc_pthread_mutex_normal_unlock_unlocked.rs @@ -15,6 +15,6 @@ fn main() { assert_eq!(libc::pthread_mutex_init(&mut mutex as *mut _, &mutexattr as *const _), 0); assert_eq!(libc::pthread_mutex_lock(&mut mutex as *mut _), 0); assert_eq!(libc::pthread_mutex_unlock(&mut mutex as *mut _), 0); - libc::pthread_mutex_unlock(&mut mutex as *mut _); //~ ERROR was not locked + libc::pthread_mutex_unlock(&mut mutex as *mut _); //~ ERROR: was not locked } } diff --git a/tests/fail/sync/libc_pthread_mutexattr_double_destroy.rs b/tests/fail/sync/libc_pthread_mutexattr_double_destroy.rs index ffa786b65893f..8fb7cc3ea6030 100644 --- a/tests/fail/sync/libc_pthread_mutexattr_double_destroy.rs +++ b/tests/fail/sync/libc_pthread_mutexattr_double_destroy.rs @@ -14,6 +14,6 @@ fn main() { libc::pthread_mutexattr_destroy(attr.as_mut_ptr()); libc::pthread_mutexattr_destroy(attr.as_mut_ptr()); - //~^ ERROR Undefined Behavior: using uninitialized data, but this operation requires initialized memory + //~^ ERROR: Undefined Behavior: using uninitialized data, but this operation requires initialized memory } } diff --git a/tests/fail/sync/libc_pthread_rwlock_destroy_read_locked.rs b/tests/fail/sync/libc_pthread_rwlock_destroy_read_locked.rs index 6a9f548d1a301..0efb6724c1774 100644 --- a/tests/fail/sync/libc_pthread_rwlock_destroy_read_locked.rs +++ b/tests/fail/sync/libc_pthread_rwlock_destroy_read_locked.rs @@ -8,6 +8,6 @@ fn main() { let rw = std::cell::UnsafeCell::new(libc::PTHREAD_RWLOCK_INITIALIZER); unsafe { assert_eq!(libc::pthread_rwlock_rdlock(rw.get()), 0); - libc::pthread_rwlock_destroy(rw.get()); //~ ERROR destroyed a locked rwlock + libc::pthread_rwlock_destroy(rw.get()); //~ ERROR: destroyed a locked rwlock } } diff --git a/tests/fail/sync/libc_pthread_rwlock_destroy_write_locked.rs b/tests/fail/sync/libc_pthread_rwlock_destroy_write_locked.rs index 5f5f16d2cf0ee..11c09c1b13426 100644 --- a/tests/fail/sync/libc_pthread_rwlock_destroy_write_locked.rs +++ b/tests/fail/sync/libc_pthread_rwlock_destroy_write_locked.rs @@ -8,6 +8,6 @@ fn main() { let rw = std::cell::UnsafeCell::new(libc::PTHREAD_RWLOCK_INITIALIZER); unsafe { assert_eq!(libc::pthread_rwlock_wrlock(rw.get()), 0); - libc::pthread_rwlock_destroy(rw.get()); //~ ERROR destroyed a locked rwlock + libc::pthread_rwlock_destroy(rw.get()); //~ ERROR: destroyed a locked rwlock } } diff --git a/tests/fail/sync/libc_pthread_rwlock_double_destroy.rs b/tests/fail/sync/libc_pthread_rwlock_double_destroy.rs index 1ba89fb22cf39..9de0383f9daf4 100644 --- a/tests/fail/sync/libc_pthread_rwlock_double_destroy.rs +++ b/tests/fail/sync/libc_pthread_rwlock_double_destroy.rs @@ -11,6 +11,6 @@ fn main() { libc::pthread_rwlock_destroy(&mut lock); libc::pthread_rwlock_destroy(&mut lock); - //~^ ERROR Undefined Behavior: using uninitialized data, but this operation requires initialized memory + //~^ ERROR: Undefined Behavior: using uninitialized data, but this operation requires initialized memory } } diff --git a/tests/fail/sync/libc_pthread_rwlock_unlock_unlocked.rs b/tests/fail/sync/libc_pthread_rwlock_unlock_unlocked.rs index 7918a9665a033..9d3ca275cb04f 100644 --- a/tests/fail/sync/libc_pthread_rwlock_unlock_unlocked.rs +++ b/tests/fail/sync/libc_pthread_rwlock_unlock_unlocked.rs @@ -7,6 +7,6 @@ extern crate libc; fn main() { let rw = std::cell::UnsafeCell::new(libc::PTHREAD_RWLOCK_INITIALIZER); unsafe { - libc::pthread_rwlock_unlock(rw.get()); //~ ERROR was not locked + libc::pthread_rwlock_unlock(rw.get()); //~ ERROR: was not locked } } diff --git a/tests/fail/transmute-pair-uninit.rs b/tests/fail/transmute-pair-uninit.rs index 0835287b9e4ff..bc95f3cb7ad3a 100644 --- a/tests/fail/transmute-pair-uninit.rs +++ b/tests/fail/transmute-pair-uninit.rs @@ -17,7 +17,7 @@ fn main() { assert_eq!(byte, 0); } let v = unsafe { *z.offset(first_undef) }; - //~^ ERROR uninitialized + //~^ ERROR: uninitialized if v == 0 { println!("it is zero"); } diff --git a/tests/fail/type-too-large.rs b/tests/fail/type-too-large.rs index 932964ebdd7b9..21b272f8ec398 100644 --- a/tests/fail/type-too-large.rs +++ b/tests/fail/type-too-large.rs @@ -2,5 +2,5 @@ fn main() { let _fat: [u8; (1 << 61) + (1 << 31)]; - _fat = [0; (1u64 << 61) as usize + (1u64 << 31) as usize]; //~ ERROR post-monomorphization error + _fat = [0; (1u64 << 61) as usize + (1u64 << 31) as usize]; //~ ERROR: post-monomorphization error } diff --git a/tests/fail/unaligned_pointers/atomic_unaligned.rs b/tests/fail/unaligned_pointers/atomic_unaligned.rs index 68b0efdbfeb44..9dd652fd8217a 100644 --- a/tests/fail/unaligned_pointers/atomic_unaligned.rs +++ b/tests/fail/unaligned_pointers/atomic_unaligned.rs @@ -8,6 +8,6 @@ fn main() { let zptr = &z as *const _ as *const u64; unsafe { ::std::intrinsics::atomic_load_seqcst(zptr); - //~^ERROR accessing memory with alignment 4, but alignment 8 is required + //~^ERROR: accessing memory with alignment 4, but alignment 8 is required } } diff --git a/tests/fail/unaligned_pointers/dyn_alignment.rs b/tests/fail/unaligned_pointers/dyn_alignment.rs index fe9c395230290..b943c7db7ccd6 100644 --- a/tests/fail/unaligned_pointers/dyn_alignment.rs +++ b/tests/fail/unaligned_pointers/dyn_alignment.rs @@ -19,6 +19,6 @@ fn main() { (&mut ptr as *mut _ as *mut *const u8).write(&buf as *const _ as *const u8); } // Re-borrow that. This should be UB. - let _ptr = &*ptr; //~ERROR alignment 256 is required + let _ptr = &*ptr; //~ERROR: alignment 256 is required } } diff --git a/tests/fail/unaligned_pointers/intptrcast_alignment_check.rs b/tests/fail/unaligned_pointers/intptrcast_alignment_check.rs index 172461424ec04..da4cadc1c8763 100644 --- a/tests/fail/unaligned_pointers/intptrcast_alignment_check.rs +++ b/tests/fail/unaligned_pointers/intptrcast_alignment_check.rs @@ -12,6 +12,6 @@ fn main() { // Manually make sure the pointer is properly aligned. let base_addr_aligned = if base_addr % 2 == 0 { base_addr } else { base_addr + 1 }; let u16_ptr = base_addr_aligned as *mut u16; - unsafe { *u16_ptr = 2 }; //~ERROR memory with alignment 1, but alignment 2 is required + unsafe { *u16_ptr = 2 }; //~ERROR: memory with alignment 1, but alignment 2 is required println!("{:?}", x); } diff --git a/tests/fail/unaligned_pointers/reference_to_packed.rs b/tests/fail/unaligned_pointers/reference_to_packed.rs index b4659805745aa..752210dca46e8 100644 --- a/tests/fail/unaligned_pointers/reference_to_packed.rs +++ b/tests/fail/unaligned_pointers/reference_to_packed.rs @@ -14,6 +14,6 @@ fn main() { for _ in 0..10 { let foo = Foo { x: 42, y: 99 }; let p = &foo.x; - let i = *p; //~ERROR alignment 4 is required + let i = *p; //~ERROR: alignment 4 is required } } diff --git a/tests/fail/unaligned_pointers/unaligned_ptr1.rs b/tests/fail/unaligned_pointers/unaligned_ptr1.rs index a3b483281139d..73adc4dc44916 100644 --- a/tests/fail/unaligned_pointers/unaligned_ptr1.rs +++ b/tests/fail/unaligned_pointers/unaligned_ptr1.rs @@ -7,6 +7,6 @@ fn main() { let x = [2u16, 3, 4]; // Make it big enough so we don't get an out-of-bounds error. let x = &x[0] as *const _ as *const u32; // This must fail because alignment is violated: the allocation's base is not sufficiently aligned. - let _x = unsafe { *x }; //~ERROR memory with alignment 2, but alignment 4 is required + let _x = unsafe { *x }; //~ERROR: memory with alignment 2, but alignment 4 is required } } diff --git a/tests/fail/unaligned_pointers/unaligned_ptr2.rs b/tests/fail/unaligned_pointers/unaligned_ptr2.rs index 88fcd30278d72..c252944ffb7b7 100644 --- a/tests/fail/unaligned_pointers/unaligned_ptr2.rs +++ b/tests/fail/unaligned_pointers/unaligned_ptr2.rs @@ -8,5 +8,5 @@ fn main() { let x = (x.as_ptr() as *const u8).wrapping_offset(3) as *const u32; // This must fail because alignment is violated: the offset is not sufficiently aligned. // Also make the offset not a power of 2, that used to ICE. - let _x = unsafe { *x }; //~ERROR memory with alignment 1, but alignment 4 is required + let _x = unsafe { *x }; //~ERROR: memory with alignment 1, but alignment 4 is required } diff --git a/tests/fail/unaligned_pointers/unaligned_ptr3.rs b/tests/fail/unaligned_pointers/unaligned_ptr3.rs index 3a4b1497ae6bb..7605dd175a982 100644 --- a/tests/fail/unaligned_pointers/unaligned_ptr3.rs +++ b/tests/fail/unaligned_pointers/unaligned_ptr3.rs @@ -8,6 +8,6 @@ fn main() { let x = &x[0] as *const _ as *const *const u8; // cast to ptr-to-ptr, so that we load a ptr // This must fail because alignment is violated. Test specifically for loading pointers, // which have special code in miri's memory. - let _x = unsafe { *x }; //~ERROR but alignment + let _x = unsafe { *x }; //~ERROR: but alignment } } diff --git a/tests/fail/unaligned_pointers/unaligned_ptr4.rs b/tests/fail/unaligned_pointers/unaligned_ptr4.rs index 659fbf1470ce1..852febe4c04cc 100644 --- a/tests/fail/unaligned_pointers/unaligned_ptr4.rs +++ b/tests/fail/unaligned_pointers/unaligned_ptr4.rs @@ -9,6 +9,6 @@ fn main() { for _ in 0..10 { let x = [0u8; 4]; let ptr = x.as_ptr().wrapping_offset(1).cast::(); - let _val = unsafe { *ptr }; //~ERROR but alignment + let _val = unsafe { *ptr }; //~ERROR: but alignment } } diff --git a/tests/fail/unaligned_pointers/unaligned_ptr_addr_of.rs b/tests/fail/unaligned_pointers/unaligned_ptr_addr_of.rs index 28a58556eb395..e439cf2b03b96 100644 --- a/tests/fail/unaligned_pointers/unaligned_ptr_addr_of.rs +++ b/tests/fail/unaligned_pointers/unaligned_ptr_addr_of.rs @@ -9,6 +9,6 @@ fn main() { let x = &x[0] as *const _ as *const u32; // This must fail because alignment is violated: the allocation's base is not sufficiently aligned. // The deref is UB even if we just put the result into a raw pointer. - let _x = unsafe { ptr::addr_of!(*x) }; //~ ERROR memory with alignment 2, but alignment 4 is required + let _x = unsafe { ptr::addr_of!(*x) }; //~ ERROR: memory with alignment 2, but alignment 4 is required } } diff --git a/tests/fail/unaligned_pointers/unaligned_ptr_zst.rs b/tests/fail/unaligned_pointers/unaligned_ptr_zst.rs index 26c315d34bf50..9076581b55bbc 100644 --- a/tests/fail/unaligned_pointers/unaligned_ptr_zst.rs +++ b/tests/fail/unaligned_pointers/unaligned_ptr_zst.rs @@ -8,6 +8,6 @@ fn main() { let x = i as u8; let x = &x as *const _ as *const [u32; 0]; // This must fail because alignment is violated. Test specifically for loading ZST. - let _x = unsafe { *x }; //~ERROR alignment 4 is required + let _x = unsafe { *x }; //~ERROR: alignment 4 is required } } diff --git a/tests/fail/uninit_byte_read.rs b/tests/fail/uninit_byte_read.rs index e08d34d138561..f1dace0cff9b1 100644 --- a/tests/fail/uninit_byte_read.rs +++ b/tests/fail/uninit_byte_read.rs @@ -1,7 +1,7 @@ //@compile-flags: -Zmiri-disable-stacked-borrows fn main() { let v: Vec = Vec::with_capacity(10); - let undef = unsafe { *v.get_unchecked(5) }; //~ ERROR uninitialized + let undef = unsafe { *v.get_unchecked(5) }; //~ ERROR: uninitialized let x = undef + 1; panic!("this should never print: {}", x); } diff --git a/tests/fail/uninit_raw_ptr.rs b/tests/fail/uninit_raw_ptr.rs index c2ede1bb146ad..e5a34f4a261c4 100644 --- a/tests/fail/uninit_raw_ptr.rs +++ b/tests/fail/uninit_raw_ptr.rs @@ -1,4 +1,4 @@ fn main() { let _val = unsafe { std::mem::MaybeUninit::<*const u8>::uninit().assume_init() }; - //~^ ERROR constructing invalid value at .value: encountered uninitialized raw pointer + //~^ ERROR: constructing invalid value at .value: encountered uninitialized raw pointer } diff --git a/tests/fail/unsized-local.rs b/tests/fail/unsized-local.rs index 8dd07c585c627..ceccae4e3e76f 100644 --- a/tests/fail/unsized-local.rs +++ b/tests/fail/unsized-local.rs @@ -14,7 +14,7 @@ fn main() { } } - let x = *(Box::new(A) as Box); //~ERROR unsized locals are not supported + let x = *(Box::new(A) as Box); //~ERROR: unsized locals are not supported assert_eq!(x.foo(), format!("hello")); // I'm not sure whether we want this to work diff --git a/tests/fail/unsupported_foreign_function.rs b/tests/fail/unsupported_foreign_function.rs index b7f4d9038ec61..dfd099e734b99 100644 --- a/tests/fail/unsupported_foreign_function.rs +++ b/tests/fail/unsupported_foreign_function.rs @@ -4,6 +4,6 @@ fn main() { } unsafe { - foo(); //~ ERROR unsupported operation: can't call foreign function: foo + foo(); //~ ERROR: unsupported operation: can't call foreign function: foo } } diff --git a/tests/fail/unsupported_signal.rs b/tests/fail/unsupported_signal.rs index 9cdf3cfdc664f..4319dc7c69fe7 100644 --- a/tests/fail/unsupported_signal.rs +++ b/tests/fail/unsupported_signal.rs @@ -8,6 +8,6 @@ extern crate libc; fn main() { unsafe { libc::signal(libc::SIGPIPE, libc::SIG_IGN); - //~^ ERROR unsupported operation: can't call foreign function: signal + //~^ ERROR: unsupported operation: can't call foreign function: signal } } diff --git a/tests/fail/validity/cast_fn_ptr1.rs b/tests/fail/validity/cast_fn_ptr1.rs index 1bd889e899941..6ab73569c6347 100644 --- a/tests/fail/validity/cast_fn_ptr1.rs +++ b/tests/fail/validity/cast_fn_ptr1.rs @@ -9,5 +9,5 @@ fn main() { let g: fn(*const i32) = unsafe { std::mem::transmute(f as fn(&i32)) }; g(0usize as *const i32) - //~^ ERROR encountered a null reference + //~^ ERROR: encountered a null reference } diff --git a/tests/fail/validity/cast_fn_ptr2.rs b/tests/fail/validity/cast_fn_ptr2.rs index 7e7ad4710f5c3..64ddb563be538 100644 --- a/tests/fail/validity/cast_fn_ptr2.rs +++ b/tests/fail/validity/cast_fn_ptr2.rs @@ -11,5 +11,5 @@ fn main() { let g: fn() -> &'static i32 = unsafe { std::mem::transmute(f as fn() -> *const i32) }; let _x = g(); - //~^ ERROR encountered a null reference + //~^ ERROR: encountered a null reference } diff --git a/tests/fail/validity/dangling_ref1.rs b/tests/fail/validity/dangling_ref1.rs index cc94cc6ca0edb..6bf2d9295a370 100644 --- a/tests/fail/validity/dangling_ref1.rs +++ b/tests/fail/validity/dangling_ref1.rs @@ -3,5 +3,5 @@ use std::mem; fn main() { - let _x: &i32 = unsafe { mem::transmute(16usize) }; //~ ERROR encountered a dangling reference (address 0x10 is unallocated) + let _x: &i32 = unsafe { mem::transmute(16usize) }; //~ ERROR: encountered a dangling reference (address 0x10 is unallocated) } diff --git a/tests/fail/validity/dangling_ref2.rs b/tests/fail/validity/dangling_ref2.rs index eba026fdda86a..77d2358ae7772 100644 --- a/tests/fail/validity/dangling_ref2.rs +++ b/tests/fail/validity/dangling_ref2.rs @@ -5,5 +5,5 @@ use std::mem; fn main() { let val = 14; let ptr = (&val as *const i32).wrapping_offset(1); - let _x: &i32 = unsafe { mem::transmute(ptr) }; //~ ERROR dangling reference (going beyond the bounds of its allocation) + let _x: &i32 = unsafe { mem::transmute(ptr) }; //~ ERROR: dangling reference (going beyond the bounds of its allocation) } diff --git a/tests/fail/validity/dangling_ref3.rs b/tests/fail/validity/dangling_ref3.rs index 8decc845ecb45..8e8a75bd7ec04 100644 --- a/tests/fail/validity/dangling_ref3.rs +++ b/tests/fail/validity/dangling_ref3.rs @@ -8,5 +8,5 @@ fn dangling() -> *const u8 { } fn main() { - let _x: &i32 = unsafe { mem::transmute(dangling()) }; //~ ERROR dangling reference (use-after-free) + let _x: &i32 = unsafe { mem::transmute(dangling()) }; //~ ERROR: dangling reference (use-after-free) } diff --git a/tests/fail/validity/invalid_bool.rs b/tests/fail/validity/invalid_bool.rs index df6c19df7f231..4f11bb2629f5f 100644 --- a/tests/fail/validity/invalid_bool.rs +++ b/tests/fail/validity/invalid_bool.rs @@ -1,3 +1,3 @@ fn main() { - let _b = unsafe { std::mem::transmute::(2) }; //~ ERROR expected a boolean + let _b = unsafe { std::mem::transmute::(2) }; //~ ERROR: expected a boolean } diff --git a/tests/fail/validity/invalid_bool_uninit.rs b/tests/fail/validity/invalid_bool_uninit.rs index 89b57b2d50d10..f90fae3ab92cf 100644 --- a/tests/fail/validity/invalid_bool_uninit.rs +++ b/tests/fail/validity/invalid_bool_uninit.rs @@ -6,5 +6,5 @@ union MyUninit { } fn main() { - let _b = unsafe { MyUninit { init: () }.uninit }; //~ ERROR encountered uninitialized bytes, but expected a boolean + let _b = unsafe { MyUninit { init: () }.uninit }; //~ ERROR: encountered uninitialized bytes, but expected a boolean } diff --git a/tests/fail/validity/invalid_char.rs b/tests/fail/validity/invalid_char.rs index 80749fd7c7916..568892e591096 100644 --- a/tests/fail/validity/invalid_char.rs +++ b/tests/fail/validity/invalid_char.rs @@ -1,7 +1,7 @@ fn main() { assert!(std::char::from_u32(-1_i32 as u32).is_none()); let _val = match unsafe { std::mem::transmute::(-1) } { - //~^ ERROR encountered 0xffffffff, but expected a valid unicode scalar value + //~^ ERROR: encountered 0xffffffff, but expected a valid unicode scalar value 'a' => true, 'b' => false, _ => true, diff --git a/tests/fail/validity/invalid_char_uninit.rs b/tests/fail/validity/invalid_char_uninit.rs index cb885d001cff0..cb82ce7463766 100644 --- a/tests/fail/validity/invalid_char_uninit.rs +++ b/tests/fail/validity/invalid_char_uninit.rs @@ -6,5 +6,5 @@ union MyUninit { } fn main() { - let _b = unsafe { MyUninit { init: () }.uninit }; //~ ERROR encountered uninitialized bytes, but expected a valid unicode scalar value + let _b = unsafe { MyUninit { init: () }.uninit }; //~ ERROR: encountered uninitialized bytes, but expected a valid unicode scalar value } diff --git a/tests/fail/validity/invalid_enum_tag.rs b/tests/fail/validity/invalid_enum_tag.rs index 4bc60ba51e70c..fa115e1e78e46 100644 --- a/tests/fail/validity/invalid_enum_tag.rs +++ b/tests/fail/validity/invalid_enum_tag.rs @@ -7,5 +7,5 @@ pub enum Foo { } fn main() { - let _f = unsafe { std::mem::transmute::(42) }; //~ ERROR constructing invalid value at .: encountered 0x0000002a, but expected a valid enum tag + let _f = unsafe { std::mem::transmute::(42) }; //~ ERROR: constructing invalid value at .: encountered 0x0000002a, but expected a valid enum tag } diff --git a/tests/fail/validity/invalid_enum_tag_256variants_uninit.rs b/tests/fail/validity/invalid_enum_tag_256variants_uninit.rs index 10e30cf85fe62..708e0cafa90df 100644 --- a/tests/fail/validity/invalid_enum_tag_256variants_uninit.rs +++ b/tests/fail/validity/invalid_enum_tag_256variants_uninit.rs @@ -268,5 +268,5 @@ union MyUninit { } fn main() { - let _a = unsafe { MyUninit { init: () }.uninit }; //~ ERROR constructing invalid value at .: encountered uninitialized bytes, but expected a valid enum tag + let _a = unsafe { MyUninit { init: () }.uninit }; //~ ERROR: constructing invalid value at .: encountered uninitialized bytes, but expected a valid enum tag } diff --git a/tests/fail/validity/invalid_fnptr_null.rs b/tests/fail/validity/invalid_fnptr_null.rs index 0634fba36a330..8d2045ca4a659 100644 --- a/tests/fail/validity/invalid_fnptr_null.rs +++ b/tests/fail/validity/invalid_fnptr_null.rs @@ -1,5 +1,5 @@ #![allow(invalid_value)] fn main() { - let _b: fn() = unsafe { std::mem::transmute(0usize) }; //~ ERROR encountered a null function pointer + let _b: fn() = unsafe { std::mem::transmute(0usize) }; //~ ERROR: encountered a null function pointer } diff --git a/tests/fail/validity/invalid_fnptr_uninit.rs b/tests/fail/validity/invalid_fnptr_uninit.rs index 2d479dd319f3d..26f958bd64fec 100644 --- a/tests/fail/validity/invalid_fnptr_uninit.rs +++ b/tests/fail/validity/invalid_fnptr_uninit.rs @@ -6,5 +6,5 @@ union MyUninit { } fn main() { - let _b = unsafe { MyUninit { init: () }.uninit }; //~ ERROR encountered uninitialized bytes + let _b = unsafe { MyUninit { init: () }.uninit }; //~ ERROR: encountered uninitialized bytes } diff --git a/tests/fail/validity/nonzero.rs b/tests/fail/validity/nonzero.rs index 6344bb61ae25e..384c94a556998 100644 --- a/tests/fail/validity/nonzero.rs +++ b/tests/fail/validity/nonzero.rs @@ -9,5 +9,5 @@ pub(crate) struct NonZero(pub(crate) T); fn main() { // Make sure that we detect this even when no function call is happening along the way - let _x = Some(unsafe { NonZero(0) }); //~ ERROR encountered 0, but expected something greater or equal to 1 + let _x = Some(unsafe { NonZero(0) }); //~ ERROR: encountered 0, but expected something greater or equal to 1 } diff --git a/tests/fail/validity/ptr_integer_array_transmute.rs b/tests/fail/validity/ptr_integer_array_transmute.rs index 92c635ff22181..c8613d274c81d 100644 --- a/tests/fail/validity/ptr_integer_array_transmute.rs +++ b/tests/fail/validity/ptr_integer_array_transmute.rs @@ -1,4 +1,4 @@ fn main() { let r = &mut 42; - let _i: [usize; 1] = unsafe { std::mem::transmute(r) }; //~ ERROR encountered a pointer, but expected plain (non-pointer) bytes + let _i: [usize; 1] = unsafe { std::mem::transmute(r) }; //~ ERROR: encountered a pointer, but expected plain (non-pointer) bytes } diff --git a/tests/fail/validity/ref_to_uninhabited1.rs b/tests/fail/validity/ref_to_uninhabited1.rs index a46ce017c5a0f..2e6be8b971c64 100644 --- a/tests/fail/validity/ref_to_uninhabited1.rs +++ b/tests/fail/validity/ref_to_uninhabited1.rs @@ -3,7 +3,7 @@ use std::mem::{forget, transmute}; fn main() { unsafe { - let x: Box = transmute(&mut 42); //~ERROR encountered a box pointing to uninhabited type ! + let x: Box = transmute(&mut 42); //~ERROR: encountered a box pointing to uninhabited type ! forget(x); } } diff --git a/tests/fail/validity/ref_to_uninhabited2.rs b/tests/fail/validity/ref_to_uninhabited2.rs index 0a791d1e7fee8..8934a06b5d73a 100644 --- a/tests/fail/validity/ref_to_uninhabited2.rs +++ b/tests/fail/validity/ref_to_uninhabited2.rs @@ -4,6 +4,6 @@ enum Void {} fn main() { unsafe { - let _x: &(i32, Void) = transmute(&42); //~ERROR encountered a reference pointing to uninhabited type (i32, Void) + let _x: &(i32, Void) = transmute(&42); //~ERROR: encountered a reference pointing to uninhabited type (i32, Void) } } diff --git a/tests/fail/validity/transmute_through_ptr.rs b/tests/fail/validity/transmute_through_ptr.rs index 9db2ba9953044..60b3bdd6cd69a 100644 --- a/tests/fail/validity/transmute_through_ptr.rs +++ b/tests/fail/validity/transmute_through_ptr.rs @@ -14,6 +14,6 @@ fn main() { let mut x = Bool::True; evil(&mut x); let y = x; // reading this ought to be enough to trigger validation - //~^ ERROR constructing invalid value at .: encountered 0x0000002c, but expected a valid enum tag + //~^ ERROR: constructing invalid value at .: encountered 0x0000002c, but expected a valid enum tag println!("{:?}", y); // make sure it is used (and not optimized away) } diff --git a/tests/fail/validity/uninit_float.rs b/tests/fail/validity/uninit_float.rs index 43748570d9a49..3e7c14786e351 100644 --- a/tests/fail/validity/uninit_float.rs +++ b/tests/fail/validity/uninit_float.rs @@ -2,5 +2,5 @@ fn main() { let _val = unsafe { std::mem::MaybeUninit::::uninit().assume_init() }; - //~^ ERROR constructing invalid value at .value: encountered uninitialized bytes, but expected initialized bytes + //~^ ERROR: constructing invalid value at .value: encountered uninitialized bytes, but expected initialized bytes } diff --git a/tests/fail/validity/uninit_integer.rs b/tests/fail/validity/uninit_integer.rs index b5a367ba8cb70..0a1253b5b96b0 100644 --- a/tests/fail/validity/uninit_integer.rs +++ b/tests/fail/validity/uninit_integer.rs @@ -2,5 +2,5 @@ fn main() { let _val = unsafe { std::mem::MaybeUninit::::uninit().assume_init() }; - //~^ ERROR constructing invalid value at .value: encountered uninitialized bytes, but expected initialized bytes + //~^ ERROR: constructing invalid value at .value: encountered uninitialized bytes, but expected initialized bytes } diff --git a/tests/fail/validity/uninit_integer_signed.rs b/tests/fail/validity/uninit_integer_signed.rs index 609bad7e4fb68..fa484413784c5 100644 --- a/tests/fail/validity/uninit_integer_signed.rs +++ b/tests/fail/validity/uninit_integer_signed.rs @@ -2,5 +2,5 @@ fn main() { let _val = unsafe { std::mem::MaybeUninit::::uninit().assume_init() }; - //~^ ERROR constructing invalid value at .value: encountered uninitialized bytes, but expected initialized bytes + //~^ ERROR: constructing invalid value at .value: encountered uninitialized bytes, but expected initialized bytes } diff --git a/tests/fail/zst1.rs b/tests/fail/zst1.rs index d400fba5d0c24..cc81481e4fa4c 100644 --- a/tests/fail/zst1.rs +++ b/tests/fail/zst1.rs @@ -1,5 +1,5 @@ fn main() { // make sure ZST locals cannot be accessed let x = &() as *const () as *const i8; - let _val = unsafe { *x }; //~ ERROR out-of-bounds + let _val = unsafe { *x }; //~ ERROR: out-of-bounds } diff --git a/tests/fail/zst2.rs b/tests/fail/zst2.rs index 55c78fe8f944e..82470866f179f 100644 --- a/tests/fail/zst2.rs +++ b/tests/fail/zst2.rs @@ -11,5 +11,5 @@ fn main() { let mut x_box = Box::new(1u8); let x = &mut *x_box as *mut _ as *mut [u8; 0]; drop(x_box); - unsafe { *x = zst_val }; //~ ERROR dereferenced after this allocation got freed + unsafe { *x = zst_val }; //~ ERROR: dereferenced after this allocation got freed } diff --git a/tests/fail/zst3.rs b/tests/fail/zst3.rs index 47a7c0d3c2a4b..a511f38998feb 100644 --- a/tests/fail/zst3.rs +++ b/tests/fail/zst3.rs @@ -14,5 +14,5 @@ fn main() { unsafe { *(x as *mut [u8; 0]) = zst_val }; // One byte further is OOB. let x = x.wrapping_offset(1); - unsafe { *(x as *mut [u8; 0]) = zst_val }; //~ ERROR out-of-bounds + unsafe { *(x as *mut [u8; 0]) = zst_val }; //~ ERROR: out-of-bounds } diff --git a/ui_test/src/lib.rs b/ui_test/src/lib.rs index bebda768babee..b2e71b762beae 100644 --- a/ui_test/src/lib.rs +++ b/ui_test/src/lib.rs @@ -215,12 +215,6 @@ pub fn run_tests(config: Config) -> Result<()> { eprintln!(" {level:?}: {message}") } } - Error::ErrorPatternWithoutErrorAnnotation(path, line) => { - eprintln!( - "Annotation at {}:{line} matched an error diagnostic but did not have `ERROR` before its message", - path.display() - ); - } } eprintln!(); } @@ -280,7 +274,6 @@ enum Error { msgs: Vec, path: Option<(PathBuf, usize)>, }, - ErrorPatternWithoutErrorAnnotation(PathBuf, usize), } type Errors = Vec; @@ -414,27 +407,17 @@ fn check_annotations( continue; } } - if let Some(level) = level { - // If we found a diagnostic with a level annotation, make sure that all - // diagnostics of that level have annotations, even if we don't end up finding a matching diagnostic - // for this pattern. - lowest_annotation_level = std::cmp::min(lowest_annotation_level, level); - } + + // If we found a diagnostic with a level annotation, make sure that all + // diagnostics of that level have annotations, even if we don't end up finding a matching diagnostic + // for this pattern. + lowest_annotation_level = std::cmp::min(lowest_annotation_level, level); if let Some(msgs) = messages.get_mut(line) { - let found = msgs.iter().position(|msg| { - msg.message.contains(matched) - // in case there is no level on the annotation, match any level. - && level.map_or(true, |level| { - msg.level == level - }) - }); + let found = + msgs.iter().position(|msg| msg.message.contains(matched) && msg.level == level); if let Some(found) = found { - let msg = msgs.remove(found); - if msg.level == Level::Error && level.is_none() { - errors - .push(Error::ErrorPatternWithoutErrorAnnotation(path.to_path_buf(), line)); - } + msgs.remove(found); continue; } } @@ -443,7 +426,12 @@ fn check_annotations( } let filter = |msgs: Vec| -> Vec<_> { - msgs.into_iter().filter(|msg| msg.level >= lowest_annotation_level).collect() + msgs.into_iter() + .filter(|msg| { + msg.level + >= comments.require_annotations_for_level.unwrap_or(lowest_annotation_level) + }) + .collect() }; let messages_from_unknown_file_or_line = filter(messages_from_unknown_file_or_line); diff --git a/ui_test/src/parser.rs b/ui_test/src/parser.rs index 72ccc0136201c..5b666eef66efb 100644 --- a/ui_test/src/parser.rs +++ b/ui_test/src/parser.rs @@ -31,6 +31,9 @@ pub(crate) struct Comments { /// An arbitrary pattern to look for in the stderr. pub error_pattern: Option<(String, usize)>, pub error_matches: Vec, + /// Ignore diagnostics below this level. + /// `None` means pick the lowest level from the `error_pattern`s. + pub require_annotations_for_level: Option, } /// The conditions used for "ignore" and "only" filters. @@ -46,7 +49,7 @@ pub(crate) enum Condition { pub(crate) struct ErrorMatch { pub matched: String, pub revision: Option, - pub level: Option, + pub level: Level, /// The line where the message was defined, for reporting issues with it (e.g. in case it wasn't found). pub definition_line: usize, /// The line this pattern is expecting to find a message in. @@ -188,6 +191,13 @@ impl Comments { ensure!(!self.stderr_per_bitwidth, "cannot specifiy stderr-per-bitwidth twice"); self.stderr_per_bitwidth = true; } + "require-annotations-for-level" => { + ensure!( + self.require_annotations_for_level.is_none(), + "cannot specify `require-annotations-for-level` twice" + ); + self.require_annotations_for_level = Some(args.trim().parse()?); + } command => { if let Some(s) = command.strip_prefix("ignore-") { // args are ignored (can be sue as comment) @@ -231,7 +241,7 @@ impl Comments { } } - // parse something like (?P\||[\^]+)? *(?PERROR|HELP|WARN|NOTE)?:?(?P.*) + // parse something like (?P\||[\^]+)? *(?PERROR|HELP|WARN|NOTE): (?P.*) fn parse_pattern_inner( &mut self, pattern: &str, @@ -255,14 +265,15 @@ impl Comments { _ => (l, pattern), }; - let (level, pattern) = match pattern.trim_start().split_once(|c| matches!(c, ':' | ' ')) { - None => (None, pattern), - Some((level, pattern_without_level)) => - match level.parse().ok() { - Some(level) => (Some(level), pattern_without_level), - None => (None, pattern), - }, - }; + let pattern = pattern.trim_start(); + let offset = pattern + .chars() + .position(|c| !matches!(c, 'A'..='Z' | 'a'..='z')) + .ok_or_else(|| eyre!("pattern without level"))?; + + let level = pattern[..offset].parse()?; + let pattern = &pattern[offset..]; + let pattern = pattern.strip_prefix(':').ok_or_else(|| eyre!("no `:` after level found"))?; let matched = pattern.trim().to_string(); diff --git a/ui_test/src/parser/tests.rs b/ui_test/src/parser/tests.rs index 096cc8eab9657..31a9ec2639eb0 100644 --- a/ui_test/src/parser/tests.rs +++ b/ui_test/src/parser/tests.rs @@ -2,20 +2,16 @@ use std::path::Path; use super::Comments; -use crate::tests::init; -use color_eyre::eyre::{bail, Result}; - #[test] -fn parse_simple_comment() -> Result<()> { - init(); +fn parse_simple_comment() { let s = r" use std::mem; fn main() { - let _x: &i32 = unsafe { mem::transmute(16usize) }; //~ ERROR encountered a dangling reference (address $HEX is unallocated) + let _x: &i32 = unsafe { mem::transmute(16usize) }; //~ ERROR: encountered a dangling reference (address $HEX is unallocated) } "; - let comments = Comments::parse(Path::new(""), s)?; + let comments = Comments::parse(Path::new(""), s).unwrap(); println!("parsed comments: {:#?}", comments); assert_eq!(comments.error_matches[0].definition_line, 5); assert_eq!(comments.error_matches[0].revision, None); @@ -23,47 +19,57 @@ fn main() { comments.error_matches[0].matched, "encountered a dangling reference (address $HEX is unallocated)" ); - Ok(()) } #[test] -fn parse_slash_slash_at() -> Result<()> { - init(); +fn parse_missing_level() { + let s = r" +use std::mem; + +fn main() { + let _x: &i32 = unsafe { mem::transmute(16usize) }; //~ encountered a dangling reference (address $HEX is unallocated) +} + "; + match Comments::parse(Path::new(""), s) { + Ok(_) => panic!("expected parsing to fail"), + Err(_) => {} + } +} + +#[test] +fn parse_slash_slash_at() { let s = r" //@ error-pattern: foomp use std::mem; "; - let comments = Comments::parse(Path::new(""), s)?; + let comments = Comments::parse(Path::new(""), s).unwrap(); println!("parsed comments: {:#?}", comments); assert_eq!(comments.error_pattern, Some(("foomp".to_string(), 2))); - Ok(()) } #[test] -fn parse_slash_slash_at_fail() -> Result<()> { - init(); +fn parse_slash_slash_at_fail() { let s = r" //@ error-patttern foomp use std::mem; "; match Comments::parse(Path::new(""), s) { - Ok(_) => bail!("expected parsing to fail"), - Err(_) => Ok(()), + Ok(_) => panic!("expected parsing to fail"), + Err(_) => {} } } #[test] -fn missing_colon_fail() -> Result<()> { - init(); +fn missing_colon_fail() { let s = r" //@stderr-per-bitwidth hello use std::mem; "; match Comments::parse(Path::new(""), s) { - Ok(_) => bail!("expected parsing to fail"), - Err(_) => Ok(()), + Ok(_) => panic!("expected parsing to fail"), + Err(_) => {} } } diff --git a/ui_test/src/rustc_stderr.rs b/ui_test/src/rustc_stderr.rs index fc772c84040bf..a216731c7556c 100644 --- a/ui_test/src/rustc_stderr.rs +++ b/ui_test/src/rustc_stderr.rs @@ -3,6 +3,7 @@ use std::{ path::{Path, PathBuf}, }; +use color_eyre::eyre::{eyre, Error}; use regex::Regex; #[derive(serde::Deserialize, Debug)] @@ -45,7 +46,7 @@ struct Span { } impl std::str::FromStr for Level { - type Err = String; + type Err = Error; fn from_str(s: &str) -> Result { match s { "ERROR" | "error" => Ok(Self::Error), @@ -54,7 +55,7 @@ impl std::str::FromStr for Level { "NOTE" | "note" => Ok(Self::Note), "failure-note" => Ok(Self::FailureNote), "error: internal compiler error" => Ok(Self::Ice), - _ => Err(format!("unknown level `{s}`")), + _ => Err(eyre!("unknown level `{s}`")), } } } diff --git a/ui_test/src/tests.rs b/ui_test/src/tests.rs index 11a3d6aca2784..96c0f362b675d 100644 --- a/ui_test/src/tests.rs +++ b/ui_test/src/tests.rs @@ -20,17 +20,16 @@ fn config() -> Config { } #[test] -fn issue_2156() -> Result<()> { - init(); +fn issue_2156() { let s = r" use std::mem; fn main() { - let _x: &i32 = unsafe { mem::transmute(16usize) }; //~ ERROR encountered a dangling reference (address $HEX is unallocated) + let _x: &i32 = unsafe { mem::transmute(16usize) }; //~ ERROR: encountered a dangling reference (address $HEX is unallocated) } "; let path = Path::new("$DIR/"); - let comments = Comments::parse(path, s)?; + let comments = Comments::parse(path, s).unwrap(); let mut errors = vec![]; let config = config(); let messages = vec![ @@ -47,22 +46,21 @@ fn main() { [ Error::PatternNotFound { definition_line: 5, .. }, Error::ErrorsWithoutPattern { path: Some((_, 5)), .. }, - ] => Ok(()), + ] => {} _ => panic!("{:#?}", errors), } } #[test] -fn find_pattern() -> Result<()> { - init(); +fn find_pattern() { let s = r" use std::mem; fn main() { - let _x: &i32 = unsafe { mem::transmute(16usize) }; //~ ERROR encountered a dangling reference (address 0x10 is unallocated) + let _x: &i32 = unsafe { mem::transmute(16usize) }; //~ ERROR: encountered a dangling reference (address 0x10 is unallocated) } "; - let comments = Comments::parse(Path::new(""), s)?; + let comments = Comments::parse(Path::new(""), s).unwrap(); let config = config(); { let messages = vec![vec![], vec![], vec![], vec![], vec![], vec![ @@ -139,24 +137,23 @@ fn main() { ); match &errors[..] { // Note no `ErrorsWithoutPattern`, because there are no `//~NOTE` in the test file, so we ignore them - [Error::PatternNotFound { definition_line: 5, .. }] => Ok(()), + [Error::PatternNotFound { definition_line: 5, .. }] => {} _ => panic!("not the expected error: {:#?}", errors), } } } #[test] -fn duplicate_pattern() -> Result<()> { - init(); +fn duplicate_pattern() { let s = r" use std::mem; fn main() { - let _x: &i32 = unsafe { mem::transmute(16usize) }; //~ ERROR encountered a dangling reference (address 0x10 is unallocated) - //~^ ERROR encountered a dangling reference (address 0x10 is unallocated) + let _x: &i32 = unsafe { mem::transmute(16usize) }; //~ ERROR: encountered a dangling reference (address 0x10 is unallocated) + //~^ ERROR: encountered a dangling reference (address 0x10 is unallocated) } "; - let comments = Comments::parse(Path::new(""), s)?; + let comments = Comments::parse(Path::new(""), s).unwrap(); let config = config(); let messages = vec![ vec![], vec![], vec![], vec![], vec![], @@ -170,22 +167,21 @@ fn main() { let mut errors = vec![]; check_annotations(messages, vec![], Path::new("moobar"), &mut errors, &config, "", &comments); match &errors[..] { - [Error::PatternNotFound { definition_line: 6, .. }] => Ok(()), + [Error::PatternNotFound { definition_line: 6, .. }] => {} _ => panic!("{:#?}", errors), } } #[test] -fn missing_pattern() -> Result<()> { - init(); +fn missing_pattern() { let s = r" use std::mem; fn main() { - let _x: &i32 = unsafe { mem::transmute(16usize) }; //~ ERROR encountered a dangling reference (address 0x10 is unallocated) + let _x: &i32 = unsafe { mem::transmute(16usize) }; //~ ERROR: encountered a dangling reference (address 0x10 is unallocated) } "; - let comments = Comments::parse(Path::new(""), s)?; + let comments = Comments::parse(Path::new(""), s).unwrap(); let config = config(); let messages = vec![ vec![], vec![], vec![], vec![], vec![], @@ -203,23 +199,22 @@ fn main() { let mut errors = vec![]; check_annotations(messages, vec![], Path::new("moobar"), &mut errors, &config, "", &comments); match &errors[..] { - [Error::ErrorsWithoutPattern { path: Some((_, 5)), .. }] => Ok(()), + [Error::ErrorsWithoutPattern { path: Some((_, 5)), .. }] => {} _ => panic!("{:#?}", errors), } } #[test] -fn missing_warn_pattern() -> Result<()> { - init(); +fn missing_warn_pattern() { let s = r" use std::mem; fn main() { - let _x: &i32 = unsafe { mem::transmute(16usize) }; //~ ERROR encountered a dangling reference (address 0x10 is unallocated) - //~^ WARN cake + let _x: &i32 = unsafe { mem::transmute(16usize) }; //~ ERROR: encountered a dangling reference (address 0x10 is unallocated) + //~^ WARN: cake } "; - let comments = Comments::parse(Path::new(""), s)?; + let comments = Comments::parse(Path::new(""), s).unwrap(); let config = config(); let messages= vec![ vec![], @@ -247,7 +242,7 @@ fn main() { match &errors[..] { [Error::ErrorsWithoutPattern { path: Some((_, 5)), msgs, .. }] => match &msgs[..] { - [Message { message, level: Level::Warn }] if message == "kaboom" => Ok(()), + [Message { message, level: Level::Warn }] if message == "kaboom" => {} _ => panic!("{:#?}", msgs), }, _ => panic!("{:#?}", errors), @@ -255,17 +250,16 @@ fn main() { } #[test] -fn missing_implicit_warn_pattern() -> Result<()> { - init(); +fn missing_implicit_warn_pattern() { let s = r" use std::mem; - +//@require-annotations-for-level: ERROR fn main() { - let _x: &i32 = unsafe { mem::transmute(16usize) }; //~ ERROR encountered a dangling reference (address 0x10 is unallocated) - //~^ cake + let _x: &i32 = unsafe { mem::transmute(16usize) }; //~ ERROR: encountered a dangling reference (address 0x10 is unallocated) + //~^ WARN: cake } "; - let comments = Comments::parse(Path::new(""), s)?; + let comments = Comments::parse(Path::new(""), s).unwrap(); let config = config(); let messages = vec![ vec![], @@ -291,46 +285,7 @@ fn main() { let mut errors = vec![]; check_annotations(messages, vec![], Path::new("moobar"), &mut errors, &config, "", &comments); match &errors[..] { - [] => Ok(()), + [] => {} _ => panic!("{:#?}", errors), } } - -#[test] -fn implicit_err_pattern() -> Result<()> { - init(); - let s = r" -use std::mem; - -fn main() { - let _x: &i32 = unsafe { mem::transmute(16usize) }; //~ encountered a dangling reference (address 0x10 is unallocated) -} - "; - let comments = Comments::parse(Path::new(""), s)?; - let config = config(); - let messages = vec![ - vec![], - vec![], - vec![], - vec![], - vec![], - vec![ - Message { - message: "Undefined Behavior: type validation failed: encountered a dangling reference (address 0x10 is unallocated)".to_string(), - level: Level::Error, - }, - ], - ]; - let mut errors = vec![]; - check_annotations(messages, vec![], Path::new("moobar"), &mut errors, &config, "", &comments); - match &errors[..] { - [Error::ErrorPatternWithoutErrorAnnotation(_, 5)] => Ok(()), - _ => panic!("{:#?}", errors), - } -} - -/// Call this from every test to initialize eyre only once across all tests. -pub fn init() { - static INIT: std::sync::Once = std::sync::Once::new(); - INIT.call_once(|| color_eyre::install().unwrap()); -} From a64f9e7250021aed25a3f87a8aacc44cb3529d6b Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Mon, 11 Jul 2022 11:50:33 +0000 Subject: [PATCH 3459/3747] Remove error annotations stderr they still showed up in multiline messages --- tests/compiletest.rs | 2 ++ .../function_calls/exported_symbol_bad_unwind2.both.stderr | 4 ++-- .../exported_symbol_bad_unwind2.definition.stderr | 4 ++-- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/tests/compiletest.rs b/tests/compiletest.rs index 008fc7806457f..4270c60c4c3c1 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -106,6 +106,8 @@ regexes! { "[^ `]*/(rust[^/]*|checkout)/library/" => "RUSTLIB/", // erase platform file paths "sys/[a-z]+/" => "sys/PLATFORM/", + // erase error annotations + "//(\\[[a-z,]+\\])?~.*" => "", } fn ui(mode: Mode, path: &str) -> Result<()> { diff --git a/tests/fail/function_calls/exported_symbol_bad_unwind2.both.stderr b/tests/fail/function_calls/exported_symbol_bad_unwind2.both.stderr index 74f1d2b113100..9bc70225c56b5 100644 --- a/tests/fail/function_calls/exported_symbol_bad_unwind2.both.stderr +++ b/tests/fail/function_calls/exported_symbol_bad_unwind2.both.stderr @@ -4,8 +4,8 @@ error: abnormal termination: the program aborted execution --> $DIR/exported_symbol_bad_unwind2.rs:LL:CC | LL | / extern "C-unwind" fn nounwind() { -LL | | //[definition]~^ ERROR: abnormal termination: the program aborted execution -LL | | //[both]~^^ ERROR: abnormal termination: the program aborted execution +LL | | +LL | | LL | | panic!(); LL | | } | |_^ the program aborted execution diff --git a/tests/fail/function_calls/exported_symbol_bad_unwind2.definition.stderr b/tests/fail/function_calls/exported_symbol_bad_unwind2.definition.stderr index 74f1d2b113100..9bc70225c56b5 100644 --- a/tests/fail/function_calls/exported_symbol_bad_unwind2.definition.stderr +++ b/tests/fail/function_calls/exported_symbol_bad_unwind2.definition.stderr @@ -4,8 +4,8 @@ error: abnormal termination: the program aborted execution --> $DIR/exported_symbol_bad_unwind2.rs:LL:CC | LL | / extern "C-unwind" fn nounwind() { -LL | | //[definition]~^ ERROR: abnormal termination: the program aborted execution -LL | | //[both]~^^ ERROR: abnormal termination: the program aborted execution +LL | | +LL | | LL | | panic!(); LL | | } | |_^ the program aborted execution From 01253437ea41dc72eb04c0e443e0bda2584224c5 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Mon, 11 Jul 2022 12:21:02 +0000 Subject: [PATCH 3460/3747] Pacify clippy --- ui_test/src/parser/tests.rs | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/ui_test/src/parser/tests.rs b/ui_test/src/parser/tests.rs index 31a9ec2639eb0..f41c2f234ab86 100644 --- a/ui_test/src/parser/tests.rs +++ b/ui_test/src/parser/tests.rs @@ -30,10 +30,7 @@ fn main() { let _x: &i32 = unsafe { mem::transmute(16usize) }; //~ encountered a dangling reference (address $HEX is unallocated) } "; - match Comments::parse(Path::new(""), s) { - Ok(_) => panic!("expected parsing to fail"), - Err(_) => {} - } + assert!(Comments::parse(Path::new(""), s).is_err(), "expected parsing to fail"); } #[test] @@ -55,10 +52,7 @@ fn parse_slash_slash_at_fail() { use std::mem; "; - match Comments::parse(Path::new(""), s) { - Ok(_) => panic!("expected parsing to fail"), - Err(_) => {} - } + assert!(Comments::parse(Path::new(""), s).is_err(), "expected parsing to fail"); } #[test] @@ -68,8 +62,5 @@ fn missing_colon_fail() { use std::mem; "; - match Comments::parse(Path::new(""), s) { - Ok(_) => panic!("expected parsing to fail"), - Err(_) => {} - } + assert!(Comments::parse(Path::new(""), s).is_err(), "expected parsing to fail"); } From 1ca8d60734cc75b56b3001fe04657723a6974a0d Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Mon, 11 Jul 2022 17:19:10 +0000 Subject: [PATCH 3461/3747] Fix annotation filtering with revisions --- tests/compiletest.rs | 2 -- .../function_calls/exported_symbol_bad_unwind2.both.stderr | 4 ++-- .../exported_symbol_bad_unwind2.definition.stderr | 4 ++-- ui_test/src/rustc_stderr.rs | 2 +- 4 files changed, 5 insertions(+), 7 deletions(-) diff --git a/tests/compiletest.rs b/tests/compiletest.rs index 4270c60c4c3c1..008fc7806457f 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -106,8 +106,6 @@ regexes! { "[^ `]*/(rust[^/]*|checkout)/library/" => "RUSTLIB/", // erase platform file paths "sys/[a-z]+/" => "sys/PLATFORM/", - // erase error annotations - "//(\\[[a-z,]+\\])?~.*" => "", } fn ui(mode: Mode, path: &str) -> Result<()> { diff --git a/tests/fail/function_calls/exported_symbol_bad_unwind2.both.stderr b/tests/fail/function_calls/exported_symbol_bad_unwind2.both.stderr index 9bc70225c56b5..7d9302e3e3adc 100644 --- a/tests/fail/function_calls/exported_symbol_bad_unwind2.both.stderr +++ b/tests/fail/function_calls/exported_symbol_bad_unwind2.both.stderr @@ -4,8 +4,8 @@ error: abnormal termination: the program aborted execution --> $DIR/exported_symbol_bad_unwind2.rs:LL:CC | LL | / extern "C-unwind" fn nounwind() { -LL | | -LL | | +LL | | +LL | | LL | | panic!(); LL | | } | |_^ the program aborted execution diff --git a/tests/fail/function_calls/exported_symbol_bad_unwind2.definition.stderr b/tests/fail/function_calls/exported_symbol_bad_unwind2.definition.stderr index 9bc70225c56b5..7d9302e3e3adc 100644 --- a/tests/fail/function_calls/exported_symbol_bad_unwind2.definition.stderr +++ b/tests/fail/function_calls/exported_symbol_bad_unwind2.definition.stderr @@ -4,8 +4,8 @@ error: abnormal termination: the program aborted execution --> $DIR/exported_symbol_bad_unwind2.rs:LL:CC | LL | / extern "C-unwind" fn nounwind() { -LL | | -LL | | +LL | | +LL | | LL | | panic!(); LL | | } | |_^ the program aborted execution diff --git a/ui_test/src/rustc_stderr.rs b/ui_test/src/rustc_stderr.rs index a216731c7556c..8e031947581b3 100644 --- a/ui_test/src/rustc_stderr.rs +++ b/ui_test/src/rustc_stderr.rs @@ -117,7 +117,7 @@ impl Span { } pub(crate) fn filter_annotations_from_rendered(rendered: &str) -> std::borrow::Cow<'_, str> { - let annotations = Regex::new(r" *//(\[[^\]]\])?~.*").unwrap(); + let annotations = Regex::new(r" *//(\[[a-z,]+\])?~.*").unwrap(); annotations.replace_all(rendered, "") } From bfc23e2cdd4d096eecd1d1160a4029aa88667274 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Mon, 11 Jul 2022 17:25:56 +0000 Subject: [PATCH 3462/3747] Document require-annotations-for-level --- ui_test/README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ui_test/README.md b/ui_test/README.md index fef2c6d44ba6a..24c5940382d13 100644 --- a/ui_test/README.md +++ b/ui_test/README.md @@ -38,6 +38,8 @@ their command specifies, or the test will fail without even being run. * you can specify this multiple times, accumulating all the env vars * `//@normalize-stderr-test: "REGEX" -> "REPLACEMENT"` replaces all matches of `REGEX` in the stderr with `REPLACEMENT`. The replacement may specify `$1` and similar backreferences to paste captures. * you can specify multiple such commands, there is no need to create a single regex that handles multiple replacements that you want to perform. +* `//@require-annotations-for-level: LEVEL` can be used to change the level of diagnostics that require a corresponding annotation. + * this is only useful if there are any annotations like `HELP`, `WARN` or `NOTE`, as these would automatically require annotations for all other diagnostics of the same or higher level. ## Significant differences to compiletest-rs From c6061116e99dfa15fc2f787cba589ba87cb2c6c4 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 11 Jul 2022 21:27:05 -0400 Subject: [PATCH 3463/3747] set up triagebot --- triagebot.toml | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 triagebot.toml diff --git a/triagebot.toml b/triagebot.toml new file mode 100644 index 0000000000000..264f0da7d33d3 --- /dev/null +++ b/triagebot.toml @@ -0,0 +1,2 @@ +# Gives us the commands 'ready', 'author', 'blocked' +[shortcut] From 49a6c230cb6ebfbafa282d59d119500c4064215e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 9 Jul 2022 10:13:19 -0400 Subject: [PATCH 3464/3747] remove deprecated options --- README.md | 11 - src/bin/miri.rs | 14 - src/eval.rs | 6 - src/intptrcast.rs | 12 +- src/machine.rs | 17 +- .../invalid_enum_tag_256variants_uninit.rs | 272 ------------------ ...invalid_enum_tag_256variants_uninit.stderr | 16 -- tests/pass/move-uninit-primval.rs | 7 +- tests/pass/move-uninit-primval.stderr | 1 - tests/pass/uninit_number_ignored.rs | 8 - tests/pass/uninit_number_ignored.stderr | 1 - 11 files changed, 11 insertions(+), 354 deletions(-) delete mode 100644 tests/fail/validity/invalid_enum_tag_256variants_uninit.rs delete mode 100644 tests/fail/validity/invalid_enum_tag_256variants_uninit.stderr delete mode 100644 tests/pass/move-uninit-primval.stderr delete mode 100644 tests/pass/uninit_number_ignored.rs delete mode 100644 tests/pass/uninit_number_ignored.stderr diff --git a/README.md b/README.md index 7679537e7f88b..d1dde153c4787 100644 --- a/README.md +++ b/README.md @@ -329,17 +329,6 @@ The remaining flags are for advanced use only, and more likely to change or be r Some of these are **unsound**, which means they can lead to Miri failing to detect cases of undefined behavior in a program. -* `-Zmiri-allow-uninit-numbers` disables the check to ensure that number types (integer and float - types) always hold initialized data. (They must still be initialized when any actual operation, - such as arithmetic, is performed.) Using this flag is **unsound** and - [deprecated](https://github.com/rust-lang/miri/issues/2187). This has no effect when - `-Zmiri-disable-validation` is present. -* `-Zmiri-allow-ptr-int-transmute` makes Miri more accepting of transmutation between pointers and - integers via `mem::transmute` or union/pointer type punning. This has two effects: it disables the - check against integers storing a pointer (i.e., data with provenance), thus allowing - pointer-to-integer transmutation, and it treats integer-to-pointer transmutation as equivalent to - a cast. Implies `-Zmiri-permissive-provenance`. Using this flag is **unsound** and - [deprecated](https://github.com/rust-lang/miri/issues/2188). * `-Zmiri-disable-abi-check` disables checking [function ABI]. Using this flag is **unsound**. * `-Zmiri-disable-alignment-check` disables checking pointer alignment, so you diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 4f00e4be18ab4..0f464da175d03 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -328,19 +328,6 @@ fn main() { "WARNING: the flag `-Zmiri-check-number-validity` no longer has any effect \ since it is now enabled by default" ); - } else if arg == "-Zmiri-allow-uninit-numbers" { - eprintln!( - "WARNING: `-Zmiri-allow-uninit-numbers` is deprecated and planned to be removed. \ - Please let us know at if you rely on this flag." - ); - miri_config.allow_uninit_numbers = true; - } else if arg == "-Zmiri-allow-ptr-int-transmute" { - eprintln!( - "WARNING: `-Zmiri-allow-ptr-int-transmute` is deprecated and planned to be removed. \ - Please let us know at if you rely on this flag." - ); - miri_config.allow_ptr_int_transmute = true; - miri_config.provenance_mode = ProvenanceMode::Permissive; } else if arg == "-Zmiri-disable-abi-check" { miri_config.check_abi = false; } else if arg == "-Zmiri-disable-isolation" { @@ -378,7 +365,6 @@ fn main() { eprintln!("WARNING: `-Zmiri-tag-raw-pointers` has no effect; it is enabled by default"); } else if arg == "-Zmiri-strict-provenance" { miri_config.provenance_mode = ProvenanceMode::Strict; - miri_config.allow_ptr_int_transmute = false; } else if arg == "-Zmiri-permissive-provenance" { miri_config.provenance_mode = ProvenanceMode::Permissive; } else if arg == "-Zmiri-mute-stdout-stderr" { diff --git a/src/eval.rs b/src/eval.rs index d75b4f5fa6d2a..0ab85ef264d9d 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -77,10 +77,6 @@ pub struct MiriConfig { pub stacked_borrows: bool, /// Controls alignment checking. pub check_alignment: AlignmentCheck, - /// Controls integer and float validity initialization checking. - pub allow_uninit_numbers: bool, - /// Controls how we treat ptr2int and int2ptr transmutes. - pub allow_ptr_int_transmute: bool, /// Controls function [ABI](Abi) checking. pub check_abi: bool, /// Action for an op requiring communication with the host. @@ -134,8 +130,6 @@ impl Default for MiriConfig { validate: true, stacked_borrows: true, check_alignment: AlignmentCheck::Int, - allow_uninit_numbers: false, - allow_ptr_int_transmute: false, check_abi: true, isolated_op: IsolatedOp::Reject(RejectOpWith::Abort), ignore_leaks: false, diff --git a/src/intptrcast.rs b/src/intptrcast.rs index e569960f68fba..0ffa067059f52 100644 --- a/src/intptrcast.rs +++ b/src/intptrcast.rs @@ -107,19 +107,13 @@ impl<'mir, 'tcx> GlobalStateInner { } pub fn ptr_from_addr_transmute( - ecx: &MiriEvalContext<'mir, 'tcx>, + _ecx: &MiriEvalContext<'mir, 'tcx>, addr: u64, ) -> Pointer> { trace!("Transmuting {:#x} to a pointer", addr); - let provenance = if ecx.machine.allow_ptr_int_transmute { - // When we allow transmutes, treat them like casts: generating a wildcard pointer. - Some(Tag::Wildcard) - } else { - // Usually, we consider transmuted pointers to be "invalid" (`None` provenance). - None - }; - Pointer::new(provenance, Size::from_bytes(addr)) + // We consider transmuted pointers to be "invalid" (`None` provenance). + Pointer::new(None, Size::from_bytes(addr)) } pub fn ptr_from_addr_cast( diff --git a/src/machine.rs b/src/machine.rs index 12df9e271fb96..9d35b43cc56fe 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -260,13 +260,6 @@ pub struct Evaluator<'mir, 'tcx> { /// Whether to enforce the validity invariant. pub(crate) validate: bool, - /// Whether to allow uninitialized numbers (integers and floats). - pub(crate) allow_uninit_numbers: bool, - - /// Whether to allow ptr2int transmutes, and whether to allow *dereferencing* the result of an - /// int2ptr transmute. - pub(crate) allow_ptr_int_transmute: bool, - /// Whether to enforce [ABI](Abi) of function calls. pub(crate) enforce_abi: bool, @@ -373,8 +366,6 @@ impl<'mir, 'tcx> Evaluator<'mir, 'tcx> { tls: TlsData::default(), isolated_op: config.isolated_op, validate: config.validate, - allow_uninit_numbers: config.allow_uninit_numbers, - allow_ptr_int_transmute: config.allow_ptr_int_transmute, enforce_abi: config.check_abi, file_handler: FileHandler::new(config.mute_stdout_stderr), dir_handler: Default::default(), @@ -527,13 +518,13 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { } #[inline(always)] - fn enforce_number_init(ecx: &MiriEvalContext<'mir, 'tcx>) -> bool { - !ecx.machine.allow_uninit_numbers + fn enforce_number_init(_ecx: &MiriEvalContext<'mir, 'tcx>) -> bool { + true } #[inline(always)] - fn enforce_number_no_provenance(ecx: &MiriEvalContext<'mir, 'tcx>) -> bool { - !ecx.machine.allow_ptr_int_transmute + fn enforce_number_no_provenance(_ecx: &MiriEvalContext<'mir, 'tcx>) -> bool { + true } #[inline(always)] diff --git a/tests/fail/validity/invalid_enum_tag_256variants_uninit.rs b/tests/fail/validity/invalid_enum_tag_256variants_uninit.rs deleted file mode 100644 index 708e0cafa90df..0000000000000 --- a/tests/fail/validity/invalid_enum_tag_256variants_uninit.rs +++ /dev/null @@ -1,272 +0,0 @@ -// Even when uninit numbers are allowed, this enum is not. -//@compile-flags: -Zmiri-allow-uninit-numbers -#![allow(unused, deprecated, invalid_value)] - -#[derive(Copy, Clone)] -enum A { - A0, - A1, - A2, - A3, - A4, - A5, - A6, - A7, - A8, - A9, - A10, - A11, - A12, - A13, - A14, - A15, - A16, - A17, - A18, - A19, - A20, - A21, - A22, - A23, - A24, - A25, - A26, - A27, - A28, - A29, - A30, - A31, - A32, - A33, - A34, - A35, - A36, - A37, - A38, - A39, - A40, - A41, - A42, - A43, - A44, - A45, - A46, - A47, - A48, - A49, - A50, - A51, - A52, - A53, - A54, - A55, - A56, - A57, - A58, - A59, - A60, - A61, - A62, - A63, - A64, - A65, - A66, - A67, - A68, - A69, - A70, - A71, - A72, - A73, - A74, - A75, - A76, - A77, - A78, - A79, - A80, - A81, - A82, - A83, - A84, - A85, - A86, - A87, - A88, - A89, - A90, - A91, - A92, - A93, - A94, - A95, - A96, - A97, - A98, - A99, - A100, - A101, - A102, - A103, - A104, - A105, - A106, - A107, - A108, - A109, - A110, - A111, - A112, - A113, - A114, - A115, - A116, - A117, - A118, - A119, - A120, - A121, - A122, - A123, - A124, - A125, - A126, - A127, - A128, - A129, - A130, - A131, - A132, - A133, - A134, - A135, - A136, - A137, - A138, - A139, - A140, - A141, - A142, - A143, - A144, - A145, - A146, - A147, - A148, - A149, - A150, - A151, - A152, - A153, - A154, - A155, - A156, - A157, - A158, - A159, - A160, - A161, - A162, - A163, - A164, - A165, - A166, - A167, - A168, - A169, - A170, - A171, - A172, - A173, - A174, - A175, - A176, - A177, - A178, - A179, - A180, - A181, - A182, - A183, - A184, - A185, - A186, - A187, - A188, - A189, - A190, - A191, - A192, - A193, - A194, - A195, - A196, - A197, - A198, - A199, - A200, - A201, - A202, - A203, - A204, - A205, - A206, - A207, - A208, - A209, - A210, - A211, - A212, - A213, - A214, - A215, - A216, - A217, - A218, - A219, - A220, - A221, - A222, - A223, - A224, - A225, - A226, - A227, - A228, - A229, - A230, - A231, - A232, - A233, - A234, - A235, - A236, - A237, - A238, - A239, - A240, - A241, - A242, - A243, - A244, - A245, - A246, - A247, - A248, - A249, - A250, - A251, - A252, - A253, - A254, - A255, -} - -union MyUninit { - init: (), - uninit: A, -} - -fn main() { - let _a = unsafe { MyUninit { init: () }.uninit }; //~ ERROR: constructing invalid value at .: encountered uninitialized bytes, but expected a valid enum tag -} diff --git a/tests/fail/validity/invalid_enum_tag_256variants_uninit.stderr b/tests/fail/validity/invalid_enum_tag_256variants_uninit.stderr deleted file mode 100644 index c3ebf462b6d75..0000000000000 --- a/tests/fail/validity/invalid_enum_tag_256variants_uninit.stderr +++ /dev/null @@ -1,16 +0,0 @@ -WARNING: `-Zmiri-allow-uninit-numbers` is deprecated and planned to be removed. Please let us know at if you rely on this flag. -error: Undefined Behavior: constructing invalid value at .: encountered uninitialized bytes, but expected a valid enum tag - --> $DIR/invalid_enum_tag_256variants_uninit.rs:LL:CC - | -LL | let _a = unsafe { MyUninit { init: () }.uninit }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .: encountered uninitialized bytes, but expected a valid enum tag - | - = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior - = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: - = note: inside `main` at $DIR/invalid_enum_tag_256variants_uninit.rs:LL:CC - -note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace - -error: aborting due to previous error - diff --git a/tests/pass/move-uninit-primval.rs b/tests/pass/move-uninit-primval.rs index 220470b637fcb..f5fd27fa0d4ed 100644 --- a/tests/pass/move-uninit-primval.rs +++ b/tests/pass/move-uninit-primval.rs @@ -1,13 +1,14 @@ -//@compile-flags: -Zmiri-allow-uninit-numbers #![allow(deprecated)] +use std::mem; + struct Foo { - _inner: i32, + _inner: mem::MaybeUninit, } fn main() { unsafe { - let foo = Foo { _inner: std::mem::uninitialized() }; + let foo = Foo { _inner: mem::uninitialized() }; let _bar = foo; } } diff --git a/tests/pass/move-uninit-primval.stderr b/tests/pass/move-uninit-primval.stderr deleted file mode 100644 index d9f2331fe7fa5..0000000000000 --- a/tests/pass/move-uninit-primval.stderr +++ /dev/null @@ -1 +0,0 @@ -WARNING: `-Zmiri-allow-uninit-numbers` is deprecated and planned to be removed. Please let us know at if you rely on this flag. diff --git a/tests/pass/uninit_number_ignored.rs b/tests/pass/uninit_number_ignored.rs deleted file mode 100644 index 44f6fa2679853..0000000000000 --- a/tests/pass/uninit_number_ignored.rs +++ /dev/null @@ -1,8 +0,0 @@ -//@compile-flags: -Zmiri-allow-uninit-numbers -// This test is adapted from https://github.com/rust-lang/miri/issues/1340#issue-600900312. - -fn main() { - let _val1 = unsafe { std::mem::MaybeUninit::::uninit().assume_init() }; - let _val2 = unsafe { std::mem::MaybeUninit::::uninit().assume_init() }; - let _val3 = unsafe { std::mem::MaybeUninit::::uninit().assume_init() }; -} diff --git a/tests/pass/uninit_number_ignored.stderr b/tests/pass/uninit_number_ignored.stderr deleted file mode 100644 index d9f2331fe7fa5..0000000000000 --- a/tests/pass/uninit_number_ignored.stderr +++ /dev/null @@ -1 +0,0 @@ -WARNING: `-Zmiri-allow-uninit-numbers` is deprecated and planned to be removed. Please let us know at if you rely on this flag. From 9f1cab53a724cfb61cdd49c884e142a8d7007cda Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 11 Jul 2022 22:55:59 -0400 Subject: [PATCH 3465/3747] allow some relabeling as well --- triagebot.toml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/triagebot.toml b/triagebot.toml index 264f0da7d33d3..21a154cafd40d 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -1,2 +1,11 @@ +[relabel] +allow-unauthenticated = [ + "A-*", + "C-*", + "E-*", + "I-*", + "S-*", + ] + # Gives us the commands 'ready', 'author', 'blocked' [shortcut] From cd3535d25664f02cbf66863a3ccfa682d8082629 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 12 Jul 2022 09:49:11 -0400 Subject: [PATCH 3466/3747] test that we also find bad uses of mem::uninitialized --- tests/fail/validity/uninit_float.rs | 4 +++- tests/fail/validity/uninit_float.stderr | 4 ++-- tests/fail/validity/uninit_integer_signed.rs | 6 ------ tests/fail/validity/uninit_integer_signed.stderr | 15 --------------- 4 files changed, 5 insertions(+), 24 deletions(-) delete mode 100644 tests/fail/validity/uninit_integer_signed.rs delete mode 100644 tests/fail/validity/uninit_integer_signed.stderr diff --git a/tests/fail/validity/uninit_float.rs b/tests/fail/validity/uninit_float.rs index 3e7c14786e351..0f4a22cf5b77d 100644 --- a/tests/fail/validity/uninit_float.rs +++ b/tests/fail/validity/uninit_float.rs @@ -1,6 +1,8 @@ +#![allow(deprecated)] // This test is adapted from https://github.com/rust-lang/miri/issues/1340#issue-600900312. fn main() { - let _val = unsafe { std::mem::MaybeUninit::::uninit().assume_init() }; + // Deliberately using `mem::uninitialized` to make sure that despite all the mitigations, we consider this UB. + let _val: f32 = unsafe { std::mem::uninitialized() }; //~^ ERROR: constructing invalid value at .value: encountered uninitialized bytes, but expected initialized bytes } diff --git a/tests/fail/validity/uninit_float.stderr b/tests/fail/validity/uninit_float.stderr index 2fe27c904329d..d9611af79eebf 100644 --- a/tests/fail/validity/uninit_float.stderr +++ b/tests/fail/validity/uninit_float.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: constructing invalid value at .value: encountered uninitialized bytes, but expected initialized bytes --> $DIR/uninit_float.rs:LL:CC | -LL | let _val = unsafe { std::mem::MaybeUninit::::uninit().assume_init() }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .value: encountered uninitialized bytes, but expected initialized bytes +LL | let _val: f32 = unsafe { std::mem::uninitialized() }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .value: encountered uninitialized bytes, but expected initialized bytes | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/validity/uninit_integer_signed.rs b/tests/fail/validity/uninit_integer_signed.rs deleted file mode 100644 index fa484413784c5..0000000000000 --- a/tests/fail/validity/uninit_integer_signed.rs +++ /dev/null @@ -1,6 +0,0 @@ -// This test is adapted from https://github.com/rust-lang/miri/issues/1340#issue-600900312. - -fn main() { - let _val = unsafe { std::mem::MaybeUninit::::uninit().assume_init() }; - //~^ ERROR: constructing invalid value at .value: encountered uninitialized bytes, but expected initialized bytes -} diff --git a/tests/fail/validity/uninit_integer_signed.stderr b/tests/fail/validity/uninit_integer_signed.stderr deleted file mode 100644 index c53c96c596e4a..0000000000000 --- a/tests/fail/validity/uninit_integer_signed.stderr +++ /dev/null @@ -1,15 +0,0 @@ -error: Undefined Behavior: constructing invalid value at .value: encountered uninitialized bytes, but expected initialized bytes - --> $DIR/uninit_integer_signed.rs:LL:CC - | -LL | let _val = unsafe { std::mem::MaybeUninit::::uninit().assume_init() }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .value: encountered uninitialized bytes, but expected initialized bytes - | - = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior - = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: - = note: inside `main` at $DIR/uninit_integer_signed.rs:LL:CC - -note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace - -error: aborting due to previous error - From afa1dddcf97cf6008cfb447739b4b61e04f86660 Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Sat, 2 Jul 2022 14:38:23 -0400 Subject: [PATCH 3467/3747] Store protectors outside Item, pack Tag and Perm Previously, Item was a struct of a NonZeroU64, an Option which was usually unset or irrelevant, and a 4-variant enum. So collectively, the size of an Item was 24 bytes, but only 8 bytes were used for the most part. So this takes advantage of the fact that it is probably impossible to exhaust the total space of SbTags, and steals 3 bits from it to pack the whole struct into a single u64. This bit-packing means that we reduce peak memory usage when Miri goes memory-bound by ~3x. We also get CPU performance improvements of varying size, because not only are we simply accessing less memory, we can now compare a Vec using a memcmp because it does not have any padding. --- src/machine.rs | 12 +- src/stacked_borrows.rs | 226 +++++++++++++----- src/stacked_borrows/diagnostics.rs | 4 +- src/stacked_borrows/stack.rs | 65 ++--- src/thread.rs | 4 + .../fail/stacked_borrows/aliasing_mut1.stderr | 4 +- .../fail/stacked_borrows/aliasing_mut2.stderr | 4 +- .../fail/stacked_borrows/aliasing_mut4.stderr | 4 +- .../deallocate_against_barrier1.stderr | 4 +- .../deallocate_against_barrier2.stderr | 4 +- .../stacked_borrows/illegal_write6.stderr | 4 +- .../invalidate_against_barrier1.stderr | 4 +- .../invalidate_against_barrier2.stderr | 4 +- .../stacked_borrows/newtype_retagging.stderr | 4 +- 14 files changed, 233 insertions(+), 114 deletions(-) diff --git a/src/machine.rs b/src/machine.rs index 12df9e271fb96..122bee2970e24 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -54,15 +54,18 @@ pub struct FrameData<'tcx> { /// for the start of this frame. When we finish executing this frame, /// we use this to register a completed event with `measureme`. pub timing: Option, + + pub protected_tags: Vec, } impl<'tcx> std::fmt::Debug for FrameData<'tcx> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { // Omitting `timing`, it does not support `Debug`. - let FrameData { call_id, catch_unwind, timing: _ } = self; + let FrameData { call_id, catch_unwind, timing: _, protected_tags } = self; f.debug_struct("FrameData") .field("call_id", call_id) .field("catch_unwind", catch_unwind) + .field("protected_tags", protected_tags) .finish() } } @@ -788,6 +791,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { range, machine.stacked_borrows.as_ref().unwrap(), machine.current_span(), + &machine.threads, )?; } if let Some(weak_memory) = &alloc_extra.weak_memory { @@ -819,6 +823,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { range, machine.stacked_borrows.as_ref().unwrap(), machine.current_span(), + &machine.threads, )?; } if let Some(weak_memory) = &alloc_extra.weak_memory { @@ -852,6 +857,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { tag, range, machine.stacked_borrows.as_ref().unwrap(), + &machine.threads, ) } else { Ok(()) @@ -892,7 +898,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { stacked_borrows.borrow_mut().new_call() }); - let extra = FrameData { call_id, catch_unwind: None, timing }; + let extra = FrameData { call_id, catch_unwind: None, timing, protected_tags: Vec::new() }; Ok(frame.with_extra(extra)) } @@ -936,7 +942,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { ) -> InterpResult<'tcx, StackPopJump> { let timing = frame.extra.timing.take(); if let Some(stacked_borrows) = &ecx.machine.stacked_borrows { - stacked_borrows.borrow_mut().end_call(frame.extra.call_id); + stacked_borrows.borrow_mut().end_call(&frame.extra); } let res = ecx.handle_stack_pop_unwind(frame.extra, unwinding); if let Some(profiler) = ecx.machine.profiler.as_ref() { diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 4e83c2c8aa967..8996754be3672 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -92,27 +92,99 @@ pub enum Permission { Disabled, } -/// An item in the per-location borrow stack. -#[derive(Copy, Clone, Hash, PartialEq, Eq)] -pub struct Item { - /// The permission this item grants. - perm: Permission, - /// The pointers the permission is granted to. - tag: SbTag, - /// An optional protector, ensuring the item cannot get popped until `CallId` is over. - protector: Option, +impl Permission { + const UNIQUE: u64 = 0; + const SHARED_READ_WRITE: u64 = 1; + const SHARED_READ_ONLY: u64 = 2; + const DISABLED: u64 = 3; + + fn to_bits(self) -> u64 { + match self { + Permission::Unique => Self::UNIQUE, + Permission::SharedReadWrite => Self::SHARED_READ_WRITE, + Permission::SharedReadOnly => Self::SHARED_READ_ONLY, + Permission::Disabled => Self::DISABLED, + } + } + + fn from_bits(perm: u64) -> Self { + match perm { + Self::UNIQUE => Permission::Unique, + Self::SHARED_READ_WRITE => Permission::SharedReadWrite, + Self::SHARED_READ_ONLY => Permission::SharedReadOnly, + Self::DISABLED => Permission::Disabled, + _ => unreachable!(), + } + } } -impl fmt::Debug for Item { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "[{:?} for {:?}", self.perm, self.tag)?; - if let Some(call) = self.protector { - write!(f, " (call {})", call)?; +mod item { + use super::{Permission, SbTag}; + use std::fmt; + use std::num::NonZeroU64; + + /// An item in the per-location borrow stack. + #[derive(Copy, Clone, Hash, PartialEq, Eq)] + pub struct Item(u64); + + // An Item contains 3 bitfields: + // * Bits 0-61 store an SbTag + // * Bits 61-63 store a Permission + // * Bit 64 stores a flag which indicates if we have a protector + const TAG_MASK: u64 = u64::MAX >> 3; + const PERM_MASK: u64 = 0x3 << 61; + const PROTECTED_MASK: u64 = 0x1 << 63; + + const PERM_SHIFT: u64 = 61; + const PROTECTED_SHIFT: u64 = 63; + + impl Item { + pub fn new(tag: SbTag, perm: Permission, protected: bool) -> Self { + assert!(tag.0.get() <= TAG_MASK); + let packed_tag = tag.0.get(); + let packed_perm = perm.to_bits() << PERM_SHIFT; + let packed_protected = (protected as u64) << PROTECTED_SHIFT; + + let new = Self(packed_tag | packed_perm | packed_protected); + + debug_assert!(new.tag() == tag); + debug_assert!(new.perm() == perm); + debug_assert!(new.protected() == protected); + + new + } + + /// The pointers the permission is granted to. + pub fn tag(self) -> SbTag { + SbTag(NonZeroU64::new(self.0 & TAG_MASK).unwrap()) + } + + /// The permission this item grants. + pub fn perm(self) -> Permission { + Permission::from_bits((self.0 & PERM_MASK) >> PERM_SHIFT) + } + + /// Whether or not there is a protector for this tag + pub fn protected(self) -> bool { + self.0 & PROTECTED_MASK > 0 + } + + /// Set the Permission stored in this Item to Permission::Disabled + pub fn set_disabled(&mut self) { + // Clear the current set permission + self.0 &= !PERM_MASK; + // Write Permission::Disabled to the Permission bits + self.0 |= Permission::Disabled.to_bits() << PERM_SHIFT; + } + } + + impl fmt::Debug for Item { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "[{:?} for {:?}]", self.perm(), self.tag()) } - write!(f, "]")?; - Ok(()) } } +pub use item::Item; /// Extra per-allocation state. #[derive(Clone, Debug)] @@ -136,8 +208,8 @@ pub struct GlobalStateInner { base_ptr_tags: FxHashMap, /// Next unused call ID (for protectors). next_call_id: CallId, - /// Those call IDs corresponding to functions that are still running. - active_calls: FxHashSet, + /// All tags currently protected + protected_tags: FxHashSet, /// The pointer ids to trace tracked_pointer_tags: HashSet, /// The call ids to trace @@ -201,7 +273,7 @@ impl GlobalStateInner { next_ptr_tag: SbTag(NonZeroU64::new(1).unwrap()), base_ptr_tags: FxHashMap::default(), next_call_id: NonZeroU64::new(1).unwrap(), - active_calls: FxHashSet::default(), + protected_tags: FxHashSet::default(), tracked_pointer_tags, tracked_call_ids, retag_fields, @@ -221,17 +293,14 @@ impl GlobalStateInner { if self.tracked_call_ids.contains(&id) { register_diagnostic(NonHaltingDiagnostic::CreatedCallId(id)); } - assert!(self.active_calls.insert(id)); self.next_call_id = NonZeroU64::new(id.get() + 1).unwrap(); id } - pub fn end_call(&mut self, id: CallId) { - assert!(self.active_calls.remove(&id)); - } - - fn is_active(&self, id: CallId) -> bool { - self.active_calls.contains(&id) + pub fn end_call(&mut self, frame: &machine::FrameData<'_>) { + for tag in &frame.protected_tags { + self.protected_tags.remove(tag); + } } pub fn base_ptr_tag(&mut self, id: AllocId) -> SbTag { @@ -287,7 +356,7 @@ impl<'tcx> Stack { /// Find the first write-incompatible item above the given one -- /// i.e, find the height to which the stack will be truncated when writing to `granting`. fn find_first_write_incompatible(&self, granting: usize) -> usize { - let perm = self.get(granting).unwrap().perm; + let perm = self.get(granting).unwrap().perm(); match perm { Permission::SharedReadOnly => bug!("Cannot use SharedReadOnly for writing"), Permission::Disabled => bug!("Cannot use Disabled for anything"), @@ -299,7 +368,7 @@ impl<'tcx> Stack { // The SharedReadWrite *just* above us are compatible, to skip those. let mut idx = granting + 1; while let Some(item) = self.get(idx) { - if item.perm == Permission::SharedReadWrite { + if item.perm() == Permission::SharedReadWrite { // Go on. idx += 1; } else { @@ -325,32 +394,44 @@ impl<'tcx> Stack { provoking_access: Option<(SbTagExtra, AllocRange, Size, AccessKind)>, // just for debug printing and error messages global: &GlobalStateInner, alloc_history: &mut AllocHistory, + threads: &ThreadManager<'_, 'tcx>, ) -> InterpResult<'tcx> { - if global.tracked_pointer_tags.contains(&item.tag) { + if global.tracked_pointer_tags.contains(&item.tag()) { register_diagnostic(NonHaltingDiagnostic::PoppedPointerTag( *item, provoking_access.map(|(tag, _alloc_range, _size, access)| (tag, access)), )); } - if let Some(call) = item.protector { - if global.is_active(call) { - if let Some((tag, _alloc_range, _offset, _access)) = provoking_access { - Err(err_sb_ub( - format!( - "not granting access to tag {:?} because incompatible item is protected: {:?}", - tag, item - ), - None, - tag.and_then(|tag| alloc_history.get_logs_relevant_to(tag, Some(item.tag))), - ))? - } else { - Err(err_sb_ub( - format!("deallocating while item is protected: {:?}", item), - None, - None, - ))? - } + if !item.protected() { + return Ok(()); + } + + if global.protected_tags.contains(&item.tag()) { + let call_id = threads + .all_stacks() + .flatten() + .find(|t| t.extra.protected_tags.contains(&item.tag())) + .map(|frame| frame.extra.call_id) + .unwrap(); // FIXME: Surely we should find something, but a panic seems wrong here? + if let Some((tag, _alloc_range, _offset, _access)) = provoking_access { + Err(err_sb_ub( + format!( + "not granting access to tag {:?} because incompatible item is protected: {:?} (call {:?})", + tag, item, call_id + ), + None, + tag.and_then(|tag| alloc_history.get_logs_relevant_to(tag, Some(item.tag()))), + ))? + } else { + Err(err_sb_ub( + format!( + "deallocating while item is protected: {:?} (call {:?})", + item, call_id + ), + None, + None, + ))? } } Ok(()) @@ -369,6 +450,7 @@ impl<'tcx> Stack { current_span: &mut CurrentSpan<'_, '_, 'tcx>, alloc_history: &mut AllocHistory, exposed_tags: &FxHashSet, + threads: &ThreadManager<'_, 'tcx>, ) -> InterpResult<'tcx> { // Two main steps: Find granting item, remove incompatible items above. @@ -399,8 +481,9 @@ impl<'tcx> Stack { Some((tag, alloc_range, offset, access)), global, alloc_history, + threads, )?; - alloc_history.log_invalidation(item.tag, alloc_range, current_span); + alloc_history.log_invalidation(item.tag(), alloc_range, current_span); Ok(()) })?; } else { @@ -425,8 +508,9 @@ impl<'tcx> Stack { Some((tag, alloc_range, offset, access)), global, alloc_history, + threads, )?; - alloc_history.log_invalidation(item.tag, alloc_range, current_span); + alloc_history.log_invalidation(item.tag(), alloc_range, current_span); Ok(()) })?; } @@ -439,9 +523,9 @@ impl<'tcx> Stack { for i in 0..self.len() { let item = self.get(i).unwrap(); // Skip disabled items, they cannot be matched anyway. - if !matches!(item.perm, Permission::Disabled) { + if !matches!(item.perm(), Permission::Disabled) { // We are looking for a strict upper bound, so add 1 to this tag. - max = cmp::max(item.tag.0.checked_add(1).unwrap(), max); + max = cmp::max(item.tag().0.checked_add(1).unwrap(), max); } } if let Some(unk) = self.unknown_bottom() { @@ -467,6 +551,7 @@ impl<'tcx> Stack { global: &GlobalStateInner, alloc_history: &mut AllocHistory, exposed_tags: &FxHashSet, + threads: &ThreadManager<'_, 'tcx>, ) -> InterpResult<'tcx> { // Step 1: Make sure there is a granting item. self.find_granting(AccessKind::Write, tag, exposed_tags).map_err(|_| { @@ -482,7 +567,7 @@ impl<'tcx> Stack { // Step 2: Consider all items removed. This checks for protectors. for idx in (0..self.len()).rev() { let item = self.get(idx).unwrap(); - Stack::item_popped(&item, None, global, alloc_history)?; + Stack::item_popped(&item, None, global, alloc_history, threads)?; } Ok(()) } @@ -502,10 +587,11 @@ impl<'tcx> Stack { current_span: &mut CurrentSpan<'_, '_, 'tcx>, alloc_history: &mut AllocHistory, exposed_tags: &FxHashSet, + threads: &ThreadManager<'_, 'tcx>, ) -> InterpResult<'tcx> { // Figure out which access `perm` corresponds to. let access = - if new.perm.grants(AccessKind::Write) { AccessKind::Write } else { AccessKind::Read }; + if new.perm().grants(AccessKind::Write) { AccessKind::Write } else { AccessKind::Read }; // Now we figure out which item grants our parent (`derived_from`) this kind of access. // We use that to determine where to put the new item. @@ -517,7 +603,7 @@ impl<'tcx> Stack { // Compute where to put the new item. // Either way, we ensure that we insert the new item in a way such that between // `derived_from` and the new one, there are only items *compatible with* `derived_from`. - let new_idx = if new.perm == Permission::SharedReadWrite { + let new_idx = if new.perm() == Permission::SharedReadWrite { assert!( access == AccessKind::Write, "this case only makes sense for stack-like accesses" @@ -550,6 +636,7 @@ impl<'tcx> Stack { current_span, alloc_history, exposed_tags, + threads, )?; // We insert "as far up as possible": We know only compatible items are remaining @@ -571,7 +658,7 @@ impl<'tcx> Stack { impl<'tcx> Stacks { /// Creates new stack with initial tag. fn new(size: Size, perm: Permission, tag: SbTag) -> Self { - let item = Item { perm, tag, protector: None }; + let item = Item::new(tag, perm, false); let stack = Stack::new(item); Stacks { @@ -637,6 +724,7 @@ impl Stacks { range: AllocRange, state: &GlobalState, mut current_span: CurrentSpan<'_, '_, 'tcx>, + threads: &ThreadManager<'_, 'tcx>, ) -> InterpResult<'tcx> { trace!( "read access with tag {:?}: {:?}, size {}", @@ -654,6 +742,7 @@ impl Stacks { &mut current_span, history, exposed_tags, + threads, ) }) } @@ -666,6 +755,7 @@ impl Stacks { range: AllocRange, state: &GlobalState, mut current_span: CurrentSpan<'_, '_, 'tcx>, + threads: &ThreadManager<'_, 'tcx>, ) -> InterpResult<'tcx> { trace!( "write access with tag {:?}: {:?}, size {}", @@ -683,6 +773,7 @@ impl Stacks { &mut current_span, history, exposed_tags, + threads, ) }) } @@ -694,11 +785,12 @@ impl Stacks { tag: SbTagExtra, range: AllocRange, state: &GlobalState, + threads: &ThreadManager<'_, 'tcx>, ) -> InterpResult<'tcx> { trace!("deallocation with tag {:?}: {:?}, size {}", tag, alloc_id, range.size.bytes()); let state = state.borrow(); self.for_each(range, |offset, stack, history, exposed_tags| { - stack.dealloc(tag, (alloc_id, range, offset), &state, history, exposed_tags) + stack.dealloc(tag, (alloc_id, range, offset), &state, history, exposed_tags, threads) })?; Ok(()) } @@ -801,7 +893,6 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx }); } - let protector = if protect { Some(this.frame().extra.call_id) } else { None }; trace!( "reborrow: {} reference {:?} derived from {:?} (pointee {}): {:?}, size {}", kind, @@ -812,6 +903,13 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx size.bytes() ); + if protect { + this.frame_mut().extra.protected_tags.push(new_tag); + this.machine.stacked_borrows.as_mut().unwrap().get_mut().protected_tags.insert(new_tag); + } + // FIXME: can't hold the current span handle across the borrows of self above + let current_span = &mut this.machine.current_span(); + // Update the stacks. // Make sure that raw pointers and mutable shared references are reborrowed "weak": // There could be existing unique pointers reborrowed from them that should remain valid! @@ -848,15 +946,16 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } else { Permission::SharedReadWrite }; - let protector = if frozen { - protector + let protected = if frozen { + protect } else { // We do not protect inside UnsafeCell. // This fixes https://github.com/rust-lang/rust/issues/55005. - None + false }; - let item = Item { perm, tag: new_tag, protector }; + let item = Item::new(new_tag, perm, protected); let mut global = this.machine.stacked_borrows.as_ref().unwrap().borrow_mut(); + let threads = &this.machine.threads; stacked_borrows.for_each(range, |offset, stack, history, exposed_tags| { stack.grant( orig_tag, @@ -866,6 +965,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx current_span, history, exposed_tags, + threads, ) }) })?; @@ -881,9 +981,10 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx .as_mut() .expect("we should have Stacked Borrows data") .borrow_mut(); - let item = Item { perm, tag: new_tag, protector }; + let item = Item::new(new_tag, perm, protect); let range = alloc_range(base_offset, size); let mut global = machine.stacked_borrows.as_ref().unwrap().borrow_mut(); + let threads = &machine.threads; let current_span = &mut machine.current_span(); // `get_alloc_extra_mut` invalidated our old `current_span` stacked_borrows.for_each(range, |offset, stack, history, exposed_tags| { stack.grant( @@ -894,6 +995,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx current_span, history, exposed_tags, + threads, ) })?; diff --git a/src/stacked_borrows/diagnostics.rs b/src/stacked_borrows/diagnostics.rs index d787865c4e2d2..1fa619a3ae4d4 100644 --- a/src/stacked_borrows/diagnostics.rs +++ b/src/stacked_borrows/diagnostics.rs @@ -141,7 +141,7 @@ impl AllocHistory { ) -> InterpError<'tcx> { let action = format!( "trying to reborrow {derived_from:?} for {new_perm:?} permission at {alloc_id:?}[{offset:#x}]", - new_perm = new.perm, + new_perm = new.perm(), offset = error_offset.bytes(), ); err_sb_ub( @@ -185,7 +185,7 @@ fn error_cause(stack: &Stack, tag: SbTagExtra) -> &'static str { if let SbTagExtra::Concrete(tag) = tag { if (0..stack.len()) .map(|i| stack.get(i).unwrap()) - .any(|item| item.tag == tag && item.perm != Permission::Disabled) + .any(|item| item.tag() == tag && item.perm() != Permission::Disabled) { ", but that tag only grants SharedReadOnly permission for this location" } else { diff --git a/src/stacked_borrows/stack.rs b/src/stacked_borrows/stack.rs index ccdd85eafd8eb..0863f80232775 100644 --- a/src/stacked_borrows/stack.rs +++ b/src/stacked_borrows/stack.rs @@ -37,7 +37,7 @@ pub struct Stack { } /// A very small cache of searches of the borrow stack -/// This maps tags to locations in the borrow stack. Any use of this still needs to do a +/// This maps items to locations in the borrow stack. Any use of this still needs to do a /// probably-cold random access into the borrow stack to figure out what `Permission` an /// `SbTag` grants. We could avoid this by also storing the `Permission` in the cache, but /// most lookups into the cache are immediately followed by access of the full borrow stack anyway. @@ -48,7 +48,7 @@ pub struct Stack { #[cfg(feature = "stack-cache")] #[derive(Clone, Debug)] struct StackCache { - tags: [SbTag; CACHE_LEN], // Hot in find_granting + items: [Item; CACHE_LEN], // Hot in find_granting idx: [usize; CACHE_LEN], // Hot in grant } @@ -59,11 +59,11 @@ impl StackCache { /// We use the position in the cache to represent how recently a tag was used; the first position /// is the most recently used tag. So an add shifts every element towards the end, and inserts /// the new element at the start. We lose the last element. - /// This strategy is effective at keeping the most-accessed tags in the cache, but it costs a + /// This strategy is effective at keeping the most-accessed items in the cache, but it costs a /// linear shift across the entire cache when we add a new tag. - fn add(&mut self, idx: usize, tag: SbTag) { - self.tags.copy_within(0..CACHE_LEN - 1, 1); - self.tags[0] = tag; + fn add(&mut self, idx: usize, item: Item) { + self.items.copy_within(0..CACHE_LEN - 1, 1); + self.items[0] = item; self.idx.copy_within(0..CACHE_LEN - 1, 1); self.idx[0] = idx; } @@ -80,20 +80,20 @@ impl Eq for Stack {} impl<'tcx> Stack { /// Panics if any of the caching mechanisms have broken, - /// - The StackCache indices don't refer to the parallel tags, - /// - There are no Unique tags outside of first_unique..last_unique + /// - The StackCache indices don't refer to the parallel items, + /// - There are no Unique items outside of first_unique..last_unique #[cfg(feature = "expensive-debug-assertions")] fn verify_cache_consistency(&self) { // Only a full cache needs to be valid. Also see the comments in find_granting_cache // and set_unknown_bottom. if self.borrows.len() >= CACHE_LEN { - for (tag, stack_idx) in self.cache.tags.iter().zip(self.cache.idx.iter()) { - assert_eq!(self.borrows[*stack_idx].tag, *tag); + for (tag, stack_idx) in self.cache.items.iter().zip(self.cache.idx.iter()) { + assert_eq!(self.borrows[*stack_idx], *tag); } } for (idx, item) in self.borrows.iter().enumerate() { - if item.perm == Permission::Unique { + if item.perm() == Permission::Unique { assert!( self.unique_range.contains(&idx), "{:?} {:?}", @@ -128,7 +128,7 @@ impl<'tcx> Stack { .rev() // search top-to-bottom .find_map(|(idx, item)| { // If the item fits and *might* be this wildcard, use it. - if item.perm.grants(access) && exposed_tags.contains(&item.tag) { + if item.perm().grants(access) && exposed_tags.contains(&item.tag()) { Some(idx) } else { None @@ -161,9 +161,9 @@ impl<'tcx> Stack { // If we didn't find the tag in the cache, fall back to a linear search of the // whole stack, and add the tag to the cache. for (stack_idx, item) in self.borrows.iter().enumerate().rev() { - if tag == item.tag && item.perm.grants(access) { + if tag == item.tag() && item.perm().grants(access) { #[cfg(feature = "stack-cache")] - self.cache.add(stack_idx, tag); + self.cache.add(stack_idx, *item); return Some(stack_idx); } } @@ -175,7 +175,7 @@ impl<'tcx> Stack { // This looks like a common-sense optimization; we're going to do a linear search of the // cache or the borrow stack to scan the shorter of the two. This optimization is miniscule // and this check actually ensures we do not access an invalid cache. - // When a stack is created and when tags are removed from the top of the borrow stack, we + // When a stack is created and when items are removed from the top of the borrow stack, we // need some valid value to populate the cache. In both cases, we try to use the bottom // item. But when the stack is cleared in `set_unknown_bottom` there is nothing we could // place in the cache that is correct. But due to the way we populate the cache in @@ -185,21 +185,23 @@ impl<'tcx> Stack { return None; } // Search the cache for the tag we're looking up - let cache_idx = self.cache.tags.iter().position(|t| *t == tag)?; + let cache_idx = self.cache.items.iter().position(|t| t.tag() == tag)?; let stack_idx = self.cache.idx[cache_idx]; // If we found the tag, look up its position in the stack to see if it grants // the required permission - if self.borrows[stack_idx].perm.grants(access) { + if self.cache.items[cache_idx].perm().grants(access) { // If it does, and it's not already in the most-recently-used position, re-insert it at // the most-recently-used position. This technically reduces the efficiency of the // cache by duplicating elements, but current benchmarks do not seem to benefit from // avoiding this duplication. // But if the tag is in position 1, avoiding the duplicating add is trivial. + // If it does, and it's not already in the most-recently-used position, move it there. + // Except if the tag is in position 1, this is equivalent to just a swap, so do that. if cache_idx == 1 { - self.cache.tags.swap(0, 1); + self.cache.items.swap(0, 1); self.cache.idx.swap(0, 1); } else if cache_idx > 1 { - self.cache.add(stack_idx, tag); + self.cache.add(stack_idx, self.cache.items[cache_idx]); } Some(stack_idx) } else { @@ -224,7 +226,7 @@ impl<'tcx> Stack { if self.unique_range.end >= new_idx { self.unique_range.end += 1; } - if new.perm == Permission::Unique { + if new.perm() == Permission::Unique { // Make sure the possibly-unique range contains the new borrow self.unique_range.start = self.unique_range.start.min(new_idx); self.unique_range.end = self.unique_range.end.max(new_idx + 1); @@ -233,7 +235,7 @@ impl<'tcx> Stack { // The above insert changes the meaning of every index in the cache >= new_idx, so now // we need to find every one of those indexes and increment it. // But if the insert is at the end (equivalent to a push), we can skip this step because - // it didn't change the position of any other tags. + // it didn't change the position of any other items. if new_idx != self.borrows.len() - 1 { for idx in &mut self.cache.idx { if *idx >= new_idx { @@ -243,7 +245,7 @@ impl<'tcx> Stack { } // This primes the cache for the next access, which is almost always the just-added tag. - self.cache.add(new_idx, new.tag); + self.cache.add(new_idx, new); #[cfg(feature = "expensive-debug-assertions")] self.verify_cache_consistency(); @@ -255,9 +257,9 @@ impl<'tcx> Stack { borrows: vec![item], unknown_bottom: None, #[cfg(feature = "stack-cache")] - cache: StackCache { idx: [0; CACHE_LEN], tags: [item.tag; CACHE_LEN] }, + cache: StackCache { idx: [0; CACHE_LEN], items: [item; CACHE_LEN] }, #[cfg(feature = "stack-cache")] - unique_range: if item.perm == Permission::Unique { 0..1 } else { 0..0 }, + unique_range: if item.perm() == Permission::Unique { 0..1 } else { 0..0 }, } } @@ -298,10 +300,15 @@ impl<'tcx> Stack { let lower = unique_range.start.max(disable_start); let upper = (unique_range.end + 1).min(self.borrows.len()); for item in &mut self.borrows[lower..upper] { - if item.perm == Permission::Unique { + if item.perm() == Permission::Unique { log::trace!("access: disabling item {:?}", item); visitor(*item)?; - item.perm = Permission::Disabled; + item.set_disabled(); + for t in &mut self.cache.items { + if t.tag() == item.tag() { + t.set_disabled(); + } + } } } } @@ -341,7 +348,7 @@ impl<'tcx> Stack { // also possible that the whole cache is still valid. So we call this method to repair what // aspects of the cache are now invalid, instead of resetting the whole thing to a trivially // valid default state. - let base_tag = self.borrows[0].tag; + let base_tag = self.borrows[0]; let mut removed = 0; let mut cursor = 0; // Remove invalid entries from the cache by rotating them to the end of the cache, then @@ -350,7 +357,7 @@ impl<'tcx> Stack { for _ in 0..CACHE_LEN - 1 { if self.cache.idx[cursor] >= start { self.cache.idx[cursor..CACHE_LEN - removed].rotate_left(1); - self.cache.tags[cursor..CACHE_LEN - removed].rotate_left(1); + self.cache.items[cursor..CACHE_LEN - removed].rotate_left(1); removed += 1; } else { cursor += 1; @@ -358,7 +365,7 @@ impl<'tcx> Stack { } for i in CACHE_LEN - removed - 1..CACHE_LEN { self.cache.idx[i] = 0; - self.cache.tags[i] = base_tag; + self.cache.items[i] = base_tag; } if start < self.unique_range.start.saturating_sub(1) { diff --git a/src/thread.rs b/src/thread.rs index 420eeb810fd87..96135d093d967 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -281,6 +281,10 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { &mut self.threads[self.active_thread].stack } + pub fn all_stacks(&self) -> impl Iterator>]> { + self.threads.iter().map(|t| &t.stack[..]) + } + /// Create a new thread and returns its id. fn create_thread(&mut self) -> ThreadId { let new_thread_id = ThreadId::new(self.threads.len()); diff --git a/tests/fail/stacked_borrows/aliasing_mut1.stderr b/tests/fail/stacked_borrows/aliasing_mut1.stderr index 34a53aa8f307a..82c504cd836f9 100644 --- a/tests/fail/stacked_borrows/aliasing_mut1.stderr +++ b/tests/fail/stacked_borrows/aliasing_mut1.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: not granting access to tag because incompatible item is protected: [Unique for (call ID)] +error: Undefined Behavior: not granting access to tag because incompatible item is protected: [Unique for ] (call ID) --> $DIR/aliasing_mut1.rs:LL:CC | LL | pub fn safe(_x: &mut i32, _y: &mut i32) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not granting access to tag because incompatible item is protected: [Unique for (call ID)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not granting access to tag because incompatible item is protected: [Unique for ] (call ID) | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information diff --git a/tests/fail/stacked_borrows/aliasing_mut2.stderr b/tests/fail/stacked_borrows/aliasing_mut2.stderr index 7830648ee8f3c..2973e22b2b793 100644 --- a/tests/fail/stacked_borrows/aliasing_mut2.stderr +++ b/tests/fail/stacked_borrows/aliasing_mut2.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: not granting access to tag because incompatible item is protected: [SharedReadOnly for (call ID)] +error: Undefined Behavior: not granting access to tag because incompatible item is protected: [SharedReadOnly for ] (call ID) --> $DIR/aliasing_mut2.rs:LL:CC | LL | pub fn safe(_x: &i32, _y: &mut i32) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not granting access to tag because incompatible item is protected: [SharedReadOnly for (call ID)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not granting access to tag because incompatible item is protected: [SharedReadOnly for ] (call ID) | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information diff --git a/tests/fail/stacked_borrows/aliasing_mut4.stderr b/tests/fail/stacked_borrows/aliasing_mut4.stderr index f62ce1e519649..b9a7b810dbd85 100644 --- a/tests/fail/stacked_borrows/aliasing_mut4.stderr +++ b/tests/fail/stacked_borrows/aliasing_mut4.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: not granting access to tag because incompatible item is protected: [SharedReadOnly for (call ID)] +error: Undefined Behavior: not granting access to tag because incompatible item is protected: [SharedReadOnly for ] (call ID) --> $DIR/aliasing_mut4.rs:LL:CC | LL | pub fn safe(_x: &i32, _y: &mut Cell) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not granting access to tag because incompatible item is protected: [SharedReadOnly for (call ID)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not granting access to tag because incompatible item is protected: [SharedReadOnly for ] (call ID) | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information diff --git a/tests/fail/stacked_borrows/deallocate_against_barrier1.stderr b/tests/fail/stacked_borrows/deallocate_against_barrier1.stderr index c3ea7a437cdb1..124731e85bd59 100644 --- a/tests/fail/stacked_borrows/deallocate_against_barrier1.stderr +++ b/tests/fail/stacked_borrows/deallocate_against_barrier1.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: deallocating while item is protected: [Unique for (call ID)] +error: Undefined Behavior: deallocating while item is protected: [Unique for ] (call ID) --> RUSTLIB/alloc/src/alloc.rs:LL:CC | LL | unsafe { __rust_dealloc(ptr, layout.size(), layout.align()) } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ deallocating while item is protected: [Unique for (call ID)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ deallocating while item is protected: [Unique for ] (call ID) | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information diff --git a/tests/fail/stacked_borrows/deallocate_against_barrier2.stderr b/tests/fail/stacked_borrows/deallocate_against_barrier2.stderr index d6c31e0649ec3..e09158dfb4083 100644 --- a/tests/fail/stacked_borrows/deallocate_against_barrier2.stderr +++ b/tests/fail/stacked_borrows/deallocate_against_barrier2.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: deallocating while item is protected: [SharedReadWrite for (call ID)] +error: Undefined Behavior: deallocating while item is protected: [SharedReadWrite for ] (call ID) --> RUSTLIB/alloc/src/alloc.rs:LL:CC | LL | unsafe { __rust_dealloc(ptr, layout.size(), layout.align()) } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ deallocating while item is protected: [SharedReadWrite for (call ID)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ deallocating while item is protected: [SharedReadWrite for ] (call ID) | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information diff --git a/tests/fail/stacked_borrows/illegal_write6.stderr b/tests/fail/stacked_borrows/illegal_write6.stderr index cbf4a22f23f27..cab6f392d1b11 100644 --- a/tests/fail/stacked_borrows/illegal_write6.stderr +++ b/tests/fail/stacked_borrows/illegal_write6.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: not granting access to tag because incompatible item is protected: [Unique for (call ID)] +error: Undefined Behavior: not granting access to tag because incompatible item is protected: [Unique for ] (call ID) --> $DIR/illegal_write6.rs:LL:CC | LL | unsafe { *y = 2 }; - | ^^^^^^ not granting access to tag because incompatible item is protected: [Unique for (call ID)] + | ^^^^^^ not granting access to tag because incompatible item is protected: [Unique for ] (call ID) | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information diff --git a/tests/fail/stacked_borrows/invalidate_against_barrier1.stderr b/tests/fail/stacked_borrows/invalidate_against_barrier1.stderr index 5f54134a24315..40d5147cadff5 100644 --- a/tests/fail/stacked_borrows/invalidate_against_barrier1.stderr +++ b/tests/fail/stacked_borrows/invalidate_against_barrier1.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: not granting access to tag because incompatible item is protected: [Unique for (call ID)] +error: Undefined Behavior: not granting access to tag because incompatible item is protected: [Unique for ] (call ID) --> $DIR/invalidate_against_barrier1.rs:LL:CC | LL | let _val = unsafe { *x }; - | ^^ not granting access to tag because incompatible item is protected: [Unique for (call ID)] + | ^^ not granting access to tag because incompatible item is protected: [Unique for ] (call ID) | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information diff --git a/tests/fail/stacked_borrows/invalidate_against_barrier2.stderr b/tests/fail/stacked_borrows/invalidate_against_barrier2.stderr index 15bc91e869f9d..30148396cc5d1 100644 --- a/tests/fail/stacked_borrows/invalidate_against_barrier2.stderr +++ b/tests/fail/stacked_borrows/invalidate_against_barrier2.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: not granting access to tag because incompatible item is protected: [SharedReadOnly for (call ID)] +error: Undefined Behavior: not granting access to tag because incompatible item is protected: [SharedReadOnly for ] (call ID) --> $DIR/invalidate_against_barrier2.rs:LL:CC | LL | unsafe { *x = 0 }; - | ^^^^^^ not granting access to tag because incompatible item is protected: [SharedReadOnly for (call ID)] + | ^^^^^^ not granting access to tag because incompatible item is protected: [SharedReadOnly for ] (call ID) | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information diff --git a/tests/fail/stacked_borrows/newtype_retagging.stderr b/tests/fail/stacked_borrows/newtype_retagging.stderr index 860a628492c78..337a22967c7dd 100644 --- a/tests/fail/stacked_borrows/newtype_retagging.stderr +++ b/tests/fail/stacked_borrows/newtype_retagging.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: not granting access to tag because incompatible item is protected: [Unique for (call ID)] +error: Undefined Behavior: not granting access to tag because incompatible item is protected: [Unique for ] (call ID) --> RUSTLIB/alloc/src/boxed.rs:LL:CC | LL | Box(unsafe { Unique::new_unchecked(raw) }, alloc) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not granting access to tag because incompatible item is protected: [Unique for (call ID)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not granting access to tag because incompatible item is protected: [Unique for ] (call ID) | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information From 4eff60ad6e37cd8f37e994d42c8c1ce271670bd4 Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Mon, 11 Jul 2022 20:54:31 -0400 Subject: [PATCH 3468/3747] Rearrange and document the new implementation stacked_borrow now has an item module, and its own FrameExtra. These serve to protect the implementation of Item (which is a bunch of bit-packing tricks) from the primary logic of Stacked Borrows, and the FrameExtra we have separates Stacked Borrows more cleanly from the interpreter itself. The new strategy for checking protectors also makes some subtle performance tradeoffs, so they are now documented in Stack::item_popped because that function primarily benefits from them, and it also touches every aspect of them. Also separating the actual CallId that is protecting a Tag from the Tag makes it inconvienent to reproduce exactly the same protector errors, so this also takes the opportunity to use some slightly cleaner English in those errors. We need to make some change, might as well make it good. --- src/lib.rs | 4 +- src/machine.rs | 19 +- src/stacked_borrows.rs | 187 ++++++------------ src/stacked_borrows/item.rs | 104 ++++++++++ src/stacked_borrows/stack.rs | 9 +- tests/compiletest.rs | 2 +- .../fail/stacked_borrows/aliasing_mut1.stderr | 4 +- .../fail/stacked_borrows/aliasing_mut2.stderr | 4 +- .../fail/stacked_borrows/aliasing_mut4.stderr | 4 +- .../deallocate_against_barrier1.rs | 2 +- .../deallocate_against_barrier1.stderr | 4 +- .../deallocate_against_barrier2.rs | 2 +- .../deallocate_against_barrier2.stderr | 4 +- .../stacked_borrows/illegal_write6.stderr | 4 +- .../invalidate_against_barrier1.stderr | 4 +- .../invalidate_against_barrier2.stderr | 4 +- .../fail/stacked_borrows/newtype_retagging.rs | 2 +- .../stacked_borrows/newtype_retagging.stderr | 4 +- 18 files changed, 206 insertions(+), 161 deletions(-) create mode 100644 src/stacked_borrows/item.rs diff --git a/src/lib.rs b/src/lib.rs index f3e6e0eef70a3..b3d408a6dc072 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -90,8 +90,8 @@ pub use crate::mono_hash_map::MonoHashMap; pub use crate::operator::EvalContextExt as OperatorEvalContextExt; pub use crate::range_map::RangeMap; pub use crate::stacked_borrows::{ - stack::Stack, CallId, EvalContextExt as StackedBorEvalContextExt, Item, Permission, SbTag, - SbTagExtra, Stacks, + CallId, EvalContextExt as StackedBorEvalContextExt, Item, Permission, SbTag, SbTagExtra, Stack, + Stacks, }; pub use crate::sync::{CondvarId, EvalContextExt as SyncEvalContextExt, MutexId, RwLockId}; pub use crate::thread::{ diff --git a/src/machine.rs b/src/machine.rs index 122bee2970e24..e31d7ba0105d6 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -5,7 +5,6 @@ use std::borrow::Cow; use std::cell::RefCell; use std::collections::HashSet; use std::fmt; -use std::num::NonZeroU64; use std::time::Instant; use rand::rngs::StdRng; @@ -43,7 +42,7 @@ pub const NUM_CPUS: u64 = 1; /// Extra data stored with each stack frame pub struct FrameData<'tcx> { /// Extra data for Stacked Borrows. - pub call_id: stacked_borrows::CallId, + pub stacked_borrows: Option, /// If this is Some(), then this is a special "catch unwind" frame (the frame of `try_fn` /// called by `try`). When this frame is popped during unwinding a panic, @@ -54,18 +53,15 @@ pub struct FrameData<'tcx> { /// for the start of this frame. When we finish executing this frame, /// we use this to register a completed event with `measureme`. pub timing: Option, - - pub protected_tags: Vec, } impl<'tcx> std::fmt::Debug for FrameData<'tcx> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { // Omitting `timing`, it does not support `Debug`. - let FrameData { call_id, catch_unwind, timing: _, protected_tags } = self; + let FrameData { stacked_borrows, catch_unwind, timing: _ } = self; f.debug_struct("FrameData") - .field("call_id", call_id) + .field("stacked_borrows", stacked_borrows) .field("catch_unwind", catch_unwind) - .field("protected_tags", protected_tags) .finish() } } @@ -894,11 +890,12 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { }; let stacked_borrows = ecx.machine.stacked_borrows.as_ref(); - let call_id = stacked_borrows.map_or(NonZeroU64::new(1).unwrap(), |stacked_borrows| { - stacked_borrows.borrow_mut().new_call() - }); - let extra = FrameData { call_id, catch_unwind: None, timing, protected_tags: Vec::new() }; + let extra = FrameData { + stacked_borrows: stacked_borrows.map(|sb| sb.borrow_mut().new_frame()), + catch_unwind: None, + timing, + }; Ok(frame.with_extra(extra)) } diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 8996754be3672..4cae27ecd2192 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -16,6 +16,7 @@ use rustc_middle::ty::{ }; use rustc_span::DUMMY_SP; use rustc_target::abi::Size; +use smallvec::SmallVec; use std::collections::HashSet; use crate::*; @@ -23,8 +24,10 @@ use crate::*; pub mod diagnostics; use diagnostics::{AllocHistory, TagHistory}; -pub mod stack; -use stack::Stack; +mod item; +pub use item::{Item, Permission}; +mod stack; +pub use stack::Stack; pub type CallId = NonZeroU64; @@ -78,113 +81,21 @@ impl SbTagExtra { } } -/// Indicates which permission is granted (by this item to some pointers) -#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] -pub enum Permission { - /// Grants unique mutable access. - Unique, - /// Grants shared mutable access. - SharedReadWrite, - /// Grants shared read-only access. - SharedReadOnly, - /// Grants no access, but separates two groups of SharedReadWrite so they are not - /// all considered mutually compatible. - Disabled, -} - -impl Permission { - const UNIQUE: u64 = 0; - const SHARED_READ_WRITE: u64 = 1; - const SHARED_READ_ONLY: u64 = 2; - const DISABLED: u64 = 3; - - fn to_bits(self) -> u64 { - match self { - Permission::Unique => Self::UNIQUE, - Permission::SharedReadWrite => Self::SHARED_READ_WRITE, - Permission::SharedReadOnly => Self::SHARED_READ_ONLY, - Permission::Disabled => Self::DISABLED, - } - } - - fn from_bits(perm: u64) -> Self { - match perm { - Self::UNIQUE => Permission::Unique, - Self::SHARED_READ_WRITE => Permission::SharedReadWrite, - Self::SHARED_READ_ONLY => Permission::SharedReadOnly, - Self::DISABLED => Permission::Disabled, - _ => unreachable!(), - } - } -} - -mod item { - use super::{Permission, SbTag}; - use std::fmt; - use std::num::NonZeroU64; - - /// An item in the per-location borrow stack. - #[derive(Copy, Clone, Hash, PartialEq, Eq)] - pub struct Item(u64); - - // An Item contains 3 bitfields: - // * Bits 0-61 store an SbTag - // * Bits 61-63 store a Permission - // * Bit 64 stores a flag which indicates if we have a protector - const TAG_MASK: u64 = u64::MAX >> 3; - const PERM_MASK: u64 = 0x3 << 61; - const PROTECTED_MASK: u64 = 0x1 << 63; - - const PERM_SHIFT: u64 = 61; - const PROTECTED_SHIFT: u64 = 63; - - impl Item { - pub fn new(tag: SbTag, perm: Permission, protected: bool) -> Self { - assert!(tag.0.get() <= TAG_MASK); - let packed_tag = tag.0.get(); - let packed_perm = perm.to_bits() << PERM_SHIFT; - let packed_protected = (protected as u64) << PROTECTED_SHIFT; - - let new = Self(packed_tag | packed_perm | packed_protected); - - debug_assert!(new.tag() == tag); - debug_assert!(new.perm() == perm); - debug_assert!(new.protected() == protected); - - new - } - - /// The pointers the permission is granted to. - pub fn tag(self) -> SbTag { - SbTag(NonZeroU64::new(self.0 & TAG_MASK).unwrap()) - } - - /// The permission this item grants. - pub fn perm(self) -> Permission { - Permission::from_bits((self.0 & PERM_MASK) >> PERM_SHIFT) - } - - /// Whether or not there is a protector for this tag - pub fn protected(self) -> bool { - self.0 & PROTECTED_MASK > 0 - } - - /// Set the Permission stored in this Item to Permission::Disabled - pub fn set_disabled(&mut self) { - // Clear the current set permission - self.0 &= !PERM_MASK; - // Write Permission::Disabled to the Permission bits - self.0 |= Permission::Disabled.to_bits() << PERM_SHIFT; - } - } - - impl fmt::Debug for Item { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "[{:?} for {:?}]", self.perm(), self.tag()) - } - } +#[derive(Debug)] +pub struct FrameExtra { + /// The ID of the call this frame corresponds to. + call_id: CallId, + + /// If this frame is protecting any tags, they are listed here. We use this list to do + /// incremental updates of the global list of protected tags stored in the + /// `stacked_borrows::GlobalState` upon function return, and if we attempt to pop a protected + /// tag, to identify which call is responsible for protecting the tag. + /// See `Stack::item_popped` for more explanation. + /// + /// This will contain one tag per reference passed to the function, so + /// a size of 2 is enough for the vast majority of functions. + protected_tags: SmallVec<[SbTag; 2]>, } -pub use item::Item; /// Extra per-allocation state. #[derive(Clone, Debug)] @@ -208,7 +119,11 @@ pub struct GlobalStateInner { base_ptr_tags: FxHashMap, /// Next unused call ID (for protectors). next_call_id: CallId, - /// All tags currently protected + /// All currently protected tags. + /// An item is protected if its tag is in this set, *and* it has the "protected" bit set. + /// We add tags to this when they are created with a protector in `reborrow`, and + /// we remove tags from this when the call which is protecting them returns, in + /// `GlobalStateInner::end_call`. See `Stack::item_popped` for more details. protected_tags: FxHashSet, /// The pointer ids to trace tracked_pointer_tags: HashSet, @@ -287,18 +202,23 @@ impl GlobalStateInner { id } - pub fn new_call(&mut self) -> CallId { - let id = self.next_call_id; - trace!("new_call: Assigning ID {}", id); - if self.tracked_call_ids.contains(&id) { - register_diagnostic(NonHaltingDiagnostic::CreatedCallId(id)); + pub fn new_frame(&mut self) -> FrameExtra { + let call_id = self.next_call_id; + trace!("new_frame: Assigning call ID {}", call_id); + if self.tracked_call_ids.contains(&call_id) { + register_diagnostic(NonHaltingDiagnostic::CreatedCallId(call_id)); } - self.next_call_id = NonZeroU64::new(id.get() + 1).unwrap(); - id + self.next_call_id = NonZeroU64::new(call_id.get() + 1).unwrap(); + FrameExtra { call_id, protected_tags: SmallVec::new() } } pub fn end_call(&mut self, frame: &machine::FrameData<'_>) { - for tag in &frame.protected_tags { + for tag in &frame + .stacked_borrows + .as_ref() + .expect("we should have Stacked Borrows data") + .protected_tags + { self.protected_tags.remove(tag); } } @@ -407,17 +327,40 @@ impl<'tcx> Stack { return Ok(()); } + // We store tags twice, once in global.protected_tags and once in each call frame. + // We do this because consulting a single global set in this function is faster + // than attempting to search all call frames in the program for the `FrameExtra` + // (if any) which is protecting the popped tag. + // + // This duplication trades off making `end_call` slower to make this function faster. This + // trade-off is profitable in practice for a combination of two reasons. + // 1. A single protected tag can (and does in some programs) protect thousands of `Item`s. + // Therefore, adding overhead to in function call/return is profitable even if it only + // saves a little work in this function. + // 2. Most frames protect only one or two tags. So this duplicative global turns a search + // which ends up about linear in the number of protected tags in the program into a + // constant time check (and a slow linear, because the tags in the frames aren't contiguous). if global.protected_tags.contains(&item.tag()) { + // This path is cold because it is fatal to the program. So here it is fine to do the + // more expensive search to figure out which call is responsible for protecting this + // tag. let call_id = threads .all_stacks() .flatten() - .find(|t| t.extra.protected_tags.contains(&item.tag())) - .map(|frame| frame.extra.call_id) + .map(|frame| { + frame + .extra + .stacked_borrows + .as_ref() + .expect("we should have Stacked Borrows data") + }) + .find(|frame| frame.protected_tags.contains(&item.tag())) + .map(|frame| frame.call_id) .unwrap(); // FIXME: Surely we should find something, but a panic seems wrong here? if let Some((tag, _alloc_range, _offset, _access)) = provoking_access { Err(err_sb_ub( format!( - "not granting access to tag {:?} because incompatible item is protected: {:?} (call {:?})", + "not granting access to tag {:?} because incompatible item {:?} is protected by call {:?}", tag, item, call_id ), None, @@ -426,7 +369,7 @@ impl<'tcx> Stack { } else { Err(err_sb_ub( format!( - "deallocating while item is protected: {:?} (call {:?})", + "deallocating while item {:?} is protected by call {:?}", item, call_id ), None, @@ -904,7 +847,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ); if protect { - this.frame_mut().extra.protected_tags.push(new_tag); + this.frame_mut().extra.stacked_borrows.as_mut().unwrap().protected_tags.push(new_tag); this.machine.stacked_borrows.as_mut().unwrap().get_mut().protected_tags.insert(new_tag); } // FIXME: can't hold the current span handle across the borrows of self above diff --git a/src/stacked_borrows/item.rs b/src/stacked_borrows/item.rs new file mode 100644 index 0000000000000..ad1b9b075b40f --- /dev/null +++ b/src/stacked_borrows/item.rs @@ -0,0 +1,104 @@ +use crate::stacked_borrows::SbTag; +use std::fmt; +use std::num::NonZeroU64; + +/// An item in the per-location borrow stack. +#[derive(Copy, Clone, Hash, PartialEq, Eq)] +pub struct Item(u64); + +// An Item contains 3 bitfields: +// * Bits 0-61 store an SbTag +// * Bits 61-63 store a Permission +// * Bit 64 stores a flag which indicates if we have a protector +const TAG_MASK: u64 = u64::MAX >> 3; +const PERM_MASK: u64 = 0x3 << 61; +const PROTECTED_MASK: u64 = 0x1 << 63; + +const PERM_SHIFT: u64 = 61; +const PROTECTED_SHIFT: u64 = 63; + +impl Item { + pub fn new(tag: SbTag, perm: Permission, protected: bool) -> Self { + assert!(tag.0.get() <= TAG_MASK); + let packed_tag = tag.0.get(); + let packed_perm = perm.to_bits() << PERM_SHIFT; + let packed_protected = (protected as u64) << PROTECTED_SHIFT; + + let new = Self(packed_tag | packed_perm | packed_protected); + + debug_assert!(new.tag() == tag); + debug_assert!(new.perm() == perm); + debug_assert!(new.protected() == protected); + + new + } + + /// The pointers the permission is granted to. + pub fn tag(self) -> SbTag { + SbTag(NonZeroU64::new(self.0 & TAG_MASK).unwrap()) + } + + /// The permission this item grants. + pub fn perm(self) -> Permission { + Permission::from_bits((self.0 & PERM_MASK) >> PERM_SHIFT) + } + + /// Whether or not there is a protector for this tag + pub fn protected(self) -> bool { + self.0 & PROTECTED_MASK > 0 + } + + /// Set the Permission stored in this Item + pub fn set_permission(&mut self, perm: Permission) { + // Clear the current set permission + self.0 &= !PERM_MASK; + // Write Permission::Disabled to the Permission bits + self.0 |= perm.to_bits() << PERM_SHIFT; + } +} + +impl fmt::Debug for Item { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "[{:?} for {:?}]", self.perm(), self.tag()) + } +} + +/// Indicates which permission is granted (by this item to some pointers) +#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] +pub enum Permission { + /// Grants unique mutable access. + Unique, + /// Grants shared mutable access. + SharedReadWrite, + /// Grants shared read-only access. + SharedReadOnly, + /// Grants no access, but separates two groups of SharedReadWrite so they are not + /// all considered mutually compatible. + Disabled, +} + +impl Permission { + const UNIQUE: u64 = 0; + const SHARED_READ_WRITE: u64 = 1; + const SHARED_READ_ONLY: u64 = 2; + const DISABLED: u64 = 3; + + fn to_bits(self) -> u64 { + match self { + Permission::Unique => Self::UNIQUE, + Permission::SharedReadWrite => Self::SHARED_READ_WRITE, + Permission::SharedReadOnly => Self::SHARED_READ_ONLY, + Permission::Disabled => Self::DISABLED, + } + } + + fn from_bits(perm: u64) -> Self { + match perm { + Self::UNIQUE => Permission::Unique, + Self::SHARED_READ_WRITE => Permission::SharedReadWrite, + Self::SHARED_READ_ONLY => Permission::SharedReadOnly, + Self::DISABLED => Permission::Disabled, + _ => unreachable!(), + } + } +} diff --git a/src/stacked_borrows/stack.rs b/src/stacked_borrows/stack.rs index 0863f80232775..1b05471618a52 100644 --- a/src/stacked_borrows/stack.rs +++ b/src/stacked_borrows/stack.rs @@ -303,10 +303,11 @@ impl<'tcx> Stack { if item.perm() == Permission::Unique { log::trace!("access: disabling item {:?}", item); visitor(*item)?; - item.set_disabled(); - for t in &mut self.cache.items { - if t.tag() == item.tag() { - t.set_disabled(); + item.set_permission(Permission::Disabled); + // Also update all copies of this item in the cache. + for it in &mut self.cache.items { + if it.tag() == item.tag() { + it.set_permission(Permission::Disabled); } } } diff --git a/tests/compiletest.rs b/tests/compiletest.rs index 008fc7806457f..c568d1c50434c 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -97,7 +97,7 @@ regexes! { // erase specific alignments "alignment [0-9]+" => "alignment ALIGN", // erase thread caller ids - r"\(call [0-9]+\)" => "(call ID)", + r"call [0-9]+" => "call ID", // erase platform module paths "sys::[a-z]+::" => "sys::PLATFORM::", // Windows file paths diff --git a/tests/fail/stacked_borrows/aliasing_mut1.stderr b/tests/fail/stacked_borrows/aliasing_mut1.stderr index 82c504cd836f9..b821d1e6edb42 100644 --- a/tests/fail/stacked_borrows/aliasing_mut1.stderr +++ b/tests/fail/stacked_borrows/aliasing_mut1.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: not granting access to tag because incompatible item is protected: [Unique for ] (call ID) +error: Undefined Behavior: not granting access to tag because incompatible item [Unique for ] is protected by call ID --> $DIR/aliasing_mut1.rs:LL:CC | LL | pub fn safe(_x: &mut i32, _y: &mut i32) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not granting access to tag because incompatible item is protected: [Unique for ] (call ID) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not granting access to tag because incompatible item [Unique for ] is protected by call ID | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information diff --git a/tests/fail/stacked_borrows/aliasing_mut2.stderr b/tests/fail/stacked_borrows/aliasing_mut2.stderr index 2973e22b2b793..594b578fc09a7 100644 --- a/tests/fail/stacked_borrows/aliasing_mut2.stderr +++ b/tests/fail/stacked_borrows/aliasing_mut2.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: not granting access to tag because incompatible item is protected: [SharedReadOnly for ] (call ID) +error: Undefined Behavior: not granting access to tag because incompatible item [SharedReadOnly for ] is protected by call ID --> $DIR/aliasing_mut2.rs:LL:CC | LL | pub fn safe(_x: &i32, _y: &mut i32) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not granting access to tag because incompatible item is protected: [SharedReadOnly for ] (call ID) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not granting access to tag because incompatible item [SharedReadOnly for ] is protected by call ID | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information diff --git a/tests/fail/stacked_borrows/aliasing_mut4.stderr b/tests/fail/stacked_borrows/aliasing_mut4.stderr index b9a7b810dbd85..0c7d85ae5756c 100644 --- a/tests/fail/stacked_borrows/aliasing_mut4.stderr +++ b/tests/fail/stacked_borrows/aliasing_mut4.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: not granting access to tag because incompatible item is protected: [SharedReadOnly for ] (call ID) +error: Undefined Behavior: not granting access to tag because incompatible item [SharedReadOnly for ] is protected by call ID --> $DIR/aliasing_mut4.rs:LL:CC | LL | pub fn safe(_x: &i32, _y: &mut Cell) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not granting access to tag because incompatible item is protected: [SharedReadOnly for ] (call ID) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not granting access to tag because incompatible item [SharedReadOnly for ] is protected by call ID | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information diff --git a/tests/fail/stacked_borrows/deallocate_against_barrier1.rs b/tests/fail/stacked_borrows/deallocate_against_barrier1.rs index 0798f863ce110..20e026df7b9b2 100644 --- a/tests/fail/stacked_borrows/deallocate_against_barrier1.rs +++ b/tests/fail/stacked_borrows/deallocate_against_barrier1.rs @@ -1,4 +1,4 @@ -//@error-pattern: deallocating while item is protected +//@error-pattern: deallocating while item fn inner(x: &mut i32, f: fn(&mut i32)) { // `f` may mutate, but it may not deallocate! diff --git a/tests/fail/stacked_borrows/deallocate_against_barrier1.stderr b/tests/fail/stacked_borrows/deallocate_against_barrier1.stderr index 124731e85bd59..689c0a5deae68 100644 --- a/tests/fail/stacked_borrows/deallocate_against_barrier1.stderr +++ b/tests/fail/stacked_borrows/deallocate_against_barrier1.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: deallocating while item is protected: [Unique for ] (call ID) +error: Undefined Behavior: deallocating while item [Unique for ] is protected by call ID --> RUSTLIB/alloc/src/alloc.rs:LL:CC | LL | unsafe { __rust_dealloc(ptr, layout.size(), layout.align()) } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ deallocating while item is protected: [Unique for ] (call ID) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ deallocating while item [Unique for ] is protected by call ID | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information diff --git a/tests/fail/stacked_borrows/deallocate_against_barrier2.rs b/tests/fail/stacked_borrows/deallocate_against_barrier2.rs index 23c54c8d89883..9cb2d52bf2e9a 100644 --- a/tests/fail/stacked_borrows/deallocate_against_barrier2.rs +++ b/tests/fail/stacked_borrows/deallocate_against_barrier2.rs @@ -1,4 +1,4 @@ -//@error-pattern: deallocating while item is protected +//@error-pattern: deallocating while item use std::marker::PhantomPinned; pub struct NotUnpin(i32, PhantomPinned); diff --git a/tests/fail/stacked_borrows/deallocate_against_barrier2.stderr b/tests/fail/stacked_borrows/deallocate_against_barrier2.stderr index e09158dfb4083..a1a7ce0c6bb68 100644 --- a/tests/fail/stacked_borrows/deallocate_against_barrier2.stderr +++ b/tests/fail/stacked_borrows/deallocate_against_barrier2.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: deallocating while item is protected: [SharedReadWrite for ] (call ID) +error: Undefined Behavior: deallocating while item [SharedReadWrite for ] is protected by call ID --> RUSTLIB/alloc/src/alloc.rs:LL:CC | LL | unsafe { __rust_dealloc(ptr, layout.size(), layout.align()) } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ deallocating while item is protected: [SharedReadWrite for ] (call ID) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ deallocating while item [SharedReadWrite for ] is protected by call ID | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information diff --git a/tests/fail/stacked_borrows/illegal_write6.stderr b/tests/fail/stacked_borrows/illegal_write6.stderr index cab6f392d1b11..42f7b3f8b54bf 100644 --- a/tests/fail/stacked_borrows/illegal_write6.stderr +++ b/tests/fail/stacked_borrows/illegal_write6.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: not granting access to tag because incompatible item is protected: [Unique for ] (call ID) +error: Undefined Behavior: not granting access to tag because incompatible item [Unique for ] is protected by call ID --> $DIR/illegal_write6.rs:LL:CC | LL | unsafe { *y = 2 }; - | ^^^^^^ not granting access to tag because incompatible item is protected: [Unique for ] (call ID) + | ^^^^^^ not granting access to tag because incompatible item [Unique for ] is protected by call ID | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information diff --git a/tests/fail/stacked_borrows/invalidate_against_barrier1.stderr b/tests/fail/stacked_borrows/invalidate_against_barrier1.stderr index 40d5147cadff5..4a1b14e460941 100644 --- a/tests/fail/stacked_borrows/invalidate_against_barrier1.stderr +++ b/tests/fail/stacked_borrows/invalidate_against_barrier1.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: not granting access to tag because incompatible item is protected: [Unique for ] (call ID) +error: Undefined Behavior: not granting access to tag because incompatible item [Unique for ] is protected by call ID --> $DIR/invalidate_against_barrier1.rs:LL:CC | LL | let _val = unsafe { *x }; - | ^^ not granting access to tag because incompatible item is protected: [Unique for ] (call ID) + | ^^ not granting access to tag because incompatible item [Unique for ] is protected by call ID | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information diff --git a/tests/fail/stacked_borrows/invalidate_against_barrier2.stderr b/tests/fail/stacked_borrows/invalidate_against_barrier2.stderr index 30148396cc5d1..c6f158316f512 100644 --- a/tests/fail/stacked_borrows/invalidate_against_barrier2.stderr +++ b/tests/fail/stacked_borrows/invalidate_against_barrier2.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: not granting access to tag because incompatible item is protected: [SharedReadOnly for ] (call ID) +error: Undefined Behavior: not granting access to tag because incompatible item [SharedReadOnly for ] is protected by call ID --> $DIR/invalidate_against_barrier2.rs:LL:CC | LL | unsafe { *x = 0 }; - | ^^^^^^ not granting access to tag because incompatible item is protected: [SharedReadOnly for ] (call ID) + | ^^^^^^ not granting access to tag because incompatible item [SharedReadOnly for ] is protected by call ID | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information diff --git a/tests/fail/stacked_borrows/newtype_retagging.rs b/tests/fail/stacked_borrows/newtype_retagging.rs index 4786cd02d954f..f9cceb761af3e 100644 --- a/tests/fail/stacked_borrows/newtype_retagging.rs +++ b/tests/fail/stacked_borrows/newtype_retagging.rs @@ -1,5 +1,5 @@ //@compile-flags: -Zmiri-retag-fields -//@error-pattern: incompatible item is protected +//@error-pattern: is protected by call struct Newtype<'a>(&'a mut i32); fn dealloc_while_running(_n: Newtype<'_>, dealloc: impl FnOnce()) { diff --git a/tests/fail/stacked_borrows/newtype_retagging.stderr b/tests/fail/stacked_borrows/newtype_retagging.stderr index 337a22967c7dd..d9aebecfda731 100644 --- a/tests/fail/stacked_borrows/newtype_retagging.stderr +++ b/tests/fail/stacked_borrows/newtype_retagging.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: not granting access to tag because incompatible item is protected: [Unique for ] (call ID) +error: Undefined Behavior: not granting access to tag because incompatible item [Unique for ] is protected by call ID --> RUSTLIB/alloc/src/boxed.rs:LL:CC | LL | Box(unsafe { Unique::new_unchecked(raw) }, alloc) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not granting access to tag because incompatible item is protected: [Unique for ] (call ID) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not granting access to tag because incompatible item [Unique for ] is protected by call ID | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information From 7d9f04f7a8b3ef3c0e00a50e58f86fa8d8cf34ea Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Sat, 9 Jul 2022 19:53:21 -0400 Subject: [PATCH 3469/3747] Add a benchmark of the hang-on-test-failure code path --- bench-cargo-miri/slice-get-unchecked/Cargo.lock | 7 +++++++ bench-cargo-miri/slice-get-unchecked/Cargo.toml | 8 ++++++++ bench-cargo-miri/slice-get-unchecked/src/main.rs | 12 ++++++++++++ 3 files changed, 27 insertions(+) create mode 100644 bench-cargo-miri/slice-get-unchecked/Cargo.lock create mode 100644 bench-cargo-miri/slice-get-unchecked/Cargo.toml create mode 100644 bench-cargo-miri/slice-get-unchecked/src/main.rs diff --git a/bench-cargo-miri/slice-get-unchecked/Cargo.lock b/bench-cargo-miri/slice-get-unchecked/Cargo.lock new file mode 100644 index 0000000000000..a375afaed3098 --- /dev/null +++ b/bench-cargo-miri/slice-get-unchecked/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "slice-get-unchecked" +version = "0.1.0" diff --git a/bench-cargo-miri/slice-get-unchecked/Cargo.toml b/bench-cargo-miri/slice-get-unchecked/Cargo.toml new file mode 100644 index 0000000000000..1ac2276866ff7 --- /dev/null +++ b/bench-cargo-miri/slice-get-unchecked/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "slice-get-unchecked" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/bench-cargo-miri/slice-get-unchecked/src/main.rs b/bench-cargo-miri/slice-get-unchecked/src/main.rs new file mode 100644 index 0000000000000..a72083bd9de31 --- /dev/null +++ b/bench-cargo-miri/slice-get-unchecked/src/main.rs @@ -0,0 +1,12 @@ +//! This is a stripped-down version of the code pattern that causes runtime blowup when printing +//! backtraces in a failed test under cargo miri test with -Zmiri-disable-isolation. +//! See https://github.com/rust-lang/miri/issues/2273 + +fn main() { + let x = vec![0u8; 4096]; + let mut i = 0; + while i < x.len() { + let _element = unsafe { *x.get_unchecked(i) }; + i += 1; + } +} From 837bf8427165d6e56783a97a57061416d1ac2fec Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 13 Jul 2022 13:09:23 +0000 Subject: [PATCH 3470/3747] Error patterns can be regexes --- .../deallocate_against_barrier1.rs | 2 +- .../deallocate_against_barrier2.rs | 2 +- ui_test/README.md | 1 + ui_test/src/lib.rs | 24 ++++++------ ui_test/src/parser.rs | 39 ++++++++++++++++--- ui_test/src/parser/tests.rs | 29 +++++++++++--- 6 files changed, 73 insertions(+), 24 deletions(-) diff --git a/tests/fail/stacked_borrows/deallocate_against_barrier1.rs b/tests/fail/stacked_borrows/deallocate_against_barrier1.rs index 20e026df7b9b2..9b710424c55c4 100644 --- a/tests/fail/stacked_borrows/deallocate_against_barrier1.rs +++ b/tests/fail/stacked_borrows/deallocate_against_barrier1.rs @@ -1,4 +1,4 @@ -//@error-pattern: deallocating while item +//@error-pattern: /deallocating while item \[Unique for .*\] is protected/ fn inner(x: &mut i32, f: fn(&mut i32)) { // `f` may mutate, but it may not deallocate! diff --git a/tests/fail/stacked_borrows/deallocate_against_barrier2.rs b/tests/fail/stacked_borrows/deallocate_against_barrier2.rs index 9cb2d52bf2e9a..36e133e383650 100644 --- a/tests/fail/stacked_borrows/deallocate_against_barrier2.rs +++ b/tests/fail/stacked_borrows/deallocate_against_barrier2.rs @@ -1,4 +1,4 @@ -//@error-pattern: deallocating while item +//@error-pattern: /deallocating while item \[SharedReadWrite for .*\] is protected/ use std::marker::PhantomPinned; pub struct NotUnpin(i32, PhantomPinned); diff --git a/ui_test/README.md b/ui_test/README.md index 24c5940382d13..55639c9589e10 100644 --- a/ui_test/README.md +++ b/ui_test/README.md @@ -17,6 +17,7 @@ to make sure that the test will always keep failing with a specific message at t * If the all caps note is left out, a message of any level is matched. Leaving it out is not allowed for `ERROR` levels. * This checks the output *before* normalization, so you can check things that get normalized away, but need to be careful not to accidentally have a pattern that differs between platforms. +* if `XXX` is of the form `/XXX/` it is treated as a regex instead of a substring and will succeed if the regex matches. In order to change how a single test is tested, you can add various `//@` comments to the test. Any other comments will be ignored, and all `//@` comments must be formatted precisely as diff --git a/ui_test/src/lib.rs b/ui_test/src/lib.rs index b2e71b762beae..32c04290bca20 100644 --- a/ui_test/src/lib.rs +++ b/ui_test/src/lib.rs @@ -10,7 +10,7 @@ use std::sync::Mutex; pub use color_eyre; use color_eyre::eyre::Result; use colored::*; -use parser::ErrorMatch; +use parser::{ErrorMatch, Pattern}; use regex::Regex; use rustc_stderr::{Level, Message}; @@ -177,7 +177,12 @@ pub fn run_tests(config: Config) -> Result<()> { match error { Error::ExitStatus(mode, exit_status) => eprintln!("{mode:?} got {exit_status}"), Error::PatternNotFound { pattern, definition_line } => { - eprintln!("`{pattern}` {} in stderr output", "not found".red()); + match pattern { + Pattern::SubString(s) => + eprintln!("substring `{s}` {} in stderr output", "not found".red()), + Pattern::Regex(r) => + eprintln!("`/{r}/` does {} stderr output", "not match".red()), + } eprintln!( "expected because of pattern here: {}:{definition_line}", path.display().to_string().bold() @@ -257,7 +262,7 @@ enum Error { /// Got an invalid exit status for the given mode. ExitStatus(Mode, ExitStatus), PatternNotFound { - pattern: String, + pattern: Pattern, definition_line: usize, }, /// A ui test checking for failure does not have any failure patterns @@ -384,14 +389,11 @@ fn check_annotations( // in the messages. if let Some(i) = messages_from_unknown_file_or_line .iter() - .position(|msg| msg.message.contains(error_pattern)) + .position(|msg| error_pattern.matches(&msg.message)) { messages_from_unknown_file_or_line.remove(i); } else { - errors.push(Error::PatternNotFound { - pattern: error_pattern.to_string(), - definition_line, - }); + errors.push(Error::PatternNotFound { pattern: error_pattern.clone(), definition_line }); } } @@ -399,7 +401,7 @@ fn check_annotations( // We will ensure that *all* diagnostics of level at least `lowest_annotation_level` // are matched. let mut lowest_annotation_level = Level::Error; - for &ErrorMatch { ref matched, revision: ref rev, definition_line, line, level } in + for &ErrorMatch { ref pattern, revision: ref rev, definition_line, line, level } in &comments.error_matches { if let Some(rev) = rev { @@ -415,14 +417,14 @@ fn check_annotations( if let Some(msgs) = messages.get_mut(line) { let found = - msgs.iter().position(|msg| msg.message.contains(matched) && msg.level == level); + msgs.iter().position(|msg| pattern.matches(&msg.message) && msg.level == level); if let Some(found) = found { msgs.remove(found); continue; } } - errors.push(Error::PatternNotFound { pattern: matched.to_string(), definition_line }); + errors.push(Error::PatternNotFound { pattern: pattern.clone(), definition_line }); } let filter = |msgs: Vec| -> Vec<_> { diff --git a/ui_test/src/parser.rs b/ui_test/src/parser.rs index 5b666eef66efb..7d810a95e4122 100644 --- a/ui_test/src/parser.rs +++ b/ui_test/src/parser.rs @@ -29,7 +29,7 @@ pub(crate) struct Comments { /// Normalizations to apply to the stderr output before emitting it to disk pub normalize_stderr: Vec<(Regex, String)>, /// An arbitrary pattern to look for in the stderr. - pub error_pattern: Option<(String, usize)>, + pub error_pattern: Option<(Pattern, usize)>, pub error_matches: Vec, /// Ignore diagnostics below this level. /// `None` means pick the lowest level from the `error_pattern`s. @@ -45,9 +45,15 @@ pub(crate) enum Condition { Bitwidth(u8), } +#[derive(Debug, Clone)] +pub(crate) enum Pattern { + SubString(String), + Regex(Regex), +} + #[derive(Debug)] pub(crate) struct ErrorMatch { - pub matched: String, + pub pattern: Pattern, pub revision: Option, pub level: Level, /// The line where the message was defined, for reporting issues with it (e.g. in case it wasn't found). @@ -184,7 +190,7 @@ impl Comments { "cannot specifiy error_pattern twice, previous: {:?}", self.error_pattern ); - self.error_pattern = Some((args.trim().to_string(), l)); + self.error_pattern = Some((Pattern::parse(args.trim())?, l)); } "stderr-per-bitwidth" => { // args are ignored (can be used as comment) @@ -275,14 +281,16 @@ impl Comments { let pattern = &pattern[offset..]; let pattern = pattern.strip_prefix(':').ok_or_else(|| eyre!("no `:` after level found"))?; - let matched = pattern.trim().to_string(); + let pattern = pattern.trim(); + + ensure!(!pattern.is_empty(), "no pattern specified"); - ensure!(!matched.is_empty(), "no pattern specified"); + let pattern = Pattern::parse(pattern)?; *fallthrough_to = Some(match_line); self.error_matches.push(ErrorMatch { - matched, + pattern, revision, level, definition_line: l, @@ -292,3 +300,22 @@ impl Comments { Ok(()) } } + +impl Pattern { + pub(crate) fn matches(&self, message: &str) -> bool { + match self { + Pattern::SubString(s) => message.contains(s), + Pattern::Regex(r) => r.is_match(message), + } + } + + pub(crate) fn parse(pattern: &str) -> Result { + if let Some(pattern) = pattern.strip_prefix('/') { + let regex = + pattern.strip_suffix('/').ok_or_else(|| eyre!("regex must end with `/`"))?; + Ok(Pattern::Regex(Regex::new(regex)?)) + } else { + Ok(Pattern::SubString(pattern.to_string())) + } + } +} diff --git a/ui_test/src/parser/tests.rs b/ui_test/src/parser/tests.rs index f41c2f234ab86..343857d44bd35 100644 --- a/ui_test/src/parser/tests.rs +++ b/ui_test/src/parser/tests.rs @@ -1,5 +1,7 @@ use std::path::Path; +use crate::parser::Pattern; + use super::Comments; #[test] @@ -15,10 +17,11 @@ fn main() { println!("parsed comments: {:#?}", comments); assert_eq!(comments.error_matches[0].definition_line, 5); assert_eq!(comments.error_matches[0].revision, None); - assert_eq!( - comments.error_matches[0].matched, - "encountered a dangling reference (address $HEX is unallocated)" - ); + match &comments.error_matches[0].pattern { + Pattern::SubString(s) => + assert_eq!(s, "encountered a dangling reference (address $HEX is unallocated)"), + other => panic!("expected substring, got {other:?}"), + } } #[test] @@ -42,7 +45,23 @@ use std::mem; "; let comments = Comments::parse(Path::new(""), s).unwrap(); println!("parsed comments: {:#?}", comments); - assert_eq!(comments.error_pattern, Some(("foomp".to_string(), 2))); + let pat = comments.error_pattern.unwrap(); + assert_eq!(format!("{:?}", pat.0), r#"SubString("foomp")"#); + assert_eq!(pat.1, 2); +} + +#[test] +fn parse_regex_error_pattern() { + let s = r" +//@ error-pattern: /foomp/ +use std::mem; + + "; + let comments = Comments::parse(Path::new(""), s).unwrap(); + println!("parsed comments: {:#?}", comments); + let pat = comments.error_pattern.unwrap(); + assert_eq!(format!("{:?}", pat.0), r#"Regex(foomp)"#); + assert_eq!(pat.1, 2); } #[test] From 3bd0e8a2cac5b6141261b11c0d8b12e94ca908d3 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 4 Jul 2022 14:53:54 -0400 Subject: [PATCH 3471/3747] move checking ptr tracking on item pop into cold helper function --- src/stacked_borrows.rs | 101 +++++++++++++++++++++++++---------------- 1 file changed, 62 insertions(+), 39 deletions(-) diff --git a/src/stacked_borrows.rs b/src/stacked_borrows.rs index 4cae27ecd2192..d9ccc773a0181 100644 --- a/src/stacked_borrows.rs +++ b/src/stacked_borrows.rs @@ -316,11 +316,22 @@ impl<'tcx> Stack { alloc_history: &mut AllocHistory, threads: &ThreadManager<'_, 'tcx>, ) -> InterpResult<'tcx> { - if global.tracked_pointer_tags.contains(&item.tag()) { - register_diagnostic(NonHaltingDiagnostic::PoppedPointerTag( - *item, - provoking_access.map(|(tag, _alloc_range, _size, access)| (tag, access)), - )); + if !global.tracked_pointer_tags.is_empty() { + check_tracked(item, &provoking_access, global); + + #[inline(never)] // cold path + fn check_tracked( + item: &Item, + provoking_access: &Option<(SbTagExtra, AllocRange, Size, AccessKind)>, + global: &GlobalStateInner, + ) { + if global.tracked_pointer_tags.contains(&item.tag()) { + register_diagnostic(NonHaltingDiagnostic::PoppedPointerTag( + *item, + provoking_access.map(|(tag, _alloc_range, _size, access)| (tag, access)), + )); + } + } } if !item.protected() { @@ -341,40 +352,52 @@ impl<'tcx> Stack { // which ends up about linear in the number of protected tags in the program into a // constant time check (and a slow linear, because the tags in the frames aren't contiguous). if global.protected_tags.contains(&item.tag()) { - // This path is cold because it is fatal to the program. So here it is fine to do the - // more expensive search to figure out which call is responsible for protecting this - // tag. - let call_id = threads - .all_stacks() - .flatten() - .map(|frame| { - frame - .extra - .stacked_borrows - .as_ref() - .expect("we should have Stacked Borrows data") - }) - .find(|frame| frame.protected_tags.contains(&item.tag())) - .map(|frame| frame.call_id) - .unwrap(); // FIXME: Surely we should find something, but a panic seems wrong here? - if let Some((tag, _alloc_range, _offset, _access)) = provoking_access { - Err(err_sb_ub( - format!( - "not granting access to tag {:?} because incompatible item {:?} is protected by call {:?}", - tag, item, call_id - ), - None, - tag.and_then(|tag| alloc_history.get_logs_relevant_to(tag, Some(item.tag()))), - ))? - } else { - Err(err_sb_ub( - format!( - "deallocating while item {:?} is protected by call {:?}", - item, call_id - ), - None, - None, - ))? + return Err(protector_error(item, &provoking_access, alloc_history, threads)); + + #[inline(never)] // cold path + fn protector_error<'tcx>( + item: &Item, + provoking_access: &Option<(SbTagExtra, AllocRange, Size, AccessKind)>, + alloc_history: &mut AllocHistory, + threads: &ThreadManager<'_, 'tcx>, + ) -> InterpErrorInfo<'tcx> { + // This path is cold because it is fatal to the program. So here it is fine to do the + // more expensive search to figure out which call is responsible for protecting this + // tag. + let call_id = threads + .all_stacks() + .flatten() + .map(|frame| { + frame + .extra + .stacked_borrows + .as_ref() + .expect("we should have Stacked Borrows data") + }) + .find(|frame| frame.protected_tags.contains(&item.tag())) + .map(|frame| frame.call_id) + .unwrap(); // FIXME: Surely we should find something, but a panic seems wrong here? + if let Some((tag, _alloc_range, _offset, _access)) = provoking_access { + err_sb_ub( + format!( + "not granting access to tag {:?} because incompatible item {:?} is protected by call {:?}", + tag, item, call_id + ), + None, + tag.and_then(|tag| { + alloc_history.get_logs_relevant_to(tag, Some(item.tag())) + }), + ) + } else { + err_sb_ub( + format!( + "deallocating while item {:?} is protected by call {:?}", + item, call_id + ), + None, + None, + ) + }.into() } } Ok(()) From 757e88c901f7b8fed41829729b6a23317be12b3e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 13 Jul 2022 18:59:33 -0400 Subject: [PATCH 3472/3747] use ui_test regex capabilities --- tests/fail/alloc/global_system_mixup.rs | 2 +- tests/fail/alloc/stack_free.rs | 2 +- tests/fail/provenance/ptr_int_unexposed.rs | 2 +- tests/fail/stacked_borrows/alias_through_mutation.rs | 2 +- tests/fail/stacked_borrows/box_exclusive_violation1.rs | 6 +++--- tests/fail/stacked_borrows/box_exclusive_violation1.stderr | 4 ++-- tests/fail/stacked_borrows/buggy_as_mut_slice.rs | 2 +- tests/fail/stacked_borrows/buggy_split_at_mut.rs | 2 +- tests/fail/stacked_borrows/exposed_only_ro.rs | 2 +- tests/fail/stacked_borrows/illegal_read1.rs | 2 +- tests/fail/stacked_borrows/illegal_read2.rs | 2 +- tests/fail/stacked_borrows/illegal_read3.rs | 2 +- tests/fail/stacked_borrows/illegal_read4.rs | 2 +- tests/fail/stacked_borrows/illegal_read5.rs | 2 +- tests/fail/stacked_borrows/illegal_read6.rs | 2 +- tests/fail/stacked_borrows/illegal_read7.rs | 2 +- tests/fail/stacked_borrows/illegal_read8.rs | 2 +- tests/fail/stacked_borrows/illegal_read_despite_exposed1.rs | 2 +- tests/fail/stacked_borrows/illegal_read_despite_exposed2.rs | 2 +- tests/fail/stacked_borrows/illegal_write1.rs | 2 +- tests/fail/stacked_borrows/illegal_write2.rs | 2 +- tests/fail/stacked_borrows/illegal_write3.rs | 2 +- tests/fail/stacked_borrows/illegal_write4.rs | 2 +- tests/fail/stacked_borrows/illegal_write5.rs | 2 +- tests/fail/stacked_borrows/illegal_write6.rs | 2 +- .../fail/stacked_borrows/illegal_write_despite_exposed1.rs | 3 ++- tests/fail/stacked_borrows/interior_mut1.rs | 2 +- tests/fail/stacked_borrows/interior_mut2.rs | 2 +- tests/fail/stacked_borrows/load_invalid_mut.rs | 2 +- tests/fail/stacked_borrows/load_invalid_shr.rs | 2 +- tests/fail/stacked_borrows/mut_exclusive_violation1.rs | 2 +- tests/fail/stacked_borrows/mut_exclusive_violation2.rs | 2 +- tests/fail/stacked_borrows/outdated_local.rs | 2 +- tests/fail/stacked_borrows/pass_invalid_mut.rs | 2 +- tests/fail/stacked_borrows/pass_invalid_shr.rs | 2 +- tests/fail/stacked_borrows/pointer_smuggling.rs | 2 +- tests/fail/stacked_borrows/raw_tracking.rs | 2 +- tests/fail/stacked_borrows/return_invalid_mut.rs | 2 +- tests/fail/stacked_borrows/return_invalid_mut_option.rs | 2 +- tests/fail/stacked_borrows/return_invalid_mut_tuple.rs | 2 +- tests/fail/stacked_borrows/return_invalid_shr.rs | 2 +- tests/fail/stacked_borrows/return_invalid_shr_option.rs | 2 +- tests/fail/stacked_borrows/return_invalid_shr_tuple.rs | 2 +- tests/fail/stacked_borrows/shared_rw_borrows_are_weak1.rs | 2 +- tests/fail/stacked_borrows/shared_rw_borrows_are_weak2.rs | 2 +- tests/fail/stacked_borrows/shr_frozen_violation1.rs | 2 +- tests/fail/stacked_borrows/transmute-is-no-escape.rs | 2 +- tests/fail/stacked_borrows/unescaped_local.rs | 2 +- tests/fail/stacked_borrows/unescaped_static.rs | 2 +- tests/fail/stacked_borrows/zst_slice.rs | 2 +- 50 files changed, 54 insertions(+), 53 deletions(-) diff --git a/tests/fail/alloc/global_system_mixup.rs b/tests/fail/alloc/global_system_mixup.rs index 01db2f1a225df..47b098c71a2bf 100644 --- a/tests/fail/alloc/global_system_mixup.rs +++ b/tests/fail/alloc/global_system_mixup.rs @@ -1,6 +1,6 @@ // Make sure we detect when the `Global` and `System` allocators are mixed // (even when the default `Global` uses `System`). -//@error-pattern: which is Rust heap memory, using +//@error-pattern: /deallocating .*, which is Rust heap memory, using .* heap deallocation operation/ //@normalize-stderr-test: "using [A-Za-z]+ heap deallocation operation" -> "using PLATFORM heap deallocation operation" //@normalize-stderr-test: "\| +\^+" -> "| ^" diff --git a/tests/fail/alloc/stack_free.rs b/tests/fail/alloc/stack_free.rs index a97431bc2f05e..baf53decc4413 100644 --- a/tests/fail/alloc/stack_free.rs +++ b/tests/fail/alloc/stack_free.rs @@ -1,7 +1,7 @@ // Validation/SB changes why we fail //@compile-flags: -Zmiri-disable-validation -Zmiri-disable-stacked-borrows -//@error-pattern: which is stack variable memory, using Rust heap deallocation operation +//@error-pattern: /deallocating .*, which is stack variable memory, using Rust heap deallocation operation/ fn main() { let x = 42; diff --git a/tests/fail/provenance/ptr_int_unexposed.rs b/tests/fail/provenance/ptr_int_unexposed.rs index dd8d52b2d2e24..07de41d10a038 100644 --- a/tests/fail/provenance/ptr_int_unexposed.rs +++ b/tests/fail/provenance/ptr_int_unexposed.rs @@ -8,5 +8,5 @@ fn main() { let x_usize: usize = x_ptr.addr(); // Cast back an address that did *not* get exposed. let ptr = std::ptr::from_exposed_addr::(x_usize); - assert_eq!(unsafe { *ptr }, 3); //~ ERROR: Undefined Behavior: dereferencing pointer failed + assert_eq!(unsafe { *ptr }, 3); //~ ERROR: is a dangling pointer } diff --git a/tests/fail/stacked_borrows/alias_through_mutation.rs b/tests/fail/stacked_borrows/alias_through_mutation.rs index dfadeec6c9e91..73095bb2fc94b 100644 --- a/tests/fail/stacked_borrows/alias_through_mutation.rs +++ b/tests/fail/stacked_borrows/alias_through_mutation.rs @@ -11,5 +11,5 @@ fn main() { retarget(&mut target_alias, target); // now `target_alias` points to the same thing as `target` *target = 13; - let _val = *target_alias; //~ ERROR: borrow stack + let _val = *target_alias; //~ ERROR: /read access .* tag does not exist in the borrow stack/ } diff --git a/tests/fail/stacked_borrows/box_exclusive_violation1.rs b/tests/fail/stacked_borrows/box_exclusive_violation1.rs index ce7ff8f9e2aad..87a6b7bbd67ec 100644 --- a/tests/fail/stacked_borrows/box_exclusive_violation1.rs +++ b/tests/fail/stacked_borrows/box_exclusive_violation1.rs @@ -1,4 +1,4 @@ -fn demo_mut_advanced_unique(mut our: Box) -> i32 { +fn demo_box_advanced_unique(mut our: Box) -> i32 { unknown_code_1(&*our); // This "re-asserts" uniqueness of the reference: After writing, we know @@ -24,10 +24,10 @@ fn unknown_code_1(x: &i32) { fn unknown_code_2() { unsafe { - *LEAK = 7; //~ ERROR: borrow stack + *LEAK = 7; //~ ERROR: /write access .* tag does not exist in the borrow stack/ } } fn main() { - demo_mut_advanced_unique(Box::new(0)); + demo_box_advanced_unique(Box::new(0)); } diff --git a/tests/fail/stacked_borrows/box_exclusive_violation1.stderr b/tests/fail/stacked_borrows/box_exclusive_violation1.stderr index 88ecca87962d5..7214ef27be33c 100644 --- a/tests/fail/stacked_borrows/box_exclusive_violation1.stderr +++ b/tests/fail/stacked_borrows/box_exclusive_violation1.stderr @@ -21,7 +21,7 @@ LL | *our = 5; | ^^^^^^^^ = note: backtrace: = note: inside `unknown_code_2` at $DIR/box_exclusive_violation1.rs:LL:CC -note: inside `demo_mut_advanced_unique` at $DIR/box_exclusive_violation1.rs:LL:CC +note: inside `demo_box_advanced_unique` at $DIR/box_exclusive_violation1.rs:LL:CC --> $DIR/box_exclusive_violation1.rs:LL:CC | LL | unknown_code_2(); @@ -29,7 +29,7 @@ LL | unknown_code_2(); note: inside `main` at $DIR/box_exclusive_violation1.rs:LL:CC --> $DIR/box_exclusive_violation1.rs:LL:CC | -LL | demo_mut_advanced_unique(Box::new(0)); +LL | demo_box_advanced_unique(Box::new(0)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/buggy_as_mut_slice.rs b/tests/fail/stacked_borrows/buggy_as_mut_slice.rs index 5eeec933c7c86..8615a9a58ad96 100644 --- a/tests/fail/stacked_borrows/buggy_as_mut_slice.rs +++ b/tests/fail/stacked_borrows/buggy_as_mut_slice.rs @@ -11,5 +11,5 @@ fn main() { let v1 = safe::as_mut_slice(&v); let _v2 = safe::as_mut_slice(&v); v1[1] = 5; - //~^ ERROR: borrow stack + //~^ ERROR: /write access .* tag does not exist in the borrow stack/ } diff --git a/tests/fail/stacked_borrows/buggy_split_at_mut.rs b/tests/fail/stacked_borrows/buggy_split_at_mut.rs index 92380a4bf4967..db64d559c517c 100644 --- a/tests/fail/stacked_borrows/buggy_split_at_mut.rs +++ b/tests/fail/stacked_borrows/buggy_split_at_mut.rs @@ -19,7 +19,7 @@ mod safe { fn main() { let mut array = [1, 2, 3, 4]; let (a, b) = safe::split_at_mut(&mut array, 0); - //~^ ERROR: borrow stack + //~^ ERROR: /reborrow .* tag does not exist in the borrow stack/ a[1] = 5; b[1] = 6; } diff --git a/tests/fail/stacked_borrows/exposed_only_ro.rs b/tests/fail/stacked_borrows/exposed_only_ro.rs index f2fdc213b1430..0b4fb0ccd33bd 100644 --- a/tests/fail/stacked_borrows/exposed_only_ro.rs +++ b/tests/fail/stacked_borrows/exposed_only_ro.rs @@ -8,5 +8,5 @@ fn main() { let _fool = &mut x as *mut i32; // this would have fooled the old untagged pointer logic let addr = (&x as *const i32).expose_addr(); let ptr = std::ptr::from_exposed_addr_mut::(addr); - unsafe { *ptr = 0 }; //~ ERROR: borrow stack + unsafe { *ptr = 0 }; //~ ERROR: /write access using .* no exposed tags have suitable permission in the borrow stack/ } diff --git a/tests/fail/stacked_borrows/illegal_read1.rs b/tests/fail/stacked_borrows/illegal_read1.rs index b5734964060ef..1dea282739ce1 100644 --- a/tests/fail/stacked_borrows/illegal_read1.rs +++ b/tests/fail/stacked_borrows/illegal_read1.rs @@ -8,7 +8,7 @@ fn main() { let xref = unsafe { &mut *xraw }; // derived from raw, so using raw is still ok... callee(xraw); let _val = *xref; // ...but any use of raw will invalidate our ref. - //~^ ERROR: borrow stack + //~^ ERROR: /read access .* tag does not exist in the borrow stack/ } fn callee(xraw: *mut i32) { diff --git a/tests/fail/stacked_borrows/illegal_read2.rs b/tests/fail/stacked_borrows/illegal_read2.rs index ed6972c1deb93..b765b4d9ce99d 100644 --- a/tests/fail/stacked_borrows/illegal_read2.rs +++ b/tests/fail/stacked_borrows/illegal_read2.rs @@ -8,7 +8,7 @@ fn main() { let xref = unsafe { &mut *xraw }; // derived from raw, so using raw is still ok... callee(xraw); let _val = *xref; // ...but any use of raw will invalidate our ref. - //~^ ERROR: borrow stack + //~^ ERROR: /read access .* tag does not exist in the borrow stack/ } fn callee(xraw: *mut i32) { diff --git a/tests/fail/stacked_borrows/illegal_read3.rs b/tests/fail/stacked_borrows/illegal_read3.rs index 0173ca14b22da..43ea0a0e84da5 100644 --- a/tests/fail/stacked_borrows/illegal_read3.rs +++ b/tests/fail/stacked_borrows/illegal_read3.rs @@ -18,7 +18,7 @@ fn main() { callee(xref1_sneaky); // ... though any use of it will invalidate our ref. let _val = *xref2; - //~^ ERROR: borrow stack + //~^ ERROR: /read access .* tag does not exist in the borrow stack/ } fn callee(xref1: HiddenRef) { diff --git a/tests/fail/stacked_borrows/illegal_read4.rs b/tests/fail/stacked_borrows/illegal_read4.rs index 2d4e395a42703..a9ecb88d3520b 100644 --- a/tests/fail/stacked_borrows/illegal_read4.rs +++ b/tests/fail/stacked_borrows/illegal_read4.rs @@ -5,5 +5,5 @@ fn main() { let xraw = xref1 as *mut _; let xref2 = unsafe { &mut *xraw }; let _val = unsafe { *xraw }; // use the raw again, this invalidates xref2 *even* with the special read except for uniq refs - let _illegal = *xref2; //~ ERROR: borrow stack + let _illegal = *xref2; //~ ERROR: /read access .* tag does not exist in the borrow stack/ } diff --git a/tests/fail/stacked_borrows/illegal_read5.rs b/tests/fail/stacked_borrows/illegal_read5.rs index 49556e618d27b..228c15f72e173 100644 --- a/tests/fail/stacked_borrows/illegal_read5.rs +++ b/tests/fail/stacked_borrows/illegal_read5.rs @@ -14,5 +14,5 @@ fn main() { let _val = *xref; // we can even still use our mutable reference mem::forget(unsafe { ptr::read(xshr) }); // but after reading through the shared ref let _val = *xref; // the mutable one is dead and gone - //~^ ERROR: borrow stack + //~^ ERROR: /read access .* tag does not exist in the borrow stack/ } diff --git a/tests/fail/stacked_borrows/illegal_read6.rs b/tests/fail/stacked_borrows/illegal_read6.rs index 943a61af4f6ef..4af22580ab64f 100644 --- a/tests/fail/stacked_borrows/illegal_read6.rs +++ b/tests/fail/stacked_borrows/illegal_read6.rs @@ -5,6 +5,6 @@ fn main() { let raw = x as *mut _; let x = &mut *x; // kill `raw` let _y = &*x; // this should not activate `raw` again - let _val = *raw; //~ ERROR: borrow stack + let _val = *raw; //~ ERROR: /read access .* tag does not exist in the borrow stack/ } } diff --git a/tests/fail/stacked_borrows/illegal_read7.rs b/tests/fail/stacked_borrows/illegal_read7.rs index e263e8b70a91d..c0d3816f4475b 100644 --- a/tests/fail/stacked_borrows/illegal_read7.rs +++ b/tests/fail/stacked_borrows/illegal_read7.rs @@ -17,6 +17,6 @@ fn main() { // without invalidating `x`. That would be bad! It would mean that creating `shr` // leaked `x` to `raw`. let _val = ptr::read(raw); - let _val = *x.get_mut(); //~ ERROR: borrow stack + let _val = *x.get_mut(); //~ ERROR: /reborrow .* tag does not exist in the borrow stack/ } } diff --git a/tests/fail/stacked_borrows/illegal_read8.rs b/tests/fail/stacked_borrows/illegal_read8.rs index 13c12cc75d77b..f0a1658a5a23a 100644 --- a/tests/fail/stacked_borrows/illegal_read8.rs +++ b/tests/fail/stacked_borrows/illegal_read8.rs @@ -10,6 +10,6 @@ fn main() { let _val = *y2; let _val = *y1; *y2 += 1; - let _fail = *y1; //~ ERROR: borrow stack + let _fail = *y1; //~ ERROR: /read access .* tag does not exist in the borrow stack/ } } diff --git a/tests/fail/stacked_borrows/illegal_read_despite_exposed1.rs b/tests/fail/stacked_borrows/illegal_read_despite_exposed1.rs index d779d4e446571..76516b7d924be 100644 --- a/tests/fail/stacked_borrows/illegal_read_despite_exposed1.rs +++ b/tests/fail/stacked_borrows/illegal_read_despite_exposed1.rs @@ -12,6 +12,6 @@ fn main() { // And we test that it has uniqueness by doing a conflicting write. *exposed_ptr = 0; // Stack: Unknown( u32 { *a = 1; let _b = &*a; - unsafe { *y = 2 }; //~ ERROR: not granting access to tag + unsafe { *y = 2 }; //~ ERROR: /not granting access .* because incompatible item .* is protected/ return *a; } diff --git a/tests/fail/stacked_borrows/illegal_write_despite_exposed1.rs b/tests/fail/stacked_borrows/illegal_write_despite_exposed1.rs index f14fcb14793ce..0e34c5c98fc1f 100644 --- a/tests/fail/stacked_borrows/illegal_write_despite_exposed1.rs +++ b/tests/fail/stacked_borrows/illegal_write_despite_exposed1.rs @@ -9,8 +9,9 @@ fn main() { let root2 = &*exposed_ptr; // Stack: Unknown( &mut i32 { let xraw = x as *mut (i32, i32); let ret = unsafe { &mut (*xraw).1 }; let _val = unsafe { *xraw }; // invalidate xref - ret //~ ERROR: borrow stack + ret //~ ERROR: /reborrow .* tag does not exist in the borrow stack/ } fn main() { diff --git a/tests/fail/stacked_borrows/return_invalid_mut_option.rs b/tests/fail/stacked_borrows/return_invalid_mut_option.rs index 931b420166e7d..da3401260e1e9 100644 --- a/tests/fail/stacked_borrows/return_invalid_mut_option.rs +++ b/tests/fail/stacked_borrows/return_invalid_mut_option.rs @@ -10,7 +10,7 @@ fn foo(x: &mut (i32, i32)) -> Option<&mut i32> { fn main() { match foo(&mut (1, 2)) { - Some(_x) => {} //~ ERROR: borrow stack + Some(_x) => {} //~ ERROR: /reborrow .* tag does not exist in the borrow stack/ None => {} } } diff --git a/tests/fail/stacked_borrows/return_invalid_mut_tuple.rs b/tests/fail/stacked_borrows/return_invalid_mut_tuple.rs index fbd9a6e5d2692..2184d20b1cfaf 100644 --- a/tests/fail/stacked_borrows/return_invalid_mut_tuple.rs +++ b/tests/fail/stacked_borrows/return_invalid_mut_tuple.rs @@ -8,5 +8,5 @@ fn foo(x: &mut (i32, i32)) -> (&mut i32,) { } fn main() { - foo(&mut (1, 2)).0; //~ ERROR: borrow stack + foo(&mut (1, 2)).0; //~ ERROR: /reborrow .* tag does not exist in the borrow stack/ } diff --git a/tests/fail/stacked_borrows/return_invalid_shr.rs b/tests/fail/stacked_borrows/return_invalid_shr.rs index a595b91c834c8..b1d16c025ebf0 100644 --- a/tests/fail/stacked_borrows/return_invalid_shr.rs +++ b/tests/fail/stacked_borrows/return_invalid_shr.rs @@ -3,7 +3,7 @@ fn foo(x: &mut (i32, i32)) -> &i32 { let xraw = x as *mut (i32, i32); let ret = unsafe { &(*xraw).1 }; unsafe { *xraw = (42, 23) }; // unfreeze - ret //~ ERROR: borrow stack + ret //~ ERROR: /reborrow .* tag does not exist in the borrow stack/ } fn main() { diff --git a/tests/fail/stacked_borrows/return_invalid_shr_option.rs b/tests/fail/stacked_borrows/return_invalid_shr_option.rs index 56af567f6e8f5..e9faa945206eb 100644 --- a/tests/fail/stacked_borrows/return_invalid_shr_option.rs +++ b/tests/fail/stacked_borrows/return_invalid_shr_option.rs @@ -9,7 +9,7 @@ fn foo(x: &mut (i32, i32)) -> Option<&i32> { fn main() { match foo(&mut (1, 2)) { - Some(_x) => {} //~ ERROR: borrow stack + Some(_x) => {} //~ ERROR: /reborrow .* tag does not exist in the borrow stack/ None => {} } } diff --git a/tests/fail/stacked_borrows/return_invalid_shr_tuple.rs b/tests/fail/stacked_borrows/return_invalid_shr_tuple.rs index 38f01d7cc20b3..11eb4de56c9fc 100644 --- a/tests/fail/stacked_borrows/return_invalid_shr_tuple.rs +++ b/tests/fail/stacked_borrows/return_invalid_shr_tuple.rs @@ -8,5 +8,5 @@ fn foo(x: &mut (i32, i32)) -> (&i32,) { } fn main() { - foo(&mut (1, 2)).0; //~ ERROR: borrow stack + foo(&mut (1, 2)).0; //~ ERROR: /reborrow .* tag does not exist in the borrow stack/ } diff --git a/tests/fail/stacked_borrows/shared_rw_borrows_are_weak1.rs b/tests/fail/stacked_borrows/shared_rw_borrows_are_weak1.rs index 91994d286b95c..01b2775d9d363 100644 --- a/tests/fail/stacked_borrows/shared_rw_borrows_are_weak1.rs +++ b/tests/fail/stacked_borrows/shared_rw_borrows_are_weak1.rs @@ -11,6 +11,6 @@ fn main() { let y: &mut Cell = mem::transmute(&mut *x); // launder lifetime let shr_rw = &*x; // thanks to interior mutability this will be a SharedReadWrite shr_rw.set(1); - y.get_mut(); //~ ERROR: borrow stack + y.get_mut(); //~ ERROR: /reborrow .* tag does not exist in the borrow stack/ } } diff --git a/tests/fail/stacked_borrows/shared_rw_borrows_are_weak2.rs b/tests/fail/stacked_borrows/shared_rw_borrows_are_weak2.rs index ee44ebbb07185..012e9561ca848 100644 --- a/tests/fail/stacked_borrows/shared_rw_borrows_are_weak2.rs +++ b/tests/fail/stacked_borrows/shared_rw_borrows_are_weak2.rs @@ -12,6 +12,6 @@ fn main() { let y: &i32 = mem::transmute(&*x.borrow()); // launder lifetime let shr_rw = &*x; // thanks to interior mutability this will be a SharedReadWrite shr_rw.replace(1); - let _val = *y; //~ ERROR: borrow stack + let _val = *y; //~ ERROR: /read access .* tag does not exist in the borrow stack/ } } diff --git a/tests/fail/stacked_borrows/shr_frozen_violation1.rs b/tests/fail/stacked_borrows/shr_frozen_violation1.rs index 11082da6ea3ab..d1322dc6e57bb 100644 --- a/tests/fail/stacked_borrows/shr_frozen_violation1.rs +++ b/tests/fail/stacked_borrows/shr_frozen_violation1.rs @@ -10,6 +10,6 @@ fn main() { fn unknown_code(x: &i32) { unsafe { - *(x as *const i32 as *mut i32) = 7; //~ ERROR: only grants SharedReadOnly permission + *(x as *const i32 as *mut i32) = 7; //~ ERROR: /write access .* only grants SharedReadOnly permission/ } } diff --git a/tests/fail/stacked_borrows/transmute-is-no-escape.rs b/tests/fail/stacked_borrows/transmute-is-no-escape.rs index c7d6090232016..233b927dfc7ee 100644 --- a/tests/fail/stacked_borrows/transmute-is-no-escape.rs +++ b/tests/fail/stacked_borrows/transmute-is-no-escape.rs @@ -10,5 +10,5 @@ fn main() { let _raw: *mut i32 = unsafe { mem::transmute(&mut x[0]) }; // `raw` still carries a tag, so we get another pointer to the same location that does not carry a tag let raw = (&mut x[1] as *mut i32).wrapping_offset(-1); - unsafe { *raw = 13 }; //~ ERROR: borrow stack + unsafe { *raw = 13 }; //~ ERROR: /write access .* tag does not exist in the borrow stack/ } diff --git a/tests/fail/stacked_borrows/unescaped_local.rs b/tests/fail/stacked_borrows/unescaped_local.rs index 5b808472b4e63..49c0e66d85701 100644 --- a/tests/fail/stacked_borrows/unescaped_local.rs +++ b/tests/fail/stacked_borrows/unescaped_local.rs @@ -7,6 +7,6 @@ fn main() { let raw = &mut x as *mut i32 as usize as *mut i32; let _ptr = &mut x; unsafe { - *raw = 13; //~ ERROR: borrow stack + *raw = 13; //~ ERROR: /write access .* no exposed tags/ } } diff --git a/tests/fail/stacked_borrows/unescaped_static.rs b/tests/fail/stacked_borrows/unescaped_static.rs index 66641d648d86f..a25d9b5162ec8 100644 --- a/tests/fail/stacked_borrows/unescaped_static.rs +++ b/tests/fail/stacked_borrows/unescaped_static.rs @@ -3,5 +3,5 @@ static ARRAY: [u8; 2] = [0, 1]; fn main() { let ptr_to_first = &ARRAY[0] as *const u8; // Illegally use this to access the 2nd element. - let _val = unsafe { *ptr_to_first.add(1) }; //~ ERROR: borrow stack + let _val = unsafe { *ptr_to_first.add(1) }; //~ ERROR: /read access .* tag does not exist in the borrow stack/ } diff --git a/tests/fail/stacked_borrows/zst_slice.rs b/tests/fail/stacked_borrows/zst_slice.rs index 3e27f514bc888..11065186fc495 100644 --- a/tests/fail/stacked_borrows/zst_slice.rs +++ b/tests/fail/stacked_borrows/zst_slice.rs @@ -1,5 +1,5 @@ //@compile-flags: -Zmiri-strict-provenance -//@error-pattern: does not exist in the borrow stack +//@error-pattern: /reborrow .* tag does not exist in the borrow stack/ fn main() { unsafe { From 83b9172774a9894ee484e4eb693368282d8f0a32 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 13 Jul 2022 19:37:41 -0400 Subject: [PATCH 3473/3747] move stacked_borrows.rs together with the other files of its module --- src/{stacked_borrows.rs => stacked_borrows/mod.rs} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/{stacked_borrows.rs => stacked_borrows/mod.rs} (100%) diff --git a/src/stacked_borrows.rs b/src/stacked_borrows/mod.rs similarity index 100% rename from src/stacked_borrows.rs rename to src/stacked_borrows/mod.rs From cc42cb1b21c31af582ee109d7069224f91c9f278 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 13 Jul 2022 19:40:53 -0400 Subject: [PATCH 3474/3747] reborrow error: clarify that we are reborrowing *from* that tag --- src/stacked_borrows/diagnostics.rs | 2 +- tests/fail/box-cell-alias.stderr | 4 ++-- tests/fail/stacked_borrows/aliasing_mut3.stderr | 4 ++-- tests/fail/stacked_borrows/buggy_split_at_mut.stderr | 4 ++-- tests/fail/stacked_borrows/illegal_read7.stderr | 4 ++-- tests/fail/stacked_borrows/interior_mut1.stderr | 4 ++-- tests/fail/stacked_borrows/interior_mut2.stderr | 4 ++-- tests/fail/stacked_borrows/load_invalid_mut.stderr | 4 ++-- tests/fail/stacked_borrows/load_invalid_shr.stderr | 4 ++-- tests/fail/stacked_borrows/pass_invalid_mut.stderr | 4 ++-- tests/fail/stacked_borrows/pass_invalid_shr.stderr | 4 ++-- tests/fail/stacked_borrows/return_invalid_mut.stderr | 4 ++-- tests/fail/stacked_borrows/return_invalid_mut_option.stderr | 4 ++-- tests/fail/stacked_borrows/return_invalid_mut_tuple.stderr | 4 ++-- tests/fail/stacked_borrows/return_invalid_shr.stderr | 4 ++-- tests/fail/stacked_borrows/return_invalid_shr_option.stderr | 4 ++-- tests/fail/stacked_borrows/return_invalid_shr_tuple.stderr | 4 ++-- tests/fail/stacked_borrows/shared_rw_borrows_are_weak1.stderr | 4 ++-- tests/fail/stacked_borrows/zst_slice.stderr | 4 ++-- 19 files changed, 37 insertions(+), 37 deletions(-) diff --git a/src/stacked_borrows/diagnostics.rs b/src/stacked_borrows/diagnostics.rs index 1fa619a3ae4d4..133164f390dfb 100644 --- a/src/stacked_borrows/diagnostics.rs +++ b/src/stacked_borrows/diagnostics.rs @@ -140,7 +140,7 @@ impl AllocHistory { stack: &Stack, ) -> InterpError<'tcx> { let action = format!( - "trying to reborrow {derived_from:?} for {new_perm:?} permission at {alloc_id:?}[{offset:#x}]", + "trying to reborrow from {derived_from:?} for {new_perm:?} permission at {alloc_id:?}[{offset:#x}]", new_perm = new.perm(), offset = error_offset.bytes(), ); diff --git a/tests/fail/box-cell-alias.stderr b/tests/fail/box-cell-alias.stderr index c7fd1c6415e03..705348ba0f06d 100644 --- a/tests/fail/box-cell-alias.stderr +++ b/tests/fail/box-cell-alias.stderr @@ -1,10 +1,10 @@ -error: Undefined Behavior: trying to reborrow for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location +error: Undefined Behavior: trying to reborrow from for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location --> $DIR/box-cell-alias.rs:LL:CC | LL | unsafe { (*ptr).set(20) }; | ^^^^^^^^^^^^^^ | | - | trying to reborrow for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | trying to reborrow from for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location | this error occurs as part of a reborrow at ALLOC[0x0..0x1] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental diff --git a/tests/fail/stacked_borrows/aliasing_mut3.stderr b/tests/fail/stacked_borrows/aliasing_mut3.stderr index 8e489b738657a..0bb7b8d3a85cf 100644 --- a/tests/fail/stacked_borrows/aliasing_mut3.stderr +++ b/tests/fail/stacked_borrows/aliasing_mut3.stderr @@ -1,10 +1,10 @@ -error: Undefined Behavior: trying to reborrow for SharedReadOnly permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location +error: Undefined Behavior: trying to reborrow from for SharedReadOnly permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location --> $DIR/aliasing_mut3.rs:LL:CC | LL | pub fn safe(_x: &mut i32, _y: &i32) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | - | trying to reborrow for SharedReadOnly permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | trying to reborrow from for SharedReadOnly permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location | this error occurs as part of a reborrow at ALLOC[0x0..0x4] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental diff --git a/tests/fail/stacked_borrows/buggy_split_at_mut.stderr b/tests/fail/stacked_borrows/buggy_split_at_mut.stderr index 6e6dc38aaf061..41ab9cfa92ae5 100644 --- a/tests/fail/stacked_borrows/buggy_split_at_mut.stderr +++ b/tests/fail/stacked_borrows/buggy_split_at_mut.stderr @@ -1,10 +1,10 @@ -error: Undefined Behavior: trying to reborrow for Unique permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location +error: Undefined Behavior: trying to reborrow from for Unique permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location --> $DIR/buggy_split_at_mut.rs:LL:CC | LL | let (a, b) = safe::split_at_mut(&mut array, 0); | ^ | | - | trying to reborrow for Unique permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | trying to reborrow from for Unique permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location | this error occurs as part of a reborrow at ALLOC[0x0..0x10] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental diff --git a/tests/fail/stacked_borrows/illegal_read7.stderr b/tests/fail/stacked_borrows/illegal_read7.stderr index 56ebd93918bf3..11335df4da0a3 100644 --- a/tests/fail/stacked_borrows/illegal_read7.stderr +++ b/tests/fail/stacked_borrows/illegal_read7.stderr @@ -1,10 +1,10 @@ -error: Undefined Behavior: trying to reborrow for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location +error: Undefined Behavior: trying to reborrow from for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location --> $DIR/illegal_read7.rs:LL:CC | LL | let _val = *x.get_mut(); | ^^^^^^^^^^^ | | - | trying to reborrow for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | trying to reborrow from for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location | this error occurs as part of a reborrow at ALLOC[0x0..0x4] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental diff --git a/tests/fail/stacked_borrows/interior_mut1.stderr b/tests/fail/stacked_borrows/interior_mut1.stderr index 73be074ce91a7..a2643841eac1b 100644 --- a/tests/fail/stacked_borrows/interior_mut1.stderr +++ b/tests/fail/stacked_borrows/interior_mut1.stderr @@ -1,10 +1,10 @@ -error: Undefined Behavior: trying to reborrow for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location +error: Undefined Behavior: trying to reborrow from for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location --> $DIR/interior_mut1.rs:LL:CC | LL | let _val = *inner_shr.get(); | ^^^^^^^^^^^^^^^ | | - | trying to reborrow for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | trying to reborrow from for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location | this error occurs as part of a reborrow at ALLOC[0x0..0x4] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental diff --git a/tests/fail/stacked_borrows/interior_mut2.stderr b/tests/fail/stacked_borrows/interior_mut2.stderr index 74e91d49c418d..0dbf6e2ea9f9a 100644 --- a/tests/fail/stacked_borrows/interior_mut2.stderr +++ b/tests/fail/stacked_borrows/interior_mut2.stderr @@ -1,10 +1,10 @@ -error: Undefined Behavior: trying to reborrow for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location +error: Undefined Behavior: trying to reborrow from for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location --> $DIR/interior_mut2.rs:LL:CC | LL | let _val = *inner_shr.get(); | ^^^^^^^^^^^^^^^ | | - | trying to reborrow for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | trying to reborrow from for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location | this error occurs as part of a reborrow at ALLOC[0x0..0x4] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental diff --git a/tests/fail/stacked_borrows/load_invalid_mut.stderr b/tests/fail/stacked_borrows/load_invalid_mut.stderr index 293d85cc9f457..f8e03c631eeeb 100644 --- a/tests/fail/stacked_borrows/load_invalid_mut.stderr +++ b/tests/fail/stacked_borrows/load_invalid_mut.stderr @@ -1,10 +1,10 @@ -error: Undefined Behavior: trying to reborrow for Unique permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location +error: Undefined Behavior: trying to reborrow from for Unique permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location --> $DIR/load_invalid_mut.rs:LL:CC | LL | let _val = *xref_in_mem; | ^^^^^^^^^^^^ | | - | trying to reborrow for Unique permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | trying to reborrow from for Unique permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location | this error occurs as part of a reborrow at ALLOC[0x0..0x4] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental diff --git a/tests/fail/stacked_borrows/load_invalid_shr.stderr b/tests/fail/stacked_borrows/load_invalid_shr.stderr index 5749daa51fd9f..a9546c9a7680a 100644 --- a/tests/fail/stacked_borrows/load_invalid_shr.stderr +++ b/tests/fail/stacked_borrows/load_invalid_shr.stderr @@ -1,10 +1,10 @@ -error: Undefined Behavior: trying to reborrow for SharedReadOnly permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location +error: Undefined Behavior: trying to reborrow from for SharedReadOnly permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location --> $DIR/load_invalid_shr.rs:LL:CC | LL | let _val = *xref_in_mem; | ^^^^^^^^^^^^ | | - | trying to reborrow for SharedReadOnly permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | trying to reborrow from for SharedReadOnly permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location | this error occurs as part of a reborrow at ALLOC[0x0..0x4] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental diff --git a/tests/fail/stacked_borrows/pass_invalid_mut.stderr b/tests/fail/stacked_borrows/pass_invalid_mut.stderr index 933ef1ad5970a..f254fd16dcbe1 100644 --- a/tests/fail/stacked_borrows/pass_invalid_mut.stderr +++ b/tests/fail/stacked_borrows/pass_invalid_mut.stderr @@ -1,10 +1,10 @@ -error: Undefined Behavior: trying to reborrow for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location +error: Undefined Behavior: trying to reborrow from for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location --> $DIR/pass_invalid_mut.rs:LL:CC | LL | foo(xref); | ^^^^ | | - | trying to reborrow for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | trying to reborrow from for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location | this error occurs as part of a reborrow at ALLOC[0x0..0x4] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental diff --git a/tests/fail/stacked_borrows/pass_invalid_shr.stderr b/tests/fail/stacked_borrows/pass_invalid_shr.stderr index 02cf62f033261..28500836aa8d4 100644 --- a/tests/fail/stacked_borrows/pass_invalid_shr.stderr +++ b/tests/fail/stacked_borrows/pass_invalid_shr.stderr @@ -1,10 +1,10 @@ -error: Undefined Behavior: trying to reborrow for SharedReadOnly permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location +error: Undefined Behavior: trying to reborrow from for SharedReadOnly permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location --> $DIR/pass_invalid_shr.rs:LL:CC | LL | foo(xref); | ^^^^ | | - | trying to reborrow for SharedReadOnly permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | trying to reborrow from for SharedReadOnly permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location | this error occurs as part of a reborrow at ALLOC[0x0..0x4] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental diff --git a/tests/fail/stacked_borrows/return_invalid_mut.stderr b/tests/fail/stacked_borrows/return_invalid_mut.stderr index 230c3e82ff231..7c80070443700 100644 --- a/tests/fail/stacked_borrows/return_invalid_mut.stderr +++ b/tests/fail/stacked_borrows/return_invalid_mut.stderr @@ -1,10 +1,10 @@ -error: Undefined Behavior: trying to reborrow for Unique permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location +error: Undefined Behavior: trying to reborrow from for Unique permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location --> $DIR/return_invalid_mut.rs:LL:CC | LL | ret | ^^^ | | - | trying to reborrow for Unique permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location + | trying to reborrow from for Unique permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location | this error occurs as part of a reborrow at ALLOC[0x4..0x8] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental diff --git a/tests/fail/stacked_borrows/return_invalid_mut_option.stderr b/tests/fail/stacked_borrows/return_invalid_mut_option.stderr index f278113e42577..cab997b47357b 100644 --- a/tests/fail/stacked_borrows/return_invalid_mut_option.stderr +++ b/tests/fail/stacked_borrows/return_invalid_mut_option.stderr @@ -1,10 +1,10 @@ -error: Undefined Behavior: trying to reborrow for Unique permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location +error: Undefined Behavior: trying to reborrow from for Unique permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location --> $DIR/return_invalid_mut_option.rs:LL:CC | LL | Some(_x) => {} | ^^ | | - | trying to reborrow for Unique permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location + | trying to reborrow from for Unique permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location | this error occurs as part of a reborrow at ALLOC[0x4..0x8] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental diff --git a/tests/fail/stacked_borrows/return_invalid_mut_tuple.stderr b/tests/fail/stacked_borrows/return_invalid_mut_tuple.stderr index 9465fd072ea93..46ef6a737a637 100644 --- a/tests/fail/stacked_borrows/return_invalid_mut_tuple.stderr +++ b/tests/fail/stacked_borrows/return_invalid_mut_tuple.stderr @@ -1,10 +1,10 @@ -error: Undefined Behavior: trying to reborrow for Unique permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location +error: Undefined Behavior: trying to reborrow from for Unique permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location --> $DIR/return_invalid_mut_tuple.rs:LL:CC | LL | foo(&mut (1, 2)).0; | ^^^^^^^^^^^^^^^^^^ | | - | trying to reborrow for Unique permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location + | trying to reborrow from for Unique permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location | this error occurs as part of a reborrow at ALLOC[0x4..0x8] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental diff --git a/tests/fail/stacked_borrows/return_invalid_shr.stderr b/tests/fail/stacked_borrows/return_invalid_shr.stderr index 75ea8bb89ec0f..6f745b69fc722 100644 --- a/tests/fail/stacked_borrows/return_invalid_shr.stderr +++ b/tests/fail/stacked_borrows/return_invalid_shr.stderr @@ -1,10 +1,10 @@ -error: Undefined Behavior: trying to reborrow for SharedReadOnly permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location +error: Undefined Behavior: trying to reborrow from for SharedReadOnly permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location --> $DIR/return_invalid_shr.rs:LL:CC | LL | ret | ^^^ | | - | trying to reborrow for SharedReadOnly permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location + | trying to reborrow from for SharedReadOnly permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location | this error occurs as part of a reborrow at ALLOC[0x4..0x8] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental diff --git a/tests/fail/stacked_borrows/return_invalid_shr_option.stderr b/tests/fail/stacked_borrows/return_invalid_shr_option.stderr index 27656b46ccfcb..2441c9aa1c510 100644 --- a/tests/fail/stacked_borrows/return_invalid_shr_option.stderr +++ b/tests/fail/stacked_borrows/return_invalid_shr_option.stderr @@ -1,10 +1,10 @@ -error: Undefined Behavior: trying to reborrow for SharedReadOnly permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location +error: Undefined Behavior: trying to reborrow from for SharedReadOnly permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location --> $DIR/return_invalid_shr_option.rs:LL:CC | LL | Some(_x) => {} | ^^ | | - | trying to reborrow for SharedReadOnly permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location + | trying to reborrow from for SharedReadOnly permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location | this error occurs as part of a reborrow at ALLOC[0x4..0x8] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental diff --git a/tests/fail/stacked_borrows/return_invalid_shr_tuple.stderr b/tests/fail/stacked_borrows/return_invalid_shr_tuple.stderr index 9fdc878086514..5102f7cb53c45 100644 --- a/tests/fail/stacked_borrows/return_invalid_shr_tuple.stderr +++ b/tests/fail/stacked_borrows/return_invalid_shr_tuple.stderr @@ -1,10 +1,10 @@ -error: Undefined Behavior: trying to reborrow for SharedReadOnly permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location +error: Undefined Behavior: trying to reborrow from for SharedReadOnly permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location --> $DIR/return_invalid_shr_tuple.rs:LL:CC | LL | foo(&mut (1, 2)).0; | ^^^^^^^^^^^^^^^^^^ | | - | trying to reborrow for SharedReadOnly permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location + | trying to reborrow from for SharedReadOnly permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location | this error occurs as part of a reborrow at ALLOC[0x4..0x8] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental diff --git a/tests/fail/stacked_borrows/shared_rw_borrows_are_weak1.stderr b/tests/fail/stacked_borrows/shared_rw_borrows_are_weak1.stderr index 9909778ab28ed..a412add67e024 100644 --- a/tests/fail/stacked_borrows/shared_rw_borrows_are_weak1.stderr +++ b/tests/fail/stacked_borrows/shared_rw_borrows_are_weak1.stderr @@ -1,10 +1,10 @@ -error: Undefined Behavior: trying to reborrow for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location +error: Undefined Behavior: trying to reborrow from for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location --> $DIR/shared_rw_borrows_are_weak1.rs:LL:CC | LL | y.get_mut(); | ^^^^^^^^^^^ | | - | trying to reborrow for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | trying to reborrow from for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location | this error occurs as part of a reborrow at ALLOC[0x0..0x4] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental diff --git a/tests/fail/stacked_borrows/zst_slice.stderr b/tests/fail/stacked_borrows/zst_slice.stderr index 2878f4c069af7..d47e967b543b0 100644 --- a/tests/fail/stacked_borrows/zst_slice.stderr +++ b/tests/fail/stacked_borrows/zst_slice.stderr @@ -1,10 +1,10 @@ -error: Undefined Behavior: trying to reborrow for SharedReadOnly permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location +error: Undefined Behavior: trying to reborrow from for SharedReadOnly permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location --> RUSTLIB/core/src/slice/mod.rs:LL:CC | LL | unsafe { &*index.get_unchecked(self) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | - | trying to reborrow for SharedReadOnly permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location + | trying to reborrow from for SharedReadOnly permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location | this error occurs as part of a reborrow at ALLOC[0x4..0x8] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental From a272ca2cf7f4cfa227d9d9ffddf910aa2e0fb169 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 13 Jul 2022 20:18:45 -0400 Subject: [PATCH 3475/3747] add another weak mem consistency test --- tests/pass/0weak_memory_consistency.rs | 51 +++++++++++++++++++++++--- 1 file changed, 46 insertions(+), 5 deletions(-) diff --git a/tests/pass/0weak_memory_consistency.rs b/tests/pass/0weak_memory_consistency.rs index 19e19b47cfed3..668635d7ff8ae 100644 --- a/tests/pass/0weak_memory_consistency.rs +++ b/tests/pass/0weak_memory_consistency.rs @@ -20,8 +20,8 @@ // "Mathematizing C++ concurrency", ACM SIGPLAN Notices, vol. 46, no. 1, pp. 55-66, 2011. // Available: https://ss265.host.cs.st-andrews.ac.uk/papers/n3132.pdf. -use std::sync::atomic::AtomicUsize; use std::sync::atomic::Ordering::*; +use std::sync::atomic::{fence, AtomicBool, AtomicI32}; use std::thread::spawn; #[derive(Copy, Clone)] @@ -32,13 +32,17 @@ unsafe impl Sync for EvilSend {} // We can't create static items because we need to run each test // multiple times -fn static_atomic(val: usize) -> &'static AtomicUsize { - let ret = Box::leak(Box::new(AtomicUsize::new(val))); +fn static_atomic(val: i32) -> &'static AtomicI32 { + let ret = Box::leak(Box::new(AtomicI32::new(val))); + ret +} +fn static_atomic_bool(val: bool) -> &'static AtomicBool { + let ret = Box::leak(Box::new(AtomicBool::new(val))); ret } // Spins until it acquires a pre-determined value. -fn acquires_value(loc: &AtomicUsize, val: usize) -> usize { +fn acquires_value(loc: &AtomicI32, val: i32) -> i32 { while loc.load(Acquire) != val { std::hint::spin_loop(); } @@ -207,7 +211,7 @@ fn test_sc_store_buffering() { } fn test_single_thread() { - let x = AtomicUsize::new(42); + let x = AtomicI32::new(42); assert_eq!(x.load(Relaxed), 42); @@ -216,6 +220,42 @@ fn test_single_thread() { assert_eq!(x.load(Relaxed), 43); } +fn test_sync_through_rmw_and_fences() { + // Example from https://github.com/llvm/llvm-project/issues/56450#issuecomment-1183695905 + #[no_mangle] + pub fn rdmw(storing: &AtomicI32, sync: &AtomicI32, loading: &AtomicI32) -> i32 { + storing.store(1, Relaxed); + fence(Release); + sync.fetch_add(0, Relaxed); + fence(Acquire); + loading.load(Relaxed) + } + + let x = static_atomic(0); + let y = static_atomic(0); + let z = static_atomic(0); + + // Since each thread is so short, we need to make sure that they truely run at the same time + // Otherwise t1 will finish before t2 even starts + let go = static_atomic_bool(false); + + let t1 = spawn(move || { + while !go.load(Relaxed) {} + rdmw(y, x, z) + }); + + let t2 = spawn(move || { + while !go.load(Relaxed) {} + rdmw(z, x, y) + }); + + go.store(true, Relaxed); + + let a = t1.join().unwrap(); + let b = t2.join().unwrap(); + assert_ne!((a, b), (0, 0)); +} + pub fn main() { for _ in 0..50 { test_single_thread(); @@ -225,5 +265,6 @@ pub fn main() { test_wrc(); test_corr(); test_sc_store_buffering(); + test_sync_through_rmw_and_fences(); } } From bd69a92b4b794bde4900385d6befaf644accb496 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 13 Jul 2022 22:35:45 -0400 Subject: [PATCH 3476/3747] rustup --- rust-version | 2 +- tests/pass/union-overwrite.rs | 2 -- tests/pass/union.rs | 3 +-- 3 files changed, 2 insertions(+), 5 deletions(-) diff --git a/rust-version b/rust-version index 2a26cb608235a..3b418bcb11d16 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -c396bb3b8a16b1f2762b7c6078dc3e023f6a2493 +cbb07c27a4d78f95557a6b9cdcc32f98d67a0c22 diff --git a/tests/pass/union-overwrite.rs b/tests/pass/union-overwrite.rs index d3c81834bc4b4..f1d3d9d48101a 100644 --- a/tests/pass/union-overwrite.rs +++ b/tests/pass/union-overwrite.rs @@ -1,5 +1,3 @@ -#![feature(untagged_unions)] - #[repr(C)] #[derive(Clone, Copy)] struct Pair(T, U); diff --git a/tests/pass/union.rs b/tests/pass/union.rs index f98a213102851..8a6dd49f45038 100644 --- a/tests/pass/union.rs +++ b/tests/pass/union.rs @@ -1,5 +1,3 @@ -#![feature(untagged_unions)] - fn main() { a(); b(); @@ -22,6 +20,7 @@ fn a() { } fn b() { + #[derive(Copy, Clone)] struct S { x: u32, y: u32, From 11f2b834648bb07ce64c1dcd3c4b7dd0252ab9bb Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 14 Jul 2022 07:29:20 -0400 Subject: [PATCH 3477/3747] fix a missing thread join --- tests/pass/concurrency/sync.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/tests/pass/concurrency/sync.rs b/tests/pass/concurrency/sync.rs index b7e6f229faae2..64bd7ebb27fd7 100644 --- a/tests/pass/concurrency/sync.rs +++ b/tests/pass/concurrency/sync.rs @@ -219,10 +219,8 @@ fn park_unpark() { // know Miri's timed synchronization primitives do not do that. assert!((200..1000).contains(&start.elapsed().as_millis())); -} -fn check_condvar() { - let _ = std::sync::Condvar::new(); + t2.join().unwrap(); } fn main() { @@ -236,5 +234,4 @@ fn main() { check_once(); park_timeout(); park_unpark(); - check_condvar(); } From 820f322b86772fe3fdadebb587cc877efff4e61c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 14 Jul 2022 08:07:59 -0400 Subject: [PATCH 3478/3747] add work-around for #2164 --- tests/pass/0weak_memory_consistency.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/pass/0weak_memory_consistency.rs b/tests/pass/0weak_memory_consistency.rs index 668635d7ff8ae..8b7ce50d2d42e 100644 --- a/tests/pass/0weak_memory_consistency.rs +++ b/tests/pass/0weak_memory_consistency.rs @@ -34,10 +34,12 @@ unsafe impl Sync for EvilSend {} // multiple times fn static_atomic(val: i32) -> &'static AtomicI32 { let ret = Box::leak(Box::new(AtomicI32::new(val))); + ret.store(val, Relaxed); // work around https://github.com/rust-lang/miri/issues/2164 ret } fn static_atomic_bool(val: bool) -> &'static AtomicBool { let ret = Box::leak(Box::new(AtomicBool::new(val))); + ret.store(val, Relaxed); // work around https://github.com/rust-lang/miri/issues/2164 ret } From 07c3e42bd7c21be29227646dfce465cb57827465 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 14 Jul 2022 08:13:24 -0400 Subject: [PATCH 3479/3747] replace a macro by a function --- tests/pass/weak_memory/weak.rs | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/tests/pass/weak_memory/weak.rs b/tests/pass/weak_memory/weak.rs index 1d82b85844f41..5e2e78882de55 100644 --- a/tests/pass/weak_memory/weak.rs +++ b/tests/pass/weak_memory/weak.rs @@ -72,7 +72,7 @@ fn seq_cst() -> bool { fn initialization_write() -> bool { let x = static_atomic(11); - assert_eq!(x.load(Relaxed), 11); + assert_eq!(x.load(Relaxed), 11); // work around https://github.com/rust-lang/miri/issues/2164 let wait = static_atomic(0); @@ -94,15 +94,13 @@ fn initialization_write() -> bool { r2 == 11 } -// Asserts that the function returns true at least once in 100 runs -macro_rules! assert_once { - ($f:ident) => { - assert!(std::iter::repeat_with(|| $f()).take(100).any(|x| x)); - }; +/// Asserts that the function returns true at least once in 100 runs +fn assert_once(f: fn() -> bool) { + assert!(std::iter::repeat_with(|| f()).take(100).any(|x| x)); } pub fn main() { - assert_once!(relaxed); - assert_once!(seq_cst); - assert_once!(initialization_write); + assert_once(relaxed); + assert_once(seq_cst); + assert_once(initialization_write); } From b8a0c49e51a65aff7189da95583fb5273c02ce37 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 14 Jul 2022 08:23:04 -0400 Subject: [PATCH 3480/3747] test that we can see this weak behavior --- tests/pass/weak_memory/weak.rs | 51 ++++++++++++++++++++++++++++++++-- 1 file changed, 48 insertions(+), 3 deletions(-) diff --git a/tests/pass/weak_memory/weak.rs b/tests/pass/weak_memory/weak.rs index 5e2e78882de55..71d57dd11ec78 100644 --- a/tests/pass/weak_memory/weak.rs +++ b/tests/pass/weak_memory/weak.rs @@ -8,8 +8,8 @@ // Spurious failure is possible, if you are really unlucky with // the RNG and always read the latest value from the store buffer. -use std::sync::atomic::AtomicUsize; use std::sync::atomic::Ordering::*; +use std::sync::atomic::{fence, AtomicUsize}; use std::thread::spawn; #[derive(Copy, Clone)] @@ -70,7 +70,7 @@ fn seq_cst() -> bool { r3 == 1 } -fn initialization_write() -> bool { +fn initialization_write(add_fence: bool) -> bool { let x = static_atomic(11); assert_eq!(x.load(Relaxed), 11); // work around https://github.com/rust-lang/miri/issues/2164 @@ -85,6 +85,9 @@ fn initialization_write() -> bool { let j2 = spawn(move || { reads_value(wait, 1); + if add_fence { + fence(AcqRel); + } x.load(Relaxed) }); @@ -94,6 +97,46 @@ fn initialization_write() -> bool { r2 == 11 } +fn faa_replaced_by_load() -> bool { + // Example from https://github.com/llvm/llvm-project/issues/56450#issuecomment-1183695905 + #[no_mangle] + pub fn rdmw(storing: &AtomicUsize, sync: &AtomicUsize, loading: &AtomicUsize) -> usize { + storing.store(1, Relaxed); + fence(Release); + // sync.fetch_add(0, Relaxed); + sync.load(Relaxed); + fence(Acquire); + loading.load(Relaxed) + } + + let x = static_atomic(0); + assert_eq!(x.load(Relaxed), 0); // work around https://github.com/rust-lang/miri/issues/2164 + let y = static_atomic(0); + assert_eq!(y.load(Relaxed), 0); // work around https://github.com/rust-lang/miri/issues/2164 + let z = static_atomic(0); + assert_eq!(z.load(Relaxed), 0); // work around https://github.com/rust-lang/miri/issues/2164 + + // Since each thread is so short, we need to make sure that they truely run at the same time + // Otherwise t1 will finish before t2 even starts + let go = static_atomic(0); + + let t1 = spawn(move || { + while go.load(Relaxed) == 0 {} + rdmw(y, x, z) + }); + + let t2 = spawn(move || { + while go.load(Relaxed) == 0 {} + rdmw(z, x, y) + }); + + go.store(1, Relaxed); + + let a = t1.join().unwrap(); + let b = t2.join().unwrap(); + (a, b) == (0, 0) +} + /// Asserts that the function returns true at least once in 100 runs fn assert_once(f: fn() -> bool) { assert!(std::iter::repeat_with(|| f()).take(100).any(|x| x)); @@ -102,5 +145,7 @@ fn assert_once(f: fn() -> bool) { pub fn main() { assert_once(relaxed); assert_once(seq_cst); - assert_once(initialization_write); + assert_once(|| initialization_write(false)); + assert_once(|| initialization_write(true)); + assert_once(faa_replaced_by_load); } From eaa7f10cb1087bed06f96a84c55253881bfdeb15 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 14 Jul 2022 09:54:20 -0400 Subject: [PATCH 3481/3747] rustup --- rust-version | 2 +- src/shims/backtrace.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/rust-version b/rust-version index 3b418bcb11d16..45abe7e8c653a 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -cbb07c27a4d78f95557a6b9cdcc32f98d67a0c22 +0ed9c64c3e63acac9bd77abce62501696c390450 diff --git a/src/shims/backtrace.rs b/src/shims/backtrace.rs index 339aa4d57e220..4aa58b45662d8 100644 --- a/src/shims/backtrace.rs +++ b/src/shims/backtrace.rs @@ -48,7 +48,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let mut span = frame.current_span(); // Match the behavior of runtime backtrace spans // by using a non-macro span in our backtrace. See `FunctionCx::debug_loc`. - if span.from_expansion() && !tcx.sess.opts.debugging_opts.debug_macros { + if span.from_expansion() && !tcx.sess.opts.unstable_opts.debug_macros { span = rustc_span::hygiene::walk_chain(span, frame.body.span.ctxt()) } data.push((frame.instance, span.lo())); From efc76af1342c55fde2f0bb316f126cd96558fc76 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 13 Jul 2022 19:22:22 -0400 Subject: [PATCH 3482/3747] don't forcefully enable debug assertions, but make -debug mode usable still set those flags on CI though, we want to catch overflow there --- Cargo.toml | 3 +++ ci.sh | 2 +- miri | 4 +--- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index af73a7af31c71..b6e1cdf5ca874 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -57,3 +57,6 @@ default = ["stack-cache"] # Will be enabled on CI via `--all-features`. expensive-debug-assertions = [] stack-cache = [] + +[profile.dev] +opt-level = 2 # because it's too slow otherwise diff --git a/ci.sh b/ci.sh index e7c6ed833c60c..05a3ee358ce4d 100755 --- a/ci.sh +++ b/ci.sh @@ -3,7 +3,7 @@ set -euo pipefail set -x # Determine configuration -export RUSTFLAGS="-D warnings" +export RUSTFLAGS="-D warnings -C debug-assertions -C debuginfo=1" export CARGO_INCREMENTAL=0 export CARGO_EXTRA_FLAGS="--all-features" # in particular, expensive-debug-assertions diff --git a/miri b/miri index f0d92b6a2b539..a1931485f6915 100755 --- a/miri +++ b/miri @@ -108,9 +108,7 @@ if [ -z "$CARGO_TARGET_DIR" ]; then export CARGO_TARGET_DIR="$MIRIDIR/target" fi # We set the rpath so that Miri finds the private rustc libraries it needs. -# We enable debug-assertions to get tracing. -# We enable line-only debuginfo for backtraces. -export RUSTFLAGS="-C link-args=-Wl,-rpath,$LIBDIR -C debug-assertions -C debuginfo=1 $RUSTFLAGS" +export RUSTFLAGS="-C link-args=-Wl,-rpath,$LIBDIR $RUSTFLAGS" # Determine flags passed to all cargo invocations. # This is a bit more annoying that one would hope due to # . From 5d5999ab13e849c66f39b23a685512110e0d8eee Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 14 Jul 2022 08:06:37 -0400 Subject: [PATCH 3483/3747] make cache consistency checks into regular debug assertions --- Cargo.toml | 2 -- ci.sh | 4 ++-- src/stacked_borrows/stack.rs | 10 +++++----- 3 files changed, 7 insertions(+), 9 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index b6e1cdf5ca874..a2a880f8e308c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -54,8 +54,6 @@ harness = false [features] default = ["stack-cache"] -# Will be enabled on CI via `--all-features`. -expensive-debug-assertions = [] stack-cache = [] [profile.dev] diff --git a/ci.sh b/ci.sh index 05a3ee358ce4d..68da8addc2c87 100755 --- a/ci.sh +++ b/ci.sh @@ -5,11 +5,11 @@ set -x # Determine configuration export RUSTFLAGS="-D warnings -C debug-assertions -C debuginfo=1" export CARGO_INCREMENTAL=0 -export CARGO_EXTRA_FLAGS="--all-features" # in particular, expensive-debug-assertions +export CARGO_EXTRA_FLAGS="--all-features" # Prepare echo "Build and install miri" -CARGO_EXTRA_FLAGS="" ./miri install # implicitly locked -- and the *installed* Miri does *not* get the expensive-debug-assertions feature +RUSTFLAGS="" ./miri install # implicitly locked, and explicitly without debug assertions ./miri build --all-targets --locked # the build that all the `./miri test` below will use echo diff --git a/src/stacked_borrows/stack.rs b/src/stacked_borrows/stack.rs index 1b05471618a52..bc7ffd4faea55 100644 --- a/src/stacked_borrows/stack.rs +++ b/src/stacked_borrows/stack.rs @@ -82,7 +82,7 @@ impl<'tcx> Stack { /// Panics if any of the caching mechanisms have broken, /// - The StackCache indices don't refer to the parallel items, /// - There are no Unique items outside of first_unique..last_unique - #[cfg(feature = "expensive-debug-assertions")] + #[cfg(debug_assertions)] fn verify_cache_consistency(&self) { // Only a full cache needs to be valid. Also see the comments in find_granting_cache // and set_unknown_bottom. @@ -115,7 +115,7 @@ impl<'tcx> Stack { tag: SbTagExtra, exposed_tags: &FxHashSet, ) -> Result, ()> { - #[cfg(feature = "expensive-debug-assertions")] + #[cfg(debug_assertions)] self.verify_cache_consistency(); let SbTagExtra::Concrete(tag) = tag else { @@ -247,7 +247,7 @@ impl<'tcx> Stack { // This primes the cache for the next access, which is almost always the just-added tag. self.cache.add(new_idx, new); - #[cfg(feature = "expensive-debug-assertions")] + #[cfg(debug_assertions)] self.verify_cache_consistency(); } @@ -325,7 +325,7 @@ impl<'tcx> Stack { self.unique_range.end = self.unique_range.end.min(disable_start + 1); } - #[cfg(feature = "expensive-debug-assertions")] + #[cfg(debug_assertions)] self.verify_cache_consistency(); Ok(()) @@ -380,7 +380,7 @@ impl<'tcx> Stack { self.unique_range = 0..0; } - #[cfg(feature = "expensive-debug-assertions")] + #[cfg(debug_assertions)] self.verify_cache_consistency(); Ok(()) } From fa7811bbe1532f06aea058700433c20fc31f5e39 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 14 Jul 2022 13:08:09 -0400 Subject: [PATCH 3484/3747] use the cargo default for debug/release builds --- ci.sh | 4 ++-- miri | 72 +++++++++++++++++++++-------------------------------------- 2 files changed, 27 insertions(+), 49 deletions(-) diff --git a/ci.sh b/ci.sh index 68da8addc2c87..8c63a57a4f490 100755 --- a/ci.sh +++ b/ci.sh @@ -3,13 +3,13 @@ set -euo pipefail set -x # Determine configuration -export RUSTFLAGS="-D warnings -C debug-assertions -C debuginfo=1" +export RUSTFLAGS="-D warnings" export CARGO_INCREMENTAL=0 export CARGO_EXTRA_FLAGS="--all-features" # Prepare echo "Build and install miri" -RUSTFLAGS="" ./miri install # implicitly locked, and explicitly without debug assertions +./miri install # implicitly locked ./miri build --all-targets --locked # the build that all the `./miri test` below will use echo diff --git a/miri b/miri index a1931485f6915..7b53b802db62a 100755 --- a/miri +++ b/miri @@ -6,7 +6,8 @@ USAGE=$(cat <<"EOF" ./miri install : Installs the miri driver and cargo-miri. are passed to `cargo install`. Sets up the rpath such that the installed binary should work in any -working directory. +working directory. However, the rustup toolchain when invoking `cargo miri` +needs to be the same one used for `./miri install`. ./miri build : Just build miri. are passed to `cargo build`. @@ -22,10 +23,6 @@ to the final `cargo test` invocation. Build miri, set up a sysroot and then run the driver with the given . (Also respects MIRIFLAGS environment variable.) -The commands above also exist in a "-debug" variant (e.g. "./miri run-debug -") which uses debug builds instead of release builds, for faster build -times and slower execution times. - ./miri fmt : Format all sources and tests. are passed to `rustfmt`. @@ -99,38 +96,21 @@ fi # Prepare flags for cargo and rustc. CARGO="cargo +$TOOLCHAIN" -if [ -z "$CARGO_INCREMENTAL" ]; then - # Default CARGO_INCREMENTAL to 1. - export CARGO_INCREMENTAL=1 -fi if [ -z "$CARGO_TARGET_DIR" ]; then # Share target dir between `miri` and `cargo-miri`. export CARGO_TARGET_DIR="$MIRIDIR/target" fi # We set the rpath so that Miri finds the private rustc libraries it needs. export RUSTFLAGS="-C link-args=-Wl,-rpath,$LIBDIR $RUSTFLAGS" -# Determine flags passed to all cargo invocations. -# This is a bit more annoying that one would hope due to -# . -case "$COMMAND" in -*-debug) - CARGO_INSTALL_FLAGS="--target $TARGET --debug $CARGO_EXTRA_FLAGS" - CARGO_BUILD_FLAGS="--target $TARGET $CARGO_EXTRA_FLAGS" - ;; -*) - CARGO_INSTALL_FLAGS="--target $TARGET $CARGO_EXTRA_FLAGS" - CARGO_BUILD_FLAGS="--target $TARGET --release $CARGO_EXTRA_FLAGS" - ;; -esac ## Helper functions # Build a sysroot and set MIRI_SYSROOT to use it. Arguments are passed to `cargo miri setup`. build_sysroot() { # Build once, for the user to see. - $CARGO run $CARGO_BUILD_FLAGS --manifest-path "$MIRIDIR"/cargo-miri/Cargo.toml -- miri setup "$@" + $CARGO run $CARGO_EXTRA_FLAGS --manifest-path "$MIRIDIR"/cargo-miri/Cargo.toml -- miri setup "$@" # Call again, to just set env var. - export MIRI_SYSROOT="$($CARGO run $CARGO_BUILD_FLAGS --manifest-path "$MIRIDIR"/cargo-miri/Cargo.toml -q -- miri setup --print-sysroot "$@")" + export MIRI_SYSROOT="$($CARGO run $CARGO_EXTRA_FLAGS --manifest-path "$MIRIDIR"/cargo-miri/Cargo.toml -q -- miri setup --print-sysroot "$@")" } # Prepare and set MIRI_SYSROOT. Respects `MIRI_TEST_TARGET` and takes into account @@ -152,37 +132,35 @@ find_sysroot() { # Run command. case "$COMMAND" in -install|install-debug) +install) # "--locked" to respect the Cargo.lock file if it exists, # "--offline" to avoid querying the registry (for yanked packages). - $CARGO install $CARGO_INSTALL_FLAGS --path "$MIRIDIR" --force --locked --offline "$@" - $CARGO install $CARGO_INSTALL_FLAGS --path "$MIRIDIR"/cargo-miri --force --locked --offline "$@" + $CARGO install $CARGO_EXTRA_FLAGS --path "$MIRIDIR" --force --locked --offline "$@" + $CARGO install $CARGO_EXTRA_FLAGS --path "$MIRIDIR"/cargo-miri --force --locked --offline "$@" ;; -check|check-debug) +check) # Check, and let caller control flags. - $CARGO check $CARGO_BUILD_FLAGS --manifest-path "$MIRIDIR"/Cargo.toml --all-targets "$@" - $CARGO check $CARGO_BUILD_FLAGS --manifest-path "$MIRIDIR"/cargo-miri/Cargo.toml "$@" + $CARGO check $CARGO_EXTRA_FLAGS --manifest-path "$MIRIDIR"/Cargo.toml --all-targets "$@" + $CARGO check $CARGO_EXTRA_FLAGS --manifest-path "$MIRIDIR"/cargo-miri/Cargo.toml "$@" ;; -build|build-debug) +build) # Build, and let caller control flags. - $CARGO build $CARGO_BUILD_FLAGS --manifest-path "$MIRIDIR"/Cargo.toml "$@" - $CARGO build $CARGO_BUILD_FLAGS --manifest-path "$MIRIDIR"/cargo-miri/Cargo.toml "$@" + $CARGO build $CARGO_EXTRA_FLAGS --manifest-path "$MIRIDIR"/Cargo.toml "$@" + $CARGO build $CARGO_EXTRA_FLAGS --manifest-path "$MIRIDIR"/cargo-miri/Cargo.toml "$@" ;; -test|test-debug|bless|bless-debug) +test|bless) # First build and get a sysroot. - $CARGO build $CARGO_BUILD_FLAGS --manifest-path "$MIRIDIR"/Cargo.toml + $CARGO build $CARGO_EXTRA_FLAGS --manifest-path "$MIRIDIR"/Cargo.toml find_sysroot - case "$COMMAND" in - bless|bless-debug) + if [ "$COMMAND" = "bless" ]; then export MIRI_BLESS="Gesundheit" - ;; - esac + fi # Then test, and let caller control flags. # Only in root project and ui_test as `cargo-miri` has no tests. - $CARGO test $CARGO_BUILD_FLAGS --manifest-path "$MIRIDIR"/Cargo.toml "$@" - $CARGO test $CARGO_BUILD_FLAGS --manifest-path "$MIRIDIR"/ui_test/Cargo.toml "$@" + $CARGO test $CARGO_EXTRA_FLAGS --manifest-path "$MIRIDIR"/Cargo.toml "$@" + $CARGO test $CARGO_EXTRA_FLAGS --manifest-path "$MIRIDIR"/ui_test/Cargo.toml "$@" ;; -run|run-debug) +run) # Scan for "--target" to overwrite the "MIRI_TEST_TARGET" env var so # that we set the MIRI_SYSROOT up the right way. FOUND_TARGET_OPT=0 @@ -200,19 +178,19 @@ run|run-debug) MIRIFLAGS="$MIRIFLAGS --target $MIRI_TEST_TARGET" fi # First build and get a sysroot. - $CARGO build $CARGO_BUILD_FLAGS --manifest-path "$MIRIDIR"/Cargo.toml + $CARGO build $CARGO_EXTRA_FLAGS --manifest-path "$MIRIDIR"/Cargo.toml find_sysroot # Then run the actual command. - exec $CARGO run $CARGO_BUILD_FLAGS --manifest-path "$MIRIDIR"/Cargo.toml -- --sysroot "$MIRI_SYSROOT" $MIRIFLAGS "$@" + exec $CARGO run $CARGO_EXTRA_FLAGS --manifest-path "$MIRIDIR"/Cargo.toml -- --sysroot "$MIRI_SYSROOT" $MIRIFLAGS "$@" ;; fmt) find "$MIRIDIR" -not \( -name target -prune \) -name '*.rs' \ | xargs rustfmt +$TOOLCHAIN --edition=2021 --config-path "$MIRIDIR/rustfmt.toml" "$@" ;; clippy) - $CARGO clippy $CARGO_BUILD_FLAGS --manifest-path "$MIRIDIR"/Cargo.toml --all-targets "$@" - $CARGO clippy $CARGO_BUILD_FLAGS --manifest-path "$MIRIDIR"/ui_test/Cargo.toml --all-targets "$@" - $CARGO clippy $CARGO_BUILD_FLAGS --manifest-path "$MIRIDIR"/cargo-miri/Cargo.toml "$@" + $CARGO clippy $CARGO_EXTRA_FLAGS --manifest-path "$MIRIDIR"/Cargo.toml --all-targets "$@" + $CARGO clippy $CARGO_EXTRA_FLAGS --manifest-path "$MIRIDIR"/ui_test/Cargo.toml --all-targets "$@" + $CARGO clippy $CARGO_EXTRA_FLAGS --manifest-path "$MIRIDIR"/cargo-miri/Cargo.toml "$@" ;; *) if [ -n "$COMMAND" ]; then From 421f92bee65452600c3ecdf63de5395809d78e55 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 14 Jul 2022 13:23:35 -0400 Subject: [PATCH 3485/3747] make some debug assertions in RangeObjectMap be full assertions --- src/concurrency/range_object_map.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/concurrency/range_object_map.rs b/src/concurrency/range_object_map.rs index 2bb3280302392..50d3f8c9b20ea 100644 --- a/src/concurrency/range_object_map.rs +++ b/src/concurrency/range_object_map.rs @@ -117,11 +117,11 @@ impl RangeObjectMap { self.v.insert(pos, Elem { range, data }); // If we aren't the first element, then our start must be greater than the preivous element's end if pos > 0 { - debug_assert!(self.v[pos - 1].range.end() <= range.start); + assert!(self.v[pos - 1].range.end() <= range.start); } // If we aren't the last element, then our end must be smaller than next element's start if pos < self.v.len() - 1 { - debug_assert!(range.end() <= self.v[pos + 1].range.start); + assert!(range.end() <= self.v[pos + 1].range.start); } } From d6cbe5d014c8c02ed4077ee702d34ea442c62e47 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 14 Jul 2022 14:27:24 -0400 Subject: [PATCH 3486/3747] ensure that RangeMap panics on OOB --- src/range_map.rs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/range_map.rs b/src/range_map.rs index 474ad9dcccd93..c77ea63b0873f 100644 --- a/src/range_map.rs +++ b/src/range_map.rs @@ -77,6 +77,10 @@ impl RangeMap { }; // The first offset that is not included any more. let end = offset + len; + assert!( + end <= self.v.last().unwrap().range.end, + "iterating beyond the bounds of this RangeMap" + ); slice .iter() .take_while(move |elem| elem.range.start < end) @@ -279,4 +283,18 @@ mod tests { assert_eq!(map.v.len(), 5); assert_eq!(to_vec(&map, 10, 10), vec![23, 42, 23, 23, 23, 19, 19, 19, 19, 19]); } + + #[test] + #[should_panic] + fn out_of_range_iter_mut() { + let mut map = RangeMap::::new(Size::from_bytes(20), -1); + let _ = map.iter_mut(Size::from_bytes(11), Size::from_bytes(11)); + } + + #[test] + #[should_panic] + fn out_of_range_iter() { + let map = RangeMap::::new(Size::from_bytes(20), -1); + let _ = map.iter(Size::from_bytes(11), Size::from_bytes(11)); + } } From 8c13a9ccd376a82c695f32123c407fe16d6663e5 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 15 Jul 2022 08:02:13 -0400 Subject: [PATCH 3487/3747] clarify how to run the manually installed Miri --- CONTRIBUTING.md | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index bde1921eb8ce4..a57ef09e7db9f 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -28,11 +28,6 @@ install that exact version of rustc as a toolchain: This will set up a rustup toolchain called `miri` and set it as an override for the current directory. -If you want to also have `clippy` installed, you need to run this: -``` -./rustup-toolchain "" -c clippy -``` - [`rustup-toolchain-install-master`]: https://github.com/kennytm/rustup-toolchain-install-master ## Building and testing Miri @@ -131,6 +126,8 @@ development version of Miri using and then you can use it as if it was installed by `rustup`. Make sure you use the same toolchain when calling `cargo miri` that you used when installing Miri! +Usually this means you have to write `cargo +miri miri ...` to select the `miri` +toolchain that was installed by `./rustup-toolchain`. There's a test for the cargo wrapper in the `test-cargo-miri` directory; run `./run-test.py` in there to execute it. Like `./miri test`, this respects the From 98c401977bfd0e8a807481e53de6dbaae8cb0974 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 15 Jul 2022 08:09:43 -0400 Subject: [PATCH 3488/3747] rustup --- rust-version | 2 +- src/helpers.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/rust-version b/rust-version index 45abe7e8c653a..86a09bfa57bfc 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -0ed9c64c3e63acac9bd77abce62501696c390450 +6077b7cda466afa2b75a62b232ab46dbeb148bcb diff --git a/src/helpers.rs b/src/helpers.rs index 29bf92af3faf2..d0b0852d010c8 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -259,7 +259,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let mir = this.load_mir(f.def, None)?; let dest = match dest { Some(dest) => *dest, - None => MPlaceTy::dangling(this.layout_of(mir.return_ty())?).into(), + None => MPlaceTy::fake_alloc_zst(this.layout_of(mir.return_ty())?).into(), }; this.push_stack_frame(f, mir, &dest, stack_pop)?; From 9782b7b039ce1fb585c933d8ce64610256399c59 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 16 Jul 2022 23:40:36 -0400 Subject: [PATCH 3489/3747] rustup --- rust-version | 2 +- src/helpers.rs | 2 +- src/shims/backtrace.rs | 2 +- src/shims/windows/foreign_items.rs | 2 -- tests/fail/stacked_borrows/issue-miri-1050-1.rs | 2 +- tests/fail/stacked_borrows/issue-miri-1050-1.stderr | 4 ++-- tests/fail/stacked_borrows/issue-miri-1050-2.rs | 2 +- tests/fail/stacked_borrows/issue-miri-1050-2.stderr | 4 ++-- 8 files changed, 9 insertions(+), 11 deletions(-) diff --git a/rust-version b/rust-version index 86a09bfa57bfc..5396b338cecb3 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -6077b7cda466afa2b75a62b232ab46dbeb148bcb +db41351753df840773ca628d8daa040e95d00eef diff --git a/src/helpers.rs b/src/helpers.rs index d0b0852d010c8..b650e2ddf2255 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -631,7 +631,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Ensure that the access is within bounds. assert!(op_place.layout.size >= offset + layout.size); - let value_place = op_place.offset(offset, MemPlaceMeta::None, layout, this)?; + let value_place = op_place.offset(offset, layout, this)?; Ok(value_place) } diff --git a/src/shims/backtrace.rs b/src/shims/backtrace.rs index 4aa58b45662d8..62e5afbca8bcf 100644 --- a/src/shims/backtrace.rs +++ b/src/shims/backtrace.rs @@ -105,7 +105,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let offset = ptr_layout.size * i.try_into().unwrap(); let op_place = - buf_place.offset(offset, MemPlaceMeta::None, ptr_layout, this)?; + buf_place.offset(offset, ptr_layout, this)?; this.write_pointer(ptr, &op_place.into())?; } diff --git a/src/shims/windows/foreign_items.rs b/src/shims/windows/foreign_items.rs index 0bb082dba9b2f..689d1873d58fd 100644 --- a/src/shims/windows/foreign_items.rs +++ b/src/shims/windows/foreign_items.rs @@ -154,7 +154,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Set page size. let page_size = system_info.offset( field_offsets[2], - MemPlaceMeta::None, dword_layout, &this.tcx, )?; @@ -165,7 +164,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Set number of processors. let num_cpus = system_info.offset( field_offsets[6], - MemPlaceMeta::None, dword_layout, &this.tcx, )?; diff --git a/tests/fail/stacked_borrows/issue-miri-1050-1.rs b/tests/fail/stacked_borrows/issue-miri-1050-1.rs index 6e14b9af146c6..1e44cc6c800ee 100644 --- a/tests/fail/stacked_borrows/issue-miri-1050-1.rs +++ b/tests/fail/stacked_borrows/issue-miri-1050-1.rs @@ -3,6 +3,6 @@ fn main() { unsafe { let ptr = Box::into_raw(Box::new(0u16)); - Box::from_raw(ptr as *mut u32); + drop(Box::from_raw(ptr as *mut u32)); } } diff --git a/tests/fail/stacked_borrows/issue-miri-1050-1.stderr b/tests/fail/stacked_borrows/issue-miri-1050-1.stderr index 946e3e8e66640..4d8488fa76843 100644 --- a/tests/fail/stacked_borrows/issue-miri-1050-1.stderr +++ b/tests/fail/stacked_borrows/issue-miri-1050-1.stderr @@ -12,8 +12,8 @@ LL | Box(unsafe { Unique::new_unchecked(raw) }, alloc) note: inside `main` at $DIR/issue-miri-1050-1.rs:LL:CC --> $DIR/issue-miri-1050-1.rs:LL:CC | -LL | Box::from_raw(ptr as *mut u32); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | drop(Box::from_raw(ptr as *mut u32)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/issue-miri-1050-2.rs b/tests/fail/stacked_borrows/issue-miri-1050-2.rs index 571cb6213fec2..6e90559a9ef5b 100644 --- a/tests/fail/stacked_borrows/issue-miri-1050-2.rs +++ b/tests/fail/stacked_borrows/issue-miri-1050-2.rs @@ -4,6 +4,6 @@ use std::ptr::NonNull; fn main() { unsafe { let ptr = NonNull::::dangling(); - Box::from_raw(ptr.as_ptr()); + drop(Box::from_raw(ptr.as_ptr())); } } diff --git a/tests/fail/stacked_borrows/issue-miri-1050-2.stderr b/tests/fail/stacked_borrows/issue-miri-1050-2.stderr index 33ac311766775..562a82fb610be 100644 --- a/tests/fail/stacked_borrows/issue-miri-1050-2.stderr +++ b/tests/fail/stacked_borrows/issue-miri-1050-2.stderr @@ -12,8 +12,8 @@ LL | Box(unsafe { Unique::new_unchecked(raw) }, alloc) note: inside `main` at $DIR/issue-miri-1050-2.rs:LL:CC --> $DIR/issue-miri-1050-2.rs:LL:CC | -LL | Box::from_raw(ptr.as_ptr()); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | drop(Box::from_raw(ptr.as_ptr())); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace From 43100f5f4b8b8c0b437bfe8b380198cb99e62cc3 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Sun, 17 Jul 2022 07:46:02 +0000 Subject: [PATCH 3490/3747] Remove `--offline` from `./miri install` as otherwise we can't add more dependencies to miri as CI will fail. if you want this locally, pass it to your invocation. --- miri | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/miri b/miri index 7b53b802db62a..bb2fc5b12318d 100755 --- a/miri +++ b/miri @@ -133,10 +133,9 @@ find_sysroot() { # Run command. case "$COMMAND" in install) - # "--locked" to respect the Cargo.lock file if it exists, - # "--offline" to avoid querying the registry (for yanked packages). - $CARGO install $CARGO_EXTRA_FLAGS --path "$MIRIDIR" --force --locked --offline "$@" - $CARGO install $CARGO_EXTRA_FLAGS --path "$MIRIDIR"/cargo-miri --force --locked --offline "$@" + # "--locked" to respect the Cargo.lock file if it exists. + $CARGO install $CARGO_EXTRA_FLAGS --path "$MIRIDIR" --force --locked "$@" + $CARGO install $CARGO_EXTRA_FLAGS --path "$MIRIDIR"/cargo-miri --force --locked "$@" ;; check) # Check, and let caller control flags. From 444841bba9c31f1fe5b7b419ee82eb27e37a344e Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Sun, 17 Jul 2022 07:56:57 +0000 Subject: [PATCH 3491/3747] Add test flag for running a test only on the host --- ui_test/README.md | 2 ++ ui_test/src/lib.rs | 11 ++++++----- ui_test/src/parser.rs | 6 ++++++ 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/ui_test/README.md b/ui_test/README.md index 55639c9589e10..4ecebcc8ddb24 100644 --- a/ui_test/README.md +++ b/ui_test/README.md @@ -25,8 +25,10 @@ their command specifies, or the test will fail without even being run. * `//@ignore-XXX` avoids running the test on targets whose triple contains `XXX` * `XXX` can also be one of `64bit`, `32bit` or `16bit` + * `XXX` can also be `on-host`, which will only run the test during cross compilation testing. * `//@only-XXX` avoids running the test on targets whose triple **does not** contain `XXX` * `XXX` can also be one of `64bit`, `32bit` or `16bit` + * `XXX` can also be `on-host`, which will not run the test during cross compilation testing * `//@stderr-per-bitwidth` produces one stderr file per bitwidth, as they may differ significantly sometimes * `//@error-pattern: XXX` make sure the stderr output contains `XXX` * `//@revisions: XXX YYY` runs the test once for each space separated name in the list diff --git a/ui_test/src/lib.rs b/ui_test/src/lib.rs index 32c04290bca20..16f7be30f8b2e 100644 --- a/ui_test/src/lib.rs +++ b/ui_test/src/lib.rs @@ -109,7 +109,7 @@ pub fn run_tests(config: Config) -> Result<()> { } let comments = Comments::parse_file(&path)?; // Ignore file if only/ignore rules do (not) apply - if !test_file_conditions(&comments, &target) { + if !test_file_conditions(&comments, &target, &config) { ignored.fetch_add(1, Ordering::Relaxed); eprintln!( "{} ... {}", @@ -499,19 +499,20 @@ fn output_path(path: &Path, comments: &Comments, kind: String, target: &str) -> path.with_extension(kind) } -fn test_condition(condition: &Condition, target: &str) -> bool { +fn test_condition(condition: &Condition, target: &str, config: &Config) -> bool { match condition { Condition::Bitwidth(bits) => get_pointer_width(target) == *bits, Condition::Target(t) => target.contains(t), + Condition::OnHost => config.target.is_none(), } } /// Returns whether according to the in-file conditions, this file should be run. -fn test_file_conditions(comments: &Comments, target: &str) -> bool { - if comments.ignore.iter().any(|c| test_condition(c, target)) { +fn test_file_conditions(comments: &Comments, target: &str, config: &Config) -> bool { + if comments.ignore.iter().any(|c| test_condition(c, target, config)) { return false; } - comments.only.iter().all(|c| test_condition(c, target)) + comments.only.iter().all(|c| test_condition(c, target, config)) } // Taken 1:1 from compiletest-rs diff --git a/ui_test/src/parser.rs b/ui_test/src/parser.rs index 7d810a95e4122..994c0800fcc17 100644 --- a/ui_test/src/parser.rs +++ b/ui_test/src/parser.rs @@ -43,6 +43,8 @@ pub(crate) enum Condition { Target(String), /// Tests that the bitwidth is the given one. Bitwidth(u8), + /// Tests that the target is the host. + OnHost, } #[derive(Debug, Clone)] @@ -64,6 +66,10 @@ pub(crate) struct ErrorMatch { impl Condition { fn parse(c: &str) -> Self { + match c { + "on-host" => return Condition::OnHost, + _ => {} + } if let Some(bits) = c.strip_suffix("bit") { let bits: u8 = bits.parse().expect( "ignore/only filter ending in 'bit' must be of the form 'Nbit' for some integer N", From 8527bfc63b8c6eb9451e1adb08c39cc4d54c1bc5 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Sun, 17 Jul 2022 08:07:26 +0000 Subject: [PATCH 3492/3747] clippy --- ui_test/src/parser.rs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/ui_test/src/parser.rs b/ui_test/src/parser.rs index 994c0800fcc17..e7fb484434d79 100644 --- a/ui_test/src/parser.rs +++ b/ui_test/src/parser.rs @@ -66,11 +66,9 @@ pub(crate) struct ErrorMatch { impl Condition { fn parse(c: &str) -> Self { - match c { - "on-host" => return Condition::OnHost, - _ => {} - } - if let Some(bits) = c.strip_suffix("bit") { + if c == "on-host" { + Condition::OnHost + } else if let Some(bits) = c.strip_suffix("bit") { let bits: u8 = bits.parse().expect( "ignore/only filter ending in 'bit' must be of the form 'Nbit' for some integer N", ); From e8ab64e424a377cdb5d6373b10d4d6ed68e38f13 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 16 Jul 2022 23:44:37 -0400 Subject: [PATCH 3493/3747] make unused flags work like they used to --- src/shims/backtrace.rs | 3 +-- src/shims/windows/foreign_items.rs | 12 ++---------- tests/compiletest.rs | 3 ++- 3 files changed, 5 insertions(+), 13 deletions(-) diff --git a/src/shims/backtrace.rs b/src/shims/backtrace.rs index 62e5afbca8bcf..5b39f2a48aae9 100644 --- a/src/shims/backtrace.rs +++ b/src/shims/backtrace.rs @@ -104,8 +104,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx for (i, ptr) in ptrs.into_iter().enumerate() { let offset = ptr_layout.size * i.try_into().unwrap(); - let op_place = - buf_place.offset(offset, ptr_layout, this)?; + let op_place = buf_place.offset(offset, ptr_layout, this)?; this.write_pointer(ptr, &op_place.into())?; } diff --git a/src/shims/windows/foreign_items.rs b/src/shims/windows/foreign_items.rs index 689d1873d58fd..28e60a68048cc 100644 --- a/src/shims/windows/foreign_items.rs +++ b/src/shims/windows/foreign_items.rs @@ -152,21 +152,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx .collect(); // Set page size. - let page_size = system_info.offset( - field_offsets[2], - dword_layout, - &this.tcx, - )?; + let page_size = system_info.offset(field_offsets[2], dword_layout, &this.tcx)?; this.write_scalar( Scalar::from_int(PAGE_SIZE, dword_layout.size), &page_size.into(), )?; // Set number of processors. - let num_cpus = system_info.offset( - field_offsets[6], - dword_layout, - &this.tcx, - )?; + let num_cpus = system_info.offset(field_offsets[6], dword_layout, &this.tcx)?; this.write_scalar(Scalar::from_int(NUM_CPUS, dword_layout.size), &num_cpus.into())?; } diff --git a/tests/compiletest.rs b/tests/compiletest.rs index c568d1c50434c..ec49e80ca9633 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -19,9 +19,10 @@ fn run_tests(mode: Mode, path: &str, target: Option) -> Result<()> { // Less aggressive warnings to make the rustc toolstate management less painful. // (We often get warnings when e.g. a feature gets stabilized or some lint gets added/improved.) flags.push("-Astable-features".to_owned()); + flags.push("-Aunused".to_owned()); } else { flags.push("-Dwarnings".to_owned()); - flags.push("-Dunused".to_owned()); // overwrite the -Aunused in compiletest-rs + flags.push("-Dunused".to_owned()); } if let Ok(sysroot) = env::var("MIRI_SYSROOT") { flags.push("--sysroot".to_string()); From 68510600a3f8f69fab24bbb256918b4fe46ba639 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 17 Jul 2022 10:19:29 -0400 Subject: [PATCH 3494/3747] use PlaceTy visitor --- src/stacked_borrows/mod.rs | 34 +++++++++++++++------------------- 1 file changed, 15 insertions(+), 19 deletions(-) diff --git a/src/stacked_borrows/mod.rs b/src/stacked_borrows/mod.rs index d9ccc773a0181..d1e9ae1c57044 100644 --- a/src/stacked_borrows/mod.rs +++ b/src/stacked_borrows/mod.rs @@ -1037,17 +1037,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Raw pointers need to be enabled. ty::RawPtr(tym) if kind == RetagKind::Raw => Some((RefKind::Raw { mutable: tym.mutbl == Mutability::Mut }, false)), - // Boxes are handled separately due to that allocator situation. + // Boxes are handled separately due to that allocator situation, + // see the visitor below. _ => None, } } - // We need a visitor to visit all references. However, that requires - // a `MPlaceTy` (or `OpTy`), so we have a fast path for reference types that - // avoids allocating. - + // For some types we can do the work without starting up the visitor infrastructure. if let Some((ref_kind, protector)) = qualify(place.layout.ty, kind) { - // Fast path. let val = this.read_immediate(&this.place_to_op(place)?)?; let val = this.retag_reference(&val, ref_kind, protector)?; this.write_immediate(*val, place)?; @@ -1077,11 +1074,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) { return Ok(()); } - // Now go visit this thing. - let place = this.force_allocation(place)?; + // Now go visit this thing. let mut visitor = RetagVisitor { ecx: this, kind }; - return visitor.visit_value(&place); + return visitor.visit_value(place); // The actual visitor. struct RetagVisitor<'ecx, 'mir, 'tcx> { @@ -1091,36 +1087,36 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx impl<'ecx, 'mir, 'tcx> MutValueVisitor<'mir, 'tcx, Evaluator<'mir, 'tcx>> for RetagVisitor<'ecx, 'mir, 'tcx> { - type V = MPlaceTy<'tcx, Tag>; + type V = PlaceTy<'tcx, Tag>; #[inline(always)] fn ecx(&mut self) -> &mut MiriEvalContext<'mir, 'tcx> { self.ecx } - fn visit_box(&mut self, place: &MPlaceTy<'tcx, Tag>) -> InterpResult<'tcx> { + fn visit_box(&mut self, place: &PlaceTy<'tcx, Tag>) -> InterpResult<'tcx> { // Boxes do not get a protector: protectors reflect that references outlive the call // they were passed in to; that's just not the case for boxes. let (ref_kind, protector) = (RefKind::Unique { two_phase: false }, false); - - let val = self.ecx.read_immediate(&place.into())?; + let val = self.ecx.read_immediate(&self.ecx.place_to_op(place)?)?; let val = self.ecx.retag_reference(&val, ref_kind, protector)?; - self.ecx.write_immediate(*val, &place.into())?; + self.ecx.write_immediate(*val, place)?; Ok(()) } - fn visit_value(&mut self, place: &MPlaceTy<'tcx, Tag>) -> InterpResult<'tcx> { + fn visit_value(&mut self, place: &PlaceTy<'tcx, Tag>) -> InterpResult<'tcx> { if let Some((ref_kind, protector)) = qualify(place.layout.ty, self.kind) { - let val = self.ecx.read_immediate(&place.into())?; + let val = self.ecx.read_immediate(&self.ecx.place_to_op(place)?)?; let val = self.ecx.retag_reference(&val, ref_kind, protector)?; - self.ecx.write_immediate(*val, &place.into())?; + self.ecx.write_immediate(*val, place)?; } else if matches!(place.layout.ty.kind(), ty::RawPtr(..)) { // Wide raw pointers *do* have fields and their types are strange. // vtables have a type like `&[*const (); 3]` or so! // Do *not* recurse into them. - // (No need to worry about wide references or boxes, those always "qualify".) + // (No need to worry about wide references, those always "qualify". And Boxes + // are handles specially by the visitor anyway.) } else { - // Maybe we need to go deeper. + // Recurse deeper. self.walk_value(place)?; } Ok(()) From 39866f817a002505f63f0e5d7ff06b9e99453015 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 17 Jul 2022 10:32:03 -0400 Subject: [PATCH 3495/3747] remove a fastpath that does not seem to actually help --- src/stacked_borrows/mod.rs | 77 +++++++++++++++----------------------- 1 file changed, 31 insertions(+), 46 deletions(-) diff --git a/src/stacked_borrows/mod.rs b/src/stacked_borrows/mod.rs index d1e9ae1c57044..9040d03632ed9 100644 --- a/src/stacked_borrows/mod.rs +++ b/src/stacked_borrows/mod.rs @@ -1021,6 +1021,10 @@ impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mi pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { fn retag(&mut self, kind: RetagKind, place: &PlaceTy<'tcx, Tag>) -> InterpResult<'tcx> { let this = self.eval_context_mut(); + let retag_fields = this.machine.stacked_borrows.as_mut().unwrap().get_mut().retag_fields; + let mut visitor = RetagVisitor { ecx: this, kind, retag_fields }; + return visitor.visit_value(place); + // Determine mutability and whether to add a protector. // Cannot use `builtin_deref` because that reports *immutable* for `Box`, // making it useless. @@ -1043,46 +1047,25 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } - // For some types we can do the work without starting up the visitor infrastructure. - if let Some((ref_kind, protector)) = qualify(place.layout.ty, kind) { - let val = this.read_immediate(&this.place_to_op(place)?)?; - let val = this.retag_reference(&val, ref_kind, protector)?; - this.write_immediate(*val, place)?; - return Ok(()); - } - - // If we don't want to recurse, we are already done. - // EXCEPT if this is a `Box`, then we have to recurse because allocators. - // (Yes this means we technically also recursively retag the allocator itself even if field - // retagging is not enabled. *shrug*) - if !this.machine.stacked_borrows.as_mut().unwrap().get_mut().retag_fields - && !place.layout.ty.ty_adt_def().is_some_and(|adt| adt.is_box()) - { - return Ok(()); - } - - // Skip some types that have no further structure we might care about. - if matches!( - place.layout.ty.kind(), - ty::RawPtr(..) - | ty::Ref(..) - | ty::Int(..) - | ty::Uint(..) - | ty::Float(..) - | ty::Bool - | ty::Char - ) { - return Ok(()); - } - - // Now go visit this thing. - let mut visitor = RetagVisitor { ecx: this, kind }; - return visitor.visit_value(place); - // The actual visitor. struct RetagVisitor<'ecx, 'mir, 'tcx> { ecx: &'ecx mut MiriEvalContext<'mir, 'tcx>, kind: RetagKind, + retag_fields: bool, + } + impl<'ecx, 'mir, 'tcx> RetagVisitor<'ecx, 'mir, 'tcx> { + #[inline(always)] // yes this helps in our benchmarks + fn retag_place( + &mut self, + place: &PlaceTy<'tcx, Tag>, + ref_kind: RefKind, + protector: bool, + ) -> InterpResult<'tcx> { + let val = self.ecx.read_immediate(&self.ecx.place_to_op(place)?)?; + let val = self.ecx.retag_reference(&val, ref_kind, protector)?; + self.ecx.write_immediate(*val, place)?; + Ok(()) + } } impl<'ecx, 'mir, 'tcx> MutValueVisitor<'mir, 'tcx, Evaluator<'mir, 'tcx>> for RetagVisitor<'ecx, 'mir, 'tcx> @@ -1097,26 +1080,28 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn visit_box(&mut self, place: &PlaceTy<'tcx, Tag>) -> InterpResult<'tcx> { // Boxes do not get a protector: protectors reflect that references outlive the call // they were passed in to; that's just not the case for boxes. - let (ref_kind, protector) = (RefKind::Unique { two_phase: false }, false); - let val = self.ecx.read_immediate(&self.ecx.place_to_op(place)?)?; - let val = self.ecx.retag_reference(&val, ref_kind, protector)?; - self.ecx.write_immediate(*val, place)?; - Ok(()) + self.retag_place( + place, + RefKind::Unique { two_phase: false }, + /*protector*/ false, + ) } fn visit_value(&mut self, place: &PlaceTy<'tcx, Tag>) -> InterpResult<'tcx> { if let Some((ref_kind, protector)) = qualify(place.layout.ty, self.kind) { - let val = self.ecx.read_immediate(&self.ecx.place_to_op(place)?)?; - let val = self.ecx.retag_reference(&val, ref_kind, protector)?; - self.ecx.write_immediate(*val, place)?; + self.retag_place(place, ref_kind, protector)?; } else if matches!(place.layout.ty.kind(), ty::RawPtr(..)) { // Wide raw pointers *do* have fields and their types are strange. // vtables have a type like `&[*const (); 3]` or so! // Do *not* recurse into them. // (No need to worry about wide references, those always "qualify". And Boxes // are handles specially by the visitor anyway.) - } else { - // Recurse deeper. + } else if self.retag_fields + || place.layout.ty.ty_adt_def().is_some_and(|adt| adt.is_box()) + { + // Recurse deeper. Need to always recurse for `Box` to even hit `visit_box`. + // (Yes this means we technically also recursively retag the allocator itself + // even if field retagging is not enabled. *shrug*) self.walk_value(place)?; } Ok(()) From 2f84cb34c11b4a6127b687ae6c353f33e3edeee7 Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Fri, 8 Jul 2022 14:48:26 -0400 Subject: [PATCH 3496/3747] Pass through isatty if the host is also unix --- src/shims/unix/foreign_items.rs | 8 ++--- src/shims/unix/fs.rs | 61 +++++++++++++++++++++++++++++++++ 2 files changed, 63 insertions(+), 6 deletions(-) diff --git a/src/shims/unix/foreign_items.rs b/src/shims/unix/foreign_items.rs index 44147433c037e..57dfd6f1810c2 100644 --- a/src/shims/unix/foreign_items.rs +++ b/src/shims/unix/foreign_items.rs @@ -440,12 +440,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Miscellaneous "isatty" => { let [fd] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; - this.read_scalar(fd)?.to_i32()?; - // "returns 1 if fd is an open file descriptor referring to a terminal; otherwise 0 is returned, and errno is set to indicate the error" - // FIXME: we just say nothing is a terminal. - let enotty = this.eval_libc("ENOTTY")?; - this.set_last_error(enotty)?; - this.write_null(dest)?; + let result = this.isatty(fd)?; + this.write_scalar(Scalar::from_i32(result), dest)?; } "pthread_atfork" => { let [prepare, parent, child] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; diff --git a/src/shims/unix/fs.rs b/src/shims/unix/fs.rs index c7d7789f03ab7..3fdf82ebc6a74 100644 --- a/src/shims/unix/fs.rs +++ b/src/shims/unix/fs.rs @@ -50,6 +50,9 @@ trait FileDescriptor: std::fmt::Debug { ) -> InterpResult<'tcx, io::Result>; fn dup(&mut self) -> io::Result>; + + #[cfg(unix)] + fn as_unix_host_fd(&self) -> Option; } impl FileDescriptor for FileHandle { @@ -114,6 +117,12 @@ impl FileDescriptor for FileHandle { let duplicated = self.file.try_clone()?; Ok(Box::new(FileHandle { file: duplicated, writable: self.writable })) } + + #[cfg(unix)] + fn as_unix_host_fd(&self) -> Option { + use std::os::unix::io::AsRawFd; + Some(self.file.as_raw_fd()) + } } impl FileDescriptor for io::Stdin { @@ -159,6 +168,11 @@ impl FileDescriptor for io::Stdin { fn dup(&mut self) -> io::Result> { Ok(Box::new(io::stdin())) } + + #[cfg(unix)] + fn as_unix_host_fd(&self) -> Option { + Some(libc::STDIN_FILENO) + } } impl FileDescriptor for io::Stdout { @@ -209,6 +223,11 @@ impl FileDescriptor for io::Stdout { fn dup(&mut self) -> io::Result> { Ok(Box::new(io::stdout())) } + + #[cfg(unix)] + fn as_unix_host_fd(&self) -> Option { + Some(libc::STDOUT_FILENO) + } } impl FileDescriptor for io::Stderr { @@ -252,6 +271,11 @@ impl FileDescriptor for io::Stderr { fn dup(&mut self) -> io::Result> { Ok(Box::new(io::stderr())) } + + #[cfg(unix)] + fn as_unix_host_fd(&self) -> Option { + Some(libc::STDERR_FILENO) + } } #[derive(Debug)] @@ -297,6 +321,11 @@ impl FileDescriptor for DummyOutput { fn dup<'tcx>(&mut self) -> io::Result> { Ok(Box::new(DummyOutput)) } + + #[cfg(unix)] + fn as_unix_host_fd(&self) -> Option { + None + } } #[derive(Debug)] @@ -1660,6 +1689,38 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } } + + #[cfg_attr(not(unix), allow(unused))] + fn isatty(&mut self, miri_fd: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + let this = self.eval_context_mut(); + #[cfg(unix)] + { + let miri_fd = this.read_scalar(miri_fd)?.to_i32()?; + if let Some(host_fd) = + this.machine.file_handler.handles.get(&miri_fd).and_then(|fd| fd.as_unix_host_fd()) + { + // "returns 1 if fd is an open file descriptor referring to a terminal; + // otherwise 0 is returned, and errno is set to indicate the error" + // SAFETY: isatty has no preconditions + let is_tty = unsafe { libc::isatty(host_fd) }; + if is_tty == 0 { + let errno = std::io::Error::last_os_error() + .raw_os_error() + .map(Scalar::from_i32) + .unwrap(); + this.set_last_error(errno)?; + } + return Ok(is_tty); + } + } + // We are attemping to use a Unix interface on a non-Unix platform, or we are on a Unix + // platform and the passed file descriptor is not open. + // FIXME: It should be possible to emulate this at least on Windows by using + // GetConsoleMode. + let enotty = this.eval_libc("ENOTTY")?; + this.set_last_error(enotty)?; + Ok(0) + } } /// Extracts the number of seconds and nanoseconds elapsed between `time` and the unix epoch when From eefdeacdb1aa2515359ba3cedfb04c81d74e783a Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Sun, 17 Jul 2022 21:13:59 -0400 Subject: [PATCH 3497/3747] Test that isatty doesn't crash --- tests/pass/libc.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/tests/pass/libc.rs b/tests/pass/libc.rs index 53c85d2b07d1a..6da5279270715 100644 --- a/tests/pass/libc.rs +++ b/tests/pass/libc.rs @@ -311,6 +311,17 @@ fn test_posix_gettimeofday() { assert_eq!(is_error, -1); } +fn test_isatty() { + // Testing whether our isatty shim returns the right value would require controlling whether + // these streams are actually TTYs, which is hard. + // For now, we just check that these calls are supported at all. + unsafe { + libc::isatty(libc::STDIN_FILENO); + libc::isatty(libc::STDOUT_FILENO); + libc::isatty(libc::STDERR_FILENO); + } +} + fn main() { #[cfg(any(target_os = "linux", target_os = "freebsd"))] test_posix_fadvise(); @@ -335,4 +346,6 @@ fn main() { #[cfg(any(target_os = "linux"))] test_clocks(); + + test_isatty(); } From 896f558f2b8e0bd29cc08f5af5e0edfe07783042 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 17 Jul 2022 21:50:10 -0400 Subject: [PATCH 3498/3747] with isolation we want to be fully deterministic --- src/shims/unix/fs.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/shims/unix/fs.rs b/src/shims/unix/fs.rs index 3fdf82ebc6a74..1420279247f46 100644 --- a/src/shims/unix/fs.rs +++ b/src/shims/unix/fs.rs @@ -1694,7 +1694,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn isatty(&mut self, miri_fd: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); #[cfg(unix)] - { + if matches!(this.machine.isolated_op, IsolatedOp::Allow) { let miri_fd = this.read_scalar(miri_fd)?.to_i32()?; if let Some(host_fd) = this.machine.file_handler.handles.get(&miri_fd).and_then(|fd| fd.as_unix_host_fd()) @@ -1714,7 +1714,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } // We are attemping to use a Unix interface on a non-Unix platform, or we are on a Unix - // platform and the passed file descriptor is not open. + // platform and the passed file descriptor is not open, or isolation is enabled // FIXME: It should be possible to emulate this at least on Windows by using // GetConsoleMode. let enotty = this.eval_libc("ENOTTY")?; From 1c85975768d42e21ec5ead95b5b301f3137c80cf Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 17 Jul 2022 21:54:10 -0400 Subject: [PATCH 3499/3747] ui_test: more robust syntax for target filtering --- .../libc_pthread_create_main_terminate.rs | 2 +- .../fail/concurrency/libc_pthread_join_detached.rs | 2 +- tests/fail/concurrency/libc_pthread_join_joined.rs | 2 +- tests/fail/concurrency/libc_pthread_join_main.rs | 2 +- .../fail/concurrency/libc_pthread_join_multiple.rs | 2 +- tests/fail/concurrency/libc_pthread_join_self.rs | 2 +- tests/fail/concurrency/thread-spawn.rs | 2 +- .../concurrency/thread_local_static_dealloc.rs | 2 +- tests/fail/concurrency/too_few_args.rs | 2 +- tests/fail/concurrency/too_many_args.rs | 2 +- tests/fail/concurrency/unwind_top_of_stack.rs | 2 +- tests/fail/data_race/alloc_read_race.rs | 2 +- tests/fail/data_race/alloc_write_race.rs | 2 +- tests/fail/data_race/atomic_read_na_write_race1.rs | 2 +- tests/fail/data_race/atomic_read_na_write_race2.rs | 2 +- tests/fail/data_race/atomic_write_na_read_race1.rs | 2 +- tests/fail/data_race/atomic_write_na_read_race2.rs | 2 +- .../fail/data_race/atomic_write_na_write_race1.rs | 2 +- .../fail/data_race/atomic_write_na_write_race2.rs | 2 +- tests/fail/data_race/dangling_thread_async_race.rs | 2 +- tests/fail/data_race/dangling_thread_race.rs | 2 +- tests/fail/data_race/dealloc_read_race1.rs | 2 +- tests/fail/data_race/dealloc_read_race2.rs | 2 +- tests/fail/data_race/dealloc_read_race_stack.rs | 2 +- tests/fail/data_race/dealloc_write_race1.rs | 2 +- tests/fail/data_race/dealloc_write_race2.rs | 2 +- tests/fail/data_race/dealloc_write_race_stack.rs | 2 +- tests/fail/data_race/enable_after_join_to_main.rs | 2 +- tests/fail/data_race/fence_after_load.rs | 2 +- tests/fail/data_race/read_write_race.rs | 2 +- tests/fail/data_race/read_write_race_stack.rs | 2 +- tests/fail/data_race/relax_acquire_race.rs | 2 +- tests/fail/data_race/release_seq_race.rs | 2 +- .../fail/data_race/release_seq_race_same_thread.rs | 2 +- tests/fail/data_race/rmw_race.rs | 2 +- tests/fail/data_race/stack_pop_race.rs | 2 +- tests/fail/data_race/write_write_race.rs | 2 +- tests/fail/data_race/write_write_race_stack.rs | 2 +- tests/fail/environ-gets-deallocated.rs | 2 +- tests/fail/fs/close_stdout.rs | 2 +- tests/fail/fs/isolated_file.rs | 2 +- tests/fail/fs/isolated_stdin.rs | 2 +- tests/fail/fs/read_from_stdout.rs | 2 +- tests/fail/fs/unix_open_missing_required_mode.rs | 2 +- tests/fail/fs/write_to_stdin.rs | 2 +- tests/fail/should-pass/cpp20_rwc_syncs.rs | 2 +- .../fail/sync/libc_pthread_cond_double_destroy.rs | 2 +- .../sync/libc_pthread_condattr_double_destroy.rs | 2 +- .../fail/sync/libc_pthread_mutex_NULL_deadlock.rs | 2 +- tests/fail/sync/libc_pthread_mutex_deadlock.rs | 2 +- .../sync/libc_pthread_mutex_default_deadlock.rs | 2 +- .../fail/sync/libc_pthread_mutex_destroy_locked.rs | 2 +- .../fail/sync/libc_pthread_mutex_double_destroy.rs | 2 +- .../sync/libc_pthread_mutex_normal_deadlock.rs | 2 +- .../libc_pthread_mutex_normal_unlock_unlocked.rs | 2 +- tests/fail/sync/libc_pthread_mutex_wrong_owner.rs | 2 +- .../sync/libc_pthread_mutexattr_double_destroy.rs | 2 +- .../libc_pthread_rwlock_destroy_read_locked.rs | 2 +- .../libc_pthread_rwlock_destroy_write_locked.rs | 2 +- .../sync/libc_pthread_rwlock_double_destroy.rs | 2 +- ...ead_rwlock_read_write_deadlock_single_thread.rs | 2 +- .../sync/libc_pthread_rwlock_read_wrong_owner.rs | 2 +- .../sync/libc_pthread_rwlock_unlock_unlocked.rs | 2 +- .../libc_pthread_rwlock_write_read_deadlock.rs | 2 +- ...ead_rwlock_write_read_deadlock_single_thread.rs | 2 +- .../libc_pthread_rwlock_write_write_deadlock.rs | 2 +- ...ad_rwlock_write_write_deadlock_single_thread.rs | 2 +- .../sync/libc_pthread_rwlock_write_wrong_owner.rs | 2 +- tests/fail/unsupported_signal.rs | 2 +- tests/fail/weak_memory/racing_mixed_size.rs | 2 +- tests/fail/weak_memory/racing_mixed_size_read.rs | 2 +- tests/panic/panic/unsupported_syscall.rs | 4 ++-- tests/pass/0weak_memory_consistency.rs | 2 +- tests/pass/calloc.rs | 2 +- tests/pass/concurrency/channels.rs | 2 +- .../pass/concurrency/concurrent_caller_location.rs | 2 +- tests/pass/concurrency/data_race.rs | 2 +- .../pass/concurrency/disable_data_race_detector.rs | 2 +- tests/pass/concurrency/issue1643.rs | 2 +- tests/pass/concurrency/libc_pthread_cond.rs | 4 ++-- tests/pass/concurrency/linux-futex.rs | 2 +- tests/pass/concurrency/simple.rs | 2 +- tests/pass/concurrency/spin_loop.rs | 2 +- tests/pass/concurrency/spin_loops_nopreempt.rs | 2 +- tests/pass/concurrency/sync.rs | 2 +- tests/pass/concurrency/sync_nopreempt.rs | 2 +- tests/pass/concurrency/thread_locals.rs | 2 +- tests/pass/concurrency/tls_lib_drop.rs | 2 +- tests/pass/concurrency/tls_pthread_drop_order.rs | 2 +- tests/pass/fs.rs | 2 +- tests/pass/fs_with_isolation.rs | 2 +- tests/pass/libc.rs | 2 +- tests/pass/linux-getrandom-without-isolation.rs | 2 +- tests/pass/linux-getrandom.rs | 2 +- tests/pass/malloc.rs | 2 +- tests/pass/no_std.rs | 2 +- tests/pass/panic/concurrent-panic.rs | 2 +- tests/pass/threadleak_ignored.rs | 2 +- tests/pass/weak_memory/extra_cpp.rs | 2 +- tests/pass/weak_memory/extra_cpp_unsafe.rs | 2 +- tests/pass/weak_memory/weak.rs | 2 +- tests/pass/wtf8.rs | 2 +- ui_test/src/parser.rs | 14 ++++++++------ 103 files changed, 112 insertions(+), 110 deletions(-) diff --git a/tests/fail/concurrency/libc_pthread_create_main_terminate.rs b/tests/fail/concurrency/libc_pthread_create_main_terminate.rs index ab80cdd205bca..169a021215d5a 100644 --- a/tests/fail/concurrency/libc_pthread_create_main_terminate.rs +++ b/tests/fail/concurrency/libc_pthread_create_main_terminate.rs @@ -1,4 +1,4 @@ -//@ignore-windows: No libc on Windows +//@ignore-target-windows: No libc on Windows //@error-pattern: the main thread terminated without waiting for all remaining threads // Check that we terminate the program when the main thread terminates. diff --git a/tests/fail/concurrency/libc_pthread_join_detached.rs b/tests/fail/concurrency/libc_pthread_join_detached.rs index 1ec1d630ecb90..6f0d45e2dc099 100644 --- a/tests/fail/concurrency/libc_pthread_join_detached.rs +++ b/tests/fail/concurrency/libc_pthread_join_detached.rs @@ -1,4 +1,4 @@ -//@ignore-windows: No libc on Windows +//@ignore-target-windows: No libc on Windows // Joining a detached thread is undefined behavior. diff --git a/tests/fail/concurrency/libc_pthread_join_joined.rs b/tests/fail/concurrency/libc_pthread_join_joined.rs index b067556e51b07..77f59fabca5ea 100644 --- a/tests/fail/concurrency/libc_pthread_join_joined.rs +++ b/tests/fail/concurrency/libc_pthread_join_joined.rs @@ -1,4 +1,4 @@ -//@ignore-windows: No libc on Windows +//@ignore-target-windows: No libc on Windows // Joining an already joined thread is undefined behavior. diff --git a/tests/fail/concurrency/libc_pthread_join_main.rs b/tests/fail/concurrency/libc_pthread_join_main.rs index ebfe8c865e3dc..aff28bcc9b575 100644 --- a/tests/fail/concurrency/libc_pthread_join_main.rs +++ b/tests/fail/concurrency/libc_pthread_join_main.rs @@ -1,4 +1,4 @@ -//@ignore-windows: No libc on Windows +//@ignore-target-windows: No libc on Windows // Joining the main thread is undefined behavior. diff --git a/tests/fail/concurrency/libc_pthread_join_multiple.rs b/tests/fail/concurrency/libc_pthread_join_multiple.rs index 39cd9ff77976f..d4d54d3a23fde 100644 --- a/tests/fail/concurrency/libc_pthread_join_multiple.rs +++ b/tests/fail/concurrency/libc_pthread_join_multiple.rs @@ -1,4 +1,4 @@ -//@ignore-windows: No libc on Windows +//@ignore-target-windows: No libc on Windows // Joining the same thread from multiple threads is undefined behavior. diff --git a/tests/fail/concurrency/libc_pthread_join_self.rs b/tests/fail/concurrency/libc_pthread_join_self.rs index 7b91560ab6b19..b911b2db3a16f 100644 --- a/tests/fail/concurrency/libc_pthread_join_self.rs +++ b/tests/fail/concurrency/libc_pthread_join_self.rs @@ -1,4 +1,4 @@ -//@ignore-windows: No libc on Windows +//@ignore-target-windows: No libc on Windows // We are making scheduler assumptions here. //@compile-flags: -Zmiri-preemption-rate=0 diff --git a/tests/fail/concurrency/thread-spawn.rs b/tests/fail/concurrency/thread-spawn.rs index 650a42b43b5d3..84848e35a0f3e 100644 --- a/tests/fail/concurrency/thread-spawn.rs +++ b/tests/fail/concurrency/thread-spawn.rs @@ -1,4 +1,4 @@ -//@only-windows: Only Windows is not supported. +//@only-target-windows: Only Windows is not supported. use std::thread; diff --git a/tests/fail/concurrency/thread_local_static_dealloc.rs b/tests/fail/concurrency/thread_local_static_dealloc.rs index f638e21901dd7..7c54e3bca7c11 100644 --- a/tests/fail/concurrency/thread_local_static_dealloc.rs +++ b/tests/fail/concurrency/thread_local_static_dealloc.rs @@ -1,4 +1,4 @@ -//@ignore-windows: Concurrency on Windows is not supported yet. +//@ignore-target-windows: Concurrency on Windows is not supported yet. //! Ensure that thread-local statics get deallocated when the thread dies. diff --git a/tests/fail/concurrency/too_few_args.rs b/tests/fail/concurrency/too_few_args.rs index 5d173b3848073..11e97ca290f40 100644 --- a/tests/fail/concurrency/too_few_args.rs +++ b/tests/fail/concurrency/too_few_args.rs @@ -1,4 +1,4 @@ -//@ignore-windows: Concurrency on Windows is not supported yet. +//@ignore-target-windows: Concurrency on Windows is not supported yet. //! The thread function must have exactly one argument. diff --git a/tests/fail/concurrency/too_many_args.rs b/tests/fail/concurrency/too_many_args.rs index 8305765a37a35..dd44207a62551 100644 --- a/tests/fail/concurrency/too_many_args.rs +++ b/tests/fail/concurrency/too_many_args.rs @@ -1,4 +1,4 @@ -//@ignore-windows: Concurrency on Windows is not supported yet. +//@ignore-target-windows: Concurrency on Windows is not supported yet. //! The thread function must have exactly one argument. diff --git a/tests/fail/concurrency/unwind_top_of_stack.rs b/tests/fail/concurrency/unwind_top_of_stack.rs index 3bd9284c7c8a2..179ff9c146e89 100644 --- a/tests/fail/concurrency/unwind_top_of_stack.rs +++ b/tests/fail/concurrency/unwind_top_of_stack.rs @@ -1,4 +1,4 @@ -//@ignore-windows: Concurrency on Windows is not supported yet. +//@ignore-target-windows: Concurrency on Windows is not supported yet. //@compile-flags: -Zmiri-disable-abi-check //! Unwinding past the top frame of a stack is Undefined Behavior. diff --git a/tests/fail/data_race/alloc_read_race.rs b/tests/fail/data_race/alloc_read_race.rs index bdd38ea056933..f3f63aeb2b836 100644 --- a/tests/fail/data_race/alloc_read_race.rs +++ b/tests/fail/data_race/alloc_read_race.rs @@ -1,4 +1,4 @@ -//@ignore-windows: Concurrency on Windows is not supported yet. +//@ignore-target-windows: Concurrency on Windows is not supported yet. //@compile-flags: -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 #![feature(new_uninit)] diff --git a/tests/fail/data_race/alloc_write_race.rs b/tests/fail/data_race/alloc_write_race.rs index 1322f727e6f01..a2738c3879b33 100644 --- a/tests/fail/data_race/alloc_write_race.rs +++ b/tests/fail/data_race/alloc_write_race.rs @@ -1,4 +1,4 @@ -//@ignore-windows: Concurrency on Windows is not supported yet. +//@ignore-target-windows: Concurrency on Windows is not supported yet. //@compile-flags: -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 #![feature(new_uninit)] diff --git a/tests/fail/data_race/atomic_read_na_write_race1.rs b/tests/fail/data_race/atomic_read_na_write_race1.rs index 3cdb9d4a6543e..1ef021edc8cc7 100644 --- a/tests/fail/data_race/atomic_read_na_write_race1.rs +++ b/tests/fail/data_race/atomic_read_na_write_race1.rs @@ -1,6 +1,6 @@ // We want to control preemption here. //@compile-flags: -Zmiri-preemption-rate=0 -//@ignore-windows: Concurrency on Windows is not supported yet. +//@ignore-target-windows: Concurrency on Windows is not supported yet. #![feature(core_intrinsics)] use std::intrinsics; diff --git a/tests/fail/data_race/atomic_read_na_write_race2.rs b/tests/fail/data_race/atomic_read_na_write_race2.rs index 79f9cceb5c9c6..493985f6cf17b 100644 --- a/tests/fail/data_race/atomic_read_na_write_race2.rs +++ b/tests/fail/data_race/atomic_read_na_write_race2.rs @@ -1,6 +1,6 @@ // We want to control preemption here. //@compile-flags: -Zmiri-preemption-rate=0 -//@ignore-windows: Concurrency on Windows is not supported yet. +//@ignore-target-windows: Concurrency on Windows is not supported yet. use std::sync::atomic::AtomicUsize; use std::sync::atomic::Ordering; diff --git a/tests/fail/data_race/atomic_write_na_read_race1.rs b/tests/fail/data_race/atomic_write_na_read_race1.rs index 6e9f37a9c43bd..ca9c28abf1a90 100644 --- a/tests/fail/data_race/atomic_write_na_read_race1.rs +++ b/tests/fail/data_race/atomic_write_na_read_race1.rs @@ -1,6 +1,6 @@ // We want to control preemption here. //@compile-flags: -Zmiri-preemption-rate=0 -//@ignore-windows: Concurrency on Windows is not supported yet. +//@ignore-target-windows: Concurrency on Windows is not supported yet. use std::sync::atomic::AtomicUsize; use std::sync::atomic::Ordering; diff --git a/tests/fail/data_race/atomic_write_na_read_race2.rs b/tests/fail/data_race/atomic_write_na_read_race2.rs index 4ab5abd5a3ee2..77b2945f73715 100644 --- a/tests/fail/data_race/atomic_write_na_read_race2.rs +++ b/tests/fail/data_race/atomic_write_na_read_race2.rs @@ -1,6 +1,6 @@ // We want to control preemption here. //@compile-flags: -Zmiri-preemption-rate=0 -//@ignore-windows: Concurrency on Windows is not supported yet. +//@ignore-target-windows: Concurrency on Windows is not supported yet. #![feature(core_intrinsics)] use std::intrinsics::atomic_store; diff --git a/tests/fail/data_race/atomic_write_na_write_race1.rs b/tests/fail/data_race/atomic_write_na_write_race1.rs index 4c4ec0865cc90..34922dd595ed6 100644 --- a/tests/fail/data_race/atomic_write_na_write_race1.rs +++ b/tests/fail/data_race/atomic_write_na_write_race1.rs @@ -1,6 +1,6 @@ // We want to control preemption here. //@compile-flags: -Zmiri-preemption-rate=0 -//@ignore-windows: Concurrency on Windows is not supported yet. +//@ignore-target-windows: Concurrency on Windows is not supported yet. #![feature(core_intrinsics)] use std::intrinsics::atomic_store; diff --git a/tests/fail/data_race/atomic_write_na_write_race2.rs b/tests/fail/data_race/atomic_write_na_write_race2.rs index 715c2d44b2607..1d242ff3cdd6f 100644 --- a/tests/fail/data_race/atomic_write_na_write_race2.rs +++ b/tests/fail/data_race/atomic_write_na_write_race2.rs @@ -1,6 +1,6 @@ // We want to control preemption here. //@compile-flags: -Zmiri-preemption-rate=0 -//@ignore-windows: Concurrency on Windows is not supported yet. +//@ignore-target-windows: Concurrency on Windows is not supported yet. use std::sync::atomic::AtomicUsize; use std::sync::atomic::Ordering; diff --git a/tests/fail/data_race/dangling_thread_async_race.rs b/tests/fail/data_race/dangling_thread_async_race.rs index 732e89c89907c..6264255265f68 100644 --- a/tests/fail/data_race/dangling_thread_async_race.rs +++ b/tests/fail/data_race/dangling_thread_async_race.rs @@ -1,6 +1,6 @@ // We want to control preemption here. //@compile-flags: -Zmiri-disable-isolation -Zmiri-preemption-rate=0 -//@ignore-windows: Concurrency on Windows is not supported yet. +//@ignore-target-windows: Concurrency on Windows is not supported yet. use std::mem; use std::thread::{sleep, spawn}; diff --git a/tests/fail/data_race/dangling_thread_race.rs b/tests/fail/data_race/dangling_thread_race.rs index 170fa8b774401..6f44fc69dbb77 100644 --- a/tests/fail/data_race/dangling_thread_race.rs +++ b/tests/fail/data_race/dangling_thread_race.rs @@ -1,6 +1,6 @@ // We want to control preemption here. //@compile-flags: -Zmiri-disable-isolation -Zmiri-preemption-rate=0 -//@ignore-windows: Concurrency on Windows is not supported yet. +//@ignore-target-windows: Concurrency on Windows is not supported yet. use std::mem; use std::thread::{sleep, spawn}; diff --git a/tests/fail/data_race/dealloc_read_race1.rs b/tests/fail/data_race/dealloc_read_race1.rs index 80a0fe2111ec6..5349073ec3b78 100644 --- a/tests/fail/data_race/dealloc_read_race1.rs +++ b/tests/fail/data_race/dealloc_read_race1.rs @@ -1,6 +1,6 @@ // We want to control preemption here. //@compile-flags: -Zmiri-preemption-rate=0 -//@ignore-windows: Concurrency on Windows is not supported yet. +//@ignore-target-windows: Concurrency on Windows is not supported yet. use std::thread::spawn; diff --git a/tests/fail/data_race/dealloc_read_race2.rs b/tests/fail/data_race/dealloc_read_race2.rs index 898588a1a0e88..bb9070ef7503c 100644 --- a/tests/fail/data_race/dealloc_read_race2.rs +++ b/tests/fail/data_race/dealloc_read_race2.rs @@ -1,6 +1,6 @@ // We want to control preemption here. //@compile-flags: -Zmiri-preemption-rate=0 -//@ignore-windows: Concurrency on Windows is not supported yet. +//@ignore-target-windows: Concurrency on Windows is not supported yet. use std::thread::spawn; diff --git a/tests/fail/data_race/dealloc_read_race_stack.rs b/tests/fail/data_race/dealloc_read_race_stack.rs index 475379a02ecfe..e114fbb8b4f11 100644 --- a/tests/fail/data_race/dealloc_read_race_stack.rs +++ b/tests/fail/data_race/dealloc_read_race_stack.rs @@ -1,4 +1,4 @@ -//@ignore-windows: Concurrency on Windows is not supported yet. +//@ignore-target-windows: Concurrency on Windows is not supported yet. //@compile-flags: -Zmiri-disable-isolation -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 use std::ptr::null_mut; diff --git a/tests/fail/data_race/dealloc_write_race1.rs b/tests/fail/data_race/dealloc_write_race1.rs index 711b7ba9d4eb7..35949920e102e 100644 --- a/tests/fail/data_race/dealloc_write_race1.rs +++ b/tests/fail/data_race/dealloc_write_race1.rs @@ -1,6 +1,6 @@ // We want to control preemption here. //@compile-flags: -Zmiri-preemption-rate=0 -//@ignore-windows: Concurrency on Windows is not supported yet. +//@ignore-target-windows: Concurrency on Windows is not supported yet. use std::thread::spawn; diff --git a/tests/fail/data_race/dealloc_write_race2.rs b/tests/fail/data_race/dealloc_write_race2.rs index e7b7d558ed9df..b569086c8c34e 100644 --- a/tests/fail/data_race/dealloc_write_race2.rs +++ b/tests/fail/data_race/dealloc_write_race2.rs @@ -1,6 +1,6 @@ // We want to control preemption here. //@compile-flags: -Zmiri-preemption-rate=0 -//@ignore-windows: Concurrency on Windows is not supported yet. +//@ignore-target-windows: Concurrency on Windows is not supported yet. use std::thread::spawn; diff --git a/tests/fail/data_race/dealloc_write_race_stack.rs b/tests/fail/data_race/dealloc_write_race_stack.rs index 7f6beb7f32d83..0c74c7adf59cb 100644 --- a/tests/fail/data_race/dealloc_write_race_stack.rs +++ b/tests/fail/data_race/dealloc_write_race_stack.rs @@ -1,4 +1,4 @@ -//@ignore-windows: Concurrency on Windows is not supported yet. +//@ignore-target-windows: Concurrency on Windows is not supported yet. //@compile-flags: -Zmiri-disable-isolation -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 use std::ptr::null_mut; diff --git a/tests/fail/data_race/enable_after_join_to_main.rs b/tests/fail/data_race/enable_after_join_to_main.rs index 2e9fce198d1d4..f2235b95257b3 100644 --- a/tests/fail/data_race/enable_after_join_to_main.rs +++ b/tests/fail/data_race/enable_after_join_to_main.rs @@ -1,6 +1,6 @@ // We want to control preemption here. //@compile-flags: -Zmiri-preemption-rate=0 -//@ignore-windows: Concurrency on Windows is not supported yet. +//@ignore-target-windows: Concurrency on Windows is not supported yet. use std::thread::spawn; diff --git a/tests/fail/data_race/fence_after_load.rs b/tests/fail/data_race/fence_after_load.rs index f41c7a25523e8..8acbe12e82d62 100644 --- a/tests/fail/data_race/fence_after_load.rs +++ b/tests/fail/data_race/fence_after_load.rs @@ -1,6 +1,6 @@ // We want to control preemption here. //@compile-flags: -Zmiri-disable-isolation -Zmiri-preemption-rate=0 -//@ignore-windows: Concurrency on Windows is not supported yet. +//@ignore-target-windows: Concurrency on Windows is not supported yet. use std::sync::atomic::{fence, AtomicUsize, Ordering}; use std::sync::Arc; use std::thread; diff --git a/tests/fail/data_race/read_write_race.rs b/tests/fail/data_race/read_write_race.rs index e1134669f7821..cff868fb699fe 100644 --- a/tests/fail/data_race/read_write_race.rs +++ b/tests/fail/data_race/read_write_race.rs @@ -1,6 +1,6 @@ // We want to control preemption here. //@compile-flags: -Zmiri-preemption-rate=0 -//@ignore-windows: Concurrency on Windows is not supported yet. +//@ignore-target-windows: Concurrency on Windows is not supported yet. use std::thread::spawn; diff --git a/tests/fail/data_race/read_write_race_stack.rs b/tests/fail/data_race/read_write_race_stack.rs index 802e90d222af0..b22173fa5a94a 100644 --- a/tests/fail/data_race/read_write_race_stack.rs +++ b/tests/fail/data_race/read_write_race_stack.rs @@ -1,4 +1,4 @@ -//@ignore-windows: Concurrency on Windows is not supported yet. +//@ignore-target-windows: Concurrency on Windows is not supported yet. //@compile-flags: -Zmiri-disable-isolation -Zmir-opt-level=0 -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 // Note: mir-opt-level set to 0 to prevent the read of stack_var in thread 1 diff --git a/tests/fail/data_race/relax_acquire_race.rs b/tests/fail/data_race/relax_acquire_race.rs index 4238372f21fad..b99388b8923c0 100644 --- a/tests/fail/data_race/relax_acquire_race.rs +++ b/tests/fail/data_race/relax_acquire_race.rs @@ -1,4 +1,4 @@ -//@ignore-windows: Concurrency on Windows is not supported yet. +//@ignore-target-windows: Concurrency on Windows is not supported yet. //@compile-flags: -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 use std::sync::atomic::{AtomicUsize, Ordering}; diff --git a/tests/fail/data_race/release_seq_race.rs b/tests/fail/data_race/release_seq_race.rs index cd11aac95955f..31fc5d9a479f3 100644 --- a/tests/fail/data_race/release_seq_race.rs +++ b/tests/fail/data_race/release_seq_race.rs @@ -1,4 +1,4 @@ -//@ignore-windows: Concurrency on Windows is not supported yet. +//@ignore-target-windows: Concurrency on Windows is not supported yet. //@compile-flags: -Zmiri-disable-isolation -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 use std::sync::atomic::{AtomicUsize, Ordering}; diff --git a/tests/fail/data_race/release_seq_race_same_thread.rs b/tests/fail/data_race/release_seq_race_same_thread.rs index 854ea09f11ebb..c0ce437047a8a 100644 --- a/tests/fail/data_race/release_seq_race_same_thread.rs +++ b/tests/fail/data_race/release_seq_race_same_thread.rs @@ -1,4 +1,4 @@ -//@ignore-windows: Concurrency on Windows is not supported yet. +//@ignore-target-windows: Concurrency on Windows is not supported yet. //@compile-flags: -Zmiri-disable-isolation -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 use std::sync::atomic::{AtomicUsize, Ordering}; diff --git a/tests/fail/data_race/rmw_race.rs b/tests/fail/data_race/rmw_race.rs index 2f7f8986a49e1..540b01b0935d3 100644 --- a/tests/fail/data_race/rmw_race.rs +++ b/tests/fail/data_race/rmw_race.rs @@ -1,4 +1,4 @@ -//@ignore-windows: Concurrency on Windows is not supported yet. +//@ignore-target-windows: Concurrency on Windows is not supported yet. //@compile-flags: -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 use std::sync::atomic::{AtomicUsize, Ordering}; diff --git a/tests/fail/data_race/stack_pop_race.rs b/tests/fail/data_race/stack_pop_race.rs index 444c28d50aaf5..8f371a680f11d 100644 --- a/tests/fail/data_race/stack_pop_race.rs +++ b/tests/fail/data_race/stack_pop_race.rs @@ -1,4 +1,4 @@ -//@ignore-windows: Concurrency on Windows is not supported yet. +//@ignore-target-windows: Concurrency on Windows is not supported yet. //@compile-flags: -Zmiri-preemption-rate=0 use std::thread; diff --git a/tests/fail/data_race/write_write_race.rs b/tests/fail/data_race/write_write_race.rs index fae4582e7e470..ac75c771e4751 100644 --- a/tests/fail/data_race/write_write_race.rs +++ b/tests/fail/data_race/write_write_race.rs @@ -1,6 +1,6 @@ // We want to control preemption here. //@compile-flags: -Zmiri-preemption-rate=0 -//@ignore-windows: Concurrency on Windows is not supported yet. +//@ignore-target-windows: Concurrency on Windows is not supported yet. use std::thread::spawn; diff --git a/tests/fail/data_race/write_write_race_stack.rs b/tests/fail/data_race/write_write_race_stack.rs index 4b83413b39224..5193b155512c1 100644 --- a/tests/fail/data_race/write_write_race_stack.rs +++ b/tests/fail/data_race/write_write_race_stack.rs @@ -1,4 +1,4 @@ -//@ignore-windows: Concurrency on Windows is not supported yet. +//@ignore-target-windows: Concurrency on Windows is not supported yet. //@compile-flags: -Zmiri-disable-isolation -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 use std::ptr::null_mut; diff --git a/tests/fail/environ-gets-deallocated.rs b/tests/fail/environ-gets-deallocated.rs index 39629610c6320..e4597140b8440 100644 --- a/tests/fail/environ-gets-deallocated.rs +++ b/tests/fail/environ-gets-deallocated.rs @@ -1,4 +1,4 @@ -//@ignore-windows: Windows does not have a global environ list that the program can access directly +//@ignore-target-windows: Windows does not have a global environ list that the program can access directly #[cfg(any(target_os = "linux", target_os = "freebsd"))] fn get_environ() -> *const *const u8 { diff --git a/tests/fail/fs/close_stdout.rs b/tests/fail/fs/close_stdout.rs index 3271722de0f9e..bc709fe36d578 100644 --- a/tests/fail/fs/close_stdout.rs +++ b/tests/fail/fs/close_stdout.rs @@ -1,4 +1,4 @@ -//@ignore-windows: No libc on Windows +//@ignore-target-windows: No libc on Windows //@compile-flags: -Zmiri-disable-isolation // FIXME: standard handles cannot be closed (https://github.com/rust-lang/rust/issues/40032) diff --git a/tests/fail/fs/isolated_file.rs b/tests/fail/fs/isolated_file.rs index 00bb492147a8c..9b664ffe52acd 100644 --- a/tests/fail/fs/isolated_file.rs +++ b/tests/fail/fs/isolated_file.rs @@ -1,4 +1,4 @@ -//@ignore-windows: File handling is not implemented yet +//@ignore-target-windows: File handling is not implemented yet //@error-pattern: `open` not available when isolation is enabled fn main() { diff --git a/tests/fail/fs/isolated_stdin.rs b/tests/fail/fs/isolated_stdin.rs index 27c66c58eb2f8..cd54de3bcecc3 100644 --- a/tests/fail/fs/isolated_stdin.rs +++ b/tests/fail/fs/isolated_stdin.rs @@ -1,4 +1,4 @@ -//@ignore-windows: No libc on Windows +//@ignore-target-windows: No libc on Windows #![feature(rustc_private)] diff --git a/tests/fail/fs/read_from_stdout.rs b/tests/fail/fs/read_from_stdout.rs index d78bc9f34d7d3..949fe88f43336 100644 --- a/tests/fail/fs/read_from_stdout.rs +++ b/tests/fail/fs/read_from_stdout.rs @@ -1,5 +1,5 @@ //@compile-flags: -Zmiri-disable-isolation -//@ignore-windows: No libc on Windows +//@ignore-target-windows: No libc on Windows #![feature(rustc_private)] diff --git a/tests/fail/fs/unix_open_missing_required_mode.rs b/tests/fail/fs/unix_open_missing_required_mode.rs index 03993db81f576..1f6beadcb82ff 100644 --- a/tests/fail/fs/unix_open_missing_required_mode.rs +++ b/tests/fail/fs/unix_open_missing_required_mode.rs @@ -1,4 +1,4 @@ -//@ignore-windows: No libc on Windows +//@ignore-target-windows: No libc on Windows //@compile-flags: -Zmiri-disable-isolation #![feature(rustc_private)] diff --git a/tests/fail/fs/write_to_stdin.rs b/tests/fail/fs/write_to_stdin.rs index 78ea0f4a18bd5..4ad7b648e1cfa 100644 --- a/tests/fail/fs/write_to_stdin.rs +++ b/tests/fail/fs/write_to_stdin.rs @@ -1,4 +1,4 @@ -//@ignore-windows: No libc on Windows +//@ignore-target-windows: No libc on Windows #![feature(rustc_private)] diff --git a/tests/fail/should-pass/cpp20_rwc_syncs.rs b/tests/fail/should-pass/cpp20_rwc_syncs.rs index 6478f446accc4..dbac6469fbab8 100644 --- a/tests/fail/should-pass/cpp20_rwc_syncs.rs +++ b/tests/fail/should-pass/cpp20_rwc_syncs.rs @@ -1,4 +1,4 @@ -//@ignore-windows: Concurrency on Windows is not supported yet. +//@ignore-target-windows: Concurrency on Windows is not supported yet. //@compile-flags: -Zmiri-ignore-leaks //@error-pattern: unreachable diff --git a/tests/fail/sync/libc_pthread_cond_double_destroy.rs b/tests/fail/sync/libc_pthread_cond_double_destroy.rs index 77235d485cde7..d0a4ac46cb330 100644 --- a/tests/fail/sync/libc_pthread_cond_double_destroy.rs +++ b/tests/fail/sync/libc_pthread_cond_double_destroy.rs @@ -1,4 +1,4 @@ -//@ignore-windows: No libc on Windows +//@ignore-target-windows: No libc on Windows #![feature(rustc_private)] /// Test that destroying a pthread_cond twice fails, even without a check for number validity diff --git a/tests/fail/sync/libc_pthread_condattr_double_destroy.rs b/tests/fail/sync/libc_pthread_condattr_double_destroy.rs index 3b4522fb046c7..c64b323813841 100644 --- a/tests/fail/sync/libc_pthread_condattr_double_destroy.rs +++ b/tests/fail/sync/libc_pthread_condattr_double_destroy.rs @@ -1,4 +1,4 @@ -//@ignore-windows: No libc on Windows +//@ignore-target-windows: No libc on Windows #![feature(rustc_private)] /// Test that destroying a pthread_condattr twice fails, even without a check for number validity diff --git a/tests/fail/sync/libc_pthread_mutex_NULL_deadlock.rs b/tests/fail/sync/libc_pthread_mutex_NULL_deadlock.rs index ade9903b9dd50..8797e895d8c89 100644 --- a/tests/fail/sync/libc_pthread_mutex_NULL_deadlock.rs +++ b/tests/fail/sync/libc_pthread_mutex_NULL_deadlock.rs @@ -1,4 +1,4 @@ -//@ignore-windows: No libc on Windows +//@ignore-target-windows: No libc on Windows // // Check that if we pass NULL attribute, then we get the default mutex type. diff --git a/tests/fail/sync/libc_pthread_mutex_deadlock.rs b/tests/fail/sync/libc_pthread_mutex_deadlock.rs index 597d7721b12d2..7da6e51600008 100644 --- a/tests/fail/sync/libc_pthread_mutex_deadlock.rs +++ b/tests/fail/sync/libc_pthread_mutex_deadlock.rs @@ -1,4 +1,4 @@ -//@ignore-windows: No libc on Windows +//@ignore-target-windows: No libc on Windows #![feature(rustc_private)] diff --git a/tests/fail/sync/libc_pthread_mutex_default_deadlock.rs b/tests/fail/sync/libc_pthread_mutex_default_deadlock.rs index dee5c80e9c405..70a85aa0f9898 100644 --- a/tests/fail/sync/libc_pthread_mutex_default_deadlock.rs +++ b/tests/fail/sync/libc_pthread_mutex_default_deadlock.rs @@ -1,4 +1,4 @@ -//@ignore-windows: No libc on Windows +//@ignore-target-windows: No libc on Windows // // Check that if we do not set the mutex type, it is the default. diff --git a/tests/fail/sync/libc_pthread_mutex_destroy_locked.rs b/tests/fail/sync/libc_pthread_mutex_destroy_locked.rs index a7ef5e44c9da1..fc69ace369930 100644 --- a/tests/fail/sync/libc_pthread_mutex_destroy_locked.rs +++ b/tests/fail/sync/libc_pthread_mutex_destroy_locked.rs @@ -1,4 +1,4 @@ -//@ignore-windows: No libc on Windows +//@ignore-target-windows: No libc on Windows #![feature(rustc_private)] diff --git a/tests/fail/sync/libc_pthread_mutex_double_destroy.rs b/tests/fail/sync/libc_pthread_mutex_double_destroy.rs index 8f60409b0052b..9b539afc1992a 100644 --- a/tests/fail/sync/libc_pthread_mutex_double_destroy.rs +++ b/tests/fail/sync/libc_pthread_mutex_double_destroy.rs @@ -1,4 +1,4 @@ -//@ignore-windows: No libc on Windows +//@ignore-target-windows: No libc on Windows #![feature(rustc_private)] /// Test that destroying a pthread_mutex twice fails, even without a check for number validity diff --git a/tests/fail/sync/libc_pthread_mutex_normal_deadlock.rs b/tests/fail/sync/libc_pthread_mutex_normal_deadlock.rs index 45475249befcd..944e86e106d7a 100644 --- a/tests/fail/sync/libc_pthread_mutex_normal_deadlock.rs +++ b/tests/fail/sync/libc_pthread_mutex_normal_deadlock.rs @@ -1,4 +1,4 @@ -//@ignore-windows: No libc on Windows +//@ignore-target-windows: No libc on Windows #![feature(rustc_private)] diff --git a/tests/fail/sync/libc_pthread_mutex_normal_unlock_unlocked.rs b/tests/fail/sync/libc_pthread_mutex_normal_unlock_unlocked.rs index da23819ebc314..c2bdce82b6f8f 100644 --- a/tests/fail/sync/libc_pthread_mutex_normal_unlock_unlocked.rs +++ b/tests/fail/sync/libc_pthread_mutex_normal_unlock_unlocked.rs @@ -1,4 +1,4 @@ -//@ignore-windows: No libc on Windows +//@ignore-target-windows: No libc on Windows #![feature(rustc_private)] diff --git a/tests/fail/sync/libc_pthread_mutex_wrong_owner.rs b/tests/fail/sync/libc_pthread_mutex_wrong_owner.rs index d91245104b0e1..eea4db7115974 100644 --- a/tests/fail/sync/libc_pthread_mutex_wrong_owner.rs +++ b/tests/fail/sync/libc_pthread_mutex_wrong_owner.rs @@ -1,4 +1,4 @@ -//@ignore-windows: No libc on Windows +//@ignore-target-windows: No libc on Windows #![feature(rustc_private)] diff --git a/tests/fail/sync/libc_pthread_mutexattr_double_destroy.rs b/tests/fail/sync/libc_pthread_mutexattr_double_destroy.rs index 8fb7cc3ea6030..620dbb94a78a2 100644 --- a/tests/fail/sync/libc_pthread_mutexattr_double_destroy.rs +++ b/tests/fail/sync/libc_pthread_mutexattr_double_destroy.rs @@ -1,4 +1,4 @@ -//@ignore-windows: No libc on Windows +//@ignore-target-windows: No libc on Windows #![feature(rustc_private)] /// Test that destroying a pthread_mutexattr twice fails, even without a check for number validity diff --git a/tests/fail/sync/libc_pthread_rwlock_destroy_read_locked.rs b/tests/fail/sync/libc_pthread_rwlock_destroy_read_locked.rs index 0efb6724c1774..67b77ff286470 100644 --- a/tests/fail/sync/libc_pthread_rwlock_destroy_read_locked.rs +++ b/tests/fail/sync/libc_pthread_rwlock_destroy_read_locked.rs @@ -1,4 +1,4 @@ -//@ignore-windows: No libc on Windows +//@ignore-target-windows: No libc on Windows #![feature(rustc_private)] diff --git a/tests/fail/sync/libc_pthread_rwlock_destroy_write_locked.rs b/tests/fail/sync/libc_pthread_rwlock_destroy_write_locked.rs index 11c09c1b13426..5bc5fe3c6bc4c 100644 --- a/tests/fail/sync/libc_pthread_rwlock_destroy_write_locked.rs +++ b/tests/fail/sync/libc_pthread_rwlock_destroy_write_locked.rs @@ -1,4 +1,4 @@ -//@ignore-windows: No libc on Windows +//@ignore-target-windows: No libc on Windows #![feature(rustc_private)] diff --git a/tests/fail/sync/libc_pthread_rwlock_double_destroy.rs b/tests/fail/sync/libc_pthread_rwlock_double_destroy.rs index 9de0383f9daf4..7e756c5bb88f0 100644 --- a/tests/fail/sync/libc_pthread_rwlock_double_destroy.rs +++ b/tests/fail/sync/libc_pthread_rwlock_double_destroy.rs @@ -1,4 +1,4 @@ -//@ignore-windows: No libc on Windows +//@ignore-target-windows: No libc on Windows #![feature(rustc_private)] /// Test that destroying a pthread_rwlock twice fails, even without a check for number validity diff --git a/tests/fail/sync/libc_pthread_rwlock_read_write_deadlock_single_thread.rs b/tests/fail/sync/libc_pthread_rwlock_read_write_deadlock_single_thread.rs index 9c8d22310cab9..76fceb315f441 100644 --- a/tests/fail/sync/libc_pthread_rwlock_read_write_deadlock_single_thread.rs +++ b/tests/fail/sync/libc_pthread_rwlock_read_write_deadlock_single_thread.rs @@ -1,4 +1,4 @@ -//@ignore-windows: No libc on Windows +//@ignore-target-windows: No libc on Windows #![feature(rustc_private)] diff --git a/tests/fail/sync/libc_pthread_rwlock_read_wrong_owner.rs b/tests/fail/sync/libc_pthread_rwlock_read_wrong_owner.rs index 361cc7cdd850d..e971fd8c302a5 100644 --- a/tests/fail/sync/libc_pthread_rwlock_read_wrong_owner.rs +++ b/tests/fail/sync/libc_pthread_rwlock_read_wrong_owner.rs @@ -1,4 +1,4 @@ -//@ignore-windows: No libc on Windows +//@ignore-target-windows: No libc on Windows #![feature(rustc_private)] diff --git a/tests/fail/sync/libc_pthread_rwlock_unlock_unlocked.rs b/tests/fail/sync/libc_pthread_rwlock_unlock_unlocked.rs index 9d3ca275cb04f..29cfd36cafc20 100644 --- a/tests/fail/sync/libc_pthread_rwlock_unlock_unlocked.rs +++ b/tests/fail/sync/libc_pthread_rwlock_unlock_unlocked.rs @@ -1,4 +1,4 @@ -//@ignore-windows: No libc on Windows +//@ignore-target-windows: No libc on Windows #![feature(rustc_private)] diff --git a/tests/fail/sync/libc_pthread_rwlock_write_read_deadlock.rs b/tests/fail/sync/libc_pthread_rwlock_write_read_deadlock.rs index 3158b944a7f77..e9c5c17f3eba7 100644 --- a/tests/fail/sync/libc_pthread_rwlock_write_read_deadlock.rs +++ b/tests/fail/sync/libc_pthread_rwlock_write_read_deadlock.rs @@ -1,4 +1,4 @@ -//@ignore-windows: No libc on Windows +//@ignore-target-windows: No libc on Windows #![feature(rustc_private)] diff --git a/tests/fail/sync/libc_pthread_rwlock_write_read_deadlock_single_thread.rs b/tests/fail/sync/libc_pthread_rwlock_write_read_deadlock_single_thread.rs index c6b468eb89b11..5ed25344e7c73 100644 --- a/tests/fail/sync/libc_pthread_rwlock_write_read_deadlock_single_thread.rs +++ b/tests/fail/sync/libc_pthread_rwlock_write_read_deadlock_single_thread.rs @@ -1,4 +1,4 @@ -//@ignore-windows: No libc on Windows +//@ignore-target-windows: No libc on Windows #![feature(rustc_private)] diff --git a/tests/fail/sync/libc_pthread_rwlock_write_write_deadlock.rs b/tests/fail/sync/libc_pthread_rwlock_write_write_deadlock.rs index 91adaf85499fa..3d15370e83dd9 100644 --- a/tests/fail/sync/libc_pthread_rwlock_write_write_deadlock.rs +++ b/tests/fail/sync/libc_pthread_rwlock_write_write_deadlock.rs @@ -1,4 +1,4 @@ -//@ignore-windows: No libc on Windows +//@ignore-target-windows: No libc on Windows #![feature(rustc_private)] diff --git a/tests/fail/sync/libc_pthread_rwlock_write_write_deadlock_single_thread.rs b/tests/fail/sync/libc_pthread_rwlock_write_write_deadlock_single_thread.rs index 13a7ceefc7bbe..14361bee54c06 100644 --- a/tests/fail/sync/libc_pthread_rwlock_write_write_deadlock_single_thread.rs +++ b/tests/fail/sync/libc_pthread_rwlock_write_write_deadlock_single_thread.rs @@ -1,4 +1,4 @@ -//@ignore-windows: No libc on Windows +//@ignore-target-windows: No libc on Windows #![feature(rustc_private)] diff --git a/tests/fail/sync/libc_pthread_rwlock_write_wrong_owner.rs b/tests/fail/sync/libc_pthread_rwlock_write_wrong_owner.rs index a205bbcb6b55b..668ccb3ecaeff 100644 --- a/tests/fail/sync/libc_pthread_rwlock_write_wrong_owner.rs +++ b/tests/fail/sync/libc_pthread_rwlock_write_wrong_owner.rs @@ -1,4 +1,4 @@ -//@ignore-windows: No libc on Windows +//@ignore-target-windows: No libc on Windows #![feature(rustc_private)] diff --git a/tests/fail/unsupported_signal.rs b/tests/fail/unsupported_signal.rs index 4319dc7c69fe7..e9bd340fcafb7 100644 --- a/tests/fail/unsupported_signal.rs +++ b/tests/fail/unsupported_signal.rs @@ -1,6 +1,6 @@ //! `signal()` is special on Linux and macOS that it's only supported within libstd. //! The implementation is not complete enough to permit user code to call it. -//@ignore-windows: No libc on Windows +//@ignore-target-windows: No libc on Windows #![feature(rustc_private)] extern crate libc; diff --git a/tests/fail/weak_memory/racing_mixed_size.rs b/tests/fail/weak_memory/racing_mixed_size.rs index d697e5f8fbeae..a7c5a41917623 100644 --- a/tests/fail/weak_memory/racing_mixed_size.rs +++ b/tests/fail/weak_memory/racing_mixed_size.rs @@ -1,6 +1,6 @@ // We want to control preemption here. //@compile-flags: -Zmiri-preemption-rate=0 -//@ignore-windows: Concurrency on Windows is not supported yet. +//@ignore-target-windows: Concurrency on Windows is not supported yet. #![feature(core_intrinsics)] diff --git a/tests/fail/weak_memory/racing_mixed_size_read.rs b/tests/fail/weak_memory/racing_mixed_size_read.rs index 0eacaeeaa9ee8..aeaa6b68f6c8c 100644 --- a/tests/fail/weak_memory/racing_mixed_size_read.rs +++ b/tests/fail/weak_memory/racing_mixed_size_read.rs @@ -1,6 +1,6 @@ // We want to control preemption here. //@compile-flags: -Zmiri-preemption-rate=0 -//@ignore-windows: Concurrency on Windows is not supported yet. +//@ignore-target-windows: Concurrency on Windows is not supported yet. #![feature(core_intrinsics)] diff --git a/tests/panic/panic/unsupported_syscall.rs b/tests/panic/panic/unsupported_syscall.rs index 3338c46c04efc..a689172814667 100644 --- a/tests/panic/panic/unsupported_syscall.rs +++ b/tests/panic/panic/unsupported_syscall.rs @@ -1,5 +1,5 @@ -//@ignore-windows: No libc on Windows -//@ignore-apple: `syscall` is not supported on macOS +//@ignore-target-windows: No libc on Windows +//@ignore-target-apple: `syscall` is not supported on macOS //@compile-flags: -Zmiri-panic-on-unsupported #![feature(rustc_private)] diff --git a/tests/pass/0weak_memory_consistency.rs b/tests/pass/0weak_memory_consistency.rs index 8b7ce50d2d42e..b5b6b83cce1bb 100644 --- a/tests/pass/0weak_memory_consistency.rs +++ b/tests/pass/0weak_memory_consistency.rs @@ -1,4 +1,4 @@ -//@ignore-windows: Concurrency on Windows is not supported yet. +//@ignore-target-windows: Concurrency on Windows is not supported yet. //@compile-flags: -Zmiri-ignore-leaks -Zmiri-disable-stacked-borrows // The following tests check whether our weak memory emulation produces diff --git a/tests/pass/calloc.rs b/tests/pass/calloc.rs index a75bb0606118a..a9efb776b69ea 100644 --- a/tests/pass/calloc.rs +++ b/tests/pass/calloc.rs @@ -1,4 +1,4 @@ -//@ignore-windows: No libc on Windows +//@ignore-target-windows: No libc on Windows #![feature(rustc_private)] diff --git a/tests/pass/concurrency/channels.rs b/tests/pass/concurrency/channels.rs index e94c69b286d60..40d729f042d19 100644 --- a/tests/pass/concurrency/channels.rs +++ b/tests/pass/concurrency/channels.rs @@ -1,4 +1,4 @@ -//@ignore-windows: Concurrency on Windows is not supported yet. +//@ignore-target-windows: Concurrency on Windows is not supported yet. //@compile-flags: -Zmiri-strict-provenance use std::sync::mpsc::{channel, sync_channel}; diff --git a/tests/pass/concurrency/concurrent_caller_location.rs b/tests/pass/concurrency/concurrent_caller_location.rs index 6bd601abd56e9..a07f6b13e6d79 100644 --- a/tests/pass/concurrency/concurrent_caller_location.rs +++ b/tests/pass/concurrency/concurrent_caller_location.rs @@ -1,4 +1,4 @@ -//@ignore-windows: Concurrency on Windows is not supported yet. +//@ignore-target-windows: Concurrency on Windows is not supported yet. use std::panic::Location; use std::thread::spawn; diff --git a/tests/pass/concurrency/data_race.rs b/tests/pass/concurrency/data_race.rs index 69b6c53a2b792..5d1e1bb266cad 100644 --- a/tests/pass/concurrency/data_race.rs +++ b/tests/pass/concurrency/data_race.rs @@ -1,4 +1,4 @@ -//@ignore-windows: Concurrency on Windows is not supported yet. +//@ignore-target-windows: Concurrency on Windows is not supported yet. //@compile-flags: -Zmiri-disable-weak-memory-emulation use std::sync::atomic::{fence, AtomicUsize, Ordering}; diff --git a/tests/pass/concurrency/disable_data_race_detector.rs b/tests/pass/concurrency/disable_data_race_detector.rs index a3c1e4621a3ac..a4852b4674e81 100644 --- a/tests/pass/concurrency/disable_data_race_detector.rs +++ b/tests/pass/concurrency/disable_data_race_detector.rs @@ -1,4 +1,4 @@ -//@ignore-windows: Concurrency on Windows is not supported yet. +//@ignore-target-windows: Concurrency on Windows is not supported yet. //@compile-flags: -Zmiri-disable-data-race-detector use std::thread::spawn; diff --git a/tests/pass/concurrency/issue1643.rs b/tests/pass/concurrency/issue1643.rs index cfe9cf4cc2f78..f4fe43d88cb1e 100644 --- a/tests/pass/concurrency/issue1643.rs +++ b/tests/pass/concurrency/issue1643.rs @@ -1,4 +1,4 @@ -//@ignore-windows: Concurrency on Windows is not supported yet. +//@ignore-target-windows: Concurrency on Windows is not supported yet. use std::thread::spawn; diff --git a/tests/pass/concurrency/libc_pthread_cond.rs b/tests/pass/concurrency/libc_pthread_cond.rs index 8d245e2f8ddd8..eb491486be703 100644 --- a/tests/pass/concurrency/libc_pthread_cond.rs +++ b/tests/pass/concurrency/libc_pthread_cond.rs @@ -1,5 +1,5 @@ -//@ignore-windows: No libc on Windows -//@ignore-apple: pthread_condattr_setclock is not supported on MacOS. +//@ignore-target-windows: No libc on Windows +//@ignore-target-apple: pthread_condattr_setclock is not supported on MacOS. //@compile-flags: -Zmiri-disable-isolation #![feature(rustc_private)] diff --git a/tests/pass/concurrency/linux-futex.rs b/tests/pass/concurrency/linux-futex.rs index 1ec0ec599f7b0..f9c87e0723c50 100644 --- a/tests/pass/concurrency/linux-futex.rs +++ b/tests/pass/concurrency/linux-futex.rs @@ -1,4 +1,4 @@ -//@only-linux +//@only-target-linux //@compile-flags: -Zmiri-disable-isolation #![feature(rustc_private)] diff --git a/tests/pass/concurrency/simple.rs b/tests/pass/concurrency/simple.rs index ac268dab5e94b..1d85c7fc9bd08 100644 --- a/tests/pass/concurrency/simple.rs +++ b/tests/pass/concurrency/simple.rs @@ -1,4 +1,4 @@ -//@ignore-windows: Concurrency on Windows is not supported yet. +//@ignore-target-windows: Concurrency on Windows is not supported yet. //@compile-flags: -Zmiri-strict-provenance use std::thread; diff --git a/tests/pass/concurrency/spin_loop.rs b/tests/pass/concurrency/spin_loop.rs index e1c472589904d..5f34168dbb1e9 100644 --- a/tests/pass/concurrency/spin_loop.rs +++ b/tests/pass/concurrency/spin_loop.rs @@ -1,4 +1,4 @@ -//@ignore-windows: Concurrency on Windows is not supported yet. +//@ignore-target-windows: Concurrency on Windows is not supported yet. use std::sync::atomic::{AtomicUsize, Ordering}; use std::thread; diff --git a/tests/pass/concurrency/spin_loops_nopreempt.rs b/tests/pass/concurrency/spin_loops_nopreempt.rs index 823d2ec76540c..34be0dd39481f 100644 --- a/tests/pass/concurrency/spin_loops_nopreempt.rs +++ b/tests/pass/concurrency/spin_loops_nopreempt.rs @@ -1,4 +1,4 @@ -//@ignore-windows: Concurrency on Windows is not supported yet. +//@ignore-target-windows: Concurrency on Windows is not supported yet. // This specifically tests behavior *without* preemption. //@compile-flags: -Zmiri-preemption-rate=0 diff --git a/tests/pass/concurrency/sync.rs b/tests/pass/concurrency/sync.rs index 64bd7ebb27fd7..268153b612ae3 100644 --- a/tests/pass/concurrency/sync.rs +++ b/tests/pass/concurrency/sync.rs @@ -1,4 +1,4 @@ -//@ignore-windows: Concurrency on Windows is not supported yet. +//@ignore-target-windows: Concurrency on Windows is not supported yet. //@compile-flags: -Zmiri-disable-isolation -Zmiri-strict-provenance use std::sync::{Arc, Barrier, Condvar, Mutex, Once, RwLock}; diff --git a/tests/pass/concurrency/sync_nopreempt.rs b/tests/pass/concurrency/sync_nopreempt.rs index e6ee4fe594f10..a53f143fef673 100644 --- a/tests/pass/concurrency/sync_nopreempt.rs +++ b/tests/pass/concurrency/sync_nopreempt.rs @@ -1,4 +1,4 @@ -//@ignore-windows: Concurrency on Windows is not supported yet. +//@ignore-target-windows: Concurrency on Windows is not supported yet. // We are making scheduler assumptions here. //@compile-flags: -Zmiri-strict-provenance -Zmiri-preemption-rate=0 diff --git a/tests/pass/concurrency/thread_locals.rs b/tests/pass/concurrency/thread_locals.rs index 82ce61d958d89..34431def33f81 100644 --- a/tests/pass/concurrency/thread_locals.rs +++ b/tests/pass/concurrency/thread_locals.rs @@ -1,4 +1,4 @@ -//@ignore-windows: Concurrency on Windows is not supported yet. +//@ignore-target-windows: Concurrency on Windows is not supported yet. //@compile-flags: -Zmiri-strict-provenance //! The main purpose of this test is to check that if we take a pointer to diff --git a/tests/pass/concurrency/tls_lib_drop.rs b/tests/pass/concurrency/tls_lib_drop.rs index 74ba8ee762071..6c66cd3a62fb5 100644 --- a/tests/pass/concurrency/tls_lib_drop.rs +++ b/tests/pass/concurrency/tls_lib_drop.rs @@ -1,4 +1,4 @@ -//@ignore-windows: Concurrency on Windows is not supported yet. +//@ignore-target-windows: Concurrency on Windows is not supported yet. use std::cell::RefCell; use std::thread; diff --git a/tests/pass/concurrency/tls_pthread_drop_order.rs b/tests/pass/concurrency/tls_pthread_drop_order.rs index b265e7da0b259..c9e8b9271ccfb 100644 --- a/tests/pass/concurrency/tls_pthread_drop_order.rs +++ b/tests/pass/concurrency/tls_pthread_drop_order.rs @@ -1,4 +1,4 @@ -//@ignore-windows: No libc on Windows +//@ignore-target-windows: No libc on Windows #![feature(rustc_private)] extern crate libc; diff --git a/tests/pass/fs.rs b/tests/pass/fs.rs index ced7831568e7b..aa5cd83c69cda 100644 --- a/tests/pass/fs.rs +++ b/tests/pass/fs.rs @@ -1,4 +1,4 @@ -//@ignore-windows: File handling is not implemented yet +//@ignore-target-windows: File handling is not implemented yet //@compile-flags: -Zmiri-disable-isolation #![feature(rustc_private)] diff --git a/tests/pass/fs_with_isolation.rs b/tests/pass/fs_with_isolation.rs index 719882702cdd2..41ada94e276e2 100644 --- a/tests/pass/fs_with_isolation.rs +++ b/tests/pass/fs_with_isolation.rs @@ -1,4 +1,4 @@ -//@ignore-windows: File handling is not implemented yet +//@ignore-target-windows: File handling is not implemented yet //@compile-flags: -Zmiri-isolation-error=warn-nobacktrace //@normalize-stderr-test: "(stat(x)?)" -> "$$STAT" diff --git a/tests/pass/libc.rs b/tests/pass/libc.rs index 53c85d2b07d1a..486ae4b3cfae2 100644 --- a/tests/pass/libc.rs +++ b/tests/pass/libc.rs @@ -1,4 +1,4 @@ -//@ignore-windows: No libc on Windows +//@ignore-target-windows: No libc on Windows //@compile-flags: -Zmiri-disable-isolation #![feature(rustc_private)] diff --git a/tests/pass/linux-getrandom-without-isolation.rs b/tests/pass/linux-getrandom-without-isolation.rs index 90e054533c14d..fea3bb3fdce9d 100644 --- a/tests/pass/linux-getrandom-without-isolation.rs +++ b/tests/pass/linux-getrandom-without-isolation.rs @@ -1,4 +1,4 @@ -//@only-linux +//@only-target-linux //@compile-flags: -Zmiri-disable-isolation #![feature(rustc_private)] extern crate libc; diff --git a/tests/pass/linux-getrandom.rs b/tests/pass/linux-getrandom.rs index 70c106f6460aa..1d0ab6ed746a6 100644 --- a/tests/pass/linux-getrandom.rs +++ b/tests/pass/linux-getrandom.rs @@ -1,4 +1,4 @@ -//@only-linux +//@only-target-linux #![feature(rustc_private)] extern crate libc; diff --git a/tests/pass/malloc.rs b/tests/pass/malloc.rs index c0a6a89fbed0c..d20ceddbb8edb 100644 --- a/tests/pass/malloc.rs +++ b/tests/pass/malloc.rs @@ -1,4 +1,4 @@ -//@ignore-windows: No libc on Windows +//@ignore-target-windows: No libc on Windows #![feature(rustc_private)] diff --git a/tests/pass/no_std.rs b/tests/pass/no_std.rs index d8a462daf5a94..10632c2cce497 100644 --- a/tests/pass/no_std.rs +++ b/tests/pass/no_std.rs @@ -3,7 +3,7 @@ // windows tls dtors go through libstd right now, thus this test // cannot pass. When windows tls dtors go through the special magic // windows linker section, we can run this test on windows again. -//@ignore-windows +//@ignore-target-windows #[start] fn start(_: isize, _: *const *const u8) -> isize { diff --git a/tests/pass/panic/concurrent-panic.rs b/tests/pass/panic/concurrent-panic.rs index 1231760865fb0..1acae69b8d3b3 100644 --- a/tests/pass/panic/concurrent-panic.rs +++ b/tests/pass/panic/concurrent-panic.rs @@ -1,4 +1,4 @@ -//@ignore-windows: Concurrency on Windows is not supported yet. +//@ignore-target-windows: Concurrency on Windows is not supported yet. // We are making scheduler assumptions here. //@compile-flags: -Zmiri-preemption-rate=0 diff --git a/tests/pass/threadleak_ignored.rs b/tests/pass/threadleak_ignored.rs index 2ba0b453ff394..077d8d0837538 100644 --- a/tests/pass/threadleak_ignored.rs +++ b/tests/pass/threadleak_ignored.rs @@ -1,4 +1,4 @@ -//@ignore-windows: Concurrency on Windows is not supported yet. +//@ignore-target-windows: Concurrency on Windows is not supported yet. // FIXME: disallow preemption to work around https://github.com/rust-lang/rust/issues/55005 //@compile-flags: -Zmiri-ignore-leaks -Zmiri-preemption-rate=0 diff --git a/tests/pass/weak_memory/extra_cpp.rs b/tests/pass/weak_memory/extra_cpp.rs index 61ba1ab922489..52c13cbdced37 100644 --- a/tests/pass/weak_memory/extra_cpp.rs +++ b/tests/pass/weak_memory/extra_cpp.rs @@ -1,4 +1,4 @@ -//@ignore-windows: Concurrency on Windows is not supported yet. +//@ignore-target-windows: Concurrency on Windows is not supported yet. //@compile-flags: -Zmiri-ignore-leaks // Tests operations not perfomable through C++'s atomic API diff --git a/tests/pass/weak_memory/extra_cpp_unsafe.rs b/tests/pass/weak_memory/extra_cpp_unsafe.rs index 0aff70ab7b786..1c6c370ced3b1 100644 --- a/tests/pass/weak_memory/extra_cpp_unsafe.rs +++ b/tests/pass/weak_memory/extra_cpp_unsafe.rs @@ -1,4 +1,4 @@ -//@ignore-windows: Concurrency on Windows is not supported yet. +//@ignore-target-windows: Concurrency on Windows is not supported yet. //@compile-flags: -Zmiri-ignore-leaks // Tests operations not perfomable through C++'s atomic API diff --git a/tests/pass/weak_memory/weak.rs b/tests/pass/weak_memory/weak.rs index 71d57dd11ec78..dc7982991b693 100644 --- a/tests/pass/weak_memory/weak.rs +++ b/tests/pass/weak_memory/weak.rs @@ -1,4 +1,4 @@ -//@ignore-windows: Concurrency on Windows is not supported yet. +//@ignore-target-windows: Concurrency on Windows is not supported yet. //@compile-flags: -Zmiri-ignore-leaks -Zmiri-preemption-rate=0 // Tests showing weak memory behaviours are exhibited. All tests diff --git a/tests/pass/wtf8.rs b/tests/pass/wtf8.rs index bf23f65c7f0c7..be8348654a325 100644 --- a/tests/pass/wtf8.rs +++ b/tests/pass/wtf8.rs @@ -1,4 +1,4 @@ -//@only-windows +//@only-target-windows use std::ffi::{OsStr, OsString}; use std::os::windows::ffi::{OsStrExt, OsStringExt}; diff --git a/ui_test/src/parser.rs b/ui_test/src/parser.rs index e7fb484434d79..5284862688775 100644 --- a/ui_test/src/parser.rs +++ b/ui_test/src/parser.rs @@ -65,16 +65,18 @@ pub(crate) struct ErrorMatch { } impl Condition { - fn parse(c: &str) -> Self { + fn parse(c: &str) -> Result { if c == "on-host" { - Condition::OnHost + Ok(Condition::OnHost) } else if let Some(bits) = c.strip_suffix("bit") { let bits: u8 = bits.parse().expect( "ignore/only filter ending in 'bit' must be of the form 'Nbit' for some integer N", ); - Condition::Bitwidth(bits) + Ok(Condition::Bitwidth(bits)) + } else if let Some(target) = c.strip_prefix("target-") { + Ok(Condition::Target(target.to_owned())) } else { - Condition::Target(c.to_owned()) + Err(eyre!("invalid ignore/only condition {c:?}")) } } } @@ -211,13 +213,13 @@ impl Comments { command => { if let Some(s) = command.strip_prefix("ignore-") { // args are ignored (can be sue as comment) - self.ignore.push(Condition::parse(s)); + self.ignore.push(Condition::parse(s)?); return Ok(()); } if let Some(s) = command.strip_prefix("only-") { // args are ignored (can be sue as comment) - self.only.push(Condition::parse(s)); + self.only.push(Condition::parse(s)?); return Ok(()); } bail!("unknown command {command}"); From 090f2892143ef872e561334907115c5e26eeef76 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 17 Jul 2022 21:57:56 -0400 Subject: [PATCH 3500/3747] make an expect into proper error reporting --- ui_test/src/parser.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ui_test/src/parser.rs b/ui_test/src/parser.rs index 5284862688775..d583e625facee 100644 --- a/ui_test/src/parser.rs +++ b/ui_test/src/parser.rs @@ -69,9 +69,9 @@ impl Condition { if c == "on-host" { Ok(Condition::OnHost) } else if let Some(bits) = c.strip_suffix("bit") { - let bits: u8 = bits.parse().expect( - "ignore/only filter ending in 'bit' must be of the form 'Nbit' for some integer N", - ); + let bits: u8 = bits.parse().map_err(|_err| { + eyre!("invalid ignore/only filter ending in 'bit': {c:?} is not a valid bitwdith") + })?; Ok(Condition::Bitwidth(bits)) } else if let Some(target) = c.strip_prefix("target-") { Ok(Condition::Target(target.to_owned())) From e30dd07139aa5bda7d690b20e9336edae3f42e4f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 17 Jul 2022 21:51:52 -0400 Subject: [PATCH 3501/3747] libc test: also call isatty on an actual file --- tests/pass/libc.rs | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/tests/pass/libc.rs b/tests/pass/libc.rs index 6da5279270715..ea3848a9749a7 100644 --- a/tests/pass/libc.rs +++ b/tests/pass/libc.rs @@ -1,11 +1,12 @@ //@ignore-windows: No libc on Windows //@compile-flags: -Zmiri-disable-isolation - #![feature(rustc_private)] +use std::fs::{remove_file, File}; +use std::os::unix::io::AsRawFd; + extern crate libc; -#[cfg(any(target_os = "linux", target_os = "freebsd"))] fn tmp() -> std::path::PathBuf { std::env::var("MIRI_TEMP") .map(std::path::PathBuf::from) @@ -15,9 +16,7 @@ fn tmp() -> std::path::PathBuf { #[cfg(any(target_os = "linux", target_os = "freebsd"))] fn test_posix_fadvise() { use std::convert::TryInto; - use std::fs::{remove_file, File}; use std::io::Write; - use std::os::unix::io::AsRawFd; let path = tmp().join("miri_test_libc_posix_fadvise.txt"); // Cleanup before test @@ -44,9 +43,7 @@ fn test_posix_fadvise() { #[cfg(any(target_os = "linux"))] fn test_sync_file_range() { - use std::fs::{remove_file, File}; use std::io::Write; - use std::os::unix::io::AsRawFd; let path = tmp().join("miri_test_libc_sync_file_range.txt"); // Cleanup before test. @@ -319,6 +316,19 @@ fn test_isatty() { libc::isatty(libc::STDIN_FILENO); libc::isatty(libc::STDOUT_FILENO); libc::isatty(libc::STDERR_FILENO); + + // But when we open a file, it is definitely not a TTY. + let path = tmp().join("notatty.txt"); + // Cleanup before test. + remove_file(&path).ok(); + let file = File::create(&path).unwrap(); + + assert_eq!(libc::isatty(file.as_raw_fd()), 0); + assert_eq!(std::io::Error::last_os_error().raw_os_error().unwrap(), libc::ENOTTY); + + // Cleanup after test. + drop(file); + remove_file(&path).unwrap(); } } From 52a6ac96b0a2a270400d75ba9ed3aa829826b5db Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 18 Jul 2022 07:55:11 -0400 Subject: [PATCH 3502/3747] move atomic intrinsics to their own file --- rust-version | 2 +- src/lib.rs | 1 + src/shims/intrinsics/atomic.rs | 437 ++++++++++++++++ .../{intrinsics.rs => intrinsics/mod.rs} | 481 ++---------------- 4 files changed, 473 insertions(+), 448 deletions(-) create mode 100644 src/shims/intrinsics/atomic.rs rename src/shims/{intrinsics.rs => intrinsics/mod.rs} (68%) diff --git a/rust-version b/rust-version index 5396b338cecb3..362bcc35eade2 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -db41351753df840773ca628d8daa040e95d00eef +880416180b0a9ee1141c07d4d17667edb77daebd diff --git a/src/lib.rs b/src/lib.rs index b3d408a6dc072..80281d37de9a5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -62,6 +62,7 @@ pub use rustc_const_eval::interpret::{self, AllocMap, PlaceTy}; pub use crate::shims::dlsym::{Dlsym, EvalContextExt as _}; pub use crate::shims::env::{EnvVars, EvalContextExt as _}; pub use crate::shims::foreign_items::EvalContextExt as _; +pub use crate::shims::intrinsics::atomic::EvalContextExt as _; pub use crate::shims::intrinsics::EvalContextExt as _; pub use crate::shims::os_str::EvalContextExt as _; pub use crate::shims::panic::{CatchUnwindData, EvalContextExt as _}; diff --git a/src/shims/intrinsics/atomic.rs b/src/shims/intrinsics/atomic.rs new file mode 100644 index 0000000000000..2ba591127cea4 --- /dev/null +++ b/src/shims/intrinsics/atomic.rs @@ -0,0 +1,437 @@ +use rustc_middle::{mir, mir::BinOp}; +use rustc_target::abi::Align; + +use crate::*; +use helpers::check_arg_count; + +pub enum AtomicOp { + MirOp(mir::BinOp, bool), + Max, + Min, +} + +impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} +pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { + /// Calls the atomic intrinsic `intrinsic`; the `atomic_` prefix has already been removed. + fn emulate_atomic_intrinsic( + &mut self, + intrinsic_name: &str, + args: &[OpTy<'tcx, Tag>], + dest: &PlaceTy<'tcx, Tag>, + ) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + match intrinsic_name { + // Atomic operations + "load_seqcst" => this.atomic_load(args, dest, AtomicReadOrd::SeqCst)?, + "load_relaxed" => this.atomic_load(args, dest, AtomicReadOrd::Relaxed)?, + "load_acquire" => this.atomic_load(args, dest, AtomicReadOrd::Acquire)?, + + "store_seqcst" => this.atomic_store(args, AtomicWriteOrd::SeqCst)?, + "store_relaxed" => this.atomic_store(args, AtomicWriteOrd::Relaxed)?, + "store_release" => this.atomic_store(args, AtomicWriteOrd::Release)?, + + "fence_acquire" => this.atomic_fence(args, AtomicFenceOrd::Acquire)?, + "fence_release" => this.atomic_fence(args, AtomicFenceOrd::Release)?, + "fence_acqrel" => this.atomic_fence(args, AtomicFenceOrd::AcqRel)?, + "fence_seqcst" => this.atomic_fence(args, AtomicFenceOrd::SeqCst)?, + + "singlethreadfence_acquire" => this.compiler_fence(args, AtomicFenceOrd::Acquire)?, + "singlethreadfence_release" => this.compiler_fence(args, AtomicFenceOrd::Release)?, + "singlethreadfence_acqrel" => this.compiler_fence(args, AtomicFenceOrd::AcqRel)?, + "singlethreadfence_seqcst" => this.compiler_fence(args, AtomicFenceOrd::SeqCst)?, + + "xchg_seqcst" => this.atomic_exchange(args, dest, AtomicRwOrd::SeqCst)?, + "xchg_acquire" => this.atomic_exchange(args, dest, AtomicRwOrd::Acquire)?, + "xchg_release" => this.atomic_exchange(args, dest, AtomicRwOrd::Release)?, + "xchg_acqrel" => this.atomic_exchange(args, dest, AtomicRwOrd::AcqRel)?, + "xchg_relaxed" => this.atomic_exchange(args, dest, AtomicRwOrd::Relaxed)?, + + #[rustfmt::skip] + "cxchg_seqcst_seqcst" => + this.atomic_compare_exchange(args, dest, AtomicRwOrd::SeqCst, AtomicReadOrd::SeqCst)?, + #[rustfmt::skip] + "cxchg_acquire_acquire" => + this.atomic_compare_exchange(args, dest, AtomicRwOrd::Acquire, AtomicReadOrd::Acquire)?, + #[rustfmt::skip] + "cxchg_release_relaxed" => + this.atomic_compare_exchange(args, dest, AtomicRwOrd::Release, AtomicReadOrd::Relaxed)?, + #[rustfmt::skip] + "cxchg_acqrel_acquire" => + this.atomic_compare_exchange(args, dest, AtomicRwOrd::AcqRel, AtomicReadOrd::Acquire)?, + #[rustfmt::skip] + "cxchg_relaxed_relaxed" => + this.atomic_compare_exchange(args, dest, AtomicRwOrd::Relaxed, AtomicReadOrd::Relaxed)?, + #[rustfmt::skip] + "cxchg_acquire_relaxed" => + this.atomic_compare_exchange(args, dest, AtomicRwOrd::Acquire, AtomicReadOrd::Relaxed)?, + #[rustfmt::skip] + "cxchg_acqrel_relaxed" => + this.atomic_compare_exchange(args, dest, AtomicRwOrd::AcqRel, AtomicReadOrd::Relaxed)?, + #[rustfmt::skip] + "cxchg_seqcst_relaxed" => + this.atomic_compare_exchange(args, dest, AtomicRwOrd::SeqCst, AtomicReadOrd::Relaxed)?, + #[rustfmt::skip] + "cxchg_seqcst_acquire" => + this.atomic_compare_exchange(args, dest, AtomicRwOrd::SeqCst, AtomicReadOrd::Acquire)?, + + #[rustfmt::skip] + "cxchgweak_seqcst_seqcst" => + this.atomic_compare_exchange_weak(args, dest, AtomicRwOrd::SeqCst, AtomicReadOrd::SeqCst)?, + #[rustfmt::skip] + "cxchgweak_acquire_acquire" => + this.atomic_compare_exchange_weak(args, dest, AtomicRwOrd::Acquire, AtomicReadOrd::Acquire)?, + #[rustfmt::skip] + "cxchgweak_release_relaxed" => + this.atomic_compare_exchange_weak(args, dest, AtomicRwOrd::Release, AtomicReadOrd::Relaxed)?, + #[rustfmt::skip] + "cxchgweak_acqrel_acquire" => + this.atomic_compare_exchange_weak(args, dest, AtomicRwOrd::AcqRel, AtomicReadOrd::Acquire)?, + #[rustfmt::skip] + "cxchgweak_relaxed_relaxed" => + this.atomic_compare_exchange_weak(args, dest, AtomicRwOrd::Relaxed, AtomicReadOrd::Relaxed)?, + #[rustfmt::skip] + "cxchgweak_acquire_relaxed" => + this.atomic_compare_exchange_weak(args, dest, AtomicRwOrd::Acquire, AtomicReadOrd::Relaxed)?, + #[rustfmt::skip] + "cxchgweak_acqrel_relaxed" => + this.atomic_compare_exchange_weak(args, dest, AtomicRwOrd::AcqRel, AtomicReadOrd::Relaxed)?, + #[rustfmt::skip] + "cxchgweak_seqcst_relaxed" => + this.atomic_compare_exchange_weak(args, dest, AtomicRwOrd::SeqCst, AtomicReadOrd::Relaxed)?, + #[rustfmt::skip] + "cxchgweak_seqcst_acquire" => + this.atomic_compare_exchange_weak(args, dest, AtomicRwOrd::SeqCst, AtomicReadOrd::Acquire)?, + + #[rustfmt::skip] + "or_seqcst" => + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitOr, false), AtomicRwOrd::SeqCst)?, + #[rustfmt::skip] + "or_acquire" => + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitOr, false), AtomicRwOrd::Acquire)?, + #[rustfmt::skip] + "or_release" => + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitOr, false), AtomicRwOrd::Release)?, + #[rustfmt::skip] + "or_acqrel" => + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitOr, false), AtomicRwOrd::AcqRel)?, + #[rustfmt::skip] + "or_relaxed" => + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitOr, false), AtomicRwOrd::Relaxed)?, + #[rustfmt::skip] + "xor_seqcst" => + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitXor, false), AtomicRwOrd::SeqCst)?, + #[rustfmt::skip] + "xor_acquire" => + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitXor, false), AtomicRwOrd::Acquire)?, + #[rustfmt::skip] + "xor_release" => + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitXor, false), AtomicRwOrd::Release)?, + #[rustfmt::skip] + "xor_acqrel" => + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitXor, false), AtomicRwOrd::AcqRel)?, + #[rustfmt::skip] + "xor_relaxed" => + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitXor, false), AtomicRwOrd::Relaxed)?, + #[rustfmt::skip] + "and_seqcst" => + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitAnd, false), AtomicRwOrd::SeqCst)?, + #[rustfmt::skip] + "and_acquire" => + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitAnd, false), AtomicRwOrd::Acquire)?, + #[rustfmt::skip] + "and_release" => + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitAnd, false), AtomicRwOrd::Release)?, + #[rustfmt::skip] + "and_acqrel" => + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitAnd, false), AtomicRwOrd::AcqRel)?, + #[rustfmt::skip] + "and_relaxed" => + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitAnd, false), AtomicRwOrd::Relaxed)?, + #[rustfmt::skip] + "nand_seqcst" => + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitAnd, true), AtomicRwOrd::SeqCst)?, + #[rustfmt::skip] + "nand_acquire" => + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitAnd, true), AtomicRwOrd::Acquire)?, + #[rustfmt::skip] + "nand_release" => + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitAnd, true), AtomicRwOrd::Release)?, + #[rustfmt::skip] + "nand_acqrel" => + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitAnd, true), AtomicRwOrd::AcqRel)?, + #[rustfmt::skip] + "nand_relaxed" => + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitAnd, true), AtomicRwOrd::Relaxed)?, + #[rustfmt::skip] + "xadd_seqcst" => + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::Add, false), AtomicRwOrd::SeqCst)?, + #[rustfmt::skip] + "xadd_acquire" => + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::Add, false), AtomicRwOrd::Acquire)?, + #[rustfmt::skip] + "xadd_release" => + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::Add, false), AtomicRwOrd::Release)?, + #[rustfmt::skip] + "xadd_acqrel" => + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::Add, false), AtomicRwOrd::AcqRel)?, + #[rustfmt::skip] + "xadd_relaxed" => + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::Add, false), AtomicRwOrd::Relaxed)?, + #[rustfmt::skip] + "xsub_seqcst" => + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::Sub, false), AtomicRwOrd::SeqCst)?, + #[rustfmt::skip] + "xsub_acquire" => + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::Sub, false), AtomicRwOrd::Acquire)?, + #[rustfmt::skip] + "xsub_release" => + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::Sub, false), AtomicRwOrd::Release)?, + #[rustfmt::skip] + "xsub_acqrel" => + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::Sub, false), AtomicRwOrd::AcqRel)?, + #[rustfmt::skip] + "xsub_relaxed" => + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::Sub, false), AtomicRwOrd::Relaxed)?, + + "min_seqcst" => this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOrd::SeqCst)?, + "min_acquire" => this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOrd::Acquire)?, + "min_release" => this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOrd::Release)?, + "min_acqrel" => this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOrd::AcqRel)?, + "min_relaxed" => this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOrd::Relaxed)?, + "max_seqcst" => this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOrd::SeqCst)?, + "max_acquire" => this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOrd::Acquire)?, + "max_release" => this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOrd::Release)?, + "max_acqrel" => this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOrd::AcqRel)?, + "max_relaxed" => this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOrd::Relaxed)?, + "umin_seqcst" => this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOrd::SeqCst)?, + "umin_acquire" => this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOrd::Acquire)?, + "umin_release" => this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOrd::Release)?, + "umin_acqrel" => this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOrd::AcqRel)?, + "umin_relaxed" => this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOrd::Relaxed)?, + "umax_seqcst" => this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOrd::SeqCst)?, + "umax_acquire" => this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOrd::Acquire)?, + "umax_release" => this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOrd::Release)?, + "umax_acqrel" => this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOrd::AcqRel)?, + "umax_relaxed" => this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOrd::Relaxed)?, + + name => throw_unsup_format!("unimplemented intrinsic: `atomic_{name}`"), + } + Ok(()) + } + + fn atomic_load( + &mut self, + args: &[OpTy<'tcx, Tag>], + dest: &PlaceTy<'tcx, Tag>, + atomic: AtomicReadOrd, + ) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + + let [place] = check_arg_count(args)?; + let place = this.deref_operand(place)?; + + // make sure it fits into a scalar; otherwise it cannot be atomic + let val = this.read_scalar_atomic(&place, atomic)?; + + // Check alignment requirements. Atomics must always be aligned to their size, + // even if the type they wrap would be less aligned (e.g. AtomicU64 on 32bit must + // be 8-aligned). + let align = Align::from_bytes(place.layout.size.bytes()).unwrap(); + this.check_ptr_access_align( + place.ptr, + place.layout.size, + align, + CheckInAllocMsg::MemoryAccessTest, + )?; + // Perform regular access. + this.write_scalar(val, dest)?; + Ok(()) + } + + fn atomic_store( + &mut self, + args: &[OpTy<'tcx, Tag>], + atomic: AtomicWriteOrd, + ) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + + let [place, val] = check_arg_count(args)?; + let place = this.deref_operand(place)?; + let val = this.read_scalar(val)?; // make sure it fits into a scalar; otherwise it cannot be atomic + + // Check alignment requirements. Atomics must always be aligned to their size, + // even if the type they wrap would be less aligned (e.g. AtomicU64 on 32bit must + // be 8-aligned). + let align = Align::from_bytes(place.layout.size.bytes()).unwrap(); + this.check_ptr_access_align( + place.ptr, + place.layout.size, + align, + CheckInAllocMsg::MemoryAccessTest, + )?; + + // Perform atomic store + this.write_scalar_atomic(val, &place, atomic)?; + Ok(()) + } + + fn compiler_fence( + &mut self, + args: &[OpTy<'tcx, Tag>], + atomic: AtomicFenceOrd, + ) -> InterpResult<'tcx> { + let [] = check_arg_count(args)?; + let _ = atomic; + //FIXME: compiler fences are currently ignored + Ok(()) + } + + fn atomic_fence( + &mut self, + args: &[OpTy<'tcx, Tag>], + atomic: AtomicFenceOrd, + ) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + let [] = check_arg_count(args)?; + this.validate_atomic_fence(atomic)?; + Ok(()) + } + + fn atomic_op( + &mut self, + args: &[OpTy<'tcx, Tag>], + dest: &PlaceTy<'tcx, Tag>, + atomic_op: AtomicOp, + atomic: AtomicRwOrd, + ) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + + let [place, rhs] = check_arg_count(args)?; + let place = this.deref_operand(place)?; + + if !place.layout.ty.is_integral() && !place.layout.ty.is_unsafe_ptr() { + span_bug!( + this.cur_span(), + "atomic arithmetic operations only work on integer and raw pointer types", + ); + } + let rhs = this.read_immediate(rhs)?; + + // Check alignment requirements. Atomics must always be aligned to their size, + // even if the type they wrap would be less aligned (e.g. AtomicU64 on 32bit must + // be 8-aligned). + let align = Align::from_bytes(place.layout.size.bytes()).unwrap(); + this.check_ptr_access_align( + place.ptr, + place.layout.size, + align, + CheckInAllocMsg::MemoryAccessTest, + )?; + + match atomic_op { + AtomicOp::Min => { + let old = this.atomic_min_max_scalar(&place, rhs, true, atomic)?; + this.write_immediate(*old, dest)?; // old value is returned + Ok(()) + } + AtomicOp::Max => { + let old = this.atomic_min_max_scalar(&place, rhs, false, atomic)?; + this.write_immediate(*old, dest)?; // old value is returned + Ok(()) + } + AtomicOp::MirOp(op, neg) => { + let old = this.atomic_op_immediate(&place, &rhs, op, neg, atomic)?; + this.write_immediate(*old, dest)?; // old value is returned + Ok(()) + } + } + } + + fn atomic_exchange( + &mut self, + args: &[OpTy<'tcx, Tag>], + dest: &PlaceTy<'tcx, Tag>, + atomic: AtomicRwOrd, + ) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + + let [place, new] = check_arg_count(args)?; + let place = this.deref_operand(place)?; + let new = this.read_scalar(new)?; + + // Check alignment requirements. Atomics must always be aligned to their size, + // even if the type they wrap would be less aligned (e.g. AtomicU64 on 32bit must + // be 8-aligned). + let align = Align::from_bytes(place.layout.size.bytes()).unwrap(); + this.check_ptr_access_align( + place.ptr, + place.layout.size, + align, + CheckInAllocMsg::MemoryAccessTest, + )?; + + let old = this.atomic_exchange_scalar(&place, new, atomic)?; + this.write_scalar(old, dest)?; // old value is returned + Ok(()) + } + + fn atomic_compare_exchange_impl( + &mut self, + args: &[OpTy<'tcx, Tag>], + dest: &PlaceTy<'tcx, Tag>, + success: AtomicRwOrd, + fail: AtomicReadOrd, + can_fail_spuriously: bool, + ) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + + let [place, expect_old, new] = check_arg_count(args)?; + let place = this.deref_operand(place)?; + let expect_old = this.read_immediate(expect_old)?; // read as immediate for the sake of `binary_op()` + let new = this.read_scalar(new)?; + + // Check alignment requirements. Atomics must always be aligned to their size, + // even if the type they wrap would be less aligned (e.g. AtomicU64 on 32bit must + // be 8-aligned). + let align = Align::from_bytes(place.layout.size.bytes()).unwrap(); + this.check_ptr_access_align( + place.ptr, + place.layout.size, + align, + CheckInAllocMsg::MemoryAccessTest, + )?; + + let old = this.atomic_compare_exchange_scalar( + &place, + &expect_old, + new, + success, + fail, + can_fail_spuriously, + )?; + + // Return old value. + this.write_immediate(old, dest)?; + Ok(()) + } + + fn atomic_compare_exchange( + &mut self, + args: &[OpTy<'tcx, Tag>], + dest: &PlaceTy<'tcx, Tag>, + success: AtomicRwOrd, + fail: AtomicReadOrd, + ) -> InterpResult<'tcx> { + self.atomic_compare_exchange_impl(args, dest, success, fail, false) + } + + fn atomic_compare_exchange_weak( + &mut self, + args: &[OpTy<'tcx, Tag>], + dest: &PlaceTy<'tcx, Tag>, + success: AtomicRwOrd, + fail: AtomicReadOrd, + ) -> InterpResult<'tcx> { + self.atomic_compare_exchange_impl(args, dest, success, fail, true) + } +} diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics/mod.rs similarity index 68% rename from src/shims/intrinsics.rs rename to src/shims/intrinsics/mod.rs index ab79438c734de..6195147259af2 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics/mod.rs @@ -1,21 +1,17 @@ +pub mod atomic; + use std::iter; use log::trace; use rustc_apfloat::{Float, Round}; use rustc_middle::ty::layout::{HasParamEnv, IntegerExt, LayoutOf}; -use rustc_middle::{mir, mir::BinOp, ty, ty::FloatTy}; -use rustc_target::abi::{Align, Endian, HasDataLayout, Integer, Size}; +use rustc_middle::{mir, ty, ty::FloatTy}; +use rustc_target::abi::{Endian, HasDataLayout, Integer, Size}; use crate::*; use helpers::check_arg_count; -pub enum AtomicOp { - MirOp(mir::BinOp, bool), - Max, - Min, -} - impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { fn call_intrinsic( @@ -28,11 +24,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); + // See if the core engine can handle this intrinsic. if this.emulate_intrinsic(instance, args, dest, ret)? { return Ok(()); } - // All supported intrinsics have a return place. + // All remaining supported intrinsics have a return place. let intrinsic_name = this.tcx.item_name(instance.def_id()); let intrinsic_name = intrinsic_name.as_str(); let ret = match ret { @@ -40,7 +37,33 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Some(p) => p, }; - // Then handle terminating intrinsics. + // Some intrinsics are special and need the "ret". + match intrinsic_name { + "try" => return this.handle_try(args, dest, ret), + _ => {} + } + + // The rest jumps to `ret` immediately. + this.emulate_intrinsic_by_name(intrinsic_name, args, dest)?; + + trace!("{:?}", this.dump_place(**dest)); + this.go_to_block(ret); + Ok(()) + } + + /// Emulates a Miri-supported intrinsic (not supported by the core engine). + fn emulate_intrinsic_by_name( + &mut self, + intrinsic_name: &str, + args: &[OpTy<'tcx, Tag>], + dest: &PlaceTy<'tcx, Tag>, + ) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + + if let Some(name) = intrinsic_name.strip_prefix("atomic_") { + return this.emulate_atomic_intrinsic(name, args, dest); + } + match intrinsic_name { // Miri overwriting CTFE intrinsics. "ptr_guaranteed_eq" => { @@ -78,7 +101,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "write_bytes" | "volatile_set_memory" => { let [ptr, val_byte, count] = check_arg_count(args)?; - let ty = instance.substs.type_at(0); + let ty = ptr.layout.ty.builtin_deref(true).unwrap().ty; let ty_layout = this.layout_of(ty)?; let val_byte = this.read_scalar(val_byte)?.to_u8()?; let ptr = this.read_pointer(ptr)?; @@ -859,230 +882,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_int(res, dest)?; } - // Atomic operations - "atomic_load_seqcst" => this.atomic_load(args, dest, AtomicReadOrd::SeqCst)?, - "atomic_load_relaxed" => this.atomic_load(args, dest, AtomicReadOrd::Relaxed)?, - "atomic_load_acquire" => this.atomic_load(args, dest, AtomicReadOrd::Acquire)?, - - "atomic_store_seqcst" => this.atomic_store(args, AtomicWriteOrd::SeqCst)?, - "atomic_store_relaxed" => this.atomic_store(args, AtomicWriteOrd::Relaxed)?, - "atomic_store_release" => this.atomic_store(args, AtomicWriteOrd::Release)?, - - "atomic_fence_acquire" => this.atomic_fence(args, AtomicFenceOrd::Acquire)?, - "atomic_fence_release" => this.atomic_fence(args, AtomicFenceOrd::Release)?, - "atomic_fence_acqrel" => this.atomic_fence(args, AtomicFenceOrd::AcqRel)?, - "atomic_fence_seqcst" => this.atomic_fence(args, AtomicFenceOrd::SeqCst)?, - - "atomic_singlethreadfence_acquire" => - this.compiler_fence(args, AtomicFenceOrd::Acquire)?, - "atomic_singlethreadfence_release" => - this.compiler_fence(args, AtomicFenceOrd::Release)?, - "atomic_singlethreadfence_acqrel" => - this.compiler_fence(args, AtomicFenceOrd::AcqRel)?, - "atomic_singlethreadfence_seqcst" => - this.compiler_fence(args, AtomicFenceOrd::SeqCst)?, - - "atomic_xchg_seqcst" => this.atomic_exchange(args, dest, AtomicRwOrd::SeqCst)?, - "atomic_xchg_acquire" => this.atomic_exchange(args, dest, AtomicRwOrd::Acquire)?, - "atomic_xchg_release" => this.atomic_exchange(args, dest, AtomicRwOrd::Release)?, - "atomic_xchg_acqrel" => this.atomic_exchange(args, dest, AtomicRwOrd::AcqRel)?, - "atomic_xchg_relaxed" => this.atomic_exchange(args, dest, AtomicRwOrd::Relaxed)?, - - #[rustfmt::skip] - "atomic_cxchg_seqcst_seqcst" => - this.atomic_compare_exchange(args, dest, AtomicRwOrd::SeqCst, AtomicReadOrd::SeqCst)?, - #[rustfmt::skip] - "atomic_cxchg_acquire_acquire" => - this.atomic_compare_exchange(args, dest, AtomicRwOrd::Acquire, AtomicReadOrd::Acquire)?, - #[rustfmt::skip] - "atomic_cxchg_release_relaxed" => - this.atomic_compare_exchange(args, dest, AtomicRwOrd::Release, AtomicReadOrd::Relaxed)?, - #[rustfmt::skip] - "atomic_cxchg_acqrel_acquire" => - this.atomic_compare_exchange(args, dest, AtomicRwOrd::AcqRel, AtomicReadOrd::Acquire)?, - #[rustfmt::skip] - "atomic_cxchg_relaxed_relaxed" => - this.atomic_compare_exchange(args, dest, AtomicRwOrd::Relaxed, AtomicReadOrd::Relaxed)?, - #[rustfmt::skip] - "atomic_cxchg_acquire_relaxed" => - this.atomic_compare_exchange(args, dest, AtomicRwOrd::Acquire, AtomicReadOrd::Relaxed)?, - #[rustfmt::skip] - "atomic_cxchg_acqrel_relaxed" => - this.atomic_compare_exchange(args, dest, AtomicRwOrd::AcqRel, AtomicReadOrd::Relaxed)?, - #[rustfmt::skip] - "atomic_cxchg_seqcst_relaxed" => - this.atomic_compare_exchange(args, dest, AtomicRwOrd::SeqCst, AtomicReadOrd::Relaxed)?, - #[rustfmt::skip] - "atomic_cxchg_seqcst_acquire" => - this.atomic_compare_exchange(args, dest, AtomicRwOrd::SeqCst, AtomicReadOrd::Acquire)?, - - #[rustfmt::skip] - "atomic_cxchgweak_seqcst_seqcst" => - this.atomic_compare_exchange_weak(args, dest, AtomicRwOrd::SeqCst, AtomicReadOrd::SeqCst)?, - #[rustfmt::skip] - "atomic_cxchgweak_acquire_acquire" => - this.atomic_compare_exchange_weak(args, dest, AtomicRwOrd::Acquire, AtomicReadOrd::Acquire)?, - #[rustfmt::skip] - "atomic_cxchgweak_release_relaxed" => - this.atomic_compare_exchange_weak(args, dest, AtomicRwOrd::Release, AtomicReadOrd::Relaxed)?, - #[rustfmt::skip] - "atomic_cxchgweak_acqrel_acquire" => - this.atomic_compare_exchange_weak(args, dest, AtomicRwOrd::AcqRel, AtomicReadOrd::Acquire)?, - #[rustfmt::skip] - "atomic_cxchgweak_relaxed_relaxed" => - this.atomic_compare_exchange_weak(args, dest, AtomicRwOrd::Relaxed, AtomicReadOrd::Relaxed)?, - #[rustfmt::skip] - "atomic_cxchgweak_acquire_relaxed" => - this.atomic_compare_exchange_weak(args, dest, AtomicRwOrd::Acquire, AtomicReadOrd::Relaxed)?, - #[rustfmt::skip] - "atomic_cxchgweak_acqrel_relaxed" => - this.atomic_compare_exchange_weak(args, dest, AtomicRwOrd::AcqRel, AtomicReadOrd::Relaxed)?, - #[rustfmt::skip] - "atomic_cxchgweak_seqcst_relaxed" => - this.atomic_compare_exchange_weak(args, dest, AtomicRwOrd::SeqCst, AtomicReadOrd::Relaxed)?, - #[rustfmt::skip] - "atomic_cxchgweak_seqcst_acquire" => - this.atomic_compare_exchange_weak(args, dest, AtomicRwOrd::SeqCst, AtomicReadOrd::Acquire)?, - - #[rustfmt::skip] - "atomic_or_seqcst" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitOr, false), AtomicRwOrd::SeqCst)?, - #[rustfmt::skip] - "atomic_or_acquire" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitOr, false), AtomicRwOrd::Acquire)?, - #[rustfmt::skip] - "atomic_or_release" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitOr, false), AtomicRwOrd::Release)?, - #[rustfmt::skip] - "atomic_or_acqrel" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitOr, false), AtomicRwOrd::AcqRel)?, - #[rustfmt::skip] - "atomic_or_relaxed" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitOr, false), AtomicRwOrd::Relaxed)?, - #[rustfmt::skip] - "atomic_xor_seqcst" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitXor, false), AtomicRwOrd::SeqCst)?, - #[rustfmt::skip] - "atomic_xor_acquire" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitXor, false), AtomicRwOrd::Acquire)?, - #[rustfmt::skip] - "atomic_xor_release" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitXor, false), AtomicRwOrd::Release)?, - #[rustfmt::skip] - "atomic_xor_acqrel" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitXor, false), AtomicRwOrd::AcqRel)?, - #[rustfmt::skip] - "atomic_xor_relaxed" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitXor, false), AtomicRwOrd::Relaxed)?, - #[rustfmt::skip] - "atomic_and_seqcst" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitAnd, false), AtomicRwOrd::SeqCst)?, - #[rustfmt::skip] - "atomic_and_acquire" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitAnd, false), AtomicRwOrd::Acquire)?, - #[rustfmt::skip] - "atomic_and_release" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitAnd, false), AtomicRwOrd::Release)?, - #[rustfmt::skip] - "atomic_and_acqrel" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitAnd, false), AtomicRwOrd::AcqRel)?, - #[rustfmt::skip] - "atomic_and_relaxed" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitAnd, false), AtomicRwOrd::Relaxed)?, - #[rustfmt::skip] - "atomic_nand_seqcst" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitAnd, true), AtomicRwOrd::SeqCst)?, - #[rustfmt::skip] - "atomic_nand_acquire" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitAnd, true), AtomicRwOrd::Acquire)?, - #[rustfmt::skip] - "atomic_nand_release" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitAnd, true), AtomicRwOrd::Release)?, - #[rustfmt::skip] - "atomic_nand_acqrel" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitAnd, true), AtomicRwOrd::AcqRel)?, - #[rustfmt::skip] - "atomic_nand_relaxed" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitAnd, true), AtomicRwOrd::Relaxed)?, - #[rustfmt::skip] - "atomic_xadd_seqcst" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::Add, false), AtomicRwOrd::SeqCst)?, - #[rustfmt::skip] - "atomic_xadd_acquire" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::Add, false), AtomicRwOrd::Acquire)?, - #[rustfmt::skip] - "atomic_xadd_release" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::Add, false), AtomicRwOrd::Release)?, - #[rustfmt::skip] - "atomic_xadd_acqrel" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::Add, false), AtomicRwOrd::AcqRel)?, - #[rustfmt::skip] - "atomic_xadd_relaxed" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::Add, false), AtomicRwOrd::Relaxed)?, - #[rustfmt::skip] - "atomic_xsub_seqcst" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::Sub, false), AtomicRwOrd::SeqCst)?, - #[rustfmt::skip] - "atomic_xsub_acquire" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::Sub, false), AtomicRwOrd::Acquire)?, - #[rustfmt::skip] - "atomic_xsub_release" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::Sub, false), AtomicRwOrd::Release)?, - #[rustfmt::skip] - "atomic_xsub_acqrel" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::Sub, false), AtomicRwOrd::AcqRel)?, - #[rustfmt::skip] - "atomic_xsub_relaxed" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::Sub, false), AtomicRwOrd::Relaxed)?, - "atomic_min_seqcst" => - this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOrd::SeqCst)?, - "atomic_min_acquire" => - this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOrd::Acquire)?, - "atomic_min_release" => - this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOrd::Release)?, - "atomic_min_acqrel" => - this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOrd::AcqRel)?, - "atomic_min_relaxed" => - this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOrd::Relaxed)?, - "atomic_max_seqcst" => - this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOrd::SeqCst)?, - "atomic_max_acquire" => - this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOrd::Acquire)?, - "atomic_max_release" => - this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOrd::Release)?, - "atomic_max_acqrel" => - this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOrd::AcqRel)?, - "atomic_max_relaxed" => - this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOrd::Relaxed)?, - "atomic_umin_seqcst" => - this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOrd::SeqCst)?, - "atomic_umin_acquire" => - this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOrd::Acquire)?, - "atomic_umin_release" => - this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOrd::Release)?, - "atomic_umin_acqrel" => - this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOrd::AcqRel)?, - "atomic_umin_relaxed" => - this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOrd::Relaxed)?, - "atomic_umax_seqcst" => - this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOrd::SeqCst)?, - "atomic_umax_acquire" => - this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOrd::Acquire)?, - "atomic_umax_release" => - this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOrd::Release)?, - "atomic_umax_acqrel" => - this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOrd::AcqRel)?, - "atomic_umax_relaxed" => - this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOrd::Relaxed)?, - // Other "exact_div" => { let [num, denom] = check_arg_count(args)?; this.exact_div(&this.read_immediate(num)?, &this.read_immediate(denom)?, dest)?; } - "try" => return this.handle_try(args, dest, ret), - "breakpoint" => { let [] = check_arg_count(args)?; // normally this would raise a SIGTRAP, which aborts if no debugger is connected @@ -1092,227 +897,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx name => throw_unsup_format!("unimplemented intrinsic: `{name}`"), } - trace!("{:?}", this.dump_place(**dest)); - this.go_to_block(ret); - Ok(()) - } - - fn atomic_load( - &mut self, - args: &[OpTy<'tcx, Tag>], - dest: &PlaceTy<'tcx, Tag>, - atomic: AtomicReadOrd, - ) -> InterpResult<'tcx> { - let this = self.eval_context_mut(); - - let [place] = check_arg_count(args)?; - let place = this.deref_operand(place)?; - - // make sure it fits into a scalar; otherwise it cannot be atomic - let val = this.read_scalar_atomic(&place, atomic)?; - - // Check alignment requirements. Atomics must always be aligned to their size, - // even if the type they wrap would be less aligned (e.g. AtomicU64 on 32bit must - // be 8-aligned). - let align = Align::from_bytes(place.layout.size.bytes()).unwrap(); - this.check_ptr_access_align( - place.ptr, - place.layout.size, - align, - CheckInAllocMsg::MemoryAccessTest, - )?; - // Perform regular access. - this.write_scalar(val, dest)?; - Ok(()) - } - - fn atomic_store( - &mut self, - args: &[OpTy<'tcx, Tag>], - atomic: AtomicWriteOrd, - ) -> InterpResult<'tcx> { - let this = self.eval_context_mut(); - - let [place, val] = check_arg_count(args)?; - let place = this.deref_operand(place)?; - let val = this.read_scalar(val)?; // make sure it fits into a scalar; otherwise it cannot be atomic - - // Check alignment requirements. Atomics must always be aligned to their size, - // even if the type they wrap would be less aligned (e.g. AtomicU64 on 32bit must - // be 8-aligned). - let align = Align::from_bytes(place.layout.size.bytes()).unwrap(); - this.check_ptr_access_align( - place.ptr, - place.layout.size, - align, - CheckInAllocMsg::MemoryAccessTest, - )?; - - // Perform atomic store - this.write_scalar_atomic(val, &place, atomic)?; - Ok(()) - } - - fn compiler_fence( - &mut self, - args: &[OpTy<'tcx, Tag>], - atomic: AtomicFenceOrd, - ) -> InterpResult<'tcx> { - let [] = check_arg_count(args)?; - let _ = atomic; - //FIXME: compiler fences are currently ignored Ok(()) } - fn atomic_fence( - &mut self, - args: &[OpTy<'tcx, Tag>], - atomic: AtomicFenceOrd, - ) -> InterpResult<'tcx> { - let this = self.eval_context_mut(); - let [] = check_arg_count(args)?; - this.validate_atomic_fence(atomic)?; - Ok(()) - } - - fn atomic_op( - &mut self, - args: &[OpTy<'tcx, Tag>], - dest: &PlaceTy<'tcx, Tag>, - atomic_op: AtomicOp, - atomic: AtomicRwOrd, - ) -> InterpResult<'tcx> { - let this = self.eval_context_mut(); - - let [place, rhs] = check_arg_count(args)?; - let place = this.deref_operand(place)?; - - if !place.layout.ty.is_integral() && !place.layout.ty.is_unsafe_ptr() { - span_bug!( - this.cur_span(), - "atomic arithmetic operations only work on integer and raw pointer types", - ); - } - let rhs = this.read_immediate(rhs)?; - - // Check alignment requirements. Atomics must always be aligned to their size, - // even if the type they wrap would be less aligned (e.g. AtomicU64 on 32bit must - // be 8-aligned). - let align = Align::from_bytes(place.layout.size.bytes()).unwrap(); - this.check_ptr_access_align( - place.ptr, - place.layout.size, - align, - CheckInAllocMsg::MemoryAccessTest, - )?; - - match atomic_op { - AtomicOp::Min => { - let old = this.atomic_min_max_scalar(&place, rhs, true, atomic)?; - this.write_immediate(*old, dest)?; // old value is returned - Ok(()) - } - AtomicOp::Max => { - let old = this.atomic_min_max_scalar(&place, rhs, false, atomic)?; - this.write_immediate(*old, dest)?; // old value is returned - Ok(()) - } - AtomicOp::MirOp(op, neg) => { - let old = this.atomic_op_immediate(&place, &rhs, op, neg, atomic)?; - this.write_immediate(*old, dest)?; // old value is returned - Ok(()) - } - } - } - - fn atomic_exchange( - &mut self, - args: &[OpTy<'tcx, Tag>], - dest: &PlaceTy<'tcx, Tag>, - atomic: AtomicRwOrd, - ) -> InterpResult<'tcx> { - let this = self.eval_context_mut(); - - let [place, new] = check_arg_count(args)?; - let place = this.deref_operand(place)?; - let new = this.read_scalar(new)?; - - // Check alignment requirements. Atomics must always be aligned to their size, - // even if the type they wrap would be less aligned (e.g. AtomicU64 on 32bit must - // be 8-aligned). - let align = Align::from_bytes(place.layout.size.bytes()).unwrap(); - this.check_ptr_access_align( - place.ptr, - place.layout.size, - align, - CheckInAllocMsg::MemoryAccessTest, - )?; - - let old = this.atomic_exchange_scalar(&place, new, atomic)?; - this.write_scalar(old, dest)?; // old value is returned - Ok(()) - } - - fn atomic_compare_exchange_impl( - &mut self, - args: &[OpTy<'tcx, Tag>], - dest: &PlaceTy<'tcx, Tag>, - success: AtomicRwOrd, - fail: AtomicReadOrd, - can_fail_spuriously: bool, - ) -> InterpResult<'tcx> { - let this = self.eval_context_mut(); - - let [place, expect_old, new] = check_arg_count(args)?; - let place = this.deref_operand(place)?; - let expect_old = this.read_immediate(expect_old)?; // read as immediate for the sake of `binary_op()` - let new = this.read_scalar(new)?; - - // Check alignment requirements. Atomics must always be aligned to their size, - // even if the type they wrap would be less aligned (e.g. AtomicU64 on 32bit must - // be 8-aligned). - let align = Align::from_bytes(place.layout.size.bytes()).unwrap(); - this.check_ptr_access_align( - place.ptr, - place.layout.size, - align, - CheckInAllocMsg::MemoryAccessTest, - )?; - - let old = this.atomic_compare_exchange_scalar( - &place, - &expect_old, - new, - success, - fail, - can_fail_spuriously, - )?; - - // Return old value. - this.write_immediate(old, dest)?; - Ok(()) - } - - fn atomic_compare_exchange( - &mut self, - args: &[OpTy<'tcx, Tag>], - dest: &PlaceTy<'tcx, Tag>, - success: AtomicRwOrd, - fail: AtomicReadOrd, - ) -> InterpResult<'tcx> { - self.atomic_compare_exchange_impl(args, dest, success, fail, false) - } - - fn atomic_compare_exchange_weak( - &mut self, - args: &[OpTy<'tcx, Tag>], - dest: &PlaceTy<'tcx, Tag>, - success: AtomicRwOrd, - fail: AtomicReadOrd, - ) -> InterpResult<'tcx> { - self.atomic_compare_exchange_impl(args, dest, success, fail, true) - } - fn float_to_int_unchecked( &self, f: F, From 53ead1b8c960a63a9422725d54d405c65756a1bb Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 18 Jul 2022 08:00:36 -0400 Subject: [PATCH 3503/3747] move simd intrinsics to their own file --- src/shims/intrinsics/atomic.rs | 1 - src/shims/intrinsics/mod.rs | 599 +------------------------------- src/shims/intrinsics/simd.rs | 613 +++++++++++++++++++++++++++++++++ 3 files changed, 620 insertions(+), 593 deletions(-) create mode 100644 src/shims/intrinsics/simd.rs diff --git a/src/shims/intrinsics/atomic.rs b/src/shims/intrinsics/atomic.rs index 2ba591127cea4..e51fd98c5522d 100644 --- a/src/shims/intrinsics/atomic.rs +++ b/src/shims/intrinsics/atomic.rs @@ -21,7 +21,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); match intrinsic_name { - // Atomic operations "load_seqcst" => this.atomic_load(args, dest, AtomicReadOrd::SeqCst)?, "load_relaxed" => this.atomic_load(args, dest, AtomicReadOrd::Relaxed)?, "load_acquire" => this.atomic_load(args, dest, AtomicReadOrd::Acquire)?, diff --git a/src/shims/intrinsics/mod.rs b/src/shims/intrinsics/mod.rs index 6195147259af2..a8b8b807bd828 100644 --- a/src/shims/intrinsics/mod.rs +++ b/src/shims/intrinsics/mod.rs @@ -1,16 +1,18 @@ pub mod atomic; +mod simd; use std::iter; use log::trace; use rustc_apfloat::{Float, Round}; -use rustc_middle::ty::layout::{HasParamEnv, IntegerExt, LayoutOf}; +use rustc_middle::ty::layout::{IntegerExt, LayoutOf}; use rustc_middle::{mir, ty, ty::FloatTy}; -use rustc_target::abi::{Endian, HasDataLayout, Integer, Size}; +use rustc_target::abi::Integer; use crate::*; use helpers::check_arg_count; +use simd::EvalContextExt as _; impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { @@ -63,6 +65,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if let Some(name) = intrinsic_name.strip_prefix("atomic_") { return this.emulate_atomic_intrinsic(name, args, dest); } + if let Some(name) = intrinsic_name.strip_prefix("simd_") { + return this.emulate_simd_intrinsic(name, args, dest); + } match intrinsic_name { // Miri overwriting CTFE intrinsics. @@ -347,541 +352,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(res, dest)?; } - // SIMD operations - #[rustfmt::skip] - | "simd_neg" - | "simd_fabs" - | "simd_ceil" - | "simd_floor" - | "simd_round" - | "simd_trunc" - | "simd_fsqrt" => { - let [op] = check_arg_count(args)?; - let (op, op_len) = this.operand_to_simd(op)?; - let (dest, dest_len) = this.place_to_simd(dest)?; - - assert_eq!(dest_len, op_len); - - #[derive(Copy, Clone)] - enum HostFloatOp { - Ceil, - Floor, - Round, - Trunc, - Sqrt, - } - #[derive(Copy, Clone)] - enum Op { - MirOp(mir::UnOp), - Abs, - HostOp(HostFloatOp), - } - let which = match intrinsic_name { - "simd_neg" => Op::MirOp(mir::UnOp::Neg), - "simd_fabs" => Op::Abs, - "simd_ceil" => Op::HostOp(HostFloatOp::Ceil), - "simd_floor" => Op::HostOp(HostFloatOp::Floor), - "simd_round" => Op::HostOp(HostFloatOp::Round), - "simd_trunc" => Op::HostOp(HostFloatOp::Trunc), - "simd_fsqrt" => Op::HostOp(HostFloatOp::Sqrt), - _ => unreachable!(), - }; - - for i in 0..dest_len { - let op = this.read_immediate(&this.mplace_index(&op, i)?.into())?; - let dest = this.mplace_index(&dest, i)?; - let val = match which { - Op::MirOp(mir_op) => this.unary_op(mir_op, &op)?.to_scalar()?, - Op::Abs => { - // Works for f32 and f64. - let ty::Float(float_ty) = op.layout.ty.kind() else { - span_bug!(this.cur_span(), "{} operand is not a float", intrinsic_name) - }; - let op = op.to_scalar()?; - match float_ty { - FloatTy::F32 => Scalar::from_f32(op.to_f32()?.abs()), - FloatTy::F64 => Scalar::from_f64(op.to_f64()?.abs()), - } - } - Op::HostOp(host_op) => { - let ty::Float(float_ty) = op.layout.ty.kind() else { - span_bug!(this.cur_span(), "{} operand is not a float", intrinsic_name) - }; - // FIXME using host floats - match float_ty { - FloatTy::F32 => { - let f = f32::from_bits(op.to_scalar()?.to_u32()?); - let res = match host_op { - HostFloatOp::Ceil => f.ceil(), - HostFloatOp::Floor => f.floor(), - HostFloatOp::Round => f.round(), - HostFloatOp::Trunc => f.trunc(), - HostFloatOp::Sqrt => f.sqrt(), - }; - Scalar::from_u32(res.to_bits()) - } - FloatTy::F64 => { - let f = f64::from_bits(op.to_scalar()?.to_u64()?); - let res = match host_op { - HostFloatOp::Ceil => f.ceil(), - HostFloatOp::Floor => f.floor(), - HostFloatOp::Round => f.round(), - HostFloatOp::Trunc => f.trunc(), - HostFloatOp::Sqrt => f.sqrt(), - }; - Scalar::from_u64(res.to_bits()) - } - } - - } - }; - this.write_scalar(val, &dest.into())?; - } - } - #[rustfmt::skip] - | "simd_add" - | "simd_sub" - | "simd_mul" - | "simd_div" - | "simd_rem" - | "simd_shl" - | "simd_shr" - | "simd_and" - | "simd_or" - | "simd_xor" - | "simd_eq" - | "simd_ne" - | "simd_lt" - | "simd_le" - | "simd_gt" - | "simd_ge" - | "simd_fmax" - | "simd_fmin" - | "simd_saturating_add" - | "simd_saturating_sub" - | "simd_arith_offset" => { - use mir::BinOp; - - let [left, right] = check_arg_count(args)?; - let (left, left_len) = this.operand_to_simd(left)?; - let (right, right_len) = this.operand_to_simd(right)?; - let (dest, dest_len) = this.place_to_simd(dest)?; - - assert_eq!(dest_len, left_len); - assert_eq!(dest_len, right_len); - - enum Op { - MirOp(BinOp), - SaturatingOp(BinOp), - FMax, - FMin, - WrappingOffset, - } - let which = match intrinsic_name { - "simd_add" => Op::MirOp(BinOp::Add), - "simd_sub" => Op::MirOp(BinOp::Sub), - "simd_mul" => Op::MirOp(BinOp::Mul), - "simd_div" => Op::MirOp(BinOp::Div), - "simd_rem" => Op::MirOp(BinOp::Rem), - "simd_shl" => Op::MirOp(BinOp::Shl), - "simd_shr" => Op::MirOp(BinOp::Shr), - "simd_and" => Op::MirOp(BinOp::BitAnd), - "simd_or" => Op::MirOp(BinOp::BitOr), - "simd_xor" => Op::MirOp(BinOp::BitXor), - "simd_eq" => Op::MirOp(BinOp::Eq), - "simd_ne" => Op::MirOp(BinOp::Ne), - "simd_lt" => Op::MirOp(BinOp::Lt), - "simd_le" => Op::MirOp(BinOp::Le), - "simd_gt" => Op::MirOp(BinOp::Gt), - "simd_ge" => Op::MirOp(BinOp::Ge), - "simd_fmax" => Op::FMax, - "simd_fmin" => Op::FMin, - "simd_saturating_add" => Op::SaturatingOp(BinOp::Add), - "simd_saturating_sub" => Op::SaturatingOp(BinOp::Sub), - "simd_arith_offset" => Op::WrappingOffset, - _ => unreachable!(), - }; - - for i in 0..dest_len { - let left = this.read_immediate(&this.mplace_index(&left, i)?.into())?; - let right = this.read_immediate(&this.mplace_index(&right, i)?.into())?; - let dest = this.mplace_index(&dest, i)?; - let val = match which { - Op::MirOp(mir_op) => { - let (val, overflowed, ty) = this.overflowing_binary_op(mir_op, &left, &right)?; - if matches!(mir_op, BinOp::Shl | BinOp::Shr) { - // Shifts have extra UB as SIMD operations that the MIR binop does not have. - // See . - if overflowed { - let r_val = right.to_scalar()?.to_bits(right.layout.size)?; - throw_ub_format!("overflowing shift by {r_val} in `{intrinsic_name}` in SIMD lane {i}"); - } - } - if matches!(mir_op, BinOp::Eq | BinOp::Ne | BinOp::Lt | BinOp::Le | BinOp::Gt | BinOp::Ge) { - // Special handling for boolean-returning operations - assert_eq!(ty, this.tcx.types.bool); - let val = val.to_bool().unwrap(); - bool_to_simd_element(val, dest.layout.size) - } else { - assert_ne!(ty, this.tcx.types.bool); - assert_eq!(ty, dest.layout.ty); - val - } - } - Op::SaturatingOp(mir_op) => { - this.saturating_arith(mir_op, &left, &right)? - } - Op::WrappingOffset => { - let ptr = this.scalar_to_ptr(left.to_scalar()?)?; - let offset_count = right.to_scalar()?.to_machine_isize(this)?; - let pointee_ty = left.layout.ty.builtin_deref(true).unwrap().ty; - - let pointee_size = i64::try_from(this.layout_of(pointee_ty)?.size.bytes()).unwrap(); - let offset_bytes = offset_count.wrapping_mul(pointee_size); - let offset_ptr = ptr.wrapping_signed_offset(offset_bytes, this); - Scalar::from_maybe_pointer(offset_ptr, this) - } - Op::FMax => { - fmax_op(&left, &right)? - } - Op::FMin => { - fmin_op(&left, &right)? - } - }; - this.write_scalar(val, &dest.into())?; - } - } - "simd_fma" => { - let [a, b, c] = check_arg_count(args)?; - let (a, a_len) = this.operand_to_simd(a)?; - let (b, b_len) = this.operand_to_simd(b)?; - let (c, c_len) = this.operand_to_simd(c)?; - let (dest, dest_len) = this.place_to_simd(dest)?; - - assert_eq!(dest_len, a_len); - assert_eq!(dest_len, b_len); - assert_eq!(dest_len, c_len); - - for i in 0..dest_len { - let a = this.read_immediate(&this.mplace_index(&a, i)?.into())?.to_scalar()?; - let b = this.read_immediate(&this.mplace_index(&b, i)?.into())?.to_scalar()?; - let c = this.read_immediate(&this.mplace_index(&c, i)?.into())?.to_scalar()?; - let dest = this.mplace_index(&dest, i)?; - - // Works for f32 and f64. - let ty::Float(float_ty) = dest.layout.ty.kind() else { - span_bug!(this.cur_span(), "{} operand is not a float", intrinsic_name) - }; - let val = match float_ty { - FloatTy::F32 => - Scalar::from_f32(a.to_f32()?.mul_add(b.to_f32()?, c.to_f32()?).value), - FloatTy::F64 => - Scalar::from_f64(a.to_f64()?.mul_add(b.to_f64()?, c.to_f64()?).value), - }; - this.write_scalar(val, &dest.into())?; - } - } - #[rustfmt::skip] - | "simd_reduce_and" - | "simd_reduce_or" - | "simd_reduce_xor" - | "simd_reduce_any" - | "simd_reduce_all" - | "simd_reduce_max" - | "simd_reduce_min" => { - use mir::BinOp; - - let [op] = check_arg_count(args)?; - let (op, op_len) = this.operand_to_simd(op)?; - - let imm_from_bool = - |b| ImmTy::from_scalar(Scalar::from_bool(b), this.machine.layouts.bool); - - enum Op { - MirOp(BinOp), - MirOpBool(BinOp), - Max, - Min, - } - let which = match intrinsic_name { - "simd_reduce_and" => Op::MirOp(BinOp::BitAnd), - "simd_reduce_or" => Op::MirOp(BinOp::BitOr), - "simd_reduce_xor" => Op::MirOp(BinOp::BitXor), - "simd_reduce_any" => Op::MirOpBool(BinOp::BitOr), - "simd_reduce_all" => Op::MirOpBool(BinOp::BitAnd), - "simd_reduce_max" => Op::Max, - "simd_reduce_min" => Op::Min, - _ => unreachable!(), - }; - - // Initialize with first lane, then proceed with the rest. - let mut res = this.read_immediate(&this.mplace_index(&op, 0)?.into())?; - if matches!(which, Op::MirOpBool(_)) { - // Convert to `bool` scalar. - res = imm_from_bool(simd_element_to_bool(res)?); - } - for i in 1..op_len { - let op = this.read_immediate(&this.mplace_index(&op, i)?.into())?; - res = match which { - Op::MirOp(mir_op) => { - this.binary_op(mir_op, &res, &op)? - } - Op::MirOpBool(mir_op) => { - let op = imm_from_bool(simd_element_to_bool(op)?); - this.binary_op(mir_op, &res, &op)? - } - Op::Max => { - if matches!(res.layout.ty.kind(), ty::Float(_)) { - ImmTy::from_scalar(fmax_op(&res, &op)?, res.layout) - } else { - // Just boring integers, so NaNs to worry about - if this.binary_op(BinOp::Ge, &res, &op)?.to_scalar()?.to_bool()? { - res - } else { - op - } - } - } - Op::Min => { - if matches!(res.layout.ty.kind(), ty::Float(_)) { - ImmTy::from_scalar(fmin_op(&res, &op)?, res.layout) - } else { - // Just boring integers, so NaNs to worry about - if this.binary_op(BinOp::Le, &res, &op)?.to_scalar()?.to_bool()? { - res - } else { - op - } - } - } - }; - } - this.write_immediate(*res, dest)?; - } - #[rustfmt::skip] - | "simd_reduce_add_ordered" - | "simd_reduce_mul_ordered" => { - use mir::BinOp; - - let [op, init] = check_arg_count(args)?; - let (op, op_len) = this.operand_to_simd(op)?; - let init = this.read_immediate(init)?; - - let mir_op = match intrinsic_name { - "simd_reduce_add_ordered" => BinOp::Add, - "simd_reduce_mul_ordered" => BinOp::Mul, - _ => unreachable!(), - }; - - let mut res = init; - for i in 0..op_len { - let op = this.read_immediate(&this.mplace_index(&op, i)?.into())?; - res = this.binary_op(mir_op, &res, &op)?; - } - this.write_immediate(*res, dest)?; - } - "simd_select" => { - let [mask, yes, no] = check_arg_count(args)?; - let (mask, mask_len) = this.operand_to_simd(mask)?; - let (yes, yes_len) = this.operand_to_simd(yes)?; - let (no, no_len) = this.operand_to_simd(no)?; - let (dest, dest_len) = this.place_to_simd(dest)?; - - assert_eq!(dest_len, mask_len); - assert_eq!(dest_len, yes_len); - assert_eq!(dest_len, no_len); - - for i in 0..dest_len { - let mask = this.read_immediate(&this.mplace_index(&mask, i)?.into())?; - let yes = this.read_immediate(&this.mplace_index(&yes, i)?.into())?; - let no = this.read_immediate(&this.mplace_index(&no, i)?.into())?; - let dest = this.mplace_index(&dest, i)?; - - let val = if simd_element_to_bool(mask)? { yes } else { no }; - this.write_immediate(*val, &dest.into())?; - } - } - "simd_select_bitmask" => { - let [mask, yes, no] = check_arg_count(args)?; - let (yes, yes_len) = this.operand_to_simd(yes)?; - let (no, no_len) = this.operand_to_simd(no)?; - let (dest, dest_len) = this.place_to_simd(dest)?; - let bitmask_len = dest_len.max(8); - - assert!(mask.layout.ty.is_integral()); - assert!(bitmask_len <= 64); - assert_eq!(bitmask_len, mask.layout.size.bits()); - assert_eq!(dest_len, yes_len); - assert_eq!(dest_len, no_len); - - let mask: u64 = this - .read_scalar(mask)? - .check_init()? - .to_bits(mask.layout.size)? - .try_into() - .unwrap(); - for i in 0..dest_len { - let mask = - mask & (1 << simd_bitmask_index(i, dest_len, this.data_layout().endian)); - let yes = this.read_immediate(&this.mplace_index(&yes, i)?.into())?; - let no = this.read_immediate(&this.mplace_index(&no, i)?.into())?; - let dest = this.mplace_index(&dest, i)?; - - let val = if mask != 0 { yes } else { no }; - this.write_immediate(*val, &dest.into())?; - } - for i in dest_len..bitmask_len { - // If the mask is "padded", ensure that padding is all-zero. - let mask = mask & (1 << i); - if mask != 0 { - throw_ub_format!( - "a SIMD bitmask less than 8 bits long must be filled with 0s for the remaining bits" - ); - } - } - } - #[rustfmt::skip] - "simd_cast" | "simd_as" => { - let [op] = check_arg_count(args)?; - let (op, op_len) = this.operand_to_simd(op)?; - let (dest, dest_len) = this.place_to_simd(dest)?; - - assert_eq!(dest_len, op_len); - - let safe_cast = intrinsic_name == "simd_as"; - - for i in 0..dest_len { - let op = this.read_immediate(&this.mplace_index(&op, i)?.into())?; - let dest = this.mplace_index(&dest, i)?; - - let val = match (op.layout.ty.kind(), dest.layout.ty.kind()) { - // Int-to-(int|float): always safe - (ty::Int(_) | ty::Uint(_), ty::Int(_) | ty::Uint(_) | ty::Float(_)) => - this.misc_cast(&op, dest.layout.ty)?, - // Float-to-float: always safe - (ty::Float(_), ty::Float(_)) => - this.misc_cast(&op, dest.layout.ty)?, - // Float-to-int in safe mode - (ty::Float(_), ty::Int(_) | ty::Uint(_)) if safe_cast => - this.misc_cast(&op, dest.layout.ty)?, - // Float-to-int in unchecked mode - (ty::Float(FloatTy::F32), ty::Int(_) | ty::Uint(_)) if !safe_cast => - this.float_to_int_unchecked(op.to_scalar()?.to_f32()?, dest.layout.ty)?.into(), - (ty::Float(FloatTy::F64), ty::Int(_) | ty::Uint(_)) if !safe_cast => - this.float_to_int_unchecked(op.to_scalar()?.to_f64()?, dest.layout.ty)?.into(), - _ => - throw_unsup_format!( - "Unsupported SIMD cast from element type {from_ty} to {to_ty}", - from_ty = op.layout.ty, - to_ty = dest.layout.ty, - ), - }; - this.write_immediate(val, &dest.into())?; - } - } - "simd_shuffle" => { - let [left, right, index] = check_arg_count(args)?; - let (left, left_len) = this.operand_to_simd(left)?; - let (right, right_len) = this.operand_to_simd(right)?; - let (dest, dest_len) = this.place_to_simd(dest)?; - - // `index` is an array, not a SIMD type - let ty::Array(_, index_len) = index.layout.ty.kind() else { - span_bug!(this.cur_span(), "simd_shuffle index argument has non-array type {}", index.layout.ty) - }; - let index_len = index_len.eval_usize(*this.tcx, this.param_env()); - - assert_eq!(left_len, right_len); - assert_eq!(index_len, dest_len); - - for i in 0..dest_len { - let src_index: u64 = this - .read_immediate(&this.operand_index(index, i)?)? - .to_scalar()? - .to_u32()? - .into(); - let dest = this.mplace_index(&dest, i)?; - - let val = if src_index < left_len { - this.read_immediate(&this.mplace_index(&left, src_index)?.into())? - } else if src_index < left_len.checked_add(right_len).unwrap() { - this.read_immediate( - &this.mplace_index(&right, src_index - left_len)?.into(), - )? - } else { - span_bug!( - this.cur_span(), - "simd_shuffle index {src_index} is out of bounds for 2 vectors of size {left_len}", - ); - }; - this.write_immediate(*val, &dest.into())?; - } - } - "simd_gather" => { - let [passthru, ptrs, mask] = check_arg_count(args)?; - let (passthru, passthru_len) = this.operand_to_simd(passthru)?; - let (ptrs, ptrs_len) = this.operand_to_simd(ptrs)?; - let (mask, mask_len) = this.operand_to_simd(mask)?; - let (dest, dest_len) = this.place_to_simd(dest)?; - - assert_eq!(dest_len, passthru_len); - assert_eq!(dest_len, ptrs_len); - assert_eq!(dest_len, mask_len); - - for i in 0..dest_len { - let passthru = this.read_immediate(&this.mplace_index(&passthru, i)?.into())?; - let ptr = this.read_immediate(&this.mplace_index(&ptrs, i)?.into())?; - let mask = this.read_immediate(&this.mplace_index(&mask, i)?.into())?; - let dest = this.mplace_index(&dest, i)?; - - let val = if simd_element_to_bool(mask)? { - let place = this.deref_operand(&ptr.into())?; - this.read_immediate(&place.into())? - } else { - passthru - }; - this.write_immediate(*val, &dest.into())?; - } - } - "simd_scatter" => { - let [value, ptrs, mask] = check_arg_count(args)?; - let (value, value_len) = this.operand_to_simd(value)?; - let (ptrs, ptrs_len) = this.operand_to_simd(ptrs)?; - let (mask, mask_len) = this.operand_to_simd(mask)?; - - assert_eq!(ptrs_len, value_len); - assert_eq!(ptrs_len, mask_len); - - for i in 0..ptrs_len { - let value = this.read_immediate(&this.mplace_index(&value, i)?.into())?; - let ptr = this.read_immediate(&this.mplace_index(&ptrs, i)?.into())?; - let mask = this.read_immediate(&this.mplace_index(&mask, i)?.into())?; - - if simd_element_to_bool(mask)? { - let place = this.deref_operand(&ptr.into())?; - this.write_immediate(*value, &place.into())?; - } - } - } - "simd_bitmask" => { - let [op] = check_arg_count(args)?; - let (op, op_len) = this.operand_to_simd(op)?; - let bitmask_len = op_len.max(8); - - assert!(dest.layout.ty.is_integral()); - assert!(bitmask_len <= 64); - assert_eq!(bitmask_len, dest.layout.size.bits()); - - let mut res = 0u64; - for i in 0..op_len { - let op = this.read_immediate(&this.mplace_index(&op, i)?.into())?; - if simd_element_to_bool(op)? { - res |= 1 << simd_bitmask_index(i, op_len, this.data_layout().endian); - } - } - this.write_int(res, dest)?; - } - // Other "exact_div" => { let [num, denom] = check_arg_count(args)?; @@ -953,58 +423,3 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx }) } } - -fn fmax_op<'tcx>( - left: &ImmTy<'tcx, Tag>, - right: &ImmTy<'tcx, Tag>, -) -> InterpResult<'tcx, Scalar> { - assert_eq!(left.layout.ty, right.layout.ty); - let ty::Float(float_ty) = left.layout.ty.kind() else { - bug!("fmax operand is not a float") - }; - let left = left.to_scalar()?; - let right = right.to_scalar()?; - Ok(match float_ty { - FloatTy::F32 => Scalar::from_f32(left.to_f32()?.max(right.to_f32()?)), - FloatTy::F64 => Scalar::from_f64(left.to_f64()?.max(right.to_f64()?)), - }) -} - -fn fmin_op<'tcx>( - left: &ImmTy<'tcx, Tag>, - right: &ImmTy<'tcx, Tag>, -) -> InterpResult<'tcx, Scalar> { - assert_eq!(left.layout.ty, right.layout.ty); - let ty::Float(float_ty) = left.layout.ty.kind() else { - bug!("fmin operand is not a float") - }; - let left = left.to_scalar()?; - let right = right.to_scalar()?; - Ok(match float_ty { - FloatTy::F32 => Scalar::from_f32(left.to_f32()?.min(right.to_f32()?)), - FloatTy::F64 => Scalar::from_f64(left.to_f64()?.min(right.to_f64()?)), - }) -} - -fn bool_to_simd_element(b: bool, size: Size) -> Scalar { - // SIMD uses all-1 as pattern for "true" - let val = if b { -1 } else { 0 }; - Scalar::from_int(val, size) -} - -fn simd_element_to_bool(elem: ImmTy<'_, Tag>) -> InterpResult<'_, bool> { - let val = elem.to_scalar()?.to_int(elem.layout.size)?; - Ok(match val { - 0 => false, - -1 => true, - _ => throw_ub_format!("each element of a SIMD mask must be all-0-bits or all-1-bits"), - }) -} - -fn simd_bitmask_index(idx: u64, vec_len: u64, endianess: Endian) -> u64 { - assert!(idx < vec_len); - match endianess { - Endian::Little => idx, - Endian::Big => vec_len - 1 - idx, // reverse order of bits - } -} diff --git a/src/shims/intrinsics/simd.rs b/src/shims/intrinsics/simd.rs new file mode 100644 index 0000000000000..fe5250ed08434 --- /dev/null +++ b/src/shims/intrinsics/simd.rs @@ -0,0 +1,613 @@ +use rustc_apfloat::Float; +use rustc_middle::ty::layout::{HasParamEnv, LayoutOf}; +use rustc_middle::{mir, ty, ty::FloatTy}; +use rustc_target::abi::{Endian, HasDataLayout, Size}; + +use crate::*; +use helpers::check_arg_count; + +impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} +pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { + /// Calls the simd intrinsic `intrinsic`; the `simd_` prefix has already been removed. + fn emulate_simd_intrinsic( + &mut self, + intrinsic_name: &str, + args: &[OpTy<'tcx, Tag>], + dest: &PlaceTy<'tcx, Tag>, + ) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + match intrinsic_name { + #[rustfmt::skip] + | "neg" + | "fabs" + | "ceil" + | "floor" + | "round" + | "trunc" + | "fsqrt" => { + let [op] = check_arg_count(args)?; + let (op, op_len) = this.operand_to_simd(op)?; + let (dest, dest_len) = this.place_to_simd(dest)?; + + assert_eq!(dest_len, op_len); + + #[derive(Copy, Clone)] + enum HostFloatOp { + Ceil, + Floor, + Round, + Trunc, + Sqrt, + } + #[derive(Copy, Clone)] + enum Op { + MirOp(mir::UnOp), + Abs, + HostOp(HostFloatOp), + } + let which = match intrinsic_name { + "neg" => Op::MirOp(mir::UnOp::Neg), + "fabs" => Op::Abs, + "ceil" => Op::HostOp(HostFloatOp::Ceil), + "floor" => Op::HostOp(HostFloatOp::Floor), + "round" => Op::HostOp(HostFloatOp::Round), + "trunc" => Op::HostOp(HostFloatOp::Trunc), + "fsqrt" => Op::HostOp(HostFloatOp::Sqrt), + _ => unreachable!(), + }; + + for i in 0..dest_len { + let op = this.read_immediate(&this.mplace_index(&op, i)?.into())?; + let dest = this.mplace_index(&dest, i)?; + let val = match which { + Op::MirOp(mir_op) => this.unary_op(mir_op, &op)?.to_scalar()?, + Op::Abs => { + // Works for f32 and f64. + let ty::Float(float_ty) = op.layout.ty.kind() else { + span_bug!(this.cur_span(), "{} operand is not a float", intrinsic_name) + }; + let op = op.to_scalar()?; + match float_ty { + FloatTy::F32 => Scalar::from_f32(op.to_f32()?.abs()), + FloatTy::F64 => Scalar::from_f64(op.to_f64()?.abs()), + } + } + Op::HostOp(host_op) => { + let ty::Float(float_ty) = op.layout.ty.kind() else { + span_bug!(this.cur_span(), "{} operand is not a float", intrinsic_name) + }; + // FIXME using host floats + match float_ty { + FloatTy::F32 => { + let f = f32::from_bits(op.to_scalar()?.to_u32()?); + let res = match host_op { + HostFloatOp::Ceil => f.ceil(), + HostFloatOp::Floor => f.floor(), + HostFloatOp::Round => f.round(), + HostFloatOp::Trunc => f.trunc(), + HostFloatOp::Sqrt => f.sqrt(), + }; + Scalar::from_u32(res.to_bits()) + } + FloatTy::F64 => { + let f = f64::from_bits(op.to_scalar()?.to_u64()?); + let res = match host_op { + HostFloatOp::Ceil => f.ceil(), + HostFloatOp::Floor => f.floor(), + HostFloatOp::Round => f.round(), + HostFloatOp::Trunc => f.trunc(), + HostFloatOp::Sqrt => f.sqrt(), + }; + Scalar::from_u64(res.to_bits()) + } + } + + } + }; + this.write_scalar(val, &dest.into())?; + } + } + #[rustfmt::skip] + | "add" + | "sub" + | "mul" + | "div" + | "rem" + | "shl" + | "shr" + | "and" + | "or" + | "xor" + | "eq" + | "ne" + | "lt" + | "le" + | "gt" + | "ge" + | "fmax" + | "fmin" + | "saturating_add" + | "saturating_sub" + | "arith_offset" => { + use mir::BinOp; + + let [left, right] = check_arg_count(args)?; + let (left, left_len) = this.operand_to_simd(left)?; + let (right, right_len) = this.operand_to_simd(right)?; + let (dest, dest_len) = this.place_to_simd(dest)?; + + assert_eq!(dest_len, left_len); + assert_eq!(dest_len, right_len); + + enum Op { + MirOp(BinOp), + SaturatingOp(BinOp), + FMax, + FMin, + WrappingOffset, + } + let which = match intrinsic_name { + "add" => Op::MirOp(BinOp::Add), + "sub" => Op::MirOp(BinOp::Sub), + "mul" => Op::MirOp(BinOp::Mul), + "div" => Op::MirOp(BinOp::Div), + "rem" => Op::MirOp(BinOp::Rem), + "shl" => Op::MirOp(BinOp::Shl), + "shr" => Op::MirOp(BinOp::Shr), + "and" => Op::MirOp(BinOp::BitAnd), + "or" => Op::MirOp(BinOp::BitOr), + "xor" => Op::MirOp(BinOp::BitXor), + "eq" => Op::MirOp(BinOp::Eq), + "ne" => Op::MirOp(BinOp::Ne), + "lt" => Op::MirOp(BinOp::Lt), + "le" => Op::MirOp(BinOp::Le), + "gt" => Op::MirOp(BinOp::Gt), + "ge" => Op::MirOp(BinOp::Ge), + "fmax" => Op::FMax, + "fmin" => Op::FMin, + "saturating_add" => Op::SaturatingOp(BinOp::Add), + "saturating_sub" => Op::SaturatingOp(BinOp::Sub), + "arith_offset" => Op::WrappingOffset, + _ => unreachable!(), + }; + + for i in 0..dest_len { + let left = this.read_immediate(&this.mplace_index(&left, i)?.into())?; + let right = this.read_immediate(&this.mplace_index(&right, i)?.into())?; + let dest = this.mplace_index(&dest, i)?; + let val = match which { + Op::MirOp(mir_op) => { + let (val, overflowed, ty) = this.overflowing_binary_op(mir_op, &left, &right)?; + if matches!(mir_op, BinOp::Shl | BinOp::Shr) { + // Shifts have extra UB as SIMD operations that the MIR binop does not have. + // See . + if overflowed { + let r_val = right.to_scalar()?.to_bits(right.layout.size)?; + throw_ub_format!("overflowing shift by {r_val} in `simd_{intrinsic_name}` in SIMD lane {i}"); + } + } + if matches!(mir_op, BinOp::Eq | BinOp::Ne | BinOp::Lt | BinOp::Le | BinOp::Gt | BinOp::Ge) { + // Special handling for boolean-returning operations + assert_eq!(ty, this.tcx.types.bool); + let val = val.to_bool().unwrap(); + bool_to_simd_element(val, dest.layout.size) + } else { + assert_ne!(ty, this.tcx.types.bool); + assert_eq!(ty, dest.layout.ty); + val + } + } + Op::SaturatingOp(mir_op) => { + this.saturating_arith(mir_op, &left, &right)? + } + Op::WrappingOffset => { + let ptr = this.scalar_to_ptr(left.to_scalar()?)?; + let offset_count = right.to_scalar()?.to_machine_isize(this)?; + let pointee_ty = left.layout.ty.builtin_deref(true).unwrap().ty; + + let pointee_size = i64::try_from(this.layout_of(pointee_ty)?.size.bytes()).unwrap(); + let offset_bytes = offset_count.wrapping_mul(pointee_size); + let offset_ptr = ptr.wrapping_signed_offset(offset_bytes, this); + Scalar::from_maybe_pointer(offset_ptr, this) + } + Op::FMax => { + fmax_op(&left, &right)? + } + Op::FMin => { + fmin_op(&left, &right)? + } + }; + this.write_scalar(val, &dest.into())?; + } + } + "fma" => { + let [a, b, c] = check_arg_count(args)?; + let (a, a_len) = this.operand_to_simd(a)?; + let (b, b_len) = this.operand_to_simd(b)?; + let (c, c_len) = this.operand_to_simd(c)?; + let (dest, dest_len) = this.place_to_simd(dest)?; + + assert_eq!(dest_len, a_len); + assert_eq!(dest_len, b_len); + assert_eq!(dest_len, c_len); + + for i in 0..dest_len { + let a = this.read_immediate(&this.mplace_index(&a, i)?.into())?.to_scalar()?; + let b = this.read_immediate(&this.mplace_index(&b, i)?.into())?.to_scalar()?; + let c = this.read_immediate(&this.mplace_index(&c, i)?.into())?.to_scalar()?; + let dest = this.mplace_index(&dest, i)?; + + // Works for f32 and f64. + let ty::Float(float_ty) = dest.layout.ty.kind() else { + span_bug!(this.cur_span(), "{} operand is not a float", intrinsic_name) + }; + let val = match float_ty { + FloatTy::F32 => + Scalar::from_f32(a.to_f32()?.mul_add(b.to_f32()?, c.to_f32()?).value), + FloatTy::F64 => + Scalar::from_f64(a.to_f64()?.mul_add(b.to_f64()?, c.to_f64()?).value), + }; + this.write_scalar(val, &dest.into())?; + } + } + #[rustfmt::skip] + | "reduce_and" + | "reduce_or" + | "reduce_xor" + | "reduce_any" + | "reduce_all" + | "reduce_max" + | "reduce_min" => { + use mir::BinOp; + + let [op] = check_arg_count(args)?; + let (op, op_len) = this.operand_to_simd(op)?; + + let imm_from_bool = + |b| ImmTy::from_scalar(Scalar::from_bool(b), this.machine.layouts.bool); + + enum Op { + MirOp(BinOp), + MirOpBool(BinOp), + Max, + Min, + } + let which = match intrinsic_name { + "reduce_and" => Op::MirOp(BinOp::BitAnd), + "reduce_or" => Op::MirOp(BinOp::BitOr), + "reduce_xor" => Op::MirOp(BinOp::BitXor), + "reduce_any" => Op::MirOpBool(BinOp::BitOr), + "reduce_all" => Op::MirOpBool(BinOp::BitAnd), + "reduce_max" => Op::Max, + "reduce_min" => Op::Min, + _ => unreachable!(), + }; + + // Initialize with first lane, then proceed with the rest. + let mut res = this.read_immediate(&this.mplace_index(&op, 0)?.into())?; + if matches!(which, Op::MirOpBool(_)) { + // Convert to `bool` scalar. + res = imm_from_bool(simd_element_to_bool(res)?); + } + for i in 1..op_len { + let op = this.read_immediate(&this.mplace_index(&op, i)?.into())?; + res = match which { + Op::MirOp(mir_op) => { + this.binary_op(mir_op, &res, &op)? + } + Op::MirOpBool(mir_op) => { + let op = imm_from_bool(simd_element_to_bool(op)?); + this.binary_op(mir_op, &res, &op)? + } + Op::Max => { + if matches!(res.layout.ty.kind(), ty::Float(_)) { + ImmTy::from_scalar(fmax_op(&res, &op)?, res.layout) + } else { + // Just boring integers, so NaNs to worry about + if this.binary_op(BinOp::Ge, &res, &op)?.to_scalar()?.to_bool()? { + res + } else { + op + } + } + } + Op::Min => { + if matches!(res.layout.ty.kind(), ty::Float(_)) { + ImmTy::from_scalar(fmin_op(&res, &op)?, res.layout) + } else { + // Just boring integers, so NaNs to worry about + if this.binary_op(BinOp::Le, &res, &op)?.to_scalar()?.to_bool()? { + res + } else { + op + } + } + } + }; + } + this.write_immediate(*res, dest)?; + } + #[rustfmt::skip] + | "reduce_add_ordered" + | "reduce_mul_ordered" => { + use mir::BinOp; + + let [op, init] = check_arg_count(args)?; + let (op, op_len) = this.operand_to_simd(op)?; + let init = this.read_immediate(init)?; + + let mir_op = match intrinsic_name { + "reduce_add_ordered" => BinOp::Add, + "reduce_mul_ordered" => BinOp::Mul, + _ => unreachable!(), + }; + + let mut res = init; + for i in 0..op_len { + let op = this.read_immediate(&this.mplace_index(&op, i)?.into())?; + res = this.binary_op(mir_op, &res, &op)?; + } + this.write_immediate(*res, dest)?; + } + "select" => { + let [mask, yes, no] = check_arg_count(args)?; + let (mask, mask_len) = this.operand_to_simd(mask)?; + let (yes, yes_len) = this.operand_to_simd(yes)?; + let (no, no_len) = this.operand_to_simd(no)?; + let (dest, dest_len) = this.place_to_simd(dest)?; + + assert_eq!(dest_len, mask_len); + assert_eq!(dest_len, yes_len); + assert_eq!(dest_len, no_len); + + for i in 0..dest_len { + let mask = this.read_immediate(&this.mplace_index(&mask, i)?.into())?; + let yes = this.read_immediate(&this.mplace_index(&yes, i)?.into())?; + let no = this.read_immediate(&this.mplace_index(&no, i)?.into())?; + let dest = this.mplace_index(&dest, i)?; + + let val = if simd_element_to_bool(mask)? { yes } else { no }; + this.write_immediate(*val, &dest.into())?; + } + } + "select_bitmask" => { + let [mask, yes, no] = check_arg_count(args)?; + let (yes, yes_len) = this.operand_to_simd(yes)?; + let (no, no_len) = this.operand_to_simd(no)?; + let (dest, dest_len) = this.place_to_simd(dest)?; + let bitmask_len = dest_len.max(8); + + assert!(mask.layout.ty.is_integral()); + assert!(bitmask_len <= 64); + assert_eq!(bitmask_len, mask.layout.size.bits()); + assert_eq!(dest_len, yes_len); + assert_eq!(dest_len, no_len); + + let mask: u64 = this + .read_scalar(mask)? + .check_init()? + .to_bits(mask.layout.size)? + .try_into() + .unwrap(); + for i in 0..dest_len { + let mask = + mask & (1 << simd_bitmask_index(i, dest_len, this.data_layout().endian)); + let yes = this.read_immediate(&this.mplace_index(&yes, i)?.into())?; + let no = this.read_immediate(&this.mplace_index(&no, i)?.into())?; + let dest = this.mplace_index(&dest, i)?; + + let val = if mask != 0 { yes } else { no }; + this.write_immediate(*val, &dest.into())?; + } + for i in dest_len..bitmask_len { + // If the mask is "padded", ensure that padding is all-zero. + let mask = mask & (1 << i); + if mask != 0 { + throw_ub_format!( + "a SIMD bitmask less than 8 bits long must be filled with 0s for the remaining bits" + ); + } + } + } + #[rustfmt::skip] + "cast" | "as" => { + let [op] = check_arg_count(args)?; + let (op, op_len) = this.operand_to_simd(op)?; + let (dest, dest_len) = this.place_to_simd(dest)?; + + assert_eq!(dest_len, op_len); + + let safe_cast = intrinsic_name == "as"; + + for i in 0..dest_len { + let op = this.read_immediate(&this.mplace_index(&op, i)?.into())?; + let dest = this.mplace_index(&dest, i)?; + + let val = match (op.layout.ty.kind(), dest.layout.ty.kind()) { + // Int-to-(int|float): always safe + (ty::Int(_) | ty::Uint(_), ty::Int(_) | ty::Uint(_) | ty::Float(_)) => + this.misc_cast(&op, dest.layout.ty)?, + // Float-to-float: always safe + (ty::Float(_), ty::Float(_)) => + this.misc_cast(&op, dest.layout.ty)?, + // Float-to-int in safe mode + (ty::Float(_), ty::Int(_) | ty::Uint(_)) if safe_cast => + this.misc_cast(&op, dest.layout.ty)?, + // Float-to-int in unchecked mode + (ty::Float(FloatTy::F32), ty::Int(_) | ty::Uint(_)) if !safe_cast => + this.float_to_int_unchecked(op.to_scalar()?.to_f32()?, dest.layout.ty)?.into(), + (ty::Float(FloatTy::F64), ty::Int(_) | ty::Uint(_)) if !safe_cast => + this.float_to_int_unchecked(op.to_scalar()?.to_f64()?, dest.layout.ty)?.into(), + _ => + throw_unsup_format!( + "Unsupported SIMD cast from element type {from_ty} to {to_ty}", + from_ty = op.layout.ty, + to_ty = dest.layout.ty, + ), + }; + this.write_immediate(val, &dest.into())?; + } + } + "shuffle" => { + let [left, right, index] = check_arg_count(args)?; + let (left, left_len) = this.operand_to_simd(left)?; + let (right, right_len) = this.operand_to_simd(right)?; + let (dest, dest_len) = this.place_to_simd(dest)?; + + // `index` is an array, not a SIMD type + let ty::Array(_, index_len) = index.layout.ty.kind() else { + span_bug!(this.cur_span(), "simd_shuffle index argument has non-array type {}", index.layout.ty) + }; + let index_len = index_len.eval_usize(*this.tcx, this.param_env()); + + assert_eq!(left_len, right_len); + assert_eq!(index_len, dest_len); + + for i in 0..dest_len { + let src_index: u64 = this + .read_immediate(&this.operand_index(index, i)?)? + .to_scalar()? + .to_u32()? + .into(); + let dest = this.mplace_index(&dest, i)?; + + let val = if src_index < left_len { + this.read_immediate(&this.mplace_index(&left, src_index)?.into())? + } else if src_index < left_len.checked_add(right_len).unwrap() { + this.read_immediate( + &this.mplace_index(&right, src_index - left_len)?.into(), + )? + } else { + span_bug!( + this.cur_span(), + "simd_shuffle index {src_index} is out of bounds for 2 vectors of size {left_len}", + ); + }; + this.write_immediate(*val, &dest.into())?; + } + } + "gather" => { + let [passthru, ptrs, mask] = check_arg_count(args)?; + let (passthru, passthru_len) = this.operand_to_simd(passthru)?; + let (ptrs, ptrs_len) = this.operand_to_simd(ptrs)?; + let (mask, mask_len) = this.operand_to_simd(mask)?; + let (dest, dest_len) = this.place_to_simd(dest)?; + + assert_eq!(dest_len, passthru_len); + assert_eq!(dest_len, ptrs_len); + assert_eq!(dest_len, mask_len); + + for i in 0..dest_len { + let passthru = this.read_immediate(&this.mplace_index(&passthru, i)?.into())?; + let ptr = this.read_immediate(&this.mplace_index(&ptrs, i)?.into())?; + let mask = this.read_immediate(&this.mplace_index(&mask, i)?.into())?; + let dest = this.mplace_index(&dest, i)?; + + let val = if simd_element_to_bool(mask)? { + let place = this.deref_operand(&ptr.into())?; + this.read_immediate(&place.into())? + } else { + passthru + }; + this.write_immediate(*val, &dest.into())?; + } + } + "scatter" => { + let [value, ptrs, mask] = check_arg_count(args)?; + let (value, value_len) = this.operand_to_simd(value)?; + let (ptrs, ptrs_len) = this.operand_to_simd(ptrs)?; + let (mask, mask_len) = this.operand_to_simd(mask)?; + + assert_eq!(ptrs_len, value_len); + assert_eq!(ptrs_len, mask_len); + + for i in 0..ptrs_len { + let value = this.read_immediate(&this.mplace_index(&value, i)?.into())?; + let ptr = this.read_immediate(&this.mplace_index(&ptrs, i)?.into())?; + let mask = this.read_immediate(&this.mplace_index(&mask, i)?.into())?; + + if simd_element_to_bool(mask)? { + let place = this.deref_operand(&ptr.into())?; + this.write_immediate(*value, &place.into())?; + } + } + } + "bitmask" => { + let [op] = check_arg_count(args)?; + let (op, op_len) = this.operand_to_simd(op)?; + let bitmask_len = op_len.max(8); + + assert!(dest.layout.ty.is_integral()); + assert!(bitmask_len <= 64); + assert_eq!(bitmask_len, dest.layout.size.bits()); + + let mut res = 0u64; + for i in 0..op_len { + let op = this.read_immediate(&this.mplace_index(&op, i)?.into())?; + if simd_element_to_bool(op)? { + res |= 1 << simd_bitmask_index(i, op_len, this.data_layout().endian); + } + } + this.write_int(res, dest)?; + } + + name => throw_unsup_format!("unimplemented intrinsic: `simd_{name}`"), + } + Ok(()) + } +} + +fn bool_to_simd_element(b: bool, size: Size) -> Scalar { + // SIMD uses all-1 as pattern for "true" + let val = if b { -1 } else { 0 }; + Scalar::from_int(val, size) +} + +fn simd_element_to_bool(elem: ImmTy<'_, Tag>) -> InterpResult<'_, bool> { + let val = elem.to_scalar()?.to_int(elem.layout.size)?; + Ok(match val { + 0 => false, + -1 => true, + _ => throw_ub_format!("each element of a SIMD mask must be all-0-bits or all-1-bits"), + }) +} + +fn simd_bitmask_index(idx: u64, vec_len: u64, endianess: Endian) -> u64 { + assert!(idx < vec_len); + match endianess { + Endian::Little => idx, + Endian::Big => vec_len - 1 - idx, // reverse order of bits + } +} + +fn fmax_op<'tcx>( + left: &ImmTy<'tcx, Tag>, + right: &ImmTy<'tcx, Tag>, +) -> InterpResult<'tcx, Scalar> { + assert_eq!(left.layout.ty, right.layout.ty); + let ty::Float(float_ty) = left.layout.ty.kind() else { + bug!("fmax operand is not a float") + }; + let left = left.to_scalar()?; + let right = right.to_scalar()?; + Ok(match float_ty { + FloatTy::F32 => Scalar::from_f32(left.to_f32()?.max(right.to_f32()?)), + FloatTy::F64 => Scalar::from_f64(left.to_f64()?.max(right.to_f64()?)), + }) +} + +fn fmin_op<'tcx>( + left: &ImmTy<'tcx, Tag>, + right: &ImmTy<'tcx, Tag>, +) -> InterpResult<'tcx, Scalar> { + assert_eq!(left.layout.ty, right.layout.ty); + let ty::Float(float_ty) = left.layout.ty.kind() else { + bug!("fmin operand is not a float") + }; + let left = left.to_scalar()?; + let right = right.to_scalar()?; + Ok(match float_ty { + FloatTy::F32 => Scalar::from_f32(left.to_f32()?.min(right.to_f32()?)), + FloatTy::F64 => Scalar::from_f64(left.to_f64()?.min(right.to_f64()?)), + }) +} From 1174cda4f1d3aff6d2a34e7300d5ea12769de0f5 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 18 Jul 2022 08:05:46 -0400 Subject: [PATCH 3504/3747] remove ret param from foreign_item hierarchy --- src/shims/foreign_items.rs | 9 ++++----- src/shims/unix/foreign_items.rs | 8 +++----- src/shims/unix/freebsd/foreign_items.rs | 2 -- src/shims/unix/linux/foreign_items.rs | 2 -- src/shims/unix/macos/foreign_items.rs | 2 -- src/shims/windows/foreign_items.rs | 2 -- 6 files changed, 7 insertions(+), 18 deletions(-) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index cd4fedad0fba0..8d82c912f3803 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -297,8 +297,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Some(p) => p, }; - // Second: functions that return. - match this.emulate_foreign_item_by_name(link_name, abi, args, dest, ret)? { + // Second: functions that return immediately. + match this.emulate_foreign_item_by_name(link_name, abi, args, dest)? { EmulateByNameResult::NeedsJumping => { trace!("{:?}", this.dump_place(**dest)); this.go_to_block(ret); @@ -355,7 +355,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx abi: Abi, args: &[OpTy<'tcx, Tag>], dest: &PlaceTy<'tcx, Tag>, - ret: mir::BasicBlock, ) -> InterpResult<'tcx, EmulateByNameResult<'mir, 'tcx>> { let this = self.eval_context_mut(); @@ -702,8 +701,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Platform-specific shims _ => match this.tcx.sess.target.os.as_ref() { - target if target_os_is_unix(target) => return shims::unix::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, abi, args, dest, ret), - "windows" => return shims::windows::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, abi, args, dest, ret), + target if target_os_is_unix(target) => return shims::unix::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, abi, args, dest), + "windows" => return shims::windows::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, abi, args, dest), target => throw_unsup_format!("the target `{}` is not supported", target), } }; diff --git a/src/shims/unix/foreign_items.rs b/src/shims/unix/foreign_items.rs index 57dfd6f1810c2..cf34b4baec7f7 100644 --- a/src/shims/unix/foreign_items.rs +++ b/src/shims/unix/foreign_items.rs @@ -2,7 +2,6 @@ use std::ffi::OsStr; use log::trace; -use rustc_middle::mir; use rustc_middle::ty::layout::LayoutOf; use rustc_span::Symbol; use rustc_target::abi::{Align, Size}; @@ -22,7 +21,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx abi: Abi, args: &[OpTy<'tcx, Tag>], dest: &PlaceTy<'tcx, Tag>, - ret: mir::BasicBlock, ) -> InterpResult<'tcx, EmulateByNameResult<'mir, 'tcx>> { let this = self.eval_context_mut(); @@ -533,9 +531,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Platform-specific shims _ => { match this.tcx.sess.target.os.as_ref() { - "linux" => return shims::unix::linux::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, abi, args, dest, ret), - "macos" => return shims::unix::macos::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, abi, args, dest, ret), - "freebsd" => return shims::unix::freebsd::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, abi, args, dest, ret), + "linux" => return shims::unix::linux::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, abi, args, dest), + "macos" => return shims::unix::macos::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, abi, args, dest), + "freebsd" => return shims::unix::freebsd::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, abi, args, dest), _ => unreachable!(), } } diff --git a/src/shims/unix/freebsd/foreign_items.rs b/src/shims/unix/freebsd/foreign_items.rs index 66e339cc4a820..2350e5a12c11d 100644 --- a/src/shims/unix/freebsd/foreign_items.rs +++ b/src/shims/unix/freebsd/foreign_items.rs @@ -1,4 +1,3 @@ -use rustc_middle::mir; use rustc_span::Symbol; use rustc_target::spec::abi::Abi; @@ -14,7 +13,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx abi: Abi, args: &[OpTy<'tcx, Tag>], dest: &PlaceTy<'tcx, Tag>, - _ret: mir::BasicBlock, ) -> InterpResult<'tcx, EmulateByNameResult<'mir, 'tcx>> { let this = self.eval_context_mut(); match link_name.as_str() { diff --git a/src/shims/unix/linux/foreign_items.rs b/src/shims/unix/linux/foreign_items.rs index bbdb1b8a31c45..efd4e2a8c03d3 100644 --- a/src/shims/unix/linux/foreign_items.rs +++ b/src/shims/unix/linux/foreign_items.rs @@ -1,4 +1,3 @@ -use rustc_middle::mir; use rustc_span::Symbol; use rustc_target::spec::abi::Abi; @@ -17,7 +16,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx abi: Abi, args: &[OpTy<'tcx, Tag>], dest: &PlaceTy<'tcx, Tag>, - _ret: mir::BasicBlock, ) -> InterpResult<'tcx, EmulateByNameResult<'mir, 'tcx>> { let this = self.eval_context_mut(); diff --git a/src/shims/unix/macos/foreign_items.rs b/src/shims/unix/macos/foreign_items.rs index 089a082fa3699..58dd40cda301d 100644 --- a/src/shims/unix/macos/foreign_items.rs +++ b/src/shims/unix/macos/foreign_items.rs @@ -1,4 +1,3 @@ -use rustc_middle::mir; use rustc_span::Symbol; use rustc_target::spec::abi::Abi; @@ -15,7 +14,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx abi: Abi, args: &[OpTy<'tcx, Tag>], dest: &PlaceTy<'tcx, Tag>, - _ret: mir::BasicBlock, ) -> InterpResult<'tcx, EmulateByNameResult<'mir, 'tcx>> { let this = self.eval_context_mut(); diff --git a/src/shims/windows/foreign_items.rs b/src/shims/windows/foreign_items.rs index 28e60a68048cc..65634342417be 100644 --- a/src/shims/windows/foreign_items.rs +++ b/src/shims/windows/foreign_items.rs @@ -1,6 +1,5 @@ use std::iter; -use rustc_middle::mir; use rustc_span::Symbol; use rustc_target::abi::Size; use rustc_target::spec::abi::Abi; @@ -18,7 +17,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx abi: Abi, args: &[OpTy<'tcx, Tag>], dest: &PlaceTy<'tcx, Tag>, - _ret: mir::BasicBlock, ) -> InterpResult<'tcx, EmulateByNameResult<'mir, 'tcx>> { let this = self.eval_context_mut(); From c850ffe01a4d3d8eef74f2c5220a65ec8d167b72 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 18 Jul 2022 08:20:06 -0400 Subject: [PATCH 3505/3747] add support for new RMW orders --- src/shims/intrinsics/atomic.rs | 84 ++++++++++++++++++++++++---------- tests/pass/atomic.rs | 45 ++++++++---------- 2 files changed, 79 insertions(+), 50 deletions(-) diff --git a/src/shims/intrinsics/atomic.rs b/src/shims/intrinsics/atomic.rs index e51fd98c5522d..d446eff537f31 100644 --- a/src/shims/intrinsics/atomic.rs +++ b/src/shims/intrinsics/atomic.rs @@ -49,57 +49,93 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "cxchg_seqcst_seqcst" => this.atomic_compare_exchange(args, dest, AtomicRwOrd::SeqCst, AtomicReadOrd::SeqCst)?, #[rustfmt::skip] - "cxchg_acquire_acquire" => - this.atomic_compare_exchange(args, dest, AtomicRwOrd::Acquire, AtomicReadOrd::Acquire)?, + "cxchg_seqcst_acquire" => + this.atomic_compare_exchange(args, dest, AtomicRwOrd::SeqCst, AtomicReadOrd::Acquire)?, #[rustfmt::skip] - "cxchg_release_relaxed" => - this.atomic_compare_exchange(args, dest, AtomicRwOrd::Release, AtomicReadOrd::Relaxed)?, + "cxchg_seqcst_relaxed" => + this.atomic_compare_exchange(args, dest, AtomicRwOrd::SeqCst, AtomicReadOrd::Relaxed)?, + #[rustfmt::skip] + "cxchg_acqrel_seqcst" => + this.atomic_compare_exchange(args, dest, AtomicRwOrd::AcqRel, AtomicReadOrd::SeqCst)?, #[rustfmt::skip] "cxchg_acqrel_acquire" => this.atomic_compare_exchange(args, dest, AtomicRwOrd::AcqRel, AtomicReadOrd::Acquire)?, #[rustfmt::skip] - "cxchg_relaxed_relaxed" => - this.atomic_compare_exchange(args, dest, AtomicRwOrd::Relaxed, AtomicReadOrd::Relaxed)?, + "cxchg_acqrel_relaxed" => + this.atomic_compare_exchange(args, dest, AtomicRwOrd::AcqRel, AtomicReadOrd::Relaxed)?, + #[rustfmt::skip] + "cxchg_acquire_seqcst" => + this.atomic_compare_exchange(args, dest, AtomicRwOrd::Acquire, AtomicReadOrd::SeqCst)?, + #[rustfmt::skip] + "cxchg_acquire_acquire" => + this.atomic_compare_exchange(args, dest, AtomicRwOrd::Acquire, AtomicReadOrd::Acquire)?, #[rustfmt::skip] "cxchg_acquire_relaxed" => this.atomic_compare_exchange(args, dest, AtomicRwOrd::Acquire, AtomicReadOrd::Relaxed)?, #[rustfmt::skip] - "cxchg_acqrel_relaxed" => - this.atomic_compare_exchange(args, dest, AtomicRwOrd::AcqRel, AtomicReadOrd::Relaxed)?, + "cxchg_release_seqcst" => + this.atomic_compare_exchange(args, dest, AtomicRwOrd::Release, AtomicReadOrd::SeqCst)?, #[rustfmt::skip] - "cxchg_seqcst_relaxed" => - this.atomic_compare_exchange(args, dest, AtomicRwOrd::SeqCst, AtomicReadOrd::Relaxed)?, + "cxchg_release_acquire" => + this.atomic_compare_exchange(args, dest, AtomicRwOrd::Release, AtomicReadOrd::Acquire)?, #[rustfmt::skip] - "cxchg_seqcst_acquire" => - this.atomic_compare_exchange(args, dest, AtomicRwOrd::SeqCst, AtomicReadOrd::Acquire)?, + "cxchg_release_relaxed" => + this.atomic_compare_exchange(args, dest, AtomicRwOrd::Release, AtomicReadOrd::Relaxed)?, + #[rustfmt::skip] + "cxchg_relaxed_seqcst" => + this.atomic_compare_exchange(args, dest, AtomicRwOrd::Relaxed, AtomicReadOrd::SeqCst)?, + #[rustfmt::skip] + "cxchg_relaxed_acquire" => + this.atomic_compare_exchange(args, dest, AtomicRwOrd::Relaxed, AtomicReadOrd::Acquire)?, + #[rustfmt::skip] + "cxchg_relaxed_relaxed" => + this.atomic_compare_exchange(args, dest, AtomicRwOrd::Relaxed, AtomicReadOrd::Relaxed)?, #[rustfmt::skip] "cxchgweak_seqcst_seqcst" => this.atomic_compare_exchange_weak(args, dest, AtomicRwOrd::SeqCst, AtomicReadOrd::SeqCst)?, #[rustfmt::skip] - "cxchgweak_acquire_acquire" => - this.atomic_compare_exchange_weak(args, dest, AtomicRwOrd::Acquire, AtomicReadOrd::Acquire)?, + "cxchgweak_seqcst_acquire" => + this.atomic_compare_exchange_weak(args, dest, AtomicRwOrd::SeqCst, AtomicReadOrd::Acquire)?, #[rustfmt::skip] - "cxchgweak_release_relaxed" => - this.atomic_compare_exchange_weak(args, dest, AtomicRwOrd::Release, AtomicReadOrd::Relaxed)?, + "cxchgweak_seqcst_relaxed" => + this.atomic_compare_exchange_weak(args, dest, AtomicRwOrd::SeqCst, AtomicReadOrd::Relaxed)?, + #[rustfmt::skip] + "cxchgweak_acqrel_seqcst" => + this.atomic_compare_exchange_weak(args, dest, AtomicRwOrd::AcqRel, AtomicReadOrd::SeqCst)?, #[rustfmt::skip] "cxchgweak_acqrel_acquire" => this.atomic_compare_exchange_weak(args, dest, AtomicRwOrd::AcqRel, AtomicReadOrd::Acquire)?, #[rustfmt::skip] - "cxchgweak_relaxed_relaxed" => - this.atomic_compare_exchange_weak(args, dest, AtomicRwOrd::Relaxed, AtomicReadOrd::Relaxed)?, + "cxchgweak_acqrel_relaxed" => + this.atomic_compare_exchange_weak(args, dest, AtomicRwOrd::AcqRel, AtomicReadOrd::Relaxed)?, + #[rustfmt::skip] + "cxchgweak_acquire_seqcst" => + this.atomic_compare_exchange_weak(args, dest, AtomicRwOrd::Acquire, AtomicReadOrd::SeqCst)?, + #[rustfmt::skip] + "cxchgweak_acquire_acquire" => + this.atomic_compare_exchange_weak(args, dest, AtomicRwOrd::Acquire, AtomicReadOrd::Acquire)?, #[rustfmt::skip] "cxchgweak_acquire_relaxed" => this.atomic_compare_exchange_weak(args, dest, AtomicRwOrd::Acquire, AtomicReadOrd::Relaxed)?, #[rustfmt::skip] - "cxchgweak_acqrel_relaxed" => - this.atomic_compare_exchange_weak(args, dest, AtomicRwOrd::AcqRel, AtomicReadOrd::Relaxed)?, + "cxchgweak_release_seqcst" => + this.atomic_compare_exchange_weak(args, dest, AtomicRwOrd::Release, AtomicReadOrd::SeqCst)?, #[rustfmt::skip] - "cxchgweak_seqcst_relaxed" => - this.atomic_compare_exchange_weak(args, dest, AtomicRwOrd::SeqCst, AtomicReadOrd::Relaxed)?, + "cxchgweak_release_acquire" => + this.atomic_compare_exchange_weak(args, dest, AtomicRwOrd::Release, AtomicReadOrd::Acquire)?, #[rustfmt::skip] - "cxchgweak_seqcst_acquire" => - this.atomic_compare_exchange_weak(args, dest, AtomicRwOrd::SeqCst, AtomicReadOrd::Acquire)?, + "cxchgweak_release_relaxed" => + this.atomic_compare_exchange_weak(args, dest, AtomicRwOrd::Release, AtomicReadOrd::Relaxed)?, + #[rustfmt::skip] + "cxchgweak_relaxed_seqcst" => + this.atomic_compare_exchange_weak(args, dest, AtomicRwOrd::Relaxed, AtomicReadOrd::SeqCst)?, + #[rustfmt::skip] + "cxchgweak_relaxed_acquire" => + this.atomic_compare_exchange_weak(args, dest, AtomicRwOrd::Relaxed, AtomicReadOrd::Acquire)?, + #[rustfmt::skip] + "cxchgweak_relaxed_relaxed" => + this.atomic_compare_exchange_weak(args, dest, AtomicRwOrd::Relaxed, AtomicReadOrd::Relaxed)?, #[rustfmt::skip] "or_seqcst" => diff --git a/tests/pass/atomic.rs b/tests/pass/atomic.rs index 9b82e006fa162..e3d80a78916f6 100644 --- a/tests/pass/atomic.rs +++ b/tests/pass/atomic.rs @@ -51,18 +51,22 @@ fn atomic_all_ops() { static ATOMIC: AtomicIsize = AtomicIsize::new(0); static ATOMIC_UNSIGNED: AtomicU64 = AtomicU64::new(0); + let load_orders = [Relaxed, Acquire, SeqCst]; + let stored_orders = [Relaxed, Release, SeqCst]; + let rmw_orders = [Relaxed, Release, Acquire, AcqRel, SeqCst]; + // loads - for o in [Relaxed, Acquire, SeqCst] { + for o in load_orders { ATOMIC.load(o); } // stores - for o in [Relaxed, Release, SeqCst] { + for o in stored_orders { ATOMIC.store(1, o); } // most RMWs - for o in [Relaxed, Release, Acquire, AcqRel, SeqCst] { + for o in rmw_orders { ATOMIC.swap(0, o); ATOMIC.fetch_or(0, o); ATOMIC.fetch_xor(0, o); @@ -76,29 +80,13 @@ fn atomic_all_ops() { ATOMIC_UNSIGNED.fetch_max(0, o); } - // RMWs with deparate failure ordering - ATOMIC.store(0, SeqCst); - assert_eq!(ATOMIC.compare_exchange(0, 1, Relaxed, Relaxed), Ok(0)); - assert_eq!(ATOMIC.compare_exchange(0, 2, Acquire, Relaxed), Err(1)); - assert_eq!(ATOMIC.compare_exchange(0, 1, Release, Relaxed), Err(1)); - assert_eq!(ATOMIC.compare_exchange(1, 0, AcqRel, Relaxed), Ok(1)); - ATOMIC.compare_exchange(0, 1, SeqCst, Relaxed).ok(); - ATOMIC.compare_exchange(0, 1, Acquire, Acquire).ok(); - ATOMIC.compare_exchange(0, 1, AcqRel, Acquire).ok(); - ATOMIC.compare_exchange(0, 1, SeqCst, Acquire).ok(); - ATOMIC.compare_exchange(0, 1, SeqCst, SeqCst).ok(); - - ATOMIC.store(0, SeqCst); - compare_exchange_weak_loop!(ATOMIC, 0, 1, Relaxed, Relaxed); - assert_eq!(ATOMIC.compare_exchange_weak(0, 2, Acquire, Relaxed), Err(1)); - assert_eq!(ATOMIC.compare_exchange_weak(0, 1, Release, Relaxed), Err(1)); - compare_exchange_weak_loop!(ATOMIC, 1, 0, AcqRel, Relaxed); - assert_eq!(ATOMIC.load(Relaxed), 0); - ATOMIC.compare_exchange_weak(0, 1, SeqCst, Relaxed).ok(); - ATOMIC.compare_exchange_weak(0, 1, Acquire, Acquire).ok(); - ATOMIC.compare_exchange_weak(0, 1, AcqRel, Acquire).ok(); - ATOMIC.compare_exchange_weak(0, 1, SeqCst, Acquire).ok(); - ATOMIC.compare_exchange_weak(0, 1, SeqCst, SeqCst).ok(); + // RMWs with separate failure ordering + for o1 in rmw_orders { + for o2 in load_orders { + let _res = ATOMIC.compare_exchange(0, 0, o1, o2); + let _res = ATOMIC.compare_exchange_weak(0, 0, o1, o2); + } + } } fn atomic_u64() { @@ -106,7 +94,12 @@ fn atomic_u64() { ATOMIC.store(1, SeqCst); assert_eq!(ATOMIC.compare_exchange(0, 0x100, AcqRel, Acquire), Err(1)); + assert_eq!(ATOMIC.compare_exchange(0, 1, Release, Relaxed), Err(1)); + assert_eq!(ATOMIC.compare_exchange(1, 0, AcqRel, Relaxed), Ok(1)); + assert_eq!(ATOMIC.compare_exchange(0, 1, Relaxed, Relaxed), Ok(0)); compare_exchange_weak_loop!(ATOMIC, 1, 0x100, AcqRel, Acquire); + assert_eq!(ATOMIC.compare_exchange_weak(0, 2, Acquire, Relaxed), Err(0x100)); + assert_eq!(ATOMIC.compare_exchange_weak(0, 1, Release, Relaxed), Err(0x100)); assert_eq!(ATOMIC.load(Relaxed), 0x100); assert_eq!(ATOMIC.fetch_max(0x10, SeqCst), 0x100); From ad3010c449572d86bb668ed1dc53bac5df041374 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 18 Jul 2022 08:22:27 -0400 Subject: [PATCH 3506/3747] make atomic intrinsic impl details private --- src/lib.rs | 1 - src/shims/intrinsics/mod.rs | 3 ++- src/shims/unix/linux/sync.rs | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 80281d37de9a5..b3d408a6dc072 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -62,7 +62,6 @@ pub use rustc_const_eval::interpret::{self, AllocMap, PlaceTy}; pub use crate::shims::dlsym::{Dlsym, EvalContextExt as _}; pub use crate::shims::env::{EnvVars, EvalContextExt as _}; pub use crate::shims::foreign_items::EvalContextExt as _; -pub use crate::shims::intrinsics::atomic::EvalContextExt as _; pub use crate::shims::intrinsics::EvalContextExt as _; pub use crate::shims::os_str::EvalContextExt as _; pub use crate::shims::panic::{CatchUnwindData, EvalContextExt as _}; diff --git a/src/shims/intrinsics/mod.rs b/src/shims/intrinsics/mod.rs index a8b8b807bd828..9ffa40f333535 100644 --- a/src/shims/intrinsics/mod.rs +++ b/src/shims/intrinsics/mod.rs @@ -1,4 +1,4 @@ -pub mod atomic; +mod atomic; mod simd; use std::iter; @@ -11,6 +11,7 @@ use rustc_middle::{mir, ty, ty::FloatTy}; use rustc_target::abi::Integer; use crate::*; +use atomic::EvalContextExt as _; use helpers::check_arg_count; use simd::EvalContextExt as _; diff --git a/src/shims/unix/linux/sync.rs b/src/shims/unix/linux/sync.rs index a0e35c730c3d6..a81fdb5e99888 100644 --- a/src/shims/unix/linux/sync.rs +++ b/src/shims/unix/linux/sync.rs @@ -169,7 +169,7 @@ pub fn futex<'tcx>( // // Thankfully, preemptions cannot happen inside a Miri shim, so we do not need to // do anything special to guarantee fence-load-comparison atomicity. - this.atomic_fence(&[], AtomicFenceOrd::SeqCst)?; + this.validate_atomic_fence(AtomicFenceOrd::SeqCst)?; // Read an `i32` through the pointer, regardless of any wrapper types. // It's not uncommon for `addr` to be passed as another type than `*mut i32`, such as `*const AtomicI32`. let futex_val = this @@ -240,7 +240,7 @@ pub fn futex<'tcx>( // Together with the SeqCst fence in futex_wait, this makes sure that futex_wait // will see the latest value on addr which could be changed by our caller // before doing the syscall. - this.atomic_fence(&[], AtomicFenceOrd::SeqCst)?; + this.validate_atomic_fence(AtomicFenceOrd::SeqCst)?; let mut n = 0; for _ in 0..val { if let Some(thread) = this.futex_wake(addr_usize, bitset) { From 6ab64620a60f958883ef9dfee8515a776001b85d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 18 Jul 2022 08:55:50 -0400 Subject: [PATCH 3507/3747] refactor atomic intrinsic handling to actually parse the intrinsic name --- src/shims/intrinsics/atomic.rs | 332 ++++++++++----------------------- 1 file changed, 100 insertions(+), 232 deletions(-) diff --git a/src/shims/intrinsics/atomic.rs b/src/shims/intrinsics/atomic.rs index d446eff537f31..78e13a498ce1b 100644 --- a/src/shims/intrinsics/atomic.rs +++ b/src/shims/intrinsics/atomic.rs @@ -1,10 +1,12 @@ -use rustc_middle::{mir, mir::BinOp}; +use rustc_middle::{mir, mir::BinOp, ty}; use rustc_target::abi::Align; use crate::*; use helpers::check_arg_count; pub enum AtomicOp { + /// The `bool` indicates whether the result of the operation should be negated + /// (must be a boolean-typed operation). MirOp(mir::BinOp, bool), Max, Min, @@ -20,236 +22,99 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx dest: &PlaceTy<'tcx, Tag>, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - match intrinsic_name { - "load_seqcst" => this.atomic_load(args, dest, AtomicReadOrd::SeqCst)?, - "load_relaxed" => this.atomic_load(args, dest, AtomicReadOrd::Relaxed)?, - "load_acquire" => this.atomic_load(args, dest, AtomicReadOrd::Acquire)?, - - "store_seqcst" => this.atomic_store(args, AtomicWriteOrd::SeqCst)?, - "store_relaxed" => this.atomic_store(args, AtomicWriteOrd::Relaxed)?, - "store_release" => this.atomic_store(args, AtomicWriteOrd::Release)?, - - "fence_acquire" => this.atomic_fence(args, AtomicFenceOrd::Acquire)?, - "fence_release" => this.atomic_fence(args, AtomicFenceOrd::Release)?, - "fence_acqrel" => this.atomic_fence(args, AtomicFenceOrd::AcqRel)?, - "fence_seqcst" => this.atomic_fence(args, AtomicFenceOrd::SeqCst)?, - - "singlethreadfence_acquire" => this.compiler_fence(args, AtomicFenceOrd::Acquire)?, - "singlethreadfence_release" => this.compiler_fence(args, AtomicFenceOrd::Release)?, - "singlethreadfence_acqrel" => this.compiler_fence(args, AtomicFenceOrd::AcqRel)?, - "singlethreadfence_seqcst" => this.compiler_fence(args, AtomicFenceOrd::SeqCst)?, - - "xchg_seqcst" => this.atomic_exchange(args, dest, AtomicRwOrd::SeqCst)?, - "xchg_acquire" => this.atomic_exchange(args, dest, AtomicRwOrd::Acquire)?, - "xchg_release" => this.atomic_exchange(args, dest, AtomicRwOrd::Release)?, - "xchg_acqrel" => this.atomic_exchange(args, dest, AtomicRwOrd::AcqRel)?, - "xchg_relaxed" => this.atomic_exchange(args, dest, AtomicRwOrd::Relaxed)?, - - #[rustfmt::skip] - "cxchg_seqcst_seqcst" => - this.atomic_compare_exchange(args, dest, AtomicRwOrd::SeqCst, AtomicReadOrd::SeqCst)?, - #[rustfmt::skip] - "cxchg_seqcst_acquire" => - this.atomic_compare_exchange(args, dest, AtomicRwOrd::SeqCst, AtomicReadOrd::Acquire)?, - #[rustfmt::skip] - "cxchg_seqcst_relaxed" => - this.atomic_compare_exchange(args, dest, AtomicRwOrd::SeqCst, AtomicReadOrd::Relaxed)?, - #[rustfmt::skip] - "cxchg_acqrel_seqcst" => - this.atomic_compare_exchange(args, dest, AtomicRwOrd::AcqRel, AtomicReadOrd::SeqCst)?, - #[rustfmt::skip] - "cxchg_acqrel_acquire" => - this.atomic_compare_exchange(args, dest, AtomicRwOrd::AcqRel, AtomicReadOrd::Acquire)?, - #[rustfmt::skip] - "cxchg_acqrel_relaxed" => - this.atomic_compare_exchange(args, dest, AtomicRwOrd::AcqRel, AtomicReadOrd::Relaxed)?, - #[rustfmt::skip] - "cxchg_acquire_seqcst" => - this.atomic_compare_exchange(args, dest, AtomicRwOrd::Acquire, AtomicReadOrd::SeqCst)?, - #[rustfmt::skip] - "cxchg_acquire_acquire" => - this.atomic_compare_exchange(args, dest, AtomicRwOrd::Acquire, AtomicReadOrd::Acquire)?, - #[rustfmt::skip] - "cxchg_acquire_relaxed" => - this.atomic_compare_exchange(args, dest, AtomicRwOrd::Acquire, AtomicReadOrd::Relaxed)?, - #[rustfmt::skip] - "cxchg_release_seqcst" => - this.atomic_compare_exchange(args, dest, AtomicRwOrd::Release, AtomicReadOrd::SeqCst)?, - #[rustfmt::skip] - "cxchg_release_acquire" => - this.atomic_compare_exchange(args, dest, AtomicRwOrd::Release, AtomicReadOrd::Acquire)?, - #[rustfmt::skip] - "cxchg_release_relaxed" => - this.atomic_compare_exchange(args, dest, AtomicRwOrd::Release, AtomicReadOrd::Relaxed)?, - #[rustfmt::skip] - "cxchg_relaxed_seqcst" => - this.atomic_compare_exchange(args, dest, AtomicRwOrd::Relaxed, AtomicReadOrd::SeqCst)?, - #[rustfmt::skip] - "cxchg_relaxed_acquire" => - this.atomic_compare_exchange(args, dest, AtomicRwOrd::Relaxed, AtomicReadOrd::Acquire)?, - #[rustfmt::skip] - "cxchg_relaxed_relaxed" => - this.atomic_compare_exchange(args, dest, AtomicRwOrd::Relaxed, AtomicReadOrd::Relaxed)?, - - #[rustfmt::skip] - "cxchgweak_seqcst_seqcst" => - this.atomic_compare_exchange_weak(args, dest, AtomicRwOrd::SeqCst, AtomicReadOrd::SeqCst)?, - #[rustfmt::skip] - "cxchgweak_seqcst_acquire" => - this.atomic_compare_exchange_weak(args, dest, AtomicRwOrd::SeqCst, AtomicReadOrd::Acquire)?, - #[rustfmt::skip] - "cxchgweak_seqcst_relaxed" => - this.atomic_compare_exchange_weak(args, dest, AtomicRwOrd::SeqCst, AtomicReadOrd::Relaxed)?, - #[rustfmt::skip] - "cxchgweak_acqrel_seqcst" => - this.atomic_compare_exchange_weak(args, dest, AtomicRwOrd::AcqRel, AtomicReadOrd::SeqCst)?, - #[rustfmt::skip] - "cxchgweak_acqrel_acquire" => - this.atomic_compare_exchange_weak(args, dest, AtomicRwOrd::AcqRel, AtomicReadOrd::Acquire)?, - #[rustfmt::skip] - "cxchgweak_acqrel_relaxed" => - this.atomic_compare_exchange_weak(args, dest, AtomicRwOrd::AcqRel, AtomicReadOrd::Relaxed)?, - #[rustfmt::skip] - "cxchgweak_acquire_seqcst" => - this.atomic_compare_exchange_weak(args, dest, AtomicRwOrd::Acquire, AtomicReadOrd::SeqCst)?, - #[rustfmt::skip] - "cxchgweak_acquire_acquire" => - this.atomic_compare_exchange_weak(args, dest, AtomicRwOrd::Acquire, AtomicReadOrd::Acquire)?, - #[rustfmt::skip] - "cxchgweak_acquire_relaxed" => - this.atomic_compare_exchange_weak(args, dest, AtomicRwOrd::Acquire, AtomicReadOrd::Relaxed)?, - #[rustfmt::skip] - "cxchgweak_release_seqcst" => - this.atomic_compare_exchange_weak(args, dest, AtomicRwOrd::Release, AtomicReadOrd::SeqCst)?, - #[rustfmt::skip] - "cxchgweak_release_acquire" => - this.atomic_compare_exchange_weak(args, dest, AtomicRwOrd::Release, AtomicReadOrd::Acquire)?, - #[rustfmt::skip] - "cxchgweak_release_relaxed" => - this.atomic_compare_exchange_weak(args, dest, AtomicRwOrd::Release, AtomicReadOrd::Relaxed)?, - #[rustfmt::skip] - "cxchgweak_relaxed_seqcst" => - this.atomic_compare_exchange_weak(args, dest, AtomicRwOrd::Relaxed, AtomicReadOrd::SeqCst)?, - #[rustfmt::skip] - "cxchgweak_relaxed_acquire" => - this.atomic_compare_exchange_weak(args, dest, AtomicRwOrd::Relaxed, AtomicReadOrd::Acquire)?, - #[rustfmt::skip] - "cxchgweak_relaxed_relaxed" => - this.atomic_compare_exchange_weak(args, dest, AtomicRwOrd::Relaxed, AtomicReadOrd::Relaxed)?, - - #[rustfmt::skip] - "or_seqcst" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitOr, false), AtomicRwOrd::SeqCst)?, - #[rustfmt::skip] - "or_acquire" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitOr, false), AtomicRwOrd::Acquire)?, - #[rustfmt::skip] - "or_release" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitOr, false), AtomicRwOrd::Release)?, - #[rustfmt::skip] - "or_acqrel" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitOr, false), AtomicRwOrd::AcqRel)?, - #[rustfmt::skip] - "or_relaxed" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitOr, false), AtomicRwOrd::Relaxed)?, - #[rustfmt::skip] - "xor_seqcst" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitXor, false), AtomicRwOrd::SeqCst)?, - #[rustfmt::skip] - "xor_acquire" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitXor, false), AtomicRwOrd::Acquire)?, - #[rustfmt::skip] - "xor_release" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitXor, false), AtomicRwOrd::Release)?, - #[rustfmt::skip] - "xor_acqrel" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitXor, false), AtomicRwOrd::AcqRel)?, - #[rustfmt::skip] - "xor_relaxed" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitXor, false), AtomicRwOrd::Relaxed)?, - #[rustfmt::skip] - "and_seqcst" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitAnd, false), AtomicRwOrd::SeqCst)?, - #[rustfmt::skip] - "and_acquire" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitAnd, false), AtomicRwOrd::Acquire)?, - #[rustfmt::skip] - "and_release" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitAnd, false), AtomicRwOrd::Release)?, - #[rustfmt::skip] - "and_acqrel" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitAnd, false), AtomicRwOrd::AcqRel)?, - #[rustfmt::skip] - "and_relaxed" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitAnd, false), AtomicRwOrd::Relaxed)?, - #[rustfmt::skip] - "nand_seqcst" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitAnd, true), AtomicRwOrd::SeqCst)?, - #[rustfmt::skip] - "nand_acquire" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitAnd, true), AtomicRwOrd::Acquire)?, - #[rustfmt::skip] - "nand_release" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitAnd, true), AtomicRwOrd::Release)?, - #[rustfmt::skip] - "nand_acqrel" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitAnd, true), AtomicRwOrd::AcqRel)?, - #[rustfmt::skip] - "nand_relaxed" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitAnd, true), AtomicRwOrd::Relaxed)?, - #[rustfmt::skip] - "xadd_seqcst" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::Add, false), AtomicRwOrd::SeqCst)?, - #[rustfmt::skip] - "xadd_acquire" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::Add, false), AtomicRwOrd::Acquire)?, - #[rustfmt::skip] - "xadd_release" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::Add, false), AtomicRwOrd::Release)?, - #[rustfmt::skip] - "xadd_acqrel" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::Add, false), AtomicRwOrd::AcqRel)?, - #[rustfmt::skip] - "xadd_relaxed" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::Add, false), AtomicRwOrd::Relaxed)?, - #[rustfmt::skip] - "xsub_seqcst" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::Sub, false), AtomicRwOrd::SeqCst)?, - #[rustfmt::skip] - "xsub_acquire" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::Sub, false), AtomicRwOrd::Acquire)?, - #[rustfmt::skip] - "xsub_release" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::Sub, false), AtomicRwOrd::Release)?, - #[rustfmt::skip] - "xsub_acqrel" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::Sub, false), AtomicRwOrd::AcqRel)?, - #[rustfmt::skip] - "xsub_relaxed" => - this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::Sub, false), AtomicRwOrd::Relaxed)?, - - "min_seqcst" => this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOrd::SeqCst)?, - "min_acquire" => this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOrd::Acquire)?, - "min_release" => this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOrd::Release)?, - "min_acqrel" => this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOrd::AcqRel)?, - "min_relaxed" => this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOrd::Relaxed)?, - "max_seqcst" => this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOrd::SeqCst)?, - "max_acquire" => this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOrd::Acquire)?, - "max_release" => this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOrd::Release)?, - "max_acqrel" => this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOrd::AcqRel)?, - "max_relaxed" => this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOrd::Relaxed)?, - "umin_seqcst" => this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOrd::SeqCst)?, - "umin_acquire" => this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOrd::Acquire)?, - "umin_release" => this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOrd::Release)?, - "umin_acqrel" => this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOrd::AcqRel)?, - "umin_relaxed" => this.atomic_op(args, dest, AtomicOp::Min, AtomicRwOrd::Relaxed)?, - "umax_seqcst" => this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOrd::SeqCst)?, - "umax_acquire" => this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOrd::Acquire)?, - "umax_release" => this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOrd::Release)?, - "umax_acqrel" => this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOrd::AcqRel)?, - "umax_relaxed" => this.atomic_op(args, dest, AtomicOp::Max, AtomicRwOrd::Relaxed)?, - - name => throw_unsup_format!("unimplemented intrinsic: `atomic_{name}`"), + + let intrinsic_structure: Vec<_> = intrinsic_name.split('_').collect(); + + fn read_ord<'tcx>(ord: &str) -> InterpResult<'tcx, AtomicReadOrd> { + Ok(match ord { + "seqcst" => AtomicReadOrd::SeqCst, + "acquire" => AtomicReadOrd::Acquire, + "relaxed" => AtomicReadOrd::Relaxed, + _ => throw_unsup_format!("unsupported read ordering `{ord}`"), + }) + } + + fn write_ord<'tcx>(ord: &str) -> InterpResult<'tcx, AtomicWriteOrd> { + Ok(match ord { + "seqcst" => AtomicWriteOrd::SeqCst, + "release" => AtomicWriteOrd::Release, + "relaxed" => AtomicWriteOrd::Relaxed, + _ => throw_unsup_format!("unsupported write ordering `{ord}`"), + }) + } + + fn rw_ord<'tcx>(ord: &str) -> InterpResult<'tcx, AtomicRwOrd> { + Ok(match ord { + "seqcst" => AtomicRwOrd::SeqCst, + "acqrel" => AtomicRwOrd::AcqRel, + "acquire" => AtomicRwOrd::Acquire, + "release" => AtomicRwOrd::Release, + "relaxed" => AtomicRwOrd::Relaxed, + _ => throw_unsup_format!("unsupported read-write ordering `{ord}`"), + }) + } + + fn fence_ord<'tcx>(ord: &str) -> InterpResult<'tcx, AtomicFenceOrd> { + Ok(match ord { + "seqcst" => AtomicFenceOrd::SeqCst, + "acqrel" => AtomicFenceOrd::AcqRel, + "acquire" => AtomicFenceOrd::Acquire, + "release" => AtomicFenceOrd::Release, + _ => throw_unsup_format!("unsupported fence ordering `{ord}`"), + }) + } + + match &*intrinsic_structure { + ["load", ord] => this.atomic_load(args, dest, read_ord(ord)?)?, + ["store", ord] => this.atomic_store(args, write_ord(ord)?)?, + + ["fence", ord] => this.atomic_fence(args, fence_ord(ord)?)?, + ["singlethreadfence", ord] => this.compiler_fence(args, fence_ord(ord)?)?, + + ["xchg", ord] => this.atomic_exchange(args, dest, rw_ord(ord)?)?, + ["cxchg", ord1, ord2] => + this.atomic_compare_exchange(args, dest, rw_ord(ord1)?, read_ord(ord2)?)?, + ["cxchgweak", ord1, ord2] => + this.atomic_compare_exchange_weak(args, dest, rw_ord(ord1)?, read_ord(ord2)?)?, + + ["or", ord] => + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitOr, false), rw_ord(ord)?)?, + ["xor", ord] => + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitXor, false), rw_ord(ord)?)?, + ["and", ord] => + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitAnd, false), rw_ord(ord)?)?, + ["nand", ord] => + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::BitAnd, true), rw_ord(ord)?)?, + ["xadd", ord] => + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::Add, false), rw_ord(ord)?)?, + ["xsub", ord] => + this.atomic_op(args, dest, AtomicOp::MirOp(BinOp::Sub, false), rw_ord(ord)?)?, + ["min", ord] => { + // Later we will use the type to indicate signed vs unsigned, + // so make sure it matches the intrinsic name. + assert!(matches!(args[1].layout.ty.kind(), ty::Int(_))); + this.atomic_op(args, dest, AtomicOp::Min, rw_ord(ord)?)?; + } + ["umin", ord] => { + // Later we will use the type to indicate signed vs unsigned, + // so make sure it matches the intrinsic name. + assert!(matches!(args[1].layout.ty.kind(), ty::Uint(_))); + this.atomic_op(args, dest, AtomicOp::Min, rw_ord(ord)?)?; + } + ["max", ord] => { + // Later we will use the type to indicate signed vs unsigned, + // so make sure it matches the intrinsic name. + assert!(matches!(args[1].layout.ty.kind(), ty::Int(_))); + this.atomic_op(args, dest, AtomicOp::Max, rw_ord(ord)?)?; + } + ["umax", ord] => { + // Later we will use the type to indicate signed vs unsigned, + // so make sure it matches the intrinsic name. + assert!(matches!(args[1].layout.ty.kind(), ty::Uint(_))); + this.atomic_op(args, dest, AtomicOp::Max, rw_ord(ord)?)?; + } + + _ => throw_unsup_format!("unimplemented intrinsic: `atomic_{intrinsic_name}`"), } Ok(()) } @@ -343,6 +208,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let [place, rhs] = check_arg_count(args)?; let place = this.deref_operand(place)?; + let rhs = this.read_immediate(rhs)?; if !place.layout.ty.is_integral() && !place.layout.ty.is_unsafe_ptr() { span_bug!( @@ -350,7 +216,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "atomic arithmetic operations only work on integer and raw pointer types", ); } - let rhs = this.read_immediate(rhs)?; + if rhs.layout.ty != place.layout.ty { + span_bug!(this.cur_span(), "atomic arithmetic operation type mismatch"); + } // Check alignment requirements. Atomics must always be aligned to their size, // even if the type they wrap would be less aligned (e.g. AtomicU64 on 32bit must From bfd148b783febe248f4d601c8d9d542348345bf0 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 18 Jul 2022 17:47:32 -0400 Subject: [PATCH 3508/3747] use env vars, not Cargo.toml, to configure out dev profile --- Cargo.toml | 5 +++-- miri | 6 +++++- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index a2a880f8e308c..208b3a764436f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -56,5 +56,6 @@ harness = false default = ["stack-cache"] stack-cache = [] -[profile.dev] -opt-level = 2 # because it's too slow otherwise +# Be aware that this file is inside a workspace when used via the +# submodule in the rustc repo. That means there are many cargo features +# we cannot use, such as profiles. diff --git a/miri b/miri index bb2fc5b12318d..04d441b60780d 100755 --- a/miri +++ b/miri @@ -96,10 +96,14 @@ fi # Prepare flags for cargo and rustc. CARGO="cargo +$TOOLCHAIN" +# Share target dir between `miri` and `cargo-miri`. if [ -z "$CARGO_TARGET_DIR" ]; then - # Share target dir between `miri` and `cargo-miri`. export CARGO_TARGET_DIR="$MIRIDIR/target" fi +# We configure dev builds to not be unusably slow. +if [ -z "$CARGO_PROFILE_DEV_OPT_LEVEL" ]; then + export CARGO_PROFILE_DEV_OPT_LEVEL=2 +fi # We set the rpath so that Miri finds the private rustc libraries it needs. export RUSTFLAGS="-C link-args=-Wl,-rpath,$LIBDIR $RUSTFLAGS" From 56fefe19bfcdc9a3ce631615859c7cc5cdd0ee58 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 18 Jul 2022 19:50:03 -0400 Subject: [PATCH 3509/3747] cargo-miri: write the Xargo project files atomically --- cargo-miri/bin.rs | 47 ++++++++++++++++++++++++++++++----------------- 1 file changed, 30 insertions(+), 17 deletions(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index 4c9f3aabaab49..c4ed92d038524 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -319,6 +319,23 @@ fn ask_to_run(mut cmd: Command, ask: bool, text: &str) { } } +/// Writes the given content to the given file *cross-process atomically*, in the sense that another +/// process concurrently reading that file will see either the old content or the new content, but +/// not some intermediate (e.g., empty) state. +/// +/// We assume no other parts of this same process are trying to read or write that file. +fn write_to_file(filename: &Path, content: &str) { + // Create a temporary file with the desired contents. + let mut temp_filename = filename.as_os_str().to_os_string(); + temp_filename.push(&format!(".{}", std::process::id())); + let mut temp_file = File::create(&temp_filename).unwrap(); + temp_file.write_all(content.as_bytes()).unwrap(); + drop(temp_file); + + // Move file to the desired location. + fs::rename(temp_filename, filename).unwrap(); +} + /// Performs the setup required to make `cargo miri` work: Getting a custom-built libstd. Then sets /// `MIRI_SYSROOT`. Skipped if `MIRI_SYSROOT` is already set, in which case we expect the user has /// done all this already. @@ -398,28 +415,25 @@ fn setup(subcommand: MiriCommand) { if !dir.exists() { fs::create_dir_all(&dir).unwrap(); } - let mut xargo_toml = File::create(dir.join("Xargo.toml")).unwrap(); - if std::env::var_os("MIRI_NO_STD").is_none() { - // The interesting bit: Xargo.toml (only needs content if we actually need std) - xargo_toml - .write_all( - br#" + // The interesting bit: Xargo.toml (only needs content if we actually need std) + let xargo_toml = if std::env::var_os("MIRI_NO_STD").is_some() { + "" + } else { + r#" [dependencies.std] default_features = false # We support unwinding, so enable that panic runtime. features = ["panic_unwind", "backtrace"] [dependencies.test] -"#, - ) - .unwrap(); - } +"# + }; + write_to_file(&dir.join("Xargo.toml"), xargo_toml); // The boring bits: a dummy project for xargo. // FIXME: With xargo-check, can we avoid doing this? - File::create(dir.join("Cargo.toml")) - .unwrap() - .write_all( - br#" + write_to_file( + &dir.join("Cargo.toml"), + r#" [package] name = "miri-xargo" description = "A dummy project for building libstd with xargo." @@ -428,9 +442,8 @@ version = "0.0.0" [lib] path = "lib.rs" "#, - ) - .unwrap(); - File::create(dir.join("lib.rs")).unwrap().write_all(b"#![no_std]").unwrap(); + ); + write_to_file(&dir.join("lib.rs"), "#![no_std]"); // Determine architectures. // We always need to set a target so rustc bootstrap can tell apart host from target crates. From 04b66ce34282a3b510cbc6a1cdd28da44f9d33f3 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 18 Jul 2022 21:42:50 -0400 Subject: [PATCH 3510/3747] update ui_test readme --- ui_test/README.md | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/ui_test/README.md b/ui_test/README.md index 4ecebcc8ddb24..f1b1a5d67e0ae 100644 --- a/ui_test/README.md +++ b/ui_test/README.md @@ -23,12 +23,11 @@ In order to change how a single test is tested, you can add various `//@` commen Any other comments will be ignored, and all `//@` comments must be formatted precisely as their command specifies, or the test will fail without even being run. -* `//@ignore-XXX` avoids running the test on targets whose triple contains `XXX` - * `XXX` can also be one of `64bit`, `32bit` or `16bit` - * `XXX` can also be `on-host`, which will only run the test during cross compilation testing. -* `//@only-XXX` avoids running the test on targets whose triple **does not** contain `XXX` - * `XXX` can also be one of `64bit`, `32bit` or `16bit` - * `XXX` can also be `on-host`, which will not run the test during cross compilation testing +* `//@ignore-C` avoids running the test when condition `C` is met. + * `C` can be `target-XXX`, which checks whether the target triple contains `XXX`. + * `C` can also be one of `64bit`, `32bit` or `16bit`. + * `C` can also be `on-host`, which will only run the test during cross compilation testing. +* `//@only-C` **only** runs the test when condition `C` is met. The conditions are the same as with `ignore`. * `//@stderr-per-bitwidth` produces one stderr file per bitwidth, as they may differ significantly sometimes * `//@error-pattern: XXX` make sure the stderr output contains `XXX` * `//@revisions: XXX YYY` runs the test once for each space separated name in the list @@ -46,5 +45,5 @@ their command specifies, or the test will fail without even being run. ## Significant differences to compiletest-rs -* `ignore-*` and `only-*` opereate solely on the triple, instead of supporting things like `macos` +* `ignore-target-*` and `only-target-*` opereate solely on the triple, instead of supporting things like `macos` * only `//~` comments can be individualized per revision From 1d5cfb565ca70109dc2c6eb69b8c3d72b4ca8dcd Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 19 Jul 2022 08:03:39 -0400 Subject: [PATCH 3511/3747] rustup --- rust-version | 2 +- tests/fail/concurrency/too_few_args.stderr | 2 +- tests/fail/concurrency/too_many_args.stderr | 2 +- tests/fail/erroneous_const.stderr | 2 +- tests/fail/erroneous_const2.stderr | 2 +- tests/fail/panic/double_panic.stderr | 2 +- tests/fail/panic/panic_abort1.stderr | 2 +- tests/fail/panic/panic_abort2.stderr | 2 +- tests/fail/panic/panic_abort3.stderr | 2 +- tests/fail/panic/panic_abort4.stderr | 2 +- 10 files changed, 10 insertions(+), 10 deletions(-) diff --git a/rust-version b/rust-version index 362bcc35eade2..f4afa43534555 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -880416180b0a9ee1141c07d4d17667edb77daebd +4603ac31b0655793a82f110f544dc1c6abc57bb7 diff --git a/tests/fail/concurrency/too_few_args.stderr b/tests/fail/concurrency/too_few_args.stderr index 093a307685019..c1eb4d8cb6b6e 100644 --- a/tests/fail/concurrency/too_few_args.stderr +++ b/tests/fail/concurrency/too_few_args.stderr @@ -8,7 +8,7 @@ LL | panic!() = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: backtrace: = note: inside `thread_start` at RUSTLIB/std/src/panic.rs:LL:CC - = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::panic::panic_2015` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to previous error diff --git a/tests/fail/concurrency/too_many_args.stderr b/tests/fail/concurrency/too_many_args.stderr index 87e22ec1dcf65..42a96ae626367 100644 --- a/tests/fail/concurrency/too_many_args.stderr +++ b/tests/fail/concurrency/too_many_args.stderr @@ -8,7 +8,7 @@ LL | panic!() = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: backtrace: = note: inside `thread_start` at RUSTLIB/std/src/panic.rs:LL:CC - = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::panic::panic_2015` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to previous error diff --git a/tests/fail/erroneous_const.stderr b/tests/fail/erroneous_const.stderr index d4b8f25e03851..8138d69f4031e 100644 --- a/tests/fail/erroneous_const.stderr +++ b/tests/fail/erroneous_const.stderr @@ -4,7 +4,7 @@ error[E0080]: evaluation of `PrintName::::VOID` failed LL | const VOID: ! = panic!(); | ^^^^^^^^ the evaluated program panicked at 'explicit panic', $DIR/erroneous_const.rs:LL:CC | - = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::panic::panic_2015` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info) error: post-monomorphization error: referenced constant has errors --> $DIR/erroneous_const.rs:LL:CC diff --git a/tests/fail/erroneous_const2.stderr b/tests/fail/erroneous_const2.stderr index 75e3d9bcd2114..05ed8ea1c14bc 100644 --- a/tests/fail/erroneous_const2.stderr +++ b/tests/fail/erroneous_const2.stderr @@ -22,7 +22,7 @@ LL | println!("{}", FOO); | = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #71800 - = note: this error originates in the macro `$crate::format_args_nl` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::format_args_nl` which comes from the expansion of the macro `println` (in Nightly builds, run with -Z macro-backtrace for more info) error: post-monomorphization error: referenced constant has errors --> $DIR/erroneous_const2.rs:LL:CC diff --git a/tests/fail/panic/double_panic.stderr b/tests/fail/panic/double_panic.stderr index c88dfd39e1072..f1d2b4de97cc2 100644 --- a/tests/fail/panic/double_panic.stderr +++ b/tests/fail/panic/double_panic.stderr @@ -86,7 +86,7 @@ note: inside `main` at $DIR/double_panic.rs:LL:CC | LL | } | ^ - = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::panic::panic_2015` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info) note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/panic/panic_abort1.stderr b/tests/fail/panic/panic_abort1.stderr index 808fccaaeca88..7547199454643 100644 --- a/tests/fail/panic/panic_abort1.stderr +++ b/tests/fail/panic/panic_abort1.stderr @@ -17,7 +17,7 @@ note: inside `main` at RUSTLIB/std/src/panic.rs:LL:CC | LL | std::panic!("panicking from libstd"); | ^ - = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::panic::panic_2015` which comes from the expansion of the macro `std::panic` (in Nightly builds, run with -Z macro-backtrace for more info) note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/panic/panic_abort2.stderr b/tests/fail/panic/panic_abort2.stderr index 9b86dc92f7178..2fdf889d798a2 100644 --- a/tests/fail/panic/panic_abort2.stderr +++ b/tests/fail/panic/panic_abort2.stderr @@ -18,7 +18,7 @@ note: inside `main` at RUSTLIB/std/src/panic.rs:LL:CC | LL | std::panic!("{}-panicking from libstd", 42); | ^ - = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::panic::panic_2015` which comes from the expansion of the macro `std::panic` (in Nightly builds, run with -Z macro-backtrace for more info) note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/panic/panic_abort3.stderr b/tests/fail/panic/panic_abort3.stderr index 2bb50d55bfe42..8704b0d940b7a 100644 --- a/tests/fail/panic/panic_abort3.stderr +++ b/tests/fail/panic/panic_abort3.stderr @@ -18,7 +18,7 @@ note: inside `main` at RUSTLIB/core/src/panic.rs:LL:CC | LL | core::panic!("panicking from libcore"); | ^ - = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::panic::panic_2015` which comes from the expansion of the macro `core::panic` (in Nightly builds, run with -Z macro-backtrace for more info) note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/panic/panic_abort4.stderr b/tests/fail/panic/panic_abort4.stderr index 8ab5793016120..1d75d72c0317c 100644 --- a/tests/fail/panic/panic_abort4.stderr +++ b/tests/fail/panic/panic_abort4.stderr @@ -18,7 +18,7 @@ note: inside `main` at RUSTLIB/core/src/panic.rs:LL:CC | LL | core::panic!("{}-panicking from libcore", 42); | ^ - = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) + = note: this error originates in the macro `$crate::panic::panic_2015` which comes from the expansion of the macro `core::panic` (in Nightly builds, run with -Z macro-backtrace for more info) note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace From 9dba78a76b7343ac70321b4224746f5e412df088 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 19 Jul 2022 13:19:00 -0400 Subject: [PATCH 3512/3747] show a better error when running Miri with the wrong sysroot --- cargo-miri/bin.rs | 15 +++++++++------ src/bin/miri.rs | 32 +++++++++++++++++++++++++------- 2 files changed, 34 insertions(+), 13 deletions(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index c4ed92d038524..233d81826eecf 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -374,12 +374,15 @@ fn setup(subcommand: MiriCommand) { } None => { // Check for `rust-src` rustup component. - let sysroot = miri() - .args(&["--print", "sysroot"]) - .output() - .expect("failed to determine sysroot") - .stdout; - let sysroot = std::str::from_utf8(&sysroot).unwrap(); + let output = + miri().args(&["--print", "sysroot"]).output().expect("failed to determine sysroot"); + if !output.status.success() { + show_error(format!( + "Failed to determine sysroot; Miri said:\n{}", + String::from_utf8_lossy(&output.stderr).trim_end() + )); + } + let sysroot = std::str::from_utf8(&output.stdout).unwrap(); let sysroot = Path::new(sysroot.trim_end_matches('\n')); // Check for `$SYSROOT/lib/rustlib/src/rust/library`; test if that contains `std/Cargo.toml`. let rustup_src = diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 4f00e4be18ab4..5131f3ae9ca9c 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -1,5 +1,5 @@ #![feature(rustc_private, stmt_expr_attributes)] -#![allow(clippy::manual_range_contains)] +#![allow(clippy::manual_range_contains, clippy::useless_format)] extern crate rustc_data_structures; extern crate rustc_driver; @@ -143,6 +143,11 @@ impl rustc_driver::Callbacks for MiriBeRustCompilerCalls { } } +fn show_error(msg: String) -> ! { + eprintln!("fatal error: {}", msg); + std::process::exit(1) +} + fn init_early_loggers() { // Note that our `extern crate log` is *not* the same as rustc's; as a result, we have to // initialize them both, and we always initialize `miri`'s first. @@ -214,13 +219,26 @@ fn compile_time_sysroot() -> Option { let home = option_env!("RUSTUP_HOME").or(option_env!("MULTIRUST_HOME")); let toolchain = option_env!("RUSTUP_TOOLCHAIN").or(option_env!("MULTIRUST_TOOLCHAIN")); Some(match (home, toolchain) { - (Some(home), Some(toolchain)) => format!("{}/toolchains/{}", home, toolchain), - _ => - option_env!("RUST_SYSROOT") - .expect( + (Some(home), Some(toolchain)) => { + // Check that at runtime, we are still in this toolchain. + let toolchain_runtime = + env::var_os("RUSTUP_TOOLCHAIN").or_else(|| env::var_os("MULTIRUST_TOOLCHAIN")); + if !matches!(toolchain_runtime, Some(r) if r == toolchain) { + show_error(format!( + "This Miri got built with local toolchain `{toolchain}`, but now is being run under a different toolchain. \n\ + Make sure to run Miri in the toolchain it got built with, e.g. via `cargo +{toolchain} miri`." + )); + } + + format!("{}/toolchains/{}", home, toolchain) + } + _ => option_env!("RUST_SYSROOT") + .unwrap_or_else(|| { + show_error(format!( "To build Miri without rustup, set the `RUST_SYSROOT` env var at build time", - ) - .to_owned(), + )) + }) + .to_owned(), }) } From 5cf7ed1e04dc7834d7e8030937a0f8195beed6cb Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 19 Jul 2022 13:31:43 -0400 Subject: [PATCH 3513/3747] show where the interpreter was interpreting when an ICE occurs --- src/diagnostics.rs | 18 ++++++++++++++++++ src/eval.rs | 13 +++++++++---- 2 files changed, 27 insertions(+), 4 deletions(-) diff --git a/src/diagnostics.rs b/src/diagnostics.rs index 4dfa7bd07cbec..1c6cfa096863f 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -505,4 +505,22 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } }); } + + /// We had a panic in Miri itself, try to print something useful. + fn handle_ice(&self) { + eprintln!(); + eprintln!( + "Miri caused an ICE during evaluation. Here's the interpreter backtrace at the time of the panic:" + ); + let this = self.eval_context_ref(); + let stacktrace = this.generate_stacktrace(); + report_msg( + this, + DiagLevel::Note, + "the place in the program where the ICE was triggered", + vec![], + vec![], + &stacktrace, + ); + } } diff --git a/src/eval.rs b/src/eval.rs index d75b4f5fa6d2a..87ee50387c2f2 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -1,7 +1,10 @@ //! Main evaluator loop and setting up the initial stack frame. +use std::collections::HashSet; use std::ffi::OsStr; use std::iter; +use std::panic::{self, AssertUnwindSafe}; +use std::thread; use log::info; @@ -15,8 +18,6 @@ use rustc_target::spec::abi::Abi; use rustc_session::config::EntryFnType; -use std::collections::HashSet; - use crate::*; #[derive(Copy, Clone, Debug, PartialEq)] @@ -332,7 +333,7 @@ pub fn eval_entry<'tcx>( }; // Perform the main execution. - let res: InterpResult<'_, i64> = (|| { + let res: thread::Result> = panic::catch_unwind(AssertUnwindSafe(|| { // Main loop. loop { let info = ecx.preprocess_diagnostics(); @@ -362,7 +363,11 @@ pub fn eval_entry<'tcx>( } let return_code = ecx.read_scalar(&ret_place.into())?.to_machine_isize(&ecx)?; Ok(return_code) - })(); + })); + let res = res.unwrap_or_else(|panic_payload| { + ecx.handle_ice(); + panic::resume_unwind(panic_payload) + }); // Machine cleanup. // Execution of the program has halted so any memory access we do here From fb3ac74696d64f02e3e75e563a9e378b8b3886bc Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 19 Jul 2022 14:40:17 -0400 Subject: [PATCH 3514/3747] on an error, always print the unnormalized stderr --- ui_test/src/lib.rs | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/ui_test/src/lib.rs b/ui_test/src/lib.rs index 16f7be30f8b2e..568e39f5670f0 100644 --- a/ui_test/src/lib.rs +++ b/ui_test/src/lib.rs @@ -172,7 +172,6 @@ pub fn run_tests(config: Config) -> Result<()> { eprintln!(); eprintln!("command: {:?}", miri); eprintln!(); - let mut dump_stderr = true; for error in errors { match error { Error::ExitStatus(mode, exit_status) => eprintln!("{mode:?} got {exit_status}"), @@ -194,9 +193,6 @@ pub fn run_tests(config: Config) -> Result<()> { Error::PatternFoundInPassTest => eprintln!("{}", "error pattern found in success test".red()), Error::OutputDiffers { path, actual, expected } => { - if path.extension().unwrap() == "stderr" { - dump_stderr = false; - } eprintln!("actual output differed from expected {}", path.display()); eprintln!("{}", pretty_assertions::StrComparison::new(expected, actual)); eprintln!() @@ -223,12 +219,9 @@ pub fn run_tests(config: Config) -> Result<()> { } eprintln!(); } - // Unless we already dumped the stderr via an OutputDiffers diff, let's dump it here. - if dump_stderr { - eprintln!("actual stderr:"); - eprintln!("{}", stderr); - eprintln!(); - } + eprintln!("full stderr:"); + eprintln!("{}", stderr); + eprintln!(); } eprintln!("{}", "failures:".red().underline()); for (path, _miri, _revision, _errors, _stderr) in &failures { From 9f9aa00f5d4900c2ec4071fd80ac184f9f95f718 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 19 Jul 2022 14:44:00 -0400 Subject: [PATCH 3515/3747] tweak failure output a little --- ui_test/src/lib.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ui_test/src/lib.rs b/ui_test/src/lib.rs index 568e39f5670f0..917e382379abe 100644 --- a/ui_test/src/lib.rs +++ b/ui_test/src/lib.rs @@ -164,11 +164,11 @@ pub fn run_tests(config: Config) -> Result<()> { if !failures.is_empty() { for (path, miri, revision, errors, stderr) in &failures { eprintln!(); - eprint!("{}", path.display().to_string().underline()); + eprint!("{}", path.display().to_string().underline().bold()); if !revision.is_empty() { eprint!(" (revision `{}`)", revision); } - eprint!(" {}", "FAILED".red()); + eprint!(" {}", "FAILED:".red().bold()); eprintln!(); eprintln!("command: {:?}", miri); eprintln!(); @@ -223,7 +223,7 @@ pub fn run_tests(config: Config) -> Result<()> { eprintln!("{}", stderr); eprintln!(); } - eprintln!("{}", "failures:".red().underline()); + eprintln!("{}", "FAILURES:".red().underline().bold()); for (path, _miri, _revision, _errors, _stderr) in &failures { eprintln!(" {}", path.display()); } From 5721927afe9ccae2d09691d20223e68d8669fb0c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 19 Jul 2022 15:44:47 -0400 Subject: [PATCH 3516/3747] rustup --- rust-version | 2 +- src/helpers.rs | 2 +- src/shims/intrinsics/mod.rs | 4 ++-- src/shims/panic.rs | 2 +- src/shims/unix/linux/sync.rs | 2 +- src/shims/unix/sync.rs | 3 +-- src/stacked_borrows/mod.rs | 6 +++--- 7 files changed, 10 insertions(+), 11 deletions(-) diff --git a/rust-version b/rust-version index f4afa43534555..38f4b2bda5f2e 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -4603ac31b0655793a82f110f544dc1c6abc57bb7 +29c5a028b0c92aa5da6a8eb6d6585a389fcf1035 diff --git a/src/helpers.rs b/src/helpers.rs index b650e2ddf2255..190eb2098ad01 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -258,7 +258,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Push frame. let mir = this.load_mir(f.def, None)?; let dest = match dest { - Some(dest) => *dest, + Some(dest) => dest.clone(), None => MPlaceTy::fake_alloc_zst(this.layout_of(mir.return_ty())?).into(), }; this.push_stack_frame(f, mir, &dest, stack_pop)?; diff --git a/src/shims/intrinsics/mod.rs b/src/shims/intrinsics/mod.rs index 9ffa40f333535..97f9a7b93cace 100644 --- a/src/shims/intrinsics/mod.rs +++ b/src/shims/intrinsics/mod.rs @@ -224,7 +224,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "frem_fast" => mir::BinOp::Rem, _ => bug!(), }; - let float_finite = |x: ImmTy<'tcx, _>| -> InterpResult<'tcx, bool> { + let float_finite = |x: &ImmTy<'tcx, _>| -> InterpResult<'tcx, bool> { Ok(match x.layout.ty.kind() { ty::Float(FloatTy::F32) => x.to_scalar()?.to_f32()?.is_finite(), ty::Float(FloatTy::F64) => x.to_scalar()?.to_f64()?.is_finite(), @@ -234,7 +234,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ), }) }; - match (float_finite(a)?, float_finite(b)?) { + match (float_finite(&a)?, float_finite(&b)?) { (false, false) => throw_ub_format!( "`{intrinsic_name}` intrinsic called with non-finite value as both parameters", ), diff --git a/src/shims/panic.rs b/src/shims/panic.rs index c356dd86676da..42264f6ff3440 100644 --- a/src/shims/panic.rs +++ b/src/shims/panic.rs @@ -108,7 +108,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // when we pop this frame. if this.tcx.sess.panic_strategy() == PanicStrategy::Unwind { this.frame_mut().extra.catch_unwind = - Some(CatchUnwindData { catch_fn, data, dest: *dest, ret }); + Some(CatchUnwindData { catch_fn, data, dest: dest.clone(), ret }); } Ok(()) diff --git a/src/shims/unix/linux/sync.rs b/src/shims/unix/linux/sync.rs index a81fdb5e99888..d921b66afbd0d 100644 --- a/src/shims/unix/linux/sync.rs +++ b/src/shims/unix/linux/sync.rs @@ -188,8 +188,8 @@ pub fn futex<'tcx>( this.write_scalar(Scalar::from_machine_isize(0, this), dest)?; // Register a timeout callback if a timeout was specified. // This callback will override the return value when the timeout triggers. - let dest = *dest; if let Some(timeout_time) = timeout_time { + let dest = dest.clone(); this.register_timeout_callback( thread, timeout_time, diff --git a/src/shims/unix/sync.rs b/src/shims/unix/sync.rs index ae63907c2c865..590bc1bf0056c 100644 --- a/src/shims/unix/sync.rs +++ b/src/shims/unix/sync.rs @@ -828,9 +828,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // We return success for now and override it in the timeout callback. this.write_scalar(Scalar::from_i32(0), dest)?; - let dest = *dest; - // Register the timeout callback. + let dest = dest.clone(); this.register_timeout_callback( active_thread, timeout_time, diff --git a/src/stacked_borrows/mod.rs b/src/stacked_borrows/mod.rs index 9040d03632ed9..fb40291302d61 100644 --- a/src/stacked_borrows/mod.rs +++ b/src/stacked_borrows/mod.rs @@ -985,7 +985,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // See https://github.com/rust-lang/unsafe-code-guidelines/issues/276. let size = match size { Some(size) => size, - None => return Ok(*val), + None => return Ok(val.clone()), }; // Compute new borrow. @@ -1116,13 +1116,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// explicit. Also see . fn retag_return_place(&mut self) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - let return_place = this.frame_mut().return_place; + let return_place = &this.frame().return_place; if return_place.layout.is_zst() { // There may not be any memory here, nothing to do. return Ok(()); } // We need this to be in-memory to use tagged pointers. - let return_place = this.force_allocation(&return_place)?; + let return_place = this.force_allocation(&return_place.clone())?; // We have to turn the place into a pointer to use the existing code. // (The pointer type does not matter, so we use a raw pointer.) From 4d220c31a4aa1567d66263b368554ef160a9e01e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 19 Jul 2022 19:39:30 -0400 Subject: [PATCH 3517/3747] add some dyn upcasting tests --- tests/pass/upcast.rs | 418 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 418 insertions(+) create mode 100644 tests/pass/upcast.rs diff --git a/tests/pass/upcast.rs b/tests/pass/upcast.rs new file mode 100644 index 0000000000000..030c2a7cbf627 --- /dev/null +++ b/tests/pass/upcast.rs @@ -0,0 +1,418 @@ +#![feature(trait_upcasting)] +#![allow(incomplete_features)] + +fn main() { + basic(); + diamond(); + struct_(); + replace_vptr(); +} + +fn basic() { + trait Foo: PartialEq + std::fmt::Debug + Send + Sync { + fn a(&self) -> i32 { + 10 + } + + fn z(&self) -> i32 { + 11 + } + + fn y(&self) -> i32 { + 12 + } + } + + trait Bar: Foo { + fn b(&self) -> i32 { + 20 + } + + fn w(&self) -> i32 { + 21 + } + } + + trait Baz: Bar { + fn c(&self) -> i32 { + 30 + } + } + + impl Foo for i32 { + fn a(&self) -> i32 { + 100 + } + } + + impl Bar for i32 { + fn b(&self) -> i32 { + 200 + } + } + + impl Baz for i32 { + fn c(&self) -> i32 { + 300 + } + } + + let baz: &dyn Baz = &1; + let _: &dyn std::fmt::Debug = baz; + assert_eq!(*baz, 1); + assert_eq!(baz.a(), 100); + assert_eq!(baz.b(), 200); + assert_eq!(baz.c(), 300); + assert_eq!(baz.z(), 11); + assert_eq!(baz.y(), 12); + assert_eq!(baz.w(), 21); + + let bar: &dyn Bar = baz; + let _: &dyn std::fmt::Debug = bar; + assert_eq!(*bar, 1); + assert_eq!(bar.a(), 100); + assert_eq!(bar.b(), 200); + assert_eq!(bar.z(), 11); + assert_eq!(bar.y(), 12); + assert_eq!(bar.w(), 21); + + let foo: &dyn Foo = baz; + let _: &dyn std::fmt::Debug = foo; + assert_eq!(*foo, 1); + assert_eq!(foo.a(), 100); + assert_eq!(foo.z(), 11); + assert_eq!(foo.y(), 12); + + let foo: &dyn Foo = bar; + let _: &dyn std::fmt::Debug = foo; + assert_eq!(*foo, 1); + assert_eq!(foo.a(), 100); + assert_eq!(foo.z(), 11); + assert_eq!(foo.y(), 12); +} + +fn diamond() { + trait Foo: PartialEq + std::fmt::Debug + Send + Sync { + fn a(&self) -> i32 { + 10 + } + + fn z(&self) -> i32 { + 11 + } + + fn y(&self) -> i32 { + 12 + } + } + + trait Bar1: Foo { + fn b(&self) -> i32 { + 20 + } + + fn w(&self) -> i32 { + 21 + } + } + + trait Bar2: Foo { + fn c(&self) -> i32 { + 30 + } + + fn v(&self) -> i32 { + 31 + } + } + + trait Baz: Bar1 + Bar2 { + fn d(&self) -> i32 { + 40 + } + } + + impl Foo for i32 { + fn a(&self) -> i32 { + 100 + } + } + + impl Bar1 for i32 { + fn b(&self) -> i32 { + 200 + } + } + + impl Bar2 for i32 { + fn c(&self) -> i32 { + 300 + } + } + + impl Baz for i32 { + fn d(&self) -> i32 { + 400 + } + } + + let baz: &dyn Baz = &1; + let _: &dyn std::fmt::Debug = baz; + assert_eq!(*baz, 1); + assert_eq!(baz.a(), 100); + assert_eq!(baz.b(), 200); + assert_eq!(baz.c(), 300); + assert_eq!(baz.d(), 400); + assert_eq!(baz.z(), 11); + assert_eq!(baz.y(), 12); + assert_eq!(baz.w(), 21); + assert_eq!(baz.v(), 31); + + let bar1: &dyn Bar1 = baz; + let _: &dyn std::fmt::Debug = bar1; + assert_eq!(*bar1, 1); + assert_eq!(bar1.a(), 100); + assert_eq!(bar1.b(), 200); + assert_eq!(bar1.z(), 11); + assert_eq!(bar1.y(), 12); + assert_eq!(bar1.w(), 21); + + let bar2: &dyn Bar2 = baz; + let _: &dyn std::fmt::Debug = bar2; + assert_eq!(*bar2, 1); + assert_eq!(bar2.a(), 100); + assert_eq!(bar2.c(), 300); + assert_eq!(bar2.z(), 11); + assert_eq!(bar2.y(), 12); + assert_eq!(bar2.v(), 31); + + let foo: &dyn Foo = baz; + let _: &dyn std::fmt::Debug = foo; + assert_eq!(*foo, 1); + assert_eq!(foo.a(), 100); + + let foo: &dyn Foo = bar1; + let _: &dyn std::fmt::Debug = foo; + assert_eq!(*foo, 1); + assert_eq!(foo.a(), 100); + + let foo: &dyn Foo = bar2; + let _: &dyn std::fmt::Debug = foo; + assert_eq!(*foo, 1); + assert_eq!(foo.a(), 100); +} + +fn struct_() { + use std::rc::Rc; + use std::sync::Arc; + + trait Foo: PartialEq + std::fmt::Debug + Send + Sync { + fn a(&self) -> i32 { + 10 + } + + fn z(&self) -> i32 { + 11 + } + + fn y(&self) -> i32 { + 12 + } + } + + trait Bar: Foo { + fn b(&self) -> i32 { + 20 + } + + fn w(&self) -> i32 { + 21 + } + } + + trait Baz: Bar { + fn c(&self) -> i32 { + 30 + } + } + + impl Foo for i32 { + fn a(&self) -> i32 { + 100 + } + } + + impl Bar for i32 { + fn b(&self) -> i32 { + 200 + } + } + + impl Baz for i32 { + fn c(&self) -> i32 { + 300 + } + } + + fn test_box() { + let v = Box::new(1); + + let baz: Box = v.clone(); + assert_eq!(*baz, 1); + assert_eq!(baz.a(), 100); + assert_eq!(baz.b(), 200); + assert_eq!(baz.c(), 300); + assert_eq!(baz.z(), 11); + assert_eq!(baz.y(), 12); + assert_eq!(baz.w(), 21); + + let baz: Box = v.clone(); + let bar: Box = baz; + assert_eq!(*bar, 1); + assert_eq!(bar.a(), 100); + assert_eq!(bar.b(), 200); + assert_eq!(bar.z(), 11); + assert_eq!(bar.y(), 12); + assert_eq!(bar.w(), 21); + + let baz: Box = v.clone(); + let foo: Box = baz; + assert_eq!(*foo, 1); + assert_eq!(foo.a(), 100); + assert_eq!(foo.z(), 11); + assert_eq!(foo.y(), 12); + + let baz: Box = v.clone(); + let bar: Box = baz; + let foo: Box = bar; + assert_eq!(*foo, 1); + assert_eq!(foo.a(), 100); + assert_eq!(foo.z(), 11); + assert_eq!(foo.y(), 12); + } + + fn test_rc() { + let v = Rc::new(1); + + let baz: Rc = v.clone(); + assert_eq!(*baz, 1); + assert_eq!(baz.a(), 100); + assert_eq!(baz.b(), 200); + assert_eq!(baz.c(), 300); + assert_eq!(baz.z(), 11); + assert_eq!(baz.y(), 12); + assert_eq!(baz.w(), 21); + + let baz: Rc = v.clone(); + let bar: Rc = baz; + assert_eq!(*bar, 1); + assert_eq!(bar.a(), 100); + assert_eq!(bar.b(), 200); + assert_eq!(bar.z(), 11); + assert_eq!(bar.y(), 12); + assert_eq!(bar.w(), 21); + + let baz: Rc = v.clone(); + let foo: Rc = baz; + assert_eq!(*foo, 1); + assert_eq!(foo.a(), 100); + assert_eq!(foo.z(), 11); + assert_eq!(foo.y(), 12); + + let baz: Rc = v.clone(); + let bar: Rc = baz; + let foo: Rc = bar; + assert_eq!(*foo, 1); + assert_eq!(foo.a(), 100); + assert_eq!(foo.z(), 11); + assert_eq!(foo.y(), 12); + assert_eq!(foo.z(), 11); + assert_eq!(foo.y(), 12); + } + + fn test_arc() { + let v = Arc::new(1); + + let baz: Arc = v.clone(); + assert_eq!(*baz, 1); + assert_eq!(baz.a(), 100); + assert_eq!(baz.b(), 200); + assert_eq!(baz.c(), 300); + assert_eq!(baz.z(), 11); + assert_eq!(baz.y(), 12); + assert_eq!(baz.w(), 21); + + let baz: Arc = v.clone(); + let bar: Arc = baz; + assert_eq!(*bar, 1); + assert_eq!(bar.a(), 100); + assert_eq!(bar.b(), 200); + assert_eq!(bar.z(), 11); + assert_eq!(bar.y(), 12); + assert_eq!(bar.w(), 21); + + let baz: Arc = v.clone(); + let foo: Arc = baz; + assert_eq!(*foo, 1); + assert_eq!(foo.a(), 100); + assert_eq!(foo.z(), 11); + assert_eq!(foo.y(), 12); + + let baz: Arc = v.clone(); + let bar: Arc = baz; + let foo: Arc = bar; + assert_eq!(*foo, 1); + assert_eq!(foo.a(), 100); + assert_eq!(foo.z(), 11); + assert_eq!(foo.y(), 12); + } + + test_box(); + test_rc(); + test_arc(); +} + +fn replace_vptr() { + trait A { + fn foo_a(&self); + } + + trait B { + fn foo_b(&self); + } + + trait C: A + B { + fn foo_c(&self); + } + + struct S(i32); + + impl A for S { + fn foo_a(&self) { + unreachable!(); + } + } + + impl B for S { + fn foo_b(&self) { + assert_eq!(42, self.0); + } + } + + impl C for S { + fn foo_c(&self) { + unreachable!(); + } + } + + fn invoke_inner(b: &dyn B) { + b.foo_b(); + } + + fn invoke_outer(c: &dyn C) { + invoke_inner(c); + } + + let s = S(42); + invoke_outer(&s); +} From db93abe8234ad14d8adca09b5d6f93030a82d4b6 Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Tue, 19 Jul 2022 17:08:17 -0400 Subject: [PATCH 3518/3747] Fix bugs where unique_range became invalid And also expand the cache integrity checks to cover this case, and generally assert a lot more about the unique_range, then tighten up sloppy implementation scenarios that this uncovered. --- src/stacked_borrows/stack.rs | 42 +++++++++++++++++++++++++++--------- 1 file changed, 32 insertions(+), 10 deletions(-) diff --git a/src/stacked_borrows/stack.rs b/src/stacked_borrows/stack.rs index bc7ffd4faea55..9fab5433d84cc 100644 --- a/src/stacked_borrows/stack.rs +++ b/src/stacked_borrows/stack.rs @@ -92,6 +92,7 @@ impl<'tcx> Stack { } } + // Check that all Unique items fall within unique_range. for (idx, item) in self.borrows.iter().enumerate() { if item.perm() == Permission::Unique { assert!( @@ -102,6 +103,18 @@ impl<'tcx> Stack { ); } } + + // Check that the unique_range is a valid index into the borrow stack. + let uniques = &self.borrows[self.unique_range.clone()]; + + // Check that the start of the unique_range is precise. + if let Some(first_unique) = uniques.first() { + assert_eq!(first_unique.perm(), Permission::Unique); + } + // We cannot assert that the unique range is exact on the upper end. + // When we pop items within the unique range, setting the end of the range precisely + // require doing a linear search of the borrow stack, which is exactly the kind of + // operation that all this caching exists to avoid. } /// Find the item granting the given kind of access to the given tag, and return where @@ -227,9 +240,14 @@ impl<'tcx> Stack { self.unique_range.end += 1; } if new.perm() == Permission::Unique { - // Make sure the possibly-unique range contains the new borrow - self.unique_range.start = self.unique_range.start.min(new_idx); - self.unique_range.end = self.unique_range.end.max(new_idx + 1); + // If this is the first Unique, set the range to contain just the new item. + if self.unique_range == (0..0) { + self.unique_range = new_idx..new_idx + 1; + } else { + // We already have other Unique items, expand the range to include the new item + self.unique_range.start = self.unique_range.start.min(new_idx); + self.unique_range.end = self.unique_range.end.max(new_idx + 1); + } } // The above insert changes the meaning of every index in the cache >= new_idx, so now @@ -282,6 +300,10 @@ impl<'tcx> Stack { // cache when it has been cleared and not yet refilled. self.borrows.clear(); self.unknown_bottom = Some(tag); + #[cfg(feature = "stack-cache")] + { + self.unique_range = 0..0; + } } /// Find all `Unique` elements in this borrow stack above `granting_idx`, pass a copy of them @@ -298,7 +320,7 @@ impl<'tcx> Stack { if disable_start <= unique_range.end { let lower = unique_range.start.max(disable_start); - let upper = (unique_range.end + 1).min(self.borrows.len()); + let upper = self.unique_range.end; for item in &mut self.borrows[lower..upper] { if item.perm() == Permission::Unique { log::trace!("access: disabling item {:?}", item); @@ -315,14 +337,14 @@ impl<'tcx> Stack { } #[cfg(feature = "stack-cache")] - if disable_start < self.unique_range.start { + if disable_start <= self.unique_range.start { // We disabled all Unique items self.unique_range.start = 0; self.unique_range.end = 0; } else { - // Truncate the range to disable_start. This is + 2 because we are only removing - // elements after disable_start, and this range does not include the end. - self.unique_range.end = self.unique_range.end.min(disable_start + 1); + // Truncate the range to only include items up to the index that we started disabling + // at. + self.unique_range.end = self.unique_range.end.min(disable_start); } #[cfg(debug_assertions)] @@ -369,12 +391,12 @@ impl<'tcx> Stack { self.cache.items[i] = base_tag; } - if start < self.unique_range.start.saturating_sub(1) { + if start <= self.unique_range.start { // We removed all the Unique items self.unique_range = 0..0; } else { // Ensure the range doesn't extend past the new top of the stack - self.unique_range.end = self.unique_range.end.min(start + 1); + self.unique_range.end = self.unique_range.end.min(start); } } else { self.unique_range = 0..0; From 3e93045c8781bff244c119302a349a1be6bff83f Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Tue, 19 Jul 2022 20:22:04 -0400 Subject: [PATCH 3519/3747] Add a minimal reproducer of the ICE Co-authored-by: Ralf Jung --- tests/pass/issues/issue-miri-2389.rs | 17 +++++++++++++++++ tests/pass/issues/issue-miri-2389.stderr | 15 +++++++++++++++ 2 files changed, 32 insertions(+) create mode 100644 tests/pass/issues/issue-miri-2389.rs create mode 100644 tests/pass/issues/issue-miri-2389.stderr diff --git a/tests/pass/issues/issue-miri-2389.rs b/tests/pass/issues/issue-miri-2389.rs new file mode 100644 index 0000000000000..469122095e512 --- /dev/null +++ b/tests/pass/issues/issue-miri-2389.rs @@ -0,0 +1,17 @@ +use std::cell::Cell; + +fn main() { + unsafe { + let root0 = Cell::new(42); + let wildcard = &root0 as *const Cell as usize as *const Cell; + // empty the stack to unknown (via SRW reborrow from wildcard) + let _ref0 = &*wildcard; + // Do a non-SRW reborrow from wildcard to start building up a stack again. + // Now new refs start being inserted at idx 0, pushing the unique_range up. + let _refn = &*&*&*&*&*(wildcard.cast::()); + // empty the stack again, but this time with unique_range.start sitting at some high index. + let _ref0 = &*wildcard; + // and do a read which tries to clear the uniques + wildcard.cast::().read(); + } +} diff --git a/tests/pass/issues/issue-miri-2389.stderr b/tests/pass/issues/issue-miri-2389.stderr new file mode 100644 index 0000000000000..2ff931f231573 --- /dev/null +++ b/tests/pass/issues/issue-miri-2389.stderr @@ -0,0 +1,15 @@ +warning: integer-to-pointer cast + --> $DIR/issue-miri-2389.rs:LL:CC + | +LL | let wildcard = &root0 as *const Cell as usize as *const Cell; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ integer-to-pointer cast + | + = help: This program is using integer-to-pointer casts or (equivalently) `ptr::from_exposed_addr`, + = help: which means that Miri might miss pointer bugs in this program. + = help: See https://doc.rust-lang.org/nightly/std/ptr/fn.from_exposed_addr.html for more details on that operation. + = help: To ensure that Miri does not miss bugs in your program, use Strict Provenance APIs (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance, https://crates.io/crates/sptr) instead. + = help: You can then pass the `-Zmiri-strict-provenance` flag to Miri, to ensure you are not relying on `from_exposed_addr` semantics. + = help: Alternatively, the `-Zmiri-permissive-provenance` flag disables this warning. + = note: backtrace: + = note: inside `main` at $DIR/issue-miri-2389.rs:LL:CC + From 4268918a502f899c4bc9041e7610c3bbc4d76517 Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Tue, 19 Jul 2022 20:53:48 -0400 Subject: [PATCH 3520/3747] Clarify implementation a bit --- src/stacked_borrows/stack.rs | 7 ++++--- tests/pass/{issues => stacked-borrows}/issue-miri-2389.rs | 0 .../{issues => stacked-borrows}/issue-miri-2389.stderr | 0 3 files changed, 4 insertions(+), 3 deletions(-) rename tests/pass/{issues => stacked-borrows}/issue-miri-2389.rs (100%) rename tests/pass/{issues => stacked-borrows}/issue-miri-2389.stderr (100%) diff --git a/src/stacked_borrows/stack.rs b/src/stacked_borrows/stack.rs index 9fab5433d84cc..32c1be5fb1e2b 100644 --- a/src/stacked_borrows/stack.rs +++ b/src/stacked_borrows/stack.rs @@ -105,6 +105,7 @@ impl<'tcx> Stack { } // Check that the unique_range is a valid index into the borrow stack. + // This asserts that the unique_range's start <= end. let uniques = &self.borrows[self.unique_range.clone()]; // Check that the start of the unique_range is precise. @@ -113,7 +114,7 @@ impl<'tcx> Stack { } // We cannot assert that the unique range is exact on the upper end. // When we pop items within the unique range, setting the end of the range precisely - // require doing a linear search of the borrow stack, which is exactly the kind of + // requires doing a linear search of the borrow stack, which is exactly the kind of // operation that all this caching exists to avoid. } @@ -240,8 +241,8 @@ impl<'tcx> Stack { self.unique_range.end += 1; } if new.perm() == Permission::Unique { - // If this is the first Unique, set the range to contain just the new item. - if self.unique_range == (0..0) { + // If this is the only Unique, set the range to contain just the new item. + if self.unique_range.is_empty() { self.unique_range = new_idx..new_idx + 1; } else { // We already have other Unique items, expand the range to include the new item diff --git a/tests/pass/issues/issue-miri-2389.rs b/tests/pass/stacked-borrows/issue-miri-2389.rs similarity index 100% rename from tests/pass/issues/issue-miri-2389.rs rename to tests/pass/stacked-borrows/issue-miri-2389.rs diff --git a/tests/pass/issues/issue-miri-2389.stderr b/tests/pass/stacked-borrows/issue-miri-2389.stderr similarity index 100% rename from tests/pass/issues/issue-miri-2389.stderr rename to tests/pass/stacked-borrows/issue-miri-2389.stderr From 5fbf036670592d79eae81c4617141502b53a09a8 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 19 Jul 2022 21:44:45 -0400 Subject: [PATCH 3521/3747] only do env var cleanup if all threads have stopped --- src/concurrency/data_race.rs | 78 ++++++++++++++++++------------------ src/eval.rs | 13 +++--- 2 files changed, 45 insertions(+), 46 deletions(-) diff --git a/src/concurrency/data_race.rs b/src/concurrency/data_race.rs index 4b402b51fc59d..8ee8df7445b3b 100644 --- a/src/concurrency/data_race.rs +++ b/src/concurrency/data_race.rs @@ -436,45 +436,6 @@ impl MemoryCellClocks { /// Evaluation context extensions. impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { - /// Temporarily allow data-races to occur. This should only be used in - /// one of these cases: - /// - One of the appropriate `validate_atomic` functions will be called to - /// to treat a memory access as atomic. - /// - The memory being accessed should be treated as internal state, that - /// cannot be accessed by the interpreted program. - /// - Execution of the interpreted program execution has halted. - #[inline] - fn allow_data_races_ref(&self, op: impl FnOnce(&MiriEvalContext<'mir, 'tcx>) -> R) -> R { - let this = self.eval_context_ref(); - if let Some(data_race) = &this.machine.data_race { - data_race.ongoing_action_data_race_free.set(true); - } - let result = op(this); - if let Some(data_race) = &this.machine.data_race { - data_race.ongoing_action_data_race_free.set(false); - } - result - } - - /// Same as `allow_data_races_ref`, this temporarily disables any data-race detection and - /// so should only be used for atomic operations or internal state that the program cannot - /// access. - #[inline] - fn allow_data_races_mut( - &mut self, - op: impl FnOnce(&mut MiriEvalContext<'mir, 'tcx>) -> R, - ) -> R { - let this = self.eval_context_mut(); - if let Some(data_race) = &this.machine.data_race { - data_race.ongoing_action_data_race_free.set(true); - } - let result = op(this); - if let Some(data_race) = &this.machine.data_race { - data_race.ongoing_action_data_race_free.set(false); - } - result - } - /// Atomic variant of read_scalar_at_offset. fn read_scalar_at_offset_atomic( &self, @@ -1044,6 +1005,45 @@ impl VClockAlloc { impl<'mir, 'tcx: 'mir> EvalContextPrivExt<'mir, 'tcx> for MiriEvalContext<'mir, 'tcx> {} trait EvalContextPrivExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { + /// Temporarily allow data-races to occur. This should only be used in + /// one of these cases: + /// - One of the appropriate `validate_atomic` functions will be called to + /// to treat a memory access as atomic. + /// - The memory being accessed should be treated as internal state, that + /// cannot be accessed by the interpreted program. + /// - Execution of the interpreted program execution has halted. + #[inline] + fn allow_data_races_ref(&self, op: impl FnOnce(&MiriEvalContext<'mir, 'tcx>) -> R) -> R { + let this = self.eval_context_ref(); + if let Some(data_race) = &this.machine.data_race { + data_race.ongoing_action_data_race_free.set(true); + } + let result = op(this); + if let Some(data_race) = &this.machine.data_race { + data_race.ongoing_action_data_race_free.set(false); + } + result + } + + /// Same as `allow_data_races_ref`, this temporarily disables any data-race detection and + /// so should only be used for atomic operations or internal state that the program cannot + /// access. + #[inline] + fn allow_data_races_mut( + &mut self, + op: impl FnOnce(&mut MiriEvalContext<'mir, 'tcx>) -> R, + ) -> R { + let this = self.eval_context_mut(); + if let Some(data_race) = &this.machine.data_race { + data_race.ongoing_action_data_race_free.set(true); + } + let result = op(this); + if let Some(data_race) = &this.machine.data_race { + data_race.ongoing_action_data_race_free.set(false); + } + result + } + /// Generic atomic operation implementation fn validate_atomic_op( &self, diff --git a/src/eval.rs b/src/eval.rs index 44459621e393d..996d04a2c57cc 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -363,13 +363,12 @@ pub fn eval_entry<'tcx>( panic::resume_unwind(panic_payload) }); - // Machine cleanup. - // Execution of the program has halted so any memory access we do here - // cannot produce a real data race. If we do not do something to disable - // data race detection here, some uncommon combination of errors will - // cause a data race to be detected: - // https://github.com/rust-lang/miri/issues/2020 - ecx.allow_data_races_mut(|ecx| EnvVars::cleanup(ecx).unwrap()); + // Machine cleanup. Only do this if all threads have terminated; threads that are still running + // might cause data races (https://github.com/rust-lang/miri/issues/2020) or Stacked Borrows + // errors (https://github.com/rust-lang/miri/issues/2396) if we deallocate here. + if ecx.have_all_terminated() { + EnvVars::cleanup(&mut ecx).unwrap(); + } // Process the result. match res { From e12a721d84a612fe0e31e2c450f46f0907f6ec37 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 20 Jul 2022 07:42:08 -0400 Subject: [PATCH 3522/3747] no need for an exhaustive enum of subcommands --- cargo-miri/bin.rs | 34 +++++++++++++++++++--------------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index 233d81826eecf..2ab854b906a4f 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -1,3 +1,4 @@ +#![feature(let_else)] #![allow(clippy::useless_format, clippy::derive_partial_eq_without_eq)] mod version; @@ -34,11 +35,12 @@ Examples: cargo miri test -- test-suite-filter "#; -#[derive(Copy, Clone, Debug, PartialEq, Eq)] +#[derive(Clone, Debug)] enum MiriCommand { - Run, - Test, + /// Our own special 'setup' command. Setup, + /// A command to be forwarded to cargo. + Forward(String), } /// The information to run a crate with the given environment. @@ -339,9 +341,10 @@ fn write_to_file(filename: &Path, content: &str) { /// Performs the setup required to make `cargo miri` work: Getting a custom-built libstd. Then sets /// `MIRI_SYSROOT`. Skipped if `MIRI_SYSROOT` is already set, in which case we expect the user has /// done all this already. -fn setup(subcommand: MiriCommand) { +fn setup(subcommand: &MiriCommand) { + let only_setup = matches!(subcommand, MiriCommand::Setup); if std::env::var_os("MIRI_SYSROOT").is_some() { - if subcommand == MiriCommand::Setup { + if only_setup { println!("WARNING: MIRI_SYSROOT already set, not doing anything.") } return; @@ -349,7 +352,7 @@ fn setup(subcommand: MiriCommand) { // Subcommands other than `setup` will do a setup if necessary, but // interactively confirm first. - let ask_user = subcommand != MiriCommand::Setup; + let ask_user = !only_setup; // First, we need xargo. if xargo_version().map_or(true, |v| v < XARGO_MIN_VERSION) { @@ -495,11 +498,11 @@ path = "lib.rs" let sysroot = if target == &host { dir.join("HOST") } else { PathBuf::from(dir) }; std::env::set_var("MIRI_SYSROOT", &sysroot); // pass the env var to the processes we spawn, which will turn it into "--sysroot" flags // Figure out what to print. - let print_sysroot = subcommand == MiriCommand::Setup && has_arg_flag("--print-sysroot"); // whether we just print the sysroot path + let print_sysroot = only_setup && has_arg_flag("--print-sysroot"); // whether we just print the sysroot path if print_sysroot { // Print just the sysroot and nothing else; this way we do not need any escaping. println!("{}", sysroot.display()); - } else if subcommand == MiriCommand::Setup { + } else if only_setup { println!("A libstd for Miri is now available in `{}`.", sysroot.display()); } } @@ -573,10 +576,12 @@ fn phase_cargo_miri(mut args: env::Args) { // Require a subcommand before any flags. // We cannot know which of those flags take arguments and which do not, // so we cannot detect subcommands later. - let subcommand = match args.next().as_deref() { - Some("test" | "t") => MiriCommand::Test, - Some("run" | "r") => MiriCommand::Run, - Some("setup") => MiriCommand::Setup, + let Some(subcommand) = args.next() else { + show_error(format!("`cargo miri` needs to be called with a subcommand (`run`, `test`)")); + }; + let subcommand = match &*subcommand { + "setup" => MiriCommand::Setup, + "test" | "t" | "run" | "r" => MiriCommand::Forward(subcommand), // Invalid command. _ => show_error(format!( @@ -586,7 +591,7 @@ fn phase_cargo_miri(mut args: env::Args) { let verbose = has_arg_flag("-v"); // We always setup. - setup(subcommand); + setup(&subcommand); // Invoke actual cargo for the job, but with different flags. // We re-use `cargo test` and `cargo run`, which makes target and binary handling very easy but @@ -596,8 +601,7 @@ fn phase_cargo_miri(mut args: env::Args) { // harder. let cargo_miri_path = std::env::current_exe().expect("current executable path invalid"); let cargo_cmd = match subcommand { - MiriCommand::Test => "test", - MiriCommand::Run => "run", + MiriCommand::Forward(s) => s, MiriCommand::Setup => return, // `cargo miri setup` stops here. }; let mut cmd = cargo(); From e0514508b4b7cb4042683e6524df8f3ec9f0104f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 20 Jul 2022 11:27:04 -0400 Subject: [PATCH 3523/3747] fix test file name --- tests/pass/{upcast.rs => dyn-upcast.rs} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename tests/pass/{upcast.rs => dyn-upcast.rs} (100%) diff --git a/tests/pass/upcast.rs b/tests/pass/dyn-upcast.rs similarity index 100% rename from tests/pass/upcast.rs rename to tests/pass/dyn-upcast.rs From ab6fb9d2aa440a48723d311bcd065be9552a27f0 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Thu, 14 Jul 2022 10:03:08 +0000 Subject: [PATCH 3524/3747] Allow tests to have dependencies --- Cargo.lock | 35 ++ cargo-miri/bin.rs | 62 ++- test-cargo-miri/Cargo.lock | 23 +- test-cargo-miri/Cargo.toml | 2 - test-cargo-miri/run-test.py | 28 +- test-cargo-miri/tests/test.rs | 8 +- test_dependencies/Cargo.lock | 376 ++++++++++++++++++ test_dependencies/Cargo.toml | 19 + test_dependencies/src/main.rs | 1 + tests/compiletest.rs | 49 ++- .../libc_pthread_create_main_terminate.rs | 2 - .../concurrency/libc_pthread_join_detached.rs | 2 - .../concurrency/libc_pthread_join_joined.rs | 2 - .../concurrency/libc_pthread_join_main.rs | 2 - .../concurrency/libc_pthread_join_multiple.rs | 2 - .../concurrency/libc_pthread_join_self.rs | 2 - tests/fail/concurrency/too_few_args.rs | 2 - tests/fail/concurrency/too_many_args.rs | 2 - tests/fail/concurrency/unwind_top_of_stack.rs | 2 - tests/fail/fs/close_stdout.rs | 2 - tests/fail/fs/isolated_stdin.rs | 2 - tests/fail/fs/read_from_stdout.rs | 2 - .../fs/unix_open_missing_required_mode.rs | 2 - tests/fail/fs/write_to_stdin.rs | 2 - .../sync/libc_pthread_cond_double_destroy.rs | 1 - .../libc_pthread_condattr_double_destroy.rs | 1 - .../sync/libc_pthread_mutex_NULL_deadlock.rs | 2 - .../fail/sync/libc_pthread_mutex_deadlock.rs | 2 - .../libc_pthread_mutex_default_deadlock.rs | 2 - .../sync/libc_pthread_mutex_destroy_locked.rs | 2 - .../sync/libc_pthread_mutex_double_destroy.rs | 1 - .../libc_pthread_mutex_normal_deadlock.rs | 2 - ...bc_pthread_mutex_normal_unlock_unlocked.rs | 2 - .../sync/libc_pthread_mutex_wrong_owner.rs | 2 - .../libc_pthread_mutexattr_double_destroy.rs | 1 - ...libc_pthread_rwlock_destroy_read_locked.rs | 2 - ...ibc_pthread_rwlock_destroy_write_locked.rs | 2 - .../libc_pthread_rwlock_double_destroy.rs | 1 - ...wlock_read_write_deadlock_single_thread.rs | 2 - .../libc_pthread_rwlock_read_wrong_owner.rs | 2 - .../libc_pthread_rwlock_unlock_unlocked.rs | 2 - ...libc_pthread_rwlock_write_read_deadlock.rs | 2 - ...wlock_write_read_deadlock_single_thread.rs | 2 - ...ibc_pthread_rwlock_write_write_deadlock.rs | 2 - ...lock_write_write_deadlock_single_thread.rs | 2 - .../libc_pthread_rwlock_write_wrong_owner.rs | 2 - tests/fail/tokio_mvp.rs | 7 + tests/fail/tokio_mvp.stderr | 19 + tests/fail/unsupported_signal.rs | 2 - tests/panic/panic/unsupported_syscall.rs | 2 - tests/pass/calloc.rs | 2 - tests/pass/concurrency/libc_pthread_cond.rs | 2 - tests/pass/concurrency/linux-futex.rs | 1 - .../concurrency/tls_pthread_drop_order.rs | 1 - tests/pass/foreign-fn-linkname.rs | 2 - tests/pass/fs.rs | 2 - tests/pass/fs_with_isolation.rs | 2 - tests/pass/libc.rs | 2 - .../pass/linux-getrandom-without-isolation.rs | 1 - tests/pass/linux-getrandom.rs | 1 - tests/pass/malloc.rs | 2 - tests/pass/random.rs | 22 + tests/pass/regions-mock-trans.rs | 2 - ui_test/Cargo.lock | 35 ++ ui_test/Cargo.toml | 2 +- ui_test/README.md | 2 + ui_test/src/dependencies.rs | 137 +++++++ ui_test/src/lib.rs | 37 +- ui_test/src/tests.rs | 2 + 69 files changed, 792 insertions(+), 165 deletions(-) create mode 100644 test_dependencies/Cargo.lock create mode 100644 test_dependencies/Cargo.toml create mode 100644 test_dependencies/src/main.rs create mode 100644 tests/fail/tokio_mvp.rs create mode 100644 tests/fail/tokio_mvp.stderr create mode 100644 tests/pass/random.rs create mode 100644 ui_test/src/dependencies.rs diff --git a/Cargo.lock b/Cargo.lock index cc707c630e54e..f660ed77620a1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -73,6 +73,37 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +[[package]] +name = "camino" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "869119e97797867fd90f5e22af7d0bd274bd4635ebb9eb68c04f3f513ae6c412" +dependencies = [ + "serde", +] + +[[package]] +name = "cargo-platform" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cbdb825da8a5df079a43676dbe042702f1707b1109f713a01420fbb4cc71fa27" +dependencies = [ + "serde", +] + +[[package]] +name = "cargo_metadata" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3abb7553d5b9b8421c6de7cb02606ff15e0c6eea7d8eadd75ef013fd636bec36" +dependencies = [ + "camino", + "cargo-platform", + "semver", + "serde", + "serde_json", +] + [[package]] name = "cc" version = "1.0.73" @@ -596,6 +627,9 @@ name = "semver" version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8cb243bdfdb5936c8dc3c45762a19d12ab4550cdc753bc247637d4ec35a040fd" +dependencies = [ + "serde", +] [[package]] name = "serde" @@ -724,6 +758,7 @@ dependencies = [ name = "ui_test" version = "0.1.0" dependencies = [ + "cargo_metadata", "color-eyre", "colored", "crossbeam", diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index 2ab854b906a4f..6e140ab7143d4 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -3,6 +3,7 @@ mod version; +use std::collections::HashMap; use std::env; use std::ffi::{OsStr, OsString}; use std::fmt::Write as _; @@ -114,10 +115,14 @@ fn show_error(msg: String) -> ! { std::process::exit(1) } -// Determines whether a `--flag` is present. +/// Determines whether a `--flag` is present. fn has_arg_flag(name: &str) -> bool { - let mut args = std::env::args().take_while(|val| val != "--"); - args.any(|val| val == name) + num_arg_flag(name) > 0 +} + +/// Determines how many times a `--flag` is present. +fn num_arg_flag(name: &str) -> usize { + std::env::args().take_while(|val| val != "--").filter(|val| val == name).count() } /// Yields all values of command line flag `name` as `Ok(arg)`, and all other arguments except @@ -588,7 +593,7 @@ fn phase_cargo_miri(mut args: env::Args) { "`cargo miri` supports the following subcommands: `run`, `test`, and `setup`." )), }; - let verbose = has_arg_flag("-v"); + let verbose = num_arg_flag("-v"); // We always setup. setup(&subcommand); @@ -685,7 +690,7 @@ fn phase_cargo_miri(mut args: env::Args) { cmd.env("MIRI_LOCAL_CRATES", local_crates(&metadata)); // Run cargo. - if verbose { + if verbose > 0 { eprintln!("[cargo-miri miri] RUSTC_WRAPPER={:?}", cargo_miri_path); eprintln!("[cargo-miri miri] {}={:?}", target_runner_env_name, cargo_miri_path); if *target != host { @@ -693,7 +698,7 @@ fn phase_cargo_miri(mut args: env::Args) { } eprintln!("[cargo-miri miri] RUSTDOC={:?}", cargo_miri_path); eprintln!("[cargo-miri miri] {:?}", cmd); - cmd.env("MIRI_VERBOSE", ""); // This makes the other phases verbose. + cmd.env("MIRI_VERBOSE", verbose.to_string()); // This makes the other phases verbose. } exec(cmd) } @@ -752,7 +757,8 @@ fn phase_rustc(mut args: env::Args, phase: RustcPhase) { } } - let verbose = std::env::var_os("MIRI_VERBOSE").is_some(); + let verbose = std::env::var("MIRI_VERBOSE") + .map_or(0, |verbose| verbose.parse().expect("verbosity flag must be an integer")); let target_crate = is_target_crate(); let print = get_arg_flag_value("--print").is_some() || has_arg_flag("-vV"); // whether this is cargo/xargo invoking rustc to get some infos @@ -761,13 +767,13 @@ fn phase_rustc(mut args: env::Args, phase: RustcPhase) { // https://github.com/rust-lang/miri/issues/1724#issuecomment-787115693 // As we store a JSON file instead of building the crate here, an empty file is fine. let dep_info_name = out_filename("", ".d"); - if verbose { + if verbose > 0 { eprintln!("[cargo-miri rustc] writing stub dep-info to `{}`", dep_info_name.display()); } File::create(dep_info_name).expect("failed to create fake .d file"); let filename = out_filename("", ""); - if verbose { + if verbose > 0 { eprintln!("[cargo-miri rustc] writing run info to `{}`", filename.display()); } info.store(&filename); @@ -810,7 +816,7 @@ fn phase_rustc(mut args: env::Args, phase: RustcPhase) { cmd.args(&env.args); cmd.env("MIRI_BE_RUSTC", "target"); - if verbose { + if verbose > 0 { eprintln!( "[cargo-miri rustc] captured input:\n{}", std::str::from_utf8(&env.stdin).unwrap() @@ -877,6 +883,15 @@ fn phase_rustc(mut args: env::Args, phase: RustcPhase) { cmd.arg("-C").arg("panic=abort"); } } else { + // For host crates (but not when we are printing), we might still have to set the sysroot. + if !print { + // When we're running `cargo-miri` from `x.py` we need to pass the sysroot explicitly as rustc + // can't figure out the sysroot on its own unless it's from rustup. + if let Some(sysroot) = std::env::var_os("SYSROOT") { + cmd.arg("--sysroot").arg(sysroot); + } + } + // For host crates or when we are printing, just forward everything. cmd.args(args); } @@ -888,8 +903,14 @@ fn phase_rustc(mut args: env::Args, phase: RustcPhase) { cmd.env("MIRI_BE_RUSTC", if target_crate { "target" } else { "host" }); // Run it. - if verbose { - eprintln!("[cargo-miri rustc] {:?}", cmd); + if verbose > 0 { + eprint!("[cargo-miri rustc] "); + if verbose > 1 { + for (key, value) in env_vars_from_cmd(&cmd) { + eprintln!("{key}={value:?} \\"); + } + } + eprintln!("{:?}", cmd); } exec(cmd); @@ -908,6 +929,23 @@ fn phase_rustc(mut args: env::Args, phase: RustcPhase) { } } +fn env_vars_from_cmd(cmd: &Command) -> Vec<(String, String)> { + let mut envs = HashMap::new(); + for (key, value) in std::env::vars() { + envs.insert(key, value); + } + for (key, value) in cmd.get_envs() { + if let Some(value) = value { + envs.insert(key.to_str().unwrap().into(), value.to_str().unwrap().to_owned()); + } else { + envs.remove(key.to_str().unwrap()); + } + } + let mut envs: Vec<_> = envs.into_iter().collect(); + envs.sort(); + envs +} + #[derive(Debug, Copy, Clone, PartialEq)] enum RunnerPhase { /// `cargo` is running a binary diff --git a/test-cargo-miri/Cargo.lock b/test-cargo-miri/Cargo.lock index d34db9f14dfcf..4cf58d723a256 100644 --- a/test-cargo-miri/Cargo.lock +++ b/test-cargo-miri/Cargo.lock @@ -15,8 +15,6 @@ dependencies = [ "byteorder", "cdylib", "exported_symbol", - "getrandom 0.1.16", - "getrandom 0.2.7", "issue_1567", "issue_1691", "issue_1705", @@ -51,17 +49,6 @@ dependencies = [ name = "exported_symbol_dep" version = "0.1.0" -[[package]] -name = "getrandom" -version = "0.1.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" -dependencies = [ - "cfg-if", - "libc", - "wasi 0.9.0+wasi-snapshot-preview1", -] - [[package]] name = "getrandom" version = "0.2.7" @@ -70,7 +57,7 @@ checksum = "4eb1a864a501629691edf6c15a593b7a51eebaa1e8468e9ddc623de7c9b58ec6" dependencies = [ "cfg-if", "libc", - "wasi 0.11.0+wasi-snapshot-preview1", + "wasi", ] [[package]] @@ -185,7 +172,7 @@ version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7" dependencies = [ - "getrandom 0.2.7", + "getrandom", ] [[package]] @@ -223,12 +210,6 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5bd2fe26506023ed7b5e1e315add59d6f584c621d037f9368fea9cfb988f368c" -[[package]] -name = "wasi" -version = "0.9.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" - [[package]] name = "wasi" version = "0.11.0+wasi-snapshot-preview1" diff --git a/test-cargo-miri/Cargo.toml b/test-cargo-miri/Cargo.toml index 2193d354d5d21..89a8463e4b325 100644 --- a/test-cargo-miri/Cargo.toml +++ b/test-cargo-miri/Cargo.toml @@ -19,8 +19,6 @@ issue_rust_86261 = { path = "issue-rust-86261" } [dev-dependencies] rand = { version = "0.8", features = ["small_rng"] } -getrandom_1 = { package = "getrandom", version = "0.1" } -getrandom_2 = { package = "getrandom", version = "0.2" } serde_derive = "1.0" # not actually used, but exercises some unique code path (`--extern` .so file) page_size = "0.4.1" diff --git a/test-cargo-miri/run-test.py b/test-cargo-miri/run-test.py index 09e7df39b1c07..bc0046ffb148d 100755 --- a/test-cargo-miri/run-test.py +++ b/test-cargo-miri/run-test.py @@ -5,7 +5,7 @@ and the working directory to contain the cargo-miri-test project. ''' -import sys, subprocess, os, re +import sys, subprocess, os, re, difflib CGREEN = '\33[32m' CBOLD = '\33[1m' @@ -27,6 +27,17 @@ def normalize_stdout(str): str = str.replace("src\\", "src/") # normalize paths across platforms return re.sub("finished in \d+\.\d\ds", "finished in $TIME", str) +def check_output(actual, path, name): + expected = open(path).read() + if expected == actual: + return True + print(f"{path} did not match reference!") + print(f"--- BEGIN diff {name} ---") + for text in difflib.unified_diff(expected.split("\n"), actual.split("\n")): + print(text) + print(f"--- END diff {name} ---") + return False + def test(name, cmd, stdout_ref, stderr_ref, stdin=b'', env={}): print("Testing {}...".format(name)) ## Call `cargo miri`, capture all output @@ -42,17 +53,14 @@ def test(name, cmd, stdout_ref, stderr_ref, stdin=b'', env={}): (stdout, stderr) = p.communicate(input=stdin) stdout = stdout.decode("UTF-8") stderr = stderr.decode("UTF-8") - if p.returncode == 0 and normalize_stdout(stdout) == open(stdout_ref).read() and stderr == open(stderr_ref).read(): + stdout = normalize_stdout(stdout) + + stdout_matches = check_output(stdout, stdout_ref, "stdout") + stderr_matches = check_output(stderr, stderr_ref, "stderr") + + if p.returncode == 0 and stdout_matches and stderr_matches: # All good! return - # Show output - print("Test stdout or stderr did not match reference!") - print("--- BEGIN test stdout ---") - print(stdout, end="") - print("--- END test stdout ---") - print("--- BEGIN test stderr ---") - print(stderr, end="") - print("--- END test stderr ---") fail("exit code was {}".format(p.returncode)) def test_no_rebuild(name, cmd, env={}): diff --git a/test-cargo-miri/tests/test.rs b/test-cargo-miri/tests/test.rs index 8a938ef3c25f6..eb31058e1c19b 100644 --- a/test-cargo-miri/tests/test.rs +++ b/test-cargo-miri/tests/test.rs @@ -20,15 +20,9 @@ fn does_not_work_on_miri() { assert!(&x as *const _ as usize % 4 < 4); } -// We also use this to test some external crates, that we cannot depend on in the compiletest suite. - +// Make sure integration tests can access dev-dependencies #[test] fn entropy_rng() { - // Test `getrandom` directly (in multiple different versions). - let mut data = vec![0; 16]; - getrandom_1::getrandom(&mut data).unwrap(); - getrandom_2::getrandom(&mut data).unwrap(); - // Try seeding with "real" entropy. let mut rng = SmallRng::from_entropy(); let _val = rng.gen::(); diff --git a/test_dependencies/Cargo.lock b/test_dependencies/Cargo.lock new file mode 100644 index 0000000000000..6b5e8c942244f --- /dev/null +++ b/test_dependencies/Cargo.lock @@ -0,0 +1,376 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bytes" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4872d67bab6358e59559027aa3b9157c53d9358c51423c17554809a8858e0f8" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "getrandom" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" +dependencies = [ + "cfg-if", + "libc", + "wasi 0.9.0+wasi-snapshot-preview1", +] + +[[package]] +name = "getrandom" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4eb1a864a501629691edf6c15a593b7a51eebaa1e8468e9ddc623de7c9b58ec6" +dependencies = [ + "cfg-if", + "libc", + "wasi 0.11.0+wasi-snapshot-preview1", +] + +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + +[[package]] +name = "libc" +version = "0.2.126" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836" + +[[package]] +name = "lock_api" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "327fa5b6a6940e4699ec49a9beae1ea4845c6bab9314e4f84ac68742139d8c53" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "memchr" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" + +[[package]] +name = "mio" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57ee1c23c7c63b0c9250c339ffdc69255f110b298b901b9f6c82547b7b87caaf" +dependencies = [ + "libc", + "log", + "wasi 0.11.0+wasi-snapshot-preview1", + "windows-sys", +] + +[[package]] +name = "miri-test-deps" +version = "0.1.0" +dependencies = [ + "getrandom 0.1.16", + "getrandom 0.2.7", + "libc", + "rand", + "tokio", +] + +[[package]] +name = "num_cpus" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "once_cell" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18a6dbe30758c9f83eb00cbea4ac95966305f5a7772f3f42ebfc7fc7eddbd8e1" + +[[package]] +name = "parking_lot" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09a279cbf25cb0757810394fbc1e359949b59e348145c643a939a525692e6929" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-sys", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" + +[[package]] +name = "ppv-lite86" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872" + +[[package]] +name = "proc-macro2" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd96a1e8ed2596c337f8eae5f24924ec83f5ad5ab21ea8e455d3566c69fbcaf7" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3bcdf212e9776fbcb2d23ab029360416bb1706b1aea2d1a5ba002727cbcab804" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7" +dependencies = [ + "getrandom 0.2.7", +] + +[[package]] +name = "redox_syscall" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62f25bc4c7e55e0b0b7a1d43fb893f4fa1361d0abe38b9ce4f323c2adfe6ef42" +dependencies = [ + "bitflags", +] + +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + +[[package]] +name = "signal-hook-registry" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e51e73328dc4ac0c7ccbda3a494dfa03df1de2f46018127f60c693f2648455b0" +dependencies = [ + "libc", +] + +[[package]] +name = "smallvec" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fd0db749597d91ff862fd1d55ea87f7855a744a8425a64695b6fca237d1dad1" + +[[package]] +name = "socket2" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66d72b759436ae32898a2af0a14218dbf55efde3feeb170eb623637db85ee1e0" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "syn" +version = "1.0.98" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c50aef8a904de4c23c788f104b7dddc7d6f79c647c7c8ce4cc8f73eb0ca773dd" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "tokio" +version = "1.19.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c51a52ed6686dd62c320f9b89299e9dfb46f730c7a48e635c19f21d116cb1439" +dependencies = [ + "bytes", + "libc", + "memchr", + "mio", + "num_cpus", + "once_cell", + "parking_lot", + "pin-project-lite", + "signal-hook-registry", + "socket2", + "tokio-macros", + "winapi", +] + +[[package]] +name = "tokio-macros" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9724f9a975fb987ef7a3cd9be0350edcbe130698af5b8f7a631e23d42d052484" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "unicode-ident" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5bd2fe26506023ed7b5e1e315add59d6f584c621d037f9368fea9cfb988f368c" + +[[package]] +name = "wasi" +version = "0.9.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-sys" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea04155a16a59f9eab786fe12a4a450e75cdb175f9e0d80da1e17db09f55b8d2" +dependencies = [ + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_msvc" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9bb8c3fd39ade2d67e9874ac4f3db21f0d710bee00fe7cab16949ec184eeaa47" + +[[package]] +name = "windows_i686_gnu" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "180e6ccf01daf4c426b846dfc66db1fc518f074baa793aa7d9b9aaeffad6a3b6" + +[[package]] +name = "windows_i686_msvc" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2e7917148b2812d1eeafaeb22a97e4813dfa60a3f8f78ebe204bcc88f12f024" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4dcd171b8776c41b97521e5da127a2d86ad280114807d0b2ab1e462bc764d9e1" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.36.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680" diff --git a/test_dependencies/Cargo.toml b/test_dependencies/Cargo.toml new file mode 100644 index 0000000000000..edaa6a6926030 --- /dev/null +++ b/test_dependencies/Cargo.toml @@ -0,0 +1,19 @@ +[package] +authors = ["Miri Team"] +description = "dependencies that unit tests can have" +license = "MIT OR Apache-2.0" +name = "miri-test-deps" +repository = "https://github.com/rust-lang/miri" +version = "0.1.0" +edition = "2021" + +[dependencies] +# all dependencies (and their transitive ones) listed here can be used in `tests/`. +tokio = { version = "1.0", features = ["full"] } +libc = "0.2" + +getrandom_1 = { package = "getrandom", version = "0.1" } +getrandom_2 = { package = "getrandom", version = "0.2" } +rand = { version = "0.8", features = ["small_rng"] } + +[workspace] diff --git a/test_dependencies/src/main.rs b/test_dependencies/src/main.rs new file mode 100644 index 0000000000000..f328e4d9d04c3 --- /dev/null +++ b/test_dependencies/src/main.rs @@ -0,0 +1 @@ +fn main() {} diff --git a/tests/compiletest.rs b/tests/compiletest.rs index ec49e80ca9633..37b9de7327a29 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -1,8 +1,8 @@ use colored::*; use regex::Regex; -use std::env; -use std::path::PathBuf; -use ui_test::{color_eyre::Result, Config, Mode, OutputConflictHandling}; +use std::path::{Path, PathBuf}; +use std::{env, ffi::OsString}; +use ui_test::{color_eyre::Result, Config, DependencyBuilder, Mode, OutputConflictHandling}; fn miri_path() -> PathBuf { PathBuf::from(option_env!("MIRI").unwrap_or(env!("CARGO_BIN_EXE_miri"))) @@ -12,31 +12,31 @@ fn run_tests(mode: Mode, path: &str, target: Option) -> Result<()> { let in_rustc_test_suite = option_env!("RUSTC_STAGE").is_some(); // Add some flags we always want. - let mut flags = Vec::new(); - flags.push("--edition".to_owned()); - flags.push("2018".to_owned()); + let mut flags: Vec = Vec::new(); + flags.push("--edition".into()); + flags.push("2018".into()); if in_rustc_test_suite { // Less aggressive warnings to make the rustc toolstate management less painful. // (We often get warnings when e.g. a feature gets stabilized or some lint gets added/improved.) - flags.push("-Astable-features".to_owned()); - flags.push("-Aunused".to_owned()); + flags.push("-Astable-features".into()); + flags.push("-Aunused".into()); } else { - flags.push("-Dwarnings".to_owned()); - flags.push("-Dunused".to_owned()); + flags.push("-Dwarnings".into()); + flags.push("-Dunused".into()); } - if let Ok(sysroot) = env::var("MIRI_SYSROOT") { - flags.push("--sysroot".to_string()); + if let Some(sysroot) = env::var_os("MIRI_SYSROOT") { + flags.push("--sysroot".into()); flags.push(sysroot); } if let Ok(extra_flags) = env::var("MIRIFLAGS") { for flag in extra_flags.split_whitespace() { - flags.push(flag.to_string()); + flags.push(flag.into()); } } - flags.push("-Zui-testing".to_string()); + flags.push("-Zui-testing".into()); if let Some(target) = &target { - flags.push("--target".to_string()); - flags.push(target.clone()); + flags.push("--target".into()); + flags.push(target.into()); } let skip_ui_checks = env::var_os("MIRI_SKIP_UI_CHECKS").is_some(); @@ -51,6 +51,8 @@ fn run_tests(mode: Mode, path: &str, target: Option) -> Result<()> { // Pass on all arguments as filters. let path_filter = std::env::args().skip(1); + let use_std = env::var_os("MIRI_NO_STD").is_none(); + let config = Config { args: flags, target, @@ -61,6 +63,19 @@ fn run_tests(mode: Mode, path: &str, target: Option) -> Result<()> { path_filter: path_filter.collect(), program: miri_path(), output_conflict_handling, + dependencies_crate_manifest_path: use_std + .then(|| Path::new("test_dependencies").join("Cargo.toml")), + dependency_builder: Some(DependencyBuilder { + program: std::env::var_os("CARGO").unwrap().into(), + args: vec![ + "run".into(), + "--manifest-path".into(), + "cargo-miri/Cargo.toml".into(), + "--".into(), + "miri".into(), + ], + envs: vec![], + }), }; ui_test::run_tests(config) } @@ -107,6 +122,8 @@ regexes! { "[^ `]*/(rust[^/]*|checkout)/library/" => "RUSTLIB/", // erase platform file paths "sys/[a-z]+/" => "sys/PLATFORM/", + // erase paths into the crate registry + r"[^ ]*/\.cargo/registry/.*/(.*\.rs)" => "CARGO_REGISTRY/$1", } fn ui(mode: Mode, path: &str) -> Result<()> { diff --git a/tests/fail/concurrency/libc_pthread_create_main_terminate.rs b/tests/fail/concurrency/libc_pthread_create_main_terminate.rs index 169a021215d5a..9da9fbf2029d1 100644 --- a/tests/fail/concurrency/libc_pthread_create_main_terminate.rs +++ b/tests/fail/concurrency/libc_pthread_create_main_terminate.rs @@ -5,8 +5,6 @@ #![feature(rustc_private)] -extern crate libc; - use std::{mem, ptr}; extern "C" fn thread_start(_null: *mut libc::c_void) -> *mut libc::c_void { diff --git a/tests/fail/concurrency/libc_pthread_join_detached.rs b/tests/fail/concurrency/libc_pthread_join_detached.rs index 6f0d45e2dc099..e81978fc9953a 100644 --- a/tests/fail/concurrency/libc_pthread_join_detached.rs +++ b/tests/fail/concurrency/libc_pthread_join_detached.rs @@ -4,8 +4,6 @@ #![feature(rustc_private)] -extern crate libc; - use std::{mem, ptr}; extern "C" fn thread_start(_null: *mut libc::c_void) -> *mut libc::c_void { diff --git a/tests/fail/concurrency/libc_pthread_join_joined.rs b/tests/fail/concurrency/libc_pthread_join_joined.rs index 77f59fabca5ea..11e00429c6ced 100644 --- a/tests/fail/concurrency/libc_pthread_join_joined.rs +++ b/tests/fail/concurrency/libc_pthread_join_joined.rs @@ -4,8 +4,6 @@ #![feature(rustc_private)] -extern crate libc; - use std::{mem, ptr}; extern "C" fn thread_start(_null: *mut libc::c_void) -> *mut libc::c_void { diff --git a/tests/fail/concurrency/libc_pthread_join_main.rs b/tests/fail/concurrency/libc_pthread_join_main.rs index aff28bcc9b575..f029f08772f2e 100644 --- a/tests/fail/concurrency/libc_pthread_join_main.rs +++ b/tests/fail/concurrency/libc_pthread_join_main.rs @@ -4,8 +4,6 @@ #![feature(rustc_private)] -extern crate libc; - use std::{ptr, thread}; fn main() { diff --git a/tests/fail/concurrency/libc_pthread_join_multiple.rs b/tests/fail/concurrency/libc_pthread_join_multiple.rs index d4d54d3a23fde..017036ab01e18 100644 --- a/tests/fail/concurrency/libc_pthread_join_multiple.rs +++ b/tests/fail/concurrency/libc_pthread_join_multiple.rs @@ -4,8 +4,6 @@ #![feature(rustc_private)] -extern crate libc; - use std::thread; use std::{mem, ptr}; diff --git a/tests/fail/concurrency/libc_pthread_join_self.rs b/tests/fail/concurrency/libc_pthread_join_self.rs index b911b2db3a16f..ae61488931737 100644 --- a/tests/fail/concurrency/libc_pthread_join_self.rs +++ b/tests/fail/concurrency/libc_pthread_join_self.rs @@ -6,8 +6,6 @@ #![feature(rustc_private)] -extern crate libc; - use std::{ptr, thread}; fn main() { diff --git a/tests/fail/concurrency/too_few_args.rs b/tests/fail/concurrency/too_few_args.rs index 11e97ca290f40..4760fbb6b0513 100644 --- a/tests/fail/concurrency/too_few_args.rs +++ b/tests/fail/concurrency/too_few_args.rs @@ -4,8 +4,6 @@ #![feature(rustc_private)] -extern crate libc; - use std::{mem, ptr}; extern "C" fn thread_start() -> *mut libc::c_void { diff --git a/tests/fail/concurrency/too_many_args.rs b/tests/fail/concurrency/too_many_args.rs index dd44207a62551..6abe767dc8a73 100644 --- a/tests/fail/concurrency/too_many_args.rs +++ b/tests/fail/concurrency/too_many_args.rs @@ -4,8 +4,6 @@ #![feature(rustc_private)] -extern crate libc; - use std::{mem, ptr}; extern "C" fn thread_start(_null: *mut libc::c_void, _x: i32) -> *mut libc::c_void { diff --git a/tests/fail/concurrency/unwind_top_of_stack.rs b/tests/fail/concurrency/unwind_top_of_stack.rs index 179ff9c146e89..bd49401e61f57 100644 --- a/tests/fail/concurrency/unwind_top_of_stack.rs +++ b/tests/fail/concurrency/unwind_top_of_stack.rs @@ -5,8 +5,6 @@ #![feature(rustc_private, c_unwind)] -extern crate libc; - use std::{mem, ptr}; extern "C-unwind" fn thread_start(_null: *mut libc::c_void) -> *mut libc::c_void { diff --git a/tests/fail/fs/close_stdout.rs b/tests/fail/fs/close_stdout.rs index bc709fe36d578..86a6239f5f364 100644 --- a/tests/fail/fs/close_stdout.rs +++ b/tests/fail/fs/close_stdout.rs @@ -5,8 +5,6 @@ #![feature(rustc_private)] -extern crate libc; - fn main() { unsafe { libc::close(1); //~ ERROR: stdout cannot be closed diff --git a/tests/fail/fs/isolated_stdin.rs b/tests/fail/fs/isolated_stdin.rs index cd54de3bcecc3..86b04a0383543 100644 --- a/tests/fail/fs/isolated_stdin.rs +++ b/tests/fail/fs/isolated_stdin.rs @@ -2,8 +2,6 @@ #![feature(rustc_private)] -extern crate libc; - fn main() -> std::io::Result<()> { let mut bytes = [0u8; 512]; unsafe { diff --git a/tests/fail/fs/read_from_stdout.rs b/tests/fail/fs/read_from_stdout.rs index 949fe88f43336..0fd8ba2fc4195 100644 --- a/tests/fail/fs/read_from_stdout.rs +++ b/tests/fail/fs/read_from_stdout.rs @@ -3,8 +3,6 @@ #![feature(rustc_private)] -extern crate libc; - fn main() -> std::io::Result<()> { let mut bytes = [0u8; 512]; unsafe { diff --git a/tests/fail/fs/unix_open_missing_required_mode.rs b/tests/fail/fs/unix_open_missing_required_mode.rs index 1f6beadcb82ff..4740dcebe9200 100644 --- a/tests/fail/fs/unix_open_missing_required_mode.rs +++ b/tests/fail/fs/unix_open_missing_required_mode.rs @@ -3,8 +3,6 @@ #![feature(rustc_private)] -extern crate libc; - fn main() { test_file_open_missing_needed_mode(); } diff --git a/tests/fail/fs/write_to_stdin.rs b/tests/fail/fs/write_to_stdin.rs index 4ad7b648e1cfa..0e9109fc6e238 100644 --- a/tests/fail/fs/write_to_stdin.rs +++ b/tests/fail/fs/write_to_stdin.rs @@ -2,8 +2,6 @@ #![feature(rustc_private)] -extern crate libc; - fn main() -> std::io::Result<()> { let bytes = b"hello"; unsafe { diff --git a/tests/fail/sync/libc_pthread_cond_double_destroy.rs b/tests/fail/sync/libc_pthread_cond_double_destroy.rs index d0a4ac46cb330..90d5997f87120 100644 --- a/tests/fail/sync/libc_pthread_cond_double_destroy.rs +++ b/tests/fail/sync/libc_pthread_cond_double_destroy.rs @@ -2,7 +2,6 @@ #![feature(rustc_private)] /// Test that destroying a pthread_cond twice fails, even without a check for number validity -extern crate libc; fn main() { unsafe { diff --git a/tests/fail/sync/libc_pthread_condattr_double_destroy.rs b/tests/fail/sync/libc_pthread_condattr_double_destroy.rs index c64b323813841..028a924196f27 100644 --- a/tests/fail/sync/libc_pthread_condattr_double_destroy.rs +++ b/tests/fail/sync/libc_pthread_condattr_double_destroy.rs @@ -2,7 +2,6 @@ #![feature(rustc_private)] /// Test that destroying a pthread_condattr twice fails, even without a check for number validity -extern crate libc; fn main() { unsafe { diff --git a/tests/fail/sync/libc_pthread_mutex_NULL_deadlock.rs b/tests/fail/sync/libc_pthread_mutex_NULL_deadlock.rs index 8797e895d8c89..d87455877abcd 100644 --- a/tests/fail/sync/libc_pthread_mutex_NULL_deadlock.rs +++ b/tests/fail/sync/libc_pthread_mutex_NULL_deadlock.rs @@ -4,8 +4,6 @@ #![feature(rustc_private)] -extern crate libc; - fn main() { unsafe { let mut mutex: libc::pthread_mutex_t = std::mem::zeroed(); diff --git a/tests/fail/sync/libc_pthread_mutex_deadlock.rs b/tests/fail/sync/libc_pthread_mutex_deadlock.rs index 7da6e51600008..f77f5c2e20226 100644 --- a/tests/fail/sync/libc_pthread_mutex_deadlock.rs +++ b/tests/fail/sync/libc_pthread_mutex_deadlock.rs @@ -2,8 +2,6 @@ #![feature(rustc_private)] -extern crate libc; - use std::cell::UnsafeCell; use std::sync::Arc; use std::thread; diff --git a/tests/fail/sync/libc_pthread_mutex_default_deadlock.rs b/tests/fail/sync/libc_pthread_mutex_default_deadlock.rs index 70a85aa0f9898..b28101e20b246 100644 --- a/tests/fail/sync/libc_pthread_mutex_default_deadlock.rs +++ b/tests/fail/sync/libc_pthread_mutex_default_deadlock.rs @@ -4,8 +4,6 @@ #![feature(rustc_private)] -extern crate libc; - fn main() { unsafe { let mutexattr: libc::pthread_mutexattr_t = std::mem::zeroed(); diff --git a/tests/fail/sync/libc_pthread_mutex_destroy_locked.rs b/tests/fail/sync/libc_pthread_mutex_destroy_locked.rs index fc69ace369930..0f74446fa27e7 100644 --- a/tests/fail/sync/libc_pthread_mutex_destroy_locked.rs +++ b/tests/fail/sync/libc_pthread_mutex_destroy_locked.rs @@ -2,8 +2,6 @@ #![feature(rustc_private)] -extern crate libc; - fn main() { unsafe { let mut mutexattr: libc::pthread_mutexattr_t = std::mem::zeroed(); diff --git a/tests/fail/sync/libc_pthread_mutex_double_destroy.rs b/tests/fail/sync/libc_pthread_mutex_double_destroy.rs index 9b539afc1992a..89022f3b5625e 100644 --- a/tests/fail/sync/libc_pthread_mutex_double_destroy.rs +++ b/tests/fail/sync/libc_pthread_mutex_double_destroy.rs @@ -2,7 +2,6 @@ #![feature(rustc_private)] /// Test that destroying a pthread_mutex twice fails, even without a check for number validity -extern crate libc; fn main() { unsafe { diff --git a/tests/fail/sync/libc_pthread_mutex_normal_deadlock.rs b/tests/fail/sync/libc_pthread_mutex_normal_deadlock.rs index 944e86e106d7a..ab6d9c7739d7b 100644 --- a/tests/fail/sync/libc_pthread_mutex_normal_deadlock.rs +++ b/tests/fail/sync/libc_pthread_mutex_normal_deadlock.rs @@ -2,8 +2,6 @@ #![feature(rustc_private)] -extern crate libc; - fn main() { unsafe { let mut mutexattr: libc::pthread_mutexattr_t = std::mem::zeroed(); diff --git a/tests/fail/sync/libc_pthread_mutex_normal_unlock_unlocked.rs b/tests/fail/sync/libc_pthread_mutex_normal_unlock_unlocked.rs index c2bdce82b6f8f..f259a4dee7d8d 100644 --- a/tests/fail/sync/libc_pthread_mutex_normal_unlock_unlocked.rs +++ b/tests/fail/sync/libc_pthread_mutex_normal_unlock_unlocked.rs @@ -2,8 +2,6 @@ #![feature(rustc_private)] -extern crate libc; - fn main() { unsafe { let mut mutexattr: libc::pthread_mutexattr_t = std::mem::zeroed(); diff --git a/tests/fail/sync/libc_pthread_mutex_wrong_owner.rs b/tests/fail/sync/libc_pthread_mutex_wrong_owner.rs index eea4db7115974..b8e57f8f74e9e 100644 --- a/tests/fail/sync/libc_pthread_mutex_wrong_owner.rs +++ b/tests/fail/sync/libc_pthread_mutex_wrong_owner.rs @@ -2,8 +2,6 @@ #![feature(rustc_private)] -extern crate libc; - use std::cell::UnsafeCell; use std::sync::Arc; use std::thread; diff --git a/tests/fail/sync/libc_pthread_mutexattr_double_destroy.rs b/tests/fail/sync/libc_pthread_mutexattr_double_destroy.rs index 620dbb94a78a2..ac6292570e497 100644 --- a/tests/fail/sync/libc_pthread_mutexattr_double_destroy.rs +++ b/tests/fail/sync/libc_pthread_mutexattr_double_destroy.rs @@ -2,7 +2,6 @@ #![feature(rustc_private)] /// Test that destroying a pthread_mutexattr twice fails, even without a check for number validity -extern crate libc; fn main() { unsafe { diff --git a/tests/fail/sync/libc_pthread_rwlock_destroy_read_locked.rs b/tests/fail/sync/libc_pthread_rwlock_destroy_read_locked.rs index 67b77ff286470..ae7c1bbde72af 100644 --- a/tests/fail/sync/libc_pthread_rwlock_destroy_read_locked.rs +++ b/tests/fail/sync/libc_pthread_rwlock_destroy_read_locked.rs @@ -2,8 +2,6 @@ #![feature(rustc_private)] -extern crate libc; - fn main() { let rw = std::cell::UnsafeCell::new(libc::PTHREAD_RWLOCK_INITIALIZER); unsafe { diff --git a/tests/fail/sync/libc_pthread_rwlock_destroy_write_locked.rs b/tests/fail/sync/libc_pthread_rwlock_destroy_write_locked.rs index 5bc5fe3c6bc4c..9642595ca4e0b 100644 --- a/tests/fail/sync/libc_pthread_rwlock_destroy_write_locked.rs +++ b/tests/fail/sync/libc_pthread_rwlock_destroy_write_locked.rs @@ -2,8 +2,6 @@ #![feature(rustc_private)] -extern crate libc; - fn main() { let rw = std::cell::UnsafeCell::new(libc::PTHREAD_RWLOCK_INITIALIZER); unsafe { diff --git a/tests/fail/sync/libc_pthread_rwlock_double_destroy.rs b/tests/fail/sync/libc_pthread_rwlock_double_destroy.rs index 7e756c5bb88f0..81b1661ce8d41 100644 --- a/tests/fail/sync/libc_pthread_rwlock_double_destroy.rs +++ b/tests/fail/sync/libc_pthread_rwlock_double_destroy.rs @@ -2,7 +2,6 @@ #![feature(rustc_private)] /// Test that destroying a pthread_rwlock twice fails, even without a check for number validity -extern crate libc; fn main() { unsafe { diff --git a/tests/fail/sync/libc_pthread_rwlock_read_write_deadlock_single_thread.rs b/tests/fail/sync/libc_pthread_rwlock_read_write_deadlock_single_thread.rs index 76fceb315f441..158dd8c1cda33 100644 --- a/tests/fail/sync/libc_pthread_rwlock_read_write_deadlock_single_thread.rs +++ b/tests/fail/sync/libc_pthread_rwlock_read_write_deadlock_single_thread.rs @@ -2,8 +2,6 @@ #![feature(rustc_private)] -extern crate libc; - fn main() { let rw = std::cell::UnsafeCell::new(libc::PTHREAD_RWLOCK_INITIALIZER); unsafe { diff --git a/tests/fail/sync/libc_pthread_rwlock_read_wrong_owner.rs b/tests/fail/sync/libc_pthread_rwlock_read_wrong_owner.rs index e971fd8c302a5..23dda68c6a428 100644 --- a/tests/fail/sync/libc_pthread_rwlock_read_wrong_owner.rs +++ b/tests/fail/sync/libc_pthread_rwlock_read_wrong_owner.rs @@ -2,8 +2,6 @@ #![feature(rustc_private)] -extern crate libc; - use std::cell::UnsafeCell; use std::sync::Arc; use std::thread; diff --git a/tests/fail/sync/libc_pthread_rwlock_unlock_unlocked.rs b/tests/fail/sync/libc_pthread_rwlock_unlock_unlocked.rs index 29cfd36cafc20..fdcf8e41d36fb 100644 --- a/tests/fail/sync/libc_pthread_rwlock_unlock_unlocked.rs +++ b/tests/fail/sync/libc_pthread_rwlock_unlock_unlocked.rs @@ -2,8 +2,6 @@ #![feature(rustc_private)] -extern crate libc; - fn main() { let rw = std::cell::UnsafeCell::new(libc::PTHREAD_RWLOCK_INITIALIZER); unsafe { diff --git a/tests/fail/sync/libc_pthread_rwlock_write_read_deadlock.rs b/tests/fail/sync/libc_pthread_rwlock_write_read_deadlock.rs index e9c5c17f3eba7..adbb95fc28e8b 100644 --- a/tests/fail/sync/libc_pthread_rwlock_write_read_deadlock.rs +++ b/tests/fail/sync/libc_pthread_rwlock_write_read_deadlock.rs @@ -2,8 +2,6 @@ #![feature(rustc_private)] -extern crate libc; - use std::cell::UnsafeCell; use std::sync::Arc; use std::thread; diff --git a/tests/fail/sync/libc_pthread_rwlock_write_read_deadlock_single_thread.rs b/tests/fail/sync/libc_pthread_rwlock_write_read_deadlock_single_thread.rs index 5ed25344e7c73..a7d16caa7a491 100644 --- a/tests/fail/sync/libc_pthread_rwlock_write_read_deadlock_single_thread.rs +++ b/tests/fail/sync/libc_pthread_rwlock_write_read_deadlock_single_thread.rs @@ -2,8 +2,6 @@ #![feature(rustc_private)] -extern crate libc; - fn main() { let rw = std::cell::UnsafeCell::new(libc::PTHREAD_RWLOCK_INITIALIZER); unsafe { diff --git a/tests/fail/sync/libc_pthread_rwlock_write_write_deadlock.rs b/tests/fail/sync/libc_pthread_rwlock_write_write_deadlock.rs index 3d15370e83dd9..070373255d327 100644 --- a/tests/fail/sync/libc_pthread_rwlock_write_write_deadlock.rs +++ b/tests/fail/sync/libc_pthread_rwlock_write_write_deadlock.rs @@ -2,8 +2,6 @@ #![feature(rustc_private)] -extern crate libc; - use std::cell::UnsafeCell; use std::sync::Arc; use std::thread; diff --git a/tests/fail/sync/libc_pthread_rwlock_write_write_deadlock_single_thread.rs b/tests/fail/sync/libc_pthread_rwlock_write_write_deadlock_single_thread.rs index 14361bee54c06..867c6272c4633 100644 --- a/tests/fail/sync/libc_pthread_rwlock_write_write_deadlock_single_thread.rs +++ b/tests/fail/sync/libc_pthread_rwlock_write_write_deadlock_single_thread.rs @@ -2,8 +2,6 @@ #![feature(rustc_private)] -extern crate libc; - fn main() { let rw = std::cell::UnsafeCell::new(libc::PTHREAD_RWLOCK_INITIALIZER); unsafe { diff --git a/tests/fail/sync/libc_pthread_rwlock_write_wrong_owner.rs b/tests/fail/sync/libc_pthread_rwlock_write_wrong_owner.rs index 668ccb3ecaeff..cff2a7a2e98c2 100644 --- a/tests/fail/sync/libc_pthread_rwlock_write_wrong_owner.rs +++ b/tests/fail/sync/libc_pthread_rwlock_write_wrong_owner.rs @@ -2,8 +2,6 @@ #![feature(rustc_private)] -extern crate libc; - use std::cell::UnsafeCell; use std::sync::Arc; use std::thread; diff --git a/tests/fail/tokio_mvp.rs b/tests/fail/tokio_mvp.rs new file mode 100644 index 0000000000000..7cb42c09a9677 --- /dev/null +++ b/tests/fail/tokio_mvp.rs @@ -0,0 +1,7 @@ +//@compile-flags: -Zmiri-disable-isolation +//@error-pattern: can't call foreign function: epoll_create1 +//@normalize-stderr-test: " = note: inside .*\n" -> "" +//@only-target-linux: the errors differ too much between platforms + +#[tokio::main] +async fn main() {} diff --git a/tests/fail/tokio_mvp.stderr b/tests/fail/tokio_mvp.stderr new file mode 100644 index 0000000000000..cff948f364087 --- /dev/null +++ b/tests/fail/tokio_mvp.stderr @@ -0,0 +1,19 @@ +error: unsupported operation: can't call foreign function: epoll_create1 + --> CARGO_REGISTRY/epoll.rs:LL:CC + | +LL | syscall!(epoll_create1(flag)).map(|ep| Selector { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't call foreign function: epoll_create1 + | + = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support + = note: backtrace: +note: inside `main` at $DIR/tokio_mvp.rs:LL:CC + --> $DIR/tokio_mvp.rs:LL:CC + | +LL | #[tokio::main] + | ^^^^^^^^^^^^^^ + = note: this error originates in the macro `syscall` which comes from the expansion of the attribute macro `tokio::main` (in Nightly builds, run with -Z macro-backtrace for more info) + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/fail/unsupported_signal.rs b/tests/fail/unsupported_signal.rs index e9bd340fcafb7..20ebcc9bc4735 100644 --- a/tests/fail/unsupported_signal.rs +++ b/tests/fail/unsupported_signal.rs @@ -3,8 +3,6 @@ //@ignore-target-windows: No libc on Windows #![feature(rustc_private)] -extern crate libc; - fn main() { unsafe { libc::signal(libc::SIGPIPE, libc::SIG_IGN); diff --git a/tests/panic/panic/unsupported_syscall.rs b/tests/panic/panic/unsupported_syscall.rs index a689172814667..27595bf1071ff 100644 --- a/tests/panic/panic/unsupported_syscall.rs +++ b/tests/panic/panic/unsupported_syscall.rs @@ -3,8 +3,6 @@ //@compile-flags: -Zmiri-panic-on-unsupported #![feature(rustc_private)] -extern crate libc; - fn main() { unsafe { libc::syscall(0); diff --git a/tests/pass/calloc.rs b/tests/pass/calloc.rs index a9efb776b69ea..e155d53ce812e 100644 --- a/tests/pass/calloc.rs +++ b/tests/pass/calloc.rs @@ -2,8 +2,6 @@ #![feature(rustc_private)] -extern crate libc; - use core::slice; fn main() { diff --git a/tests/pass/concurrency/libc_pthread_cond.rs b/tests/pass/concurrency/libc_pthread_cond.rs index eb491486be703..c5b0e86666a0a 100644 --- a/tests/pass/concurrency/libc_pthread_cond.rs +++ b/tests/pass/concurrency/libc_pthread_cond.rs @@ -6,8 +6,6 @@ /// Test that conditional variable timeouts are working properly with both /// monotonic and system clocks. -extern crate libc; - use std::mem::MaybeUninit; use std::time::Instant; diff --git a/tests/pass/concurrency/linux-futex.rs b/tests/pass/concurrency/linux-futex.rs index f9c87e0723c50..43216481e76fb 100644 --- a/tests/pass/concurrency/linux-futex.rs +++ b/tests/pass/concurrency/linux-futex.rs @@ -2,7 +2,6 @@ //@compile-flags: -Zmiri-disable-isolation #![feature(rustc_private)] -extern crate libc; use std::mem::MaybeUninit; use std::ptr; diff --git a/tests/pass/concurrency/tls_pthread_drop_order.rs b/tests/pass/concurrency/tls_pthread_drop_order.rs index c9e8b9271ccfb..1ccc57da25fad 100644 --- a/tests/pass/concurrency/tls_pthread_drop_order.rs +++ b/tests/pass/concurrency/tls_pthread_drop_order.rs @@ -1,7 +1,6 @@ //@ignore-target-windows: No libc on Windows #![feature(rustc_private)] -extern crate libc; use std::mem; use std::ptr; diff --git a/tests/pass/foreign-fn-linkname.rs b/tests/pass/foreign-fn-linkname.rs index 391b182fda03c..40aeb2ef6313f 100644 --- a/tests/pass/foreign-fn-linkname.rs +++ b/tests/pass/foreign-fn-linkname.rs @@ -1,8 +1,6 @@ //ignore-windows: Uses POSIX APIs #![feature(rustc_private)] -extern crate libc; - use std::ffi::CString; mod mlibc { diff --git a/tests/pass/fs.rs b/tests/pass/fs.rs index aa5cd83c69cda..9d59fedb20edb 100644 --- a/tests/pass/fs.rs +++ b/tests/pass/fs.rs @@ -4,8 +4,6 @@ #![feature(rustc_private)] #![feature(io_error_more)] -extern crate libc; - use std::ffi::CString; use std::fs::{ create_dir, read_dir, read_link, remove_dir, remove_dir_all, remove_file, rename, File, diff --git a/tests/pass/fs_with_isolation.rs b/tests/pass/fs_with_isolation.rs index 41ada94e276e2..f73e64ad17a26 100644 --- a/tests/pass/fs_with_isolation.rs +++ b/tests/pass/fs_with_isolation.rs @@ -4,8 +4,6 @@ #![feature(rustc_private)] -extern crate libc; - use std::ffi::CString; use std::fs::{self, File}; use std::io::{Error, ErrorKind}; diff --git a/tests/pass/libc.rs b/tests/pass/libc.rs index 99b7c3f249f51..9b83ab45b0c01 100644 --- a/tests/pass/libc.rs +++ b/tests/pass/libc.rs @@ -5,8 +5,6 @@ use std::fs::{remove_file, File}; use std::os::unix::io::AsRawFd; -extern crate libc; - fn tmp() -> std::path::PathBuf { std::env::var("MIRI_TEMP") .map(std::path::PathBuf::from) diff --git a/tests/pass/linux-getrandom-without-isolation.rs b/tests/pass/linux-getrandom-without-isolation.rs index fea3bb3fdce9d..12b42552bd5d6 100644 --- a/tests/pass/linux-getrandom-without-isolation.rs +++ b/tests/pass/linux-getrandom-without-isolation.rs @@ -1,7 +1,6 @@ //@only-target-linux //@compile-flags: -Zmiri-disable-isolation #![feature(rustc_private)] -extern crate libc; use std::ptr; diff --git a/tests/pass/linux-getrandom.rs b/tests/pass/linux-getrandom.rs index 1d0ab6ed746a6..e3309f480d36e 100644 --- a/tests/pass/linux-getrandom.rs +++ b/tests/pass/linux-getrandom.rs @@ -1,6 +1,5 @@ //@only-target-linux #![feature(rustc_private)] -extern crate libc; use std::ptr; diff --git a/tests/pass/malloc.rs b/tests/pass/malloc.rs index d20ceddbb8edb..9066e2af25fa3 100644 --- a/tests/pass/malloc.rs +++ b/tests/pass/malloc.rs @@ -2,8 +2,6 @@ #![feature(rustc_private)] -extern crate libc; - use core::{ptr, slice}; fn main() { diff --git a/tests/pass/random.rs b/tests/pass/random.rs new file mode 100644 index 0000000000000..808d1006d4f3a --- /dev/null +++ b/tests/pass/random.rs @@ -0,0 +1,22 @@ +use rand::{rngs::SmallRng, Rng, SeedableRng}; +// mac-os `getrandom_1` does some pointer shenanigans +//@compile-flags: -Zmiri-permissive-provenance + +fn main() { + // Test `getrandom` directly (in multiple different versions). + let mut data = vec![0; 16]; + getrandom_1::getrandom(&mut data).unwrap(); + getrandom_2::getrandom(&mut data).unwrap(); + + // Try seeding with "real" entropy. + let mut rng = SmallRng::from_entropy(); + let _val = rng.gen::(); + let _val = rng.gen::(); + let _val = rng.gen::(); + + // Also try per-thread RNG. + let mut rng = rand::thread_rng(); + let _val = rng.gen::(); + let _val = rng.gen::(); + let _val = rng.gen::(); +} diff --git a/tests/pass/regions-mock-trans.rs b/tests/pass/regions-mock-trans.rs index 5dafc88756f11..7432ea9582618 100644 --- a/tests/pass/regions-mock-trans.rs +++ b/tests/pass/regions-mock-trans.rs @@ -2,8 +2,6 @@ #![feature(rustc_private)] -extern crate libc; - use std::mem; struct Arena(()); diff --git a/ui_test/Cargo.lock b/ui_test/Cargo.lock index 2065cc34bef85..9addea9b19d0b 100644 --- a/ui_test/Cargo.lock +++ b/ui_test/Cargo.lock @@ -67,6 +67,37 @@ dependencies = [ "rustc-demangle", ] +[[package]] +name = "camino" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "869119e97797867fd90f5e22af7d0bd274bd4635ebb9eb68c04f3f513ae6c412" +dependencies = [ + "serde", +] + +[[package]] +name = "cargo-platform" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cbdb825da8a5df079a43676dbe042702f1707b1109f713a01420fbb4cc71fa27" +dependencies = [ + "serde", +] + +[[package]] +name = "cargo_metadata" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3abb7553d5b9b8421c6de7cb02606ff15e0c6eea7d8eadd75ef013fd636bec36" +dependencies = [ + "camino", + "cargo-platform", + "semver", + "serde", + "serde_json", +] + [[package]] name = "cc" version = "1.0.73" @@ -390,6 +421,9 @@ name = "semver" version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8cb243bdfdb5936c8dc3c45762a19d12ab4550cdc753bc247637d4ec35a040fd" +dependencies = [ + "serde", +] [[package]] name = "serde" @@ -497,6 +531,7 @@ dependencies = [ name = "ui_test" version = "0.1.0" dependencies = [ + "cargo_metadata", "color-eyre", "colored", "crossbeam", diff --git a/ui_test/Cargo.toml b/ui_test/Cargo.toml index cdc5e5db472c1..bb14eb7ecfe30 100644 --- a/ui_test/Cargo.toml +++ b/ui_test/Cargo.toml @@ -18,4 +18,4 @@ lazy_static = "1.4.0" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" color-eyre = { version = "0.6.1", default-features = false, features = ["capture-spantrace"] } - +cargo_metadata = "0.15" diff --git a/ui_test/README.md b/ui_test/README.md index f1b1a5d67e0ae..3db3361faa532 100644 --- a/ui_test/README.md +++ b/ui_test/README.md @@ -47,3 +47,5 @@ their command specifies, or the test will fail without even being run. * `ignore-target-*` and `only-target-*` opereate solely on the triple, instead of supporting things like `macos` * only `//~` comments can be individualized per revision +* only supports `ui` tests +* tests are run in named order, so you can prefix slow tests with `0` in order to make them get run first diff --git a/ui_test/src/dependencies.rs b/ui_test/src/dependencies.rs new file mode 100644 index 0000000000000..ab3a0156595f7 --- /dev/null +++ b/ui_test/src/dependencies.rs @@ -0,0 +1,137 @@ +use color_eyre::eyre::{bail, Result}; +use std::{ + collections::{HashMap, HashSet}, + path::{Path, PathBuf}, + process::Command, +}; + +use crate::Config; + +#[derive(Default, Debug)] +pub struct Dependencies { + /// All paths that must be imported with `-L dependency=`. This is for + /// finding proc macros run on the host and dependencies for the target. + pub import_paths: Vec, + /// The name as chosen in the `Cargo.toml` and its corresponding rmeta file. + pub dependencies: Vec<(String, PathBuf)>, +} + +/// Compiles dependencies and returns the crate names and corresponding rmeta files. +pub fn build_dependencies(config: &Config) -> Result { + let manifest_path = match &config.dependencies_crate_manifest_path { + Some(path) => path, + None => return Ok(Default::default()), + }; + let (program, args, envs): (&Path, &[_], &[_]) = match &config.dependency_builder { + Some(db) => (&db.program, &db.args, &db.envs), + None => (Path::new("cargo"), &[], &[]), + }; + let mut build = Command::new(program); + build.args(args); + // HACK: we're using `cargo run` (or `cargo miri run`), because the latter does not + // support `cargo miri build` yet. + build.arg("run"); + + if let Some(target) = &config.target { + build.arg(format!("--target={target}")); + } + + // Reusable closure for setting up the environment both for artifact generation and `cargo_metadata` + let setup_command = |cmd: &mut Command| { + cmd.envs(envs.iter().map(|(k, v)| (k, v))); + cmd.arg("--manifest-path").arg(manifest_path); + }; + + setup_command(&mut build); + build + .arg("--target-dir=target/test_dependencies") + .arg("--message-format=json") + .arg("-Zunstable-options"); + + let output = build.output()?; + + if !output.status.success() { + let stdout = String::from_utf8(output.stdout)?; + let stderr = String::from_utf8(output.stderr)?; + bail!("failed to compile dependencies:\nstderr:\n{stderr}\n\nstdout:{stdout}"); + } + + // Collect all artifacts generated + let output = output.stdout; + let output = String::from_utf8(output)?; + let mut import_paths: HashSet = HashSet::new(); + let mut artifacts: HashMap<_, _> = output + .lines() + .filter_map(|line| { + let message = serde_json::from_str::(line).ok()?; + if let cargo_metadata::Message::CompilerArtifact(artifact) = message { + for filename in &artifact.filenames { + import_paths.insert(filename.parent().unwrap().into()); + } + let filename = artifact + .filenames + .into_iter() + .find(|filename| filename.extension() == Some("rmeta"))?; + Some((artifact.package_id, filename.into_std_path_buf())) + } else { + None + } + }) + .collect(); + + // Check which crates are mentioned in the crate itself + let mut metadata = cargo_metadata::MetadataCommand::new().cargo_command(); + setup_command(&mut metadata); + let output = metadata.output()?; + + if !output.status.success() { + let stdout = String::from_utf8(output.stdout)?; + let stderr = String::from_utf8(output.stderr)?; + bail!("failed to run cargo-metadata:\nstderr:\n{stderr}\n\nstdout:{stdout}"); + } + + let output = output.stdout; + let output = String::from_utf8(output)?; + + for line in output.lines() { + if !line.starts_with('{') { + continue; + } + let metadata: cargo_metadata::Metadata = serde_json::from_str(line)?; + // Only take artifacts that are defined in the Cargo.toml + + // First, find the root artifact + let root = metadata + .packages + .iter() + .find(|package| { + package.manifest_path.as_std_path().canonicalize().unwrap() + == manifest_path.canonicalize().unwrap() + }) + .unwrap(); + + // Then go over all of its dependencies + let dependencies = root + .dependencies + .iter() + .map(|package| { + // Get the id for the package matching the version requirement of the dep + let id = &metadata + .packages + .iter() + .find(|&dep| dep.name == package.name && package.req.matches(&dep.version)) + .expect("dependency does not exist") + .id; + // Return the name chosen in `Cargo.toml` and the path to the corresponding artifact + ( + package.rename.clone().unwrap_or_else(|| package.name.clone()), + artifacts.remove(id).expect("package without artifact"), + ) + }) + .collect(); + let import_paths = import_paths.into_iter().collect(); + return Ok(Dependencies { dependencies, import_paths }); + } + + bail!("no json found in cargo-metadata output") +} diff --git a/ui_test/src/lib.rs b/ui_test/src/lib.rs index 917e382379abe..4318e8a8e034d 100644 --- a/ui_test/src/lib.rs +++ b/ui_test/src/lib.rs @@ -1,6 +1,7 @@ #![allow(clippy::enum_variant_names, clippy::useless_format, clippy::too_many_arguments)] use std::collections::VecDeque; +use std::ffi::OsString; use std::fmt::Write; use std::path::{Path, PathBuf}; use std::process::{Command, ExitStatus}; @@ -14,8 +15,10 @@ use parser::{ErrorMatch, Pattern}; use regex::Regex; use rustc_stderr::{Level, Message}; +use crate::dependencies::build_dependencies; use crate::parser::{Comments, Condition}; +mod dependencies; mod parser; mod rustc_stderr; #[cfg(test)] @@ -24,7 +27,7 @@ mod tests; #[derive(Debug)] pub struct Config { /// Arguments passed to the binary that is executed. - pub args: Vec, + pub args: Vec, /// `None` to run on the host, otherwise a target triple pub target: Option, /// Filters applied to stderr output before processing it @@ -38,6 +41,18 @@ pub struct Config { pub output_conflict_handling: OutputConflictHandling, /// Only run tests with one of these strings in their path/name pub path_filter: Vec, + /// Path to a `Cargo.toml` that describes which dependencies the tests can access. + pub dependencies_crate_manifest_path: Option, + /// Can be used to override what command to run instead of `cargo` to build the + /// dependencies in `manifest_path` + pub dependency_builder: Option, +} + +#[derive(Debug)] +pub struct DependencyBuilder { + pub program: PathBuf, + pub args: Vec, + pub envs: Vec<(String, String)>, } #[derive(Debug)] @@ -53,12 +68,26 @@ pub enum OutputConflictHandling { pub type Filter = Vec<(Regex, &'static str)>; -pub fn run_tests(config: Config) -> Result<()> { +pub fn run_tests(mut config: Config) -> Result<()> { eprintln!(" Compiler flags: {:?}", config.args); // Get the triple with which to run the tests let target = config.target.clone().unwrap_or_else(|| config.get_host()); + let dependencies = build_dependencies(&config)?; + for (name, dependency) in dependencies.dependencies { + config.args.push("--extern".into()); + let mut dep = OsString::from(name); + dep.push("="); + dep.push(dependency); + config.args.push(dep); + } + for import_path in dependencies.import_paths { + config.args.push("-L".into()); + config.args.push(import_path.into()); + } + let config = config; + // A channel for files to process let (submit, receive) = crossbeam::channel::unbounded(); @@ -294,9 +323,7 @@ fn run_test( for arg in &comments.compile_flags { miri.arg(arg); } - for (k, v) in &comments.env_vars { - miri.env(k, v); - } + miri.envs(comments.env_vars.iter().map(|(k, v)| (k, v))); let output = miri.output().expect("could not execute miri"); let mut errors = config.mode.ok(output.status); let stderr = check_test_result( diff --git a/ui_test/src/tests.rs b/ui_test/src/tests.rs index 96c0f362b675d..8b0bd517a1054 100644 --- a/ui_test/src/tests.rs +++ b/ui_test/src/tests.rs @@ -16,6 +16,8 @@ fn config() -> Config { path_filter: vec![], program: PathBuf::from("cake"), output_conflict_handling: OutputConflictHandling::Error, + dependencies_crate_manifest_path: None, + dependency_builder: None, } } From c81cfe240ab478b79d6167ebba28eb8fba3cd24c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 20 Jul 2022 15:47:09 -0400 Subject: [PATCH 3525/3747] cargo-miri: reorder --target to after the user-defined commands --- cargo-miri/bin.rs | 38 +++++++++++++++++--------------------- 1 file changed, 17 insertions(+), 21 deletions(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index 4c9f3aabaab49..d294bc5b127a3 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -584,27 +584,12 @@ fn phase_cargo_miri(mut args: env::Args) { MiriCommand::Run => "run", MiriCommand::Setup => return, // `cargo miri setup` stops here. }; + let metadata = get_cargo_metadata(); let mut cmd = cargo(); cmd.arg(cargo_cmd); - // Make sure we know the build target, and cargo does, too. - // This is needed to make the `CARGO_TARGET_*_RUNNER` env var do something, - // and it later helps us detect which crates are proc-macro/build-script - // (host crates) and which crates are needed for the program itself. - let host = version_info().host; - let target = get_arg_flag_value("--target"); - let target = if let Some(ref target) = target { - target - } else { - // No target given. Pick default and tell cargo about it. - cmd.arg("--target"); - cmd.arg(&host); - &host - }; - - let mut target_dir = None; - // Forward all arguments before `--` other than `--target-dir` and its value to Cargo. + let mut target_dir = None; for arg in ArgSplitFlagValue::new(&mut args, "--target-dir") { match arg { Ok(value) => { @@ -618,16 +603,27 @@ fn phase_cargo_miri(mut args: env::Args) { } } } - - let metadata = get_cargo_metadata(); - // Detect the target directory if it's not specified via `--target-dir`. let target_dir = target_dir.get_or_insert_with(|| metadata.target_directory.clone()); - // Set `--target-dir` to `miri` inside the original target directory. target_dir.push("miri"); cmd.arg("--target-dir").arg(target_dir); + // Make sure we know the build target, and cargo does, too. + // This is needed to make the `CARGO_TARGET_*_RUNNER` env var do something, + // and it later helps us detect which crates are proc-macro/build-script + // (host crates) and which crates are needed for the program itself. + let host = version_info().host; + let target = get_arg_flag_value("--target"); + let target = if let Some(ref target) = target { + target + } else { + // No target given. Pick default and tell cargo about it. + cmd.arg("--target"); + cmd.arg(&host); + &host + }; + // Forward all further arguments after `--` to cargo. cmd.arg("--").args(args); From ff4666f39cfa48d5a887a62f49c5f0c04b44642a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 20 Jul 2022 16:02:06 -0400 Subject: [PATCH 3526/3747] rustup --- rust-version | 2 +- src/concurrency/data_race.rs | 50 +++---- src/concurrency/weak_memory.rs | 50 ++++--- src/diagnostics.rs | 2 +- src/eval.rs | 4 +- src/helpers.rs | 105 ++++++++------ src/intptrcast.rs | 10 +- src/lib.rs | 9 +- src/machine.rs | 151 +++++++++++--------- src/operator.rs | 12 +- src/shims/backtrace.rs | 16 +-- src/shims/dlsym.rs | 4 +- src/shims/env.rs | 49 ++++--- src/shims/foreign_items.rs | 20 +-- src/shims/intrinsics/atomic.rs | 34 ++--- src/shims/intrinsics/mod.rs | 12 +- src/shims/intrinsics/simd.rs | 20 +-- src/shims/mod.rs | 10 +- src/shims/os_str.rs | 23 +-- src/shims/panic.rs | 12 +- src/shims/time.rs | 23 +-- src/shims/tls.rs | 12 +- src/shims/unix/dlsym.rs | 4 +- src/shims/unix/foreign_items.rs | 4 +- src/shims/unix/freebsd/dlsym.rs | 4 +- src/shims/unix/freebsd/foreign_items.rs | 4 +- src/shims/unix/fs.rs | 112 ++++++++------- src/shims/unix/linux/dlsym.rs | 4 +- src/shims/unix/linux/foreign_items.rs | 12 +- src/shims/unix/linux/sync.rs | 4 +- src/shims/unix/macos/dlsym.rs | 4 +- src/shims/unix/macos/foreign_items.rs | 4 +- src/shims/unix/sync.rs | 177 +++++++++++++++--------- src/shims/unix/thread.rs | 20 +-- src/shims/windows/dlsym.rs | 4 +- src/shims/windows/foreign_items.rs | 4 +- src/shims/windows/sync.rs | 20 ++- src/stacked_borrows/diagnostics.rs | 15 +- src/stacked_borrows/mod.rs | 74 ++++------ src/stacked_borrows/stack.rs | 11 +- src/sync.rs | 2 +- src/thread.rs | 34 +++-- 42 files changed, 627 insertions(+), 520 deletions(-) diff --git a/rust-version b/rust-version index 38f4b2bda5f2e..f456ded7f4623 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -29c5a028b0c92aa5da6a8eb6d6585a389fcf1035 +a7468c60f8dbf5feb23ad840b174d7e57113a846 diff --git a/src/concurrency/data_race.rs b/src/concurrency/data_race.rs index 8ee8df7445b3b..3f05925d34385 100644 --- a/src/concurrency/data_race.rs +++ b/src/concurrency/data_race.rs @@ -439,11 +439,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { /// Atomic variant of read_scalar_at_offset. fn read_scalar_at_offset_atomic( &self, - op: &OpTy<'tcx, Tag>, + op: &OpTy<'tcx, Provenance>, offset: u64, layout: TyAndLayout<'tcx>, atomic: AtomicReadOrd, - ) -> InterpResult<'tcx, ScalarMaybeUninit> { + ) -> InterpResult<'tcx, ScalarMaybeUninit> { let this = self.eval_context_ref(); let value_place = this.deref_operand_and_offset(op, offset, layout)?; this.read_scalar_atomic(&value_place, atomic) @@ -452,9 +452,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { /// Atomic variant of write_scalar_at_offset. fn write_scalar_at_offset_atomic( &mut self, - op: &OpTy<'tcx, Tag>, + op: &OpTy<'tcx, Provenance>, offset: u64, - value: impl Into>, + value: impl Into>, layout: TyAndLayout<'tcx>, atomic: AtomicWriteOrd, ) -> InterpResult<'tcx> { @@ -466,9 +466,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { /// Perform an atomic read operation at the memory location. fn read_scalar_atomic( &self, - place: &MPlaceTy<'tcx, Tag>, + place: &MPlaceTy<'tcx, Provenance>, atomic: AtomicReadOrd, - ) -> InterpResult<'tcx, ScalarMaybeUninit> { + ) -> InterpResult<'tcx, ScalarMaybeUninit> { let this = self.eval_context_ref(); // This will read from the last store in the modification order of this location. In case // weak memory emulation is enabled, this may not be the store we will pick to actually read from and return. @@ -485,8 +485,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { /// Perform an atomic write operation at the memory location. fn write_scalar_atomic( &mut self, - val: ScalarMaybeUninit, - dest: &MPlaceTy<'tcx, Tag>, + val: ScalarMaybeUninit, + dest: &MPlaceTy<'tcx, Provenance>, atomic: AtomicWriteOrd, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); @@ -504,12 +504,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { /// Perform an atomic operation on a memory location. fn atomic_op_immediate( &mut self, - place: &MPlaceTy<'tcx, Tag>, - rhs: &ImmTy<'tcx, Tag>, + place: &MPlaceTy<'tcx, Provenance>, + rhs: &ImmTy<'tcx, Provenance>, op: mir::BinOp, neg: bool, atomic: AtomicRwOrd, - ) -> InterpResult<'tcx, ImmTy<'tcx, Tag>> { + ) -> InterpResult<'tcx, ImmTy<'tcx, Provenance>> { let this = self.eval_context_mut(); this.validate_overlapping_atomic(place)?; @@ -535,10 +535,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { /// scalar value, the old value is returned. fn atomic_exchange_scalar( &mut self, - place: &MPlaceTy<'tcx, Tag>, - new: ScalarMaybeUninit, + place: &MPlaceTy<'tcx, Provenance>, + new: ScalarMaybeUninit, atomic: AtomicRwOrd, - ) -> InterpResult<'tcx, ScalarMaybeUninit> { + ) -> InterpResult<'tcx, ScalarMaybeUninit> { let this = self.eval_context_mut(); this.validate_overlapping_atomic(place)?; @@ -555,11 +555,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { /// scalar value, the old value is returned. fn atomic_min_max_scalar( &mut self, - place: &MPlaceTy<'tcx, Tag>, - rhs: ImmTy<'tcx, Tag>, + place: &MPlaceTy<'tcx, Provenance>, + rhs: ImmTy<'tcx, Provenance>, min: bool, atomic: AtomicRwOrd, - ) -> InterpResult<'tcx, ImmTy<'tcx, Tag>> { + ) -> InterpResult<'tcx, ImmTy<'tcx, Provenance>> { let this = self.eval_context_mut(); this.validate_overlapping_atomic(place)?; @@ -595,13 +595,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { /// identical. fn atomic_compare_exchange_scalar( &mut self, - place: &MPlaceTy<'tcx, Tag>, - expect_old: &ImmTy<'tcx, Tag>, - new: ScalarMaybeUninit, + place: &MPlaceTy<'tcx, Provenance>, + expect_old: &ImmTy<'tcx, Provenance>, + new: ScalarMaybeUninit, success: AtomicRwOrd, fail: AtomicReadOrd, can_fail_spuriously: bool, - ) -> InterpResult<'tcx, Immediate> { + ) -> InterpResult<'tcx, Immediate> { use rand::Rng as _; let this = self.eval_context_mut(); @@ -651,7 +651,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { /// associated memory-place and on the current thread. fn validate_atomic_load( &self, - place: &MPlaceTy<'tcx, Tag>, + place: &MPlaceTy<'tcx, Provenance>, atomic: AtomicReadOrd, ) -> InterpResult<'tcx> { let this = self.eval_context_ref(); @@ -674,7 +674,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { /// associated memory-place and on the current thread. fn validate_atomic_store( &mut self, - place: &MPlaceTy<'tcx, Tag>, + place: &MPlaceTy<'tcx, Provenance>, atomic: AtomicWriteOrd, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); @@ -697,7 +697,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { /// at the associated memory place and on the current thread. fn validate_atomic_rmw( &mut self, - place: &MPlaceTy<'tcx, Tag>, + place: &MPlaceTy<'tcx, Provenance>, atomic: AtomicRwOrd, ) -> InterpResult<'tcx> { use AtomicRwOrd::*; @@ -1047,7 +1047,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { /// Generic atomic operation implementation fn validate_atomic_op( &self, - place: &MPlaceTy<'tcx, Tag>, + place: &MPlaceTy<'tcx, Provenance>, atomic: A, description: &str, mut op: impl FnMut( diff --git a/src/concurrency/weak_memory.rs b/src/concurrency/weak_memory.rs index f7cc9c4732ace..137a9f43d4eea 100644 --- a/src/concurrency/weak_memory.rs +++ b/src/concurrency/weak_memory.rs @@ -83,7 +83,8 @@ use rustc_const_eval::interpret::{ use rustc_data_structures::fx::FxHashMap; use crate::{ - AtomicReadOrd, AtomicRwOrd, AtomicWriteOrd, Tag, ThreadManager, VClock, VTimestamp, VectorIdx, + AtomicReadOrd, AtomicRwOrd, AtomicWriteOrd, Provenance, ThreadManager, VClock, VTimestamp, + VectorIdx, }; use super::{ @@ -127,7 +128,7 @@ struct StoreElement { // FIXME: this means the store is either fully initialized or fully uninitialized; // we will have to change this if we want to support atomics on // partially initialized data. - val: ScalarMaybeUninit, + val: ScalarMaybeUninit, /// Timestamp of first loads from this store element by each thread /// Behind a RefCell to keep load op take &self @@ -174,7 +175,7 @@ impl StoreBufferAlloc { fn get_or_create_store_buffer<'tcx>( &self, range: AllocRange, - init: ScalarMaybeUninit, + init: ScalarMaybeUninit, ) -> InterpResult<'tcx, Ref<'_, StoreBuffer>> { let access_type = self.store_buffers.borrow().access_type(range); let pos = match access_type { @@ -199,7 +200,7 @@ impl StoreBufferAlloc { fn get_or_create_store_buffer_mut<'tcx>( &mut self, range: AllocRange, - init: ScalarMaybeUninit, + init: ScalarMaybeUninit, ) -> InterpResult<'tcx, &mut StoreBuffer> { let buffers = self.store_buffers.get_mut(); let access_type = buffers.access_type(range); @@ -220,7 +221,7 @@ impl StoreBufferAlloc { } impl<'mir, 'tcx: 'mir> StoreBuffer { - fn new(init: ScalarMaybeUninit) -> Self { + fn new(init: ScalarMaybeUninit) -> Self { let mut buffer = VecDeque::new(); buffer.reserve(STORE_BUFFER_LIMIT); let mut ret = Self { buffer }; @@ -253,7 +254,7 @@ impl<'mir, 'tcx: 'mir> StoreBuffer { is_seqcst: bool, rng: &mut (impl rand::Rng + ?Sized), validate: impl FnOnce() -> InterpResult<'tcx>, - ) -> InterpResult<'tcx, ScalarMaybeUninit> { + ) -> InterpResult<'tcx, ScalarMaybeUninit> { // Having a live borrow to store_buffer while calling validate_atomic_load is fine // because the race detector doesn't touch store_buffer @@ -278,7 +279,7 @@ impl<'mir, 'tcx: 'mir> StoreBuffer { fn buffered_write( &mut self, - val: ScalarMaybeUninit, + val: ScalarMaybeUninit, global: &DataRaceState, thread_mgr: &ThreadManager<'_, '_>, is_seqcst: bool, @@ -366,7 +367,7 @@ impl<'mir, 'tcx: 'mir> StoreBuffer { /// ATOMIC STORE IMPL in the paper (except we don't need the location's vector clock) fn store_impl( &mut self, - val: ScalarMaybeUninit, + val: ScalarMaybeUninit, index: VectorIdx, thread_clock: &VClock, is_seqcst: bool, @@ -408,7 +409,11 @@ impl StoreElement { /// buffer regardless of subsequent loads by the same thread; if the earliest load of another /// thread doesn't happen before the current one, then no subsequent load by the other thread /// can happen before the current one. - fn load_impl(&self, index: VectorIdx, clocks: &ThreadClockSet) -> ScalarMaybeUninit { + fn load_impl( + &self, + index: VectorIdx, + clocks: &ThreadClockSet, + ) -> ScalarMaybeUninit { let _ = self.loads.borrow_mut().try_insert(index, clocks.clock[index]); self.val } @@ -421,7 +426,10 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>: // If weak memory emulation is enabled, check if this atomic op imperfectly overlaps with a previous // atomic read or write. If it does, then we require it to be ordered (non-racy) with all previous atomic // accesses on all the bytes in range - fn validate_overlapping_atomic(&self, place: &MPlaceTy<'tcx, Tag>) -> InterpResult<'tcx> { + fn validate_overlapping_atomic( + &self, + place: &MPlaceTy<'tcx, Provenance>, + ) -> InterpResult<'tcx> { let this = self.eval_context_ref(); let (alloc_id, base_offset, ..) = this.ptr_get_alloc_id(place.ptr)?; if let crate::AllocExtra { @@ -448,10 +456,10 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>: fn buffered_atomic_rmw( &mut self, - new_val: ScalarMaybeUninit, - place: &MPlaceTy<'tcx, Tag>, + new_val: ScalarMaybeUninit, + place: &MPlaceTy<'tcx, Provenance>, atomic: AtomicRwOrd, - init: ScalarMaybeUninit, + init: ScalarMaybeUninit, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let (alloc_id, base_offset, ..) = this.ptr_get_alloc_id(place.ptr)?; @@ -474,11 +482,11 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>: fn buffered_atomic_read( &self, - place: &MPlaceTy<'tcx, Tag>, + place: &MPlaceTy<'tcx, Provenance>, atomic: AtomicReadOrd, - latest_in_mo: ScalarMaybeUninit, + latest_in_mo: ScalarMaybeUninit, validate: impl FnOnce() -> InterpResult<'tcx>, - ) -> InterpResult<'tcx, ScalarMaybeUninit> { + ) -> InterpResult<'tcx, ScalarMaybeUninit> { let this = self.eval_context_ref(); if let Some(global) = &this.machine.data_race { let (alloc_id, base_offset, ..) = this.ptr_get_alloc_id(place.ptr)?; @@ -510,10 +518,10 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>: fn buffered_atomic_write( &mut self, - val: ScalarMaybeUninit, - dest: &MPlaceTy<'tcx, Tag>, + val: ScalarMaybeUninit, + dest: &MPlaceTy<'tcx, Provenance>, atomic: AtomicWriteOrd, - init: ScalarMaybeUninit, + init: ScalarMaybeUninit, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let (alloc_id, base_offset, ..) = this.ptr_get_alloc_id(dest.ptr)?; @@ -555,9 +563,9 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>: /// to perform load_impl on the latest store element fn perform_read_on_buffered_latest( &self, - place: &MPlaceTy<'tcx, Tag>, + place: &MPlaceTy<'tcx, Provenance>, atomic: AtomicReadOrd, - init: ScalarMaybeUninit, + init: ScalarMaybeUninit, ) -> InterpResult<'tcx> { let this = self.eval_context_ref(); diff --git a/src/diagnostics.rs b/src/diagnostics.rs index 1c6cfa096863f..6a692059be927 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -65,7 +65,7 @@ pub enum NonHaltingDiagnostic { CreatedPointerTag(NonZeroU64, Option<(AllocId, AllocRange)>), /// This `Item` was popped from the borrow stack, either due to an access with the given tag or /// a deallocation when the second argument is `None`. - PoppedPointerTag(Item, Option<(SbTagExtra, AccessKind)>), + PoppedPointerTag(Item, Option<(ProvenanceExtra, AccessKind)>), CreatedCallId(CallId), CreatedAlloc(AllocId, Size, Align, MemoryKind), FreedAlloc(AllocId), diff --git a/src/eval.rs b/src/eval.rs index 996d04a2c57cc..0f354aa549494 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -165,7 +165,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( entry_id: DefId, entry_type: EntryFnType, config: &MiriConfig, -) -> InterpResult<'tcx, (InterpCx<'mir, 'tcx, Evaluator<'mir, 'tcx>>, MPlaceTy<'tcx, Tag>)> { +) -> InterpResult<'tcx, (InterpCx<'mir, 'tcx, Evaluator<'mir, 'tcx>>, MPlaceTy<'tcx, Provenance>)> { let param_env = ty::ParamEnv::reveal_all(); let layout_cx = LayoutCx { tcx, param_env }; let mut ecx = InterpCx::new( @@ -202,7 +202,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( // Third argument (`argv`): created from `config.args`. let argv = { // Put each argument in memory, collect pointers. - let mut argvs = Vec::>::new(); + let mut argvs = Vec::>::new(); for arg in config.args.iter() { // Make space for `0` terminator. let size = u64::try_from(arg.len()).unwrap().checked_add(1).unwrap(); diff --git a/src/helpers.rs b/src/helpers.rs index 190eb2098ad01..01fc8e0df3f0c 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -84,7 +84,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// Evaluates the scalar at the specified path. Returns Some(val) /// if the path could be resolved, and None otherwise - fn eval_path_scalar(&self, path: &[&str]) -> InterpResult<'tcx, Scalar> { + fn eval_path_scalar(&self, path: &[&str]) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_ref(); let instance = this.resolve_path(path); let cid = GlobalId { instance, promoted: None }; @@ -94,7 +94,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } /// Helper function to get a `libc` constant as a `Scalar`. - fn eval_libc(&self, name: &str) -> InterpResult<'tcx, Scalar> { + fn eval_libc(&self, name: &str) -> InterpResult<'tcx, Scalar> { self.eval_path_scalar(&["libc", name]) } @@ -105,7 +105,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } /// Helper function to get a `windows` constant as a `Scalar`. - fn eval_windows(&self, module: &str, name: &str) -> InterpResult<'tcx, Scalar> { + fn eval_windows(&self, module: &str, name: &str) -> InterpResult<'tcx, Scalar> { self.eval_context_ref().eval_path_scalar(&["std", "sys", "windows", module, name]) } @@ -134,9 +134,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// Project to the given *named* field of the mplace (which must be a struct or union type). fn mplace_field_named( &self, - mplace: &MPlaceTy<'tcx, Tag>, + mplace: &MPlaceTy<'tcx, Provenance>, name: &str, - ) -> InterpResult<'tcx, MPlaceTy<'tcx, Tag>> { + ) -> InterpResult<'tcx, MPlaceTy<'tcx, Provenance>> { let this = self.eval_context_ref(); let adt = mplace.layout.ty.ty_adt_def().unwrap(); for (idx, field) in adt.non_enum_variant().fields.iter().enumerate() { @@ -150,7 +150,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// Write an int of the appropriate size to `dest`. The target type may be signed or unsigned, /// we try to do the right thing anyway. `i128` can fit all integer types except for `u128` so /// this method is fine for almost all integer types. - fn write_int(&mut self, i: impl Into, dest: &PlaceTy<'tcx, Tag>) -> InterpResult<'tcx> { + fn write_int( + &mut self, + i: impl Into, + dest: &PlaceTy<'tcx, Provenance>, + ) -> InterpResult<'tcx> { assert!(dest.layout.abi.is_scalar(), "write_int on non-scalar type {}", dest.layout.ty); let val = if dest.layout.abi.is_signed() { Scalar::from_int(i, dest.layout.size) @@ -164,7 +168,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn write_int_fields( &mut self, values: &[i128], - dest: &MPlaceTy<'tcx, Tag>, + dest: &MPlaceTy<'tcx, Provenance>, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); for (idx, &val) in values.iter().enumerate() { @@ -178,7 +182,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn write_int_fields_named( &mut self, values: &[(&str, i128)], - dest: &MPlaceTy<'tcx, Tag>, + dest: &MPlaceTy<'tcx, Provenance>, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); for &(name, val) in values.iter() { @@ -189,24 +193,24 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } /// Write a 0 of the appropriate size to `dest`. - fn write_null(&mut self, dest: &PlaceTy<'tcx, Tag>) -> InterpResult<'tcx> { + fn write_null(&mut self, dest: &PlaceTy<'tcx, Provenance>) -> InterpResult<'tcx> { self.write_int(0, dest) } /// Test if this pointer equals 0. - fn ptr_is_null(&self, ptr: Pointer>) -> InterpResult<'tcx, bool> { + fn ptr_is_null(&self, ptr: Pointer>) -> InterpResult<'tcx, bool> { Ok(ptr.addr().bytes() == 0) } /// Get the `Place` for a local - fn local_place(&mut self, local: mir::Local) -> InterpResult<'tcx, PlaceTy<'tcx, Tag>> { + fn local_place(&mut self, local: mir::Local) -> InterpResult<'tcx, PlaceTy<'tcx, Provenance>> { let this = self.eval_context_mut(); let place = mir::Place { local, projection: List::empty() }; this.eval_place(place) } /// Generate some random bytes, and write them to `dest`. - fn gen_random(&mut self, ptr: Pointer>, len: u64) -> InterpResult<'tcx> { + fn gen_random(&mut self, ptr: Pointer>, len: u64) -> InterpResult<'tcx> { // Some programs pass in a null pointer and a length of 0 // to their platform's random-generation function (e.g. getrandom()) // on Linux. For compatibility with these programs, we don't perform @@ -240,8 +244,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx &mut self, f: ty::Instance<'tcx>, caller_abi: Abi, - args: &[Immediate], - dest: Option<&PlaceTy<'tcx, Tag>>, + args: &[Immediate], + dest: Option<&PlaceTy<'tcx, Provenance>>, stack_pop: StackPopCleanup, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); @@ -285,7 +289,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// The range is relative to `place`. fn visit_freeze_sensitive( &self, - place: &MPlaceTy<'tcx, Tag>, + place: &MPlaceTy<'tcx, Provenance>, size: Size, mut action: impl FnMut(AllocRange, bool) -> InterpResult<'tcx>, ) -> InterpResult<'tcx> { @@ -304,7 +308,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let mut cur_addr = start_addr; // Called when we detected an `UnsafeCell` at the given offset and size. // Calls `action` and advances `cur_ptr`. - let mut unsafe_cell_action = |unsafe_cell_ptr: &Pointer>, + let mut unsafe_cell_action = |unsafe_cell_ptr: &Pointer>, unsafe_cell_size: Size| { // We assume that we are given the fields in increasing offset order, // and nothing else changes. @@ -359,7 +363,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// whether we are inside an `UnsafeCell` or not. struct UnsafeCellVisitor<'ecx, 'mir, 'tcx, F> where - F: FnMut(&MPlaceTy<'tcx, Tag>) -> InterpResult<'tcx>, + F: FnMut(&MPlaceTy<'tcx, Provenance>) -> InterpResult<'tcx>, { ecx: &'ecx MiriEvalContext<'mir, 'tcx>, unsafe_cell_action: F, @@ -368,9 +372,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx impl<'ecx, 'mir, 'tcx: 'mir, F> ValueVisitor<'mir, 'tcx, Evaluator<'mir, 'tcx>> for UnsafeCellVisitor<'ecx, 'mir, 'tcx, F> where - F: FnMut(&MPlaceTy<'tcx, Tag>) -> InterpResult<'tcx>, + F: FnMut(&MPlaceTy<'tcx, Provenance>) -> InterpResult<'tcx>, { - type V = MPlaceTy<'tcx, Tag>; + type V = MPlaceTy<'tcx, Provenance>; #[inline(always)] fn ecx(&self) -> &MiriEvalContext<'mir, 'tcx> { @@ -378,7 +382,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // Hook to detect `UnsafeCell`. - fn visit_value(&mut self, v: &MPlaceTy<'tcx, Tag>) -> InterpResult<'tcx> { + fn visit_value(&mut self, v: &MPlaceTy<'tcx, Provenance>) -> InterpResult<'tcx> { trace!("UnsafeCellVisitor: {:?} {:?}", *v, v.layout.ty); let is_unsafe_cell = match v.layout.ty.kind() { ty::Adt(adt, _) => @@ -421,8 +425,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Make sure we visit aggregrates in increasing offset order. fn visit_aggregate( &mut self, - place: &MPlaceTy<'tcx, Tag>, - fields: impl Iterator>>, + place: &MPlaceTy<'tcx, Provenance>, + fields: impl Iterator>>, ) -> InterpResult<'tcx> { match place.layout.fields { FieldsShape::Array { .. } => { @@ -432,8 +436,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } FieldsShape::Arbitrary { .. } => { // Gather the subplaces and sort them before visiting. - let mut places = - fields.collect::>>>()?; + let mut places = fields + .collect::>>>()?; // we just compare offsets, the abs. value never matters places.sort_by_key(|place| place.ptr.addr()); self.walk_aggregate(place, places.into_iter().map(Ok)) @@ -447,7 +451,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn visit_union( &mut self, - _v: &MPlaceTy<'tcx, Tag>, + _v: &MPlaceTy<'tcx, Provenance>, _fields: NonZeroUsize, ) -> InterpResult<'tcx> { bug!("we should have already handled unions in `visit_value`") @@ -511,7 +515,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// Get last error variable as a place, lazily allocating thread-local storage for it if /// necessary. - fn last_error_place(&mut self) -> InterpResult<'tcx, MPlaceTy<'tcx, Tag>> { + fn last_error_place(&mut self) -> InterpResult<'tcx, MPlaceTy<'tcx, Provenance>> { let this = self.eval_context_mut(); if let Some(errno_place) = this.active_thread_ref().last_error { Ok(errno_place) @@ -526,14 +530,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } /// Sets the last error variable. - fn set_last_error(&mut self, scalar: Scalar) -> InterpResult<'tcx> { + fn set_last_error(&mut self, scalar: Scalar) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let errno_place = this.last_error_place()?; this.write_scalar(scalar, &errno_place.into()) } /// Gets the last error variable. - fn get_last_error(&mut self) -> InterpResult<'tcx, Scalar> { + fn get_last_error(&mut self) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); let errno_place = this.last_error_place()?; this.read_scalar(&errno_place.into())?.check_init() @@ -541,7 +545,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// This function tries to produce the most similar OS error from the `std::io::ErrorKind` /// as a platform-specific errnum. - fn io_error_to_errnum(&self, err_kind: std::io::ErrorKind) -> InterpResult<'tcx, Scalar> { + fn io_error_to_errnum( + &self, + err_kind: std::io::ErrorKind, + ) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_ref(); let target = &this.tcx.sess.target; if target.families.iter().any(|f| f == "unix") { @@ -575,7 +582,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } /// The inverse of `io_error_to_errnum`. - fn errnum_to_io_error(&self, errnum: Scalar) -> InterpResult<'tcx, std::io::ErrorKind> { + fn errnum_to_io_error( + &self, + errnum: Scalar, + ) -> InterpResult<'tcx, std::io::ErrorKind> { let this = self.eval_context_ref(); let target = &this.tcx.sess.target; if target.families.iter().any(|f| f == "unix") { @@ -621,10 +631,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// Calculates the MPlaceTy given the offset and layout of an access on an operand fn deref_operand_and_offset( &self, - op: &OpTy<'tcx, Tag>, + op: &OpTy<'tcx, Provenance>, offset: u64, layout: TyAndLayout<'tcx>, - ) -> InterpResult<'tcx, MPlaceTy<'tcx, Tag>> { + ) -> InterpResult<'tcx, MPlaceTy<'tcx, Provenance>> { let this = self.eval_context_ref(); let op_place = this.deref_operand(op)?; let offset = Size::from_bytes(offset); @@ -637,10 +647,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn read_scalar_at_offset( &self, - op: &OpTy<'tcx, Tag>, + op: &OpTy<'tcx, Provenance>, offset: u64, layout: TyAndLayout<'tcx>, - ) -> InterpResult<'tcx, ScalarMaybeUninit> { + ) -> InterpResult<'tcx, ScalarMaybeUninit> { let this = self.eval_context_ref(); let value_place = this.deref_operand_and_offset(op, offset, layout)?; this.read_scalar(&value_place.into()) @@ -648,9 +658,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn write_scalar_at_offset( &mut self, - op: &OpTy<'tcx, Tag>, + op: &OpTy<'tcx, Provenance>, offset: u64, - value: impl Into>, + value: impl Into>, layout: TyAndLayout<'tcx>, ) -> InterpResult<'tcx, ()> { let this = self.eval_context_mut(); @@ -661,7 +671,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// Parse a `timespec` struct and return it as a `std::time::Duration`. It returns `None` /// if the value in the `timespec` struct is invalid. Some libc functions will return /// `EINVAL` in this case. - fn read_timespec(&mut self, tp: &MPlaceTy<'tcx, Tag>) -> InterpResult<'tcx, Option> { + fn read_timespec( + &mut self, + tp: &MPlaceTy<'tcx, Provenance>, + ) -> InterpResult<'tcx, Option> { let this = self.eval_context_mut(); let seconds_place = this.mplace_field(tp, 0)?; let seconds_scalar = this.read_scalar(&seconds_place.into())?; @@ -683,7 +696,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx }) } - fn read_c_str<'a>(&'a self, ptr: Pointer>) -> InterpResult<'tcx, &'a [u8]> + fn read_c_str<'a>(&'a self, ptr: Pointer>) -> InterpResult<'tcx, &'a [u8]> where 'tcx: 'a, 'mir: 'a, @@ -709,7 +722,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.read_bytes_ptr(ptr, len) } - fn read_wide_str(&self, mut ptr: Pointer>) -> InterpResult<'tcx, Vec> { + fn read_wide_str(&self, mut ptr: Pointer>) -> InterpResult<'tcx, Vec> { let this = self.eval_context_ref(); let size2 = Size::from_bytes(2); let align2 = Align::from_bytes(2).unwrap(); @@ -801,17 +814,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx abi: Abi, exp_abi: Abi, link_name: Symbol, - args: &'a [OpTy<'tcx, Tag>], - ) -> InterpResult<'tcx, &'a [OpTy<'tcx, Tag>; N]> + args: &'a [OpTy<'tcx, Provenance>], + ) -> InterpResult<'tcx, &'a [OpTy<'tcx, Provenance>; N]> where - &'a [OpTy<'tcx, Tag>; N]: TryFrom<&'a [OpTy<'tcx, Tag>]>, + &'a [OpTy<'tcx, Provenance>; N]: TryFrom<&'a [OpTy<'tcx, Provenance>]>, { self.check_abi_and_shim_symbol_clash(abi, exp_abi, link_name)?; check_arg_count(args) } /// Mark a machine allocation that was just created as immutable. - fn mark_immutable(&mut self, mplace: &MemPlace) { + fn mark_immutable(&mut self, mplace: &MemPlace) { let this = self.eval_context_mut(); // This got just allocated, so there definitely is a pointer here. let provenance = mplace.ptr.into_pointer_or_addr().unwrap().provenance; @@ -866,10 +879,10 @@ impl<'a, 'mir, 'tcx> CurrentSpan<'a, 'mir, 'tcx> { /// Check that the number of args is what we expect. pub fn check_arg_count<'a, 'tcx, const N: usize>( - args: &'a [OpTy<'tcx, Tag>], -) -> InterpResult<'tcx, &'a [OpTy<'tcx, Tag>; N]> + args: &'a [OpTy<'tcx, Provenance>], +) -> InterpResult<'tcx, &'a [OpTy<'tcx, Provenance>; N]> where - &'a [OpTy<'tcx, Tag>; N]: TryFrom<&'a [OpTy<'tcx, Tag>]>, + &'a [OpTy<'tcx, Provenance>; N]: TryFrom<&'a [OpTy<'tcx, Provenance>]>, { if let Ok(ops) = args.try_into() { return Ok(ops); diff --git a/src/intptrcast.rs b/src/intptrcast.rs index 0ffa067059f52..4272966ae6cc3 100644 --- a/src/intptrcast.rs +++ b/src/intptrcast.rs @@ -109,7 +109,7 @@ impl<'mir, 'tcx> GlobalStateInner { pub fn ptr_from_addr_transmute( _ecx: &MiriEvalContext<'mir, 'tcx>, addr: u64, - ) -> Pointer> { + ) -> Pointer> { trace!("Transmuting {:#x} to a pointer", addr); // We consider transmuted pointers to be "invalid" (`None` provenance). @@ -119,7 +119,7 @@ impl<'mir, 'tcx> GlobalStateInner { pub fn ptr_from_addr_cast( ecx: &MiriEvalContext<'mir, 'tcx>, addr: u64, - ) -> InterpResult<'tcx, Pointer>> { + ) -> InterpResult<'tcx, Pointer>> { trace!("Casting {:#x} to a pointer", addr); let global_state = ecx.machine.intptrcast.borrow(); @@ -146,7 +146,7 @@ impl<'mir, 'tcx> GlobalStateInner { } // This is how wildcard pointers are born. - Ok(Pointer::new(Some(Tag::Wildcard), Size::from_bytes(addr))) + Ok(Pointer::new(Some(Provenance::Wildcard), Size::from_bytes(addr))) } fn alloc_base_addr(ecx: &MiriEvalContext<'mir, 'tcx>, alloc_id: AllocId) -> u64 { @@ -208,11 +208,11 @@ impl<'mir, 'tcx> GlobalStateInner { /// access is going. pub fn abs_ptr_to_rel( ecx: &MiriEvalContext<'mir, 'tcx>, - ptr: Pointer, + ptr: Pointer, ) -> Option<(AllocId, Size)> { let (tag, addr) = ptr.into_parts(); // addr is absolute (Tag provenance) - let alloc_id = if let Tag::Concrete { alloc_id, .. } = tag { + let alloc_id = if let Provenance::Concrete { alloc_id, .. } = tag { alloc_id } else { // A wildcard pointer. diff --git a/src/lib.rs b/src/lib.rs index b3d408a6dc072..35351664caf4e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -57,7 +57,7 @@ mod vector_clock; // Make all those symbols available in the same place as our own. pub use rustc_const_eval::interpret::*; // Resolve ambiguity. -pub use rustc_const_eval::interpret::{self, AllocMap, PlaceTy}; +pub use rustc_const_eval::interpret::{self, AllocMap, PlaceTy, Provenance as _}; pub use crate::shims::dlsym::{Dlsym, EvalContextExt as _}; pub use crate::shims::env::{EnvVars, EvalContextExt as _}; @@ -83,15 +83,14 @@ pub use crate::eval::{ pub use crate::helpers::{CurrentSpan, EvalContextExt as HelpersEvalContextExt}; pub use crate::intptrcast::ProvenanceMode; pub use crate::machine::{ - AllocExtra, Evaluator, FrameData, MiriEvalContext, MiriEvalContextExt, MiriMemoryKind, Tag, - NUM_CPUS, PAGE_SIZE, STACK_ADDR, STACK_SIZE, + AllocExtra, Evaluator, FrameData, MiriEvalContext, MiriEvalContextExt, MiriMemoryKind, + Provenance, ProvenanceExtra, NUM_CPUS, PAGE_SIZE, STACK_ADDR, STACK_SIZE, }; pub use crate::mono_hash_map::MonoHashMap; pub use crate::operator::EvalContextExt as OperatorEvalContextExt; pub use crate::range_map::RangeMap; pub use crate::stacked_borrows::{ - CallId, EvalContextExt as StackedBorEvalContextExt, Item, Permission, SbTag, SbTagExtra, Stack, - Stacks, + CallId, EvalContextExt as StackedBorEvalContextExt, Item, Permission, SbTag, Stack, Stacks, }; pub use crate::sync::{CondvarId, EvalContextExt as SyncEvalContextExt, MutexId, RwLockId}; pub use crate::thread::{ diff --git a/src/machine.rs b/src/machine.rs index 00d41cfb70a38..1adfb83778116 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -126,9 +126,9 @@ impl fmt::Display for MiriMemoryKind { } } -/// Pointer provenance (tag). +/// Pointer provenance. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub enum Tag { +pub enum Provenance { Concrete { alloc_id: AllocId, /// Stacked Borrows tag. @@ -137,27 +137,34 @@ pub enum Tag { Wildcard, } +/// The "extra" information a pointer has over a regular AllocId. +#[derive(Copy, Clone)] +pub enum ProvenanceExtra { + Concrete(SbTag), + Wildcard, +} + #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] -static_assert_size!(Pointer, 24); +static_assert_size!(Pointer, 24); // FIXME: this would with in 24bytes but layout optimizations are not smart enough // #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] -//static_assert_size!(Pointer>, 24); +//static_assert_size!(Pointer>, 24); #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] -static_assert_size!(ScalarMaybeUninit, 32); +static_assert_size!(ScalarMaybeUninit, 32); -impl Provenance for Tag { - /// We use absolute addresses in the `offset` of a `Pointer`. +impl interpret::Provenance for Provenance { + /// We use absolute addresses in the `offset` of a `Pointer`. const OFFSET_IS_ADDR: bool = true; /// We cannot err on partial overwrites, it happens too often in practice (due to unions). const ERR_ON_PARTIAL_PTR_OVERWRITE: bool = false; fn fmt(ptr: &Pointer, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let (tag, addr) = ptr.into_parts(); // address is absolute + let (prov, addr) = ptr.into_parts(); // address is absolute write!(f, "{:#x}", addr.bytes())?; - match tag { - Tag::Concrete { alloc_id, sb } => { + match prov { + Provenance::Concrete { alloc_id, sb } => { // Forward `alternate` flag to `alloc_id` printing. if f.alternate() { write!(f, "[{:#?}]", alloc_id)?; @@ -167,7 +174,7 @@ impl Provenance for Tag { // Print Stacked Borrows tag. write!(f, "{:?}", sb)?; } - Tag::Wildcard => { + Provenance::Wildcard => { write!(f, "[wildcard]")?; } } @@ -177,8 +184,26 @@ impl Provenance for Tag { fn get_alloc_id(self) -> Option { match self { - Tag::Concrete { alloc_id, .. } => Some(alloc_id), - Tag::Wildcard => None, + Provenance::Concrete { alloc_id, .. } => Some(alloc_id), + Provenance::Wildcard => None, + } + } +} + +impl fmt::Debug for ProvenanceExtra { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + ProvenanceExtra::Concrete(pid) => write!(f, "{pid:?}"), + ProvenanceExtra::Wildcard => write!(f, ""), + } + } +} + +impl ProvenanceExtra { + pub fn and_then(self, f: impl FnOnce(SbTag) -> Option) -> Option { + match self { + ProvenanceExtra::Concrete(pid) => f(pid), + ProvenanceExtra::Wildcard => None, } } } @@ -244,9 +269,9 @@ pub struct Evaluator<'mir, 'tcx> { /// Program arguments (`Option` because we can only initialize them after creating the ecx). /// These are *pointers* to argc/argv because macOS. /// We also need the full command line as one string because of Windows. - pub(crate) argc: Option>, - pub(crate) argv: Option>, - pub(crate) cmd_line: Option>, + pub(crate) argc: Option>, + pub(crate) argv: Option>, + pub(crate) cmd_line: Option>, /// TLS state. pub(crate) tls: TlsData<'tcx>, @@ -302,7 +327,7 @@ pub struct Evaluator<'mir, 'tcx> { pub(crate) local_crates: Vec, /// Mapping extern static names to their base pointer. - extern_statics: FxHashMap>, + extern_statics: FxHashMap>, /// The random number generator used for resolving non-determinism. /// Needs to be queried by ptr_to_int, hence needs interior mutability. @@ -403,7 +428,7 @@ impl<'mir, 'tcx> Evaluator<'mir, 'tcx> { fn add_extern_static( this: &mut MiriEvalContext<'mir, 'tcx>, name: &str, - ptr: Pointer>, + ptr: Pointer>, ) { // This got just allocated, so there definitely is a pointer here. let ptr = ptr.into_pointer_or_addr().unwrap(); @@ -491,11 +516,13 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { type FrameExtra = FrameData<'tcx>; type AllocExtra = AllocExtra; - type PointerTag = Tag; - type TagExtra = SbTagExtra; + type Provenance = Provenance; + type ProvenanceExtra = ProvenanceExtra; - type MemoryMap = - MonoHashMap, Allocation)>; + type MemoryMap = MonoHashMap< + AllocId, + (MemoryKind, Allocation), + >; const GLOBAL_KIND: Option = Some(MiriMemoryKind::Global); @@ -541,8 +568,8 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { ecx: &mut MiriEvalContext<'mir, 'tcx>, instance: ty::Instance<'tcx>, abi: Abi, - args: &[OpTy<'tcx, Tag>], - dest: &PlaceTy<'tcx, Tag>, + args: &[OpTy<'tcx, Provenance>], + dest: &PlaceTy<'tcx, Provenance>, ret: Option, unwind: StackPopUnwind, ) -> InterpResult<'tcx, Option<(&'mir mir::Body<'tcx>, ty::Instance<'tcx>)>> { @@ -554,8 +581,8 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { ecx: &mut MiriEvalContext<'mir, 'tcx>, fn_val: Dlsym, abi: Abi, - args: &[OpTy<'tcx, Tag>], - dest: &PlaceTy<'tcx, Tag>, + args: &[OpTy<'tcx, Provenance>], + dest: &PlaceTy<'tcx, Provenance>, ret: Option, _unwind: StackPopUnwind, ) -> InterpResult<'tcx> { @@ -566,8 +593,8 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { fn call_intrinsic( ecx: &mut MiriEvalContext<'mir, 'tcx>, instance: ty::Instance<'tcx>, - args: &[OpTy<'tcx, Tag>], - dest: &PlaceTy<'tcx, Tag>, + args: &[OpTy<'tcx, Provenance>], + dest: &PlaceTy<'tcx, Provenance>, ret: Option, unwind: StackPopUnwind, ) -> InterpResult<'tcx> { @@ -592,23 +619,23 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { fn binary_ptr_op( ecx: &MiriEvalContext<'mir, 'tcx>, bin_op: mir::BinOp, - left: &ImmTy<'tcx, Tag>, - right: &ImmTy<'tcx, Tag>, - ) -> InterpResult<'tcx, (Scalar, bool, ty::Ty<'tcx>)> { + left: &ImmTy<'tcx, Provenance>, + right: &ImmTy<'tcx, Provenance>, + ) -> InterpResult<'tcx, (Scalar, bool, ty::Ty<'tcx>)> { ecx.binary_ptr_op(bin_op, left, right) } fn thread_local_static_base_pointer( ecx: &mut MiriEvalContext<'mir, 'tcx>, def_id: DefId, - ) -> InterpResult<'tcx, Pointer> { + ) -> InterpResult<'tcx, Pointer> { ecx.get_or_create_thread_local_alloc(def_id) } fn extern_static_base_pointer( ecx: &MiriEvalContext<'mir, 'tcx>, def_id: DefId, - ) -> InterpResult<'tcx, Pointer> { + ) -> InterpResult<'tcx, Pointer> { let link_name = ecx.item_link_name(def_id); if let Some(&ptr) = ecx.machine.extern_statics.get(&link_name) { Ok(ptr) @@ -621,12 +648,12 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { } } - fn init_allocation_extra<'b>( + fn adjust_allocation<'b>( ecx: &MiriEvalContext<'mir, 'tcx>, id: AllocId, alloc: Cow<'b, Allocation>, kind: Option>, - ) -> InterpResult<'tcx, Cow<'b, Allocation>> { + ) -> InterpResult<'tcx, Cow<'b, Allocation>> { let kind = kind.expect("we set our STATIC_KIND so this cannot be None"); if ecx.machine.tracked_alloc_ids.contains(&id) { register_diagnostic(NonHaltingDiagnostic::CreatedAlloc( @@ -664,7 +691,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { } else { None }; - let alloc: Allocation = alloc.convert_tag_add_extra( + let alloc: Allocation = alloc.adjust_from_tcx( &ecx.tcx, AllocExtra { stacked_borrows: stacks.map(RefCell::new), @@ -676,19 +703,19 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { Ok(Cow::Owned(alloc)) } - fn tag_alloc_base_pointer( + fn adjust_alloc_base_pointer( ecx: &MiriEvalContext<'mir, 'tcx>, ptr: Pointer, - ) -> Pointer { + ) -> Pointer { if cfg!(debug_assertions) { // The machine promises to never call us on thread-local or extern statics. let alloc_id = ptr.provenance; match ecx.tcx.get_global_alloc(alloc_id) { Some(GlobalAlloc::Static(def_id)) if ecx.tcx.is_thread_local_static(def_id) => { - panic!("tag_alloc_base_pointer called on thread-local static") + panic!("adjust_alloc_base_pointer called on thread-local static") } Some(GlobalAlloc::Static(def_id)) if ecx.tcx.is_foreign_item(def_id) => { - panic!("tag_alloc_base_pointer called on extern static") + panic!("adjust_alloc_base_pointer called on extern static") } _ => {} } @@ -701,7 +728,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { SbTag::default() }; Pointer::new( - Tag::Concrete { alloc_id: ptr.provenance, sb: sb_tag }, + Provenance::Concrete { alloc_id: ptr.provenance, sb: sb_tag }, Size::from_bytes(absolute_addr), ) } @@ -710,7 +737,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { fn ptr_from_addr_cast( ecx: &MiriEvalContext<'mir, 'tcx>, addr: u64, - ) -> InterpResult<'tcx, Pointer>> { + ) -> InterpResult<'tcx, Pointer>> { intptrcast::GlobalStateInner::ptr_from_addr_cast(ecx, addr) } @@ -718,19 +745,19 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { fn ptr_from_addr_transmute( ecx: &MiriEvalContext<'mir, 'tcx>, addr: u64, - ) -> Pointer> { + ) -> Pointer> { intptrcast::GlobalStateInner::ptr_from_addr_transmute(ecx, addr) } fn expose_ptr( ecx: &mut InterpCx<'mir, 'tcx, Self>, - ptr: Pointer, + ptr: Pointer, ) -> InterpResult<'tcx> { match ptr.provenance { - Tag::Concrete { alloc_id, sb } => { + Provenance::Concrete { alloc_id, sb } => { intptrcast::GlobalStateInner::expose_ptr(ecx, alloc_id, sb); } - Tag::Wildcard => { + Provenance::Wildcard => { // No need to do anything for wildcard pointers as // their provenances have already been previously exposed. } @@ -742,14 +769,14 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { /// or a `None` with an absolute address if that conversion is not possible. fn ptr_get_alloc( ecx: &MiriEvalContext<'mir, 'tcx>, - ptr: Pointer, - ) -> Option<(AllocId, Size, Self::TagExtra)> { + ptr: Pointer, + ) -> Option<(AllocId, Size, Self::ProvenanceExtra)> { let rel = intptrcast::GlobalStateInner::abs_ptr_to_rel(ecx, ptr); rel.map(|(alloc_id, size)| { let sb = match ptr.provenance { - Tag::Concrete { sb, .. } => SbTagExtra::Concrete(sb), - Tag::Wildcard => SbTagExtra::Wildcard, + Provenance::Concrete { sb, .. } => ProvenanceExtra::Concrete(sb), + Provenance::Wildcard => ProvenanceExtra::Wildcard, }; (alloc_id, size, sb) }) @@ -760,7 +787,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { _tcx: TyCtxt<'tcx>, machine: &Self, alloc_extra: &AllocExtra, - (alloc_id, tag): (AllocId, Self::TagExtra), + (alloc_id, prov_extra): (AllocId, Self::ProvenanceExtra), range: AllocRange, ) -> InterpResult<'tcx> { if let Some(data_race) = &alloc_extra.data_race { @@ -774,7 +801,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { if let Some(stacked_borrows) = &alloc_extra.stacked_borrows { stacked_borrows.borrow_mut().memory_read( alloc_id, - tag, + prov_extra, range, machine.stacked_borrows.as_ref().unwrap(), machine.current_span(), @@ -792,7 +819,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { _tcx: TyCtxt<'tcx>, machine: &mut Self, alloc_extra: &mut AllocExtra, - (alloc_id, tag): (AllocId, Self::TagExtra), + (alloc_id, prov_extra): (AllocId, Self::ProvenanceExtra), range: AllocRange, ) -> InterpResult<'tcx> { if let Some(data_race) = &mut alloc_extra.data_race { @@ -806,7 +833,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { if let Some(stacked_borrows) = &mut alloc_extra.stacked_borrows { stacked_borrows.get_mut().memory_written( alloc_id, - tag, + prov_extra, range, machine.stacked_borrows.as_ref().unwrap(), machine.current_span(), @@ -824,7 +851,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { _tcx: TyCtxt<'tcx>, machine: &mut Self, alloc_extra: &mut AllocExtra, - (alloc_id, tag): (AllocId, Self::TagExtra), + (alloc_id, prove_extra): (AllocId, Self::ProvenanceExtra), range: AllocRange, ) -> InterpResult<'tcx> { if machine.tracked_alloc_ids.contains(&alloc_id) { @@ -841,7 +868,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { if let Some(stacked_borrows) = &mut alloc_extra.stacked_borrows { stacked_borrows.get_mut().memory_deallocated( alloc_id, - tag, + prove_extra, range, machine.stacked_borrows.as_ref().unwrap(), &machine.threads, @@ -855,7 +882,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { fn retag( ecx: &mut InterpCx<'mir, 'tcx, Self>, kind: mir::RetagKind, - place: &PlaceTy<'tcx, Tag>, + place: &PlaceTy<'tcx, Provenance>, ) -> InterpResult<'tcx> { if ecx.machine.stacked_borrows.is_some() { ecx.retag(kind, place) } else { Ok(()) } } @@ -863,8 +890,8 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { #[inline(always)] fn init_frame_extra( ecx: &mut InterpCx<'mir, 'tcx, Self>, - frame: Frame<'mir, 'tcx, Tag>, - ) -> InterpResult<'tcx, Frame<'mir, 'tcx, Tag, FrameData<'tcx>>> { + frame: Frame<'mir, 'tcx, Provenance>, + ) -> InterpResult<'tcx, Frame<'mir, 'tcx, Provenance, FrameData<'tcx>>> { // Start recording our event before doing anything else let timing = if let Some(profiler) = ecx.machine.profiler.as_ref() { let fn_name = frame.instance.to_string(); @@ -892,13 +919,13 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { fn stack<'a>( ecx: &'a InterpCx<'mir, 'tcx, Self>, - ) -> &'a [Frame<'mir, 'tcx, Self::PointerTag, Self::FrameExtra>] { + ) -> &'a [Frame<'mir, 'tcx, Self::Provenance, Self::FrameExtra>] { ecx.active_thread_stack() } fn stack_mut<'a>( ecx: &'a mut InterpCx<'mir, 'tcx, Self>, - ) -> &'a mut Vec> { + ) -> &'a mut Vec> { ecx.active_thread_stack_mut() } @@ -925,7 +952,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { #[inline(always)] fn after_stack_pop( ecx: &mut InterpCx<'mir, 'tcx, Self>, - mut frame: Frame<'mir, 'tcx, Tag, FrameData<'tcx>>, + mut frame: Frame<'mir, 'tcx, Provenance, FrameData<'tcx>>, unwinding: bool, ) -> InterpResult<'tcx, StackPopJump> { let timing = frame.extra.timing.take(); diff --git a/src/operator.rs b/src/operator.rs index 2c77830a6d145..758e747d27867 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -9,18 +9,18 @@ pub trait EvalContextExt<'tcx> { fn binary_ptr_op( &self, bin_op: mir::BinOp, - left: &ImmTy<'tcx, Tag>, - right: &ImmTy<'tcx, Tag>, - ) -> InterpResult<'tcx, (Scalar, bool, Ty<'tcx>)>; + left: &ImmTy<'tcx, Provenance>, + right: &ImmTy<'tcx, Provenance>, + ) -> InterpResult<'tcx, (Scalar, bool, Ty<'tcx>)>; } impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { fn binary_ptr_op( &self, bin_op: mir::BinOp, - left: &ImmTy<'tcx, Tag>, - right: &ImmTy<'tcx, Tag>, - ) -> InterpResult<'tcx, (Scalar, bool, Ty<'tcx>)> { + left: &ImmTy<'tcx, Provenance>, + right: &ImmTy<'tcx, Provenance>, + ) -> InterpResult<'tcx, (Scalar, bool, Ty<'tcx>)> { use rustc_middle::mir::BinOp::*; trace!("ptr_op: {:?} {:?} {:?}", *left, bin_op, *right); diff --git a/src/shims/backtrace.rs b/src/shims/backtrace.rs index 5b39f2a48aae9..3c15165d67be4 100644 --- a/src/shims/backtrace.rs +++ b/src/shims/backtrace.rs @@ -11,8 +11,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx &mut self, abi: Abi, link_name: Symbol, - args: &[OpTy<'tcx, Tag>], - dest: &PlaceTy<'tcx, Tag>, + args: &[OpTy<'tcx, Provenance>], + dest: &PlaceTy<'tcx, Provenance>, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let [flags] = this.check_shim(abi, Abi::Rust, link_name, args)?; @@ -31,8 +31,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx &mut self, abi: Abi, link_name: Symbol, - args: &[OpTy<'tcx, Tag>], - dest: &PlaceTy<'tcx, Tag>, + args: &[OpTy<'tcx, Provenance>], + dest: &PlaceTy<'tcx, Provenance>, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let tcx = this.tcx; @@ -117,7 +117,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn resolve_frame_pointer( &mut self, - ptr: &OpTy<'tcx, Tag>, + ptr: &OpTy<'tcx, Provenance>, ) -> InterpResult<'tcx, (Instance<'tcx>, Loc, String, String)> { let this = self.eval_context_mut(); @@ -145,8 +145,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx &mut self, abi: Abi, link_name: Symbol, - args: &[OpTy<'tcx, Tag>], - dest: &PlaceTy<'tcx, Tag>, + args: &[OpTy<'tcx, Provenance>], + dest: &PlaceTy<'tcx, Provenance>, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let [ptr, flags] = this.check_shim(abi, Abi::Rust, link_name, args)?; @@ -228,7 +228,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx &mut self, abi: Abi, link_name: Symbol, - args: &[OpTy<'tcx, Tag>], + args: &[OpTy<'tcx, Provenance>], ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); diff --git a/src/shims/dlsym.rs b/src/shims/dlsym.rs index 499e9f8a201fd..5cb3c99e3d194 100644 --- a/src/shims/dlsym.rs +++ b/src/shims/dlsym.rs @@ -33,8 +33,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx &mut self, dlsym: Dlsym, abi: Abi, - args: &[OpTy<'tcx, Tag>], - dest: &PlaceTy<'tcx, Tag>, + args: &[OpTy<'tcx, Provenance>], + dest: &PlaceTy<'tcx, Provenance>, ret: Option, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); diff --git a/src/shims/env.rs b/src/shims/env.rs index f4aaeea2c122e..f0818e71b6670 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -30,10 +30,10 @@ fn windows_check_buffer_size((success, len): (bool, u64)) -> u32 { pub struct EnvVars<'tcx> { /// Stores pointers to the environment variables. These variables must be stored as /// null-terminated target strings (c_str or wide_str) with the `"{name}={value}"` format. - map: FxHashMap>>, + map: FxHashMap>>, /// Place where the `environ` static is stored. Lazily initialized, but then never changes. - pub(crate) environ: Option>, + pub(crate) environ: Option>, } impl<'tcx> EnvVars<'tcx> { @@ -92,7 +92,7 @@ fn alloc_env_var_as_c_str<'mir, 'tcx>( name: &OsStr, value: &OsStr, ecx: &mut InterpCx<'mir, 'tcx, Evaluator<'mir, 'tcx>>, -) -> InterpResult<'tcx, Pointer>> { +) -> InterpResult<'tcx, Pointer>> { let mut name_osstring = name.to_os_string(); name_osstring.push("="); name_osstring.push(value); @@ -103,7 +103,7 @@ fn alloc_env_var_as_wide_str<'mir, 'tcx>( name: &OsStr, value: &OsStr, ecx: &mut InterpCx<'mir, 'tcx, Evaluator<'mir, 'tcx>>, -) -> InterpResult<'tcx, Pointer>> { +) -> InterpResult<'tcx, Pointer>> { let mut name_osstring = name.to_os_string(); name_osstring.push("="); name_osstring.push(value); @@ -112,7 +112,10 @@ fn alloc_env_var_as_wide_str<'mir, 'tcx>( impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { - fn getenv(&mut self, name_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, Pointer>> { + fn getenv( + &mut self, + name_op: &OpTy<'tcx, Provenance>, + ) -> InterpResult<'tcx, Pointer>> { let this = self.eval_context_mut(); this.assert_target_os_is_unix("getenv"); @@ -133,9 +136,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx #[allow(non_snake_case)] fn GetEnvironmentVariableW( &mut self, - name_op: &OpTy<'tcx, Tag>, // LPCWSTR - buf_op: &OpTy<'tcx, Tag>, // LPWSTR - size_op: &OpTy<'tcx, Tag>, // DWORD + name_op: &OpTy<'tcx, Provenance>, // LPCWSTR + buf_op: &OpTy<'tcx, Provenance>, // LPWSTR + size_op: &OpTy<'tcx, Provenance>, // DWORD ) -> InterpResult<'tcx, u32> { // ^ Returns DWORD (u32 on Windows) @@ -168,7 +171,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } #[allow(non_snake_case)] - fn GetEnvironmentStringsW(&mut self) -> InterpResult<'tcx, Pointer>> { + fn GetEnvironmentStringsW(&mut self) -> InterpResult<'tcx, Pointer>> { let this = self.eval_context_mut(); this.assert_target_os("windows", "GetEnvironmentStringsW"); @@ -191,7 +194,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx #[allow(non_snake_case)] fn FreeEnvironmentStringsW( &mut self, - env_block_op: &OpTy<'tcx, Tag>, + env_block_op: &OpTy<'tcx, Provenance>, ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); this.assert_target_os("windows", "FreeEnvironmentStringsW"); @@ -204,8 +207,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn setenv( &mut self, - name_op: &OpTy<'tcx, Tag>, - value_op: &OpTy<'tcx, Tag>, + name_op: &OpTy<'tcx, Provenance>, + value_op: &OpTy<'tcx, Provenance>, ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); this.assert_target_os_is_unix("setenv"); @@ -239,8 +242,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx #[allow(non_snake_case)] fn SetEnvironmentVariableW( &mut self, - name_op: &OpTy<'tcx, Tag>, // LPCWSTR - value_op: &OpTy<'tcx, Tag>, // LPCWSTR + name_op: &OpTy<'tcx, Provenance>, // LPCWSTR + value_op: &OpTy<'tcx, Provenance>, // LPCWSTR ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); this.assert_target_os("windows", "SetEnvironmentVariableW"); @@ -276,7 +279,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } - fn unsetenv(&mut self, name_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + fn unsetenv(&mut self, name_op: &OpTy<'tcx, Provenance>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); this.assert_target_os_is_unix("unsetenv"); @@ -304,9 +307,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn getcwd( &mut self, - buf_op: &OpTy<'tcx, Tag>, - size_op: &OpTy<'tcx, Tag>, - ) -> InterpResult<'tcx, Pointer>> { + buf_op: &OpTy<'tcx, Provenance>, + size_op: &OpTy<'tcx, Provenance>, + ) -> InterpResult<'tcx, Pointer>> { let this = self.eval_context_mut(); this.assert_target_os_is_unix("getcwd"); @@ -337,8 +340,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx #[allow(non_snake_case)] fn GetCurrentDirectoryW( &mut self, - size_op: &OpTy<'tcx, Tag>, // DWORD - buf_op: &OpTy<'tcx, Tag>, // LPTSTR + size_op: &OpTy<'tcx, Provenance>, // DWORD + buf_op: &OpTy<'tcx, Provenance>, // LPTSTR ) -> InterpResult<'tcx, u32> { let this = self.eval_context_mut(); this.assert_target_os("windows", "GetCurrentDirectoryW"); @@ -361,7 +364,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(0) } - fn chdir(&mut self, path_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + fn chdir(&mut self, path_op: &OpTy<'tcx, Provenance>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); this.assert_target_os_is_unix("chdir"); @@ -386,7 +389,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx #[allow(non_snake_case)] fn SetCurrentDirectoryW( &mut self, - path_op: &OpTy<'tcx, Tag>, // LPCTSTR + path_op: &OpTy<'tcx, Provenance>, // LPCTSTR ) -> InterpResult<'tcx, i32> { // ^ Returns BOOL (i32 on Windows) @@ -428,7 +431,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // Collect all the pointers to each variable in a vector. - let mut vars: Vec>> = + let mut vars: Vec>> = this.machine.env_vars.map.values().copied().collect(); // Add the trailing null pointer. vars.push(Pointer::null()); diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 8d82c912f3803..99f0617162192 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -74,7 +74,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx size: u64, zero_init: bool, kind: MiriMemoryKind, - ) -> InterpResult<'tcx, Pointer>> { + ) -> InterpResult<'tcx, Pointer>> { let this = self.eval_context_mut(); if size == 0 { Ok(Pointer::null()) @@ -89,7 +89,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } - fn free(&mut self, ptr: Pointer>, kind: MiriMemoryKind) -> InterpResult<'tcx> { + fn free( + &mut self, + ptr: Pointer>, + kind: MiriMemoryKind, + ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); if !this.ptr_is_null(ptr)? { this.deallocate_ptr(ptr, None, kind.into())?; @@ -99,10 +103,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn realloc( &mut self, - old_ptr: Pointer>, + old_ptr: Pointer>, new_size: u64, kind: MiriMemoryKind, - ) -> InterpResult<'tcx, Pointer>> { + ) -> InterpResult<'tcx, Pointer>> { let this = self.eval_context_mut(); let new_align = this.min_align(new_size, kind); if this.ptr_is_null(old_ptr)? { @@ -231,8 +235,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx &mut self, def_id: DefId, abi: Abi, - args: &[OpTy<'tcx, Tag>], - dest: &PlaceTy<'tcx, Tag>, + args: &[OpTy<'tcx, Provenance>], + dest: &PlaceTy<'tcx, Provenance>, ret: Option, unwind: StackPopUnwind, ) -> InterpResult<'tcx, Option<(&'mir mir::Body<'tcx>, ty::Instance<'tcx>)>> { @@ -353,8 +357,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx &mut self, link_name: Symbol, abi: Abi, - args: &[OpTy<'tcx, Tag>], - dest: &PlaceTy<'tcx, Tag>, + args: &[OpTy<'tcx, Provenance>], + dest: &PlaceTy<'tcx, Provenance>, ) -> InterpResult<'tcx, EmulateByNameResult<'mir, 'tcx>> { let this = self.eval_context_mut(); diff --git a/src/shims/intrinsics/atomic.rs b/src/shims/intrinsics/atomic.rs index 78e13a498ce1b..8e0bb746e3cd4 100644 --- a/src/shims/intrinsics/atomic.rs +++ b/src/shims/intrinsics/atomic.rs @@ -18,8 +18,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn emulate_atomic_intrinsic( &mut self, intrinsic_name: &str, - args: &[OpTy<'tcx, Tag>], - dest: &PlaceTy<'tcx, Tag>, + args: &[OpTy<'tcx, Provenance>], + dest: &PlaceTy<'tcx, Provenance>, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); @@ -121,8 +121,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn atomic_load( &mut self, - args: &[OpTy<'tcx, Tag>], - dest: &PlaceTy<'tcx, Tag>, + args: &[OpTy<'tcx, Provenance>], + dest: &PlaceTy<'tcx, Provenance>, atomic: AtomicReadOrd, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); @@ -150,7 +150,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn atomic_store( &mut self, - args: &[OpTy<'tcx, Tag>], + args: &[OpTy<'tcx, Provenance>], atomic: AtomicWriteOrd, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); @@ -177,7 +177,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn compiler_fence( &mut self, - args: &[OpTy<'tcx, Tag>], + args: &[OpTy<'tcx, Provenance>], atomic: AtomicFenceOrd, ) -> InterpResult<'tcx> { let [] = check_arg_count(args)?; @@ -188,7 +188,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn atomic_fence( &mut self, - args: &[OpTy<'tcx, Tag>], + args: &[OpTy<'tcx, Provenance>], atomic: AtomicFenceOrd, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); @@ -199,8 +199,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn atomic_op( &mut self, - args: &[OpTy<'tcx, Tag>], - dest: &PlaceTy<'tcx, Tag>, + args: &[OpTy<'tcx, Provenance>], + dest: &PlaceTy<'tcx, Provenance>, atomic_op: AtomicOp, atomic: AtomicRwOrd, ) -> InterpResult<'tcx> { @@ -252,8 +252,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn atomic_exchange( &mut self, - args: &[OpTy<'tcx, Tag>], - dest: &PlaceTy<'tcx, Tag>, + args: &[OpTy<'tcx, Provenance>], + dest: &PlaceTy<'tcx, Provenance>, atomic: AtomicRwOrd, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); @@ -280,8 +280,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn atomic_compare_exchange_impl( &mut self, - args: &[OpTy<'tcx, Tag>], - dest: &PlaceTy<'tcx, Tag>, + args: &[OpTy<'tcx, Provenance>], + dest: &PlaceTy<'tcx, Provenance>, success: AtomicRwOrd, fail: AtomicReadOrd, can_fail_spuriously: bool, @@ -320,8 +320,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn atomic_compare_exchange( &mut self, - args: &[OpTy<'tcx, Tag>], - dest: &PlaceTy<'tcx, Tag>, + args: &[OpTy<'tcx, Provenance>], + dest: &PlaceTy<'tcx, Provenance>, success: AtomicRwOrd, fail: AtomicReadOrd, ) -> InterpResult<'tcx> { @@ -330,8 +330,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn atomic_compare_exchange_weak( &mut self, - args: &[OpTy<'tcx, Tag>], - dest: &PlaceTy<'tcx, Tag>, + args: &[OpTy<'tcx, Provenance>], + dest: &PlaceTy<'tcx, Provenance>, success: AtomicRwOrd, fail: AtomicReadOrd, ) -> InterpResult<'tcx> { diff --git a/src/shims/intrinsics/mod.rs b/src/shims/intrinsics/mod.rs index 97f9a7b93cace..c07ed8b294891 100644 --- a/src/shims/intrinsics/mod.rs +++ b/src/shims/intrinsics/mod.rs @@ -20,8 +20,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn call_intrinsic( &mut self, instance: ty::Instance<'tcx>, - args: &[OpTy<'tcx, Tag>], - dest: &PlaceTy<'tcx, Tag>, + args: &[OpTy<'tcx, Provenance>], + dest: &PlaceTy<'tcx, Provenance>, ret: Option, _unwind: StackPopUnwind, ) -> InterpResult<'tcx> { @@ -58,8 +58,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn emulate_intrinsic_by_name( &mut self, intrinsic_name: &str, - args: &[OpTy<'tcx, Tag>], - dest: &PlaceTy<'tcx, Tag>, + args: &[OpTy<'tcx, Provenance>], + dest: &PlaceTy<'tcx, Provenance>, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); @@ -375,9 +375,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx &self, f: F, dest_ty: ty::Ty<'tcx>, - ) -> InterpResult<'tcx, Scalar> + ) -> InterpResult<'tcx, Scalar> where - F: Float + Into>, + F: Float + Into>, { let this = self.eval_context_ref(); diff --git a/src/shims/intrinsics/simd.rs b/src/shims/intrinsics/simd.rs index fe5250ed08434..96e97d79358bf 100644 --- a/src/shims/intrinsics/simd.rs +++ b/src/shims/intrinsics/simd.rs @@ -12,8 +12,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn emulate_simd_intrinsic( &mut self, intrinsic_name: &str, - args: &[OpTy<'tcx, Tag>], - dest: &PlaceTy<'tcx, Tag>, + args: &[OpTy<'tcx, Provenance>], + dest: &PlaceTy<'tcx, Provenance>, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); match intrinsic_name { @@ -557,13 +557,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } -fn bool_to_simd_element(b: bool, size: Size) -> Scalar { +fn bool_to_simd_element(b: bool, size: Size) -> Scalar { // SIMD uses all-1 as pattern for "true" let val = if b { -1 } else { 0 }; Scalar::from_int(val, size) } -fn simd_element_to_bool(elem: ImmTy<'_, Tag>) -> InterpResult<'_, bool> { +fn simd_element_to_bool(elem: ImmTy<'_, Provenance>) -> InterpResult<'_, bool> { let val = elem.to_scalar()?.to_int(elem.layout.size)?; Ok(match val { 0 => false, @@ -581,9 +581,9 @@ fn simd_bitmask_index(idx: u64, vec_len: u64, endianess: Endian) -> u64 { } fn fmax_op<'tcx>( - left: &ImmTy<'tcx, Tag>, - right: &ImmTy<'tcx, Tag>, -) -> InterpResult<'tcx, Scalar> { + left: &ImmTy<'tcx, Provenance>, + right: &ImmTy<'tcx, Provenance>, +) -> InterpResult<'tcx, Scalar> { assert_eq!(left.layout.ty, right.layout.ty); let ty::Float(float_ty) = left.layout.ty.kind() else { bug!("fmax operand is not a float") @@ -597,9 +597,9 @@ fn fmax_op<'tcx>( } fn fmin_op<'tcx>( - left: &ImmTy<'tcx, Tag>, - right: &ImmTy<'tcx, Tag>, -) -> InterpResult<'tcx, Scalar> { + left: &ImmTy<'tcx, Provenance>, + right: &ImmTy<'tcx, Provenance>, +) -> InterpResult<'tcx, Scalar> { assert_eq!(left.layout.ty, right.layout.ty); let ty::Float(float_ty) = left.layout.ty.kind() else { bug!("fmin operand is not a float") diff --git a/src/shims/mod.rs b/src/shims/mod.rs index 2423ffaf5fe01..f5b4de30a5700 100644 --- a/src/shims/mod.rs +++ b/src/shims/mod.rs @@ -27,8 +27,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx &mut self, instance: ty::Instance<'tcx>, abi: Abi, - args: &[OpTy<'tcx, Tag>], - dest: &PlaceTy<'tcx, Tag>, + args: &[OpTy<'tcx, Provenance>], + dest: &PlaceTy<'tcx, Provenance>, ret: Option, unwind: StackPopUnwind, ) -> InterpResult<'tcx, Option<(&'mir mir::Body<'tcx>, ty::Instance<'tcx>)>> { @@ -62,9 +62,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// the actual MIR of `align_offset`. fn align_offset( &mut self, - ptr_op: &OpTy<'tcx, Tag>, - align_op: &OpTy<'tcx, Tag>, - dest: &PlaceTy<'tcx, Tag>, + ptr_op: &OpTy<'tcx, Provenance>, + align_op: &OpTy<'tcx, Provenance>, + dest: &PlaceTy<'tcx, Provenance>, ret: Option, unwind: StackPopUnwind, ) -> InterpResult<'tcx, bool> { diff --git a/src/shims/os_str.rs b/src/shims/os_str.rs index d6669b21a731a..71824bee346e4 100644 --- a/src/shims/os_str.rs +++ b/src/shims/os_str.rs @@ -52,7 +52,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// the Unix APIs usually handle. fn read_os_str_from_c_str<'a>( &'a self, - ptr: Pointer>, + ptr: Pointer>, ) -> InterpResult<'tcx, &'a OsStr> where 'tcx: 'a, @@ -67,7 +67,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// which is what the Windows APIs usually handle. fn read_os_str_from_wide_str<'a>( &'a self, - ptr: Pointer>, + ptr: Pointer>, ) -> InterpResult<'tcx, OsString> where 'tcx: 'a, @@ -96,7 +96,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn write_os_str_to_c_str( &mut self, os_str: &OsStr, - ptr: Pointer>, + ptr: Pointer>, size: u64, ) -> InterpResult<'tcx, (bool, u64)> { let bytes = os_str_to_bytes(os_str)?; @@ -119,7 +119,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn write_os_str_to_wide_str( &mut self, os_str: &OsStr, - ptr: Pointer>, + ptr: Pointer>, size: u64, ) -> InterpResult<'tcx, (bool, u64)> { #[cfg(windows)] @@ -165,7 +165,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx &mut self, os_str: &OsStr, memkind: MemoryKind, - ) -> InterpResult<'tcx, Pointer>> { + ) -> InterpResult<'tcx, Pointer>> { let size = u64::try_from(os_str.len()).unwrap().checked_add(1).unwrap(); // Make space for `0` terminator. let this = self.eval_context_mut(); @@ -180,7 +180,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx &mut self, os_str: &OsStr, memkind: MemoryKind, - ) -> InterpResult<'tcx, Pointer>> { + ) -> InterpResult<'tcx, Pointer>> { let size = u64::try_from(os_str.len()).unwrap().checked_add(1).unwrap(); // Make space for `0x0000` terminator. let this = self.eval_context_mut(); @@ -193,7 +193,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// Read a null-terminated sequence of bytes, and perform path separator conversion if needed. fn read_path_from_c_str<'a>( &'a self, - ptr: Pointer>, + ptr: Pointer>, ) -> InterpResult<'tcx, Cow<'a, Path>> where 'tcx: 'a, @@ -209,7 +209,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } /// Read a null-terminated sequence of `u16`s, and perform path separator conversion if needed. - fn read_path_from_wide_str(&self, ptr: Pointer>) -> InterpResult<'tcx, PathBuf> { + fn read_path_from_wide_str( + &self, + ptr: Pointer>, + ) -> InterpResult<'tcx, PathBuf> { let this = self.eval_context_ref(); let os_str = this.read_os_str_from_wide_str(ptr)?; @@ -224,7 +227,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn write_path_to_c_str( &mut self, path: &Path, - ptr: Pointer>, + ptr: Pointer>, size: u64, ) -> InterpResult<'tcx, (bool, u64)> { let this = self.eval_context_mut(); @@ -238,7 +241,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn write_path_to_wide_str( &mut self, path: &Path, - ptr: Pointer>, + ptr: Pointer>, size: u64, ) -> InterpResult<'tcx, (bool, u64)> { let this = self.eval_context_mut(); diff --git a/src/shims/panic.rs b/src/shims/panic.rs index 42264f6ff3440..362b929eabfee 100644 --- a/src/shims/panic.rs +++ b/src/shims/panic.rs @@ -26,11 +26,11 @@ use helpers::check_arg_count; #[derive(Debug)] pub struct CatchUnwindData<'tcx> { /// The `catch_fn` callback to call in case of a panic. - catch_fn: Scalar, + catch_fn: Scalar, /// The `data` argument for that callback. - data: Scalar, + data: Scalar, /// The return place from the original call to `try`. - dest: PlaceTy<'tcx, Tag>, + dest: PlaceTy<'tcx, Provenance>, /// The return block from the original call to `try`. ret: mir::BasicBlock, } @@ -43,7 +43,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx &mut self, abi: Abi, link_name: Symbol, - args: &[OpTy<'tcx, Tag>], + args: &[OpTy<'tcx, Provenance>], unwind: StackPopUnwind, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); @@ -65,8 +65,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// Handles the `try` intrinsic, the underlying implementation of `std::panicking::try`. fn handle_try( &mut self, - args: &[OpTy<'tcx, Tag>], - dest: &PlaceTy<'tcx, Tag>, + args: &[OpTy<'tcx, Provenance>], + dest: &PlaceTy<'tcx, Provenance>, ret: mir::BasicBlock, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); diff --git a/src/shims/time.rs b/src/shims/time.rs index 0fd5cebd23451..a2cbd84bc2dbb 100644 --- a/src/shims/time.rs +++ b/src/shims/time.rs @@ -13,8 +13,8 @@ impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mi pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { fn clock_gettime( &mut self, - clk_id_op: &OpTy<'tcx, Tag>, - tp_op: &OpTy<'tcx, Tag>, + clk_id_op: &OpTy<'tcx, Provenance>, + tp_op: &OpTy<'tcx, Provenance>, ) -> InterpResult<'tcx, i32> { // This clock support is deliberately minimal because a lot of clock types have fiddly // properties (is it possible for Miri to be suspended independently of the host?). If you @@ -59,8 +59,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn gettimeofday( &mut self, - tv_op: &OpTy<'tcx, Tag>, - tz_op: &OpTy<'tcx, Tag>, + tv_op: &OpTy<'tcx, Provenance>, + tz_op: &OpTy<'tcx, Provenance>, ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); @@ -85,7 +85,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } #[allow(non_snake_case)] - fn GetSystemTimeAsFileTime(&mut self, LPFILETIME_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx> { + fn GetSystemTimeAsFileTime( + &mut self, + LPFILETIME_op: &OpTy<'tcx, Provenance>, + ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); this.assert_target_os("windows", "GetSystemTimeAsFileTime"); @@ -115,7 +118,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx #[allow(non_snake_case)] fn QueryPerformanceCounter( &mut self, - lpPerformanceCount_op: &OpTy<'tcx, Tag>, + lpPerformanceCount_op: &OpTy<'tcx, Provenance>, ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); @@ -138,7 +141,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx #[allow(non_snake_case)] fn QueryPerformanceFrequency( &mut self, - lpFrequency_op: &OpTy<'tcx, Tag>, + lpFrequency_op: &OpTy<'tcx, Provenance>, ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); @@ -172,7 +175,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx }) } - fn mach_timebase_info(&mut self, info_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + fn mach_timebase_info(&mut self, info_op: &OpTy<'tcx, Provenance>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); this.assert_target_os("macos", "mach_timebase_info"); @@ -190,8 +193,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn nanosleep( &mut self, - req_op: &OpTy<'tcx, Tag>, - _rem: &OpTy<'tcx, Tag>, + req_op: &OpTy<'tcx, Provenance>, + _rem: &OpTy<'tcx, Provenance>, ) -> InterpResult<'tcx, i32> { // Signal handlers are not supported, so rem will never be written to. diff --git a/src/shims/tls.rs b/src/shims/tls.rs index 5a72c872b04d0..13af447f76c67 100644 --- a/src/shims/tls.rs +++ b/src/shims/tls.rs @@ -19,7 +19,7 @@ pub type TlsKey = u128; pub struct TlsEntry<'tcx> { /// The data for this key. None is used to represent NULL. /// (We normalize this early to avoid having to do a NULL-ptr-test each time we access the data.) - data: BTreeMap>, + data: BTreeMap>, dtor: Option>, } @@ -41,7 +41,7 @@ pub struct TlsData<'tcx> { /// A single per thread destructor of the thread local storage (that's how /// things work on macOS) with a data argument. - macos_thread_dtors: BTreeMap, Scalar)>, + macos_thread_dtors: BTreeMap, Scalar)>, /// State for currently running TLS dtors. If this map contains a key for a /// specific thread, it means that we are in the "destruct" phase, during @@ -94,7 +94,7 @@ impl<'tcx> TlsData<'tcx> { key: TlsKey, thread_id: ThreadId, cx: &impl HasDataLayout, - ) -> InterpResult<'tcx, Scalar> { + ) -> InterpResult<'tcx, Scalar> { match self.keys.get(&key) { Some(TlsEntry { data, .. }) => { let value = data.get(&thread_id).copied(); @@ -109,7 +109,7 @@ impl<'tcx> TlsData<'tcx> { &mut self, key: TlsKey, thread_id: ThreadId, - new_data: Scalar, + new_data: Scalar, cx: &impl HasDataLayout, ) -> InterpResult<'tcx> { match self.keys.get_mut(&key) { @@ -140,7 +140,7 @@ impl<'tcx> TlsData<'tcx> { &mut self, thread: ThreadId, dtor: ty::Instance<'tcx>, - data: Scalar, + data: Scalar, ) -> InterpResult<'tcx> { if self.dtors_running.contains_key(&thread) { // UB, according to libstd docs. @@ -179,7 +179,7 @@ impl<'tcx> TlsData<'tcx> { &mut self, key: Option, thread_id: ThreadId, - ) -> Option<(ty::Instance<'tcx>, Scalar, TlsKey)> { + ) -> Option<(ty::Instance<'tcx>, Scalar, TlsKey)> { use std::ops::Bound::*; let thread_local = &mut self.keys; diff --git a/src/shims/unix/dlsym.rs b/src/shims/unix/dlsym.rs index 2c563a9551f24..a806c16e28bbb 100644 --- a/src/shims/unix/dlsym.rs +++ b/src/shims/unix/dlsym.rs @@ -32,8 +32,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx &mut self, dlsym: Dlsym, abi: Abi, - args: &[OpTy<'tcx, Tag>], - dest: &PlaceTy<'tcx, Tag>, + args: &[OpTy<'tcx, Provenance>], + dest: &PlaceTy<'tcx, Provenance>, ret: Option, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); diff --git a/src/shims/unix/foreign_items.rs b/src/shims/unix/foreign_items.rs index cf34b4baec7f7..2a051fb775397 100644 --- a/src/shims/unix/foreign_items.rs +++ b/src/shims/unix/foreign_items.rs @@ -19,8 +19,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx &mut self, link_name: Symbol, abi: Abi, - args: &[OpTy<'tcx, Tag>], - dest: &PlaceTy<'tcx, Tag>, + args: &[OpTy<'tcx, Provenance>], + dest: &PlaceTy<'tcx, Provenance>, ) -> InterpResult<'tcx, EmulateByNameResult<'mir, 'tcx>> { let this = self.eval_context_mut(); diff --git a/src/shims/unix/freebsd/dlsym.rs b/src/shims/unix/freebsd/dlsym.rs index 18347d274e93c..74c322c666d48 100644 --- a/src/shims/unix/freebsd/dlsym.rs +++ b/src/shims/unix/freebsd/dlsym.rs @@ -19,8 +19,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn call_dlsym( &mut self, dlsym: Dlsym, - _args: &[OpTy<'tcx, Tag>], - _dest: &PlaceTy<'tcx, Tag>, + _args: &[OpTy<'tcx, Provenance>], + _dest: &PlaceTy<'tcx, Provenance>, ret: Option, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); diff --git a/src/shims/unix/freebsd/foreign_items.rs b/src/shims/unix/freebsd/foreign_items.rs index 2350e5a12c11d..658711526d00c 100644 --- a/src/shims/unix/freebsd/foreign_items.rs +++ b/src/shims/unix/freebsd/foreign_items.rs @@ -11,8 +11,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx &mut self, link_name: Symbol, abi: Abi, - args: &[OpTy<'tcx, Tag>], - dest: &PlaceTy<'tcx, Tag>, + args: &[OpTy<'tcx, Provenance>], + dest: &PlaceTy<'tcx, Provenance>, ) -> InterpResult<'tcx, EmulateByNameResult<'mir, 'tcx>> { let this = self.eval_context_mut(); match link_name.as_str() { diff --git a/src/shims/unix/fs.rs b/src/shims/unix/fs.rs index 1420279247f46..50a2053078f85 100644 --- a/src/shims/unix/fs.rs +++ b/src/shims/unix/fs.rs @@ -386,7 +386,7 @@ trait EvalContextExtPrivate<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, ' fn macos_stat_write_buf( &mut self, metadata: FileMetadata, - buf_op: &OpTy<'tcx, Tag>, + buf_op: &OpTy<'tcx, Provenance>, ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); @@ -493,7 +493,7 @@ pub struct OpenDir { /// The directory reader on the host. read_dir: ReadDir, /// The most recent entry returned by readdir() - entry: Pointer>, + entry: Pointer>, } impl OpenDir { @@ -556,7 +556,7 @@ fn maybe_sync_file( impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { - fn open(&mut self, args: &[OpTy<'tcx, Tag>]) -> InterpResult<'tcx, i32> { + fn open(&mut self, args: &[OpTy<'tcx, Provenance>]) -> InterpResult<'tcx, i32> { if args.len() < 2 { throw_ub_format!( "incorrect number of arguments for `open`: got {}, expected at least 2", @@ -667,7 +667,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.try_unwrap_io_result(fd) } - fn fcntl(&mut self, args: &[OpTy<'tcx, Tag>]) -> InterpResult<'tcx, i32> { + fn fcntl(&mut self, args: &[OpTy<'tcx, Provenance>]) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); if args.len() < 2 { @@ -741,7 +741,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } - fn close(&mut self, fd_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + fn close(&mut self, fd_op: &OpTy<'tcx, Provenance>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); let fd = this.read_scalar(fd_op)?.to_i32()?; @@ -754,7 +754,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } - fn read(&mut self, fd: i32, buf: Pointer>, count: u64) -> InterpResult<'tcx, i64> { + fn read( + &mut self, + fd: i32, + buf: Pointer>, + count: u64, + ) -> InterpResult<'tcx, i64> { let this = self.eval_context_mut(); // Isolation check is done via `FileDescriptor` trait. @@ -802,7 +807,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } - fn write(&mut self, fd: i32, buf: Pointer>, count: u64) -> InterpResult<'tcx, i64> { + fn write( + &mut self, + fd: i32, + buf: Pointer>, + count: u64, + ) -> InterpResult<'tcx, i64> { let this = self.eval_context_mut(); // Isolation check is done via `FileDescriptor` trait. @@ -832,9 +842,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn lseek64( &mut self, - fd_op: &OpTy<'tcx, Tag>, - offset_op: &OpTy<'tcx, Tag>, - whence_op: &OpTy<'tcx, Tag>, + fd_op: &OpTy<'tcx, Provenance>, + offset_op: &OpTy<'tcx, Provenance>, + whence_op: &OpTy<'tcx, Provenance>, ) -> InterpResult<'tcx, i64> { let this = self.eval_context_mut(); @@ -867,7 +877,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } - fn unlink(&mut self, path_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + fn unlink(&mut self, path_op: &OpTy<'tcx, Provenance>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); let path = this.read_path_from_c_str(this.read_pointer(path_op)?)?; @@ -885,8 +895,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn symlink( &mut self, - target_op: &OpTy<'tcx, Tag>, - linkpath_op: &OpTy<'tcx, Tag>, + target_op: &OpTy<'tcx, Provenance>, + linkpath_op: &OpTy<'tcx, Provenance>, ) -> InterpResult<'tcx, i32> { #[cfg(unix)] fn create_link(src: &Path, dst: &Path) -> std::io::Result<()> { @@ -916,8 +926,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn macos_stat( &mut self, - path_op: &OpTy<'tcx, Tag>, - buf_op: &OpTy<'tcx, Tag>, + path_op: &OpTy<'tcx, Provenance>, + buf_op: &OpTy<'tcx, Provenance>, ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); this.assert_target_os("macos", "stat"); @@ -945,8 +955,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // `lstat` is used to get symlink metadata. fn macos_lstat( &mut self, - path_op: &OpTy<'tcx, Tag>, - buf_op: &OpTy<'tcx, Tag>, + path_op: &OpTy<'tcx, Provenance>, + buf_op: &OpTy<'tcx, Provenance>, ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); this.assert_target_os("macos", "lstat"); @@ -972,8 +982,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn macos_fstat( &mut self, - fd_op: &OpTy<'tcx, Tag>, - buf_op: &OpTy<'tcx, Tag>, + fd_op: &OpTy<'tcx, Provenance>, + buf_op: &OpTy<'tcx, Provenance>, ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); @@ -997,11 +1007,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn linux_statx( &mut self, - dirfd_op: &OpTy<'tcx, Tag>, // Should be an `int` - pathname_op: &OpTy<'tcx, Tag>, // Should be a `const char *` - flags_op: &OpTy<'tcx, Tag>, // Should be an `int` - mask_op: &OpTy<'tcx, Tag>, // Should be an `unsigned int` - statxbuf_op: &OpTy<'tcx, Tag>, // Should be a `struct statx *` + dirfd_op: &OpTy<'tcx, Provenance>, // Should be an `int` + pathname_op: &OpTy<'tcx, Provenance>, // Should be a `const char *` + flags_op: &OpTy<'tcx, Provenance>, // Should be an `int` + mask_op: &OpTy<'tcx, Provenance>, // Should be an `unsigned int` + statxbuf_op: &OpTy<'tcx, Provenance>, // Should be a `struct statx *` ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); @@ -1188,8 +1198,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn rename( &mut self, - oldpath_op: &OpTy<'tcx, Tag>, - newpath_op: &OpTy<'tcx, Tag>, + oldpath_op: &OpTy<'tcx, Provenance>, + newpath_op: &OpTy<'tcx, Provenance>, ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); @@ -1219,8 +1229,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn mkdir( &mut self, - path_op: &OpTy<'tcx, Tag>, - mode_op: &OpTy<'tcx, Tag>, + path_op: &OpTy<'tcx, Provenance>, + mode_op: &OpTy<'tcx, Provenance>, ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); @@ -1256,7 +1266,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.try_unwrap_io_result(result) } - fn rmdir(&mut self, path_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + fn rmdir(&mut self, path_op: &OpTy<'tcx, Provenance>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); let path = this.read_path_from_c_str(this.read_pointer(path_op)?)?; @@ -1273,7 +1283,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.try_unwrap_io_result(result) } - fn opendir(&mut self, name_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, Scalar> { + fn opendir( + &mut self, + name_op: &OpTy<'tcx, Provenance>, + ) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); let name = this.read_path_from_c_str(this.read_pointer(name_op)?)?; @@ -1304,7 +1317,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } - fn linux_readdir64(&mut self, dirp_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, Scalar> { + fn linux_readdir64( + &mut self, + dirp_op: &OpTy<'tcx, Provenance>, + ) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); this.assert_target_os("linux", "readdir64"); @@ -1393,9 +1409,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn macos_readdir_r( &mut self, - dirp_op: &OpTy<'tcx, Tag>, - entry_op: &OpTy<'tcx, Tag>, - result_op: &OpTy<'tcx, Tag>, + dirp_op: &OpTy<'tcx, Provenance>, + entry_op: &OpTy<'tcx, Provenance>, + result_op: &OpTy<'tcx, Provenance>, ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); @@ -1490,7 +1506,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } - fn closedir(&mut self, dirp_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + fn closedir(&mut self, dirp_op: &OpTy<'tcx, Provenance>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); let dirp = this.read_scalar(dirp_op)?.to_machine_usize(this)?; @@ -1513,8 +1529,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn ftruncate64( &mut self, - fd_op: &OpTy<'tcx, Tag>, - length_op: &OpTy<'tcx, Tag>, + fd_op: &OpTy<'tcx, Provenance>, + length_op: &OpTy<'tcx, Provenance>, ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); @@ -1551,7 +1567,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } - fn fsync(&mut self, fd_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + fn fsync(&mut self, fd_op: &OpTy<'tcx, Provenance>) -> InterpResult<'tcx, i32> { // On macOS, `fsync` (unlike `fcntl(F_FULLFSYNC)`) does not wait for the // underlying disk to finish writing. In the interest of host compatibility, // we conservatively implement this with `sync_all`, which @@ -1578,7 +1594,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } - fn fdatasync(&mut self, fd_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + fn fdatasync(&mut self, fd_op: &OpTy<'tcx, Provenance>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); let fd = this.read_scalar(fd_op)?.to_i32()?; @@ -1602,10 +1618,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn sync_file_range( &mut self, - fd_op: &OpTy<'tcx, Tag>, - offset_op: &OpTy<'tcx, Tag>, - nbytes_op: &OpTy<'tcx, Tag>, - flags_op: &OpTy<'tcx, Tag>, + fd_op: &OpTy<'tcx, Provenance>, + offset_op: &OpTy<'tcx, Provenance>, + nbytes_op: &OpTy<'tcx, Provenance>, + flags_op: &OpTy<'tcx, Provenance>, ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); @@ -1647,9 +1663,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn readlink( &mut self, - pathname_op: &OpTy<'tcx, Tag>, - buf_op: &OpTy<'tcx, Tag>, - bufsize_op: &OpTy<'tcx, Tag>, + pathname_op: &OpTy<'tcx, Provenance>, + buf_op: &OpTy<'tcx, Provenance>, + bufsize_op: &OpTy<'tcx, Provenance>, ) -> InterpResult<'tcx, i64> { let this = self.eval_context_mut(); @@ -1691,7 +1707,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } #[cfg_attr(not(unix), allow(unused))] - fn isatty(&mut self, miri_fd: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + fn isatty(&mut self, miri_fd: &OpTy<'tcx, Provenance>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); #[cfg(unix)] if matches!(this.machine.isolated_op, IsolatedOp::Allow) { @@ -1740,7 +1756,7 @@ fn extract_sec_and_nsec<'tcx>( /// Stores a file's metadata in order to avoid code duplication in the different metadata related /// shims. struct FileMetadata { - mode: Scalar, + mode: Scalar, size: u64, created: Option<(u64, u32)>, accessed: Option<(u64, u32)>, diff --git a/src/shims/unix/linux/dlsym.rs b/src/shims/unix/linux/dlsym.rs index 01bf17db9f09c..44d51c4a0b3ab 100644 --- a/src/shims/unix/linux/dlsym.rs +++ b/src/shims/unix/linux/dlsym.rs @@ -23,8 +23,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn call_dlsym( &mut self, dlsym: Dlsym, - _args: &[OpTy<'tcx, Tag>], - _dest: &PlaceTy<'tcx, Tag>, + _args: &[OpTy<'tcx, Provenance>], + _dest: &PlaceTy<'tcx, Provenance>, ret: Option, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); diff --git a/src/shims/unix/linux/foreign_items.rs b/src/shims/unix/linux/foreign_items.rs index efd4e2a8c03d3..bae3780b460c7 100644 --- a/src/shims/unix/linux/foreign_items.rs +++ b/src/shims/unix/linux/foreign_items.rs @@ -14,8 +14,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx &mut self, link_name: Symbol, abi: Abi, - args: &[OpTy<'tcx, Tag>], - dest: &PlaceTy<'tcx, Tag>, + args: &[OpTy<'tcx, Provenance>], + dest: &PlaceTy<'tcx, Provenance>, ) -> InterpResult<'tcx, EmulateByNameResult<'mir, 'tcx>> { let this = self.eval_context_mut(); @@ -165,10 +165,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Shims the linux `getrandom` syscall. fn getrandom<'tcx>( this: &mut MiriEvalContext<'_, 'tcx>, - ptr: &OpTy<'tcx, Tag>, - len: &OpTy<'tcx, Tag>, - flags: &OpTy<'tcx, Tag>, - dest: &PlaceTy<'tcx, Tag>, + ptr: &OpTy<'tcx, Provenance>, + len: &OpTy<'tcx, Provenance>, + flags: &OpTy<'tcx, Provenance>, + dest: &PlaceTy<'tcx, Provenance>, ) -> InterpResult<'tcx> { let ptr = this.read_pointer(ptr)?; let len = this.read_scalar(len)?.to_machine_usize(this)?; diff --git a/src/shims/unix/linux/sync.rs b/src/shims/unix/linux/sync.rs index d921b66afbd0d..a11aa8ed849c8 100644 --- a/src/shims/unix/linux/sync.rs +++ b/src/shims/unix/linux/sync.rs @@ -7,8 +7,8 @@ use std::time::{Instant, SystemTime}; /// `args` is the arguments *after* the syscall number. pub fn futex<'tcx>( this: &mut MiriEvalContext<'_, 'tcx>, - args: &[OpTy<'tcx, Tag>], - dest: &PlaceTy<'tcx, Tag>, + args: &[OpTy<'tcx, Provenance>], + dest: &PlaceTy<'tcx, Provenance>, ) -> InterpResult<'tcx> { // The amount of arguments used depends on the type of futex operation. // The full futex syscall takes six arguments (excluding the syscall diff --git a/src/shims/unix/macos/dlsym.rs b/src/shims/unix/macos/dlsym.rs index 2e97b7918e96b..f21f1ae9af6dd 100644 --- a/src/shims/unix/macos/dlsym.rs +++ b/src/shims/unix/macos/dlsym.rs @@ -27,8 +27,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn call_dlsym( &mut self, dlsym: Dlsym, - args: &[OpTy<'tcx, Tag>], - dest: &PlaceTy<'tcx, Tag>, + args: &[OpTy<'tcx, Provenance>], + dest: &PlaceTy<'tcx, Provenance>, ret: Option, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); diff --git a/src/shims/unix/macos/foreign_items.rs b/src/shims/unix/macos/foreign_items.rs index 58dd40cda301d..21c7762c3ca19 100644 --- a/src/shims/unix/macos/foreign_items.rs +++ b/src/shims/unix/macos/foreign_items.rs @@ -12,8 +12,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx &mut self, link_name: Symbol, abi: Abi, - args: &[OpTy<'tcx, Tag>], - dest: &PlaceTy<'tcx, Tag>, + args: &[OpTy<'tcx, Provenance>], + dest: &PlaceTy<'tcx, Provenance>, ) -> InterpResult<'tcx, EmulateByNameResult<'mir, 'tcx>> { let this = self.eval_context_mut(); diff --git a/src/shims/unix/sync.rs b/src/shims/unix/sync.rs index 590bc1bf0056c..18226c2b8cf64 100644 --- a/src/shims/unix/sync.rs +++ b/src/shims/unix/sync.rs @@ -21,14 +21,14 @@ const PTHREAD_MUTEX_NORMAL_FLAG: i32 = 0x8000000; fn is_mutex_kind_default<'mir, 'tcx: 'mir>( ecx: &mut MiriEvalContext<'mir, 'tcx>, - kind: Scalar, + kind: Scalar, ) -> InterpResult<'tcx, bool> { Ok(kind == ecx.eval_libc("PTHREAD_MUTEX_DEFAULT")?) } fn is_mutex_kind_normal<'mir, 'tcx: 'mir>( ecx: &mut MiriEvalContext<'mir, 'tcx>, - kind: Scalar, + kind: Scalar, ) -> InterpResult<'tcx, bool> { let kind = kind.to_i32()?; let mutex_normal_kind = ecx.eval_libc("PTHREAD_MUTEX_NORMAL")?.to_i32()?; @@ -37,15 +37,15 @@ fn is_mutex_kind_normal<'mir, 'tcx: 'mir>( fn mutexattr_get_kind<'mir, 'tcx: 'mir>( ecx: &MiriEvalContext<'mir, 'tcx>, - attr_op: &OpTy<'tcx, Tag>, -) -> InterpResult<'tcx, ScalarMaybeUninit> { + attr_op: &OpTy<'tcx, Provenance>, +) -> InterpResult<'tcx, ScalarMaybeUninit> { ecx.read_scalar_at_offset(attr_op, 0, ecx.machine.layouts.i32) } fn mutexattr_set_kind<'mir, 'tcx: 'mir>( ecx: &mut MiriEvalContext<'mir, 'tcx>, - attr_op: &OpTy<'tcx, Tag>, - kind: impl Into>, + attr_op: &OpTy<'tcx, Provenance>, + kind: impl Into>, ) -> InterpResult<'tcx, ()> { ecx.write_scalar_at_offset(attr_op, 0, kind, layout_of_maybe_uninit(ecx.tcx, ecx.tcx.types.i32)) } @@ -61,8 +61,8 @@ fn mutexattr_set_kind<'mir, 'tcx: 'mir>( fn mutex_get_kind<'mir, 'tcx: 'mir>( ecx: &MiriEvalContext<'mir, 'tcx>, - mutex_op: &OpTy<'tcx, Tag>, -) -> InterpResult<'tcx, ScalarMaybeUninit> { + mutex_op: &OpTy<'tcx, Provenance>, +) -> InterpResult<'tcx, ScalarMaybeUninit> { let offset = if ecx.pointer_size().bytes() == 8 { 16 } else { 12 }; ecx.read_scalar_at_offset_atomic( mutex_op, @@ -74,8 +74,8 @@ fn mutex_get_kind<'mir, 'tcx: 'mir>( fn mutex_set_kind<'mir, 'tcx: 'mir>( ecx: &mut MiriEvalContext<'mir, 'tcx>, - mutex_op: &OpTy<'tcx, Tag>, - kind: impl Into>, + mutex_op: &OpTy<'tcx, Provenance>, + kind: impl Into>, ) -> InterpResult<'tcx, ()> { let offset = if ecx.pointer_size().bytes() == 8 { 16 } else { 12 }; ecx.write_scalar_at_offset_atomic( @@ -89,15 +89,15 @@ fn mutex_set_kind<'mir, 'tcx: 'mir>( fn mutex_get_id<'mir, 'tcx: 'mir>( ecx: &MiriEvalContext<'mir, 'tcx>, - mutex_op: &OpTy<'tcx, Tag>, -) -> InterpResult<'tcx, ScalarMaybeUninit> { + mutex_op: &OpTy<'tcx, Provenance>, +) -> InterpResult<'tcx, ScalarMaybeUninit> { ecx.read_scalar_at_offset_atomic(mutex_op, 4, ecx.machine.layouts.u32, AtomicReadOrd::Relaxed) } fn mutex_set_id<'mir, 'tcx: 'mir>( ecx: &mut MiriEvalContext<'mir, 'tcx>, - mutex_op: &OpTy<'tcx, Tag>, - id: impl Into>, + mutex_op: &OpTy<'tcx, Provenance>, + id: impl Into>, ) -> InterpResult<'tcx, ()> { ecx.write_scalar_at_offset_atomic( mutex_op, @@ -110,7 +110,7 @@ fn mutex_set_id<'mir, 'tcx: 'mir>( fn mutex_get_or_create_id<'mir, 'tcx: 'mir>( ecx: &mut MiriEvalContext<'mir, 'tcx>, - mutex_op: &OpTy<'tcx, Tag>, + mutex_op: &OpTy<'tcx, Provenance>, ) -> InterpResult<'tcx, MutexId> { let value_place = ecx.deref_operand_and_offset(mutex_op, 4, ecx.machine.layouts.u32)?; @@ -145,15 +145,15 @@ fn mutex_get_or_create_id<'mir, 'tcx: 'mir>( fn rwlock_get_id<'mir, 'tcx: 'mir>( ecx: &MiriEvalContext<'mir, 'tcx>, - rwlock_op: &OpTy<'tcx, Tag>, -) -> InterpResult<'tcx, ScalarMaybeUninit> { + rwlock_op: &OpTy<'tcx, Provenance>, +) -> InterpResult<'tcx, ScalarMaybeUninit> { ecx.read_scalar_at_offset_atomic(rwlock_op, 4, ecx.machine.layouts.u32, AtomicReadOrd::Relaxed) } fn rwlock_set_id<'mir, 'tcx: 'mir>( ecx: &mut MiriEvalContext<'mir, 'tcx>, - rwlock_op: &OpTy<'tcx, Tag>, - id: impl Into>, + rwlock_op: &OpTy<'tcx, Provenance>, + id: impl Into>, ) -> InterpResult<'tcx, ()> { ecx.write_scalar_at_offset_atomic( rwlock_op, @@ -166,7 +166,7 @@ fn rwlock_set_id<'mir, 'tcx: 'mir>( fn rwlock_get_or_create_id<'mir, 'tcx: 'mir>( ecx: &mut MiriEvalContext<'mir, 'tcx>, - rwlock_op: &OpTy<'tcx, Tag>, + rwlock_op: &OpTy<'tcx, Provenance>, ) -> InterpResult<'tcx, RwLockId> { let value_place = ecx.deref_operand_and_offset(rwlock_op, 4, ecx.machine.layouts.u32)?; @@ -200,15 +200,15 @@ fn rwlock_get_or_create_id<'mir, 'tcx: 'mir>( fn condattr_get_clock_id<'mir, 'tcx: 'mir>( ecx: &MiriEvalContext<'mir, 'tcx>, - attr_op: &OpTy<'tcx, Tag>, -) -> InterpResult<'tcx, ScalarMaybeUninit> { + attr_op: &OpTy<'tcx, Provenance>, +) -> InterpResult<'tcx, ScalarMaybeUninit> { ecx.read_scalar_at_offset(attr_op, 0, ecx.machine.layouts.i32) } fn condattr_set_clock_id<'mir, 'tcx: 'mir>( ecx: &mut MiriEvalContext<'mir, 'tcx>, - attr_op: &OpTy<'tcx, Tag>, - clock_id: impl Into>, + attr_op: &OpTy<'tcx, Provenance>, + clock_id: impl Into>, ) -> InterpResult<'tcx, ()> { ecx.write_scalar_at_offset( attr_op, @@ -229,15 +229,15 @@ fn condattr_set_clock_id<'mir, 'tcx: 'mir>( fn cond_get_id<'mir, 'tcx: 'mir>( ecx: &MiriEvalContext<'mir, 'tcx>, - cond_op: &OpTy<'tcx, Tag>, -) -> InterpResult<'tcx, ScalarMaybeUninit> { + cond_op: &OpTy<'tcx, Provenance>, +) -> InterpResult<'tcx, ScalarMaybeUninit> { ecx.read_scalar_at_offset_atomic(cond_op, 4, ecx.machine.layouts.u32, AtomicReadOrd::Relaxed) } fn cond_set_id<'mir, 'tcx: 'mir>( ecx: &mut MiriEvalContext<'mir, 'tcx>, - cond_op: &OpTy<'tcx, Tag>, - id: impl Into>, + cond_op: &OpTy<'tcx, Provenance>, + id: impl Into>, ) -> InterpResult<'tcx, ()> { ecx.write_scalar_at_offset_atomic( cond_op, @@ -250,7 +250,7 @@ fn cond_set_id<'mir, 'tcx: 'mir>( fn cond_get_or_create_id<'mir, 'tcx: 'mir>( ecx: &mut MiriEvalContext<'mir, 'tcx>, - cond_op: &OpTy<'tcx, Tag>, + cond_op: &OpTy<'tcx, Provenance>, ) -> InterpResult<'tcx, CondvarId> { let value_place = ecx.deref_operand_and_offset(cond_op, 4, ecx.machine.layouts.u32)?; @@ -278,15 +278,15 @@ fn cond_get_or_create_id<'mir, 'tcx: 'mir>( fn cond_get_clock_id<'mir, 'tcx: 'mir>( ecx: &MiriEvalContext<'mir, 'tcx>, - cond_op: &OpTy<'tcx, Tag>, -) -> InterpResult<'tcx, ScalarMaybeUninit> { + cond_op: &OpTy<'tcx, Provenance>, +) -> InterpResult<'tcx, ScalarMaybeUninit> { ecx.read_scalar_at_offset(cond_op, 8, ecx.machine.layouts.i32) } fn cond_set_clock_id<'mir, 'tcx: 'mir>( ecx: &mut MiriEvalContext<'mir, 'tcx>, - cond_op: &OpTy<'tcx, Tag>, - clock_id: impl Into>, + cond_op: &OpTy<'tcx, Provenance>, + clock_id: impl Into>, ) -> InterpResult<'tcx, ()> { ecx.write_scalar_at_offset( cond_op, @@ -347,7 +347,10 @@ fn release_cond_mutex_and_block<'mir, 'tcx: 'mir>( impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { - fn pthread_mutexattr_init(&mut self, attr_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + fn pthread_mutexattr_init( + &mut self, + attr_op: &OpTy<'tcx, Provenance>, + ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); let default_kind = this.eval_libc("PTHREAD_MUTEX_DEFAULT")?; @@ -358,8 +361,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn pthread_mutexattr_settype( &mut self, - attr_op: &OpTy<'tcx, Tag>, - kind_op: &OpTy<'tcx, Tag>, + attr_op: &OpTy<'tcx, Provenance>, + kind_op: &OpTy<'tcx, Provenance>, ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); @@ -397,7 +400,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(0) } - fn pthread_mutexattr_destroy(&mut self, attr_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + fn pthread_mutexattr_destroy( + &mut self, + attr_op: &OpTy<'tcx, Provenance>, + ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); // Destroying an uninit pthread_mutexattr is UB, so check to make sure it's not uninit. @@ -423,8 +429,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn pthread_mutex_init( &mut self, - mutex_op: &OpTy<'tcx, Tag>, - attr_op: &OpTy<'tcx, Tag>, + mutex_op: &OpTy<'tcx, Provenance>, + attr_op: &OpTy<'tcx, Provenance>, ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); @@ -443,7 +449,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(0) } - fn pthread_mutex_lock(&mut self, mutex_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + fn pthread_mutex_lock(&mut self, mutex_op: &OpTy<'tcx, Provenance>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); let kind = mutex_get_kind(this, mutex_op)?.check_init()?; @@ -480,7 +486,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } - fn pthread_mutex_trylock(&mut self, mutex_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + fn pthread_mutex_trylock( + &mut self, + mutex_op: &OpTy<'tcx, Provenance>, + ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); let kind = mutex_get_kind(this, mutex_op)?.check_init()?; @@ -513,7 +522,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } - fn pthread_mutex_unlock(&mut self, mutex_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + fn pthread_mutex_unlock( + &mut self, + mutex_op: &OpTy<'tcx, Provenance>, + ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); let kind = mutex_get_kind(this, mutex_op)?.check_init()?; @@ -545,7 +557,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } - fn pthread_mutex_destroy(&mut self, mutex_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + fn pthread_mutex_destroy( + &mut self, + mutex_op: &OpTy<'tcx, Provenance>, + ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); let id = mutex_get_or_create_id(this, mutex_op)?; @@ -566,7 +581,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(0) } - fn pthread_rwlock_rdlock(&mut self, rwlock_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + fn pthread_rwlock_rdlock( + &mut self, + rwlock_op: &OpTy<'tcx, Provenance>, + ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); let id = rwlock_get_or_create_id(this, rwlock_op)?; @@ -581,7 +599,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } - fn pthread_rwlock_tryrdlock(&mut self, rwlock_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + fn pthread_rwlock_tryrdlock( + &mut self, + rwlock_op: &OpTy<'tcx, Provenance>, + ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); let id = rwlock_get_or_create_id(this, rwlock_op)?; @@ -595,7 +616,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } - fn pthread_rwlock_wrlock(&mut self, rwlock_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + fn pthread_rwlock_wrlock( + &mut self, + rwlock_op: &OpTy<'tcx, Provenance>, + ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); let id = rwlock_get_or_create_id(this, rwlock_op)?; @@ -622,7 +646,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(0) } - fn pthread_rwlock_trywrlock(&mut self, rwlock_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + fn pthread_rwlock_trywrlock( + &mut self, + rwlock_op: &OpTy<'tcx, Provenance>, + ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); let id = rwlock_get_or_create_id(this, rwlock_op)?; @@ -636,7 +663,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } - fn pthread_rwlock_unlock(&mut self, rwlock_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + fn pthread_rwlock_unlock( + &mut self, + rwlock_op: &OpTy<'tcx, Provenance>, + ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); let id = rwlock_get_or_create_id(this, rwlock_op)?; @@ -652,7 +682,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } - fn pthread_rwlock_destroy(&mut self, rwlock_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + fn pthread_rwlock_destroy( + &mut self, + rwlock_op: &OpTy<'tcx, Provenance>, + ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); let id = rwlock_get_or_create_id(this, rwlock_op)?; @@ -671,7 +704,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(0) } - fn pthread_condattr_init(&mut self, attr_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + fn pthread_condattr_init( + &mut self, + attr_op: &OpTy<'tcx, Provenance>, + ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); // The default value of the clock attribute shall refer to the system @@ -685,8 +721,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn pthread_condattr_setclock( &mut self, - attr_op: &OpTy<'tcx, Tag>, - clock_id_op: &OpTy<'tcx, Tag>, + attr_op: &OpTy<'tcx, Provenance>, + clock_id_op: &OpTy<'tcx, Provenance>, ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); @@ -705,8 +741,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn pthread_condattr_getclock( &mut self, - attr_op: &OpTy<'tcx, Tag>, - clk_id_op: &OpTy<'tcx, Tag>, + attr_op: &OpTy<'tcx, Provenance>, + clk_id_op: &OpTy<'tcx, Provenance>, ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); @@ -716,7 +752,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(0) } - fn pthread_condattr_destroy(&mut self, attr_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + fn pthread_condattr_destroy( + &mut self, + attr_op: &OpTy<'tcx, Provenance>, + ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); // Destroying an uninit pthread_condattr is UB, so check to make sure it's not uninit. @@ -730,8 +769,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn pthread_cond_init( &mut self, - cond_op: &OpTy<'tcx, Tag>, - attr_op: &OpTy<'tcx, Tag>, + cond_op: &OpTy<'tcx, Provenance>, + attr_op: &OpTy<'tcx, Provenance>, ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); @@ -750,7 +789,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(0) } - fn pthread_cond_signal(&mut self, cond_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + fn pthread_cond_signal(&mut self, cond_op: &OpTy<'tcx, Provenance>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); let id = cond_get_or_create_id(this, cond_op)?; if let Some((thread, mutex)) = this.condvar_signal(id) { @@ -760,7 +799,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(0) } - fn pthread_cond_broadcast(&mut self, cond_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + fn pthread_cond_broadcast( + &mut self, + cond_op: &OpTy<'tcx, Provenance>, + ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); let id = cond_get_or_create_id(this, cond_op)?; @@ -773,8 +815,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn pthread_cond_wait( &mut self, - cond_op: &OpTy<'tcx, Tag>, - mutex_op: &OpTy<'tcx, Tag>, + cond_op: &OpTy<'tcx, Provenance>, + mutex_op: &OpTy<'tcx, Provenance>, ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); @@ -790,10 +832,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn pthread_cond_timedwait( &mut self, - cond_op: &OpTy<'tcx, Tag>, - mutex_op: &OpTy<'tcx, Tag>, - abstime_op: &OpTy<'tcx, Tag>, - dest: &PlaceTy<'tcx, Tag>, + cond_op: &OpTy<'tcx, Provenance>, + mutex_op: &OpTy<'tcx, Provenance>, + abstime_op: &OpTy<'tcx, Provenance>, + dest: &PlaceTy<'tcx, Provenance>, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); @@ -852,7 +894,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(()) } - fn pthread_cond_destroy(&mut self, cond_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + fn pthread_cond_destroy( + &mut self, + cond_op: &OpTy<'tcx, Provenance>, + ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); let id = cond_get_or_create_id(this, cond_op)?; diff --git a/src/shims/unix/thread.rs b/src/shims/unix/thread.rs index 8dc5f81354a32..1a8531e880474 100644 --- a/src/shims/unix/thread.rs +++ b/src/shims/unix/thread.rs @@ -6,10 +6,10 @@ impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tc pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { fn pthread_create( &mut self, - thread: &OpTy<'tcx, Tag>, - _attr: &OpTy<'tcx, Tag>, - start_routine: &OpTy<'tcx, Tag>, - arg: &OpTy<'tcx, Tag>, + thread: &OpTy<'tcx, Provenance>, + _attr: &OpTy<'tcx, Provenance>, + start_routine: &OpTy<'tcx, Provenance>, + arg: &OpTy<'tcx, Provenance>, ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); @@ -59,8 +59,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn pthread_join( &mut self, - thread: &OpTy<'tcx, Tag>, - retval: &OpTy<'tcx, Tag>, + thread: &OpTy<'tcx, Provenance>, + retval: &OpTy<'tcx, Provenance>, ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); @@ -75,7 +75,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(0) } - fn pthread_detach(&mut self, thread: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, i32> { + fn pthread_detach(&mut self, thread: &OpTy<'tcx, Provenance>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); let thread_id = this.read_scalar(thread)?.to_machine_usize(this)?; @@ -84,14 +84,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(0) } - fn pthread_self(&mut self, dest: &PlaceTy<'tcx, Tag>) -> InterpResult<'tcx> { + fn pthread_self(&mut self, dest: &PlaceTy<'tcx, Provenance>) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let thread_id = this.get_active_thread(); this.write_scalar(Scalar::from_uint(thread_id.to_u32(), dest.layout.size), dest) } - fn prctl(&mut self, args: &[OpTy<'tcx, Tag>]) -> InterpResult<'tcx, i32> { + fn prctl(&mut self, args: &[OpTy<'tcx, Provenance>]) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); this.assert_target_os("linux", "prctl"); @@ -138,7 +138,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(0) } - fn pthread_setname_np(&mut self, name: Pointer>) -> InterpResult<'tcx> { + fn pthread_setname_np(&mut self, name: Pointer>) -> InterpResult<'tcx> { let this = self.eval_context_mut(); this.assert_target_os("macos", "pthread_setname_np"); diff --git a/src/shims/windows/dlsym.rs b/src/shims/windows/dlsym.rs index 60ef11b796088..ee4f392277721 100644 --- a/src/shims/windows/dlsym.rs +++ b/src/shims/windows/dlsym.rs @@ -31,8 +31,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx &mut self, dlsym: Dlsym, abi: Abi, - args: &[OpTy<'tcx, Tag>], - dest: &PlaceTy<'tcx, Tag>, + args: &[OpTy<'tcx, Provenance>], + dest: &PlaceTy<'tcx, Provenance>, ret: Option, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); diff --git a/src/shims/windows/foreign_items.rs b/src/shims/windows/foreign_items.rs index 65634342417be..3f4b8b14002e7 100644 --- a/src/shims/windows/foreign_items.rs +++ b/src/shims/windows/foreign_items.rs @@ -15,8 +15,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx &mut self, link_name: Symbol, abi: Abi, - args: &[OpTy<'tcx, Tag>], - dest: &PlaceTy<'tcx, Tag>, + args: &[OpTy<'tcx, Provenance>], + dest: &PlaceTy<'tcx, Provenance>, ) -> InterpResult<'tcx, EmulateByNameResult<'mir, 'tcx>> { let this = self.eval_context_mut(); diff --git a/src/shims/windows/sync.rs b/src/shims/windows/sync.rs index 35603f7f38632..878b9b94a639c 100644 --- a/src/shims/windows/sync.rs +++ b/src/shims/windows/sync.rs @@ -5,7 +5,7 @@ use crate::*; fn srwlock_get_or_create_id<'mir, 'tcx: 'mir>( ecx: &mut MiriEvalContext<'mir, 'tcx>, - lock_op: &OpTy<'tcx, Tag>, + lock_op: &OpTy<'tcx, Provenance>, ) -> InterpResult<'tcx, RwLockId> { let value_place = ecx.deref_operand_and_offset(lock_op, 0, ecx.machine.layouts.u32)?; @@ -34,7 +34,7 @@ fn srwlock_get_or_create_id<'mir, 'tcx: 'mir>( impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { #[allow(non_snake_case)] - fn AcquireSRWLockExclusive(&mut self, lock_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx> { + fn AcquireSRWLockExclusive(&mut self, lock_op: &OpTy<'tcx, Provenance>) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let id = srwlock_get_or_create_id(this, lock_op)?; let active_thread = this.get_active_thread(); @@ -56,7 +56,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } #[allow(non_snake_case)] - fn TryAcquireSRWLockExclusive(&mut self, lock_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, u8> { + fn TryAcquireSRWLockExclusive( + &mut self, + lock_op: &OpTy<'tcx, Provenance>, + ) -> InterpResult<'tcx, u8> { let this = self.eval_context_mut(); let id = srwlock_get_or_create_id(this, lock_op)?; let active_thread = this.get_active_thread(); @@ -71,7 +74,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } #[allow(non_snake_case)] - fn ReleaseSRWLockExclusive(&mut self, lock_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx> { + fn ReleaseSRWLockExclusive(&mut self, lock_op: &OpTy<'tcx, Provenance>) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let id = srwlock_get_or_create_id(this, lock_op)?; let active_thread = this.get_active_thread(); @@ -87,7 +90,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } #[allow(non_snake_case)] - fn AcquireSRWLockShared(&mut self, lock_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx> { + fn AcquireSRWLockShared(&mut self, lock_op: &OpTy<'tcx, Provenance>) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let id = srwlock_get_or_create_id(this, lock_op)?; let active_thread = this.get_active_thread(); @@ -102,7 +105,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } #[allow(non_snake_case)] - fn TryAcquireSRWLockShared(&mut self, lock_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx, u8> { + fn TryAcquireSRWLockShared( + &mut self, + lock_op: &OpTy<'tcx, Provenance>, + ) -> InterpResult<'tcx, u8> { let this = self.eval_context_mut(); let id = srwlock_get_or_create_id(this, lock_op)?; let active_thread = this.get_active_thread(); @@ -116,7 +122,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } #[allow(non_snake_case)] - fn ReleaseSRWLockShared(&mut self, lock_op: &OpTy<'tcx, Tag>) -> InterpResult<'tcx> { + fn ReleaseSRWLockShared(&mut self, lock_op: &OpTy<'tcx, Provenance>) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let id = srwlock_get_or_create_id(this, lock_op)?; let active_thread = this.get_active_thread(); diff --git a/src/stacked_borrows/diagnostics.rs b/src/stacked_borrows/diagnostics.rs index 133164f390dfb..6521f0772112d 100644 --- a/src/stacked_borrows/diagnostics.rs +++ b/src/stacked_borrows/diagnostics.rs @@ -5,11 +5,8 @@ use rustc_span::{Span, SpanData}; use rustc_target::abi::Size; use crate::helpers::CurrentSpan; -use crate::stacked_borrows::{err_sb_ub, AccessKind, Permission}; -use crate::Item; -use crate::SbTag; -use crate::SbTagExtra; -use crate::Stack; +use crate::stacked_borrows::{err_sb_ub, AccessKind}; +use crate::*; use rustc_middle::mir::interpret::InterpError; @@ -132,7 +129,7 @@ impl AllocHistory { /// Report a descriptive error when `new` could not be granted from `derived_from`. pub fn grant_error<'tcx>( &self, - derived_from: SbTagExtra, + derived_from: ProvenanceExtra, new: Item, alloc_id: AllocId, alloc_range: AllocRange, @@ -155,7 +152,7 @@ impl AllocHistory { pub fn access_error<'tcx>( &self, access: AccessKind, - tag: SbTagExtra, + tag: ProvenanceExtra, alloc_id: AllocId, alloc_range: AllocRange, error_offset: Size, @@ -181,8 +178,8 @@ fn operation_summary( format!("this error occurs as part of {operation} at {alloc_id:?}{alloc_range:?}") } -fn error_cause(stack: &Stack, tag: SbTagExtra) -> &'static str { - if let SbTagExtra::Concrete(tag) = tag { +fn error_cause(stack: &Stack, prov_extra: ProvenanceExtra) -> &'static str { + if let ProvenanceExtra::Concrete(tag) = prov_extra { if (0..stack.len()) .map(|i| stack.get(i).unwrap()) .any(|item| item.tag() == tag && item.perm() != Permission::Disabled) diff --git a/src/stacked_borrows/mod.rs b/src/stacked_borrows/mod.rs index fb40291302d61..c20927013b0b8 100644 --- a/src/stacked_borrows/mod.rs +++ b/src/stacked_borrows/mod.rs @@ -55,32 +55,6 @@ impl fmt::Debug for SbTag { } } -/// The "extra" information an SB pointer has over a regular AllocId. -/// Newtype for `Option`. -#[derive(Copy, Clone)] -pub enum SbTagExtra { - Concrete(SbTag), - Wildcard, -} - -impl fmt::Debug for SbTagExtra { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - SbTagExtra::Concrete(pid) => write!(f, "{pid:?}"), - SbTagExtra::Wildcard => write!(f, ""), - } - } -} - -impl SbTagExtra { - fn and_then(self, f: impl FnOnce(SbTag) -> Option) -> Option { - match self { - SbTagExtra::Concrete(pid) => f(pid), - SbTagExtra::Wildcard => None, - } - } -} - #[derive(Debug)] pub struct FrameExtra { /// The ID of the call this frame corresponds to. @@ -311,7 +285,7 @@ impl<'tcx> Stack { /// currently checking. fn item_popped( item: &Item, - provoking_access: Option<(SbTagExtra, AllocRange, Size, AccessKind)>, // just for debug printing and error messages + provoking_access: Option<(ProvenanceExtra, AllocRange, Size, AccessKind)>, // just for debug printing and error messages global: &GlobalStateInner, alloc_history: &mut AllocHistory, threads: &ThreadManager<'_, 'tcx>, @@ -322,7 +296,7 @@ impl<'tcx> Stack { #[inline(never)] // cold path fn check_tracked( item: &Item, - provoking_access: &Option<(SbTagExtra, AllocRange, Size, AccessKind)>, + provoking_access: &Option<(ProvenanceExtra, AllocRange, Size, AccessKind)>, global: &GlobalStateInner, ) { if global.tracked_pointer_tags.contains(&item.tag()) { @@ -357,7 +331,7 @@ impl<'tcx> Stack { #[inline(never)] // cold path fn protector_error<'tcx>( item: &Item, - provoking_access: &Option<(SbTagExtra, AllocRange, Size, AccessKind)>, + provoking_access: &Option<(ProvenanceExtra, AllocRange, Size, AccessKind)>, alloc_history: &mut AllocHistory, threads: &ThreadManager<'_, 'tcx>, ) -> InterpErrorInfo<'tcx> { @@ -410,7 +384,7 @@ impl<'tcx> Stack { fn access( &mut self, access: AccessKind, - tag: SbTagExtra, + tag: ProvenanceExtra, (alloc_id, alloc_range, offset): (AllocId, AllocRange, Size), // just for debug printing and error messages global: &mut GlobalStateInner, current_span: &mut CurrentSpan<'_, '_, 'tcx>, @@ -482,7 +456,7 @@ impl<'tcx> Stack { } // If this was an approximate action, we now collapse everything into an unknown. - if granting_idx.is_none() || matches!(tag, SbTagExtra::Wildcard) { + if granting_idx.is_none() || matches!(tag, ProvenanceExtra::Wildcard) { // Compute the upper bound of the items that remain. // (This is why we did all the work above: to reduce the items we have to consider here.) let mut max = NonZeroU64::new(1).unwrap(); @@ -512,7 +486,7 @@ impl<'tcx> Stack { /// active protectors at all because we will remove all items. fn dealloc( &mut self, - tag: SbTagExtra, + tag: ProvenanceExtra, (alloc_id, _alloc_range, _offset): (AllocId, AllocRange, Size), // just for debug printing and error messages global: &GlobalStateInner, alloc_history: &mut AllocHistory, @@ -546,7 +520,7 @@ impl<'tcx> Stack { /// `range` that we are currently checking. fn grant( &mut self, - derived_from: SbTagExtra, + derived_from: ProvenanceExtra, new: Item, (alloc_id, alloc_range, offset): (AllocId, AllocRange, Size), // just for debug printing and error messages global: &mut GlobalStateInner, @@ -575,7 +549,7 @@ impl<'tcx> Stack { "this case only makes sense for stack-like accesses" ); - let (Some(granting_idx), SbTagExtra::Concrete(_)) = (granting_idx, derived_from) else { + let (Some(granting_idx), ProvenanceExtra::Concrete(_)) = (granting_idx, derived_from) else { // The parent is a wildcard pointer or matched the unknown bottom. // This is approximate. Nobody knows what happened, so forget everything. // The new thing is SRW anyway, so we cannot push it "on top of the unkown part" @@ -686,7 +660,7 @@ impl Stacks { pub fn memory_read<'tcx>( &mut self, alloc_id: AllocId, - tag: SbTagExtra, + tag: ProvenanceExtra, range: AllocRange, state: &GlobalState, mut current_span: CurrentSpan<'_, '_, 'tcx>, @@ -717,7 +691,7 @@ impl Stacks { pub fn memory_written<'tcx>( &mut self, alloc_id: AllocId, - tag: SbTagExtra, + tag: ProvenanceExtra, range: AllocRange, state: &GlobalState, mut current_span: CurrentSpan<'_, '_, 'tcx>, @@ -748,7 +722,7 @@ impl Stacks { pub fn memory_deallocated<'tcx>( &mut self, alloc_id: AllocId, - tag: SbTagExtra, + tag: ProvenanceExtra, range: AllocRange, state: &GlobalState, threads: &ThreadManager<'_, 'tcx>, @@ -770,7 +744,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// happened. fn reborrow( &mut self, - place: &MPlaceTy<'tcx, Tag>, + place: &MPlaceTy<'tcx, Provenance>, size: Size, kind: RefKind, new_tag: SbTag, @@ -782,7 +756,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // It is crucial that this gets called on all code paths, to ensure we track tag creation. let log_creation = |this: &MiriEvalContext<'mir, 'tcx>, current_span: &mut CurrentSpan<'_, 'mir, 'tcx>, - loc: Option<(AllocId, Size, SbTagExtra)>| // alloc_id, base_offset, orig_tag + loc: Option<(AllocId, Size, ProvenanceExtra)>| // alloc_id, base_offset, orig_tag -> InterpResult<'tcx> { let global = this.machine.stacked_borrows.as_ref().unwrap().borrow(); if global.tracked_pointer_tags.contains(&new_tag) { @@ -798,7 +772,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx }; // The SB history tracking needs a parent tag, so skip if we come from a wildcard. - let SbTagExtra::Concrete(orig_tag) = orig_tag else { + let ProvenanceExtra::Concrete(orig_tag) = orig_tag else { // FIXME: should we log this? return Ok(()) }; @@ -972,10 +946,10 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// `mutbl` can be `None` to make this a raw pointer. fn retag_reference( &mut self, - val: &ImmTy<'tcx, Tag>, + val: &ImmTy<'tcx, Provenance>, kind: RefKind, protect: bool, - ) -> InterpResult<'tcx, ImmTy<'tcx, Tag>> { + ) -> InterpResult<'tcx, ImmTy<'tcx, Provenance>> { let this = self.eval_context_mut(); // We want a place for where the ptr *points to*, so we get one. let place = this.ref_to_mplace(val)?; @@ -1001,12 +975,12 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Some(alloc_id) => { // If `reborrow` could figure out the AllocId of this ptr, hard-code it into the new one. // Even if we started out with a wildcard, this newly retagged pointer is tied to that allocation. - Tag::Concrete { alloc_id, sb: new_tag } + Provenance::Concrete { alloc_id, sb: new_tag } } None => { // Looks like this has to stay a wildcard pointer. - assert!(matches!(prov, Tag::Wildcard)); - Tag::Wildcard + assert!(matches!(prov, Provenance::Wildcard)); + Provenance::Wildcard } } }) @@ -1019,7 +993,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { - fn retag(&mut self, kind: RetagKind, place: &PlaceTy<'tcx, Tag>) -> InterpResult<'tcx> { + fn retag(&mut self, kind: RetagKind, place: &PlaceTy<'tcx, Provenance>) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let retag_fields = this.machine.stacked_borrows.as_mut().unwrap().get_mut().retag_fields; let mut visitor = RetagVisitor { ecx: this, kind, retag_fields }; @@ -1057,7 +1031,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx #[inline(always)] // yes this helps in our benchmarks fn retag_place( &mut self, - place: &PlaceTy<'tcx, Tag>, + place: &PlaceTy<'tcx, Provenance>, ref_kind: RefKind, protector: bool, ) -> InterpResult<'tcx> { @@ -1070,14 +1044,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx impl<'ecx, 'mir, 'tcx> MutValueVisitor<'mir, 'tcx, Evaluator<'mir, 'tcx>> for RetagVisitor<'ecx, 'mir, 'tcx> { - type V = PlaceTy<'tcx, Tag>; + type V = PlaceTy<'tcx, Provenance>; #[inline(always)] fn ecx(&mut self) -> &mut MiriEvalContext<'mir, 'tcx> { self.ecx } - fn visit_box(&mut self, place: &PlaceTy<'tcx, Tag>) -> InterpResult<'tcx> { + fn visit_box(&mut self, place: &PlaceTy<'tcx, Provenance>) -> InterpResult<'tcx> { // Boxes do not get a protector: protectors reflect that references outlive the call // they were passed in to; that's just not the case for boxes. self.retag_place( @@ -1087,7 +1061,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) } - fn visit_value(&mut self, place: &PlaceTy<'tcx, Tag>) -> InterpResult<'tcx> { + fn visit_value(&mut self, place: &PlaceTy<'tcx, Provenance>) -> InterpResult<'tcx> { if let Some((ref_kind, protector)) = qualify(place.layout.ty, self.kind) { self.retag_place(place, ref_kind, protector)?; } else if matches!(place.layout.ty.kind(), ty::RawPtr(..)) { diff --git a/src/stacked_borrows/stack.rs b/src/stacked_borrows/stack.rs index 32c1be5fb1e2b..c0d4d0d291f30 100644 --- a/src/stacked_borrows/stack.rs +++ b/src/stacked_borrows/stack.rs @@ -1,8 +1,11 @@ -use crate::stacked_borrows::{AccessKind, Item, Permission, SbTag, SbTagExtra}; -use rustc_data_structures::fx::FxHashSet; #[cfg(feature = "stack-cache")] use std::ops::Range; +use rustc_data_structures::fx::FxHashSet; + +use crate::stacked_borrows::{AccessKind, Item, Permission, SbTag}; +use crate::ProvenanceExtra; + /// Exactly what cache size we should use is a difficult tradeoff. There will always be some /// workload which has a `SbTag` working set which exceeds the size of the cache, and ends up /// falling back to linear searches of the borrow stack very often. @@ -126,13 +129,13 @@ impl<'tcx> Stack { pub(super) fn find_granting( &mut self, access: AccessKind, - tag: SbTagExtra, + tag: ProvenanceExtra, exposed_tags: &FxHashSet, ) -> Result, ()> { #[cfg(debug_assertions)] self.verify_cache_consistency(); - let SbTagExtra::Concrete(tag) = tag else { + let ProvenanceExtra::Concrete(tag) = tag else { // Handle the wildcard case. // Go search the stack for an exposed tag. if let Some(idx) = diff --git a/src/sync.rs b/src/sync.rs index 0eebe4f654e4c..5571bbd8f2dc5 100644 --- a/src/sync.rs +++ b/src/sync.rs @@ -42,7 +42,7 @@ macro_rules! declare_id { } impl $name { - pub fn to_u32_scalar<'tcx>(&self) -> Scalar { + pub fn to_u32_scalar<'tcx>(&self) -> Scalar { Scalar::from_u32(self.0.get()) } } diff --git a/src/thread.rs b/src/thread.rs index 96135d093d967..683694f482eaa 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -70,7 +70,7 @@ impl From for ThreadId { } impl ThreadId { - pub fn to_u32_scalar(&self) -> Scalar { + pub fn to_u32_scalar(&self) -> Scalar { Scalar::from_u32(self.0) } } @@ -112,7 +112,7 @@ pub struct Thread<'mir, 'tcx> { thread_name: Option>, /// The virtual call stack. - stack: Vec>>, + stack: Vec>>, /// The join status. join_status: ThreadJoinStatus, @@ -120,10 +120,10 @@ pub struct Thread<'mir, 'tcx> { /// The temporary used for storing the argument of /// the call to `miri_start_panic` (the panic payload) when unwinding. /// This is pointer-sized, and matches the `Payload` type in `src/libpanic_unwind/miri.rs`. - pub(crate) panic_payload: Option>, + pub(crate) panic_payload: Option>, /// Last OS error location in memory. It is a 32-bit integer. - pub(crate) last_error: Option>, + pub(crate) last_error: Option>, } impl<'mir, 'tcx> Thread<'mir, 'tcx> { @@ -227,7 +227,7 @@ pub struct ThreadManager<'mir, 'tcx> { pub(crate) sync: SynchronizationState, /// A mapping from a thread-local static to an allocation id of a thread /// specific allocation. - thread_local_alloc_ids: RefCell>>, + thread_local_alloc_ids: RefCell>>, /// A flag that indicates that we should change the active thread. yield_active_thread: bool, /// Callbacks that are called once the specified time passes. @@ -256,7 +256,7 @@ impl<'mir, 'tcx> Default for ThreadManager<'mir, 'tcx> { impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { /// Check if we have an allocation for the given thread local static for the /// active thread. - fn get_thread_local_alloc_id(&self, def_id: DefId) -> Option> { + fn get_thread_local_alloc_id(&self, def_id: DefId) -> Option> { self.thread_local_alloc_ids.borrow().get(&(def_id, self.active_thread)).cloned() } @@ -264,7 +264,7 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { /// static for the active thread. /// /// Panics if a thread local is initialized twice for the same thread. - fn set_thread_local_alloc(&self, def_id: DefId, ptr: Pointer) { + fn set_thread_local_alloc(&self, def_id: DefId, ptr: Pointer) { self.thread_local_alloc_ids .borrow_mut() .try_insert((def_id, self.active_thread), ptr) @@ -272,16 +272,20 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { } /// Borrow the stack of the active thread. - pub fn active_thread_stack(&self) -> &[Frame<'mir, 'tcx, Tag, FrameData<'tcx>>] { + pub fn active_thread_stack(&self) -> &[Frame<'mir, 'tcx, Provenance, FrameData<'tcx>>] { &self.threads[self.active_thread].stack } /// Mutably borrow the stack of the active thread. - fn active_thread_stack_mut(&mut self) -> &mut Vec>> { + fn active_thread_stack_mut( + &mut self, + ) -> &mut Vec>> { &mut self.threads[self.active_thread].stack } - pub fn all_stacks(&self) -> impl Iterator>]> { + pub fn all_stacks( + &self, + ) -> impl Iterator>]> { self.threads.iter().map(|t| &t.stack[..]) } @@ -468,7 +472,7 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { fn thread_terminated( &mut self, mut data_race: Option<&mut data_race::GlobalState>, - ) -> Vec> { + ) -> Vec> { let mut free_tls_statics = Vec::new(); { let mut thread_local_statics = self.thread_local_alloc_ids.borrow_mut(); @@ -589,7 +593,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn get_or_create_thread_local_alloc( &mut self, def_id: DefId, - ) -> InterpResult<'tcx, Pointer> { + ) -> InterpResult<'tcx, Pointer> { let this = self.eval_context_mut(); let tcx = this.tcx; if let Some(old_alloc) = this.machine.threads.get_thread_local_alloc_id(def_id) { @@ -686,13 +690,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } #[inline] - fn active_thread_stack(&self) -> &[Frame<'mir, 'tcx, Tag, FrameData<'tcx>>] { + fn active_thread_stack(&self) -> &[Frame<'mir, 'tcx, Provenance, FrameData<'tcx>>] { let this = self.eval_context_ref(); this.machine.threads.active_thread_stack() } #[inline] - fn active_thread_stack_mut(&mut self) -> &mut Vec>> { + fn active_thread_stack_mut( + &mut self, + ) -> &mut Vec>> { let this = self.eval_context_mut(); this.machine.threads.active_thread_stack_mut() } From 59f9a918eddcf9d131f55c2ef96d9e82a5706cf0 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 20 Jul 2022 17:40:49 -0400 Subject: [PATCH 3527/3747] handle get_alloc_extra the same throughout Stacked Borrows --- src/intptrcast.rs | 9 +++++-- src/machine.rs | 7 +++--- src/stacked_borrows/mod.rs | 48 ++++++++++++++++++++++++-------------- 3 files changed, 41 insertions(+), 23 deletions(-) diff --git a/src/intptrcast.rs b/src/intptrcast.rs index 4272966ae6cc3..442c201e8ece6 100644 --- a/src/intptrcast.rs +++ b/src/intptrcast.rs @@ -94,16 +94,21 @@ impl<'mir, 'tcx> GlobalStateInner { None } - pub fn expose_ptr(ecx: &mut MiriEvalContext<'mir, 'tcx>, alloc_id: AllocId, sb: SbTag) { + pub fn expose_ptr( + ecx: &mut MiriEvalContext<'mir, 'tcx>, + alloc_id: AllocId, + sb: SbTag, + ) -> InterpResult<'tcx> { let global_state = ecx.machine.intptrcast.get_mut(); // In strict mode, we don't need this, so we can save some cycles by not tracking it. if global_state.provenance_mode != ProvenanceMode::Strict { trace!("Exposing allocation id {alloc_id:?}"); global_state.exposed.insert(alloc_id); if ecx.machine.stacked_borrows.is_some() { - ecx.expose_tag(alloc_id, sb); + ecx.expose_tag(alloc_id, sb)?; } } + Ok(()) } pub fn ptr_from_addr_transmute( diff --git a/src/machine.rs b/src/machine.rs index 1adfb83778116..1ac60e2ad84be 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -754,15 +754,14 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { ptr: Pointer, ) -> InterpResult<'tcx> { match ptr.provenance { - Provenance::Concrete { alloc_id, sb } => { - intptrcast::GlobalStateInner::expose_ptr(ecx, alloc_id, sb); - } + Provenance::Concrete { alloc_id, sb } => + intptrcast::GlobalStateInner::expose_ptr(ecx, alloc_id, sb), Provenance::Wildcard => { // No need to do anything for wildcard pointers as // their provenances have already been previously exposed. + Ok(()) } } - Ok(()) } /// Convert a pointer with provenance into an allocation-offset pair, diff --git a/src/stacked_borrows/mod.rs b/src/stacked_borrows/mod.rs index c20927013b0b8..38a73929a0362 100644 --- a/src/stacked_borrows/mod.rs +++ b/src/stacked_borrows/mod.rs @@ -777,20 +777,31 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx return Ok(()) }; - let extra = this.get_alloc_extra(alloc_id)?; - let mut stacked_borrows = extra - .stacked_borrows - .as_ref() - .expect("we should have Stacked Borrows data") - .borrow_mut(); - stacked_borrows.history.log_creation( - Some(orig_tag), - new_tag, - alloc_range(base_offset, size), - current_span, - ); - if protect { - stacked_borrows.history.log_protector(orig_tag, new_tag, current_span); + let (_size, _align, kind) = this.get_alloc_info(alloc_id); + match kind { + AllocKind::LiveData => { + // This should have alloc_extra data, but `get_alloc_extra` can still fail + // if converting this alloc_id from a global to a local one + // uncovers a non-supported `extern static`. + let extra = this.get_alloc_extra(alloc_id)?; + let mut stacked_borrows = extra + .stacked_borrows + .as_ref() + .expect("we should have Stacked Borrows data") + .borrow_mut(); + stacked_borrows.history.log_creation( + Some(orig_tag), + new_tag, + alloc_range(base_offset, size), + current_span, + ); + if protect { + stacked_borrows.history.log_protector(orig_tag, new_tag, current_span); + } + } + AllocKind::Function | AllocKind::Dead => { + // No stacked borrows on these allocations. + } } Ok(()) }; @@ -1116,7 +1127,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } /// Mark the given tag as exposed. It was found on a pointer with the given AllocId. - fn expose_tag(&mut self, alloc_id: AllocId, tag: SbTag) { + fn expose_tag(&mut self, alloc_id: AllocId, tag: SbTag) -> InterpResult<'tcx> { let this = self.eval_context_mut(); // Function pointers and dead objects don't have an alloc_extra so we ignore them. @@ -1125,8 +1136,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let (_size, _align, kind) = this.get_alloc_info(alloc_id); match kind { AllocKind::LiveData => { - // This should have alloc_extra data. - let alloc_extra = this.get_alloc_extra(alloc_id).unwrap(); + // This should have alloc_extra data, but `get_alloc_extra` can still fail + // if converting this alloc_id from a global to a local one + // uncovers a non-supported `extern static`. + let alloc_extra = this.get_alloc_extra(alloc_id)?; trace!("Stacked Borrows tag {tag:?} exposed in {alloc_id:?}"); alloc_extra.stacked_borrows.as_ref().unwrap().borrow_mut().exposed_tags.insert(tag); } @@ -1134,5 +1147,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // No stacked borrows on these allocations. } } + Ok(()) } } From e649a9acfb64bb3117a1695945f46c92f0a68d1a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 20 Jul 2022 17:40:27 -0400 Subject: [PATCH 3528/3747] check for extern static size mismatches --- src/machine.rs | 29 +++++++++++++++++++--- tests/fail/extern_static_wrong_size.rs | 10 ++++++++ tests/fail/extern_static_wrong_size.stderr | 14 +++++++++++ 3 files changed, 50 insertions(+), 3 deletions(-) create mode 100644 tests/fail/extern_static_wrong_size.rs create mode 100644 tests/fail/extern_static_wrong_size.stderr diff --git a/src/machine.rs b/src/machine.rs index 1ac60e2ad84be..67a6c997e9902 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -638,12 +638,35 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { ) -> InterpResult<'tcx, Pointer> { let link_name = ecx.item_link_name(def_id); if let Some(&ptr) = ecx.machine.extern_statics.get(&link_name) { + // Various parts of the engine rely on `get_alloc_info` for size and alignment + // information. That uses the type information of this static. + // Make sure it matches the Miri allocation for this. + let Provenance::Concrete { alloc_id, .. } = ptr.provenance else { + panic!("extern_statics cannot contain wildcards") + }; + let (shim_size, shim_align, _kind) = ecx.get_alloc_info(alloc_id); + let extern_decl_layout = + ecx.tcx.layout_of(ty::ParamEnv::empty().and(ecx.tcx.type_of(def_id))).unwrap(); + if extern_decl_layout.size != shim_size || extern_decl_layout.align.abi != shim_align { + throw_unsup_format!( + "`extern` static `{name}` from crate `{krate}` has been declared \ + with a size of {decl_size} bytes and alignment of {decl_align} bytes, \ + but Miri emulates it via an extern static shim \ + with a size of {shim_size} bytes and alignment of {shim_align} bytes", + name = ecx.tcx.def_path_str(def_id), + krate = ecx.tcx.crate_name(def_id.krate), + decl_size = extern_decl_layout.size.bytes(), + decl_align = extern_decl_layout.align.abi.bytes(), + shim_size = shim_size.bytes(), + shim_align = shim_align.bytes(), + ) + } Ok(ptr) } else { throw_unsup_format!( - "`extern` static `{}` from crate `{}` is not supported by Miri", - ecx.tcx.def_path_str(def_id), - ecx.tcx.crate_name(def_id.krate), + "`extern` static `{name}` from crate `{krate}` is not supported by Miri", + name = ecx.tcx.def_path_str(def_id), + krate = ecx.tcx.crate_name(def_id.krate), ) } } diff --git a/tests/fail/extern_static_wrong_size.rs b/tests/fail/extern_static_wrong_size.rs new file mode 100644 index 0000000000000..17061f0e5c81c --- /dev/null +++ b/tests/fail/extern_static_wrong_size.rs @@ -0,0 +1,10 @@ +//@ only-target-linux: we need a specific extern supported on this target +//@normalize-stderr-test: "[48] bytes" -> "N bytes" + +extern "C" { + static mut environ: i8; +} + +fn main() { + let _val = unsafe { environ }; //~ ERROR: /has been declared with a size of 1 bytes and alignment of 1 bytes, but Miri emulates it via an extern static shim with a size of [48] bytes and alignment of [48] bytes/ +} diff --git a/tests/fail/extern_static_wrong_size.stderr b/tests/fail/extern_static_wrong_size.stderr new file mode 100644 index 0000000000000..fdeb7bb5f6880 --- /dev/null +++ b/tests/fail/extern_static_wrong_size.stderr @@ -0,0 +1,14 @@ +error: unsupported operation: `extern` static `environ` from crate `extern_static_wrong_size` has been declared with a size of 1 bytes and alignment of 1 bytes, but Miri emulates it via an extern static shim with a size of N bytes and alignment of N bytes + --> $DIR/extern_static_wrong_size.rs:LL:CC + | +LL | let _val = unsafe { environ }; + | ^^^^^^^ `extern` static `environ` from crate `extern_static_wrong_size` has been declared with a size of 1 bytes and alignment of 1 bytes, but Miri emulates it via an extern static shim with a size of N bytes and alignment of N bytes + | + = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support + = note: backtrace: + = note: inside `main` at $DIR/extern_static_wrong_size.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + From 9f99d1068959abdd7a51b0c43bcc54f83bc7ca30 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 20 Jul 2022 18:31:44 -0400 Subject: [PATCH 3529/3747] =?UTF-8?q?some=20stray=20tag=20=E2=86=92=20prov?= =?UTF-8?q?=20renames?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/concurrency/data_race.rs | 2 +- src/shims/backtrace.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/concurrency/data_race.rs b/src/concurrency/data_race.rs index 3f05925d34385..90b38225105df 100644 --- a/src/concurrency/data_race.rs +++ b/src/concurrency/data_race.rs @@ -1061,7 +1061,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { if let Some(data_race) = &this.machine.data_race { if data_race.race_detecting() { let size = place.layout.size; - let (alloc_id, base_offset, _tag) = this.ptr_get_alloc_id(place.ptr)?; + let (alloc_id, base_offset, _prov) = this.ptr_get_alloc_id(place.ptr)?; // Load and log the atomic operation. // Note that atomic loads are possible even from read-only allocations, so `get_alloc_extra_mut` is not an option. let alloc_meta = this.get_alloc_extra(alloc_id)?.data_race.as_ref().unwrap(); diff --git a/src/shims/backtrace.rs b/src/shims/backtrace.rs index 3c15165d67be4..c5aab255aaf84 100644 --- a/src/shims/backtrace.rs +++ b/src/shims/backtrace.rs @@ -123,7 +123,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let ptr = this.read_pointer(ptr)?; // Take apart the pointer, we need its pieces. - let (alloc_id, offset, _tag) = this.ptr_get_alloc_id(ptr)?; + let (alloc_id, offset, _prov) = this.ptr_get_alloc_id(ptr)?; let fn_instance = if let Some(GlobalAlloc::Function(instance)) = this.tcx.get_global_alloc(alloc_id) { From 517e1d78b8a2daf7285ddf24f8642a922df02f89 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 20 Jul 2022 12:38:27 +0000 Subject: [PATCH 3530/3747] Add a scheme for always using the default toolchain, running clippy and fmt before running any other command --- .gitignore | 1 + CONTRIBUTING.md | 13 +++++++++++++ miri | 19 +++++++++++++++++++ 3 files changed, 33 insertions(+) diff --git a/.gitignore b/.gitignore index dcefbc62c70b3..185ff4f756c1f 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,4 @@ tex/*/out perf.data perf.data.old flamegraph.svg +.auto-* diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index a57ef09e7db9f..47864d822c4f4 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -28,6 +28,11 @@ install that exact version of rustc as a toolchain: This will set up a rustup toolchain called `miri` and set it as an override for the current directory. +You can also create a `.auto-everything` file (contents don't matter, can be empty), which +will cause any `./miri` command to automatically call `rustup-toolchain`, `clippy` and `rustfmt` +for you. If you don't want all of these to happen, you can add individual `.auto-toolchain`, +`.auto-clippy` and `.auto-fmt` files respectively. + [`rustup-toolchain-install-master`]: https://github.com/kennytm/rustup-toolchain-install-master ## Building and testing Miri @@ -244,6 +249,14 @@ rustup toolchain link stage2 build/x86_64-unknown-linux-gnu/stage2 rustup override set stage2 ``` +Note: When you are working with a locally built rustc or any other toolchain that +is not the same as the one in `rust-version`, you should not have `.auto-everything` or +`.auto-toolchain` as that will keep resetting your toolchain. + +``` +rm -f .auto-everything .auto-toolchain +``` + Important: You need to delete the Miri cache when you change the stdlib; otherwise the old, chached version will be used. On Linux, the cache is located at `~/.cache/miri`, and on Windows, it is located at `%LOCALAPPDATA%\rust-lang\miri\cache`; the exact diff --git a/miri b/miri index 04d441b60780d..19925e14be63d 100755 --- a/miri +++ b/miri @@ -48,6 +48,25 @@ Pass extra flags to all cargo invocations. EOF ) +## Run the subcommands that the user requested to always run first +if [ -z "$AUTO_OPS" ]; then + export AUTO_OPS=42 + + # Run this first, so that the toolchain doesn't change after + # other code has run. + if [ -f ".auto-everything" ] || [ -f ".auto-toolchain" ] ; then + "$MIRIDIR"/rustup-toolchain + fi + + if [ -f ".auto-everything" ] || [ -f ".auto-fmt" ] ; then + $0 fmt + fi + + if [ -f ".auto-everything" ] || [ -f ".auto-clippy" ] ; then + $0 clippy -- -D warnings + fi +fi + ## Preparation # macOS does not have a useful readlink/realpath so we have to use Python instead... MIRIDIR=$(python3 -c 'import os, sys; print(os.path.dirname(os.path.realpath(sys.argv[1])))' "$0") From 4d4eeca8a8da67c3dd6e27dd8665b4f11763fd87 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 20 Jul 2022 20:37:54 -0400 Subject: [PATCH 3531/3747] fix miri script --- miri | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/miri b/miri index 19925e14be63d..2a9be1de3629c 100755 --- a/miri +++ b/miri @@ -48,33 +48,34 @@ Pass extra flags to all cargo invocations. EOF ) -## Run the subcommands that the user requested to always run first +## We need to know where we are. +# macOS does not have a useful readlink/realpath so we have to use Python instead... +MIRIDIR=$(python3 -c 'import os, sys; print(os.path.dirname(os.path.realpath(sys.argv[1])))' "$0") + +## Run the auto-things. if [ -z "$AUTO_OPS" ]; then export AUTO_OPS=42 # Run this first, so that the toolchain doesn't change after # other code has run. - if [ -f ".auto-everything" ] || [ -f ".auto-toolchain" ] ; then + if [ -f "$MIRIDIR/.auto-everything" ] || [ -f "$MIRIDIR/.auto-toolchain" ] ; then "$MIRIDIR"/rustup-toolchain fi - if [ -f ".auto-everything" ] || [ -f ".auto-fmt" ] ; then + if [ -f "$MIRIDIR/.auto-everything" ] || [ -f "$MIRIDIR/.auto-fmt" ] ; then $0 fmt fi - if [ -f ".auto-everything" ] || [ -f ".auto-clippy" ] ; then + if [ -f "$MIRIDIR/.auto-everything" ] || [ -f "$MIRIDIR/.auto-clippy" ] ; then $0 clippy -- -D warnings fi fi -## Preparation -# macOS does not have a useful readlink/realpath so we have to use Python instead... -MIRIDIR=$(python3 -c 'import os, sys; print(os.path.dirname(os.path.realpath(sys.argv[1])))' "$0") -TOOLCHAIN=$(cd "$MIRIDIR"; rustup show active-toolchain | head -n 1 | cut -d ' ' -f 1) - -# Determine command. +## Determine command and toolchain. COMMAND="$1" [ $# -gt 0 ] && shift +# Doing this *after* auto-toolchain logic above, since that might change the toolchain. +TOOLCHAIN=$(cd "$MIRIDIR"; rustup show active-toolchain | head -n 1 | cut -d ' ' -f 1) ## Handle some commands early, since they should *not* alter the environment. case "$COMMAND" in From 88ad9ca9067ea1ce04313d7384c14fc24d1adbee Mon Sep 17 00:00:00 2001 From: Rain Date: Tue, 19 Jul 2022 19:37:24 -0700 Subject: [PATCH 3532/3747] [cargo-miri] support nextest Add the ability to run the `list` and `run` nextest commands, which enable per-test isolation. --- cargo-miri/bin.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index ecce1dece0284..9f6603f80b7eb 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -27,6 +27,7 @@ Usage: Subcommands: run, r Run binaries test, t Run tests + nextest Run tests with nextest (requires cargo-nextest installed) setup Only perform automatic setup, but without asking questions (for getting a proper libstd) The cargo options are exactly the same as for `cargo run` and `cargo test`, respectively. @@ -586,11 +587,10 @@ fn phase_cargo_miri(mut args: env::Args) { }; let subcommand = match &*subcommand { "setup" => MiriCommand::Setup, - "test" | "t" | "run" | "r" => MiriCommand::Forward(subcommand), - // Invalid command. + "test" | "t" | "run" | "r" | "nextest" => MiriCommand::Forward(subcommand), _ => show_error(format!( - "`cargo miri` supports the following subcommands: `run`, `test`, and `setup`." + "`cargo miri` supports the following subcommands: `run`, `test`, `nextest`, and `setup`." )), }; let verbose = num_arg_flag("-v"); From 30931eeecb047d1729d7c709af4036e20f20c5ea Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Mon, 18 Jul 2022 09:02:40 +0000 Subject: [PATCH 3533/3747] Add a dedicated thread for output printing --- ui_test/src/lib.rs | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/ui_test/src/lib.rs b/ui_test/src/lib.rs index 4318e8a8e034d..ee20920e54ffd 100644 --- a/ui_test/src/lib.rs +++ b/ui_test/src/lib.rs @@ -123,11 +123,22 @@ pub fn run_tests(mut config: Config) -> Result<()> { drop(submit); }); + // A channel for the messages emitted by the individual test threads. + let (finish_file, finished_files) = crossbeam::channel::unbounded(); + + s.spawn(|_| { + for msg in finished_files { + eprintln!("{msg}"); + } + }); + let mut threads = vec![]; // Create N worker threads that receive files to test. for _ in 0..std::thread::available_parallelism().unwrap().get() { + let finish_file = finish_file.clone(); threads.push(s.spawn(|_| -> Result<()> { + let finish_file = finish_file; for path in &receive { if !config.path_filter.is_empty() { let path_display = path.display().to_string(); @@ -140,11 +151,12 @@ pub fn run_tests(mut config: Config) -> Result<()> { // Ignore file if only/ignore rules do (not) apply if !test_file_conditions(&comments, &target, &config) { ignored.fetch_add(1, Ordering::Relaxed); - eprintln!( + let msg = format!( "{} ... {}", path.display(), "ignored (in-test comment)".yellow() ); + finish_file.send(msg)?; continue; } // Run the test for all revisions @@ -161,10 +173,10 @@ pub fn run_tests(mut config: Config) -> Result<()> { } write!(msg, "... ").unwrap(); if errors.is_empty() { - eprintln!("{msg}{}", "ok".green()); + write!(msg, "{}", "ok".green()).unwrap(); succeeded.fetch_add(1, Ordering::Relaxed); } else { - eprintln!("{msg}{}", "FAILED".red().bold()); + write!(msg, "{}", "FAILED".red().bold()).unwrap(); failures.lock().unwrap().push(( path.clone(), m, @@ -173,11 +185,13 @@ pub fn run_tests(mut config: Config) -> Result<()> { stderr, )); } + finish_file.send(msg)?; } } Ok(()) })); } + for thread in threads { thread.join().unwrap()?; } From 68041b42fc4a915321c31895f4544e8e70a0c4c8 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Mon, 18 Jul 2022 09:19:20 +0000 Subject: [PATCH 3534/3747] Print one character per test instead of one line --- tests/compiletest.rs | 14 +++++++++++-- ui_test/src/lib.rs | 47 +++++++++++++++++++++++++++++++++----------- ui_test/src/tests.rs | 1 + 3 files changed, 48 insertions(+), 14 deletions(-) diff --git a/tests/compiletest.rs b/tests/compiletest.rs index 37b9de7327a29..72aa140d66a2b 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -48,8 +48,17 @@ fn run_tests(mode: Mode, path: &str, target: Option) -> Result<()> { (true, true) => panic!("cannot use MIRI_BLESS and MIRI_SKIP_UI_CHECKS at the same time"), }; - // Pass on all arguments as filters. - let path_filter = std::env::args().skip(1); + // Pass on all unknown arguments as filters. + let mut quiet = false; + let path_filter = std::env::args().skip(1).filter(|arg| { + match &**arg { + "--quiet" => { + quiet = true; + false + } + _ => true, + } + }); let use_std = env::var_os("MIRI_NO_STD").is_none(); @@ -76,6 +85,7 @@ fn run_tests(mode: Mode, path: &str, target: Option) -> Result<()> { ], envs: vec![], }), + quiet, }; ui_test::run_tests(config) } diff --git a/ui_test/src/lib.rs b/ui_test/src/lib.rs index ee20920e54ffd..f33f8cd83f338 100644 --- a/ui_test/src/lib.rs +++ b/ui_test/src/lib.rs @@ -46,6 +46,8 @@ pub struct Config { /// Can be used to override what command to run instead of `cargo` to build the /// dependencies in `manifest_path` pub dependency_builder: Option, + /// Print one character per test instead of one line + pub quiet: bool, } #[derive(Debug)] @@ -125,10 +127,38 @@ pub fn run_tests(mut config: Config) -> Result<()> { // A channel for the messages emitted by the individual test threads. let (finish_file, finished_files) = crossbeam::channel::unbounded(); + enum TestResult { + Ok, + Failed, + Ignored, + } s.spawn(|_| { - for msg in finished_files { - eprintln!("{msg}"); + if config.quiet { + for (i, (_, result)) in finished_files.into_iter().enumerate() { + // Humans start counting at 1 + let i = i + 1; + match result { + TestResult::Ok => eprint!("{}", ".".green()), + TestResult::Failed => eprint!("{}", "F".red().bold()), + TestResult::Ignored => eprint!("{}", "i".yellow()), + } + if i % 100 == 0 { + eprintln!(" {i}"); + } + } + } else { + for (msg, result) in finished_files { + eprint!("{msg} ... "); + eprintln!( + "{}", + match result { + TestResult::Ok => "ok".green(), + TestResult::Failed => "FAILED".red().bold(), + TestResult::Ignored => "ignored (in-test comment)".yellow(), + } + ); + } } }); @@ -151,12 +181,7 @@ pub fn run_tests(mut config: Config) -> Result<()> { // Ignore file if only/ignore rules do (not) apply if !test_file_conditions(&comments, &target, &config) { ignored.fetch_add(1, Ordering::Relaxed); - let msg = format!( - "{} ... {}", - path.display(), - "ignored (in-test comment)".yellow() - ); - finish_file.send(msg)?; + finish_file.send((path.display().to_string(), TestResult::Ignored))?; continue; } // Run the test for all revisions @@ -171,12 +196,11 @@ pub fn run_tests(mut config: Config) -> Result<()> { if !revision.is_empty() { write!(msg, "(revision `{revision}`) ").unwrap(); } - write!(msg, "... ").unwrap(); if errors.is_empty() { - write!(msg, "{}", "ok".green()).unwrap(); + finish_file.send((msg, TestResult::Ok))?; succeeded.fetch_add(1, Ordering::Relaxed); } else { - write!(msg, "{}", "FAILED".red().bold()).unwrap(); + finish_file.send((msg, TestResult::Failed))?; failures.lock().unwrap().push(( path.clone(), m, @@ -185,7 +209,6 @@ pub fn run_tests(mut config: Config) -> Result<()> { stderr, )); } - finish_file.send(msg)?; } } Ok(()) diff --git a/ui_test/src/tests.rs b/ui_test/src/tests.rs index 8b0bd517a1054..2032988ed384d 100644 --- a/ui_test/src/tests.rs +++ b/ui_test/src/tests.rs @@ -18,6 +18,7 @@ fn config() -> Config { output_conflict_handling: OutputConflictHandling::Error, dependencies_crate_manifest_path: None, dependency_builder: None, + quiet: false, } } From ecacc56843ae0bd1ba264a9abf95c31ee66a9f8b Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Thu, 21 Jul 2022 07:39:54 +0000 Subject: [PATCH 3535/3747] Use names suggestive of channel endpoints --- ui_test/src/lib.rs | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/ui_test/src/lib.rs b/ui_test/src/lib.rs index f33f8cd83f338..06a84cfbf32eb 100644 --- a/ui_test/src/lib.rs +++ b/ui_test/src/lib.rs @@ -126,7 +126,7 @@ pub fn run_tests(mut config: Config) -> Result<()> { }); // A channel for the messages emitted by the individual test threads. - let (finish_file, finished_files) = crossbeam::channel::unbounded(); + let (finished_files_sender, finished_files_recv) = crossbeam::channel::unbounded(); enum TestResult { Ok, Failed, @@ -135,7 +135,7 @@ pub fn run_tests(mut config: Config) -> Result<()> { s.spawn(|_| { if config.quiet { - for (i, (_, result)) in finished_files.into_iter().enumerate() { + for (i, (_, result)) in finished_files_recv.into_iter().enumerate() { // Humans start counting at 1 let i = i + 1; match result { @@ -148,7 +148,7 @@ pub fn run_tests(mut config: Config) -> Result<()> { } } } else { - for (msg, result) in finished_files { + for (msg, result) in finished_files_recv { eprint!("{msg} ... "); eprintln!( "{}", @@ -166,9 +166,9 @@ pub fn run_tests(mut config: Config) -> Result<()> { // Create N worker threads that receive files to test. for _ in 0..std::thread::available_parallelism().unwrap().get() { - let finish_file = finish_file.clone(); + let finished_files_sender = finished_files_sender.clone(); threads.push(s.spawn(|_| -> Result<()> { - let finish_file = finish_file; + let finished_files_sender = finished_files_sender; for path in &receive { if !config.path_filter.is_empty() { let path_display = path.display().to_string(); @@ -181,7 +181,8 @@ pub fn run_tests(mut config: Config) -> Result<()> { // Ignore file if only/ignore rules do (not) apply if !test_file_conditions(&comments, &target, &config) { ignored.fetch_add(1, Ordering::Relaxed); - finish_file.send((path.display().to_string(), TestResult::Ignored))?; + finished_files_sender + .send((path.display().to_string(), TestResult::Ignored))?; continue; } // Run the test for all revisions @@ -197,10 +198,10 @@ pub fn run_tests(mut config: Config) -> Result<()> { write!(msg, "(revision `{revision}`) ").unwrap(); } if errors.is_empty() { - finish_file.send((msg, TestResult::Ok))?; + finished_files_sender.send((msg, TestResult::Ok))?; succeeded.fetch_add(1, Ordering::Relaxed); } else { - finish_file.send((msg, TestResult::Failed))?; + finished_files_sender.send((msg, TestResult::Failed))?; failures.lock().unwrap().push(( path.clone(), m, From 7c30ba183c9903362ffc93921d659dda665f5039 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 21 Jul 2022 07:19:56 -0400 Subject: [PATCH 3536/3747] fix auto-toolchain pwd --- miri | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/miri b/miri index 2a9be1de3629c..38f8e546aecba 100755 --- a/miri +++ b/miri @@ -59,7 +59,7 @@ if [ -z "$AUTO_OPS" ]; then # Run this first, so that the toolchain doesn't change after # other code has run. if [ -f "$MIRIDIR/.auto-everything" ] || [ -f "$MIRIDIR/.auto-toolchain" ] ; then - "$MIRIDIR"/rustup-toolchain + (cd "$MIRIDIR" && ./rustup-toolchain) fi if [ -f "$MIRIDIR/.auto-everything" ] || [ -f "$MIRIDIR/.auto-fmt" ] ; then From 8fa15428786e1e618791566b474e5b3bcf34775d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 21 Jul 2022 08:06:11 -0400 Subject: [PATCH 3537/3747] make test-cargo-miri only about cargo remove rand (large dependency) and page-size (testing the dependency, not cargo-miri). keep only byteorder as a "demo" dependency, it is a leaf and builds quickly. --- test-cargo-miri/Cargo.lock | 108 ++---------------- test-cargo-miri/Cargo.toml | 3 +- test-cargo-miri/cdylib/Cargo.toml | 2 +- test-cargo-miri/run-test.py | 2 +- test-cargo-miri/src/main.rs | 11 +- test-cargo-miri/test.bin-target.stdout.ref | 2 +- test-cargo-miri/test.cross-target.stdout.ref | 6 +- test-cargo-miri/test.default.stdout.ref | 6 +- .../test.filter.cross-target.stdout.ref | 4 +- test-cargo-miri/test.filter.stdout.ref | 4 +- test-cargo-miri/test.test-target.stdout.ref | 10 +- test-cargo-miri/tests/test.rs | 46 +++----- 12 files changed, 45 insertions(+), 159 deletions(-) diff --git a/test-cargo-miri/Cargo.lock b/test-cargo-miri/Cargo.lock index 4cf58d723a256..3f61fb3d5408d 100644 --- a/test-cargo-miri/Cargo.lock +++ b/test-cargo-miri/Cargo.lock @@ -2,6 +2,12 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "byteorder" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fc10e8cc6b2580fda3f36eb6dc5316657f812a3df879a44a66fc9f0fdbc4855" + [[package]] name = "byteorder" version = "1.4.3" @@ -12,7 +18,8 @@ checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" name = "cargo-miri-test" version = "0.1.0" dependencies = [ - "byteorder", + "byteorder 0.5.3", + "byteorder 1.4.3", "cdylib", "exported_symbol", "issue_1567", @@ -20,8 +27,6 @@ dependencies = [ "issue_1705", "issue_1760", "issue_rust_86261", - "page_size", - "rand", "serde_derive", ] @@ -29,15 +34,9 @@ dependencies = [ name = "cdylib" version = "0.1.0" dependencies = [ - "byteorder", + "byteorder 1.4.3", ] -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - [[package]] name = "exported_symbol" version = "0.1.0" @@ -49,17 +48,6 @@ dependencies = [ name = "exported_symbol_dep" version = "0.1.0" -[[package]] -name = "getrandom" -version = "0.2.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4eb1a864a501629691edf6c15a593b7a51eebaa1e8468e9ddc623de7c9b58ec6" -dependencies = [ - "cfg-if", - "libc", - "wasi", -] - [[package]] name = "hermit-abi" version = "0.1.19" @@ -73,7 +61,7 @@ dependencies = [ name = "issue_1567" version = "0.1.0" dependencies = [ - "byteorder", + "byteorder 1.4.3", ] [[package]] @@ -84,7 +72,7 @@ version = "0.1.0" name = "issue_1705" version = "0.1.0" dependencies = [ - "byteorder", + "byteorder 1.4.3", ] [[package]] @@ -111,22 +99,6 @@ dependencies = [ "libc", ] -[[package]] -name = "page_size" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eebde548fbbf1ea81a99b128872779c437752fb99f217c45245e1a61dcd9edcd" -dependencies = [ - "libc", - "winapi", -] - -[[package]] -name = "ppv-lite86" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872" - [[package]] name = "proc-macro2" version = "1.0.40" @@ -145,36 +117,6 @@ dependencies = [ "proc-macro2", ] -[[package]] -name = "rand" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" -dependencies = [ - "libc", - "rand_chacha", - "rand_core", -] - -[[package]] -name = "rand_chacha" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" -dependencies = [ - "ppv-lite86", - "rand_core", -] - -[[package]] -name = "rand_core" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7" -dependencies = [ - "getrandom", -] - [[package]] name = "serde_derive" version = "1.0.137" @@ -209,31 +151,3 @@ name = "unicode-ident" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5bd2fe26506023ed7b5e1e315add59d6f584c621d037f9368fea9cfb988f368c" - -[[package]] -name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" - -[[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/test-cargo-miri/Cargo.toml b/test-cargo-miri/Cargo.toml index 89a8463e4b325..51967c54e15cf 100644 --- a/test-cargo-miri/Cargo.toml +++ b/test-cargo-miri/Cargo.toml @@ -18,9 +18,8 @@ issue_1760 = { path = "issue-1760" } issue_rust_86261 = { path = "issue-rust-86261" } [dev-dependencies] -rand = { version = "0.8", features = ["small_rng"] } +byteorder_2 = { package = "byteorder", version = "0.5" } # to test dev-dependencies behave as expected, with renaming serde_derive = "1.0" # not actually used, but exercises some unique code path (`--extern` .so file) -page_size = "0.4.1" [lib] test = false # test that this is respected (will show in the output) diff --git a/test-cargo-miri/cdylib/Cargo.toml b/test-cargo-miri/cdylib/Cargo.toml index 4e5b5601a56ce..527602e0a888f 100644 --- a/test-cargo-miri/cdylib/Cargo.toml +++ b/test-cargo-miri/cdylib/Cargo.toml @@ -9,4 +9,4 @@ edition = "2018" crate-type = ["cdylib"] [dependencies] -byteorder = "1.0" +byteorder = "1.0" # to test dependencies of sub-crates diff --git a/test-cargo-miri/run-test.py b/test-cargo-miri/run-test.py index bc0046ffb148d..ab43c72511584 100755 --- a/test-cargo-miri/run-test.py +++ b/test-cargo-miri/run-test.py @@ -134,7 +134,7 @@ def test_cargo_miri_test(): env={'MIRIFLAGS': "-Zmiri-permissive-provenance -Zmiri-disable-isolation"}, ) test("`cargo miri test` (with filter)", - cargo_miri("test") + ["--", "--format=pretty", "le1"], + cargo_miri("test") + ["--", "--format=pretty", "pl"], filter_ref, "test.stderr-empty.ref", ) test("`cargo miri test` (test target)", diff --git a/test-cargo-miri/src/main.rs b/test-cargo-miri/src/main.rs index 5807d0765fb31..41c52b7017028 100644 --- a/test-cargo-miri/src/main.rs +++ b/test-cargo-miri/src/main.rs @@ -45,17 +45,12 @@ fn main() { #[cfg(test)] mod test { - use rand::{Rng, SeedableRng}; + use byteorder_2::{BigEndian, ByteOrder}; // Make sure in-crate tests with dev-dependencies work #[test] - fn rng() { - let mut rng = rand::rngs::StdRng::seed_from_u64(0xcafebeef); - let x: u32 = rng.gen(); - let y: usize = rng.gen(); - let z: u128 = rng.gen(); - assert_ne!(x as usize, y); - assert_ne!(y as u128, z); + fn dev_dependency() { + let _n = ::read_u64(&[1, 2, 3, 4, 5, 6, 7, 8]); } #[test] diff --git a/test-cargo-miri/test.bin-target.stdout.ref b/test-cargo-miri/test.bin-target.stdout.ref index 62cfd1d37a172..5264530160bc5 100644 --- a/test-cargo-miri/test.bin-target.stdout.ref +++ b/test-cargo-miri/test.bin-target.stdout.ref @@ -1,7 +1,7 @@ running 2 tests +test test::dev_dependency ... ok test test::exported_symbol ... ok -test test::rng ... ok test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out diff --git a/test-cargo-miri/test.cross-target.stdout.ref b/test-cargo-miri/test.cross-target.stdout.ref index 3673e5549d8c2..8c543e479f4e0 100644 --- a/test-cargo-miri/test.cross-target.stdout.ref +++ b/test-cargo-miri/test.cross-target.stdout.ref @@ -5,7 +5,7 @@ test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out imported main -running 8 tests -..i..... -test result: ok. 7 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out +running 6 tests +...i.. +test result: ok. 5 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out diff --git a/test-cargo-miri/test.default.stdout.ref b/test-cargo-miri/test.default.stdout.ref index a59108efb3323..9a17f3d61b6ac 100644 --- a/test-cargo-miri/test.default.stdout.ref +++ b/test-cargo-miri/test.default.stdout.ref @@ -5,9 +5,9 @@ test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out imported main -running 8 tests -..i..... -test result: ok. 7 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out +running 6 tests +...i.. +test result: ok. 5 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out running 4 tests diff --git a/test-cargo-miri/test.filter.cross-target.stdout.ref b/test-cargo-miri/test.filter.cross-target.stdout.ref index 9fb7670d06495..bb0282d6c9167 100644 --- a/test-cargo-miri/test.filter.cross-target.stdout.ref +++ b/test-cargo-miri/test.filter.cross-target.stdout.ref @@ -6,7 +6,7 @@ test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 2 filtered out imported main running 1 test -test simple1 ... ok +test simple ... ok -test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 7 filtered out +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 5 filtered out diff --git a/test-cargo-miri/test.filter.stdout.ref b/test-cargo-miri/test.filter.stdout.ref index 4b598960a0963..c618956656a8a 100644 --- a/test-cargo-miri/test.filter.stdout.ref +++ b/test-cargo-miri/test.filter.stdout.ref @@ -6,9 +6,9 @@ test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 2 filtered out imported main running 1 test -test simple1 ... ok +test simple ... ok -test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 7 filtered out +test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 5 filtered out running 0 tests diff --git a/test-cargo-miri/test.test-target.stdout.ref b/test-cargo-miri/test.test-target.stdout.ref index ca069b702eba4..dd59b32b780c8 100644 --- a/test-cargo-miri/test.test-target.stdout.ref +++ b/test-cargo-miri/test.test-target.stdout.ref @@ -1,13 +1,11 @@ -running 8 tests +running 6 tests test cargo_env ... ok +test deps ... ok test do_panic - should panic ... ok test does_not_work_on_miri ... ignored -test entropy_rng ... ok test fail_index_check - should panic ... ok -test page_size ... ok -test simple1 ... ok -test simple2 ... ok +test simple ... ok -test result: ok. 7 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out +test result: ok. 5 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out diff --git a/test-cargo-miri/tests/test.rs b/test-cargo-miri/tests/test.rs index eb31058e1c19b..1d8282accc02a 100644 --- a/test-cargo-miri/tests/test.rs +++ b/test-cargo-miri/tests/test.rs @@ -1,39 +1,26 @@ -use rand::{rngs::SmallRng, Rng, SeedableRng}; - -// Having more than 1 test does seem to make a difference -// (i.e., this calls ptr::swap which having just one test does not). #[test] -fn simple1() { +fn simple() { assert_eq!(4, 4); } -#[test] -fn simple2() { - assert_ne!(42, 24); -} - // A test that won't work on miri (tests disabling tests). #[test] #[cfg_attr(miri, ignore)] fn does_not_work_on_miri() { - let x = 0u8; - assert!(&x as *const _ as usize % 4 < 4); + unsafe { std::arch::asm!("") }; } -// Make sure integration tests can access dev-dependencies +// Make sure integration tests can access both dependencies and dev-dependencies #[test] -fn entropy_rng() { - // Try seeding with "real" entropy. - let mut rng = SmallRng::from_entropy(); - let _val = rng.gen::(); - let _val = rng.gen::(); - let _val = rng.gen::(); - - // Also try per-thread RNG. - let mut rng = rand::thread_rng(); - let _val = rng.gen::(); - let _val = rng.gen::(); - let _val = rng.gen::(); +fn deps() { + { + use byteorder::{BigEndian, ByteOrder}; + let _n = ::read_u64(&[1, 2, 3, 4, 5, 6, 7, 8]); + } + { + use byteorder_2::{BigEndian, ByteOrder}; + let _n = ::read_u64(&[1, 2, 3, 4, 5, 6, 7, 8]); + } } #[test] @@ -49,17 +36,10 @@ fn do_panic() // In large, friendly letters :) panic!("Explicit panic from test!"); } +// A different way of raising a panic #[test] #[allow(unconditional_panic)] #[should_panic(expected = "the len is 0 but the index is 42")] fn fail_index_check() { [][42] } - -#[test] -fn page_size() { - let page_size = page_size::get(); - - // In particular, this checks that it is not 0. - assert!(page_size.is_power_of_two(), "page size not a power of two: {}", page_size); -} From b1b368c30ebc55b752e69ac687791504e62851cc Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 21 Jul 2022 08:14:41 -0400 Subject: [PATCH 3538/3747] test page_size via test dependency support and move crate tests to their own folders --- test_dependencies/Cargo.lock | 11 +++++++++++ test_dependencies/Cargo.toml | 1 + tests/fail/{ => crates}/tokio_mvp.rs | 0 tests/fail/{ => crates}/tokio_mvp.stderr | 0 tests/pass/crates/page_size.rs | 6 ++++++ tests/pass/{ => crates}/random.rs | 0 6 files changed, 18 insertions(+) rename tests/fail/{ => crates}/tokio_mvp.rs (100%) rename tests/fail/{ => crates}/tokio_mvp.stderr (100%) create mode 100644 tests/pass/crates/page_size.rs rename tests/pass/{ => crates}/random.rs (100%) diff --git a/test_dependencies/Cargo.lock b/test_dependencies/Cargo.lock index 6b5e8c942244f..a492deba4c528 100644 --- a/test_dependencies/Cargo.lock +++ b/test_dependencies/Cargo.lock @@ -107,6 +107,7 @@ dependencies = [ "getrandom 0.1.16", "getrandom 0.2.7", "libc", + "page_size", "rand", "tokio", ] @@ -127,6 +128,16 @@ version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "18a6dbe30758c9f83eb00cbea4ac95966305f5a7772f3f42ebfc7fc7eddbd8e1" +[[package]] +name = "page_size" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eebde548fbbf1ea81a99b128872779c437752fb99f217c45245e1a61dcd9edcd" +dependencies = [ + "libc", + "winapi", +] + [[package]] name = "parking_lot" version = "0.12.1" diff --git a/test_dependencies/Cargo.toml b/test_dependencies/Cargo.toml index edaa6a6926030..0bf43aefebffb 100644 --- a/test_dependencies/Cargo.toml +++ b/test_dependencies/Cargo.toml @@ -11,6 +11,7 @@ edition = "2021" # all dependencies (and their transitive ones) listed here can be used in `tests/`. tokio = { version = "1.0", features = ["full"] } libc = "0.2" +page_size = "0.4.1" getrandom_1 = { package = "getrandom", version = "0.1" } getrandom_2 = { package = "getrandom", version = "0.2" } diff --git a/tests/fail/tokio_mvp.rs b/tests/fail/crates/tokio_mvp.rs similarity index 100% rename from tests/fail/tokio_mvp.rs rename to tests/fail/crates/tokio_mvp.rs diff --git a/tests/fail/tokio_mvp.stderr b/tests/fail/crates/tokio_mvp.stderr similarity index 100% rename from tests/fail/tokio_mvp.stderr rename to tests/fail/crates/tokio_mvp.stderr diff --git a/tests/pass/crates/page_size.rs b/tests/pass/crates/page_size.rs new file mode 100644 index 0000000000000..cdcabf3333814 --- /dev/null +++ b/tests/pass/crates/page_size.rs @@ -0,0 +1,6 @@ +fn main() { + let page_size = page_size::get(); + + // In particular, this checks that it is not 0. + assert!(page_size.is_power_of_two(), "page size not a power of two: {}", page_size); +} diff --git a/tests/pass/random.rs b/tests/pass/crates/random.rs similarity index 100% rename from tests/pass/random.rs rename to tests/pass/crates/random.rs From 800273c1d9005c6433098735f663bd8e362ce69b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 21 Jul 2022 09:14:11 -0400 Subject: [PATCH 3539/3747] cargo-miri: set RUSTC to us --- cargo-miri/bin.rs | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index 9f6603f80b7eb..d2c772d7d9220 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -661,14 +661,17 @@ fn phase_cargo_miri(mut args: env::Args) { ); } cmd.env("RUSTC_WRAPPER", &cargo_miri_path); - // Having both `RUSTC_WRAPPER` and `RUSTC` set does some odd things, so let's avoid that. - // See . + // We are going to invoke `MIRI` for everything, not `RUSTC`. if env::var_os("RUSTC").is_some() && env::var_os("MIRI").is_none() { println!( "WARNING: Ignoring `RUSTC` environment variable; set `MIRI` if you want to control the binary used as the driver." ); } - cmd.env_remove("RUSTC"); + // We'd prefer to just clear this env var, but cargo does not always honor `RUSTC_WRAPPER` + // (https://github.com/rust-lang/cargo/issues/10885). There is no good way to single out these invocations; + // some build scripts use the RUSTC env var as well. So we set it directly to the `miri` driver and + // hope that all they do is ask for the version number -- things could quickly go downhill from here. + cmd.env("RUSTC", &find_miri()); let runner_env_name = |triple: &str| format!("CARGO_TARGET_{}_RUNNER", triple.to_uppercase().replace('-', "_")); @@ -1173,8 +1176,14 @@ fn main() { match args.next().as_deref() { Some("miri") => phase_cargo_miri(args), - Some("rustc") => phase_rustc(args, RustcPhase::Build), Some(arg) => { + // If the first arg is equal to the RUSTC variable (which should be set at this point), + // then we need to behave as rustc. This is the somewhat counter-intuitive behavior of + // having both RUSTC and RUSTC_WRAPPER set (see + // https://github.com/rust-lang/cargo/issues/10886). + if arg == env::var_os("RUSTC").unwrap() { + return phase_rustc(args, RustcPhase::Build); + } // We have to distinguish the "runner" and "rustdoc" cases. // As runner, the first argument is the binary (a file that should exist, with an absolute path); // as rustdoc, the first argument is a flag (`--something`). From 7cd1d78a4769995546967e413dbbd672c11a153e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 21 Jul 2022 09:30:09 -0400 Subject: [PATCH 3540/3747] only complain about runtime toolchain mismatch when there actually is a runtime toolchain --- src/bin/miri.rs | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 8bd33b591d72c..516c730e3fbdb 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -220,16 +220,17 @@ fn compile_time_sysroot() -> Option { let toolchain = option_env!("RUSTUP_TOOLCHAIN").or(option_env!("MULTIRUST_TOOLCHAIN")); Some(match (home, toolchain) { (Some(home), Some(toolchain)) => { - // Check that at runtime, we are still in this toolchain. - let toolchain_runtime = - env::var_os("RUSTUP_TOOLCHAIN").or_else(|| env::var_os("MULTIRUST_TOOLCHAIN")); - if !matches!(toolchain_runtime, Some(r) if r == toolchain) { - show_error(format!( - "This Miri got built with local toolchain `{toolchain}`, but now is being run under a different toolchain. \n\ + // Check that at runtime, we are still in this toolchain (if there is any toolchain). + if let Some(toolchain_runtime) = + env::var_os("RUSTUP_TOOLCHAIN").or_else(|| env::var_os("MULTIRUST_TOOLCHAIN")) + { + if toolchain_runtime != toolchain { + show_error(format!( + "This Miri got built with local toolchain `{toolchain}`, but now is being run under a different toolchain. \n\ Make sure to run Miri in the toolchain it got built with, e.g. via `cargo +{toolchain} miri`." - )); + )); + } } - format!("{}/toolchains/{}", home, toolchain) } _ => option_env!("RUST_SYSROOT") From 929712c49c112e20332cbb87acc3f6941450979b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 21 Jul 2022 09:36:59 -0400 Subject: [PATCH 3541/3747] reduce chance of RUSTC collisions --- cargo-miri/bin.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index d2c772d7d9220..53d348c16d711 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -671,7 +671,10 @@ fn phase_cargo_miri(mut args: env::Args) { // (https://github.com/rust-lang/cargo/issues/10885). There is no good way to single out these invocations; // some build scripts use the RUSTC env var as well. So we set it directly to the `miri` driver and // hope that all they do is ask for the version number -- things could quickly go downhill from here. - cmd.env("RUSTC", &find_miri()); + // In `main`, we need the value of `RUSTC` to distinguish RUSTC_WRAPPER invocations from rustdoc + // or TARGET_RUNNER invocations, so we canonicalize it here to make it exceedingly unlikely that + // there would be a collision. + cmd.env("RUSTC", &fs::canonicalize(find_miri()).unwrap()); let runner_env_name = |triple: &str| format!("CARGO_TARGET_{}_RUNNER", triple.to_uppercase().replace('-', "_")); From 0a9feb3c9f93eb66d75a731dfd41151af16252b5 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 21 Jul 2022 09:58:00 -0400 Subject: [PATCH 3542/3747] some more debug output --- cargo-miri/bin.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index 53d348c16d711..9c964829dd135 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -820,10 +820,10 @@ fn phase_rustc(mut args: env::Args, phase: RustcPhase) { if verbose > 0 { eprintln!( - "[cargo-miri rustc] captured input:\n{}", + "[cargo-miri rustc inside rustdoc] captured input:\n{}", std::str::from_utf8(&env.stdin).unwrap() ); - eprintln!("[cargo-miri rustc] {:?}", cmd); + eprintln!("[cargo-miri rustc inside rustdoc] going to run:\n{:?}", cmd); } exec_with_pipe(cmd, &env.stdin); @@ -906,7 +906,10 @@ fn phase_rustc(mut args: env::Args, phase: RustcPhase) { // Run it. if verbose > 0 { - eprint!("[cargo-miri rustc] "); + eprintln!( + "[cargo-miri rustc] target_crate={target_crate} runnable_crate={runnable_crate} print={print}" + ); + eprintln!("[cargo-miri rustc] going to run:"); if verbose > 1 { for (key, value) in env_vars_from_cmd(&cmd) { eprintln!("{key}={value:?} \\"); From bb52965b73bb5885591fdd5b596a8d8f36d75f4e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 21 Jul 2022 10:36:55 -0400 Subject: [PATCH 3543/3747] make the find_miri returned path actually exist --- cargo-miri/bin.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index 9c964829dd135..48beb7c935d67 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -212,7 +212,11 @@ fn find_miri() -> PathBuf { return path.into(); } let mut path = std::env::current_exe().expect("current executable path invalid"); - path.set_file_name("miri"); + if cfg!(windows) { + path.set_file_name("miri.exe"); + } else { + path.set_file_name("miri"); + } path } From 5e4b64645712b0cefd3de751907d00210f735ed0 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 21 Jul 2022 10:48:41 -0400 Subject: [PATCH 3544/3747] aarch inline asm is not stable yet --- test-cargo-miri/tests/test.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/test-cargo-miri/tests/test.rs b/test-cargo-miri/tests/test.rs index 1d8282accc02a..9ed2152893964 100644 --- a/test-cargo-miri/tests/test.rs +++ b/test-cargo-miri/tests/test.rs @@ -7,7 +7,11 @@ fn simple() { #[test] #[cfg_attr(miri, ignore)] fn does_not_work_on_miri() { - unsafe { std::arch::asm!("") }; + // Only do this where inline assembly is stable. + #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] + unsafe { + std::arch::asm!("foo"); + } } // Make sure integration tests can access both dependencies and dev-dependencies From 392342fcaf4c08c060d7ea7db2c03f3b5830def9 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Thu, 21 Jul 2022 11:45:22 +0000 Subject: [PATCH 3545/3747] Avoid rustformatting on autosave --- CONTRIBUTING.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 47864d822c4f4..f6147bbbe5355 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -168,11 +168,15 @@ to `.vscode/settings.json` in your local Miri clone: "./cargo-miri/Cargo.toml" ], "rust-analyzer.checkOnSave.overrideCommand": [ + "env", + "AUTO_OPS=42", "./miri", "check", "--message-format=json" ], "rust-analyzer.buildScripts.overrideCommand": [ + "env", + "AUTO_OPS=42", "./miri", "check", "--message-format=json", From bfa2ff646c5830de1662576658f4ae69e207ffca Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Thu, 21 Jul 2022 12:24:13 +0000 Subject: [PATCH 3546/3747] Use a MIRI namespaced env var name for auto ops --- CONTRIBUTING.md | 4 ++-- miri | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index f6147bbbe5355..42f77b5cbc0ed 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -169,14 +169,14 @@ to `.vscode/settings.json` in your local Miri clone: ], "rust-analyzer.checkOnSave.overrideCommand": [ "env", - "AUTO_OPS=42", + "MIRI_AUTO_OPS=no", "./miri", "check", "--message-format=json" ], "rust-analyzer.buildScripts.overrideCommand": [ "env", - "AUTO_OPS=42", + "MIRI_AUTO_OPS=no", "./miri", "check", "--message-format=json", diff --git a/miri b/miri index 38f8e546aecba..463e4607baedb 100755 --- a/miri +++ b/miri @@ -53,8 +53,8 @@ EOF MIRIDIR=$(python3 -c 'import os, sys; print(os.path.dirname(os.path.realpath(sys.argv[1])))' "$0") ## Run the auto-things. -if [ -z "$AUTO_OPS" ]; then - export AUTO_OPS=42 +if [ -z "$MIRI_AUTO_OPS" ]; then + export MIRI_AUTO_OPS=42 # Run this first, so that the toolchain doesn't change after # other code has run. From 9e7f3cdc36fdef06647f5c35a91dc4631f0b92d7 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Thu, 21 Jul 2022 15:07:07 +0000 Subject: [PATCH 3547/3747] Document MIRI_AUTO_OPS --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index d1dde153c4787..2214bcf4c59cb 100644 --- a/README.md +++ b/README.md @@ -393,6 +393,9 @@ Some native rustc `-Z` flags are also very relevant for Miri: Moreover, Miri recognizes some environment variables: +* `MIRI_AUTO_OPS` indicates whether the automatic execution of rustfmt, clippy and rustup-toolchain + should be skipped. If it is set to any value, they are skipped. This is used for avoiding + infinite recursion in `./miri` and to allow automated IDE actions to avoid the auto ops. * `MIRI_LOG`, `MIRI_BACKTRACE` control logging and backtrace printing during Miri executions, also [see "Testing the Miri driver" in `CONTRIBUTING.md`][testing-miri]. * `MIRIFLAGS` (recognized by `cargo miri` and the test suite) defines extra From 309413717fbeb6a9eb56ebe63726c6fe305117b8 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 21 Jul 2022 12:04:17 -0400 Subject: [PATCH 3548/3747] cargo-miri debugging improvements --- cargo-miri/bin.rs | 103 +++++++++++++++++++++++++--------------------- 1 file changed, 57 insertions(+), 46 deletions(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index 48beb7c935d67..113b0c04a3ae2 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -572,7 +572,51 @@ fn local_crates(metadata: &Metadata) -> String { local_crates } -fn phase_cargo_miri(mut args: env::Args) { +fn env_vars_from_cmd(cmd: &Command) -> Vec<(String, String)> { + let mut envs = HashMap::new(); + for (key, value) in std::env::vars() { + envs.insert(key, value); + } + for (key, value) in cmd.get_envs() { + if let Some(value) = value { + envs.insert(key.to_string_lossy().to_string(), value.to_string_lossy().to_string()); + } else { + envs.remove(&key.to_string_lossy().to_string()); + } + } + let mut envs: Vec<_> = envs.into_iter().collect(); + envs.sort(); + envs +} + +/// Debug-print a command that is going to be run. +fn debug_cmd(prefix: &str, verbose: usize, cmd: &Command) { + if verbose == 0 { + return; + } + // We only do a single `eprintln!` call to minimize concurrency interactions. + let mut out = prefix.to_string(); + writeln!(out, " running command: env \\").unwrap(); + if verbose > 1 { + // Print the full environment this will be called in. + for (key, value) in env_vars_from_cmd(cmd) { + writeln!(out, "{key}={value:?} \\").unwrap(); + } + } else { + // Print only what has been changed for this `cmd`. + for (var, val) in cmd.get_envs() { + if let Some(val) = val { + writeln!(out, "{}={:?} \\", var.to_string_lossy(), val).unwrap(); + } else { + writeln!(out, "--unset={}", var.to_string_lossy()).unwrap(); + } + } + } + write!(out, "{cmd:?}").unwrap(); + eprintln!("{}", out); +} + +fn phase_cargo_miri(mut args: impl Iterator) { // Check for version and help flags even when invoked as `cargo-miri`. if has_arg_flag("--help") || has_arg_flag("-h") { show_help(); @@ -694,18 +738,12 @@ fn phase_cargo_miri(mut args: env::Args) { cmd.env("RUSTDOC", &cargo_miri_path); cmd.env("MIRI_LOCAL_CRATES", local_crates(&metadata)); - - // Run cargo. if verbose > 0 { - eprintln!("[cargo-miri miri] RUSTC_WRAPPER={:?}", cargo_miri_path); - eprintln!("[cargo-miri miri] {}={:?}", target_runner_env_name, cargo_miri_path); - if *target != host { - eprintln!("[cargo-miri miri] {}={:?}", host_runner_env_name, cargo_miri_path); - } - eprintln!("[cargo-miri miri] RUSTDOC={:?}", cargo_miri_path); - eprintln!("[cargo-miri miri] {:?}", cmd); cmd.env("MIRI_VERBOSE", verbose.to_string()); // This makes the other phases verbose. } + + // Run cargo. + debug_cmd("[cargo-miri miri]", verbose, &cmd); exec(cmd) } @@ -913,14 +951,8 @@ fn phase_rustc(mut args: env::Args, phase: RustcPhase) { eprintln!( "[cargo-miri rustc] target_crate={target_crate} runnable_crate={runnable_crate} print={print}" ); - eprintln!("[cargo-miri rustc] going to run:"); - if verbose > 1 { - for (key, value) in env_vars_from_cmd(&cmd) { - eprintln!("{key}={value:?} \\"); - } - } - eprintln!("{:?}", cmd); } + debug_cmd("[cargo-miri rustc]", verbose, &cmd); exec(cmd); // Create a stub .rlib file if "link" was requested by cargo. @@ -938,23 +970,6 @@ fn phase_rustc(mut args: env::Args, phase: RustcPhase) { } } -fn env_vars_from_cmd(cmd: &Command) -> Vec<(String, String)> { - let mut envs = HashMap::new(); - for (key, value) in std::env::vars() { - envs.insert(key, value); - } - for (key, value) in cmd.get_envs() { - if let Some(value) = value { - envs.insert(key.to_str().unwrap().into(), value.to_str().unwrap().to_owned()); - } else { - envs.remove(key.to_str().unwrap()); - } - } - let mut envs: Vec<_> = envs.into_iter().collect(); - envs.sort(); - envs -} - #[derive(Debug, Copy, Clone, PartialEq)] enum RunnerPhase { /// `cargo` is running a binary @@ -963,8 +978,9 @@ enum RunnerPhase { Rustdoc, } -fn phase_runner(binary: &Path, binary_args: env::Args, phase: RunnerPhase) { - let verbose = std::env::var_os("MIRI_VERBOSE").is_some(); +fn phase_runner(binary: &Path, binary_args: impl Iterator, phase: RunnerPhase) { + let verbose = std::env::var("MIRI_VERBOSE") + .map_or(0, |verbose| verbose.parse().expect("verbosity flag must be an integer")); let file = File::open(&binary) .unwrap_or_else(|_| show_error(format!("file {:?} not found or `cargo-miri` invoked incorrectly; please only invoke this binary through `cargo miri`", binary))); @@ -991,7 +1007,7 @@ fn phase_runner(binary: &Path, binary_args: env::Args, phase: RunnerPhase) { // Set missing env vars. We prefer build-time env vars over run-time ones; see // for the kind of issue that fixes. for (name, val) in info.env { - if verbose { + if verbose > 0 { if let Some(old_val) = env::var_os(&name) { if old_val != val { eprintln!( @@ -1048,10 +1064,7 @@ fn phase_runner(binary: &Path, binary_args: env::Args, phase: RunnerPhase) { cmd.env("MIRI_CWD", env::current_dir().unwrap()); // Run it. - if verbose { - eprintln!("[cargo-miri runner] {:?}", cmd); - } - + debug_cmd("[cargo-miri runner]", verbose, &cmd); match phase { RunnerPhase::Rustdoc => exec_with_pipe(cmd, &info.stdin), RunnerPhase::Cargo => exec(cmd), @@ -1059,7 +1072,8 @@ fn phase_runner(binary: &Path, binary_args: env::Args, phase: RunnerPhase) { } fn phase_rustdoc(fst_arg: &str, mut args: env::Args) { - let verbose = std::env::var_os("MIRI_VERBOSE").is_some(); + let verbose = std::env::var("MIRI_VERBOSE") + .map_or(0, |verbose| verbose.parse().expect("verbosity flag must be an integer")); // phase_cargo_miri sets the RUSTDOC env var to ourselves, so we can't use that here; // just default to a straight-forward invocation for now: @@ -1126,10 +1140,7 @@ fn phase_rustdoc(fst_arg: &str, mut args: env::Args) { cmd.arg("--test-builder").arg(&cargo_miri_path); // invoked by forwarding most arguments cmd.arg("--runtool").arg(&cargo_miri_path); // invoked with just a single path argument - if verbose { - eprintln!("[cargo-miri rustdoc] {:?}", cmd); - } - + debug_cmd("[cargo-miri rustdoc]", verbose, &cmd); exec(cmd) } From d43e12e412bda35b519dc5038d3344dd2d2d2b22 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 21 Jul 2022 12:43:30 -0400 Subject: [PATCH 3549/3747] say what we are doing --- ui_test/src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/ui_test/src/lib.rs b/ui_test/src/lib.rs index 06a84cfbf32eb..7fd053eace189 100644 --- a/ui_test/src/lib.rs +++ b/ui_test/src/lib.rs @@ -76,6 +76,7 @@ pub fn run_tests(mut config: Config) -> Result<()> { // Get the triple with which to run the tests let target = config.target.clone().unwrap_or_else(|| config.get_host()); + eprintln!(" Building test dependencies..."); let dependencies = build_dependencies(&config)?; for (name, dependency) in dependencies.dependencies { config.args.push("--extern".into()); From 4030210aa1e817f7abc8638d5a8d0643a6216d1f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 21 Jul 2022 13:44:16 -0400 Subject: [PATCH 3550/3747] we don't need unstable options --- ui_test/src/dependencies.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/ui_test/src/dependencies.rs b/ui_test/src/dependencies.rs index ab3a0156595f7..1d6bf7af32ef6 100644 --- a/ui_test/src/dependencies.rs +++ b/ui_test/src/dependencies.rs @@ -45,8 +45,7 @@ pub fn build_dependencies(config: &Config) -> Result { setup_command(&mut build); build .arg("--target-dir=target/test_dependencies") - .arg("--message-format=json") - .arg("-Zunstable-options"); + .arg("--message-format=json"); let output = build.output()?; From e286dfa7d3e4f8cf298f3002d15630a15df963d0 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 21 Jul 2022 14:03:58 -0400 Subject: [PATCH 3551/3747] don't force target-dir (cargo-miri already deconflicts that) --- ui_test/src/dependencies.rs | 4 +--- ui_test/src/lib.rs | 2 +- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/ui_test/src/dependencies.rs b/ui_test/src/dependencies.rs index 1d6bf7af32ef6..8ec7090b96a64 100644 --- a/ui_test/src/dependencies.rs +++ b/ui_test/src/dependencies.rs @@ -43,9 +43,7 @@ pub fn build_dependencies(config: &Config) -> Result { }; setup_command(&mut build); - build - .arg("--target-dir=target/test_dependencies") - .arg("--message-format=json"); + build.arg("--message-format=json"); let output = build.output()?; diff --git a/ui_test/src/lib.rs b/ui_test/src/lib.rs index 7fd053eace189..bcc48b4b63169 100644 --- a/ui_test/src/lib.rs +++ b/ui_test/src/lib.rs @@ -54,7 +54,7 @@ pub struct Config { pub struct DependencyBuilder { pub program: PathBuf, pub args: Vec, - pub envs: Vec<(String, String)>, + pub envs: Vec<(String, OsString)>, } #[derive(Debug)] From e3018b8a97f4fb8b67ccd449f4eebb7dd2e204dd Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 21 Jul 2022 15:34:32 -0400 Subject: [PATCH 3552/3747] normalize stronger --- tests/compiletest.rs | 2 +- tests/fail/crates/tokio_mvp.stderr | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/compiletest.rs b/tests/compiletest.rs index 72aa140d66a2b..0f0179de5d243 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -133,7 +133,7 @@ regexes! { // erase platform file paths "sys/[a-z]+/" => "sys/PLATFORM/", // erase paths into the crate registry - r"[^ ]*/\.cargo/registry/.*/(.*\.rs)" => "CARGO_REGISTRY/$1", + r"[^ ]*/\.?cargo/registry/.*/(.*\.rs)" => "CARGO_REGISTRY/.../$1", } fn ui(mode: Mode, path: &str) -> Result<()> { diff --git a/tests/fail/crates/tokio_mvp.stderr b/tests/fail/crates/tokio_mvp.stderr index cff948f364087..8df83662aa023 100644 --- a/tests/fail/crates/tokio_mvp.stderr +++ b/tests/fail/crates/tokio_mvp.stderr @@ -1,5 +1,5 @@ error: unsupported operation: can't call foreign function: epoll_create1 - --> CARGO_REGISTRY/epoll.rs:LL:CC + --> CARGO_REGISTRY/.../epoll.rs:LL:CC | LL | syscall!(epoll_create1(flag)).map(|ep| Selector { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't call foreign function: epoll_create1 From 7c99f90271932500deb6a2147561e7c00dcce716 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 21 Jul 2022 16:58:16 -0400 Subject: [PATCH 3553/3747] cargo-miri: clean up phase dispatching a bit --- cargo-miri/bin.rs | 95 +++++++++++++++++++---------------------------- 1 file changed, 38 insertions(+), 57 deletions(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index 113b0c04a3ae2..c02847dfdd97f 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -60,7 +60,7 @@ struct CrateRunEnv { impl CrateRunEnv { /// Gather all the information we need. - fn collect(args: env::Args, capture_stdin: bool) -> Self { + fn collect(args: impl Iterator, capture_stdin: bool) -> Self { let args = args.collect(); let env = env::vars_os().collect(); let current_dir = env::current_dir().unwrap().into_os_string(); @@ -757,7 +757,7 @@ enum RustcPhase { Rustdoc, } -fn phase_rustc(mut args: env::Args, phase: RustcPhase) { +fn phase_rustc(mut args: impl Iterator, phase: RustcPhase) { /// Determines if we are being invoked (as rustc) to build a crate for /// the "target" architecture, in contrast to the "host" architecture. /// Host crates are for build scripts and proc macros and still need to @@ -978,10 +978,11 @@ enum RunnerPhase { Rustdoc, } -fn phase_runner(binary: &Path, binary_args: impl Iterator, phase: RunnerPhase) { +fn phase_runner(mut binary_args: impl Iterator, phase: RunnerPhase) { let verbose = std::env::var("MIRI_VERBOSE") .map_or(0, |verbose| verbose.parse().expect("verbosity flag must be an integer")); + let binary = binary_args.next().unwrap(); let file = File::open(&binary) .unwrap_or_else(|_| show_error(format!("file {:?} not found or `cargo-miri` invoked incorrectly; please only invoke this binary through `cargo miri`", binary))); let file = BufReader::new(file); @@ -1071,7 +1072,7 @@ fn phase_runner(binary: &Path, binary_args: impl Iterator, phase: } } -fn phase_rustdoc(fst_arg: &str, mut args: env::Args) { +fn phase_rustdoc(mut args: impl Iterator) { let verbose = std::env::var("MIRI_VERBOSE") .map_or(0, |verbose| verbose.parse().expect("verbosity flag must be an integer")); @@ -1079,17 +1080,8 @@ fn phase_rustdoc(fst_arg: &str, mut args: env::Args) { // just default to a straight-forward invocation for now: let mut cmd = Command::new("rustdoc"); - // Because of the way the main function is structured, we have to take the first argument spearately - // from the rest; to simplify the following argument patching loop, we'll just skip that one. - // This is fine for now, because cargo will never pass --extern arguments in the first position, - // but we should defensively assert that this will work. let extern_flag = "--extern"; - assert!(fst_arg != extern_flag); - cmd.arg(fst_arg); - let runtool_flag = "--runtool"; - // `crossmode` records if *any* argument matches `runtool_flag`; here we check the first one. - let mut crossmode = fst_arg == runtool_flag; while let Some(arg) = args.next() { if arg == extern_flag { // Patch --extern arguments to use *.rmeta files, since phase_cargo_rustc only creates stub *.rlib files. @@ -1098,17 +1090,12 @@ fn phase_rustdoc(fst_arg: &str, mut args: env::Args) { // An existing --runtool flag indicates cargo is running in cross-target mode, which we don't support. // Note that this is only passed when cargo is run with the unstable -Zdoctest-xcompile flag; // otherwise, we won't be called as rustdoc at all. - crossmode = true; - break; + show_error(format!("cross-interpreting doctests is not currently supported by Miri.")); } else { cmd.arg(arg); } } - if crossmode { - show_error(format!("cross-interpreting doctests is not currently supported by Miri.")); - } - // Doctests of `proc-macro` crates (and their dependencies) are always built for the host, // so we are not able to run them in Miri. if ArgFlagValueIter::new("--crate-type").any(|crate_type| crate_type == "proc-macro") { @@ -1178,16 +1165,7 @@ fn main() { // since we don't specify any runtool-args, and rustdoc supplies multiple arguments to // the test-builder unconditionally, we can just check the number of remaining arguments: if args.len() == 1 { - let arg = args.next().unwrap(); - let binary = Path::new(&arg); - if binary.exists() { - phase_runner(binary, args, RunnerPhase::Rustdoc); - } else { - show_error(format!( - "`cargo-miri` called with non-existing path argument `{}` in rustdoc mode; please invoke this binary through `cargo miri`", - arg - )); - } + phase_runner(args, RunnerPhase::Rustdoc); } else { phase_rustc(args, RustcPhase::Rustdoc); } @@ -1195,35 +1173,38 @@ fn main() { return; } - match args.next().as_deref() { - Some("miri") => phase_cargo_miri(args), - Some(arg) => { - // If the first arg is equal to the RUSTC variable (which should be set at this point), - // then we need to behave as rustc. This is the somewhat counter-intuitive behavior of - // having both RUSTC and RUSTC_WRAPPER set (see - // https://github.com/rust-lang/cargo/issues/10886). - if arg == env::var_os("RUSTC").unwrap() { - return phase_rustc(args, RustcPhase::Build); - } - // We have to distinguish the "runner" and "rustdoc" cases. - // As runner, the first argument is the binary (a file that should exist, with an absolute path); - // as rustdoc, the first argument is a flag (`--something`). - let binary = Path::new(arg); - if binary.exists() { - assert!(!arg.starts_with("--")); // not a flag - phase_runner(binary, args, RunnerPhase::Cargo); - } else if arg.starts_with("--") { - phase_rustdoc(arg, args); - } else { - show_error(format!( - "`cargo-miri` called with unexpected first argument `{}`; please only invoke this binary through `cargo miri`", - arg - )); - } + let mut args = args.peekable(); + if args.next_if(|a| a == "miri").is_some() { + phase_cargo_miri(args); + } else if let Some(arg) = args.peek().cloned() { + // Cargo calls us for everything it does. We could be invoked as rustc, rustdoc, or the runner. + + // If the first arg is equal to the RUSTC variable (which should be set at this point), + // then we need to behave as rustc. This is the somewhat counter-intuitive behavior of + // having both RUSTC and RUSTC_WRAPPER set (see + // https://github.com/rust-lang/cargo/issues/10886). + if arg == env::var("RUSTC").unwrap() { + args.next().unwrap(); // consume wrapped RUSTC command. + return phase_rustc(args, RustcPhase::Build); } - _ => + // We have to distinguish the "runner" and "rustdoc" cases. + // As runner, the first argument is the binary (a file that should exist, with an absolute path); + // as rustdoc, the first argument is a flag (`--something`). + let binary = Path::new(&arg); + if binary.exists() { + assert!(!arg.starts_with("--")); // not a flag + phase_runner(args, RunnerPhase::Cargo); + } else if arg.starts_with("--") { + phase_rustdoc(args); + } else { show_error(format!( - "`cargo-miri` called without first argument; please only invoke this binary through `cargo miri`" - )), + "`cargo-miri` called with unexpected first argument `{}`; please only invoke this binary through `cargo miri`", + arg + )); + } + } else { + show_error(format!( + "`cargo-miri` called without first argument; please only invoke this binary through `cargo miri`" + )); } } From fb428dfee3252f378f796c7497a8fb29753c795d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 21 Jul 2022 17:04:04 -0400 Subject: [PATCH 3554/3747] avoid redundant setting of env vars in phase_runner --- cargo-miri/bin.rs | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index c02847dfdd97f..8b60d90520ab2 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -1008,14 +1008,16 @@ fn phase_runner(mut binary_args: impl Iterator, phase: RunnerPhas // Set missing env vars. We prefer build-time env vars over run-time ones; see // for the kind of issue that fixes. for (name, val) in info.env { - if verbose > 0 { - if let Some(old_val) = env::var_os(&name) { - if old_val != val { - eprintln!( - "[cargo-miri runner] Overwriting run-time env var {:?}={:?} with build-time value {:?}", - name, old_val, val - ); - } + if let Some(old_val) = env::var_os(&name) { + if old_val == val { + // This one did not actually change, no need to re-set it. + // (This keeps the `debug_cmd` below more manageable.) + continue; + } else if verbose > 0 { + eprintln!( + "[cargo-miri runner] Overwriting run-time env var {:?}={:?} with build-time value {:?}", + name, old_val, val + ); } } cmd.env(name, val); From a6b35412d817dfcb6d4333fb290460044eff742d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 18 Jul 2022 10:38:26 -0400 Subject: [PATCH 3555/3747] adjust for symbolic vtables --- src/intptrcast.rs | 8 +++--- src/machine.rs | 2 +- src/shims/backtrace.rs | 16 ++++++------ src/stacked_borrows/mod.rs | 4 +-- tests/fail/issue-miri-1112.rs | 2 +- tests/fail/issue-miri-1112.stderr | 4 +-- tests/fail/stacked_borrows/vtable.stderr | 25 ------------------- tests/fail/validity/invalid_wide_raw.rs | 2 +- tests/fail/validity/invalid_wide_raw.stderr | 4 +-- .../issues/issue-miri-2123.rs} | 10 +++++--- tests/pass/pointers.rs | 19 +++++++++++++- 11 files changed, 47 insertions(+), 49 deletions(-) delete mode 100644 tests/fail/stacked_borrows/vtable.stderr rename tests/{fail/stacked_borrows/vtable.rs => pass/issues/issue-miri-2123.rs} (54%) diff --git a/src/intptrcast.rs b/src/intptrcast.rs index 442c201e8ece6..aa7111cb81fc6 100644 --- a/src/intptrcast.rs +++ b/src/intptrcast.rs @@ -86,7 +86,9 @@ impl<'mir, 'tcx> GlobalStateInner { if global_state.exposed.contains(&alloc_id) { let (_size, _align, kind) = ecx.get_alloc_info(alloc_id); match kind { - AllocKind::LiveData | AllocKind::Function => return Some(alloc_id), + AllocKind::LiveData | AllocKind::Function | AllocKind::VTable => { + return Some(alloc_id); + } AllocKind::Dead => {} } } @@ -187,8 +189,8 @@ impl<'mir, 'tcx> GlobalStateInner { // Remember next base address. If this allocation is zero-sized, leave a gap // of at least 1 to avoid two allocations having the same base address. - // (The logic in `alloc_id_from_addr` assumes unique addresses, and function - // pointers to different functions need to be distinguishable!) + // (The logic in `alloc_id_from_addr` assumes unique addresses, and different + // function/vtable pointers need to be distinguishable!) global_state.next_base_addr = base_addr.checked_add(max(size.bytes(), 1)).unwrap(); // Given that `next_base_addr` increases in each allocation, pushing the // corresponding tuple keeps `int_to_ptr_map` sorted diff --git a/src/machine.rs b/src/machine.rs index 67a6c997e9902..40f4c9ed90c00 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -733,7 +733,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { if cfg!(debug_assertions) { // The machine promises to never call us on thread-local or extern statics. let alloc_id = ptr.provenance; - match ecx.tcx.get_global_alloc(alloc_id) { + match ecx.tcx.try_get_global_alloc(alloc_id) { Some(GlobalAlloc::Static(def_id)) if ecx.tcx.is_thread_local_static(def_id) => { panic!("adjust_alloc_base_pointer called on thread-local static") } diff --git a/src/shims/backtrace.rs b/src/shims/backtrace.rs index c5aab255aaf84..54ab8665ce35c 100644 --- a/src/shims/backtrace.rs +++ b/src/shims/backtrace.rs @@ -122,15 +122,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); let ptr = this.read_pointer(ptr)?; - // Take apart the pointer, we need its pieces. + // Take apart the pointer, we need its pieces. The offset encodes the span. let (alloc_id, offset, _prov) = this.ptr_get_alloc_id(ptr)?; - let fn_instance = - if let Some(GlobalAlloc::Function(instance)) = this.tcx.get_global_alloc(alloc_id) { - instance - } else { - throw_ub_format!("expected function pointer, found {:?}", ptr); - }; + // This has to be an actual global fn ptr, not a dlsym function. + let fn_instance = if let Some(GlobalAlloc::Function(instance)) = + this.tcx.try_get_global_alloc(alloc_id) + { + instance + } else { + throw_ub_format!("expected static function pointer, found {:?}", ptr); + }; let lo = this.tcx.sess.source_map().lookup_char_pos(BytePos(offset.bytes().try_into().unwrap())); diff --git a/src/stacked_borrows/mod.rs b/src/stacked_borrows/mod.rs index 38a73929a0362..624b32dfd4957 100644 --- a/src/stacked_borrows/mod.rs +++ b/src/stacked_borrows/mod.rs @@ -799,7 +799,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx stacked_borrows.history.log_protector(orig_tag, new_tag, current_span); } } - AllocKind::Function | AllocKind::Dead => { + AllocKind::Function | AllocKind::VTable | AllocKind::Dead => { // No stacked borrows on these allocations. } } @@ -1143,7 +1143,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx trace!("Stacked Borrows tag {tag:?} exposed in {alloc_id:?}"); alloc_extra.stacked_borrows.as_ref().unwrap().borrow_mut().exposed_tags.insert(tag); } - AllocKind::Function | AllocKind::Dead => { + AllocKind::Function | AllocKind::VTable | AllocKind::Dead => { // No stacked borrows on these allocations. } } diff --git a/tests/fail/issue-miri-1112.rs b/tests/fail/issue-miri-1112.rs index abf627bb2a767..387253a3f9872 100644 --- a/tests/fail/issue-miri-1112.rs +++ b/tests/fail/issue-miri-1112.rs @@ -28,7 +28,7 @@ impl FunnyPointer { data: data as *const _ as *const (), vtable: ptr as *const _ as *const (), }; - let obj = std::mem::transmute::(obj); //~ ERROR: invalid drop function pointer in vtable + let obj = std::mem::transmute::(obj); //~ ERROR: expected a vtable pointer &*obj } } diff --git a/tests/fail/issue-miri-1112.stderr b/tests/fail/issue-miri-1112.stderr index 89dc8dc327f82..4a2bdb0f414d4 100644 --- a/tests/fail/issue-miri-1112.stderr +++ b/tests/fail/issue-miri-1112.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: constructing invalid value: encountered invalid drop function pointer in vtable (function has incompatible signature) +error: Undefined Behavior: constructing invalid value: encountered $HEX[ALLOC], but expected a vtable pointer --> $DIR/issue-miri-1112.rs:LL:CC | LL | let obj = std::mem::transmute::(obj); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered invalid drop function pointer in vtable (function has incompatible signature) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered $HEX[ALLOC], but expected a vtable pointer | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/stacked_borrows/vtable.stderr b/tests/fail/stacked_borrows/vtable.stderr deleted file mode 100644 index 534f811e48abe..0000000000000 --- a/tests/fail/stacked_borrows/vtable.stderr +++ /dev/null @@ -1,25 +0,0 @@ -error: Undefined Behavior: constructing invalid value: encountered vtable pointer does not have permission to read drop function pointer - --> RUSTLIB/core/src/ptr/metadata.rs:LL:CC - | -LL | unsafe { PtrRepr { components: PtrComponents { data_address, metadata } }.const_ptr } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered vtable pointer does not have permission to read drop function pointer - | - = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior - = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: - = note: inside `std::ptr::from_raw_parts::` at RUSTLIB/core/src/ptr/metadata.rs:LL:CC -note: inside `uwu` at $DIR/vtable.rs:LL:CC - --> $DIR/vtable.rs:LL:CC - | -LL | core::ptr::from_raw_parts(thin, unsafe { core::mem::transmute(meta) }) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: inside `main` at $DIR/vtable.rs:LL:CC - --> $DIR/vtable.rs:LL:CC - | -LL | let _ = uwu(ptr, core::mem::transmute(meta)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace - -error: aborting due to previous error - diff --git a/tests/fail/validity/invalid_wide_raw.rs b/tests/fail/validity/invalid_wide_raw.rs index 0a2f6f5b152c5..2ad972a9d4d7d 100644 --- a/tests/fail/validity/invalid_wide_raw.rs +++ b/tests/fail/validity/invalid_wide_raw.rs @@ -7,5 +7,5 @@ fn main() { #[allow(dead_code)] x: *mut dyn T, } - dbg!(S { x: unsafe { std::mem::transmute((0usize, 0usize)) } }); //~ ERROR: encountered dangling vtable pointer in wide pointer + dbg!(S { x: unsafe { std::mem::transmute((0usize, 0usize)) } }); //~ ERROR: encountered null pointer, but expected a vtable pointer } diff --git a/tests/fail/validity/invalid_wide_raw.stderr b/tests/fail/validity/invalid_wide_raw.stderr index 624b9764c9e14..304008f651631 100644 --- a/tests/fail/validity/invalid_wide_raw.stderr +++ b/tests/fail/validity/invalid_wide_raw.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: constructing invalid value: encountered dangling vtable pointer in wide pointer +error: Undefined Behavior: constructing invalid value: encountered null pointer, but expected a vtable pointer --> $DIR/invalid_wide_raw.rs:LL:CC | LL | dbg!(S { x: unsafe { std::mem::transmute((0usize, 0usize)) } }); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered dangling vtable pointer in wide pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered null pointer, but expected a vtable pointer | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/stacked_borrows/vtable.rs b/tests/pass/issues/issue-miri-2123.rs similarity index 54% rename from tests/fail/stacked_borrows/vtable.rs rename to tests/pass/issues/issue-miri-2123.rs index 27e035c404bab..9740d2c9ee8ed 100644 --- a/tests/fail/stacked_borrows/vtable.rs +++ b/tests/pass/issues/issue-miri-2123.rs @@ -1,12 +1,13 @@ -//@error-pattern: vtable pointer does not have permission -#![feature(ptr_metadata)] +#![feature(ptr_metadata, layout_for_ptr)] + +use std::{mem, ptr}; trait Foo {} impl Foo for u32 {} fn uwu(thin: *const (), meta: &'static ()) -> *const dyn Foo { - core::ptr::from_raw_parts(thin, unsafe { core::mem::transmute(meta) }) + ptr::from_raw_parts(thin, unsafe { mem::transmute(meta) }) } fn main() { @@ -14,6 +15,7 @@ fn main() { let orig = 1_u32; let x = &orig as &dyn Foo; let (ptr, meta) = (x as *const dyn Foo).to_raw_parts(); - let _ = uwu(ptr, core::mem::transmute(meta)); + let ptr = uwu(ptr, mem::transmute(meta)); + mem::size_of_val_raw(ptr); } } diff --git a/tests/pass/pointers.rs b/tests/pass/pointers.rs index a0c20af426973..a271e764d9f4a 100644 --- a/tests/pass/pointers.rs +++ b/tests/pass/pointers.rs @@ -1,4 +1,7 @@ -use std::mem::transmute; +#![feature(ptr_metadata)] + +use std::mem::{self, transmute}; +use std::ptr; fn one_line_ref() -> i16 { *&1 @@ -71,6 +74,19 @@ fn wide_ptr_ops() { assert!(!(a > b)); } +fn metadata_vtable() { + let p = &0i32 as &dyn std::fmt::Debug; + let meta: ptr::DynMetadata<_> = ptr::metadata(p as *const _); + assert_eq!(meta.size_of(), mem::size_of::()); + assert_eq!(meta.align_of(), mem::align_of::()); + + type T = [i32; 16]; + let p = &T::default() as &dyn std::fmt::Debug; + let meta: ptr::DynMetadata<_> = ptr::metadata(p as *const _); + assert_eq!(meta.size_of(), mem::size_of::()); + assert_eq!(meta.align_of(), mem::align_of::()); +} + fn main() { assert_eq!(one_line_ref(), 1); assert_eq!(basic_ref(), 1); @@ -116,4 +132,5 @@ fn main() { assert!(dangling >= 4); wide_ptr_ops(); + metadata_vtable(); } From bd441b1eb93475107717ffca59202c11263b5e5e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 20 Jul 2022 19:51:19 -0400 Subject: [PATCH 3556/3747] test for some bad use of vtables --- tests/fail/dyn-call-trait-mismatch.rs | 16 ++++++ tests/fail/dyn-call-trait-mismatch.stderr | 15 ++++++ tests/fail/dyn-upcast-trait-mismatch.rs | 58 +++++++++++++++++++++ tests/fail/dyn-upcast-trait-mismatch.stderr | 15 ++++++ 4 files changed, 104 insertions(+) create mode 100644 tests/fail/dyn-call-trait-mismatch.rs create mode 100644 tests/fail/dyn-call-trait-mismatch.stderr create mode 100644 tests/fail/dyn-upcast-trait-mismatch.rs create mode 100644 tests/fail/dyn-upcast-trait-mismatch.stderr diff --git a/tests/fail/dyn-call-trait-mismatch.rs b/tests/fail/dyn-call-trait-mismatch.rs new file mode 100644 index 0000000000000..0e7c3dbcc040f --- /dev/null +++ b/tests/fail/dyn-call-trait-mismatch.rs @@ -0,0 +1,16 @@ +trait T1 { + fn method1(self: Box); +} +trait T2 { + fn method2(self: Box); +} + +impl T1 for i32 { + fn method1(self: Box) {} +} + +fn main() { + let r = Box::new(0) as Box; + let r2: Box = unsafe { std::mem::transmute(r) }; + r2.method2(); //~ERROR: call on a pointer whose vtable does not match its type +} diff --git a/tests/fail/dyn-call-trait-mismatch.stderr b/tests/fail/dyn-call-trait-mismatch.stderr new file mode 100644 index 0000000000000..2673a22a3df26 --- /dev/null +++ b/tests/fail/dyn-call-trait-mismatch.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: `dyn` call on a pointer whose vtable does not match its type + --> $DIR/dyn-call-trait-mismatch.rs:LL:CC + | +LL | r2.method2(); + | ^^^^^^^^^^^^ `dyn` call on a pointer whose vtable does not match its type + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: backtrace: + = note: inside `main` at $DIR/dyn-call-trait-mismatch.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/fail/dyn-upcast-trait-mismatch.rs b/tests/fail/dyn-upcast-trait-mismatch.rs new file mode 100644 index 0000000000000..f53e9a03f4bef --- /dev/null +++ b/tests/fail/dyn-upcast-trait-mismatch.rs @@ -0,0 +1,58 @@ +#![feature(trait_upcasting)] +#![allow(incomplete_features)] + +trait Foo: PartialEq + std::fmt::Debug + Send + Sync { + fn a(&self) -> i32 { + 10 + } + + fn z(&self) -> i32 { + 11 + } + + fn y(&self) -> i32 { + 12 + } +} + +trait Bar: Foo { + fn b(&self) -> i32 { + 20 + } + + fn w(&self) -> i32 { + 21 + } +} + +trait Baz: Bar { + fn c(&self) -> i32 { + 30 + } +} + +impl Foo for i32 { + fn a(&self) -> i32 { + 100 + } +} + +impl Bar for i32 { + fn b(&self) -> i32 { + 200 + } +} + +impl Baz for i32 { + fn c(&self) -> i32 { + 300 + } +} + +fn main() { + let baz: &dyn Baz = &1; + // We already fail on the implicit upcast inserted here. + let baz_fake: &dyn Bar = unsafe { std::mem::transmute(baz) }; + //~^ERROR: upcast on a pointer whose vtable does not match its type + let _err = baz_fake as &dyn Foo; +} diff --git a/tests/fail/dyn-upcast-trait-mismatch.stderr b/tests/fail/dyn-upcast-trait-mismatch.stderr new file mode 100644 index 0000000000000..0e5e22b9b4b99 --- /dev/null +++ b/tests/fail/dyn-upcast-trait-mismatch.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: upcast on a pointer whose vtable does not match its type + --> $DIR/dyn-upcast-trait-mismatch.rs:LL:CC + | +LL | let baz_fake: &dyn Bar = unsafe { std::mem::transmute(baz) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^ upcast on a pointer whose vtable does not match its type + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: backtrace: + = note: inside `main` at $DIR/dyn-upcast-trait-mismatch.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + From 16b15ec9c9fe92d71824182d766c837012b20028 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 22 Jul 2022 07:52:32 -0400 Subject: [PATCH 3557/3747] rustup --- rust-version | 2 +- tests/fail/intrinsics/simd-float-to-int.stderr | 2 +- tests/fail/intrinsics/simd-gather.stderr | 2 +- tests/fail/intrinsics/simd-scatter.stderr | 2 +- tests/pass/issues/issue-miri-2123.rs | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/rust-version b/rust-version index f456ded7f4623..22b5b1a34a65a 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -a7468c60f8dbf5feb23ad840b174d7e57113a846 +e7a9c1141698bc4557b9da3d3fce2bf75339427f diff --git a/tests/fail/intrinsics/simd-float-to-int.stderr b/tests/fail/intrinsics/simd-float-to-int.stderr index 233074105b2b9..ddeda599214f6 100644 --- a/tests/fail/intrinsics/simd-float-to-int.stderr +++ b/tests/fail/intrinsics/simd-float-to-int.stderr @@ -7,7 +7,7 @@ LL | implement! { f32 } = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: backtrace: - = note: inside `core::core_simd::round::>::to_int_unchecked::` at RUSTLIB/core/src/../../portable-simd/crates/core_simd/src/round.rs:LL:CC + = note: inside `core::core_simd::round::>::to_int_unchecked::` at RUSTLIB/core/src/../../portable-simd/crates/core_simd/src/round.rs:LL:CC note: inside `main` at $DIR/simd-float-to-int.rs:LL:CC --> $DIR/simd-float-to-int.rs:LL:CC | diff --git a/tests/fail/intrinsics/simd-gather.stderr b/tests/fail/intrinsics/simd-gather.stderr index 6b935bc6e2549..a23307c05ffbc 100644 --- a/tests/fail/intrinsics/simd-gather.stderr +++ b/tests/fail/intrinsics/simd-gather.stderr @@ -7,7 +7,7 @@ LL | unsafe { intrinsics::simd_gather(or, ptrs, enable.to_int()) } = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: backtrace: - = note: inside `std::simd::Simd::::gather_select_unchecked` at RUSTLIB/core/src/../../portable-simd/crates/core_simd/src/vector.rs:LL:CC + = note: inside `std::simd::Simd::::gather_select_unchecked` at RUSTLIB/core/src/../../portable-simd/crates/core_simd/src/vector.rs:LL:CC note: inside `main` at $DIR/simd-gather.rs:LL:CC --> $DIR/simd-gather.rs:LL:CC | diff --git a/tests/fail/intrinsics/simd-scatter.stderr b/tests/fail/intrinsics/simd-scatter.stderr index 24fc6782f1493..ba8c8f3470601 100644 --- a/tests/fail/intrinsics/simd-scatter.stderr +++ b/tests/fail/intrinsics/simd-scatter.stderr @@ -7,7 +7,7 @@ LL | intrinsics::simd_scatter(self, ptrs, enable.to_int()) = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: backtrace: - = note: inside `std::simd::Simd::::scatter_select_unchecked` at RUSTLIB/core/src/../../portable-simd/crates/core_simd/src/vector.rs:LL:CC + = note: inside `std::simd::Simd::::scatter_select_unchecked` at RUSTLIB/core/src/../../portable-simd/crates/core_simd/src/vector.rs:LL:CC note: inside `main` at $DIR/simd-scatter.rs:LL:CC --> $DIR/simd-scatter.rs:LL:CC | diff --git a/tests/pass/issues/issue-miri-2123.rs b/tests/pass/issues/issue-miri-2123.rs index 9740d2c9ee8ed..e39e5fe454a2c 100644 --- a/tests/pass/issues/issue-miri-2123.rs +++ b/tests/pass/issues/issue-miri-2123.rs @@ -16,6 +16,6 @@ fn main() { let x = &orig as &dyn Foo; let (ptr, meta) = (x as *const dyn Foo).to_raw_parts(); let ptr = uwu(ptr, mem::transmute(meta)); - mem::size_of_val_raw(ptr); + let _size = mem::size_of_val_raw(ptr); } } From 83cbbd7bce12684f044b3c9d6c321723b0a737e7 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 21 Jul 2022 16:49:41 -0400 Subject: [PATCH 3558/3747] support MIRI_HOST_SYSROOT env var for stage 0 builds Together with a patch on the rustc side, this makes './x.py test src/tools/miri --stage 0' work again. :) --- README.md | 2 ++ cargo-miri/bin.rs | 10 ++++++---- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 2214bcf4c59cb..0741f373bb677 100644 --- a/README.md +++ b/README.md @@ -445,6 +445,8 @@ binaries, and as such worth documenting: crate currently being compiled. * `MIRI_VERBOSE` when set to any value tells the various `cargo-miri` phases to perform verbose logging. +* `MIRI_HOST_SYSROOT` is set by bootstrap to tell `cargo-miri` which sysroot to use for *host* + operations. [testing-miri]: CONTRIBUTING.md#testing-the-miri-driver diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index 8b60d90520ab2..bb2eb54ffebca 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -721,7 +721,9 @@ fn phase_cargo_miri(mut args: impl Iterator) { // hope that all they do is ask for the version number -- things could quickly go downhill from here. // In `main`, we need the value of `RUSTC` to distinguish RUSTC_WRAPPER invocations from rustdoc // or TARGET_RUNNER invocations, so we canonicalize it here to make it exceedingly unlikely that - // there would be a collision. + // there would be a collision with other invocations of cargo-miri (as rustdoc or as runner). + // We explicitly do this even if RUSTC_STAGE is set, since for these builds we do *not* want the + // bootstrap `rustc` thing in our way! Instead, we have MIRI_HOST_SYSROOT to use for host builds. cmd.env("RUSTC", &fs::canonicalize(find_miri()).unwrap()); let runner_env_name = @@ -929,9 +931,9 @@ fn phase_rustc(mut args: impl Iterator, phase: RustcPhase) { } else { // For host crates (but not when we are printing), we might still have to set the sysroot. if !print { - // When we're running `cargo-miri` from `x.py` we need to pass the sysroot explicitly as rustc - // can't figure out the sysroot on its own unless it's from rustup. - if let Some(sysroot) = std::env::var_os("SYSROOT") { + // When we're running `cargo-miri` from `x.py` we need to pass the sysroot explicitly + // due to bootstrap complications. + if let Some(sysroot) = std::env::var_os("MIRI_HOST_SYSROOT") { cmd.arg("--sysroot").arg(sysroot); } } From e8b3d56565e1ba5f47f5154b1147acafedad6b5a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 21 Mar 2022 09:15:38 -0400 Subject: [PATCH 3559/3747] test bitmasks smaller than a byte --- tests/pass/portable-simd.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/pass/portable-simd.rs b/tests/pass/portable-simd.rs index 0dfe617bd8dc9..ceefd180dffe2 100644 --- a/tests/pass/portable-simd.rs +++ b/tests/pass/portable-simd.rs @@ -201,7 +201,7 @@ fn simd_mask() { let values = [false, false, false, true]; let mask = Mask::::from_array(values); let bitmask = mask.to_bitmask(); - // FIXME fails until https://github.com/rust-lang/portable-simd/pull/267 lands: assert_eq!(bitmask, 0b1000); + assert_eq!(bitmask, 0b1000); assert_eq!(Mask::::from_bitmask(bitmask), mask); } From 45eeaa362bfd3193b508123fac1163c8c3a1ab3b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 22 Jul 2022 08:49:03 -0400 Subject: [PATCH 3560/3747] rustup --- rust-version | 2 +- .../fail/intrinsics/simd-float-to-int.stderr | 9 ++- tests/pass/portable-simd.rs | 56 +++++++++---------- 3 files changed, 33 insertions(+), 34 deletions(-) diff --git a/rust-version b/rust-version index 22b5b1a34a65a..b54ff9e100ed0 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -e7a9c1141698bc4557b9da3d3fce2bf75339427f +41419e70366962c9a878bfe673ef4df38db6f7f1 diff --git a/tests/fail/intrinsics/simd-float-to-int.stderr b/tests/fail/intrinsics/simd-float-to-int.stderr index ddeda599214f6..d29b356d268dc 100644 --- a/tests/fail/intrinsics/simd-float-to-int.stderr +++ b/tests/fail/intrinsics/simd-float-to-int.stderr @@ -1,19 +1,18 @@ error: Undefined Behavior: `float_to_int_unchecked` intrinsic called on 3.40282347E+38 which cannot be represented in target type `i32` - --> RUSTLIB/core/src/../../portable-simd/crates/core_simd/src/round.rs:LL:CC + --> RUSTLIB/core/src/../../portable-simd/crates/core_simd/src/vector.rs:LL:CC | -LL | implement! { f32 } - | ^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on 3.40282347E+38 which cannot be represented in target type `i32` +LL | unsafe { intrinsics::simd_cast(self) } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ `float_to_int_unchecked` intrinsic called on 3.40282347E+38 which cannot be represented in target type `i32` | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: backtrace: - = note: inside `core::core_simd::round::>::to_int_unchecked::` at RUSTLIB/core/src/../../portable-simd/crates/core_simd/src/round.rs:LL:CC + = note: inside `std::simd::Simd::::to_int_unchecked::` at RUSTLIB/core/src/../../portable-simd/crates/core_simd/src/vector.rs:LL:CC note: inside `main` at $DIR/simd-float-to-int.rs:LL:CC --> $DIR/simd-float-to-int.rs:LL:CC | LL | let _x: i32x2 = f32x2::from_array([f32::MAX, f32::MIN]).to_int_unchecked(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: this error originates in the macro `implement` (in Nightly builds, run with -Z macro-backtrace for more info) note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/pass/portable-simd.rs b/tests/pass/portable-simd.rs index ceefd180dffe2..ec70eea6b1771 100644 --- a/tests/pass/portable-simd.rs +++ b/tests/pass/portable-simd.rs @@ -13,20 +13,20 @@ fn simd_ops_f32() { assert_eq!(a / f32x4::splat(2.0), f32x4::splat(5.0)); assert_eq!(a % b, f32x4::from_array([0.0, 0.0, 1.0, 2.0])); assert_eq!(b.abs(), f32x4::from_array([1.0, 2.0, 3.0, 4.0])); - assert_eq!(a.max(b * f32x4::splat(4.0)), f32x4::from_array([10.0, 10.0, 12.0, 10.0])); - assert_eq!(a.min(b * f32x4::splat(4.0)), f32x4::from_array([4.0, 8.0, 10.0, -16.0])); + assert_eq!(a.simd_max(b * f32x4::splat(4.0)), f32x4::from_array([10.0, 10.0, 12.0, 10.0])); + assert_eq!(a.simd_min(b * f32x4::splat(4.0)), f32x4::from_array([4.0, 8.0, 10.0, -16.0])); assert_eq!(a.mul_add(b, a), (a * b) + a); assert_eq!(b.mul_add(b, a), (b * b) + a); assert_eq!((a * a).sqrt(), a); assert_eq!((b * b).sqrt(), b.abs()); - assert_eq!(a.lanes_eq(f32x4::splat(5.0) * b), Mask::from_array([false, true, false, false])); - assert_eq!(a.lanes_ne(f32x4::splat(5.0) * b), Mask::from_array([true, false, true, true])); - assert_eq!(a.lanes_le(f32x4::splat(5.0) * b), Mask::from_array([false, true, true, false])); - assert_eq!(a.lanes_lt(f32x4::splat(5.0) * b), Mask::from_array([false, false, true, false])); - assert_eq!(a.lanes_ge(f32x4::splat(5.0) * b), Mask::from_array([true, true, false, true])); - assert_eq!(a.lanes_gt(f32x4::splat(5.0) * b), Mask::from_array([true, false, false, true])); + assert_eq!(a.simd_eq(f32x4::splat(5.0) * b), Mask::from_array([false, true, false, false])); + assert_eq!(a.simd_ne(f32x4::splat(5.0) * b), Mask::from_array([true, false, true, true])); + assert_eq!(a.simd_le(f32x4::splat(5.0) * b), Mask::from_array([false, true, true, false])); + assert_eq!(a.simd_lt(f32x4::splat(5.0) * b), Mask::from_array([false, false, true, false])); + assert_eq!(a.simd_ge(f32x4::splat(5.0) * b), Mask::from_array([true, true, false, true])); + assert_eq!(a.simd_gt(f32x4::splat(5.0) * b), Mask::from_array([true, false, false, true])); assert_eq!(a.reduce_sum(), 40.0); assert_eq!(b.reduce_sum(), 2.0); @@ -38,13 +38,13 @@ fn simd_ops_f32() { assert_eq!(b.reduce_min(), -4.0); assert_eq!( - f32x2::from_array([0.0, f32::NAN]).max(f32x2::from_array([f32::NAN, 0.0])), + f32x2::from_array([0.0, f32::NAN]).simd_max(f32x2::from_array([f32::NAN, 0.0])), f32x2::from_array([0.0, 0.0]) ); assert_eq!(f32x2::from_array([0.0, f32::NAN]).reduce_max(), 0.0); assert_eq!(f32x2::from_array([f32::NAN, 0.0]).reduce_max(), 0.0); assert_eq!( - f32x2::from_array([0.0, f32::NAN]).min(f32x2::from_array([f32::NAN, 0.0])), + f32x2::from_array([0.0, f32::NAN]).simd_min(f32x2::from_array([f32::NAN, 0.0])), f32x2::from_array([0.0, 0.0]) ); assert_eq!(f32x2::from_array([0.0, f32::NAN]).reduce_min(), 0.0); @@ -62,20 +62,20 @@ fn simd_ops_f64() { assert_eq!(a / f64x4::splat(2.0), f64x4::splat(5.0)); assert_eq!(a % b, f64x4::from_array([0.0, 0.0, 1.0, 2.0])); assert_eq!(b.abs(), f64x4::from_array([1.0, 2.0, 3.0, 4.0])); - assert_eq!(a.max(b * f64x4::splat(4.0)), f64x4::from_array([10.0, 10.0, 12.0, 10.0])); - assert_eq!(a.min(b * f64x4::splat(4.0)), f64x4::from_array([4.0, 8.0, 10.0, -16.0])); + assert_eq!(a.simd_max(b * f64x4::splat(4.0)), f64x4::from_array([10.0, 10.0, 12.0, 10.0])); + assert_eq!(a.simd_min(b * f64x4::splat(4.0)), f64x4::from_array([4.0, 8.0, 10.0, -16.0])); assert_eq!(a.mul_add(b, a), (a * b) + a); assert_eq!(b.mul_add(b, a), (b * b) + a); assert_eq!((a * a).sqrt(), a); assert_eq!((b * b).sqrt(), b.abs()); - assert_eq!(a.lanes_eq(f64x4::splat(5.0) * b), Mask::from_array([false, true, false, false])); - assert_eq!(a.lanes_ne(f64x4::splat(5.0) * b), Mask::from_array([true, false, true, true])); - assert_eq!(a.lanes_le(f64x4::splat(5.0) * b), Mask::from_array([false, true, true, false])); - assert_eq!(a.lanes_lt(f64x4::splat(5.0) * b), Mask::from_array([false, false, true, false])); - assert_eq!(a.lanes_ge(f64x4::splat(5.0) * b), Mask::from_array([true, true, false, true])); - assert_eq!(a.lanes_gt(f64x4::splat(5.0) * b), Mask::from_array([true, false, false, true])); + assert_eq!(a.simd_eq(f64x4::splat(5.0) * b), Mask::from_array([false, true, false, false])); + assert_eq!(a.simd_ne(f64x4::splat(5.0) * b), Mask::from_array([true, false, true, true])); + assert_eq!(a.simd_le(f64x4::splat(5.0) * b), Mask::from_array([false, true, true, false])); + assert_eq!(a.simd_lt(f64x4::splat(5.0) * b), Mask::from_array([false, false, true, false])); + assert_eq!(a.simd_ge(f64x4::splat(5.0) * b), Mask::from_array([true, true, false, true])); + assert_eq!(a.simd_gt(f64x4::splat(5.0) * b), Mask::from_array([true, false, false, true])); assert_eq!(a.reduce_sum(), 40.0); assert_eq!(b.reduce_sum(), 2.0); @@ -87,13 +87,13 @@ fn simd_ops_f64() { assert_eq!(b.reduce_min(), -4.0); assert_eq!( - f64x2::from_array([0.0, f64::NAN]).max(f64x2::from_array([f64::NAN, 0.0])), + f64x2::from_array([0.0, f64::NAN]).simd_max(f64x2::from_array([f64::NAN, 0.0])), f64x2::from_array([0.0, 0.0]) ); assert_eq!(f64x2::from_array([0.0, f64::NAN]).reduce_max(), 0.0); assert_eq!(f64x2::from_array([f64::NAN, 0.0]).reduce_max(), 0.0); assert_eq!( - f64x2::from_array([0.0, f64::NAN]).min(f64x2::from_array([f64::NAN, 0.0])), + f64x2::from_array([0.0, f64::NAN]).simd_min(f64x2::from_array([f64::NAN, 0.0])), f64x2::from_array([0.0, 0.0]) ); assert_eq!(f64x2::from_array([0.0, f64::NAN]).reduce_min(), 0.0); @@ -113,8 +113,8 @@ fn simd_ops_i32() { assert_eq!(a % b, i32x4::from_array([0, 0, 1, 2])); assert_eq!(i32x2::splat(i32::MIN) % i32x2::splat(-1), i32x2::splat(0)); assert_eq!(b.abs(), i32x4::from_array([1, 2, 3, 4])); - assert_eq!(a.max(b * i32x4::splat(4)), i32x4::from_array([10, 10, 12, 10])); - assert_eq!(a.min(b * i32x4::splat(4)), i32x4::from_array([4, 8, 10, -16])); + assert_eq!(a.simd_max(b * i32x4::splat(4)), i32x4::from_array([10, 10, 12, 10])); + assert_eq!(a.simd_min(b * i32x4::splat(4)), i32x4::from_array([4, 8, 10, -16])); assert_eq!( i8x4::from_array([i8::MAX, -23, 23, i8::MIN]).saturating_add(i8x4::from_array([ @@ -160,12 +160,12 @@ fn simd_ops_i32() { assert_eq!(b | i32x4::splat(2), i32x4::from_array([3, 2, 3, -2])); assert_eq!(b ^ i32x4::splat(2), i32x4::from_array([3, 0, 1, -2])); - assert_eq!(a.lanes_eq(i32x4::splat(5) * b), Mask::from_array([false, true, false, false])); - assert_eq!(a.lanes_ne(i32x4::splat(5) * b), Mask::from_array([true, false, true, true])); - assert_eq!(a.lanes_le(i32x4::splat(5) * b), Mask::from_array([false, true, true, false])); - assert_eq!(a.lanes_lt(i32x4::splat(5) * b), Mask::from_array([false, false, true, false])); - assert_eq!(a.lanes_ge(i32x4::splat(5) * b), Mask::from_array([true, true, false, true])); - assert_eq!(a.lanes_gt(i32x4::splat(5) * b), Mask::from_array([true, false, false, true])); + assert_eq!(a.simd_eq(i32x4::splat(5) * b), Mask::from_array([false, true, false, false])); + assert_eq!(a.simd_ne(i32x4::splat(5) * b), Mask::from_array([true, false, true, true])); + assert_eq!(a.simd_le(i32x4::splat(5) * b), Mask::from_array([false, true, true, false])); + assert_eq!(a.simd_lt(i32x4::splat(5) * b), Mask::from_array([false, false, true, false])); + assert_eq!(a.simd_ge(i32x4::splat(5) * b), Mask::from_array([true, true, false, true])); + assert_eq!(a.simd_gt(i32x4::splat(5) * b), Mask::from_array([true, false, false, true])); assert_eq!(a.reduce_sum(), 40); assert_eq!(b.reduce_sum(), 2); From 1787c731abdb2bf395ffdd83b8cfbc6e8420065c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 22 Jul 2022 10:34:52 -0400 Subject: [PATCH 3561/3747] add more track_caller tests --- tests/pass/track-caller-attribute.rs | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/tests/pass/track-caller-attribute.rs b/tests/pass/track-caller-attribute.rs index dd1e2f809adfe..6694764a234d4 100644 --- a/tests/pass/track-caller-attribute.rs +++ b/tests/pass/track-caller-attribute.rs @@ -66,6 +66,27 @@ fn test_trait_obj() { assert_eq!(location.column(), 28); } +fn test_trait_obj2() { + // track_caller on the impl but not the trait. + pub trait Foo { + fn foo(&self) -> &'static Location<'static>; + } + + struct Bar; + impl Foo for Bar { + #[track_caller] + fn foo(&self) -> &'static Location<'static> { + std::panic::Location::caller() + } + } + let expected_line = line!() - 4; // the `fn` signature above + + let f = &Bar as &dyn Foo; + let loc = f.foo(); // trait doesn't track, so we don't point at this call site + assert_eq!(loc.file(), file!()); + assert_eq!(loc.line(), expected_line); +} + fn main() { let location = Location::caller(); let expected_line = line!() - 1; @@ -105,4 +126,5 @@ fn main() { test_fn_ptr(); test_trait_obj(); + test_trait_obj2(); } From 00b382d1a5854ccefad7378968b1f6df66bf2da9 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 22 Jul 2022 20:53:20 -0400 Subject: [PATCH 3562/3747] add num_cpus crate test --- test_dependencies/Cargo.lock | 1 + test_dependencies/Cargo.toml | 1 + tests/pass/crates/num_cpus.rs | 5 +++++ tests/pass/crates/random.rs | 2 +- 4 files changed, 8 insertions(+), 1 deletion(-) create mode 100644 tests/pass/crates/num_cpus.rs diff --git a/test_dependencies/Cargo.lock b/test_dependencies/Cargo.lock index a492deba4c528..d4b32e2c29a22 100644 --- a/test_dependencies/Cargo.lock +++ b/test_dependencies/Cargo.lock @@ -107,6 +107,7 @@ dependencies = [ "getrandom 0.1.16", "getrandom 0.2.7", "libc", + "num_cpus", "page_size", "rand", "tokio", diff --git a/test_dependencies/Cargo.toml b/test_dependencies/Cargo.toml index 0bf43aefebffb..58f731f91d0f4 100644 --- a/test_dependencies/Cargo.toml +++ b/test_dependencies/Cargo.toml @@ -12,6 +12,7 @@ edition = "2021" tokio = { version = "1.0", features = ["full"] } libc = "0.2" page_size = "0.4.1" +num_cpus = "1.10.1" getrandom_1 = { package = "getrandom", version = "0.1" } getrandom_2 = { package = "getrandom", version = "0.2" } diff --git a/tests/pass/crates/num_cpus.rs b/tests/pass/crates/num_cpus.rs new file mode 100644 index 0000000000000..84339feb11e17 --- /dev/null +++ b/tests/pass/crates/num_cpus.rs @@ -0,0 +1,5 @@ +//@compile-flags: -Zmiri-disable-isolation + +fn main() { + assert_eq!(num_cpus::get(), 1); +} diff --git a/tests/pass/crates/random.rs b/tests/pass/crates/random.rs index 808d1006d4f3a..5eccf3b0ea115 100644 --- a/tests/pass/crates/random.rs +++ b/tests/pass/crates/random.rs @@ -1,6 +1,6 @@ -use rand::{rngs::SmallRng, Rng, SeedableRng}; // mac-os `getrandom_1` does some pointer shenanigans //@compile-flags: -Zmiri-permissive-provenance +use rand::{rngs::SmallRng, Rng, SeedableRng}; fn main() { // Test `getrandom` directly (in multiple different versions). From 34922be8013235f37de66cf79573ed2bd2678d85 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 22 Jul 2022 20:53:31 -0400 Subject: [PATCH 3563/3747] remove num_cpus test from test-cargo-miri --- test-cargo-miri/Cargo.lock | 27 +-------------------------- test-cargo-miri/subcrate/Cargo.toml | 2 +- test-cargo-miri/subcrate/test.rs | 6 ++++-- 3 files changed, 6 insertions(+), 29 deletions(-) diff --git a/test-cargo-miri/Cargo.lock b/test-cargo-miri/Cargo.lock index 3f61fb3d5408d..38bfb2ac62077 100644 --- a/test-cargo-miri/Cargo.lock +++ b/test-cargo-miri/Cargo.lock @@ -48,15 +48,6 @@ dependencies = [ name = "exported_symbol_dep" version = "0.1.0" -[[package]] -name = "hermit-abi" -version = "0.1.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" -dependencies = [ - "libc", -] - [[package]] name = "issue_1567" version = "0.1.0" @@ -83,22 +74,6 @@ version = "0.1.0" name = "issue_rust_86261" version = "0.1.0" -[[package]] -name = "libc" -version = "0.2.126" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836" - -[[package]] -name = "num_cpus" -version = "1.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1" -dependencies = [ - "hermit-abi", - "libc", -] - [[package]] name = "proc-macro2" version = "1.0.40" @@ -132,7 +107,7 @@ dependencies = [ name = "subcrate" version = "0.1.0" dependencies = [ - "num_cpus", + "byteorder 1.4.3", ] [[package]] diff --git a/test-cargo-miri/subcrate/Cargo.toml b/test-cargo-miri/subcrate/Cargo.toml index ea2936d52a054..06b1ce1cba4b8 100644 --- a/test-cargo-miri/subcrate/Cargo.toml +++ b/test-cargo-miri/subcrate/Cargo.toml @@ -18,4 +18,4 @@ path = "test.rs" harness = false [dev-dependencies] -num_cpus = "1.10.1" +byteorder = "1.0" diff --git a/test-cargo-miri/subcrate/test.rs b/test-cargo-miri/subcrate/test.rs index fdab9402813be..77e3c2878ca0e 100644 --- a/test-cargo-miri/subcrate/test.rs +++ b/test-cargo-miri/subcrate/test.rs @@ -1,5 +1,7 @@ use std::env; +use byteorder::{ByteOrder, LittleEndian}; + fn main() { println!("subcrate testing"); @@ -11,6 +13,6 @@ fn main() { let crate_dir = crate_dir.to_string_lossy().replace("\\", "/"); assert_eq!(env_dir, crate_dir); - // Make sure we can call `num_cpus`. - num_cpus::get(); + // Make sure we can call dev-dependencies. + let _n = ::read_u32(&[1, 2, 3, 4]); } From 3f0fdf290fe523fdbb6be21eafe4915638373fe8 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 23 Jul 2022 08:24:33 -0400 Subject: [PATCH 3564/3747] pass clippy::cast_lossless --- src/lib.rs | 3 ++- src/shims/env.rs | 2 +- src/shims/tls.rs | 2 +- src/stacked_borrows/item.rs | 2 +- 4 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 35351664caf4e..1a07ce9aa12bd 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -9,7 +9,7 @@ #![feature(is_some_with)] #![feature(nonzero_ops)] #![feature(local_key_cell_methods)] -#![warn(rust_2018_idioms)] +// Configure clippy and other lints #![allow( clippy::collapsible_else_if, clippy::collapsible_if, @@ -24,6 +24,7 @@ clippy::derive_hash_xor_eq, clippy::too_many_arguments )] +#![warn(rust_2018_idioms, clippy::cast_lossless)] extern crate rustc_apfloat; extern crate rustc_ast; diff --git a/src/shims/env.rs b/src/shims/env.rs index f0818e71b6670..c1d39dc092865 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -202,7 +202,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let env_block_ptr = this.read_pointer(env_block_op)?; let result = this.deallocate_ptr(env_block_ptr, None, MiriMemoryKind::Runtime.into()); // If the function succeeds, the return value is nonzero. - Ok(result.is_ok() as i32) + Ok(i32::from(result.is_ok())) } fn setenv( diff --git a/src/shims/tls.rs b/src/shims/tls.rs index 13af447f76c67..9d19160b84d63 100644 --- a/src/shims/tls.rs +++ b/src/shims/tls.rs @@ -73,7 +73,7 @@ impl<'tcx> TlsData<'tcx> { self.keys.try_insert(new_key, TlsEntry { data: Default::default(), dtor }).unwrap(); trace!("New TLS key allocated: {} with dtor {:?}", new_key, dtor); - if max_size.bits() < 128 && new_key >= (1u128 << max_size.bits() as u128) { + if max_size.bits() < 128 && new_key >= (1u128 << max_size.bits()) { throw_unsup_format!("we ran out of TLS key space"); } Ok(new_key) diff --git a/src/stacked_borrows/item.rs b/src/stacked_borrows/item.rs index ad1b9b075b40f..709b27d191b26 100644 --- a/src/stacked_borrows/item.rs +++ b/src/stacked_borrows/item.rs @@ -22,7 +22,7 @@ impl Item { assert!(tag.0.get() <= TAG_MASK); let packed_tag = tag.0.get(); let packed_perm = perm.to_bits() << PERM_SHIFT; - let packed_protected = (protected as u64) << PROTECTED_SHIFT; + let packed_protected = u64::from(protected) << PROTECTED_SHIFT; let new = Self(packed_tag | packed_perm | packed_protected); From b67a6ff09911736f331933074939dd4fb7b38200 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 23 Jul 2022 08:35:45 -0400 Subject: [PATCH 3565/3747] pass clippy::cast_sign_loss and clippy::cast_possible_wrap --- src/intptrcast.rs | 1 + src/lib.rs | 7 ++++++- src/shims/env.rs | 2 +- src/shims/foreign_items.rs | 12 ++++++++++-- src/shims/unix/fs.rs | 8 ++++++-- src/shims/windows/dlsym.rs | 2 +- 6 files changed, 25 insertions(+), 7 deletions(-) diff --git a/src/intptrcast.rs b/src/intptrcast.rs index aa7111cb81fc6..99fc086a229cd 100644 --- a/src/intptrcast.rs +++ b/src/intptrcast.rs @@ -230,6 +230,7 @@ impl<'mir, 'tcx> GlobalStateInner { // Wrapping "addr - base_addr" let dl = ecx.data_layout(); + #[allow(clippy::cast_possible_wrap)] // we want to wrap here let neg_base_addr = (base_addr as i64).wrapping_neg(); Some(( alloc_id, diff --git a/src/lib.rs b/src/lib.rs index 1a07ce9aa12bd..c1b0c4afca68c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -24,7 +24,12 @@ clippy::derive_hash_xor_eq, clippy::too_many_arguments )] -#![warn(rust_2018_idioms, clippy::cast_lossless)] +#![warn( + rust_2018_idioms, + clippy::cast_possible_wrap, // unsigned -> signed + clippy::cast_sign_loss, // signed -> unsigned + clippy::cast_lossless, +)] extern crate rustc_apfloat; extern crate rustc_ast; diff --git a/src/shims/env.rs b/src/shims/env.rs index c1d39dc092865..db1ddf6291fd9 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -459,7 +459,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // The reason we need to do this wacky of a conversion is because // `libc::getpid` returns an i32, however, `std::process::id()` return an u32. // So we un-do the conversion that stdlib does and turn it back into an i32. - + #[allow(clippy::cast_possible_wrap)] Ok(std::process::id() as i32) } diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 99f0617162192..317eab082c0c2 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -526,8 +526,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "memrchr" => { let [ptr, val, num] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let ptr = this.read_pointer(ptr)?; - let val = this.read_scalar(val)?.to_i32()? as u8; + let val = this.read_scalar(val)?.to_i32()?; let num = this.read_scalar(num)?.to_machine_usize(this)?; + // The docs say val is "interpreted as unsigned char". + #[allow(clippy::cast_sign_loss)] + let val = val as u8; + if let Some(idx) = this .read_bytes_ptr(ptr, Size::from_bytes(num))? .iter() @@ -543,8 +547,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "memchr" => { let [ptr, val, num] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let ptr = this.read_pointer(ptr)?; - let val = this.read_scalar(val)?.to_i32()? as u8; + let val = this.read_scalar(val)?.to_i32()?; let num = this.read_scalar(num)?.to_machine_usize(this)?; + // The docs say val is "interpreted as unsigned char". + #[allow(clippy::cast_sign_loss)] + let val = val as u8; + let idx = this .read_bytes_ptr(ptr, Size::from_bytes(num))? .iter() diff --git a/src/shims/unix/fs.rs b/src/shims/unix/fs.rs index 50a2053078f85..3b82cb3c4eb8a 100644 --- a/src/shims/unix/fs.rs +++ b/src/shims/unix/fs.rs @@ -776,7 +776,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // We cap the number of read bytes to the largest value that we are able to fit in both the // host's and target's `isize`. This saves us from having to handle overflows later. - let count = count.min(this.machine_isize_max() as u64).min(isize::MAX as u64); + let count = count + .min(u64::try_from(this.machine_isize_max()).unwrap()) + .min(u64::try_from(isize::MAX).unwrap()); let communicate = this.machine.communicate(); if let Some(file_descriptor) = this.machine.file_handler.handles.get_mut(&fd) { @@ -827,7 +829,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // We cap the number of written bytes to the largest value that we are able to fit in both the // host's and target's `isize`. This saves us from having to handle overflows later. - let count = count.min(this.machine_isize_max() as u64).min(isize::MAX as u64); + let count = count + .min(u64::try_from(this.machine_isize_max()).unwrap()) + .min(u64::try_from(isize::MAX).unwrap()); let communicate = this.machine.communicate(); if let Some(file_descriptor) = this.machine.file_handler.handles.get(&fd) { diff --git a/src/shims/windows/dlsym.rs b/src/shims/windows/dlsym.rs index ee4f392277721..51b0e3b83d473 100644 --- a/src/shims/windows/dlsym.rs +++ b/src/shims/windows/dlsym.rs @@ -102,7 +102,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Return whether this was a success. >= 0 is success. // For the error code we arbitrarily pick 0xC0000185, STATUS_IO_DEVICE_ERROR. this.write_scalar( - Scalar::from_i32(if written.is_some() { 0 } else { 0xC0000185u32 as i32 }), + Scalar::from_u32(if written.is_some() { 0 } else { 0xC0000185u32 }), dest, )?; } From 7f6034862d0a22c7337eb428c67fcdb23b9168ae Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 23 Jul 2022 08:44:16 -0400 Subject: [PATCH 3566/3747] pass clippy::cast_possible_truncation --- src/lib.rs | 1 + src/shims/backtrace.rs | 6 ++++-- src/shims/foreign_items.rs | 12 ++++++++---- src/shims/intrinsics/mod.rs | 5 +---- src/shims/unix/fs.rs | 4 ++-- src/shims/windows/dlsym.rs | 3 ++- src/shims/windows/foreign_items.rs | 2 +- 7 files changed, 19 insertions(+), 14 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index c1b0c4afca68c..caae17b202235 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -29,6 +29,7 @@ clippy::cast_possible_wrap, // unsigned -> signed clippy::cast_sign_loss, // signed -> unsigned clippy::cast_lossless, + clippy::cast_possible_truncation, )] extern crate rustc_apfloat; diff --git a/src/shims/backtrace.rs b/src/shims/backtrace.rs index 54ab8665ce35c..9182b2a72173b 100644 --- a/src/shims/backtrace.rs +++ b/src/shims/backtrace.rs @@ -171,9 +171,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ); } - let lineno: u32 = lo.line as u32; + // `u32` is not enough to fit line/colno, which can be `usize`. It seems unlikely that a + // file would have more than 2^32 lines or columns, but whatever, just default to 0. + let lineno: u32 = u32::try_from(lo.line).unwrap_or(0); // `lo.col` is 0-based - add 1 to make it 1-based for the caller. - let colno: u32 = lo.col.0 as u32 + 1; + let colno: u32 = u32::try_from(lo.col.0 + 1).unwrap_or(0); let dest = this.force_allocation(dest)?; if let ty::Adt(adt, _) = dest.layout.ty.kind() { diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 317eab082c0c2..208e7ea788f7d 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -82,8 +82,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let align = this.min_align(size, kind); let ptr = this.allocate_ptr(Size::from_bytes(size), align, kind.into())?; if zero_init { - // We just allocated this, the access is definitely in-bounds. - this.write_bytes_ptr(ptr.into(), iter::repeat(0u8).take(size as usize)).unwrap(); + // We just allocated this, the access is definitely in-bounds and fits into our address space. + this.write_bytes_ptr( + ptr.into(), + iter::repeat(0u8).take(usize::try_from(size).unwrap()), + ) + .unwrap(); } Ok(ptr.into()) } @@ -529,7 +533,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let val = this.read_scalar(val)?.to_i32()?; let num = this.read_scalar(num)?.to_machine_usize(this)?; // The docs say val is "interpreted as unsigned char". - #[allow(clippy::cast_sign_loss)] + #[allow(clippy::cast_sign_loss, clippy::cast_possible_truncation)] let val = val as u8; if let Some(idx) = this @@ -550,7 +554,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let val = this.read_scalar(val)?.to_i32()?; let num = this.read_scalar(num)?.to_machine_usize(this)?; // The docs say val is "interpreted as unsigned char". - #[allow(clippy::cast_sign_loss)] + #[allow(clippy::cast_sign_loss, clippy::cast_possible_truncation)] let val = val as u8; let idx = this diff --git a/src/shims/intrinsics/mod.rs b/src/shims/intrinsics/mod.rs index c07ed8b294891..4c2d08ffceabc 100644 --- a/src/shims/intrinsics/mod.rs +++ b/src/shims/intrinsics/mod.rs @@ -117,10 +117,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let byte_count = ty_layout.size.checked_mul(count, this).ok_or_else(|| { err_ub_format!("overflow computing total size of `{intrinsic_name}`") })?; - this.write_bytes_ptr( - ptr, - iter::repeat(val_byte).take(byte_count.bytes() as usize), - )?; + this.write_bytes_ptr(ptr, iter::repeat(val_byte).take(byte_count.bytes_usize()))?; } // Floating-point operations diff --git a/src/shims/unix/fs.rs b/src/shims/unix/fs.rs index 3b82cb3c4eb8a..dc31237a31997 100644 --- a/src/shims/unix/fs.rs +++ b/src/shims/unix/fs.rs @@ -785,8 +785,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx trace!("read: FD mapped to {:?}", file_descriptor); // We want to read at most `count` bytes. We are sure that `count` is not negative // because it was a target's `usize`. Also we are sure that its smaller than - // `usize::MAX` because it is a host's `isize`. - let mut bytes = vec![0; count as usize]; + // `usize::MAX` because it is bounded by the host's `isize`. + let mut bytes = vec![0; usize::try_from(count).unwrap()]; // `File::read` never returns a value larger than `count`, // so this cannot fail. let result = diff --git a/src/shims/windows/dlsym.rs b/src/shims/windows/dlsym.rs index 51b0e3b83d473..eab5f99c87851 100644 --- a/src/shims/windows/dlsym.rs +++ b/src/shims/windows/dlsym.rs @@ -84,7 +84,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } else { io::stderr().write(buf_cont) }; - res.ok().map(|n| n as u32) + // We write at most `n` bytes, which is a `u32`, so we cannot have written more than that. + res.ok().map(|n| u32::try_from(n).unwrap()) } else { throw_unsup_format!( "on Windows, writing to anything except stdout/stderr is not supported" diff --git a/src/shims/windows/foreign_items.rs b/src/shims/windows/foreign_items.rs index 3f4b8b14002e7..29afe52cafd6c 100644 --- a/src/shims/windows/foreign_items.rs +++ b/src/shims/windows/foreign_items.rs @@ -116,7 +116,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Initialize with `0`. this.write_bytes_ptr( system_info.ptr, - iter::repeat(0u8).take(system_info.layout.size.bytes() as usize), + iter::repeat(0u8).take(system_info.layout.size.bytes_usize()), )?; // Set selected fields. let word_layout = this.machine.layouts.u16; From 649b2164824c47419ffeffa7266f18a9cc84824e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 23 Jul 2022 09:36:59 -0400 Subject: [PATCH 3567/3747] add a flag to print a diagnostic when an outdated value is returned from an atomic load --- README.md | 3 +++ src/bin/miri.rs | 2 ++ src/concurrency/data_race.rs | 6 +++++- src/concurrency/weak_memory.rs | 34 ++++++++++++++++++++++------------ src/diagnostics.rs | 7 ++++++- src/eval.rs | 3 +++ src/machine.rs | 7 +++++-- 7 files changed, 46 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index 0741f373bb677..fa235a45f5093 100644 --- a/README.md +++ b/README.md @@ -377,6 +377,9 @@ to Miri failing to detect cases of undefined behavior in a program. happening and where in your code would be a good place to look for it. Specifying this argument multiple times does not overwrite the previous values, instead it appends its values to the list. Listing a tag multiple times has no effect. +* `-Zmiri-track-weak-memory-loads` shows a backtrace when weak memory emulation returns an outdated + value from a load. This can help diagnose problems that disappear under + `-Zmiri-disable-weak-memory-emulation`. [function ABI]: https://doc.rust-lang.org/reference/items/functions.html#extern-function-qualifier diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 516c730e3fbdb..14694ac7b0536 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -358,6 +358,8 @@ fn main() { miri_config.isolated_op = miri::IsolatedOp::Allow; } else if arg == "-Zmiri-disable-weak-memory-emulation" { miri_config.weak_memory_emulation = false; + } else if arg == "-Zmiri-track-weak-memory-loads" { + miri_config.track_outdated_loads = true; } else if let Some(param) = arg.strip_prefix("-Zmiri-isolation-error=") { if matches!(isolation_enabled, Some(false)) { panic!("-Zmiri-isolation-error cannot be used along with -Zmiri-disable-isolation"); diff --git a/src/concurrency/data_race.rs b/src/concurrency/data_race.rs index 90b38225105df..6ea87a82cb924 100644 --- a/src/concurrency/data_race.rs +++ b/src/concurrency/data_race.rs @@ -1187,12 +1187,15 @@ pub struct GlobalState { /// The timestamp of last SC write performed by each thread last_sc_write: RefCell, + + /// Track when an outdated (weak memory) load happens. + pub track_outdated_loads: bool, } impl GlobalState { /// Create a new global state, setup with just thread-id=0 /// advanced to timestamp = 1. - pub fn new() -> Self { + pub fn new(config: &MiriConfig) -> Self { let mut global_state = GlobalState { multi_threaded: Cell::new(false), ongoing_action_data_race_free: Cell::new(false), @@ -1203,6 +1206,7 @@ impl GlobalState { terminated_threads: RefCell::new(FxHashMap::default()), last_sc_fence: RefCell::new(VClock::default()), last_sc_write: RefCell::new(VClock::default()), + track_outdated_loads: config.track_outdated_loads, }; // Setup the main-thread since it is not explicitly created: diff --git a/src/concurrency/weak_memory.rs b/src/concurrency/weak_memory.rs index 137a9f43d4eea..317258a028d0b 100644 --- a/src/concurrency/weak_memory.rs +++ b/src/concurrency/weak_memory.rs @@ -82,10 +82,7 @@ use rustc_const_eval::interpret::{ }; use rustc_data_structures::fx::FxHashMap; -use crate::{ - AtomicReadOrd, AtomicRwOrd, AtomicWriteOrd, Provenance, ThreadManager, VClock, VTimestamp, - VectorIdx, -}; +use crate::*; use super::{ data_race::{GlobalState as DataRaceState, ThreadClockSet}, @@ -113,6 +110,13 @@ pub(super) struct StoreBuffer { buffer: VecDeque, } +/// Whether a load returned the latest value or not. +#[derive(PartialEq, Eq)] +enum LoadRecency { + Latest, + Outdated, +} + #[derive(Debug, Clone, PartialEq, Eq)] struct StoreElement { /// The identifier of the vector index, corresponding to a thread @@ -254,11 +258,11 @@ impl<'mir, 'tcx: 'mir> StoreBuffer { is_seqcst: bool, rng: &mut (impl rand::Rng + ?Sized), validate: impl FnOnce() -> InterpResult<'tcx>, - ) -> InterpResult<'tcx, ScalarMaybeUninit> { + ) -> InterpResult<'tcx, (ScalarMaybeUninit, LoadRecency)> { // Having a live borrow to store_buffer while calling validate_atomic_load is fine // because the race detector doesn't touch store_buffer - let store_elem = { + let (store_elem, recency) = { // The `clocks` we got here must be dropped before calling validate_atomic_load // as the race detector will update it let (.., clocks) = global.current_thread_state(thread_mgr); @@ -274,7 +278,7 @@ impl<'mir, 'tcx: 'mir> StoreBuffer { let (index, clocks) = global.current_thread_state(thread_mgr); let loaded = store_elem.load_impl(index, &clocks); - Ok(loaded) + Ok((loaded, recency)) } fn buffered_write( @@ -296,7 +300,7 @@ impl<'mir, 'tcx: 'mir> StoreBuffer { is_seqcst: bool, clocks: &ThreadClockSet, rng: &mut R, - ) -> &StoreElement { + ) -> (&StoreElement, LoadRecency) { use rand::seq::IteratorRandom; let mut found_sc = false; // FIXME: we want an inclusive take_while (stops after a false predicate, but @@ -359,9 +363,12 @@ impl<'mir, 'tcx: 'mir> StoreBuffer { } }); - candidates - .choose(rng) - .expect("store buffer cannot be empty, an element is populated on construction") + let chosen = candidates.choose(rng).expect("store buffer cannot be empty"); + if std::ptr::eq(chosen, self.buffer.back().expect("store buffer cannot be empty")) { + (chosen, LoadRecency::Latest) + } else { + (chosen, LoadRecency::Outdated) + } } /// ATOMIC STORE IMPL in the paper (except we don't need the location's vector clock) @@ -499,13 +506,16 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>: alloc_range(base_offset, place.layout.size), latest_in_mo, )?; - let loaded = buffer.buffered_read( + let (loaded, recency) = buffer.buffered_read( global, &this.machine.threads, atomic == AtomicReadOrd::SeqCst, &mut *rng, validate, )?; + if global.track_outdated_loads && recency == LoadRecency::Outdated { + register_diagnostic(NonHaltingDiagnostic::WeakMemoryOutdatedLoad); + } return Ok(loaded); } diff --git a/src/diagnostics.rs b/src/diagnostics.rs index 6a692059be927..a378df0ad82b4 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -74,6 +74,7 @@ pub enum NonHaltingDiagnostic { Int2Ptr { details: bool, }, + WeakMemoryOutdatedLoad, } /// Level of Miri specific diagnostics @@ -474,6 +475,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx format!("progress report: current operation being executed is here"), Int2Ptr { .. } => format!("integer-to-pointer cast"), + WeakMemoryOutdatedLoad => + format!("weak memory emulation: outdated value returned from load"), }; let (title, diag_level) = match e { @@ -485,7 +488,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | CreatedCallId(..) | CreatedAlloc(..) | FreedAlloc(..) - | ProgressReport => ("tracking was triggered", DiagLevel::Note), + | ProgressReport + | WeakMemoryOutdatedLoad => + ("tracking was triggered", DiagLevel::Note), }; let helps = match e { diff --git a/src/eval.rs b/src/eval.rs index 0f354aa549494..53264bd465914 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -102,6 +102,8 @@ pub struct MiriConfig { pub data_race_detector: bool, /// Determine if weak memory emulation should be enabled. Requires data race detection to be enabled pub weak_memory_emulation: bool, + /// Track when an outdated (weak memory) load happens. + pub track_outdated_loads: bool, /// Rate of spurious failures for compare_exchange_weak atomic operations, /// between 0.0 and 1.0, defaulting to 0.8 (80% chance of failure). pub cmpxchg_weak_failure_rate: f64, @@ -143,6 +145,7 @@ impl Default for MiriConfig { tracked_alloc_ids: HashSet::default(), data_race_detector: true, weak_memory_emulation: true, + track_outdated_loads: false, cmpxchg_weak_failure_rate: 0.8, // 80% measureme_out: None, panic_on_unsupported: false, diff --git a/src/machine.rs b/src/machine.rs index 40f4c9ed90c00..c77de4ec51ff2 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -376,8 +376,11 @@ impl<'mir, 'tcx> Evaluator<'mir, 'tcx> { } else { None }; - let data_race = - if config.data_race_detector { Some(data_race::GlobalState::new()) } else { None }; + let data_race = if config.data_race_detector { + Some(data_race::GlobalState::new(config)) + } else { + None + }; Evaluator { stacked_borrows, data_race, From b08e51d79a0a4051eab997007ff36d9ca1ee4ace Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 23 Jul 2022 11:54:07 -0400 Subject: [PATCH 3568/3747] refactor away some 'else { None }' --- src/machine.rs | 42 ++++++++++++++---------------------------- 1 file changed, 14 insertions(+), 28 deletions(-) diff --git a/src/machine.rs b/src/machine.rs index c77de4ec51ff2..3e45f77d54c3a 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -367,20 +367,14 @@ impl<'mir, 'tcx> Evaluator<'mir, 'tcx> { measureme::Profiler::new(out).expect("Couldn't create `measureme` profiler") }); let rng = StdRng::seed_from_u64(config.seed.unwrap_or(0)); - let stacked_borrows = if config.stacked_borrows { - Some(RefCell::new(stacked_borrows::GlobalStateInner::new( + let stacked_borrows = config.stacked_borrows.then(|| { + RefCell::new(stacked_borrows::GlobalStateInner::new( config.tracked_pointer_tags.clone(), config.tracked_call_ids.clone(), config.retag_fields, - ))) - } else { - None - }; - let data_race = if config.data_race_detector { - Some(data_race::GlobalState::new(config)) - } else { - None - }; + )) + }); + let data_race = config.data_race_detector.then(|| data_race::GlobalState::new(config)); Evaluator { stacked_borrows, data_race, @@ -691,32 +685,24 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { } let alloc = alloc.into_owned(); - let stacks = if let Some(stacked_borrows) = &ecx.machine.stacked_borrows { - Some(Stacks::new_allocation( + let stacks = ecx.machine.stacked_borrows.as_ref().map(|stacked_borrows| { + Stacks::new_allocation( id, alloc.size(), stacked_borrows, kind, ecx.machine.current_span(), - )) - } else { - None - }; - let race_alloc = if let Some(data_race) = &ecx.machine.data_race { - Some(data_race::AllocExtra::new_allocation( + ) + }); + let race_alloc = ecx.machine.data_race.as_ref().map(|data_race| { + data_race::AllocExtra::new_allocation( data_race, &ecx.machine.threads, alloc.size(), kind, - )) - } else { - None - }; - let buffer_alloc = if ecx.machine.weak_memory { - Some(weak_memory::AllocExtra::new_allocation()) - } else { - None - }; + ) + }); + let buffer_alloc = ecx.machine.weak_memory.then(weak_memory::AllocExtra::new_allocation); let alloc: Allocation = alloc.adjust_from_tcx( &ecx.tcx, AllocExtra { From 6c0398da7d74ec7bf16e4f48a900036aecfd714c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 23 Jul 2022 12:47:26 -0400 Subject: [PATCH 3569/3747] don't dump xargo output onto users of 'cargo miri test' --- cargo-miri/bin.rs | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index bb2eb54ffebca..72e56daf57eb3 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -497,9 +497,24 @@ path = "lib.rs" // Disable debug assertions in the standard library -- Miri is already slow enough. // But keep the overflow checks, they are cheap. command.env("RUSTFLAGS", "-Cdebug-assertions=off -Coverflow-checks=on"); + // Manage the output the user sees. + if only_setup { + eprintln!("Preparing a sysroot for Miri..."); + } else { + eprint!("Preparing a sysroot for Miri... "); + command.stdout(process::Stdio::null()); + command.stderr(process::Stdio::null()); + } // Finally run it! if command.status().expect("failed to run xargo").success().not() { - show_error(format!("failed to run xargo")); + if only_setup { + show_error(format!("failed to run xargo, see error details above")) + } else { + show_error(format!("failed to run xargo; run `cargo miri setup` to see the error details")) + } + } + if !only_setup { + eprintln!("done"); } // That should be it! But we need to figure out where xargo built stuff. @@ -510,10 +525,10 @@ path = "lib.rs" // Figure out what to print. let print_sysroot = only_setup && has_arg_flag("--print-sysroot"); // whether we just print the sysroot path if print_sysroot { - // Print just the sysroot and nothing else; this way we do not need any escaping. + // Print just the sysroot and nothing else to stdout; this way we do not need any escaping. println!("{}", sysroot.display()); } else if only_setup { - println!("A libstd for Miri is now available in `{}`.", sysroot.display()); + eprintln!("A sysroot for Miri is now available in `{}`.", sysroot.display()); } } From 0c5392f4354ba06028155c318fca1d3b287f83ea Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 23 Jul 2022 13:28:44 -0400 Subject: [PATCH 3570/3747] now test-cargo-miri will actually work even without a hot cache :D --- cargo-miri/bin.rs | 4 +++- ci.sh | 5 ++--- test-cargo-miri/run-test.py | 16 ++++++++-------- 3 files changed, 13 insertions(+), 12 deletions(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index 72e56daf57eb3..4c0b9e41d3bfa 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -510,7 +510,9 @@ path = "lib.rs" if only_setup { show_error(format!("failed to run xargo, see error details above")) } else { - show_error(format!("failed to run xargo; run `cargo miri setup` to see the error details")) + show_error(format!( + "failed to run xargo; run `cargo miri setup` to see the error details" + )) } } if !only_setup { diff --git a/ci.sh b/ci.sh index 8c63a57a4f490..7bd131405bd50 100755 --- a/ci.sh +++ b/ci.sh @@ -21,6 +21,7 @@ function run_tests { echo "Testing host architecture" fi + ## ui test suite ./miri test --locked if [ -z "${MIRI_TEST_TARGET+exists}" ]; then # Only for host architecture: tests with optimizations (`-O` is what cargo passes, but crank MIR @@ -30,15 +31,13 @@ function run_tests { MIRIFLAGS="-O -Zmir-opt-level=4" MIRI_SKIP_UI_CHECKS=1 ./miri test --locked -- tests/{pass,panic} fi + ## test-cargo-miri # On Windows, there is always "python", not "python3" or "python2". if command -v python3 > /dev/null; then PYTHON=python3 else PYTHON=python fi - - # "miri test" has built the sysroot for us, now this should pass without - # any interactive questions. ${PYTHON} test-cargo-miri/run-test.py echo diff --git a/test-cargo-miri/run-test.py b/test-cargo-miri/run-test.py index ab43c72511584..3805bd19777f7 100755 --- a/test-cargo-miri/run-test.py +++ b/test-cargo-miri/run-test.py @@ -25,7 +25,12 @@ def cargo_miri(cmd, quiet = True): def normalize_stdout(str): str = str.replace("src\\", "src/") # normalize paths across platforms - return re.sub("finished in \d+\.\d\ds", "finished in $TIME", str) + str = re.sub("finished in \d+\.\d\ds", "finished in $TIME", str) # the time keeps changing, obviously + return str + +def normalize_stderr(str): + str = str.replace("Preparing a sysroot for Miri... done\n", "") # remove leading cargo-miri setup output + return str def check_output(actual, path, name): expected = open(path).read() @@ -51,9 +56,8 @@ def test(name, cmd, stdout_ref, stderr_ref, stdin=b'', env={}): env=p_env, ) (stdout, stderr) = p.communicate(input=stdin) - stdout = stdout.decode("UTF-8") - stderr = stderr.decode("UTF-8") - stdout = normalize_stdout(stdout) + stdout = normalize_stdout(stdout.decode("UTF-8")) + stderr = normalize_stderr(stderr.decode("UTF-8")) stdout_matches = check_output(stdout, stdout_ref, "stdout") stderr_matches = check_output(stderr, stderr_ref, "stderr") @@ -175,10 +179,6 @@ def test_cargo_miri_test(): target_str = " for target {}".format(os.environ['MIRI_TEST_TARGET']) if 'MIRI_TEST_TARGET' in os.environ else "" print(CGREEN + CBOLD + "## Running `cargo miri` tests{}".format(target_str) + CEND) -if not 'MIRI_SYSROOT' in os.environ: - # Make sure we got a working sysroot. - # (If the sysroot gets built later when output is compared, that leads to test failures.) - subprocess.run(cargo_miri("setup"), check=True) test_cargo_miri_run() test_cargo_miri_test() # Ensure we did not create anything outside the expected target dir. From dd01870657fa415bb5f1fa1b66dc7d7b1aa3e08c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 23 Jul 2022 17:36:42 -0400 Subject: [PATCH 3571/3747] cargo-miri: use '--config target.runner' rather than the TARGET_RUNNER env vars --- cargo-miri/bin.rs | 91 ++++++++++++++++++++++++----------------------- 1 file changed, 46 insertions(+), 45 deletions(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index 4c0b9e41d3bfa..202ac890fabd2 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -9,7 +9,7 @@ use std::ffi::{OsStr, OsString}; use std::fmt::Write as _; use std::fs::{self, File}; use std::io::{self, BufRead, BufReader, BufWriter, Read, Write}; -use std::iter::TakeWhile; +use std::iter::{self, TakeWhile}; use std::ops::Not; use std::path::{Path, PathBuf}; use std::process::{self, Command}; @@ -206,6 +206,14 @@ fn forward_miri_sysroot(cmd: &mut Command) { cmd.arg(sysroot); } +/// Escapes `s` in a way that is suitable for using it as a string literal in TOML syntax. +fn escape_for_toml(s: &str) -> String { + // We want to surround this string in quotes `"`. So we first escape all quotes, + // and also all backslashes (that are used to escape quotes). + let s = s.replace('\\', r#"\\"#).replace('"', r#"\""#); + format!("\"{}\"", s) +} + /// Returns the path to the `miri` binary fn find_miri() -> PathBuf { if let Some(path) = env::var_os("MIRI") { @@ -669,7 +677,11 @@ fn phase_cargo_miri(mut args: impl Iterator) { // describes an alternative // approach that uses `cargo check`, making that part easier but target and binary handling // harder. - let cargo_miri_path = std::env::current_exe().expect("current executable path invalid"); + let cargo_miri_path = std::env::current_exe() + .expect("current executable path invalid") + .into_os_string() + .into_string() + .expect("current executable path is not valid UTF-8"); let cargo_cmd = match subcommand { MiriCommand::Forward(s) => s, MiriCommand::Setup => return, // `cargo miri setup` stops here. @@ -699,8 +711,8 @@ fn phase_cargo_miri(mut args: impl Iterator) { target_dir.push("miri"); cmd.arg("--target-dir").arg(target_dir); - // Make sure we know the build target, and cargo does, too. - // This is needed to make the `CARGO_TARGET_*_RUNNER` env var do something, + // Make sure the build target is explicitly set. + // This is needed to make the `target.runner` settings do something, // and it later helps us detect which crates are proc-macro/build-script // (host crates) and which crates are needed for the program itself. let host = version_info().host; @@ -714,6 +726,18 @@ fn phase_cargo_miri(mut args: impl Iterator) { &host }; + let cargo_miri_path_for_toml = escape_for_toml(&cargo_miri_path); + cmd.arg("--config") + .arg(format!("target.{target}.runner=[{cargo_miri_path_for_toml}, 'runner']",)); + if &host != target { + // Set ourselves as runner for host and target. (Unit tests of `proc-macro` crates are run on + // the host, so we set the host runner to us in order to skip them.) + // But only do that if host and target are different; setting this command twice otherwise + // makes cargo concatenate the two arrays. + cmd.arg("--config") + .arg(format!("target.{host}.runner=[{cargo_miri_path_for_toml}, 'runner']",)); + } + // Forward all further arguments after `--` to cargo. cmd.arg("--").args(args); @@ -743,16 +767,6 @@ fn phase_cargo_miri(mut args: impl Iterator) { // bootstrap `rustc` thing in our way! Instead, we have MIRI_HOST_SYSROOT to use for host builds. cmd.env("RUSTC", &fs::canonicalize(find_miri()).unwrap()); - let runner_env_name = - |triple: &str| format!("CARGO_TARGET_{}_RUNNER", triple.to_uppercase().replace('-', "_")); - let host_runner_env_name = runner_env_name(&host); - let target_runner_env_name = runner_env_name(target); - // Set the target runner to us, so we can interpret the binaries. - cmd.env(&target_runner_env_name, &cargo_miri_path); - // Unit tests of `proc-macro` crates are run on the host, so we set the host runner to - // us in order to skip them. - cmd.env(&host_runner_env_name, &cargo_miri_path); - // Set rustdoc to us as well, so we can run doctests. cmd.env("RUSTDOC", &cargo_miri_path); @@ -1194,38 +1208,25 @@ fn main() { return; } - let mut args = args.peekable(); - if args.next_if(|a| a == "miri").is_some() { - phase_cargo_miri(args); - } else if let Some(arg) = args.peek().cloned() { - // Cargo calls us for everything it does. We could be invoked as rustc, rustdoc, or the runner. - - // If the first arg is equal to the RUSTC variable (which should be set at this point), - // then we need to behave as rustc. This is the somewhat counter-intuitive behavior of - // having both RUSTC and RUSTC_WRAPPER set (see - // https://github.com/rust-lang/cargo/issues/10886). - if arg == env::var("RUSTC").unwrap() { - args.next().unwrap(); // consume wrapped RUSTC command. - return phase_rustc(args, RustcPhase::Build); - } - // We have to distinguish the "runner" and "rustdoc" cases. - // As runner, the first argument is the binary (a file that should exist, with an absolute path); - // as rustdoc, the first argument is a flag (`--something`). - let binary = Path::new(&arg); - if binary.exists() { - assert!(!arg.starts_with("--")); // not a flag - phase_runner(args, RunnerPhase::Cargo); - } else if arg.starts_with("--") { - phase_rustdoc(args); - } else { - show_error(format!( - "`cargo-miri` called with unexpected first argument `{}`; please only invoke this binary through `cargo miri`", - arg - )); - } - } else { + let Some(first) = args.next() else { show_error(format!( "`cargo-miri` called without first argument; please only invoke this binary through `cargo miri`" - )); + )) + }; + match first.as_str() { + "miri" => phase_cargo_miri(args), + "runner" => phase_runner(args, RunnerPhase::Cargo), + arg if arg == env::var("RUSTC").unwrap() => { + // If the first arg is equal to the RUSTC env ariable (which should be set at this + // point), then we need to behave as rustc. This is the somewhat counter-intuitive + // behavior of having both RUSTC and RUSTC_WRAPPER set + // (see https://github.com/rust-lang/cargo/issues/10886). + phase_rustc(args, RustcPhase::Build) + } + _ => { + // Everything else must be rustdoc. But we need to get `first` "back onto the iterator", + // it is some part of the rustdoc invocation. + phase_rustdoc(iter::once(first).chain(args)); + } } } From e14df0537025b660adf23edeb069954a25a23611 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 23 Jul 2022 17:46:02 -0400 Subject: [PATCH 3572/3747] set runner for all targets via 'all()' --- cargo-miri/bin.rs | 25 +++++++------------------ 1 file changed, 7 insertions(+), 18 deletions(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index 202ac890fabd2..ff3361899c4bf 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -715,28 +715,17 @@ fn phase_cargo_miri(mut args: impl Iterator) { // This is needed to make the `target.runner` settings do something, // and it later helps us detect which crates are proc-macro/build-script // (host crates) and which crates are needed for the program itself. - let host = version_info().host; - let target = get_arg_flag_value("--target"); - let target = if let Some(ref target) = target { - target - } else { - // No target given. Pick default and tell cargo about it. + if get_arg_flag_value("--target").is_none() { + // No target given. Explicitly pick the host. cmd.arg("--target"); - cmd.arg(&host); - &host - }; + cmd.arg(version_info().host); + } + // Set ourselves as runner for al binaries invoked by cargo. + // We use `all()` since `true` is not a thing in cfg-lang, but the empty conjunction is. :) let cargo_miri_path_for_toml = escape_for_toml(&cargo_miri_path); cmd.arg("--config") - .arg(format!("target.{target}.runner=[{cargo_miri_path_for_toml}, 'runner']",)); - if &host != target { - // Set ourselves as runner for host and target. (Unit tests of `proc-macro` crates are run on - // the host, so we set the host runner to us in order to skip them.) - // But only do that if host and target are different; setting this command twice otherwise - // makes cargo concatenate the two arrays. - cmd.arg("--config") - .arg(format!("target.{host}.runner=[{cargo_miri_path_for_toml}, 'runner']",)); - } + .arg(format!("target.'cfg(all())'.runner=[{cargo_miri_path_for_toml}, 'runner']")); // Forward all further arguments after `--` to cargo. cmd.arg("--").args(args); From b93fcd99e84f31becfb205c858b2054a9ce9b902 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 23 Jul 2022 17:58:20 -0400 Subject: [PATCH 3573/3747] avoid spurious 'Preparing a sysroot for Miri...' in 'cargo miri setup --print-sysroot' also clean up sysroot building printing logic a bit --- cargo-miri/bin.rs | 28 ++++++++++++++++++---------- miri | 3 --- 2 files changed, 18 insertions(+), 13 deletions(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index ff3361899c4bf..1b14d4da9cc47 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -35,6 +35,11 @@ The cargo options are exactly the same as for `cargo run` and `cargo test`, resp Examples: cargo miri run cargo miri test -- test-suite-filter + + cargo miri setup --print sysroot + This will print the path to the generated sysroot (and nothing else) on stdout. + stderr will still contain progress information about how the build is doing. + "#; #[derive(Clone, Debug)] @@ -361,6 +366,8 @@ fn write_to_file(filename: &Path, content: &str) { /// done all this already. fn setup(subcommand: &MiriCommand) { let only_setup = matches!(subcommand, MiriCommand::Setup); + let ask_user = !only_setup; + let print_sysroot = only_setup && has_arg_flag("--print-sysroot"); // whether we just print the sysroot path if std::env::var_os("MIRI_SYSROOT").is_some() { if only_setup { println!("WARNING: MIRI_SYSROOT already set, not doing anything.") @@ -368,10 +375,6 @@ fn setup(subcommand: &MiriCommand) { return; } - // Subcommands other than `setup` will do a setup if necessary, but - // interactively confirm first. - let ask_user = !only_setup; - // First, we need xargo. if xargo_version().map_or(true, |v| v < XARGO_MIN_VERSION) { if std::env::var_os("XARGO_CHECK").is_some() { @@ -507,8 +510,14 @@ path = "lib.rs" command.env("RUSTFLAGS", "-Cdebug-assertions=off -Coverflow-checks=on"); // Manage the output the user sees. if only_setup { + // We want to be explicit. eprintln!("Preparing a sysroot for Miri..."); + if print_sysroot { + // Be extra sure there is no noise on stdout. + command.stdout(process::Stdio::null()); + } } else { + // We want to be quiet, but still let the user know that something is happening. eprint!("Preparing a sysroot for Miri... "); command.stdout(process::Stdio::null()); command.stderr(process::Stdio::null()); @@ -523,9 +532,6 @@ path = "lib.rs" )) } } - if !only_setup { - eprintln!("done"); - } // That should be it! But we need to figure out where xargo built stuff. // Unfortunately, it puts things into a different directory when the @@ -533,12 +539,14 @@ path = "lib.rs" let sysroot = if target == &host { dir.join("HOST") } else { PathBuf::from(dir) }; std::env::set_var("MIRI_SYSROOT", &sysroot); // pass the env var to the processes we spawn, which will turn it into "--sysroot" flags // Figure out what to print. - let print_sysroot = only_setup && has_arg_flag("--print-sysroot"); // whether we just print the sysroot path + if only_setup { + eprintln!("A sysroot for Miri is now available in `{}`.", sysroot.display()); + } else { + eprintln!("done"); + } if print_sysroot { // Print just the sysroot and nothing else to stdout; this way we do not need any escaping. println!("{}", sysroot.display()); - } else if only_setup { - eprintln!("A sysroot for Miri is now available in `{}`.", sysroot.display()); } } diff --git a/miri b/miri index 463e4607baedb..8bef9d1291a90 100755 --- a/miri +++ b/miri @@ -131,9 +131,6 @@ export RUSTFLAGS="-C link-args=-Wl,-rpath,$LIBDIR $RUSTFLAGS" # Build a sysroot and set MIRI_SYSROOT to use it. Arguments are passed to `cargo miri setup`. build_sysroot() { - # Build once, for the user to see. - $CARGO run $CARGO_EXTRA_FLAGS --manifest-path "$MIRIDIR"/cargo-miri/Cargo.toml -- miri setup "$@" - # Call again, to just set env var. export MIRI_SYSROOT="$($CARGO run $CARGO_EXTRA_FLAGS --manifest-path "$MIRIDIR"/cargo-miri/Cargo.toml -q -- miri setup --print-sysroot "$@")" } From 8b643809ccd3f9e124ee0dcd2fd5cc10d4ec969a Mon Sep 17 00:00:00 2001 From: Nilstrieb <48135649+Nilstrieb@users.noreply.github.com> Date: Sat, 23 Jul 2022 22:27:05 +0200 Subject: [PATCH 3574/3747] Fix outdated docs in sb stack cache Since `Item` is bitpacked now, the full `Item` is stored in the cache. --- src/stacked_borrows/stack.rs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/stacked_borrows/stack.rs b/src/stacked_borrows/stack.rs index c0d4d0d291f30..6fd8d85f2b5fe 100644 --- a/src/stacked_borrows/stack.rs +++ b/src/stacked_borrows/stack.rs @@ -39,11 +39,7 @@ pub struct Stack { unique_range: Range, } -/// A very small cache of searches of the borrow stack -/// This maps items to locations in the borrow stack. Any use of this still needs to do a -/// probably-cold random access into the borrow stack to figure out what `Permission` an -/// `SbTag` grants. We could avoid this by also storing the `Permission` in the cache, but -/// most lookups into the cache are immediately followed by access of the full borrow stack anyway. +/// A very small cache of searches of a borrow stack, mapping `Item`s to their position in said stack. /// /// It may seem like maintaining this cache is a waste for small stacks, but /// (a) iterating over small fixed-size arrays is super fast, and (b) empirically this helps *a lot*, From 25b11f6424d928b1c6876ed3d49655fc4b1f6ffc Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 23 Jul 2022 19:22:02 -0400 Subject: [PATCH 3575/3747] attempt to overwrite globally set build.rustc-wrapper --- cargo-miri/bin.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index 4c0b9e41d3bfa..2478e331191c3 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -488,14 +488,14 @@ path = "lib.rs" command.env("RUSTC", &cargo_miri_path); } command.env("MIRI_CALLED_FROM_XARGO", "1"); - // Make sure there are no other wrappers or flags getting in our way - // (Cc https://github.com/rust-lang/miri/issues/1421). - // This is consistent with normal `cargo build` that does not apply `RUSTFLAGS` - // to the sysroot either. - command.env_remove("RUSTC_WRAPPER"); - command.env_remove("RUSTFLAGS"); - // Disable debug assertions in the standard library -- Miri is already slow enough. - // But keep the overflow checks, they are cheap. + // Make sure there are no other wrappers getting in our way + // (Cc https://github.com/rust-lang/miri/issues/1421, https://github.com/rust-lang/miri/issues/2429). + // Looks like setting `RUSTC_WRAPPER` to the empty string overwrites `build.rustc-wrapper` set via `config.toml`. + command.env("RUSTC_WRAPPER", ""); + // Disable debug assertions in the standard library -- Miri is already slow enough. But keep the + // overflow checks, they are cheap. This completely overwrites flags the user might have set, + // which is consistent with normal `cargo build` that does not apply `RUSTFLAGS` to the sysroot + // either. command.env("RUSTFLAGS", "-Cdebug-assertions=off -Coverflow-checks=on"); // Manage the output the user sees. if only_setup { From 7267e0d4c5eb8ce2d445bb8c28104de489a2c79e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 23 Jul 2022 19:30:15 -0400 Subject: [PATCH 3576/3747] attempt to test RUSTC and RUSTC_WRAPPER shenanigans on CI --- cargo-miri/bin.rs | 1 + ci.sh | 13 +++++++++++++ 2 files changed, 14 insertions(+) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index 2478e331191c3..9cba2e772bcd7 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -483,6 +483,7 @@ path = "lib.rs" // The `MIRI_CALLED_FROM_XARGO` will mean we dispatch to `phase_setup_rustc`. let cargo_miri_path = std::env::current_exe().expect("current executable path invalid"); if env::var_os("RUSTC_STAGE").is_some() { + assert!(env::var_os("RUSTC").is_some()); command.env("RUSTC_REAL", &cargo_miri_path); } else { command.env("RUSTC", &cargo_miri_path); diff --git a/ci.sh b/ci.sh index 7bd131405bd50..f93c218f1b0ef 100755 --- a/ci.sh +++ b/ci.sh @@ -38,8 +38,21 @@ function run_tests { else PYTHON=python fi + # Some environment setup that attempts to confuse the heck out of cargo-miri. + if [ "$HOST_TARGET" = x86_64-unknown-linux-gnu ]; then + # These act up on Windows (`which miri` produces a filename that does not exist?!?), + # so let's do this only on Linux. Also makes sure things work without these set. + export RUSTC=$(which rustc) + export MIRI=$(which miri) + fi + mkdir -p .cargo + echo 'build.rustc-wrapper = "thisdoesnotexist"' > .cargo/config.toml + # Run the actual test ${PYTHON} test-cargo-miri/run-test.py echo + # Clean up + unset RUSTC MIRI + rm -rf .cargo # Ensure that our benchmarks all work, on the host at least. if [ -z "${MIRI_TEST_TARGET+exists}" ]; then From 5c52a7695c26a96cd8d2a54e0756730c207b3240 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 24 Jul 2022 07:37:10 -0400 Subject: [PATCH 3577/3747] ui_test: build dependencies in locked mode unless bless is enabled --- ui_test/src/dependencies.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/ui_test/src/dependencies.rs b/ui_test/src/dependencies.rs index 8ec7090b96a64..582641b97ae13 100644 --- a/ui_test/src/dependencies.rs +++ b/ui_test/src/dependencies.rs @@ -5,7 +5,7 @@ use std::{ process::Command, }; -use crate::Config; +use crate::{Config, OutputConflictHandling}; #[derive(Default, Debug)] pub struct Dependencies { @@ -40,6 +40,9 @@ pub fn build_dependencies(config: &Config) -> Result { let setup_command = |cmd: &mut Command| { cmd.envs(envs.iter().map(|(k, v)| (k, v))); cmd.arg("--manifest-path").arg(manifest_path); + if matches!(config.output_conflict_handling, OutputConflictHandling::Error) { + cmd.arg("--locked"); + } }; setup_command(&mut build); From c33fc24566da5e342e03183c07314c910b690d25 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 24 Jul 2022 08:37:29 -0400 Subject: [PATCH 3578/3747] rustup --- rust-version | 2 +- .../dangling_pointers/null_pointer_write_zst.rs | 2 +- .../null_pointer_write_zst.stderr | 14 ++++---------- tests/fail/intrinsics/write_bytes_overflow.rs | 2 +- tests/fail/intrinsics/write_bytes_overflow.stderr | 14 ++++---------- 5 files changed, 11 insertions(+), 23 deletions(-) diff --git a/rust-version b/rust-version index b54ff9e100ed0..c710735735c7c 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -41419e70366962c9a878bfe673ef4df38db6f7f1 +35a061724802377a21fc6dac1ebcbb9b8d1f558a diff --git a/tests/fail/dangling_pointers/null_pointer_write_zst.rs b/tests/fail/dangling_pointers/null_pointer_write_zst.rs index 7181a5979b442..c00344b6de23a 100644 --- a/tests/fail/dangling_pointers/null_pointer_write_zst.rs +++ b/tests/fail/dangling_pointers/null_pointer_write_zst.rs @@ -1,6 +1,5 @@ // Some optimizations remove ZST accesses, thus masking this UB. //@compile-flags: -Zmir-opt-level=0 -//@error-pattern: memory access failed: null pointer is a dangling pointer #[allow(deref_nullptr)] fn main() { @@ -8,4 +7,5 @@ fn main() { // Also not assigning directly as that's array initialization, not assignment. let zst_val = [1u8; 0]; unsafe { std::ptr::null_mut::<[u8; 0]>().write(zst_val) }; + //~^ERROR: memory access failed: null pointer is a dangling pointer } diff --git a/tests/fail/dangling_pointers/null_pointer_write_zst.stderr b/tests/fail/dangling_pointers/null_pointer_write_zst.stderr index 0535aaa3e2d16..17ac04a706fff 100644 --- a/tests/fail/dangling_pointers/null_pointer_write_zst.stderr +++ b/tests/fail/dangling_pointers/null_pointer_write_zst.stderr @@ -1,19 +1,13 @@ error: Undefined Behavior: memory access failed: null pointer is a dangling pointer (it has no provenance) - --> RUSTLIB/core/src/ptr/mod.rs:LL:CC + --> $DIR/null_pointer_write_zst.rs:LL:CC | -LL | copy_nonoverlapping(&src as *const T, dst, 1); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: null pointer is a dangling pointer (it has no provenance) +LL | unsafe { std::ptr::null_mut::<[u8; 0]>().write(zst_val) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ memory access failed: null pointer is a dangling pointer (it has no provenance) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: backtrace: - = note: inside `std::ptr::write::<[u8; 0]>` at RUSTLIB/core/src/ptr/mod.rs:LL:CC - = note: inside `std::ptr::mut_ptr::::write` at RUSTLIB/core/src/ptr/mut_ptr.rs:LL:CC -note: inside `main` at $DIR/null_pointer_write_zst.rs:LL:CC - --> $DIR/null_pointer_write_zst.rs:LL:CC - | -LL | unsafe { std::ptr::null_mut::<[u8; 0]>().write(zst_val) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: inside `main` at $DIR/null_pointer_write_zst.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/write_bytes_overflow.rs b/tests/fail/intrinsics/write_bytes_overflow.rs index 5c49dc00165c9..08bc096d6c366 100644 --- a/tests/fail/intrinsics/write_bytes_overflow.rs +++ b/tests/fail/intrinsics/write_bytes_overflow.rs @@ -1,9 +1,9 @@ -//@error-pattern: overflow computing total size of `write_bytes` use std::mem; fn main() { let mut y = 0; unsafe { (&mut y as *mut i32).write_bytes(0u8, 1usize << (mem::size_of::() * 8 - 1)); + //~^ ERROR: overflow computing total size of `write_bytes` } } diff --git a/tests/fail/intrinsics/write_bytes_overflow.stderr b/tests/fail/intrinsics/write_bytes_overflow.stderr index 1e5381279529f..47610b0623012 100644 --- a/tests/fail/intrinsics/write_bytes_overflow.stderr +++ b/tests/fail/intrinsics/write_bytes_overflow.stderr @@ -1,19 +1,13 @@ error: Undefined Behavior: overflow computing total size of `write_bytes` - --> RUSTLIB/core/src/intrinsics.rs:LL:CC + --> $DIR/write_bytes_overflow.rs:LL:CC | -LL | write_bytes(dst, val, count) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflow computing total size of `write_bytes` +LL | (&mut y as *mut i32).write_bytes(0u8, 1usize << (mem::size_of::() * 8 - 1)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflow computing total size of `write_bytes` | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: backtrace: - = note: inside `std::intrinsics::write_bytes::` at RUSTLIB/core/src/intrinsics.rs:LL:CC - = note: inside `std::ptr::mut_ptr::::write_bytes` at RUSTLIB/core/src/ptr/mut_ptr.rs:LL:CC -note: inside `main` at $DIR/write_bytes_overflow.rs:LL:CC - --> $DIR/write_bytes_overflow.rs:LL:CC - | -LL | (&mut y as *mut i32).write_bytes(0u8, 1usize << (mem::size_of::() * 8 - 1)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: inside `main` at $DIR/write_bytes_overflow.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace From 3ee56989c7f3d355b32f194fca03c0e47a3bd445 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 24 Jul 2022 08:48:58 -0400 Subject: [PATCH 3579/3747] get rid of some uses of core_intrinsics --- tests/fail/data_race/atomic_read_na_write_race1.rs | 7 ++----- tests/fail/data_race/atomic_read_na_write_race1.stderr | 4 ++-- tests/fail/data_race/atomic_write_na_read_race2.rs | 7 ++----- tests/fail/data_race/atomic_write_na_read_race2.stderr | 2 +- tests/fail/data_race/atomic_write_na_write_race1.rs | 7 ++----- tests/fail/data_race/atomic_write_na_write_race1.stderr | 2 +- tests/fail/weak_memory/racing_mixed_size_read.rs | 8 +++----- tests/fail/weak_memory/racing_mixed_size_read.stderr | 4 ++-- tests/pass/weak_memory/extra_cpp.rs | 1 - tests/pass/weak_memory/extra_cpp_unsafe.rs | 3 +-- 10 files changed, 16 insertions(+), 29 deletions(-) diff --git a/tests/fail/data_race/atomic_read_na_write_race1.rs b/tests/fail/data_race/atomic_read_na_write_race1.rs index 1ef021edc8cc7..30900a85d003f 100644 --- a/tests/fail/data_race/atomic_read_na_write_race1.rs +++ b/tests/fail/data_race/atomic_read_na_write_race1.rs @@ -1,10 +1,8 @@ // We want to control preemption here. //@compile-flags: -Zmiri-preemption-rate=0 //@ignore-target-windows: Concurrency on Windows is not supported yet. -#![feature(core_intrinsics)] -use std::intrinsics; -use std::sync::atomic::AtomicUsize; +use std::sync::atomic::{AtomicUsize, Ordering}; use std::thread::spawn; #[derive(Copy, Clone)] @@ -23,8 +21,7 @@ pub fn main() { }); let j2 = spawn(move || { - //Equivalent to: (&*c.0).load(Ordering::SeqCst) - intrinsics::atomic_load_seqcst(c.0 as *mut usize) //~ ERROR: Data race detected between Atomic Load on thread `` and Write on thread `` + (&*c.0).load(Ordering::SeqCst) //~ ERROR: Data race detected between Atomic Load on thread `` and Write on thread `` }); j1.join().unwrap(); diff --git a/tests/fail/data_race/atomic_read_na_write_race1.stderr b/tests/fail/data_race/atomic_read_na_write_race1.stderr index 2a0ca9260782c..e7a219e123526 100644 --- a/tests/fail/data_race/atomic_read_na_write_race1.stderr +++ b/tests/fail/data_race/atomic_read_na_write_race1.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: Data race detected between Atomic Load on thread `` and Write on thread `` at ALLOC --> $DIR/atomic_read_na_write_race1.rs:LL:CC | -LL | intrinsics::atomic_load_seqcst(c.0 as *mut usize) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Data race detected between Atomic Load on thread `` and Write on thread `` at ALLOC +LL | (&*c.0).load(Ordering::SeqCst) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Data race detected between Atomic Load on thread `` and Write on thread `` at ALLOC | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/data_race/atomic_write_na_read_race2.rs b/tests/fail/data_race/atomic_write_na_read_race2.rs index 77b2945f73715..1a79dde0b08ac 100644 --- a/tests/fail/data_race/atomic_write_na_read_race2.rs +++ b/tests/fail/data_race/atomic_write_na_read_race2.rs @@ -1,10 +1,8 @@ // We want to control preemption here. //@compile-flags: -Zmiri-preemption-rate=0 //@ignore-target-windows: Concurrency on Windows is not supported yet. -#![feature(core_intrinsics)] -use std::intrinsics::atomic_store; -use std::sync::atomic::AtomicUsize; +use std::sync::atomic::{AtomicUsize, Ordering}; use std::thread::spawn; #[derive(Copy, Clone)] @@ -23,8 +21,7 @@ pub fn main() { }); let j2 = spawn(move || { - //Equivalent to: (&*c.0).store(32, Ordering::SeqCst) - atomic_store(c.0 as *mut usize, 32); //~ ERROR: Data race detected between Atomic Store on thread `` and Read on thread `` + (&*c.0).store(32, Ordering::SeqCst); //~ ERROR: Data race detected between Atomic Store on thread `` and Read on thread `` }); j1.join().unwrap(); diff --git a/tests/fail/data_race/atomic_write_na_read_race2.stderr b/tests/fail/data_race/atomic_write_na_read_race2.stderr index 69bf6c5f37425..e9c6005f27e6b 100644 --- a/tests/fail/data_race/atomic_write_na_read_race2.stderr +++ b/tests/fail/data_race/atomic_write_na_read_race2.stderr @@ -1,7 +1,7 @@ error: Undefined Behavior: Data race detected between Atomic Store on thread `` and Read on thread `` at ALLOC --> $DIR/atomic_write_na_read_race2.rs:LL:CC | -LL | atomic_store(c.0 as *mut usize, 32); +LL | (&*c.0).store(32, Ordering::SeqCst); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Data race detected between Atomic Store on thread `` and Read on thread `` at ALLOC | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior diff --git a/tests/fail/data_race/atomic_write_na_write_race1.rs b/tests/fail/data_race/atomic_write_na_write_race1.rs index 34922dd595ed6..04015c2d14205 100644 --- a/tests/fail/data_race/atomic_write_na_write_race1.rs +++ b/tests/fail/data_race/atomic_write_na_write_race1.rs @@ -1,10 +1,8 @@ // We want to control preemption here. //@compile-flags: -Zmiri-preemption-rate=0 //@ignore-target-windows: Concurrency on Windows is not supported yet. -#![feature(core_intrinsics)] -use std::intrinsics::atomic_store; -use std::sync::atomic::AtomicUsize; +use std::sync::atomic::{AtomicUsize, Ordering}; use std::thread::spawn; #[derive(Copy, Clone)] @@ -23,8 +21,7 @@ pub fn main() { }); let j2 = spawn(move || { - //Equivalent to: (&*c.0).store(64, Ordering::SeqCst) - atomic_store(c.0 as *mut usize, 64); //~ ERROR: Data race detected between Atomic Store on thread `` and Write on thread `` + (&*c.0).store(64, Ordering::SeqCst); //~ ERROR: Data race detected between Atomic Store on thread `` and Write on thread `` }); j1.join().unwrap(); diff --git a/tests/fail/data_race/atomic_write_na_write_race1.stderr b/tests/fail/data_race/atomic_write_na_write_race1.stderr index 6abcf4fe3d12b..5ecc4ca040263 100644 --- a/tests/fail/data_race/atomic_write_na_write_race1.stderr +++ b/tests/fail/data_race/atomic_write_na_write_race1.stderr @@ -1,7 +1,7 @@ error: Undefined Behavior: Data race detected between Atomic Store on thread `` and Write on thread `` at ALLOC --> $DIR/atomic_write_na_write_race1.rs:LL:CC | -LL | atomic_store(c.0 as *mut usize, 64); +LL | (&*c.0).store(64, Ordering::SeqCst); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Data race detected between Atomic Store on thread `` and Write on thread `` at ALLOC | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior diff --git a/tests/fail/weak_memory/racing_mixed_size_read.rs b/tests/fail/weak_memory/racing_mixed_size_read.rs index aeaa6b68f6c8c..1c0b1c2be8fda 100644 --- a/tests/fail/weak_memory/racing_mixed_size_read.rs +++ b/tests/fail/weak_memory/racing_mixed_size_read.rs @@ -2,10 +2,8 @@ //@compile-flags: -Zmiri-preemption-rate=0 //@ignore-target-windows: Concurrency on Windows is not supported yet. -#![feature(core_intrinsics)] - -use std::sync::atomic::AtomicU32; use std::sync::atomic::Ordering::*; +use std::sync::atomic::{AtomicU16, AtomicU32}; use std::thread::spawn; fn static_atomic(val: u32) -> &'static AtomicU32 { @@ -31,8 +29,8 @@ pub fn main() { let x_ptr = x as *const AtomicU32 as *const u32; let x_split = split_u32_ptr(x_ptr); unsafe { - let hi = &(*x_split)[0] as *const u16; - std::intrinsics::atomic_load_relaxed(hi); //~ ERROR: imperfectly overlapping + let hi = x_split as *const u16 as *const AtomicU16; + (*hi).load(Relaxed); //~ ERROR: imperfectly overlapping } }); diff --git a/tests/fail/weak_memory/racing_mixed_size_read.stderr b/tests/fail/weak_memory/racing_mixed_size_read.stderr index 9988f4a86d426..8dbf9e6948bd7 100644 --- a/tests/fail/weak_memory/racing_mixed_size_read.stderr +++ b/tests/fail/weak_memory/racing_mixed_size_read.stderr @@ -1,8 +1,8 @@ error: unsupported operation: racy imperfectly overlapping atomic access is not possible in the C++20 memory model, and not supported by Miri's weak memory emulation --> $DIR/racing_mixed_size_read.rs:LL:CC | -LL | std::intrinsics::atomic_load_relaxed(hi); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ racy imperfectly overlapping atomic access is not possible in the C++20 memory model, and not supported by Miri's weak memory emulation +LL | (*hi).load(Relaxed); + | ^^^^^^^^^^^^^^^^^^^ racy imperfectly overlapping atomic access is not possible in the C++20 memory model, and not supported by Miri's weak memory emulation | = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support = note: backtrace: diff --git a/tests/pass/weak_memory/extra_cpp.rs b/tests/pass/weak_memory/extra_cpp.rs index 52c13cbdced37..d98fba26ffa80 100644 --- a/tests/pass/weak_memory/extra_cpp.rs +++ b/tests/pass/weak_memory/extra_cpp.rs @@ -5,7 +5,6 @@ // but doable in safe (at least sound) Rust. #![feature(atomic_from_mut)] -#![feature(core_intrinsics)] use std::sync::atomic::Ordering::*; use std::sync::atomic::{AtomicU16, AtomicU32}; diff --git a/tests/pass/weak_memory/extra_cpp_unsafe.rs b/tests/pass/weak_memory/extra_cpp_unsafe.rs index 1c6c370ced3b1..f5c6021a4a85b 100644 --- a/tests/pass/weak_memory/extra_cpp_unsafe.rs +++ b/tests/pass/weak_memory/extra_cpp_unsafe.rs @@ -7,7 +7,6 @@ // memory model in the future. #![feature(atomic_from_mut)] -#![feature(core_intrinsics)] use std::sync::atomic::AtomicU32; use std::sync::atomic::Ordering::*; @@ -27,7 +26,7 @@ fn racing_mixed_atomicity_read() { let j2 = spawn(move || { let x_ptr = x as *const AtomicU32 as *const u32; - unsafe { std::intrinsics::atomic_load_relaxed(x_ptr) } + unsafe { x_ptr.read() } }); let r1 = j1.join().unwrap(); From d905901d65a2725992fba6a634147b3ddaafaa1d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 24 Jul 2022 10:06:49 -0400 Subject: [PATCH 3580/3747] make miri a better RUSTC by default inside cargo-miri this requires a change in sysroot handling: miri driver now requires MIRI_SYSROOT to be set when it is in 'target' mode, rather than relying on `--sysroot` always being present. --- README.md | 5 +-- cargo-miri/bin.rs | 87 +++++++++++++++++++++----------------- miri | 8 +++- src/bin/miri.rs | 58 +++++++++++++++---------- test-cargo-miri/Cargo.lock | 7 +++ test-cargo-miri/Cargo.toml | 3 ++ test-cargo-miri/build.rs | 5 +++ tests/compiletest.rs | 4 -- 8 files changed, 107 insertions(+), 70 deletions(-) diff --git a/README.md b/README.md index fa235a45f5093..1ab081bfe2351 100644 --- a/README.md +++ b/README.md @@ -409,10 +409,9 @@ Moreover, Miri recognizes some environment variables: checkout. Note that changing files in that directory does not automatically trigger a re-build of the standard library; you have to clear the Miri build cache manually (on Linux, `rm -rf ~/.cache/miri`). -* `MIRI_SYSROOT` (recognized by `cargo miri` and the test suite) indicates the +* `MIRI_SYSROOT` (recognized by `cargo miri` and the Miri driver) indicates the sysroot to use. Only set this if you do not want to use the automatically - created sysroot. (The `miri` driver sysroot is controlled via the `--sysroot` - flag instead.) + created sysroot. * `MIRI_TEST_TARGET` (recognized by the test suite and the `./miri` script) indicates which target architecture to test against. `miri` and `cargo miri` accept the `--target` flag for the same purpose. diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index 216584ac9b022..7bfd99a7f1ed3 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -205,12 +205,6 @@ fn forward_patched_extern_arg(args: &mut impl Iterator, cmd: &mut } } -fn forward_miri_sysroot(cmd: &mut Command) { - let sysroot = env::var_os("MIRI_SYSROOT").expect("the wrapper should have set MIRI_SYSROOT"); - cmd.arg("--sysroot"); - cmd.arg(sysroot); -} - /// Escapes `s` in a way that is suitable for using it as a string literal in TOML syntax. fn escape_for_toml(s: &str) -> String { // We want to surround this string in quotes `"`. So we first escape all quotes, @@ -237,8 +231,15 @@ fn miri() -> Command { Command::new(find_miri()) } +fn miri_for_host() -> Command { + let mut cmd = miri(); + cmd.env("MIRI_BE_RUSTC", "host"); + cmd +} + fn version_info() -> VersionMeta { - VersionMeta::for_command(miri()).expect("failed to determine underlying rustc version of Miri") + VersionMeta::for_command(miri_for_host()) + .expect("failed to determine underlying rustc version of Miri") } fn cargo() -> Command { @@ -336,7 +337,7 @@ fn ask_to_run(mut cmd: Command, ask: bool, text: &str) { a => show_error(format!("invalid answer `{}`", a)), }; } else { - println!("Running `{:?}` to {}.", cmd, text); + eprintln!("Running `{:?}` to {}.", cmd, text); } if cmd.status().unwrap_or_else(|_| panic!("failed to execute {:?}", cmd)).success().not() { @@ -364,7 +365,7 @@ fn write_to_file(filename: &Path, content: &str) { /// Performs the setup required to make `cargo miri` work: Getting a custom-built libstd. Then sets /// `MIRI_SYSROOT`. Skipped if `MIRI_SYSROOT` is already set, in which case we expect the user has /// done all this already. -fn setup(subcommand: &MiriCommand) { +fn setup(subcommand: &MiriCommand, host: &str, target: &str) { let only_setup = matches!(subcommand, MiriCommand::Setup); let ask_user = !only_setup; let print_sysroot = only_setup && has_arg_flag("--print-sysroot"); // whether we just print the sysroot path @@ -398,8 +399,10 @@ fn setup(subcommand: &MiriCommand) { } None => { // Check for `rust-src` rustup component. - let output = - miri().args(&["--print", "sysroot"]).output().expect("failed to determine sysroot"); + let output = miri_for_host() + .args(&["--print", "sysroot"]) + .output() + .expect("failed to determine sysroot"); if !output.status.success() { show_error(format!( "Failed to determine sysroot; Miri said:\n{}", @@ -472,18 +475,21 @@ path = "lib.rs" ); write_to_file(&dir.join("lib.rs"), "#![no_std]"); - // Determine architectures. - // We always need to set a target so rustc bootstrap can tell apart host from target crates. - let host = version_info().host; - let target = get_arg_flag_value("--target"); - let target = target.as_ref().unwrap_or(&host); + // Figure out where xargo will build its stuff. + // Unfortunately, it puts things into a different directory when the + // architecture matches the host. + let sysroot = if target == host { dir.join("HOST") } else { PathBuf::from(dir) }; + // Make sure all target-level Miri invocations know their sysroot. + std::env::set_var("MIRI_SYSROOT", &sysroot); + // Now invoke xargo. let mut command = xargo_check(); command.arg("check").arg("-q"); - command.arg("--target").arg(target); command.current_dir(&dir); command.env("XARGO_HOME", &dir); command.env("XARGO_RUST_SRC", &rust_src); + // We always need to set a target so rustc bootstrap can tell apart host from target crates. + command.arg("--target").arg(target); // Use Miri as rustc to build a libstd compatible with us (and use the right flags). // However, when we are running in bootstrap, we cannot just overwrite `RUSTC`, // because we still need bootstrap to distinguish between host and target crates. @@ -523,6 +529,7 @@ path = "lib.rs" command.stdout(process::Stdio::null()); command.stderr(process::Stdio::null()); } + // Finally run it! if command.status().expect("failed to run xargo").success().not() { if only_setup { @@ -534,11 +541,6 @@ path = "lib.rs" } } - // That should be it! But we need to figure out where xargo built stuff. - // Unfortunately, it puts things into a different directory when the - // architecture matches the host. - let sysroot = if target == &host { dir.join("HOST") } else { PathBuf::from(dir) }; - std::env::set_var("MIRI_SYSROOT", &sysroot); // pass the env var to the processes we spawn, which will turn it into "--sysroot" flags // Figure out what to print. if only_setup { eprintln!("A sysroot for Miri is now available in `{}`.", sysroot.display()); @@ -677,8 +679,13 @@ fn phase_cargo_miri(mut args: impl Iterator) { }; let verbose = num_arg_flag("-v"); + // Determine the involved architectures. + let host = version_info().host; + let target = get_arg_flag_value("--target"); + let target = target.as_ref().unwrap_or(&host); + // We always setup. - setup(&subcommand); + setup(&subcommand, &host, target); // Invoke actual cargo for the job, but with different flags. // We re-use `cargo test` and `cargo run`, which makes target and binary handling very easy but @@ -727,7 +734,7 @@ fn phase_cargo_miri(mut args: impl Iterator) { if get_arg_flag_value("--target").is_none() { // No target given. Explicitly pick the host. cmd.arg("--target"); - cmd.arg(version_info().host); + cmd.arg(&host); } // Set ourselves as runner for al binaries invoked by cargo. @@ -754,16 +761,19 @@ fn phase_cargo_miri(mut args: impl Iterator) { "WARNING: Ignoring `RUSTC` environment variable; set `MIRI` if you want to control the binary used as the driver." ); } - // We'd prefer to just clear this env var, but cargo does not always honor `RUSTC_WRAPPER` - // (https://github.com/rust-lang/cargo/issues/10885). There is no good way to single out these invocations; - // some build scripts use the RUSTC env var as well. So we set it directly to the `miri` driver and - // hope that all they do is ask for the version number -- things could quickly go downhill from here. + // Build scripts (and also cargo: https://github.com/rust-lang/cargo/issues/10885) will invoke `rustc` even when `RUSTC_WRAPPER` is set. + // To make sure everything is coherent, we want that to be the Miri driver, but acting as rustc, on the target level. + // (Target, rather than host, is needed for cross-interpretation situations.) This is not a + // perfect emulation of real rustc (it might be unable to produce binaries since the sysroot is + // check-only), but it's as close as we can get, and it's good enough for autocfg. + // // In `main`, we need the value of `RUSTC` to distinguish RUSTC_WRAPPER invocations from rustdoc // or TARGET_RUNNER invocations, so we canonicalize it here to make it exceedingly unlikely that // there would be a collision with other invocations of cargo-miri (as rustdoc or as runner). // We explicitly do this even if RUSTC_STAGE is set, since for these builds we do *not* want the // bootstrap `rustc` thing in our way! Instead, we have MIRI_HOST_SYSROOT to use for host builds. cmd.env("RUSTC", &fs::canonicalize(find_miri()).unwrap()); + cmd.env("MIRI_BE_RUSTC", "target"); // we better remember to *unset* this in the other phases! // Set rustdoc to us as well, so we can run doctests. cmd.env("RUSTDOC", &cargo_miri_path); @@ -832,6 +842,11 @@ fn phase_rustc(mut args: impl Iterator, phase: RustcPhase) { } } + // phase_cargo_miri set `MIRI_BE_RUSTC` for when build scripts directly invoke the driver; + // however, if we get called back by cargo here, we'll carefully compute the right flags + // ourselves, so we first un-do what the earlier phase did. + env::remove_var("MIRI_BE_RUSTC"); + let verbose = std::env::var("MIRI_VERBOSE") .map_or(0, |verbose| verbose.parse().expect("verbosity flag must be an integer")); let target_crate = is_target_crate(); @@ -946,11 +961,6 @@ fn phase_rustc(mut args: impl Iterator, phase: RustcPhase) { } } - // Use our custom sysroot (but not if that is what we are currently building). - if phase != RustcPhase::Setup { - forward_miri_sysroot(&mut cmd); - } - // During setup, patch the panic runtime for `libpanic_abort` (mirroring what bootstrap usually does). if phase == RustcPhase::Setup && get_arg_flag_value("--crate-name").as_deref() == Some("panic_abort") @@ -1010,6 +1020,11 @@ enum RunnerPhase { } fn phase_runner(mut binary_args: impl Iterator, phase: RunnerPhase) { + // phase_cargo_miri set `MIRI_BE_RUSTC` for when build scripts directly invoke the driver; + // however, if we get called back by cargo here, we'll carefully compute the right flags + // ourselves, so we first un-do what the earlier phase did. + env::remove_var("MIRI_BE_RUSTC"); + let verbose = std::env::var("MIRI_VERBOSE") .map_or(0, |verbose| verbose.parse().expect("verbosity flag must be an integer")); @@ -1077,10 +1092,6 @@ fn phase_runner(mut binary_args: impl Iterator, phase: RunnerPhas cmd.arg(arg); } } - // Set sysroot (if we are inside rustdoc, we already did that in `phase_cargo_rustdoc`). - if phase != RunnerPhase::Rustdoc { - forward_miri_sysroot(&mut cmd); - } // Respect `MIRIFLAGS`. if let Ok(a) = env::var("MIRIFLAGS") { // This code is taken from `RUSTFLAGS` handling in cargo. @@ -1151,7 +1162,7 @@ fn phase_rustdoc(mut args: impl Iterator) { cmd.arg("-Z").arg("unstable-options"); // rustdoc needs to know the right sysroot. - forward_miri_sysroot(&mut cmd); + cmd.arg("--sysroot").arg(env::var_os("MIRI_SYSROOT").unwrap()); // make sure the 'miri' flag is set for rustdoc cmd.arg("--cfg").arg("miri"); diff --git a/miri b/miri index 8bef9d1291a90..956b8cca75b88 100755 --- a/miri +++ b/miri @@ -131,7 +131,11 @@ export RUSTFLAGS="-C link-args=-Wl,-rpath,$LIBDIR $RUSTFLAGS" # Build a sysroot and set MIRI_SYSROOT to use it. Arguments are passed to `cargo miri setup`. build_sysroot() { - export MIRI_SYSROOT="$($CARGO run $CARGO_EXTRA_FLAGS --manifest-path "$MIRIDIR"/cargo-miri/Cargo.toml -q -- miri setup --print-sysroot "$@")" + if ! MIRI_SYSROOT="$($CARGO run $CARGO_EXTRA_FLAGS --manifest-path "$MIRIDIR"/cargo-miri/Cargo.toml -q -- miri setup --print-sysroot "$@")"; then + echo "'cargo miri setup' failed" + exit 1 + fi + export MIRI_SYSROOT } # Prepare and set MIRI_SYSROOT. Respects `MIRI_TEST_TARGET` and takes into account @@ -201,7 +205,7 @@ run) $CARGO build $CARGO_EXTRA_FLAGS --manifest-path "$MIRIDIR"/Cargo.toml find_sysroot # Then run the actual command. - exec $CARGO run $CARGO_EXTRA_FLAGS --manifest-path "$MIRIDIR"/Cargo.toml -- --sysroot "$MIRI_SYSROOT" $MIRIFLAGS "$@" + exec $CARGO run $CARGO_EXTRA_FLAGS --manifest-path "$MIRIDIR"/Cargo.toml -- $MIRIFLAGS "$@" ;; fmt) find "$MIRIDIR" -not \( -name target -prune \) -name '*.rs' \ diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 14694ac7b0536..489eb959906c9 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -27,7 +27,7 @@ use rustc_middle::{ }, ty::{query::ExternProviders, TyCtxt}, }; -use rustc_session::{search_paths::PathKind, CtfeBacktrace}; +use rustc_session::{config::CrateType, search_paths::PathKind, CtfeBacktrace}; use miri::{BacktraceStyle, ProvenanceMode}; @@ -60,6 +60,10 @@ impl rustc_driver::Callbacks for MiriCompilerCalls { queries.global_ctxt().unwrap().peek_mut().enter(|tcx| { init_late_loggers(tcx); + if !tcx.sess.crate_types().contains(&CrateType::Executable) { + tcx.sess.fatal("miri only makes sense on bin crates"); + } + let (entry_def_id, entry_type) = if let Some(entry_def) = tcx.entry_fn(()) { entry_def } else { @@ -204,9 +208,9 @@ fn init_late_loggers(tcx: TyCtxt<'_>) { } } -/// Returns the "default sysroot" that Miri will use if no `--sysroot` flag is set. +/// Returns the "default sysroot" that Miri will use for host things if no `--sysroot` flag is set. /// Should be a compile-time constant. -fn compile_time_sysroot() -> Option { +fn host_sysroot() -> Option { if option_env!("RUSTC_STAGE").is_some() { // This is being built as part of rustc, and gets shipped with rustup. // We can rely on the sysroot computation in librustc_session. @@ -227,7 +231,7 @@ fn compile_time_sysroot() -> Option { if toolchain_runtime != toolchain { show_error(format!( "This Miri got built with local toolchain `{toolchain}`, but now is being run under a different toolchain. \n\ - Make sure to run Miri in the toolchain it got built with, e.g. via `cargo +{toolchain} miri`." + Make sure to run Miri in the toolchain it got built with, e.g. via `cargo +{toolchain} miri`." )); } } @@ -246,25 +250,42 @@ fn compile_time_sysroot() -> Option { /// Execute a compiler with the given CLI arguments and callbacks. fn run_compiler( mut args: Vec, + target_crate: bool, callbacks: &mut (dyn rustc_driver::Callbacks + Send), - insert_default_args: bool, ) -> ! { // Make sure we use the right default sysroot. The default sysroot is wrong, // because `get_or_default_sysroot` in `librustc_session` bases that on `current_exe`. // - // Make sure we always call `compile_time_sysroot` as that also does some sanity-checks - // of the environment we were built in. - // FIXME: Ideally we'd turn a bad build env into a compile-time error via CTFE or so. - if let Some(sysroot) = compile_time_sysroot() { - let sysroot_flag = "--sysroot"; - if !args.iter().any(|e| e == sysroot_flag) { + // Make sure we always call `host_sysroot` as that also does some sanity-checks + // of the environment we were built in and whether it matches what we are running in. + let host_default_sysroot = host_sysroot(); + // Now see if we even need to set something. + let sysroot_flag = "--sysroot"; + if !args.iter().any(|e| e == sysroot_flag) { + // No sysroot was set, let's see if we have a custom default we want to configure. + let default_sysroot = if target_crate { + // Using the built-in default here would be plain wrong, so we *require* + // the env var to make sure things make sense. + Some(env::var("MIRI_SYSROOT").unwrap_or_else(|_| { + show_error(format!( + "Miri was invoked in 'target' mode without `MIRI_SYSROOT` or `--sysroot` being set" + )) + })) + } else { + host_default_sysroot + }; + if let Some(sysroot) = default_sysroot { // We need to overwrite the default that librustc_session would compute. args.push(sysroot_flag.to_owned()); args.push(sysroot); } } - if insert_default_args { + // Don't insert `MIRI_DEFAULT_ARGS`, in particular, `--cfg=miri`, if we are building + // a "host" crate. That may cause procedural macros (and probably build scripts) to + // depend on Miri-only symbols, such as `miri_resolve_frame`: + // https://github.com/rust-lang/miri/issues/1760 + if target_crate { // Some options have different defaults in Miri than in plain rustc; apply those by making // them the first arguments after the binary name (but later arguments can overwrite them). args.splice(1..1, miri::MIRI_DEFAULT_ARGS.iter().map(ToString::to_string)); @@ -302,13 +323,8 @@ fn main() { // We cannot use `rustc_driver::main` as we need to adjust the CLI arguments. run_compiler( env::args().collect(), + target_crate, &mut MiriBeRustCompilerCalls { target_crate }, - // Don't insert `MIRI_DEFAULT_ARGS`, in particular, `--cfg=miri`, if we are building - // a "host" crate. That may cause procedural macros (and probably build scripts) to - // depend on Miri-only symbols, such as `miri_resolve_frame`: - // https://github.com/rust-lang/miri/issues/1760 - #[rustfmt::skip] - /* insert_default_args: */ target_crate, ) } @@ -502,9 +518,5 @@ fn main() { debug!("rustc arguments: {:?}", rustc_args); debug!("crate arguments: {:?}", miri_config.args); - run_compiler( - rustc_args, - &mut MiriCompilerCalls { miri_config }, - /* insert_default_args: */ true, - ) + run_compiler(rustc_args, /* target_crate: */ true, &mut MiriCompilerCalls { miri_config }) } diff --git a/test-cargo-miri/Cargo.lock b/test-cargo-miri/Cargo.lock index 38bfb2ac62077..a297dd27dbc94 100644 --- a/test-cargo-miri/Cargo.lock +++ b/test-cargo-miri/Cargo.lock @@ -2,6 +2,12 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + [[package]] name = "byteorder" version = "0.5.3" @@ -18,6 +24,7 @@ checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" name = "cargo-miri-test" version = "0.1.0" dependencies = [ + "autocfg", "byteorder 0.5.3", "byteorder 1.4.3", "cdylib", diff --git a/test-cargo-miri/Cargo.toml b/test-cargo-miri/Cargo.toml index 51967c54e15cf..5d9e5d143b3b3 100644 --- a/test-cargo-miri/Cargo.toml +++ b/test-cargo-miri/Cargo.toml @@ -21,6 +21,9 @@ issue_rust_86261 = { path = "issue-rust-86261" } byteorder_2 = { package = "byteorder", version = "0.5" } # to test dev-dependencies behave as expected, with renaming serde_derive = "1.0" # not actually used, but exercises some unique code path (`--extern` .so file) +[build-dependencies] +autocfg = "1" + [lib] test = false # test that this is respected (will show in the output) diff --git a/test-cargo-miri/build.rs b/test-cargo-miri/build.rs index 8b1e3af6231a0..5a01aab12300f 100644 --- a/test-cargo-miri/build.rs +++ b/test-cargo-miri/build.rs @@ -20,4 +20,9 @@ fn main() { println!("cargo:rerun-if-changed=build.rs"); println!("cargo:rerun-if-env-changed=MIRITESTVAR"); println!("cargo:rustc-env=MIRITESTVAR=testval"); + + // Test that autocfg works. This invokes RUSTC. + let a = autocfg::new(); + assert!(a.probe_sysroot_crate("std")); + assert!(!a.probe_sysroot_crate("doesnotexist")); } diff --git a/tests/compiletest.rs b/tests/compiletest.rs index 0f0179de5d243..48e0ae855be39 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -24,10 +24,6 @@ fn run_tests(mode: Mode, path: &str, target: Option) -> Result<()> { flags.push("-Dwarnings".into()); flags.push("-Dunused".into()); } - if let Some(sysroot) = env::var_os("MIRI_SYSROOT") { - flags.push("--sysroot".into()); - flags.push(sysroot); - } if let Ok(extra_flags) = env::var("MIRIFLAGS") { for flag in extra_flags.split_whitespace() { flags.push(flag.into()); From 0b1d5a495718027ed28d20491223adc16f29cfc5 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 24 Jul 2022 10:17:33 -0400 Subject: [PATCH 3581/3747] test all of the autocfg queries --- README.md | 6 +++--- test-cargo-miri/build.rs | 12 ++++++++++++ 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 1ab081bfe2351..5fbf89c86b969 100644 --- a/README.md +++ b/README.md @@ -409,9 +409,9 @@ Moreover, Miri recognizes some environment variables: checkout. Note that changing files in that directory does not automatically trigger a re-build of the standard library; you have to clear the Miri build cache manually (on Linux, `rm -rf ~/.cache/miri`). -* `MIRI_SYSROOT` (recognized by `cargo miri` and the Miri driver) indicates the - sysroot to use. Only set this if you do not want to use the automatically - created sysroot. +* `MIRI_SYSROOT` (recognized by `cargo miri` and the Miri driver) indicates the sysroot to use. When + using `cargo miri`, only set this if you do not want to use the automatically created sysroot. For + directly invoking the Miri driver, this variable (or a `--sysroot` flag) is mandatory. * `MIRI_TEST_TARGET` (recognized by the test suite and the `./miri` script) indicates which target architecture to test against. `miri` and `cargo miri` accept the `--target` flag for the same purpose. diff --git a/test-cargo-miri/build.rs b/test-cargo-miri/build.rs index 5a01aab12300f..6c1f4d80d3392 100644 --- a/test-cargo-miri/build.rs +++ b/test-cargo-miri/build.rs @@ -25,4 +25,16 @@ fn main() { let a = autocfg::new(); assert!(a.probe_sysroot_crate("std")); assert!(!a.probe_sysroot_crate("doesnotexist")); + assert!(a.probe_rustc_version(1, 0)); + assert!(!a.probe_rustc_version(2, 0)); + assert!(a.probe_type("i128")); + assert!(!a.probe_type("doesnotexist")); + assert!(a.probe_trait("Send")); + assert!(!a.probe_trait("doesnotexist")); + assert!(a.probe_path("std::num")); + assert!(!a.probe_path("doesnotexist")); + assert!(a.probe_constant("i32::MAX")); + assert!(!a.probe_constant("doesnotexist")); + assert!(a.probe_expression("Box::new(0)")); + assert!(!a.probe_expression("doesnotexist")); } From 9406b6da68762ec26d9e60b03b38722fee6395ef Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 24 Jul 2022 13:58:14 -0400 Subject: [PATCH 3582/3747] fmt --- cargo-miri/bin.rs | 36 +++++++++++++++++++++--------------- 1 file changed, 21 insertions(+), 15 deletions(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index 7bfd99a7f1ed3..8aeeb044d3c17 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -761,17 +761,19 @@ fn phase_cargo_miri(mut args: impl Iterator) { "WARNING: Ignoring `RUSTC` environment variable; set `MIRI` if you want to control the binary used as the driver." ); } - // Build scripts (and also cargo: https://github.com/rust-lang/cargo/issues/10885) will invoke `rustc` even when `RUSTC_WRAPPER` is set. - // To make sure everything is coherent, we want that to be the Miri driver, but acting as rustc, on the target level. - // (Target, rather than host, is needed for cross-interpretation situations.) This is not a - // perfect emulation of real rustc (it might be unable to produce binaries since the sysroot is - // check-only), but it's as close as we can get, and it's good enough for autocfg. + // Build scripts (and also cargo: https://github.com/rust-lang/cargo/issues/10885) will invoke + // `rustc` even when `RUSTC_WRAPPER` is set. To make sure everything is coherent, we want that + // to be the Miri driver, but acting as rustc, on the target level. (Target, rather than host, + // is needed for cross-interpretation situations.) This is not a perfect emulation of real rustc + // (it might be unable to produce binaries since the sysroot is check-only), but it's as close + // as we can get, and it's good enough for autocfg. // // In `main`, we need the value of `RUSTC` to distinguish RUSTC_WRAPPER invocations from rustdoc // or TARGET_RUNNER invocations, so we canonicalize it here to make it exceedingly unlikely that - // there would be a collision with other invocations of cargo-miri (as rustdoc or as runner). - // We explicitly do this even if RUSTC_STAGE is set, since for these builds we do *not* want the - // bootstrap `rustc` thing in our way! Instead, we have MIRI_HOST_SYSROOT to use for host builds. + // there would be a collision with other invocations of cargo-miri (as rustdoc or as runner). We + // explicitly do this even if RUSTC_STAGE is set, since for these builds we do *not* want the + // bootstrap `rustc` thing in our way! Instead, we have MIRI_HOST_SYSROOT to use for host + // builds. cmd.env("RUSTC", &fs::canonicalize(find_miri()).unwrap()); cmd.env("MIRI_BE_RUSTC", "target"); // we better remember to *unset* this in the other phases! @@ -850,7 +852,8 @@ fn phase_rustc(mut args: impl Iterator, phase: RustcPhase) { let verbose = std::env::var("MIRI_VERBOSE") .map_or(0, |verbose| verbose.parse().expect("verbosity flag must be an integer")); let target_crate = is_target_crate(); - let print = get_arg_flag_value("--print").is_some() || has_arg_flag("-vV"); // whether this is cargo/xargo invoking rustc to get some infos + // Determine whether this is cargo/xargo invoking rustc to get some infos. + let info_query = get_arg_flag_value("--print").is_some() || has_arg_flag("-vV"); let store_json = |info: CrateRunInfo| { // Create a stub .d file to stop Cargo from "rebuilding" the crate: @@ -872,7 +875,7 @@ fn phase_rustc(mut args: impl Iterator, phase: RustcPhase) { info.store(&out_filename("", ".exe")); }; - let runnable_crate = !print && is_runnable_crate(); + let runnable_crate = !info_query && is_runnable_crate(); if runnable_crate && target_crate { assert!( @@ -934,7 +937,7 @@ fn phase_rustc(mut args: impl Iterator, phase: RustcPhase) { let mut emit_link_hack = false; // Arguments are treated very differently depending on whether this crate is // for interpretation by Miri, or for use by a build script / proc macro. - if !print && target_crate { + if !info_query && target_crate { // Forward arguments, but remove "link" from "--emit" to make this a check-only build. let emit_flag = "--emit"; while let Some(arg) = args.next() { @@ -968,8 +971,9 @@ fn phase_rustc(mut args: impl Iterator, phase: RustcPhase) { cmd.arg("-C").arg("panic=abort"); } } else { - // For host crates (but not when we are printing), we might still have to set the sysroot. - if !print { + // For host crates (but not when we are just printing some info), + // we might still have to set the sysroot. + if !info_query { // When we're running `cargo-miri` from `x.py` we need to pass the sysroot explicitly // due to bootstrap complications. if let Some(sysroot) = std::env::var_os("MIRI_HOST_SYSROOT") { @@ -990,7 +994,7 @@ fn phase_rustc(mut args: impl Iterator, phase: RustcPhase) { // Run it. if verbose > 0 { eprintln!( - "[cargo-miri rustc] target_crate={target_crate} runnable_crate={runnable_crate} print={print}" + "[cargo-miri rustc] target_crate={target_crate} runnable_crate={runnable_crate} info_query={info_query}" ); } debug_cmd("[cargo-miri rustc]", verbose, &cmd); @@ -1030,7 +1034,9 @@ fn phase_runner(mut binary_args: impl Iterator, phase: RunnerPhas let binary = binary_args.next().unwrap(); let file = File::open(&binary) - .unwrap_or_else(|_| show_error(format!("file {:?} not found or `cargo-miri` invoked incorrectly; please only invoke this binary through `cargo miri`", binary))); + .unwrap_or_else(|_| show_error(format!( + "file {:?} not found or `cargo-miri` invoked incorrectly; please only invoke this binary through `cargo miri`", binary + ))); let file = BufReader::new(file); let info = serde_json::from_reader(file).unwrap_or_else(|_| { From 8f3b594d1ee94e5e908ea6a775560f3c7ab695e7 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 24 Jul 2022 15:23:39 -0400 Subject: [PATCH 3583/3747] more tests for ptr_offset_from_unsinged --- .../ptr_offset_from_unsigned_neg.rs | 9 +++++++++ .../ptr_offset_from_unsigned_neg.stderr | 20 +++++++++++++++++++ tests/pass/intrinsics.rs | 9 ++------- tests/pass/pointers.rs | 9 ++++++++- tests/pass/ptr_offset.rs | 18 +++++++++++++++++ 5 files changed, 57 insertions(+), 8 deletions(-) create mode 100644 tests/fail/intrinsics/ptr_offset_from_unsigned_neg.rs create mode 100644 tests/fail/intrinsics/ptr_offset_from_unsigned_neg.stderr diff --git a/tests/fail/intrinsics/ptr_offset_from_unsigned_neg.rs b/tests/fail/intrinsics/ptr_offset_from_unsigned_neg.rs new file mode 100644 index 0000000000000..d6413faf74bfa --- /dev/null +++ b/tests/fail/intrinsics/ptr_offset_from_unsigned_neg.rs @@ -0,0 +1,9 @@ +//@error-pattern: first pointer has smaller offset than second: 0 < 4 +#![feature(ptr_sub_ptr)] + +fn main() { + let arr = [0u8; 8]; + let ptr1 = arr.as_ptr(); + let ptr2 = ptr1.wrapping_add(4); + let _val = unsafe { ptr1.sub_ptr(ptr2) }; +} diff --git a/tests/fail/intrinsics/ptr_offset_from_unsigned_neg.stderr b/tests/fail/intrinsics/ptr_offset_from_unsigned_neg.stderr new file mode 100644 index 0000000000000..bb68f9f5c18c5 --- /dev/null +++ b/tests/fail/intrinsics/ptr_offset_from_unsigned_neg.stderr @@ -0,0 +1,20 @@ +error: Undefined Behavior: ptr_offset_from_unsigned called when first pointer has smaller offset than second: 0 < 4 + --> RUSTLIB/core/src/ptr/const_ptr.rs:LL:CC + | +LL | unsafe { intrinsics::ptr_offset_from_unsigned(self, origin) } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ptr_offset_from_unsigned called when first pointer has smaller offset than second: 0 < 4 + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: backtrace: + = note: inside `std::ptr::const_ptr::::sub_ptr` at RUSTLIB/core/src/ptr/const_ptr.rs:LL:CC +note: inside `main` at $DIR/ptr_offset_from_unsigned_neg.rs:LL:CC + --> $DIR/ptr_offset_from_unsigned_neg.rs:LL:CC + | +LL | let _val = unsafe { ptr1.sub_ptr(ptr2) }; + | ^^^^^^^^^^^^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/pass/intrinsics.rs b/tests/pass/intrinsics.rs index 756744badaf9c..6267e6e6bc111 100644 --- a/tests/pass/intrinsics.rs +++ b/tests/pass/intrinsics.rs @@ -1,6 +1,6 @@ //@compile-flags: -Zmiri-permissive-provenance -#![feature(core_intrinsics, const_raw_ptr_comparison)] -#![feature(layout_for_ptr)] +#![feature(core_intrinsics, layout_for_ptr)] +//! Tests for various intrinsics that do not fit anywhere else. use std::intrinsics; use std::mem::{size_of, size_of_val, size_of_val_raw}; @@ -39,9 +39,4 @@ fn main() { let _v = intrinsics::discriminant_value(&0); let _v = intrinsics::discriminant_value(&true); let _v = intrinsics::discriminant_value(&vec![1, 2, 3]); - - let addr = &13 as *const i32; - let addr2 = (addr as usize).wrapping_add(usize::MAX).wrapping_add(1); - assert!(addr.guaranteed_eq(addr2 as *const _)); - assert!(addr.guaranteed_ne(0x100 as *const _)); } diff --git a/tests/pass/pointers.rs b/tests/pass/pointers.rs index a271e764d9f4a..b2e6f4556fa2e 100644 --- a/tests/pass/pointers.rs +++ b/tests/pass/pointers.rs @@ -1,4 +1,5 @@ -#![feature(ptr_metadata)] +//@compile-flags: -Zmiri-permissive-provenance +#![feature(ptr_metadata, const_raw_ptr_comparison)] use std::mem::{self, transmute}; use std::ptr; @@ -131,6 +132,12 @@ fn main() { assert!(dangling > 3); assert!(dangling >= 4); + // CTFE-specific equality tests, need to also work at runtime. + let addr = &13 as *const i32; + let addr2 = (addr as usize).wrapping_add(usize::MAX).wrapping_add(1); + assert!(addr.guaranteed_eq(addr2 as *const _)); + assert!(addr.guaranteed_ne(0x100 as *const _)); + wide_ptr_ops(); metadata_vtable(); } diff --git a/tests/pass/ptr_offset.rs b/tests/pass/ptr_offset.rs index 5270e8663b2d7..95eac8522fb40 100644 --- a/tests/pass/ptr_offset.rs +++ b/tests/pass/ptr_offset.rs @@ -1,7 +1,9 @@ //@compile-flags: -Zmiri-permissive-provenance +#![feature(ptr_sub_ptr)] use std::{mem, ptr}; fn main() { + smoke(); test_offset_from(); test_vec_into_iter(); ptr_arith_offset(); @@ -9,6 +11,20 @@ fn main() { ptr_offset(); } +fn smoke() { + // Smoke-test various offsetting operations. + let ptr = &5; + let ptr = ptr as *const i32; + let _val = ptr.wrapping_offset(0); + let _val = unsafe { ptr.offset(0) }; + let _val = ptr.wrapping_add(0); + let _val = unsafe { ptr.add(0) }; + let _val = ptr.wrapping_sub(0); + let _val = unsafe { ptr.sub(0) }; + let _val = unsafe { ptr.offset_from(ptr) }; + let _val = unsafe { ptr.sub_ptr(ptr) }; +} + fn test_offset_from() { unsafe { let buf = [0u32; 4]; @@ -17,12 +33,14 @@ fn test_offset_from() { let y = x.offset(12); assert_eq!(y.offset_from(x), 12); + assert_eq!(y.sub_ptr(x), 12); assert_eq!(x.offset_from(y), -12); assert_eq!((y as *const u32).offset_from(x as *const u32), 12 / 4); assert_eq!((x as *const u32).offset_from(y as *const u32), -12 / 4); let x = (((x as usize) * 2) / 2) as *const u8; assert_eq!(y.offset_from(x), 12); + assert_eq!(y.sub_ptr(x), 12); assert_eq!(x.offset_from(y), -12); } } From cbff63a6944b3285a9525881dc85870e694fb055 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 24 Jul 2022 17:51:29 -0400 Subject: [PATCH 3584/3747] rustup --- rust-version | 2 +- src/machine.rs | 13 ------------- src/operator.rs | 4 ++-- src/shims/intrinsics/simd.rs | 2 +- src/shims/panic.rs | 7 +++---- src/shims/tls.rs | 13 ++++--------- src/shims/unix/linux/sync.rs | 2 +- 7 files changed, 12 insertions(+), 31 deletions(-) diff --git a/rust-version b/rust-version index c710735735c7c..b70ab6fdd46e5 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -35a061724802377a21fc6dac1ebcbb9b8d1f558a +7fe022f5aa32bbbb33c3a58755729d6667a461a9 diff --git a/src/machine.rs b/src/machine.rs index 3e45f77d54c3a..2c9bfe803ad2f 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -545,11 +545,6 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { true } - #[inline(always)] - fn enforce_number_no_provenance(_ecx: &MiriEvalContext<'mir, 'tcx>) -> bool { - true - } - #[inline(always)] fn enforce_abi(ecx: &MiriEvalContext<'mir, 'tcx>) -> bool { ecx.machine.enforce_abi @@ -753,14 +748,6 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { intptrcast::GlobalStateInner::ptr_from_addr_cast(ecx, addr) } - #[inline(always)] - fn ptr_from_addr_transmute( - ecx: &MiriEvalContext<'mir, 'tcx>, - addr: u64, - ) -> Pointer> { - intptrcast::GlobalStateInner::ptr_from_addr_transmute(ecx, addr) - } - fn expose_ptr( ecx: &mut InterpCx<'mir, 'tcx, Self>, ptr: Pointer, diff --git a/src/operator.rs b/src/operator.rs index 758e747d27867..679686b4005e1 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -57,7 +57,7 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { Offset => { assert!(left.layout.ty.is_unsafe_ptr()); - let ptr = self.scalar_to_ptr(left.to_scalar()?)?; + let ptr = left.to_scalar()?.to_pointer(self)?; let offset = right.to_scalar()?.to_machine_isize(self)?; let pointee_ty = @@ -71,7 +71,7 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { Add | Sub | BitOr | BitAnd | BitXor => { assert!(left.layout.ty.is_unsafe_ptr()); assert!(right.layout.ty.is_unsafe_ptr()); - let ptr = self.scalar_to_ptr(left.to_scalar()?)?; + let ptr = left.to_scalar()?.to_pointer(self)?; // We do the actual operation with usize-typed scalars. let left = ImmTy::from_uint(ptr.addr().bytes(), self.machine.layouts.usize); let right = ImmTy::from_uint( diff --git a/src/shims/intrinsics/simd.rs b/src/shims/intrinsics/simd.rs index 96e97d79358bf..d467c3c509f5f 100644 --- a/src/shims/intrinsics/simd.rs +++ b/src/shims/intrinsics/simd.rs @@ -201,7 +201,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.saturating_arith(mir_op, &left, &right)? } Op::WrappingOffset => { - let ptr = this.scalar_to_ptr(left.to_scalar()?)?; + let ptr = left.to_scalar()?.to_pointer(this)?; let offset_count = right.to_scalar()?.to_machine_isize(this)?; let pointee_ty = left.layout.ty.builtin_deref(true).unwrap().ty; diff --git a/src/shims/panic.rs b/src/shims/panic.rs index 362b929eabfee..687c84308a97c 100644 --- a/src/shims/panic.rs +++ b/src/shims/panic.rs @@ -26,7 +26,7 @@ use helpers::check_arg_count; #[derive(Debug)] pub struct CatchUnwindData<'tcx> { /// The `catch_fn` callback to call in case of a panic. - catch_fn: Scalar, + catch_fn: Pointer>, /// The `data` argument for that callback. data: Scalar, /// The return place from the original call to `try`. @@ -86,7 +86,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let [try_fn, data, catch_fn] = check_arg_count(args)?; let try_fn = this.read_pointer(try_fn)?; let data = this.read_scalar(data)?.check_init()?; - let catch_fn = this.read_scalar(catch_fn)?.check_init()?; + let catch_fn = this.read_pointer(catch_fn)?; // Now we make a function call, and pass `data` as first and only argument. let f_instance = this.get_ptr_fn(try_fn)?.as_instance()?; @@ -140,8 +140,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let payload = this.active_thread_mut().panic_payload.take().unwrap(); // Push the `catch_fn` stackframe. - let f_instance = - this.get_ptr_fn(this.scalar_to_ptr(catch_unwind.catch_fn)?)?.as_instance()?; + let f_instance = this.get_ptr_fn(catch_unwind.catch_fn)?.as_instance()?; trace!("catch_fn: {:?}", f_instance); this.call_function( f_instance, diff --git a/src/shims/tls.rs b/src/shims/tls.rs index 13af447f76c67..2f0fb41b9e92f 100644 --- a/src/shims/tls.rs +++ b/src/shims/tls.rs @@ -241,15 +241,10 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // (that would be basically https://github.com/rust-lang/miri/issues/450), // we specifically look up the static in libstd that we know is placed // in that section. - let thread_callback = this.eval_path_scalar(&[ - "std", - "sys", - "windows", - "thread_local_key", - "p_thread_callback", - ])?; - let thread_callback = - this.get_ptr_fn(this.scalar_to_ptr(thread_callback)?)?.as_instance()?; + let thread_callback = this + .eval_path_scalar(&["std", "sys", "windows", "thread_local_key", "p_thread_callback"])? + .to_pointer(this)?; + let thread_callback = this.get_ptr_fn(thread_callback)?.as_instance()?; // The signature of this function is `unsafe extern "system" fn(h: c::LPVOID, dwReason: c::DWORD, pv: c::LPVOID)`. let reason = this.eval_path_scalar(&["std", "sys", "windows", "c", "DLL_THREAD_DETACH"])?; diff --git a/src/shims/unix/linux/sync.rs b/src/shims/unix/linux/sync.rs index a11aa8ed849c8..59de10498745f 100644 --- a/src/shims/unix/linux/sync.rs +++ b/src/shims/unix/linux/sync.rs @@ -121,7 +121,7 @@ pub fn futex<'tcx>( // The API requires `addr` to be a 4-byte aligned pointer, and will // use the 4 bytes at the given address as an (atomic) i32. this.check_ptr_access_align( - this.scalar_to_ptr(addr_scalar)?, + addr_scalar.to_pointer(this)?, Size::from_bytes(4), Align::from_bytes(4).unwrap(), CheckInAllocMsg::MemoryAccessTest, From b514667c36f559317a316a5d9b8cd019328be581 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 24 Jul 2022 14:28:45 -0400 Subject: [PATCH 3585/3747] adjust for more backtrace pruning --- tests/fail/intrinsics/copy_overflow.rs | 2 +- tests/fail/intrinsics/copy_overflow.stderr | 14 ++++---------- tests/fail/intrinsics/out_of_bounds_ptr_1.rs | 3 +-- tests/fail/intrinsics/out_of_bounds_ptr_1.stderr | 13 ++++--------- tests/fail/intrinsics/out_of_bounds_ptr_2.rs | 3 +-- tests/fail/intrinsics/out_of_bounds_ptr_2.stderr | 13 ++++--------- tests/fail/intrinsics/out_of_bounds_ptr_3.rs | 3 +-- tests/fail/intrinsics/out_of_bounds_ptr_3.stderr | 13 ++++--------- tests/fail/intrinsics/overflowing-unchecked-rsh.rs | 6 ++---- .../intrinsics/overflowing-unchecked-rsh.stderr | 4 ++-- tests/fail/intrinsics/ptr_offset_0_plus_0.rs | 3 ++- tests/fail/intrinsics/ptr_offset_0_plus_0.stderr | 13 ++++--------- tests/fail/intrinsics/ptr_offset_from_oob.rs | 6 +----- tests/fail/intrinsics/ptr_offset_from_oob.stderr | 4 ++-- tests/fail/intrinsics/ptr_offset_int_plus_int.rs | 3 +-- .../fail/intrinsics/ptr_offset_int_plus_int.stderr | 13 ++++--------- tests/fail/intrinsics/ptr_offset_int_plus_ptr.rs | 3 +-- .../fail/intrinsics/ptr_offset_int_plus_ptr.stderr | 13 ++++--------- tests/fail/intrinsics/ptr_offset_overflow.rs | 3 +-- tests/fail/intrinsics/ptr_offset_overflow.stderr | 13 ++++--------- tests/fail/intrinsics/ptr_offset_ptr_plus_0.rs | 4 ++-- tests/fail/intrinsics/ptr_offset_ptr_plus_0.stderr | 13 ++++--------- tests/fail/intrinsics/unchecked_add1.rs | 7 +++---- tests/fail/intrinsics/unchecked_add1.stderr | 4 ++-- tests/fail/intrinsics/unchecked_add2.rs | 7 +++---- tests/fail/intrinsics/unchecked_add2.stderr | 4 ++-- tests/fail/intrinsics/unchecked_mul1.rs | 6 ++---- tests/fail/intrinsics/unchecked_mul1.stderr | 4 ++-- tests/fail/intrinsics/unchecked_mul2.rs | 6 ++---- tests/fail/intrinsics/unchecked_mul2.stderr | 4 ++-- tests/fail/intrinsics/unchecked_sub1.rs | 6 ++---- tests/fail/intrinsics/unchecked_sub1.stderr | 4 ++-- tests/fail/intrinsics/unchecked_sub2.rs | 6 ++---- tests/fail/intrinsics/unchecked_sub2.stderr | 4 ++-- tests/fail/invalid_enum_tag.rs | 4 +--- tests/fail/invalid_enum_tag.stderr | 13 ++++--------- tests/fail/provenance/ptr_invalid_offset.rs | 3 +-- tests/fail/provenance/ptr_invalid_offset.stderr | 13 ++++--------- tests/fail/should-pass/cpp20_rwc_syncs.rs | 3 +-- tests/fail/should-pass/cpp20_rwc_syncs.stderr | 13 ++++--------- tests/fail/unreachable.rs | 3 +-- tests/fail/unreachable.stderr | 13 ++++--------- tests/fail/weak_memory/racing_mixed_size.rs | 3 ++- 43 files changed, 102 insertions(+), 193 deletions(-) diff --git a/tests/fail/intrinsics/copy_overflow.rs b/tests/fail/intrinsics/copy_overflow.rs index c4ce192c449c3..e64a1f9090214 100644 --- a/tests/fail/intrinsics/copy_overflow.rs +++ b/tests/fail/intrinsics/copy_overflow.rs @@ -1,4 +1,3 @@ -//@error-pattern: overflow computing total size use std::mem; fn main() { @@ -6,5 +5,6 @@ fn main() { let mut y = 0; unsafe { (&mut y as *mut i32).copy_from(&x, 1usize << (mem::size_of::() * 8 - 1)); + //~^ERROR: overflow computing total size } } diff --git a/tests/fail/intrinsics/copy_overflow.stderr b/tests/fail/intrinsics/copy_overflow.stderr index 76917ae7ea157..3534f4d1fb85b 100644 --- a/tests/fail/intrinsics/copy_overflow.stderr +++ b/tests/fail/intrinsics/copy_overflow.stderr @@ -1,19 +1,13 @@ error: Undefined Behavior: overflow computing total size of `copy` - --> RUSTLIB/core/src/intrinsics.rs:LL:CC + --> $DIR/copy_overflow.rs:LL:CC | -LL | copy(src, dst, count) - | ^^^^^^^^^^^^^^^^^^^^^ overflow computing total size of `copy` +LL | (&mut y as *mut i32).copy_from(&x, 1usize << (mem::size_of::() * 8 - 1)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflow computing total size of `copy` | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: backtrace: - = note: inside `std::intrinsics::copy::` at RUSTLIB/core/src/intrinsics.rs:LL:CC - = note: inside `std::ptr::mut_ptr::::copy_from` at RUSTLIB/core/src/ptr/mut_ptr.rs:LL:CC -note: inside `main` at $DIR/copy_overflow.rs:LL:CC - --> $DIR/copy_overflow.rs:LL:CC - | -LL | (&mut y as *mut i32).copy_from(&x, 1usize << (mem::size_of::() * 8 - 1)); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: inside `main` at $DIR/copy_overflow.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/out_of_bounds_ptr_1.rs b/tests/fail/intrinsics/out_of_bounds_ptr_1.rs index 0109bff696888..b6a110ee84d2c 100644 --- a/tests/fail/intrinsics/out_of_bounds_ptr_1.rs +++ b/tests/fail/intrinsics/out_of_bounds_ptr_1.rs @@ -1,8 +1,7 @@ -//@error-pattern: pointer to 5 bytes starting at offset 0 is out-of-bounds fn main() { let v = [0i8; 4]; let x = &v as *const i8; // The error is inside another function, so we cannot match it by line - let x = unsafe { x.offset(5) }; + let x = unsafe { x.offset(5) }; //~ERROR: pointer to 5 bytes starting at offset 0 is out-of-bounds panic!("this should never print: {:?}", x); } diff --git a/tests/fail/intrinsics/out_of_bounds_ptr_1.stderr b/tests/fail/intrinsics/out_of_bounds_ptr_1.stderr index 789e9d1f6cbed..afa2c8306466c 100644 --- a/tests/fail/intrinsics/out_of_bounds_ptr_1.stderr +++ b/tests/fail/intrinsics/out_of_bounds_ptr_1.stderr @@ -1,18 +1,13 @@ error: Undefined Behavior: out-of-bounds pointer arithmetic: ALLOC has size 4, so pointer to 5 bytes starting at offset 0 is out-of-bounds - --> RUSTLIB/core/src/ptr/const_ptr.rs:LL:CC + --> $DIR/out_of_bounds_ptr_1.rs:LL:CC | -LL | unsafe { intrinsics::offset(self, count) } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer arithmetic: ALLOC has size 4, so pointer to 5 bytes starting at offset 0 is out-of-bounds +LL | let x = unsafe { x.offset(5) }; + | ^^^^^^^^^^^ out-of-bounds pointer arithmetic: ALLOC has size 4, so pointer to 5 bytes starting at offset 0 is out-of-bounds | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: backtrace: - = note: inside `std::ptr::const_ptr::::offset` at RUSTLIB/core/src/ptr/const_ptr.rs:LL:CC -note: inside `main` at $DIR/out_of_bounds_ptr_1.rs:LL:CC - --> $DIR/out_of_bounds_ptr_1.rs:LL:CC - | -LL | let x = unsafe { x.offset(5) }; - | ^^^^^^^^^^^ + = note: inside `main` at $DIR/out_of_bounds_ptr_1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/out_of_bounds_ptr_2.rs b/tests/fail/intrinsics/out_of_bounds_ptr_2.rs index 74d391dc21208..0d4eea9a5bdea 100644 --- a/tests/fail/intrinsics/out_of_bounds_ptr_2.rs +++ b/tests/fail/intrinsics/out_of_bounds_ptr_2.rs @@ -1,7 +1,6 @@ -//@error-pattern: overflowing in-bounds pointer arithmetic fn main() { let v = [0i8; 4]; let x = &v as *const i8; - let x = unsafe { x.offset(isize::MIN) }; + let x = unsafe { x.offset(isize::MIN) }; //~ERROR: overflowing in-bounds pointer arithmetic panic!("this should never print: {:?}", x); } diff --git a/tests/fail/intrinsics/out_of_bounds_ptr_2.stderr b/tests/fail/intrinsics/out_of_bounds_ptr_2.stderr index 70ce2dc02a821..a32b50a18e6a6 100644 --- a/tests/fail/intrinsics/out_of_bounds_ptr_2.stderr +++ b/tests/fail/intrinsics/out_of_bounds_ptr_2.stderr @@ -1,18 +1,13 @@ error: Undefined Behavior: overflowing in-bounds pointer arithmetic - --> RUSTLIB/core/src/ptr/const_ptr.rs:LL:CC + --> $DIR/out_of_bounds_ptr_2.rs:LL:CC | -LL | unsafe { intrinsics::offset(self, count) } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflowing in-bounds pointer arithmetic +LL | let x = unsafe { x.offset(isize::MIN) }; + | ^^^^^^^^^^^^^^^^^^^^ overflowing in-bounds pointer arithmetic | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: backtrace: - = note: inside `std::ptr::const_ptr::::offset` at RUSTLIB/core/src/ptr/const_ptr.rs:LL:CC -note: inside `main` at $DIR/out_of_bounds_ptr_2.rs:LL:CC - --> $DIR/out_of_bounds_ptr_2.rs:LL:CC - | -LL | let x = unsafe { x.offset(isize::MIN) }; - | ^^^^^^^^^^^^^^^^^^^^ + = note: inside `main` at $DIR/out_of_bounds_ptr_2.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/out_of_bounds_ptr_3.rs b/tests/fail/intrinsics/out_of_bounds_ptr_3.rs index b54cf3dd25c03..701bc33a645e1 100644 --- a/tests/fail/intrinsics/out_of_bounds_ptr_3.rs +++ b/tests/fail/intrinsics/out_of_bounds_ptr_3.rs @@ -1,7 +1,6 @@ -//@error-pattern: pointer to 1 byte starting at offset -1 is out-of-bounds fn main() { let v = [0i8; 4]; let x = &v as *const i8; - let x = unsafe { x.offset(-1) }; + let x = unsafe { x.offset(-1) }; //~ERROR: pointer to 1 byte starting at offset -1 is out-of-bounds panic!("this should never print: {:?}", x); } diff --git a/tests/fail/intrinsics/out_of_bounds_ptr_3.stderr b/tests/fail/intrinsics/out_of_bounds_ptr_3.stderr index 973bf043e155c..d06c33beb48a1 100644 --- a/tests/fail/intrinsics/out_of_bounds_ptr_3.stderr +++ b/tests/fail/intrinsics/out_of_bounds_ptr_3.stderr @@ -1,18 +1,13 @@ error: Undefined Behavior: out-of-bounds pointer arithmetic: ALLOC has size 4, so pointer to 1 byte starting at offset -1 is out-of-bounds - --> RUSTLIB/core/src/ptr/const_ptr.rs:LL:CC + --> $DIR/out_of_bounds_ptr_3.rs:LL:CC | -LL | unsafe { intrinsics::offset(self, count) } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer arithmetic: ALLOC has size 4, so pointer to 1 byte starting at offset -1 is out-of-bounds +LL | let x = unsafe { x.offset(-1) }; + | ^^^^^^^^^^^^ out-of-bounds pointer arithmetic: ALLOC has size 4, so pointer to 1 byte starting at offset -1 is out-of-bounds | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: backtrace: - = note: inside `std::ptr::const_ptr::::offset` at RUSTLIB/core/src/ptr/const_ptr.rs:LL:CC -note: inside `main` at $DIR/out_of_bounds_ptr_3.rs:LL:CC - --> $DIR/out_of_bounds_ptr_3.rs:LL:CC - | -LL | let x = unsafe { x.offset(-1) }; - | ^^^^^^^^^^^^ + = note: inside `main` at $DIR/out_of_bounds_ptr_3.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/overflowing-unchecked-rsh.rs b/tests/fail/intrinsics/overflowing-unchecked-rsh.rs index 958a9f90ed983..fe2e85be69868 100644 --- a/tests/fail/intrinsics/overflowing-unchecked-rsh.rs +++ b/tests/fail/intrinsics/overflowing-unchecked-rsh.rs @@ -1,10 +1,8 @@ -#![feature(core_intrinsics)] - -use std::intrinsics::*; +#![feature(unchecked_math)] fn main() { unsafe { - let _n = unchecked_shr(1i64, 64); + let _n = 1i64.unchecked_shr(64); //~^ ERROR: overflowing shift by 64 in `unchecked_shr` } } diff --git a/tests/fail/intrinsics/overflowing-unchecked-rsh.stderr b/tests/fail/intrinsics/overflowing-unchecked-rsh.stderr index 705ae01188b8c..bba92602285ac 100644 --- a/tests/fail/intrinsics/overflowing-unchecked-rsh.stderr +++ b/tests/fail/intrinsics/overflowing-unchecked-rsh.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: overflowing shift by 64 in `unchecked_shr` --> $DIR/overflowing-unchecked-rsh.rs:LL:CC | -LL | let _n = unchecked_shr(1i64, 64); - | ^^^^^^^^^^^^^^^^^^^^^^^ overflowing shift by 64 in `unchecked_shr` +LL | let _n = 1i64.unchecked_shr(64); + | ^^^^^^^^^^^^^^^^^^^^^^ overflowing shift by 64 in `unchecked_shr` | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/intrinsics/ptr_offset_0_plus_0.rs b/tests/fail/intrinsics/ptr_offset_0_plus_0.rs index 32974a825a54c..e2329c1313984 100644 --- a/tests/fail/intrinsics/ptr_offset_0_plus_0.rs +++ b/tests/fail/intrinsics/ptr_offset_0_plus_0.rs @@ -1,8 +1,9 @@ -//@error-pattern: null pointer is a dangling pointer //@compile-flags: -Zmiri-permissive-provenance +#[rustfmt::skip] // fails with "left behind trailing whitespace" fn main() { let x = 0 as *mut i32; let _x = x.wrapping_offset(8); // ok, this has no inbounds tag let _x = unsafe { x.offset(0) }; // UB despite offset 0, NULL is never inbounds + //~^ERROR: null pointer is a dangling pointer } diff --git a/tests/fail/intrinsics/ptr_offset_0_plus_0.stderr b/tests/fail/intrinsics/ptr_offset_0_plus_0.stderr index cb9b02c840519..40a5022351dd7 100644 --- a/tests/fail/intrinsics/ptr_offset_0_plus_0.stderr +++ b/tests/fail/intrinsics/ptr_offset_0_plus_0.stderr @@ -1,18 +1,13 @@ error: Undefined Behavior: out-of-bounds pointer arithmetic: null pointer is a dangling pointer (it has no provenance) - --> RUSTLIB/core/src/ptr/mut_ptr.rs:LL:CC + --> $DIR/ptr_offset_0_plus_0.rs:LL:CC | -LL | unsafe { intrinsics::offset(self, count) as *mut T } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer arithmetic: null pointer is a dangling pointer (it has no provenance) +LL | let _x = unsafe { x.offset(0) }; // UB despite offset 0, NULL is never inbounds + | ^^^^^^^^^^^ out-of-bounds pointer arithmetic: null pointer is a dangling pointer (it has no provenance) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: backtrace: - = note: inside `std::ptr::mut_ptr::::offset` at RUSTLIB/core/src/ptr/mut_ptr.rs:LL:CC -note: inside `main` at $DIR/ptr_offset_0_plus_0.rs:LL:CC - --> $DIR/ptr_offset_0_plus_0.rs:LL:CC - | -LL | let _x = unsafe { x.offset(0) }; // UB despite offset 0, NULL is never inbounds - | ^^^^^^^^^^^ + = note: inside `main` at $DIR/ptr_offset_0_plus_0.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/ptr_offset_from_oob.rs b/tests/fail/intrinsics/ptr_offset_from_oob.rs index 1fd5100a97b9f..0e5acf08b2030 100644 --- a/tests/fail/intrinsics/ptr_offset_from_oob.rs +++ b/tests/fail/intrinsics/ptr_offset_from_oob.rs @@ -1,11 +1,7 @@ -#![feature(core_intrinsics)] - -use std::intrinsics::ptr_offset_from; - fn main() { let start_ptr = &4 as *const _ as *const u8; let length = 10; let end_ptr = start_ptr.wrapping_add(length); // Even if the offset is 0, a dangling OOB pointer is not allowed. - unsafe { ptr_offset_from(end_ptr, end_ptr) }; //~ERROR: pointer at offset 10 is out-of-bounds + unsafe { end_ptr.offset_from(end_ptr) }; //~ERROR: pointer at offset 10 is out-of-bounds } diff --git a/tests/fail/intrinsics/ptr_offset_from_oob.stderr b/tests/fail/intrinsics/ptr_offset_from_oob.stderr index 699ca1a87ae87..546245a499e12 100644 --- a/tests/fail/intrinsics/ptr_offset_from_oob.stderr +++ b/tests/fail/intrinsics/ptr_offset_from_oob.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: out-of-bounds offset_from: ALLOC has size 4, so pointer at offset 10 is out-of-bounds --> $DIR/ptr_offset_from_oob.rs:LL:CC | -LL | unsafe { ptr_offset_from(end_ptr, end_ptr) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds offset_from: ALLOC has size 4, so pointer at offset 10 is out-of-bounds +LL | unsafe { end_ptr.offset_from(end_ptr) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds offset_from: ALLOC has size 4, so pointer at offset 10 is out-of-bounds | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/intrinsics/ptr_offset_int_plus_int.rs b/tests/fail/intrinsics/ptr_offset_int_plus_int.rs index f51e00746e2fd..19bd265c14351 100644 --- a/tests/fail/intrinsics/ptr_offset_int_plus_int.rs +++ b/tests/fail/intrinsics/ptr_offset_int_plus_int.rs @@ -1,9 +1,8 @@ -//@error-pattern: is a dangling pointer //@compile-flags: -Zmiri-permissive-provenance fn main() { // Can't offset an integer pointer by non-zero offset. unsafe { - let _val = (1 as *mut u8).offset(1); + let _val = (1 as *mut u8).offset(1); //~ERROR: is a dangling pointer } } diff --git a/tests/fail/intrinsics/ptr_offset_int_plus_int.stderr b/tests/fail/intrinsics/ptr_offset_int_plus_int.stderr index e92b0a3216652..a96717a067071 100644 --- a/tests/fail/intrinsics/ptr_offset_int_plus_int.stderr +++ b/tests/fail/intrinsics/ptr_offset_int_plus_int.stderr @@ -1,18 +1,13 @@ error: Undefined Behavior: out-of-bounds pointer arithmetic: 0x1[noalloc] is a dangling pointer (it has no provenance) - --> RUSTLIB/core/src/ptr/mut_ptr.rs:LL:CC + --> $DIR/ptr_offset_int_plus_int.rs:LL:CC | -LL | unsafe { intrinsics::offset(self, count) as *mut T } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer arithmetic: 0x1[noalloc] is a dangling pointer (it has no provenance) +LL | let _val = (1 as *mut u8).offset(1); + | ^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer arithmetic: 0x1[noalloc] is a dangling pointer (it has no provenance) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: backtrace: - = note: inside `std::ptr::mut_ptr::::offset` at RUSTLIB/core/src/ptr/mut_ptr.rs:LL:CC -note: inside `main` at $DIR/ptr_offset_int_plus_int.rs:LL:CC - --> $DIR/ptr_offset_int_plus_int.rs:LL:CC - | -LL | let _val = (1 as *mut u8).offset(1); - | ^^^^^^^^^^^^^^^^^^^^^^^^ + = note: inside `main` at $DIR/ptr_offset_int_plus_int.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/ptr_offset_int_plus_ptr.rs b/tests/fail/intrinsics/ptr_offset_int_plus_ptr.rs index 8fc4d7fe7350b..fd3c9b44615c2 100644 --- a/tests/fail/intrinsics/ptr_offset_int_plus_ptr.rs +++ b/tests/fail/intrinsics/ptr_offset_int_plus_ptr.rs @@ -1,10 +1,9 @@ -//@error-pattern: is a dangling pointer //@compile-flags: -Zmiri-permissive-provenance fn main() { let ptr = Box::into_raw(Box::new(0u32)); // Can't start with an integer pointer and get to something usable unsafe { - let _val = (1 as *mut u8).offset(ptr as isize); + let _val = (1 as *mut u8).offset(ptr as isize); //~ERROR: is a dangling pointer } } diff --git a/tests/fail/intrinsics/ptr_offset_int_plus_ptr.stderr b/tests/fail/intrinsics/ptr_offset_int_plus_ptr.stderr index 47eac678e2efc..c1abe01dcea56 100644 --- a/tests/fail/intrinsics/ptr_offset_int_plus_ptr.stderr +++ b/tests/fail/intrinsics/ptr_offset_int_plus_ptr.stderr @@ -1,18 +1,13 @@ error: Undefined Behavior: out-of-bounds pointer arithmetic: 0x1[noalloc] is a dangling pointer (it has no provenance) - --> RUSTLIB/core/src/ptr/mut_ptr.rs:LL:CC + --> $DIR/ptr_offset_int_plus_ptr.rs:LL:CC | -LL | unsafe { intrinsics::offset(self, count) as *mut T } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer arithmetic: 0x1[noalloc] is a dangling pointer (it has no provenance) +LL | let _val = (1 as *mut u8).offset(ptr as isize); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer arithmetic: 0x1[noalloc] is a dangling pointer (it has no provenance) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: backtrace: - = note: inside `std::ptr::mut_ptr::::offset` at RUSTLIB/core/src/ptr/mut_ptr.rs:LL:CC -note: inside `main` at $DIR/ptr_offset_int_plus_ptr.rs:LL:CC - --> $DIR/ptr_offset_int_plus_ptr.rs:LL:CC - | -LL | let _val = (1 as *mut u8).offset(ptr as isize); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: inside `main` at $DIR/ptr_offset_int_plus_ptr.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/ptr_offset_overflow.rs b/tests/fail/intrinsics/ptr_offset_overflow.rs index 829cf90c855d7..c3db1e23b9bfb 100644 --- a/tests/fail/intrinsics/ptr_offset_overflow.rs +++ b/tests/fail/intrinsics/ptr_offset_overflow.rs @@ -1,6 +1,5 @@ -//@error-pattern: overflowing in-bounds pointer arithmetic fn main() { let v = [1i8, 2]; let x = &v[1] as *const i8; - let _val = unsafe { x.offset(isize::MIN) }; + let _val = unsafe { x.offset(isize::MIN) }; //~ERROR: overflowing in-bounds pointer arithmetic } diff --git a/tests/fail/intrinsics/ptr_offset_overflow.stderr b/tests/fail/intrinsics/ptr_offset_overflow.stderr index d8596acc33b0c..d5935006e43bc 100644 --- a/tests/fail/intrinsics/ptr_offset_overflow.stderr +++ b/tests/fail/intrinsics/ptr_offset_overflow.stderr @@ -1,18 +1,13 @@ error: Undefined Behavior: overflowing in-bounds pointer arithmetic - --> RUSTLIB/core/src/ptr/const_ptr.rs:LL:CC + --> $DIR/ptr_offset_overflow.rs:LL:CC | -LL | unsafe { intrinsics::offset(self, count) } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflowing in-bounds pointer arithmetic +LL | let _val = unsafe { x.offset(isize::MIN) }; + | ^^^^^^^^^^^^^^^^^^^^ overflowing in-bounds pointer arithmetic | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: backtrace: - = note: inside `std::ptr::const_ptr::::offset` at RUSTLIB/core/src/ptr/const_ptr.rs:LL:CC -note: inside `main` at $DIR/ptr_offset_overflow.rs:LL:CC - --> $DIR/ptr_offset_overflow.rs:LL:CC - | -LL | let _val = unsafe { x.offset(isize::MIN) }; - | ^^^^^^^^^^^^^^^^^^^^ + = note: inside `main` at $DIR/ptr_offset_overflow.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/ptr_offset_ptr_plus_0.rs b/tests/fail/intrinsics/ptr_offset_ptr_plus_0.rs index f8ee7d0b5092a..575e28854b1a9 100644 --- a/tests/fail/intrinsics/ptr_offset_ptr_plus_0.rs +++ b/tests/fail/intrinsics/ptr_offset_ptr_plus_0.rs @@ -1,7 +1,7 @@ -//@error-pattern: pointer at offset 32 is out-of-bounds - +#[rustfmt::skip] // fails with "left behind trailing whitespace" fn main() { let x = Box::into_raw(Box::new(0u32)); let x = x.wrapping_offset(8); // ok, this has no inbounds tag let _x = unsafe { x.offset(0) }; // UB despite offset 0, the pointer is not inbounds of the only object it can point to + //~^ERROR: pointer at offset 32 is out-of-bounds } diff --git a/tests/fail/intrinsics/ptr_offset_ptr_plus_0.stderr b/tests/fail/intrinsics/ptr_offset_ptr_plus_0.stderr index 767ed2fc3c45e..5c516d5a490f3 100644 --- a/tests/fail/intrinsics/ptr_offset_ptr_plus_0.stderr +++ b/tests/fail/intrinsics/ptr_offset_ptr_plus_0.stderr @@ -1,18 +1,13 @@ error: Undefined Behavior: out-of-bounds pointer arithmetic: ALLOC has size 4, so pointer at offset 32 is out-of-bounds - --> RUSTLIB/core/src/ptr/mut_ptr.rs:LL:CC + --> $DIR/ptr_offset_ptr_plus_0.rs:LL:CC | -LL | unsafe { intrinsics::offset(self, count) as *mut T } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer arithmetic: ALLOC has size 4, so pointer at offset 32 is out-of-bounds +LL | let _x = unsafe { x.offset(0) }; // UB despite offset 0, the pointer is not inbounds of the only object it can point to + | ^^^^^^^^^^^ out-of-bounds pointer arithmetic: ALLOC has size 4, so pointer at offset 32 is out-of-bounds | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: backtrace: - = note: inside `std::ptr::mut_ptr::::offset` at RUSTLIB/core/src/ptr/mut_ptr.rs:LL:CC -note: inside `main` at $DIR/ptr_offset_ptr_plus_0.rs:LL:CC - --> $DIR/ptr_offset_ptr_plus_0.rs:LL:CC - | -LL | let _x = unsafe { x.offset(0) }; // UB despite offset 0, the pointer is not inbounds of the only object it can point to - | ^^^^^^^^^^^ + = note: inside `main` at $DIR/ptr_offset_ptr_plus_0.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/unchecked_add1.rs b/tests/fail/intrinsics/unchecked_add1.rs index 25dbb817fae0d..13265d0fb0ee4 100644 --- a/tests/fail/intrinsics/unchecked_add1.rs +++ b/tests/fail/intrinsics/unchecked_add1.rs @@ -1,7 +1,6 @@ -#![feature(core_intrinsics)] +#![feature(unchecked_math)] + fn main() { // MAX overflow - unsafe { - std::intrinsics::unchecked_add(40000u16, 30000); //~ ERROR: overflow executing `unchecked_add` - } + let _val = unsafe { 40000u16.unchecked_add(30000) }; //~ ERROR: overflow executing `unchecked_add` } diff --git a/tests/fail/intrinsics/unchecked_add1.stderr b/tests/fail/intrinsics/unchecked_add1.stderr index 9d48590593f52..062acbb8de8cf 100644 --- a/tests/fail/intrinsics/unchecked_add1.stderr +++ b/tests/fail/intrinsics/unchecked_add1.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: overflow executing `unchecked_add` --> $DIR/unchecked_add1.rs:LL:CC | -LL | std::intrinsics::unchecked_add(40000u16, 30000); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflow executing `unchecked_add` +LL | let _val = unsafe { 40000u16.unchecked_add(30000) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflow executing `unchecked_add` | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/intrinsics/unchecked_add2.rs b/tests/fail/intrinsics/unchecked_add2.rs index a454f6478059f..229f50321d7df 100644 --- a/tests/fail/intrinsics/unchecked_add2.rs +++ b/tests/fail/intrinsics/unchecked_add2.rs @@ -1,7 +1,6 @@ -#![feature(core_intrinsics)] +#![feature(unchecked_math)] + fn main() { // MIN overflow - unsafe { - std::intrinsics::unchecked_add(-30000i16, -8000); //~ ERROR: overflow executing `unchecked_add` - } + let _val = unsafe { (-30000i16).unchecked_add(-8000) }; //~ ERROR: overflow executing `unchecked_add` } diff --git a/tests/fail/intrinsics/unchecked_add2.stderr b/tests/fail/intrinsics/unchecked_add2.stderr index 64691932e7120..09b622d6e2960 100644 --- a/tests/fail/intrinsics/unchecked_add2.stderr +++ b/tests/fail/intrinsics/unchecked_add2.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: overflow executing `unchecked_add` --> $DIR/unchecked_add2.rs:LL:CC | -LL | std::intrinsics::unchecked_add(-30000i16, -8000); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflow executing `unchecked_add` +LL | let _val = unsafe { (-30000i16).unchecked_add(-8000) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflow executing `unchecked_add` | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/intrinsics/unchecked_mul1.rs b/tests/fail/intrinsics/unchecked_mul1.rs index 514eb60602da3..810d3418dc8fe 100644 --- a/tests/fail/intrinsics/unchecked_mul1.rs +++ b/tests/fail/intrinsics/unchecked_mul1.rs @@ -1,7 +1,5 @@ -#![feature(core_intrinsics)] +#![feature(unchecked_math)] fn main() { // MAX overflow - unsafe { - std::intrinsics::unchecked_mul(300u16, 250u16); //~ ERROR: overflow executing `unchecked_mul` - } + let _val = unsafe { 300u16.unchecked_mul(250u16) }; //~ ERROR: overflow executing `unchecked_mul` } diff --git a/tests/fail/intrinsics/unchecked_mul1.stderr b/tests/fail/intrinsics/unchecked_mul1.stderr index 4d3a45d415757..e260c343c4e62 100644 --- a/tests/fail/intrinsics/unchecked_mul1.stderr +++ b/tests/fail/intrinsics/unchecked_mul1.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: overflow executing `unchecked_mul` --> $DIR/unchecked_mul1.rs:LL:CC | -LL | std::intrinsics::unchecked_mul(300u16, 250u16); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflow executing `unchecked_mul` +LL | let _val = unsafe { 300u16.unchecked_mul(250u16) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflow executing `unchecked_mul` | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/intrinsics/unchecked_mul2.rs b/tests/fail/intrinsics/unchecked_mul2.rs index e103c1e7ad179..421019542a95a 100644 --- a/tests/fail/intrinsics/unchecked_mul2.rs +++ b/tests/fail/intrinsics/unchecked_mul2.rs @@ -1,7 +1,5 @@ -#![feature(core_intrinsics)] +#![feature(unchecked_math)] fn main() { // MIN overflow - unsafe { - std::intrinsics::unchecked_mul(1_000_000_000i32, -4); //~ ERROR: overflow executing `unchecked_mul` - } + let _val = unsafe { 1_000_000_000i32.unchecked_mul(-4) }; //~ ERROR: overflow executing `unchecked_mul` } diff --git a/tests/fail/intrinsics/unchecked_mul2.stderr b/tests/fail/intrinsics/unchecked_mul2.stderr index b64ef116be45d..88b3a49b98eca 100644 --- a/tests/fail/intrinsics/unchecked_mul2.stderr +++ b/tests/fail/intrinsics/unchecked_mul2.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: overflow executing `unchecked_mul` --> $DIR/unchecked_mul2.rs:LL:CC | -LL | std::intrinsics::unchecked_mul(1_000_000_000i32, -4); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflow executing `unchecked_mul` +LL | let _val = unsafe { 1_000_000_000i32.unchecked_mul(-4) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflow executing `unchecked_mul` | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/intrinsics/unchecked_sub1.rs b/tests/fail/intrinsics/unchecked_sub1.rs index e99f88edc8635..c6e0066674413 100644 --- a/tests/fail/intrinsics/unchecked_sub1.rs +++ b/tests/fail/intrinsics/unchecked_sub1.rs @@ -1,7 +1,5 @@ -#![feature(core_intrinsics)] +#![feature(unchecked_math)] fn main() { // MIN overflow - unsafe { - std::intrinsics::unchecked_sub(14u32, 22); //~ ERROR: overflow executing `unchecked_sub` - } + let _val = unsafe { 14u32.unchecked_sub(22) }; //~ ERROR: overflow executing `unchecked_sub` } diff --git a/tests/fail/intrinsics/unchecked_sub1.stderr b/tests/fail/intrinsics/unchecked_sub1.stderr index 8454382777a02..ebd7bc10eb413 100644 --- a/tests/fail/intrinsics/unchecked_sub1.stderr +++ b/tests/fail/intrinsics/unchecked_sub1.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: overflow executing `unchecked_sub` --> $DIR/unchecked_sub1.rs:LL:CC | -LL | std::intrinsics::unchecked_sub(14u32, 22); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflow executing `unchecked_sub` +LL | let _val = unsafe { 14u32.unchecked_sub(22) }; + | ^^^^^^^^^^^^^^^^^^^^^^^ overflow executing `unchecked_sub` | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/intrinsics/unchecked_sub2.rs b/tests/fail/intrinsics/unchecked_sub2.rs index f83f6843c9ecd..65aa292e212da 100644 --- a/tests/fail/intrinsics/unchecked_sub2.rs +++ b/tests/fail/intrinsics/unchecked_sub2.rs @@ -1,7 +1,5 @@ -#![feature(core_intrinsics)] +#![feature(unchecked_math)] fn main() { // MAX overflow - unsafe { - std::intrinsics::unchecked_sub(30000i16, -7000); //~ ERROR: overflow executing `unchecked_sub` - } + let _val = unsafe { 30000i16.unchecked_sub(-7000) }; //~ ERROR: overflow executing `unchecked_sub` } diff --git a/tests/fail/intrinsics/unchecked_sub2.stderr b/tests/fail/intrinsics/unchecked_sub2.stderr index 2e6fc2e0b64f5..73d7c4d86bc02 100644 --- a/tests/fail/intrinsics/unchecked_sub2.stderr +++ b/tests/fail/intrinsics/unchecked_sub2.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: overflow executing `unchecked_sub` --> $DIR/unchecked_sub2.rs:LL:CC | -LL | std::intrinsics::unchecked_sub(30000i16, -7000); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflow executing `unchecked_sub` +LL | let _val = unsafe { 30000i16.unchecked_sub(-7000) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ overflow executing `unchecked_sub` | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/invalid_enum_tag.rs b/tests/fail/invalid_enum_tag.rs index 92cc1d1d34e48..84fa2c2973901 100644 --- a/tests/fail/invalid_enum_tag.rs +++ b/tests/fail/invalid_enum_tag.rs @@ -2,8 +2,6 @@ // Make sure we find these even with many checks disabled. //@compile-flags: -Zmiri-disable-alignment-check -Zmiri-disable-stacked-borrows -Zmiri-disable-validation -//@error-pattern: enum value has invalid tag - use std::mem; #[repr(C)] @@ -16,5 +14,5 @@ pub enum Foo { fn main() { let f = unsafe { std::mem::transmute::(42) }; - let _val = mem::discriminant(&f); + let _val = mem::discriminant(&f); //~ERROR: enum value has invalid tag } diff --git a/tests/fail/invalid_enum_tag.stderr b/tests/fail/invalid_enum_tag.stderr index 2f5a4541129c9..eff59cbfc8c27 100644 --- a/tests/fail/invalid_enum_tag.stderr +++ b/tests/fail/invalid_enum_tag.stderr @@ -1,18 +1,13 @@ error: Undefined Behavior: enum value has invalid tag: $HEX - --> RUSTLIB/core/src/mem/mod.rs:LL:CC + --> $DIR/invalid_enum_tag.rs:LL:CC | -LL | Discriminant(intrinsics::discriminant_value(v)) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ enum value has invalid tag: $HEX +LL | let _val = mem::discriminant(&f); + | ^^^^^^^^^^^^^^^^^^^^^ enum value has invalid tag: $HEX | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: backtrace: - = note: inside `std::mem::discriminant::` at RUSTLIB/core/src/mem/mod.rs:LL:CC -note: inside `main` at $DIR/invalid_enum_tag.rs:LL:CC - --> $DIR/invalid_enum_tag.rs:LL:CC - | -LL | let _val = mem::discriminant(&f); - | ^^^^^^^^^^^^^^^^^^^^^ + = note: inside `main` at $DIR/invalid_enum_tag.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/provenance/ptr_invalid_offset.rs b/tests/fail/provenance/ptr_invalid_offset.rs index a3510d8e89290..91ba18f768055 100644 --- a/tests/fail/provenance/ptr_invalid_offset.rs +++ b/tests/fail/provenance/ptr_invalid_offset.rs @@ -1,5 +1,4 @@ //@compile-flags: -Zmiri-strict-provenance -//@error-pattern: is a dangling pointer #![feature(strict_provenance)] fn main() { @@ -7,5 +6,5 @@ fn main() { let ptr = &x as *const _ as *const u8; let roundtrip = std::ptr::invalid::(ptr as usize); // Not even offsetting this is allowed. - let _ = unsafe { roundtrip.offset(1) }; + let _ = unsafe { roundtrip.offset(1) }; //~ERROR: is a dangling pointer } diff --git a/tests/fail/provenance/ptr_invalid_offset.stderr b/tests/fail/provenance/ptr_invalid_offset.stderr index df73689deae8d..813a6515b7714 100644 --- a/tests/fail/provenance/ptr_invalid_offset.stderr +++ b/tests/fail/provenance/ptr_invalid_offset.stderr @@ -1,18 +1,13 @@ error: Undefined Behavior: out-of-bounds pointer arithmetic: $HEX[noalloc] is a dangling pointer (it has no provenance) - --> RUSTLIB/core/src/ptr/const_ptr.rs:LL:CC + --> $DIR/ptr_invalid_offset.rs:LL:CC | -LL | unsafe { intrinsics::offset(self, count) } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer arithmetic: $HEX[noalloc] is a dangling pointer (it has no provenance) +LL | let _ = unsafe { roundtrip.offset(1) }; + | ^^^^^^^^^^^^^^^^^^^ out-of-bounds pointer arithmetic: $HEX[noalloc] is a dangling pointer (it has no provenance) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: backtrace: - = note: inside `std::ptr::const_ptr::::offset` at RUSTLIB/core/src/ptr/const_ptr.rs:LL:CC -note: inside `main` at $DIR/ptr_invalid_offset.rs:LL:CC - --> $DIR/ptr_invalid_offset.rs:LL:CC - | -LL | let _ = unsafe { roundtrip.offset(1) }; - | ^^^^^^^^^^^^^^^^^^^ + = note: inside `main` at $DIR/ptr_invalid_offset.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/should-pass/cpp20_rwc_syncs.rs b/tests/fail/should-pass/cpp20_rwc_syncs.rs index dbac6469fbab8..6a7622671b59d 100644 --- a/tests/fail/should-pass/cpp20_rwc_syncs.rs +++ b/tests/fail/should-pass/cpp20_rwc_syncs.rs @@ -1,6 +1,5 @@ //@ignore-target-windows: Concurrency on Windows is not supported yet. //@compile-flags: -Zmiri-ignore-leaks -//@error-pattern: unreachable // https://plv.mpi-sws.org/scfix/paper.pdf // 2.2 Second Problem: SC Fences are Too Weak @@ -77,7 +76,7 @@ fn test_cpp20_rwc_syncs() { if (b, c) == (0, 0) { // This *should* be unreachable, but Miri will reach it. unsafe { - std::hint::unreachable_unchecked(); + std::hint::unreachable_unchecked(); //~ERROR: unreachable } } } diff --git a/tests/fail/should-pass/cpp20_rwc_syncs.stderr b/tests/fail/should-pass/cpp20_rwc_syncs.stderr index 0ab02687e2aef..17573a33b3d70 100644 --- a/tests/fail/should-pass/cpp20_rwc_syncs.stderr +++ b/tests/fail/should-pass/cpp20_rwc_syncs.stderr @@ -1,18 +1,13 @@ error: Undefined Behavior: entering unreachable code - --> RUSTLIB/core/src/hint.rs:LL:CC + --> $DIR/cpp20_rwc_syncs.rs:LL:CC | -LL | unsafe { intrinsics::unreachable() } - | ^^^^^^^^^^^^^^^^^^^^^^^^^ entering unreachable code +LL | std::hint::unreachable_unchecked(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ entering unreachable code | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: backtrace: - = note: inside `std::hint::unreachable_unchecked` at RUSTLIB/core/src/hint.rs:LL:CC -note: inside `test_cpp20_rwc_syncs` at $DIR/cpp20_rwc_syncs.rs:LL:CC - --> $DIR/cpp20_rwc_syncs.rs:LL:CC - | -LL | std::hint::unreachable_unchecked(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: inside `test_cpp20_rwc_syncs` at $DIR/cpp20_rwc_syncs.rs:LL:CC note: inside `main` at $DIR/cpp20_rwc_syncs.rs:LL:CC --> $DIR/cpp20_rwc_syncs.rs:LL:CC | diff --git a/tests/fail/unreachable.rs b/tests/fail/unreachable.rs index ef2bb42c65cc6..3389d5b9ddeaf 100644 --- a/tests/fail/unreachable.rs +++ b/tests/fail/unreachable.rs @@ -1,4 +1,3 @@ -//@error-pattern: entering unreachable code fn main() { - unsafe { std::hint::unreachable_unchecked() } + unsafe { std::hint::unreachable_unchecked() } //~ERROR: entering unreachable code } diff --git a/tests/fail/unreachable.stderr b/tests/fail/unreachable.stderr index e9eb3649dea4a..b487b4374756b 100644 --- a/tests/fail/unreachable.stderr +++ b/tests/fail/unreachable.stderr @@ -1,18 +1,13 @@ error: Undefined Behavior: entering unreachable code - --> RUSTLIB/core/src/hint.rs:LL:CC + --> $DIR/unreachable.rs:LL:CC | -LL | unsafe { intrinsics::unreachable() } - | ^^^^^^^^^^^^^^^^^^^^^^^^^ entering unreachable code +LL | unsafe { std::hint::unreachable_unchecked() } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ entering unreachable code | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: backtrace: - = note: inside `std::hint::unreachable_unchecked` at RUSTLIB/core/src/hint.rs:LL:CC -note: inside `main` at $DIR/unreachable.rs:LL:CC - --> $DIR/unreachable.rs:LL:CC - | -LL | unsafe { std::hint::unreachable_unchecked() } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: inside `main` at $DIR/unreachable.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/weak_memory/racing_mixed_size.rs b/tests/fail/weak_memory/racing_mixed_size.rs index a7c5a41917623..95a10510713cc 100644 --- a/tests/fail/weak_memory/racing_mixed_size.rs +++ b/tests/fail/weak_memory/racing_mixed_size.rs @@ -4,6 +4,7 @@ #![feature(core_intrinsics)] +use std::ptr; use std::sync::atomic::AtomicU32; use std::sync::atomic::Ordering::*; use std::thread::spawn; @@ -30,7 +31,7 @@ pub fn main() { let x_ptr = x as *const AtomicU32 as *const u32; let x_split = split_u32_ptr(x_ptr); unsafe { - let hi = &(*x_split)[0] as *const u16; + let hi = ptr::addr_of!((*x_split)[0]); std::intrinsics::atomic_load_relaxed(hi); //~ ERROR: imperfectly overlapping } }); From 39d8c4de357c2846c586d7d3794163da8a63578a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 25 Jul 2022 10:35:07 -0400 Subject: [PATCH 3586/3747] rustup --- rust-version | 2 +- .../fail/intrinsics/ptr_offset_from_unsigned_neg.rs | 5 +++-- .../intrinsics/ptr_offset_from_unsigned_neg.stderr | 13 ++++--------- 3 files changed, 8 insertions(+), 12 deletions(-) diff --git a/rust-version b/rust-version index b70ab6fdd46e5..b948bc8b4e6af 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -7fe022f5aa32bbbb33c3a58755729d6667a461a9 +2fdbf075cf502431ca9fee6616331b32e34f25de diff --git a/tests/fail/intrinsics/ptr_offset_from_unsigned_neg.rs b/tests/fail/intrinsics/ptr_offset_from_unsigned_neg.rs index d6413faf74bfa..67aa60e785b10 100644 --- a/tests/fail/intrinsics/ptr_offset_from_unsigned_neg.rs +++ b/tests/fail/intrinsics/ptr_offset_from_unsigned_neg.rs @@ -1,9 +1,10 @@ -//@error-pattern: first pointer has smaller offset than second: 0 < 4 +// Preparing for a rustc behavior change that'll happen soon: (FIXME remove this after the next submodule bump succeeded) +//@normalize-stderr-test: "`(ptr_offset_from_unsigned)`" -> "$1" #![feature(ptr_sub_ptr)] fn main() { let arr = [0u8; 8]; let ptr1 = arr.as_ptr(); let ptr2 = ptr1.wrapping_add(4); - let _val = unsafe { ptr1.sub_ptr(ptr2) }; + let _val = unsafe { ptr1.sub_ptr(ptr2) }; //~ERROR: first pointer has smaller offset than second: 0 < 4 } diff --git a/tests/fail/intrinsics/ptr_offset_from_unsigned_neg.stderr b/tests/fail/intrinsics/ptr_offset_from_unsigned_neg.stderr index bb68f9f5c18c5..93a05fe8d9e98 100644 --- a/tests/fail/intrinsics/ptr_offset_from_unsigned_neg.stderr +++ b/tests/fail/intrinsics/ptr_offset_from_unsigned_neg.stderr @@ -1,18 +1,13 @@ error: Undefined Behavior: ptr_offset_from_unsigned called when first pointer has smaller offset than second: 0 < 4 - --> RUSTLIB/core/src/ptr/const_ptr.rs:LL:CC + --> $DIR/ptr_offset_from_unsigned_neg.rs:LL:CC | -LL | unsafe { intrinsics::ptr_offset_from_unsigned(self, origin) } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ptr_offset_from_unsigned called when first pointer has smaller offset than second: 0 < 4 +LL | let _val = unsafe { ptr1.sub_ptr(ptr2) }; + | ^^^^^^^^^^^^^^^^^^ ptr_offset_from_unsigned called when first pointer has smaller offset than second: 0 < 4 | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: backtrace: - = note: inside `std::ptr::const_ptr::::sub_ptr` at RUSTLIB/core/src/ptr/const_ptr.rs:LL:CC -note: inside `main` at $DIR/ptr_offset_from_unsigned_neg.rs:LL:CC - --> $DIR/ptr_offset_from_unsigned_neg.rs:LL:CC - | -LL | let _val = unsafe { ptr1.sub_ptr(ptr2) }; - | ^^^^^^^^^^^^^^^^^^ + = note: inside `main` at $DIR/ptr_offset_from_unsigned_neg.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace From cd6b723bb66c7cc32a1436db43079dc4236eaa90 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Mon, 25 Jul 2022 17:55:45 +0000 Subject: [PATCH 3587/3747] Add default impls for `FileDescriptor` methods --- src/shims/unix/fs.rs | 155 ++++++++---------------------- tests/fail/fs/close_stdout.rs | 2 +- tests/fail/fs/close_stdout.stderr | 4 +- 3 files changed, 41 insertions(+), 120 deletions(-) diff --git a/src/shims/unix/fs.rs b/src/shims/unix/fs.rs index dc31237a31997..c9f35c0489171 100644 --- a/src/shims/unix/fs.rs +++ b/src/shims/unix/fs.rs @@ -24,38 +24,56 @@ struct FileHandle { } trait FileDescriptor: std::fmt::Debug { - fn as_file_handle<'tcx>(&self) -> InterpResult<'tcx, &FileHandle>; + fn name(&self) -> &'static str; + + fn as_file_handle<'tcx>(&self) -> InterpResult<'tcx, &FileHandle> { + throw_unsup_format!("{} cannot be used as FileHandle", self.name()); + } fn read<'tcx>( &mut self, - communicate_allowed: bool, - bytes: &mut [u8], - ) -> InterpResult<'tcx, io::Result>; + _communicate_allowed: bool, + _bytes: &mut [u8], + ) -> InterpResult<'tcx, io::Result> { + throw_unsup_format!("cannot read from {}", self.name()); + } fn write<'tcx>( &self, - communicate_allowed: bool, - bytes: &[u8], - ) -> InterpResult<'tcx, io::Result>; + _communicate_allowed: bool, + _bytes: &[u8], + ) -> InterpResult<'tcx, io::Result> { + throw_unsup_format!("cannot write to {}", self.name()); + } fn seek<'tcx>( &mut self, - communicate_allowed: bool, - offset: SeekFrom, - ) -> InterpResult<'tcx, io::Result>; + _communicate_allowed: bool, + _offset: SeekFrom, + ) -> InterpResult<'tcx, io::Result> { + throw_unsup_format!("cannot seek on {}", self.name()); + } fn close<'tcx>( self: Box, _communicate_allowed: bool, - ) -> InterpResult<'tcx, io::Result>; + ) -> InterpResult<'tcx, io::Result> { + throw_unsup_format!("cannot close {}", self.name()); + } fn dup(&mut self) -> io::Result>; #[cfg(unix)] - fn as_unix_host_fd(&self) -> Option; + fn as_unix_host_fd(&self) -> Option { + None + } } impl FileDescriptor for FileHandle { + fn name(&self) -> &'static str { + "FILE" + } + fn as_file_handle<'tcx>(&self) -> InterpResult<'tcx, &FileHandle> { Ok(self) } @@ -126,8 +144,8 @@ impl FileDescriptor for FileHandle { } impl FileDescriptor for io::Stdin { - fn as_file_handle<'tcx>(&self) -> InterpResult<'tcx, &FileHandle> { - throw_unsup_format!("stdin cannot be used as FileHandle"); + fn name(&self) -> &'static str { + "stdin" } fn read<'tcx>( @@ -142,29 +160,6 @@ impl FileDescriptor for io::Stdin { Ok(Read::read(self, bytes)) } - fn write<'tcx>( - &self, - _communicate_allowed: bool, - _bytes: &[u8], - ) -> InterpResult<'tcx, io::Result> { - throw_unsup_format!("cannot write to stdin"); - } - - fn seek<'tcx>( - &mut self, - _communicate_allowed: bool, - _offset: SeekFrom, - ) -> InterpResult<'tcx, io::Result> { - throw_unsup_format!("cannot seek on stdin"); - } - - fn close<'tcx>( - self: Box, - _communicate_allowed: bool, - ) -> InterpResult<'tcx, io::Result> { - throw_unsup_format!("stdin cannot be closed"); - } - fn dup(&mut self) -> io::Result> { Ok(Box::new(io::stdin())) } @@ -176,16 +171,8 @@ impl FileDescriptor for io::Stdin { } impl FileDescriptor for io::Stdout { - fn as_file_handle<'tcx>(&self) -> InterpResult<'tcx, &FileHandle> { - throw_unsup_format!("stdout cannot be used as FileHandle"); - } - - fn read<'tcx>( - &mut self, - _communicate_allowed: bool, - _bytes: &mut [u8], - ) -> InterpResult<'tcx, io::Result> { - throw_unsup_format!("cannot read from stdout"); + fn name(&self) -> &'static str { + "stdout" } fn write<'tcx>( @@ -205,21 +192,6 @@ impl FileDescriptor for io::Stdout { Ok(result) } - fn seek<'tcx>( - &mut self, - _communicate_allowed: bool, - _offset: SeekFrom, - ) -> InterpResult<'tcx, io::Result> { - throw_unsup_format!("cannot seek on stdout"); - } - - fn close<'tcx>( - self: Box, - _communicate_allowed: bool, - ) -> InterpResult<'tcx, io::Result> { - throw_unsup_format!("stdout cannot be closed"); - } - fn dup(&mut self) -> io::Result> { Ok(Box::new(io::stdout())) } @@ -231,16 +203,8 @@ impl FileDescriptor for io::Stdout { } impl FileDescriptor for io::Stderr { - fn as_file_handle<'tcx>(&self) -> InterpResult<'tcx, &FileHandle> { - throw_unsup_format!("stderr cannot be used as FileHandle"); - } - - fn read<'tcx>( - &mut self, - _communicate_allowed: bool, - _bytes: &mut [u8], - ) -> InterpResult<'tcx, io::Result> { - throw_unsup_format!("cannot read from stderr"); + fn name(&self) -> &'static str { + "stderr" } fn write<'tcx>( @@ -253,21 +217,6 @@ impl FileDescriptor for io::Stderr { Ok(Write::write(&mut { self }, bytes)) } - fn seek<'tcx>( - &mut self, - _communicate_allowed: bool, - _offset: SeekFrom, - ) -> InterpResult<'tcx, io::Result> { - throw_unsup_format!("cannot seek on stderr"); - } - - fn close<'tcx>( - self: Box, - _communicate_allowed: bool, - ) -> InterpResult<'tcx, io::Result> { - throw_unsup_format!("stderr cannot be closed"); - } - fn dup(&mut self) -> io::Result> { Ok(Box::new(io::stderr())) } @@ -282,16 +231,8 @@ impl FileDescriptor for io::Stderr { struct DummyOutput; impl FileDescriptor for DummyOutput { - fn as_file_handle<'tcx>(&self) -> InterpResult<'tcx, &FileHandle> { - throw_unsup_format!("stderr and stdout cannot be used as FileHandle"); - } - - fn read<'tcx>( - &mut self, - _communicate_allowed: bool, - _bytes: &mut [u8], - ) -> InterpResult<'tcx, io::Result> { - throw_unsup_format!("cannot read from stderr or stdout"); + fn name(&self) -> &'static str { + "stderr and stdout" } fn write<'tcx>( @@ -303,29 +244,9 @@ impl FileDescriptor for DummyOutput { Ok(Ok(bytes.len())) } - fn seek<'tcx>( - &mut self, - _communicate_allowed: bool, - _offset: SeekFrom, - ) -> InterpResult<'tcx, io::Result> { - throw_unsup_format!("cannot seek on stderr or stdout"); - } - - fn close<'tcx>( - self: Box, - _communicate_allowed: bool, - ) -> InterpResult<'tcx, io::Result> { - throw_unsup_format!("stderr and stdout cannot be closed"); - } - fn dup<'tcx>(&mut self) -> io::Result> { Ok(Box::new(DummyOutput)) } - - #[cfg(unix)] - fn as_unix_host_fd(&self) -> Option { - None - } } #[derive(Debug)] diff --git a/tests/fail/fs/close_stdout.rs b/tests/fail/fs/close_stdout.rs index 86a6239f5f364..e4eab5fd69640 100644 --- a/tests/fail/fs/close_stdout.rs +++ b/tests/fail/fs/close_stdout.rs @@ -7,6 +7,6 @@ fn main() { unsafe { - libc::close(1); //~ ERROR: stdout cannot be closed + libc::close(1); //~ ERROR: cannot close stdout } } diff --git a/tests/fail/fs/close_stdout.stderr b/tests/fail/fs/close_stdout.stderr index 08f744a5c4588..eb2c54e05f1fa 100644 --- a/tests/fail/fs/close_stdout.stderr +++ b/tests/fail/fs/close_stdout.stderr @@ -1,8 +1,8 @@ -error: unsupported operation: stdout cannot be closed +error: unsupported operation: cannot close stdout --> $DIR/close_stdout.rs:LL:CC | LL | libc::close(1); - | ^^^^^^^^^^^^^^ stdout cannot be closed + | ^^^^^^^^^^^^^^ cannot close stdout | = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support = note: backtrace: From 5875c0d220c594b38b962a54386cc462060031f5 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 25 Jul 2022 22:40:56 -0400 Subject: [PATCH 3588/3747] add test for dyn call issue --- rust-version | 2 +- tests/fail/issue-miri-2432.rs | 19 +++++++++++++++++++ tests/fail/issue-miri-2432.stderr | 15 +++++++++++++++ 3 files changed, 35 insertions(+), 1 deletion(-) create mode 100644 tests/fail/issue-miri-2432.rs create mode 100644 tests/fail/issue-miri-2432.stderr diff --git a/rust-version b/rust-version index b948bc8b4e6af..927ced2a2d13a 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -2fdbf075cf502431ca9fee6616331b32e34f25de +a86705942c4cfaaee60f2e7308ca2bca703a710f diff --git a/tests/fail/issue-miri-2432.rs b/tests/fail/issue-miri-2432.rs new file mode 100644 index 0000000000000..f822479c43685 --- /dev/null +++ b/tests/fail/issue-miri-2432.rs @@ -0,0 +1,19 @@ +#![allow(where_clauses_object_safety)] + +trait Trait {} + +trait X { + fn foo(&self) + where + Self: Trait; +} + +impl X for () { + fn foo(&self) {} +} + +impl Trait for dyn X {} + +pub fn main() { + ::foo(&()); //~ERROR: trying to call something that is not a method +} diff --git a/tests/fail/issue-miri-2432.stderr b/tests/fail/issue-miri-2432.stderr new file mode 100644 index 0000000000000..a5c9300fb07ca --- /dev/null +++ b/tests/fail/issue-miri-2432.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: `dyn` call trying to call something that is not a method + --> $DIR/issue-miri-2432.rs:LL:CC + | +LL | ::foo(&()); + | ^^^^^^^^^^^^^^^^^^^^^^ `dyn` call trying to call something that is not a method + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: backtrace: + = note: inside `main` at $DIR/issue-miri-2432.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + From dd3b8e8b1bfe1bad169cb0050d60b3c4bb9c2a7a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 26 Jul 2022 20:38:25 -0400 Subject: [PATCH 3589/3747] rustup --- rust-version | 2 +- tests/fail/intrinsics/ptr_offset_from_unsigned_neg.rs | 2 -- tests/fail/intrinsics/ptr_offset_from_unsigned_neg.stderr | 4 ++-- 3 files changed, 3 insertions(+), 5 deletions(-) diff --git a/rust-version b/rust-version index 927ced2a2d13a..5f09f4f35b137 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -a86705942c4cfaaee60f2e7308ca2bca703a710f +c11207ec89b856164bba03b8ecfe07b0b234ed21 diff --git a/tests/fail/intrinsics/ptr_offset_from_unsigned_neg.rs b/tests/fail/intrinsics/ptr_offset_from_unsigned_neg.rs index 67aa60e785b10..06d13d9bdbaf3 100644 --- a/tests/fail/intrinsics/ptr_offset_from_unsigned_neg.rs +++ b/tests/fail/intrinsics/ptr_offset_from_unsigned_neg.rs @@ -1,5 +1,3 @@ -// Preparing for a rustc behavior change that'll happen soon: (FIXME remove this after the next submodule bump succeeded) -//@normalize-stderr-test: "`(ptr_offset_from_unsigned)`" -> "$1" #![feature(ptr_sub_ptr)] fn main() { diff --git a/tests/fail/intrinsics/ptr_offset_from_unsigned_neg.stderr b/tests/fail/intrinsics/ptr_offset_from_unsigned_neg.stderr index 93a05fe8d9e98..419b7497a2f9c 100644 --- a/tests/fail/intrinsics/ptr_offset_from_unsigned_neg.stderr +++ b/tests/fail/intrinsics/ptr_offset_from_unsigned_neg.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: ptr_offset_from_unsigned called when first pointer has smaller offset than second: 0 < 4 +error: Undefined Behavior: `ptr_offset_from_unsigned` called when first pointer has smaller offset than second: 0 < 4 --> $DIR/ptr_offset_from_unsigned_neg.rs:LL:CC | LL | let _val = unsafe { ptr1.sub_ptr(ptr2) }; - | ^^^^^^^^^^^^^^^^^^ ptr_offset_from_unsigned called when first pointer has smaller offset than second: 0 < 4 + | ^^^^^^^^^^^^^^^^^^ `ptr_offset_from_unsigned` called when first pointer has smaller offset than second: 0 < 4 | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information From 622613f957e07ffe1398fa17bc84f185e62df27f Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Sat, 23 Jul 2022 13:59:08 -0400 Subject: [PATCH 3590/3747] Use real exec on cfg(unix) targets When cargo-miri is executed as a cargo test runner or rustdoc runtool, external tools expect what they launch as the runner/runtool to be the process actually running the test. But in the implementation, we launch the Miri interpreter as a subprocess using std::process::Command. This tends to confuse other tools (like nextest) and users (like the author). What we really want is to call POSIX exec so that the cargo-miri process becomes the interpreter. So this implements just that; we call execve via a cfg(unix) extension trait. Windows has no such mechanism, but it also doesn't have POSIX signals, which is the primary tripping hazard this change fixes. --- cargo-miri/bin.rs | 84 ++++++++++++++++++++++++++++++++++------------- 1 file changed, 61 insertions(+), 23 deletions(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index 216584ac9b022..ce7328e2e6c56 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -51,7 +51,7 @@ enum MiriCommand { } /// The information to run a crate with the given environment. -#[derive(Serialize, Deserialize)] +#[derive(Clone, Serialize, Deserialize)] struct CrateRunEnv { /// The command-line arguments. args: Vec, @@ -249,27 +249,56 @@ fn xargo_check() -> Command { Command::new(env::var_os("XARGO_CHECK").unwrap_or_else(|| OsString::from("xargo-check"))) } -/// Execute the command. If it fails, fail this process with the same exit code. -/// Otherwise, continue. -fn exec(mut cmd: Command) { - let exit_status = cmd.status().expect("failed to run command"); - if exit_status.success().not() { +/// Execute the `Command`, where possible by replacing the current process with a new process +/// described by the `Command`. Then exit this process with the exit code of the new process. +fn exec(mut cmd: Command) -> ! { + // On non-Unix imitate POSIX exec as closely as we can + #[cfg(not(unix))] + { + let exit_status = cmd.status().expect("failed to run command"); std::process::exit(exit_status.code().unwrap_or(-1)) } + // On Unix targets, actually exec. + // If exec returns, process setup has failed. This is the same error condition as the expect in + // the non-Unix case. + #[cfg(unix)] + { + use std::os::unix::process::CommandExt; + let error = cmd.exec(); + Err(error).expect("failed to run command") + } } -/// Execute the command and pipe `input` into its stdin. -/// If it fails, fail this process with the same exit code. -/// Otherwise, continue. -fn exec_with_pipe(mut cmd: Command, input: &[u8]) { - cmd.stdin(process::Stdio::piped()); - let mut child = cmd.spawn().expect("failed to spawn process"); +/// Execute the `Command`, where possible by replacing the current process with a new process +/// described by the `Command`. Then exit this process with the exit code of the new process. +/// `input` is also piped to the new process's stdin, on cfg(unix) platforms by writing its +/// contents to `path` first, then setting stdin to that file. +fn exec_with_pipe

(mut cmd: Command, input: &[u8], path: P) -> ! +where + P: AsRef, +{ + #[cfg(unix)] { - let stdin = child.stdin.as_mut().expect("failed to open stdin"); - stdin.write_all(input).expect("failed to write out test source"); + // Write the bytes we want to send to stdin out to a file + std::fs::write(&path, input).unwrap(); + // Open the file for reading, and set our new stdin to it + let stdin = File::open(&path).unwrap(); + cmd.stdin(stdin); + // Unlink the file so that it is fully cleaned up as soon as the new process exits + std::fs::remove_file(&path).unwrap(); + // Finally, we can hand off control. + exec(cmd) } - let exit_status = child.wait().expect("failed to run command"); - if exit_status.success().not() { + #[cfg(not(unix))] + { + drop(path); // We don't need the path, we can pipe the bytes directly + cmd.stdin(process::Stdio::piped()); + let mut child = cmd.spawn().expect("failed to spawn process"); + { + let stdin = child.stdin.as_mut().expect("failed to open stdin"); + stdin.write_all(input).expect("failed to write out test source"); + } + let exit_status = child.wait().expect("failed to run command"); std::process::exit(exit_status.code().unwrap_or(-1)) } } @@ -872,6 +901,8 @@ fn phase_rustc(mut args: impl Iterator, phase: RustcPhase) { // and environment variables; this is used when cargo calls us again in the CARGO_TARGET_RUNNER phase. let env = CrateRunEnv::collect(args, inside_rustdoc); + store_json(CrateRunInfo::RunWith(env.clone())); + // Rustdoc expects us to exit with an error code if the test is marked as `compile_fail`, // just creating the JSON file is not enough: we need to detect syntax errors, // so we need to run Miri with `MIRI_BE_RUSTC` for a check-only build. @@ -888,7 +919,15 @@ fn phase_rustc(mut args: impl Iterator, phase: RustcPhase) { cmd.arg("--emit=metadata"); } - cmd.args(&env.args); + // Alter the `-o` parameter so that it does not overwrite the JSON file we stored above. + let mut args = env.args.clone(); + for i in 0..args.len() { + if args[i] == "-o" { + args[i + 1].push_str(".miri"); + } + } + + cmd.args(&args); cmd.env("MIRI_BE_RUSTC", "target"); if verbose > 0 { @@ -899,11 +938,9 @@ fn phase_rustc(mut args: impl Iterator, phase: RustcPhase) { eprintln!("[cargo-miri rustc inside rustdoc] going to run:\n{:?}", cmd); } - exec_with_pipe(cmd, &env.stdin); + exec_with_pipe(cmd, &env.stdin, format!("{}.stdin", out_filename("", "").display())); } - store_json(CrateRunInfo::RunWith(env)); - return; } @@ -983,8 +1020,6 @@ fn phase_rustc(mut args: impl Iterator, phase: RustcPhase) { "[cargo-miri rustc] target_crate={target_crate} runnable_crate={runnable_crate} print={print}" ); } - debug_cmd("[cargo-miri rustc]", verbose, &cmd); - exec(cmd); // Create a stub .rlib file if "link" was requested by cargo. // This is necessary to prevent cargo from doing rebuilds all the time. @@ -999,6 +1034,9 @@ fn phase_rustc(mut args: impl Iterator, phase: RustcPhase) { File::create(out_filename("", ".dll")).expect("failed to create fake .dll file"); File::create(out_filename("", ".lib")).expect("failed to create fake .lib file"); } + + debug_cmd("[cargo-miri rustc]", verbose, &cmd); + exec(cmd); } #[derive(Debug, Copy, Clone, PartialEq)] @@ -1100,7 +1138,7 @@ fn phase_runner(mut binary_args: impl Iterator, phase: RunnerPhas // Run it. debug_cmd("[cargo-miri runner]", verbose, &cmd); match phase { - RunnerPhase::Rustdoc => exec_with_pipe(cmd, &info.stdin), + RunnerPhase::Rustdoc => exec_with_pipe(cmd, &info.stdin, format!("{}.stdin", binary)), RunnerPhase::Cargo => exec(cmd), } } From 38e7bcf7f18d5617f43c7b84f050f7a87f3c5308 Mon Sep 17 00:00:00 2001 From: Aleksei Trifonov Date: Fri, 29 Jul 2022 05:25:59 +0300 Subject: [PATCH 3591/3747] Use cargo_metadata in cargo-miri --- cargo-miri/Cargo.lock | 75 +++++++++++++++++++++++++++++++------------ cargo-miri/Cargo.toml | 1 + cargo-miri/bin.rs | 45 ++++++++++---------------- 3 files changed, 73 insertions(+), 48 deletions(-) diff --git a/cargo-miri/Cargo.lock b/cargo-miri/Cargo.lock index abb60080b786e..95c2bda505c5b 100644 --- a/cargo-miri/Cargo.lock +++ b/cargo-miri/Cargo.lock @@ -20,10 +20,20 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +[[package]] +name = "camino" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "869119e97797867fd90f5e22af7d0bd274bd4635ebb9eb68c04f3f513ae6c412" +dependencies = [ + "serde", +] + [[package]] name = "cargo-miri" version = "0.1.0" dependencies = [ + "cargo_metadata", "directories", "rustc-workspace-hack", "rustc_version", @@ -32,6 +42,28 @@ dependencies = [ "vergen", ] +[[package]] +name = "cargo-platform" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cbdb825da8a5df079a43676dbe042702f1707b1109f713a01420fbb4cc71fa27" +dependencies = [ + "serde", +] + +[[package]] +name = "cargo_metadata" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3abb7553d5b9b8421c6de7cb02606ff15e0c6eea7d8eadd75ef013fd636bec36" +dependencies = [ + "camino", + "cargo-platform", + "semver", + "serde", + "serde_json", +] + [[package]] name = "cc" version = "1.0.72" @@ -274,11 +306,11 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.33" +version = "1.0.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb37d2df5df740e582f28f8560cf425f52bb267d872fe58358eadb554909f07a" +checksum = "c278e965f1d8cf32d6e0e96de3d3e79712178ae67986d9cf9151f51e95aac89b" dependencies = [ - "unicode-xid", + "unicode-ident", ] [[package]] @@ -338,24 +370,27 @@ checksum = "73b4b750c782965c211b42f022f59af1fbceabdd026623714f104152f1ec149f" [[package]] name = "semver" -version = "1.0.4" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "568a8e6258aa33c13358f81fd834adb854c6f7c9468520910a9b1e8fac068012" +checksum = "a2333e6df6d6598f2b1974829f853c2b4c5f4a6e503c10af918081aa6f8564e1" +dependencies = [ + "serde", +] [[package]] name = "serde" -version = "1.0.131" +version = "1.0.140" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4ad69dfbd3e45369132cc64e6748c2d65cdfb001a2b1c232d128b4ad60561c1" +checksum = "fc855a42c7967b7c369eb5860f7164ef1f6f81c20c7cc1141f2a604e18723b03" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.131" +version = "1.0.140" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b710a83c4e0dff6a3d511946b95274ad9ca9e5d3ae497b63fda866ac955358d2" +checksum = "6f2122636b9fe3b81f1cb25099fcf2d3f542cdb1d45940d56c713158884a05da" dependencies = [ "proc-macro2", "quote", @@ -364,9 +399,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.73" +version = "1.0.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcbd0344bc6533bc7ec56df11d42fb70f1b912351c0825ccb7211b59d8af7cf5" +checksum = "82c2c1fdcd807d1098552c5b9a36e425e42e9fbd7c6a37a8425f390f781f7fa7" dependencies = [ "itoa", "ryu", @@ -375,13 +410,13 @@ dependencies = [ [[package]] name = "syn" -version = "1.0.82" +version = "1.0.98" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8daf5dd0bb60cbd4137b1b587d2fc0ae729bc07cf01cd70b36a1ed5ade3b9d59" +checksum = "c50aef8a904de4c23c788f104b7dddc7d6f79c647c7c8ce4cc8f73eb0ca773dd" dependencies = [ "proc-macro2", "quote", - "unicode-xid", + "unicode-ident", ] [[package]] @@ -435,6 +470,12 @@ version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1a01404663e3db436ed2746d9fefef640d868edae3cceb81c3b8d5732fda678f" +[[package]] +name = "unicode-ident" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15c61ba63f9235225a22310255a29b806b907c9b8c964bcbd0a2c70f3f2deea7" + [[package]] name = "unicode-normalization" version = "0.1.19" @@ -444,12 +485,6 @@ dependencies = [ "tinyvec", ] -[[package]] -name = "unicode-xid" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" - [[package]] name = "url" version = "2.2.2" diff --git a/cargo-miri/Cargo.toml b/cargo-miri/Cargo.toml index eb926525305c3..8bcd77c70b013 100644 --- a/cargo-miri/Cargo.toml +++ b/cargo-miri/Cargo.toml @@ -17,6 +17,7 @@ doctest = false # and no doc tests directories = "3" rustc_version = "0.4" serde_json = "1.0.40" +cargo_metadata = "0.15.0" # A noop dependency that changes in the Rust repository, it's a bit of a hack. # See the `src/tools/rustc-workspace-hack/README.md` file in `rust-lang/rust` diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index faa116ff7e384..d11d3f15b8855 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -16,6 +16,7 @@ use std::process::{self, Command}; use rustc_version::VersionMeta; use serde::{Deserialize, Serialize}; +use cargo_metadata::{MetadataCommand, Metadata}; use version::*; @@ -582,41 +583,29 @@ path = "lib.rs" } } -#[derive(Deserialize)] -struct Metadata { - target_directory: PathBuf, - workspace_members: Vec, -} - fn get_cargo_metadata() -> Metadata { - let mut cmd = cargo(); - // `-Zunstable-options` is required by `--config`. - cmd.args(["metadata", "--no-deps", "--format-version=1", "-Zunstable-options"]); // The `build.target-dir` config can be passed by `--config` flags, so forward them to // `cargo metadata`. + let mut additional_options = Vec::new(); + // `-Zunstable-options` is required by `--config`. + additional_options.push("-Zunstable-options".to_string()); + let config_flag = "--config"; for arg in ArgSplitFlagValue::new( env::args().skip(3), // skip the program name, "miri" and "run" / "test" config_flag, - ) - // Only look at `Ok` - .flatten() - { - cmd.arg(config_flag).arg(arg); - } - let mut child = cmd - .stdin(process::Stdio::null()) - .stdout(process::Stdio::piped()) - .spawn() - .expect("failed ro run `cargo metadata`"); - // Check this `Result` after `status.success()` is checked, so we don't print the error - // to stderr if `cargo metadata` is also printing to stderr. - let metadata: Result = serde_json::from_reader(child.stdout.take().unwrap()); - let status = child.wait().expect("failed to wait for `cargo metadata` to exit"); - if !status.success() { - std::process::exit(status.code().unwrap_or(-1)); + ).flatten() { // Only look at `Ok` + additional_options.push(config_flag.to_string()); + additional_options.push(arg); } - metadata.unwrap_or_else(|e| show_error(format!("invalid `cargo metadata` output: {}", e))) + + let metadata = MetadataCommand::new() + .no_deps() + .other_options(additional_options) + .exec() + .unwrap(); + + metadata } /// Pulls all the crates in this workspace from the cargo metadata. @@ -627,7 +616,7 @@ fn local_crates(metadata: &Metadata) -> String { assert!(!metadata.workspace_members.is_empty()); let mut local_crates = String::new(); for member in &metadata.workspace_members { - let name = member.split(' ').next().unwrap(); + let name = member.repr.split(' ').next().unwrap(); let name = name.replace('-', "_"); local_crates.push_str(&name); local_crates.push(','); From 01a6109925151228f755a7fce7b384ca34dad13c Mon Sep 17 00:00:00 2001 From: Aleksei Trifonov Date: Fri, 29 Jul 2022 14:42:42 +0300 Subject: [PATCH 3592/3747] Fix formatting --- cargo-miri/bin.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index d11d3f15b8855..9c98542be8798 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -14,9 +14,9 @@ use std::ops::Not; use std::path::{Path, PathBuf}; use std::process::{self, Command}; +use cargo_metadata::{Metadata, MetadataCommand}; use rustc_version::VersionMeta; use serde::{Deserialize, Serialize}; -use cargo_metadata::{MetadataCommand, Metadata}; use version::*; @@ -594,16 +594,16 @@ fn get_cargo_metadata() -> Metadata { for arg in ArgSplitFlagValue::new( env::args().skip(3), // skip the program name, "miri" and "run" / "test" config_flag, - ).flatten() { // Only look at `Ok` + ) + // Only look at `Ok` + .flatten() + { additional_options.push(config_flag.to_string()); additional_options.push(arg); } - let metadata = MetadataCommand::new() - .no_deps() - .other_options(additional_options) - .exec() - .unwrap(); + let metadata = + MetadataCommand::new().no_deps().other_options(additional_options).exec().unwrap(); metadata } From 66f6fa68fa7e49d13a3fcf4128790a38220651d6 Mon Sep 17 00:00:00 2001 From: Hiroki6 Date: Sun, 31 Jul 2022 16:08:27 +0200 Subject: [PATCH 3593/3747] Fix typo in eval.rs --- src/eval.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/eval.rs b/src/eval.rs index 53264bd465914..c6fde1e683e0e 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -246,7 +246,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( } // Store command line as UTF-16 for Windows `GetCommandLineW`. { - // Construct a command string with all the aguments. + // Construct a command string with all the arguments. let cmd_utf16: Vec = args_to_utf16_command_string(config.args.iter()); let cmd_type = tcx.mk_array(tcx.types.u16, u64::try_from(cmd_utf16.len()).unwrap()); @@ -311,7 +311,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( /// Evaluates the entry function specified by `entry_id`. /// Returns `Some(return_code)` if program executed completed. -/// Returns `None` if an evaluation error occured. +/// Returns `None` if an evaluation error occurred. pub fn eval_entry<'tcx>( tcx: TyCtxt<'tcx>, entry_id: DefId, From f6badf037ec423bf41e64b815749a6be8b09dea6 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 1 Aug 2022 09:13:34 -0400 Subject: [PATCH 3594/3747] rustup --- cargo-miri/bin.rs | 4 ++-- rust-version | 2 +- test-cargo-miri/run-test.py | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs index 9c98542be8798..4ddf2295362ac 100644 --- a/cargo-miri/bin.rs +++ b/cargo-miri/bin.rs @@ -548,14 +548,14 @@ path = "lib.rs" // Manage the output the user sees. if only_setup { // We want to be explicit. - eprintln!("Preparing a sysroot for Miri..."); + eprintln!("Preparing a sysroot for Miri (target: {target})..."); if print_sysroot { // Be extra sure there is no noise on stdout. command.stdout(process::Stdio::null()); } } else { // We want to be quiet, but still let the user know that something is happening. - eprint!("Preparing a sysroot for Miri... "); + eprint!("Preparing a sysroot for Miri (target: {target})... "); command.stdout(process::Stdio::null()); command.stderr(process::Stdio::null()); } diff --git a/rust-version b/rust-version index 5f09f4f35b137..22daf00bd05de 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -c11207ec89b856164bba03b8ecfe07b0b234ed21 +1f5d8d49eb6111931091f700d07518cd2b80bc18 diff --git a/test-cargo-miri/run-test.py b/test-cargo-miri/run-test.py index 3805bd19777f7..4485d3252ccc2 100755 --- a/test-cargo-miri/run-test.py +++ b/test-cargo-miri/run-test.py @@ -29,7 +29,7 @@ def normalize_stdout(str): return str def normalize_stderr(str): - str = str.replace("Preparing a sysroot for Miri... done\n", "") # remove leading cargo-miri setup output + str = re.sub("Preparing a sysroot for Miri \(target: [a-z0-9_-]+\)\.\.\. done\n", "", str) # remove leading cargo-miri setup output return str def check_output(actual, path, name): From 9ffea913b8f116b4dcda1b1998b5bfcf50a6dc14 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 1 Aug 2022 09:27:10 -0400 Subject: [PATCH 3595/3747] clippy --- src/eval.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/eval.rs b/src/eval.rs index c6fde1e683e0e..cb24dea3a88dd 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -312,6 +312,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( /// Evaluates the entry function specified by `entry_id`. /// Returns `Some(return_code)` if program executed completed. /// Returns `None` if an evaluation error occurred. +#[allow(clippy::needless_lifetimes)] pub fn eval_entry<'tcx>( tcx: TyCtxt<'tcx>, entry_id: DefId, From b43bede93826f459e210957c8fd12fc1dd77d678 Mon Sep 17 00:00:00 2001 From: Christian Legnitto Date: Thu, 30 Jun 2022 13:10:31 -0400 Subject: [PATCH 3596/3747] Add shim for `realpath` on unix --- src/helpers.rs | 1 + src/shims/unix/foreign_items.rs | 5 + src/shims/unix/fs.rs | 62 ++++++++++++ src/shims/unix/macos/foreign_items.rs | 6 ++ tests/pass/fs.rs | 19 ++++ tests/pass/libc.rs | 133 +++++++++++++++++++++++++- 6 files changed, 224 insertions(+), 2 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index 01fc8e0df3f0c..766a3cba734b4 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -37,6 +37,7 @@ const UNIX_IO_ERROR_TABLE: &[(std::io::ErrorKind, &str)] = { (NotFound, "ENOENT"), (Interrupted, "EINTR"), (InvalidInput, "EINVAL"), + (InvalidFilename, "ENAMETOOLONG"), (TimedOut, "ETIMEDOUT"), (AlreadyExists, "EEXIST"), (WouldBlock, "EWOULDBLOCK"), diff --git a/src/shims/unix/foreign_items.rs b/src/shims/unix/foreign_items.rs index 2a051fb775397..5eb2d0a6cac2e 100644 --- a/src/shims/unix/foreign_items.rs +++ b/src/shims/unix/foreign_items.rs @@ -161,6 +161,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // fadvise is only informational, we can ignore it. this.write_null(dest)?; } + "realpath" => { + let [path, resolved_path] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let result = this.realpath(path, resolved_path)?; + this.write_pointer(result, dest)?; + } // Time related shims "gettimeofday" => { diff --git a/src/shims/unix/fs.rs b/src/shims/unix/fs.rs index c9f35c0489171..76c170987912c 100644 --- a/src/shims/unix/fs.rs +++ b/src/shims/unix/fs.rs @@ -1,5 +1,6 @@ use std::borrow::Cow; use std::collections::BTreeMap; +use std::convert::TryInto; use std::fs::{ read_dir, remove_dir, remove_file, rename, DirBuilder, File, FileType, OpenOptions, ReadDir, }; @@ -1662,6 +1663,67 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.set_last_error(enotty)?; Ok(0) } + + fn realpath( + &mut self, + path_op: &OpTy<'tcx, Provenance>, + processed_path_op: &OpTy<'tcx, Provenance>, + ) -> InterpResult<'tcx, Pointer>> { + let this = self.eval_context_mut(); + this.assert_target_os_is_unix("realpath"); + + let pathname = this.read_path_from_c_str(this.read_pointer(path_op)?)?; + let processed_ptr = this.read_pointer(processed_path_op)?; + + // Reject if isolation is enabled. + if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { + this.reject_in_isolation("`realpath`", reject_with)?; + let eacc = this.eval_libc("EACCES")?; + this.set_last_error(eacc)?; + return Ok(Pointer::null()); + } + + let result = std::fs::canonicalize(pathname); + match result { + Ok(resolved) => { + let path_max = this + .eval_libc_i32("PATH_MAX")? + .try_into() + .expect("PATH_MAX does not fit in u64"); + let dest = if this.ptr_is_null(processed_ptr)? { + // POSIX says behavior when passing a null pointer is implementation-defined, + // but GNU/linux, freebsd, netbsd, bionic/android, and macos all treat a null pointer + // similarly to: + // + // "If resolved_path is specified as NULL, then realpath() uses + // malloc(3) to allocate a buffer of up to PATH_MAX bytes to hold + // the resolved pathname, and returns a pointer to this buffer. The + // caller should deallocate this buffer using free(3)." + // + this.alloc_os_str_as_c_str(resolved.as_os_str(), MiriMemoryKind::C.into())? + } else { + let (wrote_path, _) = + this.write_path_to_c_str(&resolved, processed_ptr, path_max)?; + + if !wrote_path { + // Note that we do not explicitly handle `FILENAME_MAX` + // (different from `PATH_MAX` above) as it is Linux-specific and + // seems like a bit of a mess anyway: . + let enametoolong = this.eval_libc("ENAMETOOLONG")?; + this.set_last_error(enametoolong)?; + return Ok(Pointer::null()); + } + processed_ptr + }; + + Ok(dest) + } + Err(e) => { + this.set_last_error_from_io_error(e.kind())?; + Ok(Pointer::null()) + } + } + } } /// Extracts the number of seconds and nanoseconds elapsed between `time` and the unix epoch when diff --git a/src/shims/unix/macos/foreign_items.rs b/src/shims/unix/macos/foreign_items.rs index 21c7762c3ca19..fb545d8b5847e 100644 --- a/src/shims/unix/macos/foreign_items.rs +++ b/src/shims/unix/macos/foreign_items.rs @@ -73,6 +73,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let result = this.ftruncate64(fd, length)?; this.write_scalar(Scalar::from_i32(result), dest)?; } + "realpath$DARWIN_EXTSN" => { + let [path, resolved_path] = + this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let result = this.realpath(path, resolved_path)?; + this.write_pointer(result, dest)?; + } // Environment related shims "_NSGetEnviron" => { diff --git a/tests/pass/fs.rs b/tests/pass/fs.rs index 9d59fedb20edb..a8025007bf5f5 100644 --- a/tests/pass/fs.rs +++ b/tests/pass/fs.rs @@ -24,6 +24,7 @@ fn main() { test_errors(); test_rename(); test_directory(); + test_canonicalize(); test_dup_stdout_stderr(); // These all require unix, if the test is changed to no longer `ignore-windows`, move these to a unix test @@ -365,6 +366,24 @@ fn test_rename() { remove_file(&path2).unwrap(); } +fn test_canonicalize() { + use std::fs::canonicalize; + let dir_path = prepare_dir("miri_test_fs_dir"); + create_dir(&dir_path).unwrap(); + let path = dir_path.join("test_file"); + drop(File::create(&path).unwrap()); + + let p = canonicalize(format!("{}/./test_file", dir_path.to_string_lossy())).unwrap(); + assert_eq!(p.to_string_lossy().find('.'), None); + + remove_dir_all(&dir_path).unwrap(); + + // Make sure we get an error for long paths. + use std::convert::TryInto; + let too_long = "x/".repeat(libc::PATH_MAX.try_into().unwrap()); + assert!(canonicalize(too_long).is_err()); +} + fn test_directory() { let dir_path = prepare_dir("miri_test_fs_dir"); // Creating a directory should succeed. diff --git a/tests/pass/libc.rs b/tests/pass/libc.rs index 9b83ab45b0c01..2735e5b25bc3b 100644 --- a/tests/pass/libc.rs +++ b/tests/pass/libc.rs @@ -1,16 +1,141 @@ //@ignore-target-windows: No libc on Windows //@compile-flags: -Zmiri-disable-isolation +#![feature(io_error_more)] #![feature(rustc_private)] use std::fs::{remove_file, File}; use std::os::unix::io::AsRawFd; +use std::path::PathBuf; -fn tmp() -> std::path::PathBuf { +fn tmp() -> PathBuf { std::env::var("MIRI_TEMP") - .map(std::path::PathBuf::from) + .map(|tmp| { + // MIRI_TEMP is set outside of our emulated + // program, so it may have path separators that don't + // correspond to our target platform. We normalize them here + // before constructing a `PathBuf` + return PathBuf::from(tmp.replace("\\", "/")); + }) .unwrap_or_else(|_| std::env::temp_dir()) } +/// Test allocating variant of `realpath`. +fn test_posix_realpath_alloc() { + use std::ffi::OsString; + use std::ffi::{CStr, CString}; + use std::fs::{remove_file, File}; + use std::os::unix::ffi::OsStrExt; + use std::os::unix::ffi::OsStringExt; + + let buf; + let path = tmp().join("miri_test_libc_posix_realpath_alloc"); + let c_path = CString::new(path.as_os_str().as_bytes()).expect("CString::new failed"); + + // Cleanup before test. + remove_file(&path).ok(); + // Create file. + drop(File::create(&path).unwrap()); + unsafe { + let r = libc::realpath(c_path.as_ptr(), std::ptr::null_mut()); + assert!(!r.is_null()); + buf = CStr::from_ptr(r).to_bytes().to_vec(); + libc::free(r as *mut _); + } + let canonical = PathBuf::from(OsString::from_vec(buf)); + assert_eq!(path.file_name(), canonical.file_name()); + + // Cleanup after test. + remove_file(&path).unwrap(); +} + +/// Test non-allocating variant of `realpath`. +fn test_posix_realpath_noalloc() { + use std::ffi::{CStr, CString}; + use std::fs::{remove_file, File}; + use std::os::unix::ffi::OsStrExt; + + let path = tmp().join("miri_test_libc_posix_realpath_noalloc"); + let c_path = CString::new(path.as_os_str().as_bytes()).expect("CString::new failed"); + + let mut v = vec![0; libc::PATH_MAX as usize]; + + // Cleanup before test. + remove_file(&path).ok(); + // Create file. + drop(File::create(&path).unwrap()); + unsafe { + let r = libc::realpath(c_path.as_ptr(), v.as_mut_ptr()); + assert!(!r.is_null()); + } + let c = unsafe { CStr::from_ptr(v.as_ptr()) }; + let canonical = PathBuf::from(c.to_str().expect("CStr to str")); + + assert_eq!(path.file_name(), canonical.file_name()); + + // Cleanup after test. + remove_file(&path).unwrap(); +} + +/// Test failure cases for `realpath`. +fn test_posix_realpath_errors() { + use std::convert::TryInto; + use std::ffi::CString; + use std::fs::{create_dir_all, remove_dir_all}; + use std::io::ErrorKind; + use std::os::unix::ffi::OsStrExt; + use std::os::unix::fs::symlink; + + // Test non-existent path returns an error. + let c_path = CString::new("./nothing_to_see_here").expect("CString::new failed"); + let r = unsafe { libc::realpath(c_path.as_ptr(), std::ptr::null_mut()) }; + assert!(r.is_null()); + let e = std::io::Error::last_os_error(); + assert_eq!(e.raw_os_error(), Some(libc::ENOENT)); + assert_eq!(e.kind(), ErrorKind::NotFound); + + // Test that a long path returns an error. + // + // Linux first checks if the path exists and macos does not. + // Using an existing path ensures all platforms return `ENAMETOOLONG` given a long path. + // + // Rather than creating a bunch of directories, we create two directories containing symlinks. + // Sadly we can't avoid creating directories and instead use a path like "./././././" or "./../../" as linux + // appears to collapse "." and ".." before checking path length. + let path = tmp().join("posix_realpath_errors"); + // Cleanup before test. + remove_dir_all(&path).ok(); + + // The directories we will put symlinks in. + let x = path.join("x/"); + let y = path.join("y/"); + + // The symlinks in each directory pointing to each other. + let yx_sym = y.join("x"); + let xy_sym = x.join("y"); + + // Create directories. + create_dir_all(&x).expect("dir x"); + create_dir_all(&y).expect("dir y"); + + // Create symlinks between directories. + symlink(&x, &yx_sym).expect("symlink x"); + symlink(&y, &xy_sym).expect("symlink y "); + + // This path exists due to the symlinks created above. + let too_long = path.join("x/y/".repeat(libc::PATH_MAX.try_into().unwrap())); + + let c_path = CString::new(too_long.into_os_string().as_bytes()).expect("CString::new failed"); + let r = unsafe { libc::realpath(c_path.as_ptr(), std::ptr::null_mut()) }; + let e = std::io::Error::last_os_error(); + + assert!(r.is_null()); + assert_eq!(e.raw_os_error(), Some(libc::ENAMETOOLONG)); + assert_eq!(e.kind(), ErrorKind::InvalidFilename); + + // Cleanup after test. + remove_dir_all(&path).ok(); +} + #[cfg(any(target_os = "linux", target_os = "freebsd"))] fn test_posix_fadvise() { use std::convert::TryInto; @@ -336,6 +461,10 @@ fn main() { test_posix_gettimeofday(); + test_posix_realpath_alloc(); + test_posix_realpath_noalloc(); + test_posix_realpath_errors(); + #[cfg(any(target_os = "linux"))] test_sync_file_range(); From 8356f4cc23ea4c2403011b6c2c619738fce7e32a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 2 Aug 2022 18:08:43 -0400 Subject: [PATCH 3597/3747] output realpath as a path, and remove a bogus test --- src/helpers.rs | 1 + src/shims/os_str.rs | 13 ++++++++++++ src/shims/unix/fs.rs | 2 +- tests/pass/libc.rs | 48 -------------------------------------------- 4 files changed, 15 insertions(+), 49 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index 766a3cba734b4..acc2367afa28d 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -42,6 +42,7 @@ const UNIX_IO_ERROR_TABLE: &[(std::io::ErrorKind, &str)] = { (AlreadyExists, "EEXIST"), (WouldBlock, "EWOULDBLOCK"), (DirectoryNotEmpty, "ENOTEMPTY"), + (FilesystemLoop, "ELOOP"), ] }; diff --git a/src/shims/os_str.rs b/src/shims/os_str.rs index 71824bee346e4..b9f3a435ea429 100644 --- a/src/shims/os_str.rs +++ b/src/shims/os_str.rs @@ -250,6 +250,19 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_os_str_to_wide_str(&os_str, ptr, size) } + /// Allocate enough memory to store a Path as a null-terminated sequence of bytes, + /// adjusting path separators if needed. + fn alloc_path_as_c_str( + &mut self, + path: &Path, + memkind: MemoryKind, + ) -> InterpResult<'tcx, Pointer>> { + let this = self.eval_context_mut(); + let os_str = this + .convert_path_separator(Cow::Borrowed(path.as_os_str()), PathConversion::HostToTarget); + this.alloc_os_str_as_c_str(&os_str, memkind) + } + fn convert_path_separator<'a>( &self, os_str: Cow<'a, OsStr>, diff --git a/src/shims/unix/fs.rs b/src/shims/unix/fs.rs index 76c170987912c..36be1ec4f6fa0 100644 --- a/src/shims/unix/fs.rs +++ b/src/shims/unix/fs.rs @@ -1700,7 +1700,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // the resolved pathname, and returns a pointer to this buffer. The // caller should deallocate this buffer using free(3)." // - this.alloc_os_str_as_c_str(resolved.as_os_str(), MiriMemoryKind::C.into())? + this.alloc_path_as_c_str(&resolved, MiriMemoryKind::C.into())? } else { let (wrote_path, _) = this.write_path_to_c_str(&resolved, processed_ptr, path_max)?; diff --git a/tests/pass/libc.rs b/tests/pass/libc.rs index 2735e5b25bc3b..c7331b110e9ad 100644 --- a/tests/pass/libc.rs +++ b/tests/pass/libc.rs @@ -23,7 +23,6 @@ fn tmp() -> PathBuf { fn test_posix_realpath_alloc() { use std::ffi::OsString; use std::ffi::{CStr, CString}; - use std::fs::{remove_file, File}; use std::os::unix::ffi::OsStrExt; use std::os::unix::ffi::OsStringExt; @@ -51,7 +50,6 @@ fn test_posix_realpath_alloc() { /// Test non-allocating variant of `realpath`. fn test_posix_realpath_noalloc() { use std::ffi::{CStr, CString}; - use std::fs::{remove_file, File}; use std::os::unix::ffi::OsStrExt; let path = tmp().join("miri_test_libc_posix_realpath_noalloc"); @@ -78,12 +76,8 @@ fn test_posix_realpath_noalloc() { /// Test failure cases for `realpath`. fn test_posix_realpath_errors() { - use std::convert::TryInto; use std::ffi::CString; - use std::fs::{create_dir_all, remove_dir_all}; use std::io::ErrorKind; - use std::os::unix::ffi::OsStrExt; - use std::os::unix::fs::symlink; // Test non-existent path returns an error. let c_path = CString::new("./nothing_to_see_here").expect("CString::new failed"); @@ -92,48 +86,6 @@ fn test_posix_realpath_errors() { let e = std::io::Error::last_os_error(); assert_eq!(e.raw_os_error(), Some(libc::ENOENT)); assert_eq!(e.kind(), ErrorKind::NotFound); - - // Test that a long path returns an error. - // - // Linux first checks if the path exists and macos does not. - // Using an existing path ensures all platforms return `ENAMETOOLONG` given a long path. - // - // Rather than creating a bunch of directories, we create two directories containing symlinks. - // Sadly we can't avoid creating directories and instead use a path like "./././././" or "./../../" as linux - // appears to collapse "." and ".." before checking path length. - let path = tmp().join("posix_realpath_errors"); - // Cleanup before test. - remove_dir_all(&path).ok(); - - // The directories we will put symlinks in. - let x = path.join("x/"); - let y = path.join("y/"); - - // The symlinks in each directory pointing to each other. - let yx_sym = y.join("x"); - let xy_sym = x.join("y"); - - // Create directories. - create_dir_all(&x).expect("dir x"); - create_dir_all(&y).expect("dir y"); - - // Create symlinks between directories. - symlink(&x, &yx_sym).expect("symlink x"); - symlink(&y, &xy_sym).expect("symlink y "); - - // This path exists due to the symlinks created above. - let too_long = path.join("x/y/".repeat(libc::PATH_MAX.try_into().unwrap())); - - let c_path = CString::new(too_long.into_os_string().as_bytes()).expect("CString::new failed"); - let r = unsafe { libc::realpath(c_path.as_ptr(), std::ptr::null_mut()) }; - let e = std::io::Error::last_os_error(); - - assert!(r.is_null()); - assert_eq!(e.raw_os_error(), Some(libc::ENAMETOOLONG)); - assert_eq!(e.kind(), ErrorKind::InvalidFilename); - - // Cleanup after test. - remove_dir_all(&path).ok(); } #[cfg(any(target_os = "linux", target_os = "freebsd"))] From 87b9075920ae46aeb5e97220ea02cd88fa1d5652 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 2 Aug 2022 18:27:06 -0400 Subject: [PATCH 3598/3747] avoid double-space in test logging --- ui_test/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ui_test/src/lib.rs b/ui_test/src/lib.rs index bcc48b4b63169..9206c0f3d8e58 100644 --- a/ui_test/src/lib.rs +++ b/ui_test/src/lib.rs @@ -194,9 +194,9 @@ pub fn run_tests(mut config: Config) -> Result<()> { run_test(&path, &config, &target, &revision, &comments); // Using a single `eprintln!` to prevent messages from threads from getting intermingled. - let mut msg = format!("{} ", path.display()); + let mut msg = format!("{}", path.display()); if !revision.is_empty() { - write!(msg, "(revision `{revision}`) ").unwrap(); + write!(msg, " (revision `{revision}`) ").unwrap(); } if errors.is_empty() { finished_files_sender.send((msg, TestResult::Ok))?; From b29e7b8e4e4539eb1d916cf14123595858b79185 Mon Sep 17 00:00:00 2001 From: Christian Legnitto Date: Fri, 8 Jul 2022 01:51:16 -0400 Subject: [PATCH 3599/3747] Add `mkstemp` shim for unix Co-authored-by: Ralf Jung --- src/shims/unix/foreign_items.rs | 5 + src/shims/unix/fs.rs | 130 ++++++++++++++++++++- tests/fail/fs/mkstemp_immutable_arg.rs | 13 +++ tests/fail/fs/mkstemp_immutable_arg.stderr | 20 ++++ tests/pass/libc.rs | 45 +++++++ 5 files changed, 212 insertions(+), 1 deletion(-) create mode 100644 tests/fail/fs/mkstemp_immutable_arg.rs create mode 100644 tests/fail/fs/mkstemp_immutable_arg.stderr diff --git a/src/shims/unix/foreign_items.rs b/src/shims/unix/foreign_items.rs index 5eb2d0a6cac2e..83815cccb0c4d 100644 --- a/src/shims/unix/foreign_items.rs +++ b/src/shims/unix/foreign_items.rs @@ -166,6 +166,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let result = this.realpath(path, resolved_path)?; this.write_pointer(result, dest)?; } + "mkstemp" => { + let [template] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let result = this.mkstemp(template)?; + this.write_scalar(Scalar::from_i32(result), dest)?; + } // Time related shims "gettimeofday" => { diff --git a/src/shims/unix/fs.rs b/src/shims/unix/fs.rs index 36be1ec4f6fa0..9b00579d873b9 100644 --- a/src/shims/unix/fs.rs +++ b/src/shims/unix/fs.rs @@ -5,7 +5,7 @@ use std::fs::{ read_dir, remove_dir, remove_file, rename, DirBuilder, File, FileType, OpenOptions, ReadDir, }; use std::io::{self, ErrorKind, Read, Seek, SeekFrom, Write}; -use std::path::Path; +use std::path::{Path, PathBuf}; use std::time::SystemTime; use log::trace; @@ -14,6 +14,7 @@ use rustc_data_structures::fx::FxHashMap; use rustc_middle::ty::{self, layout::LayoutOf}; use rustc_target::abi::{Align, Size}; +use crate::shims::os_str::bytes_to_os_str; use crate::*; use shims::os_str::os_str_to_bytes; use shims::time::system_time_to_duration; @@ -1724,6 +1725,133 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } } + fn mkstemp(&mut self, template_op: &OpTy<'tcx, Provenance>) -> InterpResult<'tcx, i32> { + use rand::seq::SliceRandom; + + // POSIX defines the template string. + const TEMPFILE_TEMPLATE_STR: &str = "XXXXXX"; + + let this = self.eval_context_mut(); + this.assert_target_os_is_unix("mkstemp"); + + // POSIX defines the maximum number of attempts before failure. + // + // `mkstemp()` relies on `tmpnam()` which in turn relies on `TMP_MAX`. + // POSIX says this about `TMP_MAX`: + // * Minimum number of unique filenames generated by `tmpnam()`. + // * Maximum number of times an application can call `tmpnam()` reliably. + // * The value of `TMP_MAX` is at least 25. + // * On XSI-conformant systems, the value of `TMP_MAX` is at least 10000. + // See . + let max_attempts = this.eval_libc("TMP_MAX")?.to_u32()?; + + // Get the raw bytes from the template -- as a byte slice, this is a string in the target + // (and the target is unix, so a byte slice is the right representation). + let template_ptr = this.read_pointer(template_op)?; + let mut template = this.eval_context_ref().read_c_str(template_ptr)?.to_owned(); + let template_bytes = template.as_mut_slice(); + + // Reject if isolation is enabled. + if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { + this.reject_in_isolation("`mkstemp`", reject_with)?; + let eacc = this.eval_libc("EACCES")?; + this.set_last_error(eacc)?; + return Ok(-1); + } + + // Get the bytes of the suffix we expect in _target_ encoding. + let suffix_bytes = TEMPFILE_TEMPLATE_STR.as_bytes(); + + // At this point we have one `&[u8]` that represents the template and one `&[u8]` + // that represents the expected suffix. + + // Now we figure out the index of the slice we expect to contain the suffix. + let start_pos = template_bytes.len().saturating_sub(suffix_bytes.len()); + let end_pos = template_bytes.len(); + let last_six_char_bytes = &template_bytes[start_pos..end_pos]; + + // If we don't find the suffix, it is an error. + if last_six_char_bytes != suffix_bytes { + let einval = this.eval_libc("EINVAL")?; + this.set_last_error(einval)?; + return Ok(-1); + } + + // At this point we know we have 6 ASCII 'X' characters as a suffix. + + // From + const SUBSTITUTIONS: &[char; 62] = &[ + 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', + 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', + 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', + 'Z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + ]; + + // The file is opened with specific options, which Rust does not expose in a portable way. + // So we use specific APIs depending on the host OS. + let mut fopts = OpenOptions::new(); + fopts.read(true).write(true).create_new(true); + + #[cfg(unix)] + { + use std::os::unix::fs::OpenOptionsExt; + fopts.mode(0o600); + // Do not allow others to read or modify this file. + fopts.custom_flags(libc::O_EXCL); + } + #[cfg(windows)] + { + use std::os::windows::fs::OpenOptionsExt; + // Do not allow others to read or modify this file. + fopts.share_mode(0); + } + + // If the generated file already exists, we will try again `max_attempts` many times. + for _ in 0..max_attempts { + let rng = this.machine.rng.get_mut(); + + // Generate a random unique suffix. + let unique_suffix = SUBSTITUTIONS.choose_multiple(rng, 6).collect::(); + + // Replace the template string with the random string. + template_bytes[start_pos..end_pos].copy_from_slice(unique_suffix.as_bytes()); + + // Write the modified template back to the passed in pointer to maintain POSIX semantics. + this.write_bytes_ptr(template_ptr, template_bytes.iter().copied())?; + + // To actually open the file, turn this into a host OsString. + let p = bytes_to_os_str(template_bytes)?.to_os_string(); + + let possibly_unique = std::env::temp_dir().join::(p.into()); + + let file = fopts.open(&possibly_unique); + + match file { + Ok(f) => { + let fh = &mut this.machine.file_handler; + let fd = fh.insert_fd(Box::new(FileHandle { file: f, writable: true })); + return Ok(fd); + } + Err(e) => + match e.kind() { + // If the random file already exists, keep trying. + ErrorKind::AlreadyExists => continue, + // Any other errors are returned to the caller. + _ => { + // "On error, -1 is returned, and errno is set to + // indicate the error" + this.set_last_error_from_io_error(e.kind())?; + return Ok(-1); + } + }, + } + } + + // We ran out of attempts to create the file, return an error. + let eexist = this.eval_libc("EEXIST")?; + this.set_last_error(eexist)?; + Ok(-1) + } } /// Extracts the number of seconds and nanoseconds elapsed between `time` and the unix epoch when diff --git a/tests/fail/fs/mkstemp_immutable_arg.rs b/tests/fail/fs/mkstemp_immutable_arg.rs new file mode 100644 index 0000000000000..5be1fb394b902 --- /dev/null +++ b/tests/fail/fs/mkstemp_immutable_arg.rs @@ -0,0 +1,13 @@ +//@ignore-target-windows: No libc on Windows +//@compile-flags: -Zmiri-disable-isolation + +#![feature(rustc_private)] + +fn main() { + test_mkstemp_immutable_arg(); +} + +fn test_mkstemp_immutable_arg() { + let s: *mut libc::c_char = b"fooXXXXXX\0" as *const _ as *mut _; + let _fd = unsafe { libc::mkstemp(s) }; //~ ERROR: Undefined Behavior: writing to alloc1 which is read-only +} diff --git a/tests/fail/fs/mkstemp_immutable_arg.stderr b/tests/fail/fs/mkstemp_immutable_arg.stderr new file mode 100644 index 0000000000000..0bd91f90a10f3 --- /dev/null +++ b/tests/fail/fs/mkstemp_immutable_arg.stderr @@ -0,0 +1,20 @@ +error: Undefined Behavior: writing to ALLOC which is read-only + --> $DIR/mkstemp_immutable_arg.rs:LL:CC + | +LL | let _fd = unsafe { libc::mkstemp(s) }; + | ^^^^^^^^^^^^^^^^ writing to ALLOC which is read-only + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: backtrace: + = note: inside `test_mkstemp_immutable_arg` at $DIR/mkstemp_immutable_arg.rs:LL:CC +note: inside `main` at $DIR/mkstemp_immutable_arg.rs:LL:CC + --> $DIR/mkstemp_immutable_arg.rs:LL:CC + | +LL | test_mkstemp_immutable_arg(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/pass/libc.rs b/tests/pass/libc.rs index c7331b110e9ad..468da0845a88e 100644 --- a/tests/pass/libc.rs +++ b/tests/pass/libc.rs @@ -407,11 +407,56 @@ fn test_isatty() { } } +fn test_posix_mkstemp() { + use std::ffi::CString; + use std::ffi::OsStr; + use std::os::unix::ffi::OsStrExt; + use std::os::unix::io::FromRawFd; + use std::path::Path; + + let valid_template = "fooXXXXXX"; + // C needs to own this as `mkstemp(3)` says: + // "Since it will be modified, `template` must not be a string constant, but + // should be declared as a character array." + // There seems to be no `as_mut_ptr` on `CString` so we need to use `into_raw`. + let ptr = CString::new(valid_template).unwrap().into_raw(); + let fd = unsafe { libc::mkstemp(ptr) }; + // Take ownership back in Rust to not leak memory. + let slice = unsafe { CString::from_raw(ptr) }; + assert!(fd > 0); + let osstr = OsStr::from_bytes(slice.to_bytes()); + let path: &Path = osstr.as_ref(); + let name = path.file_name().unwrap().to_string_lossy(); + assert!(name.ne("fooXXXXXX")); + assert!(name.starts_with("foo")); + assert_eq!(name.len(), 9); + assert_eq!( + name.chars().skip(3).filter(char::is_ascii_alphanumeric).collect::>().len(), + 6 + ); + let file = unsafe { File::from_raw_fd(fd) }; + assert!(file.set_len(0).is_ok()); + + let invalid_templates = vec!["foo", "barXX", "XXXXXXbaz", "whatXXXXXXever", "X"]; + for t in invalid_templates { + let ptr = CString::new(t).unwrap().into_raw(); + let fd = unsafe { libc::mkstemp(ptr) }; + let _ = unsafe { CString::from_raw(ptr) }; + // "On error, -1 is returned, and errno is set to + // indicate the error" + assert_eq!(fd, -1); + let e = std::io::Error::last_os_error(); + assert_eq!(e.raw_os_error(), Some(libc::EINVAL)); + assert_eq!(e.kind(), std::io::ErrorKind::InvalidInput); + } +} + fn main() { #[cfg(any(target_os = "linux", target_os = "freebsd"))] test_posix_fadvise(); test_posix_gettimeofday(); + test_posix_mkstemp(); test_posix_realpath_alloc(); test_posix_realpath_noalloc(); From 29e9a8aa1a3639393681f2d1bd471a38eb08e318 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 2 Aug 2022 21:41:26 -0400 Subject: [PATCH 3600/3747] split cargo-miri into multiple files also greatly extend the 'who calls who' comment --- .github/workflows/ci.yml | 2 +- cargo-miri/Cargo.toml | 2 +- cargo-miri/bin.rs | 1274 ------------------------------- cargo-miri/src/main.rs | 95 +++ cargo-miri/src/phases.rs | 601 +++++++++++++++ cargo-miri/src/setup.rs | 247 ++++++ cargo-miri/src/util.rs | 375 +++++++++ cargo-miri/{ => src}/version.rs | 0 8 files changed, 1320 insertions(+), 1276 deletions(-) delete mode 100644 cargo-miri/bin.rs create mode 100644 cargo-miri/src/main.rs create mode 100644 cargo-miri/src/phases.rs create mode 100644 cargo-miri/src/setup.rs create mode 100644 cargo-miri/src/util.rs rename cargo-miri/{ => src}/version.rs (100%) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7d6e39dc31b26..95303a592c8a2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -58,7 +58,7 @@ jobs: # contains package information of crates installed via `cargo install`. ~/.cargo/.crates.toml ~/.cargo/.crates2.json - key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock', 'cargo-miri/version.rs') }} + key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock', 'cargo-miri/src/version.rs') }} restore-keys: ${{ runner.os }}-cargo - name: Install rustup-toolchain-install-master and xargo diff --git a/cargo-miri/Cargo.toml b/cargo-miri/Cargo.toml index 8bcd77c70b013..9ac170c5b5377 100644 --- a/cargo-miri/Cargo.toml +++ b/cargo-miri/Cargo.toml @@ -9,7 +9,7 @@ edition = "2021" [[bin]] name = "cargo-miri" -path = "bin.rs" +path = "src/main.rs" test = false # we have no unit tests doctest = false # and no doc tests diff --git a/cargo-miri/bin.rs b/cargo-miri/bin.rs deleted file mode 100644 index 4ddf2295362ac..0000000000000 --- a/cargo-miri/bin.rs +++ /dev/null @@ -1,1274 +0,0 @@ -#![feature(let_else)] -#![allow(clippy::useless_format, clippy::derive_partial_eq_without_eq)] - -mod version; - -use std::collections::HashMap; -use std::env; -use std::ffi::{OsStr, OsString}; -use std::fmt::Write as _; -use std::fs::{self, File}; -use std::io::{self, BufRead, BufReader, BufWriter, Read, Write}; -use std::iter::{self, TakeWhile}; -use std::ops::Not; -use std::path::{Path, PathBuf}; -use std::process::{self, Command}; - -use cargo_metadata::{Metadata, MetadataCommand}; -use rustc_version::VersionMeta; -use serde::{Deserialize, Serialize}; - -use version::*; - -const CARGO_MIRI_HELP: &str = r#"Runs binary crates and tests in Miri - -Usage: - cargo miri [subcommand] [...] [--] [...] - -Subcommands: - run, r Run binaries - test, t Run tests - nextest Run tests with nextest (requires cargo-nextest installed) - setup Only perform automatic setup, but without asking questions (for getting a proper libstd) - -The cargo options are exactly the same as for `cargo run` and `cargo test`, respectively. - -Examples: - cargo miri run - cargo miri test -- test-suite-filter - - cargo miri setup --print sysroot - This will print the path to the generated sysroot (and nothing else) on stdout. - stderr will still contain progress information about how the build is doing. - -"#; - -#[derive(Clone, Debug)] -enum MiriCommand { - /// Our own special 'setup' command. - Setup, - /// A command to be forwarded to cargo. - Forward(String), -} - -/// The information to run a crate with the given environment. -#[derive(Clone, Serialize, Deserialize)] -struct CrateRunEnv { - /// The command-line arguments. - args: Vec, - /// The environment. - env: Vec<(OsString, OsString)>, - /// The current working directory. - current_dir: OsString, - /// The contents passed via standard input. - stdin: Vec, -} - -impl CrateRunEnv { - /// Gather all the information we need. - fn collect(args: impl Iterator, capture_stdin: bool) -> Self { - let args = args.collect(); - let env = env::vars_os().collect(); - let current_dir = env::current_dir().unwrap().into_os_string(); - - let mut stdin = Vec::new(); - if capture_stdin { - std::io::stdin().lock().read_to_end(&mut stdin).expect("cannot read stdin"); - } - - CrateRunEnv { args, env, current_dir, stdin } - } -} - -/// The information Miri needs to run a crate. Stored as JSON when the crate is "compiled". -#[derive(Serialize, Deserialize)] -enum CrateRunInfo { - /// Run it with the given environment. - RunWith(CrateRunEnv), - /// Skip it as Miri does not support interpreting such kind of crates. - SkipProcMacroTest, -} - -impl CrateRunInfo { - fn store(&self, filename: &Path) { - let file = File::create(filename) - .unwrap_or_else(|_| show_error(format!("cannot create `{}`", filename.display()))); - let file = BufWriter::new(file); - serde_json::ser::to_writer(file, self) - .unwrap_or_else(|_| show_error(format!("cannot write to `{}`", filename.display()))); - } -} - -fn show_help() { - println!("{}", CARGO_MIRI_HELP); -} - -fn show_version() { - let mut version = format!("miri {}", env!("CARGO_PKG_VERSION")); - // Only use `option_env` on vergen variables to ensure the build succeeds - // when vergen failed to find the git info. - if let Some(sha) = option_env!("VERGEN_GIT_SHA_SHORT") { - // This `unwrap` can never fail because if VERGEN_GIT_SHA_SHORT exists, then so does - // VERGEN_GIT_COMMIT_DATE. - #[allow(clippy::option_env_unwrap)] - write!(&mut version, " ({} {})", sha, option_env!("VERGEN_GIT_COMMIT_DATE").unwrap()) - .unwrap(); - } - println!("{}", version); -} - -fn show_error(msg: String) -> ! { - eprintln!("fatal error: {}", msg); - std::process::exit(1) -} - -/// Determines whether a `--flag` is present. -fn has_arg_flag(name: &str) -> bool { - num_arg_flag(name) > 0 -} - -/// Determines how many times a `--flag` is present. -fn num_arg_flag(name: &str) -> usize { - std::env::args().take_while(|val| val != "--").filter(|val| val == name).count() -} - -/// Yields all values of command line flag `name` as `Ok(arg)`, and all other arguments except -/// the flag as `Err(arg)`. (The flag `name` itself is not yielded at all, only its values are.) -struct ArgSplitFlagValue<'a, I> { - args: TakeWhile bool>, - name: &'a str, -} - -impl<'a, I: Iterator> ArgSplitFlagValue<'a, I> { - fn new(args: I, name: &'a str) -> Self { - Self { - // Stop searching at `--`. - args: args.take_while(|val| val != "--"), - name, - } - } -} - -impl> Iterator for ArgSplitFlagValue<'_, I> { - type Item = Result; - - fn next(&mut self) -> Option { - let arg = self.args.next()?; - if let Some(suffix) = arg.strip_prefix(self.name) { - // Strip leading `name`. - if suffix.is_empty() { - // This argument is exactly `name`; the next one is the value. - return self.args.next().map(Ok); - } else if let Some(suffix) = suffix.strip_prefix('=') { - // This argument is `name=value`; get the value. - return Some(Ok(suffix.to_owned())); - } - } - Some(Err(arg)) - } -} - -/// Yields all values of command line flag `name`. -struct ArgFlagValueIter<'a>(ArgSplitFlagValue<'a, env::Args>); - -impl<'a> ArgFlagValueIter<'a> { - fn new(name: &'a str) -> Self { - Self(ArgSplitFlagValue::new(env::args(), name)) - } -} - -impl Iterator for ArgFlagValueIter<'_> { - type Item = String; - - fn next(&mut self) -> Option { - loop { - if let Ok(value) = self.0.next()? { - return Some(value); - } - } - } -} - -/// Gets the value of a `--flag`. -fn get_arg_flag_value(name: &str) -> Option { - ArgFlagValueIter::new(name).next() -} - -fn forward_patched_extern_arg(args: &mut impl Iterator, cmd: &mut Command) { - cmd.arg("--extern"); // always forward flag, but adjust filename: - let path = args.next().expect("`--extern` should be followed by a filename"); - if let Some(lib) = path.strip_suffix(".rlib") { - // If this is an rlib, make it an rmeta. - cmd.arg(format!("{}.rmeta", lib)); - } else { - // Some other extern file (e.g. a `.so`). Forward unchanged. - cmd.arg(path); - } -} - -/// Escapes `s` in a way that is suitable for using it as a string literal in TOML syntax. -fn escape_for_toml(s: &str) -> String { - // We want to surround this string in quotes `"`. So we first escape all quotes, - // and also all backslashes (that are used to escape quotes). - let s = s.replace('\\', r#"\\"#).replace('"', r#"\""#); - format!("\"{}\"", s) -} - -/// Returns the path to the `miri` binary -fn find_miri() -> PathBuf { - if let Some(path) = env::var_os("MIRI") { - return path.into(); - } - let mut path = std::env::current_exe().expect("current executable path invalid"); - if cfg!(windows) { - path.set_file_name("miri.exe"); - } else { - path.set_file_name("miri"); - } - path -} - -fn miri() -> Command { - Command::new(find_miri()) -} - -fn miri_for_host() -> Command { - let mut cmd = miri(); - cmd.env("MIRI_BE_RUSTC", "host"); - cmd -} - -fn version_info() -> VersionMeta { - VersionMeta::for_command(miri_for_host()) - .expect("failed to determine underlying rustc version of Miri") -} - -fn cargo() -> Command { - Command::new(env::var_os("CARGO").unwrap_or_else(|| OsString::from("cargo"))) -} - -fn xargo_check() -> Command { - Command::new(env::var_os("XARGO_CHECK").unwrap_or_else(|| OsString::from("xargo-check"))) -} - -/// Execute the `Command`, where possible by replacing the current process with a new process -/// described by the `Command`. Then exit this process with the exit code of the new process. -fn exec(mut cmd: Command) -> ! { - // On non-Unix imitate POSIX exec as closely as we can - #[cfg(not(unix))] - { - let exit_status = cmd.status().expect("failed to run command"); - std::process::exit(exit_status.code().unwrap_or(-1)) - } - // On Unix targets, actually exec. - // If exec returns, process setup has failed. This is the same error condition as the expect in - // the non-Unix case. - #[cfg(unix)] - { - use std::os::unix::process::CommandExt; - let error = cmd.exec(); - Err(error).expect("failed to run command") - } -} - -/// Execute the `Command`, where possible by replacing the current process with a new process -/// described by the `Command`. Then exit this process with the exit code of the new process. -/// `input` is also piped to the new process's stdin, on cfg(unix) platforms by writing its -/// contents to `path` first, then setting stdin to that file. -fn exec_with_pipe

(mut cmd: Command, input: &[u8], path: P) -> ! -where - P: AsRef, -{ - #[cfg(unix)] - { - // Write the bytes we want to send to stdin out to a file - std::fs::write(&path, input).unwrap(); - // Open the file for reading, and set our new stdin to it - let stdin = File::open(&path).unwrap(); - cmd.stdin(stdin); - // Unlink the file so that it is fully cleaned up as soon as the new process exits - std::fs::remove_file(&path).unwrap(); - // Finally, we can hand off control. - exec(cmd) - } - #[cfg(not(unix))] - { - drop(path); // We don't need the path, we can pipe the bytes directly - cmd.stdin(process::Stdio::piped()); - let mut child = cmd.spawn().expect("failed to spawn process"); - { - let stdin = child.stdin.as_mut().expect("failed to open stdin"); - stdin.write_all(input).expect("failed to write out test source"); - } - let exit_status = child.wait().expect("failed to run command"); - std::process::exit(exit_status.code().unwrap_or(-1)) - } -} - -fn xargo_version() -> Option<(u32, u32, u32)> { - let out = xargo_check().arg("--version").output().ok()?; - if !out.status.success() { - return None; - } - // Parse output. The first line looks like "xargo 0.3.12 (b004f1c 2018-12-13)". - let line = out - .stderr - .lines() - .next() - .expect("malformed `xargo --version` output: not at least one line") - .expect("malformed `xargo --version` output: error reading first line"); - let (name, version) = { - let mut split = line.split(' '); - ( - split.next().expect("malformed `xargo --version` output: empty"), - split.next().expect("malformed `xargo --version` output: not at least two words"), - ) - }; - if name != "xargo" { - // This is some fork of xargo - return None; - } - let mut version_pieces = version.split('.'); - let major = version_pieces - .next() - .expect("malformed `xargo --version` output: not a major version piece") - .parse() - .expect("malformed `xargo --version` output: major version is not an integer"); - let minor = version_pieces - .next() - .expect("malformed `xargo --version` output: not a minor version piece") - .parse() - .expect("malformed `xargo --version` output: minor version is not an integer"); - let patch = version_pieces - .next() - .expect("malformed `xargo --version` output: not a patch version piece") - .parse() - .expect("malformed `xargo --version` output: patch version is not an integer"); - if version_pieces.next().is_some() { - panic!("malformed `xargo --version` output: more than three pieces in version"); - } - Some((major, minor, patch)) -} - -fn ask_to_run(mut cmd: Command, ask: bool, text: &str) { - // Disable interactive prompts in CI (GitHub Actions, Travis, AppVeyor, etc). - // Azure doesn't set `CI` though (nothing to see here, just Microsoft being Microsoft), - // so we also check their `TF_BUILD`. - let is_ci = env::var_os("CI").is_some() || env::var_os("TF_BUILD").is_some(); - if ask && !is_ci { - let mut buf = String::new(); - print!("I will run `{:?}` to {}. Proceed? [Y/n] ", cmd, text); - io::stdout().flush().unwrap(); - io::stdin().read_line(&mut buf).unwrap(); - match buf.trim().to_lowercase().as_ref() { - // Proceed. - "" | "y" | "yes" => {} - "n" | "no" => show_error(format!("aborting as per your request")), - a => show_error(format!("invalid answer `{}`", a)), - }; - } else { - eprintln!("Running `{:?}` to {}.", cmd, text); - } - - if cmd.status().unwrap_or_else(|_| panic!("failed to execute {:?}", cmd)).success().not() { - show_error(format!("failed to {}", text)); - } -} - -/// Writes the given content to the given file *cross-process atomically*, in the sense that another -/// process concurrently reading that file will see either the old content or the new content, but -/// not some intermediate (e.g., empty) state. -/// -/// We assume no other parts of this same process are trying to read or write that file. -fn write_to_file(filename: &Path, content: &str) { - // Create a temporary file with the desired contents. - let mut temp_filename = filename.as_os_str().to_os_string(); - temp_filename.push(&format!(".{}", std::process::id())); - let mut temp_file = File::create(&temp_filename).unwrap(); - temp_file.write_all(content.as_bytes()).unwrap(); - drop(temp_file); - - // Move file to the desired location. - fs::rename(temp_filename, filename).unwrap(); -} - -/// Performs the setup required to make `cargo miri` work: Getting a custom-built libstd. Then sets -/// `MIRI_SYSROOT`. Skipped if `MIRI_SYSROOT` is already set, in which case we expect the user has -/// done all this already. -fn setup(subcommand: &MiriCommand, host: &str, target: &str) { - let only_setup = matches!(subcommand, MiriCommand::Setup); - let ask_user = !only_setup; - let print_sysroot = only_setup && has_arg_flag("--print-sysroot"); // whether we just print the sysroot path - if std::env::var_os("MIRI_SYSROOT").is_some() { - if only_setup { - println!("WARNING: MIRI_SYSROOT already set, not doing anything.") - } - return; - } - - // First, we need xargo. - if xargo_version().map_or(true, |v| v < XARGO_MIN_VERSION) { - if std::env::var_os("XARGO_CHECK").is_some() { - // The user manually gave us a xargo binary; don't do anything automatically. - show_error(format!("xargo is too old; please upgrade to the latest version")) - } - let mut cmd = cargo(); - cmd.args(&["install", "xargo"]); - ask_to_run(cmd, ask_user, "install a recent enough xargo"); - } - - // Determine where the rust sources are located. The env vars manually setting the source - // (`MIRI_LIB_SRC`, `XARGO_RUST_SRC`) trump auto-detection. - let rust_src_env_var = - std::env::var_os("MIRI_LIB_SRC").or_else(|| std::env::var_os("XARGO_RUST_SRC")); - let rust_src = match rust_src_env_var { - Some(path) => { - let path = PathBuf::from(path); - // Make path absolute if possible. - path.canonicalize().unwrap_or(path) - } - None => { - // Check for `rust-src` rustup component. - let output = miri_for_host() - .args(&["--print", "sysroot"]) - .output() - .expect("failed to determine sysroot"); - if !output.status.success() { - show_error(format!( - "Failed to determine sysroot; Miri said:\n{}", - String::from_utf8_lossy(&output.stderr).trim_end() - )); - } - let sysroot = std::str::from_utf8(&output.stdout).unwrap(); - let sysroot = Path::new(sysroot.trim_end_matches('\n')); - // Check for `$SYSROOT/lib/rustlib/src/rust/library`; test if that contains `std/Cargo.toml`. - let rustup_src = - sysroot.join("lib").join("rustlib").join("src").join("rust").join("library"); - if !rustup_src.join("std").join("Cargo.toml").exists() { - // Ask the user to install the `rust-src` component, and use that. - let mut cmd = Command::new("rustup"); - cmd.args(&["component", "add", "rust-src"]); - ask_to_run( - cmd, - ask_user, - "install the `rust-src` component for the selected toolchain", - ); - } - rustup_src - } - }; - if !rust_src.exists() { - show_error(format!("given Rust source directory `{}` does not exist.", rust_src.display())); - } - if rust_src.file_name().and_then(OsStr::to_str) != Some("library") { - show_error(format!( - "given Rust source directory `{}` does not seem to be the `library` subdirectory of \ - a Rust source checkout.", - rust_src.display() - )); - } - - // Next, we need our own libstd. Prepare a xargo project for that purpose. - // We will do this work in whatever is a good cache dir for this platform. - let dirs = directories::ProjectDirs::from("org", "rust-lang", "miri").unwrap(); - let dir = dirs.cache_dir(); - if !dir.exists() { - fs::create_dir_all(&dir).unwrap(); - } - // The interesting bit: Xargo.toml (only needs content if we actually need std) - let xargo_toml = if std::env::var_os("MIRI_NO_STD").is_some() { - "" - } else { - r#" -[dependencies.std] -default_features = false -# We support unwinding, so enable that panic runtime. -features = ["panic_unwind", "backtrace"] - -[dependencies.test] -"# - }; - write_to_file(&dir.join("Xargo.toml"), xargo_toml); - // The boring bits: a dummy project for xargo. - // FIXME: With xargo-check, can we avoid doing this? - write_to_file( - &dir.join("Cargo.toml"), - r#" -[package] -name = "miri-xargo" -description = "A dummy project for building libstd with xargo." -version = "0.0.0" - -[lib] -path = "lib.rs" -"#, - ); - write_to_file(&dir.join("lib.rs"), "#![no_std]"); - - // Figure out where xargo will build its stuff. - // Unfortunately, it puts things into a different directory when the - // architecture matches the host. - let sysroot = if target == host { dir.join("HOST") } else { PathBuf::from(dir) }; - // Make sure all target-level Miri invocations know their sysroot. - std::env::set_var("MIRI_SYSROOT", &sysroot); - - // Now invoke xargo. - let mut command = xargo_check(); - command.arg("check").arg("-q"); - command.current_dir(&dir); - command.env("XARGO_HOME", &dir); - command.env("XARGO_RUST_SRC", &rust_src); - // We always need to set a target so rustc bootstrap can tell apart host from target crates. - command.arg("--target").arg(target); - // Use Miri as rustc to build a libstd compatible with us (and use the right flags). - // However, when we are running in bootstrap, we cannot just overwrite `RUSTC`, - // because we still need bootstrap to distinguish between host and target crates. - // In that case we overwrite `RUSTC_REAL` instead which determines the rustc used - // for target crates. - // We set ourselves (`cargo-miri`) instead of Miri directly to be able to patch the flags - // for `libpanic_abort` (usually this is done by bootstrap but we have to do it ourselves). - // The `MIRI_CALLED_FROM_XARGO` will mean we dispatch to `phase_setup_rustc`. - let cargo_miri_path = std::env::current_exe().expect("current executable path invalid"); - if env::var_os("RUSTC_STAGE").is_some() { - assert!(env::var_os("RUSTC").is_some()); - command.env("RUSTC_REAL", &cargo_miri_path); - } else { - command.env("RUSTC", &cargo_miri_path); - } - command.env("MIRI_CALLED_FROM_XARGO", "1"); - // Make sure there are no other wrappers getting in our way - // (Cc https://github.com/rust-lang/miri/issues/1421, https://github.com/rust-lang/miri/issues/2429). - // Looks like setting `RUSTC_WRAPPER` to the empty string overwrites `build.rustc-wrapper` set via `config.toml`. - command.env("RUSTC_WRAPPER", ""); - // Disable debug assertions in the standard library -- Miri is already slow enough. But keep the - // overflow checks, they are cheap. This completely overwrites flags the user might have set, - // which is consistent with normal `cargo build` that does not apply `RUSTFLAGS` to the sysroot - // either. - command.env("RUSTFLAGS", "-Cdebug-assertions=off -Coverflow-checks=on"); - // Manage the output the user sees. - if only_setup { - // We want to be explicit. - eprintln!("Preparing a sysroot for Miri (target: {target})..."); - if print_sysroot { - // Be extra sure there is no noise on stdout. - command.stdout(process::Stdio::null()); - } - } else { - // We want to be quiet, but still let the user know that something is happening. - eprint!("Preparing a sysroot for Miri (target: {target})... "); - command.stdout(process::Stdio::null()); - command.stderr(process::Stdio::null()); - } - - // Finally run it! - if command.status().expect("failed to run xargo").success().not() { - if only_setup { - show_error(format!("failed to run xargo, see error details above")) - } else { - show_error(format!( - "failed to run xargo; run `cargo miri setup` to see the error details" - )) - } - } - - // Figure out what to print. - if only_setup { - eprintln!("A sysroot for Miri is now available in `{}`.", sysroot.display()); - } else { - eprintln!("done"); - } - if print_sysroot { - // Print just the sysroot and nothing else to stdout; this way we do not need any escaping. - println!("{}", sysroot.display()); - } -} - -fn get_cargo_metadata() -> Metadata { - // The `build.target-dir` config can be passed by `--config` flags, so forward them to - // `cargo metadata`. - let mut additional_options = Vec::new(); - // `-Zunstable-options` is required by `--config`. - additional_options.push("-Zunstable-options".to_string()); - - let config_flag = "--config"; - for arg in ArgSplitFlagValue::new( - env::args().skip(3), // skip the program name, "miri" and "run" / "test" - config_flag, - ) - // Only look at `Ok` - .flatten() - { - additional_options.push(config_flag.to_string()); - additional_options.push(arg); - } - - let metadata = - MetadataCommand::new().no_deps().other_options(additional_options).exec().unwrap(); - - metadata -} - -/// Pulls all the crates in this workspace from the cargo metadata. -/// Workspace members are emitted like "miri 0.1.0 (path+file:///path/to/miri)" -/// Additionally, somewhere between cargo metadata and TyCtxt, '-' gets replaced with '_' so we -/// make that same transformation here. -fn local_crates(metadata: &Metadata) -> String { - assert!(!metadata.workspace_members.is_empty()); - let mut local_crates = String::new(); - for member in &metadata.workspace_members { - let name = member.repr.split(' ').next().unwrap(); - let name = name.replace('-', "_"); - local_crates.push_str(&name); - local_crates.push(','); - } - local_crates.pop(); // Remove the trailing ',' - - local_crates -} - -fn env_vars_from_cmd(cmd: &Command) -> Vec<(String, String)> { - let mut envs = HashMap::new(); - for (key, value) in std::env::vars() { - envs.insert(key, value); - } - for (key, value) in cmd.get_envs() { - if let Some(value) = value { - envs.insert(key.to_string_lossy().to_string(), value.to_string_lossy().to_string()); - } else { - envs.remove(&key.to_string_lossy().to_string()); - } - } - let mut envs: Vec<_> = envs.into_iter().collect(); - envs.sort(); - envs -} - -/// Debug-print a command that is going to be run. -fn debug_cmd(prefix: &str, verbose: usize, cmd: &Command) { - if verbose == 0 { - return; - } - // We only do a single `eprintln!` call to minimize concurrency interactions. - let mut out = prefix.to_string(); - writeln!(out, " running command: env \\").unwrap(); - if verbose > 1 { - // Print the full environment this will be called in. - for (key, value) in env_vars_from_cmd(cmd) { - writeln!(out, "{key}={value:?} \\").unwrap(); - } - } else { - // Print only what has been changed for this `cmd`. - for (var, val) in cmd.get_envs() { - if let Some(val) = val { - writeln!(out, "{}={:?} \\", var.to_string_lossy(), val).unwrap(); - } else { - writeln!(out, "--unset={}", var.to_string_lossy()).unwrap(); - } - } - } - write!(out, "{cmd:?}").unwrap(); - eprintln!("{}", out); -} - -fn phase_cargo_miri(mut args: impl Iterator) { - // Check for version and help flags even when invoked as `cargo-miri`. - if has_arg_flag("--help") || has_arg_flag("-h") { - show_help(); - return; - } - if has_arg_flag("--version") || has_arg_flag("-V") { - show_version(); - return; - } - - // Require a subcommand before any flags. - // We cannot know which of those flags take arguments and which do not, - // so we cannot detect subcommands later. - let Some(subcommand) = args.next() else { - show_error(format!("`cargo miri` needs to be called with a subcommand (`run`, `test`)")); - }; - let subcommand = match &*subcommand { - "setup" => MiriCommand::Setup, - "test" | "t" | "run" | "r" | "nextest" => MiriCommand::Forward(subcommand), - _ => - show_error(format!( - "`cargo miri` supports the following subcommands: `run`, `test`, `nextest`, and `setup`." - )), - }; - let verbose = num_arg_flag("-v"); - - // Determine the involved architectures. - let host = version_info().host; - let target = get_arg_flag_value("--target"); - let target = target.as_ref().unwrap_or(&host); - - // We always setup. - setup(&subcommand, &host, target); - - // Invoke actual cargo for the job, but with different flags. - // We re-use `cargo test` and `cargo run`, which makes target and binary handling very easy but - // requires some extra work to make the build check-only (see all the `--emit` hacks below). - // describes an alternative - // approach that uses `cargo check`, making that part easier but target and binary handling - // harder. - let cargo_miri_path = std::env::current_exe() - .expect("current executable path invalid") - .into_os_string() - .into_string() - .expect("current executable path is not valid UTF-8"); - let cargo_cmd = match subcommand { - MiriCommand::Forward(s) => s, - MiriCommand::Setup => return, // `cargo miri setup` stops here. - }; - let metadata = get_cargo_metadata(); - let mut cmd = cargo(); - cmd.arg(cargo_cmd); - - // Forward all arguments before `--` other than `--target-dir` and its value to Cargo. - let mut target_dir = None; - for arg in ArgSplitFlagValue::new(&mut args, "--target-dir") { - match arg { - Ok(value) => { - if target_dir.is_some() { - show_error(format!("`--target-dir` is provided more than once")); - } - target_dir = Some(value.into()); - } - Err(arg) => { - cmd.arg(arg); - } - } - } - // Detect the target directory if it's not specified via `--target-dir`. - let target_dir = target_dir.get_or_insert_with(|| metadata.target_directory.clone()); - // Set `--target-dir` to `miri` inside the original target directory. - target_dir.push("miri"); - cmd.arg("--target-dir").arg(target_dir); - - // Make sure the build target is explicitly set. - // This is needed to make the `target.runner` settings do something, - // and it later helps us detect which crates are proc-macro/build-script - // (host crates) and which crates are needed for the program itself. - if get_arg_flag_value("--target").is_none() { - // No target given. Explicitly pick the host. - cmd.arg("--target"); - cmd.arg(&host); - } - - // Set ourselves as runner for al binaries invoked by cargo. - // We use `all()` since `true` is not a thing in cfg-lang, but the empty conjunction is. :) - let cargo_miri_path_for_toml = escape_for_toml(&cargo_miri_path); - cmd.arg("--config") - .arg(format!("target.'cfg(all())'.runner=[{cargo_miri_path_for_toml}, 'runner']")); - - // Forward all further arguments after `--` to cargo. - cmd.arg("--").args(args); - - // Set `RUSTC_WRAPPER` to ourselves. Cargo will prepend that binary to its usual invocation, - // i.e., the first argument is `rustc` -- which is what we use in `main` to distinguish - // the two codepaths. (That extra argument is why we prefer this over setting `RUSTC`.) - if env::var_os("RUSTC_WRAPPER").is_some() { - println!( - "WARNING: Ignoring `RUSTC_WRAPPER` environment variable, Miri does not support wrapping." - ); - } - cmd.env("RUSTC_WRAPPER", &cargo_miri_path); - // We are going to invoke `MIRI` for everything, not `RUSTC`. - if env::var_os("RUSTC").is_some() && env::var_os("MIRI").is_none() { - println!( - "WARNING: Ignoring `RUSTC` environment variable; set `MIRI` if you want to control the binary used as the driver." - ); - } - // Build scripts (and also cargo: https://github.com/rust-lang/cargo/issues/10885) will invoke - // `rustc` even when `RUSTC_WRAPPER` is set. To make sure everything is coherent, we want that - // to be the Miri driver, but acting as rustc, on the target level. (Target, rather than host, - // is needed for cross-interpretation situations.) This is not a perfect emulation of real rustc - // (it might be unable to produce binaries since the sysroot is check-only), but it's as close - // as we can get, and it's good enough for autocfg. - // - // In `main`, we need the value of `RUSTC` to distinguish RUSTC_WRAPPER invocations from rustdoc - // or TARGET_RUNNER invocations, so we canonicalize it here to make it exceedingly unlikely that - // there would be a collision with other invocations of cargo-miri (as rustdoc or as runner). We - // explicitly do this even if RUSTC_STAGE is set, since for these builds we do *not* want the - // bootstrap `rustc` thing in our way! Instead, we have MIRI_HOST_SYSROOT to use for host - // builds. - cmd.env("RUSTC", &fs::canonicalize(find_miri()).unwrap()); - cmd.env("MIRI_BE_RUSTC", "target"); // we better remember to *unset* this in the other phases! - - // Set rustdoc to us as well, so we can run doctests. - cmd.env("RUSTDOC", &cargo_miri_path); - - cmd.env("MIRI_LOCAL_CRATES", local_crates(&metadata)); - if verbose > 0 { - cmd.env("MIRI_VERBOSE", verbose.to_string()); // This makes the other phases verbose. - } - - // Run cargo. - debug_cmd("[cargo-miri miri]", verbose, &cmd); - exec(cmd) -} - -#[derive(Debug, Copy, Clone, PartialEq)] -enum RustcPhase { - /// `rustc` called via `xargo` for sysroot build. - Setup, - /// `rustc` called by `cargo` for regular build. - Build, - /// `rustc` called by `rustdoc` for doctest. - Rustdoc, -} - -fn phase_rustc(mut args: impl Iterator, phase: RustcPhase) { - /// Determines if we are being invoked (as rustc) to build a crate for - /// the "target" architecture, in contrast to the "host" architecture. - /// Host crates are for build scripts and proc macros and still need to - /// be built like normal; target crates need to be built for or interpreted - /// by Miri. - /// - /// Currently, we detect this by checking for "--target=", which is - /// never set for host crates. This matches what rustc bootstrap does, - /// which hopefully makes it "reliable enough". This relies on us always - /// invoking cargo itself with `--target`, which `in_cargo_miri` ensures. - fn is_target_crate() -> bool { - get_arg_flag_value("--target").is_some() - } - - /// Returns whether or not Cargo invoked the wrapper (this binary) to compile - /// the final, binary crate (either a test for 'cargo test', or a binary for 'cargo run') - /// Cargo does not give us this information directly, so we need to check - /// various command-line flags. - fn is_runnable_crate() -> bool { - let is_bin = get_arg_flag_value("--crate-type").as_deref().unwrap_or("bin") == "bin"; - let is_test = has_arg_flag("--test"); - is_bin || is_test - } - - fn out_filename(prefix: &str, suffix: &str) -> PathBuf { - if let Some(out_dir) = get_arg_flag_value("--out-dir") { - let mut path = PathBuf::from(out_dir); - path.push(format!( - "{}{}{}{}", - prefix, - get_arg_flag_value("--crate-name").unwrap(), - // This is technically a `-C` flag but the prefix seems unique enough... - // (and cargo passes this before the filename so it should be unique) - get_arg_flag_value("extra-filename").unwrap_or_default(), - suffix, - )); - path - } else { - let out_file = get_arg_flag_value("-o").unwrap(); - PathBuf::from(out_file) - } - } - - // phase_cargo_miri set `MIRI_BE_RUSTC` for when build scripts directly invoke the driver; - // however, if we get called back by cargo here, we'll carefully compute the right flags - // ourselves, so we first un-do what the earlier phase did. - env::remove_var("MIRI_BE_RUSTC"); - - let verbose = std::env::var("MIRI_VERBOSE") - .map_or(0, |verbose| verbose.parse().expect("verbosity flag must be an integer")); - let target_crate = is_target_crate(); - // Determine whether this is cargo/xargo invoking rustc to get some infos. - let info_query = get_arg_flag_value("--print").is_some() || has_arg_flag("-vV"); - - let store_json = |info: CrateRunInfo| { - // Create a stub .d file to stop Cargo from "rebuilding" the crate: - // https://github.com/rust-lang/miri/issues/1724#issuecomment-787115693 - // As we store a JSON file instead of building the crate here, an empty file is fine. - let dep_info_name = out_filename("", ".d"); - if verbose > 0 { - eprintln!("[cargo-miri rustc] writing stub dep-info to `{}`", dep_info_name.display()); - } - File::create(dep_info_name).expect("failed to create fake .d file"); - - let filename = out_filename("", ""); - if verbose > 0 { - eprintln!("[cargo-miri rustc] writing run info to `{}`", filename.display()); - } - info.store(&filename); - // For Windows, do the same thing again with `.exe` appended to the filename. - // (Need to do this here as cargo moves that "binary" to a different place before running it.) - info.store(&out_filename("", ".exe")); - }; - - let runnable_crate = !info_query && is_runnable_crate(); - - if runnable_crate && target_crate { - assert!( - phase != RustcPhase::Setup, - "there should be no interpretation during sysroot build" - ); - let inside_rustdoc = phase == RustcPhase::Rustdoc; - // This is the binary or test crate that we want to interpret under Miri. - // But we cannot run it here, as cargo invoked us as a compiler -- our stdin and stdout are not - // like we want them. - // Instead of compiling, we write JSON into the output file with all the relevant command-line flags - // and environment variables; this is used when cargo calls us again in the CARGO_TARGET_RUNNER phase. - let env = CrateRunEnv::collect(args, inside_rustdoc); - - store_json(CrateRunInfo::RunWith(env.clone())); - - // Rustdoc expects us to exit with an error code if the test is marked as `compile_fail`, - // just creating the JSON file is not enough: we need to detect syntax errors, - // so we need to run Miri with `MIRI_BE_RUSTC` for a check-only build. - if inside_rustdoc { - let mut cmd = miri(); - - // Ensure --emit argument for a check-only build is present. - // We cannot use the usual helpers since we need to check specifically in `env.args`. - if let Some(i) = env.args.iter().position(|arg| arg.starts_with("--emit=")) { - // For `no_run` tests, rustdoc passes a `--emit` flag; make sure it has the right shape. - assert_eq!(env.args[i], "--emit=metadata"); - } else { - // For all other kinds of tests, we can just add our flag. - cmd.arg("--emit=metadata"); - } - - // Alter the `-o` parameter so that it does not overwrite the JSON file we stored above. - let mut args = env.args.clone(); - for i in 0..args.len() { - if args[i] == "-o" { - args[i + 1].push_str(".miri"); - } - } - - cmd.args(&args); - cmd.env("MIRI_BE_RUSTC", "target"); - - if verbose > 0 { - eprintln!( - "[cargo-miri rustc inside rustdoc] captured input:\n{}", - std::str::from_utf8(&env.stdin).unwrap() - ); - eprintln!("[cargo-miri rustc inside rustdoc] going to run:\n{:?}", cmd); - } - - exec_with_pipe(cmd, &env.stdin, format!("{}.stdin", out_filename("", "").display())); - } - - return; - } - - if runnable_crate && ArgFlagValueIter::new("--extern").any(|krate| krate == "proc_macro") { - // This is a "runnable" `proc-macro` crate (unit tests). We do not support - // interpreting that under Miri now, so we write a JSON file to (display a - // helpful message and) skip it in the runner phase. - store_json(CrateRunInfo::SkipProcMacroTest); - return; - } - - let mut cmd = miri(); - let mut emit_link_hack = false; - // Arguments are treated very differently depending on whether this crate is - // for interpretation by Miri, or for use by a build script / proc macro. - if !info_query && target_crate { - // Forward arguments, but remove "link" from "--emit" to make this a check-only build. - let emit_flag = "--emit"; - while let Some(arg) = args.next() { - if let Some(val) = arg.strip_prefix(emit_flag) { - // Patch this argument. First, extract its value. - let val = - val.strip_prefix('=').expect("`cargo` should pass `--emit=X` as one argument"); - let mut val: Vec<_> = val.split(',').collect(); - // Now make sure "link" is not in there, but "metadata" is. - if let Some(i) = val.iter().position(|&s| s == "link") { - emit_link_hack = true; - val.remove(i); - if !val.iter().any(|&s| s == "metadata") { - val.push("metadata"); - } - } - cmd.arg(format!("{}={}", emit_flag, val.join(","))); - } else if arg == "--extern" { - // Patch `--extern` filenames, since Cargo sometimes passes stub `.rlib` files: - // https://github.com/rust-lang/miri/issues/1705 - forward_patched_extern_arg(&mut args, &mut cmd); - } else { - cmd.arg(arg); - } - } - - // During setup, patch the panic runtime for `libpanic_abort` (mirroring what bootstrap usually does). - if phase == RustcPhase::Setup - && get_arg_flag_value("--crate-name").as_deref() == Some("panic_abort") - { - cmd.arg("-C").arg("panic=abort"); - } - } else { - // For host crates (but not when we are just printing some info), - // we might still have to set the sysroot. - if !info_query { - // When we're running `cargo-miri` from `x.py` we need to pass the sysroot explicitly - // due to bootstrap complications. - if let Some(sysroot) = std::env::var_os("MIRI_HOST_SYSROOT") { - cmd.arg("--sysroot").arg(sysroot); - } - } - - // For host crates or when we are printing, just forward everything. - cmd.args(args); - } - - // We want to compile, not interpret. We still use Miri to make sure the compiler version etc - // are the exact same as what is used for interpretation. - // MIRI_DEFAULT_ARGS should not be used to build host crates, hence setting "target" or "host" - // as the value here to help Miri differentiate them. - cmd.env("MIRI_BE_RUSTC", if target_crate { "target" } else { "host" }); - - // Run it. - if verbose > 0 { - eprintln!( - "[cargo-miri rustc] target_crate={target_crate} runnable_crate={runnable_crate} info_query={info_query}" - ); - } - - // Create a stub .rlib file if "link" was requested by cargo. - // This is necessary to prevent cargo from doing rebuilds all the time. - if emit_link_hack { - // Some platforms prepend "lib", some do not... let's just create both files. - File::create(out_filename("lib", ".rlib")).expect("failed to create fake .rlib file"); - File::create(out_filename("", ".rlib")).expect("failed to create fake .rlib file"); - // Just in case this is a cdylib or staticlib, also create those fake files. - File::create(out_filename("lib", ".so")).expect("failed to create fake .so file"); - File::create(out_filename("lib", ".a")).expect("failed to create fake .a file"); - File::create(out_filename("lib", ".dylib")).expect("failed to create fake .dylib file"); - File::create(out_filename("", ".dll")).expect("failed to create fake .dll file"); - File::create(out_filename("", ".lib")).expect("failed to create fake .lib file"); - } - - debug_cmd("[cargo-miri rustc]", verbose, &cmd); - exec(cmd); -} - -#[derive(Debug, Copy, Clone, PartialEq)] -enum RunnerPhase { - /// `cargo` is running a binary - Cargo, - /// `rustdoc` is running a binary - Rustdoc, -} - -fn phase_runner(mut binary_args: impl Iterator, phase: RunnerPhase) { - // phase_cargo_miri set `MIRI_BE_RUSTC` for when build scripts directly invoke the driver; - // however, if we get called back by cargo here, we'll carefully compute the right flags - // ourselves, so we first un-do what the earlier phase did. - env::remove_var("MIRI_BE_RUSTC"); - - let verbose = std::env::var("MIRI_VERBOSE") - .map_or(0, |verbose| verbose.parse().expect("verbosity flag must be an integer")); - - let binary = binary_args.next().unwrap(); - let file = File::open(&binary) - .unwrap_or_else(|_| show_error(format!( - "file {:?} not found or `cargo-miri` invoked incorrectly; please only invoke this binary through `cargo miri`", binary - ))); - let file = BufReader::new(file); - - let info = serde_json::from_reader(file).unwrap_or_else(|_| { - show_error(format!( - "file {:?} contains outdated or invalid JSON; try `cargo clean`", - binary - )) - }); - let info = match info { - CrateRunInfo::RunWith(info) => info, - CrateRunInfo::SkipProcMacroTest => { - eprintln!( - "Running unit tests of `proc-macro` crates is not currently supported by Miri." - ); - return; - } - }; - - let mut cmd = miri(); - - // Set missing env vars. We prefer build-time env vars over run-time ones; see - // for the kind of issue that fixes. - for (name, val) in info.env { - if let Some(old_val) = env::var_os(&name) { - if old_val == val { - // This one did not actually change, no need to re-set it. - // (This keeps the `debug_cmd` below more manageable.) - continue; - } else if verbose > 0 { - eprintln!( - "[cargo-miri runner] Overwriting run-time env var {:?}={:?} with build-time value {:?}", - name, old_val, val - ); - } - } - cmd.env(name, val); - } - - // Forward rustc arguments. - // We need to patch "--extern" filenames because we forced a check-only - // build without cargo knowing about that: replace `.rlib` suffix by - // `.rmeta`. - // We also need to remove `--error-format` as cargo specifies that to be JSON, - // but when we run here, cargo does not interpret the JSON any more. `--json` - // then also nees to be dropped. - let mut args = info.args.into_iter(); - let error_format_flag = "--error-format"; - let json_flag = "--json"; - while let Some(arg) = args.next() { - if arg == "--extern" { - forward_patched_extern_arg(&mut args, &mut cmd); - } else if let Some(suffix) = arg.strip_prefix(error_format_flag) { - assert!(suffix.starts_with('=')); - // Drop this argument. - } else if let Some(suffix) = arg.strip_prefix(json_flag) { - assert!(suffix.starts_with('=')); - // Drop this argument. - } else { - cmd.arg(arg); - } - } - // Respect `MIRIFLAGS`. - if let Ok(a) = env::var("MIRIFLAGS") { - // This code is taken from `RUSTFLAGS` handling in cargo. - let args = a.split(' ').map(str::trim).filter(|s| !s.is_empty()).map(str::to_string); - cmd.args(args); - } - - // Then pass binary arguments. - cmd.arg("--"); - cmd.args(binary_args); - - // Make sure we use the build-time working directory for interpreting Miri/rustc arguments. - // But then we need to switch to the run-time one, which we instruct Miri do do by setting `MIRI_CWD`. - cmd.current_dir(info.current_dir); - cmd.env("MIRI_CWD", env::current_dir().unwrap()); - - // Run it. - debug_cmd("[cargo-miri runner]", verbose, &cmd); - match phase { - RunnerPhase::Rustdoc => exec_with_pipe(cmd, &info.stdin, format!("{}.stdin", binary)), - RunnerPhase::Cargo => exec(cmd), - } -} - -fn phase_rustdoc(mut args: impl Iterator) { - let verbose = std::env::var("MIRI_VERBOSE") - .map_or(0, |verbose| verbose.parse().expect("verbosity flag must be an integer")); - - // phase_cargo_miri sets the RUSTDOC env var to ourselves, so we can't use that here; - // just default to a straight-forward invocation for now: - let mut cmd = Command::new("rustdoc"); - - let extern_flag = "--extern"; - let runtool_flag = "--runtool"; - while let Some(arg) = args.next() { - if arg == extern_flag { - // Patch --extern arguments to use *.rmeta files, since phase_cargo_rustc only creates stub *.rlib files. - forward_patched_extern_arg(&mut args, &mut cmd); - } else if arg == runtool_flag { - // An existing --runtool flag indicates cargo is running in cross-target mode, which we don't support. - // Note that this is only passed when cargo is run with the unstable -Zdoctest-xcompile flag; - // otherwise, we won't be called as rustdoc at all. - show_error(format!("cross-interpreting doctests is not currently supported by Miri.")); - } else { - cmd.arg(arg); - } - } - - // Doctests of `proc-macro` crates (and their dependencies) are always built for the host, - // so we are not able to run them in Miri. - if ArgFlagValueIter::new("--crate-type").any(|crate_type| crate_type == "proc-macro") { - eprintln!("Running doctests of `proc-macro` crates is not currently supported by Miri."); - return; - } - - // For each doctest, rustdoc starts two child processes: first the test is compiled, - // then the produced executable is invoked. We want to reroute both of these to cargo-miri, - // such that the first time we'll enter phase_cargo_rustc, and phase_cargo_runner second. - // - // rustdoc invokes the test-builder by forwarding most of its own arguments, which makes - // it difficult to determine when phase_cargo_rustc should run instead of phase_cargo_rustdoc. - // Furthermore, the test code is passed via stdin, rather than a temporary file, so we need - // to let phase_cargo_rustc know to expect that. We'll use this environment variable as a flag: - cmd.env("MIRI_CALLED_FROM_RUSTDOC", "1"); - - // The `--test-builder` and `--runtool` arguments are unstable rustdoc features, - // which are disabled by default. We first need to enable them explicitly: - cmd.arg("-Z").arg("unstable-options"); - - // rustdoc needs to know the right sysroot. - cmd.arg("--sysroot").arg(env::var_os("MIRI_SYSROOT").unwrap()); - // make sure the 'miri' flag is set for rustdoc - cmd.arg("--cfg").arg("miri"); - - // Make rustdoc call us back. - let cargo_miri_path = std::env::current_exe().expect("current executable path invalid"); - cmd.arg("--test-builder").arg(&cargo_miri_path); // invoked by forwarding most arguments - cmd.arg("--runtool").arg(&cargo_miri_path); // invoked with just a single path argument - - debug_cmd("[cargo-miri rustdoc]", verbose, &cmd); - exec(cmd) -} - -fn main() { - // Rustc does not support non-UTF-8 arguments so we make no attempt either. - // (We do support non-UTF-8 environment variables though.) - let mut args = std::env::args(); - // Skip binary name. - args.next().unwrap(); - - // Dispatch to `cargo-miri` phase. There are four phases: - // - When we are called via `cargo miri`, we run as the frontend and invoke the underlying - // cargo. We set RUSTDOC, RUSTC_WRAPPER and CARGO_TARGET_RUNNER to ourselves. - // - When we are executed due to RUSTDOC, we run rustdoc and set both `--test-builder` and - // `--runtool` to ourselves. - // - When we are executed due to RUSTC_WRAPPER (or as the rustdoc test builder), we build crates - // or store the flags of binary crates for later interpretation. - // - When we are executed due to CARGO_TARGET_RUNNER (or as the rustdoc runtool), we start - // interpretation based on the flags that were stored earlier. - // - // Additionally, we also set ourselves as RUSTC when calling xargo to build the sysroot, which - // has to be treated slightly differently than when we build regular crates. - - // Dispatch running as part of sysroot compilation. - if env::var_os("MIRI_CALLED_FROM_XARGO").is_some() { - phase_rustc(args, RustcPhase::Setup); - return; - } - - // The way rustdoc invokes rustc is indistuingishable from the way cargo invokes rustdoc by the - // arguments alone. `phase_cargo_rustdoc` sets this environment variable to let us disambiguate. - if env::var_os("MIRI_CALLED_FROM_RUSTDOC").is_some() { - // ...however, we then also see this variable when rustdoc invokes us as the testrunner! - // The runner is invoked as `$runtool ($runtool-arg)* output_file`; - // since we don't specify any runtool-args, and rustdoc supplies multiple arguments to - // the test-builder unconditionally, we can just check the number of remaining arguments: - if args.len() == 1 { - phase_runner(args, RunnerPhase::Rustdoc); - } else { - phase_rustc(args, RustcPhase::Rustdoc); - } - - return; - } - - let Some(first) = args.next() else { - show_error(format!( - "`cargo-miri` called without first argument; please only invoke this binary through `cargo miri`" - )) - }; - match first.as_str() { - "miri" => phase_cargo_miri(args), - "runner" => phase_runner(args, RunnerPhase::Cargo), - arg if arg == env::var("RUSTC").unwrap() => { - // If the first arg is equal to the RUSTC env ariable (which should be set at this - // point), then we need to behave as rustc. This is the somewhat counter-intuitive - // behavior of having both RUSTC and RUSTC_WRAPPER set - // (see https://github.com/rust-lang/cargo/issues/10886). - phase_rustc(args, RustcPhase::Build) - } - _ => { - // Everything else must be rustdoc. But we need to get `first` "back onto the iterator", - // it is some part of the rustdoc invocation. - phase_rustdoc(iter::once(first).chain(args)); - } - } -} diff --git a/cargo-miri/src/main.rs b/cargo-miri/src/main.rs new file mode 100644 index 0000000000000..9c07f90a40782 --- /dev/null +++ b/cargo-miri/src/main.rs @@ -0,0 +1,95 @@ +#![feature(let_else)] +#![allow(clippy::useless_format, clippy::derive_partial_eq_without_eq)] + +mod phases; +mod setup; +mod util; +mod version; + +use std::{env, iter}; + +use crate::{phases::*, util::*}; + +fn main() { + // Rustc does not support non-UTF-8 arguments so we make no attempt either. + // (We do support non-UTF-8 environment variables though.) + let mut args = std::env::args(); + // Skip binary name. + args.next().unwrap(); + + // Dispatch to `cargo-miri` phase. Here is a rough idea of "who calls who". + // + // Initially, we are invoked as `cargo-miri miri run/test`. We first run the setup phase: + // - We call `xargo`, and set `RUSTC` back to us, together with `MIRI_CALLED_FROM_XARGO`, + // so that xargo's rustc invocations end up in `phase_rustc` with `RustcPhase::Setup`. + // There we then call the Miri driver with `MIRI_BE_RUSTC` to perform the actual build. + // + // Then we call `cargo run/test`, exactly forwarding all user flags, plus some configuration so + // that we control every binary invoked by cargo: + // - We set RUSTC_WRAPPER to ourselves, so for (almost) all rustc invocations, we end up in + // `phase_rustc` with `RustcPhase::Build`. This will in turn either determine that a + // dependency needs to be built (for which it invokes the Miri driver with `MIRI_BE_RUSTC`), + // or determine that this is a binary Miri should run, in which case we generate a JSON file + // with all the information needed to build and run this crate. + // (We don't run it yet since cargo thinks this is a build step, not a run step -- running the + // binary here would lead to a bad user experience.) + // - We set RUSTC to the Miri driver and also set `MIRI_BE_RUSTC`, so that gets called by build + // scripts (and cargo uses it for the version query). + // - We set `target.*.runner` to `cargo-miri runner`, which ends up calling `phase_runner` for + // `RunnerPhase::Cargo`. This parses the JSON file written in `phase_rustc` and then invokes + // the actual Miri driver for interpretation. + // - We set RUSTDOC to ourselves, which ends up in `phase_rustdoc`. There we call regular + // rustdoc with some extra flags, and we set `MIRI_CALLED_FROM_RUSTDOC` to recognize this + // phase in our recursive invocations: + // - We set the `--test-builder` flag of rustdoc to ourselves, which ends up in `phase_rustc` + // with `RustcPhase::Rustdoc`. There we perform a check-build (needed to get the expected + // build failures for `compile_fail` doctests) and then store a JSON file with the + // information needed to run this test. + // - We also set `--runtool` to ourselves, which ends up in `phase_runner` with + // `RunnerPhase::Rustdoc`. There we parse the JSON file written in `phase_rustc` and invoke + // the Miri driver for interpretation. + + // Dispatch running as part of sysroot compilation. + if env::var_os("MIRI_CALLED_FROM_XARGO").is_some() { + phase_rustc(args, RustcPhase::Setup); + return; + } + + // The way rustdoc invokes rustc is indistuingishable from the way cargo invokes rustdoc by the + // arguments alone. `phase_cargo_rustdoc` sets this environment variable to let us disambiguate. + if env::var_os("MIRI_CALLED_FROM_RUSTDOC").is_some() { + // ...however, we then also see this variable when rustdoc invokes us as the testrunner! + // The runner is invoked as `$runtool ($runtool-arg)* output_file`; + // since we don't specify any runtool-args, and rustdoc supplies multiple arguments to + // the test-builder unconditionally, we can just check the number of remaining arguments: + if args.len() == 1 { + phase_runner(args, RunnerPhase::Rustdoc); + } else { + phase_rustc(args, RustcPhase::Rustdoc); + } + + return; + } + + let Some(first) = args.next() else { + show_error(format!( + "`cargo-miri` called without first argument; please only invoke this binary through `cargo miri`" + )) + }; + match first.as_str() { + "miri" => phase_cargo_miri(args), + "runner" => phase_runner(args, RunnerPhase::Cargo), + arg if arg == env::var("RUSTC").unwrap() => { + // If the first arg is equal to the RUSTC env ariable (which should be set at this + // point), then we need to behave as rustc. This is the somewhat counter-intuitive + // behavior of having both RUSTC and RUSTC_WRAPPER set + // (see https://github.com/rust-lang/cargo/issues/10886). + phase_rustc(args, RustcPhase::Build) + } + _ => { + // Everything else must be rustdoc. But we need to get `first` "back onto the iterator", + // it is some part of the rustdoc invocation. + phase_rustdoc(iter::once(first).chain(args)); + } + } +} diff --git a/cargo-miri/src/phases.rs b/cargo-miri/src/phases.rs new file mode 100644 index 0000000000000..4ba627de482cf --- /dev/null +++ b/cargo-miri/src/phases.rs @@ -0,0 +1,601 @@ +//! Implements the various phases of `cargo miri run/test`. + +use std::env; +use std::fmt::Write as _; +use std::fs::{self, File}; +use std::io::BufReader; +use std::path::PathBuf; +use std::process::Command; + +use crate::{setup::*, util::*}; + +const CARGO_MIRI_HELP: &str = r#"Runs binary crates and tests in Miri + +Usage: + cargo miri [subcommand] [...] [--] [...] + +Subcommands: + run, r Run binaries + test, t Run tests + nextest Run tests with nextest (requires cargo-nextest installed) + setup Only perform automatic setup, but without asking questions (for getting a proper libstd) + +The cargo options are exactly the same as for `cargo run` and `cargo test`, respectively. + +Examples: + cargo miri run + cargo miri test -- test-suite-filter + + cargo miri setup --print sysroot + This will print the path to the generated sysroot (and nothing else) on stdout. + stderr will still contain progress information about how the build is doing. + +"#; + +fn show_help() { + println!("{}", CARGO_MIRI_HELP); +} + +fn show_version() { + let mut version = format!("miri {}", env!("CARGO_PKG_VERSION")); + // Only use `option_env` on vergen variables to ensure the build succeeds + // when vergen failed to find the git info. + if let Some(sha) = option_env!("VERGEN_GIT_SHA_SHORT") { + // This `unwrap` can never fail because if VERGEN_GIT_SHA_SHORT exists, then so does + // VERGEN_GIT_COMMIT_DATE. + #[allow(clippy::option_env_unwrap)] + write!(&mut version, " ({} {})", sha, option_env!("VERGEN_GIT_COMMIT_DATE").unwrap()) + .unwrap(); + } + println!("{}", version); +} + +fn forward_patched_extern_arg(args: &mut impl Iterator, cmd: &mut Command) { + cmd.arg("--extern"); // always forward flag, but adjust filename: + let path = args.next().expect("`--extern` should be followed by a filename"); + if let Some(lib) = path.strip_suffix(".rlib") { + // If this is an rlib, make it an rmeta. + cmd.arg(format!("{}.rmeta", lib)); + } else { + // Some other extern file (e.g. a `.so`). Forward unchanged. + cmd.arg(path); + } +} + +pub fn phase_cargo_miri(mut args: impl Iterator) { + // Check for version and help flags even when invoked as `cargo-miri`. + if has_arg_flag("--help") || has_arg_flag("-h") { + show_help(); + return; + } + if has_arg_flag("--version") || has_arg_flag("-V") { + show_version(); + return; + } + + // Require a subcommand before any flags. + // We cannot know which of those flags take arguments and which do not, + // so we cannot detect subcommands later. + let Some(subcommand) = args.next() else { + show_error(format!("`cargo miri` needs to be called with a subcommand (`run`, `test`)")); + }; + let subcommand = match &*subcommand { + "setup" => MiriCommand::Setup, + "test" | "t" | "run" | "r" | "nextest" => MiriCommand::Forward(subcommand), + _ => + show_error(format!( + "`cargo miri` supports the following subcommands: `run`, `test`, `nextest`, and `setup`." + )), + }; + let verbose = num_arg_flag("-v"); + + // Determine the involved architectures. + let host = version_info().host; + let target = get_arg_flag_value("--target"); + let target = target.as_ref().unwrap_or(&host); + + // We always setup. + setup(&subcommand, &host, target); + + // Invoke actual cargo for the job, but with different flags. + // We re-use `cargo test` and `cargo run`, which makes target and binary handling very easy but + // requires some extra work to make the build check-only (see all the `--emit` hacks below). + // describes an alternative + // approach that uses `cargo check`, making that part easier but target and binary handling + // harder. + let cargo_miri_path = std::env::current_exe() + .expect("current executable path invalid") + .into_os_string() + .into_string() + .expect("current executable path is not valid UTF-8"); + let cargo_cmd = match subcommand { + MiriCommand::Forward(s) => s, + MiriCommand::Setup => return, // `cargo miri setup` stops here. + }; + let metadata = get_cargo_metadata(); + let mut cmd = cargo(); + cmd.arg(cargo_cmd); + + // Forward all arguments before `--` other than `--target-dir` and its value to Cargo. + let mut target_dir = None; + for arg in ArgSplitFlagValue::new(&mut args, "--target-dir") { + match arg { + Ok(value) => { + if target_dir.is_some() { + show_error(format!("`--target-dir` is provided more than once")); + } + target_dir = Some(value.into()); + } + Err(arg) => { + cmd.arg(arg); + } + } + } + // Detect the target directory if it's not specified via `--target-dir`. + let target_dir = target_dir.get_or_insert_with(|| metadata.target_directory.clone()); + // Set `--target-dir` to `miri` inside the original target directory. + target_dir.push("miri"); + cmd.arg("--target-dir").arg(target_dir); + + // Make sure the build target is explicitly set. + // This is needed to make the `target.runner` settings do something, + // and it later helps us detect which crates are proc-macro/build-script + // (host crates) and which crates are needed for the program itself. + if get_arg_flag_value("--target").is_none() { + // No target given. Explicitly pick the host. + cmd.arg("--target"); + cmd.arg(&host); + } + + // Set ourselves as runner for al binaries invoked by cargo. + // We use `all()` since `true` is not a thing in cfg-lang, but the empty conjunction is. :) + let cargo_miri_path_for_toml = escape_for_toml(&cargo_miri_path); + cmd.arg("--config") + .arg(format!("target.'cfg(all())'.runner=[{cargo_miri_path_for_toml}, 'runner']")); + + // Forward all further arguments after `--` to cargo. + cmd.arg("--").args(args); + + // Set `RUSTC_WRAPPER` to ourselves. Cargo will prepend that binary to its usual invocation, + // i.e., the first argument is `rustc` -- which is what we use in `main` to distinguish + // the two codepaths. (That extra argument is why we prefer this over setting `RUSTC`.) + if env::var_os("RUSTC_WRAPPER").is_some() { + println!( + "WARNING: Ignoring `RUSTC_WRAPPER` environment variable, Miri does not support wrapping." + ); + } + cmd.env("RUSTC_WRAPPER", &cargo_miri_path); + // We are going to invoke `MIRI` for everything, not `RUSTC`. + if env::var_os("RUSTC").is_some() && env::var_os("MIRI").is_none() { + println!( + "WARNING: Ignoring `RUSTC` environment variable; set `MIRI` if you want to control the binary used as the driver." + ); + } + // Build scripts (and also cargo: https://github.com/rust-lang/cargo/issues/10885) will invoke + // `rustc` even when `RUSTC_WRAPPER` is set. To make sure everything is coherent, we want that + // to be the Miri driver, but acting as rustc, on the target level. (Target, rather than host, + // is needed for cross-interpretation situations.) This is not a perfect emulation of real rustc + // (it might be unable to produce binaries since the sysroot is check-only), but it's as close + // as we can get, and it's good enough for autocfg. + // + // In `main`, we need the value of `RUSTC` to distinguish RUSTC_WRAPPER invocations from rustdoc + // or TARGET_RUNNER invocations, so we canonicalize it here to make it exceedingly unlikely that + // there would be a collision with other invocations of cargo-miri (as rustdoc or as runner). We + // explicitly do this even if RUSTC_STAGE is set, since for these builds we do *not* want the + // bootstrap `rustc` thing in our way! Instead, we have MIRI_HOST_SYSROOT to use for host + // builds. + cmd.env("RUSTC", &fs::canonicalize(find_miri()).unwrap()); + cmd.env("MIRI_BE_RUSTC", "target"); // we better remember to *unset* this in the other phases! + + // Set rustdoc to us as well, so we can run doctests. + cmd.env("RUSTDOC", &cargo_miri_path); + + cmd.env("MIRI_LOCAL_CRATES", local_crates(&metadata)); + if verbose > 0 { + cmd.env("MIRI_VERBOSE", verbose.to_string()); // This makes the other phases verbose. + } + + // Run cargo. + debug_cmd("[cargo-miri miri]", verbose, &cmd); + exec(cmd) +} + +#[derive(Debug, Copy, Clone, PartialEq)] +pub enum RustcPhase { + /// `rustc` called via `xargo` for sysroot build. + Setup, + /// `rustc` called by `cargo` for regular build. + Build, + /// `rustc` called by `rustdoc` for doctest. + Rustdoc, +} + +pub fn phase_rustc(mut args: impl Iterator, phase: RustcPhase) { + /// Determines if we are being invoked (as rustc) to build a crate for + /// the "target" architecture, in contrast to the "host" architecture. + /// Host crates are for build scripts and proc macros and still need to + /// be built like normal; target crates need to be built for or interpreted + /// by Miri. + /// + /// Currently, we detect this by checking for "--target=", which is + /// never set for host crates. This matches what rustc bootstrap does, + /// which hopefully makes it "reliable enough". This relies on us always + /// invoking cargo itself with `--target`, which `in_cargo_miri` ensures. + fn is_target_crate() -> bool { + get_arg_flag_value("--target").is_some() + } + + /// Returns whether or not Cargo invoked the wrapper (this binary) to compile + /// the final, binary crate (either a test for 'cargo test', or a binary for 'cargo run') + /// Cargo does not give us this information directly, so we need to check + /// various command-line flags. + fn is_runnable_crate() -> bool { + let is_bin = get_arg_flag_value("--crate-type").as_deref().unwrap_or("bin") == "bin"; + let is_test = has_arg_flag("--test"); + is_bin || is_test + } + + fn out_filename(prefix: &str, suffix: &str) -> PathBuf { + if let Some(out_dir) = get_arg_flag_value("--out-dir") { + let mut path = PathBuf::from(out_dir); + path.push(format!( + "{}{}{}{}", + prefix, + get_arg_flag_value("--crate-name").unwrap(), + // This is technically a `-C` flag but the prefix seems unique enough... + // (and cargo passes this before the filename so it should be unique) + get_arg_flag_value("extra-filename").unwrap_or_default(), + suffix, + )); + path + } else { + let out_file = get_arg_flag_value("-o").unwrap(); + PathBuf::from(out_file) + } + } + + // phase_cargo_miri set `MIRI_BE_RUSTC` for when build scripts directly invoke the driver; + // however, if we get called back by cargo here, we'll carefully compute the right flags + // ourselves, so we first un-do what the earlier phase did. + env::remove_var("MIRI_BE_RUSTC"); + + let verbose = std::env::var("MIRI_VERBOSE") + .map_or(0, |verbose| verbose.parse().expect("verbosity flag must be an integer")); + let target_crate = is_target_crate(); + // Determine whether this is cargo/xargo invoking rustc to get some infos. + let info_query = get_arg_flag_value("--print").is_some() || has_arg_flag("-vV"); + + let store_json = |info: CrateRunInfo| { + // Create a stub .d file to stop Cargo from "rebuilding" the crate: + // https://github.com/rust-lang/miri/issues/1724#issuecomment-787115693 + // As we store a JSON file instead of building the crate here, an empty file is fine. + let dep_info_name = out_filename("", ".d"); + if verbose > 0 { + eprintln!("[cargo-miri rustc] writing stub dep-info to `{}`", dep_info_name.display()); + } + File::create(dep_info_name).expect("failed to create fake .d file"); + + let filename = out_filename("", ""); + if verbose > 0 { + eprintln!("[cargo-miri rustc] writing run info to `{}`", filename.display()); + } + info.store(&filename); + // For Windows, do the same thing again with `.exe` appended to the filename. + // (Need to do this here as cargo moves that "binary" to a different place before running it.) + info.store(&out_filename("", ".exe")); + }; + + let runnable_crate = !info_query && is_runnable_crate(); + + if runnable_crate && target_crate { + assert!( + phase != RustcPhase::Setup, + "there should be no interpretation during sysroot build" + ); + let inside_rustdoc = phase == RustcPhase::Rustdoc; + // This is the binary or test crate that we want to interpret under Miri. + // But we cannot run it here, as cargo invoked us as a compiler -- our stdin and stdout are not + // like we want them. + // Instead of compiling, we write JSON into the output file with all the relevant command-line flags + // and environment variables; this is used when cargo calls us again in the CARGO_TARGET_RUNNER phase. + let env = CrateRunEnv::collect(args, inside_rustdoc); + + store_json(CrateRunInfo::RunWith(env.clone())); + + // Rustdoc expects us to exit with an error code if the test is marked as `compile_fail`, + // just creating the JSON file is not enough: we need to detect syntax errors, + // so we need to run Miri with `MIRI_BE_RUSTC` for a check-only build. + if inside_rustdoc { + let mut cmd = miri(); + + // Ensure --emit argument for a check-only build is present. + // We cannot use the usual helpers since we need to check specifically in `env.args`. + if let Some(i) = env.args.iter().position(|arg| arg.starts_with("--emit=")) { + // For `no_run` tests, rustdoc passes a `--emit` flag; make sure it has the right shape. + assert_eq!(env.args[i], "--emit=metadata"); + } else { + // For all other kinds of tests, we can just add our flag. + cmd.arg("--emit=metadata"); + } + + // Alter the `-o` parameter so that it does not overwrite the JSON file we stored above. + let mut args = env.args.clone(); + for i in 0..args.len() { + if args[i] == "-o" { + args[i + 1].push_str(".miri"); + } + } + + cmd.args(&args); + cmd.env("MIRI_BE_RUSTC", "target"); + + if verbose > 0 { + eprintln!( + "[cargo-miri rustc inside rustdoc] captured input:\n{}", + std::str::from_utf8(&env.stdin).unwrap() + ); + eprintln!("[cargo-miri rustc inside rustdoc] going to run:\n{:?}", cmd); + } + + exec_with_pipe(cmd, &env.stdin, format!("{}.stdin", out_filename("", "").display())); + } + + return; + } + + if runnable_crate && ArgFlagValueIter::new("--extern").any(|krate| krate == "proc_macro") { + // This is a "runnable" `proc-macro` crate (unit tests). We do not support + // interpreting that under Miri now, so we write a JSON file to (display a + // helpful message and) skip it in the runner phase. + store_json(CrateRunInfo::SkipProcMacroTest); + return; + } + + let mut cmd = miri(); + let mut emit_link_hack = false; + // Arguments are treated very differently depending on whether this crate is + // for interpretation by Miri, or for use by a build script / proc macro. + if !info_query && target_crate { + // Forward arguments, but remove "link" from "--emit" to make this a check-only build. + let emit_flag = "--emit"; + while let Some(arg) = args.next() { + if let Some(val) = arg.strip_prefix(emit_flag) { + // Patch this argument. First, extract its value. + let val = + val.strip_prefix('=').expect("`cargo` should pass `--emit=X` as one argument"); + let mut val: Vec<_> = val.split(',').collect(); + // Now make sure "link" is not in there, but "metadata" is. + if let Some(i) = val.iter().position(|&s| s == "link") { + emit_link_hack = true; + val.remove(i); + if !val.iter().any(|&s| s == "metadata") { + val.push("metadata"); + } + } + cmd.arg(format!("{}={}", emit_flag, val.join(","))); + } else if arg == "--extern" { + // Patch `--extern` filenames, since Cargo sometimes passes stub `.rlib` files: + // https://github.com/rust-lang/miri/issues/1705 + forward_patched_extern_arg(&mut args, &mut cmd); + } else { + cmd.arg(arg); + } + } + + // During setup, patch the panic runtime for `libpanic_abort` (mirroring what bootstrap usually does). + if phase == RustcPhase::Setup + && get_arg_flag_value("--crate-name").as_deref() == Some("panic_abort") + { + cmd.arg("-C").arg("panic=abort"); + } + } else { + // For host crates (but not when we are just printing some info), + // we might still have to set the sysroot. + if !info_query { + // When we're running `cargo-miri` from `x.py` we need to pass the sysroot explicitly + // due to bootstrap complications. + if let Some(sysroot) = std::env::var_os("MIRI_HOST_SYSROOT") { + cmd.arg("--sysroot").arg(sysroot); + } + } + + // For host crates or when we are printing, just forward everything. + cmd.args(args); + } + + // We want to compile, not interpret. We still use Miri to make sure the compiler version etc + // are the exact same as what is used for interpretation. + // MIRI_DEFAULT_ARGS should not be used to build host crates, hence setting "target" or "host" + // as the value here to help Miri differentiate them. + cmd.env("MIRI_BE_RUSTC", if target_crate { "target" } else { "host" }); + + // Run it. + if verbose > 0 { + eprintln!( + "[cargo-miri rustc] target_crate={target_crate} runnable_crate={runnable_crate} info_query={info_query}" + ); + } + + // Create a stub .rlib file if "link" was requested by cargo. + // This is necessary to prevent cargo from doing rebuilds all the time. + if emit_link_hack { + // Some platforms prepend "lib", some do not... let's just create both files. + File::create(out_filename("lib", ".rlib")).expect("failed to create fake .rlib file"); + File::create(out_filename("", ".rlib")).expect("failed to create fake .rlib file"); + // Just in case this is a cdylib or staticlib, also create those fake files. + File::create(out_filename("lib", ".so")).expect("failed to create fake .so file"); + File::create(out_filename("lib", ".a")).expect("failed to create fake .a file"); + File::create(out_filename("lib", ".dylib")).expect("failed to create fake .dylib file"); + File::create(out_filename("", ".dll")).expect("failed to create fake .dll file"); + File::create(out_filename("", ".lib")).expect("failed to create fake .lib file"); + } + + debug_cmd("[cargo-miri rustc]", verbose, &cmd); + exec(cmd); +} + +#[derive(Debug, Copy, Clone, PartialEq)] +pub enum RunnerPhase { + /// `cargo` is running a binary + Cargo, + /// `rustdoc` is running a binary + Rustdoc, +} + +pub fn phase_runner(mut binary_args: impl Iterator, phase: RunnerPhase) { + // phase_cargo_miri set `MIRI_BE_RUSTC` for when build scripts directly invoke the driver; + // however, if we get called back by cargo here, we'll carefully compute the right flags + // ourselves, so we first un-do what the earlier phase did. + env::remove_var("MIRI_BE_RUSTC"); + + let verbose = std::env::var("MIRI_VERBOSE") + .map_or(0, |verbose| verbose.parse().expect("verbosity flag must be an integer")); + + let binary = binary_args.next().unwrap(); + let file = File::open(&binary) + .unwrap_or_else(|_| show_error(format!( + "file {:?} not found or `cargo-miri` invoked incorrectly; please only invoke this binary through `cargo miri`", binary + ))); + let file = BufReader::new(file); + + let info = serde_json::from_reader(file).unwrap_or_else(|_| { + show_error(format!( + "file {:?} contains outdated or invalid JSON; try `cargo clean`", + binary + )) + }); + let info = match info { + CrateRunInfo::RunWith(info) => info, + CrateRunInfo::SkipProcMacroTest => { + eprintln!( + "Running unit tests of `proc-macro` crates is not currently supported by Miri." + ); + return; + } + }; + + let mut cmd = miri(); + + // Set missing env vars. We prefer build-time env vars over run-time ones; see + // for the kind of issue that fixes. + for (name, val) in info.env { + if let Some(old_val) = env::var_os(&name) { + if old_val == val { + // This one did not actually change, no need to re-set it. + // (This keeps the `debug_cmd` below more manageable.) + continue; + } else if verbose > 0 { + eprintln!( + "[cargo-miri runner] Overwriting run-time env var {:?}={:?} with build-time value {:?}", + name, old_val, val + ); + } + } + cmd.env(name, val); + } + + // Forward rustc arguments. + // We need to patch "--extern" filenames because we forced a check-only + // build without cargo knowing about that: replace `.rlib` suffix by + // `.rmeta`. + // We also need to remove `--error-format` as cargo specifies that to be JSON, + // but when we run here, cargo does not interpret the JSON any more. `--json` + // then also nees to be dropped. + let mut args = info.args.into_iter(); + let error_format_flag = "--error-format"; + let json_flag = "--json"; + while let Some(arg) = args.next() { + if arg == "--extern" { + forward_patched_extern_arg(&mut args, &mut cmd); + } else if let Some(suffix) = arg.strip_prefix(error_format_flag) { + assert!(suffix.starts_with('=')); + // Drop this argument. + } else if let Some(suffix) = arg.strip_prefix(json_flag) { + assert!(suffix.starts_with('=')); + // Drop this argument. + } else { + cmd.arg(arg); + } + } + // Respect `MIRIFLAGS`. + if let Ok(a) = env::var("MIRIFLAGS") { + // This code is taken from `RUSTFLAGS` handling in cargo. + let args = a.split(' ').map(str::trim).filter(|s| !s.is_empty()).map(str::to_string); + cmd.args(args); + } + + // Then pass binary arguments. + cmd.arg("--"); + cmd.args(binary_args); + + // Make sure we use the build-time working directory for interpreting Miri/rustc arguments. + // But then we need to switch to the run-time one, which we instruct Miri do do by setting `MIRI_CWD`. + cmd.current_dir(info.current_dir); + cmd.env("MIRI_CWD", env::current_dir().unwrap()); + + // Run it. + debug_cmd("[cargo-miri runner]", verbose, &cmd); + match phase { + RunnerPhase::Rustdoc => exec_with_pipe(cmd, &info.stdin, format!("{}.stdin", binary)), + RunnerPhase::Cargo => exec(cmd), + } +} + +pub fn phase_rustdoc(mut args: impl Iterator) { + let verbose = std::env::var("MIRI_VERBOSE") + .map_or(0, |verbose| verbose.parse().expect("verbosity flag must be an integer")); + + // phase_cargo_miri sets the RUSTDOC env var to ourselves, so we can't use that here; + // just default to a straight-forward invocation for now: + let mut cmd = Command::new("rustdoc"); + + let extern_flag = "--extern"; + let runtool_flag = "--runtool"; + while let Some(arg) = args.next() { + if arg == extern_flag { + // Patch --extern arguments to use *.rmeta files, since phase_cargo_rustc only creates stub *.rlib files. + forward_patched_extern_arg(&mut args, &mut cmd); + } else if arg == runtool_flag { + // An existing --runtool flag indicates cargo is running in cross-target mode, which we don't support. + // Note that this is only passed when cargo is run with the unstable -Zdoctest-xcompile flag; + // otherwise, we won't be called as rustdoc at all. + show_error(format!("cross-interpreting doctests is not currently supported by Miri.")); + } else { + cmd.arg(arg); + } + } + + // Doctests of `proc-macro` crates (and their dependencies) are always built for the host, + // so we are not able to run them in Miri. + if ArgFlagValueIter::new("--crate-type").any(|crate_type| crate_type == "proc-macro") { + eprintln!("Running doctests of `proc-macro` crates is not currently supported by Miri."); + return; + } + + // For each doctest, rustdoc starts two child processes: first the test is compiled, + // then the produced executable is invoked. We want to reroute both of these to cargo-miri, + // such that the first time we'll enter phase_cargo_rustc, and phase_cargo_runner second. + // + // rustdoc invokes the test-builder by forwarding most of its own arguments, which makes + // it difficult to determine when phase_cargo_rustc should run instead of phase_cargo_rustdoc. + // Furthermore, the test code is passed via stdin, rather than a temporary file, so we need + // to let phase_cargo_rustc know to expect that. We'll use this environment variable as a flag: + cmd.env("MIRI_CALLED_FROM_RUSTDOC", "1"); + + // The `--test-builder` and `--runtool` arguments are unstable rustdoc features, + // which are disabled by default. We first need to enable them explicitly: + cmd.arg("-Z").arg("unstable-options"); + + // rustdoc needs to know the right sysroot. + cmd.arg("--sysroot").arg(env::var_os("MIRI_SYSROOT").unwrap()); + // make sure the 'miri' flag is set for rustdoc + cmd.arg("--cfg").arg("miri"); + + // Make rustdoc call us back. + let cargo_miri_path = std::env::current_exe().expect("current executable path invalid"); + cmd.arg("--test-builder").arg(&cargo_miri_path); // invoked by forwarding most arguments + cmd.arg("--runtool").arg(&cargo_miri_path); // invoked with just a single path argument + + debug_cmd("[cargo-miri rustdoc]", verbose, &cmd); + exec(cmd) +} diff --git a/cargo-miri/src/setup.rs b/cargo-miri/src/setup.rs new file mode 100644 index 0000000000000..1211b47e3ba24 --- /dev/null +++ b/cargo-miri/src/setup.rs @@ -0,0 +1,247 @@ +//! Implements `cargo miri setup` via xargo + +use std::env; +use std::ffi::OsStr; +use std::fs::{self}; +use std::io::BufRead; +use std::ops::Not; +use std::path::{Path, PathBuf}; +use std::process::{self, Command}; + +use crate::{util::*, version::*}; + +fn xargo_version() -> Option<(u32, u32, u32)> { + let out = xargo_check().arg("--version").output().ok()?; + if !out.status.success() { + return None; + } + // Parse output. The first line looks like "xargo 0.3.12 (b004f1c 2018-12-13)". + let line = out + .stderr + .lines() + .next() + .expect("malformed `xargo --version` output: not at least one line") + .expect("malformed `xargo --version` output: error reading first line"); + let (name, version) = { + let mut split = line.split(' '); + ( + split.next().expect("malformed `xargo --version` output: empty"), + split.next().expect("malformed `xargo --version` output: not at least two words"), + ) + }; + if name != "xargo" { + // This is some fork of xargo + return None; + } + let mut version_pieces = version.split('.'); + let major = version_pieces + .next() + .expect("malformed `xargo --version` output: not a major version piece") + .parse() + .expect("malformed `xargo --version` output: major version is not an integer"); + let minor = version_pieces + .next() + .expect("malformed `xargo --version` output: not a minor version piece") + .parse() + .expect("malformed `xargo --version` output: minor version is not an integer"); + let patch = version_pieces + .next() + .expect("malformed `xargo --version` output: not a patch version piece") + .parse() + .expect("malformed `xargo --version` output: patch version is not an integer"); + if version_pieces.next().is_some() { + panic!("malformed `xargo --version` output: more than three pieces in version"); + } + Some((major, minor, patch)) +} + +/// Performs the setup required to make `cargo miri` work: Getting a custom-built libstd. Then sets +/// `MIRI_SYSROOT`. Skipped if `MIRI_SYSROOT` is already set, in which case we expect the user has +/// done all this already. +pub fn setup(subcommand: &MiriCommand, host: &str, target: &str) { + let only_setup = matches!(subcommand, MiriCommand::Setup); + let ask_user = !only_setup; + let print_sysroot = only_setup && has_arg_flag("--print-sysroot"); // whether we just print the sysroot path + if std::env::var_os("MIRI_SYSROOT").is_some() { + if only_setup { + println!("WARNING: MIRI_SYSROOT already set, not doing anything.") + } + return; + } + + // First, we need xargo. + if xargo_version().map_or(true, |v| v < XARGO_MIN_VERSION) { + if std::env::var_os("XARGO_CHECK").is_some() { + // The user manually gave us a xargo binary; don't do anything automatically. + show_error(format!("xargo is too old; please upgrade to the latest version")) + } + let mut cmd = cargo(); + cmd.args(&["install", "xargo"]); + ask_to_run(cmd, ask_user, "install a recent enough xargo"); + } + + // Determine where the rust sources are located. The env vars manually setting the source + // (`MIRI_LIB_SRC`, `XARGO_RUST_SRC`) trump auto-detection. + let rust_src_env_var = + std::env::var_os("MIRI_LIB_SRC").or_else(|| std::env::var_os("XARGO_RUST_SRC")); + let rust_src = match rust_src_env_var { + Some(path) => { + let path = PathBuf::from(path); + // Make path absolute if possible. + path.canonicalize().unwrap_or(path) + } + None => { + // Check for `rust-src` rustup component. + let output = miri_for_host() + .args(&["--print", "sysroot"]) + .output() + .expect("failed to determine sysroot"); + if !output.status.success() { + show_error(format!( + "Failed to determine sysroot; Miri said:\n{}", + String::from_utf8_lossy(&output.stderr).trim_end() + )); + } + let sysroot = std::str::from_utf8(&output.stdout).unwrap(); + let sysroot = Path::new(sysroot.trim_end_matches('\n')); + // Check for `$SYSROOT/lib/rustlib/src/rust/library`; test if that contains `std/Cargo.toml`. + let rustup_src = + sysroot.join("lib").join("rustlib").join("src").join("rust").join("library"); + if !rustup_src.join("std").join("Cargo.toml").exists() { + // Ask the user to install the `rust-src` component, and use that. + let mut cmd = Command::new("rustup"); + cmd.args(&["component", "add", "rust-src"]); + ask_to_run( + cmd, + ask_user, + "install the `rust-src` component for the selected toolchain", + ); + } + rustup_src + } + }; + if !rust_src.exists() { + show_error(format!("given Rust source directory `{}` does not exist.", rust_src.display())); + } + if rust_src.file_name().and_then(OsStr::to_str) != Some("library") { + show_error(format!( + "given Rust source directory `{}` does not seem to be the `library` subdirectory of \ + a Rust source checkout.", + rust_src.display() + )); + } + + // Next, we need our own libstd. Prepare a xargo project for that purpose. + // We will do this work in whatever is a good cache dir for this platform. + let dirs = directories::ProjectDirs::from("org", "rust-lang", "miri").unwrap(); + let dir = dirs.cache_dir(); + if !dir.exists() { + fs::create_dir_all(&dir).unwrap(); + } + // The interesting bit: Xargo.toml (only needs content if we actually need std) + let xargo_toml = if std::env::var_os("MIRI_NO_STD").is_some() { + "" + } else { + r#" +[dependencies.std] +default_features = false +# We support unwinding, so enable that panic runtime. +features = ["panic_unwind", "backtrace"] + +[dependencies.test] +"# + }; + write_to_file(&dir.join("Xargo.toml"), xargo_toml); + // The boring bits: a dummy project for xargo. + // FIXME: With xargo-check, can we avoid doing this? + write_to_file( + &dir.join("Cargo.toml"), + r#" +[package] +name = "miri-xargo" +description = "A dummy project for building libstd with xargo." +version = "0.0.0" + +[lib] +path = "lib.rs" +"#, + ); + write_to_file(&dir.join("lib.rs"), "#![no_std]"); + + // Figure out where xargo will build its stuff. + // Unfortunately, it puts things into a different directory when the + // architecture matches the host. + let sysroot = if target == host { dir.join("HOST") } else { PathBuf::from(dir) }; + // Make sure all target-level Miri invocations know their sysroot. + std::env::set_var("MIRI_SYSROOT", &sysroot); + + // Now invoke xargo. + let mut command = xargo_check(); + command.arg("check").arg("-q"); + command.current_dir(&dir); + command.env("XARGO_HOME", &dir); + command.env("XARGO_RUST_SRC", &rust_src); + // We always need to set a target so rustc bootstrap can tell apart host from target crates. + command.arg("--target").arg(target); + // Use Miri as rustc to build a libstd compatible with us (and use the right flags). + // However, when we are running in bootstrap, we cannot just overwrite `RUSTC`, + // because we still need bootstrap to distinguish between host and target crates. + // In that case we overwrite `RUSTC_REAL` instead which determines the rustc used + // for target crates. + // We set ourselves (`cargo-miri`) instead of Miri directly to be able to patch the flags + // for `libpanic_abort` (usually this is done by bootstrap but we have to do it ourselves). + // The `MIRI_CALLED_FROM_XARGO` will mean we dispatch to `phase_setup_rustc`. + let cargo_miri_path = std::env::current_exe().expect("current executable path invalid"); + if env::var_os("RUSTC_STAGE").is_some() { + assert!(env::var_os("RUSTC").is_some()); + command.env("RUSTC_REAL", &cargo_miri_path); + } else { + command.env("RUSTC", &cargo_miri_path); + } + command.env("MIRI_CALLED_FROM_XARGO", "1"); + // Make sure there are no other wrappers getting in our way + // (Cc https://github.com/rust-lang/miri/issues/1421, https://github.com/rust-lang/miri/issues/2429). + // Looks like setting `RUSTC_WRAPPER` to the empty string overwrites `build.rustc-wrapper` set via `config.toml`. + command.env("RUSTC_WRAPPER", ""); + // Disable debug assertions in the standard library -- Miri is already slow enough. But keep the + // overflow checks, they are cheap. This completely overwrites flags the user might have set, + // which is consistent with normal `cargo build` that does not apply `RUSTFLAGS` to the sysroot + // either. + command.env("RUSTFLAGS", "-Cdebug-assertions=off -Coverflow-checks=on"); + // Manage the output the user sees. + if only_setup { + // We want to be explicit. + eprintln!("Preparing a sysroot for Miri (target: {target})..."); + if print_sysroot { + // Be extra sure there is no noise on stdout. + command.stdout(process::Stdio::null()); + } + } else { + // We want to be quiet, but still let the user know that something is happening. + eprint!("Preparing a sysroot for Miri (target: {target})... "); + command.stdout(process::Stdio::null()); + command.stderr(process::Stdio::null()); + } + + // Finally run it! + if command.status().expect("failed to run xargo").success().not() { + if only_setup { + show_error(format!("failed to run xargo, see error details above")) + } else { + show_error(format!( + "failed to run xargo; run `cargo miri setup` to see the error details" + )) + } + } + + // Figure out what to print. + if only_setup { + eprintln!("A sysroot for Miri is now available in `{}`.", sysroot.display()); + } else { + eprintln!("done"); + } + if print_sysroot { + // Print just the sysroot and nothing else to stdout; this way we do not need any escaping. + println!("{}", sysroot.display()); + } +} diff --git a/cargo-miri/src/util.rs b/cargo-miri/src/util.rs new file mode 100644 index 0000000000000..d6a42a2f855dc --- /dev/null +++ b/cargo-miri/src/util.rs @@ -0,0 +1,375 @@ +use std::collections::HashMap; +use std::env; +use std::ffi::OsString; +use std::fmt::Write as _; +use std::fs::{self, File}; +use std::io::{self, BufWriter, Read, Write}; +use std::iter::TakeWhile; +use std::ops::Not; +use std::path::{Path, PathBuf}; +use std::process::Command; + +use cargo_metadata::{Metadata, MetadataCommand}; +use rustc_version::VersionMeta; +use serde::{Deserialize, Serialize}; + +/// The information to run a crate with the given environment. +#[derive(Clone, Serialize, Deserialize)] +pub struct CrateRunEnv { + /// The command-line arguments. + pub args: Vec, + /// The environment. + pub env: Vec<(OsString, OsString)>, + /// The current working directory. + pub current_dir: OsString, + /// The contents passed via standard input. + pub stdin: Vec, +} + +impl CrateRunEnv { + /// Gather all the information we need. + pub fn collect(args: impl Iterator, capture_stdin: bool) -> Self { + let args = args.collect(); + let env = env::vars_os().collect(); + let current_dir = env::current_dir().unwrap().into_os_string(); + + let mut stdin = Vec::new(); + if capture_stdin { + std::io::stdin().lock().read_to_end(&mut stdin).expect("cannot read stdin"); + } + + CrateRunEnv { args, env, current_dir, stdin } + } +} + +/// The information Miri needs to run a crate. Stored as JSON when the crate is "compiled". +#[derive(Serialize, Deserialize)] +pub enum CrateRunInfo { + /// Run it with the given environment. + RunWith(CrateRunEnv), + /// Skip it as Miri does not support interpreting such kind of crates. + SkipProcMacroTest, +} + +impl CrateRunInfo { + pub fn store(&self, filename: &Path) { + let file = File::create(filename) + .unwrap_or_else(|_| show_error(format!("cannot create `{}`", filename.display()))); + let file = BufWriter::new(file); + serde_json::ser::to_writer(file, self) + .unwrap_or_else(|_| show_error(format!("cannot write to `{}`", filename.display()))); + } +} + +#[derive(Clone, Debug)] +pub enum MiriCommand { + /// Our own special 'setup' command. + Setup, + /// A command to be forwarded to cargo. + Forward(String), +} + +pub fn show_error(msg: String) -> ! { + eprintln!("fatal error: {}", msg); + std::process::exit(1) +} + +/// Determines whether a `--flag` is present. +pub fn has_arg_flag(name: &str) -> bool { + num_arg_flag(name) > 0 +} + +/// Determines how many times a `--flag` is present. +pub fn num_arg_flag(name: &str) -> usize { + std::env::args().take_while(|val| val != "--").filter(|val| val == name).count() +} + +/// Yields all values of command line flag `name` as `Ok(arg)`, and all other arguments except +/// the flag as `Err(arg)`. (The flag `name` itself is not yielded at all, only its values are.) +pub struct ArgSplitFlagValue<'a, I> { + args: TakeWhile bool>, + name: &'a str, +} + +impl<'a, I: Iterator> ArgSplitFlagValue<'a, I> { + pub fn new(args: I, name: &'a str) -> Self { + Self { + // Stop searching at `--`. + args: args.take_while(|val| val != "--"), + name, + } + } +} + +impl> Iterator for ArgSplitFlagValue<'_, I> { + type Item = Result; + + fn next(&mut self) -> Option { + let arg = self.args.next()?; + if let Some(suffix) = arg.strip_prefix(self.name) { + // Strip leading `name`. + if suffix.is_empty() { + // This argument is exactly `name`; the next one is the value. + return self.args.next().map(Ok); + } else if let Some(suffix) = suffix.strip_prefix('=') { + // This argument is `name=value`; get the value. + return Some(Ok(suffix.to_owned())); + } + } + Some(Err(arg)) + } +} + +/// Yields all values of command line flag `name`. +pub struct ArgFlagValueIter<'a>(ArgSplitFlagValue<'a, env::Args>); + +impl<'a> ArgFlagValueIter<'a> { + pub fn new(name: &'a str) -> Self { + Self(ArgSplitFlagValue::new(env::args(), name)) + } +} + +impl Iterator for ArgFlagValueIter<'_> { + type Item = String; + + fn next(&mut self) -> Option { + loop { + if let Ok(value) = self.0.next()? { + return Some(value); + } + } + } +} + +/// Gets the value of a `--flag`. +pub fn get_arg_flag_value(name: &str) -> Option { + ArgFlagValueIter::new(name).next() +} + +/// Escapes `s` in a way that is suitable for using it as a string literal in TOML syntax. +pub fn escape_for_toml(s: &str) -> String { + // We want to surround this string in quotes `"`. So we first escape all quotes, + // and also all backslashes (that are used to escape quotes). + let s = s.replace('\\', r#"\\"#).replace('"', r#"\""#); + format!("\"{}\"", s) +} + +/// Returns the path to the `miri` binary +pub fn find_miri() -> PathBuf { + if let Some(path) = env::var_os("MIRI") { + return path.into(); + } + let mut path = std::env::current_exe().expect("current executable path invalid"); + if cfg!(windows) { + path.set_file_name("miri.exe"); + } else { + path.set_file_name("miri"); + } + path +} + +pub fn miri() -> Command { + Command::new(find_miri()) +} + +pub fn miri_for_host() -> Command { + let mut cmd = miri(); + cmd.env("MIRI_BE_RUSTC", "host"); + cmd +} + +pub fn version_info() -> VersionMeta { + VersionMeta::for_command(miri_for_host()) + .expect("failed to determine underlying rustc version of Miri") +} + +pub fn cargo() -> Command { + Command::new(env::var_os("CARGO").unwrap_or_else(|| OsString::from("cargo"))) +} + +pub fn xargo_check() -> Command { + Command::new(env::var_os("XARGO_CHECK").unwrap_or_else(|| OsString::from("xargo-check"))) +} + +/// Execute the `Command`, where possible by replacing the current process with a new process +/// described by the `Command`. Then exit this process with the exit code of the new process. +pub fn exec(mut cmd: Command) -> ! { + // On non-Unix imitate POSIX exec as closely as we can + #[cfg(not(unix))] + { + let exit_status = cmd.status().expect("failed to run command"); + std::process::exit(exit_status.code().unwrap_or(-1)) + } + // On Unix targets, actually exec. + // If exec returns, process setup has failed. This is the same error condition as the expect in + // the non-Unix case. + #[cfg(unix)] + { + use std::os::unix::process::CommandExt; + let error = cmd.exec(); + Err(error).expect("failed to run command") + } +} + +/// Execute the `Command`, where possible by replacing the current process with a new process +/// described by the `Command`. Then exit this process with the exit code of the new process. +/// `input` is also piped to the new process's stdin, on cfg(unix) platforms by writing its +/// contents to `path` first, then setting stdin to that file. +pub fn exec_with_pipe

(mut cmd: Command, input: &[u8], path: P) -> ! +where + P: AsRef, +{ + #[cfg(unix)] + { + // Write the bytes we want to send to stdin out to a file + std::fs::write(&path, input).unwrap(); + // Open the file for reading, and set our new stdin to it + let stdin = File::open(&path).unwrap(); + cmd.stdin(stdin); + // Unlink the file so that it is fully cleaned up as soon as the new process exits + std::fs::remove_file(&path).unwrap(); + // Finally, we can hand off control. + exec(cmd) + } + #[cfg(not(unix))] + { + drop(path); // We don't need the path, we can pipe the bytes directly + cmd.stdin(std::process::Stdio::piped()); + let mut child = cmd.spawn().expect("failed to spawn process"); + { + let stdin = child.stdin.as_mut().expect("failed to open stdin"); + stdin.write_all(input).expect("failed to write out test source"); + } + let exit_status = child.wait().expect("failed to run command"); + std::process::exit(exit_status.code().unwrap_or(-1)) + } +} + +pub fn ask_to_run(mut cmd: Command, ask: bool, text: &str) { + // Disable interactive prompts in CI (GitHub Actions, Travis, AppVeyor, etc). + // Azure doesn't set `CI` though (nothing to see here, just Microsoft being Microsoft), + // so we also check their `TF_BUILD`. + let is_ci = env::var_os("CI").is_some() || env::var_os("TF_BUILD").is_some(); + if ask && !is_ci { + let mut buf = String::new(); + print!("I will run `{:?}` to {}. Proceed? [Y/n] ", cmd, text); + io::stdout().flush().unwrap(); + io::stdin().read_line(&mut buf).unwrap(); + match buf.trim().to_lowercase().as_ref() { + // Proceed. + "" | "y" | "yes" => {} + "n" | "no" => show_error(format!("aborting as per your request")), + a => show_error(format!("invalid answer `{}`", a)), + }; + } else { + eprintln!("Running `{:?}` to {}.", cmd, text); + } + + if cmd.status().unwrap_or_else(|_| panic!("failed to execute {:?}", cmd)).success().not() { + show_error(format!("failed to {}", text)); + } +} + +/// Writes the given content to the given file *cross-process atomically*, in the sense that another +/// process concurrently reading that file will see either the old content or the new content, but +/// not some intermediate (e.g., empty) state. +/// +/// We assume no other parts of this same process are trying to read or write that file. +pub fn write_to_file(filename: &Path, content: &str) { + // Create a temporary file with the desired contents. + let mut temp_filename = filename.as_os_str().to_os_string(); + temp_filename.push(&format!(".{}", std::process::id())); + let mut temp_file = File::create(&temp_filename).unwrap(); + temp_file.write_all(content.as_bytes()).unwrap(); + drop(temp_file); + + // Move file to the desired location. + fs::rename(temp_filename, filename).unwrap(); +} + +pub fn get_cargo_metadata() -> Metadata { + // The `build.target-dir` config can be passed by `--config` flags, so forward them to + // `cargo metadata`. + let mut additional_options = Vec::new(); + // `-Zunstable-options` is required by `--config`. + additional_options.push("-Zunstable-options".to_string()); + + let config_flag = "--config"; + for arg in ArgSplitFlagValue::new( + env::args().skip(3), // skip the program name, "miri" and "run" / "test" + config_flag, + ) + // Only look at `Ok` + .flatten() + { + additional_options.push(config_flag.to_string()); + additional_options.push(arg); + } + + let metadata = + MetadataCommand::new().no_deps().other_options(additional_options).exec().unwrap(); + + metadata +} + +/// Pulls all the crates in this workspace from the cargo metadata. +/// Workspace members are emitted like "miri 0.1.0 (path+file:///path/to/miri)" +/// Additionally, somewhere between cargo metadata and TyCtxt, '-' gets replaced with '_' so we +/// make that same transformation here. +pub fn local_crates(metadata: &Metadata) -> String { + assert!(!metadata.workspace_members.is_empty()); + let mut local_crates = String::new(); + for member in &metadata.workspace_members { + let name = member.repr.split(' ').next().unwrap(); + let name = name.replace('-', "_"); + local_crates.push_str(&name); + local_crates.push(','); + } + local_crates.pop(); // Remove the trailing ',' + + local_crates +} + +fn env_vars_from_cmd(cmd: &Command) -> Vec<(String, String)> { + let mut envs = HashMap::new(); + for (key, value) in std::env::vars() { + envs.insert(key, value); + } + for (key, value) in cmd.get_envs() { + if let Some(value) = value { + envs.insert(key.to_string_lossy().to_string(), value.to_string_lossy().to_string()); + } else { + envs.remove(&key.to_string_lossy().to_string()); + } + } + let mut envs: Vec<_> = envs.into_iter().collect(); + envs.sort(); + envs +} + +/// Debug-print a command that is going to be run. +pub fn debug_cmd(prefix: &str, verbose: usize, cmd: &Command) { + if verbose == 0 { + return; + } + // We only do a single `eprintln!` call to minimize concurrency interactions. + let mut out = prefix.to_string(); + writeln!(out, " running command: env \\").unwrap(); + if verbose > 1 { + // Print the full environment this will be called in. + for (key, value) in env_vars_from_cmd(cmd) { + writeln!(out, "{key}={value:?} \\").unwrap(); + } + } else { + // Print only what has been changed for this `cmd`. + for (var, val) in cmd.get_envs() { + if let Some(val) = val { + writeln!(out, "{}={:?} \\", var.to_string_lossy(), val).unwrap(); + } else { + writeln!(out, "--unset={}", var.to_string_lossy()).unwrap(); + } + } + } + write!(out, "{cmd:?}").unwrap(); + eprintln!("{}", out); +} diff --git a/cargo-miri/version.rs b/cargo-miri/src/version.rs similarity index 100% rename from cargo-miri/version.rs rename to cargo-miri/src/version.rs From 9154f8b22c56c071e78e1f3d706fd75f43ff218c Mon Sep 17 00:00:00 2001 From: Christian Legnitto Date: Wed, 3 Aug 2022 10:39:43 -0400 Subject: [PATCH 3601/3747] Add additional raw error mappings for the nightly `io_error_more` feature Some crates are using nightly and failing when mapping these errors, for example : ``` error: unsupported operation: io error NotADirectory cannot be translated into a raw os error --> /root/.rustup/toolchains/miri/lib/rustlib/src/rust/library/std/src/sys/unix/fs.rs:1203:19 ``` --- src/helpers.rs | 43 +++++++++++++++++++++++++++++++++---------- 1 file changed, 33 insertions(+), 10 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index acc2367afa28d..ee2c39b511540 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -23,26 +23,49 @@ use crate::*; impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} +// This mapping is the reverse of `decode_error_kind` in +// +// and should be kept in sync. const UNIX_IO_ERROR_TABLE: &[(std::io::ErrorKind, &str)] = { use std::io::ErrorKind::*; &[ + (ArgumentListTooLong, "E2BIG"), + (AddrInUse, "EADDRINUSE"), + (AddrNotAvailable, "EADDRNOTAVAIL"), + (ResourceBusy, "EBUSY"), + (ConnectionAborted, "ECONNABORTED"), (ConnectionRefused, "ECONNREFUSED"), (ConnectionReset, "ECONNRESET"), - (PermissionDenied, "EPERM"), - (BrokenPipe, "EPIPE"), - (NotConnected, "ENOTCONN"), - (ConnectionAborted, "ECONNABORTED"), - (AddrNotAvailable, "EADDRNOTAVAIL"), - (AddrInUse, "EADDRINUSE"), - (NotFound, "ENOENT"), + (Deadlock, "EDEADLK"), + (FilesystemQuotaExceeded, "EDQUOT"), + (AlreadyExists, "EEXIST"), + (FileTooLarge, "EFBIG"), + (HostUnreachable, "EHOSTUNREACH"), (Interrupted, "EINTR"), (InvalidInput, "EINVAL"), + (IsADirectory, "EISDIR"), + (FilesystemLoop, "ELOOP"), + (NotFound, "ENOENT"), + (OutOfMemory, "ENOMEM"), + (StorageFull, "ENOSPC"), + (Unsupported, "ENOSYS"), + (TooManyLinks, "EMLINK"), (InvalidFilename, "ENAMETOOLONG"), + (NetworkDown, "ENETDOWN"), + (NetworkUnreachable, "ENETUNREACH"), + (NotConnected, "ENOTCONN"), + (NotADirectory, "ENOTDIR"), + (DirectoryNotEmpty, "ENOTEMPTY"), + (BrokenPipe, "EPIPE"), + (ReadOnlyFilesystem, "EROFS"), + (NotSeekable, "ESPIPE"), + (StaleNetworkFileHandle, "ESTALE"), (TimedOut, "ETIMEDOUT"), - (AlreadyExists, "EEXIST"), + (ExecutableFileBusy, "ETXTBSY"), + (CrossesDevices, "EXDEV"), + // The following have two valid options...we pick one. + (PermissionDenied, "EPERM"), (WouldBlock, "EWOULDBLOCK"), - (DirectoryNotEmpty, "ENOTEMPTY"), - (FilesystemLoop, "ELOOP"), ] }; From e1e1f42f39801c4f9195443fc5f1ac6e8505310e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 3 Aug 2022 11:51:39 -0400 Subject: [PATCH 3602/3747] make errno table syntactically more similar to rustc library code --- src/helpers.rs | 88 ++++++++++++++++++++++++++------------------------ 1 file changed, 45 insertions(+), 43 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index ee2c39b511540..8523af84d0660 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -23,49 +23,51 @@ use crate::*; impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} -// This mapping is the reverse of `decode_error_kind` in -// -// and should be kept in sync. -const UNIX_IO_ERROR_TABLE: &[(std::io::ErrorKind, &str)] = { +// This mapping should match `decode_error_kind` in +// . +const UNIX_IO_ERROR_TABLE: &[(&str, std::io::ErrorKind)] = { use std::io::ErrorKind::*; &[ - (ArgumentListTooLong, "E2BIG"), - (AddrInUse, "EADDRINUSE"), - (AddrNotAvailable, "EADDRNOTAVAIL"), - (ResourceBusy, "EBUSY"), - (ConnectionAborted, "ECONNABORTED"), - (ConnectionRefused, "ECONNREFUSED"), - (ConnectionReset, "ECONNRESET"), - (Deadlock, "EDEADLK"), - (FilesystemQuotaExceeded, "EDQUOT"), - (AlreadyExists, "EEXIST"), - (FileTooLarge, "EFBIG"), - (HostUnreachable, "EHOSTUNREACH"), - (Interrupted, "EINTR"), - (InvalidInput, "EINVAL"), - (IsADirectory, "EISDIR"), - (FilesystemLoop, "ELOOP"), - (NotFound, "ENOENT"), - (OutOfMemory, "ENOMEM"), - (StorageFull, "ENOSPC"), - (Unsupported, "ENOSYS"), - (TooManyLinks, "EMLINK"), - (InvalidFilename, "ENAMETOOLONG"), - (NetworkDown, "ENETDOWN"), - (NetworkUnreachable, "ENETUNREACH"), - (NotConnected, "ENOTCONN"), - (NotADirectory, "ENOTDIR"), - (DirectoryNotEmpty, "ENOTEMPTY"), - (BrokenPipe, "EPIPE"), - (ReadOnlyFilesystem, "EROFS"), - (NotSeekable, "ESPIPE"), - (StaleNetworkFileHandle, "ESTALE"), - (TimedOut, "ETIMEDOUT"), - (ExecutableFileBusy, "ETXTBSY"), - (CrossesDevices, "EXDEV"), - // The following have two valid options...we pick one. - (PermissionDenied, "EPERM"), - (WouldBlock, "EWOULDBLOCK"), + ("E2BIG", ArgumentListTooLong), + ("EADDRINUSE", AddrInUse), + ("EADDRNOTAVAIL", AddrNotAvailable), + ("EBUSY", ResourceBusy), + ("ECONNABORTED", ConnectionAborted), + ("ECONNREFUSED", ConnectionRefused), + ("ECONNRESET", ConnectionReset), + ("EDEADLK", Deadlock), + ("EDQUOT", FilesystemQuotaExceeded), + ("EEXIST", AlreadyExists), + ("EFBIG", FileTooLarge), + ("EHOSTUNREACH", HostUnreachable), + ("EINTR", Interrupted), + ("EINVAL", InvalidInput), + ("EISDIR", IsADirectory), + ("ELOOP", FilesystemLoop), + ("ENOENT", NotFound), + ("ENOMEM", OutOfMemory), + ("ENOSPC", StorageFull), + ("ENOSYS", Unsupported), + ("EMLINK", TooManyLinks), + ("ENAMETOOLONG", InvalidFilename), + ("ENETDOWN", NetworkDown), + ("ENETUNREACH", NetworkUnreachable), + ("ENOTCONN", NotConnected), + ("ENOTDIR", NotADirectory), + ("ENOTEMPTY", DirectoryNotEmpty), + ("EPIPE", BrokenPipe), + ("EROFS", ReadOnlyFilesystem), + ("ESPIPE", NotSeekable), + ("ESTALE", StaleNetworkFileHandle), + ("ETIMEDOUT", TimedOut), + ("ETXTBSY", ExecutableFileBusy), + ("EXDEV", CrossesDevices), + // The following have two valid options. We have both for the forwards mapping; only the + // first one will be used for the backwards mapping. + ("EPERM", PermissionDenied), + ("EACCES", PermissionDenied), + ("EWOULDBLOCK", WouldBlock), + ("EAGAIN", WouldBlock), ] }; @@ -577,7 +579,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_ref(); let target = &this.tcx.sess.target; if target.families.iter().any(|f| f == "unix") { - for &(kind, name) in UNIX_IO_ERROR_TABLE { + for &(name, kind) in UNIX_IO_ERROR_TABLE { if err_kind == kind { return this.eval_libc(name); } @@ -615,7 +617,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let target = &this.tcx.sess.target; if target.families.iter().any(|f| f == "unix") { let errnum = errnum.to_i32()?; - for &(kind, name) in UNIX_IO_ERROR_TABLE { + for &(name, kind) in UNIX_IO_ERROR_TABLE { if errnum == this.eval_libc_i32(name)? { return Ok(kind); } From 6d14a5e2a7c17f1fec43c319cc9317ded44701ea Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 5 Aug 2022 19:21:47 -0400 Subject: [PATCH 3603/3747] avoid strerror_r failure on unknown errnum --- src/helpers.rs | 11 +++++++---- src/shims/unix/foreign_items.rs | 7 +++++-- tests/pass/fs.rs | 10 ++++++++++ 3 files changed, 22 insertions(+), 6 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index 8523af84d0660..220347ff1b968 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -609,20 +609,23 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } /// The inverse of `io_error_to_errnum`. - fn errnum_to_io_error( + #[allow(clippy::needless_return)] + fn try_errnum_to_io_error( &self, errnum: Scalar, - ) -> InterpResult<'tcx, std::io::ErrorKind> { + ) -> InterpResult<'tcx, Option> { let this = self.eval_context_ref(); let target = &this.tcx.sess.target; if target.families.iter().any(|f| f == "unix") { let errnum = errnum.to_i32()?; for &(name, kind) in UNIX_IO_ERROR_TABLE { if errnum == this.eval_libc_i32(name)? { - return Ok(kind); + return Ok(Some(kind)); } } - throw_unsup_format!("raw errnum {:?} cannot be translated into io::Error", errnum) + // Our table is as complete as the mapping in std, so we are okay with saying "that's a + // strange one" here. + return Ok(None); } else { throw_unsup_format!( "converting errnum into io::Error is unsupported for OS {}", diff --git a/src/shims/unix/foreign_items.rs b/src/shims/unix/foreign_items.rs index 83815cccb0c4d..dc80d592a0c1a 100644 --- a/src/shims/unix/foreign_items.rs +++ b/src/shims/unix/foreign_items.rs @@ -465,8 +465,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let buf = this.read_pointer(buf)?; let buflen = this.read_scalar(buflen)?.to_machine_usize(this)?; - let error = this.errnum_to_io_error(errnum)?; - let formatted = error.to_string(); + let error = this.try_errnum_to_io_error(errnum)?; + let formatted = match error { + Some(err) => format!("{err}"), + None => format!(""), + }; let (complete, _) = this.write_os_str_to_c_str(OsStr::new(&formatted), buf, buflen)?; let ret = if complete { 0 } else { this.eval_libc_i32("ERANGE")? }; this.write_int(ret, dest)?; diff --git a/tests/pass/fs.rs b/tests/pass/fs.rs index a8025007bf5f5..af9f854ce527f 100644 --- a/tests/pass/fs.rs +++ b/tests/pass/fs.rs @@ -3,6 +3,7 @@ #![feature(rustc_private)] #![feature(io_error_more)] +#![feature(io_error_uncategorized)] use std::ffi::CString; use std::fs::{ @@ -26,6 +27,7 @@ fn main() { test_directory(); test_canonicalize(); test_dup_stdout_stderr(); + test_from_raw_os_error(); // These all require unix, if the test is changed to no longer `ignore-windows`, move these to a unix test test_file_open_unix_allow_two_args(); @@ -434,3 +436,11 @@ fn test_dup_stdout_stderr() { libc::write(new_stderr, bytes.as_ptr() as *const libc::c_void, bytes.len()); } } + +fn test_from_raw_os_error() { + let code = 6; // not a code that std or Miri know + let error = Error::from_raw_os_error(code); + assert!(matches!(error.kind(), ErrorKind::Uncategorized)); + // Make sure we can also format this. + format!("{error:?}"); +} From d7875ea53008f2af7a4318503ae42204e6c17a67 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 5 Aug 2022 20:17:14 -0400 Subject: [PATCH 3604/3747] fix an ICE in nanosleep() --- src/shims/time.rs | 6 +++++- tests/pass/sleep_long.rs | 18 ++++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) create mode 100644 tests/pass/sleep_long.rs diff --git a/src/shims/time.rs b/src/shims/time.rs index a2cbd84bc2dbb..d9edbe3d7bdf4 100644 --- a/src/shims/time.rs +++ b/src/shims/time.rs @@ -210,7 +210,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx return Ok(-1); } }; - let timeout_time = Time::Monotonic(Instant::now().checked_add(duration).unwrap()); + // If adding the duration overflows, let's just sleep for an hour. Waking up early is always acceptable. + let timeout_time = Instant::now() + .checked_add(duration) + .unwrap_or_else(|| Instant::now().checked_add(Duration::from_secs(3600)).unwrap()); + let timeout_time = Time::Monotonic(timeout_time); let active_thread = this.get_active_thread(); this.block_thread(active_thread); diff --git a/tests/pass/sleep_long.rs b/tests/pass/sleep_long.rs new file mode 100644 index 0000000000000..dd4a1843942c4 --- /dev/null +++ b/tests/pass/sleep_long.rs @@ -0,0 +1,18 @@ +//@ignore-target-windows: no threads nor sleep on Windows +//@compile-flags: -Zmiri-ignore-leaks -Zmiri-disable-isolation +use std::sync::{Arc, Mutex}; +use std::thread; +use std::time::Duration; + +fn main() { + let finished = Arc::new(Mutex::new(false)); + let t_finished = finished.clone(); + thread::spawn(move || { + // Sleep very, very long. + thread::sleep(Duration::new(u64::MAX, 0)); + *t_finished.lock().unwrap() = true; + }); + thread::sleep(Duration::from_millis(100)); + assert_eq!(*finished.lock().unwrap(), false); + // Stopping the main thread will also kill the sleeper. +} From d61e55a1d4f5c00e3f1b7ab025683f50a8c075d2 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 6 Aug 2022 08:17:19 -0400 Subject: [PATCH 3605/3747] add support for env::home_dir and a bit of cleanup --- src/shims/unix/foreign_items.rs | 36 ++++++++++++------- src/shims/unix/fs.rs | 50 +++++++++++++++------------ src/shims/unix/linux/foreign_items.rs | 35 +++++++++++++++++++ src/shims/unix/mod.rs | 3 ++ src/shims/windows/foreign_items.rs | 1 + tests/pass/home.rs | 9 +++++ 6 files changed, 99 insertions(+), 35 deletions(-) create mode 100644 tests/pass/home.rs diff --git a/src/shims/unix/foreign_items.rs b/src/shims/unix/foreign_items.rs index dc80d592a0c1a..7dde2d7d2c193 100644 --- a/src/shims/unix/foreign_items.rs +++ b/src/shims/unix/foreign_items.rs @@ -228,16 +228,21 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let [name] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let name = this.read_scalar(name)?.to_i32()?; - let sysconfs = &[ - ("_SC_PAGESIZE", Scalar::from_int(PAGE_SIZE, this.pointer_size())), - ("_SC_NPROCESSORS_CONF", Scalar::from_int(NUM_CPUS, this.pointer_size())), - ("_SC_NPROCESSORS_ONLN", Scalar::from_int(NUM_CPUS, this.pointer_size())), + // FIXME: Which of these are POSIX, and which are GNU/Linux? + // At least the names seem to all also exist on macOS. + let sysconfs: &[(&str, fn(&MiriEvalContext<'_, '_>) -> Scalar)] = &[ + ("_SC_PAGESIZE", |this| Scalar::from_int(PAGE_SIZE, this.pointer_size())), + ("_SC_NPROCESSORS_CONF", |this| Scalar::from_int(NUM_CPUS, this.pointer_size())), + ("_SC_NPROCESSORS_ONLN", |this| Scalar::from_int(NUM_CPUS, this.pointer_size())), + // 512 seems to be a reasonable default. The value is not critical, in + // the sense that getpwuid_r takes and checks the buffer length. + ("_SC_GETPW_R_SIZE_MAX", |this| Scalar::from_int(512, this.pointer_size())) ]; let mut result = None; for &(sysconf_name, value) in sysconfs { let sysconf_name = this.eval_libc_i32(sysconf_name)?; if sysconf_name == name { - result = Some(value); + result = Some(value(this)); break; } } @@ -474,6 +479,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let ret = if complete { 0 } else { this.eval_libc_i32("ERANGE")? }; this.write_int(ret, dest)?; } + "getpid" => { + let [] = this.check_shim(abi, Abi::C { unwind: false}, link_name, args)?; + let result = this.getpid()?; + this.write_scalar(Scalar::from_i32(result), dest)?; + } // Incomplete shims that we "stub out" just to get pre-main initialization code to work. // These shims are enabled only when the caller is in the standard library. @@ -500,9 +510,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_null(dest)?; } - // Querying system information - "pthread_attr_getstack" => { - // We don't support "pthread_attr_setstack", so we just pretend all stacks have the same values here. Hence we can mostly ignore the input `attr_place`. + "pthread_attr_getstack" + if this.frame_in_std() => { + // We don't support "pthread_attr_setstack", so we just pretend all stacks have the same values here. + // Hence we can mostly ignore the input `attr_place`. let [attr_place, addr_place, size_place] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let _attr_place = this.deref_operand(attr_place)?; @@ -535,10 +546,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_null(dest)?; } - "getpid" => { - let [] = this.check_shim(abi, Abi::C { unwind: false}, link_name, args)?; - let result = this.getpid()?; - this.write_scalar(Scalar::from_i32(result), dest)?; + "getuid" + if this.frame_in_std() => { + let [] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + // FOr now, just pretend we always have this fixed UID. + this.write_int(super::UID, dest)?; } // Platform-specific shims diff --git a/src/shims/unix/fs.rs b/src/shims/unix/fs.rs index 9b00579d873b9..3dccdd5e74f17 100644 --- a/src/shims/unix/fs.rs +++ b/src/shims/unix/fs.rs @@ -1091,31 +1091,35 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ], &statxbuf, )?; - this.write_int_fields( + #[rustfmt::skip] + this.write_int_fields_named( &[ - access_sec.into(), // stx_atime.tv_sec - access_nsec.into(), // stx_atime.tv_nsec + ("tv_sec", access_sec.into()), + ("tv_nsec", access_nsec.into()), ], &this.mplace_field_named(&statxbuf, "stx_atime")?, )?; - this.write_int_fields( + #[rustfmt::skip] + this.write_int_fields_named( &[ - created_sec.into(), // stx_btime.tv_sec - created_nsec.into(), // stx_btime.tv_nsec + ("tv_sec", created_sec.into()), + ("tv_nsec", created_nsec.into()), ], &this.mplace_field_named(&statxbuf, "stx_btime")?, )?; - this.write_int_fields( + #[rustfmt::skip] + this.write_int_fields_named( &[ - 0.into(), // stx_ctime.tv_sec - 0.into(), // stx_ctime.tv_nsec + ("tv_sec", 0.into()), + ("tv_nsec", 0.into()), ], &this.mplace_field_named(&statxbuf, "stx_ctime")?, )?; - this.write_int_fields( + #[rustfmt::skip] + this.write_int_fields_named( &[ - modified_sec.into(), // stx_mtime.tv_sec - modified_nsec.into(), // stx_mtime.tv_nsec + ("tv_sec", modified_sec.into()), + ("tv_nsec", modified_nsec.into()), ], &this.mplace_field_named(&statxbuf, "stx_mtime")?, )?; @@ -1302,12 +1306,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let file_type = this.file_type_to_d_type(dir_entry.file_type())?; - this.write_int_fields( + this.write_int_fields_named( &[ - ino.into(), // d_ino - 0, // d_off - size.into(), // d_reclen - file_type.into(), // d_type + ("d_ino", ino.into()), + ("d_off", 0), + ("d_reclen", size.into()), + ("d_type", file_type.into()), ], &MPlaceTy::from_aligned_ptr(entry, dirent64_layout), )?; @@ -1398,13 +1402,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let file_type = this.file_type_to_d_type(dir_entry.file_type())?; - this.write_int_fields( + this.write_int_fields_named( &[ - ino.into(), // d_ino - 0, // d_seekoff - 0, // d_reclen - file_name_len.into(), // d_namlen - file_type.into(), // d_type + ("d_ino", ino.into()), + ("d_seekoff", 0), + ("d_reclen", 0), + ("d_namlen", file_name_len.into()), + ("d_type", file_type.into()), ], &entry_place, )?; diff --git a/src/shims/unix/linux/foreign_items.rs b/src/shims/unix/linux/foreign_items.rs index bae3780b460c7..61016c424954f 100644 --- a/src/shims/unix/linux/foreign_items.rs +++ b/src/shims/unix/linux/foreign_items.rs @@ -155,6 +155,41 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_null(dest)?; } + "getpwuid_r" if this.frame_in_std() => { + let [uid, pwd, buf, buflen, result] = + this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + this.check_no_isolation("`getpwuid_r`")?; + + let uid = this.read_scalar(uid)?.to_u32()?; + let pwd = this.deref_operand(pwd)?; + let buf = this.read_pointer(buf)?; + let buflen = this.read_scalar(buflen)?.to_machine_usize(this)?; + let result = this.deref_operand(result)?; + + // Must be for "us". + if uid != crate::shims::unix::UID { + throw_unsup_format!("`getpwuid_r` on other users is not supported"); + } + + // Reset all fields to `uninit` to make sure nobody reads them. + this.write_uninit(&pwd.into())?; + + // We only set the home_dir field. + #[allow(deprecated)] + let home_dir = std::env::home_dir().unwrap(); + let (written, _) = this.write_path_to_c_str(&home_dir, buf, buflen)?; + let pw_dir = this.mplace_field_named(&pwd, "pw_dir")?; + this.write_pointer(buf, &pw_dir.into())?; + + if written { + this.write_pointer(pwd.ptr, &result.into())?; + this.write_null(dest)?; + } else { + this.write_null(&result.into())?; + this.write_scalar(this.eval_libc("ERANGE")?, dest)?; + } + } + _ => return Ok(EmulateByNameResult::NotSupported), }; diff --git a/src/shims/unix/mod.rs b/src/shims/unix/mod.rs index 8e8c70bbd0faf..35380fc06d79b 100644 --- a/src/shims/unix/mod.rs +++ b/src/shims/unix/mod.rs @@ -10,3 +10,6 @@ mod linux; mod macos; pub use fs::{DirHandler, FileHandler}; + +// Make up some constants. +const UID: u32 = 1000; diff --git a/src/shims/windows/foreign_items.rs b/src/shims/windows/foreign_items.rs index 29afe52cafd6c..6520609b76f4e 100644 --- a/src/shims/windows/foreign_items.rs +++ b/src/shims/windows/foreign_items.rs @@ -110,6 +110,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Querying system information "GetSystemInfo" => { + // Also called from `page_size` crate. let [system_info] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; let system_info = this.deref_operand(system_info)?; diff --git a/tests/pass/home.rs b/tests/pass/home.rs new file mode 100644 index 0000000000000..0fb69aad00770 --- /dev/null +++ b/tests/pass/home.rs @@ -0,0 +1,9 @@ +//@only-target-linux: home_dir is only supported on Linux +//@compile-flags: -Zmiri-disable-isolation +use std::env; + +fn main() { + env::remove_var("HOME"); // make sure we enter the interesting codepath + #[allow(deprecated)] + env::home_dir().unwrap(); +} From 889c073aa66049d28d7bb243cd9d774cfa96f4ae Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 6 Aug 2022 09:03:33 -0400 Subject: [PATCH 3606/3747] really, clippy?!? --- src/lib.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index caae17b202235..8b1c18a499f6c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -22,7 +22,8 @@ clippy::useless_format, clippy::derive_partial_eq_without_eq, clippy::derive_hash_xor_eq, - clippy::too_many_arguments + clippy::too_many_arguments, + clippy::type_complexity )] #![warn( rust_2018_idioms, From 5a4ac1ebf0e30b415b90a57904e4c2cb32f35068 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 6 Aug 2022 10:30:55 -0400 Subject: [PATCH 3607/3747] work around apfloat bug in FMA by using host floats instead --- src/shims/foreign_items.rs | 18 +++++++++--------- src/shims/intrinsics/mod.rs | 34 ++++++++++++++++++++-------------- src/shims/intrinsics/simd.rs | 19 +++++++++++++++---- tests/pass/intrinsics-math.rs | 2 ++ tests/pass/portable-simd.rs | 10 ++++++++++ 5 files changed, 56 insertions(+), 27 deletions(-) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 208e7ea788f7d..9a985b2450391 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -588,7 +588,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let [f] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; // FIXME: Using host floats. let f = f32::from_bits(this.read_scalar(f)?.to_u32()?); - let f = match link_name.as_str() { + let res = match link_name.as_str() { "cbrtf" => f.cbrt(), "coshf" => f.cosh(), "sinhf" => f.sinh(), @@ -598,7 +598,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "atanf" => f.atan(), _ => bug!(), }; - this.write_scalar(Scalar::from_u32(f.to_bits()), dest)?; + this.write_scalar(Scalar::from_u32(res.to_bits()), dest)?; } #[rustfmt::skip] | "_hypotf" @@ -611,12 +611,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // FIXME: Using host floats. let f1 = f32::from_bits(this.read_scalar(f1)?.to_u32()?); let f2 = f32::from_bits(this.read_scalar(f2)?.to_u32()?); - let n = match link_name.as_str() { + let res = match link_name.as_str() { "_hypotf" | "hypotf" => f1.hypot(f2), "atan2f" => f1.atan2(f2), _ => bug!(), }; - this.write_scalar(Scalar::from_u32(n.to_bits()), dest)?; + this.write_scalar(Scalar::from_u32(res.to_bits()), dest)?; } #[rustfmt::skip] | "cbrt" @@ -630,7 +630,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let [f] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; // FIXME: Using host floats. let f = f64::from_bits(this.read_scalar(f)?.to_u64()?); - let f = match link_name.as_str() { + let res = match link_name.as_str() { "cbrt" => f.cbrt(), "cosh" => f.cosh(), "sinh" => f.sinh(), @@ -640,7 +640,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "atan" => f.atan(), _ => bug!(), }; - this.write_scalar(Scalar::from_u64(f.to_bits()), dest)?; + this.write_scalar(Scalar::from_u64(res.to_bits()), dest)?; } #[rustfmt::skip] | "_hypot" @@ -651,12 +651,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // FIXME: Using host floats. let f1 = f64::from_bits(this.read_scalar(f1)?.to_u64()?); let f2 = f64::from_bits(this.read_scalar(f2)?.to_u64()?); - let n = match link_name.as_str() { + let res = match link_name.as_str() { "_hypot" | "hypot" => f1.hypot(f2), "atan2" => f1.atan2(f2), _ => bug!(), }; - this.write_scalar(Scalar::from_u64(n.to_bits()), dest)?; + this.write_scalar(Scalar::from_u64(res.to_bits()), dest)?; } #[rustfmt::skip] | "_ldexp" @@ -668,7 +668,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let x = this.read_scalar(x)?.to_f64()?; let exp = this.read_scalar(exp)?.to_i32()?; - // Saturating cast to i16. Even those are outside the valid exponent range to + // Saturating cast to i16. Even those are outside the valid exponent range so // `scalbn` below will do its over/underflow handling. let exp = if exp > i32::from(i16::MAX) { i16::MAX diff --git a/src/shims/intrinsics/mod.rs b/src/shims/intrinsics/mod.rs index 4c2d08ffceabc..08a6e0fcc0eef 100644 --- a/src/shims/intrinsics/mod.rs +++ b/src/shims/intrinsics/mod.rs @@ -285,7 +285,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // FIXME: Using host floats. let f = f32::from_bits(this.read_scalar(f)?.to_u32()?); let f2 = f32::from_bits(this.read_scalar(f2)?.to_u32()?); - this.write_scalar(Scalar::from_u32(f.powf(f2).to_bits()), dest)?; + let res = f.powf(f2); + this.write_scalar(Scalar::from_u32(res.to_bits()), dest)?; } "powf64" => { @@ -293,25 +294,28 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // FIXME: Using host floats. let f = f64::from_bits(this.read_scalar(f)?.to_u64()?); let f2 = f64::from_bits(this.read_scalar(f2)?.to_u64()?); - this.write_scalar(Scalar::from_u64(f.powf(f2).to_bits()), dest)?; + let res = f.powf(f2); + this.write_scalar(Scalar::from_u64(res.to_bits()), dest)?; } "fmaf32" => { let [a, b, c] = check_arg_count(args)?; - let a = this.read_scalar(a)?.to_f32()?; - let b = this.read_scalar(b)?.to_f32()?; - let c = this.read_scalar(c)?.to_f32()?; - let res = a.mul_add(b, c).value; - this.write_scalar(Scalar::from_f32(res), dest)?; + // FIXME: Using host floats, to work around https://github.com/rust-lang/miri/issues/2468. + let a = f32::from_bits(this.read_scalar(a)?.to_u32()?); + let b = f32::from_bits(this.read_scalar(b)?.to_u32()?); + let c = f32::from_bits(this.read_scalar(c)?.to_u32()?); + let res = a.mul_add(b, c); + this.write_scalar(Scalar::from_u32(res.to_bits()), dest)?; } "fmaf64" => { let [a, b, c] = check_arg_count(args)?; - let a = this.read_scalar(a)?.to_f64()?; - let b = this.read_scalar(b)?.to_f64()?; - let c = this.read_scalar(c)?.to_f64()?; - let res = a.mul_add(b, c).value; - this.write_scalar(Scalar::from_f64(res), dest)?; + // FIXME: Using host floats, to work around https://github.com/rust-lang/miri/issues/2468. + let a = f64::from_bits(this.read_scalar(a)?.to_u64()?); + let b = f64::from_bits(this.read_scalar(b)?.to_u64()?); + let c = f64::from_bits(this.read_scalar(c)?.to_u64()?); + let res = a.mul_add(b, c); + this.write_scalar(Scalar::from_u64(res.to_bits()), dest)?; } "powif32" => { @@ -319,7 +323,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // FIXME: Using host floats. let f = f32::from_bits(this.read_scalar(f)?.to_u32()?); let i = this.read_scalar(i)?.to_i32()?; - this.write_scalar(Scalar::from_u32(f.powi(i).to_bits()), dest)?; + let res = f.powi(i); + this.write_scalar(Scalar::from_u32(res.to_bits()), dest)?; } "powif64" => { @@ -327,7 +332,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // FIXME: Using host floats. let f = f64::from_bits(this.read_scalar(f)?.to_u64()?); let i = this.read_scalar(i)?.to_i32()?; - this.write_scalar(Scalar::from_u64(f.powi(i).to_bits()), dest)?; + let res = f.powi(i); + this.write_scalar(Scalar::from_u64(res.to_bits()), dest)?; } "float_to_int_unchecked" => { diff --git a/src/shims/intrinsics/simd.rs b/src/shims/intrinsics/simd.rs index d467c3c509f5f..0c3241683a186 100644 --- a/src/shims/intrinsics/simd.rs +++ b/src/shims/intrinsics/simd.rs @@ -238,14 +238,25 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let dest = this.mplace_index(&dest, i)?; // Works for f32 and f64. + // FIXME: using host floats to work around https://github.com/rust-lang/miri/issues/2468. let ty::Float(float_ty) = dest.layout.ty.kind() else { span_bug!(this.cur_span(), "{} operand is not a float", intrinsic_name) }; let val = match float_ty { - FloatTy::F32 => - Scalar::from_f32(a.to_f32()?.mul_add(b.to_f32()?, c.to_f32()?).value), - FloatTy::F64 => - Scalar::from_f64(a.to_f64()?.mul_add(b.to_f64()?, c.to_f64()?).value), + FloatTy::F32 => { + let a = f32::from_bits(a.to_u32()?); + let b = f32::from_bits(b.to_u32()?); + let c = f32::from_bits(c.to_u32()?); + let res = a.mul_add(b, c); + Scalar::from_u32(res.to_bits()) + } + FloatTy::F64 => { + let a = f64::from_bits(a.to_u64()?); + let b = f64::from_bits(b.to_u64()?); + let c = f64::from_bits(c.to_u64()?); + let res = a.mul_add(b, c); + Scalar::from_u64(res.to_bits()) + } }; this.write_scalar(val, &dest.into())?; } diff --git a/tests/pass/intrinsics-math.rs b/tests/pass/intrinsics-math.rs index 0cb42580fcb2c..fad01047b9c6e 100644 --- a/tests/pass/intrinsics-math.rs +++ b/tests/pass/intrinsics-math.rs @@ -60,6 +60,8 @@ pub fn main() { assert_eq!(0.0f32.mul_add(-2.0, f32::consts::E), f32::consts::E); assert_approx_eq!(3.0f64.mul_add(2.0, 5.0), 11.0); assert_eq!(0.0f64.mul_add(-2.0f64, f64::consts::E), f64::consts::E); + assert_eq!((-3.2f32).mul_add(2.4, f32::NEG_INFINITY), f32::NEG_INFINITY); + assert_eq!((-3.2f64).mul_add(2.4, f64::NEG_INFINITY), f64::NEG_INFINITY); assert_approx_eq!((-1.0f32).abs(), 1.0f32); assert_approx_eq!(34.2f64.abs(), 34.2f64); diff --git a/tests/pass/portable-simd.rs b/tests/pass/portable-simd.rs index ec70eea6b1771..173ac654b03d5 100644 --- a/tests/pass/portable-simd.rs +++ b/tests/pass/portable-simd.rs @@ -18,6 +18,11 @@ fn simd_ops_f32() { assert_eq!(a.mul_add(b, a), (a * b) + a); assert_eq!(b.mul_add(b, a), (b * b) + a); + assert_eq!(a.mul_add(b, b), (a * b) + b); + assert_eq!( + f32x4::splat(-3.2).mul_add(b, f32x4::splat(f32::NEG_INFINITY)), + f32x4::splat(f32::NEG_INFINITY) + ); assert_eq!((a * a).sqrt(), a); assert_eq!((b * b).sqrt(), b.abs()); @@ -67,6 +72,11 @@ fn simd_ops_f64() { assert_eq!(a.mul_add(b, a), (a * b) + a); assert_eq!(b.mul_add(b, a), (b * b) + a); + assert_eq!(a.mul_add(b, b), (a * b) + b); + assert_eq!( + f64x4::splat(-3.2).mul_add(b, f64x4::splat(f64::NEG_INFINITY)), + f64x4::splat(f64::NEG_INFINITY) + ); assert_eq!((a * a).sqrt(), a); assert_eq!((b * b).sqrt(), b.abs()); From b1316eca922655f5d81559c1c26f457693aa5c2b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 6 Aug 2022 09:33:08 -0400 Subject: [PATCH 3608/3747] support and test some more math functions --- src/shims/foreign_items.rs | 20 +++++++++- tests/pass/intrinsics-math.rs | 75 ++++++++++++++++++++++++----------- 2 files changed, 71 insertions(+), 24 deletions(-) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 9a985b2450391..e7cfd43f1b1e7 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -575,15 +575,18 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_scalar(Scalar::from_machine_usize(u64::try_from(n).unwrap(), this), dest)?; } - // math functions + // math functions (note that there are also intrinsics for some other functions) #[rustfmt::skip] | "cbrtf" | "coshf" | "sinhf" | "tanf" + | "tanhf" | "acosf" | "asinf" | "atanf" + | "log1pf" + | "expm1f" => { let [f] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; // FIXME: Using host floats. @@ -593,9 +596,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "coshf" => f.cosh(), "sinhf" => f.sinh(), "tanf" => f.tan(), + "tanhf" => f.tanh(), "acosf" => f.acos(), "asinf" => f.asin(), "atanf" => f.atan(), + "log1pf" => f.ln_1p(), + "expm1f" => f.exp_m1(), _ => bug!(), }; this.write_scalar(Scalar::from_u32(res.to_bits()), dest)?; @@ -604,6 +610,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "_hypotf" | "hypotf" | "atan2f" + | "fdimf" => { let [f1, f2] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; // underscore case for windows, here and below @@ -614,6 +621,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let res = match link_name.as_str() { "_hypotf" | "hypotf" => f1.hypot(f2), "atan2f" => f1.atan2(f2), + #[allow(deprecated)] + "fdimf" => f1.abs_sub(f2), _ => bug!(), }; this.write_scalar(Scalar::from_u32(res.to_bits()), dest)?; @@ -623,9 +632,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "cosh" | "sinh" | "tan" + | "tanh" | "acos" | "asin" | "atan" + | "log1p" + | "expm1" => { let [f] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; // FIXME: Using host floats. @@ -635,9 +647,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "cosh" => f.cosh(), "sinh" => f.sinh(), "tan" => f.tan(), + "tanh" => f.tanh(), "acos" => f.acos(), "asin" => f.asin(), "atan" => f.atan(), + "log1p" => f.ln_1p(), + "expm1" => f.exp_m1(), _ => bug!(), }; this.write_scalar(Scalar::from_u64(res.to_bits()), dest)?; @@ -646,6 +661,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | "_hypot" | "hypot" | "atan2" + | "fdim" => { let [f1, f2] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; // FIXME: Using host floats. @@ -654,6 +670,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let res = match link_name.as_str() { "_hypot" | "hypot" => f1.hypot(f2), "atan2" => f1.atan2(f2), + #[allow(deprecated)] + "fdim" => f1.abs_sub(f2), _ => bug!(), }; this.write_scalar(Scalar::from_u64(res.to_bits()), dest)?; diff --git a/tests/pass/intrinsics-math.rs b/tests/pass/intrinsics-math.rs index fad01047b9c6e..5973f4cd197fe 100644 --- a/tests/pass/intrinsics-math.rs +++ b/tests/pass/intrinsics-math.rs @@ -32,24 +32,24 @@ pub fn main() { assert_approx_eq!(25f32.powi(-2), 0.0016f32); assert_approx_eq!(23.2f64.powi(2), 538.24f64); - assert_approx_eq!(0f32.sin(), 0f32); - assert_approx_eq!((f64::consts::PI / 2f64).sin(), 1f64); - - assert_approx_eq!(0f32.cos(), 1f32); - assert_approx_eq!((f64::consts::PI * 2f64).cos(), 1f64); - assert_approx_eq!(25f32.powf(-2f32), 0.0016f32); assert_approx_eq!(400f64.powf(0.5f64), 20f64); - assert_approx_eq!((1f32.exp() - f32::consts::E).abs(), 0f32); + assert_approx_eq!(1f32.exp(), f32::consts::E); assert_approx_eq!(1f64.exp(), f64::consts::E); + assert_approx_eq!(1f32.exp_m1(), f32::consts::E - 1.0); + assert_approx_eq!(1f64.exp_m1(), f64::consts::E - 1.0); + assert_approx_eq!(10f32.exp2(), 1024f32); assert_approx_eq!(50f64.exp2(), 1125899906842624f64); - assert_approx_eq!((f32::consts::E.ln() - 1f32).abs(), 0f32); + assert_approx_eq!(f32::consts::E.ln(), 1f32); assert_approx_eq!(1f64.ln(), 0f64); + assert_approx_eq!(0f32.ln_1p(), 0f32); + assert_approx_eq!(0f64.ln_1p(), 0f64); + assert_approx_eq!(10f32.log10(), 1f32); assert_approx_eq!(f64::consts::E.log10(), f64::consts::LOG10_E); @@ -66,6 +66,12 @@ pub fn main() { assert_approx_eq!((-1.0f32).abs(), 1.0f32); assert_approx_eq!(34.2f64.abs(), 34.2f64); + #[allow(deprecated)] + { + assert_approx_eq!(5.0f32.abs_sub(3.0), 2.0); + assert_approx_eq!(3.0f64.abs_sub(5.0), 0.0); + } + assert_approx_eq!(3.8f32.floor(), 3.0f32); assert_approx_eq!((-1.1f64).floor(), -2.0f64); @@ -81,31 +87,54 @@ pub fn main() { assert_approx_eq!(3.0f32.hypot(4.0f32), 5.0f32); assert_approx_eq!(3.0f64.hypot(4.0f64), 5.0f64); - assert_approx_eq!(1.0f32.atan2(2.0f32), 0.46364761f32); - assert_approx_eq!(1.0f32.atan2(2.0f32), 0.46364761f32); + assert_eq!(3.3_f32.round(), 3.0); + assert_eq!(3.3_f64.round(), 3.0); - assert_approx_eq!(1.0f32.cosh(), 1.54308f32); - assert_approx_eq!(1.0f64.cosh(), 1.54308f64); + assert_eq!(ldexp(0.65f64, 3i32), 5.2f64); + assert_eq!(ldexp(1.42, 0xFFFF), f64::INFINITY); + assert_eq!(ldexp(1.42, -0xFFFF), 0f64); + + // Trigonometric functions. + + assert_approx_eq!(0f32.sin(), 0f32); + assert_approx_eq!((f64::consts::PI / 2f64).sin(), 1f64); + assert_approx_eq!(f32::consts::FRAC_PI_6.sin(), 0.5); + assert_approx_eq!(f64::consts::FRAC_PI_6.sin(), 0.5); + assert_approx_eq!(f32::consts::FRAC_PI_4.sin().asin(), f32::consts::FRAC_PI_4); + assert_approx_eq!(f64::consts::FRAC_PI_4.sin().asin(), f64::consts::FRAC_PI_4); assert_approx_eq!(1.0f32.sinh(), 1.1752012f32); assert_approx_eq!(1.0f64.sinh(), 1.1752012f64); + assert_approx_eq!(2.0f32.asinh(), 1.443635475178810342493276740273105f32); + assert_approx_eq!((-2.0f64).asinh(), -1.443635475178810342493276740273105f64); - assert_approx_eq!(1.0f32.tan(), 1.557408f32); - assert_approx_eq!(1.0f64.tan(), 1.557408f64); - + assert_approx_eq!(0f32.cos(), 1f32); + assert_approx_eq!((f64::consts::PI * 2f64).cos(), 1f64); + assert_approx_eq!(f32::consts::FRAC_PI_3.cos(), 0.5); + assert_approx_eq!(f64::consts::FRAC_PI_3.cos(), 0.5); assert_approx_eq!(f32::consts::FRAC_PI_4.cos().acos(), f32::consts::FRAC_PI_4); assert_approx_eq!(f64::consts::FRAC_PI_4.cos().acos(), f64::consts::FRAC_PI_4); - assert_approx_eq!(f32::consts::FRAC_PI_4.sin().asin(), f32::consts::FRAC_PI_4); - assert_approx_eq!(f64::consts::FRAC_PI_4.sin().asin(), f64::consts::FRAC_PI_4); + assert_approx_eq!(1.0f32.cosh(), 1.54308f32); + assert_approx_eq!(1.0f64.cosh(), 1.54308f64); + assert_approx_eq!(2.0f32.acosh(), 1.31695789692481670862504634730796844f32); + assert_approx_eq!(3.0f64.acosh(), 1.76274717403908605046521864995958461f64); + assert_approx_eq!(1.0f32.tan(), 1.557408f32); + assert_approx_eq!(1.0f64.tan(), 1.557408f64); assert_approx_eq!(1.0_f32, 1.0_f32.tan().atan()); assert_approx_eq!(1.0_f64, 1.0_f64.tan().atan()); + assert_approx_eq!(1.0f32.atan2(2.0f32), 0.46364761f32); + assert_approx_eq!(1.0f32.atan2(2.0f32), 0.46364761f32); - assert_eq!(3.3_f32.round(), 3.0); - assert_eq!(3.3_f64.round(), 3.0); - - assert_eq!(ldexp(0.65f64, 3i32), 5.2f64); - assert_eq!(ldexp(1.42, 0xFFFF), f64::INFINITY); - assert_eq!(ldexp(1.42, -0xFFFF), 0f64); + assert_approx_eq!( + 1.0f32.tanh(), + (1.0 - f32::consts::E.powi(-2)) / (1.0 + f32::consts::E.powi(-2)) + ); + assert_approx_eq!( + 1.0f64.tanh(), + (1.0 - f64::consts::E.powi(-2)) / (1.0 + f64::consts::E.powi(-2)) + ); + assert_approx_eq!(0.5f32.atanh(), 0.54930614433405484569762261846126285f32); + assert_approx_eq!(0.5f64.atanh(), 0.54930614433405484569762261846126285f64); } From 61be3bae40ffe16dff1fc2e0147ecf125064fde3 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 6 Aug 2022 11:47:14 -0400 Subject: [PATCH 3609/3747] support current_exe on macOS, and fix write_os_str length logic --- src/shims/env.rs | 4 ++-- src/shims/os_str.rs | 10 ++++++---- src/shims/unix/fs.rs | 3 ++- src/shims/unix/macos/foreign_items.rs | 27 +++++++++++++++++++++++++++ tests/pass/current_exe.rs | 8 ++++++++ 5 files changed, 45 insertions(+), 7 deletions(-) create mode 100644 tests/pass/current_exe.rs diff --git a/src/shims/env.rs b/src/shims/env.rs index db1ddf6291fd9..d333e78e5240f 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -18,11 +18,11 @@ fn windows_check_buffer_size((success, len): (bool, u64)) -> u32 { if success { // If the function succeeds, the return value is the number of characters stored in the target buffer, // not including the terminating null character. - u32::try_from(len).unwrap() + u32::try_from(len.checked_sub(1).unwrap()).unwrap() } else { // If the target buffer was not large enough to hold the data, the return value is the buffer size, in characters, // required to hold the string and its terminating null character. - u32::try_from(len.checked_add(1).unwrap()).unwrap() + u32::try_from(len).unwrap() } } diff --git a/src/shims/os_str.rs b/src/shims/os_str.rs index b9f3a435ea429..f99e2d174b531 100644 --- a/src/shims/os_str.rs +++ b/src/shims/os_str.rs @@ -92,7 +92,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// the Unix APIs usually handle. This function returns `Ok((false, length))` without trying /// to write if `size` is not large enough to fit the contents of `os_string` plus a null /// terminator. It returns `Ok((true, length))` if the writing process was successful. The - /// string length returned does not include the null terminator. + /// string length returned does include the null terminator. fn write_os_str_to_c_str( &mut self, os_str: &OsStr, @@ -103,7 +103,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // If `size` is smaller or equal than `bytes.len()`, writing `bytes` plus the required null // terminator to memory using the `ptr` pointer would cause an out-of-bounds access. let string_length = u64::try_from(bytes.len()).unwrap(); - if size <= string_length { + let string_length = string_length.checked_add(1).unwrap(); + if size < string_length { return Ok((false, string_length)); } self.eval_context_mut() @@ -115,7 +116,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// the Windows APIs usually handle. This function returns `Ok((false, length))` without trying /// to write if `size` is not large enough to fit the contents of `os_string` plus a null /// terminator. It returns `Ok((true, length))` if the writing process was successful. The - /// string length returned does not include the null terminator. + /// string length returned does include the null terminator. Length is measured in units of + /// `u16.` fn write_os_str_to_wide_str( &mut self, os_str: &OsStr, @@ -157,7 +159,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx alloc .write_scalar(alloc_range(size2 * offset, size2), Scalar::from_u16(wchar).into())?; } - Ok((true, string_length - 1)) + Ok((true, string_length)) } /// Allocate enough memory to store the given `OsStr` as a null-terminated sequence of bytes. diff --git a/src/shims/unix/fs.rs b/src/shims/unix/fs.rs index 3dccdd5e74f17..951ddae2c14d0 100644 --- a/src/shims/unix/fs.rs +++ b/src/shims/unix/fs.rs @@ -1380,11 +1380,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let name_place = this.mplace_field(&entry_place, 5)?; let file_name = dir_entry.file_name(); // not a Path as there are no separators! - let (name_fits, file_name_len) = this.write_os_str_to_c_str( + let (name_fits, file_name_buf_len) = this.write_os_str_to_c_str( &file_name, name_place.ptr, name_place.layout.size.bytes(), )?; + let file_name_len = file_name_buf_len.checked_sub(1).unwrap(); if !name_fits { throw_unsup_format!( "a directory entry had a name too large to fit in libc::dirent" diff --git a/src/shims/unix/macos/foreign_items.rs b/src/shims/unix/macos/foreign_items.rs index fb545d8b5847e..35751d5818ab8 100644 --- a/src/shims/unix/macos/foreign_items.rs +++ b/src/shims/unix/macos/foreign_items.rs @@ -117,6 +117,33 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx dest, )?; } + "_NSGetExecutablePath" => { + let [buf, bufsize] = + this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + this.check_no_isolation("`_NSGetExecutablePath`")?; + + let buf_ptr = this.read_pointer(buf)?; + let bufsize = this.deref_operand(bufsize)?; + + // Using the host current_exe is a bit off, but consistent with Linux + // (where stdlib reads /proc/self/exe). + let path = std::env::current_exe().unwrap(); + let (written, size_needed) = this.write_path_to_c_str( + &path, + buf_ptr, + this.read_scalar(&bufsize.into())?.to_u32()?.into(), + )?; + + if written { + this.write_null(dest)?; + } else { + this.write_scalar( + Scalar::from_u32(size_needed.try_into().unwrap()), + &bufsize.into(), + )?; + this.write_int(-1, dest)?; + } + } // Thread-local storage "_tlv_atexit" => { diff --git a/tests/pass/current_exe.rs b/tests/pass/current_exe.rs new file mode 100644 index 0000000000000..64f62b230e488 --- /dev/null +++ b/tests/pass/current_exe.rs @@ -0,0 +1,8 @@ +//@ignore-target-windows +//@compile-flags: -Zmiri-disable-isolation +use std::env; + +fn main() { + // The actual value we get is a bit odd: we get the Miri binary that interprets us. + env::current_exe().unwrap(); +} From f8449c2c78366d9ce016bb0b8be788d76ed9528e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 6 Aug 2022 14:31:11 -0400 Subject: [PATCH 3610/3747] stop excluding TERM env var on Unix --- README.md | 5 ++--- src/shims/env.rs | 7 ++++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 5fbf89c86b969..c7a3200dbd904 100644 --- a/README.md +++ b/README.md @@ -282,9 +282,8 @@ environment variable. We first document the most relevant and most commonly used verbose. `hide` hides the warning entirely. * `-Zmiri-env-exclude=` keeps the `var` environment variable isolated from the host so that it cannot be accessed by the program. Can be used multiple times to exclude several variables. The - `TERM` environment variable is excluded by default to [speed up the test - harness](https://github.com/rust-lang/miri/issues/1702). This has no effect unless - `-Zmiri-disable-isolation` is also set. + `TERM` environment variable is excluded by default in Windows to prevent the libtest harness from + accessing the file system. This has no effect unless `-Zmiri-disable-isolation` is also set. * `-Zmiri-env-forward=` forwards the `var` environment variable to the interpreted program. Can be used multiple times to forward several variables. This takes precedence over `-Zmiri-env-exclude`: if a variable is both forwarded and exluced, it *will* get forwarded. This diff --git a/src/shims/env.rs b/src/shims/env.rs index db1ddf6291fd9..3dd0b65d0290d 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -42,10 +42,11 @@ impl<'tcx> EnvVars<'tcx> { config: &MiriConfig, ) -> InterpResult<'tcx> { let target_os = ecx.tcx.sess.target.os.as_ref(); - // HACK: Exclude `TERM` var to avoid terminfo trying to open the termcap file. - // This is (a) very slow and (b) does not work on Windows. let mut excluded_env_vars = config.excluded_env_vars.clone(); - excluded_env_vars.push("TERM".to_owned()); + if target_os == "windows" { + // HACK: Exclude `TERM` var to avoid terminfo trying to open the termcap file. + excluded_env_vars.push("TERM".to_owned()); + } // Skip the loop entirely if we don't want to forward anything. if ecx.machine.communicate() || !config.forwarded_env_vars.is_empty() { From 437d2414124b9f7409c00ceb86008c1945e1fb7a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 6 Aug 2022 11:53:18 -0400 Subject: [PATCH 3611/3747] move tests covering the env:: module into their own directory --- ci.sh | 2 +- tests/pass/{ => env}/args.rs | 0 tests/pass/{ => env}/args.stdout | 0 tests/pass/{ => env}/current_dir.rs | 0 tests/pass/{ => env}/current_dir_with_isolation.rs | 0 tests/pass/{ => env}/current_dir_with_isolation.stderr | 0 tests/pass/{ => env}/current_exe.rs | 1 + tests/pass/{ => env}/home.rs | 0 tests/pass/{env-exclude.rs => env/var-exclude.rs} | 0 tests/pass/{env-forward.rs => env/var-forward.rs} | 0 .../var-without-isolation.rs} | 0 tests/pass/{env.rs => env/var.rs} | 0 tests/pass/{env.stdout => env/var.stdout} | 0 tests/pass/libc.rs | 4 ++-- 14 files changed, 4 insertions(+), 3 deletions(-) rename tests/pass/{ => env}/args.rs (100%) rename tests/pass/{ => env}/args.stdout (100%) rename tests/pass/{ => env}/current_dir.rs (100%) rename tests/pass/{ => env}/current_dir_with_isolation.rs (100%) rename tests/pass/{ => env}/current_dir_with_isolation.stderr (100%) rename tests/pass/{ => env}/current_exe.rs (68%) rename tests/pass/{ => env}/home.rs (100%) rename tests/pass/{env-exclude.rs => env/var-exclude.rs} (100%) rename tests/pass/{env-forward.rs => env/var-forward.rs} (100%) rename tests/pass/{env-without-isolation.rs => env/var-without-isolation.rs} (100%) rename tests/pass/{env.rs => env/var.rs} (100%) rename tests/pass/{env.stdout => env/var.stdout} (100%) diff --git a/ci.sh b/ci.sh index f93c218f1b0ef..67cbed4f826d8 100755 --- a/ci.sh +++ b/ci.sh @@ -80,7 +80,7 @@ case $HOST_TARGET in MIRI_TEST_TARGET=i686-unknown-linux-gnu run_tests MIRI_TEST_TARGET=aarch64-apple-darwin run_tests MIRI_TEST_TARGET=i686-pc-windows-msvc run_tests - MIRI_TEST_TARGET=x86_64-unknown-freebsd run_tests_minimal hello integer vec current_dir data_race env + MIRI_TEST_TARGET=x86_64-unknown-freebsd run_tests_minimal hello integer vec data_race env/var MIRI_TEST_TARGET=thumbv7em-none-eabihf MIRI_NO_STD=1 run_tests_minimal no_std # no_std embedded architecture ;; x86_64-apple-darwin) diff --git a/tests/pass/args.rs b/tests/pass/env/args.rs similarity index 100% rename from tests/pass/args.rs rename to tests/pass/env/args.rs diff --git a/tests/pass/args.stdout b/tests/pass/env/args.stdout similarity index 100% rename from tests/pass/args.stdout rename to tests/pass/env/args.stdout diff --git a/tests/pass/current_dir.rs b/tests/pass/env/current_dir.rs similarity index 100% rename from tests/pass/current_dir.rs rename to tests/pass/env/current_dir.rs diff --git a/tests/pass/current_dir_with_isolation.rs b/tests/pass/env/current_dir_with_isolation.rs similarity index 100% rename from tests/pass/current_dir_with_isolation.rs rename to tests/pass/env/current_dir_with_isolation.rs diff --git a/tests/pass/current_dir_with_isolation.stderr b/tests/pass/env/current_dir_with_isolation.stderr similarity index 100% rename from tests/pass/current_dir_with_isolation.stderr rename to tests/pass/env/current_dir_with_isolation.stderr diff --git a/tests/pass/current_exe.rs b/tests/pass/env/current_exe.rs similarity index 68% rename from tests/pass/current_exe.rs rename to tests/pass/env/current_exe.rs index 64f62b230e488..15ea6a52b7b6b 100644 --- a/tests/pass/current_exe.rs +++ b/tests/pass/env/current_exe.rs @@ -1,4 +1,5 @@ //@ignore-target-windows +//@only-on-host: the Linux std implementation opens /proc/self/exe, which doesn't work cross-target //@compile-flags: -Zmiri-disable-isolation use std::env; diff --git a/tests/pass/home.rs b/tests/pass/env/home.rs similarity index 100% rename from tests/pass/home.rs rename to tests/pass/env/home.rs diff --git a/tests/pass/env-exclude.rs b/tests/pass/env/var-exclude.rs similarity index 100% rename from tests/pass/env-exclude.rs rename to tests/pass/env/var-exclude.rs diff --git a/tests/pass/env-forward.rs b/tests/pass/env/var-forward.rs similarity index 100% rename from tests/pass/env-forward.rs rename to tests/pass/env/var-forward.rs diff --git a/tests/pass/env-without-isolation.rs b/tests/pass/env/var-without-isolation.rs similarity index 100% rename from tests/pass/env-without-isolation.rs rename to tests/pass/env/var-without-isolation.rs diff --git a/tests/pass/env.rs b/tests/pass/env/var.rs similarity index 100% rename from tests/pass/env.rs rename to tests/pass/env/var.rs diff --git a/tests/pass/env.stdout b/tests/pass/env/var.stdout similarity index 100% rename from tests/pass/env.stdout rename to tests/pass/env/var.stdout diff --git a/tests/pass/libc.rs b/tests/pass/libc.rs index 468da0845a88e..b584856021484 100644 --- a/tests/pass/libc.rs +++ b/tests/pass/libc.rs @@ -88,7 +88,7 @@ fn test_posix_realpath_errors() { assert_eq!(e.kind(), ErrorKind::NotFound); } -#[cfg(any(target_os = "linux", target_os = "freebsd"))] +#[cfg(any(target_os = "linux"))] fn test_posix_fadvise() { use std::convert::TryInto; use std::io::Write; @@ -452,7 +452,7 @@ fn test_posix_mkstemp() { } fn main() { - #[cfg(any(target_os = "linux", target_os = "freebsd"))] + #[cfg(any(target_os = "linux"))] test_posix_fadvise(); test_posix_gettimeofday(); From 79d147edb75299f9d4789b689f9c7f34a7db7709 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 6 Aug 2022 14:34:44 -0400 Subject: [PATCH 3612/3747] make home_dir work on macOS --- src/shims/unix/foreign_items.rs | 36 +++++++++++++++++++++++++++ src/shims/unix/linux/foreign_items.rs | 35 -------------------------- tests/pass/env/home.rs | 2 +- 3 files changed, 37 insertions(+), 36 deletions(-) diff --git a/src/shims/unix/foreign_items.rs b/src/shims/unix/foreign_items.rs index 7dde2d7d2c193..6ea10de0b8a83 100644 --- a/src/shims/unix/foreign_items.rs +++ b/src/shims/unix/foreign_items.rs @@ -553,6 +553,42 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_int(super::UID, dest)?; } + "getpwuid_r" if this.frame_in_std() => { + let [uid, pwd, buf, buflen, result] = + this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + this.check_no_isolation("`getpwuid_r`")?; + + let uid = this.read_scalar(uid)?.to_u32()?; + let pwd = this.deref_operand(pwd)?; + let buf = this.read_pointer(buf)?; + let buflen = this.read_scalar(buflen)?.to_machine_usize(this)?; + let result = this.deref_operand(result)?; + + // Must be for "us". + if uid != crate::shims::unix::UID { + throw_unsup_format!("`getpwuid_r` on other users is not supported"); + } + + // Reset all fields to `uninit` to make sure nobody reads them. + // (This is a std-only shim so we are okay with such hacks.) + this.write_uninit(&pwd.into())?; + + // We only set the home_dir field. + #[allow(deprecated)] + let home_dir = std::env::home_dir().unwrap(); + let (written, _) = this.write_path_to_c_str(&home_dir, buf, buflen)?; + let pw_dir = this.mplace_field_named(&pwd, "pw_dir")?; + this.write_pointer(buf, &pw_dir.into())?; + + if written { + this.write_pointer(pwd.ptr, &result.into())?; + this.write_null(dest)?; + } else { + this.write_null(&result.into())?; + this.write_scalar(this.eval_libc("ERANGE")?, dest)?; + } + } + // Platform-specific shims _ => { match this.tcx.sess.target.os.as_ref() { diff --git a/src/shims/unix/linux/foreign_items.rs b/src/shims/unix/linux/foreign_items.rs index 61016c424954f..bae3780b460c7 100644 --- a/src/shims/unix/linux/foreign_items.rs +++ b/src/shims/unix/linux/foreign_items.rs @@ -155,41 +155,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_null(dest)?; } - "getpwuid_r" if this.frame_in_std() => { - let [uid, pwd, buf, buflen, result] = - this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; - this.check_no_isolation("`getpwuid_r`")?; - - let uid = this.read_scalar(uid)?.to_u32()?; - let pwd = this.deref_operand(pwd)?; - let buf = this.read_pointer(buf)?; - let buflen = this.read_scalar(buflen)?.to_machine_usize(this)?; - let result = this.deref_operand(result)?; - - // Must be for "us". - if uid != crate::shims::unix::UID { - throw_unsup_format!("`getpwuid_r` on other users is not supported"); - } - - // Reset all fields to `uninit` to make sure nobody reads them. - this.write_uninit(&pwd.into())?; - - // We only set the home_dir field. - #[allow(deprecated)] - let home_dir = std::env::home_dir().unwrap(); - let (written, _) = this.write_path_to_c_str(&home_dir, buf, buflen)?; - let pw_dir = this.mplace_field_named(&pwd, "pw_dir")?; - this.write_pointer(buf, &pw_dir.into())?; - - if written { - this.write_pointer(pwd.ptr, &result.into())?; - this.write_null(dest)?; - } else { - this.write_null(&result.into())?; - this.write_scalar(this.eval_libc("ERANGE")?, dest)?; - } - } - _ => return Ok(EmulateByNameResult::NotSupported), }; diff --git a/tests/pass/env/home.rs b/tests/pass/env/home.rs index 0fb69aad00770..9eb9c3af569dd 100644 --- a/tests/pass/env/home.rs +++ b/tests/pass/env/home.rs @@ -1,4 +1,4 @@ -//@only-target-linux: home_dir is only supported on Linux +//@ignore-target-windows: home_dir is not supported on Windows //@compile-flags: -Zmiri-disable-isolation use std::env; From 353f7d539ae628a46ecfa1c316d963633e17e780 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 4 Aug 2022 09:55:18 -0400 Subject: [PATCH 3613/3747] add special exception for std_miri_test crate to call std-only functions --- src/helpers.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/helpers.rs b/src/helpers.rs index 220347ff1b968..7c9f8740eb420 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -803,7 +803,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Fall back to the instance of the function itself. let instance = instance.unwrap_or(frame.instance); // Now check if this is in the same crate as start_fn. - this.tcx.def_path(instance.def_id()).krate == this.tcx.def_path(start_fn).krate + // As a special exception we also allow unit tests from + // to call these + // shims. + let frame_crate = this.tcx.def_path(instance.def_id()).krate; + frame_crate == this.tcx.def_path(start_fn).krate + || this.tcx.crate_name(frame_crate).as_str() == "std_miri_test" } /// Handler that should be called when unsupported functionality is encountered. From 76d99c37c90496425fb7f3f8e2be4e9c16f276af Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 6 Aug 2022 15:21:08 -0400 Subject: [PATCH 3614/3747] fix RUSTC_BACKTRACE always being set --- src/bin/miri.rs | 7 +++++++ src/eval.rs | 6 +++++- src/shims/env.rs | 8 ++++---- 3 files changed, 16 insertions(+), 5 deletions(-) diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 489eb959906c9..430f9e2f637ba 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -306,6 +306,11 @@ fn parse_comma_list(input: &str) -> Result, T::Err> { } fn main() { + // Snapshot a copy of the environment before `rustc` starts messing with it. + // (`install_ice_hook` might change `RUST_BACKTRACE`.) + let env_snapshot = env::vars_os().collect::>(); + + // Earliest rustc setup. rustc_driver::install_ice_hook(); // If the environment asks us to actually be rustc, then do that. @@ -333,6 +338,8 @@ fn main() { // Parse our arguments and split them across `rustc` and `miri`. let mut miri_config = miri::MiriConfig::default(); + miri_config.env = env_snapshot; + let mut rustc_args = vec![]; let mut after_dashdash = false; diff --git a/src/eval.rs b/src/eval.rs index cb24dea3a88dd..981776e3eebd2 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -1,7 +1,7 @@ //! Main evaluator loop and setting up the initial stack frame. use std::collections::HashSet; -use std::ffi::OsStr; +use std::ffi::{OsStr, OsString}; use std::iter; use std::panic::{self, AssertUnwindSafe}; use std::thread; @@ -72,6 +72,9 @@ pub enum BacktraceStyle { /// Configuration needed to spawn a Miri instance. #[derive(Clone)] pub struct MiriConfig { + /// The host environment snapshot to use as basis for what is provided to the interpreted program. + /// (This is still subject to isolation as well as `excluded_env_vars` and `forwarded_env_vars`.) + pub env: Vec<(OsString, OsString)>, /// Determine if validity checking is enabled. pub validate: bool, /// Determines if Stacked Borrows is enabled. @@ -130,6 +133,7 @@ pub struct MiriConfig { impl Default for MiriConfig { fn default() -> MiriConfig { MiriConfig { + env: vec![], validate: true, stacked_borrows: true, check_alignment: AlignmentCheck::Int, diff --git a/src/shims/env.rs b/src/shims/env.rs index db1ddf6291fd9..07b9cf18192c8 100644 --- a/src/shims/env.rs +++ b/src/shims/env.rs @@ -49,11 +49,11 @@ impl<'tcx> EnvVars<'tcx> { // Skip the loop entirely if we don't want to forward anything. if ecx.machine.communicate() || !config.forwarded_env_vars.is_empty() { - for (name, value) in env::vars_os() { + for (name, value) in &config.env { // Always forward what is in `forwarded_env_vars`; that list can take precedence over excluded_env_vars. - let forward = config.forwarded_env_vars.iter().any(|v| **v == name) + let forward = config.forwarded_env_vars.iter().any(|v| **v == *name) || (ecx.machine.communicate() - && !excluded_env_vars.iter().any(|v| **v == name)); + && !excluded_env_vars.iter().any(|v| **v == *name)); if forward { let var_ptr = match target_os { target if target_os_is_unix(target) => @@ -65,7 +65,7 @@ impl<'tcx> EnvVars<'tcx> { unsupported ), }; - ecx.machine.env_vars.map.insert(name, var_ptr); + ecx.machine.env_vars.map.insert(name.clone(), var_ptr); } } } From d2ba40e9e1ff18f14b2d75462c0f7d7afcae7e76 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 6 Aug 2022 15:29:43 -0400 Subject: [PATCH 3615/3747] make tests pass again --- src/bin/miri.rs | 6 +++++- tests/pass/backtrace/backtrace-global-alloc.rs | 1 + tests/pass/backtrace/backtrace-std.rs | 1 + 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 430f9e2f637ba..dcccdecc6cf14 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -1,5 +1,9 @@ #![feature(rustc_private, stmt_expr_attributes)] -#![allow(clippy::manual_range_contains, clippy::useless_format)] +#![allow( + clippy::manual_range_contains, + clippy::useless_format, + clippy::field_reassign_with_default +)] extern crate rustc_data_structures; extern crate rustc_driver; diff --git a/tests/pass/backtrace/backtrace-global-alloc.rs b/tests/pass/backtrace/backtrace-global-alloc.rs index 45d6535bc139a..406a5b62333d4 100644 --- a/tests/pass/backtrace/backtrace-global-alloc.rs +++ b/tests/pass/backtrace/backtrace-global-alloc.rs @@ -1,4 +1,5 @@ //@compile-flags: -Zmiri-disable-isolation +//@rustc-env: RUST_BACKTRACE=1 #![feature(backtrace)] diff --git a/tests/pass/backtrace/backtrace-std.rs b/tests/pass/backtrace/backtrace-std.rs index 488b87ede8fc9..9106310e513dc 100644 --- a/tests/pass/backtrace/backtrace-std.rs +++ b/tests/pass/backtrace/backtrace-std.rs @@ -1,4 +1,5 @@ //@compile-flags: -Zmiri-disable-isolation +//@rustc-env: RUST_BACKTRACE=1 #![feature(backtrace)] From 141d5a6396d1763d2e753edd60d3e6311c13c4c9 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 6 Aug 2022 15:30:00 -0400 Subject: [PATCH 3616/3747] avoid panic/panic folder --- tests/panic/{panic => }/div-by-zero-2.rs | 0 tests/panic/{panic => }/div-by-zero-2.stderr | 0 tests/panic/{panic => }/overflowing-lsh-neg.rs | 0 tests/panic/{panic => }/overflowing-lsh-neg.stderr | 0 tests/panic/{panic => }/overflowing-rsh-1.rs | 0 tests/panic/{panic => }/overflowing-rsh-1.stderr | 0 tests/panic/{panic => }/overflowing-rsh-2.rs | 0 tests/panic/{panic => }/overflowing-rsh-2.stderr | 0 tests/panic/{panic => }/panic1.rs | 0 tests/panic/{panic => }/panic1.stderr | 0 tests/panic/{panic => }/panic2.rs | 0 tests/panic/{panic => }/panic2.stderr | 0 tests/panic/{panic => }/panic3.rs | 0 tests/panic/{panic => }/panic3.stderr | 0 tests/panic/{panic => }/panic4.rs | 0 tests/panic/{panic => }/panic4.stderr | 0 tests/panic/{panic => }/unsupported_foreign_function.rs | 0 tests/panic/{panic => }/unsupported_foreign_function.stderr | 0 tests/panic/{panic => }/unsupported_syscall.rs | 0 tests/panic/{panic => }/unsupported_syscall.stderr | 0 20 files changed, 0 insertions(+), 0 deletions(-) rename tests/panic/{panic => }/div-by-zero-2.rs (100%) rename tests/panic/{panic => }/div-by-zero-2.stderr (100%) rename tests/panic/{panic => }/overflowing-lsh-neg.rs (100%) rename tests/panic/{panic => }/overflowing-lsh-neg.stderr (100%) rename tests/panic/{panic => }/overflowing-rsh-1.rs (100%) rename tests/panic/{panic => }/overflowing-rsh-1.stderr (100%) rename tests/panic/{panic => }/overflowing-rsh-2.rs (100%) rename tests/panic/{panic => }/overflowing-rsh-2.stderr (100%) rename tests/panic/{panic => }/panic1.rs (100%) rename tests/panic/{panic => }/panic1.stderr (100%) rename tests/panic/{panic => }/panic2.rs (100%) rename tests/panic/{panic => }/panic2.stderr (100%) rename tests/panic/{panic => }/panic3.rs (100%) rename tests/panic/{panic => }/panic3.stderr (100%) rename tests/panic/{panic => }/panic4.rs (100%) rename tests/panic/{panic => }/panic4.stderr (100%) rename tests/panic/{panic => }/unsupported_foreign_function.rs (100%) rename tests/panic/{panic => }/unsupported_foreign_function.stderr (100%) rename tests/panic/{panic => }/unsupported_syscall.rs (100%) rename tests/panic/{panic => }/unsupported_syscall.stderr (100%) diff --git a/tests/panic/panic/div-by-zero-2.rs b/tests/panic/div-by-zero-2.rs similarity index 100% rename from tests/panic/panic/div-by-zero-2.rs rename to tests/panic/div-by-zero-2.rs diff --git a/tests/panic/panic/div-by-zero-2.stderr b/tests/panic/div-by-zero-2.stderr similarity index 100% rename from tests/panic/panic/div-by-zero-2.stderr rename to tests/panic/div-by-zero-2.stderr diff --git a/tests/panic/panic/overflowing-lsh-neg.rs b/tests/panic/overflowing-lsh-neg.rs similarity index 100% rename from tests/panic/panic/overflowing-lsh-neg.rs rename to tests/panic/overflowing-lsh-neg.rs diff --git a/tests/panic/panic/overflowing-lsh-neg.stderr b/tests/panic/overflowing-lsh-neg.stderr similarity index 100% rename from tests/panic/panic/overflowing-lsh-neg.stderr rename to tests/panic/overflowing-lsh-neg.stderr diff --git a/tests/panic/panic/overflowing-rsh-1.rs b/tests/panic/overflowing-rsh-1.rs similarity index 100% rename from tests/panic/panic/overflowing-rsh-1.rs rename to tests/panic/overflowing-rsh-1.rs diff --git a/tests/panic/panic/overflowing-rsh-1.stderr b/tests/panic/overflowing-rsh-1.stderr similarity index 100% rename from tests/panic/panic/overflowing-rsh-1.stderr rename to tests/panic/overflowing-rsh-1.stderr diff --git a/tests/panic/panic/overflowing-rsh-2.rs b/tests/panic/overflowing-rsh-2.rs similarity index 100% rename from tests/panic/panic/overflowing-rsh-2.rs rename to tests/panic/overflowing-rsh-2.rs diff --git a/tests/panic/panic/overflowing-rsh-2.stderr b/tests/panic/overflowing-rsh-2.stderr similarity index 100% rename from tests/panic/panic/overflowing-rsh-2.stderr rename to tests/panic/overflowing-rsh-2.stderr diff --git a/tests/panic/panic/panic1.rs b/tests/panic/panic1.rs similarity index 100% rename from tests/panic/panic/panic1.rs rename to tests/panic/panic1.rs diff --git a/tests/panic/panic/panic1.stderr b/tests/panic/panic1.stderr similarity index 100% rename from tests/panic/panic/panic1.stderr rename to tests/panic/panic1.stderr diff --git a/tests/panic/panic/panic2.rs b/tests/panic/panic2.rs similarity index 100% rename from tests/panic/panic/panic2.rs rename to tests/panic/panic2.rs diff --git a/tests/panic/panic/panic2.stderr b/tests/panic/panic2.stderr similarity index 100% rename from tests/panic/panic/panic2.stderr rename to tests/panic/panic2.stderr diff --git a/tests/panic/panic/panic3.rs b/tests/panic/panic3.rs similarity index 100% rename from tests/panic/panic/panic3.rs rename to tests/panic/panic3.rs diff --git a/tests/panic/panic/panic3.stderr b/tests/panic/panic3.stderr similarity index 100% rename from tests/panic/panic/panic3.stderr rename to tests/panic/panic3.stderr diff --git a/tests/panic/panic/panic4.rs b/tests/panic/panic4.rs similarity index 100% rename from tests/panic/panic/panic4.rs rename to tests/panic/panic4.rs diff --git a/tests/panic/panic/panic4.stderr b/tests/panic/panic4.stderr similarity index 100% rename from tests/panic/panic/panic4.stderr rename to tests/panic/panic4.stderr diff --git a/tests/panic/panic/unsupported_foreign_function.rs b/tests/panic/unsupported_foreign_function.rs similarity index 100% rename from tests/panic/panic/unsupported_foreign_function.rs rename to tests/panic/unsupported_foreign_function.rs diff --git a/tests/panic/panic/unsupported_foreign_function.stderr b/tests/panic/unsupported_foreign_function.stderr similarity index 100% rename from tests/panic/panic/unsupported_foreign_function.stderr rename to tests/panic/unsupported_foreign_function.stderr diff --git a/tests/panic/panic/unsupported_syscall.rs b/tests/panic/unsupported_syscall.rs similarity index 100% rename from tests/panic/panic/unsupported_syscall.rs rename to tests/panic/unsupported_syscall.rs diff --git a/tests/panic/panic/unsupported_syscall.stderr b/tests/panic/unsupported_syscall.stderr similarity index 100% rename from tests/panic/panic/unsupported_syscall.stderr rename to tests/panic/unsupported_syscall.stderr From e12df0f4043f89bc59eb40e351fdb58f0b545abb Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 6 Aug 2022 19:31:20 -0400 Subject: [PATCH 3617/3747] also forward --manifest-path to 'cargo metadata' --- cargo-miri/src/phases.rs | 1 + cargo-miri/src/util.rs | 38 +++++++++++++++++++++----------------- 2 files changed, 22 insertions(+), 17 deletions(-) diff --git a/cargo-miri/src/phases.rs b/cargo-miri/src/phases.rs index 4ba627de482cf..376b191192f48 100644 --- a/cargo-miri/src/phases.rs +++ b/cargo-miri/src/phases.rs @@ -117,6 +117,7 @@ pub fn phase_cargo_miri(mut args: impl Iterator) { cmd.arg(cargo_cmd); // Forward all arguments before `--` other than `--target-dir` and its value to Cargo. + // (We want to *change* the target-dir value, so we must not forward it.) let mut target_dir = None; for arg in ArgSplitFlagValue::new(&mut args, "--target-dir") { match arg { diff --git a/cargo-miri/src/util.rs b/cargo-miri/src/util.rs index d6a42a2f855dc..729794ed9930c 100644 --- a/cargo-miri/src/util.rs +++ b/cargo-miri/src/util.rs @@ -287,29 +287,33 @@ pub fn write_to_file(filename: &Path, content: &str) { fs::rename(temp_filename, filename).unwrap(); } -pub fn get_cargo_metadata() -> Metadata { - // The `build.target-dir` config can be passed by `--config` flags, so forward them to - // `cargo metadata`. - let mut additional_options = Vec::new(); +// Computes the extra flags that need to be passed to cargo to make it behave like the current +// cargo invocation. +fn cargo_extra_flags() -> Vec { + let mut flags = Vec::new(); // `-Zunstable-options` is required by `--config`. - additional_options.push("-Zunstable-options".to_string()); + flags.push("-Zunstable-options".to_string()); + // Forward `--config` flags. let config_flag = "--config"; - for arg in ArgSplitFlagValue::new( - env::args().skip(3), // skip the program name, "miri" and "run" / "test" - config_flag, - ) - // Only look at `Ok` - .flatten() - { - additional_options.push(config_flag.to_string()); - additional_options.push(arg); + for arg in ArgFlagValueIter::new(config_flag) { + flags.push(config_flag.to_string()); + flags.push(arg); + } + + // Forward `--manifest-path`. + let manifest_flag = "--manifest-path"; + if let Some(manifest) = get_arg_flag_value(manifest_flag) { + flags.push(manifest_flag.to_string()); + flags.push(manifest); } - let metadata = - MetadataCommand::new().no_deps().other_options(additional_options).exec().unwrap(); + flags +} - metadata +pub fn get_cargo_metadata() -> Metadata { + // This will honor the `CARGO` env var the same way our `cargo()` does. + MetadataCommand::new().no_deps().other_options(cargo_extra_flags()).exec().unwrap() } /// Pulls all the crates in this workspace from the cargo metadata. From 465538245a3a8768b9bf33d4fdd448cf32f29921 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 6 Aug 2022 19:41:31 -0400 Subject: [PATCH 3618/3747] reuse arg flag parse logic in rustdoc handling --- cargo-miri/src/phases.rs | 12 ++++++------ cargo-miri/src/util.rs | 21 +++++++++++++-------- 2 files changed, 19 insertions(+), 14 deletions(-) diff --git a/cargo-miri/src/phases.rs b/cargo-miri/src/phases.rs index 376b191192f48..38bc624369563 100644 --- a/cargo-miri/src/phases.rs +++ b/cargo-miri/src/phases.rs @@ -310,17 +310,17 @@ pub fn phase_rustc(mut args: impl Iterator, phase: RustcPhase) { let mut cmd = miri(); // Ensure --emit argument for a check-only build is present. - // We cannot use the usual helpers since we need to check specifically in `env.args`. - if let Some(i) = env.args.iter().position(|arg| arg.starts_with("--emit=")) { + if let Some(val) = ArgFlagValueIter::new(env.args.clone().into_iter(), "--emit").next() + { // For `no_run` tests, rustdoc passes a `--emit` flag; make sure it has the right shape. - assert_eq!(env.args[i], "--emit=metadata"); + assert_eq!(val, "metadata"); } else { // For all other kinds of tests, we can just add our flag. cmd.arg("--emit=metadata"); } // Alter the `-o` parameter so that it does not overwrite the JSON file we stored above. - let mut args = env.args.clone(); + let mut args = env.args; for i in 0..args.len() { if args[i] == "-o" { args[i + 1].push_str(".miri"); @@ -344,7 +344,7 @@ pub fn phase_rustc(mut args: impl Iterator, phase: RustcPhase) { return; } - if runnable_crate && ArgFlagValueIter::new("--extern").any(|krate| krate == "proc_macro") { + if runnable_crate && get_arg_flag_values("--extern").any(|krate| krate == "proc_macro") { // This is a "runnable" `proc-macro` crate (unit tests). We do not support // interpreting that under Miri now, so we write a JSON file to (display a // helpful message and) skip it in the runner phase. @@ -568,7 +568,7 @@ pub fn phase_rustdoc(mut args: impl Iterator) { // Doctests of `proc-macro` crates (and their dependencies) are always built for the host, // so we are not able to run them in Miri. - if ArgFlagValueIter::new("--crate-type").any(|crate_type| crate_type == "proc-macro") { + if get_arg_flag_values("--crate-type").any(|crate_type| crate_type == "proc-macro") { eprintln!("Running doctests of `proc-macro` crates is not currently supported by Miri."); return; } diff --git a/cargo-miri/src/util.rs b/cargo-miri/src/util.rs index 729794ed9930c..27e312a4662a0 100644 --- a/cargo-miri/src/util.rs +++ b/cargo-miri/src/util.rs @@ -81,7 +81,7 @@ pub fn has_arg_flag(name: &str) -> bool { /// Determines how many times a `--flag` is present. pub fn num_arg_flag(name: &str) -> usize { - std::env::args().take_while(|val| val != "--").filter(|val| val == name).count() + env::args().take_while(|val| val != "--").filter(|val| val == name).count() } /// Yields all values of command line flag `name` as `Ok(arg)`, and all other arguments except @@ -121,15 +121,15 @@ impl> Iterator for ArgSplitFlagValue<'_, I> { } /// Yields all values of command line flag `name`. -pub struct ArgFlagValueIter<'a>(ArgSplitFlagValue<'a, env::Args>); +pub struct ArgFlagValueIter<'a, I>(ArgSplitFlagValue<'a, I>); -impl<'a> ArgFlagValueIter<'a> { - pub fn new(name: &'a str) -> Self { - Self(ArgSplitFlagValue::new(env::args(), name)) +impl<'a, I: Iterator> ArgFlagValueIter<'a, I> { + pub fn new(args: I, name: &'a str) -> Self { + Self(ArgSplitFlagValue::new(args, name)) } } -impl Iterator for ArgFlagValueIter<'_> { +impl> Iterator for ArgFlagValueIter<'_, I> { type Item = String; fn next(&mut self) -> Option { @@ -141,9 +141,14 @@ impl Iterator for ArgFlagValueIter<'_> { } } +/// Gets the values of a `--flag`. +pub fn get_arg_flag_values<'a>(name: &'a str) -> impl Iterator + 'a { + ArgFlagValueIter::new(env::args(), name) +} + /// Gets the value of a `--flag`. pub fn get_arg_flag_value(name: &str) -> Option { - ArgFlagValueIter::new(name).next() + get_arg_flag_values(name).next() } /// Escapes `s` in a way that is suitable for using it as a string literal in TOML syntax. @@ -296,7 +301,7 @@ fn cargo_extra_flags() -> Vec { // Forward `--config` flags. let config_flag = "--config"; - for arg in ArgFlagValueIter::new(config_flag) { + for arg in get_arg_flag_values(config_flag) { flags.push(config_flag.to_string()); flags.push(arg); } From 08e7d945629b32b32c34d5df84d881292e6f0451 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 6 Aug 2022 21:17:54 -0400 Subject: [PATCH 3619/3747] avoid some string copies... --- cargo-miri/src/arg.rs | 134 +++++++++++++++++++++++++++++++++++++++ cargo-miri/src/main.rs | 1 + cargo-miri/src/phases.rs | 5 +- cargo-miri/src/util.rs | 80 +---------------------- 4 files changed, 140 insertions(+), 80 deletions(-) create mode 100644 cargo-miri/src/arg.rs diff --git a/cargo-miri/src/arg.rs b/cargo-miri/src/arg.rs new file mode 100644 index 0000000000000..e8bac4625f710 --- /dev/null +++ b/cargo-miri/src/arg.rs @@ -0,0 +1,134 @@ +//! Utilities for dealing with argument flags + +use std::borrow::Cow; +use std::env; + +/// Determines whether a `--flag` is present. +pub fn has_arg_flag(name: &str) -> bool { + num_arg_flag(name) > 0 +} + +/// Determines how many times a `--flag` is present. +pub fn num_arg_flag(name: &str) -> usize { + env::args().take_while(|val| val != "--").filter(|val| val == name).count() +} + +/// Yields all values of command line flag `name` as `Ok(arg)`, and all other arguments except +/// the flag as `Err(arg)`. (The flag `name` itself is not yielded at all, only its values are.) +pub struct ArgSplitFlagValue<'a, I> { + args: Option, + name: &'a str, +} + +impl<'a, I: Iterator> ArgSplitFlagValue<'a, I> { + fn new(args: I, name: &'a str) -> Self { + Self { args: Some(args), name } + } +} + +impl<'s, I: Iterator>> Iterator for ArgSplitFlagValue<'_, I> { + // If the original iterator was all `Owned`, then we will only ever yield `Owned` + // (so `into_owned()` is cheap). + type Item = Result, Cow<'s, str>>; + + fn next(&mut self) -> Option { + let Some(args) = self.args.as_mut() else { + // We already canceled this iterator. + return None; + }; + let arg = args.next()?; + if arg == "--" { + // Stop searching at `--`. + self.args = None; + return None; + } + // These branches cannot be merged if we want to avoid the allocation in the `Borrowed` branch. + match &arg { + Cow::Borrowed(arg) => + if let Some(suffix) = arg.strip_prefix(self.name) { + // Strip leading `name`. + if suffix.is_empty() { + // This argument is exactly `name`; the next one is the value. + return args.next().map(Ok); + } else if let Some(suffix) = suffix.strip_prefix('=') { + // This argument is `name=value`; get the value. + return Some(Ok(Cow::Borrowed(suffix))); + } + }, + Cow::Owned(arg) => + if let Some(suffix) = arg.strip_prefix(self.name) { + // Strip leading `name`. + if suffix.is_empty() { + // This argument is exactly `name`; the next one is the value. + return args.next().map(Ok); + } else if let Some(suffix) = suffix.strip_prefix('=') { + // This argument is `name=value`; get the value. We need to do an allocation + // here as a `String` cannot be subsliced (what would the lifetime be?). + return Some(Ok(Cow::Owned(suffix.to_owned()))); + } + }, + } + Some(Err(arg)) + } +} + +impl<'a, I: Iterator + 'a> ArgSplitFlagValue<'a, I> { + pub fn from_string_iter( + args: I, + name: &'a str, + ) -> impl Iterator> + 'a { + ArgSplitFlagValue::new(args.map(Cow::Owned), name).map(|x| { + match x { + Ok(Cow::Owned(s)) => Ok(s), + Err(Cow::Owned(s)) => Err(s), + _ => panic!("iterator converted owned to borrowed"), + } + }) + } +} + +impl<'x: 'a, 'a, I: Iterator + 'a> ArgSplitFlagValue<'a, I> { + pub fn from_str_iter( + args: I, + name: &'a str, + ) -> impl Iterator> + 'a { + ArgSplitFlagValue::new(args.map(Cow::Borrowed), name).map(|x| { + match x { + Ok(Cow::Borrowed(s)) => Ok(s), + Err(Cow::Borrowed(s)) => Err(s), + _ => panic!("iterator converted borrowed to owned"), + } + }) + } +} + +/// Yields all values of command line flag `name`. +pub struct ArgFlagValueIter; + +impl ArgFlagValueIter { + pub fn from_string_iter<'a, I: Iterator + 'a>( + args: I, + name: &'a str, + ) -> impl Iterator + 'a { + ArgSplitFlagValue::from_string_iter(args, name).filter_map(Result::ok) + } +} + +impl ArgFlagValueIter { + pub fn from_str_iter<'x: 'a, 'a, I: Iterator + 'a>( + args: I, + name: &'a str, + ) -> impl Iterator + 'a { + ArgSplitFlagValue::from_str_iter(args, name).filter_map(Result::ok) + } +} + +/// Gets the values of a `--flag`. +pub fn get_arg_flag_values(name: &str) -> impl Iterator + '_ { + ArgFlagValueIter::from_string_iter(env::args(), name) +} + +/// Gets the value of a `--flag`. +pub fn get_arg_flag_value(name: &str) -> Option { + get_arg_flag_values(name).next() +} diff --git a/cargo-miri/src/main.rs b/cargo-miri/src/main.rs index 9c07f90a40782..f809eecf96af8 100644 --- a/cargo-miri/src/main.rs +++ b/cargo-miri/src/main.rs @@ -1,6 +1,7 @@ #![feature(let_else)] #![allow(clippy::useless_format, clippy::derive_partial_eq_without_eq)] +mod arg; mod phases; mod setup; mod util; diff --git a/cargo-miri/src/phases.rs b/cargo-miri/src/phases.rs index 38bc624369563..d0c0dafe071af 100644 --- a/cargo-miri/src/phases.rs +++ b/cargo-miri/src/phases.rs @@ -119,7 +119,7 @@ pub fn phase_cargo_miri(mut args: impl Iterator) { // Forward all arguments before `--` other than `--target-dir` and its value to Cargo. // (We want to *change* the target-dir value, so we must not forward it.) let mut target_dir = None; - for arg in ArgSplitFlagValue::new(&mut args, "--target-dir") { + for arg in ArgSplitFlagValue::from_string_iter(&mut args, "--target-dir") { match arg { Ok(value) => { if target_dir.is_some() { @@ -310,7 +310,8 @@ pub fn phase_rustc(mut args: impl Iterator, phase: RustcPhase) { let mut cmd = miri(); // Ensure --emit argument for a check-only build is present. - if let Some(val) = ArgFlagValueIter::new(env.args.clone().into_iter(), "--emit").next() + if let Some(val) = + ArgFlagValueIter::from_str_iter(env.args.iter().map(|s| s as &str), "--emit").next() { // For `no_run` tests, rustdoc passes a `--emit` flag; make sure it has the right shape. assert_eq!(val, "metadata"); diff --git a/cargo-miri/src/util.rs b/cargo-miri/src/util.rs index 27e312a4662a0..04cfd2077bb72 100644 --- a/cargo-miri/src/util.rs +++ b/cargo-miri/src/util.rs @@ -4,7 +4,6 @@ use std::ffi::OsString; use std::fmt::Write as _; use std::fs::{self, File}; use std::io::{self, BufWriter, Read, Write}; -use std::iter::TakeWhile; use std::ops::Not; use std::path::{Path, PathBuf}; use std::process::Command; @@ -13,6 +12,8 @@ use cargo_metadata::{Metadata, MetadataCommand}; use rustc_version::VersionMeta; use serde::{Deserialize, Serialize}; +pub use crate::arg::*; + /// The information to run a crate with the given environment. #[derive(Clone, Serialize, Deserialize)] pub struct CrateRunEnv { @@ -74,83 +75,6 @@ pub fn show_error(msg: String) -> ! { std::process::exit(1) } -/// Determines whether a `--flag` is present. -pub fn has_arg_flag(name: &str) -> bool { - num_arg_flag(name) > 0 -} - -/// Determines how many times a `--flag` is present. -pub fn num_arg_flag(name: &str) -> usize { - env::args().take_while(|val| val != "--").filter(|val| val == name).count() -} - -/// Yields all values of command line flag `name` as `Ok(arg)`, and all other arguments except -/// the flag as `Err(arg)`. (The flag `name` itself is not yielded at all, only its values are.) -pub struct ArgSplitFlagValue<'a, I> { - args: TakeWhile bool>, - name: &'a str, -} - -impl<'a, I: Iterator> ArgSplitFlagValue<'a, I> { - pub fn new(args: I, name: &'a str) -> Self { - Self { - // Stop searching at `--`. - args: args.take_while(|val| val != "--"), - name, - } - } -} - -impl> Iterator for ArgSplitFlagValue<'_, I> { - type Item = Result; - - fn next(&mut self) -> Option { - let arg = self.args.next()?; - if let Some(suffix) = arg.strip_prefix(self.name) { - // Strip leading `name`. - if suffix.is_empty() { - // This argument is exactly `name`; the next one is the value. - return self.args.next().map(Ok); - } else if let Some(suffix) = suffix.strip_prefix('=') { - // This argument is `name=value`; get the value. - return Some(Ok(suffix.to_owned())); - } - } - Some(Err(arg)) - } -} - -/// Yields all values of command line flag `name`. -pub struct ArgFlagValueIter<'a, I>(ArgSplitFlagValue<'a, I>); - -impl<'a, I: Iterator> ArgFlagValueIter<'a, I> { - pub fn new(args: I, name: &'a str) -> Self { - Self(ArgSplitFlagValue::new(args, name)) - } -} - -impl> Iterator for ArgFlagValueIter<'_, I> { - type Item = String; - - fn next(&mut self) -> Option { - loop { - if let Ok(value) = self.0.next()? { - return Some(value); - } - } - } -} - -/// Gets the values of a `--flag`. -pub fn get_arg_flag_values<'a>(name: &'a str) -> impl Iterator + 'a { - ArgFlagValueIter::new(env::args(), name) -} - -/// Gets the value of a `--flag`. -pub fn get_arg_flag_value(name: &str) -> Option { - get_arg_flag_values(name).next() -} - /// Escapes `s` in a way that is suitable for using it as a string literal in TOML syntax. pub fn escape_for_toml(s: &str) -> String { // We want to surround this string in quotes `"`. So we first escape all quotes, From 04744a2935ba5c3e01af396ff91e24afba212acb Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 6 Aug 2022 22:45:25 -0400 Subject: [PATCH 3620/3747] fix CI benchmark checks --- ci.sh | 4 ++-- miri | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/ci.sh b/ci.sh index 67cbed4f826d8..a29fc3deca58d 100755 --- a/ci.sh +++ b/ci.sh @@ -54,8 +54,8 @@ function run_tests { unset RUSTC MIRI rm -rf .cargo - # Ensure that our benchmarks all work, on the host at least. - if [ -z "${MIRI_TEST_TARGET+exists}" ]; then + # Ensure that our benchmarks all work, but only on Linux hosts. + if [ -z "${MIRI_TEST_TARGET+exists}" ] && [ "$HOST_TARGET" = x86_64-unknown-linux-gnu ] ; then for BENCH in $(ls "bench-cargo-miri"); do cargo miri run --manifest-path bench-cargo-miri/$BENCH/Cargo.toml done diff --git a/miri b/miri index 956b8cca75b88..0295fc3ab3ac3 100755 --- a/miri +++ b/miri @@ -90,13 +90,13 @@ bench) # Make sure we have an up-to-date Miri installed "$0" install # Run the requested benchmarks - if [ -z "$@" ]; then + if [ -z "${1+exists}" ]; then BENCHES=( $(ls "$MIRIDIR/bench-cargo-miri" ) ) else BENCHES=("$@") fi for BENCH in "${BENCHES[@]}"; do - hyperfine -w 1 -m 5 --shell=none "cargo +$TOOLCHAIN miri run --manifest-path bench-cargo-miri/$BENCH/Cargo.toml" + hyperfine -w 1 -m 5 --shell=none "cargo +$TOOLCHAIN miri run --manifest-path $MIRIDIR/bench-cargo-miri/$BENCH/Cargo.toml" done exit 0 ;; From 366d11b2d8d1d5c51bc4a5f056debac77a01c071 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 7 Aug 2022 09:17:16 -0400 Subject: [PATCH 3621/3747] enable rustc lints (but not in cargo-miri and ui_test) --- cargo-miri/src/main.rs | 2 +- miri | 2 ++ ui_test/src/lib.rs | 7 ++++++- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/cargo-miri/src/main.rs b/cargo-miri/src/main.rs index f809eecf96af8..7b16af6f0c64e 100644 --- a/cargo-miri/src/main.rs +++ b/cargo-miri/src/main.rs @@ -1,5 +1,5 @@ #![feature(let_else)] -#![allow(clippy::useless_format, clippy::derive_partial_eq_without_eq)] +#![allow(clippy::useless_format, clippy::derive_partial_eq_without_eq, rustc::internal)] mod arg; mod phases; diff --git a/miri b/miri index 0295fc3ab3ac3..5893d0ca05f2a 100755 --- a/miri +++ b/miri @@ -124,6 +124,8 @@ fi if [ -z "$CARGO_PROFILE_DEV_OPT_LEVEL" ]; then export CARGO_PROFILE_DEV_OPT_LEVEL=2 fi +# Enable rustc-specific lints +export RUSTFLAGS="-Zunstable-options -Wrustc::internal $RUSTFLAGS" # We set the rpath so that Miri finds the private rustc libraries it needs. export RUSTFLAGS="-C link-args=-Wl,-rpath,$LIBDIR $RUSTFLAGS" diff --git a/ui_test/src/lib.rs b/ui_test/src/lib.rs index 9206c0f3d8e58..871574c4936df 100644 --- a/ui_test/src/lib.rs +++ b/ui_test/src/lib.rs @@ -1,4 +1,9 @@ -#![allow(clippy::enum_variant_names, clippy::useless_format, clippy::too_many_arguments)] +#![allow( + clippy::enum_variant_names, + clippy::useless_format, + clippy::too_many_arguments, + rustc::internal +)] use std::collections::VecDeque; use std::ffi::OsString; From b36b5e38b73e8253e15ed94a7194e335572f4e57 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 7 Aug 2022 09:46:52 -0400 Subject: [PATCH 3622/3747] fix rustc lints in Miri --- miri | 2 +- src/bin/miri.rs | 5 +++-- src/eval.rs | 14 +++++++------- src/lib.rs | 4 +++- src/machine.rs | 9 ++++----- src/shims/intrinsics/mod.rs | 7 +++++-- src/stacked_borrows/mod.rs | 12 ++++++------ src/sync.rs | 7 ++++--- 8 files changed, 33 insertions(+), 27 deletions(-) diff --git a/miri b/miri index 5893d0ca05f2a..5088a9ceffdbb 100755 --- a/miri +++ b/miri @@ -124,7 +124,7 @@ fi if [ -z "$CARGO_PROFILE_DEV_OPT_LEVEL" ]; then export CARGO_PROFILE_DEV_OPT_LEVEL=2 fi -# Enable rustc-specific lints +# Enable rustc-specific lints (ignored without `-Zunstable-options`). export RUSTFLAGS="-Zunstable-options -Wrustc::internal $RUSTFLAGS" # We set the rpath so that Miri finds the private rustc libraries it needs. export RUSTFLAGS="-C link-args=-Wl,-rpath,$LIBDIR $RUSTFLAGS" diff --git a/src/bin/miri.rs b/src/bin/miri.rs index dcccdecc6cf14..b5a45d162f21b 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -101,13 +101,14 @@ struct MiriBeRustCompilerCalls { } impl rustc_driver::Callbacks for MiriBeRustCompilerCalls { + #[allow(rustc::potential_query_instability)] // rustc_codegen_ssa (where this code is copied from) also allows this lint fn config(&mut self, config: &mut Config) { if config.opts.prints.is_empty() && self.target_crate { // Queries overriden here affect the data stored in `rmeta` files of dependencies, // which will be used later in non-`MIRI_BE_RUSTC` mode. config.override_queries = Some(|_, local_providers, _| { - // `exported_symbols()` provided by rustc always returns empty result if - // `tcx.sess.opts.output_types.should_codegen()` is false. + // `exported_symbols` and `reachable_non_generics` provided by rustc always returns + // an empty result if `tcx.sess.opts.output_types.should_codegen()` is false. local_providers.exported_symbols = |tcx, cnum| { assert_eq!(cnum, LOCAL_CRATE); tcx.arena.alloc_from_iter( diff --git a/src/eval.rs b/src/eval.rs index 981776e3eebd2..12e895852d22e 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -1,6 +1,5 @@ //! Main evaluator loop and setting up the initial stack frame. -use std::collections::HashSet; use std::ffi::{OsStr, OsString}; use std::iter; use std::panic::{self, AssertUnwindSafe}; @@ -8,6 +7,7 @@ use std::thread; use log::info; +use rustc_data_structures::fx::FxHashSet; use rustc_hir::def_id::DefId; use rustc_middle::ty::{ self, @@ -96,11 +96,11 @@ pub struct MiriConfig { /// The seed to use when non-determinism or randomness are required (e.g. ptr-to-int cast, `getrandom()`). pub seed: Option, /// The stacked borrows pointer ids to report about - pub tracked_pointer_tags: HashSet, + pub tracked_pointer_tags: FxHashSet, /// The stacked borrows call IDs to report about - pub tracked_call_ids: HashSet, + pub tracked_call_ids: FxHashSet, /// The allocation ids to report about. - pub tracked_alloc_ids: HashSet, + pub tracked_alloc_ids: FxHashSet, /// Determine if data race detection should be enabled pub data_race_detector: bool, /// Determine if weak memory emulation should be enabled. Requires data race detection to be enabled @@ -144,9 +144,9 @@ impl Default for MiriConfig { forwarded_env_vars: vec![], args: vec![], seed: None, - tracked_pointer_tags: HashSet::default(), - tracked_call_ids: HashSet::default(), - tracked_alloc_ids: HashSet::default(), + tracked_pointer_tags: FxHashSet::default(), + tracked_call_ids: FxHashSet::default(), + tracked_alloc_ids: FxHashSet::default(), data_race_detector: true, weak_memory_emulation: true, track_outdated_loads: false, diff --git a/src/lib.rs b/src/lib.rs index 8b1c18a499f6c..94958b2ff5fb2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -23,7 +23,9 @@ clippy::derive_partial_eq_without_eq, clippy::derive_hash_xor_eq, clippy::too_many_arguments, - clippy::type_complexity + clippy::type_complexity, + // We are not implementing queries here so it's fine + rustc::potential_query_instability )] #![warn( rust_2018_idioms, diff --git a/src/machine.rs b/src/machine.rs index 2c9bfe803ad2f..14df64d8aa308 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -3,7 +3,6 @@ use std::borrow::Cow; use std::cell::RefCell; -use std::collections::HashSet; use std::fmt; use std::time::Instant; @@ -11,7 +10,7 @@ use rand::rngs::StdRng; use rand::SeedableRng; use rustc_ast::ast::Mutability; -use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; #[allow(unused)] use rustc_data_structures::static_assert_size; use rustc_middle::{ @@ -19,7 +18,7 @@ use rustc_middle::{ ty::{ self, layout::{LayoutCx, LayoutError, LayoutOf, TyAndLayout}, - Instance, TyCtxt, TypeAndMut, + Instance, Ty, TyCtxt, TypeAndMut, }, }; use rustc_span::def_id::{CrateNum, DefId}; @@ -335,7 +334,7 @@ pub struct Evaluator<'mir, 'tcx> { /// The allocation IDs to report when they are being allocated /// (helps for debugging memory leaks and use after free bugs). - tracked_alloc_ids: HashSet, + tracked_alloc_ids: FxHashSet, /// Controls whether alignment of memory accesses is being checked. pub(crate) check_alignment: AlignmentCheck, @@ -613,7 +612,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { bin_op: mir::BinOp, left: &ImmTy<'tcx, Provenance>, right: &ImmTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, (Scalar, bool, ty::Ty<'tcx>)> { + ) -> InterpResult<'tcx, (Scalar, bool, Ty<'tcx>)> { ecx.binary_ptr_op(bin_op, left, right) } diff --git a/src/shims/intrinsics/mod.rs b/src/shims/intrinsics/mod.rs index 08a6e0fcc0eef..6b311707c35d8 100644 --- a/src/shims/intrinsics/mod.rs +++ b/src/shims/intrinsics/mod.rs @@ -7,7 +7,10 @@ use log::trace; use rustc_apfloat::{Float, Round}; use rustc_middle::ty::layout::{IntegerExt, LayoutOf}; -use rustc_middle::{mir, ty, ty::FloatTy}; +use rustc_middle::{ + mir, + ty::{self, FloatTy, Ty}, +}; use rustc_target::abi::Integer; use crate::*; @@ -377,7 +380,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn float_to_int_unchecked( &self, f: F, - dest_ty: ty::Ty<'tcx>, + dest_ty: Ty<'tcx>, ) -> InterpResult<'tcx, Scalar> where F: Float + Into>, diff --git a/src/stacked_borrows/mod.rs b/src/stacked_borrows/mod.rs index 624b32dfd4957..e0cc3e81cf0b4 100644 --- a/src/stacked_borrows/mod.rs +++ b/src/stacked_borrows/mod.rs @@ -13,11 +13,11 @@ use rustc_middle::mir::RetagKind; use rustc_middle::ty::{ self, layout::{HasParamEnv, LayoutOf}, + Ty, }; use rustc_span::DUMMY_SP; use rustc_target::abi::Size; use smallvec::SmallVec; -use std::collections::HashSet; use crate::*; @@ -100,9 +100,9 @@ pub struct GlobalStateInner { /// `GlobalStateInner::end_call`. See `Stack::item_popped` for more details. protected_tags: FxHashSet, /// The pointer ids to trace - tracked_pointer_tags: HashSet, + tracked_pointer_tags: FxHashSet, /// The call ids to trace - tracked_call_ids: HashSet, + tracked_call_ids: FxHashSet, /// Whether to recurse into datatypes when searching for pointers to retag. retag_fields: bool, } @@ -154,8 +154,8 @@ impl fmt::Display for RefKind { /// Utilities for initialization and ID generation impl GlobalStateInner { pub fn new( - tracked_pointer_tags: HashSet, - tracked_call_ids: HashSet, + tracked_pointer_tags: FxHashSet, + tracked_call_ids: FxHashSet, retag_fields: bool, ) -> Self { GlobalStateInner { @@ -1013,7 +1013,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Determine mutability and whether to add a protector. // Cannot use `builtin_deref` because that reports *immutable* for `Box`, // making it useless. - fn qualify(ty: ty::Ty<'_>, kind: RetagKind) -> Option<(RefKind, bool)> { + fn qualify(ty: Ty<'_>, kind: RetagKind) -> Option<(RefKind, bool)> { match ty.kind() { // References are simple. ty::Ref(_, _, Mutability::Mut) => diff --git a/src/sync.rs b/src/sync.rs index 5571bbd8f2dc5..de7d528d3346a 100644 --- a/src/sync.rs +++ b/src/sync.rs @@ -1,9 +1,10 @@ -use std::collections::{hash_map::Entry, HashMap, VecDeque}; +use std::collections::{hash_map::Entry, VecDeque}; use std::num::NonZeroU32; use std::ops::Not; use log::trace; +use rustc_data_structures::fx::FxHashMap; use rustc_index::vec::{Idx, IndexVec}; use crate::*; @@ -77,7 +78,7 @@ struct RwLock { writer: Option, /// The readers that currently own the lock and how many times they acquired /// the lock. - readers: HashMap, + readers: FxHashMap, /// The queue of writer threads waiting for this lock. writer_queue: VecDeque, /// The queue of reader threads waiting for this lock. @@ -153,7 +154,7 @@ pub(super) struct SynchronizationState { mutexes: IndexVec, rwlocks: IndexVec, condvars: IndexVec, - futexes: HashMap, + futexes: FxHashMap, } // Private extension trait for local helper methods From 0f1ce435020f111982351d70d8bfe9e7ae2a6bb8 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 7 Aug 2022 11:53:25 -0400 Subject: [PATCH 3623/3747] clarifying comments for target-dir handling --- cargo-miri/src/phases.rs | 1 + cargo-miri/src/util.rs | 2 ++ 2 files changed, 3 insertions(+) diff --git a/cargo-miri/src/phases.rs b/cargo-miri/src/phases.rs index d0c0dafe071af..8635661323d1a 100644 --- a/cargo-miri/src/phases.rs +++ b/cargo-miri/src/phases.rs @@ -133,6 +133,7 @@ pub fn phase_cargo_miri(mut args: impl Iterator) { } } // Detect the target directory if it's not specified via `--target-dir`. + // (`cargo metadata` does not support `--target-dir`, that's why we have to handle this ourselves.) let target_dir = target_dir.get_or_insert_with(|| metadata.target_directory.clone()); // Set `--target-dir` to `miri` inside the original target directory. target_dir.push("miri"); diff --git a/cargo-miri/src/util.rs b/cargo-miri/src/util.rs index 04cfd2077bb72..b5401d71671da 100644 --- a/cargo-miri/src/util.rs +++ b/cargo-miri/src/util.rs @@ -237,6 +237,8 @@ fn cargo_extra_flags() -> Vec { flags.push(manifest); } + // Forwarding `--target-dir` would make sense, but `cargo metadata` does not support that flag. + flags } From 5ead47e623ccaf16aaf5d5932e14212c6bb3f9a8 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 7 Aug 2022 20:36:57 -0400 Subject: [PATCH 3624/3747] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 22daf00bd05de..cac0155e3ce47 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -1f5d8d49eb6111931091f700d07518cd2b80bc18 +93ab13b4e894ab74258c40aaf29872db2b17b6b4 From 12e3f75fd49e094ba5ec2f51576a78a88f2bafeb Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 8 Aug 2022 11:32:31 -0400 Subject: [PATCH 3625/3747] don't make it qutie so easy to get Miri to panic --- src/bin/miri.rs | 58 ++++++++++++++++++++++++++++--------------------- 1 file changed, 33 insertions(+), 25 deletions(-) diff --git a/src/bin/miri.rs b/src/bin/miri.rs index b5a45d162f21b..3325fc97d8257 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -152,11 +152,15 @@ impl rustc_driver::Callbacks for MiriBeRustCompilerCalls { } } -fn show_error(msg: String) -> ! { - eprintln!("fatal error: {}", msg); +fn show_error(msg: &str) -> ! { + eprintln!("fatal error: {msg}"); std::process::exit(1) } +macro_rules! show_error { + ($($tt:tt)*) => { show_error(&format!($($tt)*)) }; +} + fn init_early_loggers() { // Note that our `extern crate log` is *not* the same as rustc's; as a result, we have to // initialize them both, and we always initialize `miri`'s first. @@ -234,19 +238,19 @@ fn host_sysroot() -> Option { env::var_os("RUSTUP_TOOLCHAIN").or_else(|| env::var_os("MULTIRUST_TOOLCHAIN")) { if toolchain_runtime != toolchain { - show_error(format!( + show_error!( "This Miri got built with local toolchain `{toolchain}`, but now is being run under a different toolchain. \n\ Make sure to run Miri in the toolchain it got built with, e.g. via `cargo +{toolchain} miri`." - )); + ) } } format!("{}/toolchains/{}", home, toolchain) } _ => option_env!("RUST_SYSROOT") .unwrap_or_else(|| { - show_error(format!( + show_error!( "To build Miri without rustup, set the `RUST_SYSROOT` env var at build time", - )) + ) }) .to_owned(), }) @@ -272,9 +276,9 @@ fn run_compiler( // Using the built-in default here would be plain wrong, so we *require* // the env var to make sure things make sense. Some(env::var("MIRI_SYSROOT").unwrap_or_else(|_| { - show_error(format!( + show_error!( "Miri was invoked in 'target' mode without `MIRI_SYSROOT` or `--sysroot` being set" - )) + ) })) } else { host_default_sysroot @@ -379,7 +383,9 @@ fn main() { miri_config.check_abi = false; } else if arg == "-Zmiri-disable-isolation" { if matches!(isolation_enabled, Some(true)) { - panic!("-Zmiri-disable-isolation cannot be used along with -Zmiri-isolation-error"); + show_error!( + "-Zmiri-disable-isolation cannot be used along with -Zmiri-isolation-error" + ); } else { isolation_enabled = Some(false); } @@ -390,7 +396,9 @@ fn main() { miri_config.track_outdated_loads = true; } else if let Some(param) = arg.strip_prefix("-Zmiri-isolation-error=") { if matches!(isolation_enabled, Some(false)) { - panic!("-Zmiri-isolation-error cannot be used along with -Zmiri-disable-isolation"); + show_error!( + "-Zmiri-isolation-error cannot be used along with -Zmiri-disable-isolation" + ); } else { isolation_enabled = Some(true); } @@ -402,7 +410,7 @@ fn main() { "warn-nobacktrace" => miri::IsolatedOp::Reject(miri::RejectOpWith::WarningWithoutBacktrace), _ => - panic!( + show_error!( "-Zmiri-isolation-error must be `abort`, `hide`, `warn`, or `warn-nobacktrace`" ), }; @@ -426,11 +434,11 @@ fn main() { ); } else if let Some(param) = arg.strip_prefix("-Zmiri-seed=") { if miri_config.seed.is_some() { - panic!("Cannot specify -Zmiri-seed multiple times!"); + show_error!("Cannot specify -Zmiri-seed multiple times!"); } let seed = u64::from_str_radix(param, 16) - .unwrap_or_else(|_| panic!( - "-Zmiri-seed should only contain valid hex digits [0-9a-fA-F] and fit into a u64 (max 16 characters)" + .unwrap_or_else(|_| show_error!( + "-Zmiri-seed should only contain valid hex digits [0-9a-fA-F] and must fit into a u64 (max 16 characters)" )); miri_config.seed = Some(seed); } else if let Some(param) = arg.strip_prefix("-Zmiri-env-exclude=") { @@ -441,7 +449,7 @@ fn main() { let ids: Vec = match parse_comma_list(param) { Ok(ids) => ids, Err(err) => - panic!( + show_error!( "-Zmiri-track-pointer-tag requires a comma separated list of valid `u64` arguments: {}", err ), @@ -450,14 +458,14 @@ fn main() { if let Some(id) = id { miri_config.tracked_pointer_tags.insert(id); } else { - panic!("-Zmiri-track-pointer-tag requires nonzero arguments"); + show_error!("-Zmiri-track-pointer-tag requires nonzero arguments"); } } } else if let Some(param) = arg.strip_prefix("-Zmiri-track-call-id=") { let ids: Vec = match parse_comma_list(param) { Ok(ids) => ids, Err(err) => - panic!( + show_error!( "-Zmiri-track-call-id requires a comma separated list of valid `u64` arguments: {}", err ), @@ -466,14 +474,14 @@ fn main() { if let Some(id) = id { miri_config.tracked_call_ids.insert(id); } else { - panic!("-Zmiri-track-call-id requires a nonzero argument"); + show_error!("-Zmiri-track-call-id requires a nonzero argument"); } } } else if let Some(param) = arg.strip_prefix("-Zmiri-track-alloc-id=") { let ids: Vec = match parse_comma_list::(param) { Ok(ids) => ids.into_iter().map(miri::AllocId).collect(), Err(err) => - panic!( + show_error!( "-Zmiri-track-alloc-id requires a comma separated list of valid non-zero `u64` arguments: {}", err ), @@ -483,11 +491,11 @@ fn main() { let rate = match param.parse::() { Ok(rate) if rate >= 0.0 && rate <= 1.0 => rate, Ok(_) => - panic!( + show_error!( "-Zmiri-compare-exchange-weak-failure-rate must be between `0.0` and `1.0`" ), Err(err) => - panic!( + show_error!( "-Zmiri-compare-exchange-weak-failure-rate requires a `f64` between `0.0` and `1.0`: {}", err ), @@ -496,9 +504,9 @@ fn main() { } else if let Some(param) = arg.strip_prefix("-Zmiri-preemption-rate=") { let rate = match param.parse::() { Ok(rate) if rate >= 0.0 && rate <= 1.0 => rate, - Ok(_) => panic!("-Zmiri-preemption-rate must be between `0.0` and `1.0`"), + Ok(_) => show_error!("-Zmiri-preemption-rate must be between `0.0` and `1.0`"), Err(err) => - panic!( + show_error!( "-Zmiri-preemption-rate requires a `f64` between `0.0` and `1.0`: {}", err ), @@ -510,7 +518,7 @@ fn main() { } else if let Some(param) = arg.strip_prefix("-Zmiri-report-progress=") { let interval = match param.parse::() { Ok(i) => i, - Err(err) => panic!("-Zmiri-report-progress requires a `u32`: {}", err), + Err(err) => show_error!("-Zmiri-report-progress requires a `u32`: {}", err), }; miri_config.report_progress = Some(interval); } else if let Some(param) = arg.strip_prefix("-Zmiri-measureme=") { @@ -520,7 +528,7 @@ fn main() { "0" => BacktraceStyle::Off, "1" => BacktraceStyle::Short, "full" => BacktraceStyle::Full, - _ => panic!("-Zmiri-backtrace may only be 0, 1, or full"), + _ => show_error!("-Zmiri-backtrace may only be 0, 1, or full"), }; } else { // Forward to rustc. From 1164815750a4149443b244da68e4408033a3cb5e Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 8 Aug 2022 11:32:49 -0400 Subject: [PATCH 3626/3747] make cargo-miri show_error a bit nicer to use --- cargo-miri/src/main.rs | 8 +++++--- cargo-miri/src/phases.rs | 19 ++++++++----------- cargo-miri/src/setup.rs | 18 ++++++++---------- cargo-miri/src/util.rs | 24 ++++++++++++++---------- 4 files changed, 35 insertions(+), 34 deletions(-) diff --git a/cargo-miri/src/main.rs b/cargo-miri/src/main.rs index 7b16af6f0c64e..30b03c57dbab6 100644 --- a/cargo-miri/src/main.rs +++ b/cargo-miri/src/main.rs @@ -1,10 +1,12 @@ #![feature(let_else)] #![allow(clippy::useless_format, clippy::derive_partial_eq_without_eq, rustc::internal)] +#[macro_use] +mod util; + mod arg; mod phases; mod setup; -mod util; mod version; use std::{env, iter}; @@ -73,9 +75,9 @@ fn main() { } let Some(first) = args.next() else { - show_error(format!( + show_error!( "`cargo-miri` called without first argument; please only invoke this binary through `cargo miri`" - )) + ) }; match first.as_str() { "miri" => phase_cargo_miri(args), diff --git a/cargo-miri/src/phases.rs b/cargo-miri/src/phases.rs index 8635661323d1a..93eb3cb174659 100644 --- a/cargo-miri/src/phases.rs +++ b/cargo-miri/src/phases.rs @@ -77,15 +77,15 @@ pub fn phase_cargo_miri(mut args: impl Iterator) { // We cannot know which of those flags take arguments and which do not, // so we cannot detect subcommands later. let Some(subcommand) = args.next() else { - show_error(format!("`cargo miri` needs to be called with a subcommand (`run`, `test`)")); + show_error!("`cargo miri` needs to be called with a subcommand (`run`, `test`)"); }; let subcommand = match &*subcommand { "setup" => MiriCommand::Setup, "test" | "t" | "run" | "r" | "nextest" => MiriCommand::Forward(subcommand), _ => - show_error(format!( + show_error!( "`cargo miri` supports the following subcommands: `run`, `test`, `nextest`, and `setup`." - )), + ), }; let verbose = num_arg_flag("-v"); @@ -123,7 +123,7 @@ pub fn phase_cargo_miri(mut args: impl Iterator) { match arg { Ok(value) => { if target_dir.is_some() { - show_error(format!("`--target-dir` is provided more than once")); + show_error!("`--target-dir` is provided more than once"); } target_dir = Some(value.into()); } @@ -456,16 +456,13 @@ pub fn phase_runner(mut binary_args: impl Iterator, phase: Runner let binary = binary_args.next().unwrap(); let file = File::open(&binary) - .unwrap_or_else(|_| show_error(format!( + .unwrap_or_else(|_| show_error!( "file {:?} not found or `cargo-miri` invoked incorrectly; please only invoke this binary through `cargo miri`", binary - ))); + )); let file = BufReader::new(file); let info = serde_json::from_reader(file).unwrap_or_else(|_| { - show_error(format!( - "file {:?} contains outdated or invalid JSON; try `cargo clean`", - binary - )) + show_error!("file {:?} contains outdated or invalid JSON; try `cargo clean`", binary) }); let info = match info { CrateRunInfo::RunWith(info) => info, @@ -562,7 +559,7 @@ pub fn phase_rustdoc(mut args: impl Iterator) { // An existing --runtool flag indicates cargo is running in cross-target mode, which we don't support. // Note that this is only passed when cargo is run with the unstable -Zdoctest-xcompile flag; // otherwise, we won't be called as rustdoc at all. - show_error(format!("cross-interpreting doctests is not currently supported by Miri.")); + show_error!("cross-interpreting doctests is not currently supported by Miri."); } else { cmd.arg(arg); } diff --git a/cargo-miri/src/setup.rs b/cargo-miri/src/setup.rs index 1211b47e3ba24..62d6e25a53e0c 100644 --- a/cargo-miri/src/setup.rs +++ b/cargo-miri/src/setup.rs @@ -73,7 +73,7 @@ pub fn setup(subcommand: &MiriCommand, host: &str, target: &str) { if xargo_version().map_or(true, |v| v < XARGO_MIN_VERSION) { if std::env::var_os("XARGO_CHECK").is_some() { // The user manually gave us a xargo binary; don't do anything automatically. - show_error(format!("xargo is too old; please upgrade to the latest version")) + show_error!("xargo is too old; please upgrade to the latest version") } let mut cmd = cargo(); cmd.args(&["install", "xargo"]); @@ -97,10 +97,10 @@ pub fn setup(subcommand: &MiriCommand, host: &str, target: &str) { .output() .expect("failed to determine sysroot"); if !output.status.success() { - show_error(format!( + show_error!( "Failed to determine sysroot; Miri said:\n{}", String::from_utf8_lossy(&output.stderr).trim_end() - )); + ); } let sysroot = std::str::from_utf8(&output.stdout).unwrap(); let sysroot = Path::new(sysroot.trim_end_matches('\n')); @@ -121,14 +121,14 @@ pub fn setup(subcommand: &MiriCommand, host: &str, target: &str) { } }; if !rust_src.exists() { - show_error(format!("given Rust source directory `{}` does not exist.", rust_src.display())); + show_error!("given Rust source directory `{}` does not exist.", rust_src.display()); } if rust_src.file_name().and_then(OsStr::to_str) != Some("library") { - show_error(format!( + show_error!( "given Rust source directory `{}` does not seem to be the `library` subdirectory of \ a Rust source checkout.", rust_src.display() - )); + ); } // Next, we need our own libstd. Prepare a xargo project for that purpose. @@ -226,11 +226,9 @@ path = "lib.rs" // Finally run it! if command.status().expect("failed to run xargo").success().not() { if only_setup { - show_error(format!("failed to run xargo, see error details above")) + show_error!("failed to run xargo, see error details above") } else { - show_error(format!( - "failed to run xargo; run `cargo miri setup` to see the error details" - )) + show_error!("failed to run xargo; run `cargo miri setup` to see the error details") } } diff --git a/cargo-miri/src/util.rs b/cargo-miri/src/util.rs index b5401d71671da..8095958d21d1d 100644 --- a/cargo-miri/src/util.rs +++ b/cargo-miri/src/util.rs @@ -14,6 +14,15 @@ use serde::{Deserialize, Serialize}; pub use crate::arg::*; +pub fn show_error(msg: &str) -> ! { + eprintln!("fatal error: {msg}"); + std::process::exit(1) +} + +macro_rules! show_error { + ($($tt:tt)*) => { show_error(&format!($($tt)*)) }; +} + /// The information to run a crate with the given environment. #[derive(Clone, Serialize, Deserialize)] pub struct CrateRunEnv { @@ -55,10 +64,10 @@ pub enum CrateRunInfo { impl CrateRunInfo { pub fn store(&self, filename: &Path) { let file = File::create(filename) - .unwrap_or_else(|_| show_error(format!("cannot create `{}`", filename.display()))); + .unwrap_or_else(|_| show_error!("cannot create `{}`", filename.display())); let file = BufWriter::new(file); serde_json::ser::to_writer(file, self) - .unwrap_or_else(|_| show_error(format!("cannot write to `{}`", filename.display()))); + .unwrap_or_else(|_| show_error!("cannot write to `{}`", filename.display())); } } @@ -70,11 +79,6 @@ pub enum MiriCommand { Forward(String), } -pub fn show_error(msg: String) -> ! { - eprintln!("fatal error: {}", msg); - std::process::exit(1) -} - /// Escapes `s` in a way that is suitable for using it as a string literal in TOML syntax. pub fn escape_for_toml(s: &str) -> String { // We want to surround this string in quotes `"`. So we first escape all quotes, @@ -187,15 +191,15 @@ pub fn ask_to_run(mut cmd: Command, ask: bool, text: &str) { match buf.trim().to_lowercase().as_ref() { // Proceed. "" | "y" | "yes" => {} - "n" | "no" => show_error(format!("aborting as per your request")), - a => show_error(format!("invalid answer `{}`", a)), + "n" | "no" => show_error!("aborting as per your request"), + a => show_error!("invalid answer `{}`", a), }; } else { eprintln!("Running `{:?}` to {}.", cmd, text); } if cmd.status().unwrap_or_else(|_| panic!("failed to execute {:?}", cmd)).success().not() { - show_error(format!("failed to {}", text)); + show_error!("failed to {}", text); } } From b99d7bc77f1b7986954ec8bd2f1c9f80664e8fd4 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 8 Aug 2022 11:35:54 -0400 Subject: [PATCH 3627/3747] avoid intermediate allocations in show_error macro --- cargo-miri/src/main.rs | 2 +- cargo-miri/src/util.rs | 4 ++-- src/bin/miri.rs | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/cargo-miri/src/main.rs b/cargo-miri/src/main.rs index 30b03c57dbab6..09e2cd3c2867c 100644 --- a/cargo-miri/src/main.rs +++ b/cargo-miri/src/main.rs @@ -11,7 +11,7 @@ mod version; use std::{env, iter}; -use crate::{phases::*, util::*}; +use crate::phases::*; fn main() { // Rustc does not support non-UTF-8 arguments so we make no attempt either. diff --git a/cargo-miri/src/util.rs b/cargo-miri/src/util.rs index 8095958d21d1d..8f29eebaac100 100644 --- a/cargo-miri/src/util.rs +++ b/cargo-miri/src/util.rs @@ -14,13 +14,13 @@ use serde::{Deserialize, Serialize}; pub use crate::arg::*; -pub fn show_error(msg: &str) -> ! { +pub fn show_error(msg: &impl std::fmt::Display) -> ! { eprintln!("fatal error: {msg}"); std::process::exit(1) } macro_rules! show_error { - ($($tt:tt)*) => { show_error(&format!($($tt)*)) }; + ($($tt:tt)*) => { crate::util::show_error(&format_args!($($tt)*)) }; } /// The information to run a crate with the given environment. diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 3325fc97d8257..ca0787b229830 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -152,13 +152,13 @@ impl rustc_driver::Callbacks for MiriBeRustCompilerCalls { } } -fn show_error(msg: &str) -> ! { +fn show_error(msg: &impl std::fmt::Display) -> ! { eprintln!("fatal error: {msg}"); std::process::exit(1) } macro_rules! show_error { - ($($tt:tt)*) => { show_error(&format!($($tt)*)) }; + ($($tt:tt)*) => { show_error(&format_args!($($tt)*)) }; } fn init_early_loggers() { From d630671a33942988391a6a5b52ae0346057e2cf7 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 5 Aug 2022 16:27:44 -0400 Subject: [PATCH 3628/3747] move atomic access alginment check to helper function and inside atomic access lib --- src/concurrency/data_race.rs | 27 ++++++++++++++- src/shims/intrinsics/atomic.rs | 63 +++------------------------------- 2 files changed, 30 insertions(+), 60 deletions(-) diff --git a/src/concurrency/data_race.rs b/src/concurrency/data_race.rs index 6ea87a82cb924..65f198f3c9dd7 100644 --- a/src/concurrency/data_race.rs +++ b/src/concurrency/data_race.rs @@ -49,7 +49,7 @@ use std::{ use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_index::vec::{Idx, IndexVec}; use rustc_middle::{mir, ty::layout::TyAndLayout}; -use rustc_target::abi::Size; +use rustc_target::abi::{Align, Size}; use crate::*; @@ -463,6 +463,22 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { this.write_scalar_atomic(value.into(), &value_place, atomic) } + /// Checks that an atomic access is legal at the given place. + fn atomic_access_check(&self, place: &MPlaceTy<'tcx, Provenance>) -> InterpResult<'tcx> { + let this = self.eval_context_ref(); + // Check alignment requirements. Atomics must always be aligned to their size, + // even if the type they wrap would be less aligned (e.g. AtomicU64 on 32bit must + // be 8-aligned). + let align = Align::from_bytes(place.layout.size.bytes()).unwrap(); + this.check_ptr_access_align( + place.ptr, + place.layout.size, + align, + CheckInAllocMsg::MemoryAccessTest, + )?; + Ok(()) + } + /// Perform an atomic read operation at the memory location. fn read_scalar_atomic( &self, @@ -470,6 +486,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { atomic: AtomicReadOrd, ) -> InterpResult<'tcx, ScalarMaybeUninit> { let this = self.eval_context_ref(); + this.atomic_access_check(place)?; // This will read from the last store in the modification order of this location. In case // weak memory emulation is enabled, this may not be the store we will pick to actually read from and return. // This is fine with StackedBorrow and race checks because they don't concern metadata on @@ -490,6 +507,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { atomic: AtomicWriteOrd, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); + this.atomic_access_check(dest)?; + this.validate_overlapping_atomic(dest)?; this.allow_data_races_mut(move |this| this.write_scalar(val, &dest.into()))?; this.validate_atomic_store(dest, atomic)?; @@ -511,6 +530,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { atomic: AtomicRwOrd, ) -> InterpResult<'tcx, ImmTy<'tcx, Provenance>> { let this = self.eval_context_mut(); + this.atomic_access_check(place)?; this.validate_overlapping_atomic(place)?; let old = this.allow_data_races_mut(|this| this.read_immediate(&place.into()))?; @@ -540,6 +560,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { atomic: AtomicRwOrd, ) -> InterpResult<'tcx, ScalarMaybeUninit> { let this = self.eval_context_mut(); + this.atomic_access_check(place)?; this.validate_overlapping_atomic(place)?; let old = this.allow_data_races_mut(|this| this.read_scalar(&place.into()))?; @@ -561,6 +582,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { atomic: AtomicRwOrd, ) -> InterpResult<'tcx, ImmTy<'tcx, Provenance>> { let this = self.eval_context_mut(); + this.atomic_access_check(place)?; this.validate_overlapping_atomic(place)?; let old = this.allow_data_races_mut(|this| this.read_immediate(&place.into()))?; @@ -604,6 +626,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { ) -> InterpResult<'tcx, Immediate> { use rand::Rng as _; let this = self.eval_context_mut(); + this.atomic_access_check(place)?; this.validate_overlapping_atomic(place)?; // Failure ordering cannot be stronger than success ordering, therefore first attempt @@ -1016,6 +1039,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { fn allow_data_races_ref(&self, op: impl FnOnce(&MiriEvalContext<'mir, 'tcx>) -> R) -> R { let this = self.eval_context_ref(); if let Some(data_race) = &this.machine.data_race { + assert!(!data_race.ongoing_action_data_race_free.get(), "cannot nest allow_data_races"); data_race.ongoing_action_data_race_free.set(true); } let result = op(this); @@ -1035,6 +1059,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { ) -> R { let this = self.eval_context_mut(); if let Some(data_race) = &this.machine.data_race { + assert!(!data_race.ongoing_action_data_race_free.get(), "cannot nest allow_data_races"); data_race.ongoing_action_data_race_free.set(true); } let result = op(this); diff --git a/src/shims/intrinsics/atomic.rs b/src/shims/intrinsics/atomic.rs index 8e0bb746e3cd4..752bc0e302e74 100644 --- a/src/shims/intrinsics/atomic.rs +++ b/src/shims/intrinsics/atomic.rs @@ -1,5 +1,4 @@ use rustc_middle::{mir, mir::BinOp, ty}; -use rustc_target::abi::Align; use crate::*; use helpers::check_arg_count; @@ -130,20 +129,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let [place] = check_arg_count(args)?; let place = this.deref_operand(place)?; - // make sure it fits into a scalar; otherwise it cannot be atomic + // Perform atomic load. let val = this.read_scalar_atomic(&place, atomic)?; - - // Check alignment requirements. Atomics must always be aligned to their size, - // even if the type they wrap would be less aligned (e.g. AtomicU64 on 32bit must - // be 8-aligned). - let align = Align::from_bytes(place.layout.size.bytes()).unwrap(); - this.check_ptr_access_align( - place.ptr, - place.layout.size, - align, - CheckInAllocMsg::MemoryAccessTest, - )?; - // Perform regular access. + // Perform regular store. this.write_scalar(val, dest)?; Ok(()) } @@ -157,19 +145,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let [place, val] = check_arg_count(args)?; let place = this.deref_operand(place)?; - let val = this.read_scalar(val)?; // make sure it fits into a scalar; otherwise it cannot be atomic - - // Check alignment requirements. Atomics must always be aligned to their size, - // even if the type they wrap would be less aligned (e.g. AtomicU64 on 32bit must - // be 8-aligned). - let align = Align::from_bytes(place.layout.size.bytes()).unwrap(); - this.check_ptr_access_align( - place.ptr, - place.layout.size, - align, - CheckInAllocMsg::MemoryAccessTest, - )?; + // Perform regular load. + let val = this.read_scalar(val)?; // Perform atomic store this.write_scalar_atomic(val, &place, atomic)?; Ok(()) @@ -220,17 +198,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx span_bug!(this.cur_span(), "atomic arithmetic operation type mismatch"); } - // Check alignment requirements. Atomics must always be aligned to their size, - // even if the type they wrap would be less aligned (e.g. AtomicU64 on 32bit must - // be 8-aligned). - let align = Align::from_bytes(place.layout.size.bytes()).unwrap(); - this.check_ptr_access_align( - place.ptr, - place.layout.size, - align, - CheckInAllocMsg::MemoryAccessTest, - )?; - match atomic_op { AtomicOp::Min => { let old = this.atomic_min_max_scalar(&place, rhs, true, atomic)?; @@ -262,17 +229,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let place = this.deref_operand(place)?; let new = this.read_scalar(new)?; - // Check alignment requirements. Atomics must always be aligned to their size, - // even if the type they wrap would be less aligned (e.g. AtomicU64 on 32bit must - // be 8-aligned). - let align = Align::from_bytes(place.layout.size.bytes()).unwrap(); - this.check_ptr_access_align( - place.ptr, - place.layout.size, - align, - CheckInAllocMsg::MemoryAccessTest, - )?; - let old = this.atomic_exchange_scalar(&place, new, atomic)?; this.write_scalar(old, dest)?; // old value is returned Ok(()) @@ -293,17 +249,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let expect_old = this.read_immediate(expect_old)?; // read as immediate for the sake of `binary_op()` let new = this.read_scalar(new)?; - // Check alignment requirements. Atomics must always be aligned to their size, - // even if the type they wrap would be less aligned (e.g. AtomicU64 on 32bit must - // be 8-aligned). - let align = Align::from_bytes(place.layout.size.bytes()).unwrap(); - this.check_ptr_access_align( - place.ptr, - place.layout.size, - align, - CheckInAllocMsg::MemoryAccessTest, - )?; - let old = this.atomic_compare_exchange_scalar( &place, &expect_old, From cd2edbfd098b6c9351f8c168c8f36c190ce5e675 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 5 Aug 2022 17:47:28 -0400 Subject: [PATCH 3629/3747] ensure atomics happen on mutable allocations, and fix futex test --- src/concurrency/data_race.rs | 12 ++++++++++++ .../fail/concurrency/read_only_atomic_cmpxchg.rs | 11 +++++++++++ .../concurrency/read_only_atomic_cmpxchg.stderr | 15 +++++++++++++++ tests/fail/concurrency/read_only_atomic_load.rs | 13 +++++++++++++ .../fail/concurrency/read_only_atomic_load.stderr | 15 +++++++++++++++ tests/pass/concurrency/linux-futex.rs | 6 +++--- 6 files changed, 69 insertions(+), 3 deletions(-) create mode 100644 tests/fail/concurrency/read_only_atomic_cmpxchg.rs create mode 100644 tests/fail/concurrency/read_only_atomic_cmpxchg.stderr create mode 100644 tests/fail/concurrency/read_only_atomic_load.rs create mode 100644 tests/fail/concurrency/read_only_atomic_load.stderr diff --git a/src/concurrency/data_race.rs b/src/concurrency/data_race.rs index 65f198f3c9dd7..51105ec98df01 100644 --- a/src/concurrency/data_race.rs +++ b/src/concurrency/data_race.rs @@ -46,6 +46,7 @@ use std::{ mem, }; +use rustc_ast::Mutability; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_index::vec::{Idx, IndexVec}; use rustc_middle::{mir, ty::layout::TyAndLayout}; @@ -476,6 +477,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { align, CheckInAllocMsg::MemoryAccessTest, )?; + // Ensure the allocation is mutable. Even failing (read-only) compare_exchange need mutable + // memory on many targets (i.e., they segfault if taht memory is mapped read-only), and + // atomic loads can be implemented via compare_exchange on some targets. See + // . + // We avoid `get_ptr_alloc` since we do *not* want to run the access hooks -- the actual + // access will happen later. + let (alloc_id, _offset, _prov) = + this.ptr_try_get_alloc_id(place.ptr).expect("there are no zero-sized atomic accesses"); + if this.get_alloc_mutability(alloc_id)? == Mutability::Not { + throw_ub_format!("atomic operations cannot be performed on read-only memory"); + } Ok(()) } diff --git a/tests/fail/concurrency/read_only_atomic_cmpxchg.rs b/tests/fail/concurrency/read_only_atomic_cmpxchg.rs new file mode 100644 index 0000000000000..cb6aeea665d39 --- /dev/null +++ b/tests/fail/concurrency/read_only_atomic_cmpxchg.rs @@ -0,0 +1,11 @@ +// Should not rely on the aliasing model for its failure. +//@compile-flags: -Zmiri-disable-stacked-borrows + +use std::sync::atomic::{AtomicI32, Ordering}; + +fn main() { + static X: i32 = 0; + let x = &X as *const i32 as *const AtomicI32; + let x = unsafe { &*x }; + x.compare_exchange(1, 2, Ordering::Relaxed, Ordering::Relaxed).unwrap_err(); //~ERROR: atomic operations cannot be performed on read-only memory +} diff --git a/tests/fail/concurrency/read_only_atomic_cmpxchg.stderr b/tests/fail/concurrency/read_only_atomic_cmpxchg.stderr new file mode 100644 index 0000000000000..2753c492266b0 --- /dev/null +++ b/tests/fail/concurrency/read_only_atomic_cmpxchg.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: atomic operations cannot be performed on read-only memory + --> $DIR/read_only_atomic_cmpxchg.rs:LL:CC + | +LL | x.compare_exchange(1, 2, Ordering::Relaxed, Ordering::Relaxed).unwrap_err(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ atomic operations cannot be performed on read-only memory + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: backtrace: + = note: inside `main` at $DIR/read_only_atomic_cmpxchg.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/fail/concurrency/read_only_atomic_load.rs b/tests/fail/concurrency/read_only_atomic_load.rs new file mode 100644 index 0000000000000..6e92453e3c195 --- /dev/null +++ b/tests/fail/concurrency/read_only_atomic_load.rs @@ -0,0 +1,13 @@ +// Should not rely on the aliasing model for its failure. +//@compile-flags: -Zmiri-disable-stacked-borrows + +use std::sync::atomic::{AtomicI32, Ordering}; + +fn main() { + static X: i32 = 0; + let x = &X as *const i32 as *const AtomicI32; + let x = unsafe { &*x }; + // Some targets can implement atomic loads via compare_exchange, so we cannot allow them on + // read-only memory. + x.load(Ordering::Relaxed); //~ERROR: atomic operations cannot be performed on read-only memory +} diff --git a/tests/fail/concurrency/read_only_atomic_load.stderr b/tests/fail/concurrency/read_only_atomic_load.stderr new file mode 100644 index 0000000000000..588081afc62c0 --- /dev/null +++ b/tests/fail/concurrency/read_only_atomic_load.stderr @@ -0,0 +1,15 @@ +error: Undefined Behavior: atomic operations cannot be performed on read-only memory + --> $DIR/read_only_atomic_load.rs:LL:CC + | +LL | x.load(Ordering::Relaxed); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ atomic operations cannot be performed on read-only memory + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: backtrace: + = note: inside `main` at $DIR/read_only_atomic_load.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/pass/concurrency/linux-futex.rs b/tests/pass/concurrency/linux-futex.rs index 43216481e76fb..2c99bfa1000cd 100644 --- a/tests/pass/concurrency/linux-futex.rs +++ b/tests/pass/concurrency/linux-futex.rs @@ -130,7 +130,7 @@ fn wait_absolute_timeout() { fn wait_wake() { let start = Instant::now(); - static FUTEX: i32 = 0; + static mut FUTEX: i32 = 0; let t = thread::spawn(move || { thread::sleep(Duration::from_millis(200)); @@ -167,7 +167,7 @@ fn wait_wake() { fn wait_wake_bitset() { let start = Instant::now(); - static FUTEX: i32 = 0; + static mut FUTEX: i32 = 0; let t = thread::spawn(move || { thread::sleep(Duration::from_millis(200)); @@ -277,8 +277,8 @@ fn concurrent_wait_wake() { // Make sure we got the interesting case (of having woken a thread) at least once, but not *each* time. let woken = WOKEN.load(Ordering::Relaxed); - assert!(woken > 0 && woken < rounds); //eprintln!("waking happened {woken} times"); + assert!(woken > 0 && woken < rounds); } fn main() { From 927ab19cfc67f96f7543aa929bd1a01c8f226dc2 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 5 Aug 2022 17:53:18 -0400 Subject: [PATCH 3630/3747] make some operations private to the data race detector / atomic intrinsic file --- src/concurrency/data_race.rs | 200 ++++++++++++++++----------------- src/shims/intrinsics/atomic.rs | 13 ++- src/shims/unix/linux/sync.rs | 4 +- 3 files changed, 110 insertions(+), 107 deletions(-) diff --git a/src/concurrency/data_race.rs b/src/concurrency/data_race.rs index 51105ec98df01..bcbdb616514f1 100644 --- a/src/concurrency/data_race.rs +++ b/src/concurrency/data_race.rs @@ -464,33 +464,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { this.write_scalar_atomic(value.into(), &value_place, atomic) } - /// Checks that an atomic access is legal at the given place. - fn atomic_access_check(&self, place: &MPlaceTy<'tcx, Provenance>) -> InterpResult<'tcx> { - let this = self.eval_context_ref(); - // Check alignment requirements. Atomics must always be aligned to their size, - // even if the type they wrap would be less aligned (e.g. AtomicU64 on 32bit must - // be 8-aligned). - let align = Align::from_bytes(place.layout.size.bytes()).unwrap(); - this.check_ptr_access_align( - place.ptr, - place.layout.size, - align, - CheckInAllocMsg::MemoryAccessTest, - )?; - // Ensure the allocation is mutable. Even failing (read-only) compare_exchange need mutable - // memory on many targets (i.e., they segfault if taht memory is mapped read-only), and - // atomic loads can be implemented via compare_exchange on some targets. See - // . - // We avoid `get_ptr_alloc` since we do *not* want to run the access hooks -- the actual - // access will happen later. - let (alloc_id, _offset, _prov) = - this.ptr_try_get_alloc_id(place.ptr).expect("there are no zero-sized atomic accesses"); - if this.get_alloc_mutability(alloc_id)? == Mutability::Not { - throw_ub_format!("atomic operations cannot be performed on read-only memory"); - } - Ok(()) - } - /// Perform an atomic read operation at the memory location. fn read_scalar_atomic( &self, @@ -682,80 +655,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { Ok(res) } - /// Update the data-race detector for an atomic read occurring at the - /// associated memory-place and on the current thread. - fn validate_atomic_load( - &self, - place: &MPlaceTy<'tcx, Provenance>, - atomic: AtomicReadOrd, - ) -> InterpResult<'tcx> { - let this = self.eval_context_ref(); - this.validate_overlapping_atomic(place)?; - this.validate_atomic_op( - place, - atomic, - "Atomic Load", - move |memory, clocks, index, atomic| { - if atomic == AtomicReadOrd::Relaxed { - memory.load_relaxed(&mut *clocks, index) - } else { - memory.load_acquire(&mut *clocks, index) - } - }, - ) - } - - /// Update the data-race detector for an atomic write occurring at the - /// associated memory-place and on the current thread. - fn validate_atomic_store( - &mut self, - place: &MPlaceTy<'tcx, Provenance>, - atomic: AtomicWriteOrd, - ) -> InterpResult<'tcx> { - let this = self.eval_context_mut(); - this.validate_overlapping_atomic(place)?; - this.validate_atomic_op( - place, - atomic, - "Atomic Store", - move |memory, clocks, index, atomic| { - if atomic == AtomicWriteOrd::Relaxed { - memory.store_relaxed(clocks, index) - } else { - memory.store_release(clocks, index) - } - }, - ) - } - - /// Update the data-race detector for an atomic read-modify-write occurring - /// at the associated memory place and on the current thread. - fn validate_atomic_rmw( - &mut self, - place: &MPlaceTy<'tcx, Provenance>, - atomic: AtomicRwOrd, - ) -> InterpResult<'tcx> { - use AtomicRwOrd::*; - let acquire = matches!(atomic, Acquire | AcqRel | SeqCst); - let release = matches!(atomic, Release | AcqRel | SeqCst); - let this = self.eval_context_mut(); - this.validate_overlapping_atomic(place)?; - this.validate_atomic_op(place, atomic, "Atomic RMW", move |memory, clocks, index, _| { - if acquire { - memory.load_acquire(clocks, index)?; - } else { - memory.load_relaxed(clocks, index)?; - } - if release { - memory.rmw_release(clocks, index) - } else { - memory.rmw_relaxed(clocks, index) - } - }) - } - /// Update the data-race detector for an atomic fence on the current thread. - fn validate_atomic_fence(&mut self, atomic: AtomicFenceOrd) -> InterpResult<'tcx> { + fn atomic_fence(&mut self, atomic: AtomicFenceOrd) -> InterpResult<'tcx> { let this = self.eval_context_mut(); if let Some(data_race) = &mut this.machine.data_race { data_race.maybe_perform_sync_operation(&this.machine.threads, |index, mut clocks| { @@ -1081,6 +982,105 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { result } + /// Checks that an atomic access is legal at the given place. + fn atomic_access_check(&self, place: &MPlaceTy<'tcx, Provenance>) -> InterpResult<'tcx> { + let this = self.eval_context_ref(); + // Check alignment requirements. Atomics must always be aligned to their size, + // even if the type they wrap would be less aligned (e.g. AtomicU64 on 32bit must + // be 8-aligned). + let align = Align::from_bytes(place.layout.size.bytes()).unwrap(); + this.check_ptr_access_align( + place.ptr, + place.layout.size, + align, + CheckInAllocMsg::MemoryAccessTest, + )?; + // Ensure the allocation is mutable. Even failing (read-only) compare_exchange need mutable + // memory on many targets (i.e., they segfault if taht memory is mapped read-only), and + // atomic loads can be implemented via compare_exchange on some targets. See + // . + // We avoid `get_ptr_alloc` since we do *not* want to run the access hooks -- the actual + // access will happen later. + let (alloc_id, _offset, _prov) = + this.ptr_try_get_alloc_id(place.ptr).expect("there are no zero-sized atomic accesses"); + if this.get_alloc_mutability(alloc_id)? == Mutability::Not { + throw_ub_format!("atomic operations cannot be performed on read-only memory"); + } + Ok(()) + } + + /// Update the data-race detector for an atomic read occurring at the + /// associated memory-place and on the current thread. + fn validate_atomic_load( + &self, + place: &MPlaceTy<'tcx, Provenance>, + atomic: AtomicReadOrd, + ) -> InterpResult<'tcx> { + let this = self.eval_context_ref(); + this.validate_overlapping_atomic(place)?; + this.validate_atomic_op( + place, + atomic, + "Atomic Load", + move |memory, clocks, index, atomic| { + if atomic == AtomicReadOrd::Relaxed { + memory.load_relaxed(&mut *clocks, index) + } else { + memory.load_acquire(&mut *clocks, index) + } + }, + ) + } + + /// Update the data-race detector for an atomic write occurring at the + /// associated memory-place and on the current thread. + fn validate_atomic_store( + &mut self, + place: &MPlaceTy<'tcx, Provenance>, + atomic: AtomicWriteOrd, + ) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + this.validate_overlapping_atomic(place)?; + this.validate_atomic_op( + place, + atomic, + "Atomic Store", + move |memory, clocks, index, atomic| { + if atomic == AtomicWriteOrd::Relaxed { + memory.store_relaxed(clocks, index) + } else { + memory.store_release(clocks, index) + } + }, + ) + } + + /// Update the data-race detector for an atomic read-modify-write occurring + /// at the associated memory place and on the current thread. + fn validate_atomic_rmw( + &mut self, + place: &MPlaceTy<'tcx, Provenance>, + atomic: AtomicRwOrd, + ) -> InterpResult<'tcx> { + use AtomicRwOrd::*; + let acquire = matches!(atomic, Acquire | AcqRel | SeqCst); + let release = matches!(atomic, Release | AcqRel | SeqCst); + let this = self.eval_context_mut(); + this.validate_overlapping_atomic(place)?; + this.validate_atomic_op(place, atomic, "Atomic RMW", move |memory, clocks, index, _| { + if acquire { + memory.load_acquire(clocks, index)?; + } else { + memory.load_relaxed(clocks, index)?; + } + if release { + memory.rmw_release(clocks, index) + } else { + memory.rmw_relaxed(clocks, index) + } + }) + } + /// Generic atomic operation implementation fn validate_atomic_op( &self, diff --git a/src/shims/intrinsics/atomic.rs b/src/shims/intrinsics/atomic.rs index 752bc0e302e74..86f132f73fc80 100644 --- a/src/shims/intrinsics/atomic.rs +++ b/src/shims/intrinsics/atomic.rs @@ -67,8 +67,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ["load", ord] => this.atomic_load(args, dest, read_ord(ord)?)?, ["store", ord] => this.atomic_store(args, write_ord(ord)?)?, - ["fence", ord] => this.atomic_fence(args, fence_ord(ord)?)?, - ["singlethreadfence", ord] => this.compiler_fence(args, fence_ord(ord)?)?, + ["fence", ord] => this.atomic_fence_intrinsic(args, fence_ord(ord)?)?, + ["singlethreadfence", ord] => this.compiler_fence_intrinsic(args, fence_ord(ord)?)?, ["xchg", ord] => this.atomic_exchange(args, dest, rw_ord(ord)?)?, ["cxchg", ord1, ord2] => @@ -117,7 +117,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } Ok(()) } +} +impl<'mir, 'tcx: 'mir> EvalContextPrivExt<'mir, 'tcx> for MiriEvalContext<'mir, 'tcx> {} +trait EvalContextPrivExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { fn atomic_load( &mut self, args: &[OpTy<'tcx, Provenance>], @@ -153,7 +156,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(()) } - fn compiler_fence( + fn compiler_fence_intrinsic( &mut self, args: &[OpTy<'tcx, Provenance>], atomic: AtomicFenceOrd, @@ -164,14 +167,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(()) } - fn atomic_fence( + fn atomic_fence_intrinsic( &mut self, args: &[OpTy<'tcx, Provenance>], atomic: AtomicFenceOrd, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let [] = check_arg_count(args)?; - this.validate_atomic_fence(atomic)?; + this.atomic_fence(atomic)?; Ok(()) } diff --git a/src/shims/unix/linux/sync.rs b/src/shims/unix/linux/sync.rs index 59de10498745f..b33553f4663b9 100644 --- a/src/shims/unix/linux/sync.rs +++ b/src/shims/unix/linux/sync.rs @@ -169,7 +169,7 @@ pub fn futex<'tcx>( // // Thankfully, preemptions cannot happen inside a Miri shim, so we do not need to // do anything special to guarantee fence-load-comparison atomicity. - this.validate_atomic_fence(AtomicFenceOrd::SeqCst)?; + this.atomic_fence(AtomicFenceOrd::SeqCst)?; // Read an `i32` through the pointer, regardless of any wrapper types. // It's not uncommon for `addr` to be passed as another type than `*mut i32`, such as `*const AtomicI32`. let futex_val = this @@ -240,7 +240,7 @@ pub fn futex<'tcx>( // Together with the SeqCst fence in futex_wait, this makes sure that futex_wait // will see the latest value on addr which could be changed by our caller // before doing the syscall. - this.validate_atomic_fence(AtomicFenceOrd::SeqCst)?; + this.atomic_fence(AtomicFenceOrd::SeqCst)?; let mut n = 0; for _ in 0..val { if let Some(thread) = this.futex_wake(addr_usize, bitset) { From 43d39636724616b752b18088b95d0e2e61c84844 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 7 Aug 2022 08:00:39 -0400 Subject: [PATCH 3631/3747] more detailed error message --- src/concurrency/data_race.rs | 15 ++++++++++++--- .../concurrency/read_only_atomic_cmpxchg.stderr | 6 ++++++ .../fail/concurrency/read_only_atomic_load.stderr | 6 ++++++ 3 files changed, 24 insertions(+), 3 deletions(-) diff --git a/src/concurrency/data_race.rs b/src/concurrency/data_race.rs index bcbdb616514f1..410c2b9c3ddf7 100644 --- a/src/concurrency/data_race.rs +++ b/src/concurrency/data_race.rs @@ -997,14 +997,23 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { )?; // Ensure the allocation is mutable. Even failing (read-only) compare_exchange need mutable // memory on many targets (i.e., they segfault if taht memory is mapped read-only), and - // atomic loads can be implemented via compare_exchange on some targets. See - // . + // atomic loads can be implemented via compare_exchange on some targets. There could + // possibly be some very specific exceptions to this, see + // for details. // We avoid `get_ptr_alloc` since we do *not* want to run the access hooks -- the actual // access will happen later. let (alloc_id, _offset, _prov) = this.ptr_try_get_alloc_id(place.ptr).expect("there are no zero-sized atomic accesses"); if this.get_alloc_mutability(alloc_id)? == Mutability::Not { - throw_ub_format!("atomic operations cannot be performed on read-only memory"); + // FIXME: make this prettier, once these messages have separate title/span/help messages. + throw_ub_format!( + "atomic operations cannot be performed on read-only memory\n\ + many platforms require atomic read-modify-write instructions to be performed on writeable memory, even if the operation fails \ + (and is hence nominally read-only)\n\ + some platforms implement (some) atomic loads via compare-exchange, which means they do not work on read-only memory; \ + it is possible that we could have an exception permitting this for specific kinds of loads\n\ + please report an issue at if this is a problem for you" + ); } Ok(()) } diff --git a/tests/fail/concurrency/read_only_atomic_cmpxchg.stderr b/tests/fail/concurrency/read_only_atomic_cmpxchg.stderr index 2753c492266b0..b90dc5c9d6cd5 100644 --- a/tests/fail/concurrency/read_only_atomic_cmpxchg.stderr +++ b/tests/fail/concurrency/read_only_atomic_cmpxchg.stderr @@ -1,8 +1,14 @@ error: Undefined Behavior: atomic operations cannot be performed on read-only memory + many platforms require atomic read-modify-write instructions to be performed on writeable memory, even if the operation fails (and is hence nominally read-only) + some platforms implement (some) atomic loads via compare-exchange, which means they do not work on read-only memory; it is possible that we could have an exception permitting this for specific kinds of loads + please report an issue at if this is a problem for you --> $DIR/read_only_atomic_cmpxchg.rs:LL:CC | LL | x.compare_exchange(1, 2, Ordering::Relaxed, Ordering::Relaxed).unwrap_err(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ atomic operations cannot be performed on read-only memory +many platforms require atomic read-modify-write instructions to be performed on writeable memory, even if the operation fails (and is hence nominally read-only) +some platforms implement (some) atomic loads via compare-exchange, which means they do not work on read-only memory; it is possible that we could have an exception permitting this for specific kinds of loads +please report an issue at if this is a problem for you | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/concurrency/read_only_atomic_load.stderr b/tests/fail/concurrency/read_only_atomic_load.stderr index 588081afc62c0..b19d3755fbb04 100644 --- a/tests/fail/concurrency/read_only_atomic_load.stderr +++ b/tests/fail/concurrency/read_only_atomic_load.stderr @@ -1,8 +1,14 @@ error: Undefined Behavior: atomic operations cannot be performed on read-only memory + many platforms require atomic read-modify-write instructions to be performed on writeable memory, even if the operation fails (and is hence nominally read-only) + some platforms implement (some) atomic loads via compare-exchange, which means they do not work on read-only memory; it is possible that we could have an exception permitting this for specific kinds of loads + please report an issue at if this is a problem for you --> $DIR/read_only_atomic_load.rs:LL:CC | LL | x.load(Ordering::Relaxed); | ^^^^^^^^^^^^^^^^^^^^^^^^^ atomic operations cannot be performed on read-only memory +many platforms require atomic read-modify-write instructions to be performed on writeable memory, even if the operation fails (and is hence nominally read-only) +some platforms implement (some) atomic loads via compare-exchange, which means they do not work on read-only memory; it is possible that we could have an exception permitting this for specific kinds of loads +please report an issue at if this is a problem for you | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information From a1f5a75c80a325804b96d9a9f2d2f862ad29c736 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 9 Aug 2022 13:59:43 -0400 Subject: [PATCH 3632/3747] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index cac0155e3ce47..eb973aa081561 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -93ab13b4e894ab74258c40aaf29872db2b17b6b4 +6d3f1beae1720055e5a30f4dbe7a9e7fb810c65e From 591274bbd9506e88ac9280dc79d0db38cb11707b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 10 Aug 2022 08:03:00 -0400 Subject: [PATCH 3633/3747] rustup --- rust-version | 2 +- tests/pass/backtrace/backtrace-global-alloc.rs | 2 -- tests/pass/backtrace/backtrace-std.rs | 2 -- tests/pass/integer-ops.rs | 14 ++++++++------ 4 files changed, 9 insertions(+), 11 deletions(-) diff --git a/rust-version b/rust-version index eb973aa081561..71d06eff494cf 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -6d3f1beae1720055e5a30f4dbe7a9e7fb810c65e +1603a70f82240ba2d27f72f964e36614d7620ad3 diff --git a/tests/pass/backtrace/backtrace-global-alloc.rs b/tests/pass/backtrace/backtrace-global-alloc.rs index 406a5b62333d4..6660e5bb57c09 100644 --- a/tests/pass/backtrace/backtrace-global-alloc.rs +++ b/tests/pass/backtrace/backtrace-global-alloc.rs @@ -1,8 +1,6 @@ //@compile-flags: -Zmiri-disable-isolation //@rustc-env: RUST_BACKTRACE=1 -#![feature(backtrace)] - use std::alloc::System; use std::backtrace::Backtrace; diff --git a/tests/pass/backtrace/backtrace-std.rs b/tests/pass/backtrace/backtrace-std.rs index 9106310e513dc..b2a5ac180298c 100644 --- a/tests/pass/backtrace/backtrace-std.rs +++ b/tests/pass/backtrace/backtrace-std.rs @@ -1,8 +1,6 @@ //@compile-flags: -Zmiri-disable-isolation //@rustc-env: RUST_BACKTRACE=1 -#![feature(backtrace)] - use std::backtrace::Backtrace; #[inline(never)] diff --git a/tests/pass/integer-ops.rs b/tests/pass/integer-ops.rs index 8608d12d4d872..724be9efc9f82 100644 --- a/tests/pass/integer-ops.rs +++ b/tests/pass/integer-ops.rs @@ -176,10 +176,12 @@ pub fn main() { // Logarithms macro_rules! test_log { ($type:ident, $max_log2:expr, $max_log10:expr) => { - assert_eq!($type::MIN.checked_log2(), None); - assert_eq!($type::MIN.checked_log10(), None); - assert_eq!($type::MAX.checked_log2(), Some($max_log2)); - assert_eq!($type::MAX.checked_log10(), Some($max_log10)); + assert_eq!($type::MIN.checked_ilog2(), None); + assert_eq!($type::MIN.checked_ilog10(), None); + assert_eq!($type::MAX.checked_ilog2(), Some($max_log2)); + assert_eq!($type::MAX.checked_ilog10(), Some($max_log10)); + assert_eq!($type::MAX.ilog2(), $max_log2); + assert_eq!($type::MAX.ilog10(), $max_log10); }; } @@ -195,9 +197,9 @@ pub fn main() { test_log!(u128, 127, 38); for i in (1..=i16::MAX).step_by(i8::MAX as usize) { - assert_eq!(i.checked_log(13), Some((i as f32).log(13.0) as u32)); + assert_eq!(i.checked_ilog(13), Some((i as f32).log(13.0) as u32)); } for i in (1..=u16::MAX).step_by(i8::MAX as usize) { - assert_eq!(i.checked_log(13), Some((i as f32).log(13.0) as u32)); + assert_eq!(i.checked_ilog(13), Some((i as f32).log(13.0) as u32)); } } From 23cd7b863ff0ca4fba9e28402a067f3f75772d26 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 11 Aug 2022 19:01:19 -0400 Subject: [PATCH 3634/3747] rustup for pthread_setname_np on Linux --- rust-version | 2 +- src/shims/unix/foreign_items.rs | 3 ++- src/shims/unix/linux/foreign_items.rs | 9 +++++++ src/shims/unix/macos/foreign_items.rs | 4 ++-- src/shims/unix/thread.rs | 34 ++++++++++++++++----------- src/thread.rs | 25 ++++++++------------ 6 files changed, 44 insertions(+), 33 deletions(-) diff --git a/rust-version b/rust-version index 71d06eff494cf..0bcadc0a366f8 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -1603a70f82240ba2d27f72f964e36614d7620ad3 +20ffea6938b5839c390252e07940b99e3b6a889a diff --git a/src/shims/unix/foreign_items.rs b/src/shims/unix/foreign_items.rs index 6ea10de0b8a83..0ca838b2103f5 100644 --- a/src/shims/unix/foreign_items.rs +++ b/src/shims/unix/foreign_items.rs @@ -437,7 +437,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "pthread_self" => { let [] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; - this.pthread_self(dest)?; + let res = this.pthread_self()?; + this.write_scalar(res, dest)?; } "sched_yield" => { let [] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; diff --git a/src/shims/unix/linux/foreign_items.rs b/src/shims/unix/linux/foreign_items.rs index bae3780b460c7..817bfc7d1cc9c 100644 --- a/src/shims/unix/linux/foreign_items.rs +++ b/src/shims/unix/linux/foreign_items.rs @@ -69,6 +69,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let result = this.pthread_condattr_getclock(attr, clock_id)?; this.write_scalar(Scalar::from_i32(result), dest)?; } + "pthread_setname_np" => { + let [thread, name] = + this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let res = this.pthread_setname_np( + this.read_scalar(thread)?.check_init()?, + this.read_scalar(name)?.check_init()?, + )?; + this.write_scalar(res, dest)?; + } // Dynamically invoked syscalls "syscall" => { diff --git a/src/shims/unix/macos/foreign_items.rs b/src/shims/unix/macos/foreign_items.rs index 35751d5818ab8..da8e8a63bfe8a 100644 --- a/src/shims/unix/macos/foreign_items.rs +++ b/src/shims/unix/macos/foreign_items.rs @@ -173,8 +173,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Threading "pthread_setname_np" => { let [name] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; - let name = this.read_pointer(name)?; - this.pthread_setname_np(name)?; + let thread = this.pthread_self()?; + this.pthread_setname_np(thread, this.read_scalar(name)?.check_init()?)?; } // Incomplete shims that we "stub out" just to get pre-main initialization code to work. diff --git a/src/shims/unix/thread.rs b/src/shims/unix/thread.rs index 1a8531e880474..22114eae6724f 100644 --- a/src/shims/unix/thread.rs +++ b/src/shims/unix/thread.rs @@ -84,11 +84,27 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(0) } - fn pthread_self(&mut self, dest: &PlaceTy<'tcx, Provenance>) -> InterpResult<'tcx> { + fn pthread_self(&mut self) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); let thread_id = this.get_active_thread(); - this.write_scalar(Scalar::from_uint(thread_id.to_u32(), dest.layout.size), dest) + Ok(Scalar::from_machine_usize(thread_id.into(), this)) + } + + fn pthread_setname_np( + &mut self, + thread: Scalar, + name: Scalar, + ) -> InterpResult<'tcx, Scalar> { + let this = self.eval_context_mut(); + + let thread = ThreadId::try_from(thread.to_machine_usize(this)?).unwrap(); + let name = name.to_pointer(this)?; + + let name = this.read_c_str(name)?.to_owned(); + this.set_thread_name(thread, name); + + Ok(Scalar::from_u32(0)) } fn prctl(&mut self, args: &[OpTy<'tcx, Provenance>]) -> InterpResult<'tcx, i32> { @@ -117,7 +133,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // byte. Since `read_c_str` returns the string without the null // byte, we need to truncate to 15. name.truncate(15); - this.set_active_thread_name(name); + this.set_thread_name(this.get_active_thread(), name); } else if option == this.eval_libc_i32("PR_GET_NAME")? { if args.len() < 2 { throw_ub_format!( @@ -127,7 +143,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } let address = this.read_pointer(&args[1])?; - let mut name = this.get_active_thread_name().to_vec(); + let mut name = this.get_thread_name(this.get_active_thread()).to_vec(); name.push(0u8); assert!(name.len() <= 16); this.write_bytes_ptr(address, name)?; @@ -138,16 +154,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(0) } - fn pthread_setname_np(&mut self, name: Pointer>) -> InterpResult<'tcx> { - let this = self.eval_context_mut(); - this.assert_target_os("macos", "pthread_setname_np"); - - let name = this.read_c_str(name)?.to_owned(); - this.set_active_thread_name(name); - - Ok(()) - } - fn sched_yield(&mut self) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); diff --git a/src/thread.rs b/src/thread.rs index 683694f482eaa..6f394fa42fc9c 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -69,9 +69,9 @@ impl From for ThreadId { } } -impl ThreadId { - pub fn to_u32_scalar(&self) -> Scalar { - Scalar::from_u32(self.0) +impl From for u64 { + fn from(t: ThreadId) -> Self { + t.0.into() } } @@ -394,14 +394,9 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { Ok(()) } - /// Set the name of the active thread. - fn set_active_thread_name(&mut self, new_thread_name: Vec) { - self.active_thread_mut().thread_name = Some(new_thread_name); - } - - /// Get the name of the active thread. - pub fn get_active_thread_name(&self) -> &[u8] { - self.active_thread_ref().thread_name() + /// Set the name of the given thread. + pub fn set_thread_name(&mut self, thread: ThreadId, new_thread_name: Vec) { + self.threads[thread].thread_name = Some(new_thread_name); } /// Get the name of the given thread. @@ -704,18 +699,18 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } #[inline] - fn set_active_thread_name(&mut self, new_thread_name: Vec) { + fn set_thread_name(&mut self, thread: ThreadId, new_thread_name: Vec) { let this = self.eval_context_mut(); - this.machine.threads.set_active_thread_name(new_thread_name); + this.machine.threads.set_thread_name(thread, new_thread_name); } #[inline] - fn get_active_thread_name<'c>(&'c self) -> &'c [u8] + fn get_thread_name<'c>(&'c self, thread: ThreadId) -> &'c [u8] where 'mir: 'c, { let this = self.eval_context_ref(); - this.machine.threads.get_active_thread_name() + this.machine.threads.get_thread_name(thread) } #[inline] From 38a495346f89b04653b552e0aaff201065bd8038 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 11 Aug 2022 19:04:44 -0400 Subject: [PATCH 3635/3747] remove prctl, now that std does not use it any more it is a terrible variadic function... --- src/shims/unix/linux/foreign_items.rs | 6 --- src/shims/unix/thread.rs | 47 ----------------------- tests/pass/libc.rs | 55 --------------------------- 3 files changed, 108 deletions(-) diff --git a/src/shims/unix/linux/foreign_items.rs b/src/shims/unix/linux/foreign_items.rs index 817bfc7d1cc9c..8c569fb34bba6 100644 --- a/src/shims/unix/linux/foreign_items.rs +++ b/src/shims/unix/linux/foreign_items.rs @@ -51,12 +51,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // Threading - "prctl" => { - // prctl is variadic. (It is not documented like that in the manpage, but defined like that in the libc crate.) - this.check_abi_and_shim_symbol_clash(abi, Abi::C { unwind: false }, link_name)?; - let result = this.prctl(args)?; - this.write_scalar(Scalar::from_i32(result), dest)?; - } "pthread_condattr_setclock" => { let [attr, clock_id] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; diff --git a/src/shims/unix/thread.rs b/src/shims/unix/thread.rs index 22114eae6724f..0df70543fac88 100644 --- a/src/shims/unix/thread.rs +++ b/src/shims/unix/thread.rs @@ -107,53 +107,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(Scalar::from_u32(0)) } - fn prctl(&mut self, args: &[OpTy<'tcx, Provenance>]) -> InterpResult<'tcx, i32> { - let this = self.eval_context_mut(); - this.assert_target_os("linux", "prctl"); - - if args.is_empty() { - throw_ub_format!( - "incorrect number of arguments for `prctl`: got {}, expected at least 1", - args.len() - ); - } - - let option = this.read_scalar(&args[0])?.to_i32()?; - if option == this.eval_libc_i32("PR_SET_NAME")? { - if args.len() < 2 { - throw_ub_format!( - "incorrect number of arguments for `prctl` with `PR_SET_NAME`: got {}, expected at least 2", - args.len() - ); - } - - let address = this.read_pointer(&args[1])?; - let mut name = this.read_c_str(address)?.to_owned(); - // The name should be no more than 16 bytes, including the null - // byte. Since `read_c_str` returns the string without the null - // byte, we need to truncate to 15. - name.truncate(15); - this.set_thread_name(this.get_active_thread(), name); - } else if option == this.eval_libc_i32("PR_GET_NAME")? { - if args.len() < 2 { - throw_ub_format!( - "incorrect number of arguments for `prctl` with `PR_SET_NAME`: got {}, expected at least 2", - args.len() - ); - } - - let address = this.read_pointer(&args[1])?; - let mut name = this.get_thread_name(this.get_active_thread()).to_vec(); - name.push(0u8); - assert!(name.len() <= 16); - this.write_bytes_ptr(address, name)?; - } else { - throw_unsup_format!("unsupported prctl option {}", option); - } - - Ok(0) - } - fn sched_yield(&mut self) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); diff --git a/tests/pass/libc.rs b/tests/pass/libc.rs index b584856021484..f3aaccd57411b 100644 --- a/tests/pass/libc.rs +++ b/tests/pass/libc.rs @@ -277,58 +277,6 @@ fn test_rwlock_libc_static_initializer() { } } -/// Test whether the `prctl` shim correctly sets the thread name. -/// -/// Note: `prctl` exists only on Linux. -#[cfg(any(target_os = "linux"))] -fn test_prctl_thread_name() { - use libc::c_long; - use std::ffi::CString; - unsafe { - let mut buf = [255; 10]; - assert_eq!( - libc::prctl(libc::PR_GET_NAME, buf.as_mut_ptr(), 0 as c_long, 0 as c_long, 0 as c_long), - 0, - ); - // Rust runtime might set thread name, so we allow two options here. - assert!(&buf[..10] == b"\0" || &buf[..5] == b"main\0"); - let thread_name = CString::new("hello").expect("CString::new failed"); - assert_eq!( - libc::prctl( - libc::PR_SET_NAME, - thread_name.as_ptr(), - 0 as c_long, - 0 as c_long, - 0 as c_long, - ), - 0, - ); - let mut buf = [255; 6]; - assert_eq!( - libc::prctl(libc::PR_GET_NAME, buf.as_mut_ptr(), 0 as c_long, 0 as c_long, 0 as c_long), - 0, - ); - assert_eq!(b"hello\0", &buf); - let long_thread_name = CString::new("01234567890123456789").expect("CString::new failed"); - assert_eq!( - libc::prctl( - libc::PR_SET_NAME, - long_thread_name.as_ptr(), - 0 as c_long, - 0 as c_long, - 0 as c_long, - ), - 0, - ); - let mut buf = [255; 16]; - assert_eq!( - libc::prctl(libc::PR_GET_NAME, buf.as_mut_ptr(), 0 as c_long, 0 as c_long, 0 as c_long), - 0, - ); - assert_eq!(b"012345678901234\0", &buf); - } -} - /// Tests whether each thread has its own `__errno_location`. fn test_thread_local_errno() { #[cfg(target_os = "linux")] @@ -473,9 +421,6 @@ fn main() { #[cfg(any(target_os = "linux"))] test_mutex_libc_static_initializer_recursive(); - #[cfg(any(target_os = "linux"))] - test_prctl_thread_name(); - test_thread_local_errno(); #[cfg(any(target_os = "linux"))] From 96049ef88eb38af624134ee465d87eb91717b903 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 11 Aug 2022 19:27:15 -0400 Subject: [PATCH 3636/3747] move a bunch of type information into the respective shim --- src/shims/time.rs | 21 ++-- src/shims/unix/foreign_items.rs | 8 +- src/shims/unix/fs.rs | 136 ++++++++++++++------------ src/shims/unix/linux/foreign_items.rs | 8 +- src/shims/unix/macos/foreign_items.rs | 20 ++-- src/shims/unix/sync.rs | 10 +- 6 files changed, 106 insertions(+), 97 deletions(-) diff --git a/src/shims/time.rs b/src/shims/time.rs index d9edbe3d7bdf4..c3eb0161c210f 100644 --- a/src/shims/time.rs +++ b/src/shims/time.rs @@ -15,7 +15,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx &mut self, clk_id_op: &OpTy<'tcx, Provenance>, tp_op: &OpTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, i32> { + ) -> InterpResult<'tcx, Scalar> { // This clock support is deliberately minimal because a lot of clock types have fiddly // properties (is it possible for Miri to be suspended independently of the host?). If you // have a use for another clock type, please open an issue. @@ -46,7 +46,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } else { let einval = this.eval_libc("EINVAL")?; this.set_last_error(einval)?; - return Ok(-1); + return Ok(Scalar::from_i32(-1)); }; let tv_sec = duration.as_secs(); @@ -54,7 +54,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.write_int_fields(&[tv_sec.into(), tv_nsec.into()], &this.deref_operand(tp_op)?)?; - Ok(0) + Ok(Scalar::from_i32(0)) } fn gettimeofday( @@ -160,7 +160,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(-1) // Return non-zero on success } - fn mach_absolute_time(&self) -> InterpResult<'tcx, u64> { + fn mach_absolute_time(&self) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_ref(); this.assert_target_os("macos", "mach_absolute_time"); @@ -169,13 +169,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // This returns a u64, with time units determined dynamically by `mach_timebase_info`. // We return plain nanoseconds. let duration = Instant::now().duration_since(this.machine.time_anchor); - u64::try_from(duration.as_nanos()).map_err(|_| { + let res = u64::try_from(duration.as_nanos()).map_err(|_| { err_unsup_format!("programs running longer than 2^64 nanoseconds are not supported") - .into() - }) + })?; + Ok(Scalar::from_u64(res)) } - fn mach_timebase_info(&mut self, info_op: &OpTy<'tcx, Provenance>) -> InterpResult<'tcx, i32> { + fn mach_timebase_info( + &mut self, + info_op: &OpTy<'tcx, Provenance>, + ) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); this.assert_target_os("macos", "mach_timebase_info"); @@ -188,7 +191,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let (numer, denom) = (1, 1); this.write_int_fields(&[numer.into(), denom.into()], &info)?; - Ok(0) // KERN_SUCCESS + Ok(Scalar::from_i32(0)) // KERN_SUCCESS } fn nanosleep( diff --git a/src/shims/unix/foreign_items.rs b/src/shims/unix/foreign_items.rs index 0ca838b2103f5..3dea8f203bb75 100644 --- a/src/shims/unix/foreign_items.rs +++ b/src/shims/unix/foreign_items.rs @@ -63,7 +63,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "close" => { let [fd] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.close(fd)?; - this.write_scalar(Scalar::from_i32(result), dest)?; + this.write_scalar(result, dest)?; } "fcntl" => { // `fcntl` is variadic. The argument count is checked based on the first argument @@ -128,13 +128,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "lseek64" => { let [fd, offset, whence] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.lseek64(fd, offset, whence)?; - this.write_scalar(Scalar::from_i64(result), dest)?; + this.write_scalar(result, dest)?; } "ftruncate64" => { let [fd, length] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.ftruncate64(fd, length)?; - this.write_scalar(Scalar::from_i32(result), dest)?; + this.write_scalar(result, dest)?; } "fsync" => { let [fd] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; @@ -164,7 +164,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "realpath" => { let [path, resolved_path] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.realpath(path, resolved_path)?; - this.write_pointer(result, dest)?; + this.write_scalar(result, dest)?; } "mkstemp" => { let [template] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; diff --git a/src/shims/unix/fs.rs b/src/shims/unix/fs.rs index 951ddae2c14d0..2a6499ce99949 100644 --- a/src/shims/unix/fs.rs +++ b/src/shims/unix/fs.rs @@ -664,17 +664,19 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } - fn close(&mut self, fd_op: &OpTy<'tcx, Provenance>) -> InterpResult<'tcx, i32> { + fn close(&mut self, fd_op: &OpTy<'tcx, Provenance>) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); let fd = this.read_scalar(fd_op)?.to_i32()?; - if let Some(file_descriptor) = this.machine.file_handler.handles.remove(&fd) { - let result = file_descriptor.close(this.machine.communicate())?; - this.try_unwrap_io_result(result) - } else { - this.handle_not_found() - } + Ok(Scalar::from_i32( + if let Some(file_descriptor) = this.machine.file_handler.handles.remove(&fd) { + let result = file_descriptor.close(this.machine.communicate())?; + this.try_unwrap_io_result(result)? + } else { + this.handle_not_found()? + }, + )) } fn read( @@ -772,7 +774,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fd_op: &OpTy<'tcx, Provenance>, offset_op: &OpTy<'tcx, Provenance>, whence_op: &OpTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, i64> { + ) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); // Isolation check is done via `FileDescriptor` trait. @@ -790,18 +792,20 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } else { let einval = this.eval_libc("EINVAL")?; this.set_last_error(einval)?; - return Ok(-1); + return Ok(Scalar::from_i64(-1)); }; let communicate = this.machine.communicate(); - if let Some(file_descriptor) = this.machine.file_handler.handles.get_mut(&fd) { - let result = file_descriptor - .seek(communicate, seek_from)? - .map(|offset| i64::try_from(offset).unwrap()); - this.try_unwrap_io_result(result) - } else { - this.handle_not_found() - } + Ok(Scalar::from_i64( + if let Some(file_descriptor) = this.machine.file_handler.handles.get_mut(&fd) { + let result = file_descriptor + .seek(communicate, seek_from)? + .map(|offset| i64::try_from(offset).unwrap()); + this.try_unwrap_io_result(result)? + } else { + this.handle_not_found()? + }, + )) } fn unlink(&mut self, path_op: &OpTy<'tcx, Provenance>) -> InterpResult<'tcx, i32> { @@ -855,7 +859,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx &mut self, path_op: &OpTy<'tcx, Provenance>, buf_op: &OpTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, i32> { + ) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); this.assert_target_os("macos", "stat"); @@ -867,16 +871,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.reject_in_isolation("`stat`", reject_with)?; let eacc = this.eval_libc("EACCES")?; this.set_last_error(eacc)?; - return Ok(-1); + return Ok(Scalar::from_i32(-1)); } // `stat` always follows symlinks. let metadata = match FileMetadata::from_path(this, &path, true)? { Some(metadata) => metadata, - None => return Ok(-1), + None => return Ok(Scalar::from_i32(-1)), // `FileMetadata` has set errno }; - this.macos_stat_write_buf(metadata, buf_op) + Ok(Scalar::from_i32(this.macos_stat_write_buf(metadata, buf_op)?)) } // `lstat` is used to get symlink metadata. @@ -884,7 +888,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx &mut self, path_op: &OpTy<'tcx, Provenance>, buf_op: &OpTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, i32> { + ) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); this.assert_target_os("macos", "lstat"); @@ -896,22 +900,22 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.reject_in_isolation("`lstat`", reject_with)?; let eacc = this.eval_libc("EACCES")?; this.set_last_error(eacc)?; - return Ok(-1); + return Ok(Scalar::from_i32(-1)); } let metadata = match FileMetadata::from_path(this, &path, false)? { Some(metadata) => metadata, - None => return Ok(-1), + None => return Ok(Scalar::from_i32(-1)), // `FileMetadata` has set errno }; - this.macos_stat_write_buf(metadata, buf_op) + Ok(Scalar::from_i32(this.macos_stat_write_buf(metadata, buf_op)?)) } fn macos_fstat( &mut self, fd_op: &OpTy<'tcx, Provenance>, buf_op: &OpTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, i32> { + ) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); this.assert_target_os("macos", "fstat"); @@ -922,14 +926,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { this.reject_in_isolation("`fstat`", reject_with)?; // Set error code as "EBADF" (bad fd) - return this.handle_not_found(); + return Ok(Scalar::from_i32(this.handle_not_found()?)); } let metadata = match FileMetadata::from_fd(this, fd)? { Some(metadata) => metadata, - None => return Ok(-1), + None => return Ok(Scalar::from_i32(-1)), }; - this.macos_stat_write_buf(metadata, buf_op) + Ok(Scalar::from_i32(this.macos_stat_write_buf(metadata, buf_op)?)) } fn linux_statx( @@ -1343,7 +1347,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx dirp_op: &OpTy<'tcx, Provenance>, entry_op: &OpTy<'tcx, Provenance>, result_op: &OpTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, i32> { + ) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); this.assert_target_os("macos", "readdir_r"); @@ -1354,13 +1358,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { this.reject_in_isolation("`readdir_r`", reject_with)?; // Set error code as "EBADF" (bad fd) - return this.handle_not_found(); + return Ok(Scalar::from_i32(this.handle_not_found()?)); } let open_dir = this.machine.dir_handler.streams.get_mut(&dirp).ok_or_else(|| { err_unsup_format!("the DIR pointer passed to readdir_r did not come from opendir") })?; - match open_dir.read_dir.next() { + Ok(Scalar::from_i32(match open_dir.read_dir.next() { Some(Ok(dir_entry)) => { // Write into entry, write pointer to result, return 0 on success. // The name is written with write_os_str_to_c_str, while the rest of the @@ -1417,17 +1421,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let result_place = this.deref_operand(result_op)?; this.write_scalar(this.read_scalar(entry_op)?, &result_place.into())?; - Ok(0) + 0 } None => { // end of stream: return 0, assign *result=NULL this.write_null(&this.deref_operand(result_op)?.into())?; - Ok(0) + 0 } Some(Err(e)) => match e.raw_os_error() { // return positive error number on error - Some(error) => Ok(error), + Some(error) => error, None => { throw_unsup_format!( "the error {} couldn't be converted to a return value", @@ -1435,7 +1439,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) } }, - } + })) } fn closedir(&mut self, dirp_op: &OpTy<'tcx, Provenance>) -> InterpResult<'tcx, i32> { @@ -1463,7 +1467,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx &mut self, fd_op: &OpTy<'tcx, Provenance>, length_op: &OpTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, i32> { + ) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); let fd = this.read_scalar(fd_op)?.to_i32()?; @@ -1473,30 +1477,32 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { this.reject_in_isolation("`ftruncate64`", reject_with)?; // Set error code as "EBADF" (bad fd) - return this.handle_not_found(); + return Ok(Scalar::from_i32(this.handle_not_found()?)); } - if let Some(file_descriptor) = this.machine.file_handler.handles.get_mut(&fd) { - // FIXME: Support ftruncate64 for all FDs - let FileHandle { file, writable } = file_descriptor.as_file_handle()?; - if *writable { - if let Ok(length) = length.try_into() { - let result = file.set_len(length); - this.try_unwrap_io_result(result.map(|_| 0i32)) + Ok(Scalar::from_i32( + if let Some(file_descriptor) = this.machine.file_handler.handles.get_mut(&fd) { + // FIXME: Support ftruncate64 for all FDs + let FileHandle { file, writable } = file_descriptor.as_file_handle()?; + if *writable { + if let Ok(length) = length.try_into() { + let result = file.set_len(length); + this.try_unwrap_io_result(result.map(|_| 0i32))? + } else { + let einval = this.eval_libc("EINVAL")?; + this.set_last_error(einval)?; + -1 + } } else { + // The file is not writable let einval = this.eval_libc("EINVAL")?; this.set_last_error(einval)?; - Ok(-1) + -1 } } else { - // The file is not writable - let einval = this.eval_libc("EINVAL")?; - this.set_last_error(einval)?; - Ok(-1) - } - } else { - this.handle_not_found() - } + this.handle_not_found()? + }, + )) } fn fsync(&mut self, fd_op: &OpTy<'tcx, Provenance>) -> InterpResult<'tcx, i32> { @@ -1554,7 +1560,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx offset_op: &OpTy<'tcx, Provenance>, nbytes_op: &OpTy<'tcx, Provenance>, flags_op: &OpTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, i32> { + ) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); let fd = this.read_scalar(fd_op)?.to_i32()?; @@ -1565,7 +1571,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if offset < 0 || nbytes < 0 { let einval = this.eval_libc("EINVAL")?; this.set_last_error(einval)?; - return Ok(-1); + return Ok(Scalar::from_i32(-1)); } let allowed_flags = this.eval_libc_i32("SYNC_FILE_RANGE_WAIT_BEFORE")? | this.eval_libc_i32("SYNC_FILE_RANGE_WRITE")? @@ -1573,23 +1579,23 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if flags & allowed_flags != flags { let einval = this.eval_libc("EINVAL")?; this.set_last_error(einval)?; - return Ok(-1); + return Ok(Scalar::from_i32(-1)); } // Reject if isolation is enabled. if let IsolatedOp::Reject(reject_with) = this.machine.isolated_op { this.reject_in_isolation("`sync_file_range`", reject_with)?; // Set error code as "EBADF" (bad fd) - return this.handle_not_found(); + return Ok(Scalar::from_i32(this.handle_not_found()?)); } if let Some(file_descriptor) = this.machine.file_handler.handles.get(&fd) { // FIXME: Support sync_data_range for all FDs let FileHandle { file, writable } = file_descriptor.as_file_handle()?; let io_result = maybe_sync_file(file, *writable, File::sync_data); - this.try_unwrap_io_result(io_result) + Ok(Scalar::from_i32(this.try_unwrap_io_result(io_result)?)) } else { - this.handle_not_found() + Ok(Scalar::from_i32(this.handle_not_found()?)) } } @@ -1674,7 +1680,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx &mut self, path_op: &OpTy<'tcx, Provenance>, processed_path_op: &OpTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, Pointer>> { + ) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); this.assert_target_os_is_unix("realpath"); @@ -1686,7 +1692,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.reject_in_isolation("`realpath`", reject_with)?; let eacc = this.eval_libc("EACCES")?; this.set_last_error(eacc)?; - return Ok(Pointer::null()); + return Ok(Scalar::from_machine_usize(0, this)); } let result = std::fs::canonicalize(pathname); @@ -1717,16 +1723,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // seems like a bit of a mess anyway: . let enametoolong = this.eval_libc("ENAMETOOLONG")?; this.set_last_error(enametoolong)?; - return Ok(Pointer::null()); + return Ok(Scalar::from_machine_usize(0, this)); } processed_ptr }; - Ok(dest) + Ok(Scalar::from_maybe_pointer(dest, this)) } Err(e) => { this.set_last_error_from_io_error(e.kind())?; - Ok(Pointer::null()) + Ok(Scalar::from_machine_usize(0, this)) } } } diff --git a/src/shims/unix/linux/foreign_items.rs b/src/shims/unix/linux/foreign_items.rs index 8c569fb34bba6..6881d829c150d 100644 --- a/src/shims/unix/linux/foreign_items.rs +++ b/src/shims/unix/linux/foreign_items.rs @@ -38,7 +38,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let [fd, offset, nbytes, flags] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.sync_file_range(fd, offset, nbytes, flags)?; - this.write_scalar(Scalar::from_i32(result), dest)?; + this.write_scalar(result, dest)?; } // Time related shims @@ -47,7 +47,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let [clk_id, tp] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.clock_gettime(clk_id, tp)?; - this.write_scalar(Scalar::from_i32(result), dest)?; + this.write_scalar(result, dest)?; } // Threading @@ -55,13 +55,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let [attr, clock_id] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.pthread_condattr_setclock(attr, clock_id)?; - this.write_scalar(Scalar::from_i32(result), dest)?; + this.write_scalar(result, dest)?; } "pthread_condattr_getclock" => { let [attr, clock_id] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.pthread_condattr_getclock(attr, clock_id)?; - this.write_scalar(Scalar::from_i32(result), dest)?; + this.write_scalar(result, dest)?; } "pthread_setname_np" => { let [thread, name] = diff --git a/src/shims/unix/macos/foreign_items.rs b/src/shims/unix/macos/foreign_items.rs index da8e8a63bfe8a..fd7d5fb763eef 100644 --- a/src/shims/unix/macos/foreign_items.rs +++ b/src/shims/unix/macos/foreign_items.rs @@ -29,24 +29,24 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "close$NOCANCEL" => { let [result] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.close(result)?; - this.write_scalar(Scalar::from_i32(result), dest)?; + this.write_scalar(result, dest)?; } "stat" | "stat64" | "stat$INODE64" => { let [path, buf] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.macos_stat(path, buf)?; - this.write_scalar(Scalar::from_i32(result), dest)?; + this.write_scalar(result, dest)?; } "lstat" | "lstat64" | "lstat$INODE64" => { let [path, buf] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.macos_lstat(path, buf)?; - this.write_scalar(Scalar::from_i32(result), dest)?; + this.write_scalar(result, dest)?; } "fstat" | "fstat64" | "fstat$INODE64" => { let [fd, buf] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.macos_fstat(fd, buf)?; - this.write_scalar(Scalar::from_i32(result), dest)?; + this.write_scalar(result, dest)?; } "opendir$INODE64" => { let [name] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; @@ -57,27 +57,27 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let [dirp, entry, result] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.macos_readdir_r(dirp, entry, result)?; - this.write_scalar(Scalar::from_i32(result), dest)?; + this.write_scalar(result, dest)?; } "lseek" => { let [fd, offset, whence] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; // macOS is 64bit-only, so this is lseek64 let result = this.lseek64(fd, offset, whence)?; - this.write_scalar(Scalar::from_i64(result), dest)?; + this.write_scalar(result, dest)?; } "ftruncate" => { let [fd, length] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; // macOS is 64bit-only, so this is ftruncate64 let result = this.ftruncate64(fd, length)?; - this.write_scalar(Scalar::from_i32(result), dest)?; + this.write_scalar(result, dest)?; } "realpath$DARWIN_EXTSN" => { let [path, resolved_path] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.realpath(path, resolved_path)?; - this.write_pointer(result, dest)?; + this.write_scalar(result, dest)?; } // Environment related shims @@ -93,13 +93,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "mach_absolute_time" => { let [] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.mach_absolute_time()?; - this.write_scalar(Scalar::from_u64(result), dest)?; + this.write_scalar(result, dest)?; } "mach_timebase_info" => { let [info] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let result = this.mach_timebase_info(info)?; - this.write_scalar(Scalar::from_i32(result), dest)?; + this.write_scalar(result, dest)?; } // Access to command-line arguments diff --git a/src/shims/unix/sync.rs b/src/shims/unix/sync.rs index 18226c2b8cf64..69e632915b170 100644 --- a/src/shims/unix/sync.rs +++ b/src/shims/unix/sync.rs @@ -723,7 +723,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx &mut self, attr_op: &OpTy<'tcx, Provenance>, clock_id_op: &OpTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, i32> { + ) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); let clock_id = this.read_scalar(clock_id_op)?.check_init()?; @@ -733,23 +733,23 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx condattr_set_clock_id(this, attr_op, clock_id)?; } else { let einval = this.eval_libc_i32("EINVAL")?; - return Ok(einval); + return Ok(Scalar::from_i32(einval)); } - Ok(0) + Ok(Scalar::from_i32(0)) } fn pthread_condattr_getclock( &mut self, attr_op: &OpTy<'tcx, Provenance>, clk_id_op: &OpTy<'tcx, Provenance>, - ) -> InterpResult<'tcx, i32> { + ) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); let clock_id = condattr_get_clock_id(this, attr_op)?; this.write_scalar(clock_id, &this.deref_operand(clk_id_op)?.into())?; - Ok(0) + Ok(Scalar::from_i32(0)) } fn pthread_condattr_destroy( From 74e87b1dc573c2488c6cd319216f08b0c39d7e6f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 12 Aug 2022 11:24:55 -0400 Subject: [PATCH 3637/3747] add test for raw_eq on a pointer --- tests/fail/intrinsics/raw_eq_on_ptr.rs | 11 +++++++++++ tests/fail/intrinsics/raw_eq_on_ptr.stderr | 14 ++++++++++++++ 2 files changed, 25 insertions(+) create mode 100644 tests/fail/intrinsics/raw_eq_on_ptr.rs create mode 100644 tests/fail/intrinsics/raw_eq_on_ptr.stderr diff --git a/tests/fail/intrinsics/raw_eq_on_ptr.rs b/tests/fail/intrinsics/raw_eq_on_ptr.rs new file mode 100644 index 0000000000000..675b7cf9224bd --- /dev/null +++ b/tests/fail/intrinsics/raw_eq_on_ptr.rs @@ -0,0 +1,11 @@ +#![feature(intrinsics)] + +extern "rust-intrinsic" { + fn raw_eq(a: &T, b: &T) -> bool; +} + +fn main() { + let x = &0; + // FIXME: the error message is not great (should be UB rather than 'unsupported') + unsafe { raw_eq(&x, &x) }; //~ERROR: unsupported operation +} diff --git a/tests/fail/intrinsics/raw_eq_on_ptr.stderr b/tests/fail/intrinsics/raw_eq_on_ptr.stderr new file mode 100644 index 0000000000000..6c5e618315c80 --- /dev/null +++ b/tests/fail/intrinsics/raw_eq_on_ptr.stderr @@ -0,0 +1,14 @@ +error: unsupported operation: unable to turn pointer into raw bytes + --> $DIR/raw_eq_on_ptr.rs:LL:CC + | +LL | unsafe { raw_eq(&x, &x) }; + | ^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | + = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support + = note: backtrace: + = note: inside `main` at $DIR/raw_eq_on_ptr.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + From e75b2c8543ee08abed6f3d072447afc514af13bb Mon Sep 17 00:00:00 2001 From: 5225225 <5225225@mailbox.org> Date: Sat, 13 Aug 2022 13:20:56 +0100 Subject: [PATCH 3638/3747] Breaking posix_memalign precondition is not UB --- src/shims/unix/foreign_items.rs | 34 ++++++-------- tests/pass/posix_memalign.rs | 83 +++++++++++++++++++++++++++++++++ 2 files changed, 98 insertions(+), 19 deletions(-) create mode 100644 tests/pass/posix_memalign.rs diff --git a/src/shims/unix/foreign_items.rs b/src/shims/unix/foreign_items.rs index 3dea8f203bb75..877a144963a2a 100644 --- a/src/shims/unix/foreign_items.rs +++ b/src/shims/unix/foreign_items.rs @@ -186,27 +186,23 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let align = this.read_scalar(align)?.to_machine_usize(this)?; let size = this.read_scalar(size)?.to_machine_usize(this)?; // Align must be power of 2, and also at least ptr-sized (POSIX rules). - if !align.is_power_of_two() { - throw_ub_format!("posix_memalign: alignment must be a power of two, but is {}", align); - } - if align < this.pointer_size().bytes() { - throw_ub_format!( - "posix_memalign: alignment must be at least the size of a pointer, but is {}", - align, - ); - } - - if size == 0 { - this.write_null(&ret.into())?; + // But failure to adhere to this is not UB, it's an error condition. + if !align.is_power_of_two() || align < this.pointer_size().bytes() { + let einval = this.eval_libc_i32("EINVAL")?; + this.write_int(einval, dest)?; } else { - let ptr = this.allocate_ptr( - Size::from_bytes(size), - Align::from_bytes(align).unwrap(), - MiriMemoryKind::C.into(), - )?; - this.write_pointer(ptr, &ret.into())?; + if size == 0 { + this.write_null(&ret.into())?; + } else { + let ptr = this.allocate_ptr( + Size::from_bytes(size), + Align::from_bytes(align).unwrap(), + MiriMemoryKind::C.into(), + )?; + this.write_pointer(ptr, &ret.into())?; + } + this.write_null(dest)?; } - this.write_null(dest)?; } // Dynamic symbol loading diff --git a/tests/pass/posix_memalign.rs b/tests/pass/posix_memalign.rs new file mode 100644 index 0000000000000..5dadb62436d64 --- /dev/null +++ b/tests/pass/posix_memalign.rs @@ -0,0 +1,83 @@ +//@ignore-target-windows: No libc on Windows + +#![feature(rustc_private)] +#![feature(pointer_is_aligned)] +#![feature(strict_provenance)] + +use core::ptr; + +fn main() { + // A normal allocation. + unsafe { + let mut ptr: *mut libc::c_void = ptr::null_mut(); + let align = 8; + let size = 64; + assert_eq!(libc::posix_memalign(&mut ptr, align, size), 0); + assert!(!ptr.is_null()); + assert!(ptr.is_aligned_to(align)); + ptr.cast::().write_bytes(1, size); + libc::free(ptr); + } + + // Align > size. + unsafe { + let mut ptr: *mut libc::c_void = ptr::null_mut(); + let align = 64; + let size = 8; + assert_eq!(libc::posix_memalign(&mut ptr, align, size), 0); + assert!(!ptr.is_null()); + assert!(ptr.is_aligned_to(align)); + ptr.cast::().write_bytes(1, size); + libc::free(ptr); + } + + // Size not multiple of align + unsafe { + let mut ptr: *mut libc::c_void = ptr::null_mut(); + let align = 16; + let size = 31; + assert_eq!(libc::posix_memalign(&mut ptr, align, size), 0); + assert!(!ptr.is_null()); + assert!(ptr.is_aligned_to(align)); + ptr.cast::().write_bytes(1, size); + libc::free(ptr); + } + + // Size == 0 + unsafe { + let mut ptr: *mut libc::c_void = ptr::null_mut(); + let align = 64; + let size = 0; + assert_eq!(libc::posix_memalign(&mut ptr, align, size), 0); + // We are not required to return null if size == 0, but we currently do. + // It's fine to remove this assert if we start returning non-null pointers. + assert!(ptr.is_null()); + assert!(ptr.is_aligned_to(align)); + // Regardless of what we return, it must be `free`able. + libc::free(ptr); + } + + // Non-power of 2 align + unsafe { + let mut ptr: *mut libc::c_void = ptr::invalid_mut(0x1234567); + let align = 15; + let size = 8; + assert_eq!(libc::posix_memalign(&mut ptr, align, size), libc::EINVAL); + // The pointer is not modified on failure, posix_memalign(3) says: + // > On Linux (and other systems), posix_memalign() does not modify memptr on failure. + // > A requirement standardizing this behavior was added in POSIX.1-2008 TC2. + assert_eq!(ptr.addr(), 0x1234567); + } + + // Too small align (smaller than ptr) + unsafe { + let mut ptr: *mut libc::c_void = ptr::invalid_mut(0x1234567); + let align = std::mem::size_of::() / 2; + let size = 8; + assert_eq!(libc::posix_memalign(&mut ptr, align, size), libc::EINVAL); + // The pointer is not modified on failure, posix_memalign(3) says: + // > On Linux (and other systems), posix_memalign() does not modify memptr on failure. + // > A requirement standardizing this behavior was added in POSIX.1-2008 TC2. + assert_eq!(ptr.addr(), 0x1234567); + } +} From 7df41a77b821946e2f187d938e4bc9ef49e03f79 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 13 Aug 2022 08:22:19 -0400 Subject: [PATCH 3639/3747] rustup --- rust-version | 2 +- src/lib.rs | 1 + tests/fail/const-ub-checks.rs | 11 +++++++++++ tests/fail/const-ub-checks.stderr | 9 +++++++++ 4 files changed, 22 insertions(+), 1 deletion(-) create mode 100644 tests/fail/const-ub-checks.rs create mode 100644 tests/fail/const-ub-checks.stderr diff --git a/rust-version b/rust-version index 0bcadc0a366f8..fdd18704d1840 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -20ffea6938b5839c390252e07940b99e3b6a889a +75b7e52e92c3b00fc891b47f5b2efdff0a2be55a diff --git a/src/lib.rs b/src/lib.rs index 94958b2ff5fb2..ba337f28311e9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -116,4 +116,5 @@ pub const MIRI_DEFAULT_ARGS: &[&str] = &[ "-Zmir-opt-level=0", "--cfg=miri", "-Cdebug-assertions=on", + "-Zextra-const-ub-checks", ]; diff --git a/tests/fail/const-ub-checks.rs b/tests/fail/const-ub-checks.rs new file mode 100644 index 0000000000000..fa522c30cbd0f --- /dev/null +++ b/tests/fail/const-ub-checks.rs @@ -0,0 +1,11 @@ +#![feature(const_ptr_read)] + +const UNALIGNED_READ: () = unsafe { + let x = &[0u8; 4]; + let ptr = x.as_ptr().cast::(); + ptr.read(); //~ERROR: evaluation of constant value failed +}; + +fn main() { + let _x = UNALIGNED_READ; +} diff --git a/tests/fail/const-ub-checks.stderr b/tests/fail/const-ub-checks.stderr new file mode 100644 index 0000000000000..a8b7ea242b970 --- /dev/null +++ b/tests/fail/const-ub-checks.stderr @@ -0,0 +1,9 @@ +error[E0080]: evaluation of constant value failed + --> $DIR/const-ub-checks.rs:LL:CC + | +LL | ptr.read(); + | ^^^^^^^^^^ accessing memory with alignment ALIGN, but alignment ALIGN is required + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0080`. From d59bad95fdd0157df3bfcbfb878bc7c451d0bee2 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 13 Aug 2022 09:03:30 -0400 Subject: [PATCH 3640/3747] fix data_race test --- tests/pass/concurrency/data_race.rs | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/tests/pass/concurrency/data_race.rs b/tests/pass/concurrency/data_race.rs index 5d1e1bb266cad..9c7030db3db8b 100644 --- a/tests/pass/concurrency/data_race.rs +++ b/tests/pass/concurrency/data_race.rs @@ -1,5 +1,5 @@ //@ignore-target-windows: Concurrency on Windows is not supported yet. -//@compile-flags: -Zmiri-disable-weak-memory-emulation +//@compile-flags: -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 use std::sync::atomic::{fence, AtomicUsize, Ordering}; use std::thread::spawn; @@ -10,9 +10,9 @@ struct EvilSend(pub T); unsafe impl Send for EvilSend {} unsafe impl Sync for EvilSend {} -static SYNC: AtomicUsize = AtomicUsize::new(0); - fn test_fence_sync() { + static SYNC: AtomicUsize = AtomicUsize::new(0); + let mut var = 0u32; let ptr = &mut var as *mut u32; let evil_ptr = EvilSend(ptr); @@ -28,7 +28,7 @@ fn test_fence_sync() { fence(Ordering::Acquire); unsafe { *evil_ptr.0 } } else { - 0 + panic!(); // relies on thread 2 going last } }); @@ -56,6 +56,8 @@ fn test_multiple_reads() { } pub fn test_rmw_no_block() { + static SYNC: AtomicUsize = AtomicUsize::new(0); + let mut a = 0u32; let b = &mut a as *mut u32; let c = EvilSend(b); @@ -77,11 +79,13 @@ pub fn test_rmw_no_block() { j1.join().unwrap(); j2.join().unwrap(); let v = j3.join().unwrap(); - assert!(v == 1 || v == 2); + assert!(v == 1 || v == 2); // relies on thread 3 going last } } pub fn test_simple_release() { + static SYNC: AtomicUsize = AtomicUsize::new(0); + let mut a = 0u32; let b = &mut a as *mut u32; let c = EvilSend(b); @@ -95,7 +99,7 @@ pub fn test_simple_release() { let j2 = spawn(move || if SYNC.load(Ordering::Acquire) == 1 { *c.0 } else { 0 }); j1.join().unwrap(); - assert_eq!(j2.join().unwrap(), 1); + assert_eq!(j2.join().unwrap(), 1); // relies on thread 2 going last } } From e70473d9442d17de7f7d38d3d7e8606226d1c4fa Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sun, 14 Aug 2022 07:51:45 -0400 Subject: [PATCH 3641/3747] rustup --- rust-version | 2 +- tests/fail/provenance/strict_provenance_cast.rs | 3 ++- tests/fail/provenance/strict_provenance_cast.stderr | 4 ++-- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/rust-version b/rust-version index fdd18704d1840..aaf664f44e3e0 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -75b7e52e92c3b00fc891b47f5b2efdff0a2be55a +2fbc08e2ce64dee45a29cb6133da6b32366268aa diff --git a/tests/fail/provenance/strict_provenance_cast.rs b/tests/fail/provenance/strict_provenance_cast.rs index 0016e78792540..04552d0c332fd 100644 --- a/tests/fail/provenance/strict_provenance_cast.rs +++ b/tests/fail/provenance/strict_provenance_cast.rs @@ -1,6 +1,7 @@ //@compile-flags: -Zmiri-strict-provenance +#![feature(strict_provenance)] fn main() { let addr = &0 as *const i32 as usize; - let _ptr = addr as *const i32; //~ ERROR: integer-to-pointer casts and `ptr::from_exposed_addr` are not supported + let _ptr = std::ptr::from_exposed_addr::(addr); //~ ERROR: integer-to-pointer casts and `ptr::from_exposed_addr` are not supported } diff --git a/tests/fail/provenance/strict_provenance_cast.stderr b/tests/fail/provenance/strict_provenance_cast.stderr index ff6ab1c9e95bf..5796a3196dc6c 100644 --- a/tests/fail/provenance/strict_provenance_cast.stderr +++ b/tests/fail/provenance/strict_provenance_cast.stderr @@ -1,8 +1,8 @@ error: unsupported operation: integer-to-pointer casts and `ptr::from_exposed_addr` are not supported with `-Zmiri-strict-provenance` --> $DIR/strict_provenance_cast.rs:LL:CC | -LL | let _ptr = addr as *const i32; - | ^^^^^^^^^^^^^^^^^^ integer-to-pointer casts and `ptr::from_exposed_addr` are not supported with `-Zmiri-strict-provenance` +LL | let _ptr = std::ptr::from_exposed_addr::(addr); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ integer-to-pointer casts and `ptr::from_exposed_addr` are not supported with `-Zmiri-strict-provenance` | = help: use Strict Provenance APIs (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance, https://crates.io/crates/sptr) instead = note: backtrace: From 297ddffff3248c0d60a07a8a96cb2d06d6191a2b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 15 Aug 2022 18:31:40 -0400 Subject: [PATCH 3642/3747] add test that we do not merge neighboring SRW --- .../disable_mut_does_not_merge_srw.rs | 17 +++++++++++ .../disable_mut_does_not_merge_srw.stderr | 28 +++++++++++++++++++ 2 files changed, 45 insertions(+) create mode 100644 tests/fail/stacked_borrows/disable_mut_does_not_merge_srw.rs create mode 100644 tests/fail/stacked_borrows/disable_mut_does_not_merge_srw.stderr diff --git a/tests/fail/stacked_borrows/disable_mut_does_not_merge_srw.rs b/tests/fail/stacked_borrows/disable_mut_does_not_merge_srw.rs new file mode 100644 index 0000000000000..1dcd7621acd2c --- /dev/null +++ b/tests/fail/stacked_borrows/disable_mut_does_not_merge_srw.rs @@ -0,0 +1,17 @@ +// This tests demonstrates the effect of 'Disabling' mutable references on reads, rather than +// removing them from the stack -- the latter would 'merge' neighboring SRW groups which we would +// like to avoid. +fn main() { + unsafe { + let mut mem = 0; + let base = &mut mem as *mut i32; // the base pointer we build the rest of the stack on + let mutref = &mut *base; + let raw = mutref as *mut i32; + // in the stack, we now have [base, mutref, raw] + let _val = *base; + // now mutref is disabled + *base = 1; + // this should pop raw from the stack, since it is in a different SRW group + let _val = *raw; //~ERROR: that tag does not exist in the borrow stack + } +} diff --git a/tests/fail/stacked_borrows/disable_mut_does_not_merge_srw.stderr b/tests/fail/stacked_borrows/disable_mut_does_not_merge_srw.stderr new file mode 100644 index 0000000000000..b3f0204c09faf --- /dev/null +++ b/tests/fail/stacked_borrows/disable_mut_does_not_merge_srw.stderr @@ -0,0 +1,28 @@ +error: Undefined Behavior: attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + --> $DIR/disable_mut_does_not_merge_srw.rs:LL:CC + | +LL | let _val = *raw; + | ^^^^ + | | + | attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | this error occurs as part of an access at ALLOC[0x0..0x4] + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information +help: was created by a retag at offsets [0x0..0x4] + --> $DIR/disable_mut_does_not_merge_srw.rs:LL:CC + | +LL | let raw = mutref as *mut i32; + | ^^^^^^ +help: was later invalidated at offsets [0x0..0x4] + --> $DIR/disable_mut_does_not_merge_srw.rs:LL:CC + | +LL | *base = 1; + | ^^^^^^^^^ + = note: backtrace: + = note: inside `main` at $DIR/disable_mut_does_not_merge_srw.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + From 79ebfa25dcde23f3eb95238a23707b69cc01a528 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 15 Aug 2022 18:35:11 -0400 Subject: [PATCH 3643/3747] make Miri build without the stack-cache feature --- src/stacked_borrows/stack.rs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/stacked_borrows/stack.rs b/src/stacked_borrows/stack.rs index 6fd8d85f2b5fe..4a9a13d35b527 100644 --- a/src/stacked_borrows/stack.rs +++ b/src/stacked_borrows/stack.rs @@ -81,7 +81,7 @@ impl<'tcx> Stack { /// Panics if any of the caching mechanisms have broken, /// - The StackCache indices don't refer to the parallel items, /// - There are no Unique items outside of first_unique..last_unique - #[cfg(debug_assertions)] + #[cfg(all(feature = "stack-cache", debug_assertions))] fn verify_cache_consistency(&self) { // Only a full cache needs to be valid. Also see the comments in find_granting_cache // and set_unknown_bottom. @@ -128,7 +128,7 @@ impl<'tcx> Stack { tag: ProvenanceExtra, exposed_tags: &FxHashSet, ) -> Result, ()> { - #[cfg(debug_assertions)] + #[cfg(all(feature = "stack-cache", debug_assertions))] self.verify_cache_consistency(); let ProvenanceExtra::Concrete(tag) = tag else { @@ -320,13 +320,14 @@ impl<'tcx> Stack { if disable_start <= unique_range.end { let lower = unique_range.start.max(disable_start); - let upper = self.unique_range.end; + let upper = unique_range.end; for item in &mut self.borrows[lower..upper] { if item.perm() == Permission::Unique { log::trace!("access: disabling item {:?}", item); visitor(*item)?; item.set_permission(Permission::Disabled); // Also update all copies of this item in the cache. + #[cfg(feature = "stack-cache")] for it in &mut self.cache.items { if it.tag() == item.tag() { it.set_permission(Permission::Disabled); @@ -347,7 +348,7 @@ impl<'tcx> Stack { self.unique_range.end = self.unique_range.end.min(disable_start); } - #[cfg(debug_assertions)] + #[cfg(all(feature = "stack-cache", debug_assertions))] self.verify_cache_consistency(); Ok(()) @@ -402,7 +403,7 @@ impl<'tcx> Stack { self.unique_range = 0..0; } - #[cfg(debug_assertions)] + #[cfg(all(feature = "stack-cache", debug_assertions))] self.verify_cache_consistency(); Ok(()) } From 2e3da5d8c30238cddbc63131776af485d2d10cda Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 15 Aug 2022 19:33:07 -0400 Subject: [PATCH 3644/3747] check no-default-features and all-features build on CI --- ci.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ci.sh b/ci.sh index a29fc3deca58d..8189596dba777 100755 --- a/ci.sh +++ b/ci.sh @@ -5,11 +5,12 @@ set -x # Determine configuration export RUSTFLAGS="-D warnings" export CARGO_INCREMENTAL=0 -export CARGO_EXTRA_FLAGS="--all-features" # Prepare echo "Build and install miri" ./miri install # implicitly locked +./miri check --no-default-features # make sure this can be built +./miri check --all-features # and this, too ./miri build --all-targets --locked # the build that all the `./miri test` below will use echo From db43ee5714900900a52ad5050b77993288472ce2 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 15 Aug 2022 20:23:19 -0400 Subject: [PATCH 3645/3747] defend test against overly smart Miri --- .../stacked_borrows/disable_mut_does_not_merge_srw.rs | 11 ++++++++--- .../disable_mut_does_not_merge_srw.stderr | 4 ++-- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/tests/fail/stacked_borrows/disable_mut_does_not_merge_srw.rs b/tests/fail/stacked_borrows/disable_mut_does_not_merge_srw.rs index 1dcd7621acd2c..fed5cd26f4d63 100644 --- a/tests/fail/stacked_borrows/disable_mut_does_not_merge_srw.rs +++ b/tests/fail/stacked_borrows/disable_mut_does_not_merge_srw.rs @@ -5,9 +5,14 @@ fn main() { unsafe { let mut mem = 0; let base = &mut mem as *mut i32; // the base pointer we build the rest of the stack on - let mutref = &mut *base; - let raw = mutref as *mut i32; - // in the stack, we now have [base, mutref, raw] + let raw = { + let mutref = &mut *base; + mutref as *mut i32 + }; + // In the stack, we now have [base, mutref, raw]. + // We do this in a weird way where `mutref` is out of scope here, just in case + // Miri decides to get smart and argue that items for tags that are no longer + // used by any pointer stored anywhere in the machine can be removed. let _val = *base; // now mutref is disabled *base = 1; diff --git a/tests/fail/stacked_borrows/disable_mut_does_not_merge_srw.stderr b/tests/fail/stacked_borrows/disable_mut_does_not_merge_srw.stderr index b3f0204c09faf..9f5182ae98ffd 100644 --- a/tests/fail/stacked_borrows/disable_mut_does_not_merge_srw.stderr +++ b/tests/fail/stacked_borrows/disable_mut_does_not_merge_srw.stderr @@ -12,8 +12,8 @@ LL | let _val = *raw; help: was created by a retag at offsets [0x0..0x4] --> $DIR/disable_mut_does_not_merge_srw.rs:LL:CC | -LL | let raw = mutref as *mut i32; - | ^^^^^^ +LL | mutref as *mut i32 + | ^^^^^^ help: was later invalidated at offsets [0x0..0x4] --> $DIR/disable_mut_does_not_merge_srw.rs:LL:CC | From 7c18b38e04f61442ad74533d7b4ed2907238fade Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Mon, 15 Aug 2022 18:13:11 -0400 Subject: [PATCH 3646/3747] Rename memory hooks --- src/machine.rs | 12 ++++++------ src/stacked_borrows/mod.rs | 6 +++--- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/machine.rs b/src/machine.rs index 14df64d8aa308..4ebf7dceab839 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -780,7 +780,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { } #[inline(always)] - fn memory_read( + fn before_memory_read( _tcx: TyCtxt<'tcx>, machine: &Self, alloc_extra: &AllocExtra, @@ -796,7 +796,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { )?; } if let Some(stacked_borrows) = &alloc_extra.stacked_borrows { - stacked_borrows.borrow_mut().memory_read( + stacked_borrows.borrow_mut().before_memory_read( alloc_id, prov_extra, range, @@ -812,7 +812,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { } #[inline(always)] - fn memory_written( + fn before_memory_write( _tcx: TyCtxt<'tcx>, machine: &mut Self, alloc_extra: &mut AllocExtra, @@ -828,7 +828,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { )?; } if let Some(stacked_borrows) = &mut alloc_extra.stacked_borrows { - stacked_borrows.get_mut().memory_written( + stacked_borrows.get_mut().before_memory_write( alloc_id, prov_extra, range, @@ -844,7 +844,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { } #[inline(always)] - fn memory_deallocated( + fn before_memory_deallocation( _tcx: TyCtxt<'tcx>, machine: &mut Self, alloc_extra: &mut AllocExtra, @@ -863,7 +863,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { )?; } if let Some(stacked_borrows) = &mut alloc_extra.stacked_borrows { - stacked_borrows.get_mut().memory_deallocated( + stacked_borrows.get_mut().before_memory_deallocation( alloc_id, prove_extra, range, diff --git a/src/stacked_borrows/mod.rs b/src/stacked_borrows/mod.rs index e0cc3e81cf0b4..b6b03f1669997 100644 --- a/src/stacked_borrows/mod.rs +++ b/src/stacked_borrows/mod.rs @@ -657,7 +657,7 @@ impl Stacks { } #[inline(always)] - pub fn memory_read<'tcx>( + pub fn before_memory_read<'tcx>( &mut self, alloc_id: AllocId, tag: ProvenanceExtra, @@ -688,7 +688,7 @@ impl Stacks { } #[inline(always)] - pub fn memory_written<'tcx>( + pub fn before_memory_write<'tcx>( &mut self, alloc_id: AllocId, tag: ProvenanceExtra, @@ -719,7 +719,7 @@ impl Stacks { } #[inline(always)] - pub fn memory_deallocated<'tcx>( + pub fn before_memory_deallocation<'tcx>( &mut self, alloc_id: AllocId, tag: ProvenanceExtra, From 3992f067283dbfb9e2996d3fcee5ad2d2fac9c24 Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Tue, 16 Aug 2022 08:07:46 -0400 Subject: [PATCH 3647/3747] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index aaf664f44e3e0..7317986eaea43 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -2fbc08e2ce64dee45a29cb6133da6b32366268aa +8556e6620e4866526b3cea767ad8c20ae877a569 From ecb8ac5cf41bcb20921df6be22caad07fb74136a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 16 Aug 2022 08:54:20 -0400 Subject: [PATCH 3648/3747] make sure all builds are locked on CI --- ci.sh | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/ci.sh b/ci.sh index 8189596dba777..51cec8fe16196 100755 --- a/ci.sh +++ b/ci.sh @@ -2,16 +2,18 @@ set -euo pipefail set -x -# Determine configuration +# Determine configuration for installed build +echo "Installing release version of Miri" export RUSTFLAGS="-D warnings" export CARGO_INCREMENTAL=0 - -# Prepare -echo "Build and install miri" ./miri install # implicitly locked + +# Prepare debug build for direct `./miri` invocations +echo "Building debug version of Miri" +export CARGO_EXTRA_FLAGS="--locked" ./miri check --no-default-features # make sure this can be built ./miri check --all-features # and this, too -./miri build --all-targets --locked # the build that all the `./miri test` below will use +./miri build --all-targets # the build that all the `./miri test` below will use echo # Test @@ -23,13 +25,13 @@ function run_tests { fi ## ui test suite - ./miri test --locked + ./miri test if [ -z "${MIRI_TEST_TARGET+exists}" ]; then # Only for host architecture: tests with optimizations (`-O` is what cargo passes, but crank MIR # optimizations up all the way). # Optimizations change diagnostics (mostly backtraces), so we don't check them #FIXME(#2155): we want to only run the pass and panic tests here, not the fail tests. - MIRIFLAGS="-O -Zmir-opt-level=4" MIRI_SKIP_UI_CHECKS=1 ./miri test --locked -- tests/{pass,panic} + MIRIFLAGS="-O -Zmir-opt-level=4" MIRI_SKIP_UI_CHECKS=1 ./miri test -- tests/{pass,panic} fi ## test-cargo-miri @@ -70,7 +72,7 @@ function run_tests_minimal { echo "Testing MINIMAL host architecture: only testing $@" fi - ./miri test --locked -- "$@" + ./miri test -- "$@" } # host From b4bdd5ca10d8887b32b0f2010f4c16e5f0285b26 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 17 Aug 2022 07:44:12 -0400 Subject: [PATCH 3649/3747] fix vscode configuration --- CONTRIBUTING.md | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 42f77b5cbc0ed..b2964e046ecb0 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -174,16 +174,14 @@ to `.vscode/settings.json` in your local Miri clone: "check", "--message-format=json" ], - "rust-analyzer.buildScripts.overrideCommand": [ + // Contrary to what the name suggests, this also affects proc macros. + "rust-analyzer.cargo.buildScripts.overrideCommand": [ "env", "MIRI_AUTO_OPS=no", "./miri", "check", "--message-format=json", ], - "rust-analyzer.rustfmt.extraArgs": [ - "+nightly" - ], } ``` From 38002b624aaacbb05f2640d60975e1470dfe5c1a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 17 Aug 2022 21:50:23 -0400 Subject: [PATCH 3650/3747] organize shim tests into shims folder --- tests/fail/{ => shims}/backtrace/bad-backtrace-decl.rs | 0 tests/fail/{ => shims}/backtrace/bad-backtrace-decl.stderr | 0 tests/fail/{ => shims}/backtrace/bad-backtrace-flags.rs | 0 tests/fail/{ => shims}/backtrace/bad-backtrace-flags.stderr | 0 tests/fail/{ => shims}/backtrace/bad-backtrace-ptr.rs | 0 tests/fail/{ => shims}/backtrace/bad-backtrace-ptr.stderr | 0 tests/fail/{ => shims}/backtrace/bad-backtrace-resolve-flags.rs | 0 .../fail/{ => shims}/backtrace/bad-backtrace-resolve-flags.stderr | 0 .../{ => shims}/backtrace/bad-backtrace-resolve-names-flags.rs | 0 .../backtrace/bad-backtrace-resolve-names-flags.stderr | 0 tests/fail/{ => shims}/backtrace/bad-backtrace-size-flags.rs | 0 tests/fail/{ => shims}/backtrace/bad-backtrace-size-flags.stderr | 0 tests/fail/{ => shims}/fs/close_stdout.rs | 0 tests/fail/{ => shims}/fs/close_stdout.stderr | 0 tests/fail/{ => shims}/fs/isolated_file.rs | 0 tests/fail/{ => shims}/fs/isolated_file.stderr | 0 tests/fail/{ => shims}/fs/isolated_stdin.rs | 0 tests/fail/{ => shims}/fs/isolated_stdin.stderr | 0 tests/fail/{ => shims}/fs/mkstemp_immutable_arg.rs | 0 tests/fail/{ => shims}/fs/mkstemp_immutable_arg.stderr | 0 tests/fail/{ => shims}/fs/read_from_stdout.rs | 0 tests/fail/{ => shims}/fs/read_from_stdout.stderr | 0 tests/fail/{ => shims}/fs/unix_open_missing_required_mode.rs | 0 tests/fail/{ => shims}/fs/unix_open_missing_required_mode.stderr | 0 tests/fail/{ => shims}/fs/write_to_stdin.rs | 0 tests/fail/{ => shims}/fs/write_to_stdin.stderr | 0 tests/fail/{ => shims}/shim_arg_size.32bit.stderr | 0 tests/fail/{ => shims}/shim_arg_size.64bit.stderr | 0 tests/fail/{ => shims}/shim_arg_size.rs | 0 tests/fail/{ => shims}/sync/libc_pthread_cond_double_destroy.rs | 0 .../fail/{ => shims}/sync/libc_pthread_cond_double_destroy.stderr | 0 .../fail/{ => shims}/sync/libc_pthread_condattr_double_destroy.rs | 0 .../{ => shims}/sync/libc_pthread_condattr_double_destroy.stderr | 0 tests/fail/{ => shims}/sync/libc_pthread_mutex_NULL_deadlock.rs | 0 .../fail/{ => shims}/sync/libc_pthread_mutex_NULL_deadlock.stderr | 0 tests/fail/{ => shims}/sync/libc_pthread_mutex_deadlock.rs | 0 tests/fail/{ => shims}/sync/libc_pthread_mutex_deadlock.stderr | 0 .../fail/{ => shims}/sync/libc_pthread_mutex_default_deadlock.rs | 0 .../{ => shims}/sync/libc_pthread_mutex_default_deadlock.stderr | 0 tests/fail/{ => shims}/sync/libc_pthread_mutex_destroy_locked.rs | 0 .../{ => shims}/sync/libc_pthread_mutex_destroy_locked.stderr | 0 tests/fail/{ => shims}/sync/libc_pthread_mutex_double_destroy.rs | 0 .../{ => shims}/sync/libc_pthread_mutex_double_destroy.stderr | 0 tests/fail/{ => shims}/sync/libc_pthread_mutex_normal_deadlock.rs | 0 .../{ => shims}/sync/libc_pthread_mutex_normal_deadlock.stderr | 0 .../{ => shims}/sync/libc_pthread_mutex_normal_unlock_unlocked.rs | 0 .../sync/libc_pthread_mutex_normal_unlock_unlocked.stderr | 0 tests/fail/{ => shims}/sync/libc_pthread_mutex_wrong_owner.rs | 0 tests/fail/{ => shims}/sync/libc_pthread_mutex_wrong_owner.stderr | 0 .../{ => shims}/sync/libc_pthread_mutexattr_double_destroy.rs | 0 .../{ => shims}/sync/libc_pthread_mutexattr_double_destroy.stderr | 0 .../{ => shims}/sync/libc_pthread_rwlock_destroy_read_locked.rs | 0 .../sync/libc_pthread_rwlock_destroy_read_locked.stderr | 0 .../{ => shims}/sync/libc_pthread_rwlock_destroy_write_locked.rs | 0 .../sync/libc_pthread_rwlock_destroy_write_locked.stderr | 0 tests/fail/{ => shims}/sync/libc_pthread_rwlock_double_destroy.rs | 0 .../{ => shims}/sync/libc_pthread_rwlock_double_destroy.stderr | 0 .../sync/libc_pthread_rwlock_read_write_deadlock_single_thread.rs | 0 .../libc_pthread_rwlock_read_write_deadlock_single_thread.stderr | 0 .../fail/{ => shims}/sync/libc_pthread_rwlock_read_wrong_owner.rs | 0 .../{ => shims}/sync/libc_pthread_rwlock_read_wrong_owner.stderr | 0 .../fail/{ => shims}/sync/libc_pthread_rwlock_unlock_unlocked.rs | 0 .../{ => shims}/sync/libc_pthread_rwlock_unlock_unlocked.stderr | 0 .../{ => shims}/sync/libc_pthread_rwlock_write_read_deadlock.rs | 0 .../sync/libc_pthread_rwlock_write_read_deadlock.stderr | 0 .../sync/libc_pthread_rwlock_write_read_deadlock_single_thread.rs | 0 .../libc_pthread_rwlock_write_read_deadlock_single_thread.stderr | 0 .../{ => shims}/sync/libc_pthread_rwlock_write_write_deadlock.rs | 0 .../sync/libc_pthread_rwlock_write_write_deadlock.stderr | 0 .../libc_pthread_rwlock_write_write_deadlock_single_thread.rs | 0 .../libc_pthread_rwlock_write_write_deadlock_single_thread.stderr | 0 .../{ => shims}/sync/libc_pthread_rwlock_write_wrong_owner.rs | 0 .../{ => shims}/sync/libc_pthread_rwlock_write_wrong_owner.stderr | 0 tests/pass/{ => shims}/env/args.rs | 0 tests/pass/{ => shims}/env/args.stdout | 0 tests/pass/{ => shims}/env/current_dir.rs | 0 tests/pass/{ => shims}/env/current_dir_with_isolation.rs | 0 tests/pass/{ => shims}/env/current_dir_with_isolation.stderr | 0 tests/pass/{ => shims}/env/current_exe.rs | 0 tests/pass/{ => shims}/env/home.rs | 0 tests/pass/{ => shims}/env/var-exclude.rs | 0 tests/pass/{ => shims}/env/var-forward.rs | 0 tests/pass/{ => shims}/env/var-without-isolation.rs | 0 tests/pass/{ => shims}/env/var.rs | 0 tests/pass/{ => shims}/env/var.stdout | 0 tests/pass/{ => shims}/exit.rs | 0 tests/pass/{ => shims}/fs.rs | 0 tests/pass/{ => shims}/fs.stderr | 0 tests/pass/{ => shims}/fs.stdout | 0 tests/pass/{ => shims}/fs_with_isolation.rs | 0 tests/pass/{ => shims}/fs_with_isolation.stderr | 0 tests/pass/{ => shims}/libc.rs | 0 tests/pass/{ => shims}/linux-getrandom-without-isolation.rs | 0 tests/pass/{ => shims}/linux-getrandom.rs | 0 tests/pass/{ => shims}/posix_memalign.rs | 0 tests/pass/{ => shims}/sleep_long.rs | 0 tests/pass/{ => shims}/time.rs | 0 97 files changed, 0 insertions(+), 0 deletions(-) rename tests/fail/{ => shims}/backtrace/bad-backtrace-decl.rs (100%) rename tests/fail/{ => shims}/backtrace/bad-backtrace-decl.stderr (100%) rename tests/fail/{ => shims}/backtrace/bad-backtrace-flags.rs (100%) rename tests/fail/{ => shims}/backtrace/bad-backtrace-flags.stderr (100%) rename tests/fail/{ => shims}/backtrace/bad-backtrace-ptr.rs (100%) rename tests/fail/{ => shims}/backtrace/bad-backtrace-ptr.stderr (100%) rename tests/fail/{ => shims}/backtrace/bad-backtrace-resolve-flags.rs (100%) rename tests/fail/{ => shims}/backtrace/bad-backtrace-resolve-flags.stderr (100%) rename tests/fail/{ => shims}/backtrace/bad-backtrace-resolve-names-flags.rs (100%) rename tests/fail/{ => shims}/backtrace/bad-backtrace-resolve-names-flags.stderr (100%) rename tests/fail/{ => shims}/backtrace/bad-backtrace-size-flags.rs (100%) rename tests/fail/{ => shims}/backtrace/bad-backtrace-size-flags.stderr (100%) rename tests/fail/{ => shims}/fs/close_stdout.rs (100%) rename tests/fail/{ => shims}/fs/close_stdout.stderr (100%) rename tests/fail/{ => shims}/fs/isolated_file.rs (100%) rename tests/fail/{ => shims}/fs/isolated_file.stderr (100%) rename tests/fail/{ => shims}/fs/isolated_stdin.rs (100%) rename tests/fail/{ => shims}/fs/isolated_stdin.stderr (100%) rename tests/fail/{ => shims}/fs/mkstemp_immutable_arg.rs (100%) rename tests/fail/{ => shims}/fs/mkstemp_immutable_arg.stderr (100%) rename tests/fail/{ => shims}/fs/read_from_stdout.rs (100%) rename tests/fail/{ => shims}/fs/read_from_stdout.stderr (100%) rename tests/fail/{ => shims}/fs/unix_open_missing_required_mode.rs (100%) rename tests/fail/{ => shims}/fs/unix_open_missing_required_mode.stderr (100%) rename tests/fail/{ => shims}/fs/write_to_stdin.rs (100%) rename tests/fail/{ => shims}/fs/write_to_stdin.stderr (100%) rename tests/fail/{ => shims}/shim_arg_size.32bit.stderr (100%) rename tests/fail/{ => shims}/shim_arg_size.64bit.stderr (100%) rename tests/fail/{ => shims}/shim_arg_size.rs (100%) rename tests/fail/{ => shims}/sync/libc_pthread_cond_double_destroy.rs (100%) rename tests/fail/{ => shims}/sync/libc_pthread_cond_double_destroy.stderr (100%) rename tests/fail/{ => shims}/sync/libc_pthread_condattr_double_destroy.rs (100%) rename tests/fail/{ => shims}/sync/libc_pthread_condattr_double_destroy.stderr (100%) rename tests/fail/{ => shims}/sync/libc_pthread_mutex_NULL_deadlock.rs (100%) rename tests/fail/{ => shims}/sync/libc_pthread_mutex_NULL_deadlock.stderr (100%) rename tests/fail/{ => shims}/sync/libc_pthread_mutex_deadlock.rs (100%) rename tests/fail/{ => shims}/sync/libc_pthread_mutex_deadlock.stderr (100%) rename tests/fail/{ => shims}/sync/libc_pthread_mutex_default_deadlock.rs (100%) rename tests/fail/{ => shims}/sync/libc_pthread_mutex_default_deadlock.stderr (100%) rename tests/fail/{ => shims}/sync/libc_pthread_mutex_destroy_locked.rs (100%) rename tests/fail/{ => shims}/sync/libc_pthread_mutex_destroy_locked.stderr (100%) rename tests/fail/{ => shims}/sync/libc_pthread_mutex_double_destroy.rs (100%) rename tests/fail/{ => shims}/sync/libc_pthread_mutex_double_destroy.stderr (100%) rename tests/fail/{ => shims}/sync/libc_pthread_mutex_normal_deadlock.rs (100%) rename tests/fail/{ => shims}/sync/libc_pthread_mutex_normal_deadlock.stderr (100%) rename tests/fail/{ => shims}/sync/libc_pthread_mutex_normal_unlock_unlocked.rs (100%) rename tests/fail/{ => shims}/sync/libc_pthread_mutex_normal_unlock_unlocked.stderr (100%) rename tests/fail/{ => shims}/sync/libc_pthread_mutex_wrong_owner.rs (100%) rename tests/fail/{ => shims}/sync/libc_pthread_mutex_wrong_owner.stderr (100%) rename tests/fail/{ => shims}/sync/libc_pthread_mutexattr_double_destroy.rs (100%) rename tests/fail/{ => shims}/sync/libc_pthread_mutexattr_double_destroy.stderr (100%) rename tests/fail/{ => shims}/sync/libc_pthread_rwlock_destroy_read_locked.rs (100%) rename tests/fail/{ => shims}/sync/libc_pthread_rwlock_destroy_read_locked.stderr (100%) rename tests/fail/{ => shims}/sync/libc_pthread_rwlock_destroy_write_locked.rs (100%) rename tests/fail/{ => shims}/sync/libc_pthread_rwlock_destroy_write_locked.stderr (100%) rename tests/fail/{ => shims}/sync/libc_pthread_rwlock_double_destroy.rs (100%) rename tests/fail/{ => shims}/sync/libc_pthread_rwlock_double_destroy.stderr (100%) rename tests/fail/{ => shims}/sync/libc_pthread_rwlock_read_write_deadlock_single_thread.rs (100%) rename tests/fail/{ => shims}/sync/libc_pthread_rwlock_read_write_deadlock_single_thread.stderr (100%) rename tests/fail/{ => shims}/sync/libc_pthread_rwlock_read_wrong_owner.rs (100%) rename tests/fail/{ => shims}/sync/libc_pthread_rwlock_read_wrong_owner.stderr (100%) rename tests/fail/{ => shims}/sync/libc_pthread_rwlock_unlock_unlocked.rs (100%) rename tests/fail/{ => shims}/sync/libc_pthread_rwlock_unlock_unlocked.stderr (100%) rename tests/fail/{ => shims}/sync/libc_pthread_rwlock_write_read_deadlock.rs (100%) rename tests/fail/{ => shims}/sync/libc_pthread_rwlock_write_read_deadlock.stderr (100%) rename tests/fail/{ => shims}/sync/libc_pthread_rwlock_write_read_deadlock_single_thread.rs (100%) rename tests/fail/{ => shims}/sync/libc_pthread_rwlock_write_read_deadlock_single_thread.stderr (100%) rename tests/fail/{ => shims}/sync/libc_pthread_rwlock_write_write_deadlock.rs (100%) rename tests/fail/{ => shims}/sync/libc_pthread_rwlock_write_write_deadlock.stderr (100%) rename tests/fail/{ => shims}/sync/libc_pthread_rwlock_write_write_deadlock_single_thread.rs (100%) rename tests/fail/{ => shims}/sync/libc_pthread_rwlock_write_write_deadlock_single_thread.stderr (100%) rename tests/fail/{ => shims}/sync/libc_pthread_rwlock_write_wrong_owner.rs (100%) rename tests/fail/{ => shims}/sync/libc_pthread_rwlock_write_wrong_owner.stderr (100%) rename tests/pass/{ => shims}/env/args.rs (100%) rename tests/pass/{ => shims}/env/args.stdout (100%) rename tests/pass/{ => shims}/env/current_dir.rs (100%) rename tests/pass/{ => shims}/env/current_dir_with_isolation.rs (100%) rename tests/pass/{ => shims}/env/current_dir_with_isolation.stderr (100%) rename tests/pass/{ => shims}/env/current_exe.rs (100%) rename tests/pass/{ => shims}/env/home.rs (100%) rename tests/pass/{ => shims}/env/var-exclude.rs (100%) rename tests/pass/{ => shims}/env/var-forward.rs (100%) rename tests/pass/{ => shims}/env/var-without-isolation.rs (100%) rename tests/pass/{ => shims}/env/var.rs (100%) rename tests/pass/{ => shims}/env/var.stdout (100%) rename tests/pass/{ => shims}/exit.rs (100%) rename tests/pass/{ => shims}/fs.rs (100%) rename tests/pass/{ => shims}/fs.stderr (100%) rename tests/pass/{ => shims}/fs.stdout (100%) rename tests/pass/{ => shims}/fs_with_isolation.rs (100%) rename tests/pass/{ => shims}/fs_with_isolation.stderr (100%) rename tests/pass/{ => shims}/libc.rs (100%) rename tests/pass/{ => shims}/linux-getrandom-without-isolation.rs (100%) rename tests/pass/{ => shims}/linux-getrandom.rs (100%) rename tests/pass/{ => shims}/posix_memalign.rs (100%) rename tests/pass/{ => shims}/sleep_long.rs (100%) rename tests/pass/{ => shims}/time.rs (100%) diff --git a/tests/fail/backtrace/bad-backtrace-decl.rs b/tests/fail/shims/backtrace/bad-backtrace-decl.rs similarity index 100% rename from tests/fail/backtrace/bad-backtrace-decl.rs rename to tests/fail/shims/backtrace/bad-backtrace-decl.rs diff --git a/tests/fail/backtrace/bad-backtrace-decl.stderr b/tests/fail/shims/backtrace/bad-backtrace-decl.stderr similarity index 100% rename from tests/fail/backtrace/bad-backtrace-decl.stderr rename to tests/fail/shims/backtrace/bad-backtrace-decl.stderr diff --git a/tests/fail/backtrace/bad-backtrace-flags.rs b/tests/fail/shims/backtrace/bad-backtrace-flags.rs similarity index 100% rename from tests/fail/backtrace/bad-backtrace-flags.rs rename to tests/fail/shims/backtrace/bad-backtrace-flags.rs diff --git a/tests/fail/backtrace/bad-backtrace-flags.stderr b/tests/fail/shims/backtrace/bad-backtrace-flags.stderr similarity index 100% rename from tests/fail/backtrace/bad-backtrace-flags.stderr rename to tests/fail/shims/backtrace/bad-backtrace-flags.stderr diff --git a/tests/fail/backtrace/bad-backtrace-ptr.rs b/tests/fail/shims/backtrace/bad-backtrace-ptr.rs similarity index 100% rename from tests/fail/backtrace/bad-backtrace-ptr.rs rename to tests/fail/shims/backtrace/bad-backtrace-ptr.rs diff --git a/tests/fail/backtrace/bad-backtrace-ptr.stderr b/tests/fail/shims/backtrace/bad-backtrace-ptr.stderr similarity index 100% rename from tests/fail/backtrace/bad-backtrace-ptr.stderr rename to tests/fail/shims/backtrace/bad-backtrace-ptr.stderr diff --git a/tests/fail/backtrace/bad-backtrace-resolve-flags.rs b/tests/fail/shims/backtrace/bad-backtrace-resolve-flags.rs similarity index 100% rename from tests/fail/backtrace/bad-backtrace-resolve-flags.rs rename to tests/fail/shims/backtrace/bad-backtrace-resolve-flags.rs diff --git a/tests/fail/backtrace/bad-backtrace-resolve-flags.stderr b/tests/fail/shims/backtrace/bad-backtrace-resolve-flags.stderr similarity index 100% rename from tests/fail/backtrace/bad-backtrace-resolve-flags.stderr rename to tests/fail/shims/backtrace/bad-backtrace-resolve-flags.stderr diff --git a/tests/fail/backtrace/bad-backtrace-resolve-names-flags.rs b/tests/fail/shims/backtrace/bad-backtrace-resolve-names-flags.rs similarity index 100% rename from tests/fail/backtrace/bad-backtrace-resolve-names-flags.rs rename to tests/fail/shims/backtrace/bad-backtrace-resolve-names-flags.rs diff --git a/tests/fail/backtrace/bad-backtrace-resolve-names-flags.stderr b/tests/fail/shims/backtrace/bad-backtrace-resolve-names-flags.stderr similarity index 100% rename from tests/fail/backtrace/bad-backtrace-resolve-names-flags.stderr rename to tests/fail/shims/backtrace/bad-backtrace-resolve-names-flags.stderr diff --git a/tests/fail/backtrace/bad-backtrace-size-flags.rs b/tests/fail/shims/backtrace/bad-backtrace-size-flags.rs similarity index 100% rename from tests/fail/backtrace/bad-backtrace-size-flags.rs rename to tests/fail/shims/backtrace/bad-backtrace-size-flags.rs diff --git a/tests/fail/backtrace/bad-backtrace-size-flags.stderr b/tests/fail/shims/backtrace/bad-backtrace-size-flags.stderr similarity index 100% rename from tests/fail/backtrace/bad-backtrace-size-flags.stderr rename to tests/fail/shims/backtrace/bad-backtrace-size-flags.stderr diff --git a/tests/fail/fs/close_stdout.rs b/tests/fail/shims/fs/close_stdout.rs similarity index 100% rename from tests/fail/fs/close_stdout.rs rename to tests/fail/shims/fs/close_stdout.rs diff --git a/tests/fail/fs/close_stdout.stderr b/tests/fail/shims/fs/close_stdout.stderr similarity index 100% rename from tests/fail/fs/close_stdout.stderr rename to tests/fail/shims/fs/close_stdout.stderr diff --git a/tests/fail/fs/isolated_file.rs b/tests/fail/shims/fs/isolated_file.rs similarity index 100% rename from tests/fail/fs/isolated_file.rs rename to tests/fail/shims/fs/isolated_file.rs diff --git a/tests/fail/fs/isolated_file.stderr b/tests/fail/shims/fs/isolated_file.stderr similarity index 100% rename from tests/fail/fs/isolated_file.stderr rename to tests/fail/shims/fs/isolated_file.stderr diff --git a/tests/fail/fs/isolated_stdin.rs b/tests/fail/shims/fs/isolated_stdin.rs similarity index 100% rename from tests/fail/fs/isolated_stdin.rs rename to tests/fail/shims/fs/isolated_stdin.rs diff --git a/tests/fail/fs/isolated_stdin.stderr b/tests/fail/shims/fs/isolated_stdin.stderr similarity index 100% rename from tests/fail/fs/isolated_stdin.stderr rename to tests/fail/shims/fs/isolated_stdin.stderr diff --git a/tests/fail/fs/mkstemp_immutable_arg.rs b/tests/fail/shims/fs/mkstemp_immutable_arg.rs similarity index 100% rename from tests/fail/fs/mkstemp_immutable_arg.rs rename to tests/fail/shims/fs/mkstemp_immutable_arg.rs diff --git a/tests/fail/fs/mkstemp_immutable_arg.stderr b/tests/fail/shims/fs/mkstemp_immutable_arg.stderr similarity index 100% rename from tests/fail/fs/mkstemp_immutable_arg.stderr rename to tests/fail/shims/fs/mkstemp_immutable_arg.stderr diff --git a/tests/fail/fs/read_from_stdout.rs b/tests/fail/shims/fs/read_from_stdout.rs similarity index 100% rename from tests/fail/fs/read_from_stdout.rs rename to tests/fail/shims/fs/read_from_stdout.rs diff --git a/tests/fail/fs/read_from_stdout.stderr b/tests/fail/shims/fs/read_from_stdout.stderr similarity index 100% rename from tests/fail/fs/read_from_stdout.stderr rename to tests/fail/shims/fs/read_from_stdout.stderr diff --git a/tests/fail/fs/unix_open_missing_required_mode.rs b/tests/fail/shims/fs/unix_open_missing_required_mode.rs similarity index 100% rename from tests/fail/fs/unix_open_missing_required_mode.rs rename to tests/fail/shims/fs/unix_open_missing_required_mode.rs diff --git a/tests/fail/fs/unix_open_missing_required_mode.stderr b/tests/fail/shims/fs/unix_open_missing_required_mode.stderr similarity index 100% rename from tests/fail/fs/unix_open_missing_required_mode.stderr rename to tests/fail/shims/fs/unix_open_missing_required_mode.stderr diff --git a/tests/fail/fs/write_to_stdin.rs b/tests/fail/shims/fs/write_to_stdin.rs similarity index 100% rename from tests/fail/fs/write_to_stdin.rs rename to tests/fail/shims/fs/write_to_stdin.rs diff --git a/tests/fail/fs/write_to_stdin.stderr b/tests/fail/shims/fs/write_to_stdin.stderr similarity index 100% rename from tests/fail/fs/write_to_stdin.stderr rename to tests/fail/shims/fs/write_to_stdin.stderr diff --git a/tests/fail/shim_arg_size.32bit.stderr b/tests/fail/shims/shim_arg_size.32bit.stderr similarity index 100% rename from tests/fail/shim_arg_size.32bit.stderr rename to tests/fail/shims/shim_arg_size.32bit.stderr diff --git a/tests/fail/shim_arg_size.64bit.stderr b/tests/fail/shims/shim_arg_size.64bit.stderr similarity index 100% rename from tests/fail/shim_arg_size.64bit.stderr rename to tests/fail/shims/shim_arg_size.64bit.stderr diff --git a/tests/fail/shim_arg_size.rs b/tests/fail/shims/shim_arg_size.rs similarity index 100% rename from tests/fail/shim_arg_size.rs rename to tests/fail/shims/shim_arg_size.rs diff --git a/tests/fail/sync/libc_pthread_cond_double_destroy.rs b/tests/fail/shims/sync/libc_pthread_cond_double_destroy.rs similarity index 100% rename from tests/fail/sync/libc_pthread_cond_double_destroy.rs rename to tests/fail/shims/sync/libc_pthread_cond_double_destroy.rs diff --git a/tests/fail/sync/libc_pthread_cond_double_destroy.stderr b/tests/fail/shims/sync/libc_pthread_cond_double_destroy.stderr similarity index 100% rename from tests/fail/sync/libc_pthread_cond_double_destroy.stderr rename to tests/fail/shims/sync/libc_pthread_cond_double_destroy.stderr diff --git a/tests/fail/sync/libc_pthread_condattr_double_destroy.rs b/tests/fail/shims/sync/libc_pthread_condattr_double_destroy.rs similarity index 100% rename from tests/fail/sync/libc_pthread_condattr_double_destroy.rs rename to tests/fail/shims/sync/libc_pthread_condattr_double_destroy.rs diff --git a/tests/fail/sync/libc_pthread_condattr_double_destroy.stderr b/tests/fail/shims/sync/libc_pthread_condattr_double_destroy.stderr similarity index 100% rename from tests/fail/sync/libc_pthread_condattr_double_destroy.stderr rename to tests/fail/shims/sync/libc_pthread_condattr_double_destroy.stderr diff --git a/tests/fail/sync/libc_pthread_mutex_NULL_deadlock.rs b/tests/fail/shims/sync/libc_pthread_mutex_NULL_deadlock.rs similarity index 100% rename from tests/fail/sync/libc_pthread_mutex_NULL_deadlock.rs rename to tests/fail/shims/sync/libc_pthread_mutex_NULL_deadlock.rs diff --git a/tests/fail/sync/libc_pthread_mutex_NULL_deadlock.stderr b/tests/fail/shims/sync/libc_pthread_mutex_NULL_deadlock.stderr similarity index 100% rename from tests/fail/sync/libc_pthread_mutex_NULL_deadlock.stderr rename to tests/fail/shims/sync/libc_pthread_mutex_NULL_deadlock.stderr diff --git a/tests/fail/sync/libc_pthread_mutex_deadlock.rs b/tests/fail/shims/sync/libc_pthread_mutex_deadlock.rs similarity index 100% rename from tests/fail/sync/libc_pthread_mutex_deadlock.rs rename to tests/fail/shims/sync/libc_pthread_mutex_deadlock.rs diff --git a/tests/fail/sync/libc_pthread_mutex_deadlock.stderr b/tests/fail/shims/sync/libc_pthread_mutex_deadlock.stderr similarity index 100% rename from tests/fail/sync/libc_pthread_mutex_deadlock.stderr rename to tests/fail/shims/sync/libc_pthread_mutex_deadlock.stderr diff --git a/tests/fail/sync/libc_pthread_mutex_default_deadlock.rs b/tests/fail/shims/sync/libc_pthread_mutex_default_deadlock.rs similarity index 100% rename from tests/fail/sync/libc_pthread_mutex_default_deadlock.rs rename to tests/fail/shims/sync/libc_pthread_mutex_default_deadlock.rs diff --git a/tests/fail/sync/libc_pthread_mutex_default_deadlock.stderr b/tests/fail/shims/sync/libc_pthread_mutex_default_deadlock.stderr similarity index 100% rename from tests/fail/sync/libc_pthread_mutex_default_deadlock.stderr rename to tests/fail/shims/sync/libc_pthread_mutex_default_deadlock.stderr diff --git a/tests/fail/sync/libc_pthread_mutex_destroy_locked.rs b/tests/fail/shims/sync/libc_pthread_mutex_destroy_locked.rs similarity index 100% rename from tests/fail/sync/libc_pthread_mutex_destroy_locked.rs rename to tests/fail/shims/sync/libc_pthread_mutex_destroy_locked.rs diff --git a/tests/fail/sync/libc_pthread_mutex_destroy_locked.stderr b/tests/fail/shims/sync/libc_pthread_mutex_destroy_locked.stderr similarity index 100% rename from tests/fail/sync/libc_pthread_mutex_destroy_locked.stderr rename to tests/fail/shims/sync/libc_pthread_mutex_destroy_locked.stderr diff --git a/tests/fail/sync/libc_pthread_mutex_double_destroy.rs b/tests/fail/shims/sync/libc_pthread_mutex_double_destroy.rs similarity index 100% rename from tests/fail/sync/libc_pthread_mutex_double_destroy.rs rename to tests/fail/shims/sync/libc_pthread_mutex_double_destroy.rs diff --git a/tests/fail/sync/libc_pthread_mutex_double_destroy.stderr b/tests/fail/shims/sync/libc_pthread_mutex_double_destroy.stderr similarity index 100% rename from tests/fail/sync/libc_pthread_mutex_double_destroy.stderr rename to tests/fail/shims/sync/libc_pthread_mutex_double_destroy.stderr diff --git a/tests/fail/sync/libc_pthread_mutex_normal_deadlock.rs b/tests/fail/shims/sync/libc_pthread_mutex_normal_deadlock.rs similarity index 100% rename from tests/fail/sync/libc_pthread_mutex_normal_deadlock.rs rename to tests/fail/shims/sync/libc_pthread_mutex_normal_deadlock.rs diff --git a/tests/fail/sync/libc_pthread_mutex_normal_deadlock.stderr b/tests/fail/shims/sync/libc_pthread_mutex_normal_deadlock.stderr similarity index 100% rename from tests/fail/sync/libc_pthread_mutex_normal_deadlock.stderr rename to tests/fail/shims/sync/libc_pthread_mutex_normal_deadlock.stderr diff --git a/tests/fail/sync/libc_pthread_mutex_normal_unlock_unlocked.rs b/tests/fail/shims/sync/libc_pthread_mutex_normal_unlock_unlocked.rs similarity index 100% rename from tests/fail/sync/libc_pthread_mutex_normal_unlock_unlocked.rs rename to tests/fail/shims/sync/libc_pthread_mutex_normal_unlock_unlocked.rs diff --git a/tests/fail/sync/libc_pthread_mutex_normal_unlock_unlocked.stderr b/tests/fail/shims/sync/libc_pthread_mutex_normal_unlock_unlocked.stderr similarity index 100% rename from tests/fail/sync/libc_pthread_mutex_normal_unlock_unlocked.stderr rename to tests/fail/shims/sync/libc_pthread_mutex_normal_unlock_unlocked.stderr diff --git a/tests/fail/sync/libc_pthread_mutex_wrong_owner.rs b/tests/fail/shims/sync/libc_pthread_mutex_wrong_owner.rs similarity index 100% rename from tests/fail/sync/libc_pthread_mutex_wrong_owner.rs rename to tests/fail/shims/sync/libc_pthread_mutex_wrong_owner.rs diff --git a/tests/fail/sync/libc_pthread_mutex_wrong_owner.stderr b/tests/fail/shims/sync/libc_pthread_mutex_wrong_owner.stderr similarity index 100% rename from tests/fail/sync/libc_pthread_mutex_wrong_owner.stderr rename to tests/fail/shims/sync/libc_pthread_mutex_wrong_owner.stderr diff --git a/tests/fail/sync/libc_pthread_mutexattr_double_destroy.rs b/tests/fail/shims/sync/libc_pthread_mutexattr_double_destroy.rs similarity index 100% rename from tests/fail/sync/libc_pthread_mutexattr_double_destroy.rs rename to tests/fail/shims/sync/libc_pthread_mutexattr_double_destroy.rs diff --git a/tests/fail/sync/libc_pthread_mutexattr_double_destroy.stderr b/tests/fail/shims/sync/libc_pthread_mutexattr_double_destroy.stderr similarity index 100% rename from tests/fail/sync/libc_pthread_mutexattr_double_destroy.stderr rename to tests/fail/shims/sync/libc_pthread_mutexattr_double_destroy.stderr diff --git a/tests/fail/sync/libc_pthread_rwlock_destroy_read_locked.rs b/tests/fail/shims/sync/libc_pthread_rwlock_destroy_read_locked.rs similarity index 100% rename from tests/fail/sync/libc_pthread_rwlock_destroy_read_locked.rs rename to tests/fail/shims/sync/libc_pthread_rwlock_destroy_read_locked.rs diff --git a/tests/fail/sync/libc_pthread_rwlock_destroy_read_locked.stderr b/tests/fail/shims/sync/libc_pthread_rwlock_destroy_read_locked.stderr similarity index 100% rename from tests/fail/sync/libc_pthread_rwlock_destroy_read_locked.stderr rename to tests/fail/shims/sync/libc_pthread_rwlock_destroy_read_locked.stderr diff --git a/tests/fail/sync/libc_pthread_rwlock_destroy_write_locked.rs b/tests/fail/shims/sync/libc_pthread_rwlock_destroy_write_locked.rs similarity index 100% rename from tests/fail/sync/libc_pthread_rwlock_destroy_write_locked.rs rename to tests/fail/shims/sync/libc_pthread_rwlock_destroy_write_locked.rs diff --git a/tests/fail/sync/libc_pthread_rwlock_destroy_write_locked.stderr b/tests/fail/shims/sync/libc_pthread_rwlock_destroy_write_locked.stderr similarity index 100% rename from tests/fail/sync/libc_pthread_rwlock_destroy_write_locked.stderr rename to tests/fail/shims/sync/libc_pthread_rwlock_destroy_write_locked.stderr diff --git a/tests/fail/sync/libc_pthread_rwlock_double_destroy.rs b/tests/fail/shims/sync/libc_pthread_rwlock_double_destroy.rs similarity index 100% rename from tests/fail/sync/libc_pthread_rwlock_double_destroy.rs rename to tests/fail/shims/sync/libc_pthread_rwlock_double_destroy.rs diff --git a/tests/fail/sync/libc_pthread_rwlock_double_destroy.stderr b/tests/fail/shims/sync/libc_pthread_rwlock_double_destroy.stderr similarity index 100% rename from tests/fail/sync/libc_pthread_rwlock_double_destroy.stderr rename to tests/fail/shims/sync/libc_pthread_rwlock_double_destroy.stderr diff --git a/tests/fail/sync/libc_pthread_rwlock_read_write_deadlock_single_thread.rs b/tests/fail/shims/sync/libc_pthread_rwlock_read_write_deadlock_single_thread.rs similarity index 100% rename from tests/fail/sync/libc_pthread_rwlock_read_write_deadlock_single_thread.rs rename to tests/fail/shims/sync/libc_pthread_rwlock_read_write_deadlock_single_thread.rs diff --git a/tests/fail/sync/libc_pthread_rwlock_read_write_deadlock_single_thread.stderr b/tests/fail/shims/sync/libc_pthread_rwlock_read_write_deadlock_single_thread.stderr similarity index 100% rename from tests/fail/sync/libc_pthread_rwlock_read_write_deadlock_single_thread.stderr rename to tests/fail/shims/sync/libc_pthread_rwlock_read_write_deadlock_single_thread.stderr diff --git a/tests/fail/sync/libc_pthread_rwlock_read_wrong_owner.rs b/tests/fail/shims/sync/libc_pthread_rwlock_read_wrong_owner.rs similarity index 100% rename from tests/fail/sync/libc_pthread_rwlock_read_wrong_owner.rs rename to tests/fail/shims/sync/libc_pthread_rwlock_read_wrong_owner.rs diff --git a/tests/fail/sync/libc_pthread_rwlock_read_wrong_owner.stderr b/tests/fail/shims/sync/libc_pthread_rwlock_read_wrong_owner.stderr similarity index 100% rename from tests/fail/sync/libc_pthread_rwlock_read_wrong_owner.stderr rename to tests/fail/shims/sync/libc_pthread_rwlock_read_wrong_owner.stderr diff --git a/tests/fail/sync/libc_pthread_rwlock_unlock_unlocked.rs b/tests/fail/shims/sync/libc_pthread_rwlock_unlock_unlocked.rs similarity index 100% rename from tests/fail/sync/libc_pthread_rwlock_unlock_unlocked.rs rename to tests/fail/shims/sync/libc_pthread_rwlock_unlock_unlocked.rs diff --git a/tests/fail/sync/libc_pthread_rwlock_unlock_unlocked.stderr b/tests/fail/shims/sync/libc_pthread_rwlock_unlock_unlocked.stderr similarity index 100% rename from tests/fail/sync/libc_pthread_rwlock_unlock_unlocked.stderr rename to tests/fail/shims/sync/libc_pthread_rwlock_unlock_unlocked.stderr diff --git a/tests/fail/sync/libc_pthread_rwlock_write_read_deadlock.rs b/tests/fail/shims/sync/libc_pthread_rwlock_write_read_deadlock.rs similarity index 100% rename from tests/fail/sync/libc_pthread_rwlock_write_read_deadlock.rs rename to tests/fail/shims/sync/libc_pthread_rwlock_write_read_deadlock.rs diff --git a/tests/fail/sync/libc_pthread_rwlock_write_read_deadlock.stderr b/tests/fail/shims/sync/libc_pthread_rwlock_write_read_deadlock.stderr similarity index 100% rename from tests/fail/sync/libc_pthread_rwlock_write_read_deadlock.stderr rename to tests/fail/shims/sync/libc_pthread_rwlock_write_read_deadlock.stderr diff --git a/tests/fail/sync/libc_pthread_rwlock_write_read_deadlock_single_thread.rs b/tests/fail/shims/sync/libc_pthread_rwlock_write_read_deadlock_single_thread.rs similarity index 100% rename from tests/fail/sync/libc_pthread_rwlock_write_read_deadlock_single_thread.rs rename to tests/fail/shims/sync/libc_pthread_rwlock_write_read_deadlock_single_thread.rs diff --git a/tests/fail/sync/libc_pthread_rwlock_write_read_deadlock_single_thread.stderr b/tests/fail/shims/sync/libc_pthread_rwlock_write_read_deadlock_single_thread.stderr similarity index 100% rename from tests/fail/sync/libc_pthread_rwlock_write_read_deadlock_single_thread.stderr rename to tests/fail/shims/sync/libc_pthread_rwlock_write_read_deadlock_single_thread.stderr diff --git a/tests/fail/sync/libc_pthread_rwlock_write_write_deadlock.rs b/tests/fail/shims/sync/libc_pthread_rwlock_write_write_deadlock.rs similarity index 100% rename from tests/fail/sync/libc_pthread_rwlock_write_write_deadlock.rs rename to tests/fail/shims/sync/libc_pthread_rwlock_write_write_deadlock.rs diff --git a/tests/fail/sync/libc_pthread_rwlock_write_write_deadlock.stderr b/tests/fail/shims/sync/libc_pthread_rwlock_write_write_deadlock.stderr similarity index 100% rename from tests/fail/sync/libc_pthread_rwlock_write_write_deadlock.stderr rename to tests/fail/shims/sync/libc_pthread_rwlock_write_write_deadlock.stderr diff --git a/tests/fail/sync/libc_pthread_rwlock_write_write_deadlock_single_thread.rs b/tests/fail/shims/sync/libc_pthread_rwlock_write_write_deadlock_single_thread.rs similarity index 100% rename from tests/fail/sync/libc_pthread_rwlock_write_write_deadlock_single_thread.rs rename to tests/fail/shims/sync/libc_pthread_rwlock_write_write_deadlock_single_thread.rs diff --git a/tests/fail/sync/libc_pthread_rwlock_write_write_deadlock_single_thread.stderr b/tests/fail/shims/sync/libc_pthread_rwlock_write_write_deadlock_single_thread.stderr similarity index 100% rename from tests/fail/sync/libc_pthread_rwlock_write_write_deadlock_single_thread.stderr rename to tests/fail/shims/sync/libc_pthread_rwlock_write_write_deadlock_single_thread.stderr diff --git a/tests/fail/sync/libc_pthread_rwlock_write_wrong_owner.rs b/tests/fail/shims/sync/libc_pthread_rwlock_write_wrong_owner.rs similarity index 100% rename from tests/fail/sync/libc_pthread_rwlock_write_wrong_owner.rs rename to tests/fail/shims/sync/libc_pthread_rwlock_write_wrong_owner.rs diff --git a/tests/fail/sync/libc_pthread_rwlock_write_wrong_owner.stderr b/tests/fail/shims/sync/libc_pthread_rwlock_write_wrong_owner.stderr similarity index 100% rename from tests/fail/sync/libc_pthread_rwlock_write_wrong_owner.stderr rename to tests/fail/shims/sync/libc_pthread_rwlock_write_wrong_owner.stderr diff --git a/tests/pass/env/args.rs b/tests/pass/shims/env/args.rs similarity index 100% rename from tests/pass/env/args.rs rename to tests/pass/shims/env/args.rs diff --git a/tests/pass/env/args.stdout b/tests/pass/shims/env/args.stdout similarity index 100% rename from tests/pass/env/args.stdout rename to tests/pass/shims/env/args.stdout diff --git a/tests/pass/env/current_dir.rs b/tests/pass/shims/env/current_dir.rs similarity index 100% rename from tests/pass/env/current_dir.rs rename to tests/pass/shims/env/current_dir.rs diff --git a/tests/pass/env/current_dir_with_isolation.rs b/tests/pass/shims/env/current_dir_with_isolation.rs similarity index 100% rename from tests/pass/env/current_dir_with_isolation.rs rename to tests/pass/shims/env/current_dir_with_isolation.rs diff --git a/tests/pass/env/current_dir_with_isolation.stderr b/tests/pass/shims/env/current_dir_with_isolation.stderr similarity index 100% rename from tests/pass/env/current_dir_with_isolation.stderr rename to tests/pass/shims/env/current_dir_with_isolation.stderr diff --git a/tests/pass/env/current_exe.rs b/tests/pass/shims/env/current_exe.rs similarity index 100% rename from tests/pass/env/current_exe.rs rename to tests/pass/shims/env/current_exe.rs diff --git a/tests/pass/env/home.rs b/tests/pass/shims/env/home.rs similarity index 100% rename from tests/pass/env/home.rs rename to tests/pass/shims/env/home.rs diff --git a/tests/pass/env/var-exclude.rs b/tests/pass/shims/env/var-exclude.rs similarity index 100% rename from tests/pass/env/var-exclude.rs rename to tests/pass/shims/env/var-exclude.rs diff --git a/tests/pass/env/var-forward.rs b/tests/pass/shims/env/var-forward.rs similarity index 100% rename from tests/pass/env/var-forward.rs rename to tests/pass/shims/env/var-forward.rs diff --git a/tests/pass/env/var-without-isolation.rs b/tests/pass/shims/env/var-without-isolation.rs similarity index 100% rename from tests/pass/env/var-without-isolation.rs rename to tests/pass/shims/env/var-without-isolation.rs diff --git a/tests/pass/env/var.rs b/tests/pass/shims/env/var.rs similarity index 100% rename from tests/pass/env/var.rs rename to tests/pass/shims/env/var.rs diff --git a/tests/pass/env/var.stdout b/tests/pass/shims/env/var.stdout similarity index 100% rename from tests/pass/env/var.stdout rename to tests/pass/shims/env/var.stdout diff --git a/tests/pass/exit.rs b/tests/pass/shims/exit.rs similarity index 100% rename from tests/pass/exit.rs rename to tests/pass/shims/exit.rs diff --git a/tests/pass/fs.rs b/tests/pass/shims/fs.rs similarity index 100% rename from tests/pass/fs.rs rename to tests/pass/shims/fs.rs diff --git a/tests/pass/fs.stderr b/tests/pass/shims/fs.stderr similarity index 100% rename from tests/pass/fs.stderr rename to tests/pass/shims/fs.stderr diff --git a/tests/pass/fs.stdout b/tests/pass/shims/fs.stdout similarity index 100% rename from tests/pass/fs.stdout rename to tests/pass/shims/fs.stdout diff --git a/tests/pass/fs_with_isolation.rs b/tests/pass/shims/fs_with_isolation.rs similarity index 100% rename from tests/pass/fs_with_isolation.rs rename to tests/pass/shims/fs_with_isolation.rs diff --git a/tests/pass/fs_with_isolation.stderr b/tests/pass/shims/fs_with_isolation.stderr similarity index 100% rename from tests/pass/fs_with_isolation.stderr rename to tests/pass/shims/fs_with_isolation.stderr diff --git a/tests/pass/libc.rs b/tests/pass/shims/libc.rs similarity index 100% rename from tests/pass/libc.rs rename to tests/pass/shims/libc.rs diff --git a/tests/pass/linux-getrandom-without-isolation.rs b/tests/pass/shims/linux-getrandom-without-isolation.rs similarity index 100% rename from tests/pass/linux-getrandom-without-isolation.rs rename to tests/pass/shims/linux-getrandom-without-isolation.rs diff --git a/tests/pass/linux-getrandom.rs b/tests/pass/shims/linux-getrandom.rs similarity index 100% rename from tests/pass/linux-getrandom.rs rename to tests/pass/shims/linux-getrandom.rs diff --git a/tests/pass/posix_memalign.rs b/tests/pass/shims/posix_memalign.rs similarity index 100% rename from tests/pass/posix_memalign.rs rename to tests/pass/shims/posix_memalign.rs diff --git a/tests/pass/sleep_long.rs b/tests/pass/shims/sleep_long.rs similarity index 100% rename from tests/pass/sleep_long.rs rename to tests/pass/shims/sleep_long.rs diff --git a/tests/pass/time.rs b/tests/pass/shims/time.rs similarity index 100% rename from tests/pass/time.rs rename to tests/pass/shims/time.rs From 7c856f88639685faff194ea7d12748ae0936436c Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 17 Aug 2022 21:54:28 -0400 Subject: [PATCH 3651/3747] move libc pthread tests into separate file --- tests/pass/shims/{libc.rs => libc-misc.rs} | 125 -------------------- tests/pass/shims/pthreads.rs | 127 +++++++++++++++++++++ 2 files changed, 127 insertions(+), 125 deletions(-) rename tests/pass/shims/{libc.rs => libc-misc.rs} (61%) create mode 100644 tests/pass/shims/pthreads.rs diff --git a/tests/pass/shims/libc.rs b/tests/pass/shims/libc-misc.rs similarity index 61% rename from tests/pass/shims/libc.rs rename to tests/pass/shims/libc-misc.rs index f3aaccd57411b..a883a3d967a3c 100644 --- a/tests/pass/shims/libc.rs +++ b/tests/pass/shims/libc-misc.rs @@ -1,7 +1,6 @@ //@ignore-target-windows: No libc on Windows //@compile-flags: -Zmiri-disable-isolation #![feature(io_error_more)] -#![feature(rustc_private)] use std::fs::{remove_file, File}; use std::os::unix::io::AsRawFd; @@ -161,122 +160,6 @@ fn test_sync_file_range() { assert_eq!(result_2, 0); } -fn test_mutex_libc_init_recursive() { - unsafe { - let mut attr: libc::pthread_mutexattr_t = std::mem::zeroed(); - assert_eq!(libc::pthread_mutexattr_init(&mut attr as *mut _), 0); - assert_eq!( - libc::pthread_mutexattr_settype(&mut attr as *mut _, libc::PTHREAD_MUTEX_RECURSIVE), - 0, - ); - let mut mutex: libc::pthread_mutex_t = std::mem::zeroed(); - assert_eq!(libc::pthread_mutex_init(&mut mutex as *mut _, &mut attr as *mut _), 0); - assert_eq!(libc::pthread_mutex_lock(&mut mutex as *mut _), 0); - assert_eq!(libc::pthread_mutex_trylock(&mut mutex as *mut _), 0); - assert_eq!(libc::pthread_mutex_unlock(&mut mutex as *mut _), 0); - assert_eq!(libc::pthread_mutex_unlock(&mut mutex as *mut _), 0); - assert_eq!(libc::pthread_mutex_trylock(&mut mutex as *mut _), 0); - assert_eq!(libc::pthread_mutex_lock(&mut mutex as *mut _), 0); - assert_eq!(libc::pthread_mutex_unlock(&mut mutex as *mut _), 0); - assert_eq!(libc::pthread_mutex_unlock(&mut mutex as *mut _), 0); - assert_eq!(libc::pthread_mutex_unlock(&mut mutex as *mut _), libc::EPERM); - assert_eq!(libc::pthread_mutex_destroy(&mut mutex as *mut _), 0); - assert_eq!(libc::pthread_mutexattr_destroy(&mut attr as *mut _), 0); - } -} - -fn test_mutex_libc_init_normal() { - unsafe { - let mut mutexattr: libc::pthread_mutexattr_t = std::mem::zeroed(); - assert_eq!( - libc::pthread_mutexattr_settype(&mut mutexattr as *mut _, 0x12345678), - libc::EINVAL, - ); - assert_eq!( - libc::pthread_mutexattr_settype(&mut mutexattr as *mut _, libc::PTHREAD_MUTEX_NORMAL), - 0, - ); - let mut mutex: libc::pthread_mutex_t = std::mem::zeroed(); - assert_eq!(libc::pthread_mutex_init(&mut mutex as *mut _, &mutexattr as *const _), 0); - assert_eq!(libc::pthread_mutex_lock(&mut mutex as *mut _), 0); - assert_eq!(libc::pthread_mutex_trylock(&mut mutex as *mut _), libc::EBUSY); - assert_eq!(libc::pthread_mutex_unlock(&mut mutex as *mut _), 0); - assert_eq!(libc::pthread_mutex_trylock(&mut mutex as *mut _), 0); - assert_eq!(libc::pthread_mutex_unlock(&mut mutex as *mut _), 0); - assert_eq!(libc::pthread_mutex_destroy(&mut mutex as *mut _), 0); - } -} - -fn test_mutex_libc_init_errorcheck() { - unsafe { - let mut mutexattr: libc::pthread_mutexattr_t = std::mem::zeroed(); - assert_eq!( - libc::pthread_mutexattr_settype( - &mut mutexattr as *mut _, - libc::PTHREAD_MUTEX_ERRORCHECK, - ), - 0, - ); - let mut mutex: libc::pthread_mutex_t = std::mem::zeroed(); - assert_eq!(libc::pthread_mutex_init(&mut mutex as *mut _, &mutexattr as *const _), 0); - assert_eq!(libc::pthread_mutex_lock(&mut mutex as *mut _), 0); - assert_eq!(libc::pthread_mutex_trylock(&mut mutex as *mut _), libc::EBUSY); - assert_eq!(libc::pthread_mutex_lock(&mut mutex as *mut _), libc::EDEADLK); - assert_eq!(libc::pthread_mutex_unlock(&mut mutex as *mut _), 0); - assert_eq!(libc::pthread_mutex_trylock(&mut mutex as *mut _), 0); - assert_eq!(libc::pthread_mutex_unlock(&mut mutex as *mut _), 0); - assert_eq!(libc::pthread_mutex_unlock(&mut mutex as *mut _), libc::EPERM); - assert_eq!(libc::pthread_mutex_destroy(&mut mutex as *mut _), 0); - } -} - -// Only linux provides PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP, -// libc for macOS just has the default PTHREAD_MUTEX_INITIALIZER. -#[cfg(target_os = "linux")] -fn test_mutex_libc_static_initializer_recursive() { - let mutex = std::cell::UnsafeCell::new(libc::PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP); - unsafe { - assert_eq!(libc::pthread_mutex_lock(mutex.get()), 0); - assert_eq!(libc::pthread_mutex_trylock(mutex.get()), 0); - assert_eq!(libc::pthread_mutex_unlock(mutex.get()), 0); - assert_eq!(libc::pthread_mutex_unlock(mutex.get()), 0); - assert_eq!(libc::pthread_mutex_trylock(mutex.get()), 0); - assert_eq!(libc::pthread_mutex_lock(mutex.get()), 0); - assert_eq!(libc::pthread_mutex_unlock(mutex.get()), 0); - assert_eq!(libc::pthread_mutex_unlock(mutex.get()), 0); - assert_eq!(libc::pthread_mutex_unlock(mutex.get()), libc::EPERM); - assert_eq!(libc::pthread_mutex_destroy(mutex.get()), 0); - } -} - -// Testing the behavior of std::sync::RwLock does not fully exercise the pthread rwlock shims, we -// need to go a layer deeper and test the behavior of the libc functions, because -// std::sys::unix::rwlock::RWLock itself keeps track of write_locked and num_readers. -fn test_rwlock_libc_static_initializer() { - let rw = std::cell::UnsafeCell::new(libc::PTHREAD_RWLOCK_INITIALIZER); - unsafe { - assert_eq!(libc::pthread_rwlock_rdlock(rw.get()), 0); - assert_eq!(libc::pthread_rwlock_rdlock(rw.get()), 0); - assert_eq!(libc::pthread_rwlock_unlock(rw.get()), 0); - assert_eq!(libc::pthread_rwlock_tryrdlock(rw.get()), 0); - assert_eq!(libc::pthread_rwlock_unlock(rw.get()), 0); - assert_eq!(libc::pthread_rwlock_trywrlock(rw.get()), libc::EBUSY); - assert_eq!(libc::pthread_rwlock_unlock(rw.get()), 0); - - assert_eq!(libc::pthread_rwlock_wrlock(rw.get()), 0); - assert_eq!(libc::pthread_rwlock_tryrdlock(rw.get()), libc::EBUSY); - assert_eq!(libc::pthread_rwlock_trywrlock(rw.get()), libc::EBUSY); - assert_eq!(libc::pthread_rwlock_unlock(rw.get()), 0); - - assert_eq!(libc::pthread_rwlock_trywrlock(rw.get()), 0); - assert_eq!(libc::pthread_rwlock_tryrdlock(rw.get()), libc::EBUSY); - assert_eq!(libc::pthread_rwlock_trywrlock(rw.get()), libc::EBUSY); - assert_eq!(libc::pthread_rwlock_unlock(rw.get()), 0); - - assert_eq!(libc::pthread_rwlock_destroy(rw.get()), 0); - } -} - /// Tests whether each thread has its own `__errno_location`. fn test_thread_local_errno() { #[cfg(target_os = "linux")] @@ -413,14 +296,6 @@ fn main() { #[cfg(any(target_os = "linux"))] test_sync_file_range(); - test_mutex_libc_init_recursive(); - test_mutex_libc_init_normal(); - test_mutex_libc_init_errorcheck(); - test_rwlock_libc_static_initializer(); - - #[cfg(any(target_os = "linux"))] - test_mutex_libc_static_initializer_recursive(); - test_thread_local_errno(); #[cfg(any(target_os = "linux"))] diff --git a/tests/pass/shims/pthreads.rs b/tests/pass/shims/pthreads.rs new file mode 100644 index 0000000000000..d062eda7e90c8 --- /dev/null +++ b/tests/pass/shims/pthreads.rs @@ -0,0 +1,127 @@ +//@ignore-target-windows: No libc on Windows + +fn main() { + test_mutex_libc_init_recursive(); + test_mutex_libc_init_normal(); + test_mutex_libc_init_errorcheck(); + test_rwlock_libc_static_initializer(); + + #[cfg(any(target_os = "linux"))] + test_mutex_libc_static_initializer_recursive(); +} + +fn test_mutex_libc_init_recursive() { + unsafe { + let mut attr: libc::pthread_mutexattr_t = std::mem::zeroed(); + assert_eq!(libc::pthread_mutexattr_init(&mut attr as *mut _), 0); + assert_eq!( + libc::pthread_mutexattr_settype(&mut attr as *mut _, libc::PTHREAD_MUTEX_RECURSIVE), + 0, + ); + let mut mutex: libc::pthread_mutex_t = std::mem::zeroed(); + assert_eq!(libc::pthread_mutex_init(&mut mutex as *mut _, &mut attr as *mut _), 0); + assert_eq!(libc::pthread_mutex_lock(&mut mutex as *mut _), 0); + assert_eq!(libc::pthread_mutex_trylock(&mut mutex as *mut _), 0); + assert_eq!(libc::pthread_mutex_unlock(&mut mutex as *mut _), 0); + assert_eq!(libc::pthread_mutex_unlock(&mut mutex as *mut _), 0); + assert_eq!(libc::pthread_mutex_trylock(&mut mutex as *mut _), 0); + assert_eq!(libc::pthread_mutex_lock(&mut mutex as *mut _), 0); + assert_eq!(libc::pthread_mutex_unlock(&mut mutex as *mut _), 0); + assert_eq!(libc::pthread_mutex_unlock(&mut mutex as *mut _), 0); + assert_eq!(libc::pthread_mutex_unlock(&mut mutex as *mut _), libc::EPERM); + assert_eq!(libc::pthread_mutex_destroy(&mut mutex as *mut _), 0); + assert_eq!(libc::pthread_mutexattr_destroy(&mut attr as *mut _), 0); + } +} + +fn test_mutex_libc_init_normal() { + unsafe { + let mut mutexattr: libc::pthread_mutexattr_t = std::mem::zeroed(); + assert_eq!( + libc::pthread_mutexattr_settype(&mut mutexattr as *mut _, 0x12345678), + libc::EINVAL, + ); + assert_eq!( + libc::pthread_mutexattr_settype(&mut mutexattr as *mut _, libc::PTHREAD_MUTEX_NORMAL), + 0, + ); + let mut mutex: libc::pthread_mutex_t = std::mem::zeroed(); + assert_eq!(libc::pthread_mutex_init(&mut mutex as *mut _, &mutexattr as *const _), 0); + assert_eq!(libc::pthread_mutex_lock(&mut mutex as *mut _), 0); + assert_eq!(libc::pthread_mutex_trylock(&mut mutex as *mut _), libc::EBUSY); + assert_eq!(libc::pthread_mutex_unlock(&mut mutex as *mut _), 0); + assert_eq!(libc::pthread_mutex_trylock(&mut mutex as *mut _), 0); + assert_eq!(libc::pthread_mutex_unlock(&mut mutex as *mut _), 0); + assert_eq!(libc::pthread_mutex_destroy(&mut mutex as *mut _), 0); + } +} + +fn test_mutex_libc_init_errorcheck() { + unsafe { + let mut mutexattr: libc::pthread_mutexattr_t = std::mem::zeroed(); + assert_eq!( + libc::pthread_mutexattr_settype( + &mut mutexattr as *mut _, + libc::PTHREAD_MUTEX_ERRORCHECK, + ), + 0, + ); + let mut mutex: libc::pthread_mutex_t = std::mem::zeroed(); + assert_eq!(libc::pthread_mutex_init(&mut mutex as *mut _, &mutexattr as *const _), 0); + assert_eq!(libc::pthread_mutex_lock(&mut mutex as *mut _), 0); + assert_eq!(libc::pthread_mutex_trylock(&mut mutex as *mut _), libc::EBUSY); + assert_eq!(libc::pthread_mutex_lock(&mut mutex as *mut _), libc::EDEADLK); + assert_eq!(libc::pthread_mutex_unlock(&mut mutex as *mut _), 0); + assert_eq!(libc::pthread_mutex_trylock(&mut mutex as *mut _), 0); + assert_eq!(libc::pthread_mutex_unlock(&mut mutex as *mut _), 0); + assert_eq!(libc::pthread_mutex_unlock(&mut mutex as *mut _), libc::EPERM); + assert_eq!(libc::pthread_mutex_destroy(&mut mutex as *mut _), 0); + } +} + +// Only linux provides PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP, +// libc for macOS just has the default PTHREAD_MUTEX_INITIALIZER. +#[cfg(target_os = "linux")] +fn test_mutex_libc_static_initializer_recursive() { + let mutex = std::cell::UnsafeCell::new(libc::PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP); + unsafe { + assert_eq!(libc::pthread_mutex_lock(mutex.get()), 0); + assert_eq!(libc::pthread_mutex_trylock(mutex.get()), 0); + assert_eq!(libc::pthread_mutex_unlock(mutex.get()), 0); + assert_eq!(libc::pthread_mutex_unlock(mutex.get()), 0); + assert_eq!(libc::pthread_mutex_trylock(mutex.get()), 0); + assert_eq!(libc::pthread_mutex_lock(mutex.get()), 0); + assert_eq!(libc::pthread_mutex_unlock(mutex.get()), 0); + assert_eq!(libc::pthread_mutex_unlock(mutex.get()), 0); + assert_eq!(libc::pthread_mutex_unlock(mutex.get()), libc::EPERM); + assert_eq!(libc::pthread_mutex_destroy(mutex.get()), 0); + } +} + +// Testing the behavior of std::sync::RwLock does not fully exercise the pthread rwlock shims, we +// need to go a layer deeper and test the behavior of the libc functions, because +// std::sys::unix::rwlock::RWLock itself keeps track of write_locked and num_readers. +fn test_rwlock_libc_static_initializer() { + let rw = std::cell::UnsafeCell::new(libc::PTHREAD_RWLOCK_INITIALIZER); + unsafe { + assert_eq!(libc::pthread_rwlock_rdlock(rw.get()), 0); + assert_eq!(libc::pthread_rwlock_rdlock(rw.get()), 0); + assert_eq!(libc::pthread_rwlock_unlock(rw.get()), 0); + assert_eq!(libc::pthread_rwlock_tryrdlock(rw.get()), 0); + assert_eq!(libc::pthread_rwlock_unlock(rw.get()), 0); + assert_eq!(libc::pthread_rwlock_trywrlock(rw.get()), libc::EBUSY); + assert_eq!(libc::pthread_rwlock_unlock(rw.get()), 0); + + assert_eq!(libc::pthread_rwlock_wrlock(rw.get()), 0); + assert_eq!(libc::pthread_rwlock_tryrdlock(rw.get()), libc::EBUSY); + assert_eq!(libc::pthread_rwlock_trywrlock(rw.get()), libc::EBUSY); + assert_eq!(libc::pthread_rwlock_unlock(rw.get()), 0); + + assert_eq!(libc::pthread_rwlock_trywrlock(rw.get()), 0); + assert_eq!(libc::pthread_rwlock_tryrdlock(rw.get()), libc::EBUSY); + assert_eq!(libc::pthread_rwlock_trywrlock(rw.get()), libc::EBUSY); + assert_eq!(libc::pthread_rwlock_unlock(rw.get()), 0); + + assert_eq!(libc::pthread_rwlock_destroy(rw.get()), 0); + } +} From 83953f58e76b8edc236acf56f2526f4fd0957e83 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 17 Aug 2022 21:58:10 -0400 Subject: [PATCH 3652/3747] remove unneeded rustc_private feature --- tests/fail/concurrency/libc_pthread_create_main_terminate.rs | 2 -- tests/fail/concurrency/libc_pthread_join_detached.rs | 2 -- tests/fail/concurrency/libc_pthread_join_joined.rs | 2 -- tests/fail/concurrency/libc_pthread_join_main.rs | 2 -- tests/fail/concurrency/libc_pthread_join_multiple.rs | 2 -- tests/fail/concurrency/libc_pthread_join_self.rs | 2 -- tests/fail/concurrency/too_few_args.rs | 2 -- tests/fail/concurrency/too_many_args.rs | 2 -- tests/fail/concurrency/unwind_top_of_stack.rs | 2 +- tests/fail/shims/fs/close_stdout.rs | 2 -- tests/fail/shims/fs/isolated_stdin.rs | 2 -- tests/fail/shims/fs/mkstemp_immutable_arg.rs | 2 -- tests/fail/shims/fs/read_from_stdout.rs | 2 -- tests/fail/shims/fs/unix_open_missing_required_mode.rs | 2 -- tests/fail/shims/fs/write_to_stdin.rs | 2 -- tests/fail/shims/sync/libc_pthread_cond_double_destroy.rs | 1 - tests/fail/shims/sync/libc_pthread_condattr_double_destroy.rs | 1 - tests/fail/shims/sync/libc_pthread_mutex_NULL_deadlock.rs | 2 -- tests/fail/shims/sync/libc_pthread_mutex_deadlock.rs | 2 -- tests/fail/shims/sync/libc_pthread_mutex_default_deadlock.rs | 2 -- tests/fail/shims/sync/libc_pthread_mutex_destroy_locked.rs | 2 -- tests/fail/shims/sync/libc_pthread_mutex_double_destroy.rs | 1 - tests/fail/shims/sync/libc_pthread_mutex_normal_deadlock.rs | 2 -- .../shims/sync/libc_pthread_mutex_normal_unlock_unlocked.rs | 2 -- tests/fail/shims/sync/libc_pthread_mutex_wrong_owner.rs | 2 -- tests/fail/shims/sync/libc_pthread_mutexattr_double_destroy.rs | 1 - .../fail/shims/sync/libc_pthread_rwlock_destroy_read_locked.rs | 2 -- .../fail/shims/sync/libc_pthread_rwlock_destroy_write_locked.rs | 2 -- tests/fail/shims/sync/libc_pthread_rwlock_double_destroy.rs | 1 - .../libc_pthread_rwlock_read_write_deadlock_single_thread.rs | 2 -- tests/fail/shims/sync/libc_pthread_rwlock_read_wrong_owner.rs | 2 -- tests/fail/shims/sync/libc_pthread_rwlock_unlock_unlocked.rs | 2 -- .../fail/shims/sync/libc_pthread_rwlock_write_read_deadlock.rs | 2 -- .../libc_pthread_rwlock_write_read_deadlock_single_thread.rs | 2 -- .../fail/shims/sync/libc_pthread_rwlock_write_write_deadlock.rs | 2 -- .../libc_pthread_rwlock_write_write_deadlock_single_thread.rs | 2 -- tests/fail/shims/sync/libc_pthread_rwlock_write_wrong_owner.rs | 2 -- tests/fail/unsupported_signal.rs | 1 - tests/panic/unsupported_syscall.rs | 1 - tests/pass/calloc.rs | 2 -- tests/pass/concurrency/libc_pthread_cond.rs | 2 -- tests/pass/concurrency/linux-futex.rs | 2 -- tests/pass/concurrency/tls_pthread_drop_order.rs | 2 -- tests/pass/foreign-fn-linkname.rs | 1 - tests/pass/malloc.rs | 2 -- tests/pass/regions-mock-trans.rs | 2 -- tests/pass/shims/fs.rs | 1 - tests/pass/shims/fs_with_isolation.rs | 2 -- tests/pass/shims/linux-getrandom-without-isolation.rs | 1 - tests/pass/shims/linux-getrandom.rs | 1 - tests/pass/shims/posix_memalign.rs | 1 - 51 files changed, 1 insertion(+), 89 deletions(-) diff --git a/tests/fail/concurrency/libc_pthread_create_main_terminate.rs b/tests/fail/concurrency/libc_pthread_create_main_terminate.rs index 9da9fbf2029d1..065ad2d725f8f 100644 --- a/tests/fail/concurrency/libc_pthread_create_main_terminate.rs +++ b/tests/fail/concurrency/libc_pthread_create_main_terminate.rs @@ -3,8 +3,6 @@ // Check that we terminate the program when the main thread terminates. -#![feature(rustc_private)] - use std::{mem, ptr}; extern "C" fn thread_start(_null: *mut libc::c_void) -> *mut libc::c_void { diff --git a/tests/fail/concurrency/libc_pthread_join_detached.rs b/tests/fail/concurrency/libc_pthread_join_detached.rs index e81978fc9953a..488b14bbcfa85 100644 --- a/tests/fail/concurrency/libc_pthread_join_detached.rs +++ b/tests/fail/concurrency/libc_pthread_join_detached.rs @@ -2,8 +2,6 @@ // Joining a detached thread is undefined behavior. -#![feature(rustc_private)] - use std::{mem, ptr}; extern "C" fn thread_start(_null: *mut libc::c_void) -> *mut libc::c_void { diff --git a/tests/fail/concurrency/libc_pthread_join_joined.rs b/tests/fail/concurrency/libc_pthread_join_joined.rs index 11e00429c6ced..ebd1710bbf226 100644 --- a/tests/fail/concurrency/libc_pthread_join_joined.rs +++ b/tests/fail/concurrency/libc_pthread_join_joined.rs @@ -2,8 +2,6 @@ // Joining an already joined thread is undefined behavior. -#![feature(rustc_private)] - use std::{mem, ptr}; extern "C" fn thread_start(_null: *mut libc::c_void) -> *mut libc::c_void { diff --git a/tests/fail/concurrency/libc_pthread_join_main.rs b/tests/fail/concurrency/libc_pthread_join_main.rs index f029f08772f2e..df6b520431b6a 100644 --- a/tests/fail/concurrency/libc_pthread_join_main.rs +++ b/tests/fail/concurrency/libc_pthread_join_main.rs @@ -2,8 +2,6 @@ // Joining the main thread is undefined behavior. -#![feature(rustc_private)] - use std::{ptr, thread}; fn main() { diff --git a/tests/fail/concurrency/libc_pthread_join_multiple.rs b/tests/fail/concurrency/libc_pthread_join_multiple.rs index 017036ab01e18..e5187093befde 100644 --- a/tests/fail/concurrency/libc_pthread_join_multiple.rs +++ b/tests/fail/concurrency/libc_pthread_join_multiple.rs @@ -2,8 +2,6 @@ // Joining the same thread from multiple threads is undefined behavior. -#![feature(rustc_private)] - use std::thread; use std::{mem, ptr}; diff --git a/tests/fail/concurrency/libc_pthread_join_self.rs b/tests/fail/concurrency/libc_pthread_join_self.rs index ae61488931737..0c25c690f3721 100644 --- a/tests/fail/concurrency/libc_pthread_join_self.rs +++ b/tests/fail/concurrency/libc_pthread_join_self.rs @@ -4,8 +4,6 @@ // Joining itself is undefined behavior. -#![feature(rustc_private)] - use std::{ptr, thread}; fn main() { diff --git a/tests/fail/concurrency/too_few_args.rs b/tests/fail/concurrency/too_few_args.rs index 4760fbb6b0513..43c7c74d410f5 100644 --- a/tests/fail/concurrency/too_few_args.rs +++ b/tests/fail/concurrency/too_few_args.rs @@ -2,8 +2,6 @@ //! The thread function must have exactly one argument. -#![feature(rustc_private)] - use std::{mem, ptr}; extern "C" fn thread_start() -> *mut libc::c_void { diff --git a/tests/fail/concurrency/too_many_args.rs b/tests/fail/concurrency/too_many_args.rs index 6abe767dc8a73..d660037ca6695 100644 --- a/tests/fail/concurrency/too_many_args.rs +++ b/tests/fail/concurrency/too_many_args.rs @@ -2,8 +2,6 @@ //! The thread function must have exactly one argument. -#![feature(rustc_private)] - use std::{mem, ptr}; extern "C" fn thread_start(_null: *mut libc::c_void, _x: i32) -> *mut libc::c_void { diff --git a/tests/fail/concurrency/unwind_top_of_stack.rs b/tests/fail/concurrency/unwind_top_of_stack.rs index bd49401e61f57..c2b9d56e19c92 100644 --- a/tests/fail/concurrency/unwind_top_of_stack.rs +++ b/tests/fail/concurrency/unwind_top_of_stack.rs @@ -3,7 +3,7 @@ //! Unwinding past the top frame of a stack is Undefined Behavior. -#![feature(rustc_private, c_unwind)] +#![feature(c_unwind)] use std::{mem, ptr}; diff --git a/tests/fail/shims/fs/close_stdout.rs b/tests/fail/shims/fs/close_stdout.rs index e4eab5fd69640..09da8509af412 100644 --- a/tests/fail/shims/fs/close_stdout.rs +++ b/tests/fail/shims/fs/close_stdout.rs @@ -3,8 +3,6 @@ // FIXME: standard handles cannot be closed (https://github.com/rust-lang/rust/issues/40032) -#![feature(rustc_private)] - fn main() { unsafe { libc::close(1); //~ ERROR: cannot close stdout diff --git a/tests/fail/shims/fs/isolated_stdin.rs b/tests/fail/shims/fs/isolated_stdin.rs index 86b04a0383543..a45f805696d49 100644 --- a/tests/fail/shims/fs/isolated_stdin.rs +++ b/tests/fail/shims/fs/isolated_stdin.rs @@ -1,7 +1,5 @@ //@ignore-target-windows: No libc on Windows -#![feature(rustc_private)] - fn main() -> std::io::Result<()> { let mut bytes = [0u8; 512]; unsafe { diff --git a/tests/fail/shims/fs/mkstemp_immutable_arg.rs b/tests/fail/shims/fs/mkstemp_immutable_arg.rs index 5be1fb394b902..ba9f404d7c9ac 100644 --- a/tests/fail/shims/fs/mkstemp_immutable_arg.rs +++ b/tests/fail/shims/fs/mkstemp_immutable_arg.rs @@ -1,8 +1,6 @@ //@ignore-target-windows: No libc on Windows //@compile-flags: -Zmiri-disable-isolation -#![feature(rustc_private)] - fn main() { test_mkstemp_immutable_arg(); } diff --git a/tests/fail/shims/fs/read_from_stdout.rs b/tests/fail/shims/fs/read_from_stdout.rs index 0fd8ba2fc4195..073fca4712e9a 100644 --- a/tests/fail/shims/fs/read_from_stdout.rs +++ b/tests/fail/shims/fs/read_from_stdout.rs @@ -1,8 +1,6 @@ //@compile-flags: -Zmiri-disable-isolation //@ignore-target-windows: No libc on Windows -#![feature(rustc_private)] - fn main() -> std::io::Result<()> { let mut bytes = [0u8; 512]; unsafe { diff --git a/tests/fail/shims/fs/unix_open_missing_required_mode.rs b/tests/fail/shims/fs/unix_open_missing_required_mode.rs index 4740dcebe9200..ae231d4be667e 100644 --- a/tests/fail/shims/fs/unix_open_missing_required_mode.rs +++ b/tests/fail/shims/fs/unix_open_missing_required_mode.rs @@ -1,8 +1,6 @@ //@ignore-target-windows: No libc on Windows //@compile-flags: -Zmiri-disable-isolation -#![feature(rustc_private)] - fn main() { test_file_open_missing_needed_mode(); } diff --git a/tests/fail/shims/fs/write_to_stdin.rs b/tests/fail/shims/fs/write_to_stdin.rs index 0e9109fc6e238..d039ad718d339 100644 --- a/tests/fail/shims/fs/write_to_stdin.rs +++ b/tests/fail/shims/fs/write_to_stdin.rs @@ -1,7 +1,5 @@ //@ignore-target-windows: No libc on Windows -#![feature(rustc_private)] - fn main() -> std::io::Result<()> { let bytes = b"hello"; unsafe { diff --git a/tests/fail/shims/sync/libc_pthread_cond_double_destroy.rs b/tests/fail/shims/sync/libc_pthread_cond_double_destroy.rs index 90d5997f87120..94ca3496ed948 100644 --- a/tests/fail/shims/sync/libc_pthread_cond_double_destroy.rs +++ b/tests/fail/shims/sync/libc_pthread_cond_double_destroy.rs @@ -1,5 +1,4 @@ //@ignore-target-windows: No libc on Windows -#![feature(rustc_private)] /// Test that destroying a pthread_cond twice fails, even without a check for number validity diff --git a/tests/fail/shims/sync/libc_pthread_condattr_double_destroy.rs b/tests/fail/shims/sync/libc_pthread_condattr_double_destroy.rs index 028a924196f27..13e639a867dcc 100644 --- a/tests/fail/shims/sync/libc_pthread_condattr_double_destroy.rs +++ b/tests/fail/shims/sync/libc_pthread_condattr_double_destroy.rs @@ -1,5 +1,4 @@ //@ignore-target-windows: No libc on Windows -#![feature(rustc_private)] /// Test that destroying a pthread_condattr twice fails, even without a check for number validity diff --git a/tests/fail/shims/sync/libc_pthread_mutex_NULL_deadlock.rs b/tests/fail/shims/sync/libc_pthread_mutex_NULL_deadlock.rs index d87455877abcd..8b2510733831f 100644 --- a/tests/fail/shims/sync/libc_pthread_mutex_NULL_deadlock.rs +++ b/tests/fail/shims/sync/libc_pthread_mutex_NULL_deadlock.rs @@ -2,8 +2,6 @@ // // Check that if we pass NULL attribute, then we get the default mutex type. -#![feature(rustc_private)] - fn main() { unsafe { let mut mutex: libc::pthread_mutex_t = std::mem::zeroed(); diff --git a/tests/fail/shims/sync/libc_pthread_mutex_deadlock.rs b/tests/fail/shims/sync/libc_pthread_mutex_deadlock.rs index f77f5c2e20226..6c3cb738e2997 100644 --- a/tests/fail/shims/sync/libc_pthread_mutex_deadlock.rs +++ b/tests/fail/shims/sync/libc_pthread_mutex_deadlock.rs @@ -1,7 +1,5 @@ //@ignore-target-windows: No libc on Windows -#![feature(rustc_private)] - use std::cell::UnsafeCell; use std::sync::Arc; use std::thread; diff --git a/tests/fail/shims/sync/libc_pthread_mutex_default_deadlock.rs b/tests/fail/shims/sync/libc_pthread_mutex_default_deadlock.rs index b28101e20b246..f443768819f96 100644 --- a/tests/fail/shims/sync/libc_pthread_mutex_default_deadlock.rs +++ b/tests/fail/shims/sync/libc_pthread_mutex_default_deadlock.rs @@ -2,8 +2,6 @@ // // Check that if we do not set the mutex type, it is the default. -#![feature(rustc_private)] - fn main() { unsafe { let mutexattr: libc::pthread_mutexattr_t = std::mem::zeroed(); diff --git a/tests/fail/shims/sync/libc_pthread_mutex_destroy_locked.rs b/tests/fail/shims/sync/libc_pthread_mutex_destroy_locked.rs index 0f74446fa27e7..ec3965c7574eb 100644 --- a/tests/fail/shims/sync/libc_pthread_mutex_destroy_locked.rs +++ b/tests/fail/shims/sync/libc_pthread_mutex_destroy_locked.rs @@ -1,7 +1,5 @@ //@ignore-target-windows: No libc on Windows -#![feature(rustc_private)] - fn main() { unsafe { let mut mutexattr: libc::pthread_mutexattr_t = std::mem::zeroed(); diff --git a/tests/fail/shims/sync/libc_pthread_mutex_double_destroy.rs b/tests/fail/shims/sync/libc_pthread_mutex_double_destroy.rs index 89022f3b5625e..622c3eaeae30d 100644 --- a/tests/fail/shims/sync/libc_pthread_mutex_double_destroy.rs +++ b/tests/fail/shims/sync/libc_pthread_mutex_double_destroy.rs @@ -1,5 +1,4 @@ //@ignore-target-windows: No libc on Windows -#![feature(rustc_private)] /// Test that destroying a pthread_mutex twice fails, even without a check for number validity diff --git a/tests/fail/shims/sync/libc_pthread_mutex_normal_deadlock.rs b/tests/fail/shims/sync/libc_pthread_mutex_normal_deadlock.rs index ab6d9c7739d7b..5ea09fa5aac3d 100644 --- a/tests/fail/shims/sync/libc_pthread_mutex_normal_deadlock.rs +++ b/tests/fail/shims/sync/libc_pthread_mutex_normal_deadlock.rs @@ -1,7 +1,5 @@ //@ignore-target-windows: No libc on Windows -#![feature(rustc_private)] - fn main() { unsafe { let mut mutexattr: libc::pthread_mutexattr_t = std::mem::zeroed(); diff --git a/tests/fail/shims/sync/libc_pthread_mutex_normal_unlock_unlocked.rs b/tests/fail/shims/sync/libc_pthread_mutex_normal_unlock_unlocked.rs index f259a4dee7d8d..8ce7542edb87f 100644 --- a/tests/fail/shims/sync/libc_pthread_mutex_normal_unlock_unlocked.rs +++ b/tests/fail/shims/sync/libc_pthread_mutex_normal_unlock_unlocked.rs @@ -1,7 +1,5 @@ //@ignore-target-windows: No libc on Windows -#![feature(rustc_private)] - fn main() { unsafe { let mut mutexattr: libc::pthread_mutexattr_t = std::mem::zeroed(); diff --git a/tests/fail/shims/sync/libc_pthread_mutex_wrong_owner.rs b/tests/fail/shims/sync/libc_pthread_mutex_wrong_owner.rs index b8e57f8f74e9e..b56775252e4b4 100644 --- a/tests/fail/shims/sync/libc_pthread_mutex_wrong_owner.rs +++ b/tests/fail/shims/sync/libc_pthread_mutex_wrong_owner.rs @@ -1,7 +1,5 @@ //@ignore-target-windows: No libc on Windows -#![feature(rustc_private)] - use std::cell::UnsafeCell; use std::sync::Arc; use std::thread; diff --git a/tests/fail/shims/sync/libc_pthread_mutexattr_double_destroy.rs b/tests/fail/shims/sync/libc_pthread_mutexattr_double_destroy.rs index ac6292570e497..474a277516d94 100644 --- a/tests/fail/shims/sync/libc_pthread_mutexattr_double_destroy.rs +++ b/tests/fail/shims/sync/libc_pthread_mutexattr_double_destroy.rs @@ -1,5 +1,4 @@ //@ignore-target-windows: No libc on Windows -#![feature(rustc_private)] /// Test that destroying a pthread_mutexattr twice fails, even without a check for number validity diff --git a/tests/fail/shims/sync/libc_pthread_rwlock_destroy_read_locked.rs b/tests/fail/shims/sync/libc_pthread_rwlock_destroy_read_locked.rs index ae7c1bbde72af..603580ff58abd 100644 --- a/tests/fail/shims/sync/libc_pthread_rwlock_destroy_read_locked.rs +++ b/tests/fail/shims/sync/libc_pthread_rwlock_destroy_read_locked.rs @@ -1,7 +1,5 @@ //@ignore-target-windows: No libc on Windows -#![feature(rustc_private)] - fn main() { let rw = std::cell::UnsafeCell::new(libc::PTHREAD_RWLOCK_INITIALIZER); unsafe { diff --git a/tests/fail/shims/sync/libc_pthread_rwlock_destroy_write_locked.rs b/tests/fail/shims/sync/libc_pthread_rwlock_destroy_write_locked.rs index 9642595ca4e0b..ae44f22d146ca 100644 --- a/tests/fail/shims/sync/libc_pthread_rwlock_destroy_write_locked.rs +++ b/tests/fail/shims/sync/libc_pthread_rwlock_destroy_write_locked.rs @@ -1,7 +1,5 @@ //@ignore-target-windows: No libc on Windows -#![feature(rustc_private)] - fn main() { let rw = std::cell::UnsafeCell::new(libc::PTHREAD_RWLOCK_INITIALIZER); unsafe { diff --git a/tests/fail/shims/sync/libc_pthread_rwlock_double_destroy.rs b/tests/fail/shims/sync/libc_pthread_rwlock_double_destroy.rs index 81b1661ce8d41..800986f7506c0 100644 --- a/tests/fail/shims/sync/libc_pthread_rwlock_double_destroy.rs +++ b/tests/fail/shims/sync/libc_pthread_rwlock_double_destroy.rs @@ -1,5 +1,4 @@ //@ignore-target-windows: No libc on Windows -#![feature(rustc_private)] /// Test that destroying a pthread_rwlock twice fails, even without a check for number validity diff --git a/tests/fail/shims/sync/libc_pthread_rwlock_read_write_deadlock_single_thread.rs b/tests/fail/shims/sync/libc_pthread_rwlock_read_write_deadlock_single_thread.rs index 158dd8c1cda33..782c95b6d2e3c 100644 --- a/tests/fail/shims/sync/libc_pthread_rwlock_read_write_deadlock_single_thread.rs +++ b/tests/fail/shims/sync/libc_pthread_rwlock_read_write_deadlock_single_thread.rs @@ -1,7 +1,5 @@ //@ignore-target-windows: No libc on Windows -#![feature(rustc_private)] - fn main() { let rw = std::cell::UnsafeCell::new(libc::PTHREAD_RWLOCK_INITIALIZER); unsafe { diff --git a/tests/fail/shims/sync/libc_pthread_rwlock_read_wrong_owner.rs b/tests/fail/shims/sync/libc_pthread_rwlock_read_wrong_owner.rs index 23dda68c6a428..1b498ad8fcdb4 100644 --- a/tests/fail/shims/sync/libc_pthread_rwlock_read_wrong_owner.rs +++ b/tests/fail/shims/sync/libc_pthread_rwlock_read_wrong_owner.rs @@ -1,7 +1,5 @@ //@ignore-target-windows: No libc on Windows -#![feature(rustc_private)] - use std::cell::UnsafeCell; use std::sync::Arc; use std::thread; diff --git a/tests/fail/shims/sync/libc_pthread_rwlock_unlock_unlocked.rs b/tests/fail/shims/sync/libc_pthread_rwlock_unlock_unlocked.rs index fdcf8e41d36fb..05f7e7a06c57f 100644 --- a/tests/fail/shims/sync/libc_pthread_rwlock_unlock_unlocked.rs +++ b/tests/fail/shims/sync/libc_pthread_rwlock_unlock_unlocked.rs @@ -1,7 +1,5 @@ //@ignore-target-windows: No libc on Windows -#![feature(rustc_private)] - fn main() { let rw = std::cell::UnsafeCell::new(libc::PTHREAD_RWLOCK_INITIALIZER); unsafe { diff --git a/tests/fail/shims/sync/libc_pthread_rwlock_write_read_deadlock.rs b/tests/fail/shims/sync/libc_pthread_rwlock_write_read_deadlock.rs index adbb95fc28e8b..201844615e182 100644 --- a/tests/fail/shims/sync/libc_pthread_rwlock_write_read_deadlock.rs +++ b/tests/fail/shims/sync/libc_pthread_rwlock_write_read_deadlock.rs @@ -1,7 +1,5 @@ //@ignore-target-windows: No libc on Windows -#![feature(rustc_private)] - use std::cell::UnsafeCell; use std::sync::Arc; use std::thread; diff --git a/tests/fail/shims/sync/libc_pthread_rwlock_write_read_deadlock_single_thread.rs b/tests/fail/shims/sync/libc_pthread_rwlock_write_read_deadlock_single_thread.rs index a7d16caa7a491..538f14ef89f20 100644 --- a/tests/fail/shims/sync/libc_pthread_rwlock_write_read_deadlock_single_thread.rs +++ b/tests/fail/shims/sync/libc_pthread_rwlock_write_read_deadlock_single_thread.rs @@ -1,7 +1,5 @@ //@ignore-target-windows: No libc on Windows -#![feature(rustc_private)] - fn main() { let rw = std::cell::UnsafeCell::new(libc::PTHREAD_RWLOCK_INITIALIZER); unsafe { diff --git a/tests/fail/shims/sync/libc_pthread_rwlock_write_write_deadlock.rs b/tests/fail/shims/sync/libc_pthread_rwlock_write_write_deadlock.rs index 070373255d327..b1d7e0492e5a2 100644 --- a/tests/fail/shims/sync/libc_pthread_rwlock_write_write_deadlock.rs +++ b/tests/fail/shims/sync/libc_pthread_rwlock_write_write_deadlock.rs @@ -1,7 +1,5 @@ //@ignore-target-windows: No libc on Windows -#![feature(rustc_private)] - use std::cell::UnsafeCell; use std::sync::Arc; use std::thread; diff --git a/tests/fail/shims/sync/libc_pthread_rwlock_write_write_deadlock_single_thread.rs b/tests/fail/shims/sync/libc_pthread_rwlock_write_write_deadlock_single_thread.rs index 867c6272c4633..2c963d36510e6 100644 --- a/tests/fail/shims/sync/libc_pthread_rwlock_write_write_deadlock_single_thread.rs +++ b/tests/fail/shims/sync/libc_pthread_rwlock_write_write_deadlock_single_thread.rs @@ -1,7 +1,5 @@ //@ignore-target-windows: No libc on Windows -#![feature(rustc_private)] - fn main() { let rw = std::cell::UnsafeCell::new(libc::PTHREAD_RWLOCK_INITIALIZER); unsafe { diff --git a/tests/fail/shims/sync/libc_pthread_rwlock_write_wrong_owner.rs b/tests/fail/shims/sync/libc_pthread_rwlock_write_wrong_owner.rs index cff2a7a2e98c2..dd099474d8fed 100644 --- a/tests/fail/shims/sync/libc_pthread_rwlock_write_wrong_owner.rs +++ b/tests/fail/shims/sync/libc_pthread_rwlock_write_wrong_owner.rs @@ -1,7 +1,5 @@ //@ignore-target-windows: No libc on Windows -#![feature(rustc_private)] - use std::cell::UnsafeCell; use std::sync::Arc; use std::thread; diff --git a/tests/fail/unsupported_signal.rs b/tests/fail/unsupported_signal.rs index 20ebcc9bc4735..d50041ffbd9de 100644 --- a/tests/fail/unsupported_signal.rs +++ b/tests/fail/unsupported_signal.rs @@ -1,7 +1,6 @@ //! `signal()` is special on Linux and macOS that it's only supported within libstd. //! The implementation is not complete enough to permit user code to call it. //@ignore-target-windows: No libc on Windows -#![feature(rustc_private)] fn main() { unsafe { diff --git a/tests/panic/unsupported_syscall.rs b/tests/panic/unsupported_syscall.rs index 27595bf1071ff..31d666e1d9d80 100644 --- a/tests/panic/unsupported_syscall.rs +++ b/tests/panic/unsupported_syscall.rs @@ -1,7 +1,6 @@ //@ignore-target-windows: No libc on Windows //@ignore-target-apple: `syscall` is not supported on macOS //@compile-flags: -Zmiri-panic-on-unsupported -#![feature(rustc_private)] fn main() { unsafe { diff --git a/tests/pass/calloc.rs b/tests/pass/calloc.rs index e155d53ce812e..62ab63c5fc788 100644 --- a/tests/pass/calloc.rs +++ b/tests/pass/calloc.rs @@ -1,7 +1,5 @@ //@ignore-target-windows: No libc on Windows -#![feature(rustc_private)] - use core::slice; fn main() { diff --git a/tests/pass/concurrency/libc_pthread_cond.rs b/tests/pass/concurrency/libc_pthread_cond.rs index c5b0e86666a0a..b0325f7d78e50 100644 --- a/tests/pass/concurrency/libc_pthread_cond.rs +++ b/tests/pass/concurrency/libc_pthread_cond.rs @@ -2,8 +2,6 @@ //@ignore-target-apple: pthread_condattr_setclock is not supported on MacOS. //@compile-flags: -Zmiri-disable-isolation -#![feature(rustc_private)] - /// Test that conditional variable timeouts are working properly with both /// monotonic and system clocks. use std::mem::MaybeUninit; diff --git a/tests/pass/concurrency/linux-futex.rs b/tests/pass/concurrency/linux-futex.rs index 2c99bfa1000cd..a456528ec2074 100644 --- a/tests/pass/concurrency/linux-futex.rs +++ b/tests/pass/concurrency/linux-futex.rs @@ -1,8 +1,6 @@ //@only-target-linux //@compile-flags: -Zmiri-disable-isolation -#![feature(rustc_private)] - use std::mem::MaybeUninit; use std::ptr; use std::sync::atomic::AtomicI32; diff --git a/tests/pass/concurrency/tls_pthread_drop_order.rs b/tests/pass/concurrency/tls_pthread_drop_order.rs index 1ccc57da25fad..6200233c81193 100644 --- a/tests/pass/concurrency/tls_pthread_drop_order.rs +++ b/tests/pass/concurrency/tls_pthread_drop_order.rs @@ -1,7 +1,5 @@ //@ignore-target-windows: No libc on Windows -#![feature(rustc_private)] - use std::mem; use std::ptr; diff --git a/tests/pass/foreign-fn-linkname.rs b/tests/pass/foreign-fn-linkname.rs index 40aeb2ef6313f..c1cb028f55da9 100644 --- a/tests/pass/foreign-fn-linkname.rs +++ b/tests/pass/foreign-fn-linkname.rs @@ -1,5 +1,4 @@ //ignore-windows: Uses POSIX APIs -#![feature(rustc_private)] use std::ffi::CString; diff --git a/tests/pass/malloc.rs b/tests/pass/malloc.rs index 9066e2af25fa3..f5e014c000d15 100644 --- a/tests/pass/malloc.rs +++ b/tests/pass/malloc.rs @@ -1,7 +1,5 @@ //@ignore-target-windows: No libc on Windows -#![feature(rustc_private)] - use core::{ptr, slice}; fn main() { diff --git a/tests/pass/regions-mock-trans.rs b/tests/pass/regions-mock-trans.rs index 7432ea9582618..caaf48c2bec7a 100644 --- a/tests/pass/regions-mock-trans.rs +++ b/tests/pass/regions-mock-trans.rs @@ -1,7 +1,5 @@ //ignore-windows: Uses POSIX APIs -#![feature(rustc_private)] - use std::mem; struct Arena(()); diff --git a/tests/pass/shims/fs.rs b/tests/pass/shims/fs.rs index af9f854ce527f..9faced0291612 100644 --- a/tests/pass/shims/fs.rs +++ b/tests/pass/shims/fs.rs @@ -1,7 +1,6 @@ //@ignore-target-windows: File handling is not implemented yet //@compile-flags: -Zmiri-disable-isolation -#![feature(rustc_private)] #![feature(io_error_more)] #![feature(io_error_uncategorized)] diff --git a/tests/pass/shims/fs_with_isolation.rs b/tests/pass/shims/fs_with_isolation.rs index f73e64ad17a26..f5420dbc5538e 100644 --- a/tests/pass/shims/fs_with_isolation.rs +++ b/tests/pass/shims/fs_with_isolation.rs @@ -2,8 +2,6 @@ //@compile-flags: -Zmiri-isolation-error=warn-nobacktrace //@normalize-stderr-test: "(stat(x)?)" -> "$$STAT" -#![feature(rustc_private)] - use std::ffi::CString; use std::fs::{self, File}; use std::io::{Error, ErrorKind}; diff --git a/tests/pass/shims/linux-getrandom-without-isolation.rs b/tests/pass/shims/linux-getrandom-without-isolation.rs index 12b42552bd5d6..349b447569a4b 100644 --- a/tests/pass/shims/linux-getrandom-without-isolation.rs +++ b/tests/pass/shims/linux-getrandom-without-isolation.rs @@ -1,6 +1,5 @@ //@only-target-linux //@compile-flags: -Zmiri-disable-isolation -#![feature(rustc_private)] use std::ptr; diff --git a/tests/pass/shims/linux-getrandom.rs b/tests/pass/shims/linux-getrandom.rs index e3309f480d36e..a1436c7319d33 100644 --- a/tests/pass/shims/linux-getrandom.rs +++ b/tests/pass/shims/linux-getrandom.rs @@ -1,5 +1,4 @@ //@only-target-linux -#![feature(rustc_private)] use std::ptr; diff --git a/tests/pass/shims/posix_memalign.rs b/tests/pass/shims/posix_memalign.rs index 5dadb62436d64..9bd8a00d68dcd 100644 --- a/tests/pass/shims/posix_memalign.rs +++ b/tests/pass/shims/posix_memalign.rs @@ -1,6 +1,5 @@ //@ignore-target-windows: No libc on Windows -#![feature(rustc_private)] #![feature(pointer_is_aligned)] #![feature(strict_provenance)] From ed41f1c96980ed26512e10e39406d8c91033a9e7 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 17 Aug 2022 22:00:54 -0400 Subject: [PATCH 3653/3747] remove some leftover //ignore that did not do anything --- tests/pass/foreign-fn-linkname.rs | 2 -- tests/pass/regions-mock-trans.rs | 2 -- 2 files changed, 4 deletions(-) diff --git a/tests/pass/foreign-fn-linkname.rs b/tests/pass/foreign-fn-linkname.rs index c1cb028f55da9..9f090a4eff5d8 100644 --- a/tests/pass/foreign-fn-linkname.rs +++ b/tests/pass/foreign-fn-linkname.rs @@ -1,5 +1,3 @@ -//ignore-windows: Uses POSIX APIs - use std::ffi::CString; mod mlibc { diff --git a/tests/pass/regions-mock-trans.rs b/tests/pass/regions-mock-trans.rs index caaf48c2bec7a..57f1b75f4d52b 100644 --- a/tests/pass/regions-mock-trans.rs +++ b/tests/pass/regions-mock-trans.rs @@ -1,5 +1,3 @@ -//ignore-windows: Uses POSIX APIs - use std::mem; struct Arena(()); From b6fc2fc82a90ee1deb4a65c811764c610155b6b9 Mon Sep 17 00:00:00 2001 From: DrMeepster <19316085+DrMeepster@users.noreply.github.com> Date: Wed, 25 May 2022 16:28:37 -0700 Subject: [PATCH 3654/3747] basic theading --- src/lib.rs | 2 + src/shims/tls.rs | 16 +- src/shims/unix/thread.rs | 43 +---- src/shims/windows/dlsym.rs | 20 ++- src/shims/windows/foreign_items.rs | 102 ++++++----- src/shims/windows/handle.rs | 162 ++++++++++++++++++ src/shims/windows/mod.rs | 2 + src/shims/windows/thread.rs | 84 +++++++++ src/thread.rs | 113 +++++++++--- ...rs => libc_pthread_create_too_few_args.rs} | 2 +- ...> libc_pthread_create_too_few_args.stderr} | 2 +- ...s => libc_pthread_create_too_many_args.rs} | 2 +- ... libc_pthread_create_too_many_args.stderr} | 2 +- .../concurrency/libc_pthread_join_detached.rs | 2 +- .../libc_pthread_join_detached.stderr | 2 +- tests/fail/concurrency/thread-spawn.rs | 9 - tests/fail/concurrency/thread-spawn.stderr | 30 ---- .../thread_local_static_dealloc.rs | 2 - tests/fail/concurrency/unwind_top_of_stack.rs | 3 +- tests/fail/data_race/alloc_read_race.rs | 1 - tests/fail/data_race/alloc_write_race.rs | 1 - .../data_race/atomic_read_na_write_race1.rs | 1 - .../data_race/atomic_read_na_write_race2.rs | 1 - .../data_race/atomic_write_na_read_race1.rs | 1 - .../data_race/atomic_write_na_read_race2.rs | 1 - .../data_race/atomic_write_na_write_race1.rs | 1 - .../data_race/atomic_write_na_write_race2.rs | 1 - .../data_race/dangling_thread_async_race.rs | 1 - tests/fail/data_race/dangling_thread_race.rs | 1 - tests/fail/data_race/dealloc_read_race1.rs | 1 - tests/fail/data_race/dealloc_read_race2.rs | 1 - .../fail/data_race/dealloc_read_race_stack.rs | 1 - tests/fail/data_race/dealloc_write_race1.rs | 1 - tests/fail/data_race/dealloc_write_race2.rs | 1 - .../data_race/dealloc_write_race_stack.rs | 1 - .../data_race/enable_after_join_to_main.rs | 1 - tests/fail/data_race/fence_after_load.rs | 1 - tests/fail/data_race/read_write_race.rs | 1 - tests/fail/data_race/read_write_race_stack.rs | 1 - tests/fail/data_race/relax_acquire_race.rs | 1 - tests/fail/data_race/release_seq_race.rs | 1 - .../data_race/release_seq_race_same_thread.rs | 1 - tests/fail/data_race/rmw_race.rs | 1 - tests/fail/data_race/write_write_race.rs | 1 - .../fail/data_race/write_write_race_stack.rs | 1 - tests/fail/should-pass/cpp20_rwc_syncs.rs | 1 - tests/fail/weak_memory/racing_mixed_size.rs | 1 - .../weak_memory/racing_mixed_size_read.rs | 1 - tests/pass/0weak_memory_consistency.rs | 1 - tests/pass/concurrency/channels.rs | 2 +- .../concurrency/concurrent_caller_location.rs | 2 - tests/pass/concurrency/data_race.rs | 1 - .../concurrency/disable_data_race_detector.rs | 1 - tests/pass/concurrency/issue1643.rs | 2 - tests/pass/concurrency/simple.rs | 1 - tests/pass/concurrency/spin_loop.rs | 1 - .../pass/concurrency/spin_loops_nopreempt.rs | 2 +- tests/pass/concurrency/thread_locals.rs | 1 - tests/pass/concurrency/tls_lib_drop.rs | 2 - tests/pass/panic/concurrent-panic.rs | 2 +- tests/pass/shims/time.rs | 3 - tests/pass/threadleak_ignored.rs | 2 +- tests/pass/weak_memory/extra_cpp.rs | 1 - tests/pass/weak_memory/extra_cpp_unsafe.rs | 1 - tests/pass/weak_memory/weak.rs | 1 - 65 files changed, 448 insertions(+), 207 deletions(-) create mode 100644 src/shims/windows/handle.rs create mode 100644 src/shims/windows/thread.rs rename tests/fail/concurrency/{too_few_args.rs => libc_pthread_create_too_few_args.rs} (92%) rename tests/fail/concurrency/{too_few_args.stderr => libc_pthread_create_too_few_args.stderr} (92%) rename tests/fail/concurrency/{too_many_args.rs => libc_pthread_create_too_many_args.rs} (92%) rename tests/fail/concurrency/{too_many_args.stderr => libc_pthread_create_too_many_args.stderr} (92%) delete mode 100644 tests/fail/concurrency/thread-spawn.rs delete mode 100644 tests/fail/concurrency/thread-spawn.stderr diff --git a/src/lib.rs b/src/lib.rs index ba337f28311e9..73c96b2e59abb 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -5,6 +5,8 @@ #![feature(try_blocks)] #![feature(let_else)] #![feature(io_error_more)] +#![feature(int_log)] +#![feature(variant_count)] #![feature(yeet_expr)] #![feature(is_some_with)] #![feature(nonzero_ops)] diff --git a/src/shims/tls.rs b/src/shims/tls.rs index 633e0322bb83d..8627d9a044790 100644 --- a/src/shims/tls.rs +++ b/src/shims/tls.rs @@ -229,25 +229,25 @@ impl<'tcx> TlsData<'tcx> { impl<'mir, 'tcx: 'mir> EvalContextPrivExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { - /// Schedule TLS destructors for the main thread on Windows. The - /// implementation assumes that we do not support concurrency on Windows - /// yet. + /// Schedule TLS destructors for Windows. + /// On windows, TLS destructors are managed by std. fn schedule_windows_tls_dtors(&mut self) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let active_thread = this.get_active_thread(); - assert_eq!(this.get_total_thread_count(), 1, "concurrency on Windows is not supported"); + // Windows has a special magic linker section that is run on certain events. // Instead of searching for that section and supporting arbitrary hooks in there // (that would be basically https://github.com/rust-lang/miri/issues/450), // we specifically look up the static in libstd that we know is placed // in that section. - let thread_callback = this - .eval_path_scalar(&["std", "sys", "windows", "thread_local_key", "p_thread_callback"])? - .to_pointer(this)?; + let thread_callback = + this.eval_windows("thread_local_key", "p_thread_callback")?.to_pointer(this)?; let thread_callback = this.get_ptr_fn(thread_callback)?.as_instance()?; + // Technically, the reason should be `DLL_PROCESS_DETACH` when the main thread exits but std ignores it. + let reason = this.eval_windows("c", "DLL_THREAD_DETACH")?; + // The signature of this function is `unsafe extern "system" fn(h: c::LPVOID, dwReason: c::DWORD, pv: c::LPVOID)`. - let reason = this.eval_path_scalar(&["std", "sys", "windows", "c", "DLL_THREAD_DETACH"])?; this.call_function( thread_callback, Abi::System { unwind: false }, diff --git a/src/shims/unix/thread.rs b/src/shims/unix/thread.rs index 0df70543fac88..094183b3e781a 100644 --- a/src/shims/unix/thread.rs +++ b/src/shims/unix/thread.rs @@ -13,47 +13,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - // Create the new thread - let new_thread_id = this.create_thread(); - - // Write the current thread-id, switch to the next thread later - // to treat this write operation as occuring on the current thread. - let thread_info_place = this.deref_operand(thread)?; - this.write_scalar( - Scalar::from_uint(new_thread_id.to_u32(), thread_info_place.layout.size), - &thread_info_place.into(), - )?; - - // Read the function argument that will be sent to the new thread - // before the thread starts executing since reading after the - // context switch will incorrectly report a data-race. - let fn_ptr = this.read_pointer(start_routine)?; - let func_arg = this.read_immediate(arg)?; - - // Finally switch to new thread so that we can push the first stackframe. - // After this all accesses will be treated as occuring in the new thread. - let old_thread_id = this.set_active_thread(new_thread_id); - - // Perform the function pointer load in the new thread frame. - let instance = this.get_ptr_fn(fn_ptr)?.as_instance()?; - - // Note: the returned value is currently ignored (see the FIXME in - // pthread_join below) because the Rust standard library does not use - // it. - let ret_place = - this.allocate(this.layout_of(this.tcx.types.usize)?, MiriMemoryKind::Machine.into())?; - - this.call_function( - instance, + this.start_thread( + Some(thread), + start_routine, Abi::C { unwind: false }, - &[*func_arg], - Some(&ret_place.into()), - StackPopCleanup::Root { cleanup: true }, + arg, + this.layout_of(this.tcx.types.usize)?, )?; - // Restore the old active thread frame. - this.set_active_thread(old_thread_id); - Ok(0) } diff --git a/src/shims/windows/dlsym.rs b/src/shims/windows/dlsym.rs index eab5f99c87851..f18e27d38c2bc 100644 --- a/src/shims/windows/dlsym.rs +++ b/src/shims/windows/dlsym.rs @@ -5,11 +5,13 @@ use rustc_target::spec::abi::Abi; use log::trace; use crate::helpers::check_arg_count; +use crate::shims::windows::handle::Handle; use crate::*; #[derive(Debug, Copy, Clone)] pub enum Dlsym { NtWriteFile, + SetThreadDescription, } impl Dlsym { @@ -18,8 +20,8 @@ impl Dlsym { pub fn from_str<'tcx>(name: &str) -> InterpResult<'tcx, Option> { Ok(match name { "GetSystemTimePreciseAsFileTime" => None, - "SetThreadDescription" => None, "NtWriteFile" => Some(Dlsym::NtWriteFile), + "SetThreadDescription" => Some(Dlsym::SetThreadDescription), _ => throw_unsup_format!("unsupported Windows dlsym: {}", name), }) } @@ -107,6 +109,22 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx dest, )?; } + Dlsym::SetThreadDescription => { + let [handle, name] = check_arg_count(args)?; + + let name = this.read_wide_str(this.read_pointer(name)?)?; + + let thread = + match Handle::from_scalar(this.read_scalar(handle)?.check_init()?, this)? { + Some(Handle::Thread(thread)) => thread, + Some(Handle::CurrentThread) => this.get_active_thread(), + _ => throw_ub_format!("invalid handle"), + }; + + this.set_thread_name_wide(thread, name); + + this.write_null(dest)?; + } } trace!("{:?}", this.dump_place(**dest)); diff --git a/src/shims/windows/foreign_items.rs b/src/shims/windows/foreign_items.rs index 6520609b76f4e..00a80f869751a 100644 --- a/src/shims/windows/foreign_items.rs +++ b/src/shims/windows/foreign_items.rs @@ -1,12 +1,17 @@ use std::iter; +use std::time::{Duration, Instant}; use rustc_span::Symbol; use rustc_target::abi::Size; use rustc_target::spec::abi::Abi; +use crate::thread::Time; use crate::*; use shims::foreign_items::EmulateByNameResult; +use shims::windows::handle::{EvalContextExt as _, Handle}; use shims::windows::sync::EvalContextExt as _; +use shims::windows::thread::EvalContextExt as _; + use smallvec::SmallVec; impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} @@ -219,6 +224,29 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let result = this.QueryPerformanceFrequency(lpFrequency)?; this.write_scalar(Scalar::from_i32(result), dest)?; } + "Sleep" => { + let [timeout] = + this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; + + this.check_no_isolation("`Sleep`")?; + + let timeout_ms = this.read_scalar(timeout)?.to_u32()?; + + let duration = Duration::from_millis(timeout_ms as u64); + let timeout_time = Time::Monotonic(Instant::now().checked_add(duration).unwrap()); + + let active_thread = this.get_active_thread(); + this.block_thread(active_thread); + + this.register_timeout_callback( + active_thread, + timeout_time, + Box::new(move |ecx| { + ecx.unblock_thread(active_thread); + Ok(()) + }), + ); + } // Synchronization primitives "AcquireSRWLockExclusive" => { @@ -314,10 +342,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // FIXME: we should set last_error, but to what? this.write_null(dest)?; } - "SwitchToThread" => { + // this is only callable from std because we know that std ignores the return value + "SwitchToThread" if this.frame_in_std() => { let [] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; - // Note that once Miri supports concurrency, this will need to return a nonzero - // value if this call does result in switching to another thread. + + this.yield_active_thread(); + + // FIXME: this should return a nonzero value if this call does result in switching to another thread. this.write_null(dest)?; } "GetStdHandle" => { @@ -329,14 +360,37 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // std-only shim. this.write_scalar(Scalar::from_machine_isize(which.into(), this), dest)?; } + "CloseHandle" => { + let [handle] = + this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; - // Better error for attempts to create a thread + this.CloseHandle(handle)?; + + this.write_scalar(Scalar::from_u32(1), dest)?; + } + + // Threading "CreateThread" => { - let [_, _, _, _, _, _] = + let [security, stacksize, start, arg, flags, thread] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; - this.handle_unsupported("can't create threads on Windows")?; - return Ok(EmulateByNameResult::AlreadyJumped); + let thread_id = + this.CreateThread(security, stacksize, start, arg, flags, thread)?; + + this.write_scalar(Handle::Thread(thread_id).to_scalar(this), dest)?; + } + "WaitForSingleObject" => { + let [handle, timeout] = + this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; + + this.WaitForSingleObject(handle, timeout)?; + + this.write_scalar(Scalar::from_u32(0), dest)?; + } + "GetCurrentThread" => { + let [] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; + + this.write_scalar(Handle::CurrentThread.to_scalar(this), dest)?; } // Incomplete shims that we "stub out" just to get pre-main initialization code to work. @@ -374,40 +428,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Any non zero value works for the stdlib. This is just used for stack overflows anyway. this.write_scalar(Scalar::from_u32(1), dest)?; } - | "InitializeCriticalSection" - | "EnterCriticalSection" - | "LeaveCriticalSection" - | "DeleteCriticalSection" - if this.frame_in_std() => - { - #[allow(non_snake_case)] - let [_lpCriticalSection] = - this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; - assert_eq!( - this.get_total_thread_count(), - 1, - "concurrency on Windows is not supported" - ); - // Nothing to do, not even a return value. - // (Windows locks are reentrant, and we have only 1 thread, - // so not doing any futher checks here is at least not incorrect.) - } - "TryEnterCriticalSection" if this.frame_in_std() => { - #[allow(non_snake_case)] - let [_lpCriticalSection] = - this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; - assert_eq!( - this.get_total_thread_count(), - 1, - "concurrency on Windows is not supported" - ); - // There is only one thread, so this always succeeds and returns TRUE. - this.write_scalar(Scalar::from_i32(1), dest)?; - } - "GetCurrentThread" if this.frame_in_std() => { - let [] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; - this.write_scalar(Scalar::from_machine_isize(1, this), dest)?; - } "GetCurrentProcessId" if this.frame_in_std() => { let [] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; let result = this.GetCurrentProcessId()?; diff --git a/src/shims/windows/handle.rs b/src/shims/windows/handle.rs new file mode 100644 index 0000000000000..ff64a958da3ee --- /dev/null +++ b/src/shims/windows/handle.rs @@ -0,0 +1,162 @@ +use rustc_target::abi::HasDataLayout; +use std::mem::variant_count; + +use crate::*; + +/// A Windows `HANDLE` that represents a resource instead of being null or a pseudohandle. +/// +/// This is a seperate type from [`Handle`] to simplify the packing and unpacking code. +#[derive(Clone, Copy)] +enum RealHandle { + Thread(ThreadId), +} + +impl RealHandle { + const USABLE_BITS: u32 = 31; + + const THREAD_DISCRIMINANT: u32 = 1; + + fn discriminant(self) -> u32 { + match self { + // can't use zero here because all zero handle is invalid + Self::Thread(_) => Self::THREAD_DISCRIMINANT, + } + } + + fn data(self) -> u32 { + match self { + Self::Thread(thread) => thread.to_u32(), + } + } + + fn packed_disc_size() -> u32 { + // log2(x) + 1 is how many bits it takes to store x + // because the discriminants start at 1, the variant count is equal to the highest discriminant + variant_count::().ilog2() + 1 + } + + /// This function packs the discriminant and data values into a 31-bit space. + /// None of this layout is guaranteed to applications by Windows or Miri. + /// The sign bit is not used to avoid overlapping any pseudo-handles. + fn to_packed(self) -> i32 { + let disc_size = Self::packed_disc_size(); + let data_size = Self::USABLE_BITS - disc_size; + + let discriminant = self.discriminant(); + let data = self.data(); + + // make sure the discriminant fits into `disc_size` bits + assert!(discriminant < 2u32.pow(disc_size)); + + // make sure the data fits into `data_size` bits + assert!(data < 2u32.pow(data_size)); + + // packs the data into the lower `data_size` bits + // and packs the discriminant right above the data + (discriminant << data_size | data) as i32 + } + + fn new(discriminant: u32, data: u32) -> Option { + match discriminant { + Self::THREAD_DISCRIMINANT => Some(Self::Thread(data.into())), + _ => None, + } + } + + /// see docs for `to_packed` + fn from_packed(handle: i32) -> Option { + let handle_bits = handle as u32; + + let disc_size = Self::packed_disc_size(); + let data_size = Self::USABLE_BITS - disc_size; + + // the lower `data_size` bits of this mask are 1 + let data_mask = 2u32.pow(data_size) - 1; + + // the discriminant is stored right above the lower `data_size` bits + let discriminant = handle_bits >> data_size; + + // the data is stored in the lower `data_size` bits + let data = handle_bits & data_mask; + + Self::new(discriminant, data) + } +} + +/// Miri representation of a Windows `HANDLE` +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +pub enum Handle { + Null, // = 0 + + // pseudo-handles + // The lowest real windows pseudo-handle is -6, so miri pseduo-handles start at -7 to break code hardcoding these values + CurrentThread, // = -7 + + // real handles + Thread(ThreadId), +} + +impl Handle { + const CURRENT_THREAD_VALUE: i32 = -7; + + fn to_packed(self) -> i32 { + match self { + Self::Null => 0, + Self::CurrentThread => Self::CURRENT_THREAD_VALUE, + Self::Thread(thread) => RealHandle::Thread(thread).to_packed(), + } + } + + pub fn to_scalar(self, cx: &impl HasDataLayout) -> Scalar { + // 64-bit handles are sign extended 32-bit handles + // see https://docs.microsoft.com/en-us/windows/win32/winprog64/interprocess-communication + let handle = self.to_packed().into(); + + Scalar::from_machine_isize(handle, cx) + } + + fn from_packed(handle: i64) -> Option { + let current_thread_val = Self::CURRENT_THREAD_VALUE as i64; + + if handle == 0 { + Some(Self::Null) + } else if handle == current_thread_val { + Some(Self::CurrentThread) + } else if let Ok(handle) = handle.try_into() { + match RealHandle::from_packed(handle)? { + RealHandle::Thread(id) => Some(Self::Thread(id)), + } + } else { + // if a handle doesn't fit in an i32, it isn't valid. + None + } + } + + pub fn from_scalar<'tcx>( + handle: Scalar, + cx: &impl HasDataLayout, + ) -> InterpResult<'tcx, Option> { + let handle = handle.to_machine_isize(cx)?; + + Ok(Self::from_packed(handle)) + } +} + +impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} + +#[allow(non_snake_case)] +pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { + fn CloseHandle(&mut self, handle_op: &OpTy<'tcx, Provenance>) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + + match Handle::from_scalar(this.read_scalar(handle_op)?.check_init()?, this)? { + Some(Handle::Thread(thread)) => this.detach_thread(thread)?, + _ => + throw_machine_stop!(TerminationInfo::Abort( + "invalid handle passed to `CloseHandle`".into() + )), + }; + + Ok(()) + } +} diff --git a/src/shims/windows/mod.rs b/src/shims/windows/mod.rs index 668d69966bc4c..40fe71b2dbd02 100644 --- a/src/shims/windows/mod.rs +++ b/src/shims/windows/mod.rs @@ -1,4 +1,6 @@ pub mod dlsym; pub mod foreign_items; +mod handle; mod sync; +mod thread; diff --git a/src/shims/windows/thread.rs b/src/shims/windows/thread.rs new file mode 100644 index 0000000000000..66cd9dd0348fc --- /dev/null +++ b/src/shims/windows/thread.rs @@ -0,0 +1,84 @@ +use std::time::{Duration, Instant}; + +use rustc_middle::ty::layout::LayoutOf; +use rustc_target::spec::abi::Abi; + +use crate::thread::Time; +use crate::*; +use shims::windows::handle::Handle; + +impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} + +#[allow(non_snake_case)] +pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { + fn CreateThread( + &mut self, + security_op: &OpTy<'tcx, Provenance>, + stacksize_op: &OpTy<'tcx, Provenance>, + start_op: &OpTy<'tcx, Provenance>, + arg_op: &OpTy<'tcx, Provenance>, + flags_op: &OpTy<'tcx, Provenance>, + thread_op: &OpTy<'tcx, Provenance>, + ) -> InterpResult<'tcx, ThreadId> { + let this = self.eval_context_mut(); + + if !this.ptr_is_null(this.read_pointer(security_op)?)? { + throw_unsup_format!("non-null `lpThreadAttributes` in `CreateThread`") + } + + // stacksize is ignored, but still needs to be a valid usize + let _ = this.read_scalar(stacksize_op)?.to_machine_usize(this)?; + + let flags = this.read_scalar(flags_op)?.to_u32()?; + + let stack_size_param_is_a_reservation = + this.eval_windows("c", "STACK_SIZE_PARAM_IS_A_RESERVATION")?.to_u32()?; + + if flags != 0 && flags != stack_size_param_is_a_reservation { + throw_unsup_format!("unsupported `dwCreationFlags` {} in `CreateThread`", flags) + } + + let thread = + if this.ptr_is_null(this.read_pointer(thread_op)?)? { None } else { Some(thread_op) }; + + this.start_thread( + thread, + start_op, + Abi::System { unwind: false }, + arg_op, + this.layout_of(this.tcx.types.u32)?, + ) + } + + fn WaitForSingleObject( + &mut self, + handle: &OpTy<'tcx, Provenance>, + timeout: &OpTy<'tcx, Provenance>, + ) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + + let thread = match Handle::from_scalar(this.read_scalar(handle)?.check_init()?, this)? { + Some(Handle::Thread(thread)) => thread, + Some(Handle::CurrentThread) => throw_ub_format!("trying to wait on itself"), + _ => throw_ub_format!("invalid handle"), + }; + + if this.read_scalar(timeout)?.to_u32()? != this.eval_windows("c", "INFINITE")?.to_u32()? { + this.check_no_isolation("`WaitForSingleObject` with non-infinite timeout")?; + } + + let timeout_ms = this.read_scalar(timeout)?.to_u32()?; + + let timeout_time = if timeout_ms == this.eval_windows("c", "INFINITE")?.to_u32()? { + None + } else { + let duration = Duration::from_millis(timeout_ms as u64); + + Some(Time::Monotonic(Instant::now().checked_add(duration).unwrap())) + }; + + this.wait_on_thread(timeout_time, thread)?; + + Ok(()) + } +} diff --git a/src/thread.rs b/src/thread.rs index 6f394fa42fc9c..fa70dcfa2a3de 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -11,6 +11,8 @@ use rustc_data_structures::fx::FxHashMap; use rustc_hir::def_id::DefId; use rustc_index::vec::{Idx, IndexVec}; use rustc_middle::mir::Mutability; +use rustc_middle::ty::layout::TyAndLayout; +use rustc_target::spec::abi::Abi; use crate::concurrency::data_race; use crate::sync::SynchronizationState; @@ -179,7 +181,7 @@ impl<'mir, 'tcx> Thread<'mir, 'tcx> { } /// A specific moment in time. -#[derive(Debug)] +#[derive(Debug, Copy, Clone)] pub enum Time { Monotonic(Instant), RealTime(SystemTime), @@ -238,10 +240,7 @@ impl<'mir, 'tcx> Default for ThreadManager<'mir, 'tcx> { fn default() -> Self { let mut threads = IndexVec::new(); // Create the main thread and add it to the list of threads. - let mut main_thread = Thread::new("main"); - // The main thread can *not* be joined on. - main_thread.join_status = ThreadJoinStatus::Detached; - threads.push(main_thread); + threads.push(Thread::new("main")); Self { active_thread: ThreadId::new(0), threads, @@ -254,6 +253,13 @@ impl<'mir, 'tcx> Default for ThreadManager<'mir, 'tcx> { } impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { + pub(crate) fn init(ecx: &mut MiriEvalContext<'mir, 'tcx>) { + if ecx.tcx.sess.target.os.as_ref() != "windows" { + // The main thread can *not* be joined on except on windows. + ecx.machine.threads.threads[ThreadId::new(0)].join_status = ThreadJoinStatus::Detached; + } + } + /// Check if we have an allocation for the given thread local static for the /// active thread. fn get_thread_local_alloc_id(&self, def_id: DefId) -> Option> { @@ -348,10 +354,23 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { /// Mark the thread as detached, which means that no other thread will try /// to join it and the thread is responsible for cleaning up. - fn detach_thread(&mut self, id: ThreadId) -> InterpResult<'tcx> { - if self.threads[id].join_status != ThreadJoinStatus::Joinable { + /// + /// `allow_terminated_joined` allows detaching joined threads that have already terminated. + /// This matches Windows's behavior for `CloseHandle`. + fn detach_thread(&mut self, id: ThreadId, allow_terminated_joined: bool) -> InterpResult<'tcx> { + trace!("detaching {:?}", id); + + let is_ub = if allow_terminated_joined && self.threads[id].state == ThreadState::Terminated + { + self.threads[id].join_status == ThreadJoinStatus::Detached + } else { + self.threads[id].join_status != ThreadJoinStatus::Joinable + }; + + if is_ub { throw_ub_format!("trying to detach thread that was already detached or joined"); } + self.threads[id].join_status = ThreadJoinStatus::Detached; Ok(()) } @@ -362,18 +381,10 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { joined_thread_id: ThreadId, data_race: Option<&mut data_race::GlobalState>, ) -> InterpResult<'tcx> { - if self.threads[joined_thread_id].join_status != ThreadJoinStatus::Joinable { - throw_ub_format!("trying to join a detached or already joined thread"); - } - if joined_thread_id == self.active_thread { - throw_ub_format!("trying to join itself"); + if self.threads[joined_thread_id].join_status == ThreadJoinStatus::Detached { + throw_ub_format!("trying to join a detached thread"); } - assert!( - self.threads - .iter() - .all(|thread| thread.state != ThreadState::BlockedOnJoin(joined_thread_id)), - "a joinable thread already has threads waiting for its termination" - ); + // Mark the joined thread as being joined so that we detect if other // threads try to join it. self.threads[joined_thread_id].join_status = ThreadJoinStatus::Joined; @@ -624,9 +635,62 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } #[inline] - fn detach_thread(&mut self, thread_id: ThreadId) -> InterpResult<'tcx> { + fn start_thread( + &mut self, + thread: Option>, + start_routine: Pointer>, + start_abi: Abi, + func_arg: ImmTy<'tcx, Provenance>, + ret_layout: TyAndLayout<'tcx>, + ) -> InterpResult<'tcx, ThreadId> { + let this = self.eval_context_mut(); + + // Create the new thread + let new_thread_id = this.create_thread(); + + // Write the current thread-id, switch to the next thread later + // to treat this write operation as occuring on the current thread. + if let Some(thread_info_place) = thread { + this.write_scalar( + Scalar::from_uint(new_thread_id.to_u32(), thread_info_place.layout.size), + &thread_info_place.into(), + )?; + } + + // Finally switch to new thread so that we can push the first stackframe. + // After this all accesses will be treated as occuring in the new thread. + let old_thread_id = this.set_active_thread(new_thread_id); + + // Perform the function pointer load in the new thread frame. + let instance = this.get_ptr_fn(start_routine)?.as_instance()?; + + // Note: the returned value is currently ignored (see the FIXME in + // pthread_join in shims/unix/thread.rs) because the Rust standard library does not use + // it. + let ret_place = this.allocate(ret_layout, MiriMemoryKind::Machine.into())?; + + this.call_function( + instance, + start_abi, + &[*func_arg], + Some(&ret_place.into()), + StackPopCleanup::Root { cleanup: true }, + )?; + + // Restore the old active thread frame. + this.set_active_thread(old_thread_id); + + Ok(new_thread_id) + } + + #[inline] + fn detach_thread( + &mut self, + thread_id: ThreadId, + allow_terminated_joined: bool, + ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - this.machine.threads.detach_thread(thread_id) + this.machine.threads.detach_thread(thread_id, allow_terminated_joined) } #[inline] @@ -704,6 +768,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.machine.threads.set_thread_name(thread, new_thread_name); } + #[inline] + fn set_thread_name_wide(&mut self, thread: ThreadId, new_thread_name: Vec) { + let this = self.eval_context_mut(); + this.machine.threads.set_thread_name( + thread, + new_thread_name.into_iter().flat_map(u16::to_ne_bytes).collect(), + ); + } + #[inline] fn get_thread_name<'c>(&'c self, thread: ThreadId) -> &'c [u8] where diff --git a/tests/fail/concurrency/too_few_args.rs b/tests/fail/concurrency/libc_pthread_create_too_few_args.rs similarity index 92% rename from tests/fail/concurrency/too_few_args.rs rename to tests/fail/concurrency/libc_pthread_create_too_few_args.rs index 43c7c74d410f5..e1d3704af7c0b 100644 --- a/tests/fail/concurrency/too_few_args.rs +++ b/tests/fail/concurrency/libc_pthread_create_too_few_args.rs @@ -1,4 +1,4 @@ -//@ignore-target-windows: Concurrency on Windows is not supported yet. +//@ignore-target-windows: No libc on Windows //! The thread function must have exactly one argument. diff --git a/tests/fail/concurrency/too_few_args.stderr b/tests/fail/concurrency/libc_pthread_create_too_few_args.stderr similarity index 92% rename from tests/fail/concurrency/too_few_args.stderr rename to tests/fail/concurrency/libc_pthread_create_too_few_args.stderr index c1eb4d8cb6b6e..2304b42b2c786 100644 --- a/tests/fail/concurrency/too_few_args.stderr +++ b/tests/fail/concurrency/libc_pthread_create_too_few_args.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: callee has fewer arguments than expected - --> $DIR/too_few_args.rs:LL:CC + --> $DIR/libc_pthread_create_too_few_args.rs:LL:CC | LL | panic!() | ^^^^^^^^ callee has fewer arguments than expected diff --git a/tests/fail/concurrency/too_many_args.rs b/tests/fail/concurrency/libc_pthread_create_too_many_args.rs similarity index 92% rename from tests/fail/concurrency/too_many_args.rs rename to tests/fail/concurrency/libc_pthread_create_too_many_args.rs index d660037ca6695..7408634db528f 100644 --- a/tests/fail/concurrency/too_many_args.rs +++ b/tests/fail/concurrency/libc_pthread_create_too_many_args.rs @@ -1,4 +1,4 @@ -//@ignore-target-windows: Concurrency on Windows is not supported yet. +//@ignore-target-windows: No libc on Windows //! The thread function must have exactly one argument. diff --git a/tests/fail/concurrency/too_many_args.stderr b/tests/fail/concurrency/libc_pthread_create_too_many_args.stderr similarity index 92% rename from tests/fail/concurrency/too_many_args.stderr rename to tests/fail/concurrency/libc_pthread_create_too_many_args.stderr index 42a96ae626367..49c7f579970f2 100644 --- a/tests/fail/concurrency/too_many_args.stderr +++ b/tests/fail/concurrency/libc_pthread_create_too_many_args.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: callee has more arguments than expected - --> $DIR/too_many_args.rs:LL:CC + --> $DIR/libc_pthread_create_too_many_args.rs:LL:CC | LL | panic!() | ^^^^^^^^ callee has more arguments than expected diff --git a/tests/fail/concurrency/libc_pthread_join_detached.rs b/tests/fail/concurrency/libc_pthread_join_detached.rs index 488b14bbcfa85..0b810dc8c7212 100644 --- a/tests/fail/concurrency/libc_pthread_join_detached.rs +++ b/tests/fail/concurrency/libc_pthread_join_detached.rs @@ -15,6 +15,6 @@ fn main() { // assert_eq!(libc::pthread_attr_init(&mut attr), 0); FIXME: this function is not yet implemented. assert_eq!(libc::pthread_create(&mut native, &attr, thread_start, ptr::null_mut()), 0); assert_eq!(libc::pthread_detach(native), 0); - assert_eq!(libc::pthread_join(native, ptr::null_mut()), 0); //~ ERROR: Undefined Behavior: trying to join a detached or already joined thread + assert_eq!(libc::pthread_join(native, ptr::null_mut()), 0); //~ ERROR: Undefined Behavior: trying to join a detached thread } } diff --git a/tests/fail/concurrency/libc_pthread_join_detached.stderr b/tests/fail/concurrency/libc_pthread_join_detached.stderr index be9781ff46ea1..e381a71b25204 100644 --- a/tests/fail/concurrency/libc_pthread_join_detached.stderr +++ b/tests/fail/concurrency/libc_pthread_join_detached.stderr @@ -2,7 +2,7 @@ error: Undefined Behavior: trying to join a detached or already joined thread --> $DIR/libc_pthread_join_detached.rs:LL:CC | LL | ... assert_eq!(libc::pthread_join(native, ptr::null_mut()), 0); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trying to join a detached or already joined thread + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trying to join a detached thread | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/concurrency/thread-spawn.rs b/tests/fail/concurrency/thread-spawn.rs deleted file mode 100644 index 84848e35a0f3e..0000000000000 --- a/tests/fail/concurrency/thread-spawn.rs +++ /dev/null @@ -1,9 +0,0 @@ -//@only-target-windows: Only Windows is not supported. - -use std::thread; - -//@error-pattern: can't create threads on Windows - -fn main() { - thread::spawn(|| {}); -} diff --git a/tests/fail/concurrency/thread-spawn.stderr b/tests/fail/concurrency/thread-spawn.stderr deleted file mode 100644 index 2e4b3a045e691..0000000000000 --- a/tests/fail/concurrency/thread-spawn.stderr +++ /dev/null @@ -1,30 +0,0 @@ -error: unsupported operation: can't create threads on Windows - --> RUSTLIB/std/src/sys/PLATFORM/thread.rs:LL:CC - | -LL | let ret = c::CreateThread( - | ___________________^ -LL | | ptr::null_mut(), -LL | | stack, -LL | | thread_start, -... | -LL | | ptr::null_mut(), -LL | | ); - | |_________^ can't create threads on Windows - | - = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support - = note: backtrace: - = note: inside `std::sys::PLATFORM::thread::Thread::new` at RUSTLIB/std/src/sys/PLATFORM/thread.rs:LL:CC - = note: inside `std::thread::Builder::spawn_unchecked_::<[closure@$DIR/thread-spawn.rs:LL:CC], ()>` at RUSTLIB/std/src/thread/mod.rs:LL:CC - = note: inside `std::thread::Builder::spawn_unchecked::<[closure@$DIR/thread-spawn.rs:LL:CC], ()>` at RUSTLIB/std/src/thread/mod.rs:LL:CC - = note: inside `std::thread::Builder::spawn::<[closure@$DIR/thread-spawn.rs:LL:CC], ()>` at RUSTLIB/std/src/thread/mod.rs:LL:CC - = note: inside `std::thread::spawn::<[closure@$DIR/thread-spawn.rs:LL:CC], ()>` at RUSTLIB/std/src/thread/mod.rs:LL:CC -note: inside `main` at $DIR/thread-spawn.rs:LL:CC - --> $DIR/thread-spawn.rs:LL:CC - | -LL | thread::spawn(|| {}); - | ^^^^^^^^^^^^^^^^^^^^ - -note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace - -error: aborting due to previous error - diff --git a/tests/fail/concurrency/thread_local_static_dealloc.rs b/tests/fail/concurrency/thread_local_static_dealloc.rs index 7c54e3bca7c11..d89c670b632e6 100644 --- a/tests/fail/concurrency/thread_local_static_dealloc.rs +++ b/tests/fail/concurrency/thread_local_static_dealloc.rs @@ -1,5 +1,3 @@ -//@ignore-target-windows: Concurrency on Windows is not supported yet. - //! Ensure that thread-local statics get deallocated when the thread dies. #![feature(thread_local)] diff --git a/tests/fail/concurrency/unwind_top_of_stack.rs b/tests/fail/concurrency/unwind_top_of_stack.rs index c2b9d56e19c92..61d3b964e620b 100644 --- a/tests/fail/concurrency/unwind_top_of_stack.rs +++ b/tests/fail/concurrency/unwind_top_of_stack.rs @@ -1,4 +1,5 @@ -//@ignore-target-windows: Concurrency on Windows is not supported yet. +//@ignore-windows: No libc on Windows + //@compile-flags: -Zmiri-disable-abi-check //! Unwinding past the top frame of a stack is Undefined Behavior. diff --git a/tests/fail/data_race/alloc_read_race.rs b/tests/fail/data_race/alloc_read_race.rs index f3f63aeb2b836..0bd3068af1ffe 100644 --- a/tests/fail/data_race/alloc_read_race.rs +++ b/tests/fail/data_race/alloc_read_race.rs @@ -1,4 +1,3 @@ -//@ignore-target-windows: Concurrency on Windows is not supported yet. //@compile-flags: -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 #![feature(new_uninit)] diff --git a/tests/fail/data_race/alloc_write_race.rs b/tests/fail/data_race/alloc_write_race.rs index a2738c3879b33..7991280721e29 100644 --- a/tests/fail/data_race/alloc_write_race.rs +++ b/tests/fail/data_race/alloc_write_race.rs @@ -1,4 +1,3 @@ -//@ignore-target-windows: Concurrency on Windows is not supported yet. //@compile-flags: -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 #![feature(new_uninit)] diff --git a/tests/fail/data_race/atomic_read_na_write_race1.rs b/tests/fail/data_race/atomic_read_na_write_race1.rs index 30900a85d003f..2b0446d724a02 100644 --- a/tests/fail/data_race/atomic_read_na_write_race1.rs +++ b/tests/fail/data_race/atomic_read_na_write_race1.rs @@ -1,6 +1,5 @@ // We want to control preemption here. //@compile-flags: -Zmiri-preemption-rate=0 -//@ignore-target-windows: Concurrency on Windows is not supported yet. use std::sync::atomic::{AtomicUsize, Ordering}; use std::thread::spawn; diff --git a/tests/fail/data_race/atomic_read_na_write_race2.rs b/tests/fail/data_race/atomic_read_na_write_race2.rs index 493985f6cf17b..ef5157515c64a 100644 --- a/tests/fail/data_race/atomic_read_na_write_race2.rs +++ b/tests/fail/data_race/atomic_read_na_write_race2.rs @@ -1,6 +1,5 @@ // We want to control preemption here. //@compile-flags: -Zmiri-preemption-rate=0 -//@ignore-target-windows: Concurrency on Windows is not supported yet. use std::sync::atomic::AtomicUsize; use std::sync::atomic::Ordering; diff --git a/tests/fail/data_race/atomic_write_na_read_race1.rs b/tests/fail/data_race/atomic_write_na_read_race1.rs index ca9c28abf1a90..8c17e76748438 100644 --- a/tests/fail/data_race/atomic_write_na_read_race1.rs +++ b/tests/fail/data_race/atomic_write_na_read_race1.rs @@ -1,6 +1,5 @@ // We want to control preemption here. //@compile-flags: -Zmiri-preemption-rate=0 -//@ignore-target-windows: Concurrency on Windows is not supported yet. use std::sync::atomic::AtomicUsize; use std::sync::atomic::Ordering; diff --git a/tests/fail/data_race/atomic_write_na_read_race2.rs b/tests/fail/data_race/atomic_write_na_read_race2.rs index 1a79dde0b08ac..f14d7c704dbb1 100644 --- a/tests/fail/data_race/atomic_write_na_read_race2.rs +++ b/tests/fail/data_race/atomic_write_na_read_race2.rs @@ -1,6 +1,5 @@ // We want to control preemption here. //@compile-flags: -Zmiri-preemption-rate=0 -//@ignore-target-windows: Concurrency on Windows is not supported yet. use std::sync::atomic::{AtomicUsize, Ordering}; use std::thread::spawn; diff --git a/tests/fail/data_race/atomic_write_na_write_race1.rs b/tests/fail/data_race/atomic_write_na_write_race1.rs index 04015c2d14205..0804b33407580 100644 --- a/tests/fail/data_race/atomic_write_na_write_race1.rs +++ b/tests/fail/data_race/atomic_write_na_write_race1.rs @@ -1,6 +1,5 @@ // We want to control preemption here. //@compile-flags: -Zmiri-preemption-rate=0 -//@ignore-target-windows: Concurrency on Windows is not supported yet. use std::sync::atomic::{AtomicUsize, Ordering}; use std::thread::spawn; diff --git a/tests/fail/data_race/atomic_write_na_write_race2.rs b/tests/fail/data_race/atomic_write_na_write_race2.rs index 1d242ff3cdd6f..658cddcc9c5b6 100644 --- a/tests/fail/data_race/atomic_write_na_write_race2.rs +++ b/tests/fail/data_race/atomic_write_na_write_race2.rs @@ -1,6 +1,5 @@ // We want to control preemption here. //@compile-flags: -Zmiri-preemption-rate=0 -//@ignore-target-windows: Concurrency on Windows is not supported yet. use std::sync::atomic::AtomicUsize; use std::sync::atomic::Ordering; diff --git a/tests/fail/data_race/dangling_thread_async_race.rs b/tests/fail/data_race/dangling_thread_async_race.rs index 6264255265f68..af2588e923240 100644 --- a/tests/fail/data_race/dangling_thread_async_race.rs +++ b/tests/fail/data_race/dangling_thread_async_race.rs @@ -1,6 +1,5 @@ // We want to control preemption here. //@compile-flags: -Zmiri-disable-isolation -Zmiri-preemption-rate=0 -//@ignore-target-windows: Concurrency on Windows is not supported yet. use std::mem; use std::thread::{sleep, spawn}; diff --git a/tests/fail/data_race/dangling_thread_race.rs b/tests/fail/data_race/dangling_thread_race.rs index 6f44fc69dbb77..1ee619c3f99d5 100644 --- a/tests/fail/data_race/dangling_thread_race.rs +++ b/tests/fail/data_race/dangling_thread_race.rs @@ -1,6 +1,5 @@ // We want to control preemption here. //@compile-flags: -Zmiri-disable-isolation -Zmiri-preemption-rate=0 -//@ignore-target-windows: Concurrency on Windows is not supported yet. use std::mem; use std::thread::{sleep, spawn}; diff --git a/tests/fail/data_race/dealloc_read_race1.rs b/tests/fail/data_race/dealloc_read_race1.rs index 5349073ec3b78..cbc02549a2541 100644 --- a/tests/fail/data_race/dealloc_read_race1.rs +++ b/tests/fail/data_race/dealloc_read_race1.rs @@ -1,6 +1,5 @@ // We want to control preemption here. //@compile-flags: -Zmiri-preemption-rate=0 -//@ignore-target-windows: Concurrency on Windows is not supported yet. use std::thread::spawn; diff --git a/tests/fail/data_race/dealloc_read_race2.rs b/tests/fail/data_race/dealloc_read_race2.rs index bb9070ef7503c..24cce5d6fac1c 100644 --- a/tests/fail/data_race/dealloc_read_race2.rs +++ b/tests/fail/data_race/dealloc_read_race2.rs @@ -1,6 +1,5 @@ // We want to control preemption here. //@compile-flags: -Zmiri-preemption-rate=0 -//@ignore-target-windows: Concurrency on Windows is not supported yet. use std::thread::spawn; diff --git a/tests/fail/data_race/dealloc_read_race_stack.rs b/tests/fail/data_race/dealloc_read_race_stack.rs index e114fbb8b4f11..5484370f35c17 100644 --- a/tests/fail/data_race/dealloc_read_race_stack.rs +++ b/tests/fail/data_race/dealloc_read_race_stack.rs @@ -1,4 +1,3 @@ -//@ignore-target-windows: Concurrency on Windows is not supported yet. //@compile-flags: -Zmiri-disable-isolation -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 use std::ptr::null_mut; diff --git a/tests/fail/data_race/dealloc_write_race1.rs b/tests/fail/data_race/dealloc_write_race1.rs index 35949920e102e..23bf73fe8c5ad 100644 --- a/tests/fail/data_race/dealloc_write_race1.rs +++ b/tests/fail/data_race/dealloc_write_race1.rs @@ -1,6 +1,5 @@ // We want to control preemption here. //@compile-flags: -Zmiri-preemption-rate=0 -//@ignore-target-windows: Concurrency on Windows is not supported yet. use std::thread::spawn; diff --git a/tests/fail/data_race/dealloc_write_race2.rs b/tests/fail/data_race/dealloc_write_race2.rs index b569086c8c34e..7c8033e2335e9 100644 --- a/tests/fail/data_race/dealloc_write_race2.rs +++ b/tests/fail/data_race/dealloc_write_race2.rs @@ -1,6 +1,5 @@ // We want to control preemption here. //@compile-flags: -Zmiri-preemption-rate=0 -//@ignore-target-windows: Concurrency on Windows is not supported yet. use std::thread::spawn; diff --git a/tests/fail/data_race/dealloc_write_race_stack.rs b/tests/fail/data_race/dealloc_write_race_stack.rs index 0c74c7adf59cb..1872abfe021b3 100644 --- a/tests/fail/data_race/dealloc_write_race_stack.rs +++ b/tests/fail/data_race/dealloc_write_race_stack.rs @@ -1,4 +1,3 @@ -//@ignore-target-windows: Concurrency on Windows is not supported yet. //@compile-flags: -Zmiri-disable-isolation -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 use std::ptr::null_mut; diff --git a/tests/fail/data_race/enable_after_join_to_main.rs b/tests/fail/data_race/enable_after_join_to_main.rs index f2235b95257b3..c11239da7febb 100644 --- a/tests/fail/data_race/enable_after_join_to_main.rs +++ b/tests/fail/data_race/enable_after_join_to_main.rs @@ -1,6 +1,5 @@ // We want to control preemption here. //@compile-flags: -Zmiri-preemption-rate=0 -//@ignore-target-windows: Concurrency on Windows is not supported yet. use std::thread::spawn; diff --git a/tests/fail/data_race/fence_after_load.rs b/tests/fail/data_race/fence_after_load.rs index 8acbe12e82d62..ae443908598fe 100644 --- a/tests/fail/data_race/fence_after_load.rs +++ b/tests/fail/data_race/fence_after_load.rs @@ -1,6 +1,5 @@ // We want to control preemption here. //@compile-flags: -Zmiri-disable-isolation -Zmiri-preemption-rate=0 -//@ignore-target-windows: Concurrency on Windows is not supported yet. use std::sync::atomic::{fence, AtomicUsize, Ordering}; use std::sync::Arc; use std::thread; diff --git a/tests/fail/data_race/read_write_race.rs b/tests/fail/data_race/read_write_race.rs index cff868fb699fe..482dd2df7df91 100644 --- a/tests/fail/data_race/read_write_race.rs +++ b/tests/fail/data_race/read_write_race.rs @@ -1,6 +1,5 @@ // We want to control preemption here. //@compile-flags: -Zmiri-preemption-rate=0 -//@ignore-target-windows: Concurrency on Windows is not supported yet. use std::thread::spawn; diff --git a/tests/fail/data_race/read_write_race_stack.rs b/tests/fail/data_race/read_write_race_stack.rs index b22173fa5a94a..1b4932439b010 100644 --- a/tests/fail/data_race/read_write_race_stack.rs +++ b/tests/fail/data_race/read_write_race_stack.rs @@ -1,4 +1,3 @@ -//@ignore-target-windows: Concurrency on Windows is not supported yet. //@compile-flags: -Zmiri-disable-isolation -Zmir-opt-level=0 -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 // Note: mir-opt-level set to 0 to prevent the read of stack_var in thread 1 diff --git a/tests/fail/data_race/relax_acquire_race.rs b/tests/fail/data_race/relax_acquire_race.rs index b99388b8923c0..240b4c90eb225 100644 --- a/tests/fail/data_race/relax_acquire_race.rs +++ b/tests/fail/data_race/relax_acquire_race.rs @@ -1,4 +1,3 @@ -//@ignore-target-windows: Concurrency on Windows is not supported yet. //@compile-flags: -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 use std::sync::atomic::{AtomicUsize, Ordering}; diff --git a/tests/fail/data_race/release_seq_race.rs b/tests/fail/data_race/release_seq_race.rs index 31fc5d9a479f3..5ae801278357b 100644 --- a/tests/fail/data_race/release_seq_race.rs +++ b/tests/fail/data_race/release_seq_race.rs @@ -1,4 +1,3 @@ -//@ignore-target-windows: Concurrency on Windows is not supported yet. //@compile-flags: -Zmiri-disable-isolation -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 use std::sync::atomic::{AtomicUsize, Ordering}; diff --git a/tests/fail/data_race/release_seq_race_same_thread.rs b/tests/fail/data_race/release_seq_race_same_thread.rs index c0ce437047a8a..63e6dc2dd71b9 100644 --- a/tests/fail/data_race/release_seq_race_same_thread.rs +++ b/tests/fail/data_race/release_seq_race_same_thread.rs @@ -1,4 +1,3 @@ -//@ignore-target-windows: Concurrency on Windows is not supported yet. //@compile-flags: -Zmiri-disable-isolation -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 use std::sync::atomic::{AtomicUsize, Ordering}; diff --git a/tests/fail/data_race/rmw_race.rs b/tests/fail/data_race/rmw_race.rs index 540b01b0935d3..122780d11aa1f 100644 --- a/tests/fail/data_race/rmw_race.rs +++ b/tests/fail/data_race/rmw_race.rs @@ -1,4 +1,3 @@ -//@ignore-target-windows: Concurrency on Windows is not supported yet. //@compile-flags: -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 use std::sync::atomic::{AtomicUsize, Ordering}; diff --git a/tests/fail/data_race/write_write_race.rs b/tests/fail/data_race/write_write_race.rs index ac75c771e4751..13c31c87cbbae 100644 --- a/tests/fail/data_race/write_write_race.rs +++ b/tests/fail/data_race/write_write_race.rs @@ -1,6 +1,5 @@ // We want to control preemption here. //@compile-flags: -Zmiri-preemption-rate=0 -//@ignore-target-windows: Concurrency on Windows is not supported yet. use std::thread::spawn; diff --git a/tests/fail/data_race/write_write_race_stack.rs b/tests/fail/data_race/write_write_race_stack.rs index 5193b155512c1..731ac8b26aa74 100644 --- a/tests/fail/data_race/write_write_race_stack.rs +++ b/tests/fail/data_race/write_write_race_stack.rs @@ -1,4 +1,3 @@ -//@ignore-target-windows: Concurrency on Windows is not supported yet. //@compile-flags: -Zmiri-disable-isolation -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 use std::ptr::null_mut; diff --git a/tests/fail/should-pass/cpp20_rwc_syncs.rs b/tests/fail/should-pass/cpp20_rwc_syncs.rs index 6a7622671b59d..545875a582a46 100644 --- a/tests/fail/should-pass/cpp20_rwc_syncs.rs +++ b/tests/fail/should-pass/cpp20_rwc_syncs.rs @@ -1,4 +1,3 @@ -//@ignore-target-windows: Concurrency on Windows is not supported yet. //@compile-flags: -Zmiri-ignore-leaks // https://plv.mpi-sws.org/scfix/paper.pdf diff --git a/tests/fail/weak_memory/racing_mixed_size.rs b/tests/fail/weak_memory/racing_mixed_size.rs index 95a10510713cc..7bbb7f9fe7c2a 100644 --- a/tests/fail/weak_memory/racing_mixed_size.rs +++ b/tests/fail/weak_memory/racing_mixed_size.rs @@ -1,6 +1,5 @@ // We want to control preemption here. //@compile-flags: -Zmiri-preemption-rate=0 -//@ignore-target-windows: Concurrency on Windows is not supported yet. #![feature(core_intrinsics)] diff --git a/tests/fail/weak_memory/racing_mixed_size_read.rs b/tests/fail/weak_memory/racing_mixed_size_read.rs index 1c0b1c2be8fda..73178980b7e5a 100644 --- a/tests/fail/weak_memory/racing_mixed_size_read.rs +++ b/tests/fail/weak_memory/racing_mixed_size_read.rs @@ -1,6 +1,5 @@ // We want to control preemption here. //@compile-flags: -Zmiri-preemption-rate=0 -//@ignore-target-windows: Concurrency on Windows is not supported yet. use std::sync::atomic::Ordering::*; use std::sync::atomic::{AtomicU16, AtomicU32}; diff --git a/tests/pass/0weak_memory_consistency.rs b/tests/pass/0weak_memory_consistency.rs index b5b6b83cce1bb..8c650bca2f36b 100644 --- a/tests/pass/0weak_memory_consistency.rs +++ b/tests/pass/0weak_memory_consistency.rs @@ -1,4 +1,3 @@ -//@ignore-target-windows: Concurrency on Windows is not supported yet. //@compile-flags: -Zmiri-ignore-leaks -Zmiri-disable-stacked-borrows // The following tests check whether our weak memory emulation produces diff --git a/tests/pass/concurrency/channels.rs b/tests/pass/concurrency/channels.rs index 40d729f042d19..c75c5199bf11d 100644 --- a/tests/pass/concurrency/channels.rs +++ b/tests/pass/concurrency/channels.rs @@ -1,4 +1,4 @@ -//@ignore-target-windows: Concurrency on Windows is not supported yet. +//@ignore-target-windows: Channels on Windows are not supported yet. //@compile-flags: -Zmiri-strict-provenance use std::sync::mpsc::{channel, sync_channel}; diff --git a/tests/pass/concurrency/concurrent_caller_location.rs b/tests/pass/concurrency/concurrent_caller_location.rs index a07f6b13e6d79..0490330a15d8b 100644 --- a/tests/pass/concurrency/concurrent_caller_location.rs +++ b/tests/pass/concurrency/concurrent_caller_location.rs @@ -1,5 +1,3 @@ -//@ignore-target-windows: Concurrency on Windows is not supported yet. - use std::panic::Location; use std::thread::spawn; diff --git a/tests/pass/concurrency/data_race.rs b/tests/pass/concurrency/data_race.rs index 9c7030db3db8b..4e3c99058a0df 100644 --- a/tests/pass/concurrency/data_race.rs +++ b/tests/pass/concurrency/data_race.rs @@ -1,4 +1,3 @@ -//@ignore-target-windows: Concurrency on Windows is not supported yet. //@compile-flags: -Zmiri-disable-weak-memory-emulation -Zmiri-preemption-rate=0 use std::sync::atomic::{fence, AtomicUsize, Ordering}; diff --git a/tests/pass/concurrency/disable_data_race_detector.rs b/tests/pass/concurrency/disable_data_race_detector.rs index a4852b4674e81..d71e51b038429 100644 --- a/tests/pass/concurrency/disable_data_race_detector.rs +++ b/tests/pass/concurrency/disable_data_race_detector.rs @@ -1,4 +1,3 @@ -//@ignore-target-windows: Concurrency on Windows is not supported yet. //@compile-flags: -Zmiri-disable-data-race-detector use std::thread::spawn; diff --git a/tests/pass/concurrency/issue1643.rs b/tests/pass/concurrency/issue1643.rs index f4fe43d88cb1e..c0956569ad8f9 100644 --- a/tests/pass/concurrency/issue1643.rs +++ b/tests/pass/concurrency/issue1643.rs @@ -1,5 +1,3 @@ -//@ignore-target-windows: Concurrency on Windows is not supported yet. - use std::thread::spawn; fn initialize() { diff --git a/tests/pass/concurrency/simple.rs b/tests/pass/concurrency/simple.rs index 1d85c7fc9bd08..556e0a24769d7 100644 --- a/tests/pass/concurrency/simple.rs +++ b/tests/pass/concurrency/simple.rs @@ -1,4 +1,3 @@ -//@ignore-target-windows: Concurrency on Windows is not supported yet. //@compile-flags: -Zmiri-strict-provenance use std::thread; diff --git a/tests/pass/concurrency/spin_loop.rs b/tests/pass/concurrency/spin_loop.rs index 5f34168dbb1e9..019bd44f16488 100644 --- a/tests/pass/concurrency/spin_loop.rs +++ b/tests/pass/concurrency/spin_loop.rs @@ -1,4 +1,3 @@ -//@ignore-target-windows: Concurrency on Windows is not supported yet. use std::sync::atomic::{AtomicUsize, Ordering}; use std::thread; diff --git a/tests/pass/concurrency/spin_loops_nopreempt.rs b/tests/pass/concurrency/spin_loops_nopreempt.rs index 34be0dd39481f..5d8e2ef5f0282 100644 --- a/tests/pass/concurrency/spin_loops_nopreempt.rs +++ b/tests/pass/concurrency/spin_loops_nopreempt.rs @@ -1,4 +1,4 @@ -//@ignore-target-windows: Concurrency on Windows is not supported yet. +//@ignore-target-windows: Channels on Windows are not supported yet. // This specifically tests behavior *without* preemption. //@compile-flags: -Zmiri-preemption-rate=0 diff --git a/tests/pass/concurrency/thread_locals.rs b/tests/pass/concurrency/thread_locals.rs index 34431def33f81..b19e56312f304 100644 --- a/tests/pass/concurrency/thread_locals.rs +++ b/tests/pass/concurrency/thread_locals.rs @@ -1,4 +1,3 @@ -//@ignore-target-windows: Concurrency on Windows is not supported yet. //@compile-flags: -Zmiri-strict-provenance //! The main purpose of this test is to check that if we take a pointer to diff --git a/tests/pass/concurrency/tls_lib_drop.rs b/tests/pass/concurrency/tls_lib_drop.rs index 6c66cd3a62fb5..8ce011ede34e0 100644 --- a/tests/pass/concurrency/tls_lib_drop.rs +++ b/tests/pass/concurrency/tls_lib_drop.rs @@ -1,5 +1,3 @@ -//@ignore-target-windows: Concurrency on Windows is not supported yet. - use std::cell::RefCell; use std::thread; diff --git a/tests/pass/panic/concurrent-panic.rs b/tests/pass/panic/concurrent-panic.rs index 1acae69b8d3b3..342269c6acbe3 100644 --- a/tests/pass/panic/concurrent-panic.rs +++ b/tests/pass/panic/concurrent-panic.rs @@ -1,4 +1,4 @@ -//@ignore-target-windows: Concurrency on Windows is not supported yet. +//@ignore-target-windows: Condvars on Windows are not supported yet. // We are making scheduler assumptions here. //@compile-flags: -Zmiri-preemption-rate=0 diff --git a/tests/pass/shims/time.rs b/tests/pass/shims/time.rs index e1094006fb1fa..23b5ab57efa02 100644 --- a/tests/pass/shims/time.rs +++ b/tests/pass/shims/time.rs @@ -8,8 +8,6 @@ fn duration_sanity(diff: Duration) { assert!(diff.as_millis() < 500); } -// Sleeping on Windows is not supported yet. -#[cfg(unix)] fn test_sleep() { let before = Instant::now(); std::thread::sleep(Duration::from_millis(100)); @@ -50,6 +48,5 @@ fn main() { assert_eq!(now2 - diff, now1); duration_sanity(diff); - #[cfg(unix)] test_sleep(); } diff --git a/tests/pass/threadleak_ignored.rs b/tests/pass/threadleak_ignored.rs index 077d8d0837538..99bac7aa42a80 100644 --- a/tests/pass/threadleak_ignored.rs +++ b/tests/pass/threadleak_ignored.rs @@ -1,4 +1,4 @@ -//@ignore-target-windows: Concurrency on Windows is not supported yet. +//@ignore-target-windows: Channels on Windows are not supported yet. // FIXME: disallow preemption to work around https://github.com/rust-lang/rust/issues/55005 //@compile-flags: -Zmiri-ignore-leaks -Zmiri-preemption-rate=0 diff --git a/tests/pass/weak_memory/extra_cpp.rs b/tests/pass/weak_memory/extra_cpp.rs index d98fba26ffa80..07cbb4a803f1f 100644 --- a/tests/pass/weak_memory/extra_cpp.rs +++ b/tests/pass/weak_memory/extra_cpp.rs @@ -1,4 +1,3 @@ -//@ignore-target-windows: Concurrency on Windows is not supported yet. //@compile-flags: -Zmiri-ignore-leaks // Tests operations not perfomable through C++'s atomic API diff --git a/tests/pass/weak_memory/extra_cpp_unsafe.rs b/tests/pass/weak_memory/extra_cpp_unsafe.rs index f5c6021a4a85b..f7e2748408ff8 100644 --- a/tests/pass/weak_memory/extra_cpp_unsafe.rs +++ b/tests/pass/weak_memory/extra_cpp_unsafe.rs @@ -1,4 +1,3 @@ -//@ignore-target-windows: Concurrency on Windows is not supported yet. //@compile-flags: -Zmiri-ignore-leaks // Tests operations not perfomable through C++'s atomic API diff --git a/tests/pass/weak_memory/weak.rs b/tests/pass/weak_memory/weak.rs index dc7982991b693..4c3be6b3559ae 100644 --- a/tests/pass/weak_memory/weak.rs +++ b/tests/pass/weak_memory/weak.rs @@ -1,4 +1,3 @@ -//@ignore-target-windows: Concurrency on Windows is not supported yet. //@compile-flags: -Zmiri-ignore-leaks -Zmiri-preemption-rate=0 // Tests showing weak memory behaviours are exhibited. All tests From 08ffbb8d8ad5a65825a458982981222bccf951b7 Mon Sep 17 00:00:00 2001 From: DrMeepster <19316085+DrMeepster@users.noreply.github.com> Date: Fri, 15 Jul 2022 01:40:06 -0700 Subject: [PATCH 3655/3747] fix windows join/detach and add tests --- src/machine.rs | 1 + src/shims/time.rs | 26 ++++++++++++ src/shims/unix/thread.rs | 4 +- src/shims/windows/dlsym.rs | 4 +- src/shims/windows/foreign_items.rs | 19 +-------- src/shims/windows/handle.rs | 15 ++++--- src/shims/windows/thread.rs | 25 ++++------- src/thread.rs | 34 +++++++++++++++ tests/fail/concurrency/unwind_top_of_stack.rs | 2 +- .../fail/concurrency/windows_join_detached.rs | 21 ++++++++++ .../concurrency/windows_join_detached.stderr | 22 ++++++++++ tests/fail/concurrency/windows_join_main.rs | 28 +++++++++++++ .../fail/concurrency/windows_join_main.stderr | 12 ++++++ tests/fail/concurrency/windows_join_self.rs | 25 +++++++++++ .../fail/concurrency/windows_join_self.stderr | 12 ++++++ .../concurrency/windows_detach_terminated.rs | 21 ++++++++++ .../pass/concurrency/windows_join_multiple.rs | 41 +++++++++++++++++++ 17 files changed, 265 insertions(+), 47 deletions(-) create mode 100644 tests/fail/concurrency/windows_join_detached.rs create mode 100644 tests/fail/concurrency/windows_join_detached.stderr create mode 100644 tests/fail/concurrency/windows_join_main.rs create mode 100644 tests/fail/concurrency/windows_join_main.stderr create mode 100644 tests/fail/concurrency/windows_join_self.rs create mode 100644 tests/fail/concurrency/windows_join_self.stderr create mode 100644 tests/pass/concurrency/windows_detach_terminated.rs create mode 100644 tests/pass/concurrency/windows_join_multiple.rs diff --git a/src/machine.rs b/src/machine.rs index 4ebf7dceab839..943d5570f7b78 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -418,6 +418,7 @@ impl<'mir, 'tcx> Evaluator<'mir, 'tcx> { ) -> InterpResult<'tcx> { EnvVars::init(this, config)?; Evaluator::init_extern_statics(this)?; + ThreadManager::init(this); Ok(()) } diff --git a/src/shims/time.rs b/src/shims/time.rs index c3eb0161c210f..e495f723668d7 100644 --- a/src/shims/time.rs +++ b/src/shims/time.rs @@ -233,4 +233,30 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(0) } + + #[allow(non_snake_case)] + fn Sleep(&mut self, timeout: &OpTy<'tcx, Provenance>) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + + this.check_no_isolation("`Sleep`")?; + + let timeout_ms = this.read_scalar(timeout)?.to_u32()?; + + let duration = Duration::from_millis(timeout_ms.into()); + let timeout_time = Time::Monotonic(Instant::now().checked_add(duration).unwrap()); + + let active_thread = this.get_active_thread(); + this.block_thread(active_thread); + + this.register_timeout_callback( + active_thread, + timeout_time, + Box::new(move |ecx| { + ecx.unblock_thread(active_thread); + Ok(()) + }), + ); + + Ok(()) + } } diff --git a/src/shims/unix/thread.rs b/src/shims/unix/thread.rs index 094183b3e781a..d675df0f53f10 100644 --- a/src/shims/unix/thread.rs +++ b/src/shims/unix/thread.rs @@ -37,7 +37,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } let thread_id = this.read_scalar(thread)?.to_machine_usize(this)?; - this.join_thread(thread_id.try_into().expect("thread ID should fit in u32"))?; + this.join_thread_exclusive(thread_id.try_into().expect("thread ID should fit in u32"))?; Ok(0) } @@ -46,7 +46,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); let thread_id = this.read_scalar(thread)?.to_machine_usize(this)?; - this.detach_thread(thread_id.try_into().expect("thread ID should fit in u32"))?; + this.detach_thread(thread_id.try_into().expect("thread ID should fit in u32"), false)?; Ok(0) } diff --git a/src/shims/windows/dlsym.rs b/src/shims/windows/dlsym.rs index f18e27d38c2bc..d64be9cc0527f 100644 --- a/src/shims/windows/dlsym.rs +++ b/src/shims/windows/dlsym.rs @@ -5,7 +5,7 @@ use rustc_target::spec::abi::Abi; use log::trace; use crate::helpers::check_arg_count; -use crate::shims::windows::handle::Handle; +use crate::shims::windows::handle::{EvalContextExt as _, Handle}; use crate::*; #[derive(Debug, Copy, Clone)] @@ -118,7 +118,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx match Handle::from_scalar(this.read_scalar(handle)?.check_init()?, this)? { Some(Handle::Thread(thread)) => thread, Some(Handle::CurrentThread) => this.get_active_thread(), - _ => throw_ub_format!("invalid handle"), + _ => this.invalid_handle("SetThreadDescription")?, }; this.set_thread_name_wide(thread, name); diff --git a/src/shims/windows/foreign_items.rs b/src/shims/windows/foreign_items.rs index 00a80f869751a..6014281100fc3 100644 --- a/src/shims/windows/foreign_items.rs +++ b/src/shims/windows/foreign_items.rs @@ -228,24 +228,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let [timeout] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; - this.check_no_isolation("`Sleep`")?; - - let timeout_ms = this.read_scalar(timeout)?.to_u32()?; - - let duration = Duration::from_millis(timeout_ms as u64); - let timeout_time = Time::Monotonic(Instant::now().checked_add(duration).unwrap()); - - let active_thread = this.get_active_thread(); - this.block_thread(active_thread); - - this.register_timeout_callback( - active_thread, - timeout_time, - Box::new(move |ecx| { - ecx.unblock_thread(active_thread); - Ok(()) - }), - ); + this.Sleep(timeout)?; } // Synchronization primitives diff --git a/src/shims/windows/handle.rs b/src/shims/windows/handle.rs index ff64a958da3ee..e1617ae6a8d91 100644 --- a/src/shims/windows/handle.rs +++ b/src/shims/windows/handle.rs @@ -146,16 +146,19 @@ impl<'mir, 'tcx> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tc #[allow(non_snake_case)] pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { + fn invalid_handle(&mut self, function_name: &str) -> InterpResult<'tcx, !> { + throw_machine_stop!(TerminationInfo::Abort(format!( + "invalid handle passed to `{function_name}`" + ))) + } + fn CloseHandle(&mut self, handle_op: &OpTy<'tcx, Provenance>) -> InterpResult<'tcx> { let this = self.eval_context_mut(); match Handle::from_scalar(this.read_scalar(handle_op)?.check_init()?, this)? { - Some(Handle::Thread(thread)) => this.detach_thread(thread)?, - _ => - throw_machine_stop!(TerminationInfo::Abort( - "invalid handle passed to `CloseHandle`".into() - )), - }; + Some(Handle::Thread(thread)) => this.detach_thread(thread, true)?, + _ => this.invalid_handle("CloseHandle")?, + } Ok(()) } diff --git a/src/shims/windows/thread.rs b/src/shims/windows/thread.rs index 66cd9dd0348fc..6b6c4916dee2b 100644 --- a/src/shims/windows/thread.rs +++ b/src/shims/windows/thread.rs @@ -1,11 +1,8 @@ -use std::time::{Duration, Instant}; - use rustc_middle::ty::layout::LayoutOf; use rustc_target::spec::abi::Abi; -use crate::thread::Time; use crate::*; -use shims::windows::handle::Handle; +use shims::windows::handle::{EvalContextExt as _, Handle}; impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} @@ -59,25 +56,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let thread = match Handle::from_scalar(this.read_scalar(handle)?.check_init()?, this)? { Some(Handle::Thread(thread)) => thread, - Some(Handle::CurrentThread) => throw_ub_format!("trying to wait on itself"), - _ => throw_ub_format!("invalid handle"), + // Unlike on posix, joining the current thread is not UB on windows. + // It will just deadlock. + Some(Handle::CurrentThread) => this.get_active_thread(), + _ => this.invalid_handle("WaitForSingleObject")?, }; if this.read_scalar(timeout)?.to_u32()? != this.eval_windows("c", "INFINITE")?.to_u32()? { - this.check_no_isolation("`WaitForSingleObject` with non-infinite timeout")?; + throw_unsup_format!("`WaitForSingleObject` with non-infinite timeout"); } - let timeout_ms = this.read_scalar(timeout)?.to_u32()?; - - let timeout_time = if timeout_ms == this.eval_windows("c", "INFINITE")?.to_u32()? { - None - } else { - let duration = Duration::from_millis(timeout_ms as u64); - - Some(Time::Monotonic(Instant::now().checked_add(duration).unwrap())) - }; - - this.wait_on_thread(timeout_time, thread)?; + this.join_thread(thread)?; Ok(()) } diff --git a/src/thread.rs b/src/thread.rs index fa70dcfa2a3de..f7fcdd5822a28 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -405,6 +405,31 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { Ok(()) } + /// Mark that the active thread tries to exclusively join the thread with `joined_thread_id`. + /// If the thread is already joined by another thread + fn join_thread_exclusive( + &mut self, + joined_thread_id: ThreadId, + data_race: Option<&mut data_race::GlobalState>, + ) -> InterpResult<'tcx> { + if self.threads[joined_thread_id].join_status == ThreadJoinStatus::Joined { + throw_ub_format!("trying to join an already joined thread"); + } + + if joined_thread_id == self.active_thread { + throw_ub_format!("trying to join itself"); + } + + assert!( + self.threads + .iter() + .all(|thread| thread.state != ThreadState::BlockedOnJoin(joined_thread_id)), + "a joinable thread already has threads waiting for its termination" + ); + + self.join_thread(joined_thread_id, data_race) + } + /// Set the name of the given thread. pub fn set_thread_name(&mut self, thread: ThreadId, new_thread_name: Vec) { self.threads[thread].thread_name = Some(new_thread_name); @@ -700,6 +725,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(()) } + #[inline] + fn join_thread_exclusive(&mut self, joined_thread_id: ThreadId) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + this.machine + .threads + .join_thread_exclusive(joined_thread_id, this.machine.data_race.as_mut())?; + Ok(()) + } + #[inline] fn set_active_thread(&mut self, thread_id: ThreadId) -> ThreadId { let this = self.eval_context_mut(); diff --git a/tests/fail/concurrency/unwind_top_of_stack.rs b/tests/fail/concurrency/unwind_top_of_stack.rs index 61d3b964e620b..4704cfed03938 100644 --- a/tests/fail/concurrency/unwind_top_of_stack.rs +++ b/tests/fail/concurrency/unwind_top_of_stack.rs @@ -1,4 +1,4 @@ -//@ignore-windows: No libc on Windows +//@ignore-target-windows: No libc on Windows //@compile-flags: -Zmiri-disable-abi-check diff --git a/tests/fail/concurrency/windows_join_detached.rs b/tests/fail/concurrency/windows_join_detached.rs new file mode 100644 index 0000000000000..548ed63534dbd --- /dev/null +++ b/tests/fail/concurrency/windows_join_detached.rs @@ -0,0 +1,21 @@ +//@only-target-windows: Uses win32 api functions +//@error-pattern: Undefined Behavior: trying to join a detached thread + +// Joining a detached thread is undefined behavior. + +use std::os::windows::io::{AsRawHandle, RawHandle}; +use std::thread; + +extern "system" { + fn CloseHandle(handle: RawHandle) -> u32; +} + +fn main() { + let thread = thread::spawn(|| ()); + + unsafe { + assert_ne!(CloseHandle(thread.as_raw_handle()), 0); + } + + thread.join().unwrap(); +} diff --git a/tests/fail/concurrency/windows_join_detached.stderr b/tests/fail/concurrency/windows_join_detached.stderr new file mode 100644 index 0000000000000..a0e85f6ce5ab4 --- /dev/null +++ b/tests/fail/concurrency/windows_join_detached.stderr @@ -0,0 +1,22 @@ +error: Undefined Behavior: trying to join a detached thread + --> RUSTLIB/std/src/sys/PLATFORM/thread.rs:LL:CC + | +LL | let rc = unsafe { c::WaitForSingleObject(self.handle.as_raw_handle(), c::INFINITE) }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trying to join a detached thread + | + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information + = note: backtrace: + = note: inside `std::sys::PLATFORM::thread::Thread::join` at RUSTLIB/std/src/sys/PLATFORM/thread.rs:LL:CC + = note: inside `std::thread::JoinInner::<()>::join` at RUSTLIB/std/src/thread/mod.rs:LL:CC + = note: inside `std::thread::JoinHandle::<()>::join` at RUSTLIB/std/src/thread/mod.rs:LL:CC +note: inside `main` at $DIR/windows_join_detached.rs:LL:CC + --> $DIR/windows_join_detached.rs:LL:CC + | +LL | thread.join().unwrap(); + | ^^^^^^^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/fail/concurrency/windows_join_main.rs b/tests/fail/concurrency/windows_join_main.rs new file mode 100644 index 0000000000000..ea52220d44999 --- /dev/null +++ b/tests/fail/concurrency/windows_join_main.rs @@ -0,0 +1,28 @@ +//@only-target-windows: Uses win32 api functions +// We are making scheduler assumptions here. +//@compile-flags: -Zmiri-preemption-rate=0 + +// On windows, joining main is not UB, but it will block a thread forever. + +use std::thread; + +extern "system" { + fn WaitForSingleObject(handle: usize, timeout: u32) -> u32; +} + +const INFINITE: u32 = u32::MAX; + +// This is how miri represents the handle for thread 0. +// This value can be "legitimately" obtained by using `GetCurrentThread` with `DuplicateHandle` +// but miri does not implement `DuplicateHandle` yet. +const MAIN_THREAD: usize = 1 << 30; + +fn main() { + thread::spawn(|| { + unsafe { + assert_eq!(WaitForSingleObject(MAIN_THREAD, INFINITE), 0); //~ ERROR: deadlock: the evaluated program deadlocked + } + }) + .join() + .unwrap(); +} diff --git a/tests/fail/concurrency/windows_join_main.stderr b/tests/fail/concurrency/windows_join_main.stderr new file mode 100644 index 0000000000000..72b854d354a39 --- /dev/null +++ b/tests/fail/concurrency/windows_join_main.stderr @@ -0,0 +1,12 @@ +error: deadlock: the evaluated program deadlocked + --> $DIR/windows_join_main.rs:LL:CC + | +LL | WaitForSingleObject(MAIN_THREAD, INFINITE); + | ^ the evaluated program deadlocked + | + = note: inside closure at $DIR/windows_join_main.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/fail/concurrency/windows_join_self.rs b/tests/fail/concurrency/windows_join_self.rs new file mode 100644 index 0000000000000..d9bbf66a7dca5 --- /dev/null +++ b/tests/fail/concurrency/windows_join_self.rs @@ -0,0 +1,25 @@ +//@only-target-windows: Uses win32 api functions +// We are making scheduler assumptions here. +//@compile-flags: -Zmiri-preemption-rate=0 + +// On windows, a thread joining itself is not UB, but it will deadlock. + +use std::thread; + +extern "system" { + fn GetCurrentThread() -> usize; + fn WaitForSingleObject(handle: usize, timeout: u32) -> u32; +} + +const INFINITE: u32 = u32::MAX; + +fn main() { + thread::spawn(|| { + unsafe { + let native = GetCurrentThread(); + assert_eq!(WaitForSingleObject(native, INFINITE), 0); //~ ERROR: deadlock: the evaluated program deadlocked + } + }) + .join() + .unwrap(); +} diff --git a/tests/fail/concurrency/windows_join_self.stderr b/tests/fail/concurrency/windows_join_self.stderr new file mode 100644 index 0000000000000..bbec3f7257ec0 --- /dev/null +++ b/tests/fail/concurrency/windows_join_self.stderr @@ -0,0 +1,12 @@ +error: deadlock: the evaluated program deadlocked + --> $DIR/windows_join_self.rs:LL:CC + | +LL | assert_eq!(WaitForSingleObject(native, INFINITE), 0); + | ^ the evaluated program deadlocked + | + = note: inside closure at $DIR/windows_join_self.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/pass/concurrency/windows_detach_terminated.rs b/tests/pass/concurrency/windows_detach_terminated.rs new file mode 100644 index 0000000000000..91088ce6aef9b --- /dev/null +++ b/tests/pass/concurrency/windows_detach_terminated.rs @@ -0,0 +1,21 @@ +//@only-target-windows: Uses win32 api functions +// We are making scheduler assumptions here. +//@compile-flags: -Zmiri-preemption-rate=0 + +use std::os::windows::io::IntoRawHandle; +use std::thread; + +extern "system" { + fn CloseHandle(handle: usize) -> i32; +} + +fn main() { + let thread = thread::spawn(|| {}).into_raw_handle() as usize; + + // this yield ensures that `thread` is terminated by this point + thread::yield_now(); + + unsafe { + assert_ne!(CloseHandle(thread), 0); + } +} diff --git a/tests/pass/concurrency/windows_join_multiple.rs b/tests/pass/concurrency/windows_join_multiple.rs new file mode 100644 index 0000000000000..986e2b8cc10f7 --- /dev/null +++ b/tests/pass/concurrency/windows_join_multiple.rs @@ -0,0 +1,41 @@ +//@only-target-windows: Uses win32 api functions +// We are making scheduler assumptions here. +//@compile-flags: -Zmiri-preemption-rate=0 + +use std::os::windows::io::IntoRawHandle; +use std::sync::atomic::{AtomicBool, Ordering}; +use std::thread; + +extern "system" { + fn WaitForSingleObject(handle: usize, timeout: u32) -> u32; +} + +const INFINITE: u32 = u32::MAX; + +fn main() { + static FLAG: AtomicBool = AtomicBool::new(false); + + let blocker = thread::spawn(|| { + while !FLAG.load(Ordering::Relaxed) { + thread::yield_now(); + } + }) + .into_raw_handle() as usize; + + let waiter = move || { + unsafe { + assert_eq!(WaitForSingleObject(blocker, INFINITE), 0); + } + }; + + let waiter1 = thread::spawn(waiter); + let waiter2 = thread::spawn(waiter); + + // this yield ensures `waiter1` & `waiter2` are blocked on `blocker` by this point + thread::yield_now(); + + FLAG.store(true, Ordering::Relaxed); + + waiter1.join().unwrap(); + waiter2.join().unwrap(); +} From 9f69c41c5fc0e876c75927cbc3ef7a5eff481ecc Mon Sep 17 00:00:00 2001 From: DrMeepster <19316085+DrMeepster@users.noreply.github.com> Date: Sat, 16 Jul 2022 00:36:11 -0700 Subject: [PATCH 3656/3747] rewrite handle impl again --- src/shims/windows/dlsym.rs | 15 +- src/shims/windows/foreign_items.rs | 9 +- src/shims/windows/handle.rs | 139 +++++++++--------- src/shims/windows/thread.rs | 4 +- tests/fail/concurrency/windows_join_main.rs | 4 +- .../fail/concurrency/windows_join_main.stderr | 7 +- 6 files changed, 90 insertions(+), 88 deletions(-) diff --git a/src/shims/windows/dlsym.rs b/src/shims/windows/dlsym.rs index d64be9cc0527f..fc36913638e0c 100644 --- a/src/shims/windows/dlsym.rs +++ b/src/shims/windows/dlsym.rs @@ -5,7 +5,7 @@ use rustc_target::spec::abi::Abi; use log::trace; use crate::helpers::check_arg_count; -use crate::shims::windows::handle::{EvalContextExt as _, Handle}; +use crate::shims::windows::handle::{EvalContextExt as _, Handle, PseudoHandle}; use crate::*; #[derive(Debug, Copy, Clone)] @@ -112,14 +112,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Dlsym::SetThreadDescription => { let [handle, name] = check_arg_count(args)?; + let handle = this.read_scalar(handle)?.check_init()?; + let name = this.read_wide_str(this.read_pointer(name)?)?; - let thread = - match Handle::from_scalar(this.read_scalar(handle)?.check_init()?, this)? { - Some(Handle::Thread(thread)) => thread, - Some(Handle::CurrentThread) => this.get_active_thread(), - _ => this.invalid_handle("SetThreadDescription")?, - }; + let thread = match Handle::from_scalar(handle, this)? { + Some(Handle::Thread(thread)) => thread, + Some(Handle::Pseudo(PseudoHandle::CurrentThread)) => this.get_active_thread(), + _ => this.invalid_handle("SetThreadDescription")?, + }; this.set_thread_name_wide(thread, name); diff --git a/src/shims/windows/foreign_items.rs b/src/shims/windows/foreign_items.rs index 6014281100fc3..cc030ec3d0cf1 100644 --- a/src/shims/windows/foreign_items.rs +++ b/src/shims/windows/foreign_items.rs @@ -1,14 +1,12 @@ use std::iter; -use std::time::{Duration, Instant}; use rustc_span::Symbol; use rustc_target::abi::Size; use rustc_target::spec::abi::Abi; -use crate::thread::Time; use crate::*; use shims::foreign_items::EmulateByNameResult; -use shims::windows::handle::{EvalContextExt as _, Handle}; +use shims::windows::handle::{EvalContextExt as _, Handle, PseudoHandle}; use shims::windows::sync::EvalContextExt as _; use shims::windows::thread::EvalContextExt as _; @@ -373,7 +371,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "GetCurrentThread" => { let [] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; - this.write_scalar(Handle::CurrentThread.to_scalar(this), dest)?; + this.write_scalar( + Handle::Pseudo(PseudoHandle::CurrentThread).to_scalar(this), + dest, + )?; } // Incomplete shims that we "stub out" just to get pre-main initialization code to work. diff --git a/src/shims/windows/handle.rs b/src/shims/windows/handle.rs index e1617ae6a8d91..041033717e44c 100644 --- a/src/shims/windows/handle.rs +++ b/src/shims/windows/handle.rs @@ -3,44 +3,79 @@ use std::mem::variant_count; use crate::*; -/// A Windows `HANDLE` that represents a resource instead of being null or a pseudohandle. -/// -/// This is a seperate type from [`Handle`] to simplify the packing and unpacking code. -#[derive(Clone, Copy)] -enum RealHandle { - Thread(ThreadId), +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +pub enum PseudoHandle { + CurrentThread, } -impl RealHandle { - const USABLE_BITS: u32 = 31; +impl PseudoHandle { + const CURRENT_THREAD_VALUE: u32 = 0; - const THREAD_DISCRIMINANT: u32 = 1; + fn value(self) -> u32 { + match self { + Self::CurrentThread => Self::CURRENT_THREAD_VALUE, + } + } + + fn from_value(value: u32) -> Option { + match value { + Self::CURRENT_THREAD_VALUE => Some(Self::CurrentThread), + _ => None, + } + } +} + +/// Miri representation of a Windows `HANDLE` +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +pub enum Handle { + Null, + Pseudo(PseudoHandle), + Thread(ThreadId), +} + +impl Handle { + const NULL_DISCRIMINANT: u32 = 0; + const PSEUDO_DISCRIMINANT: u32 = 1; + const THREAD_DISCRIMINANT: u32 = 2; fn discriminant(self) -> u32 { match self { - // can't use zero here because all zero handle is invalid + Self::Null => Self::NULL_DISCRIMINANT, + Self::Pseudo(_) => Self::PSEUDO_DISCRIMINANT, Self::Thread(_) => Self::THREAD_DISCRIMINANT, } } fn data(self) -> u32 { match self { + Self::Null => 0, + Self::Pseudo(pseudo_handle) => pseudo_handle.value(), Self::Thread(thread) => thread.to_u32(), } } fn packed_disc_size() -> u32 { - // log2(x) + 1 is how many bits it takes to store x - // because the discriminants start at 1, the variant count is equal to the highest discriminant - variant_count::().ilog2() + 1 + // ceil(log2(x)) is how many bits it takes to store x numbers + let variant_count = variant_count::(); + + // however, std's ilog2 is floor(log2(x)) + let floor_log2 = variant_count.ilog2(); + + // we need to add one for non powers of two to compensate for the difference + let ceil_log2 = if variant_count.is_power_of_two() { floor_log2 } else { floor_log2 + 1 }; + + ceil_log2 } - /// This function packs the discriminant and data values into a 31-bit space. + /// Converts a handle into its machine representation. + /// + /// The upper [`Self::packed_disc_size()`] bits are used to store a discriminant corresponding to the handle variant. + /// The remaining bits are used for the variant's field. + /// /// None of this layout is guaranteed to applications by Windows or Miri. - /// The sign bit is not used to avoid overlapping any pseudo-handles. - fn to_packed(self) -> i32 { + fn to_packed(self) -> u32 { let disc_size = Self::packed_disc_size(); - let data_size = Self::USABLE_BITS - disc_size; + let data_size = u32::BITS - disc_size; let discriminant = self.discriminant(); let data = self.data(); @@ -53,90 +88,54 @@ impl RealHandle { // packs the data into the lower `data_size` bits // and packs the discriminant right above the data - (discriminant << data_size | data) as i32 + discriminant << data_size | data } fn new(discriminant: u32, data: u32) -> Option { match discriminant { + Self::NULL_DISCRIMINANT if data == 0 => Some(Self::Null), + Self::PSEUDO_DISCRIMINANT => Some(Self::Pseudo(PseudoHandle::from_value(data)?)), Self::THREAD_DISCRIMINANT => Some(Self::Thread(data.into())), _ => None, } } /// see docs for `to_packed` - fn from_packed(handle: i32) -> Option { - let handle_bits = handle as u32; - + fn from_packed(handle: u32) -> Option { let disc_size = Self::packed_disc_size(); - let data_size = Self::USABLE_BITS - disc_size; + let data_size = u32::BITS - disc_size; // the lower `data_size` bits of this mask are 1 let data_mask = 2u32.pow(data_size) - 1; // the discriminant is stored right above the lower `data_size` bits - let discriminant = handle_bits >> data_size; + let discriminant = handle >> data_size; // the data is stored in the lower `data_size` bits - let data = handle_bits & data_mask; + let data = handle & data_mask; Self::new(discriminant, data) } -} - -/// Miri representation of a Windows `HANDLE` -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub enum Handle { - Null, // = 0 - - // pseudo-handles - // The lowest real windows pseudo-handle is -6, so miri pseduo-handles start at -7 to break code hardcoding these values - CurrentThread, // = -7 - - // real handles - Thread(ThreadId), -} - -impl Handle { - const CURRENT_THREAD_VALUE: i32 = -7; - - fn to_packed(self) -> i32 { - match self { - Self::Null => 0, - Self::CurrentThread => Self::CURRENT_THREAD_VALUE, - Self::Thread(thread) => RealHandle::Thread(thread).to_packed(), - } - } pub fn to_scalar(self, cx: &impl HasDataLayout) -> Scalar { // 64-bit handles are sign extended 32-bit handles // see https://docs.microsoft.com/en-us/windows/win32/winprog64/interprocess-communication - let handle = self.to_packed().into(); - - Scalar::from_machine_isize(handle, cx) - } - - fn from_packed(handle: i64) -> Option { - let current_thread_val = Self::CURRENT_THREAD_VALUE as i64; - - if handle == 0 { - Some(Self::Null) - } else if handle == current_thread_val { - Some(Self::CurrentThread) - } else if let Ok(handle) = handle.try_into() { - match RealHandle::from_packed(handle)? { - RealHandle::Thread(id) => Some(Self::Thread(id)), - } - } else { - // if a handle doesn't fit in an i32, it isn't valid. - None - } + let signed_handle = self.to_packed() as i32; + Scalar::from_machine_isize(signed_handle.into(), cx) } pub fn from_scalar<'tcx>( handle: Scalar, cx: &impl HasDataLayout, ) -> InterpResult<'tcx, Option> { - let handle = handle.to_machine_isize(cx)?; + let sign_extended_handle = handle.to_machine_isize(cx)?; + + let handle = if let Ok(signed_handle) = i32::try_from(sign_extended_handle) { + signed_handle as u32 + } else { + // if a handle doesn't fit in an i32, it isn't valid. + return Ok(None); + }; Ok(Self::from_packed(handle)) } diff --git a/src/shims/windows/thread.rs b/src/shims/windows/thread.rs index 6b6c4916dee2b..08eb4ddba10ce 100644 --- a/src/shims/windows/thread.rs +++ b/src/shims/windows/thread.rs @@ -2,7 +2,7 @@ use rustc_middle::ty::layout::LayoutOf; use rustc_target::spec::abi::Abi; use crate::*; -use shims::windows::handle::{EvalContextExt as _, Handle}; +use shims::windows::handle::{EvalContextExt as _, Handle, PseudoHandle}; impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} @@ -58,7 +58,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Some(Handle::Thread(thread)) => thread, // Unlike on posix, joining the current thread is not UB on windows. // It will just deadlock. - Some(Handle::CurrentThread) => this.get_active_thread(), + Some(Handle::Pseudo(PseudoHandle::CurrentThread)) => this.get_active_thread(), _ => this.invalid_handle("WaitForSingleObject")?, }; diff --git a/tests/fail/concurrency/windows_join_main.rs b/tests/fail/concurrency/windows_join_main.rs index ea52220d44999..d3b54cdf156fd 100644 --- a/tests/fail/concurrency/windows_join_main.rs +++ b/tests/fail/concurrency/windows_join_main.rs @@ -7,7 +7,7 @@ use std::thread; extern "system" { - fn WaitForSingleObject(handle: usize, timeout: u32) -> u32; + fn WaitForSingleObject(handle: isize, timeout: u32) -> u32; } const INFINITE: u32 = u32::MAX; @@ -15,7 +15,7 @@ const INFINITE: u32 = u32::MAX; // This is how miri represents the handle for thread 0. // This value can be "legitimately" obtained by using `GetCurrentThread` with `DuplicateHandle` // but miri does not implement `DuplicateHandle` yet. -const MAIN_THREAD: usize = 1 << 30; +const MAIN_THREAD: isize = (2i32 << 30) as isize; fn main() { thread::spawn(|| { diff --git a/tests/fail/concurrency/windows_join_main.stderr b/tests/fail/concurrency/windows_join_main.stderr index 72b854d354a39..ff0d074fa7d26 100644 --- a/tests/fail/concurrency/windows_join_main.stderr +++ b/tests/fail/concurrency/windows_join_main.stderr @@ -1,10 +1,11 @@ error: deadlock: the evaluated program deadlocked --> $DIR/windows_join_main.rs:LL:CC | -LL | WaitForSingleObject(MAIN_THREAD, INFINITE); - | ^ the evaluated program deadlocked +LL | assert_eq!(WaitForSingleObject(MAIN_THREAD, INFINITE), 0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the evaluated program deadlocked | - = note: inside closure at $DIR/windows_join_main.rs:LL:CC + = note: inside closure at RUSTLIB/core/src/macros/mod.rs:LL:CC + = note: this error originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info) note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace From d34242e8f1c538a8b4e01100a273ef1c5d456abd Mon Sep 17 00:00:00 2001 From: DrMeepster <19316085+DrMeepster@users.noreply.github.com> Date: Sun, 31 Jul 2022 17:15:15 -0700 Subject: [PATCH 3657/3747] fix various issues --- src/shims/os_str.rs | 2 +- src/shims/tls.rs | 5 +- src/shims/unix/thread.rs | 15 +- src/shims/windows/dlsym.rs | 2 +- src/shims/windows/foreign_items.rs | 25 +-- src/shims/windows/handle.rs | 29 +-- src/shims/windows/thread.rs | 48 +++-- src/thread.rs | 23 ++- .../libc_pthread_join_detached.stderr | 6 +- .../concurrency/libc_pthread_join_joined.rs | 2 +- .../libc_pthread_join_joined.stderr | 6 +- .../concurrency/libc_pthread_join_main.rs | 2 +- .../concurrency/libc_pthread_join_main.stderr | 6 +- .../concurrency/libc_pthread_join_multiple.rs | 2 +- .../libc_pthread_join_multiple.stderr | 4 +- tests/fail/concurrency/windows_join_main.rs | 2 +- tests/pass/concurrency/tls_lib_drop.rs | 2 + .../pass/concurrency/tls_lib_drop_windows.rs | 191 ++++++++++++++++++ .../concurrency/tls_lib_drop_windows.stdout | 5 + 19 files changed, 306 insertions(+), 71 deletions(-) create mode 100644 tests/pass/concurrency/tls_lib_drop_windows.rs create mode 100644 tests/pass/concurrency/tls_lib_drop_windows.stdout diff --git a/src/shims/os_str.rs b/src/shims/os_str.rs index f99e2d174b531..fcf92dfc9f935 100644 --- a/src/shims/os_str.rs +++ b/src/shims/os_str.rs @@ -74,7 +74,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx 'mir: 'a, { #[cfg(windows)] - pub fn u16vec_to_osstring<'tcx, 'a>(u16_vec: Vec) -> InterpResult<'tcx, OsString> { + pub fn u16vec_to_osstring<'tcx>(u16_vec: Vec) -> InterpResult<'tcx, OsString> { Ok(OsString::from_wide(&u16_vec[..])) } #[cfg(not(windows))] diff --git a/src/shims/tls.rs b/src/shims/tls.rs index 8627d9a044790..a520548798113 100644 --- a/src/shims/tls.rs +++ b/src/shims/tls.rs @@ -244,10 +244,13 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.eval_windows("thread_local_key", "p_thread_callback")?.to_pointer(this)?; let thread_callback = this.get_ptr_fn(thread_callback)?.as_instance()?; - // Technically, the reason should be `DLL_PROCESS_DETACH` when the main thread exits but std ignores it. + // FIXME: Technically, the reason should be `DLL_PROCESS_DETACH` when the main thread exits + // but std treats both the same. let reason = this.eval_windows("c", "DLL_THREAD_DETACH")?; // The signature of this function is `unsafe extern "system" fn(h: c::LPVOID, dwReason: c::DWORD, pv: c::LPVOID)`. + // FIXME: `h` should be a handle to the current module and what `pv` should be is unknown + // but both are ignored by std this.call_function( thread_callback, Abi::System { unwind: false }, diff --git a/src/shims/unix/thread.rs b/src/shims/unix/thread.rs index d675df0f53f10..9365ec9a21f4d 100644 --- a/src/shims/unix/thread.rs +++ b/src/shims/unix/thread.rs @@ -13,11 +13,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); + let thread_info_place = this.deref_operand(thread)?; + + let start_routine = this.read_pointer(start_routine)?; + + let func_arg = this.read_immediate(arg)?; + this.start_thread( - Some(thread), + Some(thread_info_place), start_routine, Abi::C { unwind: false }, - arg, + func_arg, this.layout_of(this.tcx.types.usize)?, )?; @@ -46,7 +52,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); let thread_id = this.read_scalar(thread)?.to_machine_usize(this)?; - this.detach_thread(thread_id.try_into().expect("thread ID should fit in u32"), false)?; + this.detach_thread( + thread_id.try_into().expect("thread ID should fit in u32"), + /*allow_terminated_joined*/ false, + )?; Ok(0) } diff --git a/src/shims/windows/dlsym.rs b/src/shims/windows/dlsym.rs index fc36913638e0c..4c5e7a9b31387 100644 --- a/src/shims/windows/dlsym.rs +++ b/src/shims/windows/dlsym.rs @@ -122,7 +122,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx _ => this.invalid_handle("SetThreadDescription")?, }; - this.set_thread_name_wide(thread, name); + this.set_thread_name_wide(thread, &name); this.write_null(dest)?; } diff --git a/src/shims/windows/foreign_items.rs b/src/shims/windows/foreign_items.rs index cc030ec3d0cf1..d853f3084d492 100644 --- a/src/shims/windows/foreign_items.rs +++ b/src/shims/windows/foreign_items.rs @@ -323,15 +323,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // FIXME: we should set last_error, but to what? this.write_null(dest)?; } - // this is only callable from std because we know that std ignores the return value - "SwitchToThread" if this.frame_in_std() => { - let [] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; - - this.yield_active_thread(); - - // FIXME: this should return a nonzero value if this call does result in switching to another thread. - this.write_null(dest)?; - } "GetStdHandle" => { let [which] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; @@ -339,6 +330,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // We just make this the identity function, so we know later in `NtWriteFile` which // one it is. This is very fake, but libtest needs it so we cannot make it a // std-only shim. + // FIXME: this should return real HANDLEs when io support is added this.write_scalar(Scalar::from_machine_isize(which.into(), this), dest)?; } "CloseHandle" => { @@ -364,9 +356,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let [handle, timeout] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; - this.WaitForSingleObject(handle, timeout)?; - - this.write_scalar(Scalar::from_u32(0), dest)?; + let ret = this.WaitForSingleObject(handle, timeout)?; + this.write_scalar(Scalar::from_u32(ret), dest)?; } "GetCurrentThread" => { let [] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; @@ -382,6 +373,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "GetProcessHeap" if this.frame_in_std() => { let [] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; // Just fake a HANDLE + // It's fine to not use the Handle type here because its a stub this.write_scalar(Scalar::from_machine_isize(1, this), dest)?; } "GetModuleHandleA" if this.frame_in_std() => { @@ -417,6 +409,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let result = this.GetCurrentProcessId()?; this.write_scalar(Scalar::from_u32(result), dest)?; } + // this is only callable from std because we know that std ignores the return value + "SwitchToThread" if this.frame_in_std() => { + let [] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; + + this.yield_active_thread(); + + // FIXME: this should return a nonzero value if this call does result in switching to another thread. + this.write_null(dest)?; + } _ => return Ok(EmulateByNameResult::NotSupported), } diff --git a/src/shims/windows/handle.rs b/src/shims/windows/handle.rs index 041033717e44c..443af1dfeaaa4 100644 --- a/src/shims/windows/handle.rs +++ b/src/shims/windows/handle.rs @@ -8,6 +8,14 @@ pub enum PseudoHandle { CurrentThread, } +/// Miri representation of a Windows `HANDLE` +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +pub enum Handle { + Null, + Pseudo(PseudoHandle), + Thread(ThreadId), +} + impl PseudoHandle { const CURRENT_THREAD_VALUE: u32 = 0; @@ -25,14 +33,6 @@ impl PseudoHandle { } } -/// Miri representation of a Windows `HANDLE` -#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] -pub enum Handle { - Null, - Pseudo(PseudoHandle), - Thread(ThreadId), -} - impl Handle { const NULL_DISCRIMINANT: u32 = 0; const PSEUDO_DISCRIMINANT: u32 = 1; @@ -62,9 +62,7 @@ impl Handle { let floor_log2 = variant_count.ilog2(); // we need to add one for non powers of two to compensate for the difference - let ceil_log2 = if variant_count.is_power_of_two() { floor_log2 } else { floor_log2 + 1 }; - - ceil_log2 + if variant_count.is_power_of_two() { floor_log2 } else { floor_log2 + 1 } } /// Converts a handle into its machine representation. @@ -120,6 +118,7 @@ impl Handle { pub fn to_scalar(self, cx: &impl HasDataLayout) -> Scalar { // 64-bit handles are sign extended 32-bit handles // see https://docs.microsoft.com/en-us/windows/win32/winprog64/interprocess-communication + #[allow(clippy::cast_possible_wrap)] // we want it to wrap let signed_handle = self.to_packed() as i32; Scalar::from_machine_isize(signed_handle.into(), cx) } @@ -130,6 +129,7 @@ impl Handle { ) -> InterpResult<'tcx, Option> { let sign_extended_handle = handle.to_machine_isize(cx)?; + #[allow(clippy::cast_sign_loss)] // we want to lose the sign let handle = if let Ok(signed_handle) = i32::try_from(sign_extended_handle) { signed_handle as u32 } else { @@ -154,8 +154,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn CloseHandle(&mut self, handle_op: &OpTy<'tcx, Provenance>) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - match Handle::from_scalar(this.read_scalar(handle_op)?.check_init()?, this)? { - Some(Handle::Thread(thread)) => this.detach_thread(thread, true)?, + let handle = this.read_scalar(handle_op)?.check_init()?; + + match Handle::from_scalar(handle, this)? { + Some(Handle::Thread(thread)) => + this.detach_thread(thread, /*allow_terminated_joined*/ true)?, _ => this.invalid_handle("CloseHandle")?, } diff --git a/src/shims/windows/thread.rs b/src/shims/windows/thread.rs index 08eb4ddba10ce..06a5887d3e509 100644 --- a/src/shims/windows/thread.rs +++ b/src/shims/windows/thread.rs @@ -19,55 +19,71 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, ThreadId> { let this = self.eval_context_mut(); - if !this.ptr_is_null(this.read_pointer(security_op)?)? { - throw_unsup_format!("non-null `lpThreadAttributes` in `CreateThread`") - } + let security = this.read_pointer(security_op)?; // stacksize is ignored, but still needs to be a valid usize - let _ = this.read_scalar(stacksize_op)?.to_machine_usize(this)?; + this.read_scalar(stacksize_op)?.to_machine_usize(this)?; + + let start_routine = this.read_pointer(start_op)?; + + let func_arg = this.read_immediate(arg_op)?; let flags = this.read_scalar(flags_op)?.to_u32()?; + let thread = if this.ptr_is_null(this.read_pointer(thread_op)?)? { + None + } else { + let thread_info_place = this.deref_operand(thread_op)?; + Some(thread_info_place) + }; + let stack_size_param_is_a_reservation = this.eval_windows("c", "STACK_SIZE_PARAM_IS_A_RESERVATION")?.to_u32()?; + // We ignore the stack size, so we also ignore the + // `STACK_SIZE_PARAM_IS_A_RESERVATION` flag. if flags != 0 && flags != stack_size_param_is_a_reservation { throw_unsup_format!("unsupported `dwCreationFlags` {} in `CreateThread`", flags) } - let thread = - if this.ptr_is_null(this.read_pointer(thread_op)?)? { None } else { Some(thread_op) }; + if !this.ptr_is_null(security)? { + throw_unsup_format!("non-null `lpThreadAttributes` in `CreateThread`") + } this.start_thread( thread, - start_op, + start_routine, Abi::System { unwind: false }, - arg_op, + func_arg, this.layout_of(this.tcx.types.u32)?, ) } fn WaitForSingleObject( &mut self, - handle: &OpTy<'tcx, Provenance>, - timeout: &OpTy<'tcx, Provenance>, - ) -> InterpResult<'tcx> { + handle_op: &OpTy<'tcx, Provenance>, + timeout_op: &OpTy<'tcx, Provenance>, + ) -> InterpResult<'tcx, u32> { let this = self.eval_context_mut(); - let thread = match Handle::from_scalar(this.read_scalar(handle)?.check_init()?, this)? { + let handle = this.read_scalar(handle_op)?.check_init()?; + + let timeout = this.read_scalar(timeout_op)?.to_u32()?; + + let thread = match Handle::from_scalar(handle, this)? { Some(Handle::Thread(thread)) => thread, - // Unlike on posix, joining the current thread is not UB on windows. - // It will just deadlock. + // Unlike on posix, the outcome of joining the current thread is not documented. + // On current Windows, it just deadlocks. Some(Handle::Pseudo(PseudoHandle::CurrentThread)) => this.get_active_thread(), _ => this.invalid_handle("WaitForSingleObject")?, }; - if this.read_scalar(timeout)?.to_u32()? != this.eval_windows("c", "INFINITE")?.to_u32()? { + if timeout != this.eval_windows("c", "INFINITE")?.to_u32()? { throw_unsup_format!("`WaitForSingleObject` with non-infinite timeout"); } this.join_thread(thread)?; - Ok(()) + Ok(0) } } diff --git a/src/thread.rs b/src/thread.rs index f7fcdd5822a28..b92728be20874 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -181,7 +181,7 @@ impl<'mir, 'tcx> Thread<'mir, 'tcx> { } /// A specific moment in time. -#[derive(Debug, Copy, Clone)] +#[derive(Debug)] pub enum Time { Monotonic(Instant), RealTime(SystemTime), @@ -357,16 +357,19 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { /// /// `allow_terminated_joined` allows detaching joined threads that have already terminated. /// This matches Windows's behavior for `CloseHandle`. + /// + /// See : + /// > The handle is valid until closed, even after the thread it represents has been terminated. fn detach_thread(&mut self, id: ThreadId, allow_terminated_joined: bool) -> InterpResult<'tcx> { trace!("detaching {:?}", id); let is_ub = if allow_terminated_joined && self.threads[id].state == ThreadState::Terminated { + // "Detached" in particular means "not yet joined". Redundant detaching is still UB. self.threads[id].join_status == ThreadJoinStatus::Detached } else { self.threads[id].join_status != ThreadJoinStatus::Joinable }; - if is_ub { throw_ub_format!("trying to detach thread that was already detached or joined"); } @@ -406,7 +409,7 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { } /// Mark that the active thread tries to exclusively join the thread with `joined_thread_id`. - /// If the thread is already joined by another thread + /// If the thread is already joined by another thread, it will throw UB fn join_thread_exclusive( &mut self, joined_thread_id: ThreadId, @@ -424,7 +427,7 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { self.threads .iter() .all(|thread| thread.state != ThreadState::BlockedOnJoin(joined_thread_id)), - "a joinable thread already has threads waiting for its termination" + "this thread already has threads waiting for its termination" ); self.join_thread(joined_thread_id, data_race) @@ -803,12 +806,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } #[inline] - fn set_thread_name_wide(&mut self, thread: ThreadId, new_thread_name: Vec) { + fn set_thread_name_wide(&mut self, thread: ThreadId, new_thread_name: &[u16]) { let this = self.eval_context_mut(); - this.machine.threads.set_thread_name( - thread, - new_thread_name.into_iter().flat_map(u16::to_ne_bytes).collect(), - ); + + // The Windows `GetThreadDescription` shim to get the thread name isn't implemented, so being lossy is okay. + // This is only read by diagnostics, which already use `from_utf8_lossy`. + this.machine + .threads + .set_thread_name(thread, String::from_utf16_lossy(new_thread_name).into_bytes()); } #[inline] diff --git a/tests/fail/concurrency/libc_pthread_join_detached.stderr b/tests/fail/concurrency/libc_pthread_join_detached.stderr index e381a71b25204..92b693c0fd6bf 100644 --- a/tests/fail/concurrency/libc_pthread_join_detached.stderr +++ b/tests/fail/concurrency/libc_pthread_join_detached.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: trying to join a detached or already joined thread +error: Undefined Behavior: trying to join a detached thread --> $DIR/libc_pthread_join_detached.rs:LL:CC | -LL | ... assert_eq!(libc::pthread_join(native, ptr::null_mut()), 0); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trying to join a detached thread +LL | assert_eq!(libc::pthread_join(native, ptr::null_mut()), 0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trying to join a detached thread | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/concurrency/libc_pthread_join_joined.rs b/tests/fail/concurrency/libc_pthread_join_joined.rs index ebd1710bbf226..04ca4bbb3f611 100644 --- a/tests/fail/concurrency/libc_pthread_join_joined.rs +++ b/tests/fail/concurrency/libc_pthread_join_joined.rs @@ -15,6 +15,6 @@ fn main() { // assert_eq!(libc::pthread_attr_init(&mut attr), 0); FIXME: this function is not yet implemented. assert_eq!(libc::pthread_create(&mut native, &attr, thread_start, ptr::null_mut()), 0); assert_eq!(libc::pthread_join(native, ptr::null_mut()), 0); - assert_eq!(libc::pthread_join(native, ptr::null_mut()), 0); //~ ERROR: Undefined Behavior: trying to join a detached or already joined thread + assert_eq!(libc::pthread_join(native, ptr::null_mut()), 0); //~ ERROR: Undefined Behavior: trying to join an already joined thread } } diff --git a/tests/fail/concurrency/libc_pthread_join_joined.stderr b/tests/fail/concurrency/libc_pthread_join_joined.stderr index 5ac35ffe512e3..f11b94cde8ee6 100644 --- a/tests/fail/concurrency/libc_pthread_join_joined.stderr +++ b/tests/fail/concurrency/libc_pthread_join_joined.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: trying to join a detached or already joined thread +error: Undefined Behavior: trying to join an already joined thread --> $DIR/libc_pthread_join_joined.rs:LL:CC | -LL | ... assert_eq!(libc::pthread_join(native, ptr::null_mut()), 0); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trying to join a detached or already joined thread +LL | assert_eq!(libc::pthread_join(native, ptr::null_mut()), 0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trying to join an already joined thread | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/concurrency/libc_pthread_join_main.rs b/tests/fail/concurrency/libc_pthread_join_main.rs index df6b520431b6a..7576518216372 100644 --- a/tests/fail/concurrency/libc_pthread_join_main.rs +++ b/tests/fail/concurrency/libc_pthread_join_main.rs @@ -8,7 +8,7 @@ fn main() { let thread_id: libc::pthread_t = unsafe { libc::pthread_self() }; let handle = thread::spawn(move || { unsafe { - assert_eq!(libc::pthread_join(thread_id, ptr::null_mut()), 0); //~ ERROR: Undefined Behavior: trying to join a detached or already joined thread + assert_eq!(libc::pthread_join(thread_id, ptr::null_mut()), 0); //~ ERROR: Undefined Behavior: trying to join a detached thread } }); thread::yield_now(); diff --git a/tests/fail/concurrency/libc_pthread_join_main.stderr b/tests/fail/concurrency/libc_pthread_join_main.stderr index fe136549ce511..c162f37b309f7 100644 --- a/tests/fail/concurrency/libc_pthread_join_main.stderr +++ b/tests/fail/concurrency/libc_pthread_join_main.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: trying to join a detached or already joined thread +error: Undefined Behavior: trying to join a detached thread --> $DIR/libc_pthread_join_main.rs:LL:CC | -LL | ... assert_eq!(libc::pthread_join(thread_id, ptr::null_mut()), 0); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trying to join a detached or already joined thread +LL | assert_eq!(libc::pthread_join(thread_id, ptr::null_mut()), 0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trying to join a detached thread | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/concurrency/libc_pthread_join_multiple.rs b/tests/fail/concurrency/libc_pthread_join_multiple.rs index e5187093befde..966f416eeac7e 100644 --- a/tests/fail/concurrency/libc_pthread_join_multiple.rs +++ b/tests/fail/concurrency/libc_pthread_join_multiple.rs @@ -21,7 +21,7 @@ fn main() { let mut native_copy: libc::pthread_t = mem::zeroed(); ptr::copy_nonoverlapping(&native, &mut native_copy, 1); let handle = thread::spawn(move || { - assert_eq!(libc::pthread_join(native_copy, ptr::null_mut()), 0); //~ ERROR: Undefined Behavior: trying to join a detached or already joined thread + assert_eq!(libc::pthread_join(native_copy, ptr::null_mut()), 0); //~ ERROR: Undefined Behavior: trying to join an already joined thread }); assert_eq!(libc::pthread_join(native, ptr::null_mut()), 0); handle.join().unwrap(); diff --git a/tests/fail/concurrency/libc_pthread_join_multiple.stderr b/tests/fail/concurrency/libc_pthread_join_multiple.stderr index 9b91e5a3d0ed1..c0c73086f14d6 100644 --- a/tests/fail/concurrency/libc_pthread_join_multiple.stderr +++ b/tests/fail/concurrency/libc_pthread_join_multiple.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: trying to join a detached or already joined thread +error: Undefined Behavior: trying to join an already joined thread --> $DIR/libc_pthread_join_multiple.rs:LL:CC | LL | ... assert_eq!(libc::pthread_join(native_copy, ptr::null_mut()), 0); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trying to join a detached or already joined thread + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ trying to join an already joined thread | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/concurrency/windows_join_main.rs b/tests/fail/concurrency/windows_join_main.rs index d3b54cdf156fd..cde6d19ef25bb 100644 --- a/tests/fail/concurrency/windows_join_main.rs +++ b/tests/fail/concurrency/windows_join_main.rs @@ -12,7 +12,7 @@ extern "system" { const INFINITE: u32 = u32::MAX; -// This is how miri represents the handle for thread 0. +// XXX HACK: This is how miri represents the handle for thread 0. // This value can be "legitimately" obtained by using `GetCurrentThread` with `DuplicateHandle` // but miri does not implement `DuplicateHandle` yet. const MAIN_THREAD: isize = (2i32 << 30) as isize; diff --git a/tests/pass/concurrency/tls_lib_drop.rs b/tests/pass/concurrency/tls_lib_drop.rs index 8ce011ede34e0..3fd6e2d6f2426 100644 --- a/tests/pass/concurrency/tls_lib_drop.rs +++ b/tests/pass/concurrency/tls_lib_drop.rs @@ -1,3 +1,5 @@ +//@ignore-target-windows: TLS destructor order is different on Windows. + use std::cell::RefCell; use std::thread; diff --git a/tests/pass/concurrency/tls_lib_drop_windows.rs b/tests/pass/concurrency/tls_lib_drop_windows.rs new file mode 100644 index 0000000000000..e8c6538e701d3 --- /dev/null +++ b/tests/pass/concurrency/tls_lib_drop_windows.rs @@ -0,0 +1,191 @@ +//@only-target-windows: TLS destructor order is different on Windows. + +use std::cell::RefCell; +use std::thread; + +struct TestCell { + value: RefCell, +} + +impl Drop for TestCell { + fn drop(&mut self) { + for _ in 0..10 { + thread::yield_now(); + } + println!("Dropping: {} (should be before 'Continue main 1').", *self.value.borrow()) + } +} + +thread_local! { + static A: TestCell = TestCell { value: RefCell::new(0) }; + static A_CONST: TestCell = const { TestCell { value: RefCell::new(10) } }; +} + +/// Check that destructors of the library thread locals are executed immediately +/// after a thread terminates. +fn check_destructors() { + thread::spawn(|| { + A.with(|f| { + assert_eq!(*f.value.borrow(), 0); + *f.value.borrow_mut() = 5; + }); + A_CONST.with(|f| { + assert_eq!(*f.value.borrow(), 10); + *f.value.borrow_mut() = 15; + }); + }) + .join() + .unwrap(); + println!("Continue main 1.") +} + +struct JoinCell { + value: RefCell>>, +} + +impl Drop for JoinCell { + fn drop(&mut self) { + for _ in 0..10 { + thread::yield_now(); + } + let join_handle = self.value.borrow_mut().take().unwrap(); + println!("Joining: {} (should be before 'Continue main 2').", join_handle.join().unwrap()); + } +} + +thread_local! { + static B: JoinCell = JoinCell { value: RefCell::new(None) }; +} + +/// Check that the destructor can be blocked joining another thread. +fn check_blocking() { + thread::spawn(|| { + B.with(|f| { + assert!(f.value.borrow().is_none()); + let handle = thread::spawn(|| 7); + *f.value.borrow_mut() = Some(handle); + }); + }) + .join() + .unwrap(); + println!("Continue main 2."); + // Preempt the main thread so that the destructor gets executed and can join + // the thread. + thread::yield_now(); + thread::yield_now(); +} + +// This test tests that TLS destructors have run before the thread joins. The +// test has no false positives (meaning: if the test fails, there's actually +// an ordering problem). It may have false negatives, where the test passes but +// join is not guaranteed to be after the TLS destructors. However, false +// negatives should be exceedingly rare due to judicious use of +// thread::yield_now and running the test several times. +fn join_orders_after_tls_destructors() { + use std::sync::atomic::{AtomicU8, Ordering}; + + // We emulate a synchronous MPSC rendezvous channel using only atomics and + // thread::yield_now. We can't use std::mpsc as the implementation itself + // may rely on thread locals. + // + // The basic state machine for an SPSC rendezvous channel is: + // FRESH -> THREAD1_WAITING -> MAIN_THREAD_RENDEZVOUS + // where the first transition is done by the “receiving” thread and the 2nd + // transition is done by the “sending” thread. + // + // We add an additional state `THREAD2_LAUNCHED` between `FRESH` and + // `THREAD1_WAITING` to block until all threads are actually running. + // + // A thread that joins on the “receiving” thread completion should never + // observe the channel in the `THREAD1_WAITING` state. If this does occur, + // we switch to the “poison” state `THREAD2_JOINED` and panic all around. + // (This is equivalent to “sending” from an alternate producer thread.) + const FRESH: u8 = 0; + const THREAD2_LAUNCHED: u8 = 1; + const THREAD1_WAITING: u8 = 2; + const MAIN_THREAD_RENDEZVOUS: u8 = 3; + const THREAD2_JOINED: u8 = 4; + static SYNC_STATE: AtomicU8 = AtomicU8::new(FRESH); + + for _ in 0..10 { + SYNC_STATE.store(FRESH, Ordering::SeqCst); + + let jh = thread::Builder::new() + .name("thread1".into()) + .spawn(move || { + struct TlDrop; + + impl Drop for TlDrop { + fn drop(&mut self) { + let mut sync_state = SYNC_STATE.swap(THREAD1_WAITING, Ordering::SeqCst); + loop { + match sync_state { + THREAD2_LAUNCHED | THREAD1_WAITING => thread::yield_now(), + MAIN_THREAD_RENDEZVOUS => break, + THREAD2_JOINED => + panic!( + "Thread 1 still running after thread 2 joined on thread 1" + ), + v => unreachable!("sync state: {}", v), + } + sync_state = SYNC_STATE.load(Ordering::SeqCst); + } + } + } + + thread_local! { + static TL_DROP: TlDrop = TlDrop; + } + + TL_DROP.with(|_| {}); + + loop { + match SYNC_STATE.load(Ordering::SeqCst) { + FRESH => thread::yield_now(), + THREAD2_LAUNCHED => break, + v => unreachable!("sync state: {}", v), + } + } + }) + .unwrap(); + + let jh2 = thread::Builder::new() + .name("thread2".into()) + .spawn(move || { + assert_eq!(SYNC_STATE.swap(THREAD2_LAUNCHED, Ordering::SeqCst), FRESH); + jh.join().unwrap(); + match SYNC_STATE.swap(THREAD2_JOINED, Ordering::SeqCst) { + MAIN_THREAD_RENDEZVOUS => return, + THREAD2_LAUNCHED | THREAD1_WAITING => { + panic!("Thread 2 running after thread 1 join before main thread rendezvous") + } + v => unreachable!("sync state: {:?}", v), + } + }) + .unwrap(); + + loop { + match SYNC_STATE.compare_exchange( + THREAD1_WAITING, + MAIN_THREAD_RENDEZVOUS, + Ordering::SeqCst, + Ordering::SeqCst, + ) { + Ok(_) => break, + Err(FRESH) => thread::yield_now(), + Err(THREAD2_LAUNCHED) => thread::yield_now(), + Err(THREAD2_JOINED) => { + panic!("Main thread rendezvous after thread 2 joined thread 1") + } + v => unreachable!("sync state: {:?}", v), + } + } + jh2.join().unwrap(); + } +} + +fn main() { + check_destructors(); + check_blocking(); + join_orders_after_tls_destructors(); +} diff --git a/tests/pass/concurrency/tls_lib_drop_windows.stdout b/tests/pass/concurrency/tls_lib_drop_windows.stdout new file mode 100644 index 0000000000000..e5b8efcaf5fac --- /dev/null +++ b/tests/pass/concurrency/tls_lib_drop_windows.stdout @@ -0,0 +1,5 @@ +Dropping: 15 (should be before 'Continue main 1'). +Dropping: 5 (should be before 'Continue main 1'). +Continue main 1. +Joining: 7 (should be before 'Continue main 2'). +Continue main 2. From a05a8eb805166dcc5408175f16c46303b76c871d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 18 Aug 2022 08:15:41 -0400 Subject: [PATCH 3658/3747] add very basic Android support --- ci.sh | 1 + rust-version | 2 +- src/helpers.rs | 2 +- src/machine.rs | 44 +++++++++++++++----- src/shims/unix/android/dlsym.rs | 53 +++++++++++++++++++++++++ src/shims/unix/android/foreign_items.rs | 23 +++++++++++ src/shims/unix/android/mod.rs | 2 + src/shims/unix/dlsym.rs | 15 ++++--- src/shims/unix/foreign_items.rs | 9 +++-- src/shims/unix/freebsd/dlsym.rs | 4 ++ src/shims/unix/linux/dlsym.rs | 4 ++ src/shims/unix/mod.rs | 1 + src/shims/windows/dlsym.rs | 4 +- 13 files changed, 143 insertions(+), 21 deletions(-) create mode 100644 src/shims/unix/android/dlsym.rs create mode 100644 src/shims/unix/android/foreign_items.rs create mode 100644 src/shims/unix/android/mod.rs diff --git a/ci.sh b/ci.sh index 51cec8fe16196..d1a8db183d146 100755 --- a/ci.sh +++ b/ci.sh @@ -84,6 +84,7 @@ case $HOST_TARGET in MIRI_TEST_TARGET=aarch64-apple-darwin run_tests MIRI_TEST_TARGET=i686-pc-windows-msvc run_tests MIRI_TEST_TARGET=x86_64-unknown-freebsd run_tests_minimal hello integer vec data_race env/var + MIRI_TEST_TARGET=aarch64-linux-android run_tests_minimal hello integer vec MIRI_TEST_TARGET=thumbv7em-none-eabihf MIRI_NO_STD=1 run_tests_minimal no_std # no_std embedded architecture ;; x86_64-apple-darwin) diff --git a/rust-version b/rust-version index 7317986eaea43..45dbb37c86acc 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -8556e6620e4866526b3cea767ad8c20ae877a569 +9c20b2a8cc7588decb6de25ac6a7912dcef24d65 diff --git a/src/helpers.rs b/src/helpers.rs index 7c9f8740eb420..d63bf97ad51dd 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -954,5 +954,5 @@ pub fn get_local_crates(tcx: TyCtxt<'_>) -> Vec { /// Helper function used inside the shims of foreign functions to check that /// `target_os` is a supported UNIX OS. pub fn target_os_is_unix(target_os: &str) -> bool { - matches!(target_os, "linux" | "macos" | "freebsd") + matches!(target_os, "linux" | "macos" | "freebsd" | "android") } diff --git a/src/machine.rs b/src/machine.rs index 4ebf7dceab839..d45f5de381f35 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -232,13 +232,15 @@ pub struct PrimitiveLayouts<'tcx> { pub u32: TyAndLayout<'tcx>, pub usize: TyAndLayout<'tcx>, pub bool: TyAndLayout<'tcx>, - pub mut_raw_ptr: TyAndLayout<'tcx>, + pub mut_raw_ptr: TyAndLayout<'tcx>, // *mut () + pub const_raw_ptr: TyAndLayout<'tcx>, // *const () } impl<'mir, 'tcx: 'mir> PrimitiveLayouts<'tcx> { fn new(layout_cx: LayoutCx<'tcx, TyCtxt<'tcx>>) -> Result> { let tcx = layout_cx.tcx; let mut_raw_ptr = tcx.mk_ptr(TypeAndMut { ty: tcx.types.unit, mutbl: Mutability::Mut }); + let const_raw_ptr = tcx.mk_ptr(TypeAndMut { ty: tcx.types.unit, mutbl: Mutability::Not }); Ok(Self { unit: layout_cx.layout_of(tcx.mk_unit())?, i8: layout_cx.layout_of(tcx.types.i8)?, @@ -251,6 +253,7 @@ impl<'mir, 'tcx: 'mir> PrimitiveLayouts<'tcx> { usize: layout_cx.layout_of(tcx.types.usize)?, bool: layout_cx.layout_of(tcx.types.bool)?, mut_raw_ptr: layout_cx.layout_of(mut_raw_ptr)?, + const_raw_ptr: layout_cx.layout_of(const_raw_ptr)?, }) } } @@ -431,6 +434,17 @@ impl<'mir, 'tcx> Evaluator<'mir, 'tcx> { this.machine.extern_statics.try_insert(Symbol::intern(name), ptr).unwrap(); } + fn alloc_extern_static( + this: &mut MiriEvalContext<'mir, 'tcx>, + name: &str, + val: ImmTy<'tcx, Provenance>, + ) -> InterpResult<'tcx> { + let place = this.allocate(val.layout, MiriMemoryKind::ExternStatic.into())?; + this.write_immediate(*val, &place.into())?; + Self::add_extern_static(this, name, place.ptr); + Ok(()) + } + /// Sets up the "extern statics" for this machine. fn init_extern_statics(this: &mut MiriEvalContext<'mir, 'tcx>) -> InterpResult<'tcx> { match this.tcx.sess.target.os.as_ref() { @@ -447,10 +461,8 @@ impl<'mir, 'tcx> Evaluator<'mir, 'tcx> { // syscall that we do support). for name in &["__cxa_thread_atexit_impl", "getrandom", "statx", "__clock_gettime64"] { - let layout = this.machine.layouts.usize; - let place = this.allocate(layout, MiriMemoryKind::ExternStatic.into())?; - this.write_scalar(Scalar::from_machine_usize(0, this), &place.into())?; - Self::add_extern_static(this, name, place.ptr); + let val = ImmTy::from_int(0, this.machine.layouts.usize); + Self::alloc_extern_static(this, name, val)?; } } "freebsd" => { @@ -461,13 +473,27 @@ impl<'mir, 'tcx> Evaluator<'mir, 'tcx> { this.machine.env_vars.environ.unwrap().ptr, ); } + "android" => { + // "signal" + let layout = this.machine.layouts.const_raw_ptr; + let dlsym = Dlsym::from_str("signal".as_bytes(), &this.tcx.sess.target.os)? + .expect("`signal` must be an actual dlsym on android"); + let ptr = this.create_fn_alloc_ptr(FnVal::Other(dlsym)); + let val = ImmTy::from_scalar(Scalar::from_pointer(ptr, this), layout); + Self::alloc_extern_static(this, "signal", val)?; + // A couple zero-initialized pointer-sized extern statics. + // Most of them are for weak symbols, which we all set to null (indicating that the + // symbol is not supported, and triggering fallback code.) + for name in &["bsd_signal"] { + let val = ImmTy::from_int(0, this.machine.layouts.usize); + Self::alloc_extern_static(this, name, val)?; + } + } "windows" => { // "_tls_used" // This is some obscure hack that is part of the Windows TLS story. It's a `u8`. - let layout = this.machine.layouts.u8; - let place = this.allocate(layout, MiriMemoryKind::ExternStatic.into())?; - this.write_scalar(Scalar::from_u8(0), &place.into())?; - Self::add_extern_static(this, "_tls_used", place.ptr); + let val = ImmTy::from_int(0, this.machine.layouts.u8); + Self::alloc_extern_static(this, "_tls_used", val)?; } _ => {} // No "extern statics" supported on this target } diff --git a/src/shims/unix/android/dlsym.rs b/src/shims/unix/android/dlsym.rs new file mode 100644 index 0000000000000..a6b24d0fa507d --- /dev/null +++ b/src/shims/unix/android/dlsym.rs @@ -0,0 +1,53 @@ +use rustc_middle::mir; + +use crate::helpers::check_arg_count; +use crate::*; + +#[derive(Debug, Copy, Clone)] +#[allow(non_camel_case_types)] +pub enum Dlsym { + signal, +} + +impl Dlsym { + // Returns an error for unsupported symbols, and None if this symbol + // should become a NULL pointer (pretend it does not exist). + pub fn from_str<'tcx>(name: &str) -> InterpResult<'tcx, Option> { + Ok(match &*name { + "signal" => Some(Dlsym::signal), + _ => throw_unsup_format!("unsupported Android dlsym: {}", name), + }) + } +} + +impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} +pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { + fn call_dlsym( + &mut self, + dlsym: Dlsym, + args: &[OpTy<'tcx, Provenance>], + dest: &PlaceTy<'tcx, Provenance>, + ret: Option, + ) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + let ret = ret.expect("we don't support any diverging dlsym"); + assert!(this.tcx.sess.target.os == "android"); + + match dlsym { + Dlsym::signal => { + if !this.frame_in_std() { + throw_unsup_format!( + "`signal` support is crude and just enough for libstd to work" + ); + } + + let &[ref _sig, ref _func] = check_arg_count(args)?; + this.write_null(dest)?; + } + } + + log::trace!("{:?}", this.dump_place(**dest)); + this.go_to_block(ret); + Ok(()) + } +} diff --git a/src/shims/unix/android/foreign_items.rs b/src/shims/unix/android/foreign_items.rs new file mode 100644 index 0000000000000..cde98b31e0318 --- /dev/null +++ b/src/shims/unix/android/foreign_items.rs @@ -0,0 +1,23 @@ +use rustc_span::Symbol; +use rustc_target::spec::abi::Abi; + +use crate::*; +use shims::foreign_items::EmulateByNameResult; + +impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} + +pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { + fn emulate_foreign_item_by_name( + &mut self, + link_name: Symbol, + _abi: Abi, + _args: &[OpTy<'tcx, Provenance>], + _dest: &PlaceTy<'tcx, Provenance>, + ) -> InterpResult<'tcx, EmulateByNameResult<'mir, 'tcx>> { + let _this = self.eval_context_mut(); + match link_name.as_str() { + _ => return Ok(EmulateByNameResult::NotSupported), + } + //Ok(EmulateByNameResult::NeedsJumping) + } +} diff --git a/src/shims/unix/android/mod.rs b/src/shims/unix/android/mod.rs new file mode 100644 index 0000000000000..434f5f30b5a56 --- /dev/null +++ b/src/shims/unix/android/mod.rs @@ -0,0 +1,2 @@ +pub mod dlsym; +pub mod foreign_items; diff --git a/src/shims/unix/dlsym.rs b/src/shims/unix/dlsym.rs index a806c16e28bbb..fee1282291792 100644 --- a/src/shims/unix/dlsym.rs +++ b/src/shims/unix/dlsym.rs @@ -2,15 +2,17 @@ use rustc_middle::mir; use rustc_target::spec::abi::Abi; use crate::*; +use shims::unix::android::dlsym as android; use shims::unix::freebsd::dlsym as freebsd; use shims::unix::linux::dlsym as linux; use shims::unix::macos::dlsym as macos; #[derive(Debug, Copy, Clone)] pub enum Dlsym { + Android(android::Dlsym), + FreeBsd(freebsd::Dlsym), Linux(linux::Dlsym), MacOs(macos::Dlsym), - FreeBsd(freebsd::Dlsym), } impl Dlsym { @@ -18,10 +20,11 @@ impl Dlsym { // should become a NULL pointer (pretend it does not exist). pub fn from_str<'tcx>(name: &str, target_os: &str) -> InterpResult<'tcx, Option> { Ok(match target_os { + "android" => android::Dlsym::from_str(name)?.map(Dlsym::Android), + "freebsd" => freebsd::Dlsym::from_str(name)?.map(Dlsym::FreeBsd), "linux" => linux::Dlsym::from_str(name)?.map(Dlsym::Linux), "macos" => macos::Dlsym::from_str(name)?.map(Dlsym::MacOs), - "freebsd" => freebsd::Dlsym::from_str(name)?.map(Dlsym::FreeBsd), - _ => unreachable!(), + _ => panic!("unsupported Unix OS {target_os}"), }) } } @@ -41,10 +44,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.check_abi(abi, Abi::C { unwind: false })?; match dlsym { - Dlsym::Linux(dlsym) => linux::EvalContextExt::call_dlsym(this, dlsym, args, dest, ret), - Dlsym::MacOs(dlsym) => macos::EvalContextExt::call_dlsym(this, dlsym, args, dest, ret), + Dlsym::Android(dlsym) => + android::EvalContextExt::call_dlsym(this, dlsym, args, dest, ret), Dlsym::FreeBsd(dlsym) => freebsd::EvalContextExt::call_dlsym(this, dlsym, args, dest, ret), + Dlsym::Linux(dlsym) => linux::EvalContextExt::call_dlsym(this, dlsym, args, dest, ret), + Dlsym::MacOs(dlsym) => macos::EvalContextExt::call_dlsym(this, dlsym, args, dest, ret), } } } diff --git a/src/shims/unix/foreign_items.rs b/src/shims/unix/foreign_items.rs index 877a144963a2a..58b0997c6c017 100644 --- a/src/shims/unix/foreign_items.rs +++ b/src/shims/unix/foreign_items.rs @@ -24,6 +24,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, EmulateByNameResult<'mir, 'tcx>> { let this = self.eval_context_mut(); + #[rustfmt::skip] match link_name.as_str() { // Environment related shims "getenv" => { @@ -588,11 +589,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Platform-specific shims _ => { - match this.tcx.sess.target.os.as_ref() { + let target_os = &*this.tcx.sess.target.os; + match target_os { + "android" => return shims::unix::android::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, abi, args, dest), + "freebsd" => return shims::unix::freebsd::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, abi, args, dest), "linux" => return shims::unix::linux::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, abi, args, dest), "macos" => return shims::unix::macos::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, abi, args, dest), - "freebsd" => return shims::unix::freebsd::foreign_items::EvalContextExt::emulate_foreign_item_by_name(this, link_name, abi, args, dest), - _ => unreachable!(), + _ => panic!("unsupported Unix OS {target_os}"), } } }; diff --git a/src/shims/unix/freebsd/dlsym.rs b/src/shims/unix/freebsd/dlsym.rs index 74c322c666d48..ebc1998f1b579 100644 --- a/src/shims/unix/freebsd/dlsym.rs +++ b/src/shims/unix/freebsd/dlsym.rs @@ -28,5 +28,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx assert!(this.tcx.sess.target.os == "freebsd"); match dlsym {} + + //trace!("{:?}", this.dump_place(**dest)); + //this.go_to_block(ret); + //Ok(()) } } diff --git a/src/shims/unix/linux/dlsym.rs b/src/shims/unix/linux/dlsym.rs index 44d51c4a0b3ab..f5cf1e0071a9d 100644 --- a/src/shims/unix/linux/dlsym.rs +++ b/src/shims/unix/linux/dlsym.rs @@ -32,5 +32,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx assert!(this.tcx.sess.target.os == "linux"); match dlsym {} + + //trace!("{:?}", this.dump_place(**dest)); + //this.go_to_block(ret); + //Ok(()) } } diff --git a/src/shims/unix/mod.rs b/src/shims/unix/mod.rs index 35380fc06d79b..6fefb054f3c04 100644 --- a/src/shims/unix/mod.rs +++ b/src/shims/unix/mod.rs @@ -5,6 +5,7 @@ mod fs; mod sync; mod thread; +mod android; mod freebsd; mod linux; mod macos; diff --git a/src/shims/windows/dlsym.rs b/src/shims/windows/dlsym.rs index eab5f99c87851..e14c2a86b09cc 100644 --- a/src/shims/windows/dlsym.rs +++ b/src/shims/windows/dlsym.rs @@ -45,7 +45,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Dlsym::NtWriteFile => { if !this.frame_in_std() { throw_unsup_format!( - "NtWriteFile support is crude and just enough for stdout to work" + "`NtWriteFile` support is crude and just enough for stdout to work" ); } @@ -68,7 +68,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx if byte_offset != 0 { throw_unsup_format!( - "NtWriteFile ByteOffset paremeter is non-null, which is unsupported" + "`NtWriteFile` `ByteOffset` paremeter is non-null, which is unsupported" ); } From 3ec8dd87608b47ecc4f0eaa832a927f38f133eb1 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 18 Aug 2022 08:25:28 -0400 Subject: [PATCH 3659/3747] implement setting the thread name on freebsd --- ci.sh | 2 +- src/shims/unix/freebsd/foreign_items.rs | 12 +++++++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/ci.sh b/ci.sh index d1a8db183d146..f93c9700c5a1c 100755 --- a/ci.sh +++ b/ci.sh @@ -83,7 +83,7 @@ case $HOST_TARGET in MIRI_TEST_TARGET=i686-unknown-linux-gnu run_tests MIRI_TEST_TARGET=aarch64-apple-darwin run_tests MIRI_TEST_TARGET=i686-pc-windows-msvc run_tests - MIRI_TEST_TARGET=x86_64-unknown-freebsd run_tests_minimal hello integer vec data_race env/var + MIRI_TEST_TARGET=x86_64-unknown-freebsd run_tests_minimal hello integer vec panic/panic concurrency/simple atomic data_race env/var MIRI_TEST_TARGET=aarch64-linux-android run_tests_minimal hello integer vec MIRI_TEST_TARGET=thumbv7em-none-eabihf MIRI_NO_STD=1 run_tests_minimal no_std # no_std embedded architecture ;; diff --git a/src/shims/unix/freebsd/foreign_items.rs b/src/shims/unix/freebsd/foreign_items.rs index 658711526d00c..92e76ff09dcb5 100644 --- a/src/shims/unix/freebsd/foreign_items.rs +++ b/src/shims/unix/freebsd/foreign_items.rs @@ -3,6 +3,7 @@ use rustc_target::spec::abi::Abi; use crate::*; use shims::foreign_items::EmulateByNameResult; +use shims::unix::thread::EvalContextExt as _; impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} @@ -16,12 +17,21 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, EmulateByNameResult<'mir, 'tcx>> { let this = self.eval_context_mut(); match link_name.as_str() { - // Linux's `pthread_getattr_np` equivalent + // Threading "pthread_attr_get_np" if this.frame_in_std() => { let [_thread, _attr] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; this.write_null(dest)?; } + "pthread_set_name_np" => { + let [thread, name] = + this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + let res = this.pthread_setname_np( + this.read_scalar(thread)?.check_init()?, + this.read_scalar(name)?.check_init()?, + )?; + this.write_scalar(res, dest)?; + } // errno "__error" => { From 4359f43e922a07d26dd9942f184289289d2aef84 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 18 Aug 2022 08:39:53 -0400 Subject: [PATCH 3660/3747] make abort-on-panic work on Android --- ci.sh | 2 +- src/shims/unix/android/dlsym.rs | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/ci.sh b/ci.sh index f93c9700c5a1c..d70feec66f268 100755 --- a/ci.sh +++ b/ci.sh @@ -84,7 +84,7 @@ case $HOST_TARGET in MIRI_TEST_TARGET=aarch64-apple-darwin run_tests MIRI_TEST_TARGET=i686-pc-windows-msvc run_tests MIRI_TEST_TARGET=x86_64-unknown-freebsd run_tests_minimal hello integer vec panic/panic concurrency/simple atomic data_race env/var - MIRI_TEST_TARGET=aarch64-linux-android run_tests_minimal hello integer vec + MIRI_TEST_TARGET=aarch64-linux-android run_tests_minimal hello integer vec panic/panic MIRI_TEST_TARGET=thumbv7em-none-eabihf MIRI_NO_STD=1 run_tests_minimal no_std # no_std embedded architecture ;; x86_64-apple-darwin) diff --git a/src/shims/unix/android/dlsym.rs b/src/shims/unix/android/dlsym.rs index a6b24d0fa507d..3e9b00fbe5f2e 100644 --- a/src/shims/unix/android/dlsym.rs +++ b/src/shims/unix/android/dlsym.rs @@ -15,6 +15,7 @@ impl Dlsym { pub fn from_str<'tcx>(name: &str) -> InterpResult<'tcx, Option> { Ok(match &*name { "signal" => Some(Dlsym::signal), + "android_set_abort_message" => None, _ => throw_unsup_format!("unsupported Android dlsym: {}", name), }) } From 5e10f14584f20f8b0b7716916a0d08e836696ef4 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 18 Aug 2022 09:13:07 -0400 Subject: [PATCH 3661/3747] clippy... --- src/lib.rs | 1 + src/shims/unix/android/dlsym.rs | 2 +- src/shims/unix/android/foreign_items.rs | 5 ++++- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index ba337f28311e9..2c30ee06c0573 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -24,6 +24,7 @@ clippy::derive_hash_xor_eq, clippy::too_many_arguments, clippy::type_complexity, + clippy::single_element_loop, // We are not implementing queries here so it's fine rustc::potential_query_instability )] diff --git a/src/shims/unix/android/dlsym.rs b/src/shims/unix/android/dlsym.rs index 3e9b00fbe5f2e..28941a3de4ecc 100644 --- a/src/shims/unix/android/dlsym.rs +++ b/src/shims/unix/android/dlsym.rs @@ -13,7 +13,7 @@ impl Dlsym { // Returns an error for unsupported symbols, and None if this symbol // should become a NULL pointer (pretend it does not exist). pub fn from_str<'tcx>(name: &str) -> InterpResult<'tcx, Option> { - Ok(match &*name { + Ok(match name { "signal" => Some(Dlsym::signal), "android_set_abort_message" => None, _ => throw_unsup_format!("unsupported Android dlsym: {}", name), diff --git a/src/shims/unix/android/foreign_items.rs b/src/shims/unix/android/foreign_items.rs index cde98b31e0318..9c12736887fa0 100644 --- a/src/shims/unix/android/foreign_items.rs +++ b/src/shims/unix/android/foreign_items.rs @@ -15,9 +15,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx _dest: &PlaceTy<'tcx, Provenance>, ) -> InterpResult<'tcx, EmulateByNameResult<'mir, 'tcx>> { let _this = self.eval_context_mut(); + #[allow(clippy::match_single_binding)] match link_name.as_str() { _ => return Ok(EmulateByNameResult::NotSupported), } - //Ok(EmulateByNameResult::NeedsJumping) + + #[allow(unreachable_code)] + Ok(EmulateByNameResult::NeedsJumping) } } From c466ac0b3ec200ac53b1ca8196c47261b692bda1 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 18 Aug 2022 11:25:20 -0400 Subject: [PATCH 3662/3747] add some missing assert_target_os --- src/shims/time.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/shims/time.rs b/src/shims/time.rs index e495f723668d7..67303c47db7ee 100644 --- a/src/shims/time.rs +++ b/src/shims/time.rs @@ -197,12 +197,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn nanosleep( &mut self, req_op: &OpTy<'tcx, Provenance>, - _rem: &OpTy<'tcx, Provenance>, + _rem: &OpTy<'tcx, Provenance>, // Signal handlers are not supported, so rem will never be written to. ) -> InterpResult<'tcx, i32> { - // Signal handlers are not supported, so rem will never be written to. - let this = self.eval_context_mut(); + this.assert_target_os_is_unix("nanosleep"); this.check_no_isolation("`nanosleep`")?; let duration = match this.read_timespec(&this.deref_operand(req_op)?)? { @@ -238,6 +237,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn Sleep(&mut self, timeout: &OpTy<'tcx, Provenance>) -> InterpResult<'tcx> { let this = self.eval_context_mut(); + this.assert_target_os("windows", "Sleep"); this.check_no_isolation("`Sleep`")?; let timeout_ms = this.read_scalar(timeout)?.to_u32()?; From 14e72e7ffaef3880279e9f3d2fef7dcf8fc5cb5b Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Sun, 22 May 2022 19:39:09 -0400 Subject: [PATCH 3663/3747] Improve information sharing across SB diagnostics Previous Stacked Borrows diagnostics were missing a lot of information about the state of the interpreter, and it was difficult to add additional state because it was threaded through all the intervening function signatures. This change factors a lot of the arguments which used to be passed individually to many stacked borrows functions into a single `DiagnosticCx`, which is built in `Stacks::for_each`, and since it wraps a handle to `AllocHistory`, we can now handle more nuanced things like heterogeneous borrow of `!Freeze` types. --- src/diagnostics.rs | 21 +- src/helpers.rs | 52 +- src/machine.rs | 26 +- src/stacked_borrows/diagnostics.rs | 512 ++++++++++++++---- src/stacked_borrows/mod.rs | 349 ++++-------- tests/fail/box-cell-alias.stderr | 10 +- .../alias_through_mutation.stderr | 4 +- .../fail/stacked_borrows/aliasing_mut1.stderr | 2 +- .../fail/stacked_borrows/aliasing_mut2.stderr | 2 +- .../fail/stacked_borrows/aliasing_mut3.stderr | 14 +- .../fail/stacked_borrows/aliasing_mut4.stderr | 2 +- .../box_exclusive_violation1.stderr | 4 +- .../stacked_borrows/buggy_as_mut_slice.stderr | 4 +- .../stacked_borrows/buggy_split_at_mut.rs | 2 +- .../stacked_borrows/buggy_split_at_mut.stderr | 10 +- .../stacked_borrows/fnentry_invalidation.rs | 20 + .../fnentry_invalidation.stderr | 28 + .../fail/stacked_borrows/illegal_read1.stderr | 4 +- .../fail/stacked_borrows/illegal_read2.stderr | 4 +- .../fail/stacked_borrows/illegal_read3.stderr | 4 +- .../fail/stacked_borrows/illegal_read4.stderr | 4 +- .../fail/stacked_borrows/illegal_read5.stderr | 4 +- .../fail/stacked_borrows/illegal_read6.stderr | 4 +- tests/fail/stacked_borrows/illegal_read7.rs | 2 +- .../fail/stacked_borrows/illegal_read7.stderr | 10 +- .../fail/stacked_borrows/illegal_read8.stderr | 4 +- .../illegal_read_despite_exposed1.stderr | 10 + .../illegal_read_despite_exposed2.stderr | 10 + .../stacked_borrows/illegal_write1.stderr | 2 +- .../stacked_borrows/illegal_write2.stderr | 4 +- .../stacked_borrows/illegal_write3.stderr | 2 +- .../stacked_borrows/illegal_write4.stderr | 4 +- .../stacked_borrows/illegal_write5.stderr | 4 +- .../stacked_borrows/illegal_write6.stderr | 2 +- .../illegal_write_despite_exposed1.stderr | 10 + tests/fail/stacked_borrows/interior_mut1.rs | 2 +- .../fail/stacked_borrows/interior_mut1.stderr | 10 +- tests/fail/stacked_borrows/interior_mut2.rs | 2 +- .../fail/stacked_borrows/interior_mut2.stderr | 10 +- .../invalidate_against_barrier1.stderr | 2 +- .../invalidate_against_barrier2.stderr | 2 +- .../fail/stacked_borrows/load_invalid_mut.rs | 2 +- .../stacked_borrows/load_invalid_mut.stderr | 10 +- .../fail/stacked_borrows/load_invalid_shr.rs | 2 +- .../stacked_borrows/load_invalid_shr.stderr | 10 +- .../mut_exclusive_violation1.stderr | 4 +- .../mut_exclusive_violation2.stderr | 4 +- .../stacked_borrows/newtype_retagging.stderr | 2 +- .../stacked_borrows/outdated_local.stderr | 4 +- .../fail/stacked_borrows/pass_invalid_mut.rs | 2 +- .../stacked_borrows/pass_invalid_mut.stderr | 10 +- .../fail/stacked_borrows/pass_invalid_shr.rs | 2 +- .../stacked_borrows/pass_invalid_shr.stderr | 10 +- .../stacked_borrows/pointer_smuggling.stderr | 4 +- .../fail/stacked_borrows/raw_tracking.stderr | 4 +- .../stacked_borrows/return_invalid_mut.rs | 2 +- .../stacked_borrows/return_invalid_mut.stderr | 10 +- .../return_invalid_mut_option.rs | 2 +- .../return_invalid_mut_option.stderr | 10 +- .../return_invalid_mut_tuple.rs | 2 +- .../return_invalid_mut_tuple.stderr | 10 +- .../stacked_borrows/return_invalid_shr.rs | 2 +- .../stacked_borrows/return_invalid_shr.stderr | 10 +- .../return_invalid_shr_option.rs | 2 +- .../return_invalid_shr_option.stderr | 10 +- .../return_invalid_shr_tuple.rs | 2 +- .../return_invalid_shr_tuple.stderr | 10 +- .../shared_rw_borrows_are_weak1.rs | 2 +- .../shared_rw_borrows_are_weak1.stderr | 10 +- .../shared_rw_borrows_are_weak2.stderr | 4 +- .../shr_frozen_violation1.stderr | 2 +- tests/fail/stacked_borrows/track_caller.rs | 17 + .../fail/stacked_borrows/track_caller.stderr | 28 + .../transmute-is-no-escape.stderr | 2 +- .../stacked_borrows/unescaped_static.stderr | 2 +- tests/fail/stacked_borrows/zst_slice.rs | 2 +- tests/fail/stacked_borrows/zst_slice.stderr | 8 +- 77 files changed, 876 insertions(+), 521 deletions(-) create mode 100644 tests/fail/stacked_borrows/fnentry_invalidation.rs create mode 100644 tests/fail/stacked_borrows/fnentry_invalidation.stderr create mode 100644 tests/fail/stacked_borrows/track_caller.rs create mode 100644 tests/fail/stacked_borrows/track_caller.stderr diff --git a/src/diagnostics.rs b/src/diagnostics.rs index a378df0ad82b4..eafe56955d1f4 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -178,20 +178,15 @@ pub fn report_error<'tcx, 'mir>( (None, format!("this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental")), (None, format!("see {url} for further information")), ]; - match history { - Some(TagHistory::Tagged {tag, created: (created_range, created_span), invalidated, protected }) => { - let msg = format!("{tag:?} was created by a retag at offsets {created_range:?}"); - helps.push((Some(*created_span), msg)); - if let Some((invalidated_range, invalidated_span)) = invalidated { - let msg = format!("{tag:?} was later invalidated at offsets {invalidated_range:?}"); - helps.push((Some(*invalidated_span), msg)); - } - if let Some((protecting_tag, protecting_tag_span, protection_span)) = protected { - helps.push((Some(*protecting_tag_span), format!("{tag:?} was protected due to {protecting_tag:?} which was created here"))); - helps.push((Some(*protection_span), format!("this protector is live for this call"))); - } + if let Some(TagHistory {created, invalidated, protected}) = history.clone() { + helps.push((Some(created.1), created.0)); + if let Some((msg, span)) = invalidated { + helps.push((Some(span), msg)); + } + if let Some([(protector_msg, protector_span), (protection_msg, protection_span)]) = protected { + helps.push((Some(protector_span), protector_msg)); + helps.push((Some(protection_span), protection_msg)); } - None => {} } helps } diff --git a/src/helpers.rs b/src/helpers.rs index d63bf97ad51dd..6f6cbcc38a777 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -876,8 +876,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } impl<'mir, 'tcx> Evaluator<'mir, 'tcx> { - pub fn current_span(&self) -> CurrentSpan<'_, 'mir, 'tcx> { - CurrentSpan { span: None, machine: self } + pub fn current_span(&self, tcx: TyCtxt<'tcx>) -> CurrentSpan<'_, 'mir, 'tcx> { + CurrentSpan { span: None, machine: self, tcx } } } @@ -888,27 +888,61 @@ impl<'mir, 'tcx> Evaluator<'mir, 'tcx> { #[derive(Clone)] pub struct CurrentSpan<'a, 'mir, 'tcx> { span: Option, + tcx: TyCtxt<'tcx>, machine: &'a Evaluator<'mir, 'tcx>, } -impl<'a, 'mir, 'tcx> CurrentSpan<'a, 'mir, 'tcx> { +impl<'a, 'mir: 'a, 'tcx: 'a + 'mir> CurrentSpan<'a, 'mir, 'tcx> { + /// Get the current span, skipping non-local frames. + /// This function is backed by a cache, and can be assumed to be very fast. pub fn get(&mut self) -> Span { - *self.span.get_or_insert_with(|| Self::current_span(self.machine)) + *self.span.get_or_insert_with(|| Self::current_span(self.tcx, self.machine)) } + /// Similar to `CurrentSpan::get`, but retrieves the parent frame of the first non-local frame. + /// This is useful when we are processing something which occurs on function-entry and we want + /// to point at the call to the function, not the function definition generally. #[inline(never)] - fn current_span(machine: &Evaluator<'_, '_>) -> Span { + pub fn get_parent(&mut self) -> Span { + let idx = Self::current_span_index(self.tcx, self.machine); + Self::nth_span(self.machine, idx.wrapping_sub(1)) + } + + #[inline(never)] + fn current_span(tcx: TyCtxt<'_>, machine: &Evaluator<'_, '_>) -> Span { + let idx = Self::current_span_index(tcx, machine); + Self::nth_span(machine, idx) + } + + fn nth_span(machine: &Evaluator<'_, '_>, idx: usize) -> Span { + machine + .threads + .active_thread_stack() + .get(idx) + .map(Frame::current_span) + .unwrap_or(rustc_span::DUMMY_SP) + } + + // Find the position of the inner-most frame which is part of the crate being + // compiled/executed, part of the Cargo workspace, and is also not #[track_caller]. + fn current_span_index(tcx: TyCtxt<'_>, machine: &Evaluator<'_, '_>) -> usize { machine .threads .active_thread_stack() .iter() + .enumerate() .rev() - .find(|frame| { + .find_map(|(idx, frame)| { let def_id = frame.instance.def_id(); - def_id.is_local() || machine.local_crates.contains(&def_id.krate) + if (def_id.is_local() || machine.local_crates.contains(&def_id.krate)) + && !frame.instance.def.requires_caller_location(tcx) + { + Some(idx) + } else { + None + } }) - .map(|frame| frame.current_span()) - .unwrap_or(rustc_span::DUMMY_SP) + .unwrap_or(0) } } diff --git a/src/machine.rs b/src/machine.rs index 4dc0916067399..7357731f3592c 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -137,7 +137,7 @@ pub enum Provenance { } /// The "extra" information a pointer has over a regular AllocId. -#[derive(Copy, Clone)] +#[derive(Copy, Clone, PartialEq)] pub enum ProvenanceExtra { Concrete(SbTag), Wildcard, @@ -706,15 +706,10 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { } let alloc = alloc.into_owned(); - let stacks = ecx.machine.stacked_borrows.as_ref().map(|stacked_borrows| { - Stacks::new_allocation( - id, - alloc.size(), - stacked_borrows, - kind, - ecx.machine.current_span(), - ) - }); + let stacks = + ecx.machine.stacked_borrows.as_ref().map(|stacked_borrows| { + Stacks::new_allocation(id, alloc.size(), stacked_borrows, kind) + }); let race_alloc = ecx.machine.data_race.as_ref().map(|data_race| { data_race::AllocExtra::new_allocation( data_race, @@ -808,7 +803,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { #[inline(always)] fn before_memory_read( - _tcx: TyCtxt<'tcx>, + tcx: TyCtxt<'tcx>, machine: &Self, alloc_extra: &AllocExtra, (alloc_id, prov_extra): (AllocId, Self::ProvenanceExtra), @@ -828,7 +823,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { prov_extra, range, machine.stacked_borrows.as_ref().unwrap(), - machine.current_span(), + machine.current_span(tcx), &machine.threads, )?; } @@ -840,7 +835,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { #[inline(always)] fn before_memory_write( - _tcx: TyCtxt<'tcx>, + tcx: TyCtxt<'tcx>, machine: &mut Self, alloc_extra: &mut AllocExtra, (alloc_id, prov_extra): (AllocId, Self::ProvenanceExtra), @@ -860,7 +855,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { prov_extra, range, machine.stacked_borrows.as_ref().unwrap(), - machine.current_span(), + machine.current_span(tcx), &machine.threads, )?; } @@ -872,7 +867,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { #[inline(always)] fn before_memory_deallocation( - _tcx: TyCtxt<'tcx>, + tcx: TyCtxt<'tcx>, machine: &mut Self, alloc_extra: &mut AllocExtra, (alloc_id, prove_extra): (AllocId, Self::ProvenanceExtra), @@ -895,6 +890,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { prove_extra, range, machine.stacked_borrows.as_ref().unwrap(), + machine.current_span(tcx), &machine.threads, ) } else { diff --git a/src/stacked_borrows/diagnostics.rs b/src/stacked_borrows/diagnostics.rs index 6521f0772112d..ac2783670cfff 100644 --- a/src/stacked_borrows/diagnostics.rs +++ b/src/stacked_borrows/diagnostics.rs @@ -1,91 +1,294 @@ use smallvec::SmallVec; +use std::fmt; -use rustc_middle::mir::interpret::{AllocId, AllocRange}; +use rustc_middle::mir::interpret::{alloc_range, AllocId, AllocRange}; use rustc_span::{Span, SpanData}; use rustc_target::abi::Size; use crate::helpers::CurrentSpan; -use crate::stacked_borrows::{err_sb_ub, AccessKind}; +use crate::stacked_borrows::{err_sb_ub, AccessKind, GlobalStateInner, Permission}; use crate::*; use rustc_middle::mir::interpret::InterpError; #[derive(Clone, Debug)] pub struct AllocHistory { - // The time tags can be compressed down to one bit per event, by just storing a Vec - // where each bit is set to indicate if the event was a creation or a retag - current_time: usize, - creations: smallvec::SmallVec<[Event; 2]>, - invalidations: smallvec::SmallVec<[Event; 1]>, + id: AllocId, + creations: smallvec::SmallVec<[Creation; 1]>, + invalidations: smallvec::SmallVec<[Invalidation; 1]>, protectors: smallvec::SmallVec<[Protection; 1]>, } #[derive(Clone, Debug)] -struct Protection { - orig_tag: SbTag, - tag: SbTag, +struct Creation { + retag: RetagOp, span: Span, } +impl Creation { + fn generate_diagnostic(&self) -> (String, SpanData) { + let tag = self.retag.new_tag; + if let Some(perm) = self.retag.permission { + ( + format!( + "{tag:?} was created by a {:?} retag at offsets {:?}", + perm, self.retag.range, + ), + self.span.data(), + ) + } else { + assert!(self.retag.range.size == Size::ZERO); + ( + format!( + "{tag:?} would have been created here, but this is a zero-size retag ({:?}) so the tag in question does not exist anywhere", + self.retag.range, + ), + self.span.data(), + ) + } + } +} + #[derive(Clone, Debug)] -struct Event { - parent: Option, +struct Invalidation { tag: SbTag, range: AllocRange, span: Span, + cause: InvalidationCause, } -pub enum TagHistory { - Tagged { - tag: SbTag, - created: (AllocRange, SpanData), - invalidated: Option<(AllocRange, SpanData)>, - protected: Option<(SbTag, SpanData, SpanData)>, - }, +#[derive(Clone, Debug)] +enum InvalidationCause { + Access(AccessKind), + Retag(Permission, RetagCause), +} + +impl Invalidation { + fn generate_diagnostic(&self) -> (String, SpanData) { + ( + format!( + "{:?} was later invalidated at offsets {:?} by a {}", + self.tag, self.range, self.cause + ), + self.span.data(), + ) + } +} + +impl fmt::Display for InvalidationCause { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + InvalidationCause::Access(kind) => write!(f, "{}", kind), + InvalidationCause::Retag(perm, kind) => + if *kind == RetagCause::FnEntry { + write!(f, "{:?} FnEntry retag", perm) + } else { + write!(f, "{:?} retag", perm) + }, + } + } +} + +#[derive(Clone, Debug)] +struct Protection { + orig_tag: ProvenanceExtra, + tag: SbTag, + span: Span, +} + +#[derive(Clone)] +pub struct TagHistory { + pub created: (String, SpanData), + pub invalidated: Option<(String, SpanData)>, + pub protected: Option<([(String, SpanData); 2])>, +} + +pub struct DiagnosticCxBuilder<'ecx, 'mir, 'tcx> { + operation: Operation, + current_span: CurrentSpan<'ecx, 'mir, 'tcx>, + threads: &'ecx ThreadManager<'mir, 'tcx>, +} + +pub struct DiagnosticCx<'ecx, 'mir, 'tcx, 'history> { + operation: Operation, + current_span: CurrentSpan<'ecx, 'mir, 'tcx>, + threads: &'ecx ThreadManager<'mir, 'tcx>, + history: &'history mut AllocHistory, + offset: Size, +} + +impl<'ecx, 'mir, 'tcx, 'history> DiagnosticCxBuilder<'ecx, 'mir, 'tcx> { + pub fn build( + self, + history: &'history mut AllocHistory, + offset: Size, + ) -> DiagnosticCx<'ecx, 'mir, 'tcx, 'history> { + DiagnosticCx { + operation: self.operation, + current_span: self.current_span, + threads: self.threads, + history, + offset, + } + } + + pub fn retag( + current_span: CurrentSpan<'ecx, 'mir, 'tcx>, + threads: &'ecx ThreadManager<'mir, 'tcx>, + cause: RetagCause, + new_tag: SbTag, + orig_tag: ProvenanceExtra, + range: AllocRange, + ) -> Self { + let operation = + Operation::Retag(RetagOp { cause, new_tag, orig_tag, range, permission: None }); + + DiagnosticCxBuilder { current_span, threads, operation } + } + + pub fn read( + current_span: CurrentSpan<'ecx, 'mir, 'tcx>, + threads: &'ecx ThreadManager<'mir, 'tcx>, + tag: ProvenanceExtra, + range: AllocRange, + ) -> Self { + let operation = Operation::Access(AccessOp { kind: AccessKind::Read, tag, range }); + DiagnosticCxBuilder { current_span, threads, operation } + } + + pub fn write( + current_span: CurrentSpan<'ecx, 'mir, 'tcx>, + threads: &'ecx ThreadManager<'mir, 'tcx>, + tag: ProvenanceExtra, + range: AllocRange, + ) -> Self { + let operation = Operation::Access(AccessOp { kind: AccessKind::Write, tag, range }); + DiagnosticCxBuilder { current_span, threads, operation } + } + + pub fn dealloc( + current_span: CurrentSpan<'ecx, 'mir, 'tcx>, + threads: &'ecx ThreadManager<'mir, 'tcx>, + tag: ProvenanceExtra, + ) -> Self { + let operation = Operation::Dealloc(DeallocOp { tag }); + DiagnosticCxBuilder { current_span, threads, operation } + } +} + +impl<'ecx, 'mir, 'tcx, 'history> DiagnosticCx<'ecx, 'mir, 'tcx, 'history> { + pub fn unbuild(self) -> DiagnosticCxBuilder<'ecx, 'mir, 'tcx> { + DiagnosticCxBuilder { + operation: self.operation, + current_span: self.current_span, + threads: self.threads, + } + } +} + +#[derive(Debug, Clone)] +enum Operation { + Retag(RetagOp), + Access(AccessOp), + Dealloc(DeallocOp), +} + +#[derive(Debug, Clone)] +struct RetagOp { + cause: RetagCause, + new_tag: SbTag, + orig_tag: ProvenanceExtra, + range: AllocRange, + permission: Option, +} + +#[derive(Debug, Clone, Copy, PartialEq)] +pub enum RetagCause { + Normal, + FnReturn, + FnEntry, + TwoPhase, +} + +#[derive(Debug, Clone)] +struct AccessOp { + kind: AccessKind, + tag: ProvenanceExtra, + range: AllocRange, +} + +#[derive(Debug, Clone)] +struct DeallocOp { + tag: ProvenanceExtra, } impl AllocHistory { - pub fn new() -> Self { + pub fn new(id: AllocId) -> Self { Self { - current_time: 0, + id, creations: SmallVec::new(), invalidations: SmallVec::new(), protectors: SmallVec::new(), } } +} - pub fn log_creation( - &mut self, - parent: Option, - tag: SbTag, - range: AllocRange, - current_span: &mut CurrentSpan<'_, '_, '_>, - ) { - let span = current_span.get(); - self.creations.push(Event { parent, tag, range, span }); - self.current_time += 1; +impl<'ecx, 'mir, 'tcx, 'history> DiagnosticCx<'ecx, 'mir, 'tcx, 'history> { + pub fn start_grant(&mut self, perm: Permission) { + let Operation::Retag(op) = &mut self.operation else { + unreachable!("start_grant must only be called during a retag, this is: {:?}", self.operation) + }; + op.permission = Some(perm); + + let last_creation = &mut self.history.creations.last_mut().unwrap(); + match last_creation.retag.permission { + None => { + last_creation.retag.permission = Some(perm); + } + Some(previous) => + if previous != perm { + let previous_range = last_creation.retag.range; + last_creation.retag.range = alloc_range(previous_range.start, self.offset); + let mut new_event = last_creation.clone(); + new_event.retag.range = alloc_range(self.offset, previous_range.end()); + new_event.retag.permission = Some(perm); + self.history.creations.push(new_event); + }, + } } - pub fn log_invalidation( - &mut self, - tag: SbTag, - range: AllocRange, - current_span: &mut CurrentSpan<'_, '_, '_>, - ) { - let span = current_span.get(); - self.invalidations.push(Event { parent: None, tag, range, span }); - self.current_time += 1; + pub fn log_creation(&mut self) { + let Operation::Retag(op) = &self.operation else { + unreachable!("log_creation must only be called during a retag") + }; + self.history.creations.push(Creation { retag: op.clone(), span: self.current_span.get() }); } - pub fn log_protector( - &mut self, - orig_tag: SbTag, - tag: SbTag, - current_span: &mut CurrentSpan<'_, '_, '_>, - ) { - let span = current_span.get(); - self.protectors.push(Protection { orig_tag, tag, span }); - self.current_time += 1; + pub fn log_invalidation(&mut self, tag: SbTag) { + let mut span = self.current_span.get(); + let (range, cause) = match &self.operation { + Operation::Retag(RetagOp { cause, range, permission, .. }) => { + if *cause == RetagCause::FnEntry { + span = self.current_span.get_parent(); + } + (*range, InvalidationCause::Retag(permission.unwrap(), *cause)) + } + Operation::Access(AccessOp { kind, range, .. }) => + (*range, InvalidationCause::Access(*kind)), + _ => unreachable!("Tags can only be invalidated during a retag or access"), + }; + self.history.invalidations.push(Invalidation { tag, range, span, cause }); + } + + pub fn log_protector(&mut self) { + let Operation::Retag(op) = &self.operation else { + unreachable!("Protectors can only be created during a retag") + }; + self.history.protectors.push(Protection { + orig_tag: op.orig_tag, + tag: op.new_tag, + span: self.current_span.get(), + }); } pub fn get_logs_relevant_to( @@ -93,9 +296,48 @@ impl AllocHistory { tag: SbTag, protector_tag: Option, ) -> Option { + let Some(created) = self.history + .creations + .iter() + .rev() + .find_map(|event| { + // First, look for a Creation event where the tag and the offset matches. This + // ensrues that we pick the right Creation event when a retag isn't uniform due to + // Freeze. + let range = event.retag.range; + if event.retag.new_tag == tag + && self.offset >= range.start + && self.offset < (range.start + range.size) + { + Some(event.generate_diagnostic()) + } else { + None + } + }) + .or_else(|| { + // If we didn't find anything with a matching offset, just return the event where + // the tag was created. This branch is hit when we use a tag at an offset that + // doesn't have the tag. + self.history.creations.iter().rev().find_map(|event| { + if event.retag.new_tag == tag { + Some(event.generate_diagnostic()) + } else { + None + } + }) + }) else { + // But if we don't have a creation event, this is related to a wildcard, and there + // is really nothing we can do to help. + return None; + }; + + let invalidated = self.history.invalidations.iter().rev().find_map(|event| { + if event.tag == tag { Some(event.generate_diagnostic()) } else { None } + }); + let protected = protector_tag .and_then(|protector| { - self.protectors.iter().find_map(|protection| { + self.history.protectors.iter().find_map(|protection| { if protection.tag == protector { Some((protection.orig_tag, protection.span.data())) } else { @@ -104,77 +346,141 @@ impl AllocHistory { }) }) .and_then(|(tag, call_span)| { - self.creations.iter().rev().find_map(|event| { - if event.tag == tag { - Some((event.parent?, event.span.data(), call_span)) + self.history.creations.iter().rev().find_map(|event| { + if ProvenanceExtra::Concrete(event.retag.new_tag) == tag { + Some((event.retag.orig_tag, event.span.data(), call_span)) } else { None } }) + }) + .map(|(protecting_tag, protecting_tag_span, protection_span)| { + [ + ( + format!( + "{tag:?} was protected due to {protecting_tag:?} which was created here" + ), + protecting_tag_span, + ), + (format!("this protector is live for this call"), protection_span), + ] }); - let get_matching = |events: &[Event]| { - events.iter().rev().find_map(|event| { - if event.tag == tag { Some((event.range, event.span.data())) } else { None } - }) - }; - Some(TagHistory::Tagged { - tag, - created: get_matching(&self.creations)?, - invalidated: get_matching(&self.invalidations), - protected, - }) + Some(TagHistory { created, invalidated, protected }) } /// Report a descriptive error when `new` could not be granted from `derived_from`. - pub fn grant_error<'tcx>( - &self, - derived_from: ProvenanceExtra, - new: Item, - alloc_id: AllocId, - alloc_range: AllocRange, - error_offset: Size, - stack: &Stack, - ) -> InterpError<'tcx> { + pub fn grant_error(&self, perm: Permission, stack: &Stack) -> InterpError<'tcx> { + let Operation::Retag(op) = &self.operation else { + unreachable!("grant_error should only be called during a retag") + }; let action = format!( - "trying to reborrow from {derived_from:?} for {new_perm:?} permission at {alloc_id:?}[{offset:#x}]", - new_perm = new.perm(), - offset = error_offset.bytes(), + "trying to retag from {:?} for {:?} permission at {:?}[{:#x}]", + op.orig_tag, + perm, + self.history.id, + self.offset.bytes(), ); err_sb_ub( - format!("{}{}", action, error_cause(stack, derived_from)), - Some(operation_summary("a reborrow", alloc_id, alloc_range)), - derived_from.and_then(|derived_from| self.get_logs_relevant_to(derived_from, None)), + format!("{}{}", action, error_cause(stack, op.orig_tag)), + Some(operation_summary(&op.cause.summary(), self.history.id, op.range)), + op.orig_tag.and_then(|orig_tag| self.get_logs_relevant_to(orig_tag, None)), ) } /// Report a descriptive error when `access` is not permitted based on `tag`. - pub fn access_error<'tcx>( - &self, - access: AccessKind, - tag: ProvenanceExtra, - alloc_id: AllocId, - alloc_range: AllocRange, - error_offset: Size, - stack: &Stack, - ) -> InterpError<'tcx> { + pub fn access_error(&self, stack: &Stack) -> InterpError<'tcx> { + let Operation::Access(op) = &self.operation else { + unreachable!("access_error should only be called during an access") + }; let action = format!( "attempting a {access} using {tag:?} at {alloc_id:?}[{offset:#x}]", - offset = error_offset.bytes(), + access = op.kind, + tag = op.tag, + alloc_id = self.history.id, + offset = self.offset.bytes(), ); err_sb_ub( - format!("{}{}", action, error_cause(stack, tag)), - Some(operation_summary("an access", alloc_id, alloc_range)), - tag.and_then(|tag| self.get_logs_relevant_to(tag, None)), + format!("{}{}", action, error_cause(stack, op.tag)), + Some(operation_summary("an access", self.history.id, op.range)), + op.tag.and_then(|tag| self.get_logs_relevant_to(tag, None)), ) } + + pub fn protector_error(&self, item: &Item) -> InterpError<'tcx> { + let call_id = self + .threads + .all_stacks() + .flatten() + .map(|frame| { + frame.extra.stacked_borrows.as_ref().expect("we should have Stacked Borrows data") + }) + .find(|frame| frame.protected_tags.contains(&item.tag())) + .map(|frame| frame.call_id) + .unwrap(); // FIXME: Surely we should find something, but a panic seems wrong here? + match self.operation { + Operation::Dealloc(_) => + err_sb_ub( + format!( + "deallocating while item {:?} is protected by call {:?}", + item, call_id + ), + None, + None, + ), + Operation::Retag(RetagOp { orig_tag: tag, .. }) + | Operation::Access(AccessOp { tag, .. }) => + err_sb_ub( + format!( + "not granting access to tag {:?} because incompatible item {:?} is protected by call {:?}", + tag, item, call_id + ), + None, + tag.and_then(|tag| self.get_logs_relevant_to(tag, Some(item.tag()))), + ), + } + } + + pub fn dealloc_error(&self) -> InterpError<'tcx> { + let Operation::Dealloc(op) = &self.operation else { + unreachable!("dealloc_error should only be called during a deallocation") + }; + err_sb_ub( + format!( + "no item granting write access for deallocation to tag {:?} at {:?} found in borrow stack", + op.tag, self.history.id, + ), + None, + op.tag.and_then(|tag| self.get_logs_relevant_to(tag, None)), + ) + } + + #[inline(never)] + pub fn check_tracked_tag_popped(&self, item: &Item, global: &GlobalStateInner) { + if !global.tracked_pointer_tags.contains(&item.tag()) { + return; + } + let summary = match self.operation { + Operation::Dealloc(_) => None, + Operation::Access(AccessOp { kind, tag, .. }) => Some((tag, kind)), + Operation::Retag(RetagOp { orig_tag, permission, .. }) => { + let kind = match permission + .expect("start_grant should set the current permission before popping a tag") + { + Permission::SharedReadOnly => AccessKind::Read, + Permission::Unique => AccessKind::Write, + Permission::SharedReadWrite | Permission::Disabled => { + panic!("Only SharedReadOnly and Unique retags can pop tags"); + } + }; + Some((orig_tag, kind)) + } + }; + register_diagnostic(NonHaltingDiagnostic::PoppedPointerTag(*item, summary)); + } } -fn operation_summary( - operation: &'static str, - alloc_id: AllocId, - alloc_range: AllocRange, -) -> String { +fn operation_summary(operation: &str, alloc_id: AllocId, alloc_range: AllocRange) -> String { format!("this error occurs as part of {operation} at {alloc_id:?}{alloc_range:?}") } @@ -192,3 +498,15 @@ fn error_cause(stack: &Stack, prov_extra: ProvenanceExtra) -> &'static str { ", but no exposed tags have suitable permission in the borrow stack for this location" } } + +impl RetagCause { + fn summary(&self) -> String { + match self { + RetagCause::Normal => "retag", + RetagCause::FnEntry => "FnEntry retag", + RetagCause::FnReturn => "FnReturn retag", + RetagCause::TwoPhase => "two-phase retag", + } + .to_string() + } +} diff --git a/src/stacked_borrows/mod.rs b/src/stacked_borrows/mod.rs index b6b03f1669997..6cb76e7b23aa5 100644 --- a/src/stacked_borrows/mod.rs +++ b/src/stacked_borrows/mod.rs @@ -22,7 +22,7 @@ use smallvec::SmallVec; use crate::*; pub mod diagnostics; -use diagnostics::{AllocHistory, TagHistory}; +use diagnostics::{AllocHistory, DiagnosticCx, DiagnosticCxBuilder, RetagCause, TagHistory}; mod item; pub use item::{Item, Permission}; @@ -142,11 +142,11 @@ pub enum RefKind { impl fmt::Display for RefKind { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { - RefKind::Unique { two_phase: false } => write!(f, "unique"), - RefKind::Unique { two_phase: true } => write!(f, "unique (two-phase)"), - RefKind::Shared => write!(f, "shared"), - RefKind::Raw { mutable: true } => write!(f, "raw (mutable)"), - RefKind::Raw { mutable: false } => write!(f, "raw (constant)"), + RefKind::Unique { two_phase: false } => write!(f, "unique reference"), + RefKind::Unique { two_phase: true } => write!(f, "unique reference (two-phase)"), + RefKind::Shared => write!(f, "shared reference"), + RefKind::Raw { mutable: true } => write!(f, "raw (mutable) pointer"), + RefKind::Raw { mutable: false } => write!(f, "raw (constant) pointer"), } } } @@ -285,94 +285,19 @@ impl<'tcx> Stack { /// currently checking. fn item_popped( item: &Item, - provoking_access: Option<(ProvenanceExtra, AllocRange, Size, AccessKind)>, // just for debug printing and error messages global: &GlobalStateInner, - alloc_history: &mut AllocHistory, - threads: &ThreadManager<'_, 'tcx>, + dcx: &mut DiagnosticCx<'_, '_, 'tcx, '_>, ) -> InterpResult<'tcx> { if !global.tracked_pointer_tags.is_empty() { - check_tracked(item, &provoking_access, global); - - #[inline(never)] // cold path - fn check_tracked( - item: &Item, - provoking_access: &Option<(ProvenanceExtra, AllocRange, Size, AccessKind)>, - global: &GlobalStateInner, - ) { - if global.tracked_pointer_tags.contains(&item.tag()) { - register_diagnostic(NonHaltingDiagnostic::PoppedPointerTag( - *item, - provoking_access.map(|(tag, _alloc_range, _size, access)| (tag, access)), - )); - } - } + dcx.check_tracked_tag_popped(item, global); } if !item.protected() { return Ok(()); } - // We store tags twice, once in global.protected_tags and once in each call frame. - // We do this because consulting a single global set in this function is faster - // than attempting to search all call frames in the program for the `FrameExtra` - // (if any) which is protecting the popped tag. - // - // This duplication trades off making `end_call` slower to make this function faster. This - // trade-off is profitable in practice for a combination of two reasons. - // 1. A single protected tag can (and does in some programs) protect thousands of `Item`s. - // Therefore, adding overhead to in function call/return is profitable even if it only - // saves a little work in this function. - // 2. Most frames protect only one or two tags. So this duplicative global turns a search - // which ends up about linear in the number of protected tags in the program into a - // constant time check (and a slow linear, because the tags in the frames aren't contiguous). if global.protected_tags.contains(&item.tag()) { - return Err(protector_error(item, &provoking_access, alloc_history, threads)); - - #[inline(never)] // cold path - fn protector_error<'tcx>( - item: &Item, - provoking_access: &Option<(ProvenanceExtra, AllocRange, Size, AccessKind)>, - alloc_history: &mut AllocHistory, - threads: &ThreadManager<'_, 'tcx>, - ) -> InterpErrorInfo<'tcx> { - // This path is cold because it is fatal to the program. So here it is fine to do the - // more expensive search to figure out which call is responsible for protecting this - // tag. - let call_id = threads - .all_stacks() - .flatten() - .map(|frame| { - frame - .extra - .stacked_borrows - .as_ref() - .expect("we should have Stacked Borrows data") - }) - .find(|frame| frame.protected_tags.contains(&item.tag())) - .map(|frame| frame.call_id) - .unwrap(); // FIXME: Surely we should find something, but a panic seems wrong here? - if let Some((tag, _alloc_range, _offset, _access)) = provoking_access { - err_sb_ub( - format!( - "not granting access to tag {:?} because incompatible item {:?} is protected by call {:?}", - tag, item, call_id - ), - None, - tag.and_then(|tag| { - alloc_history.get_logs_relevant_to(tag, Some(item.tag())) - }), - ) - } else { - err_sb_ub( - format!( - "deallocating while item {:?} is protected by call {:?}", - item, call_id - ), - None, - None, - ) - }.into() - } + return Err(dcx.protector_error(item).into()); } Ok(()) } @@ -385,19 +310,15 @@ impl<'tcx> Stack { &mut self, access: AccessKind, tag: ProvenanceExtra, - (alloc_id, alloc_range, offset): (AllocId, AllocRange, Size), // just for debug printing and error messages global: &mut GlobalStateInner, - current_span: &mut CurrentSpan<'_, '_, 'tcx>, - alloc_history: &mut AllocHistory, + dcx: &mut DiagnosticCx<'_, '_, 'tcx, '_>, exposed_tags: &FxHashSet, - threads: &ThreadManager<'_, 'tcx>, ) -> InterpResult<'tcx> { // Two main steps: Find granting item, remove incompatible items above. // Step 1: Find granting item. - let granting_idx = self.find_granting(access, tag, exposed_tags).map_err(|_| { - alloc_history.access_error(access, tag, alloc_id, alloc_range, offset, self) - })?; + let granting_idx = + self.find_granting(access, tag, exposed_tags).map_err(|_| dcx.access_error(self))?; // Step 2: Remove incompatible items above them. Make sure we do not remove protected // items. Behavior differs for reads and writes. @@ -416,14 +337,8 @@ impl<'tcx> Stack { 0 }; self.pop_items_after(first_incompatible_idx, |item| { - Stack::item_popped( - &item, - Some((tag, alloc_range, offset, access)), - global, - alloc_history, - threads, - )?; - alloc_history.log_invalidation(item.tag(), alloc_range, current_span); + Stack::item_popped(&item, global, dcx)?; + dcx.log_invalidation(item.tag()); Ok(()) })?; } else { @@ -443,14 +358,8 @@ impl<'tcx> Stack { 0 }; self.disable_uniques_starting_at(first_incompatible_idx, |item| { - Stack::item_popped( - &item, - Some((tag, alloc_range, offset, access)), - global, - alloc_history, - threads, - )?; - alloc_history.log_invalidation(item.tag(), alloc_range, current_span); + Stack::item_popped(&item, global, dcx)?; + dcx.log_invalidation(item.tag()); Ok(()) })?; } @@ -487,27 +396,18 @@ impl<'tcx> Stack { fn dealloc( &mut self, tag: ProvenanceExtra, - (alloc_id, _alloc_range, _offset): (AllocId, AllocRange, Size), // just for debug printing and error messages global: &GlobalStateInner, - alloc_history: &mut AllocHistory, + dcx: &mut DiagnosticCx<'_, '_, 'tcx, '_>, exposed_tags: &FxHashSet, - threads: &ThreadManager<'_, 'tcx>, ) -> InterpResult<'tcx> { // Step 1: Make sure there is a granting item. - self.find_granting(AccessKind::Write, tag, exposed_tags).map_err(|_| { - err_sb_ub(format!( - "no item granting write access for deallocation to tag {:?} at {:?} found in borrow stack", - tag, alloc_id, - ), - None, - tag.and_then(|tag| alloc_history.get_logs_relevant_to(tag, None)), - ) - })?; + self.find_granting(AccessKind::Write, tag, exposed_tags) + .map_err(|_| dcx.dealloc_error())?; // Step 2: Consider all items removed. This checks for protectors. for idx in (0..self.len()).rev() { let item = self.get(idx).unwrap(); - Stack::item_popped(&item, None, global, alloc_history, threads)?; + Stack::item_popped(&item, global, dcx)?; } Ok(()) } @@ -522,23 +422,21 @@ impl<'tcx> Stack { &mut self, derived_from: ProvenanceExtra, new: Item, - (alloc_id, alloc_range, offset): (AllocId, AllocRange, Size), // just for debug printing and error messages global: &mut GlobalStateInner, - current_span: &mut CurrentSpan<'_, '_, 'tcx>, - alloc_history: &mut AllocHistory, + dcx: &mut DiagnosticCx<'_, '_, 'tcx, '_>, exposed_tags: &FxHashSet, - threads: &ThreadManager<'_, 'tcx>, ) -> InterpResult<'tcx> { + dcx.start_grant(new.perm()); + // Figure out which access `perm` corresponds to. let access = if new.perm().grants(AccessKind::Write) { AccessKind::Write } else { AccessKind::Read }; // Now we figure out which item grants our parent (`derived_from`) this kind of access. // We use that to determine where to put the new item. - let granting_idx = - self.find_granting(access, derived_from, exposed_tags).map_err(|_| { - alloc_history.grant_error(derived_from, new, alloc_id, alloc_range, offset, self) - })?; + let granting_idx = self + .find_granting(access, derived_from, exposed_tags) + .map_err(|_| dcx.grant_error(new.perm(), self))?; // Compute where to put the new item. // Either way, we ensure that we insert the new item in a way such that between @@ -568,16 +466,7 @@ impl<'tcx> Stack { // A "safe" reborrow for a pointer that actually expects some aliasing guarantees. // Here, creating a reference actually counts as an access. // This ensures F2b for `Unique`, by removing offending `SharedReadOnly`. - self.access( - access, - derived_from, - (alloc_id, alloc_range, offset), - global, - current_span, - alloc_history, - exposed_tags, - threads, - )?; + self.access(access, derived_from, global, dcx, exposed_tags)?; // We insert "as far up as possible": We know only compatible items are remaining // on top of `derived_from`, and we want the new item at the top so that we @@ -596,14 +485,15 @@ impl<'tcx> Stack { /// Map per-stack operations to higher-level per-location-range operations. impl<'tcx> Stacks { - /// Creates new stack with initial tag. - fn new(size: Size, perm: Permission, tag: SbTag) -> Self { + /// Creates a new stack with an initial tag. For diagnostic purposes, we also need to know + /// the [`AllocId`] of the allocation this is associated with. + fn new(size: Size, perm: Permission, tag: SbTag, id: AllocId) -> Self { let item = Item::new(tag, perm, false); let stack = Stack::new(item); Stacks { stacks: RangeMap::new(size, stack), - history: AllocHistory::new(), + history: AllocHistory::new(id), exposed_tags: FxHashSet::default(), } } @@ -612,15 +502,17 @@ impl<'tcx> Stacks { fn for_each( &mut self, range: AllocRange, + mut dcx_builder: DiagnosticCxBuilder<'_, '_, 'tcx>, mut f: impl FnMut( - Size, &mut Stack, - &mut AllocHistory, + &mut DiagnosticCx<'_, '_, 'tcx, '_>, &mut FxHashSet, ) -> InterpResult<'tcx>, ) -> InterpResult<'tcx> { for (offset, stack) in self.stacks.iter_mut(range.start, range.size) { - f(offset, stack, &mut self.history, &mut self.exposed_tags)?; + let mut dcx = dcx_builder.build(&mut self.history, offset); + f(stack, &mut dcx, &mut self.exposed_tags)?; + dcx_builder = dcx.unbuild(); } Ok(()) } @@ -633,7 +525,6 @@ impl Stacks { size: Size, state: &GlobalState, kind: MemoryKind, - mut current_span: CurrentSpan<'_, '_, '_>, ) -> Self { let mut extra = state.borrow_mut(); let (base_tag, perm) = match kind { @@ -646,25 +537,18 @@ impl Stacks { // Everything else is shared by default. _ => (extra.base_ptr_tag(id), Permission::SharedReadWrite), }; - let mut stacks = Stacks::new(size, perm, base_tag); - stacks.history.log_creation( - None, - base_tag, - alloc_range(Size::ZERO, size), - &mut current_span, - ); - stacks + Stacks::new(size, perm, base_tag, id) } #[inline(always)] - pub fn before_memory_read<'tcx>( + pub fn before_memory_read<'tcx, 'mir>( &mut self, alloc_id: AllocId, tag: ProvenanceExtra, range: AllocRange, state: &GlobalState, - mut current_span: CurrentSpan<'_, '_, 'tcx>, - threads: &ThreadManager<'_, 'tcx>, + current_span: CurrentSpan<'_, 'mir, 'tcx>, + threads: &ThreadManager<'mir, 'tcx>, ) -> InterpResult<'tcx> { trace!( "read access with tag {:?}: {:?}, size {}", @@ -672,30 +556,22 @@ impl Stacks { Pointer::new(alloc_id, range.start), range.size.bytes() ); + let dcx = DiagnosticCxBuilder::read(current_span, threads, tag, range); let mut state = state.borrow_mut(); - self.for_each(range, |offset, stack, history, exposed_tags| { - stack.access( - AccessKind::Read, - tag, - (alloc_id, range, offset), - &mut state, - &mut current_span, - history, - exposed_tags, - threads, - ) + self.for_each(range, dcx, |stack, dcx, exposed_tags| { + stack.access(AccessKind::Read, tag, &mut state, dcx, exposed_tags) }) } #[inline(always)] - pub fn before_memory_write<'tcx>( + pub fn before_memory_write<'tcx, 'mir>( &mut self, alloc_id: AllocId, tag: ProvenanceExtra, range: AllocRange, state: &GlobalState, - mut current_span: CurrentSpan<'_, '_, 'tcx>, - threads: &ThreadManager<'_, 'tcx>, + current_span: CurrentSpan<'_, 'mir, 'tcx>, + threads: &ThreadManager<'mir, 'tcx>, ) -> InterpResult<'tcx> { trace!( "write access with tag {:?}: {:?}, size {}", @@ -703,34 +579,28 @@ impl Stacks { Pointer::new(alloc_id, range.start), range.size.bytes() ); + let dcx = DiagnosticCxBuilder::write(current_span, threads, tag, range); let mut state = state.borrow_mut(); - self.for_each(range, |offset, stack, history, exposed_tags| { - stack.access( - AccessKind::Write, - tag, - (alloc_id, range, offset), - &mut state, - &mut current_span, - history, - exposed_tags, - threads, - ) + self.for_each(range, dcx, |stack, dcx, exposed_tags| { + stack.access(AccessKind::Write, tag, &mut state, dcx, exposed_tags) }) } #[inline(always)] - pub fn before_memory_deallocation<'tcx>( + pub fn before_memory_deallocation<'tcx, 'mir>( &mut self, alloc_id: AllocId, tag: ProvenanceExtra, range: AllocRange, state: &GlobalState, - threads: &ThreadManager<'_, 'tcx>, + current_span: CurrentSpan<'_, 'mir, 'tcx>, + threads: &ThreadManager<'mir, 'tcx>, ) -> InterpResult<'tcx> { trace!("deallocation with tag {:?}: {:?}, size {}", tag, alloc_id, range.size.bytes()); + let dcx = DiagnosticCxBuilder::dealloc(current_span, threads, tag); let state = state.borrow(); - self.for_each(range, |offset, stack, history, exposed_tags| { - stack.dealloc(tag, (alloc_id, range, offset), &state, history, exposed_tags, threads) + self.for_each(range, dcx, |stack, dcx, exposed_tags| { + stack.dealloc(tag, &state, dcx, exposed_tags) })?; Ok(()) } @@ -747,15 +617,15 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx place: &MPlaceTy<'tcx, Provenance>, size: Size, kind: RefKind, + retag_cause: RetagCause, // What caused this retag, for diagnostics only new_tag: SbTag, protect: bool, ) -> InterpResult<'tcx, Option> { let this = self.eval_context_mut(); - let current_span = &mut this.machine.current_span(); // It is crucial that this gets called on all code paths, to ensure we track tag creation. let log_creation = |this: &MiriEvalContext<'mir, 'tcx>, - current_span: &mut CurrentSpan<'_, 'mir, 'tcx>, + current_span: CurrentSpan<'_, 'mir, 'tcx>, loc: Option<(AllocId, Size, ProvenanceExtra)>| // alloc_id, base_offset, orig_tag -> InterpResult<'tcx> { let global = this.machine.stacked_borrows.as_ref().unwrap().borrow(); @@ -771,14 +641,8 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx return Ok(()) }; - // The SB history tracking needs a parent tag, so skip if we come from a wildcard. - let ProvenanceExtra::Concrete(orig_tag) = orig_tag else { - // FIXME: should we log this? - return Ok(()) - }; - - let (_size, _align, kind) = this.get_alloc_info(alloc_id); - match kind { + let (_size, _align, alloc_kind) = this.get_alloc_info(alloc_id); + match alloc_kind { AllocKind::LiveData => { // This should have alloc_extra data, but `get_alloc_extra` can still fail // if converting this alloc_id from a global to a local one @@ -789,14 +653,18 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx .as_ref() .expect("we should have Stacked Borrows data") .borrow_mut(); - stacked_borrows.history.log_creation( - Some(orig_tag), + let dcx = DiagnosticCxBuilder::retag( + current_span, + &this.machine.threads, + retag_cause, new_tag, + orig_tag, alloc_range(base_offset, size), - current_span, ); + let mut dcx = dcx.build(&mut stacked_borrows.history, base_offset); + dcx.log_creation(); if protect { - stacked_borrows.history.log_protector(orig_tag, new_tag, current_span); + dcx.log_protector(); } } AllocKind::Function | AllocKind::VTable | AllocKind::Dead => { @@ -806,6 +674,8 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(()) }; + let current_span = this.machine.current_span(*this.tcx); + if size == Size::ZERO { trace!( "reborrow of size 0: {} reference {:?} derived from {:?} (pointee {})", @@ -829,6 +699,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx log_creation(this, current_span, None)?; return Ok(None); } + let (alloc_id, base_offset, orig_tag) = this.ptr_get_alloc_id(place.ptr)?; log_creation(this, current_span, Some((alloc_id, base_offset, orig_tag)))?; @@ -855,11 +726,22 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ); if protect { + // We store tags twice, once in global.protected_tags and once in each call frame. + // We do this because consulting a single global set in this function is faster + // than attempting to search all call frames in the program for the `FrameExtra` + // (if any) which is protecting the popped tag. + // + // This duplication trades off making `end_call` slower to make this function faster. This + // trade-off is profitable in practice for a combination of two reasons. + // 1. A single protected tag can (and does in some programs) protect thousands of `Item`s. + // Therefore, adding overhead to in function call/return is profitable even if it only + // saves a little work in this function. + // 2. Most frames protect only one or two tags. So this duplicative global turns a search + // which ends up about linear in the number of protected tags in the program into a + // constant time check (and a slow linear, because the tags in the frames aren't contiguous). this.frame_mut().extra.stacked_borrows.as_mut().unwrap().protected_tags.push(new_tag); this.machine.stacked_borrows.as_mut().unwrap().get_mut().protected_tags.insert(new_tag); } - // FIXME: can't hold the current span handle across the borrows of self above - let current_span = &mut this.machine.current_span(); // Update the stacks. // Make sure that raw pointers and mutable shared references are reborrowed "weak": @@ -906,26 +788,26 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx }; let item = Item::new(new_tag, perm, protected); let mut global = this.machine.stacked_borrows.as_ref().unwrap().borrow_mut(); - let threads = &this.machine.threads; - stacked_borrows.for_each(range, |offset, stack, history, exposed_tags| { - stack.grant( - orig_tag, - item, - (alloc_id, range, offset), - &mut global, - current_span, - history, - exposed_tags, - threads, - ) + let dcx = DiagnosticCxBuilder::retag( + this.machine.current_span(*this.tcx), + &this.machine.threads, + retag_cause, + new_tag, + orig_tag, + alloc_range(base_offset, size), + ); + stacked_borrows.for_each(range, dcx, |stack, dcx, exposed_tags| { + stack.grant(orig_tag, item, &mut global, dcx, exposed_tags) }) })?; return Ok(Some(alloc_id)); } }; + // Here we can avoid `borrow()` calls because we have mutable references. // Note that this asserts that the allocation is mutable -- but since we are creating a // mutable pointer, that seems reasonable. + let tcx = *this.tcx; let (alloc_extra, machine) = this.get_alloc_extra_mut(alloc_id)?; let mut stacked_borrows = alloc_extra .stacked_borrows @@ -935,19 +817,16 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let item = Item::new(new_tag, perm, protect); let range = alloc_range(base_offset, size); let mut global = machine.stacked_borrows.as_ref().unwrap().borrow_mut(); - let threads = &machine.threads; - let current_span = &mut machine.current_span(); // `get_alloc_extra_mut` invalidated our old `current_span` - stacked_borrows.for_each(range, |offset, stack, history, exposed_tags| { - stack.grant( - orig_tag, - item, - (alloc_id, range, offset), - &mut global, - current_span, - history, - exposed_tags, - threads, - ) + let dcx = DiagnosticCxBuilder::retag( + machine.current_span(tcx), + &machine.threads, + retag_cause, + new_tag, + orig_tag, + alloc_range(base_offset, size), + ); + stacked_borrows.for_each(range, dcx, |stack, dcx, exposed_tags| { + stack.grant(orig_tag, item, &mut global, dcx, exposed_tags) })?; Ok(Some(alloc_id)) @@ -959,6 +838,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx &mut self, val: &ImmTy<'tcx, Provenance>, kind: RefKind, + retag_cause: RetagCause, // What caused this retag, for diagnostics only protect: bool, ) -> InterpResult<'tcx, ImmTy<'tcx, Provenance>> { let this = self.eval_context_mut(); @@ -977,7 +857,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let new_tag = this.machine.stacked_borrows.as_mut().unwrap().get_mut().new_ptr(); // Reborrow. - let alloc_id = this.reborrow(&place, size, kind, new_tag, protect)?; + let alloc_id = this.reborrow(&place, size, kind, retag_cause, new_tag, protect)?; // Adjust pointer. let new_place = place.map_provenance(|p| { @@ -1007,7 +887,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn retag(&mut self, kind: RetagKind, place: &PlaceTy<'tcx, Provenance>) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let retag_fields = this.machine.stacked_borrows.as_mut().unwrap().get_mut().retag_fields; - let mut visitor = RetagVisitor { ecx: this, kind, retag_fields }; + let retag_cause = match kind { + RetagKind::TwoPhase { .. } => RetagCause::TwoPhase, + RetagKind::FnEntry => RetagCause::FnEntry, + RetagKind::Raw | RetagKind::Default => RetagCause::Normal, + }; + let mut visitor = RetagVisitor { ecx: this, kind, retag_cause, retag_fields }; return visitor.visit_value(place); // Determine mutability and whether to add a protector. @@ -1036,6 +921,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx struct RetagVisitor<'ecx, 'mir, 'tcx> { ecx: &'ecx mut MiriEvalContext<'mir, 'tcx>, kind: RetagKind, + retag_cause: RetagCause, retag_fields: bool, } impl<'ecx, 'mir, 'tcx> RetagVisitor<'ecx, 'mir, 'tcx> { @@ -1044,10 +930,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx &mut self, place: &PlaceTy<'tcx, Provenance>, ref_kind: RefKind, + retag_cause: RetagCause, protector: bool, ) -> InterpResult<'tcx> { let val = self.ecx.read_immediate(&self.ecx.place_to_op(place)?)?; - let val = self.ecx.retag_reference(&val, ref_kind, protector)?; + let val = self.ecx.retag_reference(&val, ref_kind, retag_cause, protector)?; self.ecx.write_immediate(*val, place)?; Ok(()) } @@ -1068,13 +955,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx self.retag_place( place, RefKind::Unique { two_phase: false }, + self.retag_cause, /*protector*/ false, ) } fn visit_value(&mut self, place: &PlaceTy<'tcx, Provenance>) -> InterpResult<'tcx> { if let Some((ref_kind, protector)) = qualify(place.layout.ty, self.kind) { - self.retag_place(place, ref_kind, protector)?; + self.retag_place(place, ref_kind, self.retag_cause, protector)?; } else if matches!(place.layout.ty.kind(), ty::RawPtr(..)) { // Wide raw pointers *do* have fields and their types are strange. // vtables have a type like `&[*const (); 3]` or so! @@ -1117,6 +1005,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let val = this.retag_reference( &val, RefKind::Unique { two_phase: false }, + RetagCause::FnReturn, /*protector*/ true, )?; // And use reborrowed pointer for return place. diff --git a/tests/fail/box-cell-alias.stderr b/tests/fail/box-cell-alias.stderr index 705348ba0f06d..1436afcd212be 100644 --- a/tests/fail/box-cell-alias.stderr +++ b/tests/fail/box-cell-alias.stderr @@ -1,20 +1,20 @@ -error: Undefined Behavior: trying to reborrow from for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location +error: Undefined Behavior: trying to retag from for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location --> $DIR/box-cell-alias.rs:LL:CC | LL | unsafe { (*ptr).set(20) }; | ^^^^^^^^^^^^^^ | | - | trying to reborrow from for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location - | this error occurs as part of a reborrow at ALLOC[0x0..0x1] + | trying to retag from for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | this error occurs as part of retag at ALLOC[0x0..0x1] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information -help: was created by a retag at offsets [0x0..0x1] +help: was created by a SharedReadWrite retag at offsets [0x0..0x1] --> $DIR/box-cell-alias.rs:LL:CC | LL | let ptr: *const Cell = &*val; | ^^^^^ -help: was later invalidated at offsets [0x0..0x1] +help: was later invalidated at offsets [0x0..0x1] by a Unique retag --> $DIR/box-cell-alias.rs:LL:CC | LL | let res = helper(val, ptr); diff --git a/tests/fail/stacked_borrows/alias_through_mutation.stderr b/tests/fail/stacked_borrows/alias_through_mutation.stderr index ec985cb26a996..74d1e4ebbcb84 100644 --- a/tests/fail/stacked_borrows/alias_through_mutation.stderr +++ b/tests/fail/stacked_borrows/alias_through_mutation.stderr @@ -9,12 +9,12 @@ LL | let _val = *target_alias; | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information -help: was created by a retag at offsets [0x0..0x4] +help: was created by a SharedReadOnly retag at offsets [0x0..0x4] --> $DIR/alias_through_mutation.rs:LL:CC | LL | *x = &mut *(target as *mut _); | ^^^^^^^^^^^^^^^^^^^^^^^^ -help: was later invalidated at offsets [0x0..0x4] +help: was later invalidated at offsets [0x0..0x4] by a write access --> $DIR/alias_through_mutation.rs:LL:CC | LL | *target = 13; diff --git a/tests/fail/stacked_borrows/aliasing_mut1.stderr b/tests/fail/stacked_borrows/aliasing_mut1.stderr index b821d1e6edb42..e3f05f3350a5c 100644 --- a/tests/fail/stacked_borrows/aliasing_mut1.stderr +++ b/tests/fail/stacked_borrows/aliasing_mut1.stderr @@ -6,7 +6,7 @@ LL | pub fn safe(_x: &mut i32, _y: &mut i32) {} | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information -help: was created by a retag at offsets [0x0..0x4] +help: was created by a Unique retag at offsets [0x0..0x4] --> $DIR/aliasing_mut1.rs:LL:CC | LL | let xraw: *mut i32 = unsafe { mem::transmute(&mut x) }; diff --git a/tests/fail/stacked_borrows/aliasing_mut2.stderr b/tests/fail/stacked_borrows/aliasing_mut2.stderr index 594b578fc09a7..94c2ffa07f715 100644 --- a/tests/fail/stacked_borrows/aliasing_mut2.stderr +++ b/tests/fail/stacked_borrows/aliasing_mut2.stderr @@ -6,7 +6,7 @@ LL | pub fn safe(_x: &i32, _y: &mut i32) {} | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information -help: was created by a retag at offsets [0x0..0x4] +help: was created by a Unique retag at offsets [0x0..0x4] --> $DIR/aliasing_mut2.rs:LL:CC | LL | let xref = &mut x; diff --git a/tests/fail/stacked_borrows/aliasing_mut3.stderr b/tests/fail/stacked_borrows/aliasing_mut3.stderr index 0bb7b8d3a85cf..0fa31260323fb 100644 --- a/tests/fail/stacked_borrows/aliasing_mut3.stderr +++ b/tests/fail/stacked_borrows/aliasing_mut3.stderr @@ -1,24 +1,24 @@ -error: Undefined Behavior: trying to reborrow from for SharedReadOnly permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location +error: Undefined Behavior: trying to retag from for SharedReadOnly permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location --> $DIR/aliasing_mut3.rs:LL:CC | LL | pub fn safe(_x: &mut i32, _y: &i32) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | - | trying to reborrow from for SharedReadOnly permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location - | this error occurs as part of a reborrow at ALLOC[0x0..0x4] + | trying to retag from for SharedReadOnly permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | this error occurs as part of FnEntry retag at ALLOC[0x0..0x4] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information -help: was created by a retag at offsets [0x0..0x4] +help: was created by a SharedReadOnly retag at offsets [0x0..0x4] --> $DIR/aliasing_mut3.rs:LL:CC | LL | safe_raw(xraw, xshr); | ^^^^ -help: was later invalidated at offsets [0x0..0x4] +help: was later invalidated at offsets [0x0..0x4] by a Unique FnEntry retag --> $DIR/aliasing_mut3.rs:LL:CC | -LL | pub fn safe(_x: &mut i32, _y: &i32) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | safe_raw(xraw, xshr); + | ^^^^^^^^^^^^^^^^^^^^ = note: backtrace: = note: inside `safe` at $DIR/aliasing_mut3.rs:LL:CC note: inside `main` at $DIR/aliasing_mut3.rs:LL:CC diff --git a/tests/fail/stacked_borrows/aliasing_mut4.stderr b/tests/fail/stacked_borrows/aliasing_mut4.stderr index 0c7d85ae5756c..f48d39b2e49f0 100644 --- a/tests/fail/stacked_borrows/aliasing_mut4.stderr +++ b/tests/fail/stacked_borrows/aliasing_mut4.stderr @@ -6,7 +6,7 @@ LL | pub fn safe(_x: &i32, _y: &mut Cell) {} | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information -help: was created by a retag at offsets [0x0..0x4] +help: was created by a Unique retag at offsets [0x0..0x4] --> $DIR/aliasing_mut4.rs:LL:CC | LL | let xref = &mut x; diff --git a/tests/fail/stacked_borrows/box_exclusive_violation1.stderr b/tests/fail/stacked_borrows/box_exclusive_violation1.stderr index 7214ef27be33c..dfe49d7f08926 100644 --- a/tests/fail/stacked_borrows/box_exclusive_violation1.stderr +++ b/tests/fail/stacked_borrows/box_exclusive_violation1.stderr @@ -9,12 +9,12 @@ LL | *LEAK = 7; | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information -help: was created by a retag at offsets [0x0..0x4] +help: was created by a SharedReadOnly retag at offsets [0x0..0x4] --> $DIR/box_exclusive_violation1.rs:LL:CC | LL | LEAK = x as *const _ as *mut _; | ^ -help: was later invalidated at offsets [0x0..0x4] +help: was later invalidated at offsets [0x0..0x4] by a write access --> $DIR/box_exclusive_violation1.rs:LL:CC | LL | *our = 5; diff --git a/tests/fail/stacked_borrows/buggy_as_mut_slice.stderr b/tests/fail/stacked_borrows/buggy_as_mut_slice.stderr index 6e78ed6c72983..c0fc247cd4a20 100644 --- a/tests/fail/stacked_borrows/buggy_as_mut_slice.stderr +++ b/tests/fail/stacked_borrows/buggy_as_mut_slice.stderr @@ -9,12 +9,12 @@ LL | v1[1] = 5; | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information -help: was created by a retag at offsets [0x0..0xc] +help: was created by a Unique retag at offsets [0x0..0xc] --> $DIR/buggy_as_mut_slice.rs:LL:CC | LL | let v1 = safe::as_mut_slice(&v); | ^^^^^^^^^^^^^^^^^^^^^^ -help: was later invalidated at offsets [0x0..0xc] +help: was later invalidated at offsets [0x0..0xc] by a Unique retag --> $DIR/buggy_as_mut_slice.rs:LL:CC | LL | unsafe { from_raw_parts_mut(self_.as_ptr() as *mut T, self_.len()) } diff --git a/tests/fail/stacked_borrows/buggy_split_at_mut.rs b/tests/fail/stacked_borrows/buggy_split_at_mut.rs index db64d559c517c..8a1ea86d63385 100644 --- a/tests/fail/stacked_borrows/buggy_split_at_mut.rs +++ b/tests/fail/stacked_borrows/buggy_split_at_mut.rs @@ -19,7 +19,7 @@ mod safe { fn main() { let mut array = [1, 2, 3, 4]; let (a, b) = safe::split_at_mut(&mut array, 0); - //~^ ERROR: /reborrow .* tag does not exist in the borrow stack/ + //~^ ERROR: /retag .* tag does not exist in the borrow stack/ a[1] = 5; b[1] = 6; } diff --git a/tests/fail/stacked_borrows/buggy_split_at_mut.stderr b/tests/fail/stacked_borrows/buggy_split_at_mut.stderr index 41ab9cfa92ae5..b4c5140882f32 100644 --- a/tests/fail/stacked_borrows/buggy_split_at_mut.stderr +++ b/tests/fail/stacked_borrows/buggy_split_at_mut.stderr @@ -1,20 +1,20 @@ -error: Undefined Behavior: trying to reborrow from for Unique permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location +error: Undefined Behavior: trying to retag from for Unique permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location --> $DIR/buggy_split_at_mut.rs:LL:CC | LL | let (a, b) = safe::split_at_mut(&mut array, 0); | ^ | | - | trying to reborrow from for Unique permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location - | this error occurs as part of a reborrow at ALLOC[0x0..0x10] + | trying to retag from for Unique permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | this error occurs as part of retag at ALLOC[0x0..0x10] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information -help: was created by a retag at offsets [0x0..0x10] +help: was created by a Unique retag at offsets [0x0..0x10] --> $DIR/buggy_split_at_mut.rs:LL:CC | LL | from_raw_parts_mut(ptr, len - mid), // BUG: should be "mid" instead of "len - mid" | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -help: was later invalidated at offsets [0x0..0x10] +help: was later invalidated at offsets [0x0..0x10] by a Unique retag --> $DIR/buggy_split_at_mut.rs:LL:CC | LL | from_raw_parts_mut(ptr.offset(mid as isize), len - mid), diff --git a/tests/fail/stacked_borrows/fnentry_invalidation.rs b/tests/fail/stacked_borrows/fnentry_invalidation.rs new file mode 100644 index 0000000000000..37214bebb8285 --- /dev/null +++ b/tests/fail/stacked_borrows/fnentry_invalidation.rs @@ -0,0 +1,20 @@ +// Test that spans displayed in diagnostics identify the function call, not the function +// definition, as the location of invalidation due to FnEntry retag. Technically the FnEntry retag +// occurs inside the function, but what the user wants to know is which call produced the +// invalidation. +fn main() { + let mut x = 0i32; + let z = &mut x as *mut i32; + x.do_bad(); + unsafe { + let _oof = *z; //~ ERROR: /read access .* tag does not exist in the borrow stack/ + } +} + +trait Bad { + fn do_bad(&mut self) { + // who knows + } +} + +impl Bad for i32 {} diff --git a/tests/fail/stacked_borrows/fnentry_invalidation.stderr b/tests/fail/stacked_borrows/fnentry_invalidation.stderr new file mode 100644 index 0000000000000..a66fd32003474 --- /dev/null +++ b/tests/fail/stacked_borrows/fnentry_invalidation.stderr @@ -0,0 +1,28 @@ +error: Undefined Behavior: attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + --> $DIR/fnentry_invalidation.rs:LL:CC + | +LL | let _oof = *z; + | ^^ + | | + | attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | this error occurs as part of an access at ALLOC[0x0..0x4] + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information +help: was created by a SharedReadWrite retag at offsets [0x0..0x4] + --> $DIR/fnentry_invalidation.rs:LL:CC + | +LL | let z = &mut x as *mut i32; + | ^^^^^^ +help: was later invalidated at offsets [0x0..0x4] by a Unique FnEntry retag + --> $DIR/fnentry_invalidation.rs:LL:CC + | +LL | x.do_bad(); + | ^^^^^^^^^^ + = note: backtrace: + = note: inside `main` at $DIR/fnentry_invalidation.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/fail/stacked_borrows/illegal_read1.stderr b/tests/fail/stacked_borrows/illegal_read1.stderr index 3f4ade9a712f0..6e9d491137c85 100644 --- a/tests/fail/stacked_borrows/illegal_read1.stderr +++ b/tests/fail/stacked_borrows/illegal_read1.stderr @@ -9,12 +9,12 @@ LL | let _val = *xref; // ...but any use of raw will invalidate our ref. | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information -help: was created by a retag at offsets [0x0..0x4] +help: was created by a Unique retag at offsets [0x0..0x4] --> $DIR/illegal_read1.rs:LL:CC | LL | let xref = unsafe { &mut *xraw }; // derived from raw, so using raw is still ok... | ^^^^^^^^^^ -help: was later invalidated at offsets [0x0..0x4] +help: was later invalidated at offsets [0x0..0x4] by a read access --> $DIR/illegal_read1.rs:LL:CC | LL | let _val = unsafe { *xraw }; diff --git a/tests/fail/stacked_borrows/illegal_read2.stderr b/tests/fail/stacked_borrows/illegal_read2.stderr index cb0ac56027828..fb1f9ec6a884f 100644 --- a/tests/fail/stacked_borrows/illegal_read2.stderr +++ b/tests/fail/stacked_borrows/illegal_read2.stderr @@ -9,12 +9,12 @@ LL | let _val = *xref; // ...but any use of raw will invalidate our ref. | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information -help: was created by a retag at offsets [0x0..0x4] +help: was created by a Unique retag at offsets [0x0..0x4] --> $DIR/illegal_read2.rs:LL:CC | LL | let xref = unsafe { &mut *xraw }; // derived from raw, so using raw is still ok... | ^^^^^^^^^^ -help: was later invalidated at offsets [0x0..0x4] +help: was later invalidated at offsets [0x0..0x4] by a SharedReadOnly retag --> $DIR/illegal_read2.rs:LL:CC | LL | let shr = unsafe { &*xraw }; diff --git a/tests/fail/stacked_borrows/illegal_read3.stderr b/tests/fail/stacked_borrows/illegal_read3.stderr index bdeca5f7ec86e..55ab8877999ca 100644 --- a/tests/fail/stacked_borrows/illegal_read3.stderr +++ b/tests/fail/stacked_borrows/illegal_read3.stderr @@ -9,12 +9,12 @@ LL | let _val = *xref2; | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information -help: was created by a retag at offsets [0x0..0x4] +help: was created by a Unique retag at offsets [0x0..0x4] --> $DIR/illegal_read3.rs:LL:CC | LL | let xref2 = &mut *xref1; | ^^^^^^^^^^^ -help: was later invalidated at offsets [0x0..0x4] +help: was later invalidated at offsets [0x0..0x4] by a read access --> $DIR/illegal_read3.rs:LL:CC | LL | let _val = unsafe { *xref1.r }; diff --git a/tests/fail/stacked_borrows/illegal_read4.stderr b/tests/fail/stacked_borrows/illegal_read4.stderr index 59c2088c0c85d..3bb064e2f4162 100644 --- a/tests/fail/stacked_borrows/illegal_read4.stderr +++ b/tests/fail/stacked_borrows/illegal_read4.stderr @@ -9,12 +9,12 @@ LL | let _illegal = *xref2; | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information -help: was created by a retag at offsets [0x0..0x4] +help: was created by a Unique retag at offsets [0x0..0x4] --> $DIR/illegal_read4.rs:LL:CC | LL | let xref2 = unsafe { &mut *xraw }; | ^^^^^^^^^^ -help: was later invalidated at offsets [0x0..0x4] +help: was later invalidated at offsets [0x0..0x4] by a read access --> $DIR/illegal_read4.rs:LL:CC | LL | let _val = unsafe { *xraw }; // use the raw again, this invalidates xref2 *even* with the special read except for uniq refs diff --git a/tests/fail/stacked_borrows/illegal_read5.stderr b/tests/fail/stacked_borrows/illegal_read5.stderr index d1506f1996847..e060463cf1d3f 100644 --- a/tests/fail/stacked_borrows/illegal_read5.stderr +++ b/tests/fail/stacked_borrows/illegal_read5.stderr @@ -9,12 +9,12 @@ LL | let _val = *xref; // the mutable one is dead and gone | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information -help: was created by a retag at offsets [$HEX..$HEX] +help: was created by a Unique retag at offsets [$HEX..$HEX] --> $DIR/illegal_read5.rs:LL:CC | LL | let xref: &mut i32 = &mut *refmut; | ^^^^^^^^^^^^ -help: was later invalidated at offsets [$HEX..$HEX] +help: was later invalidated at offsets [$HEX..$HEX] by a read access --> $DIR/illegal_read5.rs:LL:CC | LL | mem::forget(unsafe { ptr::read(xshr) }); // but after reading through the shared ref diff --git a/tests/fail/stacked_borrows/illegal_read6.stderr b/tests/fail/stacked_borrows/illegal_read6.stderr index 5abea6f611a40..8ef720925646a 100644 --- a/tests/fail/stacked_borrows/illegal_read6.stderr +++ b/tests/fail/stacked_borrows/illegal_read6.stderr @@ -9,12 +9,12 @@ LL | let _val = *raw; | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information -help: was created by a retag at offsets [0x0..0x4] +help: was created by a SharedReadWrite retag at offsets [0x0..0x4] --> $DIR/illegal_read6.rs:LL:CC | LL | let raw = x as *mut _; | ^ -help: was later invalidated at offsets [0x0..0x4] +help: was later invalidated at offsets [0x0..0x4] by a Unique retag --> $DIR/illegal_read6.rs:LL:CC | LL | let x = &mut *x; // kill `raw` diff --git a/tests/fail/stacked_borrows/illegal_read7.rs b/tests/fail/stacked_borrows/illegal_read7.rs index c0d3816f4475b..1901e8e4e3480 100644 --- a/tests/fail/stacked_borrows/illegal_read7.rs +++ b/tests/fail/stacked_borrows/illegal_read7.rs @@ -17,6 +17,6 @@ fn main() { // without invalidating `x`. That would be bad! It would mean that creating `shr` // leaked `x` to `raw`. let _val = ptr::read(raw); - let _val = *x.get_mut(); //~ ERROR: /reborrow .* tag does not exist in the borrow stack/ + let _val = *x.get_mut(); //~ ERROR: /retag .* tag does not exist in the borrow stack/ } } diff --git a/tests/fail/stacked_borrows/illegal_read7.stderr b/tests/fail/stacked_borrows/illegal_read7.stderr index 11335df4da0a3..5c42b0a5863c1 100644 --- a/tests/fail/stacked_borrows/illegal_read7.stderr +++ b/tests/fail/stacked_borrows/illegal_read7.stderr @@ -1,20 +1,20 @@ -error: Undefined Behavior: trying to reborrow from for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location +error: Undefined Behavior: trying to retag from for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location --> $DIR/illegal_read7.rs:LL:CC | LL | let _val = *x.get_mut(); | ^^^^^^^^^^^ | | - | trying to reborrow from for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location - | this error occurs as part of a reborrow at ALLOC[0x0..0x4] + | trying to retag from for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | this error occurs as part of two-phase retag at ALLOC[0x0..0x4] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information -help: was created by a retag at offsets [0x0..0x4] +help: was created by a Unique retag at offsets [0x0..0x4] --> $DIR/illegal_read7.rs:LL:CC | LL | let x = &mut *raw; | ^^^^^^^^^ -help: was later invalidated at offsets [0x0..0x4] +help: was later invalidated at offsets [0x0..0x4] by a read access --> $DIR/illegal_read7.rs:LL:CC | LL | let _val = ptr::read(raw); diff --git a/tests/fail/stacked_borrows/illegal_read8.stderr b/tests/fail/stacked_borrows/illegal_read8.stderr index ef150e84f274e..c962d1c3e4032 100644 --- a/tests/fail/stacked_borrows/illegal_read8.stderr +++ b/tests/fail/stacked_borrows/illegal_read8.stderr @@ -9,12 +9,12 @@ LL | let _fail = *y1; | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information -help: was created by a retag at offsets [0x0..0x4] +help: was created by a SharedReadOnly retag at offsets [0x0..0x4] --> $DIR/illegal_read8.rs:LL:CC | LL | let y1: &i32 = mem::transmute(&*x); // launder lifetimes | ^^^^^^^^^^^^^^^^^^^ -help: was later invalidated at offsets [0x0..0x4] +help: was later invalidated at offsets [0x0..0x4] by a write access --> $DIR/illegal_read8.rs:LL:CC | LL | *y2 += 1; diff --git a/tests/fail/stacked_borrows/illegal_read_despite_exposed1.stderr b/tests/fail/stacked_borrows/illegal_read_despite_exposed1.stderr index 7c77c62575d70..4607a9dbf675d 100644 --- a/tests/fail/stacked_borrows/illegal_read_despite_exposed1.stderr +++ b/tests/fail/stacked_borrows/illegal_read_despite_exposed1.stderr @@ -9,6 +9,16 @@ LL | let _val = *root2; | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information +help: was created by a Unique retag at offsets [0x0..0x4] + --> $DIR/illegal_read_despite_exposed1.rs:LL:CC + | +LL | let root2 = &mut *exposed_ptr; + | ^^^^^^^^^^^^^^^^^ +help: was later invalidated at offsets [0x0..0x4] by a write access + --> $DIR/illegal_read_despite_exposed1.rs:LL:CC + | +LL | *exposed_ptr = 0; + | ^^^^^^^^^^^^^^^^ = note: backtrace: = note: inside `main` at $DIR/illegal_read_despite_exposed1.rs:LL:CC diff --git a/tests/fail/stacked_borrows/illegal_read_despite_exposed2.stderr b/tests/fail/stacked_borrows/illegal_read_despite_exposed2.stderr index 4fbbd4c6bedeb..4bf0df7d0625e 100644 --- a/tests/fail/stacked_borrows/illegal_read_despite_exposed2.stderr +++ b/tests/fail/stacked_borrows/illegal_read_despite_exposed2.stderr @@ -9,6 +9,16 @@ LL | let _val = *root2; | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information +help: was created by a Unique retag at offsets [0x0..0x4] + --> $DIR/illegal_read_despite_exposed2.rs:LL:CC + | +LL | let root2 = &mut *exposed_ptr; + | ^^^^^^^^^^^^^^^^^ +help: was later invalidated at offsets [0x0..0x4] by a read access + --> $DIR/illegal_read_despite_exposed2.rs:LL:CC + | +LL | let _val = *exposed_ptr; + | ^^^^^^^^^^^^ = note: backtrace: = note: inside `main` at $DIR/illegal_read_despite_exposed2.rs:LL:CC diff --git a/tests/fail/stacked_borrows/illegal_write1.stderr b/tests/fail/stacked_borrows/illegal_write1.stderr index f939720516922..55ba9aab9bf4e 100644 --- a/tests/fail/stacked_borrows/illegal_write1.stderr +++ b/tests/fail/stacked_borrows/illegal_write1.stderr @@ -9,7 +9,7 @@ LL | unsafe { *x = 42 }; | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information -help: was created by a retag at offsets [0x0..0x4] +help: was created by a SharedReadOnly retag at offsets [0x0..0x4] --> $DIR/illegal_write1.rs:LL:CC | LL | let x: *mut u32 = xref as *const _ as *mut _; diff --git a/tests/fail/stacked_borrows/illegal_write2.stderr b/tests/fail/stacked_borrows/illegal_write2.stderr index 92dacf214f8c2..ceb4ce040b896 100644 --- a/tests/fail/stacked_borrows/illegal_write2.stderr +++ b/tests/fail/stacked_borrows/illegal_write2.stderr @@ -9,12 +9,12 @@ LL | unsafe { *target2 = 13 }; | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information -help: was created by a retag at offsets [0x0..0x4] +help: was created by a SharedReadWrite retag at offsets [0x0..0x4] --> $DIR/illegal_write2.rs:LL:CC | LL | let target2 = target as *mut _; | ^^^^^^ -help: was later invalidated at offsets [0x0..0x4] +help: was later invalidated at offsets [0x0..0x4] by a Unique retag --> $DIR/illegal_write2.rs:LL:CC | LL | drop(&mut *target); // reborrow diff --git a/tests/fail/stacked_borrows/illegal_write3.stderr b/tests/fail/stacked_borrows/illegal_write3.stderr index bb6d189f85205..e091e25190bbf 100644 --- a/tests/fail/stacked_borrows/illegal_write3.stderr +++ b/tests/fail/stacked_borrows/illegal_write3.stderr @@ -9,7 +9,7 @@ LL | unsafe { *ptr = 42 }; | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information -help: was created by a retag at offsets [0x0..0x4] +help: was created by a SharedReadOnly retag at offsets [0x0..0x4] --> $DIR/illegal_write3.rs:LL:CC | LL | let ptr = r#ref as *const _ as *mut _; // raw ptr, with raw tag diff --git a/tests/fail/stacked_borrows/illegal_write4.stderr b/tests/fail/stacked_borrows/illegal_write4.stderr index 97301d64deb3f..d66585ff7f14c 100644 --- a/tests/fail/stacked_borrows/illegal_write4.stderr +++ b/tests/fail/stacked_borrows/illegal_write4.stderr @@ -9,12 +9,12 @@ LL | let _val = *reference; | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information -help: was created by a retag at offsets [0x0..0x4] +help: was created by a SharedReadOnly retag at offsets [0x0..0x4] --> $DIR/illegal_write4.rs:LL:CC | LL | let reference = unsafe { &*raw }; // freeze | ^^^^^ -help: was later invalidated at offsets [0x0..0x4] +help: was later invalidated at offsets [0x0..0x4] by a Unique retag --> $DIR/illegal_write4.rs:LL:CC | LL | let _mut_ref: &mut i32 = unsafe { mem::transmute(raw) }; // &mut, with raw tag diff --git a/tests/fail/stacked_borrows/illegal_write5.stderr b/tests/fail/stacked_borrows/illegal_write5.stderr index 9cb32d7bdfd1c..319c2d77062cb 100644 --- a/tests/fail/stacked_borrows/illegal_write5.stderr +++ b/tests/fail/stacked_borrows/illegal_write5.stderr @@ -9,12 +9,12 @@ LL | let _val = *xref; | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information -help: was created by a retag at offsets [0x0..0x4] +help: was created by a Unique retag at offsets [0x0..0x4] --> $DIR/illegal_write5.rs:LL:CC | LL | let xref = unsafe { &mut *xraw }; | ^^^^^^^^^^ -help: was later invalidated at offsets [0x0..0x4] +help: was later invalidated at offsets [0x0..0x4] by a write access --> $DIR/illegal_write5.rs:LL:CC | LL | unsafe { *xraw = 15 }; diff --git a/tests/fail/stacked_borrows/illegal_write6.stderr b/tests/fail/stacked_borrows/illegal_write6.stderr index 42f7b3f8b54bf..56576b1ff39b5 100644 --- a/tests/fail/stacked_borrows/illegal_write6.stderr +++ b/tests/fail/stacked_borrows/illegal_write6.stderr @@ -6,7 +6,7 @@ LL | unsafe { *y = 2 }; | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information -help: was created by a retag at offsets [0x0..0x4] +help: was created by a SharedReadWrite retag at offsets [0x0..0x4] --> $DIR/illegal_write6.rs:LL:CC | LL | let p = x as *mut u32; diff --git a/tests/fail/stacked_borrows/illegal_write_despite_exposed1.stderr b/tests/fail/stacked_borrows/illegal_write_despite_exposed1.stderr index 0f5834077b3d8..aa436b544126c 100644 --- a/tests/fail/stacked_borrows/illegal_write_despite_exposed1.stderr +++ b/tests/fail/stacked_borrows/illegal_write_despite_exposed1.stderr @@ -9,6 +9,16 @@ LL | let _val = *root2; | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information +help: was created by a SharedReadOnly retag at offsets [0x0..0x4] + --> $DIR/illegal_write_despite_exposed1.rs:LL:CC + | +LL | let root2 = &*exposed_ptr; + | ^^^^^^^^^^^^^ +help: was later invalidated at offsets [0x0..0x4] by a write access + --> $DIR/illegal_write_despite_exposed1.rs:LL:CC + | +LL | *exposed_ptr = 0; + | ^^^^^^^^^^^^^^^^ = note: backtrace: = note: inside `main` at $DIR/illegal_write_despite_exposed1.rs:LL:CC diff --git a/tests/fail/stacked_borrows/interior_mut1.rs b/tests/fail/stacked_borrows/interior_mut1.rs index fda203910a443..6911238fc53e9 100644 --- a/tests/fail/stacked_borrows/interior_mut1.rs +++ b/tests/fail/stacked_borrows/interior_mut1.rs @@ -12,6 +12,6 @@ fn main() { *c.get() = UnsafeCell::new(1); // invalidates inner_shr // stack: [c: SharedReadWrite] - let _val = *inner_shr.get(); //~ ERROR: /reborrow .* tag does not exist in the borrow stack/ + let _val = *inner_shr.get(); //~ ERROR: /retag .* tag does not exist in the borrow stack/ } } diff --git a/tests/fail/stacked_borrows/interior_mut1.stderr b/tests/fail/stacked_borrows/interior_mut1.stderr index a2643841eac1b..3aaca3892a54a 100644 --- a/tests/fail/stacked_borrows/interior_mut1.stderr +++ b/tests/fail/stacked_borrows/interior_mut1.stderr @@ -1,20 +1,20 @@ -error: Undefined Behavior: trying to reborrow from for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location +error: Undefined Behavior: trying to retag from for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location --> $DIR/interior_mut1.rs:LL:CC | LL | let _val = *inner_shr.get(); | ^^^^^^^^^^^^^^^ | | - | trying to reborrow from for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location - | this error occurs as part of a reborrow at ALLOC[0x0..0x4] + | trying to retag from for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | this error occurs as part of retag at ALLOC[0x0..0x4] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information -help: was created by a retag at offsets [0x0..0x4] +help: was created by a SharedReadWrite retag at offsets [0x0..0x4] --> $DIR/interior_mut1.rs:LL:CC | LL | let inner_shr = &*inner_uniq; // adds a SharedReadWrite | ^^^^^^^^^^^^ -help: was later invalidated at offsets [0x0..0x4] +help: was later invalidated at offsets [0x0..0x4] by a write access --> $DIR/interior_mut1.rs:LL:CC | LL | *c.get() = UnsafeCell::new(1); // invalidates inner_shr diff --git a/tests/fail/stacked_borrows/interior_mut2.rs b/tests/fail/stacked_borrows/interior_mut2.rs index 7f8c16c488e79..5e9d177cd038d 100644 --- a/tests/fail/stacked_borrows/interior_mut2.rs +++ b/tests/fail/stacked_borrows/interior_mut2.rs @@ -25,6 +25,6 @@ fn main() { // stack: [c: SharedReadWrite] // now this does not work any more - let _val = *inner_shr.get(); //~ ERROR: /reborrow .* tag does not exist in the borrow stack/ + let _val = *inner_shr.get(); //~ ERROR: /retag .* tag does not exist in the borrow stack/ } } diff --git a/tests/fail/stacked_borrows/interior_mut2.stderr b/tests/fail/stacked_borrows/interior_mut2.stderr index 0dbf6e2ea9f9a..b0141cc34fb65 100644 --- a/tests/fail/stacked_borrows/interior_mut2.stderr +++ b/tests/fail/stacked_borrows/interior_mut2.stderr @@ -1,20 +1,20 @@ -error: Undefined Behavior: trying to reborrow from for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location +error: Undefined Behavior: trying to retag from for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location --> $DIR/interior_mut2.rs:LL:CC | LL | let _val = *inner_shr.get(); | ^^^^^^^^^^^^^^^ | | - | trying to reborrow from for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location - | this error occurs as part of a reborrow at ALLOC[0x0..0x4] + | trying to retag from for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | this error occurs as part of retag at ALLOC[0x0..0x4] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information -help: was created by a retag at offsets [0x0..0x4] +help: was created by a SharedReadWrite retag at offsets [0x0..0x4] --> $DIR/interior_mut2.rs:LL:CC | LL | let inner_shr = &*inner_uniq; | ^^^^^^^^^^^^ -help: was later invalidated at offsets [0x0..0x4] +help: was later invalidated at offsets [0x0..0x4] by a write access --> $DIR/interior_mut2.rs:LL:CC | LL | *c.get() = UnsafeCell::new(0); // now inner_shr gets invalidated diff --git a/tests/fail/stacked_borrows/invalidate_against_barrier1.stderr b/tests/fail/stacked_borrows/invalidate_against_barrier1.stderr index 4a1b14e460941..378f7b7d1ef56 100644 --- a/tests/fail/stacked_borrows/invalidate_against_barrier1.stderr +++ b/tests/fail/stacked_borrows/invalidate_against_barrier1.stderr @@ -6,7 +6,7 @@ LL | let _val = unsafe { *x }; | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information -help: was created by a retag at offsets [0x0..0x4] +help: was created by a SharedReadWrite retag at offsets [0x0..0x4] --> $DIR/invalidate_against_barrier1.rs:LL:CC | LL | let xraw = &mut x as *mut _; diff --git a/tests/fail/stacked_borrows/invalidate_against_barrier2.stderr b/tests/fail/stacked_borrows/invalidate_against_barrier2.stderr index c6f158316f512..0352b671823e6 100644 --- a/tests/fail/stacked_borrows/invalidate_against_barrier2.stderr +++ b/tests/fail/stacked_borrows/invalidate_against_barrier2.stderr @@ -6,7 +6,7 @@ LL | unsafe { *x = 0 }; | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information -help: was created by a retag at offsets [0x0..0x4] +help: was created by a SharedReadWrite retag at offsets [0x0..0x4] --> $DIR/invalidate_against_barrier2.rs:LL:CC | LL | let xraw = &mut x as *mut _; diff --git a/tests/fail/stacked_borrows/load_invalid_mut.rs b/tests/fail/stacked_borrows/load_invalid_mut.rs index 4e3a16b96d025..5c99c82da6d6a 100644 --- a/tests/fail/stacked_borrows/load_invalid_mut.rs +++ b/tests/fail/stacked_borrows/load_invalid_mut.rs @@ -8,5 +8,5 @@ fn main() { let xref = unsafe { &mut *xraw }; let xref_in_mem = Box::new(xref); let _val = unsafe { *xraw }; // invalidate xref - let _val = *xref_in_mem; //~ ERROR: /reborrow .* tag does not exist in the borrow stack/ + let _val = *xref_in_mem; //~ ERROR: /retag .* tag does not exist in the borrow stack/ } diff --git a/tests/fail/stacked_borrows/load_invalid_mut.stderr b/tests/fail/stacked_borrows/load_invalid_mut.stderr index f8e03c631eeeb..43b6ce8d895ea 100644 --- a/tests/fail/stacked_borrows/load_invalid_mut.stderr +++ b/tests/fail/stacked_borrows/load_invalid_mut.stderr @@ -1,20 +1,20 @@ -error: Undefined Behavior: trying to reborrow from for Unique permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location +error: Undefined Behavior: trying to retag from for Unique permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location --> $DIR/load_invalid_mut.rs:LL:CC | LL | let _val = *xref_in_mem; | ^^^^^^^^^^^^ | | - | trying to reborrow from for Unique permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location - | this error occurs as part of a reborrow at ALLOC[0x0..0x4] + | trying to retag from for Unique permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | this error occurs as part of retag at ALLOC[0x0..0x4] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information -help: was created by a retag at offsets [0x0..0x4] +help: was created by a Unique retag at offsets [0x0..0x4] --> $DIR/load_invalid_mut.rs:LL:CC | LL | let xref_in_mem = Box::new(xref); | ^^^^^^^^^^^^^^ -help: was later invalidated at offsets [0x0..0x4] +help: was later invalidated at offsets [0x0..0x4] by a read access --> $DIR/load_invalid_mut.rs:LL:CC | LL | let _val = unsafe { *xraw }; // invalidate xref diff --git a/tests/fail/stacked_borrows/load_invalid_shr.rs b/tests/fail/stacked_borrows/load_invalid_shr.rs index fb279e4710d12..8f94cc07a24f7 100644 --- a/tests/fail/stacked_borrows/load_invalid_shr.rs +++ b/tests/fail/stacked_borrows/load_invalid_shr.rs @@ -8,5 +8,5 @@ fn main() { let xref = unsafe { &*xraw }; let xref_in_mem = Box::new(xref); unsafe { *xraw = 42 }; // unfreeze - let _val = *xref_in_mem; //~ ERROR: /reborrow .* tag does not exist in the borrow stack/ + let _val = *xref_in_mem; //~ ERROR: /retag .* tag does not exist in the borrow stack/ } diff --git a/tests/fail/stacked_borrows/load_invalid_shr.stderr b/tests/fail/stacked_borrows/load_invalid_shr.stderr index a9546c9a7680a..2177ebdd70210 100644 --- a/tests/fail/stacked_borrows/load_invalid_shr.stderr +++ b/tests/fail/stacked_borrows/load_invalid_shr.stderr @@ -1,20 +1,20 @@ -error: Undefined Behavior: trying to reborrow from for SharedReadOnly permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location +error: Undefined Behavior: trying to retag from for SharedReadOnly permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location --> $DIR/load_invalid_shr.rs:LL:CC | LL | let _val = *xref_in_mem; | ^^^^^^^^^^^^ | | - | trying to reborrow from for SharedReadOnly permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location - | this error occurs as part of a reborrow at ALLOC[0x0..0x4] + | trying to retag from for SharedReadOnly permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | this error occurs as part of retag at ALLOC[0x0..0x4] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information -help: was created by a retag at offsets [0x0..0x4] +help: was created by a SharedReadOnly retag at offsets [0x0..0x4] --> $DIR/load_invalid_shr.rs:LL:CC | LL | let xref_in_mem = Box::new(xref); | ^^^^^^^^^^^^^^ -help: was later invalidated at offsets [0x0..0x4] +help: was later invalidated at offsets [0x0..0x4] by a write access --> $DIR/load_invalid_shr.rs:LL:CC | LL | unsafe { *xraw = 42 }; // unfreeze diff --git a/tests/fail/stacked_borrows/mut_exclusive_violation1.stderr b/tests/fail/stacked_borrows/mut_exclusive_violation1.stderr index acc904794fb53..42f872eac62f6 100644 --- a/tests/fail/stacked_borrows/mut_exclusive_violation1.stderr +++ b/tests/fail/stacked_borrows/mut_exclusive_violation1.stderr @@ -9,12 +9,12 @@ LL | *LEAK = 7; | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information -help: was created by a retag at offsets [0x0..0x4] +help: was created by a SharedReadOnly retag at offsets [0x0..0x4] --> $DIR/mut_exclusive_violation1.rs:LL:CC | LL | LEAK = x as *const _ as *mut _; | ^ -help: was later invalidated at offsets [0x0..0x4] +help: was later invalidated at offsets [0x0..0x4] by a write access --> $DIR/mut_exclusive_violation1.rs:LL:CC | LL | *our = 5; diff --git a/tests/fail/stacked_borrows/mut_exclusive_violation2.stderr b/tests/fail/stacked_borrows/mut_exclusive_violation2.stderr index 5bbf9bc518472..1952172d927b7 100644 --- a/tests/fail/stacked_borrows/mut_exclusive_violation2.stderr +++ b/tests/fail/stacked_borrows/mut_exclusive_violation2.stderr @@ -9,12 +9,12 @@ LL | let _val = *raw1; | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information -help: was created by a retag at offsets [0x0..0x4] +help: was created by a Unique retag at offsets [0x0..0x4] --> $DIR/mut_exclusive_violation2.rs:LL:CC | LL | let raw1 = ptr1.as_mut(); | ^^^^^^^^^^^^^ -help: was later invalidated at offsets [0x0..0x4] +help: was later invalidated at offsets [0x0..0x4] by a Unique retag --> $DIR/mut_exclusive_violation2.rs:LL:CC | LL | let _raw2 = ptr2.as_mut(); diff --git a/tests/fail/stacked_borrows/newtype_retagging.stderr b/tests/fail/stacked_borrows/newtype_retagging.stderr index d9aebecfda731..2d26787231dc6 100644 --- a/tests/fail/stacked_borrows/newtype_retagging.stderr +++ b/tests/fail/stacked_borrows/newtype_retagging.stderr @@ -6,7 +6,7 @@ LL | Box(unsafe { Unique::new_unchecked(raw) }, alloc) | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information -help: was created by a retag at offsets [0x0..0x4] +help: was created by a SharedReadWrite retag at offsets [0x0..0x4] --> $DIR/newtype_retagging.rs:LL:CC | LL | let ptr = Box::into_raw(Box::new(0i32)); diff --git a/tests/fail/stacked_borrows/outdated_local.stderr b/tests/fail/stacked_borrows/outdated_local.stderr index d2ada64586312..e111a8227b2aa 100644 --- a/tests/fail/stacked_borrows/outdated_local.stderr +++ b/tests/fail/stacked_borrows/outdated_local.stderr @@ -9,12 +9,12 @@ LL | assert_eq!(unsafe { *y }, 1); | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information -help: was created by a retag at offsets [0x0..0x4] +help: was created by a SharedReadOnly retag at offsets [0x0..0x4] --> $DIR/outdated_local.rs:LL:CC | LL | let y: *const i32 = &x; | ^^ -help: was later invalidated at offsets [0x0..0x4] +help: was later invalidated at offsets [0x0..0x4] by a write access --> $DIR/outdated_local.rs:LL:CC | LL | x = 1; // this invalidates y by reactivating the lowermost uniq borrow for this local diff --git a/tests/fail/stacked_borrows/pass_invalid_mut.rs b/tests/fail/stacked_borrows/pass_invalid_mut.rs index 55c93981e3cd9..8db2c149b17e0 100644 --- a/tests/fail/stacked_borrows/pass_invalid_mut.rs +++ b/tests/fail/stacked_borrows/pass_invalid_mut.rs @@ -6,5 +6,5 @@ fn main() { let xraw = x as *mut _; let xref = unsafe { &mut *xraw }; let _val = unsafe { *xraw }; // invalidate xref - foo(xref); //~ ERROR: /reborrow .* tag does not exist in the borrow stack/ + foo(xref); //~ ERROR: /retag .* tag does not exist in the borrow stack/ } diff --git a/tests/fail/stacked_borrows/pass_invalid_mut.stderr b/tests/fail/stacked_borrows/pass_invalid_mut.stderr index f254fd16dcbe1..5fd9778054458 100644 --- a/tests/fail/stacked_borrows/pass_invalid_mut.stderr +++ b/tests/fail/stacked_borrows/pass_invalid_mut.stderr @@ -1,20 +1,20 @@ -error: Undefined Behavior: trying to reborrow from for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location +error: Undefined Behavior: trying to retag from for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location --> $DIR/pass_invalid_mut.rs:LL:CC | LL | foo(xref); | ^^^^ | | - | trying to reborrow from for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location - | this error occurs as part of a reborrow at ALLOC[0x0..0x4] + | trying to retag from for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | this error occurs as part of two-phase retag at ALLOC[0x0..0x4] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information -help: was created by a retag at offsets [0x0..0x4] +help: was created by a Unique retag at offsets [0x0..0x4] --> $DIR/pass_invalid_mut.rs:LL:CC | LL | let xref = unsafe { &mut *xraw }; | ^^^^^^^^^^ -help: was later invalidated at offsets [0x0..0x4] +help: was later invalidated at offsets [0x0..0x4] by a read access --> $DIR/pass_invalid_mut.rs:LL:CC | LL | let _val = unsafe { *xraw }; // invalidate xref diff --git a/tests/fail/stacked_borrows/pass_invalid_shr.rs b/tests/fail/stacked_borrows/pass_invalid_shr.rs index db8e6681e0de7..903c2733107bb 100644 --- a/tests/fail/stacked_borrows/pass_invalid_shr.rs +++ b/tests/fail/stacked_borrows/pass_invalid_shr.rs @@ -6,5 +6,5 @@ fn main() { let xraw = x as *mut _; let xref = unsafe { &*xraw }; unsafe { *xraw = 42 }; // unfreeze - foo(xref); //~ ERROR: /reborrow .* tag does not exist in the borrow stack/ + foo(xref); //~ ERROR: /retag .* tag does not exist in the borrow stack/ } diff --git a/tests/fail/stacked_borrows/pass_invalid_shr.stderr b/tests/fail/stacked_borrows/pass_invalid_shr.stderr index 28500836aa8d4..0f0df02babb51 100644 --- a/tests/fail/stacked_borrows/pass_invalid_shr.stderr +++ b/tests/fail/stacked_borrows/pass_invalid_shr.stderr @@ -1,20 +1,20 @@ -error: Undefined Behavior: trying to reborrow from for SharedReadOnly permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location +error: Undefined Behavior: trying to retag from for SharedReadOnly permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location --> $DIR/pass_invalid_shr.rs:LL:CC | LL | foo(xref); | ^^^^ | | - | trying to reborrow from for SharedReadOnly permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location - | this error occurs as part of a reborrow at ALLOC[0x0..0x4] + | trying to retag from for SharedReadOnly permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | this error occurs as part of retag at ALLOC[0x0..0x4] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information -help: was created by a retag at offsets [0x0..0x4] +help: was created by a SharedReadOnly retag at offsets [0x0..0x4] --> $DIR/pass_invalid_shr.rs:LL:CC | LL | let xref = unsafe { &*xraw }; | ^^^^^^ -help: was later invalidated at offsets [0x0..0x4] +help: was later invalidated at offsets [0x0..0x4] by a write access --> $DIR/pass_invalid_shr.rs:LL:CC | LL | unsafe { *xraw = 42 }; // unfreeze diff --git a/tests/fail/stacked_borrows/pointer_smuggling.stderr b/tests/fail/stacked_borrows/pointer_smuggling.stderr index 66427bdf64d69..43d689a0f4bbb 100644 --- a/tests/fail/stacked_borrows/pointer_smuggling.stderr +++ b/tests/fail/stacked_borrows/pointer_smuggling.stderr @@ -9,12 +9,12 @@ LL | let _x = unsafe { *PTR }; | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information -help: was created by a retag at offsets [0x0..0x1] +help: was created by a SharedReadWrite retag at offsets [0x0..0x1] --> $DIR/pointer_smuggling.rs:LL:CC | LL | PTR = x; | ^ -help: was later invalidated at offsets [0x0..0x1] +help: was later invalidated at offsets [0x0..0x1] by a write access --> $DIR/pointer_smuggling.rs:LL:CC | LL | *val = 2; // this invalidates any raw ptrs `fun1` might have created. diff --git a/tests/fail/stacked_borrows/raw_tracking.stderr b/tests/fail/stacked_borrows/raw_tracking.stderr index 2028a91142727..fc846f6d9f6a0 100644 --- a/tests/fail/stacked_borrows/raw_tracking.stderr +++ b/tests/fail/stacked_borrows/raw_tracking.stderr @@ -9,12 +9,12 @@ LL | unsafe { *raw1 = 13 }; | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information -help: was created by a retag at offsets [0x0..0x4] +help: was created by a SharedReadWrite retag at offsets [0x0..0x4] --> $DIR/raw_tracking.rs:LL:CC | LL | let raw1 = &mut l as *mut _; | ^^^^^^ -help: was later invalidated at offsets [0x0..0x4] +help: was later invalidated at offsets [0x0..0x4] by a Unique retag --> $DIR/raw_tracking.rs:LL:CC | LL | let raw2 = &mut l as *mut _; // invalidates raw1 diff --git a/tests/fail/stacked_borrows/return_invalid_mut.rs b/tests/fail/stacked_borrows/return_invalid_mut.rs index 1f379d4a77e7a..7d9a6f11aff97 100644 --- a/tests/fail/stacked_borrows/return_invalid_mut.rs +++ b/tests/fail/stacked_borrows/return_invalid_mut.rs @@ -3,7 +3,7 @@ fn foo(x: &mut (i32, i32)) -> &mut i32 { let xraw = x as *mut (i32, i32); let ret = unsafe { &mut (*xraw).1 }; let _val = unsafe { *xraw }; // invalidate xref - ret //~ ERROR: /reborrow .* tag does not exist in the borrow stack/ + ret //~ ERROR: /retag .* tag does not exist in the borrow stack/ } fn main() { diff --git a/tests/fail/stacked_borrows/return_invalid_mut.stderr b/tests/fail/stacked_borrows/return_invalid_mut.stderr index 7c80070443700..c9194208e5dd5 100644 --- a/tests/fail/stacked_borrows/return_invalid_mut.stderr +++ b/tests/fail/stacked_borrows/return_invalid_mut.stderr @@ -1,20 +1,20 @@ -error: Undefined Behavior: trying to reborrow from for Unique permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location +error: Undefined Behavior: trying to retag from for Unique permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location --> $DIR/return_invalid_mut.rs:LL:CC | LL | ret | ^^^ | | - | trying to reborrow from for Unique permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location - | this error occurs as part of a reborrow at ALLOC[0x4..0x8] + | trying to retag from for Unique permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location + | this error occurs as part of retag at ALLOC[0x4..0x8] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information -help: was created by a retag at offsets [0x4..0x8] +help: was created by a Unique retag at offsets [0x4..0x8] --> $DIR/return_invalid_mut.rs:LL:CC | LL | let ret = unsafe { &mut (*xraw).1 }; | ^^^^^^^^^^^^^^ -help: was later invalidated at offsets [0x0..0x8] +help: was later invalidated at offsets [0x0..0x8] by a read access --> $DIR/return_invalid_mut.rs:LL:CC | LL | let _val = unsafe { *xraw }; // invalidate xref diff --git a/tests/fail/stacked_borrows/return_invalid_mut_option.rs b/tests/fail/stacked_borrows/return_invalid_mut_option.rs index da3401260e1e9..7fa9cf77d44b2 100644 --- a/tests/fail/stacked_borrows/return_invalid_mut_option.rs +++ b/tests/fail/stacked_borrows/return_invalid_mut_option.rs @@ -10,7 +10,7 @@ fn foo(x: &mut (i32, i32)) -> Option<&mut i32> { fn main() { match foo(&mut (1, 2)) { - Some(_x) => {} //~ ERROR: /reborrow .* tag does not exist in the borrow stack/ + Some(_x) => {} //~ ERROR: /retag .* tag does not exist in the borrow stack/ None => {} } } diff --git a/tests/fail/stacked_borrows/return_invalid_mut_option.stderr b/tests/fail/stacked_borrows/return_invalid_mut_option.stderr index cab997b47357b..789d0a3aa8293 100644 --- a/tests/fail/stacked_borrows/return_invalid_mut_option.stderr +++ b/tests/fail/stacked_borrows/return_invalid_mut_option.stderr @@ -1,20 +1,20 @@ -error: Undefined Behavior: trying to reborrow from for Unique permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location +error: Undefined Behavior: trying to retag from for Unique permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location --> $DIR/return_invalid_mut_option.rs:LL:CC | LL | Some(_x) => {} | ^^ | | - | trying to reborrow from for Unique permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location - | this error occurs as part of a reborrow at ALLOC[0x4..0x8] + | trying to retag from for Unique permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location + | this error occurs as part of retag at ALLOC[0x4..0x8] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information -help: was created by a retag at offsets [0x4..0x8] +help: was created by a Unique retag at offsets [0x4..0x8] --> $DIR/return_invalid_mut_option.rs:LL:CC | LL | let ret = Some(ret); | ^^^ -help: was later invalidated at offsets [0x0..0x8] +help: was later invalidated at offsets [0x0..0x8] by a read access --> $DIR/return_invalid_mut_option.rs:LL:CC | LL | let _val = unsafe { *xraw }; // invalidate xref diff --git a/tests/fail/stacked_borrows/return_invalid_mut_tuple.rs b/tests/fail/stacked_borrows/return_invalid_mut_tuple.rs index 2184d20b1cfaf..c94fef90542fd 100644 --- a/tests/fail/stacked_borrows/return_invalid_mut_tuple.rs +++ b/tests/fail/stacked_borrows/return_invalid_mut_tuple.rs @@ -8,5 +8,5 @@ fn foo(x: &mut (i32, i32)) -> (&mut i32,) { } fn main() { - foo(&mut (1, 2)).0; //~ ERROR: /reborrow .* tag does not exist in the borrow stack/ + foo(&mut (1, 2)).0; //~ ERROR: /retag .* tag does not exist in the borrow stack/ } diff --git a/tests/fail/stacked_borrows/return_invalid_mut_tuple.stderr b/tests/fail/stacked_borrows/return_invalid_mut_tuple.stderr index 46ef6a737a637..f7fc75bfd098f 100644 --- a/tests/fail/stacked_borrows/return_invalid_mut_tuple.stderr +++ b/tests/fail/stacked_borrows/return_invalid_mut_tuple.stderr @@ -1,20 +1,20 @@ -error: Undefined Behavior: trying to reborrow from for Unique permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location +error: Undefined Behavior: trying to retag from for Unique permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location --> $DIR/return_invalid_mut_tuple.rs:LL:CC | LL | foo(&mut (1, 2)).0; | ^^^^^^^^^^^^^^^^^^ | | - | trying to reborrow from for Unique permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location - | this error occurs as part of a reborrow at ALLOC[0x4..0x8] + | trying to retag from for Unique permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location + | this error occurs as part of retag at ALLOC[0x4..0x8] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information -help: was created by a retag at offsets [0x4..0x8] +help: was created by a Unique retag at offsets [0x4..0x8] --> $DIR/return_invalid_mut_tuple.rs:LL:CC | LL | let ret = (unsafe { &mut (*xraw).1 },); | ^^^^^^^^^^^^^^ -help: was later invalidated at offsets [0x0..0x8] +help: was later invalidated at offsets [0x0..0x8] by a read access --> $DIR/return_invalid_mut_tuple.rs:LL:CC | LL | let _val = unsafe { *xraw }; // invalidate xref diff --git a/tests/fail/stacked_borrows/return_invalid_shr.rs b/tests/fail/stacked_borrows/return_invalid_shr.rs index b1d16c025ebf0..45526498dadf5 100644 --- a/tests/fail/stacked_borrows/return_invalid_shr.rs +++ b/tests/fail/stacked_borrows/return_invalid_shr.rs @@ -3,7 +3,7 @@ fn foo(x: &mut (i32, i32)) -> &i32 { let xraw = x as *mut (i32, i32); let ret = unsafe { &(*xraw).1 }; unsafe { *xraw = (42, 23) }; // unfreeze - ret //~ ERROR: /reborrow .* tag does not exist in the borrow stack/ + ret //~ ERROR: /retag .* tag does not exist in the borrow stack/ } fn main() { diff --git a/tests/fail/stacked_borrows/return_invalid_shr.stderr b/tests/fail/stacked_borrows/return_invalid_shr.stderr index 6f745b69fc722..fef83c478fe91 100644 --- a/tests/fail/stacked_borrows/return_invalid_shr.stderr +++ b/tests/fail/stacked_borrows/return_invalid_shr.stderr @@ -1,20 +1,20 @@ -error: Undefined Behavior: trying to reborrow from for SharedReadOnly permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location +error: Undefined Behavior: trying to retag from for SharedReadOnly permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location --> $DIR/return_invalid_shr.rs:LL:CC | LL | ret | ^^^ | | - | trying to reborrow from for SharedReadOnly permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location - | this error occurs as part of a reborrow at ALLOC[0x4..0x8] + | trying to retag from for SharedReadOnly permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location + | this error occurs as part of retag at ALLOC[0x4..0x8] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information -help: was created by a retag at offsets [0x4..0x8] +help: was created by a SharedReadOnly retag at offsets [0x4..0x8] --> $DIR/return_invalid_shr.rs:LL:CC | LL | let ret = unsafe { &(*xraw).1 }; | ^^^^^^^^^^ -help: was later invalidated at offsets [0x0..0x8] +help: was later invalidated at offsets [0x0..0x8] by a write access --> $DIR/return_invalid_shr.rs:LL:CC | LL | unsafe { *xraw = (42, 23) }; // unfreeze diff --git a/tests/fail/stacked_borrows/return_invalid_shr_option.rs b/tests/fail/stacked_borrows/return_invalid_shr_option.rs index e9faa945206eb..3a028ceed86ae 100644 --- a/tests/fail/stacked_borrows/return_invalid_shr_option.rs +++ b/tests/fail/stacked_borrows/return_invalid_shr_option.rs @@ -9,7 +9,7 @@ fn foo(x: &mut (i32, i32)) -> Option<&i32> { fn main() { match foo(&mut (1, 2)) { - Some(_x) => {} //~ ERROR: /reborrow .* tag does not exist in the borrow stack/ + Some(_x) => {} //~ ERROR: /retag .* tag does not exist in the borrow stack/ None => {} } } diff --git a/tests/fail/stacked_borrows/return_invalid_shr_option.stderr b/tests/fail/stacked_borrows/return_invalid_shr_option.stderr index 2441c9aa1c510..cc316aaf44ece 100644 --- a/tests/fail/stacked_borrows/return_invalid_shr_option.stderr +++ b/tests/fail/stacked_borrows/return_invalid_shr_option.stderr @@ -1,20 +1,20 @@ -error: Undefined Behavior: trying to reborrow from for SharedReadOnly permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location +error: Undefined Behavior: trying to retag from for SharedReadOnly permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location --> $DIR/return_invalid_shr_option.rs:LL:CC | LL | Some(_x) => {} | ^^ | | - | trying to reborrow from for SharedReadOnly permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location - | this error occurs as part of a reborrow at ALLOC[0x4..0x8] + | trying to retag from for SharedReadOnly permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location + | this error occurs as part of retag at ALLOC[0x4..0x8] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information -help: was created by a retag at offsets [0x4..0x8] +help: was created by a SharedReadOnly retag at offsets [0x4..0x8] --> $DIR/return_invalid_shr_option.rs:LL:CC | LL | let ret = Some(unsafe { &(*xraw).1 }); | ^^^^^^^^^^ -help: was later invalidated at offsets [0x0..0x8] +help: was later invalidated at offsets [0x0..0x8] by a write access --> $DIR/return_invalid_shr_option.rs:LL:CC | LL | unsafe { *xraw = (42, 23) }; // unfreeze diff --git a/tests/fail/stacked_borrows/return_invalid_shr_tuple.rs b/tests/fail/stacked_borrows/return_invalid_shr_tuple.rs index 11eb4de56c9fc..e4536626dbf2c 100644 --- a/tests/fail/stacked_borrows/return_invalid_shr_tuple.rs +++ b/tests/fail/stacked_borrows/return_invalid_shr_tuple.rs @@ -8,5 +8,5 @@ fn foo(x: &mut (i32, i32)) -> (&i32,) { } fn main() { - foo(&mut (1, 2)).0; //~ ERROR: /reborrow .* tag does not exist in the borrow stack/ + foo(&mut (1, 2)).0; //~ ERROR: /retag .* tag does not exist in the borrow stack/ } diff --git a/tests/fail/stacked_borrows/return_invalid_shr_tuple.stderr b/tests/fail/stacked_borrows/return_invalid_shr_tuple.stderr index 5102f7cb53c45..f6be5d0e53a06 100644 --- a/tests/fail/stacked_borrows/return_invalid_shr_tuple.stderr +++ b/tests/fail/stacked_borrows/return_invalid_shr_tuple.stderr @@ -1,20 +1,20 @@ -error: Undefined Behavior: trying to reborrow from for SharedReadOnly permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location +error: Undefined Behavior: trying to retag from for SharedReadOnly permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location --> $DIR/return_invalid_shr_tuple.rs:LL:CC | LL | foo(&mut (1, 2)).0; | ^^^^^^^^^^^^^^^^^^ | | - | trying to reborrow from for SharedReadOnly permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location - | this error occurs as part of a reborrow at ALLOC[0x4..0x8] + | trying to retag from for SharedReadOnly permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location + | this error occurs as part of retag at ALLOC[0x4..0x8] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information -help: was created by a retag at offsets [0x4..0x8] +help: was created by a SharedReadOnly retag at offsets [0x4..0x8] --> $DIR/return_invalid_shr_tuple.rs:LL:CC | LL | let ret = (unsafe { &(*xraw).1 },); | ^^^^^^^^^^ -help: was later invalidated at offsets [0x0..0x8] +help: was later invalidated at offsets [0x0..0x8] by a write access --> $DIR/return_invalid_shr_tuple.rs:LL:CC | LL | unsafe { *xraw = (42, 23) }; // unfreeze diff --git a/tests/fail/stacked_borrows/shared_rw_borrows_are_weak1.rs b/tests/fail/stacked_borrows/shared_rw_borrows_are_weak1.rs index 01b2775d9d363..2450ec4b4a1d0 100644 --- a/tests/fail/stacked_borrows/shared_rw_borrows_are_weak1.rs +++ b/tests/fail/stacked_borrows/shared_rw_borrows_are_weak1.rs @@ -11,6 +11,6 @@ fn main() { let y: &mut Cell = mem::transmute(&mut *x); // launder lifetime let shr_rw = &*x; // thanks to interior mutability this will be a SharedReadWrite shr_rw.set(1); - y.get_mut(); //~ ERROR: /reborrow .* tag does not exist in the borrow stack/ + y.get_mut(); //~ ERROR: /retag .* tag does not exist in the borrow stack/ } } diff --git a/tests/fail/stacked_borrows/shared_rw_borrows_are_weak1.stderr b/tests/fail/stacked_borrows/shared_rw_borrows_are_weak1.stderr index a412add67e024..3f5f2c66ae1ff 100644 --- a/tests/fail/stacked_borrows/shared_rw_borrows_are_weak1.stderr +++ b/tests/fail/stacked_borrows/shared_rw_borrows_are_weak1.stderr @@ -1,20 +1,20 @@ -error: Undefined Behavior: trying to reborrow from for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location +error: Undefined Behavior: trying to retag from for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location --> $DIR/shared_rw_borrows_are_weak1.rs:LL:CC | LL | y.get_mut(); | ^^^^^^^^^^^ | | - | trying to reborrow from for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location - | this error occurs as part of a reborrow at ALLOC[0x0..0x4] + | trying to retag from for SharedReadWrite permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | this error occurs as part of two-phase retag at ALLOC[0x0..0x4] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information -help: was created by a retag at offsets [0x0..0x4] +help: was created by a Unique retag at offsets [0x0..0x4] --> $DIR/shared_rw_borrows_are_weak1.rs:LL:CC | LL | let y: &mut Cell = mem::transmute(&mut *x); // launder lifetime | ^^^^^^^^^^^^^^^^^^^^^^^ -help: was later invalidated at offsets [0x0..0x4] +help: was later invalidated at offsets [0x0..0x4] by a Unique retag --> $DIR/shared_rw_borrows_are_weak1.rs:LL:CC | LL | shr_rw.set(1); diff --git a/tests/fail/stacked_borrows/shared_rw_borrows_are_weak2.stderr b/tests/fail/stacked_borrows/shared_rw_borrows_are_weak2.stderr index 2c0117577f2e5..0a551fe824b5e 100644 --- a/tests/fail/stacked_borrows/shared_rw_borrows_are_weak2.stderr +++ b/tests/fail/stacked_borrows/shared_rw_borrows_are_weak2.stderr @@ -9,12 +9,12 @@ LL | let _val = *y; | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information -help: was created by a retag at offsets [$HEX..$HEX] +help: was created by a SharedReadOnly retag at offsets [$HEX..$HEX] --> $DIR/shared_rw_borrows_are_weak2.rs:LL:CC | LL | let y: &i32 = mem::transmute(&*x.borrow()); // launder lifetime | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -help: was later invalidated at offsets [$HEX..$HEX] +help: was later invalidated at offsets [$HEX..$HEX] by a Unique retag --> $DIR/shared_rw_borrows_are_weak2.rs:LL:CC | LL | shr_rw.replace(1); diff --git a/tests/fail/stacked_borrows/shr_frozen_violation1.stderr b/tests/fail/stacked_borrows/shr_frozen_violation1.stderr index 47799b18e1f9d..9ae8461e13ea2 100644 --- a/tests/fail/stacked_borrows/shr_frozen_violation1.stderr +++ b/tests/fail/stacked_borrows/shr_frozen_violation1.stderr @@ -9,7 +9,7 @@ LL | *(x as *const i32 as *mut i32) = 7; | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information -help: was created by a retag at offsets [0x0..0x4] +help: was created by a SharedReadOnly retag at offsets [0x0..0x4] --> $DIR/shr_frozen_violation1.rs:LL:CC | LL | *(x as *const i32 as *mut i32) = 7; diff --git a/tests/fail/stacked_borrows/track_caller.rs b/tests/fail/stacked_borrows/track_caller.rs new file mode 100644 index 0000000000000..3455eb4684ea2 --- /dev/null +++ b/tests/fail/stacked_borrows/track_caller.rs @@ -0,0 +1,17 @@ +// This is a copy of illegal_read1.rs, but with #[track_caller] on the test. +// This test only checks that our diagnostics do not display the contents of callee. + +#[rustfmt::skip] // rustfmt bug: https://github.com/rust-lang/rustfmt/issues/5391 +fn main() { + let mut x = 15; + let xraw = &mut x as *mut _; + let xref = unsafe { &mut *xraw }; // derived from raw, so using raw is still ok... + callee(xraw); + let _val = *xref; // ...but any use of raw will invalidate our ref. + //~^ ERROR: /read access .* tag does not exist in the borrow stack/ +} + +#[track_caller] +fn callee(xraw: *mut i32) { + let _val = unsafe { *xraw }; +} diff --git a/tests/fail/stacked_borrows/track_caller.stderr b/tests/fail/stacked_borrows/track_caller.stderr new file mode 100644 index 0000000000000..5ad22305910aa --- /dev/null +++ b/tests/fail/stacked_borrows/track_caller.stderr @@ -0,0 +1,28 @@ +error: Undefined Behavior: attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + --> $DIR/track_caller.rs:LL:CC + | +LL | let _val = *xref; // ...but any use of raw will invalidate our ref. + | ^^^^^ + | | + | attempting a read access using at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | this error occurs as part of an access at ALLOC[0x0..0x4] + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information +help: was created by a Unique retag at offsets [0x0..0x4] + --> $DIR/track_caller.rs:LL:CC + | +LL | let xref = unsafe { &mut *xraw }; // derived from raw, so using raw is still ok... + | ^^^^^^^^^^ +help: was later invalidated at offsets [0x0..0x4] by a read access + --> $DIR/track_caller.rs:LL:CC + | +LL | callee(xraw); + | ^^^^^^^^^^^^ + = note: backtrace: + = note: inside `main` at $DIR/track_caller.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/fail/stacked_borrows/transmute-is-no-escape.stderr b/tests/fail/stacked_borrows/transmute-is-no-escape.stderr index b48abb3df7098..eaac77034cce8 100644 --- a/tests/fail/stacked_borrows/transmute-is-no-escape.stderr +++ b/tests/fail/stacked_borrows/transmute-is-no-escape.stderr @@ -9,7 +9,7 @@ LL | unsafe { *raw = 13 }; | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information -help: was created by a retag at offsets [0x4..0x8] +help: was created by a SharedReadWrite retag at offsets [0x4..0x8] --> $DIR/transmute-is-no-escape.rs:LL:CC | LL | let raw = (&mut x[1] as *mut i32).wrapping_offset(-1); diff --git a/tests/fail/stacked_borrows/unescaped_static.stderr b/tests/fail/stacked_borrows/unescaped_static.stderr index 018ff77b2e939..7b210ed9314e8 100644 --- a/tests/fail/stacked_borrows/unescaped_static.stderr +++ b/tests/fail/stacked_borrows/unescaped_static.stderr @@ -9,7 +9,7 @@ LL | let _val = unsafe { *ptr_to_first.add(1) }; | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information -help: was created by a retag at offsets [0x0..0x1] +help: was created by a SharedReadOnly retag at offsets [0x0..0x1] --> $DIR/unescaped_static.rs:LL:CC | LL | let ptr_to_first = &ARRAY[0] as *const u8; diff --git a/tests/fail/stacked_borrows/zst_slice.rs b/tests/fail/stacked_borrows/zst_slice.rs index 11065186fc495..77daa9c9811ae 100644 --- a/tests/fail/stacked_borrows/zst_slice.rs +++ b/tests/fail/stacked_borrows/zst_slice.rs @@ -1,5 +1,5 @@ //@compile-flags: -Zmiri-strict-provenance -//@error-pattern: /reborrow .* tag does not exist in the borrow stack/ +//@error-pattern: /retag .* tag does not exist in the borrow stack/ fn main() { unsafe { diff --git a/tests/fail/stacked_borrows/zst_slice.stderr b/tests/fail/stacked_borrows/zst_slice.stderr index d47e967b543b0..6d0e785cea765 100644 --- a/tests/fail/stacked_borrows/zst_slice.stderr +++ b/tests/fail/stacked_borrows/zst_slice.stderr @@ -1,15 +1,15 @@ -error: Undefined Behavior: trying to reborrow from for SharedReadOnly permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location +error: Undefined Behavior: trying to retag from for SharedReadOnly permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location --> RUSTLIB/core/src/slice/mod.rs:LL:CC | LL | unsafe { &*index.get_unchecked(self) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | - | trying to reborrow from for SharedReadOnly permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location - | this error occurs as part of a reborrow at ALLOC[0x4..0x8] + | trying to retag from for SharedReadOnly permission at ALLOC[0x4], but that tag does not exist in the borrow stack for this location + | this error occurs as part of retag at ALLOC[0x4..0x8] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information -help: was created by a retag at offsets [0x0..0x0] +help: would have been created here, but this is a zero-size retag ([0x0..0x0]) so the tag in question does not exist anywhere --> $DIR/zst_slice.rs:LL:CC | LL | assert_eq!(*s.get_unchecked(1), 2); From 17fc52a06d07828fb7d2ef6f5202a9ae41b532c8 Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Mon, 15 Aug 2022 22:19:00 -0400 Subject: [PATCH 3664/3747] Clean up diff churn a bit, adjust comments --- src/stacked_borrows/diagnostics.rs | 4 ++++ src/stacked_borrows/mod.rs | 32 +++++++++++++++--------------- 2 files changed, 20 insertions(+), 16 deletions(-) diff --git a/src/stacked_borrows/diagnostics.rs b/src/stacked_borrows/diagnostics.rs index ac2783670cfff..be363abad2a49 100644 --- a/src/stacked_borrows/diagnostics.rs +++ b/src/stacked_borrows/diagnostics.rs @@ -370,6 +370,7 @@ impl<'ecx, 'mir, 'tcx, 'history> DiagnosticCx<'ecx, 'mir, 'tcx, 'history> { } /// Report a descriptive error when `new` could not be granted from `derived_from`. + #[inline(never)] // This is only called on fatal code paths pub fn grant_error(&self, perm: Permission, stack: &Stack) -> InterpError<'tcx> { let Operation::Retag(op) = &self.operation else { unreachable!("grant_error should only be called during a retag") @@ -389,6 +390,7 @@ impl<'ecx, 'mir, 'tcx, 'history> DiagnosticCx<'ecx, 'mir, 'tcx, 'history> { } /// Report a descriptive error when `access` is not permitted based on `tag`. + #[inline(never)] // This is only called on fatal code paths pub fn access_error(&self, stack: &Stack) -> InterpError<'tcx> { let Operation::Access(op) = &self.operation else { unreachable!("access_error should only be called during an access") @@ -407,6 +409,7 @@ impl<'ecx, 'mir, 'tcx, 'history> DiagnosticCx<'ecx, 'mir, 'tcx, 'history> { ) } + #[inline(never)] // This is only called on fatal code paths pub fn protector_error(&self, item: &Item) -> InterpError<'tcx> { let call_id = self .threads @@ -441,6 +444,7 @@ impl<'ecx, 'mir, 'tcx, 'history> DiagnosticCx<'ecx, 'mir, 'tcx, 'history> { } } + #[inline(never)] // This is only called on fatal code paths pub fn dealloc_error(&self) -> InterpError<'tcx> { let Operation::Dealloc(op) = &self.operation else { unreachable!("dealloc_error should only be called during a deallocation") diff --git a/src/stacked_borrows/mod.rs b/src/stacked_borrows/mod.rs index 6cb76e7b23aa5..9861e6fdb17bc 100644 --- a/src/stacked_borrows/mod.rs +++ b/src/stacked_borrows/mod.rs @@ -296,6 +296,19 @@ impl<'tcx> Stack { return Ok(()); } + // We store tags twice, once in global.protected_tags and once in each call frame. + // We do this because consulting a single global set in this function is faster + // than attempting to search all call frames in the program for the `FrameExtra` + // (if any) which is protecting the popped tag. + // + // This duplication trades off making `end_call` slower to make this function faster. This + // trade-off is profitable in practice for a combination of two reasons. + // 1. A single protected tag can (and does in some programs) protect thousands of `Item`s. + // Therefore, adding overhead in function call/return is profitable even if it only + // saves a little work in this function. + // 2. Most frames protect only one or two tags. So this duplicative global turns a search + // which ends up about linear in the number of protected tags in the program into a + // constant time check (and a slow linear, because the tags in the frames aren't contiguous). if global.protected_tags.contains(&item.tag()) { return Err(dcx.protector_error(item).into()); } @@ -622,6 +635,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx protect: bool, ) -> InterpResult<'tcx, Option> { let this = self.eval_context_mut(); + let current_span = this.machine.current_span(*this.tcx); // It is crucial that this gets called on all code paths, to ensure we track tag creation. let log_creation = |this: &MiriEvalContext<'mir, 'tcx>, @@ -674,8 +688,6 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(()) }; - let current_span = this.machine.current_span(*this.tcx); - if size == Size::ZERO { trace!( "reborrow of size 0: {} reference {:?} derived from {:?} (pointee {})", @@ -726,19 +738,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ); if protect { - // We store tags twice, once in global.protected_tags and once in each call frame. - // We do this because consulting a single global set in this function is faster - // than attempting to search all call frames in the program for the `FrameExtra` - // (if any) which is protecting the popped tag. - // - // This duplication trades off making `end_call` slower to make this function faster. This - // trade-off is profitable in practice for a combination of two reasons. - // 1. A single protected tag can (and does in some programs) protect thousands of `Item`s. - // Therefore, adding overhead to in function call/return is profitable even if it only - // saves a little work in this function. - // 2. Most frames protect only one or two tags. So this duplicative global turns a search - // which ends up about linear in the number of protected tags in the program into a - // constant time check (and a slow linear, because the tags in the frames aren't contiguous). + // See comment in `Stack::item_popped` for why we store the tag twice. this.frame_mut().extra.stacked_borrows.as_mut().unwrap().protected_tags.push(new_tag); this.machine.stacked_borrows.as_mut().unwrap().get_mut().protected_tags.insert(new_tag); } @@ -818,7 +818,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let range = alloc_range(base_offset, size); let mut global = machine.stacked_borrows.as_ref().unwrap().borrow_mut(); let dcx = DiagnosticCxBuilder::retag( - machine.current_span(tcx), + machine.current_span(tcx), // `get_alloc_extra_mut` invalidated our old `current_span` &machine.threads, retag_cause, new_tag, From 15a4f0a9e094f09b658dbb3a176d62c8661dec3b Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Tue, 16 Aug 2022 20:32:58 -0400 Subject: [PATCH 3665/3747] some CurrentSpan cleanup --- src/helpers.rs | 29 ++++++------ src/stacked_borrows/diagnostics.rs | 33 ++++++++------ src/stacked_borrows/mod.rs | 72 +++++++++++++++++------------- 3 files changed, 76 insertions(+), 58 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index 6f6cbcc38a777..f634c8d0c9ac4 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -877,7 +877,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx impl<'mir, 'tcx> Evaluator<'mir, 'tcx> { pub fn current_span(&self, tcx: TyCtxt<'tcx>) -> CurrentSpan<'_, 'mir, 'tcx> { - CurrentSpan { span: None, machine: self, tcx } + CurrentSpan { current_frame_idx: None, machine: self, tcx } } } @@ -887,7 +887,7 @@ impl<'mir, 'tcx> Evaluator<'mir, 'tcx> { /// The result of that search is cached so that later calls are approximately free. #[derive(Clone)] pub struct CurrentSpan<'a, 'mir, 'tcx> { - span: Option, + current_frame_idx: Option, tcx: TyCtxt<'tcx>, machine: &'a Evaluator<'mir, 'tcx>, } @@ -896,25 +896,19 @@ impl<'a, 'mir: 'a, 'tcx: 'a + 'mir> CurrentSpan<'a, 'mir, 'tcx> { /// Get the current span, skipping non-local frames. /// This function is backed by a cache, and can be assumed to be very fast. pub fn get(&mut self) -> Span { - *self.span.get_or_insert_with(|| Self::current_span(self.tcx, self.machine)) + let idx = self.current_frame_idx(); + Self::frame_span(self.machine, idx) } /// Similar to `CurrentSpan::get`, but retrieves the parent frame of the first non-local frame. /// This is useful when we are processing something which occurs on function-entry and we want /// to point at the call to the function, not the function definition generally. - #[inline(never)] pub fn get_parent(&mut self) -> Span { - let idx = Self::current_span_index(self.tcx, self.machine); - Self::nth_span(self.machine, idx.wrapping_sub(1)) - } - - #[inline(never)] - fn current_span(tcx: TyCtxt<'_>, machine: &Evaluator<'_, '_>) -> Span { - let idx = Self::current_span_index(tcx, machine); - Self::nth_span(machine, idx) + let idx = self.current_frame_idx(); + Self::frame_span(self.machine, idx.wrapping_sub(1)) } - fn nth_span(machine: &Evaluator<'_, '_>, idx: usize) -> Span { + fn frame_span(machine: &Evaluator<'_, '_>, idx: usize) -> Span { machine .threads .active_thread_stack() @@ -923,9 +917,16 @@ impl<'a, 'mir: 'a, 'tcx: 'a + 'mir> CurrentSpan<'a, 'mir, 'tcx> { .unwrap_or(rustc_span::DUMMY_SP) } + fn current_frame_idx(&mut self) -> usize { + *self + .current_frame_idx + .get_or_insert_with(|| Self::compute_current_frame_index(self.tcx, self.machine)) + } + // Find the position of the inner-most frame which is part of the crate being // compiled/executed, part of the Cargo workspace, and is also not #[track_caller]. - fn current_span_index(tcx: TyCtxt<'_>, machine: &Evaluator<'_, '_>) -> usize { + #[inline(never)] + fn compute_current_frame_index(tcx: TyCtxt<'_>, machine: &Evaluator<'_, '_>) -> usize { machine .threads .active_thread_stack() diff --git a/src/stacked_borrows/diagnostics.rs b/src/stacked_borrows/diagnostics.rs index be363abad2a49..741a3d363dd35 100644 --- a/src/stacked_borrows/diagnostics.rs +++ b/src/stacked_borrows/diagnostics.rs @@ -103,26 +103,30 @@ pub struct TagHistory { pub protected: Option<([(String, SpanData); 2])>, } -pub struct DiagnosticCxBuilder<'ecx, 'mir, 'tcx> { +pub struct DiagnosticCxBuilder<'span, 'ecx, 'mir, 'tcx> { operation: Operation, - current_span: CurrentSpan<'ecx, 'mir, 'tcx>, + // 'span cannot be merged with any other lifetime since they appear invariantly, under the + // mutable ref. + current_span: &'span mut CurrentSpan<'ecx, 'mir, 'tcx>, threads: &'ecx ThreadManager<'mir, 'tcx>, } -pub struct DiagnosticCx<'ecx, 'mir, 'tcx, 'history> { +pub struct DiagnosticCx<'span, 'history, 'ecx, 'mir, 'tcx> { operation: Operation, - current_span: CurrentSpan<'ecx, 'mir, 'tcx>, + // 'span and 'history cannot be merged, since when we call `unbuild` we need + // to return the exact 'span that was used when calling `build`. + current_span: &'span mut CurrentSpan<'ecx, 'mir, 'tcx>, threads: &'ecx ThreadManager<'mir, 'tcx>, history: &'history mut AllocHistory, offset: Size, } -impl<'ecx, 'mir, 'tcx, 'history> DiagnosticCxBuilder<'ecx, 'mir, 'tcx> { - pub fn build( +impl<'span, 'ecx, 'mir, 'tcx> DiagnosticCxBuilder<'span, 'ecx, 'mir, 'tcx> { + pub fn build<'history>( self, history: &'history mut AllocHistory, offset: Size, - ) -> DiagnosticCx<'ecx, 'mir, 'tcx, 'history> { + ) -> DiagnosticCx<'span, 'history, 'ecx, 'mir, 'tcx> { DiagnosticCx { operation: self.operation, current_span: self.current_span, @@ -133,7 +137,7 @@ impl<'ecx, 'mir, 'tcx, 'history> DiagnosticCxBuilder<'ecx, 'mir, 'tcx> { } pub fn retag( - current_span: CurrentSpan<'ecx, 'mir, 'tcx>, + current_span: &'span mut CurrentSpan<'ecx, 'mir, 'tcx>, threads: &'ecx ThreadManager<'mir, 'tcx>, cause: RetagCause, new_tag: SbTag, @@ -147,7 +151,7 @@ impl<'ecx, 'mir, 'tcx, 'history> DiagnosticCxBuilder<'ecx, 'mir, 'tcx> { } pub fn read( - current_span: CurrentSpan<'ecx, 'mir, 'tcx>, + current_span: &'span mut CurrentSpan<'ecx, 'mir, 'tcx>, threads: &'ecx ThreadManager<'mir, 'tcx>, tag: ProvenanceExtra, range: AllocRange, @@ -157,7 +161,7 @@ impl<'ecx, 'mir, 'tcx, 'history> DiagnosticCxBuilder<'ecx, 'mir, 'tcx> { } pub fn write( - current_span: CurrentSpan<'ecx, 'mir, 'tcx>, + current_span: &'span mut CurrentSpan<'ecx, 'mir, 'tcx>, threads: &'ecx ThreadManager<'mir, 'tcx>, tag: ProvenanceExtra, range: AllocRange, @@ -167,7 +171,7 @@ impl<'ecx, 'mir, 'tcx, 'history> DiagnosticCxBuilder<'ecx, 'mir, 'tcx> { } pub fn dealloc( - current_span: CurrentSpan<'ecx, 'mir, 'tcx>, + current_span: &'span mut CurrentSpan<'ecx, 'mir, 'tcx>, threads: &'ecx ThreadManager<'mir, 'tcx>, tag: ProvenanceExtra, ) -> Self { @@ -176,8 +180,8 @@ impl<'ecx, 'mir, 'tcx, 'history> DiagnosticCxBuilder<'ecx, 'mir, 'tcx> { } } -impl<'ecx, 'mir, 'tcx, 'history> DiagnosticCx<'ecx, 'mir, 'tcx, 'history> { - pub fn unbuild(self) -> DiagnosticCxBuilder<'ecx, 'mir, 'tcx> { +impl<'span, 'history, 'ecx, 'mir, 'tcx> DiagnosticCx<'span, 'history, 'ecx, 'mir, 'tcx> { + pub fn unbuild(self) -> DiagnosticCxBuilder<'span, 'ecx, 'mir, 'tcx> { DiagnosticCxBuilder { operation: self.operation, current_span: self.current_span, @@ -233,7 +237,7 @@ impl AllocHistory { } } -impl<'ecx, 'mir, 'tcx, 'history> DiagnosticCx<'ecx, 'mir, 'tcx, 'history> { +impl<'span, 'history, 'ecx, 'mir, 'tcx> DiagnosticCx<'span, 'history, 'ecx, 'mir, 'tcx> { pub fn start_grant(&mut self, perm: Permission) { let Operation::Retag(op) = &mut self.operation else { unreachable!("start_grant must only be called during a retag, this is: {:?}", self.operation) @@ -247,6 +251,7 @@ impl<'ecx, 'mir, 'tcx, 'history> DiagnosticCx<'ecx, 'mir, 'tcx, 'history> { } Some(previous) => if previous != perm { + // 'Split up' the creation event. let previous_range = last_creation.retag.range; last_creation.retag.range = alloc_range(previous_range.start, self.offset); let mut new_event = last_creation.clone(); diff --git a/src/stacked_borrows/mod.rs b/src/stacked_borrows/mod.rs index 9861e6fdb17bc..66fdd685def5b 100644 --- a/src/stacked_borrows/mod.rs +++ b/src/stacked_borrows/mod.rs @@ -286,7 +286,7 @@ impl<'tcx> Stack { fn item_popped( item: &Item, global: &GlobalStateInner, - dcx: &mut DiagnosticCx<'_, '_, 'tcx, '_>, + dcx: &mut DiagnosticCx<'_, '_, '_, '_, 'tcx>, ) -> InterpResult<'tcx> { if !global.tracked_pointer_tags.is_empty() { dcx.check_tracked_tag_popped(item, global); @@ -324,7 +324,7 @@ impl<'tcx> Stack { access: AccessKind, tag: ProvenanceExtra, global: &mut GlobalStateInner, - dcx: &mut DiagnosticCx<'_, '_, 'tcx, '_>, + dcx: &mut DiagnosticCx<'_, '_, '_, '_, 'tcx>, exposed_tags: &FxHashSet, ) -> InterpResult<'tcx> { // Two main steps: Find granting item, remove incompatible items above. @@ -410,7 +410,7 @@ impl<'tcx> Stack { &mut self, tag: ProvenanceExtra, global: &GlobalStateInner, - dcx: &mut DiagnosticCx<'_, '_, 'tcx, '_>, + dcx: &mut DiagnosticCx<'_, '_, '_, '_, 'tcx>, exposed_tags: &FxHashSet, ) -> InterpResult<'tcx> { // Step 1: Make sure there is a granting item. @@ -436,7 +436,7 @@ impl<'tcx> Stack { derived_from: ProvenanceExtra, new: Item, global: &mut GlobalStateInner, - dcx: &mut DiagnosticCx<'_, '_, 'tcx, '_>, + dcx: &mut DiagnosticCx<'_, '_, '_, '_, 'tcx>, exposed_tags: &FxHashSet, ) -> InterpResult<'tcx> { dcx.start_grant(new.perm()); @@ -515,10 +515,10 @@ impl<'tcx> Stacks { fn for_each( &mut self, range: AllocRange, - mut dcx_builder: DiagnosticCxBuilder<'_, '_, 'tcx>, + mut dcx_builder: DiagnosticCxBuilder<'_, '_, '_, 'tcx>, mut f: impl FnMut( &mut Stack, - &mut DiagnosticCx<'_, '_, 'tcx, '_>, + &mut DiagnosticCx<'_, '_, '_, '_, 'tcx>, &mut FxHashSet, ) -> InterpResult<'tcx>, ) -> InterpResult<'tcx> { @@ -554,22 +554,25 @@ impl Stacks { } #[inline(always)] - pub fn before_memory_read<'tcx, 'mir>( + pub fn before_memory_read<'tcx, 'mir, 'ecx>( &mut self, alloc_id: AllocId, tag: ProvenanceExtra, range: AllocRange, state: &GlobalState, - current_span: CurrentSpan<'_, 'mir, 'tcx>, - threads: &ThreadManager<'mir, 'tcx>, - ) -> InterpResult<'tcx> { + mut current_span: CurrentSpan<'ecx, 'mir, 'tcx>, + threads: &'ecx ThreadManager<'mir, 'tcx>, + ) -> InterpResult<'tcx> + where + 'tcx: 'ecx, + { trace!( "read access with tag {:?}: {:?}, size {}", tag, Pointer::new(alloc_id, range.start), range.size.bytes() ); - let dcx = DiagnosticCxBuilder::read(current_span, threads, tag, range); + let dcx = DiagnosticCxBuilder::read(&mut current_span, threads, tag, range); let mut state = state.borrow_mut(); self.for_each(range, dcx, |stack, dcx, exposed_tags| { stack.access(AccessKind::Read, tag, &mut state, dcx, exposed_tags) @@ -577,14 +580,14 @@ impl Stacks { } #[inline(always)] - pub fn before_memory_write<'tcx, 'mir>( + pub fn before_memory_write<'tcx, 'mir, 'ecx>( &mut self, alloc_id: AllocId, tag: ProvenanceExtra, range: AllocRange, state: &GlobalState, - current_span: CurrentSpan<'_, 'mir, 'tcx>, - threads: &ThreadManager<'mir, 'tcx>, + mut current_span: CurrentSpan<'ecx, 'mir, 'tcx>, + threads: &'ecx ThreadManager<'mir, 'tcx>, ) -> InterpResult<'tcx> { trace!( "write access with tag {:?}: {:?}, size {}", @@ -592,7 +595,7 @@ impl Stacks { Pointer::new(alloc_id, range.start), range.size.bytes() ); - let dcx = DiagnosticCxBuilder::write(current_span, threads, tag, range); + let dcx = DiagnosticCxBuilder::write(&mut current_span, threads, tag, range); let mut state = state.borrow_mut(); self.for_each(range, dcx, |stack, dcx, exposed_tags| { stack.access(AccessKind::Write, tag, &mut state, dcx, exposed_tags) @@ -600,17 +603,17 @@ impl Stacks { } #[inline(always)] - pub fn before_memory_deallocation<'tcx, 'mir>( + pub fn before_memory_deallocation<'tcx, 'mir, 'ecx>( &mut self, alloc_id: AllocId, tag: ProvenanceExtra, range: AllocRange, state: &GlobalState, - current_span: CurrentSpan<'_, 'mir, 'tcx>, - threads: &ThreadManager<'mir, 'tcx>, + mut current_span: CurrentSpan<'ecx, 'mir, 'tcx>, + threads: &'ecx ThreadManager<'mir, 'tcx>, ) -> InterpResult<'tcx> { trace!("deallocation with tag {:?}: {:?}, size {}", tag, alloc_id, range.size.bytes()); - let dcx = DiagnosticCxBuilder::dealloc(current_span, threads, tag); + let dcx = DiagnosticCxBuilder::dealloc(&mut current_span, threads, tag); let state = state.borrow(); self.for_each(range, dcx, |stack, dcx, exposed_tags| { stack.dealloc(tag, &state, dcx, exposed_tags) @@ -621,8 +624,11 @@ impl Stacks { /// Retagging/reborrowing. There is some policy in here, such as which permissions /// to grant for which references, and when to add protectors. -impl<'mir, 'tcx: 'mir> EvalContextPrivExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} -trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { +impl<'mir: 'ecx, 'tcx: 'mir, 'ecx> EvalContextPrivExt<'mir, 'tcx, 'ecx> + for crate::MiriEvalContext<'mir, 'tcx> +{ +} +trait EvalContextPrivExt<'mir: 'ecx, 'tcx: 'mir, 'ecx>: crate::MiriEvalContextExt<'mir, 'tcx> { /// Returns the `AllocId` the reborrow was done in, if some actual borrow stack manipulation /// happened. fn reborrow( @@ -635,11 +641,9 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx protect: bool, ) -> InterpResult<'tcx, Option> { let this = self.eval_context_mut(); - let current_span = this.machine.current_span(*this.tcx); // It is crucial that this gets called on all code paths, to ensure we track tag creation. let log_creation = |this: &MiriEvalContext<'mir, 'tcx>, - current_span: CurrentSpan<'_, 'mir, 'tcx>, loc: Option<(AllocId, Size, ProvenanceExtra)>| // alloc_id, base_offset, orig_tag -> InterpResult<'tcx> { let global = this.machine.stacked_borrows.as_ref().unwrap().borrow(); @@ -658,6 +662,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let (_size, _align, alloc_kind) = this.get_alloc_info(alloc_id); match alloc_kind { AllocKind::LiveData => { + let current_span = &mut this.machine.current_span(*this.tcx); // This should have alloc_extra data, but `get_alloc_extra` can still fail // if converting this alloc_id from a global to a local one // uncovers a non-supported `extern static`. @@ -667,9 +672,12 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx .as_ref() .expect("we should have Stacked Borrows data") .borrow_mut(); - let dcx = DiagnosticCxBuilder::retag( + let threads = &this.machine.threads; + // Note that we create a *second* `DiagnosticCxBuilder` below for the actual retag. + // FIXME: can this be done cleaner? + let dcx = DiagnosticCxBuilder::retag( current_span, - &this.machine.threads, + threads, retag_cause, new_tag, orig_tag, @@ -704,16 +712,16 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Dangling slices are a common case here; it's valid to get their length but with raw // pointer tagging for example all calls to get_unchecked on them are invalid. if let Ok((alloc_id, base_offset, orig_tag)) = this.ptr_try_get_alloc_id(place.ptr) { - log_creation(this, current_span, Some((alloc_id, base_offset, orig_tag)))?; + log_creation(this, Some((alloc_id, base_offset, orig_tag)))?; return Ok(Some(alloc_id)); } // This pointer doesn't come with an AllocId. :shrug: - log_creation(this, current_span, None)?; + log_creation(this, None)?; return Ok(None); } let (alloc_id, base_offset, orig_tag) = this.ptr_get_alloc_id(place.ptr)?; - log_creation(this, current_span, Some((alloc_id, base_offset, orig_tag)))?; + log_creation(this, Some((alloc_id, base_offset, orig_tag)))?; // Ensure we bail out if the pointer goes out-of-bounds (see miri#1050). let (alloc_size, _) = this.get_live_alloc_size_and_align(alloc_id)?; @@ -770,6 +778,8 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx .as_ref() .expect("we should have Stacked Borrows data") .borrow_mut(); + // FIXME: can't share this with the current_span inside log_creation + let mut current_span = this.machine.current_span(*this.tcx); this.visit_freeze_sensitive(place, size, |mut range, frozen| { // Adjust range. range.start += base_offset; @@ -789,7 +799,7 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let item = Item::new(new_tag, perm, protected); let mut global = this.machine.stacked_borrows.as_ref().unwrap().borrow_mut(); let dcx = DiagnosticCxBuilder::retag( - this.machine.current_span(*this.tcx), + &mut current_span, // FIXME avoid this `clone` &this.machine.threads, retag_cause, new_tag, @@ -817,8 +827,10 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let item = Item::new(new_tag, perm, protect); let range = alloc_range(base_offset, size); let mut global = machine.stacked_borrows.as_ref().unwrap().borrow_mut(); + // FIXME: can't share this with the current_span inside log_creation + let current_span = &mut machine.current_span(tcx); let dcx = DiagnosticCxBuilder::retag( - machine.current_span(tcx), // `get_alloc_extra_mut` invalidated our old `current_span` + current_span, &machine.threads, retag_cause, new_tag, From 7397c8e9cf73ff338c0e00a64a4de66fd9553df3 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 18 Aug 2022 15:32:45 -0400 Subject: [PATCH 3666/3747] re-bless after rebase --- .../stacked_borrows/disable_mut_does_not_merge_srw.stderr | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/fail/stacked_borrows/disable_mut_does_not_merge_srw.stderr b/tests/fail/stacked_borrows/disable_mut_does_not_merge_srw.stderr index 9f5182ae98ffd..a959bb90fbb72 100644 --- a/tests/fail/stacked_borrows/disable_mut_does_not_merge_srw.stderr +++ b/tests/fail/stacked_borrows/disable_mut_does_not_merge_srw.stderr @@ -9,12 +9,12 @@ LL | let _val = *raw; | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information -help: was created by a retag at offsets [0x0..0x4] +help: was created by a SharedReadWrite retag at offsets [0x0..0x4] --> $DIR/disable_mut_does_not_merge_srw.rs:LL:CC | LL | mutref as *mut i32 | ^^^^^^ -help: was later invalidated at offsets [0x0..0x4] +help: was later invalidated at offsets [0x0..0x4] by a write access --> $DIR/disable_mut_does_not_merge_srw.rs:LL:CC | LL | *base = 1; From 53037a7c0982a91549afba717517e2b13df7a232 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 6 Aug 2022 17:13:31 -0400 Subject: [PATCH 3667/3747] allow NOP-casts with mismatching vtables --- tests/fail/dyn-upcast-trait-mismatch.rs | 3 +-- tests/fail/dyn-upcast-trait-mismatch.stderr | 4 ++-- tests/pass/dyn-upcast.rs | 9 +++++++++ 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/tests/fail/dyn-upcast-trait-mismatch.rs b/tests/fail/dyn-upcast-trait-mismatch.rs index f53e9a03f4bef..648ac07c43ec9 100644 --- a/tests/fail/dyn-upcast-trait-mismatch.rs +++ b/tests/fail/dyn-upcast-trait-mismatch.rs @@ -51,8 +51,7 @@ impl Baz for i32 { fn main() { let baz: &dyn Baz = &1; - // We already fail on the implicit upcast inserted here. let baz_fake: &dyn Bar = unsafe { std::mem::transmute(baz) }; - //~^ERROR: upcast on a pointer whose vtable does not match its type let _err = baz_fake as &dyn Foo; + //~^ERROR: upcast on a pointer whose vtable does not match its type } diff --git a/tests/fail/dyn-upcast-trait-mismatch.stderr b/tests/fail/dyn-upcast-trait-mismatch.stderr index 0e5e22b9b4b99..cdd1421a660c9 100644 --- a/tests/fail/dyn-upcast-trait-mismatch.stderr +++ b/tests/fail/dyn-upcast-trait-mismatch.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: upcast on a pointer whose vtable does not match its type --> $DIR/dyn-upcast-trait-mismatch.rs:LL:CC | -LL | let baz_fake: &dyn Bar = unsafe { std::mem::transmute(baz) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^ upcast on a pointer whose vtable does not match its type +LL | let _err = baz_fake as &dyn Foo; + | ^^^^^^^^ upcast on a pointer whose vtable does not match its type | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/pass/dyn-upcast.rs b/tests/pass/dyn-upcast.rs index 030c2a7cbf627..8432012a9ba52 100644 --- a/tests/pass/dyn-upcast.rs +++ b/tests/pass/dyn-upcast.rs @@ -6,6 +6,15 @@ fn main() { diamond(); struct_(); replace_vptr(); + vtable_mismatch_nop_cast(); +} + +fn vtable_mismatch_nop_cast() { + let ptr: &dyn std::fmt::Display = &0; + // Even though the vtable is for the wrong trait, this cast doesn't actually change the needed + // vtable so it should still be allowed. + let ptr: *const (dyn std::fmt::Debug + Send + Sync) = unsafe { std::mem::transmute(ptr) }; + let _ptr2 = ptr as *const dyn std::fmt::Debug; } fn basic() { From cf04c1f1ce37cefc2ebd629d6e633d0c5c1d6a48 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 19 Aug 2022 23:32:58 -0400 Subject: [PATCH 3668/3747] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index 45dbb37c86acc..e3e71f5c2fd26 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -9c20b2a8cc7588decb6de25ac6a7912dcef24d65 +e1b28cd2f16bd5b832183d7968cae3bb9213e78d From 0c3ad68a5a973642c6789a5c57d10e84fdb66520 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 19 Aug 2022 08:01:38 -0400 Subject: [PATCH 3669/3747] add ./miri cargo for RA to invoke --- CONTRIBUTING.md | 4 +++- cargo-miri/miri | 3 ++- miri | 11 ++++++++++- 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index b2964e046ecb0..8d965ae8fcb8d 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -171,7 +171,8 @@ to `.vscode/settings.json` in your local Miri clone: "env", "MIRI_AUTO_OPS=no", "./miri", - "check", + "cargo", + "clippy", // make this `check` when working with a locally built rustc "--message-format=json" ], // Contrary to what the name suggests, this also affects proc macros. @@ -179,6 +180,7 @@ to `.vscode/settings.json` in your local Miri clone: "env", "MIRI_AUTO_OPS=no", "./miri", + "cargo", "check", "--message-format=json", ], diff --git a/cargo-miri/miri b/cargo-miri/miri index ed8c80b33fd06..cf3ad06788ab1 100755 --- a/cargo-miri/miri +++ b/cargo-miri/miri @@ -1,3 +1,4 @@ #!/bin/sh -# Hack to work around https://github.com/rust-analyzer/rust-analyzer/issues/10793. +# RA invokes `./miri cargo ...` for each workspace, so we need to forward that to the main `miri` +# script. See . exec "$(dirname "$0")"/../miri "$@" diff --git a/miri b/miri index 5088a9ceffdbb..a72fe91f594b6 100755 --- a/miri +++ b/miri @@ -29,6 +29,10 @@ Format all sources and tests. are passed to `rustfmt`. ./miri clippy : Runs clippy on all sources. are passed to `cargo clippy`. +./miri cargo : +Runs just `cargo ` with the Miri-specific environment variables. +Mainly meant to be invoked by rust-analyzer. + ./miri many-seeds : Runs over and over again with different seeds for Miri. The MIRIFLAGS variable is set to its original value appended with ` -Zmiri-seed=$SEED` for @@ -44,7 +48,7 @@ MIRI_SYSROOT: If already set, the "sysroot setup" step is skipped. CARGO_EXTRA_FLAGS: -Pass extra flags to all cargo invocations. +Pass extra flags to all cargo invocations. (Ignored by `./miri cargo`.) EOF ) @@ -218,6 +222,11 @@ clippy) $CARGO clippy $CARGO_EXTRA_FLAGS --manifest-path "$MIRIDIR"/ui_test/Cargo.toml --all-targets "$@" $CARGO clippy $CARGO_EXTRA_FLAGS --manifest-path "$MIRIDIR"/cargo-miri/Cargo.toml "$@" ;; +cargo) + # We carefully kept the working dir intact, so this will run cargo *on the workspace in the + # current working dir*, not on the main Miri workspace. That is exactly what RA needs. + $CARGO "$@" + ;; *) if [ -n "$COMMAND" ]; then echo "Unknown command: $COMMAND" From b073fe2537bfd59abb9cb7631768e808312f3fda Mon Sep 17 00:00:00 2001 From: Hiroki6 Date: Sun, 21 Aug 2022 23:28:13 +0200 Subject: [PATCH 3670/3747] move vector_clock and sync into concurrency & make vector_clock private move thread it back --- src/concurrency/data_race.rs | 5 ++++- src/concurrency/mod.rs | 2 ++ src/{ => concurrency}/sync.rs | 3 ++- src/{ => concurrency}/vector_clock.rs | 0 src/concurrency/weak_memory.rs | 1 + src/lib.rs | 16 ++++++---------- src/shims/time.rs | 2 +- src/shims/unix/sync.rs | 2 +- src/thread.rs | 2 +- 9 files changed, 18 insertions(+), 15 deletions(-) rename src/{ => concurrency}/sync.rs (99%) rename src/{ => concurrency}/vector_clock.rs (100%) diff --git a/src/concurrency/data_race.rs b/src/concurrency/data_race.rs index 410c2b9c3ddf7..0e176ec91fcfe 100644 --- a/src/concurrency/data_race.rs +++ b/src/concurrency/data_race.rs @@ -54,7 +54,10 @@ use rustc_target::abi::{Align, Size}; use crate::*; -use super::weak_memory::EvalContextExt as _; +use super::{ + vector_clock::{VClock, VTimestamp, VectorIdx}, + weak_memory::EvalContextExt as _, +}; pub type AllocExtra = VClockAlloc; diff --git a/src/concurrency/mod.rs b/src/concurrency/mod.rs index 5f8bba802728c..07c3f0d5993e2 100644 --- a/src/concurrency/mod.rs +++ b/src/concurrency/mod.rs @@ -1,3 +1,5 @@ pub mod data_race; mod range_object_map; +pub mod sync; +mod vector_clock; pub mod weak_memory; diff --git a/src/sync.rs b/src/concurrency/sync.rs similarity index 99% rename from src/sync.rs rename to src/concurrency/sync.rs index de7d528d3346a..81e5a83a1fb5e 100644 --- a/src/sync.rs +++ b/src/concurrency/sync.rs @@ -7,6 +7,7 @@ use log::trace; use rustc_data_structures::fx::FxHashMap; use rustc_index::vec::{Idx, IndexVec}; +use super::vector_clock::VClock; use crate::*; /// We cannot use the `newtype_index!` macro because we have to use 0 as a @@ -150,7 +151,7 @@ struct FutexWaiter { /// The state of all synchronization variables. #[derive(Default, Debug)] -pub(super) struct SynchronizationState { +pub(crate) struct SynchronizationState { mutexes: IndexVec, rwlocks: IndexVec, condvars: IndexVec, diff --git a/src/vector_clock.rs b/src/concurrency/vector_clock.rs similarity index 100% rename from src/vector_clock.rs rename to src/concurrency/vector_clock.rs diff --git a/src/concurrency/weak_memory.rs b/src/concurrency/weak_memory.rs index 317258a028d0b..30037b6394e56 100644 --- a/src/concurrency/weak_memory.rs +++ b/src/concurrency/weak_memory.rs @@ -87,6 +87,7 @@ use crate::*; use super::{ data_race::{GlobalState as DataRaceState, ThreadClockSet}, range_object_map::{AccessType, RangeObjectMap}, + vector_clock::{VClock, VTimestamp, VectorIdx}, }; pub type AllocExtra = StoreBufferAlloc; diff --git a/src/lib.rs b/src/lib.rs index 8ca3e8d15e182..d2bb904f3e5d4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -61,9 +61,7 @@ mod operator; mod range_map; mod shims; mod stacked_borrows; -mod sync; -mod thread; -mod vector_clock; +pub mod thread; // Establish a "crate-wide prelude": we often import `crate::*`. @@ -87,17 +85,17 @@ pub use crate::concurrency::data_race::{ EvalContextExt as DataRaceEvalContextExt, }; pub use crate::diagnostics::{ - register_diagnostic, report_error, EvalContextExt as DiagnosticsEvalContextExt, - NonHaltingDiagnostic, TerminationInfo, + EvalContextExt as DiagnosticsEvalContextExt, NonHaltingDiagnostic, register_diagnostic, + report_error, TerminationInfo, }; pub use crate::eval::{ - create_ecx, eval_entry, AlignmentCheck, BacktraceStyle, IsolatedOp, MiriConfig, RejectOpWith, + AlignmentCheck, BacktraceStyle, create_ecx, eval_entry, IsolatedOp, MiriConfig, RejectOpWith, }; pub use crate::helpers::{CurrentSpan, EvalContextExt as HelpersEvalContextExt}; pub use crate::intptrcast::ProvenanceMode; pub use crate::machine::{ AllocExtra, Evaluator, FrameData, MiriEvalContext, MiriEvalContextExt, MiriMemoryKind, - Provenance, ProvenanceExtra, NUM_CPUS, PAGE_SIZE, STACK_ADDR, STACK_SIZE, + NUM_CPUS, PAGE_SIZE, Provenance, ProvenanceExtra, STACK_ADDR, STACK_SIZE, }; pub use crate::mono_hash_map::MonoHashMap; pub use crate::operator::EvalContextExt as OperatorEvalContextExt; @@ -105,12 +103,10 @@ pub use crate::range_map::RangeMap; pub use crate::stacked_borrows::{ CallId, EvalContextExt as StackedBorEvalContextExt, Item, Permission, SbTag, Stack, Stacks, }; -pub use crate::sync::{CondvarId, EvalContextExt as SyncEvalContextExt, MutexId, RwLockId}; +pub use concurrency::sync::{CondvarId, EvalContextExt as SyncEvalContextExt, MutexId, RwLockId}; pub use crate::thread::{ EvalContextExt as ThreadsEvalContextExt, SchedulingAction, ThreadId, ThreadManager, ThreadState, }; -pub use crate::vector_clock::{VClock, VTimestamp, VectorIdx}; - /// Insert rustc arguments at the beginning of the argument list that Miri wants to be /// set per default, for maximal validation power. pub const MIRI_DEFAULT_ARGS: &[&str] = &[ diff --git a/src/shims/time.rs b/src/shims/time.rs index 67303c47db7ee..d639939ec5bba 100644 --- a/src/shims/time.rs +++ b/src/shims/time.rs @@ -1,7 +1,7 @@ use std::time::{Duration, Instant, SystemTime}; +use crate::thread::Time; use crate::*; -use thread::Time; /// Returns the time elapsed between the provided time and the unix epoch as a `Duration`. pub fn system_time_to_duration<'tcx>(time: &SystemTime) -> InterpResult<'tcx, Duration> { diff --git a/src/shims/unix/sync.rs b/src/shims/unix/sync.rs index 69e632915b170..246cb100bcb5a 100644 --- a/src/shims/unix/sync.rs +++ b/src/shims/unix/sync.rs @@ -3,8 +3,8 @@ use std::time::SystemTime; use rustc_hir::LangItem; use rustc_middle::ty::{layout::TyAndLayout, query::TyCtxtAt, subst::Subst, Ty}; +use crate::thread::Time; use crate::*; -use thread::Time; // pthread_mutexattr_t is either 4 or 8 bytes, depending on the platform. diff --git a/src/thread.rs b/src/thread.rs index b92728be20874..dc8b1c291148d 100644 --- a/src/thread.rs +++ b/src/thread.rs @@ -15,7 +15,7 @@ use rustc_middle::ty::layout::TyAndLayout; use rustc_target::spec::abi::Abi; use crate::concurrency::data_race; -use crate::sync::SynchronizationState; +use crate::concurrency::sync::SynchronizationState; use crate::*; #[derive(Clone, Copy, Debug, PartialEq, Eq)] From 8ee68490122fba1849565e99804e8c78ee4d9e3a Mon Sep 17 00:00:00 2001 From: Hiroki6 Date: Sun, 21 Aug 2022 23:43:16 +0200 Subject: [PATCH 3671/3747] rustfmt --- src/lib.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index d2bb904f3e5d4..550d9b9d7b55a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -85,17 +85,17 @@ pub use crate::concurrency::data_race::{ EvalContextExt as DataRaceEvalContextExt, }; pub use crate::diagnostics::{ - EvalContextExt as DiagnosticsEvalContextExt, NonHaltingDiagnostic, register_diagnostic, - report_error, TerminationInfo, + register_diagnostic, report_error, EvalContextExt as DiagnosticsEvalContextExt, + NonHaltingDiagnostic, TerminationInfo, }; pub use crate::eval::{ - AlignmentCheck, BacktraceStyle, create_ecx, eval_entry, IsolatedOp, MiriConfig, RejectOpWith, + create_ecx, eval_entry, AlignmentCheck, BacktraceStyle, IsolatedOp, MiriConfig, RejectOpWith, }; pub use crate::helpers::{CurrentSpan, EvalContextExt as HelpersEvalContextExt}; pub use crate::intptrcast::ProvenanceMode; pub use crate::machine::{ AllocExtra, Evaluator, FrameData, MiriEvalContext, MiriEvalContextExt, MiriMemoryKind, - NUM_CPUS, PAGE_SIZE, Provenance, ProvenanceExtra, STACK_ADDR, STACK_SIZE, + Provenance, ProvenanceExtra, NUM_CPUS, PAGE_SIZE, STACK_ADDR, STACK_SIZE, }; pub use crate::mono_hash_map::MonoHashMap; pub use crate::operator::EvalContextExt as OperatorEvalContextExt; @@ -103,10 +103,10 @@ pub use crate::range_map::RangeMap; pub use crate::stacked_borrows::{ CallId, EvalContextExt as StackedBorEvalContextExt, Item, Permission, SbTag, Stack, Stacks, }; -pub use concurrency::sync::{CondvarId, EvalContextExt as SyncEvalContextExt, MutexId, RwLockId}; pub use crate::thread::{ EvalContextExt as ThreadsEvalContextExt, SchedulingAction, ThreadId, ThreadManager, ThreadState, }; +pub use concurrency::sync::{CondvarId, EvalContextExt as SyncEvalContextExt, MutexId, RwLockId}; /// Insert rustc arguments at the beginning of the argument list that Miri wants to be /// set per default, for maximal validation power. pub const MIRI_DEFAULT_ARGS: &[&str] = &[ From 8497fd490691c9db35d09f3a0c10cf65b023b784 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 23 Jul 2022 09:10:23 -0400 Subject: [PATCH 3672/3747] pass clippy::integer_arithmetic in our shims --- src/lib.rs | 1 + src/shims/backtrace.rs | 2 +- src/shims/foreign_items.rs | 9 ++++++++- src/shims/intrinsics/simd.rs | 31 +++++++++++++++++++------------ src/shims/mod.rs | 2 ++ src/shims/time.rs | 2 +- src/shims/tls.rs | 1 + src/shims/unix/fs.rs | 1 + src/shims/unix/linux/sync.rs | 1 + src/shims/windows/handle.rs | 10 +++++++--- 10 files changed, 42 insertions(+), 18 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 8ca3e8d15e182..aff63c3c19dfa 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -27,6 +27,7 @@ clippy::too_many_arguments, clippy::type_complexity, clippy::single_element_loop, + clippy::needless_return, // We are not implementing queries here so it's fine rustc::potential_query_instability )] diff --git a/src/shims/backtrace.rs b/src/shims/backtrace.rs index 9182b2a72173b..bce4961339cd5 100644 --- a/src/shims/backtrace.rs +++ b/src/shims/backtrace.rs @@ -175,7 +175,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // file would have more than 2^32 lines or columns, but whatever, just default to 0. let lineno: u32 = u32::try_from(lo.line).unwrap_or(0); // `lo.col` is 0-based - add 1 to make it 1-based for the caller. - let colno: u32 = u32::try_from(lo.col.0 + 1).unwrap_or(0); + let colno: u32 = u32::try_from(lo.col.0.saturating_add(1)).unwrap_or(0); let dest = this.force_allocation(dest)?; if let ty::Adt(adt, _) = dest.layout.ty.kind() { diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index e7cfd43f1b1e7..b9bd713d4d316 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -164,6 +164,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx .expect("interpreting a non-executable crate"); for cnum in iter::once(LOCAL_CRATE).chain( dependency_format.1.iter().enumerate().filter_map(|(num, &linkage)| { + // We add 1 to the number because that's what rustc also does everywhere it + // calls `CrateNum::new`... + #[allow(clippy::integer_arithmetic)] (linkage != Linkage::NotLinked).then_some(CrateNum::new(num + 1)) }), ) { @@ -542,7 +545,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx .rev() .position(|&c| c == val) { - let new_ptr = ptr.offset(Size::from_bytes(num - idx as u64 - 1), this)?; + let idx = u64::try_from(idx).unwrap(); + #[allow(clippy::integer_arithmetic)] // idx < num, so this never wraps + let new_ptr = ptr.offset(Size::from_bytes(num - idx - 1), this)?; this.write_pointer(new_ptr, dest)?; } else { this.write_null(dest)?; @@ -708,7 +713,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let a = this.read_scalar(a)?.to_u64()?; let b = this.read_scalar(b)?.to_u64()?; + #[allow(clippy::integer_arithmetic)] // adding two u64 and a u8 cannot wrap in a u128 let wide_sum = u128::from(c_in) + u128::from(a) + u128::from(b); + #[allow(clippy::integer_arithmetic)] // it's a u128, we can shift by 64 let (c_out, sum) = ((wide_sum >> 64).truncate::(), wide_sum.truncate::()); let c_out_field = this.place_field(dest, 0)?; diff --git a/src/shims/intrinsics/simd.rs b/src/shims/intrinsics/simd.rs index 0c3241683a186..1b7ec5913506e 100644 --- a/src/shims/intrinsics/simd.rs +++ b/src/shims/intrinsics/simd.rs @@ -393,6 +393,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx assert_eq!(bitmask_len, mask.layout.size.bits()); assert_eq!(dest_len, yes_len); assert_eq!(dest_len, no_len); + let dest_len = u32::try_from(dest_len).unwrap(); + let bitmask_len = u32::try_from(bitmask_len).unwrap(); let mask: u64 = this .read_scalar(mask)? @@ -401,18 +403,20 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx .try_into() .unwrap(); for i in 0..dest_len { - let mask = - mask & (1 << simd_bitmask_index(i, dest_len, this.data_layout().endian)); - let yes = this.read_immediate(&this.mplace_index(&yes, i)?.into())?; - let no = this.read_immediate(&this.mplace_index(&no, i)?.into())?; - let dest = this.mplace_index(&dest, i)?; + let mask = mask + & 1u64 + .checked_shl(simd_bitmask_index(i, dest_len, this.data_layout().endian)) + .unwrap(); + let yes = this.read_immediate(&this.mplace_index(&yes, i.into())?.into())?; + let no = this.read_immediate(&this.mplace_index(&no, i.into())?.into())?; + let dest = this.mplace_index(&dest, i.into())?; let val = if mask != 0 { yes } else { no }; this.write_immediate(*val, &dest.into())?; } for i in dest_len..bitmask_len { // If the mask is "padded", ensure that padding is all-zero. - let mask = mask & (1 << i); + let mask = mask & 1u64.checked_shl(i).unwrap(); if mask != 0 { throw_ub_format!( "a SIMD bitmask less than 8 bits long must be filled with 0s for the remaining bits" @@ -485,9 +489,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let val = if src_index < left_len { this.read_immediate(&this.mplace_index(&left, src_index)?.into())? } else if src_index < left_len.checked_add(right_len).unwrap() { - this.read_immediate( - &this.mplace_index(&right, src_index - left_len)?.into(), - )? + let right_idx = src_index.checked_sub(left_len).unwrap(); + this.read_immediate(&this.mplace_index(&right, right_idx)?.into())? } else { span_bug!( this.cur_span(), @@ -551,12 +554,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx assert!(dest.layout.ty.is_integral()); assert!(bitmask_len <= 64); assert_eq!(bitmask_len, dest.layout.size.bits()); + let op_len = u32::try_from(op_len).unwrap(); let mut res = 0u64; for i in 0..op_len { - let op = this.read_immediate(&this.mplace_index(&op, i)?.into())?; + let op = this.read_immediate(&this.mplace_index(&op, i.into())?.into())?; if simd_element_to_bool(op)? { - res |= 1 << simd_bitmask_index(i, op_len, this.data_layout().endian); + res |= 1u64 + .checked_shl(simd_bitmask_index(i, op_len, this.data_layout().endian)) + .unwrap(); } } this.write_int(res, dest)?; @@ -583,10 +589,11 @@ fn simd_element_to_bool(elem: ImmTy<'_, Provenance>) -> InterpResult<'_, bool> { }) } -fn simd_bitmask_index(idx: u64, vec_len: u64, endianess: Endian) -> u64 { +fn simd_bitmask_index(idx: u32, vec_len: u32, endianess: Endian) -> u32 { assert!(idx < vec_len); match endianess { Endian::Little => idx, + #[allow(clippy::integer_arithmetic)] // idx < vec_len Endian::Big => vec_len - 1 - idx, // reverse order of bits } } diff --git a/src/shims/mod.rs b/src/shims/mod.rs index f5b4de30a5700..618295592450f 100644 --- a/src/shims/mod.rs +++ b/src/shims/mod.rs @@ -1,3 +1,5 @@ +#![warn(clippy::integer_arithmetic)] + mod backtrace; pub mod foreign_items; pub mod intrinsics; diff --git a/src/shims/time.rs b/src/shims/time.rs index 67303c47db7ee..d3c545ea58cc9 100644 --- a/src/shims/time.rs +++ b/src/shims/time.rs @@ -84,7 +84,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Ok(0) } - #[allow(non_snake_case)] + #[allow(non_snake_case, clippy::integer_arithmetic)] fn GetSystemTimeAsFileTime( &mut self, LPFILETIME_op: &OpTy<'tcx, Provenance>, diff --git a/src/shims/tls.rs b/src/shims/tls.rs index a520548798113..ede4b12c2d21c 100644 --- a/src/shims/tls.rs +++ b/src/shims/tls.rs @@ -63,6 +63,7 @@ impl<'tcx> Default for TlsData<'tcx> { impl<'tcx> TlsData<'tcx> { /// Generate a new TLS key with the given destructor. /// `max_size` determines the integer size the key has to fit in. + #[allow(clippy::integer_arithmetic)] pub fn create_tls_key( &mut self, dtor: Option>, diff --git a/src/shims/unix/fs.rs b/src/shims/unix/fs.rs index 2a6499ce99949..d3f4f5ef5451f 100644 --- a/src/shims/unix/fs.rs +++ b/src/shims/unix/fs.rs @@ -443,6 +443,7 @@ pub struct DirHandler { } impl DirHandler { + #[allow(clippy::integer_arithmetic)] fn insert_new(&mut self, read_dir: ReadDir) -> u64 { let id = self.next_id; self.next_id += 1; diff --git a/src/shims/unix/linux/sync.rs b/src/shims/unix/linux/sync.rs index b33553f4663b9..f9c97a23721c5 100644 --- a/src/shims/unix/linux/sync.rs +++ b/src/shims/unix/linux/sync.rs @@ -242,6 +242,7 @@ pub fn futex<'tcx>( // before doing the syscall. this.atomic_fence(AtomicFenceOrd::SeqCst)?; let mut n = 0; + #[allow(clippy::integer_arithmetic)] for _ in 0..val { if let Some(thread) = this.futex_wake(addr_usize, bitset) { this.unblock_thread(thread); diff --git a/src/shims/windows/handle.rs b/src/shims/windows/handle.rs index 443af1dfeaaa4..92e0a9a34e122 100644 --- a/src/shims/windows/handle.rs +++ b/src/shims/windows/handle.rs @@ -62,6 +62,7 @@ impl Handle { let floor_log2 = variant_count.ilog2(); // we need to add one for non powers of two to compensate for the difference + #[allow(clippy::integer_arithmetic)] // cannot overflow if variant_count.is_power_of_two() { floor_log2 } else { floor_log2 + 1 } } @@ -73,7 +74,7 @@ impl Handle { /// None of this layout is guaranteed to applications by Windows or Miri. fn to_packed(self) -> u32 { let disc_size = Self::packed_disc_size(); - let data_size = u32::BITS - disc_size; + let data_size = u32::BITS.checked_sub(disc_size).unwrap(); let discriminant = self.discriminant(); let data = self.data(); @@ -86,7 +87,8 @@ impl Handle { // packs the data into the lower `data_size` bits // and packs the discriminant right above the data - discriminant << data_size | data + #[allow(clippy::integer_arithmetic)] // cannot overflow + return discriminant << data_size | data; } fn new(discriminant: u32, data: u32) -> Option { @@ -101,12 +103,14 @@ impl Handle { /// see docs for `to_packed` fn from_packed(handle: u32) -> Option { let disc_size = Self::packed_disc_size(); - let data_size = u32::BITS - disc_size; + let data_size = u32::BITS.checked_sub(disc_size).unwrap(); // the lower `data_size` bits of this mask are 1 + #[allow(clippy::integer_arithmetic)] // cannot overflow let data_mask = 2u32.pow(data_size) - 1; // the discriminant is stored right above the lower `data_size` bits + #[allow(clippy::integer_arithmetic)] // cannot overflow let discriminant = handle >> data_size; // the data is stored in the lower `data_size` bits From daaa81fc5e5290e6a9c191e185206c2fe616a105 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 11 Aug 2022 20:40:53 -0400 Subject: [PATCH 3673/3747] document general shim pattern --- src/shims/foreign_items.rs | 32 +++++++++++++++++++++++++++ src/shims/unix/foreign_items.rs | 1 + src/shims/unix/linux/foreign_items.rs | 2 ++ src/shims/unix/macos/foreign_items.rs | 2 ++ src/shims/windows/foreign_items.rs | 2 ++ 5 files changed, 39 insertions(+) diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index e7cfd43f1b1e7..f9e9f7f02caaf 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -366,6 +366,38 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, EmulateByNameResult<'mir, 'tcx>> { let this = self.eval_context_mut(); + // When adding a new shim, you should follow the following pattern: + // ``` + // "shim_name" => { + // let [arg1, arg2, arg3] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; + // let result = this.shim_name(arg1, arg2, arg3)?; + // this.write_scalar(result, dest)?; + // } + // ``` + // and then define `shim_name` as a helper function in an extension trait in a suitable file + // (see e.g. `unix/fs.rs`): + // ``` + // fn shim_name( + // &mut self, + // arg1: &OpTy<'tcx, Provenance>, + // arg2: &OpTy<'tcx, Provenance>, + // arg3: &OpTy<'tcx, Provenance>) + // -> InterpResult<'tcx, Scalar> { + // let this = self.eval_context_mut(); + // + // // First thing: load all the arguments. Details depend on the shim. + // let arg1 = this.read_scalar(arg1)?.to_u32()?; + // let arg2 = this.read_pointer(arg2)?; // when you need to work with the pointer directly + // let arg3 = this.deref_operand(arg3)?; // when you want to load/store through the pointer at its declared type + // + // // ... + // + // Ok(Scalar::from_u32(42)) + // } + // ``` + // You might find existing shims not following this pattern, most + // likely because they predate it or because for some reason they cannot be made to fit. + // Here we dispatch all the shims for foreign functions. If you have a platform specific // shim, add it to the corresponding submodule. match link_name.as_str() { diff --git a/src/shims/unix/foreign_items.rs b/src/shims/unix/foreign_items.rs index 58b0997c6c017..49bff7c17ea44 100644 --- a/src/shims/unix/foreign_items.rs +++ b/src/shims/unix/foreign_items.rs @@ -24,6 +24,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, EmulateByNameResult<'mir, 'tcx>> { let this = self.eval_context_mut(); + // See `fn emulate_foreign_item_by_name` in `shims/foreign_items.rs` for the general pattern. #[rustfmt::skip] match link_name.as_str() { // Environment related shims diff --git a/src/shims/unix/linux/foreign_items.rs b/src/shims/unix/linux/foreign_items.rs index 6881d829c150d..1e007db1e9329 100644 --- a/src/shims/unix/linux/foreign_items.rs +++ b/src/shims/unix/linux/foreign_items.rs @@ -19,6 +19,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, EmulateByNameResult<'mir, 'tcx>> { let this = self.eval_context_mut(); + // See `fn emulate_foreign_item_by_name` in `shims/foreign_items.rs` for the general pattern. + match link_name.as_str() { // errno "__errno_location" => { diff --git a/src/shims/unix/macos/foreign_items.rs b/src/shims/unix/macos/foreign_items.rs index fd7d5fb763eef..be789648e78dc 100644 --- a/src/shims/unix/macos/foreign_items.rs +++ b/src/shims/unix/macos/foreign_items.rs @@ -17,6 +17,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, EmulateByNameResult<'mir, 'tcx>> { let this = self.eval_context_mut(); + // See `fn emulate_foreign_item_by_name` in `shims/foreign_items.rs` for the general pattern. + match link_name.as_str() { // errno "__error" => { diff --git a/src/shims/windows/foreign_items.rs b/src/shims/windows/foreign_items.rs index d853f3084d492..c6536d1d094ca 100644 --- a/src/shims/windows/foreign_items.rs +++ b/src/shims/windows/foreign_items.rs @@ -23,6 +23,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, EmulateByNameResult<'mir, 'tcx>> { let this = self.eval_context_mut(); + // See `fn emulate_foreign_item_by_name` in `shims/foreign_items.rs` for the general pattern. + // Windows API stubs. // HANDLE = isize // NTSTATUS = LONH = i32 From afacf62cf0421e032e6e001b6f4ba49f508b14c8 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 22 Aug 2022 12:13:42 -0400 Subject: [PATCH 3674/3747] notes on TLS dtor order --- src/shims/tls.rs | 11 +- tests/pass/concurrency/tls_lib_drop.rs | 10 +- tests/pass/concurrency/tls_lib_drop.stdout | 4 +- .../pass/concurrency/tls_lib_drop_windows.rs | 191 ------------------ .../concurrency/tls_lib_drop_windows.stdout | 5 - .../concurrency/tls_pthread_drop_order.rs | 7 + 6 files changed, 24 insertions(+), 204 deletions(-) delete mode 100644 tests/pass/concurrency/tls_lib_drop_windows.rs delete mode 100644 tests/pass/concurrency/tls_lib_drop_windows.stdout diff --git a/src/shims/tls.rs b/src/shims/tls.rs index ede4b12c2d21c..f0f1d0e52bdb9 100644 --- a/src/shims/tls.rs +++ b/src/shims/tls.rs @@ -165,8 +165,8 @@ impl<'tcx> TlsData<'tcx> { /// and the thread has a non-NULL value associated with that key, /// the value of the key is set to NULL, and then the function pointed /// to is called with the previously associated value as its sole argument. - /// The order of destructor calls is unspecified if more than one destructor - /// exists for a thread when it exits. + /// **The order of destructor calls is unspecified if more than one destructor + /// exists for a thread when it exits.** /// /// If, after all the destructors have been called for all non-NULL values /// with associated destructors, there are still some non-NULL values with @@ -188,6 +188,13 @@ impl<'tcx> TlsData<'tcx> { Some(key) => Excluded(key), None => Unbounded, }; + // We interpret the documentaion above (taken from POSIX) as saying that we need to iterate + // over all keys and run each destructor at least once before running any destructor a 2nd + // time. That's why we have `key` to indicate how far we got in the current iteration. If we + // return `None`, `schedule_next_pthread_tls_dtor` will re-try with `ket` set to `None` to + // start the next round. + // TODO: In the future, we might consider randomizing destructor order, but we still have to + // uphold this requirement. for (&key, TlsEntry { data, dtor }) in thread_local.range_mut((start, Unbounded)) { match data.entry(thread_id) { BTreeEntry::Occupied(entry) => { diff --git a/tests/pass/concurrency/tls_lib_drop.rs b/tests/pass/concurrency/tls_lib_drop.rs index 3fd6e2d6f2426..04e89ec361b74 100644 --- a/tests/pass/concurrency/tls_lib_drop.rs +++ b/tests/pass/concurrency/tls_lib_drop.rs @@ -1,5 +1,3 @@ -//@ignore-target-windows: TLS destructor order is different on Windows. - use std::cell::RefCell; use std::thread; @@ -24,14 +22,18 @@ thread_local! { /// Check that destructors of the library thread locals are executed immediately /// after a thread terminates. fn check_destructors() { + // We use the same value for both of them, since destructor order differs between Miri on Linux + // (which uses `register_dtor_fallback`, in the end using a single pthread_key to manage a + // thread-local linked list of dtors to call), real Linux rustc (which uses + // `__cxa_thread_atexit_impl`), and Miri on Windows. thread::spawn(|| { A.with(|f| { assert_eq!(*f.value.borrow(), 0); - *f.value.borrow_mut() = 5; + *f.value.borrow_mut() = 8; }); A_CONST.with(|f| { assert_eq!(*f.value.borrow(), 10); - *f.value.borrow_mut() = 15; + *f.value.borrow_mut() = 8; }); }) .join() diff --git a/tests/pass/concurrency/tls_lib_drop.stdout b/tests/pass/concurrency/tls_lib_drop.stdout index 9cd7e049d1a0a..b7877820a0ca9 100644 --- a/tests/pass/concurrency/tls_lib_drop.stdout +++ b/tests/pass/concurrency/tls_lib_drop.stdout @@ -1,5 +1,5 @@ -Dropping: 5 (should be before 'Continue main 1'). -Dropping: 15 (should be before 'Continue main 1'). +Dropping: 8 (should be before 'Continue main 1'). +Dropping: 8 (should be before 'Continue main 1'). Continue main 1. Joining: 7 (should be before 'Continue main 2'). Continue main 2. diff --git a/tests/pass/concurrency/tls_lib_drop_windows.rs b/tests/pass/concurrency/tls_lib_drop_windows.rs deleted file mode 100644 index e8c6538e701d3..0000000000000 --- a/tests/pass/concurrency/tls_lib_drop_windows.rs +++ /dev/null @@ -1,191 +0,0 @@ -//@only-target-windows: TLS destructor order is different on Windows. - -use std::cell::RefCell; -use std::thread; - -struct TestCell { - value: RefCell, -} - -impl Drop for TestCell { - fn drop(&mut self) { - for _ in 0..10 { - thread::yield_now(); - } - println!("Dropping: {} (should be before 'Continue main 1').", *self.value.borrow()) - } -} - -thread_local! { - static A: TestCell = TestCell { value: RefCell::new(0) }; - static A_CONST: TestCell = const { TestCell { value: RefCell::new(10) } }; -} - -/// Check that destructors of the library thread locals are executed immediately -/// after a thread terminates. -fn check_destructors() { - thread::spawn(|| { - A.with(|f| { - assert_eq!(*f.value.borrow(), 0); - *f.value.borrow_mut() = 5; - }); - A_CONST.with(|f| { - assert_eq!(*f.value.borrow(), 10); - *f.value.borrow_mut() = 15; - }); - }) - .join() - .unwrap(); - println!("Continue main 1.") -} - -struct JoinCell { - value: RefCell>>, -} - -impl Drop for JoinCell { - fn drop(&mut self) { - for _ in 0..10 { - thread::yield_now(); - } - let join_handle = self.value.borrow_mut().take().unwrap(); - println!("Joining: {} (should be before 'Continue main 2').", join_handle.join().unwrap()); - } -} - -thread_local! { - static B: JoinCell = JoinCell { value: RefCell::new(None) }; -} - -/// Check that the destructor can be blocked joining another thread. -fn check_blocking() { - thread::spawn(|| { - B.with(|f| { - assert!(f.value.borrow().is_none()); - let handle = thread::spawn(|| 7); - *f.value.borrow_mut() = Some(handle); - }); - }) - .join() - .unwrap(); - println!("Continue main 2."); - // Preempt the main thread so that the destructor gets executed and can join - // the thread. - thread::yield_now(); - thread::yield_now(); -} - -// This test tests that TLS destructors have run before the thread joins. The -// test has no false positives (meaning: if the test fails, there's actually -// an ordering problem). It may have false negatives, where the test passes but -// join is not guaranteed to be after the TLS destructors. However, false -// negatives should be exceedingly rare due to judicious use of -// thread::yield_now and running the test several times. -fn join_orders_after_tls_destructors() { - use std::sync::atomic::{AtomicU8, Ordering}; - - // We emulate a synchronous MPSC rendezvous channel using only atomics and - // thread::yield_now. We can't use std::mpsc as the implementation itself - // may rely on thread locals. - // - // The basic state machine for an SPSC rendezvous channel is: - // FRESH -> THREAD1_WAITING -> MAIN_THREAD_RENDEZVOUS - // where the first transition is done by the “receiving” thread and the 2nd - // transition is done by the “sending” thread. - // - // We add an additional state `THREAD2_LAUNCHED` between `FRESH` and - // `THREAD1_WAITING` to block until all threads are actually running. - // - // A thread that joins on the “receiving” thread completion should never - // observe the channel in the `THREAD1_WAITING` state. If this does occur, - // we switch to the “poison” state `THREAD2_JOINED` and panic all around. - // (This is equivalent to “sending” from an alternate producer thread.) - const FRESH: u8 = 0; - const THREAD2_LAUNCHED: u8 = 1; - const THREAD1_WAITING: u8 = 2; - const MAIN_THREAD_RENDEZVOUS: u8 = 3; - const THREAD2_JOINED: u8 = 4; - static SYNC_STATE: AtomicU8 = AtomicU8::new(FRESH); - - for _ in 0..10 { - SYNC_STATE.store(FRESH, Ordering::SeqCst); - - let jh = thread::Builder::new() - .name("thread1".into()) - .spawn(move || { - struct TlDrop; - - impl Drop for TlDrop { - fn drop(&mut self) { - let mut sync_state = SYNC_STATE.swap(THREAD1_WAITING, Ordering::SeqCst); - loop { - match sync_state { - THREAD2_LAUNCHED | THREAD1_WAITING => thread::yield_now(), - MAIN_THREAD_RENDEZVOUS => break, - THREAD2_JOINED => - panic!( - "Thread 1 still running after thread 2 joined on thread 1" - ), - v => unreachable!("sync state: {}", v), - } - sync_state = SYNC_STATE.load(Ordering::SeqCst); - } - } - } - - thread_local! { - static TL_DROP: TlDrop = TlDrop; - } - - TL_DROP.with(|_| {}); - - loop { - match SYNC_STATE.load(Ordering::SeqCst) { - FRESH => thread::yield_now(), - THREAD2_LAUNCHED => break, - v => unreachable!("sync state: {}", v), - } - } - }) - .unwrap(); - - let jh2 = thread::Builder::new() - .name("thread2".into()) - .spawn(move || { - assert_eq!(SYNC_STATE.swap(THREAD2_LAUNCHED, Ordering::SeqCst), FRESH); - jh.join().unwrap(); - match SYNC_STATE.swap(THREAD2_JOINED, Ordering::SeqCst) { - MAIN_THREAD_RENDEZVOUS => return, - THREAD2_LAUNCHED | THREAD1_WAITING => { - panic!("Thread 2 running after thread 1 join before main thread rendezvous") - } - v => unreachable!("sync state: {:?}", v), - } - }) - .unwrap(); - - loop { - match SYNC_STATE.compare_exchange( - THREAD1_WAITING, - MAIN_THREAD_RENDEZVOUS, - Ordering::SeqCst, - Ordering::SeqCst, - ) { - Ok(_) => break, - Err(FRESH) => thread::yield_now(), - Err(THREAD2_LAUNCHED) => thread::yield_now(), - Err(THREAD2_JOINED) => { - panic!("Main thread rendezvous after thread 2 joined thread 1") - } - v => unreachable!("sync state: {:?}", v), - } - } - jh2.join().unwrap(); - } -} - -fn main() { - check_destructors(); - check_blocking(); - join_orders_after_tls_destructors(); -} diff --git a/tests/pass/concurrency/tls_lib_drop_windows.stdout b/tests/pass/concurrency/tls_lib_drop_windows.stdout deleted file mode 100644 index e5b8efcaf5fac..0000000000000 --- a/tests/pass/concurrency/tls_lib_drop_windows.stdout +++ /dev/null @@ -1,5 +0,0 @@ -Dropping: 15 (should be before 'Continue main 1'). -Dropping: 5 (should be before 'Continue main 1'). -Continue main 1. -Joining: 7 (should be before 'Continue main 2'). -Continue main 2. diff --git a/tests/pass/concurrency/tls_pthread_drop_order.rs b/tests/pass/concurrency/tls_pthread_drop_order.rs index 6200233c81193..6516396ac5404 100644 --- a/tests/pass/concurrency/tls_pthread_drop_order.rs +++ b/tests/pass/concurrency/tls_pthread_drop_order.rs @@ -1,4 +1,9 @@ //@ignore-target-windows: No libc on Windows +//! Test that pthread_key destructors are run in the right order. +//! Note that these are *not* used by actual `thread_local!` on Linux! Those use +//! `thread_local_dtor::register_dtor` from the stdlib instead. In Miri this hits the fallback path +//! in `register_dtor_fallback`, which uses a *single* pthread_key to manage a thread-local list of +//! dtors to call. use std::mem; use std::ptr; @@ -44,6 +49,8 @@ unsafe extern "C" fn dtor(ptr: *mut u64) { // If the record is wrong, the cannary will never get cleared, leading to a leak -> test fails. // If the record is incomplete (i.e., more dtor calls happen), the check at the beginning of this function will fail -> test fails. // The correct sequence is: First key 0, then key 1, then key 0. + // Note that this relies on dtor order, which is not specified by POSIX, but seems to be + // consistent between Miri and Linux currently (as of Aug 2022). if RECORD == 0_1_0 { drop(Box::from_raw(CANNARY)); CANNARY = ptr::null_mut(); From 5259fb9bb0f54bbcfdccce3a1fc28e01d0066e2c Mon Sep 17 00:00:00 2001 From: Hiroki6 Date: Mon, 22 Aug 2022 19:13:39 +0200 Subject: [PATCH 3675/3747] move thread.rs into concurrency --- src/concurrency/mod.rs | 1 + src/{ => concurrency}/thread.rs | 0 src/lib.rs | 5 ++--- src/shims/time.rs | 2 +- src/shims/unix/linux/sync.rs | 2 +- src/shims/unix/sync.rs | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) rename src/{ => concurrency}/thread.rs (100%) diff --git a/src/concurrency/mod.rs b/src/concurrency/mod.rs index 07c3f0d5993e2..61ef3d5640e00 100644 --- a/src/concurrency/mod.rs +++ b/src/concurrency/mod.rs @@ -1,5 +1,6 @@ pub mod data_race; mod range_object_map; pub mod sync; +pub mod thread; mod vector_clock; pub mod weak_memory; diff --git a/src/thread.rs b/src/concurrency/thread.rs similarity index 100% rename from src/thread.rs rename to src/concurrency/thread.rs diff --git a/src/lib.rs b/src/lib.rs index 5657bba64784d..846290ae6c6b4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -62,7 +62,6 @@ mod operator; mod range_map; mod shims; mod stacked_borrows; -pub mod thread; // Establish a "crate-wide prelude": we often import `crate::*`. @@ -104,10 +103,10 @@ pub use crate::range_map::RangeMap; pub use crate::stacked_borrows::{ CallId, EvalContextExt as StackedBorEvalContextExt, Item, Permission, SbTag, Stack, Stacks, }; -pub use crate::thread::{ +pub use concurrency::sync::{CondvarId, EvalContextExt as SyncEvalContextExt, MutexId, RwLockId}; +pub use concurrency::thread::{ EvalContextExt as ThreadsEvalContextExt, SchedulingAction, ThreadId, ThreadManager, ThreadState, }; -pub use concurrency::sync::{CondvarId, EvalContextExt as SyncEvalContextExt, MutexId, RwLockId}; /// Insert rustc arguments at the beginning of the argument list that Miri wants to be /// set per default, for maximal validation power. pub const MIRI_DEFAULT_ARGS: &[&str] = &[ diff --git a/src/shims/time.rs b/src/shims/time.rs index 3f4600e0e340b..a574a0612c47d 100644 --- a/src/shims/time.rs +++ b/src/shims/time.rs @@ -1,6 +1,6 @@ use std::time::{Duration, Instant, SystemTime}; -use crate::thread::Time; +use crate::concurrency::thread::Time; use crate::*; /// Returns the time elapsed between the provided time and the unix epoch as a `Duration`. diff --git a/src/shims/unix/linux/sync.rs b/src/shims/unix/linux/sync.rs index f9c97a23721c5..73a042d45b8fd 100644 --- a/src/shims/unix/linux/sync.rs +++ b/src/shims/unix/linux/sync.rs @@ -1,4 +1,4 @@ -use crate::thread::Time; +use crate::concurrency::thread::Time; use crate::*; use rustc_target::abi::{Align, Size}; use std::time::{Instant, SystemTime}; diff --git a/src/shims/unix/sync.rs b/src/shims/unix/sync.rs index 246cb100bcb5a..b8504fb08d48f 100644 --- a/src/shims/unix/sync.rs +++ b/src/shims/unix/sync.rs @@ -3,7 +3,7 @@ use std::time::SystemTime; use rustc_hir::LangItem; use rustc_middle::ty::{layout::TyAndLayout, query::TyCtxtAt, subst::Subst, Ty}; -use crate::thread::Time; +use crate::concurrency::thread::Time; use crate::*; // pthread_mutexattr_t is either 4 or 8 bytes, depending on the platform. From 2107cbbe2fb6b6ad3bbfc45464e3b08868de8d29 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 22 Aug 2022 14:48:47 -0400 Subject: [PATCH 3676/3747] reorganize imports a bit --- src/lib.rs | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 846290ae6c6b4..bd0cb8057022f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -80,9 +80,16 @@ pub use crate::shims::time::EvalContextExt as _; pub use crate::shims::tls::{EvalContextExt as _, TlsData}; pub use crate::shims::EvalContextExt as _; -pub use crate::concurrency::data_race::{ - AtomicFenceOrd, AtomicReadOrd, AtomicRwOrd, AtomicWriteOrd, - EvalContextExt as DataRaceEvalContextExt, +pub use crate::concurrency::{ + data_race::{ + AtomicFenceOrd, AtomicReadOrd, AtomicRwOrd, AtomicWriteOrd, + EvalContextExt as DataRaceEvalContextExt, + }, + sync::{CondvarId, EvalContextExt as SyncEvalContextExt, MutexId, RwLockId}, + thread::{ + EvalContextExt as ThreadsEvalContextExt, SchedulingAction, ThreadId, ThreadManager, + ThreadState, + }, }; pub use crate::diagnostics::{ register_diagnostic, report_error, EvalContextExt as DiagnosticsEvalContextExt, @@ -103,10 +110,7 @@ pub use crate::range_map::RangeMap; pub use crate::stacked_borrows::{ CallId, EvalContextExt as StackedBorEvalContextExt, Item, Permission, SbTag, Stack, Stacks, }; -pub use concurrency::sync::{CondvarId, EvalContextExt as SyncEvalContextExt, MutexId, RwLockId}; -pub use concurrency::thread::{ - EvalContextExt as ThreadsEvalContextExt, SchedulingAction, ThreadId, ThreadManager, ThreadState, -}; + /// Insert rustc arguments at the beginning of the argument list that Miri wants to be /// set per default, for maximal validation power. pub const MIRI_DEFAULT_ARGS: &[&str] = &[ From 1914b615ff77904308b7d0e5481fe5f053830444 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 22 Aug 2022 21:23:02 -0400 Subject: [PATCH 3677/3747] cope with rustc aborting due to a signal --- ui_test/src/lib.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ui_test/src/lib.rs b/ui_test/src/lib.rs index 871574c4936df..c87ac938ffd22 100644 --- a/ui_test/src/lib.rs +++ b/ui_test/src/lib.rs @@ -272,7 +272,7 @@ pub fn run_tests(mut config: Config) -> Result<()> { } Error::ErrorsWithoutPattern { path: None, msgs } => { eprintln!( - "There were {} unmatched diagnostics that occurred outside the testfile and had not pattern", + "There were {} unmatched diagnostics that occurred outside the testfile and had no pattern", msgs.len(), ); for Message { level, message } in msgs { @@ -629,8 +629,8 @@ pub enum Mode { impl Mode { fn ok(self, status: ExitStatus) -> Errors { - match (status.code().unwrap(), self) { - (1, Mode::Fail) | (101, Mode::Panic) | (0, Mode::Pass) => vec![], + match (status.code(), self) { + (Some(1), Mode::Fail) | (Some(101), Mode::Panic) | (Some(0), Mode::Pass) => vec![], _ => vec![Error::ExitStatus(self, status)], } } From 6f8885e60f4363752b8757e926f1a6db683dc21b Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 27 Jul 2022 08:56:24 +0000 Subject: [PATCH 3678/3747] Run `pass` tests without building dependencies first --- tests/compiletest.rs | 31 ++++++++++++++----- tests/{pass => pass-dep}/calloc.rs | 0 .../concurrency/libc_pthread_cond.rs | 0 .../concurrency/linux-futex.rs | 0 .../concurrency/tls_pthread_drop_order.rs | 0 .../{pass => pass-dep}/foreign-fn-linkname.rs | 0 tests/{pass => pass-dep}/malloc.rs | 0 tests/{pass/crates => pass-dep}/num_cpus.rs | 0 tests/{pass/crates => pass-dep}/page_size.rs | 0 tests/{pass/crates => pass-dep}/random.rs | 0 .../{pass => pass-dep}/regions-mock-trans.rs | 0 tests/{pass => pass-dep}/shims/fs.rs | 0 tests/{pass => pass-dep}/shims/fs.stderr | 0 tests/{pass => pass-dep}/shims/fs.stdout | 0 .../shims/fs_with_isolation.rs | 0 .../shims/fs_with_isolation.stderr | 0 tests/{pass => pass-dep}/shims/libc-misc.rs | 0 .../linux-getrandom-without-isolation.rs | 0 .../shims/linux-getrandom.rs | 0 .../shims/posix_memalign.rs | 0 tests/{pass => pass-dep}/shims/pthreads.rs | 0 21 files changed, 24 insertions(+), 7 deletions(-) rename tests/{pass => pass-dep}/calloc.rs (100%) rename tests/{pass => pass-dep}/concurrency/libc_pthread_cond.rs (100%) rename tests/{pass => pass-dep}/concurrency/linux-futex.rs (100%) rename tests/{pass => pass-dep}/concurrency/tls_pthread_drop_order.rs (100%) rename tests/{pass => pass-dep}/foreign-fn-linkname.rs (100%) rename tests/{pass => pass-dep}/malloc.rs (100%) rename tests/{pass/crates => pass-dep}/num_cpus.rs (100%) rename tests/{pass/crates => pass-dep}/page_size.rs (100%) rename tests/{pass/crates => pass-dep}/random.rs (100%) rename tests/{pass => pass-dep}/regions-mock-trans.rs (100%) rename tests/{pass => pass-dep}/shims/fs.rs (100%) rename tests/{pass => pass-dep}/shims/fs.stderr (100%) rename tests/{pass => pass-dep}/shims/fs.stdout (100%) rename tests/{pass => pass-dep}/shims/fs_with_isolation.rs (100%) rename tests/{pass => pass-dep}/shims/fs_with_isolation.stderr (100%) rename tests/{pass => pass-dep}/shims/libc-misc.rs (100%) rename tests/{pass => pass-dep}/shims/linux-getrandom-without-isolation.rs (100%) rename tests/{pass => pass-dep}/shims/linux-getrandom.rs (100%) rename tests/{pass => pass-dep}/shims/posix_memalign.rs (100%) rename tests/{pass => pass-dep}/shims/pthreads.rs (100%) diff --git a/tests/compiletest.rs b/tests/compiletest.rs index 48e0ae855be39..b38edc9e0f7dd 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -8,7 +8,12 @@ fn miri_path() -> PathBuf { PathBuf::from(option_env!("MIRI").unwrap_or(env!("CARGO_BIN_EXE_miri"))) } -fn run_tests(mode: Mode, path: &str, target: Option) -> Result<()> { +fn run_tests( + mode: Mode, + path: &str, + target: Option, + with_dependencies: bool, +) -> Result<()> { let in_rustc_test_suite = option_env!("RUSTC_STAGE").is_some(); // Add some flags we always want. @@ -68,7 +73,7 @@ fn run_tests(mode: Mode, path: &str, target: Option) -> Result<()> { path_filter: path_filter.collect(), program: miri_path(), output_conflict_handling, - dependencies_crate_manifest_path: use_std + dependencies_crate_manifest_path: (with_dependencies && use_std) .then(|| Path::new("test_dependencies").join("Cargo.toml")), dependency_builder: Some(DependencyBuilder { program: std::env::var_os("CARGO").unwrap().into(), @@ -132,7 +137,14 @@ regexes! { r"[^ ]*/\.?cargo/registry/.*/(.*\.rs)" => "CARGO_REGISTRY/.../$1", } -fn ui(mode: Mode, path: &str) -> Result<()> { +enum Dependencies { + WithDependencies, + WithoutDependencies, +} + +use Dependencies::*; + +fn ui(mode: Mode, path: &str, with_dependencies: Dependencies) -> Result<()> { let target = get_target(); let msg = format!( @@ -141,7 +153,11 @@ fn ui(mode: Mode, path: &str) -> Result<()> { ); eprintln!("{}", msg.green().bold()); - run_tests(mode, path, target) + let with_dependencies = match with_dependencies { + WithDependencies => true, + WithoutDependencies => false, + }; + run_tests(mode, path, target, with_dependencies) } fn get_target() -> Option { @@ -156,9 +172,10 @@ fn main() -> Result<()> { // Let the tests know where to store temp files (they might run for a different target, which can make this hard to find). env::set_var("MIRI_TEMP", env::temp_dir()); - ui(Mode::Pass, "tests/pass")?; - ui(Mode::Panic, "tests/panic")?; - ui(Mode::Fail, "tests/fail")?; + ui(Mode::Pass, "tests/pass", WithoutDependencies)?; + ui(Mode::Pass, "tests/pass-dep", WithDependencies)?; + ui(Mode::Panic, "tests/panic", WithDependencies)?; + ui(Mode::Fail, "tests/fail", WithDependencies)?; Ok(()) } diff --git a/tests/pass/calloc.rs b/tests/pass-dep/calloc.rs similarity index 100% rename from tests/pass/calloc.rs rename to tests/pass-dep/calloc.rs diff --git a/tests/pass/concurrency/libc_pthread_cond.rs b/tests/pass-dep/concurrency/libc_pthread_cond.rs similarity index 100% rename from tests/pass/concurrency/libc_pthread_cond.rs rename to tests/pass-dep/concurrency/libc_pthread_cond.rs diff --git a/tests/pass/concurrency/linux-futex.rs b/tests/pass-dep/concurrency/linux-futex.rs similarity index 100% rename from tests/pass/concurrency/linux-futex.rs rename to tests/pass-dep/concurrency/linux-futex.rs diff --git a/tests/pass/concurrency/tls_pthread_drop_order.rs b/tests/pass-dep/concurrency/tls_pthread_drop_order.rs similarity index 100% rename from tests/pass/concurrency/tls_pthread_drop_order.rs rename to tests/pass-dep/concurrency/tls_pthread_drop_order.rs diff --git a/tests/pass/foreign-fn-linkname.rs b/tests/pass-dep/foreign-fn-linkname.rs similarity index 100% rename from tests/pass/foreign-fn-linkname.rs rename to tests/pass-dep/foreign-fn-linkname.rs diff --git a/tests/pass/malloc.rs b/tests/pass-dep/malloc.rs similarity index 100% rename from tests/pass/malloc.rs rename to tests/pass-dep/malloc.rs diff --git a/tests/pass/crates/num_cpus.rs b/tests/pass-dep/num_cpus.rs similarity index 100% rename from tests/pass/crates/num_cpus.rs rename to tests/pass-dep/num_cpus.rs diff --git a/tests/pass/crates/page_size.rs b/tests/pass-dep/page_size.rs similarity index 100% rename from tests/pass/crates/page_size.rs rename to tests/pass-dep/page_size.rs diff --git a/tests/pass/crates/random.rs b/tests/pass-dep/random.rs similarity index 100% rename from tests/pass/crates/random.rs rename to tests/pass-dep/random.rs diff --git a/tests/pass/regions-mock-trans.rs b/tests/pass-dep/regions-mock-trans.rs similarity index 100% rename from tests/pass/regions-mock-trans.rs rename to tests/pass-dep/regions-mock-trans.rs diff --git a/tests/pass/shims/fs.rs b/tests/pass-dep/shims/fs.rs similarity index 100% rename from tests/pass/shims/fs.rs rename to tests/pass-dep/shims/fs.rs diff --git a/tests/pass/shims/fs.stderr b/tests/pass-dep/shims/fs.stderr similarity index 100% rename from tests/pass/shims/fs.stderr rename to tests/pass-dep/shims/fs.stderr diff --git a/tests/pass/shims/fs.stdout b/tests/pass-dep/shims/fs.stdout similarity index 100% rename from tests/pass/shims/fs.stdout rename to tests/pass-dep/shims/fs.stdout diff --git a/tests/pass/shims/fs_with_isolation.rs b/tests/pass-dep/shims/fs_with_isolation.rs similarity index 100% rename from tests/pass/shims/fs_with_isolation.rs rename to tests/pass-dep/shims/fs_with_isolation.rs diff --git a/tests/pass/shims/fs_with_isolation.stderr b/tests/pass-dep/shims/fs_with_isolation.stderr similarity index 100% rename from tests/pass/shims/fs_with_isolation.stderr rename to tests/pass-dep/shims/fs_with_isolation.stderr diff --git a/tests/pass/shims/libc-misc.rs b/tests/pass-dep/shims/libc-misc.rs similarity index 100% rename from tests/pass/shims/libc-misc.rs rename to tests/pass-dep/shims/libc-misc.rs diff --git a/tests/pass/shims/linux-getrandom-without-isolation.rs b/tests/pass-dep/shims/linux-getrandom-without-isolation.rs similarity index 100% rename from tests/pass/shims/linux-getrandom-without-isolation.rs rename to tests/pass-dep/shims/linux-getrandom-without-isolation.rs diff --git a/tests/pass/shims/linux-getrandom.rs b/tests/pass-dep/shims/linux-getrandom.rs similarity index 100% rename from tests/pass/shims/linux-getrandom.rs rename to tests/pass-dep/shims/linux-getrandom.rs diff --git a/tests/pass/shims/posix_memalign.rs b/tests/pass-dep/shims/posix_memalign.rs similarity index 100% rename from tests/pass/shims/posix_memalign.rs rename to tests/pass-dep/shims/posix_memalign.rs diff --git a/tests/pass/shims/pthreads.rs b/tests/pass-dep/shims/pthreads.rs similarity index 100% rename from tests/pass/shims/pthreads.rs rename to tests/pass-dep/shims/pthreads.rs From fb071a14bd065da54c5bbc497033503932925cb2 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Thu, 25 Aug 2022 10:10:32 +0000 Subject: [PATCH 3679/3747] Use ui_test from crates.io instead of having it in-tree --- Cargo.lock | 4 +- Cargo.toml | 2 +- miri | 4 +- ui_test/Cargo.lock | 578 -------------------------------- ui_test/Cargo.toml | 21 -- ui_test/README.md | 51 --- ui_test/src/dependencies.rs | 137 -------- ui_test/src/lib.rs | 637 ------------------------------------ ui_test/src/parser.rs | 327 ------------------ ui_test/src/parser/tests.rs | 85 ----- ui_test/src/rustc_stderr.rs | 155 --------- ui_test/src/tests.rs | 294 ----------------- 12 files changed, 5 insertions(+), 2290 deletions(-) delete mode 100644 ui_test/Cargo.lock delete mode 100644 ui_test/Cargo.toml delete mode 100644 ui_test/README.md delete mode 100644 ui_test/src/dependencies.rs delete mode 100644 ui_test/src/lib.rs delete mode 100644 ui_test/src/parser.rs delete mode 100644 ui_test/src/parser/tests.rs delete mode 100644 ui_test/src/rustc_stderr.rs delete mode 100644 ui_test/src/tests.rs diff --git a/Cargo.lock b/Cargo.lock index f660ed77620a1..b0601ba3d4605 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -756,7 +756,9 @@ dependencies = [ [[package]] name = "ui_test" -version = "0.1.0" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43a7bfdb147f57c498ca629c7802b57899de0bb82ae36b6f01f1540da41832f1" dependencies = [ "cargo_metadata", "color-eyre", diff --git a/Cargo.toml b/Cargo.toml index 208b3a764436f..39bc9185db314 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -38,7 +38,7 @@ libc = "0.2" [dev-dependencies] colored = "2" -ui_test = { path = "ui_test" } +ui_test = "0.1" # Features chosen to match those required by env_logger, to avoid rebuilds regex = { version = "1.5.5", default-features = false, features = ["perf", "std"] } lazy_static = "1.4.0" diff --git a/miri b/miri index a72fe91f594b6..84bd74817090a 100755 --- a/miri +++ b/miri @@ -186,9 +186,8 @@ test|bless) export MIRI_BLESS="Gesundheit" fi # Then test, and let caller control flags. - # Only in root project and ui_test as `cargo-miri` has no tests. + # Only in root project as `cargo-miri` has no tests. $CARGO test $CARGO_EXTRA_FLAGS --manifest-path "$MIRIDIR"/Cargo.toml "$@" - $CARGO test $CARGO_EXTRA_FLAGS --manifest-path "$MIRIDIR"/ui_test/Cargo.toml "$@" ;; run) # Scan for "--target" to overwrite the "MIRI_TEST_TARGET" env var so @@ -219,7 +218,6 @@ fmt) ;; clippy) $CARGO clippy $CARGO_EXTRA_FLAGS --manifest-path "$MIRIDIR"/Cargo.toml --all-targets "$@" - $CARGO clippy $CARGO_EXTRA_FLAGS --manifest-path "$MIRIDIR"/ui_test/Cargo.toml --all-targets "$@" $CARGO clippy $CARGO_EXTRA_FLAGS --manifest-path "$MIRIDIR"/cargo-miri/Cargo.toml "$@" ;; cargo) diff --git a/ui_test/Cargo.lock b/ui_test/Cargo.lock deleted file mode 100644 index 9addea9b19d0b..0000000000000 --- a/ui_test/Cargo.lock +++ /dev/null @@ -1,578 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "addr2line" -version = "0.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9ecd88a8c8378ca913a680cd98f0f13ac67383d35993f86c90a70e3f137816b" -dependencies = [ - "gimli", -] - -[[package]] -name = "adler" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" - -[[package]] -name = "aho-corasick" -version = "0.7.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f" -dependencies = [ - "memchr", -] - -[[package]] -name = "ansi_term" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2" -dependencies = [ - "winapi", -] - -[[package]] -name = "atty" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" -dependencies = [ - "hermit-abi", - "libc", - "winapi", -] - -[[package]] -name = "autocfg" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" - -[[package]] -name = "backtrace" -version = "0.3.65" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11a17d453482a265fd5f8479f2a3f405566e6ca627837aaddb85af8b1ab8ef61" -dependencies = [ - "addr2line", - "cc", - "cfg-if", - "libc", - "miniz_oxide", - "object", - "rustc-demangle", -] - -[[package]] -name = "camino" -version = "1.0.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "869119e97797867fd90f5e22af7d0bd274bd4635ebb9eb68c04f3f513ae6c412" -dependencies = [ - "serde", -] - -[[package]] -name = "cargo-platform" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cbdb825da8a5df079a43676dbe042702f1707b1109f713a01420fbb4cc71fa27" -dependencies = [ - "serde", -] - -[[package]] -name = "cargo_metadata" -version = "0.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3abb7553d5b9b8421c6de7cb02606ff15e0c6eea7d8eadd75ef013fd636bec36" -dependencies = [ - "camino", - "cargo-platform", - "semver", - "serde", - "serde_json", -] - -[[package]] -name = "cc" -version = "1.0.73" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11" - -[[package]] -name = "cfg-if" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" - -[[package]] -name = "color-eyre" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ebf286c900a6d5867aeff75cfee3192857bb7f24b547d4f0df2ed6baa812c90" -dependencies = [ - "backtrace", - "color-spantrace", - "eyre", - "indenter", - "once_cell", - "owo-colors", - "tracing-error", -] - -[[package]] -name = "color-spantrace" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ba75b3d9449ecdccb27ecbc479fdc0b87fa2dd43d2f8298f9bf0e59aacc8dce" -dependencies = [ - "once_cell", - "owo-colors", - "tracing-core", - "tracing-error", -] - -[[package]] -name = "colored" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3616f750b84d8f0de8a58bda93e08e2a81ad3f523089b05f1dffecab48c6cbd" -dependencies = [ - "atty", - "lazy_static", - "winapi", -] - -[[package]] -name = "crossbeam" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ae5588f6b3c3cb05239e90bd110f257254aecd01e4635400391aeae07497845" -dependencies = [ - "cfg-if", - "crossbeam-channel", - "crossbeam-deque", - "crossbeam-epoch", - "crossbeam-queue", - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-channel" -version = "0.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5aaa7bd5fb665c6864b5f963dd9097905c54125909c7aa94c9e18507cdbe6c53" -dependencies = [ - "cfg-if", - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-deque" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6455c0ca19f0d2fbf751b908d5c55c1f5cbc65e03c4225427254b46890bdde1e" -dependencies = [ - "cfg-if", - "crossbeam-epoch", - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-epoch" -version = "0.9.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1145cf131a2c6ba0615079ab6a638f7e1973ac9c2634fcbeaaad6114246efe8c" -dependencies = [ - "autocfg", - "cfg-if", - "crossbeam-utils", - "lazy_static", - "memoffset", - "scopeguard", -] - -[[package]] -name = "crossbeam-queue" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f25d8400f4a7a5778f0e4e52384a48cbd9b5c495d110786187fc750075277a2" -dependencies = [ - "cfg-if", - "crossbeam-utils", -] - -[[package]] -name = "crossbeam-utils" -version = "0.8.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bf124c720b7686e3c2663cf54062ab0f68a88af2fb6a030e87e30bf721fcb38" -dependencies = [ - "cfg-if", - "lazy_static", -] - -[[package]] -name = "ctor" -version = "0.1.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f877be4f7c9f246b183111634f75baa039715e3f46ce860677d3b19a69fb229c" -dependencies = [ - "quote", - "syn", -] - -[[package]] -name = "diff" -version = "0.1.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e25ea47919b1560c4e3b7fe0aaab9becf5b84a10325ddf7db0f0ba5e1026499" - -[[package]] -name = "eyre" -version = "0.6.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c2b6b5a29c02cdc822728b7d7b8ae1bab3e3b05d44522770ddd49722eeac7eb" -dependencies = [ - "indenter", - "once_cell", -] - -[[package]] -name = "gimli" -version = "0.26.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78cc372d058dcf6d5ecd98510e7fbc9e5aec4d21de70f65fea8fecebcd881bd4" - -[[package]] -name = "hermit-abi" -version = "0.1.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" -dependencies = [ - "libc", -] - -[[package]] -name = "indenter" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce23b50ad8242c51a442f3ff322d56b02f08852c77e4c0b4d3fd684abc89c683" - -[[package]] -name = "itoa" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "112c678d4050afce233f4f2852bb2eb519230b3cf12f33585275537d7e41578d" - -[[package]] -name = "lazy_static" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" - -[[package]] -name = "libc" -version = "0.2.126" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "349d5a591cd28b49e1d1037471617a32ddcda5731b99419008085f72d5a53836" - -[[package]] -name = "memchr" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" - -[[package]] -name = "memoffset" -version = "0.6.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce" -dependencies = [ - "autocfg", -] - -[[package]] -name = "miniz_oxide" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f5c75688da582b8ffc1f1799e9db273f32133c49e048f614d22ec3256773ccc" -dependencies = [ - "adler", -] - -[[package]] -name = "object" -version = "0.28.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e42c982f2d955fac81dd7e1d0e1426a7d702acd9c98d19ab01083a6a0328c424" -dependencies = [ - "memchr", -] - -[[package]] -name = "once_cell" -version = "1.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18a6dbe30758c9f83eb00cbea4ac95966305f5a7772f3f42ebfc7fc7eddbd8e1" - -[[package]] -name = "output_vt100" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "628223faebab4e3e40667ee0b2336d34a5b960ff60ea743ddfdbcf7770bcfb66" -dependencies = [ - "winapi", -] - -[[package]] -name = "owo-colors" -version = "3.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "decf7381921fea4dcb2549c5667eda59b3ec297ab7e2b5fc33eac69d2e7da87b" - -[[package]] -name = "pin-project-lite" -version = "0.2.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" - -[[package]] -name = "pretty_assertions" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c89f989ac94207d048d92db058e4f6ec7342b0971fc58d1271ca148b799b3563" -dependencies = [ - "ansi_term", - "ctor", - "diff", - "output_vt100", -] - -[[package]] -name = "proc-macro2" -version = "1.0.39" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c54b25569025b7fc9651de43004ae593a75ad88543b17178aa5e1b9c4f15f56f" -dependencies = [ - "unicode-ident", -] - -[[package]] -name = "quote" -version = "1.0.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1feb54ed693b93a84e14094943b84b7c4eae204c512b7ccb95ab0c66d278ad1" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "regex" -version = "1.5.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d83f127d94bdbcda4c8cc2e50f6f84f4b611f69c902699ca385a39c3a75f9ff1" -dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax", -] - -[[package]] -name = "regex-syntax" -version = "0.6.26" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49b3de9ec5dc0a3417da371aab17d729997c15010e7fd24ff707773a33bddb64" - -[[package]] -name = "rustc-demangle" -version = "0.1.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342" - -[[package]] -name = "rustc_version" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" -dependencies = [ - "semver", -] - -[[package]] -name = "ryu" -version = "1.0.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3f6f92acf49d1b98f7a81226834412ada05458b7364277387724a237f062695" - -[[package]] -name = "scopeguard" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" - -[[package]] -name = "semver" -version = "1.0.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8cb243bdfdb5936c8dc3c45762a19d12ab4550cdc753bc247637d4ec35a040fd" -dependencies = [ - "serde", -] - -[[package]] -name = "serde" -version = "1.0.137" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61ea8d54c77f8315140a05f4c7237403bf38b72704d031543aa1d16abbf517d1" -dependencies = [ - "serde_derive", -] - -[[package]] -name = "serde_derive" -version = "1.0.137" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f26faba0c3959972377d3b2d306ee9f71faee9714294e41bb777f83f88578be" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "serde_json" -version = "1.0.81" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b7ce2b32a1aed03c558dc61a5cd328f15aff2dbc17daad8fb8af04d2100e15c" -dependencies = [ - "itoa", - "ryu", - "serde", -] - -[[package]] -name = "sharded-slab" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "900fba806f70c630b0a382d0d825e17a0f19fcd059a2ade1ff237bcddf446b31" -dependencies = [ - "lazy_static", -] - -[[package]] -name = "syn" -version = "1.0.95" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbaf6116ab8924f39d52792136fb74fd60a80194cf1b1c6ffa6453eef1c3f942" -dependencies = [ - "proc-macro2", - "quote", - "unicode-ident", -] - -[[package]] -name = "thread_local" -version = "1.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5516c27b78311c50bf42c071425c560ac799b11c30b31f87e3081965fe5e0180" -dependencies = [ - "once_cell", -] - -[[package]] -name = "tracing" -version = "0.1.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a400e31aa60b9d44a52a8ee0343b5b18566b03a8321e0d321f695cf56e940160" -dependencies = [ - "cfg-if", - "pin-project-lite", - "tracing-core", -] - -[[package]] -name = "tracing-core" -version = "0.1.28" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b7358be39f2f274f322d2aaed611acc57f382e8eb1e5b48cb9ae30933495ce7" -dependencies = [ - "once_cell", - "valuable", -] - -[[package]] -name = "tracing-error" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d686ec1c0f384b1277f097b2f279a2ecc11afe8c133c1aabf036a27cb4cd206e" -dependencies = [ - "tracing", - "tracing-subscriber", -] - -[[package]] -name = "tracing-subscriber" -version = "0.3.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a713421342a5a666b7577783721d3117f1b69a393df803ee17bb73b1e122a59" -dependencies = [ - "sharded-slab", - "thread_local", - "tracing-core", -] - -[[package]] -name = "ui_test" -version = "0.1.0" -dependencies = [ - "cargo_metadata", - "color-eyre", - "colored", - "crossbeam", - "lazy_static", - "pretty_assertions", - "regex", - "rustc_version", - "serde", - "serde_json", -] - -[[package]] -name = "unicode-ident" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d22af068fba1eb5edcb4aea19d382b2a3deb4c8f9d475c589b6ada9e0fd493ee" - -[[package]] -name = "valuable" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" - -[[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/ui_test/Cargo.toml b/ui_test/Cargo.toml deleted file mode 100644 index bb14eb7ecfe30..0000000000000 --- a/ui_test/Cargo.toml +++ /dev/null @@ -1,21 +0,0 @@ -[package] -name = "ui_test" -version = "0.1.0" -edition = "2021" - -[lib] -test = true # we have unit tests -doctest = false # but no doc tests - -[dependencies] -rustc_version = "0.4" -colored = "2" -# Features chosen to match those required by env_logger, to avoid rebuilds -regex = { version = "1.5.5", default-features = false, features = ["perf", "std"] } -pretty_assertions = "1.2.1" -crossbeam = "0.8.1" -lazy_static = "1.4.0" -serde = { version = "1.0", features = ["derive"] } -serde_json = "1.0" -color-eyre = { version = "0.6.1", default-features = false, features = ["capture-spantrace"] } -cargo_metadata = "0.15" diff --git a/ui_test/README.md b/ui_test/README.md deleted file mode 100644 index 3db3361faa532..0000000000000 --- a/ui_test/README.md +++ /dev/null @@ -1,51 +0,0 @@ -A smaller version of compiletest-rs - -## Magic behavior - -* Tests are run in order of their filenames (files first, then recursing into folders). - So if you have any slow tests, prepend them with a small integral number to make them get run first, taking advantage of parallelism as much as possible (instead of waiting for the slow tests at the end). - -## Supported magic comment annotations - -If your test tests for failure, you need to add a `//~` annotation where the error is happening -to make sure that the test will always keep failing with a specific message at the annotated line. - -`//~ ERROR: XXX` make sure the stderr output contains `XXX` for an error in the line where this comment is written - -* Also supports `HELP`, `WARN` or `NOTE` for different kind of message - * if one of those levels is specified explicitly, *all* diagnostics of this level or higher need an annotation. If you want to avoid this, just leave out the all caps level note entirely. -* If the all caps note is left out, a message of any level is matched. Leaving it out is not allowed for `ERROR` levels. -* This checks the output *before* normalization, so you can check things that get normalized away, but need to - be careful not to accidentally have a pattern that differs between platforms. -* if `XXX` is of the form `/XXX/` it is treated as a regex instead of a substring and will succeed if the regex matches. - -In order to change how a single test is tested, you can add various `//@` comments to the test. -Any other comments will be ignored, and all `//@` comments must be formatted precisely as -their command specifies, or the test will fail without even being run. - -* `//@ignore-C` avoids running the test when condition `C` is met. - * `C` can be `target-XXX`, which checks whether the target triple contains `XXX`. - * `C` can also be one of `64bit`, `32bit` or `16bit`. - * `C` can also be `on-host`, which will only run the test during cross compilation testing. -* `//@only-C` **only** runs the test when condition `C` is met. The conditions are the same as with `ignore`. -* `//@stderr-per-bitwidth` produces one stderr file per bitwidth, as they may differ significantly sometimes -* `//@error-pattern: XXX` make sure the stderr output contains `XXX` -* `//@revisions: XXX YYY` runs the test once for each space separated name in the list - * emits one stderr file per revision - * `//~` comments can be restricted to specific revisions by adding the revision name before the `~` in square brackets: `//[XXX]~` -* `//@compile-flags: XXX` appends `XXX` to the command line arguments passed to the rustc driver - * you can specify this multiple times, and all the flags will accumulate -* `//@rustc-env: XXX=YYY` sets the env var `XXX` to `YYY` for the rustc driver execution. - * for Miri these env vars are used during compilation via rustc and during the emulation of the program - * you can specify this multiple times, accumulating all the env vars -* `//@normalize-stderr-test: "REGEX" -> "REPLACEMENT"` replaces all matches of `REGEX` in the stderr with `REPLACEMENT`. The replacement may specify `$1` and similar backreferences to paste captures. - * you can specify multiple such commands, there is no need to create a single regex that handles multiple replacements that you want to perform. -* `//@require-annotations-for-level: LEVEL` can be used to change the level of diagnostics that require a corresponding annotation. - * this is only useful if there are any annotations like `HELP`, `WARN` or `NOTE`, as these would automatically require annotations for all other diagnostics of the same or higher level. - -## Significant differences to compiletest-rs - -* `ignore-target-*` and `only-target-*` opereate solely on the triple, instead of supporting things like `macos` -* only `//~` comments can be individualized per revision -* only supports `ui` tests -* tests are run in named order, so you can prefix slow tests with `0` in order to make them get run first diff --git a/ui_test/src/dependencies.rs b/ui_test/src/dependencies.rs deleted file mode 100644 index 582641b97ae13..0000000000000 --- a/ui_test/src/dependencies.rs +++ /dev/null @@ -1,137 +0,0 @@ -use color_eyre::eyre::{bail, Result}; -use std::{ - collections::{HashMap, HashSet}, - path::{Path, PathBuf}, - process::Command, -}; - -use crate::{Config, OutputConflictHandling}; - -#[derive(Default, Debug)] -pub struct Dependencies { - /// All paths that must be imported with `-L dependency=`. This is for - /// finding proc macros run on the host and dependencies for the target. - pub import_paths: Vec, - /// The name as chosen in the `Cargo.toml` and its corresponding rmeta file. - pub dependencies: Vec<(String, PathBuf)>, -} - -/// Compiles dependencies and returns the crate names and corresponding rmeta files. -pub fn build_dependencies(config: &Config) -> Result { - let manifest_path = match &config.dependencies_crate_manifest_path { - Some(path) => path, - None => return Ok(Default::default()), - }; - let (program, args, envs): (&Path, &[_], &[_]) = match &config.dependency_builder { - Some(db) => (&db.program, &db.args, &db.envs), - None => (Path::new("cargo"), &[], &[]), - }; - let mut build = Command::new(program); - build.args(args); - // HACK: we're using `cargo run` (or `cargo miri run`), because the latter does not - // support `cargo miri build` yet. - build.arg("run"); - - if let Some(target) = &config.target { - build.arg(format!("--target={target}")); - } - - // Reusable closure for setting up the environment both for artifact generation and `cargo_metadata` - let setup_command = |cmd: &mut Command| { - cmd.envs(envs.iter().map(|(k, v)| (k, v))); - cmd.arg("--manifest-path").arg(manifest_path); - if matches!(config.output_conflict_handling, OutputConflictHandling::Error) { - cmd.arg("--locked"); - } - }; - - setup_command(&mut build); - build.arg("--message-format=json"); - - let output = build.output()?; - - if !output.status.success() { - let stdout = String::from_utf8(output.stdout)?; - let stderr = String::from_utf8(output.stderr)?; - bail!("failed to compile dependencies:\nstderr:\n{stderr}\n\nstdout:{stdout}"); - } - - // Collect all artifacts generated - let output = output.stdout; - let output = String::from_utf8(output)?; - let mut import_paths: HashSet = HashSet::new(); - let mut artifacts: HashMap<_, _> = output - .lines() - .filter_map(|line| { - let message = serde_json::from_str::(line).ok()?; - if let cargo_metadata::Message::CompilerArtifact(artifact) = message { - for filename in &artifact.filenames { - import_paths.insert(filename.parent().unwrap().into()); - } - let filename = artifact - .filenames - .into_iter() - .find(|filename| filename.extension() == Some("rmeta"))?; - Some((artifact.package_id, filename.into_std_path_buf())) - } else { - None - } - }) - .collect(); - - // Check which crates are mentioned in the crate itself - let mut metadata = cargo_metadata::MetadataCommand::new().cargo_command(); - setup_command(&mut metadata); - let output = metadata.output()?; - - if !output.status.success() { - let stdout = String::from_utf8(output.stdout)?; - let stderr = String::from_utf8(output.stderr)?; - bail!("failed to run cargo-metadata:\nstderr:\n{stderr}\n\nstdout:{stdout}"); - } - - let output = output.stdout; - let output = String::from_utf8(output)?; - - for line in output.lines() { - if !line.starts_with('{') { - continue; - } - let metadata: cargo_metadata::Metadata = serde_json::from_str(line)?; - // Only take artifacts that are defined in the Cargo.toml - - // First, find the root artifact - let root = metadata - .packages - .iter() - .find(|package| { - package.manifest_path.as_std_path().canonicalize().unwrap() - == manifest_path.canonicalize().unwrap() - }) - .unwrap(); - - // Then go over all of its dependencies - let dependencies = root - .dependencies - .iter() - .map(|package| { - // Get the id for the package matching the version requirement of the dep - let id = &metadata - .packages - .iter() - .find(|&dep| dep.name == package.name && package.req.matches(&dep.version)) - .expect("dependency does not exist") - .id; - // Return the name chosen in `Cargo.toml` and the path to the corresponding artifact - ( - package.rename.clone().unwrap_or_else(|| package.name.clone()), - artifacts.remove(id).expect("package without artifact"), - ) - }) - .collect(); - let import_paths = import_paths.into_iter().collect(); - return Ok(Dependencies { dependencies, import_paths }); - } - - bail!("no json found in cargo-metadata output") -} diff --git a/ui_test/src/lib.rs b/ui_test/src/lib.rs deleted file mode 100644 index c87ac938ffd22..0000000000000 --- a/ui_test/src/lib.rs +++ /dev/null @@ -1,637 +0,0 @@ -#![allow( - clippy::enum_variant_names, - clippy::useless_format, - clippy::too_many_arguments, - rustc::internal -)] - -use std::collections::VecDeque; -use std::ffi::OsString; -use std::fmt::Write; -use std::path::{Path, PathBuf}; -use std::process::{Command, ExitStatus}; -use std::sync::atomic::{AtomicUsize, Ordering}; -use std::sync::Mutex; - -pub use color_eyre; -use color_eyre::eyre::Result; -use colored::*; -use parser::{ErrorMatch, Pattern}; -use regex::Regex; -use rustc_stderr::{Level, Message}; - -use crate::dependencies::build_dependencies; -use crate::parser::{Comments, Condition}; - -mod dependencies; -mod parser; -mod rustc_stderr; -#[cfg(test)] -mod tests; - -#[derive(Debug)] -pub struct Config { - /// Arguments passed to the binary that is executed. - pub args: Vec, - /// `None` to run on the host, otherwise a target triple - pub target: Option, - /// Filters applied to stderr output before processing it - pub stderr_filters: Filter, - /// Filters applied to stdout output before processing it - pub stdout_filters: Filter, - /// The folder in which to start searching for .rs files - pub root_dir: PathBuf, - pub mode: Mode, - pub program: PathBuf, - pub output_conflict_handling: OutputConflictHandling, - /// Only run tests with one of these strings in their path/name - pub path_filter: Vec, - /// Path to a `Cargo.toml` that describes which dependencies the tests can access. - pub dependencies_crate_manifest_path: Option, - /// Can be used to override what command to run instead of `cargo` to build the - /// dependencies in `manifest_path` - pub dependency_builder: Option, - /// Print one character per test instead of one line - pub quiet: bool, -} - -#[derive(Debug)] -pub struct DependencyBuilder { - pub program: PathBuf, - pub args: Vec, - pub envs: Vec<(String, OsString)>, -} - -#[derive(Debug)] -pub enum OutputConflictHandling { - /// The default: emit a diff of the expected/actual output. - Error, - /// Ignore mismatches in the stderr/stdout files. - Ignore, - /// Instead of erroring if the stderr/stdout differs from the expected - /// automatically replace it with the found output (after applying filters). - Bless, -} - -pub type Filter = Vec<(Regex, &'static str)>; - -pub fn run_tests(mut config: Config) -> Result<()> { - eprintln!(" Compiler flags: {:?}", config.args); - - // Get the triple with which to run the tests - let target = config.target.clone().unwrap_or_else(|| config.get_host()); - - eprintln!(" Building test dependencies..."); - let dependencies = build_dependencies(&config)?; - for (name, dependency) in dependencies.dependencies { - config.args.push("--extern".into()); - let mut dep = OsString::from(name); - dep.push("="); - dep.push(dependency); - config.args.push(dep); - } - for import_path in dependencies.import_paths { - config.args.push("-L".into()); - config.args.push(import_path.into()); - } - let config = config; - - // A channel for files to process - let (submit, receive) = crossbeam::channel::unbounded(); - - // Some statistics and failure reports. - let failures = Mutex::new(vec![]); - let succeeded = AtomicUsize::default(); - let ignored = AtomicUsize::default(); - let filtered = AtomicUsize::default(); - - crossbeam::scope(|s| -> Result<()> { - // Create a thread that is in charge of walking the directory and submitting jobs. - // It closes the channel when it is done. - s.spawn(|_| { - let mut todo = VecDeque::new(); - todo.push_back(config.root_dir.clone()); - while let Some(path) = todo.pop_front() { - if path.is_dir() { - // Enqueue everything inside this directory. - // We want it sorted, to have some control over scheduling of slow tests. - let mut entries = - std::fs::read_dir(path).unwrap().collect::, _>>().unwrap(); - entries.sort_by_key(|e| e.file_name()); - for entry in entries { - todo.push_back(entry.path()); - } - } else if path.extension().map(|ext| ext == "rs").unwrap_or(false) { - // Forward .rs files to the test workers. - submit.send(path).unwrap(); - } - } - // There will be no more jobs. This signals the workers to quit. - // (This also ensures `submit` is moved into this closure.) - drop(submit); - }); - - // A channel for the messages emitted by the individual test threads. - let (finished_files_sender, finished_files_recv) = crossbeam::channel::unbounded(); - enum TestResult { - Ok, - Failed, - Ignored, - } - - s.spawn(|_| { - if config.quiet { - for (i, (_, result)) in finished_files_recv.into_iter().enumerate() { - // Humans start counting at 1 - let i = i + 1; - match result { - TestResult::Ok => eprint!("{}", ".".green()), - TestResult::Failed => eprint!("{}", "F".red().bold()), - TestResult::Ignored => eprint!("{}", "i".yellow()), - } - if i % 100 == 0 { - eprintln!(" {i}"); - } - } - } else { - for (msg, result) in finished_files_recv { - eprint!("{msg} ... "); - eprintln!( - "{}", - match result { - TestResult::Ok => "ok".green(), - TestResult::Failed => "FAILED".red().bold(), - TestResult::Ignored => "ignored (in-test comment)".yellow(), - } - ); - } - } - }); - - let mut threads = vec![]; - - // Create N worker threads that receive files to test. - for _ in 0..std::thread::available_parallelism().unwrap().get() { - let finished_files_sender = finished_files_sender.clone(); - threads.push(s.spawn(|_| -> Result<()> { - let finished_files_sender = finished_files_sender; - for path in &receive { - if !config.path_filter.is_empty() { - let path_display = path.display().to_string(); - if !config.path_filter.iter().any(|filter| path_display.contains(filter)) { - filtered.fetch_add(1, Ordering::Relaxed); - continue; - } - } - let comments = Comments::parse_file(&path)?; - // Ignore file if only/ignore rules do (not) apply - if !test_file_conditions(&comments, &target, &config) { - ignored.fetch_add(1, Ordering::Relaxed); - finished_files_sender - .send((path.display().to_string(), TestResult::Ignored))?; - continue; - } - // Run the test for all revisions - for revision in - comments.revisions.clone().unwrap_or_else(|| vec![String::new()]) - { - let (m, errors, stderr) = - run_test(&path, &config, &target, &revision, &comments); - - // Using a single `eprintln!` to prevent messages from threads from getting intermingled. - let mut msg = format!("{}", path.display()); - if !revision.is_empty() { - write!(msg, " (revision `{revision}`) ").unwrap(); - } - if errors.is_empty() { - finished_files_sender.send((msg, TestResult::Ok))?; - succeeded.fetch_add(1, Ordering::Relaxed); - } else { - finished_files_sender.send((msg, TestResult::Failed))?; - failures.lock().unwrap().push(( - path.clone(), - m, - revision, - errors, - stderr, - )); - } - } - } - Ok(()) - })); - } - - for thread in threads { - thread.join().unwrap()?; - } - Ok(()) - }) - .unwrap()?; - - // Print all errors in a single thread to show reliable output - let failures = failures.into_inner().unwrap(); - let succeeded = succeeded.load(Ordering::Relaxed); - let ignored = ignored.load(Ordering::Relaxed); - let filtered = filtered.load(Ordering::Relaxed); - if !failures.is_empty() { - for (path, miri, revision, errors, stderr) in &failures { - eprintln!(); - eprint!("{}", path.display().to_string().underline().bold()); - if !revision.is_empty() { - eprint!(" (revision `{}`)", revision); - } - eprint!(" {}", "FAILED:".red().bold()); - eprintln!(); - eprintln!("command: {:?}", miri); - eprintln!(); - for error in errors { - match error { - Error::ExitStatus(mode, exit_status) => eprintln!("{mode:?} got {exit_status}"), - Error::PatternNotFound { pattern, definition_line } => { - match pattern { - Pattern::SubString(s) => - eprintln!("substring `{s}` {} in stderr output", "not found".red()), - Pattern::Regex(r) => - eprintln!("`/{r}/` does {} stderr output", "not match".red()), - } - eprintln!( - "expected because of pattern here: {}:{definition_line}", - path.display().to_string().bold() - ); - } - Error::NoPatternsFound => { - eprintln!("{}", "no error patterns found in failure test".red()); - } - Error::PatternFoundInPassTest => - eprintln!("{}", "error pattern found in success test".red()), - Error::OutputDiffers { path, actual, expected } => { - eprintln!("actual output differed from expected {}", path.display()); - eprintln!("{}", pretty_assertions::StrComparison::new(expected, actual)); - eprintln!() - } - Error::ErrorsWithoutPattern { path: None, msgs } => { - eprintln!( - "There were {} unmatched diagnostics that occurred outside the testfile and had no pattern", - msgs.len(), - ); - for Message { level, message } in msgs { - eprintln!(" {level:?}: {message}") - } - } - Error::ErrorsWithoutPattern { path: Some((path, line)), msgs } => { - eprintln!( - "There were {} unmatched diagnostics at {}:{line}", - msgs.len(), - path.display() - ); - for Message { level, message } in msgs { - eprintln!(" {level:?}: {message}") - } - } - } - eprintln!(); - } - eprintln!("full stderr:"); - eprintln!("{}", stderr); - eprintln!(); - } - eprintln!("{}", "FAILURES:".red().underline().bold()); - for (path, _miri, _revision, _errors, _stderr) in &failures { - eprintln!(" {}", path.display()); - } - eprintln!(); - eprintln!( - "test result: {}. {} tests failed, {} tests passed, {} ignored, {} filtered out", - "FAIL".red(), - failures.len().to_string().red().bold(), - succeeded.to_string().green(), - ignored.to_string().yellow(), - filtered.to_string().yellow(), - ); - std::process::exit(1); - } - eprintln!(); - eprintln!( - "test result: {}. {} tests passed, {} ignored, {} filtered out", - "ok".green(), - succeeded.to_string().green(), - ignored.to_string().yellow(), - filtered.to_string().yellow(), - ); - eprintln!(); - Ok(()) -} - -#[derive(Debug)] -enum Error { - /// Got an invalid exit status for the given mode. - ExitStatus(Mode, ExitStatus), - PatternNotFound { - pattern: Pattern, - definition_line: usize, - }, - /// A ui test checking for failure does not have any failure patterns - NoPatternsFound, - /// A ui test checking for success has failure patterns - PatternFoundInPassTest, - /// Stderr/Stdout differed from the `.stderr`/`.stdout` file present. - OutputDiffers { - path: PathBuf, - actual: String, - expected: String, - }, - ErrorsWithoutPattern { - msgs: Vec, - path: Option<(PathBuf, usize)>, - }, -} - -type Errors = Vec; - -fn run_test( - path: &Path, - config: &Config, - target: &str, - revision: &str, - comments: &Comments, -) -> (Command, Errors, String) { - // Run miri - let mut miri = Command::new(&config.program); - miri.args(config.args.iter()); - miri.arg(path); - if !revision.is_empty() { - miri.arg(format!("--cfg={revision}")); - } - miri.arg("--error-format=json"); - for arg in &comments.compile_flags { - miri.arg(arg); - } - miri.envs(comments.env_vars.iter().map(|(k, v)| (k, v))); - let output = miri.output().expect("could not execute miri"); - let mut errors = config.mode.ok(output.status); - let stderr = check_test_result( - path, - config, - target, - revision, - comments, - &mut errors, - &output.stdout, - &output.stderr, - ); - (miri, errors, stderr) -} - -fn check_test_result( - path: &Path, - config: &Config, - target: &str, - revision: &str, - comments: &Comments, - errors: &mut Errors, - stdout: &[u8], - stderr: &[u8], -) -> String { - // Always remove annotation comments from stderr. - let diagnostics = rustc_stderr::process(path, stderr); - let stdout = std::str::from_utf8(stdout).unwrap(); - // Check output files (if any) - let revised = |extension: &str| { - if revision.is_empty() { - extension.to_string() - } else { - format!("{}.{}", revision, extension) - } - }; - // Check output files against actual output - check_output( - &diagnostics.rendered, - path, - errors, - revised("stderr"), - target, - &config.stderr_filters, - config, - comments, - ); - check_output( - stdout, - path, - errors, - revised("stdout"), - target, - &config.stdout_filters, - config, - comments, - ); - // Check error annotations in the source against output - check_annotations( - diagnostics.messages, - diagnostics.messages_from_unknown_file_or_line, - path, - errors, - config, - revision, - comments, - ); - diagnostics.rendered -} - -fn check_annotations( - mut messages: Vec>, - mut messages_from_unknown_file_or_line: Vec, - path: &Path, - errors: &mut Errors, - config: &Config, - revision: &str, - comments: &Comments, -) { - if let Some((ref error_pattern, definition_line)) = comments.error_pattern { - // first check the diagnostics messages outside of our file. We check this first, so that - // you can mix in-file annotations with //@error-pattern annotations, even if there is overlap - // in the messages. - if let Some(i) = messages_from_unknown_file_or_line - .iter() - .position(|msg| error_pattern.matches(&msg.message)) - { - messages_from_unknown_file_or_line.remove(i); - } else { - errors.push(Error::PatternNotFound { pattern: error_pattern.clone(), definition_line }); - } - } - - // The order on `Level` is such that `Error` is the highest level. - // We will ensure that *all* diagnostics of level at least `lowest_annotation_level` - // are matched. - let mut lowest_annotation_level = Level::Error; - for &ErrorMatch { ref pattern, revision: ref rev, definition_line, line, level } in - &comments.error_matches - { - if let Some(rev) = rev { - if rev != revision { - continue; - } - } - - // If we found a diagnostic with a level annotation, make sure that all - // diagnostics of that level have annotations, even if we don't end up finding a matching diagnostic - // for this pattern. - lowest_annotation_level = std::cmp::min(lowest_annotation_level, level); - - if let Some(msgs) = messages.get_mut(line) { - let found = - msgs.iter().position(|msg| pattern.matches(&msg.message) && msg.level == level); - if let Some(found) = found { - msgs.remove(found); - continue; - } - } - - errors.push(Error::PatternNotFound { pattern: pattern.clone(), definition_line }); - } - - let filter = |msgs: Vec| -> Vec<_> { - msgs.into_iter() - .filter(|msg| { - msg.level - >= comments.require_annotations_for_level.unwrap_or(lowest_annotation_level) - }) - .collect() - }; - - let messages_from_unknown_file_or_line = filter(messages_from_unknown_file_or_line); - if !messages_from_unknown_file_or_line.is_empty() { - errors.push(Error::ErrorsWithoutPattern { - path: None, - msgs: messages_from_unknown_file_or_line, - }); - } - - for (line, msgs) in messages.into_iter().enumerate() { - let msgs = filter(msgs); - if !msgs.is_empty() { - errors - .push(Error::ErrorsWithoutPattern { path: Some((path.to_path_buf(), line)), msgs }); - } - } - - match (config.mode, comments.error_pattern.is_some() || !comments.error_matches.is_empty()) { - (Mode::Pass, true) | (Mode::Panic, true) => errors.push(Error::PatternFoundInPassTest), - (Mode::Fail, false) => errors.push(Error::NoPatternsFound), - _ => {} - } -} - -fn check_output( - output: &str, - path: &Path, - errors: &mut Errors, - kind: String, - target: &str, - filters: &Filter, - config: &Config, - comments: &Comments, -) { - let output = normalize(path, output, filters, comments); - let path = output_path(path, comments, kind, target); - match config.output_conflict_handling { - OutputConflictHandling::Bless => - if output.is_empty() { - let _ = std::fs::remove_file(path); - } else { - std::fs::write(path, &output).unwrap(); - }, - OutputConflictHandling::Error => { - let expected_output = std::fs::read_to_string(&path).unwrap_or_default(); - if output != expected_output { - errors.push(Error::OutputDiffers { - path, - actual: output, - expected: expected_output, - }); - } - } - OutputConflictHandling::Ignore => {} - } -} - -fn output_path(path: &Path, comments: &Comments, kind: String, target: &str) -> PathBuf { - if comments.stderr_per_bitwidth { - return path.with_extension(format!("{}bit.{kind}", get_pointer_width(target))); - } - path.with_extension(kind) -} - -fn test_condition(condition: &Condition, target: &str, config: &Config) -> bool { - match condition { - Condition::Bitwidth(bits) => get_pointer_width(target) == *bits, - Condition::Target(t) => target.contains(t), - Condition::OnHost => config.target.is_none(), - } -} - -/// Returns whether according to the in-file conditions, this file should be run. -fn test_file_conditions(comments: &Comments, target: &str, config: &Config) -> bool { - if comments.ignore.iter().any(|c| test_condition(c, target, config)) { - return false; - } - comments.only.iter().all(|c| test_condition(c, target, config)) -} - -// Taken 1:1 from compiletest-rs -fn get_pointer_width(triple: &str) -> u8 { - if (triple.contains("64") && !triple.ends_with("gnux32") && !triple.ends_with("gnu_ilp32")) - || triple.starts_with("s390x") - { - 64 - } else if triple.starts_with("avr") { - 16 - } else { - 32 - } -} - -fn normalize(path: &Path, text: &str, filters: &Filter, comments: &Comments) -> String { - // Useless paths - let mut text = text.replace(&path.parent().unwrap().display().to_string(), "$DIR"); - if let Some(lib_path) = option_env!("RUSTC_LIB_PATH") { - text = text.replace(lib_path, "RUSTLIB"); - } - - for (regex, replacement) in filters.iter() { - text = regex.replace_all(&text, *replacement).to_string(); - } - - for (from, to) in &comments.normalize_stderr { - text = from.replace_all(&text, to).to_string(); - } - text -} - -impl Config { - fn get_host(&self) -> String { - rustc_version::VersionMeta::for_command(std::process::Command::new(&self.program)) - .expect("failed to parse rustc version info") - .host - } -} - -#[derive(Copy, Clone, Debug)] -pub enum Mode { - // The test passes a full execution of the rustc driver - Pass, - // The rustc driver panicked - Panic, - // The rustc driver emitted an error - Fail, -} - -impl Mode { - fn ok(self, status: ExitStatus) -> Errors { - match (status.code(), self) { - (Some(1), Mode::Fail) | (Some(101), Mode::Panic) | (Some(0), Mode::Pass) => vec![], - _ => vec![Error::ExitStatus(self, status)], - } - } -} diff --git a/ui_test/src/parser.rs b/ui_test/src/parser.rs deleted file mode 100644 index d583e625facee..0000000000000 --- a/ui_test/src/parser.rs +++ /dev/null @@ -1,327 +0,0 @@ -use std::path::Path; - -use regex::Regex; - -use crate::rustc_stderr::Level; - -use color_eyre::eyre::{bail, ensure, eyre, Result}; - -#[cfg(test)] -mod tests; - -/// This crate supports various magic comments that get parsed as file-specific -/// configuration values. This struct parses them all in one go and then they -/// get processed by their respective use sites. -#[derive(Default, Debug)] -pub(crate) struct Comments { - /// List of revision names to execute. Can only be speicified once - pub revisions: Option>, - /// Don't run this test if any of these filters apply - pub ignore: Vec, - /// Only run this test if all of these filters apply - pub only: Vec, - /// Generate one .stderr file per bit width, by prepending with `.64bit` and similar - pub stderr_per_bitwidth: bool, - /// Additional flags to pass to the executable - pub compile_flags: Vec, - /// Additional env vars to set for the executable - pub env_vars: Vec<(String, String)>, - /// Normalizations to apply to the stderr output before emitting it to disk - pub normalize_stderr: Vec<(Regex, String)>, - /// An arbitrary pattern to look for in the stderr. - pub error_pattern: Option<(Pattern, usize)>, - pub error_matches: Vec, - /// Ignore diagnostics below this level. - /// `None` means pick the lowest level from the `error_pattern`s. - pub require_annotations_for_level: Option, -} - -/// The conditions used for "ignore" and "only" filters. -#[derive(Debug)] -pub(crate) enum Condition { - /// The given string must appear in the target. - Target(String), - /// Tests that the bitwidth is the given one. - Bitwidth(u8), - /// Tests that the target is the host. - OnHost, -} - -#[derive(Debug, Clone)] -pub(crate) enum Pattern { - SubString(String), - Regex(Regex), -} - -#[derive(Debug)] -pub(crate) struct ErrorMatch { - pub pattern: Pattern, - pub revision: Option, - pub level: Level, - /// The line where the message was defined, for reporting issues with it (e.g. in case it wasn't found). - pub definition_line: usize, - /// The line this pattern is expecting to find a message in. - pub line: usize, -} - -impl Condition { - fn parse(c: &str) -> Result { - if c == "on-host" { - Ok(Condition::OnHost) - } else if let Some(bits) = c.strip_suffix("bit") { - let bits: u8 = bits.parse().map_err(|_err| { - eyre!("invalid ignore/only filter ending in 'bit': {c:?} is not a valid bitwdith") - })?; - Ok(Condition::Bitwidth(bits)) - } else if let Some(target) = c.strip_prefix("target-") { - Ok(Condition::Target(target.to_owned())) - } else { - Err(eyre!("invalid ignore/only condition {c:?}")) - } - } -} - -impl Comments { - pub(crate) fn parse_file(path: &Path) -> Result { - let content = std::fs::read_to_string(path)?; - Self::parse(path, &content) - } - - /// Parse comments in `content`. - /// `path` is only used to emit diagnostics if parsing fails. - pub(crate) fn parse(path: &Path, content: &str) -> Result { - let mut this = Self::default(); - - let mut fallthrough_to = None; // The line that a `|` will refer to. - for (l, line) in content.lines().enumerate() { - let l = l + 1; // enumerate starts at 0, but line numbers start at 1 - this.parse_checked_line(l, &mut fallthrough_to, line).map_err(|err| { - err.wrap_err(format!("{}:{l}: failed to parse annotation", path.display())) - })?; - } - Ok(this) - } - - fn parse_checked_line( - &mut self, - l: usize, - fallthrough_to: &mut Option, - line: &str, - ) -> Result<()> { - if let Some((_, command)) = line.split_once("//@") { - self.parse_command(command.trim(), l) - } else if let Some((_, pattern)) = line.split_once("//~") { - self.parse_pattern(pattern, fallthrough_to, l) - } else if let Some((_, pattern)) = line.split_once("//[") { - self.parse_revisioned_pattern(pattern, fallthrough_to, l) - } else { - *fallthrough_to = None; - Ok(()) - } - } - - fn parse_command(&mut self, command: &str, l: usize) -> Result<()> { - // Commands are letters or dashes, grab everything until the first character that is neither of those. - let (command, args) = - match command.chars().position(|c: char| !c.is_alphanumeric() && c != '-') { - None => (command, ""), - Some(i) => { - let (command, args) = command.split_at(i); - let mut args = args.chars(); - // Commands are separated from their arguments by ':' or ' ' - let next = args - .next() - .expect("the `position` above guarantees that there is at least one char"); - ensure!(next == ':', "test command must be followed by : (or end the line)"); - (command, args.as_str().trim()) - } - }; - - match command { - "revisions" => { - ensure!(self.revisions.is_none(), "cannot specifiy revisions twice"); - self.revisions = Some(args.split_whitespace().map(|s| s.to_string()).collect()); - } - "compile-flags" => { - self.compile_flags.extend(args.split_whitespace().map(|s| s.to_string())); - } - "rustc-env" => - for env in args.split_whitespace() { - let (k, v) = env.split_once('=').ok_or_else(|| { - eyre!("environment variables must be key/value pairs separated by a `=`") - })?; - self.env_vars.push((k.to_string(), v.to_string())); - }, - "normalize-stderr-test" => { - /// Parses a string literal. `s` has to start with `"`; everything until the next `"` is - /// returned in the first component. `\` can be used to escape arbitrary character. - /// Second return component is the rest of the string with leading whitespace removed. - fn parse_str(s: &str) -> Result<(&str, &str)> { - let mut chars = s.char_indices(); - match chars.next().ok_or_else(|| eyre!("missing arguments"))?.1 { - '"' => { - let s = chars.as_str(); - let mut escaped = false; - for (i, c) in chars { - if escaped { - // Accept any character as literal after a `\`. - escaped = false; - } else if c == '"' { - return Ok((&s[..(i - 1)], s[i..].trim_start())); - } else { - escaped = c == '\\'; - } - } - bail!("no closing quotes found for {s}") - } - c => bail!("expected '\"', got {c}"), - } - } - - let (from, rest) = parse_str(args)?; - - let to = rest.strip_prefix("->").ok_or_else(|| { - eyre!("normalize-stderr-test needs a pattern and replacement separated by `->`") - })?.trim_start(); - let (to, rest) = parse_str(to)?; - - ensure!(rest.is_empty(), "trailing text after pattern replacement: {rest}"); - - let from = Regex::new(from)?; - self.normalize_stderr.push((from, to.to_string())); - } - "error-pattern" => { - ensure!( - self.error_pattern.is_none(), - "cannot specifiy error_pattern twice, previous: {:?}", - self.error_pattern - ); - self.error_pattern = Some((Pattern::parse(args.trim())?, l)); - } - "stderr-per-bitwidth" => { - // args are ignored (can be used as comment) - ensure!(!self.stderr_per_bitwidth, "cannot specifiy stderr-per-bitwidth twice"); - self.stderr_per_bitwidth = true; - } - "require-annotations-for-level" => { - ensure!( - self.require_annotations_for_level.is_none(), - "cannot specify `require-annotations-for-level` twice" - ); - self.require_annotations_for_level = Some(args.trim().parse()?); - } - command => { - if let Some(s) = command.strip_prefix("ignore-") { - // args are ignored (can be sue as comment) - self.ignore.push(Condition::parse(s)?); - return Ok(()); - } - - if let Some(s) = command.strip_prefix("only-") { - // args are ignored (can be sue as comment) - self.only.push(Condition::parse(s)?); - return Ok(()); - } - bail!("unknown command {command}"); - } - } - - Ok(()) - } - - fn parse_pattern( - &mut self, - pattern: &str, - fallthrough_to: &mut Option, - l: usize, - ) -> Result<()> { - self.parse_pattern_inner(pattern, fallthrough_to, None, l) - } - - fn parse_revisioned_pattern( - &mut self, - pattern: &str, - fallthrough_to: &mut Option, - l: usize, - ) -> Result<()> { - let (revision, pattern) = - pattern.split_once(']').ok_or_else(|| eyre!("`//[` without corresponding `]`"))?; - if let Some(pattern) = pattern.strip_prefix('~') { - self.parse_pattern_inner(pattern, fallthrough_to, Some(revision.to_owned()), l) - } else { - bail!("revisioned pattern must have `~` following the `]`"); - } - } - - // parse something like (?P\||[\^]+)? *(?PERROR|HELP|WARN|NOTE): (?P.*) - fn parse_pattern_inner( - &mut self, - pattern: &str, - fallthrough_to: &mut Option, - revision: Option, - l: usize, - ) -> Result<()> { - let (match_line, pattern) = - match pattern.chars().next().ok_or_else(|| eyre!("no pattern specified"))? { - '|' => - ( - *fallthrough_to - .as_mut() - .ok_or_else(|| eyre!("`//~|` pattern without preceding line"))?, - &pattern[1..], - ), - '^' => { - let offset = pattern.chars().take_while(|&c| c == '^').count(); - (l - offset, &pattern[offset..]) - } - _ => (l, pattern), - }; - - let pattern = pattern.trim_start(); - let offset = pattern - .chars() - .position(|c| !matches!(c, 'A'..='Z' | 'a'..='z')) - .ok_or_else(|| eyre!("pattern without level"))?; - - let level = pattern[..offset].parse()?; - let pattern = &pattern[offset..]; - let pattern = pattern.strip_prefix(':').ok_or_else(|| eyre!("no `:` after level found"))?; - - let pattern = pattern.trim(); - - ensure!(!pattern.is_empty(), "no pattern specified"); - - let pattern = Pattern::parse(pattern)?; - - *fallthrough_to = Some(match_line); - - self.error_matches.push(ErrorMatch { - pattern, - revision, - level, - definition_line: l, - line: match_line, - }); - - Ok(()) - } -} - -impl Pattern { - pub(crate) fn matches(&self, message: &str) -> bool { - match self { - Pattern::SubString(s) => message.contains(s), - Pattern::Regex(r) => r.is_match(message), - } - } - - pub(crate) fn parse(pattern: &str) -> Result { - if let Some(pattern) = pattern.strip_prefix('/') { - let regex = - pattern.strip_suffix('/').ok_or_else(|| eyre!("regex must end with `/`"))?; - Ok(Pattern::Regex(Regex::new(regex)?)) - } else { - Ok(Pattern::SubString(pattern.to_string())) - } - } -} diff --git a/ui_test/src/parser/tests.rs b/ui_test/src/parser/tests.rs deleted file mode 100644 index 343857d44bd35..0000000000000 --- a/ui_test/src/parser/tests.rs +++ /dev/null @@ -1,85 +0,0 @@ -use std::path::Path; - -use crate::parser::Pattern; - -use super::Comments; - -#[test] -fn parse_simple_comment() { - let s = r" -use std::mem; - -fn main() { - let _x: &i32 = unsafe { mem::transmute(16usize) }; //~ ERROR: encountered a dangling reference (address $HEX is unallocated) -} - "; - let comments = Comments::parse(Path::new(""), s).unwrap(); - println!("parsed comments: {:#?}", comments); - assert_eq!(comments.error_matches[0].definition_line, 5); - assert_eq!(comments.error_matches[0].revision, None); - match &comments.error_matches[0].pattern { - Pattern::SubString(s) => - assert_eq!(s, "encountered a dangling reference (address $HEX is unallocated)"), - other => panic!("expected substring, got {other:?}"), - } -} - -#[test] -fn parse_missing_level() { - let s = r" -use std::mem; - -fn main() { - let _x: &i32 = unsafe { mem::transmute(16usize) }; //~ encountered a dangling reference (address $HEX is unallocated) -} - "; - assert!(Comments::parse(Path::new(""), s).is_err(), "expected parsing to fail"); -} - -#[test] -fn parse_slash_slash_at() { - let s = r" -//@ error-pattern: foomp -use std::mem; - - "; - let comments = Comments::parse(Path::new(""), s).unwrap(); - println!("parsed comments: {:#?}", comments); - let pat = comments.error_pattern.unwrap(); - assert_eq!(format!("{:?}", pat.0), r#"SubString("foomp")"#); - assert_eq!(pat.1, 2); -} - -#[test] -fn parse_regex_error_pattern() { - let s = r" -//@ error-pattern: /foomp/ -use std::mem; - - "; - let comments = Comments::parse(Path::new(""), s).unwrap(); - println!("parsed comments: {:#?}", comments); - let pat = comments.error_pattern.unwrap(); - assert_eq!(format!("{:?}", pat.0), r#"Regex(foomp)"#); - assert_eq!(pat.1, 2); -} - -#[test] -fn parse_slash_slash_at_fail() { - let s = r" -//@ error-patttern foomp -use std::mem; - - "; - assert!(Comments::parse(Path::new(""), s).is_err(), "expected parsing to fail"); -} - -#[test] -fn missing_colon_fail() { - let s = r" -//@stderr-per-bitwidth hello -use std::mem; - - "; - assert!(Comments::parse(Path::new(""), s).is_err(), "expected parsing to fail"); -} diff --git a/ui_test/src/rustc_stderr.rs b/ui_test/src/rustc_stderr.rs deleted file mode 100644 index 8e031947581b3..0000000000000 --- a/ui_test/src/rustc_stderr.rs +++ /dev/null @@ -1,155 +0,0 @@ -use std::{ - fmt::Write, - path::{Path, PathBuf}, -}; - -use color_eyre::eyre::{eyre, Error}; -use regex::Regex; - -#[derive(serde::Deserialize, Debug)] -struct RustcMessage { - rendered: Option, - spans: Vec, - level: String, - message: String, - children: Vec, -} - -#[derive(Copy, Clone, Debug, PartialOrd, Ord, PartialEq, Eq)] -pub(crate) enum Level { - Ice = 5, - Error = 4, - Warn = 3, - Help = 2, - Note = 1, - /// Only used for "For more information about this error, try `rustc --explain EXXXX`". - FailureNote = 0, -} - -#[derive(Debug)] -pub(crate) struct Message { - pub(crate) level: Level, - pub(crate) message: String, -} - -/// Information about macro expansion. -#[derive(serde::Deserialize, Debug)] -struct Expansion { - span: Span, -} - -#[derive(serde::Deserialize, Debug)] -struct Span { - line_start: usize, - file_name: PathBuf, - expansion: Option>, -} - -impl std::str::FromStr for Level { - type Err = Error; - fn from_str(s: &str) -> Result { - match s { - "ERROR" | "error" => Ok(Self::Error), - "WARN" | "warning" => Ok(Self::Warn), - "HELP" | "help" => Ok(Self::Help), - "NOTE" | "note" => Ok(Self::Note), - "failure-note" => Ok(Self::FailureNote), - "error: internal compiler error" => Ok(Self::Ice), - _ => Err(eyre!("unknown level `{s}`")), - } - } -} - -#[derive(Debug)] -pub(crate) struct Diagnostics { - /// Rendered and concatenated version of all diagnostics. - /// This is equivalent to non-json diagnostics. - pub rendered: String, - /// Per line, a list of messages for that line. - pub messages: Vec>, - /// Messages not on any line (usually because they are from libstd) - pub messages_from_unknown_file_or_line: Vec, -} - -impl RustcMessage { - fn line(&self, file: &Path) -> Option { - self.spans.iter().find_map(|span| span.line(file)) - } - - /// Put the message and its children into the line-indexed list. - fn insert_recursive( - self, - file: &Path, - messages: &mut Vec>, - messages_from_unknown_file_or_line: &mut Vec, - line: Option, - ) { - let line = self.line(file).or(line); - let msg = Message { level: self.level.parse().unwrap(), message: self.message }; - if let Some(line) = line { - if messages.len() <= line { - messages.resize_with(line + 1, Vec::new); - } - messages[line].push(msg); - // All other messages go into the general bin, unless they are specifically of the - // "aborting due to X previous errors" variety, as we never want to match those. They - // only count the number of errors and provide no useful information about the tests. - } else if !(msg.message.starts_with("aborting due to") - && msg.message.contains("previous error")) - { - messages_from_unknown_file_or_line.push(msg); - } - for child in self.children { - child.insert_recursive(file, messages, messages_from_unknown_file_or_line, line) - } - } -} - -impl Span { - /// Returns a line number *in the given file*, if possible. - fn line(&self, file: &Path) -> Option { - if self.file_name == file { - Some(self.line_start) - } else { - self.expansion.as_ref()?.span.line(file) - } - } -} - -pub(crate) fn filter_annotations_from_rendered(rendered: &str) -> std::borrow::Cow<'_, str> { - let annotations = Regex::new(r" *//(\[[a-z,]+\])?~.*").unwrap(); - annotations.replace_all(rendered, "") -} - -pub(crate) fn process(file: &Path, stderr: &[u8]) -> Diagnostics { - let stderr = std::str::from_utf8(stderr).unwrap(); - let mut rendered = String::new(); - let mut messages = vec![]; - let mut messages_from_unknown_file_or_line = vec![]; - for line in stderr.lines() { - if line.starts_with('{') { - match serde_json::from_str::(line) { - Ok(msg) => { - write!( - rendered, - "{}", - filter_annotations_from_rendered(msg.rendered.as_ref().unwrap()) - ) - .unwrap(); - msg.insert_recursive( - file, - &mut messages, - &mut messages_from_unknown_file_or_line, - None, - ); - } - Err(err) => - panic!("failed to parse rustc JSON output at line: {}\nerr:{}", line, err), - } - } else { - // FIXME: do we want to throw interpreter stderr into a separate file? - writeln!(rendered, "{}", line).unwrap(); - } - } - Diagnostics { rendered, messages, messages_from_unknown_file_or_line } -} diff --git a/ui_test/src/tests.rs b/ui_test/src/tests.rs deleted file mode 100644 index 2032988ed384d..0000000000000 --- a/ui_test/src/tests.rs +++ /dev/null @@ -1,294 +0,0 @@ -use std::path::{Path, PathBuf}; - -use crate::rustc_stderr::Level; -use crate::rustc_stderr::Message; - -use super::*; - -fn config() -> Config { - Config { - args: vec![], - target: None, - stderr_filters: vec![], - stdout_filters: vec![], - root_dir: PathBuf::from("$RUSTROOT"), - mode: Mode::Fail, - path_filter: vec![], - program: PathBuf::from("cake"), - output_conflict_handling: OutputConflictHandling::Error, - dependencies_crate_manifest_path: None, - dependency_builder: None, - quiet: false, - } -} - -#[test] -fn issue_2156() { - let s = r" -use std::mem; - -fn main() { - let _x: &i32 = unsafe { mem::transmute(16usize) }; //~ ERROR: encountered a dangling reference (address $HEX is unallocated) -} - "; - let path = Path::new("$DIR/"); - let comments = Comments::parse(path, s).unwrap(); - let mut errors = vec![]; - let config = config(); - let messages = vec![ - vec![], vec![], vec![], vec![], vec![], - vec![ - Message { - message:"Undefined Behavior: type validation failed: encountered a dangling reference (address 0x10 is unallocated)".to_string(), - level: Level::Error, - } - ] - ]; - check_annotations(messages, vec![], Path::new("moobar"), &mut errors, &config, "", &comments); - match &errors[..] { - [ - Error::PatternNotFound { definition_line: 5, .. }, - Error::ErrorsWithoutPattern { path: Some((_, 5)), .. }, - ] => {} - _ => panic!("{:#?}", errors), - } -} - -#[test] -fn find_pattern() { - let s = r" -use std::mem; - -fn main() { - let _x: &i32 = unsafe { mem::transmute(16usize) }; //~ ERROR: encountered a dangling reference (address 0x10 is unallocated) -} - "; - let comments = Comments::parse(Path::new(""), s).unwrap(); - let config = config(); - { - let messages = vec![vec![], vec![], vec![], vec![], vec![], vec![ - Message { - message: "Undefined Behavior: type validation failed: encountered a dangling reference (address 0x10 is unallocated)".to_string(), - level: Level::Error, - } - ] - ]; - let mut errors = vec![]; - check_annotations( - messages, - vec![], - Path::new("moobar"), - &mut errors, - &config, - "", - &comments, - ); - match &errors[..] { - [] => {} - _ => panic!("{:#?}", errors), - } - } - - // only difference to above is a wrong line number - { - let messages = vec![vec![], vec![], vec![], vec![], vec![ - Message { - message: "Undefined Behavior: type validation failed: encountered a dangling reference (address 0x10 is unallocated)".to_string(), - level: Level::Error, - } - ] - ]; - let mut errors = vec![]; - check_annotations( - messages, - vec![], - Path::new("moobar"), - &mut errors, - &config, - "", - &comments, - ); - match &errors[..] { - [ - Error::PatternNotFound { definition_line: 5, .. }, - Error::ErrorsWithoutPattern { path: Some((_, 4)), .. }, - ] => {} - _ => panic!("not the expected error: {:#?}", errors), - } - } - - // only difference to first is a wrong level - { - let messages = vec![ - vec![], vec![], vec![], vec![], vec![], - vec![ - Message { - message: "Undefined Behavior: type validation failed: encountered a dangling reference (address 0x10 is unallocated)".to_string(), - level: Level::Note, - } - ] - ]; - let mut errors = vec![]; - check_annotations( - messages, - vec![], - Path::new("moobar"), - &mut errors, - &config, - "", - &comments, - ); - match &errors[..] { - // Note no `ErrorsWithoutPattern`, because there are no `//~NOTE` in the test file, so we ignore them - [Error::PatternNotFound { definition_line: 5, .. }] => {} - _ => panic!("not the expected error: {:#?}", errors), - } - } -} - -#[test] -fn duplicate_pattern() { - let s = r" -use std::mem; - -fn main() { - let _x: &i32 = unsafe { mem::transmute(16usize) }; //~ ERROR: encountered a dangling reference (address 0x10 is unallocated) - //~^ ERROR: encountered a dangling reference (address 0x10 is unallocated) -} - "; - let comments = Comments::parse(Path::new(""), s).unwrap(); - let config = config(); - let messages = vec![ - vec![], vec![], vec![], vec![], vec![], - vec![ - Message { - message: "Undefined Behavior: type validation failed: encountered a dangling reference (address 0x10 is unallocated)".to_string(), - level: Level::Error, - } - ] - ]; - let mut errors = vec![]; - check_annotations(messages, vec![], Path::new("moobar"), &mut errors, &config, "", &comments); - match &errors[..] { - [Error::PatternNotFound { definition_line: 6, .. }] => {} - _ => panic!("{:#?}", errors), - } -} - -#[test] -fn missing_pattern() { - let s = r" -use std::mem; - -fn main() { - let _x: &i32 = unsafe { mem::transmute(16usize) }; //~ ERROR: encountered a dangling reference (address 0x10 is unallocated) -} - "; - let comments = Comments::parse(Path::new(""), s).unwrap(); - let config = config(); - let messages = vec![ - vec![], vec![], vec![], vec![], vec![], - vec![ - Message { - message: "Undefined Behavior: type validation failed: encountered a dangling reference (address 0x10 is unallocated)".to_string(), - level: Level::Error, - }, - Message { - message: "Undefined Behavior: type validation failed: encountered a dangling reference (address 0x10 is unallocated)".to_string(), - level: Level::Error, - } - ] - ]; - let mut errors = vec![]; - check_annotations(messages, vec![], Path::new("moobar"), &mut errors, &config, "", &comments); - match &errors[..] { - [Error::ErrorsWithoutPattern { path: Some((_, 5)), .. }] => {} - _ => panic!("{:#?}", errors), - } -} - -#[test] -fn missing_warn_pattern() { - let s = r" -use std::mem; - -fn main() { - let _x: &i32 = unsafe { mem::transmute(16usize) }; //~ ERROR: encountered a dangling reference (address 0x10 is unallocated) - //~^ WARN: cake -} - "; - let comments = Comments::parse(Path::new(""), s).unwrap(); - let config = config(); - let messages= vec![ - vec![], - vec![], - vec![], - vec![], - vec![], - vec![ - Message { - message: "Undefined Behavior: type validation failed: encountered a dangling reference (address 0x10 is unallocated)".to_string(), - level: Level::Error, - }, - Message { - message: "kaboom".to_string(), - level: Level::Warn, - }, - Message { - message: "cake".to_string(), - level: Level::Warn, - }, - ], - ]; - let mut errors = vec![]; - check_annotations(messages, vec![], Path::new("moobar"), &mut errors, &config, "", &comments); - match &errors[..] { - [Error::ErrorsWithoutPattern { path: Some((_, 5)), msgs, .. }] => - match &msgs[..] { - [Message { message, level: Level::Warn }] if message == "kaboom" => {} - _ => panic!("{:#?}", msgs), - }, - _ => panic!("{:#?}", errors), - } -} - -#[test] -fn missing_implicit_warn_pattern() { - let s = r" -use std::mem; -//@require-annotations-for-level: ERROR -fn main() { - let _x: &i32 = unsafe { mem::transmute(16usize) }; //~ ERROR: encountered a dangling reference (address 0x10 is unallocated) - //~^ WARN: cake -} - "; - let comments = Comments::parse(Path::new(""), s).unwrap(); - let config = config(); - let messages = vec![ - vec![], - vec![], - vec![], - vec![], - vec![], - vec![ - Message { - message: "Undefined Behavior: type validation failed: encountered a dangling reference (address 0x10 is unallocated)".to_string(), - level: Level::Error, - }, - Message { - message: "kaboom".to_string(), - level: Level::Warn, - }, - Message { - message: "cake".to_string(), - level: Level::Warn, - }, - ], - ]; - let mut errors = vec![]; - check_annotations(messages, vec![], Path::new("moobar"), &mut errors, &config, "", &comments); - match &errors[..] { - [] => {} - _ => panic!("{:#?}", errors), - } -} From 88a78826154870f9778af49d48974fd180e31df8 Mon Sep 17 00:00:00 2001 From: Ellen Arteca Date: Fri, 26 Aug 2022 00:47:23 +0000 Subject: [PATCH 3680/3747] C FFI support for functions with int args and returns --- .gitignore | 8 + Cargo.lock | 38 +++ Cargo.toml | 2 + README.md | 11 + build.rs | 6 + miri | 1 + src/bin/miri.rs | 13 + src/eval.rs | 5 + src/machine.rs | 22 ++ src/shims/ffi_support.rs | 291 ++++++++++++++++++ src/shims/foreign_items.rs | 17 +- src/shims/mod.rs | 1 + tests/compiletest.rs | 45 ++- tests/extern-so/fail/function_not_in_so.rs | 12 + .../extern-so/fail/function_not_in_so.stderr | 14 + tests/extern-so/libcode.version | 9 + tests/extern-so/pass/call_extern_c_fcts.rs | 46 +++ .../extern-so/pass/call_extern_c_fcts.stdout | 1 + tests/extern-so/test.c | 27 ++ 19 files changed, 565 insertions(+), 4 deletions(-) create mode 100644 build.rs create mode 100644 src/shims/ffi_support.rs create mode 100644 tests/extern-so/fail/function_not_in_so.rs create mode 100644 tests/extern-so/fail/function_not_in_so.stderr create mode 100644 tests/extern-so/libcode.version create mode 100644 tests/extern-so/pass/call_extern_c_fcts.rs create mode 100644 tests/extern-so/pass/call_extern_c_fcts.stdout create mode 100644 tests/extern-so/test.c diff --git a/.gitignore b/.gitignore index 185ff4f756c1f..c1d3d33576fbb 100644 --- a/.gitignore +++ b/.gitignore @@ -2,10 +2,18 @@ target /doc tex/*/out *.dot +*.out *.rs.bk .vscode *.mm_profdata perf.data perf.data.old flamegraph.svg +<<<<<<< HEAD +======= +<<<<<<< HEAD +tests/extern-so/libtestlib.so +======= +>>>>>>> master +>>>>>>> 58ba05a0 (C FFI support for functions with int args and returns) .auto-* diff --git a/Cargo.lock b/Cargo.lock index b0601ba3d4605..084b7b27a2fbb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,12 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "abort_on_panic" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "955f37ac58af2416bac687c8ab66a4ccba282229bd7422a28d2281a5e66a6116" + [[package]] name = "addr2line" version = "0.17.0" @@ -327,6 +333,36 @@ version = "0.2.112" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b03d17f364a3a042d5e5d46b053bbbf82c92c9430c592dd4c064dc6ee997125" +[[package]] +name = "libffi" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e08093a2ddeee94bd0c830a53d895ff91f1f3bb0f9b3c8c6b00739cdf76bc1d" +dependencies = [ + "abort_on_panic", + "libc", + "libffi-sys", +] + +[[package]] +name = "libffi-sys" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab4106b7f09d7b87d021334d5618fac1dfcfb824d4c5fe111ff0074dfd242e15" +dependencies = [ + "cc", +] + +[[package]] +name = "libloading" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "efbc0f03f9a775e9f6aed295c6a1ba2253c5757a9e03d55c6caa46a681abcddd" +dependencies = [ + "cfg-if", + "winapi", +] + [[package]] name = "lock_api" version = "0.4.5" @@ -401,6 +437,8 @@ dependencies = [ "getrandom", "lazy_static", "libc", + "libffi", + "libloading", "log", "measureme", "rand", diff --git a/Cargo.toml b/Cargo.toml index 39bc9185db314..d6d005ac36942 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,6 +20,8 @@ doctest = false # and no doc tests [dependencies] getrandom = { version = "0.2", features = ["std"] } env_logger = "0.9" +libffi = "3.0.0" +libloading = "0.7" log = "0.4" shell-escape = "0.1.4" rand = "0.8" diff --git a/README.md b/README.md index c7a3200dbd904..8e96338a865f6 100644 --- a/README.md +++ b/README.md @@ -346,6 +346,17 @@ to Miri failing to detect cases of undefined behavior in a program. this flag is **unsound**. * `-Zmiri-disable-weak-memory-emulation` disables the emulation of some C++11 weak memory effects. +* `-Zmiri-extern-so-file=` is an experimental flag for providing support + for FFI calls. Functions not provided by that file are still executed via the usual Miri shims. + **WARNING**: If an invalid/incorrect `.so` file is specified, this can cause undefined behaviour in Miri itself! + And of course, Miri cannot do any checks on the actions taken by the external code. + Note that Miri has its own handling of file descriptors, so if you want to replace *some* functions + working on file descriptors, you will have to replace *all* of them, or the two kinds of + file descriptors will be mixed up. + This is **work in progress**; currently, only integer arguments and return values are + supported (and no, pointer/integer casts to work around this limitation will not work; + they will fail horribly). + Follow [the discussion on supporting other types](https://github.com/rust-lang/miri/issues/2365). * `-Zmiri-measureme=` enables `measureme` profiling for the interpreted program. This can be used to find which parts of your program are executing slowly under Miri. The profile is written out to a file with the prefix ``, and can be processed diff --git a/build.rs b/build.rs new file mode 100644 index 0000000000000..c8121aa9733e9 --- /dev/null +++ b/build.rs @@ -0,0 +1,6 @@ +fn main() { + // Re-export the TARGET environment variable so it can + // be accessed by miri. + let target = std::env::var("TARGET").unwrap(); + println!("cargo:rustc-env=TARGET={:?}", target); +} diff --git a/miri b/miri index 84bd74817090a..19f1a987ace4a 100755 --- a/miri +++ b/miri @@ -108,6 +108,7 @@ esac ## Prepare the environment # Determine some toolchain properties +# export the target so its available in miri TARGET=$(rustc +$TOOLCHAIN --version --verbose | grep "^host:" | cut -d ' ' -f 2) SYSROOT=$(rustc +$TOOLCHAIN --print sysroot) LIBDIR=$SYSROOT/lib/rustlib/$TARGET/lib diff --git a/src/bin/miri.rs b/src/bin/miri.rs index ca0787b229830..fa6a307038937 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -530,6 +530,19 @@ fn main() { "full" => BacktraceStyle::Full, _ => show_error!("-Zmiri-backtrace may only be 0, 1, or full"), }; + } else if let Some(param) = arg.strip_prefix("-Zmiri-extern-so-file=") { + let filename = param.to_string(); + if std::path::Path::new(&filename).exists() { + if let Some(other_filename) = miri_config.external_so_file { + panic!( + "-Zmiri-extern-so-file external SO file is already set to {}", + other_filename.display() + ); + } + miri_config.external_so_file = Some(filename.into()); + } else { + panic!("-Zmiri-extern-so-file path {} does not exist", filename); + } } else { // Forward to rustc. rustc_args.push(arg); diff --git a/src/eval.rs b/src/eval.rs index 12e895852d22e..511163a2e759a 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -3,6 +3,7 @@ use std::ffi::{OsStr, OsString}; use std::iter; use std::panic::{self, AssertUnwindSafe}; +use std::path::PathBuf; use std::thread; use log::info; @@ -128,6 +129,9 @@ pub struct MiriConfig { pub report_progress: Option, /// Whether Stacked Borrows retagging should recurse into fields of datatypes. pub retag_fields: bool, + /// The location of a shared object file to load when calling external functions + /// FIXME! consider allowing users to specify paths to multiple SO files, or to a directory + pub external_so_file: Option, } impl Default for MiriConfig { @@ -159,6 +163,7 @@ impl Default for MiriConfig { preemption_rate: 0.01, // 1% report_progress: None, retag_fields: false, + external_so_file: None, } } } diff --git a/src/machine.rs b/src/machine.rs index 7357731f3592c..841c1343fa3c7 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -358,10 +358,14 @@ pub struct Evaluator<'mir, 'tcx> { pub(crate) report_progress: Option, /// The number of blocks that passed since the last progress report. pub(crate) since_progress_report: u32, + + /// Handle of the optional shared object file for external functions. + pub external_so_lib: Option<(libloading::Library, std::path::PathBuf)>, } impl<'mir, 'tcx> Evaluator<'mir, 'tcx> { pub(crate) fn new(config: &MiriConfig, layout_cx: LayoutCx<'tcx, TyCtxt<'tcx>>) -> Self { + let target_triple = &layout_cx.tcx.sess.opts.target_triple.to_string(); let local_crates = helpers::get_local_crates(layout_cx.tcx); let layouts = PrimitiveLayouts::new(layout_cx).expect("Couldn't get layouts of primitive types"); @@ -412,6 +416,24 @@ impl<'mir, 'tcx> Evaluator<'mir, 'tcx> { preemption_rate: config.preemption_rate, report_progress: config.report_progress, since_progress_report: 0, + external_so_lib: config.external_so_file.as_ref().map(|lib_file_path| { + // Check if host target == the session target. + if option_env!("TARGET") == Some(target_triple) { + panic!( + "calling external C functions in linked .so file requires target and host to be the same" + ); + } + // Note: it is the user's responsibility to provide a correct SO file. + // WATCH OUT: If an invalid/incorrect SO file is specified, this can cause + // undefined behaviour in Miri itself! + ( + unsafe { + libloading::Library::new(lib_file_path) + .expect("Failed to read specified shared object file") + }, + lib_file_path.clone(), + ) + }), } } diff --git a/src/shims/ffi_support.rs b/src/shims/ffi_support.rs new file mode 100644 index 0000000000000..f1ae1e7d3f47f --- /dev/null +++ b/src/shims/ffi_support.rs @@ -0,0 +1,291 @@ +use libffi::{high::call as ffi, low::CodePtr}; +use std::ops::Deref; + +use rustc_middle::ty::{self as ty, IntTy, Ty, UintTy}; +use rustc_span::Symbol; +use rustc_target::abi::HasDataLayout; + +use crate::*; + +impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} + +pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx> { + /// Extract the scalar value from the result of reading a scalar from the machine, + /// and convert it to a `CArg`. + fn scalar_to_carg( + k: ScalarMaybeUninit, + arg_type: Ty<'tcx>, + cx: &impl HasDataLayout, + ) -> InterpResult<'tcx, CArg> { + match arg_type.kind() { + // If the primitive provided can be converted to a type matching the type pattern + // then create a `CArg` of this primitive value with the corresponding `CArg` constructor. + // the ints + ty::Int(IntTy::I8) => { + return Ok(CArg::Int8(k.to_i8()?)); + } + ty::Int(IntTy::I16) => { + return Ok(CArg::Int16(k.to_i16()?)); + } + ty::Int(IntTy::I32) => { + return Ok(CArg::Int32(k.to_i32()?)); + } + ty::Int(IntTy::I64) => { + return Ok(CArg::Int64(k.to_i64()?)); + } + ty::Int(IntTy::Isize) => { + // This will fail if host != target, but then the entire FFI thing probably won't work well + // in that situation. + return Ok(CArg::ISize(k.to_machine_isize(cx)?.try_into().unwrap())); + } + // the uints + ty::Uint(UintTy::U8) => { + return Ok(CArg::UInt8(k.to_u8()?)); + } + ty::Uint(UintTy::U16) => { + return Ok(CArg::UInt16(k.to_u16()?)); + } + ty::Uint(UintTy::U32) => { + return Ok(CArg::UInt32(k.to_u32()?)); + } + ty::Uint(UintTy::U64) => { + return Ok(CArg::UInt64(k.to_u64()?)); + } + ty::Uint(UintTy::Usize) => { + // This will fail if host != target, but then the entire FFI thing probably won't work well + // in that situation. + return Ok(CArg::USize(k.to_machine_usize(cx)?.try_into().unwrap())); + } + _ => {} + } + // If no primitives were returned then we have an unsupported type. + throw_unsup_format!( + "unsupported scalar argument type to external C function: {:?}", + arg_type + ); + } + + /// Call external C function and + /// store output, depending on return type in the function signature. + fn call_external_c_and_store_return<'a>( + &mut self, + link_name: Symbol, + dest: &PlaceTy<'tcx, Provenance>, + ptr: CodePtr, + libffi_args: Vec>, + ) -> InterpResult<'tcx, ()> { + let this = self.eval_context_mut(); + + // Unsafe because of the call to external C code. + // Because this is calling a C function it is not necessarily sound, + // but there is no way around this and we've checked as much as we can. + unsafe { + // If the return type of a function is a primitive integer type, + // then call the function (`ptr`) with arguments `libffi_args`, store the return value as the specified + // primitive integer type, and then write this value out to the miri memory as an integer. + match dest.layout.ty.kind() { + // ints + ty::Int(IntTy::I8) => { + let x = ffi::call::(ptr, libffi_args.as_slice()); + this.write_int(x, dest)?; + return Ok(()); + } + ty::Int(IntTy::I16) => { + let x = ffi::call::(ptr, libffi_args.as_slice()); + this.write_int(x, dest)?; + return Ok(()); + } + ty::Int(IntTy::I32) => { + let x = ffi::call::(ptr, libffi_args.as_slice()); + this.write_int(x, dest)?; + return Ok(()); + } + ty::Int(IntTy::I64) => { + let x = ffi::call::(ptr, libffi_args.as_slice()); + this.write_int(x, dest)?; + return Ok(()); + } + ty::Int(IntTy::Isize) => { + let x = ffi::call::(ptr, libffi_args.as_slice()); + // `isize` doesn't `impl Into`, so convert manually. + // Convert to `i64` since this covers both 32- and 64-bit machines. + this.write_int(i64::try_from(x).unwrap(), dest)?; + return Ok(()); + } + // uints + ty::Uint(UintTy::U8) => { + let x = ffi::call::(ptr, libffi_args.as_slice()); + this.write_int(x, dest)?; + return Ok(()); + } + ty::Uint(UintTy::U16) => { + let x = ffi::call::(ptr, libffi_args.as_slice()); + this.write_int(x, dest)?; + return Ok(()); + } + ty::Uint(UintTy::U32) => { + let x = ffi::call::(ptr, libffi_args.as_slice()); + this.write_int(x, dest)?; + return Ok(()); + } + ty::Uint(UintTy::U64) => { + let x = ffi::call::(ptr, libffi_args.as_slice()); + this.write_int(x, dest)?; + return Ok(()); + } + ty::Uint(UintTy::Usize) => { + let x = ffi::call::(ptr, libffi_args.as_slice()); + // `usize` doesn't `impl Into`, so convert manually. + // Convert to `u64` since this covers both 32- and 64-bit machines. + this.write_int(u64::try_from(x).unwrap(), dest)?; + return Ok(()); + } + // Functions with no declared return type (i.e., the default return) + // have the output_type `Tuple([])`. + ty::Tuple(t_list) => + if t_list.len() == 0 { + ffi::call::<()>(ptr, libffi_args.as_slice()); + return Ok(()); + }, + _ => {} + } + // FIXME ellen! deal with all the other return types + throw_unsup_format!("unsupported return type to external C function: {:?}", link_name); + } + } + + /// Get the pointer to the function of the specified name in the shared object file, + /// if it exists. The function must be in the shared object file specified: we do *not* + /// return pointers to functions in dependencies of the library. + fn get_func_ptr_explicitly_from_lib(&mut self, link_name: Symbol) -> Option { + let this = self.eval_context_mut(); + // Try getting the function from the shared library. + // On windows `_lib_path` will be unused, hence the name starting with `_`. + let (lib, _lib_path) = this.machine.external_so_lib.as_ref().unwrap(); + let func: libloading::Symbol<'_, unsafe extern "C" fn()> = unsafe { + match lib.get(link_name.as_str().as_bytes()) { + Ok(x) => x, + Err(_) => { + return None; + } + } + }; + + // FIXME: this is a hack! + // The `libloading` crate will automatically load system libraries like `libc`. + // On linux `libloading` is based on `dlsym`: https://docs.rs/libloading/0.7.3/src/libloading/os/unix/mod.rs.html#202 + // and `dlsym`(https://linux.die.net/man/3/dlsym) looks through the dependency tree of the + // library if it can't find the symbol in the library itself. + // So, in order to check if the function was actually found in the specified + // `machine.external_so_lib` we need to check its `dli_fname` and compare it to + // the specified SO file path. + // This code is a reimplementation of the mechanism for getting `dli_fname` in `libloading`, + // from: https://docs.rs/libloading/0.7.3/src/libloading/os/unix/mod.rs.html#411 + // using the `libc` crate where this interface is public. + // No `libc::dladdr` on windows. + #[cfg(unix)] + let mut info = std::mem::MaybeUninit::::uninit(); + #[cfg(unix)] + unsafe { + if libc::dladdr(*func.deref() as *const _, info.as_mut_ptr()) != 0 { + if std::ffi::CStr::from_ptr(info.assume_init().dli_fname).to_str().unwrap() + != _lib_path.to_str().unwrap() + { + return None; + } + } + } + // Return a pointer to the function. + Some(CodePtr(*func.deref() as *mut _)) + } + + /// Call specified external C function, with supplied arguments. + /// Need to convert all the arguments from their hir representations to + /// a form compatible with C (through `libffi` call). + /// Then, convert return from the C call into a corresponding form that + /// can be stored in Miri internal memory. + fn call_external_c_fct( + &mut self, + link_name: Symbol, + dest: &PlaceTy<'tcx, Provenance>, + args: &[OpTy<'tcx, Provenance>], + ) -> InterpResult<'tcx, bool> { + // Get the pointer to the function in the shared object file if it exists. + let code_ptr = match self.get_func_ptr_explicitly_from_lib(link_name) { + Some(ptr) => ptr, + None => { + // Shared object file does not export this function -- try the shims next. + return Ok(false); + } + }; + + let this = self.eval_context_mut(); + + // Get the function arguments, and convert them to `libffi`-compatible form. + let mut libffi_args = Vec::::with_capacity(args.len()); + for cur_arg in args.iter() { + libffi_args.push(Self::scalar_to_carg( + this.read_scalar(cur_arg)?, + cur_arg.layout.ty, + this, + )?); + } + + // Convert them to `libffi::high::Arg` type. + let libffi_args = libffi_args + .iter() + .map(|cur_arg| cur_arg.arg_downcast()) + .collect::>>(); + + // Call the function and store output, depending on return type in the function signature. + self.call_external_c_and_store_return(link_name, dest, code_ptr, libffi_args)?; + Ok(true) + } +} + +#[derive(Debug, Clone)] +/// Enum of supported arguments to external C functions. +// We introduce this enum instead of just calling `ffi::arg` and storing a list +// of `libffi::high::Arg` directly, because the `libffi::high::Arg` just wraps a reference +// to the value it represents: https://docs.rs/libffi/latest/libffi/high/call/struct.Arg.html +// and we need to store a copy of the value, and pass a reference to this copy to C instead. +pub enum CArg { + /// 8-bit signed integer. + Int8(i8), + /// 16-bit signed integer. + Int16(i16), + /// 32-bit signed integer. + Int32(i32), + /// 64-bit signed integer. + Int64(i64), + /// isize. + ISize(isize), + /// 8-bit unsigned integer. + UInt8(u8), + /// 16-bit unsigned integer. + UInt16(u16), + /// 32-bit unsigned integer. + UInt32(u32), + /// 64-bit unsigned integer. + UInt64(u64), + /// usize. + USize(usize), +} + +impl<'a> CArg { + /// Convert a `CArg` to a `libffi` argument type. + fn arg_downcast(&'a self) -> libffi::high::Arg<'a> { + match self { + CArg::Int8(i) => ffi::arg(i), + CArg::Int16(i) => ffi::arg(i), + CArg::Int32(i) => ffi::arg(i), + CArg::Int64(i) => ffi::arg(i), + CArg::ISize(i) => ffi::arg(i), + CArg::UInt8(i) => ffi::arg(i), + CArg::UInt16(i) => ffi::arg(i), + CArg::UInt32(i) => ffi::arg(i), + CArg::UInt64(i) => ffi::arg(i), + CArg::USize(i) => ffi::arg(i), + } + } +} diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 960dbfe6ed8b8..b8862b3ba408f 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -23,6 +23,7 @@ use rustc_target::{ use super::backtrace::EvalContextExt as _; use crate::helpers::{convert::Truncate, target_os_is_unix}; +use crate::shims::ffi_support::EvalContextExt as _; use crate::*; /// Returned by `emulate_foreign_item_by_name`. @@ -31,7 +32,7 @@ pub enum EmulateByNameResult<'mir, 'tcx> { NeedsJumping, /// Jumping has already been taken care of. AlreadyJumped, - /// A MIR body has been found for the function + /// A MIR body has been found for the function. MirBody(&'mir mir::Body<'tcx>, ty::Instance<'tcx>), /// The item is not supported. NotSupported, @@ -369,6 +370,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, EmulateByNameResult<'mir, 'tcx>> { let this = self.eval_context_mut(); + // First deal with any external C functions in linked .so file + // (if any SO file is specified, and if the host target == the session target) + if this.machine.external_so_lib.as_ref().is_some() { + // An Ok(false) here means that the function being called was not exported + // by the specified SO file; we should continue and check if it corresponds to + // a provided shim. + if this.call_external_c_fct(link_name, dest, args)? { + return Ok(EmulateByNameResult::NeedsJumping); + } + } + // When adding a new shim, you should follow the following pattern: // ``` // "shim_name" => { @@ -779,9 +791,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx target => throw_unsup_format!("the target `{}` is not supported", target), } }; - // We only fall through to here if we did *not* hit the `_` arm above, - // i.e., if we actually emulated the function. + // i.e., if we actually emulated the function with one of the shims. Ok(EmulateByNameResult::NeedsJumping) } diff --git a/src/shims/mod.rs b/src/shims/mod.rs index 618295592450f..ee2145db7e1b5 100644 --- a/src/shims/mod.rs +++ b/src/shims/mod.rs @@ -1,6 +1,7 @@ #![warn(clippy::integer_arithmetic)] mod backtrace; +pub mod ffi_support; pub mod foreign_items; pub mod intrinsics; pub mod unix; diff --git a/tests/compiletest.rs b/tests/compiletest.rs index b38edc9e0f7dd..fe0d9be28cf2a 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -1,13 +1,42 @@ use colored::*; use regex::Regex; use std::path::{Path, PathBuf}; -use std::{env, ffi::OsString}; +use std::{env, ffi::OsString, process::Command}; use ui_test::{color_eyre::Result, Config, DependencyBuilder, Mode, OutputConflictHandling}; fn miri_path() -> PathBuf { PathBuf::from(option_env!("MIRI").unwrap_or(env!("CARGO_BIN_EXE_miri"))) } +// Build the shared object file for testing external C function calls. +fn build_so_for_c_ffi_tests() -> PathBuf { + let cc = option_env!("CC").unwrap_or("cc"); + // Target directory that we can write to. + let so_target_dir = Path::new(&env::var_os("CARGO_TARGET_DIR").unwrap()).join("miri-extern-so"); + // Create the directory if it does not already exist. + std::fs::create_dir_all(&so_target_dir) + .expect("Failed to create directory for shared object file"); + let so_file_path = so_target_dir.join("libtestlib.so"); + let cc_output = Command::new(cc) + .args([ + "-shared", + "-o", + so_file_path.to_str().unwrap(), + "tests/extern-so/test.c", + // Only add the functions specified in libcode.version to the shared object file. + // This is to avoid automatically adding `malloc`, etc. + // Source: https://anadoxin.org/blog/control-over-symbol-exports-in-gcc.html/ + "-fPIC", + "-Wl,--version-script=tests/extern-so/libcode.version", + ]) + .output() + .expect("failed to generate shared object file for testing external C function calls"); + if !cc_output.status.success() { + panic!("error in generating shared object file for testing external C function calls"); + } + so_file_path +} + fn run_tests( mode: Mode, path: &str, @@ -40,6 +69,16 @@ fn run_tests( flags.push(target.into()); } + // If we're on linux, and we're testing the extern-so functionality, + // then build the shared object file for testing external C function calls + // and push the relevant compiler flag. + if cfg!(target_os = "linux") && path.starts_with("tests/extern-so/") { + let so_file_path = build_so_for_c_ffi_tests(); + let mut flag = std::ffi::OsString::from("-Zmiri-extern-so-file="); + flag.push(so_file_path.into_os_string()); + flags.push(flag); + } + let skip_ui_checks = env::var_os("MIRI_SKIP_UI_CHECKS").is_some(); let output_conflict_handling = match (env::var_os("MIRI_BLESS").is_some(), skip_ui_checks) { @@ -176,6 +215,10 @@ fn main() -> Result<()> { ui(Mode::Pass, "tests/pass-dep", WithDependencies)?; ui(Mode::Panic, "tests/panic", WithDependencies)?; ui(Mode::Fail, "tests/fail", WithDependencies)?; + if cfg!(target_os = "linux") { + ui(Mode::Pass, "tests/extern-so/pass", WithoutDependencies)?; + ui(Mode::Fail, "tests/extern-so/fail", WithDependencies)?; + } Ok(()) } diff --git a/tests/extern-so/fail/function_not_in_so.rs b/tests/extern-so/fail/function_not_in_so.rs new file mode 100644 index 0000000000000..3aaeb632cad7b --- /dev/null +++ b/tests/extern-so/fail/function_not_in_so.rs @@ -0,0 +1,12 @@ +//@only-target-linux +//@only-on-host + +extern "C" { + fn foo(); +} + +fn main() { + unsafe { + foo(); //~ ERROR: unsupported operation: can't call foreign function: foo + } +} diff --git a/tests/extern-so/fail/function_not_in_so.stderr b/tests/extern-so/fail/function_not_in_so.stderr new file mode 100644 index 0000000000000..8ff9ca74bc584 --- /dev/null +++ b/tests/extern-so/fail/function_not_in_so.stderr @@ -0,0 +1,14 @@ +error: unsupported operation: can't call foreign function: foo + --> $DIR/function_not_in_so.rs:LL:CC + | +LL | foo(); + | ^^^^^ can't call foreign function: foo + | + = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support + = note: backtrace: + = note: inside `main` at $DIR/function_not_in_so.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/extern-so/libcode.version b/tests/extern-so/libcode.version new file mode 100644 index 0000000000000..0f04b9aaebb38 --- /dev/null +++ b/tests/extern-so/libcode.version @@ -0,0 +1,9 @@ +CODEABI_1.0 { + global: *add_one_int*; + *printer*; + *test_stack_spill*; + *get_unsigned_int*; + *add_int16*; + *add_short_to_long*; + local: *; +}; diff --git a/tests/extern-so/pass/call_extern_c_fcts.rs b/tests/extern-so/pass/call_extern_c_fcts.rs new file mode 100644 index 0000000000000..1e1d0b11e99ff --- /dev/null +++ b/tests/extern-so/pass/call_extern_c_fcts.rs @@ -0,0 +1,46 @@ +//@only-target-linux +//@only-on-host + +extern "C" { + fn add_one_int(x: i32) -> i32; + fn add_int16(x: i16) -> i16; + fn test_stack_spill( + a: i32, + b: i32, + c: i32, + d: i32, + e: i32, + f: i32, + g: i32, + h: i32, + i: i32, + j: i32, + k: i32, + l: i32, + ) -> i32; + fn add_short_to_long(x: i16, y: i64) -> i64; + fn get_unsigned_int() -> u32; + fn printer(); +} + +fn main() { + unsafe { + // test function that adds 2 to a provided int + assert_eq!(add_one_int(1), 3); + + // test function that takes the sum of its 12 arguments + assert_eq!(test_stack_spill(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12), 78); + + // test function that adds 3 to a 16 bit int + assert_eq!(add_int16(-1i16), 2i16); + + // test function that adds an i16 to an i64 + assert_eq!(add_short_to_long(-1i16, 123456789123i64), 123456789122i64); + + // test function that returns -10 as an unsigned int + assert_eq!(get_unsigned_int(), (-10i32) as u32); + + // test void function that prints from C + printer(); + } +} diff --git a/tests/extern-so/pass/call_extern_c_fcts.stdout b/tests/extern-so/pass/call_extern_c_fcts.stdout new file mode 100644 index 0000000000000..7ba13d2d7b02e --- /dev/null +++ b/tests/extern-so/pass/call_extern_c_fcts.stdout @@ -0,0 +1 @@ +printing from C diff --git a/tests/extern-so/test.c b/tests/extern-so/test.c new file mode 100644 index 0000000000000..68714f1743b6e --- /dev/null +++ b/tests/extern-so/test.c @@ -0,0 +1,27 @@ +#include + +int add_one_int(int x) { + return 2 + x; +} + +void printer() { + printf("printing from C\n"); +} + +// function with many arguments, to test functionality when some args are stored +// on the stack +int test_stack_spill(int a, int b, int c, int d, int e, int f, int g, int h, int i, int j, int k, int l) { + return a+b+c+d+e+f+g+h+i+j+k+l; +} + +unsigned int get_unsigned_int() { + return -10; +} + +short add_int16(short x) { + return x + 3; +} + +long add_short_to_long(short x, long y) { + return x + y; +} From 10a1a59c4b56d2aec378db238bcf7f9a0c548e0a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 26 Aug 2022 08:50:25 -0400 Subject: [PATCH 3681/3747] fix data race error during env var cleanup --- src/concurrency/data_race.rs | 19 +++++++++++---- src/eval.rs | 9 +++++--- tests/pass-dep/shims/env-cleanup-data-race.rs | 23 +++++++++++++++++++ 3 files changed, 44 insertions(+), 7 deletions(-) create mode 100644 tests/pass-dep/shims/env-cleanup-data-race.rs diff --git a/src/concurrency/data_race.rs b/src/concurrency/data_race.rs index 0e176ec91fcfe..c1a3db67c84ae 100644 --- a/src/concurrency/data_race.rs +++ b/src/concurrency/data_race.rs @@ -689,6 +689,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { Ok(()) } } + + /// After all threads are done running, this allows data races to occur for subsequent + /// 'administrative' machine accesses (that logically happen outside of the Abstract Machine). + fn allow_data_races_all_threads_done(&mut self) { + let this = self.eval_context_ref(); + assert!(this.have_all_terminated()); + if let Some(data_race) = &this.machine.data_race { + let old = data_race.ongoing_action_data_race_free.replace(true); + assert!(!old, "cannot nest allow_data_races"); + } + } } /// Vector clock metadata for a logical memory allocation. @@ -955,8 +966,8 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { fn allow_data_races_ref(&self, op: impl FnOnce(&MiriEvalContext<'mir, 'tcx>) -> R) -> R { let this = self.eval_context_ref(); if let Some(data_race) = &this.machine.data_race { - assert!(!data_race.ongoing_action_data_race_free.get(), "cannot nest allow_data_races"); - data_race.ongoing_action_data_race_free.set(true); + let old = data_race.ongoing_action_data_race_free.replace(true); + assert!(!old, "cannot nest allow_data_races"); } let result = op(this); if let Some(data_race) = &this.machine.data_race { @@ -975,8 +986,8 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { ) -> R { let this = self.eval_context_mut(); if let Some(data_race) = &this.machine.data_race { - assert!(!data_race.ongoing_action_data_race_free.get(), "cannot nest allow_data_races"); - data_race.ongoing_action_data_race_free.set(true); + let old = data_race.ongoing_action_data_race_free.replace(true); + assert!(!old, "cannot nest allow_data_races"); } let result = op(this); if let Some(data_race) = &this.machine.data_race { diff --git a/src/eval.rs b/src/eval.rs index 511163a2e759a..f7bc11a445d97 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -377,10 +377,13 @@ pub fn eval_entry<'tcx>( }); // Machine cleanup. Only do this if all threads have terminated; threads that are still running - // might cause data races (https://github.com/rust-lang/miri/issues/2020) or Stacked Borrows - // errors (https://github.com/rust-lang/miri/issues/2396) if we deallocate here. + // might cause Stacked Borrows errors (https://github.com/rust-lang/miri/issues/2396). if ecx.have_all_terminated() { - EnvVars::cleanup(&mut ecx).unwrap(); + // Even if all threads have terminated, we have to beware of data races since some threads + // might not have joined the main thread (https://github.com/rust-lang/miri/issues/2020, + // https://github.com/rust-lang/miri/issues/2508). + ecx.allow_data_races_all_threads_done(); + EnvVars::cleanup(&mut ecx).expect("error during env var cleanup"); } // Process the result. diff --git a/tests/pass-dep/shims/env-cleanup-data-race.rs b/tests/pass-dep/shims/env-cleanup-data-race.rs new file mode 100644 index 0000000000000..d36ffe70321b4 --- /dev/null +++ b/tests/pass-dep/shims/env-cleanup-data-race.rs @@ -0,0 +1,23 @@ +//@compile-flags: -Zmiri-disable-isolation -Zmiri-preemption-rate=0 +//@ignore-target-windows: No libc on Windows + +use std::ffi::CStr; +use std::ffi::CString; +use std::thread; + +fn main() { + unsafe { + thread::spawn(|| { + // Access the environment in another thread without taking the env lock + let k = CString::new("MIRI_ENV_VAR_TEST".as_bytes()).unwrap(); + let s = libc::getenv(k.as_ptr()) as *const libc::c_char; + if s.is_null() { + panic!("null"); + } + let _s = String::from_utf8_lossy(CStr::from_ptr(s).to_bytes()); + }); + thread::yield_now(); + // After the main thread exits, env vars will be cleaned up -- but because we have not *joined* + // the other thread, those accesses technically race with those in the other thread. + } +} From fa1e51ae7ddf5a18b73bdfa93ae194fb1a50a774 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Fri, 26 Aug 2022 14:35:40 +0000 Subject: [PATCH 3682/3747] Fix merge conflict --- .gitignore | 6 ------ 1 file changed, 6 deletions(-) diff --git a/.gitignore b/.gitignore index c1d3d33576fbb..924a93e807fe3 100644 --- a/.gitignore +++ b/.gitignore @@ -9,11 +9,5 @@ tex/*/out perf.data perf.data.old flamegraph.svg -<<<<<<< HEAD -======= -<<<<<<< HEAD tests/extern-so/libtestlib.so -======= ->>>>>>> master ->>>>>>> 58ba05a0 (C FFI support for functions with int args and returns) .auto-* From 4e017b54ad96175939c90353b89017d1fd1b9e09 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 26 Aug 2022 17:38:59 -0400 Subject: [PATCH 3683/3747] fix host/target check for extern-so --- build.rs | 2 +- src/machine.rs | 6 ++++-- src/shims/foreign_items.rs | 5 ++--- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/build.rs b/build.rs index c8121aa9733e9..15d6c963ad21f 100644 --- a/build.rs +++ b/build.rs @@ -2,5 +2,5 @@ fn main() { // Re-export the TARGET environment variable so it can // be accessed by miri. let target = std::env::var("TARGET").unwrap(); - println!("cargo:rustc-env=TARGET={:?}", target); + println!("cargo:rustc-env=TARGET={}", target); } diff --git a/src/machine.rs b/src/machine.rs index 841c1343fa3c7..70b8263a9eb25 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -418,9 +418,11 @@ impl<'mir, 'tcx> Evaluator<'mir, 'tcx> { since_progress_report: 0, external_so_lib: config.external_so_file.as_ref().map(|lib_file_path| { // Check if host target == the session target. - if option_env!("TARGET") == Some(target_triple) { + if env!("TARGET") != target_triple { panic!( - "calling external C functions in linked .so file requires target and host to be the same" + "calling external C functions in linked .so file requires host and target to be the same: host={}, target={}", + env!("TARGET"), + target_triple, ); } // Note: it is the user's responsibility to provide a correct SO file. diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index b8862b3ba408f..117e0933ddcf9 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -370,11 +370,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, EmulateByNameResult<'mir, 'tcx>> { let this = self.eval_context_mut(); - // First deal with any external C functions in linked .so file - // (if any SO file is specified, and if the host target == the session target) + // First deal with any external C functions in linked .so file. if this.machine.external_so_lib.as_ref().is_some() { // An Ok(false) here means that the function being called was not exported - // by the specified SO file; we should continue and check if it corresponds to + // by the specified `.so` file; we should continue and check if it corresponds to // a provided shim. if this.call_external_c_fct(link_name, dest, args)? { return Ok(EmulateByNameResult::NeedsJumping); From 82802337a88b241c03ccb04a934f9fdb541a3200 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 26 Aug 2022 17:40:26 -0400 Subject: [PATCH 3684/3747] rename test to match usual naming conventions what's a "fcts"? --- .../extern-so/pass/{call_extern_c_fcts.rs => call_extern_c_fn.rs} | 0 .../pass/{call_extern_c_fcts.stdout => call_extern_c_fn.stdout} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename tests/extern-so/pass/{call_extern_c_fcts.rs => call_extern_c_fn.rs} (100%) rename tests/extern-so/pass/{call_extern_c_fcts.stdout => call_extern_c_fn.stdout} (100%) diff --git a/tests/extern-so/pass/call_extern_c_fcts.rs b/tests/extern-so/pass/call_extern_c_fn.rs similarity index 100% rename from tests/extern-so/pass/call_extern_c_fcts.rs rename to tests/extern-so/pass/call_extern_c_fn.rs diff --git a/tests/extern-so/pass/call_extern_c_fcts.stdout b/tests/extern-so/pass/call_extern_c_fn.stdout similarity index 100% rename from tests/extern-so/pass/call_extern_c_fcts.stdout rename to tests/extern-so/pass/call_extern_c_fn.stdout From 235036fcb3b8cac8b98774224c56c0ab7b454bb5 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 26 Aug 2022 17:43:04 -0400 Subject: [PATCH 3685/3747] nicer errors --- src/bin/miri.rs | 6 +++--- src/machine.rs | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/bin/miri.rs b/src/bin/miri.rs index fa6a307038937..2684ad7ff3d39 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -534,14 +534,14 @@ fn main() { let filename = param.to_string(); if std::path::Path::new(&filename).exists() { if let Some(other_filename) = miri_config.external_so_file { - panic!( - "-Zmiri-extern-so-file external SO file is already set to {}", + show_error!( + "-Zmiri-extern-so-file is already set to {}", other_filename.display() ); } miri_config.external_so_file = Some(filename.into()); } else { - panic!("-Zmiri-extern-so-file path {} does not exist", filename); + show_error!("-Zmiri-extern-so-file `{}` does not exist", filename); } } else { // Forward to rustc. diff --git a/src/machine.rs b/src/machine.rs index 70b8263a9eb25..df2566de88f97 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -431,7 +431,7 @@ impl<'mir, 'tcx> Evaluator<'mir, 'tcx> { ( unsafe { libloading::Library::new(lib_file_path) - .expect("Failed to read specified shared object file") + .expect("failed to read specified extern shared object file") }, lib_file_path.clone(), ) From 3a2252b7b321076d8cf314fa49dc5a4c9da133b4 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 1 Aug 2022 21:34:28 -0400 Subject: [PATCH 3686/3747] adjust for earlier init checking in the core engine --- src/concurrency/data_race.rs | 32 +++---- src/concurrency/weak_memory.rs | 36 ++++---- src/helpers.rs | 24 +++-- src/machine.rs | 9 +- src/operator.rs | 22 +++-- src/shims/intrinsics/mod.rs | 8 +- src/shims/intrinsics/simd.rs | 41 +++++---- src/shims/panic.rs | 4 +- src/shims/unix/foreign_items.rs | 10 +-- src/shims/unix/freebsd/foreign_items.rs | 2 +- src/shims/unix/linux/foreign_items.rs | 2 +- src/shims/unix/linux/sync.rs | 2 +- src/shims/unix/macos/foreign_items.rs | 6 +- src/shims/unix/sync.rs | 90 ++++++++----------- src/shims/windows/foreign_items.rs | 4 +- src/shims/windows/sync.rs | 3 +- tests/fail/invalid_int.rs | 4 +- tests/fail/invalid_int.stderr | 4 +- tests/fail/transmute-pair-uninit.stderr | 4 +- tests/fail/uninit_byte_read.stderr | 4 +- tests/fail/validity/invalid_bool_uninit.rs | 2 +- .../fail/validity/invalid_bool_uninit.stderr | 4 +- tests/fail/validity/invalid_char_uninit.rs | 2 +- .../fail/validity/invalid_char_uninit.stderr | 4 +- tests/fail/validity/invalid_fnptr_uninit.rs | 2 +- .../fail/validity/invalid_fnptr_uninit.stderr | 4 +- tests/fail/validity/uninit_float.rs | 2 +- tests/fail/validity/uninit_float.stderr | 4 +- tests/fail/validity/uninit_integer.rs | 2 +- tests/fail/validity/uninit_integer.stderr | 4 +- tests/fail/{ => validity}/uninit_raw_ptr.rs | 2 +- .../fail/{ => validity}/uninit_raw_ptr.stderr | 4 +- tests/pass/issues/issue-miri-2068-2.rs | 16 ---- 33 files changed, 163 insertions(+), 200 deletions(-) rename tests/fail/{ => validity}/uninit_raw_ptr.rs (52%) rename tests/fail/{ => validity}/uninit_raw_ptr.stderr (76%) delete mode 100644 tests/pass/issues/issue-miri-2068-2.rs diff --git a/src/concurrency/data_race.rs b/src/concurrency/data_race.rs index c1a3db67c84ae..223fad40362a4 100644 --- a/src/concurrency/data_race.rs +++ b/src/concurrency/data_race.rs @@ -447,7 +447,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { offset: u64, layout: TyAndLayout<'tcx>, atomic: AtomicReadOrd, - ) -> InterpResult<'tcx, ScalarMaybeUninit> { + ) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_ref(); let value_place = this.deref_operand_and_offset(op, offset, layout)?; this.read_scalar_atomic(&value_place, atomic) @@ -458,7 +458,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { &mut self, op: &OpTy<'tcx, Provenance>, offset: u64, - value: impl Into>, + value: impl Into>, layout: TyAndLayout<'tcx>, atomic: AtomicWriteOrd, ) -> InterpResult<'tcx> { @@ -472,7 +472,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { &self, place: &MPlaceTy<'tcx, Provenance>, atomic: AtomicReadOrd, - ) -> InterpResult<'tcx, ScalarMaybeUninit> { + ) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_ref(); this.atomic_access_check(place)?; // This will read from the last store in the modification order of this location. In case @@ -490,7 +490,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { /// Perform an atomic write operation at the memory location. fn write_scalar_atomic( &mut self, - val: ScalarMaybeUninit, + val: Scalar, dest: &MPlaceTy<'tcx, Provenance>, atomic: AtomicWriteOrd, ) -> InterpResult<'tcx> { @@ -531,10 +531,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { this.validate_atomic_rmw(place, atomic)?; this.buffered_atomic_rmw( - val.to_scalar_or_uninit(), + val.to_scalar(), place, atomic, - old.to_scalar_or_uninit(), + old.to_scalar(), )?; Ok(old) } @@ -544,9 +544,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { fn atomic_exchange_scalar( &mut self, place: &MPlaceTy<'tcx, Provenance>, - new: ScalarMaybeUninit, + new: Scalar, atomic: AtomicRwOrd, - ) -> InterpResult<'tcx, ScalarMaybeUninit> { + ) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); this.atomic_access_check(place)?; @@ -574,7 +574,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { this.validate_overlapping_atomic(place)?; let old = this.allow_data_races_mut(|this| this.read_immediate(&place.into()))?; - let lt = this.binary_op(mir::BinOp::Lt, &old, &rhs)?.to_scalar()?.to_bool()?; + let lt = this.binary_op(mir::BinOp::Lt, &old, &rhs)?.to_scalar().to_bool()?; let new_val = if min { if lt { &old } else { &rhs } @@ -587,10 +587,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { this.validate_atomic_rmw(place, atomic)?; this.buffered_atomic_rmw( - new_val.to_scalar_or_uninit(), + new_val.to_scalar(), place, atomic, - old.to_scalar_or_uninit(), + old.to_scalar(), )?; // Return the old value. @@ -607,7 +607,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { &mut self, place: &MPlaceTy<'tcx, Provenance>, expect_old: &ImmTy<'tcx, Provenance>, - new: ScalarMaybeUninit, + new: Scalar, success: AtomicRwOrd, fail: AtomicReadOrd, can_fail_spuriously: bool, @@ -627,14 +627,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { // If the operation would succeed, but is "weak", fail some portion // of the time, based on `success_rate`. let success_rate = 1.0 - this.machine.cmpxchg_weak_failure_rate; - let cmpxchg_success = eq.to_scalar()?.to_bool()? + let cmpxchg_success = eq.to_scalar().to_bool()? && if can_fail_spuriously { this.machine.rng.get_mut().gen_bool(success_rate) } else { true }; let res = Immediate::ScalarPair( - old.to_scalar_or_uninit(), + old.to_scalar(), Scalar::from_bool(cmpxchg_success).into(), ); @@ -644,14 +644,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { if cmpxchg_success { this.allow_data_races_mut(|this| this.write_scalar(new, &place.into()))?; this.validate_atomic_rmw(place, success)?; - this.buffered_atomic_rmw(new, place, success, old.to_scalar_or_uninit())?; + this.buffered_atomic_rmw(new, place, success, old.to_scalar())?; } else { this.validate_atomic_load(place, fail)?; // A failed compare exchange is equivalent to a load, reading from the latest store // in the modification order. // Since `old` is only a value and not the store element, we need to separately // find it in our store buffer and perform load_impl on it. - this.perform_read_on_buffered_latest(place, fail, old.to_scalar_or_uninit())?; + this.perform_read_on_buffered_latest(place, fail, old.to_scalar())?; } // Return the old value. diff --git a/src/concurrency/weak_memory.rs b/src/concurrency/weak_memory.rs index 30037b6394e56..bd43e848af732 100644 --- a/src/concurrency/weak_memory.rs +++ b/src/concurrency/weak_memory.rs @@ -78,7 +78,7 @@ use std::{ }; use rustc_const_eval::interpret::{ - alloc_range, AllocRange, InterpResult, MPlaceTy, ScalarMaybeUninit, + alloc_range, AllocRange, InterpResult, MPlaceTy, Scalar, }; use rustc_data_structures::fx::FxHashMap; @@ -130,10 +130,10 @@ struct StoreElement { /// The timestamp of the storing thread when it performed the store timestamp: VTimestamp, /// The value of this store - // FIXME: this means the store is either fully initialized or fully uninitialized; + // FIXME: this means the store must be fully initialized; // we will have to change this if we want to support atomics on - // partially initialized data. - val: ScalarMaybeUninit, + // (partially) uninitialized data. + val: Scalar, /// Timestamp of first loads from this store element by each thread /// Behind a RefCell to keep load op take &self @@ -180,7 +180,7 @@ impl StoreBufferAlloc { fn get_or_create_store_buffer<'tcx>( &self, range: AllocRange, - init: ScalarMaybeUninit, + init: Scalar, ) -> InterpResult<'tcx, Ref<'_, StoreBuffer>> { let access_type = self.store_buffers.borrow().access_type(range); let pos = match access_type { @@ -205,7 +205,7 @@ impl StoreBufferAlloc { fn get_or_create_store_buffer_mut<'tcx>( &mut self, range: AllocRange, - init: ScalarMaybeUninit, + init: Scalar, ) -> InterpResult<'tcx, &mut StoreBuffer> { let buffers = self.store_buffers.get_mut(); let access_type = buffers.access_type(range); @@ -226,7 +226,7 @@ impl StoreBufferAlloc { } impl<'mir, 'tcx: 'mir> StoreBuffer { - fn new(init: ScalarMaybeUninit) -> Self { + fn new(init: Scalar) -> Self { let mut buffer = VecDeque::new(); buffer.reserve(STORE_BUFFER_LIMIT); let mut ret = Self { buffer }; @@ -259,7 +259,7 @@ impl<'mir, 'tcx: 'mir> StoreBuffer { is_seqcst: bool, rng: &mut (impl rand::Rng + ?Sized), validate: impl FnOnce() -> InterpResult<'tcx>, - ) -> InterpResult<'tcx, (ScalarMaybeUninit, LoadRecency)> { + ) -> InterpResult<'tcx, (Scalar, LoadRecency)> { // Having a live borrow to store_buffer while calling validate_atomic_load is fine // because the race detector doesn't touch store_buffer @@ -284,7 +284,7 @@ impl<'mir, 'tcx: 'mir> StoreBuffer { fn buffered_write( &mut self, - val: ScalarMaybeUninit, + val: Scalar, global: &DataRaceState, thread_mgr: &ThreadManager<'_, '_>, is_seqcst: bool, @@ -375,7 +375,7 @@ impl<'mir, 'tcx: 'mir> StoreBuffer { /// ATOMIC STORE IMPL in the paper (except we don't need the location's vector clock) fn store_impl( &mut self, - val: ScalarMaybeUninit, + val: Scalar, index: VectorIdx, thread_clock: &VClock, is_seqcst: bool, @@ -421,7 +421,7 @@ impl StoreElement { &self, index: VectorIdx, clocks: &ThreadClockSet, - ) -> ScalarMaybeUninit { + ) -> Scalar { let _ = self.loads.borrow_mut().try_insert(index, clocks.clock[index]); self.val } @@ -464,10 +464,10 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>: fn buffered_atomic_rmw( &mut self, - new_val: ScalarMaybeUninit, + new_val: Scalar, place: &MPlaceTy<'tcx, Provenance>, atomic: AtomicRwOrd, - init: ScalarMaybeUninit, + init: Scalar, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let (alloc_id, base_offset, ..) = this.ptr_get_alloc_id(place.ptr)?; @@ -492,9 +492,9 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>: &self, place: &MPlaceTy<'tcx, Provenance>, atomic: AtomicReadOrd, - latest_in_mo: ScalarMaybeUninit, + latest_in_mo: Scalar, validate: impl FnOnce() -> InterpResult<'tcx>, - ) -> InterpResult<'tcx, ScalarMaybeUninit> { + ) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_ref(); if let Some(global) = &this.machine.data_race { let (alloc_id, base_offset, ..) = this.ptr_get_alloc_id(place.ptr)?; @@ -529,10 +529,10 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>: fn buffered_atomic_write( &mut self, - val: ScalarMaybeUninit, + val: Scalar, dest: &MPlaceTy<'tcx, Provenance>, atomic: AtomicWriteOrd, - init: ScalarMaybeUninit, + init: Scalar, ) -> InterpResult<'tcx> { let this = self.eval_context_mut(); let (alloc_id, base_offset, ..) = this.ptr_get_alloc_id(dest.ptr)?; @@ -576,7 +576,7 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>: &self, place: &MPlaceTy<'tcx, Provenance>, atomic: AtomicReadOrd, - init: ScalarMaybeUninit, + init: Scalar, ) -> InterpResult<'tcx> { let this = self.eval_context_ref(); diff --git a/src/helpers.rs b/src/helpers.rs index f634c8d0c9ac4..92139d9aa2a94 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -116,8 +116,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let instance = this.resolve_path(path); let cid = GlobalId { instance, promoted: None }; let const_val = this.eval_to_allocation(cid)?; - let const_val = this.read_scalar(&const_val.into())?; - const_val.check_init() + this.read_scalar(&const_val.into()) } /// Helper function to get a `libc` constant as a `Scalar`. @@ -567,7 +566,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn get_last_error(&mut self) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); let errno_place = this.last_error_place()?; - this.read_scalar(&errno_place.into())?.check_init() + this.read_scalar(&errno_place.into()) } /// This function tries to produce the most similar OS error from the `std::io::ErrorKind` @@ -680,22 +679,31 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx op: &OpTy<'tcx, Provenance>, offset: u64, layout: TyAndLayout<'tcx>, - ) -> InterpResult<'tcx, ScalarMaybeUninit> { + ) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_ref(); let value_place = this.deref_operand_and_offset(op, offset, layout)?; this.read_scalar(&value_place.into()) } + fn write_immediate_at_offset( + &mut self, + op: &OpTy<'tcx, Provenance>, + offset: u64, + value: &ImmTy<'tcx, Provenance>, + ) -> InterpResult<'tcx, ()> { + let this = self.eval_context_mut(); + let value_place = this.deref_operand_and_offset(op, offset, value.layout)?; + this.write_immediate(**value, &value_place.into()) + } + fn write_scalar_at_offset( &mut self, op: &OpTy<'tcx, Provenance>, offset: u64, - value: impl Into>, + value: impl Into>, layout: TyAndLayout<'tcx>, ) -> InterpResult<'tcx, ()> { - let this = self.eval_context_mut(); - let value_place = this.deref_operand_and_offset(op, offset, layout)?; - this.write_scalar(value, &value_place.into()) + self.write_immediate_at_offset(op, offset, &ImmTy::from_scalar(value.into(), layout)) } /// Parse a `timespec` struct and return it as a `std::time::Duration`. It returns `None` diff --git a/src/machine.rs b/src/machine.rs index df2566de88f97..6bba5bcc5f0dd 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -149,7 +149,7 @@ static_assert_size!(Pointer, 24); // #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] //static_assert_size!(Pointer>, 24); #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))] -static_assert_size!(ScalarMaybeUninit, 32); +static_assert_size!(Scalar, 32); impl interpret::Provenance for Provenance { /// We use absolute addresses in the `offset` of a `Pointer`. @@ -581,7 +581,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { } #[inline(always)] - fn force_int_for_alignment_check(ecx: &MiriEvalContext<'mir, 'tcx>) -> bool { + fn use_addr_for_alignment_check(ecx: &MiriEvalContext<'mir, 'tcx>) -> bool { ecx.machine.check_alignment == AlignmentCheck::Int } @@ -590,11 +590,6 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { ecx.machine.validate } - #[inline(always)] - fn enforce_number_init(_ecx: &MiriEvalContext<'mir, 'tcx>) -> bool { - true - } - #[inline(always)] fn enforce_abi(ecx: &MiriEvalContext<'mir, 'tcx>) -> bool { ecx.machine.enforce_abi diff --git a/src/operator.rs b/src/operator.rs index 679686b4005e1..09e9b0cbd1540 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -32,16 +32,14 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { // Just compare the bits. ScalarPairs are compared lexicographically. // We thus always compare pairs and simply fill scalars up with 0. let left = match **left { - Immediate::Scalar(l) => (l.check_init()?.to_bits(size)?, 0), - Immediate::ScalarPair(l1, l2) => - (l1.check_init()?.to_bits(size)?, l2.check_init()?.to_bits(size)?), - Immediate::Uninit => throw_ub!(InvalidUninitBytes(None)), + Immediate::Scalar(l) => (l.to_bits(size)?, 0), + Immediate::ScalarPair(l1, l2) => (l1.to_bits(size)?, l2.to_bits(size)?), + Immediate::Uninit => panic!("we should never see uninit data here"), }; let right = match **right { - Immediate::Scalar(r) => (r.check_init()?.to_bits(size)?, 0), - Immediate::ScalarPair(r1, r2) => - (r1.check_init()?.to_bits(size)?, r2.check_init()?.to_bits(size)?), - Immediate::Uninit => throw_ub!(InvalidUninitBytes(None)), + Immediate::Scalar(r) => (r.to_bits(size)?, 0), + Immediate::ScalarPair(r1, r2) => (r1.to_bits(size)?, r2.to_bits(size)?), + Immediate::Uninit => panic!("we should never see uninit data here"), }; let res = match bin_op { Eq => left == right, @@ -57,8 +55,8 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { Offset => { assert!(left.layout.ty.is_unsafe_ptr()); - let ptr = left.to_scalar()?.to_pointer(self)?; - let offset = right.to_scalar()?.to_machine_isize(self)?; + let ptr = left.to_scalar().to_pointer(self)?; + let offset = right.to_scalar().to_machine_isize(self)?; let pointee_ty = left.layout.ty.builtin_deref(true).expect("Offset called on non-ptr type").ty; @@ -71,11 +69,11 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriEvalContext<'mir, 'tcx> { Add | Sub | BitOr | BitAnd | BitXor => { assert!(left.layout.ty.is_unsafe_ptr()); assert!(right.layout.ty.is_unsafe_ptr()); - let ptr = left.to_scalar()?.to_pointer(self)?; + let ptr = left.to_scalar().to_pointer(self)?; // We do the actual operation with usize-typed scalars. let left = ImmTy::from_uint(ptr.addr().bytes(), self.machine.layouts.usize); let right = ImmTy::from_uint( - right.to_scalar()?.to_machine_usize(self)?, + right.to_scalar().to_machine_usize(self)?, self.machine.layouts.usize, ); let (result, overflowing, _ty) = diff --git a/src/shims/intrinsics/mod.rs b/src/shims/intrinsics/mod.rs index 6b311707c35d8..a930c4a967549 100644 --- a/src/shims/intrinsics/mod.rs +++ b/src/shims/intrinsics/mod.rs @@ -226,8 +226,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx }; let float_finite = |x: &ImmTy<'tcx, _>| -> InterpResult<'tcx, bool> { Ok(match x.layout.ty.kind() { - ty::Float(FloatTy::F32) => x.to_scalar()?.to_f32()?.is_finite(), - ty::Float(FloatTy::F64) => x.to_scalar()?.to_f64()?.is_finite(), + ty::Float(FloatTy::F32) => x.to_scalar().to_f32()?.is_finite(), + ty::Float(FloatTy::F64) => x.to_scalar().to_f64()?.is_finite(), _ => bug!( "`{intrinsic_name}` called with non-float input type {ty:?}", ty = x.layout.ty, @@ -345,9 +345,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let res = match val.layout.ty.kind() { ty::Float(FloatTy::F32) => - this.float_to_int_unchecked(val.to_scalar()?.to_f32()?, dest.layout.ty)?, + this.float_to_int_unchecked(val.to_scalar().to_f32()?, dest.layout.ty)?, ty::Float(FloatTy::F64) => - this.float_to_int_unchecked(val.to_scalar()?.to_f64()?, dest.layout.ty)?, + this.float_to_int_unchecked(val.to_scalar().to_f64()?, dest.layout.ty)?, _ => span_bug!( this.cur_span(), diff --git a/src/shims/intrinsics/simd.rs b/src/shims/intrinsics/simd.rs index 1b7ec5913506e..95763e1e832f3 100644 --- a/src/shims/intrinsics/simd.rs +++ b/src/shims/intrinsics/simd.rs @@ -60,13 +60,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let op = this.read_immediate(&this.mplace_index(&op, i)?.into())?; let dest = this.mplace_index(&dest, i)?; let val = match which { - Op::MirOp(mir_op) => this.unary_op(mir_op, &op)?.to_scalar()?, + Op::MirOp(mir_op) => this.unary_op(mir_op, &op)?.to_scalar(), Op::Abs => { // Works for f32 and f64. let ty::Float(float_ty) = op.layout.ty.kind() else { span_bug!(this.cur_span(), "{} operand is not a float", intrinsic_name) }; - let op = op.to_scalar()?; + let op = op.to_scalar(); match float_ty { FloatTy::F32 => Scalar::from_f32(op.to_f32()?.abs()), FloatTy::F64 => Scalar::from_f64(op.to_f64()?.abs()), @@ -79,7 +79,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // FIXME using host floats match float_ty { FloatTy::F32 => { - let f = f32::from_bits(op.to_scalar()?.to_u32()?); + let f = f32::from_bits(op.to_scalar().to_u32()?); let res = match host_op { HostFloatOp::Ceil => f.ceil(), HostFloatOp::Floor => f.floor(), @@ -90,7 +90,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Scalar::from_u32(res.to_bits()) } FloatTy::F64 => { - let f = f64::from_bits(op.to_scalar()?.to_u64()?); + let f = f64::from_bits(op.to_scalar().to_u64()?); let res = match host_op { HostFloatOp::Ceil => f.ceil(), HostFloatOp::Floor => f.floor(), @@ -182,7 +182,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Shifts have extra UB as SIMD operations that the MIR binop does not have. // See . if overflowed { - let r_val = right.to_scalar()?.to_bits(right.layout.size)?; + let r_val = right.to_scalar().to_bits(right.layout.size)?; throw_ub_format!("overflowing shift by {r_val} in `simd_{intrinsic_name}` in SIMD lane {i}"); } } @@ -201,8 +201,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.saturating_arith(mir_op, &left, &right)? } Op::WrappingOffset => { - let ptr = left.to_scalar()?.to_pointer(this)?; - let offset_count = right.to_scalar()?.to_machine_isize(this)?; + let ptr = left.to_scalar().to_pointer(this)?; + let offset_count = right.to_scalar().to_machine_isize(this)?; let pointee_ty = left.layout.ty.builtin_deref(true).unwrap().ty; let pointee_size = i64::try_from(this.layout_of(pointee_ty)?.size.bytes()).unwrap(); @@ -232,9 +232,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx assert_eq!(dest_len, c_len); for i in 0..dest_len { - let a = this.read_immediate(&this.mplace_index(&a, i)?.into())?.to_scalar()?; - let b = this.read_immediate(&this.mplace_index(&b, i)?.into())?.to_scalar()?; - let c = this.read_immediate(&this.mplace_index(&c, i)?.into())?.to_scalar()?; + let a = this.read_scalar(&this.mplace_index(&a, i)?.into())?; + let b = this.read_scalar(&this.mplace_index(&b, i)?.into())?; + let c = this.read_scalar(&this.mplace_index(&c, i)?.into())?; let dest = this.mplace_index(&dest, i)?; // Works for f32 and f64. @@ -315,7 +315,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ImmTy::from_scalar(fmax_op(&res, &op)?, res.layout) } else { // Just boring integers, so NaNs to worry about - if this.binary_op(BinOp::Ge, &res, &op)?.to_scalar()?.to_bool()? { + if this.binary_op(BinOp::Ge, &res, &op)?.to_scalar().to_bool()? { res } else { op @@ -327,7 +327,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ImmTy::from_scalar(fmin_op(&res, &op)?, res.layout) } else { // Just boring integers, so NaNs to worry about - if this.binary_op(BinOp::Le, &res, &op)?.to_scalar()?.to_bool()? { + if this.binary_op(BinOp::Le, &res, &op)?.to_scalar().to_bool()? { res } else { op @@ -398,7 +398,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let mask: u64 = this .read_scalar(mask)? - .check_init()? .to_bits(mask.layout.size)? .try_into() .unwrap(); @@ -450,9 +449,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.misc_cast(&op, dest.layout.ty)?, // Float-to-int in unchecked mode (ty::Float(FloatTy::F32), ty::Int(_) | ty::Uint(_)) if !safe_cast => - this.float_to_int_unchecked(op.to_scalar()?.to_f32()?, dest.layout.ty)?.into(), + this.float_to_int_unchecked(op.to_scalar().to_f32()?, dest.layout.ty)?.into(), (ty::Float(FloatTy::F64), ty::Int(_) | ty::Uint(_)) if !safe_cast => - this.float_to_int_unchecked(op.to_scalar()?.to_f64()?, dest.layout.ty)?.into(), + this.float_to_int_unchecked(op.to_scalar().to_f64()?, dest.layout.ty)?.into(), _ => throw_unsup_format!( "Unsupported SIMD cast from element type {from_ty} to {to_ty}", @@ -481,7 +480,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx for i in 0..dest_len { let src_index: u64 = this .read_immediate(&this.operand_index(index, i)?)? - .to_scalar()? + .to_scalar() .to_u32()? .into(); let dest = this.mplace_index(&dest, i)?; @@ -581,7 +580,7 @@ fn bool_to_simd_element(b: bool, size: Size) -> Scalar { } fn simd_element_to_bool(elem: ImmTy<'_, Provenance>) -> InterpResult<'_, bool> { - let val = elem.to_scalar()?.to_int(elem.layout.size)?; + let val = elem.to_scalar().to_int(elem.layout.size)?; Ok(match val { 0 => false, -1 => true, @@ -606,8 +605,8 @@ fn fmax_op<'tcx>( let ty::Float(float_ty) = left.layout.ty.kind() else { bug!("fmax operand is not a float") }; - let left = left.to_scalar()?; - let right = right.to_scalar()?; + let left = left.to_scalar(); + let right = right.to_scalar(); Ok(match float_ty { FloatTy::F32 => Scalar::from_f32(left.to_f32()?.max(right.to_f32()?)), FloatTy::F64 => Scalar::from_f64(left.to_f64()?.max(right.to_f64()?)), @@ -622,8 +621,8 @@ fn fmin_op<'tcx>( let ty::Float(float_ty) = left.layout.ty.kind() else { bug!("fmin operand is not a float") }; - let left = left.to_scalar()?; - let right = right.to_scalar()?; + let left = left.to_scalar(); + let right = right.to_scalar(); Ok(match float_ty { FloatTy::F32 => Scalar::from_f32(left.to_f32()?.min(right.to_f32()?)), FloatTy::F64 => Scalar::from_f64(left.to_f64()?.min(right.to_f64()?)), diff --git a/src/shims/panic.rs b/src/shims/panic.rs index 687c84308a97c..3784dabfeac24 100644 --- a/src/shims/panic.rs +++ b/src/shims/panic.rs @@ -52,7 +52,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Get the raw pointer stored in arg[0] (the panic payload). let [payload] = this.check_shim(abi, Abi::Rust, link_name, args)?; - let payload = this.read_scalar(payload)?.check_init()?; + let payload = this.read_scalar(payload)?; let thread = this.active_thread_mut(); assert!(thread.panic_payload.is_none(), "the panic runtime should avoid double-panics"); thread.panic_payload = Some(payload); @@ -85,7 +85,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Get all the arguments. let [try_fn, data, catch_fn] = check_arg_count(args)?; let try_fn = this.read_pointer(try_fn)?; - let data = this.read_scalar(data)?.check_init()?; + let data = this.read_scalar(data)?; let catch_fn = this.read_pointer(catch_fn)?; // Now we make a function call, and pass `data` as first and only argument. diff --git a/src/shims/unix/foreign_items.rs b/src/shims/unix/foreign_items.rs index 49bff7c17ea44..09604e178e244 100644 --- a/src/shims/unix/foreign_items.rs +++ b/src/shims/unix/foreign_items.rs @@ -283,24 +283,24 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "pthread_key_delete" => { let [key] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; - let key = this.read_scalar(key)?.check_init()?.to_bits(key.layout.size)?; + let key = this.read_scalar(key)?.to_bits(key.layout.size)?; this.machine.tls.delete_tls_key(key)?; // Return success (0) this.write_null(dest)?; } "pthread_getspecific" => { let [key] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; - let key = this.read_scalar(key)?.check_init()?.to_bits(key.layout.size)?; + let key = this.read_scalar(key)?.to_bits(key.layout.size)?; let active_thread = this.get_active_thread(); let ptr = this.machine.tls.load_tls(key, active_thread, this)?; this.write_scalar(ptr, dest)?; } "pthread_setspecific" => { let [key, new_ptr] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; - let key = this.read_scalar(key)?.check_init()?.to_bits(key.layout.size)?; + let key = this.read_scalar(key)?.to_bits(key.layout.size)?; let active_thread = this.get_active_thread(); let new_data = this.read_scalar(new_ptr)?; - this.machine.tls.store_tls(key, active_thread, new_data.check_init()?, &*this.tcx)?; + this.machine.tls.store_tls(key, active_thread, new_data, &*this.tcx)?; // Return success (`0`). this.write_null(dest)?; @@ -465,7 +465,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } "strerror_r" | "__xpg_strerror_r" => { let [errnum, buf, buflen] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; - let errnum = this.read_scalar(errnum)?.check_init()?; + let errnum = this.read_scalar(errnum)?; let buf = this.read_pointer(buf)?; let buflen = this.read_scalar(buflen)?.to_machine_usize(this)?; diff --git a/src/shims/unix/freebsd/foreign_items.rs b/src/shims/unix/freebsd/foreign_items.rs index 92e76ff09dcb5..ec565aa3150e0 100644 --- a/src/shims/unix/freebsd/foreign_items.rs +++ b/src/shims/unix/freebsd/foreign_items.rs @@ -37,7 +37,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "__error" => { let [] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let errno_place = this.last_error_place()?; - this.write_scalar(errno_place.to_ref(this).to_scalar()?, dest)?; + this.write_scalar(errno_place.to_ref(this).to_scalar(), dest)?; } _ => return Ok(EmulateByNameResult::NotSupported), diff --git a/src/shims/unix/linux/foreign_items.rs b/src/shims/unix/linux/foreign_items.rs index 1e007db1e9329..3c042740b5061 100644 --- a/src/shims/unix/linux/foreign_items.rs +++ b/src/shims/unix/linux/foreign_items.rs @@ -26,7 +26,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "__errno_location" => { let [] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let errno_place = this.last_error_place()?; - this.write_scalar(errno_place.to_ref(this).to_scalar()?, dest)?; + this.write_scalar(errno_place.to_ref(this).to_scalar(), dest)?; } // File related shims (but also see "syscall" below for statx) diff --git a/src/shims/unix/linux/sync.rs b/src/shims/unix/linux/sync.rs index 73a042d45b8fd..a3f3a28dbc21d 100644 --- a/src/shims/unix/linux/sync.rs +++ b/src/shims/unix/linux/sync.rs @@ -33,7 +33,7 @@ pub fn futex<'tcx>( let val = this.read_scalar(&args[2])?.to_i32()?; let thread = this.get_active_thread(); - let addr_scalar = addr.to_scalar()?; + let addr_scalar = addr.to_scalar(); let addr_usize = addr_scalar.to_machine_usize(this)?; let futex_private = this.eval_libc_i32("FUTEX_PRIVATE_FLAG")?; diff --git a/src/shims/unix/macos/foreign_items.rs b/src/shims/unix/macos/foreign_items.rs index be789648e78dc..fa4001bab187e 100644 --- a/src/shims/unix/macos/foreign_items.rs +++ b/src/shims/unix/macos/foreign_items.rs @@ -24,7 +24,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "__error" => { let [] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let errno_place = this.last_error_place()?; - this.write_scalar(errno_place.to_ref(this).to_scalar()?, dest)?; + this.write_scalar(errno_place.to_ref(this).to_scalar(), dest)?; } // File related shims @@ -153,7 +153,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let dtor = this.read_pointer(dtor)?; let dtor = this.get_ptr_fn(dtor)?.as_instance()?; - let data = this.read_scalar(data)?.check_init()?; + let data = this.read_scalar(data)?; let active_thread = this.get_active_thread(); this.machine.tls.set_macos_thread_dtor(active_thread, dtor, data)?; } @@ -185,7 +185,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // This is a horrible hack, but since the guard page mechanism calls mmap and expects a particular return value, we just give it that value. let [addr, _, _, _, _, _] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; - let addr = this.read_scalar(addr)?.check_init()?; + let addr = this.read_scalar(addr)?; this.write_scalar(addr, dest)?; } diff --git a/src/shims/unix/sync.rs b/src/shims/unix/sync.rs index b8504fb08d48f..88c5d2e3f81eb 100644 --- a/src/shims/unix/sync.rs +++ b/src/shims/unix/sync.rs @@ -38,14 +38,14 @@ fn is_mutex_kind_normal<'mir, 'tcx: 'mir>( fn mutexattr_get_kind<'mir, 'tcx: 'mir>( ecx: &MiriEvalContext<'mir, 'tcx>, attr_op: &OpTy<'tcx, Provenance>, -) -> InterpResult<'tcx, ScalarMaybeUninit> { +) -> InterpResult<'tcx, Scalar> { ecx.read_scalar_at_offset(attr_op, 0, ecx.machine.layouts.i32) } fn mutexattr_set_kind<'mir, 'tcx: 'mir>( ecx: &mut MiriEvalContext<'mir, 'tcx>, attr_op: &OpTy<'tcx, Provenance>, - kind: impl Into>, + kind: impl Into>, ) -> InterpResult<'tcx, ()> { ecx.write_scalar_at_offset(attr_op, 0, kind, layout_of_maybe_uninit(ecx.tcx, ecx.tcx.types.i32)) } @@ -62,7 +62,7 @@ fn mutexattr_set_kind<'mir, 'tcx: 'mir>( fn mutex_get_kind<'mir, 'tcx: 'mir>( ecx: &MiriEvalContext<'mir, 'tcx>, mutex_op: &OpTy<'tcx, Provenance>, -) -> InterpResult<'tcx, ScalarMaybeUninit> { +) -> InterpResult<'tcx, Scalar> { let offset = if ecx.pointer_size().bytes() == 8 { 16 } else { 12 }; ecx.read_scalar_at_offset_atomic( mutex_op, @@ -75,7 +75,7 @@ fn mutex_get_kind<'mir, 'tcx: 'mir>( fn mutex_set_kind<'mir, 'tcx: 'mir>( ecx: &mut MiriEvalContext<'mir, 'tcx>, mutex_op: &OpTy<'tcx, Provenance>, - kind: impl Into>, + kind: impl Into>, ) -> InterpResult<'tcx, ()> { let offset = if ecx.pointer_size().bytes() == 8 { 16 } else { 12 }; ecx.write_scalar_at_offset_atomic( @@ -90,14 +90,14 @@ fn mutex_set_kind<'mir, 'tcx: 'mir>( fn mutex_get_id<'mir, 'tcx: 'mir>( ecx: &MiriEvalContext<'mir, 'tcx>, mutex_op: &OpTy<'tcx, Provenance>, -) -> InterpResult<'tcx, ScalarMaybeUninit> { +) -> InterpResult<'tcx, Scalar> { ecx.read_scalar_at_offset_atomic(mutex_op, 4, ecx.machine.layouts.u32, AtomicReadOrd::Relaxed) } fn mutex_set_id<'mir, 'tcx: 'mir>( ecx: &mut MiriEvalContext<'mir, 'tcx>, mutex_op: &OpTy<'tcx, Provenance>, - id: impl Into>, + id: impl Into>, ) -> InterpResult<'tcx, ()> { ecx.write_scalar_at_offset_atomic( mutex_op, @@ -124,8 +124,7 @@ fn mutex_get_or_create_id<'mir, 'tcx: 'mir>( AtomicReadOrd::Relaxed, false, )? - .to_scalar_pair() - .expect("compare_exchange returns a scalar pair"); + .to_scalar_pair(); Ok(if success.to_bool().expect("compare_exchange's second return value is a bool") { // Caller of the closure needs to allocate next_id @@ -146,24 +145,10 @@ fn mutex_get_or_create_id<'mir, 'tcx: 'mir>( fn rwlock_get_id<'mir, 'tcx: 'mir>( ecx: &MiriEvalContext<'mir, 'tcx>, rwlock_op: &OpTy<'tcx, Provenance>, -) -> InterpResult<'tcx, ScalarMaybeUninit> { +) -> InterpResult<'tcx, Scalar> { ecx.read_scalar_at_offset_atomic(rwlock_op, 4, ecx.machine.layouts.u32, AtomicReadOrd::Relaxed) } -fn rwlock_set_id<'mir, 'tcx: 'mir>( - ecx: &mut MiriEvalContext<'mir, 'tcx>, - rwlock_op: &OpTy<'tcx, Provenance>, - id: impl Into>, -) -> InterpResult<'tcx, ()> { - ecx.write_scalar_at_offset_atomic( - rwlock_op, - 4, - id, - layout_of_maybe_uninit(ecx.tcx, ecx.tcx.types.u32), - AtomicWriteOrd::Relaxed, - ) -} - fn rwlock_get_or_create_id<'mir, 'tcx: 'mir>( ecx: &mut MiriEvalContext<'mir, 'tcx>, rwlock_op: &OpTy<'tcx, Provenance>, @@ -180,8 +165,7 @@ fn rwlock_get_or_create_id<'mir, 'tcx: 'mir>( AtomicReadOrd::Relaxed, false, )? - .to_scalar_pair() - .expect("compare_exchange returns a scalar pair"); + .to_scalar_pair(); Ok(if success.to_bool().expect("compare_exchange's second return value is a bool") { // Caller of the closure needs to allocate next_id @@ -201,14 +185,14 @@ fn rwlock_get_or_create_id<'mir, 'tcx: 'mir>( fn condattr_get_clock_id<'mir, 'tcx: 'mir>( ecx: &MiriEvalContext<'mir, 'tcx>, attr_op: &OpTy<'tcx, Provenance>, -) -> InterpResult<'tcx, ScalarMaybeUninit> { +) -> InterpResult<'tcx, Scalar> { ecx.read_scalar_at_offset(attr_op, 0, ecx.machine.layouts.i32) } fn condattr_set_clock_id<'mir, 'tcx: 'mir>( ecx: &mut MiriEvalContext<'mir, 'tcx>, attr_op: &OpTy<'tcx, Provenance>, - clock_id: impl Into>, + clock_id: impl Into>, ) -> InterpResult<'tcx, ()> { ecx.write_scalar_at_offset( attr_op, @@ -230,14 +214,14 @@ fn condattr_set_clock_id<'mir, 'tcx: 'mir>( fn cond_get_id<'mir, 'tcx: 'mir>( ecx: &MiriEvalContext<'mir, 'tcx>, cond_op: &OpTy<'tcx, Provenance>, -) -> InterpResult<'tcx, ScalarMaybeUninit> { +) -> InterpResult<'tcx, Scalar> { ecx.read_scalar_at_offset_atomic(cond_op, 4, ecx.machine.layouts.u32, AtomicReadOrd::Relaxed) } fn cond_set_id<'mir, 'tcx: 'mir>( ecx: &mut MiriEvalContext<'mir, 'tcx>, cond_op: &OpTy<'tcx, Provenance>, - id: impl Into>, + id: impl Into>, ) -> InterpResult<'tcx, ()> { ecx.write_scalar_at_offset_atomic( cond_op, @@ -264,8 +248,7 @@ fn cond_get_or_create_id<'mir, 'tcx: 'mir>( AtomicReadOrd::Relaxed, false, )? - .to_scalar_pair() - .expect("compare_exchange returns a scalar pair"); + .to_scalar_pair(); Ok(if success.to_bool().expect("compare_exchange's second return value is a bool") { // Caller of the closure needs to allocate next_id @@ -279,14 +262,14 @@ fn cond_get_or_create_id<'mir, 'tcx: 'mir>( fn cond_get_clock_id<'mir, 'tcx: 'mir>( ecx: &MiriEvalContext<'mir, 'tcx>, cond_op: &OpTy<'tcx, Provenance>, -) -> InterpResult<'tcx, ScalarMaybeUninit> { +) -> InterpResult<'tcx, Scalar> { ecx.read_scalar_at_offset(cond_op, 8, ecx.machine.layouts.i32) } fn cond_set_clock_id<'mir, 'tcx: 'mir>( ecx: &mut MiriEvalContext<'mir, 'tcx>, cond_op: &OpTy<'tcx, Provenance>, - clock_id: impl Into>, + clock_id: impl Into>, ) -> InterpResult<'tcx, ()> { ecx.write_scalar_at_offset( cond_op, @@ -366,7 +349,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - let kind = this.read_scalar(kind_op)?.check_init()?; + let kind = this.read_scalar(kind_op)?; if kind == this.eval_libc("PTHREAD_MUTEX_NORMAL")? { // In `glibc` implementation, the numeric values of // `PTHREAD_MUTEX_NORMAL` and `PTHREAD_MUTEX_DEFAULT` are equal. @@ -407,7 +390,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); // Destroying an uninit pthread_mutexattr is UB, so check to make sure it's not uninit. - mutexattr_get_kind(this, attr_op)?.check_init()?; + mutexattr_get_kind(this, attr_op)?; // To catch double-destroys, we de-initialize the mutexattr. // This is technically not right and might lead to false positives. For example, the below @@ -421,8 +404,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // However, the way libstd uses the pthread APIs works in our favor here, so we can get away with this. // This can always be revisited to have some external state to catch double-destroys // but not complain about the above code. See https://github.com/rust-lang/miri/pull/1933 - - mutexattr_set_kind(this, attr_op, ScalarMaybeUninit::Uninit)?; + this.write_uninit(&this.deref_operand(attr_op)?.into())?; Ok(0) } @@ -438,7 +420,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let kind = if this.ptr_is_null(attr)? { this.eval_libc("PTHREAD_MUTEX_DEFAULT")? } else { - mutexattr_get_kind(this, attr_op)?.check_init()? + mutexattr_get_kind(this, attr_op)? }; // Write 0 to use the same code path as the static initializers. @@ -452,7 +434,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn pthread_mutex_lock(&mut self, mutex_op: &OpTy<'tcx, Provenance>) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - let kind = mutex_get_kind(this, mutex_op)?.check_init()?; + let kind = mutex_get_kind(this, mutex_op)?; let id = mutex_get_or_create_id(this, mutex_op)?; let active_thread = this.get_active_thread(); @@ -492,7 +474,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - let kind = mutex_get_kind(this, mutex_op)?.check_init()?; + let kind = mutex_get_kind(this, mutex_op)?; let id = mutex_get_or_create_id(this, mutex_op)?; let active_thread = this.get_active_thread(); @@ -528,7 +510,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, i32> { let this = self.eval_context_mut(); - let kind = mutex_get_kind(this, mutex_op)?.check_init()?; + let kind = mutex_get_kind(this, mutex_op)?; let id = mutex_get_or_create_id(this, mutex_op)?; let active_thread = this.get_active_thread(); @@ -570,12 +552,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // Destroying an uninit pthread_mutex is UB, so check to make sure it's not uninit. - mutex_get_kind(this, mutex_op)?.check_init()?; - mutex_get_id(this, mutex_op)?.check_init()?; + mutex_get_kind(this, mutex_op)?; + mutex_get_id(this, mutex_op)?; // This might lead to false positives, see comment in pthread_mutexattr_destroy - mutex_set_kind(this, mutex_op, ScalarMaybeUninit::Uninit)?; - mutex_set_id(this, mutex_op, ScalarMaybeUninit::Uninit)?; + this.write_uninit(&this.deref_operand(mutex_op)?.into())?; // FIXME: delete interpreter state associated with this mutex. Ok(0) @@ -695,10 +676,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // Destroying an uninit pthread_rwlock is UB, so check to make sure it's not uninit. - rwlock_get_id(this, rwlock_op)?.check_init()?; + rwlock_get_id(this, rwlock_op)?; // This might lead to false positives, see comment in pthread_mutexattr_destroy - rwlock_set_id(this, rwlock_op, ScalarMaybeUninit::Uninit)?; + this.write_uninit(&this.deref_operand(rwlock_op)?.into())?; // FIXME: delete interpreter state associated with this rwlock. Ok(0) @@ -726,7 +707,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, Scalar> { let this = self.eval_context_mut(); - let clock_id = this.read_scalar(clock_id_op)?.check_init()?; + let clock_id = this.read_scalar(clock_id_op)?; if clock_id == this.eval_libc("CLOCK_REALTIME")? || clock_id == this.eval_libc("CLOCK_MONOTONIC")? { @@ -759,10 +740,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); // Destroying an uninit pthread_condattr is UB, so check to make sure it's not uninit. - condattr_get_clock_id(this, attr_op)?.check_init()?; + condattr_get_clock_id(this, attr_op)?; // This might lead to false positives, see comment in pthread_mutexattr_destroy - condattr_set_clock_id(this, attr_op, ScalarMaybeUninit::Uninit)?; + this.write_uninit(&this.deref_operand(attr_op)?.into())?; Ok(0) } @@ -778,7 +759,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let clock_id = if this.ptr_is_null(attr)? { this.eval_libc("CLOCK_REALTIME")? } else { - condattr_get_clock_id(this, attr_op)?.check_init()? + condattr_get_clock_id(this, attr_op)? }; // Write 0 to use the same code path as the static initializers. @@ -906,12 +887,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // Destroying an uninit pthread_cond is UB, so check to make sure it's not uninit. - cond_get_id(this, cond_op)?.check_init()?; - cond_get_clock_id(this, cond_op)?.check_init()?; + cond_get_id(this, cond_op)?; + cond_get_clock_id(this, cond_op)?; // This might lead to false positives, see comment in pthread_mutexattr_destroy - cond_set_id(this, cond_op, ScalarMaybeUninit::Uninit)?; - cond_set_clock_id(this, cond_op, ScalarMaybeUninit::Uninit)?; + this.write_uninit(&this.deref_operand(cond_op)?.into())?; // FIXME: delete interpreter state associated with this condvar. Ok(0) diff --git a/src/shims/windows/foreign_items.rs b/src/shims/windows/foreign_items.rs index c6536d1d094ca..9b8f32b0ab60d 100644 --- a/src/shims/windows/foreign_items.rs +++ b/src/shims/windows/foreign_items.rs @@ -104,7 +104,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "SetLastError" => { let [error] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; - let error = this.read_scalar(error)?.check_init()?; + let error = this.read_scalar(error)?; this.set_last_error(error)?; } "GetLastError" => { @@ -187,7 +187,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; let key = u128::from(this.read_scalar(key)?.to_u32()?); let active_thread = this.get_active_thread(); - let new_data = this.read_scalar(new_ptr)?.check_init()?; + let new_data = this.read_scalar(new_ptr)?; this.machine.tls.store_tls(key, active_thread, new_data, &*this.tcx)?; // Return success (`1`). diff --git a/src/shims/windows/sync.rs b/src/shims/windows/sync.rs index 878b9b94a639c..e998b68a421f6 100644 --- a/src/shims/windows/sync.rs +++ b/src/shims/windows/sync.rs @@ -19,8 +19,7 @@ fn srwlock_get_or_create_id<'mir, 'tcx: 'mir>( AtomicReadOrd::Relaxed, false, )? - .to_scalar_pair() - .expect("compare_exchange returns a scalar pair"); + .to_scalar_pair(); Ok(if success.to_bool().expect("compare_exchange's second return value is a bool") { // Caller of the closure needs to allocate next_id diff --git a/tests/fail/invalid_int.rs b/tests/fail/invalid_int.rs index 4f76f8b6d9488..b51af24c134b2 100644 --- a/tests/fail/invalid_int.rs +++ b/tests/fail/invalid_int.rs @@ -3,6 +3,6 @@ //@compile-flags: -Zmiri-disable-alignment-check -Zmiri-disable-stacked-borrows -Zmiri-disable-validation fn main() { - let i = unsafe { std::mem::MaybeUninit::::uninit().assume_init() }; - let _x = i + 0; //~ ERROR: this operation requires initialized memory + let i = unsafe { std::mem::MaybeUninit::::uninit().assume_init() }; //~ ERROR: uninitialized + let _x = i + 0; } diff --git a/tests/fail/invalid_int.stderr b/tests/fail/invalid_int.stderr index 85aa3fb5a08bc..471c0a7b10f81 100644 --- a/tests/fail/invalid_int.stderr +++ b/tests/fail/invalid_int.stderr @@ -1,8 +1,8 @@ error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory --> $DIR/invalid_int.rs:LL:CC | -LL | let _x = i + 0; - | ^^^^^ using uninitialized data, but this operation requires initialized memory +LL | let i = unsafe { std::mem::MaybeUninit::::uninit().assume_init() }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/transmute-pair-uninit.stderr b/tests/fail/transmute-pair-uninit.stderr index ac6bf8243eee3..a8e0bdd05b6d7 100644 --- a/tests/fail/transmute-pair-uninit.stderr +++ b/tests/fail/transmute-pair-uninit.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: constructing invalid value: encountered uninitialized bytes, but expected initialized bytes +error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory --> $DIR/transmute-pair-uninit.rs:LL:CC | LL | let v = unsafe { *z.offset(first_undef) }; - | ^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered uninitialized bytes, but expected initialized bytes + | ^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/uninit_byte_read.stderr b/tests/fail/uninit_byte_read.stderr index 174d0d2416e3d..432710b04f869 100644 --- a/tests/fail/uninit_byte_read.stderr +++ b/tests/fail/uninit_byte_read.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: constructing invalid value: encountered uninitialized bytes, but expected initialized bytes +error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory --> $DIR/uninit_byte_read.rs:LL:CC | LL | let undef = unsafe { *v.get_unchecked(5) }; - | ^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered uninitialized bytes, but expected initialized bytes + | ^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/validity/invalid_bool_uninit.rs b/tests/fail/validity/invalid_bool_uninit.rs index f90fae3ab92cf..84a221a469a7a 100644 --- a/tests/fail/validity/invalid_bool_uninit.rs +++ b/tests/fail/validity/invalid_bool_uninit.rs @@ -6,5 +6,5 @@ union MyUninit { } fn main() { - let _b = unsafe { MyUninit { init: () }.uninit }; //~ ERROR: encountered uninitialized bytes, but expected a boolean + let _b = unsafe { MyUninit { init: () }.uninit }; //~ ERROR: uninitialized } diff --git a/tests/fail/validity/invalid_bool_uninit.stderr b/tests/fail/validity/invalid_bool_uninit.stderr index a4f2d844fd265..3d90a45d831cf 100644 --- a/tests/fail/validity/invalid_bool_uninit.stderr +++ b/tests/fail/validity/invalid_bool_uninit.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: constructing invalid value: encountered uninitialized bytes, but expected a boolean +error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory --> $DIR/invalid_bool_uninit.rs:LL:CC | LL | let _b = unsafe { MyUninit { init: () }.uninit }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered uninitialized bytes, but expected a boolean + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/validity/invalid_char_uninit.rs b/tests/fail/validity/invalid_char_uninit.rs index cb82ce7463766..c16e26649076a 100644 --- a/tests/fail/validity/invalid_char_uninit.rs +++ b/tests/fail/validity/invalid_char_uninit.rs @@ -6,5 +6,5 @@ union MyUninit { } fn main() { - let _b = unsafe { MyUninit { init: () }.uninit }; //~ ERROR: encountered uninitialized bytes, but expected a valid unicode scalar value + let _b = unsafe { MyUninit { init: () }.uninit }; //~ ERROR: uninitialized } diff --git a/tests/fail/validity/invalid_char_uninit.stderr b/tests/fail/validity/invalid_char_uninit.stderr index 10dff84238680..0512f90a90a47 100644 --- a/tests/fail/validity/invalid_char_uninit.stderr +++ b/tests/fail/validity/invalid_char_uninit.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: constructing invalid value: encountered uninitialized bytes, but expected a valid unicode scalar value (in `0..=$HEX` but not in `$HEX..=$HEX`) +error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory --> $DIR/invalid_char_uninit.rs:LL:CC | LL | let _b = unsafe { MyUninit { init: () }.uninit }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered uninitialized bytes, but expected a valid unicode scalar value (in `0..=$HEX` but not in `$HEX..=$HEX`) + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/validity/invalid_fnptr_uninit.rs b/tests/fail/validity/invalid_fnptr_uninit.rs index 26f958bd64fec..c857d83bde0db 100644 --- a/tests/fail/validity/invalid_fnptr_uninit.rs +++ b/tests/fail/validity/invalid_fnptr_uninit.rs @@ -6,5 +6,5 @@ union MyUninit { } fn main() { - let _b = unsafe { MyUninit { init: () }.uninit }; //~ ERROR: encountered uninitialized bytes + let _b = unsafe { MyUninit { init: () }.uninit }; //~ ERROR: uninitialized } diff --git a/tests/fail/validity/invalid_fnptr_uninit.stderr b/tests/fail/validity/invalid_fnptr_uninit.stderr index 55307f6b98d11..f5de8101709d1 100644 --- a/tests/fail/validity/invalid_fnptr_uninit.stderr +++ b/tests/fail/validity/invalid_fnptr_uninit.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: constructing invalid value: encountered uninitialized bytes, but expected a proper pointer or integer value +error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory --> $DIR/invalid_fnptr_uninit.rs:LL:CC | LL | let _b = unsafe { MyUninit { init: () }.uninit }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered uninitialized bytes, but expected a proper pointer or integer value + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/validity/uninit_float.rs b/tests/fail/validity/uninit_float.rs index 0f4a22cf5b77d..fecc02d7a505f 100644 --- a/tests/fail/validity/uninit_float.rs +++ b/tests/fail/validity/uninit_float.rs @@ -4,5 +4,5 @@ fn main() { // Deliberately using `mem::uninitialized` to make sure that despite all the mitigations, we consider this UB. let _val: f32 = unsafe { std::mem::uninitialized() }; - //~^ ERROR: constructing invalid value at .value: encountered uninitialized bytes, but expected initialized bytes + //~^ ERROR: uninitialized } diff --git a/tests/fail/validity/uninit_float.stderr b/tests/fail/validity/uninit_float.stderr index d9611af79eebf..8a677202c8ebf 100644 --- a/tests/fail/validity/uninit_float.stderr +++ b/tests/fail/validity/uninit_float.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: constructing invalid value at .value: encountered uninitialized bytes, but expected initialized bytes +error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory --> $DIR/uninit_float.rs:LL:CC | LL | let _val: f32 = unsafe { std::mem::uninitialized() }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .value: encountered uninitialized bytes, but expected initialized bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/validity/uninit_integer.rs b/tests/fail/validity/uninit_integer.rs index 0a1253b5b96b0..a9b200732653d 100644 --- a/tests/fail/validity/uninit_integer.rs +++ b/tests/fail/validity/uninit_integer.rs @@ -2,5 +2,5 @@ fn main() { let _val = unsafe { std::mem::MaybeUninit::::uninit().assume_init() }; - //~^ ERROR: constructing invalid value at .value: encountered uninitialized bytes, but expected initialized bytes + //~^ ERROR: uninitialized } diff --git a/tests/fail/validity/uninit_integer.stderr b/tests/fail/validity/uninit_integer.stderr index c461fc5afaa31..60bf2c7366771 100644 --- a/tests/fail/validity/uninit_integer.stderr +++ b/tests/fail/validity/uninit_integer.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: constructing invalid value at .value: encountered uninitialized bytes, but expected initialized bytes +error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory --> $DIR/uninit_integer.rs:LL:CC | LL | let _val = unsafe { std::mem::MaybeUninit::::uninit().assume_init() }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .value: encountered uninitialized bytes, but expected initialized bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/uninit_raw_ptr.rs b/tests/fail/validity/uninit_raw_ptr.rs similarity index 52% rename from tests/fail/uninit_raw_ptr.rs rename to tests/fail/validity/uninit_raw_ptr.rs index e5a34f4a261c4..9f99dc1a0e11c 100644 --- a/tests/fail/uninit_raw_ptr.rs +++ b/tests/fail/validity/uninit_raw_ptr.rs @@ -1,4 +1,4 @@ fn main() { let _val = unsafe { std::mem::MaybeUninit::<*const u8>::uninit().assume_init() }; - //~^ ERROR: constructing invalid value at .value: encountered uninitialized raw pointer + //~^ ERROR: uninitialized } diff --git a/tests/fail/uninit_raw_ptr.stderr b/tests/fail/validity/uninit_raw_ptr.stderr similarity index 76% rename from tests/fail/uninit_raw_ptr.stderr rename to tests/fail/validity/uninit_raw_ptr.stderr index 7241cf04ae4a1..efa444229270c 100644 --- a/tests/fail/uninit_raw_ptr.stderr +++ b/tests/fail/validity/uninit_raw_ptr.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: constructing invalid value at .value: encountered uninitialized raw pointer +error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory --> $DIR/uninit_raw_ptr.rs:LL:CC | LL | let _val = unsafe { std::mem::MaybeUninit::<*const u8>::uninit().assume_init() }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .value: encountered uninitialized raw pointer + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/pass/issues/issue-miri-2068-2.rs b/tests/pass/issues/issue-miri-2068-2.rs deleted file mode 100644 index f33806e8b4433..0000000000000 --- a/tests/pass/issues/issue-miri-2068-2.rs +++ /dev/null @@ -1,16 +0,0 @@ -//@compile-flags: -Zmiri-disable-validation - -use std::mem::MaybeUninit; - -fn main() { - unsafe { - let mut x = MaybeUninit::::uninit(); - // Put in a ptr. - x.as_mut_ptr().cast::<&i32>().write_unaligned(&0); - // Overwrite parts of that pointer with 'uninit' through a Scalar. - let ptr = x.as_mut_ptr().cast::(); - *ptr = MaybeUninit::uninit().assume_init(); - // Reading this back should hence work fine. - let _c = *ptr; - } -} From df19b856cebdf14e9016efce4e186b038712ef0a Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 27 Aug 2022 08:51:41 -0400 Subject: [PATCH 3687/3747] rustup --- rust-version | 2 +- src/concurrency/data_race.rs | 19 +++---------------- src/concurrency/weak_memory.rs | 10 ++-------- src/shims/ffi_support.rs | 2 +- src/shims/intrinsics/simd.rs | 7 ++----- src/shims/os_str.rs | 3 +-- src/shims/unix/freebsd/foreign_items.rs | 6 ++---- src/shims/unix/linux/foreign_items.rs | 6 ++---- src/shims/unix/macos/foreign_items.rs | 2 +- src/shims/unix/sync.rs | 6 +++--- src/shims/windows/dlsym.rs | 2 +- src/shims/windows/handle.rs | 2 +- src/shims/windows/sync.rs | 2 +- src/shims/windows/thread.rs | 7 +------ 14 files changed, 22 insertions(+), 54 deletions(-) diff --git a/rust-version b/rust-version index e3e71f5c2fd26..9b8d986c67114 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -e1b28cd2f16bd5b832183d7968cae3bb9213e78d +4065b89b1e7287047d7d6c65e7abd7b8ee70bcf0 diff --git a/src/concurrency/data_race.rs b/src/concurrency/data_race.rs index 223fad40362a4..87f64db26d3ac 100644 --- a/src/concurrency/data_race.rs +++ b/src/concurrency/data_race.rs @@ -530,12 +530,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { this.validate_atomic_rmw(place, atomic)?; - this.buffered_atomic_rmw( - val.to_scalar(), - place, - atomic, - old.to_scalar(), - )?; + this.buffered_atomic_rmw(val.to_scalar(), place, atomic, old.to_scalar())?; Ok(old) } @@ -586,12 +581,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { this.validate_atomic_rmw(place, atomic)?; - this.buffered_atomic_rmw( - new_val.to_scalar(), - place, - atomic, - old.to_scalar(), - )?; + this.buffered_atomic_rmw(new_val.to_scalar(), place, atomic, old.to_scalar())?; // Return the old value. Ok(old) @@ -633,10 +623,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { } else { true }; - let res = Immediate::ScalarPair( - old.to_scalar(), - Scalar::from_bool(cmpxchg_success).into(), - ); + let res = Immediate::ScalarPair(old.to_scalar(), Scalar::from_bool(cmpxchg_success)); // Update ptr depending on comparison. // if successful, perform a full rw-atomic validation diff --git a/src/concurrency/weak_memory.rs b/src/concurrency/weak_memory.rs index bd43e848af732..5a5c2c211bc99 100644 --- a/src/concurrency/weak_memory.rs +++ b/src/concurrency/weak_memory.rs @@ -77,9 +77,7 @@ use std::{ collections::VecDeque, }; -use rustc_const_eval::interpret::{ - alloc_range, AllocRange, InterpResult, MPlaceTy, Scalar, -}; +use rustc_const_eval::interpret::{alloc_range, AllocRange, InterpResult, MPlaceTy, Scalar}; use rustc_data_structures::fx::FxHashMap; use crate::*; @@ -417,11 +415,7 @@ impl StoreElement { /// buffer regardless of subsequent loads by the same thread; if the earliest load of another /// thread doesn't happen before the current one, then no subsequent load by the other thread /// can happen before the current one. - fn load_impl( - &self, - index: VectorIdx, - clocks: &ThreadClockSet, - ) -> Scalar { + fn load_impl(&self, index: VectorIdx, clocks: &ThreadClockSet) -> Scalar { let _ = self.loads.borrow_mut().try_insert(index, clocks.clock[index]); self.val } diff --git a/src/shims/ffi_support.rs b/src/shims/ffi_support.rs index f1ae1e7d3f47f..844bcb40d5353 100644 --- a/src/shims/ffi_support.rs +++ b/src/shims/ffi_support.rs @@ -13,7 +13,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx /// Extract the scalar value from the result of reading a scalar from the machine, /// and convert it to a `CArg`. fn scalar_to_carg( - k: ScalarMaybeUninit, + k: Scalar, arg_type: Ty<'tcx>, cx: &impl HasDataLayout, ) -> InterpResult<'tcx, CArg> { diff --git a/src/shims/intrinsics/simd.rs b/src/shims/intrinsics/simd.rs index 95763e1e832f3..1698477cbde8f 100644 --- a/src/shims/intrinsics/simd.rs +++ b/src/shims/intrinsics/simd.rs @@ -396,11 +396,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let dest_len = u32::try_from(dest_len).unwrap(); let bitmask_len = u32::try_from(bitmask_len).unwrap(); - let mask: u64 = this - .read_scalar(mask)? - .to_bits(mask.layout.size)? - .try_into() - .unwrap(); + let mask: u64 = + this.read_scalar(mask)?.to_bits(mask.layout.size)?.try_into().unwrap(); for i in 0..dest_len { let mask = mask & 1u64 diff --git a/src/shims/os_str.rs b/src/shims/os_str.rs index fcf92dfc9f935..6ca09f3fcad13 100644 --- a/src/shims/os_str.rs +++ b/src/shims/os_str.rs @@ -156,8 +156,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx .unwrap(); // not a ZST, so we will get a result for (offset, wchar) in u16_vec.into_iter().chain(iter::once(0x0000)).enumerate() { let offset = u64::try_from(offset).unwrap(); - alloc - .write_scalar(alloc_range(size2 * offset, size2), Scalar::from_u16(wchar).into())?; + alloc.write_scalar(alloc_range(size2 * offset, size2), Scalar::from_u16(wchar))?; } Ok((true, string_length)) } diff --git a/src/shims/unix/freebsd/foreign_items.rs b/src/shims/unix/freebsd/foreign_items.rs index ec565aa3150e0..73464cdacb002 100644 --- a/src/shims/unix/freebsd/foreign_items.rs +++ b/src/shims/unix/freebsd/foreign_items.rs @@ -26,10 +26,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "pthread_set_name_np" => { let [thread, name] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; - let res = this.pthread_setname_np( - this.read_scalar(thread)?.check_init()?, - this.read_scalar(name)?.check_init()?, - )?; + let res = + this.pthread_setname_np(this.read_scalar(thread)?, this.read_scalar(name)?)?; this.write_scalar(res, dest)?; } diff --git a/src/shims/unix/linux/foreign_items.rs b/src/shims/unix/linux/foreign_items.rs index 3c042740b5061..afa0591a3c97f 100644 --- a/src/shims/unix/linux/foreign_items.rs +++ b/src/shims/unix/linux/foreign_items.rs @@ -68,10 +68,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "pthread_setname_np" => { let [thread, name] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; - let res = this.pthread_setname_np( - this.read_scalar(thread)?.check_init()?, - this.read_scalar(name)?.check_init()?, - )?; + let res = + this.pthread_setname_np(this.read_scalar(thread)?, this.read_scalar(name)?)?; this.write_scalar(res, dest)?; } diff --git a/src/shims/unix/macos/foreign_items.rs b/src/shims/unix/macos/foreign_items.rs index fa4001bab187e..9ad2ef47e094d 100644 --- a/src/shims/unix/macos/foreign_items.rs +++ b/src/shims/unix/macos/foreign_items.rs @@ -176,7 +176,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "pthread_setname_np" => { let [name] = this.check_shim(abi, Abi::C { unwind: false }, link_name, args)?; let thread = this.pthread_self()?; - this.pthread_setname_np(thread, this.read_scalar(name)?.check_init()?)?; + this.pthread_setname_np(thread, this.read_scalar(name)?)?; } // Incomplete shims that we "stub out" just to get pre-main initialization code to work. diff --git a/src/shims/unix/sync.rs b/src/shims/unix/sync.rs index 88c5d2e3f81eb..0a4904f4bac7e 100644 --- a/src/shims/unix/sync.rs +++ b/src/shims/unix/sync.rs @@ -119,7 +119,7 @@ fn mutex_get_or_create_id<'mir, 'tcx: 'mir>( .atomic_compare_exchange_scalar( &value_place, &ImmTy::from_uint(0u32, ecx.machine.layouts.u32), - next_id.to_u32_scalar().into(), + next_id.to_u32_scalar(), AtomicRwOrd::Relaxed, AtomicReadOrd::Relaxed, false, @@ -160,7 +160,7 @@ fn rwlock_get_or_create_id<'mir, 'tcx: 'mir>( .atomic_compare_exchange_scalar( &value_place, &ImmTy::from_uint(0u32, ecx.machine.layouts.u32), - next_id.to_u32_scalar().into(), + next_id.to_u32_scalar(), AtomicRwOrd::Relaxed, AtomicReadOrd::Relaxed, false, @@ -243,7 +243,7 @@ fn cond_get_or_create_id<'mir, 'tcx: 'mir>( .atomic_compare_exchange_scalar( &value_place, &ImmTy::from_uint(0u32, ecx.machine.layouts.u32), - next_id.to_u32_scalar().into(), + next_id.to_u32_scalar(), AtomicRwOrd::Relaxed, AtomicReadOrd::Relaxed, false, diff --git a/src/shims/windows/dlsym.rs b/src/shims/windows/dlsym.rs index d87ca8f818410..5cbfecb889a23 100644 --- a/src/shims/windows/dlsym.rs +++ b/src/shims/windows/dlsym.rs @@ -112,7 +112,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx Dlsym::SetThreadDescription => { let [handle, name] = check_arg_count(args)?; - let handle = this.read_scalar(handle)?.check_init()?; + let handle = this.read_scalar(handle)?; let name = this.read_wide_str(this.read_pointer(name)?)?; diff --git a/src/shims/windows/handle.rs b/src/shims/windows/handle.rs index 92e0a9a34e122..69a6bd38d09e8 100644 --- a/src/shims/windows/handle.rs +++ b/src/shims/windows/handle.rs @@ -158,7 +158,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx fn CloseHandle(&mut self, handle_op: &OpTy<'tcx, Provenance>) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - let handle = this.read_scalar(handle_op)?.check_init()?; + let handle = this.read_scalar(handle_op)?; match Handle::from_scalar(handle, this)? { Some(Handle::Thread(thread)) => diff --git a/src/shims/windows/sync.rs b/src/shims/windows/sync.rs index e998b68a421f6..60645ee7d9566 100644 --- a/src/shims/windows/sync.rs +++ b/src/shims/windows/sync.rs @@ -14,7 +14,7 @@ fn srwlock_get_or_create_id<'mir, 'tcx: 'mir>( .atomic_compare_exchange_scalar( &value_place, &ImmTy::from_uint(0u32, ecx.machine.layouts.u32), - next_id.to_u32_scalar().into(), + next_id.to_u32_scalar(), AtomicRwOrd::Relaxed, AtomicReadOrd::Relaxed, false, diff --git a/src/shims/windows/thread.rs b/src/shims/windows/thread.rs index 06a5887d3e509..2b801ae312033 100644 --- a/src/shims/windows/thread.rs +++ b/src/shims/windows/thread.rs @@ -20,14 +20,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let this = self.eval_context_mut(); let security = this.read_pointer(security_op)?; - // stacksize is ignored, but still needs to be a valid usize this.read_scalar(stacksize_op)?.to_machine_usize(this)?; - let start_routine = this.read_pointer(start_op)?; - let func_arg = this.read_immediate(arg_op)?; - let flags = this.read_scalar(flags_op)?.to_u32()?; let thread = if this.ptr_is_null(this.read_pointer(thread_op)?)? { @@ -66,8 +62,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx ) -> InterpResult<'tcx, u32> { let this = self.eval_context_mut(); - let handle = this.read_scalar(handle_op)?.check_init()?; - + let handle = this.read_scalar(handle_op)?; let timeout = this.read_scalar(timeout_op)?.to_u32()?; let thread = match Handle::from_scalar(handle, this)? { From f4ba8b1160477a99806d99cf461acf54bee70e92 Mon Sep 17 00:00:00 2001 From: Andy Wang Date: Thu, 25 Aug 2022 00:07:17 +0100 Subject: [PATCH 3688/3747] Improve SC comments --- src/concurrency/weak_memory.rs | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/src/concurrency/weak_memory.rs b/src/concurrency/weak_memory.rs index 5a5c2c211bc99..a5f59137c22cd 100644 --- a/src/concurrency/weak_memory.rs +++ b/src/concurrency/weak_memory.rs @@ -319,6 +319,7 @@ impl<'mir, 'tcx: 'mir> StoreBuffer { keep_searching = if store_elem.timestamp <= clocks.clock[store_elem.store_index] { // CoWR: if a store happens-before the current load, // then we can't read-from anything earlier in modification order. + // C++20 §6.9.2.2 [intro.races] paragraph 18 log::info!("Stopping due to coherent write-read"); false } else if store_elem.loads.borrow().iter().any(|(&load_index, &load_timestamp)| { @@ -326,24 +327,27 @@ impl<'mir, 'tcx: 'mir> StoreBuffer { }) { // CoRR: if there was a load from this store which happened-before the current load, // then we cannot read-from anything earlier in modification order. + // C++20 §6.9.2.2 [intro.races] paragraph 16 log::info!("Stopping due to coherent read-read"); false } else if store_elem.timestamp <= clocks.fence_seqcst[store_elem.store_index] { - // The current load, which may be sequenced-after an SC fence, can only read-from - // the last store sequenced-before an SC fence in another thread (or any stores - // later than that SC fence) + // The current load, which may be sequenced-after an SC fence, cannot read-before + // the last store sequenced-before an SC fence in another thread. + // C++17 §32.4 [atomics.order] paragraph 6 log::info!("Stopping due to coherent load sequenced after sc fence"); false } else if store_elem.timestamp <= clocks.write_seqcst[store_elem.store_index] && store_elem.is_seqcst { - // The current non-SC load can only read-from the latest SC store (or any stores later than that - // SC store) + // The current non-SC load, which may be sequenced-after an SC fence, + // cannot read-before the last SC store executed before the fence. + // C++17 §32.4 [atomics.order] paragraph 4 log::info!("Stopping due to needing to load from the last SC store"); false } else if is_seqcst && store_elem.timestamp <= clocks.read_seqcst[store_elem.store_index] { - // The current SC load can only read-from the last store sequenced-before - // the last SC fence (or any stores later than the SC fence) + // The current SC load cannot read-before the last store sequenced-before + // the last SC fence. + // C++17 §32.4 [atomics.order] paragraph 5 log::info!("Stopping due to sc load needing to load from the last SC store before an SC fence"); false } else {true}; From 01dffe05751a9e8d6a3b6cc4c2eaed2f63c3e5bd Mon Sep 17 00:00:00 2001 From: Andy Wang Date: Thu, 25 Aug 2022 00:08:04 +0100 Subject: [PATCH 3689/3747] Remove useless store buffer search logging --- src/concurrency/weak_memory.rs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/concurrency/weak_memory.rs b/src/concurrency/weak_memory.rs index a5f59137c22cd..a9760a7cc35a9 100644 --- a/src/concurrency/weak_memory.rs +++ b/src/concurrency/weak_memory.rs @@ -320,7 +320,6 @@ impl<'mir, 'tcx: 'mir> StoreBuffer { // CoWR: if a store happens-before the current load, // then we can't read-from anything earlier in modification order. // C++20 §6.9.2.2 [intro.races] paragraph 18 - log::info!("Stopping due to coherent write-read"); false } else if store_elem.loads.borrow().iter().any(|(&load_index, &load_timestamp)| { load_timestamp <= clocks.clock[load_index] @@ -328,13 +327,11 @@ impl<'mir, 'tcx: 'mir> StoreBuffer { // CoRR: if there was a load from this store which happened-before the current load, // then we cannot read-from anything earlier in modification order. // C++20 §6.9.2.2 [intro.races] paragraph 16 - log::info!("Stopping due to coherent read-read"); false } else if store_elem.timestamp <= clocks.fence_seqcst[store_elem.store_index] { // The current load, which may be sequenced-after an SC fence, cannot read-before // the last store sequenced-before an SC fence in another thread. // C++17 §32.4 [atomics.order] paragraph 6 - log::info!("Stopping due to coherent load sequenced after sc fence"); false } else if store_elem.timestamp <= clocks.write_seqcst[store_elem.store_index] && store_elem.is_seqcst @@ -342,13 +339,11 @@ impl<'mir, 'tcx: 'mir> StoreBuffer { // The current non-SC load, which may be sequenced-after an SC fence, // cannot read-before the last SC store executed before the fence. // C++17 §32.4 [atomics.order] paragraph 4 - log::info!("Stopping due to needing to load from the last SC store"); false } else if is_seqcst && store_elem.timestamp <= clocks.read_seqcst[store_elem.store_index] { // The current SC load cannot read-before the last store sequenced-before // the last SC fence. // C++17 §32.4 [atomics.order] paragraph 5 - log::info!("Stopping due to sc load needing to load from the last SC store before an SC fence"); false } else {true}; From a2467c9b2acbba6434dd49a32b5ef99ce9e57412 Mon Sep 17 00:00:00 2001 From: Andy Wang Date: Thu, 25 Aug 2022 00:30:03 +0100 Subject: [PATCH 3690/3747] Add C++20 SC access test --- tests/pass/0weak_memory_consistency.rs | 30 ++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/tests/pass/0weak_memory_consistency.rs b/tests/pass/0weak_memory_consistency.rs index 8c650bca2f36b..f3820bd660d28 100644 --- a/tests/pass/0weak_memory_consistency.rs +++ b/tests/pass/0weak_memory_consistency.rs @@ -257,6 +257,35 @@ fn test_sync_through_rmw_and_fences() { assert_ne!((a, b), (0, 0)); } +// Test case by @SabrinaJewson +// https://github.com/rust-lang/miri/issues/2301#issuecomment-1221502757 +// Demonstrating C++20 SC access changes +fn test_iriw_sc_rlx() { + let x = static_atomic_bool(false); + let y = static_atomic_bool(false); + + x.store(false, Relaxed); + y.store(false, Relaxed); + + let a = spawn(move || x.store(true, Relaxed)); + let b = spawn(move || y.store(true, Relaxed)); + let c = spawn(move || { + while !x.load(SeqCst) {} + y.load(SeqCst) + }); + let d = spawn(move || { + while !y.load(SeqCst) {} + x.load(SeqCst) + }); + + a.join().unwrap(); + b.join().unwrap(); + let c = c.join().unwrap(); + let d = d.join().unwrap(); + + assert!(c || d); +} + pub fn main() { for _ in 0..50 { test_single_thread(); @@ -267,5 +296,6 @@ pub fn main() { test_corr(); test_sc_store_buffering(); test_sync_through_rmw_and_fences(); + test_iriw_sc_rlx(); } } From 0f9e009987f62d3b1c59b142770a118adfc05c9f Mon Sep 17 00:00:00 2001 From: Andy Wang Date: Fri, 26 Aug 2022 23:56:15 +0100 Subject: [PATCH 3691/3747] Fix C++20 SC access unsoundness --- src/concurrency/weak_memory.rs | 68 +++++++++++++++++++++++++--------- 1 file changed, 51 insertions(+), 17 deletions(-) diff --git a/src/concurrency/weak_memory.rs b/src/concurrency/weak_memory.rs index a9760a7cc35a9..6e7486c135549 100644 --- a/src/concurrency/weak_memory.rs +++ b/src/concurrency/weak_memory.rs @@ -6,7 +6,7 @@ //! but it is incapable of producing all possible weak behaviours allowed by the model. There are //! certain weak behaviours observable on real hardware but not while using this. //! -//! Note that this implementation does not take into account of C++20's memory model revision to SC accesses +//! Note that this implementation does not fully take into account of C++20's memory model revision to SC accesses //! and fences introduced by P0668 (). //! This implementation is not fully correct under the revised C++20 model and may generate behaviours C++20 //! disallows (). @@ -133,9 +133,17 @@ struct StoreElement { // (partially) uninitialized data. val: Scalar, + /// Metadata about loads from this store element, + /// behind a RefCell to keep load op take &self + load_info: RefCell, +} + +#[derive(Debug, Clone, PartialEq, Eq, Default)] +struct LoadInfo { /// Timestamp of first loads from this store element by each thread - /// Behind a RefCell to keep load op take &self - loads: RefCell>, + timestamps: FxHashMap, + /// Whether this store element has been read by an SC load + sc_loaded: bool, } impl StoreBufferAlloc { @@ -235,18 +243,23 @@ impl<'mir, 'tcx: 'mir> StoreBuffer { timestamp: 0, val: init, is_seqcst: false, - loads: RefCell::new(FxHashMap::default()), + load_info: RefCell::new(LoadInfo::default()), }; ret.buffer.push_back(store_elem); ret } /// Reads from the last store in modification order - fn read_from_last_store(&self, global: &DataRaceState, thread_mgr: &ThreadManager<'_, '_>) { + fn read_from_last_store( + &self, + global: &DataRaceState, + thread_mgr: &ThreadManager<'_, '_>, + is_seqcst: bool, + ) { let store_elem = self.buffer.back(); if let Some(store_elem) = store_elem { let (index, clocks) = global.current_thread_state(thread_mgr); - store_elem.load_impl(index, &clocks); + store_elem.load_impl(index, &clocks, is_seqcst); } } @@ -276,7 +289,7 @@ impl<'mir, 'tcx: 'mir> StoreBuffer { validate()?; let (index, clocks) = global.current_thread_state(thread_mgr); - let loaded = store_elem.load_impl(index, &clocks); + let loaded = store_elem.load_impl(index, &clocks, is_seqcst); Ok((loaded, recency)) } @@ -321,9 +334,9 @@ impl<'mir, 'tcx: 'mir> StoreBuffer { // then we can't read-from anything earlier in modification order. // C++20 §6.9.2.2 [intro.races] paragraph 18 false - } else if store_elem.loads.borrow().iter().any(|(&load_index, &load_timestamp)| { - load_timestamp <= clocks.clock[load_index] - }) { + } else if store_elem.load_info.borrow().timestamps.iter().any( + |(&load_index, &load_timestamp)| load_timestamp <= clocks.clock[load_index], + ) { // CoRR: if there was a load from this store which happened-before the current load, // then we cannot read-from anything earlier in modification order. // C++20 §6.9.2.2 [intro.races] paragraph 16 @@ -340,12 +353,22 @@ impl<'mir, 'tcx: 'mir> StoreBuffer { // cannot read-before the last SC store executed before the fence. // C++17 §32.4 [atomics.order] paragraph 4 false - } else if is_seqcst && store_elem.timestamp <= clocks.read_seqcst[store_elem.store_index] { + } else if is_seqcst + && store_elem.timestamp <= clocks.read_seqcst[store_elem.store_index] + { // The current SC load cannot read-before the last store sequenced-before // the last SC fence. // C++17 §32.4 [atomics.order] paragraph 5 false - } else {true}; + } else if is_seqcst && store_elem.load_info.borrow().sc_loaded { + // The current SC load cannot read-before a store that an earlier SC load has observed. + // See https://github.com/rust-lang/miri/issues/2301#issuecomment-1222720427 + // Consequences of C++20 §31.4 [atomics.order] paragraph 3.1, 3.3 (coherence-ordered before) + // and 4.1 (coherence-ordered before between SC makes global total order S) + false + } else { + true + }; true }) @@ -386,7 +409,7 @@ impl<'mir, 'tcx: 'mir> StoreBuffer { // access val, is_seqcst, - loads: RefCell::new(FxHashMap::default()), + load_info: RefCell::new(LoadInfo::default()), }; self.buffer.push_back(store_elem); if self.buffer.len() > STORE_BUFFER_LIMIT { @@ -414,8 +437,15 @@ impl StoreElement { /// buffer regardless of subsequent loads by the same thread; if the earliest load of another /// thread doesn't happen before the current one, then no subsequent load by the other thread /// can happen before the current one. - fn load_impl(&self, index: VectorIdx, clocks: &ThreadClockSet) -> Scalar { - let _ = self.loads.borrow_mut().try_insert(index, clocks.clock[index]); + fn load_impl( + &self, + index: VectorIdx, + clocks: &ThreadClockSet, + is_seqcst: bool, + ) -> Scalar { + let mut load_info = self.load_info.borrow_mut(); + load_info.sc_loaded |= is_seqcst; + let _ = load_info.timestamps.try_insert(index, clocks.clock[index]); self.val } } @@ -475,7 +505,7 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>: } let range = alloc_range(base_offset, place.layout.size); let buffer = alloc_buffers.get_or_create_store_buffer_mut(range, init)?; - buffer.read_from_last_store(global, threads); + buffer.read_from_last_store(global, threads, atomic == AtomicRwOrd::SeqCst); buffer.buffered_write(new_val, global, threads, atomic == AtomicRwOrd::SeqCst)?; } Ok(()) @@ -582,7 +612,11 @@ pub(super) trait EvalContextExt<'mir, 'tcx: 'mir>: if let Some(alloc_buffers) = this.get_alloc_extra(alloc_id)?.weak_memory.as_ref() { let buffer = alloc_buffers .get_or_create_store_buffer(alloc_range(base_offset, size), init)?; - buffer.read_from_last_store(global, &this.machine.threads); + buffer.read_from_last_store( + global, + &this.machine.threads, + atomic == AtomicReadOrd::SeqCst, + ); } } Ok(()) From 6dea99ec712bb406596113fc946c0e6e31c85e24 Mon Sep 17 00:00:00 2001 From: Andy Wang Date: Sat, 27 Aug 2022 08:19:33 +0100 Subject: [PATCH 3692/3747] Supress clippy error --- src/concurrency/weak_memory.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/concurrency/weak_memory.rs b/src/concurrency/weak_memory.rs index 6e7486c135549..cf21341e62b56 100644 --- a/src/concurrency/weak_memory.rs +++ b/src/concurrency/weak_memory.rs @@ -306,6 +306,7 @@ impl<'mir, 'tcx: 'mir> StoreBuffer { Ok(()) } + #[allow(clippy::if_same_then_else, clippy::needless_bool)] /// Selects a valid store element in the buffer. fn fetch_store( &self, From b4eff16e0c943ef8250c0d49e1bc5501ee11467b Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 27 Aug 2022 15:55:00 -0400 Subject: [PATCH 3693/3747] ensure we don't compare provenance --- src/machine.rs | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/src/machine.rs b/src/machine.rs index 6bba5bcc5f0dd..0862b3b17c6d7 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -126,7 +126,7 @@ impl fmt::Display for MiriMemoryKind { } /// Pointer provenance. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Debug, Clone, Copy)] pub enum Provenance { Concrete { alloc_id: AllocId, @@ -136,6 +136,24 @@ pub enum Provenance { Wildcard, } +// This needs to be `Eq`+`Hash` because the `Machine` trait needs that because validity checking +// *might* be recursive and then it has to track which places have already been visited. +// However, comparing provenance is meaningless, since `Wildcard` might be any provenance -- and of +// course we don't actually do recursive checking. +// We could change `RefTracking` to strip provenance for its `seen` set but that type is generic so that is quite annoying. +// Instead owe add the required instances but make them panic. +impl PartialEq for Provenance { + fn eq(&self, _other: &Self) -> bool { + panic!("Provenance must not be compared") + } +} +impl Eq for Provenance {} +impl std::hash::Hash for Provenance { + fn hash(&self, _state: &mut H) { + panic!("Provenance must not be hashed") + } +} + /// The "extra" information a pointer has over a regular AllocId. #[derive(Copy, Clone, PartialEq)] pub enum ProvenanceExtra { From d39b683053a8c8fb654331cceb783674182c4252 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 27 Aug 2022 16:08:05 -0400 Subject: [PATCH 3694/3747] dont rerun build script unnecessarily --- build.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/build.rs b/build.rs index 15d6c963ad21f..37c626baab58a 100644 --- a/build.rs +++ b/build.rs @@ -1,4 +1,6 @@ fn main() { + // Don't rebuild miri when nothing changed. + println!("cargo:rerun-if-changed=build.rs"); // Re-export the TARGET environment variable so it can // be accessed by miri. let target = std::env::var("TARGET").unwrap(); From 3e97d8e65ffc1dc6a9c342888de61146b452a1fd Mon Sep 17 00:00:00 2001 From: Andy Wang Date: Sun, 28 Aug 2022 11:05:06 +0100 Subject: [PATCH 3695/3747] Comment deviations from the paper --- src/concurrency/weak_memory.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/concurrency/weak_memory.rs b/src/concurrency/weak_memory.rs index cf21341e62b56..0e579a38af85e 100644 --- a/src/concurrency/weak_memory.rs +++ b/src/concurrency/weak_memory.rs @@ -11,6 +11,11 @@ //! This implementation is not fully correct under the revised C++20 model and may generate behaviours C++20 //! disallows (). //! +//! A modification is made to the paper's model to partially address C++20 changes. +//! Specifically, if an SC load reads from an atomic store of any ordering, then a later SC load cannot read from +//! an earlier store in the location's modification order. This is to prevent creating a backwards S edge from the second +//! load to the first, as a result of C++20's coherence-ordered before rules. +//! //! Rust follows the C++20 memory model (except for the Consume ordering and some operations not performable through C++'s //! std::atomic API). It is therefore possible for this implementation to generate behaviours never observable when the //! same program is compiled and run natively. Unfortunately, no literature exists at the time of writing which proposes From abe890d2ce8e6fa08bb5c2ccc82e45cdfbd35481 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 27 Aug 2022 11:19:35 -0400 Subject: [PATCH 3696/3747] slightly improve protector-related error messages also rename some tests that still used outdated "barrier" terminology --- src/stacked_borrows/diagnostics.rs | 36 +++++++++++-------- .../fail/stacked_borrows/aliasing_mut1.stderr | 8 ++--- .../fail/stacked_borrows/aliasing_mut2.stderr | 12 +++---- .../fail/stacked_borrows/aliasing_mut4.stderr | 12 +++---- ...r1.rs => deallocate_against_protector1.rs} | 0 ...r => deallocate_against_protector1.stderr} | 14 ++++---- ...r2.rs => deallocate_against_protector2.rs} | 0 ...r => deallocate_against_protector2.stderr} | 14 ++++---- .../stacked_borrows/illegal_write6.stderr | 12 +++---- ...r1.rs => invalidate_against_protector1.rs} | 0 ...r => invalidate_against_protector1.stderr} | 24 ++++++------- ...r2.rs => invalidate_against_protector2.rs} | 0 ...r => invalidate_against_protector2.stderr} | 24 ++++++------- .../stacked_borrows/newtype_retagging.stderr | 12 +++---- 14 files changed, 86 insertions(+), 82 deletions(-) rename tests/fail/stacked_borrows/{deallocate_against_barrier1.rs => deallocate_against_protector1.rs} (100%) rename tests/fail/stacked_borrows/{deallocate_against_barrier1.stderr => deallocate_against_protector1.stderr} (75%) rename tests/fail/stacked_borrows/{deallocate_against_barrier2.rs => deallocate_against_protector2.rs} (100%) rename tests/fail/stacked_borrows/{deallocate_against_barrier2.stderr => deallocate_against_protector2.stderr} (76%) rename tests/fail/stacked_borrows/{invalidate_against_barrier1.rs => invalidate_against_protector1.rs} (100%) rename tests/fail/stacked_borrows/{invalidate_against_barrier1.stderr => invalidate_against_protector1.stderr} (69%) rename tests/fail/stacked_borrows/{invalidate_against_barrier2.rs => invalidate_against_protector2.rs} (100%) rename tests/fail/stacked_borrows/{invalidate_against_barrier2.stderr => invalidate_against_protector2.stderr} (69%) diff --git a/src/stacked_borrows/diagnostics.rs b/src/stacked_borrows/diagnostics.rs index 741a3d363dd35..87f0ce7419181 100644 --- a/src/stacked_borrows/diagnostics.rs +++ b/src/stacked_borrows/diagnostics.rs @@ -2,7 +2,7 @@ use smallvec::SmallVec; use std::fmt; use rustc_middle::mir::interpret::{alloc_range, AllocId, AllocRange}; -use rustc_span::{Span, SpanData}; +use rustc_span::{Span, SpanData, DUMMY_SP}; use rustc_target::abi::Size; use crate::helpers::CurrentSpan; @@ -91,6 +91,7 @@ impl fmt::Display for InvalidationCause { #[derive(Clone, Debug)] struct Protection { + /// The parent tag from which this protected tag was derived. orig_tag: ProvenanceExtra, tag: SbTag, span: Span, @@ -342,32 +343,39 @@ impl<'span, 'history, 'ecx, 'mir, 'tcx> DiagnosticCx<'span, 'history, 'ecx, 'mir let protected = protector_tag .and_then(|protector| { - self.history.protectors.iter().find_map(|protection| { - if protection.tag == protector { - Some((protection.orig_tag, protection.span.data())) - } else { - None - } + self.history.protectors.iter().find(|protection| { + protection.tag == protector }) }) - .and_then(|(tag, call_span)| { + .and_then(|protection| { self.history.creations.iter().rev().find_map(|event| { - if ProvenanceExtra::Concrete(event.retag.new_tag) == tag { - Some((event.retag.orig_tag, event.span.data(), call_span)) + if ProvenanceExtra::Concrete(event.retag.new_tag) == protection.orig_tag { + Some((protection, event)) } else { None } }) }) - .map(|(protecting_tag, protecting_tag_span, protection_span)| { + .map(|(protection, protection_parent)| { + let protected_tag = protection.tag; [ ( format!( - "{tag:?} was protected due to {protecting_tag:?} which was created here" + "{tag:?} cannot be used for memory access because that would remove protected tag {protected_tag:?}, protected by this function call", ), - protecting_tag_span, + protection.span.data(), ), - (format!("this protector is live for this call"), protection_span), + if protection_parent.retag.new_tag == tag { + (format!("{protected_tag:?} was derived from {tag:?}, the tag used for this memory access"), DUMMY_SP.data()) + } else { + ( + format!( + "{protected_tag:?} was derived from {protected_parent_tag:?}, which in turn was created here", + protected_parent_tag = protection_parent.retag.new_tag, + ), + protection_parent.span.data() + ) + } ] }); diff --git a/tests/fail/stacked_borrows/aliasing_mut1.stderr b/tests/fail/stacked_borrows/aliasing_mut1.stderr index e3f05f3350a5c..e5be3061b32c4 100644 --- a/tests/fail/stacked_borrows/aliasing_mut1.stderr +++ b/tests/fail/stacked_borrows/aliasing_mut1.stderr @@ -11,16 +11,12 @@ help: was created by a Unique retag at offsets [0x0..0x4] | LL | let xraw: *mut i32 = unsafe { mem::transmute(&mut x) }; | ^^^^^^ -help: was protected due to which was created here - --> $DIR/aliasing_mut1.rs:LL:CC - | -LL | let xraw: *mut i32 = unsafe { mem::transmute(&mut x) }; - | ^^^^^^ -help: this protector is live for this call +help: cannot be used for memory access because that would remove protected tag , protected by this function call --> $DIR/aliasing_mut1.rs:LL:CC | LL | pub fn safe(_x: &mut i32, _y: &mut i32) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = help: was derived from , the tag used for this memory access = note: backtrace: = note: inside `safe` at $DIR/aliasing_mut1.rs:LL:CC note: inside `main` at $DIR/aliasing_mut1.rs:LL:CC diff --git a/tests/fail/stacked_borrows/aliasing_mut2.stderr b/tests/fail/stacked_borrows/aliasing_mut2.stderr index 94c2ffa07f715..c3dd3a893c072 100644 --- a/tests/fail/stacked_borrows/aliasing_mut2.stderr +++ b/tests/fail/stacked_borrows/aliasing_mut2.stderr @@ -11,16 +11,16 @@ help: was created by a Unique retag at offsets [0x0..0x4] | LL | let xref = &mut x; | ^^^^^^ -help: was protected due to which was created here - --> $DIR/aliasing_mut2.rs:LL:CC - | -LL | safe_raw(xshr, xraw); - | ^^^^ -help: this protector is live for this call +help: cannot be used for memory access because that would remove protected tag , protected by this function call --> $DIR/aliasing_mut2.rs:LL:CC | LL | pub fn safe(_x: &i32, _y: &mut i32) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: was derived from , which in turn was created here + --> $DIR/aliasing_mut2.rs:LL:CC + | +LL | safe_raw(xshr, xraw); + | ^^^^ = note: backtrace: = note: inside `safe` at $DIR/aliasing_mut2.rs:LL:CC note: inside `main` at $DIR/aliasing_mut2.rs:LL:CC diff --git a/tests/fail/stacked_borrows/aliasing_mut4.stderr b/tests/fail/stacked_borrows/aliasing_mut4.stderr index f48d39b2e49f0..601422ece3020 100644 --- a/tests/fail/stacked_borrows/aliasing_mut4.stderr +++ b/tests/fail/stacked_borrows/aliasing_mut4.stderr @@ -11,16 +11,16 @@ help: was created by a Unique retag at offsets [0x0..0x4] | LL | let xref = &mut x; | ^^^^^^ -help: was protected due to which was created here - --> $DIR/aliasing_mut4.rs:LL:CC - | -LL | safe_raw(xshr, xraw as *mut _); - | ^^^^ -help: this protector is live for this call +help: cannot be used for memory access because that would remove protected tag , protected by this function call --> $DIR/aliasing_mut4.rs:LL:CC | LL | pub fn safe(_x: &i32, _y: &mut Cell) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: was derived from , which in turn was created here + --> $DIR/aliasing_mut4.rs:LL:CC + | +LL | safe_raw(xshr, xraw as *mut _); + | ^^^^ = note: backtrace: = note: inside `safe` at $DIR/aliasing_mut4.rs:LL:CC note: inside `main` at $DIR/aliasing_mut4.rs:LL:CC diff --git a/tests/fail/stacked_borrows/deallocate_against_barrier1.rs b/tests/fail/stacked_borrows/deallocate_against_protector1.rs similarity index 100% rename from tests/fail/stacked_borrows/deallocate_against_barrier1.rs rename to tests/fail/stacked_borrows/deallocate_against_protector1.rs diff --git a/tests/fail/stacked_borrows/deallocate_against_barrier1.stderr b/tests/fail/stacked_borrows/deallocate_against_protector1.stderr similarity index 75% rename from tests/fail/stacked_borrows/deallocate_against_barrier1.stderr rename to tests/fail/stacked_borrows/deallocate_against_protector1.stderr index 689c0a5deae68..2ead0c6a9ddac 100644 --- a/tests/fail/stacked_borrows/deallocate_against_barrier1.stderr +++ b/tests/fail/stacked_borrows/deallocate_against_protector1.stderr @@ -12,19 +12,19 @@ LL | unsafe { __rust_dealloc(ptr, layout.size(), layout.align()) } = note: inside `alloc::alloc::box_free::` at RUSTLIB/alloc/src/alloc.rs:LL:CC = note: inside `std::ptr::drop_in_place::> - shim(Some(std::boxed::Box))` at RUSTLIB/core/src/ptr/mod.rs:LL:CC = note: inside `std::mem::drop::>` at RUSTLIB/core/src/mem/mod.rs:LL:CC -note: inside closure at $DIR/deallocate_against_barrier1.rs:LL:CC - --> $DIR/deallocate_against_barrier1.rs:LL:CC +note: inside closure at $DIR/deallocate_against_protector1.rs:LL:CC + --> $DIR/deallocate_against_protector1.rs:LL:CC | LL | drop(unsafe { Box::from_raw(raw) }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: inside `<[closure@$DIR/deallocate_against_barrier1.rs:LL:CC] as std::ops::FnOnce<(&mut i32,)>>::call_once - shim` at RUSTLIB/core/src/ops/function.rs:LL:CC -note: inside `inner` at $DIR/deallocate_against_barrier1.rs:LL:CC - --> $DIR/deallocate_against_barrier1.rs:LL:CC + = note: inside `<[closure@$DIR/deallocate_against_protector1.rs:LL:CC] as std::ops::FnOnce<(&mut i32,)>>::call_once - shim` at RUSTLIB/core/src/ops/function.rs:LL:CC +note: inside `inner` at $DIR/deallocate_against_protector1.rs:LL:CC + --> $DIR/deallocate_against_protector1.rs:LL:CC | LL | f(x) | ^^^^ -note: inside `main` at $DIR/deallocate_against_barrier1.rs:LL:CC - --> $DIR/deallocate_against_barrier1.rs:LL:CC +note: inside `main` at $DIR/deallocate_against_protector1.rs:LL:CC + --> $DIR/deallocate_against_protector1.rs:LL:CC | LL | / inner(Box::leak(Box::new(0)), |x| { LL | | let raw = x as *mut _; diff --git a/tests/fail/stacked_borrows/deallocate_against_barrier2.rs b/tests/fail/stacked_borrows/deallocate_against_protector2.rs similarity index 100% rename from tests/fail/stacked_borrows/deallocate_against_barrier2.rs rename to tests/fail/stacked_borrows/deallocate_against_protector2.rs diff --git a/tests/fail/stacked_borrows/deallocate_against_barrier2.stderr b/tests/fail/stacked_borrows/deallocate_against_protector2.stderr similarity index 76% rename from tests/fail/stacked_borrows/deallocate_against_barrier2.stderr rename to tests/fail/stacked_borrows/deallocate_against_protector2.stderr index a1a7ce0c6bb68..60be936bd7e47 100644 --- a/tests/fail/stacked_borrows/deallocate_against_barrier2.stderr +++ b/tests/fail/stacked_borrows/deallocate_against_protector2.stderr @@ -12,19 +12,19 @@ LL | unsafe { __rust_dealloc(ptr, layout.size(), layout.align()) } = note: inside `alloc::alloc::box_free::` at RUSTLIB/alloc/src/alloc.rs:LL:CC = note: inside `std::ptr::drop_in_place::> - shim(Some(std::boxed::Box))` at RUSTLIB/core/src/ptr/mod.rs:LL:CC = note: inside `std::mem::drop::>` at RUSTLIB/core/src/mem/mod.rs:LL:CC -note: inside closure at $DIR/deallocate_against_barrier2.rs:LL:CC - --> $DIR/deallocate_against_barrier2.rs:LL:CC +note: inside closure at $DIR/deallocate_against_protector2.rs:LL:CC + --> $DIR/deallocate_against_protector2.rs:LL:CC | LL | drop(unsafe { Box::from_raw(raw) }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: inside `<[closure@$DIR/deallocate_against_barrier2.rs:LL:CC] as std::ops::FnOnce<(&mut NotUnpin,)>>::call_once - shim` at RUSTLIB/core/src/ops/function.rs:LL:CC -note: inside `inner` at $DIR/deallocate_against_barrier2.rs:LL:CC - --> $DIR/deallocate_against_barrier2.rs:LL:CC + = note: inside `<[closure@$DIR/deallocate_against_protector2.rs:LL:CC] as std::ops::FnOnce<(&mut NotUnpin,)>>::call_once - shim` at RUSTLIB/core/src/ops/function.rs:LL:CC +note: inside `inner` at $DIR/deallocate_against_protector2.rs:LL:CC + --> $DIR/deallocate_against_protector2.rs:LL:CC | LL | f(x) | ^^^^ -note: inside `main` at $DIR/deallocate_against_barrier2.rs:LL:CC - --> $DIR/deallocate_against_barrier2.rs:LL:CC +note: inside `main` at $DIR/deallocate_against_protector2.rs:LL:CC + --> $DIR/deallocate_against_protector2.rs:LL:CC | LL | / inner(Box::leak(Box::new(NotUnpin(0, PhantomPinned))), |x| { LL | | let raw = x as *mut _; diff --git a/tests/fail/stacked_borrows/illegal_write6.stderr b/tests/fail/stacked_borrows/illegal_write6.stderr index 56576b1ff39b5..fd3b19adcf5ea 100644 --- a/tests/fail/stacked_borrows/illegal_write6.stderr +++ b/tests/fail/stacked_borrows/illegal_write6.stderr @@ -11,12 +11,7 @@ help: was created by a SharedReadWrite retag at offsets [0x0..0x4] | LL | let p = x as *mut u32; | ^ -help: was protected due to which was created here - --> $DIR/illegal_write6.rs:LL:CC - | -LL | foo(x, p); - | ^ -help: this protector is live for this call +help: cannot be used for memory access because that would remove protected tag , protected by this function call --> $DIR/illegal_write6.rs:LL:CC | LL | / fn foo(a: &mut u32, y: *mut u32) -> u32 { @@ -26,6 +21,11 @@ LL | | unsafe { *y = 2 }; LL | | return *a; LL | | } | |_^ +help: was derived from , which in turn was created here + --> $DIR/illegal_write6.rs:LL:CC + | +LL | foo(x, p); + | ^ = note: backtrace: = note: inside `foo` at $DIR/illegal_write6.rs:LL:CC note: inside `main` at $DIR/illegal_write6.rs:LL:CC diff --git a/tests/fail/stacked_borrows/invalidate_against_barrier1.rs b/tests/fail/stacked_borrows/invalidate_against_protector1.rs similarity index 100% rename from tests/fail/stacked_borrows/invalidate_against_barrier1.rs rename to tests/fail/stacked_borrows/invalidate_against_protector1.rs diff --git a/tests/fail/stacked_borrows/invalidate_against_barrier1.stderr b/tests/fail/stacked_borrows/invalidate_against_protector1.stderr similarity index 69% rename from tests/fail/stacked_borrows/invalidate_against_barrier1.stderr rename to tests/fail/stacked_borrows/invalidate_against_protector1.stderr index 378f7b7d1ef56..18236adec882a 100644 --- a/tests/fail/stacked_borrows/invalidate_against_barrier1.stderr +++ b/tests/fail/stacked_borrows/invalidate_against_protector1.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: not granting access to tag because incompatible item [Unique for ] is protected by call ID - --> $DIR/invalidate_against_barrier1.rs:LL:CC + --> $DIR/invalidate_against_protector1.rs:LL:CC | LL | let _val = unsafe { *x }; | ^^ not granting access to tag because incompatible item [Unique for ] is protected by call ID @@ -7,17 +7,12 @@ LL | let _val = unsafe { *x }; = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: was created by a SharedReadWrite retag at offsets [0x0..0x4] - --> $DIR/invalidate_against_barrier1.rs:LL:CC + --> $DIR/invalidate_against_protector1.rs:LL:CC | LL | let xraw = &mut x as *mut _; | ^^^^^^ -help: was protected due to which was created here - --> $DIR/invalidate_against_barrier1.rs:LL:CC - | -LL | inner(xraw, xref); - | ^^^^ -help: this protector is live for this call - --> $DIR/invalidate_against_barrier1.rs:LL:CC +help: cannot be used for memory access because that would remove protected tag , protected by this function call + --> $DIR/invalidate_against_protector1.rs:LL:CC | LL | / fn inner(x: *mut i32, _y: &mut i32) { LL | | // If `x` and `y` alias, retagging is fine with this... but we really @@ -26,10 +21,15 @@ LL | | // unique for the duration of this call. LL | | let _val = unsafe { *x }; LL | | } | |_^ +help: was derived from , which in turn was created here + --> $DIR/invalidate_against_protector1.rs:LL:CC + | +LL | inner(xraw, xref); + | ^^^^ = note: backtrace: - = note: inside `inner` at $DIR/invalidate_against_barrier1.rs:LL:CC -note: inside `main` at $DIR/invalidate_against_barrier1.rs:LL:CC - --> $DIR/invalidate_against_barrier1.rs:LL:CC + = note: inside `inner` at $DIR/invalidate_against_protector1.rs:LL:CC +note: inside `main` at $DIR/invalidate_against_protector1.rs:LL:CC + --> $DIR/invalidate_against_protector1.rs:LL:CC | LL | inner(xraw, xref); | ^^^^^^^^^^^^^^^^^ diff --git a/tests/fail/stacked_borrows/invalidate_against_barrier2.rs b/tests/fail/stacked_borrows/invalidate_against_protector2.rs similarity index 100% rename from tests/fail/stacked_borrows/invalidate_against_barrier2.rs rename to tests/fail/stacked_borrows/invalidate_against_protector2.rs diff --git a/tests/fail/stacked_borrows/invalidate_against_barrier2.stderr b/tests/fail/stacked_borrows/invalidate_against_protector2.stderr similarity index 69% rename from tests/fail/stacked_borrows/invalidate_against_barrier2.stderr rename to tests/fail/stacked_borrows/invalidate_against_protector2.stderr index 0352b671823e6..20b9d47bbef3e 100644 --- a/tests/fail/stacked_borrows/invalidate_against_barrier2.stderr +++ b/tests/fail/stacked_borrows/invalidate_against_protector2.stderr @@ -1,5 +1,5 @@ error: Undefined Behavior: not granting access to tag because incompatible item [SharedReadOnly for ] is protected by call ID - --> $DIR/invalidate_against_barrier2.rs:LL:CC + --> $DIR/invalidate_against_protector2.rs:LL:CC | LL | unsafe { *x = 0 }; | ^^^^^^ not granting access to tag because incompatible item [SharedReadOnly for ] is protected by call ID @@ -7,17 +7,12 @@ LL | unsafe { *x = 0 }; = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information help: was created by a SharedReadWrite retag at offsets [0x0..0x4] - --> $DIR/invalidate_against_barrier2.rs:LL:CC + --> $DIR/invalidate_against_protector2.rs:LL:CC | LL | let xraw = &mut x as *mut _; | ^^^^^^ -help: was protected due to which was created here - --> $DIR/invalidate_against_barrier2.rs:LL:CC - | -LL | inner(xraw, xref); - | ^^^^ -help: this protector is live for this call - --> $DIR/invalidate_against_barrier2.rs:LL:CC +help: cannot be used for memory access because that would remove protected tag , protected by this function call + --> $DIR/invalidate_against_protector2.rs:LL:CC | LL | / fn inner(x: *mut i32, _y: &i32) { LL | | // If `x` and `y` alias, retagging is fine with this... but we really @@ -26,10 +21,15 @@ LL | | // immutable for the duration of this call. LL | | unsafe { *x = 0 }; LL | | } | |_^ +help: was derived from , which in turn was created here + --> $DIR/invalidate_against_protector2.rs:LL:CC + | +LL | inner(xraw, xref); + | ^^^^ = note: backtrace: - = note: inside `inner` at $DIR/invalidate_against_barrier2.rs:LL:CC -note: inside `main` at $DIR/invalidate_against_barrier2.rs:LL:CC - --> $DIR/invalidate_against_barrier2.rs:LL:CC + = note: inside `inner` at $DIR/invalidate_against_protector2.rs:LL:CC +note: inside `main` at $DIR/invalidate_against_protector2.rs:LL:CC + --> $DIR/invalidate_against_protector2.rs:LL:CC | LL | inner(xraw, xref); | ^^^^^^^^^^^^^^^^^ diff --git a/tests/fail/stacked_borrows/newtype_retagging.stderr b/tests/fail/stacked_borrows/newtype_retagging.stderr index 2d26787231dc6..e75502d361059 100644 --- a/tests/fail/stacked_borrows/newtype_retagging.stderr +++ b/tests/fail/stacked_borrows/newtype_retagging.stderr @@ -11,18 +11,18 @@ help: was created by a SharedReadWrite retag at offsets [0x0..0x4] | LL | let ptr = Box::into_raw(Box::new(0i32)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -help: was protected due to which was created here - --> $DIR/newtype_retagging.rs:LL:CC - | -LL | Newtype(&mut *ptr), - | ^^^^^^^^^^^^^^^^^^ -help: this protector is live for this call +help: cannot be used for memory access because that would remove protected tag , protected by this function call --> $DIR/newtype_retagging.rs:LL:CC | LL | / fn dealloc_while_running(_n: Newtype<'_>, dealloc: impl FnOnce()) { LL | | dealloc(); LL | | } | |_^ +help: was derived from , which in turn was created here + --> $DIR/newtype_retagging.rs:LL:CC + | +LL | Newtype(&mut *ptr), + | ^^^^^^^^^^^^^^^^^^ = note: backtrace: = note: inside `std::boxed::Box::::from_raw_in` at RUSTLIB/alloc/src/boxed.rs:LL:CC = note: inside `std::boxed::Box::::from_raw` at RUSTLIB/alloc/src/boxed.rs:LL:CC From 70b960b879528b6ef5f8df4e0f8e2d8b72e1d221 Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Sun, 28 Aug 2022 13:07:33 -0400 Subject: [PATCH 3697/3747] Skip field retagging on ZSTs, it can take forever --- src/stacked_borrows/mod.rs | 8 ++++++++ .../stacked-borrows/zst-field-retagging-terminates.rs | 5 +++++ 2 files changed, 13 insertions(+) create mode 100644 tests/pass/stacked-borrows/zst-field-retagging-terminates.rs diff --git a/src/stacked_borrows/mod.rs b/src/stacked_borrows/mod.rs index 66fdd685def5b..5cdcaecc17d2f 100644 --- a/src/stacked_borrows/mod.rs +++ b/src/stacked_borrows/mod.rs @@ -973,6 +973,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } fn visit_value(&mut self, place: &PlaceTy<'tcx, Provenance>) -> InterpResult<'tcx> { + // If this place is smaller than a pointer, we know that it can't contain any + // pointers we need to retag, so we can stop recursion early. + // This optimization is crucial for ZSTs, because they can contain way more fields + // than we can ever visit. + if !place.layout.is_unsized() && place.layout.size < self.ecx.pointer_size() { + return Ok(()); + } + if let Some((ref_kind, protector)) = qualify(place.layout.ty, self.kind) { self.retag_place(place, ref_kind, self.retag_cause, protector)?; } else if matches!(place.layout.ty.kind(), ty::RawPtr(..)) { diff --git a/tests/pass/stacked-borrows/zst-field-retagging-terminates.rs b/tests/pass/stacked-borrows/zst-field-retagging-terminates.rs new file mode 100644 index 0000000000000..2099c5ad14968 --- /dev/null +++ b/tests/pass/stacked-borrows/zst-field-retagging-terminates.rs @@ -0,0 +1,5 @@ +//@compile-flags: -Zmiri-retag-fields +fn main() { + let array = [(); usize::MAX]; + drop(array); // Pass the array to a function, retagging its fields +} From c9b36b4dedab0c1b44f0357ddbf4ebc3a702e259 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 29 Aug 2022 07:46:03 -0400 Subject: [PATCH 3698/3747] clarify test purpose --- tests/pass/stacked-borrows/zst-field-retagging-terminates.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/pass/stacked-borrows/zst-field-retagging-terminates.rs b/tests/pass/stacked-borrows/zst-field-retagging-terminates.rs index 2099c5ad14968..ce3c8b7d5f1a1 100644 --- a/tests/pass/stacked-borrows/zst-field-retagging-terminates.rs +++ b/tests/pass/stacked-borrows/zst-field-retagging-terminates.rs @@ -1,4 +1,5 @@ //@compile-flags: -Zmiri-retag-fields +// Checks that the test does not run forever (which relies on a fast path). fn main() { let array = [(); usize::MAX]; drop(array); // Pass the array to a function, retagging its fields From da0d4829bf7ca00fce64ce8563b84299699131b2 Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Mon, 29 Aug 2022 17:14:45 -0400 Subject: [PATCH 3699/3747] Use the better FnEntry spans in protector errors --- rust-version | 2 +- src/diagnostics.rs | 3 +- src/machine.rs | 13 ++-- src/stacked_borrows/diagnostics.rs | 64 ++++++------------- src/stacked_borrows/mod.rs | 13 +++- .../fail/stacked_borrows/aliasing_mut1.stderr | 9 ++- .../fail/stacked_borrows/aliasing_mut2.stderr | 13 ++-- .../fail/stacked_borrows/aliasing_mut3.stderr | 8 +-- .../fail/stacked_borrows/aliasing_mut4.stderr | 13 ++-- tests/fail/stacked_borrows/illegal_write6.rs | 2 +- .../stacked_borrows/illegal_write6.stderr | 20 ++---- .../invalidate_against_protector1.stderr | 20 ++---- .../invalidate_against_protector2.stderr | 20 ++---- .../fail/stacked_borrows/newtype_retagging.rs | 2 +- .../stacked_borrows/newtype_retagging.stderr | 17 ++--- 15 files changed, 80 insertions(+), 139 deletions(-) diff --git a/rust-version b/rust-version index 9b8d986c67114..f7e2fa5a33d3c 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -4065b89b1e7287047d7d6c65e7abd7b8ee70bcf0 +94b2b15e63c5d2b2a6a0910e3dae554ce9415bf9 diff --git a/src/diagnostics.rs b/src/diagnostics.rs index eafe56955d1f4..26442da6d655b 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -183,9 +183,8 @@ pub fn report_error<'tcx, 'mir>( if let Some((msg, span)) = invalidated { helps.push((Some(span), msg)); } - if let Some([(protector_msg, protector_span), (protection_msg, protection_span)]) = protected { + if let Some((protector_msg, protector_span)) = protected { helps.push((Some(protector_span), protector_msg)); - helps.push((Some(protection_span), protection_msg)); } } helps diff --git a/src/machine.rs b/src/machine.rs index 0862b3b17c6d7..4f7e3a6a71b13 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -743,10 +743,15 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { } let alloc = alloc.into_owned(); - let stacks = - ecx.machine.stacked_borrows.as_ref().map(|stacked_borrows| { - Stacks::new_allocation(id, alloc.size(), stacked_borrows, kind) - }); + let stacks = ecx.machine.stacked_borrows.as_ref().map(|stacked_borrows| { + Stacks::new_allocation( + id, + alloc.size(), + stacked_borrows, + kind, + ecx.machine.current_span(*ecx.tcx), + ) + }); let race_alloc = ecx.machine.data_race.as_ref().map(|data_race| { data_race::AllocExtra::new_allocation( data_race, diff --git a/src/stacked_borrows/diagnostics.rs b/src/stacked_borrows/diagnostics.rs index 87f0ce7419181..b8e777717e973 100644 --- a/src/stacked_borrows/diagnostics.rs +++ b/src/stacked_borrows/diagnostics.rs @@ -2,7 +2,7 @@ use smallvec::SmallVec; use std::fmt; use rustc_middle::mir::interpret::{alloc_range, AllocId, AllocRange}; -use rustc_span::{Span, SpanData, DUMMY_SP}; +use rustc_span::{Span, SpanData}; use rustc_target::abi::Size; use crate::helpers::CurrentSpan; @@ -14,6 +14,7 @@ use rustc_middle::mir::interpret::InterpError; #[derive(Clone, Debug)] pub struct AllocHistory { id: AllocId, + base: (Item, Span), creations: smallvec::SmallVec<[Creation; 1]>, invalidations: smallvec::SmallVec<[Invalidation; 1]>, protectors: smallvec::SmallVec<[Protection; 1]>, @@ -91,8 +92,6 @@ impl fmt::Display for InvalidationCause { #[derive(Clone, Debug)] struct Protection { - /// The parent tag from which this protected tag was derived. - orig_tag: ProvenanceExtra, tag: SbTag, span: Span, } @@ -101,7 +100,7 @@ struct Protection { pub struct TagHistory { pub created: (String, SpanData), pub invalidated: Option<(String, SpanData)>, - pub protected: Option<([(String, SpanData); 2])>, + pub protected: Option<(String, SpanData)>, } pub struct DiagnosticCxBuilder<'span, 'ecx, 'mir, 'tcx> { @@ -228,9 +227,10 @@ struct DeallocOp { } impl AllocHistory { - pub fn new(id: AllocId) -> Self { + pub fn new(id: AllocId, item: Item, current_span: &mut CurrentSpan<'_, '_, '_>) -> Self { Self { id, + base: (item, current_span.get()), creations: SmallVec::new(), invalidations: SmallVec::new(), protectors: SmallVec::new(), @@ -290,11 +290,7 @@ impl<'span, 'history, 'ecx, 'mir, 'tcx> DiagnosticCx<'span, 'history, 'ecx, 'mir let Operation::Retag(op) = &self.operation else { unreachable!("Protectors can only be created during a retag") }; - self.history.protectors.push(Protection { - orig_tag: op.orig_tag, - tag: op.new_tag, - span: self.current_span.get(), - }); + self.history.protectors.push(Protection { tag: op.new_tag, span: self.current_span.get() }); } pub fn get_logs_relevant_to( @@ -331,6 +327,17 @@ impl<'span, 'history, 'ecx, 'mir, 'tcx> DiagnosticCx<'span, 'history, 'ecx, 'mir None } }) + }).or_else(|| { + // If we didn't find a retag that created this tag, it might be the base tag of + // this allocation. + if self.history.base.0.tag() == tag { + Some(( + format!("{:?} was created here, as a base tag for {:?}", tag, self.history.id), + self.history.base.1.data() + )) + } else { + None + } }) else { // But if we don't have a creation event, this is related to a wildcard, and there // is really nothing we can do to help. @@ -343,40 +350,11 @@ impl<'span, 'history, 'ecx, 'mir, 'tcx> DiagnosticCx<'span, 'history, 'ecx, 'mir let protected = protector_tag .and_then(|protector| { - self.history.protectors.iter().find(|protection| { - protection.tag == protector - }) + self.history.protectors.iter().find(|protection| protection.tag == protector) }) - .and_then(|protection| { - self.history.creations.iter().rev().find_map(|event| { - if ProvenanceExtra::Concrete(event.retag.new_tag) == protection.orig_tag { - Some((protection, event)) - } else { - None - } - }) - }) - .map(|(protection, protection_parent)| { + .map(|protection| { let protected_tag = protection.tag; - [ - ( - format!( - "{tag:?} cannot be used for memory access because that would remove protected tag {protected_tag:?}, protected by this function call", - ), - protection.span.data(), - ), - if protection_parent.retag.new_tag == tag { - (format!("{protected_tag:?} was derived from {tag:?}, the tag used for this memory access"), DUMMY_SP.data()) - } else { - ( - format!( - "{protected_tag:?} was derived from {protected_parent_tag:?}, which in turn was created here", - protected_parent_tag = protection_parent.retag.new_tag, - ), - protection_parent.span.data() - ) - } - ] + (format!("{protected_tag:?} is this argument"), protection.span.data()) }); Some(TagHistory { created, invalidated, protected }) @@ -448,7 +426,7 @@ impl<'span, 'history, 'ecx, 'mir, 'tcx> DiagnosticCx<'span, 'history, 'ecx, 'mir | Operation::Access(AccessOp { tag, .. }) => err_sb_ub( format!( - "not granting access to tag {:?} because incompatible item {:?} is protected by call {:?}", + "not granting access to tag {:?} because that would remove {:?} which is protected because it is an argument of call {:?}", tag, item, call_id ), None, diff --git a/src/stacked_borrows/mod.rs b/src/stacked_borrows/mod.rs index 5cdcaecc17d2f..4f7914c5fb0ff 100644 --- a/src/stacked_borrows/mod.rs +++ b/src/stacked_borrows/mod.rs @@ -500,13 +500,19 @@ impl<'tcx> Stack { impl<'tcx> Stacks { /// Creates a new stack with an initial tag. For diagnostic purposes, we also need to know /// the [`AllocId`] of the allocation this is associated with. - fn new(size: Size, perm: Permission, tag: SbTag, id: AllocId) -> Self { + fn new( + size: Size, + perm: Permission, + tag: SbTag, + id: AllocId, + current_span: &mut CurrentSpan<'_, '_, '_>, + ) -> Self { let item = Item::new(tag, perm, false); let stack = Stack::new(item); Stacks { stacks: RangeMap::new(size, stack), - history: AllocHistory::new(id), + history: AllocHistory::new(id, item, current_span), exposed_tags: FxHashSet::default(), } } @@ -538,6 +544,7 @@ impl Stacks { size: Size, state: &GlobalState, kind: MemoryKind, + mut current_span: CurrentSpan<'_, '_, '_>, ) -> Self { let mut extra = state.borrow_mut(); let (base_tag, perm) = match kind { @@ -550,7 +557,7 @@ impl Stacks { // Everything else is shared by default. _ => (extra.base_ptr_tag(id), Permission::SharedReadWrite), }; - Stacks::new(size, perm, base_tag, id) + Stacks::new(size, perm, base_tag, id, &mut current_span) } #[inline(always)] diff --git a/tests/fail/stacked_borrows/aliasing_mut1.stderr b/tests/fail/stacked_borrows/aliasing_mut1.stderr index e5be3061b32c4..514b1a9901e6a 100644 --- a/tests/fail/stacked_borrows/aliasing_mut1.stderr +++ b/tests/fail/stacked_borrows/aliasing_mut1.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: not granting access to tag because incompatible item [Unique for ] is protected by call ID +error: Undefined Behavior: not granting access to tag because that would remove [Unique for ] which is protected because it is an argument of call ID --> $DIR/aliasing_mut1.rs:LL:CC | LL | pub fn safe(_x: &mut i32, _y: &mut i32) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not granting access to tag because incompatible item [Unique for ] is protected by call ID + | ^^ not granting access to tag because that would remove [Unique for ] which is protected because it is an argument of call ID | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information @@ -11,12 +11,11 @@ help: was created by a Unique retag at offsets [0x0..0x4] | LL | let xraw: *mut i32 = unsafe { mem::transmute(&mut x) }; | ^^^^^^ -help: cannot be used for memory access because that would remove protected tag , protected by this function call +help: is this argument --> $DIR/aliasing_mut1.rs:LL:CC | LL | pub fn safe(_x: &mut i32, _y: &mut i32) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = help: was derived from , the tag used for this memory access + | ^^ = note: backtrace: = note: inside `safe` at $DIR/aliasing_mut1.rs:LL:CC note: inside `main` at $DIR/aliasing_mut1.rs:LL:CC diff --git a/tests/fail/stacked_borrows/aliasing_mut2.stderr b/tests/fail/stacked_borrows/aliasing_mut2.stderr index c3dd3a893c072..5fc56a91f577d 100644 --- a/tests/fail/stacked_borrows/aliasing_mut2.stderr +++ b/tests/fail/stacked_borrows/aliasing_mut2.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: not granting access to tag because incompatible item [SharedReadOnly for ] is protected by call ID +error: Undefined Behavior: not granting access to tag because that would remove [SharedReadOnly for ] which is protected because it is an argument of call ID --> $DIR/aliasing_mut2.rs:LL:CC | LL | pub fn safe(_x: &i32, _y: &mut i32) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not granting access to tag because incompatible item [SharedReadOnly for ] is protected by call ID + | ^^ not granting access to tag because that would remove [SharedReadOnly for ] which is protected because it is an argument of call ID | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information @@ -11,16 +11,11 @@ help: was created by a Unique retag at offsets [0x0..0x4] | LL | let xref = &mut x; | ^^^^^^ -help: cannot be used for memory access because that would remove protected tag , protected by this function call +help: is this argument --> $DIR/aliasing_mut2.rs:LL:CC | LL | pub fn safe(_x: &i32, _y: &mut i32) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -help: was derived from , which in turn was created here - --> $DIR/aliasing_mut2.rs:LL:CC - | -LL | safe_raw(xshr, xraw); - | ^^^^ + | ^^ = note: backtrace: = note: inside `safe` at $DIR/aliasing_mut2.rs:LL:CC note: inside `main` at $DIR/aliasing_mut2.rs:LL:CC diff --git a/tests/fail/stacked_borrows/aliasing_mut3.stderr b/tests/fail/stacked_borrows/aliasing_mut3.stderr index 0fa31260323fb..ee38ea417003b 100644 --- a/tests/fail/stacked_borrows/aliasing_mut3.stderr +++ b/tests/fail/stacked_borrows/aliasing_mut3.stderr @@ -2,10 +2,10 @@ error: Undefined Behavior: trying to retag from for SharedReadOnly permiss --> $DIR/aliasing_mut3.rs:LL:CC | LL | pub fn safe(_x: &mut i32, _y: &i32) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | | - | trying to retag from for SharedReadOnly permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location - | this error occurs as part of FnEntry retag at ALLOC[0x0..0x4] + | ^^ + | | + | trying to retag from for SharedReadOnly permission at ALLOC[0x0], but that tag does not exist in the borrow stack for this location + | this error occurs as part of FnEntry retag at ALLOC[0x0..0x4] | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information diff --git a/tests/fail/stacked_borrows/aliasing_mut4.stderr b/tests/fail/stacked_borrows/aliasing_mut4.stderr index 601422ece3020..d5c2e73669679 100644 --- a/tests/fail/stacked_borrows/aliasing_mut4.stderr +++ b/tests/fail/stacked_borrows/aliasing_mut4.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: not granting access to tag because incompatible item [SharedReadOnly for ] is protected by call ID +error: Undefined Behavior: not granting access to tag because that would remove [SharedReadOnly for ] which is protected because it is an argument of call ID --> $DIR/aliasing_mut4.rs:LL:CC | LL | pub fn safe(_x: &i32, _y: &mut Cell) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not granting access to tag because incompatible item [SharedReadOnly for ] is protected by call ID + | ^^ not granting access to tag because that would remove [SharedReadOnly for ] which is protected because it is an argument of call ID | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information @@ -11,16 +11,11 @@ help: was created by a Unique retag at offsets [0x0..0x4] | LL | let xref = &mut x; | ^^^^^^ -help: cannot be used for memory access because that would remove protected tag , protected by this function call +help: is this argument --> $DIR/aliasing_mut4.rs:LL:CC | LL | pub fn safe(_x: &i32, _y: &mut Cell) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -help: was derived from , which in turn was created here - --> $DIR/aliasing_mut4.rs:LL:CC - | -LL | safe_raw(xshr, xraw as *mut _); - | ^^^^ + | ^^ = note: backtrace: = note: inside `safe` at $DIR/aliasing_mut4.rs:LL:CC note: inside `main` at $DIR/aliasing_mut4.rs:LL:CC diff --git a/tests/fail/stacked_borrows/illegal_write6.rs b/tests/fail/stacked_borrows/illegal_write6.rs index 1e032840917eb..448f1493367af 100644 --- a/tests/fail/stacked_borrows/illegal_write6.rs +++ b/tests/fail/stacked_borrows/illegal_write6.rs @@ -7,6 +7,6 @@ fn main() { fn foo(a: &mut u32, y: *mut u32) -> u32 { *a = 1; let _b = &*a; - unsafe { *y = 2 }; //~ ERROR: /not granting access .* because incompatible item .* is protected/ + unsafe { *y = 2 }; //~ ERROR: /not granting access .* because that would remove .* which is protected/ return *a; } diff --git a/tests/fail/stacked_borrows/illegal_write6.stderr b/tests/fail/stacked_borrows/illegal_write6.stderr index fd3b19adcf5ea..56e4bd79d477e 100644 --- a/tests/fail/stacked_borrows/illegal_write6.stderr +++ b/tests/fail/stacked_borrows/illegal_write6.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: not granting access to tag because incompatible item [Unique for ] is protected by call ID +error: Undefined Behavior: not granting access to tag because that would remove [Unique for ] which is protected because it is an argument of call ID --> $DIR/illegal_write6.rs:LL:CC | LL | unsafe { *y = 2 }; - | ^^^^^^ not granting access to tag because incompatible item [Unique for ] is protected by call ID + | ^^^^^^ not granting access to tag because that would remove [Unique for ] which is protected because it is an argument of call ID | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information @@ -11,21 +11,11 @@ help: was created by a SharedReadWrite retag at offsets [0x0..0x4] | LL | let p = x as *mut u32; | ^ -help: cannot be used for memory access because that would remove protected tag , protected by this function call +help: is this argument --> $DIR/illegal_write6.rs:LL:CC | -LL | / fn foo(a: &mut u32, y: *mut u32) -> u32 { -LL | | *a = 1; -LL | | let _b = &*a; -LL | | unsafe { *y = 2 }; -LL | | return *a; -LL | | } - | |_^ -help: was derived from , which in turn was created here - --> $DIR/illegal_write6.rs:LL:CC - | -LL | foo(x, p); - | ^ +LL | fn foo(a: &mut u32, y: *mut u32) -> u32 { + | ^ = note: backtrace: = note: inside `foo` at $DIR/illegal_write6.rs:LL:CC note: inside `main` at $DIR/illegal_write6.rs:LL:CC diff --git a/tests/fail/stacked_borrows/invalidate_against_protector1.stderr b/tests/fail/stacked_borrows/invalidate_against_protector1.stderr index 18236adec882a..5e6fd6e02757b 100644 --- a/tests/fail/stacked_borrows/invalidate_against_protector1.stderr +++ b/tests/fail/stacked_borrows/invalidate_against_protector1.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: not granting access to tag because incompatible item [Unique for ] is protected by call ID +error: Undefined Behavior: not granting access to tag because that would remove [Unique for ] which is protected because it is an argument of call ID --> $DIR/invalidate_against_protector1.rs:LL:CC | LL | let _val = unsafe { *x }; - | ^^ not granting access to tag because incompatible item [Unique for ] is protected by call ID + | ^^ not granting access to tag because that would remove [Unique for ] which is protected because it is an argument of call ID | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information @@ -11,21 +11,11 @@ help: was created by a SharedReadWrite retag at offsets [0x0..0x4] | LL | let xraw = &mut x as *mut _; | ^^^^^^ -help: cannot be used for memory access because that would remove protected tag , protected by this function call +help: is this argument --> $DIR/invalidate_against_protector1.rs:LL:CC | -LL | / fn inner(x: *mut i32, _y: &mut i32) { -LL | | // If `x` and `y` alias, retagging is fine with this... but we really -LL | | // shouldn't be allowed to use `x` at all because `y` was assumed to be -LL | | // unique for the duration of this call. -LL | | let _val = unsafe { *x }; -LL | | } - | |_^ -help: was derived from , which in turn was created here - --> $DIR/invalidate_against_protector1.rs:LL:CC - | -LL | inner(xraw, xref); - | ^^^^ +LL | fn inner(x: *mut i32, _y: &mut i32) { + | ^^ = note: backtrace: = note: inside `inner` at $DIR/invalidate_against_protector1.rs:LL:CC note: inside `main` at $DIR/invalidate_against_protector1.rs:LL:CC diff --git a/tests/fail/stacked_borrows/invalidate_against_protector2.stderr b/tests/fail/stacked_borrows/invalidate_against_protector2.stderr index 20b9d47bbef3e..eab55d2568dee 100644 --- a/tests/fail/stacked_borrows/invalidate_against_protector2.stderr +++ b/tests/fail/stacked_borrows/invalidate_against_protector2.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: not granting access to tag because incompatible item [SharedReadOnly for ] is protected by call ID +error: Undefined Behavior: not granting access to tag because that would remove [SharedReadOnly for ] which is protected because it is an argument of call ID --> $DIR/invalidate_against_protector2.rs:LL:CC | LL | unsafe { *x = 0 }; - | ^^^^^^ not granting access to tag because incompatible item [SharedReadOnly for ] is protected by call ID + | ^^^^^^ not granting access to tag because that would remove [SharedReadOnly for ] which is protected because it is an argument of call ID | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information @@ -11,21 +11,11 @@ help: was created by a SharedReadWrite retag at offsets [0x0..0x4] | LL | let xraw = &mut x as *mut _; | ^^^^^^ -help: cannot be used for memory access because that would remove protected tag , protected by this function call +help: is this argument --> $DIR/invalidate_against_protector2.rs:LL:CC | -LL | / fn inner(x: *mut i32, _y: &i32) { -LL | | // If `x` and `y` alias, retagging is fine with this... but we really -LL | | // shouldn't be allowed to write to `x` at all because `y` was assumed to be -LL | | // immutable for the duration of this call. -LL | | unsafe { *x = 0 }; -LL | | } - | |_^ -help: was derived from , which in turn was created here - --> $DIR/invalidate_against_protector2.rs:LL:CC - | -LL | inner(xraw, xref); - | ^^^^ +LL | fn inner(x: *mut i32, _y: &i32) { + | ^^ = note: backtrace: = note: inside `inner` at $DIR/invalidate_against_protector2.rs:LL:CC note: inside `main` at $DIR/invalidate_against_protector2.rs:LL:CC diff --git a/tests/fail/stacked_borrows/newtype_retagging.rs b/tests/fail/stacked_borrows/newtype_retagging.rs index f9cceb761af3e..6e7413cff5d4b 100644 --- a/tests/fail/stacked_borrows/newtype_retagging.rs +++ b/tests/fail/stacked_borrows/newtype_retagging.rs @@ -1,5 +1,5 @@ //@compile-flags: -Zmiri-retag-fields -//@error-pattern: is protected by call +//@error-pattern: which is protected struct Newtype<'a>(&'a mut i32); fn dealloc_while_running(_n: Newtype<'_>, dealloc: impl FnOnce()) { diff --git a/tests/fail/stacked_borrows/newtype_retagging.stderr b/tests/fail/stacked_borrows/newtype_retagging.stderr index e75502d361059..7073c8162d168 100644 --- a/tests/fail/stacked_borrows/newtype_retagging.stderr +++ b/tests/fail/stacked_borrows/newtype_retagging.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: not granting access to tag because incompatible item [Unique for ] is protected by call ID +error: Undefined Behavior: not granting access to tag because that would remove [Unique for ] which is protected because it is an argument of call ID --> RUSTLIB/alloc/src/boxed.rs:LL:CC | LL | Box(unsafe { Unique::new_unchecked(raw) }, alloc) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not granting access to tag because incompatible item [Unique for ] is protected by call ID + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not granting access to tag because that would remove [Unique for ] which is protected because it is an argument of call ID | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information @@ -11,18 +11,11 @@ help: was created by a SharedReadWrite retag at offsets [0x0..0x4] | LL | let ptr = Box::into_raw(Box::new(0i32)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -help: cannot be used for memory access because that would remove protected tag , protected by this function call +help: is this argument --> $DIR/newtype_retagging.rs:LL:CC | -LL | / fn dealloc_while_running(_n: Newtype<'_>, dealloc: impl FnOnce()) { -LL | | dealloc(); -LL | | } - | |_^ -help: was derived from , which in turn was created here - --> $DIR/newtype_retagging.rs:LL:CC - | -LL | Newtype(&mut *ptr), - | ^^^^^^^^^^^^^^^^^^ +LL | fn dealloc_while_running(_n: Newtype<'_>, dealloc: impl FnOnce()) { + | ^^ = note: backtrace: = note: inside `std::boxed::Box::::from_raw_in` at RUSTLIB/alloc/src/boxed.rs:LL:CC = note: inside `std::boxed::Box::::from_raw` at RUSTLIB/alloc/src/boxed.rs:LL:CC From b74654f25c15f69c2bf91e21db46aff32265741f Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 31 Aug 2022 10:27:05 +0000 Subject: [PATCH 3700/3747] Bump UI test dependency --- Cargo.lock | 50 +++-------------------------- Cargo.toml | 2 +- tests/compiletest.rs | 75 ++++++++++++++++++++++---------------------- 3 files changed, 43 insertions(+), 84 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 084b7b27a2fbb..1ce41f0a85e34 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -32,15 +32,6 @@ dependencies = [ "memchr", ] -[[package]] -name = "ansi_term" -version = "0.12.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2" -dependencies = [ - "winapi", -] - [[package]] name = "atty" version = "0.2.14" @@ -229,21 +220,11 @@ dependencies = [ "lazy_static", ] -[[package]] -name = "ctor" -version = "0.1.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f877be4f7c9f246b183111634f75baa039715e3f46ce860677d3b19a69fb229c" -dependencies = [ - "quote", - "syn", -] - [[package]] name = "diff" -version = "0.1.12" +version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e25ea47919b1560c4e3b7fe0aaab9becf5b84a10325ddf7db0f0ba5e1026499" +checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8" [[package]] name = "env_logger" @@ -464,15 +445,6 @@ version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "18a6dbe30758c9f83eb00cbea4ac95966305f5a7772f3f42ebfc7fc7eddbd8e1" -[[package]] -name = "output_vt100" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "628223faebab4e3e40667ee0b2336d34a5b960ff60ea743ddfdbcf7770bcfb66" -dependencies = [ - "winapi", -] - [[package]] name = "owo-colors" version = "3.4.0" @@ -525,18 +497,6 @@ version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed0cfbc8191465bed66e1718596ee0b0b35d5ee1f41c5df2189d0fe8bde535ba" -[[package]] -name = "pretty_assertions" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c89f989ac94207d048d92db058e4f6ec7342b0971fc58d1271ca148b799b3563" -dependencies = [ - "ansi_term", - "ctor", - "diff", - "output_vt100", -] - [[package]] name = "proc-macro2" version = "1.0.39" @@ -794,16 +754,16 @@ dependencies = [ [[package]] name = "ui_test" -version = "0.1.1" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43a7bfdb147f57c498ca629c7802b57899de0bb82ae36b6f01f1540da41832f1" +checksum = "ee6b579f4a09b0cf15b910e8edbaaae5bc66d0674a892ec4dbd5e8a5d094d979" dependencies = [ "cargo_metadata", "color-eyre", "colored", "crossbeam", + "diff", "lazy_static", - "pretty_assertions", "regex", "rustc_version", "serde", diff --git a/Cargo.toml b/Cargo.toml index d6d005ac36942..fee63359005e2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -40,7 +40,7 @@ libc = "0.2" [dev-dependencies] colored = "2" -ui_test = "0.1" +ui_test = "0.2" # Features chosen to match those required by env_logger, to avoid rebuilds regex = { version = "1.5.5", default-features = false, features = ["perf", "std"] } lazy_static = "1.4.0" diff --git a/tests/compiletest.rs b/tests/compiletest.rs index fe0d9be28cf2a..924d253b4cfc0 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -1,7 +1,7 @@ use colored::*; use regex::Regex; use std::path::{Path, PathBuf}; -use std::{env, ffi::OsString, process::Command}; +use std::{env, process::Command}; use ui_test::{color_eyre::Result, Config, DependencyBuilder, Mode, OutputConflictHandling}; fn miri_path() -> PathBuf { @@ -43,30 +43,40 @@ fn run_tests( target: Option, with_dependencies: bool, ) -> Result<()> { + let mut config = Config { + target, + stderr_filters: STDERR.clone(), + stdout_filters: STDOUT.clone(), + root_dir: PathBuf::from(path), + mode, + program: miri_path(), + quiet: false, + ..Config::default() + }; + let in_rustc_test_suite = option_env!("RUSTC_STAGE").is_some(); // Add some flags we always want. - let mut flags: Vec = Vec::new(); - flags.push("--edition".into()); - flags.push("2018".into()); + config.args.push("--edition".into()); + config.args.push("2018".into()); if in_rustc_test_suite { // Less aggressive warnings to make the rustc toolstate management less painful. // (We often get warnings when e.g. a feature gets stabilized or some lint gets added/improved.) - flags.push("-Astable-features".into()); - flags.push("-Aunused".into()); + config.args.push("-Astable-features".into()); + config.args.push("-Aunused".into()); } else { - flags.push("-Dwarnings".into()); - flags.push("-Dunused".into()); + config.args.push("-Dwarnings".into()); + config.args.push("-Dunused".into()); } if let Ok(extra_flags) = env::var("MIRIFLAGS") { for flag in extra_flags.split_whitespace() { - flags.push(flag.into()); + config.args.push(flag.into()); } } - flags.push("-Zui-testing".into()); - if let Some(target) = &target { - flags.push("--target".into()); - flags.push(target.into()); + config.args.push("-Zui-testing".into()); + if let Some(target) = &config.target { + config.args.push("--target".into()); + config.args.push(target.into()); } // If we're on linux, and we're testing the extern-so functionality, @@ -76,45 +86,35 @@ fn run_tests( let so_file_path = build_so_for_c_ffi_tests(); let mut flag = std::ffi::OsString::from("-Zmiri-extern-so-file="); flag.push(so_file_path.into_os_string()); - flags.push(flag); + config.args.push(flag); } let skip_ui_checks = env::var_os("MIRI_SKIP_UI_CHECKS").is_some(); - let output_conflict_handling = match (env::var_os("MIRI_BLESS").is_some(), skip_ui_checks) { + config.output_conflict_handling = match (env::var_os("MIRI_BLESS").is_some(), skip_ui_checks) { (false, false) => OutputConflictHandling::Error, (true, false) => OutputConflictHandling::Bless, (false, true) => OutputConflictHandling::Ignore, (true, true) => panic!("cannot use MIRI_BLESS and MIRI_SKIP_UI_CHECKS at the same time"), }; - // Pass on all unknown arguments as filters. - let mut quiet = false; - let path_filter = std::env::args().skip(1).filter(|arg| { + // Handle command-line arguments. + config.path_filter.extend(std::env::args().skip(1).filter(|arg| { match &**arg { "--quiet" => { - quiet = true; + config.quiet = true; false } _ => true, } - }); + })); let use_std = env::var_os("MIRI_NO_STD").is_none(); - let config = Config { - args: flags, - target, - stderr_filters: STDERR.clone(), - stdout_filters: STDOUT.clone(), - root_dir: PathBuf::from(path), - mode, - path_filter: path_filter.collect(), - program: miri_path(), - output_conflict_handling, - dependencies_crate_manifest_path: (with_dependencies && use_std) - .then(|| Path::new("test_dependencies").join("Cargo.toml")), - dependency_builder: Some(DependencyBuilder { + if with_dependencies && use_std { + config.dependencies_crate_manifest_path = + Some(Path::new("test_dependencies").join("Cargo.toml")); + config.dependency_builder = Some(DependencyBuilder { program: std::env::var_os("CARGO").unwrap().into(), args: vec![ "run".into(), @@ -124,9 +124,8 @@ fn run_tests( "miri".into(), ], envs: vec![], - }), - quiet, - }; + }); + } ui_test::run_tests(config) } @@ -214,10 +213,10 @@ fn main() -> Result<()> { ui(Mode::Pass, "tests/pass", WithoutDependencies)?; ui(Mode::Pass, "tests/pass-dep", WithDependencies)?; ui(Mode::Panic, "tests/panic", WithDependencies)?; - ui(Mode::Fail, "tests/fail", WithDependencies)?; + ui(Mode::Fail { require_patterns: true }, "tests/fail", WithDependencies)?; if cfg!(target_os = "linux") { ui(Mode::Pass, "tests/extern-so/pass", WithoutDependencies)?; - ui(Mode::Fail, "tests/extern-so/fail", WithDependencies)?; + ui(Mode::Fail { require_patterns: true }, "tests/extern-so/fail", WithDependencies)?; } Ok(()) From eafc100b50684b629268acfb58b417ba1bbb3ceb Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 31 Aug 2022 11:06:35 +0000 Subject: [PATCH 3701/3747] Bump ui_test to 0.3.1 --- Cargo.lock | 4 ++-- Cargo.toml | 2 +- tests/compiletest.rs | 21 +++++++++------------ 3 files changed, 12 insertions(+), 15 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1ce41f0a85e34..28be08c467cd4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -754,9 +754,9 @@ dependencies = [ [[package]] name = "ui_test" -version = "0.2.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee6b579f4a09b0cf15b910e8edbaaae5bc66d0674a892ec4dbd5e8a5d094d979" +checksum = "7d1f546a5883ae78da735bba529ec1116661e2f73582f23920d994dc97da3a22" dependencies = [ "cargo_metadata", "color-eyre", diff --git a/Cargo.toml b/Cargo.toml index fee63359005e2..0a3dfc2a84e31 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -40,7 +40,7 @@ libc = "0.2" [dev-dependencies] colored = "2" -ui_test = "0.2" +ui_test = "0.3.1" # Features chosen to match those required by env_logger, to avoid rebuilds regex = { version = "1.5.5", default-features = false, features = ["perf", "std"] } lazy_static = "1.4.0" diff --git a/tests/compiletest.rs b/tests/compiletest.rs index 924d253b4cfc0..fc5b8c6fa99f7 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -2,7 +2,7 @@ use colored::*; use regex::Regex; use std::path::{Path, PathBuf}; use std::{env, process::Command}; -use ui_test::{color_eyre::Result, Config, DependencyBuilder, Mode, OutputConflictHandling}; +use ui_test::{color_eyre::Result, Config, Mode, OutputConflictHandling}; fn miri_path() -> PathBuf { PathBuf::from(option_env!("MIRI").unwrap_or(env!("CARGO_BIN_EXE_miri"))) @@ -114,17 +114,14 @@ fn run_tests( if with_dependencies && use_std { config.dependencies_crate_manifest_path = Some(Path::new("test_dependencies").join("Cargo.toml")); - config.dependency_builder = Some(DependencyBuilder { - program: std::env::var_os("CARGO").unwrap().into(), - args: vec![ - "run".into(), - "--manifest-path".into(), - "cargo-miri/Cargo.toml".into(), - "--".into(), - "miri".into(), - ], - envs: vec![], - }); + config.dependency_builder.args = vec![ + "run".into(), + "--manifest-path".into(), + "cargo-miri/Cargo.toml".into(), + "--".into(), + "miri".into(), + "run".into(), + ]; } ui_test::run_tests(config) } From 240f92aae8344034f92edc809fcc2581f9bed333 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 31 Aug 2022 13:36:25 +0200 Subject: [PATCH 3702/3747] add comment --- tests/compiletest.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/compiletest.rs b/tests/compiletest.rs index fc5b8c6fa99f7..6b5668e2d6c4c 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -120,7 +120,7 @@ fn run_tests( "cargo-miri/Cargo.toml".into(), "--".into(), "miri".into(), - "run".into(), + "run".into(), // There is no `cargo miri build` so we just use `cargo miri run`. ]; } ui_test::run_tests(config) From 4cb26afc0c25f77d52b6f2c83eba89466d85b214 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 31 Aug 2022 14:44:36 +0200 Subject: [PATCH 3703/3747] fix progress report being deduplicated --- src/diagnostics.rs | 70 +++++++++++++++++++++++++++++++--------------- src/machine.rs | 16 +++++------ 2 files changed, 55 insertions(+), 31 deletions(-) diff --git a/src/diagnostics.rs b/src/diagnostics.rs index 26442da6d655b..3a0d17b22a764 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -70,7 +70,9 @@ pub enum NonHaltingDiagnostic { CreatedAlloc(AllocId, Size, Align, MemoryKind), FreedAlloc(AllocId), RejectedIsolatedOp(String), - ProgressReport, + ProgressReport { + block_count: u64, // how many basic blocks have been run so far + }, Int2Ptr { details: bool, }, @@ -261,6 +263,7 @@ pub fn report_error<'tcx, 'mir>( DiagLevel::Error, &if let Some(title) = title { format!("{}: {}", title, msg[0]) } else { msg[0].clone() }, msg, + vec![], helps, &stacktrace, ); @@ -307,6 +310,7 @@ fn report_msg<'mir, 'tcx>( diag_level: DiagLevel, title: &str, span_msg: Vec, + notes: Vec<(Option, String)>, helps: Vec<(Option, String)>, stacktrace: &[FrameInfo<'tcx>], ) { @@ -331,15 +335,22 @@ fn report_msg<'mir, 'tcx>( err.note("(no span available)"); } - // Show help messages. - if !helps.is_empty() { - for (span_data, help) in helps { - if let Some(span_data) = span_data { - err.span_help(span_data.span(), &help); - } else { - err.help(&help); - } + // Show note and help messages. + for (span_data, note) in ¬es { + if let Some(span_data) = span_data { + err.span_note(span_data.span(), note); + } else { + err.note(note); } + } + for (span_data, help) in &helps { + if let Some(span_data) = span_data { + err.span_help(span_data.span(), help); + } else { + err.help(help); + } + } + if notes.len() + helps.len() > 0 { // Add visual separator before backtrace. err.note("backtrace:"); } @@ -436,6 +447,21 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // Show diagnostics. for e in diagnostics.drain(..) { use NonHaltingDiagnostic::*; + + let (title, diag_level) = match e { + RejectedIsolatedOp(_) => + ("operation rejected by isolation", DiagLevel::Warning), + Int2Ptr { .. } => ("integer-to-pointer cast", DiagLevel::Warning), + CreatedPointerTag(..) + | PoppedPointerTag(..) + | CreatedCallId(..) + | CreatedAlloc(..) + | FreedAlloc(..) + | ProgressReport { .. } + | WeakMemoryOutdatedLoad => + ("tracking was triggered", DiagLevel::Note), + }; + let msg = match e { CreatedPointerTag(tag, None) => format!("created tag {tag:?}"), @@ -465,7 +491,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx format!("freed allocation with id {id}"), RejectedIsolatedOp(ref op) => format!("{op} was made to return an error due to isolation"), - ProgressReport => + ProgressReport { .. } => format!("progress report: current operation being executed is here"), Int2Ptr { .. } => format!("integer-to-pointer cast"), @@ -473,18 +499,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx format!("weak memory emulation: outdated value returned from load"), }; - let (title, diag_level) = match e { - RejectedIsolatedOp(_) => - ("operation rejected by isolation", DiagLevel::Warning), - Int2Ptr { .. } => ("integer-to-pointer cast", DiagLevel::Warning), - CreatedPointerTag(..) - | PoppedPointerTag(..) - | CreatedCallId(..) - | CreatedAlloc(..) - | FreedAlloc(..) - | ProgressReport - | WeakMemoryOutdatedLoad => - ("tracking was triggered", DiagLevel::Note), + let notes = match e { + ProgressReport { block_count } => { + // It is important that each progress report is slightly different, since + // identical diagnostics are being deduplicated. + vec![ + (None, format!("so far, {block_count} basic blocks have been executed")), + ] + } + _ => vec![], }; let helps = match e { @@ -500,7 +523,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx _ => vec![], }; - report_msg(this, diag_level, title, vec![msg], helps, &stacktrace); + report_msg(this, diag_level, title, vec![msg], notes, helps, &stacktrace); } }); } @@ -519,6 +542,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx "the place in the program where the ICE was triggered", vec![], vec![], + vec![], &stacktrace, ); } diff --git a/src/machine.rs b/src/machine.rs index 4f7e3a6a71b13..3be4d1d1b5bcb 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -374,8 +374,8 @@ pub struct Evaluator<'mir, 'tcx> { /// If `Some`, we will report the current stack every N basic blocks. pub(crate) report_progress: Option, - /// The number of blocks that passed since the last progress report. - pub(crate) since_progress_report: u32, + // The total number of blocks that have been executed. + pub(crate) basic_block_count: u64, /// Handle of the optional shared object file for external functions. pub external_so_lib: Option<(libloading::Library, std::path::PathBuf)>, @@ -433,7 +433,7 @@ impl<'mir, 'tcx> Evaluator<'mir, 'tcx> { weak_memory: config.weak_memory_emulation, preemption_rate: config.preemption_rate, report_progress: config.report_progress, - since_progress_report: 0, + basic_block_count: 0, external_so_lib: config.external_so_file.as_ref().map(|lib_file_path| { // Check if host target == the session target. if env!("TARGET") != target_triple { @@ -992,14 +992,14 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { } fn before_terminator(ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx> { + ecx.machine.basic_block_count += 1u64; // a u64 that is only incremented by 1 will "never" overflow // Possibly report our progress. if let Some(report_progress) = ecx.machine.report_progress { - if ecx.machine.since_progress_report >= report_progress { - register_diagnostic(NonHaltingDiagnostic::ProgressReport); - ecx.machine.since_progress_report = 0; + if ecx.machine.basic_block_count % u64::from(report_progress) == 0 { + register_diagnostic(NonHaltingDiagnostic::ProgressReport { + block_count: ecx.machine.basic_block_count, + }); } - // Cannot overflow, since it is strictly less than `report_progress`. - ecx.machine.since_progress_report += 1; } // These are our preemption points. ecx.maybe_preempt_active_thread(); From 671a4b8b0ff3d4e32f2e55eaf8389e69433535df Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 31 Aug 2022 14:51:05 +0200 Subject: [PATCH 3704/3747] make backtrace header a bit more visible --- src/diagnostics.rs | 2 +- tests/extern-so/fail/function_not_in_so.stderr | 2 +- tests/fail/alloc/deallocate-bad-alignment.stderr | 2 +- tests/fail/alloc/deallocate-bad-size.stderr | 2 +- tests/fail/alloc/deallocate-twice.stderr | 2 +- tests/fail/alloc/global_system_mixup.stderr | 2 +- tests/fail/alloc/no_global_allocator.stderr | 2 +- tests/fail/alloc/reallocate-bad-size.stderr | 2 +- tests/fail/alloc/reallocate-change-alloc.stderr | 2 +- tests/fail/alloc/reallocate-dangling.stderr | 2 +- tests/fail/alloc/stack_free.stderr | 2 +- tests/fail/box-cell-alias.stderr | 2 +- tests/fail/branchless-select-i128-pointer.stderr | 2 +- tests/fail/concurrency/libc_pthread_create_too_few_args.stderr | 2 +- tests/fail/concurrency/libc_pthread_create_too_many_args.stderr | 2 +- tests/fail/concurrency/libc_pthread_join_detached.stderr | 2 +- tests/fail/concurrency/libc_pthread_join_joined.stderr | 2 +- tests/fail/concurrency/libc_pthread_join_main.stderr | 2 +- tests/fail/concurrency/libc_pthread_join_multiple.stderr | 2 +- tests/fail/concurrency/libc_pthread_join_self.stderr | 2 +- tests/fail/concurrency/read_only_atomic_cmpxchg.stderr | 2 +- tests/fail/concurrency/read_only_atomic_load.stderr | 2 +- tests/fail/concurrency/thread_local_static_dealloc.stderr | 2 +- tests/fail/concurrency/unwind_top_of_stack.stderr | 2 +- tests/fail/concurrency/windows_join_detached.stderr | 2 +- tests/fail/crates/tokio_mvp.stderr | 2 +- tests/fail/dangling_pointers/dangling_pointer_addr_of.stderr | 2 +- tests/fail/dangling_pointers/dangling_pointer_deref.stderr | 2 +- tests/fail/dangling_pointers/dangling_zst_deref.stderr | 2 +- tests/fail/dangling_pointers/deref-invalid-ptr.stderr | 2 +- tests/fail/dangling_pointers/deref-partially-dangling.stderr | 2 +- tests/fail/dangling_pointers/dyn_size.stderr | 2 +- .../fail/dangling_pointers/maybe_null_pointer_deref_zst.stderr | 2 +- .../fail/dangling_pointers/maybe_null_pointer_write_zst.stderr | 2 +- tests/fail/dangling_pointers/null_pointer_deref.stderr | 2 +- tests/fail/dangling_pointers/null_pointer_deref_zst.stderr | 2 +- tests/fail/dangling_pointers/null_pointer_write.stderr | 2 +- tests/fail/dangling_pointers/null_pointer_write_zst.stderr | 2 +- tests/fail/dangling_pointers/out_of_bounds_read1.stderr | 2 +- tests/fail/dangling_pointers/out_of_bounds_read2.stderr | 2 +- tests/fail/dangling_pointers/stack_temporary.stderr | 2 +- tests/fail/dangling_pointers/storage_dead_dangling.stderr | 2 +- tests/fail/dangling_pointers/wild_pointer_deref.stderr | 2 +- tests/fail/data_race/alloc_read_race.stderr | 2 +- tests/fail/data_race/alloc_write_race.stderr | 2 +- tests/fail/data_race/atomic_read_na_write_race1.stderr | 2 +- tests/fail/data_race/atomic_read_na_write_race2.stderr | 2 +- tests/fail/data_race/atomic_write_na_read_race1.stderr | 2 +- tests/fail/data_race/atomic_write_na_read_race2.stderr | 2 +- tests/fail/data_race/atomic_write_na_write_race1.stderr | 2 +- tests/fail/data_race/atomic_write_na_write_race2.stderr | 2 +- tests/fail/data_race/dangling_thread_async_race.stderr | 2 +- tests/fail/data_race/dangling_thread_race.stderr | 2 +- tests/fail/data_race/dealloc_read_race1.stderr | 2 +- tests/fail/data_race/dealloc_read_race2.stderr | 2 +- tests/fail/data_race/dealloc_read_race_stack.stderr | 2 +- tests/fail/data_race/dealloc_write_race1.stderr | 2 +- tests/fail/data_race/dealloc_write_race2.stderr | 2 +- tests/fail/data_race/dealloc_write_race_stack.stderr | 2 +- tests/fail/data_race/enable_after_join_to_main.stderr | 2 +- tests/fail/data_race/fence_after_load.stderr | 2 +- tests/fail/data_race/read_write_race.stderr | 2 +- tests/fail/data_race/read_write_race_stack.stderr | 2 +- tests/fail/data_race/relax_acquire_race.stderr | 2 +- tests/fail/data_race/release_seq_race.stderr | 2 +- tests/fail/data_race/release_seq_race_same_thread.stderr | 2 +- tests/fail/data_race/rmw_race.stderr | 2 +- tests/fail/data_race/stack_pop_race.stderr | 2 +- tests/fail/data_race/write_write_race.stderr | 2 +- tests/fail/data_race/write_write_race_stack.stderr | 2 +- tests/fail/dyn-call-trait-mismatch.stderr | 2 +- tests/fail/dyn-upcast-trait-mismatch.stderr | 2 +- tests/fail/environ-gets-deallocated.stderr | 2 +- tests/fail/extern_static.stderr | 2 +- tests/fail/extern_static_in_const.stderr | 2 +- tests/fail/extern_static_wrong_size.stderr | 2 +- tests/fail/fast_math_both.stderr | 2 +- tests/fail/fast_math_first.stderr | 2 +- tests/fail/fast_math_second.stderr | 2 +- tests/fail/function_calls/check_arg_abi.stderr | 2 +- tests/fail/function_calls/check_arg_count_abort.stderr | 2 +- tests/fail/function_calls/check_arg_count_too_few_args.stderr | 2 +- tests/fail/function_calls/check_arg_count_too_many_args.stderr | 2 +- tests/fail/function_calls/check_callback_abi.stderr | 2 +- .../function_calls/exported_symbol_abi_mismatch.cache.stderr | 2 +- .../function_calls/exported_symbol_abi_mismatch.fn_ptr.stderr | 2 +- .../function_calls/exported_symbol_abi_mismatch.no_cache.stderr | 2 +- tests/fail/function_calls/exported_symbol_bad_unwind1.stderr | 2 +- .../exported_symbol_bad_unwind2.extern_block.stderr | 2 +- tests/fail/function_calls/exported_symbol_clashing.stderr | 2 +- tests/fail/function_calls/exported_symbol_shim_clashing.stderr | 2 +- .../fail/function_calls/exported_symbol_wrong_arguments.stderr | 2 +- tests/fail/function_calls/exported_symbol_wrong_type.stderr | 2 +- tests/fail/function_pointers/cast_box_int_to_fn_ptr.stderr | 2 +- tests/fail/function_pointers/cast_fn_ptr1.stderr | 2 +- tests/fail/function_pointers/cast_fn_ptr2.stderr | 2 +- tests/fail/function_pointers/cast_fn_ptr3.stderr | 2 +- tests/fail/function_pointers/cast_fn_ptr4.stderr | 2 +- tests/fail/function_pointers/cast_fn_ptr5.stderr | 2 +- tests/fail/function_pointers/cast_int_to_fn_ptr.stderr | 2 +- tests/fail/function_pointers/deref_fn_ptr.stderr | 2 +- tests/fail/function_pointers/execute_memory.stderr | 2 +- tests/fail/function_pointers/fn_ptr_offset.stderr | 2 +- tests/fail/generator-pinned-moved.stderr | 2 +- tests/fail/intrinsics/assume.stderr | 2 +- tests/fail/intrinsics/copy_null.stderr | 2 +- tests/fail/intrinsics/copy_overflow.stderr | 2 +- tests/fail/intrinsics/copy_overlapping.stderr | 2 +- tests/fail/intrinsics/copy_unaligned.stderr | 2 +- tests/fail/intrinsics/ctlz_nonzero.stderr | 2 +- tests/fail/intrinsics/cttz_nonzero.stderr | 2 +- tests/fail/intrinsics/div-by-zero.stderr | 2 +- tests/fail/intrinsics/exact_div1.stderr | 2 +- tests/fail/intrinsics/exact_div2.stderr | 2 +- tests/fail/intrinsics/exact_div3.stderr | 2 +- tests/fail/intrinsics/exact_div4.stderr | 2 +- tests/fail/intrinsics/float_to_int_32_inf1.stderr | 2 +- tests/fail/intrinsics/float_to_int_32_infneg1.stderr | 2 +- tests/fail/intrinsics/float_to_int_32_nan.stderr | 2 +- tests/fail/intrinsics/float_to_int_32_nanneg.stderr | 2 +- tests/fail/intrinsics/float_to_int_32_neg.stderr | 2 +- tests/fail/intrinsics/float_to_int_32_too_big1.stderr | 2 +- tests/fail/intrinsics/float_to_int_32_too_big2.stderr | 2 +- tests/fail/intrinsics/float_to_int_32_too_small1.stderr | 2 +- tests/fail/intrinsics/float_to_int_64_inf1.stderr | 2 +- tests/fail/intrinsics/float_to_int_64_infneg1.stderr | 2 +- tests/fail/intrinsics/float_to_int_64_infneg2.stderr | 2 +- tests/fail/intrinsics/float_to_int_64_nan.stderr | 2 +- tests/fail/intrinsics/float_to_int_64_neg.stderr | 2 +- tests/fail/intrinsics/float_to_int_64_too_big1.stderr | 2 +- tests/fail/intrinsics/float_to_int_64_too_big2.stderr | 2 +- tests/fail/intrinsics/float_to_int_64_too_big3.stderr | 2 +- tests/fail/intrinsics/float_to_int_64_too_big4.stderr | 2 +- tests/fail/intrinsics/float_to_int_64_too_big5.stderr | 2 +- tests/fail/intrinsics/float_to_int_64_too_big6.stderr | 2 +- tests/fail/intrinsics/float_to_int_64_too_big7.stderr | 2 +- tests/fail/intrinsics/float_to_int_64_too_small1.stderr | 2 +- tests/fail/intrinsics/float_to_int_64_too_small2.stderr | 2 +- tests/fail/intrinsics/float_to_int_64_too_small3.stderr | 2 +- tests/fail/intrinsics/out_of_bounds_ptr_1.stderr | 2 +- tests/fail/intrinsics/out_of_bounds_ptr_2.stderr | 2 +- tests/fail/intrinsics/out_of_bounds_ptr_3.stderr | 2 +- tests/fail/intrinsics/overflowing-unchecked-rsh.stderr | 2 +- tests/fail/intrinsics/ptr_offset_0_plus_0.stderr | 2 +- tests/fail/intrinsics/ptr_offset_from_oob.stderr | 2 +- tests/fail/intrinsics/ptr_offset_from_unsigned_neg.stderr | 2 +- tests/fail/intrinsics/ptr_offset_int_plus_int.stderr | 2 +- tests/fail/intrinsics/ptr_offset_int_plus_ptr.stderr | 2 +- tests/fail/intrinsics/ptr_offset_overflow.stderr | 2 +- tests/fail/intrinsics/ptr_offset_ptr_plus_0.stderr | 2 +- tests/fail/intrinsics/raw_eq_on_ptr.stderr | 2 +- tests/fail/intrinsics/rem-by-zero.stderr | 2 +- tests/fail/intrinsics/simd-div-by-zero.stderr | 2 +- tests/fail/intrinsics/simd-div-overflow.stderr | 2 +- tests/fail/intrinsics/simd-float-to-int.stderr | 2 +- tests/fail/intrinsics/simd-gather.stderr | 2 +- tests/fail/intrinsics/simd-reduce-invalid-bool.stderr | 2 +- tests/fail/intrinsics/simd-rem-by-zero.stderr | 2 +- tests/fail/intrinsics/simd-scatter.stderr | 2 +- tests/fail/intrinsics/simd-select-bitmask-invalid.stderr | 2 +- tests/fail/intrinsics/simd-select-invalid-bool.stderr | 2 +- tests/fail/intrinsics/simd-shl-too-far.stderr | 2 +- tests/fail/intrinsics/simd-shr-too-far.stderr | 2 +- tests/fail/intrinsics/unchecked_add1.stderr | 2 +- tests/fail/intrinsics/unchecked_add2.stderr | 2 +- tests/fail/intrinsics/unchecked_div1.stderr | 2 +- tests/fail/intrinsics/unchecked_mul1.stderr | 2 +- tests/fail/intrinsics/unchecked_mul2.stderr | 2 +- tests/fail/intrinsics/unchecked_sub1.stderr | 2 +- tests/fail/intrinsics/unchecked_sub2.stderr | 2 +- tests/fail/intrinsics/write_bytes_null.stderr | 2 +- tests/fail/intrinsics/write_bytes_overflow.stderr | 2 +- tests/fail/invalid_bool.stderr | 2 +- tests/fail/invalid_char.stderr | 2 +- tests/fail/invalid_enum_tag.stderr | 2 +- tests/fail/invalid_int.stderr | 2 +- tests/fail/issue-miri-1112.stderr | 2 +- tests/fail/issue-miri-2432.stderr | 2 +- tests/fail/modifying_constants.stderr | 2 +- tests/fail/never_say_never.stderr | 2 +- tests/fail/never_transmute_humans.stderr | 2 +- tests/fail/never_transmute_void.stderr | 2 +- tests/fail/panic/bad_miri_start_panic.stderr | 2 +- tests/fail/panic/bad_unwind.stderr | 2 +- tests/fail/panic/unwind_panic_abort.stderr | 2 +- tests/fail/pointer_partial_overwrite.stderr | 2 +- tests/fail/provenance/provenance_transmute.stderr | 2 +- tests/fail/provenance/ptr_int_unexposed.stderr | 2 +- tests/fail/provenance/ptr_invalid.stderr | 2 +- tests/fail/provenance/ptr_invalid_offset.stderr | 2 +- tests/fail/provenance/strict_provenance_cast.stderr | 2 +- tests/fail/rc_as_ptr.stderr | 2 +- tests/fail/reading_half_a_pointer.stderr | 2 +- tests/fail/shims/backtrace/bad-backtrace-decl.stderr | 2 +- tests/fail/shims/backtrace/bad-backtrace-flags.stderr | 2 +- tests/fail/shims/backtrace/bad-backtrace-ptr.stderr | 2 +- tests/fail/shims/backtrace/bad-backtrace-resolve-flags.stderr | 2 +- .../shims/backtrace/bad-backtrace-resolve-names-flags.stderr | 2 +- tests/fail/shims/backtrace/bad-backtrace-size-flags.stderr | 2 +- tests/fail/shims/fs/close_stdout.stderr | 2 +- tests/fail/shims/fs/isolated_file.stderr | 2 +- tests/fail/shims/fs/isolated_stdin.stderr | 2 +- tests/fail/shims/fs/mkstemp_immutable_arg.stderr | 2 +- tests/fail/shims/fs/read_from_stdout.stderr | 2 +- tests/fail/shims/fs/unix_open_missing_required_mode.stderr | 2 +- tests/fail/shims/fs/write_to_stdin.stderr | 2 +- tests/fail/shims/shim_arg_size.64bit.stderr | 2 +- tests/fail/shims/sync/libc_pthread_cond_double_destroy.stderr | 2 +- .../fail/shims/sync/libc_pthread_condattr_double_destroy.stderr | 2 +- tests/fail/shims/sync/libc_pthread_mutex_NULL_deadlock.stderr | 2 +- .../fail/shims/sync/libc_pthread_mutex_default_deadlock.stderr | 2 +- tests/fail/shims/sync/libc_pthread_mutex_destroy_locked.stderr | 2 +- tests/fail/shims/sync/libc_pthread_mutex_double_destroy.stderr | 2 +- .../shims/sync/libc_pthread_mutex_normal_unlock_unlocked.stderr | 2 +- tests/fail/shims/sync/libc_pthread_mutex_wrong_owner.stderr | 2 +- .../shims/sync/libc_pthread_mutexattr_double_destroy.stderr | 2 +- .../shims/sync/libc_pthread_rwlock_destroy_read_locked.stderr | 2 +- .../shims/sync/libc_pthread_rwlock_destroy_write_locked.stderr | 2 +- tests/fail/shims/sync/libc_pthread_rwlock_double_destroy.stderr | 2 +- .../fail/shims/sync/libc_pthread_rwlock_read_wrong_owner.stderr | 2 +- .../fail/shims/sync/libc_pthread_rwlock_unlock_unlocked.stderr | 2 +- .../shims/sync/libc_pthread_rwlock_write_wrong_owner.stderr | 2 +- tests/fail/should-pass/cpp20_rwc_syncs.stderr | 2 +- tests/fail/stacked_borrows/alias_through_mutation.stderr | 2 +- tests/fail/stacked_borrows/aliasing_mut1.stderr | 2 +- tests/fail/stacked_borrows/aliasing_mut2.stderr | 2 +- tests/fail/stacked_borrows/aliasing_mut3.stderr | 2 +- tests/fail/stacked_borrows/aliasing_mut4.stderr | 2 +- tests/fail/stacked_borrows/box_exclusive_violation1.stderr | 2 +- tests/fail/stacked_borrows/buggy_as_mut_slice.stderr | 2 +- tests/fail/stacked_borrows/buggy_split_at_mut.stderr | 2 +- tests/fail/stacked_borrows/deallocate_against_protector1.stderr | 2 +- tests/fail/stacked_borrows/deallocate_against_protector2.stderr | 2 +- .../fail/stacked_borrows/disable_mut_does_not_merge_srw.stderr | 2 +- tests/fail/stacked_borrows/exposed_only_ro.stderr | 2 +- tests/fail/stacked_borrows/fnentry_invalidation.stderr | 2 +- tests/fail/stacked_borrows/illegal_read1.stderr | 2 +- tests/fail/stacked_borrows/illegal_read2.stderr | 2 +- tests/fail/stacked_borrows/illegal_read3.stderr | 2 +- tests/fail/stacked_borrows/illegal_read4.stderr | 2 +- tests/fail/stacked_borrows/illegal_read5.stderr | 2 +- tests/fail/stacked_borrows/illegal_read6.stderr | 2 +- tests/fail/stacked_borrows/illegal_read7.stderr | 2 +- tests/fail/stacked_borrows/illegal_read8.stderr | 2 +- tests/fail/stacked_borrows/illegal_read_despite_exposed1.stderr | 2 +- tests/fail/stacked_borrows/illegal_read_despite_exposed2.stderr | 2 +- tests/fail/stacked_borrows/illegal_write1.stderr | 2 +- tests/fail/stacked_borrows/illegal_write2.stderr | 2 +- tests/fail/stacked_borrows/illegal_write3.stderr | 2 +- tests/fail/stacked_borrows/illegal_write4.stderr | 2 +- tests/fail/stacked_borrows/illegal_write5.stderr | 2 +- tests/fail/stacked_borrows/illegal_write6.stderr | 2 +- .../fail/stacked_borrows/illegal_write_despite_exposed1.stderr | 2 +- tests/fail/stacked_borrows/interior_mut1.stderr | 2 +- tests/fail/stacked_borrows/interior_mut2.stderr | 2 +- tests/fail/stacked_borrows/invalidate_against_protector1.stderr | 2 +- tests/fail/stacked_borrows/invalidate_against_protector2.stderr | 2 +- tests/fail/stacked_borrows/issue-miri-1050-1.stderr | 2 +- tests/fail/stacked_borrows/issue-miri-1050-2.stderr | 2 +- tests/fail/stacked_borrows/load_invalid_mut.stderr | 2 +- tests/fail/stacked_borrows/load_invalid_shr.stderr | 2 +- tests/fail/stacked_borrows/mut_exclusive_violation1.stderr | 2 +- tests/fail/stacked_borrows/mut_exclusive_violation2.stderr | 2 +- tests/fail/stacked_borrows/newtype_retagging.stderr | 2 +- tests/fail/stacked_borrows/outdated_local.stderr | 2 +- tests/fail/stacked_borrows/pass_invalid_mut.stderr | 2 +- tests/fail/stacked_borrows/pass_invalid_shr.stderr | 2 +- tests/fail/stacked_borrows/pointer_smuggling.stderr | 2 +- tests/fail/stacked_borrows/raw_tracking.stderr | 2 +- tests/fail/stacked_borrows/return_invalid_mut.stderr | 2 +- tests/fail/stacked_borrows/return_invalid_mut_option.stderr | 2 +- tests/fail/stacked_borrows/return_invalid_mut_tuple.stderr | 2 +- tests/fail/stacked_borrows/return_invalid_shr.stderr | 2 +- tests/fail/stacked_borrows/return_invalid_shr_option.stderr | 2 +- tests/fail/stacked_borrows/return_invalid_shr_tuple.stderr | 2 +- tests/fail/stacked_borrows/shared_rw_borrows_are_weak1.stderr | 2 +- tests/fail/stacked_borrows/shared_rw_borrows_are_weak2.stderr | 2 +- tests/fail/stacked_borrows/shr_frozen_violation1.stderr | 2 +- tests/fail/stacked_borrows/static_memory_modification.stderr | 2 +- tests/fail/stacked_borrows/track_caller.stderr | 2 +- tests/fail/stacked_borrows/transmute-is-no-escape.stderr | 2 +- tests/fail/stacked_borrows/unescaped_local.stderr | 2 +- tests/fail/stacked_borrows/unescaped_static.stderr | 2 +- tests/fail/stacked_borrows/zst_slice.stderr | 2 +- tests/fail/static_memory_modification1.stderr | 2 +- tests/fail/static_memory_modification2.stderr | 2 +- tests/fail/static_memory_modification3.stderr | 2 +- tests/fail/transmute-pair-uninit.stderr | 2 +- tests/fail/transmute_fat1.stderr | 2 +- tests/fail/unaligned_pointers/alignment.stderr | 2 +- tests/fail/unaligned_pointers/atomic_unaligned.stderr | 2 +- tests/fail/unaligned_pointers/dyn_alignment.stderr | 2 +- tests/fail/unaligned_pointers/intptrcast_alignment_check.stderr | 2 +- tests/fail/unaligned_pointers/reference_to_packed.stderr | 2 +- tests/fail/unaligned_pointers/unaligned_ptr1.stderr | 2 +- tests/fail/unaligned_pointers/unaligned_ptr2.stderr | 2 +- tests/fail/unaligned_pointers/unaligned_ptr3.stderr | 2 +- tests/fail/unaligned_pointers/unaligned_ptr4.stderr | 2 +- tests/fail/unaligned_pointers/unaligned_ptr_addr_of.stderr | 2 +- tests/fail/unaligned_pointers/unaligned_ptr_zst.stderr | 2 +- tests/fail/uninit_buffer.stderr | 2 +- tests/fail/uninit_byte_read.stderr | 2 +- tests/fail/unreachable.stderr | 2 +- tests/fail/unsized-local.stderr | 2 +- tests/fail/unsupported_foreign_function.stderr | 2 +- tests/fail/unsupported_signal.stderr | 2 +- tests/fail/validity/cast_fn_ptr1.stderr | 2 +- tests/fail/validity/cast_fn_ptr2.stderr | 2 +- tests/fail/validity/dangling_ref1.stderr | 2 +- tests/fail/validity/dangling_ref2.stderr | 2 +- tests/fail/validity/dangling_ref3.stderr | 2 +- tests/fail/validity/invalid_bool.stderr | 2 +- tests/fail/validity/invalid_bool_uninit.stderr | 2 +- tests/fail/validity/invalid_char.stderr | 2 +- tests/fail/validity/invalid_char_uninit.stderr | 2 +- tests/fail/validity/invalid_enum_tag.stderr | 2 +- tests/fail/validity/invalid_fnptr_null.stderr | 2 +- tests/fail/validity/invalid_fnptr_uninit.stderr | 2 +- tests/fail/validity/invalid_wide_raw.stderr | 2 +- tests/fail/validity/nonzero.stderr | 2 +- tests/fail/validity/ptr_integer_array_transmute.stderr | 2 +- tests/fail/validity/ref_to_uninhabited1.stderr | 2 +- tests/fail/validity/ref_to_uninhabited2.stderr | 2 +- tests/fail/validity/too-big-slice.stderr | 2 +- tests/fail/validity/too-big-unsized.stderr | 2 +- tests/fail/validity/transmute_through_ptr.stderr | 2 +- tests/fail/validity/uninit_float.stderr | 2 +- tests/fail/validity/uninit_integer.stderr | 2 +- tests/fail/validity/uninit_raw_ptr.stderr | 2 +- tests/fail/weak_memory/racing_mixed_size.stderr | 2 +- tests/fail/weak_memory/racing_mixed_size_read.stderr | 2 +- tests/fail/zst1.stderr | 2 +- tests/fail/zst2.stderr | 2 +- tests/fail/zst3.stderr | 2 +- tests/pass/box.stderr | 2 +- tests/pass/extern_types.stderr | 2 +- tests/pass/stacked-borrows/issue-miri-2389.stderr | 2 +- 337 files changed, 337 insertions(+), 337 deletions(-) diff --git a/src/diagnostics.rs b/src/diagnostics.rs index 3a0d17b22a764..74d2fe2680a4c 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -352,7 +352,7 @@ fn report_msg<'mir, 'tcx>( } if notes.len() + helps.len() > 0 { // Add visual separator before backtrace. - err.note("backtrace:"); + err.note("BACKTRACE:"); } // Add backtrace for (idx, frame_info) in stacktrace.iter().enumerate() { diff --git a/tests/extern-so/fail/function_not_in_so.stderr b/tests/extern-so/fail/function_not_in_so.stderr index 8ff9ca74bc584..f649f0ae43e30 100644 --- a/tests/extern-so/fail/function_not_in_so.stderr +++ b/tests/extern-so/fail/function_not_in_so.stderr @@ -5,7 +5,7 @@ LL | foo(); | ^^^^^ can't call foreign function: foo | = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/function_not_in_so.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/alloc/deallocate-bad-alignment.stderr b/tests/fail/alloc/deallocate-bad-alignment.stderr index e46533ad70d3e..28439b54b2908 100644 --- a/tests/fail/alloc/deallocate-bad-alignment.stderr +++ b/tests/fail/alloc/deallocate-bad-alignment.stderr @@ -6,7 +6,7 @@ LL | unsafe { __rust_dealloc(ptr, layout.size(), layout.align()) } | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `std::alloc::dealloc` at RUSTLIB/alloc/src/alloc.rs:LL:CC note: inside `main` at $DIR/deallocate-bad-alignment.rs:LL:CC --> $DIR/deallocate-bad-alignment.rs:LL:CC diff --git a/tests/fail/alloc/deallocate-bad-size.stderr b/tests/fail/alloc/deallocate-bad-size.stderr index d3ca2a4544bf1..a6ceab1f56f51 100644 --- a/tests/fail/alloc/deallocate-bad-size.stderr +++ b/tests/fail/alloc/deallocate-bad-size.stderr @@ -6,7 +6,7 @@ LL | unsafe { __rust_dealloc(ptr, layout.size(), layout.align()) } | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `std::alloc::dealloc` at RUSTLIB/alloc/src/alloc.rs:LL:CC note: inside `main` at $DIR/deallocate-bad-size.rs:LL:CC --> $DIR/deallocate-bad-size.rs:LL:CC diff --git a/tests/fail/alloc/deallocate-twice.stderr b/tests/fail/alloc/deallocate-twice.stderr index 1fadb277a0e40..b6c5b6f97ee7b 100644 --- a/tests/fail/alloc/deallocate-twice.stderr +++ b/tests/fail/alloc/deallocate-twice.stderr @@ -6,7 +6,7 @@ LL | unsafe { __rust_dealloc(ptr, layout.size(), layout.align()) } | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `std::alloc::dealloc` at RUSTLIB/alloc/src/alloc.rs:LL:CC note: inside `main` at $DIR/deallocate-twice.rs:LL:CC --> $DIR/deallocate-twice.rs:LL:CC diff --git a/tests/fail/alloc/global_system_mixup.stderr b/tests/fail/alloc/global_system_mixup.stderr index 60b91155f5e53..4ee85add6c228 100644 --- a/tests/fail/alloc/global_system_mixup.stderr +++ b/tests/fail/alloc/global_system_mixup.stderr @@ -6,7 +6,7 @@ LL | FREE(); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `std::sys::PLATFORM::alloc::::dealloc` at RUSTLIB/std/src/sys/PLATFORM/alloc.rs:LL:CC = note: inside `::deallocate` at RUSTLIB/std/src/alloc.rs:LL:CC note: inside `main` at $DIR/global_system_mixup.rs:LL:CC diff --git a/tests/fail/alloc/no_global_allocator.stderr b/tests/fail/alloc/no_global_allocator.stderr index 5c11df9539c1c..ea70970ae0fef 100644 --- a/tests/fail/alloc/no_global_allocator.stderr +++ b/tests/fail/alloc/no_global_allocator.stderr @@ -5,7 +5,7 @@ LL | __rust_alloc(1, 1); | ^^^^^^^^^^^^^^^^^^ can't call foreign function: __rust_alloc | = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support - = note: backtrace: + = note: BACKTRACE: = note: inside `start` at $DIR/no_global_allocator.rs:LL:CC error: aborting due to previous error diff --git a/tests/fail/alloc/reallocate-bad-size.stderr b/tests/fail/alloc/reallocate-bad-size.stderr index abe47e29ed324..c11b5a851048f 100644 --- a/tests/fail/alloc/reallocate-bad-size.stderr +++ b/tests/fail/alloc/reallocate-bad-size.stderr @@ -6,7 +6,7 @@ LL | unsafe { __rust_realloc(ptr, layout.size(), layout.align(), new_size) } | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `std::alloc::realloc` at RUSTLIB/alloc/src/alloc.rs:LL:CC note: inside `main` at $DIR/reallocate-bad-size.rs:LL:CC --> $DIR/reallocate-bad-size.rs:LL:CC diff --git a/tests/fail/alloc/reallocate-change-alloc.stderr b/tests/fail/alloc/reallocate-change-alloc.stderr index c22e44b754c9a..5631dcb4cc084 100644 --- a/tests/fail/alloc/reallocate-change-alloc.stderr +++ b/tests/fail/alloc/reallocate-change-alloc.stderr @@ -6,7 +6,7 @@ LL | let _z = *x; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/reallocate-change-alloc.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/alloc/reallocate-dangling.stderr b/tests/fail/alloc/reallocate-dangling.stderr index 5eeaab8700c8d..c7db5a729048c 100644 --- a/tests/fail/alloc/reallocate-dangling.stderr +++ b/tests/fail/alloc/reallocate-dangling.stderr @@ -6,7 +6,7 @@ LL | unsafe { __rust_realloc(ptr, layout.size(), layout.align(), new_size) } | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `std::alloc::realloc` at RUSTLIB/alloc/src/alloc.rs:LL:CC note: inside `main` at $DIR/reallocate-dangling.rs:LL:CC --> $DIR/reallocate-dangling.rs:LL:CC diff --git a/tests/fail/alloc/stack_free.stderr b/tests/fail/alloc/stack_free.stderr index 6ce522df58d6e..44991542b1350 100644 --- a/tests/fail/alloc/stack_free.stderr +++ b/tests/fail/alloc/stack_free.stderr @@ -6,7 +6,7 @@ LL | unsafe { __rust_dealloc(ptr, layout.size(), layout.align()) } | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `std::alloc::dealloc` at RUSTLIB/alloc/src/alloc.rs:LL:CC = note: inside `::deallocate` at RUSTLIB/alloc/src/alloc.rs:LL:CC = note: inside `alloc::alloc::box_free::` at RUSTLIB/alloc/src/alloc.rs:LL:CC diff --git a/tests/fail/box-cell-alias.stderr b/tests/fail/box-cell-alias.stderr index 1436afcd212be..8370163997687 100644 --- a/tests/fail/box-cell-alias.stderr +++ b/tests/fail/box-cell-alias.stderr @@ -19,7 +19,7 @@ help: was later invalidated at offsets [0x0..0x1] by a Unique retag | LL | let res = helper(val, ptr); | ^^^ - = note: backtrace: + = note: BACKTRACE: = note: inside `helper` at $DIR/box-cell-alias.rs:LL:CC note: inside `main` at $DIR/box-cell-alias.rs:LL:CC --> $DIR/box-cell-alias.rs:LL:CC diff --git a/tests/fail/branchless-select-i128-pointer.stderr b/tests/fail/branchless-select-i128-pointer.stderr index 15befcd126553..96f2ff3282c82 100644 --- a/tests/fail/branchless-select-i128-pointer.stderr +++ b/tests/fail/branchless-select-i128-pointer.stderr @@ -10,7 +10,7 @@ LL | | ) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/branchless-select-i128-pointer.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/concurrency/libc_pthread_create_too_few_args.stderr b/tests/fail/concurrency/libc_pthread_create_too_few_args.stderr index 2304b42b2c786..94463bef8f0fe 100644 --- a/tests/fail/concurrency/libc_pthread_create_too_few_args.stderr +++ b/tests/fail/concurrency/libc_pthread_create_too_few_args.stderr @@ -6,7 +6,7 @@ LL | panic!() | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `thread_start` at RUSTLIB/std/src/panic.rs:LL:CC = note: this error originates in the macro `$crate::panic::panic_2015` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/fail/concurrency/libc_pthread_create_too_many_args.stderr b/tests/fail/concurrency/libc_pthread_create_too_many_args.stderr index 49c7f579970f2..fdbe91cc8a803 100644 --- a/tests/fail/concurrency/libc_pthread_create_too_many_args.stderr +++ b/tests/fail/concurrency/libc_pthread_create_too_many_args.stderr @@ -6,7 +6,7 @@ LL | panic!() | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `thread_start` at RUSTLIB/std/src/panic.rs:LL:CC = note: this error originates in the macro `$crate::panic::panic_2015` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/fail/concurrency/libc_pthread_join_detached.stderr b/tests/fail/concurrency/libc_pthread_join_detached.stderr index 92b693c0fd6bf..763e0d3665d8f 100644 --- a/tests/fail/concurrency/libc_pthread_join_detached.stderr +++ b/tests/fail/concurrency/libc_pthread_join_detached.stderr @@ -6,7 +6,7 @@ LL | assert_eq!(libc::pthread_join(native, ptr::null_mut()), 0); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/libc_pthread_join_detached.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/concurrency/libc_pthread_join_joined.stderr b/tests/fail/concurrency/libc_pthread_join_joined.stderr index f11b94cde8ee6..a3253e2ef933b 100644 --- a/tests/fail/concurrency/libc_pthread_join_joined.stderr +++ b/tests/fail/concurrency/libc_pthread_join_joined.stderr @@ -6,7 +6,7 @@ LL | assert_eq!(libc::pthread_join(native, ptr::null_mut()), 0); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/libc_pthread_join_joined.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/concurrency/libc_pthread_join_main.stderr b/tests/fail/concurrency/libc_pthread_join_main.stderr index c162f37b309f7..09e14d46a967f 100644 --- a/tests/fail/concurrency/libc_pthread_join_main.stderr +++ b/tests/fail/concurrency/libc_pthread_join_main.stderr @@ -6,7 +6,7 @@ LL | assert_eq!(libc::pthread_join(thread_id, ptr::null_mut()), 0); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside closure at $DIR/libc_pthread_join_main.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/concurrency/libc_pthread_join_multiple.stderr b/tests/fail/concurrency/libc_pthread_join_multiple.stderr index c0c73086f14d6..db5d7bfd5daef 100644 --- a/tests/fail/concurrency/libc_pthread_join_multiple.stderr +++ b/tests/fail/concurrency/libc_pthread_join_multiple.stderr @@ -6,7 +6,7 @@ LL | ... assert_eq!(libc::pthread_join(native_copy, ptr::null_mut()), 0); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside closure at $DIR/libc_pthread_join_multiple.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/concurrency/libc_pthread_join_self.stderr b/tests/fail/concurrency/libc_pthread_join_self.stderr index 38e758e46c125..8db4a83f9cebb 100644 --- a/tests/fail/concurrency/libc_pthread_join_self.stderr +++ b/tests/fail/concurrency/libc_pthread_join_self.stderr @@ -6,7 +6,7 @@ LL | assert_eq!(libc::pthread_join(native, ptr::null_mut()), 0); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside closure at $DIR/libc_pthread_join_self.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/concurrency/read_only_atomic_cmpxchg.stderr b/tests/fail/concurrency/read_only_atomic_cmpxchg.stderr index b90dc5c9d6cd5..d51fdee0b256f 100644 --- a/tests/fail/concurrency/read_only_atomic_cmpxchg.stderr +++ b/tests/fail/concurrency/read_only_atomic_cmpxchg.stderr @@ -12,7 +12,7 @@ please report an issue at if this is | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/read_only_atomic_cmpxchg.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/concurrency/read_only_atomic_load.stderr b/tests/fail/concurrency/read_only_atomic_load.stderr index b19d3755fbb04..17851d6b470b4 100644 --- a/tests/fail/concurrency/read_only_atomic_load.stderr +++ b/tests/fail/concurrency/read_only_atomic_load.stderr @@ -12,7 +12,7 @@ please report an issue at if this is | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/read_only_atomic_load.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/concurrency/thread_local_static_dealloc.stderr b/tests/fail/concurrency/thread_local_static_dealloc.stderr index 58e7cf07348f7..cc3e56398781b 100644 --- a/tests/fail/concurrency/thread_local_static_dealloc.stderr +++ b/tests/fail/concurrency/thread_local_static_dealloc.stderr @@ -6,7 +6,7 @@ LL | let _val = *dangling_ptr.0; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/thread_local_static_dealloc.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/concurrency/unwind_top_of_stack.stderr b/tests/fail/concurrency/unwind_top_of_stack.stderr index efd19ef4c51ad..98db33e3206bd 100644 --- a/tests/fail/concurrency/unwind_top_of_stack.stderr +++ b/tests/fail/concurrency/unwind_top_of_stack.stderr @@ -11,7 +11,7 @@ LL | | } | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `thread_start` at $DIR/unwind_top_of_stack.rs:LL:CC error: aborting due to previous error diff --git a/tests/fail/concurrency/windows_join_detached.stderr b/tests/fail/concurrency/windows_join_detached.stderr index a0e85f6ce5ab4..78c75611d3333 100644 --- a/tests/fail/concurrency/windows_join_detached.stderr +++ b/tests/fail/concurrency/windows_join_detached.stderr @@ -6,7 +6,7 @@ LL | let rc = unsafe { c::WaitForSingleObject(self.handle.as_raw_handle( | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `std::sys::PLATFORM::thread::Thread::join` at RUSTLIB/std/src/sys/PLATFORM/thread.rs:LL:CC = note: inside `std::thread::JoinInner::<()>::join` at RUSTLIB/std/src/thread/mod.rs:LL:CC = note: inside `std::thread::JoinHandle::<()>::join` at RUSTLIB/std/src/thread/mod.rs:LL:CC diff --git a/tests/fail/crates/tokio_mvp.stderr b/tests/fail/crates/tokio_mvp.stderr index 8df83662aa023..016081d90adf7 100644 --- a/tests/fail/crates/tokio_mvp.stderr +++ b/tests/fail/crates/tokio_mvp.stderr @@ -5,7 +5,7 @@ LL | syscall!(epoll_create1(flag)).map(|ep| Selector { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't call foreign function: epoll_create1 | = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support - = note: backtrace: + = note: BACKTRACE: note: inside `main` at $DIR/tokio_mvp.rs:LL:CC --> $DIR/tokio_mvp.rs:LL:CC | diff --git a/tests/fail/dangling_pointers/dangling_pointer_addr_of.stderr b/tests/fail/dangling_pointers/dangling_pointer_addr_of.stderr index a6a2ca1507b50..5f081afe68af8 100644 --- a/tests/fail/dangling_pointers/dangling_pointer_addr_of.stderr +++ b/tests/fail/dangling_pointers/dangling_pointer_addr_of.stderr @@ -6,7 +6,7 @@ LL | let x = unsafe { ptr::addr_of!(*p) }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at RUSTLIB/core/src/ptr/mod.rs:LL:CC = note: this error originates in the macro `ptr::addr_of` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/fail/dangling_pointers/dangling_pointer_deref.stderr b/tests/fail/dangling_pointers/dangling_pointer_deref.stderr index cca3d0278aec3..cb323818845df 100644 --- a/tests/fail/dangling_pointers/dangling_pointer_deref.stderr +++ b/tests/fail/dangling_pointers/dangling_pointer_deref.stderr @@ -6,7 +6,7 @@ LL | let x = unsafe { *p }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/dangling_pointer_deref.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/dangling_pointers/dangling_zst_deref.stderr b/tests/fail/dangling_pointers/dangling_zst_deref.stderr index 66626a925cc68..02db6302a0a1e 100644 --- a/tests/fail/dangling_pointers/dangling_zst_deref.stderr +++ b/tests/fail/dangling_pointers/dangling_zst_deref.stderr @@ -6,7 +6,7 @@ LL | let _x = unsafe { *p }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/dangling_zst_deref.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/dangling_pointers/deref-invalid-ptr.stderr b/tests/fail/dangling_pointers/deref-invalid-ptr.stderr index 68003284994eb..3e2c3903b7e47 100644 --- a/tests/fail/dangling_pointers/deref-invalid-ptr.stderr +++ b/tests/fail/dangling_pointers/deref-invalid-ptr.stderr @@ -6,7 +6,7 @@ LL | let _y = unsafe { &*x as *const u32 }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/deref-invalid-ptr.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/dangling_pointers/deref-partially-dangling.stderr b/tests/fail/dangling_pointers/deref-partially-dangling.stderr index e37b6885922bd..fe039ef3adaf9 100644 --- a/tests/fail/dangling_pointers/deref-partially-dangling.stderr +++ b/tests/fail/dangling_pointers/deref-partially-dangling.stderr @@ -6,7 +6,7 @@ LL | let val = unsafe { (*xptr).1 }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/deref-partially-dangling.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/dangling_pointers/dyn_size.stderr b/tests/fail/dangling_pointers/dyn_size.stderr index 0abcee595e159..33aa6c8441017 100644 --- a/tests/fail/dangling_pointers/dyn_size.stderr +++ b/tests/fail/dangling_pointers/dyn_size.stderr @@ -6,7 +6,7 @@ LL | let _ptr = unsafe { &*ptr }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/dyn_size.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/dangling_pointers/maybe_null_pointer_deref_zst.stderr b/tests/fail/dangling_pointers/maybe_null_pointer_deref_zst.stderr index 222f2a6281962..3e492a170c8b1 100644 --- a/tests/fail/dangling_pointers/maybe_null_pointer_deref_zst.stderr +++ b/tests/fail/dangling_pointers/maybe_null_pointer_deref_zst.stderr @@ -6,7 +6,7 @@ LL | let _x: () = unsafe { *ptr }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/maybe_null_pointer_deref_zst.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/dangling_pointers/maybe_null_pointer_write_zst.stderr b/tests/fail/dangling_pointers/maybe_null_pointer_write_zst.stderr index 12228bc1d7177..c41c20aaf4a7b 100644 --- a/tests/fail/dangling_pointers/maybe_null_pointer_write_zst.stderr +++ b/tests/fail/dangling_pointers/maybe_null_pointer_write_zst.stderr @@ -6,7 +6,7 @@ LL | unsafe { *ptr = zst_val }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/maybe_null_pointer_write_zst.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/dangling_pointers/null_pointer_deref.stderr b/tests/fail/dangling_pointers/null_pointer_deref.stderr index fbb922c4c113c..64dcaa4548476 100644 --- a/tests/fail/dangling_pointers/null_pointer_deref.stderr +++ b/tests/fail/dangling_pointers/null_pointer_deref.stderr @@ -6,7 +6,7 @@ LL | let x: i32 = unsafe { *std::ptr::null() }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/null_pointer_deref.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/dangling_pointers/null_pointer_deref_zst.stderr b/tests/fail/dangling_pointers/null_pointer_deref_zst.stderr index 40b8d0899b13c..301578a4f5fb4 100644 --- a/tests/fail/dangling_pointers/null_pointer_deref_zst.stderr +++ b/tests/fail/dangling_pointers/null_pointer_deref_zst.stderr @@ -6,7 +6,7 @@ LL | let x: () = unsafe { *std::ptr::null() }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/null_pointer_deref_zst.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/dangling_pointers/null_pointer_write.stderr b/tests/fail/dangling_pointers/null_pointer_write.stderr index a5bf59e26d25b..0e5858a96f9d7 100644 --- a/tests/fail/dangling_pointers/null_pointer_write.stderr +++ b/tests/fail/dangling_pointers/null_pointer_write.stderr @@ -6,7 +6,7 @@ LL | unsafe { *std::ptr::null_mut() = 0i32 }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/null_pointer_write.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/dangling_pointers/null_pointer_write_zst.stderr b/tests/fail/dangling_pointers/null_pointer_write_zst.stderr index 17ac04a706fff..2953d85c25f3f 100644 --- a/tests/fail/dangling_pointers/null_pointer_write_zst.stderr +++ b/tests/fail/dangling_pointers/null_pointer_write_zst.stderr @@ -6,7 +6,7 @@ LL | unsafe { std::ptr::null_mut::<[u8; 0]>().write(zst_val) }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/null_pointer_write_zst.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/dangling_pointers/out_of_bounds_read1.stderr b/tests/fail/dangling_pointers/out_of_bounds_read1.stderr index 2abc7a457b9a8..b2461ce4230ad 100644 --- a/tests/fail/dangling_pointers/out_of_bounds_read1.stderr +++ b/tests/fail/dangling_pointers/out_of_bounds_read1.stderr @@ -6,7 +6,7 @@ LL | let x = unsafe { *v.as_ptr().wrapping_offset(5) }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/out_of_bounds_read1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/dangling_pointers/out_of_bounds_read2.stderr b/tests/fail/dangling_pointers/out_of_bounds_read2.stderr index e0735dd1f926a..b17058b406298 100644 --- a/tests/fail/dangling_pointers/out_of_bounds_read2.stderr +++ b/tests/fail/dangling_pointers/out_of_bounds_read2.stderr @@ -6,7 +6,7 @@ LL | let x = unsafe { *v.as_ptr().wrapping_offset(5) }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/out_of_bounds_read2.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/dangling_pointers/stack_temporary.stderr b/tests/fail/dangling_pointers/stack_temporary.stderr index dd24e6dd675cf..679e4809ca663 100644 --- a/tests/fail/dangling_pointers/stack_temporary.stderr +++ b/tests/fail/dangling_pointers/stack_temporary.stderr @@ -6,7 +6,7 @@ LL | let val = *x; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/stack_temporary.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/dangling_pointers/storage_dead_dangling.stderr b/tests/fail/dangling_pointers/storage_dead_dangling.stderr index 25c12feaa82d1..72e5f20f924a4 100644 --- a/tests/fail/dangling_pointers/storage_dead_dangling.stderr +++ b/tests/fail/dangling_pointers/storage_dead_dangling.stderr @@ -6,7 +6,7 @@ LL | unsafe { &mut *(LEAK as *mut i32) }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `evil` at $DIR/storage_dead_dangling.rs:LL:CC note: inside `main` at $DIR/storage_dead_dangling.rs:LL:CC --> $DIR/storage_dead_dangling.rs:LL:CC diff --git a/tests/fail/dangling_pointers/wild_pointer_deref.stderr b/tests/fail/dangling_pointers/wild_pointer_deref.stderr index 571bbcef6595c..658fb228174e5 100644 --- a/tests/fail/dangling_pointers/wild_pointer_deref.stderr +++ b/tests/fail/dangling_pointers/wild_pointer_deref.stderr @@ -6,7 +6,7 @@ LL | let x = unsafe { *p }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/wild_pointer_deref.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/data_race/alloc_read_race.stderr b/tests/fail/data_race/alloc_read_race.stderr index b180c30bdf342..c6bfd12b24110 100644 --- a/tests/fail/data_race/alloc_read_race.stderr +++ b/tests/fail/data_race/alloc_read_race.stderr @@ -6,7 +6,7 @@ LL | *pointer.load(Ordering::Relaxed) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside closure at $DIR/alloc_read_race.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/data_race/alloc_write_race.stderr b/tests/fail/data_race/alloc_write_race.stderr index bae65b6262f4a..c4efc175c2077 100644 --- a/tests/fail/data_race/alloc_write_race.stderr +++ b/tests/fail/data_race/alloc_write_race.stderr @@ -6,7 +6,7 @@ LL | *pointer.load(Ordering::Relaxed) = 2; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside closure at $DIR/alloc_write_race.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/data_race/atomic_read_na_write_race1.stderr b/tests/fail/data_race/atomic_read_na_write_race1.stderr index e7a219e123526..04adf0a98b6c5 100644 --- a/tests/fail/data_race/atomic_read_na_write_race1.stderr +++ b/tests/fail/data_race/atomic_read_na_write_race1.stderr @@ -6,7 +6,7 @@ LL | (&*c.0).load(Ordering::SeqCst) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside closure at $DIR/atomic_read_na_write_race1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/data_race/atomic_read_na_write_race2.stderr b/tests/fail/data_race/atomic_read_na_write_race2.stderr index 48a9c85469080..b48f927b8fcae 100644 --- a/tests/fail/data_race/atomic_read_na_write_race2.stderr +++ b/tests/fail/data_race/atomic_read_na_write_race2.stderr @@ -6,7 +6,7 @@ LL | *atomic_ref.get_mut() = 32; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside closure at $DIR/atomic_read_na_write_race2.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/data_race/atomic_write_na_read_race1.stderr b/tests/fail/data_race/atomic_write_na_read_race1.stderr index b3e12168255a7..fdb9b353a67bf 100644 --- a/tests/fail/data_race/atomic_write_na_read_race1.stderr +++ b/tests/fail/data_race/atomic_write_na_read_race1.stderr @@ -6,7 +6,7 @@ LL | *atomic_ref.get_mut() | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside closure at $DIR/atomic_write_na_read_race1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/data_race/atomic_write_na_read_race2.stderr b/tests/fail/data_race/atomic_write_na_read_race2.stderr index e9c6005f27e6b..ec581e322b7d1 100644 --- a/tests/fail/data_race/atomic_write_na_read_race2.stderr +++ b/tests/fail/data_race/atomic_write_na_read_race2.stderr @@ -6,7 +6,7 @@ LL | (&*c.0).store(32, Ordering::SeqCst); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside closure at $DIR/atomic_write_na_read_race2.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/data_race/atomic_write_na_write_race1.stderr b/tests/fail/data_race/atomic_write_na_write_race1.stderr index 5ecc4ca040263..4c75f94d71cf5 100644 --- a/tests/fail/data_race/atomic_write_na_write_race1.stderr +++ b/tests/fail/data_race/atomic_write_na_write_race1.stderr @@ -6,7 +6,7 @@ LL | (&*c.0).store(64, Ordering::SeqCst); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside closure at $DIR/atomic_write_na_write_race1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/data_race/atomic_write_na_write_race2.stderr b/tests/fail/data_race/atomic_write_na_write_race2.stderr index 2de1c68588880..8c7f14081c87b 100644 --- a/tests/fail/data_race/atomic_write_na_write_race2.stderr +++ b/tests/fail/data_race/atomic_write_na_write_race2.stderr @@ -6,7 +6,7 @@ LL | *atomic_ref.get_mut() = 32; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside closure at $DIR/atomic_write_na_write_race2.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/data_race/dangling_thread_async_race.stderr b/tests/fail/data_race/dangling_thread_async_race.stderr index 66bb8b0be4048..663bb8d4af512 100644 --- a/tests/fail/data_race/dangling_thread_async_race.stderr +++ b/tests/fail/data_race/dangling_thread_async_race.stderr @@ -6,7 +6,7 @@ LL | *c.0 = 64; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside closure at $DIR/dangling_thread_async_race.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/data_race/dangling_thread_race.stderr b/tests/fail/data_race/dangling_thread_race.stderr index 1fd9afe176331..ad3e1735378f3 100644 --- a/tests/fail/data_race/dangling_thread_race.stderr +++ b/tests/fail/data_race/dangling_thread_race.stderr @@ -6,7 +6,7 @@ LL | *c.0 = 64; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/dangling_thread_race.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/data_race/dealloc_read_race1.stderr b/tests/fail/data_race/dealloc_read_race1.stderr index eec74e8b542a0..194c2260baaab 100644 --- a/tests/fail/data_race/dealloc_read_race1.stderr +++ b/tests/fail/data_race/dealloc_read_race1.stderr @@ -11,7 +11,7 @@ LL | | ); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside closure at $DIR/dealloc_read_race1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/data_race/dealloc_read_race2.stderr b/tests/fail/data_race/dealloc_read_race2.stderr index 41a1224101fc5..f303d57c8bd9c 100644 --- a/tests/fail/data_race/dealloc_read_race2.stderr +++ b/tests/fail/data_race/dealloc_read_race2.stderr @@ -6,7 +6,7 @@ LL | *ptr.0 | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside closure at $DIR/dealloc_read_race2.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/data_race/dealloc_read_race_stack.stderr b/tests/fail/data_race/dealloc_read_race_stack.stderr index 3c125e03a680c..c986e912f03ba 100644 --- a/tests/fail/data_race/dealloc_read_race_stack.stderr +++ b/tests/fail/data_race/dealloc_read_race_stack.stderr @@ -6,7 +6,7 @@ LL | } | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside closure at $DIR/dealloc_read_race_stack.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/data_race/dealloc_write_race1.stderr b/tests/fail/data_race/dealloc_write_race1.stderr index f16c0040bb8a4..56eb0b519c484 100644 --- a/tests/fail/data_race/dealloc_write_race1.stderr +++ b/tests/fail/data_race/dealloc_write_race1.stderr @@ -11,7 +11,7 @@ LL | | ); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside closure at $DIR/dealloc_write_race1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/data_race/dealloc_write_race2.stderr b/tests/fail/data_race/dealloc_write_race2.stderr index 6f2e829b42971..23b8e9ade0e0e 100644 --- a/tests/fail/data_race/dealloc_write_race2.stderr +++ b/tests/fail/data_race/dealloc_write_race2.stderr @@ -6,7 +6,7 @@ LL | *ptr.0 = 2; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside closure at $DIR/dealloc_write_race2.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/data_race/dealloc_write_race_stack.stderr b/tests/fail/data_race/dealloc_write_race_stack.stderr index ed069bb6fcd61..7b77e2470a1ab 100644 --- a/tests/fail/data_race/dealloc_write_race_stack.stderr +++ b/tests/fail/data_race/dealloc_write_race_stack.stderr @@ -6,7 +6,7 @@ LL | } | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside closure at $DIR/dealloc_write_race_stack.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/data_race/enable_after_join_to_main.stderr b/tests/fail/data_race/enable_after_join_to_main.stderr index cd707bdcfa9c5..26c07ae6962b5 100644 --- a/tests/fail/data_race/enable_after_join_to_main.stderr +++ b/tests/fail/data_race/enable_after_join_to_main.stderr @@ -6,7 +6,7 @@ LL | *c.0 = 64; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside closure at $DIR/enable_after_join_to_main.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/data_race/fence_after_load.stderr b/tests/fail/data_race/fence_after_load.stderr index 878342c1bd9ff..0abfe213db17d 100644 --- a/tests/fail/data_race/fence_after_load.stderr +++ b/tests/fail/data_race/fence_after_load.stderr @@ -6,7 +6,7 @@ LL | unsafe { V = 2 } | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/fence_after_load.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/data_race/read_write_race.stderr b/tests/fail/data_race/read_write_race.stderr index b87a7a10974e8..08a19537312cf 100644 --- a/tests/fail/data_race/read_write_race.stderr +++ b/tests/fail/data_race/read_write_race.stderr @@ -6,7 +6,7 @@ LL | *c.0 = 64; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside closure at $DIR/read_write_race.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/data_race/read_write_race_stack.stderr b/tests/fail/data_race/read_write_race_stack.stderr index 29739d5083c4c..20f137afe7329 100644 --- a/tests/fail/data_race/read_write_race_stack.stderr +++ b/tests/fail/data_race/read_write_race_stack.stderr @@ -6,7 +6,7 @@ LL | stack_var | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside closure at $DIR/read_write_race_stack.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/data_race/relax_acquire_race.stderr b/tests/fail/data_race/relax_acquire_race.stderr index 21f9e6f960352..6121c25db22d7 100644 --- a/tests/fail/data_race/relax_acquire_race.stderr +++ b/tests/fail/data_race/relax_acquire_race.stderr @@ -6,7 +6,7 @@ LL | *c.0 | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside closure at $DIR/relax_acquire_race.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/data_race/release_seq_race.stderr b/tests/fail/data_race/release_seq_race.stderr index a7bca03547e50..777bc4adadc6d 100644 --- a/tests/fail/data_race/release_seq_race.stderr +++ b/tests/fail/data_race/release_seq_race.stderr @@ -6,7 +6,7 @@ LL | *c.0 | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside closure at $DIR/release_seq_race.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/data_race/release_seq_race_same_thread.stderr b/tests/fail/data_race/release_seq_race_same_thread.stderr index 515ce17e16cd0..0fcb192d920fd 100644 --- a/tests/fail/data_race/release_seq_race_same_thread.stderr +++ b/tests/fail/data_race/release_seq_race_same_thread.stderr @@ -6,7 +6,7 @@ LL | *c.0 | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside closure at $DIR/release_seq_race_same_thread.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/data_race/rmw_race.stderr b/tests/fail/data_race/rmw_race.stderr index 905592fc22247..3ae6f3b84fe12 100644 --- a/tests/fail/data_race/rmw_race.stderr +++ b/tests/fail/data_race/rmw_race.stderr @@ -6,7 +6,7 @@ LL | *c.0 | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside closure at $DIR/rmw_race.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/data_race/stack_pop_race.stderr b/tests/fail/data_race/stack_pop_race.stderr index ba830753f6eea..5de27108ab633 100644 --- a/tests/fail/data_race/stack_pop_race.stderr +++ b/tests/fail/data_race/stack_pop_race.stderr @@ -6,7 +6,7 @@ LL | } | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `race` at $DIR/stack_pop_race.rs:LL:CC note: inside `main` at $DIR/stack_pop_race.rs:LL:CC --> $DIR/stack_pop_race.rs:LL:CC diff --git a/tests/fail/data_race/write_write_race.stderr b/tests/fail/data_race/write_write_race.stderr index afb9f4c1edb79..ee7072ccf5d17 100644 --- a/tests/fail/data_race/write_write_race.stderr +++ b/tests/fail/data_race/write_write_race.stderr @@ -6,7 +6,7 @@ LL | *c.0 = 64; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside closure at $DIR/write_write_race.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/data_race/write_write_race_stack.stderr b/tests/fail/data_race/write_write_race_stack.stderr index 97977bc297c16..ceb473c2a4a41 100644 --- a/tests/fail/data_race/write_write_race_stack.stderr +++ b/tests/fail/data_race/write_write_race_stack.stderr @@ -6,7 +6,7 @@ LL | stack_var = 1usize; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside closure at $DIR/write_write_race_stack.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/dyn-call-trait-mismatch.stderr b/tests/fail/dyn-call-trait-mismatch.stderr index 2673a22a3df26..03272105c4146 100644 --- a/tests/fail/dyn-call-trait-mismatch.stderr +++ b/tests/fail/dyn-call-trait-mismatch.stderr @@ -6,7 +6,7 @@ LL | r2.method2(); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/dyn-call-trait-mismatch.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/dyn-upcast-trait-mismatch.stderr b/tests/fail/dyn-upcast-trait-mismatch.stderr index cdd1421a660c9..21870ef3733e8 100644 --- a/tests/fail/dyn-upcast-trait-mismatch.stderr +++ b/tests/fail/dyn-upcast-trait-mismatch.stderr @@ -6,7 +6,7 @@ LL | let _err = baz_fake as &dyn Foo; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/dyn-upcast-trait-mismatch.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/environ-gets-deallocated.stderr b/tests/fail/environ-gets-deallocated.stderr index bb6525fa80614..a2d343bf8651c 100644 --- a/tests/fail/environ-gets-deallocated.stderr +++ b/tests/fail/environ-gets-deallocated.stderr @@ -6,7 +6,7 @@ LL | let _y = unsafe { *pointer }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/environ-gets-deallocated.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/extern_static.stderr b/tests/fail/extern_static.stderr index 0adb996decdbd..fa0d55e5f6781 100644 --- a/tests/fail/extern_static.stderr +++ b/tests/fail/extern_static.stderr @@ -5,7 +5,7 @@ LL | let _val = unsafe { std::ptr::addr_of!(FOO) }; | ^^^ `extern` static `FOO` from crate `extern_static` is not supported by Miri | = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/extern_static.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/extern_static_in_const.stderr b/tests/fail/extern_static_in_const.stderr index ebd5dd7fee157..e4ee8f1acba29 100644 --- a/tests/fail/extern_static_in_const.stderr +++ b/tests/fail/extern_static_in_const.stderr @@ -5,7 +5,7 @@ LL | let _val = X; | ^ `extern` static `E` from crate `extern_static_in_const` is not supported by Miri | = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/extern_static_in_const.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/extern_static_wrong_size.stderr b/tests/fail/extern_static_wrong_size.stderr index fdeb7bb5f6880..a56eba09df98f 100644 --- a/tests/fail/extern_static_wrong_size.stderr +++ b/tests/fail/extern_static_wrong_size.stderr @@ -5,7 +5,7 @@ LL | let _val = unsafe { environ }; | ^^^^^^^ `extern` static `environ` from crate `extern_static_wrong_size` has been declared with a size of 1 bytes and alignment of 1 bytes, but Miri emulates it via an extern static shim with a size of N bytes and alignment of N bytes | = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/extern_static_wrong_size.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/fast_math_both.stderr b/tests/fail/fast_math_both.stderr index 902c9a1f8bb53..2a0759f8a3ba7 100644 --- a/tests/fail/fast_math_both.stderr +++ b/tests/fail/fast_math_both.stderr @@ -6,7 +6,7 @@ LL | ...: f32 = core::intrinsics::fsub_fast(f32::NAN, f32::NAN); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/fast_math_both.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/fast_math_first.stderr b/tests/fail/fast_math_first.stderr index 986b487991f99..766662ca14ba9 100644 --- a/tests/fail/fast_math_first.stderr +++ b/tests/fail/fast_math_first.stderr @@ -6,7 +6,7 @@ LL | ... let _x: f32 = core::intrinsics::frem_fast(f32::NAN, 3.2); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/fast_math_first.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/fast_math_second.stderr b/tests/fail/fast_math_second.stderr index c5abb17f8fac9..ce93f9398f2cd 100644 --- a/tests/fail/fast_math_second.stderr +++ b/tests/fail/fast_math_second.stderr @@ -6,7 +6,7 @@ LL | ...f32 = core::intrinsics::fmul_fast(3.4f32, f32::INFINITY); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/fast_math_second.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/function_calls/check_arg_abi.stderr b/tests/fail/function_calls/check_arg_abi.stderr index 952acde9ea537..406ccb070bab5 100644 --- a/tests/fail/function_calls/check_arg_abi.stderr +++ b/tests/fail/function_calls/check_arg_abi.stderr @@ -6,7 +6,7 @@ LL | let _ = malloc(0); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/check_arg_abi.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/function_calls/check_arg_count_abort.stderr b/tests/fail/function_calls/check_arg_count_abort.stderr index bf24c5c917942..d90a7e31d6ee9 100644 --- a/tests/fail/function_calls/check_arg_count_abort.stderr +++ b/tests/fail/function_calls/check_arg_count_abort.stderr @@ -6,7 +6,7 @@ LL | abort(1); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/check_arg_count_abort.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/function_calls/check_arg_count_too_few_args.stderr b/tests/fail/function_calls/check_arg_count_too_few_args.stderr index ac0ec606dac8b..9e2751a216bcb 100644 --- a/tests/fail/function_calls/check_arg_count_too_few_args.stderr +++ b/tests/fail/function_calls/check_arg_count_too_few_args.stderr @@ -6,7 +6,7 @@ LL | let _ = malloc(); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/check_arg_count_too_few_args.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/function_calls/check_arg_count_too_many_args.stderr b/tests/fail/function_calls/check_arg_count_too_many_args.stderr index b465b02b6e42e..e9a38b5ae4218 100644 --- a/tests/fail/function_calls/check_arg_count_too_many_args.stderr +++ b/tests/fail/function_calls/check_arg_count_too_many_args.stderr @@ -6,7 +6,7 @@ LL | let _ = malloc(1, 2); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/check_arg_count_too_many_args.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/function_calls/check_callback_abi.stderr b/tests/fail/function_calls/check_callback_abi.stderr index 5d5c30a203ac2..50afc10979749 100644 --- a/tests/fail/function_calls/check_callback_abi.stderr +++ b/tests/fail/function_calls/check_callback_abi.stderr @@ -11,7 +11,7 @@ LL | | ); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/check_callback_abi.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/function_calls/exported_symbol_abi_mismatch.cache.stderr b/tests/fail/function_calls/exported_symbol_abi_mismatch.cache.stderr index ba2b4de889b7e..ae5c6cb72b3c9 100644 --- a/tests/fail/function_calls/exported_symbol_abi_mismatch.cache.stderr +++ b/tests/fail/function_calls/exported_symbol_abi_mismatch.cache.stderr @@ -6,7 +6,7 @@ LL | foo(); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/exported_symbol_abi_mismatch.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/function_calls/exported_symbol_abi_mismatch.fn_ptr.stderr b/tests/fail/function_calls/exported_symbol_abi_mismatch.fn_ptr.stderr index 358f86c0403b5..17d56793ac5c6 100644 --- a/tests/fail/function_calls/exported_symbol_abi_mismatch.fn_ptr.stderr +++ b/tests/fail/function_calls/exported_symbol_abi_mismatch.fn_ptr.stderr @@ -6,7 +6,7 @@ LL | std::mem::transmute::(foo)(); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/exported_symbol_abi_mismatch.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/function_calls/exported_symbol_abi_mismatch.no_cache.stderr b/tests/fail/function_calls/exported_symbol_abi_mismatch.no_cache.stderr index ba2b4de889b7e..ae5c6cb72b3c9 100644 --- a/tests/fail/function_calls/exported_symbol_abi_mismatch.no_cache.stderr +++ b/tests/fail/function_calls/exported_symbol_abi_mismatch.no_cache.stderr @@ -6,7 +6,7 @@ LL | foo(); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/exported_symbol_abi_mismatch.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/function_calls/exported_symbol_bad_unwind1.stderr b/tests/fail/function_calls/exported_symbol_bad_unwind1.stderr index 0b943432c2076..7f87ec6f3bb69 100644 --- a/tests/fail/function_calls/exported_symbol_bad_unwind1.stderr +++ b/tests/fail/function_calls/exported_symbol_bad_unwind1.stderr @@ -8,7 +8,7 @@ LL | unsafe { unwind() } | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/exported_symbol_bad_unwind1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/function_calls/exported_symbol_bad_unwind2.extern_block.stderr b/tests/fail/function_calls/exported_symbol_bad_unwind2.extern_block.stderr index f974eb87037a4..b23c05a530357 100644 --- a/tests/fail/function_calls/exported_symbol_bad_unwind2.extern_block.stderr +++ b/tests/fail/function_calls/exported_symbol_bad_unwind2.extern_block.stderr @@ -8,7 +8,7 @@ LL | unsafe { nounwind() } | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/exported_symbol_bad_unwind2.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/function_calls/exported_symbol_clashing.stderr b/tests/fail/function_calls/exported_symbol_clashing.stderr index 998b7c415930e..8eb9fa4ff5c27 100644 --- a/tests/fail/function_calls/exported_symbol_clashing.stderr +++ b/tests/fail/function_calls/exported_symbol_clashing.stderr @@ -14,7 +14,7 @@ help: then it's defined here again, in crate `exported_symbol_clashing` | LL | fn bar() {} | ^^^^^^^^ - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/exported_symbol_clashing.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/function_calls/exported_symbol_shim_clashing.stderr b/tests/fail/function_calls/exported_symbol_shim_clashing.stderr index 69b99b3747336..58a996e64530e 100644 --- a/tests/fail/function_calls/exported_symbol_shim_clashing.stderr +++ b/tests/fail/function_calls/exported_symbol_shim_clashing.stderr @@ -12,7 +12,7 @@ LL | | LL | | unreachable!() LL | | } | |_^ - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/exported_symbol_shim_clashing.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/function_calls/exported_symbol_wrong_arguments.stderr b/tests/fail/function_calls/exported_symbol_wrong_arguments.stderr index 2e80e833710e7..1aa13ce438953 100644 --- a/tests/fail/function_calls/exported_symbol_wrong_arguments.stderr +++ b/tests/fail/function_calls/exported_symbol_wrong_arguments.stderr @@ -6,7 +6,7 @@ LL | unsafe { foo(1) } | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/exported_symbol_wrong_arguments.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/function_calls/exported_symbol_wrong_type.stderr b/tests/fail/function_calls/exported_symbol_wrong_type.stderr index 900e23d1212ec..abfd7a9a6c4d9 100644 --- a/tests/fail/function_calls/exported_symbol_wrong_type.stderr +++ b/tests/fail/function_calls/exported_symbol_wrong_type.stderr @@ -6,7 +6,7 @@ LL | unsafe { FOO() } | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/exported_symbol_wrong_type.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/function_pointers/cast_box_int_to_fn_ptr.stderr b/tests/fail/function_pointers/cast_box_int_to_fn_ptr.stderr index 436cced9f02e5..ad43c2c9d3fe7 100644 --- a/tests/fail/function_pointers/cast_box_int_to_fn_ptr.stderr +++ b/tests/fail/function_pointers/cast_box_int_to_fn_ptr.stderr @@ -6,7 +6,7 @@ LL | (*g)(42) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/cast_box_int_to_fn_ptr.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/function_pointers/cast_fn_ptr1.stderr b/tests/fail/function_pointers/cast_fn_ptr1.stderr index 972fd9afc8ea7..bb2a263795980 100644 --- a/tests/fail/function_pointers/cast_fn_ptr1.stderr +++ b/tests/fail/function_pointers/cast_fn_ptr1.stderr @@ -6,7 +6,7 @@ LL | g(42) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/cast_fn_ptr1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/function_pointers/cast_fn_ptr2.stderr b/tests/fail/function_pointers/cast_fn_ptr2.stderr index 638c4ca6781ed..086712e0d13bd 100644 --- a/tests/fail/function_pointers/cast_fn_ptr2.stderr +++ b/tests/fail/function_pointers/cast_fn_ptr2.stderr @@ -6,7 +6,7 @@ LL | g(42) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/cast_fn_ptr2.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/function_pointers/cast_fn_ptr3.stderr b/tests/fail/function_pointers/cast_fn_ptr3.stderr index e21d1c6b6f733..55fd7d6072089 100644 --- a/tests/fail/function_pointers/cast_fn_ptr3.stderr +++ b/tests/fail/function_pointers/cast_fn_ptr3.stderr @@ -6,7 +6,7 @@ LL | g() | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/cast_fn_ptr3.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/function_pointers/cast_fn_ptr4.stderr b/tests/fail/function_pointers/cast_fn_ptr4.stderr index b1acafcebe7e1..610425658fe1f 100644 --- a/tests/fail/function_pointers/cast_fn_ptr4.stderr +++ b/tests/fail/function_pointers/cast_fn_ptr4.stderr @@ -6,7 +6,7 @@ LL | g(&42 as *const i32) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/cast_fn_ptr4.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/function_pointers/cast_fn_ptr5.stderr b/tests/fail/function_pointers/cast_fn_ptr5.stderr index c4915f905bf3e..c4e08b58430a2 100644 --- a/tests/fail/function_pointers/cast_fn_ptr5.stderr +++ b/tests/fail/function_pointers/cast_fn_ptr5.stderr @@ -6,7 +6,7 @@ LL | g() | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/cast_fn_ptr5.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/function_pointers/cast_int_to_fn_ptr.stderr b/tests/fail/function_pointers/cast_int_to_fn_ptr.stderr index 3d4acbe6f09ae..81fc9716a4156 100644 --- a/tests/fail/function_pointers/cast_int_to_fn_ptr.stderr +++ b/tests/fail/function_pointers/cast_int_to_fn_ptr.stderr @@ -6,7 +6,7 @@ LL | g(42) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/cast_int_to_fn_ptr.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/function_pointers/deref_fn_ptr.stderr b/tests/fail/function_pointers/deref_fn_ptr.stderr index ecd001964a1bc..7ce0b08695ebb 100644 --- a/tests/fail/function_pointers/deref_fn_ptr.stderr +++ b/tests/fail/function_pointers/deref_fn_ptr.stderr @@ -6,7 +6,7 @@ LL | *std::mem::transmute::(f) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/deref_fn_ptr.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/function_pointers/execute_memory.stderr b/tests/fail/function_pointers/execute_memory.stderr index b6438934b2b34..10c53ca2beaee 100644 --- a/tests/fail/function_pointers/execute_memory.stderr +++ b/tests/fail/function_pointers/execute_memory.stderr @@ -6,7 +6,7 @@ LL | f() | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/execute_memory.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/function_pointers/fn_ptr_offset.stderr b/tests/fail/function_pointers/fn_ptr_offset.stderr index b5164d02ace1b..f8c519c1b54b0 100644 --- a/tests/fail/function_pointers/fn_ptr_offset.stderr +++ b/tests/fail/function_pointers/fn_ptr_offset.stderr @@ -6,7 +6,7 @@ LL | x(); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/fn_ptr_offset.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/generator-pinned-moved.stderr b/tests/fail/generator-pinned-moved.stderr index f1fb366d0652e..4f73671a78947 100644 --- a/tests/fail/generator-pinned-moved.stderr +++ b/tests/fail/generator-pinned-moved.stderr @@ -6,7 +6,7 @@ LL | *num += 1; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside closure at $DIR/generator-pinned-moved.rs:LL:CC note: inside ` as std::iter::Iterator>::next` at $DIR/generator-pinned-moved.rs:LL:CC --> $DIR/generator-pinned-moved.rs:LL:CC diff --git a/tests/fail/intrinsics/assume.stderr b/tests/fail/intrinsics/assume.stderr index 1664e7ad743f4..17e4cc6698d48 100644 --- a/tests/fail/intrinsics/assume.stderr +++ b/tests/fail/intrinsics/assume.stderr @@ -6,7 +6,7 @@ LL | std::intrinsics::assume(x > 42); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/assume.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/copy_null.stderr b/tests/fail/intrinsics/copy_null.stderr index d7725064832e4..6e3215d9f1c9c 100644 --- a/tests/fail/intrinsics/copy_null.stderr +++ b/tests/fail/intrinsics/copy_null.stderr @@ -6,7 +6,7 @@ LL | copy_nonoverlapping(std::ptr::null(), ptr, 0); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/copy_null.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/copy_overflow.stderr b/tests/fail/intrinsics/copy_overflow.stderr index 3534f4d1fb85b..23a4adbd0ed6f 100644 --- a/tests/fail/intrinsics/copy_overflow.stderr +++ b/tests/fail/intrinsics/copy_overflow.stderr @@ -6,7 +6,7 @@ LL | (&mut y as *mut i32).copy_from(&x, 1usize << (mem::size_of:: | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/copy_overflow.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/copy_overlapping.stderr b/tests/fail/intrinsics/copy_overlapping.stderr index 9298a87712bbc..cdb3da74ca954 100644 --- a/tests/fail/intrinsics/copy_overlapping.stderr +++ b/tests/fail/intrinsics/copy_overlapping.stderr @@ -6,7 +6,7 @@ LL | copy_nonoverlapping(a, b, 2); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/copy_overlapping.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/copy_unaligned.stderr b/tests/fail/intrinsics/copy_unaligned.stderr index 890c7b12e03d7..a275979e6be13 100644 --- a/tests/fail/intrinsics/copy_unaligned.stderr +++ b/tests/fail/intrinsics/copy_unaligned.stderr @@ -6,7 +6,7 @@ LL | copy_nonoverlapping(&data[5], ptr, 0); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/copy_unaligned.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/ctlz_nonzero.stderr b/tests/fail/intrinsics/ctlz_nonzero.stderr index 7d4d3dd8e1b86..5ae14472a8a63 100644 --- a/tests/fail/intrinsics/ctlz_nonzero.stderr +++ b/tests/fail/intrinsics/ctlz_nonzero.stderr @@ -6,7 +6,7 @@ LL | ctlz_nonzero(0u8); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/ctlz_nonzero.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/cttz_nonzero.stderr b/tests/fail/intrinsics/cttz_nonzero.stderr index 284bfc1c4c994..ae013fb3d9794 100644 --- a/tests/fail/intrinsics/cttz_nonzero.stderr +++ b/tests/fail/intrinsics/cttz_nonzero.stderr @@ -6,7 +6,7 @@ LL | cttz_nonzero(0u8); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/cttz_nonzero.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/div-by-zero.stderr b/tests/fail/intrinsics/div-by-zero.stderr index 061123ddc1dec..8c2910de3eef4 100644 --- a/tests/fail/intrinsics/div-by-zero.stderr +++ b/tests/fail/intrinsics/div-by-zero.stderr @@ -6,7 +6,7 @@ LL | let _n = unchecked_div(1i64, 0); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/div-by-zero.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/exact_div1.stderr b/tests/fail/intrinsics/exact_div1.stderr index 6564fad475def..2c7bbc00e1b1b 100644 --- a/tests/fail/intrinsics/exact_div1.stderr +++ b/tests/fail/intrinsics/exact_div1.stderr @@ -6,7 +6,7 @@ LL | unsafe { std::intrinsics::exact_div(2, 0) }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/exact_div1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/exact_div2.stderr b/tests/fail/intrinsics/exact_div2.stderr index 7e8e2ee18121b..6a264b8b4476f 100644 --- a/tests/fail/intrinsics/exact_div2.stderr +++ b/tests/fail/intrinsics/exact_div2.stderr @@ -6,7 +6,7 @@ LL | unsafe { std::intrinsics::exact_div(2u16, 3) }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/exact_div2.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/exact_div3.stderr b/tests/fail/intrinsics/exact_div3.stderr index 8b1f15794b7cd..1a73822c300f3 100644 --- a/tests/fail/intrinsics/exact_div3.stderr +++ b/tests/fail/intrinsics/exact_div3.stderr @@ -6,7 +6,7 @@ LL | unsafe { std::intrinsics::exact_div(-19i8, 2) }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/exact_div3.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/exact_div4.stderr b/tests/fail/intrinsics/exact_div4.stderr index 4da670bc846cf..27201d9c7cf65 100644 --- a/tests/fail/intrinsics/exact_div4.stderr +++ b/tests/fail/intrinsics/exact_div4.stderr @@ -6,7 +6,7 @@ LL | unsafe { std::intrinsics::exact_div(i64::MIN, -1) }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/exact_div4.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/float_to_int_32_inf1.stderr b/tests/fail/intrinsics/float_to_int_32_inf1.stderr index 88cd4a7c184b4..c82d6b30224fc 100644 --- a/tests/fail/intrinsics/float_to_int_32_inf1.stderr +++ b/tests/fail/intrinsics/float_to_int_32_inf1.stderr @@ -6,7 +6,7 @@ LL | float_to_int_unchecked::(f32::INFINITY); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/float_to_int_32_inf1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/float_to_int_32_infneg1.stderr b/tests/fail/intrinsics/float_to_int_32_infneg1.stderr index a833001840481..4ca41b676e9c3 100644 --- a/tests/fail/intrinsics/float_to_int_32_infneg1.stderr +++ b/tests/fail/intrinsics/float_to_int_32_infneg1.stderr @@ -6,7 +6,7 @@ LL | float_to_int_unchecked::(f32::NEG_INFINITY); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/float_to_int_32_infneg1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/float_to_int_32_nan.stderr b/tests/fail/intrinsics/float_to_int_32_nan.stderr index 9bf312a9ccbd8..88b8948b0c29e 100644 --- a/tests/fail/intrinsics/float_to_int_32_nan.stderr +++ b/tests/fail/intrinsics/float_to_int_32_nan.stderr @@ -6,7 +6,7 @@ LL | float_to_int_unchecked::(f32::NAN); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/float_to_int_32_nan.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/float_to_int_32_nanneg.stderr b/tests/fail/intrinsics/float_to_int_32_nanneg.stderr index be105ccdaa711..ca798dd391aa9 100644 --- a/tests/fail/intrinsics/float_to_int_32_nanneg.stderr +++ b/tests/fail/intrinsics/float_to_int_32_nanneg.stderr @@ -6,7 +6,7 @@ LL | float_to_int_unchecked::(-f32::NAN); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/float_to_int_32_nanneg.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/float_to_int_32_neg.stderr b/tests/fail/intrinsics/float_to_int_32_neg.stderr index 6f926d442bb4e..4ff6eb8098540 100644 --- a/tests/fail/intrinsics/float_to_int_32_neg.stderr +++ b/tests/fail/intrinsics/float_to_int_32_neg.stderr @@ -6,7 +6,7 @@ LL | float_to_int_unchecked::(-1.000000001f32); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/float_to_int_32_neg.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/float_to_int_32_too_big1.stderr b/tests/fail/intrinsics/float_to_int_32_too_big1.stderr index 880eb6f48a9b3..fd17709d164b1 100644 --- a/tests/fail/intrinsics/float_to_int_32_too_big1.stderr +++ b/tests/fail/intrinsics/float_to_int_32_too_big1.stderr @@ -6,7 +6,7 @@ LL | float_to_int_unchecked::(2147483648.0f32); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/float_to_int_32_too_big1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/float_to_int_32_too_big2.stderr b/tests/fail/intrinsics/float_to_int_32_too_big2.stderr index 9ee3e2feed2f9..fdc1f65dc1485 100644 --- a/tests/fail/intrinsics/float_to_int_32_too_big2.stderr +++ b/tests/fail/intrinsics/float_to_int_32_too_big2.stderr @@ -6,7 +6,7 @@ LL | float_to_int_unchecked::((u32::MAX - 127) as f32); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/float_to_int_32_too_big2.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/float_to_int_32_too_small1.stderr b/tests/fail/intrinsics/float_to_int_32_too_small1.stderr index 0f23fc05fd723..9e743a3214449 100644 --- a/tests/fail/intrinsics/float_to_int_32_too_small1.stderr +++ b/tests/fail/intrinsics/float_to_int_32_too_small1.stderr @@ -6,7 +6,7 @@ LL | float_to_int_unchecked::(-2147483904.0f32); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/float_to_int_32_too_small1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/float_to_int_64_inf1.stderr b/tests/fail/intrinsics/float_to_int_64_inf1.stderr index eb493f141cbdd..ee01143dc8dfc 100644 --- a/tests/fail/intrinsics/float_to_int_64_inf1.stderr +++ b/tests/fail/intrinsics/float_to_int_64_inf1.stderr @@ -6,7 +6,7 @@ LL | float_to_int_unchecked::(f64::INFINITY); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/float_to_int_64_inf1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/float_to_int_64_infneg1.stderr b/tests/fail/intrinsics/float_to_int_64_infneg1.stderr index 5e499e2712020..f37b8ae550643 100644 --- a/tests/fail/intrinsics/float_to_int_64_infneg1.stderr +++ b/tests/fail/intrinsics/float_to_int_64_infneg1.stderr @@ -6,7 +6,7 @@ LL | float_to_int_unchecked::(f64::NEG_INFINITY); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/float_to_int_64_infneg1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/float_to_int_64_infneg2.stderr b/tests/fail/intrinsics/float_to_int_64_infneg2.stderr index da22fa481727f..05dcd5ebcf69a 100644 --- a/tests/fail/intrinsics/float_to_int_64_infneg2.stderr +++ b/tests/fail/intrinsics/float_to_int_64_infneg2.stderr @@ -6,7 +6,7 @@ LL | float_to_int_unchecked::(f64::NEG_INFINITY); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/float_to_int_64_infneg2.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/float_to_int_64_nan.stderr b/tests/fail/intrinsics/float_to_int_64_nan.stderr index eff110ad724c4..0a914abb2ce78 100644 --- a/tests/fail/intrinsics/float_to_int_64_nan.stderr +++ b/tests/fail/intrinsics/float_to_int_64_nan.stderr @@ -6,7 +6,7 @@ LL | float_to_int_unchecked::(f64::NAN); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/float_to_int_64_nan.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/float_to_int_64_neg.stderr b/tests/fail/intrinsics/float_to_int_64_neg.stderr index 8d8851a9d7bf2..7e24f45f653d1 100644 --- a/tests/fail/intrinsics/float_to_int_64_neg.stderr +++ b/tests/fail/intrinsics/float_to_int_64_neg.stderr @@ -6,7 +6,7 @@ LL | float_to_int_unchecked::(-1.0000000000001f64); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/float_to_int_64_neg.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/float_to_int_64_too_big1.stderr b/tests/fail/intrinsics/float_to_int_64_too_big1.stderr index 53c999ccba92f..42da33321f371 100644 --- a/tests/fail/intrinsics/float_to_int_64_too_big1.stderr +++ b/tests/fail/intrinsics/float_to_int_64_too_big1.stderr @@ -6,7 +6,7 @@ LL | float_to_int_unchecked::(2147483648.0f64); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/float_to_int_64_too_big1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/float_to_int_64_too_big2.stderr b/tests/fail/intrinsics/float_to_int_64_too_big2.stderr index 4f5927eed59a2..af4c4ceb3f73f 100644 --- a/tests/fail/intrinsics/float_to_int_64_too_big2.stderr +++ b/tests/fail/intrinsics/float_to_int_64_too_big2.stderr @@ -6,7 +6,7 @@ LL | float_to_int_unchecked::(9223372036854775808.0f64); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/float_to_int_64_too_big2.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/float_to_int_64_too_big3.stderr b/tests/fail/intrinsics/float_to_int_64_too_big3.stderr index d439b8695efb6..6e384a6fbc7cb 100644 --- a/tests/fail/intrinsics/float_to_int_64_too_big3.stderr +++ b/tests/fail/intrinsics/float_to_int_64_too_big3.stderr @@ -6,7 +6,7 @@ LL | float_to_int_unchecked::(18446744073709551616.0f64); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/float_to_int_64_too_big3.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/float_to_int_64_too_big4.stderr b/tests/fail/intrinsics/float_to_int_64_too_big4.stderr index 56677cd315544..77f05ff91e3b5 100644 --- a/tests/fail/intrinsics/float_to_int_64_too_big4.stderr +++ b/tests/fail/intrinsics/float_to_int_64_too_big4.stderr @@ -6,7 +6,7 @@ LL | float_to_int_unchecked::(u128::MAX as f64); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/float_to_int_64_too_big4.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/float_to_int_64_too_big5.stderr b/tests/fail/intrinsics/float_to_int_64_too_big5.stderr index ab5b2c954aecc..cb5eba490b447 100644 --- a/tests/fail/intrinsics/float_to_int_64_too_big5.stderr +++ b/tests/fail/intrinsics/float_to_int_64_too_big5.stderr @@ -6,7 +6,7 @@ LL | float_to_int_unchecked::(2402823669209384634633746074317 | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/float_to_int_64_too_big5.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/float_to_int_64_too_big6.stderr b/tests/fail/intrinsics/float_to_int_64_too_big6.stderr index e64ab2262715c..d899d2f808a5d 100644 --- a/tests/fail/intrinsics/float_to_int_64_too_big6.stderr +++ b/tests/fail/intrinsics/float_to_int_64_too_big6.stderr @@ -6,7 +6,7 @@ LL | float_to_int_unchecked::(f64::MAX); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/float_to_int_64_too_big6.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/float_to_int_64_too_big7.stderr b/tests/fail/intrinsics/float_to_int_64_too_big7.stderr index e9809e3ba5899..443b2759c2606 100644 --- a/tests/fail/intrinsics/float_to_int_64_too_big7.stderr +++ b/tests/fail/intrinsics/float_to_int_64_too_big7.stderr @@ -6,7 +6,7 @@ LL | float_to_int_unchecked::(f64::MIN); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/float_to_int_64_too_big7.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/float_to_int_64_too_small1.stderr b/tests/fail/intrinsics/float_to_int_64_too_small1.stderr index 714205ca1bebd..f8d88c44aa80d 100644 --- a/tests/fail/intrinsics/float_to_int_64_too_small1.stderr +++ b/tests/fail/intrinsics/float_to_int_64_too_small1.stderr @@ -6,7 +6,7 @@ LL | float_to_int_unchecked::(-2147483649.0f64); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/float_to_int_64_too_small1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/float_to_int_64_too_small2.stderr b/tests/fail/intrinsics/float_to_int_64_too_small2.stderr index b2302bf905ac6..d94e57b1e67c2 100644 --- a/tests/fail/intrinsics/float_to_int_64_too_small2.stderr +++ b/tests/fail/intrinsics/float_to_int_64_too_small2.stderr @@ -6,7 +6,7 @@ LL | float_to_int_unchecked::(-9223372036854777856.0f64); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/float_to_int_64_too_small2.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/float_to_int_64_too_small3.stderr b/tests/fail/intrinsics/float_to_int_64_too_small3.stderr index bcff0fb630423..59b74f5f51f37 100644 --- a/tests/fail/intrinsics/float_to_int_64_too_small3.stderr +++ b/tests/fail/intrinsics/float_to_int_64_too_small3.stderr @@ -6,7 +6,7 @@ LL | float_to_int_unchecked::(-240282366920938463463374607431 | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/float_to_int_64_too_small3.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/out_of_bounds_ptr_1.stderr b/tests/fail/intrinsics/out_of_bounds_ptr_1.stderr index afa2c8306466c..4422310870a64 100644 --- a/tests/fail/intrinsics/out_of_bounds_ptr_1.stderr +++ b/tests/fail/intrinsics/out_of_bounds_ptr_1.stderr @@ -6,7 +6,7 @@ LL | let x = unsafe { x.offset(5) }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/out_of_bounds_ptr_1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/out_of_bounds_ptr_2.stderr b/tests/fail/intrinsics/out_of_bounds_ptr_2.stderr index a32b50a18e6a6..6a11ebae108f0 100644 --- a/tests/fail/intrinsics/out_of_bounds_ptr_2.stderr +++ b/tests/fail/intrinsics/out_of_bounds_ptr_2.stderr @@ -6,7 +6,7 @@ LL | let x = unsafe { x.offset(isize::MIN) }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/out_of_bounds_ptr_2.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/out_of_bounds_ptr_3.stderr b/tests/fail/intrinsics/out_of_bounds_ptr_3.stderr index d06c33beb48a1..1364e0f9009d8 100644 --- a/tests/fail/intrinsics/out_of_bounds_ptr_3.stderr +++ b/tests/fail/intrinsics/out_of_bounds_ptr_3.stderr @@ -6,7 +6,7 @@ LL | let x = unsafe { x.offset(-1) }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/out_of_bounds_ptr_3.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/overflowing-unchecked-rsh.stderr b/tests/fail/intrinsics/overflowing-unchecked-rsh.stderr index bba92602285ac..9c5d0d13108ce 100644 --- a/tests/fail/intrinsics/overflowing-unchecked-rsh.stderr +++ b/tests/fail/intrinsics/overflowing-unchecked-rsh.stderr @@ -6,7 +6,7 @@ LL | let _n = 1i64.unchecked_shr(64); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/overflowing-unchecked-rsh.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/ptr_offset_0_plus_0.stderr b/tests/fail/intrinsics/ptr_offset_0_plus_0.stderr index 40a5022351dd7..9c1c387d54991 100644 --- a/tests/fail/intrinsics/ptr_offset_0_plus_0.stderr +++ b/tests/fail/intrinsics/ptr_offset_0_plus_0.stderr @@ -6,7 +6,7 @@ LL | let _x = unsafe { x.offset(0) }; // UB despite offset 0, NULL is never | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/ptr_offset_0_plus_0.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/ptr_offset_from_oob.stderr b/tests/fail/intrinsics/ptr_offset_from_oob.stderr index 546245a499e12..a31b929d7a7ae 100644 --- a/tests/fail/intrinsics/ptr_offset_from_oob.stderr +++ b/tests/fail/intrinsics/ptr_offset_from_oob.stderr @@ -6,7 +6,7 @@ LL | unsafe { end_ptr.offset_from(end_ptr) }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/ptr_offset_from_oob.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/ptr_offset_from_unsigned_neg.stderr b/tests/fail/intrinsics/ptr_offset_from_unsigned_neg.stderr index 419b7497a2f9c..803aaaa55c21e 100644 --- a/tests/fail/intrinsics/ptr_offset_from_unsigned_neg.stderr +++ b/tests/fail/intrinsics/ptr_offset_from_unsigned_neg.stderr @@ -6,7 +6,7 @@ LL | let _val = unsafe { ptr1.sub_ptr(ptr2) }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/ptr_offset_from_unsigned_neg.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/ptr_offset_int_plus_int.stderr b/tests/fail/intrinsics/ptr_offset_int_plus_int.stderr index a96717a067071..f76881011d079 100644 --- a/tests/fail/intrinsics/ptr_offset_int_plus_int.stderr +++ b/tests/fail/intrinsics/ptr_offset_int_plus_int.stderr @@ -6,7 +6,7 @@ LL | let _val = (1 as *mut u8).offset(1); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/ptr_offset_int_plus_int.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/ptr_offset_int_plus_ptr.stderr b/tests/fail/intrinsics/ptr_offset_int_plus_ptr.stderr index c1abe01dcea56..6e0744b7d5c39 100644 --- a/tests/fail/intrinsics/ptr_offset_int_plus_ptr.stderr +++ b/tests/fail/intrinsics/ptr_offset_int_plus_ptr.stderr @@ -6,7 +6,7 @@ LL | let _val = (1 as *mut u8).offset(ptr as isize); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/ptr_offset_int_plus_ptr.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/ptr_offset_overflow.stderr b/tests/fail/intrinsics/ptr_offset_overflow.stderr index d5935006e43bc..6fb94cf5f8122 100644 --- a/tests/fail/intrinsics/ptr_offset_overflow.stderr +++ b/tests/fail/intrinsics/ptr_offset_overflow.stderr @@ -6,7 +6,7 @@ LL | let _val = unsafe { x.offset(isize::MIN) }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/ptr_offset_overflow.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/ptr_offset_ptr_plus_0.stderr b/tests/fail/intrinsics/ptr_offset_ptr_plus_0.stderr index 5c516d5a490f3..b18147ce379d7 100644 --- a/tests/fail/intrinsics/ptr_offset_ptr_plus_0.stderr +++ b/tests/fail/intrinsics/ptr_offset_ptr_plus_0.stderr @@ -6,7 +6,7 @@ LL | let _x = unsafe { x.offset(0) }; // UB despite offset 0, the pointer is | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/ptr_offset_ptr_plus_0.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/raw_eq_on_ptr.stderr b/tests/fail/intrinsics/raw_eq_on_ptr.stderr index 6c5e618315c80..c6ed1750c04e0 100644 --- a/tests/fail/intrinsics/raw_eq_on_ptr.stderr +++ b/tests/fail/intrinsics/raw_eq_on_ptr.stderr @@ -5,7 +5,7 @@ LL | unsafe { raw_eq(&x, &x) }; | ^^^^^^^^^^^^^^ unable to turn pointer into raw bytes | = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/raw_eq_on_ptr.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/rem-by-zero.stderr b/tests/fail/intrinsics/rem-by-zero.stderr index 1da33d8eaf59c..1fc39188e5a94 100644 --- a/tests/fail/intrinsics/rem-by-zero.stderr +++ b/tests/fail/intrinsics/rem-by-zero.stderr @@ -6,7 +6,7 @@ LL | let _n = unchecked_rem(3u32, 0); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/rem-by-zero.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/simd-div-by-zero.stderr b/tests/fail/intrinsics/simd-div-by-zero.stderr index 552749c48ea7d..ddab24d0c1639 100644 --- a/tests/fail/intrinsics/simd-div-by-zero.stderr +++ b/tests/fail/intrinsics/simd-div-by-zero.stderr @@ -6,7 +6,7 @@ LL | simd_div(x, y); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/simd-div-by-zero.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/simd-div-overflow.stderr b/tests/fail/intrinsics/simd-div-overflow.stderr index 98a3c15162708..27d4dd9e3e73f 100644 --- a/tests/fail/intrinsics/simd-div-overflow.stderr +++ b/tests/fail/intrinsics/simd-div-overflow.stderr @@ -6,7 +6,7 @@ LL | simd_div(x, y); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/simd-div-overflow.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/simd-float-to-int.stderr b/tests/fail/intrinsics/simd-float-to-int.stderr index d29b356d268dc..36bb9643b48d4 100644 --- a/tests/fail/intrinsics/simd-float-to-int.stderr +++ b/tests/fail/intrinsics/simd-float-to-int.stderr @@ -6,7 +6,7 @@ LL | unsafe { intrinsics::simd_cast(self) } | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `std::simd::Simd::::to_int_unchecked::` at RUSTLIB/core/src/../../portable-simd/crates/core_simd/src/vector.rs:LL:CC note: inside `main` at $DIR/simd-float-to-int.rs:LL:CC --> $DIR/simd-float-to-int.rs:LL:CC diff --git a/tests/fail/intrinsics/simd-gather.stderr b/tests/fail/intrinsics/simd-gather.stderr index a23307c05ffbc..29a4ef65705ab 100644 --- a/tests/fail/intrinsics/simd-gather.stderr +++ b/tests/fail/intrinsics/simd-gather.stderr @@ -6,7 +6,7 @@ LL | unsafe { intrinsics::simd_gather(or, ptrs, enable.to_int()) } | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `std::simd::Simd::::gather_select_unchecked` at RUSTLIB/core/src/../../portable-simd/crates/core_simd/src/vector.rs:LL:CC note: inside `main` at $DIR/simd-gather.rs:LL:CC --> $DIR/simd-gather.rs:LL:CC diff --git a/tests/fail/intrinsics/simd-reduce-invalid-bool.stderr b/tests/fail/intrinsics/simd-reduce-invalid-bool.stderr index 5a44861feee1c..1e5ac5277e6dc 100644 --- a/tests/fail/intrinsics/simd-reduce-invalid-bool.stderr +++ b/tests/fail/intrinsics/simd-reduce-invalid-bool.stderr @@ -6,7 +6,7 @@ LL | simd_reduce_any(x); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/simd-reduce-invalid-bool.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/simd-rem-by-zero.stderr b/tests/fail/intrinsics/simd-rem-by-zero.stderr index dd68d3aa18406..96248e7e599cc 100644 --- a/tests/fail/intrinsics/simd-rem-by-zero.stderr +++ b/tests/fail/intrinsics/simd-rem-by-zero.stderr @@ -6,7 +6,7 @@ LL | simd_rem(x, y); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/simd-rem-by-zero.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/simd-scatter.stderr b/tests/fail/intrinsics/simd-scatter.stderr index ba8c8f3470601..fde85a63503b6 100644 --- a/tests/fail/intrinsics/simd-scatter.stderr +++ b/tests/fail/intrinsics/simd-scatter.stderr @@ -6,7 +6,7 @@ LL | intrinsics::simd_scatter(self, ptrs, enable.to_int()) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `std::simd::Simd::::scatter_select_unchecked` at RUSTLIB/core/src/../../portable-simd/crates/core_simd/src/vector.rs:LL:CC note: inside `main` at $DIR/simd-scatter.rs:LL:CC --> $DIR/simd-scatter.rs:LL:CC diff --git a/tests/fail/intrinsics/simd-select-bitmask-invalid.stderr b/tests/fail/intrinsics/simd-select-bitmask-invalid.stderr index 7b3b3292ef78a..e72cce998d0ed 100644 --- a/tests/fail/intrinsics/simd-select-bitmask-invalid.stderr +++ b/tests/fail/intrinsics/simd-select-bitmask-invalid.stderr @@ -6,7 +6,7 @@ LL | simd_select_bitmask(0b11111111u8, x, x); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/simd-select-bitmask-invalid.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/simd-select-invalid-bool.stderr b/tests/fail/intrinsics/simd-select-invalid-bool.stderr index ad5a89310681f..277ceb54ec71e 100644 --- a/tests/fail/intrinsics/simd-select-invalid-bool.stderr +++ b/tests/fail/intrinsics/simd-select-invalid-bool.stderr @@ -6,7 +6,7 @@ LL | simd_select(x, x, x); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/simd-select-invalid-bool.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/simd-shl-too-far.stderr b/tests/fail/intrinsics/simd-shl-too-far.stderr index cea99f681932f..c8445bb3cdc75 100644 --- a/tests/fail/intrinsics/simd-shl-too-far.stderr +++ b/tests/fail/intrinsics/simd-shl-too-far.stderr @@ -6,7 +6,7 @@ LL | simd_shl(x, y); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/simd-shl-too-far.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/simd-shr-too-far.stderr b/tests/fail/intrinsics/simd-shr-too-far.stderr index df3288a805c8e..8eec30c5a52f2 100644 --- a/tests/fail/intrinsics/simd-shr-too-far.stderr +++ b/tests/fail/intrinsics/simd-shr-too-far.stderr @@ -6,7 +6,7 @@ LL | simd_shr(x, y); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/simd-shr-too-far.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/unchecked_add1.stderr b/tests/fail/intrinsics/unchecked_add1.stderr index 062acbb8de8cf..f5e96198ee4c9 100644 --- a/tests/fail/intrinsics/unchecked_add1.stderr +++ b/tests/fail/intrinsics/unchecked_add1.stderr @@ -6,7 +6,7 @@ LL | let _val = unsafe { 40000u16.unchecked_add(30000) }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/unchecked_add1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/unchecked_add2.stderr b/tests/fail/intrinsics/unchecked_add2.stderr index 09b622d6e2960..5a5c7070ae0b4 100644 --- a/tests/fail/intrinsics/unchecked_add2.stderr +++ b/tests/fail/intrinsics/unchecked_add2.stderr @@ -6,7 +6,7 @@ LL | let _val = unsafe { (-30000i16).unchecked_add(-8000) }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/unchecked_add2.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/unchecked_div1.stderr b/tests/fail/intrinsics/unchecked_div1.stderr index 867c8e0a9d398..9267e0c494731 100644 --- a/tests/fail/intrinsics/unchecked_div1.stderr +++ b/tests/fail/intrinsics/unchecked_div1.stderr @@ -6,7 +6,7 @@ LL | std::intrinsics::unchecked_div(i16::MIN, -1); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/unchecked_div1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/unchecked_mul1.stderr b/tests/fail/intrinsics/unchecked_mul1.stderr index e260c343c4e62..9a5a585e1cce4 100644 --- a/tests/fail/intrinsics/unchecked_mul1.stderr +++ b/tests/fail/intrinsics/unchecked_mul1.stderr @@ -6,7 +6,7 @@ LL | let _val = unsafe { 300u16.unchecked_mul(250u16) }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/unchecked_mul1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/unchecked_mul2.stderr b/tests/fail/intrinsics/unchecked_mul2.stderr index 88b3a49b98eca..46b9f61821728 100644 --- a/tests/fail/intrinsics/unchecked_mul2.stderr +++ b/tests/fail/intrinsics/unchecked_mul2.stderr @@ -6,7 +6,7 @@ LL | let _val = unsafe { 1_000_000_000i32.unchecked_mul(-4) }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/unchecked_mul2.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/unchecked_sub1.stderr b/tests/fail/intrinsics/unchecked_sub1.stderr index ebd7bc10eb413..01e569767bac0 100644 --- a/tests/fail/intrinsics/unchecked_sub1.stderr +++ b/tests/fail/intrinsics/unchecked_sub1.stderr @@ -6,7 +6,7 @@ LL | let _val = unsafe { 14u32.unchecked_sub(22) }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/unchecked_sub1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/unchecked_sub2.stderr b/tests/fail/intrinsics/unchecked_sub2.stderr index 73d7c4d86bc02..38c1647b4f49f 100644 --- a/tests/fail/intrinsics/unchecked_sub2.stderr +++ b/tests/fail/intrinsics/unchecked_sub2.stderr @@ -6,7 +6,7 @@ LL | let _val = unsafe { 30000i16.unchecked_sub(-7000) }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/unchecked_sub2.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/write_bytes_null.stderr b/tests/fail/intrinsics/write_bytes_null.stderr index 8fd866aa8b325..b2969ca3b5929 100644 --- a/tests/fail/intrinsics/write_bytes_null.stderr +++ b/tests/fail/intrinsics/write_bytes_null.stderr @@ -6,7 +6,7 @@ LL | unsafe { write_bytes::(std::ptr::null_mut(), 0, 0) }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/write_bytes_null.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/intrinsics/write_bytes_overflow.stderr b/tests/fail/intrinsics/write_bytes_overflow.stderr index 47610b0623012..f88afde879acf 100644 --- a/tests/fail/intrinsics/write_bytes_overflow.stderr +++ b/tests/fail/intrinsics/write_bytes_overflow.stderr @@ -6,7 +6,7 @@ LL | (&mut y as *mut i32).write_bytes(0u8, 1usize << (mem::size_of::::uninit().assume_init() } | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/invalid_int.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/issue-miri-1112.stderr b/tests/fail/issue-miri-1112.stderr index 4a2bdb0f414d4..e6644a72849ff 100644 --- a/tests/fail/issue-miri-1112.stderr +++ b/tests/fail/issue-miri-1112.stderr @@ -6,7 +6,7 @@ LL | let obj = std::mem::transmute::(obj) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `FunnyPointer::from_data_ptr` at $DIR/issue-miri-1112.rs:LL:CC note: inside `main` at $DIR/issue-miri-1112.rs:LL:CC --> $DIR/issue-miri-1112.rs:LL:CC diff --git a/tests/fail/issue-miri-2432.stderr b/tests/fail/issue-miri-2432.stderr index a5c9300fb07ca..b8e13b61ceb60 100644 --- a/tests/fail/issue-miri-2432.stderr +++ b/tests/fail/issue-miri-2432.stderr @@ -6,7 +6,7 @@ LL | ::foo(&()); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/issue-miri-2432.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/modifying_constants.stderr b/tests/fail/modifying_constants.stderr index 853e3a9015e7b..6425a5d7a0ad4 100644 --- a/tests/fail/modifying_constants.stderr +++ b/tests/fail/modifying_constants.stderr @@ -6,7 +6,7 @@ LL | *y = 42; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/modifying_constants.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/never_say_never.stderr b/tests/fail/never_say_never.stderr index 4072a0376f5c7..a2a63b8baf594 100644 --- a/tests/fail/never_say_never.stderr +++ b/tests/fail/never_say_never.stderr @@ -6,7 +6,7 @@ LL | *(y as *const _ as *const !) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/never_say_never.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/never_transmute_humans.stderr b/tests/fail/never_transmute_humans.stderr index 2a8ee0a3e9bd1..e8df4739f9bcb 100644 --- a/tests/fail/never_transmute_humans.stderr +++ b/tests/fail/never_transmute_humans.stderr @@ -6,7 +6,7 @@ LL | std::mem::transmute::(Human) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/never_transmute_humans.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/never_transmute_void.stderr b/tests/fail/never_transmute_void.stderr index 31614ef3edf88..4c3a3d075f028 100644 --- a/tests/fail/never_transmute_void.stderr +++ b/tests/fail/never_transmute_void.stderr @@ -6,7 +6,7 @@ LL | match v.0 {} | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `m::f` at $DIR/never_transmute_void.rs:LL:CC note: inside `main` at $DIR/never_transmute_void.rs:LL:CC --> $DIR/never_transmute_void.rs:LL:CC diff --git a/tests/fail/panic/bad_miri_start_panic.stderr b/tests/fail/panic/bad_miri_start_panic.stderr index a664590e36ae1..3bd2be03ea1ff 100644 --- a/tests/fail/panic/bad_miri_start_panic.stderr +++ b/tests/fail/panic/bad_miri_start_panic.stderr @@ -6,7 +6,7 @@ LL | unsafe { miri_start_panic(&mut 0) } | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/bad_miri_start_panic.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/panic/bad_unwind.stderr b/tests/fail/panic/bad_unwind.stderr index be8a3668ac522..23c33f5e7f3ff 100644 --- a/tests/fail/panic/bad_unwind.stderr +++ b/tests/fail/panic/bad_unwind.stderr @@ -8,7 +8,7 @@ LL | std::panic::catch_unwind(|| unwind()).unwrap_err(); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside closure at $DIR/bad_unwind.rs:LL:CC = note: inside `std::panicking::r#try::do_call::<[closure@$DIR/bad_unwind.rs:LL:CC], ()>` at RUSTLIB/std/src/panicking.rs:LL:CC = note: inside `std::panicking::r#try::<(), [closure@$DIR/bad_unwind.rs:LL:CC]>` at RUSTLIB/std/src/panicking.rs:LL:CC diff --git a/tests/fail/panic/unwind_panic_abort.stderr b/tests/fail/panic/unwind_panic_abort.stderr index df4b9522f4671..363e69ba41db9 100644 --- a/tests/fail/panic/unwind_panic_abort.stderr +++ b/tests/fail/panic/unwind_panic_abort.stderr @@ -6,7 +6,7 @@ LL | miri_start_panic(&mut 0); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/unwind_panic_abort.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/pointer_partial_overwrite.stderr b/tests/fail/pointer_partial_overwrite.stderr index cd3c4ddd6ca43..7d10b75e8805f 100644 --- a/tests/fail/pointer_partial_overwrite.stderr +++ b/tests/fail/pointer_partial_overwrite.stderr @@ -6,7 +6,7 @@ LL | let x = *p; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/pointer_partial_overwrite.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/provenance/provenance_transmute.stderr b/tests/fail/provenance/provenance_transmute.stderr index 5b7e9442d7c07..f7c5f6046e198 100644 --- a/tests/fail/provenance/provenance_transmute.stderr +++ b/tests/fail/provenance/provenance_transmute.stderr @@ -6,7 +6,7 @@ LL | let _val = *left_ptr; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `deref` at $DIR/provenance_transmute.rs:LL:CC note: inside `main` at $DIR/provenance_transmute.rs:LL:CC --> $DIR/provenance_transmute.rs:LL:CC diff --git a/tests/fail/provenance/ptr_int_unexposed.stderr b/tests/fail/provenance/ptr_int_unexposed.stderr index f5ea7718c78ae..4ad885ddabdc0 100644 --- a/tests/fail/provenance/ptr_int_unexposed.stderr +++ b/tests/fail/provenance/ptr_int_unexposed.stderr @@ -6,7 +6,7 @@ LL | assert_eq!(unsafe { *ptr }, 3); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/ptr_int_unexposed.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/provenance/ptr_invalid.stderr b/tests/fail/provenance/ptr_invalid.stderr index 02bfef3ae73f2..ef9dcad97cbdc 100644 --- a/tests/fail/provenance/ptr_invalid.stderr +++ b/tests/fail/provenance/ptr_invalid.stderr @@ -6,7 +6,7 @@ LL | let _val = unsafe { *xptr_invalid }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/ptr_invalid.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/provenance/ptr_invalid_offset.stderr b/tests/fail/provenance/ptr_invalid_offset.stderr index 813a6515b7714..3607635c8fbe5 100644 --- a/tests/fail/provenance/ptr_invalid_offset.stderr +++ b/tests/fail/provenance/ptr_invalid_offset.stderr @@ -6,7 +6,7 @@ LL | let _ = unsafe { roundtrip.offset(1) }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/ptr_invalid_offset.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/provenance/strict_provenance_cast.stderr b/tests/fail/provenance/strict_provenance_cast.stderr index 5796a3196dc6c..998ccc8bb49c6 100644 --- a/tests/fail/provenance/strict_provenance_cast.stderr +++ b/tests/fail/provenance/strict_provenance_cast.stderr @@ -5,7 +5,7 @@ LL | let _ptr = std::ptr::from_exposed_addr::(addr); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ integer-to-pointer casts and `ptr::from_exposed_addr` are not supported with `-Zmiri-strict-provenance` | = help: use Strict Provenance APIs (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance, https://crates.io/crates/sptr) instead - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/strict_provenance_cast.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/rc_as_ptr.stderr b/tests/fail/rc_as_ptr.stderr index f2dd245be3458..70bdd157bdc34 100644 --- a/tests/fail/rc_as_ptr.stderr +++ b/tests/fail/rc_as_ptr.stderr @@ -6,7 +6,7 @@ LL | assert_eq!(42, **unsafe { &*Weak::as_ptr(&weak) }); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at RUSTLIB/core/src/macros/mod.rs:LL:CC = note: this error originates in the macro `assert_eq` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/fail/reading_half_a_pointer.stderr b/tests/fail/reading_half_a_pointer.stderr index d6690f0c7a012..28cd7cef24334 100644 --- a/tests/fail/reading_half_a_pointer.stderr +++ b/tests/fail/reading_half_a_pointer.stderr @@ -5,7 +5,7 @@ LL | let _x = *d_alias; | ^^^^^^^^ unable to turn pointer into raw bytes | = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/reading_half_a_pointer.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/shims/backtrace/bad-backtrace-decl.stderr b/tests/fail/shims/backtrace/bad-backtrace-decl.stderr index 3cb4a8e8a4589..200f5f56213d6 100644 --- a/tests/fail/shims/backtrace/bad-backtrace-decl.stderr +++ b/tests/fail/shims/backtrace/bad-backtrace-decl.stderr @@ -6,7 +6,7 @@ LL | ... miri_resolve_frame(*frame, 0); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/bad-backtrace-decl.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/shims/backtrace/bad-backtrace-flags.stderr b/tests/fail/shims/backtrace/bad-backtrace-flags.stderr index f186fb1e57179..5d51790f8a5c1 100644 --- a/tests/fail/shims/backtrace/bad-backtrace-flags.stderr +++ b/tests/fail/shims/backtrace/bad-backtrace-flags.stderr @@ -5,7 +5,7 @@ LL | miri_get_backtrace(2, std::ptr::null_mut()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unknown `miri_get_backtrace` flags 2 | = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/bad-backtrace-flags.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/shims/backtrace/bad-backtrace-ptr.stderr b/tests/fail/shims/backtrace/bad-backtrace-ptr.stderr index 72755afb34a7c..f23f834000aa1 100644 --- a/tests/fail/shims/backtrace/bad-backtrace-ptr.stderr +++ b/tests/fail/shims/backtrace/bad-backtrace-ptr.stderr @@ -6,7 +6,7 @@ LL | miri_resolve_frame(std::ptr::null_mut(), 0); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/bad-backtrace-ptr.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/shims/backtrace/bad-backtrace-resolve-flags.stderr b/tests/fail/shims/backtrace/bad-backtrace-resolve-flags.stderr index cf80488de22dd..fe123c2352f0a 100644 --- a/tests/fail/shims/backtrace/bad-backtrace-resolve-flags.stderr +++ b/tests/fail/shims/backtrace/bad-backtrace-resolve-flags.stderr @@ -5,7 +5,7 @@ LL | miri_resolve_frame(buf[0], 2); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unknown `miri_resolve_frame` flags 2 | = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/bad-backtrace-resolve-flags.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/shims/backtrace/bad-backtrace-resolve-names-flags.stderr b/tests/fail/shims/backtrace/bad-backtrace-resolve-names-flags.stderr index c7e0d41009ad0..a3003c9093f72 100644 --- a/tests/fail/shims/backtrace/bad-backtrace-resolve-names-flags.stderr +++ b/tests/fail/shims/backtrace/bad-backtrace-resolve-names-flags.stderr @@ -5,7 +5,7 @@ LL | ... miri_resolve_frame_names(buf[0], 2, std::ptr::null_mut(), std::ptr::n | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unknown `miri_resolve_frame_names` flags 2 | = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/bad-backtrace-resolve-names-flags.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/shims/backtrace/bad-backtrace-size-flags.stderr b/tests/fail/shims/backtrace/bad-backtrace-size-flags.stderr index 0cfe5d7173ce1..b4a02c0e363ed 100644 --- a/tests/fail/shims/backtrace/bad-backtrace-size-flags.stderr +++ b/tests/fail/shims/backtrace/bad-backtrace-size-flags.stderr @@ -5,7 +5,7 @@ LL | miri_backtrace_size(2); | ^^^^^^^^^^^^^^^^^^^^^^ unknown `miri_backtrace_size` flags 2 | = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/bad-backtrace-size-flags.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/shims/fs/close_stdout.stderr b/tests/fail/shims/fs/close_stdout.stderr index eb2c54e05f1fa..02f1eee97fc04 100644 --- a/tests/fail/shims/fs/close_stdout.stderr +++ b/tests/fail/shims/fs/close_stdout.stderr @@ -5,7 +5,7 @@ LL | libc::close(1); | ^^^^^^^^^^^^^^ cannot close stdout | = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/close_stdout.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/shims/fs/isolated_file.stderr b/tests/fail/shims/fs/isolated_file.stderr index e75d7b7c3d93b..4e3fdc7a45801 100644 --- a/tests/fail/shims/fs/isolated_file.stderr +++ b/tests/fail/shims/fs/isolated_file.stderr @@ -6,7 +6,7 @@ LL | let fd = cvt_r(|| unsafe { open64(path.as_ptr(), flags, opts.mode a | = help: pass the flag `-Zmiri-disable-isolation` to disable isolation; = help: or pass `-Zmiri-isolation-error=warn` to configure Miri to return an error code from isolated operations (if supported for that operation) and continue with a warning - = note: backtrace: + = note: BACKTRACE: = note: inside closure at RUSTLIB/std/src/sys/PLATFORM/fs.rs:LL:CC = note: inside `std::sys::PLATFORM::cvt_r::` at RUSTLIB/std/src/sys/PLATFORM/mod.rs:LL:CC = note: inside `std::sys::PLATFORM::fs::File::open_c` at RUSTLIB/std/src/sys/PLATFORM/fs.rs:LL:CC diff --git a/tests/fail/shims/fs/isolated_stdin.stderr b/tests/fail/shims/fs/isolated_stdin.stderr index fe9700f07b396..ed826147e3bdb 100644 --- a/tests/fail/shims/fs/isolated_stdin.stderr +++ b/tests/fail/shims/fs/isolated_stdin.stderr @@ -6,7 +6,7 @@ LL | libc::read(0, bytes.as_mut_ptr() as *mut libc::c_void, 512); | = help: pass the flag `-Zmiri-disable-isolation` to disable isolation; = help: or pass `-Zmiri-isolation-error=warn` to configure Miri to return an error code from isolated operations (if supported for that operation) and continue with a warning - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/isolated_stdin.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/shims/fs/mkstemp_immutable_arg.stderr b/tests/fail/shims/fs/mkstemp_immutable_arg.stderr index 0bd91f90a10f3..414ac1cb1b702 100644 --- a/tests/fail/shims/fs/mkstemp_immutable_arg.stderr +++ b/tests/fail/shims/fs/mkstemp_immutable_arg.stderr @@ -6,7 +6,7 @@ LL | let _fd = unsafe { libc::mkstemp(s) }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `test_mkstemp_immutable_arg` at $DIR/mkstemp_immutable_arg.rs:LL:CC note: inside `main` at $DIR/mkstemp_immutable_arg.rs:LL:CC --> $DIR/mkstemp_immutable_arg.rs:LL:CC diff --git a/tests/fail/shims/fs/read_from_stdout.stderr b/tests/fail/shims/fs/read_from_stdout.stderr index 5c16999cbf79a..bcece7ad4e55d 100644 --- a/tests/fail/shims/fs/read_from_stdout.stderr +++ b/tests/fail/shims/fs/read_from_stdout.stderr @@ -5,7 +5,7 @@ LL | libc::read(1, bytes.as_mut_ptr() as *mut libc::c_void, 512); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot read from stdout | = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/read_from_stdout.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/shims/fs/unix_open_missing_required_mode.stderr b/tests/fail/shims/fs/unix_open_missing_required_mode.stderr index a7297efaff960..38d033b494554 100644 --- a/tests/fail/shims/fs/unix_open_missing_required_mode.stderr +++ b/tests/fail/shims/fs/unix_open_missing_required_mode.stderr @@ -6,7 +6,7 @@ LL | ...safe { libc::open(name_ptr, libc::O_CREAT) }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `test_file_open_missing_needed_mode` at $DIR/unix_open_missing_required_mode.rs:LL:CC note: inside `main` at $DIR/unix_open_missing_required_mode.rs:LL:CC --> $DIR/unix_open_missing_required_mode.rs:LL:CC diff --git a/tests/fail/shims/fs/write_to_stdin.stderr b/tests/fail/shims/fs/write_to_stdin.stderr index 518d36b5551bf..d4a38e1ca9615 100644 --- a/tests/fail/shims/fs/write_to_stdin.stderr +++ b/tests/fail/shims/fs/write_to_stdin.stderr @@ -5,7 +5,7 @@ LL | libc::write(0, bytes.as_ptr() as *const libc::c_void, 5); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot write to stdin | = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/write_to_stdin.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/shims/shim_arg_size.64bit.stderr b/tests/fail/shims/shim_arg_size.64bit.stderr index 98ed99d6d729e..0e8b402ac7147 100644 --- a/tests/fail/shims/shim_arg_size.64bit.stderr +++ b/tests/fail/shims/shim_arg_size.64bit.stderr @@ -6,7 +6,7 @@ LL | let _p1 = malloc(42); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/shim_arg_size.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/shims/sync/libc_pthread_cond_double_destroy.stderr b/tests/fail/shims/sync/libc_pthread_cond_double_destroy.stderr index 0e1c776f59658..ecfedf753703d 100644 --- a/tests/fail/shims/sync/libc_pthread_cond_double_destroy.stderr +++ b/tests/fail/shims/sync/libc_pthread_cond_double_destroy.stderr @@ -6,7 +6,7 @@ LL | libc::pthread_cond_destroy(cond.as_mut_ptr()); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/libc_pthread_cond_double_destroy.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/shims/sync/libc_pthread_condattr_double_destroy.stderr b/tests/fail/shims/sync/libc_pthread_condattr_double_destroy.stderr index dee50249b6b63..f39d909adbd64 100644 --- a/tests/fail/shims/sync/libc_pthread_condattr_double_destroy.stderr +++ b/tests/fail/shims/sync/libc_pthread_condattr_double_destroy.stderr @@ -6,7 +6,7 @@ LL | libc::pthread_condattr_destroy(attr.as_mut_ptr()); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/libc_pthread_condattr_double_destroy.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/shims/sync/libc_pthread_mutex_NULL_deadlock.stderr b/tests/fail/shims/sync/libc_pthread_mutex_NULL_deadlock.stderr index 1b40f39d04bc2..4a138e6f8a25c 100644 --- a/tests/fail/shims/sync/libc_pthread_mutex_NULL_deadlock.stderr +++ b/tests/fail/shims/sync/libc_pthread_mutex_NULL_deadlock.stderr @@ -6,7 +6,7 @@ LL | libc::pthread_mutex_lock(&mut mutex as *mut _); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/libc_pthread_mutex_NULL_deadlock.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/shims/sync/libc_pthread_mutex_default_deadlock.stderr b/tests/fail/shims/sync/libc_pthread_mutex_default_deadlock.stderr index 7606472beb979..8aea3f5c6932f 100644 --- a/tests/fail/shims/sync/libc_pthread_mutex_default_deadlock.stderr +++ b/tests/fail/shims/sync/libc_pthread_mutex_default_deadlock.stderr @@ -6,7 +6,7 @@ LL | libc::pthread_mutex_lock(&mut mutex as *mut _); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/libc_pthread_mutex_default_deadlock.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/shims/sync/libc_pthread_mutex_destroy_locked.stderr b/tests/fail/shims/sync/libc_pthread_mutex_destroy_locked.stderr index 40a7b3de09d58..a8ab948116e14 100644 --- a/tests/fail/shims/sync/libc_pthread_mutex_destroy_locked.stderr +++ b/tests/fail/shims/sync/libc_pthread_mutex_destroy_locked.stderr @@ -6,7 +6,7 @@ LL | libc::pthread_mutex_destroy(&mut mutex as *mut _); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/libc_pthread_mutex_destroy_locked.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/shims/sync/libc_pthread_mutex_double_destroy.stderr b/tests/fail/shims/sync/libc_pthread_mutex_double_destroy.stderr index 274d4496266b0..9620fdbd18b2f 100644 --- a/tests/fail/shims/sync/libc_pthread_mutex_double_destroy.stderr +++ b/tests/fail/shims/sync/libc_pthread_mutex_double_destroy.stderr @@ -6,7 +6,7 @@ LL | libc::pthread_mutex_destroy(mutex.as_mut_ptr()); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/libc_pthread_mutex_double_destroy.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/shims/sync/libc_pthread_mutex_normal_unlock_unlocked.stderr b/tests/fail/shims/sync/libc_pthread_mutex_normal_unlock_unlocked.stderr index daa9a7c514483..754137b85b9af 100644 --- a/tests/fail/shims/sync/libc_pthread_mutex_normal_unlock_unlocked.stderr +++ b/tests/fail/shims/sync/libc_pthread_mutex_normal_unlock_unlocked.stderr @@ -6,7 +6,7 @@ LL | libc::pthread_mutex_unlock(&mut mutex as *mut _); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/libc_pthread_mutex_normal_unlock_unlocked.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/shims/sync/libc_pthread_mutex_wrong_owner.stderr b/tests/fail/shims/sync/libc_pthread_mutex_wrong_owner.stderr index 83c22b2673d62..aa81b06fc80af 100644 --- a/tests/fail/shims/sync/libc_pthread_mutex_wrong_owner.stderr +++ b/tests/fail/shims/sync/libc_pthread_mutex_wrong_owner.stderr @@ -6,7 +6,7 @@ LL | ...t_eq!(libc::pthread_mutex_unlock(lock_copy.0.get() as *mut _), 0); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside closure at $DIR/libc_pthread_mutex_wrong_owner.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/shims/sync/libc_pthread_mutexattr_double_destroy.stderr b/tests/fail/shims/sync/libc_pthread_mutexattr_double_destroy.stderr index 44a201fe05836..82949047d2aab 100644 --- a/tests/fail/shims/sync/libc_pthread_mutexattr_double_destroy.stderr +++ b/tests/fail/shims/sync/libc_pthread_mutexattr_double_destroy.stderr @@ -6,7 +6,7 @@ LL | libc::pthread_mutexattr_destroy(attr.as_mut_ptr()); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/libc_pthread_mutexattr_double_destroy.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/shims/sync/libc_pthread_rwlock_destroy_read_locked.stderr b/tests/fail/shims/sync/libc_pthread_rwlock_destroy_read_locked.stderr index 43f8b2dcca6f9..be73e7f1e2ad4 100644 --- a/tests/fail/shims/sync/libc_pthread_rwlock_destroy_read_locked.stderr +++ b/tests/fail/shims/sync/libc_pthread_rwlock_destroy_read_locked.stderr @@ -6,7 +6,7 @@ LL | libc::pthread_rwlock_destroy(rw.get()); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/libc_pthread_rwlock_destroy_read_locked.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/shims/sync/libc_pthread_rwlock_destroy_write_locked.stderr b/tests/fail/shims/sync/libc_pthread_rwlock_destroy_write_locked.stderr index cbaa2b3fcce9f..bc2713a5ffbfa 100644 --- a/tests/fail/shims/sync/libc_pthread_rwlock_destroy_write_locked.stderr +++ b/tests/fail/shims/sync/libc_pthread_rwlock_destroy_write_locked.stderr @@ -6,7 +6,7 @@ LL | libc::pthread_rwlock_destroy(rw.get()); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/libc_pthread_rwlock_destroy_write_locked.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/shims/sync/libc_pthread_rwlock_double_destroy.stderr b/tests/fail/shims/sync/libc_pthread_rwlock_double_destroy.stderr index 159e1b9881a90..5004f84358da8 100644 --- a/tests/fail/shims/sync/libc_pthread_rwlock_double_destroy.stderr +++ b/tests/fail/shims/sync/libc_pthread_rwlock_double_destroy.stderr @@ -6,7 +6,7 @@ LL | libc::pthread_rwlock_destroy(&mut lock); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/libc_pthread_rwlock_double_destroy.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/shims/sync/libc_pthread_rwlock_read_wrong_owner.stderr b/tests/fail/shims/sync/libc_pthread_rwlock_read_wrong_owner.stderr index 0921f3d4b506c..7dfa27b43d073 100644 --- a/tests/fail/shims/sync/libc_pthread_rwlock_read_wrong_owner.stderr +++ b/tests/fail/shims/sync/libc_pthread_rwlock_read_wrong_owner.stderr @@ -6,7 +6,7 @@ LL | ... assert_eq!(libc::pthread_rwlock_unlock(lock_copy.0.get() as *mut _), | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside closure at $DIR/libc_pthread_rwlock_read_wrong_owner.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/shims/sync/libc_pthread_rwlock_unlock_unlocked.stderr b/tests/fail/shims/sync/libc_pthread_rwlock_unlock_unlocked.stderr index 67bfde22edcfe..1c25ac2c048fb 100644 --- a/tests/fail/shims/sync/libc_pthread_rwlock_unlock_unlocked.stderr +++ b/tests/fail/shims/sync/libc_pthread_rwlock_unlock_unlocked.stderr @@ -6,7 +6,7 @@ LL | libc::pthread_rwlock_unlock(rw.get()); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/libc_pthread_rwlock_unlock_unlocked.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/shims/sync/libc_pthread_rwlock_write_wrong_owner.stderr b/tests/fail/shims/sync/libc_pthread_rwlock_write_wrong_owner.stderr index d066cb687a1a7..5bf402c775ae5 100644 --- a/tests/fail/shims/sync/libc_pthread_rwlock_write_wrong_owner.stderr +++ b/tests/fail/shims/sync/libc_pthread_rwlock_write_wrong_owner.stderr @@ -6,7 +6,7 @@ LL | ... assert_eq!(libc::pthread_rwlock_unlock(lock_copy.0.get() as *mut _), | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside closure at $DIR/libc_pthread_rwlock_write_wrong_owner.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/should-pass/cpp20_rwc_syncs.stderr b/tests/fail/should-pass/cpp20_rwc_syncs.stderr index 17573a33b3d70..8a24b085a99f6 100644 --- a/tests/fail/should-pass/cpp20_rwc_syncs.stderr +++ b/tests/fail/should-pass/cpp20_rwc_syncs.stderr @@ -6,7 +6,7 @@ LL | std::hint::unreachable_unchecked(); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `test_cpp20_rwc_syncs` at $DIR/cpp20_rwc_syncs.rs:LL:CC note: inside `main` at $DIR/cpp20_rwc_syncs.rs:LL:CC --> $DIR/cpp20_rwc_syncs.rs:LL:CC diff --git a/tests/fail/stacked_borrows/alias_through_mutation.stderr b/tests/fail/stacked_borrows/alias_through_mutation.stderr index 74d1e4ebbcb84..461275c3fa346 100644 --- a/tests/fail/stacked_borrows/alias_through_mutation.stderr +++ b/tests/fail/stacked_borrows/alias_through_mutation.stderr @@ -19,7 +19,7 @@ help: was later invalidated at offsets [0x0..0x4] by a write access | LL | *target = 13; | ^^^^^^^^^^^^ - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/alias_through_mutation.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/aliasing_mut1.stderr b/tests/fail/stacked_borrows/aliasing_mut1.stderr index 514b1a9901e6a..5d4679b13ad1f 100644 --- a/tests/fail/stacked_borrows/aliasing_mut1.stderr +++ b/tests/fail/stacked_borrows/aliasing_mut1.stderr @@ -16,7 +16,7 @@ help: is this argument | LL | pub fn safe(_x: &mut i32, _y: &mut i32) {} | ^^ - = note: backtrace: + = note: BACKTRACE: = note: inside `safe` at $DIR/aliasing_mut1.rs:LL:CC note: inside `main` at $DIR/aliasing_mut1.rs:LL:CC --> $DIR/aliasing_mut1.rs:LL:CC diff --git a/tests/fail/stacked_borrows/aliasing_mut2.stderr b/tests/fail/stacked_borrows/aliasing_mut2.stderr index 5fc56a91f577d..c8408c150e779 100644 --- a/tests/fail/stacked_borrows/aliasing_mut2.stderr +++ b/tests/fail/stacked_borrows/aliasing_mut2.stderr @@ -16,7 +16,7 @@ help: is this argument | LL | pub fn safe(_x: &i32, _y: &mut i32) {} | ^^ - = note: backtrace: + = note: BACKTRACE: = note: inside `safe` at $DIR/aliasing_mut2.rs:LL:CC note: inside `main` at $DIR/aliasing_mut2.rs:LL:CC --> $DIR/aliasing_mut2.rs:LL:CC diff --git a/tests/fail/stacked_borrows/aliasing_mut3.stderr b/tests/fail/stacked_borrows/aliasing_mut3.stderr index ee38ea417003b..c2ea90f242a22 100644 --- a/tests/fail/stacked_borrows/aliasing_mut3.stderr +++ b/tests/fail/stacked_borrows/aliasing_mut3.stderr @@ -19,7 +19,7 @@ help: was later invalidated at offsets [0x0..0x4] by a Unique FnEntry reta | LL | safe_raw(xraw, xshr); | ^^^^^^^^^^^^^^^^^^^^ - = note: backtrace: + = note: BACKTRACE: = note: inside `safe` at $DIR/aliasing_mut3.rs:LL:CC note: inside `main` at $DIR/aliasing_mut3.rs:LL:CC --> $DIR/aliasing_mut3.rs:LL:CC diff --git a/tests/fail/stacked_borrows/aliasing_mut4.stderr b/tests/fail/stacked_borrows/aliasing_mut4.stderr index d5c2e73669679..c53fe70f6dd33 100644 --- a/tests/fail/stacked_borrows/aliasing_mut4.stderr +++ b/tests/fail/stacked_borrows/aliasing_mut4.stderr @@ -16,7 +16,7 @@ help: is this argument | LL | pub fn safe(_x: &i32, _y: &mut Cell) {} | ^^ - = note: backtrace: + = note: BACKTRACE: = note: inside `safe` at $DIR/aliasing_mut4.rs:LL:CC note: inside `main` at $DIR/aliasing_mut4.rs:LL:CC --> $DIR/aliasing_mut4.rs:LL:CC diff --git a/tests/fail/stacked_borrows/box_exclusive_violation1.stderr b/tests/fail/stacked_borrows/box_exclusive_violation1.stderr index dfe49d7f08926..d82b8342f1231 100644 --- a/tests/fail/stacked_borrows/box_exclusive_violation1.stderr +++ b/tests/fail/stacked_borrows/box_exclusive_violation1.stderr @@ -19,7 +19,7 @@ help: was later invalidated at offsets [0x0..0x4] by a write access | LL | *our = 5; | ^^^^^^^^ - = note: backtrace: + = note: BACKTRACE: = note: inside `unknown_code_2` at $DIR/box_exclusive_violation1.rs:LL:CC note: inside `demo_box_advanced_unique` at $DIR/box_exclusive_violation1.rs:LL:CC --> $DIR/box_exclusive_violation1.rs:LL:CC diff --git a/tests/fail/stacked_borrows/buggy_as_mut_slice.stderr b/tests/fail/stacked_borrows/buggy_as_mut_slice.stderr index c0fc247cd4a20..6aa14361287e3 100644 --- a/tests/fail/stacked_borrows/buggy_as_mut_slice.stderr +++ b/tests/fail/stacked_borrows/buggy_as_mut_slice.stderr @@ -19,7 +19,7 @@ help: was later invalidated at offsets [0x0..0xc] by a Unique retag | LL | unsafe { from_raw_parts_mut(self_.as_ptr() as *mut T, self_.len()) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/buggy_as_mut_slice.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/buggy_split_at_mut.stderr b/tests/fail/stacked_borrows/buggy_split_at_mut.stderr index b4c5140882f32..cdeccc0855a95 100644 --- a/tests/fail/stacked_borrows/buggy_split_at_mut.stderr +++ b/tests/fail/stacked_borrows/buggy_split_at_mut.stderr @@ -19,7 +19,7 @@ help: was later invalidated at offsets [0x0..0x10] by a Unique retag | LL | from_raw_parts_mut(ptr.offset(mid as isize), len - mid), | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/buggy_split_at_mut.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/deallocate_against_protector1.stderr b/tests/fail/stacked_borrows/deallocate_against_protector1.stderr index 2ead0c6a9ddac..a5db4a00c69e7 100644 --- a/tests/fail/stacked_borrows/deallocate_against_protector1.stderr +++ b/tests/fail/stacked_borrows/deallocate_against_protector1.stderr @@ -6,7 +6,7 @@ LL | unsafe { __rust_dealloc(ptr, layout.size(), layout.align()) } | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `std::alloc::dealloc` at RUSTLIB/alloc/src/alloc.rs:LL:CC = note: inside `::deallocate` at RUSTLIB/alloc/src/alloc.rs:LL:CC = note: inside `alloc::alloc::box_free::` at RUSTLIB/alloc/src/alloc.rs:LL:CC diff --git a/tests/fail/stacked_borrows/deallocate_against_protector2.stderr b/tests/fail/stacked_borrows/deallocate_against_protector2.stderr index 60be936bd7e47..99c6ee6eb0743 100644 --- a/tests/fail/stacked_borrows/deallocate_against_protector2.stderr +++ b/tests/fail/stacked_borrows/deallocate_against_protector2.stderr @@ -6,7 +6,7 @@ LL | unsafe { __rust_dealloc(ptr, layout.size(), layout.align()) } | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `std::alloc::dealloc` at RUSTLIB/alloc/src/alloc.rs:LL:CC = note: inside `::deallocate` at RUSTLIB/alloc/src/alloc.rs:LL:CC = note: inside `alloc::alloc::box_free::` at RUSTLIB/alloc/src/alloc.rs:LL:CC diff --git a/tests/fail/stacked_borrows/disable_mut_does_not_merge_srw.stderr b/tests/fail/stacked_borrows/disable_mut_does_not_merge_srw.stderr index a959bb90fbb72..e05f44fac9d2f 100644 --- a/tests/fail/stacked_borrows/disable_mut_does_not_merge_srw.stderr +++ b/tests/fail/stacked_borrows/disable_mut_does_not_merge_srw.stderr @@ -19,7 +19,7 @@ help: was later invalidated at offsets [0x0..0x4] by a write access | LL | *base = 1; | ^^^^^^^^^ - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/disable_mut_does_not_merge_srw.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/exposed_only_ro.stderr b/tests/fail/stacked_borrows/exposed_only_ro.stderr index af76183fb25da..cb5e7bffde480 100644 --- a/tests/fail/stacked_borrows/exposed_only_ro.stderr +++ b/tests/fail/stacked_borrows/exposed_only_ro.stderr @@ -9,7 +9,7 @@ LL | unsafe { *ptr = 0 }; | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/exposed_only_ro.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/fnentry_invalidation.stderr b/tests/fail/stacked_borrows/fnentry_invalidation.stderr index a66fd32003474..653ceca858859 100644 --- a/tests/fail/stacked_borrows/fnentry_invalidation.stderr +++ b/tests/fail/stacked_borrows/fnentry_invalidation.stderr @@ -19,7 +19,7 @@ help: was later invalidated at offsets [0x0..0x4] by a Unique FnEntry reta | LL | x.do_bad(); | ^^^^^^^^^^ - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/fnentry_invalidation.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/illegal_read1.stderr b/tests/fail/stacked_borrows/illegal_read1.stderr index 6e9d491137c85..95ff05d70c30e 100644 --- a/tests/fail/stacked_borrows/illegal_read1.stderr +++ b/tests/fail/stacked_borrows/illegal_read1.stderr @@ -19,7 +19,7 @@ help: was later invalidated at offsets [0x0..0x4] by a read access | LL | let _val = unsafe { *xraw }; | ^^^^^ - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/illegal_read1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/illegal_read2.stderr b/tests/fail/stacked_borrows/illegal_read2.stderr index fb1f9ec6a884f..5cfdf77dee402 100644 --- a/tests/fail/stacked_borrows/illegal_read2.stderr +++ b/tests/fail/stacked_borrows/illegal_read2.stderr @@ -19,7 +19,7 @@ help: was later invalidated at offsets [0x0..0x4] by a SharedReadOnly reta | LL | let shr = unsafe { &*xraw }; | ^^^^^^ - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/illegal_read2.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/illegal_read3.stderr b/tests/fail/stacked_borrows/illegal_read3.stderr index 55ab8877999ca..dacf71fa3ee39 100644 --- a/tests/fail/stacked_borrows/illegal_read3.stderr +++ b/tests/fail/stacked_borrows/illegal_read3.stderr @@ -19,7 +19,7 @@ help: was later invalidated at offsets [0x0..0x4] by a read access | LL | let _val = unsafe { *xref1.r }; | ^^^^^^^^ - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/illegal_read3.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/illegal_read4.stderr b/tests/fail/stacked_borrows/illegal_read4.stderr index 3bb064e2f4162..5ce0cba617914 100644 --- a/tests/fail/stacked_borrows/illegal_read4.stderr +++ b/tests/fail/stacked_borrows/illegal_read4.stderr @@ -19,7 +19,7 @@ help: was later invalidated at offsets [0x0..0x4] by a read access | LL | let _val = unsafe { *xraw }; // use the raw again, this invalidates xref2 *even* with the special read except for uniq refs | ^^^^^ - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/illegal_read4.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/illegal_read5.stderr b/tests/fail/stacked_borrows/illegal_read5.stderr index e060463cf1d3f..63532f87944eb 100644 --- a/tests/fail/stacked_borrows/illegal_read5.stderr +++ b/tests/fail/stacked_borrows/illegal_read5.stderr @@ -19,7 +19,7 @@ help: was later invalidated at offsets [$HEX..$HEX] by a read access | LL | mem::forget(unsafe { ptr::read(xshr) }); // but after reading through the shared ref | ^^^^^^^^^^^^^^^ - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/illegal_read5.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/illegal_read6.stderr b/tests/fail/stacked_borrows/illegal_read6.stderr index 8ef720925646a..93a96ab601ea3 100644 --- a/tests/fail/stacked_borrows/illegal_read6.stderr +++ b/tests/fail/stacked_borrows/illegal_read6.stderr @@ -19,7 +19,7 @@ help: was later invalidated at offsets [0x0..0x4] by a Unique retag | LL | let x = &mut *x; // kill `raw` | ^^^^^^^ - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/illegal_read6.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/illegal_read7.stderr b/tests/fail/stacked_borrows/illegal_read7.stderr index 5c42b0a5863c1..2e8ac207beafb 100644 --- a/tests/fail/stacked_borrows/illegal_read7.stderr +++ b/tests/fail/stacked_borrows/illegal_read7.stderr @@ -19,7 +19,7 @@ help: was later invalidated at offsets [0x0..0x4] by a read access | LL | let _val = ptr::read(raw); | ^^^^^^^^^^^^^^ - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/illegal_read7.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/illegal_read8.stderr b/tests/fail/stacked_borrows/illegal_read8.stderr index c962d1c3e4032..c34fa2d8955dd 100644 --- a/tests/fail/stacked_borrows/illegal_read8.stderr +++ b/tests/fail/stacked_borrows/illegal_read8.stderr @@ -19,7 +19,7 @@ help: was later invalidated at offsets [0x0..0x4] by a write access | LL | *y2 += 1; | ^^^^^^^^ - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/illegal_read8.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/illegal_read_despite_exposed1.stderr b/tests/fail/stacked_borrows/illegal_read_despite_exposed1.stderr index 4607a9dbf675d..43b4ec2ba652b 100644 --- a/tests/fail/stacked_borrows/illegal_read_despite_exposed1.stderr +++ b/tests/fail/stacked_borrows/illegal_read_despite_exposed1.stderr @@ -19,7 +19,7 @@ help: was later invalidated at offsets [0x0..0x4] by a write access | LL | *exposed_ptr = 0; | ^^^^^^^^^^^^^^^^ - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/illegal_read_despite_exposed1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/illegal_read_despite_exposed2.stderr b/tests/fail/stacked_borrows/illegal_read_despite_exposed2.stderr index 4bf0df7d0625e..832320fc202e1 100644 --- a/tests/fail/stacked_borrows/illegal_read_despite_exposed2.stderr +++ b/tests/fail/stacked_borrows/illegal_read_despite_exposed2.stderr @@ -19,7 +19,7 @@ help: was later invalidated at offsets [0x0..0x4] by a read access | LL | let _val = *exposed_ptr; | ^^^^^^^^^^^^ - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/illegal_read_despite_exposed2.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/illegal_write1.stderr b/tests/fail/stacked_borrows/illegal_write1.stderr index 55ba9aab9bf4e..3bf27f4815e9a 100644 --- a/tests/fail/stacked_borrows/illegal_write1.stderr +++ b/tests/fail/stacked_borrows/illegal_write1.stderr @@ -14,7 +14,7 @@ help: was created by a SharedReadOnly retag at offsets [0x0..0x4] | LL | let x: *mut u32 = xref as *const _ as *mut _; | ^^^^ - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/illegal_write1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/illegal_write2.stderr b/tests/fail/stacked_borrows/illegal_write2.stderr index ceb4ce040b896..a9fe8cb6ccc02 100644 --- a/tests/fail/stacked_borrows/illegal_write2.stderr +++ b/tests/fail/stacked_borrows/illegal_write2.stderr @@ -19,7 +19,7 @@ help: was later invalidated at offsets [0x0..0x4] by a Unique retag | LL | drop(&mut *target); // reborrow | ^^^^^^^^^^^^ - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/illegal_write2.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/illegal_write3.stderr b/tests/fail/stacked_borrows/illegal_write3.stderr index e091e25190bbf..d64f2ddd87670 100644 --- a/tests/fail/stacked_borrows/illegal_write3.stderr +++ b/tests/fail/stacked_borrows/illegal_write3.stderr @@ -14,7 +14,7 @@ help: was created by a SharedReadOnly retag at offsets [0x0..0x4] | LL | let ptr = r#ref as *const _ as *mut _; // raw ptr, with raw tag | ^^^^^ - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/illegal_write3.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/illegal_write4.stderr b/tests/fail/stacked_borrows/illegal_write4.stderr index d66585ff7f14c..e3b8621eb74f2 100644 --- a/tests/fail/stacked_borrows/illegal_write4.stderr +++ b/tests/fail/stacked_borrows/illegal_write4.stderr @@ -19,7 +19,7 @@ help: was later invalidated at offsets [0x0..0x4] by a Unique retag | LL | let _mut_ref: &mut i32 = unsafe { mem::transmute(raw) }; // &mut, with raw tag | ^^^^^^^^^^^^^^^^^^^ - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/illegal_write4.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/illegal_write5.stderr b/tests/fail/stacked_borrows/illegal_write5.stderr index 319c2d77062cb..bbeb81258bde6 100644 --- a/tests/fail/stacked_borrows/illegal_write5.stderr +++ b/tests/fail/stacked_borrows/illegal_write5.stderr @@ -19,7 +19,7 @@ help: was later invalidated at offsets [0x0..0x4] by a write access | LL | unsafe { *xraw = 15 }; | ^^^^^^^^^^ - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/illegal_write5.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/illegal_write6.stderr b/tests/fail/stacked_borrows/illegal_write6.stderr index 56e4bd79d477e..331faa89f8604 100644 --- a/tests/fail/stacked_borrows/illegal_write6.stderr +++ b/tests/fail/stacked_borrows/illegal_write6.stderr @@ -16,7 +16,7 @@ help: is this argument | LL | fn foo(a: &mut u32, y: *mut u32) -> u32 { | ^ - = note: backtrace: + = note: BACKTRACE: = note: inside `foo` at $DIR/illegal_write6.rs:LL:CC note: inside `main` at $DIR/illegal_write6.rs:LL:CC --> $DIR/illegal_write6.rs:LL:CC diff --git a/tests/fail/stacked_borrows/illegal_write_despite_exposed1.stderr b/tests/fail/stacked_borrows/illegal_write_despite_exposed1.stderr index aa436b544126c..87ddf61d7586c 100644 --- a/tests/fail/stacked_borrows/illegal_write_despite_exposed1.stderr +++ b/tests/fail/stacked_borrows/illegal_write_despite_exposed1.stderr @@ -19,7 +19,7 @@ help: was later invalidated at offsets [0x0..0x4] by a write access | LL | *exposed_ptr = 0; | ^^^^^^^^^^^^^^^^ - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/illegal_write_despite_exposed1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/interior_mut1.stderr b/tests/fail/stacked_borrows/interior_mut1.stderr index 3aaca3892a54a..1d68727c82af4 100644 --- a/tests/fail/stacked_borrows/interior_mut1.stderr +++ b/tests/fail/stacked_borrows/interior_mut1.stderr @@ -19,7 +19,7 @@ help: was later invalidated at offsets [0x0..0x4] by a write access | LL | *c.get() = UnsafeCell::new(1); // invalidates inner_shr | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/interior_mut1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/interior_mut2.stderr b/tests/fail/stacked_borrows/interior_mut2.stderr index b0141cc34fb65..8a3357142261b 100644 --- a/tests/fail/stacked_borrows/interior_mut2.stderr +++ b/tests/fail/stacked_borrows/interior_mut2.stderr @@ -19,7 +19,7 @@ help: was later invalidated at offsets [0x0..0x4] by a write access | LL | *c.get() = UnsafeCell::new(0); // now inner_shr gets invalidated | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/interior_mut2.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/invalidate_against_protector1.stderr b/tests/fail/stacked_borrows/invalidate_against_protector1.stderr index 5e6fd6e02757b..f87bd2319abd7 100644 --- a/tests/fail/stacked_borrows/invalidate_against_protector1.stderr +++ b/tests/fail/stacked_borrows/invalidate_against_protector1.stderr @@ -16,7 +16,7 @@ help: is this argument | LL | fn inner(x: *mut i32, _y: &mut i32) { | ^^ - = note: backtrace: + = note: BACKTRACE: = note: inside `inner` at $DIR/invalidate_against_protector1.rs:LL:CC note: inside `main` at $DIR/invalidate_against_protector1.rs:LL:CC --> $DIR/invalidate_against_protector1.rs:LL:CC diff --git a/tests/fail/stacked_borrows/invalidate_against_protector2.stderr b/tests/fail/stacked_borrows/invalidate_against_protector2.stderr index eab55d2568dee..07c51a39b825b 100644 --- a/tests/fail/stacked_borrows/invalidate_against_protector2.stderr +++ b/tests/fail/stacked_borrows/invalidate_against_protector2.stderr @@ -16,7 +16,7 @@ help: is this argument | LL | fn inner(x: *mut i32, _y: &i32) { | ^^ - = note: backtrace: + = note: BACKTRACE: = note: inside `inner` at $DIR/invalidate_against_protector2.rs:LL:CC note: inside `main` at $DIR/invalidate_against_protector2.rs:LL:CC --> $DIR/invalidate_against_protector2.rs:LL:CC diff --git a/tests/fail/stacked_borrows/issue-miri-1050-1.stderr b/tests/fail/stacked_borrows/issue-miri-1050-1.stderr index 4d8488fa76843..16c8810a8e6d9 100644 --- a/tests/fail/stacked_borrows/issue-miri-1050-1.stderr +++ b/tests/fail/stacked_borrows/issue-miri-1050-1.stderr @@ -6,7 +6,7 @@ LL | Box(unsafe { Unique::new_unchecked(raw) }, alloc) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `std::boxed::Box::::from_raw_in` at RUSTLIB/alloc/src/boxed.rs:LL:CC = note: inside `std::boxed::Box::::from_raw` at RUSTLIB/alloc/src/boxed.rs:LL:CC note: inside `main` at $DIR/issue-miri-1050-1.rs:LL:CC diff --git a/tests/fail/stacked_borrows/issue-miri-1050-2.stderr b/tests/fail/stacked_borrows/issue-miri-1050-2.stderr index 562a82fb610be..d57e7662e504a 100644 --- a/tests/fail/stacked_borrows/issue-miri-1050-2.stderr +++ b/tests/fail/stacked_borrows/issue-miri-1050-2.stderr @@ -6,7 +6,7 @@ LL | Box(unsafe { Unique::new_unchecked(raw) }, alloc) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `std::boxed::Box::::from_raw_in` at RUSTLIB/alloc/src/boxed.rs:LL:CC = note: inside `std::boxed::Box::::from_raw` at RUSTLIB/alloc/src/boxed.rs:LL:CC note: inside `main` at $DIR/issue-miri-1050-2.rs:LL:CC diff --git a/tests/fail/stacked_borrows/load_invalid_mut.stderr b/tests/fail/stacked_borrows/load_invalid_mut.stderr index 43b6ce8d895ea..08dc171c9eef0 100644 --- a/tests/fail/stacked_borrows/load_invalid_mut.stderr +++ b/tests/fail/stacked_borrows/load_invalid_mut.stderr @@ -19,7 +19,7 @@ help: was later invalidated at offsets [0x0..0x4] by a read access | LL | let _val = unsafe { *xraw }; // invalidate xref | ^^^^^ - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/load_invalid_mut.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/load_invalid_shr.stderr b/tests/fail/stacked_borrows/load_invalid_shr.stderr index 2177ebdd70210..50bbed2b295c9 100644 --- a/tests/fail/stacked_borrows/load_invalid_shr.stderr +++ b/tests/fail/stacked_borrows/load_invalid_shr.stderr @@ -19,7 +19,7 @@ help: was later invalidated at offsets [0x0..0x4] by a write access | LL | unsafe { *xraw = 42 }; // unfreeze | ^^^^^^^^^^ - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/load_invalid_shr.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/mut_exclusive_violation1.stderr b/tests/fail/stacked_borrows/mut_exclusive_violation1.stderr index 42f872eac62f6..1c7f8e12d3d78 100644 --- a/tests/fail/stacked_borrows/mut_exclusive_violation1.stderr +++ b/tests/fail/stacked_borrows/mut_exclusive_violation1.stderr @@ -19,7 +19,7 @@ help: was later invalidated at offsets [0x0..0x4] by a write access | LL | *our = 5; | ^^^^^^^^ - = note: backtrace: + = note: BACKTRACE: = note: inside `unknown_code_2` at $DIR/mut_exclusive_violation1.rs:LL:CC note: inside `demo_mut_advanced_unique` at $DIR/mut_exclusive_violation1.rs:LL:CC --> $DIR/mut_exclusive_violation1.rs:LL:CC diff --git a/tests/fail/stacked_borrows/mut_exclusive_violation2.stderr b/tests/fail/stacked_borrows/mut_exclusive_violation2.stderr index 1952172d927b7..43b5325fc541a 100644 --- a/tests/fail/stacked_borrows/mut_exclusive_violation2.stderr +++ b/tests/fail/stacked_borrows/mut_exclusive_violation2.stderr @@ -19,7 +19,7 @@ help: was later invalidated at offsets [0x0..0x4] by a Unique retag | LL | let _raw2 = ptr2.as_mut(); | ^^^^^^^^^^^^^ - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/mut_exclusive_violation2.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/newtype_retagging.stderr b/tests/fail/stacked_borrows/newtype_retagging.stderr index 7073c8162d168..06a9b86c6f45a 100644 --- a/tests/fail/stacked_borrows/newtype_retagging.stderr +++ b/tests/fail/stacked_borrows/newtype_retagging.stderr @@ -16,7 +16,7 @@ help: is this argument | LL | fn dealloc_while_running(_n: Newtype<'_>, dealloc: impl FnOnce()) { | ^^ - = note: backtrace: + = note: BACKTRACE: = note: inside `std::boxed::Box::::from_raw_in` at RUSTLIB/alloc/src/boxed.rs:LL:CC = note: inside `std::boxed::Box::::from_raw` at RUSTLIB/alloc/src/boxed.rs:LL:CC note: inside closure at $DIR/newtype_retagging.rs:LL:CC diff --git a/tests/fail/stacked_borrows/outdated_local.stderr b/tests/fail/stacked_borrows/outdated_local.stderr index e111a8227b2aa..8c2bba5391888 100644 --- a/tests/fail/stacked_borrows/outdated_local.stderr +++ b/tests/fail/stacked_borrows/outdated_local.stderr @@ -19,7 +19,7 @@ help: was later invalidated at offsets [0x0..0x4] by a write access | LL | x = 1; // this invalidates y by reactivating the lowermost uniq borrow for this local | ^^^^^ - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/outdated_local.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/pass_invalid_mut.stderr b/tests/fail/stacked_borrows/pass_invalid_mut.stderr index 5fd9778054458..d7ab930aa3785 100644 --- a/tests/fail/stacked_borrows/pass_invalid_mut.stderr +++ b/tests/fail/stacked_borrows/pass_invalid_mut.stderr @@ -19,7 +19,7 @@ help: was later invalidated at offsets [0x0..0x4] by a read access | LL | let _val = unsafe { *xraw }; // invalidate xref | ^^^^^ - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/pass_invalid_mut.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/pass_invalid_shr.stderr b/tests/fail/stacked_borrows/pass_invalid_shr.stderr index 0f0df02babb51..c14b35c75c83d 100644 --- a/tests/fail/stacked_borrows/pass_invalid_shr.stderr +++ b/tests/fail/stacked_borrows/pass_invalid_shr.stderr @@ -19,7 +19,7 @@ help: was later invalidated at offsets [0x0..0x4] by a write access | LL | unsafe { *xraw = 42 }; // unfreeze | ^^^^^^^^^^ - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/pass_invalid_shr.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/pointer_smuggling.stderr b/tests/fail/stacked_borrows/pointer_smuggling.stderr index 43d689a0f4bbb..6415af1e18bbf 100644 --- a/tests/fail/stacked_borrows/pointer_smuggling.stderr +++ b/tests/fail/stacked_borrows/pointer_smuggling.stderr @@ -19,7 +19,7 @@ help: was later invalidated at offsets [0x0..0x1] by a write access | LL | *val = 2; // this invalidates any raw ptrs `fun1` might have created. | ^^^^^^^^ - = note: backtrace: + = note: BACKTRACE: = note: inside `fun2` at $DIR/pointer_smuggling.rs:LL:CC note: inside `main` at $DIR/pointer_smuggling.rs:LL:CC --> $DIR/pointer_smuggling.rs:LL:CC diff --git a/tests/fail/stacked_borrows/raw_tracking.stderr b/tests/fail/stacked_borrows/raw_tracking.stderr index fc846f6d9f6a0..d75934445e6d2 100644 --- a/tests/fail/stacked_borrows/raw_tracking.stderr +++ b/tests/fail/stacked_borrows/raw_tracking.stderr @@ -19,7 +19,7 @@ help: was later invalidated at offsets [0x0..0x4] by a Unique retag | LL | let raw2 = &mut l as *mut _; // invalidates raw1 | ^^^^^^ - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/raw_tracking.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/return_invalid_mut.stderr b/tests/fail/stacked_borrows/return_invalid_mut.stderr index c9194208e5dd5..9deb0c41742f3 100644 --- a/tests/fail/stacked_borrows/return_invalid_mut.stderr +++ b/tests/fail/stacked_borrows/return_invalid_mut.stderr @@ -19,7 +19,7 @@ help: was later invalidated at offsets [0x0..0x8] by a read access | LL | let _val = unsafe { *xraw }; // invalidate xref | ^^^^^ - = note: backtrace: + = note: BACKTRACE: = note: inside `foo` at $DIR/return_invalid_mut.rs:LL:CC note: inside `main` at $DIR/return_invalid_mut.rs:LL:CC --> $DIR/return_invalid_mut.rs:LL:CC diff --git a/tests/fail/stacked_borrows/return_invalid_mut_option.stderr b/tests/fail/stacked_borrows/return_invalid_mut_option.stderr index 789d0a3aa8293..1068c286c62fa 100644 --- a/tests/fail/stacked_borrows/return_invalid_mut_option.stderr +++ b/tests/fail/stacked_borrows/return_invalid_mut_option.stderr @@ -19,7 +19,7 @@ help: was later invalidated at offsets [0x0..0x8] by a read access | LL | let _val = unsafe { *xraw }; // invalidate xref | ^^^^^ - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/return_invalid_mut_option.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/return_invalid_mut_tuple.stderr b/tests/fail/stacked_borrows/return_invalid_mut_tuple.stderr index f7fc75bfd098f..79de9b668cf2b 100644 --- a/tests/fail/stacked_borrows/return_invalid_mut_tuple.stderr +++ b/tests/fail/stacked_borrows/return_invalid_mut_tuple.stderr @@ -19,7 +19,7 @@ help: was later invalidated at offsets [0x0..0x8] by a read access | LL | let _val = unsafe { *xraw }; // invalidate xref | ^^^^^ - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/return_invalid_mut_tuple.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/return_invalid_shr.stderr b/tests/fail/stacked_borrows/return_invalid_shr.stderr index fef83c478fe91..dd651517c2fb0 100644 --- a/tests/fail/stacked_borrows/return_invalid_shr.stderr +++ b/tests/fail/stacked_borrows/return_invalid_shr.stderr @@ -19,7 +19,7 @@ help: was later invalidated at offsets [0x0..0x8] by a write access | LL | unsafe { *xraw = (42, 23) }; // unfreeze | ^^^^^^^^^^^^^^^^ - = note: backtrace: + = note: BACKTRACE: = note: inside `foo` at $DIR/return_invalid_shr.rs:LL:CC note: inside `main` at $DIR/return_invalid_shr.rs:LL:CC --> $DIR/return_invalid_shr.rs:LL:CC diff --git a/tests/fail/stacked_borrows/return_invalid_shr_option.stderr b/tests/fail/stacked_borrows/return_invalid_shr_option.stderr index cc316aaf44ece..f45456305db29 100644 --- a/tests/fail/stacked_borrows/return_invalid_shr_option.stderr +++ b/tests/fail/stacked_borrows/return_invalid_shr_option.stderr @@ -19,7 +19,7 @@ help: was later invalidated at offsets [0x0..0x8] by a write access | LL | unsafe { *xraw = (42, 23) }; // unfreeze | ^^^^^^^^^^^^^^^^ - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/return_invalid_shr_option.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/return_invalid_shr_tuple.stderr b/tests/fail/stacked_borrows/return_invalid_shr_tuple.stderr index f6be5d0e53a06..2e41f505bb9d2 100644 --- a/tests/fail/stacked_borrows/return_invalid_shr_tuple.stderr +++ b/tests/fail/stacked_borrows/return_invalid_shr_tuple.stderr @@ -19,7 +19,7 @@ help: was later invalidated at offsets [0x0..0x8] by a write access | LL | unsafe { *xraw = (42, 23) }; // unfreeze | ^^^^^^^^^^^^^^^^ - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/return_invalid_shr_tuple.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/shared_rw_borrows_are_weak1.stderr b/tests/fail/stacked_borrows/shared_rw_borrows_are_weak1.stderr index 3f5f2c66ae1ff..3a139c3ab2120 100644 --- a/tests/fail/stacked_borrows/shared_rw_borrows_are_weak1.stderr +++ b/tests/fail/stacked_borrows/shared_rw_borrows_are_weak1.stderr @@ -19,7 +19,7 @@ help: was later invalidated at offsets [0x0..0x4] by a Unique retag | LL | shr_rw.set(1); | ^^^^^^^^^^^^^ - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/shared_rw_borrows_are_weak1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/shared_rw_borrows_are_weak2.stderr b/tests/fail/stacked_borrows/shared_rw_borrows_are_weak2.stderr index 0a551fe824b5e..0609a73e79315 100644 --- a/tests/fail/stacked_borrows/shared_rw_borrows_are_weak2.stderr +++ b/tests/fail/stacked_borrows/shared_rw_borrows_are_weak2.stderr @@ -19,7 +19,7 @@ help: was later invalidated at offsets [$HEX..$HEX] by a Unique retag | LL | shr_rw.replace(1); | ^^^^^^^^^^^^^^^^^ - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/shared_rw_borrows_are_weak2.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/shr_frozen_violation1.stderr b/tests/fail/stacked_borrows/shr_frozen_violation1.stderr index 9ae8461e13ea2..0818d07da48e5 100644 --- a/tests/fail/stacked_borrows/shr_frozen_violation1.stderr +++ b/tests/fail/stacked_borrows/shr_frozen_violation1.stderr @@ -14,7 +14,7 @@ help: was created by a SharedReadOnly retag at offsets [0x0..0x4] | LL | *(x as *const i32 as *mut i32) = 7; | ^ - = note: backtrace: + = note: BACKTRACE: = note: inside `unknown_code` at $DIR/shr_frozen_violation1.rs:LL:CC note: inside `foo` at $DIR/shr_frozen_violation1.rs:LL:CC --> $DIR/shr_frozen_violation1.rs:LL:CC diff --git a/tests/fail/stacked_borrows/static_memory_modification.stderr b/tests/fail/stacked_borrows/static_memory_modification.stderr index c8a0dc8dca2d8..ca99a8262b8bd 100644 --- a/tests/fail/stacked_borrows/static_memory_modification.stderr +++ b/tests/fail/stacked_borrows/static_memory_modification.stderr @@ -6,7 +6,7 @@ LL | std::mem::transmute::<&usize, &mut usize>(&X) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/static_memory_modification.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/track_caller.stderr b/tests/fail/stacked_borrows/track_caller.stderr index 5ad22305910aa..6f1d0ccd348ec 100644 --- a/tests/fail/stacked_borrows/track_caller.stderr +++ b/tests/fail/stacked_borrows/track_caller.stderr @@ -19,7 +19,7 @@ help: was later invalidated at offsets [0x0..0x4] by a read access | LL | callee(xraw); | ^^^^^^^^^^^^ - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/track_caller.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/transmute-is-no-escape.stderr b/tests/fail/stacked_borrows/transmute-is-no-escape.stderr index eaac77034cce8..a2ecb07fd3117 100644 --- a/tests/fail/stacked_borrows/transmute-is-no-escape.stderr +++ b/tests/fail/stacked_borrows/transmute-is-no-escape.stderr @@ -14,7 +14,7 @@ help: was created by a SharedReadWrite retag at offsets [0x4..0x8] | LL | let raw = (&mut x[1] as *mut i32).wrapping_offset(-1); | ^^^^^^^^^ - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/transmute-is-no-escape.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/unescaped_local.stderr b/tests/fail/stacked_borrows/unescaped_local.stderr index 6302ccde98373..4deafa890005b 100644 --- a/tests/fail/stacked_borrows/unescaped_local.stderr +++ b/tests/fail/stacked_borrows/unescaped_local.stderr @@ -9,7 +9,7 @@ LL | *raw = 13; | = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/unescaped_local.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/unescaped_static.stderr b/tests/fail/stacked_borrows/unescaped_static.stderr index 7b210ed9314e8..01a4bf4340c78 100644 --- a/tests/fail/stacked_borrows/unescaped_static.stderr +++ b/tests/fail/stacked_borrows/unescaped_static.stderr @@ -14,7 +14,7 @@ help: was created by a SharedReadOnly retag at offsets [0x0..0x1] | LL | let ptr_to_first = &ARRAY[0] as *const u8; | ^^^^^^^^^ - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/unescaped_static.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/stacked_borrows/zst_slice.stderr b/tests/fail/stacked_borrows/zst_slice.stderr index 6d0e785cea765..86f1da1f70a33 100644 --- a/tests/fail/stacked_borrows/zst_slice.stderr +++ b/tests/fail/stacked_borrows/zst_slice.stderr @@ -14,7 +14,7 @@ help: would have been created here, but this is a zero-size retag ([0x0..0 | LL | assert_eq!(*s.get_unchecked(1), 2); | ^^^^^^^^^^^^^^^^^^ - = note: backtrace: + = note: BACKTRACE: = note: inside `core::slice::::get_unchecked::` at RUSTLIB/core/src/slice/mod.rs:LL:CC note: inside `main` at $DIR/zst_slice.rs:LL:CC --> $DIR/zst_slice.rs:LL:CC diff --git a/tests/fail/static_memory_modification1.stderr b/tests/fail/static_memory_modification1.stderr index 47590afc1d1a7..5e7213ee6088e 100644 --- a/tests/fail/static_memory_modification1.stderr +++ b/tests/fail/static_memory_modification1.stderr @@ -6,7 +6,7 @@ LL | *std::mem::transmute::<&usize, &mut usize>(&X) = 6; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/static_memory_modification1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/static_memory_modification2.stderr b/tests/fail/static_memory_modification2.stderr index c8fce81ede550..4c160cd320688 100644 --- a/tests/fail/static_memory_modification2.stderr +++ b/tests/fail/static_memory_modification2.stderr @@ -6,7 +6,7 @@ LL | transmute::<&[u8], &mut [u8]>(s.as_bytes())[4] = 42; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/static_memory_modification2.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/static_memory_modification3.stderr b/tests/fail/static_memory_modification3.stderr index 16b06bb3f7968..1986059c50a8e 100644 --- a/tests/fail/static_memory_modification3.stderr +++ b/tests/fail/static_memory_modification3.stderr @@ -6,7 +6,7 @@ LL | transmute::<&[u8], &mut [u8]>(bs)[4] = 42; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/static_memory_modification3.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/transmute-pair-uninit.stderr b/tests/fail/transmute-pair-uninit.stderr index a8e0bdd05b6d7..642bf0a713436 100644 --- a/tests/fail/transmute-pair-uninit.stderr +++ b/tests/fail/transmute-pair-uninit.stderr @@ -6,7 +6,7 @@ LL | let v = unsafe { *z.offset(first_undef) }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/transmute-pair-uninit.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/transmute_fat1.stderr b/tests/fail/transmute_fat1.stderr index a2dcffb255fe4..e1907e0801949 100644 --- a/tests/fail/transmute_fat1.stderr +++ b/tests/fail/transmute_fat1.stderr @@ -6,7 +6,7 @@ LL | std::mem::transmute::<&[u8], [u8; N]>(&[1u8]) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/transmute_fat1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/unaligned_pointers/alignment.stderr b/tests/fail/unaligned_pointers/alignment.stderr index f3bd7ca27571d..bbebe3b89fd7e 100644 --- a/tests/fail/unaligned_pointers/alignment.stderr +++ b/tests/fail/unaligned_pointers/alignment.stderr @@ -6,7 +6,7 @@ LL | *(x_ptr as *mut u32) = 42; *(x_ptr.add(1) as *mut u32) = 42; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/alignment.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/unaligned_pointers/atomic_unaligned.stderr b/tests/fail/unaligned_pointers/atomic_unaligned.stderr index bde4ff615c295..8c3aa3429af5f 100644 --- a/tests/fail/unaligned_pointers/atomic_unaligned.stderr +++ b/tests/fail/unaligned_pointers/atomic_unaligned.stderr @@ -6,7 +6,7 @@ LL | ::std::intrinsics::atomic_load_seqcst(zptr); | = help: this usually indicates that your program performed an invalid operation and caused Undefined Behavior = help: but due to `-Zmiri-symbolic-alignment-check`, alignment errors can also be false positives - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/atomic_unaligned.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/unaligned_pointers/dyn_alignment.stderr b/tests/fail/unaligned_pointers/dyn_alignment.stderr index 930ec994d002d..a900b46612b8a 100644 --- a/tests/fail/unaligned_pointers/dyn_alignment.stderr +++ b/tests/fail/unaligned_pointers/dyn_alignment.stderr @@ -6,7 +6,7 @@ LL | let _ptr = &*ptr; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/dyn_alignment.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/unaligned_pointers/intptrcast_alignment_check.stderr b/tests/fail/unaligned_pointers/intptrcast_alignment_check.stderr index 963fa81b655c8..392495a386de7 100644 --- a/tests/fail/unaligned_pointers/intptrcast_alignment_check.stderr +++ b/tests/fail/unaligned_pointers/intptrcast_alignment_check.stderr @@ -6,7 +6,7 @@ LL | unsafe { *u16_ptr = 2 }; | = help: this usually indicates that your program performed an invalid operation and caused Undefined Behavior = help: but due to `-Zmiri-symbolic-alignment-check`, alignment errors can also be false positives - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/intptrcast_alignment_check.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/unaligned_pointers/reference_to_packed.stderr b/tests/fail/unaligned_pointers/reference_to_packed.stderr index ce667c1e8dece..6c2a3dca2deef 100644 --- a/tests/fail/unaligned_pointers/reference_to_packed.stderr +++ b/tests/fail/unaligned_pointers/reference_to_packed.stderr @@ -6,7 +6,7 @@ LL | let i = *p; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/reference_to_packed.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/unaligned_pointers/unaligned_ptr1.stderr b/tests/fail/unaligned_pointers/unaligned_ptr1.stderr index c557ebb11f679..49292be9cd158 100644 --- a/tests/fail/unaligned_pointers/unaligned_ptr1.stderr +++ b/tests/fail/unaligned_pointers/unaligned_ptr1.stderr @@ -6,7 +6,7 @@ LL | let _x = unsafe { *x }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/unaligned_ptr1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/unaligned_pointers/unaligned_ptr2.stderr b/tests/fail/unaligned_pointers/unaligned_ptr2.stderr index 5bff916213178..e75482f723b69 100644 --- a/tests/fail/unaligned_pointers/unaligned_ptr2.stderr +++ b/tests/fail/unaligned_pointers/unaligned_ptr2.stderr @@ -6,7 +6,7 @@ LL | let _x = unsafe { *x }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/unaligned_ptr2.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/unaligned_pointers/unaligned_ptr3.stderr b/tests/fail/unaligned_pointers/unaligned_ptr3.stderr index f887f38bec53e..50dd4fdfc89f5 100644 --- a/tests/fail/unaligned_pointers/unaligned_ptr3.stderr +++ b/tests/fail/unaligned_pointers/unaligned_ptr3.stderr @@ -6,7 +6,7 @@ LL | let _x = unsafe { *x }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/unaligned_ptr3.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/unaligned_pointers/unaligned_ptr4.stderr b/tests/fail/unaligned_pointers/unaligned_ptr4.stderr index f2fe961eb6a13..182f3e0f876f5 100644 --- a/tests/fail/unaligned_pointers/unaligned_ptr4.stderr +++ b/tests/fail/unaligned_pointers/unaligned_ptr4.stderr @@ -6,7 +6,7 @@ LL | let _val = unsafe { *ptr }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/unaligned_ptr4.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/unaligned_pointers/unaligned_ptr_addr_of.stderr b/tests/fail/unaligned_pointers/unaligned_ptr_addr_of.stderr index 157eb68b50d8d..2d8b1bf74508a 100644 --- a/tests/fail/unaligned_pointers/unaligned_ptr_addr_of.stderr +++ b/tests/fail/unaligned_pointers/unaligned_ptr_addr_of.stderr @@ -6,7 +6,7 @@ LL | let _x = unsafe { ptr::addr_of!(*x) }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at RUSTLIB/core/src/ptr/mod.rs:LL:CC = note: this error originates in the macro `ptr::addr_of` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/fail/unaligned_pointers/unaligned_ptr_zst.stderr b/tests/fail/unaligned_pointers/unaligned_ptr_zst.stderr index da53e922b7a94..aa0cbe1623b6e 100644 --- a/tests/fail/unaligned_pointers/unaligned_ptr_zst.stderr +++ b/tests/fail/unaligned_pointers/unaligned_ptr_zst.stderr @@ -6,7 +6,7 @@ LL | let _x = unsafe { *x }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/unaligned_ptr_zst.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/uninit_buffer.stderr b/tests/fail/uninit_buffer.stderr index 879c827eb8840..a543d59addb14 100644 --- a/tests/fail/uninit_buffer.stderr +++ b/tests/fail/uninit_buffer.stderr @@ -6,7 +6,7 @@ LL | let mut order = unsafe { memcmp(left.as_ptr(), right.as_ptr(), len) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `::compare` at RUSTLIB/core/src/slice/cmp.rs:LL:CC = note: inside `core::slice::cmp::::cmp` at RUSTLIB/core/src/slice/cmp.rs:LL:CC note: inside `main` at $DIR/uninit_buffer.rs:LL:CC diff --git a/tests/fail/uninit_byte_read.stderr b/tests/fail/uninit_byte_read.stderr index 432710b04f869..9f7638888d643 100644 --- a/tests/fail/uninit_byte_read.stderr +++ b/tests/fail/uninit_byte_read.stderr @@ -6,7 +6,7 @@ LL | let undef = unsafe { *v.get_unchecked(5) }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/uninit_byte_read.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/unreachable.stderr b/tests/fail/unreachable.stderr index b487b4374756b..a57d731f1f713 100644 --- a/tests/fail/unreachable.stderr +++ b/tests/fail/unreachable.stderr @@ -6,7 +6,7 @@ LL | unsafe { std::hint::unreachable_unchecked() } | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/unreachable.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/unsized-local.stderr b/tests/fail/unsized-local.stderr index 8277bc4546cb1..66d93c6f503cb 100644 --- a/tests/fail/unsized-local.stderr +++ b/tests/fail/unsized-local.stderr @@ -5,7 +5,7 @@ LL | let x = *(Box::new(A) as Box); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ unsized locals are not supported | = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/unsized-local.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/unsupported_foreign_function.stderr b/tests/fail/unsupported_foreign_function.stderr index 3298f57dd51e7..fde5fb78ac08a 100644 --- a/tests/fail/unsupported_foreign_function.stderr +++ b/tests/fail/unsupported_foreign_function.stderr @@ -5,7 +5,7 @@ LL | foo(); | ^^^^^ can't call foreign function: foo | = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/unsupported_foreign_function.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/unsupported_signal.stderr b/tests/fail/unsupported_signal.stderr index 622b1876e0f86..d22ecbc11ff66 100644 --- a/tests/fail/unsupported_signal.stderr +++ b/tests/fail/unsupported_signal.stderr @@ -5,7 +5,7 @@ LL | libc::signal(libc::SIGPIPE, libc::SIG_IGN); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't call foreign function: signal | = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/unsupported_signal.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/validity/cast_fn_ptr1.stderr b/tests/fail/validity/cast_fn_ptr1.stderr index 6ac10b10a0035..133e4b2c16a10 100644 --- a/tests/fail/validity/cast_fn_ptr1.stderr +++ b/tests/fail/validity/cast_fn_ptr1.stderr @@ -6,7 +6,7 @@ LL | g(0usize as *const i32) | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/cast_fn_ptr1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/validity/cast_fn_ptr2.stderr b/tests/fail/validity/cast_fn_ptr2.stderr index cd73237c867fe..21001f2b46096 100644 --- a/tests/fail/validity/cast_fn_ptr2.stderr +++ b/tests/fail/validity/cast_fn_ptr2.stderr @@ -6,7 +6,7 @@ LL | let _x = g(); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/cast_fn_ptr2.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/validity/dangling_ref1.stderr b/tests/fail/validity/dangling_ref1.stderr index 52e1ae2acb851..01ef071e86930 100644 --- a/tests/fail/validity/dangling_ref1.stderr +++ b/tests/fail/validity/dangling_ref1.stderr @@ -6,7 +6,7 @@ LL | let _x: &i32 = unsafe { mem::transmute(16usize) }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/dangling_ref1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/validity/dangling_ref2.stderr b/tests/fail/validity/dangling_ref2.stderr index f9d0ad5515c82..4be4e8075a728 100644 --- a/tests/fail/validity/dangling_ref2.stderr +++ b/tests/fail/validity/dangling_ref2.stderr @@ -6,7 +6,7 @@ LL | let _x: &i32 = unsafe { mem::transmute(ptr) }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/dangling_ref2.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/validity/dangling_ref3.stderr b/tests/fail/validity/dangling_ref3.stderr index 37b8d6bce6e84..4b7bdf7823686 100644 --- a/tests/fail/validity/dangling_ref3.stderr +++ b/tests/fail/validity/dangling_ref3.stderr @@ -6,7 +6,7 @@ LL | let _x: &i32 = unsafe { mem::transmute(dangling()) }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/dangling_ref3.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/validity/invalid_bool.stderr b/tests/fail/validity/invalid_bool.stderr index 31575a439b5bb..3972787a4d2fd 100644 --- a/tests/fail/validity/invalid_bool.stderr +++ b/tests/fail/validity/invalid_bool.stderr @@ -6,7 +6,7 @@ LL | let _b = unsafe { std::mem::transmute::(2) }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/invalid_bool.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/validity/invalid_bool_uninit.stderr b/tests/fail/validity/invalid_bool_uninit.stderr index 3d90a45d831cf..2dbd102d9833c 100644 --- a/tests/fail/validity/invalid_bool_uninit.stderr +++ b/tests/fail/validity/invalid_bool_uninit.stderr @@ -6,7 +6,7 @@ LL | let _b = unsafe { MyUninit { init: () }.uninit }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/invalid_bool_uninit.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/validity/invalid_char.stderr b/tests/fail/validity/invalid_char.stderr index a64452041f6f4..eeff289dfa4e1 100644 --- a/tests/fail/validity/invalid_char.stderr +++ b/tests/fail/validity/invalid_char.stderr @@ -6,7 +6,7 @@ LL | let _val = match unsafe { std::mem::transmute::(-1) } { | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/invalid_char.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/validity/invalid_char_uninit.stderr b/tests/fail/validity/invalid_char_uninit.stderr index 0512f90a90a47..c59bbedd0ab8b 100644 --- a/tests/fail/validity/invalid_char_uninit.stderr +++ b/tests/fail/validity/invalid_char_uninit.stderr @@ -6,7 +6,7 @@ LL | let _b = unsafe { MyUninit { init: () }.uninit }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/invalid_char_uninit.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/validity/invalid_enum_tag.stderr b/tests/fail/validity/invalid_enum_tag.stderr index e6a484d7bde3d..9234b4d705a9d 100644 --- a/tests/fail/validity/invalid_enum_tag.stderr +++ b/tests/fail/validity/invalid_enum_tag.stderr @@ -6,7 +6,7 @@ LL | let _f = unsafe { std::mem::transmute::(42) }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/invalid_enum_tag.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/validity/invalid_fnptr_null.stderr b/tests/fail/validity/invalid_fnptr_null.stderr index 6c744f204445f..63fad1d56e38b 100644 --- a/tests/fail/validity/invalid_fnptr_null.stderr +++ b/tests/fail/validity/invalid_fnptr_null.stderr @@ -6,7 +6,7 @@ LL | let _b: fn() = unsafe { std::mem::transmute(0usize) }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/invalid_fnptr_null.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/validity/invalid_fnptr_uninit.stderr b/tests/fail/validity/invalid_fnptr_uninit.stderr index f5de8101709d1..15ae78e35db26 100644 --- a/tests/fail/validity/invalid_fnptr_uninit.stderr +++ b/tests/fail/validity/invalid_fnptr_uninit.stderr @@ -6,7 +6,7 @@ LL | let _b = unsafe { MyUninit { init: () }.uninit }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/invalid_fnptr_uninit.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/validity/invalid_wide_raw.stderr b/tests/fail/validity/invalid_wide_raw.stderr index 304008f651631..cf12ab8dbd55a 100644 --- a/tests/fail/validity/invalid_wide_raw.stderr +++ b/tests/fail/validity/invalid_wide_raw.stderr @@ -6,7 +6,7 @@ LL | dbg!(S { x: unsafe { std::mem::transmute((0usize, 0usize)) } }); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/invalid_wide_raw.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/validity/nonzero.stderr b/tests/fail/validity/nonzero.stderr index 05b08d99d36d9..a9a68177ed973 100644 --- a/tests/fail/validity/nonzero.stderr +++ b/tests/fail/validity/nonzero.stderr @@ -6,7 +6,7 @@ LL | let _x = Some(unsafe { NonZero(0) }); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/nonzero.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/validity/ptr_integer_array_transmute.stderr b/tests/fail/validity/ptr_integer_array_transmute.stderr index 43eedb70fe654..118c6a4327cde 100644 --- a/tests/fail/validity/ptr_integer_array_transmute.stderr +++ b/tests/fail/validity/ptr_integer_array_transmute.stderr @@ -6,7 +6,7 @@ LL | let _i: [usize; 1] = unsafe { std::mem::transmute(r) }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/ptr_integer_array_transmute.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/validity/ref_to_uninhabited1.stderr b/tests/fail/validity/ref_to_uninhabited1.stderr index ae606d0a80132..4facd2159c8d0 100644 --- a/tests/fail/validity/ref_to_uninhabited1.stderr +++ b/tests/fail/validity/ref_to_uninhabited1.stderr @@ -6,7 +6,7 @@ LL | let x: Box = transmute(&mut 42); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/ref_to_uninhabited1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/validity/ref_to_uninhabited2.stderr b/tests/fail/validity/ref_to_uninhabited2.stderr index 3db040eeda10a..264465f939190 100644 --- a/tests/fail/validity/ref_to_uninhabited2.stderr +++ b/tests/fail/validity/ref_to_uninhabited2.stderr @@ -6,7 +6,7 @@ LL | let _x: &(i32, Void) = transmute(&42); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/ref_to_uninhabited2.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/validity/too-big-slice.stderr b/tests/fail/validity/too-big-slice.stderr index 591dc6d7b5c27..6df00aefe7561 100644 --- a/tests/fail/validity/too-big-slice.stderr +++ b/tests/fail/validity/too-big-slice.stderr @@ -6,7 +6,7 @@ LL | let _x: &[u8] = mem::transmute((ptr, usize::MAX)); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/too-big-slice.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/validity/too-big-unsized.stderr b/tests/fail/validity/too-big-unsized.stderr index 3b8b9f50cf87e..cbcb31b29fc30 100644 --- a/tests/fail/validity/too-big-unsized.stderr +++ b/tests/fail/validity/too-big-unsized.stderr @@ -6,7 +6,7 @@ LL | let _x: &MySlice = mem::transmute((ptr, isize::MAX as usize)); | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/too-big-unsized.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/validity/transmute_through_ptr.stderr b/tests/fail/validity/transmute_through_ptr.stderr index bf79e8649d01a..ea155405cd610 100644 --- a/tests/fail/validity/transmute_through_ptr.stderr +++ b/tests/fail/validity/transmute_through_ptr.stderr @@ -6,7 +6,7 @@ LL | let y = x; // reading this ought to be enough to trigger validation | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/transmute_through_ptr.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/validity/uninit_float.stderr b/tests/fail/validity/uninit_float.stderr index 8a677202c8ebf..c64f56e25516e 100644 --- a/tests/fail/validity/uninit_float.stderr +++ b/tests/fail/validity/uninit_float.stderr @@ -6,7 +6,7 @@ LL | let _val: f32 = unsafe { std::mem::uninitialized() }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/uninit_float.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/validity/uninit_integer.stderr b/tests/fail/validity/uninit_integer.stderr index 60bf2c7366771..5828eba7939c8 100644 --- a/tests/fail/validity/uninit_integer.stderr +++ b/tests/fail/validity/uninit_integer.stderr @@ -6,7 +6,7 @@ LL | let _val = unsafe { std::mem::MaybeUninit::::uninit().assume_ini | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/uninit_integer.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/validity/uninit_raw_ptr.stderr b/tests/fail/validity/uninit_raw_ptr.stderr index efa444229270c..68f7d2af6a5d6 100644 --- a/tests/fail/validity/uninit_raw_ptr.stderr +++ b/tests/fail/validity/uninit_raw_ptr.stderr @@ -6,7 +6,7 @@ LL | let _val = unsafe { std::mem::MaybeUninit::<*const u8>::uninit().assume | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/uninit_raw_ptr.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/weak_memory/racing_mixed_size.stderr b/tests/fail/weak_memory/racing_mixed_size.stderr index 4c53828a6ce69..dda22ac9ce24c 100644 --- a/tests/fail/weak_memory/racing_mixed_size.stderr +++ b/tests/fail/weak_memory/racing_mixed_size.stderr @@ -5,7 +5,7 @@ LL | std::intrinsics::atomic_load_relaxed(hi); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ racy imperfectly overlapping atomic access is not possible in the C++20 memory model, and not supported by Miri's weak memory emulation | = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support - = note: backtrace: + = note: BACKTRACE: = note: inside closure at $DIR/racing_mixed_size.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/weak_memory/racing_mixed_size_read.stderr b/tests/fail/weak_memory/racing_mixed_size_read.stderr index 8dbf9e6948bd7..59fa5c7410237 100644 --- a/tests/fail/weak_memory/racing_mixed_size_read.stderr +++ b/tests/fail/weak_memory/racing_mixed_size_read.stderr @@ -5,7 +5,7 @@ LL | (*hi).load(Relaxed); | ^^^^^^^^^^^^^^^^^^^ racy imperfectly overlapping atomic access is not possible in the C++20 memory model, and not supported by Miri's weak memory emulation | = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support - = note: backtrace: + = note: BACKTRACE: = note: inside closure at $DIR/racing_mixed_size_read.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/zst1.stderr b/tests/fail/zst1.stderr index eeb2429d4c6fc..b89f06af95893 100644 --- a/tests/fail/zst1.stderr +++ b/tests/fail/zst1.stderr @@ -6,7 +6,7 @@ LL | let _val = unsafe { *x }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/zst1.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/zst2.stderr b/tests/fail/zst2.stderr index 8687e8636bfe8..6c49656e4c67d 100644 --- a/tests/fail/zst2.stderr +++ b/tests/fail/zst2.stderr @@ -6,7 +6,7 @@ LL | unsafe { *x = zst_val }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/zst2.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/fail/zst3.stderr b/tests/fail/zst3.stderr index 43233d4d2afd3..c9accf2c8fbeb 100644 --- a/tests/fail/zst3.stderr +++ b/tests/fail/zst3.stderr @@ -6,7 +6,7 @@ LL | unsafe { *(x as *mut [u8; 0]) = zst_val }; | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/zst3.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace diff --git a/tests/pass/box.stderr b/tests/pass/box.stderr index 2c2534fa2b05a..0001a8dd6eb33 100644 --- a/tests/pass/box.stderr +++ b/tests/pass/box.stderr @@ -10,7 +10,7 @@ LL | let r2 = ((r as usize) + 0) as *mut i32; = help: To ensure that Miri does not miss bugs in your program, use Strict Provenance APIs (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance, https://crates.io/crates/sptr) instead. = help: You can then pass the `-Zmiri-strict-provenance` flag to Miri, to ensure you are not relying on `from_exposed_addr` semantics. = help: Alternatively, the `-Zmiri-permissive-provenance` flag disables this warning. - = note: backtrace: + = note: BACKTRACE: = note: inside `into_raw` at $DIR/box.rs:LL:CC note: inside `main` at $DIR/box.rs:LL:CC --> $DIR/box.rs:LL:CC diff --git a/tests/pass/extern_types.stderr b/tests/pass/extern_types.stderr index fcb04d951d16a..2e18f69305896 100644 --- a/tests/pass/extern_types.stderr +++ b/tests/pass/extern_types.stderr @@ -10,6 +10,6 @@ LL | let x: &Foo = unsafe { &*(16 as *const Foo) }; = help: To ensure that Miri does not miss bugs in your program, use Strict Provenance APIs (https://doc.rust-lang.org/nightly/std/ptr/index.html#strict-provenance, https://crates.io/crates/sptr) instead. = help: You can then pass the `-Zmiri-strict-provenance` flag to Miri, to ensure you are not relying on `from_exposed_addr` semantics. = help: Alternatively, the `-Zmiri-permissive-provenance` flag disables this warning. - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/extern_types.rs:LL:CC diff --git a/tests/pass/stacked-borrows/issue-miri-2389.stderr b/tests/pass/stacked-borrows/issue-miri-2389.stderr index 2ff931f231573..f3ba052ae5130 100644 --- a/tests/pass/stacked-borrows/issue-miri-2389.stderr +++ b/tests/pass/stacked-borrows/issue-miri-2389.stderr @@ -10,6 +10,6 @@ LL | let wildcard = &root0 as *const Cell as usize as *const Cell Date: Wed, 31 Aug 2022 16:05:40 +0200 Subject: [PATCH 3705/3747] make shim_arg_size ptr-width-independent --- tests/fail/shims/shim_arg_size.64bit.stderr | 15 --------------- tests/fail/shims/shim_arg_size.rs | 13 +++---------- ...arg_size.32bit.stderr => shim_arg_size.stderr} | 8 ++++---- 3 files changed, 7 insertions(+), 29 deletions(-) delete mode 100644 tests/fail/shims/shim_arg_size.64bit.stderr rename tests/fail/shims/{shim_arg_size.32bit.stderr => shim_arg_size.stderr} (72%) diff --git a/tests/fail/shims/shim_arg_size.64bit.stderr b/tests/fail/shims/shim_arg_size.64bit.stderr deleted file mode 100644 index 0e8b402ac7147..0000000000000 --- a/tests/fail/shims/shim_arg_size.64bit.stderr +++ /dev/null @@ -1,15 +0,0 @@ -error: Undefined Behavior: scalar size mismatch: expected 8 bytes but got 4 bytes instead - --> $DIR/shim_arg_size.rs:LL:CC - | -LL | let _p1 = malloc(42); - | ^^^^^^^^^^ scalar size mismatch: expected 8 bytes but got 4 bytes instead - | - = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior - = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: BACKTRACE: - = note: inside `main` at $DIR/shim_arg_size.rs:LL:CC - -note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace - -error: aborting due to previous error - diff --git a/tests/fail/shims/shim_arg_size.rs b/tests/fail/shims/shim_arg_size.rs index 383df286d4c85..3d7bc25bf5d31 100644 --- a/tests/fail/shims/shim_arg_size.rs +++ b/tests/fail/shims/shim_arg_size.rs @@ -1,17 +1,10 @@ -//@stderr-per-bitwidth - fn main() { extern "C" { - // Use the wrong type(ie. not the pointer width) for the `size` - // argument. - #[cfg(target_pointer_width = "64")] - fn malloc(size: u32) -> *mut std::ffi::c_void; - - #[cfg(target_pointer_width = "32")] - fn malloc(size: u16) -> *mut std::ffi::c_void; + // Use the wrong type (ie. not `i32`) for the `c` argument. + fn memchr(s: *const std::ffi::c_void, c: u8, n: usize) -> *mut std::ffi::c_void; } unsafe { - let _p1 = malloc(42); //~ ERROR: Undefined Behavior: scalar size mismatch + memchr(std::ptr::null(), 0, 0); //~ ERROR: Undefined Behavior: scalar size mismatch }; } diff --git a/tests/fail/shims/shim_arg_size.32bit.stderr b/tests/fail/shims/shim_arg_size.stderr similarity index 72% rename from tests/fail/shims/shim_arg_size.32bit.stderr rename to tests/fail/shims/shim_arg_size.stderr index 84b09acbac3dc..d951f81810ef6 100644 --- a/tests/fail/shims/shim_arg_size.32bit.stderr +++ b/tests/fail/shims/shim_arg_size.stderr @@ -1,12 +1,12 @@ -error: Undefined Behavior: scalar size mismatch: expected 4 bytes but got 2 bytes instead +error: Undefined Behavior: scalar size mismatch: expected 4 bytes but got 1 bytes instead --> $DIR/shim_arg_size.rs:LL:CC | -LL | let _p1 = malloc(42); - | ^^^^^^^^^^ scalar size mismatch: expected 4 bytes but got 2 bytes instead +LL | memchr(std::ptr::null(), 0, 0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ scalar size mismatch: expected 4 bytes but got 1 bytes instead | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: backtrace: + = note: BACKTRACE: = note: inside `main` at $DIR/shim_arg_size.rs:LL:CC note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace From d21b601b6e89746378e020a1e4a6f3d7e98bc5c4 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 27 Aug 2022 15:59:27 -0400 Subject: [PATCH 3706/3747] make Miri build again with rustc provenance changes --- src/diagnostics.rs | 7 +-- src/helpers.rs | 2 +- src/machine.rs | 15 ++++++ src/shims/foreign_items.rs | 8 +-- src/shims/unix/fs.rs | 2 +- src/shims/windows/dlsym.rs | 3 +- tests/fail/copy_half_a_pointer.rs | 21 ++++++++ tests/fail/copy_half_a_pointer.stderr | 14 +++++ tests/fail/intrinsics/raw_eq_on_ptr.rs | 3 +- tests/fail/intrinsics/raw_eq_on_ptr.stderr | 7 +-- tests/fail/invalid_int.rs | 1 + tests/fail/reading_half_a_pointer.rs | 3 +- tests/fail/reading_half_a_pointer.stderr | 9 ++-- tests/fail/transmute_fat1.rs | 13 ----- tests/fail/transmute_fat1.stderr | 15 ------ tests/fail/validity/invalid_bool_uninit.rs | 4 +- .../fail/validity/invalid_bool_uninit.stderr | 4 +- tests/fail/validity/invalid_char_uninit.rs | 4 +- .../fail/validity/invalid_char_uninit.stderr | 4 +- tests/fail/validity/invalid_fnptr_uninit.rs | 4 +- .../fail/validity/invalid_fnptr_uninit.stderr | 4 +- .../validity/ptr_integer_array_transmute.rs | 4 -- .../ptr_integer_array_transmute.stderr | 15 ------ tests/fail/validity/uninit_float.rs | 5 +- tests/fail/validity/uninit_float.stderr | 6 +-- tests/fail/validity/uninit_integer.rs | 4 +- tests/fail/validity/uninit_integer.stderr | 6 +-- tests/fail/validity/uninit_raw_ptr.rs | 5 +- tests/fail/validity/uninit_raw_ptr.stderr | 6 +-- tests/pass/transmute_fat.rs | 10 ---- tests/pass/transmute_ptr.rs | 52 +++++++++++++++++++ 31 files changed, 158 insertions(+), 102 deletions(-) create mode 100644 tests/fail/copy_half_a_pointer.rs create mode 100644 tests/fail/copy_half_a_pointer.stderr delete mode 100644 tests/fail/transmute_fat1.rs delete mode 100644 tests/fail/transmute_fat1.stderr delete mode 100644 tests/fail/validity/ptr_integer_array_transmute.rs delete mode 100644 tests/fail/validity/ptr_integer_array_transmute.stderr delete mode 100644 tests/pass/transmute_fat.rs create mode 100644 tests/pass/transmute_ptr.rs diff --git a/src/diagnostics.rs b/src/diagnostics.rs index 74d2fe2680a4c..8ba2995662bab 100644 --- a/src/diagnostics.rs +++ b/src/diagnostics.rs @@ -226,13 +226,14 @@ pub fn report_error<'tcx, 'mir>( let helps = match e.kind() { Unsupported( UnsupportedOpInfo::ThreadLocalStatic(_) | - UnsupportedOpInfo::ReadExternStatic(_) + UnsupportedOpInfo::ReadExternStatic(_) | + UnsupportedOpInfo::PartialPointerOverwrite(_) | // we make memory uninit instead + UnsupportedOpInfo::ReadPointerAsBytes ) => panic!("Error should never be raised by Miri: {kind:?}", kind = e.kind()), Unsupported( UnsupportedOpInfo::Unsupported(_) | - UnsupportedOpInfo::PartialPointerOverwrite(_) | - UnsupportedOpInfo::ReadPointerAsBytes + UnsupportedOpInfo::PartialPointerCopy(_) ) => vec![(None, format!("this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support"))], UndefinedBehavior(UndefinedBehaviorInfo::AlignmentCheckFailed { .. }) diff --git a/src/helpers.rs b/src/helpers.rs index 92139d9aa2a94..57c9fd3389ced 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -757,7 +757,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } // Step 2: get the bytes. - this.read_bytes_ptr(ptr, len) + this.read_bytes_ptr_strip_provenance(ptr, len) } fn read_wide_str(&self, mut ptr: Pointer>) -> InterpResult<'tcx, Vec> { diff --git a/src/machine.rs b/src/machine.rs index 3be4d1d1b5bcb..b7624ac5922d1 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -205,6 +205,21 @@ impl interpret::Provenance for Provenance { Provenance::Wildcard => None, } } + + fn join(left: Option, right: Option) -> Option { + match (left, right) { + // If both are the *same* concrete tag, that is the result. + ( + Some(Provenance::Concrete { alloc_id: left_alloc, sb: left_sb }), + Some(Provenance::Concrete { alloc_id: right_alloc, sb: right_sb }), + ) if left_alloc == right_alloc && left_sb == right_sb => left, + // If one side is a wildcard, the best possible outcome is that it is equal to the other + // one, and we use that. + (Some(Provenance::Wildcard), o) | (o, Some(Provenance::Wildcard)) => o, + // Otherwise, fall back to `None`. + _ => None, + } + } } impl fmt::Debug for ProvenanceExtra { diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index 117e0933ddcf9..b94b6bbb2b8b6 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -560,8 +560,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let n = Size::from_bytes(this.read_scalar(n)?.to_machine_usize(this)?); let result = { - let left_bytes = this.read_bytes_ptr(left, n)?; - let right_bytes = this.read_bytes_ptr(right, n)?; + let left_bytes = this.read_bytes_ptr_strip_provenance(left, n)?; + let right_bytes = this.read_bytes_ptr_strip_provenance(right, n)?; use std::cmp::Ordering::*; match left_bytes.cmp(right_bytes) { @@ -583,7 +583,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let val = val as u8; if let Some(idx) = this - .read_bytes_ptr(ptr, Size::from_bytes(num))? + .read_bytes_ptr_strip_provenance(ptr, Size::from_bytes(num))? .iter() .rev() .position(|&c| c == val) @@ -606,7 +606,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let val = val as u8; let idx = this - .read_bytes_ptr(ptr, Size::from_bytes(num))? + .read_bytes_ptr_strip_provenance(ptr, Size::from_bytes(num))? .iter() .position(|&c| c == val); if let Some(idx) = idx { diff --git a/src/shims/unix/fs.rs b/src/shims/unix/fs.rs index d3f4f5ef5451f..06cd533626a5e 100644 --- a/src/shims/unix/fs.rs +++ b/src/shims/unix/fs.rs @@ -761,7 +761,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let communicate = this.machine.communicate(); if let Some(file_descriptor) = this.machine.file_handler.handles.get(&fd) { - let bytes = this.read_bytes_ptr(buf, Size::from_bytes(count))?; + let bytes = this.read_bytes_ptr_strip_provenance(buf, Size::from_bytes(count))?; let result = file_descriptor.write(communicate, bytes)?.map(|c| i64::try_from(c).unwrap()); this.try_unwrap_io_result(result) diff --git a/src/shims/windows/dlsym.rs b/src/shims/windows/dlsym.rs index 5cbfecb889a23..8749ed91bb4bb 100644 --- a/src/shims/windows/dlsym.rs +++ b/src/shims/windows/dlsym.rs @@ -78,7 +78,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // stdout/stderr use std::io::{self, Write}; - let buf_cont = this.read_bytes_ptr(buf, Size::from_bytes(u64::from(n)))?; + let buf_cont = + this.read_bytes_ptr_strip_provenance(buf, Size::from_bytes(u64::from(n)))?; let res = if this.machine.mute_stdout_stderr { Ok(buf_cont.len()) } else if handle == -11 { diff --git a/tests/fail/copy_half_a_pointer.rs b/tests/fail/copy_half_a_pointer.rs new file mode 100644 index 0000000000000..e1dcdda7fdfe3 --- /dev/null +++ b/tests/fail/copy_half_a_pointer.rs @@ -0,0 +1,21 @@ +//@normalize-stderr-test: "\+0x[48]" -> "+HALF_PTR" +#![allow(dead_code)] + +// We use packed structs to get around alignment restrictions +#[repr(packed)] +struct Data { + pad: u8, + ptr: &'static i32, +} + +static G: i32 = 0; + +fn main() { + let mut d = Data { pad: 0, ptr: &G }; + + // Get a pointer to the beginning of the Data struct (one u8 byte, then the pointer bytes). + let d_alias = &mut d as *mut _ as *mut *const u8; + unsafe { + let _x = d_alias.read_unaligned(); //~ERROR: unable to copy parts of a pointer + } +} diff --git a/tests/fail/copy_half_a_pointer.stderr b/tests/fail/copy_half_a_pointer.stderr new file mode 100644 index 0000000000000..21797757084ee --- /dev/null +++ b/tests/fail/copy_half_a_pointer.stderr @@ -0,0 +1,14 @@ +error: unsupported operation: unable to copy parts of a pointer from memory at ALLOC+HALF_PTR + --> $DIR/copy_half_a_pointer.rs:LL:CC + | +LL | let _x = d_alias.read_unaligned(); + | ^^^^^^^^^^^^^^^^^^^^^^^^ unable to copy parts of a pointer from memory at ALLOC+HALF_PTR + | + = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support + = note: BACKTRACE: + = note: inside `main` at $DIR/copy_half_a_pointer.rs:LL:CC + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + diff --git a/tests/fail/intrinsics/raw_eq_on_ptr.rs b/tests/fail/intrinsics/raw_eq_on_ptr.rs index 675b7cf9224bd..c14f86147dbb9 100644 --- a/tests/fail/intrinsics/raw_eq_on_ptr.rs +++ b/tests/fail/intrinsics/raw_eq_on_ptr.rs @@ -6,6 +6,5 @@ extern "rust-intrinsic" { fn main() { let x = &0; - // FIXME: the error message is not great (should be UB rather than 'unsupported') - unsafe { raw_eq(&x, &x) }; //~ERROR: unsupported operation + unsafe { raw_eq(&x, &x) }; //~ERROR: `raw_eq` on bytes with provenance } diff --git a/tests/fail/intrinsics/raw_eq_on_ptr.stderr b/tests/fail/intrinsics/raw_eq_on_ptr.stderr index c6ed1750c04e0..2236ad9839c5e 100644 --- a/tests/fail/intrinsics/raw_eq_on_ptr.stderr +++ b/tests/fail/intrinsics/raw_eq_on_ptr.stderr @@ -1,10 +1,11 @@ -error: unsupported operation: unable to turn pointer into raw bytes +error: Undefined Behavior: `raw_eq` on bytes with provenance --> $DIR/raw_eq_on_ptr.rs:LL:CC | LL | unsafe { raw_eq(&x, &x) }; - | ^^^^^^^^^^^^^^ unable to turn pointer into raw bytes + | ^^^^^^^^^^^^^^ `raw_eq` on bytes with provenance | - = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: = note: inside `main` at $DIR/raw_eq_on_ptr.rs:LL:CC diff --git a/tests/fail/invalid_int.rs b/tests/fail/invalid_int.rs index b51af24c134b2..2435a87a6f28c 100644 --- a/tests/fail/invalid_int.rs +++ b/tests/fail/invalid_int.rs @@ -1,3 +1,4 @@ +#![allow(invalid_value)] // Validation makes this fail in the wrong place // Make sure we find these even with many checks disabled. //@compile-flags: -Zmiri-disable-alignment-check -Zmiri-disable-stacked-borrows -Zmiri-disable-validation diff --git a/tests/fail/reading_half_a_pointer.rs b/tests/fail/reading_half_a_pointer.rs index a8cdb11f40baf..2d66913262476 100644 --- a/tests/fail/reading_half_a_pointer.rs +++ b/tests/fail/reading_half_a_pointer.rs @@ -24,6 +24,7 @@ fn main() { // starts 1 byte to the right, so using it would actually be wrong! let d_alias = &mut w.data as *mut _ as *mut *const u8; unsafe { - let _x = *d_alias; //~ ERROR: unable to turn pointer into raw bytes + let x = *d_alias; + let _val = *x; //~ERROR: is a dangling pointer (it has no provenance) } } diff --git a/tests/fail/reading_half_a_pointer.stderr b/tests/fail/reading_half_a_pointer.stderr index 28cd7cef24334..61a7161a98bb3 100644 --- a/tests/fail/reading_half_a_pointer.stderr +++ b/tests/fail/reading_half_a_pointer.stderr @@ -1,10 +1,11 @@ -error: unsupported operation: unable to turn pointer into raw bytes +error: Undefined Behavior: dereferencing pointer failed: $HEX[noalloc] is a dangling pointer (it has no provenance) --> $DIR/reading_half_a_pointer.rs:LL:CC | -LL | let _x = *d_alias; - | ^^^^^^^^ unable to turn pointer into raw bytes +LL | let _val = *x; + | ^^ dereferencing pointer failed: $HEX[noalloc] is a dangling pointer (it has no provenance) | - = help: this is likely not a bug in the program; it indicates that the program performed an operation that the interpreter does not support + = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior + = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information = note: BACKTRACE: = note: inside `main` at $DIR/reading_half_a_pointer.rs:LL:CC diff --git a/tests/fail/transmute_fat1.rs b/tests/fail/transmute_fat1.rs deleted file mode 100644 index a60efb98f9d87..0000000000000 --- a/tests/fail/transmute_fat1.rs +++ /dev/null @@ -1,13 +0,0 @@ -#[cfg(target_pointer_width = "64")] -const N: usize = 16; - -#[cfg(target_pointer_width = "32")] -const N: usize = 8; - -fn main() { - let bad = unsafe { - std::mem::transmute::<&[u8], [u8; N]>(&[1u8]) - //~^ ERROR: constructing invalid value: encountered a pointer - }; - let _val = bad[0] + bad[bad.len() - 1]; -} diff --git a/tests/fail/transmute_fat1.stderr b/tests/fail/transmute_fat1.stderr deleted file mode 100644 index e1907e0801949..0000000000000 --- a/tests/fail/transmute_fat1.stderr +++ /dev/null @@ -1,15 +0,0 @@ -error: Undefined Behavior: constructing invalid value: encountered a pointer, but expected plain (non-pointer) bytes - --> $DIR/transmute_fat1.rs:LL:CC - | -LL | std::mem::transmute::<&[u8], [u8; N]>(&[1u8]) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a pointer, but expected plain (non-pointer) bytes - | - = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior - = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: BACKTRACE: - = note: inside `main` at $DIR/transmute_fat1.rs:LL:CC - -note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace - -error: aborting due to previous error - diff --git a/tests/fail/validity/invalid_bool_uninit.rs b/tests/fail/validity/invalid_bool_uninit.rs index 84a221a469a7a..ce4fdcabd047a 100644 --- a/tests/fail/validity/invalid_bool_uninit.rs +++ b/tests/fail/validity/invalid_bool_uninit.rs @@ -2,9 +2,9 @@ union MyUninit { init: (), - uninit: bool, + uninit: [bool; 1], } fn main() { - let _b = unsafe { MyUninit { init: () }.uninit }; //~ ERROR: uninitialized + let _b = unsafe { MyUninit { init: () }.uninit }; //~ ERROR: constructing invalid value } diff --git a/tests/fail/validity/invalid_bool_uninit.stderr b/tests/fail/validity/invalid_bool_uninit.stderr index 2dbd102d9833c..5a7bd80e40c15 100644 --- a/tests/fail/validity/invalid_bool_uninit.stderr +++ b/tests/fail/validity/invalid_bool_uninit.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory +error: Undefined Behavior: constructing invalid value at [0]: encountered uninitialized memory, but expected a boolean --> $DIR/invalid_bool_uninit.rs:LL:CC | LL | let _b = unsafe { MyUninit { init: () }.uninit }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at [0]: encountered uninitialized memory, but expected a boolean | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/validity/invalid_char_uninit.rs b/tests/fail/validity/invalid_char_uninit.rs index c16e26649076a..0e3c3ccac6f23 100644 --- a/tests/fail/validity/invalid_char_uninit.rs +++ b/tests/fail/validity/invalid_char_uninit.rs @@ -2,9 +2,9 @@ union MyUninit { init: (), - uninit: char, + uninit: [char; 1], } fn main() { - let _b = unsafe { MyUninit { init: () }.uninit }; //~ ERROR: uninitialized + let _b = unsafe { MyUninit { init: () }.uninit }; //~ ERROR: constructing invalid value } diff --git a/tests/fail/validity/invalid_char_uninit.stderr b/tests/fail/validity/invalid_char_uninit.stderr index c59bbedd0ab8b..fb5d3ee1f1f9c 100644 --- a/tests/fail/validity/invalid_char_uninit.stderr +++ b/tests/fail/validity/invalid_char_uninit.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory +error: Undefined Behavior: constructing invalid value at [0]: encountered uninitialized memory, but expected a unicode scalar value --> $DIR/invalid_char_uninit.rs:LL:CC | LL | let _b = unsafe { MyUninit { init: () }.uninit }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at [0]: encountered uninitialized memory, but expected a unicode scalar value | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/validity/invalid_fnptr_uninit.rs b/tests/fail/validity/invalid_fnptr_uninit.rs index c857d83bde0db..014a8ae847a79 100644 --- a/tests/fail/validity/invalid_fnptr_uninit.rs +++ b/tests/fail/validity/invalid_fnptr_uninit.rs @@ -2,9 +2,9 @@ union MyUninit { init: (), - uninit: fn(), + uninit: [fn(); 1], } fn main() { - let _b = unsafe { MyUninit { init: () }.uninit }; //~ ERROR: uninitialized + let _b = unsafe { MyUninit { init: () }.uninit }; //~ ERROR: constructing invalid value } diff --git a/tests/fail/validity/invalid_fnptr_uninit.stderr b/tests/fail/validity/invalid_fnptr_uninit.stderr index 15ae78e35db26..35309e90136cb 100644 --- a/tests/fail/validity/invalid_fnptr_uninit.stderr +++ b/tests/fail/validity/invalid_fnptr_uninit.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory +error: Undefined Behavior: constructing invalid value at [0]: encountered uninitialized memory, but expected a function pointer --> $DIR/invalid_fnptr_uninit.rs:LL:CC | LL | let _b = unsafe { MyUninit { init: () }.uninit }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at [0]: encountered uninitialized memory, but expected a function pointer | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/validity/ptr_integer_array_transmute.rs b/tests/fail/validity/ptr_integer_array_transmute.rs deleted file mode 100644 index c8613d274c81d..0000000000000 --- a/tests/fail/validity/ptr_integer_array_transmute.rs +++ /dev/null @@ -1,4 +0,0 @@ -fn main() { - let r = &mut 42; - let _i: [usize; 1] = unsafe { std::mem::transmute(r) }; //~ ERROR: encountered a pointer, but expected plain (non-pointer) bytes -} diff --git a/tests/fail/validity/ptr_integer_array_transmute.stderr b/tests/fail/validity/ptr_integer_array_transmute.stderr deleted file mode 100644 index 118c6a4327cde..0000000000000 --- a/tests/fail/validity/ptr_integer_array_transmute.stderr +++ /dev/null @@ -1,15 +0,0 @@ -error: Undefined Behavior: constructing invalid value: encountered a pointer, but expected plain (non-pointer) bytes - --> $DIR/ptr_integer_array_transmute.rs:LL:CC - | -LL | let _i: [usize; 1] = unsafe { std::mem::transmute(r) }; - | ^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a pointer, but expected plain (non-pointer) bytes - | - = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior - = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information - = note: BACKTRACE: - = note: inside `main` at $DIR/ptr_integer_array_transmute.rs:LL:CC - -note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace - -error: aborting due to previous error - diff --git a/tests/fail/validity/uninit_float.rs b/tests/fail/validity/uninit_float.rs index fecc02d7a505f..045bb46464fae 100644 --- a/tests/fail/validity/uninit_float.rs +++ b/tests/fail/validity/uninit_float.rs @@ -1,8 +1,9 @@ -#![allow(deprecated)] +#![allow(deprecated, invalid_value)] // This test is adapted from https://github.com/rust-lang/miri/issues/1340#issue-600900312. fn main() { // Deliberately using `mem::uninitialized` to make sure that despite all the mitigations, we consider this UB. - let _val: f32 = unsafe { std::mem::uninitialized() }; + // The array avoids a `Scalar` layout which detects uninit without even doing validation. + let _val: [f32; 1] = unsafe { std::mem::uninitialized() }; //~^ ERROR: uninitialized } diff --git a/tests/fail/validity/uninit_float.stderr b/tests/fail/validity/uninit_float.stderr index c64f56e25516e..677a0fc5570d7 100644 --- a/tests/fail/validity/uninit_float.stderr +++ b/tests/fail/validity/uninit_float.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory +error: Undefined Behavior: constructing invalid value at .value[0]: encountered uninitialized bytes --> $DIR/uninit_float.rs:LL:CC | -LL | let _val: f32 = unsafe { std::mem::uninitialized() }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory +LL | let _val: [f32; 1] = unsafe { std::mem::uninitialized() }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .value[0]: encountered uninitialized bytes | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/validity/uninit_integer.rs b/tests/fail/validity/uninit_integer.rs index a9b200732653d..a94302603a219 100644 --- a/tests/fail/validity/uninit_integer.rs +++ b/tests/fail/validity/uninit_integer.rs @@ -1,6 +1,8 @@ +#![allow(invalid_value)] // This test is from https://github.com/rust-lang/miri/issues/1340#issue-600900312. fn main() { - let _val = unsafe { std::mem::MaybeUninit::::uninit().assume_init() }; + // The array avoids a `Scalar` layout which detects uninit without even doing validation. + let _val = unsafe { std::mem::MaybeUninit::<[usize; 1]>::uninit().assume_init() }; //~^ ERROR: uninitialized } diff --git a/tests/fail/validity/uninit_integer.stderr b/tests/fail/validity/uninit_integer.stderr index 5828eba7939c8..a9ac2a6dc67e7 100644 --- a/tests/fail/validity/uninit_integer.stderr +++ b/tests/fail/validity/uninit_integer.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory +error: Undefined Behavior: constructing invalid value at .value[0]: encountered uninitialized bytes --> $DIR/uninit_integer.rs:LL:CC | -LL | let _val = unsafe { std::mem::MaybeUninit::::uninit().assume_init() }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory +LL | let _val = unsafe { std::mem::MaybeUninit::<[usize; 1]>::uninit().assume_init() }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .value[0]: encountered uninitialized bytes | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/fail/validity/uninit_raw_ptr.rs b/tests/fail/validity/uninit_raw_ptr.rs index 9f99dc1a0e11c..18703152ea108 100644 --- a/tests/fail/validity/uninit_raw_ptr.rs +++ b/tests/fail/validity/uninit_raw_ptr.rs @@ -1,4 +1,7 @@ +#![allow(invalid_value)] + fn main() { - let _val = unsafe { std::mem::MaybeUninit::<*const u8>::uninit().assume_init() }; + // The array avoids a `Scalar` layout which detects uninit without even doing validation. + let _val = unsafe { std::mem::MaybeUninit::<[*const u8; 1]>::uninit().assume_init() }; //~^ ERROR: uninitialized } diff --git a/tests/fail/validity/uninit_raw_ptr.stderr b/tests/fail/validity/uninit_raw_ptr.stderr index 68f7d2af6a5d6..bbae9cf69ffe1 100644 --- a/tests/fail/validity/uninit_raw_ptr.stderr +++ b/tests/fail/validity/uninit_raw_ptr.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: using uninitialized data, but this operation requires initialized memory +error: Undefined Behavior: constructing invalid value at .value[0]: encountered uninitialized memory, but expected a raw pointer --> $DIR/uninit_raw_ptr.rs:LL:CC | -LL | let _val = unsafe { std::mem::MaybeUninit::<*const u8>::uninit().assume_init() }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ using uninitialized data, but this operation requires initialized memory +LL | let _val = unsafe { std::mem::MaybeUninit::<[*const u8; 1]>::uninit().assume_init() }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .value[0]: encountered uninitialized memory, but expected a raw pointer | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information diff --git a/tests/pass/transmute_fat.rs b/tests/pass/transmute_fat.rs deleted file mode 100644 index dfd78ace520c5..0000000000000 --- a/tests/pass/transmute_fat.rs +++ /dev/null @@ -1,10 +0,0 @@ -// Stacked Borrows disallows this becuase the reference is never cast to a raw pointer. -//@compile-flags: -Zmiri-disable-stacked-borrows - -fn main() { - // If we are careful, we can exploit data layout... - // This is a tricky case since we are transmuting a ScalarPair type to a non-ScalarPair type. - let raw = unsafe { std::mem::transmute::<&[u8], [*const u8; 2]>(&[42]) }; - let ptr: *const u8 = unsafe { std::mem::transmute_copy(&raw) }; - assert_eq!(unsafe { *ptr }, 42); -} diff --git a/tests/pass/transmute_ptr.rs b/tests/pass/transmute_ptr.rs new file mode 100644 index 0000000000000..fd9d457e440e9 --- /dev/null +++ b/tests/pass/transmute_ptr.rs @@ -0,0 +1,52 @@ +#![feature(strict_provenance)] +use std::{mem, ptr}; + +fn t1() { + // If we are careful, we can exploit data layout... + // This is a tricky case since we are transmuting a ScalarPair type to a non-ScalarPair type. + let raw = unsafe { mem::transmute::<&[u8], [*const u8; 2]>(&[42]) }; + let ptr: *const u8 = unsafe { mem::transmute_copy(&raw) }; + assert_eq!(unsafe { *ptr }, 42); +} + +#[cfg(target_pointer_width = "64")] +const PTR_SIZE: usize = 8; +#[cfg(target_pointer_width = "32")] +const PTR_SIZE: usize = 4; + +fn t2() { + let bad = unsafe { mem::transmute::<&[u8], [u8; 2 * PTR_SIZE]>(&[1u8]) }; + let _val = bad[0] + bad[bad.len() - 1]; +} + +fn ptr_integer_array() { + let r = &mut 42; + let _i: [usize; 1] = unsafe { mem::transmute(r) }; + + let _x: [u8; PTR_SIZE] = unsafe { mem::transmute(&0) }; +} + +fn ptr_in_two_halves() { + unsafe { + let ptr = &0 as *const i32; + let arr = [ptr; 2]; + // We want to do a scalar read of a pointer at offset PTR_SIZE/2 into this array. But we + // cannot use a packed struct or `read_unaligned`, as those use the memcpy code path in + // Miri. So instead we shift the entire array by a bit and then the actual read we want to + // do is perfectly aligned. + let mut target_arr = [ptr::null::(); 3]; + let target = target_arr.as_mut_ptr().cast::(); + target.add(PTR_SIZE / 2).cast::<[*const i32; 2]>().write_unaligned(arr); + // Now target_arr[1] is a mix of the two `ptr` we had stored in `arr`. + let strange_ptr = target_arr[1]; + // Check that the provenance works out. + assert_eq!(*strange_ptr.with_addr(ptr.addr()), 0); + } +} + +fn main() { + t1(); + t2(); + ptr_integer_array(); + ptr_in_two_halves(); +} From 0113f9e727665b6fa54ef4b92766b0e40201a296 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 31 Aug 2022 18:19:14 +0200 Subject: [PATCH 3707/3747] rustup --- rust-version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-version b/rust-version index f7e2fa5a33d3c..0909f24752ac6 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -94b2b15e63c5d2b2a6a0910e3dae554ce9415bf9 +4fd4de7ea358ad6fc28c5780533ea8ccc09e1006 From 3cfb9915fcf97ac3f312d2277193d2c2cf934057 Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Wed, 31 Aug 2022 08:45:26 -0400 Subject: [PATCH 3708/3747] Add a protector test that demonstrates the base tag diagnostic --- src/stacked_borrows/diagnostics.rs | 2 +- .../invalidate_against_protector3.rs | 15 ++++++++++ .../invalidate_against_protector3.stderr | 30 +++++++++++++++++++ 3 files changed, 46 insertions(+), 1 deletion(-) create mode 100644 tests/fail/stacked_borrows/invalidate_against_protector3.rs create mode 100644 tests/fail/stacked_borrows/invalidate_against_protector3.stderr diff --git a/src/stacked_borrows/diagnostics.rs b/src/stacked_borrows/diagnostics.rs index b8e777717e973..461715cedd8fb 100644 --- a/src/stacked_borrows/diagnostics.rs +++ b/src/stacked_borrows/diagnostics.rs @@ -332,7 +332,7 @@ impl<'span, 'history, 'ecx, 'mir, 'tcx> DiagnosticCx<'span, 'history, 'ecx, 'mir // this allocation. if self.history.base.0.tag() == tag { Some(( - format!("{:?} was created here, as a base tag for {:?}", tag, self.history.id), + format!("{:?} was created here, as the base tag for {:?}", tag, self.history.id), self.history.base.1.data() )) } else { diff --git a/tests/fail/stacked_borrows/invalidate_against_protector3.rs b/tests/fail/stacked_borrows/invalidate_against_protector3.rs new file mode 100644 index 0000000000000..634eb97217c6c --- /dev/null +++ b/tests/fail/stacked_borrows/invalidate_against_protector3.rs @@ -0,0 +1,15 @@ +use std::alloc::{alloc, Layout}; + +fn inner(x: *mut i32, _y: &i32) { + // If `x` and `y` alias, retagging is fine with this... but we really + // shouldn't be allowed to write to `x` at all because `y` was assumed to be + // immutable for the duration of this call. + unsafe { *x = 0 }; //~ ERROR: protect +} + +fn main() { + unsafe { + let ptr = alloc(Layout::for_value(&0i32)) as *mut i32; + inner(ptr, &*ptr); + }; +} diff --git a/tests/fail/stacked_borrows/invalidate_against_protector3.stderr b/tests/fail/stacked_borrows/invalidate_against_protector3.stderr new file mode 100644 index 0000000000000..afda15ea160e2 --- /dev/null +++ b/tests/fail/stacked_borrows/invalidate_against_protector3.stderr @@ -0,0 +1,30 @@ +error: Undefined Behavior: not granting access to tag because that would remove [SharedReadOnly for ] which is protected because it is an argument of call ID + --> $DIR/invalidate_against_protector3.rs:LL:CC + | +LL | unsafe { *x = 0 }; + | ^^^^^^ not granting access to tag because that would remove [SharedReadOnly for ] which is protected because it is an argument of call ID + | + = help: this indicates a potential bug in the program: it performed an invalid operation, but the Stacked Borrows rules it violated are still experimental + = help: see https://github.com/rust-lang/unsafe-code-guidelines/blob/master/wip/stacked-borrows.md for further information +help: was created here, as the base tag for ALLOC + --> $DIR/invalidate_against_protector3.rs:LL:CC + | +LL | let ptr = alloc(Layout::for_value(&0i32)) as *mut i32; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: is this argument + --> $DIR/invalidate_against_protector3.rs:LL:CC + | +LL | fn inner(x: *mut i32, _y: &i32) { + | ^^ + = note: BACKTRACE: + = note: inside `inner` at $DIR/invalidate_against_protector3.rs:LL:CC +note: inside `main` at $DIR/invalidate_against_protector3.rs:LL:CC + --> $DIR/invalidate_against_protector3.rs:LL:CC + | +LL | inner(ptr, &*ptr); + | ^^^^^^^^^^^^^^^^^ + +note: some details are omitted, run with `MIRIFLAGS=-Zmiri-backtrace=full` for a verbose backtrace + +error: aborting due to previous error + From e12962b4aa1c019982fa83cbfc05939e398e8c25 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 1 Sep 2022 15:20:05 +0200 Subject: [PATCH 3709/3747] Zulip notifications: ping the Miri team --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 95303a592c8a2..8193411f87995 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -142,7 +142,7 @@ jobs: ZULIP_API_TOKEN: ${{ secrets.ZULIP_API_TOKEN }} run: | ~/.local/bin/zulip-send --stream miri --subject "Cron Job Failure (miri, $(date -u +%Y-%m))" \ - --message 'Dear @**RalfJ** and @**oli** + --message 'Dear @*T-miri*, It would appear that the Miri cron job build failed. Would you mind investigating this issue? From 5f3545e773f930c3345e7166b98bf9d2a76adff6 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 1 Sep 2022 22:25:14 +0200 Subject: [PATCH 3710/3747] disable extern-so ffi support for now due to licensing situation --- Cargo.lock | 27 --------------------------- Cargo.toml | 2 +- README.md | 11 ----------- src/shims/foreign_items.rs | 6 +++--- src/shims/mod.rs | 2 +- tests/compiletest.rs | 4 ++-- 6 files changed, 7 insertions(+), 45 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 28be08c467cd4..a7303421808fa 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,12 +2,6 @@ # It is not intended for manual editing. version = 3 -[[package]] -name = "abort_on_panic" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "955f37ac58af2416bac687c8ab66a4ccba282229bd7422a28d2281a5e66a6116" - [[package]] name = "addr2line" version = "0.17.0" @@ -314,26 +308,6 @@ version = "0.2.112" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b03d17f364a3a042d5e5d46b053bbbf82c92c9430c592dd4c064dc6ee997125" -[[package]] -name = "libffi" -version = "3.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e08093a2ddeee94bd0c830a53d895ff91f1f3bb0f9b3c8c6b00739cdf76bc1d" -dependencies = [ - "abort_on_panic", - "libc", - "libffi-sys", -] - -[[package]] -name = "libffi-sys" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab4106b7f09d7b87d021334d5618fac1dfcfb824d4c5fe111ff0074dfd242e15" -dependencies = [ - "cc", -] - [[package]] name = "libloading" version = "0.7.3" @@ -418,7 +392,6 @@ dependencies = [ "getrandom", "lazy_static", "libc", - "libffi", "libloading", "log", "measureme", diff --git a/Cargo.toml b/Cargo.toml index 0a3dfc2a84e31..c0a217b641169 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,7 +20,7 @@ doctest = false # and no doc tests [dependencies] getrandom = { version = "0.2", features = ["std"] } env_logger = "0.9" -libffi = "3.0.0" +#FIXME(miri#2526): libffi = "3.0.0" libloading = "0.7" log = "0.4" shell-escape = "0.1.4" diff --git a/README.md b/README.md index 8e96338a865f6..c7a3200dbd904 100644 --- a/README.md +++ b/README.md @@ -346,17 +346,6 @@ to Miri failing to detect cases of undefined behavior in a program. this flag is **unsound**. * `-Zmiri-disable-weak-memory-emulation` disables the emulation of some C++11 weak memory effects. -* `-Zmiri-extern-so-file=` is an experimental flag for providing support - for FFI calls. Functions not provided by that file are still executed via the usual Miri shims. - **WARNING**: If an invalid/incorrect `.so` file is specified, this can cause undefined behaviour in Miri itself! - And of course, Miri cannot do any checks on the actions taken by the external code. - Note that Miri has its own handling of file descriptors, so if you want to replace *some* functions - working on file descriptors, you will have to replace *all* of them, or the two kinds of - file descriptors will be mixed up. - This is **work in progress**; currently, only integer arguments and return values are - supported (and no, pointer/integer casts to work around this limitation will not work; - they will fail horribly). - Follow [the discussion on supporting other types](https://github.com/rust-lang/miri/issues/2365). * `-Zmiri-measureme=` enables `measureme` profiling for the interpreted program. This can be used to find which parts of your program are executing slowly under Miri. The profile is written out to a file with the prefix ``, and can be processed diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index b94b6bbb2b8b6..bd46e4ae80e22 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -23,7 +23,7 @@ use rustc_target::{ use super::backtrace::EvalContextExt as _; use crate::helpers::{convert::Truncate, target_os_is_unix}; -use crate::shims::ffi_support::EvalContextExt as _; +//FIXME(miri#2526): use crate::shims::ffi_support::EvalContextExt as _; use crate::*; /// Returned by `emulate_foreign_item_by_name`. @@ -375,9 +375,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // An Ok(false) here means that the function being called was not exported // by the specified `.so` file; we should continue and check if it corresponds to // a provided shim. - if this.call_external_c_fct(link_name, dest, args)? { + /*FIXME(miri#2526): if this.call_external_c_fct(link_name, dest, args)? { return Ok(EmulateByNameResult::NeedsJumping); - } + }*/ } // When adding a new shim, you should follow the following pattern: diff --git a/src/shims/mod.rs b/src/shims/mod.rs index ee2145db7e1b5..8179d09defe39 100644 --- a/src/shims/mod.rs +++ b/src/shims/mod.rs @@ -1,7 +1,7 @@ #![warn(clippy::integer_arithmetic)] mod backtrace; -pub mod ffi_support; +//FIXME(miri#2526): pub mod ffi_support; pub mod foreign_items; pub mod intrinsics; pub mod unix; diff --git a/tests/compiletest.rs b/tests/compiletest.rs index 6b5668e2d6c4c..0e492c3eecdf3 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -212,8 +212,8 @@ fn main() -> Result<()> { ui(Mode::Panic, "tests/panic", WithDependencies)?; ui(Mode::Fail { require_patterns: true }, "tests/fail", WithDependencies)?; if cfg!(target_os = "linux") { - ui(Mode::Pass, "tests/extern-so/pass", WithoutDependencies)?; - ui(Mode::Fail { require_patterns: true }, "tests/extern-so/fail", WithDependencies)?; + //FIXME(miri#2526): ui(Mode::Pass, "tests/extern-so/pass", WithoutDependencies)?; + //FIXME(miri#2526): ui(Mode::Fail { require_patterns: true }, "tests/extern-so/fail", WithDependencies)?; } Ok(()) From 2f348abafc697b65919073c6a36510a5b4fe0add Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 2 Sep 2022 14:38:52 +0200 Subject: [PATCH 3711/3747] Revert "disable extern-so ffi support for now due to licensing situation" This reverts commit 5f3545e773f930c3345e7166b98bf9d2a76adff6. With https://github.com/tov/libffi-rs/pull/58 landed, we no longer depend on abort_on_panic. --- Cargo.lock | 20 ++++++++++++++++++++ Cargo.toml | 2 +- README.md | 11 +++++++++++ src/shims/foreign_items.rs | 6 +++--- src/shims/mod.rs | 2 +- tests/compiletest.rs | 4 ++-- 6 files changed, 38 insertions(+), 7 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a7303421808fa..9df35ec0deb2e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -308,6 +308,25 @@ version = "0.2.112" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b03d17f364a3a042d5e5d46b053bbbf82c92c9430c592dd4c064dc6ee997125" +[[package]] +name = "libffi" +version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e454b3efb16fba3b17810ae5e41df02b649e564ab3c5a34b3b93ed07ad287e6" +dependencies = [ + "libc", + "libffi-sys", +] + +[[package]] +name = "libffi-sys" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab4106b7f09d7b87d021334d5618fac1dfcfb824d4c5fe111ff0074dfd242e15" +dependencies = [ + "cc", +] + [[package]] name = "libloading" version = "0.7.3" @@ -392,6 +411,7 @@ dependencies = [ "getrandom", "lazy_static", "libc", + "libffi", "libloading", "log", "measureme", diff --git a/Cargo.toml b/Cargo.toml index c0a217b641169..0a3dfc2a84e31 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,7 +20,7 @@ doctest = false # and no doc tests [dependencies] getrandom = { version = "0.2", features = ["std"] } env_logger = "0.9" -#FIXME(miri#2526): libffi = "3.0.0" +libffi = "3.0.0" libloading = "0.7" log = "0.4" shell-escape = "0.1.4" diff --git a/README.md b/README.md index c7a3200dbd904..8e96338a865f6 100644 --- a/README.md +++ b/README.md @@ -346,6 +346,17 @@ to Miri failing to detect cases of undefined behavior in a program. this flag is **unsound**. * `-Zmiri-disable-weak-memory-emulation` disables the emulation of some C++11 weak memory effects. +* `-Zmiri-extern-so-file=` is an experimental flag for providing support + for FFI calls. Functions not provided by that file are still executed via the usual Miri shims. + **WARNING**: If an invalid/incorrect `.so` file is specified, this can cause undefined behaviour in Miri itself! + And of course, Miri cannot do any checks on the actions taken by the external code. + Note that Miri has its own handling of file descriptors, so if you want to replace *some* functions + working on file descriptors, you will have to replace *all* of them, or the two kinds of + file descriptors will be mixed up. + This is **work in progress**; currently, only integer arguments and return values are + supported (and no, pointer/integer casts to work around this limitation will not work; + they will fail horribly). + Follow [the discussion on supporting other types](https://github.com/rust-lang/miri/issues/2365). * `-Zmiri-measureme=` enables `measureme` profiling for the interpreted program. This can be used to find which parts of your program are executing slowly under Miri. The profile is written out to a file with the prefix ``, and can be processed diff --git a/src/shims/foreign_items.rs b/src/shims/foreign_items.rs index bd46e4ae80e22..b94b6bbb2b8b6 100644 --- a/src/shims/foreign_items.rs +++ b/src/shims/foreign_items.rs @@ -23,7 +23,7 @@ use rustc_target::{ use super::backtrace::EvalContextExt as _; use crate::helpers::{convert::Truncate, target_os_is_unix}; -//FIXME(miri#2526): use crate::shims::ffi_support::EvalContextExt as _; +use crate::shims::ffi_support::EvalContextExt as _; use crate::*; /// Returned by `emulate_foreign_item_by_name`. @@ -375,9 +375,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx // An Ok(false) here means that the function being called was not exported // by the specified `.so` file; we should continue and check if it corresponds to // a provided shim. - /*FIXME(miri#2526): if this.call_external_c_fct(link_name, dest, args)? { + if this.call_external_c_fct(link_name, dest, args)? { return Ok(EmulateByNameResult::NeedsJumping); - }*/ + } } // When adding a new shim, you should follow the following pattern: diff --git a/src/shims/mod.rs b/src/shims/mod.rs index 8179d09defe39..ee2145db7e1b5 100644 --- a/src/shims/mod.rs +++ b/src/shims/mod.rs @@ -1,7 +1,7 @@ #![warn(clippy::integer_arithmetic)] mod backtrace; -//FIXME(miri#2526): pub mod ffi_support; +pub mod ffi_support; pub mod foreign_items; pub mod intrinsics; pub mod unix; diff --git a/tests/compiletest.rs b/tests/compiletest.rs index 0e492c3eecdf3..6b5668e2d6c4c 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -212,8 +212,8 @@ fn main() -> Result<()> { ui(Mode::Panic, "tests/panic", WithDependencies)?; ui(Mode::Fail { require_patterns: true }, "tests/fail", WithDependencies)?; if cfg!(target_os = "linux") { - //FIXME(miri#2526): ui(Mode::Pass, "tests/extern-so/pass", WithoutDependencies)?; - //FIXME(miri#2526): ui(Mode::Fail { require_patterns: true }, "tests/extern-so/fail", WithDependencies)?; + ui(Mode::Pass, "tests/extern-so/pass", WithoutDependencies)?; + ui(Mode::Fail { require_patterns: true }, "tests/extern-so/fail", WithDependencies)?; } Ok(()) From 7155a2190ee515fb7c73b533e559f46c774a055b Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Fri, 2 Sep 2022 13:55:18 +0000 Subject: [PATCH 3712/3747] Rustup --- rust-version | 2 +- tests/pass/concurrency/sync_nopreempt.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/rust-version b/rust-version index 0909f24752ac6..0b9f9bba0ad4b 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -4fd4de7ea358ad6fc28c5780533ea8ccc09e1006 +9353538c7bea6edb245457712cec720305c4576e diff --git a/tests/pass/concurrency/sync_nopreempt.rs b/tests/pass/concurrency/sync_nopreempt.rs index a53f143fef673..83ecd72ce8dad 100644 --- a/tests/pass/concurrency/sync_nopreempt.rs +++ b/tests/pass/concurrency/sync_nopreempt.rs @@ -16,7 +16,7 @@ fn check_conditional_variables_notify_all() { let (lock, cvar) = &*pair2; let guard = lock.lock().unwrap(); // Block waiting on the conditional variable. - let _ = cvar.wait(guard).unwrap(); + let _x = cvar.wait(guard).unwrap(); }) }) .inspect(|_| { From 6a29a6842ad6b650cb7cdbf823e3b732e8b9997a Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Fri, 2 Sep 2022 13:55:26 +0000 Subject: [PATCH 3713/3747] Clippy after rustup --- cargo-miri/src/setup.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/cargo-miri/src/setup.rs b/cargo-miri/src/setup.rs index 62d6e25a53e0c..c27bb18631758 100644 --- a/cargo-miri/src/setup.rs +++ b/cargo-miri/src/setup.rs @@ -76,7 +76,7 @@ pub fn setup(subcommand: &MiriCommand, host: &str, target: &str) { show_error!("xargo is too old; please upgrade to the latest version") } let mut cmd = cargo(); - cmd.args(&["install", "xargo"]); + cmd.args(["install", "xargo"]); ask_to_run(cmd, ask_user, "install a recent enough xargo"); } @@ -93,7 +93,7 @@ pub fn setup(subcommand: &MiriCommand, host: &str, target: &str) { None => { // Check for `rust-src` rustup component. let output = miri_for_host() - .args(&["--print", "sysroot"]) + .args(["--print", "sysroot"]) .output() .expect("failed to determine sysroot"); if !output.status.success() { @@ -110,7 +110,7 @@ pub fn setup(subcommand: &MiriCommand, host: &str, target: &str) { if !rustup_src.join("std").join("Cargo.toml").exists() { // Ask the user to install the `rust-src` component, and use that. let mut cmd = Command::new("rustup"); - cmd.args(&["component", "add", "rust-src"]); + cmd.args(["component", "add", "rust-src"]); ask_to_run( cmd, ask_user, @@ -136,7 +136,7 @@ pub fn setup(subcommand: &MiriCommand, host: &str, target: &str) { let dirs = directories::ProjectDirs::from("org", "rust-lang", "miri").unwrap(); let dir = dirs.cache_dir(); if !dir.exists() { - fs::create_dir_all(&dir).unwrap(); + fs::create_dir_all(dir).unwrap(); } // The interesting bit: Xargo.toml (only needs content if we actually need std) let xargo_toml = if std::env::var_os("MIRI_NO_STD").is_some() { @@ -178,8 +178,8 @@ path = "lib.rs" // Now invoke xargo. let mut command = xargo_check(); command.arg("check").arg("-q"); - command.current_dir(&dir); - command.env("XARGO_HOME", &dir); + command.current_dir(dir); + command.env("XARGO_HOME", dir); command.env("XARGO_RUST_SRC", &rust_src); // We always need to set a target so rustc bootstrap can tell apart host from target crates. command.arg("--target").arg(target); From 169569cccb0882d3e94c82fc89ab34a34dda0604 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 2 Sep 2022 16:10:24 +0200 Subject: [PATCH 3714/3747] tweak variable name --- tests/pass/concurrency/sync_nopreempt.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/pass/concurrency/sync_nopreempt.rs b/tests/pass/concurrency/sync_nopreempt.rs index 83ecd72ce8dad..3da33fee4c0ed 100644 --- a/tests/pass/concurrency/sync_nopreempt.rs +++ b/tests/pass/concurrency/sync_nopreempt.rs @@ -16,7 +16,7 @@ fn check_conditional_variables_notify_all() { let (lock, cvar) = &*pair2; let guard = lock.lock().unwrap(); // Block waiting on the conditional variable. - let _x = cvar.wait(guard).unwrap(); + let _guard = cvar.wait(guard).unwrap(); }) }) .inspect(|_| { From c011126f1a286c5867e9d18005362e0cd1d221cb Mon Sep 17 00:00:00 2001 From: Martin Nordholts Date: Sat, 3 Sep 2022 06:44:20 +0200 Subject: [PATCH 3715/3747] Fix build with `#[unix_sigpipe = "..."]` support in rustc --- rust-version | 2 +- src/eval.rs | 11 +++++++++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/rust-version b/rust-version index 0b9f9bba0ad4b..1b1d2b0f2b572 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -9353538c7bea6edb245457712cec720305c4576e +8c6ce6b91b172f77c795a74bfeaf74b865146b3f diff --git a/src/eval.rs b/src/eval.rs index f7bc11a445d97..bf04e42713116 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -277,7 +277,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( // Call start function. match entry_type { - EntryFnType::Main => { + EntryFnType::Main { .. } => { let start_id = tcx.lang_items().start_fn().unwrap(); let main_ret_ty = tcx.fn_sig(entry_id).output(); let main_ret_ty = main_ret_ty.no_bound_vars().unwrap(); @@ -292,10 +292,17 @@ pub fn create_ecx<'mir, 'tcx: 'mir>( let main_ptr = ecx.create_fn_alloc_ptr(FnVal::Instance(entry_instance)); + let sigpipe = 2; // Inlining of `DEFAULT` from https://github.com/rust-lang/rust/blob/master/compiler/rustc_session/src/config/sigpipe.rs + ecx.call_function( start_instance, Abi::Rust, - &[Scalar::from_pointer(main_ptr, &ecx).into(), argc.into(), argv], + &[ + Scalar::from_pointer(main_ptr, &ecx).into(), + argc.into(), + argv, + Scalar::from_u8(sigpipe).into(), + ], Some(&ret_place.into()), StackPopCleanup::Root { cleanup: true }, )?; From ee1c1e6d7850cc5ff366b5e1855918e0fc1d80b5 Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Sat, 3 Sep 2022 12:13:47 -0400 Subject: [PATCH 3716/3747] Add support for BCRYPT_RNG_ALG_HANDLE --- rust-version | 2 +- src/shims/windows/foreign_items.rs | 33 +++++++++++++++++++++--------- 2 files changed, 24 insertions(+), 11 deletions(-) diff --git a/rust-version b/rust-version index 1b1d2b0f2b572..5ce9544acc7b9 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -8c6ce6b91b172f77c795a74bfeaf74b865146b3f +47d1cdb0bcac8e417071ce1929d261efe2399ae2 diff --git a/src/shims/windows/foreign_items.rs b/src/shims/windows/foreign_items.rs index 9b8f32b0ab60d..05014a3331dad 100644 --- a/src/shims/windows/foreign_items.rs +++ b/src/shims/windows/foreign_items.rs @@ -288,19 +288,32 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx let [algorithm, ptr, len, flags] = this.check_shim(abi, Abi::System { unwind: false }, link_name, args)?; let algorithm = this.read_scalar(algorithm)?; + let algorithm = algorithm.to_machine_usize(this)?; let ptr = this.read_pointer(ptr)?; let len = this.read_scalar(len)?.to_u32()?; let flags = this.read_scalar(flags)?.to_u32()?; - if flags != 2 { - // ^ BCRYPT_USE_SYSTEM_PREFERRED_RNG - throw_unsup_format!( - "BCryptGenRandom is supported only with the BCRYPT_USE_SYSTEM_PREFERRED_RNG flag" - ); - } - if algorithm.to_machine_usize(this)? != 0 { - throw_unsup_format!( - "BCryptGenRandom algorithm must be NULL when the flag is BCRYPT_USE_SYSTEM_PREFERRED_RNG" - ); + match flags { + 0 => { + // BCRYPT_RNG_ALG_HANDLE + if algorithm != 0x81 { + throw_unsup_format!( + "BCryptGenRandom algorithm must be BCRYPT_RNG_ALG_HANDLE when the flag is 0" + ); + } + } + 2 => { + // BCRYPT_USE_SYSTEM_PREFERRED_RNG + if algorithm != 0 { + throw_unsup_format!( + "BCryptGenRandom algorithm must be NULL when the flag is BCRYPT_USE_SYSTEM_PREFERRED_RNG" + ); + } + } + _ => { + throw_unsup_format!( + "BCryptGenRandom is only supported with BCRYPT_USE_SYSTEM_PREFERRED_RNG or BCRYPT_RNG_ALG_HANDLE" + ); + } } this.gen_random(ptr, len.into())?; this.write_null(dest)?; // STATUS_SUCCESS From 4f30af52738c163c39e1d928c36664e627ee31db Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Sat, 3 Sep 2022 17:38:42 -0400 Subject: [PATCH 3717/3747] rustup: bring in Miri backtrace-rs pruning fix --- rust-version | 2 +- tests/panic/panic1.stderr | 22 ---------------------- 2 files changed, 1 insertion(+), 23 deletions(-) diff --git a/rust-version b/rust-version index 5ce9544acc7b9..0c6d053e9b4c7 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -47d1cdb0bcac8e417071ce1929d261efe2399ae2 +dec689432fac6720b2f18101ac28a21add98b1b8 diff --git a/tests/panic/panic1.stderr b/tests/panic/panic1.stderr index f86ce187b2c9b..15834d58bc6e5 100644 --- a/tests/panic/panic1.stderr +++ b/tests/panic/panic1.stderr @@ -6,26 +6,4 @@ stack backtrace: at $DIR/panic1.rs:LL:CC 2: >::call_once - shim(fn()) at RUSTLIB/core/src/ops/function.rs:LL:CC - 3: std::rt::lang_start::{closure#0} - at RUSTLIB/std/src/rt.rs:LL:CC - 4: std::ops::function::impls::call_once - at RUSTLIB/core/src/ops/function.rs:LL:CC - 5: std::panicking::r#try::do_call - at RUSTLIB/std/src/panicking.rs:LL:CC - 6: std::panicking::r#try - at RUSTLIB/std/src/panicking.rs:LL:CC - 7: std::panic::catch_unwind - at RUSTLIB/std/src/panic.rs:LL:CC - 8: std::rt::lang_start_internal::{closure#2} - at RUSTLIB/std/src/rt.rs:LL:CC - 9: std::panicking::r#try::do_call - at RUSTLIB/std/src/panicking.rs:LL:CC - 10: std::panicking::r#try - at RUSTLIB/std/src/panicking.rs:LL:CC - 11: std::panic::catch_unwind - at RUSTLIB/std/src/panic.rs:LL:CC - 12: std::rt::lang_start_internal - at RUSTLIB/std/src/rt.rs:LL:CC - 13: std::rt::lang_start - at RUSTLIB/std/src/rt.rs:LL:CC note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace. From f9ff70cef9c1bc5ad6c1592f6de73e3cdc10b579 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Wed, 7 Sep 2022 13:26:35 +0000 Subject: [PATCH 3718/3747] Rustup --- rust-version | 2 +- tests/fail/intrinsics/assume.rs | 2 +- tests/fail/intrinsics/assume.stderr | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/rust-version b/rust-version index 0c6d053e9b4c7..cbec52128d37a 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -dec689432fac6720b2f18101ac28a21add98b1b8 +e7c7aa7288559f8e5ea7ce3543ff946b09783628 diff --git a/tests/fail/intrinsics/assume.rs b/tests/fail/intrinsics/assume.rs index be06d0a7a554d..c34827427ef01 100644 --- a/tests/fail/intrinsics/assume.rs +++ b/tests/fail/intrinsics/assume.rs @@ -5,6 +5,6 @@ fn main() { unsafe { std::intrinsics::assume(x < 10); std::intrinsics::assume(x > 1); - std::intrinsics::assume(x > 42); //~ ERROR: `assume` intrinsic called with `false` + std::intrinsics::assume(x > 42); //~ ERROR: `assume` called with `false` } } diff --git a/tests/fail/intrinsics/assume.stderr b/tests/fail/intrinsics/assume.stderr index 17e4cc6698d48..c1909570d99f2 100644 --- a/tests/fail/intrinsics/assume.stderr +++ b/tests/fail/intrinsics/assume.stderr @@ -1,8 +1,8 @@ -error: Undefined Behavior: `assume` intrinsic called with `false` +error: Undefined Behavior: `assume` called with `false` --> $DIR/assume.rs:LL:CC | LL | std::intrinsics::assume(x > 42); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `assume` intrinsic called with `false` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `assume` called with `false` | = help: this indicates a bug in the program: it performed an invalid operation, and caused Undefined Behavior = help: see https://doc.rust-lang.org/nightly/reference/behavior-considered-undefined.html for further information From e91db9f03cc67287dff74300a7549695d2871028 Mon Sep 17 00:00:00 2001 From: Oli Scherer Date: Sat, 10 Sep 2022 13:56:05 +0000 Subject: [PATCH 3719/3747] Rustup --- rust-version | 2 +- src/shims/intrinsics/mod.rs | 13 +++++-------- tests/pass/pointers.rs | 4 ++-- 3 files changed, 8 insertions(+), 11 deletions(-) diff --git a/rust-version b/rust-version index cbec52128d37a..56acee2246c66 100644 --- a/rust-version +++ b/rust-version @@ -1 +1 @@ -e7c7aa7288559f8e5ea7ce3543ff946b09783628 +5197c96c49fc3b7de3ce9a31f7cc62d2cbd1f70c diff --git a/src/shims/intrinsics/mod.rs b/src/shims/intrinsics/mod.rs index a930c4a967549..ac1642b006510 100644 --- a/src/shims/intrinsics/mod.rs +++ b/src/shims/intrinsics/mod.rs @@ -75,17 +75,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx match intrinsic_name { // Miri overwriting CTFE intrinsics. - "ptr_guaranteed_eq" => { + "ptr_guaranteed_cmp" => { let [left, right] = check_arg_count(args)?; let left = this.read_immediate(left)?; let right = this.read_immediate(right)?; - this.binop_ignore_overflow(mir::BinOp::Eq, &left, &right, dest)?; - } - "ptr_guaranteed_ne" => { - let [left, right] = check_arg_count(args)?; - let left = this.read_immediate(left)?; - let right = this.read_immediate(right)?; - this.binop_ignore_overflow(mir::BinOp::Ne, &left, &right, dest)?; + let (val, _overflowed, _ty) = + this.overflowing_binary_op(mir::BinOp::Eq, &left, &right)?; + // We're type punning a bool as an u8 here. + this.write_scalar(val, dest)?; } "const_allocate" => { // For now, for compatibility with the run-time implementation of this, we just return null. diff --git a/tests/pass/pointers.rs b/tests/pass/pointers.rs index b2e6f4556fa2e..d1340a04e0498 100644 --- a/tests/pass/pointers.rs +++ b/tests/pass/pointers.rs @@ -135,8 +135,8 @@ fn main() { // CTFE-specific equality tests, need to also work at runtime. let addr = &13 as *const i32; let addr2 = (addr as usize).wrapping_add(usize::MAX).wrapping_add(1); - assert!(addr.guaranteed_eq(addr2 as *const _)); - assert!(addr.guaranteed_ne(0x100 as *const _)); + assert_eq!(addr.guaranteed_eq(addr2 as *const _), Some(true)); + assert_eq!(addr.guaranteed_ne(0x100 as *const _), Some(true)); wide_ptr_ops(); metadata_vtable(); From d61d4c6af76e10a45cd743048d56f7c35d0b22ea Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Wed, 10 Aug 2022 20:50:36 -0400 Subject: [PATCH 3720/3747] Implement -Zmiri-tag-gc a garbage collector for tags --- README.md | 4 ++ src/bin/miri.rs | 6 ++ src/concurrency/thread.rs | 4 ++ src/eval.rs | 3 + src/lib.rs | 2 + src/machine.rs | 21 +++++++ src/shims/tls.rs | 6 ++ src/stacked_borrows/mod.rs | 19 ++++++ src/stacked_borrows/stack.rs | 66 +++++++++++++++++--- src/tag_gc.rs | 117 +++++++++++++++++++++++++++++++++++ 10 files changed, 241 insertions(+), 7 deletions(-) create mode 100644 src/tag_gc.rs diff --git a/README.md b/README.md index 8e96338a865f6..120ce82e60f9c 100644 --- a/README.md +++ b/README.md @@ -323,6 +323,10 @@ environment variable. We first document the most relevant and most commonly used ensure alignment. (The standard library `align_to` method works fine in both modes; under symbolic alignment it only fills the middle slice when the allocation guarantees sufficient alignment.) +* `-Zmiri-tag-gc=` configures how often the pointer tag garbage collector runs. The default + is to search for and remove unreachable tags once every `10,000` basic blocks. Setting this to + `0` disables the garbage collector, which causes some programs to have explosive memory usage + and/or super-linear runtime. The remaining flags are for advanced use only, and more likely to change or be removed. Some of these are **unsound**, which means they can lead diff --git a/src/bin/miri.rs b/src/bin/miri.rs index 2684ad7ff3d39..d9e91951a9229 100644 --- a/src/bin/miri.rs +++ b/src/bin/miri.rs @@ -521,6 +521,12 @@ fn main() { Err(err) => show_error!("-Zmiri-report-progress requires a `u32`: {}", err), }; miri_config.report_progress = Some(interval); + } else if let Some(param) = arg.strip_prefix("-Zmiri-tag-gc=") { + let interval = match param.parse::() { + Ok(i) => i, + Err(err) => show_error!("-Zmiri-tag-gc requires a `u32`: {}", err), + }; + miri_config.gc_interval = interval; } else if let Some(param) = arg.strip_prefix("-Zmiri-measureme=") { miri_config.measureme_out = Some(param.to_string()); } else if let Some(param) = arg.strip_prefix("-Zmiri-backtrace=") { diff --git a/src/concurrency/thread.rs b/src/concurrency/thread.rs index dc8b1c291148d..e00406be13167 100644 --- a/src/concurrency/thread.rs +++ b/src/concurrency/thread.rs @@ -289,6 +289,10 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { &mut self.threads[self.active_thread].stack } + pub fn iter(&self) -> impl Iterator> { + self.threads.iter() + } + pub fn all_stacks( &self, ) -> impl Iterator>]> { diff --git a/src/eval.rs b/src/eval.rs index bf04e42713116..8cdb2876f1a1f 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -132,6 +132,8 @@ pub struct MiriConfig { /// The location of a shared object file to load when calling external functions /// FIXME! consider allowing users to specify paths to multiple SO files, or to a directory pub external_so_file: Option, + /// Run a garbage collector for SbTags every N basic blocks. + pub gc_interval: u32, } impl Default for MiriConfig { @@ -164,6 +166,7 @@ impl Default for MiriConfig { report_progress: None, retag_fields: false, external_so_file: None, + gc_interval: 10_000, } } } diff --git a/src/lib.rs b/src/lib.rs index bd0cb8057022f..4fb6704165be5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -62,6 +62,7 @@ mod operator; mod range_map; mod shims; mod stacked_borrows; +mod tag_gc; // Establish a "crate-wide prelude": we often import `crate::*`. @@ -110,6 +111,7 @@ pub use crate::range_map::RangeMap; pub use crate::stacked_borrows::{ CallId, EvalContextExt as StackedBorEvalContextExt, Item, Permission, SbTag, Stack, Stacks, }; +pub use crate::tag_gc::EvalContextExt as _; /// Insert rustc arguments at the beginning of the argument list that Miri wants to be /// set per default, for maximal validation power. diff --git a/src/machine.rs b/src/machine.rs index b7624ac5922d1..4eb68907337a1 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -394,6 +394,11 @@ pub struct Evaluator<'mir, 'tcx> { /// Handle of the optional shared object file for external functions. pub external_so_lib: Option<(libloading::Library, std::path::PathBuf)>, + + /// Run a garbage collector for SbTags every N basic blocks. + pub(crate) gc_interval: u32, + /// The number of blocks that passed since the last SbTag GC pass. + pub(crate) since_gc: u32, } impl<'mir, 'tcx> Evaluator<'mir, 'tcx> { @@ -469,6 +474,8 @@ impl<'mir, 'tcx> Evaluator<'mir, 'tcx> { lib_file_path.clone(), ) }), + gc_interval: config.gc_interval, + since_gc: 0, } } @@ -1016,6 +1023,20 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { }); } } + + // Search for SbTags to find all live pointers, then remove all other tags from borrow + // stacks. + // When debug assertions are enabled, run the GC as often as possible so that any cases + // where it mistakenly removes an important tag become visible. + if cfg!(debug_assertions) + || (ecx.machine.gc_interval > 0 && ecx.machine.since_gc >= ecx.machine.gc_interval) + { + ecx.machine.since_gc = 0; + ecx.garbage_collect_tags()?; + } else { + ecx.machine.since_gc += 1; + } + // These are our preemption points. ecx.maybe_preempt_active_thread(); Ok(()) diff --git a/src/shims/tls.rs b/src/shims/tls.rs index f0f1d0e52bdb9..343fa05712dcf 100644 --- a/src/shims/tls.rs +++ b/src/shims/tls.rs @@ -233,6 +233,12 @@ impl<'tcx> TlsData<'tcx> { data.remove(&thread_id); } } + + pub fn iter(&self, mut visitor: impl FnMut(&Scalar)) { + for scalar in self.keys.values().flat_map(|v| v.data.values()) { + visitor(scalar); + } + } } impl<'mir, 'tcx: 'mir> EvalContextPrivExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} diff --git a/src/stacked_borrows/mod.rs b/src/stacked_borrows/mod.rs index 4f7914c5fb0ff..9257628456632 100644 --- a/src/stacked_borrows/mod.rs +++ b/src/stacked_borrows/mod.rs @@ -80,6 +80,8 @@ pub struct Stacks { history: AllocHistory, /// The set of tags that have been exposed inside this allocation. exposed_tags: FxHashSet, + /// Whether this memory has been modified since the last time the tag GC ran + modified_since_last_gc: bool, } /// Extra global state, available to the memory access hooks. @@ -422,6 +424,7 @@ impl<'tcx> Stack { let item = self.get(idx).unwrap(); Stack::item_popped(&item, global, dcx)?; } + Ok(()) } @@ -496,6 +499,20 @@ impl<'tcx> Stack { } // # Stacked Borrows Core End +/// Integration with the SbTag garbage collector +impl Stacks { + pub fn remove_unreachable_tags(&mut self, live_tags: &FxHashSet) { + if self.modified_since_last_gc { + for stack in self.stacks.iter_mut_all() { + if stack.len() > 64 { + stack.retain(live_tags); + } + } + self.modified_since_last_gc = false; + } + } +} + /// Map per-stack operations to higher-level per-location-range operations. impl<'tcx> Stacks { /// Creates a new stack with an initial tag. For diagnostic purposes, we also need to know @@ -514,6 +531,7 @@ impl<'tcx> Stacks { stacks: RangeMap::new(size, stack), history: AllocHistory::new(id, item, current_span), exposed_tags: FxHashSet::default(), + modified_since_last_gc: false, } } @@ -528,6 +546,7 @@ impl<'tcx> Stacks { &mut FxHashSet, ) -> InterpResult<'tcx>, ) -> InterpResult<'tcx> { + self.modified_since_last_gc = true; for (offset, stack) in self.stacks.iter_mut(range.start, range.size) { let mut dcx = dcx_builder.build(&mut self.history, offset); f(stack, &mut dcx, &mut self.exposed_tags)?; diff --git a/src/stacked_borrows/stack.rs b/src/stacked_borrows/stack.rs index 4a9a13d35b527..494ea08b56e48 100644 --- a/src/stacked_borrows/stack.rs +++ b/src/stacked_borrows/stack.rs @@ -39,6 +39,61 @@ pub struct Stack { unique_range: Range, } +impl Stack { + pub fn retain(&mut self, tags: &FxHashSet) { + let mut first_removed = None; + + let mut read_idx = 1; + let mut write_idx = 1; + while read_idx < self.borrows.len() { + let left = self.borrows[read_idx - 1]; + let this = self.borrows[read_idx]; + let should_keep = match this.perm() { + // SharedReadWrite is the simplest case, if it's unreachable we can just remove it. + Permission::SharedReadWrite => tags.contains(&this.tag()), + // Only retain a Disabled tag if it is terminating a SharedReadWrite block. + Permission::Disabled => left.perm() == Permission::SharedReadWrite, + // Unique and SharedReadOnly can terminate a SharedReadWrite block, so only remove + // them if they are both unreachable and not directly after a SharedReadWrite. + Permission::Unique | Permission::SharedReadOnly => + left.perm() == Permission::SharedReadWrite || tags.contains(&this.tag()), + }; + + if should_keep { + if read_idx != write_idx { + self.borrows[write_idx] = self.borrows[read_idx]; + } + write_idx += 1; + } else if first_removed.is_none() { + first_removed = Some(read_idx); + } + + read_idx += 1; + } + self.borrows.truncate(write_idx); + + #[cfg(not(feature = "stack-cache"))] + drop(first_removed); // This is only needed for the stack-cache + + #[cfg(feature = "stack-cache")] + if let Some(first_removed) = first_removed { + // Either end of unique_range may have shifted, all we really know is that we can't + // have introduced a new Unique. + if !self.unique_range.is_empty() { + self.unique_range = 0..self.len(); + } + + // Replace any Items which have been collected with the base item, a known-good value. + for i in 0..CACHE_LEN { + if self.cache.idx[i] >= first_removed { + self.cache.items[i] = self.borrows[0]; + self.cache.idx[i] = 0; + } + } + } + } +} + /// A very small cache of searches of a borrow stack, mapping `Item`s to their position in said stack. /// /// It may seem like maintaining this cache is a waste for small stacks, but @@ -105,14 +160,11 @@ impl<'tcx> Stack { // Check that the unique_range is a valid index into the borrow stack. // This asserts that the unique_range's start <= end. - let uniques = &self.borrows[self.unique_range.clone()]; + let _uniques = &self.borrows[self.unique_range.clone()]; - // Check that the start of the unique_range is precise. - if let Some(first_unique) = uniques.first() { - assert_eq!(first_unique.perm(), Permission::Unique); - } - // We cannot assert that the unique range is exact on the upper end. - // When we pop items within the unique range, setting the end of the range precisely + // We cannot assert that the unique range is precise. + // Both ends may shift around when `Stack::retain` is called. Additionally, + // when we pop items within the unique range, setting the end of the range precisely // requires doing a linear search of the borrow stack, which is exactly the kind of // operation that all this caching exists to avoid. } diff --git a/src/tag_gc.rs b/src/tag_gc.rs new file mode 100644 index 0000000000000..0402e4d35dd51 --- /dev/null +++ b/src/tag_gc.rs @@ -0,0 +1,117 @@ +use crate::*; +use rustc_data_structures::fx::FxHashSet; + +impl<'mir, 'tcx: 'mir> EvalContextExt<'mir, 'tcx> for crate::MiriEvalContext<'mir, 'tcx> {} +pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> { + fn garbage_collect_tags(&mut self) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + // No reason to do anything at all if stacked borrows is off. + if this.machine.stacked_borrows.is_none() { + return Ok(()); + } + + let mut tags = FxHashSet::default(); + + for thread in this.machine.threads.iter() { + if let Some(Scalar::Ptr( + Pointer { provenance: Provenance::Concrete { sb, .. }, .. }, + _, + )) = thread.panic_payload + { + tags.insert(sb); + } + } + + self.find_tags_in_tls(&mut tags); + self.find_tags_in_memory(&mut tags); + self.find_tags_in_locals(&mut tags)?; + + self.remove_unreachable_tags(tags); + + Ok(()) + } + + fn find_tags_in_tls(&mut self, tags: &mut FxHashSet) { + let this = self.eval_context_mut(); + this.machine.tls.iter(|scalar| { + if let Scalar::Ptr(Pointer { provenance: Provenance::Concrete { sb, .. }, .. }, _) = + scalar + { + tags.insert(*sb); + } + }); + } + + fn find_tags_in_memory(&mut self, tags: &mut FxHashSet) { + let this = self.eval_context_mut(); + this.memory.alloc_map().iter(|it| { + for (_id, (_kind, alloc)) in it { + for (_size, prov) in alloc.provenance().iter() { + if let Provenance::Concrete { sb, .. } = prov { + tags.insert(*sb); + } + } + } + }); + } + + fn find_tags_in_locals(&mut self, tags: &mut FxHashSet) -> InterpResult<'tcx> { + let this = self.eval_context_mut(); + for frame in this.machine.threads.all_stacks().flatten() { + // Handle the return place of each frame + if let Ok(return_place) = frame.return_place.try_as_mplace() { + if let Some(Provenance::Concrete { sb, .. }) = return_place.ptr.provenance { + tags.insert(sb); + } + } + + for local in frame.locals.iter() { + let LocalValue::Live(value) = local.value else { + continue; + }; + match value { + Operand::Immediate(Immediate::Scalar(Scalar::Ptr(ptr, _))) => + if let Provenance::Concrete { sb, .. } = ptr.provenance { + tags.insert(sb); + }, + Operand::Immediate(Immediate::ScalarPair(s1, s2)) => { + if let Scalar::Ptr(ptr, _) = s1 { + if let Provenance::Concrete { sb, .. } = ptr.provenance { + tags.insert(sb); + } + } + if let Scalar::Ptr(ptr, _) = s2 { + if let Provenance::Concrete { sb, .. } = ptr.provenance { + tags.insert(sb); + } + } + } + Operand::Indirect(MemPlace { ptr, .. }) => { + if let Some(Provenance::Concrete { sb, .. }) = ptr.provenance { + tags.insert(sb); + } + } + Operand::Immediate(Immediate::Uninit) + | Operand::Immediate(Immediate::Scalar(Scalar::Int(_))) => {} + } + } + } + + Ok(()) + } + + fn remove_unreachable_tags(&mut self, tags: FxHashSet) { + let this = self.eval_context_mut(); + this.memory.alloc_map().iter(|it| { + for (_id, (_kind, alloc)) in it { + alloc + .extra + .stacked_borrows + .as_ref() + .unwrap() + .borrow_mut() + .remove_unreachable_tags(&tags); + } + }); + } +} From f59605ce521b6eae453875cbdfe9263ab7e50d9e Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Mon, 5 Sep 2022 18:39:32 -0400 Subject: [PATCH 3721/3747] In CI set the GC interval to 1 for Linux only --- .github/workflows/ci.yml | 4 ++++ ci.sh | 2 +- src/machine.rs | 7 ++----- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8193411f87995..fde575922dd11 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -34,6 +34,10 @@ jobs: steps: - uses: actions/checkout@v3 + - name: Set the tag GC interval to 1 on linux + if: runner.os == 'macOS' + run: echo "MIRIFLAGS=-Zmiri-tag-gc=1" >> $GITHUB_ENV + # We install gnu-tar because BSD tar is buggy on macOS builders of GHA. # See . - name: Install GNU tar diff --git a/ci.sh b/ci.sh index d70feec66f268..aa322e54a31da 100755 --- a/ci.sh +++ b/ci.sh @@ -31,7 +31,7 @@ function run_tests { # optimizations up all the way). # Optimizations change diagnostics (mostly backtraces), so we don't check them #FIXME(#2155): we want to only run the pass and panic tests here, not the fail tests. - MIRIFLAGS="-O -Zmir-opt-level=4" MIRI_SKIP_UI_CHECKS=1 ./miri test -- tests/{pass,panic} + MIRIFLAGS="${MIRIFLAGS:-} -O -Zmir-opt-level=4" MIRI_SKIP_UI_CHECKS=1 ./miri test -- tests/{pass,panic} fi ## test-cargo-miri diff --git a/src/machine.rs b/src/machine.rs index 4eb68907337a1..60fe2a91adf73 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -1015,6 +1015,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { fn before_terminator(ecx: &mut InterpCx<'mir, 'tcx, Self>) -> InterpResult<'tcx> { ecx.machine.basic_block_count += 1u64; // a u64 that is only incremented by 1 will "never" overflow + ecx.machine.since_gc += 1; // Possibly report our progress. if let Some(report_progress) = ecx.machine.report_progress { if ecx.machine.basic_block_count % u64::from(report_progress) == 0 { @@ -1028,13 +1029,9 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { // stacks. // When debug assertions are enabled, run the GC as often as possible so that any cases // where it mistakenly removes an important tag become visible. - if cfg!(debug_assertions) - || (ecx.machine.gc_interval > 0 && ecx.machine.since_gc >= ecx.machine.gc_interval) - { + if ecx.machine.gc_interval > 0 && ecx.machine.since_gc >= ecx.machine.gc_interval { ecx.machine.since_gc = 0; ecx.garbage_collect_tags()?; - } else { - ecx.machine.since_gc += 1; } // These are our preemption points. From f6cbba12cef255b119f69f71d066141222099677 Mon Sep 17 00:00:00 2001 From: lyj Date: Tue, 13 Sep 2022 17:49:41 +0800 Subject: [PATCH 3722/3747] fix typo --- src/concurrency/thread.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/concurrency/thread.rs b/src/concurrency/thread.rs index dc8b1c291148d..38c30f44c70de 100644 --- a/src/concurrency/thread.rs +++ b/src/concurrency/thread.rs @@ -582,7 +582,7 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { } // No callbacks scheduled, pick a regular thread to execute. // The active thread blocked or yielded. So we go search for another enabled thread. - // Curcially, we start searching at the current active thread ID, rather than at 0, since we + // Crucially, we start searching at the current active thread ID, rather than at 0, since we // want to avoid always scheduling threads 0 and 1 without ever making progress in thread 2. // // `skip(N)` means we start iterating at thread N, so we skip 1 more to start just *after* From 93e41f625ae97cbedca37358ef8f3d15e3164068 Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Tue, 13 Sep 2022 10:12:57 -0400 Subject: [PATCH 3723/3747] Linux has more testing, we should do the extra checks there --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index fde575922dd11..80d150e1df15d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -35,7 +35,7 @@ jobs: - uses: actions/checkout@v3 - name: Set the tag GC interval to 1 on linux - if: runner.os == 'macOS' + if: runner.os == 'Linux' run: echo "MIRIFLAGS=-Zmiri-tag-gc=1" >> $GITHUB_ENV # We install gnu-tar because BSD tar is buggy on macOS builders of GHA. From aebfbf2a91606d9a6f39005aee72725d867fd2fd Mon Sep 17 00:00:00 2001 From: bors Date: Tue, 13 Sep 2022 15:43:32 +0000 Subject: [PATCH 3724/3747] fix typo --- src/concurrency/vector_clock.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/concurrency/vector_clock.rs b/src/concurrency/vector_clock.rs index 716fdba0f67c2..32449f8eb1884 100644 --- a/src/concurrency/vector_clock.rs +++ b/src/concurrency/vector_clock.rs @@ -53,7 +53,7 @@ pub type VTimestamp = u32; /// circuit the calculation and return the correct result faster, /// also this means that there is only one unique valid length /// for each set of vector clock values and hence the PartialEq -// and Eq derivations are correct. +/// and Eq derivations are correct. #[derive(PartialEq, Eq, Default, Debug)] pub struct VClock(SmallVec<[VTimestamp; SMALL_VECTOR]>); From 6a37643265bb11658794222e9ba15652f7272990 Mon Sep 17 00:00:00 2001 From: Christian Poveda Date: Tue, 23 Aug 2022 13:55:30 -0500 Subject: [PATCH 3725/3747] make `sleep` work with isolation enabled --- src/concurrency/thread.rs | 55 ++++----- src/eval.rs | 5 - src/machine.rs | 12 +- src/shims/time.rs | 145 +++++++++++++++++++++--- src/shims/unix/linux/sync.rs | 6 +- src/shims/unix/sync.rs | 2 +- tests/pass/shims/time-with-isolation.rs | 34 ++++++ 7 files changed, 199 insertions(+), 60 deletions(-) create mode 100644 tests/pass/shims/time-with-isolation.rs diff --git a/src/concurrency/thread.rs b/src/concurrency/thread.rs index 19da0fc678ab2..8f1fabdddcf6d 100644 --- a/src/concurrency/thread.rs +++ b/src/concurrency/thread.rs @@ -3,7 +3,7 @@ use std::cell::RefCell; use std::collections::hash_map::Entry; use std::num::TryFromIntError; -use std::time::{Duration, Instant, SystemTime}; +use std::time::{Duration, SystemTime}; use log::trace; @@ -16,6 +16,7 @@ use rustc_target::spec::abi::Abi; use crate::concurrency::data_race; use crate::concurrency::sync::SynchronizationState; +use crate::shims::time::{Clock, Instant}; use crate::*; #[derive(Clone, Copy, Debug, PartialEq, Eq)] @@ -187,17 +188,6 @@ pub enum Time { RealTime(SystemTime), } -impl Time { - /// How long do we have to wait from now until the specified time? - fn get_wait_time(&self) -> Duration { - match self { - Time::Monotonic(instant) => instant.saturating_duration_since(Instant::now()), - Time::RealTime(time) => - time.duration_since(SystemTime::now()).unwrap_or(Duration::new(0, 0)), - } - } -} - /// Callbacks are used to implement timeouts. For example, waiting on a /// conditional variable with a timeout creates a callback that is called after /// the specified time and unblocks the thread. If another thread signals on the @@ -490,13 +480,16 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { } /// Get a callback that is ready to be called. - fn get_ready_callback(&mut self) -> Option<(ThreadId, TimeoutCallback<'mir, 'tcx>)> { + fn get_ready_callback( + &mut self, + clock: &Clock, + ) -> Option<(ThreadId, TimeoutCallback<'mir, 'tcx>)> { // We iterate over all threads in the order of their indices because // this allows us to have a deterministic scheduler. for thread in self.threads.indices() { match self.timeout_callbacks.entry(thread) { Entry::Occupied(entry) => - if entry.get().call_time.get_wait_time() == Duration::new(0, 0) { + if clock.get_wait_time(&entry.get().call_time) == Duration::new(0, 0) { return Some((thread, entry.remove().callback)); }, Entry::Vacant(_) => {} @@ -553,7 +546,7 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { /// used in stateless model checkers such as Loom: run the active thread as /// long as we can and switch only when we have to (the active thread was /// blocked, terminated, or has explicitly asked to be preempted). - fn schedule(&mut self) -> InterpResult<'tcx, SchedulingAction> { + fn schedule(&mut self, clock: &Clock) -> InterpResult<'tcx, SchedulingAction> { // Check whether the thread has **just** terminated (`check_terminated` // checks whether the thread has popped all its stack and if yes, sets // the thread state to terminated). @@ -580,7 +573,7 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { // at the time of the call". // let potential_sleep_time = - self.timeout_callbacks.values().map(|info| info.call_time.get_wait_time()).min(); + self.timeout_callbacks.values().map(|info| clock.get_wait_time(&info.call_time)).min(); if potential_sleep_time == Some(Duration::new(0, 0)) { return Ok(SchedulingAction::ExecuteTimeoutCallback); } @@ -615,7 +608,8 @@ impl<'mir, 'tcx: 'mir> ThreadManager<'mir, 'tcx> { // All threads are currently blocked, but we have unexecuted // timeout_callbacks, which may unblock some of the threads. Hence, // sleep until the first callback. - std::thread::sleep(sleep_time); + + clock.sleep(sleep_time); Ok(SchedulingAction::ExecuteTimeoutCallback) } else { throw_machine_stop!(TerminationInfo::Deadlock); @@ -878,18 +872,19 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx #[inline] fn run_timeout_callback(&mut self) -> InterpResult<'tcx> { let this = self.eval_context_mut(); - let (thread, callback) = - if let Some((thread, callback)) = this.machine.threads.get_ready_callback() { - (thread, callback) - } else { - // get_ready_callback can return None if the computer's clock - // was shifted after calling the scheduler and before the call - // to get_ready_callback (see issue - // https://github.com/rust-lang/miri/issues/1763). In this case, - // just do nothing, which effectively just returns to the - // scheduler. - return Ok(()); - }; + let (thread, callback) = if let Some((thread, callback)) = + this.machine.threads.get_ready_callback(&this.machine.clock) + { + (thread, callback) + } else { + // get_ready_callback can return None if the computer's clock + // was shifted after calling the scheduler and before the call + // to get_ready_callback (see issue + // https://github.com/rust-lang/miri/issues/1763). In this case, + // just do nothing, which effectively just returns to the + // scheduler. + return Ok(()); + }; // This back-and-forth with `set_active_thread` is here because of two // design decisions: // 1. Make the caller and not the callback responsible for changing @@ -906,7 +901,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx #[inline] fn schedule(&mut self) -> InterpResult<'tcx, SchedulingAction> { let this = self.eval_context_mut(); - this.machine.threads.schedule() + this.machine.threads.schedule(&this.machine.clock) } /// Handles thread termination of the active thread: wakes up threads joining on this one, diff --git a/src/eval.rs b/src/eval.rs index 8cdb2876f1a1f..e1ef7fa981753 100644 --- a/src/eval.rs +++ b/src/eval.rs @@ -359,11 +359,6 @@ pub fn eval_entry<'tcx>( assert!(ecx.step()?, "a terminated thread was scheduled for execution"); } SchedulingAction::ExecuteTimeoutCallback => { - assert!( - ecx.machine.communicate(), - "scheduler callbacks require disabled isolation, but the code \ - that created the callback did not check it" - ); ecx.run_timeout_callback()?; } SchedulingAction::ExecuteDtors => { diff --git a/src/machine.rs b/src/machine.rs index 60fe2a91adf73..7a3b8732fca50 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -4,7 +4,6 @@ use std::borrow::Cow; use std::cell::RefCell; use std::fmt; -use std::time::Instant; use rand::rngs::StdRng; use rand::SeedableRng; @@ -28,7 +27,7 @@ use rustc_target::spec::abi::Abi; use crate::{ concurrency::{data_race, weak_memory}, - shims::unix::FileHandler, + shims::{time::Clock, unix::FileHandler}, *, }; @@ -327,8 +326,8 @@ pub struct Evaluator<'mir, 'tcx> { /// The table of directory descriptors. pub(crate) dir_handler: shims::unix::DirHandler, - /// The "time anchor" for this machine's monotone clock (for `Instant` simulation). - pub(crate) time_anchor: Instant, + /// This machine's monotone clock. + pub(crate) clock: Clock, /// The set of threads. pub(crate) threads: ThreadManager<'mir, 'tcx>, @@ -434,7 +433,6 @@ impl<'mir, 'tcx> Evaluator<'mir, 'tcx> { enforce_abi: config.check_abi, file_handler: FileHandler::new(config.mute_stdout_stderr), dir_handler: Default::default(), - time_anchor: Instant::now(), layouts, threads: ThreadManager::default(), static_roots: Vec::new(), @@ -454,6 +452,7 @@ impl<'mir, 'tcx> Evaluator<'mir, 'tcx> { preemption_rate: config.preemption_rate, report_progress: config.report_progress, basic_block_count: 0, + clock: Clock::new(config.isolated_op == IsolatedOp::Allow), external_so_lib: config.external_so_file.as_ref().map(|lib_file_path| { // Check if host target == the session target. if env!("TARGET") != target_triple { @@ -1036,6 +1035,9 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for Evaluator<'mir, 'tcx> { // These are our preemption points. ecx.maybe_preempt_active_thread(); + + ecx.machine.clock.tick(); + Ok(()) } diff --git a/src/shims/time.rs b/src/shims/time.rs index a574a0612c47d..77f46ac6c3d45 100644 --- a/src/shims/time.rs +++ b/src/shims/time.rs @@ -1,8 +1,128 @@ -use std::time::{Duration, Instant, SystemTime}; +use std::sync::atomic::AtomicU64; +use std::time::{Duration, Instant as StdInstant, SystemTime}; + +use rustc_data_structures::sync::Ordering; use crate::concurrency::thread::Time; use crate::*; +/// When using a virtual clock, this defines how many nanoseconds do we pretend +/// are passing for each basic block. +const NANOSECOND_PER_BASIC_BLOCK: u64 = 10; + +#[derive(Debug)] +pub enum Instant { + Host(StdInstant), + Virtual { nanoseconds: u64 }, +} + +/// A monotone clock used for `Instant` simulation. +#[derive(Debug)] +pub enum Clock { + Host { + /// The "time anchor" for this machine's monotone clock. + time_anchor: StdInstant, + }, + Virtual { + /// The "current virtual time". + nanoseconds: AtomicU64, + }, +} + +impl Clock { + /// Create a new clock based on the availability of communication with the host. + pub fn new(communicate: bool) -> Self { + if communicate { + Self::Host { time_anchor: StdInstant::now() } + } else { + Self::Virtual { nanoseconds: 0.into() } + } + } + + /// Get the current time relative to this clock. + pub fn get(&self) -> Duration { + match self { + Self::Host { time_anchor } => StdInstant::now().saturating_duration_since(*time_anchor), + Self::Virtual { nanoseconds } => + Duration::from_nanos(nanoseconds.load(Ordering::Relaxed)), + } + } + + /// Let the time pass for a small interval. + pub fn tick(&self) { + match self { + Self::Host { .. } => { + // Time will pass without us doing anything. + } + Self::Virtual { nanoseconds } => { + nanoseconds.fetch_add(NANOSECOND_PER_BASIC_BLOCK, Ordering::Relaxed); + } + } + } + + /// Sleep for the desired duration. + pub fn sleep(&self, duration: Duration) { + match self { + Self::Host { .. } => std::thread::sleep(duration), + Self::Virtual { nanoseconds } => { + // Just pretend that we have slept for some time. + nanoseconds.fetch_add(duration.as_nanos().try_into().unwrap(), Ordering::Relaxed); + } + } + } + + /// Compute `now + duration` relative to this clock. + pub fn get_time_relative(&self, duration: Duration) -> Option